diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..0e990b715a83 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.194.0/containers/cpp +{ + "name": "Erlang/OTP", + "build": { + "dockerfile": "../.github/dockerfiles/Dockerfile.ubuntu-base", + "context": "../.github", + "args": { + "BASE": "mcr.microsoft.com/vscode/devcontainers/base:focal", + "USER": "vscode", + "GROUP": "vscode" + } + }, + "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], + + // Set *default* container specific settings.json values on container create. + "settings": {}, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vscode.cpptools", + "erlang-ls.erlang-ls" ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "gcc -v", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} diff --git a/.dir-locals.el b/.dir-locals.el index 09d02274c37f..b6586cba03d1 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -2,6 +2,7 @@ ( (erlang-mode (indent-tabs-mode . nil)) (autoconf-mode (indent-tabs-mode . nil)) + (m4-mode (indent-tabs-mode . nil)) (java-mode (indent-tabs-mode . nil)) (perl-mode (indent-tabs-mode . nil)) (xml-mode (indent-tabs-mode . nil)) diff --git a/.github/dockerfiles/Dockerfile.32-bit b/.github/dockerfiles/Dockerfile.32-bit index 5949ecc3353f..b1df0e996cba 100644 --- a/.github/dockerfiles/Dockerfile.32-bit +++ b/.github/dockerfiles/Dockerfile.32-bit @@ -1,4 +1,5 @@ -FROM docker.pkg.github.com/erlang/otp/i386-debian-base +ARG BASE=ghcr.io/erlang/otp/i386-debian-base +FROM $BASE ARG MAKEFLAGS=-j4 ENV MAKEFLAGS=$MAKEFLAGS \ @@ -16,14 +17,8 @@ ENV CFLAGS="-O2 -g -Werror" ## Configure, check that no application are disabled, then make and then build doc chunks RUN ./configure --with-ssl --prefix=/otp && \ - if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi - -RUN make && make install && \ - make install-docs DOC_TARGETS=chunks + if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + make && make install ## Disable -Werror as testcases do not compile with it on ENV CFLAGS="-O2 -g" - -RUN TESTSUITE_ROOT=/tests ./otp_build tests - -ENTRYPOINT ["bash","-c"] diff --git a/.github/dockerfiles/Dockerfile.64-bit b/.github/dockerfiles/Dockerfile.64-bit index 8d513d8c71f4..1cdb8cfd687c 100644 --- a/.github/dockerfiles/Dockerfile.64-bit +++ b/.github/dockerfiles/Dockerfile.64-bit @@ -1,12 +1,10 @@ -FROM docker.pkg.github.com/erlang/otp/ubuntu-base -## We do a SSA lint check here -ENV ERL_COMPILER_OPTIONS=ssalint +ARG BASE=ghcr.io/erlang/otp/ubuntu-base +FROM $BASE -ARG MAKEFLAGS=-j4 +ARG MAKEFLAGS=$MAKEFLAGS ENV MAKEFLAGS=$MAKEFLAGS \ - ERLC_USE_SERVER=yes \ - ERL_TOP=/buildroot/otp \ - PATH=/buildroot/otp/bin:$PATH + ERL_TOP=/buildroot/otp \ + PATH="/Erlang ∅⊤℞/bin":/buildroot/otp/bin:$PATH ARG ARCHIVE=./otp.tar.gz COPY $ARCHIVE /buildroot/otp.tar.gz @@ -14,19 +12,24 @@ RUN cd /buildroot && tar -xzf ./otp.tar.gz WORKDIR /buildroot/otp/ -ENV CC=clang CXX=clang++ \ - CFLAGS="-O2 -g -Werror" +ENV CFLAGS="-O2 -g -Werror" -## Configure, check that no application are disabled and then make -# We need --with-ssl-lib-subdir=lib/x86_64-linux-gnu since clang does not -# give us this information such as gcc does... -RUN ./configure --with-ssl --with-ssl-lib-subdir=lib/x86_64-linux-gnu --prefix=/otp && \ - if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ - make && make install +## Configure (if not cached), check that no application are disabled and then make +RUN if [ ! -f Makefile ]; then \ + touch README.md && \ + ./configure --prefix="/Erlang ∅⊤℞" && \ + if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + find . -type f -newer README.md | xargs tar --transform 's:^./:otp/:' -cf ../otp_cache.tar; \ + fi && \ + make && make docs DOC_TARGETS=chunks && \ + sudo make install install-docs DOC_TARGETS=chunks ## Disable -Werror as testcases do not compile with it on ENV CFLAGS="-O2 -g" -RUN TESTSUITE_ROOT=/tests ./otp_build tests - -ENTRYPOINT ["bash","-c"] +## Update init.sh with correct env vars +RUN echo "export MAKEFLAGS=$MAKEFLAGS" > /buildroot/env.sh && \ + echo "export ERLC_USE_SERVER=$ERLC_USE_SERVER" >> /buildroot/env.sh && \ + echo "export ERL_TOP=\"$ERL_TOP\"" >> /buildroot/env.sh && \ + echo "export PATH=\"$PATH\"" >> /buildroot/env.sh && \ + echo "export ERL_LIBS=\"$ERL_LIBS\"" >> /buildroot/env.sh diff --git a/.github/dockerfiles/Dockerfile.clang b/.github/dockerfiles/Dockerfile.clang new file mode 100644 index 000000000000..2fe7f110d354 --- /dev/null +++ b/.github/dockerfiles/Dockerfile.clang @@ -0,0 +1,32 @@ +ARG BASE=ghcr.io/erlang/otp/ubuntu-base +FROM $BASE +## We do a SSA lint check here +ENV ERL_COMPILER_OPTIONS=ssalint + +ARG MAKEFLAGS=-j4 +ENV MAKEFLAGS=$MAKEFLAGS \ + ERLC_USE_SERVER=yes \ + ERL_TOP=/buildroot/otp \ + PATH=/otp/bin:/buildroot/otp/bin:$PATH + +RUN sudo apt-get update && sudo apt-get install -y clang + +ARG ARCHIVE=./otp.tar.gz +COPY $ARCHIVE /buildroot/otp.tar.gz +RUN cd /buildroot && tar -xzf ./otp.tar.gz + +WORKDIR /buildroot/otp/ + +ENV CC=clang CXX=clang++ \ + CFLAGS="-O2 -g -Werror" + +## Configure, check that no application are disabled and then make +# We need --with-ssl-lib-subdir=lib/x86_64-linux-gnu since clang does not +# give us this information such as gcc does... +RUN ./configure --with-ssl --with-ssl-lib-subdir=lib/x86_64-linux-gnu --prefix=/otp && \ + if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + make && sudo make install && \ + make FLAVOR=emu && sudo make install FLAVOR=emu + +## Disable -Werror as testcases do not compile with it on +ENV CFLAGS="-O2 -g" diff --git a/.github/dockerfiles/Dockerfile.cross-compile b/.github/dockerfiles/Dockerfile.cross-compile index ca583e185712..c9e9c4485538 100644 --- a/.github/dockerfiles/Dockerfile.cross-compile +++ b/.github/dockerfiles/Dockerfile.cross-compile @@ -1,7 +1,8 @@ ## ## This docker file will build Erlang on 32-bit to 64-bit x86 ## -FROM docker.pkg.github.com/erlang/otp/i386-debian-base as build +ARG BASE=ghcr.io/erlang/otp/i386-debian-base +FROM $BASE as build ARG MAKEFLAGS=-j4 ENV MAKEFLAGS=$MAKEFLAGS \ @@ -17,13 +18,6 @@ RUN tar xzf ../otp.tar.gz ## Build the bootstrap system RUN cd $ERL_TOP && CFLAGS="-Wall -O2 -g" ./configure && make && make install -## Build pre-build tar ball -RUN cd $ERL_TOP && scripts/build-otp-tar -o /buildroot/otp_clean_src.tar.gz /buildroot/otp_src.tar.gz \ - -b /buildroot/bootstrap/otp/ /buildroot/otp.tar.gz - -## Prepare for a new build using pre-built tar ball -RUN cd ../ && tar -xzf ./otp_src.tar.gz - ENV HOST=$HOST_TRIP \ CC=$HOST_TRIP-gcc \ CPPFLAGS="--sysroot=/buildroot/sysroot" \ @@ -39,15 +33,16 @@ ENV HOST=$HOST_TRIP \ erl_xcomp_sysroot=/buildroot/sysroot \ ERL_TOP=/buildroot/otp +RUN cd /buildroot && tar xzf otp.tar.gz + WORKDIR /buildroot/otp ## Build the cross system # We cannot use config.guess for --build since its value clashes with the # canonical value of host... -RUN ./configure --prefix=/otp/ --host=$HOST --build=x86-pc-linux-gnu -RUN OTP_SMALL_BUILD=true V=1 make - -RUN make odbc && make install +RUN ./configure --prefix=/otp/ --host=$HOST --build=x86-pc-linux-gnu && \ + OTP_SMALL_BUILD=true V=1 make && \ + make install ## Build the cross tests ENV CFLAGS="--sysroot=/buildroot/sysroot -O2 -g" @@ -64,5 +59,3 @@ COPY --from=build /otp /otp COPY --from=build /buildroot/otp/release/tests /tests ENV PATH=/otp/bin:$PATH - -ENTRYPOINT ["bash","-c"] diff --git a/.github/dockerfiles/Dockerfile.documentation b/.github/dockerfiles/Dockerfile.documentation deleted file mode 100644 index b0c2eb801543..000000000000 --- a/.github/dockerfiles/Dockerfile.documentation +++ /dev/null @@ -1,23 +0,0 @@ -FROM docker.pkg.github.com/erlang/otp/ubuntu-base - -ARG MAKEFLAGS=-j4 -ENV MAKEFLAGS=$MAKEFLAGS \ - ERLC_USE_SERVER=yes \ - ERL_TOP=/buildroot/otp \ - PATH=/buildroot/otp/bin:$PATH - -ARG ARCHIVE=./otp.tar.gz -COPY $ARCHIVE /buildroot/otp.tar.gz -RUN cd /buildroot && tar -xzf ./otp.tar.gz - -WORKDIR /buildroot/otp/ - -ENV RELEASE_ROOT=/otp - -RUN ./configure --prefix=/otp && make && make release - -RUN ./configure && make && make release - -RUN make docs release_docs - -ENTRYPOINT ["bash","-c"] diff --git a/.github/dockerfiles/Dockerfile.ubuntu-base b/.github/dockerfiles/Dockerfile.ubuntu-base index 20df3ab80d56..1f4afa618b6a 100644 --- a/.github/dockerfiles/Dockerfile.ubuntu-base +++ b/.github/dockerfiles/Dockerfile.ubuntu-base @@ -1,16 +1,122 @@ ## ## This docker file will build a base image for building Erlang/OTP ## -ARG BASE=ubuntu:20.04 +ARG BASE=gitpod/workspace-full FROM $BASE -ENV INSTALL_LIBS="zlib1g-dev libncurses5-dev libssl-dev unixodbc-dev libgmp3-dev libwxbase3.0-dev libwxgtk3.0-gtk3-dev libwxgtk-webview3.0-gtk3-dev libsctp-dev lksctp-tools" +ENV INSTALL_LIBS="zlib1g-dev libncurses5-dev libssl-dev unixodbc-dev libsctp-dev lksctp-tools libgmp3-dev libwxbase3.0-dev libwxgtk3.0-gtk3-dev libwxgtk-webview3.0-gtk3-dev" + +USER root ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 + +## Install build tools +RUN apt-get update && apt-get -y upgrade && \ + apt-get install -y build-essential m4 autoconf fop xsltproc \ + default-jdk libxml2-utils flex pkg-config locales tzdata sudo ${INSTALL_LIBS} && \ + sed -i 's@# en_US.UTF-8@en_US.UTF-8@g' /etc/locale.gen && locale-gen && \ + update-alternatives --set wx-config /usr/lib/x86_64-linux-gnu/wx/config/gtk3-unicode-3.0 + +ARG MAKEFLAGS=-j4 +ENV MAKEFLAGS=$MAKEFLAGS \ + ERLC_USE_SERVER=yes + +ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 + +ARG USER=gitpod +ARG GROUP=gitpod +ARG gid=10 +ARG uid=421 + +RUN echo "Europe/Stockholm" > /etc/timezone && \ + ln -snf /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime && \ + if ! grep ":${gid}:$" /etc/group; then groupadd -g ${gid} localgroup; fi && \ + if [ ! -d /home/${USER} ]; then useradd -rm -d /home/${USER} -s /bin/sh -g ${gid} -G ${gid},sudo -u ${uid} ${USER}; fi && \ + echo "${USER} ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/${USER} && \ + echo "/buildroot/** r," >> /etc/apparmor.d/local/usr.sbin.named && \ + echo "/tests/** r," >> /etc/apparmor.d/local/usr.sbin.named + +## Java and log4j are used by fop to build documentation +COPY --chown=${USER}:${GROUP} dockerfiles/log4j.properties /home/${USER}/ +ENV JAVA_ARGS="-Dlog4j.configuration=file://home/${USER}/log4j.properties" + +ENV OTP_STRICT_INSTALL=yes + +RUN mkdir /buildroot /tests /otp && chown ${USER}:${GROUP} /buildroot /tests /otp + +## We install the latest version of the previous three releases in order to do +## backwards compatability testing of Erlang. +RUN apt-get install -y git curl && \ + curl -L https://raw.githubusercontent.com/kerl/kerl/master/kerl > /usr/bin/kerl && \ + chmod +x /usr/bin/kerl && \ + kerl update releases && \ + LATEST=$(kerl list releases | tail -1 | awk -F '.' '{print $1}') && \ + for release in $(seq $(( LATEST - 2 )) $(( LATEST ))); do \ + VSN=$(kerl list releases | grep "^$release" | tail -1); \ + if [ $release = $LATEST ]; then \ + echo "/usr/local/lib/erlang-${VSN}/bin" > /home/${USER}/LATEST; \ + fi && \ + kerl build ${VSN} ${VSN} && \ + kerl install ${VSN} /usr/local/lib/erlang-${VSN}; \ + done && \ + rm -rf ~/.kerl + +## Install test tools +## EXTRA_LIBS are installed using a for loop because of bugs in the erlang-doc deb package +## Apache2 may already be installed, if so we do not want to install it again +ARG EXTRA_LIBS="erlang erlang-doc" +RUN apt-get install -y \ + unixodbc odbc-postgresql postgresql ssh openssh-server groff-base gdb \ + tinyproxy bind9 nsd expect vsftpd python emacs nano vim \ + linux-tools-common linux-tools-generic jq \ + xvfb libgl1-mesa-dri && \ + for lib in ${EXTRA_LIBS}; do apt-get install -y ${lib}; done && \ + if [ ! -f /etc/apache2/apache2.conf ]; then apt-get install -y apache2; fi +RUN apt-get install -y linux-tools-$(uname -r) || true + +## We use tmux to test terminals +RUN apt-get install -y libevent-dev libutf8proc-dev && \ + cd /tmp && wget https://github.com/tmux/tmux/releases/download/3.2a/tmux-3.2a.tar.gz && \ + tar xvzf tmux-3.2a.tar.gz && cd tmux-3.2a && \ + ./configure --enable-static --enable-utf8proc && \ + make && make install + +## Setup progres so that the odbc test can run +USER postgres + +RUN service postgresql start && \ + psql -c "CREATE USER odbctest WITH SUPERUSER PASSWORD 'odbctest';" && \ + createdb -O odbctest odbctest && \ + service postgresql stop + +COPY --chown=root:${GROUP} dockerfiles/odbc.ini /etc/ +COPY --chown=root:${GROUP} dockerfiles/odbcinst.ini /etc/ + +USER ${USER} + +## Need to set USER and create a keygen file for ssh tests to pass +ENV USER=${USER} +RUN ssh-keygen -q -t rsa -N '' -f $HOME/.ssh/id_rsa && \ + cp $HOME/.ssh/id_rsa.pub $HOME/.ssh/authorized_keys + +COPY --chown=${USER}:${GROUP} dockerfiles/init.sh /buildroot/ + +WORKDIR /buildroot/ + +## Install test tools rebar3, proper and jsx +RUN export PATH="$(cat /home/${USER}/LATEST):${PATH}" && \ + latest () { \ + local VSN=$(curl -sL "https://api.github.com/repos/$1/tags" | jq -r ".[] | .name" | grep -E '^v?[0-9]' | sort -V | tail -1); \ + curl -sL "https://github.com/$1/archive/$VSN.tar.gz" > $(basename $1).tar.gz; \ + } && \ + latest erlang/rebar3 && ls -la && \ + (tar xzf rebar3.tar.gz && cd rebar3-* && ./bootstrap && sudo cp rebar3 /usr/bin) && \ + latest proper-testing/proper && \ + (tar xzf proper.tar.gz && mv proper-* proper && cd proper && make) && \ + latest talentdeficit/jsx && \ + (tar xzf jsx.tar.gz && mv jsx-* jsx && cd jsx && rebar3 compile) -RUN apt-get update && \ - apt-get -y upgrade && \ - apt-get install -y build-essential m4 autoconf fop xsltproc clang clang-format \ - default-jdk libxml2-utils $INSTALL_LIBS +ENV ERL_LIBS=/buildroot/proper:/buildroot/jsx -RUN update-alternatives --set wx-config /usr/lib/x86_64-linux-gnu/wx/config/gtk3-unicode-3.0 +ENTRYPOINT ["/buildroot/init.sh"] diff --git a/.github/dockerfiles/init.sh b/.github/dockerfiles/init.sh new file mode 100755 index 000000000000..3033e3351d03 --- /dev/null +++ b/.github/dockerfiles/init.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +if [ -f "/buildroot/env.sh" ]; then + . "/buildroot/env.sh" +fi + +sudo mkdir -p -m0755 /var/run/sshd + +sudo /usr/sbin/sshd + +sudo service postgresql start + +sudo -E bash -c "apt-get update && apt-get install -y linux-tools-common linux-tools-generic" +sudo -E bash -c "apt-get install -y linux-tools-$(uname-r)" || true + +sudo bash -c "Xvfb :99 -ac -screen 0 1920x1080x24 -nolisten tcp" & +export DISPLAY=:99 + +PATH="$PATH:$(ls -1d /usr/local/lib/erlang-*/bin | tr '\n' ':')" + +exec /bin/bash -c "$1" diff --git a/.github/dockerfiles/log4j.properties b/.github/dockerfiles/log4j.properties new file mode 100644 index 000000000000..79b28f05e913 --- /dev/null +++ b/.github/dockerfiles/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootLogger = INFO, console + +log4j.appender.console = org.apache.log4j.ConsoleAppender + +log4j.appender.console.layout = org.apache.log4j.PatternLayour +log4j.appender.console.layout.ConversionPattern = %d [%t] %-5p %c{1} - %m%n + +log4j.logger.org.apache.fop = INFO +log4j.logger.org.apache.fop.render = INFO diff --git a/.github/dockerfiles/odbc.ini b/.github/dockerfiles/odbc.ini new file mode 100644 index 000000000000..9a36ba48e131 --- /dev/null +++ b/.github/dockerfiles/odbc.ini @@ -0,0 +1,19 @@ +[PostgresLinux64Ubuntu] +Driver = PostgreSQL64 +Description = PostgreSQL Data Source +Servername = localhost +Port = 5432 +Protocol = 10 +UserName = odbctest +Password = odbctest +Database = odbctest + +[PostgresLinuxUbuntu] +Driver = PostgreSQL32 +Description = PostgreSQL Data Source +Servername = localhost +Port = 5432 +Protocol = 10 +UserName = odbctest +Password = odbctest +Database = odbctest diff --git a/.github/dockerfiles/odbcinst.ini b/.github/dockerfiles/odbcinst.ini new file mode 100644 index 000000000000..d26e6de7f4b1 --- /dev/null +++ b/.github/dockerfiles/odbcinst.ini @@ -0,0 +1,15 @@ +[PostgreSQL64] +Description = PostgreSQL Data Source +Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbca.so +Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcpsqlS.so +Debug = 0 +CommLog = 1 +UsageCount = 2 + +[PostgreSQL32] +Description = PostgreSQL Data Source +Driver = /usr/lib/i386-linux-gnu/odbc/psqlodbca.so +Setup = /usr/lib/i386-linux-gnu/odbc/libodbcpsqlS.so +Debug = 0 +CommLog = 1 +UsageCount = 2 \ No newline at end of file diff --git a/.github/scripts/base-tag b/.github/scripts/base-tag deleted file mode 100755 index b2a8017bfc12..000000000000 --- a/.github/scripts/base-tag +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -x - -case "$1" in - *i386-debian-base) - BASE="i386/debian:bullseye" - BASE_TYPE=debian-base - ;; - *debian-base) - BASE="debian:bullseye" - BASE_TYPE=debian-base - ;; - *ubuntu-base) - BASE="ubuntu:20.04" - BASE_TYPE=ubuntu-base - ;; -esac -echo "::set-output name=BASE::${BASE}" -echo "::set-output name=BASE_TYPE::${BASE_TYPE}" diff --git a/.github/scripts/build-base-image.sh b/.github/scripts/build-base-image.sh new file mode 100755 index 000000000000..7069ef391a00 --- /dev/null +++ b/.github/scripts/build-base-image.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +BASE_BRANCH="$1" + +case "${BASE_BRANCH}" in + master|maint|maint-*) + ;; + *) + BASE_BRANCH="master" + ;; +esac + +if [ -z "${BASE_TAG}" ]; then + BASE_TAG=$(grep "ARG BASE=" ".github/dockerfiles/Dockerfile.${2}" | head -1 | tr '=' ' ' | awk '{print $3}') +fi + +case "${BASE_TAG}" in + *i386-debian-base) + BASE="i386/debian:bullseye" + BASE_TYPE=debian-base + ;; + *debian-base) + BASE="debian:bullseye" + BASE_TYPE=debian-base + ;; + *ubuntu-base) + BASE="ubuntu:20.04" + BASE_TYPE=ubuntu-base + ;; +esac + +echo "BASE=${BASE}" >> $GITHUB_OUTPUT +echo "BASE_TAG=${BASE_TAG}" >> $GITHUB_OUTPUT +echo "BASE_TYPE=${BASE_TYPE}" >> $GITHUB_OUTPUT + +if [ -f "otp_docker_base.tar" ]; then + docker load -i "otp_docker_base.tar" + echo "BASE_BUILD=loaded" >> $GITHUB_OUTPUT +elif [ -f "otp_docker_base/otp_docker_base.tar" ]; then + docker load -i "otp_docker_base/otp_docker_base.tar" + echo "BASE_BUILD=loaded" >> $GITHUB_OUTPUT +else + if [ "${BASE_USE_CACHE}" != "false" ]; then + docker pull "${BASE_TAG}:${BASE_BRANCH}" + docker tag "${BASE_TAG}:${BASE_BRANCH}" "${BASE_TAG}:latest" + BASE_CACHE="--cache-from ${BASE_TAG}" + fi + + BASE_IMAGE_ID=$(docker images -q "${BASE_TAG}:latest") + + docker build --pull --tag "${BASE_TAG}:latest" \ + ${BASE_CACHE} \ + --file ".github/dockerfiles/Dockerfile.${BASE_TYPE}" \ + --build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \ + --build-arg USER=otptest --build-arg GROUP=uucp \ + --build-arg uid="$(id -u)" \ + --build-arg BASE="${BASE}" .github/ + + NEW_BASE_IMAGE_ID=$(docker images -q "${BASE_TAG}:latest") + if [ "${BASE_IMAGE_ID}" = "${NEW_BASE_IMAGE_ID}" ]; then + echo "BASE_BUILD=cached" >> $GITHUB_OUTPUT + else + echo "BASE_BUILD=re-built" >> $GITHUB_OUTPUT + docker save "${BASE_TAG}:latest" > "otp_docker_base.tar" + fi +fi diff --git a/.github/scripts/build-macos-wxwidgets.sh b/.github/scripts/build-macos-wxwidgets.sh new file mode 100755 index 000000000000..be087d9f9bbf --- /dev/null +++ b/.github/scripts/build-macos-wxwidgets.sh @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +export MAKEFLAGS=-j$(getconf _NPROCESSORS_ONLN) + +if [ -z "$WXWIDGETS_VERSION" ]; then + WXWIDGETS_VERSION=3.1.5 +fi + +vsn=$WXWIDGETS_VERSION +curl --fail -LO https://github.com/wxWidgets/wxWidgets/releases/download/v$vsn/wxWidgets-$vsn.tar.bz2 +tar -xf wxWidgets-$vsn.tar.bz2 +mv wxWidgets-$vsn/ wxWidgets + +cd wxWidgets +./configure \ + --disable-shared \ + --prefix=$PWD/release \ + --with-cocoa \ + --with-macosx-version-min=10.15 \ + --with-libjpeg=builtin \ + --with-libtiff=builtin \ + --with-libpng=builtin \ + --with-liblzma=builtin \ + --with-zlib=builtin \ + --with-expat=builtin +make +make install diff --git a/.github/scripts/build-macos.sh b/.github/scripts/build-macos.sh new file mode 100755 index 000000000000..73c35a6a22d3 --- /dev/null +++ b/.github/scripts/build-macos.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)" +export ERL_TOP="$(pwd)" +export ERLC_USE_SERVER=true +export RELEASE_ROOT="$ERL_TOP/release" +BUILD_DOCS=false + +if [ "$1" = "build_docs" ]; then + BUILD_DOCS=true + shift +fi + +./otp_build configure $* +./otp_build boot -a +./otp_build release -a "$RELEASE_ROOT" +if $BUILD_DOCS; then + make release_docs DOC_TARGETS=chunks +fi diff --git a/.github/scripts/get-pr-number.es b/.github/scripts/get-pr-number.es new file mode 100755 index 000000000000..a388e6107a68 --- /dev/null +++ b/.github/scripts/get-pr-number.es @@ -0,0 +1,57 @@ +#!/usr/bin/env escript +%%! -pa jsx/_build/default/lib/jsx/ebin/ +-mode(compile). + +main([Repo, HeadSha]) -> + io:format("Looking for: ~ts",[HeadSha]), + AllOpenPrs = ghapi("gh api --paginate -X GET /repos/"++Repo++"/pulls -f state=open"), + case lists:search( + fun(#{ <<"number">> := NR, <<"head">> := #{ <<"sha">> := Sha }}) -> + io:format("~p: Checking ~ts~n",[NR, Sha]), + string:equal(HeadSha, Sha) + end, AllOpenPrs) of + {value, #{ <<"number">> := Number } } -> + append_to_github_output("result=~p~n", [Number]); + false -> + append_to_github_output("result=~ts~n", [""]) + end. + +append_to_github_output(Fmt, Args) -> + case os:getenv("GITHUB_OUTPUT") of + false -> + io:format(standard_error, "GITHUB_OUTPUT env var missing?~n", []); + GitHubOutputFile -> + {ok, F} = file:open(GitHubOutputFile, [write, append]), + ok = io:fwrite(F, Fmt, Args), + ok = file:close(F) + end. + +ghapi(CMD) -> + decode(cmd(CMD)). + +decode(Data) -> + try jsx:decode(Data,[{return_maps, true}, return_tail]) of + {with_tail, Json, <<>>} -> + Json; + {with_tail, Json, Tail} -> + lists:concat([Json | decodeTail(Tail)]) + catch E:R:ST -> + io:format("Failed to decode: ~ts",[Data]), + erlang:raise(E,R,ST) + end. + +decodeTail(Data) -> + try jsx:decode(Data,[{return_maps, true}, return_tail]) of + {with_tail, Json, <<>>} -> + [Json]; + {with_tail, Json, Tail} -> + [Json | decodeTail(Tail)] + catch E:R:ST -> + io:format(standard_error, "Failed to decode: ~ts",[Data]), + erlang:raise(E,R,ST) + end. + +cmd(CMD) -> + ListCmd = unicode:characters_to_list(CMD), + io:format("cmd: ~ts~n",[ListCmd]), + unicode:characters_to_binary(os:cmd(ListCmd)). diff --git a/.github/scripts/init-pre-release.sh b/.github/scripts/init-pre-release.sh index 7a86f3052c0c..c7b7cab617df 100755 --- a/.github/scripts/init-pre-release.sh +++ b/.github/scripts/init-pre-release.sh @@ -3,4 +3,33 @@ ## We create a tar ball that is used later by build-otp-tar ## to create the pre-built tar ball -git archive --prefix otp/ -o otp_src.tar.gz HEAD +AUTOCONF=0 +TARGET=otp_src.tar.gz + +if [ -n "$1" ]; then + TARGET="$1" +fi + +## This script is used to create archives for older releases +## so if configure does not exist in the git repo we need to +## create it. +if [ ! -f configure ]; then + ./otp_build autoconf + find . -name aclocal.m4 | xargs git add -f + find . -name configure | xargs git add -f + find . -name config.h.in | xargs git add -f + find . -name config.guess | xargs git add -f + find . -name config.sub | xargs git add -f + find . -name install-sh | xargs git add -f + if ! git config user.name; then + git config user.email "you@example.com" + git config user.name "Your Name" + fi + git commit --no-verify -m 'Add generated configure files' + AUTOCONF=1 +fi +git archive --prefix otp/ -o "$TARGET" HEAD + +if [ "$AUTOCONF" = 1 ]; then + git reset --hard HEAD~1 +fi diff --git a/.github/scripts/path-filters.sh b/.github/scripts/path-filters.sh new file mode 100755 index 000000000000..f55bd168cf38 --- /dev/null +++ b/.github/scripts/path-filters.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +cat < { + + console.log(`Workflow: ${JSON.stringify(context.payload.workflow_run,null,2)}`); + + /* We use this link service as github does not (yet) expose an API where + you can download an artifact. + https://github.com/actions/upload-artifact/issues/50 + */ + var nightlyURL = (artifact) => { + return `https://nightly.link/${context.repo.owner}/${context.repo.repo}/actions/artifacts/${artifact.id}.zip` + }; + + const artifacts = await github.paginate( + github.rest.actions.listWorkflowRunArtifacts, + { + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + per_page: 100 + }); + + const ct_logs = artifacts.find( + (a) => { return a.name == 'test_results'; }); + const html_docs = artifacts.find( + (a) => { return a.name == 'otp_doc_html'; }); + const win_exe = artifacts.find( + (a) => { return a.name.match(/win32/); }); + + let gh_comments = await github.paginate( + github.rest.issues.listComments, + { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + per_page: 100 + }); + + /* We find the newest comment by "github-actions[bot]". There really should + only be one, but the PR scripts may be buggy and if so we want to updated + the latest post. */ + gh_comments.reverse(); + const gh_comment = gh_comments.find(c => c.user.login == "github-actions[bot]"); + + console.log(`Comment to update: ${JSON.stringify(gh_comment,null,2)}`); + + let ct_body; + + /* The EnricoMi/publish-unit-test-result-action@v1 action creates/updates a comment + to always start with "## CT Test Results". Below we append some data to that + comment to further help the user. + */ + + if (gh_comment && !gh_comment.body.match("")) { + /* If the comment does not have a marker, it has been touched by + EnricoMi/publish-unit-test-result-action@v1 and then we need + to update the comment */ + ct_body = gh_comment.body; + } else if (gh_comment && state == 'starting') { + /* If the comment exists and we are just starting the workflow we do nothing */ + return; + } else { + /* if the comment does not exist we use a place holder comment. This + needs to start with "## CT Test Results" and + contain "Results for commit" as otherwise + EnricoMi/publish-unit-test-result-action@v1 will create a new comment. */ + ct_body = "## CT Test Results\n\n"; + if (state == 'starting') { + ct_body += `Tests are running... ${context.payload.workflow_run.html_url}\n\n`; + } else { + ct_body += "No tests were run for this PR. This is either because the build failed, or the PR is based on a branch without GH actions tests configured.\n\n"; + } + ct_body += `Results for commit ${context.payload.workflow_run.head_sha}`; + } + + console.log(`ct_body: ${ct_body}`); + + const body = `${ct_body} + + + +To speed up review, make sure that you have read [Contributing to Erlang/OTP](/${context.repo.owner}/${context.repo.repo}/blob/master/CONTRIBUTING.md) and that all [checks](/${context.repo.owner}/${context.repo.repo}/pull/${pr_number}/checks) pass. + +See the [TESTING](/${context.repo.owner}/${context.repo.repo}/blob/master/HOWTO/TESTING.md) and [DEVELOPMENT](/${context.repo.owner}/${context.repo.repo}/blob/master/HOWTO/DEVELOPMENT.md) HowTo guides for details about how to run test locally. + +## Artifacts +* ` + (ct_logs ? `[Complete CT logs](https://erlang.github.io/prs/${pr_number}/ct_logs/index.html) ([Download Logs](${nightlyURL(ct_logs)}))` : "No CT logs found") + ` +* ` + (html_docs ? `[HTML Documentation](https://erlang.github.io/prs/${pr_number}/doc/index.html) ([Download HTML Docs](${nightlyURL(html_docs)}))` : "No HTML docs found") + ` +* ` + (win_exe ? `[Windows Installer](${nightlyURL(win_exe)})` : "No Windows Installer found") + ` + +// Erlang/OTP Github Action Bot +`; + if (gh_comment) { + if (gh_comment.body != body) { + console.log("Update comment: " + gh_comment.id); + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: gh_comment.id, + body: body + }); + } + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + body: body + }); + } +}; diff --git a/.github/scripts/restore-from-prebuilt.sh b/.github/scripts/restore-from-prebuilt.sh new file mode 100755 index 000000000000..9fff27c28379 --- /dev/null +++ b/.github/scripts/restore-from-prebuilt.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +set -xe + +CACHE_SOURCE_DIR="$1" +TARGET="$2" +ARCHIVE="$3" +EVENT="$4" +DELETED="$5" +CHANGES="$9" + +if [ ! -f "${CACHE_SOURCE_DIR}/otp_src.tar.gz" ] || [ "${NO_CACHE}" = "true" ]; then + cp "${ARCHIVE}" "${TARGET}" + cp "${ARCHIVE}" "${CACHE_SOURCE_DIR}/otp_src.tar.gz" + exit 0 +fi + +TMP_DIR=$(mktemp -d) +CACHE_DIR="${TMP_DIR}" +ARCHIVE_DIR="${TMP_DIR}/archive" + +mkdir "${ARCHIVE_DIR}" + +################################# +## START WORK ON THE CACHED FILES +################################# +echo "::group::{Restore cached files}" +tar -C "${CACHE_DIR}/" -xzf "${CACHE_SOURCE_DIR}/otp_src.tar.gz" + +## If configure scripts have NOT changed, we can restore configure and other C/java programs +if [ -z "${CONFIGURE}" ] || [ "${CONFIGURE}" = "false" ]; then + tar -C "${CACHE_DIR}/" -xzf "${CACHE_SOURCE_DIR}/otp_cache.tar.gz" +fi + +## If bootstrap has been changed, we do not use the cached .beam files +EXCLUDE_BOOTSTRAP=() +if [ "${BOOTSTRAP}" = "true" ]; then + find "${CACHE_DIR}/otp/lib" -name "*.beam" -exec rm -f {} \; +else + EXCLUDE_BOOTSTRAP=(--exclude "bootstrap") +fi + +## Make a copy of the cache for debugging +mkdir "${TMP_DIR}/cache" +cp -rp "${CACHE_DIR}/otp" "${TMP_DIR}/cache/" + +CACHE_DIR="${CACHE_DIR}/otp" + +echo "::group::{Delete files from PR}" +## Delete any files that this PR deletes +for delete in $DELETED; do + if [ -d "${CACHE_DIR}/${delete}" ]; then + rm -r "${CACHE_DIR}/${delete}" + elif [ -f "${CACHE_DIR}/${delete}" ]; then + rm "${CACHE_DIR}/${delete}" + else + echo "Could not find $delete to delete" + exit 1 + fi +done + +################################## +## START WORK ON THE UPDATED FILES +################################## + +echo "::group::{Extract changed files}" +if [ -n "${ARCHIVE}" ]; then + ## Extract with updated timestamp (the -m flag) so that any change will trigger a rebuild + tar -C "${ARCHIVE_DIR}/" -xzmf "${ARCHIVE}" + + ## Directory permissions in the archive and cache are for some reason different... + chmod -R g-w "${ARCHIVE_DIR}/" + + ## rlpgoD is the same as --archive, but without --times + RSYNC_ARGS=(-rlpgoD --itemize-changes --verbose --checksum --update "${EXCLUDE_BOOTSTRAP[@]}" "${ARCHIVE_DIR}/otp/" "${CACHE_DIR}/") + + CHANGES="${TMP_DIR}/changes" + PREV_CHANGES="${TMP_DIR}/prev-changes" + + touch "${PREV_CHANGES}" + + ## Below follows some rules about when we do not want to use the cache + ## The rules are run multiple times so that if any rule triggeres a delte + ## we will re-run the rules again with the new changes. + for i in $(seq 1 10); do + + echo "::group::{Run ${i} at pruning cache}" + + ## First do a dry run to see if we need to delete anything from cache + rsync --dry-run "${RSYNC_ARGS[@]}" | grep '^\(>\|c\)' > "${TMP_DIR}/changes" + cat "${TMP_DIR}/changes" + + if cmp -s "${CHANGES}" "${PREV_CHANGES}"; then + break; + fi + + ### If any parse transform is changed we recompile everything as we have + ### no idea what it may change. If the parse transform calls any other + ### modules we really should delete the cache for those as well, but + ### it is impossible for us to know which modules are used by a pt so + ### this has to be somekind of best effort. + echo "::group::{Run ${i}: parse transforms}" + PARSE_TRANSFORMS=$(grep -r '^parse_transform(' "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}' | uniq) + for pt in $PARSE_TRANSFORMS; do + if grep "$(basename "${pt}")" "${CHANGES}"; then + echo "Deleting entire cache as a parse transform has changed" >&2 + rm -rf "${CACHE_DIR:?}/" + fi + done + + echo "::group::{Run ${i}: yecc}" + ### if yecc has changed, need to recompile all .yrl files + if grep "yecc.erl$" "${CHANGES}"; then + echo "Deleting all .yrl files as yecc has changed" >&2 + find "${CACHE_DIR}/" -name "*.yrl" -exec rm -f {} \; + fi + + echo "::group::{Run ${i}: asn1}" + ### If asn1 has changed, need to re-compile all .asn1 files + if grep lib/asn1 "${CHANGES}"; then + echo "Deleting all .asn1 files as asn1 has changed" >&2 + find "${CACHE_DIR}/" -name "*.asn1" -exec rm -f {} \; + fi + + echo "::group::{Run ${i}: docs}" + ### If any of the doc generating tools change, we need to re-compile the docs + if grep "lib/\(xmerl\|erl_docgen\|edoc\)" "${CHANGES}"; then + echo "Deleting all docs as documentation tools have changed" >&2 + rm -rf "${CACHE_DIR}"/lib/*/doc/ "${CACHE_DIR}/erts/doc/" "${CACHE_DIR}/system/" + fi + + ### Find all behaviours in OTP and check if any them as changed, we need to + ### rebuild all files that use them. + echo "::group::{Run ${i}: behaviours}" + BEHAVIOURS=$(grep -r "^-callback" "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}' | uniq | sed 's:.*/\([^/.]*\)[.]erl$:\1:') + for behaviour in $BEHAVIOURS; do + if grep "${behaviour}[.]erl\$" "${CHANGES}"; then + echo "Deleting files using ${behaviour} has it has changed" >&2 + FILES=$(grep -r "^-behaviour(${behaviour})" "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}') + rm -f $FILES + fi + done + + if [ "$i" = "10" ]; then + echo "Deleting entire cache as it did not stabalize in trime" >&2 + rm -rf "${CACHE_DIR:?}" + else + mv "${CHANGES}" "${PREV_CHANGES}" + fi + done + + echo "::group::{Sync changes over cached data}" + + ## Now we do the actual sync + rsync "${RSYNC_ARGS[@]}" +fi + +tar -czf "${TARGET}" -C "${TMP_DIR}" otp + +rm -rf "${TMP_DIR}" + +echo "::endgroup::" diff --git a/.github/scripts/sync-github-prs.es b/.github/scripts/sync-github-prs.es new file mode 100755 index 000000000000..6560ae5e020e --- /dev/null +++ b/.github/scripts/sync-github-prs.es @@ -0,0 +1,191 @@ +#!/usr/bin/env escript +%%! -pa jsx/_build/default/lib/jsx/ebin/ +%% +%% This scripts downloads the docs + test results from an otp repo +%% into the Target folder. It tries its best to not create too large +%% files so that gh will still be happy with us when this is published to +%% gh pages +-mode(compile). + +main([Repo, Target]) -> + AllOpenPrs = ghapi("gh api --paginate -X GET /repos/"++Repo++"/pulls -f state=open"), + %% Download all updates, there really should not be any to download as they + %% are updated when a PR is updated, but we do it anyways just to be safe. + handle_prs(Repo, Target,AllOpenPrs), + + %% Delete any PRs that have been closed + {ok, AllPrs} = file:list_dir(Target), + lists:foreach( + fun(PRNo) -> + case lists:search( + fun(#{ <<"number">> := No }) -> + No =:= list_to_integer(PRNo) + end, AllOpenPrs) of + {value, _} -> + ok; + false -> + cmd("rm -rf " ++ filename:join(Target,PRNo)) + end + end, AllPrs); +main([Repo, Target, PRNo]) -> + handle_prs(Repo, Target, [ghapi("gh api /repos/"++Repo++"/pulls/"++PRNo)]). + +handle_prs(Repo, Target, AllPRs) -> + + %% We fetch all runs for the main.yaml repo. This takes a while, + %% but for some reason when we try to filter results using either + %% -f event=pull_request or -f branch=Ref github decides to not + %% return all the runs.... So we do it the slow way... + AllRuns = ghapi(["gh api --paginate -X GET /repos/"++Repo++"/actions/workflows/main.yaml/runs"]), + + [handle_pr(Repo, Target, PR, AllRuns) || PR <- AllPRs], + + %% Remove all links and files > 50MB + cmd(["find ",Target," -type l -exec rm -f {} \\;"]), + cmd(["find ",Target," -type f -size +50M -exec rm -f {} \\;"]), + + ok. + +%% In order to get the latest gh actions run for a PR, we have to first list +%% all workflow runs for that branch, and then look for a matching sha with the +%% current top of the PR. Github does not have any API to find it any other way. +%% See https://github.community/t/retrieve-workflow-id-for-a-given-pr/199745/4 +%% for a discussion about this. +%% +handle_pr(_Repo, Target, + #{ <<"number">> := Number, + <<"head">> := #{ <<"ref">> := _Ref, <<"sha">> := Sha } }, + Runs) -> + PRDir = filename:join(Target,integer_to_list(Number)), + case lists:search( + fun(#{ <<"head_sha">> := HeadSha, <<"status">> := Status }) -> + string:equal(HeadSha, Sha) andalso string:equal(Status, <<"completed">>) + end, maps:get(<<"workflow_runs">>, Runs)) of + {value, Run} -> + Ident = integer_to_list( + erlang:phash2( + {maps:get(<<"id">>,Run), ?MODULE:module_info(md5)})), + io:format("Checking for ~ts~n", [filename:join(PRDir, Ident)]), + case file:read_file_info(filename:join(PRDir, Ident)) of + {error, enoent} -> + cmd("rm -rf "++PRDir), + ok = file:make_dir(PRDir), + ok = file:write_file(filename:join(PRDir,Ident), integer_to_list(Number)), + + #{ <<"artifacts">> := Artifacts } = + ghapi(["gh api --paginate -X GET ",maps:get(<<"artifacts_url">>, Run)]), + + lists:foreach( + fun(#{ <<"name">> := <<"test_results">>, <<"archive_download_url">> := Url }) -> + cmd(["gh api ", unicode:characters_to_list(Url), " > /tmp/test_results.zip"]), + cmd("unzip -d /tmp/test_results /tmp/test_results.zip"), + cmd(["tar xvzf /tmp/test_results/test_results.tar.gz " + "-C ",PRDir," make_test_dir/ct_logs --strip-components=1"]), + cmd("rm -rf /tmp/test_results*"); + (#{ <<"name">> := <<"otp_doc_html">>, <<"archive_download_url">> := Url }) -> + cmd(["gh api ", unicode:characters_to_list(Url), " > /tmp/otp_doc_html.zip"]), + cmd("unzip -d /tmp/otp_doc_html /tmp/otp_doc_html.zip"), + cmd(["tar xvzf /tmp/otp_doc_html/otp_doc_html.tar.gz -C ",PRDir]), + cmd(["find ",PRDir," -name '*.pdf' -exec rm -f {} \\;"]), + cmd("rm -rf /tmp/otp_doc_html*"); + (_) -> + ok + end, Artifacts), + CTLogsIndex = filename:join([PRDir,"ct_logs","index.html"]), + case file:read_file_info(CTLogsIndex) of + {ok, _} -> + CTSuiteFiles = filename:join([PRDir,"ct_logs","ct_run*","*.logs","run.*","suite.log"]), + lists:foreach(fun purge_suite/1, filelib:wildcard(CTSuiteFiles)); + _ -> + ok = filelib:ensure_dir(CTLogsIndex), + ok = file:write_file(CTLogsIndex, ["No test logs found for ", Sha]) + end, + DocIndex = filename:join([PRDir,"doc","index.html"]), + case file:read_file_info(DocIndex) of + {ok, _} -> ok; + _ -> ok = filelib:ensure_dir(DocIndex), + ok = file:write_file(DocIndex, ["No documentation found for ", Sha]) + end; + {ok,_} -> + ok + end; + false -> + ok + end. + +%% We truncate the logs of all testcases of any suite that did not have any failures +purge_suite(SuiteFilePath) -> + {ok, SuiteFile} = file:read_file(SuiteFilePath), + SuiteDir = filename:dirname(SuiteFilePath), + Placeholder = "github truncated successful testcase", + case re:run(SuiteFile,"^=failed\s*\([0-9]+\)$",[multiline,{capture,all_but_first,binary}]) of + {match,[<<"0">>]} -> + io:format("Purging logs from: ~ts~n",[SuiteDir]), + ok = file:del_dir_r(filename:join(SuiteDir,"log_private")), + lists:foreach( + fun(File) -> + case filename:basename(File) of + "suite" ++ _ -> + ok; + "unexpected_io" ++_ -> + ok; + "cover.html" -> + ok; + _Else -> + file:write_file(File,Placeholder) + end + end, filelib:wildcard(filename:join(SuiteDir,"*.html"))); + _FailedTestcases -> + io:format("Purging logs from: ~ts~n",[SuiteDir]), + lists:foreach( + fun(File) -> + {ok, B} = file:read_file(File), + case re:run(B,"^=== Config value:",[multiline]) of + {match,_} -> + case re:run(B,"^=== successfully completed test case",[multiline]) of + {match, _} -> + file:write_file(File,Placeholder); + nomatch -> + ok + end; + nomatch -> + ok + end + end, filelib:wildcard(filename:join(SuiteDir,"*.html"))) + end. + +ghapi(CMD) -> + decode(cmd(CMD)). + +decode(Data) -> + try jsx:decode(Data,[{return_maps, true}, return_tail]) of + {with_tail, Json, <<>>} -> + Json; + {with_tail, Json, Tail} when is_map(Json) -> + [Key] = maps:keys(maps:remove(<<"total_count">>, Json)), + #{ Key => lists:flatmap( + fun(J) -> maps:get(Key, J) end, + [Json | decodeTail(Tail)]) + }; + {with_tail, Json, Tail} when is_list(Json) -> + lists:concat([Json | decodeTail(Tail)]) + catch E:R:ST -> + io:format("Failed to decode: ~ts",[Data]), + erlang:raise(E,R,ST) + end. + +decodeTail(Data) -> + try jsx:decode(Data,[{return_maps, true}, return_tail]) of + {with_tail, Json, <<>>} -> + [Json]; + {with_tail, Json, Tail} -> + [Json | decodeTail(Tail)] + catch E:R:ST -> + io:format("Failed to decode: ~ts",[Data]), + erlang:raise(E,R,ST) + end. + +cmd(CMD) -> + ListCmd = unicode:characters_to_list(CMD), + io:format("cmd: ~ts~n",[ListCmd]), + unicode:characters_to_binary(os:cmd(ListCmd)). diff --git a/.github/scripts/sync-github-releases.sh b/.github/scripts/sync-github-releases.sh index 763762234f22..b71d5b54a4eb 100755 --- a/.github/scripts/sync-github-releases.sh +++ b/.github/scripts/sync-github-releases.sh @@ -205,12 +205,21 @@ for name in "${ALL_TAGS[@]}"; do _upload_artifacts ${name} done +## Rebuild erlang.org to get links to the new artifacts +if [ ${UPLOADED} = true ]; then + curl -H "Authorization: token ${ERLANG_ORG_TOKEN}" -X POST -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/erlang/erlang-org/actions/workflows/update-gh-cache.yaml/dispatches" -d '{"ref":"master"}' +fi + ## If no assets were uploaded, we try to build one instead if [ ${UPLOADED} = false ] && [ ${#MISSING_PREBUILD[0]} != 0 ]; then name="${MISSING_PREBUILD[0]}" stripped_name=$(_strip_name "${name}") git clone https://github.com/erlang/otp -b "${name}" otp_src - (cd otp_src && ../.github/scripts/init-pre-release.sh) + if [ -f otp_src/.github/scripts/init-pre-release.sh ]; then + (cd otp_src && ERL_TOP=$(pwd) .github/scripts/init-pre-release.sh) + else + (cd otp_src && ERL_TOP=$(pwd) ../.github/scripts/init-pre-release.sh) + fi case ${stripped_name} in 23.**) ## The 32-bit dockerfile build the doc chunks which we want diff --git a/.github/workflows/actions-updater.yaml b/.github/workflows/actions-updater.yaml new file mode 100644 index 000000000000..0e186cf4e117 --- /dev/null +++ b/.github/workflows/actions-updater.yaml @@ -0,0 +1,22 @@ +name: GitHub Actions Updater + +on: + schedule: + # Automatically run on the 1st of every month + - cron: '0 0 1 * *' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run GitHub Actions Version Updater + uses: saadmk11/github-actions-version-updater@v0.7.3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit_message: "Updating GitHub actions to their latest versions" + pull_request_labels: "team:IS" diff --git a/.github/workflows/add-to-project.yaml b/.github/workflows/add-to-project.yaml new file mode 100644 index 000000000000..d387e52f4a05 --- /dev/null +++ b/.github/workflows/add-to-project.yaml @@ -0,0 +1,26 @@ +name: Add bugs to bugs project + +on: + issues: + types: + - opened + pull_request_target: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + if: github.repository == 'erlang/otp' + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v1.8.0 + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PEM }} + - uses: actions/add-to-project@v0.4.0 + with: + project-url: https://github.com/orgs/erlang/projects/13 + github-token: ${{ steps.generate_token.outputs.token }} diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 848940891115..8004ee4e7ca3 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -7,11 +7,10 @@ ## not possible so we need to rebuild all of Erlang/OTP multiple ## times. ## -## When ghcr.io support using the GITHUB_TOKEN we should migrate -## over to use it instead as that should allow us to use the +## Now that we have migrated to ghcr.io we use the ## built-in caching mechanisms of docker/build-push-action@v2. ## However as things are now we use docker directly to make things -## work. +## work due to historical reasons. ## name: Build and check Erlang/OTP @@ -20,21 +19,203 @@ on: push: pull_request: +env: + ## Equivalent to github.event_name == 'pull_request' ? github.base_ref : github.ref_name + BASE_BRANCH: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }} + jobs: pack: - name: Pack the Erlang/OTP tar.gz + name: Build Erlang/OTP (64-bit) runs-on: ubuntu-latest + outputs: + BASE_BUILD: ${{ steps.base-build.outputs.BASE_BUILD }} + changes: ${{ steps.changes.outputs.changes }} + all: ${{ steps.apps.outputs.all }} steps: - - uses: actions/checkout@v2 - - name: Create initial pre-release tar - run: .github/scripts/init-pre-release.sh + - uses: actions/checkout@v3 + - name: Get applications + id: apps + run: | + .github/scripts/path-filters.sh > .github/scripts/path-filters.yaml + ALL_APPS=$(grep '^[a-z_]*:' .github/scripts/path-filters.yaml | sed 's/:.*$//') + ALL_APPS=$(jq -n --arg inarr "${ALL_APPS}" '$inarr | split("\n")' | tr '\n' ' ') + echo "all=${ALL_APPS}" >> $GITHUB_OUTPUT + - uses: dorny/paths-filter@v2 + id: changes + with: + filters: .github/scripts/path-filters.yaml + - name: Create initial pre-release tar + run: .github/scripts/init-pre-release.sh otp_archive.tar.gz - name: Upload source tar archive - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: otp_git_archive - path: otp_src.tar.gz + path: otp_archive.tar.gz + - name: Docker login + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Cache BASE image + uses: actions/cache@v3 + with: + path: otp_docker_base.tar + key: ${{ runner.os }}-${{ hashFiles('.github/dockerfiles/Dockerfile.ubuntu-base', '.github/scripts/build-base-image.sh') }}-${{ hashFiles('OTP-VERSION') }} + - name: Build BASE image + run: .github/scripts/build-base-image.sh "${BASE_BRANCH}" 64-bit + - name: Cache pre-built tar archives + id: pre-built-cache + uses: actions/cache@v3 + with: + path: | + otp_src.tar.gz + otp_cache.tar.gz + key: prebuilt-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + prebuilt-${{ github.base_ref }}-${{ github.event.pull_request.base.sha }} + - uses: dorny/paths-filter@v2 + id: cache + with: + filters: | + no-cache: + - '.github/**' + deleted: + - deleted: '**' + bootstrap: + - 'bootstrap/**' + configure: + - '**.ac' + - '**.in' + list-files: shell + - name: Restore from cache + env: + NO_CACHE: ${{ steps.cache.outputs.no-cache }} + BOOTSTRAP: ${{ steps.cache.outputs.bootstrap }} + CONFIGURE: ${{ steps.cache.outputs.configure }} + run: | + .github/scripts/restore-from-prebuilt.sh "`pwd`" \ + "`pwd`/.github/otp.tar.gz" \ + "`pwd`/otp_archive.tar.gz" \ + '${{ github.event_name }}' \ + '${{ steps.cache.outputs.deleted_files }}' \ + '${{ steps.changes.outputs.changes }}' + - name: Upload restored cache + uses: actions/upload-artifact@v3 + if: runner.debug == 1 + with: + name: restored-cache + path: .github/otp.tar.gz + - name: Build image + run: | + docker build --tag otp \ + --build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \ + --file ".github/dockerfiles/Dockerfile.64-bit" \ + .github/ + - name: Build pre-built tar archives + run: | + docker run -v $PWD:/github --entrypoint "" otp \ + scripts/build-otp-tar -o /github/otp_clean_src.tar.gz /github/otp_src.tar.gz -b /buildroot/otp/ /github/otp_src.tar.gz + - name: Build cache + run: | + if [ -f otp_cache.tar.gz ]; then + gunzip otp_cache.tar.gz + else + docker run -v $PWD:/github --entrypoint "" otp \ + bash -c 'cp ../otp_cache.tar /github/' + fi + docker run -v $PWD:/github --entrypoint "" otp \ + bash -c 'set -x; C_APPS=$(ls -d ./lib/*/c_src); find Makefile ./make ./erts ./bin/`erts/autoconf/config.guess` ./lib/erl_interface ./lib/jinterface ${C_APPS} `echo "${C_APPS}" | sed -e 's:c_src$:priv:'` -type f -newer README.md \! -name "*.beam" \! -path "*/doc/*" | xargs tar --transform "s:^./:otp/:" -uvf /github/otp_cache.tar' + gzip otp_cache.tar + - name: Upload pre-built tar archive + uses: actions/upload-artifact@v3 + with: + name: otp_prebuilt + path: | + otp_src.tar.gz + otp_cache.tar.gz + + build-macos: + name: Build Erlang/OTP (macOS) + runs-on: macos-12 + needs: pack + env: + WXWIDGETS_VERSION: 3.1.5 + steps: + - uses: actions/checkout@v3 + + - name: Download source archive + uses: actions/download-artifact@v3 + with: + name: otp_prebuilt + + - name: Cache wxWidgets + id: wxwidgets-cache + uses: actions/cache@v3 + with: + path: wxWidgets + key: wxWidgets-${{ env.WXWIDGETS_VERSION }}-${{ runner.os }}-12 + + - name: Compile wxWidgets + if: steps.wxwidgets-cache.outputs.cache-hit != 'true' + run: .github/scripts/build-macos-wxwidgets.sh + + - name: Compile Erlang + run: | + tar -xzf ./otp_src.tar.gz + export PATH=$PWD/wxWidgets/release/bin:$PATH + cd otp + $GITHUB_WORKSPACE/.github/scripts/build-macos.sh build_docs --disable-dynamic-ssl-lib + tar -czf otp_macos_$(cat OTP_VERSION)_x86-64.tar.gz -C release . + + - name: Test Erlang + run: | + cd otp/release + ./Install -sasl $PWD + ./bin/erl -noshell -eval 'io:format("~s", [erlang:system_info(system_version)]), halt().' + ./bin/erl -noshell -eval 'ok = crypto:start(), io:format("crypto ok~n"), halt().' + ./bin/erl -noshell -eval '{wx_ref,_,_,_} = wx:new(), io:format("wx ok~n"), halt().' + + - name: Upload tarball + uses: actions/upload-artifact@v3 + with: + name: otp_prebuilt_macos_x86-64 + path: otp/otp_macos_*_x86-64.tar.gz + + build-ios: + env: + RELEASE_LIBBEAM: yes + TARGET_ARCH: aarch64-apple-ios + name: Build Erlang/OTP (iOS) + runs-on: macos-12 + needs: pack + steps: + - uses: actions/checkout@v3 + - name: Download source archive + uses: actions/download-artifact@v3 + with: + name: otp_prebuilt + + - name: Compile Erlang + run: | + tar -xzf ./otp_src.tar.gz + cd otp + $GITHUB_WORKSPACE/.github/scripts/build-macos.sh --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf --without-ssl + - name: Package .xcframework + run: | + cd otp + export BUILD_ARCH=`./erts/autoconf/config.guess` + export LIBS=`find . -not -path "*${BUILD_ARCH}*" -path "*${TARGET_ARCH}*" -not -name "*_st.a" -not -name "*_r.a" -name "*.a" | awk '{ "basename " $1 | getline name; names[name] = $1 } END { for (n in names) { print names[n] }}'` + libtool -static -o liberlang.a $LIBS + xcodebuild -create-xcframework -output ./liberlang.xcframework -library liberlang.a + + - name: Upload framework + uses: actions/upload-artifact@v3 + with: + name: ios_framework_${{ env.TARGET_ARCH }} + path: otp/liberlang.xcframework build-windows: defaults: @@ -42,11 +223,11 @@ jobs: shell: wsl-bash {0} env: WXWIDGETS_VERSION: 3.1.4 - name: Build Erlang/OTP on Windows + name: Build Erlang/OTP (Windows) runs-on: windows-2022 needs: pack steps: - - uses: Vampire/setup-wsl@v1 + - uses: Vampire/setup-wsl@v2 with: distribution: Ubuntu-18.04 @@ -57,10 +238,10 @@ jobs: shell: cmd run: | choco install openssl - move "c:\\Program Files\\OpenSSL-Win64" "c:\\OpenSSL-Win64" + IF EXIST "c:\\Program Files\\OpenSSL-Win64" (move "c:\\Program Files\\OpenSSL-Win64" "c:\\OpenSSL-Win64") ELSE (move "c:\\Program Files\\OpenSSL" "c:\\OpenSSL-Win64") - name: Cache wxWidgets - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: wxWidgets key: wxWidgets-${{ env.WXWIDGETS_VERSION }}-${{ runner.os }} @@ -68,11 +249,13 @@ jobs: # actions/cache on Windows sometimes does not set cache-hit even though there was one. Setting it manually. - name: Set wxWidgets cache id: wxwidgets-cache + env: + WSLENV: GITHUB_OUTPUT/p run: | if [ -d wxWidgets ]; then - echo "::set-output name=cache-hit::true" + echo "cache-hit=true" >> $GITHUB_OUTPUT else - echo "::set-output name=cache-hit::false" + echo "cache-hit=false" >> $GITHUB_OUTPUT fi - name: Download wxWidgets @@ -100,9 +283,9 @@ jobs: nmake TARGET_CPU=amd64 BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc - name: Download source archive - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: - name: otp_git_archive + name: otp_prebuilt - name: Compile Erlang run: | @@ -111,23 +294,79 @@ jobs: tar -xzf ./otp_src.tar.gz cd otp export ERL_TOP=`pwd` - export MAKEFLAGS=-j4 + export MAKEFLAGS=-j$(($(nproc) + 2)) export ERLC_USE_SERVER=true export ERTS_SKIP_DEPEND=true eval `./otp_build env_win32 x64` ./otp_build configure - if cat erts/CONF_INFO || cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi + if cat erts/CONF_INFO || + grep -v "Static linking with OpenSSL 3.0" lib/*/CONF_INFO || + cat lib/*/SKIP || + cat lib/SKIP-APPLICATIONS; then + exit 1 + fi ./otp_build boot -a ./otp_build release -a cp /mnt/c/opt/local64/pgm/wxWidgets-${{ env.WXWIDGETS_VERSION }}/3rdparty/webview2/runtimes/win-x64/native/WebView2Loader.dll $ERL_TOP/release/win32/erts-*/bin/ ./otp_build installer_win32 - name: Upload installer - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: - name: otp_prebuilt_win32 + name: otp_win32_installer path: otp/release/win32/otp*.exe + build-flavors: + name: Build Erlang/OTP (Types and Flavors) + runs-on: ubuntu-latest + needs: pack + if: contains(needs.pack.outputs.changes, 'emulator') + + steps: + - uses: actions/checkout@v3 + ## Download docker images + - name: Cache BASE image + uses: actions/cache@v3 + with: + path: otp_docker_base.tar + key: ${{ runner.os }}-${{ hashFiles('.github/dockerfiles/Dockerfile.ubuntu-base', '.github/scripts/build-base-image.sh') }} + - name: Docker login + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build BASE image + run: .github/scripts/build-base-image.sh "${BASE_BRANCH}" 64-bit + - name: Cache pre-built tar archives + uses: actions/cache@v3 + with: + path: | + otp_src.tar.gz + otp_cache.tar.gz + key: prebuilt-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + prebuilt-${{ github.ref_name }}-${{ github.sha }} + - name: Build image + run: | + .github/scripts/restore-from-prebuilt.sh `pwd` .github/otp.tar.gz + rm -f otp_{src,cache}.tar.gz + docker build --tag otp \ + --build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \ + --file ".github/dockerfiles/Dockerfile.64-bit" \ + .github/ + - name: Build Erlang/OTP flavors and types + run: | + TYPES="opt debug lcnt" + FLAVORS="emu jit" + for TYPE in ${TYPES}; do + for FLAVOR in ${FLAVORS}; do + echo "::group::{TYPE=$TYPE FLAVOR=$FLAVOR}" + docker run otp "make TYPE=$TYPE FLAVOR=$FLAVOR" + echo "::endgroup::" + done + done + build: name: Build Erlang/OTP runs-on: ubuntu-latest @@ -135,95 +374,332 @@ jobs: strategy: matrix: - type: [64-bit,32-bit,cross-compile,documentation] + type: [32-bit,cross-compile,clang] fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Download source archive - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: - name: otp_git_archive + name: otp_prebuilt - name: Docker login - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: - registry: docker.pkg.github.com + registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Calculate BASE image - id: base - run: | - BASE_TAG=$(grep "^FROM" .github/dockerfiles/Dockerfile.${{ matrix.type }} | head -1 | awk '{print $2}') - echo "::set-output name=BASE_TAG::${BASE_TAG}" - .github/scripts/base-tag "${BASE_TAG}" - - name: Pull BASE image - run: docker pull ${{ steps.base.outputs.BASE_TAG }} - - name: Build BASE image + - name: Cleanup GH Runner run: | - docker build --pull --tag ${{ steps.base.outputs.BASE_TAG }} \ - --cache-from ${{ steps.base.outputs.BASE_TAG }} \ - --file .github/dockerfiles/Dockerfile.${{ steps.base.outputs.BASE_TYPE }} \ - --build-arg BASE=${{ steps.base.outputs.BASE }} . + ## Delete large files from runner to get more disk space + ## See https://github.com/actions/runner-images/issues/2840 + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + - name: Cache BASE image + uses: actions/cache@v3 + if: matrix.type == 'clang' + with: + path: otp_docker_base.tar + key: ${{ runner.os }}-${{ hashFiles('.github/dockerfiles/Dockerfile.ubuntu-base', '.github/scripts/build-base-image.sh') }} + - name: Build base image + run: .github/scripts/build-base-image.sh "${BASE_BRANCH}" ${{ matrix.type }} - name: Build ${{ matrix.type }} image run: | + mv otp_src.tar.gz .github/otp.tar.gz docker build --tag otp --file .github/dockerfiles/Dockerfile.${{ matrix.type }} \ - --build-arg ARCHIVE=otp_src.tar.gz . + .github - ## Smoke build tests - - if: matrix.type == '32-bit' || matrix.type == '64-bit' || matrix.type == 'cross-compile' - name: Run smoke test - run: docker run -v $PWD/scripts:/scripts otp "cd /tests && /scripts/run-smoke-tests" + documentation: + name: Build and check documentation + runs-on: ubuntu-latest + needs: pack + steps: + - uses: actions/checkout@v3 + ## Download docker images + - name: Docker login + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Cache BASE image + uses: actions/cache@v3 + with: + path: otp_docker_base.tar + key: ${{ runner.os }}-${{ hashFiles('.github/dockerfiles/Dockerfile.ubuntu-base', '.github/scripts/build-base-image.sh') }} + - name: Build BASE image + run: .github/scripts/build-base-image.sh "${BASE_BRANCH}" 64-bit + - name: Cache pre-built tar archives + uses: actions/cache@v3 + with: + path: | + otp_src.tar.gz + otp_cache.tar.gz + key: prebuilt-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + prebuilt-${{ github.ref_name }}-${{ github.sha }} + - name: Build image + run: | + .github/scripts/restore-from-prebuilt.sh `pwd` .github/otp.tar.gz + rm -f otp_{src,cache}.tar.gz + docker build --tag otp \ + --build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \ + --file ".github/dockerfiles/Dockerfile.64-bit" \ + .github/ - ## Documentation checks - - if: matrix.type == 'documentation' - name: Run xmllimt - run: docker run otp "make xmllint" - - if: matrix.type == 'documentation' - name: Run html link check - run: docker run -v $PWD/scripts:/scripts otp "/scripts/otp_html_check /otp doc/index.html" - - if: matrix.type == 'documentation' - name: Release docs to publish - run: .github/scripts/release-docs.sh - - if: matrix.type == 'documentation' - name: Upload html documentation archive - uses: actions/upload-artifact@v2 + ## Build all the documentation + - name: Build documentation + run: | + docker build -t otp - < /proc/sys/kernel/core_pattern" + docker run --ulimit core=-1 --ulimit nofile=5000:5000 --pids-limit 512 \ + -e CTRUN_TIMEOUT=90 -e SPEC_POSTFIX=gh \ + -e TEST_NEEDS_RELEASE=true -e "RELEASE_ROOT=/buildroot/otp/Erlang ∅⊤℞" \ + -e EXTRA_ARGS="-ct_hooks cth_surefire [{path,\"/buildroot/otp/$DIR/make_test_dir/${{ matrix.type }}_junit.xml\"}]" \ + -v "$PWD/make_test_dir:/buildroot/otp/$DIR/make_test_dir" \ + -v "$PWD/scripts:/buildroot/otp/scripts" \ + otp "make TYPE=${TYPE} && make ${APP}_test TYPE=${TYPE}" + ## Rename os_mon to debug for debug build + if [ "$APP" != "${{ matrix.type }}" ]; then + mv make_test_dir/${APP}_test "make_test_dir/${{ matrix.type }}_test" + fi + - name: Cleanup tests + if: always() + run: | + rm -rf make_test_dir/otp || true + sudo bash -c "chown -R `whoami` make_test_dir && chmod -R +r make_test_dir" + tar czf ${{ matrix.type }}_test_results.tar.gz make_test_dir + - name: Upload test results + uses: actions/upload-artifact@v3 + if: always() with: - name: otp_prebuilt - path: otp_src.tar.gz + name: ${{ matrix.type }}_test_results + path: ${{ matrix.type }}_test_results.tar.gz + + system-test: + name: Test Erlang/OTP (system) + runs-on: ubuntu-latest + if: always() # Run even if the need has failed + needs: test + steps: + - uses: actions/checkout@v3 + - name: Cache BASE image + uses: actions/cache@v3 + with: + path: otp_docker_base.tar + key: ${{ runner.os }}-${{ hashFiles('.github/dockerfiles/Dockerfile.ubuntu-base', '.github/scripts/build-base-image.sh') }} + - name: Docker login + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build BASE image + run: .github/scripts/build-base-image.sh "${BASE_BRANCH}" 64-bit + - name: Download test results + uses: actions/download-artifact@v3 + - name: Cache pre-built tar archives + uses: actions/cache@v3 + with: + path: | + otp_src.tar.gz + otp_cache.tar.gz + key: prebuilt-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + prebuilt-${{ github.ref_name }}-${{ github.sha }} + - name: Build image + run: | + .github/scripts/restore-from-prebuilt.sh `pwd` .github/otp.tar.gz + rm -f otp_{src,cache}.tar.gz + docker build --tag otp \ + --build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \ + --file ".github/dockerfiles/Dockerfile.64-bit" \ + .github/ + - name: Merge test results + run: | + shopt -s nullglob + mkdir -p make_test_dir + for file in *_test_results/*.tar.gz; do + tar xzf $file + done + docker run -v $PWD/make_test_dir:/buildroot/otp/erts/make_test_dir otp \ + "ct_run -refresh_logs /buildroot/otp/erts/make_test_dir" + - name: Run system tests + run: | + docker run --ulimit core=-1 --ulimit nofile=5000:5000 --pids-limit 512 \ + -e CTRUN_TIMEOUT=90 -e SPEC_POSTFIX=gh \ + -e EXTRA_ARGS="-ct_hooks cth_surefire [{path,\"/buildroot/otp/erts/make_test_dir/system_junit.xml\"}]" \ + -e OTP_DAILY_BUILD_TOP_DIR=/buildroot/otp/erts/make_test_dir \ + -v $PWD/make_test_dir:/buildroot/otp/erts/make_test_dir otp \ + "make system_test" + - name: Cleanup tests + if: always() + run: | + rm -rf make_test_dir/otp || true + tar czf test_results.tar.gz make_test_dir + # Translate file="/buildroot/otp/lib/os_mon/make_test_dir/os_mon_test/cpu_sup_SUITE.erl" + # to file="lib/os_mon/test/cpu_sup_SUITE.erl" + sed -i -e 's:file="/buildroot/otp/:file=":g' \ + -e 's:\(file="[^/]*/[^/]*/\)make_test_dir/[^/]*:\1test:g' \ + -e 's:\(file="erts/\)make_test_dir/[^/]*:\1test:g' \ + make_test_dir/*_junit.xml + - name: Upload test results + uses: actions/upload-artifact@v3 + if: always() + with: + name: test_results + path: test_results.tar.gz + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v3 + with: + name: Unit Test Results + path: | + make_test_dir/*_junit.xml ## If this is a tag that has been pushed we do some release work release: name: Release Erlang/OTP runs-on: ubuntu-latest - needs: build + needs: documentation if: startsWith(github.ref, 'refs/tags/') && github.repository == 'erlang/otp' steps: ## This step outputs the tag name and whether the tag is a release or patch @@ -233,26 +709,23 @@ jobs: id: tag run: | TAG=${GITHUB_REF#refs/tags/} - IS_RELEASE=`$(echo $TAG | grep -E '^OTP-[0-9]+\.[0-9]+$' > /dev/null) \ - && echo "true" || echo "false"` VSN=${TAG#OTP-} - echo "::set-output name=tag::${TAG}" - echo "::set-output name=release::${IS_RELEASE}" - echo "::set-output name=vsn::${VSN}" - - - uses: actions/checkout@v2 + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "vsn=${VSN}" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 ## Publish the pre-built archive and docs - name: Download source archive - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: otp_prebuilt - name: Download html docs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: otp_doc_html - name: Download man docs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: otp_doc_man @@ -261,18 +734,14 @@ jobs: - name: Create pre-build and doc archives run: .github/scripts/create-artifacts.sh artifacts ${{ steps.tag.outputs.tag }} - - name: Build OTP Bundle - if: steps.tag.outputs.release == 'true' - run: | - scripts/bundle-otp ${{ steps.tag.outputs.tag }} - ## Create hash files - name: Create pre-build and doc archives run: | shopt -s nullglob cd artifacts - md5sum {*.tar.gz,*.txt} > MD5.txt - sha256sum {*.tar.gz,*.txt} > SHA256.txt + FILES=$(ls {*.tar.gz,*.txt}) + md5sum $FILES > MD5.txt + sha256sum $FILES > SHA256.txt - name: Upload pre-built and doc tar archives uses: softprops/action-gh-release@v1 @@ -288,3 +757,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.TRIGGER_ERLANG_ORG_BUILD }} run: | curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/erlang/erlang-org/actions/workflows/update-gh-cache.yaml/dispatches" -d '{"ref":"master"}' + + event_file: + name: "Event File" + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: Event File + path: ${{ github.event_path }} diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml new file mode 100644 index 000000000000..80a4622ae7c4 --- /dev/null +++ b/.github/workflows/pr-comment.yaml @@ -0,0 +1,131 @@ +name: Update PR details + +# read-write repo token +# access to secrets +on: + workflow_run: + workflows: ["Build and check Erlang/OTP"] + types: + - requested + - completed + +# Limit concurrency so that we don't get any races between parallel actions +concurrency: pr-comment + +jobs: + pr-number: + runs-on: ubuntu-20.04 + if: github.repository == 'erlang/otp' + outputs: + result: ${{ steps.pr-number.outputs.result }} + steps: + - uses: actions/checkout@v2 + - name: Fetch PR number + id: pr-number + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + git clone https://github.com/talentdeficit/jsx + (cd jsx && rebar3 compile) + .github/scripts/get-pr-number.es erlang/otp \ + "${{ github.event.workflow_run.head_sha }}" + + starting-tests: + runs-on: ubuntu-latest + needs: pr-number + if: github.event.action == 'requested' && needs.pr-number.outputs.result != '' + steps: + - uses: actions/checkout@v2 + ## We create an initial comment with some useful help to the user + - uses: actions/github-script@v5.1.1 + with: + script: | + const script = require('./.github/scripts/pr-comment.js'); + return await script({github, context, state: 'starting', + pr_number: ${{ needs.pr-number.outputs.result }} }); + + finished-tests: + runs-on: ubuntu-20.04 + needs: pr-number + ## Limit concurrency so that only one job deploys to erlang.github.io + concurrency: erlang.github.io-deploy + if: >- + github.event.action == 'completed' && + needs.pr-number.outputs.result != '' && + github.event.workflow_run.conclusion != 'skipped' + steps: + - uses: actions/checkout@v2 + - name: Download and Extract Artifacts + id: extract + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + mkdir -p artifacts && cd artifacts + + artifacts_url=${{ github.event.workflow_run.artifacts_url }} + + gh api "$artifacts_url" --paginate -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact + do + IFS=$'\t' read name url <<< "$artifact" + if [ "$name" = "Unit Test Results" ] || [ "$name" = "Event File" ]; then + gh api $url > "$name.zip" + unzip -d "$name" "$name.zip" + fi + done + + if [ -d "Unit Test Results" ]; then + echo "HAS_TEST_ARTIFACTS=true" >> $GITHUB_OUTPUT + else + echo "HAS_TEST_ARTIFACTS=false" >> $GITHUB_OUTPUT + fi + + - uses: actions/checkout@v2 + with: + token: ${{ secrets.ERLANG_TOKEN }} + repository: 'erlang/erlang.github.io' + path: erlang.github.io + + - name: Publish CT Test Results + uses: EnricoMi/publish-unit-test-result-action@v1 + if: steps.extract.outputs.HAS_TEST_ARTIFACTS == 'true' + with: + commit: ${{ github.event.workflow_run.head_sha }} + event_file: artifacts/Event File/event.json + event_name: ${{ github.event.workflow_run.event }} + check_name: "CT Test Results" + files: "artifacts/**/*.xml" + + - name: Upload PR to github pages + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + git clone https://github.com/talentdeficit/jsx + (cd jsx && rebar3 compile) + mkdir -p "${GITHUB_WORKSPACE}/erlang.github.io/prs/" + .github/scripts/sync-github-prs.es erlang/otp \ + "${GITHUB_WORKSPACE}/erlang.github.io/prs/" \ + "${{ needs.pr-number.outputs.result }}" + + - name: Deploy to github pages 🚀 + run: | + cd erlang.github.io + set -x + git config user.name github-actions + git config user.email github-actions@github.com + git add . + git add -u + git update-index --refresh + if ! git diff-index --quiet HEAD --; then + git commit -m "Update github pages content" + git push origin master + fi + + ## Append some useful links and tips to the test results posted by + ## Publish CT Test Results + - uses: actions/github-script@v5.1.1 + if: always() + with: + script: | + const script = require('./.github/scripts/pr-comment.js'); + return await script({github, context, state: 'finished', + pr_number: ${{ needs.pr-number.outputs.result }} }); diff --git a/.github/workflows/sync-github-releases.yaml b/.github/workflows/sync-github-releases.yaml index d3d3cf901c5a..40dc72f6849d 100644 --- a/.github/workflows/sync-github-releases.yaml +++ b/.github/workflows/sync-github-releases.yaml @@ -1,6 +1,6 @@ name: Sync all github releases with erlang.org -## Update the base image every day +## Sync all github releases + prs every hour on: workflow_dispatch: schedule: @@ -10,30 +10,50 @@ on: ## Build base images to be used by other github workflows jobs: - # Wait for up to a minute for previous runs to complete, abort if not done by then - pre-ci: - if: github.repository == 'erlang/otp' - runs-on: ubuntu-latest - timeout-minutes: 1 - steps: - - name: 'Block Concurrent Executions' - uses: softprops/turnstyle@v1 - with: - poll-interval-seconds: 10 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - sync-releases: - needs: pre-ci if: github.repository == 'erlang/otp' + concurrency: sync-github-releases runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 ## We need to login to the package registry in order to pull ## the base debian image. - name: Docker login - run: docker login https://docker.pkg.github.com -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} + run: docker login https://ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} - name: Sync releases + env: + ERLANG_ORG_TOKEN: ${{ secrets.TRIGGER_ERLANG_ORG_BUILD }} run: > .github/scripts/sync-github-releases.sh ${{ github.repository }} "Bearer ${{ secrets.GITHUB_TOKEN }}" "^[2-9][1-9]\\..*" 25m + + sync-prs: + if: github.repository == 'erlang/otp' + concurrency: erlang.github.io-deploy + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + token: ${{ secrets.ERLANG_TOKEN }} + repository: 'erlang/erlang.github.io' + path: erlang.github.io + - uses: actions/checkout@v3 + - name: Update PRs + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + git clone https://github.com/talentdeficit/jsx + (cd jsx && rebar3 compile) + rm -rf "${GITHUB_WORKSPACE}/erlang.github.io/.git" + mkdir -p "${GITHUB_WORKSPACE}/erlang.github.io/prs/" + touch "${GITHUB_WORKSPACE}/erlang.github.io/.nojekyll" + .github/scripts/sync-github-prs.es erlang/otp "${GITHUB_WORKSPACE}/erlang.github.io/prs/" + + - name: Deploy to github pages 🚀 + uses: JamesIves/github-pages-deploy-action@v4.4.1 + with: + token: ${{ secrets.ERLANG_TOKEN }} + branch: master # The branch the action should deploy to. + folder: erlang.github.io # The folder the action should deploy. + repository-name: erlang/erlang.github.io + single-commit: true diff --git a/.github/workflows/update-base.yaml b/.github/workflows/update-base.yaml index 6ded954c2a71..fa238c480315 100644 --- a/.github/workflows/update-base.yaml +++ b/.github/workflows/update-base.yaml @@ -18,25 +18,29 @@ jobs: strategy: matrix: type: [debian-base,ubuntu-base,i386-debian-base] + branch: [master, maint, maint-25] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + with: + ref: ${{ matrix.branch }} - name: Docker login - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: - registry: docker.pkg.github.com + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Calculate BASE image - id: base - run: | - echo "::set-output name=BASE_TAG::docker.pkg.github.com/erlang/otp/${{ matrix.type }}" - .github/scripts/base-tag "${{ matrix.type }}" - name: Build base image + id: base + run: >- + BASE_TAG=ghcr.io/${{ github.repository_owner }}/otp/${{ matrix.type }} + BASE_USE_CACHE=false + .github/scripts/build-base-image.sh "${{ matrix.branch }}" + - name: Push master image + if: matrix.branch == 'master' + run: docker push ${{ steps.base.outputs.BASE_TAG }}:latest + - name: Tag and push base image run: | - docker build --pull --tag ${{ steps.base.outputs.BASE_TAG }} \ - --cache-from ${{ steps.base.outputs.BASE_TAG }} \ - --file .github/dockerfiles/Dockerfile.${{ steps.base.outputs.BASE_TYPE }} \ - --build-arg BASE=${{ steps.base.outputs.BASE }} . - - name: Push base image - run: docker push ${{ steps.base.outputs.BASE_TAG }} + docker tag ${{ steps.base.outputs.BASE_TAG }}:latest \ + ${{ steps.base.outputs.BASE_TAG }}:${{ matrix.branch }} + docker push ${{ steps.base.outputs.BASE_TAG }}:${{ matrix.branch }} diff --git a/.gitignore b/.gitignore index 794d384b4d29..94664b47c88a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,11 @@ TAGS # vscode .vscode +# IntelliJ IDEA +.idea + autom4te.cache +configure.result.* *.beam *.asn1db @@ -46,11 +50,8 @@ i386-pc-solaris[0-9]*.[0-9]* i386-unknown-freebsd[0-9]*.[0-9]* x86_64-unknown-freebsd[0-9]*.[0-9]* x86_64-unknown-openbsd[0-9]*.[0-9]* -tile-tilera-linux-gnu powerpc-unknown-linux-gnu aarch64-unknown-linux-gnu -i386-elf-ose -powerpc-unknown-ose # Mac OS X a.out.dSYM/ @@ -59,8 +60,8 @@ a.out.dSYM/ *.pdb local.static.config.cache tcltk85_win32_bin.tar.gz -erts/autoconf/win32.config.cache -erts/autoconf/win64.config.cache +make/autoconf/win32.config.cache +make/autoconf/win64.config.cache erts/emulator/obj/ erts/emulator/pcre/obj/ erts/emulator/pcre/win32/ @@ -92,8 +93,6 @@ lib/crypto/priv/obj/ lib/erl_interface/obj.md/ lib/erl_interface/obj.mdd/ lib/erl_interface/src/win32/ -lib/gs/priv/tcl/ -lib/gs/tcl/binaries/ lib/megaco/src/flex/win32/ lib/odbc/c_src/win32/ lib/odbc/priv/bin/odbcserver.exe @@ -104,9 +103,6 @@ lib/os_mon/priv/obj/win32/ lib/runtime_tools/c_src/win32/ lib/runtime_tools/priv/lib/ lib/runtime_tools/priv/obj/ -lib/tools/bin/win32/ -lib/tools/c_src/win32/ -lib/tools/obj/win32/ lib/wx/c_src/win32/ lib/wx/priv/win32/ lib/wx/win32/ @@ -114,9 +110,6 @@ make/win32/ make/otp_built make/otp_doc_built -# OSE -*.d - # Used by applications that run javadoc (e.g. ic). JAVADOC-GENERATED @@ -134,15 +127,12 @@ JAVADOC-GENERATED /bootstrap/lib/edoc /bootstrap/lib/erl_docgen /bootstrap/lib/erl_interface -/bootstrap/lib/hipe -/bootstrap/lib/jinterface /bootstrap/lib/parsetools /bootstrap/lib/public_key /bootstrap/lib/runtime_tools /bootstrap/lib/sasl /bootstrap/lib/snmp /bootstrap/lib/syntax_tools -/bootstrap/lib/test_server /bootstrap/lib/wx /bootstrap/lib/xmerl @@ -228,6 +218,8 @@ JAVADOC-GENERATED /erts/test/install_SUITE_data/install_bin /erts/test/autoimport_SUITE_data/erlang.xml /erts/emulator/make_test_dir/ +/erts/epmd/make_test_dir/ +/erts/make_test_dir/ # common_test @@ -241,10 +233,13 @@ JAVADOC-GENERATED /lib/compiler/test/*_no_opt_SUITE.erl /lib/compiler/test/*_no_copt_SUITE.erl +/lib/compiler/test/*_no_copt_ssa_SUITE.erl /lib/compiler/test/*_no_ssa_opt_SUITE.erl /lib/compiler/test/*_post_opt_SUITE.erl /lib/compiler/test/*_inline_SUITE.erl -/lib/compiler/test/*_r21_SUITE.erl +/lib/compiler/test/*_r23_SUITE.erl +/lib/compiler/test/*_r24_SUITE.erl +/lib/compiler/test/*_r25_SUITE.erl /lib/compiler/test/*_no_module_opt_SUITE.erl /lib/compiler/test/*_no_type_opt_SUITE.erl /lib/compiler/test/*_dialyzer_SUITE.erl @@ -282,35 +277,6 @@ JAVADOC-GENERATED /lib/et/doc/html/*.png -# gs - -/lib/gs/src/gstk_generic.hrl -/lib/gs/contribs/ebin/*.gif -/lib/gs/contribs/ebin/*.tool -/lib/gs/doc/html/images/*.gif -/lib/gs/tcl/win32/Makefile - -# hipe - -/lib/hipe/boot_ebin/hipe.app -/lib/hipe/boot_ebin/hipe.appup -/lib/hipe/main/hipe.hrl -/lib/hipe/rtl/hipe_literals.hrl - -# ic - -/lib/ic/examples/pre_post_condition/m.hrl -/lib/ic/examples/pre_post_condition/m_i.erl -/lib/ic/examples/pre_post_condition/m_i.hrl -/lib/ic/examples/pre_post_condition/m_NotAnInteger.erl -/lib/ic/examples/pre_post_condition/oe_ex.erl -/lib/ic/examples/pre_post_condition/oe_ex.hrl -/lib/ic/priv/com/ -/lib/ic/priv/ic.jar -/lib/ic/src/icparse.erl -/lib/ic/doc/html/java -/lib/ic/java_src/SKIP - # jinterface /lib/jinterface/priv/OtpErlang.jar @@ -331,12 +297,6 @@ JAVADOC-GENERATED /lib/mnesia/test/Mnesia.* /lib/mnesia/test/test_log* -# otp_mibs - -/lib/otp_mibs/include/OTP*.hrl -/lib/otp_mibs/mibs/v1/OTP*.mib.v1 -/lib/otp_mibs/priv/mibs/OTP*.bin - # os_mon /lib/os_mon/include/OTP*.hrl diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000000..74a5155ec342 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,7 @@ +image: + file: .github/dockerfiles/Dockerfile.ubuntu-base + context: .github +vscode: + extensions: + - ms-vscode.cpptools + - erlang-ls.erlang-ls diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7a69137c037..0d7588d35c88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,16 @@ # Contributing to Erlang/OTP +1. [License](#license) +2. [Reporting a bug](#reporting-a-bug) +3. [Submitting Pull Requests](#submitting-pull-requests) + 1. [Fixing a bug](#fixing-a-bug) + 2. [Adding a new feature](#adding-a-new-feature) + 3. [Before you submit your pull request](#before-you-submit-your-pull-request) + 4. [After you have submitted your pull request](#after-you-have-submitted-your-pull-request) + ## License +```txt By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I @@ -26,18 +35,16 @@ By making a contribution to this project, I certify that: sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. +``` -Erlang/otp is licensed under the -Apache License 2.0 - -As stated in: [LICENSE.txt](LICENSE.txt) +See http://developercertificate.org/ for a copy of the Developer Certificate of Origin license. -http://developercertificate.org/ +Erlang/OTP is licensed under the Apache License 2.0, as stated in: [LICENSE.txt](LICENSE.txt) ## Reporting a bug -Report bugs at https://github.com/erlang/otp/issues. See [Bug reports](https://github.com/erlang/otp/wiki/Bug-reports) -for more information. +Report bugs at https://github.com/erlang/otp/issues. +See [Bug reports](https://github.com/erlang/otp/wiki/Bug-reports) for more information. ## Submitting Pull Requests @@ -47,7 +54,7 @@ Make sure you create a new branch for your pull request with `git checkout -b ne Give the branch a short but descriptive name, like `stdlib/lists-length-fix`. Never do your work directly on `maint` or `master`. -## Fixing a bug +### Fixing a bug * In most cases, pull requests for bug fixes should be based on the `maint` branch. There are exceptions, for example corrections to bugs that have been introduced in the `master` branch. @@ -59,12 +66,11 @@ There are exceptions, for example corrections to bugs that have been introduced * For applications without a test suite in the git repository, it would be appreciated if you provide a small code sample in the commit message or email a module that will provoke the failure. -## Adding a new feature +### Adding a new feature * In most cases, pull requests for new features should be based on the `master` branch. -* It is recommended to discuss new features on -[the erlang-questions mailing list](http://erlang.org/mailman/listinfo/erlang-questions), +* It is recommended to discuss new features in the [erlang forums](https://erlangforums.com), especially for major new features or any new features in ERTS, Kernel, or STDLIB. * It is important to write a good commit message explaining **why** the feature is needed. @@ -90,15 +96,17 @@ feature one or two releases beforehand. can be included in OTP. Major changes or new features in ERTS, Kernel, or STDLIB will need an EEP or at least a discussion on the mailing list. -## Before you submit your pull request +### Before you submit your pull request * Make sure existing test cases don't fail. It is not necessary to run all tests (that would take many hours), but you should at least run the tests for the application you have changed. -See [Running tests](https://github.com/erlang/otp/wiki/Running-tests). * Make sure the documentation builds and is according to the dtd. eg. `make xmllint` or `cd lib/stdlib/ && make xmllint` * Make sure no new dialyzer warnings have been added. eg. `make dialyzer` or `cd lib/stdlib/ && make dialyzer` * Make sure that github actions passes, if you go to https://github.com/$YOUR_GITHUB_USER/otp/actions you can enable github actions builds for you otp fork. - * Note that this only builds Erlang/OTP, it does not run any tests. + +See the [Testing](https://github.com/erlang/otp/blob/master/HOWTO/TESTING.md) and +[Development](https://github.com/erlang/otp/blob/master/HOWTO/DEVELOPMENT.md) howtos +for details on how to use run tests and use the Erlang/OTP make system. Make sure that your branch contains clean commits: @@ -127,7 +135,7 @@ Check your coding style: * In most code (Erlang and C), indentation is 4 steps. Indentation using only spaces is **strongly recommended**. -### Configuring Emacs +#### Configuring Emacs If you use Emacs, use the Erlang mode, and add the following lines to `.emacs`: @@ -142,3 +150,16 @@ If you want to change the setting only for the Erlang mode, you can use a hook l (defun my-erlang-hook () (setq indent-tabs-mode nil)) ``` + +### After you have submitted your pull request + +* Follow the discussion following your pull request, answer questions, discuss and implement +changes requested by reviewers. + +* If your pull requests introduces new public functions, they need to be tagged with the +OTP release in which they _will_ appear in the `since` tag in the functions' documentation. +As this is generally not yet certain at the time when your PR gets merged, the person assigned +to your pull request should give you an internal ticket number (for example `OTP-12345`) to use +as a placeholder in the respective `since` tags, like `since="OTP @OTP-12345@`. When your new +functions are released with an OTP release, this placeholder will get replaced with the actual +OTP version, leading to something like "OTP 26.0". diff --git a/HOWTO/DEVELOPMENT.md b/HOWTO/DEVELOPMENT.md new file mode 100644 index 000000000000..b9be3026e17a --- /dev/null +++ b/HOWTO/DEVELOPMENT.md @@ -0,0 +1,597 @@ +# Developing Erlang/OTP + +The Erlang/OTP development repository is quite large and the make system +contains a lot of functionality to help when developing. This howto +will try to showcase the most important features of the make system. + +The guide is mostly aimed towards development on a Unix platform, but +most things should work also work using WSL on Windows. The guide also +assumes that you are working in the git repositiory. Many of the +scripts and tools described here are not available in the prebuilt tar +archive that you can download for each release. + +*WARNING*: Only some of APIs mentioned in this guide are supported. This +means that they may be removed or changed without prior notice, so do +not depend on them in CI. For supported make targets see the +[Install howto](INSTALL.md) and the [Testing howto](TESTING.md). + +The make system is not always as robust as one might like, so if for +any reason something does not work, try doing a `git clean -Xfdq` and +start from the beginning again. This normally only needs to be done when +you jump in between different git branches, but it can a good thing to +keep in mind whenever things do not work as you expect them to. + +*NOTE*: This instructions may vary for different versions of Erlang/OTP, +so make sure to read the instructions for the version that you are working +with. + +1. [Short version](#short-version) +2. [Preparations](#preparations) + 1. [Faster builds](#faster-builds) +3. [Configuring](#configuring) + 1. [Help](#help) +4. [Building and testing](#building-and-testing) + 1. [Build and test a specific application](#build-and-test-a-specific-application) + 2. [Preloaded and Primary Bootstrap](#preloaded-and-primary-bootstrap) + 3. [Types and Flavors](#types-and-Flavors) + 4. [cerl](#cerl) + 5. [Static analysis](#static-analysis) +5. [Running test cases](#running-test-cases) +6. [Writing and building documentation](#writing-and-building-documentation) + 1. [Validating documentation](#validating-documentation) +7. [Github Actions](#github-actions) + 1. [Debugging github actions failures](#debugging-github-actions-failures) +8. [Using Docker](#using-docker) + 1. [Gidpod.io or VSCode dev container](#gitpod-io-or-vscode-dev-container) + +## Short version + +First make sure you have done all [preparations](#preparations) then +do this: + +```bash +git clone -b maint git@github.com:erlang/otp +cd otp && export ERL_TOP=`pwd` +./otp_build configure && make +``` + +When you have done changes, added tests or updated documentation, build and test like this: + +```bash +cd lib/$APPLICATION_NAME +make # Rebuid application +make test # Run application tests +make dialyzer # Run dialyzer +make docs # Build the docs +make xmllint # Run xmllint on the docs +``` + +Then enable [Github Actions](#github-actions) and push the changes to your fork +of Erlang/OTP to check that you have not missed anything. + +## Preparations + +Before you start working you need to clone the Erlang/OTP git repository +and install any dependencies that you do not have. See +[Required Utilities](INSTALL.md#required-utilities) and +[Optional Utilities](INSTALL.md#optional-utilities) in [INSTALL.md](INSTALL.md) +for a list of utilities to install. (Windows has its own [INSTALL Guide](INSTALL-WIN32.md) +with its own [Required Utilities](INSTALL-WIN32.md#tools-you-need-and-their-environment)). + +Then you need to set `ERL_TOP` to point at the repository you are developing in. +Not all make commands needs this environment variable set, but many do so it is +good to get into the habit of always setting it. + +```bash +cd /path/to/repository/otp +export ERL_TOP=`pwd` +``` + +Make sure that you have read the [Contributing to Erlang/OTP](../CONTRIBUTING.md) +guide if you intend to make a contribution to Erlang/OTP. + +### Faster builds + +Both `configure` and `make` take advantage of running in parallel if told to, +so in order to speed up your development environment make sure to set: + +```bash +## Change N to be at least the number of cores or hyper-threads available +export MAKEFLAGS=-jN +``` + +The Erlang compiler can be run using a [Compile Server](https://www.erlang.org/doc/man/erlc.html#compile-server), +this can cut from the total build time of Erlang/OTP by quite a lot, +especially if you have a relatively slow machine. +To enable set this environment variable: + +```bash +export ERLC_USE_SERVER=true +``` + +Re-building all application in Erlang/OTP can take a while so it is possible +to build only a subset of the applications. This is done by setting either +`OTP_SMALL_BUILD` or `OTP_TINY_BUILD` to `true` when doing make at the top +level. However, the simplest way is probably to just use the `./otp_build` +wrapper that takes the options `-t` (tiny) or `-a` (all) and defaults to +a small build. + +```bash +# You need to have done ./configure before calling make or boot. +OTP_TINY_BUILD=true make ## Equivalent to ./otp_build boot -t +OTP_SMALL_BUILD=true make ## Equivalent to ./otp_build boot +./otp_build boot -a ## Equivalent to make +``` + +## Configuring + +You run configure by issuing the command: + +```bash +./otp_build configure +``` + +On all operating systems except Windows you can also just run: + +```bash +./configure +``` + +If you change any `Makefile`s you will need to re-run configure. +If you update any `configure.ac` scripts you need to +[update the configure scripts](INSTALL.md#updating-configure-scripts). + +### Help + +The toplevel configure will give help about the features that it provides. +To get a full list of all features you need to use: + +```bash +./configure --help=r +``` + +There is documentation for what most of the options mean in the +[INSTALL.md](INSTALL.md#Configuring) howto. + +## Building and testing + +After you have done configure, you can do + +```bash +make +``` + +on the top of this repository. That will compile all of Erlang/OTP. + +You can also build a specific application: + +```bash +make stdlib +make common_test +``` + +These make commands do not manage any dependencies, so if an application needs +something from another you need to make sure that it is built. It is therefore +good practice to first build all of Erlang/OTP and then build just the one that +you are updating. + +You can also run tests from the top: + +```bash +make test # Run all tests, takes a **very** long time +make stdlib_test # Run only stdlib tests, takes less time + # Run only lists_SUITE, takes even less time +make stdlib_test ARGS="-suite lists_SUITE" + # Run only member testcase in lists_SUITE +make stdlib_test ARGS="-suite lists_SUITE -case member" +``` + +See [ct_run](https://www.erlang.org/doc/man/ct_run.html#) for a list of all options +that you can pass to ARGS. + +You can run static analysis test: + +```bash +make dialyzer # Checks all of Erlang/OTP source code +make xmllint # Checks all documentation for xmllint errors +``` + +Most of the above targets also works for a "phony" target called `emulator` that +represents erts and all its tools. So you can do this: + +```bash +make emulator # Build erts, epmd etc +make emulator_test # Run all emulator tests +``` + +If you want to pass a run-time flag to the emulator running the tests you can +use the `ERL_ARGS` flags to `make test`. For example if you want to run tests +using [off heap message queue data](https://www.erlang.org/doc/man/erlang.html#process_flag_message_queue_data) +for all process you would do this: + +```bash +ERL_ARGS="+hmqd off_heap" make emulator_test +``` + +### Build and test a specific application + +You can also build the application from within itself. Like this: + +```bash +cd lib/stdlib && make +``` + +Each application has a bunch of make targets that you can use. + +```bash +make # build all source for this application +make test # run all tests for this application +make test ARGS="-suite lists_SUITE" # run the lists_SUITE tests +make dialyzer # run dialyzer for this application +make docs # build all docs for this application +make docs DOC_TARGETS="html" # build html docs for this application +make xmllint # run xmllint on the docs for this application +``` + +If you want to view what the documentation looks like for only your application +you can do this: + +```bash +(cd doc/src && make local_docs) +``` + +and then view `doc/html/index.html`. + +### Preloaded and Primary Bootstrap + +The Erlang code loader and compiler are written in Erlang, so in order to +[bootstrap](https://en.wikipedia.org/wiki/Bootstrapping_(compilers)) +the system a number of compiled `.beam` files are commited into the +Erlang/OTP git repository. + +The Erlang code located in [erts/preloaded/src](../erts/preloaded/src) +is compiled into the VM and used to load enough code so that the code +loader in the `kernel` application can be loaded. If you update any of +that code you need to do a special preloaded update for the changes to +take effect. This is done like this: + +```bash +./otp_build update_preloaded [--no-commit] +make # Need to rebuild system after the preloaded has been updated +``` + +You need to have a working Erlang compiler in your path for this to work. +In order to be able to compile the Erlang/OTP source code, there also needs +to be a basic Erlang compiler committed into git. This is what is called the +primary bootstrap. It is quite rare that you need to update this, but if you +are extending the Erlang language and would like to use the new extensions +in the Erlang/OTP source code you it needs to be updated. As an example, when +we added `maps` to Erlang we first needed to have a commited primary bootstrap +that could compile code with maps, before we actually could use maps anywhere. +To update the primary bootstrap you do like this: + +```bash +./otp_build update_primary [--no-commit] +``` + +*NOTE*: When submitting a PR to Erlang/OTP you will be asked to not include +any commit updating preloaded or the primary bootstrap. This is because we +cannot review the contents of binary files and thus cannot make sure they do +not contain any malicious data. + +### Types and Flavors + +Erlang can be built using different types and flavors. Mostly the types and +flavors change how the Erlang VM itself is built, but some also effect how +application are built. Some of the types/flavors are: + +* Types + * opt (default) + * debug + * lcnt + * valgrind + * asan + * gcov +* Flavor + * emu + * jit (default if available) + +To build using a type and or flavor you just pass it as a variable to make. +For example: + +```bash +make TYPE=debug +make FLAVOR=emu +make TYPE=lcnt FLAVOR=emu +``` + +As you can see it is possible to combine type and flavor to create many different +versions of Erlang. You can then run these different versions by passing the +`-emu_type` and/or `-emu_flavor` flags to `erl`. That is: + +```bash +erl -emu_type lcnt +erl -emu_flavor emu -emu_type debug +``` + +When running valgrind, asan or gcov those tools create special output files that +need to be processed. To work with these files there is a special `erl` program +called `cerl` that is only available in the source tree. You can read more about +it in the [cerl section](#cerl) later in this guide. + +If you want to run the tests with a special flavor or type, the easiest way to +do that is by setting the TYPE or FLAVOR when calling make. For example if you +want to run the emulator tests using the debug emulator you can do it like this: + +```bash +make emulator_test TYPE=debug +``` + +*NOTE*: Before you run tests using a TYPE or FLAVOR you need to build the **entire** +Erlang/OTP repo using that TYPE or FLAVOR. That is `make TYPE=debug` for the example +above. + +### cerl + +`cerl` is a program available in `$ERL_TOP/bin/` that has a number of features +useful when developing the Erlang run-time system. It work just as normal `erl`, +but accepts a couple of extra command line switches. Any other command line arguments +passed to `cerl` will be passed on the Erlang as normal. The extra command line +switches are: + +* -debug + * Start a debug run-time system. +* -lcnt + * Start a lock count run-time system. +* -valgrind + * Start valgrind with the correct settings and use the `valgrind` [type](types-and-flavors). + * Set environment variable `VALGRIND_LOG_XML` to true if want xml valgrind logs. + * Set environment variable `VALGRIND_LOG_DIR` to where you want valgrind logs. + * Set environment variable `VALGRIND_MISC_FLAGS` for any extra valgrind flags you want to pass. +* -asan + * Start [Clang Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) + with the the correct settings and use the `asan` [type](types-and-flavors). + * Set environment variable `ASAN_LOG_DIR` to where you want the logs. + * Set environment variable `ASAN_OPTIONS` for any extra asan options you want to pass. +* -gcov + * Start a gcov run-time system. +* -gdb + * Start an Emacs gdb debugging session. Can be combined with -debug. +* -core /path/to/core/file + * Start an Emacs gdb debugging session for the core specified. +* -rgdb + * Start a gdb debugging session in the current terminal. Can be combined with -debug. +* -rcore /path/to/core/file + * Start a gdb debugging session in the current terminal for the core specified. +* -lldb + * Start a lldb debugging session in the current terminal. +* -rr + * Start Erlang under [rr](https://rr-project.org/) to record all events. Can be combined with -debug. +* -rr replay [session] + * Load a recording session using `rr replay`, if no session is specified the latest run session is laoded. + +If you want to run tests using `cerl` (for example if you want to run asan on +the nif_SUITE in emulator) you cannot use the `make test` approach to testing +as that uses `ct_run` under the hood and `ct_run` does not support customizing +the emulator start script. Instead you need to use the approach described in +[Run tests with Address Sanitizer](INSTALL.md#run-tests-with-address-sanitizer). + + +### Static analysis + +From the top level of Erlang/OTP you can run: + +```bash +make xmllint +make dialyzer +make format-check +``` + +This will check that the documentation is correct and that there are no +dialyzer errors. See also [Validating documentation](#validating-documentation) +for more details. + +## Running test cases + +There is a detailed description about how to run tests in [TESTING.md](TESTING.md). + +## Writing and building documentation + +Most of the Erlang/OTP documentation is written in XML files located in +`lib/$APPLICATION_NAME/doc/src`. The format of the XML is described in the +[ErlDocgen User's Guide](https://www.erlang.org/doc/apps/erl_docgen/users_guide.html). + +There is also some documentation that is written using [edoc](https://www.erlang.org/doc/man/edoc.html). + +To view the documentation the simplest way is to release it. *NOTE*: The Erlang/OTP +repository needs to have been [built](#building-and-testing) before you can build +the documentation. + +```bash +make release_docs +``` + +and then you can view `release/*/doc/index.html` in your favourite browser and +make sure that it looks nice. + +This takes a while though and to speed up the edit-view cycle you can either +limit what parts of the documentation is built using `DOC_TARGETS`. For example: + +```bash +make release_docs DOC_TARGETS=html +``` + +The different `DOC_TARGETS` built are `html`, `man`, `pdf` and `chunks`. + +You can also build the docs only for a single application. For example: + +```bash +cd lib/stdlib/doc/src && make local_docs DOC_TARGETS=html +``` + +and then view the results at `lib/stdlib/doc/html/index.html`. + +### Validating documentation + +In order to make sure that the documentation is correct you need to also +validate it. Just building the documentation does not mean that it is +correct. There are two steps that you need to do in order to validate +the docs. + +First run the `xmllint`. This makes sure that the xml follows the +[Erlang/OTP dtd](https://www.erlang.org/doc/apps/erl_docgen/overview.html) +and does some extra checks to make sure all links are correct. + +You run the xmllint like this: + +```bash +make xmllint # Run it at the top level +cd lib/stdlib && make xmllint # Run it for only a single application +``` + +When the xml has been verified you also need to make sure that there +are no broken links in the documentation. This is done by running +[`otp_html_check`](https://github.com/erlang/otp/blob/master/scripts/otp_html_check). + +You run `otp_html_check` like this: + +```bash +make release_docs DOC_TARGETS="html pdf" # First we need to release the pdf+html docs +$ERL_TOP/scripts/otp_html_check $(pwd)/release/$($ERL_TOP/erts/autoconf/config.guess) doc/index.html +``` + +The output of `otp_html_check` will print a list of broken links and anchors, for example: + +```text +**** Files not used (that I can see) +.... + +**** Broken links + +Broken Link: /lib/kernel-8.3.1/doc/html/inet.html -> "/lib/kernel-8.3.1/doc/html/files.html" + +**** References to missing anchors + +Missing Anchor: "/lib/kernel-8.3.1/doc/html/files.html#native_name_encoding-0" from /lib/kernel-8.3.1/doc/html/inet.html +Missing Anchor: "/lib/kernel-8.3.1/doc/html/inet.html#type-ip_addres" from /lib/kernel-8.3.1/doc/html/inet.html +``` + +The `Files not used` section is mostly used to debug the documentation build +process, so it can be ignored most of the time. The other to sections should +however be empty for the documentation to be correct. + +All this validation is also done by [Github Actions](#github-actions). + +## Github Actions + +Erlang/OTP uses [Github Actions](https://github.com/features/actions) as a +preliminary CI to check that nothing fundamental has been broken by the change. + +You can enable Github Actions on your own github fork in order to run the tests +before opening a PR to the main repository. + +Github Actions does too many checks to list them all but the primary ones are: + +* Build on Ubuntu Linux and Windows +* Cross build to Debian Linux on powerpc and iOS +* Build and validate documentation +* Run dialyzer on all of Erlang/OTP +* Run the tests of the changed application + +Each run generates a bunch of artifacts. The most important ones are: + +* `test_results` + * An archive containing all the logs from all tests that have been run. + Navigate to `make_test_dir/ct_logs/index.html` within the archive to + view the Common Test summary of the tests. +* `otp_win32_installer` + * A windows installer with the changes you have made. +* `otp_doc_html` + * The HTML docs with the changes you have made. + +### Debugging Github Actions failures + +Debugging Github Actions is at best a very time-consuming endevour. So if there +is an error in the build or tests that you don't easily understand I would +recommend that you try to reproduce it locally. + +This is of course not always possible, for instance if it only fails on Windows +and you do not have access to a Windows machine, but it may the worth it as the +leadtime of re-running a test is roughly 30 minutes. See the [other sections of +this guide](#developing-erlang-otp) for details on how to build and run tests +locally. + +If testcases fail when running Github Actions, it is best to start by inspecting +the logs of the test runs. The logs are attached to the finished run as +`test_results`. You will find more details about why a testcase failed in +the logs. + +## Using Docker + +In order to get a reproduceable environment for building and testing you can use +[docker](https//www.docker.com). If you are not familiar with how to use it I +would recommend [reading up a bit](https://www.docker.com/get-started) and trying +some simple examples yourself before using it to build and test Erlang/OTP. + +There is a pre-built ubuntu base image available on github, but you can also +build it locally if you want to. + +Using the pre-built base you build an image like this: + +```bash +docker login ghcr.io +git archive --prefix otp/ -o .github/otp.tar.gz HEAD +docker build -t my_otp_image -f .github/dockerfiles/Dockerfile.64-bit .github/ +``` + +This will fetch the ubuntu base image and build a 64-bit Erlang/OTP. You need to +[login to the github container registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) +in order to fetch the base image. If you want to build the base image locally +you can do that like this: + +```bash +docker build -t ghcr.io/erlang/otp/ubuntu-base \ + --build-arg BASE=ubuntu:20.04 --build-arg USER=otptest --build-arg uid=$(id -u) \ + --build-arg GROUP=uucp --build-arg gid=$(id -g) \ + -f .github/dockerfiles/Dockerfile.ubuntu-base .github/ +``` + +Which approach is fastest depends on the speed of your internet connection. + +When you have built the docker image you can run tests in it like this: + +```bash +docker run my_otp_image "make stdlib_test" +``` + +or if you want to persist the test results outside the container: + +```bash +mkdir -m 777 make_test_dir ## The 777 mode is needed to avoid permission problems +docker run --init -v $PWD/make_test_dir:/buildroot/otp/lib/stdlib/make_test_dir \ + my_otp_image "make stdlib_test" +``` + +The Common Test logs will be placed in `make_test_dir/ct_logs`. + +### Gidpod.io or VSCode dev container + +This git repository is also prepared to run using [Gitpod](https://gitpod.io/) or +[VSCode Devcontainer](https://code.visualstudio.com/docs/remote/containers). + +The support for these environments is very early so it will be a bit unstable. + +To access the gitpod for Erlang/OTP you just navigate to +[https://gitpod.io/#https://github.com/erlang/otp](https://gitpod.io/#https://github.com/erlang/otp). + +When using a VSCode dev container, you only need to open [VSCode](https://code.visualstudio.com/) +in the Erlang/OTP repository and you should get a popup that asks if you want to +run in a dev container. + +The gitpod and dev container both use the base ubuntu image built in [Using Docker](#using-docker). +So it should be possible to run all tests inside the containers with all test +dependencies available. + +*WARNING*: Using VSCode dev container on macOS can be very slow because of limitations +in the filesystem. So I would recommend either using gitpod or just work locally without +the dev container on macOS. diff --git a/HOWTO/INSTALL-ANDROID.md b/HOWTO/INSTALL-ANDROID.md index 4ca225ba3b6c..a4bca5ffedf0 100644 --- a/HOWTO/INSTALL-ANDROID.md +++ b/HOWTO/INSTALL-ANDROID.md @@ -4,7 +4,7 @@ Cross Compiling Erlang/OTP - ANDROID Introduction ------------ -This document describes how to cross compile Erlang/OTP to Android/Rasberry Pi platforms. +This document describes how to cross compile Erlang/OTP to Android/Raspberry Pi platforms. ### Download and Install the Android NDK ### @@ -135,7 +135,7 @@ Use the following commands when compiling an x86 64-bit version. $ make RELEASE_ROOT=/path/to/release/erlang release -### Target Deployment for Rasberry Pi ### +### Target Deployment for Raspberry Pi ### Make a tarball out of /path/to/release/erlang and copy it to target device. Extract it and install. diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md index f2494e6f1c78..d603986e34ee 100644 --- a/HOWTO/INSTALL-CROSS.md +++ b/HOWTO/INSTALL-CROSS.md @@ -57,9 +57,7 @@ cross compiling. The build system, including cross compilation configuration variables used, may be subject to non backward compatible changes without prior notice. Current cross build system has been tested when cross compiling some Linux/GNU -systems, but has only been partly tested for more esoteric platforms. The -VxWorks example file is highly dependent on our environment and is here more -or less only for internal use. +systems, but has only been partly tested for more esoteric platforms. ### Patches ### @@ -130,11 +128,11 @@ be built. `` is the host/target system that you build for. It does not have to be a full `CPU-VENDOR-OS` triplet, but can be. The full canonicalized `CPU-VENDOR-OS` triplet will be created by executing -`$ERL_TOP/erts/autoconf/config.sub `. If `config.sub` fails, you need +`$ERL_TOP/make/autoconf/config.sub `. If `config.sub` fails, you need to be more specific. `` should equal the `CPU-VENDOR-OS` triplet of the system that you -build on. If you execute `$ERL_TOP/erts/autoconf/config.guess`, it will in +build on. If you execute `$ERL_TOP/make/autoconf/config.guess`, it will in most cases print the triplet you want to use for this. The use of `` and `` values that differ will trigger cross @@ -265,7 +263,7 @@ have to be passed one way or the other; either by using `erl_xcomp_host=` and `erl_xcomp_build=` in the configuration file, or by using the `--host=`, and `--build=` command line arguments. -`otp_build configure` will configure both for the boostrap system on the +`otp_build configure` will configure both for the bootstrap system on the build machine and the cross host system. (10) @@ -344,15 +342,15 @@ cross compilation using `$ERL_TOP/otp_build configure`. `--build=$erl_xcomp_build` argument to the `configure` script. It does not have to be a full `CPU-VENDOR-OS` triplet, but can be. The full `CPU-VENDOR-OS` triplet will be created by - `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_build`. If set to `guess`, + `$ERL_TOP/make/autoconf/config.sub $erl_xcomp_build`. If set to `guess`, the build system will be guessed using - `$ERL_TOP/erts/autoconf/config.guess`. + `$ERL_TOP/make/autoconf/config.guess`. * `erl_xcomp_host` - Cross host/target system to build for. This value will be passed as `--host=$erl_xcomp_host` argument to the `configure` script. It does not have to be a full `CPU-VENDOR-OS` triplet, but can be. The full `CPU-VENDOR-OS` triplet will be created by - `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host`. + `$ERL_TOP/make/autoconf/config.sub $erl_xcomp_host`. * `erl_xcomp_configure_flags` - Extra configure flags to pass to the `configure` script. diff --git a/HOWTO/INSTALL-IOS.md b/HOWTO/INSTALL-IOS.md new file mode 100644 index 000000000000..3ec368ecc70a --- /dev/null +++ b/HOWTO/INSTALL-IOS.md @@ -0,0 +1,119 @@ +Cross Compiling Erlang/OTP - IOS +==================================== + +Introduction +------------ + +This document describes how to cross compile Erlang/OTP to iOS platforms. iOS has the peculiarity that it does not support the creation of shared libraries. So the build process needs to be amended to generate statically linkable and executable Erlang binaries. + +### Get Xcode Tools ### + +iOS binaries can only be cross-compiled from Apple macOS computers. For compilation the Xcode tools must be used. +### Environment Variables ### + +In order to inform the build system that it should generate the static linkable `libbeam.a` add the following environment variable during configuration and compilation: + + $ export RELEASE_LIBBEAM=yes + +### Configure Erlang/OTP ### + + To build without without OpenSSL support, run `configure` like this: + + $ ./otp_build configure \ + --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf \ + --without-ssl + + +To build with OpenSSL statically linked, run `configure` like this (note that 1.1.1k works, but needs a manual patch in ios cross build config to include engines): + + $ ./otp_build configure \ + --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf \ + --with-ssl=/path/to/libcrypto.a \ + --disable-dynamic-ssl-lib + + +### Compile Erlang/OTP ### + + $ ./otp_build boot + +### Linking a binary with your App ### + +To use the resulting `libbeam.a` it needs to be packaged into a Xcode `.xcframework` package together with all other required `.a` files. These include: + +* `libbeam.a` +* `libz.a` +* `libcrypto.a` + +Basically all .a files that have been generated by the build. + +One way of creating a combined archive out of all of these is to use `libtool`: + + $ libtool -static -o liberlang.a /Path/to/libbeam.a /Path/to/....a + +This list should also include static nifs you want to include: + +Finally packaging the archive into a `.xcframework` directory: + + $ xcodebuild -create-xcframework -output ./liberlang.xcframework -library liberlang.a + +If you're building for multiple iOS targets (e.g. simulator and phone): + + $ xcodebuild -create-xcframework -output ./liberlang.xcframework -library /Path/to/phonelib/liberlang.a -library /Path/to/simulatorlib/liberlang.a + +## Starting Erlang + +To execute erlang from within an iOS project a native C/C++ wrapper is needed that can call the function: + + erl_start(int argc, char *argv[]); + +An example call could look like this: + + $ const char *args[] = { + "my_main", + "-sbwt", + "none", + "--", + "-root", + root_dir.c_str(), + "-progname", + "erl", + "--", + "-home", + home_dir.c_str(), + "--", + "-kernel", + "shell_history", + "enabled", + "--", + "-start_epmd", + "false", + "-elixir", + "ansi_enabled", + "true", + "-noshell", + "-s", + "elixir", + "start_cli", + "-mode", + "interactive", + "-config", + config_path.c_str(), + "-boot", + boot_path.c_str(), + "-boot_var", + "RELEASE_LIB", + lib_path.c_str(), + "--", + "--", + "-extra", + "--no-halt", + }; + + erl_start(sizeof(args) / sizeof(args[0]), (char **)args); + +### Reference Example + +At the time of writing (October 2021) there is a full reference iOS application available at https://github.com/elixir-desktop/ios-example-app. + +An implementation of the native wrapper can be viewed at https://github.com/elixir-desktop/ios-example-app/blob/main/native-lib.cpp. + diff --git a/HOWTO/INSTALL-RASPBERRYPI3.md b/HOWTO/INSTALL-RASPBERRYPI3.md index a32bad052b5d..77fdc67f552c 100644 --- a/HOWTO/INSTALL-RASPBERRYPI3.md +++ b/HOWTO/INSTALL-RASPBERRYPI3.md @@ -257,9 +257,9 @@ Uncheck option: (20) - $ wget http://zlib.net/zlib-1.2.12.tar.gz - $ tar xf zlib-1.2.12.tar.gz - $ pushd zlib-1.2.12 + $ wget http://zlib.net/zlib-1.2.13.tar.gz + $ tar xf zlib-1.2.13.tar.gz + $ pushd zlib-1.2.13 $ CHOST=armv8-rpi3-linux-gnueabihf ./configure --prefix=/Volumes/xtools-build-env/local $ make $ make install diff --git a/HOWTO/INSTALL-WIN32-OLD.md b/HOWTO/INSTALL-WIN32-OLD.md index 4722771202d8..d2a0125ac775 100644 --- a/HOWTO/INSTALL-WIN32-OLD.md +++ b/HOWTO/INSTALL-WIN32-OLD.md @@ -47,7 +47,7 @@ to make the Erlang/OTP distribution for Windows better. Please submit any suggestions or patches to our [git project] [2] to let them find their way into the next version of Erlang. If making changes to the build system (like makefiles etc) please bear in mind that the -same makefiles are used on Unix/VxWorks, so that your changes +same makefiles are used on Unix, so that your changes don't break other platforms. That of course goes for C-code too; system specific code resides in the `$ERL_TOP/erts/emulator/sys/win32` and `$ERL_TOP/erts/etc/win32` directories mostly. The @@ -728,7 +728,7 @@ Lets get into more detail: 2. `$ ./otp_build boot -a` - This uses the bootstrap directory (shipped with the source, `$ERL_TOP/bootstrap`) to build a complete OTP system. When this is done you can run erl from within the source tree; - just type `$ERL_TOP/bin/erl` and you whould have the prompt. + just type `$ERL_TOP/bin/erl` and you would have the prompt. 3. `$ ./otp_build release -a` - Builds a commercial release tree from the source tree. The default is to put it in `$ERL_TOP/release/win32`. You can diff --git a/HOWTO/INSTALL-WIN32.md b/HOWTO/INSTALL-WIN32.md index c17cfbe5a378..f0f254fff65e 100644 --- a/HOWTO/INSTALL-WIN32.md +++ b/HOWTO/INSTALL-WIN32.md @@ -31,7 +31,7 @@ to make the Erlang/OTP distribution for Windows better. Please submit any suggestions or patches to our [git project] [1] to let them find their way into the next version of Erlang. If making changes to the build system (like makefiles etc) please bear in mind that the -same makefiles are used on Unix/VxWorks, so that your changes +same makefiles are used on Unix, so that your changes don't break other platforms. That of course goes for C-code too; system specific code resides in the `$ERL_TOP/erts/emulator/sys/win32` and `$ERL_TOP/erts/etc/win32` directories mostly. The @@ -61,14 +61,14 @@ This is the short story though, for the experienced and impatient: * Get, build and install OpenSSL v1.1.1d or later (up to 1.1.1d tried & working) with static libs. - * Get, build and install wxWidgets-3.1.3 or later (up to 3.1.3 - tried & working) with static libs. + * Get, build and install wxWidgets-3.2.2.1 or later (up to that + version tried & working) with static libs. * Get the Erlang source distribution (from ) and unpack with `tar` to the windows disk for example to: /mnt/c/src/ - * Install mingw-gcc, and make: `sudo apt install g++-mingw-w64 gcc-mingw-w64 make` + * Install mingw-gcc, and make: `sudo apt update && sudo apt install g++-mingw-w64 gcc-mingw-w64 make` * `$ cd UNPACK_DIR` @@ -143,29 +143,29 @@ the different tools: You need this to build crypto, ssh and ssl libs. We recommend v1.1.1d or later. - There are prebuilt avaiable binaries, which you can just + There are prebuilt available binaries, which you can just download and install, available here: URL: Install into `C:/OpenSSL-Win64` (or `C:/OpenSSL-Win32`) * wxWidgets (optional) - You need this to build wx and use gui's in debugger and observer. + You need this to build wx to use gui's in debugger and observer. - We recommend v3.1.4 or later. - Unpack into `c:/opt/local64/pgm/wxWidgets-3.1.4` + We recommend v3.2.2.1 or later. + Unpack into `c:/opt/local64/pgm/wxWidgets-3.2.2.1` - If the `wxUSE_POSTSCRIPT` isn't enabled in `c:/opt/local64/pgm/wxWidgets-3.1.4/include/wx/msw/setup.h`, + If the `wxUSE_POSTSCRIPT` isn't enabled in `c:/opt/local64/pgm/wxWidgets-3.2.2.1/include/wx/msw/setup.h`, enable it. We recommend to enable for wxWebView wxUSE_WEBVIEW_EDGE. * Download the nuget package 'Microsoft.Web.WebView2' (Version 0.9.488 or newer) * Extract the package (it's a zip archive) to wxWidgets/3rdparty/webview2 (you should have 3rdparty/webview2/build/native/include/WebView2.h file after unpacking it) - * Enable wxUSE_WEBVIEW_EDGE in `c:/opt/local64/pgm/wxWidgets-3.1.4/include/wx/msw/setup.h` + * Enable wxUSE_WEBVIEW_EDGE in `c:/opt/local64/pgm/wxWidgets-3.2.2.1/include/wx/msw/setup.h` Build with: - C:\...\> cd c:\opt\local64\pgm\wxWidgets-3.1.4\build\msw + C:\...\> cd c:\opt\local64\pgm\wxWidgets-3.2.2.1\build\msw C:\...\> nmake TARGET_CPU=amd64 BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc Remove the `TARGET_CPU=amd64` for 32bit build. diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md index e7fb4ad27a55..bfe488ff9f9c 100644 --- a/HOWTO/INSTALL.md +++ b/HOWTO/INSTALL.md @@ -6,7 +6,7 @@ Introduction This document describes how to build and install Erlang/OTP-%OTP-REL%. Erlang/OTP should be possible to build from source on any Unix/Linux system, -including OS X. You are advised to read the whole document +including macOS. You are advised to read the whole document before attempting to build and install Erlang/OTP. The source code can be downloaded from the official site of Erlang/OTP or GitHub. @@ -38,7 +38,7 @@ These are the tools you need in order to unpack and build Erlang/OTP. Build the same way as when building the unpacked tar file. -#### Building on OS X #### +#### Building on macOS #### * Xcode -- Download and install via the Mac App Store. Read about [Building on a Mac][] before proceeding. @@ -47,7 +47,6 @@ Build the same way as when building the unpacked tar file. * An `install` program that can take multiple file names. - Optional Utilities ------------------ @@ -85,8 +84,6 @@ also find the utilities needed for building the documentation. Further instructions on wxWidgets, read [Building with wxErlang][]. - - ### Building Documentation ### * `xsltproc` -- A command line XSLT processor. @@ -98,8 +95,6 @@ also find the utilities needed for building the documentation. * `fop` -- Apache FOP print formatter (requires Java). Can be downloaded from . - - How to Build and Install Erlang/OTP ----------------------------------- @@ -137,14 +132,12 @@ set. If you get errors when building, try setting the LANG variable: $ export LANG=C # Assuming bash/sh - ### Building ### Build the Erlang/OTP release. $ make - ### Testing ### Before installation you should test whether your build is working properly @@ -173,13 +166,11 @@ The following command will install the release on your system. $ make install - ### Running ### You should now have a working release of Erlang/OTP! Jump to [System Principles][] for instructions on running Erlang/OTP. - ### How to Build the Documentation ### Make sure you're in the top directory in the source tree. @@ -396,11 +387,10 @@ Some of the available `configure` options are: that do not support dynamic linking of libraries it is possible to statically link nifs and drivers with the main Erlang VM binary. This is done by passing a comma separated list to the archives that you want to statically link. e.g. - `--enable-static-nifs=/home/$USER/my_nif.a`. The path has to be absolute and the - name of the archive has to be the same as the module, i.e. `my_nif` in the - example above. This is also true for drivers, but then it is the driver name - that has to be the same as the filename. You also have to define - `STATIC_ERLANG_{NIF,DRIVER}` when compiling the .o files for the nif/driver. + `--enable-static-nifs=/home/$USER/my_nif.a`. The paths have to be absolute. + For drivers, the driver name has to be the same as the filename. You also + have to define `STATIC_ERLANG_NIF_LIBNAME` (see `erl_nif` documentation) or + `STATIC_ERLANG_DRIVER` when compiling the .o files for the nif/driver. If your nif/driver depends on some other dynamic library, you now have to link that to the Erlang VM binary. This is easily achieved by passing `LIBS=-llibname` to configure. @@ -409,7 +399,7 @@ Some of the available `configure` options are: should be compiled without one or more applications, i.e. `--without-wx`. There is no automatic dependency handling between applications. If you disable an application that another application depends on, you also have to disable the - dependant application. + dependent application. * `--enable-gettimeofday-as-os-system-time` - Force usage of `gettimeofday()` for OS system time. * `--enable-prefer-elapsed-monotonic-time-during-suspend` - Prefer an OS monotonic @@ -543,7 +533,7 @@ Other useful information can be found at our GitHub wiki: Build the same way as when building the unpacked tar file. -#### OS X (Darwin) #### +#### macOS (Darwin) #### Make sure that the command `hostname` returns a valid fully qualified host name (this is configured in `/etc/hostconfig`). Otherwise you might experience @@ -559,21 +549,24 @@ If you have Xcode 4.3, or later, you will also need to download #### Building with wxErlang #### -If you want to build the `wx` application, you will need to get wxWidgets-3.0 -(`wxWidgets-3.0.3.tar.bz2` from ) or get it from github with bug fixes: - - $ git clone --branch WX_3_0_BRANCH git@github.com:wxWidgets/wxWidgets.git +wxWidgets-3.2.x is recommended for building the `wx` application +(wxWidgets-3.0.x will also work). Download it from + or from +. It is recommended to use the +latest release in the 3.2 series, which at the time of writing +is 3.2.2.1. -The wxWidgets-3.1 version should also work if 2.8 compatibility is enabled, -add `--enable-compat28` to configure commands below. +Note that the wxWidgets-3.3 versions are experimental, but they should +also work if 3.0 compatibility is enabled by adding +`--enable-compat30` to the `configure` commands below. -Configure and build wxWidgets (shared library on linux): +On all other platforms, a shared library is built as follows: $ ./configure --prefix=/usr/local $ make && sudo make install $ export PATH=/usr/local/bin:$PATH -Configure and build wxWidgets (static library on linux): +On Linux, a static library is built as follows: $ export CFLAGS=-fPIC $ export CXXFLAGS=-fPIC @@ -581,26 +574,28 @@ Configure and build wxWidgets (static library on linux): $ make && sudo make install $ export PATH=/usr/local/bin:$PATH -Configure and build wxWidgets (on Mavericks - 10.9): +On macOs, a static library compatible with macOS 13 (Ventura) and later is built +as follows: - $ ./configure --with-cocoa --prefix=/usr/local - or without support for old versions and with static libs - $ ./configure --with-cocoa --prefix=/usr/local --with-macosx-version-min=10.9 --disable-shared + $ ./configure --prefix=/usr/local --with-macosx-version-min=13.0 --disable-shared $ make $ sudo make install $ export PATH=/usr/local/bin:$PATH -Check that you got the correct wx-config +Verify that the build and installation succeeded: $ which wx-config && wx-config --version-full -Build Erlang/OTP +Expected output is `/usr/local/bin/wx-config` on one line, followed by the full +version number. For example, if you built version 3.2.2.1, the expected output is: - $ export PATH=/usr/local/bin:$PATH - $ cd $ERL_TOP - $ ./configure - $ make - $ sudo make install + /usr/local/bin/wx-config + 3.2.2.1 + +Build Erlang/OTP in the usual way. To verify that `wx` application is +working run the following command: + + $ erl -run wx demo #### Pre-built Source Release #### @@ -751,33 +746,9 @@ passed to `configure`. One can force relative, or absolute links by passing phase. Note that such a request might cause a failure if the request cannot be satisfied. +## Erlang/OTP test architectures ## -### Running ### - - [$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md - [$ERL_TOP/HOWTO/INSTALL-WIN32.md]: INSTALL-WIN32.md - [DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html - [Building in Git]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Within-Git - [Advanced Configure]: #Advanced-configuration-and-build-of-ErlangOTP_Configuring - [Pre-built Source Release]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Prebuilt-Source-Release - [make and $ERL_TOP]: #Advanced-configuration-and-build-of-ErlangOTP_make-and-ERLTOP - [html documentation]: http://www.erlang.org/download/otp_doc_html_%OTP-VSN%.tar.gz - [man pages]: http://www.erlang.org/download/otp_doc_man_%OTP-VSN%.tar.gz - [the released source tar ball]: http://www.erlang.org/download/otp_src_%OTP-VSN%.tar.gz - [System Principles]: system/system_principles:system_principles - [native build]: #How-to-Build-and-Install-ErlangOTP - [cross build]: INSTALL-CROSS.md - [Required Utilities]: #Required-Utilities - [Optional Utilities]: #Optional-Utilities - [Building on a Mac]: #Advanced-configuration-and-build-of-ErlangOTP_Building_OS-X-Darwin - [Building with wxErlang]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Building-with-wxErlang - [libatomic_ops]: https://github.com/ivmai/libatomic_ops/ - - -### Erlang/OTP test architectures ### - - -Erlang/OTP are currently tested on the following hardware and Opererating systems. +Erlang/OTP are currently tested on the following hardware and operating systems. This is not an exhaustive list, but we try to keep it as up to date as possible. Architecture @@ -786,7 +757,7 @@ Architecture * Aarch32, Aarch64 * powerpc, powerpc64le -Operating System +Operating system * Fedora 31 * FreeBSD @@ -799,3 +770,21 @@ Operating System * Ubuntu 10.04 - 20.04 * Windows 10, Windows Server 2019 + [$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md + [$ERL_TOP/HOWTO/INSTALL-WIN32.md]: INSTALL-WIN32.md + [DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html + [Building in Git]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Within-Git + [Advanced Configure]: #Advanced-configuration-and-build-of-ErlangOTP_Configuring + [Pre-built Source Release]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Prebuilt-Source-Release + [make and $ERL_TOP]: #Advanced-configuration-and-build-of-ErlangOTP_make-and-ERLTOP + [html documentation]: https://github.com/erlang/otp/releases/download/OTP-%OTP-VSN%/otp_doc_html_%OTP-VSN%.tar.gz + [man pages]: https://github.com/erlang/otp/releases/download/OTP-%OTP-VSN%/otp_doc_man_%OTP-VSN%.tar.gz + [the released source tar ball]: https://github.com/erlang/otp/releases/download/OTP-%OTP-VSN%/otp_src_%OTP-VSN%.tar.gz + [System Principles]: system/system_principles:system_principles + [native build]: #How-to-Build-and-Install-ErlangOTP + [cross build]: INSTALL-CROSS.md + [Required Utilities]: #Required-Utilities + [Optional Utilities]: #Optional-Utilities + [Building on a Mac]: #Advanced-configuration-and-build-of-ErlangOTP_Building_macOS-Darwin + [Building with wxErlang]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Building-with-wxErlang + [libatomic_ops]: https://github.com/ivmai/libatomic_ops/ diff --git a/HOWTO/MARKDOWN.md b/HOWTO/MARKDOWN.md index 36c2b9c775d8..91b5526bf925 100644 --- a/HOWTO/MARKDOWN.md +++ b/HOWTO/MARKDOWN.md @@ -202,7 +202,7 @@ places. Appropriate attributes to the `X` tag will also be generated. This way it is relatively easy to make sure that all marker ids of a document are unique, but there is of course no guarantee that they are. - The upside of these auto generated markers is that we wont have to clutter + The upside of these auto generated markers is that we won't have to clutter the document with XML or something else while being able to refer into the document. The downside is that if you change a level 2 heading you change a lot of marker ids which may break links into a document from diff --git a/HOWTO/SYSTEMTAP.md b/HOWTO/SYSTEMTAP.md index 76deac97e59c..01b1fe8a47ce 100644 --- a/HOWTO/SYSTEMTAP.md +++ b/HOWTO/SYSTEMTAP.md @@ -43,7 +43,7 @@ Testing SystemTap, unlike DTrace, needs to know what binary it is tracing and has to be able to read that binary before it starts tracing. Your probe script -therefor has to reference the correct beam emulator and stap needs to be able +therefore has to reference the correct beam emulator and stap needs to be able to find that binary. The examples are written for "beam", but other versions such as "beam.smp" or "beam.debug.smp" might exist (depending on your configuration). Make sure you diff --git a/HOWTO/TESTING.md b/HOWTO/TESTING.md index f713f85231f3..c6bad4f65c35 100644 --- a/HOWTO/TESTING.md +++ b/HOWTO/TESTING.md @@ -5,17 +5,24 @@ Before you start testing you need to have the Erlang release which you are going to test in your path. See [$ERL_TOP/HOWTO/INSTALL.md][] for instructions on how to build an Erlang release. +*NOTE*: This instructions may vary for different versions of Erlang/OTP, +so make sure to read the instructions for the version that you are testing. + Short version ------------- -Move to the top directory of the Erlang release you want to test, i.e. -cd /ldisk/work/otp +Move to the top directory of the Erlang release you want to test, for example: +cd $HOME/git/otp + +```bash +export ERL_TOP=`pwd` # Define where the build root is +./configure && make # Build all of Erlang/OTP +make test # Test all of Erlang/OTP +``` - export ERL_TOP=`pwd` - ./otp_build setup -a - export PATH=`pwd`/bin:$PATH - ./otp_build tests - cd release/tests/test_server - erl -s ts install -s ts run all_tests -s init stop +The tests will take a long time to finish and will print a lot of logs to the +console even if tests pass. A full run takes close about 6 hours on a relatively +modern machine. See [Running tests while developing][] for details on how to run +only a subset of the tests. Where are the tests ------------------- @@ -46,14 +53,57 @@ the erl_interface tests use this feature and it should remain that way. [configuring the tests][]. These `Makefile`s are later run by the test suite to compile whatever platform specific code the tests need to run. +Running tests while developing +------------------------------ + +The `make test` command works when the current directory contains a directory +called test and in the root directory of the source code tree. + +Below are some examples that illustrate how `make test` can be +used: + +```bash +# ERL_TOP needs to be set correctly +cd /path/to/otp +export ERL_TOP=`pwd` + +# Build Erlang/OTP +# +# Note that make test will only compile test code except when +# make test is executed from $ERL_TOP. +./otp_build setup -a + +# Run all test suites for an application +(cd $ERL_TOP/lib/asn1 && make test) +make asn1_test + +# Run a test suite (The ARGS variable is passed to ct_run) +(cd $ERL_TOP/lib/stdlib && make test ARGS="-suite ets_SUITE") +make stdlib_test ARGS="-suite ets_SUITE" + +# Run a test case +(cd $ERL_TOP/erts/emulator && make test ARGS="-suite binary_SUITE -case deep_bitstr_lists") +make emulator_test ARGS="-suite binary_SUITE -case deep_bitstr_lists" + +# Run all tests +# +# When executed from $ERL_TOP, "make test" will first release and +# configure all tests and then attempt to run all tests with `ts:run`. +# This will take several hours. +(cd $ERL_TOP && make test) +``` + +For more examples see [DEVELOPMENT.md](DEVELOPMENT.md) + Releasing tests --------------- -If you cannot use [ct_run][] in the source tree you have to release the tests -into a common test directory. The easiest way to do this is to use `otp_build` -like this: +When not testing in the source tree, you first need to release all tests. +The easiest way to do this is to use `otp_build` like this: - export ERL_TOP=`pwd`; ./otp_build tests +```bash +export ERL_TOP=`pwd`; ./otp_build tests +``` This will release all tests in Erlang/OTP to `$ERL_TOP/release/tests/`. If you want to change the directory where the tests are released to use the `TESTROOT` @@ -99,24 +149,31 @@ All variables created by `ts:install()` are found in To run all test suites go to `$TESTROOT/test_server` fire up an Erlang shell and type: - ts:run(). +```erlang +ts:run(). +``` Note that running all tests will require several hours, so you may want to run the test cases for a single application - ts:run(Application, [batch]). +```erlang +ts:run(Application, [batch]). +``` or even part of the test suite for an application, for example - ts:run(emulator, bs, [batch]). +```erlang +ts:run(emulator, bs_construct_SUITE, [batch]). +``` -to run all test suite modules starting with `bs` (i.e. all modules that test -the bit syntax). +to run the tests in the `bs_construct_SUITE` module (testing construction of +binaries using the binary syntax). -To run a specific test case in a module, the full name of the module and test -case must be specified: +It is also possible to run a single test case by the specifying the module name and a function name: - ts:run(emulator, bs_bincomp_SUITE, byte_aligned, [batch]). +```erlang +ts:run(emulator, bs_bincomp_SUITE, byte_aligned, [batch]). +``` Run `ts:help().` for more information. @@ -124,66 +181,20 @@ As of R14B02 it is also possibly to start all tests but the erl_interface tests by invoking Common Test directly from the released applications test directory, i.e. - cd $TESTROOT/test_server - $ERL_TOP/bin/ct_run -suite ../compiler_test/andor_SUITE -case t_orelse +```bash +cd $TESTROOT/test_server +$ERL_TOP/bin/ct_run -suite ../compiler_test/andor_SUITE -case t_orelse +``` Running [ct_run][] from the command line still requires you to do the `ts:install()` step above. -### Convenience for running tests without the release and configuration steps - -It can be convenient to run tests with a single command. This way, one -do not need to worry about missing to run `make release_tests` after -changing a test suite. The `make test` command can be used for this -purpose. The `make test` command works when the current directory -contains a directory called test and in the root directory of the -source code tree. - -*(Warning)* Some test cases do not run correctly or cannot be run at -all through the `make test` command (typically test cases that require -test specific C code to be compiled) because `make test` runs tests -directly by invoking the `ct_run` command instead of using the `ts` -wrapper. One has to follow the procedure described above to run test -cases that do not work with `make test`. - -Below are some examples that illustrate how `make test` can be -used: - - # ERL_TOP needs to be set correctly - cd /path/to/otp - export ERL_TOP=`pwd` - - # Build Erlang/OTP - # - # Note that make test will only compile test code except when - # make test is executed from $ERL_TOP. - ./otp_build setup -a - - # Run a test case (The ARGS variable is passed to ct_run) - (cd $ERL_TOP/erts/emulator && make ARGS="-suite binary_SUITE -case deep_bitstr_lists" test) - - # Run a test suite - (cd $ERL_TOP/lib/stdlib && make ARGS="-suite ets_SUITE" test) - - # Run all test suites for an application - (cd $ERL_TOP/lib/asn1 && make test) - - # Run all tests - # - # When executed from $ERL_TOP, "make test" will first release and - # configure all tests and then attempt to run all tests with `ts:run`. - # This will take several hours. - (cd $ERL_TOP && make test) - - Examining the results --------------------- -Open the file `release/tests/test_server/index.html` in a web browser. Or open -`release/tests/test_server/last_test.html` when a test suite is running to -examine the results so far for the currently executing test suite (in R14B02 and -later you want to open the `release/tests/test_server/all_runs.html` file to -get to the currently running test) +Open the file `$ERL_TOP/release/tests/test_server/index.html` in a web browser. Or open +`$ERL_TOP/release/tests/test_server/suite.log.latest.html` when a test suite is running to +examine the results so far for the currently executing test suite. Run tests with Address Sanitizer @@ -195,15 +206,19 @@ See [$ERL_TOP/HOWTO/INSTALL.md][]. Set environment variable `ASAN_LOG_DIR` to the directory where the error logs will be generated. - export ASAN_LOG_DIR=$TESTROOT/test_server/asan_logs - mkdir $ASAN_LOG_DIR +```bash +export ASAN_LOG_DIR=$TESTROOT/test_server/asan_logs +mkdir $ASAN_LOG_DIR +``` Set environment variable `TS_RUN_EMU` to `asan`. - export TS_RUN_EMU=asan +```bash +export TS_RUN_EMU=asan +``` -Then run the tests you want with `ts:run` as described above. Either -inspect the log files directly or use the script at +Then run the tests you want with `ts:run` as [described above](#running-the-tests). +Either inspect the log files directly or use the script at `$ERL_TOP/erts/emulator/asan/asan_logs_to_html` to read all log files in `$ASAN_LOG_DIR` and distill them into one html page `asan_summary.html`. Repeated reports from the same memory leak will @@ -220,15 +235,19 @@ and build the emulator with `valgrind` build target. See Set environment variable `VALGRIND_LOG_DIR` to the directory where the valgrind error logs will be generated. - export VALGRIND_LOG_DIR=$TESTROOT/test_server/vg_logs - mkdir $VALGRIND_LOG_DIR +```bash +export VALGRIND_LOG_DIR=$TESTROOT/test_server/vg_logs +mkdir $VALGRIND_LOG_DIR +``` Set environment variable `TS_RUN_EMU` to `valgrind`. - export TS_RUN_EMU=valgrind +```bash +export TS_RUN_EMU=valgrind +``` -Then run the tests you want with `ts:run` as described above and -inspect the log file(s) in `$VALGRIND_LOG_DIR`. +Then run the tests you want with `ts:run` as [described above](#running-the-tests) +and inspect the log file(s) in `$VALGRIND_LOG_DIR`. [ct_run]: http://www.erlang.org/doc/man/ct_run.html @@ -239,5 +258,6 @@ inspect the log file(s) in `$VALGRIND_LOG_DIR`. [data_dir]: http://www.erlang.org/doc/apps/common_test/write_test_chapter.html#data_priv_dir [configuring the tests]: #configuring-the-test-environment [valgrind]: https://valgrind.org + [Running tests while developing]: #running-tests-while-developing [?TOC]: true diff --git a/Makefile.in b/Makefile.in index 3746c703e1a7..72ae67524aae 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2021. All Rights Reserved. +# Copyright Ericsson AB 1998-2022. 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. @@ -294,6 +294,13 @@ RELEASE_ROOT = $(TESTROOT) endif endif +# ---------------------------------------------------------------------- + +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif # ---------------------------------------------------------------------- @@ -372,12 +379,12 @@ endif # bootstrap is not included, it requires a pre built emulator... ifeq ($(OTP_TINY_BUILD),true) all_bootstraps: erl_interface emulator bootstrap_setup \ - tiny_secondary_bootstrap_build tiny_secondary_bootstrap_copy + tiny_secondary_bootstrap_copy else all_bootstraps: erl_interface emulator \ bootstrap_setup \ - secondary_bootstrap_build secondary_bootstrap_copy \ - tertiary_bootstrap_build tertiary_bootstrap_copy + secondary_bootstrap_copy \ + tertiary_bootstrap_copy endif # @@ -398,10 +405,16 @@ ifeq ($(OTP_SMALL_BUILD),true) cd $(ERL_TOP)/lib && \ ERL_TOP=$(ERL_TOP) PATH=$(INST_PATH_PREFIX)"$${PATH}" \ $(MAKE) TESTROOT="$(RELEASE_ROOT)" release +else +ifeq ($(OTP_TINY_BUILD),true) + cd $(ERL_TOP)/lib && \ + ERL_TOP=$(ERL_TOP) PATH=$(INST_PATH_PREFIX)"$${PATH}" \ + $(MAKE) TINY_BUILD=true TESTROOT="$(RELEASE_ROOT)" release else cd $(ERL_TOP)/lib && \ ERL_TOP=$(ERL_TOP) PATH=$(INST_PATH_PREFIX)"$${PATH}" \ $(MAKE) BUILD_ALL=1 TESTROOT="$(RELEASE_ROOT)" release +endif endif cd $(ERL_TOP)/erts && \ ERL_TOP=$(ERL_TOP) PATH=$(INST_PATH_PREFIX)"$${PATH}" \ @@ -416,7 +429,7 @@ endif # Target only used when building commercial ERTS patches # --------------------------------------------------------------- -release_docs docs: doc_bootstrap_build doc_bootstrap_copy mod2app +release_docs docs: doc_bootstrap_copy mod2app ifeq ($(OTP_SMALL_BUILD),true) cd $(ERL_TOP)/lib && \ PATH=$(BOOT_PREFIX)"$${PATH}" ERL_TOP=$(ERL_TOP) \ @@ -451,7 +464,7 @@ endif $(DOCGEN)/priv/bin/validate_links.escript $(ERL_TOP) make/$(TARGET)/mod2app.xml \ lib/*/doc/xml/*.xml erts/doc/xml/*.xml system/doc/xml/*/*.xml -mod2app: doc_bootstrap_build doc_bootstrap_copy $(ERL_TOP)/make/$(TARGET)/mod2app.xml +mod2app: doc_bootstrap_copy $(ERL_TOP)/make/$(TARGET)/mod2app.xml $(ERL_TOP)/make/$(TARGET)/mod2app.xml: erts/doc/src/Makefile lib/*/doc/src/Makefile PATH=$(BOOT_PREFIX)"$${PATH}" escript $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/priv/bin/xref_mod_app.escript -topdir $(ERL_TOP) -outfile $(ERL_TOP)/make/$(TARGET)/mod2app.xml @@ -466,7 +479,7 @@ BOOTSTRAP_COMPILER = $(BOOTSTRAP_TOP)/primary_compiler # otp.mk is only used to figure out if we are doing PGO or not include $(ERL_TOP)/make/$(TARGET)/otp.mk -.PHONY: emulator libs kernel preloaded +.PHONY: emulator libs kernel preloaded system ifeq ($(USE_PGO), true) PROFILE=use @@ -479,6 +492,13 @@ PROFILE= PROFILE_EMU_DEPS= endif +emulator_test: emulator + $(make_verbose)cd erts/emulator && ERL_TOP=$(ERL_TOP) TYPE=$(TYPE) $(MAKE) test +epmd_test: + $(make_verbose)cd erts/epmd && ERL_TOP=$(ERL_TOP) TYPE=$(TYPE) $(MAKE) test +system_test: + $(make_verbose)cd erts && ERL_TOP=$(ERL_TOP) TYPE=$(TYPE) $(MAKE) test + emulator: $(PROFILE_EMU_DEPS) $(make_verbose)cd erts && ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ $(MAKE) NO_START_SCRIPTS=true $(TYPE) FLAVOR=$(FLAVOR) PROFILE=$(PROFILE) @@ -503,13 +523,14 @@ endif endif APPS=$(patsubst $(ERL_TOP)/lib/%/doc,%,$(wildcard $(ERL_TOP)/lib/*/doc)) +NO_DIALYZER_APPS=$(filter-out dialyzer, $(APPS)) ## The dialyzer make target should not build the app -.PHONY: $(APPS) +.PHONY: $(NO_DIALYZER_APPS) -$(APPS): +$(NO_DIALYZER_APPS): $(make_verbose)cd lib/$@ && \ ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ - $(MAKE) $(TYPE) BUILD_ALL=true + $(MAKE) $(TYPE) ## ## Generate `otp_internal` from the -deprecated() attributes in source. @@ -567,14 +588,18 @@ bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/escript.exe @cp $(ERL_TOP)/erts/lib_src/yielding_c_fun/bin/$(TARGET)/yielding_c_fun.exe \ $(BOOTSTRAP_ROOT)/bootstrap/bin/yielding_c_fun.exe + @cp $(ERL_TOP)/bin/$(TARGET)/inet_gethost.exe \ + $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost.exe else -bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc $(BOOTSTRAP_ROOT)/bootstrap/bin/escript $(BOOTSTRAP_ROOT)/bootstrap/bin/yielding_c_fun +bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc $(BOOTSTRAP_ROOT)/bootstrap/bin/escript $(BOOTSTRAP_ROOT)/bootstrap/bin/yielding_c_fun $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost $(BOOTSTRAP_ROOT)/bootstrap/bin/erl: $(ERL_TOP)/erts/etc/unix/erl.src.src $(BOOTSTRAP_ROOT)/bootstrap/target - @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl + @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl @sed -e "s;%FINAL_ROOTDIR%;$(BOOTSTRAP_ROOT)/bootstrap;" \ -e "s;\$$ROOTDIR/erts-.*/bin;$(ERL_TOP)/bin/$(TARGET);" \ -e "s;EMU=.*;EMU=beam$(TYPEMARKER);" \ + -e "s;%DYN_ERL_PATH%;../../bin/$(TARGET)/dyn_erl;" \ + -e "s;%DYN_ROOTDIR_BASE_EXT%;/bootstrap;" \ $(ERL_TOP)/erts/etc/unix/erl.src.src > \ $(BOOTSTRAP_ROOT)/bootstrap/bin/erl @chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/erl @@ -595,103 +620,52 @@ $(BOOTSTRAP_ROOT)/bootstrap/bin/yielding_c_fun: $(ERL_TOP)/bin/$(TARGET)/escript @chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/yielding_c_fun endif -bootstrap_setup_target: +$(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost: $(ERL_TOP)/bin/$(TARGET)/inet_gethost $(BOOTSTRAP_ROOT)/bootstrap/target + @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost + @cp $(ERL_TOP)/bin/$(TARGET)/inet_gethost $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost + @chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET)/inet_gethost + +$(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET): + $(V_at)mkdir $@ + +bootstrap_setup_target: $(BOOTSTRAP_ROOT)/bootstrap/bin/$(TARGET) @{ test -r $(BOOTSTRAP_ROOT)/bootstrap/target && \ test $(TARGET) = `cat $(BOOTSTRAP_ROOT)/bootstrap/target`; } || \ echo $(TARGET) > $(BOOTSTRAP_ROOT)/bootstrap/target -tiny_secondary_bootstrap_build: - $(make_verbose)cd lib && \ - ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ - $(MAKE) opt SECONDARY_BOOTSTRAP=true TINY_BUILD=true ERL_COMPILE_WARNINGS_AS_ERRORS=yes - -secondary_bootstrap_build: - $(make_verbose)cd lib && \ - ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ - $(MAKE) opt SECONDARY_BOOTSTRAP=true ERL_COMPILE_WARNINGS_AS_ERRORS=yes - -tiny_secondary_bootstrap_copy: - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; fi - $(V_at)for x in lib/parsetools/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - $(V_at)for x in lib/parsetools/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; fi - $(V_at)for x in lib/sasl/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - -secondary_bootstrap_copy: - $(make_verbose) - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include ; fi - $(V_at)for x in lib/parsetools/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# $(V_at)${INSTALL_DATA} -p lib/parsetools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/ebin - $(V_at)for x in lib/parsetools/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# $(V_at)${INSTALL_DATA} -p -f lib/parsetools/include/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/parsetools/include - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1 ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src ; fi - $(V_at)for x in lib/asn1/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# $(V_at)${INSTALL_DATA} -p lib/asn1/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/ebin - $(V_at)for x in lib/asn1/src/*.[eh]rl; do \ +# The TINY SECONDARY bootstrap +# - sasl needed to create start.boot +# - parsetools needed by anything with an yrl +TINY_SECONDARY_BOOTSTRAP=parsetools sasl +TINY_SECONDARY_BOOTSTRAP_BUILD=$(TINY_SECONDARY_BOOTSTRAP) +# The SECONDARY bootstrap +# - asn1 needed by public_key +SECONDARY_BOOTSTRAP=$(TINY_SECONDARY_BOOTSTRAP) asn1 +SECONDARY_BOOTSTRAP_BUILD=$(TINY_SECONDARY_BOOTSTRAP_BUILD) asn1/src + +# The TERTIARY bootstrap +# - wx is needed for wx_object behaviour in debugger, observer and et +# - public_key is needed for include files in ssl and ssh +# - erl_interface is needed by odbc +# - syntax_tools is needed by diameter +# - snmp is needed to compile tests +# - runtime_tools includes are needed by observer +# - xmerl includes are needed by ct, edoc, erl_docgen and wx +# - common_test is needed to compile tests +TERTIARY_BOOTSTRAP_BUILD=parsetools wx public_key erl_interface syntax_tools snmp +TERTIARY_BOOTSTRAP=$(TERTIARY_BOOTSTRAP_BUILD) runtime_tools xmerl common_test + +# The DOC bootstrap +DOC_BOOTSTRAP_BUILD=xmerl edoc erl_docgen +DOC_BOOTSTRAP=$(DOC_BOOTSTRAP_BUILD) + +$(BOOTSTRAP_ROOT)/bootstrap/lib/%/update: + $(V_at)for x in "$(dir $@)" "$(dir $@)/ebin" "$(dir $@)/include"; do \ + if [ ! -d "$$x" ]; then mkdir "$$x"; fi \ + done + $(V_at)for x in $(wildcard lib/$*/ebin/*.beam); do \ BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src/$$BN; \ + TF=$(dir $@)/ebin/$$BN; \ test -f $$TF && \ test '!' -z "`find $$x -newer $$TF -print`" && \ ${INSTALL_DATA} -p $$x $$TF; \ @@ -699,234 +673,39 @@ secondary_bootstrap_copy: ${INSTALL_DATA} -p $$x $$TF; \ true; \ done -# $(V_at)${INSTALL_DATA} -p -f lib/asn1/src/*.erl lib/asn1/src/*.hrl $(BOOTSTRAP_ROOT)/bootstrap/lib/asn1/src - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; fi - $(V_at)for x in lib/xmerl/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ + $(V_at)for x in $(wildcard lib/$*/include/*.hrl) $(wildcard lib/$*/include/*.h); do \ + BN=`basename $$x`; \ + TF=$(dir $@)/include/$$BN; \ + test -f $$TF && \ + test '!' -z "`find $$x -newer $$TF -print`" && \ + ${INSTALL_DATA} -p $$x $$TF; \ + test '!' -f $$TF && \ + ${INSTALL_DATA} -p $$x $$TF; \ + true; \ done -tertiary_bootstrap_build: +tiny_secondary_bootstrap: $(make_verbose)cd lib && \ ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ - $(MAKE) opt TERTIARY_BOOTSTRAP=true ERL_COMPILE_WARNINGS_AS_ERRORS=yes - -tertiary_bootstrap_copy: - $(make_verbose) - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/include ; fi - $(V_at)for x in lib/snmp/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# $(V_at)${INSTALL_DATA} -p lib/snmp/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/snmp/ebin - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/public_key ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/public_key ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/public_key/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/public_key/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/ ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/ ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang ; fi - $(V_at)for x in lib/sasl/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# $(V_at)${INSTALL_DATA} -p lib/sasl/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin ; fi - $(V_at)for x in lib/syntax_tools/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - $(V_at)for x in lib/wx/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/wx/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# copy wx_object to remove undef behaviour warnings - $(V_at)for x in lib/wx/ebin/wx_object.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - -# copy test includes to be able to compile tests with bootstrap compiler - $(V_at)for x in lib/common_test/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - -# copy runtime_tool includes to be able to compile with include_lib - $(V_at)for x in lib/runtime_tools/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# copy public_key includes to be able to compile with include_lib - $(V_at)for x in lib/public_key/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/public_key/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# copy erl_interface includes - $(V_at)for x in lib/erl_interface/include/*.h; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# copy jinterface priv directory - $(V_at)if test -d lib/jinterface/priv; then \ - for x in lib/jinterface/priv/OtpErlang.jar; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done; \ - for x in lib/jinterface/priv/com/ericsson/otp/erlang/*; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done; \ - fi -# $(V_at)${INSTALL_DATA} -p lib/syntax_tools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin + $(MAKE) opt BOOTSTRAP="$(TINY_SECONDARY_BOOTSTRAP_BUILD)" ERL_COMPILE_WARNINGS_AS_ERRORS=yes -doc_bootstrap_build: +secondary_bootstrap: $(make_verbose)cd lib && \ ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ - $(MAKE) opt DOC_BOOTSTRAP=true + $(MAKE) opt BOOTSTRAP="$(SECONDARY_BOOTSTRAP_BUILD)" ERL_COMPILE_WARNINGS_AS_ERRORS=yes -doc_bootstrap_copy: - $(make_verbose) -# XMERL - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/ebin ; fi - $(V_at)for x in lib/xmerl/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# xmerl/include already copied in secondary bootstrap -# EDOC - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/ebin ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/include ; fi - $(V_at)for x in lib/edoc/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done - $(V_at)for x in lib/edoc/include/*.hrl; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/edoc/include/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done -# ERL_DOCGEN - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen ; fi - $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/ebin ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/ebin ; fi - $(V_at)for x in lib/erl_docgen/ebin/*.beam; do \ - BN=`basename $$x`; \ - TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/ebin/$$BN; \ - test -f $$TF && \ - test '!' -z "`find $$x -newer $$TF -print`" && \ - ${INSTALL_DATA} -p $$x $$TF; \ - test '!' -f $$TF && \ - ${INSTALL_DATA} -p $$x $$TF; \ - true; \ - done +tiny_secondary_bootstrap_copy: tiny_secondary_bootstrap $(foreach app, $(TINY_SECONDARY_BOOTSTRAP), $(BOOTSTRAP_ROOT)/bootstrap/lib/$(app)/update) +secondary_bootstrap_copy: secondary_bootstrap $(foreach app, $(SECONDARY_BOOTSTRAP), $(BOOTSTRAP_ROOT)/bootstrap/lib/$(app)/update) + +tertiary_bootstrap: + $(make_verbose) ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ + $(MAKE) -C lib opt BOOTSTRAP="$(TERTIARY_BOOTSTRAP_BUILD)" ERL_COMPILE_WARNINGS_AS_ERRORS=yes +tertiary_bootstrap_copy: tertiary_bootstrap $(foreach app, $(TERTIARY_BOOTSTRAP), $(BOOTSTRAP_ROOT)/bootstrap/lib/$(app)/update) + +doc_bootstrap: + $(make_verbose) ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \ + $(MAKE) -C lib opt BOOTSTRAP="$(DOC_BOOTSTRAP_BUILD)" +doc_bootstrap_copy: secondary_bootstrap_copy doc_bootstrap tertiary_bootstrap_copy $(foreach app, $(DOC_BOOTSTRAP), $(BOOTSTRAP_ROOT)/bootstrap/lib/$(app)/update) $(V_at)for d in priv priv/bin priv/css priv/dtd priv/dtd_html_entities priv/dtd_man_entities priv/images priv/js priv/js/flipmenu priv/xsl; do \ if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/$$d ; then mkdir -p $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/$$d ; fi; \ for x in lib/erl_docgen/$$d/*; do \ @@ -1011,9 +790,9 @@ primary_bootstrap: primary_bootstrap_build: primary_bootstrap_mkdirs primary_bootstrap_compiler \ primary_bootstrap_stdlib - $(make_verbose)cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin' \ - BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \ - BOOTSTRAP=1 opt + $(make_verbose)cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG)' \ + BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) PRIMARY_BOOTSTRAP=1 \ + BOOTSTRAP="kernel stdlib compiler" opt primary_bootstrap_compiler: $(make_verbose)cd lib/compiler && $(MAKE) \ @@ -1095,7 +874,7 @@ tests release_tests: $(TEST_DIRS) $(TEST_DIRS): if test -f $@/Makefile; then \ - (cd $@; $(MAKE) TESTROOT="$(TESTSUITE_ROOT)" \ + (cd $@; $(MAKE) TESTROOT="$(TESTSUITE_ROOT)" ERL_TOP="$(ERL_TOP)" \ PATH=$(TEST_PATH_PREFIX)$(BOOT_PREFIX)"$${PATH}" release_tests) || exit $$?; \ fi @@ -1219,7 +998,7 @@ bootstrap_clean: $(V_at)rm -f $(ERL_TOP)/bootstrap/lib/*/include/*.hrl $(V_at)rm -f $(ERL_TOP)/bootstrap/primary_compiler/ebin/* $(V_at)rm -f $(ERL_TOP)/bootstrap/primary_compiler/egen/* - $(V_at)rm -f $(ERL_TOP)/bootstrap/bin/*.* + $(V_at)rm -f $(ERL_TOP)/bootstrap/bin/*.boot $(V_at)rm -f $(KERNEL_PRELOAD:%=$(ERL_TOP)/lib/kernel/ebin/%.beam) $(V_at)test $(BOOTSTRAP_ROOT) = $(ERL_TOP) \ || $(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) bootstrap_root_clean @@ -1231,5 +1010,13 @@ bootstrap_clean: test: all release release_tests $(ERL_TOP)/make/test_target_script.sh $(ERL_TOP) +ifeq ($(TYPE),) dialyzer: all $(ERL_TOP)/scripts/run-dialyzer +endif + +APPS_TEST=$(patsubst %, %_test,$(APPS)) + +.SECONDEXPANSION: +$(APPS_TEST): $$(patsubst %_test,%,$$@) + ERL_TOP=$(ERL_TOP) TYPE=$(TYPE) $(MAKE) -C lib/$< test diff --git a/OTP_VERSION b/OTP_VERSION index 020c1b2b54f9..124b7a2cd061 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -24.3.4.13 +26.1.1 diff --git a/README.md b/README.md index 3530da414922..210b205200ca 100644 --- a/README.md +++ b/README.md @@ -4,58 +4,67 @@ **OTP** is a set of Erlang libraries, which consists of the Erlang runtime system, a number of ready-to-use components mainly written in Erlang, and a set of design principles for Erlang programs. [Learn more about Erlang and OTP](http://erlang.org/doc/system_architecture_intro/sys_arch_intro.html). -[Release notes](http://erlang.org/download/otp_versions_tree.html) for all OTP versions. - -[Learn how to program in Erlang](http://learnyousomeerlang.com/content). +[Learn how to program in Erlang](http://learnyousomeerlang.com/). ## Examples + There are several examples [on the website](http://erlang.org/faq/getting_started.html) to help you get started. The below example defines a function `world/0` that prints "Hello, world" in the Erlang shell: + ```erlang -module(hello). -export([world/0]). world() -> io:format("Hello, world\n"). ``` + Save the file as `hello.erl` and run `erl` to enter the Erlang shell to compile the module. -``` -Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] -Eshell V8.2 (abort with ^G) +```sh +Erlang/OTP 24 [erts-12.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] + +Eshell V12.2 (abort with ^G) 1> c(hello). {ok,hello} 2> hello:world(). Hello, world ok ``` + Learn more about the Erlang syntax of [modules](http://erlang.org/doc/reference_manual/modules.html), [functions](http://erlang.org/doc/reference_manual/functions.html) and [expressions](http://erlang.org/doc/reference_manual/expressions.html) on [Erlang.org](https://www.erlang.org). ## Installation + ### Binary Distributions + Erlang/OTP is available as pre-built binary packages by most OS package managers. -``` + +```sh apt-get install erlang ``` + ### Compiling from source -To compile Erlang from source, run the following commands. The complete building and installation instructions [can be found here](HOWTO/INSTALL.md). -``` +To compile Erlang from source, run the following commands. The complete building and installation instructions [can be found here](HOWTO/INSTALL.md). + +```sh git clone https://github.com/erlang/otp.git cd otp ``` + Checkout the branch or tag of your choice + +```sh +git checkout maint-25 # current latest stable version ``` -git checkout maint-24 # current latest stable version -``` -For older versions run autoconf -``` -./otp_build autoconf -``` + Configure, build and install -``` + +```sh ./configure make make install ``` + Alternatively, you can use [Kerl](https://github.com/kerl/kerl), a script that lets you easily build Erlang with a few commands. ## Bug Reports @@ -78,13 +87,17 @@ Read our [contribution guide](CONTRIBUTING.md) to learn about our development pr We have a list of [Help Wanted](https://github.com/erlang/otp/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) bugs that we would appreciate external help from the community. This is a great place to get involved. +## Awesome-Erlang + +You can find more projects, tools and articles related to Erlang/OTP on the [awesome-erlang list](https://github.com/drobakowski/awesome-erlang). Add your project there. + ## License Erlang/OTP is released under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). > %CopyrightBegin% > -> Copyright Ericsson AB 2010-2021. All Rights Reserved. +> Copyright Ericsson AB 2010-2023. 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. @@ -99,6 +112,3 @@ Erlang/OTP is released under the [Apache License 2.0](http://www.apache.org/lice > limitations under the License. > > %CopyrightEnd% - -## Awesome-Erlang -You can find more projects, tools and articles related to Erlang/OTP on the [awesome-erlang list](https://github.com/drobakowski/awesome-erlang). Add your project there. diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot index 4c9b49dbec50..384cb51b9043 100644 Binary files a/bootstrap/bin/no_dot_erlang.boot and b/bootstrap/bin/no_dot_erlang.boot differ diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot index 4c9b49dbec50..384cb51b9043 100644 Binary files a/bootstrap/bin/start.boot and b/bootstrap/bin/start.boot differ diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot index 4c9b49dbec50..384cb51b9043 100644 Binary files a/bootstrap/bin/start_clean.boot and b/bootstrap/bin/start_clean.boot differ diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam index 89d86ec819cb..82f077ac4a7b 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_a.beam and b/bootstrap/lib/compiler/ebin/beam_a.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam index 559a6df9c359..2258e3eccbf1 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_asm.beam and b/bootstrap/lib/compiler/ebin/beam_asm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam index 9dbed5dfa2fe..6691ba95f84c 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_block.beam and b/bootstrap/lib/compiler/ebin/beam_block.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_bounds.beam b/bootstrap/lib/compiler/ebin/beam_bounds.beam new file mode 100644 index 000000000000..8fa383080ab0 Binary files /dev/null and b/bootstrap/lib/compiler/ebin/beam_bounds.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_call_types.beam b/bootstrap/lib/compiler/ebin/beam_call_types.beam index 730610a94e70..a4caccf63232 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_call_types.beam and b/bootstrap/lib/compiler/ebin/beam_call_types.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam index 7fad16c7d312..b15e63e20681 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_clean.beam and b/bootstrap/lib/compiler/ebin/beam_clean.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam index 0b2a04a58b50..edfd03f4abb1 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_dict.beam and b/bootstrap/lib/compiler/ebin/beam_dict.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_digraph.beam b/bootstrap/lib/compiler/ebin/beam_digraph.beam index 7809d5868bfb..058880034d61 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_digraph.beam and b/bootstrap/lib/compiler/ebin/beam_digraph.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam index ddb3efd44e20..1c487eb6f2d5 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_disasm.beam and b/bootstrap/lib/compiler/ebin/beam_disasm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam index bb4aad66ddfc..cc6740a0ea39 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_flatten.beam and b/bootstrap/lib/compiler/ebin/beam_flatten.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam index ea808d20bc28..558708951245 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_jump.beam and b/bootstrap/lib/compiler/ebin/beam_jump.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam index 25b14e58a3c6..aa94d58c9330 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam and b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_listing.beam b/bootstrap/lib/compiler/ebin/beam_listing.beam index fde816c1102c..b2c3a859b027 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_listing.beam and b/bootstrap/lib/compiler/ebin/beam_listing.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_opcodes.beam b/bootstrap/lib/compiler/ebin/beam_opcodes.beam index 191fe66d7771..3479f1b6f9b1 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_opcodes.beam and b/bootstrap/lib/compiler/ebin/beam_opcodes.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam deleted file mode 100644 index 8f3d8962b863..000000000000 Binary files a/bootstrap/lib/compiler/ebin/beam_peep.beam and /dev/null differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa.beam b/bootstrap/lib/compiler/ebin/beam_ssa.beam index b5ae0c8e0d4a..2f54c0bd364a 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa.beam and b/bootstrap/lib/compiler/ebin/beam_ssa.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_alias.beam b/bootstrap/lib/compiler/ebin/beam_ssa_alias.beam new file mode 100644 index 000000000000..e2587a4d63bb Binary files /dev/null and b/bootstrap/lib/compiler/ebin/beam_ssa_alias.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bc_size.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bc_size.beam index 9b91bd9bdcfa..bd51e1ee7995 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_bc_size.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_bc_size.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bool.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bool.beam index aabaf0b44dfa..0f5814d1eb13 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_bool.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_bool.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam index 0b00d981f041..248c6936a496 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_check.beam b/bootstrap/lib/compiler/ebin/beam_ssa_check.beam new file mode 100644 index 000000000000..d6427f8e25d8 Binary files /dev/null and b/bootstrap/lib/compiler/ebin/beam_ssa_check.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam index f3f6a2483d69..b547cb6b2bdc 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam index 73a845193a8b..9f66da455f0d 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam b/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam deleted file mode 100644 index e442edfec889..000000000000 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam and /dev/null differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam b/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam index 0ff61632c968..1fbd08ded684 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam index cbbe63ae3163..3a8cdbc27385 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam index 0da9e9d8a68f..bd09f8bd51e3 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam index d75c4c55fc01..01fe7c4764c8 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_private_append.beam b/bootstrap/lib/compiler/ebin/beam_ssa_private_append.beam new file mode 100644 index 000000000000..75ef4f5768e1 Binary files /dev/null and b/bootstrap/lib/compiler/ebin/beam_ssa_private_append.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam index 0151a2e706c3..23459e448de7 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_share.beam b/bootstrap/lib/compiler/ebin/beam_ssa_share.beam index 4aa843a830ce..793d26d3661f 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_share.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_share.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_throw.beam b/bootstrap/lib/compiler/ebin/beam_ssa_throw.beam index e794cb482f2a..1cc337d72f1d 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_throw.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_throw.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam index 697f8f6f2323..6dbf33bf6131 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam and b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam index 5d6d1241326f..6adca21ec07d 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_trim.beam and b/bootstrap/lib/compiler/ebin/beam_trim.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_types.beam b/bootstrap/lib/compiler/ebin/beam_types.beam index 00653a158892..22c0302f9328 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_types.beam and b/bootstrap/lib/compiler/ebin/beam_types.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam index 3c7d3aa3b543..76edd9e837fa 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_utils.beam and b/bootstrap/lib/compiler/ebin/beam_utils.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam index ffb43389a5a0..5c4d9d1e3b36 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_validator.beam and b/bootstrap/lib/compiler/ebin/beam_validator.beam differ diff --git a/bootstrap/lib/compiler/ebin/beam_z.beam b/bootstrap/lib/compiler/ebin/beam_z.beam index d8c4a6f64847..2350b5e3c041 100644 Binary files a/bootstrap/lib/compiler/ebin/beam_z.beam and b/bootstrap/lib/compiler/ebin/beam_z.beam differ diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam index 6415ba73a5d4..77b61d860dd9 100644 Binary files a/bootstrap/lib/compiler/ebin/cerl.beam and b/bootstrap/lib/compiler/ebin/cerl.beam differ diff --git a/bootstrap/lib/compiler/ebin/cerl_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam index 8f5d43d1a69c..652897a0f163 100644 Binary files a/bootstrap/lib/compiler/ebin/cerl_clauses.beam and b/bootstrap/lib/compiler/ebin/cerl_clauses.beam differ diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam index 0d6904e4fda8..b56d907bf848 100644 Binary files a/bootstrap/lib/compiler/ebin/cerl_inline.beam and b/bootstrap/lib/compiler/ebin/cerl_inline.beam differ diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam index 03428f4bfb87..e25e3c7e8112 100644 Binary files a/bootstrap/lib/compiler/ebin/cerl_trees.beam and b/bootstrap/lib/compiler/ebin/cerl_trees.beam differ diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam index 279f5e194cb3..23fcc0a4f948 100644 Binary files a/bootstrap/lib/compiler/ebin/compile.beam and b/bootstrap/lib/compiler/ebin/compile.beam differ diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index 516f28d4f366..ea2723742d17 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -1,7 +1,7 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -19,10 +19,11 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "8.0.2"}, + {vsn, "8.2.2"}, {modules, [ beam_a, beam_asm, + beam_bounds, beam_block, beam_call_types, beam_clean, @@ -34,14 +35,12 @@ beam_kernel_to_ssa, beam_listing, beam_opcodes, - beam_peep, beam_ssa, beam_ssa_bc_size, beam_ssa_bool, beam_ssa_bsm, beam_ssa_codegen, beam_ssa_dead, - beam_ssa_funs, beam_ssa_lint, beam_ssa_opt, beam_ssa_pp, @@ -82,5 +81,5 @@ {registered, []}, {applications, [kernel, stdlib]}, {env, []}, - {runtime_dependencies, ["stdlib-3.13","kernel-7.0","erts-11.0", - "crypto-3.6"]}]}. + {runtime_dependencies, ["stdlib-4.0","kernel-8.4","erts-13.0", + "crypto-5.1"]}]}. diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup index 3d4fe9c021ea..2585c4a26de3 100644 --- a/bootstrap/lib/compiler/ebin/compiler.appup +++ b/bootstrap/lib/compiler/ebin/compiler.appup @@ -16,7 +16,7 @@ %% limitations under the License. %% %% %CopyrightEnd% -{"7.3.2", +{"8.2", [{<<".*">>,[{restart_application, compiler}]}], [{<<".*">>,[{restart_application, compiler}]}] }. diff --git a/bootstrap/lib/compiler/ebin/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam index e28cc846abfc..aff4a9d52302 100644 Binary files a/bootstrap/lib/compiler/ebin/core_lib.beam and b/bootstrap/lib/compiler/ebin/core_lib.beam differ diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam index 5ee46bdf471c..2237a901c83b 100644 Binary files a/bootstrap/lib/compiler/ebin/core_lint.beam and b/bootstrap/lib/compiler/ebin/core_lint.beam differ diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam index 4991cc4fd238..c46d70f2b2ed 100644 Binary files a/bootstrap/lib/compiler/ebin/core_parse.beam and b/bootstrap/lib/compiler/ebin/core_parse.beam differ diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam index 257ea98f4798..44236ea7432c 100644 Binary files a/bootstrap/lib/compiler/ebin/core_pp.beam and b/bootstrap/lib/compiler/ebin/core_pp.beam differ diff --git a/bootstrap/lib/compiler/ebin/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam index d02ac0d5534a..d49ba4c3f4d3 100644 Binary files a/bootstrap/lib/compiler/ebin/core_scan.beam and b/bootstrap/lib/compiler/ebin/core_scan.beam differ diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam index 17c4e1c11914..ab5659364f6b 100644 Binary files a/bootstrap/lib/compiler/ebin/erl_bifs.beam and b/bootstrap/lib/compiler/ebin/erl_bifs.beam differ diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam index befc45475689..32f463d79399 100644 Binary files a/bootstrap/lib/compiler/ebin/rec_env.beam and b/bootstrap/lib/compiler/ebin/rec_env.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_alias.beam b/bootstrap/lib/compiler/ebin/sys_core_alias.beam index 4903bdf4600e..999a21c5ac96 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_alias.beam and b/bootstrap/lib/compiler/ebin/sys_core_alias.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam index 020875572354..eda81d8e8967 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam and b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam index 422c67327a11..84f3c133ad33 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_fold.beam and b/bootstrap/lib/compiler/ebin/sys_core_fold.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam index 93d66ba30612..de0700d5ec68 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam and b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam index 020b5e1782fd..9311b2b0806e 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_inline.beam and b/bootstrap/lib/compiler/ebin/sys_core_inline.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_core_prepare.beam b/bootstrap/lib/compiler/ebin/sys_core_prepare.beam index a56dc0d6eed8..d297271752d9 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_core_prepare.beam and b/bootstrap/lib/compiler/ebin/sys_core_prepare.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_messages.beam b/bootstrap/lib/compiler/ebin/sys_messages.beam index a73a6e16abe4..0e0188251057 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_messages.beam and b/bootstrap/lib/compiler/ebin/sys_messages.beam differ diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam index c34e530cca1e..d2889c2e7d04 100644 Binary files a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam and b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam differ diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam index c0910c148299..a195de407e6e 100644 Binary files a/bootstrap/lib/compiler/ebin/v3_core.beam and b/bootstrap/lib/compiler/ebin/v3_core.beam differ diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam index 5d5034d5740b..7ef4a5371538 100644 Binary files a/bootstrap/lib/compiler/ebin/v3_kernel.beam and b/bootstrap/lib/compiler/ebin/v3_kernel.beam differ diff --git a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam index ffecc0c65cd2..c651e3f1105d 100644 Binary files a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam and b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam differ diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam index c483be1bfc12..0c3060a15586 100644 Binary files a/bootstrap/lib/kernel/ebin/application.beam and b/bootstrap/lib/kernel/ebin/application.beam differ diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam index c91dc12b66da..d98f199dbbed 100644 Binary files a/bootstrap/lib/kernel/ebin/application_controller.beam and b/bootstrap/lib/kernel/ebin/application_controller.beam differ diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam index b33ffefe5a11..925cef0803be 100644 Binary files a/bootstrap/lib/kernel/ebin/application_master.beam and b/bootstrap/lib/kernel/ebin/application_master.beam differ diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam index 76389d5a52ad..6a039bd8efaa 100644 Binary files a/bootstrap/lib/kernel/ebin/application_starter.beam and b/bootstrap/lib/kernel/ebin/application_starter.beam differ diff --git a/bootstrap/lib/kernel/ebin/auth.beam b/bootstrap/lib/kernel/ebin/auth.beam index 536caf55fd1f..4b92dd5f894a 100644 Binary files a/bootstrap/lib/kernel/ebin/auth.beam and b/bootstrap/lib/kernel/ebin/auth.beam differ diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam index 424cd890285a..b084b941e5ff 100644 Binary files a/bootstrap/lib/kernel/ebin/code.beam and b/bootstrap/lib/kernel/ebin/code.beam differ diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam index d9f205f7d7f1..d064f03cfd54 100644 Binary files a/bootstrap/lib/kernel/ebin/code_server.beam and b/bootstrap/lib/kernel/ebin/code_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam index 5c135ebed84f..e957296a421d 100644 Binary files a/bootstrap/lib/kernel/ebin/disk_log.beam and b/bootstrap/lib/kernel/ebin/disk_log.beam differ diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam index 80f8427f8dbc..bc729535f4c3 100644 Binary files a/bootstrap/lib/kernel/ebin/disk_log_1.beam and b/bootstrap/lib/kernel/ebin/disk_log_1.beam differ diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam index be0fa31c6882..78a599375158 100644 Binary files a/bootstrap/lib/kernel/ebin/disk_log_server.beam and b/bootstrap/lib/kernel/ebin/disk_log_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/disk_log_sup.beam b/bootstrap/lib/kernel/ebin/disk_log_sup.beam index 35077bcef7d3..b76cae08a7c4 100644 Binary files a/bootstrap/lib/kernel/ebin/disk_log_sup.beam and b/bootstrap/lib/kernel/ebin/disk_log_sup.beam differ diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam index 7ad634716ea9..a1c60611a93a 100644 Binary files a/bootstrap/lib/kernel/ebin/dist_ac.beam and b/bootstrap/lib/kernel/ebin/dist_ac.beam differ diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam index 99af0b6a9841..625e480c1d9e 100644 Binary files a/bootstrap/lib/kernel/ebin/dist_util.beam and b/bootstrap/lib/kernel/ebin/dist_util.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam index dae1ab427cc7..531154711825 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_boot_server.beam and b/bootstrap/lib/kernel/ebin/erl_boot_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_compile_server.beam b/bootstrap/lib/kernel/ebin/erl_compile_server.beam index d1d6bd6db342..7b62a57d8606 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_compile_server.beam and b/bootstrap/lib/kernel/ebin/erl_compile_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam index 7ae8ab499e5a..c005b736b45c 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_ddll.beam and b/bootstrap/lib/kernel/ebin/erl_ddll.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_distribution.beam b/bootstrap/lib/kernel/ebin/erl_distribution.beam index 5d7f85ebef2f..ccb9392d59ea 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_distribution.beam and b/bootstrap/lib/kernel/ebin/erl_distribution.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam index 0dcf03570d48..7f6e5e6c87d0 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_epmd.beam and b/bootstrap/lib/kernel/ebin/erl_epmd.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_erts_errors.beam b/bootstrap/lib/kernel/ebin/erl_erts_errors.beam index e288e70af6a7..a64d3a8da521 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_erts_errors.beam and b/bootstrap/lib/kernel/ebin/erl_erts_errors.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_kernel_errors.beam b/bootstrap/lib/kernel/ebin/erl_kernel_errors.beam index aa9833407202..3e58b02f2a97 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_kernel_errors.beam and b/bootstrap/lib/kernel/ebin/erl_kernel_errors.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_reply.beam b/bootstrap/lib/kernel/ebin/erl_reply.beam index 36d7d54dfc63..2ae87db895c9 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_reply.beam and b/bootstrap/lib/kernel/ebin/erl_reply.beam differ diff --git a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam index d73fde89f280..580524d38683 100644 Binary files a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam and b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam differ diff --git a/bootstrap/lib/kernel/ebin/erpc.beam b/bootstrap/lib/kernel/ebin/erpc.beam index 81048671a473..728b1586ba2e 100644 Binary files a/bootstrap/lib/kernel/ebin/erpc.beam and b/bootstrap/lib/kernel/ebin/erpc.beam differ diff --git a/bootstrap/lib/kernel/ebin/error_handler.beam b/bootstrap/lib/kernel/ebin/error_handler.beam index 9d9adb5821b3..7c4bfbb86e7e 100644 Binary files a/bootstrap/lib/kernel/ebin/error_handler.beam and b/bootstrap/lib/kernel/ebin/error_handler.beam differ diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam index 0ffc0cbd33d5..585416223ad9 100644 Binary files a/bootstrap/lib/kernel/ebin/error_logger.beam and b/bootstrap/lib/kernel/ebin/error_logger.beam differ diff --git a/bootstrap/lib/kernel/ebin/erts_debug.beam b/bootstrap/lib/kernel/ebin/erts_debug.beam index b664ba005cdb..560ba7b86517 100644 Binary files a/bootstrap/lib/kernel/ebin/erts_debug.beam and b/bootstrap/lib/kernel/ebin/erts_debug.beam differ diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam index 9e2ccc43843c..0fa22193897d 100644 Binary files a/bootstrap/lib/kernel/ebin/file.beam and b/bootstrap/lib/kernel/ebin/file.beam differ diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam index 62e072baa7d9..ee3974e592ec 100644 Binary files a/bootstrap/lib/kernel/ebin/file_io_server.beam and b/bootstrap/lib/kernel/ebin/file_io_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam index bba2f326cb02..ff9f619b4d7b 100644 Binary files a/bootstrap/lib/kernel/ebin/file_server.beam and b/bootstrap/lib/kernel/ebin/file_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/gen_sctp.beam b/bootstrap/lib/kernel/ebin/gen_sctp.beam index 66396860ffab..a2c440964bb8 100644 Binary files a/bootstrap/lib/kernel/ebin/gen_sctp.beam and b/bootstrap/lib/kernel/ebin/gen_sctp.beam differ diff --git a/bootstrap/lib/kernel/ebin/gen_tcp.beam b/bootstrap/lib/kernel/ebin/gen_tcp.beam index d75a5929e783..0dcc48e96a51 100644 Binary files a/bootstrap/lib/kernel/ebin/gen_tcp.beam and b/bootstrap/lib/kernel/ebin/gen_tcp.beam differ diff --git a/bootstrap/lib/kernel/ebin/gen_tcp_socket.beam b/bootstrap/lib/kernel/ebin/gen_tcp_socket.beam index 81a746890043..08cc5a37de57 100644 Binary files a/bootstrap/lib/kernel/ebin/gen_tcp_socket.beam and b/bootstrap/lib/kernel/ebin/gen_tcp_socket.beam differ diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam index 7cdaa38fd10a..f80ac0112381 100644 Binary files a/bootstrap/lib/kernel/ebin/gen_udp.beam and b/bootstrap/lib/kernel/ebin/gen_udp.beam differ diff --git a/bootstrap/lib/kernel/ebin/gen_udp_socket.beam b/bootstrap/lib/kernel/ebin/gen_udp_socket.beam index 3ce50542859c..26a60ca6491a 100644 Binary files a/bootstrap/lib/kernel/ebin/gen_udp_socket.beam and b/bootstrap/lib/kernel/ebin/gen_udp_socket.beam differ diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam index 845fb5a468fa..03e7352c7213 100644 Binary files a/bootstrap/lib/kernel/ebin/global.beam and b/bootstrap/lib/kernel/ebin/global.beam differ diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam index 6d000d094b36..35edebf29a83 100644 Binary files a/bootstrap/lib/kernel/ebin/global_group.beam and b/bootstrap/lib/kernel/ebin/global_group.beam differ diff --git a/bootstrap/lib/kernel/ebin/global_search.beam b/bootstrap/lib/kernel/ebin/global_search.beam index b17d493d956a..db26f907db07 100644 Binary files a/bootstrap/lib/kernel/ebin/global_search.beam and b/bootstrap/lib/kernel/ebin/global_search.beam differ diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam index bd8ad6948e94..c198c0676284 100644 Binary files a/bootstrap/lib/kernel/ebin/group.beam and b/bootstrap/lib/kernel/ebin/group.beam differ diff --git a/bootstrap/lib/kernel/ebin/group_history.beam b/bootstrap/lib/kernel/ebin/group_history.beam index f95b1229ee90..480c0ac288ed 100644 Binary files a/bootstrap/lib/kernel/ebin/group_history.beam and b/bootstrap/lib/kernel/ebin/group_history.beam differ diff --git a/bootstrap/lib/kernel/ebin/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam index 487209598b8d..6ee70ebb118c 100644 Binary files a/bootstrap/lib/kernel/ebin/heart.beam and b/bootstrap/lib/kernel/ebin/heart.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam index c114a8912b53..9f1bfdee7b49 100644 Binary files a/bootstrap/lib/kernel/ebin/inet.beam and b/bootstrap/lib/kernel/ebin/inet.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet6_sctp.beam b/bootstrap/lib/kernel/ebin/inet6_sctp.beam index 936fcc48baa0..ef759ce7e1c0 100644 Binary files a/bootstrap/lib/kernel/ebin/inet6_sctp.beam and b/bootstrap/lib/kernel/ebin/inet6_sctp.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam index 8b10ad0dca32..7e5d64136566 100644 Binary files a/bootstrap/lib/kernel/ebin/inet6_tcp.beam and b/bootstrap/lib/kernel/ebin/inet6_tcp.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam index 76afbf35a5f2..5f9df1a4d373 100644 Binary files a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam and b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam index 1e4d69b59db5..20ec8ff7f250 100644 Binary files a/bootstrap/lib/kernel/ebin/inet6_udp.beam and b/bootstrap/lib/kernel/ebin/inet6_udp.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam index f36e6c5592dd..3e306ebddbe4 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_config.beam and b/bootstrap/lib/kernel/ebin/inet_config.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam index cddd91d3d06c..0aef4f4ac188 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_db.beam and b/bootstrap/lib/kernel/ebin/inet_db.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam index 9d7ef22eb9f7..4dc91fa511dd 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_dns.beam and b/bootstrap/lib/kernel/ebin/inet_dns.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_epmd_dist.beam b/bootstrap/lib/kernel/ebin/inet_epmd_dist.beam new file mode 100644 index 000000000000..1c0e8711df6c Binary files /dev/null and b/bootstrap/lib/kernel/ebin/inet_epmd_dist.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_epmd_socket.beam b/bootstrap/lib/kernel/ebin/inet_epmd_socket.beam new file mode 100644 index 000000000000..c0605befc040 Binary files /dev/null and b/bootstrap/lib/kernel/ebin/inet_epmd_socket.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam index 4103e7df1736..fb5256782bc2 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam and b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_hosts.beam b/bootstrap/lib/kernel/ebin/inet_hosts.beam index d79726f6b90f..1ed316993fe6 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_hosts.beam and b/bootstrap/lib/kernel/ebin/inet_hosts.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam index e55e747bc737..3ce3943b7315 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_parse.beam and b/bootstrap/lib/kernel/ebin/inet_parse.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam index 19e502bb83d0..50e34ddde9e3 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_res.beam and b/bootstrap/lib/kernel/ebin/inet_res.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_sctp.beam b/bootstrap/lib/kernel/ebin/inet_sctp.beam index 4c72f7820c88..2e7cd85a00ec 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_sctp.beam and b/bootstrap/lib/kernel/ebin/inet_sctp.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam index e3990c9f71e6..22e43499dd57 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_tcp.beam and b/bootstrap/lib/kernel/ebin/inet_tcp.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam index 30d1eedbc373..38e0f946879c 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam and b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam differ diff --git a/bootstrap/lib/kernel/ebin/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam index f16a67b59f78..866a601a7a07 100644 Binary files a/bootstrap/lib/kernel/ebin/inet_udp.beam and b/bootstrap/lib/kernel/ebin/inet_udp.beam differ diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index 8621630ad589..ce100930fb0f 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -22,7 +22,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "8.0.2"}, + {vsn, "8.5.2"}, {modules, [application, application_controller, application_master, @@ -83,9 +83,9 @@ os, ram_file, rpc, - user, user_drv, user_sup, + prim_tty, disk_log, disk_log_1, disk_log_server, @@ -152,9 +152,13 @@ {applications, []}, {env, [{logger_level, notice}, {logger_sasl_compatible, false}, + {net_tickintensity, 4}, + {net_ticktime, 60}, + {prevent_overlapping_partitions, true}, {shell_docs_ansi,auto} ]}, {mod, {kernel, []}}, - {runtime_dependencies, ["erts-12.0", "stdlib-3.13", "sasl-3.0", "crypto-5.0"]} - ] + {runtime_dependencies, ["erts-@OTP-18248@", "stdlib-@OTP-17932@", + "sasl-3.0", "crypto-5.0"]} + ] }. diff --git a/bootstrap/lib/kernel/ebin/kernel.appup b/bootstrap/lib/kernel/ebin/kernel.appup index 5f6d9d398820..ccd0f7becd0e 100644 --- a/bootstrap/lib/kernel/ebin/kernel.appup +++ b/bootstrap/lib/kernel/ebin/kernel.appup @@ -1,7 +1,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2017. All Rights Reserved. +%% Copyright Ericsson AB 1999-2021. 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. @@ -19,49 +19,66 @@ %% %% We allow upgrade from, and downgrade to all previous %% versions from the following OTP releases: -%% - OTP 20 -%% - OTP 21 +%% - OTP 23 +%% - OTP 24 +%% - OTP 25 %% %% We also allow upgrade from, and downgrade to all %% versions that have branched off from the above %% stated previous versions. %% -{"6.3.1", - [{<<"^5\\.3$">>,[restart_new_emulator]}, - {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.0$">>,[restart_new_emulator]}, - {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.1$">>,[restart_new_emulator]}, - {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.2$">>,[restart_new_emulator]}, - {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.3$">>,[restart_new_emulator]}, - {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], - [{<<"^5\\.3$">>,[restart_new_emulator]}, - {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.0$">>,[restart_new_emulator]}, - {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.1$">>,[restart_new_emulator]}, - {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.2$">>,[restart_new_emulator]}, - {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^6\\.3$">>,[restart_new_emulator]}, - {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. +{"8.4.1", + [{<<"^7\\.0$">>,[restart_new_emulator]}, + {<<"^7\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.1$">>,[restart_new_emulator]}, + {<<"^7\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.2$">>,[restart_new_emulator]}, + {<<"^7\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^7\\.3$">>,[restart_new_emulator]}, + {<<"^7\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.0$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.2$">>,[restart_new_emulator]}, + {<<"^8\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.3$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.4$">>,[restart_new_emulator]}, + {<<"^8\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], + [{<<"^7\\.0$">>,[restart_new_emulator]}, + {<<"^7\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.1$">>,[restart_new_emulator]}, + {<<"^7\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.2$">>,[restart_new_emulator]}, + {<<"^7\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^7\\.3$">>,[restart_new_emulator]}, + {<<"^7\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^7\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.0$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.1\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.2$">>,[restart_new_emulator]}, + {<<"^8\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.3$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.3\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^8\\.4$">>,[restart_new_emulator]}, + {<<"^8\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam index d217f6fcc448..5438c8852964 100644 Binary files a/bootstrap/lib/kernel/ebin/kernel.beam and b/bootstrap/lib/kernel/ebin/kernel.beam differ diff --git a/bootstrap/lib/kernel/ebin/kernel_config.beam b/bootstrap/lib/kernel/ebin/kernel_config.beam index 7850013863fb..5724297c64c9 100644 Binary files a/bootstrap/lib/kernel/ebin/kernel_config.beam and b/bootstrap/lib/kernel/ebin/kernel_config.beam differ diff --git a/bootstrap/lib/kernel/ebin/kernel_refc.beam b/bootstrap/lib/kernel/ebin/kernel_refc.beam index 31746a1ef8d6..621ad37e8a71 100644 Binary files a/bootstrap/lib/kernel/ebin/kernel_refc.beam and b/bootstrap/lib/kernel/ebin/kernel_refc.beam differ diff --git a/bootstrap/lib/kernel/ebin/local_tcp.beam b/bootstrap/lib/kernel/ebin/local_tcp.beam index 1bd2d4186a78..0903b8b65533 100644 Binary files a/bootstrap/lib/kernel/ebin/local_tcp.beam and b/bootstrap/lib/kernel/ebin/local_tcp.beam differ diff --git a/bootstrap/lib/kernel/ebin/local_udp.beam b/bootstrap/lib/kernel/ebin/local_udp.beam index 948787c506bf..4991233152fa 100644 Binary files a/bootstrap/lib/kernel/ebin/local_udp.beam and b/bootstrap/lib/kernel/ebin/local_udp.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam index 6c6bb11c400c..c08949167edf 100644 Binary files a/bootstrap/lib/kernel/ebin/logger.beam and b/bootstrap/lib/kernel/ebin/logger.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_backend.beam b/bootstrap/lib/kernel/ebin/logger_backend.beam index d414ca24edae..a68c16c3f0e5 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_backend.beam and b/bootstrap/lib/kernel/ebin/logger_backend.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_config.beam b/bootstrap/lib/kernel/ebin/logger_config.beam index afa44cdab143..426d806acc57 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_config.beam and b/bootstrap/lib/kernel/ebin/logger_config.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam index df2a359a784a..52064f9fb0a6 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam and b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_filters.beam b/bootstrap/lib/kernel/ebin/logger_filters.beam index 99cb32c42bab..5b49dc1edae6 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_filters.beam and b/bootstrap/lib/kernel/ebin/logger_filters.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam index 0874f8de46eb..6b1fba6321ca 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_formatter.beam and b/bootstrap/lib/kernel/ebin/logger_formatter.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam index 61aaf23b0ad8..d30f921a46ea 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_h_common.beam and b/bootstrap/lib/kernel/ebin/logger_h_common.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam index ad8bbdd5a79f..406cca06d2b4 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam and b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_olp.beam b/bootstrap/lib/kernel/ebin/logger_olp.beam index f5b3861acc88..360ec62c5461 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_olp.beam and b/bootstrap/lib/kernel/ebin/logger_olp.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_proxy.beam b/bootstrap/lib/kernel/ebin/logger_proxy.beam index b5bd6def770d..f7ca3b73a678 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_proxy.beam and b/bootstrap/lib/kernel/ebin/logger_proxy.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_server.beam b/bootstrap/lib/kernel/ebin/logger_server.beam index e92a88dd30da..239aa30b3979 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_server.beam and b/bootstrap/lib/kernel/ebin/logger_server.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam index f971063e0154..1bbd6b281aca 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_simple_h.beam and b/bootstrap/lib/kernel/ebin/logger_simple_h.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam index 34d19eb954c6..bcbc4379bab0 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_std_h.beam and b/bootstrap/lib/kernel/ebin/logger_std_h.beam differ diff --git a/bootstrap/lib/kernel/ebin/logger_sup.beam b/bootstrap/lib/kernel/ebin/logger_sup.beam index 907dcd93fe81..1acbd3ab7a23 100644 Binary files a/bootstrap/lib/kernel/ebin/logger_sup.beam and b/bootstrap/lib/kernel/ebin/logger_sup.beam differ diff --git a/bootstrap/lib/kernel/ebin/net.beam b/bootstrap/lib/kernel/ebin/net.beam index a294780780a6..59506ed92f72 100644 Binary files a/bootstrap/lib/kernel/ebin/net.beam and b/bootstrap/lib/kernel/ebin/net.beam differ diff --git a/bootstrap/lib/kernel/ebin/net_adm.beam b/bootstrap/lib/kernel/ebin/net_adm.beam index 49611f379322..34f41ae964c8 100644 Binary files a/bootstrap/lib/kernel/ebin/net_adm.beam and b/bootstrap/lib/kernel/ebin/net_adm.beam differ diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam index 65a54f22e9c5..6f94b9a79a73 100644 Binary files a/bootstrap/lib/kernel/ebin/net_kernel.beam and b/bootstrap/lib/kernel/ebin/net_kernel.beam differ diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam index a907f9f2c647..1fd878838742 100644 Binary files a/bootstrap/lib/kernel/ebin/os.beam and b/bootstrap/lib/kernel/ebin/os.beam differ diff --git a/bootstrap/lib/kernel/ebin/pg.beam b/bootstrap/lib/kernel/ebin/pg.beam index 2dd5265a2089..356e58617760 100644 Binary files a/bootstrap/lib/kernel/ebin/pg.beam and b/bootstrap/lib/kernel/ebin/pg.beam differ diff --git a/bootstrap/lib/kernel/ebin/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam index bdd7cae85758..a9533af680d7 100644 Binary files a/bootstrap/lib/kernel/ebin/pg2.beam and b/bootstrap/lib/kernel/ebin/pg2.beam differ diff --git a/bootstrap/lib/kernel/ebin/prim_tty.beam b/bootstrap/lib/kernel/ebin/prim_tty.beam new file mode 100644 index 000000000000..a6ca84b1de27 Binary files /dev/null and b/bootstrap/lib/kernel/ebin/prim_tty.beam differ diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam index d1c4df77a4d5..2ad1d08b9c5e 100644 Binary files a/bootstrap/lib/kernel/ebin/ram_file.beam and b/bootstrap/lib/kernel/ebin/ram_file.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io.beam b/bootstrap/lib/kernel/ebin/raw_file_io.beam index 62ee19cba81f..81956af0422f 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io.beam and b/bootstrap/lib/kernel/ebin/raw_file_io.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam index 66339ffa5ece..4233f22faae3 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam and b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam index 6deb5b7a66e3..8d4bb23f4dfb 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam and b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam index d83bbec42f89..42bcfe10c484 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam and b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam index 352f9059043b..8596ce8d17cd 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam and b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam differ diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam index e051c80ee917..bde7b1313f43 100644 Binary files a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam and b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam differ diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam index 353f3d81d60e..0e8be3860388 100644 Binary files a/bootstrap/lib/kernel/ebin/rpc.beam and b/bootstrap/lib/kernel/ebin/rpc.beam differ diff --git a/bootstrap/lib/kernel/ebin/seq_trace.beam b/bootstrap/lib/kernel/ebin/seq_trace.beam index 6090ce265988..cd3d5a3b133c 100644 Binary files a/bootstrap/lib/kernel/ebin/seq_trace.beam and b/bootstrap/lib/kernel/ebin/seq_trace.beam differ diff --git a/bootstrap/lib/kernel/ebin/socket.beam b/bootstrap/lib/kernel/ebin/socket.beam index 609fb30f6a29..4b1063641985 100644 Binary files a/bootstrap/lib/kernel/ebin/socket.beam and b/bootstrap/lib/kernel/ebin/socket.beam differ diff --git a/bootstrap/lib/kernel/ebin/standard_error.beam b/bootstrap/lib/kernel/ebin/standard_error.beam index e42d15babcff..6a430b3c73d0 100644 Binary files a/bootstrap/lib/kernel/ebin/standard_error.beam and b/bootstrap/lib/kernel/ebin/standard_error.beam differ diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam deleted file mode 100644 index 2d28cec7d3f9..000000000000 Binary files a/bootstrap/lib/kernel/ebin/user.beam and /dev/null differ diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam index e3d59278756f..f2d93bf66090 100644 Binary files a/bootstrap/lib/kernel/ebin/user_drv.beam and b/bootstrap/lib/kernel/ebin/user_drv.beam differ diff --git a/bootstrap/lib/kernel/ebin/user_sup.beam b/bootstrap/lib/kernel/ebin/user_sup.beam index 3baabe7f8af2..1d4afba0dc37 100644 Binary files a/bootstrap/lib/kernel/ebin/user_sup.beam and b/bootstrap/lib/kernel/ebin/user_sup.beam differ diff --git a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam index 59dcb3bb4c0b..5d1290bdc480 100644 Binary files a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam and b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam differ diff --git a/bootstrap/lib/kernel/include/dist.hrl b/bootstrap/lib/kernel/include/dist.hrl index 10460ba3e840..4eef2bb3fc6e 100644 --- a/bootstrap/lib/kernel/include/dist.hrl +++ b/bootstrap/lib/kernel/include/dist.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -22,43 +22,98 @@ %% Distribution capabilities flags (corresponds with dist.h). %% --define(DFLAG_PUBLISHED,1). --define(DFLAG_ATOM_CACHE,2). --define(DFLAG_EXTENDED_REFERENCES,4). --define(DFLAG_DIST_MONITOR,8). --define(DFLAG_FUN_TAGS,16#10). --define(DFLAG_DIST_MONITOR_NAME,16#20). --define(DFLAG_HIDDEN_ATOM_CACHE,16#40). --define(DFLAG_NEW_FUN_TAGS,16#80). --define(DFLAG_EXTENDED_PIDS_PORTS,16#100). --define(DFLAG_EXPORT_PTR_TAG,16#200). --define(DFLAG_BIT_BINARIES,16#400). --define(DFLAG_NEW_FLOATS,16#800). --define(DFLAG_UNICODE_IO,16#1000). --define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000). --define(DFLAG_SMALL_ATOM_TAGS, 16#4000). --define(DFLAG_UTF8_ATOMS, 16#10000). --define(DFLAG_MAP_TAG, 16#20000). --define(DFLAG_BIG_CREATION, 16#40000). --define(DFLAG_SEND_SENDER, 16#80000). --define(DFLAG_BIG_SEQTRACE_LABELS, 16#100000). -%% -define(DFLAG_NO_MAGIC, 16#200000). %% Used internally only --define(DFLAG_EXIT_PAYLOAD, 16#400000). --define(DFLAG_FRAGMENTS, 16#00800000). --define(DFLAG_HANDSHAKE_23, 16#01000000). --define(DFLAG_RESERVED, 16#fe000000). --define(DFLAG_SPAWN, 16#100000000). --define(DFLAG_NAME_ME, 16#200000000). --define(DFLAG_V4_NC, 16#400000000). --define(DFLAG_ALIAS, 16#800000000). +-define(DFLAG_PUBLISHED, 16#01). +-define(DFLAG_ATOM_CACHE, 16#02). +-define(DFLAG_EXTENDED_REFERENCES, 16#04). +-define(DFLAG_DIST_MONITOR, 16#08). +-define(DFLAG_FUN_TAGS, 16#10). +-define(DFLAG_DIST_MONITOR_NAME, 16#20). +-define(DFLAG_HIDDEN_ATOM_CACHE, 16#40). +-define(DFLAG_NEW_FUN_TAGS, 16#80). +-define(DFLAG_EXTENDED_PIDS_PORTS, 16#100). +-define(DFLAG_EXPORT_PTR_TAG, 16#200). +-define(DFLAG_BIT_BINARIES, 16#400). +-define(DFLAG_NEW_FLOATS, 16#800). +-define(DFLAG_UNICODE_IO, 16#1000). +-define(DFLAG_DIST_HDR_ATOM_CACHE, 16#2000). +-define(DFLAG_SMALL_ATOM_TAGS, 16#4000). +-define(DFLAG_UTF8_ATOMS, 16#10000). +-define(DFLAG_MAP_TAG, 16#20000). +-define(DFLAG_BIG_CREATION, 16#40000). +-define(DFLAG_SEND_SENDER, 16#80000). +-define(DFLAG_BIG_SEQTRACE_LABELS, 16#100000). +%% -define(DFLAG_NO_MAGIC, 16#200000). %% Used internally only +-define(DFLAG_EXIT_PAYLOAD, 16#400000). +-define(DFLAG_FRAGMENTS, 16#00800000). +-define(DFLAG_HANDSHAKE_23, 16#01000000). +-define(DFLAG_UNLINK_ID, 16#02000000). +-define(DFLAG_MANDATORY_25_DIGEST, 16#04000000). +-define(DFLAG_RESERVED, 16#f8000000). + +%% Second 32-bit flag word. +-define(DFLAG_SPAWN, (16#01 bsl 32)). +-define(DFLAG_NAME_ME, (16#02 bsl 32)). +-define(DFLAG_V4_NC, (16#04 bsl 32)). +-define(DFLAG_ALIAS, (16#08 bsl 32)). + +%% The following flags are mandatory in OTP 25. OTP 25 and higher +%% will accept ?DFLAG_MANDATORY_25_DIGEST as a shorthand for all those +%% flags. +-define(MANDATORY_DFLAGS_25, + (?DFLAG_EXTENDED_REFERENCES bor + ?DFLAG_FUN_TAGS bor + ?DFLAG_EXTENDED_PIDS_PORTS bor + ?DFLAG_NEW_FUN_TAGS bor + ?DFLAG_EXPORT_PTR_TAG bor + ?DFLAG_BIT_BINARIES bor + ?DFLAG_NEW_FLOATS bor + ?DFLAG_UTF8_ATOMS bor + ?DFLAG_MAP_TAG bor + ?DFLAG_BIG_CREATION bor + ?DFLAG_HANDSHAKE_23)). + +%% New mandatory flags in OTP 26 +-define(MANDATORY_DFLAGS_26, (?DFLAG_V4_NC bor + ?DFLAG_UNLINK_ID)). + +%% All mandatory flags +-define(DFLAGS_MANDATORY, (?MANDATORY_DFLAGS_25 bor + ?MANDATORY_DFLAGS_26)). %% Also update dflag2str() in ../src/dist_util.erl %% when adding flags... +-define(ERL_DIST_VER_6, 6). % OTP-23 at least --define(ERL_DIST_VER_5, 5). % OTP-22 or (much) older --define(ERL_DIST_VER_6, 6). % OTP-23 (or maybe newer?) - --define(ERL_DIST_VER_LOW, ?ERL_DIST_VER_5). +-define(ERL_DIST_VER_LOW, ?ERL_DIST_VER_6). -define(ERL_DIST_VER_HIGH, ?ERL_DIST_VER_6). +%%% +%%% To avoid having to extend the number of distribution flags from 64 +%%% to 128, a scheme for garbage collection of the flags was +%%% introduced in OTP 25. +%%% +%%% In OTP 25, ?DFLAG_MANDATORY_25_DIGEST was introduced as a synonym +%%% for the flags defined by ?MANDATORY_DFLAGS_25. OTP 25/26 will +%%% accept the old flags to support communication with 24 and earlier, +%%% as well as ?DFLAG_MANDATORY_25_DIGEST. +%%% +%%% OTP 27 will make ?DFLAG_MANDATORY_25_DIGEST mandatory, meaning that an +%%% OTP 27 node can only communicate with OTP 25 and higher. +%%% +%%% An OTP 27 node will also introduce the new flag +%%% ?DFLAG_MANDATORY_27_DIGEST: +%%% +%%% * If ?DFLAG_MANDATORY_27_DIGEST is set, it means that all bit +%%% numbers defined by ?MANDATORY_DFLAGS_25, as well as the bit +%%% number defined by ?DFLAG_MANDATORY_25_DIGEST and any other bits +%%% made mandatory in OTP 26/27, lose their previous meanings. New +%%% meanings can then be assigned to those bit numbers as +%%% needed. (This is for communication between nodes from OTP 27 and +%%% up.) +%%% +%%% * If ?DFLAG_MANDATORY_27_DIGEST is not set, then +%%% ?DFLAG_MANDATORY_25_DIGEST must be set and all bit numbers +%%% defined by ?MANDATORY_DFLAGS_25 are ignored. (This is for +%%% communication between an OTP 27 node and an OTP 25/26 node.) +%%% diff --git a/bootstrap/lib/kernel/include/inet_sctp.hrl b/bootstrap/lib/kernel/include/inet_sctp.hrl index ddb3cdc26c02..11b06fd8e668 100644 --- a/bootstrap/lib/kernel/include/inet_sctp.hrl +++ b/bootstrap/lib/kernel/include/inet_sctp.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2016. All Rights Reserved. +%% Copyright Ericsson AB 2007-2022. 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. @@ -120,7 +120,7 @@ }). %% sctp_partial_delivery_event: XXX: Not clear whether it is delivered to -%% the Sender or to the Recepient (probably the +%% the Sender or to the Recipient (probably the %% former). Currently, there is only 1 possible %% value for "indication": -record(sctp_pdapi_event, diff --git a/bootstrap/lib/stdlib/ebin/argparse.beam b/bootstrap/lib/stdlib/ebin/argparse.beam new file mode 100644 index 000000000000..a18a79ba311e Binary files /dev/null and b/bootstrap/lib/stdlib/ebin/argparse.beam differ diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam index e837453f20fb..b1eafbbac344 100644 Binary files a/bootstrap/lib/stdlib/ebin/array.beam and b/bootstrap/lib/stdlib/ebin/array.beam differ diff --git a/bootstrap/lib/stdlib/ebin/base64.beam b/bootstrap/lib/stdlib/ebin/base64.beam index 634e301aa2e8..739abd7f1a0b 100644 Binary files a/bootstrap/lib/stdlib/ebin/base64.beam and b/bootstrap/lib/stdlib/ebin/base64.beam differ diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam index ed700d6ba8e7..11988a53062b 100644 Binary files a/bootstrap/lib/stdlib/ebin/beam_lib.beam and b/bootstrap/lib/stdlib/ebin/beam_lib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/binary.beam b/bootstrap/lib/stdlib/ebin/binary.beam index 7ec31e98b1ff..fddd1185aa2c 100644 Binary files a/bootstrap/lib/stdlib/ebin/binary.beam and b/bootstrap/lib/stdlib/ebin/binary.beam differ diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam index d90c1727fdee..b9bbddb64fa1 100644 Binary files a/bootstrap/lib/stdlib/ebin/c.beam and b/bootstrap/lib/stdlib/ebin/c.beam differ diff --git a/bootstrap/lib/stdlib/ebin/calendar.beam b/bootstrap/lib/stdlib/ebin/calendar.beam index 5915a4e686ec..6158eb9dc055 100644 Binary files a/bootstrap/lib/stdlib/ebin/calendar.beam and b/bootstrap/lib/stdlib/ebin/calendar.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam index 3e0f0f5b238c..336e92f1678e 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets.beam and b/bootstrap/lib/stdlib/ebin/dets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam index a00e8d91d9d1..964d15e65368 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets_server.beam and b/bootstrap/lib/stdlib/ebin/dets_server.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets_sup.beam b/bootstrap/lib/stdlib/ebin/dets_sup.beam index 575f88338aef..660f51eba42e 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets_sup.beam and b/bootstrap/lib/stdlib/ebin/dets_sup.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam index 8f93a0809f98..acb06a65b250 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets_utils.beam and b/bootstrap/lib/stdlib/ebin/dets_utils.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam index 8cf80d1a5cf9..5658793668b0 100644 Binary files a/bootstrap/lib/stdlib/ebin/dets_v9.beam and b/bootstrap/lib/stdlib/ebin/dets_v9.beam differ diff --git a/bootstrap/lib/stdlib/ebin/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam index a630f87dd002..c74b71395c5f 100644 Binary files a/bootstrap/lib/stdlib/ebin/dict.beam and b/bootstrap/lib/stdlib/ebin/dict.beam differ diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam index d458194421f2..8c1c9b229112 100644 Binary files a/bootstrap/lib/stdlib/ebin/digraph.beam and b/bootstrap/lib/stdlib/ebin/digraph.beam differ diff --git a/bootstrap/lib/stdlib/ebin/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam index 8c0f7ffff4a5..549a93d965e0 100644 Binary files a/bootstrap/lib/stdlib/ebin/digraph_utils.beam and b/bootstrap/lib/stdlib/ebin/digraph_utils.beam differ diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam index 4538f56b68b4..77eb241b7666 100644 Binary files a/bootstrap/lib/stdlib/ebin/edlin.beam and b/bootstrap/lib/stdlib/ebin/edlin.beam differ diff --git a/bootstrap/lib/stdlib/ebin/edlin_context.beam b/bootstrap/lib/stdlib/ebin/edlin_context.beam new file mode 100644 index 000000000000..f229f29fd2da Binary files /dev/null and b/bootstrap/lib/stdlib/ebin/edlin_context.beam differ diff --git a/bootstrap/lib/stdlib/ebin/edlin_expand.beam b/bootstrap/lib/stdlib/ebin/edlin_expand.beam index 82bd92df9266..bf7d093eed48 100644 Binary files a/bootstrap/lib/stdlib/ebin/edlin_expand.beam and b/bootstrap/lib/stdlib/ebin/edlin_expand.beam differ diff --git a/bootstrap/lib/stdlib/ebin/edlin_type_suggestion.beam b/bootstrap/lib/stdlib/ebin/edlin_type_suggestion.beam new file mode 100644 index 000000000000..dd4a8101a0d9 Binary files /dev/null and b/bootstrap/lib/stdlib/ebin/edlin_type_suggestion.beam differ diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam index 78cc9153c439..a5716e6a46c9 100644 Binary files a/bootstrap/lib/stdlib/ebin/epp.beam and b/bootstrap/lib/stdlib/ebin/epp.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam index 9a7662ac9420..a1741be5df4e 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam and b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_anno.beam b/bootstrap/lib/stdlib/ebin/erl_anno.beam index ad2d06a96fdf..fbd6517584e2 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_anno.beam and b/bootstrap/lib/stdlib/ebin/erl_anno.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam index 46397437fc46..ab7cfbd58436 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_bits.beam and b/bootstrap/lib/stdlib/ebin/erl_bits.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam index 17da56bdc818..aaf5c0b9d7b5 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_compile.beam and b/bootstrap/lib/stdlib/ebin/erl_compile.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_error.beam b/bootstrap/lib/stdlib/ebin/erl_error.beam index 3a0a7d111019..6d4e4aa9e95c 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_error.beam and b/bootstrap/lib/stdlib/ebin/erl_error.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam index 520a83388703..687077d2f19e 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_eval.beam and b/bootstrap/lib/stdlib/ebin/erl_eval.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam index d37758d1f055..800aafd15a55 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam and b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_features.beam b/bootstrap/lib/stdlib/ebin/erl_features.beam new file mode 100644 index 000000000000..bfe48d8ea501 Binary files /dev/null and b/bootstrap/lib/stdlib/ebin/erl_features.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam index bf480ea73bd7..0b6ac1a6d69a 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_internal.beam and b/bootstrap/lib/stdlib/ebin/erl_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam index 225ee318c2c0..e95d93f4e335 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_lint.beam and b/bootstrap/lib/stdlib/ebin/erl_lint.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam index c0fe981ad489..f0033eb64886 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_parse.beam and b/bootstrap/lib/stdlib/ebin/erl_parse.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam index cf5239d693e0..a5a5970d6a2a 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam and b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam index cf0edba32c9f..51867008bc83 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_pp.beam and b/bootstrap/lib/stdlib/ebin/erl_pp.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam index 0bde6b650216..ce8fca5463af 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_scan.beam and b/bootstrap/lib/stdlib/ebin/erl_scan.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_stdlib_errors.beam b/bootstrap/lib/stdlib/ebin/erl_stdlib_errors.beam index 58c370a6afdc..dbec403bb20e 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_stdlib_errors.beam and b/bootstrap/lib/stdlib/ebin/erl_stdlib_errors.beam differ diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam index be66732e821c..bc58a38e116d 100644 Binary files a/bootstrap/lib/stdlib/ebin/erl_tar.beam and b/bootstrap/lib/stdlib/ebin/erl_tar.beam differ diff --git a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam index 036c8d418c84..49a74b38f8a4 100644 Binary files a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam and b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam differ diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam index ce0d9a1d7251..dc153e80ba5f 100644 Binary files a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam and b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam differ diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam index 4c17b6ad2c44..09d8ade15dee 100644 Binary files a/bootstrap/lib/stdlib/ebin/escript.beam and b/bootstrap/lib/stdlib/ebin/escript.beam differ diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam index 7579a1f031ef..ce0a21640518 100644 Binary files a/bootstrap/lib/stdlib/ebin/ets.beam and b/bootstrap/lib/stdlib/ebin/ets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/eval_bits.beam b/bootstrap/lib/stdlib/ebin/eval_bits.beam index 28da62ef026a..ed90371d2777 100644 Binary files a/bootstrap/lib/stdlib/ebin/eval_bits.beam and b/bootstrap/lib/stdlib/ebin/eval_bits.beam differ diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam index ad98ee9aa3bc..2153273c8686 100644 Binary files a/bootstrap/lib/stdlib/ebin/file_sorter.beam and b/bootstrap/lib/stdlib/ebin/file_sorter.beam differ diff --git a/bootstrap/lib/stdlib/ebin/filelib.beam b/bootstrap/lib/stdlib/ebin/filelib.beam index 4124948a8d43..7c7c78657299 100644 Binary files a/bootstrap/lib/stdlib/ebin/filelib.beam and b/bootstrap/lib/stdlib/ebin/filelib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam index f6e8bc2610ba..5a8488525820 100644 Binary files a/bootstrap/lib/stdlib/ebin/filename.beam and b/bootstrap/lib/stdlib/ebin/filename.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam index bd84607fae84..8f0b0baf3770 100644 Binary files a/bootstrap/lib/stdlib/ebin/gb_sets.beam and b/bootstrap/lib/stdlib/ebin/gb_sets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam index 454ba0aa9f0a..8aa75b7d0be1 100644 Binary files a/bootstrap/lib/stdlib/ebin/gb_trees.beam and b/bootstrap/lib/stdlib/ebin/gb_trees.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam index a989fa0f8ab2..2b1db2c1f789 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen.beam and b/bootstrap/lib/stdlib/ebin/gen.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam index 2e178c76cf18..488cc3cda05a 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen_event.beam and b/bootstrap/lib/stdlib/ebin/gen_event.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam index 893084c55a04..cdabaa74f034 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen_fsm.beam and b/bootstrap/lib/stdlib/ebin/gen_fsm.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam index 65344338eb08..9a945d429798 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen_server.beam and b/bootstrap/lib/stdlib/ebin/gen_server.beam differ diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam index 14f6f1b4ca76..b94efa35b012 100644 Binary files a/bootstrap/lib/stdlib/ebin/gen_statem.beam and b/bootstrap/lib/stdlib/ebin/gen_statem.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam index a54a1e2865e8..497d7c6446cc 100644 Binary files a/bootstrap/lib/stdlib/ebin/io.beam and b/bootstrap/lib/stdlib/ebin/io.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam index 838e1764feeb..4b4412eed45e 100644 Binary files a/bootstrap/lib/stdlib/ebin/io_lib.beam and b/bootstrap/lib/stdlib/ebin/io_lib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam index 988d41cb8aa7..e7425b0712cd 100644 Binary files a/bootstrap/lib/stdlib/ebin/io_lib_format.beam and b/bootstrap/lib/stdlib/ebin/io_lib_format.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format_ryu_table.beam b/bootstrap/lib/stdlib/ebin/io_lib_format_ryu_table.beam deleted file mode 100644 index 7d95fef996c0..000000000000 Binary files a/bootstrap/lib/stdlib/ebin/io_lib_format_ryu_table.beam and /dev/null differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam index 2b29e395c50a..9c2357caf0a4 100644 Binary files a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam and b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam differ diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam index 1c0b4f98854e..7e1ae900b0df 100644 Binary files a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam and b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam differ diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam index 95cfff621103..067134d28f6c 100644 Binary files a/bootstrap/lib/stdlib/ebin/lists.beam and b/bootstrap/lib/stdlib/ebin/lists.beam differ diff --git a/bootstrap/lib/stdlib/ebin/log_mf_h.beam b/bootstrap/lib/stdlib/ebin/log_mf_h.beam index 30fc545d630d..57badfc8f064 100644 Binary files a/bootstrap/lib/stdlib/ebin/log_mf_h.beam and b/bootstrap/lib/stdlib/ebin/log_mf_h.beam differ diff --git a/bootstrap/lib/stdlib/ebin/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam index 2a273d6d8e93..3dbfa76f984b 100644 Binary files a/bootstrap/lib/stdlib/ebin/maps.beam and b/bootstrap/lib/stdlib/ebin/maps.beam differ diff --git a/bootstrap/lib/stdlib/ebin/math.beam b/bootstrap/lib/stdlib/ebin/math.beam index 7abbc9385b23..36d9d4b0688b 100644 Binary files a/bootstrap/lib/stdlib/ebin/math.beam and b/bootstrap/lib/stdlib/ebin/math.beam differ diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam index 917fc45f4055..a573237fe867 100644 Binary files a/bootstrap/lib/stdlib/ebin/ms_transform.beam and b/bootstrap/lib/stdlib/ebin/ms_transform.beam differ diff --git a/bootstrap/lib/stdlib/ebin/orddict.beam b/bootstrap/lib/stdlib/ebin/orddict.beam index 3d629804f76d..eae3adc34682 100644 Binary files a/bootstrap/lib/stdlib/ebin/orddict.beam and b/bootstrap/lib/stdlib/ebin/orddict.beam differ diff --git a/bootstrap/lib/stdlib/ebin/ordsets.beam b/bootstrap/lib/stdlib/ebin/ordsets.beam index 3e904d7e862a..c9eba0a35ab6 100644 Binary files a/bootstrap/lib/stdlib/ebin/ordsets.beam and b/bootstrap/lib/stdlib/ebin/ordsets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam index fd7795c36fcf..40096448288b 100644 Binary files a/bootstrap/lib/stdlib/ebin/otp_internal.beam and b/bootstrap/lib/stdlib/ebin/otp_internal.beam differ diff --git a/bootstrap/lib/stdlib/ebin/peer.beam b/bootstrap/lib/stdlib/ebin/peer.beam new file mode 100644 index 000000000000..c33b59419607 Binary files /dev/null and b/bootstrap/lib/stdlib/ebin/peer.beam differ diff --git a/bootstrap/lib/stdlib/ebin/pool.beam b/bootstrap/lib/stdlib/ebin/pool.beam index 04e83527a6df..97d7cc080c1a 100644 Binary files a/bootstrap/lib/stdlib/ebin/pool.beam and b/bootstrap/lib/stdlib/ebin/pool.beam differ diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam index f15a7e2199ed..3aa850b24122 100644 Binary files a/bootstrap/lib/stdlib/ebin/proc_lib.beam and b/bootstrap/lib/stdlib/ebin/proc_lib.beam differ diff --git a/bootstrap/lib/stdlib/ebin/proplists.beam b/bootstrap/lib/stdlib/ebin/proplists.beam index e3d584e232e0..de05dc9f9713 100644 Binary files a/bootstrap/lib/stdlib/ebin/proplists.beam and b/bootstrap/lib/stdlib/ebin/proplists.beam differ diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam index cb59b4e6a2ba..62d410e7790d 100644 Binary files a/bootstrap/lib/stdlib/ebin/qlc.beam and b/bootstrap/lib/stdlib/ebin/qlc.beam differ diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam index 4f5e240e4a7a..3e4ceae2f7ab 100644 Binary files a/bootstrap/lib/stdlib/ebin/qlc_pt.beam and b/bootstrap/lib/stdlib/ebin/qlc_pt.beam differ diff --git a/bootstrap/lib/stdlib/ebin/queue.beam b/bootstrap/lib/stdlib/ebin/queue.beam index f06730ff26ba..51035a965dd4 100644 Binary files a/bootstrap/lib/stdlib/ebin/queue.beam and b/bootstrap/lib/stdlib/ebin/queue.beam differ diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam index 86e447a949c5..bbb3a4eb5ce7 100644 Binary files a/bootstrap/lib/stdlib/ebin/rand.beam and b/bootstrap/lib/stdlib/ebin/rand.beam differ diff --git a/bootstrap/lib/stdlib/ebin/random.beam b/bootstrap/lib/stdlib/ebin/random.beam index 82da8484742a..914b337d2898 100644 Binary files a/bootstrap/lib/stdlib/ebin/random.beam and b/bootstrap/lib/stdlib/ebin/random.beam differ diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam index 4eb8ad8b3289..3358a74b0ca2 100644 Binary files a/bootstrap/lib/stdlib/ebin/re.beam and b/bootstrap/lib/stdlib/ebin/re.beam differ diff --git a/bootstrap/lib/stdlib/ebin/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam index 8bd8c5dca44a..061f08f77483 100644 Binary files a/bootstrap/lib/stdlib/ebin/sets.beam and b/bootstrap/lib/stdlib/ebin/sets.beam differ diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam index fe013f311b7c..78fa66ad43b2 100644 Binary files a/bootstrap/lib/stdlib/ebin/shell.beam and b/bootstrap/lib/stdlib/ebin/shell.beam differ diff --git a/bootstrap/lib/stdlib/ebin/shell_default.beam b/bootstrap/lib/stdlib/ebin/shell_default.beam index 6c66342b86db..8ebf59566806 100644 Binary files a/bootstrap/lib/stdlib/ebin/shell_default.beam and b/bootstrap/lib/stdlib/ebin/shell_default.beam differ diff --git a/bootstrap/lib/stdlib/ebin/shell_docs.beam b/bootstrap/lib/stdlib/ebin/shell_docs.beam index edd19f9c8d95..1ce77bc2c310 100644 Binary files a/bootstrap/lib/stdlib/ebin/shell_docs.beam and b/bootstrap/lib/stdlib/ebin/shell_docs.beam differ diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam index 271fedf8a82d..d497fcf133c1 100644 Binary files a/bootstrap/lib/stdlib/ebin/slave.beam and b/bootstrap/lib/stdlib/ebin/slave.beam differ diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam index 9d5a0d4fa29b..d4c4383f7678 100644 Binary files a/bootstrap/lib/stdlib/ebin/sofs.beam and b/bootstrap/lib/stdlib/ebin/sofs.beam differ diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index dd1a969d3de2..36d2e9b55286 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -20,7 +20,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "3.15.2"}, + {vsn, "4.2"}, {modules, [array, base64, beam_lib, @@ -36,7 +36,9 @@ digraph, digraph_utils, edlin, + edlin_context, edlin_expand, + edlin_type_suggestion, epp, eval_bits, erl_abstract_code, @@ -46,6 +48,7 @@ erl_error, erl_eval, erl_expand_records, + erl_features, erl_internal, erl_lint, erl_parse, @@ -71,7 +74,6 @@ io, io_lib, io_lib_format, - io_lib_format_ryu_table, io_lib_fread, io_lib_pretty, lists, @@ -82,6 +84,7 @@ orddict, ordsets, otp_internal, + peer, pool, proc_lib, proplists, @@ -111,6 +114,6 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-3.0","kernel-7.0","erts-12.0","crypto-3.3", + {runtime_dependencies, ["sasl-3.0","kernel-@OTP-17932@","erts-13.1","crypto-4.5", "compiler-5.0"]} ]}. diff --git a/bootstrap/lib/stdlib/ebin/stdlib.appup b/bootstrap/lib/stdlib/ebin/stdlib.appup index cf693f332c78..adebe1686060 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.appup +++ b/bootstrap/lib/stdlib/ebin/stdlib.appup @@ -1,7 +1,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2017. All Rights Reserved. +%% Copyright Ericsson AB 1999-2021. 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. @@ -19,45 +19,50 @@ %% %% We allow upgrade from, and downgrade to all previous %% versions from the following OTP releases: -%% - OTP 20 -%% - OTP 21 +%% - OTP 23 +%% - OTP 24 +%% - OTP 25 %% %% We also allow upgrade from, and downgrade to all %% versions that have branched off from the above %% stated previous versions. %% -{"3.8.1", - [{<<"^3\\.4$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.4(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.5(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.5$">>,[restart_new_emulator]}, - {<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.6$">>,[restart_new_emulator]}, - {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.7$">>,[restart_new_emulator]}, - {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.8$">>,[restart_new_emulator]}, - {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], - [{<<"^3\\.4$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.4(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.5(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.5$">>,[restart_new_emulator]}, - {<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.6$">>,[restart_new_emulator]}, - {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.7$">>,[restart_new_emulator]}, - {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.8$">>,[restart_new_emulator]}, - {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. +{"4.0", + [{<<"^3\\.13$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.14$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.15$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.16$">>,[restart_new_emulator]}, + {<<"^3\\.16\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.16\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.17$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}], + [{<<"^3\\.13$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.13\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.14$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.14\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.15$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.15\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.16$">>,[restart_new_emulator]}, + {<<"^3\\.16\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.16\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.17$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^3\\.17\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}. diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam index c1e09b2c270f..51a6a703b5e7 100644 Binary files a/bootstrap/lib/stdlib/ebin/string.beam and b/bootstrap/lib/stdlib/ebin/string.beam differ diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam index 84bd2bac576b..ff9960f6f3bc 100644 Binary files a/bootstrap/lib/stdlib/ebin/supervisor.beam and b/bootstrap/lib/stdlib/ebin/supervisor.beam differ diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam index ad695813fca3..62daac1f340f 100644 Binary files a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam and b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam differ diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam index 2ee1592d1402..b731ba01a34a 100644 Binary files a/bootstrap/lib/stdlib/ebin/sys.beam and b/bootstrap/lib/stdlib/ebin/sys.beam differ diff --git a/bootstrap/lib/stdlib/ebin/timer.beam b/bootstrap/lib/stdlib/ebin/timer.beam index 9fe97e284f52..39dd41690a7f 100644 Binary files a/bootstrap/lib/stdlib/ebin/timer.beam and b/bootstrap/lib/stdlib/ebin/timer.beam differ diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam index e0bd7593d2e0..461df9d3360a 100644 Binary files a/bootstrap/lib/stdlib/ebin/unicode.beam and b/bootstrap/lib/stdlib/ebin/unicode.beam differ diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam index 0a150bf0e11a..953a8f00fb7c 100644 Binary files a/bootstrap/lib/stdlib/ebin/unicode_util.beam and b/bootstrap/lib/stdlib/ebin/unicode_util.beam differ diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam index 076e3e74e8b0..30aa89eb9445 100644 Binary files a/bootstrap/lib/stdlib/ebin/uri_string.beam and b/bootstrap/lib/stdlib/ebin/uri_string.beam differ diff --git a/bootstrap/lib/stdlib/ebin/win32reg.beam b/bootstrap/lib/stdlib/ebin/win32reg.beam index 96869dd3f179..fa17c2ce1b44 100644 Binary files a/bootstrap/lib/stdlib/ebin/win32reg.beam and b/bootstrap/lib/stdlib/ebin/win32reg.beam differ diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam index c95763272122..b3fa72d44c93 100644 Binary files a/bootstrap/lib/stdlib/ebin/zip.beam and b/bootstrap/lib/stdlib/ebin/zip.beam differ diff --git a/configure b/configure index 19b4b01ec85d..74dc69ed7a0c 100755 --- a/configure +++ b/configure @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2018-2021. All Rights Reserved. +# Copyright Ericsson AB 2018-2022. 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. @@ -139,6 +139,10 @@ while test $# != 0; do pie_cflags="-fno-PIE" pie_ldflags="-no-pie" ;; + --enable-deterministic-build) + config_arguments="$config_arguments --enable-deterministic-build";; + --disable-deterministic-build) + config_arguments="$config_arguments --disable-deterministic-build";; CFLAGS=* | LDFLAGS=*) flgs_var=`echo "$1" | sed 's/=.*$//'` flgs_val=`echo "$1" | sed 's/^[^=]*=//'` diff --git a/configure.src b/configure.src index f0afd5c6ee7b..d320c4520b69 100644 --- a/configure.src +++ b/configure.src @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2018-2021. All Rights Reserved. +# Copyright Ericsson AB 2018-2022. 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. @@ -139,6 +139,10 @@ while test $# != 0; do pie_cflags="-fno-PIE" pie_ldflags="-no-pie" ;; + --enable-deterministic-build) + config_arguments="$config_arguments --enable-deterministic-build";; + --disable-deterministic-build) + config_arguments="$config_arguments --disable-deterministic-build";; CFLAGS=* | LDFLAGS=*) flgs_var=`echo "$1" | sed 's/=.*$//'` flgs_val=`echo "$1" | sed 's/^[^=]*=//'` diff --git a/erlang_ls.config b/erlang_ls.config new file mode 100644 index 000000000000..a695bbc92a43 --- /dev/null +++ b/erlang_ls.config @@ -0,0 +1,10 @@ +apps_dirs: + - "lib/*" + - "erts/preloaded" +include_dirs: + - "lib/*/src" + - "lib/*/include" + - "erts/preloaded/src" +diagnostics: + enabled: + - bound_var_in_pattern diff --git a/erts/.gitignore b/erts/.gitignore index 8886a8855e8f..e26eca891724 100644 --- a/erts/.gitignore +++ b/erts/.gitignore @@ -18,7 +18,10 @@ /emulator/test/Emakefile /emulator/test/*.beam /emulator/test/*_no_opt_SUITE.erl +/emulator/test/*_r25_SUITE.erl /emulator/pcre/pcre_exec_loop_break_cases.inc /emulator/beam/erl_db_insert_list.ycf.h +/emulator/ryu/obj +/obj.debug/ diff --git a/erts/Makefile b/erts/Makefile index 4f083752a761..99f4ee3a385a 100644 --- a/erts/Makefile +++ b/erts/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2006-2020. All Rights Reserved. +# Copyright Ericsson AB 2006-2022. 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. @@ -40,8 +40,8 @@ all: $(if $(FLAVOR),$(FLAVOR),$(PRIMARY_FLAVOR)) docs: $(V_at)( cd doc/src && $(MAKE) $@ ) -.PHONY: debug opt lcnt clean -debug opt lcnt clean: +.PHONY: debug opt lcnt clean test +$(TYPES) clean: $(V_at)for d in emulator $(ERTSDIRS); do \ if test -d $$d; then \ ( cd $$d && $(MAKE) $@ ) || exit $$?; \ @@ -49,9 +49,15 @@ debug opt lcnt clean: done (cd preloaded/src && $(MAKE) ../ebin/erts.app) + +.PHONY: test +test: + TEST_NEEDS_RELEASE=true TYPE=$(TYPE) \ + $(ERL_TOP)/make/test_target_script.sh $(ERL_TOP) + .PHONY: $(FLAVORS) $(FLAVORS): - $(V_at)for type in $(TYPES); do \ + $(V_at)for type in $(DEFAULT_TYPES); do \ ( $(MAKE) FLAVOR=$@ $$type ) || exit $$?; \ done @@ -80,20 +86,22 @@ local_setup: cp $(ERL_TOP)/bin/$(TARGET)/erlc.exe $(ERL_TOP)/bin/erlc.exe; \ cp $(ERL_TOP)/bin/$(TARGET)/erl.exe $(ERL_TOP)/bin/erl.exe; \ cp $(ERL_TOP)/bin/$(TARGET)/erl_call.exe $(ERL_TOP)/bin/erl_call.exe; \ - cp $(ERL_TOP)/bin/$(TARGET)/werl.exe $(ERL_TOP)/bin/werl.exe; \ cp $(ERL_TOP)/bin/$(TARGET)/escript.exe $(ERL_TOP)/bin/escript.exe; \ - chmod 755 $(ERL_TOP)/bin/erl.exe $(ERL_TOP)/bin/erlc.exe \ - $(ERL_TOP)/bin/werl.exe; \ + chmod 755 $(ERL_TOP)/bin/erl.exe $(ERL_TOP)/bin/erlc.exe; \ make_local_ini.sh $(ERL_TOP); \ cp $(ERL_TOP)/bin/erl.ini $(ERL_TOP)/bin/$(TARGET)/erl.ini; \ else \ + cd etc/unix && $(MAKE); \ sed -e "s;%FINAL_ROOTDIR%;$(ERL_TOP);" \ -e "s;erts-.*/bin;bin/$(TARGET);" \ -e "s;EMU=.*;EMU=beam$(TYPEMARKER);" \ + -e "s;%DYN_ERL_PATH%;$(TARGET)/dyn_erl;" \ + -e "s;%DYN_ROOTDIR_BASE_EXT%;;" \ $(ERL_TOP)/erts/etc/unix/erl.src.src > $(ERL_TOP)/bin/erl; \ sed -e "s;%SRC_ROOTDIR%;$(ERL_TOP);" \ -e "s;%TARGET%;$(TARGET);" \ -e "s;%VSN%;$(VSN);" \ + -e "s;%DYN_ERL_PATH%;$(TARGET)/dyn_erl;" \ $(ERL_TOP)/erts/etc/unix/cerl.src > $(ERL_TOP)/bin/cerl; \ cp $(ERL_TOP)/bin/$(TARGET)/erl_call $(ERL_TOP)/bin/erl_call; \ cp $(ERL_TOP)/bin/$(TARGET)/dialyzer $(ERL_TOP)/bin/dialyzer; \ @@ -141,7 +149,7 @@ makefiles: .PHONY: release release: ifeq ($(TYPE),) - for t in $(TYPES); do \ + for t in $(DEFAULT_TYPES); do \ ( cd emulator && $(MAKE) release TYPE=$$t ) || exit $$?; \ done else @@ -164,5 +172,3 @@ release_docs: .PHONY: xmllint xmllint: $(MAKE) -C doc/src $@ - -include $(ERL_TOP)/make/app_targets.mk diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 deleted file mode 100644 index c50c05f1c639..000000000000 --- a/erts/aclocal.m4 +++ /dev/null @@ -1,3234 +0,0 @@ -dnl -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 1998-2022. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% -dnl - -dnl -dnl aclocal.m4 -dnl -dnl Local macros used in configure.in. The Local Macros which -dnl could/should be part of autoconf are prefixed LM_, macros specific -dnl to the Erlang system are prefixed ERL_. -dnl - -AC_DEFUN(LM_PRECIOUS_VARS, -[ - -dnl ERL_TOP -AC_ARG_VAR(ERL_TOP, [Erlang/OTP top source directory]) - -dnl Tools -AC_ARG_VAR(CC, [C compiler]) -AC_ARG_VAR(CFLAGS, [C compiler flags]) -AC_ARG_VAR(STATIC_CFLAGS, [C compiler static flags]) -AC_ARG_VAR(CFLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag passed via C compiler]) -AC_ARG_VAR(CPP, [C/C++ preprocessor]) -AC_ARG_VAR(CPPFLAGS, [C/C++ preprocessor flags]) -AC_ARG_VAR(CXX, [C++ compiler]) -AC_ARG_VAR(CXXFLAGS, [C++ compiler flags]) -AC_ARG_VAR(LD, [linker (is often overridden by configure)]) -AC_ARG_VAR(LDFLAGS, [linker flags (can be risky to set since LD may be overridden by configure)]) -AC_ARG_VAR(LIBS, [libraries]) -AC_ARG_VAR(DED_LD, [linker for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) -AC_ARG_VAR(DED_LDFLAGS, [linker flags for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) -AC_ARG_VAR(DED_LD_FLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) -AC_ARG_VAR(LFS_CFLAGS, [large file support C compiler flags (set all LFS_* variables or none)]) -AC_ARG_VAR(LFS_LDFLAGS, [large file support linker flags (set all LFS_* variables or none)]) -AC_ARG_VAR(LFS_LIBS, [large file support libraries (set all LFS_* variables or none)]) -AC_ARG_VAR(RANLIB, [ranlib]) -AC_ARG_VAR(AR, [ar]) -AC_ARG_VAR(GETCONF, [getconf]) - -dnl Cross system root -AC_ARG_VAR(erl_xcomp_sysroot, [Absolute cross system root path (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_isysroot, [Absolute cross system root include path (only used when cross compiling)]) - -dnl Cross compilation variables -AC_ARG_VAR(erl_xcomp_bigendian, [big endian system: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_double_middle_endian, [double-middle-endian system: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_linux_nptl, [have Native POSIX Thread Library: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_linux_usable_sigusrx, [SIGUSR1 and SIGUSR2 can be used: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_linux_usable_sigaltstack, [have working sigaltstack(): yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_poll, [have working poll(): yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_kqueue, [have working kqueue(): yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_putenv_copy, [putenv() stores key-value copy: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_reliable_fpe, [have reliable floating point exceptions: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_getaddrinfo, [have working getaddrinfo() for both IPv4 and IPv6: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_gethrvtime_procfs_ioctl, [have working gethrvtime() which can be used with procfs ioctl(): yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_clock_gettime_cpu_time, [clock_gettime() can be used for retrieving process CPU time: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_after_morecore_hook, [__after_morecore_hook can track malloc()s core memory usage: yes|no (only used when cross compiling)]) -AC_ARG_VAR(erl_xcomp_dlsym_brk_wrappers, [dlsym(RTLD_NEXT, _) brk wrappers can track malloc()s core memory usage: yes|no (only used when cross compiling)]) - -]) - -AC_DEFUN(ERL_XCOMP_SYSROOT_INIT, -[ -erl_xcomp_without_sysroot=no -if test "$cross_compiling" = "yes"; then - test "$erl_xcomp_sysroot" != "" || erl_xcomp_without_sysroot=yes - test "$erl_xcomp_isysroot" != "" || erl_xcomp_isysroot="$erl_xcomp_sysroot" -else - erl_xcomp_sysroot= - erl_xcomp_isysroot= -fi -]) - -AC_DEFUN(LM_CHECK_GETCONF, -[ -if test "$cross_compiling" != "yes"; then - AC_CHECK_PROG([GETCONF], [getconf], [getconf], [false]) -else - dnl First check if we got a `-getconf' in $PATH - host_getconf="$host_alias-getconf" - AC_CHECK_PROG([GETCONF], [$host_getconf], [$host_getconf], [false]) - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then - dnl We should perhaps give up if we have'nt found it by now, but at - dnl least in one Tilera MDE `getconf' under sysroot is a bourne - dnl shell script which we can use. We try to find `-getconf' - dnl or `getconf' under sysconf, but only under sysconf since - dnl `getconf' in $PATH is almost guaranteed to be for the build - dnl machine. - GETCONF= - prfx="$erl_xcomp_sysroot" - AC_PATH_TOOL([GETCONF], [getconf], [false], - ["$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"]) - fi -fi -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_WINDOWS_ENVIRONMENT -dnl -dnl -dnl Tries to determine the windows build environment, i.e. -dnl MIXED_VC or MIXED_MINGW -dnl - -AC_DEFUN(LM_WINDOWS_ENVIRONMENT, -[ - -if test "X$windows_environment_" != "Xchecked"; then -windows_environment_=checked -MIXED_CYGWIN=no -MIXED_MSYS=no -MIXED_VSL=no - -dnl MIXED_VC is Microsoft Visual C++ used as standard compiler -MIXED_VC=no -dnl MIXED_MINGW is mingw(32|64) used as standard compiler -MIXED_MINGW=no - -AC_MSG_CHECKING(for mixed mingw-gcc and native VC++ environment) -if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then - if test -x /usr/bin/msys-?.0.dll; then - CFLAGS="$CFLAGS -O2" - MIXED_MSYS=yes - AC_MSG_RESULT([MSYS and VC]) - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - elif test -x /usr/bin/cygpath; then - CFLAGS="$CFLAGS -O2" - MIXED_CYGWIN=yes - AC_MSG_RESULT([Cygwin and VC]) - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - elif test -x /bin/wslpath; then - CFLAGS="$CFLAGS -O2" - MIXED_WSL=yes - AC_MSG_RESULT([WSL and VC]) - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - else - AC_MSG_RESULT([undeterminable]) - AC_MSG_ERROR(Seems to be mixed windows but not within any known env, cannot handle this!) - fi -else - AC_MSG_RESULT([no]) -fi - -AC_SUBST(MIXED_VC) - -if test "x$MIXED_MSYS" != "xyes"; then - AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) - if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then - if test -x /usr/bin/cygpath; then - CFLAGS="$CFLAGS -O2" - AC_MSG_RESULT([yes]) - MIXED_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" - else - AC_MSG_RESULT([undeterminable]) - AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) - fi - else - AC_MSG_RESULT([no]) - fi -else - AC_MSG_CHECKING(for mixed MSYS and native MinGW environment) - if test "x$GCC" = x"yes"; then - if test -x /usr/bin/msys-=.0.dll; then - CFLAGS="$CFLAGS -O2" - AC_MSG_RESULT([yes]) - MIXED_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" - else - AC_MSG_RESULT([undeterminable]) - AC_MSG_ERROR(Seems to be mixed windows but not with msys, cannot handle this!) - fi - else - AC_MSG_RESULT([no]) - fi -fi -AC_SUBST(MIXED_MINGW) - -AC_MSG_CHECKING(if we mix cygwin with any native compiler) -if test "X$MIXED_CYGWIN" = "Xyes"; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -AC_MSG_CHECKING(if we mix msys with another native compiler) -if test "X$MIXED_MSYS" = "Xyes" ; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -AC_MSG_CHECKING(if we mix WSL with another native compiler) -if test "X$MIXED_WSL" = "Xyes" ; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -fi -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_FIND_EMU_CC -dnl -dnl -dnl Tries fairly hard to find a C compiler that can handle jump tables. -dnl Defines the @EMU_CC@ variable for the makefiles and -dnl inserts NO_JUMP_TABLE in the header if one cannot be found... -dnl - -AC_DEFUN(LM_FIND_EMU_CC, - [AC_CACHE_CHECK(for a compiler that handles jumptables, - ac_cv_prog_emu_cc, - [ -AC_TRY_COMPILE([],[ -#if defined(__clang_major__) && __clang_major__ >= 3 - /* clang 3.x or later is fine */ -#elif defined(__llvm__) -#error "this version of llvm is unable to correctly compile beam_emu.c" -#endif - __label__ lbl1; - __label__ lbl2; - extern int magic(void); - int x = magic(); - static void *jtab[2]; - - jtab[0] = &&lbl1; - jtab[1] = &&lbl2; - goto *jtab[x]; -lbl1: - return 1; -lbl2: - return 2; -],ac_cv_prog_emu_cc="$CC",ac_cv_prog_emu_cc=no) - -if test "$ac_cv_prog_emu_cc" = no; then - for ac_progname in emu_cc.sh gcc-4.2 gcc; do - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_progname"; then - ac_cv_prog_emu_cc="$ac_dir/$ac_progname" - break - fi - done - IFS="$ac_save_ifs" - if test "$ac_cv_prog_emu_cc" != no; then - break - fi - done -fi - -if test "$ac_cv_prog_emu_cc" != no; then - save_CC="$CC" - save_CFLAGS=$CFLAGS - save_CPPFLAGS=$CPPFLAGS - CC="$ac_cv_prog_emu_cc" - CFLAGS="" - CPPFLAGS="" - AC_TRY_COMPILE([],[ -#if defined(__clang_major__) && __clang_major__ >= 3 - /* clang 3.x or later is fine */ -#elif defined(__llvm__) -#error "this version of llvm is unable to correctly compile beam_emu.c" -#endif - __label__ lbl1; - __label__ lbl2; - extern int magic(void); - int x = magic(); - static void *jtab[2]; - - jtab[0] = &&lbl1; - jtab[1] = &&lbl2; - goto *jtab[x]; - lbl1: - return 1; - lbl2: - return 2; - ],ac_cv_prog_emu_cc="$CC",ac_cv_prog_emu_cc=no) - CC=$save_CC - CFLAGS=$save_CFLAGS - CPPFLAGS=$save_CPPFLAGS -fi -]) -if test "$ac_cv_prog_emu_cc" = no; then - AC_DEFINE(NO_JUMP_TABLE,[],[Defined if no found C compiler can handle jump tables]) - EMU_CC="$CC" -else - EMU_CC="$ac_cv_prog_emu_cc" -fi -AC_SUBST(EMU_CC) -]) - - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_PROG_INSTALL_DIR -dnl -dnl This macro may be used by any OTP application. -dnl -dnl Figure out how to create directories with parents. -dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better) -dnl -dnl We prefer 'install -d', but use 'mkdir -p' if it exists. -dnl If none of these methods works, we give up. -dnl - - -AC_DEFUN(LM_PROG_INSTALL_DIR, -[AC_CACHE_CHECK(how to create a directory including parents, -ac_cv_prog_mkdir_p, -[ -temp_name_base=config.$$ -temp_name=$temp_name_base/x/y/z -$INSTALL -d $temp_name >/dev/null 2>&1 -ac_cv_prog_mkdir_p=none -if test -d $temp_name; then - ac_cv_prog_mkdir_p="$INSTALL -d" -else - mkdir -p $temp_name >/dev/null 2>&1 - if test -d $temp_name; then - ac_cv_prog_mkdir_p="mkdir -p" - fi -fi -rm -fr $temp_name_base -]) - -case "${ac_cv_prog_mkdir_p}" in - none) AC_MSG_ERROR(don't know how create directories with parents) ;; - *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;; -esac -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_PROG_PERL5 -dnl -dnl Try to find perl version 5. If found set PERL to the absolute path -dnl of the program, if not found set PERL to false. -dnl -AC_DEFUN(LM_PROG_PERL5, -[AC_PATH_PROGS(PERL, perl5 perl, false, - /usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH}) -if test "$PERL" = "false"; then - ac_cv_path_PERL=false - PERL=false -dnl AC_MSG_WARN(perl version 5 not found) -fi -])dnl - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_DECL_SO_BSDCOMPAT -dnl -dnl Check if the system has the SO_BSDCOMPAT flag on sockets (linux) -dnl -AC_DEFUN(LM_DECL_SO_BSDCOMPAT, -[AC_CACHE_CHECK([for SO_BSDCOMPAT declaration], ac_cv_decl_so_bsdcompat, -AC_TRY_COMPILE([#include ], [int i = SO_BSDCOMPAT;], - ac_cv_decl_so_bsdcompat=yes, - ac_cv_decl_so_bsdcompat=no)) - -case "${ac_cv_decl_so_bsdcompat}" in - "yes" ) AC_DEFINE(HAVE_SO_BSDCOMPAT,[], - [Define if you have SO_BSDCOMPAT flag on sockets]) ;; - * ) ;; -esac -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_DECL_INADDR_LOOPBACK -dnl -dnl Try to find declaration of INADDR_LOOPBACK, if nowhere provide a default -dnl - -AC_DEFUN(LM_DECL_INADDR_LOOPBACK, -[AC_CACHE_CHECK([for INADDR_LOOPBACK in netinet/in.h], - ac_cv_decl_inaddr_loopback, -[AC_TRY_COMPILE([#include -#include ], [int i = INADDR_LOOPBACK;], -ac_cv_decl_inaddr_loopback=yes, ac_cv_decl_inaddr_loopback=no) -]) - -if test ${ac_cv_decl_inaddr_loopback} = no; then - AC_CACHE_CHECK([for INADDR_LOOPBACK in rpc/types.h], - ac_cv_decl_inaddr_loopback_rpc, - AC_TRY_COMPILE([#include ], - [int i = INADDR_LOOPBACK;], - ac_cv_decl_inaddr_loopback_rpc=yes, - ac_cv_decl_inaddr_loopback_rpc=no)) - - case "${ac_cv_decl_inaddr_loopback_rpc}" in - "yes" ) - AC_DEFINE(DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H,[], - [Define if you need to include rpc/types.h to get INADDR_LOOPBACK defined]) ;; - * ) - AC_CACHE_CHECK([for INADDR_LOOPBACK in winsock2.h], - ac_cv_decl_inaddr_loopback_winsock2, - AC_TRY_COMPILE([#define WIN32_LEAN_AND_MEAN - #include ], - [int i = INADDR_LOOPBACK;], - ac_cv_decl_inaddr_loopback_winsock2=yes, - ac_cv_decl_inaddr_loopback_winsock2=no)) - case "${ac_cv_decl_inaddr_loopback_winsock2}" in - "yes" ) - AC_DEFINE(DEF_INADDR_LOOPBACK_IN_WINSOCK2_H,[], - [Define if you need to include winsock2.h to get INADDR_LOOPBACK defined]) ;; - * ) - # couldn't find it anywhere - AC_DEFINE(HAVE_NO_INADDR_LOOPBACK,[], - [Define if you don't have a definition of INADDR_LOOPBACK]) ;; - esac;; - esac -fi -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_STRUCT_SOCKADDR_SA_LEN -dnl -dnl Check if the sockaddr structure has the field sa_len -dnl - -AC_DEFUN(LM_STRUCT_SOCKADDR_SA_LEN, -[AC_CACHE_CHECK([whether struct sockaddr has sa_len field], - ac_cv_struct_sockaddr_sa_len, -AC_TRY_COMPILE([#include -#include ], [struct sockaddr s; s.sa_len = 10;], - ac_cv_struct_sockaddr_sa_len=yes, ac_cv_struct_sockaddr_sa_len=no)) - -dnl FIXME convbreak -case ${ac_cv_struct_sockaddr_sa_len} in - "no" ) AC_DEFINE(NO_SA_LEN,[1],[Define if you dont have salen]) ;; - *) ;; -esac -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_SYS_IPV6 -dnl -dnl Check for ipv6 support and what the in6_addr structure is called. -dnl (early linux used in_addr6 insted of in6_addr) -dnl - -AC_DEFUN(LM_SYS_IPV6, -[AC_MSG_CHECKING(for IP version 6 support) -AC_CACHE_VAL(ac_cv_sys_ipv6_support, -[ok_so_far=yes - AC_TRY_COMPILE([#include -#ifdef __WIN32__ -#include -#include -#else -#include -#endif], - [struct in6_addr a6; struct sockaddr_in6 s6;], ok_so_far=yes, ok_so_far=no) - -if test $ok_so_far = yes; then - ac_cv_sys_ipv6_support=yes -else - AC_TRY_COMPILE([#include -#ifdef __WIN32__ -#include -#include -#else -#include -#endif], - [struct in_addr6 a6; struct sockaddr_in6 s6;], - ac_cv_sys_ipv6_support=in_addr6, ac_cv_sys_ipv6_support=no) -fi -])dnl - -dnl -dnl Have to use old style AC_DEFINE due to BC with old autoconf. -dnl - -case ${ac_cv_sys_ipv6_support} in - yes) - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present]) - ;; - in_addr6) - AC_MSG_RESULT([yes (but I am redefining in_addr6 to in6_addr)]) - AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present]) - AC_DEFINE(HAVE_IN_ADDR6_STRUCT,[],[Early linux used in_addr6 instead of in6_addr, define if you have this]) - ;; - *) - AC_MSG_RESULT(no) - ;; -esac -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_SYS_MULTICAST -dnl -dnl Check for multicast support. Only checks for multicast options in -dnl setsockopt(), no check is performed that multicasting actually works. -dnl If options are found defines HAVE_MULTICAST_SUPPORT -dnl - -AC_DEFUN(LM_SYS_MULTICAST, -[AC_CACHE_CHECK([for multicast support], ac_cv_sys_multicast_support, -[AC_EGREP_CPP(^yes$, -[#include -#include -#include -#if defined(IP_MULTICAST_TTL) && defined(IP_MULTICAST_LOOP) && defined(IP_MULTICAST_IF) && defined(IP_ADD_MEMBERSHIP) && defined(IP_DROP_MEMBERSHIP) -yes -#endif -], ac_cv_sys_multicast_support=yes, ac_cv_sys_multicast_support=no)]) -if test $ac_cv_sys_multicast_support = yes; then - AC_DEFINE(HAVE_MULTICAST_SUPPORT,[1], - [Define if setsockopt() accepts multicast options]) -fi -])dnl - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_DECL_SYS_ERRLIST -dnl -dnl Define SYS_ERRLIST_DECLARED if the variable sys_errlist is declared -dnl in a system header file, stdio.h or errno.h. -dnl - -AC_DEFUN(LM_DECL_SYS_ERRLIST, -[AC_CACHE_CHECK([for sys_errlist declaration in stdio.h or errno.h], - ac_cv_decl_sys_errlist, -[AC_TRY_COMPILE([#include -#include ], [char *msg = *(sys_errlist + 1);], - ac_cv_decl_sys_errlist=yes, ac_cv_decl_sys_errlist=no)]) -if test $ac_cv_decl_sys_errlist = yes; then - AC_DEFINE(SYS_ERRLIST_DECLARED,[], - [define if the variable sys_errlist is declared in a system header file]) -fi -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_CHECK_FUNC_DECL( funname, declaration [, extra includes -dnl [, action-if-found [, action-if-not-found]]] ) -dnl -dnl Checks if the declaration "declaration" of "funname" conflicts -dnl with the header files idea of how the function should be -dnl declared. It is useful on systems which lack prototypes and you -dnl need to provide your own (e.g. when you want to take the address -dnl of a function). The 4'th argument is expanded if conflicting, -dnl the 5'th argument otherwise -dnl -dnl - -AC_DEFUN(LM_CHECK_FUNC_DECL, -[AC_MSG_CHECKING([for conflicting declaration of $1]) -AC_CACHE_VAL(ac_cv_func_decl_$1, -[AC_TRY_COMPILE([#include -$3],[$2 -char *c = (char *)$1; -], eval "ac_cv_func_decl_$1=no", eval "ac_cv_func_decl_$1=yes")]) -if eval "test \"`echo '$ac_cv_func_decl_'$1`\" = yes"; then - AC_MSG_RESULT(yes) - ifelse([$4], , :, [$4]) -else - AC_MSG_RESULT(no) -ifelse([$5], , , [$5 -])dnl -fi -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl AC_DOUBLE_MIDDLE_ENDIAN -dnl -dnl Checks whether doubles are represented in "middle-endian" format. -dnl Sets ac_cv_double_middle_endian={no,yes,unknown} accordingly, -dnl as well as DOUBLE_MIDDLE_ENDIAN. -dnl -dnl - -AC_DEFUN([AC_C_DOUBLE_MIDDLE_ENDIAN], -[AC_CACHE_CHECK(whether double word ordering is middle-endian, ac_cv_c_double_middle_endian, -[# It does not; compile a test program. -AC_RUN_IFELSE( -[AC_LANG_SOURCE([[#include - -int -main(void) -{ - int i = 0; - int zero = 0; - int bigendian; - int zero_index = 0; - - union - { - long int l; - char c[sizeof (long int)]; - } u; - - /* we'll use the one with 32-bit words */ - union - { - double d; - unsigned int c[2]; - } vint; - - union - { - double d; - unsigned long c[2]; - } vlong; - - union - { - double d; - unsigned short c[2]; - } vshort; - - - /* Are we little or big endian? From Harbison&Steele. */ - u.l = 1; - bigendian = (u.c[sizeof (long int) - 1] == 1); - - zero_index = bigendian ? 1 : 0; - - vint.d = 1.0; - vlong.d = 1.0; - vshort.d = 1.0; - - if (sizeof(unsigned int) == 4) - { - if (vint.c[zero_index] != 0) - zero = 1; - } - else if (sizeof(unsigned long) == 4) - { - if (vlong.c[zero_index] != 0) - zero = 1; - } - else if (sizeof(unsigned short) == 4) - { - if (vshort.c[zero_index] != 0) - zero = 1; - } - - exit (zero); -} -]])], - [ac_cv_c_double_middle_endian=no], - [ac_cv_c_double_middle_endian=yes], - [ac_cv_c_double_middle=unknown])]) -case $ac_cv_c_double_middle_endian in - yes) - m4_default([$1], - [AC_DEFINE([DOUBLE_MIDDLE_ENDIAN], 1, - [Define to 1 if your processor stores the words in a double in - middle-endian format (like some ARMs).])]) ;; - no) - $2 ;; - *) - m4_default([$3], - [AC_MSG_WARN([unknown double endianness -presetting ac_cv_c_double_middle_endian=no (or yes) will help])]) ;; -esac -])# AC_C_DOUBLE_MIDDLE_ENDIAN - - -AC_DEFUN(ERL_MONOTONIC_CLOCK, -[ - # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur - # and Monterey, since it may step backwards. - if test "$3" = "yes"; then - case $host_os in - darwin*) - default_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW" - low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW_APPROX" - high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW";; - *) - default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC" - low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST" - high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE";; - esac - else - case $host_os in - darwin*) - default_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW" - low_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW_APPROX" - high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW";; - *) - default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_UPTIME CLOCK_MONOTONIC" - low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_UPTIME_FAST" - high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_PRECISE";; - esac - fi - - case "$1" in - high_resolution) - check_msg="high resolution " - prefer_resolution_clock_gettime_monotonic="$high_resolution_clock_gettime_monotonic" - ;; - low_resolution) - check_msg="low resolution " - prefer_resolution_clock_gettime_monotonic="$low_resolution_clock_gettime_monotonic" - ;; - custom_resolution) - check_msg="custom resolution " - prefer_resolution_clock_gettime_monotonic="$2" - ;; - *) - check_msg="custom " - prefer_resolution_clock_gettime_monotonic="$2" - ;; - esac - - clock_gettime_lib="" - AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_lib="-lrt"]) - - save_LIBS="$LIBS" - LIBS="$LIBS $clock_gettime_lib" - - if test "$LD_MAY_BE_WEAK" != "no"; then - trust_test="#error May not be there due to weak linking" - else - trust_test="" - fi - - AC_CACHE_CHECK([for clock_gettime(CLOCK_MONOTONIC_RAW, _)], erl_cv_clock_gettime_monotonic_raw, - [ - AC_TRY_LINK([ -#include -$trust_test - ], - [ - struct timespec ts; - long long result; - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); - result = ((long long) ts.tv_sec) * 1000000000LL + - ((long long) ts.tv_nsec); - ], - erl_cv_clock_gettime_monotonic_raw=yes, - erl_cv_clock_gettime_monotonic_raw=no) - ]) - - AC_CACHE_CHECK([for clock_gettime() with ${check_msg}monotonic clock type], erl_cv_clock_gettime_monotonic_$1, - [ - for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do - AC_TRY_LINK([ -#include -$trust_test - ], - [ - struct timespec ts; - long long result; - clock_gettime($clock_type,&ts); - result = ((long long) ts.tv_sec) * 1000000000LL + - ((long long) ts.tv_nsec); - ], - erl_cv_clock_gettime_monotonic_$1=$clock_type, - erl_cv_clock_gettime_monotonic_$1=no) - test $erl_cv_clock_gettime_monotonic_$1 = no || break - done - ]) - - LIBS="$save_LIBS" - - if test "$LD_MAY_BE_WEAK" != "no"; then - AC_CHECK_FUNCS([clock_get_attributes gethrtime]) - else - AC_CHECK_FUNCS([clock_getres clock_get_attributes gethrtime]) - fi - - - AC_CACHE_CHECK([for mach clock_get_time() with monotonic clock type], erl_cv_mach_clock_get_time_monotonic, - [ - AC_TRY_COMPILE([ -#include -#include - ], - [ - kern_return_t res; - clock_serv_t clk_srv; - mach_timespec_t time_spec; - - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clk_srv); - res = clock_get_time(clk_srv, &time_spec); - mach_port_deallocate(mach_task_self(), clk_srv); - ], - erl_cv_mach_clock_get_time_monotonic=yes, - erl_cv_mach_clock_get_time_monotonic=no) - ]) - - erl_corrected_monotonic_clock=no - case $erl_cv_clock_gettime_monotonic_$1-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in - *-*-*-win32) - erl_monotonic_clock_func=WindowsAPI - ;; - CLOCK_*-*-*-linux*) - case $erl_cv_clock_gettime_monotonic_$1-$erl_cv_clock_gettime_monotonic_raw in - CLOCK_BOOTTIME-yes|CLOCK_MONOTONIC-yes) - erl_corrected_monotonic_clock=yes - ;; - *) - # We don't trust CLOCK_MONOTONIC to be NTP - # adjusted on linux systems that do not have - # CLOCK_MONOTONIC_RAW (although it seems to - # be...) - ;; - esac - erl_monotonic_clock_func=clock_gettime - ;; - no-no-no-linux*) - erl_monotonic_clock_func=times - ;; - CLOCK_*-*-*-*) - erl_monotonic_clock_func=clock_gettime - ;; - no-yes-*-*) - erl_monotonic_clock_func=gethrtime - ;; - no-no-yes-*) - erl_monotonic_clock_func=mach_clock_get_time - ;; - no-no-no-*) - erl_monotonic_clock_func=none - ;; - esac - - erl_monotonic_clock_low_resolution=no - erl_monotonic_clock_lib= - erl_monotonic_clock_id= - case $erl_monotonic_clock_func in - clock_gettime) - erl_monotonic_clock_id=$erl_cv_clock_gettime_monotonic_$1 - for low_res_id in $low_resolution_clock_gettime_monotonic; do - if test $erl_monotonic_clock_id = $low_res_id; then - erl_monotonic_clock_low_resolution=yes - break - fi - done - erl_monotonic_clock_lib=$clock_gettime_lib - ;; - mach_clock_get_time) - erl_monotonic_clock_id=SYSTEM_CLOCK - ;; - times) - erl_monotonic_clock_low_resolution=yes - ;; - *) - ;; - esac - -]) - -AC_DEFUN(ERL_WALL_CLOCK, -[ - default_resolution_clock_gettime_wall="CLOCK_REALTIME" - low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" - high_resolution_clock_gettime_wall="CLOCK_REALTIME_PRECISE" - - case "$1" in - high_resolution) - check_msg="high resolution " - prefer_resolution_clock_gettime_wall="$high_resolution_clock_gettime_wall" - ;; - low_resolution) - check_msg="low resolution " - prefer_resolution_clock_gettime_wall="$low_resolution_clock_gettime_wall" - ;; - custom_resolution) - check_msg="custom resolution " - prefer_resolution_clock_gettime_wall="$2" - ;; - *) - check_msg="" - prefer_resolution_clock_gettime_wall= - ;; - esac - - clock_gettime_lib="" - AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_lib="-lrt"]) - - save_LIBS="$LIBS" - LIBS="$LIBS $clock_gettime_lib" - - if test "$LD_MAY_BE_WEAK" != "no"; then - trust_test="#error May not be there due to weak linking" - else - trust_test="" - fi - - AC_CACHE_CHECK([for clock_gettime() with ${check_msg}wall clock type], erl_cv_clock_gettime_wall_$1, - [ - for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do - AC_TRY_LINK([ -#include -$trust_test - ], - [ - struct timespec ts; - long long result; - clock_gettime($clock_type,&ts); - result = ((long long) ts.tv_sec) * 1000000000LL + - ((long long) ts.tv_nsec); - ], - erl_cv_clock_gettime_wall_$1=$clock_type, - erl_cv_clock_gettime_wall_$1=no) - test $erl_cv_clock_gettime_wall_$1 = no || break - done - ]) - - LIBS="$save_LIBS" - - if test "$LD_MAY_BE_WEAK" != "no"; then - check_for_clock_getres= - else - check_for_clock_getres=clock_getres - fi - - AC_CHECK_FUNCS([$check_for_clock_getres clock_get_attributes gettimeofday]) - - AC_CACHE_CHECK([for mach clock_get_time() with wall clock type], erl_cv_mach_clock_get_time_wall, - [ - AC_TRY_COMPILE([ -#include -#include - ], - [ - kern_return_t res; - clock_serv_t clk_srv; - mach_timespec_t time_spec; - - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk_srv); - res = clock_get_time(clk_srv, &time_spec); - mach_port_deallocate(mach_task_self(), clk_srv); - ], - erl_cv_mach_clock_get_time_wall=yes, - erl_cv_mach_clock_get_time_wall=no) - ]) - - erl_wall_clock_lib= - erl_wall_clock_low_resolution=no - erl_wall_clock_id= - case $1-$erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in - *-*-*-*-win32) - erl_wall_clock_func=WindowsAPI - erl_wall_clock_low_resolution=yes - ;; - high_resolution-no-yes-*-*) - erl_wall_clock_func=mach_clock_get_time - erl_wall_clock_id=CALENDAR_CLOCK - ;; - *-CLOCK_*-*-*-*) - erl_wall_clock_func=clock_gettime - erl_wall_clock_lib=$clock_gettime_lib - erl_wall_clock_id=$erl_cv_clock_gettime_wall_$1 - for low_res_id in $low_resolution_clock_gettime_wall; do - if test $erl_wall_clock_id = $low_res_id; then - erl_wall_clock_low_resolution=yes - break - fi - done - ;; - *-no-*-yes-*) - erl_wall_clock_func=gettimeofday - ;; - *) - erl_wall_clock_func=none - ;; - esac -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_CHECK_THR_LIB -dnl -dnl This macro may be used by any OTP application. -dnl -dnl LM_CHECK_THR_LIB sets THR_LIBS, THR_DEFS, and THR_LIB_NAME. It also -dnl checks for some pthread headers which will appear in DEFS or config.h. -dnl - -AC_DEFUN(LM_CHECK_THR_LIB, -[ - -NEED_NPTL_PTHREAD_H=no - -dnl win32? -AC_MSG_CHECKING([for native win32 threads]) -if test "X$host_os" = "Xwin32"; then - AC_MSG_RESULT(yes) - THR_DEFS="-DWIN32_THREADS" - THR_LIBS= - THR_LIB_NAME=win32_threads - THR_LIB_TYPE=win32_threads -else - AC_MSG_RESULT(no) - THR_DEFS= - THR_LIBS= - THR_LIB_NAME= - THR_LIB_TYPE=posix_unknown - -dnl Try to find POSIX threads - -dnl The usual pthread lib... - AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread") - -dnl Very old versions of FreeBSD have pthreads in special c library, c_r... - if test "x$THR_LIBS" = "x"; then - AC_CHECK_LIB(c_r, pthread_create, THR_LIBS="-lc_r") - fi - -dnl QNX has pthreads in standard C library - if test "x$THR_LIBS" = "x"; then - AC_CHECK_FUNC(pthread_create, THR_LIBS="none_needed") - fi - -dnl On ofs1 the '-pthread' switch should be used - if test "x$THR_LIBS" = "x"; then - AC_MSG_CHECKING([if the '-pthread' switch can be used]) - saved_cflags=$CFLAGS - CFLAGS="$CFLAGS -pthread" - AC_TRY_LINK([#include ], - pthread_create((void*)0,(void*)0,(void*)0,(void*)0);, - [THR_DEFS="-pthread" - THR_LIBS="-pthread"]) - CFLAGS=$saved_cflags - if test "x$THR_LIBS" != "x"; then - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - fi - fi - - if test "x$THR_LIBS" != "x"; then - THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" - THR_LIB_NAME=pthread - if test "x$THR_LIBS" = "xnone_needed"; then - THR_LIBS= - fi - case $host_os in - solaris*) - THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;; - linux*) - THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" - - LM_CHECK_GETCONF - AC_MSG_CHECKING(for Native POSIX Thread Library) - libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` - if test $? -eq 0; then - case "$libpthr_vsn" in - *nptl*|*NPTL*) nptl=yes;; - *) nptl=no;; - esac - elif test "$cross_compiling" = "yes"; then - case "$erl_xcomp_linux_nptl" in - "") nptl=cross;; - yes|no) nptl=$erl_xcomp_linux_nptl;; - *) AC_MSG_ERROR([Bad erl_xcomp_linux_nptl value: $erl_xcomp_linux_nptl]);; - esac - else - nptl=no - fi - AC_MSG_RESULT($nptl) - if test $nptl = cross; then - nptl=yes - AC_MSG_WARN([result yes guessed because of cross compilation]) - fi - if test $nptl = yes; then - THR_LIB_TYPE=posix_nptl - need_nptl_incldir=no - AC_CHECK_HEADER(nptl/pthread.h, - [need_nptl_incldir=yes - NEED_NPTL_PTHREAD_H=yes]) - if test $need_nptl_incldir = yes; then - # Ahh... - nptl_path="$C_INCLUDE_PATH:$CPATH" - if test X$cross_compiling != Xyes; then - nptl_path="$nptl_path:/usr/local/include:/usr/include" - else - IROOT="$erl_xcomp_isysroot" - test "$IROOT" != "" || IROOT="$erl_xcomp_sysroot" - test "$IROOT" != "" || AC_MSG_ERROR([Don't know where to search for includes! Please set erl_xcomp_isysroot]) - nptl_path="$nptl_path:$IROOT/usr/local/include:$IROOT/usr/include" - fi - nptl_ws_path= - save_ifs="$IFS"; IFS=":" - for dir in $nptl_path; do - if test "x$dir" != "x"; then - nptl_ws_path="$nptl_ws_path $dir" - fi - done - IFS=$save_ifs - nptl_incldir= - for dir in $nptl_ws_path; do - AC_CHECK_HEADER($dir/nptl/pthread.h, - nptl_incldir=$dir/nptl) - if test "x$nptl_incldir" != "x"; then - THR_DEFS="$THR_DEFS -isystem $nptl_incldir" - break - fi - done - if test "x$nptl_incldir" = "x"; then - AC_MSG_ERROR(Failed to locate nptl system include directory) - fi - fi - fi - ;; - *) ;; - esac - - dnl We sometimes need THR_DEFS in order to find certain headers - dnl (at least for pthread.h on osf1). - saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $THR_DEFS" - - dnl - dnl Check for headers - dnl - - AC_CHECK_HEADER(pthread.h, - AC_DEFINE(HAVE_PTHREAD_H, 1, \ -[Define if you have the header file.])) - - dnl Some Linuxes have instead of - AC_CHECK_HEADER(pthread/mit/pthread.h, \ - AC_DEFINE(HAVE_MIT_PTHREAD_H, 1, \ -[Define if the pthread.h header file is in pthread/mit directory.])) - - dnl restore CPPFLAGS - CPPFLAGS=$saved_cppflags - - fi -fi - -]) - -AC_DEFUN(ERL_INTERNAL_LIBS, -[ - -ERTS_INTERNAL_X_LIBS= - -AC_CHECK_LIB(kstat, kstat_open, -[AC_DEFINE(HAVE_KSTAT, 1, [Define if you have kstat]) -ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat"]) - -AC_SUBST(ERTS_INTERNAL_X_LIBS) - -]) - -AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OP__, -[ - # $1 - atomic_op - - for atomic_bit_size in 32 64 128; do - case $atomic_bit_size in - 32) gcc_atomic_type="$gcc_atomic_type32";; - 64) gcc_atomic_type="$gcc_atomic_type64";; - 128) gcc_atomic_type="$gcc_atomic_type128";; - esac - gcc_atomic_lockfree="int x[[(2*__atomic_always_lock_free(sizeof($gcc_atomic_type), 0))-1]]" - case $1 in - __sync_add_and_fetch | __sync_fetch_and_and | __sync_fetch_and_or) - atomic_call="volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0);" - ;; - __sync_val_compare_and_swap) - atomic_call="volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0, ($gcc_atomic_type) 0);" - ;; - __atomic_store_n) - atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELAXED); $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELEASE);" - ;; - __atomic_load_n) - atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, __ATOMIC_RELAXED); res = $1(&var, __ATOMIC_ACQUIRE);" - ;; - __atomic_add_fetch| __atomic_fetch_and | __atomic_fetch_or) - atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELAXED); res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_ACQUIRE); res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELEASE);" - ;; - __atomic_compare_exchange_n) - atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type val; int res = $1(&var, &val, ($gcc_atomic_type) 0, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); res = $1(&var, &val, ($gcc_atomic_type) 0, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);" - ;; - *) - AC_MSG_ERROR([Internal error: missing implementation for $1]) - ;; - esac - eval atomic${atomic_bit_size}_call=\"$atomic_call\" - done - - AC_CACHE_CHECK([for 32-bit $1()], ethr_cv_32bit_$1, - [ - ethr_cv_32bit_$1=no - AC_TRY_LINK([], [$atomic32_call], [ethr_cv_32bit_$1=yes]) - ]) - AC_CACHE_CHECK([for 64-bit $1()], ethr_cv_64bit_$1, - [ - ethr_cv_64bit_$1=no - AC_TRY_LINK([], [$atomic64_call], [ethr_cv_64bit_$1=yes]) - ]) - AC_CACHE_CHECK([for 128-bit $1()], ethr_cv_128bit_$1, - [ - ethr_cv_128bit_$1=no - AC_TRY_LINK([], [$atomic128_call], [ethr_cv_128bit_$1=yes]) - ]) - - case $ethr_cv_128bit_$1-$ethr_cv_64bit_$1-$ethr_cv_32bit_$1 in - no-no-no) - have_atomic_ops=0;; - no-no-yes) - have_atomic_ops=4;; - no-yes-no) - have_atomic_ops=8;; - no-yes-yes) - have_atomic_ops=12;; - yes-no-no) - have_atomic_ops=16;; - yes-no-yes) - have_atomic_ops=20;; - yes-yes-no) - have_atomic_ops=24;; - yes-yes-yes) - have_atomic_ops=28;; - esac - AC_DEFINE_UNQUOTED([ETHR_HAVE_$1], [$have_atomic_ops], [Define as a bitmask corresponding to the word sizes that $1() can handle on your system]) -]) - -AC_DEFUN(ETHR_CHK_IF_NOOP, -[ - ethr_test_filename="chk_if_$1$3_noop_config1test.$$" - cat > "${ethr_test_filename}.c" < "${ethr_test_filename}.c" </dev/null 2>&1; then - ethr_$1$3_noop=yes - else - ethr_$1$3_noop=no - fi - rm -f "${ethr_test_filename}.c" "${ethr_test_filename}1.o" "${ethr_test_filename}2.o" -]) - -AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OPS, -[ - AC_CHECK_SIZEOF(short) - AC_CHECK_SIZEOF(int) - AC_CHECK_SIZEOF(long) - AC_CHECK_SIZEOF(long long) - AC_CHECK_SIZEOF(__int128_t) - - if test "$ac_cv_sizeof_short" = "4"; then - gcc_atomic_type32="short" - elif test "$ac_cv_sizeof_int" = "4"; then - gcc_atomic_type32="int" - elif test "$ac_cv_sizeof_long" = "4"; then - gcc_atomic_type32="long" - else - AC_MSG_ERROR([No 32-bit type found]) - fi - - if test "$ac_cv_sizeof_int" = "8"; then - gcc_atomic_type64="int" - elif test "$ac_cv_sizeof_long" = "8"; then - gcc_atomic_type64="long" - elif test "$ac_cv_sizeof_long_long" = "8"; then - gcc_atomic_type64="long long" - else - AC_MSG_ERROR([No 64-bit type found]) - fi - - if test "$ac_cv_sizeof___int128_t" = "16"; then - gcc_atomic_type128="__int128_t" - else - gcc_atomic_type128="#error " - fi - AC_CACHE_CHECK([for a working __sync_synchronize()], ethr_cv___sync_synchronize, - [ - ethr_cv___sync_synchronize=no - AC_TRY_LINK([], - [ __sync_synchronize(); ], - [ethr_cv___sync_synchronize=yes]) - if test $ethr_cv___sync_synchronize = yes; then - # - # Old gcc versions on at least x86 have a buggy - # __sync_synchronize() which does not emit a - # memory barrier. We try to detect this by - # compiling to assembly with and without - # __sync_synchronize() and compare the results. - # - ETHR_CHK_IF_NOOP(__sync_synchronize, [()], []) - if test $ethr___sync_synchronize_noop = yes; then - # Got a buggy implementation of - # __sync_synchronize... - ethr_cv___sync_synchronize="no; buggy implementation" - fi - fi - ]) - - if test "$ethr_cv___sync_synchronize" = "yes"; then - have_sync_synchronize_value="~0" - else - have_sync_synchronize_value="0" - fi - AC_DEFINE_UNQUOTED([ETHR_HAVE___sync_synchronize], [$have_sync_synchronize_value], [Define as a bitmask corresponding to the word sizes that __sync_synchronize() can handle on your system]) - - ETHR_CHK_GCC_ATOMIC_OP__(__sync_add_and_fetch) - ETHR_CHK_GCC_ATOMIC_OP__(__sync_fetch_and_and) - ETHR_CHK_GCC_ATOMIC_OP__(__sync_fetch_and_or) - ETHR_CHK_GCC_ATOMIC_OP__(__sync_val_compare_and_swap) - - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_store_n) - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_load_n) - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_add_fetch) - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_fetch_and) - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_fetch_or) - ETHR_CHK_GCC_ATOMIC_OP__(__atomic_compare_exchange_n) - - ethr_have_gcc_native_atomics=no - ethr_arm_dbm_sy_instr_val=0 - ethr_arm_dbm_st_instr_val=0 - ethr_arm_dbm_ld_instr_val=0 - case "$GCC-$host_cpu" in - yes-arm*|yes-aarch*) - AC_CACHE_CHECK([for ARM 'dmb sy' instruction], ethr_cv_arm_dbm_sy_instr, - [ - ethr_cv_arm_dbm_sy_instr=no - AC_TRY_LINK([], - [ - __asm__ __volatile__("dmb sy" : : : "memory"); - ], - [ethr_cv_arm_dbm_sy_instr=yes]) - ]) - if test $ethr_cv_arm_dbm_sy_instr = yes; then - ethr_arm_dbm_sy_instr_val=1 - test $ethr_cv_64bit___atomic_compare_exchange_n = yes && - ethr_have_gcc_native_atomics=yes - fi - AC_CACHE_CHECK([for ARM 'dmb st' instruction], ethr_cv_arm_dbm_st_instr, - [ - ethr_cv_arm_dbm_st_instr=no - AC_TRY_LINK([], - [ - __asm__ __volatile__("dmb st" : : : "memory"); - ], - [ethr_cv_arm_dbm_st_instr=yes]) - ]) - if test $ethr_cv_arm_dbm_st_instr = yes; then - ethr_arm_dbm_st_instr_val=1 - fi - AC_CACHE_CHECK([for ARM 'dmb ld' instruction], ethr_cv_arm_dbm_ld_instr, - [ - ethr_cv_arm_dbm_ld_instr=no - AC_TRY_LINK([], - [ - __asm__ __volatile__("dmb ld" : : : "memory"); - ], - [ethr_cv_arm_dbm_ld_instr=yes]) - ]) - if test $ethr_cv_arm_dbm_ld_instr = yes; then - ethr_arm_dbm_ld_instr_val=1 - fi;; - *) - ;; - esac - AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_INSTRUCTION], [$ethr_arm_dbm_sy_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb sy' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) - AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION], [$ethr_arm_dbm_st_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb st' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) - AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_LD_INSTRUCTION], [$ethr_arm_dbm_ld_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb ld' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) - test $ethr_cv_32bit___sync_val_compare_and_swap = yes && - ethr_have_gcc_native_atomics=yes - test $ethr_cv_64bit___sync_val_compare_and_swap = yes && - ethr_have_gcc_native_atomics=yes - if test "$ethr_cv___sync_synchronize" = "yes"; then - test $ethr_cv_64bit___atomic_compare_exchange_n = yes && - ethr_have_gcc_native_atomics=yes - test $ethr_cv_32bit___atomic_compare_exchange_n = yes && - ethr_have_gcc_native_atomics=yes - fi - ethr_have_gcc_atomic_builtins=0 - if test $ethr_have_gcc_native_atomics = yes; then - ethr_native_atomic_implementation=gcc_sync - test $ethr_cv_32bit___atomic_compare_exchange_n = yes && ethr_have_gcc_atomic_builtins=1 - test $ethr_cv_64bit___atomic_compare_exchange_n = yes && ethr_have_gcc_atomic_builtins=1 - test $ethr_have_gcc_atomic_builtins = 1 && ethr_native_atomic_implementation=gcc_atomic_sync - fi - AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC___ATOMIC_BUILTINS], [$ethr_have_gcc_atomic_builtins], [Define as a boolean indicating whether you have a gcc __atomic builtins or not]) - test $ethr_have_gcc_native_atomics = yes && ethr_have_native_atomics=yes -]) - -AC_DEFUN(ETHR_CHK_INTERLOCKED, -[ - ilckd="$1" - AC_MSG_CHECKING([for ${ilckd}()]) - case "$2" in - "1") ilckd_call="${ilckd}(var);";; - "2") ilckd_call="${ilckd}(var, ($3) 0);";; - "3") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0);";; - "4") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0, arr);";; - esac - have_interlocked_op=no - AC_TRY_LINK( - [ - #define WIN32_LEAN_AND_MEAN - #include - #include - ], - [ - volatile $3 *var; - volatile $3 arr[2]; - - $ilckd_call - return 0; - ], - [have_interlocked_op=yes]) - test $have_interlocked_op = yes && $4 - AC_MSG_RESULT([$have_interlocked_op]) -]) - -dnl ---------------------------------------------------------------------- -dnl -dnl ERL_FIND_ETHR_LIB -dnl -dnl NOTE! This macro may be changed at any time! Should *only* be used by -dnl ERTS! -dnl -dnl Find a thread library to use. Sets ETHR_LIBS to libraries to link -dnl with, ETHR_X_LIBS to extra libraries to link with (same as ETHR_LIBS -dnl except that the ethread lib itself is not included), ETHR_DEFS to -dnl defines to compile with, ETHR_THR_LIB_BASE to the name of the -dnl thread library which the ethread library is based on, and ETHR_LIB_NAME -dnl to the name of the library where the ethread implementation is located. -dnl ERL_FIND_ETHR_LIB currently searches for 'pthreads', and -dnl 'win32_threads'. If no thread library was found ETHR_LIBS, ETHR_X_LIBS, -dnl ETHR_DEFS, ETHR_THR_LIB_BASE, and ETHR_LIB_NAME are all set to the -dnl empty string. -dnl - -AC_DEFUN(ERL_FIND_ETHR_LIB, -[ - -AC_ARG_ENABLE(native-ethr-impls, - AS_HELP_STRING([--disable-native-ethr-impls], - [disable native ethread implementations]), -[ case "$enableval" in - no) disable_native_ethr_impls=yes ;; - *) disable_native_ethr_impls=no ;; - esac ], disable_native_ethr_impls=no) - -test "X$disable_native_ethr_impls" = "Xyes" && - AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations]) - -AC_ARG_ENABLE(x86-out-of-order, - AS_HELP_STRING([--enable-x86-out-of-order], - [enable x86/x84_64 out of order support (default disabled)])) - -AC_ARG_ENABLE(prefer-gcc-native-ethr-impls, - AS_HELP_STRING([--enable-prefer-gcc-native-ethr-impls], - [prefer gcc native ethread implementations]), -[ case "$enableval" in - yes) enable_prefer_gcc_native_ethr_impls=yes ;; - *) enable_prefer_gcc_native_ethr_impls=no ;; - esac ], enable_prefer_gcc_native_ethr_impls=no) - -test $enable_prefer_gcc_native_ethr_impls = yes && - AC_DEFINE(ETHR_PREFER_GCC_NATIVE_IMPLS, 1, [Define if you prefer gcc native ethread implementations]) - -AC_ARG_ENABLE(trust-gcc-atomic-builtins-memory-barriers, - AS_HELP_STRING([--enable-trust-gcc-atomic-builtins-memory-barriers], - [trust gcc atomic builtins memory barriers]), -[ case "$enableval" in - yes) trust_gcc_atomic_builtins_mbs=1 ;; - *) trust_gcc_atomic_builtins_mbs=0 ;; - esac ], trust_gcc_atomic_builtins_mbs=0) - -AC_DEFINE_UNQUOTED(ETHR_TRUST_GCC_ATOMIC_BUILTINS_MEMORY_BARRIERS, [$trust_gcc_atomic_builtins_mbs], [Define as a boolean indicating whether you trust gcc's __atomic_* builtins memory barrier implementations, or not]) - -AC_ARG_WITH(libatomic_ops, - AS_HELP_STRING([--with-libatomic_ops=PATH], - [specify and prefer usage of libatomic_ops in the ethread library])) - -AC_ARG_WITH(with_sparc_memory_order, - AS_HELP_STRING([--with-sparc-memory-order=TSO|PSO|RMO], - [specify sparc memory order (defaults to RMO)])) - -AC_ARG_ENABLE(ppc-lwsync-instruction, -AS_HELP_STRING([--enable-ppc-lwsync-instruction], [enable use of powerpc lwsync instruction]) -AS_HELP_STRING([--disable-ppc-lwsync-instruction], [disable use of powerpc lwsync instruction]), -[ case "$enableval" in - no) enable_lwsync=no ;; - *) enable_lwsync=yes ;; - esac ], -[ - AC_CHECK_SIZEOF(void *) - case $host_cpu-$ac_cv_sizeof_void_p in - macppc-8|powerpc-8|ppc-8|powerpc64-8|ppc64-8|powerpc64le-8|ppc64le-8|"Power Macintosh"-8) - enable_lwsync=yes;; - *) - enable_lwsync=undefined;; - esac ]) - -case $enable_lwsync in - no) - AC_DEFINE(ETHR_PPC_HAVE_NO_LWSYNC, [1], [Define if you do not have the powerpc lwsync instruction]) - ;; - yes) - AC_DEFINE(ETHR_PPC_HAVE_LWSYNC, [1], [Define if you have the powerpc lwsync instruction]) - ;; - *) - ;; -esac - -LM_CHECK_THR_LIB -ERL_INTERNAL_LIBS - -ERL_MONOTONIC_CLOCK(try_find_pthread_compatible, CLOCK_HIGHRES CLOCK_UPTIME_RAW CLOCK_MONOTONIC, no) - -case $erl_monotonic_clock_func in - clock_gettime) - AC_DEFINE(ETHR_HAVE_CLOCK_GETTIME_MONOTONIC, [1], [Define if you have a clock_gettime() with a monotonic clock]) - ;; - mach_clock_get_time) - AC_DEFINE(ETHR_HAVE_MACH_CLOCK_GET_TIME, [1], [Define if you have a mach clock_get_time() with a monotonic clock]) - ;; - gethrtime) - AC_DEFINE(ETHR_HAVE_GETHRTIME, [1], [Define if you have a monotonic gethrtime()]) - ;; - *) - ;; -esac - -if test "x$erl_monotonic_clock_id" != "x"; then - AC_DEFINE_UNQUOTED(ETHR_MONOTONIC_CLOCK_ID, [$erl_monotonic_clock_id], [Define to the monotonic clock id to use]) -fi - -ethr_native_atomic_implementation=none -ethr_have_native_atomics=no -ethr_have_native_spinlock=no -ETHR_THR_LIB_BASE="$THR_LIB_NAME" -ETHR_THR_LIB_BASE_TYPE="$THR_LIB_TYPE" -ETHR_DEFS="$THR_DEFS" -ETHR_X_LIBS="$THR_LIBS $ERTS_INTERNAL_X_LIBS $erl_monotonic_clock_lib" -ETHR_LIBS= -ETHR_LIB_NAME= - -ethr_modified_default_stack_size= - -AC_ARG_WITH(threadnames, -AS_HELP_STRING([--with-threadnames], [use pthread_setname to set the thread names (default)]) -AS_HELP_STRING([--without-threadnames], - [do not set any thread names]), -[], -[with_threadnames=yes]) - -dnl Name of lib where ethread implementation is located -ethr_lib_name=ethread - -case "$THR_LIB_NAME" in - - win32_threads) - ETHR_THR_LIB_BASE_DIR=win - # * _WIN32_WINNT >= 0x0400 is needed for - # TryEnterCriticalSection - # * _WIN32_WINNT >= 0x0403 is needed for - # InitializeCriticalSectionAndSpinCount - # The ethread lib will refuse to build if _WIN32_WINNT < 0x0403. - # - # -D_WIN32_WINNT should have been defined in $CPPFLAGS; fetch it - # and save it in ETHR_DEFS. - found_win32_winnt=no - for cppflag in $CPPFLAGS; do - case $cppflag in - -DWINVER*) - ETHR_DEFS="$ETHR_DEFS $cppflag" - ;; - -D_WIN32_WINNT*) - ETHR_DEFS="$ETHR_DEFS $cppflag" - found_win32_winnt=yes - ;; - *) - ;; - esac - done - if test $found_win32_winnt = no; then - AC_MSG_ERROR([-D_WIN32_WINNT missing in CPPFLAGS]) - fi - - AC_DEFINE(ETHR_WIN32_THREADS, 1, [Define if you have win32 threads]) - - if test "X$disable_native_ethr_impls" = "Xyes"; then - have_interlocked_op=no - ethr_have_native_atomics=no - else - ETHR_CHK_INTERLOCKED([_InterlockedDecrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT, 1, [Define if you have _InterlockedDecrement()])) - ETHR_CHK_INTERLOCKED([_InterlockedDecrement_rel], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT_REL, 1, [Define if you have _InterlockedDecrement_rel()])) - ETHR_CHK_INTERLOCKED([_InterlockedIncrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT, 1, [Define if you have _InterlockedIncrement()])) - ETHR_CHK_INTERLOCKED([_InterlockedIncrement_acq], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT_ACQ, 1, [Define if you have _InterlockedIncrement_acq()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD, 1, [Define if you have _InterlockedExchangeAdd()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd_acq], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD_ACQ, 1, [Define if you have _InterlockedExchangeAdd_acq()])) - ETHR_CHK_INTERLOCKED([_InterlockedAnd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND, 1, [Define if you have _InterlockedAnd()])) - ETHR_CHK_INTERLOCKED([_InterlockedOr], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR, 1, [Define if you have _InterlockedOr()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchange], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE, 1, [Define if you have _InterlockedExchange()])) - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE, 1, [Define if you have _InterlockedCompareExchange()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_acq], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ, 1, [Define if you have _InterlockedCompareExchange_acq()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_rel], [3], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL, 1, [Define if you have _InterlockedCompareExchange_rel()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - - ETHR_CHK_INTERLOCKED([_InterlockedDecrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64, 1, [Define if you have _InterlockedDecrement64()])) - ETHR_CHK_INTERLOCKED([_InterlockedDecrement64_rel], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64_REL, 1, [Define if you have _InterlockedDecrement64_rel()])) - ETHR_CHK_INTERLOCKED([_InterlockedIncrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64, 1, [Define if you have _InterlockedIncrement64()])) - ETHR_CHK_INTERLOCKED([_InterlockedIncrement64_acq], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64_ACQ, 1, [Define if you have _InterlockedIncrement64_acq()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64, 1, [Define if you have _InterlockedExchangeAdd64()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64_acq], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ, 1, [Define if you have _InterlockedExchangeAdd64_acq()])) - ETHR_CHK_INTERLOCKED([_InterlockedAnd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND64, 1, [Define if you have _InterlockedAnd64()])) - ETHR_CHK_INTERLOCKED([_InterlockedOr64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR64, 1, [Define if you have _InterlockedOr64()])) - ETHR_CHK_INTERLOCKED([_InterlockedExchange64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE64, 1, [Define if you have _InterlockedExchange64()])) - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64, 1, [Define if you have _InterlockedCompareExchange64()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_acq], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ, 1, [Define if you have _InterlockedCompareExchange64_acq()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_rel], [3], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL, 1, [Define if you have _InterlockedCompareExchange64_rel()])) - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes - - ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange128], [4], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE128, 1, [Define if you have _InterlockedCompareExchange128()])) - fi - if test "$ethr_have_native_atomics" = "yes"; then - ethr_native_atomic_implementation=windows - ethr_have_native_spinlock=yes - fi - ;; - - pthread) - ETHR_THR_LIB_BASE_DIR=pthread - AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads]) - case $host_os in - openbsd*) - # The default stack size is insufficient for our needs - # on OpenBSD. We increase it to 256 kilo words. - ethr_modified_default_stack_size=256;; - linux*) - ETHR_DEFS="$ETHR_DEFS -D_GNU_SOURCE" - - if test X$cross_compiling = Xyes; then - case X$erl_xcomp_linux_usable_sigusrx in - X) usable_sigusrx=cross;; - Xyes|Xno) usable_sigusrx=$erl_xcomp_linux_usable_sigusrx;; - *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigusrx value: $erl_xcomp_linux_usable_sigusrx]);; - esac - case X$erl_xcomp_linux_usable_sigaltstack in - X) usable_sigaltstack=cross;; - Xyes|Xno) usable_sigaltstack=$erl_xcomp_linux_usable_sigaltstack;; - *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigaltstack value: $erl_xcomp_linux_usable_sigaltstack]);; - esac - else - # FIXME: Test for actual problems instead of kernel versions - linux_kernel_vsn_=`uname -r` - case $linux_kernel_vsn_ in - [[0-1]].*|2.[[0-1]]|2.[[0-1]].*) - usable_sigusrx=no - usable_sigaltstack=no;; - 2.[[2-3]]|2.[[2-3]].*) - usable_sigusrx=yes - usable_sigaltstack=no;; - *) - usable_sigusrx=yes - usable_sigaltstack=yes;; - esac - fi - - AC_MSG_CHECKING(if SIGUSR1 and SIGUSR2 can be used) - AC_MSG_RESULT($usable_sigusrx) - if test $usable_sigusrx = cross; then - usable_sigusrx=yes - AC_MSG_WARN([result yes guessed because of cross compilation]) - fi - if test $usable_sigusrx = no; then - ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGUSRX" - fi - - AC_MSG_CHECKING(if sigaltstack can be used) - AC_MSG_RESULT($usable_sigaltstack) - if test $usable_sigaltstack = cross; then - usable_sigaltstack=yes - AC_MSG_WARN([result yes guessed because of cross compilation]) - fi - if test $usable_sigaltstack = no; then - ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK" - fi - ;; - *) ;; - esac - - dnl We sometimes need ETHR_DEFS in order to find certain headers - dnl (at least for pthread.h on osf1). - saved_cppflags="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $ETHR_DEFS" - - dnl We need the thread library in order to find some functions - saved_libs="$LIBS" - LIBS="$LIBS $ETHR_X_LIBS" - - dnl - dnl Check for headers - dnl - AC_CHECK_HEADER(pthread.h, \ - AC_DEFINE(ETHR_HAVE_PTHREAD_H, 1, \ -[Define if you have the header file.])) - - dnl Some Linuxes have instead of - AC_CHECK_HEADER(pthread/mit/pthread.h, \ - AC_DEFINE(ETHR_HAVE_MIT_PTHREAD_H, 1, \ -[Define if the pthread.h header file is in pthread/mit directory.])) - - if test $NEED_NPTL_PTHREAD_H = yes; then - AC_DEFINE(ETHR_NEED_NPTL_PTHREAD_H, 1, \ -[Define if you need the header file.]) - fi - - AC_CHECK_HEADER(sched.h, \ - AC_DEFINE(ETHR_HAVE_SCHED_H, 1, \ -[Define if you have the header file.])) - - AC_CHECK_HEADER(sys/time.h, \ - AC_DEFINE(ETHR_HAVE_SYS_TIME_H, 1, \ -[Define if you have the header file.])) - - AC_TRY_COMPILE([#include - #include ], - [struct timeval *tv; return 0;], - AC_DEFINE(ETHR_TIME_WITH_SYS_TIME, 1, \ -[Define if you can safely include both and .])) - - AC_MSG_CHECKING([for usable PTHREAD_STACK_MIN]) - pthread_stack_min=no - AC_TRY_COMPILE([ -#include -#if defined(ETHR_NEED_NPTL_PTHREAD_H) -#include -#elif defined(ETHR_HAVE_MIT_PTHREAD_H) -#include -#elif defined(ETHR_HAVE_PTHREAD_H) -#include -#endif - ], - [return PTHREAD_STACK_MIN;], - [pthread_stack_min=yes]) - - AC_MSG_RESULT([$pthread_stack_min]) - test $pthread_stack_min != yes || { - AC_DEFINE(ETHR_HAVE_USABLE_PTHREAD_STACK_MIN, 1, [Define if you can use PTHREAD_STACK_MIN]) - } - - dnl - dnl Check for functions - dnl - AC_CHECK_FUNC(pthread_spin_lock, \ - [ethr_have_native_spinlock=yes \ - AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \ -[Define if you have the pthread_spin_lock function.])]) - - have_sched_yield=no - have_librt_sched_yield=no - AC_CHECK_FUNC(sched_yield, [have_sched_yield=yes]) - if test $have_sched_yield = no; then - AC_CHECK_LIB(rt, sched_yield, - [have_librt_sched_yield=yes - ETHR_X_LIBS="$ETHR_X_LIBS -lrt"]) - fi - if test $have_sched_yield = yes || test $have_librt_sched_yield = yes; then - AC_DEFINE(ETHR_HAVE_SCHED_YIELD, 1, [Define if you have the sched_yield() function.]) - AC_MSG_CHECKING([whether sched_yield() returns an int]) - sched_yield_ret_int=no - AC_TRY_LINK([ - #ifdef ETHR_HAVE_SCHED_H - #include - #endif - ], - [int sched_yield();], - [sched_yield_ret_int=yes]) - AC_MSG_RESULT([$sched_yield_ret_int]) - if test $sched_yield_ret_int = yes; then - AC_DEFINE(ETHR_SCHED_YIELD_RET_INT, 1, [Define if sched_yield() returns an int.]) - fi - fi - - have_pthread_yield=no - AC_CHECK_FUNC(pthread_yield, [have_pthread_yield=yes]) - if test $have_pthread_yield = yes; then - AC_DEFINE(ETHR_HAVE_PTHREAD_YIELD, 1, [Define if you have the pthread_yield() function.]) - AC_MSG_CHECKING([whether pthread_yield() returns an int]) - pthread_yield_ret_int=no - AC_TRY_LINK([ - #if defined(ETHR_NEED_NPTL_PTHREAD_H) - #include - #elif defined(ETHR_HAVE_MIT_PTHREAD_H) - #include - #elif defined(ETHR_HAVE_PTHREAD_H) - #include - #endif - ], - [int pthread_yield();], - [pthread_yield_ret_int=yes]) - AC_MSG_RESULT([$pthread_yield_ret_int]) - if test $pthread_yield_ret_int = yes; then - AC_DEFINE(ETHR_PTHREAD_YIELD_RET_INT, 1, [Define if pthread_yield() returns an int.]) - fi - fi - - have_pthread_rwlock_init=no - AC_CHECK_FUNC(pthread_rwlock_init, [have_pthread_rwlock_init=yes]) - if test $have_pthread_rwlock_init = yes; then - - ethr_have_pthread_rwlockattr_setkind_np=no - AC_CHECK_FUNC(pthread_rwlockattr_setkind_np, - [ethr_have_pthread_rwlockattr_setkind_np=yes]) - - if test $ethr_have_pthread_rwlockattr_setkind_np = yes; then - AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP, 1, \ -[Define if you have the pthread_rwlockattr_setkind_np() function.]) - - AC_MSG_CHECKING([for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP]) - ethr_pthread_rwlock_writer_nonrecursive_initializer_np=no - AC_TRY_LINK([ - #if defined(ETHR_NEED_NPTL_PTHREAD_H) - #include - #elif defined(ETHR_HAVE_MIT_PTHREAD_H) - #include - #elif defined(ETHR_HAVE_PTHREAD_H) - #include - #endif - ], - [ - pthread_rwlockattr_t *attr; - return pthread_rwlockattr_setkind_np(attr, - PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); - ], - [ethr_pthread_rwlock_writer_nonrecursive_initializer_np=yes]) - AC_MSG_RESULT([$ethr_pthread_rwlock_writer_nonrecursive_initializer_np]) - if test $ethr_pthread_rwlock_writer_nonrecursive_initializer_np = yes; then - AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 1, \ -[Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock attribute.]) - fi - fi - fi - - if test "$force_pthread_rwlocks" = "yes"; then - - AC_DEFINE(ETHR_FORCE_PTHREAD_RWLOCK, 1, \ -[Define if you want to force usage of pthread rwlocks]) - - if test $have_pthread_rwlock_init = yes; then - AC_MSG_WARN([Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues.]) - else - AC_MSG_ERROR([User forced usage of pthread rwlock, but no such implementation was found]) - fi - fi - - AC_CHECK_FUNC(pthread_attr_setguardsize, \ - AC_DEFINE(ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE, 1, \ -[Define if you have the pthread_attr_setguardsize function.])) - - if test "x$erl_monotonic_clock_id" != "x"; then - AC_MSG_CHECKING(whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout) - pthread_cond_timedwait_monotonic=no - AC_TRY_LINK([ - #if defined(ETHR_NEED_NPTL_PTHREAD_H) - # include - #elif defined(ETHR_HAVE_MIT_PTHREAD_H) - # include - #elif defined(ETHR_HAVE_PTHREAD_H) - # include - #endif - #ifdef ETHR_TIME_WITH_SYS_TIME - # include - # include - #else - # ifdef ETHR_HAVE_SYS_TIME_H - # include - # else - # include - # endif - #endif - #if defined(ETHR_HAVE_MACH_CLOCK_GET_TIME) - # include - # include - #endif - ], - [ - int res; - pthread_condattr_t attr; - pthread_cond_t cond; - struct timespec cond_timeout; - pthread_mutex_t mutex; - res = pthread_condattr_init(&attr); - res = pthread_condattr_setclock(&attr, ETHR_MONOTONIC_CLOCK_ID); - res = pthread_cond_init(&cond, &attr); - res = pthread_cond_timedwait(&cond, &mutex, &cond_timeout); - ], - [pthread_cond_timedwait_monotonic=yes]) - AC_MSG_RESULT([$pthread_cond_timedwait_monotonic]) - if test $pthread_cond_timedwait_monotonic = yes; then - AC_DEFINE(ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC, [1], [Define if pthread_cond_timedwait() can be used with a monotonic clock]) - fi - fi - - linux_futex=no - AC_MSG_CHECKING([for Linux futexes]) - AC_TRY_LINK([ - #include - #include - #include - #include - ], - [ - int i = 1; - syscall(__NR_futex, (void *) &i, FUTEX_WAKE, 1, - (void*)0,(void*)0, 0); - syscall(__NR_futex, (void *) &i, FUTEX_WAIT, 0, - (void*)0,(void*)0, 0); - return 0; - ], - linux_futex=yes) - AC_MSG_RESULT([$linux_futex]) - test $linux_futex = yes && AC_DEFINE(ETHR_HAVE_LINUX_FUTEX, 1, [Define if you have a linux futex implementation.]) - - pthread_setname=no - AC_MSG_CHECKING([for pthread_setname_np]) - old_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" - AC_TRY_LINK([#define __USE_GNU - #include ], - [pthread_setname_np(pthread_self(), "name");], - pthread_setname=linux) - AC_TRY_LINK([#define __USE_GNU - #include ], - [pthread_set_name_np(pthread_self(), "name");], - pthread_setname=bsd) - AC_TRY_LINK([#define _DARWIN_C_SOURCE - #include ], - [pthread_setname_np("name");], - pthread_setname=darwin) - AC_MSG_RESULT([$pthread_setname]) - case $with_threadnames-$pthread_setname in - yes-linux) AC_DEFINE(ETHR_HAVE_PTHREAD_SETNAME_NP_2, 1, - [Define if you have linux style pthread_setname_np]);; - yes-bsd) AC_DEFINE(ETHR_HAVE_PTHREAD_SET_NAME_NP_2, 1, - [Define if you have bsd style pthread_set_name_np]);; - yes-darwin) AC_DEFINE(ETHR_HAVE_PTHREAD_SETNAME_NP_1, 1, - [Define if you have darwin style pthread_setname_np]);; - *) ;; - esac - - pthread_getname=no - AC_MSG_CHECKING([for pthread_getname_np]) - AC_TRY_LINK([#define __USE_GNU - #define _DARWIN_C_SOURCE - #include ], - [char buff[256]; pthread_getname_np(pthread_self(), buff, 256);], - pthread_getname=linux) - AC_TRY_LINK([#define __USE_GNU - #define _DARWIN_C_SOURCE - #include ], - [char buff[256]; pthread_getname_np(pthread_self(), buff);], - pthread_getname=ibm) - AC_MSG_RESULT([$pthread_getname]) - case $pthread_getname in - linux) AC_DEFINE(ETHR_HAVE_PTHREAD_GETNAME_NP_3, 1, - [Define if you have linux style pthread_getname_np]);; - ibm) AC_DEFINE(ETHR_HAVE_PTHREAD_GETNAME_NP_2, 1, - [Define if you have ibm style pthread_getname_np]);; - *) ;; - esac - CFLAGS=$old_CFLAGS - - if test "X$disable_native_ethr_impls" = "Xyes"; then - ethr_have_native_atomics=no - else - - ETHR_CHK_GCC_ATOMIC_OPS([]) - - AC_MSG_CHECKING([for a usable libatomic_ops implementation]) - case "x$with_libatomic_ops" in - xno | xyes | x) - libatomic_ops_include= - ;; - *) - if test -d "${with_libatomic_ops}/include"; then - libatomic_ops_include="-I$with_libatomic_ops/include" - CPPFLAGS="$CPPFLAGS $libatomic_ops_include" - else - AC_MSG_ERROR([libatomic_ops include directory $with_libatomic_ops/include not found]) - fi;; - esac - ethr_have_libatomic_ops=no - AC_TRY_LINK([#include "atomic_ops.h"], - [ - volatile AO_t x; - AO_t y; - int z; - - AO_nop_full(); -#if defined(AO_HAVE_store) - AO_store(&x, (AO_t) 0); -#elif defined(AO_HAVE_store_release) - AO_store_release(&x, (AO_t) 0); -#else -#error No store -#endif -#if defined(AO_HAVE_load) - z = AO_load(&x); -#elif defined(AO_HAVE_load_acquire) - z = AO_load_acquire(&x); -#else -#error No load -#endif -#if defined(AO_HAVE_compare_and_swap_full) - z = AO_compare_and_swap_full(&x, (AO_t) 0, (AO_t) 1); -#elif defined(AO_HAVE_compare_and_swap_release) - z = AO_compare_and_swap_release(&x, (AO_t) 0, (AO_t) 1); -#elif defined(AO_HAVE_compare_and_swap_acquire) - z = AO_compare_and_swap_acquire(&x, (AO_t) 0, (AO_t) 1); -#elif defined(AO_HAVE_compare_and_swap) - z = AO_compare_and_swap(&x, (AO_t) 0, (AO_t) 1); -#else -#error No compare_and_swap -#endif - ], - [ethr_have_native_atomics=yes - ethr_native_atomic_implementation=libatomic_ops - ethr_have_libatomic_ops=yes]) - AC_MSG_RESULT([$ethr_have_libatomic_ops]) - if test $ethr_have_libatomic_ops = yes; then - AC_CHECK_SIZEOF(AO_t, , - [ - #include - #include "atomic_ops.h" - ]) - AC_DEFINE_UNQUOTED(ETHR_SIZEOF_AO_T, $ac_cv_sizeof_AO_t, [Define to the size of AO_t if libatomic_ops is used]) - - AC_DEFINE(ETHR_HAVE_LIBATOMIC_OPS, 1, [Define if you have libatomic_ops atomic operations]) - if test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then - AC_DEFINE(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS, 1, [Define if you prefer libatomic_ops native ethread implementations]) - fi - ETHR_DEFS="$ETHR_DEFS $libatomic_ops_include" - elif test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then - AC_MSG_ERROR([No usable libatomic_ops implementation found]) - fi - - case "$host_cpu" in - sparc | sun4u | sparc64 | sun4v) - case "$with_sparc_memory_order" in - "TSO") - AC_DEFINE(ETHR_SPARC_TSO, 1, [Define if only run in Sparc TSO mode]);; - "PSO") - AC_DEFINE(ETHR_SPARC_PSO, 1, [Define if only run in Sparc PSO, or TSO mode]);; - "RMO"|"") - AC_DEFINE(ETHR_SPARC_RMO, 1, [Define if run in Sparc RMO, PSO, or TSO mode]);; - *) - AC_MSG_ERROR([Unsupported Sparc memory order: $with_sparc_memory_order]);; - esac - ethr_native_atomic_implementation=ethread - ethr_have_native_atomics=yes;; - i86pc | i*86 | x86_64 | amd64) - if test "$enable_x86_out_of_order" = "yes"; then - AC_DEFINE(ETHR_X86_OUT_OF_ORDER, 1, [Define if x86/x86_64 out of order instructions should be synchronized]) - fi - ethr_native_atomic_implementation=ethread - ethr_have_native_atomics=yes;; - macppc | ppc | powerpc | "Power Macintosh") - ethr_native_atomic_implementation=ethread - ethr_have_native_atomics=yes;; - tile) - ethr_native_atomic_implementation=ethread - ethr_have_native_atomics=yes;; - *) - ;; - esac - - fi - - test ethr_have_native_atomics = "yes" && ethr_have_native_spinlock=yes - - dnl Restore LIBS - LIBS=$saved_libs - dnl restore CPPFLAGS - CPPFLAGS=$saved_cppflags - - ;; - *) - ;; -esac - -AC_MSG_CHECKING([whether default stack size should be modified]) -if test "x$ethr_modified_default_stack_size" != "x"; then - AC_DEFINE_UNQUOTED(ETHR_MODIFIED_DEFAULT_STACK_SIZE, $ethr_modified_default_stack_size, [Define if you want to modify the default stack size]) - AC_MSG_RESULT([yes; to $ethr_modified_default_stack_size kilo words]) -else - AC_MSG_RESULT([no]) -fi - -if test "x$ETHR_THR_LIB_BASE" != "x"; then - ETHR_DEFS="-DUSE_THREADS $ETHR_DEFS" - ETHR_LIBS="-l$ethr_lib_name -lerts_internal_r $ETHR_X_LIBS" - ETHR_LIB_NAME=$ethr_lib_name -fi - -AC_CHECK_SIZEOF(void *) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF_PTR, $ac_cv_sizeof_void_p, [Define to the size of pointers]) - -AC_CHECK_SIZEOF(int) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF_INT, $ac_cv_sizeof_int, [Define to the size of int]) -AC_CHECK_SIZEOF(long) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG, $ac_cv_sizeof_long, [Define to the size of long]) -AC_CHECK_SIZEOF(long long) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG_LONG, $ac_cv_sizeof_long_long, [Define to the size of long long]) -AC_CHECK_SIZEOF(__int64) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT64, $ac_cv_sizeof___int64, [Define to the size of __int64]) -AC_CHECK_SIZEOF(__int128_t) -AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT128_T, $ac_cv_sizeof___int128_t, [Define to the size of __int128_t]) - - -case X$erl_xcomp_bigendian in - X) ;; - Xyes|Xno) ac_cv_c_bigendian=$erl_xcomp_bigendian;; - *) AC_MSG_ERROR([Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian]);; -esac - -AC_C_BIGENDIAN - -if test "$ac_cv_c_bigendian" = "yes"; then - AC_DEFINE(ETHR_BIGENDIAN, 1, [Define if bigendian]) -fi - -case X$erl_xcomp_double_middle_endian in - X) ;; - Xyes|Xno|Xunknown) ac_cv_c_double_middle_endian=$erl_xcomp_double_middle_endian;; - *) AC_MSG_ERROR([Bad erl_xcomp_double_middle_endian value: $erl_xcomp_double_middle_endian]);; -esac - -AC_C_DOUBLE_MIDDLE_ENDIAN - -ETHR_X86_SSE2_ASM=no -case "$GCC-$ac_cv_sizeof_void_p-$host_cpu" in - yes-4-i86pc | yes-4-i*86 | yes-4-x86_64 | yes-4-amd64) - AC_MSG_CHECKING([for gcc sse2 asm support]) - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -msse2" - gcc_sse2_asm=no - AC_TRY_COMPILE([], - [ - long long x, *y; - __asm__ __volatile__("movq %1, %0\n\t" : "=x"(x) : "m"(*y) : "memory"); - ], - [gcc_sse2_asm=yes]) - CFLAGS="$save_CFLAGS" - AC_MSG_RESULT([$gcc_sse2_asm]) - if test "$gcc_sse2_asm" = "yes"; then - AC_DEFINE(ETHR_GCC_HAVE_SSE2_ASM_SUPPORT, 1, [Define if you use a gcc that supports -msse2 and understand sse2 specific asm statements]) - ETHR_X86_SSE2_ASM=yes - fi - ;; - *) - ;; -esac - -case "$GCC-$host_cpu" in - yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64) - - if test $ac_cv_sizeof_void_p = 4; then - dw_cmpxchg="cmpxchg8b" - else - dw_cmpxchg="cmpxchg16b" - fi - - gcc_dw_cmpxchg_asm=no - gcc_pic_dw_cmpxchg_asm=no - gcc_cflags_pic=no - gcc_cmpxchg8b_pic_no_clobber_ebx=no - gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=no - - save_CFLAGS="$CFLAGS" - - # Check if it works out of the box using passed CFLAGS - # and with -fPIC added to CFLAGS if the passed CFLAGS - # doesn't trigger position independent code - pic_cmpxchg=unknown - while true; do - - case $pic_cmpxchg in - yes) pic_text="pic ";; - *) pic_text="";; - esac - - AC_MSG_CHECKING([for gcc $pic_text$dw_cmpxchg plain asm support]) - - plain_cmpxchg=no - AC_TRY_COMPILE([], - [ - char xchgd; - long new[2], xchg[2], *p; - __asm__ __volatile__( -#if ETHR_SIZEOF_PTR == 4 - "lock; cmpxchg8b %0\n\t" -#else - "lock; cmpxchg16b %0\n\t" -#endif - "setz %3\n\t" - : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "b"(new[0]) - : "cc", "memory"); - ], - [plain_cmpxchg=yes]) - - AC_MSG_RESULT([$plain_cmpxchg]) - - if test $pic_cmpxchg = yes; then - gcc_pic_dw_cmpxchg_asm=$plain_cmpxchg - break - fi - - gcc_dw_cmpxchg_asm=$plain_cmpxchg - - # If not already compiling to position independent - # code add -fPIC to CFLAGS and do it again. This - # since we want also want to know how to compile - # to position independent code since this might - # cause problems with the use of the EBX register - # as input to the asm on 32-bit x86 and old gcc - # compilers (gcc vsn < 5). - - AC_TRY_COMPILE([], - [ -#if !defined(__PIC__) || !__PIC__ -# error no pic -#endif - ], - [pic_cmpxchg=yes - gcc_cflags_pic=yes], - [pic_cmpxchg=no]) - - if test $pic_cmpxchg = yes; then - gcc_pic_dw_cmpxchg_asm=$gcc_dw_cmpxchg_asm - break - fi - - CFLAGS="$save_CFLAGS -fPIC" - pic_cmpxchg=yes - - done - - if test $gcc_pic_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4; then - - AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX workaround]) - - # Check if we can work around it by managing the ebx - # register explicitly in the asm... - - AC_TRY_COMPILE([], - [ - char xchgd; - long new[2], xchg[2], *p; - __asm__ __volatile__( - "pushl %%ebx\n\t" - "movl %8, %%ebx\n\t" - "lock; cmpxchg8b %0\n\t" - "setz %3\n\t" - "popl %%ebx\n\t" - : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "r"(new[0]) - : "cc", "memory"); - ], - [gcc_pic_dw_cmpxchg_asm=yes - gcc_cmpxchg8b_pic_no_clobber_ebx=yes]) - - AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) - - if test $gcc_pic_dw_cmpxchg_asm = no; then - - AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds]) - # If no optimization is enabled we sometimes get a - # register shortage. Check if we can work around - # this... - - AC_TRY_COMPILE([], - [ - char xchgd; - long new[2], xchg[2], *p; - __asm__ __volatile__( - "pushl %%ebx\n\t" - "movl (%7), %%ebx\n\t" - "movl 4(%7), %%ecx\n\t" - "lock; cmpxchg8b %0\n\t" - "setz %3\n\t" - "popl %%ebx\n\t" - : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) - : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "r"(new) - : "cc", "memory"); - - ], - [gcc_pic_dw_cmpxchg_asm=yes - gcc_cmpxchg8b_pic_no_clobber_ebx=yes - gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=yes]) - - AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) - fi - - if test $gcc_cflags_pic = yes; then - gcc_dw_cmpxchg_asm=$gcc_pic_dw_cmpxchg_asm - fi - - fi - - CFLAGS="$save_CFLAGS" - - if test "$gcc_cmpxchg8b_pic_no_clobber_ebx" = "yes"; then - AC_DEFINE(ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX, 1, [Define if gcc wont let you clobber ebx with cmpxchg8b and position independent code]) - fi - if test "$gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage" = "yes"; then - AC_DEFINE(ETHR_CMPXCHG8B_REGISTER_SHORTAGE, 1, [Define if you get a register shortage with cmpxchg8b and position independent code]) - fi - if test "$gcc_dw_cmpxchg_asm" = "yes"; then - AC_DEFINE(ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT, 1, [Define if you use a gcc that supports the double word cmpxchg instruction]) - fi;; - *) - ;; -esac - -AC_DEFINE(ETHR_HAVE_ETHREAD_DEFINES, 1, \ -[Define if you have all ethread defines]) - -AC_SUBST(ETHR_X_LIBS) -AC_SUBST(ETHR_LIBS) -AC_SUBST(ETHR_LIB_NAME) -AC_SUBST(ETHR_DEFS) -AC_SUBST(ETHR_THR_LIB_BASE) -AC_SUBST(ETHR_THR_LIB_BASE_DIR) -AC_SUBST(ETHR_X86_SSE2_ASM) - -]) - - -dnl ---------------------------------------------------------------------- -dnl -dnl ERL_TIME_CORRECTION -dnl -dnl Check for primitives that can be used for implementing -dnl erts_os_monotonic_time() and erts_os_system_time() -dnl - -AC_DEFUN(ERL_TIME_CORRECTION, -[ - -AC_ARG_WITH(clock-resolution, -AS_HELP_STRING([--with-clock-resolution=high|low|default], - [specify wanted clock resolution])) - -AC_ARG_WITH(clock-gettime-realtime-id, -AS_HELP_STRING([--with-clock-gettime-realtime-id=CLOCKID], - [specify clock id to use with clock_gettime() for realtime time)])) - -AC_ARG_WITH(clock-gettime-monotonic-id, -AS_HELP_STRING([--with-clock-gettime-monotonic-id=CLOCKID], - [specify clock id to use with clock_gettime() for monotonic time)])) - -AC_ARG_ENABLE(prefer-elapsed-monotonic-time-during-suspend, -AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend], - [Prefer an OS monotonic time source with elapsed time during suspend]) -AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend], - [Do not prefer an OS monotonic time source with elapsed time during suspend]), -[ case "$enableval" in - yes) prefer_elapsed_monotonic_time_during_suspend=yes ;; - *) prefer_elapsed_monotonic_time_during_suspend=no ;; - esac ], prefer_elapsed_monotonic_time_during_suspend=no) - -AC_ARG_ENABLE(gettimeofday-as-os-system-time, - AS_HELP_STRING([--enable-gettimeofday-as-os-system-time], - [Force usage of gettimeofday() for OS system time]), -[ case "$enableval" in - yes) force_gettimeofday_os_system_time=yes ;; - *) force_gettimeofday_os_system_time=no ;; - esac ], force_gettimeofday_os_system_time=no) - -case "$with_clock_resolution" in - ""|no|yes) - with_clock_resolution=default;; - high|low|default) - ;; - *) - AC_MSG_ERROR([Invalid wanted clock resolution: $with_clock_resolution]) - ;; -esac - -if test "$force_gettimeofday_os_system_time" = "yes"; then - - AC_CHECK_FUNCS([gettimeofday]) - if test "$ac_cv_func_gettimeofday" = "yes"; then - AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()]) - else - AC_MSG_ERROR([No gettimeofday() available]) - fi - -else # $force_gettimeofday_os_system_time != yes - -case "$with_clock_gettime_realtime_id" in - ""|no) - with_clock_gettime_realtime_id=no - ;; - CLOCK_*CPUTIME*) - AC_MSG_ERROR([Invalid clock_gettime() realtime clock id: Refusing to use the cputime clock id $with_clock_gettime_realtime_id as realtime clock id]) - ;; - CLOCK_MONOTONIC*|CLOCK_BOOTTIME*|CLOCK_UPTIME*|CLOCK_HIGHRES*) - AC_MSG_ERROR([Invalid clock_gettime() realtime clock id: Refusing to use the monotonic clock id $with_clock_gettime_realtime_id as realtime clock id]) - ;; - CLOCK_*) - ;; - *) - AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_realtime_id]) - ;; -esac - -case "$with_clock_resolution-$with_clock_gettime_realtime_id" in - high-no) - ERL_WALL_CLOCK(high_resolution);; - low-no) - ERL_WALL_CLOCK(low_resolution);; - default-no) - ERL_WALL_CLOCK(default_resolution);; - *) - ERL_WALL_CLOCK(custom_resolution, $with_clock_gettime_realtime_id);; -esac - -case "$erl_wall_clock_func-$erl_wall_clock_id-$with_clock_gettime_realtime_id" in - *-*-no) - ;; - clock_gettime-$with_clock_gettime_realtime_id-$with_clock_gettime_realtime_id) - ;; - *) - AC_MSG_ERROR([$with_clock_gettime_realtime_id as clock id to clock_gettime() doesn't compile]) - ;; -esac - -case $erl_wall_clock_func in - none) - AC_MSG_ERROR([No wall clock source found]) - ;; - mach_clock_get_time) - AC_DEFINE(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_system_time() using mach clock_get_time()]) - ;; - clock_gettime) - AC_DEFINE(OS_SYSTEM_TIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_system_time() using clock_gettime()]) - ;; - gettimeofday) - AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()]) - ;; - *) - ;; -esac - -if test "x$erl_wall_clock_id" != "x"; then - AC_DEFINE_UNQUOTED(WALL_CLOCK_ID_STR, ["$erl_wall_clock_id"], [Define as a string of wall clock id to use]) - AC_DEFINE_UNQUOTED(WALL_CLOCK_ID, [$erl_wall_clock_id], [Define to wall clock id to use]) -fi - -fi # $force_gettimeofday_os_system_time != yes - -case "$with_clock_gettime_monotonic_id" in - ""|no) - with_clock_gettime_monotonic_id=no - ;; - CLOCK_*CPUTIME*) - AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) - ;; - CLOCK_REALTIME*|CLOCK_TAI*) - AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) - ;; - CLOCK_MONOTONIC) - case $host_os in - darwin*) - # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur - # and Monterey, since it may step backwards. - AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use $with_clock_gettime_monotonic_id as monotonic clock id since it is buggy on MacOS]);; - *) - ;; - esac;; - CLOCK_*) - ;; - *) - AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id]) - ;; -esac - -case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in - high-no) - ERL_MONOTONIC_CLOCK(high_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; - low-no) - ERL_MONOTONIC_CLOCK(low_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; - default-no) - ERL_MONOTONIC_CLOCK(default_resolution, undefined, $prefer_elapsed_monotonic_time_during_suspend);; - *) - ERL_MONOTONIC_CLOCK(custom_resolution, $with_clock_gettime_monotonic_id, $prefer_elapsed_monotonic_time_during_suspend);; -esac - -case "$erl_monotonic_clock_func-$erl_monotonic_clock_id-$with_clock_gettime_monotonic_id" in - *-*-no) - ;; - clock_gettime-$with_clock_gettime_monotonic_id-$with_clock_gettime_monotonic_id) - ;; - *) - AC_MSG_ERROR([$with_clock_gettime_monotonic_id as clock id to clock_gettime() doesn't compile]) - ;; -esac - -case $erl_monotonic_clock_func in - times) - AC_DEFINE(OS_MONOTONIC_TIME_USING_TIMES, [1], [Define if you want to implement erts_os_monotonic_time() using times()]) - ;; - mach_clock_get_time) - AC_DEFINE(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_monotonic_time() using mach clock_get_time()]) - ;; - clock_gettime) - AC_DEFINE(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_monotonic_time() using clock_gettime()]) - ;; - gethrtime) - AC_DEFINE(OS_MONOTONIC_TIME_USING_GETHRTIME, [1], [Define if you want to implement erts_os_monotonic_time() using gethrtime()]) - ;; - *) - ;; -esac - -if test $erl_corrected_monotonic_clock = yes; then - AC_DEFINE(ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME, [1], [Define if OS monotonic clock is corrected]) -fi - -if test $erl_monotonic_clock_low_resolution = yes; then - AC_DEFINE(ERTS_HAVE_LOW_RESOLUTION_OS_MONOTONIC_LOW, [1], [Define if you have a low resolution OS monotonic clock]) -fi - -xrtlib= -if test "$erl_monotonic_clock_lib" != ""; then - xrtlib="$erl_monotonic_clock_lib" -fi -if test "$erl_wall_clock_lib" != ""; then - xrtlib="$erl_wall_clock_lib" -fi -if test "x$erl_monotonic_clock_id" != "x"; then - AC_DEFINE_UNQUOTED(MONOTONIC_CLOCK_ID_STR, ["$erl_monotonic_clock_id"], [Define as a string of monotonic clock id to use]) - AC_DEFINE_UNQUOTED(MONOTONIC_CLOCK_ID, [$erl_monotonic_clock_id], [Define to monotonic clock id to use]) -fi - -if test $erl_cv_clock_gettime_monotonic_raw = yes; then - AC_DEFINE(HAVE_CLOCK_GETTIME_MONOTONIC_RAW, [1], [Define if you have clock_gettime(CLOCK_MONOTONIC_RAW, _)]) -fi - -ERL_MONOTONIC_CLOCK(high_resolution, undefined, no) - -case $erl_monotonic_clock_low_resolution-$erl_monotonic_clock_func in - no-mach_clock_get_time) - monotonic_hrtime=yes - AC_DEFINE(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_hrtime() using mach clock_get_time()]) - ;; - no-clock_gettime) - monotonic_hrtime=yes - AC_DEFINE(SYS_HRTIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_hrtime() using clock_gettime()]) - ;; - no-gethrtime) - monotonic_hrtime=yes - AC_DEFINE(SYS_HRTIME_USING_GETHRTIME, [1], [Define if you want to implement erts_os_hrtime() using gethrtime()]) - ;; - *) - monotonic_hrtime=no - ;; -esac - -if test $monotonic_hrtime = yes; then - AC_DEFINE(HAVE_MONOTONIC_ERTS_SYS_HRTIME, [1], [Define if you have a monotonic erts_os_hrtime() implementation]) -fi - -if test "x$erl_monotonic_clock_id" != "x"; then - AC_DEFINE_UNQUOTED(HRTIME_CLOCK_ID_STR, ["$erl_monotonic_clock_id"], [Define as a string of monotonic clock id to use]) - AC_DEFINE_UNQUOTED(HRTIME_CLOCK_ID, [$erl_monotonic_clock_id], [Define to monotonic clock id to use]) -fi - - -dnl -dnl Check if gethrvtime is working, and if to use procfs ioctl -dnl or (yet to be written) write to the procfs ctl file. -dnl - -AC_MSG_CHECKING([if gethrvtime works and how to use it]) -AC_TRY_RUN([ -/* gethrvtime procfs ioctl test */ -/* These need to be undef:ed to not break activation of - * micro level process accounting on /proc/self - */ -#ifdef _LARGEFILE_SOURCE -# undef _LARGEFILE_SOURCE -#endif -#ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main() { - long msacct = PR_MSACCT; - int fd; - long long start, stop; - int i; - pid_t pid = getpid(); - char proc_self[30] = "/proc/"; - - sprintf(proc_self+strlen(proc_self), "%lu", (unsigned long) pid); - if ( (fd = open(proc_self, O_WRONLY)) == -1) - exit(1); - if (ioctl(fd, PIOCSET, &msacct) < 0) - exit(2); - if (close(fd) < 0) - exit(3); - start = gethrvtime(); - for (i = 0; i < 100; i++) - stop = gethrvtime(); - if (start == 0) - exit(4); - if (start == stop) - exit(5); - exit(0); return 0; -} -], -erl_gethrvtime=procfs_ioctl, -erl_gethrvtime=false, -[ -case X$erl_xcomp_gethrvtime_procfs_ioctl in - X) - erl_gethrvtime=cross;; - Xyes|Xno) - if test $erl_xcomp_gethrvtime_procfs_ioctl = yes; then - erl_gethrvtime=procfs_ioctl - else - erl_gethrvtime=false - fi;; - *) - AC_MSG_ERROR([Bad erl_xcomp_gethrvtime_procfs_ioctl value: $erl_xcomp_gethrvtime_procfs_ioctl]);; -esac -]) - -LIBRT=$xrtlib -case $erl_gethrvtime in - procfs_ioctl) - AC_DEFINE(HAVE_GETHRVTIME_PROCFS_IOCTL,[1], - [define if gethrvtime() works and uses ioctl() to /proc/self]) - AC_MSG_RESULT(uses ioctl to procfs) - ;; - *) - if test $erl_gethrvtime = cross; then - erl_gethrvtime=false - AC_MSG_RESULT(cross) - AC_MSG_WARN([result 'not working' guessed because of cross compilation]) - else - AC_MSG_RESULT(not working) - fi - - dnl - dnl Check if clock_gettime (linux) is working - dnl - - AC_MSG_CHECKING([if clock_gettime can be used to get thread CPU time]) - save_libs=$LIBS - LIBS="-lrt" - AC_TRY_RUN([ - #include - #include - #include - #include - #include - int main() { - long long start, stop; - int i; - struct timespec tp; - - if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp) < 0) - exit(1); - start = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; - for (i = 0; i < 100; i++) - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp); - stop = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; - if (start == 0) - exit(4); - if (start == stop) - exit(5); - exit(0); return 0; - } - ], - erl_clock_gettime_cpu_time=yes, - erl_clock_gettime_cpu_time=no, - [ - case X$erl_xcomp_clock_gettime_cpu_time in - X) erl_clock_gettime_cpu_time=cross;; - Xyes|Xno) erl_clock_gettime_cpu_time=$erl_xcomp_clock_gettime_cpu_time;; - *) AC_MSG_ERROR([Bad erl_xcomp_clock_gettime_cpu_time value: $erl_xcomp_clock_gettime_cpu_time]);; - esac - ]) - LIBS=$save_libs - AC_MSG_RESULT($erl_clock_gettime_cpu_time) - case $erl_clock_gettime_cpu_time in - yes) - AC_DEFINE(HAVE_CLOCK_GETTIME_CPU_TIME,[], - [define if clock_gettime() works for getting thread time]) - LIBRT=-lrt - ;; - cross) - erl_clock_gettime_cpu_time=no - AC_MSG_WARN([result no guessed because of cross compilation]) - ;; - *) - ;; - esac - ;; -esac -AC_SUBST(LIBRT) -])dnl - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_TRY_ENABLE_CFLAG -dnl -dnl -dnl Tries a CFLAG and sees if it can be enabled without compiler errors -dnl $1: textual cflag to add -dnl $2: variable to store the modified CFLAG in -dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) -dnl -dnl -AC_DEFUN([LM_TRY_ENABLE_CFLAG], [ - AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)]) - saved_CFLAGS=$CFLAGS; - CFLAGS="$1 $$2"; - AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false) - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - AC_MSG_RESULT([yes]) - AS_VAR_SET($2, "$1 $$2") - else - AC_MSG_RESULT([no]) - fi -]) - -AC_DEFUN([LM_CHECK_ENABLE_CFLAG], [ - AC_MSG_CHECKING([whether $CC accepts $1...]) - saved_CFLAGS=$CFLAGS; - CFLAGS="$1 $CFLAGS"; - AC_TRY_COMPILE([],[return 0;],can_enable_flag=true,can_enable_flag=false) - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - AS_VAR_SET($2, true) - AC_MSG_RESULT([yes]) - else - AS_VAR_SET($2, false) - AC_MSG_RESULT([no]) - fi -]) - -dnl -dnl LM_CHECK_RUN_CFLAG -dnl -dnl As LM_CHECK_ENABLE_CFLAG but also runs the command. Required for testing -dnl profile-guided optimization, for which the "use" step may require that the -dnl binary created in the "generate" step runs. -dnl -AC_DEFUN([LM_CHECK_RUN_CFLAG], [ - AC_MSG_CHECKING([whether $CC accepts $1...]) - saved_CFLAGS=$CFLAGS; - CFLAGS="$1 $CFLAGS"; - AC_TRY_RUN([],[return 0;],can_enable_flag=true,can_enable_flag=false) - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - AS_VAR_SET($2, true) - AC_MSG_RESULT([yes]) - else - AS_VAR_SET($2, false) - AC_MSG_RESULT([no]) - fi -]) - -dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY -dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a -dnl AC_LANG_JAVA instead...) -AC_DEFUN(ERL_TRY_LINK_JAVA, -[java_link='$JAVAC conftest.java 1>&AC_FD_CC' -changequote(, )dnl -cat > conftest.java <&AC_FD_CC - cat conftest.java 1>&AC_FD_CC - echo "configure: PATH was $PATH" 1>&AC_FD_CC -ifelse([$4], , , [ rm -rf conftest* - $4 -])dnl -fi -rm -f conftest*]) -#define UNSAFE_MASK 0xc0000000 /* Mask for bits that must be constant */ - - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_HARDWARE_ARCH -dnl -dnl Determine target hardware in ARCH -dnl -AC_DEFUN([LM_HARDWARE_ARCH], [ - AC_MSG_CHECKING([target hardware architecture]) - if test "x$host_alias" != "x" -a "x$host_cpu" != "x"; then - chk_arch_=$host_cpu - else - chk_arch_=`uname -m` - fi - - case $chk_arch_ in - sun4u) ARCH=ultrasparc;; - sparc64) ARCH=sparc64;; - sun4v) ARCH=ultrasparc;; - i86pc) ARCH=x86;; - i386) ARCH=x86;; - i486) ARCH=x86;; - i586) ARCH=x86;; - i686) ARCH=x86;; - x86_64) ARCH=amd64;; - amd64) ARCH=amd64;; - macppc) ARCH=ppc;; - powerpc) ARCH=ppc;; - ppc) ARCH=ppc;; - ppc64) ARCH=ppc64;; - ppc64le) ARCH=ppc64le;; - powerpc64) ARCH=ppc64;; - powerpc64le) ARCH=ppc64le;; - "Power Macintosh") ARCH=ppc;; - arm64) ARCH=arm64;; - armv5b) ARCH=arm;; - armv5teb) ARCH=arm;; - armv5tel) ARCH=arm;; - armv5tejl) ARCH=arm;; - armv6l) ARCH=arm;; - armv6hl) ARCH=arm;; - armv7l) ARCH=arm;; - armv7hl) ARCH=arm;; - armv8*) ARCH=arm;; - aarch64) ARCH=arm64;; - aarch*) ARCH=arm;; - tile) ARCH=tile;; - e2k) ARCH=e2k;; - *) ARCH=noarch;; - esac - AC_MSG_RESULT($ARCH) - - dnl - dnl Convert between x86 and amd64 based on the compiler's mode. - dnl Ditto between ultrasparc and sparc64. - dnl - AC_MSG_CHECKING(whether compilation mode forces ARCH adjustment) - case "$ARCH-$ac_cv_sizeof_void_p" in - x86-8) - AC_MSG_RESULT(yes: adjusting ARCH=x86 to ARCH=amd64) - ARCH=amd64 - ;; - amd64-4) - AC_MSG_RESULT(yes: adjusting ARCH=amd64 to ARCH=x86) - ARCH=x86 - ;; - ultrasparc-8) - AC_MSG_RESULT(yes: adjusting ARCH=ultrasparc to ARCH=sparc64) - ARCH=sparc64 - ;; - sparc64-4) - AC_MSG_RESULT(yes: adjusting ARCH=sparc64 to ARCH=ultrasparc) - ARCH=ultrasparc - ;; - ppc64-4) - AC_MSG_RESULT(yes: adjusting ARCH=ppc64 to ARCH=ppc) - ARCH=ppc - ;; - ppc-8) - AC_MSG_RESULT(yes: adjusting ARCH=ppc to ARCH=ppc64) - ARCH=ppc64 - ;; - arm-8) - AC_MSG_RESULT(yes: adjusting ARCH=arm to ARCH=arm64) - ARCH=arm64 - ;; - *) - AC_MSG_RESULT(no: ARCH is $ARCH) - ;; - esac - - AC_SUBST(ARCH) -]) - -dnl -dnl-------------------------------------------------------------------- -dnl Dynamic Erlang Drivers -dnl -dnl Linking to produce dynamic Erlang drivers to be loaded by Erlang's -dnl Dynamic Driver Loader and Linker (DDLL). Below the prefix DED is an -dnl abbreviation for `Dynamic Erlang Driver'. -dnl -dnl For DED we need something quite sloppy, which allows undefined references -dnl (notably driver functions) in the resulting shared library. -dnl Example of Makefile rule (and settings of macros): -dnl -dnl LIBS = @LIBS@ -dnl LD = @DED_LD@ -dnl LDFLAGS = @DED_LDFLAGS@ -dnl soname = @ldsoname@ -dnl -dnl my_drv.so: my_drv.o my_utils.o -dnl $(LD) $(LDFLAGS) $(soname) $@ -o $@ $^ -lc $(LIBS) -dnl -dnl-------------------------------------------------------------------- -dnl - -AC_DEFUN(ERL_DED, - [ - -LM_CHECK_THR_LIB - -if test "$THR_DEFS" = ""; then - DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT" -else - DED_THR_DEFS="$THR_DEFS" -fi - -AC_SUBST(DED_THR_DEFS) - -ERL_DED_FLAGS - -]) - -AC_DEFUN(ERL_DED_FLAGS, - [ - -USER_LD=$LD -USER_LDFLAGS="$LDFLAGS" - -DED_CC=$CC -DED_GCC=$GCC - -DED_CFLAGS= -DED_OSTYPE=unix -case $host_os in - linux*) - DED_CFLAGS="-D_GNU_SOURCE" ;; - win32) - DED_CFLAGS="-D_WIN32_WINNT=0x0600 -DWINVER=0x0600" - DED_OSTYPE=win32 ;; - *) - ;; -esac - -DED_WARN_FLAGS="-Wall -Wstrict-prototypes" -case "$host_cpu" in - tile*) - # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, - # and too strict for our taste. - ;; - *) - DED_WARN_FLAGS="$DED_WARN_FLAGS -Wmissing-prototypes";; -esac - -LM_TRY_ENABLE_CFLAG([-Wdeclaration-after-statement], [DED_WARN_FLAGS]) - -LM_TRY_ENABLE_CFLAG([-Werror=return-type], [DED_WERRORFLAGS]) -LM_TRY_ENABLE_CFLAG([-Werror=implicit], [DED_WERRORFLAGS]) -LM_TRY_ENABLE_CFLAG([-Werror=undef], [DED_WERRORFLAGS]) - -DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$DED_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common" -DED_INCLUDE=$DED_SYS_INCLUDE - -DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS" -if test "x$GCC" = xyes; then - # Use -fno-common for gcc, that is link error if multiple definitions of - # global variables are encountered. This is ISO C compliant. - # Until version 10, gcc has had -fcommon as default, which allows and merges - # such dubious duplicates. - LM_TRY_ENABLE_CFLAG([-fno-common], [DED_CFLAGS]) - - DED_STATIC_CFLAGS="$DED_CFLAGS" - DED_CFLAGS="$DED_CFLAGS -fPIC" - # Remove -fPIE and -fno-PIE - DED_CFLAGS=`echo $DED_CFLAGS | sed 's/-f\(no-\)\?PIE//g'` -fi - -DED_EXT=so -case $host_os in - win32) DED_EXT=dll;; - darwin*) - DED_CFLAGS="$DED_CFLAGS -fno-common" - DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -fno-common";; - *) - ;; -esac - -DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER" - -if test "$CFLAG_RUNTIME_LIBRARY_PATH" = ""; then - - CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-R" - case $host_os in - darwin*) - CFLAG_RUNTIME_LIBRARY_PATH= - ;; - win32) - CFLAG_RUNTIME_LIBRARY_PATH= - ;; - osf*) - CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-rpath," - ;; - *) - ;; - esac - -fi - -# If DED_LD is set in environment, we expect all DED_LD* variables -# to be specified (cross compiling) -if test "x$DED_LD" = "x"; then - -DED_LDFLAGS_CONFTEST= - -DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-R" -case $host_os in - win32) - DED_LD="ld.sh" - DED_LDFLAGS="-dll" - DED_LD_FLAG_RUNTIME_LIBRARY_PATH= - ;; - solaris2*|sysv4*) - DED_LDFLAGS="-G" - if test X${enable_m64_build} = Xyes; then - DED_LDFLAGS="-64 $DED_LDFLAGS" - fi - ;; - aix*|os400*) - DED_LDFLAGS="-G -bnoentry -bexpall" - ;; - freebsd2*) - # Non-ELF GNU linker - DED_LDFLAGS="-Bshareable" - ;; - darwin*) - # Mach-O linker: a shared lib and a loadable object file is not the same thing. - - if test "X${ERL_DED_FLAT_BUNDLE}" = "Xtrue"; then - # EI sets this variable when building its .so file as beam.smp - # has not been built yet and any ei lib will not - # link to beam.smp anyways - DED_LDFLAGS="-bundle -flat_namespace -undefined suppress" - else - # Cannot use flat namespaces for drivers/nifs as that may cause - # symbols to collide during loading - DED_LDFLAGS="-bundle -bundle_loader ${ERL_TOP}/bin/$host/beam.smp" - fi - # DED_LDFLAGS_CONFTEST is for use in configure tests only. We - # cannot use DED_LDFLAGS in configure tests since beam.smp has not - # been built yet... - DED_LDFLAGS_CONFTEST="-bundle" - if test X${enable_m64_build} = Xyes; then - DED_LDFLAGS="-m64 $DED_LDFLAGS" - else - if test X${enable_m32_build} = Xyes; then - DED_LDFLAGS="-m32 $DED_LDFLAGS" - else - AC_CHECK_SIZEOF(void *) - case "$ac_cv_sizeof_void_p" in - 8) - DED_LDFLAGS="-m64 $DED_LDFLAGS";; - *) - ;; - esac - fi - fi - DED_LD="$CC" - DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" - ;; - linux*) - DED_LD="$CC" - DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" - DED_LDFLAGS="-shared -Wl,-Bsymbolic" - if test X${enable_m64_build} = Xyes; then - DED_LDFLAGS="-m64 $DED_LDFLAGS" - fi; - if test X${enable_m32_build} = Xyes; then - DED_LDFLAGS="-m32 $DED_LDFLAGS" - fi - ;; - freebsd*) - DED_LD="$CC" - DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" - DED_LDFLAGS="-shared" - if test X${enable_m64_build} = Xyes; then - DED_LDFLAGS="-m64 $DED_LDFLAGS" - fi; - if test X${enable_m32_build} = Xyes; then - DED_LDFLAGS="-m32 $DED_LDFLAGS" - fi - ;; - openbsd*) - DED_LD="$CC" - DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" - DED_LDFLAGS="-shared" - ;; - osf*) - # NOTE! Whitespace after -rpath is important. - DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath " - DED_LDFLAGS="-shared -expect_unresolved '*'" - ;; - *) - # assume GNU linker and ELF - DED_LDFLAGS="-shared" - # GNU linker has no option for 64bit build, should not propagate -m64 - ;; -esac - -if test "$DED_LD" = "" && test "$USER_LD" != ""; then - DED_LD="$USER_LD" - DED_LDFLAGS="$USER_LDFLAGS $DED_LDFLAGS" -fi - -DED_LIBS=$LIBS - -fi # "x$DED_LD" = "x" - -test "$DED_LDFLAGS_CONFTEST" != "" || DED_LDFLAGS_CONFTEST="$DED_LDFLAGS" - -AC_CHECK_TOOL(DED_LD, ld, false) -test "$DED_LD" != "false" || AC_MSG_ERROR([No linker found]) - -AC_MSG_CHECKING(for static compiler flags) -DED_STATIC_CFLAGS="$DED_WERRORFLAGS $DED_WFLAGS $DED_THR_DEFS $DED_STATIC_CFLAGS" -AC_MSG_RESULT([$DED_STATIC_CFLAGS]) -AC_MSG_CHECKING(for basic compiler flags for loadable drivers) -DED_BASIC_CFLAGS=$DED_CFLAGS -AC_MSG_RESULT([$DED_CFLAGS]) -AC_MSG_CHECKING(for compiler flags for loadable drivers) -DED_CFLAGS="$DED_WERRORFLAGS $DED_WARN_FLAGS $DED_THR_DEFS $DED_CFLAGS" -AC_MSG_RESULT([$DED_CFLAGS]) -AC_MSG_CHECKING(for linker for loadable drivers) -AC_MSG_RESULT([$DED_LD]) -AC_MSG_CHECKING(for linker flags for loadable drivers) -AC_MSG_RESULT([$DED_LDFLAGS]) -AC_MSG_CHECKING(for 'runtime library path' linker flag) -if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then - AC_MSG_RESULT([$DED_LD_FLAG_RUNTIME_LIBRARY_PATH]) -else - AC_MSG_RESULT([not found]) -fi - -AC_SUBST(DED_CC) -AC_SUBST(DED_GCC) -AC_SUBST(DED_EXT) -AC_SUBST(DED_SYS_INCLUDE) -AC_SUBST(DED_INCLUDE) -AC_SUBST(DED_BASIC_CFLAGS) -AC_SUBST(DED_CFLAGS) -AC_SUBST(DED_STATIC_CFLAGS) -AC_SUBST(DED_WARN_FLAGS) -AC_SUBST(DED_WERRORFLAGS) -AC_SUBST(DED_LD) -AC_SUBST(DED_LDFLAGS) -AC_SUBST(DED_LD_FLAG_RUNTIME_LIBRARY_PATH) -AC_SUBST(DED_LIBS) -AC_SUBST(DED_OSTYPE) - -]) diff --git a/erts/autoconf/README.md b/erts/autoconf/README.md new file mode 100644 index 000000000000..4643e61f496a --- /dev/null +++ b/erts/autoconf/README.md @@ -0,0 +1,10 @@ +All files in this directory except for the README.md files are copies +of primary files located in the `$ERL_TOP/make/autoconf` directory. +Files in this directory are updated automatically when executing +`$ERL_TOP/otp_build update_configure [--no-commit]`. + +The files in this directory are only kept here in order not to break +external scripts that might depend on them being here. You typically +want to use the files in the `$ERL_TOP/make/autoconf` directory and +*not* the ones in this directory. The files in this directory will +eventually be removed. diff --git a/erts/autoconf/win32.config.cache.static b/erts/autoconf/win32.config.cache.static deleted file mode 100755 index b3328e541444..000000000000 --- a/erts/autoconf/win32.config.cache.static +++ /dev/null @@ -1,229 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -ac_cv_c_bigendian=${ac_cv_c_bigendian=no} -ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=no} -ac_cv_c_const=${ac_cv_c_const=yes} -ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=no} -ac_cv_decl_h_errno=${ac_cv_decl_h_errno=no} -ac_cv_decl_inaddr_loopback=${ac_cv_decl_inaddr_loopback=no} -ac_cv_decl_inaddr_loopback_rpc=${ac_cv_decl_inaddr_loopback_rpc=no} -ac_cv_decl_inaddr_loopback_winsock2=${ac_cv_decl_inaddr_loopback_winsock2=yes} -ac_cv_decl_so_bsdcompat=${ac_cv_decl_so_bsdcompat=no} -ac_cv_decl_sys_errlist=${ac_cv_decl_sys_errlist=no} -ac_cv_env_CC_set=set -ac_cv_env_CC_value=cc.sh -ac_cv_env_CFLAGS_set= -ac_cv_env_CFLAGS_value= -ac_cv_env_CPPFLAGS_set= -ac_cv_env_CPPFLAGS_value= -ac_cv_env_CPP_set= -ac_cv_env_CPP_value= -ac_cv_env_CXXFLAGS_set= -ac_cv_env_CXXFLAGS_value= -ac_cv_env_CXX_set=set -ac_cv_env_CXX_value=cc.sh -ac_cv_env_LDFLAGS_set= -ac_cv_env_LDFLAGS_value= -ac_cv_env_build_alias_set=set -ac_cv_env_build_alias_value=win32 -ac_cv_env_host_alias_set=set -ac_cv_env_host_alias_value=win32 -ac_cv_env_target_alias_set=set -ac_cv_env_target_alias_value=win32 -ac_cv_exeext=${ac_cv_exeext=.exe} -ac_cv_func___brk=${ac_cv_func___brk=no} -ac_cv_func___sbrk=${ac_cv_func___sbrk=no} -ac_cv_func__brk=${ac_cv_func__brk=no} -ac_cv_func__doprnt=${ac_cv_func__doprnt=no} -ac_cv_func__sbrk=${ac_cv_func__sbrk=no} -ac_cv_func_accept=${ac_cv_func_accept=no} -ac_cv_func_alloca_works=${ac_cv_func_alloca_works=yes} -ac_cv_func_brk=${ac_cv_func_brk=no} -ac_cv_func_clock_gettime=${ac_cv_func_clock_gettime=no} -ac_cv_func_connect=${ac_cv_func_connect=no} -ac_cv_func_decl_fread=${ac_cv_func_decl_fread=no} -ac_cv_func_dlopen=${ac_cv_func_dlopen=no} -ac_cv_func_dup2=${ac_cv_func_dup2=yes} -ac_cv_func_finite=${ac_cv_func_finite=no} -ac_cv_func_flockfile=${ac_cv_func_flockfile=no} -ac_cv_func_fork=${ac_cv_func_fork=no} -ac_cv_func_fork_works=${ac_cv_func_fork_works=no} -ac_cv_func_fpsetmask=${ac_cv_func_fpsetmask=no} -ac_cv_func_fstat=${ac_cv_func_fstat=yes} -ac_cv_func_gethostbyaddr=${ac_cv_func_gethostbyaddr=no} -ac_cv_func_gethostbyaddr_r=${ac_cv_func_gethostbyaddr_r=no} -ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=no} -ac_cv_func_gethostbyname2=${ac_cv_func_gethostbyname2=no} -ac_cv_func_gethostbyname_r=${ac_cv_func_gethostbyname_r=no} -ac_cv_func_gethostname=${ac_cv_func_gethostname=no} -ac_cv_func_gethrtime=${ac_cv_func_gethrtime=no} -ac_cv_func_getipnodebyaddr=${ac_cv_func_getipnodebyaddr=no} -ac_cv_func_getipnodebyname=${ac_cv_func_getipnodebyname=no} -ac_cv_func_getpagesize=${ac_cv_func_getpagesize=no} -ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=no} -ac_cv_func_gmtime_r=${ac_cv_func_gmtime_r=no} -ac_cv_func_ieee_handler=${ac_cv_func_ieee_handler=no} -ac_cv_func_inet_ntoa=${ac_cv_func_inet_ntoa=no} -ac_cv_func_isinf=${ac_cv_func_isinf=no} -ac_cv_func_isnan=${ac_cv_func_isnan=no} -ac_cv_func_localtime_r=${ac_cv_func_localtime_r=no} -ac_cv_func_mallopt=${ac_cv_func_mallopt=no} -ac_cv_func_memchr=${ac_cv_func_memchr=yes} -ac_cv_func_memcmp_working=${ac_cv_func_memcmp_working=yes} -ac_cv_func_memcpy=${ac_cv_func_memcpy=yes} -ac_cv_func_memmove=${ac_cv_func_memmove=yes} -ac_cv_func_memset=${ac_cv_func_memset=yes} -ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped=no} -ac_cv_func_mremap=${ac_cv_func_mremap=no} -ac_cv_func_nl_langinfo=${ac_cv_func_nl_langinfo=no} -ac_cv_func_openpty=${ac_cv_func_openpty=no} -ac_cv_func_posix2time=${ac_cv_func_posix2time=no} -ac_cv_func_pread=${ac_cv_func_pread=no} -ac_cv_func_pwrite=${ac_cv_func_pwrite=no} -ac_cv_func_res_gethostbyname=${ac_cv_func_res_gethostbyname=no} -ac_cv_func_sbrk=${ac_cv_func_sbrk=no} -ac_cv_func_select=${ac_cv_func_select=no} -ac_cv_func_setlocale=${ac_cv_func_setlocale=yes} -ac_cv_func_setsid=${ac_cv_func_setsid=no} -ac_cv_func_socket=${ac_cv_func_socket=no} -ac_cv_func_strchr=${ac_cv_func_strchr=yes} -ac_cv_func_strerror=${ac_cv_func_strerror=yes} -ac_cv_func_strerror_r=${ac_cv_func_strerror_r=no} -ac_cv_func_strlcat=${ac_cv_func_strlcat=no} -ac_cv_func_strlcpy=${ac_cv_func_strlcpy=no} -ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp=no} -ac_cv_func_strrchr=${ac_cv_func_strrchr=yes} -ac_cv_func_strstr=${ac_cv_func_strstr=yes} -ac_cv_func_uname=${ac_cv_func_uname=no} -ac_cv_func_vfork=${ac_cv_func_vfork=no} -ac_cv_func_vfork_works=${ac_cv_func_vfork_works=no} -ac_cv_func_vprintf=${ac_cv_func_vprintf=yes} -ac_cv_func_writev=${ac_cv_func_writev=no} -ac_cv_header_arpa_inet_h=${ac_cv_header_arpa_inet_h=no} -ac_cv_header_arpa_nameser_h=${ac_cv_header_arpa_nameser_h=no} -ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=no} -ac_cv_header_dirent_ndir_h=${ac_cv_header_dirent_ndir_h=no} -ac_cv_header_dirent_sys_dir_h=${ac_cv_header_dirent_sys_dir_h=no} -ac_cv_header_dirent_sys_ndir_h=${ac_cv_header_dirent_sys_ndir_h=no} -ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=no} -ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes} -ac_cv_header_gl_gl_h=${ac_cv_header_gl_gl_h=yes} -ac_cv_header_ieeefp_h=${ac_cv_header_ieeefp_h=no} -ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=no} -ac_cv_header_langinfo_h=${ac_cv_header_langinfo_h=no} -ac_cv_header_limits_h=${ac_cv_header_limits_h=yes} -ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes} -ac_cv_header_memory_h=${ac_cv_header_memory_h=yes} -ac_cv_header_net_errno_h=${ac_cv_header_net_errno_h=no} -ac_cv_header_netdb_h=${ac_cv_header_netdb_h=no} -ac_cv_header_netinet_in_h=${ac_cv_header_netinet_in_h=no} -ac_cv_header_pty_h=${ac_cv_header_pty_h=no} -ac_cv_header_stdc=${ac_cv_header_stdc=yes} -ac_cv_header_stddef_h=${ac_cv_header_stddef_h=yes} -ac_cv_header_stdint_h=${ac_cv_header_stdint_h=no} -ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes} -ac_cv_header_string_h=${ac_cv_header_string_h=yes} -ac_cv_header_strings_h=${ac_cv_header_strings_h=no} -ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h=no} -ac_cv_header_sys_epoll_h=${ac_cv_header_sys_epoll_h=no} -ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h=no} -ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=no} -ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h=no} -ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h=no} -ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=no} -ac_cv_header_sys_socketio_h=${ac_cv_header_sys_socketio_h=no} -ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no} -ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes} -ac_cv_header_sys_stropts_h=${ac_cv_header_sys_stropts_h=no} -ac_cv_header_sys_sysctl_h=${ac_cv_header_sys_sysctl_h=no} -ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=no} -ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes} -ac_cv_header_sys_uio_h=${ac_cv_header_sys_uio_h=no} -ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=no} -ac_cv_header_syslog_h=${ac_cv_header_syslog_h=no} -ac_cv_header_time=${ac_cv_header_time=no} -ac_cv_header_unistd_h=${ac_cv_header_unistd_h=no} -ac_cv_header_util_h=${ac_cv_header_util_h=no} -ac_cv_header_utmp_h=${ac_cv_header_utmp_h=no} -ac_cv_header_valgrind_valgrind_h=${ac_cv_header_valgrind_valgrind_h=no} -ac_cv_header_vfork_h=${ac_cv_header_vfork_h=no} -ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen=no} -ac_cv_lib_inet_main=${ac_cv_lib_inet_main=no} -ac_cv_lib_kstat_kstat_open=${ac_cv_lib_kstat_kstat_open=no} -ac_cv_lib_m_sin=${ac_cv_lib_m_sin=no} -ac_cv_lib_nsl_gethostbyname=${ac_cv_lib_nsl_gethostbyname=no} -ac_cv_lib_nsl_main=${ac_cv_lib_nsl_main=no} -ac_cv_lib_resolv_res_gethostbyname=${ac_cv_lib_resolv_res_gethostbyname=no} -ac_cv_lib_rt_clock_gettime=${ac_cv_lib_rt_clock_gettime=no} -ac_cv_lib_socket_getpeername=${ac_cv_lib_socket_getpeername=no} -ac_cv_lib_socket_main=${ac_cv_lib_socket_main=yes} -ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket=no} -ac_cv_lib_util_openpty=${ac_cv_lib_util_openpty=no} -ac_cv_lib_ws2_32_main=${ac_cv_lib_ws2_32_main=yes} -ac_cv_member_struct_ErlDrvEntry_stop_select=${ac_cv_member_struct_ErlDrvEntry_stop_select=no} -ac_cv_objext=${ac_cv_objext=o} -ac_cv_path_MKDIR=${ac_cv_path_MKDIR=/bin/mkdir} -ac_cv_path_PERL=${ac_cv_path_PERL=/usr/bin/perl} -ac_cv_path_RM=${ac_cv_path_RM=/bin/rm} -ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'} -ac_cv_prog_AR=${ac_cv_prog_AR=ar.sh} -ac_cv_prog_CC=${ac_cv_prog_CC=cc.sh} -ac_cv_prog_CPP=${ac_cv_prog_CPP='cc.sh -E'} -ac_cv_prog_CXX=${ac_cv_prog_CXX=cc.sh} -ac_cv_prog_DED_LD=${ac_cv_prog_DED_LD=ld.sh} -ac_cv_prog_ac_ct_DED_LD=${ac_cv_prog_ac_ct_DED_LD=ld.sh} -ac_cv_prog_M4=${ac_cv_prog_M4=m4} -ac_cv_prog_PERL=${ac_cv_prog_PERL=perl} -ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=true} -ac_cv_prog_LD=${ac_cv_prog_LD=ld.sh} -ac_cv_prog_ac_ct_LD=${ac_cv_prog_ac_ct_LD=ld.sh} -ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} -ac_cv_prog_cc_stdc=${ac_cv_prog_cc_stdc=} -ac_cv_prog_cxx_g=${ac_cv_prog_cxx_g=no} -ac_cv_prog_egrep=${ac_cv_prog_egrep='grep -E'} -ac_cv_prog_emu_cc=${ac_cv_prog_emu_cc=emu_cc.sh} -ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set=yes} -ac_cv_prog_mkdir_p=${ac_cv_prog_mkdir_p='/usr/bin/install -c -d'} -ac_cv_search_opendir=${ac_cv_search_opendir=no} -ac_cv_search_strerror=${ac_cv_search_strerror='none required'} -ac_cv_sizeof_char=${ac_cv_sizeof_char=1} -ac_cv_sizeof_int=${ac_cv_sizeof_int=4} -ac_cv_sizeof_long=${ac_cv_sizeof_long=4} -ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long=8} -ac_cv_sizeof_off_t=${ac_cv_sizeof_off_t=4} -ac_cv_sizeof_short=${ac_cv_sizeof_short=2} -ac_cv_sizeof_size_t=${ac_cv_sizeof_size_t=4} -ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=4} -ac_cv_struct_exception=${ac_cv_struct_exception=no} -ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no} -ac_cv_struct_tm=${ac_cv_struct_tm=time.h} -ac_cv_sys_multicast_support=${ac_cv_sys_multicast_support=no} -ac_cv_type_char=${ac_cv_type_char=yes} -ac_cv_type_int=${ac_cv_type_int=yes} -ac_cv_type_long=${ac_cv_type_long=yes} -ac_cv_type_long_long=${ac_cv_type_long_long=yes} -ac_cv_type_off_t=${ac_cv_type_off_t=yes} -ac_cv_type_pid_t=${ac_cv_type_pid_t=no} -ac_cv_type_short=${ac_cv_type_short=yes} -ac_cv_type_signal=${ac_cv_type_signal=void} -ac_cv_type_size_t=${ac_cv_type_size_t=yes} -ac_cv_type_uid_t=${ac_cv_type_uid_t=no} -ac_cv_type_void_p=${ac_cv_type_void_p=yes} -ac_cv_working_alloca_h=${ac_cv_working_alloca_h=no} -erts_cv___after_morecore_hook_can_track_malloc=${erts_cv___after_morecore_hook_can_track_malloc=no} -erts_cv_fwrite_unlocked=${erts_cv_fwrite_unlocked=no} -erts_cv_have__end_symbol=${erts_cv_have__end_symbol=no} -erts_cv_have_end_symbol=${erts_cv_have_end_symbol=no} -erts_cv_putc_unlocked=${erts_cv_putc_unlocked=no} -erts_cv_windows_h_includes_winsock2_h=${erts_cv_windows_h_includes_winsock2_h=no} diff --git a/erts/autoconf/win64.config.cache.static b/erts/autoconf/win64.config.cache.static deleted file mode 100755 index c7d92c700070..000000000000 --- a/erts/autoconf/win64.config.cache.static +++ /dev/null @@ -1,270 +0,0 @@ -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -ac_cv_c_bigendian=${ac_cv_c_bigendian=no} -ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=no} -ac_cv_c_const=${ac_cv_c_const=yes} -ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=no} -ac_cv_decl_h_errno=${ac_cv_decl_h_errno=no} -ac_cv_decl_inaddr_loopback=${ac_cv_decl_inaddr_loopback=no} -ac_cv_decl_inaddr_loopback_rpc=${ac_cv_decl_inaddr_loopback_rpc=no} -ac_cv_decl_inaddr_loopback_winsock2=${ac_cv_decl_inaddr_loopback_winsock2=yes} -ac_cv_decl_so_bsdcompat=${ac_cv_decl_so_bsdcompat=no} -ac_cv_decl_sys_errlist=${ac_cv_decl_sys_errlist=no} -ac_cv_env_AR_set=set -ac_cv_env_AR_value=ar.sh -ac_cv_env_CCC_set= -ac_cv_env_CCC_value= -ac_cv_env_CC_set=set -ac_cv_env_CC_value=cc.sh -ac_cv_env_CFLAGS_set= -ac_cv_env_CFLAGS_value= -ac_cv_env_CPPFLAGS_set= -ac_cv_env_CPPFLAGS_value= -ac_cv_env_CPP_set= -ac_cv_env_CPP_value= -ac_cv_env_CXXFLAGS_set= -ac_cv_env_CXXFLAGS_value= -ac_cv_env_CXX_set=set -ac_cv_env_CXX_value=cc.sh -ac_cv_env_LDFLAGS_set= -ac_cv_env_LDFLAGS_value= -ac_cv_env_build_alias_set=set -ac_cv_env_build_alias_value=win32 -ac_cv_env_host_alias_set=set -ac_cv_env_host_alias_value=win32 -ac_cv_env_target_alias_set=set -ac_cv_env_target_alias_value=win32 -ac_cv_exeext=${ac_cv_exeext=.exe} -ac_cv_func___brk=${ac_cv_func___brk=no} -ac_cv_func___sbrk=${ac_cv_func___sbrk=no} -ac_cv_func__brk=${ac_cv_func__brk=no} -ac_cv_func__doprnt=${ac_cv_func__doprnt=no} -ac_cv_func__sbrk=${ac_cv_func__sbrk=no} -ac_cv_func_accept=${ac_cv_func_accept=no} -ac_cv_func_alloca_works=${ac_cv_func_alloca_works=yes} -ac_cv_func_brk=${ac_cv_func_brk=no} -ac_cv_func_clock_gettime=${ac_cv_func_clock_gettime=no} -ac_cv_func_connect=${ac_cv_func_connect=no} -ac_cv_func_decl_fread=${ac_cv_func_decl_fread=yes} -ac_cv_func_dlopen=${ac_cv_func_dlopen=no} -ac_cv_func_dup2=${ac_cv_func_dup2=yes} -ac_cv_func_fdatasync=${ac_cv_func_fdatasync=no} -ac_cv_func_finite=${ac_cv_func_finite=no} -ac_cv_func_flockfile=${ac_cv_func_flockfile=no} -ac_cv_func_fork=${ac_cv_func_fork=no} -ac_cv_func_fork_works=${ac_cv_func_fork_works=no} -ac_cv_func_fpsetmask=${ac_cv_func_fpsetmask=no} -ac_cv_func_fstat=${ac_cv_func_fstat=yes} -ac_cv_func_gethostbyaddr=${ac_cv_func_gethostbyaddr=no} -ac_cv_func_gethostbyaddr_r=${ac_cv_func_gethostbyaddr_r=no} -ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=yes} -ac_cv_func_gethostbyname2=${ac_cv_func_gethostbyname2=no} -ac_cv_func_gethostbyname_r=${ac_cv_func_gethostbyname_r=no} -ac_cv_func_gethostname=${ac_cv_func_gethostname=no} -ac_cv_func_gethrtime=${ac_cv_func_gethrtime=no} -ac_cv_func_getifaddrs=${ac_cv_func_getifaddrs=no} -ac_cv_func_getipnodebyaddr=${ac_cv_func_getipnodebyaddr=no} -ac_cv_func_getipnodebyname=${ac_cv_func_getipnodebyname=no} -ac_cv_func_getpagesize=${ac_cv_func_getpagesize=no} -ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=no} -ac_cv_func_gmtime_r=${ac_cv_func_gmtime_r=no} -ac_cv_func_ieee_handler=${ac_cv_func_ieee_handler=no} -ac_cv_func_inet_ntoa=${ac_cv_func_inet_ntoa=no} -ac_cv_func_inet_pton=${ac_cv_func_inet_pton=yes} -ac_cv_func_isinf=${ac_cv_func_isinf=no} -ac_cv_func_isnan=${ac_cv_func_isnan=no} -ac_cv_func_localtime_r=${ac_cv_func_localtime_r=no} -ac_cv_func_mallopt=${ac_cv_func_mallopt=no} -ac_cv_func_memchr=${ac_cv_func_memchr=yes} -ac_cv_func_memcmp_working=${ac_cv_func_memcmp_working=yes} -ac_cv_func_memcpy=${ac_cv_func_memcpy=no} -ac_cv_func_memmove=${ac_cv_func_memmove=yes} -ac_cv_func_memset=${ac_cv_func_memset=yes} -ac_cv_func_mmap=${ac_cv_func_mmap=no} -ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped=no} -ac_cv_func_mremap=${ac_cv_func_mremap=no} -ac_cv_func_nl_langinfo=${ac_cv_func_nl_langinfo=no} -ac_cv_func_openpty=${ac_cv_func_openpty=no} -ac_cv_func_poll=${ac_cv_func_poll=no} -ac_cv_func_posix2time=${ac_cv_func_posix2time=no} -ac_cv_func_posix_fadvise=${ac_cv_func_posix_fadvise=no} -ac_cv_func_pread=${ac_cv_func_pread=no} -ac_cv_func_pwrite=${ac_cv_func_pwrite=no} -ac_cv_func_res_gethostbyname=${ac_cv_func_res_gethostbyname=no} -ac_cv_func_sbrk=${ac_cv_func_sbrk=no} -ac_cv_func_sctp_bindx=${ac_cv_func_sctp_bindx=no} -ac_cv_func_sctp_peeloff=${ac_cv_func_sctp_peeloff=no} -ac_cv_func_select=${ac_cv_func_select=no} -ac_cv_func_setlocale=${ac_cv_func_setlocale=yes} -ac_cv_func_setsid=${ac_cv_func_setsid=no} -ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed=yes} -ac_cv_func_socket=${ac_cv_func_socket=no} -ac_cv_func_strchr=${ac_cv_func_strchr=yes} -ac_cv_func_strerror=${ac_cv_func_strerror=yes} -ac_cv_func_strerror_r=${ac_cv_func_strerror_r=no} -ac_cv_func_strlcat=${ac_cv_func_strlcat=no} -ac_cv_func_strlcpy=${ac_cv_func_strlcpy=no} -ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp=no} -ac_cv_func_strrchr=${ac_cv_func_strrchr=yes} -ac_cv_func_strstr=${ac_cv_func_strstr=yes} -ac_cv_func_uname=${ac_cv_func_uname=no} -ac_cv_func_vfork=${ac_cv_func_vfork=no} -ac_cv_func_vfork_works=${ac_cv_func_vfork_works=no} -ac_cv_func_vprintf=${ac_cv_func_vprintf=yes} -ac_cv_func_writev=${ac_cv_func_writev=no} -ac_cv_have_decl_SCTPS_BOUND=${ac_cv_have_decl_SCTPS_BOUND=no} -ac_cv_have_decl_SCTPS_COOKIE_ECHOED=${ac_cv_have_decl_SCTPS_COOKIE_ECHOED=no} -ac_cv_have_decl_SCTPS_COOKIE_WAIT=${ac_cv_have_decl_SCTPS_COOKIE_WAIT=no} -ac_cv_have_decl_SCTPS_ESTABLISHED=${ac_cv_have_decl_SCTPS_ESTABLISHED=no} -ac_cv_have_decl_SCTPS_IDLE=${ac_cv_have_decl_SCTPS_IDLE=no} -ac_cv_have_decl_SCTPS_LISTEN=${ac_cv_have_decl_SCTPS_LISTEN=no} -ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT=${ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT=no} -ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING=${ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING=no} -ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED=${ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED=no} -ac_cv_have_decl_SCTPS_SHUTDOWN_SENT=${ac_cv_have_decl_SCTPS_SHUTDOWN_SENT=no} -ac_cv_have_decl_SCTP_ABORT=${ac_cv_have_decl_SCTP_ABORT=no} -ac_cv_have_decl_SCTP_ADDR_CONFIRMED=${ac_cv_have_decl_SCTP_ADDR_CONFIRMED=no} -ac_cv_have_decl_SCTP_ADDR_OVER=${ac_cv_have_decl_SCTP_ADDR_OVER=no} -ac_cv_have_decl_SCTP_BOUND=${ac_cv_have_decl_SCTP_BOUND=no} -ac_cv_have_decl_SCTP_CLOSED=${ac_cv_have_decl_SCTP_CLOSED=no} -ac_cv_have_decl_SCTP_COOKIE_ECHOED=${ac_cv_have_decl_SCTP_COOKIE_ECHOED=no} -ac_cv_have_decl_SCTP_COOKIE_WAIT=${ac_cv_have_decl_SCTP_COOKIE_WAIT=no} -ac_cv_have_decl_SCTP_DELAYED_ACK_TIME=${ac_cv_have_decl_SCTP_DELAYED_ACK_TIME=no} -ac_cv_have_decl_SCTP_EMPTY=${ac_cv_have_decl_SCTP_EMPTY=no} -ac_cv_have_decl_SCTP_EOF=${ac_cv_have_decl_SCTP_EOF=no} -ac_cv_have_decl_SCTP_ESTABLISHED=${ac_cv_have_decl_SCTP_ESTABLISHED=no} -ac_cv_have_decl_SCTP_LISTEN=${ac_cv_have_decl_SCTP_LISTEN=no} -ac_cv_have_decl_SCTP_SENDALL=${ac_cv_have_decl_SCTP_SENDALL=no} -ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT=${ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT=no} -ac_cv_have_decl_SCTP_SHUTDOWN_PENDING=${ac_cv_have_decl_SCTP_SHUTDOWN_PENDING=no} -ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED=${ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED=no} -ac_cv_have_decl_SCTP_SHUTDOWN_SENT=${ac_cv_have_decl_SCTP_SHUTDOWN_SENT=no} -ac_cv_have_decl_SCTP_UNORDERED=${ac_cv_have_decl_SCTP_UNORDERED=no} -ac_cv_have_decl_posix2time=${ac_cv_have_decl_posix2time=no} -ac_cv_header_arpa_inet_h=${ac_cv_header_arpa_inet_h=no} -ac_cv_header_arpa_nameser_h=${ac_cv_header_arpa_nameser_h=no} -ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=no} -ac_cv_header_dirent_ndir_h=${ac_cv_header_dirent_ndir_h=no} -ac_cv_header_dirent_sys_dir_h=${ac_cv_header_dirent_sys_dir_h=no} -ac_cv_header_dirent_sys_ndir_h=${ac_cv_header_dirent_sys_ndir_h=no} -ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=no} -ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes} -ac_cv_header_gl_gl_h=${ac_cv_header_gl_gl_h=yes} -ac_cv_header_ieeefp_h=${ac_cv_header_ieeefp_h=no} -ac_cv_header_ifaddrs_h=${ac_cv_header_ifaddrs_h=no} -ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=no} -ac_cv_header_langinfo_h=${ac_cv_header_langinfo_h=no} -ac_cv_header_limits_h=${ac_cv_header_limits_h=yes} -ac_cv_header_mach_o_dyld_h=${ac_cv_header_mach_o_dyld_h=no} -ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes} -ac_cv_header_memory_h=${ac_cv_header_memory_h=yes} -ac_cv_header_net_errno_h=${ac_cv_header_net_errno_h=no} -ac_cv_header_net_if_dl_h=${ac_cv_header_net_if_dl_h=no} -ac_cv_header_netdb_h=${ac_cv_header_netdb_h=no} -ac_cv_header_netinet_in_h=${ac_cv_header_netinet_in_h=no} -ac_cv_header_netpacket_packet_h=${ac_cv_header_netpacket_packet_h=no} -ac_cv_header_poll_h=${ac_cv_header_poll_h=no} -ac_cv_header_pty_h=${ac_cv_header_pty_h=no} -ac_cv_header_stdc=${ac_cv_header_stdc=yes} -ac_cv_header_stddef_h=${ac_cv_header_stddef_h=yes} -ac_cv_header_stdint_h=${ac_cv_header_stdint_h=yes} -ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes} -ac_cv_header_string_h=${ac_cv_header_string_h=yes} -ac_cv_header_strings_h=${ac_cv_header_strings_h=no} -ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h=no} -ac_cv_header_sys_epoll_h=${ac_cv_header_sys_epoll_h=no} -ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h=no} -ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=no} -ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h=no} -ac_cv_header_sys_resource_h=${ac_cv_header_sys_resource_h=no} -ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h=no} -ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=no} -ac_cv_header_sys_socketio_h=${ac_cv_header_sys_socketio_h=no} -ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no} -ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes} -ac_cv_header_sys_stropts_h=${ac_cv_header_sys_stropts_h=no} -ac_cv_header_sys_sysctl_h=${ac_cv_header_sys_sysctl_h=no} -ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=no} -ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes} -ac_cv_header_sys_uio_h=${ac_cv_header_sys_uio_h=no} -ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=no} -ac_cv_header_syslog_h=${ac_cv_header_syslog_h=no} -ac_cv_header_time=${ac_cv_header_time=no} -ac_cv_header_unistd_h=${ac_cv_header_unistd_h=no} -ac_cv_header_util_h=${ac_cv_header_util_h=no} -ac_cv_header_utmp_h=${ac_cv_header_utmp_h=no} -ac_cv_header_valgrind_valgrind_h=${ac_cv_header_valgrind_valgrind_h=no} -ac_cv_header_vfork_h=${ac_cv_header_vfork_h=no} -ac_cv_header_windows_h=${ac_cv_header_windows_h=yes} -ac_cv_header_winsock2_h=${ac_cv_header_winsock2_h=yes} -ac_cv_header_ws2tcpip_h=${ac_cv_header_ws2tcpip_h=yes} -ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen=no} -ac_cv_lib_inet_main=${ac_cv_lib_inet_main=no} -ac_cv_lib_kstat_kstat_open=${ac_cv_lib_kstat_kstat_open=no} -ac_cv_lib_m_sin=${ac_cv_lib_m_sin=no} -ac_cv_lib_nsl_gethostbyname=${ac_cv_lib_nsl_gethostbyname=no} -ac_cv_lib_nsl_main=${ac_cv_lib_nsl_main=no} -ac_cv_lib_resolv_res_gethostbyname=${ac_cv_lib_resolv_res_gethostbyname=no} -ac_cv_lib_rt_clock_gettime=${ac_cv_lib_rt_clock_gettime=no} -ac_cv_lib_socket_getpeername=${ac_cv_lib_socket_getpeername=no} -ac_cv_lib_socket_main=${ac_cv_lib_socket_main=yes} -ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket=no} -ac_cv_lib_util_openpty=${ac_cv_lib_util_openpty=no} -ac_cv_lib_ws2_32_main=${ac_cv_lib_ws2_32_main=yes} -ac_cv_member_struct_ErlDrvEntry_stop_select=${ac_cv_member_struct_ErlDrvEntry_stop_select=no} -ac_cv_member_struct_sctp_paddrparams_spp_flags=${ac_cv_member_struct_sctp_paddrparams_spp_flags=no} -ac_cv_member_struct_sctp_paddrparams_spp_pathmtu=${ac_cv_member_struct_sctp_paddrparams_spp_pathmtu=no} -ac_cv_member_struct_sctp_paddrparams_spp_sackdelay=${ac_cv_member_struct_sctp_paddrparams_spp_sackdelay=no} -ac_cv_member_struct_sctp_remote_error_sre_data=${ac_cv_member_struct_sctp_remote_error_sre_data=no} -ac_cv_member_struct_sctp_send_failed_ssf_data=${ac_cv_member_struct_sctp_send_failed_ssf_data=no} -ac_cv_objext=${ac_cv_objext=o} -ac_cv_path_MKDIR=${ac_cv_path_MKDIR=/bin/mkdir} -ac_cv_path_RM=${ac_cv_path_RM=/bin/rm} -ac_cv_prog_AR=${ac_cv_prog_AR=ar.sh} -ac_cv_prog_CC=${ac_cv_prog_CC=cc.sh} -ac_cv_prog_CPP=${ac_cv_prog_CPP='cc.sh -E'} -ac_cv_prog_CXX=${ac_cv_prog_CXX=cc.sh} -ac_cv_prog_DED_LD=${ac_cv_prog_DED_LD=ld.sh} -ac_cv_prog_JAVAC=${ac_cv_prog_JAVAC=javac.sh} -ac_cv_prog_M4=${ac_cv_prog_M4=m4} -ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=true} -ac_cv_prog_cc_c89=${ac_cv_prog_cc_c89=} -ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} -ac_cv_search_fdatasync=${ac_cv_search_fdatasync=no} -ac_cv_search_opendir=${ac_cv_search_opendir=no} -ac_cv_search_strerror=${ac_cv_search_strerror='none required'} -ac_cv_sizeof___int64=${ac_cv_sizeof___int64=8} -ac_cv_sizeof_char=${ac_cv_sizeof_char=1} -ac_cv_sizeof_int=${ac_cv_sizeof_int=4} -ac_cv_sizeof_long=${ac_cv_sizeof_long=4} -ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long=8} -ac_cv_sizeof_off_t=${ac_cv_sizeof_off_t=4} -ac_cv_sizeof_short=${ac_cv_sizeof_short=2} -ac_cv_sizeof_size_t=${ac_cv_sizeof_size_t=8} -ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=8} -ac_cv_struct_exception=${ac_cv_struct_exception=no} -ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no} -ac_cv_struct_tm=${ac_cv_struct_tm=time.h} -ac_cv_type_off_t=${ac_cv_type_off_t=yes} -ac_cv_type_pid_t=${ac_cv_type_pid_t=no} -ac_cv_type_signal=${ac_cv_type_signal=void} -ac_cv_type_size_t=${ac_cv_type_size_t=yes} -ac_cv_type_uid_t=${ac_cv_type_uid_t=no} -ac_cv_working_alloca_h=${ac_cv_working_alloca_h=no} -erts_cv___after_morecore_hook_can_track_malloc=${erts_cv___after_morecore_hook_can_track_malloc=no} -erts_cv_fwrite_unlocked=${erts_cv_fwrite_unlocked=no} -erts_cv_have__end_symbol=${erts_cv_have__end_symbol=no} -erts_cv_have_end_symbol=${erts_cv_have_end_symbol=no} -erts_cv_putc_unlocked=${erts_cv_putc_unlocked=no} -erts_cv_windows_h_includes_winsock2_h=${erts_cv_windows_h_includes_winsock2_h=no} diff --git a/erts/config.h.in b/erts/config.h.in index 8295b9041038..d7fecf863126 100644 --- a/erts/config.h.in +++ b/erts/config.h.in @@ -1,4 +1,4 @@ -/* config.h.in. Generated from configure.in by autoheader. */ +/* config.h.in. Generated from configure.ac by autoheader. */ #ifndef __ERTS_CONFIG_H__ @@ -31,6 +31,9 @@ format (like some ARMs). */ #undef DOUBLE_MIDDLE_ENDIAN +/* Define if we need frame pointers on the Erlang stack */ +#undef ERLANG_FRAME_POINTERS + /* Define if sbrk()/brk() wrappers can track malloc()s core memory use */ #undef ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC @@ -80,6 +83,15 @@ /* ESOCK counter size */ #undef ESOCK_COUNTER_SIZE +/* Enable esock */ +#undef ESOCK_ENABLE + +/* Socket address dl length */ +#undef ESOCK_SDL_LEN + +/* Use extended error info */ +#undef ESOCK_USE_EXTENDED_ERROR_INFO + /* Interface hwaddr supported */ #undef ESOCK_USE_HWADDR @@ -101,7 +113,7 @@ /* Define if bigendian */ #undef ETHR_BIGENDIAN -/* Define if gcc wont let you clobber ebx with cmpxchg8b and position +/* Define if gcc won't let you clobber ebx with cmpxchg8b and position independent code */ #undef ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX @@ -129,6 +141,11 @@ /* Define if you have all ethread defines */ #undef ETHR_HAVE_ETHREAD_DEFINES +/* Define as a boolean indicating whether you have a gcc compatible compiler + capable of generating the ARM 'dc cvau' instruction, and are compiling for + an ARM processor with ARM DC instruction support, or not */ +#undef ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION + /* Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb sy' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not */ @@ -144,6 +161,16 @@ an ARM processor with ARM DMB instruction support, or not */ #undef ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION +/* Define as a boolean indicating whether you have a gcc compatible compiler + capable of generating the ARM 'ic ivau' instruction, and are compiling for + an ARM processor with ARM IC instruction support, or not */ +#undef ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION + +/* Define as a boolean indicating whether you have a gcc compatible compiler + capable of generating the ARM 'isb sy' instruction, and are compiling for + an ARM processor with ARM ISB instruction support, or not */ +#undef ETHR_HAVE_GCC_ASM_ARM_ISB_SY_INSTRUCTION + /* Define as a boolean indicating whether you have a gcc __atomic builtins or not */ #undef ETHR_HAVE_GCC___ATOMIC_BUILTINS @@ -394,9 +421,6 @@ /* Define if only run in Sparc TSO mode */ #undef ETHR_SPARC_TSO -/* Define if you can safely include both and . */ -#undef ETHR_TIME_WITH_SYS_TIME - /* Define as a boolean indicating whether you trust gcc's __atomic_* builtins memory barrier implementations, or not */ #undef ETHR_TRUST_GCC_ATOMIC_BUILTINS_MEMORY_BARRIERS @@ -595,6 +619,9 @@ /* Define to 1 if you have the `dlopen' function. */ #undef HAVE_DLOPEN +/* Define to 1 if you have the `dlvsym' function. */ +#undef HAVE_DLVSYM + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT @@ -800,8 +827,8 @@ /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H +/* Define to 1 if you have the `memrchr' function. */ +#undef HAVE_MEMRCHR /* Define if the pthread.h header file is in pthread/mit directory. */ #undef HAVE_MIT_PTHREAD_H @@ -905,6 +932,9 @@ /* Define to 1 if you have the `sctp_bindx' function. */ #undef HAVE_SCTP_BINDX +/* Define to 1 if you have the `sctp_connectx' function. */ +#undef HAVE_SCTP_CONNECTX + /* Define to 1 if you have the `sctp_freeladdrs' function. */ #undef HAVE_SCTP_FREELADDRS @@ -959,6 +989,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H @@ -1001,6 +1034,9 @@ /* Define to 1 if `ifr_map' is a member of `struct ifreq'. */ #undef HAVE_STRUCT_IFREQ_IFR_MAP +/* Define to 1 if the system has the type `struct ip_mreqn'. */ +#undef HAVE_STRUCT_IP_MREQN + /* Define to 1 if `assoc_id' is a member of `struct sctp_accoc_value'. */ #undef HAVE_STRUCT_SCTP_ACCOC_VALUE_ASSOC_ID @@ -1027,6 +1063,9 @@ /* Define to 1 if `ssf_data' is a member of `struct sctp_send_failed'. */ #undef HAVE_STRUCT_SCTP_SEND_FAILED_SSF_DATA +/* Define to 1 if `sdl_len' is a member of `struct sockaddr_dl'. */ +#undef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN + /* Define to 1 if `sun_path' is a member of `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN_SUN_PATH @@ -1238,9 +1277,6 @@ */ #undef REDEFINE_FD_SETSIZE -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE - /* Define the sbrk() argument type. */ #undef SBRK_ARG_TYPE @@ -1292,7 +1328,9 @@ /* The size of `__int64', as computed by sizeof. */ #undef SIZEOF___INT64 -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* define if the variable sys_errlist is declared in a system header file */ @@ -1308,9 +1346,6 @@ clock_get_time() */ #undef SYS_HRTIME_USING_MACH_CLOCK_GET_TIME -/* Define to 1 if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME @@ -1350,7 +1385,7 @@ /* Define to `long int' if does not define. */ #undef off_t -/* Define to `int' if does not define. */ +/* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `unsigned int' if does not define. */ diff --git a/erts/configure b/erts/configure index 7da8d32a1bf1..a09c84ff098a 100755 --- a/erts/configure +++ b/erts/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +221,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +253,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +292,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +310,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +332,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +341,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +380,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +398,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +430,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +459,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +503,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +517,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +534,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,52 +606,51 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= - -ac_unique_file="vsn.mk" +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="emulator/beam/erl_process.c" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= +ac_func_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS +DEBUG_CFLAGS +ERL_DETERMINISTIC CFLAGS32 CC32 JAVAC @@ -636,7 +666,6 @@ FLAVORS PRIMARY_FLAVOR JIT_ARCH JIT_ENABLED -ac_ct_CXX M4 LIBRT BITS64 @@ -644,7 +673,6 @@ HAVE_VALGRIND LIBSCTP SYSTEMD_DAEMON_LIBS SOCKET_LIBS -USE_ESOCK Z_LIB TERMCAP_LIB THR_DEFS @@ -654,7 +682,7 @@ EMU_THR_DEFS EMU_THR_LIBS EMU_THR_X_LIBS EMU_THR_LIB_NAME -TYPES +DEFAULT_TYPES DIRTY_SCHEDULER_TEST ETHR_X86_SSE2_ASM ETHR_THR_LIB_BASE_DIR @@ -668,36 +696,36 @@ DEXPORT ERLANG_OSTYPE HCFLAGS HCC -INSTALL_DIR -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -XMLLINT -FOP -XSLTPROC -LN_S -PERL -YFLAGS -YACC CP MKDIR LIBCARBON ARCH OPSYS EXTERNAL_WORD_SIZE -EGREP -GREP PROFILE_COMPILER USE_PGO XCRUN LLVM_PROFDATA WERRORFLAGS WFLAGS -DEBUG_CFLAGS DEBUG_FLAGS ERTS_CONFIG_H_IDIR MIXED_MINGW MIXED_VC +INSTALL_DIR +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +XMLLINT +FOP +XSLTPROC +LN_S +PERL +YFLAGS +YACC +EGREP +GREP +ac_ct_CXX GCC STATIC_DRIVERS STATIC_NIFS @@ -710,6 +738,10 @@ OBJEXT EXEEXT ac_ct_CC CROSS_COMPILING +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -828,6 +860,7 @@ with_threadnames enable_builtin_zlib enable_esock enable_esock_use_rcvsndtimeo +enable_esock_extended_error_info with_esock_counter_size enable_esock_socket_registry with_clock_resolution @@ -836,7 +869,7 @@ with_clock_gettime_monotonic_id enable_prefer_elapsed_monotonic_time_during_suspend enable_gettimeofday_as_os_system_time with_javac -enable_sanitizers +enable_deterministic_build ' ac_precious_vars='build_alias host_alias @@ -878,9 +911,9 @@ erl_xcomp_gethrvtime_procfs_ioctl erl_xcomp_clock_gettime_cpu_time erl_xcomp_after_morecore_hook erl_xcomp_dlsym_brk_wrappers +CCC YACC -YFLAGS -CCC' +YFLAGS' # Initialize some variables set by options. @@ -949,8 +982,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -991,9 +1022,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1017,9 +1048,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1230,9 +1261,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1246,9 +1277,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1292,9 +1323,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1310,7 +1341,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1374,7 +1405,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1492,6 +1523,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1531,11 +1563,10 @@ Optional Features: list of nifs that should be linked statically. The list should be a comma separated and contain the absolute path to a .a archive for each nif that is - to be statically linked. The name of the .a archive - has to be the same as the name of the nif. Note that - you have to link any external dependencies that the - nifs have to the main binary, so for the crypto nif - you want to pass LIBS=-lcrypto to configure. + to be statically linked. Note that you have to link + any external dependencies, that the nifs have, to + the main binary. So for the crypto nifs you want to + pass LIBS=-lcrypto to configure. --enable-static-drivers comma separated list of linked-in drivers to link statically with the main binary. The list should contain the absolute path to a .a archive for each @@ -1566,6 +1597,10 @@ Optional Features: --disable-esock-rcvsndtimeo disable use of the option(s) rcvtimeo and sndtimeo (default) + --enable-esock-extended-error-info + enable use of extended error info + --disable-esock-extended-error-info + disable use of extended error info (default) --enable-esock-socket-registry enable use of the socket registry by default (default) @@ -1579,8 +1614,9 @@ Optional Features: elapsed time during suspend --enable-gettimeofday-as-os-system-time Force usage of gettimeofday() for OS system time - --enable-sanitizers[=comma-separated list of sanitizers] - Default=address,undefined + --enable-deterministic-build + enable build determinism, stripping absolute paths + from build output Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1737,9 +1773,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1767,7 +1803,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1775,7 +1812,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1785,9 +1822,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1804,14 +1841,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1819,14 +1856,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1842,14 +1880,14 @@ fi ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1857,17 +1895,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1882,10 +1921,87 @@ fi } # ac_fn_c_try_link +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + # ac_fn_c_try_run LINENO # ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -1895,25 +2011,26 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status @@ -1938,7 +2055,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -1948,14 +2065,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1965,9 +2083,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -1975,14 +2094,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -1992,14 +2111,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2009,9 +2129,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -2019,14 +2140,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -2034,7 +2155,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2044,12 +2165,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -2059,12 +2181,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -2092,9 +2214,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 &5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in @@ -2151,26 +2237,28 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -2181,11 +2269,12 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -2193,16 +2282,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -2220,115 +2302,29 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including @@ -2336,16 +2332,17 @@ fi ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (ac_aggr.$3) @@ -2354,14 +2351,15 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) @@ -2370,68 +2368,23 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop eval "$4=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. -ac_fn_c_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_decl - # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -2439,17 +2392,18 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -2457,12 +2411,13 @@ if (sizeof ($2)) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -2470,67 +2425,102 @@ if (sizeof (($2))) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop eval "$3=yes" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () +# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR +# ------------------------------------------------------------------ +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. +ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 + as_decl_name=`echo $2|sed 's/ *(.*//'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +printf %s "checking whether $as_decl_name is declared... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS - ac_retval=1 fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval -} # ac_fn_cxx_try_compile +} # ac_fn_check_decl +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2563,8 +2553,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2599,7 +2593,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2634,11 +2628,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2649,8 +2645,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2674,7 +2670,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2682,14 +2678,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2697,15 +2693,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2713,8 +2709,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2728,63 +2724,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2794,100 +2775,719 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; +struct incomplete_array +{ + int datasize; + double data[]; +}; +struct named_init { + int number; + const wchar_t *name; + double average; +}; +typedef const char *ccp; +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + const char *str = ""; + int number = 0; + float fnumber = 0; + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + return *str && number && fnumber; +} +' +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +# Test code for whether the C++ compiler supports C++98 (global declarations) +ac_cxx_conftest_cxx98_globals=' +// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are to reject old compilers that +// lack the unsuffixed header files. +#include +#include + +// and are *not* freestanding headers in C++98. +extern void assert (int); +namespace std { + extern int strcmp (const char *, const char *); +} + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::exception; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + // Extra parentheses suppress a warning when building autoconf itself, + // due to lint rules shared with more typical C programs. + assert (!(strcmp) (s, "test")); + } +} + +template struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template T add(U u) { return static_cast(u) + val; } +}; + +} // anonymous namespace +' + +# Test code for whether the C++ compiler supports C++98 (body of main) +ac_cxx_conftest_cxx98_main=' + assert (argc); + assert (! argv[0]); +{ + test_exception_syntax (); + test_template tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); +} +' + +# Test code for whether the C++ compiler supports C++11 (global declarations) +ac_cxx_conftest_cxx11_globals=' +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif + +namespace cxx11test +{ + constexpr int get_val() { return 20; } + + struct testinit + { + int i; + double d; + }; + + class delegate + { + public: + delegate(int n) : n(n) {} + delegate(): delegate(2354) {} + + virtual int getval() { return this->n; }; + protected: + int n; + }; + + class overridden : public delegate + { + public: + overridden(int n): delegate(n) {} + virtual int getval() override final { return this->n * 2; } + }; + + class nocopy + { + public: + nocopy(int i): i(i) {} + nocopy() = default; + nocopy(const nocopy&) = delete; + nocopy & operator=(const nocopy&) = delete; + private: + int i; + }; + + // for testing lambda expressions + template Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template auto sum(V first) -> V + { + return first; + } + template auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } +} +' + +# Test code for whether the C++ compiler supports C++11 (body of main) +ac_cxx_conftest_cxx11_main=' +{ + // Test auto and decltype + auto a1 = 6538; + auto a2 = 48573953.4; + auto a3 = "String literal"; + + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + + decltype(a2) a4 = 34895.034; +} +{ + // Test constexpr + short sa[cxx11test::get_val()] = { 0 }; +} +{ + // Test initializer lists + cxx11test::testinit il = { 4323, 435234.23544 }; +} +{ + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } +} +{ + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); +} +{ + // Test use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); +} +{ + // Test constructor delegation + cxx11test::delegate d1; + cxx11test::delegate d2(); + cxx11test::delegate d3(45); +} +{ + // Test override and final + cxx11test::overridden o1(55464); +} +{ + // Test nullptr + char *c = nullptr; +} +{ + // Test template brackets + test_template<::test_template> v(test_template(12)); +} +{ + // Unicode literals + char const *utf8 = u8"UTF-8 string \u2500"; + char16_t const *utf16 = u"UTF-8 string \u2500"; + char32_t const *utf32 = U"UTF-32 string \u2500"; +} +' + +# Test code for whether the C compiler supports C++11 (complete). +ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} +${ac_cxx_conftest_cxx11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + ${ac_cxx_conftest_cxx11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C++98 (complete). +ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" +as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H" +as_fn_append ac_func_c_list " vprintf HAVE_VPRINTF" + +# Auxiliary files required by this configure script. +ac_aux_files="install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu @@ -2922,8 +3522,115 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -no_werror_CFLAGS=$(echo "$CFLAGS" | sed 's/-Werror\([^=]\|$\)/ /g') -if test "$CFLAGS" != "$no_werror_CFLAGS"; then + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +no_werror_CFLAGS=$(echo " $CFLAGS " | sed 's/ -Werror / /g') +if test "X $CFLAGS " != "X$no_werror_CFLAGS"; then CFLAGS="$no_werror_CFLAGS" WERRORFLAGS=-Werror fi @@ -2965,61 +3672,33 @@ erl_top=${ERL_TOP} # echo X # echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -ac_aux_dir= -for ac_dir in $srcdir/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in $srcdir/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -# -# To configure for free source run ./configure --host=free_source -# -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -3038,21 +3717,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -3071,18 +3751,116 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=$host + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi -if test "$cross_compiling" = "yes"; then - CROSS_COMPILING=yes -else - CROSS_COMPILING=no +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 fi - +if test "$cross_compiling" = "yes"; then + CROSS_COMPILING=yes +else + CROSS_COMPILING=no +fi + + + erl_xcomp_without_sysroot=no if test "$cross_compiling" = "yes"; then test "$erl_xcomp_sysroot" != "" || erl_xcomp_without_sysroot=yes @@ -3093,6 +3871,15 @@ else fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3101,11 +3888,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3113,11 +3901,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3128,11 +3920,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3141,11 +3933,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -3153,11 +3946,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3168,11 +3965,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -3180,8 +3977,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -3194,11 +3991,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3206,11 +4004,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3221,11 +4023,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3234,11 +4036,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3247,15 +4050,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3271,18 +4078,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3293,11 +4100,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3305,11 +4113,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3320,11 +4132,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3337,11 +4149,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -3349,11 +4162,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3364,11 +4181,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3380,34 +4197,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi +else + CC="$ac_cv_prog_CC" fi fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3417,7 +4338,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -3425,7 +4346,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3437,9 +4358,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -3460,11 +4381,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -3481,7 +4403,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -3497,44 +4419,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -3548,15 +4472,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3565,7 +4489,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3577,8 +4501,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3586,10 +4510,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3597,39 +4521,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3643,11 +4568,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3656,31 +4582,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3690,29 +4617,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3721,57 +4652,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3786,94 +4720,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3883,11 +4867,12 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 -$as_echo_n "checking for library containing strerror... " >&6; } -if ${ac_cv_search_strerror+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 +printf %s "checking for library containing strerror... " >&6; } +if test ${ac_cv_search_strerror+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3895,46 +4880,48 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char strerror (); int -main () +main (void) { return strerror (); ; return 0; } _ACEOF -for ac_lib in '' cposix; do +for ac_lib in '' cposix +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_strerror=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_strerror+:} false; then : + if test ${ac_cv_search_strerror+y} +then : break fi done -if ${ac_cv_search_strerror+:} false; then : +if test ${ac_cv_search_strerror+y} +then : -else +else $as_nop ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 -$as_echo "$ac_cv_search_strerror" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 +printf "%s\n" "$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -3946,7 +4933,8 @@ ENABLE_ALLOC_TYPE_VARS= # Check whether --enable-bootstrap-only was given. -if test "${enable_bootstrap_only+set}" = set; then : +if test ${enable_bootstrap_only+y} +then : enableval=$enable_bootstrap_only; if test "X$enableval" = "Xyes"; then # Disable stuff not necessary in a bootstrap only system in order # to speed up things by reducing the amount of stuff needing to be @@ -3962,73 +4950,80 @@ fi # Check whether --enable-dirty-schedulers-test was given. -if test "${enable_dirty_schedulers_test+set}" = set; then : +if test ${enable_dirty_schedulers_test+y} +then : enableval=$enable_dirty_schedulers_test; case "$enableval" in yes) enable_dirty_schedulers_test=yes ;; *) enable_dirty_schedulers_test=no ;; esac -else +else $as_nop enable_dirty_schedulers_test=no fi # Check whether --enable-smp-require-native-atomics was given. -if test "${enable_smp_require_native_atomics+set}" = set; then : +if test ${enable_smp_require_native_atomics+y} +then : enableval=$enable_smp_require_native_atomics; case "$enableval" in no) smp_require_native_atomics=no ;; *) smp_require_native_atomics=yes ;; esac -else +else $as_nop smp_require_native_atomics=yes fi # Check whether --with-termcap was given. -if test "${with_termcap+set}" = set; then : +if test ${with_termcap+y} +then : withval=$with_termcap; -else +else $as_nop with_termcap=yes fi # Check whether --enable-lock-checking was given. -if test "${enable_lock_checking+set}" = set; then : +if test ${enable_lock_checking+y} +then : enableval=$enable_lock_checking; case "$enableval" in no) enable_lock_check=no ;; *) enable_lock_check=yes ;; esac -else +else $as_nop enable_lock_check=no fi # Check whether --enable-lock-counter was given. -if test "${enable_lock_counter+set}" = set; then : +if test ${enable_lock_counter+y} +then : enableval=$enable_lock_counter; case "$enableval" in no) enable_lock_count=no ;; *) enable_lock_count=yes ;; esac -else +else $as_nop enable_lock_count=no fi # Check whether --enable-kernel-poll was given. -if test "${enable_kernel_poll+set}" = set; then : +if test ${enable_kernel_poll+y} +then : enableval=$enable_kernel_poll; case "$enableval" in no) enable_kernel_poll=no ;; *) enable_kernel_poll=yes ;; esac -else +else $as_nop enable_kernel_poll=unknown fi # Check whether --enable-sctp was given. -if test "${enable_sctp+set}" = set; then : +if test ${enable_sctp+y} +then : enableval=$enable_sctp; case "x$enableval" in xno|xyes|xlib|x) ;; @@ -4040,44 +5035,48 @@ fi # Check whether --enable-jit was given. -if test "${enable_jit+set}" = set; then : +if test ${enable_jit+y} +then : enableval=$enable_jit; case "$enableval" in no) enable_jit=no ;; *) enable_jit=yes ;; esac -else +else $as_nop enable_jit=auto fi # Check whether --enable-m64-build was given. -if test "${enable_m64_build+set}" = set; then : +if test ${enable_m64_build+y} +then : enableval=$enable_m64_build; case "$enableval" in no) enable_m64_build=no ;; *) enable_m64_build=yes ;; esac -else +else $as_nop enable_m64_build=no fi # Check whether --enable-m32-build was given. -if test "${enable_m32_build+set}" = set; then : +if test ${enable_m32_build+y} +then : enableval=$enable_m32_build; case "$enableval" in no) enable_m32_build=no ;; *) enable_m32_build=yes ;; esac -else +else $as_nop enable_m32_build=no fi # Check whether --with-dynamic-trace was given. -if test "${with_dynamic_trace+set}" = set; then : +if test ${with_dynamic_trace+y} +then : withval=$with_dynamic_trace; fi @@ -4090,17 +5089,17 @@ case "$with_dynamic_trace" in no) DYNAMIC_TRACE_FRAMEWORK=;; lttng) -$as_echo "#define USE_LTTNG 1" >>confdefs.h +printf "%s\n" "#define USE_LTTNG 1" >>confdefs.h DYNAMIC_TRACE_FRAMEWORK=lttng;; dtrace) -$as_echo "#define USE_DTRACE 1" >>confdefs.h +printf "%s\n" "#define USE_DTRACE 1" >>confdefs.h DYNAMIC_TRACE_FRAMEWORK=dtrace;; systemtap) -$as_echo "#define USE_SYSTEMTAP 1" >>confdefs.h +printf "%s\n" "#define USE_SYSTEMTAP 1" >>confdefs.h DYNAMIC_TRACE_FRAMEWORK=systemtap;; *) @@ -4109,12 +5108,13 @@ esac if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then -$as_echo "#define USE_DYNAMIC_TRACE 1" >>confdefs.h +printf "%s\n" "#define USE_DYNAMIC_TRACE 1" >>confdefs.h fi # Check whether --enable-vm-probes was given. -if test "${enable_vm_probes+set}" = set; then : +if test ${enable_vm_probes+y} +then : enableval=$enable_vm_probes; case "$enableval" in no) use_vm_probes=no ;; *) @@ -4124,7 +5124,7 @@ if test "${enable_vm_probes+set}" = set; then : as_fn_error $? "Can not enable VM probes without any dynamic tracing framework!" "$LINENO" 5; fi;; esac -else +else $as_nop if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then use_vm_probes=yes ; else @@ -4138,14 +5138,15 @@ if test X"$DYNAMIC_TRACE_FRAMEWORK" != X"lttng"; then if test X"$use_vm_probes" = X"yes"; then USE_VM_PROBES=yes -$as_echo "#define USE_VM_PROBES 1" >>confdefs.h +printf "%s\n" "#define USE_VM_PROBES 1" >>confdefs.h fi fi # Check whether --with-assumed-cache-line-size was given. -if test "${with_assumed_cache_line_size+set}" = set; then : +if test ${with_assumed_cache_line_size+y} +then : withval=$with_assumed_cache_line_size; fi @@ -4161,34 +5162,34 @@ case "$with_assumed_cache_line_size" in esac -cat >>confdefs.h <<_ACEOF -#define ASSUMED_CACHE_LINE_SIZE $with_assumed_cache_line_size -_ACEOF +printf "%s\n" "#define ASSUMED_CACHE_LINE_SIZE $with_assumed_cache_line_size" >>confdefs.h # Check whether --enable-systemd was given. -if test "${enable_systemd+set}" = set; then : +if test ${enable_systemd+y} +then : enableval=$enable_systemd; -else +else $as_nop enable_systemd=no fi # Check whether --with-microstate-accounting was given. -if test "${with_microstate_accounting+set}" = set; then : +if test ${with_microstate_accounting+y} +then : withval=$with_microstate_accounting; -else +else $as_nop with_microstate_accounting=yes fi case "$with_microstate_accounting" in yes) -$as_echo "#define ERTS_ENABLE_MSACC 1" >>confdefs.h +printf "%s\n" "#define ERTS_ENABLE_MSACC 1" >>confdefs.h ;; extra) -$as_echo "#define ERTS_ENABLE_MSACC 2" >>confdefs.h +printf "%s\n" "#define ERTS_ENABLE_MSACC 2" >>confdefs.h ;; *) ;; esac @@ -4202,18 +5203,18 @@ else fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking OTP release" >&5 -$as_echo_n "checking OTP release... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OTP release" >&5 +printf %s "checking OTP release... " >&6; } SYSTEM_VSN=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYSTEM_VSN" >&5 -$as_echo "$SYSTEM_VSN" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SYSTEM_VSN" >&5 +printf "%s\n" "$SYSTEM_VSN" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking OTP version" >&5 -$as_echo_n "checking OTP version... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OTP version" >&5 +printf %s "checking OTP version... " >&6; } OTP_VERSION=`cat $ERL_TOP/OTP_VERSION` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTP_VERSION" >&5 -$as_echo "$OTP_VERSION" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTP_VERSION" >&5 +printf "%s\n" "$OTP_VERSION" >&6; } if test X${enable_m64_build} = Xyes; then @@ -4238,18 +5239,20 @@ else fi # Check whether --enable-static-nifs was given. -if test "${enable_static_nifs+set}" = set; then : +if test ${enable_static_nifs+y} +then : enableval=$enable_static_nifs; STATIC_NIFS="$enableval" -else +else $as_nop STATIC_NIFS=no fi # Check whether --enable-static-drivers was given. -if test "${enable_static_drivers+set}" = set; then : +if test ${enable_static_drivers+y} +then : enableval=$enable_static_drivers; STATIC_DRIVERS="$enableval" -else +else $as_nop STATIC_DRIVERS=no fi @@ -4257,24 +5260,24 @@ fi # Check whether --with-ets-write-concurrency-locks was given. -if test "${with_ets_write_concurrency_locks+set}" = set; then : +if test ${with_ets_write_concurrency_locks+y} +then : withval=$with_ets_write_concurrency_locks; fi if test X"$with_ets_write_concurrency_locks" != X""; then -cat >>confdefs.h <<_ACEOF -#define ERTS_DB_HASH_LOCK_CNT $with_ets_write_concurrency_locks -_ACEOF +printf "%s\n" "#define ERTS_DB_HASH_LOCK_CNT $with_ets_write_concurrency_locks" >>confdefs.h fi # Check whether --with-spectre-mitigation was given. -if test "${with_spectre_mitigation+set}" = set; then : +if test ${with_spectre_mitigation+y} +then : withval=$with_spectre_mitigation; -else +else $as_nop with_spectre_mitigation=no fi @@ -4288,31 +5291,36 @@ esac i_noretpoline_attr="" -if test X"$with_spectre_mitigation" != X"no"; then +if test X"$with_spectre_mitigation" != X"no" +then : + CFLAGS="$CFLAGS -mindirect-branch=thunk" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for spectre mitigation" >&5 -$as_echo_n "checking for spectre mitigation... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for spectre mitigation" >&5 +printf %s "checking for spectre mitigation... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop as_fn_error $? "no" "$LINENO" 5 fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + if test X"$with_spectre_mitigation" = X"incomplete" +then : - if test X"$with_spectre_mitigation" = X"incomplete"; then # gcc and clang support this attribute if they're recent enough. Note # that we must compile with -Werror to check for actual support as they # warn rather than error out on unsupported attributes. @@ -4321,37 +5329,45 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext i_preserve_cflags="$CFLAGS" CFLAGS="$CFLAGS -Werror" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether spectre mitigation can be disabled on a per-function basis" >&5 -$as_echo_n "checking whether spectre mitigation can be disabled on a per-function basis... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether spectre mitigation can be disabled on a per-function basis" >&5 +printf %s "checking whether spectre mitigation can be disabled on a per-function basis... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $i_noretpoline_attr int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop as_fn_error $? "no" "$LINENO" 5 fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$i_preserve_cflags" - fi + fi +fi + + +printf "%s\n" "#define ERTS_NO_RETPOLINE $i_noretpoline_attr" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ERTS_NO_RETPOLINE $i_noretpoline_attr -_ACEOF +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -4361,11 +5377,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4373,11 +5390,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4388,11 +5409,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4401,11 +5422,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4413,11 +5435,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4428,11 +5454,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -4440,8 +5466,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -4454,11 +5480,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4466,11 +5493,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4481,11 +5512,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4494,11 +5525,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4507,15 +5539,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4531,18 +5567,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4553,11 +5589,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4565,11 +5602,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4580,11 +5621,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4597,11 +5638,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4609,11 +5651,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4624,11 +5670,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4640,8 +5686,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -4649,25 +5695,129 @@ esac fi fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -4677,20 +5827,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -4700,29 +5851,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -4731,57 +5886,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -4796,94 +5954,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -4895,878 +6103,784 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -case $host_os in - linux*) CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE";; - aix*|os400*) - # * _ALL_SOURCE: Required to get the winsize structure for TIOCSWINSZ. - # * _LINUX_SOURCE_COMPAT: Not required, but makes some libc functions - # behave closer to glibc assumptions. - CPPFLAGS="$CPPFLAGS -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" - ;; - win32) - # The ethread library requires _WIN32_WINNT of at least 0x0403. - # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" - ;; - *) - ;; -esac - -if test "X$windows_environment_" != "Xchecked"; then -windows_environment_=checked -MIXED_CYGWIN=no -MIXED_MSYS=no -MIXED_VSL=no -MIXED_VC=no -MIXED_MINGW=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 -$as_echo_n "checking for mixed mingw-gcc and native VC++ environment... " >&6; } -if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then - if test -x /usr/bin/msys-?.0.dll; then - CFLAGS="$CFLAGS -O2" - MIXED_MSYS=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 -$as_echo "MSYS and VC" >&6; } - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - elif test -x /usr/bin/cygpath; then - CFLAGS="$CFLAGS -O2" - MIXED_CYGWIN=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 -$as_echo "Cygwin and VC" >&6; } - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - elif test -x /bin/wslpath; then - CFLAGS="$CFLAGS -O2" - MIXED_WSL=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 -$as_echo "WSL and VC" >&6; } - MIXED_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } - as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 - fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS -if test "x$MIXED_MSYS" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 -$as_echo_n "checking for mixed cygwin and native MinGW environment... " >&6; } - if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then - if test -x /usr/bin/cygpath; then - CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - MIXED_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } - as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 -$as_echo_n "checking for mixed MSYS and native MinGW environment... " >&6; } - if test "x$GCC" = x"yes"; then - if test -x /usr/bin/msys-=.0.dll; then - CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - MIXED_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } - as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 -$as_echo_n "checking if we mix cygwin with any native compiler... " >&6; } -if test "X$MIXED_CYGWIN" = "Xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 -$as_echo_n "checking if we mix msys with another native compiler... " >&6; } -if test "X$MIXED_MSYS" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 -$as_echo_n "checking if we mix WSL with another native compiler... " >&6; } -if test "X$MIXED_WSL" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi + test -n "$CXX" && break + done fi - - - -ERTS_CONFIG_H_IDIR="-I${ERL_TOP}/erts/$host" - - -extra_flags="$ERTS_CONFIG_H_IDIR $OTP_EXTRA_FLAGS" -CFLAGS="$CFLAGS $extra_flags" -DEBUG_CFLAGS="-g $CPPFLAGS $extra_flags $DEBUG_CFLAGS" -DEBUG_FLAGS=-g - - -case $CFLAGS in - *-m64*) - case $DEBUG_CFLAGS in - *-m64*) - ;; - *) - DEBUG_CFLAGS="-m64 $DEBUG_CFLAGS" - ;; - esac - ;; - *-m32*) - case $DEBUG_CFLAGS in - *-m32*) - ;; - *) - DEBUG_CFLAGS="-m32 $DEBUG_CFLAGS" - ;; - esac - ;; - *) - ;; -esac - -lfs_conf=ok -lfs_source=none -if test "${LFS_CFLAGS+set}" = "set" || \ - test "${LFS_LDFLAGS+set}" = "set" || \ - test "${LFS_LIBS+set}" = "set"; then - lfs_source=user -else - -if test "$cross_compiling" != "yes"; then - # Extract the first word of "getconf", so it can be a program name with args. -set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$GETCONF"; then - ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_GETCONF="getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_prog_GETCONF" && ac_cv_prog_GETCONF="false" -fi -fi -GETCONF=$ac_cv_prog_GETCONF -if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -else - host_getconf="$host_alias-getconf" - # Extract the first word of "$host_getconf", so it can be a program name with args. -set dummy $host_getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$GETCONF"; then - ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_GETCONF="$host_getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS - test -z "$ac_cv_prog_GETCONF" && ac_cv_prog_GETCONF="false" fi fi -GETCONF=$ac_cv_prog_GETCONF -if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then - GETCONF= - prfx="$erl_xcomp_sysroot" - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. -set dummy ${ac_tool_prefix}getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $GETCONF in - [\\/]* | ?:[\\/]*) - ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" -for as_dir in $as_dummy -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi + test -n "$ac_ct_CXX" && break done - done -IFS=$as_save_IFS - ;; + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; esac + CXX=$ac_ct_CXX + fi fi -GETCONF=$ac_cv_path_GETCONF -if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - + fi fi -if test -z "$ac_cv_path_GETCONF"; then - ac_pt_GETCONF=$GETCONF - # Extract the first word of "getconf", so it can be a program name with args. -set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $ac_pt_GETCONF in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" -for as_dir in $as_dummy -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } done - done -IFS=$as_save_IFS - ;; -esac -fi -ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF -if test -n "$ac_pt_GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 -$as_echo "$ac_pt_GETCONF" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +printf %s "checking whether the compiler supports GNU C++... " >&6; } +if test ${ac_cv_cxx_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ - if test "x$ac_pt_GETCONF" = x; then - GETCONF="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - GETCONF=$ac_pt_GETCONF - fi -else - GETCONF="$ac_cv_path_GETCONF" -fi +int +main (void) +{ +#ifndef __GNUC__ + choke me +#endif - fi + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + ac_compiler_gnu=yes +else $as_nop + ac_compiler_gnu=no fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - test "$GETCONF" = "false" || lfs_source=getconf fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test "$lfs_source" = "none"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to check for large file support flags; no getconf is available" >&5 -$as_echo "$as_me: WARNING: Do not know how to check for large file support flags; no getconf is available" >&2;} +if test $ac_compiler_gnu = yes; then + GXX=yes else - for var in CFLAGS LDFLAGS LIBS; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for large file support $var" >&5 -$as_echo_n "checking for large file support $var... " >&6; } - if test $lfs_source = user; then - eval "lfs_val=\"\$LFS_$var\"" - else - eval "lfs_var=LFS_$var" - lfs_val=`$GETCONF $lfs_var 2>/dev/null` || lfs_conf=failed - if test $lfs_conf = failed; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } - break - fi - eval "$lfs_var=\"$lfs_val\"" - fi - test "$lfs_val" != "" || lfs_val=none - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lfs_val" >&5 -$as_echo "$lfs_val" >&6; } - done - if test $lfs_conf = failed; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Check for large file support flags failed; $GETCONF failed" >&5 -$as_echo "$as_me: WARNING: Check for large file support flags failed; $GETCONF failed" >&2;} - else - CFLAGS="$CFLAGS $LFS_CFLAGS" - DEBUG_CFLAGS="$DEBUG_CFLAGS $LFS_CFLAGS" - LDFLAGS="$LDFLAGS $LFS_LDFLAGS" - LIBS="$LIBS $LFS_LIBS" - fi + GXX= fi - -if test "x$GCC" = xyes; then - # Treat certain GCC warnings as errors - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-Werror=return-type $WERRORFLAGS"; - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +ac_test_CXXFLAGS=${CXXFLAGS+y} +ac_save_CXXFLAGS=$CXXFLAGS +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +printf %s "checking whether $CXX accepts -g... " >&6; } +if test ${ac_cv_prog_cxx_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { -return 0; + ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - can_enable_flag=true -else - can_enable_flag=false -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - WERRORFLAGS="-Werror=return-type $WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=implicit to WERRORFLAGS (via CFLAGS)... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-Werror=implicit $WERRORFLAGS"; - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_g=yes +else $as_nop + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { -return 0; + ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - can_enable_flag=true -else - can_enable_flag=false -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - WERRORFLAGS="-Werror=implicit $WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - +if ac_fn_cxx_try_compile "$LINENO" +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=undef to WERRORFLAGS (via CFLAGS)... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-Werror=undef $WERRORFLAGS"; - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else $as_nop + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { -return 0; + ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - can_enable_flag=true -else - can_enable_flag=false +if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - WERRORFLAGS="-Werror=undef $WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - - - # until the emulator can handle this, I suggest we turn it off! - #WFLAGS="-Wall -Wshadow -Wcast-qual -Wmissing-declarations" - WFLAGS="-Wall -Wstrict-prototypes -Wpointer-arith" - - case "$host_cpu" in - tile*) - # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, - # and too strict for our taste. - ;; - *) - WFLAGS="$WFLAGS -Wmissing-prototypes";; - esac - - saved_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Wdeclaration-after-statement" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +if test $ac_test_CXXFLAGS; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_prog_cxx_stdcxx=no +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 +printf %s "checking for $CXX option to enable C++11 features... " >&6; } +if test ${ac_cv_prog_cxx_11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_11=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - -int -main () -{ -; - ; - return 0; -} +$ac_cxx_conftest_cxx11_program _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - warn_decl_after_st=true -else - warn_decl_after_st=false +for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx11=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test "X$warn_decl_after_st" = "Xtrue"; then - WFLAGS="$WFLAGS -Wdeclaration-after-statement" - fi - CFLAGS=$saved_CFLAGS - - # Use -fno-common for gcc, that is link error if multiple definitions of - # global variables are encountered. This is ISO C compliant. - # Until version 10, gcc has had -fcommon as default, which allows and merges - # such dubious duplicates. - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -fno-common to CFLAGS (via CFLAGS)... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-fno-common $CFLAGS"; - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx11" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx11" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 + ac_prog_cxx_stdcxx=cxx11 +fi +fi +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 +printf %s "checking for $CXX option to enable C++98 features... " >&6; } +if test ${ac_cv_prog_cxx_98+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_98=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - -int -main () -{ -return 0; - ; - return 0; -} +$ac_cxx_conftest_cxx98_program _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - can_enable_flag=true -else - can_enable_flag=false +for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx98=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx98" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="-fno-common $CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -else - WFLAGS="" - WERRORFLAGS=${WERRORFLAGS:-""} +if test "x$ac_cv_prog_cxx_cxx98" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx98" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx98" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 + ac_prog_cxx_stdcxx=cxx98 +fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking C99 support" >&5 -$as_echo_n "checking C99 support... " >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int -main () -{ -#if __STDC_VERSION__ < 199901L - #error "Not C99" -#endif - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="-std=gnu99 $CFLAGS" - DEBUG_CFLAGS="-std=gnu99 $DEBUG_CFLAGS" + ac_cv_path_GREP=$GREP fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS for -O switch" >&5 -$as_echo_n "checking CFLAGS for -O switch... " >&6; } -case "$CFLAGS" in - *-O*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } ;; - *) - as_fn_error $? " - CFLAGS must contain a -O flag. If you need to edit the CFLAGS you probably - also want to add the default CFLAGS. The default CFLAGS are \"-O2 -g\". - If you want to build erts without any optimization, pass -O0 to CFLAGS." "$LINENO" 5 ;; -esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" -## Check if we can do profile guided optimization of beam_emu - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-generate -Werror..." >&5 -$as_echo_n "checking whether $CC accepts -fprofile-generate -Werror...... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-generate -Werror $CFLAGS"; - if test "$cross_compiling" = yes; then : - can_enable_flag=false -else +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - +#include + Syntax error _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - return 0; -else - can_enable_flag=true +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break fi +rm -f conftest.err conftest.i conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - PROFILE_GENERATE=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - PROFILE_GENERATE=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + break +fi + done + ac_cv_prog_CPP=$CPP - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-use -Werror..." >&5 -$as_echo_n "checking whether $CC accepts -fprofile-use -Werror...... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-use -Werror $CFLAGS"; - if test "$cross_compiling" = yes; then : - can_enable_flag=false +fi + CPP=$ac_cv_prog_CPP else + ac_cv_prog_CPP=$CPP +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - +#include + Syntax error _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - return 0; -else - can_enable_flag=true -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - PROFILE_USE=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - PROFILE_USE=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi +if ac_fn_c_try_cpp "$LINENO" +then : +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-use -fprofile-correction -Werror..." >&5 -$as_echo_n "checking whether $CC accepts -fprofile-use -fprofile-correction -Werror...... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-use -fprofile-correction -Werror $CFLAGS"; - if test "$cross_compiling" = yes; then : - can_enable_flag=false -else + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - +#include _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - return 0; -else - can_enable_flag=true -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break fi +rm -f conftest.err conftest.i conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - PROFILE_CORRECTION=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - PROFILE_CORRECTION=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi -if test "X$PROFILE_CORRECTION" = "Xtrue"; then - saved_CFLAGS=$CFLAGS - saved_LDFLAGS=$LDFLAGS - CFLAGS="-fprofile-generate $saved_CFLAGS" - LDFLAGS="-fprofile-generate $saved_LDFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC links with -fprofile-generate" >&5 -$as_echo_n "checking whether $CC links with -fprofile-generate... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PROFILE_GENERATE=true +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - PROFILE_GENERATE=false +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - CFLAGS=$saved_CFLAGS - LDFLAGS=$saved_LDFLAGS fi - -## Check if this is clang - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-instr-generate -Werror..." >&5 -$as_echo_n "checking whether $CC accepts -fprofile-instr-generate -Werror...... " >&6; } - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-instr-generate -Werror $CFLAGS"; - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - can_enable_flag=true +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } else - can_enable_flag=false + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - PROFILE_INSTR_GENERATE=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - PROFILE_INSTR_GENERATE=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - -if test "X$PROFILE_INSTR_GENERATE" = "Xtrue"; then - # It was clang, now we also have to check if we have llvm-profdata and that - # we can link programs with -fprofile-instr-use - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-instr-generate -Werror $saved_CFLAGS" - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: Disabling PGO when cross-compiling" >&5 -$as_echo "$as_me: Disabling PGO when cross-compiling" >&6;} -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int -main () -{ - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - # Extract the first word of "llvm-profdata", so it can be a program name with args. -set dummy llvm-profdata; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LLVM_PROFDATA+:} false; then : - $as_echo_n "(cached) " >&6 +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else - case $LLVM_PROFDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy="$PATH:/Library/Developer/CommandLineTools/usr/bin" -for as_dir in $as_dummy +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS - ;; -esac fi -LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA -if test -n "$LLVM_PROFDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 -$as_echo "$LLVM_PROFDATA" >&6; } +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi - for ac_prog in xcrun +for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_XCRUN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$XCRUN"; then - ac_cv_prog_XCRUN="$XCRUN" # Let the user override the test. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_YACC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_XCRUN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5775,1258 +6889,1503 @@ IFS=$as_save_IFS fi fi -XCRUN=$ac_cv_prog_XCRUN -if test -n "$XCRUN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XCRUN" >&5 -$as_echo "$XCRUN" >&6; } +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +printf "%s\n" "$YACC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - test -n "$XCRUN" && break + test -n "$YACC" && break done +test -n "$YACC" || YACC="yacc" - if test "X$XCRUN" != "X" -a "X$LLVM_PROFDATA" = "X"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $XCRUN $LLVM_PROFDATA" >&5 -$as_echo_n "checking for $XCRUN $LLVM_PROFDATA... " >&6; } - if $XCRUN $LLVM_PROFDATA --help 2>& 5 >& 5; then - LLVM_PROFDATA="$XCRUN $LLVM_PROFDATA" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - fi - - if test "X$LLVM_PROFDATA" != "X"; then - CFLAGS="-fprofile-instr-use=default.profdata $saved_CFLAGS"; - $LLVM_PROFDATA merge -output=default.profdata *.profraw; - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-instr-use=default.profdata -Werror" >&5 -$as_echo_n "checking whether $CC accepts -fprofile-instr-use=default.profdata -Werror... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +for ac_prog in perl5 perl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PERL+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="/usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH}" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PROFILE_INSTR_USE=true -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - PROFILE_INSTR_USE=false + ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - rm -f default.profdata - fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf "%s\n" "$PERL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + + + test -n "$PERL" && break +done +test -n "$PERL" || PERL="false" + +if test "$PERL" = "false"; then + ac_cv_path_PERL=false + PERL=false fi - rm -f *.profraw - CFLAGS=$saved_CFLAGS; +if test "$ac_cv_path_PERL" = false; then + as_fn_error $? "Perl version 5 is required to build the emulator!" "$LINENO" 5 +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +printf %s "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +printf "%s\n" "no, using $LN_S" >&6; } fi -# Check whether --enable-pgo was given. -if test "${enable_pgo+set}" = set; then : - enableval=$enable_pgo; case "$enableval" in - no) enable_pgo=no ;; - *) enable_pgo=yes ;; +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } else - enable_pgo=default + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -USE_PGO=false -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to do PGO of erts" >&5 -$as_echo_n "checking whether to do PGO of erts... " >&6; } -if test $enable_pgo = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, disabled by user" >&5 -$as_echo "no, disabled by user" >&6; } -elif test $CROSS_COMPILING = yes; then - if test $enable_pgo = yes; then - as_fn_error $? "cannot use PGO when cross-compiling" "$LINENO" 5 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, cross compiling" >&5 -$as_echo "no, cross compiling" >&6; } +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 fi -elif test "X$host" = "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, not supported in windows" >&5 -$as_echo "no, not supported in windows" >&6; } -elif test "X$PROFILE_GENERATE" = "Xtrue" -a "X$PROFILE_USE" = "Xtrue" -a "X$PROFILE_CORRECTION" = "Xtrue"; then - ## We need -fprofile-generate and -fprofile-correction support to use PGO with - ## gcc as multiple threads run within the executed object files - USE_PGO=true - PROFILE_COMPILER=gcc - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, using -fprofile-generate -fprofile-correction" >&5 -$as_echo "yes, using -fprofile-generate -fprofile-correction" >&6; } -elif test "X$PROFILE_INSTR_GENERATE" = "Xtrue" -a "X$PROFILE_INSTR_USE" = "Xtrue"; then - USE_PGO=true - PROFILE_COMPILER=clang - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, using -fprofile-instr-generate" >&5 -$as_echo "yes, using -fprofile-instr-generate" >&6; } +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } else - if test $enable_pgo = yes; then - as_fn_error $? "cannot use PGO with this compiler" "$LINENO" 5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR fi +else + AR="$ac_cv_prog_AR" fi -USE_PGO=false - +if test "$ac_cv_prog_AR" = false; then + as_fn_error $? "No 'ar' command found in PATH" "$LINENO" 5 +fi +# +# Get programs needed for building the documentation +# -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= +## Delete previous failed configure results +if test -f doc/CONF_INFO; then + rm -f doc/CONF_INFO fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 + +for ac_prog in xsltproc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_XSLTPROC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$XSLTPROC"; then + ac_cv_prog_XSLTPROC="$XSLTPROC" # Let the user override the test. else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_XSLTPROC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS -else - # Broken: fails on valid input. -continue fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue +fi +XSLTPROC=$ac_cv_prog_XSLTPROC +if test -n "$XSLTPROC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 +printf "%s\n" "$XSLTPROC" >&6; } else - # Passes both tests. -ac_preproc_ok=: -break + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f conftest.err conftest.i conftest.$ac_ext -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - done - ac_cv_prog_CPP=$CPP + test -n "$XSLTPROC" && break +done +if test -z "$XSLTPROC"; then + echo "xsltproc" >> doc/CONF_INFO + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No 'xsltproc' command found: the documentation cannot be built" >&5 +printf "%s\n" "$as_me: WARNING: No 'xsltproc' command found: the documentation cannot be built" >&2;} fi - CPP=$ac_cv_prog_CPP + +for ac_prog in fop +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_FOP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$FOP"; then + ac_cv_prog_FOP="$FOP" # Let the user override the test. else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_FOP="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS -else - # Broken: fails on valid input. -continue fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue +fi +FOP=$ac_cv_prog_FOP +if test -n "$FOP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 +printf "%s\n" "$FOP" >&6; } else - # Passes both tests. -ac_preproc_ok=: -break + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f conftest.err conftest.i conftest.$ac_ext + + test -n "$FOP" && break done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } +if test -z "$FOP"; then + FOP="$ERL_TOP/make/fakefop" + echo "fop" >> doc/CONF_INFO + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No 'fop' command found: going to generate placeholder PDF files" >&5 +printf "%s\n" "$as_me: WARNING: No 'fop' command found: going to generate placeholder PDF files" >&2;} fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +for ac_prog in xmllint +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_XMLLINT+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$XMLLINT"; then + ac_cv_prog_XMLLINT="$XMLLINT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_XMLLINT="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done done IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi + +fi +fi +XMLLINT=$ac_cv_prog_XMLLINT +if test -n "$XMLLINT"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XMLLINT" >&5 +printf "%s\n" "$XMLLINT" >&6; } else - ac_cv_path_GREP=$GREP + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi + + test -n "$XMLLINT" && break +done + +if test -z "$XMLLINT"; then + echo "xmllint" >> doc/CONF_INFO + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No 'xmllint' command found: can't run the xmllint target for the documentation" >&5 +printf "%s\n" "$as_me: WARNING: No 'xmllint' command found: can't run the xmllint target for the documentation" >&2;} fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" +case $host in + *-*-solaris*|free_source) + if test -x /usr/ucb/install; then + INSTALL="/usr/ucb/install -c" + fi + ;; + *) + ;; +esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST + # Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; esac - $ac_path_EGREP_found && break 3 - done - done done IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" +rm -rf conftest.one conftest.two conftest.dir -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include +fi + if test ${ac_cv_path_install+y}; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } -int -main () -{ +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to create a directory including parents" >&5 +printf %s "checking how to create a directory including parents... " >&6; } +if test ${ac_cv_prog_mkdir_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop +temp_name_base=config.$$ +temp_name=$temp_name_base/x/y/z +$INSTALL -d $temp_name >/dev/null 2>&1 +ac_cv_prog_mkdir_p=none +if test -d $temp_name; then + ac_cv_prog_mkdir_p="$INSTALL -d" else - ac_cv_header_stdc=no + mkdir -p $temp_name >/dev/null 2>&1 + if test -d $temp_name; then + ac_cv_prog_mkdir_p="mkdir -p" + fi fi -rm -f conftest* +rm -fr $temp_name_base fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_mkdir_p" >&5 +printf "%s\n" "$ac_cv_prog_mkdir_p" >&6; } -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include +case "${ac_cv_prog_mkdir_p}" in + none) as_fn_error $? "don't know how create directories with parents" "$LINENO" 5 ;; + *) INSTALL_DIR="$ac_cv_prog_mkdir_p" ;; +esac -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : -else - ac_cv_header_stdc=no -fi -rm -f conftest* +case $host_os in + darwin*) + INSTALL_DATA="$INSTALL_DATA -p";; + *) + ;; +esac -fi -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif +case $build in + *tile*) + INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" + INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" + ;; + *) + ;; +esac -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi +case $host_os in + linux*) CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE";; + aix*|os400*) + # * _ALL_SOURCE: Required to get the winsize structure for TIOCSWINSZ. + # * _LINUX_SOURCE_COMPAT: Not required, but makes some libc functions + # behave closer to glibc assumptions. + CPPFLAGS="$CPPFLAGS -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" + ;; + win32) + # The ethread library requires _WIN32_WINNT of at least 0x0403. + # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" + ;; + *) + ;; +esac -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then -$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +if test "X$windows_environment_" != "Xchecked"; then +windows_environment_=checked +MIXED_CYGWIN=no +MIXED_MSYS=no +MIXED_VSL=no + +MIXED_VC=no +MIXED_MINGW=no + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 +printf %s "checking for mixed mingw-gcc and native VC++ environment... " >&6; } +if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then + if test -x /usr/bin/msys-?.0.dll; then + CFLAGS="$CFLAGS -O2" + MIXED_MSYS=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 +printf "%s\n" "MSYS and VC" >&6; } + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + elif test -x /usr/bin/cygpath; then + CFLAGS="$CFLAGS -O2" + MIXED_CYGWIN=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 +printf "%s\n" "Cygwin and VC" >&6; } + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + elif test -x /bin/wslpath; then + CFLAGS="$CFLAGS -O2" + MIXED_WSL=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 +printf "%s\n" "WSL and VC" >&6; } + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } + as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF + +if test "x$MIXED_MSYS" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 +printf %s "checking for mixed cygwin and native MinGW environment... " >&6; } + if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="$CFLAGS -O2" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + MIXED_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } + as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 +printf %s "checking for mixed MSYS and native MinGW environment... " >&6; } + if test "x$GCC" = x"yes"; then + if test -x /usr/bin/msys-=.0.dll; then + CFLAGS="$CFLAGS -O2" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + MIXED_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } + as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi fi -done +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 +printf %s "checking if we mix cygwin with any native compiler... " >&6; } +if test "X$MIXED_CYGWIN" = "Xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 +printf %s "checking if we mix msys with another native compiler... " >&6; } +if test "X$MIXED_MSYS" = "Xyes" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 +printf %s "checking if we mix WSL with another native compiler... " >&6; } +if test "X$MIXED_WSL" = "Xyes" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_void_p=0 - fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +ERTS_CONFIG_H_IDIR="-I${ERL_TOP}/erts/$host" - # Needed for ARCH and smp checks below -if test "x$ac_cv_sizeof_void_p" = x8; then - EXTERNAL_WORD_SIZE=64 -else - EXTERNAL_WORD_SIZE=32 +extra_flags="$ERTS_CONFIG_H_IDIR $OTP_EXTRA_FLAGS" +CFLAGS="$CFLAGS $extra_flags" +DEBUG_FLAGS=-g -fi +lfs_conf=ok +lfs_source=none +if test "${LFS_CFLAGS+set}" = "set" || test "${LFS_LDFLAGS+set}" = "set" || test "${LFS_LIBS+set}" = "set" +then : -if test "x$host_alias" != "x"; then - chk_opsys_=$host_os -else - chk_opsys_=`uname -s` - if test "x$chk_opsys_" = "xSunOS"; then - chk_opsys_=$chk_opsys_`uname -r` - fi -fi -case $chk_opsys_ in - win32) OPSYS=win32;; - solaris2.*|SunOS5.*) OPSYS=sol2;; - linux*|Linux) OPSYS=linux;; - darwin|Darwin) OPSYS=darwin;; - freebsd|FreeBSD) OPSYS=freebsd;; - *) OPSYS=noopsys -esac + lfs_source=user +else $as_nop +if test "$cross_compiling" != "yes" +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking target hardware architecture" >&5 -$as_echo_n "checking target hardware architecture... " >&6; } - if test "x$host_alias" != "x" -a "x$host_cpu" != "x"; then - chk_arch_=$host_cpu - else - chk_arch_=`uname -m` - fi + # Extract the first word of "getconf", so it can be a program name with args. +set dummy getconf; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$GETCONF"; then + ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_GETCONF="getconf" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS - case $chk_arch_ in - sun4u) ARCH=ultrasparc;; - sparc64) ARCH=sparc64;; - sun4v) ARCH=ultrasparc;; - i86pc) ARCH=x86;; - i386) ARCH=x86;; - i486) ARCH=x86;; - i586) ARCH=x86;; - i686) ARCH=x86;; - x86_64) ARCH=amd64;; - amd64) ARCH=amd64;; - macppc) ARCH=ppc;; - powerpc) ARCH=ppc;; - ppc) ARCH=ppc;; - ppc64) ARCH=ppc64;; - ppc64le) ARCH=ppc64le;; - powerpc64) ARCH=ppc64;; - powerpc64le) ARCH=ppc64le;; - "Power Macintosh") ARCH=ppc;; - arm64) ARCH=arm64;; - armv5b) ARCH=arm;; - armv5teb) ARCH=arm;; - armv5tel) ARCH=arm;; - armv5tejl) ARCH=arm;; - armv6l) ARCH=arm;; - armv6hl) ARCH=arm;; - armv7l) ARCH=arm;; - armv7hl) ARCH=arm;; - armv8*) ARCH=arm;; - aarch64) ARCH=arm64;; - aarch*) ARCH=arm;; - tile) ARCH=tile;; - e2k) ARCH=e2k;; - *) ARCH=noarch;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ARCH" >&5 -$as_echo "$ARCH" >&6; } + test -z "$ac_cv_prog_GETCONF" && ac_cv_prog_GETCONF="false" +fi +fi +GETCONF=$ac_cv_prog_GETCONF +if test -n "$GETCONF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compilation mode forces ARCH adjustment" >&5 -$as_echo_n "checking whether compilation mode forces ARCH adjustment... " >&6; } - case "$ARCH-$ac_cv_sizeof_void_p" in - x86-8) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=x86 to ARCH=amd64" >&5 -$as_echo "yes: adjusting ARCH=x86 to ARCH=amd64" >&6; } - ARCH=amd64 - ;; - amd64-4) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=amd64 to ARCH=x86" >&5 -$as_echo "yes: adjusting ARCH=amd64 to ARCH=x86" >&6; } - ARCH=x86 - ;; - ultrasparc-8) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ultrasparc to ARCH=sparc64" >&5 -$as_echo "yes: adjusting ARCH=ultrasparc to ARCH=sparc64" >&6; } - ARCH=sparc64 - ;; - sparc64-4) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=sparc64 to ARCH=ultrasparc" >&5 -$as_echo "yes: adjusting ARCH=sparc64 to ARCH=ultrasparc" >&6; } - ARCH=ultrasparc - ;; - ppc64-4) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ppc64 to ARCH=ppc" >&5 -$as_echo "yes: adjusting ARCH=ppc64 to ARCH=ppc" >&6; } - ARCH=ppc - ;; - ppc-8) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ppc to ARCH=ppc64" >&5 -$as_echo "yes: adjusting ARCH=ppc to ARCH=ppc64" >&6; } - ARCH=ppc64 - ;; - arm-8) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=arm to ARCH=arm64" >&5 -$as_echo "yes: adjusting ARCH=arm to ARCH=arm64" >&6; } - ARCH=arm64 - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no: ARCH is $ARCH" >&5 -$as_echo "no: ARCH is $ARCH" >&6; } - ;; - esac +else $as_nop + host_getconf="$host_alias-getconf" + # Extract the first word of "$host_getconf", so it can be a program name with args. +set dummy $host_getconf; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$GETCONF"; then + ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_GETCONF="$host_getconf" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + test -z "$ac_cv_prog_GETCONF" && ac_cv_prog_GETCONF="false" +fi +fi +GETCONF=$ac_cv_prog_GETCONF +if test -n "$GETCONF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != "" +then : -case $ARCH-$OPSYS in - amd64-darwin*|arm64-darwin*) - { $as_echo "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to cope with 64bit Darwin" >&5 -$as_echo "$as_me: Adjusting LDFLAGS to cope with 64bit Darwin" >&6;} - case $LDFLAGS in - *-m64*) - ;; - *) - LDFLAGS="-m64 $LDFLAGS" - ;; - esac - ;; - *-darwin*) - case $LDFLAGS in - *-m32*) - ;; - *) - LDFLAGS="-m32 $LDFLAGS" - ;; - esac - ;; - *) - if test X${enable_m64_build} = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to use -m64" >&5 -$as_echo "$as_me: Adjusting LDFLAGS to use -m64" >&6;} - case $LDFLAGS in - *-m64*) - ;; - *) - LDFLAGS="-m64 $LDFLAGS" - ;; - esac - fi; - if test X${enable_m32_build} = Xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to use -m32" >&5 -$as_echo "$as_me: Adjusting LDFLAGS to use -m32" >&6;} ; - case $LDFLAGS in - *-m32*) - ;; - *) - LDFLAGS="-m32 $LDFLAGS" - ;; - esac ; - fi - ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if VM has to be linked with Carbon framework" >&5 -$as_echo_n "checking if VM has to be linked with Carbon framework... " >&6; } -case $ARCH-$OPSYS in - *-darwin*) - LIBCARBON="-framework Carbon -framework Cocoa" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ;; - *) - LIBCARBON= - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ;; -esac - - - -_search_path=/bin:/usr/bin:/usr/local/bin:$PATH - -# Extract the first word of "mkdir", so it can be a program name with args. -set dummy mkdir; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_MKDIR+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $MKDIR in + GETCONF= + prfx="$erl_xcomp_sysroot" + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. +set dummy ${ac_tool_prefix}getconf; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $GETCONF in [\\/]* | ?:[\\/]*) - ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a path. + ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $_search_path +as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" +for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_MKDIR="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS - test -z "$ac_cv_path_MKDIR" && ac_cv_path_MKDIR="false" ;; esac fi -MKDIR=$ac_cv_path_MKDIR -if test -n "$MKDIR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR" >&5 -$as_echo "$MKDIR" >&6; } +GETCONF=$ac_cv_path_GETCONF +if test -n "$GETCONF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -if test "$ac_cv_path_MKDIR" = false; then - as_fn_error $? "No 'mkdir' command found" "$LINENO" 5 fi - -# Extract the first word of "cp", so it can be a program name with args. -set dummy cp; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CP+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $CP in +if test -z "$ac_cv_path_GETCONF"; then + ac_pt_GETCONF=$GETCONF + # Extract the first word of "getconf", so it can be a program name with args. +set dummy getconf; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_GETCONF in [\\/]* | ?:[\\/]*) - ac_cv_path_CP="$CP" # Let the user override the test with a path. + ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $_search_path +as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" +for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS - test -z "$ac_cv_path_CP" && ac_cv_path_CP="false" ;; esac fi -CP=$ac_cv_path_CP -if test -n "$CP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 -$as_echo "$CP" >&6; } +ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF +if test -n "$ac_pt_GETCONF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 +printf "%s\n" "$ac_pt_GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - -if test "$ac_cv_path_CP" = false; then - as_fn_error $? "No 'cp' command found" "$LINENO" 5 + if test "x$ac_pt_GETCONF" = x; then + GETCONF="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + GETCONF=$ac_pt_GETCONF + fi +else + GETCONF="$ac_cv_path_GETCONF" fi -_search_path= - - -# Remove old configuration information. -# Next line should be before first output to CONN_INFO. So this is -# just the right place. -rm -f "$ERL_TOP/erts/CONF_INFO" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we are building a sharing-preserving emulator" >&5 -$as_echo_n "checking if we are building a sharing-preserving emulator... " >&6; } -if test "$enable_sharing_preserving" = "yes"; then - -$as_echo "#define SHCOPY 1" >>confdefs.h +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } fi + test "$GETCONF" = "false" || lfs_source=getconf -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if test "$lfs_source" = "none"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to check for large file support flags; no getconf is available" >&5 +printf "%s\n" "$as_me: WARNING: Do not know how to check for large file support flags; no getconf is available" >&2;} else - # Broken: fails on valid input. -continue + for var in CFLAGS LDFLAGS LIBS; do + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for large file support $var" >&5 +printf %s "checking for large file support $var... " >&6; } + if test $lfs_source = user; then + eval "lfs_val=\"\$LFS_$var\"" + else + eval "lfs_var=LFS_$var" + lfs_val=`$GETCONF $lfs_var 2>/dev/null` || lfs_conf=failed + if test $lfs_conf = failed; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } + break + fi + eval "$lfs_var=\"$lfs_val\"" + fi + test "$lfs_val" != "" || lfs_val=none + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lfs_val" >&5 +printf "%s\n" "$lfs_val" >&6; } + done + if test $lfs_conf = failed; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Check for large file support flags failed; $GETCONF failed" >&5 +printf "%s\n" "$as_me: WARNING: Check for large file support flags failed; $GETCONF failed" >&2;} + else + CFLAGS="$CFLAGS $LFS_CFLAGS" + LDFLAGS="$LDFLAGS $LFS_LDFLAGS" + LIBS="$LIBS $LFS_LIBS" + fi fi -rm -f conftest.err conftest.i conftest.$ac_ext - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +if test "x$GCC" = xyes +then : + + # Treat certain GCC warnings as errors + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to WERRORFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-Werror=return-type $WERRORFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include + +int +main (void) +{ +return 0; + ; + return 0; +} _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + WERRORFLAGS="-Werror=return-type $WERRORFLAGS" - done - ac_cv_prog_CPP=$CPP +else $as_nop -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else - # Broken: fails on valid input. -continue fi -rm -f conftest.err conftest.i conftest.$ac_ext - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=implicit to WERRORFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-Werror=implicit $WERRORFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include + +int +main (void) +{ +return 0; + ; + return 0; +} _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + WERRORFLAGS="-Werror=implicit $WERRORFLAGS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=undef to WERRORFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-Werror=undef $WERRORFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + WERRORFLAGS="-Werror=undef $WERRORFLAGS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + # until the emulator can handle this, I suggest we turn it off! + #WFLAGS="-Wall -Wshadow -Wcast-qual -Wmissing-declarations" + WFLAGS="-Wall -Wstrict-prototypes -Wpointer-arith" + + case "$host_cpu" in + tile*) + # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, + # and too strict for our taste. + ;; + *) + WFLAGS="$WFLAGS -Wmissing-prototypes";; + esac + + saved_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Wdeclaration-after-statement" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + warn_decl_after_st=true +else $as_nop + warn_decl_after_st=false fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "X$warn_decl_after_st" = "Xtrue"; then + WFLAGS="$WFLAGS -Wdeclaration-after-statement" fi -done - done -IFS=$as_save_IFS + CFLAGS=$saved_CFLAGS + # Use -fno-common for gcc, that is link error if multiple definitions of + # global variables are encountered. This is ISO C compliant. + # Until version 10, gcc has had -fcommon as default, which allows and merges + # such dubious duplicates. + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-common to CFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fno-common $CFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + CFLAGS="-fno-common $CFLAGS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-strict-aliasing to CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-strict-aliasing to CFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fno-strict-aliasing $CFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + CFLAGS="-fno-strict-aliasing $CFLAGS" -for ac_prog in 'bison -y' byacc -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_YACC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$YACC"; then - ac_cv_prog_YACC="$YACC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_YACC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi + + +else $as_nop + + WFLAGS="" + WERRORFLAGS=${WERRORFLAGS:-""} + fi -YACC=$ac_cv_prog_YACC -if test -n "$YACC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 -$as_echo "$YACC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking C99 support" >&5 +printf %s "checking C99 support... " >&6; } + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + +#if __STDC_VERSION__ < 199901L + #error "Not C99" +#endif + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="-std=gnu99 $CFLAGS" fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test -n "$YACC" && break -done -test -n "$YACC" || YACC="yacc" -for ac_prog in perl5 perl -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PERL+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $PERL in - [\\/]* | ?:[\\/]*) - ac_cv_path_PERL="$PERL" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy="/usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH}" -for as_dir in $as_dummy -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - ;; -esac + +## Check if we can do profile guided optimization of beam_emu + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-generate -Werror..." >&5 +printf %s "checking whether $CC accepts -fprofile-generate -Werror...... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-generate -Werror $CFLAGS"; + if test "$cross_compiling" = yes +then : + can_enable_flag=false +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + return 0; +else $as_nop + can_enable_flag=true fi -PERL=$ac_cv_path_PERL -if test -n "$PERL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 -$as_echo "$PERL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : - test -n "$PERL" && break -done -test -n "$PERL" || PERL="false" + PROFILE_GENERATE=true + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + PROFILE_GENERATE=false + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -if test "$PERL" = "false"; then - ac_cv_path_PERL=false - PERL=false fi -if test "$ac_cv_path_PERL" = false; then - as_fn_error $? "Perl version 5 is required to build the emulator!" "$LINENO" 5 + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-use -Werror..." >&5 +printf %s "checking whether $CC accepts -fprofile-use -Werror...... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-use -Werror $CFLAGS"; + if test "$cross_compiling" = yes +then : + can_enable_flag=false +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + return 0; +else $as_nop + can_enable_flag=true fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -$as_echo_n "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -$as_echo "no, using $LN_S" >&6; } +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + PROFILE_USE=true + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH +else $as_nop + + PROFILE_USE=false + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-use -fprofile-correction -Werror..." >&5 +printf %s "checking whether $CC accepts -fprofile-use -fprofile-correction -Werror...... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-use -fprofile-correction -Werror $CFLAGS"; + if test "$cross_compiling" = yes +then : + can_enable_flag=false +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + return 0; +else $as_nop + can_enable_flag=true +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + PROFILE_CORRECTION=true + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + PROFILE_CORRECTION=false + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + +if test "X$PROFILE_CORRECTION" = "Xtrue" +then : + + saved_CFLAGS=$CFLAGS + saved_LDFLAGS=$LDFLAGS + CFLAGS="-fprofile-generate $saved_CFLAGS" + LDFLAGS="-fprofile-generate $saved_LDFLAGS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC links with -fprofile-generate" >&5 +printf %s "checking whether $CC links with -fprofile-generate... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + PROFILE_GENERATE=true +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + PROFILE_GENERATE=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS=$saved_CFLAGS + LDFLAGS=$saved_LDFLAGS + +fi + +## Check if this is clang + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-instr-generate -Werror..." >&5 +printf %s "checking whether $CC accepts -fprofile-instr-generate -Werror...... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-instr-generate -Werror $CFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + PROFILE_INSTR_GENERATE=true + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + PROFILE_INSTR_GENERATE=false + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + +if test "X$PROFILE_INSTR_GENERATE" = "Xtrue" +then : + + # It was clang, now we also have to check if we have llvm-profdata and that + # we can link programs with -fprofile-instr-use + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-instr-generate -Werror $saved_CFLAGS" + if test "$cross_compiling" = yes +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Disabling PGO when cross-compiling" >&5 +printf "%s\n" "$as_me: Disabling PGO when cross-compiling" >&6;} +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + # Extract the first word of "llvm-profdata", so it can be a program name with args. +set dummy llvm-profdata; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_LLVM_PROFDATA+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $LLVM_PROFDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="$PATH:/Library/Developer/CommandLineTools/usr/bin" +for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_LLVM_PROFDATA="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS + ;; +esac fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } +LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA +if test -n "$LLVM_PROFDATA"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 +printf "%s\n" "$LLVM_PROFDATA" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. + for ac_prog in xcrun +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_XCRUN+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$XCRUN"; then + ac_cv_prog_XCRUN="$XCRUN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_XCRUN="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7035,336 +8394,510 @@ IFS=$as_save_IFS fi fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } +XCRUN=$ac_cv_prog_XCRUN +if test -n "$XCRUN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XCRUN" >&5 +printf "%s\n" "$XCRUN" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" + + test -n "$XCRUN" && break +done + + if test "X$XCRUN" != "X" -a "X$LLVM_PROFDATA" = "X" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $XCRUN $LLVM_PROFDATA" >&5 +printf %s "checking for $XCRUN $LLVM_PROFDATA... " >&6; } + if $XCRUN $LLVM_PROFDATA --help 2>& 5 >& 5 +then : + + LLVM_PROFDATA="$XCRUN $LLVM_PROFDATA" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi -if test "$ac_cv_prog_AR" = false; then - as_fn_error $? "No 'ar' command found in PATH" "$LINENO" 5 fi -# -# Get programs needed for building the documentation -# + if test "X$LLVM_PROFDATA" != "X" +then : -## Delete previous failed configure results -if test -f doc/CONF_INFO; then - rm -f doc/CONF_INFO + CFLAGS="-fprofile-instr-use=default.profdata $saved_CFLAGS"; + $LLVM_PROFDATA merge -output=default.profdata *.profraw; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fprofile-instr-use=default.profdata -Werror" >&5 +printf %s "checking whether $CC accepts -fprofile-instr-use=default.profdata -Werror... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + PROFILE_INSTR_USE=true +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + PROFILE_INSTR_USE=false fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + rm -f default.profdata -for ac_prog in xsltproc -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_XSLTPROC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$XSLTPROC"; then - ac_cv_prog_XSLTPROC="$XSLTPROC" # Let the user override the test. +fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + rm -f *.profraw + CFLAGS=$saved_CFLAGS; + +fi + +# Check whether --enable-pgo was given. +if test ${enable_pgo+y} +then : + enableval=$enable_pgo; case "$enableval" in + no) enable_pgo=no ;; + *) enable_pgo=yes ;; + esac + +else $as_nop + enable_pgo=default +fi + + +USE_PGO=false +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to do PGO of erts" >&5 +printf %s "checking whether to do PGO of erts... " >&6; } +if test $enable_pgo = no; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, disabled by user" >&5 +printf "%s\n" "no, disabled by user" >&6; } +elif test $CROSS_COMPILING = yes; then + if test $enable_pgo = yes; then + as_fn_error $? "cannot use PGO when cross-compiling" "$LINENO" 5 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, cross compiling" >&5 +printf "%s\n" "no, cross compiling" >&6; } + fi +elif test "X$host" = "Xwin32"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, not supported in windows" >&5 +printf "%s\n" "no, not supported in windows" >&6; } +elif test "X$PROFILE_GENERATE" = "Xtrue" -a "X$PROFILE_USE" = "Xtrue" -a "X$PROFILE_CORRECTION" = "Xtrue"; then + ## We need -fprofile-generate and -fprofile-correction support to use PGO with + ## gcc as multiple threads run within the executed object files + USE_PGO=true + PROFILE_COMPILER=gcc + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes, using -fprofile-generate -fprofile-correction" >&5 +printf "%s\n" "yes, using -fprofile-generate -fprofile-correction" >&6; } +elif test "X$PROFILE_INSTR_GENERATE" = "Xtrue" -a "X$PROFILE_INSTR_USE" = "Xtrue"; then + USE_PGO=true + PROFILE_COMPILER=clang + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes, using -fprofile-instr-generate" >&5 +printf "%s\n" "yes, using -fprofile-instr-generate" >&6; } else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH + if test $enable_pgo = yes; then + as_fn_error $? "cannot use PGO with this compiler" "$LINENO" 5 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi +fi + +USE_PGO=false + + + + +ac_header= ac_cache= +for ac_item in $ac_header_c_list do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_XSLTPROC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item fi done - done -IFS=$as_save_IFS + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop + if test "$ac_cv_type_void_p" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 + fi fi -XSLTPROC=$ac_cv_prog_XSLTPROC -if test -n "$XSLTPROC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -$as_echo "$XSLTPROC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } - test -n "$XSLTPROC" && break -done -if test -z "$XSLTPROC"; then - echo "xsltproc" >> doc/CONF_INFO - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No 'xsltproc' command found: the documentation cannot be built" >&5 -$as_echo "$as_me: WARNING: No 'xsltproc' command found: the documentation cannot be built" >&2;} -fi +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h + + # Needed for ARCH and smp checks below +if test "x$ac_cv_sizeof_void_p" = x8; then + EXTERNAL_WORD_SIZE=64 -for ac_prog in fop -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_FOP+:} false; then : - $as_echo_n "(cached) " >&6 else - if test -n "$FOP"; then - ac_cv_prog_FOP="$FOP" # Let the user override the test. + EXTERNAL_WORD_SIZE=32 + +fi + + +if test "x$host_alias" != "x"; then + chk_opsys_=$host_os else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_FOP="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS + chk_opsys_=`uname -s` + if test "x$chk_opsys_" = "xSunOS"; then + chk_opsys_=$chk_opsys_`uname -r` + fi +fi +case $chk_opsys_ in + win32) OPSYS=win32;; + solaris2.*|SunOS5.*) OPSYS=sol2;; + linux*|Linux) OPSYS=linux;; + darwin|Darwin) OPSYS=darwin;; + freebsd|FreeBSD) OPSYS=freebsd;; + *) OPSYS=noopsys +esac + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target hardware architecture" >&5 +printf %s "checking target hardware architecture... " >&6; } + if test "x$host_alias" != "x" -a "x$host_cpu" != "x"; then + chk_arch_=$host_cpu + else + chk_arch_=`uname -m` + fi + + case $chk_arch_ in + sun4u) ARCH=ultrasparc;; + sparc64) ARCH=sparc64;; + sun4v) ARCH=ultrasparc;; + i86pc) ARCH=x86;; + i386) ARCH=x86;; + i486) ARCH=x86;; + i586) ARCH=x86;; + i686) ARCH=x86;; + x86_64) ARCH=amd64;; + amd64) ARCH=amd64;; + macppc) ARCH=ppc;; + powerpc) ARCH=ppc;; + ppc) ARCH=ppc;; + ppc64) ARCH=ppc64;; + ppc64le) ARCH=ppc64le;; + powerpc64) ARCH=ppc64;; + powerpc64le) ARCH=ppc64le;; + "Power Macintosh") ARCH=ppc;; + arm64) ARCH=arm64;; + armv5b) ARCH=arm;; + armv5teb) ARCH=arm;; + armv5tel) ARCH=arm;; + armv5tejl) ARCH=arm;; + armv6l) ARCH=arm;; + armv6hl) ARCH=arm;; + armv7l) ARCH=arm;; + armv7hl) ARCH=arm;; + armv8*) ARCH=arm;; + aarch64) ARCH=arm64;; + aarch*) ARCH=arm;; + tile) ARCH=tile;; + e2k) ARCH=e2k;; + *) ARCH=noarch;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ARCH" >&5 +printf "%s\n" "$ARCH" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compilation mode forces ARCH adjustment" >&5 +printf %s "checking whether compilation mode forces ARCH adjustment... " >&6; } + case "$ARCH-$ac_cv_sizeof_void_p" in + x86-8) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=x86 to ARCH=amd64" >&5 +printf "%s\n" "yes: adjusting ARCH=x86 to ARCH=amd64" >&6; } + ARCH=amd64 + ;; + amd64-4) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=amd64 to ARCH=x86" >&5 +printf "%s\n" "yes: adjusting ARCH=amd64 to ARCH=x86" >&6; } + ARCH=x86 + ;; + ultrasparc-8) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ultrasparc to ARCH=sparc64" >&5 +printf "%s\n" "yes: adjusting ARCH=ultrasparc to ARCH=sparc64" >&6; } + ARCH=sparc64 + ;; + sparc64-4) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=sparc64 to ARCH=ultrasparc" >&5 +printf "%s\n" "yes: adjusting ARCH=sparc64 to ARCH=ultrasparc" >&6; } + ARCH=ultrasparc + ;; + ppc64-4) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ppc64 to ARCH=ppc" >&5 +printf "%s\n" "yes: adjusting ARCH=ppc64 to ARCH=ppc" >&6; } + ARCH=ppc + ;; + ppc-8) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=ppc to ARCH=ppc64" >&5 +printf "%s\n" "yes: adjusting ARCH=ppc to ARCH=ppc64" >&6; } + ARCH=ppc64 + ;; + arm-8) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes: adjusting ARCH=arm to ARCH=arm64" >&5 +printf "%s\n" "yes: adjusting ARCH=arm to ARCH=arm64" >&6; } + ARCH=arm64 + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no: ARCH is $ARCH" >&5 +printf "%s\n" "no: ARCH is $ARCH" >&6; } + ;; + esac + + + + + + + +case $ARCH-$OPSYS in + amd64-darwin*|arm64-darwin*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to cope with 64bit Darwin" >&5 +printf "%s\n" "$as_me: Adjusting LDFLAGS to cope with 64bit Darwin" >&6;} + case $LDFLAGS in + *-m64*) + ;; + *) + LDFLAGS="-m64 $LDFLAGS" + ;; + esac + ;; + *-darwin*) + case $LDFLAGS in + *-m32*) + ;; + *) + LDFLAGS="-m32 $LDFLAGS" + ;; + esac + ;; + *) + if test X${enable_m64_build} = Xyes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to use -m64" >&5 +printf "%s\n" "$as_me: Adjusting LDFLAGS to use -m64" >&6;} + case $LDFLAGS in + *-m64*) + ;; + *) + LDFLAGS="-m64 $LDFLAGS" + ;; + esac + fi; + if test X${enable_m32_build} = Xyes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Adjusting LDFLAGS to use -m32" >&5 +printf "%s\n" "$as_me: Adjusting LDFLAGS to use -m32" >&6;} ; + case $LDFLAGS in + *-m32*) + ;; + *) + LDFLAGS="-m32 $LDFLAGS" + ;; + esac ; + fi + ;; +esac -fi -fi -FOP=$ac_cv_prog_FOP -if test -n "$FOP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FOP" >&5 -$as_echo "$FOP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if VM has to be linked with Carbon framework" >&5 +printf %s "checking if VM has to be linked with Carbon framework... " >&6; } +case $ARCH-$OPSYS in + *-darwin*) + LIBCARBON="-framework Carbon -framework Cocoa" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + *) + LIBCARBON= + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; +esac - test -n "$FOP" && break -done -if test -z "$FOP"; then - FOP="$ERL_TOP/make/fakefop" - echo "fop" >> doc/CONF_INFO - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No 'fop' command found: going to generate placeholder PDF files" >&5 -$as_echo "$as_me: WARNING: No 'fop' command found: going to generate placeholder PDF files" >&2;} -fi +_search_path=/bin:/usr/bin:/usr/local/bin:$PATH -for ac_prog in xmllint -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_XMLLINT+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$XMLLINT"; then - ac_cv_prog_XMLLINT="$XMLLINT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH +# Extract the first word of "mkdir", so it can be a program name with args. +set dummy mkdir; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_MKDIR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $MKDIR in + [\\/]* | ?:[\\/]*) + ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $_search_path do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_XMLLINT="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_MKDIR="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS + test -z "$ac_cv_path_MKDIR" && ac_cv_path_MKDIR="false" + ;; +esac fi -fi -XMLLINT=$ac_cv_prog_XMLLINT -if test -n "$XMLLINT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XMLLINT" >&5 -$as_echo "$XMLLINT" >&6; } +MKDIR=$ac_cv_path_MKDIR +if test -n "$MKDIR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR" >&5 +printf "%s\n" "$MKDIR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - test -n "$XMLLINT" && break -done - -if test -z "$XMLLINT"; then - echo "xmllint" >> doc/CONF_INFO - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No 'xmllint' command found: can't run the xmllint target for the documentation" >&5 -$as_echo "$as_me: WARNING: No 'xmllint' command found: can't run the xmllint target for the documentation" >&2;} +if test "$ac_cv_path_MKDIR" = false; then + as_fn_error $? "No 'mkdir' command found" "$LINENO" 5 fi -case $host in - *-*-solaris*|free_source) - if test -x /usr/ucb/install; then - INSTALL="/usr/ucb/install -c" - fi - ;; +# Extract the first word of "cp", so it can be a program name with args. +set dummy cp; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $CP in + [\\/]* | ?:[\\/]*) + ac_cv_path_CP="$CP" # Let the user override the test with a path. + ;; *) - ;; -esac -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH +for as_dir in $_search_path do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CP="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done done IFS=$as_save_IFS -rm -rf conftest.one conftest.two conftest.dir - + test -z "$ac_cv_path_CP" && ac_cv_path_CP="false" + ;; +esac fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi +CP=$ac_cv_path_CP +if test -n "$CP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 +printf "%s\n" "$CP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a directory including parents" >&5 -$as_echo_n "checking how to create a directory including parents... " >&6; } -if ${ac_cv_prog_mkdir_p+:} false; then : - $as_echo_n "(cached) " >&6 -else -temp_name_base=config.$$ -temp_name=$temp_name_base/x/y/z -$INSTALL -d $temp_name >/dev/null 2>&1 -ac_cv_prog_mkdir_p=none -if test -d $temp_name; then - ac_cv_prog_mkdir_p="$INSTALL -d" -else - mkdir -p $temp_name >/dev/null 2>&1 - if test -d $temp_name; then - ac_cv_prog_mkdir_p="mkdir -p" - fi +if test "$ac_cv_path_CP" = false; then + as_fn_error $? "No 'cp' command found" "$LINENO" 5 fi -rm -fr $temp_name_base -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_mkdir_p" >&5 -$as_echo "$ac_cv_prog_mkdir_p" >&6; } +_search_path= -case "${ac_cv_prog_mkdir_p}" in - none) as_fn_error $? "don't know how create directories with parents" "$LINENO" 5 ;; - *) INSTALL_DIR="$ac_cv_prog_mkdir_p" ;; -esac +# Remove old configuration information. +# Next line should be before first output to CONN_INFO. So this is +# just the right place. +rm -f "$ERL_TOP/erts/CONF_INFO" -case $host_os in - darwin*) - INSTALL_DATA="$INSTALL_DATA -p";; - *) - ;; -esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we are building a sharing-preserving emulator" >&5 +printf %s "checking if we are building a sharing-preserving emulator... " >&6; } +if test "$enable_sharing_preserving" = "yes"; then +printf "%s\n" "#define SHCOPY 1" >>confdefs.h -case $build in - *tile*) - INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" - INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" - ;; - *) - ;; -esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi HCC='$(CC)' @@ -7397,68 +8930,79 @@ esac # AIX 4.x (perhaps only for x>=2) wants -Wl,-bexpall,-brtl and doesn't # reliably return an error for others, thus we separate it out. # Otherwise we assume that if the linker accepts the flag, it is needed. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra flags needed to export symbols" >&5 -$as_echo_n "checking for extra flags needed to export symbols... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for extra flags needed to export symbols" >&5 +printf %s "checking for extra flags needed to export symbols... " >&6; } DEXPORT="" -case $host_os in - aix*|os400*) +case $host_os in #( + aix*|os400*) : + DEXPORT=-Wl,-bexpall,-brtl - ;; - bsdi*) + ;; #( + bsdi*) : + DEXPORT="-rdynamic " - ;; - win32) + ;; #( + win32) : + DEXPORT="" - ;; - *) + ;; #( + *) : + + DEXPORT= save_ldflags="$LDFLAGS" LDFLAGS=-Wl,-export-dynamic cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - DEXPORT=-Wl,-export-dynamic -else +if ac_fn_c_try_link "$LINENO" +then : + DEXPORT="$LDFLAGS" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test "$DEXPORT" = "" +then : - LDFLAGS=-Wl,-Bexport - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + LDFLAGS=-Wl,-Bexport + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - DEXPORT=-Wl,-Bexport +if ac_fn_c_try_link "$LINENO" +then : + DEXPORT="$LDFLAGS" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext + fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_ldflags" - ;; + ;; esac + case "x$DEXPORT" in "x") - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; };; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 +printf "%s\n" "none" >&6; };; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEXPORT" >&5 -$as_echo "$DEXPORT" >&6; };; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DEXPORT" >&5 +printf "%s\n" "$DEXPORT" >&6; };; esac # Check for Solaris/ultrasparc /dev/perfmon interface @@ -7466,7 +9010,7 @@ esac case "${host}:${GCC}" in sparc-*-solaris*:yes) -$as_echo "#define HAVE_SOLARIS_SPARC_PERFMON 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOLARIS_SPARC_PERFMON 1" >>confdefs.h ;; *) @@ -7478,8 +9022,8 @@ case $host_os in darwin19*) # Disable stack checking to avoid crashing with a segment fault # in macOS Catalina. - { $as_echo "$as_me:${as_lineno-$LINENO}: Turning off stack check on macOS 10.15 (Catalina)" >&5 -$as_echo "$as_me: Turning off stack check on macOS 10.15 (Catalina)" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Turning off stack check on macOS 10.15 (Catalina)" >&5 +printf "%s\n" "$as_me: Turning off stack check on macOS 10.15 (Catalina)" >&6;} CFLAGS="-fno-stack-check $CFLAGS" ;; *) @@ -7488,11 +9032,12 @@ esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 -$as_echo_n "checking for sin in -lm... " >&6; } -if ${ac_cv_lib_m_sin+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5 +printf %s "checking for sin in -lm... " >&6; } +if test ${ac_cv_lib_m_sin+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7501,43 +9046,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sin (); int -main () +main (void) { return sin (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_m_sin=yes -else +else $as_nop ac_cv_lib_m_sin=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 -$as_echo "$ac_cv_lib_m_sin" >&6; } -if test "x$ac_cv_lib_m_sin" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBM 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5 +printf "%s\n" "$ac_cv_lib_m_sin" >&6; } +if test "x$ac_cv_lib_m_sin" = xyes +then : + printf "%s\n" "#define HAVE_LIBM 1" >>confdefs.h LIBS="-lm $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7546,43 +9089,84 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dlopen (); int -main () +main (void) { return dlopen (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_dl_dlopen=yes -else +else $as_nop ac_cv_lib_dl_dlopen=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDL 1 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h + + LIBS="-ldl $LIBS" + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlvsym in -ldl" >&5 +printf %s "checking for dlvsym in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlvsym+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dlvsym (); +int +main (void) +{ +return dlvsym (); + ; + return 0; +} _ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlvsym=yes +else $as_nop + ac_cv_lib_dl_dlvsym=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlvsym" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlvsym" >&6; } +if test "x$ac_cv_lib_dl_dlvsym" = xyes +then : + printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 -$as_echo_n "checking for main in -linet... " >&6; } -if ${ac_cv_lib_inet_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 +printf %s "checking for main in -linet... " >&6; } +if test ${ac_cv_lib_inet_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7590,73 +9174,71 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_inet_main=yes -else +else $as_nop ac_cv_lib_inet_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 -$as_echo "$ac_cv_lib_inet_main" >&6; } -if test "x$ac_cv_lib_inet_main" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBINET 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 +printf "%s\n" "$ac_cv_lib_inet_main" >&6; } +if test "x$ac_cv_lib_inet_main" = xyes +then : + printf "%s\n" "#define HAVE_LIBINET 1" >>confdefs.h LIBS="-linet $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 -$as_echo_n "checking for openpty in -lutil... " >&6; } -if ${ac_cv_lib_util_openpty+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 +printf %s "checking for openpty in -lutil... " >&6; } +if test ${ac_cv_lib_util_openpty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ char openpty (); int -main () +main (void) { return openpty (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_util_openpty=yes -else +else $as_nop ac_cv_lib_util_openpty=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 -$as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBUTIL 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 +printf "%s\n" "$ac_cv_lib_util_openpty" >&6; } +if test "x$ac_cv_lib_util_openpty" = xyes +then : + printf "%s\n" "#define HAVE_LIBUTIL 1" >>confdefs.h LIBS="-lutil $LIBS" @@ -7666,97 +9248,104 @@ fi # Check whether --enable-native-ethr-impls was given. -if test "${enable_native_ethr_impls+set}" = set; then : +if test ${enable_native_ethr_impls+y} +then : enableval=$enable_native_ethr_impls; case "$enableval" in no) disable_native_ethr_impls=yes ;; *) disable_native_ethr_impls=no ;; esac -else +else $as_nop disable_native_ethr_impls=no fi test "X$disable_native_ethr_impls" = "Xyes" && -$as_echo "#define ETHR_DISABLE_NATIVE_IMPLS 1" >>confdefs.h +printf "%s\n" "#define ETHR_DISABLE_NATIVE_IMPLS 1" >>confdefs.h # Check whether --enable-x86-out-of-order was given. -if test "${enable_x86_out_of_order+set}" = set; then : +if test ${enable_x86_out_of_order+y} +then : enableval=$enable_x86_out_of_order; fi # Check whether --enable-prefer-gcc-native-ethr-impls was given. -if test "${enable_prefer_gcc_native_ethr_impls+set}" = set; then : +if test ${enable_prefer_gcc_native_ethr_impls+y} +then : enableval=$enable_prefer_gcc_native_ethr_impls; case "$enableval" in yes) enable_prefer_gcc_native_ethr_impls=yes ;; *) enable_prefer_gcc_native_ethr_impls=no ;; esac -else +else $as_nop enable_prefer_gcc_native_ethr_impls=no fi test $enable_prefer_gcc_native_ethr_impls = yes && -$as_echo "#define ETHR_PREFER_GCC_NATIVE_IMPLS 1" >>confdefs.h +printf "%s\n" "#define ETHR_PREFER_GCC_NATIVE_IMPLS 1" >>confdefs.h # Check whether --enable-trust-gcc-atomic-builtins-memory-barriers was given. -if test "${enable_trust_gcc_atomic_builtins_memory_barriers+set}" = set; then : +if test ${enable_trust_gcc_atomic_builtins_memory_barriers+y} +then : enableval=$enable_trust_gcc_atomic_builtins_memory_barriers; case "$enableval" in yes) trust_gcc_atomic_builtins_mbs=1 ;; *) trust_gcc_atomic_builtins_mbs=0 ;; esac -else +else $as_nop trust_gcc_atomic_builtins_mbs=0 fi -cat >>confdefs.h <<_ACEOF -#define ETHR_TRUST_GCC_ATOMIC_BUILTINS_MEMORY_BARRIERS $trust_gcc_atomic_builtins_mbs -_ACEOF +printf "%s\n" "#define ETHR_TRUST_GCC_ATOMIC_BUILTINS_MEMORY_BARRIERS $trust_gcc_atomic_builtins_mbs" >>confdefs.h # Check whether --with-libatomic_ops was given. -if test "${with_libatomic_ops+set}" = set; then : +if test ${with_libatomic_ops+y} +then : withval=$with_libatomic_ops; fi # Check whether --with-with_sparc_memory_order was given. -if test "${with_with_sparc_memory_order+set}" = set; then : +if test ${with_with_sparc_memory_order+y} +then : withval=$with_with_sparc_memory_order; fi # Check whether --enable-ppc-lwsync-instruction was given. -if test "${enable_ppc_lwsync_instruction+set}" = set; then : +if test ${enable_ppc_lwsync_instruction+y} +then : enableval=$enable_ppc_lwsync_instruction; case "$enableval" in no) enable_lwsync=no ;; *) enable_lwsync=yes ;; esac -else +else $as_nop # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -7765,14 +9354,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h case $host_cpu-$ac_cv_sizeof_void_p in @@ -7787,12 +9374,12 @@ fi case $enable_lwsync in no) -$as_echo "#define ETHR_PPC_HAVE_NO_LWSYNC 1" >>confdefs.h +printf "%s\n" "#define ETHR_PPC_HAVE_NO_LWSYNC 1" >>confdefs.h ;; yes) -$as_echo "#define ETHR_PPC_HAVE_LWSYNC 1" >>confdefs.h +printf "%s\n" "#define ETHR_PPC_HAVE_LWSYNC 1" >>confdefs.h ;; *) @@ -7803,29 +9390,34 @@ esac NEED_NPTL_PTHREAD_H=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 -$as_echo_n "checking for native win32 threads... " >&6; } -if test "X$host_os" = "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 +printf %s "checking for native win32 threads... " >&6; } +if test "X$host_os" = "Xwin32" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } THR_DEFS="-DWIN32_THREADS" THR_LIBS= THR_LIB_NAME=win32_threads THR_LIB_TYPE=win32_threads -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } THR_DEFS= THR_LIBS= THR_LIB_NAME= THR_LIB_TYPE=posix_unknown - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7834,40 +9426,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread_pthread_create=yes -else +else $as_nop ac_cv_lib_pthread_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : THR_LIBS="-lpthread" fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 -$as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 +printf %s "checking for pthread_create in -lc_r... " >&6; } +if test ${ac_cv_lib_c_r_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7876,96 +9470,112 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_r_pthread_create=yes -else +else $as_nop ac_cv_lib_c_r_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +if test "x$ac_cv_lib_c_r_pthread_create" = xyes +then : THR_LIBS="-lc_r" fi - fi - if test "x$THR_LIBS" = "x"; then - ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes; then : +fi + + if test "x$THR_LIBS" = "x" +then : + + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : THR_LIBS="none_needed" fi - fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 -$as_echo_n "checking if the '-pthread' switch can be used... " >&6; } +fi + + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 +printf %s "checking if the '-pthread' switch can be used... " >&6; } saved_cflags=$CFLAGS CFLAGS="$CFLAGS -pthread" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_create((void*)0,(void*)0,(void*)0,(void*)0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : THR_DEFS="-pthread" THR_LIBS="-pthread" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$saved_cflags if test "x$THR_LIBS" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - fi - if test "x$THR_LIBS" != "x"; then +fi + + if test "x$THR_LIBS" != "x" +then : + THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" THR_LIB_NAME=pthread if test "x$THR_LIBS" = "xnone_needed"; then THR_LIBS= fi - case $host_os in - solaris*) - THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;; - linux*) + case $host_os in #( + solaris*) : + + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" + ;; #( + linux*) : + THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" -if test "$cross_compiling" != "yes"; then +if test "$cross_compiling" != "yes" +then : + # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -7973,11 +9583,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7989,23 +9603,26 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else + +else $as_nop + host_getconf="$host_alias-getconf" # Extract the first word of "$host_getconf", so it can be a program name with args. set dummy $host_getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -8013,11 +9630,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="$host_getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8029,25 +9650,28 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then + if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != "" +then : + GETCONF= prfx="$erl_xcomp_sysroot" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. set dummy ${ac_tool_prefix}getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. @@ -8058,11 +9682,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8074,11 +9702,11 @@ esac fi GETCONF=$ac_cv_path_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -8087,11 +9715,12 @@ if test -z "$ac_cv_path_GETCONF"; then ac_pt_GETCONF=$GETCONF # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. @@ -8102,11 +9731,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8118,11 +9751,11 @@ esac fi ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF if test -n "$ac_pt_GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 -$as_echo "$ac_pt_GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 +printf "%s\n" "$ac_pt_GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_GETCONF" = x; then @@ -8130,8 +9763,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac GETCONF=$ac_pt_GETCONF @@ -8140,11 +9773,13 @@ else GETCONF="$ac_cv_path_GETCONF" fi - fi + fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 -$as_echo_n "checking for Native POSIX Thread Library... " >&6; } +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 +printf %s "checking for Native POSIX Thread Library... " >&6; } libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` if test $? -eq 0; then case "$libpthr_vsn" in @@ -8160,24 +9795,28 @@ $as_echo_n "checking for Native POSIX Thread Library... " >&6; } else nptl=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 -$as_echo "$nptl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 +printf "%s\n" "$nptl" >&6; } if test $nptl = cross; then nptl=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi - if test $nptl = yes; then + if test $nptl = yes +then : + THR_LIB_TYPE=posix_nptl need_nptl_incldir=no - ac_fn_c_check_header_mongrel "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_nptl_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_nptl_pthread_h" = xyes +then : need_nptl_incldir=yes NEED_NPTL_PTHREAD_H=yes fi + if test $need_nptl_incldir = yes +then : - if test $need_nptl_incldir = yes; then # Ahh... nptl_path="$C_INCLUDE_PATH:$CPATH" if test X$cross_compiling != Xyes; then @@ -8198,13 +9837,13 @@ fi IFS=$save_ifs nptl_incldir= for dir in $nptl_ws_path; do - as_ac_Header=`$as_echo "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + as_ac_Header=`printf "%s\n" "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : nptl_incldir=$dir/nptl fi - if test "x$nptl_incldir" != "x"; then THR_DEFS="$THR_DEFS -isystem $nptl_incldir" break @@ -8213,38 +9852,43 @@ fi if test "x$nptl_incldir" = "x"; then as_fn_error $? "Failed to locate nptl system include directory" "$LINENO" 5 fi - fi - fi - ;; - *) ;; - esac + +fi + +fi + ;; #( + *) : + ;; +esac saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $THR_DEFS" - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : -$as_echo "#define HAVE_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes +then : \ -$as_echo "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h fi - CPPFLAGS=$saved_cppflags - fi + +fi + fi @@ -8252,11 +9896,12 @@ fi ERTS_INTERNAL_X_LIBS= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 -$as_echo_n "checking for kstat_open in -lkstat... " >&6; } -if ${ac_cv_lib_kstat_kstat_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 +printf %s "checking for kstat_open in -lkstat... " >&6; } +if test ${ac_cv_lib_kstat_kstat_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lkstat $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -8265,32 +9910,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char kstat_open (); int -main () +main (void) { return kstat_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_kstat_kstat_open=yes -else +else $as_nop ac_cv_lib_kstat_kstat_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 -$as_echo "$ac_cv_lib_kstat_kstat_open" >&6; } -if test "x$ac_cv_lib_kstat_kstat_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 +printf "%s\n" "$ac_cv_lib_kstat_kstat_open" >&6; } +if test "x$ac_cv_lib_kstat_kstat_open" = xyes +then : -$as_echo "#define HAVE_KSTAT 1" >>confdefs.h +printf "%s\n" "#define HAVE_KSTAT 1" >>confdefs.h ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat" fi @@ -8347,11 +9991,12 @@ fi esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -8360,30 +10005,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -8397,11 +10041,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -8410,7 +10055,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -8423,23 +10068,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_try_find_pthread_compatible+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_try_find_pthread_compatible+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -8449,7 +10096,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -8462,56 +10109,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_try_find_pthread_compatible = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_try_find_pthread_compatible" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_try_find_pthread_compatible" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_try_find_pthread_compatible" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_try_find_pthread_compatible" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi + + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -8520,7 +10181,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -8535,16 +10196,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_try_find_pthread_compatible-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -8611,17 +10273,17 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } case $erl_monotonic_clock_func in clock_gettime) -$as_echo "#define ETHR_HAVE_CLOCK_GETTIME_MONOTONIC 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_CLOCK_GETTIME_MONOTONIC 1" >>confdefs.h ;; mach_clock_get_time) -$as_echo "#define ETHR_HAVE_MACH_CLOCK_GET_TIME 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_MACH_CLOCK_GET_TIME 1" >>confdefs.h ;; gethrtime) -$as_echo "#define ETHR_HAVE_GETHRTIME 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_GETHRTIME 1" >>confdefs.h ;; *) @@ -8630,9 +10292,7 @@ esac if test "x$erl_monotonic_clock_id" != "x"; then -cat >>confdefs.h <<_ACEOF -#define ETHR_MONOTONIC_CLOCK_ID $erl_monotonic_clock_id -_ACEOF +printf "%s\n" "#define ETHR_MONOTONIC_CLOCK_ID $erl_monotonic_clock_id" >>confdefs.h fi @@ -8650,18 +10310,19 @@ ethr_modified_default_stack_size= # Check whether --with-threadnames was given. -if test "${with_threadnames+set}" = set; then : +if test ${with_threadnames+y} +then : withval=$with_threadnames; -else +else $as_nop with_threadnames=yes fi ethr_lib_name=ethread -case "$THR_LIB_NAME" in +case "$THR_LIB_NAME" in #( + win32_threads) : - win32_threads) ETHR_THR_LIB_BASE_DIR=win # * _WIN32_WINNT >= 0x0400 is needed for # TryEnterCriticalSection @@ -8690,7 +10351,7 @@ case "$THR_LIB_NAME" in fi -$as_echo "#define ETHR_WIN32_THREADS 1" >>confdefs.h +printf "%s\n" "#define ETHR_WIN32_THREADS 1" >>confdefs.h if test "X$disable_native_ethr_impls" = "Xyes"; then @@ -8699,1148 +10360,1346 @@ $as_echo "#define ETHR_WIN32_THREADS 1" >>confdefs.h else ilckd="_InterlockedDecrement" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedDecrement+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedDecrement=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedDecrement=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDDECREMENT 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedDecrement" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedDecrement" >&6; } + if [ "${ethr_cv_have__InterlockedDecrement}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDDECREMENT 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedDecrement_rel" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedDecrement_rel+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedDecrement_rel=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedDecrement_rel=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDDECREMENT_REL 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedDecrement_rel" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedDecrement_rel" >&6; } + if [ "${ethr_cv_have__InterlockedDecrement_rel}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDDECREMENT_REL 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedIncrement" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedIncrement+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedIncrement=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedIncrement=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDINCREMENT 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedIncrement" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedIncrement" >&6; } + if [ "${ethr_cv_have__InterlockedIncrement}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDINCREMENT 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedIncrement_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedIncrement_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedIncrement_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedIncrement_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDINCREMENT_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedIncrement_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedIncrement_acq" >&6; } + if [ "${ethr_cv_have__InterlockedIncrement_acq}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDINCREMENT_ACQ 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedExchangeAdd" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchangeAdd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchangeAdd=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchangeAdd=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchangeAdd" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchangeAdd" >&6; } + if [ "${ethr_cv_have__InterlockedExchangeAdd}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedExchangeAdd_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchangeAdd_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchangeAdd_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchangeAdd_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchangeAdd_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchangeAdd_acq" >&6; } + if [ "${ethr_cv_have__InterlockedExchangeAdd_acq}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD_ACQ 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedAnd" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedAnd+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedAnd=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedAnd=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDAND 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedAnd" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedAnd" >&6; } + if [ "${ethr_cv_have__InterlockedAnd}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDAND 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedOr" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedOr+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedOr=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedOr=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDOR 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedOr" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedOr" >&6; } + if [ "${ethr_cv_have__InterlockedOr}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDOR 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedExchange" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchange+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchange=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchange=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGE 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchange" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchange" >&6; } + if [ "${ethr_cv_have__InterlockedExchange}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGE 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedCompareExchange" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + ethr_have_native_atomics=yes + else + : + fi - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes ilckd="_InterlockedCompareExchange_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange_acq" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange_acq}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ 1" >>confdefs.h + + ethr_have_native_atomics=yes + else + : + fi - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes ilckd="_InterlockedCompareExchange_rel" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (long) 0);";; "3") ilckd_call="${ilckd}(var, (long) 0, (long) 0);";; "4") ilckd_call="${ilckd}(var, (long) 0, (long) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange_rel+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange_rel=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile long *var; - volatile long arr[2]; + volatile long *var; + volatile long arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange_rel=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange_rel" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange_rel" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange_rel}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL 1" >>confdefs.h - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes + ethr_have_native_atomics=yes + else + : + fi ilckd="_InterlockedDecrement64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedDecrement64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedDecrement64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedDecrement64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDDECREMENT64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedDecrement64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedDecrement64" >&6; } + if [ "${ethr_cv_have__InterlockedDecrement64}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDDECREMENT64 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedDecrement64_rel" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedDecrement64_rel+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedDecrement64_rel=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedDecrement64_rel=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDDECREMENT64_REL 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedDecrement64_rel" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedDecrement64_rel" >&6; } + if [ "${ethr_cv_have__InterlockedDecrement64_rel}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDDECREMENT64_REL 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedIncrement64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedIncrement64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedIncrement64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedIncrement64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDINCREMENT64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedIncrement64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedIncrement64" >&6; } + if [ "${ethr_cv_have__InterlockedIncrement64}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDINCREMENT64 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedIncrement64_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "1" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedIncrement64_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedIncrement64_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedIncrement64_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDINCREMENT64_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedIncrement64_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedIncrement64_acq" >&6; } + if [ "${ethr_cv_have__InterlockedIncrement64_acq}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDINCREMENT64_ACQ 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedExchangeAdd64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchangeAdd64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchangeAdd64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchangeAdd64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchangeAdd64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchangeAdd64" >&6; } + if [ "${ethr_cv_have__InterlockedExchangeAdd64}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD64 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedExchangeAdd64_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchangeAdd64_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchangeAdd64_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchangeAdd64_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchangeAdd64_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchangeAdd64_acq" >&6; } + if [ "${ethr_cv_have__InterlockedExchangeAdd64_acq}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedAnd64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedAnd64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedAnd64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedAnd64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDAND64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedAnd64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedAnd64" >&6; } + if [ "${ethr_cv_have__InterlockedAnd64}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDAND64 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedOr64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedOr64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedOr64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedOr64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDOR64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedOr64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedOr64" >&6; } + if [ "${ethr_cv_have__InterlockedOr64}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDOR64 1" >>confdefs.h + + else + : + fi ilckd="_InterlockedExchange64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "2" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedExchange64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedExchange64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedExchange64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDEXCHANGE64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedExchange64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedExchange64" >&6; } + if [ "${ethr_cv_have__InterlockedExchange64}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDEXCHANGE64 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + else + : + fi ilckd="_InterlockedCompareExchange64" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange64=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange64=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange64" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange64" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange64}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 1" >>confdefs.h + + ethr_have_native_atomics=yes + else + : + fi - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes ilckd="_InterlockedCompareExchange64_acq" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange64_acq+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange64_acq=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange64_acq=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange64_acq" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange64_acq" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange64_acq}" = "yes" ]; then + +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } + ethr_have_native_atomics=yes + else + : + fi - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes ilckd="_InterlockedCompareExchange64_rel" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "3" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange64_rel+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange64_rel=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange64_rel=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange64_rel" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange64_rel" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange64_rel}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL 1" >>confdefs.h - test "$have_interlocked_op" = "yes" && ethr_have_native_atomics=yes + ethr_have_native_atomics=yes + else + : + fi ilckd="_InterlockedCompareExchange128" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 -$as_echo_n "checking for ${ilckd}()... " >&6; } case "4" in "1") ilckd_call="${ilckd}(var);";; "2") ilckd_call="${ilckd}(var, (__int64) 0);";; "3") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0);";; "4") ilckd_call="${ilckd}(var, (__int64) 0, (__int64) 0, arr);";; esac - have_interlocked_op=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ilckd}()" >&5 +printf %s "checking for ${ilckd}()... " >&6; } +if test ${ethr_cv_have__InterlockedCompareExchange128+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ethr_cv_have__InterlockedCompareExchange128=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - #define WIN32_LEAN_AND_MEAN - #include - #include + #define WIN32_LEAN_AND_MEAN + #include + #include int -main () +main (void) { - volatile __int64 *var; - volatile __int64 arr[2]; + volatile __int64 *var; + volatile __int64 arr[2]; - $ilckd_call - return 0; + $ilckd_call + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_interlocked_op=yes +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_have__InterlockedCompareExchange128=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test $have_interlocked_op = yes && -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE128 1 -_ACEOF +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_have__InterlockedCompareExchange128" >&5 +printf "%s\n" "$ethr_cv_have__InterlockedCompareExchange128" >&6; } + if [ "${ethr_cv_have__InterlockedCompareExchange128}" = "yes" ]; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_interlocked_op" >&5 -$as_echo "$have_interlocked_op" >&6; } +printf "%s\n" "#define ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE128 1" >>confdefs.h + + else + : + fi fi if test "$ethr_have_native_atomics" = "yes"; then ethr_native_atomic_implementation=windows ethr_have_native_spinlock=yes fi - ;; + ;; #( + pthread) : - pthread) ETHR_THR_LIB_BASE_DIR=pthread -$as_echo "#define ETHR_PTHREADS 1" >>confdefs.h +printf "%s\n" "#define ETHR_PTHREADS 1" >>confdefs.h case $host_os in openbsd*) @@ -9877,27 +11736,27 @@ $as_echo "#define ETHR_PTHREADS 1" >>confdefs.h esac fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if SIGUSR1 and SIGUSR2 can be used" >&5 -$as_echo_n "checking if SIGUSR1 and SIGUSR2 can be used... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $usable_sigusrx" >&5 -$as_echo "$usable_sigusrx" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if SIGUSR1 and SIGUSR2 can be used" >&5 +printf %s "checking if SIGUSR1 and SIGUSR2 can be used... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $usable_sigusrx" >&5 +printf "%s\n" "$usable_sigusrx" >&6; } if test $usable_sigusrx = cross; then usable_sigusrx=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi if test $usable_sigusrx = no; then ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGUSRX" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if sigaltstack can be used" >&5 -$as_echo_n "checking if sigaltstack can be used... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $usable_sigaltstack" >&5 -$as_echo "$usable_sigaltstack" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sigaltstack can be used" >&5 +printf %s "checking if sigaltstack can be used... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $usable_sigaltstack" >&5 +printf "%s\n" "$usable_sigaltstack" >&6; } if test $usable_sigaltstack = cross; then usable_sigaltstack=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi if test $usable_sigaltstack = no; then ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK" @@ -9912,73 +11771,54 @@ $as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2; saved_libs="$LIBS" LIBS="$LIBS $ETHR_X_LIBS" - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : \ -$as_echo "#define ETHR_HAVE_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes +then : \ -$as_echo "#define ETHR_HAVE_MIT_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_MIT_PTHREAD_H 1" >>confdefs.h fi - if test $NEED_NPTL_PTHREAD_H = yes; then -$as_echo "#define ETHR_NEED_NPTL_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define ETHR_NEED_NPTL_PTHREAD_H 1" >>confdefs.h fi - ac_fn_c_check_header_mongrel "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" -if test "x$ac_cv_header_sched_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" +if test "x$ac_cv_header_sched_h" = xyes +then : \ -$as_echo "#define ETHR_HAVE_SCHED_H 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_SCHED_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_time_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : \ -$as_echo "#define ETHR_HAVE_SYS_TIME_H 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_SYS_TIME_H 1" >>confdefs.h fi - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include -int -main () -{ -struct timeval *tv; return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -$as_echo "#define ETHR_TIME_WITH_SYS_TIME 1" >>confdefs.h - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usable PTHREAD_STACK_MIN" >&5 -$as_echo_n "checking for usable PTHREAD_STACK_MIN... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for usable PTHREAD_STACK_MIN" >&5 +printf %s "checking for usable PTHREAD_STACK_MIN... " >&6; } pthread_stack_min=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9993,32 +11833,34 @@ $as_echo_n "checking for usable PTHREAD_STACK_MIN... " >&6; } #endif int -main () +main (void) { return PTHREAD_STACK_MIN; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : pthread_stack_min=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pthread_stack_min" >&5 -$as_echo "$pthread_stack_min" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pthread_stack_min" >&5 +printf "%s\n" "$pthread_stack_min" >&6; } test $pthread_stack_min != yes || { -$as_echo "#define ETHR_HAVE_USABLE_PTHREAD_STACK_MIN 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_USABLE_PTHREAD_STACK_MIN 1" >>confdefs.h } ac_fn_c_check_func "$LINENO" "pthread_spin_lock" "ac_cv_func_pthread_spin_lock" -if test "x$ac_cv_func_pthread_spin_lock" = xyes; then : +if test "x$ac_cv_func_pthread_spin_lock" = xyes +then : \ ethr_have_native_spinlock=yes \ -$as_echo "#define ETHR_HAVE_PTHREAD_SPIN_LOCK 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_SPIN_LOCK 1" >>confdefs.h fi @@ -10026,16 +11868,20 @@ fi have_sched_yield=no have_librt_sched_yield=no ac_fn_c_check_func "$LINENO" "sched_yield" "ac_cv_func_sched_yield" -if test "x$ac_cv_func_sched_yield" = xyes; then : +if test "x$ac_cv_func_sched_yield" = xyes +then : have_sched_yield=yes fi - if test $have_sched_yield = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 -$as_echo_n "checking for sched_yield in -lrt... " >&6; } -if ${ac_cv_lib_rt_sched_yield+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test $have_sched_yield = no +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 +printf %s "checking for sched_yield in -lrt... " >&6; } +if test ${ac_cv_lib_rt_sched_yield+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10044,41 +11890,43 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sched_yield (); int -main () +main (void) { return sched_yield (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_sched_yield=yes -else +else $as_nop ac_cv_lib_rt_sched_yield=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 -$as_echo "$ac_cv_lib_rt_sched_yield" >&6; } -if test "x$ac_cv_lib_rt_sched_yield" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 +printf "%s\n" "$ac_cv_lib_rt_sched_yield" >&6; } +if test "x$ac_cv_lib_rt_sched_yield" = xyes +then : have_librt_sched_yield=yes ETHR_X_LIBS="$ETHR_X_LIBS -lrt" fi - fi - if test $have_sched_yield = yes || test $have_librt_sched_yield = yes; then -$as_echo "#define ETHR_HAVE_SCHED_YIELD 1" >>confdefs.h +fi + if test $have_sched_yield = yes || test $have_librt_sched_yield = yes +then : + - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sched_yield() returns an int" >&5 -$as_echo_n "checking whether sched_yield() returns an int... " >&6; } +printf "%s\n" "#define ETHR_HAVE_SCHED_YIELD 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sched_yield() returns an int" >&5 +printf %s "checking whether sched_yield() returns an int... " >&6; } sched_yield_ret_int=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10088,39 +11936,44 @@ $as_echo_n "checking whether sched_yield() returns an int... " >&6; } #endif int -main () +main (void) { int sched_yield(); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : sched_yield_ret_int=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sched_yield_ret_int" >&5 -$as_echo "$sched_yield_ret_int" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sched_yield_ret_int" >&5 +printf "%s\n" "$sched_yield_ret_int" >&6; } if test $sched_yield_ret_int = yes; then -$as_echo "#define ETHR_SCHED_YIELD_RET_INT 1" >>confdefs.h +printf "%s\n" "#define ETHR_SCHED_YIELD_RET_INT 1" >>confdefs.h fi - fi + +fi have_pthread_yield=no ac_fn_c_check_func "$LINENO" "pthread_yield" "ac_cv_func_pthread_yield" -if test "x$ac_cv_func_pthread_yield" = xyes; then : +if test "x$ac_cv_func_pthread_yield" = xyes +then : have_pthread_yield=yes fi - if test $have_pthread_yield = yes; then + if test $have_pthread_yield = yes +then : -$as_echo "#define ETHR_HAVE_PTHREAD_YIELD 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthread_yield() returns an int" >&5 -$as_echo_n "checking whether pthread_yield() returns an int... " >&6; } +printf "%s\n" "#define ETHR_HAVE_PTHREAD_YIELD 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_yield() returns an int" >&5 +printf %s "checking whether pthread_yield() returns an int... " >&6; } pthread_yield_ret_int=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10134,49 +11987,56 @@ $as_echo_n "checking whether pthread_yield() returns an int... " >&6; } #endif int -main () +main (void) { int pthread_yield(); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_yield_ret_int=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pthread_yield_ret_int" >&5 -$as_echo "$pthread_yield_ret_int" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pthread_yield_ret_int" >&5 +printf "%s\n" "$pthread_yield_ret_int" >&6; } if test $pthread_yield_ret_int = yes; then -$as_echo "#define ETHR_PTHREAD_YIELD_RET_INT 1" >>confdefs.h +printf "%s\n" "#define ETHR_PTHREAD_YIELD_RET_INT 1" >>confdefs.h fi - fi + +fi have_pthread_rwlock_init=no ac_fn_c_check_func "$LINENO" "pthread_rwlock_init" "ac_cv_func_pthread_rwlock_init" -if test "x$ac_cv_func_pthread_rwlock_init" = xyes; then : +if test "x$ac_cv_func_pthread_rwlock_init" = xyes +then : have_pthread_rwlock_init=yes fi - if test $have_pthread_rwlock_init = yes; then + if test $have_pthread_rwlock_init = yes +then : ethr_have_pthread_rwlockattr_setkind_np=no ac_fn_c_check_func "$LINENO" "pthread_rwlockattr_setkind_np" "ac_cv_func_pthread_rwlockattr_setkind_np" -if test "x$ac_cv_func_pthread_rwlockattr_setkind_np" = xyes; then : +if test "x$ac_cv_func_pthread_rwlockattr_setkind_np" = xyes +then : ethr_have_pthread_rwlockattr_setkind_np=yes fi - if test $ethr_have_pthread_rwlockattr_setkind_np = yes; then + if test $ethr_have_pthread_rwlockattr_setkind_np = yes +then : -$as_echo "#define ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP" >&5 -$as_echo_n "checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP... " >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP" >&5 +printf %s "checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP... " >&6; } ethr_pthread_rwlock_writer_nonrecursive_initializer_np=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10190,7 +12050,7 @@ $as_echo_n "checking for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP... " >&6; #endif int -main () +main (void) { pthread_rwlockattr_t *attr; @@ -10201,47 +12061,53 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_pthread_rwlock_writer_nonrecursive_initializer_np=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_pthread_rwlock_writer_nonrecursive_initializer_np" >&5 -$as_echo "$ethr_pthread_rwlock_writer_nonrecursive_initializer_np" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_pthread_rwlock_writer_nonrecursive_initializer_np" >&5 +printf "%s\n" "$ethr_pthread_rwlock_writer_nonrecursive_initializer_np" >&6; } if test $ethr_pthread_rwlock_writer_nonrecursive_initializer_np = yes; then -$as_echo "#define ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 1" >>confdefs.h fi - fi - fi + +fi + +fi if test "$force_pthread_rwlocks" = "yes"; then -$as_echo "#define ETHR_FORCE_PTHREAD_RWLOCK 1" >>confdefs.h +printf "%s\n" "#define ETHR_FORCE_PTHREAD_RWLOCK 1" >>confdefs.h if test $have_pthread_rwlock_init = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues." >&5 -$as_echo "$as_me: WARNING: Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues." >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues." >&5 +printf "%s\n" "$as_me: WARNING: Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues." >&2;} else as_fn_error $? "User forced usage of pthread rwlock, but no such implementation was found" "$LINENO" 5 fi fi ac_fn_c_check_func "$LINENO" "pthread_attr_setguardsize" "ac_cv_func_pthread_attr_setguardsize" -if test "x$ac_cv_func_pthread_attr_setguardsize" = xyes; then : +if test "x$ac_cv_func_pthread_attr_setguardsize" = xyes +then : \ -$as_echo "#define ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE 1" >>confdefs.h fi - if test "x$erl_monotonic_clock_id" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout" >&5 -$as_echo_n "checking whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout... " >&6; } + if test "x$erl_monotonic_clock_id" != "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout" >&5 +printf %s "checking whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout... " >&6; } pthread_cond_timedwait_monotonic=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10253,15 +12119,9 @@ $as_echo_n "checking whether pthread_cond_timedwait() can use the monotonic cloc #elif defined(ETHR_HAVE_PTHREAD_H) # include #endif - #ifdef ETHR_TIME_WITH_SYS_TIME - # include + #include + #ifdef ETHR_HAVE_SYS_TIME_H # include - #else - # ifdef ETHR_HAVE_SYS_TIME_H - # include - # else - # include - # endif #endif #if defined(ETHR_HAVE_MACH_CLOCK_GET_TIME) # include @@ -10269,7 +12129,7 @@ $as_echo_n "checking whether pthread_cond_timedwait() can use the monotonic cloc #endif int -main () +main (void) { int res; @@ -10286,23 +12146,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_cond_timedwait_monotonic=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pthread_cond_timedwait_monotonic" >&5 -$as_echo "$pthread_cond_timedwait_monotonic" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pthread_cond_timedwait_monotonic" >&5 +printf "%s\n" "$pthread_cond_timedwait_monotonic" >&6; } if test $pthread_cond_timedwait_monotonic = yes; then -$as_echo "#define ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 1" >>confdefs.h fi - fi + +fi linux_futex=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux futexes" >&5 -$as_echo_n "checking for Linux futexes... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Linux futexes" >&5 +printf %s "checking for Linux futexes... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10312,7 +12174,7 @@ $as_echo_n "checking for Linux futexes... " >&6; } #include int -main () +main (void) { int i = 1; @@ -10326,20 +12188,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : linux_futex=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $linux_futex" >&5 -$as_echo "$linux_futex" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $linux_futex" >&5 +printf "%s\n" "$linux_futex" >&6; } test $linux_futex = yes && -$as_echo "#define ETHR_HAVE_LINUX_FUTEX 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_LINUX_FUTEX 1" >>confdefs.h pthread_setname=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_setname_np" >&5 -$as_echo_n "checking for pthread_setname_np... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_setname_np" >&5 +printf %s "checking for pthread_setname_np... " >&6; } old_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10347,87 +12210,91 @@ $as_echo_n "checking for pthread_setname_np... " >&6; } #define __USE_GNU #include int -main () +main (void) { pthread_setname_np(pthread_self(), "name"); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_setname=linux fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define __USE_GNU #include int -main () +main (void) { pthread_set_name_np(pthread_self(), "name"); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_setname=bsd fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _DARWIN_C_SOURCE #include int -main () +main (void) { pthread_setname_np("name"); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_setname=darwin fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pthread_setname" >&5 -$as_echo "$pthread_setname" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pthread_setname" >&5 +printf "%s\n" "$pthread_setname" >&6; } case $with_threadnames-$pthread_setname in yes-linux) -$as_echo "#define ETHR_HAVE_PTHREAD_SETNAME_NP_2 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_SETNAME_NP_2 1" >>confdefs.h ;; yes-bsd) -$as_echo "#define ETHR_HAVE_PTHREAD_SET_NAME_NP_2 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_SET_NAME_NP_2 1" >>confdefs.h ;; yes-darwin) -$as_echo "#define ETHR_HAVE_PTHREAD_SETNAME_NP_1 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_SETNAME_NP_1 1" >>confdefs.h ;; *) ;; esac pthread_getname=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_getname_np" >&5 -$as_echo_n "checking for pthread_getname_np... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_getname_np" >&5 +printf %s "checking for pthread_getname_np... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define __USE_GNU #define _DARWIN_C_SOURCE #include int -main () +main (void) { char buff[256]; pthread_getname_np(pthread_self(), buff, 256); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_getname=linux fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10435,51 +12302,57 @@ rm -f core conftest.err conftest.$ac_objext \ #define _DARWIN_C_SOURCE #include int -main () +main (void) { char buff[256]; pthread_getname_np(pthread_self(), buff); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pthread_getname=ibm fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pthread_getname" >&5 -$as_echo "$pthread_getname" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pthread_getname" >&5 +printf "%s\n" "$pthread_getname" >&6; } case $pthread_getname in linux) -$as_echo "#define ETHR_HAVE_PTHREAD_GETNAME_NP_3 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_GETNAME_NP_3 1" >>confdefs.h ;; ibm) -$as_echo "#define ETHR_HAVE_PTHREAD_GETNAME_NP_2 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_PTHREAD_GETNAME_NP_2 1" >>confdefs.h ;; *) ;; esac CFLAGS=$old_CFLAGS - if test "X$disable_native_ethr_impls" = "Xyes"; then + if test "X$disable_native_ethr_impls" = "Xyes" +then : + ethr_have_native_atomics=no - else + +else $as_nop # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +printf %s "checking size of short... " >&6; } +if test ${ac_cv_sizeof_short+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else @@ -10488,31 +12361,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +printf "%s\n" "$ac_cv_sizeof_short" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF +printf "%s\n" "#define SIZEOF_SHORT $ac_cv_sizeof_short" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +printf %s "checking size of int... " >&6; } +if test ${ac_cv_sizeof_int+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else @@ -10521,31 +12394,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +printf "%s\n" "$ac_cv_sizeof_int" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF +printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +printf %s "checking size of long... " >&6; } +if test ${ac_cv_sizeof_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else @@ -10554,31 +12427,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +printf %s "checking size of long long... " >&6; } +if test ${ac_cv_sizeof_long_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else @@ -10587,31 +12460,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of __int128_t" >&5 -$as_echo_n "checking size of __int128_t... " >&6; } -if ${ac_cv_sizeof___int128_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int128_t))" "ac_cv_sizeof___int128_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of __int128_t" >&5 +printf %s "checking size of __int128_t... " >&6; } +if test ${ac_cv_sizeof___int128_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int128_t))" "ac_cv_sizeof___int128_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type___int128_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (__int128_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10620,14 +12493,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int128_t" >&5 -$as_echo "$ac_cv_sizeof___int128_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int128_t" >&5 +printf "%s\n" "$ac_cv_sizeof___int128_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF___INT128_T $ac_cv_sizeof___int128_t -_ACEOF +printf "%s\n" "#define SIZEOF___INT128_T $ac_cv_sizeof___int128_t" >>confdefs.h @@ -10656,28 +12527,30 @@ _ACEOF else gcc_atomic_type128="#error " fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working __sync_synchronize()" >&5 -$as_echo_n "checking for a working __sync_synchronize()... " >&6; } -if ${ethr_cv___sync_synchronize+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working __sync_synchronize()" >&5 +printf %s "checking for a working __sync_synchronize()... " >&6; } +if test ${ethr_cv___sync_synchronize+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv___sync_synchronize=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { __sync_synchronize(); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv___sync_synchronize=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $ethr_cv___sync_synchronize = yes; then # @@ -10722,8 +12595,8 @@ EOF fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv___sync_synchronize" >&5 -$as_echo "$ethr_cv___sync_synchronize" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv___sync_synchronize" >&5 +printf "%s\n" "$ethr_cv___sync_synchronize" >&6; } if test "$ethr_cv___sync_synchronize" = "yes"; then have_sync_synchronize_value="~0" @@ -10731,9 +12604,7 @@ $as_echo "$ethr_cv___sync_synchronize" >&6; } have_sync_synchronize_value="0" fi -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___sync_synchronize $have_sync_synchronize_value -_ACEOF +printf "%s\n" "#define ETHR_HAVE___sync_synchronize $have_sync_synchronize_value" >>confdefs.h @@ -10772,87 +12643,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_add_and_fetch()" >&5 -$as_echo_n "checking for 32-bit __sync_add_and_fetch()... " >&6; } -if ${ethr_cv_32bit___sync_add_and_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_add_and_fetch()" >&5 +printf %s "checking for 32-bit __sync_add_and_fetch()... " >&6; } +if test ${ethr_cv_32bit___sync_add_and_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___sync_add_and_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___sync_add_and_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_add_and_fetch" >&5 -$as_echo "$ethr_cv_32bit___sync_add_and_fetch" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_add_and_fetch()" >&5 -$as_echo_n "checking for 64-bit __sync_add_and_fetch()... " >&6; } -if ${ethr_cv_64bit___sync_add_and_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_add_and_fetch" >&5 +printf "%s\n" "$ethr_cv_32bit___sync_add_and_fetch" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_add_and_fetch()" >&5 +printf %s "checking for 64-bit __sync_add_and_fetch()... " >&6; } +if test ${ethr_cv_64bit___sync_add_and_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___sync_add_and_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___sync_add_and_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_add_and_fetch" >&5 -$as_echo "$ethr_cv_64bit___sync_add_and_fetch" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_add_and_fetch()" >&5 -$as_echo_n "checking for 128-bit __sync_add_and_fetch()... " >&6; } -if ${ethr_cv_128bit___sync_add_and_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_add_and_fetch" >&5 +printf "%s\n" "$ethr_cv_64bit___sync_add_and_fetch" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_add_and_fetch()" >&5 +printf %s "checking for 128-bit __sync_add_and_fetch()... " >&6; } +if test ${ethr_cv_128bit___sync_add_and_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___sync_add_and_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___sync_add_and_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_add_and_fetch" >&5 -$as_echo "$ethr_cv_128bit___sync_add_and_fetch" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_add_and_fetch" >&5 +printf "%s\n" "$ethr_cv_128bit___sync_add_and_fetch" >&6; } case $ethr_cv_128bit___sync_add_and_fetch-$ethr_cv_64bit___sync_add_and_fetch-$ethr_cv_32bit___sync_add_and_fetch in no-no-no) @@ -10873,9 +12750,7 @@ $as_echo "$ethr_cv_128bit___sync_add_and_fetch" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___sync_add_and_fetch $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___sync_add_and_fetch $have_atomic_ops" >>confdefs.h @@ -10914,87 +12789,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_fetch_and_and()" >&5 -$as_echo_n "checking for 32-bit __sync_fetch_and_and()... " >&6; } -if ${ethr_cv_32bit___sync_fetch_and_and+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_fetch_and_and()" >&5 +printf %s "checking for 32-bit __sync_fetch_and_and()... " >&6; } +if test ${ethr_cv_32bit___sync_fetch_and_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___sync_fetch_and_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___sync_fetch_and_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_fetch_and_and" >&5 -$as_echo "$ethr_cv_32bit___sync_fetch_and_and" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_fetch_and_and()" >&5 -$as_echo_n "checking for 64-bit __sync_fetch_and_and()... " >&6; } -if ${ethr_cv_64bit___sync_fetch_and_and+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_fetch_and_and" >&5 +printf "%s\n" "$ethr_cv_32bit___sync_fetch_and_and" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_fetch_and_and()" >&5 +printf %s "checking for 64-bit __sync_fetch_and_and()... " >&6; } +if test ${ethr_cv_64bit___sync_fetch_and_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___sync_fetch_and_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___sync_fetch_and_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_fetch_and_and" >&5 -$as_echo "$ethr_cv_64bit___sync_fetch_and_and" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_fetch_and_and()" >&5 -$as_echo_n "checking for 128-bit __sync_fetch_and_and()... " >&6; } -if ${ethr_cv_128bit___sync_fetch_and_and+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_fetch_and_and" >&5 +printf "%s\n" "$ethr_cv_64bit___sync_fetch_and_and" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_fetch_and_and()" >&5 +printf %s "checking for 128-bit __sync_fetch_and_and()... " >&6; } +if test ${ethr_cv_128bit___sync_fetch_and_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___sync_fetch_and_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___sync_fetch_and_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_fetch_and_and" >&5 -$as_echo "$ethr_cv_128bit___sync_fetch_and_and" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_fetch_and_and" >&5 +printf "%s\n" "$ethr_cv_128bit___sync_fetch_and_and" >&6; } case $ethr_cv_128bit___sync_fetch_and_and-$ethr_cv_64bit___sync_fetch_and_and-$ethr_cv_32bit___sync_fetch_and_and in no-no-no) @@ -11015,9 +12896,7 @@ $as_echo "$ethr_cv_128bit___sync_fetch_and_and" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___sync_fetch_and_and $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___sync_fetch_and_and $have_atomic_ops" >>confdefs.h @@ -11056,87 +12935,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_fetch_and_or()" >&5 -$as_echo_n "checking for 32-bit __sync_fetch_and_or()... " >&6; } -if ${ethr_cv_32bit___sync_fetch_and_or+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_fetch_and_or()" >&5 +printf %s "checking for 32-bit __sync_fetch_and_or()... " >&6; } +if test ${ethr_cv_32bit___sync_fetch_and_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___sync_fetch_and_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___sync_fetch_and_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_fetch_and_or" >&5 -$as_echo "$ethr_cv_32bit___sync_fetch_and_or" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_fetch_and_or()" >&5 -$as_echo_n "checking for 64-bit __sync_fetch_and_or()... " >&6; } -if ${ethr_cv_64bit___sync_fetch_and_or+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_fetch_and_or" >&5 +printf "%s\n" "$ethr_cv_32bit___sync_fetch_and_or" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_fetch_and_or()" >&5 +printf %s "checking for 64-bit __sync_fetch_and_or()... " >&6; } +if test ${ethr_cv_64bit___sync_fetch_and_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___sync_fetch_and_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___sync_fetch_and_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_fetch_and_or" >&5 -$as_echo "$ethr_cv_64bit___sync_fetch_and_or" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_fetch_and_or()" >&5 -$as_echo_n "checking for 128-bit __sync_fetch_and_or()... " >&6; } -if ${ethr_cv_128bit___sync_fetch_and_or+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_fetch_and_or" >&5 +printf "%s\n" "$ethr_cv_64bit___sync_fetch_and_or" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_fetch_and_or()" >&5 +printf %s "checking for 128-bit __sync_fetch_and_or()... " >&6; } +if test ${ethr_cv_128bit___sync_fetch_and_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___sync_fetch_and_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___sync_fetch_and_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_fetch_and_or" >&5 -$as_echo "$ethr_cv_128bit___sync_fetch_and_or" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_fetch_and_or" >&5 +printf "%s\n" "$ethr_cv_128bit___sync_fetch_and_or" >&6; } case $ethr_cv_128bit___sync_fetch_and_or-$ethr_cv_64bit___sync_fetch_and_or-$ethr_cv_32bit___sync_fetch_and_or in no-no-no) @@ -11157,9 +13042,7 @@ $as_echo "$ethr_cv_128bit___sync_fetch_and_or" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___sync_fetch_and_or $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___sync_fetch_and_or $have_atomic_ops" >>confdefs.h @@ -11198,87 +13081,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_val_compare_and_swap()" >&5 -$as_echo_n "checking for 32-bit __sync_val_compare_and_swap()... " >&6; } -if ${ethr_cv_32bit___sync_val_compare_and_swap+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __sync_val_compare_and_swap()" >&5 +printf %s "checking for 32-bit __sync_val_compare_and_swap()... " >&6; } +if test ${ethr_cv_32bit___sync_val_compare_and_swap+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___sync_val_compare_and_swap=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___sync_val_compare_and_swap=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_val_compare_and_swap" >&5 -$as_echo "$ethr_cv_32bit___sync_val_compare_and_swap" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_val_compare_and_swap()" >&5 -$as_echo_n "checking for 64-bit __sync_val_compare_and_swap()... " >&6; } -if ${ethr_cv_64bit___sync_val_compare_and_swap+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___sync_val_compare_and_swap" >&5 +printf "%s\n" "$ethr_cv_32bit___sync_val_compare_and_swap" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __sync_val_compare_and_swap()" >&5 +printf %s "checking for 64-bit __sync_val_compare_and_swap()... " >&6; } +if test ${ethr_cv_64bit___sync_val_compare_and_swap+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___sync_val_compare_and_swap=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___sync_val_compare_and_swap=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_val_compare_and_swap" >&5 -$as_echo "$ethr_cv_64bit___sync_val_compare_and_swap" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_val_compare_and_swap()" >&5 -$as_echo_n "checking for 128-bit __sync_val_compare_and_swap()... " >&6; } -if ${ethr_cv_128bit___sync_val_compare_and_swap+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___sync_val_compare_and_swap" >&5 +printf "%s\n" "$ethr_cv_64bit___sync_val_compare_and_swap" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __sync_val_compare_and_swap()" >&5 +printf %s "checking for 128-bit __sync_val_compare_and_swap()... " >&6; } +if test ${ethr_cv_128bit___sync_val_compare_and_swap+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___sync_val_compare_and_swap=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___sync_val_compare_and_swap=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_val_compare_and_swap" >&5 -$as_echo "$ethr_cv_128bit___sync_val_compare_and_swap" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___sync_val_compare_and_swap" >&5 +printf "%s\n" "$ethr_cv_128bit___sync_val_compare_and_swap" >&6; } case $ethr_cv_128bit___sync_val_compare_and_swap-$ethr_cv_64bit___sync_val_compare_and_swap-$ethr_cv_32bit___sync_val_compare_and_swap in no-no-no) @@ -11299,9 +13188,7 @@ $as_echo "$ethr_cv_128bit___sync_val_compare_and_swap" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___sync_val_compare_and_swap $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___sync_val_compare_and_swap $have_atomic_ops" >>confdefs.h @@ -11341,87 +13228,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_store_n()" >&5 -$as_echo_n "checking for 32-bit __atomic_store_n()... " >&6; } -if ${ethr_cv_32bit___atomic_store_n+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_store_n()" >&5 +printf %s "checking for 32-bit __atomic_store_n()... " >&6; } +if test ${ethr_cv_32bit___atomic_store_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_store_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_store_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_store_n" >&5 -$as_echo "$ethr_cv_32bit___atomic_store_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_store_n()" >&5 -$as_echo_n "checking for 64-bit __atomic_store_n()... " >&6; } -if ${ethr_cv_64bit___atomic_store_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_store_n" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_store_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_store_n()" >&5 +printf %s "checking for 64-bit __atomic_store_n()... " >&6; } +if test ${ethr_cv_64bit___atomic_store_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_store_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_store_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_store_n" >&5 -$as_echo "$ethr_cv_64bit___atomic_store_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_store_n()" >&5 -$as_echo_n "checking for 128-bit __atomic_store_n()... " >&6; } -if ${ethr_cv_128bit___atomic_store_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_store_n" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_store_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_store_n()" >&5 +printf %s "checking for 128-bit __atomic_store_n()... " >&6; } +if test ${ethr_cv_128bit___atomic_store_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_store_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_store_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_store_n" >&5 -$as_echo "$ethr_cv_128bit___atomic_store_n" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_store_n" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_store_n" >&6; } case $ethr_cv_128bit___atomic_store_n-$ethr_cv_64bit___atomic_store_n-$ethr_cv_32bit___atomic_store_n in no-no-no) @@ -11442,9 +13335,7 @@ $as_echo "$ethr_cv_128bit___atomic_store_n" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_store_n $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_store_n $have_atomic_ops" >>confdefs.h @@ -11483,87 +13374,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_load_n()" >&5 -$as_echo_n "checking for 32-bit __atomic_load_n()... " >&6; } -if ${ethr_cv_32bit___atomic_load_n+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_load_n()" >&5 +printf %s "checking for 32-bit __atomic_load_n()... " >&6; } +if test ${ethr_cv_32bit___atomic_load_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_load_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_load_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_load_n" >&5 -$as_echo "$ethr_cv_32bit___atomic_load_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_load_n()" >&5 -$as_echo_n "checking for 64-bit __atomic_load_n()... " >&6; } -if ${ethr_cv_64bit___atomic_load_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_load_n" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_load_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_load_n()" >&5 +printf %s "checking for 64-bit __atomic_load_n()... " >&6; } +if test ${ethr_cv_64bit___atomic_load_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_load_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_load_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_load_n" >&5 -$as_echo "$ethr_cv_64bit___atomic_load_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_load_n()" >&5 -$as_echo_n "checking for 128-bit __atomic_load_n()... " >&6; } -if ${ethr_cv_128bit___atomic_load_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_load_n" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_load_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_load_n()" >&5 +printf %s "checking for 128-bit __atomic_load_n()... " >&6; } +if test ${ethr_cv_128bit___atomic_load_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_load_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_load_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_load_n" >&5 -$as_echo "$ethr_cv_128bit___atomic_load_n" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_load_n" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_load_n" >&6; } case $ethr_cv_128bit___atomic_load_n-$ethr_cv_64bit___atomic_load_n-$ethr_cv_32bit___atomic_load_n in no-no-no) @@ -11584,9 +13481,7 @@ $as_echo "$ethr_cv_128bit___atomic_load_n" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_load_n $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_load_n $have_atomic_ops" >>confdefs.h @@ -11625,87 +13520,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_add_fetch()" >&5 -$as_echo_n "checking for 32-bit __atomic_add_fetch()... " >&6; } -if ${ethr_cv_32bit___atomic_add_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_add_fetch()" >&5 +printf %s "checking for 32-bit __atomic_add_fetch()... " >&6; } +if test ${ethr_cv_32bit___atomic_add_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_add_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_add_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_add_fetch" >&5 -$as_echo "$ethr_cv_32bit___atomic_add_fetch" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_add_fetch()" >&5 -$as_echo_n "checking for 64-bit __atomic_add_fetch()... " >&6; } -if ${ethr_cv_64bit___atomic_add_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_add_fetch" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_add_fetch" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_add_fetch()" >&5 +printf %s "checking for 64-bit __atomic_add_fetch()... " >&6; } +if test ${ethr_cv_64bit___atomic_add_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_add_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_add_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_add_fetch" >&5 -$as_echo "$ethr_cv_64bit___atomic_add_fetch" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_add_fetch()" >&5 -$as_echo_n "checking for 128-bit __atomic_add_fetch()... " >&6; } -if ${ethr_cv_128bit___atomic_add_fetch+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_add_fetch" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_add_fetch" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_add_fetch()" >&5 +printf %s "checking for 128-bit __atomic_add_fetch()... " >&6; } +if test ${ethr_cv_128bit___atomic_add_fetch+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_add_fetch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_add_fetch=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_add_fetch" >&5 -$as_echo "$ethr_cv_128bit___atomic_add_fetch" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_add_fetch" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_add_fetch" >&6; } case $ethr_cv_128bit___atomic_add_fetch-$ethr_cv_64bit___atomic_add_fetch-$ethr_cv_32bit___atomic_add_fetch in no-no-no) @@ -11726,9 +13627,7 @@ $as_echo "$ethr_cv_128bit___atomic_add_fetch" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_add_fetch $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_add_fetch $have_atomic_ops" >>confdefs.h @@ -11767,87 +13666,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_fetch_and()" >&5 -$as_echo_n "checking for 32-bit __atomic_fetch_and()... " >&6; } -if ${ethr_cv_32bit___atomic_fetch_and+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_fetch_and()" >&5 +printf %s "checking for 32-bit __atomic_fetch_and()... " >&6; } +if test ${ethr_cv_32bit___atomic_fetch_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_fetch_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_fetch_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_fetch_and" >&5 -$as_echo "$ethr_cv_32bit___atomic_fetch_and" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_fetch_and()" >&5 -$as_echo_n "checking for 64-bit __atomic_fetch_and()... " >&6; } -if ${ethr_cv_64bit___atomic_fetch_and+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_fetch_and" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_fetch_and" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_fetch_and()" >&5 +printf %s "checking for 64-bit __atomic_fetch_and()... " >&6; } +if test ${ethr_cv_64bit___atomic_fetch_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_fetch_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_fetch_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_fetch_and" >&5 -$as_echo "$ethr_cv_64bit___atomic_fetch_and" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_fetch_and()" >&5 -$as_echo_n "checking for 128-bit __atomic_fetch_and()... " >&6; } -if ${ethr_cv_128bit___atomic_fetch_and+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_fetch_and" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_fetch_and" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_fetch_and()" >&5 +printf %s "checking for 128-bit __atomic_fetch_and()... " >&6; } +if test ${ethr_cv_128bit___atomic_fetch_and+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_fetch_and=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_fetch_and=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_fetch_and" >&5 -$as_echo "$ethr_cv_128bit___atomic_fetch_and" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_fetch_and" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_fetch_and" >&6; } case $ethr_cv_128bit___atomic_fetch_and-$ethr_cv_64bit___atomic_fetch_and-$ethr_cv_32bit___atomic_fetch_and in no-no-no) @@ -11868,9 +13773,7 @@ $as_echo "$ethr_cv_128bit___atomic_fetch_and" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_fetch_and $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_fetch_and $have_atomic_ops" >>confdefs.h @@ -11909,87 +13812,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_fetch_or()" >&5 -$as_echo_n "checking for 32-bit __atomic_fetch_or()... " >&6; } -if ${ethr_cv_32bit___atomic_fetch_or+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_fetch_or()" >&5 +printf %s "checking for 32-bit __atomic_fetch_or()... " >&6; } +if test ${ethr_cv_32bit___atomic_fetch_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_fetch_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_fetch_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_fetch_or" >&5 -$as_echo "$ethr_cv_32bit___atomic_fetch_or" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_fetch_or()" >&5 -$as_echo_n "checking for 64-bit __atomic_fetch_or()... " >&6; } -if ${ethr_cv_64bit___atomic_fetch_or+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_fetch_or" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_fetch_or" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_fetch_or()" >&5 +printf %s "checking for 64-bit __atomic_fetch_or()... " >&6; } +if test ${ethr_cv_64bit___atomic_fetch_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_fetch_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_fetch_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_fetch_or" >&5 -$as_echo "$ethr_cv_64bit___atomic_fetch_or" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_fetch_or()" >&5 -$as_echo_n "checking for 128-bit __atomic_fetch_or()... " >&6; } -if ${ethr_cv_128bit___atomic_fetch_or+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_fetch_or" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_fetch_or" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_fetch_or()" >&5 +printf %s "checking for 128-bit __atomic_fetch_or()... " >&6; } +if test ${ethr_cv_128bit___atomic_fetch_or+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_fetch_or=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_fetch_or=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_fetch_or" >&5 -$as_echo "$ethr_cv_128bit___atomic_fetch_or" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_fetch_or" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_fetch_or" >&6; } case $ethr_cv_128bit___atomic_fetch_or-$ethr_cv_64bit___atomic_fetch_or-$ethr_cv_32bit___atomic_fetch_or in no-no-no) @@ -12010,9 +13919,7 @@ $as_echo "$ethr_cv_128bit___atomic_fetch_or" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_fetch_or $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_fetch_or $have_atomic_ops" >>confdefs.h @@ -12051,87 +13958,93 @@ _ACEOF eval atomic${atomic_bit_size}_call=\"$atomic_call\" done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_compare_exchange_n()" >&5 -$as_echo_n "checking for 32-bit __atomic_compare_exchange_n()... " >&6; } -if ${ethr_cv_32bit___atomic_compare_exchange_n+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 32-bit __atomic_compare_exchange_n()" >&5 +printf %s "checking for 32-bit __atomic_compare_exchange_n()... " >&6; } +if test ${ethr_cv_32bit___atomic_compare_exchange_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_32bit___atomic_compare_exchange_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic32_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_32bit___atomic_compare_exchange_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_compare_exchange_n" >&5 -$as_echo "$ethr_cv_32bit___atomic_compare_exchange_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_compare_exchange_n()" >&5 -$as_echo_n "checking for 64-bit __atomic_compare_exchange_n()... " >&6; } -if ${ethr_cv_64bit___atomic_compare_exchange_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_32bit___atomic_compare_exchange_n" >&5 +printf "%s\n" "$ethr_cv_32bit___atomic_compare_exchange_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit __atomic_compare_exchange_n()" >&5 +printf %s "checking for 64-bit __atomic_compare_exchange_n()... " >&6; } +if test ${ethr_cv_64bit___atomic_compare_exchange_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_64bit___atomic_compare_exchange_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic64_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_64bit___atomic_compare_exchange_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_compare_exchange_n" >&5 -$as_echo "$ethr_cv_64bit___atomic_compare_exchange_n" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_compare_exchange_n()" >&5 -$as_echo_n "checking for 128-bit __atomic_compare_exchange_n()... " >&6; } -if ${ethr_cv_128bit___atomic_compare_exchange_n+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_64bit___atomic_compare_exchange_n" >&5 +printf "%s\n" "$ethr_cv_64bit___atomic_compare_exchange_n" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 128-bit __atomic_compare_exchange_n()" >&5 +printf %s "checking for 128-bit __atomic_compare_exchange_n()... " >&6; } +if test ${ethr_cv_128bit___atomic_compare_exchange_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_128bit___atomic_compare_exchange_n=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { $atomic128_call ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_128bit___atomic_compare_exchange_n=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_compare_exchange_n" >&5 -$as_echo "$ethr_cv_128bit___atomic_compare_exchange_n" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_128bit___atomic_compare_exchange_n" >&5 +printf "%s\n" "$ethr_cv_128bit___atomic_compare_exchange_n" >&6; } case $ethr_cv_128bit___atomic_compare_exchange_n-$ethr_cv_64bit___atomic_compare_exchange_n-$ethr_cv_32bit___atomic_compare_exchange_n in no-no-no) @@ -12152,9 +14065,7 @@ $as_echo "$ethr_cv_128bit___atomic_compare_exchange_n" >&6; } have_atomic_ops=28;; esac -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE___atomic_compare_exchange_n $have_atomic_ops -_ACEOF +printf "%s\n" "#define ETHR_HAVE___atomic_compare_exchange_n $have_atomic_ops" >>confdefs.h @@ -12162,20 +14073,25 @@ _ACEOF ethr_arm_dbm_sy_instr_val=0 ethr_arm_dbm_st_instr_val=0 ethr_arm_dbm_ld_instr_val=0 - case "$GCC-$host_cpu" in - yes-arm*|yes-aarch*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb sy' instruction" >&5 -$as_echo_n "checking for ARM 'dmb sy' instruction... " >&6; } -if ${ethr_cv_arm_dbm_sy_instr+:} false; then : - $as_echo_n "(cached) " >&6 -else + ethr_arm_isb_sy_instr_val=0 + ethr_arm_dc_cvau_instr_val=0 + ethr_arm_ic_ivau_instr_val=0 + case "$GCC-$host_cpu" in #( + yes-arm*|yes-aarch*) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb sy' instruction" >&5 +printf %s "checking for ARM 'dmb sy' instruction... " >&6; } +if test ${ethr_cv_arm_dbm_sy_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_arm_dbm_sy_instr=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { __asm__ __volatile__("dmb sy" : : : "memory"); @@ -12184,32 +14100,34 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_arm_dbm_sy_instr=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_sy_instr" >&5 -$as_echo "$ethr_cv_arm_dbm_sy_instr" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_sy_instr" >&5 +printf "%s\n" "$ethr_cv_arm_dbm_sy_instr" >&6; } if test $ethr_cv_arm_dbm_sy_instr = yes; then ethr_arm_dbm_sy_instr_val=1 test $ethr_cv_64bit___atomic_compare_exchange_n = yes && ethr_have_gcc_native_atomics=yes fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb st' instruction" >&5 -$as_echo_n "checking for ARM 'dmb st' instruction... " >&6; } -if ${ethr_cv_arm_dbm_st_instr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb st' instruction" >&5 +printf %s "checking for ARM 'dmb st' instruction... " >&6; } +if test ${ethr_cv_arm_dbm_st_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_arm_dbm_st_instr=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { __asm__ __volatile__("dmb st" : : : "memory"); @@ -12218,30 +14136,32 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_arm_dbm_st_instr=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_st_instr" >&5 -$as_echo "$ethr_cv_arm_dbm_st_instr" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_st_instr" >&5 +printf "%s\n" "$ethr_cv_arm_dbm_st_instr" >&6; } if test $ethr_cv_arm_dbm_st_instr = yes; then ethr_arm_dbm_st_instr_val=1 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb ld' instruction" >&5 -$as_echo_n "checking for ARM 'dmb ld' instruction... " >&6; } -if ${ethr_cv_arm_dbm_ld_instr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'dmb ld' instruction" >&5 +printf %s "checking for ARM 'dmb ld' instruction... " >&6; } +if test ${ethr_cv_arm_dbm_ld_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ethr_cv_arm_dbm_ld_instr=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { __asm__ __volatile__("dmb ld" : : : "memory"); @@ -12250,35 +14170,144 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_cv_arm_dbm_ld_instr=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_ld_instr" >&5 -$as_echo "$ethr_cv_arm_dbm_ld_instr" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dbm_ld_instr" >&5 +printf "%s\n" "$ethr_cv_arm_dbm_ld_instr" >&6; } if test $ethr_cv_arm_dbm_ld_instr = yes; then ethr_arm_dbm_ld_instr_val=1 - fi;; - *) - ;; - esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'isb sy' instruction" >&5 +printf %s "checking for ARM 'isb sy' instruction... " >&6; } +if test ${ethr_cv_arm_isb_sy_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ethr_cv_arm_isb_sy_instr=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE_GCC_ASM_ARM_DMB_INSTRUCTION $ethr_arm_dbm_sy_instr_val + __asm__ __volatile__("isb sy\n" : : : "memory"); + + ; + return 0; +} _ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_arm_isb_sy_instr=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_isb_sy_instr" >&5 +printf "%s\n" "$ethr_cv_arm_isb_sy_instr" >&6; } + if test $ethr_cv_arm_isb_sy_instr = yes; then + ethr_arm_isb_sy_instr_val=1 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'dc cvau' instruction" >&5 +printf %s "checking for ARM 'dc cvau' instruction... " >&6; } +if test ${ethr_cv_arm_dc_cvau_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ethr_cv_arm_dc_cvau_instr=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + char data[512]; __asm__ __volatile__("dc cvau, %0\n" :: "r" (data) : "memory"); -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION $ethr_arm_dbm_st_instr_val + ; + return 0; +} _ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_arm_dc_cvau_instr=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_dc_cvau_instr" >&5 +printf "%s\n" "$ethr_cv_arm_dc_cvau_instr" >&6; } + if test $ethr_cv_arm_dc_cvau_instr = yes; then + ethr_arm_dc_cvau_instr_val=1 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ARM 'ic ivau' instruction" >&5 +printf %s "checking for ARM 'ic ivau' instruction... " >&6; } +if test ${ethr_cv_arm_ic_ivau_instr+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ethr_cv_arm_ic_ivau_instr=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int +main (void) +{ -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE_GCC_ASM_ARM_DMB_LD_INSTRUCTION $ethr_arm_dbm_ld_instr_val + char data[512]; __asm__ __volatile__("ic ivau, %0\n" :: "r" (data) : "memory"); + + ; + return 0; +} _ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ethr_cv_arm_ic_ivau_instr=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_cv_arm_ic_ivau_instr" >&5 +printf "%s\n" "$ethr_cv_arm_ic_ivau_instr" >&6; } + if test $ethr_cv_arm_ic_ivau_instr = yes; then + ethr_arm_ic_ivau_instr_val=1 + fi + ;; #( + *) : + ;; +esac + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_DMB_INSTRUCTION $ethr_arm_dbm_sy_instr_val" >>confdefs.h + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION $ethr_arm_dbm_st_instr_val" >>confdefs.h + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_DMB_LD_INSTRUCTION $ethr_arm_dbm_ld_instr_val" >>confdefs.h + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_ISB_SY_INSTRUCTION $ethr_arm_isb_sy_instr_val" >>confdefs.h + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION $ethr_arm_dc_cvau_instr_val" >>confdefs.h + + +printf "%s\n" "#define ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION $ethr_arm_ic_ivau_instr_val" >>confdefs.h + test $ethr_cv_32bit___sync_val_compare_and_swap = yes && ethr_have_gcc_native_atomics=yes @@ -12298,15 +14327,13 @@ _ACEOF test $ethr_have_gcc_atomic_builtins = 1 && ethr_native_atomic_implementation=gcc_atomic_sync fi -cat >>confdefs.h <<_ACEOF -#define ETHR_HAVE_GCC___ATOMIC_BUILTINS $ethr_have_gcc_atomic_builtins -_ACEOF +printf "%s\n" "#define ETHR_HAVE_GCC___ATOMIC_BUILTINS $ethr_have_gcc_atomic_builtins" >>confdefs.h test $ethr_have_gcc_native_atomics = yes && ethr_have_native_atomics=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a usable libatomic_ops implementation" >&5 -$as_echo_n "checking for a usable libatomic_ops implementation... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a usable libatomic_ops implementation" >&5 +printf %s "checking for a usable libatomic_ops implementation... " >&6; } case "x$with_libatomic_ops" in xno | xyes | x) libatomic_ops_include= @@ -12324,7 +14351,7 @@ $as_echo_n "checking for a usable libatomic_ops implementation... " >&6; } /* end confdefs.h. */ #include "atomic_ops.h" int -main () +main (void) { volatile AO_t x; @@ -12362,35 +14389,40 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ethr_have_native_atomics=yes ethr_native_atomic_implementation=libatomic_ops ethr_have_libatomic_ops=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ethr_have_libatomic_ops" >&5 -$as_echo "$ethr_have_libatomic_ops" >&6; } - if test $ethr_have_libatomic_ops = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ethr_have_libatomic_ops" >&5 +printf "%s\n" "$ethr_have_libatomic_ops" >&6; } + if test $ethr_have_libatomic_ops = yes +then : + # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of AO_t" >&5 -$as_echo_n "checking size of AO_t... " >&6; } -if ${ac_cv_sizeof_AO_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of AO_t" >&5 +printf %s "checking size of AO_t... " >&6; } +if test ${ac_cv_sizeof_AO_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (AO_t))" "ac_cv_sizeof_AO_t" " #include #include \"atomic_ops.h\" -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_AO_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (AO_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -12399,49 +14431,49 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_AO_t" >&5 -$as_echo "$ac_cv_sizeof_AO_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_AO_t" >&5 +printf "%s\n" "$ac_cv_sizeof_AO_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_AO_T $ac_cv_sizeof_AO_t -_ACEOF +printf "%s\n" "#define SIZEOF_AO_T $ac_cv_sizeof_AO_t" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF_AO_T $ac_cv_sizeof_AO_t -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF_AO_T $ac_cv_sizeof_AO_t" >>confdefs.h -$as_echo "#define ETHR_HAVE_LIBATOMIC_OPS 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_LIBATOMIC_OPS 1" >>confdefs.h if test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then -$as_echo "#define ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS 1" >>confdefs.h +printf "%s\n" "#define ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS 1" >>confdefs.h fi ETHR_DEFS="$ETHR_DEFS $libatomic_ops_include" - elif test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then + +elif test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x" +then : + as_fn_error $? "No usable libatomic_ops implementation found" "$LINENO" 5 - fi + +fi case "$host_cpu" in sparc | sun4u | sparc64 | sun4v) case "$with_sparc_memory_order" in "TSO") -$as_echo "#define ETHR_SPARC_TSO 1" >>confdefs.h +printf "%s\n" "#define ETHR_SPARC_TSO 1" >>confdefs.h ;; "PSO") -$as_echo "#define ETHR_SPARC_PSO 1" >>confdefs.h +printf "%s\n" "#define ETHR_SPARC_PSO 1" >>confdefs.h ;; "RMO"|"") -$as_echo "#define ETHR_SPARC_RMO 1" >>confdefs.h +printf "%s\n" "#define ETHR_SPARC_RMO 1" >>confdefs.h ;; *) as_fn_error $? "Unsupported Sparc memory order: $with_sparc_memory_order" "$LINENO" 5;; @@ -12451,7 +14483,7 @@ $as_echo "#define ETHR_SPARC_RMO 1" >>confdefs.h i86pc | i*86 | x86_64 | amd64) if test "$enable_x86_out_of_order" = "yes"; then -$as_echo "#define ETHR_X86_OUT_OF_ORDER 1" >>confdefs.h +printf "%s\n" "#define ETHR_X86_OUT_OF_ORDER 1" >>confdefs.h fi ethr_native_atomic_implementation=ethread @@ -12466,31 +14498,30 @@ $as_echo "#define ETHR_X86_OUT_OF_ORDER 1" >>confdefs.h ;; esac - fi + +fi test ethr_have_native_atomics = "yes" && ethr_have_native_spinlock=yes LIBS=$saved_libs CPPFLAGS=$saved_cppflags - ;; - *) - ;; + ;; #( + *) : + ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether default stack size should be modified" >&5 -$as_echo_n "checking whether default stack size should be modified... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether default stack size should be modified" >&5 +printf %s "checking whether default stack size should be modified... " >&6; } if test "x$ethr_modified_default_stack_size" != "x"; then -cat >>confdefs.h <<_ACEOF -#define ETHR_MODIFIED_DEFAULT_STACK_SIZE $ethr_modified_default_stack_size -_ACEOF +printf "%s\n" "#define ETHR_MODIFIED_DEFAULT_STACK_SIZE $ethr_modified_default_stack_size" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; to $ethr_modified_default_stack_size kilo words" >&5 -$as_echo "yes; to $ethr_modified_default_stack_size kilo words" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes; to $ethr_modified_default_stack_size kilo words" >&5 +printf "%s\n" "yes; to $ethr_modified_default_stack_size kilo words" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ETHR_THR_LIB_BASE" != "x"; then @@ -12503,17 +14534,19 @@ fi # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -12522,37 +14555,35 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF_PTR $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF_PTR $ac_cv_sizeof_void_p" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +printf %s "checking size of int... " >&6; } +if test ${ac_cv_sizeof_int+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else @@ -12561,36 +14592,34 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +printf "%s\n" "$ac_cv_sizeof_int" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF +printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF_INT $ac_cv_sizeof_int -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +printf %s "checking size of long... " >&6; } +if test ${ac_cv_sizeof_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else @@ -12599,36 +14628,34 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +printf %s "checking size of long long... " >&6; } +if test ${ac_cv_sizeof_long_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else @@ -12637,36 +14664,34 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of __int64" >&5 -$as_echo_n "checking size of __int64... " >&6; } -if ${ac_cv_sizeof___int64+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int64))" "ac_cv_sizeof___int64" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of __int64" >&5 +printf %s "checking size of __int64... " >&6; } +if test ${ac_cv_sizeof___int64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int64))" "ac_cv_sizeof___int64" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type___int64" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (__int64) See \`config.log' for more details" "$LINENO" 5; } else @@ -12675,36 +14700,34 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int64" >&5 -$as_echo "$ac_cv_sizeof___int64" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int64" >&5 +printf "%s\n" "$ac_cv_sizeof___int64" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF___INT64 $ac_cv_sizeof___int64 -_ACEOF +printf "%s\n" "#define SIZEOF___INT64 $ac_cv_sizeof___int64" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF___INT64 $ac_cv_sizeof___int64 -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF___INT64 $ac_cv_sizeof___int64" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of __int128_t" >&5 -$as_echo_n "checking size of __int128_t... " >&6; } -if ${ac_cv_sizeof___int128_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int128_t))" "ac_cv_sizeof___int128_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of __int128_t" >&5 +printf %s "checking size of __int128_t... " >&6; } +if test ${ac_cv_sizeof___int128_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (__int128_t))" "ac_cv_sizeof___int128_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type___int128_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (__int128_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -12713,20 +14736,16 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int128_t" >&5 -$as_echo "$ac_cv_sizeof___int128_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof___int128_t" >&5 +printf "%s\n" "$ac_cv_sizeof___int128_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF___INT128_T $ac_cv_sizeof___int128_t -_ACEOF +printf "%s\n" "#define SIZEOF___INT128_T $ac_cv_sizeof___int128_t" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define ETHR_SIZEOF___INT128_T $ac_cv_sizeof___int128_t -_ACEOF +printf "%s\n" "#define ETHR_SIZEOF___INT128_T $ac_cv_sizeof___int128_t" >>confdefs.h @@ -12736,11 +14755,12 @@ case X$erl_xcomp_bigendian in *) as_fn_error $? "Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian" "$LINENO" 5;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +printf %s "checking whether byte ordering is bigendian... " >&6; } +if test ${ac_cv_c_bigendian+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12751,7 +14771,8 @@ else typedef int dummy; _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. @@ -12775,7 +14796,7 @@ if ac_fn_c_try_compile "$LINENO"; then : fi done fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12784,7 +14805,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ @@ -12796,7 +14817,8 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -12804,7 +14826,7 @@ if ac_fn_c_try_compile "$LINENO"; then : #include int -main () +main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian @@ -12814,14 +14836,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). @@ -12830,7 +14853,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros @@ -12840,14 +14863,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef _BIG_ENDIAN not big endian @@ -12857,31 +14881,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -short int ascii_mm[] = +unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = + unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } - short int ebcdic_ii[] = + unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = + unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; @@ -12889,14 +14915,15 @@ short int ascii_mm[] = extern int foo; int -main () +main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi @@ -12909,13 +14936,13 @@ if ac_fn_c_try_compile "$LINENO"; then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int -main () +main (void) { /* Are we little or big endian? From Harbison&Steele. */ @@ -12931,9 +14958,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_c_bigendian=no -else +else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -12942,17 +14970,17 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) - $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h + printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) -$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) @@ -12963,7 +14991,7 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h if test "$ac_cv_c_bigendian" = "yes"; then -$as_echo "#define ETHR_BIGENDIAN 1" >>confdefs.h +printf "%s\n" "#define ETHR_BIGENDIAN 1" >>confdefs.h fi @@ -12973,15 +15001,17 @@ case X$erl_xcomp_double_middle_endian in *) as_fn_error $? "Bad erl_xcomp_double_middle_endian value: $erl_xcomp_double_middle_endian" "$LINENO" 5;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether double word ordering is middle-endian" >&5 -$as_echo_n "checking whether double word ordering is middle-endian... " >&6; } -if ${ac_cv_c_double_middle_endian+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether double word ordering is middle-endian" >&5 +printf %s "checking whether double word ordering is middle-endian... " >&6; } +if test ${ac_cv_c_double_middle_endian+y} +then : + printf %s "(cached) " >&6 +else $as_nop # It does not; compile a test program. -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_c_double_middle=unknown -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -13050,9 +15080,10 @@ main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_c_double_middle_endian=no -else +else $as_nop ac_cv_c_double_middle_endian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -13060,28 +15091,29 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_double_middle_endian" >&5 -$as_echo "$ac_cv_c_double_middle_endian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_double_middle_endian" >&5 +printf "%s\n" "$ac_cv_c_double_middle_endian" >&6; } case $ac_cv_c_double_middle_endian in yes) -$as_echo "#define DOUBLE_MIDDLE_ENDIAN 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_MIDDLE_ENDIAN 1" >>confdefs.h ;; no) ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unknown double endianness + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown double endianness presetting ac_cv_c_double_middle_endian=no (or yes) will help" >&5 -$as_echo "$as_me: WARNING: unknown double endianness +printf "%s\n" "$as_me: WARNING: unknown double endianness presetting ac_cv_c_double_middle_endian=no (or yes) will help" >&2;} ;; esac ETHR_X86_SSE2_ASM=no -case "$GCC-$ac_cv_sizeof_void_p-$host_cpu" in - yes-4-i86pc | yes-4-i*86 | yes-4-x86_64 | yes-4-amd64) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc sse2 asm support" >&5 -$as_echo_n "checking for gcc sse2 asm support... " >&6; } +case "$GCC-$ac_cv_sizeof_void_p-$host_cpu" in #( + yes-4-i86pc | yes-4-i*86 | yes-4-x86_64 | yes-4-amd64) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc sse2 asm support" >&5 +printf %s "checking for gcc sse2 asm support... " >&6; } save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -msse2" gcc_sse2_asm=no @@ -13089,7 +15121,7 @@ $as_echo_n "checking for gcc sse2 asm support... " >&6; } /* end confdefs.h. */ int -main () +main (void) { long long x, *y; @@ -13099,26 +15131,27 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : gcc_sse2_asm=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$save_CFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_sse2_asm" >&5 -$as_echo "$gcc_sse2_asm" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gcc_sse2_asm" >&5 +printf "%s\n" "$gcc_sse2_asm" >&6; } if test "$gcc_sse2_asm" = "yes"; then -$as_echo "#define ETHR_GCC_HAVE_SSE2_ASM_SUPPORT 1" >>confdefs.h +printf "%s\n" "#define ETHR_GCC_HAVE_SSE2_ASM_SUPPORT 1" >>confdefs.h ETHR_X86_SSE2_ASM=yes fi - ;; - *) - ;; + ;; #( + *) : + ;; esac -case "$GCC-$host_cpu" in - yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64) +case "$GCC-$host_cpu" in #( + yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64) : if test $ac_cv_sizeof_void_p = 4; then dw_cmpxchg="cmpxchg8b" @@ -13145,15 +15178,15 @@ case "$GCC-$host_cpu" in *) pic_text="";; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc $pic_text$dw_cmpxchg plain asm support" >&5 -$as_echo_n "checking for gcc $pic_text$dw_cmpxchg plain asm support... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc $pic_text$dw_cmpxchg plain asm support" >&5 +printf %s "checking for gcc $pic_text$dw_cmpxchg plain asm support... " >&6; } plain_cmpxchg=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { char xchgd; @@ -13173,13 +15206,14 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : plain_cmpxchg=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $plain_cmpxchg" >&5 -$as_echo "$plain_cmpxchg" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $plain_cmpxchg" >&5 +printf "%s\n" "$plain_cmpxchg" >&6; } if test $pic_cmpxchg = yes; then gcc_pic_dw_cmpxchg_asm=$plain_cmpxchg @@ -13200,7 +15234,7 @@ $as_echo "$plain_cmpxchg" >&6; } /* end confdefs.h. */ int -main () +main (void) { #if !defined(__PIC__) || !__PIC__ @@ -13211,13 +15245,14 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : pic_cmpxchg=yes gcc_cflags_pic=yes -else +else $as_nop pic_cmpxchg=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $pic_cmpxchg = yes; then gcc_pic_dw_cmpxchg_asm=$gcc_dw_cmpxchg_asm @@ -13229,10 +15264,12 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done - if test $gcc_pic_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4; then + if test $gcc_pic_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4 +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc pic cmpxchg8b asm support with EBX workaround" >&5 -$as_echo_n "checking for gcc pic cmpxchg8b asm support with EBX workaround... " >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc pic cmpxchg8b asm support with EBX workaround" >&5 +printf %s "checking for gcc pic cmpxchg8b asm support with EBX workaround... " >&6; } # Check if we can work around it by managing the ebx # register explicitly in the asm... @@ -13241,7 +15278,7 @@ $as_echo_n "checking for gcc pic cmpxchg8b asm support with EBX workaround... " /* end confdefs.h. */ int -main () +main (void) { char xchgd; @@ -13260,19 +15297,22 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : gcc_pic_dw_cmpxchg_asm=yes gcc_cmpxchg8b_pic_no_clobber_ebx=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gcc_pic_dw_cmpxchg_asm" >&5 +printf "%s\n" "$gcc_pic_dw_cmpxchg_asm" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_pic_dw_cmpxchg_asm" >&5 -$as_echo "$gcc_pic_dw_cmpxchg_asm" >&6; } + if test $gcc_pic_dw_cmpxchg_asm = no +then : - if test $gcc_pic_dw_cmpxchg_asm = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds" >&5 -$as_echo_n "checking for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds" >&5 +printf %s "checking for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds... " >&6; } # If no optimization is enabled we sometimes get a # register shortage. Check if we can work around # this... @@ -13281,7 +15321,7 @@ $as_echo_n "checking for gcc pic cmpxchg8b asm support with EBX and register sho /* end confdefs.h. */ int -main () +main (void) { char xchgd; @@ -13302,46 +15342,49 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : gcc_pic_dw_cmpxchg_asm=yes gcc_cmpxchg8b_pic_no_clobber_ebx=yes gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_pic_dw_cmpxchg_asm" >&5 -$as_echo "$gcc_pic_dw_cmpxchg_asm" >&6; } - fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gcc_pic_dw_cmpxchg_asm" >&5 +printf "%s\n" "$gcc_pic_dw_cmpxchg_asm" >&6; } + +fi if test $gcc_cflags_pic = yes; then gcc_dw_cmpxchg_asm=$gcc_pic_dw_cmpxchg_asm fi - fi +fi CFLAGS="$save_CFLAGS" if test "$gcc_cmpxchg8b_pic_no_clobber_ebx" = "yes"; then -$as_echo "#define ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX 1" >>confdefs.h +printf "%s\n" "#define ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX 1" >>confdefs.h fi if test "$gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage" = "yes"; then -$as_echo "#define ETHR_CMPXCHG8B_REGISTER_SHORTAGE 1" >>confdefs.h +printf "%s\n" "#define ETHR_CMPXCHG8B_REGISTER_SHORTAGE 1" >>confdefs.h fi if test "$gcc_dw_cmpxchg_asm" = "yes"; then -$as_echo "#define ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT 1" >>confdefs.h +printf "%s\n" "#define ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT 1" >>confdefs.h - fi;; - *) - ;; + fi + ;; #( + *) : + ;; esac -$as_echo "#define ETHR_HAVE_ETHREAD_DEFINES 1" >>confdefs.h +printf "%s\n" "#define ETHR_HAVE_ETHREAD_DEFINES 1" >>confdefs.h @@ -13358,7 +15401,7 @@ if test "X$ETHR_LIB_NAME" = "X"; then as_fn_error $? "cannot build emulator since no thread library was found" "$LINENO" 5 fi -TYPES=opt +DEFAULT_TYPES="opt" DIRTY_SCHEDULER_TEST=$enable_dirty_schedulers_test @@ -13377,7 +15420,7 @@ EOF test "X$smp_require_native_atomics" = "Xyes" && -$as_echo "#define ETHR_SMP_REQUIRE_NATIVE_IMPLS 1" >>confdefs.h +printf "%s\n" "#define ETHR_SMP_REQUIRE_NATIVE_IMPLS 1" >>confdefs.h case "$ethr_have_native_atomics-$smp_require_native_atomics-$ethr_have_native_spinlock" in @@ -13441,35 +15484,32 @@ EOF esac -for ac_func in posix_fadvise closefrom -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" +if test "x$ac_cv_func_posix_fadvise" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_FADVISE 1" >>confdefs.h fi -done - -for ac_header in linux/falloc.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "linux/falloc.h" "ac_cv_header_linux_falloc_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_falloc_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINUX_FALLOC_H 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom" +if test "x$ac_cv_func_closefrom" = xyes +then : + printf "%s\n" "#define HAVE_CLOSEFROM 1" >>confdefs.h fi -done +ac_fn_c_check_header_compile "$LINENO" "linux/falloc.h" "ac_cv_header_linux_falloc_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_falloc_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_FALLOC_H 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fallocate() works" >&5 -$as_echo_n "checking whether fallocate() works... " >&6; } -if ${i_cv_fallocate_works+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fallocate() works" >&5 +printf %s "checking whether fallocate() works... " >&6; } +if test ${i_cv_fallocate_works+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13482,7 +15522,7 @@ else #include int -main () +main (void) { int fd = creat("conftest.temp", 0600); @@ -13492,34 +15532,37 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : i_cv_fallocate_works=yes -else +else $as_nop i_cv_fallocate_works=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $i_cv_fallocate_works" >&5 -$as_echo "$i_cv_fallocate_works" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $i_cv_fallocate_works" >&5 +printf "%s\n" "$i_cv_fallocate_works" >&6; } if test $i_cv_fallocate_works = yes; then -$as_echo "#define HAVE_FALLOCATE 1" >>confdefs.h +printf "%s\n" "#define HAVE_FALLOCATE 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_fallocate() works" >&5 -$as_echo_n "checking whether posix_fallocate() works... " >&6; } -if ${i_cv_posix_fallocate_works+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_fallocate() works" >&5 +printf %s "checking whether posix_fallocate() works... " >&6; } +if test ${i_cv_posix_fallocate_works+y} +then : + printf %s "(cached) " >&6 +else $as_nop - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : i_cv_posix_fallocate_works=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13546,11 +15589,12 @@ else } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : i_cv_posix_fallocate_works=yes -else +else $as_nop i_cv_posix_fallocate_works=no @@ -13561,11 +15605,11 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $i_cv_posix_fallocate_works" >&5 -$as_echo "$i_cv_posix_fallocate_works" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $i_cv_posix_fallocate_works" >&5 +printf "%s\n" "$i_cv_posix_fallocate_works" >&6; } if test $i_cv_posix_fallocate_works = yes; then -$as_echo "#define HAVE_POSIX_FALLOCATE /**/" >>confdefs.h +printf "%s\n" "#define HAVE_POSIX_FALLOCATE /**/" >>confdefs.h fi @@ -13588,35 +15632,35 @@ EMU_THR_X_LIBS=$ETHR_X_LIBS EMU_THR_LIBS=$ETHR_LIBS EMU_THR_DEFS=$ETHR_DEFS ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS threads" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lock checking should be enabled" >&5 -$as_echo_n "checking whether lock checking should be enabled... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lock_check" >&5 -$as_echo "$enable_lock_check" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lock checking should be enabled" >&5 +printf %s "checking whether lock checking should be enabled... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_lock_check" >&5 +printf "%s\n" "$enable_lock_check" >&6; } if test "x$enable_lock_check" != "xno"; then EMU_THR_DEFS="$EMU_THR_DEFS -DERTS_ENABLE_LOCK_CHECK" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lock counters should be enabled" >&5 -$as_echo_n "checking whether lock counters should be enabled... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lock_count" >&5 -$as_echo "$enable_lock_count" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lock counters should be enabled" >&5 +printf %s "checking whether lock counters should be enabled... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_lock_count" >&5 +printf "%s\n" "$enable_lock_count" >&6; } if test "x$enable_lock_count" != "xno"; then - TYPES="$TYPES lcnt" + DEFAULT_TYPES="$DEFAULT_TYPES lcnt" fi case $host_os in linux*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dlopen() needs to be called before first call to dlerror()" >&5 -$as_echo_n "checking whether dlopen() needs to be called before first call to dlerror()... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether dlopen() needs to be called before first call to dlerror()" >&5 +printf %s "checking whether dlopen() needs to be called before first call to dlerror()... " >&6; } if test "x$ETHR_THR_LIB_BASE_TYPE" != "xposix_nptl"; then -$as_echo "#define ERTS_NEED_DLOPEN_BEFORE_DLERROR 1" >>confdefs.h +printf "%s\n" "#define ERTS_NEED_DLOPEN_BEFORE_DLERROR 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi ;; *) @@ -13655,11 +15699,12 @@ fi ERTS_INTERNAL_X_LIBS= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 -$as_echo_n "checking for kstat_open in -lkstat... " >&6; } -if ${ac_cv_lib_kstat_kstat_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 +printf %s "checking for kstat_open in -lkstat... " >&6; } +if test ${ac_cv_lib_kstat_kstat_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lkstat $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13668,32 +15713,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char kstat_open (); int -main () +main (void) { return kstat_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_kstat_kstat_open=yes -else +else $as_nop ac_cv_lib_kstat_kstat_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 -$as_echo "$ac_cv_lib_kstat_kstat_open" >&6; } -if test "x$ac_cv_lib_kstat_kstat_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 +printf "%s\n" "$ac_cv_lib_kstat_kstat_open" >&6; } +if test "x$ac_cv_lib_kstat_kstat_open" = xyes +then : -$as_echo "#define HAVE_KSTAT 1" >>confdefs.h +printf "%s\n" "#define HAVE_KSTAT 1" >>confdefs.h ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat" fi @@ -13712,18 +15756,20 @@ THR_DEFS=$ETHR_DEFS TERMCAP_LIB= -if test "x$with_termcap" != "xno" && - test "X$host" != "Xwin32"; then +if test "x$with_termcap" != "xno" && test "X$host" != "Xwin32" +then : + # try these libs termcap_libs="tinfo ncurses curses termcap termlib" for termcap_lib in $termcap_libs; do - as_ac_Lib=`$as_echo "ac_cv_lib_$termcap_lib''_tgetent" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tgetent in -l$termcap_lib" >&5 -$as_echo_n "checking for tgetent in -l$termcap_lib... " >&6; } -if eval \${$as_ac_Lib+:} false; then : - $as_echo_n "(cached) " >&6 -else + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$termcap_lib""_tgetent" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tgetent in -l$termcap_lib" >&5 +printf %s "checking for tgetent in -l$termcap_lib... " >&6; } +if eval test \${$as_ac_Lib+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-l$termcap_lib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13732,31 +15778,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char tgetent (); int -main () +main (void) { return tgetent (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$as_ac_Lib=yes" -else +else $as_nop eval "$as_ac_Lib=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes" +then : TERMCAP_LIB="-l$termcap_lib" fi @@ -13768,6 +15813,7 @@ fi if test "x$TERMCAP_LIB" = "x"; then as_fn_error $? "No curses library functions found" "$LINENO" 5 fi + fi @@ -13775,63 +15821,72 @@ fi if test "x$TERMCAP_LIB" != "x"; then -$as_echo "#define HAVE_TERMCAP 1" >>confdefs.h +printf "%s\n" "#define HAVE_TERMCAP 1" >>confdefs.h fi -if test "X$host" != "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wcwidth" >&5 -$as_echo_n "checking for wcwidth... " >&6; } +if test "X$host" != "Xwin32" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wcwidth" >&5 +printf %s "checking for wcwidth... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { wcwidth(0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_wcwidth=yes -else +else $as_nop have_wcwidth=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $have_wcwidth = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define HAVE_WCWIDTH 1" >>confdefs.h +printf "%s\n" "#define HAVE_WCWIDTH 1" >>confdefs.h fi + fi # Check whether --enable-builtin-zlib was given. -if test "${enable_builtin_zlib+set}" = set; then : +if test ${enable_builtin_zlib+y} +then : enableval=$enable_builtin_zlib; case "$enableval" in no) enable_builtin_zlib=no ;; *) enable_builtin_zlib=yes ;; esac -else +else $as_nop enable_builtin_zlib=no fi Z_LIB= -if test "x$enable_builtin_zlib" = "xyes"; then +if test "x$enable_builtin_zlib" = "xyes" +then : -$as_echo "#define HAVE_ZLIB_INFLATEGETDICTIONARY 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: Using our own built-in zlib source" >&5 -$as_echo "$as_me: Using our own built-in zlib source" >&6;} -else -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib 1.2.5 or higher" >&5 -$as_echo_n "checking for zlib 1.2.5 or higher... " >&6; } +printf "%s\n" "#define HAVE_ZLIB_INFLATEGETDICTIONARY 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using our own built-in zlib source" >&5 +printf "%s\n" "$as_me: Using our own built-in zlib source" >&6;} + +else $as_nop + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib 1.2.5 or higher" >&5 +printf %s "checking for zlib 1.2.5 or higher... " >&6; } zlib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13840,7 +15895,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include "zlib.h" int -main () +main (void) { #if ZLIB_VERNUM >= 0x1250 @@ -13856,30 +15911,34 @@ error return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : Z_LIB="-lz" -$as_echo "#define HAVE_LIBZ 1" >>confdefs.h +printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -if test "$Z_LIB" != ""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inflateGetDictionary" >&5 -$as_echo_n "checking for library containing inflateGetDictionary... " >&6; } -if ${ac_cv_search_inflateGetDictionary+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "$Z_LIB" != "" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inflateGetDictionary" >&5 +printf %s "checking for library containing inflateGetDictionary... " >&6; } +if test ${ac_cv_search_inflateGetDictionary+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13887,107 +15946,145 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char inflateGetDictionary (); int -main () +main (void) { return inflateGetDictionary (); ; return 0; } _ACEOF -for ac_lib in '' z; do +for ac_lib in '' z +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_inflateGetDictionary=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_inflateGetDictionary+:} false; then : + if test ${ac_cv_search_inflateGetDictionary+y} +then : break fi done -if ${ac_cv_search_inflateGetDictionary+:} false; then : +if test ${ac_cv_search_inflateGetDictionary+y} +then : -else +else $as_nop ac_cv_search_inflateGetDictionary=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inflateGetDictionary" >&5 -$as_echo "$ac_cv_search_inflateGetDictionary" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inflateGetDictionary" >&5 +printf "%s\n" "$ac_cv_search_inflateGetDictionary" >&6; } ac_res=$ac_cv_search_inflateGetDictionary -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -$as_echo "#define HAVE_ZLIB_INFLATEGETDICTIONARY 1" >>confdefs.h +printf "%s\n" "#define HAVE_ZLIB_INFLATEGETDICTIONARY 1" >>confdefs.h fi + fi LIBS=$zlib_save_LIBS + fi + # Check whether --enable-esock was given. -if test "${enable_esock+set}" = set; then : - enableval=$enable_esock; +if test ${enable_esock+y} +then : + enableval=$enable_esock; case "$enableval" in + no) enable_esock=no ;; + *) enable_esock=yes ;; + esac + +else $as_nop + enable_esock=yes fi -USE_ESOCK=yes +if test "x$enable_esock" = "xyes" +then : + + +printf "%s\n" "#define ESOCK_ENABLE 1" >>confdefs.h + + ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" +if test "x$ac_cv_func_localtime_r" = xyes +then : + printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h -if test "x$enable_esock" = "xyes"; then - USE_ESOCK=yes -else - if test "x$enable_esock" = "xno"; then - USE_ESOCK=no - fi fi +ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" +if test "x$ac_cv_func_strftime" = xyes +then : + printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h -if test "x$USE_ESOCK" = "xyes"; then - if test "x$USE_ESOCK" = "xyes"; then - for ac_func in localtime_r strftime getprotoent setprotoent endprotoent -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_func "$LINENO" "getprotoent" "ac_cv_func_getprotoent" +if test "x$ac_cv_func_getprotoent" = xyes +then : + printf "%s\n" "#define HAVE_GETPROTOENT 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "setprotoent" "ac_cv_func_setprotoent" +if test "x$ac_cv_func_setprotoent" = xyes +then : + printf "%s\n" "#define HAVE_SETPROTOENT 1" >>confdefs.h - fi fi +ac_fn_c_check_func "$LINENO" "endprotoent" "ac_cv_func_endprotoent" +if test "x$ac_cv_func_endprotoent" = xyes +then : + printf "%s\n" "#define HAVE_ENDPROTOENT 1" >>confdefs.h +fi +fi # Check whether --enable-esock_use_rcvsndtimeo was given. -if test "${enable_esock_use_rcvsndtimeo+set}" = set; then : +if test ${enable_esock_use_rcvsndtimeo+y} +then : enableval=$enable_esock_use_rcvsndtimeo; fi if test "x$enable_esock_rcvsndtimeo" = "xyes"; then -$as_echo "#define ESOCK_USE_RCVSNDTIMEO 1" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_RCVSNDTIMEO 1" >>confdefs.h + +fi + + + +# Check whether --enable-esock_extended_error_info was given. +if test ${enable_esock_extended_error_info+y} +then : + enableval=$enable_esock_extended_error_info; +fi + + +if test "x$enable_esock_extended_error_info" != "xno"; then + +printf "%s\n" "#define ESOCK_USE_EXTENDED_ERROR_INFO 1" >>confdefs.h fi @@ -13995,9 +16092,10 @@ fi # Check whether --with-esock-counter-size was given. -if test "${with_esock_counter_size+set}" = set; then : +if test ${with_esock_counter_size+y} +then : withval=$with_esock_counter_size; -else +else $as_nop with_esock_counter_size=64 fi @@ -14005,73 +16103,78 @@ fi case "$with_esock_counter_size" in 16) -$as_echo "#define ESOCK_COUNTER_SIZE 16" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 16" >>confdefs.h ;; 24) -$as_echo "#define ESOCK_COUNTER_SIZE 24" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 24" >>confdefs.h ;; 32) -$as_echo "#define ESOCK_COUNTER_SIZE 32" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 32" >>confdefs.h ;; 48) -$as_echo "#define ESOCK_COUNTER_SIZE 48" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 48" >>confdefs.h ;; 64) -$as_echo "#define ESOCK_COUNTER_SIZE 64" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 64" >>confdefs.h ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Invalid esock counter size ($with_esock_counter_size), using default (64)" >&5 -$as_echo "$as_me: WARNING: Invalid esock counter size ($with_esock_counter_size), using default (64)" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Invalid esock counter size ($with_esock_counter_size), using default (64)" >&5 +printf "%s\n" "$as_me: WARNING: Invalid esock counter size ($with_esock_counter_size), using default (64)" >&2;} -$as_echo "#define ESOCK_COUNTER_SIZE 64" >>confdefs.h +printf "%s\n" "#define ESOCK_COUNTER_SIZE 64" >>confdefs.h ;; esac ac_fn_c_check_func "$LINENO" "if_nametoindex" "ac_cv_func_if_nametoindex" -if test "x$ac_cv_func_if_nametoindex" = xyes; then : +if test "x$ac_cv_func_if_nametoindex" = xyes +then : -$as_echo "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h +printf "%s\n" "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "if_indextoname" "ac_cv_func_if_indextoname" -if test "x$ac_cv_func_if_indextoname" = xyes; then : +if test "x$ac_cv_func_if_indextoname" = xyes +then : -$as_echo "#define HAVE_IF_INDEXTONAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_IF_INDEXTONAME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "if_nameindex" "ac_cv_func_if_nameindex" -if test "x$ac_cv_func_if_nameindex" = xyes; then : +if test "x$ac_cv_func_if_nameindex" = xyes +then : -$as_echo "#define HAVE_IF_NAMEINDEX 1" >>confdefs.h +printf "%s\n" "#define HAVE_IF_NAMEINDEX 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "if_freenameindex" "ac_cv_func_if_freenameindex" -if test "x$ac_cv_func_if_freenameindex" = xyes; then : +if test "x$ac_cv_func_if_freenameindex" = xyes +then : -$as_echo "#define HAVE_IF_FREENAMEINDEX 1" >>confdefs.h +printf "%s\n" "#define HAVE_IF_FREENAMEINDEX 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname" -if test "x$ac_cv_func_gethostname" = xyes; then : +if test "x$ac_cv_func_gethostname" = xyes +then : -$as_echo "#define HAVE_GETHOSTNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTNAME 1" >>confdefs.h fi @@ -14080,20 +16183,22 @@ fi # Check whether --enable-esock-socket-registry was given. -if test "${enable_esock_socket_registry+set}" = set; then : +if test ${enable_esock_socket_registry+y} +then : enableval=$enable_esock_socket_registry; fi -if test "x$enable_esock_socket_registry" = "xno"; then : +if test "x$enable_esock_socket_registry" = "xno" +then : -$as_echo "#define ESOCK_USE_SOCKET_REGISTRY 0" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_SOCKET_REGISTRY 0" >>confdefs.h -else +else $as_nop -$as_echo "#define ESOCK_USE_SOCKET_REGISTRY 1" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_SOCKET_REGISTRY 1" >>confdefs.h fi @@ -14104,14 +16209,13 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_map" "ac_cv_member_struct_ifr #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_map" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_map" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_MAP 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_MAP 1" >>confdefs.h -$as_echo "#define ESOCK_USE_IFMAP /**/" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_IFMAP /**/" >>confdefs.h fi @@ -14122,14 +16226,13 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_hwaddr" "ac_cv_member_struct_ #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1" >>confdefs.h -$as_echo "#define ESOCK_USE_HWADDR /**/" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_HWADDR /**/" >>confdefs.h fi @@ -14140,14 +16243,13 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_ifindex" "ac_cv_member_struct #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_ifindex" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_ifindex" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_IFINDEX 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_IFINDEX 1" >>confdefs.h -$as_echo "#define ESOCK_USE_IFINDEX /**/" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_IFINDEX /**/" >>confdefs.h fi @@ -14158,19 +16260,35 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_index" "ac_cv_member_struct_i #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_index" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_index" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_INDEX 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_INDEX 1" >>confdefs.h -$as_echo "#define ESOCK_USE_INDEX /**/" >>confdefs.h +printf "%s\n" "#define ESOCK_USE_INDEX /**/" >>confdefs.h fi +ac_fn_c_check_member "$LINENO" "struct sockaddr_dl" "sdl_len" "ac_cv_member_struct_sockaddr_dl_sdl_len" "#ifdef __WIN32__ + #else + #include + #endif + +" +if test "x$ac_cv_member_struct_sockaddr_dl_sdl_len" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_DL_SDL_LEN 1" >>confdefs.h + + +printf "%s\n" "#define ESOCK_SDL_LEN /**/" >>confdefs.h + +fi + + #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right @@ -14193,18 +16311,22 @@ tk_oldLibs=$LIBS erl_checkBoth=0 SOCKET_LIBS="" ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" -if test "x$ac_cv_func_connect" = xyes; then : +if test "x$ac_cv_func_connect" = xyes +then : erl_checkSocket=0 -else +else $as_nop erl_checkSocket=1 fi -if test "$erl_checkSocket" = 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5 -$as_echo_n "checking for main in -lsocket... " >&6; } -if ${ac_cv_lib_socket_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "$erl_checkSocket" = 1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5 +printf %s "checking for main in -lsocket... " >&6; } +if test ${ac_cv_lib_socket_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14212,51 +16334,60 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_socket_main=yes -else +else $as_nop ac_cv_lib_socket_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5 -$as_echo "$ac_cv_lib_socket_main" >&6; } -if test "x$ac_cv_lib_socket_main" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5 +printf "%s\n" "$ac_cv_lib_socket_main" >&6; } +if test "x$ac_cv_lib_socket_main" = xyes +then : SOCKET_LIBS="-lsocket" -else +else $as_nop erl_checkBoth=1 fi + fi -if test "$erl_checkBoth" = 1; then +if test "$erl_checkBoth" = 1 +then : + LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" -if test "x$ac_cv_func_accept" = xyes; then : +if test "x$ac_cv_func_accept" = xyes +then : SOCKET_LIBS="-lsocket -lnsl" fi + fi LIBS="$tk_oldLibs $SOCKET_LIBS" ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 -$as_echo_n "checking for main in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_gethostbyname" = xyes +then : + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 +printf %s "checking for main in -lnsl... " >&6; } +if test ${ac_cv_lib_nsl_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14264,32 +16395,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_nsl_main=yes -else +else $as_nop ac_cv_lib_nsl_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 -$as_echo "$ac_cv_lib_nsl_main" >&6; } -if test "x$ac_cv_lib_nsl_main" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 +printf "%s\n" "$ac_cv_lib_nsl_main" >&6; } +if test "x$ac_cv_lib_nsl_main" = xyes +then : SOCKET_LIBS="$SOCKET_LIBS -lnsl" fi fi ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = xyes; then : +if test "x$ac_cv_func_gethostbyname_r" = xyes +then : have_gethostbyname_r=yes fi @@ -14299,36 +16433,43 @@ LIBS="$tk_oldLibs $SOCKET_LIBS" -if test "$have_gethostbyname_r" = yes; then + +if test "$have_gethostbyname_r" = yes +then : + # OK, so we have gethostbyname_r() - but do we know how to call it...? # (if not, HAVE_GETHOSTBYNAME_R will not be defined at all) - case $host_os in - solaris2*) + case $host_os in #( + solaris2*) : -$as_echo "#define HAVE_GETHOSTBYNAME_R GHBN_R_SOLARIS" >>confdefs.h - ;; - aix*|os400*) +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R GHBN_R_SOLARIS" >>confdefs.h + + ;; #( + aix*|os400*) : + # AIX version also needs "struct hostent_data" defn cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { struct hostent_data hd; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -$as_echo "#define HAVE_GETHOSTBYNAME_R GHBN_R_AIX" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R GHBN_R_AIX" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ;; - *) +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; #( + *) : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14339,19 +16480,21 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "^yes$" >/dev/null 2>&1; then : + $EGREP "^yes$" >/dev/null 2>&1 +then : -$as_echo "#define HAVE_GETHOSTBYNAME_R GHBN_R_GLIBC" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R GHBN_R_GLIBC" >>confdefs.h fi -rm -f conftest* +rm -rf conftest* + + ;; +esac - ;; - esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working posix_openpt implementation" >&5 -$as_echo_n "checking for working posix_openpt implementation... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working posix_openpt implementation" >&5 +printf %s "checking for working posix_openpt implementation... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14360,7 +16503,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include int -main () +main (void) { int mfd = posix_openpt(O_RDWR); @@ -14373,128 +16516,134 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : working_posix_openpt=yes -else +else $as_nop working_posix_openpt=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test "X$working_posix_openpt" = "Xyes"; then -$as_echo "#define HAVE_WORKING_POSIX_OPENPT 1" >>confdefs.h +printf "%s\n" "#define HAVE_WORKING_POSIX_OPENPT 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if netdb.h requires netinet/in.h to be previously included" >&5 -$as_echo_n "checking if netdb.h requires netinet/in.h to be previously included... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if netdb.h requires netinet/in.h to be previously included" >&5 +printf %s "checking if netdb.h requires netinet/in.h to be previously included... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "sockaddr_in" >/dev/null 2>&1; then : + $EGREP "sockaddr_in" >/dev/null 2>&1 +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : need_in_h=yes -else +else $as_nop need_in_h=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +else $as_nop need_in_h=no fi -rm -f conftest* +rm -rf conftest* if test $need_in_h = yes; then -$as_echo "#define NETDB_H_NEEDS_IN_H 1" >>confdefs.h +printf "%s\n" "#define NETDB_H_NEEDS_IN_H 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 -$as_echo_n "checking for socklen_t... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 +printf %s "checking for socklen_t... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { socklen_t test; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : have_socklen_t=yes -else +else $as_nop have_socklen_t=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext, +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext, if test $have_socklen_t = yes; then -$as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKLEN_T 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for h_errno declaration in netdb.h" >&5 -$as_echo_n "checking for h_errno declaration in netdb.h... " >&6; } -if ${ac_cv_decl_h_errno+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for h_errno declaration in netdb.h" >&5 +printf %s "checking for h_errno declaration in netdb.h... " >&6; } +if test ${ac_cv_decl_h_errno+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int err = h_errno; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_h_errno=yes -else +else $as_nop ac_cv_decl_h_errno=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_h_errno" >&5 -$as_echo "$ac_cv_decl_h_errno" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_h_errno" >&5 +printf "%s\n" "$ac_cv_decl_h_errno" >&6; } if test $ac_cv_decl_h_errno = yes; then -$as_echo "#define H_ERRNO_DECLARED 1" >>confdefs.h +printf "%s\n" "#define H_ERRNO_DECLARED 1" >>confdefs.h fi @@ -14505,19 +16654,20 @@ CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do - as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 -$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval \${$as_ac_Header+:} false; then : - $as_echo_n "(cached) " >&6 -else + as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 +printf %s "checking for $ac_hdr that defines DIR... " >&6; } +if eval test \${$as_ac_Header+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int -main () +main (void) { if ((DIR *) 0) return 0; @@ -14525,19 +16675,21 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$as_ac_Header=yes" -else +else $as_nop eval "$as_ac_Header=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$as_ac_Header - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break @@ -14546,11 +16698,12 @@ fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +printf %s "checking for library containing opendir... " >&6; } +if test ${ac_cv_search_opendir+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14558,56 +16711,59 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char opendir (); int -main () +main (void) { return opendir (); ; return 0; } _ACEOF -for ac_lib in '' dir; do +for ac_lib in '' dir +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_opendir=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : + if test ${ac_cv_search_opendir+y} +then : break fi done -if ${ac_cv_search_opendir+:} false; then : +if test ${ac_cv_search_opendir+y} +then : -else +else $as_nop ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +printf %s "checking for library containing opendir... " >&6; } +if test ${ac_cv_search_opendir+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14615,169 +16771,62 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char opendir (); int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' x; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_opendir=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : - break -fi -done -if ${ac_cv_search_opendir+:} false; then : - -else - ac_cv_search_opendir=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () +main (void) { - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; +return opendir (); + ; return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no +for ac_lib in '' x +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_opendir=$ac_res fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_opendir+y} +then : + break fi +done +if test ${ac_cv_search_opendir+y} +then : +else $as_nop + ac_cv_search_opendir=no fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +printf "%s\n" "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 -$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } -if ${ac_cv_header_sys_wait_h+:} false; then : - $as_echo_n "(cached) " >&6 -else + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if test ${ac_cv_header_sys_wait_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -14790,7 +16839,7 @@ else #endif int -main () +main (void) { int s; wait (&s); @@ -14799,75 +16848,193 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_header_sys_wait_h=yes -else +else $as_nop ac_cv_header_sys_wait_h=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 -$as_echo "$ac_cv_header_sys_wait_h" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then -$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 -$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if ${ac_cv_header_time+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -int -main () -{ -if ((struct tm *) 0) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_time=yes -else - ac_cv_header_time=no + + +ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" +if test "x$ac_cv_header_fcntl_h" = xyes +then : + printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h + fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" +if test "x$ac_cv_header_limits_h" = xyes +then : + printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 -$as_echo "$ac_cv_header_time" >&6; } -if test $ac_cv_header_time = yes; then +ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" +if test "x$ac_cv_header_unistd_h" = xyes +then : + printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h -$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "syslog.h" "ac_cv_header_syslog_h" "$ac_includes_default" +if test "x$ac_cv_header_syslog_h" = xyes +then : + printf "%s\n" "#define HAVE_SYSLOG_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = xyes +then : + printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "ieeefp.h" "ac_cv_header_ieeefp_h" "$ac_includes_default" +if test "x$ac_cv_header_ieeefp_h" = xyes +then : + printf "%s\n" "#define HAVE_IEEEFP_H 1" >>confdefs.h -for ac_header in fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.h \ - sys/types.h sys/stropts.h sys/sysctl.h \ - sys/ioctl.h sys/time.h sys/uio.h sys/mman.h \ - sys/socket.h sys/sockio.h sys/socketio.h \ - net/errno.h malloc.h arpa/nameser.h libdlpi.h \ - pty.h util.h libutil.h utmp.h langinfo.h poll.h sdkddkver.h \ - elf.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/stropts.h" "ac_cv_header_sys_stropts_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_stropts_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_STROPTS_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sysctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SYSCTL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_ioctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_uio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MMAN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sockio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/socketio.h" "ac_cv_header_sys_socketio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socketio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKETIO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" +if test "x$ac_cv_header_net_errno_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_ERRNO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" +if test "x$ac_cv_header_malloc_h" = xyes +then : + printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "arpa/nameser.h" "ac_cv_header_arpa_nameser_h" "$ac_includes_default" +if test "x$ac_cv_header_arpa_nameser_h" = xyes +then : + printf "%s\n" "#define HAVE_ARPA_NAMESER_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "libdlpi.h" "ac_cv_header_libdlpi_h" "$ac_includes_default" +if test "x$ac_cv_header_libdlpi_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBDLPI_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "pty.h" "ac_cv_header_pty_h" "$ac_includes_default" +if test "x$ac_cv_header_pty_h" = xyes +then : + printf "%s\n" "#define HAVE_PTY_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "util.h" "ac_cv_header_util_h" "$ac_includes_default" +if test "x$ac_cv_header_util_h" = xyes +then : + printf "%s\n" "#define HAVE_UTIL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default" +if test "x$ac_cv_header_libutil_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBUTIL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "utmp.h" "ac_cv_header_utmp_h" "$ac_includes_default" +if test "x$ac_cv_header_utmp_h" = xyes +then : + printf "%s\n" "#define HAVE_UTMP_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_langinfo_h" = xyes +then : + printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" +if test "x$ac_cv_header_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sdkddkver.h" "ac_cv_header_sdkddkver_h" "$ac_includes_default" +if test "x$ac_cv_header_sdkddkver_h" = xyes +then : + printf "%s\n" "#define HAVE_SDKDDKVER_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" +if test "x$ac_cv_header_elf_h" = xyes +then : + printf "%s\n" "#define HAVE_ELF_H 1" >>confdefs.h + +fi ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_hwaddr" "ac_cv_member_struct_ifreq_ifr_hwaddr" "#ifdef __WIN32__ @@ -14876,11 +17043,10 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_hwaddr" "ac_cv_member_struct_ #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1" >>confdefs.h fi @@ -14892,25 +17058,42 @@ ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_enaddr" "ac_cv_member_struct_ #endif " -if test "x$ac_cv_member_struct_ifreq_ifr_enaddr" = xyes; then : +if test "x$ac_cv_member_struct_ifreq_ifr_enaddr" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_ENADDR 1" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IFREQ_IFR_ENADDR 1 -_ACEOF + +fi + + + +ac_fn_c_check_type "$LINENO" "struct ip_mreqn" "ac_cv_type_struct_ip_mreqn" " + #include + +" +if test "x$ac_cv_type_struct_ip_mreqn" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_IP_MREQN 1" >>confdefs.h fi -if test x"$enable_systemd" != x"no"; then + +if test x"$enable_systemd" != x"no" +then : + systemd_daemon_save_LIBS=$LIBS LIBS= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sd_listen_fds" >&5 -$as_echo_n "checking for library containing sd_listen_fds... " >&6; } -if ${ac_cv_search_sd_listen_fds+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sd_listen_fds" >&5 +printf %s "checking for library containing sd_listen_fds... " >&6; } +if test ${ac_cv_search_sd_listen_fds+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14918,57 +17101,60 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sd_listen_fds (); int -main () +main (void) { return sd_listen_fds (); ; return 0; } _ACEOF -for ac_lib in '' systemd systemd-daemon; do +for ac_lib in '' systemd systemd-daemon +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $systemd_daemon_save_LIBS $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_sd_listen_fds=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_sd_listen_fds+:} false; then : + if test ${ac_cv_search_sd_listen_fds+y} +then : break fi done -if ${ac_cv_search_sd_listen_fds+:} false; then : +if test ${ac_cv_search_sd_listen_fds+y} +then : -else +else $as_nop ac_cv_search_sd_listen_fds=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sd_listen_fds" >&5 -$as_echo "$ac_cv_search_sd_listen_fds" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sd_listen_fds" >&5 +printf "%s\n" "$ac_cv_search_sd_listen_fds" >&6; } ac_res=$ac_cv_search_sd_listen_fds -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_sd_listen_fds=yes -else +else $as_nop have_sd_listen_fds=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sd_notify" >&5 -$as_echo_n "checking for library containing sd_notify... " >&6; } -if ${ac_cv_search_sd_notify+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sd_notify" >&5 +printf %s "checking for library containing sd_notify... " >&6; } +if test ${ac_cv_search_sd_notify+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14976,90 +17162,92 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sd_notify (); int -main () +main (void) { return sd_notify (); ; return 0; } _ACEOF -for ac_lib in '' systemd systemd-daemon; do +for ac_lib in '' systemd systemd-daemon +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $systemd_daemon_save_LIBS $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_sd_notify=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_sd_notify+:} false; then : + if test ${ac_cv_search_sd_notify+y} +then : break fi done -if ${ac_cv_search_sd_notify+:} false; then : +if test ${ac_cv_search_sd_notify+y} +then : -else +else $as_nop ac_cv_search_sd_notify=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sd_notify" >&5 -$as_echo "$ac_cv_search_sd_notify" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sd_notify" >&5 +printf "%s\n" "$ac_cv_search_sd_notify" >&6; } ac_res=$ac_cv_search_sd_notify -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_sd_notify=yes -else +else $as_nop have_sd_notify=no fi -for ac_header in systemd/sd-daemon.h + for ac_header in systemd/sd-daemon.h do : - ac_fn_c_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default" -if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYSTEMD_SD_DAEMON_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default" +if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes +then : + printf "%s\n" "#define HAVE_SYSTEMD_SD_DAEMON_H 1" >>confdefs.h have_systemd_sd_daemon_h=yes -else +else $as_nop have_systemd_sd_daemon_h=no fi done - if test x"$have_sd_listen_fds" = x"yes" && \ test x"$have_sd_notify" = x"yes" && \ test x"$have_systemd_sd_daemon_h" = x"yes"; then -$as_echo "#define HAVE_SYSTEMD_DAEMON 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYSTEMD_DAEMON 1" >>confdefs.h SYSTEMD_DAEMON_LIBS=$LIBS elif test x"$enable_systemd" = x"yes"; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "--enable-systemd was given, but test for systemd failed See \`config.log' for more details" "$LINENO" 5; } fi LIBS=$systemd_daemon_save_LIBS + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_open in -ldlpi" >&5 -$as_echo_n "checking for dlpi_open in -ldlpi... " >&6; } -if ${ac_cv_lib_dlpi_dlpi_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlpi_open in -ldlpi" >&5 +printf %s "checking for dlpi_open in -ldlpi... " >&6; } +if test ${ac_cv_lib_dlpi_dlpi_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldlpi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15068,47 +17256,46 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dlpi_open (); int -main () +main (void) { return dlpi_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_dlpi_dlpi_open=yes -else +else $as_nop ac_cv_lib_dlpi_dlpi_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_open" >&5 -$as_echo "$ac_cv_lib_dlpi_dlpi_open" >&6; } -if test "x$ac_cv_lib_dlpi_dlpi_open" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDLPI 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_open" >&5 +printf "%s\n" "$ac_cv_lib_dlpi_dlpi_open" >&6; } +if test "x$ac_cv_lib_dlpi_dlpi_open" = xyes +then : + printf "%s\n" "#define HAVE_LIBDLPI 1" >>confdefs.h LIBS="-ldlpi $LIBS" fi -if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then +if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no" +then : + unset -v ac_cv_lib_dlpi_dlpi_open save_ldflags="$LDFLAGS" - try_dlpi_lib=/lib + try_dlpi_lib=$erl_xcomp_sysroot/lib if test x"$ac_cv_sizeof_void_p" = x"8"; then - if test -d /lib64; then - try_dlpi_lib=/lib64 - elif test -d /lib/64; then - try_dlpi_lib=/lib/64 + if test -d $erl_xcomp_sysroot/lib64; then + try_dlpi_lib=$erl_xcomp_sysroot/lib64 + elif test -d $erl_xcomp_sysroot/lib/64; then + try_dlpi_lib=$erl_xcomp_sysroot/lib/64 fi fi if test ! -f "$try_dlpi_lib/libdlpi.so" && \ @@ -15122,13 +17309,14 @@ if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then fi LDFLAGS="-L$try_dlpi_lib -R$try_dlpi_lib $LDFLAGS" unset -v try_dlpi_lib - { $as_echo "$as_me:${as_lineno-$LINENO}: Extending the search to include /lib" >&5 -$as_echo "$as_me: Extending the search to include /lib" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlpi_open in -ldlpi" >&5 -$as_echo_n "checking for dlpi_open in -ldlpi... " >&6; } -if ${ac_cv_lib_dlpi_dlpi_open+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Extending the search to include $erl_xcomp_sysroot/lib" >&5 +printf "%s\n" "$as_me: Extending the search to include $erl_xcomp_sysroot/lib" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlpi_open in -ldlpi" >&5 +printf %s "checking for dlpi_open in -ldlpi... " >&6; } +if test ${ac_cv_lib_dlpi_dlpi_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldlpi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15137,33 +17325,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dlpi_open (); int -main () +main (void) { return dlpi_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_dlpi_dlpi_open=yes -else +else $as_nop ac_cv_lib_dlpi_dlpi_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_open" >&5 -$as_echo "$ac_cv_lib_dlpi_dlpi_open" >&6; } -if test "x$ac_cv_lib_dlpi_dlpi_open" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDLPI 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_open" >&5 +printf "%s\n" "$ac_cv_lib_dlpi_dlpi_open" >&6; } +if test "x$ac_cv_lib_dlpi_dlpi_open" = xyes +then : + printf "%s\n" "#define HAVE_LIBDLPI 1" >>confdefs.h LIBS="-ldlpi $LIBS" @@ -15173,122 +17358,189 @@ fi LDFLAGS="$save_ldflags" fi unset -v save_ldflags + fi -ac_fn_c_check_header_mongrel "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_resource_h" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 +printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +if test ${ac_cv_c_undeclared_builtin_options+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" + # This test program should *not* compile successfully. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +(void) strchr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the + # off chance that they somehow elicit warnings. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +extern void ac_decl (int, char *); -$as_echo "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h +int +main (void) +{ +(void) ac_decl (0, (char *) 0); + (void) ac_decl; - ac_fn_c_check_decl "$LINENO" "getrlimit" "ac_cv_have_decl_getrlimit" "#include -" -if test "x$ac_cv_have_decl_getrlimit" = xyes; then : + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + if test x"$ac_arg" = x +then : + ac_cv_c_undeclared_builtin_options='none needed' +else $as_nop + ac_cv_c_undeclared_builtin_options=$ac_arg +fi + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot make $CC report undeclared builtins +See \`config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : + ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; +esac + +ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_resource_h" = xyes +then : + +printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h + + ac_fn_check_decl "$LINENO" "getrlimit" "ac_cv_have_decl_getrlimit" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_getrlimit" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_GETRLIMIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "setrlimit" "ac_cv_have_decl_setrlimit" "#include -" -if test "x$ac_cv_have_decl_setrlimit" = xyes; then : +printf "%s\n" "#define HAVE_DECL_GETRLIMIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "setrlimit" "ac_cv_have_decl_setrlimit" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_setrlimit" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SETRLIMIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RLIMIT_STACK" "ac_cv_have_decl_RLIMIT_STACK" "#include -" -if test "x$ac_cv_have_decl_RLIMIT_STACK" = xyes; then : +printf "%s\n" "#define HAVE_DECL_SETRLIMIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RLIMIT_STACK" "ac_cv_have_decl_RLIMIT_STACK" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RLIMIT_STACK" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RLIMIT_STACK $ac_have_decl -_ACEOF +printf "%s\n" "#define HAVE_DECL_RLIMIT_STACK $ac_have_decl" >>confdefs.h fi - -for ac_func in getrusage -do : - ac_fn_c_check_func "$LINENO" "getrusage" "ac_cv_func_getrusage" -if test "x$ac_cv_func_getrusage" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETRUSAGE 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "getrusage" "ac_cv_func_getrusage" +if test "x$ac_cv_func_getrusage" = xyes +then : + printf "%s\n" "#define HAVE_GETRUSAGE 1" >>confdefs.h fi -done have_kernel_poll=no -ac_fn_c_check_header_mongrel "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_event_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_event_h" = xyes +then : have_kernel_poll=kqueue fi - -ac_fn_c_check_header_mongrel "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_epoll_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_epoll_h" = xyes +then : have_kernel_poll=epoll fi - -ac_fn_c_check_header_mongrel "$LINENO" "sys/devpoll.h" "ac_cv_header_sys_devpoll_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_devpoll_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "sys/devpoll.h" "ac_cv_header_sys_devpoll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_devpoll_h" = xyes +then : have_kernel_poll=/dev/poll fi - -for ac_header in sys/timerfd.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/timerfd.h" "ac_cv_header_sys_timerfd_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_timerfd_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_TIMERFD_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "sys/timerfd.h" "ac_cv_header_sys_timerfd_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_timerfd_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIMERFD_H 1" >>confdefs.h fi -done - -for ac_header in netpacket/packet.h + for ac_header in netpacket/packet.h do : - ac_fn_c_check_header_mongrel "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" -if test "x$ac_cv_header_netpacket_packet_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_NETPACKET_PACKET_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" +if test "x$ac_cv_header_netpacket_packet_h" = xyes +then : + printf "%s\n" "#define HAVE_NETPACKET_PACKET_H 1" >>confdefs.h have_netpacket_packet_h=yes -else +else $as_nop have_netpacket_packet_h=no fi done +if test "x$enable_sctp" != "xno" +then : -if test "x$enable_sctp" != "xno" ; then ac_fn_c_check_header_compile "$LINENO" "netinet/sctp.h" "ac_cv_header_netinet_sctp_h" "#if HAVE_SYS_SOCKET_H #include #endif " -if test "x$ac_cv_header_netinet_sctp_h" = xyes; then : +if test "x$ac_cv_header_netinet_sctp_h" = xyes +then : LIBSCTP=libsctp.so.1 -$as_echo "#define HAVE_SCTP_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_SCTP_H 1" >>confdefs.h fi @@ -15304,13 +17556,17 @@ case "x$enable_sctp" in fi;; esac -if test x"$ac_cv_header_netinet_sctp_h" = x"yes"; then - if test "x$enable_sctp" = "xlib"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sctp_bindx in -lsctp" >&5 -$as_echo_n "checking for sctp_bindx in -lsctp... " >&6; } -if ${ac_cv_lib_sctp_sctp_bindx+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test x"$ac_cv_header_netinet_sctp_h" = x"yes" +then : + + if test "x$enable_sctp" = "xlib" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sctp_bindx in -lsctp" >&5 +printf %s "checking for sctp_bindx in -lsctp... " >&6; } +if test ${ac_cv_lib_sctp_sctp_bindx+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsctp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15319,50 +17575,78 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sctp_bindx (); int -main () +main (void) { return sctp_bindx (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sctp_sctp_bindx=yes -else +else $as_nop ac_cv_lib_sctp_sctp_bindx=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sctp_sctp_bindx" >&5 -$as_echo "$ac_cv_lib_sctp_sctp_bindx" >&6; } -if test "x$ac_cv_lib_sctp_sctp_bindx" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSCTP 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sctp_sctp_bindx" >&5 +printf "%s\n" "$ac_cv_lib_sctp_sctp_bindx" >&6; } +if test "x$ac_cv_lib_sctp_sctp_bindx" = xyes +then : + printf "%s\n" "#define HAVE_LIBSCTP 1" >>confdefs.h LIBS="-lsctp $LIBS" fi fi - for ac_func in sctp_bindx sctp_peeloff sctp_getladdrs sctp_freeladdrs sctp_getpaddrs sctp_freepaddrs -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "sctp_bindx" "ac_cv_func_sctp_bindx" +if test "x$ac_cv_func_sctp_bindx" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_BINDX 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_peeloff" "ac_cv_func_sctp_peeloff" +if test "x$ac_cv_func_sctp_peeloff" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_PEELOFF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_getladdrs" "ac_cv_func_sctp_getladdrs" +if test "x$ac_cv_func_sctp_getladdrs" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_GETLADDRS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_freeladdrs" "ac_cv_func_sctp_freeladdrs" +if test "x$ac_cv_func_sctp_freeladdrs" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_FREELADDRS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_getpaddrs" "ac_cv_func_sctp_getpaddrs" +if test "x$ac_cv_func_sctp_getpaddrs" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_GETPADDRS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_freepaddrs" "ac_cv_func_sctp_freepaddrs" +if test "x$ac_cv_func_sctp_freepaddrs" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_FREEPADDRS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sctp_connectx" "ac_cv_func_sctp_connectx" +if test "x$ac_cv_func_sctp_connectx" = xyes +then : + printf "%s\n" "#define HAVE_SCTP_CONNECTX 1" >>confdefs.h fi -done ac_fn_c_check_member "$LINENO" "struct sctp_accoc_value" "assoc_id" "ac_cv_member_struct_sctp_accoc_value_assoc_id" "#if HAVE_SYS_SOCKET_H #include @@ -15370,450 +17654,391 @@ done #include " -if test "x$ac_cv_member_struct_sctp_accoc_value_assoc_id" = xyes; then : +if test "x$ac_cv_member_struct_sctp_accoc_value_assoc_id" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_ACCOC_VALUE_ASSOC_ID 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_ACCOC_VALUE_ASSOC_ID 1" >>confdefs.h fi - ac_fn_c_check_decl "$LINENO" "SCTP_UNORDERED" "ac_cv_have_decl_SCTP_UNORDERED" "#if HAVE_SYS_SOCKET_H + ac_fn_check_decl "$LINENO" "SCTP_UNORDERED" "ac_cv_have_decl_SCTP_UNORDERED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_UNORDERED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_UNORDERED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_UNORDERED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_ADDR_OVER" "ac_cv_have_decl_SCTP_ADDR_OVER" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_UNORDERED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_ADDR_OVER" "ac_cv_have_decl_SCTP_ADDR_OVER" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_ADDR_OVER" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_ADDR_OVER" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_ADDR_OVER $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_ABORT" "ac_cv_have_decl_SCTP_ABORT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_ADDR_OVER $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_ABORT" "ac_cv_have_decl_SCTP_ABORT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_ABORT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_ABORT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_ABORT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_EOF" "ac_cv_have_decl_SCTP_EOF" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_ABORT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_EOF" "ac_cv_have_decl_SCTP_EOF" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_EOF" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_EOF" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_EOF $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_SENDALL" "ac_cv_have_decl_SCTP_SENDALL" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_EOF $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_SENDALL" "ac_cv_have_decl_SCTP_SENDALL" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_SENDALL" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_SENDALL" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_SENDALL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_ADDR_CONFIRMED" "ac_cv_have_decl_SCTP_ADDR_CONFIRMED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_SENDALL $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_ADDR_CONFIRMED" "ac_cv_have_decl_SCTP_ADDR_CONFIRMED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_ADDR_CONFIRMED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_ADDR_CONFIRMED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_ADDR_CONFIRMED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_DELAYED_ACK_TIME" "ac_cv_have_decl_SCTP_DELAYED_ACK_TIME" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_ADDR_CONFIRMED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_DELAYED_ACK_TIME" "ac_cv_have_decl_SCTP_DELAYED_ACK_TIME" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_DELAYED_ACK_TIME" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_DELAYED_ACK_TIME" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_DELAYED_ACK_TIME $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_EMPTY" "ac_cv_have_decl_SCTP_EMPTY" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_DELAYED_ACK_TIME $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_EMPTY" "ac_cv_have_decl_SCTP_EMPTY" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_EMPTY" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_EMPTY" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_EMPTY $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_UNCONFIRMED" "ac_cv_have_decl_SCTP_UNCONFIRMED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_EMPTY $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_UNCONFIRMED" "ac_cv_have_decl_SCTP_UNCONFIRMED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_UNCONFIRMED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_UNCONFIRMED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_UNCONFIRMED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_CLOSED" "ac_cv_have_decl_SCTP_CLOSED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_UNCONFIRMED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_CLOSED" "ac_cv_have_decl_SCTP_CLOSED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_CLOSED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_CLOSED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_CLOSED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_IDLE" "ac_cv_have_decl_SCTPS_IDLE" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_CLOSED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_IDLE" "ac_cv_have_decl_SCTPS_IDLE" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_IDLE" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_IDLE" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_IDLE $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_BOUND" "ac_cv_have_decl_SCTP_BOUND" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_IDLE $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_BOUND" "ac_cv_have_decl_SCTP_BOUND" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_BOUND" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_BOUND" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_BOUND $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_BOUND" "ac_cv_have_decl_SCTPS_BOUND" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_BOUND $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_BOUND" "ac_cv_have_decl_SCTPS_BOUND" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_BOUND" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_BOUND" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_BOUND $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_LISTEN" "ac_cv_have_decl_SCTP_LISTEN" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_BOUND $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_LISTEN" "ac_cv_have_decl_SCTP_LISTEN" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_LISTEN" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_LISTEN" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_LISTEN $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_LISTEN" "ac_cv_have_decl_SCTPS_LISTEN" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_LISTEN $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_LISTEN" "ac_cv_have_decl_SCTPS_LISTEN" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_LISTEN" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_LISTEN" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_LISTEN $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_COOKIE_WAIT" "ac_cv_have_decl_SCTP_COOKIE_WAIT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_LISTEN $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_COOKIE_WAIT" "ac_cv_have_decl_SCTP_COOKIE_WAIT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_COOKIE_WAIT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_COOKIE_WAIT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_COOKIE_WAIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_COOKIE_WAIT" "ac_cv_have_decl_SCTPS_COOKIE_WAIT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_COOKIE_WAIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_COOKIE_WAIT" "ac_cv_have_decl_SCTPS_COOKIE_WAIT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_COOKIE_WAIT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_COOKIE_WAIT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_COOKIE_WAIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_COOKIE_ECHOED" "ac_cv_have_decl_SCTP_COOKIE_ECHOED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_COOKIE_WAIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_COOKIE_ECHOED" "ac_cv_have_decl_SCTP_COOKIE_ECHOED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_COOKIE_ECHOED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_COOKIE_ECHOED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_COOKIE_ECHOED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_COOKIE_ECHOED" "ac_cv_have_decl_SCTPS_COOKIE_ECHOED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_COOKIE_ECHOED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_COOKIE_ECHOED" "ac_cv_have_decl_SCTPS_COOKIE_ECHOED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_COOKIE_ECHOED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_COOKIE_ECHOED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_COOKIE_ECHOED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_ESTABLISHED" "ac_cv_have_decl_SCTP_ESTABLISHED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_COOKIE_ECHOED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_ESTABLISHED" "ac_cv_have_decl_SCTP_ESTABLISHED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_ESTABLISHED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_ESTABLISHED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_ESTABLISHED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_ESTABLISHED" "ac_cv_have_decl_SCTPS_ESTABLISHED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_ESTABLISHED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_ESTABLISHED" "ac_cv_have_decl_SCTPS_ESTABLISHED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_ESTABLISHED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_ESTABLISHED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_ESTABLISHED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_SHUTDOWN_PENDING" "ac_cv_have_decl_SCTP_SHUTDOWN_PENDING" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_ESTABLISHED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_SHUTDOWN_PENDING" "ac_cv_have_decl_SCTP_SHUTDOWN_PENDING" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_PENDING" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_PENDING" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_SHUTDOWN_PENDING $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_SHUTDOWN_PENDING" "ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_SHUTDOWN_PENDING $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_SHUTDOWN_PENDING" "ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_SHUTDOWN_PENDING $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_SHUTDOWN_SENT" "ac_cv_have_decl_SCTP_SHUTDOWN_SENT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_SHUTDOWN_PENDING $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_SHUTDOWN_SENT" "ac_cv_have_decl_SCTP_SHUTDOWN_SENT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_SENT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_SENT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_SHUTDOWN_SENT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_SHUTDOWN_SENT" "ac_cv_have_decl_SCTPS_SHUTDOWN_SENT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_SHUTDOWN_SENT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_SHUTDOWN_SENT" "ac_cv_have_decl_SCTPS_SHUTDOWN_SENT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_SENT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_SENT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_SHUTDOWN_SENT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_SHUTDOWN_RECEIVED" "ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_SHUTDOWN_SENT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_SHUTDOWN_RECEIVED" "ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_SHUTDOWN_RECEIVED" "ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_SHUTDOWN_RECEIVED" "ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTP_SHUTDOWN_ACK_SENT" "ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTP_SHUTDOWN_ACK_SENT" "ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "SCTPS_SHUTDOWN_ACK_SENT" "ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT" "#if HAVE_SYS_SOCKET_H +printf "%s\n" "#define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "SCTPS_SHUTDOWN_ACK_SENT" "ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT" "#if HAVE_SYS_SOCKET_H #include #endif #include -" -if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT $ac_have_decl -_ACEOF +printf "%s\n" "#define HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT $ac_have_decl" >>confdefs.h ac_fn_c_check_member "$LINENO" "struct sctp_paddrparams" "spp_pathmtu" "ac_cv_member_struct_sctp_paddrparams_spp_pathmtu" "#if HAVE_SYS_SOCKET_H #include @@ -15821,11 +18046,10 @@ _ACEOF #include " -if test "x$ac_cv_member_struct_sctp_paddrparams_spp_pathmtu" = xyes; then : +if test "x$ac_cv_member_struct_sctp_paddrparams_spp_pathmtu" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_PATHMTU 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_PATHMTU 1" >>confdefs.h fi @@ -15835,11 +18059,10 @@ ac_fn_c_check_member "$LINENO" "struct sctp_paddrparams" "spp_sackdelay" "ac_cv_ #include " -if test "x$ac_cv_member_struct_sctp_paddrparams_spp_sackdelay" = xyes; then : +if test "x$ac_cv_member_struct_sctp_paddrparams_spp_sackdelay" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY 1" >>confdefs.h fi @@ -15849,11 +18072,10 @@ ac_fn_c_check_member "$LINENO" "struct sctp_paddrparams" "spp_flags" "ac_cv_memb #include " -if test "x$ac_cv_member_struct_sctp_paddrparams_spp_flags" = xyes; then : +if test "x$ac_cv_member_struct_sctp_paddrparams_spp_flags" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS 1" >>confdefs.h fi @@ -15863,11 +18085,10 @@ ac_fn_c_check_member "$LINENO" "struct sctp_remote_error" "sre_data" "ac_cv_memb #include " -if test "x$ac_cv_member_struct_sctp_remote_error_sre_data" = xyes; then : +if test "x$ac_cv_member_struct_sctp_remote_error_sre_data" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_REMOTE_ERROR_SRE_DATA 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_REMOTE_ERROR_SRE_DATA 1" >>confdefs.h fi @@ -15877,11 +18098,10 @@ ac_fn_c_check_member "$LINENO" "struct sctp_send_failed" "ssf_data" "ac_cv_membe #include " -if test "x$ac_cv_member_struct_sctp_send_failed_ssf_data" = xyes; then : +if test "x$ac_cv_member_struct_sctp_send_failed_ssf_data" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_SEND_FAILED_SSF_DATA 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_SEND_FAILED_SSF_DATA 1" >>confdefs.h fi @@ -15891,11 +18111,10 @@ ac_fn_c_check_member "$LINENO" "struct sctp_event_subscribe" "sctp_authenticatio #include " -if test "x$ac_cv_member_struct_sctp_event_subscribe_sctp_authentication_event" = xyes; then : +if test "x$ac_cv_member_struct_sctp_event_subscribe_sctp_authentication_event" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_AUTHENTICATION_EVENT 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_AUTHENTICATION_EVENT 1" >>confdefs.h fi @@ -15905,46 +18124,39 @@ ac_fn_c_check_member "$LINENO" "struct sctp_event_subscribe" "sctp_sender_dry_ev #include " -if test "x$ac_cv_member_struct_sctp_event_subscribe_sctp_sender_dry_event" = xyes; then : +if test "x$ac_cv_member_struct_sctp_event_subscribe_sctp_sender_dry_event" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SENDER_DRY_EVENT 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SENDER_DRY_EVENT 1" >>confdefs.h fi + fi -for ac_header in sched.h setns.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" +if test "x$ac_cv_header_sched_h" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "setns.h" "ac_cv_header_setns_h" "$ac_includes_default" +if test "x$ac_cv_header_setns_h" = xyes +then : + printf "%s\n" "#define HAVE_SETNS_H 1" >>confdefs.h -done +fi -for ac_func in setns -do : - ac_fn_c_check_func "$LINENO" "setns" "ac_cv_func_setns" -if test "x$ac_cv_func_setns" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SETNS 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "setns" "ac_cv_func_setns" +if test "x$ac_cv_func_setns" = xyes +then : + printf "%s\n" "#define HAVE_SETNS 1" >>confdefs.h fi -done -for ac_header in linux/types.h linux/errqueue.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_TIME_H +ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "#ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_LINUX_TYPES_H @@ -15952,203 +18164,231 @@ ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE #endif " -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +if test "x$ac_cv_header_linux_types_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "linux/errqueue.h" "ac_cv_header_linux_errqueue_h" "#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_LINUX_TYPES_H +# include +#endif -done +" +if test "x$ac_cv_header_linux_errqueue_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_ERRQUEUE_H 1" >>confdefs.h + +fi HAVE_VALGRIND=no -ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes +then : HAVE_VALGRIND=yes fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SO_BSDCOMPAT declaration" >&5 -$as_echo_n "checking for SO_BSDCOMPAT declaration... " >&6; } -if ${ac_cv_decl_so_bsdcompat+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SO_BSDCOMPAT declaration" >&5 +printf %s "checking for SO_BSDCOMPAT declaration... " >&6; } +if test ${ac_cv_decl_so_bsdcompat+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int i = SO_BSDCOMPAT; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_so_bsdcompat=yes -else +else $as_nop ac_cv_decl_so_bsdcompat=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_so_bsdcompat" >&5 -$as_echo "$ac_cv_decl_so_bsdcompat" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_so_bsdcompat" >&5 +printf "%s\n" "$ac_cv_decl_so_bsdcompat" >&6; } case "${ac_cv_decl_so_bsdcompat}" in "yes" ) -$as_echo "#define HAVE_SO_BSDCOMPAT /**/" >>confdefs.h +printf "%s\n" "#define HAVE_SO_BSDCOMPAT /**/" >>confdefs.h ;; * ) ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in netinet/in.h" >&5 -$as_echo_n "checking for INADDR_LOOPBACK in netinet/in.h... " >&6; } -if ${ac_cv_decl_inaddr_loopback+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in netinet/in.h" >&5 +printf %s "checking for INADDR_LOOPBACK in netinet/in.h... " >&6; } +if test ${ac_cv_decl_inaddr_loopback+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { int i = INADDR_LOOPBACK; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_inaddr_loopback=yes -else +else $as_nop ac_cv_decl_inaddr_loopback=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback" >&5 -$as_echo "$ac_cv_decl_inaddr_loopback" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback" >&5 +printf "%s\n" "$ac_cv_decl_inaddr_loopback" >&6; } -if test ${ac_cv_decl_inaddr_loopback} = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in rpc/types.h" >&5 -$as_echo_n "checking for INADDR_LOOPBACK in rpc/types.h... " >&6; } -if ${ac_cv_decl_inaddr_loopback_rpc+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${ac_cv_decl_inaddr_loopback} = no +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in rpc/types.h" >&5 +printf %s "checking for INADDR_LOOPBACK in rpc/types.h... " >&6; } +if test ${ac_cv_decl_inaddr_loopback_rpc+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int i = INADDR_LOOPBACK; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_inaddr_loopback_rpc=yes -else +else $as_nop ac_cv_decl_inaddr_loopback_rpc=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback_rpc" >&5 -$as_echo "$ac_cv_decl_inaddr_loopback_rpc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback_rpc" >&5 +printf "%s\n" "$ac_cv_decl_inaddr_loopback_rpc" >&6; } - case "${ac_cv_decl_inaddr_loopback_rpc}" in - "yes" ) + if test "${ac_cv_decl_inaddr_loopback_rpc}" = "yes" +then : -$as_echo "#define DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H /**/" >>confdefs.h - ;; - * ) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in winsock2.h" >&5 -$as_echo_n "checking for INADDR_LOOPBACK in winsock2.h... " >&6; } -if ${ac_cv_decl_inaddr_loopback_winsock2+:} false; then : - $as_echo_n "(cached) " >&6 -else + +printf "%s\n" "#define DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H /**/" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for INADDR_LOOPBACK in winsock2.h" >&5 +printf %s "checking for INADDR_LOOPBACK in winsock2.h... " >&6; } +if test ${ac_cv_decl_inaddr_loopback_winsock2+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define WIN32_LEAN_AND_MEAN #include int -main () +main (void) { int i = INADDR_LOOPBACK; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_inaddr_loopback_winsock2=yes -else +else $as_nop ac_cv_decl_inaddr_loopback_winsock2=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback_winsock2" >&5 -$as_echo "$ac_cv_decl_inaddr_loopback_winsock2" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_inaddr_loopback_winsock2" >&5 +printf "%s\n" "$ac_cv_decl_inaddr_loopback_winsock2" >&6; } case "${ac_cv_decl_inaddr_loopback_winsock2}" in "yes" ) -$as_echo "#define DEF_INADDR_LOOPBACK_IN_WINSOCK2_H /**/" >>confdefs.h +printf "%s\n" "#define DEF_INADDR_LOOPBACK_IN_WINSOCK2_H /**/" >>confdefs.h ;; * ) # couldn't find it anywhere -$as_echo "#define HAVE_NO_INADDR_LOOPBACK /**/" >>confdefs.h +printf "%s\n" "#define HAVE_NO_INADDR_LOOPBACK /**/" >>confdefs.h ;; - esac;; - esac + esac + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys_errlist declaration in stdio.h or errno.h" >&5 -$as_echo_n "checking for sys_errlist declaration in stdio.h or errno.h... " >&6; } -if ${ac_cv_decl_sys_errlist+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys_errlist declaration in stdio.h or errno.h" >&5 +printf %s "checking for sys_errlist declaration in stdio.h or errno.h... " >&6; } +if test ${ac_cv_decl_sys_errlist+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { char *msg = *(sys_errlist + 1); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_decl_sys_errlist=yes -else +else $as_nop ac_cv_decl_sys_errlist=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_sys_errlist" >&5 -$as_echo "$ac_cv_decl_sys_errlist" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_sys_errlist" >&5 +printf "%s\n" "$ac_cv_decl_sys_errlist" >&6; } if test $ac_cv_decl_sys_errlist = yes; then -$as_echo "#define SYS_ERRLIST_DECLARED /**/" >>confdefs.h +printf "%s\n" "#define SYS_ERRLIST_DECLARED /**/" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if windows.h includes winsock2.h" >&5 -$as_echo_n "checking if windows.h includes winsock2.h... " >&6; } -if ${erts_cv_windows_h_includes_winsock2_h+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if windows.h includes winsock2.h" >&5 +printf %s "checking if windows.h includes winsock2.h... " >&6; } +if test ${erts_cv_windows_h_includes_winsock2_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef _WINSOCK2API_ #error winsock2.h not included @@ -16159,34 +18399,36 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erts_cv_windows_h_includes_winsock2_h=yes -else +else $as_nop erts_cv_windows_h_includes_winsock2_h=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_windows_h_includes_winsock2_h" >&5 -$as_echo "$erts_cv_windows_h_includes_winsock2_h" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_windows_h_includes_winsock2_h" >&5 +printf "%s\n" "$erts_cv_windows_h_includes_winsock2_h" >&6; } if test $erts_cv_windows_h_includes_winsock2_h = yes; then -$as_echo "#define WINDOWS_H_INCLUDES_WINSOCK2_H 1" >>confdefs.h +printf "%s\n" "#define WINDOWS_H_INCLUDES_WINSOCK2_H 1" >>confdefs.h fi CPPFLAGS=$saved_cppflags -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +printf %s "checking for an ANSI C-conforming const... " >&6; } +if test ${ac_cv_c_const+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __cplusplus @@ -16199,7 +18441,7 @@ main () /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. + /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ @@ -16227,7 +18469,7 @@ main () iptr p = 0; ++p; } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; @@ -16243,100 +18485,94 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_const=yes -else +else $as_nop ac_cv_c_const=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then -$as_echo "#define const /**/" >>confdefs.h +printf "%s\n" "#define const /**/" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 -$as_echo_n "checking return type of signal handlers... " >&6; } -if ${ac_cv_type_signal+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = xyes +then : + +else $as_nop + +printf "%s\n" "#define off_t long int" >>confdefs.h + +fi + + + ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default +" +if test "x$ac_cv_type_pid_t" = xyes +then : + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include + + #if defined _WIN64 && !defined __CYGWIN__ + LLP64 + #endif int -main () +main (void) { -return *(signal (0, 0)) (0) == 1; + ; return 0; } -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_signal=int -else - ac_cv_type_signal=void -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 -$as_echo "$ac_cv_type_signal" >&6; } - -cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE $ac_cv_type_signal -_ACEOF - -ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define off_t long int _ACEOF - +if ac_fn_c_try_compile "$LINENO" +then : + ac_pid_type='int' +else $as_nop + ac_pid_type='__int64' fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : - -else +printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define pid_t int -_ACEOF fi + ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$ac_cv_type_size_t" = xyes +then : -else +else $as_nop -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF +printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 -$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +printf %s "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if test ${ac_cv_struct_tm+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { struct tm tm; int *p = &tm.tm_sec; @@ -16345,51 +18581,54 @@ struct tm tm; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_tm=time.h -else +else $as_nop ac_cv_struct_tm=sys/time.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 -$as_echo "$ac_cv_struct_tm" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +printf "%s\n" "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then -$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h +printf "%s\n" "#define TM_IN_SYS_TIME 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct sockaddr has sa_len field" >&5 -$as_echo_n "checking whether struct sockaddr has sa_len field... " >&6; } -if ${ac_cv_struct_sockaddr_sa_len+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct sockaddr has sa_len field" >&5 +printf %s "checking whether struct sockaddr has sa_len field... " >&6; } +if test ${ac_cv_struct_sockaddr_sa_len+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { struct sockaddr s; s.sa_len = 10; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_sockaddr_sa_len=yes -else +else $as_nop ac_cv_struct_sockaddr_sa_len=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 -$as_echo "$ac_cv_struct_sockaddr_sa_len" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 +printf "%s\n" "$ac_cv_struct_sockaddr_sa_len" >&6; } case ${ac_cv_struct_sockaddr_sa_len} in "no" ) -$as_echo "#define NO_SA_LEN 1" >>confdefs.h +printf "%s\n" "#define NO_SA_LEN 1" >>confdefs.h ;; *) ;; esac @@ -16399,17 +18638,19 @@ esac # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 -$as_echo_n "checking size of char... " >&6; } -if ${ac_cv_sizeof_char+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 +printf %s "checking size of char... " >&6; } +if test ${ac_cv_sizeof_char+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_char" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (char) See \`config.log' for more details" "$LINENO" 5; } else @@ -16418,31 +18659,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 -$as_echo "$ac_cv_sizeof_char" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 +printf "%s\n" "$ac_cv_sizeof_char" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_CHAR $ac_cv_sizeof_char -_ACEOF +printf "%s\n" "#define SIZEOF_CHAR $ac_cv_sizeof_char" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +printf %s "checking size of short... " >&6; } +if test ${ac_cv_sizeof_short+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else @@ -16451,31 +18692,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +printf "%s\n" "$ac_cv_sizeof_short" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF +printf "%s\n" "#define SIZEOF_SHORT $ac_cv_sizeof_short" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +printf %s "checking size of int... " >&6; } +if test ${ac_cv_sizeof_int+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else @@ -16484,31 +18725,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +printf "%s\n" "$ac_cv_sizeof_int" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF +printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +printf %s "checking size of long... " >&6; } +if test ${ac_cv_sizeof_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else @@ -16517,31 +18758,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -16550,31 +18791,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +printf %s "checking size of long long... " >&6; } +if test ${ac_cv_sizeof_long_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else @@ -16583,31 +18824,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 -$as_echo_n "checking size of size_t... " >&6; } -if ${ac_cv_sizeof_size_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 +printf %s "checking size of size_t... " >&6; } +if test ${ac_cv_sizeof_size_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_size_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -16616,31 +18857,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 -$as_echo "$ac_cv_sizeof_size_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 +printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t -_ACEOF +printf "%s\n" "#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 -$as_echo_n "checking size of off_t... " >&6; } -if ${ac_cv_sizeof_off_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 +printf %s "checking size of off_t... " >&6; } +if test ${ac_cv_sizeof_off_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_off_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -16649,31 +18890,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 -$as_echo "$ac_cv_sizeof_off_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 +printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_OFF_T $ac_cv_sizeof_off_t -_ACEOF +printf "%s\n" "#define SIZEOF_OFF_T $ac_cv_sizeof_off_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 -$as_echo_n "checking size of time_t... " >&6; } -if ${ac_cv_sizeof_time_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 +printf %s "checking size of time_t... " >&6; } +if test ${ac_cv_sizeof_time_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_time_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -16682,31 +18923,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 -$as_echo "$ac_cv_sizeof_time_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 +printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_TIME_T $ac_cv_sizeof_time_t -_ACEOF +printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of suseconds_t" >&5 -$as_echo_n "checking size of suseconds_t... " >&6; } -if ${ac_cv_sizeof_suseconds_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (suseconds_t))" "ac_cv_sizeof_suseconds_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of suseconds_t" >&5 +printf %s "checking size of suseconds_t... " >&6; } +if test ${ac_cv_sizeof_suseconds_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (suseconds_t))" "ac_cv_sizeof_suseconds_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_suseconds_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (suseconds_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -16715,31 +18956,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_suseconds_t" >&5 -$as_echo "$ac_cv_sizeof_suseconds_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_suseconds_t" >&5 +printf "%s\n" "$ac_cv_sizeof_suseconds_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SUSECONDS_T $ac_cv_sizeof_suseconds_t -_ACEOF +printf "%s\n" "#define SIZEOF_SUSECONDS_T $ac_cv_sizeof_suseconds_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Float16" >&5 -$as_echo_n "checking size of _Float16... " >&6; } -if ${ac_cv_sizeof__Float16+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Float16))" "ac_cv_sizeof__Float16" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of _Float16" >&5 +printf %s "checking size of _Float16... " >&6; } +if test ${ac_cv_sizeof__Float16+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Float16))" "ac_cv_sizeof__Float16" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type__Float16" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (_Float16) See \`config.log' for more details" "$LINENO" 5; } else @@ -16748,14 +18989,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Float16" >&5 -$as_echo "$ac_cv_sizeof__Float16" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Float16" >&5 +printf "%s\n" "$ac_cv_sizeof__Float16" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF__FLOAT16 $ac_cv_sizeof__Float16 -_ACEOF +printf "%s\n" "#define SIZEOF__FLOAT16 $ac_cv_sizeof__Float16" >>confdefs.h @@ -16766,8 +19005,8 @@ if test $ac_cv_sizeof_void_p = 8; then fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler 'restrict' support" >&5 -$as_echo_n "checking for C compiler 'restrict' support... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler 'restrict' support" >&5 +printf %s "checking for C compiler 'restrict' support... " >&6; } restrict_keyword="" for x in restrict __restrict; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16777,43 +19016,42 @@ int * $x foo(int * $x arg); { int * $x var=arg; return var;} int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : restrict_keyword=$x fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test "x$restrict_keyword" != "x"; then break fi done -cat >>confdefs.h <<_ACEOF -#define ERTS_RESTRICT $restrict_keyword -_ACEOF +printf "%s\n" "#define ERTS_RESTRICT $restrict_keyword" >>confdefs.h if test "x$restrict_keyword" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_compiler_gnu" = "xyes"; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly" >&5 -$as_echo_n "checking if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly" >&5 +printf %s "checking if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly... " >&6; } ## tree-copyrename was broken in gcc 4.3 and then removed in gcc 6 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #if (__GNUC__ > 4 && __GNUC__ < 6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) @@ -16826,27 +19064,29 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : no_tree_copyrename=yes -else +else $as_nop no_tree_copyrename=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test "x$no_tree_copyrename" = "xyes"; then CFLAGS="$CFLAGS -fno-tree-copyrename" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken gcc-4.3.0 compiler" >&5 -$as_echo_n "checking for broken gcc-4.3.0 compiler... " >&6; } -if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken gcc-4.3.0 compiler" >&5 +printf %s "checking for broken gcc-4.3.0 compiler... " >&6; } +if test "$cross_compiling" = yes +then : gcc_4_3_0_bug=cross -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16884,9 +19124,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : gcc_4_3_0_bug=no -else +else $as_nop gcc_4_3_0_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -16906,8 +19147,8 @@ case $gcc_4_3_0_bug in gcc_4_3_0_bug_result="$gcc_4_3_0_bug; could not run test since cross compiling, checked version number ($gcc_dumped_vsn) instead";; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_4_3_0_bug_result" >&5 -$as_echo "$gcc_4_3_0_bug_result" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gcc_4_3_0_bug_result" >&5 +printf "%s\n" "$gcc_4_3_0_bug_result" >&6; } if test $gcc_4_3_0_bug = yes; then as_fn_error $? "This gcc miscompiles the Erlang runtime system; please use a different version" "$LINENO" 5 fi @@ -16920,11 +19161,12 @@ case X$erl_xcomp_bigendian in *) as_fn_error $? "Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian" "$LINENO" 5;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +printf %s "checking whether byte ordering is bigendian... " >&6; } +if test ${ac_cv_c_bigendian+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16935,7 +19177,8 @@ else typedef int dummy; _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. @@ -16959,7 +19202,7 @@ if ac_fn_c_try_compile "$LINENO"; then : fi done fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16968,7 +19211,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ @@ -16980,7 +19223,8 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16988,7 +19232,7 @@ if ac_fn_c_try_compile "$LINENO"; then : #include int -main () +main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian @@ -16998,14 +19242,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). @@ -17014,7 +19259,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros @@ -17024,14 +19269,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef _BIG_ENDIAN not big endian @@ -17041,31 +19287,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -short int ascii_mm[] = +unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = + unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } - short int ebcdic_ii[] = + unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = + unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; @@ -17073,14 +19321,15 @@ short int ascii_mm[] = extern int foo; int -main () +main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi @@ -17093,13 +19342,13 @@ if ac_fn_c_try_compile "$LINENO"; then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int -main () +main (void) { /* Are we little or big endian? From Harbison&Steele. */ @@ -17115,9 +19364,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_c_bigendian=no -else +else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -17126,27 +19376,27 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) -$as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h -$as_echo "#define ERTS_ENDIANNESS 1" >>confdefs.h +printf "%s\n" "#define ERTS_ENDIANNESS 1" >>confdefs.h ;; #( no) -$as_echo "#define ERTS_ENDIANNESS -1" >>confdefs.h +printf "%s\n" "#define ERTS_ENDIANNESS -1" >>confdefs.h ;; #( universal) -$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) @@ -17154,30 +19404,32 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h case "$erl_xcomp_bigendian" in yes) -$as_echo "#define ERTS_ENDIANNESS 1" >>confdefs.h +printf "%s\n" "#define ERTS_ENDIANNESS 1" >>confdefs.h ;; no) -$as_echo "#define ERTS_ENDIANNESS -1" >>confdefs.h +printf "%s\n" "#define ERTS_ENDIANNESS -1" >>confdefs.h ;; *) -$as_echo "#define ERTS_ENDIANNESS 0" >>confdefs.h +printf "%s\n" "#define ERTS_ENDIANNESS 0" >>confdefs.h ;; esac ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether double word ordering is middle-endian" >&5 -$as_echo_n "checking whether double word ordering is middle-endian... " >&6; } -if ${ac_cv_c_double_middle_endian+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether double word ordering is middle-endian" >&5 +printf %s "checking whether double word ordering is middle-endian... " >&6; } +if test ${ac_cv_c_double_middle_endian+y} +then : + printf %s "(cached) " >&6 +else $as_nop # It does not; compile a test program. -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_c_double_middle=unknown -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17246,9 +19498,10 @@ main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_c_double_middle_endian=no -else +else $as_nop ac_cv_c_double_middle_endian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -17256,40 +19509,37 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_double_middle_endian" >&5 -$as_echo "$ac_cv_c_double_middle_endian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_double_middle_endian" >&5 +printf "%s\n" "$ac_cv_c_double_middle_endian" >&6; } case $ac_cv_c_double_middle_endian in yes) -$as_echo "#define DOUBLE_MIDDLE_ENDIAN 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_MIDDLE_ENDIAN 1" >>confdefs.h ;; no) ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unknown double endianness + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown double endianness presetting ac_cv_c_double_middle_endian=no (or yes) will help" >&5 -$as_echo "$as_me: WARNING: unknown double endianness +printf "%s\n" "$as_me: WARNING: unknown double endianness presetting ac_cv_c_double_middle_endian=no (or yes) will help" >&2;} ;; esac -for ac_func in fdatasync -do : - ac_fn_c_check_func "$LINENO" "fdatasync" "ac_cv_func_fdatasync" -if test "x$ac_cv_func_fdatasync" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_FDATASYNC 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "fdatasync" "ac_cv_func_fdatasync" +if test "x$ac_cv_func_fdatasync" = xyes +then : + printf "%s\n" "#define HAVE_FDATASYNC 1" >>confdefs.h fi -done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 -$as_echo_n "checking for library containing fdatasync... " >&6; } -if ${ac_cv_search_fdatasync+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 +printf %s "checking for library containing fdatasync... " >&6; } +if test ${ac_cv_search_fdatasync+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17297,72 +19547,73 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char fdatasync (); int -main () +main (void) { return fdatasync (); ; return 0; } _ACEOF -for ac_lib in '' rt; do +for ac_lib in '' rt +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_fdatasync=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_fdatasync+:} false; then : + if test ${ac_cv_search_fdatasync+y} +then : break fi done -if ${ac_cv_search_fdatasync+:} false; then : +if test ${ac_cv_search_fdatasync+y} +then : -else +else $as_nop ac_cv_search_fdatasync=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fdatasync" >&5 -$as_echo "$ac_cv_search_fdatasync" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fdatasync" >&5 +printf "%s\n" "$ac_cv_search_fdatasync" >&6; } ac_res=$ac_cv_search_fdatasync -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi -case $host_os in - linux*|freebsd*|dragonfly*|darwin*) - for ac_func in sendfile -do : - ac_fn_c_check_func "$LINENO" "sendfile" "ac_cv_func_sendfile" -if test "x$ac_cv_func_sendfile" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SENDFILE 1 -_ACEOF +case $host_os in #( + linux*|freebsd*|dragonfly*|darwin*) : + + ac_fn_c_check_func "$LINENO" "sendfile" "ac_cv_func_sendfile" +if test "x$ac_cv_func_sendfile" = xyes +then : + printf "%s\n" "#define HAVE_SENDFILE 1" >>confdefs.h fi -done - ;; - solaris*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sendfilev" >&5 -$as_echo_n "checking for library containing sendfilev... " >&6; } -if ${ac_cv_search_sendfilev+:} false; then : - $as_echo_n "(cached) " >&6 -else + ;; #( + solaris*) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sendfilev" >&5 +printf %s "checking for library containing sendfilev... " >&6; } +if test ${ac_cv_search_sendfilev+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17370,58 +19621,61 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sendfilev (); int -main () +main (void) { return sendfilev (); ; return 0; } _ACEOF -for ac_lib in '' sendfile; do +for ac_lib in '' sendfile +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_sendfilev=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_sendfilev+:} false; then : + if test ${ac_cv_search_sendfilev+y} +then : break fi done -if ${ac_cv_search_sendfilev+:} false; then : +if test ${ac_cv_search_sendfilev+y} +then : -else +else $as_nop ac_cv_search_sendfilev=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sendfilev" >&5 -$as_echo "$ac_cv_search_sendfilev" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sendfilev" >&5 +printf "%s\n" "$ac_cv_search_sendfilev" >&6; } ac_res=$ac_cv_search_sendfilev -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -$as_echo "#define HAVE_SENDFILEV 1" >>confdefs.h +printf "%s\n" "#define HAVE_SENDFILEV 1" >>confdefs.h fi - ;; - win32) + ;; #( + win32) : + LIBS="$LIBS -lmswsock" - ;; - *) - ;; + ;; #( + *) : + ;; esac @@ -17430,33 +19684,21 @@ CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" saved_libs=$LIBS LIBS="$LIBS $EMU_THR_X_LIBS" -for ac_header in windows.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" -if test "x$ac_cv_header_windows_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_WINDOWS_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes +then : + printf "%s\n" "#define HAVE_WINDOWS_H 1" >>confdefs.h fi -done - -for ac_header in winsock2.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" -if test "x$ac_cv_header_winsock2_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_WINSOCK2_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" +if test "x$ac_cv_header_winsock2_h" = xyes +then : + printf "%s\n" "#define HAVE_WINSOCK2_H 1" >>confdefs.h fi -done - -for ac_header in ws2tcpip.h -do : - ac_fn_c_check_header_compile "$LINENO" "ws2tcpip.h" "ac_cv_header_ws2tcpip_h" " +ac_fn_c_check_header_compile "$LINENO" "ws2tcpip.h" "ac_cv_header_ws2tcpip_h" " #ifdef HAVE_WINSOCK2_H #include #endif @@ -17465,17 +19707,14 @@ do : #endif " -if test "x$ac_cv_header_ws2tcpip_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_WS2TCPIP_H 1 -_ACEOF +if test "x$ac_cv_header_ws2tcpip_h" = xyes +then : + printf "%s\n" "#define HAVE_WS2TCPIP_H 1" >>confdefs.h fi -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 -$as_echo_n "checking for getaddrinfo... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 +printf %s "checking for getaddrinfo... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17496,7 +19735,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #endif int -main () +main (void) { getaddrinfo("","",NULL,NULL); @@ -17505,18 +19744,19 @@ getaddrinfo("","",NULL,NULL); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_getaddrinfo=yes -else +else $as_nop have_getaddrinfo=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $have_getaddrinfo = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getaddrinfo accepts enough flags" >&5 -$as_echo_n "checking whether getaddrinfo accepts enough flags... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getaddrinfo accepts enough flags" >&5 +printf %s "checking whether getaddrinfo accepts enough flags... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17537,7 +19777,7 @@ $as_echo_n "checking whether getaddrinfo accepts enough flags... " >&6; } #endif int -main () +main (void) { struct addrinfo hints, *ai; @@ -17556,28 +19796,29 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : -else +else $as_nop have_getaddrinfo=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_getaddrinfo" >&5 -$as_echo "$have_getaddrinfo" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_getaddrinfo" >&5 +printf "%s\n" "$have_getaddrinfo" >&6; } case $have_getaddrinfo in yes) -$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h ;; *) ;; esac else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getnameinfo" >&5 -$as_echo_n "checking for getnameinfo... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getnameinfo" >&5 +printf %s "checking for getnameinfo... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17598,7 +19839,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #endif int -main () +main (void) { getnameinfo(NULL,0,NULL,0,NULL,0,0); @@ -17607,60 +19848,316 @@ getnameinfo(NULL,0,NULL,0,NULL,0,0); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_getnameinfo=yes -else +else $as_nop have_getnameinfo=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $have_getnameinfo = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define HAVE_GETNAMEINFO 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETNAMEINFO 1" >>confdefs.h else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -for ac_func in getipnodebyname getipnodebyaddr gethostbyname2 -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "getipnodebyname" "ac_cv_func_getipnodebyname" +if test "x$ac_cv_func_getipnodebyname" = xyes +then : + printf "%s\n" "#define HAVE_GETIPNODEBYNAME 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "getipnodebyaddr" "ac_cv_func_getipnodebyaddr" +if test "x$ac_cv_func_getipnodebyaddr" = xyes +then : + printf "%s\n" "#define HAVE_GETIPNODEBYADDR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gethostbyname2" "ac_cv_func_gethostbyname2" +if test "x$ac_cv_func_gethostbyname2" = xyes +then : + printf "%s\n" "#define HAVE_GETHOSTBYNAME2 1" >>confdefs.h +fi -for ac_func in ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \ - pread pwrite memmove strerror strerror_r strncasecmp \ - gethrtime localtime_r gmtime_r mprotect madvise posix_madvise \ - mmap mremap memcpy mallopt sbrk _sbrk __sbrk brk _brk __brk \ - flockfile fstat strlcpy strlcat setsid posix2time time2posix \ - setlocale nl_langinfo poll mlockall ppoll vsyslog -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + +ac_fn_c_check_func "$LINENO" "ieee_handler" "ac_cv_func_ieee_handler" +if test "x$ac_cv_func_ieee_handler" = xyes +then : + printf "%s\n" "#define HAVE_IEEE_HANDLER 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fpsetmask" "ac_cv_func_fpsetmask" +if test "x$ac_cv_func_fpsetmask" = xyes +then : + printf "%s\n" "#define HAVE_FPSETMASK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "finite" "ac_cv_func_finite" +if test "x$ac_cv_func_finite" = xyes +then : + printf "%s\n" "#define HAVE_FINITE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan" +if test "x$ac_cv_func_isnan" = xyes +then : + printf "%s\n" "#define HAVE_ISNAN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "isinf" "ac_cv_func_isinf" +if test "x$ac_cv_func_isinf" = xyes +then : + printf "%s\n" "#define HAVE_ISINF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "res_gethostbyname" "ac_cv_func_res_gethostbyname" +if test "x$ac_cv_func_res_gethostbyname" = xyes +then : + printf "%s\n" "#define HAVE_RES_GETHOSTBYNAME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes +then : + printf "%s\n" "#define HAVE_DLOPEN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "dlvsym" "ac_cv_func_dlvsym" +if test "x$ac_cv_func_dlvsym" = xyes +then : + printf "%s\n" "#define HAVE_DLVSYM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" +if test "x$ac_cv_func_pread" = xyes +then : + printf "%s\n" "#define HAVE_PREAD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" +if test "x$ac_cv_func_pwrite" = xyes +then : + printf "%s\n" "#define HAVE_PWRITE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" +if test "x$ac_cv_func_memmove" = xyes +then : + printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" +if test "x$ac_cv_func_strerror" = xyes +then : + printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" +if test "x$ac_cv_func_strerror_r" = xyes +then : + printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp" +if test "x$ac_cv_func_strncasecmp" = xyes +then : + printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" +if test "x$ac_cv_func_localtime_r" = xyes +then : + printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r" +if test "x$ac_cv_func_gmtime_r" = xyes +then : + printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mprotect" "ac_cv_func_mprotect" +if test "x$ac_cv_func_mprotect" = xyes +then : + printf "%s\n" "#define HAVE_MPROTECT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "madvise" "ac_cv_func_madvise" +if test "x$ac_cv_func_madvise" = xyes +then : + printf "%s\n" "#define HAVE_MADVISE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix_madvise" "ac_cv_func_posix_madvise" +if test "x$ac_cv_func_posix_madvise" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_MADVISE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = xyes +then : + printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mremap" "ac_cv_func_mremap" +if test "x$ac_cv_func_mremap" = xyes +then : + printf "%s\n" "#define HAVE_MREMAP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "memcpy" "ac_cv_func_memcpy" +if test "x$ac_cv_func_memcpy" = xyes +then : + printf "%s\n" "#define HAVE_MEMCPY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "memrchr" "ac_cv_func_memrchr" +if test "x$ac_cv_func_memrchr" = xyes +then : + printf "%s\n" "#define HAVE_MEMRCHR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mallopt" "ac_cv_func_mallopt" +if test "x$ac_cv_func_mallopt" = xyes +then : + printf "%s\n" "#define HAVE_MALLOPT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sbrk" "ac_cv_func_sbrk" +if test "x$ac_cv_func_sbrk" = xyes +then : + printf "%s\n" "#define HAVE_SBRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "_sbrk" "ac_cv_func__sbrk" +if test "x$ac_cv_func__sbrk" = xyes +then : + printf "%s\n" "#define HAVE__SBRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "__sbrk" "ac_cv_func___sbrk" +if test "x$ac_cv_func___sbrk" = xyes +then : + printf "%s\n" "#define HAVE___SBRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "brk" "ac_cv_func_brk" +if test "x$ac_cv_func_brk" = xyes +then : + printf "%s\n" "#define HAVE_BRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "_brk" "ac_cv_func__brk" +if test "x$ac_cv_func__brk" = xyes +then : + printf "%s\n" "#define HAVE__BRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "__brk" "ac_cv_func___brk" +if test "x$ac_cv_func___brk" = xyes +then : + printf "%s\n" "#define HAVE___BRK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "flockfile" "ac_cv_func_flockfile" +if test "x$ac_cv_func_flockfile" = xyes +then : + printf "%s\n" "#define HAVE_FLOCKFILE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fstat" "ac_cv_func_fstat" +if test "x$ac_cv_func_fstat" = xyes +then : + printf "%s\n" "#define HAVE_FSTAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes +then : + printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes +then : + printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid" +if test "x$ac_cv_func_setsid" = xyes +then : + printf "%s\n" "#define HAVE_SETSID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix2time" "ac_cv_func_posix2time" +if test "x$ac_cv_func_posix2time" = xyes +then : + printf "%s\n" "#define HAVE_POSIX2TIME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "time2posix" "ac_cv_func_time2posix" +if test "x$ac_cv_func_time2posix" = xyes +then : + printf "%s\n" "#define HAVE_TIME2POSIX 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" +if test "x$ac_cv_func_setlocale" = xyes +then : + printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" +if test "x$ac_cv_func_nl_langinfo" = xyes +then : + printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" +if test "x$ac_cv_func_poll" = xyes +then : + printf "%s\n" "#define HAVE_POLL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mlockall" "ac_cv_func_mlockall" +if test "x$ac_cv_func_mlockall" = xyes +then : + printf "%s\n" "#define HAVE_MLOCKALL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll" +if test "x$ac_cv_func_ppoll" = xyes +then : + printf "%s\n" "#define HAVE_PPOLL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "vsyslog" "ac_cv_func_vsyslog" +if test "x$ac_cv_func_vsyslog" = xyes +then : + printf "%s\n" "#define HAVE_VSYSLOG 1" >>confdefs.h fi -done ## We have a special check for inet_pton as AC_CHECK_FUCNS does not work ## on windows 32-bit as there a macro is used to rename the symbol... -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_pton" >&5 -$as_echo_n "checking for inet_pton... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_pton" >&5 +printf %s "checking for inet_pton... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17671,77 +20168,88 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #endif int -main () +main (void) { inet_pton(2,"",(void*)0) ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_inet_pton=yes -else +else $as_nop have_inet_pton=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $have_inet_pton = yes; then -$as_echo "#define HAVE_INET_PTON 1" >>confdefs.h +printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for isfinite" >&5 -$as_echo_n "checking for isfinite... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for isfinite" >&5 +printf %s "checking for isfinite... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { isfinite(0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_isfinite=yes -else +else $as_nop have_isfinite=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $have_isfinite = yes; then -$as_echo "#define HAVE_ISFINITE 1" >>confdefs.h +printf "%s\n" "#define HAVE_ISFINITE 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -case X$erl_xcomp_posix_memalign in - Xno) ;; - Xyes) have_posix_memalign=yes ;; - *) +case X$erl_xcomp_posix_memalign in #( + Xno) : + ;; #( + Xyes) : + + have_posix_memalign=yes + ;; #( + *) : + ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" -if test "x$ac_cv_func_posix_memalign" = xyes; then : - if test "$cross_compiling" != yes; then -if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +if test "x$ac_cv_func_posix_memalign" = xyes +then : + if test "$cross_compiling" != yes +then : + +if test "$cross_compiling" = yes +then : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17756,7 +20264,8 @@ int main(void) { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : have_posix_memalign=yes fi @@ -17764,95 +20273,98 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi - else + +else $as_nop + have_posix_memalign=yes - fi + fi -;; +fi + + ;; esac if test "$have_posix_memalign" = "yes"; then -$as_echo "#define HAVE_POSIX_MEMALIGN 1" >>confdefs.h +printf "%s\n" "#define HAVE_POSIX_MEMALIGN 1" >>confdefs.h fi case $host_os in darwin10.8.0) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for writev" >&5 -$as_echo_n "checking for writev... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } ;; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for writev" >&5 +printf %s "checking for writev... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; *) - for ac_func in writev -do : - ac_fn_c_check_func "$LINENO" "writev" "ac_cv_func_writev" -if test "x$ac_cv_func_writev" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_WRITEV 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "writev" "ac_cv_func_writev" +if test "x$ac_cv_func_writev" = xyes +then : + printf "%s\n" "#define HAVE_WRITEV 1" >>confdefs.h fi -done ;; esac -ac_fn_c_check_decl "$LINENO" "posix2time" "ac_cv_have_decl_posix2time" "#include -" -if test "x$ac_cv_have_decl_posix2time" = xyes; then : +ac_fn_check_decl "$LINENO" "posix2time" "ac_cv_have_decl_posix2time" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_posix2time" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_POSIX2TIME $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "time2posix" "ac_cv_have_decl_time2posix" "#include -" -if test "x$ac_cv_have_decl_time2posix" = xyes; then : +printf "%s\n" "#define HAVE_DECL_POSIX2TIME $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "time2posix" "ac_cv_have_decl_time2posix" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_time2posix" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_TIME2POSIX $ac_have_decl -_ACEOF +printf "%s\n" "#define HAVE_DECL_TIME2POSIX $ac_have_decl" >>confdefs.h -for ac_func in vprintf -do : - ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" -if test "x$ac_cv_func_vprintf" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_VPRINTF 1 -_ACEOF +ac_func= +for ac_item in $ac_func_c_list +do + if test $ac_func; then + ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func + if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then + echo "#define $ac_item 1" >> confdefs.h + fi + ac_func= + else + ac_func=$ac_item + fi +done -ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" -if test "x$ac_cv_func__doprnt" = xyes; then : +if test "x$ac_cv_func_vprintf" = xno +then : + ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" +if test "x$ac_cv_func__doprnt" = xyes +then : -$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h +printf "%s\n" "#define HAVE_DOPRNT 1" >>confdefs.h fi fi -done - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for conflicting declaration of fread" >&5 -$as_echo_n "checking for conflicting declaration of fread... " >&6; } -if ${ac_cv_func_decl_fread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for conflicting declaration of fread" >&5 +printf %s "checking for conflicting declaration of fread... " >&6; } +if test ${ac_cv_func_decl_fread+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { extern int fread(); char *c = (char *)fread; @@ -17861,143 +20373,152 @@ char *c = (char *)fread; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "ac_cv_func_decl_fread=no" -else +else $as_nop eval "ac_cv_func_decl_fread=yes" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if eval "test \"`echo '$ac_cv_func_decl_'fread`\" = yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define HAVE_CONFLICTING_FREAD_DECLARATION 1" >>confdefs.h +printf "%s\n" "#define HAVE_CONFLICTING_FREAD_DECLARATION 1" >>confdefs.h else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for putc_unlocked" >&5 -$as_echo_n "checking for putc_unlocked... " >&6; } -if ${erts_cv_putc_unlocked+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for putc_unlocked" >&5 +printf %s "checking for putc_unlocked... " >&6; } +if test ${erts_cv_putc_unlocked+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int res = putc_unlocked('x',stdout); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_putc_unlocked=yes -else +else $as_nop erts_cv_putc_unlocked=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_putc_unlocked" >&5 -$as_echo "$erts_cv_putc_unlocked" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_putc_unlocked" >&5 +printf "%s\n" "$erts_cv_putc_unlocked" >&6; } if test $erts_cv_putc_unlocked = yes; then -$as_echo "#define HAVE_PUTC_UNLOCKED 1" >>confdefs.h +printf "%s\n" "#define HAVE_PUTC_UNLOCKED 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fwrite_unlocked" >&5 -$as_echo_n "checking for fwrite_unlocked... " >&6; } -if ${erts_cv_fwrite_unlocked+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fwrite_unlocked" >&5 +printf %s "checking for fwrite_unlocked... " >&6; } +if test ${erts_cv_fwrite_unlocked+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { size_t res = fwrite_unlocked(NULL,sizeof(char),0,stdout); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_fwrite_unlocked=yes -else +else $as_nop erts_cv_fwrite_unlocked=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_fwrite_unlocked" >&5 -$as_echo "$erts_cv_fwrite_unlocked" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_fwrite_unlocked" >&5 +printf "%s\n" "$erts_cv_fwrite_unlocked" >&6; } if test $erts_cv_fwrite_unlocked = yes; then -$as_echo "#define HAVE_FWRITE_UNLOCKED 1" >>confdefs.h +printf "%s\n" "#define HAVE_FWRITE_UNLOCKED 1" >>confdefs.h fi -for ac_func in openpty -do : - ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_OPENPTY 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" +if test "x$ac_cv_func_openpty" = xyes +then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h fi -done -for ac_header in net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "net/if_dl.h" "ac_cv_header_net_if_dl_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_dl_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_DL_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default" +if test "x$ac_cv_header_ifaddrs_h" = xyes +then : + printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" +if test "x$ac_cv_header_netpacket_packet_h" = xyes +then : + printf "%s\n" "#define HAVE_NETPACKET_PACKET_H 1" >>confdefs.h -for ac_func in getifaddrs -do : - ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" -if test "x$ac_cv_func_getifaddrs" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETIFADDRS 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_un_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h + +fi + +ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" +if test "x$ac_cv_func_getifaddrs" = xyes +then : + printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h fi -done ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_path" "ac_cv_member_struct_sockaddr_un_sun_path" "#include " -if test "x$ac_cv_member_struct_sockaddr_un_sun_path" = xyes; then : +if test "x$ac_cv_member_struct_sockaddr_un_sun_path" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SOCKADDR_UN_SUN_PATH 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_UN_SUN_PATH 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether in6addr_any is declared" >&5 -$as_echo_n "checking whether in6addr_any is declared... " >&6; } -if ${erts_cv_have_in6addr_any+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether in6addr_any is declared" >&5 +printf %s "checking whether in6addr_any is declared... " >&6; } +if test ${erts_cv_have_in6addr_any+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18007,7 +20528,7 @@ else #include int -main () +main (void) { printf("%d", in6addr_any.s6_addr[16]); @@ -18015,31 +20536,33 @@ printf("%d", in6addr_any.s6_addr[16]); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_have_in6addr_any=yes -else +else $as_nop erts_cv_have_in6addr_any=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_in6addr_any" >&5 -$as_echo "$erts_cv_have_in6addr_any" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_in6addr_any" >&5 +printf "%s\n" "$erts_cv_have_in6addr_any" >&6; } case "$erts_cv_have_in6addr_any" in yes) -$as_echo "#define HAVE_IN6ADDR_ANY 1" >>confdefs.h +printf "%s\n" "#define HAVE_IN6ADDR_ANY 1" >>confdefs.h esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether in6addr_loopback is declared" >&5 -$as_echo_n "checking whether in6addr_loopback is declared... " >&6; } -if ${erts_cv_have_in6addr_loopback+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether in6addr_loopback is declared" >&5 +printf %s "checking whether in6addr_loopback is declared... " >&6; } +if test ${erts_cv_have_in6addr_loopback+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18049,7 +20572,7 @@ else #include int -main () +main (void) { printf("%d", in6addr_loopback.s6_addr[16]); @@ -18057,81 +20580,76 @@ printf("%d", in6addr_loopback.s6_addr[16]); return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_have_in6addr_loopback=yes -else +else $as_nop erts_cv_have_in6addr_loopback=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_in6addr_loopback" >&5 -$as_echo "$erts_cv_have_in6addr_loopback" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_in6addr_loopback" >&5 +printf "%s\n" "$erts_cv_have_in6addr_loopback" >&6; } case "$erts_cv_have_in6addr_loopback" in yes) -$as_echo "#define HAVE_IN6ADDR_LOOPBACK 1" >>confdefs.h +printf "%s\n" "#define HAVE_IN6ADDR_LOOPBACK 1" >>confdefs.h esac -ac_fn_c_check_decl "$LINENO" "IN6ADDR_ANY_INIT" "ac_cv_have_decl_IN6ADDR_ANY_INIT" " +ac_fn_check_decl "$LINENO" "IN6ADDR_ANY_INIT" "ac_cv_have_decl_IN6ADDR_ANY_INIT" " #include #include #include -" -if test "x$ac_cv_have_decl_IN6ADDR_ANY_INIT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_IN6ADDR_ANY_INIT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_IN6ADDR_ANY_INIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "IN6ADDR_LOOPBACK_INIT" "ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT" " +printf "%s\n" "#define HAVE_DECL_IN6ADDR_ANY_INIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "IN6ADDR_LOOPBACK_INIT" "ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT" " #include #include #include -" -if test "x$ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_IN6ADDR_LOOPBACK_INIT $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "IPV6_V6ONLY" "ac_cv_have_decl_IPV6_V6ONLY" " +printf "%s\n" "#define HAVE_DECL_IN6ADDR_LOOPBACK_INIT $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "IPV6_V6ONLY" "ac_cv_have_decl_IPV6_V6ONLY" " #include #include #include -" -if test "x$ac_cv_have_decl_IPV6_V6ONLY" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_IPV6_V6ONLY" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_IPV6_V6ONLY $ac_have_decl -_ACEOF +printf "%s\n" "#define HAVE_DECL_IPV6_V6ONLY $ac_have_decl" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_getaffinity/sched_setaffinity" >&5 -$as_echo_n "checking for sched_getaffinity/sched_setaffinity... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_getaffinity/sched_setaffinity" >&5 +printf %s "checking for sched_getaffinity/sched_setaffinity... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef CPU_SETSIZE @@ -18150,29 +20668,30 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : sched_xetaffinity=yes -else +else $as_nop sched_xetaffinity=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sched_xetaffinity" >&5 -$as_echo "$sched_xetaffinity" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sched_xetaffinity" >&5 +printf "%s\n" "$sched_xetaffinity" >&6; } if test $sched_xetaffinity = yes; then -$as_echo "#define HAVE_SCHED_xETAFFINITY 1" >>confdefs.h +printf "%s\n" "#define HAVE_SCHED_xETAFFINITY 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pset functionality" >&5 -$as_echo_n "checking for pset functionality... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pset functionality" >&5 +printf %s "checking for pset functionality... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int res; @@ -18187,23 +20706,24 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : pset_functionality=yes -else +else $as_nop pset_functionality=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pset_functionality" >&5 -$as_echo "$pset_functionality" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $pset_functionality" >&5 +printf "%s\n" "$pset_functionality" >&6; } if test $pset_functionality = yes; then -$as_echo "#define HAVE_PSET 1" >>confdefs.h +printf "%s\n" "#define HAVE_PSET 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for processor_bind functionality" >&5 -$as_echo_n "checking for processor_bind functionality... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for processor_bind functionality" >&5 +printf %s "checking for processor_bind functionality... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18212,7 +20732,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include int -main () +main (void) { int res = processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL); @@ -18221,23 +20741,24 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : processor_bind_functionality=yes -else +else $as_nop processor_bind_functionality=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $processor_bind_functionality" >&5 -$as_echo "$processor_bind_functionality" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $processor_bind_functionality" >&5 +printf "%s\n" "$processor_bind_functionality" >&6; } if test $processor_bind_functionality = yes; then -$as_echo "#define HAVE_PROCESSOR_BIND 1" >>confdefs.h +printf "%s\n" "#define HAVE_PROCESSOR_BIND 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cpuset_getaffinity/cpuset_setaffinity" >&5 -$as_echo_n "checking for cpuset_getaffinity/cpuset_setaffinity... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cpuset_getaffinity/cpuset_setaffinity" >&5 +printf %s "checking for cpuset_getaffinity/cpuset_setaffinity... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18245,7 +20766,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include int -main () +main (void) { int res; @@ -18261,91 +20782,98 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : cpuset_xetaffinity=yes -else +else $as_nop cpuset_xetaffinity=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cpuset_xetaffinity" >&5 -$as_echo "$cpuset_xetaffinity" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cpuset_xetaffinity" >&5 +printf "%s\n" "$cpuset_xetaffinity" >&6; } if test $cpuset_xetaffinity = yes; then -$as_echo "#define HAVE_CPUSET_xETAFFINITY 1" >>confdefs.h +printf "%s\n" "#define HAVE_CPUSET_xETAFFINITY 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'end' symbol" >&5 -$as_echo_n "checking for 'end' symbol... " >&6; } -if ${erts_cv_have_end_symbol+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 'end' symbol" >&5 +printf %s "checking for 'end' symbol... " >&6; } +if test ${erts_cv_have_end_symbol+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { extern char end; {char *x = &end; *x= 0;} ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_have_end_symbol=yes -else +else $as_nop erts_cv_have_end_symbol=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_end_symbol" >&5 -$as_echo "$erts_cv_have_end_symbol" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have_end_symbol" >&5 +printf "%s\n" "$erts_cv_have_end_symbol" >&6; } if test $erts_cv_have_end_symbol = yes; then -$as_echo "#define HAVE_END_SYMBOL 1" >>confdefs.h +printf "%s\n" "#define HAVE_END_SYMBOL 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for '_end' symbol" >&5 -$as_echo_n "checking for '_end' symbol... " >&6; } -if ${erts_cv_have__end_symbol+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for '_end' symbol" >&5 +printf %s "checking for '_end' symbol... " >&6; } +if test ${erts_cv_have__end_symbol+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { extern char _end; {char *x = &_end; *x= 0;} ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_have__end_symbol=yes -else +else $as_nop erts_cv_have__end_symbol=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have__end_symbol" >&5 -$as_echo "$erts_cv_have__end_symbol" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_have__end_symbol" >&5 +printf "%s\n" "$erts_cv_have__end_symbol" >&6; } if test $erts_cv_have__end_symbol = yes; then -$as_echo "#define HAVE__END_SYMBOL 1" >>confdefs.h +printf "%s\n" "#define HAVE__END_SYMBOL 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if __after_morecore_hook can track malloc()s core memory use" >&5 -$as_echo_n "checking if __after_morecore_hook can track malloc()s core memory use... " >&6; } -if ${erts_cv___after_morecore_hook_can_track_malloc+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if __after_morecore_hook can track malloc()s core memory use" >&5 +printf %s "checking if __after_morecore_hook can track malloc()s core memory use... " >&6; } +if test ${erts_cv___after_morecore_hook_can_track_malloc+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : case X$erl_xcomp_after_morecore_hook in X) erts_cv___after_morecore_hook_can_track_malloc=cross;; @@ -18354,7 +20882,7 @@ else esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18481,9 +21009,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : erts_cv___after_morecore_hook_can_track_malloc=yes -else +else $as_nop erts_cv___after_morecore_hook_can_track_malloc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -18491,24 +21020,27 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv___after_morecore_hook_can_track_malloc" >&5 -$as_echo "$erts_cv___after_morecore_hook_can_track_malloc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv___after_morecore_hook_can_track_malloc" >&5 +printf "%s\n" "$erts_cv___after_morecore_hook_can_track_malloc" >&6; } case $erts_cv___after_morecore_hook_can_track_malloc in yes) -$as_echo "#define ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC 1" >>confdefs.h +printf "%s\n" "#define ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC 1" >>confdefs.h ;; - cross) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; + cross) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; *) ;; esac -if test "x$ac_cv_func_sbrk" = "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking types of sbrk()s return value and argument" >&5 -$as_echo_n "checking types of sbrk()s return value and argument... " >&6; } -if ${erts_cv_sbrk_ret_arg_types+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_sbrk" = "xyes" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking types of sbrk()s return value and argument" >&5 +printf %s "checking types of sbrk()s return value and argument... " >&6; } +if test ${erts_cv_sbrk_ret_arg_types+y} +then : + printf %s "(cached) " >&6 +else $as_nop erts_cv_sbrk_ret_arg_types=unknown @@ -18523,17 +21055,18 @@ else #include #include int -main () +main (void) { $rtype sbrk($atype incr); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_sbrk_ret_arg_types="$rtype,$atype" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext IFS="," if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then @@ -18543,8 +21076,8 @@ rm -f core conftest.err conftest.$ac_objext \ done IFS=$save_ifs fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_sbrk_ret_arg_types" >&5 -$as_echo "$erts_cv_sbrk_ret_arg_types" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_sbrk_ret_arg_types" >&5 +printf "%s\n" "$erts_cv_sbrk_ret_arg_types" >&6; } if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then save_ifs="$IFS"; IFS="," @@ -18553,24 +21086,24 @@ $erts_cv_sbrk_ret_arg_types EOF IFS=$save_ifs -cat >>confdefs.h <<_ACEOF -#define SBRK_RET_TYPE $ret_type -_ACEOF +printf "%s\n" "#define SBRK_RET_TYPE $ret_type" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define SBRK_ARG_TYPE $arg_type -_ACEOF +printf "%s\n" "#define SBRK_ARG_TYPE $arg_type" >>confdefs.h fi + fi -if test $ac_cv_func_brk = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking types of brk()s return value and argument" >&5 -$as_echo_n "checking types of brk()s return value and argument... " >&6; } -if ${erts_cv_brk_ret_arg_types+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test $ac_cv_func_brk = yes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking types of brk()s return value and argument" >&5 +printf %s "checking types of brk()s return value and argument... " >&6; } +if test ${erts_cv_brk_ret_arg_types+y} +then : + printf %s "(cached) " >&6 +else $as_nop erts_cv_brk_ret_arg_types=unknown @@ -18585,17 +21118,18 @@ else #include #include int -main () +main (void) { $rtype brk($atype endds); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erts_cv_brk_ret_arg_types="$rtype,$atype" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext IFS="," if test "$erts_cv_brk_ret_arg_types" != "unknown"; then @@ -18605,8 +21139,8 @@ rm -f core conftest.err conftest.$ac_objext \ done IFS=$save_ifs fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_brk_ret_arg_types" >&5 -$as_echo "$erts_cv_brk_ret_arg_types" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_brk_ret_arg_types" >&5 +printf "%s\n" "$erts_cv_brk_ret_arg_types" >&6; } if test "$erts_cv_brk_ret_arg_types" != "unknown"; then save_ifs="$IFS"; IFS="," @@ -18615,27 +21149,27 @@ $erts_cv_brk_ret_arg_types EOF IFS=$save_ifs -cat >>confdefs.h <<_ACEOF -#define BRK_RET_TYPE $ret_type -_ACEOF +printf "%s\n" "#define BRK_RET_TYPE $ret_type" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define BRK_ARG_TYPE $arg_type -_ACEOF +printf "%s\n" "#define BRK_ARG_TYPE $arg_type" >>confdefs.h fi fi -if test $ac_cv_func_sbrk = yes; then +if test $ac_cv_func_sbrk = yes +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if sbrk()/brk() wrappers can track malloc()s core memory use" >&5 -$as_echo_n "checking if sbrk()/brk() wrappers can track malloc()s core memory use... " >&6; } -if ${erts_cv_brk_wrappers_can_track_malloc+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sbrk()/brk() wrappers can track malloc()s core memory use" >&5 +printf %s "checking if sbrk()/brk() wrappers can track malloc()s core memory use... " >&6; } +if test ${erts_cv_brk_wrappers_can_track_malloc+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : case X$erl_xcomp_dlsym_brk_wrappers in X) erts_cv_brk_wrappers_can_track_malloc=cross;; @@ -18643,7 +21177,7 @@ else *) as_fn_error $? "Bad erl_xcomp_dlsym_brk_wrappers value: $erl_xcomp_dlsym_brk_wrappers" "$LINENO" 5;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18813,9 +21347,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : erts_cv_brk_wrappers_can_track_malloc=yes -else +else $as_nop erts_cv_brk_wrappers_can_track_malloc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -18823,18 +21358,19 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erts_cv_brk_wrappers_can_track_malloc" >&5 -$as_echo "$erts_cv_brk_wrappers_can_track_malloc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erts_cv_brk_wrappers_can_track_malloc" >&5 +printf "%s\n" "$erts_cv_brk_wrappers_can_track_malloc" >&6; } case $erts_cv_brk_wrappers_can_track_malloc in yes) -$as_echo "#define ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC 1" >>confdefs.h +printf "%s\n" "#define ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC 1" >>confdefs.h ;; cross) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; *) ;; esac + fi LIBS=$saved_libs @@ -18843,17 +21379,18 @@ CPPFLAGS=$saved_cppflags case $ARCH in x86|amd64) -$as_echo "#define ERTS_STRUCTURE_ALIGNED_ALLOC 1" >>confdefs.h +printf "%s\n" "#define ERTS_STRUCTURE_ALIGNED_ALLOC 1" >>confdefs.h ;; *) ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP version 6 support" >&5 -$as_echo_n "checking for IP version 6 support... " >&6; } -if ${ac_cv_sys_ipv6_support+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for IP version 6 support" >&5 +printf %s "checking for IP version 6 support... " >&6; } +if test ${ac_cv_sys_ipv6_support+y} +then : + printf %s "(cached) " >&6 +else $as_nop ok_so_far=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18865,23 +21402,28 @@ else #include #endif int -main () +main (void) { struct in6_addr a6; struct sockaddr_in6 s6; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ok_so_far=yes -else +else $as_nop ok_so_far=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +if test $ok_so_far = yes +then : -if test $ok_so_far = yes; then ac_cv_sys_ipv6_support=yes -else + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18892,19 +21434,21 @@ else #include #endif int -main () +main (void) { struct in_addr6 a6; struct sockaddr_in6 s6; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_ipv6_support=in_addr6 -else +else $as_nop ac_cv_sys_ipv6_support=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi fi @@ -18912,34 +21456,36 @@ fi case ${ac_cv_sys_ipv6_support} in yes) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define HAVE_IN6 1" >>confdefs.h +printf "%s\n" "#define HAVE_IN6 1" >>confdefs.h ;; in_addr6) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (but I am redefining in_addr6 to in6_addr)" >&5 -$as_echo "yes (but I am redefining in_addr6 to in6_addr)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (but I am redefining in_addr6 to in6_addr)" >&5 +printf "%s\n" "yes (but I am redefining in_addr6 to in6_addr)" >&6; } -$as_echo "#define HAVE_IN6 1" >>confdefs.h +printf "%s\n" "#define HAVE_IN6 1" >>confdefs.h -$as_echo "#define HAVE_IN_ADDR6_STRUCT /**/" >>confdefs.h +printf "%s\n" "#define HAVE_IN_ADDR6_STRUCT /**/" >>confdefs.h ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for multicast support" >&5 -$as_echo_n "checking for multicast support... " >&6; } -if ${ac_cv_sys_multicast_support+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for multicast support" >&5 +printf %s "checking for multicast support... " >&6; } +if test ${ac_cv_sys_multicast_support+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -18950,19 +21496,20 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "^yes$" >/dev/null 2>&1; then : + $EGREP "^yes$" >/dev/null 2>&1 +then : ac_cv_sys_multicast_support=yes -else +else $as_nop ac_cv_sys_multicast_support=no fi -rm -f conftest* +rm -rf conftest* fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_multicast_support" >&5 -$as_echo "$ac_cv_sys_multicast_support" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_multicast_support" >&5 +printf "%s\n" "$ac_cv_sys_multicast_support" >&6; } if test $ac_cv_sys_multicast_support = yes; then -$as_echo "#define HAVE_MULTICAST_SUPPORT 1" >>confdefs.h +printf "%s\n" "#define HAVE_MULTICAST_SUPPORT 1" >>confdefs.h fi @@ -18970,43 +21517,48 @@ fi # Check whether --with-clock-resolution was given. -if test "${with_clock_resolution+set}" = set; then : +if test ${with_clock_resolution+y} +then : withval=$with_clock_resolution; fi # Check whether --with-clock-gettime-realtime-id was given. -if test "${with_clock_gettime_realtime_id+set}" = set; then : +if test ${with_clock_gettime_realtime_id+y} +then : withval=$with_clock_gettime_realtime_id; fi # Check whether --with-clock-gettime-monotonic-id was given. -if test "${with_clock_gettime_monotonic_id+set}" = set; then : +if test ${with_clock_gettime_monotonic_id+y} +then : withval=$with_clock_gettime_monotonic_id; fi # Check whether --enable-prefer-elapsed-monotonic-time-during-suspend was given. -if test "${enable_prefer_elapsed_monotonic_time_during_suspend+set}" = set; then : +if test ${enable_prefer_elapsed_monotonic_time_during_suspend+y} +then : enableval=$enable_prefer_elapsed_monotonic_time_during_suspend; case "$enableval" in yes) prefer_elapsed_monotonic_time_during_suspend=yes ;; *) prefer_elapsed_monotonic_time_during_suspend=no ;; esac -else +else $as_nop prefer_elapsed_monotonic_time_during_suspend=no fi # Check whether --enable-gettimeofday-as-os-system-time was given. -if test "${enable_gettimeofday_as_os_system_time+set}" = set; then : +if test ${enable_gettimeofday_as_os_system_time+y} +then : enableval=$enable_gettimeofday_as_os_system_time; case "$enableval" in yes) force_gettimeofday_os_system_time=yes ;; *) force_gettimeofday_os_system_time=no ;; esac -else +else $as_nop force_gettimeofday_os_system_time=no fi @@ -19021,28 +21573,28 @@ case "$with_clock_resolution" in ;; esac -if test "$force_gettimeofday_os_system_time" = "yes"; then +if test "$force_gettimeofday_os_system_time" = "yes" +then : + - for ac_func in gettimeofday -do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETTIMEOFDAY 1 -_ACEOF +if test "x$ac_cv_func_gettimeofday" = xyes +then : + printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h fi -done if test "$ac_cv_func_gettimeofday" = "yes"; then -$as_echo "#define OS_SYSTEM_TIME_GETTIMEOFDAY 1" >>confdefs.h +printf "%s\n" "#define OS_SYSTEM_TIME_GETTIMEOFDAY 1" >>confdefs.h else as_fn_error $? "No gettimeofday() available" "$LINENO" 5 fi -else # $force_gettimeofday_os_system_time != yes +else $as_nop + + # $force_gettimeofday_os_system_time != yes case "$with_clock_gettime_realtime_id" in ""|no) @@ -19061,8 +21613,9 @@ case "$with_clock_gettime_realtime_id" in ;; esac -case "$with_clock_resolution-$with_clock_gettime_realtime_id" in - high-no) +case "$with_clock_resolution-$with_clock_gettime_realtime_id" in #( + high-no) : + default_resolution_clock_gettime_wall="CLOCK_REALTIME" low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" @@ -19088,11 +21641,12 @@ case "$with_clock_resolution-$with_clock_gettime_realtime_id" in esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19101,30 +21655,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -19138,11 +21691,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } -if ${erl_cv_clock_gettime_wall_high_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } +if test ${erl_cv_clock_gettime_wall_high_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19152,7 +21706,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -19165,46 +21719,56 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_wall_high_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_wall_high_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_wall_high_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_high_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_wall_high_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_high_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_wall_high_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - check_for_clock_getres= - else - check_for_clock_getres=clock_getres - fi + if test "$LD_MAY_BE_WEAK" = "no" +then : - for ac_func in $check_for_clock_getres clock_get_attributes gettimeofday -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with wall clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_wall+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" +if test "x$ac_cv_func_gettimeofday" = xyes +then : + printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 +printf %s "checking for mach clock_get_time() with wall clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_wall+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19213,7 +21777,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -19228,16 +21792,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_wall=yes -else +else $as_nop erl_cv_mach_clock_get_time_wall=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 -$as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_lib= erl_wall_clock_low_resolution=no @@ -19269,8 +21834,10 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_func=none ;; esac -;; - low-no) + + ;; #( + low-no) : + default_resolution_clock_gettime_wall="CLOCK_REALTIME" low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" @@ -19296,11 +21863,12 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19309,30 +21877,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -19346,11 +21913,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } -if ${erl_cv_clock_gettime_wall_low_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } +if test ${erl_cv_clock_gettime_wall_low_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19360,7 +21928,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -19373,46 +21941,56 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_wall_low_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_wall_low_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_wall_low_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_low_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_wall_low_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_low_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_wall_low_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - check_for_clock_getres= - else - check_for_clock_getres=clock_getres - fi + if test "$LD_MAY_BE_WEAK" = "no" +then : - for ac_func in $check_for_clock_getres clock_get_attributes gettimeofday -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with wall clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_wall+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" +if test "x$ac_cv_func_gettimeofday" = xyes +then : + printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 +printf %s "checking for mach clock_get_time() with wall clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_wall+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19421,7 +21999,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -19436,16 +22014,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_wall=yes -else +else $as_nop erl_cv_mach_clock_get_time_wall=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 -$as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_lib= erl_wall_clock_low_resolution=no @@ -19477,8 +22056,10 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_func=none ;; esac -;; - default-no) + + ;; #( + default-no) : + default_resolution_clock_gettime_wall="CLOCK_REALTIME" low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" @@ -19504,11 +22085,12 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19517,30 +22099,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -19554,11 +22135,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } -if ${erl_cv_clock_gettime_wall_default_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } +if test ${erl_cv_clock_gettime_wall_default_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19568,7 +22150,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -19581,46 +22163,56 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_wall_default_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_wall_default_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_wall_default_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_default_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_wall_default_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_default_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_wall_default_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - check_for_clock_getres= - else - check_for_clock_getres=clock_getres - fi + if test "$LD_MAY_BE_WEAK" = "no" +then : - for ac_func in $check_for_clock_getres clock_get_attributes gettimeofday -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with wall clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_wall+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" +if test "x$ac_cv_func_gettimeofday" = xyes +then : + printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 +printf %s "checking for mach clock_get_time() with wall clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_wall+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19629,7 +22221,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -19644,16 +22236,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_wall=yes -else +else $as_nop erl_cv_mach_clock_get_time_wall=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 -$as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_lib= erl_wall_clock_low_resolution=no @@ -19685,8 +22278,10 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_func=none ;; esac -;; - *) + + ;; #( + *) : + default_resolution_clock_gettime_wall="CLOCK_REALTIME" low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" @@ -19712,11 +22307,12 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19725,30 +22321,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -19762,11 +22357,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } -if ${erl_cv_clock_gettime_wall_custom_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}wall clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}wall clock type... " >&6; } +if test ${erl_cv_clock_gettime_wall_custom_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19776,7 +22372,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -19789,46 +22385,56 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_wall_custom_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_wall_custom_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_wall_custom_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_custom_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_wall_custom_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_wall_custom_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_wall_custom_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - check_for_clock_getres= - else - check_for_clock_getres=clock_getres - fi + if test "$LD_MAY_BE_WEAK" = "no" +then : - for ac_func in $check_for_clock_getres clock_get_attributes gettimeofday -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with wall clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_wall+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" +if test "x$ac_cv_func_gettimeofday" = xyes +then : + printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h + +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with wall clock type" >&5 +printf %s "checking for mach clock_get_time() with wall clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_wall+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19837,7 +22443,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -19852,16 +22458,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_wall=yes -else +else $as_nop erl_cv_mach_clock_get_time_wall=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 -$as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_wall" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_lib= erl_wall_clock_low_resolution=no @@ -19893,7 +22500,8 @@ $as_echo "$erl_cv_mach_clock_get_time_wall" >&6; } erl_wall_clock_func=none ;; esac -;; + + ;; esac case "$erl_wall_clock_func-$erl_wall_clock_id-$with_clock_gettime_realtime_id" in @@ -19912,17 +22520,17 @@ case $erl_wall_clock_func in ;; mach_clock_get_time) -$as_echo "#define OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h +printf "%s\n" "#define OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h ;; clock_gettime) -$as_echo "#define OS_SYSTEM_TIME_USING_CLOCK_GETTIME 1" >>confdefs.h +printf "%s\n" "#define OS_SYSTEM_TIME_USING_CLOCK_GETTIME 1" >>confdefs.h ;; gettimeofday) -$as_echo "#define OS_SYSTEM_TIME_GETTIMEOFDAY 1" >>confdefs.h +printf "%s\n" "#define OS_SYSTEM_TIME_GETTIMEOFDAY 1" >>confdefs.h ;; *) @@ -19931,17 +22539,14 @@ esac if test "x$erl_wall_clock_id" != "x"; then -cat >>confdefs.h <<_ACEOF -#define WALL_CLOCK_ID_STR "$erl_wall_clock_id" -_ACEOF +printf "%s\n" "#define WALL_CLOCK_ID_STR \"$erl_wall_clock_id\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define WALL_CLOCK_ID $erl_wall_clock_id -_ACEOF +printf "%s\n" "#define WALL_CLOCK_ID $erl_wall_clock_id" >>confdefs.h fi + fi # $force_gettimeofday_os_system_time != yes case "$with_clock_gettime_monotonic_id" in @@ -19970,8 +22575,9 @@ case "$with_clock_gettime_monotonic_id" in ;; esac -case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in - high-no) +case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in #( + high-no) : + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur # and Monterey, since it may step backwards. @@ -20019,11 +22625,12 @@ case "$with_clock_resolution-$with_clock_gettime_monotonic_id" in esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20032,30 +22639,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -20069,11 +22675,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20082,7 +22689,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20095,23 +22702,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_high_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_high_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20121,7 +22730,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20134,56 +22743,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_high_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_high_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_high_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_high_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_high_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_high_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_high_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi + + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20192,7 +22815,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -20207,16 +22830,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_high_resolution-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -20278,8 +22902,10 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } ;; esac -;; - low-no) + + ;; #( + low-no) : + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur # and Monterey, since it may step backwards. @@ -20327,11 +22953,12 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20340,30 +22967,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -20377,11 +23003,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20390,7 +23017,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20403,23 +23030,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_low_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_low_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20429,7 +23058,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20442,56 +23071,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_low_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_low_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_low_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_low_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_low_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_low_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_low_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi + + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20500,7 +23143,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -20515,16 +23158,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_low_resolution-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -20586,8 +23230,10 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } ;; esac -;; - default-no) + + ;; #( + default-no) : + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur # and Monterey, since it may step backwards. @@ -20635,11 +23281,12 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20648,30 +23295,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -20685,11 +23331,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20698,7 +23345,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20711,23 +23358,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_default_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_default_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20737,7 +23386,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -20750,56 +23399,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_default_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_default_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_default_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_default_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_default_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_default_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_default_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h fi -done - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20808,7 +23471,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -20823,16 +23486,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_default_resolution-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -20894,8 +23558,10 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } ;; esac -;; - *) + + ;; #( + *) : + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur # and Monterey, since it may step backwards. @@ -20943,11 +23609,12 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20956,30 +23623,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -20993,11 +23659,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21006,7 +23673,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -21019,23 +23686,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_custom_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_custom_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21045,7 +23714,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -21058,56 +23727,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_custom_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_custom_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_custom_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_custom_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_custom_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_custom_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_custom_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi + + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21116,7 +23799,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -21131,16 +23814,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_custom_resolution-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -21202,7 +23886,8 @@ $as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } ;; esac -;; + + ;; esac case "$erl_monotonic_clock_func-$erl_monotonic_clock_id-$with_clock_gettime_monotonic_id" in @@ -21218,22 +23903,22 @@ esac case $erl_monotonic_clock_func in times) -$as_echo "#define OS_MONOTONIC_TIME_USING_TIMES 1" >>confdefs.h +printf "%s\n" "#define OS_MONOTONIC_TIME_USING_TIMES 1" >>confdefs.h ;; mach_clock_get_time) -$as_echo "#define OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h +printf "%s\n" "#define OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h ;; clock_gettime) -$as_echo "#define OS_MONOTONIC_TIME_USING_CLOCK_GETTIME 1" >>confdefs.h +printf "%s\n" "#define OS_MONOTONIC_TIME_USING_CLOCK_GETTIME 1" >>confdefs.h ;; gethrtime) -$as_echo "#define OS_MONOTONIC_TIME_USING_GETHRTIME 1" >>confdefs.h +printf "%s\n" "#define OS_MONOTONIC_TIME_USING_GETHRTIME 1" >>confdefs.h ;; *) @@ -21242,13 +23927,13 @@ esac if test $erl_corrected_monotonic_clock = yes; then -$as_echo "#define ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME 1" >>confdefs.h +printf "%s\n" "#define ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME 1" >>confdefs.h fi if test $erl_monotonic_clock_low_resolution = yes; then -$as_echo "#define ERTS_HAVE_LOW_RESOLUTION_OS_MONOTONIC_LOW 1" >>confdefs.h +printf "%s\n" "#define ERTS_HAVE_LOW_RESOLUTION_OS_MONOTONIC_LOW 1" >>confdefs.h fi @@ -21261,20 +23946,16 @@ if test "$erl_wall_clock_lib" != ""; then fi if test "x$erl_monotonic_clock_id" != "x"; then -cat >>confdefs.h <<_ACEOF -#define MONOTONIC_CLOCK_ID_STR "$erl_monotonic_clock_id" -_ACEOF +printf "%s\n" "#define MONOTONIC_CLOCK_ID_STR \"$erl_monotonic_clock_id\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define MONOTONIC_CLOCK_ID $erl_monotonic_clock_id -_ACEOF +printf "%s\n" "#define MONOTONIC_CLOCK_ID $erl_monotonic_clock_id" >>confdefs.h fi if test $erl_cv_clock_gettime_monotonic_raw = yes; then -$as_echo "#define HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1" >>confdefs.h +printf "%s\n" "#define HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1" >>confdefs.h fi @@ -21325,11 +24006,12 @@ fi esac clock_gettime_lib="" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21338,30 +24020,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : clock_gettime_lib="-lrt" fi @@ -21375,11 +24056,12 @@ fi trust_test="" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 -$as_echo_n "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } -if ${erl_cv_clock_gettime_monotonic_raw+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)" >&5 +printf %s "checking for clock_gettime(CLOCK_MONOTONIC_RAW, _)... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_raw+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21388,7 +24070,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -21401,23 +24083,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_raw=yes -else +else $as_nop erl_cv_clock_gettime_monotonic_raw=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_raw" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_raw" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_raw" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 -$as_echo_n "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } -if ${erl_cv_clock_gettime_monotonic_high_resolution+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime() with ${check_msg}monotonic clock type" >&5 +printf %s "checking for clock_gettime() with ${check_msg}monotonic clock type... " >&6; } +if test ${erl_cv_clock_gettime_monotonic_high_resolution+y} +then : + printf %s "(cached) " >&6 +else $as_nop for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21427,7 +24111,7 @@ else $trust_test int -main () +main (void) { struct timespec ts; @@ -21440,56 +24124,70 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : erl_cv_clock_gettime_monotonic_high_resolution=$clock_type -else +else $as_nop erl_cv_clock_gettime_monotonic_high_resolution=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext test $erl_cv_clock_gettime_monotonic_high_resolution = no || break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_high_resolution" >&5 -$as_echo "$erl_cv_clock_gettime_monotonic_high_resolution" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_clock_gettime_monotonic_high_resolution" >&5 +printf "%s\n" "$erl_cv_clock_gettime_monotonic_high_resolution" >&6; } LIBS="$save_LIBS" - if test "$LD_MAY_BE_WEAK" != "no"; then - for ac_func in clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF + if test "$LD_MAY_BE_WEAK" != "no" +then : + + ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h - else - for ac_func in clock_getres clock_get_attributes gethrtime -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi + + +else $as_nop + + ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "clock_get_attributes" "ac_cv_func_clock_get_attributes" +if test "x$ac_cv_func_clock_get_attributes" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GET_ATTRIBUTES 1" >>confdefs.h - fi +fi +ac_fn_c_check_func "$LINENO" "gethrtime" "ac_cv_func_gethrtime" +if test "x$ac_cv_func_gethrtime" = xyes +then : + printf "%s\n" "#define HAVE_GETHRTIME 1" >>confdefs.h +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 -$as_echo_n "checking for mach clock_get_time() with monotonic clock type... " >&6; } -if ${erl_cv_mach_clock_get_time_monotonic+:} false; then : - $as_echo_n "(cached) " >&6 -else + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mach clock_get_time() with monotonic clock type" >&5 +printf %s "checking for mach clock_get_time() with monotonic clock type... " >&6; } +if test ${erl_cv_mach_clock_get_time_monotonic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21498,7 +24196,7 @@ else #include int -main () +main (void) { kern_return_t res; @@ -21513,16 +24211,17 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : erl_cv_mach_clock_get_time_monotonic=yes -else +else $as_nop erl_cv_mach_clock_get_time_monotonic=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 -$as_echo "$erl_cv_mach_clock_get_time_monotonic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_cv_mach_clock_get_time_monotonic" >&5 +printf "%s\n" "$erl_cv_mach_clock_get_time_monotonic" >&6; } erl_corrected_monotonic_clock=no case $erl_cv_clock_gettime_monotonic_high_resolution-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in @@ -21590,19 +24289,19 @@ case $erl_monotonic_clock_low_resolution-$erl_monotonic_clock_func in no-mach_clock_get_time) monotonic_hrtime=yes -$as_echo "#define SYS_HRTIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h +printf "%s\n" "#define SYS_HRTIME_USING_MACH_CLOCK_GET_TIME 1" >>confdefs.h ;; no-clock_gettime) monotonic_hrtime=yes -$as_echo "#define SYS_HRTIME_USING_CLOCK_GETTIME 1" >>confdefs.h +printf "%s\n" "#define SYS_HRTIME_USING_CLOCK_GETTIME 1" >>confdefs.h ;; no-gethrtime) monotonic_hrtime=yes -$as_echo "#define SYS_HRTIME_USING_GETHRTIME 1" >>confdefs.h +printf "%s\n" "#define SYS_HRTIME_USING_GETHRTIME 1" >>confdefs.h ;; *) @@ -21612,28 +24311,25 @@ esac if test $monotonic_hrtime = yes; then -$as_echo "#define HAVE_MONOTONIC_ERTS_SYS_HRTIME 1" >>confdefs.h +printf "%s\n" "#define HAVE_MONOTONIC_ERTS_SYS_HRTIME 1" >>confdefs.h fi if test "x$erl_monotonic_clock_id" != "x"; then -cat >>confdefs.h <<_ACEOF -#define HRTIME_CLOCK_ID_STR "$erl_monotonic_clock_id" -_ACEOF +printf "%s\n" "#define HRTIME_CLOCK_ID_STR \"$erl_monotonic_clock_id\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define HRTIME_CLOCK_ID $erl_monotonic_clock_id -_ACEOF +printf "%s\n" "#define HRTIME_CLOCK_ID $erl_monotonic_clock_id" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if gethrvtime works and how to use it" >&5 -$as_echo_n "checking if gethrvtime works and how to use it... " >&6; } -if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gethrvtime works and how to use it" >&5 +printf %s "checking if gethrvtime works and how to use it... " >&6; } +if test "$cross_compiling" = yes +then : case X$erl_xcomp_gethrvtime_procfs_ioctl in X) @@ -21648,7 +24344,7 @@ case X$erl_xcomp_gethrvtime_procfs_ioctl in as_fn_error $? "Bad erl_xcomp_gethrvtime_procfs_ioctl value: $erl_xcomp_gethrvtime_procfs_ioctl" "$LINENO" 5;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21701,9 +24397,10 @@ int main() { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : erl_gethrvtime=procfs_ioctl -else +else $as_nop erl_gethrvtime=false fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21712,32 +24409,35 @@ fi LIBRT=$xrtlib -case $erl_gethrvtime in - procfs_ioctl) +if test "$erl_gethrvtime" = "procfs_ioctl" +then : -$as_echo "#define HAVE_GETHRVTIME_PROCFS_IOCTL 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: uses ioctl to procfs" >&5 -$as_echo "uses ioctl to procfs" >&6; } - ;; - *) +printf "%s\n" "#define HAVE_GETHRVTIME_PROCFS_IOCTL 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: uses ioctl to procfs" >&5 +printf "%s\n" "uses ioctl to procfs" >&6; } + +else $as_nop + if test $erl_gethrvtime = cross; then erl_gethrvtime=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross" >&5 -$as_echo "cross" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result 'not working' guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result 'not working' guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross" >&5 +printf "%s\n" "cross" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result 'not working' guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result 'not working' guessed because of cross compilation" >&2;} else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not working" >&5 -$as_echo "not working" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not working" >&5 +printf "%s\n" "not working" >&6; } fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if clock_gettime can be used to get thread CPU time" >&5 -$as_echo_n "checking if clock_gettime can be used to get thread CPU time... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if clock_gettime can be used to get thread CPU time" >&5 +printf %s "checking if clock_gettime can be used to get thread CPU time... " >&6; } save_libs=$LIBS LIBS="-lrt" - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : case X$erl_xcomp_clock_gettime_cpu_time in X) erl_clock_gettime_cpu_time=cross;; @@ -21745,7 +24445,7 @@ $as_echo_n "checking if clock_gettime can be used to get thread CPU time... " >& *) as_fn_error $? "Bad erl_xcomp_clock_gettime_cpu_time value: $erl_xcomp_clock_gettime_cpu_time" "$LINENO" 5;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21773,9 +24473,10 @@ else } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : erl_clock_gettime_cpu_time=yes -else +else $as_nop erl_clock_gettime_cpu_time=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21783,34 +24484,35 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi LIBS=$save_libs - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $erl_clock_gettime_cpu_time" >&5 -$as_echo "$erl_clock_gettime_cpu_time" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $erl_clock_gettime_cpu_time" >&5 +printf "%s\n" "$erl_clock_gettime_cpu_time" >&6; } case $erl_clock_gettime_cpu_time in yes) -$as_echo "#define HAVE_CLOCK_GETTIME_CPU_TIME /**/" >>confdefs.h +printf "%s\n" "#define HAVE_CLOCK_GETTIME_CPU_TIME /**/" >>confdefs.h LIBRT=-lrt ;; cross) erl_clock_gettime_cpu_time=no - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result no guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result no guessed because of cross compilation" >&2;} ;; *) ;; esac - ;; -esac + +fi # Extract the first word of "m4", so it can be a program name with args. set dummy m4; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_M4+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_M4+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$M4"; then ac_cv_prog_M4="$M4" # Let the user override the test. else @@ -21818,11 +24520,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_M4="m4" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -21833,306 +24539,78 @@ fi fi M4=$ac_cv_prog_M4 if test -n "$M4"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5 -$as_echo "$M4" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $M4" >&5 +printf "%s\n" "$M4" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi JIT_ARCH= -if test ${enable_jit} != no; then + +if test ${enable_jit} != no +then : + case "$ARCH" in amd64) JIT_ARCH=x86 ;; + arm64) + case "$OPSYS" in + win32|darwin) + # These platforms have dedicated system calls for clearing + # instruction cache, and don't require us to manually issue + # instruction barriers on all threads. + JIT_ARCH=arm + ;; + *) + # We need to use `DC CVAU`, `IC IVAU`, and `ISB SY` to clear + # instruction cache. These have already been tested as part of + # ETHR_CHK_GCC_ATOMIC_OPS([]). + + if test "$ethr_arm_isb_sy_instr_val$ethr_arm_dc_cvau_instr_val$ethr_arm_ic_ivau_instr_val" = "111"; then + JIT_ARCH=arm + else + enable_jit=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: JIT disabled due to lack of cache-clearing instructions" >&5 +printf "%s\n" "$as_me: WARNING: JIT disabled due to lack of cache-clearing instructions" >&2;} + fi + ;; + esac + ;; *) if test ${enable_jit} = yes; then - as_fn_error $? "JIT only works on x86 64-bit" "$LINENO" 5 + as_fn_error $? "JIT only works on x86 64-bit and ARM 64-bit" "$LINENO" 5 else enable_jit=no - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: JIT disabled due to lack to support on $ARCH-$OPSYS" >&5 -$as_echo "$as_me: WARNING: JIT disabled due to lack to support on $ARCH-$OPSYS" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: JIT disabled due to lack to support on $ARCH-$OPSYS" >&5 +printf "%s\n" "$as_me: WARNING: JIT disabled due to lack to support on $ARCH-$OPSYS" >&2;} fi ;; esac - - if test ${enable_jit} != no; then - if test "$CXX" != false; then - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - old_CXXFLAGS=$CXXFLAGS - CXXFLAGS="$CXXFLAGS -std=c++17" - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -else - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=cpp + + if test ${enable_jit} != no +then : + + if test "$CXX" != false +then : + + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + old_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS -std=c++17" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #if __cplusplus < 201703L #error "Needs C++17 compiler" @@ -22141,27 +24619,29 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++17 support" >&5 -$as_echo_n "checking for C++17 support... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +if ac_fn_cxx_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++17 support" >&5 +printf %s "checking for C++17 support... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } HAVE_CXX17=true -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++17 support" >&5 -$as_echo_n "checking for C++17 support... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++17 support" >&5 +printf %s "checking for C++17 support... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } HAVE_CXX17=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - fi + +fi if test "$CXX" = false -o "$HAVE_CXX17" = false; then if test ${enable_jit} = yes; then as_fn_error $? "JIT needs a C++ compiler with C++17 support" "$LINENO" 5 @@ -22171,39 +24651,48 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu JIT disabled due to lack of compiler with C++17 support EOF - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: JIT disable due to lack of C++ compiler with C++17 support" >&5 -$as_echo "$as_me: WARNING: JIT disable due to lack of C++ compiler with C++17 support" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: JIT disable due to lack of C++ compiler with C++17 support" >&5 +printf "%s\n" "$as_me: WARNING: JIT disable due to lack of C++ compiler with C++17 support" >&2;} fi fi - fi + +fi if test ${enable_jit} != no; then enable_jit=yes fi + fi -if test ${enable_jit} != no; then - case $host_os in - openbsd*) +if test ${enable_jit} != no +then : + + case $host_os in #( + openbsd*) : + # Whenever the kernel is entered (page faults, system calls, etc), # OpenBSD checks whether the stack pointer is in an area allocated with # MAP_STACK, so we can't use the native stack for Erlang code. # # https://undeadly.org/cgi?action=article;sid=20180310000858 - enable_native_stack=no;; - win32*) + enable_native_stack=no + ;; #( + win32*) : + # Windows never messes with the stack, so it's safe by default. - enable_native_stack=yes;; - *) + enable_native_stack=yes + ;; #( + *) : + # Use the native stack if we can safely redirect OS signals to a # different stack. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for safe signal delivery" >&5 -$as_echo_n "checking for safe signal delivery... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for safe signal delivery" >&5 +printf %s "checking for safe signal delivery... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) #define __DARWIN__ 1 @@ -22215,30 +24704,50 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } enable_native_stack=yes -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, disabling native stack in JIT" >&5 -$as_echo "no, disabling native stack in JIT" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, disabling native stack in JIT" >&5 +printf "%s\n" "no, disabling native stack in JIT" >&6; } enable_native_stack=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext;; - esac +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac - if test X${enable_native_stack} = Xyes; then + case "$JIT_ARCH" in + x86) + if test X${enable_native_stack} = Xyes; then -$as_echo "#define NATIVE_ERLANG_STACK /**/" >>confdefs.h +printf "%s\n" "#define NATIVE_ERLANG_STACK /**/" >>confdefs.h + + fi + ;; + arm) + # ARM JIT doesn't support native stack due to its 16-byte alignment + # requirement. + enable_native_stack=no + ;; + *) + ;; + esac - fi fi case $OPSYS in linux*) + if test X${enable_native_stack} = Xyes; then + +printf "%s\n" "#define ERLANG_FRAME_POINTERS /**/" >>confdefs.h + + fi -$as_echo "#define HAVE_LINUX_PERF_SUPPORT 1" >>confdefs.h + +printf "%s\n" "#define HAVE_LINUX_PERF_SUPPORT 1" >>confdefs.h ;; *) @@ -22246,19 +24755,19 @@ $as_echo "#define HAVE_LINUX_PERF_SUPPORT 1" >>confdefs.h esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to redefine FD_SETSIZE" >&5 -$as_echo_n "checking whether to redefine FD_SETSIZE... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to redefine FD_SETSIZE" >&5 +printf %s "checking whether to redefine FD_SETSIZE... " >&6; } case $host_os in bsdi*) -$as_echo "#define REDEFINE_FD_SETSIZE /**/" >>confdefs.h +printf "%s\n" "#define REDEFINE_FD_SETSIZE /**/" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; esac @@ -22283,15 +24792,20 @@ fi # # Check for working poll(). # -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working poll()" >&5 -$as_echo_n "checking for working poll()... " >&6; } -if test "x$ac_cv_header_poll_h" != "xyes" -o "x$ac_cv_func_poll" != "xyes"; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working poll()" >&5 +printf %s "checking for working poll()... " >&6; } +if test "x$ac_cv_header_poll_h" != "xyes" -o "x$ac_cv_func_poll" != "xyes" +then : + poll_works=no -else -if test "$cross_compiling" = yes; then : +else $as_nop + + +if test "$cross_compiling" = yes +then : case X$erl_xcomp_poll in X) poll_works=cross;; @@ -22299,7 +24813,7 @@ case X$erl_xcomp_poll in *) as_fn_error $? "Bad erl_xcomp_poll value: $erl_xcomp_poll" "$LINENO" 5;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22323,9 +24837,10 @@ main() } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : poll_works=yes -else +else $as_nop poll_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -22333,6 +24848,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi + fi case $poll_works-$host_os in @@ -22342,30 +24858,30 @@ case $poll_works-$host_os in # be used by erts). # -$as_echo "#define USE_SELECT 1" >>confdefs.h +printf "%s\n" "#define USE_SELECT 1" >>confdefs.h if test $poll_works = cross; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross" >&5 -$as_echo "cross" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed based on OS ($host_os) because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result no guessed based on OS ($host_os) because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross" >&5 +printf "%s\n" "cross" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed based on OS ($host_os) because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result no guessed based on OS ($host_os) because of cross compilation" >&2;} else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; non-existing, broken, or based on select()" >&5 -$as_echo "no; non-existing, broken, or based on select()" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no; non-existing, broken, or based on select()" >&5 +printf "%s\n" "no; non-existing, broken, or based on select()" >&6; } fi poll_works=no;; yes-*|cross-*) -$as_echo "#define ERTS_USE_POLL 1" >>confdefs.h +printf "%s\n" "#define ERTS_USE_POLL 1" >>confdefs.h if test $poll_works = cross; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross" >&5 -$as_echo "cross" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed based on OS ($host_os) because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed based on OS ($host_os) because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cross" >&5 +printf "%s\n" "cross" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed based on OS ($host_os) because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed based on OS ($host_os) because of cross compilation" >&2;} else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi poll_works=yes;; esac @@ -22376,33 +24892,35 @@ esac if test $have_kernel_poll = kqueue; then ## Some OS X kernel version seems to have bugs in them with regards to kqueue ## Disable kernel poll on those versions - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether host os has known kqueue bugs" >&5 -$as_echo_n "checking whether host os has known kqueue bugs... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether host os has known kqueue bugs" >&5 +printf %s "checking whether host os has known kqueue bugs... " >&6; } case $host_os in # Any OS X version < 16 has known problems with using kqueue # so we don't use it there. See erl_poll.c for details. darwin[0-9].*|darwin1[0-5].*) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, disabling kernel poll" >&5 -$as_echo "yes, disabling kernel poll" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes, disabling kernel poll" >&5 +printf "%s\n" "yes, disabling kernel poll" >&6; } have_kernel_poll=no ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; esac fi # # If epoll() found, check that it is level triggered. # -if test $have_kernel_poll = epoll; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether epoll is level triggered" >&5 -$as_echo_n "checking whether epoll is level triggered... " >&6; } +if test $have_kernel_poll = epoll +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether epoll is level triggered" >&5 +printf %s "checking whether epoll is level triggered... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifdef EPOLLET @@ -22419,49 +24937,51 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : level_triggered_epoll=yes -else +else $as_nop level_triggered_epoll=no have_kernel_poll=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $level_triggered_epoll" >&5 -$as_echo "$level_triggered_epoll" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $level_triggered_epoll" >&5 +printf "%s\n" "$level_triggered_epoll" >&6; } + fi # # Check if we should enable kernel poll support # -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel poll support should be enabled" >&5 -$as_echo_n "checking whether kernel poll support should be enabled... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether kernel poll support should be enabled" >&5 +printf %s "checking whether kernel poll support should be enabled... " >&6; } ERTS_ENABLE_KERNEL_POLL=no ERTS_BUILD_FALLBACK_POLL=no case $enable_kernel_poll-$have_kernel_poll in no-*) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; disabled by user" >&5 -$as_echo "no; disabled by user" >&6; };; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no; disabled by user" >&5 +printf "%s\n" "no; disabled by user" >&6; };; yes-no) as_fn_error $? "no; kernel poll support requested but not found" "$LINENO" 5;; *-no) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; };; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; };; *) case $have_kernel_poll in epoll) -$as_echo "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h ERTS_BUILD_FALLBACK_POLL=yes ;; /dev/poll) -$as_echo "#define HAVE_SYS_DEVPOLL_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYS_DEVPOLL_H 1" >>confdefs.h ;; kqueue) -$as_echo "#define HAVE_SYS_EVENT_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h ERTS_BUILD_FALLBACK_POLL=yes ;; @@ -22470,16 +24990,17 @@ $as_echo "#define HAVE_SYS_EVENT_H 1" >>confdefs.h esac ERTS_ENABLE_KERNEL_POLL=yes -$as_echo "#define ERTS_ENABLE_KERNEL_POLL 1" >>confdefs.h +printf "%s\n" "#define ERTS_ENABLE_KERNEL_POLL 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; $have_kernel_poll" >&5 -$as_echo "yes; $have_kernel_poll" >&6; };; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes; $have_kernel_poll" >&5 +printf "%s\n" "yes; $have_kernel_poll" >&6; };; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether putenv() stores a copy of the key-value pair" >&5 -$as_echo_n "checking whether putenv() stores a copy of the key-value pair... " >&6; } -if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether putenv() stores a copy of the key-value pair" >&5 +printf %s "checking whether putenv() stores a copy of the key-value pair... " >&6; } +if test "$cross_compiling" = yes +then : case X$erl_xcomp_putenv_copy in X) copying_putenv=cross;; @@ -22487,7 +25008,7 @@ case X$erl_xcomp_putenv_copy in *) as_fn_error $? "Bad erl_xcomp_putenv_copy value: $erl_xcomp_putenv_copy" "$LINENO" 5;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22522,9 +25043,10 @@ int main(void) { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : copying_putenv=yes -else +else $as_nop copying_putenv=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -22532,32 +25054,33 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $copying_putenv" >&5 -$as_echo "$copying_putenv" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $copying_putenv" >&5 +printf "%s\n" "$copying_putenv" >&6; } case $copying_putenv in yes) -$as_echo "#define HAVE_COPYING_PUTENV 1" >>confdefs.h +printf "%s\n" "#define HAVE_COPYING_PUTENV 1" >>confdefs.h ;; cross) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result no guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result no guessed because of cross compilation" >&2;};; *) ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a compiler that handles jumptables" >&5 -$as_echo_n "checking for a compiler that handles jumptables... " >&6; } -if ${ac_cv_prog_emu_cc+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a compiler that handles jumptables" >&5 +printf %s "checking for a compiler that handles jumptables... " >&6; } +if test ${ac_cv_prog_emu_cc+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #if defined(__clang_major__) && __clang_major__ >= 3 @@ -22583,12 +25106,13 @@ lbl2: return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_emu_cc="$CC" -else +else $as_nop ac_cv_prog_emu_cc=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test "$ac_cv_prog_emu_cc" = no; then for ac_progname in emu_cc.sh gcc-4.2 gcc; do @@ -22608,7 +25132,9 @@ if test "$ac_cv_prog_emu_cc" = no; then done fi -if test "$ac_cv_prog_emu_cc" != no; then +if test "$ac_cv_prog_emu_cc" != no +then : + save_CC="$CC" save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -22619,7 +25145,7 @@ if test "$ac_cv_prog_emu_cc" != no; then /* end confdefs.h. */ int -main () +main (void) { #if defined(__clang_major__) && __clang_major__ >= 3 @@ -22645,23 +25171,25 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_emu_cc="$CC" -else +else $as_nop ac_cv_prog_emu_cc=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CC=$save_CC CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS + fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_emu_cc" >&5 -$as_echo "$ac_cv_prog_emu_cc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_emu_cc" >&5 +printf "%s\n" "$ac_cv_prog_emu_cc" >&6; } if test "$ac_cv_prog_emu_cc" = no; then -$as_echo "#define NO_JUMP_TABLE /**/" >>confdefs.h +printf "%s\n" "#define NO_JUMP_TABLE /**/" >>confdefs.h EMU_CC="$CC" else @@ -22670,16 +25198,18 @@ fi -case $DYNAMIC_TRACE_FRAMEWORK in - dtrace|systemtap) +case $DYNAMIC_TRACE_FRAMEWORK in #( + dtrace|systemtap) : + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dtrace", so it can be a program name with args. set dummy ${ac_tool_prefix}dtrace; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DTRACE+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DTRACE+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$DTRACE"; then ac_cv_prog_DTRACE="$DTRACE" # Let the user override the test. else @@ -22687,11 +25217,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DTRACE="${ac_tool_prefix}dtrace" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -22702,11 +25236,11 @@ fi fi DTRACE=$ac_cv_prog_DTRACE if test -n "$DTRACE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 -$as_echo "$DTRACE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +printf "%s\n" "$DTRACE" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -22715,11 +25249,12 @@ if test -z "$ac_cv_prog_DTRACE"; then ac_ct_DTRACE=$DTRACE # Extract the first word of "dtrace", so it can be a program name with args. set dummy dtrace; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DTRACE+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DTRACE+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_DTRACE"; then ac_cv_prog_ac_ct_DTRACE="$ac_ct_DTRACE" # Let the user override the test. else @@ -22727,11 +25262,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DTRACE="dtrace" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -22742,11 +25281,11 @@ fi fi ac_ct_DTRACE=$ac_cv_prog_ac_ct_DTRACE if test -n "$ac_ct_DTRACE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DTRACE" >&5 -$as_echo "$ac_ct_DTRACE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DTRACE" >&5 +printf "%s\n" "$ac_ct_DTRACE" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DTRACE" = x; then @@ -22754,8 +25293,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DTRACE=$ac_ct_DTRACE @@ -22766,13 +25305,18 @@ fi test "$DTRACE" = "none" && as_fn_error $? "No dtrace utility found." "$LINENO" 5; enable_lttng_test=no - enable_dtrace_test=yes;; - lttng) + enable_dtrace_test=yes + ;; #( + lttng) : + enable_lttng_test=yes - enable_dtrace_test=no;; - *) + enable_dtrace_test=no + ;; #( + *) : + enable_lttng_test=no - enable_dtrace_test=no;; + enable_dtrace_test=no + ;; esac @@ -22797,43 +25341,43 @@ case $OPSYS in : # Nothing to do ;; esac -if test "$enable_dtrace_test" = "yes" ; then - if test "$DTRACE" = "dtrace" ; then - for ac_header in sys/sdt.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/sdt.h" "ac_cv_header_sys_sdt_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sdt_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_SDT_H 1 -_ACEOF +if test "$enable_dtrace_test" = "yes" +then : -fi + if test "$DTRACE" = "dtrace" +then : -done + ac_fn_c_check_header_compile "$LINENO" "sys/sdt.h" "ac_cv_header_sys_sdt_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sdt_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SDT_H 1" >>confdefs.h + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 1-stage DTrace precompilation" >&5 -$as_echo_n "checking for 1-stage DTrace precompilation... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 1-stage DTrace precompilation" >&5 +printf %s "checking for 1-stage DTrace precompilation... " >&6; } # The OS X version of dtrace prints a spurious line here. if ! dtrace -h $DTRACE_CPP -Iemulator/beam -o ./foo-dtrace.h -s emulator/beam/erlang_dtrace.d; then as_fn_error $? "Could not precompile erlang_dtrace.d: dtrace -h failed" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 2-stage DTrace precompilation" >&5 -$as_echo_n "checking for 2-stage DTrace precompilation... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 2-stage DTrace precompilation" >&5 +printf %s "checking for 2-stage DTrace precompilation... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "foo-dtrace.h" int -main () +main (void) { ERLANG_DIST_PORT_BUSY_ENABLED(); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : rm -f $DTRACE_2STEP_TEST dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&5 if test -f $DTRACE_2STEP_TEST; then @@ -22841,14 +25385,15 @@ if ac_fn_c_try_compile "$LINENO"; then : DTRACE_ENABLED_2STEP=yes fi fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext rm -f foo-dtrace.h - if test "x$DTRACE_ENABLED_2STEP" = "xyes"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + if test "x$DTRACE_ENABLED_2STEP" = "xyes" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi DTRACE_ENABLED=yes @@ -22863,38 +25408,34 @@ fi LIBS="$LIBS -ldtrace" ;; esac - else + +else $as_nop + as_fn_error $? "Dtrace preprocessing test failed." "$LINENO" 5 - fi -fi -if test "$enable_lttng_test" = "yes" ; then - for ac_header in lttng/tracepoint.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "lttng/tracepoint.h" "ac_cv_header_lttng_tracepoint_h" "$ac_includes_default" -if test "x$ac_cv_header_lttng_tracepoint_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LTTNG_TRACEPOINT_H 1 -_ACEOF +fi fi -done +if test "$enable_lttng_test" = "yes" +then : - for ac_header in lttng/tracepoint-event.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "lttng/tracepoint-event.h" "ac_cv_header_lttng_tracepoint_event_h" "$ac_includes_default" -if test "x$ac_cv_header_lttng_tracepoint_event_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LTTNG_TRACEPOINT_EVENT_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "lttng/tracepoint.h" "ac_cv_header_lttng_tracepoint_h" "$ac_includes_default" +if test "x$ac_cv_header_lttng_tracepoint_h" = xyes +then : + printf "%s\n" "#define HAVE_LTTNG_TRACEPOINT_H 1" >>confdefs.h fi -done + ac_fn_c_check_header_compile "$LINENO" "lttng/tracepoint-event.h" "ac_cv_header_lttng_tracepoint_event_h" "$ac_includes_default" +if test "x$ac_cv_header_lttng_tracepoint_event_h" = xyes +then : + printf "%s\n" "#define HAVE_LTTNG_TRACEPOINT_EVENT_H 1" >>confdefs.h + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tracepoint_enabled in lttng/tracepoint.h" >&5 -$as_echo_n "checking for tracepoint_enabled in lttng/tracepoint.h... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tracepoint_enabled in lttng/tracepoint.h" >&5 +printf %s "checking for tracepoint_enabled in lttng/tracepoint.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -22907,20 +25448,21 @@ $as_echo_n "checking for tracepoint_enabled in lttng/tracepoint.h... " >&6; } #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE int -main () +main (void) { if(tracepoint_enabled(org_erlang_otp,dummy)) do {} while(0) ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else +if ac_fn_c_try_compile "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop as_fn_error $? "no (available in lttng-ust v2.7)" "$LINENO" 5 fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \ -a "x$ac_cv_header_lttng_tracepoint_event_h" = "xyes"; then # No straight forward way to test for liblttng-ust when no public symbol exists, @@ -22929,6 +25471,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else as_fn_error $? "No LTTng support found." "$LINENO" 5 fi + fi @@ -22938,11 +25481,12 @@ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 -$as_echo_n "checking for kstat_open in -lkstat... " >&6; } -if ${ac_cv_lib_kstat_kstat_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 +printf %s "checking for kstat_open in -lkstat... " >&6; } +if test ${ac_cv_lib_kstat_kstat_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lkstat $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22951,30 +25495,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char kstat_open (); int -main () +main (void) { return kstat_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_kstat_kstat_open=yes -else +else $as_nop ac_cv_lib_kstat_kstat_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 -$as_echo "$ac_cv_lib_kstat_kstat_open" >&6; } -if test "x$ac_cv_lib_kstat_kstat_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 +printf "%s\n" "$ac_cv_lib_kstat_kstat_open" >&6; } +if test "x$ac_cv_lib_kstat_kstat_open" = xyes +then : use_cpu_sup=yes CPU_SUP_LIBS="$CPU_SUP_LIBS -lkstat" @@ -22982,11 +25525,12 @@ if test "x$ac_cv_lib_kstat_kstat_open" = xyes; then : fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kvm_open in -lkvm" >&5 -$as_echo_n "checking for kvm_open in -lkvm... " >&6; } -if ${ac_cv_lib_kvm_kvm_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for kvm_open in -lkvm" >&5 +printf %s "checking for kvm_open in -lkvm... " >&6; } +if test ${ac_cv_lib_kvm_kvm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lkvm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22995,30 +25539,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char kvm_open (); int -main () +main (void) { return kvm_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_kvm_kvm_open=yes -else +else $as_nop ac_cv_lib_kvm_kvm_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kvm_kvm_open" >&5 -$as_echo "$ac_cv_lib_kvm_kvm_open" >&6; } -if test "x$ac_cv_lib_kvm_kvm_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kvm_kvm_open" >&5 +printf "%s\n" "$ac_cv_lib_kvm_kvm_open" >&6; } +if test "x$ac_cv_lib_kvm_kvm_open" = xyes +then : use_cpu_sup=yes CPU_SUP_LIBS="$CPU_SUP_LIBS -lkvm" @@ -23045,7 +25588,8 @@ fi # Check whether --with-javac was given. -if test "${with_javac+set}" = set; then : +if test ${with_javac+y} +then : withval=$with_javac; fi @@ -23078,11 +25622,12 @@ for ac_prog in $check_javac do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_JAVAC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_JAVAC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$JAVAC"; then ac_cv_prog_JAVAC="$JAVAC" # Let the user override the test. else @@ -23090,11 +25635,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_JAVAC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -23105,23 +25654,26 @@ fi fi JAVAC=$ac_cv_prog_JAVAC if test -n "$JAVAC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 -$as_echo "$JAVAC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 +printf "%s\n" "$JAVAC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi test -n "$JAVAC" && break done -if test -n "$JAVAC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for JDK version 1.6" >&5 -$as_echo_n "checking for JDK version 1.6... " >&6; } -if ${ac_cv_prog_javac_ver_1_6+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test -n "$JAVAC" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for JDK version 1.6" >&5 +printf %s "checking for JDK version 1.6... " >&6; } +if test ${ac_cv_prog_javac_ver_1_6+y} +then : + printf %s "(cached) " >&6 +else $as_nop java_link='$JAVAC conftest.java 1>&5' cat > conftest.java <&5 (eval $java_link) 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest.class; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest.class +then : + rm -rf conftest* ac_cv_prog_javac_ver_1_6=yes -else + + +else $as_nop + echo "configure: failed program was:" 1>&5 cat conftest.java 1>&5 echo "configure: PATH was $PATH" 1>&5 rm -rf conftest* ac_cv_prog_javac_ver_1_6=no + + fi rm -f conftest* fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_javac_ver_1_6" >&5 -$as_echo "$ac_cv_prog_javac_ver_1_6" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_javac_ver_1_6" >&5 +printf "%s\n" "$ac_cv_prog_javac_ver_1_6" >&6; } if test $ac_cv_prog_javac_ver_1_6 = no; then unset -v JAVAC fi + fi if test -z "$JAVAC"; then @@ -23157,8 +25717,8 @@ if test -z "$JAVAC"; then as_fn_error $? "No java compiler found in PATH (checked for $check_javac)" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find any usable java compiler, will skip: jinterface" >&5 -$as_echo "$as_me: WARNING: Could not find any usable java compiler, will skip: jinterface" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Could not find any usable java compiler, will skip: jinterface" >&5 +printf "%s\n" "$as_me: WARNING: Could not find any usable java compiler, will skip: jinterface" >&2;} for a in $need_java ; do echo "No Java compiler found" > $ERL_TOP/lib/$a/SKIP @@ -23167,115 +25727,6 @@ fi fi # end - try to find javac - -if test -n "$ac_tool_prefix"; then - for ac_prog in $CCC c++ g++ CC cxx cc++ cl - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in $CCC c++ g++ CC cxx cc++ cl -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - -# Remove SKIP file from previous run -rm -f $ERL_TOP/lib/orber/SKIP - -if test "$CXX" = false; then - echo "No C++ compiler found" > $ERL_TOP/lib/orber/SKIP -fi - CFLAGS="$CFLAGS $CPPFLAGS" # @@ -23302,44 +25753,21 @@ fi -cat >>confdefs.h <<_ACEOF -#define ERTS_EMU_CMDLINE_FLAGS "$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS" -_ACEOF - - - - - -erts=${erl_top}/erts +printf "%s\n" "#define ERTS_EMU_CMDLINE_FLAGS \"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS\"" >>confdefs.h -erts_dirs=" - $erts/obj $erts/obj.debug - $erts/obj/$host - $erts/obj.debug/$host -" -for d in ${erl_top}/bin ${erl_top}/bin/$host $erts_dirs ; -do - if test ! -d $d; then - mkdir -p 1>/dev/null 2>&1 $d - fi -done -for ac_func in log2 -do : - ac_fn_c_check_func "$LINENO" "log2" "ac_cv_func_log2" -if test "x$ac_cv_func_log2" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LOG2 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "log2" "ac_cv_func_log2" +if test "x$ac_cv_func_log2" = xyes +then : + printf "%s\n" "#define HAVE_LOG2 1" >>confdefs.h fi -done @@ -23349,7 +25777,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") @@ -23359,12 +25787,13 @@ _Pragma("GCC diagnostic push") return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -$as_echo "#define HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$saved_CFLAGS" @@ -23374,19 +25803,31 @@ if test "x$GCC" = xyes; then fi +# Check whether --enable-deterministic-build was given. +if test ${enable_deterministic_build+y} +then : + enableval=$enable_deterministic_build; case "$enableval" in + no) ERL_DETERMINISTIC=no ;; + *) ERL_DETERMINISTIC=yes ;; + esac +else $as_nop + ERL_DETERMINISTIC=no +fi + -# Check whether --enable-sanitizers was given. -if test "${enable_sanitizers+set}" = set; then : - enableval=$enable_sanitizers; -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=address,undefined" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS for -O switch" >&5 +printf %s "checking CFLAGS for -O switch... " >&6; } +no_opt_CFLAGS=$(echo " $CFLAGS" | sed 's/ -O[^ ]*/ /g') +if test "X $CFLAGS" = "X$no_opt_CFLAGS"; then + as_fn_error $? " + CFLAGS must contain a -O flag. If you need to edit the CFLAGS you probably + also want to add the default CFLAGS. The default CFLAGS are \"-O2 -g\". + If you want to build ERTS without any optimization, pass -O0 to CFLAGS." "$LINENO" 5 fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +DEBUG_CFLAGS="-g -O0 $no_opt_CFLAGS" @@ -23396,7 +25837,7 @@ ac_config_files="$ac_config_files emulator/$host/Makefile:emulator/Makefile.in e ac_config_files="$ac_config_files ../make/make_emakefile:../make/make_emakefile.in" -ac_config_files="$ac_config_files ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in" +ac_config_files="$ac_config_files ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in" ac_config_files="$ac_config_files ../make/install_dir_data.sh:../make/install_dir_data.sh.in" @@ -23429,8 +25870,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -23460,15 +25901,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -23482,8 +25923,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -23500,7 +25941,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -23518,8 +25959,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -23542,14 +25983,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -23559,46 +26002,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -23607,13 +26050,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -23622,8 +26058,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -23635,30 +26075,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -23671,13 +26091,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -23704,18 +26125,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -23727,12 +26150,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -23763,7 +26187,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -23785,6 +26209,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -23798,6 +26226,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -23839,7 +26273,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -23848,7 +26282,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -23911,7 +26345,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -23969,14 +26403,16 @@ $config_headers Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -24014,15 +26450,15 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" @@ -24030,7 +26466,7 @@ do --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; @@ -24039,7 +26475,7 @@ do as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -24067,7 +26503,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -24081,7 +26517,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -24107,7 +26543,6 @@ do "../make/make_emakefile") CONFIG_FILES="$CONFIG_FILES ../make/make_emakefile:../make/make_emakefile.in" ;; "../lib/os_mon/c_src/$host/Makefile") CONFIG_FILES="$CONFIG_FILES ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in" ;; "../lib/runtime_tools/c_src/$host/Makefile") CONFIG_FILES="$CONFIG_FILES ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in" ;; - "../lib/tools/c_src/$host/Makefile") CONFIG_FILES="$CONFIG_FILES ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in" ;; "../make/install_dir_data.sh") CONFIG_FILES="$CONFIG_FILES ../make/install_dir_data.sh:../make/install_dir_data.sh.in" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -24120,8 +26555,8 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree @@ -24457,7 +26892,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -24465,17 +26900,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -24492,7 +26927,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -24516,9 +26951,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -24575,8 +27010,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -24619,9 +27054,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -24637,20 +27072,20 @@ which seems to be undefined. Please make sure it is defined" >&2;} # if test x"$ac_file" != x-; then { - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -24697,7 +27132,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/erts/configure.ac b/erts/configure.ac new file mode 100644 index 000000000000..540cc4b3cba4 --- /dev/null +++ b/erts/configure.ac @@ -0,0 +1,3629 @@ +dnl Process this file with autoconf to produce a configure script. -*-Autoconf-*- + +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1997-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% + +dnl The string "FIXME convbreak" means that there is a break of +dnl autoconf convention that should be cleaned up. + +AC_INIT +AC_CONFIG_SRCDIR([emulator/beam/erl_process.c]) +AC_PREREQ([2.71]) + +m4_include([otp.m4]) + +LM_PRECIOUS_VARS + +dnl We check if -Werror was given on command line and if so +dnl we disable it for the configure and only use it when +dnl actually building erts +no_werror_CFLAGS=$(echo " $CFLAGS " | sed 's/ -Werror / /g') +if test "X $CFLAGS " != "X$no_werror_CFLAGS"; then + CFLAGS="$no_werror_CFLAGS" + WERRORFLAGS=-Werror +fi + +dnl How to set srcdir absolute is taken from the GNU Emacs distribution +#### Make srcdir absolute, if it isn't already. It's important to +#### avoid running the path through pwd unnecessary, since pwd can +#### give you automounter prefixes, which can go away. +case "${srcdir}" in + /* ) ;; + . ) + ## We may be able to use the $PWD environment variable to make this + ## absolute. But sometimes PWD is inaccurate. + ## Make sure CDPATH doesn't affect cd (in case PWD is relative). + CDPATH= + if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; + then + srcdir="$PWD" + else + srcdir="`(cd ${srcdir}; pwd)`" + fi + ;; + * ) srcdir="`(cd ${srcdir}; pwd)`" ;; +esac + +## Now, make sure that ERL_TOP is set and is the same as srcdir +## +if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then + AC_MSG_ERROR(You need to set the environment variable ERL_TOP!) +fi +if test x"${ERL_TOP}/erts" != x"$srcdir"; then + AC_MSG_ERROR([You need to run configure with argument --srcdir=${ERL_TOP}/erts]) +fi +erl_top=${ERL_TOP} + +# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# echo X +# echo "X srcdir = $srcdir" +# echo "X ERL_TOP = $ERL_TOP" +# echo X +# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +AC_CONFIG_AUX_DIR([${ERL_TOP}/make/autoconf]) + +dnl ---------------------------------------------------------------------- +dnl Figure out what system we are running on. +dnl ---------------------------------------------------------------------- + +ERL_CANONICAL_SYSTEM_TYPE + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILING=yes +else + CROSS_COMPILING=no +fi +AC_SUBST(CROSS_COMPILING) + +ERL_XCOMP_SYSROOT_INIT + +AC_SEARCH_LIBS([strerror],[cposix]) + +AC_CONFIG_HEADERS([$host/config.h:config.h.in include/internal/$host/ethread_header_config.h:include/internal/ethread_header_config.h.in include/$host/erl_int_sizes_config.h:include/erl_int_sizes_config.h.in]) +dnl ---------------------------------------------------------------------- +dnl Optional features. +dnl ---------------------------------------------------------------------- +ENABLE_ALLOC_TYPE_VARS= +AC_SUBST(ENABLE_ALLOC_TYPE_VARS) + +AC_ARG_ENABLE(bootstrap-only, +AS_HELP_STRING([--enable-bootstrap-only], + [enable bootstrap only configuration]), +[ if test "X$enableval" = "Xyes"; then + # Disable stuff not necessary in a bootstrap only system in order + # to speed up things by reducing the amount of stuff needing to be + # built... + with_termcap=no + with_ssl=no + with_ssl_zlib=no + enable_jit=no + enable_sctp=no + fi +]) + +AC_ARG_ENABLE(dirty-schedulers-test, +AS_HELP_STRING([--enable-dirty-schedulers-test], [enable dirty scheduler test (for debugging purposes)]), +[ case "$enableval" in + yes) enable_dirty_schedulers_test=yes ;; + *) enable_dirty_schedulers_test=no ;; + esac ], enable_dirty_schedulers_test=no) + +AC_ARG_ENABLE(smp-require-native-atomics, + AS_HELP_STRING([--disable-smp-require-native-atomics], + [disable the SMP requirement of a native atomic implementation]), +[ case "$enableval" in + no) smp_require_native_atomics=no ;; + *) smp_require_native_atomics=yes ;; + esac ], smp_require_native_atomics=yes) + +AC_ARG_WITH(termcap, +AS_HELP_STRING([--with-termcap], [use termcap (default)]) +AS_HELP_STRING([--without-termcap], + [do not use any termcap libraries (ncurses,curses,termcap,termlib)]), +[], +[with_termcap=yes]) + +AC_ARG_ENABLE(lock-checking, +AS_HELP_STRING([--enable-lock-checking], [enable lock checking]), +[ case "$enableval" in + no) enable_lock_check=no ;; + *) enable_lock_check=yes ;; + esac +], + enable_lock_check=no) + +AC_ARG_ENABLE(lock-counter, +AS_HELP_STRING([--enable-lock-counter], [enable lock counters]), +[ case "$enableval" in + no) enable_lock_count=no ;; + *) enable_lock_count=yes ;; + esac ], enable_lock_count=no) + +AC_ARG_ENABLE(kernel-poll, +AS_HELP_STRING([--enable-kernel-poll], [enable kernel poll support]) +AS_HELP_STRING([--disable-kernel-poll], [disable kernel poll support]), +[ case "$enableval" in + no) enable_kernel_poll=no ;; + *) enable_kernel_poll=yes ;; + esac ], enable_kernel_poll=unknown) + + +AC_ARG_ENABLE(sctp, +AS_HELP_STRING([--enable-sctp], [enable sctp support (default) to on demand load the SCTP library in runtime if needed]) +AS_HELP_STRING([--enable-sctp=lib], [enable sctp support to link against the SCTP library]) +AS_HELP_STRING([--disable-sctp], [disable sctp support]), +[ case "x$enableval" in + xno|xyes|xlib|x) + ;; + x*) + AC_MSG_ERROR("invalid value --enable-sctp=$enableval") + ;; + esac ]) + +AC_ARG_ENABLE(jit, +AS_HELP_STRING([--enable-jit], [enable JIT support]) +AS_HELP_STRING([--disable-jit], [disable JIT support]), + [ case "$enableval" in + no) enable_jit=no ;; + *) enable_jit=yes ;; + esac +],enable_jit=auto) + +AC_ARG_ENABLE(m64-build, +AS_HELP_STRING([--enable-m64-build], + [build 64bit binaries using the -m64 flag to (g)cc]), +[ case "$enableval" in + no) enable_m64_build=no ;; + *) enable_m64_build=yes ;; + esac +],enable_m64_build=no) + +AC_ARG_ENABLE(m32-build, +AS_HELP_STRING([--enable-m32-build], + [build 32bit binaries using the -m32 flag to (g)cc]), +[ case "$enableval" in + no) enable_m32_build=no ;; + *) enable_m32_build=yes ;; + esac +],enable_m32_build=no) + +AC_ARG_WITH(dynamic-trace, +AS_HELP_STRING([--with-dynamic-trace={dtrace|lttng|systemtap}], + [specify use of dynamic trace framework, dtrace, lttng or systemtap]) +AS_HELP_STRING([--without-dynamic-trace], + [don't enable any dynamic tracing (default)])) + +if test X"$with_dynamic_trace" = X""; then + with_dynamic_trace=no +fi + +case "$with_dynamic_trace" in + no) DYNAMIC_TRACE_FRAMEWORK=;; + lttng) + AC_DEFINE(USE_LTTNG,[1], + [Define if you want to use lttng for dynamic tracing]) + DYNAMIC_TRACE_FRAMEWORK=lttng;; + dtrace) + AC_DEFINE(USE_DTRACE,[1], + [Define if you want to use dtrace for dynamic tracing]) + DYNAMIC_TRACE_FRAMEWORK=dtrace;; + systemtap) + AC_DEFINE(USE_SYSTEMTAP,[1], + [Define if you want to use systemtap for dynamic tracing]) + DYNAMIC_TRACE_FRAMEWORK=systemtap;; + *) + AC_MSG_ERROR(Unknown dynamic tracing framework specified with --with-dynamic-trace!);; +esac + +if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + AC_DEFINE(USE_DYNAMIC_TRACE,[1], + [Define if you want to use dynamic tracing]) +fi + +AC_ARG_ENABLE(vm-probes, +AS_HELP_STRING([--enable-vm-probes], + [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)]), + [ case "$enableval" in + no) use_vm_probes=no ;; + *) + if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + use_vm_probes=yes ; + else + AC_MSG_ERROR(Can not enable VM probes without any dynamic tracing framework!); + fi;; + esac ], if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + use_vm_probes=yes ; + else + use_vm_probes=no + fi) + +AC_SUBST(USE_VM_PROBES) +if test X"$DYNAMIC_TRACE_FRAMEWORK" != X"lttng"; then + if test X"$use_vm_probes" = X"yes"; then + USE_VM_PROBES=yes + AC_DEFINE(USE_VM_PROBES,[1], + [Define to enable VM dynamic trace probes]) + fi +fi + +AC_ARG_WITH(assumed-cache-line-size, +AS_HELP_STRING([--with-assumed-cache-line-size=SIZE], + [specify assumed cache line size in bytes (valid values are powers of two between and including 16 and 8192; default is 64)])) + +dnl Require the assumed cache-line size to be a power of two between 16 and 8192 +case "$with_assumed_cache_line_size" in + ""|no|yes) + with_assumed_cache_line_size=64;; + 16|32|64|128|256|512|1024|2048|4096|8192) + ;; + *) + AC_MSG_ERROR([Invalid assumed cache-line size of $with_assumed_cache_line_size bytes]) + ;; +esac + +AC_DEFINE_UNQUOTED(ASSUMED_CACHE_LINE_SIZE, + $with_assumed_cache_line_size, + [Assumed cache-line size (in bytes)]) + +AC_ARG_ENABLE(systemd, +AS_HELP_STRING([--enable-systemd], [enable systemd support in epmd]), +[], +[enable_systemd=no]) + +AC_ARG_WITH(microstate-accounting, +AS_HELP_STRING([--with-microstate-accounting={yes|extra}], + [enable microstate account, possibly with extra detailed states]) +AS_HELP_STRING([--without-microstate-accounting], + [don't enable microstate accounting]), +[],[with_microstate_accounting=yes]) + +case "$with_microstate_accounting" in + yes) AC_DEFINE(ERTS_ENABLE_MSACC,[1], + [Define as 1 if you want to enable microstate accounting, 2 if you want extra states]) ;; + extra) AC_DEFINE(ERTS_ENABLE_MSACC,[2], + [Define as 1 if you want to enable microstate accounting, 2 if you want extra states]) ;; + *) ;; +esac + +dnl Magic test for clearcase. +OTP_RELEASE= +if test "${ERLANG_COMMERCIAL_BUILD}" != ""; then + OTP_EXTRA_FLAGS=-DOTP_RELEASE + OTP_RELEASE=yes +else + OTP_EXTRA_FLAGS= +fi +AC_SUBST(OTP_RELEASE) + +AC_MSG_CHECKING([OTP release]) +[SYSTEM_VSN=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`] +AC_MSG_RESULT([$SYSTEM_VSN]) +AC_SUBST(SYSTEM_VSN) + +AC_MSG_CHECKING([OTP version]) +[OTP_VERSION=`cat $ERL_TOP/OTP_VERSION`] +AC_MSG_RESULT([$OTP_VERSION]) +AC_SUBST(OTP_VERSION) + +if test X${enable_m64_build} = Xyes; then + case $CFLAGS in + *-m64*) + ;; + *) + CFLAGS="-m64 $CFLAGS" + ;; + esac +else + if test X${enable_m32_build} = Xyes; + then + case $CFLAGS in + *-m32*) + ;; + *) + CFLAGS="-m32 $CFLAGS" + ;; + esac ; + fi +fi + +AC_ARG_ENABLE(static-nifs, +AS_HELP_STRING([--enable-static-nifs], [link nifs statically. If yes then all nifs in all Erlang/OTP applications will be statically linked into the main binary. It is also possible to give a list of nifs that should be linked statically. The list should be a comma separated and contain the absolute path to a .a archive for each nif that is to be statically linked. Note that you have to link any external dependencies, that the nifs have, to the main binary. So for the crypto nifs you want to pass LIBS=-lcrypto to configure.]), + STATIC_NIFS="$enableval", + STATIC_NIFS=no) +AC_SUBST(STATIC_NIFS) + +AC_ARG_ENABLE(static-drivers, +AS_HELP_STRING([--enable-static-drivers], [comma separated list of linked-in drivers to link statically with the main binary. The list should contain the absolute path to a .a archive for each driver that is to be statically linked. The name of the .a archive has to be the same as the name of the driver.]), + STATIC_DRIVERS="$enableval", + STATIC_DRIVERS=no) +AC_SUBST(STATIC_DRIVERS) + +AC_ARG_WITH(ets-write-concurrency-locks, +AS_HELP_STRING([--with-ets-write-concurrency-locks={8|16|32|64|128|256}], + [specify how many locks the write_concurrency option for ets should use.]) +AS_HELP_STRING([--without-ets-write-concurrency-locks], + [use the default number of write_concurrency locks (default)])) + +if test X"$with_ets_write_concurrency_locks" != X""; then + AC_DEFINE_UNQUOTED(ERTS_DB_HASH_LOCK_CNT,$with_ets_write_concurrency_locks, + [Define to override the default number of write_concurrency locks]) +fi + +AC_ARG_WITH(spectre-mitigation, + AS_HELP_STRING([--with-spectre-mitigation={yes|incomplete}], + [enable spectre mitigation, either fully or with mitigations + disabled in a handful places like the interpreter]) + AS_HELP_STRING([--without-spectre-mitigation], + [build without spectre mitigation]), + [],[with_spectre_mitigation=no]) + +case "$with_spectre_mitigation" in + no) ;; + yes) ;; + incomplete) ;; + *) AC_MSG_ERROR([Invalid spectre mitigation setting]) ;; +esac + +i_noretpoline_attr="" + +AS_IF([test X"$with_spectre_mitigation" != X"no"], + [ + CFLAGS="$CFLAGS -mindirect-branch=thunk" + + AC_MSG_CHECKING([for spectre mitigation]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]],[[return 0;]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_ERROR([no])]) + + AS_IF([test X"$with_spectre_mitigation" = X"incomplete"], + [ + # gcc and clang support this attribute if they're recent enough. Note + # that we must compile with -Werror to check for actual support as they + # warn rather than error out on unsupported attributes. + + i_noretpoline_attr='__attribute__((__indirect_branch__("keep")))' + i_preserve_cflags="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + + AC_MSG_CHECKING([whether spectre mitigation can be disabled on a per-function basis]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[$i_noretpoline_attr]],[[return 0;]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_ERROR([no])]) + + CFLAGS="$i_preserve_cflags" + ]) + ]) + +AC_DEFINE_UNQUOTED(ERTS_NO_RETPOLINE, $i_noretpoline_attr, + [Per-function attribute for disabling retpoline. This is + *only* defined when --with-spectre-mitigation=incomplete + and has no effects otherwise]) + +dnl ---------------------------------------------------------------------- +dnl Checks for programs. +dnl ---------------------------------------------------------------------- + +AC_LANG([C]) + +AC_PROG_CC +AC_SUBST(GCC) + +AC_PROG_CXX +AC_SUBST(CXXFLAGS) + +AC_PROG_EGREP +AC_PROG_CPP +AC_PROG_RANLIB +AC_PROG_YACC +LM_PROG_PERL5 +if test "$ac_cv_path_PERL" = false; then + AC_MSG_ERROR([Perl version 5 is required to build the emulator!]) +fi +AC_PROG_LN_S +AC_CHECK_TOOL([AR], [ar], [false]) +if test "$ac_cv_prog_AR" = false; then + AC_MSG_ERROR([No 'ar' command found in PATH]) +fi + + +# +# Get programs needed for building the documentation +# + +## Delete previous failed configure results +if test -f doc/CONF_INFO; then + rm -f doc/CONF_INFO +fi + +AC_CHECK_PROGS(XSLTPROC, xsltproc) +if test -z "$XSLTPROC"; then + echo "xsltproc" >> doc/CONF_INFO + AC_MSG_WARN([No 'xsltproc' command found: the documentation cannot be built]) +fi + +AC_CHECK_PROGS(FOP, fop) +if test -z "$FOP"; then + FOP="$ERL_TOP/make/fakefop" + echo "fop" >> doc/CONF_INFO + AC_MSG_WARN([No 'fop' command found: going to generate placeholder PDF files]) +fi + +AC_CHECK_PROGS(XMLLINT, xmllint) +if test -z "$XMLLINT"; then + echo "xmllint" >> doc/CONF_INFO + AC_MSG_WARN([No 'xmllint' command found: can't run the xmllint target for the documentation]) +fi + +dnl +dnl We can live with Solaris /usr/ucb/install +dnl +case $host in + *-*-solaris*|free_source) + if test -x /usr/ucb/install; then + INSTALL="/usr/ucb/install -c" + fi + ;; + *) + ;; +esac +AC_PROG_INSTALL +LM_PROG_INSTALL_DIR + +case $host_os in + darwin*) + dnl Need to preserve modification time on archives; + dnl otherwise, ranlib has to be run on archives + dnl again after installation. + INSTALL_DATA="$INSTALL_DATA -p";; + *) + ;; +esac + +dnl +dnl Fix for Tilera install permissions +dnl + +case $build in + *tile*) + INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" + INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" + ;; + *) + ;; +esac + +dnl --------------------------------------------------------------------- +dnl Special stuff regarding CFLAGS and details in the environment... +dnl --------------------------------------------------------------------- + +dnl NOTE: CPPFLAGS will be included in CFLAGS at the end +case $host_os in + linux*) CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE";; + aix*|os400*) + # * _ALL_SOURCE: Required to get the winsize structure for TIOCSWINSZ. + # * _LINUX_SOURCE_COMPAT: Not required, but makes some libc functions + # behave closer to glibc assumptions. + CPPFLAGS="$CPPFLAGS -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" + ;; + win32) + # The ethread library requires _WIN32_WINNT of at least 0x0403. + # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" + ;; + *) + ;; +esac + + +LM_WINDOWS_ENVIRONMENT + +dnl +dnl Flags to the C compiler +dnl +dnl Make sure we find config.h +dnl + +ERTS_CONFIG_H_IDIR="-I${ERL_TOP}/erts/$host" +AC_SUBST(ERTS_CONFIG_H_IDIR) + +extra_flags="$ERTS_CONFIG_H_IDIR $OTP_EXTRA_FLAGS" +CFLAGS="$CFLAGS $extra_flags" +DEBUG_FLAGS=-g + + +lfs_conf=ok +lfs_source=none +AS_IF([test "${LFS_CFLAGS+set}" = "set" || test "${LFS_LDFLAGS+set}" = "set" || test "${LFS_LIBS+set}" = "set"], + [ + lfs_source=user + ], + [ + LM_CHECK_GETCONF + test "$GETCONF" = "false" || lfs_source=getconf + ]) + +if test "$lfs_source" = "none"; then + AC_MSG_WARN([Do not know how to check for large file support flags; no getconf is available]) +else + for var in CFLAGS LDFLAGS LIBS; do + AC_MSG_CHECKING([for large file support $var]) + if test $lfs_source = user; then + eval "lfs_val=\"\$LFS_$var\"" + else + eval "lfs_var=LFS_$var" + lfs_val=`$GETCONF $lfs_var 2>/dev/null` || lfs_conf=failed + if test $lfs_conf = failed; then + AC_MSG_RESULT([failed]) + break + fi + eval "$lfs_var=\"$lfs_val\"" + fi + test "$lfs_val" != "" || lfs_val=none + AC_MSG_RESULT([$lfs_val]) + done + if test $lfs_conf = failed; then + AC_MSG_WARN([Check for large file support flags failed; $GETCONF failed]) + else + CFLAGS="$CFLAGS $LFS_CFLAGS" + LDFLAGS="$LDFLAGS $LFS_LDFLAGS" + LIBS="$LIBS $LFS_LIBS" + fi +fi + +AS_IF([test "x$GCC" = xyes], + [ + # Treat certain GCC warnings as errors + LM_TRY_ENABLE_CFLAG([-Werror=return-type], [WERRORFLAGS]) + LM_TRY_ENABLE_CFLAG([-Werror=implicit], [WERRORFLAGS]) + LM_TRY_ENABLE_CFLAG([-Werror=undef], [WERRORFLAGS]) + + # until the emulator can handle this, I suggest we turn it off! + #WFLAGS="-Wall -Wshadow -Wcast-qual -Wmissing-declarations" + WFLAGS="-Wall -Wstrict-prototypes -Wpointer-arith" + + case "$host_cpu" in + tile*) + # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, + # and too strict for our taste. + ;; + *) + WFLAGS="$WFLAGS -Wmissing-prototypes";; + esac + + saved_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Wdeclaration-after-statement" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[;]])],[warn_decl_after_st=true],[warn_decl_after_st=false]) + if test "X$warn_decl_after_st" = "Xtrue"; then + WFLAGS="$WFLAGS -Wdeclaration-after-statement" + fi + CFLAGS=$saved_CFLAGS + + # Use -fno-common for gcc, that is link error if multiple definitions of + # global variables are encountered. This is ISO C compliant. + # Until version 10, gcc has had -fcommon as default, which allows and merges + # such dubious duplicates. + LM_TRY_ENABLE_CFLAG([-fno-common], [CFLAGS]) + + LM_TRY_ENABLE_CFLAG([-fno-strict-aliasing], [CFLAGS]) + ], + [ + WFLAGS="" + WERRORFLAGS=${WERRORFLAGS:-""} + ]) + +AC_MSG_CHECKING([C99 support]) + +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[ +#if __STDC_VERSION__ < 199901L + #error "Not C99" +#endif]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + CFLAGS="-std=gnu99 $CFLAGS"]) + +dnl DEBUG_FLAGS is obsolete (I hope) +AC_SUBST(DEBUG_FLAGS) +AC_SUBST(WFLAGS) +AC_SUBST(WERRORFLAGS) + +## Check if we can do profile guided optimization of beam_emu +LM_CHECK_RUN_CFLAG([-fprofile-generate -Werror],[PROFILE_GENERATE]) +LM_CHECK_RUN_CFLAG([-fprofile-use -Werror],[PROFILE_USE]) +LM_CHECK_RUN_CFLAG([-fprofile-use -fprofile-correction -Werror],[PROFILE_CORRECTION]) + +AS_IF([test "X$PROFILE_CORRECTION" = "Xtrue"], + [ + saved_CFLAGS=$CFLAGS + saved_LDFLAGS=$LDFLAGS + CFLAGS="-fprofile-generate $saved_CFLAGS" + LDFLAGS="-fprofile-generate $saved_LDFLAGS" + AC_MSG_CHECKING([whether $CC links with -fprofile-generate]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[return 0;]])], + [AC_MSG_RESULT([yes]) + PROFILE_GENERATE=true], + [AC_MSG_RESULT([no]) + PROFILE_GENERATE=false]) + CFLAGS=$saved_CFLAGS + LDFLAGS=$saved_LDFLAGS + ]) + +## Check if this is clang +LM_CHECK_ENABLE_CFLAG([-fprofile-instr-generate -Werror],[PROFILE_INSTR_GENERATE]) +AS_IF([test "X$PROFILE_INSTR_GENERATE" = "Xtrue"], + [ + # It was clang, now we also have to check if we have llvm-profdata and that + # we can link programs with -fprofile-instr-use + saved_CFLAGS=$CFLAGS; + CFLAGS="-fprofile-instr-generate -Werror $saved_CFLAGS" + AC_RUN_IFELSE([AC_LANG_PROGRAM([[]],[[]])], + [AC_PATH_PROG([LLVM_PROFDATA], [llvm-profdata],[],[$PATH:/Library/Developer/CommandLineTools/usr/bin]) + AC_CHECK_PROGS([XCRUN], [xcrun]) + AS_IF([test "X$XCRUN" != "X" -a "X$LLVM_PROFDATA" = "X"], + [ + AC_MSG_CHECKING([for $XCRUN $LLVM_PROFDATA]) + AS_IF([$XCRUN $LLVM_PROFDATA --help 2>& AS_MESSAGE_LOG_FD >& AS_MESSAGE_LOG_FD], + [ + LLVM_PROFDATA="$XCRUN $LLVM_PROFDATA" + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + ]) + ]) + AC_SUBST(LLVM_PROFDATA) + AS_IF([test "X$LLVM_PROFDATA" != "X"], + [ + CFLAGS="-fprofile-instr-use=default.profdata $saved_CFLAGS"; + $LLVM_PROFDATA merge -output=default.profdata *.profraw; + AC_MSG_CHECKING([whether $CC accepts -fprofile-instr-use=default.profdata -Werror]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[return 0;]])], + [AC_MSG_RESULT([yes]) + PROFILE_INSTR_USE=true], + [AC_MSG_RESULT([no]) + PROFILE_INSTR_USE=false]) + rm -f default.profdata + ])], + [], + [AC_MSG_NOTICE([Disabling PGO when cross-compiling])]) + rm -f *.profraw + CFLAGS=$saved_CFLAGS; + ]) + +AC_ARG_ENABLE(pgo, +AS_HELP_STRING([--enable-pgo], + [build erts using PGO (profile guided optimization)]), +[ case "$enableval" in + no) enable_pgo=no ;; + *) enable_pgo=yes ;; + esac +],enable_pgo=default) + +USE_PGO=false +AC_MSG_CHECKING([whether to do PGO of erts]) +if test $enable_pgo = no; then + AC_MSG_RESULT([no, disabled by user]) +elif test $CROSS_COMPILING = yes; then + if test $enable_pgo = yes; then + AC_MSG_ERROR(cannot use PGO when cross-compiling) + else + AC_MSG_RESULT([no, cross compiling]) + fi +elif test "X$host" = "Xwin32"; then + AC_MSG_RESULT([no, not supported in windows]) +elif test "X$PROFILE_GENERATE" = "Xtrue" -a "X$PROFILE_USE" = "Xtrue" -a "X$PROFILE_CORRECTION" = "Xtrue"; then + ## We need -fprofile-generate and -fprofile-correction support to use PGO with + ## gcc as multiple threads run within the executed object files + USE_PGO=true + PROFILE_COMPILER=gcc + AC_MSG_RESULT([yes, using -fprofile-generate -fprofile-correction]) +elif test "X$PROFILE_INSTR_GENERATE" = "Xtrue" -a "X$PROFILE_INSTR_USE" = "Xtrue"; then + USE_PGO=true + PROFILE_COMPILER=clang + AC_MSG_RESULT([yes, using -fprofile-instr-generate]) +else + if test $enable_pgo = yes; then + AC_MSG_ERROR(cannot use PGO with this compiler) + else + AC_MSG_RESULT([no]) + fi +fi + +dnl Disable pgo for now +USE_PGO=false + +AC_SUBST(USE_PGO) +AC_SUBST(PROFILE_COMPILER) + +AC_CHECK_SIZEOF(void *) # Needed for ARCH and smp checks below +if test "x$ac_cv_sizeof_void_p" = x8; then + AC_SUBST(EXTERNAL_WORD_SIZE, 64) +else + AC_SUBST(EXTERNAL_WORD_SIZE, 32) +fi + +dnl +dnl Figure out operating system and cpu architecture +dnl + +if test "x$host_alias" != "x"; then + chk_opsys_=$host_os +else + chk_opsys_=`uname -s` + if test "x$chk_opsys_" = "xSunOS"; then + chk_opsys_=$chk_opsys_`uname -r` + fi +fi +case $chk_opsys_ in + win32) OPSYS=win32;; + solaris2.*|SunOS5.*) OPSYS=sol2;; + linux*|Linux) OPSYS=linux;; + darwin|Darwin) OPSYS=darwin;; + freebsd|FreeBSD) OPSYS=freebsd;; + *) OPSYS=noopsys +esac + +AC_SUBST(OPSYS) + +LM_HARDWARE_ARCH + +dnl Check consistency of os and darwin-switches + + +dnl Take care of LDFLAGS on darwin, and disable common_test as it +dnl has a build/configure system re rx-lib that is not compatible +dnl First remove common_tests skip file. + +dnl Adjust LDFLAGS to allow 64bit linkage on DARWIN +case $ARCH-$OPSYS in + amd64-darwin*|arm64-darwin*) + AC_MSG_NOTICE([Adjusting LDFLAGS to cope with 64bit Darwin]) + case $LDFLAGS in + *-m64*) + ;; + *) + LDFLAGS="-m64 $LDFLAGS" + ;; + esac + ;; + *-darwin*) + case $LDFLAGS in + *-m32*) + ;; + *) + LDFLAGS="-m32 $LDFLAGS" + ;; + esac + ;; + *) + if test X${enable_m64_build} = Xyes; then + AC_MSG_NOTICE([Adjusting LDFLAGS to use -m64]) + case $LDFLAGS in + *-m64*) + ;; + *) + LDFLAGS="-m64 $LDFLAGS" + ;; + esac + fi; + if test X${enable_m32_build} = Xyes; then + AC_MSG_NOTICE([Adjusting LDFLAGS to use -m32]) ; + case $LDFLAGS in + *-m32*) + ;; + *) + LDFLAGS="-m32 $LDFLAGS" + ;; + esac ; + fi + ;; +esac + +AC_MSG_CHECKING(if VM has to be linked with Carbon framework) +case $ARCH-$OPSYS in + *-darwin*) + LIBCARBON="-framework Carbon -framework Cocoa" + AC_MSG_RESULT([yes]) + ;; + *) + LIBCARBON= + AC_MSG_RESULT([no]) + ;; +esac + +AC_SUBST(LIBCARBON) + +_search_path=/bin:/usr/bin:/usr/local/bin:$PATH + +AC_PATH_PROG(MKDIR, mkdir, false, $_search_path) +if test "$ac_cv_path_MKDIR" = false; then + AC_MSG_ERROR([No 'mkdir' command found]) +fi + +AC_PATH_PROG(CP, cp, false, $_search_path) +if test "$ac_cv_path_CP" = false; then + AC_MSG_ERROR([No 'cp' command found]) +fi + +_search_path= + + +# Remove old configuration information. +# Next line should be before first output to CONN_INFO. So this is +# just the right place. +rm -f "$ERL_TOP/erts/CONF_INFO" + +dnl Check if we should/can build a sharing-preserving emulator +AC_MSG_CHECKING(if we are building a sharing-preserving emulator) +if test "$enable_sharing_preserving" = "yes"; then + AC_DEFINE(SHCOPY, [1], + [Define if building a sharing-preserving emulator]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +dnl ---------------------------------------------------------------------- +dnl Misc. things (some of them should go away) +dnl ---------------------------------------------------------------------- + +dnl +dnl An attempt to allow cross compiling. This is not the right way, +dnl nor does it work currently. Some makefiles still needs these +dnl variables, so we leave them in for now. +dnl +HCC='$(CC)' AC_SUBST(HCC) +HCFLAGS="" AC_SUBST(HCFLAGS) +HCFLAGS="$HCFLAGS -I${ERL_TOP}/erts/$host" + +dnl We want to use $(CC) as linker for the emulator regardless of +dnl what the user say. This might not be the right way to do it, but +dnl for now that is the way we do it. +LD='$(CC)' +LD_MAY_BE_WEAK=no +AC_SUBST(LD) + +dnl Check for cygwin and object/exe files extension +AC_EXEEXT +AC_OBJEXT + +dnl This is the os flavour, should be unix or win32 +case $host in + win32) + ERLANG_OSTYPE=win32 ;; + *) + ERLANG_OSTYPE=unix ;; +esac + +AC_SUBST(ERLANG_OSTYPE) + +# Check how to export functions from the emulator executable, needed +# when dynamically loaded drivers are loaded (so that they can find +# emulator functions). +# OS'es with ELF executables using the GNU linker (Linux and recent *BSD, +# in rare cases Solaris) typically need '-Wl,-export-dynamic' (i.e. pass +# -export-dynamic to the linker - also known as -rdynamic and some other +# variants); some sysVr4 system(s) instead need(s) '-Wl,-Bexport'. +# AIX 4.x (perhaps only for x>=2) wants -Wl,-bexpall,-brtl and doesn't +# reliably return an error for others, thus we separate it out. +# Otherwise we assume that if the linker accepts the flag, it is needed. +AC_MSG_CHECKING(for extra flags needed to export symbols) +DEXPORT="" +AS_CASE([$host_os], + [aix*|os400*], + [ + DEXPORT=-Wl,-bexpall,-brtl + ], + [bsdi*], + [ + DEXPORT="-rdynamic " + ], + [win32], + [ + DEXPORT="" + ], + [ + DEXPORT= + save_ldflags="$LDFLAGS" + LDFLAGS=-Wl,-export-dynamic + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[DEXPORT="$LDFLAGS"]) + AS_IF([test "$DEXPORT" = ""], + [ + LDFLAGS=-Wl,-Bexport + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[DEXPORT="$LDFLAGS"]) + ]) + LDFLAGS="$save_ldflags" + ]) + +AC_SUBST(DEXPORT) +case "x$DEXPORT" in + "x") + AC_MSG_RESULT([none]);; + *) + AC_MSG_RESULT([$DEXPORT]);; +esac + +# Check for Solaris/ultrasparc /dev/perfmon interface +# (also needs gcc specific asm instructions) +case "${host}:${GCC}" in + sparc-*-solaris*:yes) + AC_DEFINE(HAVE_SOLARIS_SPARC_PERFMON,[1], + [define if you have the Solaris/ultrasparc /dev/perfmon interface]) + ;; + *) + ;; +esac + + +case $host_os in + darwin19*) + # Disable stack checking to avoid crashing with a segment fault + # in macOS Catalina. + AC_MSG_NOTICE([Turning off stack check on macOS 10.15 (Catalina)]) + CFLAGS="-fno-stack-check $CFLAGS" + ;; + *) + ;; +esac + + +dnl ---------------------------------------------------------------------- +dnl Checks for libraries. +dnl ---------------------------------------------------------------------- + +AC_CHECK_LIB(m, sin) +AC_CHECK_LIB(dl, dlopen) +AC_CHECK_LIB(dl, dlvsym) +AC_CHECK_LIB(inet, main) +AC_CHECK_LIB(util, openpty) + +dnl Try to find a thread library. +dnl +dnl ETHR_LIB_NAME, ETHR_LIBS, ETHR_X_LIBS, ETHR_THR_LIB_BASE and ETHR_DEFS +dnl are set by ERL_FIND_ETHR_LIB +ERL_FIND_ETHR_LIB + +if test "X$ETHR_LIB_NAME" = "X"; then + AC_MSG_ERROR([cannot build emulator since no thread library was found]) +fi + +DEFAULT_TYPES="opt" + +DIRTY_SCHEDULER_TEST=$enable_dirty_schedulers_test +AC_SUBST(DIRTY_SCHEDULER_TEST) +test $DIRTY_SCHEDULER_TEST != yes || { + test -f "$ERL_TOP/erts/CONF_INFO" || echo "" > "$ERL_TOP/erts/CONF_INFO" + cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" + cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" + cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" + cat >> "$ERL_TOP/erts/CONF_INFO" < + #include + #include + #include + #include + #include + ]], [[ + int fd = creat("conftest.temp", 0600); + fallocate(fd, FALLOC_FL_KEEP_SIZE,(off_t) 1024,(off_t) 1024); + ]])],[i_cv_fallocate_works=yes],[i_cv_fallocate_works=no]) +]) +if test $i_cv_fallocate_works = yes; then + AC_DEFINE(HAVE_FALLOCATE, 1, Define if you have a working fallocate()) +fi + +dnl * Old glibcs have broken posix_fallocate(). Make sure not to use it. +dnl * It may also be broken in AIX. +AC_CACHE_CHECK([whether posix_fallocate() works],i_cv_posix_fallocate_works,[ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #if !defined(__sun) && !defined(__sun__) + #define _XOPEN_SOURCE 600 + #endif + #include + #include + #include + #include + #if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)) + possibly broken posix_fallocate + #endif + int main() { + int fd = creat("conftest.temp", 0600); + int ret; + if (-1 == fd) { + perror("creat()"); + return 2; + } + ret = posix_fallocate(fd, 1024, 1024) < 0 ? 1 : 0; + unlink("conftest.temp"); + return ret; + } + ]])],[ + i_cv_posix_fallocate_works=yes + ],[ + i_cv_posix_fallocate_works=no + ],[ + i_cv_posix_fallocate_works=no + ]) +]) +if test $i_cv_posix_fallocate_works = yes; then + AC_DEFINE(HAVE_POSIX_FALLOCATE,, Define if you have a working posix_fallocate()) +fi + +# +# EMU_THR_LIB_NAME, EMU_THR_LIBS, EMU_THR_X_LIBS, and EMU_THR_DEFS is +# used by the emulator, and can (but should not) be used by applications +# that only require thread support when the emulator has thread support. +# Other applications should use ETHR_LIB_NAME, ETHR_LIBS, ETHR_X_LIBS, +# and ETHR_DEFS. +# + +EMU_THR_LIB_NAME= +EMU_THR_X_LIBS= +EMU_THR_LIBS= +EMU_THR_DEFS= + +# Threads enabled for emulator +EMU_THR_LIB_NAME=$ETHR_LIB_NAME +EMU_THR_X_LIBS=$ETHR_X_LIBS +EMU_THR_LIBS=$ETHR_LIBS +EMU_THR_DEFS=$ETHR_DEFS +ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS threads" +AC_MSG_CHECKING(whether lock checking should be enabled) +AC_MSG_RESULT($enable_lock_check) +if test "x$enable_lock_check" != "xno"; then + EMU_THR_DEFS="$EMU_THR_DEFS -DERTS_ENABLE_LOCK_CHECK" +fi + +AC_MSG_CHECKING(whether lock counters should be enabled) +AC_MSG_RESULT($enable_lock_count) +if test "x$enable_lock_count" != "xno"; then + DEFAULT_TYPES="$DEFAULT_TYPES lcnt" +fi + +case $host_os in + linux*) + AC_MSG_CHECKING([whether dlopen() needs to be called before first call to dlerror()]) + if test "x$ETHR_THR_LIB_BASE_TYPE" != "xposix_nptl"; then + AC_DEFINE(ERTS_NEED_DLOPEN_BEFORE_DLERROR,[1], + [Define if dlopen() needs to be called before first call to dlerror()]) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + ;; + *) + ;; +esac + +# Remove -D_WIN32_WINNT*, -DWINVER* and -D_GNU_SOURCE from EMU_THR_DEFS +# (defined in CFLAGS). Note that we want to keep these flags +# in ETHR_DEFS, but not in EMU_THR_DEFS. +new_emu_thr_defs= +for thr_def in $EMU_THR_DEFS; do + case $thr_def in + -D_GNU_SOURCE*|-D_WIN32_WINNT*|-DWINVER*) + ;; + *) + new_emu_thr_defs="$new_emu_thr_defs $thr_def" + ;; + esac +done +EMU_THR_DEFS=$new_emu_thr_defs + +AC_SUBST(EMU_THR_LIB_NAME) +AC_SUBST(EMU_THR_X_LIBS) +AC_SUBST(EMU_THR_LIBS) +AC_SUBST(EMU_THR_DEFS) + +if test "x$enable_lock_check" = "xno"; then + EMU_LOCK_CHECKING=no +else + EMU_LOCK_CHECKING=yes +fi + +AC_SUBST(EMU_LOCK_CHECKING) + +ERL_INTERNAL_LIBS + +dnl THR_LIBS and THR_DEFS are only used by odbc +THR_LIBS=$ETHR_X_LIBS +THR_DEFS=$ETHR_DEFS + +AC_SUBST(THR_LIBS) +AC_SUBST(THR_DEFS) + +dnl ---------------------------------------------------------------------- +dnl Try to figure out where to get the termcap functions from. +dnl We use tgetent(), tgetflag(), tgetnum(), tgetstr() and tputs() +dnl ---------------------------------------------------------------------- + +TERMCAP_LIB= + +AS_IF([test "x$with_termcap" != "xno" && test "X$host" != "Xwin32"], + [ + # try these libs + termcap_libs="tinfo ncurses curses termcap termlib" + + for termcap_lib in $termcap_libs; do + AC_CHECK_LIB($termcap_lib, tgetent, TERMCAP_LIB="-l$termcap_lib") + if test "x$TERMCAP_LIB" != "x"; then + break + fi + done + + if test "x$TERMCAP_LIB" = "x"; then + AC_MSG_ERROR([No curses library functions found]) + fi + ]) + +AC_SUBST(TERMCAP_LIB) + +if test "x$TERMCAP_LIB" != "x"; then + + AC_DEFINE(HAVE_TERMCAP, 1, [Define if termcap functions exists]) +fi + +AS_IF([test "X$host" != "Xwin32"], + [ + AC_MSG_CHECKING(for wcwidth) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[wcwidth(0);]])],[have_wcwidth=yes],[have_wcwidth=no]) + if test $have_wcwidth = yes; then + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_WCWIDTH, [1], + [Define to 1 if you have a `wcwidth' function.]) + fi + ]) + +dnl ------------- +dnl zlib +dnl ------------- + +AC_ARG_ENABLE(builtin-zlib, + AS_HELP_STRING([--enable-builtin-zlib], + [force use of our own built-in zlib]), + [ case "$enableval" in + no) enable_builtin_zlib=no ;; + *) enable_builtin_zlib=yes ;; + esac ], enable_builtin_zlib=no) + +Z_LIB= + +AS_IF([test "x$enable_builtin_zlib" = "xyes"], + [ + AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1, + [Define if your zlib version defines inflateGetDictionary.]) + AC_MSG_NOTICE([Using our own built-in zlib source]) + ], + [ +AC_MSG_CHECKING(for zlib 1.2.5 or higher) +zlib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include "zlib.h" +]],[[ +#if ZLIB_VERNUM >= 0x1250 + Bytef s[1]; + s[0] = 0; + (void) adler32((uLong)0, s, 1); +#else +#error "No zlib 1.2.5 or higher found" +error +#endif +]])], +[ + Z_LIB="-lz" + AC_DEFINE(HAVE_LIBZ, 1, [Define to 1 if you have the `z' library (-lz).]) + AC_MSG_RESULT(yes) +],[ + AC_MSG_RESULT(no) +]) + +AS_IF([test "$Z_LIB" != ""], + [ + AC_SEARCH_LIBS(inflateGetDictionary, [z], + AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1, + [Define if your zlib version defines inflateGetDictionary.])) + ]) + +LIBS=$zlib_save_LIBS + + ]) + +AC_SUBST(Z_LIB) + + +dnl ------------- +dnl esock +dnl ------------- + +AC_ARG_ENABLE(esock, +AS_HELP_STRING([--enable-esock], [enable builtin experimental socket (as a nif) support (default)]) +AS_HELP_STRING([--disable-esock], [disable builtin experimental socket (as a nif) support]), + [ case "$enableval" in + no) enable_esock=no ;; + *) enable_esock=yes ;; + esac +],enable_esock=yes) + +AS_IF([test "x$enable_esock" = "xyes"], + [ + AC_DEFINE(ESOCK_ENABLE, [1], [Enable esock]) + AC_CHECK_FUNCS([localtime_r strftime getprotoent setprotoent endprotoent]) + ]) + +dnl *** ESOCK_USE_RCVSNDTIMEO *** + +AC_ARG_ENABLE(esock_use_rcvsndtimeo, +AS_HELP_STRING([--enable-esock-rcvsndtimeo], [enable use of the option(s) rcvtimeo and sndtimeo]) +AS_HELP_STRING([--disable-esock-rcvsndtimeo], [disable use of the option(s) rcvtimeo and sndtimeo (default)])) + +if test "x$enable_esock_rcvsndtimeo" = "xyes"; then + AC_DEFINE(ESOCK_USE_RCVSNDTIMEO, [1], [Use SO_[RCV|SND]TMIEO]) +fi + + +dnl *** ESOCK_USE_EXTERNDED_ERROR_INFO *** + +AC_ARG_ENABLE(esock_extended_error_info, +AS_HELP_STRING([--enable-esock-extended-error-info], [enable use of extended error info]) +AS_HELP_STRING([--disable-esock-extended-error-info], [disable use of extended error info (default)])) + +dnl Temporary! Currently we require eei to be *explicitly* +dnl disabled (for debug reasons). +if test "x$enable_esock_extended_error_info" != "xno"; then + AC_DEFINE(ESOCK_USE_EXTENDED_ERROR_INFO, [1], [Use extended error info]) +fi + + +dnl *** ESOCK_COUNTER_SIZE *** + +AC_ARG_WITH(esock-counter-size, +AS_HELP_STRING([--with-esock-counter-size=SZ], + [Size of the esock counters, in number of bits: 16 | 24 | 32 | 48 | 64; default is 64]), +[], +[with_esock_counter_size=64]) + +case "$with_esock_counter_size" in + 16) + AC_DEFINE(ESOCK_COUNTER_SIZE, [16], [ESOCK counter size]) + ;; + 24) + AC_DEFINE(ESOCK_COUNTER_SIZE, [24], [ESOCK counter size]) + ;; + 32) + AC_DEFINE(ESOCK_COUNTER_SIZE, [32], [ESOCK counter size]) + ;; + 48) + AC_DEFINE(ESOCK_COUNTER_SIZE, [48], [ESOCK counter size]) + ;; + 64) + AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size]) + ;; + *) + AC_MSG_WARN([Invalid esock counter size ($with_esock_counter_size), using default (64)]) + AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size]) + dnl with_esock_counter_size=64 + ;; +esac +dnl ESOCK_COUNTER_SIZE=$with_esock_counter_size + +dnl We don't actually (currently) use this in erlang +dnl AC_SUBST(ESOCK_COUNTER_SIZE) + +dnl Checks for the net nif +AC_CHECK_FUNC([if_nametoindex], + [AC_DEFINE(HAVE_IF_NAMETOINDEX, [1], + [Define as 1 if function exists])] + []) +AC_CHECK_FUNC([if_indextoname], + [AC_DEFINE(HAVE_IF_INDEXTONAME, [1], + [Define as 1 if function exists])], + []) +AC_CHECK_FUNC([if_nameindex], + [AC_DEFINE(HAVE_IF_NAMEINDEX, [1], + [Define as 1 if function exists])], + []) +AC_CHECK_FUNC([if_freenameindex], + [AC_DEFINE(HAVE_IF_FREENAMEINDEX, [1], + [Define as 1 if function exists])] + []) +AC_CHECK_FUNC([gethostname], + [AC_DEFINE(HAVE_GETHOSTNAME, [1], + [Define as 1 if function exists])] + []) + + +dnl *** ESOCK_USE_SOCKET_REGISTRY *** +dnl At this time we *enable* use of the socket registry by default +dnl since we want to be able to have as much debug info as possible. + +AC_ARG_ENABLE(esock-socket-registry, + AS_HELP_STRING([--enable-esock-socket-registry], + [enable use of the socket registry by default (default)]) + AS_HELP_STRING([--disable-esock-socket-registry], + [disable use of the socket registry by default])) + +AS_IF([test "x$enable_esock_socket_registry" = "xno"], [ + AC_DEFINE(ESOCK_USE_SOCKET_REGISTRY, [0], + [Don't use socket registry by default])], [ + AC_DEFINE(ESOCK_USE_SOCKET_REGISTRY, [1], + [Use socket registry by default])]) + + +AC_CHECK_MEMBERS([struct ifreq.ifr_map], + [AC_DEFINE(ESOCK_USE_IFMAP, [], [Interface map supported])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], + [AC_DEFINE(ESOCK_USE_HWADDR, [], [Interface hwaddr supported])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +AC_CHECK_MEMBERS([struct ifreq.ifr_ifindex], + [AC_DEFINE(ESOCK_USE_IFINDEX, [], [Interface ifindex supported])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +AC_CHECK_MEMBERS([struct ifreq.ifr_index], + [AC_DEFINE(ESOCK_USE_INDEX, [], [Interface index supported])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + + +AC_CHECK_MEMBERS([struct sockaddr_dl.sdl_len], + [AC_DEFINE(ESOCK_SDL_LEN, [], [Socket address dl length])], + [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +dnl +dnl This test kindly borrowed from Tcl +dnl +#-------------------------------------------------------------------- +# Check for the existence of the -lsocket and -lnsl libraries. +# The order here is important, so that they end up in the right +# order in the command line generated by make. Here are some +# special considerations: +# 1. Use "connect" and "accept" to check for -lsocket, and +# "gethostbyname" to check for -lnsl. +# 2. Use each function name only once: can't redo a check because +# autoconf caches the results of the last check and won't redo it. +# 3. Use -lnsl and -lsocket only if they supply procedures that +# aren't already present in the normal libraries. This is because +# IRIX 5.2 has libraries, but they aren't needed and they're +# bogus: they goof up name resolution if used. +# 4. On some SVR4 systems, can't use -lsocket without -lnsl too. +# To get around this problem, check for both libraries together +# if -lsocket doesn't work by itself. +#-------------------------------------------------------------------- + +tk_oldLibs=$LIBS +erl_checkBoth=0 +SOCKET_LIBS="" +AC_CHECK_FUNC(connect, erl_checkSocket=0, erl_checkSocket=1) +AS_IF([test "$erl_checkSocket" = 1], + [ + AC_CHECK_LIB(socket, main, SOCKET_LIBS="-lsocket", erl_checkBoth=1) + ]) + +AS_IF([test "$erl_checkBoth" = 1], + [ + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, SOCKET_LIBS="-lsocket -lnsl") + ]) + +LIBS="$tk_oldLibs $SOCKET_LIBS" +AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [SOCKET_LIBS="$SOCKET_LIBS -lnsl"])) +AC_CHECK_FUNC(gethostbyname_r,have_gethostbyname_r=yes) + +LIBS="$tk_oldLibs $SOCKET_LIBS" + +AC_SUBST(SOCKET_LIBS) + +dnl +dnl These gethostbyname thingies use old style AC_DEFINE for BC with ancient +dnl autoconf... +dnl + +AS_IF([test "$have_gethostbyname_r" = yes], + [ + # OK, so we have gethostbyname_r() - but do we know how to call it...? + # (if not, HAVE_GETHOSTBYNAME_R will not be defined at all) + AS_CASE([$host_os], + [solaris2*], + [ + AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_SOLARIS, + [Define to flavour of gethostbyname_r]) + ], + [aix*|os400*], + [ + # AIX version also needs "struct hostent_data" defn + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct hostent_data hd;]])],[AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_AIX, + Define to flavour of gethostbyname_r)],[]) + ], + [ + AC_EGREP_CPP(^yes$,[ +#include +#ifdef __GLIBC__ +yes +#endif + ], AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_GLIBC, + [Define to flavour of gethostbyname_r])) + ]) + ]) + +AC_MSG_CHECKING(for working posix_openpt implementation) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#define _XOPEN_SOURCE 600 +#include +#include +]], [[ + int mfd = posix_openpt(O_RDWR); + ptsname(mfd); + grantpt(mfd); + unlockpt(mfd); + return mfd; +]])],[working_posix_openpt=yes],[working_posix_openpt=no]) + +if test "X$working_posix_openpt" = "Xyes"; then + AC_DEFINE(HAVE_WORKING_POSIX_OPENPT, [1], + [Define if you have a working posix_openpt implementation]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl Check for usage of sockaddr_in in netdb.h +dnl somewhat ugly check, I check for presence of the string and that +dnl compilation works. If either fails I assume it's not needed. +dnl Seems only to be needed on a patched version of solaris2.5.1, with +dnl netdb.h version 1.18. +AC_MSG_CHECKING([if netdb.h requires netinet/in.h to be previously included]) +AC_EGREP_CPP(sockaddr_in, + [#include ], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], [[return 0;]])],[need_in_h=yes],[need_in_h=no]), + need_in_h=no) + +if test $need_in_h = yes; then + AC_DEFINE(NETDB_H_NEEDS_IN_H,[1], + [Define if netdb.h needs struct sockaddr_in ans in.h CAN be included before]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl Check for type socklen_t +dnl +AC_MSG_CHECKING([for socklen_t]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[socklen_t test;]])],[have_socklen_t=yes],[have_socklen_t=no]), + +if test $have_socklen_t = yes; then + AC_DEFINE(HAVE_SOCKLEN_T,[1],[Define if we have socklen_t]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + + +dnl h_errno isn't always declared in netdb.h, and with some definitions +dnl (e.g. function call for thread-safe) a simple 'extern int' may conflict +dnl (we do assume that h_errno exists at all...) +AC_CACHE_CHECK([for h_errno declaration in netdb.h], + ac_cv_decl_h_errno, +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int err = h_errno;]])],[ac_cv_decl_h_errno=yes],[ac_cv_decl_h_errno=no])]) +if test $ac_cv_decl_h_errno = yes; then + AC_DEFINE(H_ERRNO_DECLARED,[1], + [define if h_errno is declared (in some way) in a system header file]) +fi + + +dnl ---------------------------------------------------------------------- +dnl Checks for header files. +dnl ---------------------------------------------------------------------- + +dnl We sometimes need EMU_THR_DEFS in order to find certain headers. +saved_cppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" + +AC_HEADER_DIRENT +AC_CHECK_INCLUDES_DEFAULT + +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS_ONCE([sys/time.h]) + +dnl Interactive UX needs for socket related error codes. +dnl Some Linuxes needs instead of +dnl +AC_CHECK_HEADERS(fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.h \ + sys/types.h sys/stropts.h sys/sysctl.h \ + sys/ioctl.h sys/time.h sys/uio.h sys/mman.h \ + sys/socket.h sys/sockio.h sys/socketio.h \ + net/errno.h malloc.h arpa/nameser.h libdlpi.h \ + pty.h util.h libutil.h utmp.h langinfo.h poll.h sdkddkver.h \ + elf.h) + +AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], [], [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +AC_CHECK_MEMBERS([struct ifreq.ifr_enaddr], [], [], + [#ifdef __WIN32__ + #else + #include + #endif + ]) + +dnl ---------------------------------------------------------------------- +dnl Checks for types. +dnl ---------------------------------------------------------------------- + +AC_CHECK_TYPES([struct ip_mreqn], [], [], + [ + #include + ]) + + +dnl ---------------------------------------------------------------------- +dnl Check the availability of systemd +dnl ---------------------------------------------------------------------- +AS_IF([test x"$enable_systemd" != x"no"], +[ + +systemd_daemon_save_LIBS=$LIBS +LIBS= +AC_SEARCH_LIBS(sd_listen_fds,[systemd systemd-daemon], + [have_sd_listen_fds=yes],[have_sd_listen_fds=no],$systemd_daemon_save_LIBS) +AC_SEARCH_LIBS(sd_notify,[systemd systemd-daemon], + [have_sd_notify=yes],[have_sd_notify=no],$systemd_daemon_save_LIBS) +AC_CHECK_HEADERS(systemd/sd-daemon.h, + [have_systemd_sd_daemon_h=yes],[have_systemd_sd_daemon_h=no]) + +if test x"$have_sd_listen_fds" = x"yes" && \ + test x"$have_sd_notify" = x"yes" && \ + test x"$have_systemd_sd_daemon_h" = x"yes"; then + AC_DEFINE([HAVE_SYSTEMD_DAEMON],[1],[Define if you have systemd daemon]) + SYSTEMD_DAEMON_LIBS=$LIBS +elif test x"$enable_systemd" = x"yes"; then + AC_MSG_FAILURE([--enable-systemd was given, but test for systemd failed]) +fi +LIBS=$systemd_daemon_save_LIBS +]) +AC_SUBST(SYSTEMD_DAEMON_LIBS) + + +dnl ---------------------------------------------------------------------- +dnl Check the availability for libdlpi +dnl ---------------------------------------------------------------------- +AC_CHECK_LIB(dlpi, dlpi_open) +AS_IF([test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"], + [ + unset -v ac_cv_lib_dlpi_dlpi_open + dnl Try again now with -L/lib (or ditto 64) as argument to linker since + dnl gcc makes /usr/ccs/bin/ld ignore the crle configured linker default paths + dnl typically causing dlpi not being found on Solaris et.al + save_ldflags="$LDFLAGS" + try_dlpi_lib=$erl_xcomp_sysroot/lib + if test x"$ac_cv_sizeof_void_p" = x"8"; then + if test -d $erl_xcomp_sysroot/lib64; then + try_dlpi_lib=$erl_xcomp_sysroot/lib64 + elif test -d $erl_xcomp_sysroot/lib/64; then + try_dlpi_lib=$erl_xcomp_sysroot/lib/64 + fi + fi + if test ! -f "$try_dlpi_lib/libdlpi.so" && \ + test -f "$try_dlpi_lib/libdlpi.so.1" + then + dnl It looks like there is a missing symlink + dnl - let's be helpful and notify the user + dnl NOTE this help is far from perfect e.g if there would be no + dnl *.so.1 but a *.so.1.123 or *.so.2 this will be no help + AC_MSG_ERROR( + [Your OS installation is missing a symbolic link. + Maybe it lacks some development package(s)... + It can anyhow be fixed with the following command: + # ln -s libdlpi.so.1 $try_dlpi_lib/libdlpi.so + ]) + fi + LDFLAGS="-L$try_dlpi_lib -R$try_dlpi_lib $LDFLAGS" + unset -v try_dlpi_lib + AC_MSG_NOTICE([Extending the search to include $erl_xcomp_sysroot/lib]) + AC_CHECK_LIB(dlpi, dlpi_open) + if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then + LDFLAGS="$save_ldflags" + fi + unset -v save_ldflags + ]) + +AC_CHECK_HEADER(sys/resource.h, + [AC_DEFINE(HAVE_SYS_RESOURCE_H, 1, + [Define to 1 if you have the header file]) + AC_CHECK_DECLS([getrlimit, setrlimit, RLIMIT_STACK], + [],[], + [#include ])], + [],[]) + +AC_CHECK_FUNCS([getrusage]) + +dnl Check if we have kernel poll support +have_kernel_poll=no +AC_CHECK_HEADER(sys/event.h, have_kernel_poll=kqueue) +AC_CHECK_HEADER(sys/epoll.h, have_kernel_poll=epoll) +AC_CHECK_HEADER(sys/devpoll.h, have_kernel_poll=/dev/poll) + +dnl Check if we have timerfds to be used for high accuracy +dnl epoll_wait timeouts +AC_CHECK_HEADERS([sys/timerfd.h]) + +dnl Check if we have the header file 'netpacket/packat.h' in which +dnl type 'struct sockaddr_ll' is defined. +AC_CHECK_HEADERS([netpacket/packet.h], + have_netpacket_packet_h=yes, + have_netpacket_packet_h=no) + +dnl Check for kernel SCTP support +AC_SUBST(LIBSCTP) +AS_IF([test "x$enable_sctp" != "xno"], + [ + AC_CHECK_HEADER(netinet/sctp.h, + [LIBSCTP=libsctp.so.1 + AC_DEFINE(HAVE_SCTP_H, [1], + [Define to 1 if you have the header file])], + [], + [#if HAVE_SYS_SOCKET_H + #include + #endif + ]) + ]) + +case "x$enable_sctp" in + xno|x) + ;; + *) + if test "x$LIBSCTP" = "x" ; then + AC_MSG_ERROR([sctp support requested, but cannot be enabled since 'netinet/sctp.h' is missing]) + fi;; +esac + +AS_IF([test x"$ac_cv_header_netinet_sctp_h" = x"yes"], + [ + AS_IF([test "x$enable_sctp" = "xlib"], + AC_CHECK_LIB(sctp, sctp_bindx)) + AC_CHECK_FUNCS([sctp_bindx sctp_peeloff sctp_getladdrs sctp_freeladdrs sctp_getpaddrs sctp_freepaddrs \ + sctp_connectx]) + AC_CHECK_MEMBERS([struct sctp_accoc_value.assoc_id], [], [], + [#if HAVE_SYS_SOCKET_H + #include + #endif + #include + ]) + AC_CHECK_DECLS([SCTP_UNORDERED, SCTP_ADDR_OVER, SCTP_ABORT, + SCTP_EOF, SCTP_SENDALL, SCTP_ADDR_CONFIRMED, + SCTP_DELAYED_ACK_TIME, + SCTP_EMPTY, SCTP_UNCONFIRMED, + SCTP_CLOSED, SCTPS_IDLE, + SCTP_BOUND, SCTPS_BOUND, + SCTP_LISTEN, SCTPS_LISTEN, + SCTP_COOKIE_WAIT, SCTPS_COOKIE_WAIT, + SCTP_COOKIE_ECHOED, SCTPS_COOKIE_ECHOED, + SCTP_ESTABLISHED, SCTPS_ESTABLISHED, + SCTP_SHUTDOWN_PENDING, SCTPS_SHUTDOWN_PENDING, + SCTP_SHUTDOWN_SENT, SCTPS_SHUTDOWN_SENT, + SCTP_SHUTDOWN_RECEIVED, SCTPS_SHUTDOWN_RECEIVED, + SCTP_SHUTDOWN_ACK_SENT, SCTPS_SHUTDOWN_ACK_SENT], [], [], + [#if HAVE_SYS_SOCKET_H + #include + #endif + #include + ]) + AC_CHECK_MEMBERS([struct sctp_paddrparams.spp_pathmtu, + struct sctp_paddrparams.spp_sackdelay, + struct sctp_paddrparams.spp_flags, + struct sctp_remote_error.sre_data, + struct sctp_send_failed.ssf_data, + struct sctp_event_subscribe.sctp_authentication_event, + struct sctp_event_subscribe.sctp_sender_dry_event], [], [], + [#if HAVE_SYS_SOCKET_H + #include + #endif + #include + ]) + ]) + +dnl Check for setns +AC_CHECK_HEADERS(sched.h setns.h) +AC_CHECK_FUNCS([setns]) + +dnl Check for linux/errqueue +AC_CHECK_HEADERS([linux/types.h linux/errqueue.h], [], [], +[[#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_LINUX_TYPES_H +# include +#endif +]]) + +HAVE_VALGRIND=no +AC_CHECK_HEADER(valgrind/valgrind.h, HAVE_VALGRIND=yes) +AC_SUBST(HAVE_VALGRIND) + +LM_DECL_SO_BSDCOMPAT +LM_DECL_INADDR_LOOPBACK +LM_DECL_SYS_ERRLIST + +AC_CACHE_CHECK([if windows.h includes winsock2.h], + erts_cv_windows_h_includes_winsock2_h, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + ]], [[#ifndef _WINSOCK2API_ + #error winsock2.h not included + #endif + int i = 1; + ]])],[erts_cv_windows_h_includes_winsock2_h=yes],[erts_cv_windows_h_includes_winsock2_h=no])) +if test $erts_cv_windows_h_includes_winsock2_h = yes; then + AC_DEFINE(WINDOWS_H_INCLUDES_WINSOCK2_H, 1, \ +[Define if windows.h includes winsock2.h]) +fi + +dnl restore CPPFLAGS +CPPFLAGS=$saved_cppflags + +dnl ---------------------------------------------------------------------- +dnl Checks for typedefs, structures, and compiler characteristics. +dnl ---------------------------------------------------------------------- + +AC_C_CONST + +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T + +AC_STRUCT_TM +LM_STRUCT_SOCKADDR_SA_LEN + +AC_CHECK_SIZEOF(char, 1) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(void *) +AC_CHECK_SIZEOF(long long) +AC_CHECK_SIZEOF(size_t) +AC_CHECK_SIZEOF(off_t) +AC_CHECK_SIZEOF(time_t) +AC_CHECK_SIZEOF(suseconds_t) +AC_CHECK_SIZEOF(_Float16) + +BITS64= + +if test $ac_cv_sizeof_void_p = 8; then + BITS64=yes +fi +AC_SUBST(BITS64) + +AC_MSG_CHECKING([for C compiler 'restrict' support]) +restrict_keyword="" +for x in restrict __restrict; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int * $x foo(int * $x arg); + int * $x foo(int * $x arg) + { int * $x var=arg; return var;} + ]], [[]])],[restrict_keyword=$x],[]) + if test "x$restrict_keyword" != "x"; then + break + fi +done +AC_DEFINE_UNQUOTED(ERTS_RESTRICT,[$restrict_keyword],[Type qualifier restrict]) +if test "x$restrict_keyword" != "x"; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +if test "x$ac_compiler_gnu" = "xyes"; then +AC_MSG_CHECKING([if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly]) +## tree-copyrename was broken in gcc 4.3 and then removed in gcc 6 +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + #if (__GNUC__ > 4 && __GNUC__ < 6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + ; + #else + #error old and ok + #endif + ]])],[no_tree_copyrename=yes],[no_tree_copyrename=no]) + +if test "x$no_tree_copyrename" = "xyes"; then + CFLAGS="$CFLAGS -fno-tree-copyrename" + AC_MSG_RESULT(yes, adjusting CFLAGS) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING([for broken gcc-4.3.0 compiler]) +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +/* pr36339.c */ +extern void abort (void); + +typedef unsigned long my_uintptr_t; + +int check_a(my_uintptr_t tagged_ptr); + +int __attribute__((noinline)) try_a(my_uintptr_t x) +{ + my_uintptr_t heap[2]; + my_uintptr_t *hp = heap; + + hp[0] = x; + hp[1] = 0; + return check_a((my_uintptr_t)(void*)((char*)hp + 1)); +} + +int __attribute__((noinline)) check_a(my_uintptr_t tagged_ptr) +{ + my_uintptr_t *hp = (my_uintptr_t*)(void*)((char*)tagged_ptr - 1); + + if (hp[0] == 42 && hp[1] == 0) + return 0; + return -1; +} + +int main(void) +{ + if (try_a(42) < 0) + abort (); + return 0; +} +]])],[gcc_4_3_0_bug=no],[gcc_4_3_0_bug=yes],[gcc_4_3_0_bug=cross]) + +case $gcc_4_3_0_bug in + yes|no) + gcc_4_3_0_bug_result=$gcc_4_3_0_bug;; + cross) + gcc_dumped_vsn=`$CC -dumpversion 2>/dev/null` + case gcc-$gcc_dumped_vsn in + gcc-4.3.0) gcc_4_3_0_bug=yes;; + *) gcc_4_3_0_bug=no;; + esac + gcc_4_3_0_bug_result="$gcc_4_3_0_bug; could not run test since cross compiling, checked version number ($gcc_dumped_vsn) instead";; +esac + +AC_MSG_RESULT([$gcc_4_3_0_bug_result]) +if test $gcc_4_3_0_bug = yes; then + AC_MSG_ERROR([This gcc miscompiles the Erlang runtime system; please use a different version]) +fi + +fi + +case X$erl_xcomp_bigendian in + X) ;; + Xyes|Xno) ac_cv_c_bigendian=$erl_xcomp_bigendian;; + *) AC_MSG_ERROR([Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian]);; +esac + +AC_C_BIGENDIAN( + [ + AC_DEFINE([WORDS_BIGENDIAN], [1], [Define if big-endian]) + AC_DEFINE([ERTS_ENDIANNESS], [1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]) + ], + [ + AC_DEFINE([ERTS_ENDIANNESS], [-1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]) + ], + [ + case "$erl_xcomp_bigendian" in + yes) + AC_DEFINE([ERTS_ENDIANNESS], [1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; + no) + AC_DEFINE([ERTS_ENDIANNESS], [-1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; + *) + AC_DEFINE([ERTS_ENDIANNESS], [0], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; + esac + ]) + +AC_C_DOUBLE_MIDDLE_ENDIAN + +dnl fdatasync syscall (Unix only) +AC_CHECK_FUNCS([fdatasync]) + +dnl Find which C libraries are required to use fdatasync +dnl TODO: Remove check once SunOS >= 5.11 is required by erts. +dnl fdatasync requires linking against -lrt on SunOS <= 5.10. +dnl OpenSolaris 2009.06 is SunOS 5.11 and does not require -lrt. +AC_SEARCH_LIBS(fdatasync, [rt]) + + +dnl sendfile syscall +AS_CASE([$host_os], + [linux*|freebsd*|dragonfly*|darwin*], + [ + AC_CHECK_FUNCS([sendfile]) + ], + [solaris*], + [ + AC_SEARCH_LIBS(sendfilev, sendfile, + AC_DEFINE([HAVE_SENDFILEV],[1], + [Define to 1 if you have the `sendfilev' function.])) + ], + [win32], + [ + LIBS="$LIBS -lmswsock" + ]) + +dnl ---------------------------------------------------------------------- +dnl Checks for library functions. +dnl ---------------------------------------------------------------------- + +dnl We may need the thread library and thread flags in order to find right stuff +saved_cppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" +saved_libs=$LIBS +LIBS="$LIBS $EMU_THR_X_LIBS" + +dnl Check if we have these, in which case we'll try to build +dnl inet_gethost with ipv6 support. +AC_CHECK_HEADERS(windows.h) +AC_CHECK_HEADERS(winsock2.h) +AC_CHECK_HEADERS(ws2tcpip.h,[],[],[ +#ifdef HAVE_WINSOCK2_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#endif +]) +dnl AC_CHECK_FUNC(getaddrinfo, have_getaddrinfo=yes, have_getaddrinfo=no) +AC_MSG_CHECKING(for getaddrinfo) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#ifdef HAVE_WINSOCK2_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif +#ifndef __WIN32__ +#include +#include +#endif +]], [[ +getaddrinfo("","",NULL,NULL); +]])],[have_getaddrinfo=yes],[have_getaddrinfo=no]) +if test $have_getaddrinfo = yes; then + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([whether getaddrinfo accepts enough flags]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#ifdef HAVE_WINSOCK2_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif +#ifndef __WIN32__ +#include +#include +#endif +]], [[ + struct addrinfo hints, *ai; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET6; + if (getaddrinfo("::", NULL, &hints, &ai) == 0) { + freeaddrinfo(ai); + exit(0); + } else { + exit(1); + } +]])],[],[have_getaddrinfo=no]) + AC_MSG_RESULT($have_getaddrinfo) + case $have_getaddrinfo in + yes) + AC_DEFINE(HAVE_GETADDRINFO, [1], + [Define to 1 if you have a good `getaddrinfo' function.]);; + *) ;; + esac +else + AC_MSG_RESULT([no]) +fi +AC_MSG_CHECKING(for getnameinfo) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#ifdef HAVE_WINSOCK2_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif +#ifndef __WIN32__ +#include +#include +#endif +]], [[ +getnameinfo(NULL,0,NULL,0,NULL,0,0); +]])],[have_getnameinfo=yes],[have_getnameinfo=no]) +if test $have_getnameinfo = yes; then + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_GETNAMEINFO, [1], + [Define to 1 if you have a good `getnameinfo' function.]) +else + AC_MSG_RESULT([no]) +fi + + +AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2]) + +AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \ + dlvsym pread pwrite memmove strerror strerror_r strncasecmp \ + gethrtime localtime_r gmtime_r mprotect madvise posix_madvise \ + mmap mremap memcpy memrchr mallopt sbrk _sbrk __sbrk brk _brk __brk \ + flockfile fstat strlcpy strlcat setsid posix2time time2posix \ + setlocale nl_langinfo poll mlockall ppoll vsyslog]) + +## We have a special check for inet_pton as AC_CHECK_FUCNS does not work +## on windows 32-bit as there a macro is used to rename the symbol... +AC_MSG_CHECKING([for inet_pton]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#ifdef WIN32 +#include +#else +#include +#endif +]], [[inet_pton(2,"",(void*)0)]])],[have_inet_pton=yes],[have_inet_pton=no]) + +if test $have_inet_pton = yes; then + AC_DEFINE(HAVE_INET_PTON,[1], + [Define to 1 if you have the `inet_pton' function.]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING([for isfinite]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[isfinite(0);]])],[have_isfinite=yes],[have_isfinite=no]) + +if test $have_isfinite = yes; then + AC_DEFINE(HAVE_ISFINITE,[1], + [Define to 1 if you have the `isfinite' function.]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AS_CASE([X$erl_xcomp_posix_memalign], + [Xno], + [], + [Xyes], + [ + have_posix_memalign=yes + ], + [ + AC_CHECK_FUNC( + [posix_memalign], + [AS_IF([test "$cross_compiling" != yes], + [ +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +int main(void) { + void *ptr = NULL; + int error; + size_t alignment = 0x40000, size = 0x20028; + if ((error = posix_memalign(&ptr, alignment, size)) != 0 || ptr == NULL) + return error; + return 0; +} +]])],[have_posix_memalign=yes +],[],[]) + ], + [ + have_posix_memalign=yes + ])]) + ]) + +if test "$have_posix_memalign" = "yes"; then + AC_DEFINE(HAVE_POSIX_MEMALIGN,[1], + [Define to 1 if you have the `posix_memalign' function.]) +fi + + +dnl writev on OS X snow leopard is broken for files > 4GB +case $host_os in + darwin10.8.0) + AC_MSG_CHECKING([for writev]) + AC_MSG_RESULT(no, not stable on OS X Snow Leopard) ;; + *) + AC_CHECK_FUNCS([writev]) ;; +esac + +AC_CHECK_DECLS([posix2time, time2posix],,,[#include ]) + +AC_FUNC_VPRINTF + +dnl The AC_DEFINEs are necessary for autoheader to work. :-( +dnl for gzio +LM_CHECK_FUNC_DECL(fread, [extern int fread();],, + AC_DEFINE(HAVE_CONFLICTING_FREAD_DECLARATION,[1],[Define if you have a decl of fread that conflicts with int fread])) + +dnl Checking with TRY_LINK since putc_unlocked might be (probably is) a macro +AC_CACHE_CHECK([for putc_unlocked], + erts_cv_putc_unlocked, + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int res = putc_unlocked('x',stdout);]])],[erts_cv_putc_unlocked=yes],[erts_cv_putc_unlocked=no])) +if test $erts_cv_putc_unlocked = yes; then + AC_DEFINE(HAVE_PUTC_UNLOCKED, 1, [Define if you have putc_unlocked]) +fi + +dnl Checking with TRY_LINK since fwrite_unlocked might be a macro +AC_CACHE_CHECK([for fwrite_unlocked], + erts_cv_fwrite_unlocked, + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[size_t res = fwrite_unlocked(NULL,sizeof(char),0,stdout);]])],[erts_cv_fwrite_unlocked=yes],[erts_cv_fwrite_unlocked=no])) +if test $erts_cv_fwrite_unlocked = yes; then + AC_DEFINE(HAVE_FWRITE_UNLOCKED, 1, [Define if you have fwrite_unlocked]) +fi + +dnl Need by run_erl. +AC_CHECK_FUNCS([openpty]) + +AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h) +AC_CHECK_FUNCS([getifaddrs]) +AC_CHECK_MEMBERS([struct sockaddr_un.sun_path], [], [], + [[#include ]]) + +dnl Checks for variables in6addr_any and in6addr_loopback, +dnl +dnl They normally declared by netinet/in.h, according to POSIX, +dnl but not on Windows 7 (Windows SDK 7.1). I would have liked +dnl to just write AC_CHECK_DECL([in6addr_any], ...) but if doing so, +dnl the configure check fails erroneously on Linux with the error +dnl "cannot convert to a pointer type", on a line looking like +dnl "char *p = (char *) in6addr_any;", so work around that +dnl with some more code. +AC_CACHE_CHECK( + [whether in6addr_any is declared], + [erts_cv_have_in6addr_any], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + #include + #include + ]], + [[printf("%d", in6addr_any.s6_addr[16]);]] + )], + [erts_cv_have_in6addr_any=yes], + [erts_cv_have_in6addr_any=no] + )] +) + +case "$erts_cv_have_in6addr_any" in + yes) + AC_DEFINE([HAVE_IN6ADDR_ANY], [1], + [Define to 1 if you have the variable in6addr_any declared.]) +esac + +AC_CACHE_CHECK( + [whether in6addr_loopback is declared], + [erts_cv_have_in6addr_loopback], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + #include + #include + ]], + [[printf("%d", in6addr_loopback.s6_addr[16]);]] + )], + [erts_cv_have_in6addr_loopback=yes], + [erts_cv_have_in6addr_loopback=no] + )] +) + +case "$erts_cv_have_in6addr_loopback" in + yes) + AC_DEFINE([HAVE_IN6ADDR_LOOPBACK], [1], + [Define to 1 if you have the variable in6addr_loopback declared.]) +esac + +AC_CHECK_DECLS([IN6ADDR_ANY_INIT, IN6ADDR_LOOPBACK_INIT, IPV6_V6ONLY], [], [], + [ + #include + #include + #include + ]) + +dnl ---------------------------------------------------------------------- +dnl Checks for features/quirks in the system that affects Erlang. +dnl ---------------------------------------------------------------------- + +AC_MSG_CHECKING([for sched_getaffinity/sched_setaffinity]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ +#ifndef CPU_SETSIZE +#error no CPU_SETSIZE +#endif + int res; + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(1, &cpuset); + res = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); + res = sched_getaffinity(0, sizeof(cpu_set_t), &cpuset); + res = CPU_ISSET(1, &cpuset); + CPU_CLR(1, &cpuset); +]])],[sched_xetaffinity=yes],[sched_xetaffinity=no]) +AC_MSG_RESULT([$sched_xetaffinity]) +if test $sched_xetaffinity = yes; then + AC_DEFINE(HAVE_SCHED_xETAFFINITY, 1, [Define if you have sched_getaffinity/sched_setaffinity]) +fi + + +AC_MSG_CHECKING([for pset functionality]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + int res; + psetid_t id = PS_MYID; + int type = PS_PRIVATE; + uint_t numcpus = 1024; + processorid_t cpulist[1024]; + + res = pset_info(id, &type, &numcpus, &cpulist[0]); +]])],[pset_functionality=yes],[pset_functionality=no]) +AC_MSG_RESULT([$pset_functionality]) +if test $pset_functionality = yes; then + AC_DEFINE(HAVE_PSET, 1, [Define if you have pset functionality]) +fi + +AC_MSG_CHECKING([for processor_bind functionality]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +]], [[ + int res = processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL); +]])],[processor_bind_functionality=yes],[processor_bind_functionality=no]) +AC_MSG_RESULT([$processor_bind_functionality]) +if test $processor_bind_functionality = yes; then + AC_DEFINE(HAVE_PROCESSOR_BIND, 1, [Define if you have processor_bind functionality]) +fi + +AC_MSG_CHECKING([for cpuset_getaffinity/cpuset_setaffinity]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +]], [[ + int res; + cpuset_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(1, &cpuset); + res = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset_t), &cpuset); + res = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset_t), &cpuset); + res = CPU_ISSET(1, &cpuset); + CPU_CLR(1, &cpuset); +]])],[cpuset_xetaffinity=yes],[cpuset_xetaffinity=no]) +AC_MSG_RESULT([$cpuset_xetaffinity]) +if test $cpuset_xetaffinity = yes; then + AC_DEFINE(HAVE_CPUSET_xETAFFINITY, 1, [Define if you have cpuset_getaffinity/cpuset_setaffinity]) +fi + +AC_CACHE_CHECK([for 'end' symbol], + erts_cv_have_end_symbol, + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[extern char end; {char *x = &end; *x= 0;}]])],[erts_cv_have_end_symbol=yes],[erts_cv_have_end_symbol=no])]) +if test $erts_cv_have_end_symbol = yes; then + AC_DEFINE(HAVE_END_SYMBOL, 1, [Define if you have the 'end' symbol]) +fi + +AC_CACHE_CHECK([for '_end' symbol], + erts_cv_have__end_symbol, + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[extern char _end; {char *x = &_end; *x= 0;}]])],[erts_cv_have__end_symbol=yes],[erts_cv_have__end_symbol=no])]) +if test $erts_cv_have__end_symbol = yes; then + AC_DEFINE(HAVE__END_SYMBOL, 1, [Define if you have the '_end' symbol]) +fi + +AC_CACHE_CHECK([if __after_morecore_hook can track malloc()s core memory use], + erts_cv___after_morecore_hook_can_track_malloc, + [AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#ifdef HAVE_MALLOC_H +# include +#endif +#if defined(HAVE_END_SYMBOL) +extern char end; +#elif defined(HAVE__END_SYMBOL) +extern char _end; +#endif + +#ifdef ETHR_PTHREADS +# ifdef ETHR_HAVE_PTHREAD_H +# include +# else +# ifdef ETHR_HAVE_MIT_PTHREAD_H +# include +# endif +# endif +# define N_THR 5 +#else +# define N_THR 1 +#endif + +static char *heap_start = NULL; +static char *heap_end = NULL; + +void update_heap_size(void) +{ + heap_end = (char *) sbrk(0); +} + +void init_hook(void) +{ +#if defined(HAVE_END_SYMBOL) + heap_start = &end; +#elif defined(HAVE__END_SYMBOL) + heap_start = &_end; +#else + heap_start = sbrk(0); +#endif + __after_morecore_hook = update_heap_size; +} + +void (*__malloc_initialize_hook) (void) = init_hook; + +static int +check_malloc(int size) +{ + char *p = (char *) malloc(size); + if (!heap_start || !heap_end) return 0; + if (!p) return 0; + if (p < heap_start || heap_end <= p) return 0; + if (p + size < heap_start || heap_end < p + size) return 0; + return 1; +} + +#ifdef ETHR_PTHREADS +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static void * +do_tests(void *vresp) +{ + int i, ok = 0; +#ifdef ETHR_PTHREADS + if (pthread_mutex_lock(&mutex) != 0) + return NULL; +#endif + + for (i = 0; i < 10; i++) + if (!check_malloc(1000)) + goto failed; + for (i = 0; i < 100; i++) + if (!check_malloc(1)) + goto failed; + if (!check_malloc(1024*1024+1)) + goto failed; + if (!check_malloc(10*1024*1024+1)) + goto failed; + ok = 1; + + failed: +#ifdef ETHR_PTHREADS + if (pthread_mutex_unlock(&mutex) != 0) + return NULL; +#endif + if (ok) + *((int *) vresp) = 0; + return NULL; +} + + +int main(void) +{ + int res[N_THR], i; +#ifdef ETHR_PTHREADS + pthread_t tid[N_THR]; +#endif + +#if defined(HAVE_MALLOPT) && defined(M_MMAP_MAX) + (void) mallopt(M_MMAP_MAX, 0); +#endif + + for (i = 0; i < N_THR; i++) + res[i] = 1; +#ifdef ETHR_PTHREADS + for (i = 1; i < N_THR; i++) + if (pthread_create(&tid[i], NULL, do_tests, &res[i]) != 0) + return 1; +#endif + (void) do_tests(&res[0]); +#ifdef ETHR_PTHREADS + for (i = 1; i < N_THR; i++) + if (pthread_join(tid[i], NULL) != 0) + return 1; +#endif + for (i = 0; i < N_THR; i++) + if (res[i]) + return 1; + return 0; +} + ]])],[erts_cv___after_morecore_hook_can_track_malloc=yes],[erts_cv___after_morecore_hook_can_track_malloc=no],[ + case X$erl_xcomp_after_morecore_hook in + X) erts_cv___after_morecore_hook_can_track_malloc=cross;; + Xyes|Xno) erts_cv___after_morecore_hook_can_track_malloc=$erl_xcomp_after_morecore_hook;; + *) AC_MSG_ERROR([Bad erl_xcomp_after_morecore_hook value: $erl_xcomp_after_morecore_hook]);; + esac + + ])]) + +case $erts_cv___after_morecore_hook_can_track_malloc in + yes) AC_DEFINE(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC, 1, \ +[Define if __after_morecore_hook can track malloc()s core memory use.]);; + cross) AC_MSG_WARN([result no guessed because of cross compilation]);; + *) ;; +esac + +AS_IF([test "x$ac_cv_func_sbrk" = "xyes"], + [ + AC_CACHE_CHECK([types of sbrk()s return value and argument], + erts_cv_sbrk_ret_arg_types, + [ + + erts_cv_sbrk_ret_arg_types=unknown + ret_types="void *,char *" + arg_types="intptr_t,ptrdiff_t,int,long" + save_ifs="$IFS"; IFS="," + for rtype in $ret_types; do + for atype in $arg_types; do + IFS=$save_ifs + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], [[$rtype sbrk($atype incr);]])],[erts_cv_sbrk_ret_arg_types="$rtype,$atype"],[]) + IFS="," + if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then + break 2 + fi + done + done + IFS=$save_ifs]) + + if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then + save_ifs="$IFS"; IFS="," + read ret_type arg_type < + #include ]], [[$rtype brk($atype endds);]])],[erts_cv_brk_ret_arg_types="$rtype,$atype"],[]) + IFS="," + if test "$erts_cv_brk_ret_arg_types" != "unknown"; then + break 2 + fi + done + done + IFS=$save_ifs]) + + if test "$erts_cv_brk_ret_arg_types" != "unknown"; then + save_ifs="$IFS"; IFS="," + read ret_type arg_type < +#include +#include +#ifdef HAVE_DLFCN_H +# include +#endif + +/* + * Our implementation requires that we have sbrk(), and 'end' or '_end'. + */ + +#if !defined(HAVE_SBRK) +# error no sbrk() +#endif +#if defined(HAVE_END_SYMBOL) +extern char end; +#elif defined(HAVE__END_SYMBOL) +extern char _end; +#else +# error no 'end' nor '_end' +#endif + +#ifdef ETHR_PTHREADS +# ifdef ETHR_HAVE_PTHREAD_H +# include +# else +# ifdef ETHR_HAVE_MIT_PTHREAD_H +# include +# endif +# endif +# define N_THR 5 +#else +# define N_THR 1 +#endif + +#define SBRK_IMPL(RET_TYPE, SBRK, ARG_TYPE) \ +RET_TYPE SBRK (ARG_TYPE); \ +static RET_TYPE (*real_ ## SBRK)(ARG_TYPE) = NULL; \ +RET_TYPE \ +SBRK (ARG_TYPE arg) \ +{ \ + RET_TYPE res; \ + if (!real_ ## SBRK) real_ ## SBRK = dlsym(RTLD_NEXT, #SBRK); \ + res = (*real_ ## SBRK)(arg); \ + if (res != (RET_TYPE) -1) heap_end = (char *) (*real_ ## SBRK)(0); \ + return res; \ +} + +#define BRK_IMPL(RET_TYPE, BRK, ARG_TYPE) \ +RET_TYPE BRK (ARG_TYPE); \ +static RET_TYPE (*real_ ## BRK)(ARG_TYPE) = NULL; \ +RET_TYPE \ +BRK (ARG_TYPE arg) \ +{ \ + RET_TYPE res; \ + if (!real_ ## BRK) real_ ## BRK = dlsym(RTLD_NEXT, #BRK); \ + res = (*real_ ## BRK)(arg); \ + if (res != (RET_TYPE) -1) heap_end = (char *) arg; \ + return res; \ +} + +static char *heap_start = NULL; +static char *heap_end = NULL; + +SBRK_IMPL(SBRK_RET_TYPE, sbrk, SBRK_ARG_TYPE) +#ifdef HAVE_BRK + BRK_IMPL(BRK_RET_TYPE, brk, BRK_ARG_TYPE) +#endif + +#ifdef HAVE__SBRK + SBRK_IMPL(SBRK_RET_TYPE, _sbrk, SBRK_ARG_TYPE) +#endif +#ifdef HAVE__BRK + BRK_IMPL(BRK_RET_TYPE, _brk, BRK_ARG_TYPE) +#endif + +#ifdef HAVE___SBRK + SBRK_IMPL(SBRK_RET_TYPE, __sbrk, SBRK_ARG_TYPE) +#endif +#ifdef HAVE___BRK + BRK_IMPL(BRK_RET_TYPE, __brk, BRK_ARG_TYPE) +#endif + +static int +check_malloc(int size) +{ + char *p = (char *) malloc(size); + if (!heap_start || !heap_end) return 0; + if (!p) return 0; + if (p < heap_start || heap_end <= p) return 0; + if (p + size < heap_start || heap_end < p + size) return 0; + return 1; +} + +#ifdef ETHR_PTHREADS +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static void * +do_tests(void *vresp) +{ + int i, ok = 0; +#ifdef ETHR_PTHREADS + if (pthread_mutex_lock(&mutex) != 0) + return NULL; +#endif + + for (i = 0; i < 10; i++) + if (!check_malloc(1000)) + goto failed; + for (i = 0; i < 100; i++) + if (!check_malloc(1)) + goto failed; + if (!check_malloc(1024*1024+1)) + goto failed; + if (!check_malloc(10*1024*1024+1)) + goto failed; + ok = 1; + + failed: +#ifdef ETHR_PTHREADS + if (pthread_mutex_unlock(&mutex) != 0) + return NULL; +#endif + if (ok) + *((int *) vresp) = 0; + return NULL; +} + + +int main(void) +{ + int res[N_THR], i; +#ifdef ETHR_PTHREADS + pthread_t tid[N_THR]; +#endif +#if defined(HAVE_END_SYMBOL) + heap_start = &end; +#elif defined(HAVE__END_SYMBOL) + heap_start = &_end; +#endif + +#if defined(HAVE_MALLOPT) && defined(M_MMAP_MAX) + (void) mallopt(M_MMAP_MAX, 0); +#endif + + for (i = 0; i < N_THR; i++) + res[i] = 1; +#ifdef ETHR_PTHREADS + for (i = 1; i < N_THR; i++) + if (pthread_create(&tid[i], NULL, do_tests, &res[i]) != 0) + return 1; +#endif + (void) do_tests(&res[0]); +#ifdef ETHR_PTHREADS + for (i = 1; i < N_THR; i++) + if (pthread_join(tid[i], NULL) != 0) + return 1; +#endif + for (i = 0; i < N_THR; i++) + if (res[i]) + return 1; + return 0; +} + ]])],[erts_cv_brk_wrappers_can_track_malloc=yes],[erts_cv_brk_wrappers_can_track_malloc=no],[ + case X$erl_xcomp_dlsym_brk_wrappers in + X) erts_cv_brk_wrappers_can_track_malloc=cross;; + Xyes|Xno) erts_cv_brk_wrappers_can_track_malloc=$erl_xcomp_dlsym_brk_wrappers;; + *) AC_MSG_ERROR([Bad erl_xcomp_dlsym_brk_wrappers value: $erl_xcomp_dlsym_brk_wrappers]);; + esac + ])]) + case $erts_cv_brk_wrappers_can_track_malloc in + yes) + AC_DEFINE(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC, 1, \ +[Define if sbrk()/brk() wrappers can track malloc()s core memory use]);; + cross) + AC_MSG_WARN([result no guessed because of cross compilation]);; + *) ;; + esac + ]) + +dnl Restore LIBS +LIBS=$saved_libs +dnl restore CPPFLAGS +CPPFLAGS=$saved_cppflags + +case $ARCH in + x86|amd64) + AC_DEFINE(ERTS_STRUCTURE_ALIGNED_ALLOC, 1, [Define if structure alignment is enough for allocators. If not defined, 64-bit alignment will be forced.]);; + *) + ;; +esac + +LM_SYS_IPV6 +LM_SYS_MULTICAST +ERL_TIME_CORRECTION +AC_CHECK_PROG(M4, m4, m4) + + +dnl Test if JIT can be enabled +JIT_ARCH= +AS_IF([test ${enable_jit} != no], + [ + case "$ARCH" in + amd64) + JIT_ARCH=x86 + ;; + arm64) + case "$OPSYS" in + win32|darwin) + # These platforms have dedicated system calls for clearing + # instruction cache, and don't require us to manually issue + # instruction barriers on all threads. + JIT_ARCH=arm + ;; + *) + # We need to use `DC CVAU`, `IC IVAU`, and `ISB SY` to clear + # instruction cache. These have already been tested as part of + # ETHR_CHK_GCC_ATOMIC_OPS([]). + + if test "$ethr_arm_isb_sy_instr_val$ethr_arm_dc_cvau_instr_val$ethr_arm_ic_ivau_instr_val" = "111"; then + JIT_ARCH=arm + else + enable_jit=no + AC_MSG_WARN([JIT disabled due to lack of cache-clearing instructions]) + fi + ;; + esac + ;; + *) + if test ${enable_jit} = yes; then + AC_MSG_ERROR([JIT only works on x86 64-bit and ARM 64-bit]) + else + enable_jit=no + AC_MSG_WARN([JIT disabled due to lack to support on $ARCH-$OPSYS]) + fi + ;; + esac + + AS_IF([test ${enable_jit} != no], + [ + AS_IF([test "$CXX" != false], + [ + AC_LANG_PUSH(C++) + old_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS -std=c++17" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]], + [[#if __cplusplus < 201703L + #error "Needs C++17 compiler" + #endif]])], + [AC_MSG_CHECKING([for C++17 support]) + AC_MSG_RESULT([yes]) + HAVE_CXX17=true], + [AC_MSG_CHECKING([for C++17 support]) + AC_MSG_RESULT([no]) + HAVE_CXX17=false]) + AC_LANG_POP() + ]) + if test "$CXX" = false -o "$HAVE_CXX17" = false; then + if test ${enable_jit} = yes; then + AC_MSG_ERROR([JIT needs a C++ compiler with C++17 support]) + else + enable_jit=no + cat >> $ERL_TOP/erts/CONF_INFO <]], [[#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) + #define __DARWIN__ 1 + #endif + #if !(defined(__GLIBC__) || defined(__DARWIN__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__sun__)) + #error "Unknown libc. Assume musl, which does not allow safe signals" + #endif]])],[AC_MSG_RESULT([yes]) + enable_native_stack=yes],[AC_MSG_RESULT([no, disabling native stack in JIT]) + enable_native_stack=no + ]) + ]) + + case "$JIT_ARCH" in + x86) + if test X${enable_native_stack} = Xyes; then + AC_DEFINE(NATIVE_ERLANG_STACK, [], + [Define if we can use the native stack for Erlang code]) + fi + ;; + arm) + # ARM JIT doesn't support native stack due to its 16-byte alignment + # requirement. + enable_native_stack=no + ;; + *) + ;; + esac + ]) + +dnl +dnl Check if the `perf` profiler is supported. At the moment it assumes it +dnl always works on Linux as we're not dependent on it; this is only used to +dnl to control whether we accept `perf`-related options. +dnl +case $OPSYS in + linux*) + if test X${enable_native_stack} = Xyes; then + AC_DEFINE(ERLANG_FRAME_POINTERS, [], + [Define if we need frame pointers on the Erlang stack]) + fi + + AC_DEFINE(HAVE_LINUX_PERF_SUPPORT, 1, + [Define if the targeted system supports the `perf` profiler]) + ;; + *) + ;; +esac + +dnl +dnl Some operating systems allow you to redefine FD_SETSIZE to be able +dnl to select on more than the default number of file descriptors. +dnl We first discovered this in BSD/OS where the default is ridiculously +dnl low (256). But since we use a lot of file descriptors we found the +dnl need to go over the limit in other os's as well. Since FD_SETSIZE +dnl must be defined before pulling in sys/types.h the actual number +dnl of file descriptors is set in acconfig.h and will thus be in config.h +dnl which *always* should be included first. +dnl + +AC_MSG_CHECKING([whether to redefine FD_SETSIZE]) +case $host_os in + bsdi*) + AC_DEFINE(REDEFINE_FD_SETSIZE,[],[Define if you wish to redefine FD_SETSIZE to be able to select on more fd]) + AC_MSG_RESULT(yes) + ;; + *) + AC_MSG_RESULT(no) + ;; +esac + + + +dnl ---------------------------------------------------------------------- +dnl Tests related to configurable options given on command line +dnl (using the --disable, --enable and --with switches). +dnl ---------------------------------------------------------------------- + +JIT_ENABLED= +FLAVORS="emu jit" +# Enable jit +if test X${enable_jit} = Xyes; then + JIT_ENABLED=yes + PRIMARY_FLAVOR=jit +else + PRIMARY_FLAVOR=emu +fi + +AC_SUBST(JIT_ENABLED) +AC_SUBST(JIT_ARCH) +AC_SUBST(PRIMARY_FLAVOR) +AC_SUBST(FLAVORS) + +# +# Check for working poll(). +# +AC_MSG_CHECKING([for working poll()]) +AS_IF([test "x$ac_cv_header_poll_h" != "xyes" -o "x$ac_cv_func_poll" != "xyes"], +[ + +poll_works=no + +], +[ + +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +main() +{ +#ifdef _POLL_EMUL_H_ + exit(1); /* Implemented using select() -- fail */ +#else + struct pollfd fds[1]; + int fd; + fd = open("/dev/null", 1); + fds[0].fd = fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + if (poll(fds, 1, 0) < 0 || (fds[0].revents & POLLNVAL) != 0) { + exit(1); /* Does not work for devices -- fail */ + } + exit(0); +#endif +} +]])],[poll_works=yes],[poll_works=no],[ +case X$erl_xcomp_poll in + X) poll_works=cross;; + Xyes|Xno) poll_works=$erl_xcomp_poll;; + *) AC_MSG_ERROR([Bad erl_xcomp_poll value: $erl_xcomp_poll]);; +esac +]) + +]) + +case $poll_works-$host_os in + no-*|cross-darwin*) + # + # The USE_SELECT define is used by the ssl application (should not + # be used by erts). + # + AC_DEFINE(USE_SELECT, 1, [Define if select() should be used instead of poll()]) + if test $poll_works = cross; then + AC_MSG_RESULT(cross) + AC_MSG_WARN([result no guessed based on OS ($host_os) because of cross compilation]) + else + AC_MSG_RESULT([no; non-existing, broken, or based on select()]) + fi + poll_works=no;; + yes-*|cross-*) + AC_DEFINE(ERTS_USE_POLL, 1, [Define if poll() should be used instead of select()]) + if test $poll_works = cross; then + AC_MSG_RESULT(cross) + AC_MSG_WARN([result yes guessed based on OS ($host_os) because of cross compilation]) + else + AC_MSG_RESULT(yes) + fi + poll_works=yes;; +esac + +# +# If kqueue() found +# +if test $have_kernel_poll = kqueue; then +## Some OS X kernel version seems to have bugs in them with regards to kqueue +## Disable kernel poll on those versions + AC_MSG_CHECKING([whether host os has known kqueue bugs]) + case $host_os in + # Any OS X version < 16 has known problems with using kqueue + # so we don't use it there. See erl_poll.c for details. + darwin[[0-9]].*|darwin1[[0-5]].*) + AC_MSG_RESULT([yes, disabling kernel poll]) + have_kernel_poll=no + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +# +# If epoll() found, check that it is level triggered. +# +AS_IF([test $have_kernel_poll = epoll], + [ + AC_MSG_CHECKING([whether epoll is level triggered]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + #ifdef EPOLLET + /* Edge triggered option exist, assume level triggered + is default */ + ; + #else + /* No edge triggered option exist; assume edge + triggered only */ + #error No EPOLLET + #endif + ]])],[level_triggered_epoll=yes],[level_triggered_epoll=no + have_kernel_poll=no]) + AC_MSG_RESULT([$level_triggered_epoll]) + ]) +# +# Check if we should enable kernel poll support +# +AC_MSG_CHECKING(whether kernel poll support should be enabled) +ERTS_ENABLE_KERNEL_POLL=no +ERTS_BUILD_FALLBACK_POLL=no +case $enable_kernel_poll-$have_kernel_poll in + no-*) + AC_MSG_RESULT(no; disabled by user);; + yes-no) + AC_MSG_ERROR(no; kernel poll support requested but not found);; + *-no) + AC_MSG_RESULT(no);; + *) + case $have_kernel_poll in + epoll) + AC_DEFINE(HAVE_SYS_EPOLL_H, 1, [Define if you have the header file.]) + ERTS_BUILD_FALLBACK_POLL=yes + ;; + /dev/poll) + AC_DEFINE(HAVE_SYS_DEVPOLL_H, 1, [Define if you have header file.]) + ;; + kqueue) + AC_DEFINE(HAVE_SYS_EVENT_H, 1, [Define if you have header file.]) + ERTS_BUILD_FALLBACK_POLL=yes + ;; + *) + AC_MSG_ERROR(configure.in need to be updated);; + esac + ERTS_ENABLE_KERNEL_POLL=yes + AC_DEFINE(ERTS_ENABLE_KERNEL_POLL, 1, [Define if you have kernel poll and want to use it]) + AC_MSG_RESULT([yes; $have_kernel_poll]);; +esac +AC_SUBST(ERTS_BUILD_FALLBACK_POLL) + +AC_MSG_CHECKING([whether putenv() stores a copy of the key-value pair]) +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +int main(void) { + int i; + char *env; + char buf[10]; + for (i = 0; i < 7; i++) + buf[i] = 'X'; + buf[i] = '\0'; + buf[3] = '='; + if (putenv(buf) != 0) + return 1; + for (i = 4; i < 7; i++) + buf[i] = 'Y'; + env = getenv("XXX"); + if (!env) + return 2; + for (i = 0; i < 3; i++) + if (env[i] != 'X') + return 3; + for (i = 0; i < 3; i++) + buf[i] = 'Y'; + env = getenv("XXX"); + if (!env) + return 4; + for (i = 0; i < 3; i++) + if (env[i] != 'X') + return 5; + return 0; +} +]])],[copying_putenv=yes],[copying_putenv=no],[ +case X$erl_xcomp_putenv_copy in + X) copying_putenv=cross;; + Xyes|Xno) copying_putenv=$erl_xcomp_putenv_copy;; + *) AC_MSG_ERROR([Bad erl_xcomp_putenv_copy value: $erl_xcomp_putenv_copy]);; +esac +]) + +AC_MSG_RESULT($copying_putenv) +case $copying_putenv in + yes) + AC_DEFINE(HAVE_COPYING_PUTENV,[1],\ +[Define if you have a putenv() that stores a copy of the key-value pair]);; + cross) + AC_MSG_WARN([result no guessed because of cross compilation]);; + *) ;; +esac + +dnl ---------------------------------------------------------------------- +dnl Stuff that should be moved into their respective application +dnl ---------------------------------------------------------------------- + +dnl +dnl We should look for a compiler that handles jump tables, for beam_emu +dnl to be optimized +dnl + +LM_FIND_EMU_CC + +dnl +dnl DTrace & LTTNG +dnl +AS_CASE([$DYNAMIC_TRACE_FRAMEWORK], + [dtrace|systemtap], + [ + AC_CHECK_TOOL(DTRACE, dtrace, none) + test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]); + enable_lttng_test=no + enable_dtrace_test=yes + ], + [lttng], + [ + enable_lttng_test=yes + enable_dtrace_test=no + ], + [ + enable_lttng_test=no + enable_dtrace_test=no + ]) + +AC_SUBST(DTRACE) + +AC_SUBST(DTRACE_CPP) +AC_SUBST(DTRACE_ENABLED) +AC_SUBST(DTRACE_ENABLED_2STEP) +DTRACE_CPP=-C +DTRACE_ENABLED= +DTRACE_ENABLED_2STEP= +DTRACE_2STEP_TEST=./dtrace-test.o +DTRACE_BITS_FLAG= +case $OPSYS in + freebsd) + if test "$BITS64" = "yes" ; then + DTRACE_BITS_FLAG=-64 + else + DTRACE_BITS_FLAG=-32 + fi + ;; + *) + : # Nothing to do + ;; +esac +AS_IF([test "$enable_dtrace_test" = "yes"], + [ + AS_IF([test "$DTRACE" = "dtrace"], + [ + AC_CHECK_HEADERS(sys/sdt.h) + AC_MSG_CHECKING([for 1-stage DTrace precompilation]) + # The OS X version of dtrace prints a spurious line here. + if ! dtrace -h $DTRACE_CPP -Iemulator/beam -o ./foo-dtrace.h -s emulator/beam/erlang_dtrace.d; then + AC_MSG_ERROR([Could not precompile erlang_dtrace.d: dtrace -h failed]) + fi + AC_MSG_RESULT([yes]) + + AC_MSG_CHECKING([for 2-stage DTrace precompilation]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include "foo-dtrace.h" ]], [[ERLANG_DIST_PORT_BUSY_ENABLED();]])],[rm -f $DTRACE_2STEP_TEST + dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&AS_MESSAGE_LOG_FD + if test -f $DTRACE_2STEP_TEST; then + rm -f $DTRACE_2STEP_TEST + DTRACE_ENABLED_2STEP=yes + fi],[]) + rm -f foo-dtrace.h + AS_IF([test "x$DTRACE_ENABLED_2STEP" = "xyes"], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + + DTRACE_ENABLED=yes + case $OPSYS in + linux) + : # No extra libs to add to LIBS + ;; + freebsd) + LIBS="$LIBS -lelf" + ;; + *) + LIBS="$LIBS -ldtrace" + ;; + esac + ], + [ + AC_MSG_ERROR([Dtrace preprocessing test failed.]) + ]) + ]) + +AS_IF([test "$enable_lttng_test" = "yes"], + [ + AC_CHECK_HEADERS(lttng/tracepoint.h) + AC_CHECK_HEADERS(lttng/tracepoint-event.h) + dnl The macro tracepoint_enabled is not present in older lttng versions + dnl checking for tracepoint_enabled + AC_MSG_CHECKING([for tracepoint_enabled in lttng/tracepoint.h]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #define TRACEPOINT_PROVIDER org_erlang_otp + TRACEPOINT_EVENT( + org_erlang_otp, + dummy, + TP_ARGS(int, my_int), + TP_FIELDS(ctf_integer(int, my_int, my_int))) + #define TRACEPOINT_CREATE_PROBES + #define TRACEPOINT_DEFINE]], + [[if(tracepoint_enabled(org_erlang_otp,dummy)) do {} while(0)]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_ERROR([no (available in lttng-ust v2.7)])]) + if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \ + -a "x$ac_cv_header_lttng_tracepoint_event_h" = "xyes"; then + # No straight forward way to test for liblttng-ust when no public symbol exists, + # just add the lib. + LIBS="$LIBS -llttng-ust -ldl" + else + AC_MSG_ERROR([No LTTng support found.]) + fi + ]) + + +#-------------------------------------------------------------------- +# Os mon stuff. +#-------------------------------------------------------------------- +AC_SUBST(os_mon_programs) +AC_SUBST(CPU_SUP_LIBS) + +AC_CHECK_LIB(kstat, kstat_open, [ + use_cpu_sup=yes + CPU_SUP_LIBS="$CPU_SUP_LIBS -lkstat" + ]) + +AC_CHECK_LIB(kvm, kvm_open, [ + use_cpu_sup=yes + CPU_SUP_LIBS="$CPU_SUP_LIBS -lkvm" + ]) + +case $host_os in + solaris2*) + os_mon_programs="$os_mon_programs ferrule mod_syslog" ;; + darwin*) + use_cpu_sup=yes ;; + openbsd*) + use_cpu_sup=yes ;; + linux*) + use_cpu_sup=yes ;; + freebsd*) + use_cpu_sup=yes ;; +esac + +if test "$use_cpu_sup" = "yes"; then + os_mon_programs="$os_mon_programs cpu_sup" +fi + +AC_ARG_WITH(javac, +AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) +AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) +AS_HELP_STRING([--without-javac], [don't use any Java compiler])) + +dnl +dnl Then there are a number of apps which needs a java compiler... +dnl +need_java="jinterface" + +if test -d $ERL_TOP/lib/ic; then + need_java="$need_java ic/java_src" +fi + +# Remove all SKIP files from previous runs +for a in $need_java ; do + rm -f $ERL_TOP/lib/$a/SKIP +done + +if test "X$with_javac" = "Xno"; then + for a in $need_java ; do + echo "Java compiler disabled by user" > $ERL_TOP/lib/$a/SKIP + done + +else # begin - try to find javac + +if test "X$with_javac" != "Xyes" -a "X$with_javac" != "X"; then + check_javac=$with_javac +else + check_javac="javac.sh javac guavac gcj jikes bock" +fi + +AC_CHECK_PROGS(JAVAC, $check_javac) +AS_IF([test -n "$JAVAC"], + [ + dnl Make sure it's at least JDK 1.6 + AC_CACHE_CHECK(for JDK version 1.6, + ac_cv_prog_javac_ver_1_6, + [ERL_TRY_LINK_JAVA([], [for (String i : args);], + ac_cv_prog_javac_ver_1_6=yes, ac_cv_prog_javac_ver_1_6=no)]) + if test $ac_cv_prog_javac_ver_1_6 = no; then + unset -v JAVAC + fi + ]) +if test -z "$JAVAC"; then + + if test "X$with_javac" != "X"; then + AC_MSG_ERROR([No java compiler found in PATH (checked for $check_javac)]) + fi + + AC_MSG_WARN([Could not find any usable java compiler, will skip: jinterface]) + + for a in $need_java ; do + echo "No Java compiler found" > $ERL_TOP/lib/$a/SKIP + done +fi + +fi # end - try to find javac + +dnl ---------------------------------------------------------------------- +dnl Include CPPFLAGS in CFLAGS +dnl ---------------------------------------------------------------------- +CFLAGS="$CFLAGS $CPPFLAGS" + +# +# Currently if we compile for 64 bits we want to compile +# some external port programs using 32 bits +# + +# If not defined we trust the C compiler in $CC to do 32 bits +if test -z "$CC32"; then + CC32="$CC" +fi + +if test -z "$CFLAGS32"; then + if test $ac_cv_sizeof_void_p != 4; then + # We are compiling default 64 bits and use -m32 for 32 bit compilations + CFLAGS32="$CFLAGS -m32" + else + CFLAGS32="$CFLAGS" + fi +fi + +AC_SUBST(CC32) +AC_SUBST(CFLAGS32) + +dnl +dnl ERTS_EMU_CMDLINE_FLAGS will force modification of config.h when +dnl the emulator command line flags are modified by configure, which +dnl in turn will make 'make' detect that files depending on config.h +dnl needs to be rebuilt. +dnl + +AC_DEFINE_UNQUOTED(ERTS_EMU_CMDLINE_FLAGS, +"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS", +[The only reason ERTS_EMU_CMDLINE_FLAGS exists is to force modification of config.h when the emulator command line flags are modified by configure]) + +AC_SUBST(STATIC_CFLAGS) + +dnl --------------------------------------------------------------------- +dnl Autoheader macro for adding code at top and bottom of config.h.in +dnl --------------------------------------------------------------------- +AH_TOP([ +#ifndef __ERTS_CONFIG_H__ +#define __ERTS_CONFIG_H__ + +#define GHBN_R_SOLARIS 2 +#define GHBN_R_AIX 3 +#define GHBN_R_GLIBC 4 +]) + +AH_BOTTOM([ +/* Redefine in6_addr. XXX this should be moved to the files where it's used? */ +#ifdef HAVE_IN_ADDR6_STRUCT +#define in6_addr in_addr6 +#endif + +/* Define a reasonable default for INADDR_LOOPBACK */ +/* XXX this should be moved to the files where it's used? */ +#ifdef HAVE_NO_INADDR_LOOPBACK +#define INADDR_LOOPBACK (u_long)0x7F000001 +#endif + +#ifdef REDEFINE_FD_SETSIZE +#define FD_SETSIZE 1024 +#endif + +#ifdef HAVE_GETHRVTIME_PROCFS_IOCTL +#define HAVE_GETHRVTIME +#endif + +#if !defined(HAVE_ISFINITE) && !defined(HAVE_FINITE) +# if defined(HAVE_ISINF) && defined(HAVE_ISNAN) +# define USE_ISINF_ISNAN +# endif +#endif + +#if defined(DEBUG) && !defined(ERTS_ENABLE_LOCK_CHECK) +#define ERTS_ENABLE_LOCK_CHECK 1 +#endif + +#endif /* __ERTS_CONFIG_H__ */ +]) + +dnl ---------------------------------------------------------------------- +dnl Check for log2 +dnl ---------------------------------------------------------------------- +AC_CHECK_FUNCS([log2]) + + +dnl ---------------------------------------------------------------------- +dnl Check for GCC diagnostic ignored "-Waddress-of-packed-member" +dnl ---------------------------------------------------------------------- +saved_CFLAGS="$CFLAGS" +CFLAGS="-Werror $CFLAGS" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[_Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") + _Pragma("GCC diagnostic pop") + ]])],[AC_DEFINE(HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER,1, + define if compiler support _Pragma('GCC diagnostic ignored '-Waddress-of-packed-member''))],[]) +CFLAGS="$saved_CFLAGS" + + +dnl ---------------------------------------------------------------------- +dnl Enable any -Werror flags +dnl ---------------------------------------------------------------------- + +if test "x$GCC" = xyes; then + CFLAGS="$WERRORFLAGS $CFLAGS" +fi + +dnl ---------------------------------------------------------------------- +dnl Enable build determinism flag +dnl ---------------------------------------------------------------------- + +AC_ARG_ENABLE(deterministic-build, +AS_HELP_STRING([--enable-deterministic-build], [enable build determinism, stripping absolute paths from build output]), +[ case "$enableval" in + no) ERL_DETERMINISTIC=no ;; + *) ERL_DETERMINISTIC=yes ;; + esac ], +ERL_DETERMINISTIC=no) +AC_SUBST(ERL_DETERMINISTIC) + +AC_MSG_CHECKING([CFLAGS for -O switch]) +dnl Remove all "-O*" options +no_opt_CFLAGS=$(echo " $CFLAGS" | sed 's/ -O[[^ ]]*/ /g') +if test "X $CFLAGS" = "X$no_opt_CFLAGS"; then + AC_MSG_ERROR([ + CFLAGS must contain a -O flag. If you need to edit the CFLAGS you probably + also want to add the default CFLAGS. The default CFLAGS are "-O2 -g". + If you want to build ERTS without any optimization, pass -O0 to CFLAGS.]) +fi +AC_MSG_RESULT([yes]) +DEBUG_CFLAGS="-g -O0 $no_opt_CFLAGS" +AC_SUBST(DEBUG_CFLAGS) + +dnl ---------------------------------------------------------------------- +dnl Output the result. +dnl ---------------------------------------------------------------------- + +dnl Note that the output files are relative to $srcdir +AC_CONFIG_FILES([ + emulator/$host/Makefile:emulator/Makefile.in + epmd/src/$host/Makefile:epmd/src/Makefile.in + etc/common/$host/Makefile:etc/common/Makefile.in + include/internal/$host/ethread.mk:include/internal/ethread.mk.in + include/internal/$host/erts_internal.mk:include/internal/erts_internal.mk.in + lib_src/$host/Makefile:lib_src/Makefile.in + ../make/$host/otp.mk:../make/otp.mk.in +]) + +AC_CONFIG_FILES([../make/make_emakefile:../make/make_emakefile.in], + [chmod +x ../make/make_emakefile]) + +dnl +dnl The ones below should be moved to their respective lib +dnl +AC_CONFIG_FILES([ + ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in + ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in + ]) + +AC_CONFIG_FILES([../make/install_dir_data.sh:../make/install_dir_data.sh.in], [chmod +x ../make/install_dir_data.sh]) + +AC_OUTPUT diff --git a/erts/configure.in b/erts/configure.in deleted file mode 100644 index beff4275f8b4..000000000000 --- a/erts/configure.in +++ /dev/null @@ -1,3657 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -*-m4-*- - -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 1997-2022. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% - -dnl The string "FIXME convbreak" means that there is a break of -dnl autoconf convention that should be cleaned up. - -AC_INIT(vsn.mk) -AC_PREREQ(2.59) - -LM_PRECIOUS_VARS - -dnl We check if -Werror was given on command line and if so -dnl we disable it for the configure and only use it when -dnl actually building erts -no_werror_CFLAGS=$(echo "$CFLAGS" | sed 's/-Werror\([[^=]]\|$\)/ /g') -if test "$CFLAGS" != "$no_werror_CFLAGS"; then - CFLAGS="$no_werror_CFLAGS" - WERRORFLAGS=-Werror -fi - -dnl How to set srcdir absolute is taken from the GNU Emacs distribution -#### Make srcdir absolute, if it isn't already. It's important to -#### avoid running the path through pwd unnecessary, since pwd can -#### give you automounter prefixes, which can go away. -case "${srcdir}" in - /* ) ;; - . ) - ## We may be able to use the $PWD environment variable to make this - ## absolute. But sometimes PWD is inaccurate. - ## Make sure CDPATH doesn't affect cd (in case PWD is relative). - CDPATH= - if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; - then - srcdir="$PWD" - else - srcdir="`(cd ${srcdir}; pwd)`" - fi - ;; - * ) srcdir="`(cd ${srcdir}; pwd)`" ;; -esac - -## Now, make sure that ERL_TOP is set and is the same as srcdir -## -if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then - AC_MSG_ERROR(You need to set the environment variable ERL_TOP!) -fi -if test x"${ERL_TOP}/erts" != x"$srcdir"; then - AC_MSG_ERROR([You need to run configure with argument --srcdir=${ERL_TOP}/erts]) -fi -erl_top=${ERL_TOP} - -# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -# echo X -# echo "X srcdir = $srcdir" -# echo "X ERL_TOP = $ERL_TOP" -# echo X -# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - -AC_CONFIG_AUX_DIRS($srcdir/autoconf) - -dnl ---------------------------------------------------------------------- -dnl Figure out what system we are running on. -dnl ---------------------------------------------------------------------- - -# -# To configure for free source run ./configure --host=free_source -# -dnl -dnl AC_CANONICAL_HOST does not like free_source as a host specification, -dnl so we make a little special case. -dnl -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -else - host_os=$host -fi - -if test "$cross_compiling" = "yes"; then - CROSS_COMPILING=yes -else - CROSS_COMPILING=no -fi -AC_SUBST(CROSS_COMPILING) - -ERL_XCOMP_SYSROOT_INIT - -AC_ISC_POSIX - -AC_CONFIG_HEADER($host/config.h:config.h.in include/internal/$host/ethread_header_config.h:include/internal/ethread_header_config.h.in include/$host/erl_int_sizes_config.h:include/erl_int_sizes_config.h.in) -dnl ---------------------------------------------------------------------- -dnl Optional features. -dnl ---------------------------------------------------------------------- -ENABLE_ALLOC_TYPE_VARS= -AC_SUBST(ENABLE_ALLOC_TYPE_VARS) - -AC_ARG_ENABLE(bootstrap-only, -AS_HELP_STRING([--enable-bootstrap-only], - [enable bootstrap only configuration]), -[ if test "X$enableval" = "Xyes"; then - # Disable stuff not necessary in a bootstrap only system in order - # to speed up things by reducing the amount of stuff needing to be - # built... - with_termcap=no - with_ssl=no - with_ssl_zlib=no - enable_jit=no - enable_sctp=no - fi -]) - -AC_ARG_ENABLE(dirty-schedulers-test, -AS_HELP_STRING([--enable-dirty-schedulers-test], [enable dirty scheduler test (for debugging purposes)]), -[ case "$enableval" in - yes) enable_dirty_schedulers_test=yes ;; - *) enable_dirty_schedulers_test=no ;; - esac ], enable_dirty_schedulers_test=no) - -AC_ARG_ENABLE(smp-require-native-atomics, - AS_HELP_STRING([--disable-smp-require-native-atomics], - [disable the SMP requirement of a native atomic implementation]), -[ case "$enableval" in - no) smp_require_native_atomics=no ;; - *) smp_require_native_atomics=yes ;; - esac ], smp_require_native_atomics=yes) - -AC_ARG_WITH(termcap, -AS_HELP_STRING([--with-termcap], [use termcap (default)]) -AS_HELP_STRING([--without-termcap], - [do not use any termcap libraries (ncurses,curses,termcap,termlib)]), -[], -[with_termcap=yes]) - -AC_ARG_ENABLE(lock-checking, -AS_HELP_STRING([--enable-lock-checking], [enable lock checking]), -[ case "$enableval" in - no) enable_lock_check=no ;; - *) enable_lock_check=yes ;; - esac -], - enable_lock_check=no) - -AC_ARG_ENABLE(lock-counter, -AS_HELP_STRING([--enable-lock-counter], [enable lock counters]), -[ case "$enableval" in - no) enable_lock_count=no ;; - *) enable_lock_count=yes ;; - esac ], enable_lock_count=no) - -AC_ARG_ENABLE(kernel-poll, -AS_HELP_STRING([--enable-kernel-poll], [enable kernel poll support]) -AS_HELP_STRING([--disable-kernel-poll], [disable kernel poll support]), -[ case "$enableval" in - no) enable_kernel_poll=no ;; - *) enable_kernel_poll=yes ;; - esac ], enable_kernel_poll=unknown) - - -AC_ARG_ENABLE(sctp, -AS_HELP_STRING([--enable-sctp], [enable sctp support (default) to on demand load the SCTP library in runtime if needed]) -AS_HELP_STRING([--enable-sctp=lib], [enable sctp support to link against the SCTP library]) -AS_HELP_STRING([--disable-sctp], [disable sctp support]), -[ case "x$enableval" in - xno|xyes|xlib|x) - ;; - x*) - AC_MSG_ERROR("invalid value --enable-sctp=$enableval") - ;; - esac ]) - -AC_ARG_ENABLE(jit, -AS_HELP_STRING([--enable-jit], [enable JIT support]) -AS_HELP_STRING([--disable-jit], [disable JIT support]), - [ case "$enableval" in - no) enable_jit=no ;; - *) enable_jit=yes ;; - esac -],enable_jit=auto) - -AC_ARG_ENABLE(m64-build, -AS_HELP_STRING([--enable-m64-build], - [build 64bit binaries using the -m64 flag to (g)cc]), -[ case "$enableval" in - no) enable_m64_build=no ;; - *) enable_m64_build=yes ;; - esac -],enable_m64_build=no) - -AC_ARG_ENABLE(m32-build, -AS_HELP_STRING([--enable-m32-build], - [build 32bit binaries using the -m32 flag to (g)cc]), -[ case "$enableval" in - no) enable_m32_build=no ;; - *) enable_m32_build=yes ;; - esac -],enable_m32_build=no) - -AC_ARG_WITH(dynamic-trace, -AS_HELP_STRING([--with-dynamic-trace={dtrace|lttng|systemtap}], - [specify use of dynamic trace framework, dtrace, lttng or systemtap]) -AS_HELP_STRING([--without-dynamic-trace], - [don't enable any dynamic tracing (default)])) - -if test X"$with_dynamic_trace" = X""; then - with_dynamic_trace=no -fi - -case "$with_dynamic_trace" in - no) DYNAMIC_TRACE_FRAMEWORK=;; - lttng) - AC_DEFINE(USE_LTTNG,[1], - [Define if you want to use lttng for dynamic tracing]) - DYNAMIC_TRACE_FRAMEWORK=lttng;; - dtrace) - AC_DEFINE(USE_DTRACE,[1], - [Define if you want to use dtrace for dynamic tracing]) - DYNAMIC_TRACE_FRAMEWORK=dtrace;; - systemtap) - AC_DEFINE(USE_SYSTEMTAP,[1], - [Define if you want to use systemtap for dynamic tracing]) - DYNAMIC_TRACE_FRAMEWORK=systemtap;; - *) - AC_MSG_ERROR(Unknown dynamic tracing framework specified with --with-dynamic-trace!);; -esac - -if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then - AC_DEFINE(USE_DYNAMIC_TRACE,[1], - [Define if you want to use dynamic tracing]) -fi - -AC_ARG_ENABLE(vm-probes, -AS_HELP_STRING([--enable-vm-probes], - [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)]), - [ case "$enableval" in - no) use_vm_probes=no ;; - *) - if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then - use_vm_probes=yes ; - else - AC_MSG_ERROR(Can not enable VM probes without any dynamic tracing framework!); - fi;; - esac ], if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then - use_vm_probes=yes ; - else - use_vm_probes=no - fi) - -AC_SUBST(USE_VM_PROBES) -if test X"$DYNAMIC_TRACE_FRAMEWORK" != X"lttng"; then - if test X"$use_vm_probes" = X"yes"; then - USE_VM_PROBES=yes - AC_DEFINE(USE_VM_PROBES,[1], - [Define to enable VM dynamic trace probes]) - fi -fi - -AC_ARG_WITH(assumed-cache-line-size, -AS_HELP_STRING([--with-assumed-cache-line-size=SIZE], - [specify assumed cache line size in bytes (valid values are powers of two between and including 16 and 8192; default is 64)])) - -dnl Require the assumed cache-line size to be a power of two between 16 and 8192 -case "$with_assumed_cache_line_size" in - ""|no|yes) - with_assumed_cache_line_size=64;; - 16|32|64|128|256|512|1024|2048|4096|8192) - ;; - *) - AC_MSG_ERROR([Invalid assumed cache-line size of $with_assumed_cache_line_size bytes]) - ;; -esac - -AC_DEFINE_UNQUOTED(ASSUMED_CACHE_LINE_SIZE, - $with_assumed_cache_line_size, - [Assumed cache-line size (in bytes)]) - -AC_ARG_ENABLE(systemd, -AS_HELP_STRING([--enable-systemd], [enable systemd support in epmd]), -[], -[enable_systemd=no]) - -AC_ARG_WITH(microstate-accounting, -AS_HELP_STRING([--with-microstate-accounting={yes|extra}], - [enable microstate account, possibly with extra detailed states]) -AS_HELP_STRING([--without-microstate-accounting], - [don't enable microstate accounting]), -[],[with_microstate_accounting=yes]) - -case "$with_microstate_accounting" in - yes) AC_DEFINE(ERTS_ENABLE_MSACC,[1], - [Define as 1 if you want to enable microstate accounting, 2 if you want extra states]) ;; - extra) AC_DEFINE(ERTS_ENABLE_MSACC,[2], - [Define as 1 if you want to enable microstate accounting, 2 if you want extra states]) ;; - *) ;; -esac - -dnl Magic test for clearcase. -OTP_RELEASE= -if test "${ERLANG_COMMERCIAL_BUILD}" != ""; then - OTP_EXTRA_FLAGS=-DOTP_RELEASE - OTP_RELEASE=yes -else - OTP_EXTRA_FLAGS= -fi -AC_SUBST(OTP_RELEASE) - -AC_MSG_CHECKING([OTP release]) -[SYSTEM_VSN=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`] -AC_MSG_RESULT([$SYSTEM_VSN]) -AC_SUBST(SYSTEM_VSN) - -AC_MSG_CHECKING([OTP version]) -[OTP_VERSION=`cat $ERL_TOP/OTP_VERSION`] -AC_MSG_RESULT([$OTP_VERSION]) -AC_SUBST(OTP_VERSION) - -if test X${enable_m64_build} = Xyes; then - case $CFLAGS in - *-m64*) - ;; - *) - CFLAGS="-m64 $CFLAGS" - ;; - esac -else - if test X${enable_m32_build} = Xyes; - then - case $CFLAGS in - *-m32*) - ;; - *) - CFLAGS="-m32 $CFLAGS" - ;; - esac ; - fi -fi - -AC_ARG_ENABLE(static-nifs, -AS_HELP_STRING([--enable-static-nifs], [link nifs statically. If yes then all nifs in all Erlang/OTP applications will be statically linked into the main binary. It is also possible to give a list of nifs that should be linked statically. The list should be a comma separated and contain the absolute path to a .a archive for each nif that is to be statically linked. The name of the .a archive has to be the same as the name of the nif. Note that you have to link any external dependencies that the nifs have to the main binary, so for the crypto nif you want to pass LIBS=-lcrypto to configure.]), - STATIC_NIFS="$enableval", - STATIC_NIFS=no) -AC_SUBST(STATIC_NIFS) - -AC_ARG_ENABLE(static-drivers, -AS_HELP_STRING([--enable-static-drivers], [comma separated list of linked-in drivers to link statically with the main binary. The list should contain the absolute path to a .a archive for each driver that is to be statically linked. The name of the .a archive has to be the same as the name of the driver.]), - STATIC_DRIVERS="$enableval", - STATIC_DRIVERS=no) -AC_SUBST(STATIC_DRIVERS) - -AC_ARG_WITH(ets-write-concurrency-locks, -AS_HELP_STRING([--with-ets-write-concurrency-locks={8|16|32|64|128|256}], - [specify how many locks the write_concurrency option for ets should use.]) -AS_HELP_STRING([--without-ets-write-concurrency-locks], - [use the default number of write_concurrency locks (default)])) - -if test X"$with_ets_write_concurrency_locks" != X""; then - AC_DEFINE_UNQUOTED(ERTS_DB_HASH_LOCK_CNT,$with_ets_write_concurrency_locks, - [Define to override the default number of write_concurrency locks]) -fi - -AC_ARG_WITH(spectre-mitigation, - AS_HELP_STRING([--with-spectre-mitigation={yes|incomplete}], - [enable spectre mitigation, either fully or with mitigations - disabled in a handful places like the interpreter]) - AS_HELP_STRING([--without-spectre-mitigation], - [build without spectre mitigation]), - [],[with_spectre_mitigation=no]) - -case "$with_spectre_mitigation" in - no) ;; - yes) ;; - incomplete) ;; - *) AC_MSG_ERROR([Invalid spectre mitigation setting]) ;; -esac - -i_noretpoline_attr="" - -if test X"$with_spectre_mitigation" != X"no"; then - CFLAGS="$CFLAGS -mindirect-branch=thunk" - - AC_MSG_CHECKING([for spectre mitigation]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([],[return 0;])], - [AC_MSG_RESULT([yes])], - [AC_MSG_ERROR([no])]) - - if test X"$with_spectre_mitigation" = X"incomplete"; then - # gcc and clang support this attribute if they're recent enough. Note - # that we must compile with -Werror to check for actual support as they - # warn rather than error out on unsupported attributes. - - i_noretpoline_attr='__attribute__((__indirect_branch__("keep")))' - i_preserve_cflags="$CFLAGS" - CFLAGS="$CFLAGS -Werror" - - AC_MSG_CHECKING([whether spectre mitigation can be disabled on a per-function basis]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([$i_noretpoline_attr],[return 0;])], - [AC_MSG_RESULT([yes])], - [AC_MSG_ERROR([no])]) - - CFLAGS="$i_preserve_cflags" - fi -fi - -AC_DEFINE_UNQUOTED(ERTS_NO_RETPOLINE, $i_noretpoline_attr, - [Per-function attribute for disabling retpoline. This is - *only* defined when --with-spectre-mitigation=incomplete - and has no effects otherwise]) - -dnl ---------------------------------------------------------------------- -dnl Checks for programs. -dnl ---------------------------------------------------------------------- - -AC_PROG_CC -AC_SUBST(GCC) - -dnl --------------------------------------------------------------------- -dnl Special stuff regarding CFLAGS and details in the environment... -dnl --------------------------------------------------------------------- - -dnl NOTE: CPPFLAGS will be included in CFLAGS at the end -case $host_os in - linux*) CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE";; - aix*|os400*) - # * _ALL_SOURCE: Required to get the winsize structure for TIOCSWINSZ. - # * _LINUX_SOURCE_COMPAT: Not required, but makes some libc functions - # behave closer to glibc assumptions. - CPPFLAGS="$CPPFLAGS -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" - ;; - win32) - # The ethread library requires _WIN32_WINNT of at least 0x0403. - # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" - ;; - *) - ;; -esac - - -LM_WINDOWS_ENVIRONMENT - -dnl -dnl Flags to the C compiler -dnl -dnl Make sure we find config.h -dnl - -ERTS_CONFIG_H_IDIR="-I${ERL_TOP}/erts/$host" -AC_SUBST(ERTS_CONFIG_H_IDIR) - -extra_flags="$ERTS_CONFIG_H_IDIR $OTP_EXTRA_FLAGS" -CFLAGS="$CFLAGS $extra_flags" -DEBUG_CFLAGS="-g $CPPFLAGS $extra_flags $DEBUG_CFLAGS" -DEBUG_FLAGS=-g - -dnl -dnl Adjust DEBUG_CFLAGS to match CFLAGS in terms of -m -dnl - -case $CFLAGS in - *-m64*) - case $DEBUG_CFLAGS in - *-m64*) - ;; - *) - DEBUG_CFLAGS="-m64 $DEBUG_CFLAGS" - ;; - esac - ;; - *-m32*) - case $DEBUG_CFLAGS in - *-m32*) - ;; - *) - DEBUG_CFLAGS="-m32 $DEBUG_CFLAGS" - ;; - esac - ;; - *) - ;; -esac - -lfs_conf=ok -lfs_source=none -if test "${LFS_CFLAGS+set}" = "set" || \ - test "${LFS_LDFLAGS+set}" = "set" || \ - test "${LFS_LIBS+set}" = "set"; then - lfs_source=user -else - LM_CHECK_GETCONF - test "$GETCONF" = "false" || lfs_source=getconf -fi - -if test "$lfs_source" = "none"; then - AC_MSG_WARN([Do not know how to check for large file support flags; no getconf is available]) -else - for var in CFLAGS LDFLAGS LIBS; do - AC_MSG_CHECKING([for large file support $var]) - if test $lfs_source = user; then - eval "lfs_val=\"\$LFS_$var\"" - else - eval "lfs_var=LFS_$var" - lfs_val=`$GETCONF $lfs_var 2>/dev/null` || lfs_conf=failed - if test $lfs_conf = failed; then - AC_MSG_RESULT([failed]) - break - fi - eval "$lfs_var=\"$lfs_val\"" - fi - test "$lfs_val" != "" || lfs_val=none - AC_MSG_RESULT([$lfs_val]) - done - if test $lfs_conf = failed; then - AC_MSG_WARN([Check for large file support flags failed; $GETCONF failed]) - else - CFLAGS="$CFLAGS $LFS_CFLAGS" - DEBUG_CFLAGS="$DEBUG_CFLAGS $LFS_CFLAGS" - LDFLAGS="$LDFLAGS $LFS_LDFLAGS" - LIBS="$LIBS $LFS_LIBS" - fi -fi - -if test "x$GCC" = xyes; then - # Treat certain GCC warnings as errors - LM_TRY_ENABLE_CFLAG([-Werror=return-type], [WERRORFLAGS]) - LM_TRY_ENABLE_CFLAG([-Werror=implicit], [WERRORFLAGS]) - LM_TRY_ENABLE_CFLAG([-Werror=undef], [WERRORFLAGS]) - - # until the emulator can handle this, I suggest we turn it off! - #WFLAGS="-Wall -Wshadow -Wcast-qual -Wmissing-declarations" - WFLAGS="-Wall -Wstrict-prototypes -Wpointer-arith" - - case "$host_cpu" in - tile*) - # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, - # and too strict for our taste. - ;; - *) - WFLAGS="$WFLAGS -Wmissing-prototypes";; - esac - - saved_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Wdeclaration-after-statement" - AC_TRY_COMPILE([],[;], warn_decl_after_st=true, warn_decl_after_st=false) - if test "X$warn_decl_after_st" = "Xtrue"; then - WFLAGS="$WFLAGS -Wdeclaration-after-statement" - fi - CFLAGS=$saved_CFLAGS - - # Use -fno-common for gcc, that is link error if multiple definitions of - # global variables are encountered. This is ISO C compliant. - # Until version 10, gcc has had -fcommon as default, which allows and merges - # such dubious duplicates. - LM_TRY_ENABLE_CFLAG([-fno-common], [CFLAGS]) -else - WFLAGS="" - WERRORFLAGS=${WERRORFLAGS:-""} -fi - -AC_MSG_CHECKING([C99 support]) - -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ -#if __STDC_VERSION__ < 199901L - #error "Not C99" -#endif])], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no]) - CFLAGS="-std=gnu99 $CFLAGS" - DEBUG_CFLAGS="-std=gnu99 $DEBUG_CFLAGS"]) - -AC_MSG_CHECKING([CFLAGS for -O switch]) -case "$CFLAGS" in - *-O*) AC_MSG_RESULT([yes]) ;; - *) - AC_MSG_ERROR([ - CFLAGS must contain a -O flag. If you need to edit the CFLAGS you probably - also want to add the default CFLAGS. The default CFLAGS are "-O2 -g". - If you want to build erts without any optimization, pass -O0 to CFLAGS.]) ;; -esac - -dnl DEBUG_FLAGS is obsolete (I hope) -AC_SUBST(DEBUG_FLAGS) -AC_SUBST(DEBUG_CFLAGS) -AC_SUBST(WFLAGS) -AC_SUBST(WERRORFLAGS) - -## Check if we can do profile guided optimization of beam_emu -LM_CHECK_RUN_CFLAG([-fprofile-generate -Werror],[PROFILE_GENERATE]) -LM_CHECK_RUN_CFLAG([-fprofile-use -Werror],[PROFILE_USE]) -LM_CHECK_RUN_CFLAG([-fprofile-use -fprofile-correction -Werror],[PROFILE_CORRECTION]) - -if test "X$PROFILE_CORRECTION" = "Xtrue"; then - saved_CFLAGS=$CFLAGS - saved_LDFLAGS=$LDFLAGS - CFLAGS="-fprofile-generate $saved_CFLAGS" - LDFLAGS="-fprofile-generate $saved_LDFLAGS" - AC_MSG_CHECKING([whether $CC links with -fprofile-generate]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([],[return 0;])], - [AC_MSG_RESULT([yes]) - PROFILE_GENERATE=true], - [AC_MSG_RESULT([no]) - PROFILE_GENERATE=false]) - CFLAGS=$saved_CFLAGS - LDFLAGS=$saved_LDFLAGS -fi - -## Check if this is clang -LM_CHECK_ENABLE_CFLAG([-fprofile-instr-generate -Werror],[PROFILE_INSTR_GENERATE]) -if test "X$PROFILE_INSTR_GENERATE" = "Xtrue"; then - # It was clang, now we also have to check if we have llvm-profdata and that - # we can link programs with -fprofile-instr-use - saved_CFLAGS=$CFLAGS; - CFLAGS="-fprofile-instr-generate -Werror $saved_CFLAGS" - AC_RUN_IFELSE([AC_LANG_PROGRAM([],[])], - [AC_PATH_PROG([LLVM_PROFDATA], [llvm-profdata],[],[$PATH:/Library/Developer/CommandLineTools/usr/bin]) - AC_CHECK_PROGS([XCRUN], [xcrun]) - if test "X$XCRUN" != "X" -a "X$LLVM_PROFDATA" = "X"; then - AC_MSG_CHECKING([for $XCRUN $LLVM_PROFDATA]) - if $XCRUN $LLVM_PROFDATA --help 2>& AS_MESSAGE_LOG_FD >& AS_MESSAGE_LOG_FD; then - LLVM_PROFDATA="$XCRUN $LLVM_PROFDATA" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - fi - AC_SUBST(LLVM_PROFDATA) - if test "X$LLVM_PROFDATA" != "X"; then - CFLAGS="-fprofile-instr-use=default.profdata $saved_CFLAGS"; - $LLVM_PROFDATA merge -output=default.profdata *.profraw; - AC_MSG_CHECKING([whether $CC accepts -fprofile-instr-use=default.profdata -Werror]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[return 0;])], - [AC_MSG_RESULT([yes]) - PROFILE_INSTR_USE=true], - [AC_MSG_RESULT([no]) - PROFILE_INSTR_USE=false]) - rm -f default.profdata - fi], - [], - [AC_MSG_NOTICE([Disabling PGO when cross-compiling])]) - rm -f *.profraw - CFLAGS=$saved_CFLAGS; -fi - -AC_ARG_ENABLE(pgo, -AS_HELP_STRING([--enable-pgo], - [build erts using PGO (profile guided optimization)]), -[ case "$enableval" in - no) enable_pgo=no ;; - *) enable_pgo=yes ;; - esac -],enable_pgo=default) - -USE_PGO=false -AC_MSG_CHECKING([whether to do PGO of erts]) -if test $enable_pgo = no; then - AC_MSG_RESULT([no, disabled by user]) -elif test $CROSS_COMPILING = yes; then - if test $enable_pgo = yes; then - AC_MSG_ERROR(cannot use PGO when cross-compiling) - else - AC_MSG_RESULT([no, cross compiling]) - fi -elif test "X$host" = "Xwin32"; then - AC_MSG_RESULT([no, not supported in windows]) -elif test "X$PROFILE_GENERATE" = "Xtrue" -a "X$PROFILE_USE" = "Xtrue" -a "X$PROFILE_CORRECTION" = "Xtrue"; then - ## We need -fprofile-generate and -fprofile-correction support to use PGO with - ## gcc as multiple threads run within the executed object files - USE_PGO=true - PROFILE_COMPILER=gcc - AC_MSG_RESULT([yes, using -fprofile-generate -fprofile-correction]) -elif test "X$PROFILE_INSTR_GENERATE" = "Xtrue" -a "X$PROFILE_INSTR_USE" = "Xtrue"; then - USE_PGO=true - PROFILE_COMPILER=clang - AC_MSG_RESULT([yes, using -fprofile-instr-generate]) -else - if test $enable_pgo = yes; then - AC_MSG_ERROR(cannot use PGO with this compiler) - else - AC_MSG_RESULT([no]) - fi -fi - -dnl Disable pgo for now -USE_PGO=false - -AC_SUBST(USE_PGO) -AC_SUBST(PROFILE_COMPILER) - -AC_CHECK_SIZEOF(void *) # Needed for ARCH and smp checks below -if test "x$ac_cv_sizeof_void_p" = x8; then - AC_SUBST(EXTERNAL_WORD_SIZE, 64) -else - AC_SUBST(EXTERNAL_WORD_SIZE, 32) -fi - -dnl -dnl Figure out operating system and cpu architecture -dnl - -if test "x$host_alias" != "x"; then - chk_opsys_=$host_os -else - chk_opsys_=`uname -s` - if test "x$chk_opsys_" = "xSunOS"; then - chk_opsys_=$chk_opsys_`uname -r` - fi -fi -case $chk_opsys_ in - win32) OPSYS=win32;; - solaris2.*|SunOS5.*) OPSYS=sol2;; - linux*|Linux) OPSYS=linux;; - darwin|Darwin) OPSYS=darwin;; - freebsd|FreeBSD) OPSYS=freebsd;; - *) OPSYS=noopsys -esac - -AC_SUBST(OPSYS) - -LM_HARDWARE_ARCH - -dnl Check consistency of os and darwin-switches - - -dnl Take care of LDFLAGS on darwin, and disable common_test as it -dnl has a build/configure system re rx-lib that is not compatible -dnl First remove common_tests skip file. - -dnl Adjust LDFLAGS to allow 64bit linkage on DARWIN -case $ARCH-$OPSYS in - amd64-darwin*|arm64-darwin*) - AC_MSG_NOTICE([Adjusting LDFLAGS to cope with 64bit Darwin]) - case $LDFLAGS in - *-m64*) - ;; - *) - LDFLAGS="-m64 $LDFLAGS" - ;; - esac - ;; - *-darwin*) - case $LDFLAGS in - *-m32*) - ;; - *) - LDFLAGS="-m32 $LDFLAGS" - ;; - esac - ;; - *) - if test X${enable_m64_build} = Xyes; then - AC_MSG_NOTICE([Adjusting LDFLAGS to use -m64]) - case $LDFLAGS in - *-m64*) - ;; - *) - LDFLAGS="-m64 $LDFLAGS" - ;; - esac - fi; - if test X${enable_m32_build} = Xyes; then - AC_MSG_NOTICE([Adjusting LDFLAGS to use -m32]) ; - case $LDFLAGS in - *-m32*) - ;; - *) - LDFLAGS="-m32 $LDFLAGS" - ;; - esac ; - fi - ;; -esac - -AC_MSG_CHECKING(if VM has to be linked with Carbon framework) -case $ARCH-$OPSYS in - *-darwin*) - LIBCARBON="-framework Carbon -framework Cocoa" - AC_MSG_RESULT([yes]) - ;; - *) - LIBCARBON= - AC_MSG_RESULT([no]) - ;; -esac - -AC_SUBST(LIBCARBON) - -_search_path=/bin:/usr/bin:/usr/local/bin:$PATH - -AC_PATH_PROG(MKDIR, mkdir, false, $_search_path) -if test "$ac_cv_path_MKDIR" = false; then - AC_MSG_ERROR([No 'mkdir' command found]) -fi - -AC_PATH_PROG(CP, cp, false, $_search_path) -if test "$ac_cv_path_CP" = false; then - AC_MSG_ERROR([No 'cp' command found]) -fi - -_search_path= - - -# Remove old configuration information. -# Next line should be before first output to CONN_INFO. So this is -# just the right place. -rm -f "$ERL_TOP/erts/CONF_INFO" - -dnl Check if we should/can build a sharing-preserving emulator -AC_MSG_CHECKING(if we are building a sharing-preserving emulator) -if test "$enable_sharing_preserving" = "yes"; then - AC_DEFINE(SHCOPY, [1], - [Define if building a sharing-preserving emulator]) - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - - -dnl some tests below will call this if we haven't already - and autoconf -dnl can't handle those tests being done conditionally at runtime -AC_PROG_CPP - -AC_PROG_RANLIB - -AC_PROG_YACC -LM_PROG_PERL5 -if test "$ac_cv_path_PERL" = false; then - AC_MSG_ERROR([Perl version 5 is required to build the emulator!]) -fi -AC_PROG_LN_S - - -AC_CHECK_TOOL([AR], [ar], [false]) -if test "$ac_cv_prog_AR" = false; then - AC_MSG_ERROR([No 'ar' command found in PATH]) -fi - -# -# Get programs needed for building the documentation -# - -## Delete previous failed configure results -if test -f doc/CONF_INFO; then - rm -f doc/CONF_INFO -fi - -AC_CHECK_PROGS(XSLTPROC, xsltproc) -if test -z "$XSLTPROC"; then - echo "xsltproc" >> doc/CONF_INFO - AC_MSG_WARN([No 'xsltproc' command found: the documentation cannot be built]) -fi - -AC_CHECK_PROGS(FOP, fop) -if test -z "$FOP"; then - FOP="$ERL_TOP/make/fakefop" - echo "fop" >> doc/CONF_INFO - AC_MSG_WARN([No 'fop' command found: going to generate placeholder PDF files]) -fi - -AC_CHECK_PROGS(XMLLINT, xmllint) -if test -z "$XMLLINT"; then - echo "xmllint" >> doc/CONF_INFO - AC_MSG_WARN([No 'xmllint' command found: can't run the xmllint target for the documentation]) -fi - -dnl -dnl We can live with Solaris /usr/ucb/install -dnl -case $host in - *-*-solaris*|free_source) - if test -x /usr/ucb/install; then - INSTALL="/usr/ucb/install -c" - fi - ;; - *) - ;; -esac -AC_PROG_INSTALL -LM_PROG_INSTALL_DIR - -case $host_os in - darwin*) - dnl Need to preserve modification time on archives; - dnl otherwise, ranlib has to be run on archives - dnl again after installation. - INSTALL_DATA="$INSTALL_DATA -p";; - *) - ;; -esac - -dnl -dnl Fix for Tilera install permissions -dnl - -case $build in - *tile*) - INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" - INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" - ;; - *) - ;; -esac - -dnl ---------------------------------------------------------------------- -dnl Misc. things (some of them should go away) -dnl ---------------------------------------------------------------------- - -dnl -dnl An attempt to allow cross compiling. This is not the right way, -dnl nor does it work currently. Some makefiles still needs these -dnl variables, so we leave them in for now. -dnl -HCC='$(CC)' AC_SUBST(HCC) -HCFLAGS="" AC_SUBST(HCFLAGS) -HCFLAGS="$HCFLAGS -I${ERL_TOP}/erts/$host" - -dnl We want to use $(CC) as linker for the emulator regardless of -dnl what the user say. This might not be the right way to do it, but -dnl for now that is the way we do it. -LD='$(CC)' -LD_MAY_BE_WEAK=no -AC_SUBST(LD) - -dnl Check for cygwin and object/exe files extension -dnl AC_CYGWIN is deprecated -AC_EXEEXT -AC_OBJEXT - -dnl This is the os flavour, should be unix or win32 -case $host in - win32) - ERLANG_OSTYPE=win32 ;; - *) - ERLANG_OSTYPE=unix ;; -esac - -AC_SUBST(ERLANG_OSTYPE) - -# Check how to export functions from the emulator executable, needed -# when dynamically loaded drivers are loaded (so that they can find -# emulator functions). -# OS'es with ELF executables using the GNU linker (Linux and recent *BSD, -# in rare cases Solaris) typically need '-Wl,-export-dynamic' (i.e. pass -# -export-dynamic to the linker - also known as -rdynamic and some other -# variants); some sysVr4 system(s) instead need(s) '-Wl,-Bexport'. -# AIX 4.x (perhaps only for x>=2) wants -Wl,-bexpall,-brtl and doesn't -# reliably return an error for others, thus we separate it out. -# Otherwise we assume that if the linker accepts the flag, it is needed. -AC_MSG_CHECKING(for extra flags needed to export symbols) -DEXPORT="" -case $host_os in - aix*|os400*) - DEXPORT=-Wl,-bexpall,-brtl - ;; - bsdi*) - DEXPORT="-rdynamic " - ;; - win32) - DEXPORT="" - ;; - *) - save_ldflags="$LDFLAGS" - LDFLAGS=-Wl,-export-dynamic - AC_TRY_LINK(,,[DEXPORT=-Wl,-export-dynamic], [ - LDFLAGS=-Wl,-Bexport - AC_TRY_LINK(,,[DEXPORT=-Wl,-Bexport],)]) - LDFLAGS="$save_ldflags" - ;; -esac -AC_SUBST(DEXPORT) -case "x$DEXPORT" in - "x") - AC_MSG_RESULT([none]);; - *) - AC_MSG_RESULT([$DEXPORT]);; -esac - -# Check for Solaris/ultrasparc /dev/perfmon interface -# (also needs gcc specific asm instructions) -case "${host}:${GCC}" in - sparc-*-solaris*:yes) - AC_DEFINE(HAVE_SOLARIS_SPARC_PERFMON,[1], - [define if you have the Solaris/ultrasparc /dev/perfmon interface]) - ;; - *) - ;; -esac - - -case $host_os in - darwin19*) - # Disable stack checking to avoid crashing with a segment fault - # in macOS Catalina. - AC_MSG_NOTICE([Turning off stack check on macOS 10.15 (Catalina)]) - CFLAGS="-fno-stack-check $CFLAGS" - ;; - *) - ;; -esac - - -dnl ---------------------------------------------------------------------- -dnl Checks for libraries. -dnl ---------------------------------------------------------------------- - -AC_CHECK_LIB(m, sin) -AC_CHECK_LIB(dl, dlopen) -AC_CHECK_LIB(inet, main) -AC_CHECK_LIB(util, openpty) - -dnl Try to find a thread library. -dnl -dnl ETHR_LIB_NAME, ETHR_LIBS, ETHR_X_LIBS, ETHR_THR_LIB_BASE and ETHR_DEFS -dnl are set by ERL_FIND_ETHR_LIB -ERL_FIND_ETHR_LIB - -if test "X$ETHR_LIB_NAME" = "X"; then - AC_MSG_ERROR([cannot build emulator since no thread library was found]) -fi - -TYPES=opt - -DIRTY_SCHEDULER_TEST=$enable_dirty_schedulers_test -AC_SUBST(DIRTY_SCHEDULER_TEST) -test $DIRTY_SCHEDULER_TEST != yes || { - test -f "$ERL_TOP/erts/CONF_INFO" || echo "" > "$ERL_TOP/erts/CONF_INFO" - cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" - cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" - cat >> $ERL_TOP/erts/CONF_INFO < "$ERL_TOP/erts/CONF_INFO" - cat >> "$ERL_TOP/erts/CONF_INFO" < - #include - #include - #include - #include - #include - ], - [ - int fd = creat("conftest.temp", 0600); - fallocate(fd, FALLOC_FL_KEEP_SIZE,(off_t) 1024,(off_t) 1024); - ], i_cv_fallocate_works=yes, i_cv_fallocate_works=no) -]) -if test $i_cv_fallocate_works = yes; then - AC_DEFINE(HAVE_FALLOCATE, 1, Define if you have a working fallocate()) -fi - -dnl * Old glibcs have broken posix_fallocate(). Make sure not to use it. -dnl * It may also be broken in AIX. -AC_CACHE_CHECK([whether posix_fallocate() works],i_cv_posix_fallocate_works,[ - AC_TRY_RUN([ - #if !defined(__sun) && !defined(__sun__) - #define _XOPEN_SOURCE 600 - #endif - #include - #include - #include - #include - #if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 7)) - possibly broken posix_fallocate - #endif - int main() { - int fd = creat("conftest.temp", 0600); - int ret; - if (-1 == fd) { - perror("creat()"); - return 2; - } - ret = posix_fallocate(fd, 1024, 1024) < 0 ? 1 : 0; - unlink("conftest.temp"); - return ret; - } - ], [ - i_cv_posix_fallocate_works=yes - ], [ - i_cv_posix_fallocate_works=no - ], [ - i_cv_posix_fallocate_works=no - ]) -]) -if test $i_cv_posix_fallocate_works = yes; then - AC_DEFINE(HAVE_POSIX_FALLOCATE,, Define if you have a working posix_fallocate()) -fi - -# -# EMU_THR_LIB_NAME, EMU_THR_LIBS, EMU_THR_X_LIBS, and EMU_THR_DEFS is -# used by the emulator, and can (but should not) be used by applications -# that only require thread support when the emulator has thread support. -# Other applications should use ETHR_LIB_NAME, ETHR_LIBS, ETHR_X_LIBS, -# and ETHR_DEFS. -# - -EMU_THR_LIB_NAME= -EMU_THR_X_LIBS= -EMU_THR_LIBS= -EMU_THR_DEFS= - -# Threads enabled for emulator -EMU_THR_LIB_NAME=$ETHR_LIB_NAME -EMU_THR_X_LIBS=$ETHR_X_LIBS -EMU_THR_LIBS=$ETHR_LIBS -EMU_THR_DEFS=$ETHR_DEFS -ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS threads" -AC_MSG_CHECKING(whether lock checking should be enabled) -AC_MSG_RESULT($enable_lock_check) -if test "x$enable_lock_check" != "xno"; then - EMU_THR_DEFS="$EMU_THR_DEFS -DERTS_ENABLE_LOCK_CHECK" -fi - -AC_MSG_CHECKING(whether lock counters should be enabled) -AC_MSG_RESULT($enable_lock_count) -if test "x$enable_lock_count" != "xno"; then - TYPES="$TYPES lcnt" -fi - -case $host_os in - linux*) - AC_MSG_CHECKING([whether dlopen() needs to be called before first call to dlerror()]) - if test "x$ETHR_THR_LIB_BASE_TYPE" != "xposix_nptl"; then - AC_DEFINE(ERTS_NEED_DLOPEN_BEFORE_DLERROR,[1], - [Define if dlopen() needs to be called before first call to dlerror()]) - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - fi - ;; - *) - ;; -esac - -# Remove -D_WIN32_WINNT*, -DWINVER* and -D_GNU_SOURCE from EMU_THR_DEFS -# (defined in CFLAGS). Note that we want to keep these flags -# in ETHR_DEFS, but not in EMU_THR_DEFS. -new_emu_thr_defs= -for thr_def in $EMU_THR_DEFS; do - case $thr_def in - -D_GNU_SOURCE*|-D_WIN32_WINNT*|-DWINVER*) - ;; - *) - new_emu_thr_defs="$new_emu_thr_defs $thr_def" - ;; - esac -done -EMU_THR_DEFS=$new_emu_thr_defs - -AC_SUBST(EMU_THR_LIB_NAME) -AC_SUBST(EMU_THR_X_LIBS) -AC_SUBST(EMU_THR_LIBS) -AC_SUBST(EMU_THR_DEFS) - -if test "x$enable_lock_check" = "xno"; then - EMU_LOCK_CHECKING=no -else - EMU_LOCK_CHECKING=yes -fi - -AC_SUBST(EMU_LOCK_CHECKING) - -ERL_INTERNAL_LIBS - -dnl THR_LIBS and THR_DEFS are only used by odbc -THR_LIBS=$ETHR_X_LIBS -THR_DEFS=$ETHR_DEFS - -AC_SUBST(THR_LIBS) -AC_SUBST(THR_DEFS) - -dnl ---------------------------------------------------------------------- -dnl Try to figure out where to get the termcap functions from. -dnl We use tgetent(), tgetflag(), tgetnum(), tgetstr() and tputs() -dnl ---------------------------------------------------------------------- - -TERMCAP_LIB= - -if test "x$with_termcap" != "xno" && - test "X$host" != "Xwin32"; then - # try these libs - termcap_libs="tinfo ncurses curses termcap termlib" - - for termcap_lib in $termcap_libs; do - AC_CHECK_LIB($termcap_lib, tgetent, TERMCAP_LIB="-l$termcap_lib") - if test "x$TERMCAP_LIB" != "x"; then - break - fi - done - - if test "x$TERMCAP_LIB" = "x"; then - AC_MSG_ERROR([No curses library functions found]) - fi -fi - -AC_SUBST(TERMCAP_LIB) - -if test "x$TERMCAP_LIB" != "x"; then - - AC_DEFINE(HAVE_TERMCAP, 1, [Define if termcap functions exists]) -fi - -if test "X$host" != "Xwin32"; then - AC_MSG_CHECKING(for wcwidth) - AC_TRY_LINK([#include ], [wcwidth(0);], - have_wcwidth=yes, have_wcwidth=no) - if test $have_wcwidth = yes; then - AC_MSG_RESULT([yes]) - AC_DEFINE(HAVE_WCWIDTH, [1], - [Define to 1 if you have a `wcwidth' function.]) - fi -fi - -dnl ------------- -dnl zlib -dnl ------------- - -AC_ARG_ENABLE(builtin-zlib, - AS_HELP_STRING([--enable-builtin-zlib], - [force use of our own built-in zlib]), - [ case "$enableval" in - no) enable_builtin_zlib=no ;; - *) enable_builtin_zlib=yes ;; - esac ], enable_builtin_zlib=no) - -Z_LIB= - -if test "x$enable_builtin_zlib" = "xyes"; then - AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1, - [Define if your zlib version defines inflateGetDictionary.]) - AC_MSG_NOTICE([Using our own built-in zlib source]) -else -AC_MSG_CHECKING(for zlib 1.2.5 or higher) -zlib_save_LIBS=$LIBS -LIBS="-lz $LIBS" -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ -#include "zlib.h" -]],[[ -#if ZLIB_VERNUM >= 0x1250 - Bytef s[1]; - s[0] = 0; - (void) adler32((uLong)0, s, 1); -#else -#error "No zlib 1.2.5 or higher found" -error -#endif -]])], -[ - Z_LIB="-lz" - AC_DEFINE(HAVE_LIBZ, 1, [Define to 1 if you have the `z' library (-lz).]) - AC_MSG_RESULT(yes) -],[ - AC_MSG_RESULT(no) -]) - -if test "$Z_LIB" != ""; then - AC_SEARCH_LIBS(inflateGetDictionary, [z], - AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1, - [Define if your zlib version defines inflateGetDictionary.])) -fi - -LIBS=$zlib_save_LIBS - -fi -AC_SUBST(Z_LIB) - - -dnl ------------- -dnl esock -dnl ------------- - -AC_ARG_ENABLE(esock, -AS_HELP_STRING([--enable-esock], [enable builtin experimental socket (as a nif) support (default)]) -AS_HELP_STRING([--disable-esock], [disable builtin experimental socket (as a nif) support])) - -dnl Default value -USE_ESOCK=yes - -if test "x$enable_esock" = "xyes"; then - USE_ESOCK=yes -else - if test "x$enable_esock" = "xno"; then - USE_ESOCK=no - fi -fi - -if test "x$USE_ESOCK" = "xyes"; then - if test "x$USE_ESOCK" = "xyes"; then - AC_CHECK_FUNCS([localtime_r strftime getprotoent setprotoent endprotoent]) - fi -fi - -AC_SUBST(USE_ESOCK) - - -dnl *** ESOCK_USE_RCVSNDTIMEO *** - -AC_ARG_ENABLE(esock_use_rcvsndtimeo, -AS_HELP_STRING([--enable-esock-rcvsndtimeo], [enable use of the option(s) rcvtimeo and sndtimeo]) -AS_HELP_STRING([--disable-esock-rcvsndtimeo], [disable use of the option(s) rcvtimeo and sndtimeo (default)])) - -if test "x$enable_esock_rcvsndtimeo" = "xyes"; then - AC_DEFINE(ESOCK_USE_RCVSNDTIMEO, [1], [Use SO_[RCV|SND]TMIEO]) -fi - - -dnl *** ESOCK_COUNTER_SIZE *** - -AC_ARG_WITH(esock-counter-size, -AS_HELP_STRING([--with-esock-counter-size=SZ], - [Size of the esock counters, in number of bits: 16 | 24 | 32 | 48 | 64; default is 64]), -[], -[with_esock_counter_size=64]) - -case "$with_esock_counter_size" in - 16) - AC_DEFINE(ESOCK_COUNTER_SIZE, [16], [ESOCK counter size]) - ;; - 24) - AC_DEFINE(ESOCK_COUNTER_SIZE, [24], [ESOCK counter size]) - ;; - 32) - AC_DEFINE(ESOCK_COUNTER_SIZE, [32], [ESOCK counter size]) - ;; - 48) - AC_DEFINE(ESOCK_COUNTER_SIZE, [48], [ESOCK counter size]) - ;; - 64) - AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size]) - ;; - *) - AC_MSG_WARN([Invalid esock counter size ($with_esock_counter_size), using default (64)]) - AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size]) - dnl with_esock_counter_size=64 - ;; -esac -dnl ESOCK_COUNTER_SIZE=$with_esock_counter_size - -dnl We don't actually (currently) use this in erlang -dnl AC_SUBST(ESOCK_COUNTER_SIZE) - -dnl Checks for the net nif -AC_CHECK_FUNC([if_nametoindex], - [AC_DEFINE(HAVE_IF_NAMETOINDEX, [1], - [Define as 1 if function exists])] - []) -AC_CHECK_FUNC([if_indextoname], - [AC_DEFINE(HAVE_IF_INDEXTONAME, [1], - [Define as 1 if function exists])], - []) -AC_CHECK_FUNC([if_nameindex], - [AC_DEFINE(HAVE_IF_NAMEINDEX, [1], - [Define as 1 if function exists])], - []) -AC_CHECK_FUNC([if_freenameindex], - [AC_DEFINE(HAVE_IF_FREENAMEINDEX, [1], - [Define as 1 if function exists])] - []) -AC_CHECK_FUNC([gethostname], - [AC_DEFINE(HAVE_GETHOSTNAME, [1], - [Define as 1 if function exists])] - []) - - -dnl *** ESOCK_USE_SOCKET_REGISTRY *** -dnl At this time we *enable* use of the socket registry by default -dnl since we want to be able to have as much debug info as possible. - -AC_ARG_ENABLE(esock-socket-registry, - AS_HELP_STRING([--enable-esock-socket-registry], - [enable use of the socket registry by default (default)]) - AS_HELP_STRING([--disable-esock-socket-registry], - [disable use of the socket registry by default])) - -AS_IF([test "x$enable_esock_socket_registry" = "xno"], [ - AC_DEFINE(ESOCK_USE_SOCKET_REGISTRY, [0], - [Don't use socket registry by default])], [ - AC_DEFINE(ESOCK_USE_SOCKET_REGISTRY, [1], - [Use socket registry by default])]) - - -AC_CHECK_MEMBERS([struct ifreq.ifr_map], - [AC_DEFINE(ESOCK_USE_IFMAP, [], [Interface map supported])], - [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - -AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], - [AC_DEFINE(ESOCK_USE_HWADDR, [], [Interface hwaddr supported])], - [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - -AC_CHECK_MEMBERS([struct ifreq.ifr_ifindex], - [AC_DEFINE(ESOCK_USE_IFINDEX, [], [Interface ifindex supported])], - [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - -AC_CHECK_MEMBERS([struct ifreq.ifr_index], - [AC_DEFINE(ESOCK_USE_INDEX, [], [Interface index supported])], - [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - - -dnl -dnl This test kindly borrowed from Tcl -dnl -#-------------------------------------------------------------------- -# Check for the existence of the -lsocket and -lnsl libraries. -# The order here is important, so that they end up in the right -# order in the command line generated by make. Here are some -# special considerations: -# 1. Use "connect" and "accept" to check for -lsocket, and -# "gethostbyname" to check for -lnsl. -# 2. Use each function name only once: can't redo a check because -# autoconf caches the results of the last check and won't redo it. -# 3. Use -lnsl and -lsocket only if they supply procedures that -# aren't already present in the normal libraries. This is because -# IRIX 5.2 has libraries, but they aren't needed and they're -# bogus: they goof up name resolution if used. -# 4. On some SVR4 systems, can't use -lsocket without -lnsl too. -# To get around this problem, check for both libraries together -# if -lsocket doesn't work by itself. -#-------------------------------------------------------------------- - -tk_oldLibs=$LIBS -erl_checkBoth=0 -SOCKET_LIBS="" -AC_CHECK_FUNC(connect, erl_checkSocket=0, erl_checkSocket=1) -if test "$erl_checkSocket" = 1; then - AC_CHECK_LIB(socket, main, SOCKET_LIBS="-lsocket", erl_checkBoth=1) -fi - -if test "$erl_checkBoth" = 1; then - LIBS="$LIBS -lsocket -lnsl" - AC_CHECK_FUNC(accept, SOCKET_LIBS="-lsocket -lnsl") -fi - -LIBS="$tk_oldLibs $SOCKET_LIBS" -AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [SOCKET_LIBS="$SOCKET_LIBS -lnsl"])) -AC_CHECK_FUNC(gethostbyname_r,have_gethostbyname_r=yes) - -LIBS="$tk_oldLibs $SOCKET_LIBS" - -AC_SUBST(SOCKET_LIBS) - -dnl -dnl These gethostbyname thingies use old style AC_DEFINE for BC with ancient -dnl autoconf... -dnl - -if test "$have_gethostbyname_r" = yes; then - # OK, so we have gethostbyname_r() - but do we know how to call it...? - # (if not, HAVE_GETHOSTBYNAME_R will not be defined at all) - case $host_os in - solaris2*) - AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_SOLARIS, - [Define to flavour of gethostbyname_r]) - ;; - aix*|os400*) - # AIX version also needs "struct hostent_data" defn - AC_TRY_COMPILE([#include ], - [struct hostent_data hd;], - AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_AIX, - [Define to flavour of gethostbyname_r])) - ;; - *) - AC_EGREP_CPP(^yes$,[ -#include -#ifdef __GLIBC__ -yes -#endif - ], AC_DEFINE(HAVE_GETHOSTBYNAME_R, GHBN_R_GLIBC, - [Define to flavour of gethostbyname_r])) - ;; - esac -fi - -AC_MSG_CHECKING(for working posix_openpt implementation) -AC_TRY_LINK([ -#define _XOPEN_SOURCE 600 -#include -#include -], -[ - int mfd = posix_openpt(O_RDWR); - ptsname(mfd); - grantpt(mfd); - unlockpt(mfd); - return mfd; -], working_posix_openpt=yes, working_posix_openpt=no) - -if test "X$working_posix_openpt" = "Xyes"; then - AC_DEFINE(HAVE_WORKING_POSIX_OPENPT, [1], - [Define if you have a working posix_openpt implementation]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -dnl Check for usage of sockaddr_in in netdb.h -dnl somewhat ugly check, I check for presence of the string and that -dnl compilation works. If either fails I assume it's not needed. -dnl Seems only to be needed on a patched version of solaris2.5.1, with -dnl netdb.h version 1.18. -AC_MSG_CHECKING([if netdb.h requires netinet/in.h to be previously included]) -AC_EGREP_CPP(sockaddr_in, - [#include ], - AC_TRY_COMPILE([#include - #include ], - [return 0;], - need_in_h=yes, - need_in_h=no), - need_in_h=no) - -if test $need_in_h = yes; then - AC_DEFINE(NETDB_H_NEEDS_IN_H,[1], - [Define if netdb.h needs struct sockaddr_in ans in.h CAN be included before]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -dnl Check for type socklen_t -dnl -AC_MSG_CHECKING([for socklen_t]) -AC_TRY_COMPILE( [#include ], - [socklen_t test;], - have_socklen_t=yes, - have_socklen_t=no), - -if test $have_socklen_t = yes; then - AC_DEFINE(HAVE_SOCKLEN_T,[1],[Define if we have socklen_t]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - - -dnl h_errno isn't always declared in netdb.h, and with some definitions -dnl (e.g. function call for thread-safe) a simple 'extern int' may conflict -dnl (we do assume that h_errno exists at all...) -AC_CACHE_CHECK([for h_errno declaration in netdb.h], - ac_cv_decl_h_errno, -[AC_TRY_COMPILE([#include ], [int err = h_errno;], - ac_cv_decl_h_errno=yes, ac_cv_decl_h_errno=no)]) -if test $ac_cv_decl_h_errno = yes; then - AC_DEFINE(H_ERRNO_DECLARED,[1], - [define if h_errno is declared (in some way) in a system header file]) -fi - - -dnl ---------------------------------------------------------------------- -dnl Checks for header files. -dnl ---------------------------------------------------------------------- - -dnl We sometimes need EMU_THR_DEFS in order to find certain headers. -saved_cppflags=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" - -AC_HEADER_DIRENT -AC_HEADER_STDC -AC_HEADER_SYS_WAIT -AC_HEADER_TIME - -dnl Interactive UX needs for socket related error codes. -dnl Some Linuxes needs instead of -dnl -AC_CHECK_HEADERS(fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.h \ - sys/types.h sys/stropts.h sys/sysctl.h \ - sys/ioctl.h sys/time.h sys/uio.h sys/mman.h \ - sys/socket.h sys/sockio.h sys/socketio.h \ - net/errno.h malloc.h arpa/nameser.h libdlpi.h \ - pty.h util.h libutil.h utmp.h langinfo.h poll.h sdkddkver.h \ - elf.h) - -AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], [], [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - -AC_CHECK_MEMBERS([struct ifreq.ifr_enaddr], [], [], - [#ifdef __WIN32__ - #else - #include - #endif - ]) - -dnl ---------------------------------------------------------------------- -dnl Check the availability of systemd -dnl ---------------------------------------------------------------------- -if test x"$enable_systemd" != x"no"; then - -systemd_daemon_save_LIBS=$LIBS -LIBS= -AC_SEARCH_LIBS(sd_listen_fds,[systemd systemd-daemon], - [have_sd_listen_fds=yes],[have_sd_listen_fds=no],$systemd_daemon_save_LIBS) -AC_SEARCH_LIBS(sd_notify,[systemd systemd-daemon], - [have_sd_notify=yes],[have_sd_notify=no],$systemd_daemon_save_LIBS) -AC_CHECK_HEADERS(systemd/sd-daemon.h, - [have_systemd_sd_daemon_h=yes],[have_systemd_sd_daemon_h=no]) - -if test x"$have_sd_listen_fds" = x"yes" && \ - test x"$have_sd_notify" = x"yes" && \ - test x"$have_systemd_sd_daemon_h" = x"yes"; then - AC_DEFINE([HAVE_SYSTEMD_DAEMON],[1],[Define if you have systemd daemon]) - SYSTEMD_DAEMON_LIBS=$LIBS -elif test x"$enable_systemd" = x"yes"; then - AC_MSG_FAILURE([--enable-systemd was given, but test for systemd failed]) -fi -LIBS=$systemd_daemon_save_LIBS -fi -AC_SUBST(SYSTEMD_DAEMON_LIBS) - - -dnl ---------------------------------------------------------------------- -dnl Check the availability for libdlpi -dnl ---------------------------------------------------------------------- -AC_CHECK_LIB(dlpi, dlpi_open) -if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then - unset -v ac_cv_lib_dlpi_dlpi_open - dnl Try again now with -L/lib (or ditto 64) as argument to linker since - dnl gcc makes /usr/ccs/bin/ld ignore the crle configured linker default paths - dnl typically causing dlpi not being found on Solaris et.al - save_ldflags="$LDFLAGS" - try_dlpi_lib=/lib - if test x"$ac_cv_sizeof_void_p" = x"8"; then - if test -d /lib64; then - try_dlpi_lib=/lib64 - elif test -d /lib/64; then - try_dlpi_lib=/lib/64 - fi - fi - if test ! -f "$try_dlpi_lib/libdlpi.so" && \ - test -f "$try_dlpi_lib/libdlpi.so.1" - then - dnl It looks like there is a missing symlink - dnl - let's be helpful and notify the user - dnl NOTE this help is far from perfect e.g if there would be no - dnl *.so.1 but a *.so.1.123 or *.so.2 this will be no help - AC_MSG_ERROR( - [Your OS installation is missing a symbolic link. - Maybe it lacks some development package(s)... - It can anyhow be fixed with the following command: - # ln -s libdlpi.so.1 $try_dlpi_lib/libdlpi.so - ]) - fi - LDFLAGS="-L$try_dlpi_lib -R$try_dlpi_lib $LDFLAGS" - unset -v try_dlpi_lib - AC_MSG_NOTICE([Extending the search to include /lib]) - AC_CHECK_LIB(dlpi, dlpi_open) - if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then - LDFLAGS="$save_ldflags" - fi - unset -v save_ldflags -fi - -AC_CHECK_HEADER(sys/resource.h, - [AC_DEFINE(HAVE_SYS_RESOURCE_H, 1, - [Define to 1 if you have the header file]) - AC_CHECK_DECLS([getrlimit, setrlimit, RLIMIT_STACK], - [],[], - [#include ])], - [],[]) - -AC_CHECK_FUNCS([getrusage]) - -dnl Check if we have kernel poll support -have_kernel_poll=no -AC_CHECK_HEADER(sys/event.h, have_kernel_poll=kqueue) -AC_CHECK_HEADER(sys/epoll.h, have_kernel_poll=epoll) -AC_CHECK_HEADER(sys/devpoll.h, have_kernel_poll=/dev/poll) - -dnl Check if we have timerfds to be used for high accuracy -dnl epoll_wait timeouts -AC_CHECK_HEADERS([sys/timerfd.h]) - -dnl Check if we have the header file 'netpacket/packat.h' in which -dnl type 'struct sockaddr_ll' is defined. -AC_CHECK_HEADERS([netpacket/packet.h], - have_netpacket_packet_h=yes, - have_netpacket_packet_h=no) - -dnl Check for kernel SCTP support -AC_SUBST(LIBSCTP) -if test "x$enable_sctp" != "xno" ; then - AC_CHECK_HEADER(netinet/sctp.h, - [LIBSCTP=libsctp.so.1 - AC_DEFINE(HAVE_SCTP_H, [1], - [Define to 1 if you have the header file])], - [], - [#if HAVE_SYS_SOCKET_H - #include - #endif - ]) -fi - -case "x$enable_sctp" in - xno|x) - ;; - *) - if test "x$LIBSCTP" = "x" ; then - AC_MSG_ERROR([sctp support requested, but cannot be enabled since 'netinet/sctp.h' is missing]) - fi;; -esac - -if test x"$ac_cv_header_netinet_sctp_h" = x"yes"; then - AS_IF([test "x$enable_sctp" = "xlib"], - AC_CHECK_LIB(sctp, sctp_bindx)) - AC_CHECK_FUNCS([sctp_bindx sctp_peeloff sctp_getladdrs sctp_freeladdrs sctp_getpaddrs sctp_freepaddrs]) - AC_CHECK_MEMBERS([struct sctp_accoc_value.assoc_id], [], [], - [#if HAVE_SYS_SOCKET_H - #include - #endif - #include - ]) - AC_CHECK_DECLS([SCTP_UNORDERED, SCTP_ADDR_OVER, SCTP_ABORT, - SCTP_EOF, SCTP_SENDALL, SCTP_ADDR_CONFIRMED, - SCTP_DELAYED_ACK_TIME, - SCTP_EMPTY, SCTP_UNCONFIRMED, - SCTP_CLOSED, SCTPS_IDLE, - SCTP_BOUND, SCTPS_BOUND, - SCTP_LISTEN, SCTPS_LISTEN, - SCTP_COOKIE_WAIT, SCTPS_COOKIE_WAIT, - SCTP_COOKIE_ECHOED, SCTPS_COOKIE_ECHOED, - SCTP_ESTABLISHED, SCTPS_ESTABLISHED, - SCTP_SHUTDOWN_PENDING, SCTPS_SHUTDOWN_PENDING, - SCTP_SHUTDOWN_SENT, SCTPS_SHUTDOWN_SENT, - SCTP_SHUTDOWN_RECEIVED, SCTPS_SHUTDOWN_RECEIVED, - SCTP_SHUTDOWN_ACK_SENT, SCTPS_SHUTDOWN_ACK_SENT], [], [], - [#if HAVE_SYS_SOCKET_H - #include - #endif - #include - ]) - AC_CHECK_MEMBERS([struct sctp_paddrparams.spp_pathmtu, - struct sctp_paddrparams.spp_sackdelay, - struct sctp_paddrparams.spp_flags, - struct sctp_remote_error.sre_data, - struct sctp_send_failed.ssf_data, - struct sctp_event_subscribe.sctp_authentication_event, - struct sctp_event_subscribe.sctp_sender_dry_event], [], [], - [#if HAVE_SYS_SOCKET_H - #include - #endif - #include - ]) -fi - -dnl Check for setns -AC_CHECK_HEADERS(sched.h setns.h) -AC_CHECK_FUNCS([setns]) - -dnl Check for linux/errqueue -AC_CHECK_HEADERS([linux/types.h linux/errqueue.h], [], [], -[[#ifdef HAVE_SYS_TIME_H -# include -#endif -#ifdef HAVE_LINUX_TYPES_H -# include -#endif -]]) - -HAVE_VALGRIND=no -AC_CHECK_HEADER(valgrind/valgrind.h, HAVE_VALGRIND=yes) -AC_SUBST(HAVE_VALGRIND) - -LM_DECL_SO_BSDCOMPAT -LM_DECL_INADDR_LOOPBACK -LM_DECL_SYS_ERRLIST - -AC_CACHE_CHECK([if windows.h includes winsock2.h], - erts_cv_windows_h_includes_winsock2_h, - AC_TRY_COMPILE([#include - ], - [#ifndef _WINSOCK2API_ - #error winsock2.h not included - #endif - int i = 1; - ], - erts_cv_windows_h_includes_winsock2_h=yes, - erts_cv_windows_h_includes_winsock2_h=no)) -if test $erts_cv_windows_h_includes_winsock2_h = yes; then - AC_DEFINE(WINDOWS_H_INCLUDES_WINSOCK2_H, 1, \ -[Define if windows.h includes winsock2.h]) -fi - -dnl restore CPPFLAGS -CPPFLAGS=$saved_cppflags - -dnl ---------------------------------------------------------------------- -dnl Checks for typedefs, structures, and compiler characteristics. -dnl ---------------------------------------------------------------------- - -AC_C_CONST -AC_TYPE_SIGNAL -AC_TYPE_OFF_T -AC_TYPE_PID_T -AC_TYPE_SIZE_T - -AC_STRUCT_TM -LM_STRUCT_SOCKADDR_SA_LEN - -AC_CHECK_SIZEOF(char, 1) -AC_CHECK_SIZEOF(short) -AC_CHECK_SIZEOF(int) -AC_CHECK_SIZEOF(long) -AC_CHECK_SIZEOF(void *) -AC_CHECK_SIZEOF(long long) -AC_CHECK_SIZEOF(size_t) -AC_CHECK_SIZEOF(off_t) -AC_CHECK_SIZEOF(time_t) -AC_CHECK_SIZEOF(suseconds_t) -AC_CHECK_SIZEOF(_Float16) - -BITS64= - -if test $ac_cv_sizeof_void_p = 8; then - BITS64=yes -fi -AC_SUBST(BITS64) - -AC_MSG_CHECKING([for C compiler 'restrict' support]) -restrict_keyword="" -for x in restrict __restrict; do - AC_TRY_COMPILE([int * $x foo(int * $x arg); - int * $x foo(int * $x arg) - { int * $x var=arg; return var;} - ],[], - [restrict_keyword=$x],[]) - if test "x$restrict_keyword" != "x"; then - break - fi -done -AC_DEFINE_UNQUOTED(ERTS_RESTRICT,[$restrict_keyword],[Type qualifier restrict]) -if test "x$restrict_keyword" != "x"; then - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -if test "x$ac_compiler_gnu" = "xyes"; then -AC_MSG_CHECKING([if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly]) -## tree-copyrename was broken in gcc 4.3 and then removed in gcc 6 -AC_TRY_COMPILE([],[ - #if (__GNUC__ > 4 && __GNUC__ < 6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) - ; - #else - #error old and ok - #endif - ], - no_tree_copyrename=yes, - no_tree_copyrename=no) - -if test "x$no_tree_copyrename" = "xyes"; then - CFLAGS="$CFLAGS -fno-tree-copyrename" - AC_MSG_RESULT(yes, adjusting CFLAGS) -else - AC_MSG_RESULT(no) -fi - -AC_MSG_CHECKING([for broken gcc-4.3.0 compiler]) -AC_TRY_RUN([ -/* pr36339.c */ -extern void abort (void); - -typedef unsigned long my_uintptr_t; - -int check_a(my_uintptr_t tagged_ptr); - -int __attribute__((noinline)) try_a(my_uintptr_t x) -{ - my_uintptr_t heap[2]; - my_uintptr_t *hp = heap; - - hp[0] = x; - hp[1] = 0; - return check_a((my_uintptr_t)(void*)((char*)hp + 1)); -} - -int __attribute__((noinline)) check_a(my_uintptr_t tagged_ptr) -{ - my_uintptr_t *hp = (my_uintptr_t*)(void*)((char*)tagged_ptr - 1); - - if (hp[0] == 42 && hp[1] == 0) - return 0; - return -1; -} - -int main(void) -{ - if (try_a(42) < 0) - abort (); - return 0; -} -], gcc_4_3_0_bug=no, gcc_4_3_0_bug=yes, gcc_4_3_0_bug=cross) - -case $gcc_4_3_0_bug in - yes|no) - gcc_4_3_0_bug_result=$gcc_4_3_0_bug;; - cross) - gcc_dumped_vsn=`$CC -dumpversion 2>/dev/null` - case gcc-$gcc_dumped_vsn in - gcc-4.3.0) gcc_4_3_0_bug=yes;; - *) gcc_4_3_0_bug=no;; - esac - gcc_4_3_0_bug_result="$gcc_4_3_0_bug; could not run test since cross compiling, checked version number ($gcc_dumped_vsn) instead";; -esac - -AC_MSG_RESULT([$gcc_4_3_0_bug_result]) -if test $gcc_4_3_0_bug = yes; then - AC_MSG_ERROR([This gcc miscompiles the Erlang runtime system; please use a different version]) -fi - -fi - -case X$erl_xcomp_bigendian in - X) ;; - Xyes|Xno) ac_cv_c_bigendian=$erl_xcomp_bigendian;; - *) AC_MSG_ERROR([Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian]);; -esac - -AC_C_BIGENDIAN( - [ - AC_DEFINE([WORDS_BIGENDIAN], [1], [Define if big-endian]) - AC_DEFINE([ERTS_ENDIANNESS], [1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]) - ], - [ - AC_DEFINE([ERTS_ENDIANNESS], [-1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]) - ], - [ - case "$erl_xcomp_bigendian" in - yes) - AC_DEFINE([ERTS_ENDIANNESS], [1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; - no) - AC_DEFINE([ERTS_ENDIANNESS], [-1], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; - *) - AC_DEFINE([ERTS_ENDIANNESS], [0], [Define > 0 if big-endian < 0 if little-endian, or 0 if unknown]);; - esac - ]) - -AC_C_DOUBLE_MIDDLE_ENDIAN - -dnl fdatasync syscall (Unix only) -AC_CHECK_FUNCS([fdatasync]) - -dnl Find which C libraries are required to use fdatasync -dnl TODO: Remove check once SunOS >= 5.11 is required by erts. -dnl fdatasync requires linking against -lrt on SunOS <= 5.10. -dnl OpenSolaris 2009.06 is SunOS 5.11 and does not require -lrt. -AC_SEARCH_LIBS(fdatasync, [rt]) - - -dnl sendfile syscall -case $host_os in - linux*|freebsd*|dragonfly*|darwin*) - AC_CHECK_FUNCS([sendfile]) - ;; - solaris*) - AC_SEARCH_LIBS(sendfilev, sendfile, - AC_DEFINE([HAVE_SENDFILEV],[1], - [Define to 1 if you have the `sendfilev' function.])) - ;; - win32) - LIBS="$LIBS -lmswsock" - ;; - *) - ;; -esac - -dnl ---------------------------------------------------------------------- -dnl Checks for library functions. -dnl ---------------------------------------------------------------------- - -dnl We may need the thread library and thread flags in order to find right stuff -saved_cppflags=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $EMU_THR_DEFS" -saved_libs=$LIBS -LIBS="$LIBS $EMU_THR_X_LIBS" - -dnl Check if we have these, in which case we'll try to build -dnl inet_gethost with ipv6 support. -AC_CHECK_HEADERS(windows.h) -AC_CHECK_HEADERS(winsock2.h) -AC_CHECK_HEADERS(ws2tcpip.h,[],[],[ -#ifdef HAVE_WINSOCK2_H -#include -#endif -#ifdef HAVE_WINDOWS_H -#include -#endif -]) -dnl AC_CHECK_FUNC(getaddrinfo, have_getaddrinfo=yes, have_getaddrinfo=no) -AC_MSG_CHECKING(for getaddrinfo) -AC_TRY_LINK([ -#include -#include -#ifdef HAVE_WINSOCK2_H -#include -#endif -#ifdef HAVE_WINDOWS_H -#include -#endif -#ifdef HAVE_WS2TCPIP_H -#include -#endif -#ifndef __WIN32__ -#include -#include -#endif -], -[ -getaddrinfo("","",NULL,NULL); -],have_getaddrinfo=yes, have_getaddrinfo=no) -if test $have_getaddrinfo = yes; then - AC_MSG_RESULT([yes]) - AC_MSG_CHECKING([whether getaddrinfo accepts enough flags]) - AC_TRY_LINK([ -#include -#include -#ifdef HAVE_WINSOCK2_H -#include -#endif -#ifdef HAVE_WINDOWS_H -#include -#endif -#ifdef HAVE_WS2TCPIP_H -#include -#endif -#ifndef __WIN32__ -#include -#include -#endif -], -[ - struct addrinfo hints, *ai; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_INET6; - if (getaddrinfo("::", NULL, &hints, &ai) == 0) { - freeaddrinfo(ai); - exit(0); - } else { - exit(1); - } -],, have_getaddrinfo=no) - AC_MSG_RESULT($have_getaddrinfo) - case $have_getaddrinfo in - yes) - AC_DEFINE(HAVE_GETADDRINFO, [1], - [Define to 1 if you have a good `getaddrinfo' function.]);; - *) ;; - esac -else - AC_MSG_RESULT([no]) -fi -AC_MSG_CHECKING(for getnameinfo) -AC_TRY_LINK([ -#include -#include -#ifdef HAVE_WINSOCK2_H -#include -#endif -#ifdef HAVE_WINDOWS_H -#include -#endif -#ifdef HAVE_WS2TCPIP_H -#include -#endif -#ifndef __WIN32__ -#include -#include -#endif -], -[ -getnameinfo(NULL,0,NULL,0,NULL,0,0); -],have_getnameinfo=yes, have_getnameinfo=no) -if test $have_getnameinfo = yes; then - AC_MSG_RESULT([yes]) - AC_DEFINE(HAVE_GETNAMEINFO, [1], - [Define to 1 if you have a good `getnameinfo' function.]) -else - AC_MSG_RESULT([no]) -fi - - -AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2]) - -AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \ - pread pwrite memmove strerror strerror_r strncasecmp \ - gethrtime localtime_r gmtime_r mprotect madvise posix_madvise \ - mmap mremap memcpy mallopt sbrk _sbrk __sbrk brk _brk __brk \ - flockfile fstat strlcpy strlcat setsid posix2time time2posix \ - setlocale nl_langinfo poll mlockall ppoll vsyslog]) - -## We have a special check for inet_pton as AC_CHECK_FUCNS does not work -## on windows 32-bit as there a macro is used to rename the symbol... -AC_MSG_CHECKING([for inet_pton]) -AC_TRY_LINK([ -#ifdef WIN32 -#include -#else -#include -#endif -],[inet_pton(2,"",(void*)0)], have_inet_pton=yes, have_inet_pton=no) - -if test $have_inet_pton = yes; then - AC_DEFINE(HAVE_INET_PTON,[1], - [Define to 1 if you have the `inet_pton' function.]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -AC_MSG_CHECKING([for isfinite]) -AC_TRY_LINK([#include ], - [isfinite(0);], have_isfinite=yes, have_isfinite=no) - -if test $have_isfinite = yes; then - AC_DEFINE(HAVE_ISFINITE,[1], - [Define to 1 if you have the `isfinite' function.]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -case X$erl_xcomp_posix_memalign in - Xno) ;; - Xyes) have_posix_memalign=yes ;; - *) - AC_CHECK_FUNC( - [posix_memalign], - [if test "$cross_compiling" != yes; then -AC_TRY_RUN([ -#include -int main(void) { - void *ptr = NULL; - int error; - size_t alignment = 0x40000, size = 0x20028; - if ((error = posix_memalign(&ptr, alignment, size)) != 0 || ptr == NULL) - return error; - return 0; -} -],have_posix_memalign=yes -) - else - have_posix_memalign=yes - fi]);; -esac - -if test "$have_posix_memalign" = "yes"; then - AC_DEFINE(HAVE_POSIX_MEMALIGN,[1], - [Define to 1 if you have the `posix_memalign' function.]) -fi - - -dnl writev on OS X snow leopard is broken for files > 4GB -case $host_os in - darwin10.8.0) - AC_MSG_CHECKING([for writev]) - AC_MSG_RESULT(no, not stable on OS X Snow Leopard) ;; - *) - AC_CHECK_FUNCS([writev]) ;; -esac - -AC_CHECK_DECLS([posix2time, time2posix],,,[#include ]) - -AC_FUNC_VPRINTF - -dnl The AC_DEFINEs are necessary for autoheader to work. :-( -dnl for gzio -LM_CHECK_FUNC_DECL(fread, [extern int fread();],, - AC_DEFINE(HAVE_CONFLICTING_FREAD_DECLARATION,[1],[Define if you have a decl of fread that conflicts with int fread])) - -dnl Checking with TRY_LINK since putc_unlocked might be (probably is) a macro -AC_CACHE_CHECK([for putc_unlocked], - erts_cv_putc_unlocked, - AC_TRY_LINK([#include ], - [int res = putc_unlocked('x',stdout);], - erts_cv_putc_unlocked=yes, - erts_cv_putc_unlocked=no)) -if test $erts_cv_putc_unlocked = yes; then - AC_DEFINE(HAVE_PUTC_UNLOCKED, 1, [Define if you have putc_unlocked]) -fi - -dnl Checking with TRY_LINK since fwrite_unlocked might be a macro -AC_CACHE_CHECK([for fwrite_unlocked], - erts_cv_fwrite_unlocked, - AC_TRY_LINK([#include ], - [size_t res = fwrite_unlocked(NULL,sizeof(char),0,stdout);], - erts_cv_fwrite_unlocked=yes, - erts_cv_fwrite_unlocked=no)) -if test $erts_cv_fwrite_unlocked = yes; then - AC_DEFINE(HAVE_FWRITE_UNLOCKED, 1, [Define if you have fwrite_unlocked]) -fi - -dnl Need by run_erl. -AC_CHECK_FUNCS([openpty]) - -AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h) -AC_CHECK_FUNCS([getifaddrs]) -AC_CHECK_MEMBERS([struct sockaddr_un.sun_path], [], [], - [[#include ]]) - -dnl Checks for variables in6addr_any and in6addr_loopback, -dnl -dnl They normally declared by netinet/in.h, according to POSIX, -dnl but not on Windows 7 (Windows SDK 7.1). I would have liked -dnl to just write AC_CHECK_DECL([in6addr_any], ...) but if doing so, -dnl the configure check fails erroneously on Linux with the error -dnl "cannot convert to a pointer type", on a line looking like -dnl "char *p = (char *) in6addr_any;", so work around that -dnl with some more code. -AC_CACHE_CHECK( - [whether in6addr_any is declared], - [erts_cv_have_in6addr_any], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[ - #include - #include - #include - #include - ]], - [[printf("%d", in6addr_any.s6_addr[16]);]] - )], - [erts_cv_have_in6addr_any=yes], - [erts_cv_have_in6addr_any=no] - )] -) - -case "$erts_cv_have_in6addr_any" in - yes) - AC_DEFINE([HAVE_IN6ADDR_ANY], [1], - [Define to 1 if you have the variable in6addr_any declared.]) -esac - -AC_CACHE_CHECK( - [whether in6addr_loopback is declared], - [erts_cv_have_in6addr_loopback], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[ - #include - #include - #include - #include - ]], - [[printf("%d", in6addr_loopback.s6_addr[16]);]] - )], - [erts_cv_have_in6addr_loopback=yes], - [erts_cv_have_in6addr_loopback=no] - )] -) - -case "$erts_cv_have_in6addr_loopback" in - yes) - AC_DEFINE([HAVE_IN6ADDR_LOOPBACK], [1], - [Define to 1 if you have the variable in6addr_loopback declared.]) -esac - -AC_CHECK_DECLS([IN6ADDR_ANY_INIT, IN6ADDR_LOOPBACK_INIT, IPV6_V6ONLY], [], [], - [ - #include - #include - #include - ]) - -dnl ---------------------------------------------------------------------- -dnl Checks for features/quirks in the system that affects Erlang. -dnl ---------------------------------------------------------------------- - -AC_MSG_CHECKING([for sched_getaffinity/sched_setaffinity]) -AC_TRY_LINK([#include ], -[ -#ifndef CPU_SETSIZE -#error no CPU_SETSIZE -#endif - int res; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(1, &cpuset); - res = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); - res = sched_getaffinity(0, sizeof(cpu_set_t), &cpuset); - res = CPU_ISSET(1, &cpuset); - CPU_CLR(1, &cpuset); -], - sched_xetaffinity=yes, - sched_xetaffinity=no) -AC_MSG_RESULT([$sched_xetaffinity]) -if test $sched_xetaffinity = yes; then - AC_DEFINE(HAVE_SCHED_xETAFFINITY, 1, [Define if you have sched_getaffinity/sched_setaffinity]) -fi - - -AC_MSG_CHECKING([for pset functionality]) -AC_TRY_LINK([#include ], -[ - int res; - psetid_t id = PS_MYID; - int type = PS_PRIVATE; - uint_t numcpus = 1024; - processorid_t cpulist[1024]; - - res = pset_info(id, &type, &numcpus, &cpulist[0]); -], - pset_functionality=yes, - pset_functionality=no) -AC_MSG_RESULT([$pset_functionality]) -if test $pset_functionality = yes; then - AC_DEFINE(HAVE_PSET, 1, [Define if you have pset functionality]) -fi - -AC_MSG_CHECKING([for processor_bind functionality]) -AC_TRY_LINK([ -#include -#include -#include -], -[ - int res = processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL); -], - processor_bind_functionality=yes, - processor_bind_functionality=no) -AC_MSG_RESULT([$processor_bind_functionality]) -if test $processor_bind_functionality = yes; then - AC_DEFINE(HAVE_PROCESSOR_BIND, 1, [Define if you have processor_bind functionality]) -fi - -AC_MSG_CHECKING([for cpuset_getaffinity/cpuset_setaffinity]) -AC_TRY_LINK([ -#include -#include -], -[ - int res; - cpuset_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(1, &cpuset); - res = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset_t), &cpuset); - res = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset_t), &cpuset); - res = CPU_ISSET(1, &cpuset); - CPU_CLR(1, &cpuset); -], - cpuset_xetaffinity=yes, - cpuset_xetaffinity=no) -AC_MSG_RESULT([$cpuset_xetaffinity]) -if test $cpuset_xetaffinity = yes; then - AC_DEFINE(HAVE_CPUSET_xETAFFINITY, 1, [Define if you have cpuset_getaffinity/cpuset_setaffinity]) -fi - -AC_CACHE_CHECK([for 'end' symbol], - erts_cv_have_end_symbol, - [AC_TRY_LINK([], - [extern char end; {char *x = &end; *x= 0;}], - erts_cv_have_end_symbol=yes, - erts_cv_have_end_symbol=no)]) -if test $erts_cv_have_end_symbol = yes; then - AC_DEFINE(HAVE_END_SYMBOL, 1, [Define if you have the 'end' symbol]) -fi - -AC_CACHE_CHECK([for '_end' symbol], - erts_cv_have__end_symbol, - [AC_TRY_LINK([], - [extern char _end; {char *x = &_end; *x= 0;}], - erts_cv_have__end_symbol=yes, - erts_cv_have__end_symbol=no)]) -if test $erts_cv_have__end_symbol = yes; then - AC_DEFINE(HAVE__END_SYMBOL, 1, [Define if you have the '_end' symbol]) -fi - -AC_CACHE_CHECK([if __after_morecore_hook can track malloc()s core memory use], - erts_cv___after_morecore_hook_can_track_malloc, - [AC_TRY_RUN([ -#include -#ifdef HAVE_MALLOC_H -# include -#endif -#if defined(HAVE_END_SYMBOL) -extern char end; -#elif defined(HAVE__END_SYMBOL) -extern char _end; -#endif - -#ifdef ETHR_PTHREADS -# ifdef ETHR_HAVE_PTHREAD_H -# include -# else -# ifdef ETHR_HAVE_MIT_PTHREAD_H -# include -# endif -# endif -# define N_THR 5 -#else -# define N_THR 1 -#endif - -static char *heap_start = NULL; -static char *heap_end = NULL; - -void update_heap_size(void) -{ - heap_end = (char *) sbrk(0); -} - -void init_hook(void) -{ -#if defined(HAVE_END_SYMBOL) - heap_start = &end; -#elif defined(HAVE__END_SYMBOL) - heap_start = &_end; -#else - heap_start = sbrk(0); -#endif - __after_morecore_hook = update_heap_size; -} - -void (*__malloc_initialize_hook) (void) = init_hook; - -static int -check_malloc(int size) -{ - char *p = (char *) malloc(size); - if (!heap_start || !heap_end) return 0; - if (!p) return 0; - if (p < heap_start || heap_end <= p) return 0; - if (p + size < heap_start || heap_end < p + size) return 0; - return 1; -} - -#ifdef ETHR_PTHREADS -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -static void * -do_tests(void *vresp) -{ - int i, ok = 0; -#ifdef ETHR_PTHREADS - if (pthread_mutex_lock(&mutex) != 0) - return NULL; -#endif - - for (i = 0; i < 10; i++) - if (!check_malloc(1000)) - goto failed; - for (i = 0; i < 100; i++) - if (!check_malloc(1)) - goto failed; - if (!check_malloc(1024*1024+1)) - goto failed; - if (!check_malloc(10*1024*1024+1)) - goto failed; - ok = 1; - - failed: -#ifdef ETHR_PTHREADS - if (pthread_mutex_unlock(&mutex) != 0) - return NULL; -#endif - if (ok) - *((int *) vresp) = 0; - return NULL; -} - - -int main(void) -{ - int res[N_THR], i; -#ifdef ETHR_PTHREADS - pthread_t tid[N_THR]; -#endif - -#if defined(HAVE_MALLOPT) && defined(M_MMAP_MAX) - (void) mallopt(M_MMAP_MAX, 0); -#endif - - for (i = 0; i < N_THR; i++) - res[i] = 1; -#ifdef ETHR_PTHREADS - for (i = 1; i < N_THR; i++) - if (pthread_create(&tid[i], NULL, do_tests, &res[i]) != 0) - return 1; -#endif - (void) do_tests(&res[0]); -#ifdef ETHR_PTHREADS - for (i = 1; i < N_THR; i++) - if (pthread_join(tid[i], NULL) != 0) - return 1; -#endif - for (i = 0; i < N_THR; i++) - if (res[i]) - return 1; - return 0; -} - ], - erts_cv___after_morecore_hook_can_track_malloc=yes, - erts_cv___after_morecore_hook_can_track_malloc=no, - [ - case X$erl_xcomp_after_morecore_hook in - X) erts_cv___after_morecore_hook_can_track_malloc=cross;; - Xyes|Xno) erts_cv___after_morecore_hook_can_track_malloc=$erl_xcomp_after_morecore_hook;; - *) AC_MSG_ERROR([Bad erl_xcomp_after_morecore_hook value: $erl_xcomp_after_morecore_hook]);; - esac - ] - )]) - -case $erts_cv___after_morecore_hook_can_track_malloc in - yes) AC_DEFINE(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC, 1, \ -[Define if __after_morecore_hook can track malloc()s core memory use.]);; - cross) AC_MSG_WARN([result no guessed because of cross compilation]);; - *) ;; -esac - -if test "x$ac_cv_func_sbrk" = "xyes"; then - AC_CACHE_CHECK([types of sbrk()s return value and argument], - erts_cv_sbrk_ret_arg_types, - [ - - erts_cv_sbrk_ret_arg_types=unknown - ret_types="void *,char *" - arg_types="intptr_t,ptrdiff_t,int,long" - save_ifs="$IFS"; IFS="," - for rtype in $ret_types; do - for atype in $arg_types; do - IFS=$save_ifs - AC_TRY_LINK([#include - #include ], - [$rtype sbrk($atype incr);], - [erts_cv_sbrk_ret_arg_types="$rtype,$atype"]) - IFS="," - if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then - break 2 - fi - done - done - IFS=$save_ifs]) - - if test "$erts_cv_sbrk_ret_arg_types" != "unknown"; then - save_ifs="$IFS"; IFS="," - read ret_type arg_type < - #include ], - [$rtype brk($atype endds);], - [erts_cv_brk_ret_arg_types="$rtype,$atype"]) - IFS="," - if test "$erts_cv_brk_ret_arg_types" != "unknown"; then - break 2 - fi - done - done - IFS=$save_ifs]) - - if test "$erts_cv_brk_ret_arg_types" != "unknown"; then - save_ifs="$IFS"; IFS="," - read ret_type arg_type < -#include -#include -#ifdef HAVE_DLFCN_H -# include -#endif - -/* - * Our implementation requires that we have sbrk(), and 'end' or '_end'. - */ - -#if !defined(HAVE_SBRK) -# error no sbrk() -#endif -#if defined(HAVE_END_SYMBOL) -extern char end; -#elif defined(HAVE__END_SYMBOL) -extern char _end; -#else -# error no 'end' nor '_end' -#endif - -#ifdef ETHR_PTHREADS -# ifdef ETHR_HAVE_PTHREAD_H -# include -# else -# ifdef ETHR_HAVE_MIT_PTHREAD_H -# include -# endif -# endif -# define N_THR 5 -#else -# define N_THR 1 -#endif - -#define SBRK_IMPL(RET_TYPE, SBRK, ARG_TYPE) \ -RET_TYPE SBRK (ARG_TYPE); \ -static RET_TYPE (*real_ ## SBRK)(ARG_TYPE) = NULL; \ -RET_TYPE \ -SBRK (ARG_TYPE arg) \ -{ \ - RET_TYPE res; \ - if (!real_ ## SBRK) real_ ## SBRK = dlsym(RTLD_NEXT, #SBRK); \ - res = (*real_ ## SBRK)(arg); \ - if (res != (RET_TYPE) -1) heap_end = (char *) (*real_ ## SBRK)(0); \ - return res; \ -} - -#define BRK_IMPL(RET_TYPE, BRK, ARG_TYPE) \ -RET_TYPE BRK (ARG_TYPE); \ -static RET_TYPE (*real_ ## BRK)(ARG_TYPE) = NULL; \ -RET_TYPE \ -BRK (ARG_TYPE arg) \ -{ \ - RET_TYPE res; \ - if (!real_ ## BRK) real_ ## BRK = dlsym(RTLD_NEXT, #BRK); \ - res = (*real_ ## BRK)(arg); \ - if (res != (RET_TYPE) -1) heap_end = (char *) arg; \ - return res; \ -} - -static char *heap_start = NULL; -static char *heap_end = NULL; - -SBRK_IMPL(SBRK_RET_TYPE, sbrk, SBRK_ARG_TYPE) -#ifdef HAVE_BRK - BRK_IMPL(BRK_RET_TYPE, brk, BRK_ARG_TYPE) -#endif - -#ifdef HAVE__SBRK - SBRK_IMPL(SBRK_RET_TYPE, _sbrk, SBRK_ARG_TYPE) -#endif -#ifdef HAVE__BRK - BRK_IMPL(BRK_RET_TYPE, _brk, BRK_ARG_TYPE) -#endif - -#ifdef HAVE___SBRK - SBRK_IMPL(SBRK_RET_TYPE, __sbrk, SBRK_ARG_TYPE) -#endif -#ifdef HAVE___BRK - BRK_IMPL(BRK_RET_TYPE, __brk, BRK_ARG_TYPE) -#endif - -static int -check_malloc(int size) -{ - char *p = (char *) malloc(size); - if (!heap_start || !heap_end) return 0; - if (!p) return 0; - if (p < heap_start || heap_end <= p) return 0; - if (p + size < heap_start || heap_end < p + size) return 0; - return 1; -} - -#ifdef ETHR_PTHREADS -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -static void * -do_tests(void *vresp) -{ - int i, ok = 0; -#ifdef ETHR_PTHREADS - if (pthread_mutex_lock(&mutex) != 0) - return NULL; -#endif - - for (i = 0; i < 10; i++) - if (!check_malloc(1000)) - goto failed; - for (i = 0; i < 100; i++) - if (!check_malloc(1)) - goto failed; - if (!check_malloc(1024*1024+1)) - goto failed; - if (!check_malloc(10*1024*1024+1)) - goto failed; - ok = 1; - - failed: -#ifdef ETHR_PTHREADS - if (pthread_mutex_unlock(&mutex) != 0) - return NULL; -#endif - if (ok) - *((int *) vresp) = 0; - return NULL; -} - - -int main(void) -{ - int res[N_THR], i; -#ifdef ETHR_PTHREADS - pthread_t tid[N_THR]; -#endif -#if defined(HAVE_END_SYMBOL) - heap_start = &end; -#elif defined(HAVE__END_SYMBOL) - heap_start = &_end; -#endif - -#if defined(HAVE_MALLOPT) && defined(M_MMAP_MAX) - (void) mallopt(M_MMAP_MAX, 0); -#endif - - for (i = 0; i < N_THR; i++) - res[i] = 1; -#ifdef ETHR_PTHREADS - for (i = 1; i < N_THR; i++) - if (pthread_create(&tid[i], NULL, do_tests, &res[i]) != 0) - return 1; -#endif - (void) do_tests(&res[0]); -#ifdef ETHR_PTHREADS - for (i = 1; i < N_THR; i++) - if (pthread_join(tid[i], NULL) != 0) - return 1; -#endif - for (i = 0; i < N_THR; i++) - if (res[i]) - return 1; - return 0; -} - ], - erts_cv_brk_wrappers_can_track_malloc=yes, - erts_cv_brk_wrappers_can_track_malloc=no, - [ - case X$erl_xcomp_dlsym_brk_wrappers in - X) erts_cv_brk_wrappers_can_track_malloc=cross;; - Xyes|Xno) erts_cv_brk_wrappers_can_track_malloc=$erl_xcomp_dlsym_brk_wrappers;; - *) AC_MSG_ERROR([Bad erl_xcomp_dlsym_brk_wrappers value: $erl_xcomp_dlsym_brk_wrappers]);; - esac - ])]) - case $erts_cv_brk_wrappers_can_track_malloc in - yes) - AC_DEFINE(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC, 1, \ -[Define if sbrk()/brk() wrappers can track malloc()s core memory use]);; - cross) - AC_MSG_WARN([result no guessed because of cross compilation]);; - *) ;; - esac -fi - -dnl Restore LIBS -LIBS=$saved_libs -dnl restore CPPFLAGS -CPPFLAGS=$saved_cppflags - -case $ARCH in - x86|amd64) - AC_DEFINE(ERTS_STRUCTURE_ALIGNED_ALLOC, 1, [Define if structure alignment is enough for allocators. If not defined, 64-bit alignment will be forced.]);; - *) - ;; -esac - -LM_SYS_IPV6 -LM_SYS_MULTICAST -ERL_TIME_CORRECTION -AC_CHECK_PROG(M4, m4, m4) - - -dnl Test if JIT can be enabled -JIT_ARCH= -if test ${enable_jit} != no; then - case "$ARCH" in - amd64) - JIT_ARCH=x86 - ;; - *) - if test ${enable_jit} = yes; then - AC_MSG_ERROR([JIT only works on x86 64-bit]) - else - enable_jit=no - AC_MSG_WARN([JIT disabled due to lack to support on $ARCH-$OPSYS]) - fi - ;; - esac - - if test ${enable_jit} != no; then - if test "$CXX" != false; then - AC_LANG_PUSH(C++) - old_CXXFLAGS=$CXXFLAGS - CXXFLAGS="$CXXFLAGS -std=c++17" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([], - [#if __cplusplus < 201703L - #error "Needs C++17 compiler" - #endif])], - [AC_MSG_CHECKING([for C++17 support]) - AC_MSG_RESULT([yes]) - HAVE_CXX17=true], - [AC_MSG_CHECKING([for C++17 support]) - AC_MSG_RESULT([no]) - HAVE_CXX17=false]) - AC_LANG_POP() - fi - if test "$CXX" = false -o "$HAVE_CXX17" = false; then - if test ${enable_jit} = yes; then - AC_MSG_ERROR([JIT needs a C++ compiler with C++17 support]) - else - enable_jit=no - cat >> $ERL_TOP/erts/CONF_INFO <], - [#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) - #define __DARWIN__ 1 - #endif - #if !(defined(__GLIBC__) || defined(__DARWIN__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__sun__)) - #error "Unknown libc. Assume musl, which does not allow safe signals" - #endif], - [AC_MSG_RESULT([yes]) - enable_native_stack=yes], - [AC_MSG_RESULT([no, disabling native stack in JIT]) - enable_native_stack=no] - );; - esac - - if test X${enable_native_stack} = Xyes; then - AC_DEFINE(NATIVE_ERLANG_STACK, [], - [Define if we can use the native stack for Erlang code]) - fi -fi - -dnl -dnl Check if the `perf` profiler is supported. At the moment it assumes it -dnl always works on Linux as we're not dependent on it; this is only used to -dnl to control whether we generate `perf`-compatible memory maps. -dnl -case $OPSYS in - linux*) - AC_DEFINE(HAVE_LINUX_PERF_SUPPORT, 1, - [Define if the targeted system supports the `perf` profiler]) - ;; - *) - ;; -esac - -dnl -dnl Some operating systems allow you to redefine FD_SETSIZE to be able -dnl to select on more than the default number of file descriptors. -dnl We first discovered this in BSD/OS where the default is ridiculously -dnl low (256). But since we use a lot of file descriptors we found the -dnl need to go over the limit in other os's as well. Since FD_SETSIZE -dnl must be defined before pulling in sys/types.h the actual number -dnl of file descriptors is set in acconfig.h and will thus be in config.h -dnl which *always* should be included first. -dnl - -AC_MSG_CHECKING([whether to redefine FD_SETSIZE]) -case $host_os in - bsdi*) - AC_DEFINE(REDEFINE_FD_SETSIZE,[],[Define if you wish to redefine FD_SETSIZE to be able to select on more fd]) - AC_MSG_RESULT(yes) - ;; - *) - AC_MSG_RESULT(no) - ;; -esac - - - -dnl ---------------------------------------------------------------------- -dnl Tests related to configurable options given on command line -dnl (using the --disable, --enable and --with switches). -dnl ---------------------------------------------------------------------- - -JIT_ENABLED= -FLAVORS="emu jit" -# Enable jit -if test X${enable_jit} = Xyes; then - JIT_ENABLED=yes - PRIMARY_FLAVOR=jit -else - PRIMARY_FLAVOR=emu -fi - -AC_SUBST(JIT_ENABLED) -AC_SUBST(JIT_ARCH) -AC_SUBST(PRIMARY_FLAVOR) -AC_SUBST(FLAVORS) - -# -# Check for working poll(). -# -AC_MSG_CHECKING([for working poll()]) -if test "x$ac_cv_header_poll_h" != "xyes" -o "x$ac_cv_func_poll" != "xyes"; then - -poll_works=no - -else - -AC_TRY_RUN([ -#include -main() -{ -#ifdef _POLL_EMUL_H_ - exit(1); /* Implemented using select() -- fail */ -#else - struct pollfd fds[1]; - int fd; - fd = open("/dev/null", 1); - fds[0].fd = fd; - fds[0].events = POLLIN; - fds[0].revents = 0; - if (poll(fds, 1, 0) < 0 || (fds[0].revents & POLLNVAL) != 0) { - exit(1); /* Does not work for devices -- fail */ - } - exit(0); -#endif -} -], -poll_works=yes, -poll_works=no, -[ -case X$erl_xcomp_poll in - X) poll_works=cross;; - Xyes|Xno) poll_works=$erl_xcomp_poll;; - *) AC_MSG_ERROR([Bad erl_xcomp_poll value: $erl_xcomp_poll]);; -esac -]) - -fi - -case $poll_works-$host_os in - no-*|cross-darwin*) - # - # The USE_SELECT define is used by the ssl application (should not - # be used by erts). - # - AC_DEFINE(USE_SELECT, 1, [Define if select() should be used instead of poll()]) - if test $poll_works = cross; then - AC_MSG_RESULT(cross) - AC_MSG_WARN([result no guessed based on OS ($host_os) because of cross compilation]) - else - AC_MSG_RESULT([no; non-existing, broken, or based on select()]) - fi - poll_works=no;; - yes-*|cross-*) - AC_DEFINE(ERTS_USE_POLL, 1, [Define if poll() should be used instead of select()]) - if test $poll_works = cross; then - AC_MSG_RESULT(cross) - AC_MSG_WARN([result yes guessed based on OS ($host_os) because of cross compilation]) - else - AC_MSG_RESULT(yes) - fi - poll_works=yes;; -esac - -# -# If kqueue() found -# -if test $have_kernel_poll = kqueue; then -## Some OS X kernel version seems to have bugs in them with regards to kqueue -## Disable kernel poll on those versions - AC_MSG_CHECKING([whether host os has known kqueue bugs]) - case $host_os in - # Any OS X version < 16 has known problems with using kqueue - # so we don't use it there. See erl_poll.c for details. - darwin[[0-9]].*|darwin1[[0-5]].*) - AC_MSG_RESULT([yes, disabling kernel poll]) - have_kernel_poll=no - ;; - *) - AC_MSG_RESULT([no]) - ;; - esac -fi -# -# If epoll() found, check that it is level triggered. -# -if test $have_kernel_poll = epoll; then - AC_MSG_CHECKING([whether epoll is level triggered]) - AC_TRY_LINK([#include ],[ - #ifdef EPOLLET - /* Edge triggered option exist, assume level triggered - is default */ - ; - #else - /* No edge triggered option exist; assume edge - triggered only */ - #error No EPOLLET - #endif - ], - level_triggered_epoll=yes, - [level_triggered_epoll=no - have_kernel_poll=no]) - AC_MSG_RESULT([$level_triggered_epoll]) -fi -# -# Check if we should enable kernel poll support -# -AC_MSG_CHECKING(whether kernel poll support should be enabled) -ERTS_ENABLE_KERNEL_POLL=no -ERTS_BUILD_FALLBACK_POLL=no -case $enable_kernel_poll-$have_kernel_poll in - no-*) - AC_MSG_RESULT(no; disabled by user);; - yes-no) - AC_MSG_ERROR(no; kernel poll support requested but not found);; - *-no) - AC_MSG_RESULT(no);; - *) - case $have_kernel_poll in - epoll) - AC_DEFINE(HAVE_SYS_EPOLL_H, 1, [Define if you have the header file.]) - ERTS_BUILD_FALLBACK_POLL=yes - ;; - /dev/poll) - AC_DEFINE(HAVE_SYS_DEVPOLL_H, 1, [Define if you have header file.]) - ;; - kqueue) - AC_DEFINE(HAVE_SYS_EVENT_H, 1, [Define if you have header file.]) - ERTS_BUILD_FALLBACK_POLL=yes - ;; - *) - AC_MSG_ERROR(configure.in need to be updated);; - esac - ERTS_ENABLE_KERNEL_POLL=yes - AC_DEFINE(ERTS_ENABLE_KERNEL_POLL, 1, [Define if you have kernel poll and want to use it]) - AC_MSG_RESULT([yes; $have_kernel_poll]);; -esac -AC_SUBST(ERTS_BUILD_FALLBACK_POLL) - -AC_MSG_CHECKING([whether putenv() stores a copy of the key-value pair]) -AC_TRY_RUN([ -#include -int main(void) { - int i; - char *env; - char buf[10]; - for (i = 0; i < 7; i++) - buf[i] = 'X'; - buf[i] = '\0'; - buf[3] = '='; - if (putenv(buf) != 0) - return 1; - for (i = 4; i < 7; i++) - buf[i] = 'Y'; - env = getenv("XXX"); - if (!env) - return 2; - for (i = 0; i < 3; i++) - if (env[i] != 'X') - return 3; - for (i = 0; i < 3; i++) - buf[i] = 'Y'; - env = getenv("XXX"); - if (!env) - return 4; - for (i = 0; i < 3; i++) - if (env[i] != 'X') - return 5; - return 0; -} -], -copying_putenv=yes, -copying_putenv=no, -[ -case X$erl_xcomp_putenv_copy in - X) copying_putenv=cross;; - Xyes|Xno) copying_putenv=$erl_xcomp_putenv_copy;; - *) AC_MSG_ERROR([Bad erl_xcomp_putenv_copy value: $erl_xcomp_putenv_copy]);; -esac -]) - -AC_MSG_RESULT($copying_putenv) -case $copying_putenv in - yes) - AC_DEFINE(HAVE_COPYING_PUTENV,[1],\ -[Define if you have a putenv() that stores a copy of the key-value pair]);; - cross) - AC_MSG_WARN([result no guessed because of cross compilation]);; - *) ;; -esac - -dnl ---------------------------------------------------------------------- -dnl Stuff that should be moved into their respective application -dnl ---------------------------------------------------------------------- - -dnl -dnl We should look for a compiler that handles jump tables, for beam_emu -dnl to be optimized -dnl - -LM_FIND_EMU_CC - -dnl -dnl DTrace & LTTNG -dnl -case $DYNAMIC_TRACE_FRAMEWORK in - dtrace|systemtap) - AC_CHECK_TOOL(DTRACE, dtrace, none) - test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]); - enable_lttng_test=no - enable_dtrace_test=yes;; - lttng) - enable_lttng_test=yes - enable_dtrace_test=no;; - *) - enable_lttng_test=no - enable_dtrace_test=no;; -esac - -AC_SUBST(DTRACE) - -AC_SUBST(DTRACE_CPP) -AC_SUBST(DTRACE_ENABLED) -AC_SUBST(DTRACE_ENABLED_2STEP) -DTRACE_CPP=-C -DTRACE_ENABLED= -DTRACE_ENABLED_2STEP= -DTRACE_2STEP_TEST=./dtrace-test.o -DTRACE_BITS_FLAG= -case $OPSYS in - freebsd) - if test "$BITS64" = "yes" ; then - DTRACE_BITS_FLAG=-64 - else - DTRACE_BITS_FLAG=-32 - fi - ;; - *) - : # Nothing to do - ;; -esac -if test "$enable_dtrace_test" = "yes" ; then - if test "$DTRACE" = "dtrace" ; then - AC_CHECK_HEADERS(sys/sdt.h) - AC_MSG_CHECKING([for 1-stage DTrace precompilation]) - # The OS X version of dtrace prints a spurious line here. - if ! dtrace -h $DTRACE_CPP -Iemulator/beam -o ./foo-dtrace.h -s emulator/beam/erlang_dtrace.d; then - AC_MSG_ERROR([Could not precompile erlang_dtrace.d: dtrace -h failed]) - fi - AC_MSG_RESULT([yes]) - - AC_MSG_CHECKING([for 2-stage DTrace precompilation]) - AC_TRY_COMPILE([ #include "foo-dtrace.h" ], - [ERLANG_DIST_PORT_BUSY_ENABLED();], - [rm -f $DTRACE_2STEP_TEST - dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&AS_MESSAGE_LOG_FD - if test -f $DTRACE_2STEP_TEST; then - rm -f $DTRACE_2STEP_TEST - DTRACE_ENABLED_2STEP=yes - fi], - []) - rm -f foo-dtrace.h - AS_IF([test "x$DTRACE_ENABLED_2STEP" = "xyes"], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no])]) - - DTRACE_ENABLED=yes - case $OPSYS in - linux) - : # No extra libs to add to LIBS - ;; - freebsd) - LIBS="$LIBS -lelf" - ;; - *) - LIBS="$LIBS -ldtrace" - ;; - esac - else - AC_MSG_ERROR([Dtrace preprocessing test failed.]) - fi -fi - -if test "$enable_lttng_test" = "yes" ; then - AC_CHECK_HEADERS(lttng/tracepoint.h) - AC_CHECK_HEADERS(lttng/tracepoint-event.h) - dnl The macro tracepoint_enabled is not present in older lttng versions - dnl checking for tracepoint_enabled - AC_MSG_CHECKING([for tracepoint_enabled in lttng/tracepoint.h]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [#include - #define TRACEPOINT_PROVIDER org_erlang_otp - TRACEPOINT_EVENT( - org_erlang_otp, - dummy, - TP_ARGS(int, my_int), - TP_FIELDS(ctf_integer(int, my_int, my_int))) - #define TRACEPOINT_CREATE_PROBES - #define TRACEPOINT_DEFINE], - [if(tracepoint_enabled(org_erlang_otp,dummy)) do {} while(0)])], - [AC_MSG_RESULT([yes])], - [AC_MSG_ERROR([no (available in lttng-ust v2.7)])]) - if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \ - -a "x$ac_cv_header_lttng_tracepoint_event_h" = "xyes"; then - # No straight forward way to test for liblttng-ust when no public symbol exists, - # just add the lib. - LIBS="$LIBS -llttng-ust -ldl" - else - AC_MSG_ERROR([No LTTng support found.]) - fi -fi - - -#-------------------------------------------------------------------- -# Os mon stuff. -#-------------------------------------------------------------------- -AC_SUBST(os_mon_programs) -AC_SUBST(CPU_SUP_LIBS) - -AC_CHECK_LIB(kstat, kstat_open, [ - use_cpu_sup=yes - CPU_SUP_LIBS="$CPU_SUP_LIBS -lkstat" - ]) - -AC_CHECK_LIB(kvm, kvm_open, [ - use_cpu_sup=yes - CPU_SUP_LIBS="$CPU_SUP_LIBS -lkvm" - ]) - -case $host_os in - solaris2*) - os_mon_programs="$os_mon_programs ferrule mod_syslog" ;; - darwin*) - use_cpu_sup=yes ;; - openbsd*) - use_cpu_sup=yes ;; - linux*) - use_cpu_sup=yes ;; - freebsd*) - use_cpu_sup=yes ;; -esac - -if test "$use_cpu_sup" = "yes"; then - os_mon_programs="$os_mon_programs cpu_sup" -fi - -AC_ARG_WITH(javac, -AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) -AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) -AS_HELP_STRING([--without-javac], [don't use any Java compiler])) - -dnl -dnl Then there are a number of apps which needs a java compiler... -dnl -need_java="jinterface" - -if test -d $ERL_TOP/lib/ic; then - need_java="$need_java ic/java_src" -fi - -# Remove all SKIP files from previous runs -for a in $need_java ; do - rm -f $ERL_TOP/lib/$a/SKIP -done - -if test "X$with_javac" = "Xno"; then - for a in $need_java ; do - echo "Java compiler disabled by user" > $ERL_TOP/lib/$a/SKIP - done - -else # begin - try to find javac - -if test "X$with_javac" != "Xyes" -a "X$with_javac" != "X"; then - check_javac=$with_javac -else - check_javac="javac.sh javac guavac gcj jikes bock" -fi - -AC_CHECK_PROGS(JAVAC, $check_javac) -if test -n "$JAVAC"; then - dnl Make sure it's at least JDK 1.6 - AC_CACHE_CHECK(for JDK version 1.6, - ac_cv_prog_javac_ver_1_6, - [ERL_TRY_LINK_JAVA([], [for (String i : args);], - ac_cv_prog_javac_ver_1_6=yes, ac_cv_prog_javac_ver_1_6=no)]) - if test $ac_cv_prog_javac_ver_1_6 = no; then - unset -v JAVAC - fi -fi -if test -z "$JAVAC"; then - - if test "X$with_javac" != "X"; then - AC_MSG_ERROR([No java compiler found in PATH (checked for $check_javac)]) - fi - - AC_MSG_WARN([Could not find any usable java compiler, will skip: jinterface]) - - for a in $need_java ; do - echo "No Java compiler found" > $ERL_TOP/lib/$a/SKIP - done -fi - -fi # end - try to find javac - -dnl -dnl Orber has a c++ example, this isn't the right way to check for -dnl it, but.... -dnl -AC_SUBST(CXXFLAGS) -dnl this deliberately does not believe that 'gcc' is a C++ compiler -AC_CHECK_TOOLS(CXX, [$CCC c++ g++ CC cxx cc++ cl], false) - -# Remove SKIP file from previous run -rm -f $ERL_TOP/lib/orber/SKIP - -if test "$CXX" = false; then - echo "No C++ compiler found" > $ERL_TOP/lib/orber/SKIP -fi - -dnl ---------------------------------------------------------------------- -dnl Include CPPFLAGS in CFLAGS -dnl ---------------------------------------------------------------------- -CFLAGS="$CFLAGS $CPPFLAGS" - -# -# Currently if we compile for 64 bits we want to compile -# some external port programs using 32 bits -# - -# If not defined we trust the C compiler in $CC to do 32 bits -if test -z "$CC32"; then - CC32="$CC" -fi - -if test -z "$CFLAGS32"; then - if test $ac_cv_sizeof_void_p != 4; then - # We are compiling default 64 bits and use -m32 for 32 bit compilations - CFLAGS32="$CFLAGS -m32" - else - CFLAGS32="$CFLAGS" - fi -fi - -AC_SUBST(CC32) -AC_SUBST(CFLAGS32) - -dnl -dnl ERTS_EMU_CMDLINE_FLAGS will force modification of config.h when -dnl the emulator command line flags are modified by configure, which -dnl in turn will make 'make' detect that files depending on config.h -dnl needs to be rebuilt. -dnl - -AC_DEFINE_UNQUOTED(ERTS_EMU_CMDLINE_FLAGS, -"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS", -[The only reason ERTS_EMU_CMDLINE_FLAGS exists is to force modification of config.h when the emulator command line flags are modified by configure]) - -AC_SUBST(STATIC_CFLAGS) - -dnl ---------------------------------------------------------------------- -dnl Directories needed for the build -dnl ---------------------------------------------------------------------- - -erts=${erl_top}/erts - -erts_dirs=" - $erts/obj $erts/obj.debug - - $erts/obj/$host - $erts/obj.debug/$host - -" -for d in ${erl_top}/bin ${erl_top}/bin/$host $erts_dirs ; -do - if test ! -d $d; then - mkdir -p 1>/dev/null 2>&1 $d - fi -done - -dnl --------------------------------------------------------------------- -dnl Autoheader macro for adding code at top and bottom of config.h.in -dnl --------------------------------------------------------------------- -AH_TOP([ -#ifndef __ERTS_CONFIG_H__ -#define __ERTS_CONFIG_H__ - -#define GHBN_R_SOLARIS 2 -#define GHBN_R_AIX 3 -#define GHBN_R_GLIBC 4 -]) - -AH_BOTTOM([ -/* Redefine in6_addr. XXX this should be moved to the files where it's used? */ -#ifdef HAVE_IN_ADDR6_STRUCT -#define in6_addr in_addr6 -#endif - -/* Define a reasonable default for INADDR_LOOPBACK */ -/* XXX this should be moved to the files where it's used? */ -#ifdef HAVE_NO_INADDR_LOOPBACK -#define INADDR_LOOPBACK (u_long)0x7F000001 -#endif - -#ifdef REDEFINE_FD_SETSIZE -#define FD_SETSIZE 1024 -#endif - -#ifdef HAVE_GETHRVTIME_PROCFS_IOCTL -#define HAVE_GETHRVTIME -#endif - -#if !defined(HAVE_ISFINITE) && !defined(HAVE_FINITE) -# if defined(HAVE_ISINF) && defined(HAVE_ISNAN) -# define USE_ISINF_ISNAN -# endif -#endif - -#if defined(DEBUG) && !defined(ERTS_ENABLE_LOCK_CHECK) -#define ERTS_ENABLE_LOCK_CHECK 1 -#endif - -#endif /* __ERTS_CONFIG_H__ */ -]) - -dnl ---------------------------------------------------------------------- -dnl Check for log2 -dnl ---------------------------------------------------------------------- -AC_CHECK_FUNCS([log2]) - - -dnl ---------------------------------------------------------------------- -dnl Check for GCC diagnostic ignored "-Waddress-of-packed-member" -dnl ---------------------------------------------------------------------- -saved_CFLAGS="$CFLAGS" -CFLAGS="-Werror $CFLAGS" -AC_TRY_COMPILE([], - [_Pragma("GCC diagnostic push") - _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") - _Pragma("GCC diagnostic pop") - ], - AC_DEFINE(HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER,[1], - [define if compiler support _Pragma('GCC diagnostic ignored '-Waddress-of-packed-member'')])) -CFLAGS="$saved_CFLAGS" - - -dnl ---------------------------------------------------------------------- -dnl Enable any -Werror flags -dnl ---------------------------------------------------------------------- - -if test "x$GCC" = xyes; then - CFLAGS="$WERRORFLAGS $CFLAGS" -fi - -dnl ---------------------------------------------------------------------- -dnl Enable -fsanitize= flags. -dnl ---------------------------------------------------------------------- - -m4_define(DEFAULT_SANITIZERS, [address,undefined]) -AC_ARG_ENABLE( - sanitizers, - AS_HELP_STRING( - [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], - [Default=DEFAULT_SANITIZERS]), -[ -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" -]) - -dnl ---------------------------------------------------------------------- -dnl Output the result. -dnl ---------------------------------------------------------------------- - -dnl Note that the output files are relative to $srcdir -AC_CONFIG_FILES([ - emulator/$host/Makefile:emulator/Makefile.in - epmd/src/$host/Makefile:epmd/src/Makefile.in - etc/common/$host/Makefile:etc/common/Makefile.in - include/internal/$host/ethread.mk:include/internal/ethread.mk.in - include/internal/$host/erts_internal.mk:include/internal/erts_internal.mk.in - lib_src/$host/Makefile:lib_src/Makefile.in - ../make/$host/otp.mk:../make/otp.mk.in -]) - -AC_CONFIG_FILES([../make/make_emakefile:../make/make_emakefile.in], - [chmod +x ../make/make_emakefile]) - -dnl -dnl The ones below should be moved to their respective lib -dnl -AC_CONFIG_FILES([ - ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in - ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in - ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in - ]) - -AC_CONFIG_FILES([../make/install_dir_data.sh:../make/install_dir_data.sh.in], [chmod +x ../make/install_dir_data.sh]) - -AC_OUTPUT diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index c70ea23aaa6b..d5c27bb200a7 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -4,7 +4,7 @@
- 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -411,6 +411,13 @@ {lc,ANNO,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}. For Rep(Q), see below.

+ +

If E is a map comprehension #{E_0 || Q_1, ..., Q_k}, + where E_0 is an association K => V + and each Q_i is a qualifier, then Rep(E) = + {mc,ANNO,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}. + For Rep(E_0) and Rep(Q), see below.

+

If E is a map creation #{A_1, ..., A_k}, where each A_i is an association E_i_1 => E_i_2, @@ -429,6 +436,21 @@ where P is a pattern, then Rep(E) = {match,ANNO,Rep(P),Rep(E_0)}.

+ +

If E is a conditional match operator expression P ?= E_0, + where P is a pattern, then Rep(E) = + {maybe_match,ANNO,Rep(P),Rep(E_0)}.

+
+ +

If E is a maybe expression maybe B end, + where B is a body then Rep(E) = + {'maybe',ANNO,Rep(B)}.

+
+ +

If E is a maybe expression maybe B else Ec_1 ; ... ; Ec_k end, + where B is a body and each Ec_i is an else clause then Rep(E) = + {'maybe',ANNO,Rep(B),{'else',ANNO,[Rep(Ec_1), ..., Rep(Tc_k)]}}.

+

If E is nil, [], then Rep(E) = {nil,ANNO}.

@@ -549,7 +571,7 @@ Rep(Q) = Rep(E).

-

If Q is a generator P <- E, where P is +

If Q is a list generator P <- E, where P is a pattern and E is an expression, then Rep(Q) = {generate,ANNO,Rep(P),Rep(E)}.

@@ -558,6 +580,12 @@ a pattern and E is an expression, then Rep(Q) = {b_generate,ANNO,Rep(P),Rep(E)}.

+ +

If Q is a map generator P <- E, where P is + an association pattern P_1 := P_2 and E is an expression, then Rep(Q) = + {m_generate,ANNO,Rep(P),Rep(E)}. + For Rep(P), see below.

+
diff --git a/erts/doc/src/alt_dist.xml b/erts/doc/src/alt_dist.xml index d8d8765b9144..f6b93271881f 100644 --- a/erts/doc/src/alt_dist.xml +++ b/erts/doc/src/alt_dist.xml @@ -4,7 +4,7 @@
- 20002020 + 20002022 Ericsson AB. All Rights Reserved. @@ -314,8 +314,18 @@ accept_connection/5 should spawn a process that will perform the Erlang distribution handshake for the connection. If the handshake successfully completes it should continue to - function as a connection supervisor. This process - should preferably execute on max priority. + function as a connection supervisor. This process should + preferably execute on max priority and should be linked + to the caller. The dist_util:net_ticker_spawn_options() + function can be called to get spawn options suitable for this process + which can be passed directly to + erlang:spawn_opt/4. + dist_util:net_ticker_spawn_options() will by default return + [link, {priority, max}], but allows the user to configure more + options using the + net_ticker_spawn_options + kernel parameter. The process identifier of this process should be + returned.

The arguments:

@@ -380,8 +390,18 @@ Node. When connection has been established it should perform the Erlang distribution handshake for the connection. If the handshake successfully completes it should continue to - function as a connection supervisor. This process - should preferably execute on max priority. + function as a connection supervisor. This process should + preferably execute on max priority and should be linked + to the caller. The dist_util:net_ticker_spawn_options() + function can be called to get spawn options suitable for this process + which can be passed directly to + erlang:spawn_opt/4. + dist_util:net_ticker_spawn_options() will by default return + [link, {priority, max}], but allows the user to configure more + options using the + net_ticker_spawn_options + kernel parameter. The process identifier of this process should be + returned.

The arguments:

@@ -1025,7 +1045,7 @@ header of four bytes containing the length of the package in a big-endian 32-bit integer. As Unix domain sockets only can be used between processes on the same machine, we do not need to - code the integer in some special endianess, but we will do it anyway + code the integer in some special endianness, but we will do it anyway because in most situation you need to do it. Unix domain sockets are reliable and order maintaining, so we do not need to implement resends and such in the driver.

@@ -1410,7 +1430,7 @@
Selected Parts of the Distribution Driver Implementation -

The implemenation of the distribution driver is not completely +

The implementation of the distribution driver is not completely covered here, details about buffering and other things unrelated to driver writing are not explained. Likewise are some peculiarities of the UDS protocol not explained in diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml index 4524401473df..bc3e0850997b 100644 --- a/erts/doc/src/crash_dump.xml +++ b/erts/doc/src/crash_dump.xml @@ -4,7 +4,7 @@

- 19992022 + 19992023 Ericsson AB. All Rights Reserved. @@ -534,7 +534,7 @@ Slogan: <reason> Type

The table type, that is, set, bag, - dublicate_bag, or ordered_set.

+ duplicate_bag, or ordered_set.

Compressed diff --git a/erts/doc/src/erl_cmd.xml b/erts/doc/src/erl_cmd.xml index 5803647d2925..f6a36ecffd89 100644 --- a/erts/doc/src/erl_cmd.xml +++ b/erts/doc/src/erl_cmd.xml @@ -4,7 +4,7 @@
- 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -283,10 +283,11 @@ $ erl \ -

If this flag is present, does not maintain - a fully connected network of distributed Erlang nodes, and then - global name registration cannot be used; see - global(3).

+

+ This flag is deprecated and has been replaced by the kernel + application parameter + connect_all. +

@@ -300,6 +301,25 @@ $ erl \ console. Useful for running daemons and backgrounds processes. Implies .

+ + + + + +

Disables the + feature + in the runtime system. The special feature all can be + used to disable all non permanent features. +

+
+ -dist_listen true|false +

+ Specifies whether this node should be listening for incoming + distribution connections or not. By default a node will listen for + incoming connections. Setting this option to false + implies -hidden. +

Useful for debugging. Prints the arguments sent to the emulator.

@@ -318,7 +338,10 @@ $ erl \ build a specific flavor by doing make FLAVOR=$FLAVOR in the Erlang/OTP source repository.)

- + + + +

Start an emulator of a different type. For example, to start the lock-counter emulator, use -emu_type lcnt. @@ -329,6 +352,18 @@ $ erl \ Use the configure option --enable-lock-counter to build the lock-counter emulator.)

+ + + + + +

Enables the + feature + in the runtime system. The special feature all can be + used to enable all features. +

+

Sets the host OS environment variable to @@ -400,7 +435,7 @@ $ erl \ the name supplied together with flag or .

- +

Makes write some debug information while interpreting the boot script.

@@ -461,10 +496,12 @@ $ erl \

Makes the Erlang runtime system into a distributed node. This flag invokes all network servers necessary for a node to become distributed; see - net_kernel(3). It is also ensured that + net_kernel(3). It also ensures that runs on the current host before Erlang is - started; see epmd(1) and the - -start_epmd option.

+ started (see epmd(1) and the + -start_epmd option) and + that a magic cookie has been set + (see -setcookie).

The node name will be , where is the fully qualified host name of the current host. For short names, use flag @@ -503,12 +540,12 @@ $ erl \ to implement an Alternative Carrier for the Erlang Distribution.

- +

Ensures that the Erlang runtime system never tries to read any input. Implies .

- +

Starts an Erlang runtime system with no shell. This flag makes it possible to have the Erlang runtime system as a @@ -580,6 +617,9 @@ $ erl \

Before OTP-23 the user needed to supply a valid -sname or -name for -remsh to work. This is still the case if the target node is not running OTP-23 or later.

+

The connecting node needs to have a proper shell with terminal emulation. + This means that UNIX users must use an Erlang compiled with terminal capabilities and + Windows users must use werl(1).

@@ -608,11 +648,14 @@ $ erl \ passed as atoms. See init(3).

- +

Sets the magic cookie of the node to ; see - - erlang:set_cookie/2.

+ erlang:set_cookie/1. + See see section + Distributed Erlang + in the Erlang Reference Manual for more details. +

@@ -893,7 +936,7 @@ $ erl \

Sets the default maximum heap size of processes to the size - . Defaults to 0, which means that no + words. Defaults to 0, which means that no maximum heap size is used. For more information, see process_flag(max_heap_size, MaxHeapSize).

@@ -906,6 +949,14 @@ $ erl \ process_flag(max_heap_size, MaxHeapSize).

+ + +

Sets whether to include the size of shared off-heap binaries + in the sum compared against the maximum heap size. Defaults to + false. For more information, see + + process_flag(max_heap_size, MaxHeapSize).

+

Sets whether to kill processes reaching the maximum heap size or not. @@ -961,15 +1012,62 @@ $ erl \ +IOt are used, +IOPt is ignored.

- +JPperf true|false + +IOs true|false + +

Enable or disable scheduler thread poll optimization. Default is + true. +

+

If enabled, file descriptors that are frequently read may be moved to + a special pollset used by scheduler threads. The objective is to + reduce the number of system calls and thereby CPU load, but it can + in some cases increase scheduling latency for individual file + descriptor input events. +

+
+ +JPperf true|false|dump|map|fp|no_fp -

Enables or disables support for the `perf` profiler when running - with the JIT on Linux. Defaults to false.

+

Enables or disables support for the perf profiler when + running with the JIT on Linux. Defaults to false.

+

This option can be combined multiple times to enable several + options:

+ + dump + Gives perf detailed line information, so that the + perf annotate feature works. + map + Gives perf a map over all module code, letting it + translate machine code addresses to Erlang source code + locations. This also enables frame pointers for Erlang code so that + perf can walk the call stacks of Erlang processes, which + costs one extra word per stack frame. + fp + Enables frame pointers independently of the map + option. + no_fp + Disables the frame pointers added by the map + option. + true + Enables map and dump. + false + Disables all other options. +

For more details about how to run perf see the perf support section in the BeamAsm internal documentation.

+ +JMsingle true|false + +

Enables or disables the use of single-mapped RWX memory for JIT + code. The default is to map JIT:ed machine code into two + regions sharing the same physical pages, where one region is + executable but not writable, and the other writable but not + executable. As some tools, such as QEMU user mode emulation, + cannot deal with the dual mapping, this flags allows it to be + disabled. This flag is automatically enabled by the + +JPperf flag. +

+

Prevents loading information about source filenames and line @@ -981,6 +1079,23 @@ $ erl \

Memory allocator-specific flags. For more information, see erts_alloc(3).

+ +pad true|false + +

Since: OTP 25.3

+

+ The boolean value used with the +pad parameter determines + the default value of the + + async_dist process flag of newly spawned processes. + By default, if no +pad command line option is passed, + the async_dist flag will be set to false. +

+

+ The value used in runtime can be inspected by calling + + erlang:system_info(async_dist). +

+
@@ -1501,6 +1616,16 @@ $ erl \ erlang:system_info(cpu_topology).

+ +ssrct + +

Skips reading CPU topology.

+ +

Reading CPU topology slows down startup when starting many + parallel instances of ERTS on systems with large amount of + cores, using this flag might speed up execution in such + scenarios.

+
+
+sfwi Interval

Sets scheduler-forced wakeup interval. All run queues are @@ -1716,6 +1841,11 @@ $ erl \ limit is per distribution channel. A higher limit gives lower latency and higher throughput at the expense of higher memory use.

+

+ This limit only affects processes that have disabled + fully + asynchronous distributed signaling. +

+zdntgc time @@ -1782,7 +1912,7 @@ $ erl \ A negative value causes the termination of the runtime system - to wait indefinitely until the crash dump file has been completly + to wait indefinitely until the crash dump file has been completely written. This is the default if option -heart is not passed to erl and ERL_CRASH_DUMP_SECONDS is not set. @@ -1871,14 +2001,17 @@ $ erl \ The .erlang startup file

When Erlang/OTP is started, the system searches for a file named - .erlang in the user's home directory.

+ .erlang in the + user's home directory and then + + filename:basedir(user_config, "erlang").

If an .erlang file is found, it is assumed to contain valid Erlang expressions. These expressions are evaluated as if they were input to the shell.

A typical .erlang file contains a set of search paths, for example:

diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml index de0b125c3aa5..389e967f5fa1 100644 --- a/erts/doc/src/erl_dist_protocol.xml +++ b/erts/doc/src/erl_dist_protocol.xml @@ -5,7 +5,7 @@
2007 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -161,7 +161,8 @@ LowestVersion

The lowest distribution version that this node can handle. - Should be 5 to support connections to nodes older than OTP 23.

+ The value in OTP 25 and later is 6 as support for connections to + nodes older than OTP 23 has been dropped.

Nlen @@ -549,12 +550,19 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n",

This section describes the distribution handshake protocol used between nodes to establishing a connection. The protocol was introduced in - Erlang/OTP R6 and has remained unchanged until OTP 23. The changes made in - OTP 23 were designed to be compatible with the older protocol - version. That is an old node can still connect toward a new node and vice - versa. + Erlang/OTP R6 and amended in OTP 23. From OTP 25 support for the older + protocol was dropped. Therefore an OTP 25 node can not connect to nodes + older than OTP 23. This documentation only decribes the part of the + protocol used by OTP 25.

- + +

+ A bug introduced in OTP 25.0 may cause OTP 25 nodes to reject connection + attempts from OTP 23 and 24 nodes that are not using epmd to gain + version information about the remote node. + This is fixed in OTP 25.3. +

+
General

The TCP/IP distribution uses a handshake that expects a @@ -658,19 +666,20 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n",

- The old send_name format is sent from nodes only supporting version 5 - or to nodes that might only support version 5. The Version is - a 16-bit big endian integer and must always have the value 5, even - if node A supports version 6. Flags are the + The old send_name format is only sent from OTP 23 and 24 + nodes that are not using epmd and therefore do not know if + the remote node only supports protocol version 5. The Version is + a 16-bit big endian integer and must always have the value + 5 (even though node A supports version 6). Flags are the capability flags of node A in 32-bit big endian. The flag bit DFLAG_HANDSHAKE_23 - should be set if node A supports version 6. + must be set (as node A must supports version 6). Name is the full node name of A, as a string of bytes (the packet length denotes how long it is).

- The new send_name is only sent from nodes supporting version 6 to + The new send_name is sent to nodes known to support version 6. Flags are the capability flags of node A in 64-bit big endian. The flag bit @@ -682,6 +691,11 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n", 16-bit big endian. Any extra data after the node Name must be accepted and ignored.

+

+ The Name must be just the host name (without @) when + DFLAG_NAME_ME + is set. +

3) recv_status/send_status @@ -737,34 +751,39 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n", named:

- The handshake willl continue, but A requested a dynamic + The handshake will continue, but A requested a dynamic node name by setting flag DFLAG_NAME_ME. The dynamic node name of A is supplied at the end of the status message from - B.

-
+ B. The host name of A which was sent as Name + in send_name will be used by node B to generate + the full dynamic node name.

+ + + 1 + Slen=6 + 2 + Nlen + 4 + + + 's' + Status='named:' + Nlen + Name + Creation + + The format of the 'named:' status message +
+

+ Name is the full dynamic node name of A, as a + string of bytes. Nlen is the byte length of the node name in + 16-bit big endian. Creation is the incarnation identifier + of node A generated by node B. + Any extra data after the node Creation must be accepted and ignored. +

+ - - - 1 - Slen=6 - 2 - Nlen - - - 's' - Status='named:' - Nlen - Name - - The format of the 'named:' status message -
-

- Name is the full dynamic node name of A, as a - string of bytes. Nlen is the byte length of the node name in - 16-bit big endian. Any extra data after the node Name must be - accepted and ignored. -

3B) send_status/recv_status @@ -780,26 +799,8 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n", handshake continues with B sending A another message, the challenge. The challenge contains the same type of information as the "name" message initially sent from A to B, plus - a 32-bit challenge. The challenge message can have two different - formats: + a 32-bit challenge:

- - - 1 - 2 - 4 - 4 - Nlen - - - 'n' - Version=5 - Flags - Challenge - Name - - The old challenge message format (version 5) -
1 @@ -819,32 +820,18 @@ io:format("old/unused name ~ts at port ~p, fd = ~p ~n", The new challenge message format (version 6)
-

- The old challenge message is sent from old B nodes - (supporting only version 5) or if node A had not capability flag - DFLAG_HANDSHAKE_23 - set. The Version is a 16-bit big endian integer and - must always have the value 5. -

-

- The new challenge message is sent from new B nodes if node - A had capability flag - DFLAG_HANDSHAKE_23 set. Any extra data after the - node Name must be accepted and ignored. -

Challenge is a 32-bit big-endian integer. The other fields are node B's flags, creation and full node name, similar to - the send_name message. + the send_name message. Any extra data after the node + Name must be accepted and ignored.

-
- + 4B) send_complement/recv_complement

The complement message, from A to B, is only sent if - node A initially sent an old name message and received back a - new challenge message from node B. It contains complementary + node A initially sent an old name message. It contains complementary information missing in the initial old name message from node A.

@@ -940,7 +927,7 @@ recv_status <---------------------------------------------- send_challenge recv_challenge -(if old send_name and new recv_challenge +(if old send_name send_complement - - - - - - - - - - - - - - - -> recv_complement) @@ -996,9 +983,9 @@ DiB == gen_digest(ChA, ICA)? -define(DFLAG_FUN_TAGS,16#10). -

The node uses separate tag for funs (lambdas) in the distribution - protocol.

-

This flag will become mandatory in OTP 25.

+

The node uses separate tags for funs (lambdas) in the + distribution protocol. This flag is mandatory. If not + present, the connection is refused.

-define(DFLAG_DIST_MONITOR_NAME,16#20). @@ -1024,20 +1011,21 @@ DiB == gen_digest(ChA, ICA)? -define(DFLAG_EXPORT_PTR_TAG,16#200).

The node understands the - EXPORT_EXT tag.

-

This flag will become mandatory in OTP 25.

+ EXPORT_EXT tag. + This flag is mandatory. If not present, the connection is refused. +

-define(DFLAG_BIT_BINARIES,16#400).

The node understands the - BIT_BINARY_EXT tag.

-

This flag will become mandatory in OTP 25.

+ BIT_BINARY_EXT tag. + This flag is mandatory. If not present, the connection is refused.

-define(DFLAG_NEW_FLOATS,16#800).

The node understands the - NEW_FLOAT_EXT tag.

-

This flag will become mandatory in OTP 25.

+ NEW_FLOAT_EXT tag. This flag is + mandatory. If not present, the connection is refused.

-define(DFLAG_UNICODE_IO,16#1000). @@ -1063,8 +1051,8 @@ DiB == gen_digest(ChA, ICA)? -define(DFLAG_MAP_TAG, 16#20000).

The node understands the map tag - MAP_EXT.

-

This flag will become mandatory in OTP 25.

+ MAP_EXT. This flag is + mandatory. If not present, the connection is refused.

-define(DFLAG_BIG_CREATION, 16#40000). @@ -1104,16 +1092,20 @@ DiB == gen_digest(ChA, ICA)? -define(DFLAG_HANDSHAKE_23, 16#1000000).

The node supports the new connection setup handshake (version 6) - introduced in OTP 23.

+ introduced in OTP 23. This flag is mandatory (from OTP 25). If not + present, the connection is refused.

-define(DFLAG_UNLINK_ID, 16#2000000). -

Use the new link protocol.

-

This flag will become mandatory in OTP 26.

-

Unless both nodes have set the DFLAG_UNLINK_ID flag, the - old link protocol - will be used as a fallback.

+

Use the new link protocol.

+

This flag is mandatory as of OTP 26.

+ -define(DFLAG_MANDATORY_25_DIGEST, (1 bsl 36)). + +

The node supports all capabilities that are mandatory in OTP 25. + Introduced in OTP 25.

+

This flag will become mandatory in OTP 27.

+
-define(DFLAG_SPAWN, (1 bsl 32)).

Set if the SPAWN_REQUEST, @@ -1138,8 +1130,7 @@ DiB == gen_digest(ChA, ICA)? V4_PORT_EXT, and in the reference case up to 5 32-bit ID words are now accepted in NEWER_REFERENCE_EXT. - Introduced in OTP 24.

-

This flag will become mandatory in OTP 26.

+ This flag was introduced in OTP 24 and became mandatory in OTP 26.

-define(DFLAG_ALIAS, (1 bsl 35)). @@ -1278,17 +1269,12 @@ DiB == gen_digest(ChA, ICA)?

{3, FromPid, ToPid, Reason}

This signal is sent when a link has been broken

- UNLINK (deprecated) + UNLINK (obsolete)

{4, FromPid, ToPid}

-

This signal is sent by FromPid in order to remove - a link between FromPid and ToPid, when using the - old link - protocol.

-

This signal has been deprecated and will not - be supported in OTP 26. For more information see the - documentation of the - new link protocol. +

This signal is obsolete and not supported as of + OTP 26. For more information see the documentation of the + link protocol.

NODE_LINK @@ -1419,7 +1405,7 @@ DiB == gen_digest(ChA, ICA)?
PAYLOAD_EXIT_TT -

{25, FromPid, ToPid}

+

{25, FromPid, ToPid, TraceToken}

Followed by Reason.

This control message replaces the EXIT_TT control @@ -1441,7 +1427,7 @@ DiB == gen_digest(ChA, ICA)? PAYLOAD_EXIT2_TT -

{27, FromPid, ToPid}

+

{27, FromPid, ToPid, TraceToken}

Followed by Reason.

This control message replaces the EXIT2_TT control @@ -1452,7 +1438,7 @@ DiB == gen_digest(ChA, ICA)? PAYLOAD_MONITOR_P_EXIT -

{28, FromPid, ToPid, Ref}

+

{28, FromProc, ToPid, Ref}

Followed by Reason.

This control message replaces the MONITOR_P_EXIT control @@ -1578,11 +1564,9 @@ DiB == gen_digest(ChA, ICA)? among all not yet acknowledged UNLINK_ID signals from FromPid to ToPid.

- This signal is only passed when the - new link protocol - has been negotiated using the - DFLAG_UNLINK_ID - distribution flag. + This signal is part of the + new link protocol + which became mandatory as of OTP 26.

UNLINK_ID_ACK @@ -1597,11 +1581,9 @@ DiB == gen_digest(ChA, ICA)? ToPid identifies the sender of the UNLINK_ID signal.

- This signal is only passed when the - new link protocol - has been negotiated using the - DFLAG_UNLINK_ID - distribution flag. + This signal is part of the + new link protocol + which became mandatory as of OTP 26.

@@ -1632,200 +1614,173 @@ DiB == gen_digest(ChA, ICA)?
+ + + Link Protocol -
- - New Link Protocol - -

- The new link protocol will be used when both nodes flag that - they understand it using the - DFLAG_UNLINK_ID - distribution flag. If - one of the nodes does not understand the new link protocol, the - old link protocol - will be used as a fallback. -

- -

- The new link protocol introduces two new signals, - UNLINK_ID and - UNLINK_ID_ACK, - which replace the old - UNLINK - signal. The old LINK - signal is still sent in order to set up a link, but handled - differently upon reception. -

- -

- In order to set up a link, a LINK signal is sent, from - the process initiating the operation, to the process that it - wants to link to. In order to remove a link, an - UNLINK_ID signal is sent, from the process initiating - the operation, to the linked process. The receiver of an - UNLINK_ID signal responds with an UNLINK_ID_ACK - signal. Upon reception of an UNLINK_ID signal, the - corresponding UNLINK_ID_ACK signal must be - sent before any other signals are sent to the sender of the - UNLINK_ID signal. Together with - the - signal ordering guarantee of Erlang this makes it - possible for the sender of the UNLINK_ID signal to know - the order of other signals which is essential for the protocol. - The UNLINK_ID_ACK signal should contain the same - Id as the Id contained in the UNLINK_ID - signal being acknowledged. -

+

+ The new link protocol introduced in OTP 23.3 became mandatory + as of OTP 26. As of OTP 26, OTP nodes will therefor refuse to + connect to nodes that do not indicate that they support the + new link protocol using the + DFLAG_UNLINK_ID + distribution flag. +

-

- Processes also need to maintain process local information about - links. The state of this process local information is changed - when the signals above are sent and received. This process - local information also determines if a signal should be sent - when a process calls - link/1 or - unlink/1. - A LINK signal is only sent if there does not currently - exist an active link between the processes according to the - process local information and an UNLINK_ID signal is - only sent if there currently exists an active link between the - processes according to the process local information. -

+

+ The new link protocol introduced two new signals, + UNLINK_ID and + UNLINK_ID_ACK, + which replaced the old + UNLINK + signal. The old LINK + signal is still sent in order to set up a link, but handled + differently upon reception. +

-

- The process local information about a link contains: -

- - Pid - - Process identifier of the linked process. - - Active Flag - - If set, the link is active and the process will react on - incoming - exit signals issued due to the link. If not set, - the link is inactive and incoming exit signals, issued due - to the link, will be ignored. That is, the processes are - considered as not linked. - - Unlink Id - - Identifier of an outstanding unlink operation. That is, - an unlink operation that has not yet been acknowledged. - This information is only used when the active flag is not - set. - - +

+ In order to set up a link, a LINK signal is sent, from + the process initiating the operation, to the process that it + wants to link to. In order to remove a link, an + UNLINK_ID signal is sent, from the process initiating + the operation, to the linked process. The receiver of an + UNLINK_ID signal responds with an UNLINK_ID_ACK + signal. Upon reception of an UNLINK_ID signal, the + corresponding UNLINK_ID_ACK signal must be + sent before any other signals are sent to the sender of the + UNLINK_ID signal. Together with + the + signal ordering guarantee of Erlang this makes it + possible for the sender of the UNLINK_ID signal to know + the order of other signals which is essential for the protocol. + The UNLINK_ID_ACK signal should contain the same + Id as the Id contained in the UNLINK_ID + signal being acknowledged. +

-

- A process is only considered linked to another process - if it has process local information about the link - containing the process identifier of the other process and - with the active flag set. -

+

+ Processes also need to maintain process local information about + links. The state of this process local information is changed + when the signals above are sent and received. This process + local information also determines if a signal should be sent + when a process calls + link/1 or + unlink/1. + A LINK signal is only sent if there does not currently + exist an active link between the processes according to the + process local information and an UNLINK_ID signal is + only sent if there currently exists an active link between the + processes according to the process local information. +

-

- The process local information about a link is updated as - follows: -

- - A LINK signal is sent - - Link information is created if not already existing. The - active flag is set, and unlink id is cleared. That is, - if we had an outstanding unlink operation we will ignore - the result of that operation and enable the link. - - A LINK signal is received - - If no link information already exists, it is created, the - active flag is set and unlink id is cleared. If the link - information already exists, the signal is silently ignored, - regardless of whether the active flag is set or not. - That is, if we have an outstanding unlink operation we will - not activate the link. In this scenario, the sender - of the LINK signal has not yet sent an - UNLINK_ID_ACK signal corresponding to our - UNLINK_ID signal which means that it will receive - our UNLINK_ID signal after it sent its - LINK signal. This in turn means that both processes - in the end will agree that there is no link between them. - - An UNLINK_ID signal is sent - - Link information already exists and the active flag is set - (otherwise the signal would not be sent). The active flag - is unset, and the unlink id of the signal is saved in the - link information. - - An UNLINK_ID signal is received - - If the active flag is set, information about the link - is removed. If the active flag is not set (that is, we have - an outstanding unlink operation), the information about the - link is left unchanged. - - An UNLINK_ID_ACK signal is sent - - This is done when an UNLINK_ID signal is received and - causes no further changes of the link information. - - An UNLINK_ID_ACK signal is received - - If information about the link exists, the active flag is not - set, and the unlink id in the link information equals the - Id in the signal, the link information is removed; - otherwise, the signal is ignored. - - +

+ The process local information about a link contains: +

+ + Pid + + Process identifier of the linked process. + + Active Flag + + If set, the link is active and the process will react on + incoming + exit signals issued due to the link. If not set, + the link is inactive and incoming exit signals, issued due + to the link, will be ignored. That is, the processes are + considered as not linked. + + Unlink Id + + Identifier of an outstanding unlink operation. That is, + an unlink operation that has not yet been acknowledged. + This information is only used when the active flag is not + set. + + -

- When a process receives an exit signal due to a link, the - process will first react to the exit signal if the link - is active and then remove the process local information about - the link. -

-

- In case the connection is lost between two nodes, exit signals - with exit reason noconnection are sent to all processes - with links over the connection. This will cause all process - local information about links over the connection to be - removed. -

-

- Exactly the same link protocol is also used internally on an - Erlang node. The signals however have different formats since - they do not have to be sent over the wire. -

-
+

+ A process is only considered linked to another process + if it has process local information about the link + containing the process identifier of the other process and + with the active flag set. +

-
- - Old Link Protocol +

+ The process local information about a link is updated as + follows: +

+ + A LINK signal is sent + + Link information is created if not already existing. The + active flag is set, and unlink id is cleared. That is, + if we had an outstanding unlink operation we will ignore + the result of that operation and enable the link. + + A LINK signal is received + + If no link information already exists, it is created, the + active flag is set and unlink id is cleared. If the link + information already exists, the signal is silently ignored, + regardless of whether the active flag is set or not. + That is, if we have an outstanding unlink operation we will + not activate the link. In this scenario, the sender + of the LINK signal has not yet sent an + UNLINK_ID_ACK signal corresponding to our + UNLINK_ID signal which means that it will receive + our UNLINK_ID signal after it sent its + LINK signal. This in turn means that both processes + in the end will agree that there is no link between them. + + An UNLINK_ID signal is sent + + Link information already exists and the active flag is set + (otherwise the signal would not be sent). The active flag + is unset, and the unlink id of the signal is saved in the + link information. + + An UNLINK_ID signal is received + + If the active flag is set, information about the link + is removed. If the active flag is not set (that is, we have + an outstanding unlink operation), the information about the + link is left unchanged. + + An UNLINK_ID_ACK signal is sent + + This is done when an UNLINK_ID signal is received and + causes no further changes of the link information. + + An UNLINK_ID_ACK signal is received + + If information about the link exists, the active flag is not + set, and the unlink id in the link information equals the + Id in the signal, the link information is removed; + otherwise, the signal is ignored. + + -

- The old link protocol utilize two signals - LINK, and - UNLINK. The - LINK signal informs the other process that a link - should be set up, and the UNLINK signal informs the - other process that a link should be removed. This protocol - is however a bit too naive. If both processes operate on the - link simultaneously, the link may end up in an inconsistent - state where one process thinks it is linked while the other - thinks it is not linked. -

-

- This protocol is deprecated and support for it will be removed - in OTP 26. Until then, it will be used as fallback when - communicating with old nodes that do not understand the - new link - protocol. -

-
+

+ When a process receives an exit signal due to a link, the + process will first react to the exit signal if the link + is active and then remove the process local information about + the link. +

+

+ In case the connection is lost between two nodes, exit signals + with exit reason noconnection are sent to all processes + with links over the connection. This will cause all process + local information about links over the connection to be + removed. +

+

+ Exactly the same link protocol is also used internally on an + Erlang node. The signals however have different formats since + they do not have to be sent over the wire. +

diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 2547b6e952cf..5e0e0349f362 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -4,7 +4,7 @@
- 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -2567,12 +2567,14 @@ ErlDrvTermData spec[] = { ERL_DRV_STRING_CONS, (ErlDrvTermData)"abc", 3, }; erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0])); ]]> -

The ERL_DRV_EXT2TERM term type is used for passing a +

+ + The ERL_DRV_EXT2TERM term type is used for passing a term encoded with the external format, that is, a term that has been encoded by - erlang:term_to_binary, + erlang:term_to_binary(), erl_interface:ei(3), and so on. For example, if binp is a pointer to an ErlDrvBinary diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml index 5e2dd99945d1..ef431723b49c 100644 --- a/erts/doc/src/erl_ext_dist.xml +++ b/erts/doc/src/erl_ext_dist.xml @@ -5,7 +5,7 @@

2007 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -655,6 +655,7 @@ encoded using NEW_PORT_EXT, even external ports received as PORT_EXT from older nodes.

+
@@ -683,8 +684,10 @@ works just like in NEW_PID_EXT. Port operations are not allowed across node boundaries.

-

V4_PORT_EXT was introduced in OTP 24, but only to be decoded - and echoed back. Not encoded for local ports. +

In OTP 26 distribution flag + DFLAG_V4_NC + as well as V4_PORT_EXT became mandatory accepting full + 64-bit ports to be decoded and echoed back.

@@ -742,23 +745,17 @@ encoded as an atom.

ID -

A 32-bit big endian unsigned integer. If distribution flag - DFLAG_V4_NC - is not set, only 15 bits may be used and the rest must be 0.

+

A 32-bit big endian unsigned integer.

Serial -

A 32-bit big endian unsigned integer. If distribution flag - DFLAG_V4_NC - is not set, only 13 bits may be used and the rest must be 0.

+

A 32-bit big endian unsigned integer.

Creation

A 32-bit big endian unsigned integer. All identifiers originating from the same node incarnation must have identical Creation values. This makes it possible to separate identifiers from old - (crashed) nodes from a new one. The value zero should be avoided for - normal operations as it is used as a wild card for debug purpose - (like a pid returned by - erlang:list_to_pid/1).

+ (crashed) nodes from a new one. The value zero is reserved and + must be avoided for normal operations.

NEW_PID_EXT was introduced in OTP 19, but only to be decoded @@ -770,9 +767,10 @@ even external pids received as PID_EXT from older nodes.

-

In OTP 24 distribution flag +

In OTP 26 distribution flag DFLAG_V4_NC - was introduced, accepting full 64-bit pids to be decoded and echoed back. + became mandatory accepting full 64-bit pids to be decoded + and echoed back.

@@ -1082,9 +1080,7 @@ encoded as an atom.

Len -

A 16-bit big endian unsigned integer not larger than 5 when the - DFLAG_V4_NC - has been set; otherwise not larger than 3.

+

A 16-bit big endian unsigned integer not larger than 5.

ID

A sequence of Len big-endian unsigned integers @@ -1106,11 +1102,14 @@ NEW_REFERENCE_EXT from older nodes.

+

In OTP 26 distribution flag + DFLAG_V4_NC + became mandatory. References now can contain up to 5 ID words.

- FUN_EXT + FUN_EXT (removed)
1 @@ -1131,46 +1130,7 @@ Free vars ... FUN_EXT
- - Pid - -

A process identifier as in - PID_EXT. - Represents the process in which the fun was created. -

-
- Module - -

- The module that the fun is implemented in, - encoded as an atom. -

-
- Index - -

An integer encoded using - - SMALL_INTEGER_EXT - or INTEGER_EXT. - It is typically a small index into the module's fun table. -

-
- Uniq - -

An integer encoded using - - SMALL_INTEGER_EXT or - INTEGER_EXT. - Uniq is the hash value of the parse for the fun. -

-
- Free vars - -

NumFree number of terms, each one encoded according - to its type. -

-
-
+

Not emitted since OTP R8, and not decoded since OTP 23.

@@ -1205,7 +1165,7 @@ NEW_FUN_EXT

- This is the new encoding of internal funs: fun F/A and + This is the encoding of internal funs: fun F/A and fun(Arg1,..) -> ... end.

@@ -1461,6 +1421,46 @@
+
+ + LOCAL_EXT + + + 1 + ... + + + 121 + ... + + LOCAL_EXT
+

+ Marks that this is encoded on an alternative local external term + format intended to only be decoded by a specific local decoder. + The bytes following from here on may contain any unspecified type + of encoding of terms. It is the responsibility of the user to only + attempt to decode terms on the local external term format which has + been produced by a matching encoder. +

+

+ This tag is used by the Erlang runtime system upon encoding the local + external term format when the + local + option is passed to + term_to_binary/2, + but can be used by other encoders as well providing similar + functionality. The Erlang runtime system adds a hash immediately + following the LOCAL_EXT tag which is verified on decoding in + order to verify that encoder and decoder match which might be a good + practice. This will very likely catch mistakes made by users, but + is not guaranteed to, and is not intended to, prevent decoding of an + intentionally forged encoding on the local external term format. +

+

+ LOCAL_EXT was introduced in OTP 26.0. +

+
+ diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 7a3b766f4ccd..4d31879c6a1f 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -4,7 +4,7 @@
- 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -100,6 +100,8 @@ ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL) -export([init/0, hello/0]). +-nifs([hello/0]). + -on_load(init/0). init() -> @@ -127,7 +129,13 @@ $> erl which loads the NIF library and replaces the hello function with its native implementation in C. Once loaded, a NIF library is persistent. It will not be unloaded until the module code version that it belongs to is - purged.

+ purged. +

+

+ The + -nifs() attribute specifies which functions in the + module that are to be replaced by NIFs. +

Each NIF must have an implementation in Erlang to be invoked if the function is called before the NIF library is successfully loaded. A @@ -140,21 +148,6 @@ $> erl However, unused local stub functions will be optimized away by the compiler, causing loading of the NIF library to fail.

- -

- There is a known limitation for Erlang fallback functions of NIFs. Avoid - functions involved in traversal of binaries by matching and - recursion. If a NIF is loaded over such function, binary arguments to - the NIF may get corrupted and cause VM crash or other misbehavior. -

-

Example of such bad fallback function:

- -skip_until(Byte, <<Byte, Rest/binary>>) -> - Rest; -skip_until(Byte, <<_, Rest/binary>>) -> - skip_until(Byte, Rest). - -
@@ -178,11 +171,37 @@ skip_until(Byte, <<_, Rest/binary>>) -> to query terms, like enif_is_atom, enif_is_identical, and enif_compare.

All terms of type ERL_NIF_TERM belong to an environment of - type ErlNifEnv. The - lifetime of a term is controlled by the lifetime of its environment - object. All API functions that read or write terms has the - environment that the term belongs to as the first function - argument.

+ type ErlNifEnv, + except atoms created during loading (by callbacks + load or + upgrade). The lifetime of + a term is controlled by the lifetime of its environment object. All + API functions that read or write terms have the environment that the + term belongs to as the first function argument. However, the atoms + created during loading can be referred as a term in any ErlNifEnv. + That is, the best practice it to create all your atoms during + loading and store them in static/global variables, for example:

+ + +ERL_NIF_TERM world_atom; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + world_atom = enif_make_atom(env, "world"); + return 0; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM hello_string = enif_make_string(env, "Hello", ERL_NIF_LATIN1); + return enif_make_tuple2(env, hello_string, world_atom); +} + +static ErlNifFunc nif_funcs[] = { { "hello", 0, hello } }; + +ERL_NIF_INIT(niftest, nif_funcs, load, NULL, NULL, NULL) +]]> Binaries @@ -599,9 +618,15 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail,

The fourth argument NULL is ignored. It was earlier used for the deprecated reload callback which is no longer supported since OTP 20.

-

If compiling a NIF for static inclusion through - --enable-static-nifs, you must define STATIC_ERLANG_NIF - before the ERL_NIF_INIT declaration.

+

If compiling a NIF lib for static inclusion through + --enable-static-nifs, then the macro + STATIC_ERLANG_NIF_LIBNAME must be defined as the name of the + archive file (excluding file extension .a) without string + quotations. It must only contain characters allowed in a C + indentifier. The macro must be defined before erl_nif.h is + included. If the older macro STATIC_ERLANG_NIF is instead + used, then the name of the archive file must match the name of the + module.

int (*load)(ErlNifEnv* caller_env, void** priv_data, ERL_NIF_TERM load_info) @@ -786,6 +811,41 @@ typedef struct { To compare two monitors, enif_compare_monitors must be used.

+ ErlNifOnHaltCallback + + +typedef void ErlNifOnHaltCallback(void *priv_data); +

+ The function prototype of an on halt callback function. +

+

+ An on halt callback can be installed using + enif_set_option(). Such + an installed callback will be called when the runtime system is + halting. +

+
+ ErlNifOption + +

+ An enumeration of the options that can be set using + enif_set_option(). +

+

Currently valid options:

+ + ERL_NIF_OPT_DELAY_HALT +

+ Enable delay of runtime system halt with flushing enabled until + all calls to NIFs in the NIF library have returned. +

+ ERL_NIF_OPT_ON_HALT +

+ Install a callback that will be called when the runtime system + halts with flushing enabled. +

+
+
+ ErlNifPid

A process identifier (pid). In contrast to pid terms (instances of @@ -870,11 +930,12 @@ typedef void ErlNifResourceDynCall(ErlNifEnv* caller_env, void* obj, void* call_ typedef enum { - ERL_NIF_LATIN1 + ERL_NIF_LATIN1, + ERL_NIF_UTF8, }ErlNifCharEncoding;

The character encoding used in strings and atoms. The only - supported encoding is ERL_NIF_LATIN1 for - ISO Latin-1 (8-bit ASCII).

+ supported encodings are ERL_NIF_LATIN1 for + ISO Latin-1 (8-bit ASCII) and ERL_NIF_UTF8 for UTF-8.

ErlNifSysInfo @@ -1297,7 +1358,7 @@ typedef struct { int enif_dynamic_resource_call(ErlNifEnv* caller_env, - ERL_NIF_MODULE rt_module, ERL_NIF_MODULE rt_name, ERL_NIF_TERM resource, + ERL_NIF_TERM rt_module, ERL_NIF_TERM rt_name, ERL_NIF_TERM resource, void* call_data) Call a resource in another module. @@ -1396,32 +1457,32 @@ enif_free_iovec(iovec);]]> - intenif_get_atom(ErlNifEnv* env, ERL_NIF_TERM - term, char* buf, unsigned size, ErlNifCharEncoding encode) + intenif_get_atom(ErlNifEnv *env, ERL_NIF_TERM + term, char *buf, unsigned size, ErlNifCharEncoding encoding) Get the text representation of an atom term.

Writes a NULL-terminated string in the buffer pointed to by - buf of size size, consisting of the string - representation of the atom term with encoding - encode.

+ buf of size size bytes, consisting of the string + representation of the atom term with + encoding.

Returns the number of bytes written (including terminating NULL character) or 0 if term is not an atom with - maximum length of size-1.

+ maximum length of size-1 bytes in encoding.

- intenif_get_atom_length(ErlNifEnv* env, - ERL_NIF_TERM term, unsigned* len, ErlNifCharEncoding encode) + intenif_get_atom_length(ErlNifEnv *env, + ERL_NIF_TERM term, unsigned *len, ErlNifCharEncoding encoding) Get the length of atom term.

Sets *len to the length (number of bytes excluding terminating NULL character) of the atom term with - encoding encode.

+ encoding.

Returns true on success, or false if term is not - an atom.

+ an atom or if the atom cannot be encoded using encoding.

@@ -1563,13 +1624,13 @@ enif_free_iovec(iovec);]]> intenif_get_string(ErlNifEnv* env, ERL_NIF_TERM list, char* buf, unsigned size, - ErlNifCharEncoding encode) + ErlNifCharEncoding encoding) Get a C-string from a list.

Writes a NULL-terminated string in the buffer pointed to by buf with size size, consisting of the characters - in the string list. The characters are written using encoding - encode.

+ in the string list. The characters are written using + encoding.

Returns one of the following:

The number of bytes written (including terminating NULL @@ -1577,13 +1638,28 @@ enif_free_iovec(iovec);]]> -size if the string was truncated because of buffer space 0 if list is not a string that can be encoded - with encode or if size was < 1. + with encoding or if size was < 1.

The written string is always NULL-terminated, unless buffer size is < 1.

+ + + intenif_get_string_length(ErlNifEnv *env, + ERL_NIF_TERM list, unsigned *len, ErlNifCharEncoding encoding) + + Get the length of a C-string list. + +

Sets *len to the length (number of bytes excluding + terminating NULL character) of the string list with + encoding.

+

Returns true on success, or false if list is not + a string that can be encoded with encoding.

+
+
+ intenif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM term, int* arity, const ERL_NIF_TERM** array) @@ -2030,7 +2106,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); ERL_NIF_TERM - enif_make_atom(ErlNifEnv* env, const char* name) + enif_make_atom(ErlNifEnv *env, const char *name) Create an atom term. @@ -2043,16 +2119,16 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); - ERL_NIF_TERMenif_make_atom_len(ErlNifEnv* env, - const char* name, size_t len) + ERL_NIF_TERMenif_make_atom_len(ErlNifEnv *env, + const char *name, size_t len) Create an atom term.

Create an atom term from the string name with length - len. NULL characters are treated as any other - characters. If len exceeds the maximum length - allowed for an atom (255 characters), enif_make_atom invokes - - enif_make_badarg.

+ len and ISO Latin-1 encoding. NULL characters are + treated as any other characters. If len exceeds the maximum + length allowed for an atom (255 characters), enif_make_atom + invokes enif_make_badarg + .

@@ -2121,35 +2197,37 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec);
- intenif_make_existing_atom(ErlNifEnv* env, - const char* name, ERL_NIF_TERM* atom, ErlNifCharEncoding - encode) + intenif_make_existing_atom(ErlNifEnv *env, + const char *name, ERL_NIF_TERM *atom, ErlNifCharEncoding + encoding) Create an existing atom term.

Tries to create the term of an already existing atom from - the NULL-terminated C-string name with encoding - encode.

+ the NULL-terminated C-string name with + encoding.

If the atom already exists, this function stores the term in - *atom and returns true, otherwise false. - Also returns false if the length of name exceeds the - maximum length allowed for an atom (255 characters).

+ *atom and returns true, otherwise returns false. + It also returns false if the string name exceeds the + maximum length allowed for an atom (255 characters) or if name + is not correctly encoded.

- intenif_make_existing_atom_len(ErlNifEnv* env, - const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding + intenif_make_existing_atom_len(ErlNifEnv *env, + const char *name, size_t len, ERL_NIF_TERM *atom, ErlNifCharEncoding encoding) Create an existing atom term.

Tries to create the term of an already existing atom from the - string name with length len and encoding - encode. NULL + string name with length len bytes and + encoding. NULL characters are treated as any other characters.

If the atom already exists, this function stores the term in - *atom and returns true, otherwise false. - Also returns false if len exceeds the maximum length - allowed for an atom (255 characters).

+ *atom and returns true, otherwise returns false. + It also returns false if the string name exceeds the + maximum length allowed for an atom (255 characters) or if name + is not correctly encoded.

@@ -2316,6 +2394,40 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); + + intenif_make_new_atom(ErlNifEnv *env, + const char *name, ERL_NIF_TERM *atom, ErlNifCharEncoding + encoding) + Create a new or existing atom term. + +

Creates an atom term from the NULL-terminated C-string + name with + encoding.

+

If successful, true is returned and the atom term is stored in + *atom.

+

Otherwise, false is returned if the length of name + exceeds the maximum length allowed for an atom (255 characters) + or if name is not correctly encoded.

+
+
+ + + intenif_make_new_atom_len(ErlNifEnv *env, + const char *name, size_t len, ERL_NIF_TERM *atom, ErlNifCharEncoding + encoding) + Create a new or existing atom term. + +

Create an atom term from string name with + length len bytes and + encoding.

+

If successful, true is returned and atom term is stored in + *atom.

+

Otherwise, false is returned if the string exceeds the maximum + length allowed for an atom (255 characters) or if the string is not + correctly encoded.

+
+
+ unsigned char *enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp) @@ -2453,24 +2565,24 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); - ERL_NIF_TERMenif_make_string(ErlNifEnv* env, - const char* string, ErlNifCharEncoding encoding) + ERL_NIF_TERMenif_make_string(ErlNifEnv *env, + const char *string, ErlNifCharEncoding encoding) Create a string.

Creates a list containing the characters of the - NULL-terminated string string with encoding + NULL-terminated string string with encoding.

- ERL_NIF_TERMenif_make_string_len(ErlNifEnv* - env, const char* string, size_t len, ErlNifCharEncoding + ERL_NIF_TERMenif_make_string_len(ErlNifEnv + *env, const char *string, size_t len, ErlNifCharEncoding encoding) Create a string.

Creates a list containing the characters of the string string - with length len and encoding + with length len and encoding. NULL characters are treated as any other characters.

@@ -2850,7 +2962,9 @@ enif_map_iterator_destroy(env, &iter);

Notice that enif_open_resource_type is only allowed to be called in the two callbacks load and - upgrade.

+ upgrade. The resource type + is only created or taken over if the calling load/upgrade + function returns successfully.

See also enif_open_resource_type_x.

@@ -3242,7 +3356,7 @@ enif_map_iterator_destroy(env, &iter); ERL_NIF_SELECT_READ and/or ERL_NIF_SELECT_WRITE to indicate which type of event to cancel. Arguments pid and ref are ignored when ERL_NIF_SELECT_CANCEL is specified. - The return value will tell if the event was actualy cancelled or if a + The return value will tell if the event was actually cancelled or if a notification may already have been sent.

Use ERL_NIF_SELECT_STOP as mode in order to safely close an event object that has been passed to enif_select. The @@ -3413,6 +3527,146 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { + + + intenif_set_option(ErlNifEnv *env, ErlNifOption opt, ...) + + + Set an option. + + + +

+ Set an option. On success, zero will be returned. On failure, a non + zero value will be returned. Currently the following options can be set: +

+ + + int enif_set_option(ErlNifEnv *env, + ERL_NIF_OPT_DELAY_HALT) + + +

+ Enable delay of runtime system halt with flushing enabled until + all calls to NIFs in the NIF library have returned. If the + delay halt feature has not been enabled, a halt with + flushing enabled may complete even though processes are still + executing inside NIFs in the NIF library. Note that by + returning we here mean the first point where the NIF + returns control back to the runtime system, and not the + point where a call to a NIF return a value back to the Erlang + code that called the NIF. That is, if you schedule execution of + a NIF, using + enif_schedule_nif(), from within a NIF while + the system is halting, the scheduled NIF call will not + be executed even though delay halt has been enabled for + the NIF library. +

+

+ The runtime system halts when one of the + erlang:halt() + BIFs are called. By default flushing is enabled, but can be + disabled using the + erlang:halt/2 BIF. + When flushing has been disabled, the delay halt setting + will have no effect. That is, the runtime system will halt without + waiting for NIFs to return even if the delay halt setting + has been enabled. See the + {flush, boolean()} + option of erlang:halt/2 for more information. +

+

+ The ERL_NIF_OPT_DELAY_HALT option can only be set during + loading of a NIF library in a call to enif_set_option() + inside a NIF library + load() or + upgrade() call, + and will fail if set somewhere else. The env + argument must be the callback environment passed to the + load() or the upgrade() call. This option can also + only be set once. That is, the delay halt setting cannot + be changed once it has been enabled. The delay halt + setting is tied to the module instance with which the NIF library + instance has been loaded. That is, in case both a new and old + version of a module using the NIF library are loaded, they can + have the same or different delay halt settings. +

+

+ The delay halt feature can be used in combination with an + on halt callback. + The on halt callback is in this case typically used to + notify processes blocked in NIFs in the library that it is time + to return in order to let the runtime system complete the + halting. Such NIFs should be dirty NIFs, since ordinary NIFs + should never block for a long time. +

+
+ + int enif_set_option(ErlNifEnv *env, + ERL_NIF_OPT_ON_HALT, + ErlNifOnHaltCallback + *on_halt) + + +

+ Install a callback that will be called when the runtime system + halts with flushing enabled. +

+

+ The runtime system halts when one of the + erlang:halt() BIFs + are called. By default flushing is enabled, but can be disabled + using the + erlang:halt/2 BIF. + When flushing has been disabled, the runtime system will halt + without calling any on halt callbacks even if such are + installed. See the + {flush, boolean()} + option of erlang:halt/2 for more information. +

+

+ The ERL_NIF_OPT_ON_HALT option can only be set during + loading of a NIF library in a call to enif_set_option() + inside a NIF library + load() or + upgrade() call, + and will fail if called somewhere else. The env + argument must be the callback environment passed to the + load() or the upgrade() call. The on_halt + argument should be a function pointer to the callback to install. + The on halt callback will be tied to the module instance + with which the NIF library instance has been loaded. That is, in + case both a new and old version of a module using the NIF library + are loaded, they can both have different, none, or the same + on halt callbacks installed. When unloading the NIF + library during a + code purge, an + installed on halt callback will be uninstalled. + The ERL_NIF_OPT_ON_HALT option can also only be set + once. That is, the on halt callback cannot be changed + or removed once it has been installed by any other means than + purging the module instance that loaded the NIF library. +

+

+ When the installed on halt callback is called, it will be + passed a pointer to priv_data as argument. The + priv_data pointer can be set when loading the NIF library. +

+

+ The on halt callback can be used in combination with + delay of halt until + all calls into the library have returned. The on halt + callback is in this case typically used to notify processes + blocked in NIFs in the library that it is time to return in order + to let the runtime system complete the halting. Such NIFs should + be dirty NIFs, since ordinary NIFs should never block for a long + time. +

+
+
+ +
+ void enif_set_pid_undefined(ErlNifPid* pid) @@ -3766,7 +4020,10 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) {
See Also -

- erlang:load_nif/2

+

+ erlang:load_nif/2
+ NIFs (tutorial)
+ Debugging NIFs and Port Drivers +

diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index a5e4a3b3311c..345e8f000a22 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4,7 +4,7 @@
- 19962022 + 19962023 Ericsson AB. All Rights Reserved. @@ -510,14 +510,14 @@ -

An opaque handle identifing a distribution channel.

+

An opaque handle identifying a distribution channel.

-

An opaque handle identifing a +

An opaque handle identifying a NIF resource object .

@@ -552,7 +552,6 @@ MQD)

- @@ -561,7 +560,15 @@ section in the Erlang Reference Manual.

- + + + +

The destination for a send operation, can be a remote or local process identifier, + a (local) port, a reference denoting a process alias, a locally registered name, or a tuple + {RegName, Node} + for a registered name at another node.

+
+
@@ -783,12 +790,12 @@ client(ServerPid, Request) -> utf8 or unicode, the characters are encoded using UTF-8 where characters may require multiple bytes.

- +

As from Erlang/OTP 20, atoms can contain any Unicode character and atom_to_binary(Atom, latin1) may fail if the text representation for Atom contains a Unicode character > 255.

-
+

Example:

 > atom_to_binary('Erlang', latin1).
@@ -867,11 +874,11 @@ client(ServerPid, Request) ->
           Binary. If Encoding
           is utf8 or unicode, the binary must contain
           valid UTF-8 sequences.

- +

As from Erlang/OTP 20, binary_to_atom(Binary, utf8) is capable of decoding any Unicode character. Earlier versions would fail if the binary contained Unicode characters > 255.

-
+

The number of characters that are permitted in an atom name is limited. The default limits can be found in the @@ -1385,7 +1392,7 @@ hello by passing option {allow_gc, false}.

- +

Up until ERTS version 8.*, the check process code operation checks for all types of references to the old code. That is, @@ -1407,7 +1414,7 @@ hello and will automatically be enabled if dirty scheduler support is enabled.

-
+

See also code(3).

Failures:

@@ -1582,6 +1589,10 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)). headers and the beginning of any following message body.

The variants http_bin and httph_bin return strings (HttpString) as binaries instead of lists.

+

Since OTP 26.0, Host may be an IPv6 + address enclosed in [], as defined in + RFC2732 + .

Options:

@@ -1670,7 +1681,13 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)). demonitor(MonitorRef, [flush]) can be used instead of demonitor(MonitorRef) if this cleanup is wanted.

- +

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

+

Before Erlang/OTP R11B (ERTS 5.5) demonitor/1 behaved completely asynchronously, that is, the monitor was active until the "demonitor signal" reached the monitored entity. This @@ -1680,7 +1697,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).

The current behavior can be viewed as two combined operations: asynchronously send a "demonitor signal" to the monitored entity and ignore any future results of the monitor.

-
+

Failure: It is an error if MonitorRef refers to a monitoring started by another process. Not all such cases are cheap to check. If checking is cheap, the call fails with @@ -1738,9 +1755,9 @@ end otherwise true.

- +

More options can be added in a future release.

-
+

Failures:

badarg @@ -1783,7 +1800,9 @@ end

Prints a text representation of Term on the standard output.

-

This BIF is intended for debugging only.

+

This BIF is intended for debugging only. The printed representation + may contain internal details that do not match the high-level + representation of the term in Erlang.

@@ -1818,7 +1837,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -1847,7 +1866,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -1883,7 +1902,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -1904,7 +1923,7 @@ end Once this function has been called, InputHandler is the only process allowed to call erlang:dist_ctrl_put_data(DHandle, Data) - with the DHandle identifing this distribution + with the DHandle identifying this distribution channel.

@@ -1916,7 +1935,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -1949,7 +1968,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -1998,7 +2017,7 @@ end

This function is used when implementing an alternative distribution carrier using processes as distribution - controllers. DHandle is retrived + controllers. DHandle is retrieved via the callback f_handshake_complete. More information can be found in the documentation of @@ -2275,6 +2294,12 @@ example_fun(A1, A2) -> reasons.

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

@@ -2364,7 +2389,14 @@ true
> float_to_binary(7.12, [{decimals, 4}, compact]). <<"7.12">> > float_to_binary(7.12, [{scientific, 3}]). -<<"7.120e+00">> +<<"7.120e+00">> +> float_to_binary(7.12, [short]). +<<"7.12">> +> float_to_binary(0.1+0.2, [short]). +<<"0.30000000000000004">> +> float_to_binary(0.1+0.2) +<<"3.00000000000000044409e-01">> + @@ -2399,6 +2431,16 @@ true formatted using scientific notation with Decimals digits of precision.

+

If option short is specified, the float is formatted + with the smallest number of digits that still guarantees that + F =:= list_to_float(float_to_list(F, [short])). When the float + is inside the range (-2⁵³, 2⁵³), the notation + that yields the smallest number of characters is used (scientific + notation or normal decimal notation). Floats outside the range + (-2⁵³, 2⁵³) are always formatted using + scientific notation to avoid confusing results when doing arithmetic + operations.

+

If Options is [], the function behaves as float_to_list/1.

@@ -2412,6 +2454,10 @@ true "7.12" > float_to_list(7.12, [{scientific, 3}]). "7.120e+00" +> float_to_list(7.12, [short]). +"7.12" +> float_to_list(0.1+0.2, [short]). +"0.30000000000000004" > float_to_list(0.1+0.2) "3.00000000000000044409e-01" @@ -2515,6 +2561,15 @@ of Floating Point Numbers.

Fun was statically allocated when module was loaded (this optimisation is performed for local functions that do not capture the environment).

+ +

In Erlang/OTP 27, we plan to change the return value so that + it always points to the local init process, regardless + of which process or node the fun was originally created on. See + + Upcoming Potential Incompatibilities + . +

+
{index, Index} @@ -2608,11 +2663,11 @@ of Floating Point Numbers.

marker="#fun_info/1">erlang:fun_info/1 for how to get the environment of a fun.

- +

The output of fun_to_list/1 can differ between Erlang implementations and may change in future versions.

-
+

Examples:

-module(test). @@ -2640,7 +2695,7 @@ account.

{#Fun<test.2.107738983>,#Fun<test.3.107738983>}

Explanation: The string representations differ because the funs -come from different fun experssions.

+come from different fun expressions.

 > {fun() -> 1 end, fun() -> 1 end}. > 
 {#Fun<erl_eval.45.97283095>,#Fun<erl_eval.45.97283095>}
@@ -2796,7 +2851,9 @@ uncompiled code with the same arity are mapped to the same list by
       Get the magic cookie of the local node.
       
         

Returns the magic cookie of the local node if the node is - alive, otherwise the atom nocookie.

+ alive, otherwise the atom nocookie. This value is set by + set_cookie/1. +

@@ -2806,7 +2863,8 @@ uncompiled code with the same arity are mapped to the same list by

Returns the magic cookie for node Node if the local node is alive, - otherwise the atom nocookie.

+ otherwise the atom nocookie. This value is set by + set_cookie/2.

@@ -2857,8 +2915,23 @@ uncompiled code with the same arity are mapped to the same list by groups have a group leader. All I/O from the group is channeled to the group leader. When a new process is spawned, it gets the same group leader as the spawning - process. Initially, at system startup, init is both - its own group leader and the group leader of all processes.

+ process.

+

Initially, at system startup, init is both + its own group leader and the group leader of all processes. + During the boot of a system the group leader for processes + will be changed depending on the need of the system. Some examples + where this is done are:

+ + When an application is started, the top supervisor of that + application will have its group leader set to the application + master. See + application:start/2 for more details. + When running tests, both common_test and + eunit set the + group leader in order to capture any I/O from the testcase. + The interactive shell + sets the group leader to intercept I/O. + @@ -2875,7 +2948,7 @@ uncompiled code with the same arity are mapped to the same list by applications with a supervision tree, because OTP assumes the group leader of their processes is their application master.

-

Setting the group leader follows the signal ordering guarentees +

Setting the group leader follows the signal ordering guarantees described in the Processes Chapter in the Erlang Reference Manual.

@@ -2884,6 +2957,12 @@ uncompiled code with the same arity are mapped to the same list by and OTP design principles related to starting and stopping applications.

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

@@ -2892,7 +2971,7 @@ uncompiled code with the same arity are mapped to the same list by Halt the Erlang runtime system and indicate normal exit to the calling environment. -

The same as +

The same as calling halt(0, []). Example:

 > halt().
@@ -2901,10 +2980,11 @@ os_prompt%
- + Halt the Erlang runtime system. -

The same as +

The same as calling halt(Status, []). Example:

 > halt(17).
@@ -2915,44 +2995,156 @@ os_prompt%
- + + Halt the Erlang runtime system by aborting. + +

+ The same as calling + halt(abort, []). +

+
+
+ + + + + Halt the Erlang runtime system and create an Erlang crash dump. + + +

+ The same as calling + halt(CrashDumpSlogan, []). +

+
+
+ + + Halt the Erlang runtime system. + -

Status must be a non-negative integer, a string, - or the atom abort. - Halts the Erlang runtime system. Has no return value. - Depending on Status, the following occurs:

+

+ Halt the runtime system with status code + Status. +

+ +

+ On many platforms, the OS supports only status codes 0-255. A too + large status code is truncated by clearing the high bits. +

+
+

+ Currently the following options are valid: +

- integer() - The runtime system exits with integer value - Status - as status code to the calling environment (OS). - -

On many platforms, the OS supports only status - codes 0-255. A too large status code is truncated by clearing - the high bits.

-
-
- string() - An Erlang crash dump is produced with Status - as slogan. Then the runtime system exits with status code 1. - The string will be truncated if longer than 200 characters. - -

Before ERTS 9.1 (OTP-20.1) only code points in the range 0-255 - was accepted in the string. Now any unicode string is valid.

-
-
- abort - The runtime system aborts producing a core dump, if that is - enabled in the OS. + {flush, EnableFlushing} + +

+ If EnableFlushing equals true, which also is the + default behavior, the runtime system will perform the following + operations before terminating: +

+ +

+ Flush all outstanding output. +

+

+ Send all Erlang ports exit signals and wait for them + to exit. +

+

+ Wait for all async threads to complete all outstanding + async jobs. +

+

+ Call all installed NIF + on halt callbacks. +

+

+ Wait for all ongoing NIF + calls with the delay halt setting enabled to + return. +

+

+ Call all installed atexit/on_exit callbacks. +

+
+

+ If EnableFlushing equals false, the runtime system + will terminate immediately without performing any of the above + listed operations. +

+ +

+ Runtime systems prior to OTP 26.0 called all installed + atexit/on_exit callbacks also when flush + was disabled, but as of OTP 26.0 this is no longer the case. +

+
-

For integer Status, the Erlang runtime system - closes all ports and allows async threads to finish their - operations before exiting. To exit without such flushing, use - Option as {flush,false}.

-

For statuses string() and abort, option - flush is ignored and flushing is not done.

+
+
+ + + + Halt the Erlang runtime system by aborting. + + +

+ Halt the Erlang runtime system by aborting and produce a core dump + if core dumping has been enabled in the environment that the + runtime system is executing in. +

+

+ The {flush, boolean()} + option will be ignored, and flushing will be disabled. +

+
+
+ + + + + Halt the Erlang runtime system and create an Erlang crash dump. + + + +

+ Halt the Erlang runtime system and generate an + Erlang crash dump. The + string CrashDumpSlogan will be used as slogan + in the Erlang crash dump created. The slogan will be trunkated if + CrashDumpSlogan is longer than 1023 characters. +

+

+ The {flush, boolean()} + option will be ignored, and flushing will be disabled. +

+

+ Behavior changes compared to earlier versions: +

+ + +

+ Before OTP 24.2, the slogan was truncated if + CrashDumpSlogan was longer than 200 + characters. Now it will be truncated if longer than 1023 + characters. +

+
+ +

+ Before OTP 20.1, only code points in the range 0-255 were + accepted in the slogan. Now any Unicode string is valid. +

+
+
@@ -2961,12 +3153,17 @@ os_prompt%
Head of a list.

Returns the head of List, that is, - the first element, for example:

+ the first element.

+

It works with improper lists.

+

Examples:

 > hd([1,2,3,4,5]).
 1
+
+> hd([first, second, third, so_on | improper_end]).
+first

Allowed in guard tests.

-

Failure: badarg if List is the empty +

Failure: badarg if List is an empty list [].

@@ -3164,7 +3361,7 @@ os_prompt%

A node can also be alive if it has got a name from a call to net_kernel:start/1 + marker="kernel:net_kernel#start/2">net_kernel:start/2 and has not been stopped by a call to net_kernel:stop/0.

@@ -3364,7 +3561,7 @@ is_process_alive(P2Pid),

See the documentation about signals and erlang:exit/2 for more - information about signals and exit singnals.

+ information about signals and exit signals.

@@ -3514,6 +3711,12 @@ is_process_alive(P2Pid), chapter of the ERTS User's Guide.

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

Failure:

badarg if PidOrPort does not identify @@ -3790,6 +3993,11 @@ is_process_alive(P2Pid), previous current code for Module will remain until the on_load call has finished. + not_allowed + The code in Binary has been + compiled with features that are currently not enabled in the + runtime system. +

This BIF is intended for the code server (see @@ -3845,6 +4053,16 @@ is_process_alive(P2Pid), allowed. +

+ If the + -nifs() attribute is used (which is recommended), + all NIFs in the dynamic library much be declared as such for + load_nif/2 to succeed. On the other hand, all functions declared + with the -nifs() attribute do not have to be implemented by the + dynamic library. This allows a target independent Erlang file to + contain fallback implementations for functions that may lack NIF + support depending on target OS/hardware platform. +

@@ -3950,7 +4168,7 @@ is_process_alive(P2Pid), - Create a new tuple with specifed arity and contents. + Create a new tuple with specified arity and contents.

Creates a tuple of size Arity, where each element has value DefaultValue, and then fills in @@ -4063,6 +4281,8 @@ is_process_alive(P2Pid),

 > max("abc", "b").
 "b"
+

Allowed in guard tests.

+

Allowed in guards tests from Erlang/OTP 26.

@@ -4148,7 +4368,7 @@ is_process_alive(P2Pid),

The total amount of memory currently allocated for the emulator that is not directly related to any Erlang process. Memory presented as processes is not - included in this memory. + included in this memory. instrument(3) can be used to get a more detailed breakdown of what memory is part of this type.

@@ -4190,7 +4410,7 @@ is_process_alive(P2Pid), when the emulator is run with instrumentation.

For information on how to run the emulator with instrumentation, see - + instrument(3) and/or erl(1).

@@ -4238,11 +4458,11 @@ RealSystem = system + MissedSystem larger than the total size of the dynamically allocated memory blocks.

- +

As from ERTS 5.6.4, erlang:memory/0 requires that all erts_alloc(3) allocators are enabled (default behavior).

-
+

Failure: notsup if an erts_alloc(3) allocator has been disabled.

@@ -4259,12 +4479,12 @@ RealSystem = system + MissedSystem Type. The argument can also be specified as a list of memory_type() atoms, in which case a corresponding list of {memory_type(), Size :: integer >= 0} tuples is returned.

- +

As from ERTS 5.6.4, erlang:memory/1 requires that all erts_alloc(3) allocators are enabled (default behavior).

-
+

Failures:

badarg @@ -4315,6 +4535,8 @@ RealSystem = system + MissedSystem
 > min("abc", "b").
 "abc"
+

Allowed in guard tests.

+

Allowed in guards tests from Erlang/OTP 26.

@@ -4322,14 +4544,13 @@ RealSystem = system + MissedSystem Check if a module is loaded. -

Returns true if the module Module - is loaded, otherwise false. It does not attempt to load - the module.

- -

This BIF is intended for the code server (see - code(3)) - and is not to be used elsewhere.

-
+

+ Returns true if the module Module is + loaded as + + current code; otherwise, false. It does + not attempt to load the module. +

@@ -4409,7 +4630,7 @@ RealSystem = system + MissedSystem a tuple {RegisteredName, Node} for a registered process, located elsewhere.

-

Before ERTS 10.0 (OTP 21.0), monitoring a process could fail with +

Before ERTS 10.0 (OTP 21.0), monitoring a process could fail with badarg if the monitored process resided on a primitive node (such as erl_interface or jinterface), where remote process monitoring is not implemented.

@@ -4418,7 +4639,7 @@ RealSystem = system + MissedSystem connection. That is, a {'DOWN', _, process, _, noconnection} is the only message that may be received, as the primitive node have no way of reporting the status of the monitored process.

-
+ @@ -4506,6 +4727,12 @@ RealSystem = system + MissedSystem possible values for Tag, Object, and Info in the monitor message will be introduced.

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

@@ -4887,6 +5114,91 @@ receive_replies(ReqId, N, Acc) -> + + + All nodes of a certain type in the system. + +

+ Returns a list of NodeInfo tuples. The first + element is the node name. Nodes to be included in the list are + determined by the first argument Arg in the same + way as for + nodes(Arg). + The second element of NodeInfo tuples is a map + containing further information about the node identified by the + first element. The information present in this map is determined by + the InfoOpts map passed as the second argument. + Currently the following associations are allowed in the + InfoOpts map:

+ + connection_id => boolean() +

+ If the value of the association equals true, the Info + map in the returned result will contain the key connection_id + associated with the value ConnectionId. If + ConnectionId equals undefined, the node + is not connected to the node which the caller is executing on, or + is the node which the caller is executing on. If + ConnectionId is an integer, the node is + currently connected to the node which the caller is executing on. +

+

+ + The integer connection identifier value together with a node name + identifies a specific connection instance to the node with that + node name. The connection identifier value is node local. That is, + on the other node the connection identifier will not be the + same value. If a connection is taken down and then taken up again, + the connection identifier value will change for the connection to + that node. The amount of values for connection identifiers are + limited, so it is possible to see the same value for different + instances, but quite unlikely. It is undefined how the value + change between two consecutive connection instances. +

+ node_type => boolean() +

+ If the value of the association equals true, the Info + map in the returned result will contain the key node_type + associated with the value NodeTypeInfo. + Currently the following node types exist:

+ + visible +

+ The node is connected to the node of the calling process + through an ordinary visible connection. That is, the node + name would appear in the result returned by + nodes/0. +

+ hidden +

+ The node is connected to the node of the calling process + through a hidden connection. That is, the node + name would not appear in the result returned by + nodes/0. +

+ this +

+ This is the node of the calling process. +

+ known +

+ The node is not connected but known to the node of the + calling process. +

+
+
+
+

Example:

+ +(a@localhost)1> nodes([this, connected], #{connection_id=>true, node_type=>true}). +[{c@localhost,#{connection_id => 13892108,node_type => hidden}}, + {b@localhost,#{connection_id => 3067553,node_type => visible}}, + {a@localhost,#{connection_id => undefined,node_type => this}}] +(a@localhost)2> + +
+
+ Elapsed time since 00:00 GMT. @@ -4924,7 +5236,7 @@ receive_replies(ReqId, N, Acc) -> new Erlang port. A port can be seen as an external Erlang process.

The name of the executable as well as the arguments - specifed in cd, env, args, and arg0 are + specified in cd, env, args, and arg0 are subject to Unicode filename translation if the system is running in Unicode filename mode. To avoid translation or to force, for example UTF-8, supply the executable @@ -5071,7 +5383,7 @@ receive_replies(ReqId, N, Acc) -> Val must be strings. The one exception is Val being the atom false (in analogy with - os:getenv/1, + os:getenv/1), which removes the environment variable.

@@ -5559,9 +5871,9 @@ receive_replies(ReqId, N, Acc) -> false is returned. - +

More options can be added in a future release.

- +

Failures:

badarg @@ -6022,6 +6334,68 @@ receive_replies(ReqId, N, Acc) -> + + Enable or disable fully asynchronous distributed signaling + for the calling process. + + +

+ Enable or disable fully asynchronous distributed signaling + for the calling process. When disabled, which is the default, the + process sending a distributed signal will block in the send + operation if the buffer for the distribution channel reach the + distribution buffer busy + limit. The process will remain blocked until the buffer + shrinks enough. This might in some cases take a substantial amount + of time. When async_dist is enabled, send operations of + distributed signals will always buffer the signal on the outgoing + distribution channel and then immediately return. That is, these + send operations will never block the sending process. +

+

+ Since no flow control is enforced by the runtime system when + async_dist process flag is enabled, you need to make sure + that flow control for such data is implemented, or that the amount + of such data is known to always be limited. Unlimited signaling with + async_dist enabled in the absence of flow control will + typically cause the sending runtime system to crash on an out of + memory condition. +

+

+ Blocking due to disabled async_dist can be monitored by + erlang:system_monitor() + using the + busy_dist_port + option. Only data buffered by processes which (at the time of sending + a signal) have disabled async_dist will be counted when + determining whether or not an operation should block the caller. +

+

+ The async_dist flag can also be set on a new process when + spawning it using the + spawn_opt() BIF with the + option {async_dist, + Enable}. The default async_dist flag to use on + newly spawned processes can be set by passing the command line + argument +pad + <boolean> when starting the runtime system. If the + +pad <boolean> command line argument is not passed, the + default value of the async_dist flag will be false. +

+

+ You can inspect the state of the async_dist process flag of a + process by calling + process_info(Pid, async_dist). +

+

+ Returns the old value of the async_dist flag. +

+
+
+ + + Set process flag trap_exit for the calling process. @@ -6039,13 +6413,13 @@ receive_replies(ReqId, N, Acc) -> - + Set process flag error_handler for the calling process.

Used by a process to redefine the error handler for undefined function calls and undefined registered - processes. Inexperienced users are not to use this flag, + processes. Use this flag with substantial caution, as code auto-loading depends on the correct operation of the error handling module.

Returns the old value of the flag.

@@ -6053,7 +6427,7 @@ receive_replies(ReqId, N, Acc) ->
- + Set process flag fullsweep_after for the calling process. @@ -6064,7 +6438,7 @@ receive_replies(ReqId, N, Acc) -> - Set process flag min_heap_size for the calling process. @@ -6075,7 +6449,7 @@ receive_replies(ReqId, N, Acc) -> - + Set process flag min_bin_vheap_size for the calling process. @@ -6086,7 +6460,7 @@ receive_replies(ReqId, N, Acc) -> - Set process flag max_heap_size for the calling process. @@ -6096,6 +6470,11 @@ receive_replies(ReqId, N, Acc) -> If MaxHeapSize is an integer, the system default values for kill and error_logger are used.

+

+ For details on how the heap grows, see + Sizing + the heap in the ERTS internal documentation. +

size @@ -6147,6 +6526,26 @@ receive_replies(ReqId, N, Acc) -> or erlang:system_flag(max_heap_size, MaxHeapSize).

+ include_shared_binaries + +

+ When set to true, off-heap binaries are included in the + total sum compared against the size limit. Off-heap binaries + are typically larger binaries that may be shared between + processes. The size of a shared binary is included by all + processes that are referring it. Also, the entire size of a large + binary may be included even if only a smaller part of it is + referred by the process. +

+

+ If include_shared_binaries is not defined in the map, the + system default is used. The default system default is false. + It can be changed by either the option + +hmaxib in erl(1), + or + erlang:system_flag(max_heap_size, MaxHeapSize). +

+

The heap size of a process is quite hard to predict, especially the amount of memory that is used during the garbage collection. When @@ -6160,7 +6559,7 @@ receive_replies(ReqId, N, Acc) -> - Set process flag message_queue_data for the calling process. @@ -6202,7 +6601,7 @@ receive_replies(ReqId, N, Acc) -> - Set process flag priority for the calling process. @@ -6275,7 +6674,7 @@ receive_replies(ReqId, N, Acc) -> - + Set process flag save_calls for the calling process.

N must be an integer in the interval 0..10000. @@ -6306,7 +6705,7 @@ receive_replies(ReqId, N, Acc) -> - + Set process flag sensitive for the calling process.

Sets or clears flag sensitive for the current process. @@ -6434,7 +6833,7 @@ receive_replies(ReqId, N, Acc) -> Items were included in ItemList. Valid Items can be included multiple times in ItemList.

-

Getting process informations follows the signal ordering guarantees +

Getting process information follows the signal ordering guarantees described in the Processes Chapter in the Erlang Reference Manual.

@@ -6451,6 +6850,18 @@ receive_replies(ReqId, N, Acc) ->

Valid InfoTuples with corresponding Items:

+ + + {async_dist, Enabled} + + +

Since: OTP 25.3

+

+ Current value of the + + async_dist process flag. +

+
{backtrace, Bin}

Binary Bin contains the same information @@ -6632,6 +7043,14 @@ receive_replies(ReqId, N, Acc) -> process_flag(message_queue_data, MQD).

+ {parent, Pid} + +

Pid is the identifier + of the parent process, the one that spawned current + process. When the process does not have a parent + undefined is returned. Only the initial process + (init) on a node lacks a parent, though.

+
{priority, Level}

Level is the current priority level for @@ -6779,12 +7198,12 @@ receive_replies(ReqId, N, Acc) -> code(3)) and is not to be used elsewhere.

- +

As from ERTS 8.0 (Erlang/OTP 19), any lingering processes that still execute the old code is killed by this function. In earlier versions, such incorrect use could cause much more fatal failures, like emulator crash.

-
+

Failure: badarg if there is no old code for Module.

@@ -7082,7 +7501,6 @@ true Send a message. -

Sends a message and returns Msg. This is the same as using the @@ -7090,19 +7508,23 @@ true Dest ! Msg.

Dest can be a remote or local process identifier, an alias, a (local) port, a locally registered name, or a tuple - {RegName, Node} - for a registered name at another node.

+ {RegName, Node} for a registered name at another node.

The function fails with a badarg run-time error if Dest is an atom name, but this name is not registered. This is the only case when send fails for an unreachable destination Dest (of correct type).

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

Send a message conditionally. -

Either sends a message and returns ok, or does not send the message but returns something else (see below). @@ -7124,6 +7546,12 @@ true instead. +

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

As with erlang:send_nosuspend/2,3: use with extreme care.

@@ -7158,7 +7586,6 @@ true Try to send a message without ever blocking. -

The same as erlang:send(Dest, @@ -7208,7 +7635,6 @@ true Try to send a message without ever blocking. -

The same as erlang:send(Dest, @@ -7250,6 +7676,8 @@ true Distributed Erlang in the Erlang Reference Manual in System Documentation).

+

You can get this value using + get_cookie/0.

Failure: function_clause if the local node is not alive.

@@ -7267,6 +7695,8 @@ true Distributed Erlang in the Erlang Reference Manual in System Documentation).

+

You can get this value using + get_cookie/1.

Failure: function_clause if the local node is not alive.

@@ -7687,6 +8117,21 @@ true process_flag(message_queue_data, MQD).

+ + + {async_dist, Enabled} + + +

Since: OTP 25.3

+

+ Set the + + async_dist process flag of the spawned process. + This option will override the default value set by the command + line argument + +pad <boolean>. +

+
@@ -8037,6 +8482,11 @@ true

+

+ If a spawn reply message is delivered, it is guaranteed to be + delivered before any other signals from the newly spawned + process are delivered to the process issuing the spawn request. +

This function will fail with a badarg exception if:

@@ -8061,6 +8511,12 @@ true A spawn request can be abandoned by calling spawn_request_abandon/1.

+

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

@@ -8481,13 +8937,13 @@ lists:map(
 > statistics(reductions).
 {2046,11}
-

As from ERTS 5.5 (Erlang/OTP R11B), +

As from ERTS 5.5 (Erlang/OTP R11B), this value does not include reductions performed in current time slices of currently scheduled processes. If an exact value is wanted, use statistics(exact_reductions).

-
+ @@ -8593,7 +9049,7 @@ lists:map( and dirty CPU schedulers in the system have been busy. This value is normally a better indicator of how much load an Erlang node is under instead of - looking at the CPU utilization privided by tools such as top or + looking at the CPU utilization provided by tools such as top or sysstat. This is because scheduler_wall_time also includes time where the scheduler is waiting for some other reasource (such as an internal mutex) to be available but does not use the CPU. In order to better @@ -8898,7 +9354,7 @@ ok

- Appart from the reply message, the {asynchronous, + Apart from the reply message, the {asynchronous, ReplyTag} option behaves exactly the same as the asynchronous option without reply tag.

@@ -9152,12 +9608,17 @@ ok

Sets the default maximum heap size settings for processes. The size is specified in words. The new max_heap_size - effects only processes spawned efter the change has been made. + effects only processes spawned after the change has been made. max_heap_size can be set for individual processes using spawn_opt/2,3,4 or process_flag/2.

Returns the old value of the flag.

+

+ For details on how the heap grows, see + Sizing + the heap in the ERTS internal documentation. +

@@ -9533,7 +9994,7 @@ Metadata = #{ pid => pid(), - + System info overview.

Returns information about the current system. @@ -9556,6 +10017,7 @@ Metadata = #{ pid => pid(),

cpu_topology, logical_processors, + cpu_quota, update_cpu_info

@@ -9625,6 +10087,7 @@ Metadata = #{ pid => pid(), Distribution Information

+ async_dist, creation, delayed_node_table_gc, dist, @@ -9819,8 +10282,9 @@ Metadata = #{ pid => pid(), - - + + + Information about the CPU topology of the system. @@ -9981,16 +10445,16 @@ Metadata = #{ pid => pid(), - - - - - - - - - + + + + + + + + Information about the default process heap settings. @@ -10050,8 +10514,10 @@ Metadata = #{ pid => pid(), system-wide maximum heap size settings for spawned processes. This setting can be set using the command-line flags +hmax, - +hmaxk and - +hmaxel in + +hmaxk, + +hmaxel and + +hmaxibl in + erl(1). It can also be changed at runtime using erlang:system_flag(max_heap_size, MaxHeapSize). @@ -10101,12 +10567,12 @@ Metadata = #{ pid => pid(), - - - - - - + + + + + + Information about various system limits. @@ -10179,15 +10645,15 @@ Metadata = #{ pid => pid(), - - - - - - - - + + + + + + + Information about system time. @@ -10282,7 +10748,7 @@ Metadata = #{ pid => pid(), introduced in the future:

{function, Function} -

Function is the name of the funcion used.

+

Function is the name of the function used.

{clock_id, ClockId}

Exists only if Function @@ -10407,20 +10873,20 @@ Metadata = #{ pid => pid(), - - - - - - - - - - - - - + + + + + + + + + + + + Information about system schedulers. @@ -10707,29 +11173,41 @@ Metadata = #{ pid => pid(), - + - - - - + + + + Information about erlang distribution.

Returns information about Erlang Distribution in the current system as specified by Item:

+ async_dist + +

Since: OTP 25.3

+

+ Returns the value of the command line argument + +pad <boolean> + which the runtime system use. This value determines the default + + async_dist value for newly spawned processes. +

+
creation -

Returns the creation of the local node as an integer. +

Returns the "creation" value of the local node as an integer. The creation is changed when a node is restarted. The creation of a node is stored in process identifiers, port - identifiers, and references. This makes it (to some - extent) possible to distinguish between identifiers from - different incarnations of a node. The valid - creations are integers in the range 1..3, but this will - probably change in a future release. If the node is not + identifiers, and references. This makes it possible to distinguish + between identifiers from different incarnations of a node. + Creation values are currently 32-bit positive integers, but this + may change in future releases. If the node is not alive, 0 is returned.

@@ -10792,72 +11270,74 @@ Metadata = #{ pid => pid(), - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Information about the system. @@ -11225,7 +11705,7 @@ Metadata = #{ pid => pid(), MonitorPid. SusPid is the pid that got suspended when sending to Port.

- busy_dist_port + busy_dist_port

If a process in the system gets suspended because it sends to a process on a remote node whose inter-node @@ -11437,71 +11917,192 @@ hello

Returns a binary data object that is the result of encoding Term according to the Erlang external - term format.

-

If option compressed is provided, the external term - format is compressed. The compressed format is automatically - recognized by binary_to_term/1 as from Erlang/OTP R7B.

-

A compression level can be specified by giving option - {compressed, Level}. - Level is an integer - with range 0..9, where:

- -

0 - No compression is done (it is the same as - giving no compressed option).

-

1 - Takes least time but may not compress - as well as the higher levels.

-

6 - Default level when option compressed - is provided.

-

9 - Takes most time and tries to produce a smaller - result. Notice "tries" in the preceding sentence; depending - on the input term, level 9 compression either does or does - not produce a smaller result than level 1 compression.

-
-

Option {minor_version, Version} - can be used to control some - encoding details. This option was introduced in Erlang/OTP R11B-4. - The valid values for Version are:

- - 0 - -

Floats are encoded using a textual representation. - This option is useful to ensure that releases before Erlang/OTP - R11B-4 can decode resulting binary.

-

This version encode atoms that can be represented by a - latin1 string using latin1 encoding while only atoms that - cannot be represented by latin1 are encoded using utf8.

-
- 1 - -

This is as of Erlang/OTP 17.0 the default. It forces any floats - in the term to be encoded in a more space-efficient and exact way - (namely in the 64-bit IEEE format, rather than converted to a - textual representation). As from Erlang/OTP R11B-4, - binary_to_term/1 can decode this representation.

-

This version encode atoms that can be represented by a - latin1 string using latin1 encoding while only atoms that - cannot be represented by latin1 are encoded using utf8.

-
- 2 - -

Drops usage of the latin1 atom encoding and unconditionally - use utf8 encoding for all atoms. Erlang/OTP - systems as of R16B can decode this representation.

- -

In Erlang/OTP 26, the default minor_version is planned - to change from 1 to 2. See - - Upcoming Potential Incompatibilities - . -

-
-
-
-

Option deterministic (introduced in OTP 24.1) can - be used to ensure that within the same major release of Erlang/OTP, - the same encoded representation is returned for the same - term. There is still no guarantee that the encoded representation - remains the same between major releases of Erlang/OTP.

+ term format.

+

Currently supported options:

+ + compressed + +

+ Compress the external term format. The compressed + format is automatically recognized by binary_to_term/1 + as from Erlang/OTP R7B. +

+
+ {compressed, Level} + +

+ Compress the external term format to a given level. + The compression level is specified by Level + which is an integer in the range 0..9, where: +

+ + 0 +

+ No compression is done (it is the same as giving no + compressed option). +

+ 1 +

+ Takes least time but may not compress as well as the higher + levels. +

+ 6 +

+ Default level when option compressed is provided. +

+ 9 +

+ Takes most time and tries to produce a smaller result. + Notice "tries" in the preceding sentence; depending + on the input term, level 9 compression either does or does + not produce a smaller result than level 1 compression. +

+
+
+ {minor_version, Version} + +

+ The option can be used to control some encoding details. Valid + values for Version are: +

+ + 0 + +

Floats are encoded using a textual representation.

+

Atoms that can be represented by a latin1 string are encoded + using latin1 while only atoms that cannot be represented by latin1 + are encoded using utf8.

+
+ 1 + +

Floats are encoded in a more space-efficient and exact way + (namely in the 64-bit IEEE format, rather than converted to a + textual representation). As from Erlang/OTP R11B-4, + binary_to_term/1 can decode this representation.

+

Atoms that can be represented by a latin1 string are encoded + using latin1 while only atoms that cannot be represented by latin1 + are encoded using utf8.

+
+ 2 + +

This is as of Erlang/OTP 26.0 the default. Atoms are + unconditionally encoded using utf8. Erlang/OTP systems as of R16B + can decode this representation.

+
+
+
+ deterministic + +

+ This option can be used to ensure that, within the same major + release of Erlang/OTP, the same encoded representation is returned + for the same term. There is still no guarantee that the encoded + representation remains the same between major releases of + Erlang/OTP. +

+

+ This option cannot be combined with the local option. +

+
+ local + + +

+ This option will cause encoding of Term + to an alternative local version of the external term format which + when decoded by the same runtime system instance will produce a + term identical to the encoded term even when the node name and/or + creation of the + current runtime system instance have changed between encoding + and decoding. When encoding without the local option, + local identifiers such as pids, + ports and + references will not + be the same if node name and/or creation of the current runtime + system instance changed between encoding and decoding. This since + such identifiers refer to a specific node by node name and + creation. +

+

+ Node name and creation of a runtime system instance change + when the distribution is started or stopped. The distribution is + started when the runtime system is started using the + -name or + -sname command line + arguments. Note that the actual start of the distribution happens + after other code in the startup phase has begun executing. The + distribution can also be started by calling + net_kernel:start/2 + and stopped by calling + net_kernel:stop/1 + if it has not been started via the command line. +

+

+ The decoding of a term encoded with the local option, + using for example + binary_to_term(), + will try to verify that the term actually was encoded by the same + runtime system instance, and will in the vast majority of cases + fail if the encoding was performed by another runtime system + instance. You should however not trust that this + verification will work in all cases. You should make + sure to only decode terms encoded with the local + option on the same Erlang runtime system instance as the one that + encoded the terms. +

+

+ Since it is only the runtime system that encoded a term using + the local option that can decode it, the local encoding + is typically pieced together with something else to produce a + reply to where the local encoding originates from. + If a term encoded using the local option is stripped of + its leading version number, it can be added as part + of a larger term (for example as an element in a tuple) when + encoding on the external term format using, for example, + ei. In the ei + case, you would strip it of the version number using + ei_decode_version() + and then add the remaining local encoding to what you are encoding + using for example + ei_x_append_buf(). +

+

+ A good example of when you want to use the local option, is + when you want to make a request from a process to a port + driver and utilize the + selective + receive optimization when receiving the reply. In + this scenario you want to create a reference, serialize the + reference on the external term format using the local + option, pass this to the driver in the request, and then wait + for the reply message in a selective receive matching on the + reference. The driver should send the reply using either + erl_drv_output_term() + or + erl_drv_send_term() + using the term type + ERL_DRV_EXT2TERM + for the, in the request, previously received reference on the + external term format. Note that you should not strip the + leading version number from the local encoding when using the + term type ERL_DRV_EXT2TERM of this functionality. If you + in this example do not encode the reference using the local + option, and the distribution is started or stopped while the + request is ongoing, the process that made the request will hang + indefinitely since the reference in the reply message will never + match. +

+

+ This option cannot be combined with the deterministic + option. +

+

+ For more information see the + LOCAL_EXT + tag in the documentation of the external term format. +

+
+

See also binary_to_term/1.

@@ -11698,7 +12299,9 @@ timestamp() -> Tail of a list.

Returns the tail of List, that is, - the list minus the first element, for example:

+ the list minus the first element

+

It works with improper lists.

+

Examples:

 > tl([geesties, guilies, beasties]).
 [guilies, beasties]
@@ -11713,7 +12316,7 @@ timestamp() -> improper_end

Allowed in guard tests.

Failure: badarg if List - is the empty list [].

+ is an empty list [].

@@ -12460,7 +13063,7 @@ improper_end

Returns a list of atoms indicating what kind of traces is enabled for the process. The list is empty if no - traces are enabled, and one or more of the followings + traces are enabled, and one or more of the following atoms if traces are enabled: send, 'receive', set_on_spawn, call, return_to, procs, ports, @@ -12541,6 +13144,21 @@ improper_end erlang:trace_pattern/3.

+ call_memory + +

Returns the accumulated number of words allocated by this function. + Accumulation stops at the next memory traced function: if there + are outer, middle and inner functions each + allocating 3 words, but only outer is traced, it will report + 9 allocated words. If outer and inner are traced, + 6 words are reported for outer and 3 for inner. + When function is not traced, false is returned. + Returned tuple is [{Pid, Count, Words}], + for each process that executed the function.

+

See also + + erlang:trace_pattern/3.

+
all

Returns a list containing the @@ -12843,15 +13461,15 @@ improper_end restart -

For the FlagList options call_count - and call_time: restarts +

For the FlagList options call_count, + call_time and call_memory: restarts the existing counters. The behavior is undefined for other FlagList options.

pause

For the FlagList options - call_count and call_time: pauses + call_count, call_time and call_memory: pauses the existing counters. The behavior is undefined for other FlagList options.

@@ -12927,6 +13545,20 @@ improper_end erlang:trace_info/2.

+ call_memory + +

Starts (MatchSpec == true) or stops + (MatchSpec == false) call memory + tracing for all types of function calls.

+

If call memory tracing is started while already running, + counters and allocations restart from zero. To pause + running counters, use MatchSpec == pause. + Paused and running counters can be restarted from zero with + MatchSpec == restart.

+

To read the counter value, use + + erlang:trace_info/2.

+

The options global and local are mutually exclusive, and global is the default (if no options are @@ -13248,7 +13880,12 @@ end protocol can be found in the Distribution Protocol chapter of the ERTS User's Guide.

- +

+ For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. +

Failure: badarg if Id does not identify a process or a node local port. diff --git a/erts/doc/src/erlc_cmd.xml b/erts/doc/src/erlc_cmd.xml index 98042d49b786..5274e9b3223d 100644 --- a/erts/doc/src/erlc_cmd.xml +++ b/erts/doc/src/erlc_cmd.xml @@ -4,7 +4,7 @@

- 19972020 + 19972022 Ericsson AB. All Rights Reserved. @@ -142,6 +142,47 @@

Use the compile server.

+ + + -enable-feature <Feature> + + +

Enables the + feature feature + during compilation. The special feature all can be + used to enable all features. +

+
+ + + -disable-feature <feature> + + +

Disables the + feature feature + during compilation. The special feature all can be + used to disable all non permanent features. +

+
+ -list-features + +

List short descriptions of the + current configurable features. + Non configurable features, i.e., those with a status of + rejected or permanent will not be shown. +

+
+ -describe-feature <feature> + +

+ Show long description and history of + feature feature. +

+
-M

Produces a Makefile rule to track header dependencies. The @@ -326,7 +367,7 @@ erlc +export_all file.erl

Using the compile server does not always speed up the build, as the compile server sometimes must be restarted to ensure correctness. - Here are some examples of situtations that force a restart:

+ Here are some examples of situations that force a restart:

erlc wants to use a different version of Erlang diff --git a/erts/doc/src/erlsrv_cmd.xml b/erts/doc/src/erlsrv_cmd.xml index e8f066b21b5d..4973a163e46d 100644 --- a/erts/doc/src/erlsrv_cmd.xml +++ b/erts/doc/src/erlsrv_cmd.xml @@ -4,7 +4,7 @@
- 19982021 + 19982023 Ericsson AB. All Rights Reserved. @@ -112,8 +112,7 @@

The location of the Erlang emulator. The default is the located in the same - directory as erlsrv.exe. Do not specify - as this emulator, it will not work.

+ directory as erlsrv.exe.

If the system uses release handling, this is to be set to a program similar to .

diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml index 1a1e583ab11a..914c936095c2 100644 --- a/erts/doc/src/erts_alloc.xml +++ b/erts/doc/src/erts_alloc.xml @@ -4,7 +4,7 @@
- 20022021 + 20022023 Ericsson AB. All Rights Reserved. @@ -514,6 +514,29 @@

See also acul.

+ acful |de]]> + + +

Abandon carrier free utilization limit. When the utilization of + a carrier falls belows this limit erts_alloc instructs the OS that + unused memory in the carrier can be re-used for allocation by other OS + procesesses. On Unix this is done by calling madvise(..., ..., MADV_FREE) + on the unused memory region, on Windows it is done by calling + VirtualAlloc(..., ..., MEM_RESET, PAGE_READWRITE). Defaults to 0 + which means that no memory will be marked as re-usable by the OS.

+

A valid + ]]> is an integer in the range + [0, 100] representing utilization in percent. If this value is + larger than the acul limit it will be lowered to the current + acul limit. If de (default + enabled) is passed instead of a ]]>, + a recommended non-zero utilization value is used. The value + chosen depends on the allocator type and can be changed between + ERTS versions. +

+

See also acul.

+
+ as bf|aobf|aoff|aoffcbf|aoffcaobf|ageffcaoff|ageffcbf|ageffcaobf|gf|af]]> @@ -550,7 +573,7 @@

Adds a small tag to each allocated block that contains basic information about what it is and who allocated it. Use the - instrument + instrument module to inspect this information.

The runtime overhead is one word per allocation when enabled. This @@ -638,7 +661,7 @@ good fit strategy is selected for allocator ]]>. When the good fit strategy is used, free blocks are placed in segregated free-lists. Each free-list - contains blocks of sizes in a specific range. The maxiumum block + contains blocks of sizes in a specific range. The maximum block search depth sets a limit on the maximum number of blocks to inspect in a free-list during a search for suitable block satisfying the request.

@@ -781,10 +804,6 @@ +M<S>atags for a more complete description.

- +Mit X - -

Reserved for future use. Do not use this flag.

-
@@ -813,18 +832,6 @@

Configures all allocators as they were configured in respective Erlang/OTP release. These will eventually be removed.

- config - -

Disables features that cannot be enabled while creating an - allocator configuration with - - erts_alloc_config(3).

- -

This option is to be used only while running - erts_alloc_config(3), not when - using the created configuration.

-
-
+Mlpm all|no @@ -880,21 +887,13 @@

erts_alloc is not obliged to strictly use the settings that have been passed to it (it can even ignore them).

- -

The - erts_alloc_config(3) - tool can be used to aid creation of an - erts_alloc configuration that is suitable for a limited - number of runtime scenarios.

See Also

erl(1), erlang(3), - - erts_alloc_config(3), - + instrument(3)

diff --git a/erts/doc/src/escript_cmd.xml b/erts/doc/src/escript_cmd.xml index 78b121ee97a5..d168edce3a28 100644 --- a/erts/doc/src/escript_cmd.xml +++ b/erts/doc/src/escript_cmd.xml @@ -4,7 +4,7 @@
- 20072021 + 20072023 Ericsson AB. All Rights Reserved. @@ -118,10 +118,9 @@ $ escript factorial 5 applies to the script itself. The encoding of the I/O-server, however, must be set explicitly as follows:

-io:setopts([{encoding, unicode}]) -

The default encoding of the I/O-server for standard_io - is latin1, as the script runs in a non-interactive terminal - (see section +io:setopts([{encoding, latin1}]) +

The default encoding of the I/O-server for standard_io + is unicode if its supported. (see section Summary of Options) in the STDLIB User's Guide.

diff --git a/erts/doc/src/inet_cfg.xml b/erts/doc/src/inet_cfg.xml index 635156378e02..76788f50b734 100644 --- a/erts/doc/src/inet_cfg.xml +++ b/erts/doc/src/inet_cfg.xml @@ -4,7 +4,7 @@
- 20042020 + 20042022 Ericsson AB. All Rights Reserved. @@ -79,7 +79,7 @@ or , see below.

Native lookup (system calls) is always the default resolver method. - This is true for all platforms, except VxWorks and OSE Delta where + This is true for all platforms, except OSE Delta where or is used (in that priority order).

diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml index 1b22cbe4787e..2d6b22a82620 100644 --- a/erts/doc/src/init.xml +++ b/erts/doc/src/init.xml @@ -4,7 +4,7 @@
- 19962020 + 19962021 Ericsson AB. All Rights Reserved. @@ -108,7 +108,7 @@ 3> init:get_argument(progname). {ok,[["erl"]]} - home + home

The home directory (on Unix, the value of $HOME):

diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 65a886fe967d..a62eef43c490 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -4,7 +4,7 @@
 
   
- 19992021 + 19992023 Ericsson AB. All Rights Reserved. @@ -87,7 +87,8 @@ | | | | | | - | | + | | + | | | | | | | | @@ -111,10 +112,14 @@ GuardFunction ::= BoolFunction | | | | | | - | | - | | - | - | | + | + | | + | | + | | + | | + | | + | | + | | | | | | | | @@ -139,6 +144,7 @@ | | | | | | + | | | @@ -169,8 +175,9 @@ | | | | | | - | | - | | + | | + | | + | | | | | | | | @@ -193,10 +200,14 @@ GuardFunction ::= BoolFunction | | | | | | - | | - | | - | - | | + | + | | + | | + | | + | | + | | + | | + | | | | | | | | @@ -221,9 +232,10 @@ follows:

- is_atom, is_float, is_integer, is_list, - is_number, is_pid, is_port, is_reference, - is_tuple, is_map, is_binary, is_function + is_atom, is_boolean, is_float, + is_integer, is_list, is_number, is_pid, + is_port, is_reference, is_tuple, is_map, + is_binary, is_bitstring, is_function

Same as the corresponding guard tests in Erlang, return @@ -272,8 +284,12 @@ returns false.

abs, element, hd, length, - map_get, map_size, node, round, - size, bit_size, tl, trunc, '+', + map_get, map_size, + max, min, + node, round, ceil, floor, float, + size, bit_size, byte_size, tuple_size, + tl, + trunc, binary_part, '+', '-', '*', 'div', 'rem', 'band', 'bor', 'bxor', 'bnot', 'bsl', 'bsr', '>', '>=', '<', '=<', @@ -435,6 +451,37 @@ . The calling Erlang function is not available during such calls.

+ caller_line + +

Similar to caller but returns additional information about + the source code location of the function call-site within the + caller function. Returns the calling function as a tuple + {Module, Function, Arity, {File, Line}}. File is the + string + file name while Line is source line number. If the File + and Line cannot be determined, {Module, Function, Arity, undefined} + is returned. If the calling function cannot be determined, the atom + is returned. Can only be used in the + part when tracing.

+

Notice that if a "technically built in function" (that is, a + function not written in Erlang) is traced, the + function sometimes returns the atom + . The calling + Erlang function is not available during such calls.

+
+ current_stacktrace + +

Returns the current call stack back-trace + (stacktrace) + of the calling function. The stack has the same format as in the + catch part of a try. See The call-stack back trace (stacktrace). + The depth of the stacktrace is truncated according to the + backtrace_depth system flag setting.

+ +

Accepts a depth parameter. The depth value will be + backtrace_depth if the argument is greater.

+
display

For debugging purposes only. Displays the single argument as an @@ -867,7 +914,7 @@ ['$_']}] ]]> -

Function ets:test_ms/2> +

Function ets:test_ms/2 can be useful for testing complicated ETS matches.

diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index fa630834a694..692c1e3c31a5 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -4,7 +4,7 @@
- 20042022 + 20042023 Ericsson AB. All Rights Reserved. @@ -31,2072 +31,4982 @@

This document describes the changes made to the ERTS application.

-
Erts 12.3.2.13 +
Erts 14.1
Fixed Bugs and Malfunctions -

The following functions are now much faster when given - a long list or binary:

- erlang:list_to_integer/1 - erlang:binary_to_integer/1 - erlang:binary_to_integer/2 - erlang:list_to_integer/2 - string:to_integer/1

- Own Id: OTP-18659 Aux Id: PR-7426

+ maps:put with existing key and identical value was not + optimized as a no-op correctly if having the same 32-bit + hash as another key in the map. In practice very rare and + harmless.

+

+ Own Id: OTP-18592

-
-
- -
- -
Erts 12.3.2.12 - -
Fixed Bugs and Malfunctions - -

In rare circumstances, bit syntax matching of an - invalid code point for a utf32 would crash the - runtime system.

+

Fixed an issue with truncated crash slogans on failed + emulator start.

- Own Id: OTP-18560

+ Own Id: OTP-18623 Aux Id: GH-7344

+

Fixed a bug where the emulator was unable to determine + the current cgroup CPU quota.

- If a runtime system which was starting the distribution - already had existing pids, ports, or references referring - to a node with the same nodename/creation pair that the - runtime system was about to use, these already existing - pids, ports, or references would not work as expected in - various situations after the node had gone alive. This - could only occur if the runtime system was communicated - such pids, ports, or references prior to the distribution - was started. That is, it was extremely unlikely to happen - unless the distribution was started dynamically and was - even then very unlikely to happen. The runtime system now - checks for already existing pids, ports, and references - with the same nodename/creation pair that it is about to - use. If such are found another creation will be chosen in - order to avoid these issues.

+ Own Id: OTP-18645 Aux Id: GH-7401

+
+

- Own Id: OTP-18570 Aux Id: PR-7190

+ A process optimized for parallel signal delivery could + under some circumstances lose wakeup information. That + is, the processes was not woken up to take care of the + signal, so the signal would not be taken care of until + the process was woken by another signal. Only processes + configured with message_queue_data + set to off_heap utilize this optimization.

+

+ Own Id: OTP-18647 Aux Id: PR-7595

-

Constructing a binary segment not aligned with a byte - boundary, with a size not fitting in 31 bits, and with a - value not fitting in a 64-bit word could crash the - runtime system.

- Own Id: OTP-18597

+ Function socket:close/1 could cause a VM crash on + Windows.

+

+ Own Id: OTP-18669 Aux Id: OTP-18029

-
-
- - -
Improvements and New Features - +

Fixed a bug in the ARM JIT where it could accidentally + add garbage trailing bits when creating bitstrings whose + size wasn't an even multiple of 8 bits.

- Further robustify implementation of large maps (> 32 - keys). Keys that happen to have same internal 32-bit hash - values are now put in collision nodes which are traversed - with linear search. This removes the demand for the - internal hash function when salted to eventually produce - different hashes for all possible pairs of unequal terms.

+ Own Id: OTP-18672 Aux Id: GH-7469

+
+

- Own Id: OTP-18569

+ Fix erlang:system_info/1 documentation to show + correct types.

+

+ Own Id: OTP-18674 Aux Id: PR-7472

-
-
- -
- -
Erts 12.3.2.11 - -
Fixed Bugs and Malfunctions -

- Fix bug sometimes causing emulator crash at node shutdown - when there are pending connections. Only seen when - running duel distribution protocols, inet_drv and - inet_tls_dist.

+ Expanded the documentation about how to use the + standard_io, standard_error and user + I/O devices.

- Own Id: OTP-18243 Aux Id: GH-6247, PR-6258

+ Added the types io:standard_io/0, + io:standard:error/0 and io:user/0.

+

+ Own Id: OTP-18676 Aux Id: PR-7473 GH-7459

-

Fix bug in binary_to_term (and distributed - receive) when decoding a large map (>32 keys) with - unsorted small maps (<= 32) as keys of the large - map.

-

This was only a problem if the term was encoded by - erl_interface, jinterface or otherwise, as - the VM itself always encodes small maps with sorted - keys.

-

The "binary_to_term" would appear as successful but - the created large map was internally inconsistent. The - smaller key-maps could not be found with maps:get and - friends. Other operations such as map compare and merge - could probably also give incorrect results.

- Own Id: OTP-18343 Aux Id: GH-6496

+ Fix compilation with GNU termcap.

+

+ Own Id: OTP-18702 Aux Id: GH-7381

- Implementations of the call() - driver callback that returned a faulty encoded result - could cause a memory leak and could cause invalid data on - the heap of the processes calling erlang:port_call/3.

+ Delivery time of message signals to a process not + executing any receive expressions could become + very long, potentially infinite. For example, a process + checking for messages using process_info(self(), + message_queue_len) or process_info(self(), + messages) and avoiding to execute a receive + expression matching on messages could be very slow in + detecting new messages. Note that you are still + discouraged from using process_info() this way. A + process that wants to check if there are messages + available to handle should execute a receive + expression matching on messages.

- Own Id: OTP-18525 Aux Id: PR-7049

+ Own Id: OTP-18706 Aux Id: GH-7413, PR-7595, ERIERL-979

+

On AArch64 (ARM64), when calculating both the quotient + and remainder with a divisor begin a power two, the + remainder could be incorrectly calculated.

- Aliases created in combination with a monitor using the - {alias, explicit_unalias} option stopped working - from remote nodes when a 'DOWN' signal had been - received due to the monitor or if the monitor was removed - using the erlang:demonitor() BIF.

+ Own Id: OTP-18724 Aux Id: GH-7566, PR-7567

+
+

- This bug was introduced in OTP 24.3.4.10 and OTP 25.3.

+ Fix bug causing "magic" references in a compressed + ETS table to not keep the referred object alive. The + symptom would be the referred object being garbage + collected prematurely and the reference appearing stale, + not referring to anything. Examples of such magically + referred objects are atomics and NIF resources.

- Own Id: OTP-18557 Aux Id: PR-7131, OTP-18496

+ Own Id: OTP-18732 Aux Id: GH-7444, PR-7458

-
-
- -
- -
Erts 12.3.2.10 - -
Fixed Bugs and Malfunctions - +

Matching out short bitstrings with a fixed size not + divisible by 8 could could lead to the runtime system + terminating with an "Overrun heap and stack" error.

- Active process aliases of a process at its termination - leaked memory.

+ Own Id: OTP-18733 Aux Id: GH-7292

+
+

- Own Id: OTP-18496 Aux Id: GH-6947, PR-6953

+ A constant flow of incoming non-message signals could + prevent a process needing to execute dirty from doing so.

+

+ Own Id: OTP-18737 Aux Id: PR-7595

-
-
- -
- -
Erts 12.3.2.9 - -
Fixed Bugs and Malfunctions - +

A BEAM file usually contains a chunk with the tag + "Type" containing type information that can be used by + the JIT. The beam_lib:strip/1 takes care to + preserve that chunk, but a build/release tool that does + customized stripping could accidentally remove the chunk. + Loading a BEAM file without the "Type" chunk could cause + incorrect behavior of the loaded code.

- process_info(Pid, status) when Pid /= - self() could return an erroneous result.

+ Own Id: OTP-18745 Aux Id: GH-7492, PR-7616

+
+

- Own Id: OTP-18421 Aux Id: PR-6806

+ gen_udp:recv/* for Unix Domain Socket in binary + mode and passive mode has been fixed to not crash.

+

+ Own Id: OTP-18747 Aux Id: GH-7605

-

In rare circumstances, when a process exceeded its - allowed heap size set by option max_heap_size, it - would not be killed as it should be, but instead enter a - kind of zombie state it would never get out of.

- Own Id: OTP-18463 Aux Id: PR-6858

+ The cleanup operation of not yet delivered signals to a + terminated process yielded excessively.

+

+ Own Id: OTP-18752 Aux Id: PR-7633

+
+ +

+ Fixed minor hashing issue with the local option of + term_to_binary()/term_to_iovec().

+

+ Own Id: OTP-18753 Aux Id: PR-7634

-
- -
Erts 12.3.2.8 -
Fixed Bugs and Malfunctions +
Improvements and New Features -

Fixed a bug in selective receive optimization that - could crash 32-bit emulators.

- Own Id: OTP-18383 Aux Id: ERIERL-905

+ Update gen_tcp_socket and gen_udp_socket to handle + 'completion' (socket on Windows).

+

+ Own Id: OTP-18586 Aux Id: OTP-18029

- A race condition which was very rarely triggered could - cause the signal queue of a process to become - inconsistent causing the runtime system to crash.

+ Add support for Unix Domain Sockets (only for STREAM + sockets) on Windows for 'socket'.

- Own Id: OTP-18388 Aux Id: OTP-17462, PR-6662

+ Own Id: OTP-18611 Aux Id: OTP-18029, #5024

-
-
- -
- -
Erts 12.3.2.7 - -
Fixed Bugs and Malfunctions - +

In Erlang/OTP 27, by default escripts will be compiled + before being executed. That means that the + compiler application must be installed. It is + possible to force the escript to be interpreted by adding + the directive -mode(interpret). to the escript + file.

+

In Erlang/OTP 28, support for interpreting an escript + will be removed.

- Spec for function net:if_names/0 incorrect

+ Own Id: OTP-18638

+
+

- Own Id: OTP-18296 Aux Id: OTP-16464

+ Add basic support for socket ioctl on Windows.

+

+ Own Id: OTP-18660

- Fix bug in binary_to_term decoding a binary term - 2Gbyte or larger.

+ Removed erts/etc/darwin/Info.plist, as it is no longer + necessary after macos 10.12

- Own Id: OTP-18306 Aux Id: GH-6393, PR-6401

+ Own Id: OTP-18661 Aux Id: PR-6112

- Fix list_to_atom/1 for negative code points. Could - either return with a positive code point or fail with an - incorrect exception.

+ Add support for (Windows) socket option exclusiveaddruse.

- Own Id: OTP-18321

+ Own Id: OTP-18686

- Fix bug in binary_to_term decoding a list of - length 1G or longer.

+ [socket] Add support for the 'nopush' option.

- Own Id: OTP-18328 Aux Id: GH-6439, PR-6440

+ Own Id: OTP-18687

-
-
- -
- -
Erts 12.3.2.6 - -
Fixed Bugs and Malfunctions -

- Notifications - about available distribution data sent to - distribution controller processes could be lost. - Distribution controller processes can be used when - implementing an alternative distribution carrier. The - default distribution over tcp was not effected and the - bug was also not present on x86/x86_64 platforms.

+ Add support for socket option 'BSP STATE'.

- Own Id: OTP-18258 Aux Id: GH-6309, PR-6324

+ Own Id: OTP-18693

+
+ +

+ Add tcp socket options 'keepcnt', 'keepidle' and + 'keepintvl'.

+

+ Own Id: OTP-18698

+
+ +

+ Add support for misc (Windows) socket options + ('max_msg_size' and 'maxdg').

+

+ Own Id: OTP-18710

-
Erts 12.3.2.5 +
Erts 14.0.2
Fixed Bugs and Malfunctions

- Fix writing and reading of more than 2 GB in a single - read/write operation on macOS. Before this fix attempting - to read/write more than 2GB would result in - {error,einval}.

+ Fix using the IME (Input Method Editor) to enter text in + cmd.exe and powershell.exe on Windows.

- Own Id: OTP-18222 Aux Id: PR-6248 GH-6242

+ Own Id: OTP-18630 Aux Id: PR-7275 GH-7029

+
+ +

+ Multiple socket:accept calls issue. When making multiple + accept calls, only the last call is active.

+

+ Own Id: OTP-18635 Aux Id: #7328

+
+ +

+ Fix the shell to ignore terminal delay when the terminal + capabilities report that they should be used.

+

+ Own Id: OTP-18636 Aux Id: PR-7352 GH-7308

+
+ +

+ Fix "oldshell" to echo characters while typing on + Windows.

+

+ Own Id: OTP-18637 Aux Id: PR-7359 GH-7324

+
+ +

+ On Windows, a call to the function socket:close, when + there are waiting active calls to read, write or accept + functions, could hang.

+

+ Own Id: OTP-18646

+
+ +

+ Fix issues when reading or configuring standard_io + on Windows when erl.exe is started using -noshell + flag.

+

+ Own Id: OTP-18649 Aux Id: GH-7261 PR-7400

+
+ +

The following functions are now much faster when given + a long list or binary:

+ erlang:list_to_integer/1 + erlang:binary_to_integer/1 + erlang:binary_to_integer/2 + erlang:list_to_integer/2 + string:to_integer/1 +

+ Own Id: OTP-18659 Aux Id: PR-7426

+
+ +

On AArch64 (ARM64), equality and non-equality tests + with literal bitstrings could succeed when they should + fail and vice versa.

+

+ Own Id: OTP-18663 Aux Id: GH-7433, PR-7437

-
Erts 12.3.2.4 +
Erts 14.0.1
Fixed Bugs and Malfunctions

- Fix bug causing ets:info (and sometimes - ets:whereis) to return 'undefined' for an existing - table if a concurrent process were doing - ets:insert with a long list on the same table.

+ Build of the socket nif failed on Solaris 11.

- Own Id: OTP-18218 Aux Id: ERIERL-855

+ Own Id: OTP-18585 Aux Id: OTP-18029

+
+ +

Fixed two reduction-counting bugs relating to + binaries.

+

+ Own Id: OTP-18587

+
+ +

Constructing a binary segment not aligned with a byte + boundary, with a size not fitting in 31 bits, and with a + value not fitting in a 64-bit word could crash the + runtime system.

+

+ Own Id: OTP-18597

+
+ +

When a binary construction failed because of bad size + for a segment, the error information was not always + correct.

+

+ Own Id: OTP-18602 Aux Id: GH-7282

+
+ +

Fixed a crash when calling a fun that was defined in a + module that had been upgraded.

+

+ Own Id: OTP-18621 Aux Id: GH-7288

-
Erts 12.3.2.3 +
Erts 14.0
Fixed Bugs and Malfunctions -

Fix faulty distribution encoding of terms with - either

a fun with bit-string or - export-fun in its environment when encoded toward a not - yet established (pending) connection or a - fun with a binary/bitstring, in its environment, - referring to an off-heap binary (larger than 64 - bytes).

The symptom could be failed - decoding on the receiving side leading to aborted - connection. Fix OTP-18093 is a workaround for theses bugs - that makes the VM accepts such faulty encoded funs.

-

The first encoding bug toward pending connection - exists only in OTP 23 and 24, but the second one exists - also on OTP 25.

-

- Own Id: OTP-18104 Aux Id: OTP-18093

-
- -

Distributed exit signals could be lost under the - following conditions:

An exit signal - from a parent process to a child process was lost if:

-

the parent process terminated before the - spawn request that created the child had completed, -

the spawn request set up a link - between parent and child

the spawn - request was distributed, and

the - exit reason was larger than one machine word.

-

Loss of a connection over which - a not yet completed spawn request was ongoing could cause - loss of exit signals. Such loss of exit signals was very - rare. Besides the above described connection loss also - the following conditions had to be satisfied:

-

The spawn request that was interrupted by the - connection loss also had to set up a link between the - parent process and the child process.

-

The parent process that issued the spawn - request also had to be terminating while the spawn - request was interrupted by the connection loss. -

The same parent process also had to - have made other spawn requests to other nodes than to the - node to which the connection was lost.

-

These spawn requests to the other nodes also - had to set up links.

These spawn - requests to the other nodes also had to be not yet - completed at the time of the connection loss. That is, - the spawn reply from the child process had not yet - reached the parent process.

If all - the conditions above were met, exit signals to the - children spawned due to the above described spawn - requests to other nodes could be lost.

-

The above bug also caused a significant memory leak - when it was triggered since the destruction of the parent - process never completed.

+

If a local fun was called while reloading the + exact same module that defined said fun, there + was a small window in which the call would land in code + that was yet to be fully loaded.

- Own Id: OTP-18164 Aux Id: PR-6114

+ Own Id: OTP-18016

- A race could cause process_info(Pid, - message_queue_len) on other processes to return - invalid results.

+ Fix the TLS distribution to work when starting Erlang in + embedded mode and a connection is done before kernel is + fully started.

- Own Id: OTP-18169 Aux Id: PR-6134

+ Own Id: OTP-18248 Aux Id: PR-6227 GH-6085

- Fixed reduction counting for handling process system - tasks.

+ erl -remsh has been improved to provide better + error reasons and work when using a shell without + terminal support (that is an "oldshell").

- Own Id: OTP-18170 Aux Id: PR-6135

+ Own Id: OTP-18271 Aux Id: PR-6279

- Priority elevation of terminating processes did not work - which could cause execution of such processes to be - delayed.

+ Fix so that -fno-omit-frame-pointer is applied to + all of the Erlang VM when using the JIT so that tools, + such as perf, can crawl the process stacks.

- Own Id: OTP-18175 Aux Id: PR-6142

+ Own Id: OTP-18274 Aux Id: PR-6048

- An unlink operation made by a process that terminated - before the unlink operation completed, i.e., before it - had received an unlink-ack signal from the linked - process, caused an exit signal to erroneously be sent - from the terminating process to the process being - unlinked. This exit signal would most often be ignored by - the receiver, but if the receiver of the exit signal - concurrently set up a new link, it could receive the exit - signal with the actual exit reason of the terminating - process instead of a noproc exit reason. It is - however very hard to detect that this has happened and - has no obvious negative consequences, so it should be - considered harmless.

-

- A distributed unlink-ack signal received by a terminating - process was also not properly removed which could cause a - minor memory leak.

+ Compilation server now support unicode paths in + compilation server for filesystems that are encoded with + unicode.

- Own Id: OTP-18177 Aux Id: PR-6150

+ Own Id: OTP-18277 Aux Id: PR-6306

+

Reintroduced the optimization that turned anonymous + functions without free variables into literals + (OTP-15195). This optimization was lost during + refactoring in OTP 24.

Alongside this fix, we plan + to remove the "fun creator pid" feature in OTP 27. See + Upcoming + Potential Incompatibilities for more + details.

- The monitor/3 BIF - did not apply options to the created monitor if the - target process or port did not exist. That is, the - corresponding down message would get a `DOWN` tag - even if a custom tag had been set, and the returned - reference was not an alias even if the alias - option had been passed.

-

- Own Id: OTP-18190 Aux Id: GH-6185, PR-6209

+ Own Id: OTP-18498

+

Fixed a crash during tracing on certain platforms that + cannot use the machine stack for Erlang code (mainly + OpenBSD and Linux with musl).

- The erlang:monotonic_time/1, - erlang:system_time/1, - erlang:time_offset/1, - and os:system_time/1 - BIFs erroneously failed when passed the argument - native.

-

- Own Id: OTP-18197 Aux Id: GH-6165, PR-6213

+ Own Id: OTP-18561

-
- -
Erts 12.3.2.2 -
Fixed Bugs and Malfunctions +
Improvements and New Features

- Fixed emulator crash that could happen during crashdump - generation of ETS tables with options ordered_set - and {write_concurrency,true}.

+ The enif_set_option() + function has been introduced into the NIF API. It can be + used in order to set the ERL_NIF_OPT_DELAY_HALT + and/or ERL_NIF_OPT_ON_HALT + options with which one can synchronize halt of the + runtime system with flushing enabled and execution of + NIFs. Halt of the + runtime system without flushing enabled, + now terminates the runtime system without execution of + atexit/on_exit handlers that may have been + installed into the runtime system which might be + considered a potential incompatibility.

- Own Id: OTP-18144 Aux Id: GH-5981

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-17771 Aux Id: GH-5325, PR-6370

+
+ +

The TTY/terminal subsystem has been rewritten by + moving more code to Erlang from the old linked-in driver + and implementing all the I/O primitives needed in a NIF + instead.

On Unix platforms the user should not + notice a lot of difference, besides better handling of + unicode characters and fixing of some long standing bugs. +

Windows users will notice that erl.exe has the + same functionality as a normal Unix shell and that + werl.exe has been removed and replaced with a symlink to + erl.exe. This makes the Windows Erlang terminal + experience identical to that of Unix.

The + re-write brings with it a number of bug fixes and feature + additions:

The TTY is now reset when + Erlang exits, fixing zsh to not break when terminating an + Erlang session. standard_error now + uses the same unicode mode as standard_io. + Hitting backspace when searching the shell history + with an empty search string no longer breaks the + shell. Tab expansion now works on remote + nodes started using the JCL interface. It is + now possible to configure the shell slogan and the + session slogans (that is the texts that appear when you + start an Erlang shell). See the kernel documentation for + more details. Added shell:start_interactive + for starting the interactive shell from a non-interactive + Erlang session (for example an escript). On + Windows, when starting in detached mode the standard + handler are now set to nul devices instead of + being unset. Standard I/O now always + defaults to unicode mode if supported. Previously + the default was latin1 if the runtime system had + been started with -oldshell or -noshell + (for example in an escript). To send raw bytes + over standard out, one now explicitly has to specify + io:setopts(standard_io, [{encoding, latin1}]). + +

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-17932 Aux Id: PR-6144 GH-3150 GH-3390 GH-4343 + GH-4225

-
-
- -
- -
Erts 12.3.2.1 - -
Fixed Bugs and Malfunctions - +

Add support for socket on Windows.

+ Pre release status. Error codes not + finalized. No explicit support for Windows + specific options (socket options, flags for read and + write). New async api for Windows + (completion). See the Asynchronous calls chapter + in the (Socket Usage) Users Guide. To ensure + platform independence, gen_tcp and gen_udp is + intended to be used (not yet updated). +

- Accept funs (NEW_FUN_EXT) with incorrectly encoded size - field. This is a workaround for a bug (OTP-18104) - existing in OTP 23 and 24 that could cause incorrect size - fields in certain cases. The emulator does not use the - decoded size field, but erl_interface still does - and is not helped by this workaround.

+ Own Id: OTP-18029

+
+

- Own Id: OTP-18093 Aux Id: OTP-18104, PR-5987

+ Updated configure cache for Windows. This makes configure + run faster on Windows as many more checks are cached.

+

+ Own Id: OTP-18053 Aux Id: PR-6101

+

Optimized record updates.

- The zlib built in to the runtime system has been updated - to version 1.2.12. (Note that on most platforms, the - platform's own zlib is used.)

+ Own Id: OTP-18126 Aux Id: PR-6033

+
+ +

Optimized internal hash routines.

- Own Id: OTP-18123 Aux Id: GH-5994

+ Own Id: OTP-18131

-
-
- -
- -
Erts 12.3.2 - -
Fixed Bugs and Malfunctions - +

As announced when OTP 25 was released, multi + time warp mode is now enabled by default. This + assumes that all code executing on the system is + time + warp safe.

If you have old code in + the system that is not time warp safe, you now explicitly + need to start the system in no time + warp mode (or singe + time warp mode if it is partially time warp + safe) in order to avoid problems. When starting the + system in no time warp mode, the system behaves as it did + prior to the introduction of the extended time + functionality introduced in OTP 18.

If you have + code that is not time warp safe, you are strongly + encouraged to change this so that you can use multi time + warp mode. Compared to no time warp mode, multi time warp + mode improves scalability and performance as well as + accuracy and precision of time measurements.

- Let EPMD tolerate failure when binding to IPv4/IPv6 - loopback intefaces in addition to user-supplied addresses - via ERL_EPMD_ADDRESS or the -address - option. This can happen, for example, if the host system - has ipv6 disabled via the disable_ipv6 sysctl.

+ *** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-17970 Aux Id: PR-5762

+ Own Id: OTP-18135 Aux Id: GH-4965, PR-6046

+
+ +

There are several new optimization for binary syntax + in the JIT:

Creation and matching of + binaries with segments of fixed sizes have been + optimized. Creation and matching of UTF-8 + segments have been optimized. Appending to + binaries has been optimized. +

+ Own Id: OTP-18137 Aux Id: PR-6259, PR-6404, PR-6576, + PR-6804

+
+ +

As announced since the release of OTP 24, support + for:

version 4 node container types + in the external term format are now mandatory. That is, + references supporting up to 5 32-bit integer identifiers, + and process and port identifiers with support for 64-bit + data storage. The distribution flag DFLAG_V4_NC + is therefor now also mandatory. OTP has since OTP 24 + supported this. Also note that the external format + produced by term_to_binary() and + term_to_iovec() will unconditionally produce pids, + ports, and references supporting this larger format. +

the new + link protocol introduced in OTP 23.3 is now + mandatory. The distribution flag DFLAG_UNLINK_ID + is therefor now also mandatory.

+

Due to the above, OTP 26 nodes will refuse to connect + to OTP nodes from releases prior to OTP 24.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-18140 Aux Id: PR-6072

-

Fixed a rare bug in binary_to_term/1, - enif_make_map_from_arrays, - erl_drv_send_term, and Erlang distribution that - could crash the emulator.

+

Optimization of process + aliases made possible now that support for + version + 4 node container types in the external term + format is mandatory.

- Own Id: OTP-18027

+ Own Id: OTP-18141 Aux Id: OTP-18140, PR-6073

-

Fixed a rare race in persistent_term:get/1,2 - that could cause it to return the value of another - key.

+

The compiler and JIT now generate better code for + creation of small maps where all keys are literals known + at compile time.

- Own Id: OTP-18065 Aux Id: GH-5908

+ Own Id: OTP-18185 Aux Id: GH-6139

- Fix bug where the process message queue was left in an - inconsistent state when changing from on_heap to off_heap - message queue data causing the GC to segfault.

+ When erl -eval fails to execute a command, an + error description is printed to standard_error.

- Own Id: OTP-18075 Aux Id: PR-5927

+ Own Id: OTP-18227 Aux Id: PR-6254

+

Support for UTF-8 atoms and strings in the NIF + interface including new functions + enif_make_new_atom, enif_make_new_atom_len + and enif_get_string_length.

- Fix functions that convert universal to localtime (such - as erlang:localtime/0 and - erlang:universaltime_to_localtime/1) to fetch the correct - localtime if it is changed after the start of the VM.

+ Own Id: OTP-18334 Aux Id: PR-6434

+
+ +

The following inet:setopts/2 + options have been introduced:

reuseport +

Reuse of local port. Load balancing may or may + not be provided depending on underlying OS.

+ reuseport_lb +

Reuse of local port. Load balancing + provided.

exclusiveaddruse +

Exclusive address/port usage on Windows. This + socket option is Windows specific and will silently be + ignored on other systems.

The + behavior of setting reuseaddr + on Windows have changed in a backwards + incompatible way. The underlying SO_REUSEADDR + socket option is now only set if both the reusaddr + and the reuseport inet options have been + set. This since the underlying SO_REUSEADDR socket + option on Windows behaves similar to how BSD behaves if + both the underlying socket options SO_REUSEADDR + and SO_REUSEPORT have been set. See the + documentation of the reuseaddr option for more + information.

- Own Id: OTP-18076 Aux Id: ERIERL-802 PR-5905

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-18344 Aux Id: PR-6522, PR-6944, OTP-18324, + PR-6481, GH-6461

+

erlang:display/1 will now print large maps in a + more readable way (similar to how small maps are + printed).

- Fix memory leak when a process doing a distributed - fragmented send is sent an exit signal. Before this fix - the receiving node would be left with an incomplete - message that would remain until the nodes were - disconnected. The bug has existed since Erlang/OTP 21.

+ Own Id: OTP-18360 Aux Id: PR-6497

+
+ +

The BIFs min/2 and max/2 are now allowed + to be used in guards and match specs.

- Own Id: OTP-18077 Aux Id: GH-5876 PR-5892

+ Own Id: OTP-18367 Aux Id: GH-6544

- Corrected the behaviour of the shutdown function when - using with the inet_backend = socket. It was not - sufficiently compatible with the "old" gen_tcp.

+ Fail enif_init_resource_type and friends by + returning NULL if not called during load/upgrade. Old + behavior was undefined.

- Own Id: OTP-18080 Aux Id: GH-5930

+ Own Id: OTP-18369

-
-
- -
- -
Erts 12.3.1 - -
Fixed Bugs and Malfunctions - -

erlang:open_port({spawn, _},_) has been fixed - on Windows to handle whitespace characters in the path - correctly.

This could, for example, cause - execution of the resolver helper program - inet_gethost to fail and instead possibly execute - a different program.

- Own Id: OTP-17978 Aux Id: OTP-17958

+ New option include_shared_binaries for the + max_heap_size process limit. If set to + true, large binaries (> 64 bytes), which may be + referred by several processes, are included in the memory + sum compared against the max_heap_size limit.

+

+ Own Id: OTP-18410 Aux Id: GH-5889, PR-6345

+

Map comprehensions as suggested in EEP 58 has now been + implemented.

- Fix race condition when creating crash dump that could - cause multiple threads to race when writing the initial - information in a crash dump.

+ Own Id: OTP-18413 Aux Id: EEP-58, PR-6727

+
+ +

Some map operations have been optimized by changing + the internal sort order of atom keys. This changes the + (undocumented) order of how atom keys in small maps are + printed and returned by maps:to_list/1 and + maps:next/1. The new order is unpredictable and + may change between different invocations of the Erlang + VM.

+

For applications where order is important, there is a + new function maps:iterator/2 for creating + iterators that return the map elements in a deterministic + order. There are also new modifiers k and K + for the format string for io:format() to support + printing map elements ordered.

- The race condition was introduced in erts-12.2 - (Erlang/OTP 24.2).

+ Own Id: OTP-18414 Aux Id: PR-6151

+
+ +

Reduced memory usage of + file:read_file_info/1,2

- Own Id: OTP-17993 Aux Id: PR-5806

+ Own Id: OTP-18424 Aux Id: PR-6716

+

Add new function current_stacktrace for trace + match specifications used by + erlang:trace_pattern/3.

This new option + puts the current stacktrace of the caller into the trace + message sent to the trace receiver.

- Fix Erlang monotonic time on MacOS. Previously used OS - monotonic time primitive on MacOS is buggy and will not - be used anymore. It has been replaced with usage of - another OS monotonic time primitive that does not appear - to be buggy.

-

- Own Id: OTP-17998 Aux Id: PR-5825, GH-5554

+ Own Id: OTP-18425 Aux Id: PR-6628, GH-5333

-
-
- -
- -
Erts 12.3 - -
Fixed Bugs and Malfunctions - -

Fixed a bug in the x86 JIT that might cause floating - point instructions to wrongly throw an exception.

- Own Id: OTP-17822

+ The amount of significant bits in node local process + identifiers and port identifiers has been extended from + 28 bits to 60 bits on 64-bit runtime systems. This makes + these identifiers large enough to in practice never + having to be reused during the life time of a node.

+

+ Own Id: OTP-18435 Aux Id: PR-6827

- Preserve correct nodedown_reason if supervised - distribution controller processes exit with {shutdown, - Reason}.

+ New trace feature call_memory. Similar to + call_time tracing, but instead of measure + accumulated time in traced functions it measures + accumulated heap space consumed by traced functions. It + can be used to compare how much different functions are + contributing to garbage collection being triggered.

- Own Id: OTP-17838 Aux Id: PR-5748

+ Own Id: OTP-18440 Aux Id: PR-6351

+

It is no longer necessary to enable a feature in the + runtime system in order to load modules that are using + it. It is sufficient to enable the feature in the + compiler when compiling it.

+

That means that to use feature maybe_expr in + Erlang/OTP 26, it is sufficient to enable it during + compilation.

+

In Erlang/OTP 27, feature maybe_expr will be + enabled by default, but it will be possible to disable + it.

- Handling of send_timeout for gen_tcp has - been corrected so that the timeout is honored also when - sending 0 bytes.

-

- Own Id: OTP-17840

+ Own Id: OTP-18445

-

By default global does not take any - actions to restore a fully connected network when - connections are lost due to network issues. This is - problematic for all applications expecting a fully - connected network to be provided, such as for example - mnesia, but also for global itself. A - network of overlapping partitions might cause the - internal state of global to become inconsistent. - Such an inconsistency can remain even after such - partitions have been brought together to form a fully - connected network again. The effect on other applications - that expects that a fully connected network is maintained - may vary, but they might misbehave in very subtle hard to - detect ways during such a partitioning.

In order - to prevent such issues, we have introduced a prevent - overlapping partitions fix which can be enabled using - the prevent_overlapping_partitions - kernel(6) parameter. When this fix has been - enabled, global will actively disconnect from - nodes that reports that they have lost connections to - other nodes. This will cause fully connected partitions - to form instead of leaving the network in a state with - overlapping partitions. Note that this fix has to - be enabled on all nodes in the network in order to - work properly. Since this quite substantially changes the - behavior, this fix is currently disabled by default. - Since you might get hard to detect issues without this - fix you are, however, strongly advised to enable - this fix in order to avoid issues such as the ones - described above. As of OTP 25 this fix will become - enabled by default.

+

Handling of on_load modules during boot has + been improved by adding an extra step in the boot order + for embedded mode that runs all on_load handlers, + instead of relying on explicit invocation of them, later, + when the kernel supervision tree starts.

This is + mostly a code improvement and OTP internal simplification + to avoid future bugs and to simplify code maintenance. +

- Own Id: OTP-17843 Aux Id: ERIERL-732, PR-5611

+ Own Id: OTP-18447

-

Corrected the type specification of - erlang:seq_trace/2.

- Own Id: OTP-17900 Aux Id: GH-5667

+ Introduced the local + option of term_to_binary/2 + and term_to_iovec/2.

+

+ Own Id: OTP-18477 Aux Id: PR-7006

- Fix memory leak when tracing on running on a process that - only handle system tasks or non-message signals (for - example process_info requests).

+ Document the commonly used practice to create and store + static atoms at NIF load time in callbacks load or + upgrade.

- Own Id: OTP-17904 Aux Id: ERIERL-757

+ Own Id: OTP-18483 Aux Id: PR-6888

-
-
- - -
Improvements and New Features -

- Add support for using socket:sockaddr_in() and - socket:sockaddr_in6() when using gen_sctp, gen_tcp and - gen_udp. This will make it possible to use Link Local - IPv6 addresses.

+ Optimize ets:lookup_element for uncompressed + tables by using a more efficient method to copy the term + from ETS to the heap of the calling process.

- Own Id: OTP-17455 Aux Id: GH-4852

+ Own Id: OTP-18493 Aux Id: PR-6272

+

The default encoding of atoms by term_to_binary + and term_to_iovec have changed from Latin1 to + UTF-8. The old encoding can still be obtained with + options {minor_version, 1}.

Apart from + encoding code points between 128 and 255 with two bytes + (UTF-8) instead of one, most atoms will occupy one less + byte as the length field use only one byte instead of two + if possible.

- Show on_load failure reasons in embedded mode.

+ *** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-17718 Aux Id: PR-5199

+ Own Id: OTP-18505 Aux Id: PR-6991

- Compile date saved in the Erlang VM executable has been - removed.

+ The version of zlib included in the Erlang/OTP source + code is now 1.2.13.

- Own Id: OTP-17891 Aux Id: PR-5589

+ Own Id: OTP-18517

- Improve documentation for the dynamic node name feature.

+ gen_tcp:send/*, gen_udp:send/* and + gen_sctp:send/* have been optimized to use the + infamous receive reference optimization, so now sending + should not have bad performance when the calling process + has a large message queue.

- Own Id: OTP-17918

+ Own Id: OTP-18520 Aux Id: GH-6455

-
-
- -
- -
Erts 12.2.1 - -
Fixed Bugs and Malfunctions - -

Fixed a memory leak in file:read_file_info/2 - and file:read_file/1 on Windows.

+

Added the new built-in type dynamic() + introduced in EEP-61, improving support for gradual type + checkers.

- Own Id: OTP-17827 Aux Id: GH-5527

+ Own Id: OTP-18522

- Fix GC emulator crash when spawn_request was used - when message tracing was enabled.

+ Optimize maps:merge/2 memory consumption for small + maps (<33 keys) by reusing key tuples or entire maps + if the result map has the same number of keys as any of + the argument maps.

- Own Id: OTP-17871 Aux Id: PR-5612

+ Own Id: OTP-18523 Aux Id: PR-7004

-
-
- -
- -
Erts 12.2 - -
Fixed Bugs and Malfunctions - -

When matching and constructing utf16 segments - in the binary syntax, the native flag would be - ignored. That is, the endian would always be big endian - even on a little-endian computer (almost all modern - computers).

- Own Id: OTP-17713

+ Optimize maps:merge/2 memory consumption further + for small maps by mutating 2nd map to use literal key + tuple of 1st map if both have the same keys.

+

+ Own Id: OTP-18524 Aux Id: PR-7004, OTP-18523

+

ceil/1, floor/1, is_bitstring/1, + is_boolean/1, is_function/2, and + tuple_size/1 can now be used in match + specifications.

- Fix the help printout of +JPperf.

-

- Own Id: OTP-17749 Aux Id: PR-5378 GH-5361

+ Own Id: OTP-18526 Aux Id: GH-7045

- Fix bug that could cause Erlang to deadlock during - creation of an Erlang crash dump.

+ Allow IPv6 addresses as host in http packets + decoded by erlang:decode_packet/3 and + gen_tcp packet option. The IPv6 address should be + enclosed within [] according to RFC2732.

- Own Id: OTP-17751 Aux Id: PR-5315

+ Own Id: OTP-18540 Aux Id: PR-6900

- Fixed C++ build errors on some aarch64 platforms.

+ Removed the experimental erts_alloc_config module. + It no longer produced good configurations and cannot be + fixed in a reasonably backwards compatible manner. It has + since OTP 25 been deprecated and scheduled for removal in + OTP 26.

- Own Id: OTP-17763 Aux Id: GH-5351

-
- -

For macOS, the Info.plist file embedded in the - runtime system now only contains the absolute minimum - amount of information needed for the web view in - wx to work towards localhost. The other - fields have been removed, allowing an application - packaged in a bundle to specify the application name and - other parameter in its own Info.plist file.

+ *** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-17785 Aux Id: PR-5393

+ Own Id: OTP-18549 Aux Id: PR-7105

- Fix bug in internal stacks (WSTACK and ESTACK) used by - term_to_binary/2 to encode terms. The bug could - cause a segfault if a very very large map was to be - encoded with the deterministic option given.

+ ERTS internal thread names have been changed. All threads + created by ERTS now have a prefix erts_ followed + by a type name potentially followed by an integer index. + For example, normal schedulers are now named + erts_sched_<IX>, dirty CPU schedulers + erts_dcpus_<IX>, and dirty IO schedulers + erts_dios_<IX>. NIF and driver thread names + are truncated at 15 characters regardless of whether the + underlying platform support more characters or not.

- Own Id: OTP-17804 Aux Id: PR-5372

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-18552 Aux Id: PR-6973

- Improve the error printout when open_port/2 fails - because of invalid arguments.

+ Further robustify implementation of large maps (> 32 + keys). Keys that happen to have same internal 32-bit hash + values are now put in collision nodes which are traversed + with linear search. This removes the demand for the + internal hash function when salted to eventually produce + different hashes for all possible pairs of unequal terms.

- Own Id: OTP-17805 Aux Id: PR-5406

+ Own Id: OTP-18569

+

In Erlang/OTP 27, 0.0 will no longer be + considered to be exactly equal to -0.0. See + Upcoming + Potential Incompatibilities.

- Fix bug in crash dumps where the stackframe of a process - would be printed using an incorrect format.

-

- Crash dump viewer has also been fixed to be able read the - broken stack format.

-

- The bug has existed since Erlang/OTP 23.0.

-

- Own Id: OTP-17814 Aux Id: PR-5462

+ Own Id: OTP-18574

+
+ +
Erts 13.2.2.3 -
Improvements and New Features +
Fixed Bugs and Malfunctions

- An option for enabling dirty scheduler specific allocator - instances has been introduced. By default such allocator - instances are disabled. For more information see the - documentation of the +Mdai - erl command line argument.

+ A process optimized for parallel signal delivery could + under some circumstances lose wakeup information. That + is, the processes was not woken up to take care of the + signal, so the signal would not be taken care of until + the process was woken by another signal. Only processes + configured with message_queue_data + set to off_heap utilize this optimization.

- Own Id: OTP-17363 Aux Id: GH-4728, PR-5187

+ Own Id: OTP-18647 Aux Id: PR-7595

- Minor optimization of receive markers in message queues.

+ Delivery time of message signals to a process not + executing any receive expressions could become + very long, potentially infinite. For example, a process + checking for messages using process_info(self(), + message_queue_len) or process_info(self(), + messages) and avoiding to execute a receive + expression matching on messages could be very slow in + detecting new messages. Note that you are still + discouraged from using process_info() this way. A + process that wants to check if there are messages + available to handle should execute a receive + expression matching on messages.

- Own Id: OTP-17673 Aux Id: OTP-16226

+ Own Id: OTP-18706 Aux Id: GH-7413, PR-7595, ERIERL-979

- All predefined types have been added to the erlang - module together with documentation.

-

- Any reference to a predefined type now links to that - documentation so that the user can view it.

+ Fix bug causing "magic" references in a compressed + ETS table to not keep the referred object alive. The + symptom would be the referred object being garbage + collected prematurely and the reference appearing stale, + not referring to anything. Examples of such magically + referred objects are atomics and NIF resources.

- Own Id: OTP-17689 Aux Id: PR-5292

+ Own Id: OTP-18732 Aux Id: GH-7444, PR-7458

- Suppress a code checker warning caused by debug builds of - YCF. YCF tries to get a conservative estimate of the - bottom of the stack by reading and returning a call stack - allocated variable.

+ A constant flow of incoming non-message signals could + prevent a process needing to execute dirty from doing so.

- Own Id: OTP-17719

+ Own Id: OTP-18737 Aux Id: PR-7595

- Add file and product properties to erl.exe and werl.exe.

+ The cleanup operation of not yet delivered signals to a + terminated process yielded excessively.

- Own Id: OTP-17724 Aux Id: ERL-1224

+ Own Id: OTP-18752 Aux Id: PR-7633

+
+
+ +
+ +
Erts 13.2.2.2 + +
Fixed Bugs and Malfunctions +

- Micro optimization in bitstring append operations.

+ Multiple socket:accept calls issue. When making multiple + accept calls, only the last call is active.

- Own Id: OTP-17760 Aux Id: ERIERL-725, PR-5414

+ Own Id: OTP-18635 Aux Id: #7328

+

The following functions are now much faster when given + a long list or binary:

+ erlang:list_to_integer/1 + erlang:binary_to_integer/1 + erlang:binary_to_integer/2 + erlang:list_to_integer/2 + string:to_integer/1

- Responsiveness of processes executing on normal or - low priority could suffer due to code purging or - literal area removal on systems with a huge amount of - processes. This since during these operations all - processes on the system were scheduled for execution at - once.

-

- This problem has been fixed by introducing a limit on - outstanding purge and copy literal requests in the - system. By default this limit is set to twice the amount - of schedulers on the system. This will ensure that - schedulers will have enough work scheduled to perform - these operations as quickly as possible at the same time - as other work will be interleaved to a much higher - degree. Performance of these operations will however be - somewhat degraded due to the overhead of enforcing this - limit compared to when using a very large limit.

-

- This limit can be set by passing the +zosrl - command line argument to erl, or by calling - erlang:system_flag(outstanding_system_requests_limit, - NewLimit).

-

- Own Id: OTP-17796 Aux Id: ERIERL-729, PR-5473

+ Own Id: OTP-18659 Aux Id: PR-7426

-
Erts 12.1.5 +
Erts 13.2.2.1
Fixed Bugs and Malfunctions +

Fixed a crash during tracing on certain platforms that + cannot use the machine stack for Erlang code (mainly + OpenBSD and Linux with musl).

- The runtime system could call select() with a too - large timeout value when executing on MacOS. This could - in turn cause the runtime system to crash.

+ Own Id: OTP-18561

+
+ +

Constructing a binary segment not aligned with a byte + boundary, with a size not fitting in 31 bits, and with a + value not fitting in a 64-bit word could crash the + runtime system.

- Own Id: OTP-17735 Aux Id: GH-5339

+ Own Id: OTP-18597

+
+
+ + +
Improvements and New Features + -

The fix for Linux's behaviour when reconnecting an - UDP socket in PR-5120 released in OTP-24.1.2 has been - refined to only dissolve the socket's connection before a - connect if the socket is already connected, that is: only - for a reconnect.

This allows code to open a - socket with an ephemeral port, get the port number and - connect; without the port number changing (on Linux). - This turned out to have at least one valid use case - (besides test cases).

Should one reconnect the - socket then the port number may change, on Linux; it is a - known quirk, which can be worked around by binding to a - specific port number when opening the socket. If you can - do without an ephemeral port, that is...

- Own Id: OTP-17736 Aux Id: GH-5279, PR-5120, OTP-17559

-
- -

Certain distributed signals that for various reasons - must to be forced into the distribution buffer even when - it is full would instead be lost if the distribution - buffer was full when sent. The effected signals:

- EXIT signals with exit reasons of one - word size. DOWN signals with exit - reasons of one word size. demonitor - signals from a terminating process. - unlink_ack signals on OTP 23 and 24. - spawn_reply signals on OTP 23 and 24. - + Further robustify implementation of large maps (> 32 + keys). Keys that happen to have same internal 32-bit hash + values are now put in collision nodes which are traversed + with linear search. This removes the demand for the + internal hash function when salted to eventually produce + different hashes for all possible pairs of unequal terms.

- Own Id: OTP-17737 Aux Id: GH-5346, GH-4989

+ Own Id: OTP-18569

-
Erts 12.1.4 +
Erts 13.2.2
Fixed Bugs and Malfunctions

- Fix bug where a gen_tcp write error that happened during - a delayed_send would cause a use after free segfault.

-

- Own Id: OTP-17731 Aux Id: PR-5285

-
- -

- Fix x86 JIT bug where a rem instruction could - cause a segfault if given values that would cause an - badarith exception.

+ If a runtime system which was starting the distribution + already had existing pids, ports, or references referring + to a node with the same nodename/creation pair that the + runtime system was about to use, these already existing + pids, ports, or references would not work as expected in + various situations after the node had gone alive. This + could only occur if the runtime system was communicated + such pids, ports, or references prior to the distribution + was started. That is, it was extremely unlikely to happen + unless the distribution was started dynamically and was + even then very unlikely to happen. The runtime system now + checks for already existing pids, ports, and references + with the same nodename/creation pair that it is about to + use. If such are found another creation will be chosen in + order to avoid these issues.

- Own Id: OTP-17732 Aux Id: PR-5331 ERIERL-664

+ Own Id: OTP-18570 Aux Id: PR-7190

-
Erts 12.1.3 +
Erts 13.2.1
Fixed Bugs and Malfunctions +

Fixed a bug in the loader that prevented certain + modules compiled with no_ssa_opt from being + loaded.

- Reduction counter was not updated before and after doing - apply operations on the runtime system with the - jit enabled. This caused reduction counting to get out of - sync if a garbage collection was made as part of the - apply operation.

-

- Own Id: OTP-17675

+ Own Id: OTP-18519 Aux Id: GH-7024

- This fixes a bug in erts_factory_undo that caused - the heap to not be reset correctly. The - erts_factory_undo function is, for example, called - when a binary_to_term/1 call fails to reset the - heap to its state before the binary_to_term/1 - call. This can cause the heap to contain invalid terms - which potentially can cause issues (e.g., crashes) when - the whole heap is scanned.

+ Implementations of the call() + driver callback that returned a faulty encoded result + could cause a memory leak and could cause invalid data on + the heap of the processes calling erlang:port_call/3.

- Own Id: OTP-17677

+ Own Id: OTP-18525 Aux Id: PR-7049

-

When attempting to construct a binary with an segment - having an illegal type for the size (e.g. an atom), there - could be an unnecessary memory allocation (and subsequent - deallocation) before the operation failed. Amended to - fail before allocating any memory for the binary.

+

Fixed a memory corruption issue when upgrading code. + The bug was introduced in OTP 25.3

- Own Id: OTP-17686

+ Own Id: OTP-18553

-

Fix bug in persistent_term when a key-value - pair contains a magic reference that is referred more - than once. Magic references are NIF resources or returned - from BIFs like ets:new, atomics:new. The - bug could cause the memory of the referred resource to be - prematurely deallocated.

The bug also apply to - magic references in message passing on a runtime built - with configure option - --enable-sharing-preserving.

Bug exist for - 64-bit since OTP-24.0 and for 32-bit since OTP-20.0.

+

Fixed configure tests for a few ARM-specific + instructions, which prevented the emulator from being + built on some platforms.

- Own Id: OTP-17700 Aux Id: GH-5271, PR-5273

+ Own Id: OTP-18554

-

Fixed a crash when inspecting the stack trace of an - exception raised at a very high line number.

-

This bug was introduced in OTP 24.

- Own Id: OTP-17712

+ Aliases created in combination with a monitor using the + {alias, explicit_unalias} option stopped working + from remote nodes when a 'DOWN' signal had been + received due to the monitor or if the monitor was removed + using the erlang:demonitor() BIF.

+

+ This bug was introduced in OTP 24.3.4.10 and OTP 25.3.

+

+ Own Id: OTP-18557 Aux Id: PR-7131, OTP-18496

-

The following two bugs that caused - erlang:demonitor() to behave erroneously have been - fixed. The bugs were only triggered if the monitor that - was removed by demonitor() had previously been - created simultaneously as a monitor and as an alias.

- A demonitor operation on a monitor created - using the {alias, reply_demonitor} option - erroneously behaved as if the {alias, - explicit_unalias} option had been used. - A demonitor operation did not prevent a - corresponding 'DOWN' message from being delivered - if the monitor reference was kept as an active alias - after the operation. This could only occur if the - monitored process simultaneously terminated before the - demonitor signal reached it, and the exit reason was not - an immediate term. That is, a term larger than one - machine word. +

In rare circumstances, bit syntax matching of an + invalid code point for a utf32 would crash the + runtime system.

- Own Id: OTP-17722 Aux Id: GH-5310, PR-5313

+ Own Id: OTP-18560

-
-
- -
- -
Erts 12.1.2 - -
Improvements and New Features -

- The python scripts that existed in - erts/lib_src/yielding_c_fun/lib/tiny_regex_c/scripts had - a license that was incompatible with Erlang/OTP's - license. This ticket removes these scripts that were not - used by us.

+ Building the runtime system failed when native atomic + support was missing. Note that execution on such systems + have only been rudimentary tested.

- Own Id: OTP-17658

+ Own Id: OTP-18563 Aux Id: GH-7114, PR-7159

-
Erts 12.1.1 +
Erts 13.2
Fixed Bugs and Malfunctions +

Fixed a bug on Windows where + file:read_file_info/1 would fail for files with + corrupt metadata.

- A race between an exiting port and handling of - simultaneously received signals to that port could cause - a runtime system crash. The effected signals are - link, monitor and demonitor. On OTP - 22 a similiar race could also cause a memory leak when - receiving an unlink signal.

-

- Own Id: OTP-17642 Aux Id: PR-5248

+ Own Id: OTP-18348 Aux Id: GH-6356

- A user defined tag - on a monitor message could cause the runtime - system to crash when the monitor message had been - received.

+ Fix process_info(_, binary) to again include + "writable binaries" which were lost in OTP-25.0. Writable + binaries are an optimization used when binaries are + appended upon in a loop.

- Own Id: OTP-17646 Aux Id: GH-5221, PR-5232

+ Own Id: OTP-18373 Aux Id: PR-6574, GH-6573

- A call to erlang:demonitor(Ref) - where the reference Ref referred to an active - alias, but not an active monitor, caused the runtime - system to crash.

+ Fix rare race when receiving fragmented messages on a + terminating connection. Could potentially cause memory + leaks as well as double free crashes. Bug exists since + OTP 22.0.

- Own Id: OTP-17647 Aux Id: GH-5225, PR-5230

+ Own Id: OTP-18382 Aux Id: PR-6585

- The message queue of a process entered an inconsistent - state after a receive expression with an invalid - timeout value was executed. If the exception raised due - to the invalid timeout value was caught, the following - receive expression executed by the process could - fail to match messages already present in the message - queue.

-

- On OTP 24 this could also cause the whole runtime system - to crash.

+ Fixed bug that could maybe cause problems when a file + descriptor number is closed by a linked in driver and + then opened (reused) and passed to enif_select by + a NIF. No actual symptoms seen, only failed internal + assertions in debug build.

- Own Id: OTP-17651 Aux Id: GH-5235, PR-5244

+ Own Id: OTP-18391

- Sending a Port ! {PortOwner, close} signal from a - process other than the port owner could erroneously - trigger a badsig exit signal being sent to the - port owner process even though the correct - PortOwner had been passed in the signal.

+ The runtime system could crash when tracing a process + executing on a dirty scheduler.

- Own Id: OTP-17665 Aux Id: PR-5248

+ Own Id: OTP-18398 Aux Id: PR-6495, GH-6448, GH-5984

-
-
- -
- -
Erts 12.1 - -
Fixed Bugs and Malfunctions - -

Atoms with Unicode code points greater than 255 (for - example Greek or Cyrillic characters) would not be - displayed correctly by crashdump_viewer.

+

In the binary syntax, attempting to match out integers + with size exceeding 2 GiB could crash the runtime + system.

- Own Id: OTP-17377

+ Own Id: OTP-18406 Aux Id: GH-6701

+

Fixed edge case in floating-point negation where A + = 0.0, B = -A did not produce B = -0.0 on + x86_64 JIT.

- Fix rare minor memory leak related to jit code loading.

-

- Own Id: OTP-17445 Aux Id: PR-4843

+ Own Id: OTP-18411 Aux Id: GH-6717

-

The extended error information has been corrected and - improved for the following BIFs: - binary_to_existing_atom/2, - list_to_existing_atom/1, - erlang:send_after/{3,4}, and - erlang:start_timer/{3,4}.

+

Fixed an issue in the JIT that could crash the + emulator on some platforms.

- Own Id: OTP-17449 Aux Id: GH-4900

+ Own Id: OTP-18418

- Fix bug provoked when building with gcc 10 and link time - optimization (-flto), causing Erlang compiler to crash. - Bug exists since OTP-24.0.

+ Added meta data to the windows installer.

- Own Id: OTP-17477 Aux Id: GH-4846, PR-4894

+ Own Id: OTP-18429 Aux Id: PR-6587 GH-4232 GH-6537

-

Corrected bugs where builds were not reducible even - when the deterministic option was given. In - particular, modules with map literals with more than 32 - elements could cause this problem.

-

As part of this fix, the term_to_binary BIF now - accepts the option deterministic.

+

Fixed ETS insertion order into bag and + duplicate_bag of tuples with identical keys when + passed in a list to ets:insert/2. The insert order + has been head-to-tail but was accidentally changed in OTP + 23.0. For bag it was reverted (tail-to-head), + while for duplicate_bag it was sometimes reverted + depending on the length of the list and number of + "reductions" left for the calling process.

This + fix changes the insert order of ets:insert/2 back + to always be head-to-tail of the list argument.

- Own Id: OTP-17495 Aux Id: PR-5153

+ Own Id: OTP-18434 Aux Id: PR-6752

-

After an exception has been caught in a process, the - stack trace would be kept in the process longer than - necessary.

+

With the JIT for AArch64 (AMD64), calling bxor + in with non-integer arguments in a guard would crash the + runtime system.

- Own Id: OTP-17512

+ Own Id: OTP-18454 Aux Id: PR-6839

- Fix rare race bug in memory management of distribution - entries. Have been seen to cause VM crash when massive - number of repeated concurrent failing connection - attempts.

+ Fix bug regarding process flag max_heap_size. + Could cause strange behavior when a process was killed + due to exceeding the limit.

- Own Id: OTP-17513 Aux Id: GH-4964, PR-5015

+ Own Id: OTP-18457 Aux Id: PR-6816

- The configure test for - --disable-esock-socket-registry has been corrected - so disabling now works.

+ Fixed binary comprehensions to be similar to other + creation of binary data with respect to its contribution + of triggering garbage collection.

- Own Id: OTP-17539

+ Own Id: OTP-18458

-

init:stop() no longer unloads loaded code - before terminating the runtime system. On systems with - slow CPUs (such as Raspberry PI Zero), that can - significantly speed up termination of the runtime - system.

+

In rare circumstances, when a process exceeded its + allowed heap size set by option max_heap_size, it + would not be killed as it should be, but instead enter a + kind of zombie state it would never get out of.

- Own Id: OTP-17542 Aux Id: GH-5031, PR-5032

+ Own Id: OTP-18463 Aux Id: PR-6858

+

Instead of crashing, the list_to_integer/1 and + list_to_integer/2 BIFs now raise the + system_limit exception for overlong lists that + can't be converted to integers. Similarly, the + string:to_integer/1 BIF now returns + {error,system_limit} for overlong lists.

- Fixed match specifications that use maps in either the - guard or the body to work properly.

+ Own Id: OTP-18475 Aux Id: PR-6897

+
+

- With this fix both keys and values in maps can be - expressions.

+ Active process aliases of a process at its termination + leaked memory.

- Various other crashes and bugs when using maps in match - specifications have also been fixed.

-

- Own Id: OTP-17567 Aux Id: PR-4915 PR-5115

+ Own Id: OTP-18496 Aux Id: GH-6947, PR-6953

+
+
+ + +
Improvements and New Features +

- Parsing of the result value in the native DNS resolver - has been made more defensive against incorrect results.

+ Support for fully asynchronous distributed signaling + where send operations never block. This + functionality is by default disabled and can be enabled + per process. For more information see the documentation + of process_flag(async_dist, + Bool).

- Own Id: OTP-17578 Aux Id: ERIERL-683

+ Own Id: OTP-18374 Aux Id: PR-6632

-

When binary_to_term/2 failed, the extended - error information would always blame the second argument - even if the actual error was in the first argument.

+

Added the +JPperf no_fp option to explicitly + disable Erlang frame pointers otherwise added when using + the +JPperf map option.

- Own Id: OTP-17591 Aux Id: GH-5171

+ Own Id: OTP-18426

+
+
+ +
+ +
Erts 13.1.5 + +
Fixed Bugs and Malfunctions + -

On 32-bit computers, binary_to_term/1,2 is now - more resilient against corrupted binaries containing maps - in the external format.

+

Comparisons between small numbers and pids or ports + would in some edge cases say that the number was greater + than the pid or port, violating the term order.

- Own Id: OTP-17604

+ Own Id: OTP-18415

- A call to process_info(Pid, status) could - erroneously report the status running when it - should have reported waiting. This occurred when - the calling process was executing on a higher priority - than the process being inspected. This bug has been - present since OTP 21.0 (erts version 10.0).

+ process_info(Pid, status) when Pid /= + self() could return an erroneous result.

- Own Id: OTP-17628

+ Own Id: OTP-18421 Aux Id: PR-6806

+
+ +
Erts 13.1.4 -
Improvements and New Features +
Fixed Bugs and Malfunctions +

Fixed a bug in selective receive optimization that + could crash 32-bit emulators.

- Optimize memory usage of erts internal processes used - during code loading/purging by hibernating them after a - long time of inactivity.

-

- Own Id: OTP-17426 Aux Id: PR-4785

+ Own Id: OTP-18383 Aux Id: ERIERL-905

- Add the type erlang:stacktrace/0.

+ A race condition which was very rarely triggered could + cause the signal queue of a process to become + inconsistent causing the runtime system to crash.

- Own Id: OTP-17453 Aux Id: PR-4764

+ Own Id: OTP-18388 Aux Id: OTP-17462, PR-6662

+
+
+ +
+ +
Erts 13.1.3 + +
Fixed Bugs and Malfunctions +

- The arity argument of error/2,3 - can now be none to indicate that the calling - functions arity should be used.

+ Fix perf/gdb JIT symbols to not contain + CodeInfoPrologue for the JIT internal module + erts_beamasm.

- Own Id: OTP-17456 Aux Id: PR-4764

+ Own Id: OTP-18256 Aux Id: PR-6316

- Optimize match spec compiler for immediate (single word) - constant terms.

+ Fixed minor memory leaks.

- Own Id: OTP-17469

+ Own Id: OTP-18281 Aux Id: PR-4840

-

Functions erlang:set_cookie(Cookie) and - erlang:get_cookie(Node) have been added for - completeness and to facilitate configuring distributed - nodes with different cookies.

The documentation - regarding distribution cookies has been improved to be - less vague.

+

Fix bugs in ets:insert and + ets:insert_new when called with a list of tuples + to insert while a concurrent process either deletes or + renames the table. The table deletion could be done with + ets:delete/1 or be caused by termination of the + table owning process.

Symptoms are either VM crash + or strange incorrect behavior from the insert operation. + The risk of triggering the bugs increases with the length + of the list of tuple to insert. Bugs exist since OTP + 23.0.

- Own Id: OTP-17538 Aux Id: GH-5063, PR-5111

+ Own Id: OTP-18284 Aux Id: PR-6305

-

A workaround has been implemented for Linux's quirky - behaviour to not adjust the source IP address when - connecting a connected (reconnecing) UDP socket.

- The workaround is to, on Linux, always dissolve any - connection before connecting an UDP socket.

- Own Id: OTP-17559 Aux Id: GH-5092, PR-5120

+ Boost execution of scheduled thread progress jobs. This + to prevent memory exhaustion in extremely rapid + allocation/deallocation scenarios, such as repeated ETS + table creations/deletions.

+

+ Own Id: OTP-18294 Aux Id: PR-6390

- The internal documentation for how to use Yielding C Fun - (YCF) has been updated to contain text about best - practices for using YCF for ERTS.

+ Fix segv crash during crash dumping an ETS table doing + ets:delete_all_objects.

- Own Id: OTP-17596

+ Own Id: OTP-18295

- Optimize garbage collection for processes with large - number of binaries, funs and/or external pids/ports/refs.

+ Spec for function net:if_names/0 incorrect

- Own Id: OTP-17602 Aux Id: PR-5149

+ Own Id: OTP-18296 Aux Id: OTP-16464

-
-
- -
- -
Erts 12.0.4 - -
Fixed Bugs and Malfunctions -

- A call to the process_info() BIF could end up - hanging for ever due to a bug introduced when the new - selective receive optimization was introduced in OTP - 24.0. Note that this bug only effects - process_info().

+ Fix bug in binary_to_term decoding a binary term + 2Gbyte or larger.

- Own Id: OTP-17548 Aux Id: PR-5078, OTP-10391

+ Own Id: OTP-18306 Aux Id: GH-6393, PR-6401

+

Documentation of erlang:module_loaded/1 + has been adjusted:

It did not previously + say that the BIF only returns true for modules + loaded as current code. The warning + claiming that the BIF should only be used by the code + server has been removed.

- Fix buffer overrun problem in the tty driver. The problem - happens on some platforms when using the CTRL+R - functionality of newshell with very long strings in the - history.

+ Own Id: OTP-18313 Aux Id: PR-6456

+
+

- Own Id: OTP-17560 Aux Id: GH-5116

+ Fix list_to_atom/1 for negative code points. Could + either return with a positive code point or fail with an + incorrect exception.

+

+ Own Id: OTP-18321

+

Fix rare bug causing VM crash when sending to a pid of + a spawning process returned from + erlang:processes/0.

Only seen when provoked + by system process literal_area_collector, triggered by a + module purge operation, on a VM started with +Meamin (no + customized allocators).

- Fix race-condition that could cause a crash when tracing - scheduling or garbage collections on a process that was - running on a dirty scheduler.

+ Own Id: OTP-18322 Aux Id: PR-6479

+
+

- Own Id: OTP-17568 Aux Id: PR-4940

+ gen_udp:open/2 with option(s) add_membership or + drop_membership would drop earlier options.

+

+ Own Id: OTP-18323 Aux Id: #6476

- Fix rare bug where re:run would crash/return invalid - results when given a subbinary as subject.

+ The inet:setopts/2 + {reuseaddr, true} option will now be ignored on + Windows unless the socket is an UDP socket. For more + information see the documentation of the reuseaddr + option part of the documentation of + inet:setopts/2.

+

+ Prior to OTP 25 the {reuseaddr, true} option was + ignored for all sockets on Windows, but as of OTP 25.0 + this was changed so that it was not ignored for any + sockets.

- This bug has existed since Erlang/OTP 20.0.

+ *** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-17585 Aux Id: GH-5150

+ Own Id: OTP-18324 Aux Id: GH-6461, PR-6481

-

binary_to_term/1,2 is now more resilient - against corrupted binaries containing maps in the - external format.

- Own Id: OTP-17594

+ Fix bug in binary_to_term decoding a list of + length 1G or longer.

+

+ Own Id: OTP-18328 Aux Id: GH-6439, PR-6440

+
+ +

Fix bug in binary_to_term (and distributed + receive) when decoding a large map (>32 keys) with + unsorted small maps (<= 32) as keys of the large + map.

+

This was only a problem if the term was encoded by + erl_interface, jinterface or otherwise, as + the VM itself always encodes small maps with sorted + keys.

+

The "binary_to_term" would appear as successful but + the created large map was internally inconsistent. The + smaller key-maps could not be found with maps:get and + friends. Other operations such as map compare and merge + could probably also give incorrect results.

+

+ Own Id: OTP-18343 Aux Id: GH-6496

+
+ +

+ Fix Windows bug in open_port({spawn, Command}, ..) + when Command is found via the OS search PATH and + that directory path contains white spaces. The port + program would start but the command line arguments to it + could be incorrect.

+

+ Own Id: OTP-18345 Aux Id: GH-6387, PR-6396

-
Erts 12.0.3 +
Erts 13.1.2.1
Fixed Bugs and Malfunctions +

Fixed a bug in selective receive optimization that + could crash 32-bit emulators.

- A call to erlang:cancel_timer(_, [{info, false}]) - could cause the calling process to block forever in the - call. Note that only the synchronous version of the call - (that is, the async option is false) in - combination with the info option set to - false was effected by this bug.

-

- Own Id: OTP-17472 Aux Id: PR-4932

+ Own Id: OTP-18383 Aux Id: ERIERL-905

- Microstate accounting (msacc) and - os:perf_counter() unintentionally used system time - instead of monotonic time for time measurements on a lot - of systems. These systems were all non x86/x86_64 systems - or x86/x86_64 systems without a reliable and constant - rdtsc instruction.

-

- The lock counting (lcnt) built runtime system also - unintentionally used system time instead of monotonic - time for time measurements on all systems.

+ A race condition which was very rarely triggered could + cause the signal queue of a process to become + inconsistent causing the runtime system to crash.

- Own Id: OTP-17493

+ Own Id: OTP-18388 Aux Id: OTP-17462, PR-6662

+
+
+ +
+ +
Erts 13.1.2 + +
Fixed Bugs and Malfunctions +

- Simultaneous calls to - erlang:system_flag(schedulers_online, _) could - cause callers to end up in a suspended state forever.

+ Add abandon carrier free utilization limit + (+Muacful) option to erts_alloc. This option + allows the user to mark unused segments in a memory + carrier as re-useable by the OS if needed.

- Own Id: OTP-17500 Aux Id: GH-4809

+ This functionality was a non-configurable default before + Erlang/OTP 25, but removed due to performance issues.

+

+ Own Id: OTP-18290 Aux Id: ERIERL-866 PR-6378

-
Erts 12.0.2 +
Erts 13.1.1
Fixed Bugs and Malfunctions

- Not yet handled alias-message signals in the signal queue - at the time when a garbage collection was performed could - cause a memory corruption which in turn could result in a - crash of the runtime system. This bug was introduced in - OTP 24.0.

+ Listen sockets created with the socket module, leaked + (erlang-) monitors.

- Own Id: OTP-17431 Aux Id: GH-4858, PR-4870, OTP-16718

+ Own Id: OTP-18240 Aux Id: #6285

- Fixed bug when using external pids/ports in keys of big - maps (> 32). Could cause runtime crash. Bug exists since - OTP 24.0.

+ Notifications + about available distribution data sent to + distribution controller processes could be lost. + Distribution controller processes can be used when + implementing an alternative distribution carrier. The + default distribution over tcp was not effected and the + bug was also not present on x86/x86_64 platforms.

- Own Id: OTP-17436 Aux Id: PR-4875

+ Own Id: OTP-18258 Aux Id: GH-6309, PR-6324

+
+
+ +
+ +
Erts 13.1 + +
Fixed Bugs and Malfunctions + -

After a node restart with init:restart/0,1, - the module socket was not usable because - supporting tables had been cleared and not - re-initialized. This has now been fixed.

Handling - of the "." domain as a search domain was incorrect and - caused a crash in the DNS resolver inet_res, which - has now been fixed.

- Own Id: OTP-17439 Aux Id: GH-4827, PR-4888, GH-4838

+ Fixed inconsistency bugs in global due to + nodeup/nodedown messages not being + delivered before/after traffic over connections. Also + fixed various other inconsistency bugs and deadlocks in + both global_group + and global.

+

+ As building blocks for these fixes, a new BIF erlang:nodes/2 + has been introduced and net_kernel:monitor_nodes/2 + has been extended.

+

+ The -hidden and + -connect_all + command line arguments did not work if multiple instances + were present on the command line which has been fixed. + The new kernel parameter connect_all + has also been introduced in order to replace the + -connect_all command line argument.

+

+ Own Id: OTP-17934 Aux Id: PR-6007

- A call to port_command() could cause a scheduler - to end up in an eternal loop if the port was busy and the - calling process had incoming signals at the time of the - call. This bug was introduced in OTP 23.3.2 (ERTS version - 11.2.1), OTP 22.3.4.18 (ERTS version 10.7.2.10), and OTP - 21.3.8.23 (ERTS version 10.3.5.18).

-

- Own Id: OTP-17448 Aux Id: GH-4898, PR-4903, OTP-17291

-
- -

Bug fixes and code cleanup for the new socket - implementation, such as:

Assertions on the result - of demonitoring has been added in the NIF code, where - appropriate.

Internal state handling for socket - close in the NIF code has been reviewed.

Looping - over close() for EINTR in the NIF code has - been removed, since it is strongly discouraged on Linux - and Posix is not clear about if it is allowed.

- The inet_backend temporary socket option for - legacy gen_tcp sockets has been documented. -

The return value from net:getaddrinfo/2 - has been corrected: the protocol field is now an - atom(), instead of, incorrectly, - list(atom()). The documentation has also been - corrected about this return type.

Deferred close - of a socket:sendfile/* file was broken and has - been corrected.

Some debug code, not enabled by - default, in the socket NIF has been corrected to not - accidentally core dump for debug printouts of more or - less innocent events.

+ Fixed IPv6 multicast_if and membership socket options.

- Own Id: OTP-17452

+ Own Id: OTP-18091 Aux Id: #5789

- Dirty execution of a process in combination with an - unlink signal from a port to the process could cause the - signal queue of the process to enter into an inconsistent - state. The result of the inconsistency typically caused a - crash of the runtime system. This bug was introduced in - OTP 23.3 (ERTS version 11.2).

+ Accept funs (NEW_FUN_EXT) with incorrectly encoded size + field. This is a workaround for a bug (OTP-18104) + existing in OTP 23 and 24 that could cause incorrect size + fields in certain cases. The emulator does not use the + decoded size field, but erl_interface still does + and is not helped by this workaround.

- Own Id: OTP-17462 Aux Id: GH-4885, PR-4914, OTP-17127

+ Own Id: OTP-18093 Aux Id: OTP-18104, PR-5987

-
-
- -
- -
Erts 12.0.1 - -
Fixed Bugs and Malfunctions -

- Commit of generated configure script.

+ Fixed issue with inet:getifaddrs hanging on pure IPv6 + Windows

- Own Id: OTP-17420 Aux Id: OTP-17398, GH-4821

+ Own Id: OTP-18102 Aux Id: #5904

-
-
- -
- -
Erts 12.0 - -
Fixed Bugs and Malfunctions - +

Fix faulty distribution encoding of terms with + either

a fun with bit-string or + export-fun in its environment when encoded toward a not + yet established (pending) connection or a + fun with a binary/bitstring, in its environment, + referring to an off-heap binary (larger than 64 + bytes).

The symptom could be failed + decoding on the receiving side leading to aborted + connection. Fix OTP-18093 is a workaround for theses bugs + that makes the VM accepts such faulty encoded funs.

+

The first encoding bug toward pending connection + exists only in OTP 23 and 24, but the second one exists + also on OTP 25.

- file:open/2 now throws an badarg error when opened - with both the ram and raw options.

-

- Own Id: OTP-16822 Aux Id: PR-2723

+ Own Id: OTP-18104 Aux Id: OTP-18093

- The estone benchmark has been updated to better reflect - changes in the compiler and run-time system.

+ Fixed emulator crash that could happen during crashdump + generation of ETS tables with options ordered_set + and {write_concurrency,true}.

- Own Id: OTP-16879

+ Own Id: OTP-18144 Aux Id: GH-5981

- Fix profile guided optimization of run-time system when - using GCC 7 or later.

+ Retrieval of monotonic and system clock resolution on + MacOS could cause a crash and/or erroneous results.

- Own Id: OTP-16880

+ Own Id: OTP-18160 Aux Id: PR-6103

- Fix double close of fd when creating crash dump.

+ Fix bug where the max allowed size of erl +hmax + was lower than what was allowed by process_flag.

- Own Id: OTP-16884

+ Own Id: OTP-18161 Aux Id: PR-6081

+

On computers with ARM64 (AArch64) processors, the JIT + could generate incorrect code when more than 4095 bits + were skipped at the tail end of a binary match.

- Improve erl error message when unable to open - included args_file.

-

- Own Id: OTP-17014

+ Own Id: OTP-18201

+

In rare circumstances, an is_binary/1 guard + test could succeed when given a large integer.

- Remove warning text about the -- operation from - documentation

-

- The -- operation was optimized in Erlang/OTP 22 so - that its worst case complexity is O(N*log(N)), where N is - the total size of the input lists. Therefore, the warning - in the documentation saying that the time complexity is - proportional to length(A)*length(B) is incorrect and is - no longer needed. Notice that Erlang/OTP 21 will no - longer be supported when Erlang/OTP 24 gets released.

-

- Own Id: OTP-17020

+ Own Id: OTP-18216 Aux Id: GH-6239, PR-6240

- A floating point zero (0.0) can be both positive (+0.0) - and negative (-0.0). Multiple bugs in the compiler, - runtime system, and STDLIB have been fixed to ensure that - the minus sign on 0.0 is not lost.

+ Fix bug causing ets:info (and sometimes + ets:whereis) to return 'undefined' for an existing + table if a concurrent process were doing + ets:insert with a long list on the same table.

- Own Id: OTP-17077 Aux Id: ERL-1431, PR-2903, PR-2905, - PR-2906

+ Own Id: OTP-18218 Aux Id: ERIERL-855

- Fix compiler warnings produced by the clang compiler.

+ Fix writing and reading of more than 2 GB in a single + read/write operation on macOS. Before this fix attempting + to read/write more than 2GB would result in + {error,einval}.

- Own Id: OTP-17105 Aux Id: PR-2872

+ Own Id: OTP-18222 Aux Id: PR-6248 GH-6242

- Windows process erl.exe killed if its service - process erlsrv.exe terminates.

+ Fix bug sometimes causing emulator crash at node shutdown + when there are pending connections. Only seen when + running duel distribution protocols, inet_drv and + inet_tls_dist.

- Own Id: OTP-17131 Aux Id: PR-3031, GH-4360

+ Own Id: OTP-18243 Aux Id: GH-6247, PR-6258

+
+
+ + +
Improvements and New Features + -

The configure scripts in crypto and - erts now fail if a requested feature cannot be - enabled.

Large parts of the configure - script of crypto have been rewritten with various - improvements and bug fixes. It is now better at finding - usable OpenSSL libraries, but will in the following cases - fail to detect OpenSSL libraries where it previously - sometimes detected the libraries by chance:

- OpenSSL installations with include - directory and lib directory parts installed in - different base directories. In order to detect such - installations after this change, the user must explicitly - specify the locations using the --with-ssl=<path> - and the --with-ssl-incl=<path> - configure command line arguments. - When building with old gcc compilers or other - compilers on Debian derivatives with multiarch - directories under the lib directory. In order to - detect such installations after this change, the user - must explicitly specify the multiarch directory name - using the --with-ssl-lib-subdir=lib/<multiarch-dir> - configure command line argument. +

Yield when adjusting large process message queues due + to

copying terms from a literal area + prior to removing the literal area.

+

changing the message_queue_data state + from on_heap to off_heap.

+

The message queue adjustment work will now be + interleaved with all other types of work that processes + have to do, even other message queue adjustment work.

- Own Id: OTP-17254 Aux Id: ERIERL-618, GH-4230

+ Own Id: OTP-17340 Aux Id: PR-6133

- The erl command line arguments +Bi, - +Bd, and +B erroneously caused reception of - the USR1 signal to terminate the runtime system - without creating a crash dump. Reception of the - USR1 signal now always cause termination - with creation of a crash dump, regardless of - command line arguments passed. This bug has existed at - least since OTP R5B.

-

- *** POTENTIAL INCOMPATIBILITY ***

+ Add rudimentary debug feature (option) for the + inet-driver based sockets, such as gen_tcp and gen_udp.

- Own Id: OTP-17275 Aux Id: PR-4553

+ Own Id: OTP-18032

- Add check to make sure that when passing an option to - erl that requires an argument, but none is given, - we report an error. This fixes a bug introduced in - OTP-22.1 via OTP-15926.

+ Introduced the hidden and dist_listen + options to net_kernel:start/2.

- Own Id: OTP-17314 Aux Id: OTP-15926, GH-4624, PR-

+ Also documented the -dist_listen + command line argument which was erroneously documented as + a kernel parameter and not as a command line + argument.

+

+ Own Id: OTP-18107 Aux Id: PR-6009

- The "Last calls" section in crash dumps have been updated - to print newlines after each non-function - save_calls state (send, receive, timeout).

+ New documentation chapter "Debugging NIFs and Port + Drivers" under Interoperability Tutorial.

- Own Id: OTP-17329 Aux Id: PR-4730

+ Own Id: OTP-18109

- Sockets created with socket:accept not counted - (socket:info/0).

+ Add new API function erl_features:configurable/0

- Own Id: OTP-17372

+ Own Id: OTP-18199 Aux Id: PR-5790

+
+ +
Erts 13.0.4 -
Improvements and New Features +
Fixed Bugs and Malfunctions

- The experimental socket module can now use any - protocol (by name) the OS supports. Suggested in PR-2641, - implemented in PR-2670.

-

- Own Id: OTP-14601 Aux Id: PR-2641, PR-2670, OTP-16749

-
- -

- New functions enif_dynamic_resource_call enables - NIFs to call native code in another NIF module. The call - is done via a resource callback function dyncall - supplied by the user with the new - enif_init_resource_type.

-

- Own Id: OTP-14753

-
- -

- Runtime support for new improved selective receive - optimization.

-

- Own Id: OTP-16226 Aux Id: OTP-10391

-
- -

The deprecated function erlang:get_stacktrace/0 - has been removed. Use the new syntax in try/catch to - retrieve the stack backtrace.

+ The monitor/3 BIF + did not apply options to the created monitor if the + target process or port did not exist. That is, the + corresponding down message would get a `DOWN` tag + even if a custom tag had been set, and the returned + reference was not an alias even if the alias + option had been passed.

- Own Id: OTP-16653

+ Own Id: OTP-18190 Aux Id: GH-6185, PR-6209

- Support for handling abstract code created before OTP R15 - has been dropped.

+ The erlang:monotonic_time/1, + erlang:system_time/1, + erlang:time_offset/1, + and os:system_time/1 + BIFs erroneously failed when passed the argument + native.

- Own Id: OTP-16678 Aux Id: PR-2627

+ Own Id: OTP-18197 Aux Id: GH-6165, PR-6213

+
+
+ +
+ +
Erts 13.0.3 + +
Fixed Bugs and Malfunctions + +

Distributed exit signals could be lost under the + following conditions:

An exit signal + from a parent process to a child process was lost if:

+

the parent process terminated before the + spawn request that created the child had completed, +

the spawn request set up a link + between parent and child

the spawn + request was distributed, and

the + exit reason was larger than one machine word.

+

Loss of a connection over which + a not yet completed spawn request was ongoing could cause + loss of exit signals. Such loss of exit signals was very + rare. Besides the above described connection loss also + the following conditions had to be satisfied:

+

The spawn request that was interrupted by the + connection loss also had to set up a link between the + parent process and the child process.

+

The parent process that issued the spawn + request also had to be terminating while the spawn + request was interrupted by the connection loss. +

The same parent process also had to + have made other spawn requests to other nodes than to the + node to which the connection was lost.

+

These spawn requests to the other nodes also + had to set up links.

These spawn + requests to the other nodes also had to be not yet + completed at the time of the connection loss. That is, + the spawn reply from the child process had not yet + reached the parent process.

If all + the conditions above were met, exit signals to the + children spawned due to the above described spawn + requests to other nodes could be lost.

+

The above bug also caused a significant memory leak + when it was triggered since the destruction of the parent + process never completed.

- Extended error information for failing BIF calls as - proposed in EEP - 54 has been implemented.

-

- When a BIF call from the Erlang shell fails, more - information about which argument or arguments that were - in error will be printed. The same extended error - information will by proc_lib, common_test, - and qlc when BIF calls fail.

+ Own Id: OTP-18164 Aux Id: PR-6114

+
+

- For applications that wish to provide the same extended - error information, there are new functions - erl_error:format_exception/3 and - erl_error:format_exception/4.

+ A race could cause process_info(Pid, + message_queue_len) on other processes to return + invalid results.

- There is a new error/3 BIF that allows - applications or libraries to provide extended error - information in the same way for their own exceptions.

+ Own Id: OTP-18169 Aux Id: PR-6134

+
+

- Own Id: OTP-16686

+ Fixed reduction counting for handling process system + tasks.

+

+ Own Id: OTP-18170 Aux Id: PR-6135

- The erlang module - documentation has been updated to improve clarity and - description of edge cases.

+ Priority elevation of terminating processes did not work + which could cause execution of such processes to be + delayed.

- Own Id: OTP-16687 Aux Id: PR-2996 PR-2762

+ Own Id: OTP-18175 Aux Id: PR-6142

- An example implementation of Erlang distribution over UDS - using distribution processes has been introduced.

+ An unlink operation made by a process that terminated + before the unlink operation completed, i.e., before it + had received an unlink-ack signal from the linked + process, caused an exit signal to erroneously be sent + from the terminating process to the process being + unlinked. This exit signal would most often be ignored by + the receiver, but if the receiver of the exit signal + concurrently set up a new link, it could receive the exit + signal with the actual exit reason of the terminating + process instead of a noproc exit reason. It is + however very hard to detect that this has happened and + has no obvious negative consequences, so it should be + considered harmless.

- Thanks to Jérôme de Bretagne

+ A distributed unlink-ack signal received by a terminating + process was also not properly removed which could cause a + minor memory leak.

- Own Id: OTP-16703 Aux Id: PR-2620

+ Own Id: OTP-18177 Aux Id: PR-6150

+
+
+ +
+ +
Erts 13.0.2 + +
Fixed Bugs and Malfunctions + +

On computers with the ARM64 (AArch64) architecture + (such as Apple Silicon Macs) a rem expression + followed by a div expression with the same + operands could evaluate to the wrong result if the result + of the rem expression was unused.

- Improve code generation when creating funs by adding a - new beam instruction make_fun3 that does not do GC and - allows for better register allocation.

-

- Own Id: OTP-16712

+ Own Id: OTP-18143

+
+
+ +
+ +
Erts 13.0.1 + +
Fixed Bugs and Malfunctions +

- The process - alias feature as outlined by EEP - 53 has been introduced. It is introduced in order - to provide a lightweight mechanism that can prevent late - replies after timeout or connection loss. For more - information, see EEP 53 and the documentation of the new - alias/1 BIF - and the new options to the monitor/3 - BIF.

+ A spawn_reply signal from a remote node could be + delayed and be delivered after other signals from the + newly spawned process.

- The call operation in the framework used by - gen_server, gen_statem, and - gen_event has been updated to utilize alias in - order to prevent late responses. The gen_statem - behavior still use a proxy process in the distributed - case, since it has always prevented late replies and - aliases wont work against pre OTP 24 nodes. The proxy - process can be removed in OTP 26.

+ When this bug triggered, the connection to the node where + the process was spawned sometimes could be taken down due + to the bug. The following error message would then be + logged if this happened: Missing 'spawn_reply' signal + from the node <RemoteNode> detected by <Pid> + on the node <LocalNode>. The node + <RemoteNode> probably suffers from the bug with + ticket id OTP-17737.

- The alias feature also made it possible to introduce new - functions similar to the erpc:receive_response() - function in the gen behaviors, so the new functions - gen_server:receive_response(), - gen_statem:receive_response(), - gen_event:receive_response() - have also been introduced.

+ This bug only affected processes which had enabled + off_heap + message_queue_data and parallel reception + of signals had been automatically enabled.

- Own Id: OTP-16718 Aux Id: PR-2735

+ This bug was introduced in OTP 25.0, ERTS version 13.0.

+

+ Own Id: OTP-18105 Aux Id: OTP-16982, PR-6003

- Accept 64-bit process identifiers from external nodes. - This is the first step in an upgrade path toward using - 64-bit pids in a future OTP release.

+ Fixed type spec of erlang:system_info(dist_ctrl).

- Own Id: OTP-16720 Aux Id: PR-2680

+ Own Id: OTP-18106 Aux Id: PR-5992

-

The experimental new socket API has been further - developed. Some backwards incompatible changes with - respect to OTP 23 have been made.

The control - message format has been changed so a decoded value is now - in the 'value' field instead of in the 'data' field. The - 'data' field now always contains binary data.

- Some type names have been changed regarding message - headers and control message headers.

- socket:bind/2 now returns plain ok instead - of {ok, Port} which was only relevant for the - inet and inet6 address families and often - not interesting. To find out which port was chosen use - socket:sockname/1.

- *** POTENTIAL INCOMPATIBILITY ***

+ The zlib built in to the runtime system has been updated + to version 1.2.12. (Note that on most platforms, the + platform's own zlib is used.)

- Own Id: OTP-16749 Aux Id: OTP-14601

+ Own Id: OTP-18123 Aux Id: GH-5994

- Remove old unused +MYm and ERL_MALLOC_LIB - options.

+ The erlang:is_alive() BIF could return true + before configured distribution service was available. + This bug was introduced in OTP 25.0 ERTS version 13.0.

- Own Id: OTP-16788

+ The erlang:monitor_node() and + erlang:monitor() BIFs could erroneously fail even + though configured distribution service was available. + This occurred if these BIFs were called after the + distribution had been started using dynamic node name + assignment but before the name had been assigned.

+

+ Own Id: OTP-18124 Aux Id: OTP-17558, PR-6032

+
+
+ +
+ +
Erts 13.0 + +
Fixed Bugs and Malfunctions +

- Increase timer resolution on windows.

+ The socket option 'reuseaddr' is *no longer* ignored on + Windows.

- Own Id: OTP-16814 Aux Id: PR-2704

+ Own Id: OTP-17447 Aux Id: GH-4819

- The code loader has been rewritten in order to be able to - load JIT:ed code. As a consequence of this, it is no - longer possible to load HiPE code.

+ The growth rate of writable binaries has been adjusted to + only increase by 20% after 16MB in size. Before this + change the size would always double.

+

+ This change may degrade write performance of large + binaries.

*** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-16878

+ Own Id: OTP-17569 Aux Id: PR-4793

- Add support in the Erlang/OTP build system to generate a - compilation database that can be used by third-party - tools (such as irony in Emacs) to compile the erts C and - C++ source code. Create the database using make - compdb.

+ Fix reduction counting bug in re:run that caused + the function to yield too frequently when doing + global matches.

- Own Id: OTP-16881

+ Own Id: OTP-17661 Aux Id: PR-5165

- The BeamAsm JIT-compiler has been added to Erlang/OTP. - The JIT-compiler is enabled by default on most x86 64-bit - platforms that have a C++ compiler that can compile - C++17. To verify that a JIT enabled emulator is running - you can use erlang:system_info(emu_flavor).

-

- For more information see the internal documentation of BeamAsm in - erts.

+ Fix spelling mistakes in epmd error messages.

- Own Id: OTP-16885 Aux Id: PR-2745

+ Own Id: OTP-17758 Aux Id: PR-5391

- By default all ERTS internal memory allocators based on - alloc_util will now use their own separate carrier - pool for migration of carriers instead of using a node - global carrier pool. This was the default behavior - between OTP 17 and OTP 21, but changed to use a node - global carrier pool as of OTP 22.0. Usage of the node - global carrier pool proved troublesome since it had a - tendency to spread long lived blocks into allocators with - normally short lived blocks causing increased memory - fragmentation. The node global carrier pool behavior as - well as other behaviors can be configured using the - +M<S>cp - command line argument.

+ Fix bug where the "newshell" would trigger a newline at + the column width of the terminal, even if the next + character to be printed was a newline. This would cause + the terminal to render two newlines instead of one.

- Own Id: OTP-16898 Aux Id: OTP-16856

+ Own Id: OTP-17779 Aux Id: GH-5403 PR-5599

- New functions have been added to the maps module: - merge_with/3, intersect/2, - intersect_with/3, filtermap/2, - from_keys/2, and maps:foreach/2.

-

- maps:merge_with/3 is the same as merge/2 - but takes an extra fun that is used to combine items with - the same key.

+ Fix the memory value returned from + ets:info(Tid,memory) when the + read_concurrency option is used.

- maps:intersect/2 computes the intersection of two - maps.

+ Before this fix the memory used by the scheduler specific + lock cache lines was not counted towards the total. This + caused the returned memory usage to be very incorrect on + systems with many schedulers for tables with man locks.

- maps:intersect_with/3 is the same as - intersect/2 but takes an extra fun that is used to - combine intersecting items.

+ Own Id: OTP-17832 Aux Id: PR-5494

+
+

- maps:filtermap/2 allows filtering and mapping of a - map in a single pass.

+ Fix the undocumented --profile_boot option to work + again.

- maps:from_keys/2 constructs a map from a list of - keys and a single value and can be used to to optimize - sets operations such as from_list/1, filter/2, - intersection/2, and subtract/2.

+ Own Id: OTP-17836 Aux Id: PR-5546

+
+

- maps:foreach/2 allows iteration over a map without - returning any value.

+ [socket] Encode of sockaddr has been improved.

- Own Id: OTP-16936 Aux Id: ERL-1367

+ Own Id: OTP-18020

- Change escripts to output any errors or warnings - to standard error instead of standard out.

-

- *** POTENTIAL INCOMPATIBILITY ***

+ Fix erl_child_setup (the program used by + open_port({spawn,...}) and os:cmd/1) to + better handle partial reads from the Erlang VM.

- Own Id: OTP-16945

+ Own Id: OTP-18047 Aux Id: PR-5861

+

The runtime system would crash when attempting to + create more than 33554431 atoms.

- A new erl parameter for specifying a file descriptor with - configuration data has been added. This makes it possible - to pass the parameter "-configfd FD" when executing the - erl command. When this option is given, the system will - try to read and parse configuration parameters from the - file descriptor.

+ Own Id: OTP-18068 Aux Id: GH-5903

+
+
+
+ + +
Improvements and New Features + +

- Own Id: OTP-16952

+ Users can now configure ETS tables with the + {write_concurrency, auto} option. This option + forces tables to automatically change the number of locks + that are used at run-time depending on how much + concurrency is detected. The {decentralized_counters, + true} option is enabled by default when + {write_concurrency, auto} is active.

+

+ Benchmark results comparing this option with the other + ETS optimization options are available here:

+

+ https://erlang.org/bench/ets_bench_result_lock_config.html

+

+ Own Id: OTP-15991 Aux Id: PR-5208

-

The experimental HiPE application has been removed, - together with all related functionality in other - applications.

- *** POTENTIAL INCOMPATIBILITY ***

+ The net module now works on Windows.

- Own Id: OTP-16963

+ Own Id: OTP-16464

+

To enable more optimizations, BEAM files compiled with + OTP 21 and earlier cannot be loaded in OTP 25.

- The pretty printer for floating point number have been - changed to make it easier to see if the integer part of - the number has been rounded. After the change the digit - that may have been rounded always appears last or just - before the exponent character (e or E). This is - accomplished by always printing the number using - scientific notation if it is so large that the integer - part could be rounded.

+ Own Id: OTP-16702

+
+

- Own Id: OTP-16980 Aux Id: ERL-1308

+ Optimize minor garbage collection for processes with + large number of binaries, funs and/or external + pids/ports/refs. This is a continuation of the + optimization (OTP-17602) released in OTP-24.1.

+

+ Own Id: OTP-16852 Aux Id: ERL-1347, PR-5195

-

The erlang:monitor_node/2 BIF will now fail - with a notalive exception if distribution has not - been started on the current node; it used to fail with a - badarg exception.

+

+ The signal queue of a process with + message_queue_data=off_heap* has been optimized to allow + parallel reception of signals from multiple processes.

+

+ This is possible to do as Erlang only guarantees that + signals (i.e., message signals and non-message signals) + sent from a single process to another process are ordered + in send order. However, there are no ordering guarantees + for signals sent from different processes to a particular + process. Therefore, several processes can send signals in + parallel to a specific process without synchronizing with + each other. However, such signal sending was previously + always serialized as the senders had to acquire the lock + for the outer signal queue of the receiving process. This + parallel signal sending optimization yields much better + scalability for signal sending than what was previously + possible, see + https://erlang.org/bench/sigq_bench_result.html for + benchmark results.

+

+ * Information about how to enable the + message_queue_data=off_heap setting can be found in the + documentation of the function erlang:process_flag/2.

+

+ Own Id: OTP-16982 Aux Id: PR-5020

+
+ +

The JIT now works for 64-bit ARM processors.

+

+ Own Id: OTP-17119 Aux Id: PR-4869

+
+ +

+ Added support for the compile attribute -nifs() to + empower compiler and loader with information about which + functions may be overridden as NIFs by + erlang:load_nif/2. It is recommended to use this + attribute in all modules that load NIF libraries.

+

+ Own Id: OTP-17151 Aux Id: ERIERL-590, PR-5479

+
+ +

+ A test case has been added to the otp_SUITE that test + that the dependency versions for OTP's applications are + correct. The test case uses xref to check if the used + functions are available in the specified dependency + versions. The test case depends on the Erlang/OTP team's + testing infrastructure and will be skipped if its + dependencies are not met.

+

+ Own Id: OTP-17224

+
+ +

+ An Erlang installation directory is now relocatable on + the file system given that the paths in the + installation's RELEASES file are paths that are + relative to the installations root directory. The + `release_handler:create_RELEASES/4 function can + generate a RELEASES file with relative paths if + its RootDir parameter is set to the empty string.

+

+ Own Id: OTP-17304

+
+ +

The following distribution flags are now mandatory: + DFLAG_BIT_BINARIES, DFLAG_EXPORT_PTR_TAG, + DFLAG_MAP_TAGS, DFLAG_NEW_FLOATS, and + DFLAG_FUN_TAGS. This mainly concerns libraries or + application that implement the distribution protocol + themselves.

+

+ Own Id: OTP-17318 Aux Id: PR-4972

+
+ +

+ Input for configure scripts adapted to + autoconf 2.71.

+

+ Own Id: OTP-17414 Aux Id: PR-4967

+
+ +

When binary construction using the binary syntax + fails, the error message printed in the shell and by + erl_error:format_exception/3,4 will contain more + detailed information about what went wrong.

+

+ Own Id: OTP-17504 Aux Id: GH-4971, PR-5281, PR-5752

+
+ +

+ The configuration files .erlang, .erlang.cookie + and .erlang.crypt + can now be located in the XDG Config Home directory.

+

+ See the documentation for each file and + filename:basedir/2 for more details.

+

+ Own Id: OTP-17554 Aux Id: GH-5016 PR-5408 OTP-17821

+
+ +

+ Make byte_size/1 and binary_part/2/3 + callable from match specs (in ETS and tracing).

+

+ Own Id: OTP-17555 Aux Id: PR-5027

+
+ +

+ Dynamic node name improvements: erlang:is_alive/0 + changed to return true for pending dynamic node name and + new function net_kernel:get_state/0.

+

+ Own Id: OTP-17558 Aux Id: OTP-17538, PR-5111, GH-5402

+
+ +

+ A new option called short has been added to the + functions erlang:float_to_list and + erlang:float_to_binary. This option creates the + shortest correctly rounded string representation of the + given float that can be converted back to the same float + again.

+

+ Own Id: OTP-17562 Aux Id: GH-4492

+
+ +

+ The tagged tuple tests and fun-calls have been optimized + and are now a little bit cheaper than previously.

+

+ These optimizations become possible after making sure + that all boxed terms have at least one word allocated + after the arity word. This has been accomplished by + letting all empty tuples refer to the same empty tuple + literal which also reduces memory usage for empty tuples.

+

+ Own Id: OTP-17608

+
+ +

+ The signal queue benchmark in parallel_messages_SUITE and + the ETS benchmark in ets_SUITE have benchmark result + visualization HTML pages with "fill-screen" buttons to + make the graphs bigger. This button did not work as + intended before. When pressing the button for a graph, + the last graph got replaced with a bigger version and not + the one over the button. This is now fixed.

+

+ Own Id: OTP-17630

+
+ +

+ The test case num_bif_SUITE:t_float_to_string previously + failed sometimes as it assumed a certain rounding of + floats printed with sprintf but the rounding type is + platform specific.

+

+ Own Id: OTP-17636

+
+ +

+ Optimize interpreter to create heap binaries of small + match contexts if possible.

+

+ This optimization was already done in the JIT.

+

+ Own Id: OTP-17660 Aux Id: PR-5164

+
+ +

+ Optimize integer multiplication for x86 JIT

+

+ Own Id: OTP-17667 Aux Id: PR-5237

+
+ +

+ Removed use of node creation value zero as a wildcard. + Also prevent zero from being used as creation by + erl_interface and jinterface nodes.

+

+ Own Id: OTP-17682 Aux Id: PR-5347

+
+ +

+ Distributed spawn operations now require distributed + spawn_request() support. Distributed + spawn_request() was introduced in OTP 23. That is, + distributed spawn operations against Erlang nodes of + releases prior to OTP 23 will fail.

*** POTENTIAL INCOMPATIBILITY ***

- Own Id: OTP-16987

+ Own Id: OTP-17683 Aux Id: PR-5306

+

The Erlang compiler now includes type information in + BEAM files, and the JIT can now use that type information + to do optimizations such as eliminating or simplifying + type tests.

- Accept references up to a size of 160-bits from remote - nodes. This is the first step in an upgrade path toward - using references up to 160-bits in a future OTP release.

+ Own Id: OTP-17684 Aux Id: PR-5316, PR-5664

+
+ +

Improved the JIT's support for external tools like + perf and gdb, allowing them to show line + numbers and even the original Erlang source code when + that can be found.

+

To aid them in finding the source code, the + absolute_path compiler option has been added to + embed the absolute file path of a module.

+

+ Own Id: OTP-17685

+
+ +

+ Add [32-bit] to the Erlang shell title row for 32-bit + VMs.

+

+ Own Id: OTP-17717 Aux Id: PR-5290

+
+ +

Instructions for how to build the runtime system for + iOS/iPadOS can now be found in + HOWTO/INSTALL.md.

+

+ Own Id: OTP-17728 Aux Id: PR-5284

+
+ +

+ Add support for static Elixir NIF modules with + non-alphanumeric characters by using new macro + STATIC_ERLANG_NIF_LIBNAME.

+

+ Own Id: OTP-17729 Aux Id: PR-5477

+
+ +

+ Add new function caller_line to for trace match + specifications used by erlang:trace_pattern/3.

+

+ This new option puts the line number of the caller into + the trace message sent to the trace receiver.

+

+ Own Id: OTP-17753 Aux Id: PR-5305 GH-5297

+
+ +

+ A new erl command line argument +ssrct has + been introduced which will cause the runtime system to + skip reading CPU topology information. This reduce start + up time especially when the CPU topology is large. + Reading of CPU topology information is now also skipped + if a user defined CPU topology is set using the + +sct command line argument.

+

+ Own Id: OTP-17762 Aux Id: GH-5204, PR-5219

+
+ +

+ The default time warp mode will change in Erlang/OTP 26. + Added a warning about this upcoming potential + incompatibility to the documentation.

+

+ Own Id: OTP-17772 Aux Id: GH-4965 PR-5644

+
+ +

The emulator will no longer mark unused memory as + discardable (e.g. through madvise(2)), as it + caused more problems than it solved.

+

+ Own Id: OTP-17824

+
+ +

When a record matching or record update fails, a + {badrecord,ExpectedRecordTag} exception used to be + raised. In this release, the exception has been changed + to {badrecord,ActualValue}, where + ActualValue is the actual that was found instead + of the expected record.

+

+ Own Id: OTP-17841 Aux Id: PR-5694

+
+ +

+ Removed the previously undocumented and unsupported + emem tool.

+

+ Own Id: OTP-17892 Aux Id: PR-5591

+
+ +

+ Remove version number from the default install path on + Windows.

+

+ Own Id: OTP-17899 Aux Id: PR-5524

+
+ +

+ On Windows apply the limit flag + JOB_OBJECT_LIMIT_BREAKAWAY_OK in the Erlang service to be + able to start a OS child process with a different session + number.

+

+ Own Id: OTP-17927 Aux Id: PR-5283

+
+ +

+ New erl command line option +IOs. It can be used + to disable scheduler thread poll optimization, which has + been seen to cause degraded event latency in some use + cases.

+

+ Own Id: OTP-17945 Aux Id: GH-4759, PR-5809

+
+ +

+ An API for multihomed SCTP connect has been added in the + guise of gen_sctp:connectx_init/*

+

+ Own Id: OTP-17951 Aux Id: PR-5656

+
+ +

+ [socket] Add encoding of the field hatype of the type + sockaddr_ll (family 'packet').

+

+ Own Id: OTP-17968 Aux Id: OTP-16464

+
+ +

+ A cross compilation issue has been fixed about finding + libdlpi during the configure phase.

+

+ Own Id: OTP-17985 Aux Id: GH-5728

+
+ +

+ process_info/2 + now also accepts parent as argument. When passed, + the process identifier of the parent process will be + returned.

+

+ Own Id: OTP-17999 Aux Id: PR-5768

+
+ +

+ Add function attributes to erl_nif and + erl_driver APis to improve compiler detection of + interface misuse.

+

+ Own Id: OTP-18006 Aux Id: PR-5932

+
+ +

+ The exported type erlang:send_destination/0 + has been introduced.

+

+ Own Id: OTP-18033 Aux Id: PR-2926, GH-5376

+
+ +

+ Building of the C/C++ make dependencies on Windows has + been optimized to be a lot faster.

+

+ Own Id: OTP-18036 Aux Id: PR-5846

+
+ +

file:sync/1 will now use the + F_BARRIERFSYNC flag when available on Mac OS.

+

+ Own Id: OTP-18038

+
+
+
+ +
+ +
Erts 12.3.2.13 + +
Fixed Bugs and Malfunctions + + +

The following functions are now much faster when given + a long list or binary:

+ erlang:list_to_integer/1 + erlang:binary_to_integer/1 + erlang:binary_to_integer/2 + erlang:list_to_integer/2 + string:to_integer/1 +

+ Own Id: OTP-18659 Aux Id: PR-7426

+
+
+
+ +
+ +
Erts 12.3.2.12 + +
Fixed Bugs and Malfunctions + + +

In rare circumstances, bit syntax matching of an + invalid code point for a utf32 would crash the + runtime system.

+

+ Own Id: OTP-18560

+
+ +

+ If a runtime system which was starting the distribution + already had existing pids, ports, or references referring + to a node with the same nodename/creation pair that the + runtime system was about to use, these already existing + pids, ports, or references would not work as expected in + various situations after the node had gone alive. This + could only occur if the runtime system was communicated + such pids, ports, or references prior to the distribution + was started. That is, it was extremely unlikely to happen + unless the distribution was started dynamically and was + even then very unlikely to happen. The runtime system now + checks for already existing pids, ports, and references + with the same nodename/creation pair that it is about to + use. If such are found another creation will be chosen in + order to avoid these issues.

+

+ Own Id: OTP-18570 Aux Id: PR-7190

+
+ +

Constructing a binary segment not aligned with a byte + boundary, with a size not fitting in 31 bits, and with a + value not fitting in a 64-bit word could crash the + runtime system.

+

+ Own Id: OTP-18597

+
+
+
+ + +
Improvements and New Features + + +

+ Further robustify implementation of large maps (> 32 + keys). Keys that happen to have same internal 32-bit hash + values are now put in collision nodes which are traversed + with linear search. This removes the demand for the + internal hash function when salted to eventually produce + different hashes for all possible pairs of unequal terms.

+

+ Own Id: OTP-18569

+
+
+
+ +
+ +
Erts 12.3.2.11 + +
Fixed Bugs and Malfunctions + + +

+ Fix bug sometimes causing emulator crash at node shutdown + when there are pending connections. Only seen when + running duel distribution protocols, inet_drv and + inet_tls_dist.

+

+ Own Id: OTP-18243 Aux Id: GH-6247, PR-6258

+
+ +

Fix bug in binary_to_term (and distributed + receive) when decoding a large map (>32 keys) with + unsorted small maps (<= 32) as keys of the large + map.

+

This was only a problem if the term was encoded by + erl_interface, jinterface or otherwise, as + the VM itself always encodes small maps with sorted + keys.

+

The "binary_to_term" would appear as successful but + the created large map was internally inconsistent. The + smaller key-maps could not be found with maps:get and + friends. Other operations such as map compare and merge + could probably also give incorrect results.

+

+ Own Id: OTP-18343 Aux Id: GH-6496

+
+ +

+ Implementations of the call() + driver callback that returned a faulty encoded result + could cause a memory leak and could cause invalid data on + the heap of the processes calling erlang:port_call/3.

+

+ Own Id: OTP-18525 Aux Id: PR-7049

+
+ +

+ Aliases created in combination with a monitor using the + {alias, explicit_unalias} option stopped working + from remote nodes when a 'DOWN' signal had been + received due to the monitor or if the monitor was removed + using the erlang:demonitor() BIF.

+

+ This bug was introduced in OTP 24.3.4.10 and OTP 25.3.

+

+ Own Id: OTP-18557 Aux Id: PR-7131, OTP-18496

+
+
+
+ +
+ +
Erts 12.3.2.10 + +
Fixed Bugs and Malfunctions + + +

+ Active process aliases of a process at its termination + leaked memory.

+

+ Own Id: OTP-18496 Aux Id: GH-6947, PR-6953

+
+
+
+ +
+ +
Erts 12.3.2.9 + +
Fixed Bugs and Malfunctions + + +

+ process_info(Pid, status) when Pid /= + self() could return an erroneous result.

+

+ Own Id: OTP-18421 Aux Id: PR-6806

+
+ +

In rare circumstances, when a process exceeded its + allowed heap size set by option max_heap_size, it + would not be killed as it should be, but instead enter a + kind of zombie state it would never get out of.

+

+ Own Id: OTP-18463 Aux Id: PR-6858

+
+
+
+ +
+ +
Erts 12.3.2.8 + +
Fixed Bugs and Malfunctions + + +

Fixed a bug in selective receive optimization that + could crash 32-bit emulators.

+

+ Own Id: OTP-18383 Aux Id: ERIERL-905

+
+ +

+ A race condition which was very rarely triggered could + cause the signal queue of a process to become + inconsistent causing the runtime system to crash.

+

+ Own Id: OTP-18388 Aux Id: OTP-17462, PR-6662

+
+
+
+ +
+ +
Erts 12.3.2.7 + +
Fixed Bugs and Malfunctions + + +

+ Spec for function net:if_names/0 incorrect

+

+ Own Id: OTP-18296 Aux Id: OTP-16464

+
+ +

+ Fix bug in binary_to_term decoding a binary term + 2Gbyte or larger.

+

+ Own Id: OTP-18306 Aux Id: GH-6393, PR-6401

+
+ +

+ Fix list_to_atom/1 for negative code points. Could + either return with a positive code point or fail with an + incorrect exception.

+

+ Own Id: OTP-18321

+
+ +

+ Fix bug in binary_to_term decoding a list of + length 1G or longer.

+

+ Own Id: OTP-18328 Aux Id: GH-6439, PR-6440

+
+
+
+ +
+ +
Erts 12.3.2.6 + +
Fixed Bugs and Malfunctions + + +

+ Notifications + about available distribution data sent to + distribution controller processes could be lost. + Distribution controller processes can be used when + implementing an alternative distribution carrier. The + default distribution over tcp was not effected and the + bug was also not present on x86/x86_64 platforms.

+

+ Own Id: OTP-18258 Aux Id: GH-6309, PR-6324

+
+
+
+ +
+ +
Erts 12.3.2.5 + +
Fixed Bugs and Malfunctions + + +

+ Fix writing and reading of more than 2 GB in a single + read/write operation on macOS. Before this fix attempting + to read/write more than 2GB would result in + {error,einval}.

+

+ Own Id: OTP-18222 Aux Id: PR-6248 GH-6242

+
+
+
+ +
+ +
Erts 12.3.2.4 + +
Fixed Bugs and Malfunctions + + +

+ Fix bug causing ets:info (and sometimes + ets:whereis) to return 'undefined' for an existing + table if a concurrent process were doing + ets:insert with a long list on the same table.

+

+ Own Id: OTP-18218 Aux Id: ERIERL-855

+
+
+
+ +
+ +
Erts 12.3.2.3 + +
Fixed Bugs and Malfunctions + + +

Fix faulty distribution encoding of terms with + either

a fun with bit-string or + export-fun in its environment when encoded toward a not + yet established (pending) connection or a + fun with a binary/bitstring, in its environment, + referring to an off-heap binary (larger than 64 + bytes).

The symptom could be failed + decoding on the receiving side leading to aborted + connection. Fix OTP-18093 is a workaround for theses bugs + that makes the VM accepts such faulty encoded funs.

+

The first encoding bug toward pending connection + exists only in OTP 23 and 24, but the second one exists + also on OTP 25.

+

+ Own Id: OTP-18104 Aux Id: OTP-18093

+
+ +

Distributed exit signals could be lost under the + following conditions:

An exit signal + from a parent process to a child process was lost if:

+

the parent process terminated before the + spawn request that created the child had completed, +

the spawn request set up a link + between parent and child

the spawn + request was distributed, and

the + exit reason was larger than one machine word.

+

Loss of a connection over which + a not yet completed spawn request was ongoing could cause + loss of exit signals. Such loss of exit signals was very + rare. Besides the above described connection loss also + the following conditions had to be satisfied:

+

The spawn request that was interrupted by the + connection loss also had to set up a link between the + parent process and the child process.

+

The parent process that issued the spawn + request also had to be terminating while the spawn + request was interrupted by the connection loss. +

The same parent process also had to + have made other spawn requests to other nodes than to the + node to which the connection was lost.

+

These spawn requests to the other nodes also + had to set up links.

These spawn + requests to the other nodes also had to be not yet + completed at the time of the connection loss. That is, + the spawn reply from the child process had not yet + reached the parent process.

If all + the conditions above were met, exit signals to the + children spawned due to the above described spawn + requests to other nodes could be lost.

+

The above bug also caused a significant memory leak + when it was triggered since the destruction of the parent + process never completed.

+

+ Own Id: OTP-18164 Aux Id: PR-6114

+
+ +

+ A race could cause process_info(Pid, + message_queue_len) on other processes to return + invalid results.

+

+ Own Id: OTP-18169 Aux Id: PR-6134

+
+ +

+ Fixed reduction counting for handling process system + tasks.

+

+ Own Id: OTP-18170 Aux Id: PR-6135

+
+ +

+ Priority elevation of terminating processes did not work + which could cause execution of such processes to be + delayed.

+

+ Own Id: OTP-18175 Aux Id: PR-6142

+
+ +

+ An unlink operation made by a process that terminated + before the unlink operation completed, i.e., before it + had received an unlink-ack signal from the linked + process, caused an exit signal to erroneously be sent + from the terminating process to the process being + unlinked. This exit signal would most often be ignored by + the receiver, but if the receiver of the exit signal + concurrently set up a new link, it could receive the exit + signal with the actual exit reason of the terminating + process instead of a noproc exit reason. It is + however very hard to detect that this has happened and + has no obvious negative consequences, so it should be + considered harmless.

+

+ A distributed unlink-ack signal received by a terminating + process was also not properly removed which could cause a + minor memory leak.

+

+ Own Id: OTP-18177 Aux Id: PR-6150

+
+ +

+ The monitor/3 BIF + did not apply options to the created monitor if the + target process or port did not exist. That is, the + corresponding down message would get a `DOWN` tag + even if a custom tag had been set, and the returned + reference was not an alias even if the alias + option had been passed.

+

+ Own Id: OTP-18190 Aux Id: GH-6185, PR-6209

+
+ +

+ The erlang:monotonic_time/1, + erlang:system_time/1, + erlang:time_offset/1, + and os:system_time/1 + BIFs erroneously failed when passed the argument + native.

+

+ Own Id: OTP-18197 Aux Id: GH-6165, PR-6213

+
+
+
+ +
+ +
Erts 12.3.2.2 + +
Fixed Bugs and Malfunctions + + +

+ Fixed emulator crash that could happen during crashdump + generation of ETS tables with options ordered_set + and {write_concurrency,true}.

+

+ Own Id: OTP-18144 Aux Id: GH-5981

+
+
+
+ +
+ +
Erts 12.3.2.1 + +
Fixed Bugs and Malfunctions + + +

+ Accept funs (NEW_FUN_EXT) with incorrectly encoded size + field. This is a workaround for a bug (OTP-18104) + existing in OTP 23 and 24 that could cause incorrect size + fields in certain cases. The emulator does not use the + decoded size field, but erl_interface still does + and is not helped by this workaround.

+

+ Own Id: OTP-18093 Aux Id: OTP-18104, PR-5987

+
+ +

+ The zlib built in to the runtime system has been updated + to version 1.2.12. (Note that on most platforms, the + platform's own zlib is used.)

+

+ Own Id: OTP-18123 Aux Id: GH-5994

+
+
+
+ +
+ +
Erts 12.3.2 + +
Fixed Bugs and Malfunctions + + +

+ Let EPMD tolerate failure when binding to IPv4/IPv6 + loopback intefaces in addition to user-supplied addresses + via ERL_EPMD_ADDRESS or the -address + option. This can happen, for example, if the host system + has ipv6 disabled via the disable_ipv6 sysctl.

+

+ Own Id: OTP-17970 Aux Id: PR-5762

+
+ +

Fixed a rare bug in binary_to_term/1, + enif_make_map_from_arrays, + erl_drv_send_term, and Erlang distribution that + could crash the emulator.

+

+ Own Id: OTP-18027

+
+ +

Fixed a rare race in persistent_term:get/1,2 + that could cause it to return the value of another + key.

+

+ Own Id: OTP-18065 Aux Id: GH-5908

+
+ +

+ Fix bug where the process message queue was left in an + inconsistent state when changing from on_heap to off_heap + message queue data causing the GC to segfault.

+

+ Own Id: OTP-18075 Aux Id: PR-5927

+
+ +

+ Fix functions that convert universal to localtime (such + as erlang:localtime/0 and + erlang:universaltime_to_localtime/1) to fetch the correct + localtime if it is changed after the start of the VM.

+

+ Own Id: OTP-18076 Aux Id: ERIERL-802 PR-5905

+
+ +

+ Fix memory leak when a process doing a distributed + fragmented send is sent an exit signal. Before this fix + the receiving node would be left with an incomplete + message that would remain until the nodes were + disconnected. The bug has existed since Erlang/OTP 21.

+

+ Own Id: OTP-18077 Aux Id: GH-5876 PR-5892

+
+ +

+ Corrected the behaviour of the shutdown function when + using with the inet_backend = socket. It was not + sufficiently compatible with the "old" gen_tcp.

+

+ Own Id: OTP-18080 Aux Id: GH-5930

+
+
+
+ +
+ +
Erts 12.3.1 + +
Fixed Bugs and Malfunctions + + +

erlang:open_port({spawn, _},_) has been fixed + on Windows to handle whitespace characters in the path + correctly.

This could, for example, cause + execution of the resolver helper program + inet_gethost to fail and instead possibly execute + a different program.

+

+ Own Id: OTP-17978 Aux Id: OTP-17958

+
+ +

+ Fix race condition when creating crash dump that could + cause multiple threads to race when writing the initial + information in a crash dump.

+

+ The race condition was introduced in erts-12.2 + (Erlang/OTP 24.2).

+

+ Own Id: OTP-17993 Aux Id: PR-5806

+
+ +

+ Fix Erlang monotonic time on MacOS. Previously used OS + monotonic time primitive on MacOS is buggy and will not + be used anymore. It has been replaced with usage of + another OS monotonic time primitive that does not appear + to be buggy.

+

+ Own Id: OTP-17998 Aux Id: PR-5825, GH-5554

+
+
+
+ +
+ +
Erts 12.3 + +
Fixed Bugs and Malfunctions + + +

Fixed a bug in the x86 JIT that might cause floating + point instructions to wrongly throw an exception.

+

+ Own Id: OTP-17822

+
+ +

+ Preserve correct nodedown_reason if supervised + distribution controller processes exit with {shutdown, + Reason}.

+

+ Own Id: OTP-17838 Aux Id: PR-5748

+
+ +

+ Handling of send_timeout for gen_tcp has + been corrected so that the timeout is honored also when + sending 0 bytes.

+

+ Own Id: OTP-17840

+
+ +

By default global does not take any + actions to restore a fully connected network when + connections are lost due to network issues. This is + problematic for all applications expecting a fully + connected network to be provided, such as for example + mnesia, but also for global itself. A + network of overlapping partitions might cause the + internal state of global to become inconsistent. + Such an inconsistency can remain even after such + partitions have been brought together to form a fully + connected network again. The effect on other applications + that expects that a fully connected network is maintained + may vary, but they might misbehave in very subtle hard to + detect ways during such a partitioning.

In order + to prevent such issues, we have introduced a prevent + overlapping partitions fix which can be enabled using + the prevent_overlapping_partitions + kernel(6) parameter. When this fix has been + enabled, global will actively disconnect from + nodes that reports that they have lost connections to + other nodes. This will cause fully connected partitions + to form instead of leaving the network in a state with + overlapping partitions. Note that this fix has to + be enabled on all nodes in the network in order to + work properly. Since this quite substantially changes the + behavior, this fix is currently disabled by default. + Since you might get hard to detect issues without this + fix you are, however, strongly advised to enable + this fix in order to avoid issues such as the ones + described above. As of OTP 25 this fix will become + enabled by default.

+

+ Own Id: OTP-17843 Aux Id: ERIERL-732, PR-5611

+
+ +

Corrected the type specification of + erlang:seq_trace/2.

+

+ Own Id: OTP-17900 Aux Id: GH-5667

+
+ +

+ Fix memory leak when tracing on running on a process that + only handle system tasks or non-message signals (for + example process_info requests).

+

+ Own Id: OTP-17904 Aux Id: ERIERL-757

+
+
+
+ + +
Improvements and New Features + + +

+ Add support for using socket:sockaddr_in() and + socket:sockaddr_in6() when using gen_sctp, gen_tcp and + gen_udp. This will make it possible to use Link Local + IPv6 addresses.

+

+ Own Id: OTP-17455 Aux Id: GH-4852

+
+ +

+ Show on_load failure reasons in embedded mode.

+

+ Own Id: OTP-17718 Aux Id: PR-5199

+
+ +

+ Compile date saved in the Erlang VM executable has been + removed.

+

+ Own Id: OTP-17891 Aux Id: PR-5589

+
+ +

+ Improve documentation for the dynamic node name feature.

+

+ Own Id: OTP-17918

+
+
+
+ +
+ +
Erts 12.2.1 + +
Fixed Bugs and Malfunctions + + +

Fixed a memory leak in file:read_file_info/2 + and file:read_file/1 on Windows.

+

+ Own Id: OTP-17827 Aux Id: GH-5527

+
+ +

+ Fix GC emulator crash when spawn_request was used + when message tracing was enabled.

+

+ Own Id: OTP-17871 Aux Id: PR-5612

+
+
+
+ +
+ +
Erts 12.2 + +
Fixed Bugs and Malfunctions + + +

When matching and constructing utf16 segments + in the binary syntax, the native flag would be + ignored. That is, the endian would always be big endian + even on a little-endian computer (almost all modern + computers).

+

+ Own Id: OTP-17713

+
+ +

+ Fix the help printout of +JPperf.

+

+ Own Id: OTP-17749 Aux Id: PR-5378 GH-5361

+
+ +

+ Fix bug that could cause Erlang to deadlock during + creation of an Erlang crash dump.

+

+ Own Id: OTP-17751 Aux Id: PR-5315

+
+ +

+ Fixed C++ build errors on some aarch64 platforms.

+

+ Own Id: OTP-17763 Aux Id: GH-5351

+
+ +

For macOS, the Info.plist file embedded in the + runtime system now only contains the absolute minimum + amount of information needed for the web view in + wx to work towards localhost. The other + fields have been removed, allowing an application + packaged in a bundle to specify the application name and + other parameter in its own Info.plist file.

+

+ Own Id: OTP-17785 Aux Id: PR-5393

+
+ +

+ Fix bug in internal stacks (WSTACK and ESTACK) used by + term_to_binary/2 to encode terms. The bug could + cause a segfault if a very very large map was to be + encoded with the deterministic option given.

+

+ Own Id: OTP-17804 Aux Id: PR-5372

+
+ +

+ Improve the error printout when open_port/2 fails + because of invalid arguments.

+

+ Own Id: OTP-17805 Aux Id: PR-5406

+
+ +

+ Fix bug in crash dumps where the stackframe of a process + would be printed using an incorrect format.

+

+ Crash dump viewer has also been fixed to be able read the + broken stack format.

+

+ The bug has existed since Erlang/OTP 23.0.

+

+ Own Id: OTP-17814 Aux Id: PR-5462

+
+
+
+ + +
Improvements and New Features + + +

+ An option for enabling dirty scheduler specific allocator + instances has been introduced. By default such allocator + instances are disabled. For more information see the + documentation of the +Mdai + erl command line argument.

+

+ Own Id: OTP-17363 Aux Id: GH-4728, PR-5187

+
+ +

+ Minor optimization of receive markers in message queues.

+

+ Own Id: OTP-17673 Aux Id: OTP-16226

+
+ +

+ All predefined types have been added to the erlang + module together with documentation.

+

+ Any reference to a predefined type now links to that + documentation so that the user can view it.

+

+ Own Id: OTP-17689 Aux Id: PR-5292

+
+ +

+ Suppress a code checker warning caused by debug builds of + YCF. YCF tries to get a conservative estimate of the + bottom of the stack by reading and returning a call stack + allocated variable.

+

+ Own Id: OTP-17719

+
+ +

+ Add file and product properties to erl.exe and werl.exe.

+

+ Own Id: OTP-17724 Aux Id: ERL-1224

+
+ +

+ Micro optimization in bitstring append operations.

+

+ Own Id: OTP-17760 Aux Id: ERIERL-725, PR-5414

+
+ +

+ Responsiveness of processes executing on normal or + low priority could suffer due to code purging or + literal area removal on systems with a huge amount of + processes. This since during these operations all + processes on the system were scheduled for execution at + once.

+

+ This problem has been fixed by introducing a limit on + outstanding purge and copy literal requests in the + system. By default this limit is set to twice the amount + of schedulers on the system. This will ensure that + schedulers will have enough work scheduled to perform + these operations as quickly as possible at the same time + as other work will be interleaved to a much higher + degree. Performance of these operations will however be + somewhat degraded due to the overhead of enforcing this + limit compared to when using a very large limit.

+

+ This limit can be set by passing the +zosrl + command line argument to erl, or by calling + erlang:system_flag(outstanding_system_requests_limit, + NewLimit).

+

+ Own Id: OTP-17796 Aux Id: ERIERL-729, PR-5473

+
+
+
+ +
+ +
Erts 12.1.5 + +
Fixed Bugs and Malfunctions + + +

+ The runtime system could call select() with a too + large timeout value when executing on MacOS. This could + in turn cause the runtime system to crash.

+

+ Own Id: OTP-17735 Aux Id: GH-5339

+
+ +

The fix for Linux's behaviour when reconnecting an + UDP socket in PR-5120 released in OTP-24.1.2 has been + refined to only dissolve the socket's connection before a + connect if the socket is already connected, that is: only + for a reconnect.

This allows code to open a + socket with an ephemeral port, get the port number and + connect; without the port number changing (on Linux). + This turned out to have at least one valid use case + (besides test cases).

Should one reconnect the + socket then the port number may change, on Linux; it is a + known quirk, which can be worked around by binding to a + specific port number when opening the socket. If you can + do without an ephemeral port, that is...

+

+ Own Id: OTP-17736 Aux Id: GH-5279, PR-5120, OTP-17559

+
+ +

Certain distributed signals that for various reasons + must to be forced into the distribution buffer even when + it is full would instead be lost if the distribution + buffer was full when sent. The effected signals:

+ EXIT signals with exit reasons of one + word size. DOWN signals with exit + reasons of one word size. demonitor + signals from a terminating process. + unlink_ack signals on OTP 23 and 24. + spawn_reply signals on OTP 23 and 24. + +

+ Own Id: OTP-17737 Aux Id: GH-5346, GH-4989

+
+
+
+ +
+ +
Erts 12.1.4 + +
Fixed Bugs and Malfunctions + + +

+ Fix bug where a gen_tcp write error that happened during + a delayed_send would cause a use after free segfault.

+

+ Own Id: OTP-17731 Aux Id: PR-5285

+
+ +

+ Fix x86 JIT bug where a rem instruction could + cause a segfault if given values that would cause an + badarith exception.

+

+ Own Id: OTP-17732 Aux Id: PR-5331 ERIERL-664

+
+
+
+ +
+ +
Erts 12.1.3 + +
Fixed Bugs and Malfunctions + + +

+ Reduction counter was not updated before and after doing + apply operations on the runtime system with the + jit enabled. This caused reduction counting to get out of + sync if a garbage collection was made as part of the + apply operation.

+

+ Own Id: OTP-17675

+
+ +

+ This fixes a bug in erts_factory_undo that caused + the heap to not be reset correctly. The + erts_factory_undo function is, for example, called + when a binary_to_term/1 call fails to reset the + heap to its state before the binary_to_term/1 + call. This can cause the heap to contain invalid terms + which potentially can cause issues (e.g., crashes) when + the whole heap is scanned.

+

+ Own Id: OTP-17677

+
+ +

When attempting to construct a binary with an segment + having an illegal type for the size (e.g. an atom), there + could be an unnecessary memory allocation (and subsequent + deallocation) before the operation failed. Amended to + fail before allocating any memory for the binary.

+

+ Own Id: OTP-17686

+
+ +

Fix bug in persistent_term when a key-value + pair contains a magic reference that is referred more + than once. Magic references are NIF resources or returned + from BIFs like ets:new, atomics:new. The + bug could cause the memory of the referred resource to be + prematurely deallocated.

The bug also apply to + magic references in message passing on a runtime built + with configure option + --enable-sharing-preserving.

Bug exist for + 64-bit since OTP-24.0 and for 32-bit since OTP-20.0.

+

+ Own Id: OTP-17700 Aux Id: GH-5271, PR-5273

+
+ +

Fixed a crash when inspecting the stack trace of an + exception raised at a very high line number.

+

This bug was introduced in OTP 24.

+

+ Own Id: OTP-17712

+
+ +

The following two bugs that caused + erlang:demonitor() to behave erroneously have been + fixed. The bugs were only triggered if the monitor that + was removed by demonitor() had previously been + created simultaneously as a monitor and as an alias.

+ A demonitor operation on a monitor created + using the {alias, reply_demonitor} option + erroneously behaved as if the {alias, + explicit_unalias} option had been used. + A demonitor operation did not prevent a + corresponding 'DOWN' message from being delivered + if the monitor reference was kept as an active alias + after the operation. This could only occur if the + monitored process simultaneously terminated before the + demonitor signal reached it, and the exit reason was not + an immediate term. That is, a term larger than one + machine word. +

+ Own Id: OTP-17722 Aux Id: GH-5310, PR-5313

+
+
+
+ +
+ +
Erts 12.1.2 + +
Improvements and New Features + + +

+ The python scripts that existed in + erts/lib_src/yielding_c_fun/lib/tiny_regex_c/scripts had + a license that was incompatible with Erlang/OTP's + license. This ticket removes these scripts that were not + used by us.

+

+ Own Id: OTP-17658

+
+
+
+ +
+ +
Erts 12.1.1 + +
Fixed Bugs and Malfunctions + + +

+ A race between an exiting port and handling of + simultaneously received signals to that port could cause + a runtime system crash. The effected signals are + link, monitor and demonitor. On OTP + 22 a similar race could also cause a memory leak when + receiving an unlink signal.

+

+ Own Id: OTP-17642 Aux Id: PR-5248

+
+ +

+ A user defined tag + on a monitor message could cause the runtime + system to crash when the monitor message had been + received.

+

+ Own Id: OTP-17646 Aux Id: GH-5221, PR-5232

+
+ +

+ A call to erlang:demonitor(Ref) + where the reference Ref referred to an active + alias, but not an active monitor, caused the runtime + system to crash.

+

+ Own Id: OTP-17647 Aux Id: GH-5225, PR-5230

+
+ +

+ The message queue of a process entered an inconsistent + state after a receive expression with an invalid + timeout value was executed. If the exception raised due + to the invalid timeout value was caught, the following + receive expression executed by the process could + fail to match messages already present in the message + queue.

+

+ On OTP 24 this could also cause the whole runtime system + to crash.

+

+ Own Id: OTP-17651 Aux Id: GH-5235, PR-5244

+
+ +

+ Sending a Port ! {PortOwner, close} signal from a + process other than the port owner could erroneously + trigger a badsig exit signal being sent to the + port owner process even though the correct + PortOwner had been passed in the signal.

+

+ Own Id: OTP-17665 Aux Id: PR-5248

+
+
+
+ +
+ +
Erts 12.1 + +
Fixed Bugs and Malfunctions + + +

Atoms with Unicode code points greater than 255 (for + example Greek or Cyrillic characters) would not be + displayed correctly by crashdump_viewer.

+

+ Own Id: OTP-17377

+
+ +

+ Fix rare minor memory leak related to jit code loading.

+

+ Own Id: OTP-17445 Aux Id: PR-4843

+
+ +

The extended error information has been corrected and + improved for the following BIFs: + binary_to_existing_atom/2, + list_to_existing_atom/1, + erlang:send_after/{3,4}, and + erlang:start_timer/{3,4}.

+

+ Own Id: OTP-17449 Aux Id: GH-4900

+
+ +

+ Fix bug provoked when building with gcc 10 and link time + optimization (-flto), causing Erlang compiler to crash. + Bug exists since OTP-24.0.

+

+ Own Id: OTP-17477 Aux Id: GH-4846, PR-4894

+
+ +

Corrected bugs where builds were not reducible even + when the deterministic option was given. In + particular, modules with map literals with more than 32 + elements could cause this problem.

+

As part of this fix, the term_to_binary BIF now + accepts the option deterministic.

+

+ Own Id: OTP-17495 Aux Id: PR-5153

+
+ +

After an exception has been caught in a process, the + stack trace would be kept in the process longer than + necessary.

+

+ Own Id: OTP-17512

+
+ +

+ Fix rare race bug in memory management of distribution + entries. Have been seen to cause VM crash when massive + number of repeated concurrent failing connection + attempts.

+

+ Own Id: OTP-17513 Aux Id: GH-4964, PR-5015

+
+ +

+ The configure test for + --disable-esock-socket-registry has been corrected + so disabling now works.

+

+ Own Id: OTP-17539

+
+ +

init:stop() no longer unloads loaded code + before terminating the runtime system. On systems with + slow CPUs (such as Raspberry PI Zero), that can + significantly speed up termination of the runtime + system.

+

+ Own Id: OTP-17542 Aux Id: GH-5031, PR-5032

+
+ +

+ Fixed match specifications that use maps in either the + guard or the body to work properly.

+

+ With this fix both keys and values in maps can be + expressions.

+

+ Various other crashes and bugs when using maps in match + specifications have also been fixed.

+

+ Own Id: OTP-17567 Aux Id: PR-4915 PR-5115

+
+ +

+ Parsing of the result value in the native DNS resolver + has been made more defensive against incorrect results.

+

+ Own Id: OTP-17578 Aux Id: ERIERL-683

+
+ +

When binary_to_term/2 failed, the extended + error information would always blame the second argument + even if the actual error was in the first argument.

+

+ Own Id: OTP-17591 Aux Id: GH-5171

+
+ +

On 32-bit computers, binary_to_term/1,2 is now + more resilient against corrupted binaries containing maps + in the external format.

+

+ Own Id: OTP-17604

+
+ +

+ A call to process_info(Pid, status) could + erroneously report the status running when it + should have reported waiting. This occurred when + the calling process was executing on a higher priority + than the process being inspected. This bug has been + present since OTP 21.0 (erts version 10.0).

+

+ Own Id: OTP-17628

+
+
+
+ + +
Improvements and New Features + + +

+ Optimize memory usage of erts internal processes used + during code loading/purging by hibernating them after a + long time of inactivity.

+

+ Own Id: OTP-17426 Aux Id: PR-4785

+
+ +

+ Add the type erlang:stacktrace/0.

+

+ Own Id: OTP-17453 Aux Id: PR-4764

+
+ +

+ The arity argument of error/2,3 + can now be none to indicate that the calling + functions arity should be used.

+

+ Own Id: OTP-17456 Aux Id: PR-4764

+
+ +

+ Optimize match spec compiler for immediate (single word) + constant terms.

+

+ Own Id: OTP-17469

+
+ +

Functions erlang:set_cookie(Cookie) and + erlang:get_cookie(Node) have been added for + completeness and to facilitate configuring distributed + nodes with different cookies.

The documentation + regarding distribution cookies has been improved to be + less vague.

+

+ Own Id: OTP-17538 Aux Id: GH-5063, PR-5111

+
+ +

A workaround has been implemented for Linux's quirky + behaviour to not adjust the source IP address when + connecting a connected (reconnecing) UDP socket.

+ The workaround is to, on Linux, always dissolve any + connection before connecting an UDP socket.

+

+ Own Id: OTP-17559 Aux Id: GH-5092, PR-5120

+
+ +

+ The internal documentation for how to use Yielding C Fun + (YCF) has been updated to contain text about best + practices for using YCF for ERTS.

+

+ Own Id: OTP-17596

+
+ +

+ Optimize garbage collection for processes with large + number of binaries, funs and/or external pids/ports/refs.

+

+ Own Id: OTP-17602 Aux Id: PR-5149

+
+
+
+ +
+ +
Erts 12.0.4 + +
Fixed Bugs and Malfunctions + + +

+ A call to the process_info() BIF could end up + hanging for ever due to a bug introduced when the new + selective receive optimization was introduced in OTP + 24.0. Note that this bug only effects + process_info().

+

+ Own Id: OTP-17548 Aux Id: PR-5078, OTP-10391

+
+ +

+ Fix buffer overrun problem in the tty driver. The problem + happens on some platforms when using the CTRL+R + functionality of newshell with very long strings in the + history.

+

+ Own Id: OTP-17560 Aux Id: GH-5116

+
+ +

+ Fix race-condition that could cause a crash when tracing + scheduling or garbage collections on a process that was + running on a dirty scheduler.

+

+ Own Id: OTP-17568 Aux Id: PR-4940

+
+ +

+ Fix rare bug where re:run would crash/return invalid + results when given a subbinary as subject.

+

+ This bug has existed since Erlang/OTP 20.0.

+

+ Own Id: OTP-17585 Aux Id: GH-5150

+
+ +

binary_to_term/1,2 is now more resilient + against corrupted binaries containing maps in the + external format.

+

+ Own Id: OTP-17594

+
+
+
+ +
+ +
Erts 12.0.3 + +
Fixed Bugs and Malfunctions + + +

+ A call to erlang:cancel_timer(_, [{info, false}]) + could cause the calling process to block forever in the + call. Note that only the synchronous version of the call + (that is, the async option is false) in + combination with the info option set to + false was effected by this bug.

+

+ Own Id: OTP-17472 Aux Id: PR-4932

+
+ +

+ Microstate accounting (msacc) and + os:perf_counter() unintentionally used system time + instead of monotonic time for time measurements on a lot + of systems. These systems were all non x86/x86_64 systems + or x86/x86_64 systems without a reliable and constant + rdtsc instruction.

+

+ The lock counting (lcnt) built runtime system also + unintentionally used system time instead of monotonic + time for time measurements on all systems.

+

+ Own Id: OTP-17493

+
+ +

+ Simultaneous calls to + erlang:system_flag(schedulers_online, _) could + cause callers to end up in a suspended state forever.

+

+ Own Id: OTP-17500 Aux Id: GH-4809

+
+
+
+ +
+ +
Erts 12.0.2 + +
Fixed Bugs and Malfunctions + + +

+ Not yet handled alias-message signals in the signal queue + at the time when a garbage collection was performed could + cause a memory corruption which in turn could result in a + crash of the runtime system. This bug was introduced in + OTP 24.0.

+

+ Own Id: OTP-17431 Aux Id: GH-4858, PR-4870, OTP-16718

+
+ +

+ Fixed bug when using external pids/ports in keys of big + maps (> 32). Could cause runtime crash. Bug exists since + OTP 24.0.

+

+ Own Id: OTP-17436 Aux Id: PR-4875

+
+ +

After a node restart with init:restart/0,1, + the module socket was not usable because + supporting tables had been cleared and not + re-initialized. This has now been fixed.

Handling + of the "." domain as a search domain was incorrect and + caused a crash in the DNS resolver inet_res, which + has now been fixed.

+

+ Own Id: OTP-17439 Aux Id: GH-4827, PR-4888, GH-4838

+
+ +

+ A call to port_command() could cause a scheduler + to end up in an eternal loop if the port was busy and the + calling process had incoming signals at the time of the + call. This bug was introduced in OTP 23.3.2 (ERTS version + 11.2.1), OTP 22.3.4.18 (ERTS version 10.7.2.10), and OTP + 21.3.8.23 (ERTS version 10.3.5.18).

+

+ Own Id: OTP-17448 Aux Id: GH-4898, PR-4903, OTP-17291

+
+ +

Bug fixes and code cleanup for the new socket + implementation, such as:

Assertions on the result + of demonitoring has been added in the NIF code, where + appropriate.

Internal state handling for socket + close in the NIF code has been reviewed.

Looping + over close() for EINTR in the NIF code has + been removed, since it is strongly discouraged on Linux + and Posix is not clear about if it is allowed.

+ The inet_backend temporary socket option for + legacy gen_tcp sockets has been documented. +

The return value from net:getaddrinfo/2 + has been corrected: the protocol field is now an + atom(), instead of, incorrectly, + list(atom()). The documentation has also been + corrected about this return type.

Deferred close + of a socket:sendfile/* file was broken and has + been corrected.

Some debug code, not enabled by + default, in the socket NIF has been corrected to not + accidentally core dump for debug printouts of more or + less innocent events.

+

+ Own Id: OTP-17452

+
+ +

+ Dirty execution of a process in combination with an + unlink signal from a port to the process could cause the + signal queue of the process to enter into an inconsistent + state. The result of the inconsistency typically caused a + crash of the runtime system. This bug was introduced in + OTP 23.3 (ERTS version 11.2).

+

+ Own Id: OTP-17462 Aux Id: GH-4885, PR-4914, OTP-17127

+
+
+
+ +
+ +
Erts 12.0.1 + +
Fixed Bugs and Malfunctions + + +

+ Commit of generated configure script.

+

+ Own Id: OTP-17420 Aux Id: OTP-17398, GH-4821

+
+
+
+ +
+ +
Erts 12.0 + +
Fixed Bugs and Malfunctions + + +

+ file:open/2 now throws an badarg error when opened + with both the ram and raw options.

+

+ Own Id: OTP-16822 Aux Id: PR-2723

+
+ +

+ The estone benchmark has been updated to better reflect + changes in the compiler and run-time system.

+

+ Own Id: OTP-16879

+
+ +

+ Fix profile guided optimization of run-time system when + using GCC 7 or later.

+

+ Own Id: OTP-16880

+
+ +

+ Fix double close of fd when creating crash dump.

+

+ Own Id: OTP-16884

+
+ +

+ Improve erl error message when unable to open + included args_file.

+

+ Own Id: OTP-17014

+
+ +

+ Remove warning text about the -- operation from + documentation

+

+ The -- operation was optimized in Erlang/OTP 22 so + that its worst case complexity is O(N*log(N)), where N is + the total size of the input lists. Therefore, the warning + in the documentation saying that the time complexity is + proportional to length(A)*length(B) is incorrect and is + no longer needed. Notice that Erlang/OTP 21 will no + longer be supported when Erlang/OTP 24 gets released.

+

+ Own Id: OTP-17020

+
+ +

+ A floating point zero (0.0) can be both positive (+0.0) + and negative (-0.0). Multiple bugs in the compiler, + runtime system, and STDLIB have been fixed to ensure that + the minus sign on 0.0 is not lost.

+

+ Own Id: OTP-17077 Aux Id: ERL-1431, PR-2903, PR-2905, + PR-2906

+
+ +

+ Fix compiler warnings produced by the clang compiler.

+

+ Own Id: OTP-17105 Aux Id: PR-2872

+
+ +

+ Windows process erl.exe killed if its service + process erlsrv.exe terminates.

+

+ Own Id: OTP-17131 Aux Id: PR-3031, GH-4360

+
+ +

The configure scripts in crypto and + erts now fail if a requested feature cannot be + enabled.

Large parts of the configure + script of crypto have been rewritten with various + improvements and bug fixes. It is now better at finding + usable OpenSSL libraries, but will in the following cases + fail to detect OpenSSL libraries where it previously + sometimes detected the libraries by chance:

+ OpenSSL installations with include + directory and lib directory parts installed in + different base directories. In order to detect such + installations after this change, the user must explicitly + specify the locations using the --with-ssl=<path> + and the --with-ssl-incl=<path> + configure command line arguments. + When building with old gcc compilers or other + compilers on Debian derivatives with multiarch + directories under the lib directory. In order to + detect such installations after this change, the user + must explicitly specify the multiarch directory name + using the --with-ssl-lib-subdir=lib/<multiarch-dir> + configure command line argument. +

+ Own Id: OTP-17254 Aux Id: ERIERL-618, GH-4230

+
+ +

+ The erl command line arguments +Bi, + +Bd, and +B erroneously caused reception of + the USR1 signal to terminate the runtime system + without creating a crash dump. Reception of the + USR1 signal now always cause termination + with creation of a crash dump, regardless of + command line arguments passed. This bug has existed at + least since OTP R5B.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-17275 Aux Id: PR-4553

+
+ +

+ Add check to make sure that when passing an option to + erl that requires an argument, but none is given, + we report an error. This fixes a bug introduced in + OTP-22.1 via OTP-15926.

+

+ Own Id: OTP-17314 Aux Id: OTP-15926, GH-4624, PR-

+
+ +

+ The "Last calls" section in crash dumps have been updated + to print newlines after each non-function + save_calls state (send, receive, timeout).

+

+ Own Id: OTP-17329 Aux Id: PR-4730

+
+ +

+ Sockets created with socket:accept not counted + (socket:info/0).

+

+ Own Id: OTP-17372

+
+
+
+ + +
Improvements and New Features + + +

+ The experimental socket module can now use any + protocol (by name) the OS supports. Suggested in PR-2641, + implemented in PR-2670.

+

+ Own Id: OTP-14601 Aux Id: PR-2641, PR-2670, OTP-16749

+
+ +

+ New functions enif_dynamic_resource_call enables + NIFs to call native code in another NIF module. The call + is done via a resource callback function dyncall + supplied by the user with the new + enif_init_resource_type.

+

+ Own Id: OTP-14753

+
+ +

+ Runtime support for new improved selective receive + optimization.

+

+ Own Id: OTP-16226 Aux Id: OTP-10391

+
+ +

The deprecated function erlang:get_stacktrace/0 + has been removed. Use the new syntax in try/catch to + retrieve the stack backtrace.

+

+ Own Id: OTP-16653

+
+ +

+ Support for handling abstract code created before OTP R15 + has been dropped.

+

+ Own Id: OTP-16678 Aux Id: PR-2627

+
+ +

+ Extended error information for failing BIF calls as + proposed in EEP + 54 has been implemented.

+

+ When a BIF call from the Erlang shell fails, more + information about which argument or arguments that were + in error will be printed. The same extended error + information will by proc_lib, common_test, + and qlc when BIF calls fail.

+

+ For applications that wish to provide the same extended + error information, there are new functions + erl_error:format_exception/3 and + erl_error:format_exception/4.

+

+ There is a new error/3 BIF that allows + applications or libraries to provide extended error + information in the same way for their own exceptions.

+

+ Own Id: OTP-16686

+
+ +

+ The erlang module + documentation has been updated to improve clarity and + description of edge cases.

+

+ Own Id: OTP-16687 Aux Id: PR-2996 PR-2762

+
+ +

+ An example implementation of Erlang distribution over UDS + using distribution processes has been introduced.

+

+ Thanks to Jérôme de Bretagne

+

+ Own Id: OTP-16703 Aux Id: PR-2620

+
+ +

+ Improve code generation when creating funs by adding a + new beam instruction make_fun3 that does not do GC and + allows for better register allocation.

+

+ Own Id: OTP-16712

+
+ +

+ The process + alias feature as outlined by EEP + 53 has been introduced. It is introduced in order + to provide a lightweight mechanism that can prevent late + replies after timeout or connection loss. For more + information, see EEP 53 and the documentation of the new + alias/1 BIF + and the new options to the monitor/3 + BIF.

+

+ The call operation in the framework used by + gen_server, gen_statem, and + gen_event has been updated to utilize alias in + order to prevent late responses. The gen_statem + behavior still use a proxy process in the distributed + case, since it has always prevented late replies and + aliases won't work against pre OTP 24 nodes. The proxy + process can be removed in OTP 26.

+

+ The alias feature also made it possible to introduce new + functions similar to the erpc:receive_response() + function in the gen behaviors, so the new functions + gen_server:receive_response(), + gen_statem:receive_response(), + gen_event:receive_response() + have also been introduced.

+

+ Own Id: OTP-16718 Aux Id: PR-2735

+
+ +

+ Accept 64-bit process identifiers from external nodes. + This is the first step in an upgrade path toward using + 64-bit pids in a future OTP release.

+

+ Own Id: OTP-16720 Aux Id: PR-2680

+
+ +

The experimental new socket API has been further + developed. Some backwards incompatible changes with + respect to OTP 23 have been made.

The control + message format has been changed so a decoded value is now + in the 'value' field instead of in the 'data' field. The + 'data' field now always contains binary data.

+ Some type names have been changed regarding message + headers and control message headers.

+ socket:bind/2 now returns plain ok instead + of {ok, Port} which was only relevant for the + inet and inet6 address families and often + not interesting. To find out which port was chosen use + socket:sockname/1.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-16749 Aux Id: OTP-14601

+
+ +

+ Remove old unused +MYm and ERL_MALLOC_LIB + options.

+

+ Own Id: OTP-16788

+
+ +

+ Increase timer resolution on windows.

+

+ Own Id: OTP-16814 Aux Id: PR-2704

+
+ +

+ The code loader has been rewritten in order to be able to + load JIT:ed code. As a consequence of this, it is no + longer possible to load HiPE code.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-16878

+
+ +

+ Add support in the Erlang/OTP build system to generate a + compilation database that can be used by third-party + tools (such as irony in Emacs) to compile the erts C and + C++ source code. Create the database using make + compdb.

+

+ Own Id: OTP-16881

+
+ +

+ The BeamAsm JIT-compiler has been added to Erlang/OTP. + The JIT-compiler is enabled by default on most x86 64-bit + platforms that have a C++ compiler that can compile + C++17. To verify that a JIT enabled emulator is running + you can use erlang:system_info(emu_flavor).

+

+ For more information see the internal documentation of BeamAsm in + erts.

+

+ Own Id: OTP-16885 Aux Id: PR-2745

+
+ +

+ By default all ERTS internal memory allocators based on + alloc_util will now use their own separate carrier + pool for migration of carriers instead of using a node + global carrier pool. This was the default behavior + between OTP 17 and OTP 21, but changed to use a node + global carrier pool as of OTP 22.0. Usage of the node + global carrier pool proved troublesome since it had a + tendency to spread long lived blocks into allocators with + normally short lived blocks causing increased memory + fragmentation. The node global carrier pool behavior as + well as other behaviors can be configured using the + +M<S>cp + command line argument.

+

+ Own Id: OTP-16898 Aux Id: OTP-16856

+
+ +

+ New functions have been added to the maps module: + merge_with/3, intersect/2, + intersect_with/3, filtermap/2, + from_keys/2, and maps:foreach/2.

+

+ maps:merge_with/3 is the same as merge/2 + but takes an extra fun that is used to combine items with + the same key.

+

+ maps:intersect/2 computes the intersection of two + maps.

+

+ maps:intersect_with/3 is the same as + intersect/2 but takes an extra fun that is used to + combine intersecting items.

+

+ maps:filtermap/2 allows filtering and mapping of a + map in a single pass.

+

+ maps:from_keys/2 constructs a map from a list of + keys and a single value and can be used to to optimize + sets operations such as from_list/1, filter/2, + intersection/2, and subtract/2.

+

+ maps:foreach/2 allows iteration over a map without + returning any value.

+

+ Own Id: OTP-16936 Aux Id: ERL-1367

+
+ +

+ Change escripts to output any errors or warnings + to standard error instead of standard out.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-16945

+
+ +

+ A new erl parameter for specifying a file descriptor with + configuration data has been added. This makes it possible + to pass the parameter "-configfd FD" when executing the + erl command. When this option is given, the system will + try to read and parse configuration parameters from the + file descriptor.

+

+ Own Id: OTP-16952

+
+ +

The experimental HiPE application has been removed, + together with all related functionality in other + applications.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-16963

+
+ +

+ The pretty printer for floating point number have been + changed to make it easier to see if the integer part of + the number has been rounded. After the change the digit + that may have been rounded always appears last or just + before the exponent character (e or E). This is + accomplished by always printing the number using + scientific notation if it is so large that the integer + part could be rounded.

+

+ Own Id: OTP-16980 Aux Id: ERL-1308

+
+ +

The erlang:monitor_node/2 BIF will now fail + with a notalive exception if distribution has not + been started on the current node; it used to fail with a + badarg exception.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-16987

+
+ +

+ Accept references up to a size of 160-bits from remote + nodes. This is the first step in an upgrade path toward + using references up to 160-bits in a future OTP release.

+

+ Own Id: OTP-17005 Aux Id: OTP-16718

+
+ +

+ Accept 64-bit port identifiers from external nodes. This + is the first step in an upgrade path toward using 64-bit + port identifiers in a future OTP release.

+

+ Own Id: OTP-17007

+
+ +

+ One can now pass the ERL_ROOTDIR environment variable to + the erl and start scrips. This makes it easier to use + Erlang for Android apps. On Android, apps don't control + where they will be installed.

+

+ Own Id: OTP-17028

+
+ +

+ All long running functions in the maps API are now + yielding. In previous releases the functions + maps:from_list/1, maps:keys/1 and + maps:values/1 did not yield. This could cause + unfair scheduling of processes.

+

+ Own Id: OTP-17057

+
+ +

+ socket:sendfile/2,3,4,5 has been implemented, for + platforms that support the underlying socket library + call.

+

+ Own Id: OTP-17154 Aux Id: OTP-16749

+
+ +

The bit matching and construction syntax now supports + 16-bit floats (IEEE 754-2008).

+

+ Own Id: OTP-17207

+
+ +

+ Add process_flag(fullsweep_after, N) to change + fullsweep_after value in an already spawned + process.

+

+ Own Id: OTP-17285 Aux Id: PR-4651

+
+ +

+ The max_heap_size error report has been updated to + include the message queue size.

+

+ Own Id: OTP-17293 Aux Id: PR-4672

+
+ +

+ Introduce new types nonempty_binary() and + nonempty_bitstring().

+

+ Own Id: OTP-17301 Aux Id: GH-4636

+
+ +

Optimize updates of large maps with identical keys and + values. E.g. in the example below the original Map + will be reused as the return of the second update.

+

1> Map = LargeMap#{ a => b }.

2> + Map#{ a := b }.

The same optimization was done + for small maps (< 33 keys) in erts-10.4 (OTP + 22.0).

+

+ Own Id: OTP-17310 Aux Id: PR-4656

+
+ +

+ The previously undocumented internal -no_epmd + option has been made documented and public.

+

+ Own Id: OTP-17341 Aux Id: PR-2945

+
+ +

+ Reduce memory carrier super alignment on 64-bit + architectures. In practice allows more fine grained + control over configuration of memory carrier sizes, from + increments of 256kb to 16kb.

+

+ Own Id: OTP-17368

+
+
+
+ +
+ +
Erts 11.2.2.18 + +
Fixed Bugs and Malfunctions + + +

+ Fix list_to_atom/1 for negative code points. Could + either return with a positive code point or fail with an + incorrect exception.

+

+ Own Id: OTP-18321

+
+ +

+ A race condition which was very rarely triggered could + cause the signal queue of a process to become + inconsistent causing the runtime system to crash.

+

+ Own Id: OTP-18388 Aux Id: OTP-17462, PR-6662

+
+ +

+ process_info(Pid, status) when Pid /= + self() could return an erroneous result.

+

+ Own Id: OTP-18421 Aux Id: PR-6806

+
+ +

In rare circumstances, when a process exceeded its + allowed heap size set by option max_heap_size, it + would not be killed as it should be, but instead enter a + kind of zombie state it would never get out of.

+

+ Own Id: OTP-18463 Aux Id: PR-6858

+
+ +

+ Implementations of the call() + driver callback that returned a faulty encoded result + could cause a memory leak and could cause invalid data on + the heap of the processes calling erlang:port_call/3.

+

+ Own Id: OTP-18525 Aux Id: PR-7049

+
+ +

+ If a runtime system which was starting the distribution + already had existing pids, ports, or references referring + to a node with the same nodename/creation pair that the + runtime system was about to use, these already existing + pids, ports, or references would not work as expected in + various situations after the node had gone alive. This + could only occur if the runtime system was communicated + such pids, ports, or references prior to the distribution + was started. That is, it was extremely unlikely to happen + unless the distribution was started dynamically and was + even then very unlikely to happen. The runtime system now + checks for already existing pids, ports, and references + with the same nodename/creation pair that it is about to + use. If such are found another creation will be chosen in + order to avoid these issues.

+

+ Own Id: OTP-18570 Aux Id: PR-7190

+
+
+
+ +
+ +
Erts 11.2.2.17 + +
Fixed Bugs and Malfunctions + + +

+ Notifications + about available distribution data sent to + distribution controller processes could be lost. + Distribution controller processes can be used when + implementing an alternative distribution carrier. The + default distribution over tcp was not effected and the + bug was also not present on x86/x86_64 platforms.

+

+ Own Id: OTP-18258 Aux Id: GH-6309, PR-6324

+
+
+
+ +
+ +
Erts 11.2.2.16 + +
Fixed Bugs and Malfunctions + + +

Distributed exit signals could be lost under the + following conditions:

An exit signal + from a parent process to a child process was lost if:

+

the parent process terminated before the + spawn request that created the child had completed, +

the spawn request set up a link + between parent and child

the spawn + request was distributed, and

the + exit reason was larger than one machine word.

+

Loss of a connection over which + a not yet completed spawn request was ongoing could cause + loss of exit signals. Such loss of exit signals was very + rare. Besides the above described connection loss also + the following conditions had to be satisfied:

+

The spawn request that was interrupted by the + connection loss also had to set up a link between the + parent process and the child process.

+

The parent process that issued the spawn + request also had to be terminating while the spawn + request was interrupted by the connection loss. +

The same parent process also had to + have made other spawn requests to other nodes than to the + node to which the connection was lost.

+

These spawn requests to the other nodes also + had to set up links.

These spawn + requests to the other nodes also had to be not yet + completed at the time of the connection loss. That is, + the spawn reply from the child process had not yet + reached the parent process.

If all + the conditions above were met, exit signals to the + children spawned due to the above described spawn + requests to other nodes could be lost.

+

The above bug also caused a significant memory leak + when it was triggered since the destruction of the parent + process never completed.

+

+ Own Id: OTP-18164 Aux Id: PR-6114

+
+ +

+ A race could cause process_info(Pid, + message_queue_len) on other processes to return + invalid results.

+

+ Own Id: OTP-18169 Aux Id: PR-6134

+
+ +

+ Fixed reduction counting for handling process system + tasks.

+

+ Own Id: OTP-18170 Aux Id: PR-6135

+
+ +

+ Priority elevation of terminating processes did not work + which could cause execution of such processes to be + delayed.

+

+ Own Id: OTP-18175 Aux Id: PR-6142

+
+ +

+ An unlink operation made by a process that terminated + before the unlink operation completed, i.e., before it + had received an unlink-ack signal from the linked + process, caused an exit signal to erroneously be sent + from the terminating process to the process being + unlinked. This exit signal would most often be ignored by + the receiver, but if the receiver of the exit signal + concurrently set up a new link, it could receive the exit + signal with the actual exit reason of the terminating + process instead of a noproc exit reason. It is + however very hard to detect that this has happened and + has no obvious negative consequences, so it should be + considered harmless.

+

+ A distributed unlink-ack signal received by a terminating + process was also not properly removed which could cause a + minor memory leak.

+

+ Own Id: OTP-18177 Aux Id: PR-6150

+
+ +

+ The erlang:monotonic_time/1, + erlang:system_time/1, + erlang:time_offset/1, + and os:system_time/1 + BIFs erroneously failed when passed the argument + native.

+

+ Own Id: OTP-18197 Aux Id: GH-6165, PR-6213

+
+ +

+ Fix writing and reading of more than 2 GB in a single + read/write operation on macOS. Before this fix attempting + to read/write more than 2GB would result in + {error,einval}.

+

+ Own Id: OTP-18222 Aux Id: PR-6248 GH-6242

+
+
+
+ +
+ +
Erts 11.2.2.15 + +
Fixed Bugs and Malfunctions + + +

Fix faulty distribution encoding of terms with + either

a fun with bit-string or + export-fun in its environment when encoded toward a not + yet established (pending) connection or a + fun with a binary/bitstring, in its environment, + referring to an off-heap binary (larger than 64 + bytes).

The symptom could be failed + decoding on the receiving side leading to aborted + connection. Fix OTP-18093 is a workaround for theses bugs + that makes the VM accepts such faulty encoded funs.

+

The first encoding bug toward pending connection + exists only in OTP 23 and 24, but the second one exists + also on OTP 25.

+

+ Own Id: OTP-18104 Aux Id: OTP-18093

+
+
+
+ +
+ +
Erts 11.2.2.14 + +
Fixed Bugs and Malfunctions + + +

+ Accept funs (NEW_FUN_EXT) with incorrectly encoded size + field. This is a workaround for a bug (OTP-18104) + existing in OTP 23 and 24 that could cause incorrect size + fields in certain cases. The emulator does not use the + decoded size field, but erl_interface still does + and is not helped by this workaround.

- Own Id: OTP-17005 Aux Id: OTP-16718

+ Own Id: OTP-18093 Aux Id: OTP-18104, PR-5987

- Accept 64-bit port identifiers from external nodes. This - is the first step in an upgrade path toward using 64-bit - port identifiers in a future OTP release.

+ The zlib built in to the runtime system has been updated + to version 1.2.12. (Note that on most platforms, the + platform's own zlib is used.)

- Own Id: OTP-17007

+ Own Id: OTP-18123 Aux Id: GH-5994

- One can now pass the ERL_ROOTDIR environment variable to - the erl and start scrips. This makes it easier to use - Erlang for Android apps. On Android, apps don't control - where they will be installed.

+ Fixed emulator crash that could happen during crashdump + generation of ETS tables with options ordered_set + and {write_concurrency,true}.

- Own Id: OTP-17028

+ Own Id: OTP-18144 Aux Id: GH-5981

+
+
+ +
+ +
Erts 11.2.2.13 + +
Fixed Bugs and Malfunctions +

- All long running functions in the maps API are now - yielding. In previous releases the functions - maps:from_list/1, maps:keys/1 and - maps:values/1 did not yield. This could cause - unfair scheduling of processes.

+ Let EPMD tolerate failure when binding to IPv4/IPv6 + loopback intefaces in addition to user-supplied addresses + via ERL_EPMD_ADDRESS or the -address + option. This can happen, for example, if the host system + has ipv6 disabled via the disable_ipv6 sysctl.

- Own Id: OTP-17057

+ Own Id: OTP-17970 Aux Id: PR-5762

+

Fixed a rare bug in binary_to_term/1, + enif_make_map_from_arrays, + erl_drv_send_term, and Erlang distribution that + could crash the emulator.

- socket:sendfile/2,3,4,5 has been implemented, for - platforms that support the underlying socket library - call.

-

- Own Id: OTP-17154 Aux Id: OTP-16749

+ Own Id: OTP-18027

-

The bit matching and construction syntax now supports - 16-bit floats (IEEE 754-2008).

+

Fixed a rare race in persistent_term:get/1,2 + that could cause it to return the value of another + key.

- Own Id: OTP-17207

+ Own Id: OTP-18065 Aux Id: GH-5908

- Add process_flag(fullsweep_after, N) to change - fullsweep_after value in an already spawned - process.

+ Fix bug where the process message queue was left in an + inconsistent state when changing from on_heap to off_heap + message queue data causing the GC to segfault.

- Own Id: OTP-17285 Aux Id: PR-4651

+ Own Id: OTP-18075 Aux Id: PR-5927

- The max_heap_size error report has been updated to - include the message queue size.

+ Fix functions that convert universal to localtime (such + as erlang:localtime/0 and + erlang:universaltime_to_localtime/1) to fetch the correct + localtime if it is changed after the start of the VM.

- Own Id: OTP-17293 Aux Id: PR-4672

+ Own Id: OTP-18076 Aux Id: ERIERL-802 PR-5905

- Introduce new types nonempty_binary() and - nonempty_bitstring().

+ Fix memory leak when a process doing a distributed + fragmented send is sent an exit signal. Before this fix + the receiving node would be left with an incomplete + message that would remain until the nodes were + disconnected. The bug has existed since Erlang/OTP 21.

- Own Id: OTP-17301 Aux Id: GH-4636

+ Own Id: OTP-18077 Aux Id: GH-5876 PR-5892

+
+
+ +
+ +
Erts 11.2.2.12 + +
Fixed Bugs and Malfunctions + -

Optimize updates of large maps with identical keys and - values. E.g. in the example below the original Map - will be reused as the return of the second update.

-

1> Map = LargeMap#{ a => b }.

2> - Map#{ a := b }.

The same optimization was done - for small maps (< 33 keys) in erts-10.4 (OTP - 22.0).

- Own Id: OTP-17310 Aux Id: PR-4656

+ Fix Erlang monotonic time on MacOS. Previously used OS + monotonic time primitive on MacOS is buggy and will not + be used anymore. It has been replaced with usage of + another OS monotonic time primitive that does not appear + to be buggy.

+

+ Own Id: OTP-17998 Aux Id: PR-5825, GH-5554

+
+
+ +
+ +
Erts 11.2.2.11 + +
Fixed Bugs and Malfunctions + +

By default global does not take any + actions to restore a fully connected network when + connections are lost due to network issues. This is + problematic for all applications expecting a fully + connected network to be provided, such as for example + mnesia, but also for global itself. A + network of overlapping partitions might cause the + internal state of global to become inconsistent. + Such an inconsistency can remain even after such + partitions have been brought together to form a fully + connected network again. The effect on other applications + that expects that a fully connected network is maintained + may vary, but they might misbehave in very subtle hard to + detect ways during such a partitioning.

In order + to prevent such issues, we have introduced a prevent + overlapping partitions fix which can be enabled using + the prevent_overlapping_partitions + kernel(6) parameter. When this fix has been + enabled, global will actively disconnect from + nodes that reports that they have lost connections to + other nodes. This will cause fully connected partitions + to form instead of leaving the network in a state with + overlapping partitions. Note that this fix has to + be enabled on all nodes in the network in order to + work properly. Since this quite substantially changes the + behavior, this fix is currently disabled by default. + Since you might get hard to detect issues without this + fix you are, however, strongly advised to enable + this fix in order to avoid issues such as the ones + described above. As of OTP 25 this fix will become + enabled by default.

- The previously undocumented internal -no_epmd - option has been made documented and public.

-

- Own Id: OTP-17341 Aux Id: PR-2945

+ Own Id: OTP-17843 Aux Id: ERIERL-732, PR-5611

- Reduce memory carrier super alignment on 64-bit - architectures. In practice allows more fine grained - control over configuration of memory carrier sizes, from - increments of 256kb to 16kb.

+ Fix memory leak when tracing on running on a process that + only handle system tasks or non-message signals (for + example process_info requests).

- Own Id: OTP-17368

+ Own Id: OTP-17904 Aux Id: ERIERL-757

@@ -2220,7 +5130,7 @@ simultaneously received signals to that port could cause a runtime system crash. The effected signals are link, monitor and demonitor. On OTP - 22 a similiar race could also cause a memory leak when + 22 a similar race could also cause a memory leak when receiving an unlink signal.

Own Id: OTP-17642 Aux Id: PR-5248

@@ -3464,7 +6374,7 @@

Internally in BEAM, handling of continuation pointers has been simplified. This change is not user-visible, - except when examing a process stack in the crashdump + except when examining a process stack in the crashdump viewer. The continuation pointer for a function will now be stored below the y(0) for that function.

@@ -3898,6 +6808,104 @@

+
Erts 10.7.2.18 + +
Fixed Bugs and Malfunctions + + +

+ Fix bug where the process message queue was left in an + inconsistent state when changing from on_heap to off_heap + message queue data causing the GC to segfault.

+

+ Own Id: OTP-18075 Aux Id: PR-5927

+
+ +

+ Fix functions that convert universal to localtime (such + as erlang:localtime/0 and + erlang:universaltime_to_localtime/1) to fetch the correct + localtime if it is changed after the start of the VM.

+

+ Own Id: OTP-18076 Aux Id: ERIERL-802 PR-5905

+
+ +

+ Fix memory leak when a process doing a distributed + fragmented send is sent an exit signal. Before this fix + the receiving node would be left with an incomplete + message that would remain until the nodes were + disconnected. The bug has existed since Erlang/OTP 21.

+

+ Own Id: OTP-18077 Aux Id: GH-5876 PR-5892

+
+
+
+ +
+ +
Erts 10.7.2.17 + +
Fixed Bugs and Malfunctions + + +

By default global does not take any + actions to restore a fully connected network when + connections are lost due to network issues. This is + problematic for all applications expecting a fully + connected network to be provided, such as for example + mnesia, but also for global itself. A + network of overlapping partitions might cause the + internal state of global to become inconsistent. + Such an inconsistency can remain even after such + partitions have been brought together to form a fully + connected network again. The effect on other applications + that expects that a fully connected network is maintained + may vary, but they might misbehave in very subtle hard to + detect ways during such a partitioning.

In order + to prevent such issues, we have introduced a prevent + overlapping partitions fix which can be enabled using + the prevent_overlapping_partitions + kernel(6) parameter. When this fix has been + enabled, global will actively disconnect from + nodes that reports that they have lost connections to + other nodes. This will cause fully connected partitions + to form instead of leaving the network in a state with + overlapping partitions. Note that this fix has to + be enabled on all nodes in the network in order to + work properly. Since this quite substantially changes the + behavior, this fix is currently disabled by default. + Since you might get hard to detect issues without this + fix you are, however, strongly advised to enable + this fix in order to avoid issues such as the ones + described above. As of OTP 25 this fix will become + enabled by default.

+

+ Own Id: OTP-17843 Aux Id: ERIERL-732, PR-5611

+
+ +

+ Fix memory leak when tracing on running on a process that + only handle system tasks or non-message signals (for + example process_info requests).

+

+ Own Id: OTP-17904 Aux Id: ERIERL-757

+
+ +

+ Fix Erlang monotonic time on MacOS. Previously used OS + monotonic time primitive on MacOS is buggy and will not + be used anymore. It has been replaced with usage of + another OS monotonic time primitive that does not appear + to be buggy.

+

+ Own Id: OTP-17998 Aux Id: PR-5825, GH-5554

+
+
+
+ +
+
Erts 10.7.2.16
Improvements and New Features @@ -3994,7 +7002,7 @@ simultaneously received signals to that port could cause a runtime system crash. The effected signals are link, monitor and demonitor. On OTP - 22 a similiar race could also cause a memory leak when + 22 a similar race could also cause a memory leak when receiving an unlink signal.

Own Id: OTP-17642 Aux Id: PR-5248

@@ -8334,7 +11342,7 @@ cpu_timestamp in erlang:trace/3 to use it instead of per process CPU time. This makes this - option useable on such OSs when running multiple + option usable on such OSs when running multiple schedulers.

Own Id: OTP-15090

@@ -8378,7 +11386,7 @@

- Fix segfault when a process is interally re-scheduled + Fix segfault when a process is internally re-scheduled while being traced for in out events. This bug was introduced in erts-8.0 (OTP-19.0).

@@ -8929,7 +11937,7 @@ request signal to the other process and waits for the result instead of locking the other process and reading the result directly. In some special cases where no - conflicts occur, signal order wont be violated, and the + conflicts occur, signal order won't be violated, and the amount of data requested is guaranteed to be small, the inspected process may be inspected directly.

@@ -11146,7 +14154,7 @@

Add option to make SIGTERM trigger the OS default - behaviour instead of doing a gracefull shutdown. To + behaviour instead of doing a graceful shutdown. To activate this bahviour the environment variable ERL_ZZ_SIGTERM_KILL should be set to "true". This option only works in OTP 19 as OTP 20 will have a different way @@ -11475,9 +14483,9 @@

Fix a quite rare bug causing VM crash during code loading and the use of export funs (fun M:F/A) of not yet loaded - modules. Requires a very specfic timing of concurrent + modules. Requires a very specific timing of concurrent scheduler threads. Has been seen on ARM but can probably - also occure on other architectures. Bug has existed since + also occurred on other architectures. Bug has existed since OTP R16.

Own Id: OTP-14144 Aux Id: seq13242

@@ -11781,7 +14789,7 @@

- Update build scripts to not make assumtions about where + Update build scripts to not make assumptions about where env, cp and perl are located.

Own Id: OTP-13800

@@ -13656,7 +16664,7 @@

Fix global call trace when hipe compiled code call beam compiled functions. Tracing of beam functions should now - alway work regardless who the caller is.

+ always work regardless who the caller is.

Own Id: OTP-11939

@@ -14032,7 +17040,7 @@

Development of perfctr in the linux kernel ceased in 2010. The perfctr support code in the Erlang VM is thus - effectively dead code and therefor removed.

+ effectively dead code and therefore removed.

Own Id: OTP-12508

@@ -14677,7 +17685,7 @@

Fix two cases of unreachable code caused by false use of - assigment operators.

+ assignment operators.

Own Id: OTP-12222

@@ -15731,11 +18739,11 @@ Characteristics impact: A call to the garbage_collect/1 BIF or the check_process_code/2 BIF will normally take longer - time to complete while the system as a whole wont be as + time to complete while the system as a whole won't be as much negatively effected by the operation as before. A call to code:purge/1 and code:soft_purge/1 may complete faster or slower depending on the state of - the system while the system as a whole wont be as much + the system while the system as a whole won't be as much negatively effected by the operation as before.

Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648

@@ -16729,7 +19737,7 @@ system:

Reduced memory footprint when the memory load is unevenly distributed between scheduler specific allocator instances. Depending on - the default allocaton strategy used on a specific + the default allocation strategy used on a specific allocator there might or might not be a slight performance loss. When enabled on the fix_alloc allocator, a different strategy for @@ -17011,7 +20019,7 @@ Memory leak when terminating ports Memory leak when reaching the system limit of maximum amount of concurrently existing ports - Crashs due to missing, or late test of bad port + Crashes due to missing, or late test of bad port handle The newly introduced driver API function erl_drv_busy_msgq_limits() could not be used by dynamically linked in drivers on Windows @@ -17022,7 +20030,7 @@

Fix {packet,httph} header capitalization for - unrecognized header fields longer than 20 charachters + unrecognized header fields longer than 20 characters such as Sec-Websocket-Version. The limit is simply raised from 20 to 50 characters with the hope that valid headers longer than 50 are not used.

@@ -17220,7 +20228,7 @@ For instance, prefer sbc segments over mbc segments, caching policy is time-arrow aware, evicting older cached segments to store newer segments.

The default - number of cachable segment has been increased from five + number of cacheable segment has been increased from five to ten segments. This can be modified, same as before, with the command line option +MMmcs 5

Impact: Increased speed for processing on larger @@ -17295,8 +20303,8 @@

The effect of the deprecated environment variable - ERL_MAX_PORTS had been removed premeturely. It has now - been readded. Note that this is still scheduled to be + ERL_MAX_PORTS had been removed prematurely. It has now + been re-added. Note that this is still scheduled to be released in R17B.

Own Id: OTP-10895

@@ -17524,7 +20532,7 @@ port lock as well as truly asynchronous communication with ports.
Optimized lookup of port handles from drivers. Optimized driver lookup when - creating ports. Preemptable Preemptible erlang:ports/0 BIF. Improving responsiveness by bumping reductions for a process calling a driver callback @@ -18086,7 +21094,7 @@

- Correct formating in exit error messages

+ Correct formatting in exit error messages

Ensure displayed sizes are not negative. (Thanks to Michael Santos)

@@ -18443,7 +21451,7 @@
Fixed Bugs and Malfunctions -

erlang:system_profile errorneous profiled the +

erlang:system_profile erroneous profiled the profiler process when observing runnable processes. This has been corrected.

@@ -18524,7 +21532,7 @@ and async threads operations when you exit the emulator, you use erlang:halt/2 with an integer first argument and an option list containing {flush,false} as the second - argument. Note that now is flushing not dependant of the + argument. Note that now is flushing not dependent of the exit code, and you cannot only flush async threads operations which we deemed as a strange behaviour anyway.

@@ -20835,7 +23843,7 @@

epmd used to generate a message to the syslog when it started up, which could be annoying. This has been - changed to only generate the message if the debug swith + changed to only generate the message if the debug switch is given. (Thanks to Michael Santos.)

Own Id: OTP-8775

@@ -21011,7 +24019,7 @@

Extreme combinations of register/unregister in a highly - parallell SMP application could crash the VM. The error + parallel SMP application could crash the VM. The error is corrected.

Own Id: OTP-8663

@@ -21255,7 +24263,7 @@

Support for using gcc's built-in functions for atomic - memory access has been added. This functionallity will be + memory access has been added. This functionality will be used if available and no other native atomic implementation in ERTS is available.

@@ -21736,7 +24744,7 @@ GC. See the documentation for spawn_opt/2-5, erlang:system_info/1, erlang:system_flag/2, process_flag/2-3, erlang:trace/3, and the - documenation for erl for the new command line + documentation for erl for the new command line options +hms and +hmbs.

Own Id: OTP-8370

@@ -21766,7 +24774,7 @@ app-vsn/ebin/mod.beam file, the file info for the app-vsn and app-vsn/ebin directories are faked using the file info from the archive file as origin. The virtual - direcories can also be listed. For short, the top + directories can also be listed. For short, the top directories are virtual if they does not exist.

Own Id: OTP-8387

@@ -22189,7 +25197,7 @@

- The pthread rwlock implemention on Linux could cause + The pthread rwlock implementation on Linux could cause starvation of writers. We, therefore, now use our own rwlock implementation on Linux.

@@ -23275,7 +26283,7 @@

- Floating point arithmetics in drivers could cause a + Floating point arithmetic in drivers could cause a runtime system crash and/or unexpected results on runtime systems with floating point exceptions enabled. Floating point exceptions are disabled unless explicitly enabled @@ -23287,7 +26295,7 @@

A bug when many sockets got signalled simultaneously causing the emulator to panic with the message - "Inconsistent, why isnt io reported?" is now corrected.

+ "Inconsistent, why isn't io reported?" is now corrected.

Own Id: OTP-7420

@@ -23745,7 +26753,7 @@

- Floating point arithmetics in drivers can cause a runtime + Floating point arithmetic in drivers can cause a runtime system crash and/or unexpected results on runtime systems with floating point exceptions enabled. Floating point exceptions are disabled unless explicitly enabled or if @@ -24071,7 +27079,7 @@

- Floating point arithmetics in drivers can cause a runtime + Floating point arithmetic in drivers can cause a runtime system crash on runtime systems with floating point exceptions enabled. Floating point exceptions are disabled unless explicitly enabled or if hipe is enabled.

@@ -25123,7 +28131,7 @@

Attempting to construct a binary longer than 536870911 bytes will now fail with a exception (rather than fail in mysterious ways or construct an - binary with incorrect contents). Similarily, attempting + binary with incorrect contents). Similarly, attempting to match a binary longer than 536870911 bytes will now fail (instead of producing an incorrect result). This limitation has been documented in the Efficiency Guide. diff --git a/erts/doc/src/persistent_term.xml b/erts/doc/src/persistent_term.xml index 46cb313ff1b2..c2e967b6946d 100644 --- a/erts/doc/src/persistent_term.xml +++ b/erts/doc/src/persistent_term.xml @@ -4,7 +4,7 @@

- 20182020 + 20182022 Ericsson AB. All Rights Reserved. @@ -50,7 +50,7 @@ performance when updating or deleting persistent terms.

Term lookup (using get/1), is done in constant time + marker="#get/1">get/1) is done in constant time and without taking any locks, and the term is not copied to the heap (as is the case with terms stored in ETS tables).

@@ -71,7 +71,7 @@ scan of their heaps for the term that has been deleted. While such scan is relatively light-weight, if there are many processes, the system can become less responsive until all - process have scanned their heaps.

+ processes have scanned their heaps.

If the deleted term (or any part of it) is still used by a process, that process will do a major (fullsweep) garbage @@ -146,7 +146,7 @@

Updating or deleting a persistent term will trigger a global GC if the term does not fit in one machine word. Processes will be scheduled as usual, but all processes will be made runnable at - once, which will make the system less responsive until all process + once, which will make the system less responsive until all processes have run and scanned their heaps for the deleted terms. One way to minimize the effects on responsiveness could be to minimize the number of processes on the node before updating or deleting a @@ -157,7 +157,7 @@ persistent term could be deleted or updated in the future. If a process holds a reference to a persistent term when the term is deleted, the process will be garbage collected and the term copied - to process.

+ to the process.

Avoid updating or deleting more than one persistent term at a time. Each deleted term will trigger its own global GC. That diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml index b3a36b907e7c..30c514c1a3f8 100644 --- a/erts/doc/src/time_correction.xml +++ b/erts/doc/src/time_correction.xml @@ -4,7 +4,7 @@

- 19992021 + 19992023 Ericsson AB. All Rights Reserved. @@ -34,29 +34,42 @@
- New Extended Time Functionality -

As from Erlang/OTP 18 (ERTS 7.0) the time functionality - has been extended. This includes a + Extended Time Functionality + +

As of Erlang/OTP 18 (ERTS 7.0) the time functionality + was extended. This includes a new API for time and time warp modes that change the system behavior when system time changes.

-

The default - time warp mode has the same behavior as before, and the - old API still works. Thus, you are not required to change - anything unless you want to. However, you are strongly - encouraged to use the new API instead of the old API based - on erlang:now/0. - erlang:now/0 is deprecated, as it is and - will be a scalability bottleneck.

- -

By using the new API, you - automatically get scalability and performance improvements. This - also enables you to use the - multi-time warp mode - that improves accuracy and precision of time measurements.

+ +

+ As of Erlang/OTP 26 (ERTS 14.0) the + multi time warp + mode is enabled by default. This assumes that all + code executing on the system is + time warp safe. +

+

+ If you have old code in the system that is not time warp + safe, you now explicitly need to start the system in + no time warp + mode (or + singe time warp + mode if it is partially time warp safe) in order + to avoid problems. When starting the system in no time warp + mode, the system behaves as it did prior to the introduction + of the extended time functionality introduced in OTP 18. +

+

+ If you have code that is not time warp safe, you are strongly + encouraged to change this so that you can use multi time + warp mode. Compared to no time warp mode, multi time warp + mode improves scalability and performance as well as accuracy + and precision of time measurements. +

@@ -405,13 +418,9 @@
No Time Warp Mode

The time offset is determined at runtime system start - and does not change later. This is the default behavior, but - not because it is the best mode (which it is not). It is - default only because this is how the runtime system - behaved until ERTS 7.0. - Ensure that your Erlang code that can execute during a time - warp is time warp - safe before enabling other modes.

+ and does not change later. This is the same behavior as was + default prior to OTP 26 (ERTS 14.0), and the only behavior + prior to OTP 18 (ERTS 7.0).

As the time offset is not allowed to change, time correction must adjust the frequency of the Erlang @@ -558,7 +567,8 @@ better, and behave better on almost all platforms. Also, the accuracy and precision of time measurements are better. Only Erlang runtime systems executing on - ancient platforms benefit from another configuration.

+ ancient platforms benefit from another configuration. + As of OTP 26 (ERTS 14.0) this is also the default.

The time offset can change at any time without limitations. That is, Erlang system time can perform time warps both diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml index e82e2cc80748..a14e3a2b1de9 100644 --- a/erts/doc/src/tty.xml +++ b/erts/doc/src/tty.xml @@ -4,7 +4,7 @@

- 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -41,13 +41,17 @@
 erl
-

operates in one of two modes:

+

operates in several different modes:

Normal mode, in which text lines can be edited and sent to the shell.

+ +

Search mode, in which the user can search for previous commands in + the history buffer.

+

Shell break mode, which allows the user to kill the current shell, start multiple shells, and so on.

@@ -66,12 +70,17 @@ erl
C-a means pressing the Ctrl key and the letter a simultaneously. + C-S-a means pressing the Ctrl key, the Shift + key, and the letter a simultaneously. M-f means pressing the Esc key and the letter - f in sequence. + f in sequence or pressing the Alt key and the letter + f simultaneously.
Home and End represent the keys with the same name on the keyboard. - Left and Right represent the corresponding arrow - keys. + Left, Right, Up and Down represent + the corresponding arrow keys. + When a function has multiple possible key sequences they are + listed on individual lines in the Key Sequence column. @@ -92,7 +101,7 @@ erlBackward character - C-Left + C-Left
M-Left
Backward word
@@ -120,7 +129,7 @@ erl Forward character - C-Right + C-Right
M-Right
Forward word
@@ -141,6 +150,14 @@ erl C-l + Clears the screen + + + M-c + Clears the current expression + + + M-l Redraw line @@ -148,11 +165,26 @@ erl Fetch next line from the history buffer + + C-o
M-o
+ Edit the current line using the editor specified in + the environment variable VISUAL or EDITOR. The environment variables can + contain arguments to the editor if needed, for example VISUAL="emacs -nw". + On Windows the editor cannot be a console based editor. +
C-p Fetch previous line from the history buffer + + C-r + Enter search mode and then search backward in the shell history + + + C-s + In search mode, search forward in the shell history + C-t Transpose characters @@ -169,6 +201,34 @@ erl C-] Insert matching closing bracket + + C-Up
M-Up
+ Navigate one row up when editing multiple lines +
+ + C-Down
M-Down
+ Navigate one row down when editing multiple lines +
+ + M-Enter + Insert a new line at cursor + + + M-<
M-S-Up
+ Navigate to the start of the current expression +
+ + M->
M-S-Down
+ Navigate to the end of the current expression +
+ + Tab
C-i
+ Autocomplete current expression, or show completion suggestions +
+ + M-c + Clear current expression + tty Text Editing
diff --git a/erts/emulator/Makefile b/erts/emulator/Makefile index 65fdbdb74762..b1a363082c20 100644 --- a/erts/emulator/Makefile +++ b/erts/emulator/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2016. All Rights Reserved. +# Copyright Ericsson AB 1997-2021. 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. @@ -23,3 +23,5 @@ include $(ERL_TOP)/make/run_make.mk +include $(ERL_TOP)/make/app_targets.mk + diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 99da2b101ed0..0ca5128de18a 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2022. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -33,6 +33,7 @@ LIBS = @LIBS@ Z_LIB=@Z_LIB@ CROSS_COMPILING = @CROSS_COMPILING@ NO_INLINE_FUNCTIONS=false +USING_VC=@MIXED_VC@ OPCODE_TABLES = \ $(ERL_TOP)/lib/compiler/src/genop.tab \ @@ -56,7 +57,7 @@ JIT_ENABLED=no endif ifeq ($(FLAVOR),jit) -OMIT_OMIT_FP=no +OMIT_OMIT_FP=yes OPCODE_TABLES += \ beam/jit/$(JIT_ARCH)/ops.tab \ beam/jit/$(JIT_ARCH)/predicates.tab \ @@ -202,8 +203,10 @@ space+= STATIC_NIFS=@STATIC_NIFS@ ifneq ($(STATIC_NIFS),no) ifeq ($(STATIC_NIFS),yes) -STATIC_NIFS=$(ERL_TOP)/lib/asn1/priv/lib/$(TARGET)/asn1rt_nif.a \ - $(ERL_TOP)/lib/crypto/priv/lib/$(TARGET)/crypto$(TYPEMARKER).a +STATIC_NIFS=$(ERL_TOP)/lib/asn1/priv/lib/$(TARGET)/asn1rt_nif.a +ifeq ($(wildcard $(ERL_TOP)/lib/crypto/SKIP),) + STATIC_NIFS+=$(ERL_TOP)/lib/crypto/priv/lib/$(TARGET)/crypto$(TYPEMARKER).a +endif endif STATIC_NIFS:=$(subst $(comma),$(space),$(STATIC_NIFS)) endif @@ -218,7 +221,7 @@ endif # -# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c +# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys_drivers.c # FLAVOR_MARKER=.$(FLAVOR) @@ -239,9 +242,6 @@ VOID_EMULATOR = endif OPSYS=@OPSYS@ -ifeq ($(OPSYS),darwin) -LDFLAGS += -sectcreate __TEXT __info_plist "$(ERL_TOP)/erts/etc/darwin/Info.plist" -endif sol2CFLAGS= linuxCFLAGS= @@ -371,6 +371,14 @@ endif EPCRE_LIB = $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/$(LIB_PREFIX)epcre$(LIB_SUFFIX) DEPLIBS += $(EPCRE_LIB) +DEPLIBS += $(RYU_LIBRARY) +ifeq ($(TARGET),win32) +LIBS += -L$(RYU_OBJDIR) -lryu +else +# Build on darwin fails if -lryu is used +LIBS += $(RYU_LIBRARY) +endif + LIBSCTP = @LIBSCTP@ ORG_THR_LIBS=@EMU_THR_LIBS@ @@ -412,7 +420,8 @@ OBJDIR = obj/$(TTF_DIR) CREATE_DIRS += $(OBJDIR) \ pcre/obj/$(TARGET)/$(TYPE) \ - $(ZLIB_OBJDIR) + $(ZLIB_OBJDIR) \ + $(RYU_OBJDIR) ifeq ($(FLAVOR),jit) CREATE_DIRS+=$(OBJDIR)/asmjit/ $(OBJDIR)/asmjit/core $(OBJDIR)/asmjit/$(JIT_ARCH) @@ -420,6 +429,7 @@ CREATE_DIRS+=$(TTF_DIR)/asmjit $(TTF_DIR)/asmjit/core $(TTF_DIR)/asmjit/$(JIT_AR endif BINDIR = $(ERL_TOP)/bin/$(TARGET) +CREATE_DIRS += $(BINDIR) ERLANG_OSTYPE = @ERLANG_OSTYPE@ @@ -427,8 +437,10 @@ ENABLE_ALLOC_TYPE_VARS += @ERLANG_OSTYPE@ ifeq ($(TARGET), win32) FLAVOR_EXECUTABLE = beam$(TF_MARKER).dll +EMULATOR_LIB = libbeam.lib else FLAVOR_EXECUTABLE = beam$(TF_MARKER) +EMULATOR_LIB = libbeam.a PROFILE_EXECUTABLE = beam.prof$(TF_MARKER) endif CS_EXECUTABLE = erl_child_setup$(TYPEMARKER) @@ -467,7 +479,7 @@ ifdef VOID_EMULATOR all: @echo $(VOID_EMULATOR)' - omitted target all' else -all: $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS) +all: $(BINDIR)/$(EMULATOR_EXECUTABLE) $(BINDIR)/$(EMULATOR_LIB) $(UNIX_ONLY_BUILDS) endif $(BINDIR)/$(PRIMARY_EXECUTABLE): $(BINDIR)/$(FLAVOR_EXECUTABLE) @@ -478,6 +490,7 @@ endif include zlib/zlib.mk include pcre/pcre.mk +include ryu/ryu.mk $(ERTS_LIB): $(V_at)cd $(ERTS_LIB_DIR) && $(MAKE) $(TYPE) @@ -490,6 +503,7 @@ clean: $(RM) -r obj/$(TARGET) $(RM) -r pcre/obj/$(TARGET) $(PCRE_GENINC) $(RM) -r zlib/obj/$(TARGET) + $(RM) -r ryu/obj/$(TARGET) $(RM) -r bin/$(TARGET) cd $(ERTS_LIB_DIR) && $(MAKE) clean @@ -522,6 +536,10 @@ release_spec: all $(INSTALL_DATA) $(RELEASE_INCLUDES) "$(RELEASE_PATH)/usr/include" $(INSTALL_DATA) $(RELEASE_INCLUDES) "$(RELSYSDIR)/include" $(INSTALL_PROGRAM) $(BINDIR)/$(EMULATOR_EXECUTABLE) "$(RELSYSDIR)/bin" +ifeq ($(RELEASE_LIBBEAM),yes) + $(INSTALL_DIR) "$(RELSYSDIR)/lib" + $(INSTALL_PROGRAM) $(BINDIR)/$(EMULATOR_LIB) "$(RELSYSDIR)/lib" +endif ifeq ($(ERLANG_OSTYPE), unix) $(INSTALL_PROGRAM) $(BINDIR)/$(CS_EXECUTABLE) "$(RELSYSDIR)/bin" endif @@ -575,6 +593,11 @@ $(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops -emulator $(OPCODE_TABLES) && echo $? >$(TTF_DIR)/OPCODES-GENERATED GENERATE += $(TTF_DIR)/OPCODES-GENERATED +ifeq ($(FLAVOR),jit) +$(TTF_DIR)/beam_asm_global.hpp: beam/jit/$(JIT_ARCH)/beam_asm_global.hpp.pl + $(gen_verbose)LANG=C $(PERL) $< > $@ +GENERATE += $(TTF_DIR)/beam_asm_global.hpp +endif # bif and atom table ATOMS= beam/atom.names @@ -696,7 +719,7 @@ ASMJIT_H = $(wildcard asmjit/*.h) $(wildcard asmjit/core/*.h) $(wildcard asmjit/ ASMJIT_TTF_H = $(foreach HEADER,$(ASMJIT_H),$(TTF_DIR)/$(HEADER)) ifeq ($(FLAVOR),jit) -GENERATE+=$(ASMJIT_TTF_H) +GENERATE+=$(ASMJIT_TTF_H) $(TTF_DIR)/asmjit/asmjit.hpp endif # Preloaded code. @@ -704,14 +727,10 @@ endif # This list must be consistent with PRE_LOADED_MODULES in # erts/preloaded/src/Makefile. -ifeq ($(USE_ESOCK), yes) ESOCK_PRELOAD_BEAM = \ $(ERL_TOP)/erts/preloaded/ebin/socket_registry.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_socket.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_net.beam -else -ESOCK_PRELOAD_BEAM = -endif PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \ $(ERL_TOP)/erts/preloaded/ebin/erl_init.beam \ @@ -774,6 +793,7 @@ ifndef Z_LIB COMMON_INCLUDES += -Izlib endif COMMON_INCLUDES += -Ipcre +COMMON_INCLUDES += -Iryu COMMON_INCLUDES += -I../include -I../include/$(TARGET) COMMON_INCLUDES += -I../include/internal -I../include/internal/$(TARGET) @@ -903,24 +923,30 @@ $(OBJDIR)/%.o: nifs/$(ERLANG_OSTYPE)/%.c # included before any other directives, including other #includes. # ASMJIT_FLAGS=-DASMJIT_EMBED=1 -DASMJIT_NO_BUILDER=1 -DASMJIT_NO_DEPRECATED=1 -DASMJIT_STATIC=1 -DASMJIT_NO_FOREIGN=1 + ASMJIT_PCH_OBJ=$(TTF_DIR)/asmjit/asmjit.hpp.gch ASMJIT_PCH_SRC=$(TTF_DIR)/asmjit/asmjit.hpp +$(OBJDIR)/%.o: beam/jit/%.cpp $(ASMJIT_PCH_OBJ) + $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ + $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ + -include $(ASMJIT_PCH_SRC) -c $< -o $@ + $(OBJDIR)/%.o: beam/jit/$(JIT_ARCH)/%.cpp beam/jit/$(JIT_ARCH)/beam_asm.hpp $(ASMJIT_PCH_OBJ) - $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ - $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ + $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ + $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ -include $(ASMJIT_PCH_SRC) -c $< -o $@ $(OBJDIR)/asmjit/%.o: asmjit/%.cpp $(ASMJIT_PCH_OBJ) $(dir $@) - $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ - $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ + $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ + $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ -include $(ASMJIT_PCH_SRC) -c $< -o $@ ## The dependency on erl_bif_info.c is in order to trigger a rebuild when ## the git sha define on the command line argument changes $(ASMJIT_PCH_OBJ): $(ASMJIT_PCH_SRC) $(ASMJIT_TTF_H) beam/erl_bif_info.c - $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ - $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ + $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ + $(subst -O2, $(GEN_OPT_FLGS), $(CXXFLAGS)) \ -I$(TTF_DIR) -c $< -o $@ ## We copy all asmjit headers into TTF_DIR in order for cross-compilation @@ -992,21 +1018,37 @@ COMMON_OBJS = \ ASMJIT_OBJS = $(patsubst %.cpp,$(OBJDIR)/%.o,$(ASMJIT_CPP)) JIT_OBJS = \ - $(OBJDIR)/asm_load.o \ - $(OBJDIR)/beam_jit_common.o + $(OBJDIR)/asm_load.o \ + $(OBJDIR)/beam_asm_global.o \ + $(OBJDIR)/beam_asm_module.o \ + $(OBJDIR)/beam_jit_common.o \ + $(OBJDIR)/beam_jit_main.o \ + $(OBJDIR)/beam_jit_metadata.o \ + $(OBJDIR)/process_main.o ifeq ($(JIT_ARCH), x86) JIT_OBJS += \ - $(OBJDIR)/beam_asm.o \ - $(OBJDIR)/beam_asm_global.o \ - $(OBJDIR)/beam_asm_module.o \ - $(OBJDIR)/beam_asm_perf.o \ $(OBJDIR)/instr_arith.o \ $(OBJDIR)/instr_bs.o \ $(OBJDIR)/instr_bif.o \ $(OBJDIR)/instr_call.o \ $(OBJDIR)/instr_common.o \ $(OBJDIR)/instr_float.o \ + $(OBJDIR)/instr_fun.o \ + $(OBJDIR)/instr_guard_bifs.o \ + $(OBJDIR)/instr_map.o \ + $(OBJDIR)/instr_msg.o \ + $(OBJDIR)/instr_select.o \ + $(OBJDIR)/instr_trace.o +else +JIT_OBJS += \ + $(OBJDIR)/instr_arith.o \ + $(OBJDIR)/instr_bs.o \ + $(OBJDIR)/instr_bif.o \ + $(OBJDIR)/instr_call.o \ + $(OBJDIR)/instr_common.o \ + $(OBJDIR)/instr_float.o \ + $(OBJDIR)/instr_fun.o \ $(OBJDIR)/instr_guard_bifs.o \ $(OBJDIR)/instr_map.o \ $(OBJDIR)/instr_msg.o \ @@ -1019,38 +1061,17 @@ JIT_OBJS += $(ASMJIT_OBJS) EMU_OBJS = \ $(OBJDIR)/emu_load.o -ifeq ($(USE_ESOCK), yes) - -# WE ARE USING ESOCK - ESOCK_NIF_OBJS = \ $(OBJDIR)/prim_socket_nif.o \ $(OBJDIR)/prim_net_nif.o -ifneq ($(TARGET), win32) -# These are *currently* only needed for non-win32, -# since the nif-functions for socket and net are basically -# stubbed with notsup in the win32 case. ESOCK_RUN_OBJS = \ $(OBJDIR)/socket_dbg.o \ $(OBJDIR)/socket_tarray.o \ $(OBJDIR)/socket_util.o -else -ESOCK_RUN_OBJS = -endif - -else - -# WE ARE *NOT* USING ESOCK - -ESOCK_NIF_OBJS = -ESOCK_RUN_OBJS = - -endif - RUN_OBJS += \ - $(OBJDIR)/erl_alloc.o $(OBJDIR)/erl_mtrace.o \ + $(OBJDIR)/erl_alloc.o \ $(OBJDIR)/erl_alloc_util.o $(OBJDIR)/erl_goodfit_alloc.o \ $(OBJDIR)/erl_bestfit_alloc.o $(OBJDIR)/erl_afit_alloc.o \ $(OBJDIR)/erl_init.o \ @@ -1099,11 +1120,14 @@ RUN_OBJS += \ $(ESOCK_RUN_OBJS) $(OBJDIR)/erl_flxctr.o \ $(OBJDIR)/erl_nfunc_sched.o \ $(OBJDIR)/erl_global_literals.o \ - $(OBJDIR)/beam_file.o + $(OBJDIR)/beam_file.o \ + $(OBJDIR)/beam_types.o \ + $(OBJDIR)/erl_term_hashing.o LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o NIF_OBJS = \ + $(OBJDIR)/prim_tty_nif.o \ $(OBJDIR)/erl_tracer_nif.o \ $(OBJDIR)/prim_buffer_nif.o \ $(OBJDIR)/prim_file_nif.o \ @@ -1114,10 +1138,8 @@ ifeq ($(TARGET),win32) DRV_OBJS = \ $(OBJDIR)/registry_drv.o \ $(OBJDIR)/inet_drv.o \ - $(OBJDIR)/ram_file_drv.o \ - $(OBJDIR)/ttsl_drv.o + $(OBJDIR)/ram_file_drv.o OS_OBJS = \ - $(OBJDIR)/win_con.o \ $(OBJDIR)/dll_sys.o \ $(OBJDIR)/driver_tab.o \ $(OBJDIR)/sys_float.o \ @@ -1125,7 +1147,8 @@ OS_OBJS = \ $(OBJDIR)/sys_interrupt.o \ $(OBJDIR)/sys_env.o \ $(OBJDIR)/dosmap.o \ - $(OBJDIR)/win_prim_file.o + $(OBJDIR)/win_prim_file.o \ + $(OBJDIR)/win_socket_asyncio.o else OS_OBJS = \ @@ -1137,12 +1160,12 @@ OS_OBJS = \ $(OBJDIR)/unix_prim_file.o \ $(OBJDIR)/sys_float.o \ $(OBJDIR)/sys_time.o \ - $(OBJDIR)/sys_signal_stack.o + $(OBJDIR)/sys_signal_stack.o \ + $(OBJDIR)/unix_socket_syncio.o DRV_OBJS = \ $(OBJDIR)/inet_drv.o \ - $(OBJDIR)/ram_file_drv.o \ - $(OBJDIR)/ttsl_drv.o + $(OBJDIR)/ram_file_drv.o endif ifneq ($(STATIC_NIFS),no) @@ -1175,7 +1198,6 @@ OS_OBJS += $(OBJDIR)/erl_poll.o \ $(OBJDIR)/erl_mmap.o \ $(OBJDIR)/erl_osenv.o \ $(OBJDIR)/erl_$(ERLANG_OSTYPE)_sys_ddll.o \ - $(OBJDIR)/erl_mtrace_sys_wrap.o \ $(OBJDIR)/erl_sys_common_misc.o \ $(OBJDIR)/erl_os_monotonic_time_extender.o @@ -1234,6 +1256,26 @@ $(BINDIR)/$(FLAVOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) endif +# ---------------------------------------------------------------------- +# The emulator as a static lib ... +# +ifeq ($(USING_VC),yes) +AR_OUT=-out: +AR_FLAGS= +else +AR_OUT= +ifeq ($(V),0) +AR_FLAGS=rc +else +AR_FLAGS=rcv +endif +endif + +$(BINDIR)/${EMULATOR_LIB}: $(PRELOAD_OBJ) $(OBJS) $(DEPLIBS) + $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ \ + $(PRELOAD_OBJ) $(OBJS) + $(V_RANLIB) $@ + # ---------------------------------------------------------------------- # Dependencies # @@ -1286,9 +1328,9 @@ NIF_COMMON_SRC=$(wildcard nifs/common/*.c) endif NIF_OSTYPE_SRC=$(wildcard nifs/$(ERLANG_OSTYPE)/*.c) ALL_SYS_SRC=$(wildcard sys/$(ERLANG_OSTYPE)/*.c) $(wildcard sys/common/*.c) -# We use $(shell ls) here instead of wildcard as $(wildcard ) resolved at +# We use $(shell find) here instead of wildcard as $(wildcard ) resolved at # loadtime of the makefile and at that time these files are not generated yet. -TARGET_SRC=$(shell ls $(TARGET)/*.c) $(shell ls $(TTF_DIR)/*.c) +TARGET_SRC=$(shell find $(TARGET) $(TTF_DIR) -maxdepth 1 -name "*.c") # I do not want the -MG flag on windows, it does not work properly for a # windows build. @@ -1297,11 +1339,14 @@ ifeq ($(TARGET),win32) #DEP_CC=$(EMU_CC) DEP_CC=$(CC) -DEP_FLAGS=-MM $(subst -O2,,$(CFLAGS)) $(INCLUDES) -I../etc/win32 \ +DEP_CXX=$(CXX) +DEP_INCLUDES=$(INCLUDES) -I../etc/win32 \ -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) \ -Inifs/common -Inifs/$(ERLANG_OSTYPE) +DEP_FLAGS=-MM $(subst -O2,,$(CFLAGS)) $(INCLUDES) +DEP_CXXFLAGS=-MM $(subst -O2,,$(CXXFLAGS)) $(DEP_INCLUDES) $(ASMJIT_FLAGS) -# ifeq (@MIXED_VC@,yes) +# ifeq ($(USING_VC),yes) # VC++ used for compiling. If __GNUC__ is defined we will include # other headers then when compiling which will result in faulty # dependencies. @@ -1339,34 +1384,58 @@ $(TARGET)/gen_git_version.mk: # rebuild. $(V_at)if utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi -.PHONY: depend -ifdef VOID_EMULATOR -depend: - @echo $(VOID_EMULATOR)' - omitted target depend' -else -depend: $(TTF_DIR)/depend.mk -$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) +DEPEND_DEPS=jit src drv nif sys target zlib ryu + +$(TTF_DIR)/src.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \ - | $(SED_DEPEND) > $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ +$(TTF_DIR)/drv.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ $(V_at)$(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) >> $@ +$(TTF_DIR)/nif.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) $(NIF_COMMON_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ $(V_at)$(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(NIF_OSTYPE_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) >> $@ +$(TTF_DIR)/sys.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ +$(TTF_DIR)/target.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ +$(TTF_DIR)/zlib.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) $(V_at)$(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \ - | $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND_ZLIB) > $@ +$(TTF_DIR)/ryu.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) + $(V_at)$(DEP_CC) $(DEP_FLAGS) $(RYU_SRC) \ + | $(SED_DEPEND_ZLIB) > $@ +$(TTF_DIR)/jit.depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + $(gen_verbose) + @touch $@ ifeq ($(JIT_ENABLED),yes) $(V_at)$(DEP_CXX) $(DEP_CXXFLAGS) $(BEAM_CPP_SRC) \ - | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + | $(SED_DEPEND) > $@ endif + +.PHONY: depend +ifdef VOID_EMULATOR +depend: + @echo $(VOID_EMULATOR)' - omitted target depend' +else +depend: $(TTF_DIR)/depend.mk +$(TTF_DIR)/depend.mk: $(foreach dep, $(DEPEND_DEPS), $(TTF_DIR)/$(dep).depend.mk) + $(gen_verbose) + $(V_at)echo "" > "$@" + $(V_at)for dep in "$^"; do cat $$dep >> "$@"; done $(V_at)cd $(ERTS_LIB_DIR) && $(MAKE) depend endif @@ -1389,11 +1458,11 @@ compdb: format-check: clang-format --Werror --dry-run -i beam/jit/*.hpp beam/jit/*.c beam/jit/*.h \ - beam/jit/*/*.cpp beam/jit/*/*.hpp + beam/jit/*.cpp beam/jit/*/*.cpp beam/jit/*/*.hpp format: clang-format -i beam/jit/*.hpp beam/jit/*.c beam/jit/*.h \ - beam/jit/*/*.cpp beam/jit/*/*.hpp + beam/jit/*.cpp beam/jit/*/*.cpp beam/jit/*/*.hpp ifneq ($(ERTS_SKIP_DEPEND),true) ifneq ($(MAKECMDGOALS),clean) diff --git a/erts/emulator/asan/asan_logs_to_html b/erts/emulator/asan/asan_logs_to_html index b83bdb9d31e2..89030e426e66 100755 --- a/erts/emulator/asan/asan_logs_to_html +++ b/erts/emulator/asan/asan_logs_to_html @@ -152,8 +152,8 @@ match_loop(Out, Bin, RegEx0, LogAcc0, PrevEnd, Unmatched0, LM0) -> %% ErrorReport "(?:(==ERROR: AddressSanitizer:.*\n" "(?:.*\n)+?)" % any lines (non-greedy) - "(?:^(?:==|--)|\\z))" % stop at line begining with == or -- - % or at end-of-string + "(?:^[=-]+$|\\z))" % stop at line consisting of only = or - + % or at end-of-string "|" %% Skipped "(?:^[=-]+$)" % skip lines consisting only of = or - @@ -188,7 +188,7 @@ match_loop(Out, Bin, RegEx0, LogAcc0, PrevEnd, Unmatched0, LM0) -> Unmatched1 = [BP({PrevEnd, Start-PrevEnd})|Unmatched0], TypeBin = BP(TypeIx), - %% We indentify a leak by its type (direct or indirect) + %% We identify a leak by its type (direct or indirect) %% and its full call stack. Key = {TypeBin, BP(StackIx)}, {LogAcc2, LM2} = @@ -262,10 +262,16 @@ log_error(_Out, #logacc{app_err=AppErr, tc_err=TcErr}=LogAcc, Txt0) -> [_Exe, App, _Rest] -> io_format("

Before first test case of ~s

\n", [App]); - [_Exe, _App, "tc", Num, Mod, Rest] -> - [Func | _] = string:lexemes(Rest, "."), - io_format("

Test case #~s ~s:~s

\n", - [Num, Mod, Func]); + [_Exe, _App, "tc", Num, Mod, Rest0] -> + [Func | Rest1] = string:lexemes(Rest0, "."), + SubNode = case Rest1 of + ["subnode" | _] -> + " (subnode)"; + _ -> + "" + end, + io_format("

Test case #~s ~s:~s~s

\n", + [Num, Mod, Func, SubNode]); _ -> io_format("

Strange log file name '~s'

\n", [SrcFile]) @@ -360,7 +366,7 @@ try_delete_srcfile(LogAcc) -> ignore; #logacc{did_output=false} -> %% This file did not contribute any output. - %% Optimize future script invokations by removing it. + %% Optimize future script invocations by removing it. delete_file(LogAcc#logacc.srcfile); _ -> keep diff --git a/erts/emulator/asan/suppress b/erts/emulator/asan/suppress index 26ba649522fa..71db30c040cc 100644 --- a/erts/emulator/asan/suppress +++ b/erts/emulator/asan/suppress @@ -1,8 +1,3 @@ -leak:erts_alloc_permanent_cache_aligned - -# Harmless leak of ErtsThrPrgrData from async threads in exiting emulator -leak:erts_thr_progress_register_unmanaged_thread - # Block passed to sigaltstack() leak:sys_thread_init_signal_stack diff --git a/erts/emulator/asmjit.version b/erts/emulator/asmjit.version index dfb88343e62c..0220314b7a51 100644 --- a/erts/emulator/asmjit.version +++ b/erts/emulator/asmjit.version @@ -1 +1 @@ -23ddf56b00f47d8aa0c82ad225e4b3a92661da7e +915186f6c5c2f5a4638e5cb97ccc23d741521a64 diff --git a/erts/emulator/asmjit/arm/a64assembler.cpp b/erts/emulator/asmjit/arm/a64assembler.cpp index 9f8c9b1a9f2f..ec698de767b2 100644 --- a/erts/emulator/asmjit/arm/a64assembler.cpp +++ b/erts/emulator/asmjit/arm/a64assembler.cpp @@ -698,25 +698,25 @@ static const Support::Array commonHiRegIdOfType = {{ #undef V static inline bool checkValidRegs(const Operand_& o0) noexcept { - return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])); + return bool(unsigned(o0.id() < 31) | unsigned(o0.id() == commonHiRegIdOfType[o0.as().type()])); } static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1) noexcept { - return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & - ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) ; + return bool((unsigned(o0.id() < 31) | unsigned(o0.id() == commonHiRegIdOfType[o0.as().type()])) & + (unsigned(o1.id() < 31) | unsigned(o1.id() == commonHiRegIdOfType[o1.as().type()]))); } static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { - return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & - ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) & - ((o2.id() < 31) | (o2.id() == commonHiRegIdOfType[o2.as().type()])) ; + return bool((unsigned(o0.id() < 31) | unsigned(o0.id() == commonHiRegIdOfType[o0.as().type()])) & + (unsigned(o1.id() < 31) | unsigned(o1.id() == commonHiRegIdOfType[o1.as().type()])) & + (unsigned(o2.id() < 31) | unsigned(o2.id() == commonHiRegIdOfType[o2.as().type()]))); } static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { - return ((o0.id() < 31) | (o0.id() == commonHiRegIdOfType[o0.as().type()])) & - ((o1.id() < 31) | (o1.id() == commonHiRegIdOfType[o1.as().type()])) & - ((o2.id() < 31) | (o2.id() == commonHiRegIdOfType[o2.as().type()])) & - ((o3.id() < 31) | (o3.id() == commonHiRegIdOfType[o3.as().type()])) ; + return bool((unsigned(o0.id() < 31) | unsigned(o0.id() == commonHiRegIdOfType[o0.as().type()])) & + (unsigned(o1.id() < 31) | unsigned(o1.id() == commonHiRegIdOfType[o1.as().type()])) & + (unsigned(o2.id() < 31) | unsigned(o2.id() == commonHiRegIdOfType[o2.as().type()])) & + (unsigned(o3.id() < 31) | unsigned(o3.id() == commonHiRegIdOfType[o3.as().type()]))); } // a64::Assembler - Construction & Destruction @@ -4993,13 +4993,11 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co if (Support::test(options, InstOptions::kReserved)) { #ifndef ASMJIT_NO_LOGGING if (_logger) - EmitterUtils::logInstructionEmitted(this, instId, options, o0, o1, o2, opExt, 0, 0, writer.cursor()); + EmitterUtils::logInstructionEmitted(this, BaseInst::composeARMInstId(instId, instCC), options, o0, o1, o2, opExt, 0, 0, writer.cursor()); #endif } - resetExtraReg(); - resetInstOptions(); - resetInlineComment(); + resetState(); writer.done(this); return kErrorOk; @@ -5025,9 +5023,7 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co #ifndef ASMJIT_NO_LOGGING return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt); #else - resetExtraReg(); - resetInstOptions(); - resetInlineComment(); + resetState(); return reportError(err); #endif } diff --git a/erts/emulator/asmjit/arm/a64compiler.h b/erts/emulator/asmjit/arm/a64compiler.h index ebed549581c7..bed408a98fd2 100644 --- a/erts/emulator/asmjit/arm/a64compiler.h +++ b/erts/emulator/asmjit/arm/a64compiler.h @@ -169,6 +169,18 @@ class ASMJIT_VIRTAPI Compiler //! \} + //! \name Compiler specific + //! \{ + + //! Special pseudo-instruction that can be used to load a memory address into `o0` GP register. + //! + //! \note At the moment this instruction is only useful to load a stack allocated address into a GP register + //! for further use. It makes very little sense to use it for anything else. The semantics of this instruction + //! is the same as X86 `LEA` (load effective address) instruction. + inline Error loadAddressOf(const Gp& o0, const Mem& o1) { return _emitter()->_emitI(Inst::kIdAdr, o0, o1); } + + //! \} + //! \name Function Call & Ret Intrinsics //! \{ diff --git a/erts/emulator/asmjit/arm/a64emithelper.cpp b/erts/emulator/asmjit/arm/a64emithelper.cpp index 2d8a5781cd6e..1e8da619a6b8 100644 --- a/erts/emulator/asmjit/arm/a64emithelper.cpp +++ b/erts/emulator/asmjit/arm/a64emithelper.cpp @@ -117,7 +117,7 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove( case TypeId::kUInt32: case TypeId::kInt64: case TypeId::kUInt64: - return emitter->mov(src.as().x(), dst.as().x()); + return emitter->mov(dst.as().x(), src.as().x()); default: { if (TypeUtils::isFloat32(typeId) || TypeUtils::isVec32(typeId)) diff --git a/erts/emulator/asmjit/arm/a64formatter.cpp b/erts/emulator/asmjit/arm/a64formatter.cpp index bccb68b99b08..d6738ca8f8af 100644 --- a/erts/emulator/asmjit/arm/a64formatter.cpp +++ b/erts/emulator/asmjit/arm/a64formatter.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: Zlib #include "../core/api-build_p.h" -#ifndef ASMJIT_NO_LOGGING +#if !defined(ASMJIT_NO_AARCH64) && !defined(ASMJIT_NO_LOGGING) #include "../core/misc_p.h" #include "../core/support.h" @@ -295,4 +295,4 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction( ASMJIT_END_SUB_NAMESPACE -#endif // !ASMJIT_NO_LOGGING +#endif // !ASMJIT_NO_AARCH64 && !ASMJIT_NO_LOGGING diff --git a/erts/emulator/asmjit/arm/a64instapi.cpp b/erts/emulator/asmjit/arm/a64instapi.cpp index dc98bc8f73cd..82bed0e78e2b 100644 --- a/erts/emulator/asmjit/arm/a64instapi.cpp +++ b/erts/emulator/asmjit/arm/a64instapi.cpp @@ -8,7 +8,7 @@ #include "../core/cpuinfo.h" #include "../core/misc_p.h" -#include "../core/support.h" +#include "../core/support_p.h" #include "../arm/a64instapi_p.h" #include "../arm/a64instdb_p.h" #include "../arm/a64operand.h" @@ -26,8 +26,11 @@ Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noe if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId))) return DebugUtils::errored(kErrorInvalidInstruction); - const InstDB::InstInfo& info = InstDB::infoById(realId); - return output.append(InstDB::_nameData + info._nameDataIndex); + + char nameData[32]; + size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[realId], InstDB::_instNameStringTable); + + return output.append(nameData, nameSize); } InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept { @@ -46,30 +49,28 @@ InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexce if (ASMJIT_UNLIKELY(prefix > 'z' - 'a')) return Inst::kIdNone; - uint32_t index = InstDB::instNameIndex[prefix].start; - if (ASMJIT_UNLIKELY(!index)) - return Inst::kIdNone; + size_t base = InstDB::instNameIndex[prefix].start; + size_t end = InstDB::instNameIndex[prefix].end; - const char* nameData = InstDB::_nameData; - const InstDB::InstInfo* table = InstDB::_instInfoTable; + if (ASMJIT_UNLIKELY(!base)) + return Inst::kIdNone; - const InstDB::InstInfo* base = table + index; - const InstDB::InstInfo* end = table + InstDB::instNameIndex[prefix].end; + char nameData[32]; + for (size_t lim = end - base; lim != 0; lim >>= 1) { + size_t instId = base + (lim >> 1); + size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable); - for (size_t lim = (size_t)(end - base); lim != 0; lim >>= 1) { - const InstDB::InstInfo* cur = base + (lim >> 1); - int result = Support::cmpInstName(nameData + cur[0]._nameDataIndex, s, len); + int result = Support::compareStringViews(s, len, nameData, nameSize); + if (result < 0) + continue; - if (result < 0) { - base = cur + 1; + if (result > 0) { + base = instId + 1; lim--; continue; } - if (result > 0) - continue; - - return uint32_t((size_t)(cur - table)); + return InstId(instId); } return Inst::kIdNone; @@ -139,7 +140,7 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId))) return DebugUtils::errored(kErrorInvalidInstruction); - out->_instFlags = 0; + out->_instFlags = InstRWFlags::kNone; out->_opCount = uint8_t(opCount); out->_rmFeature = 0; out->_extraReg.reset(); diff --git a/erts/emulator/asmjit/arm/a64instdb.cpp b/erts/emulator/asmjit/arm/a64instdb.cpp index 64709b5db031..49be360e92cc 100644 --- a/erts/emulator/asmjit/arm/a64instdb.cpp +++ b/erts/emulator/asmjit/arm/a64instdb.cpp @@ -18,20 +18,11 @@ namespace InstDB { // a64::InstDB - InstInfoTable // =========================== -// Don't store `_nameDataIndex` if instruction names are disabled. Since some -// APIs can use `_nameDataIndex` it's much safer if it's zero if it's not used. -#if defined(ASMJIT_NO_TEXT) - #define NAME_DATA_INDEX(x) 0 -#else - #define NAME_DATA_INDEX(x) x -#endif - // Defines an ARM/AArch64 instruction. -#define INST(id, opcodeEncoding, opcodeData, rwInfoIndex, flags, opcodeDataIndex, nameDataIndex) { \ +#define INST(id, opcodeEncoding, opcodeData, rwInfoIndex, flags, opcodeDataIndex) { \ uint32_t(kEncoding##opcodeEncoding), \ uint32_t(opcodeDataIndex), \ 0, \ - uint32_t(NAME_DATA_INDEX(nameDataIndex)), \ uint16_t(rwInfoIndex), \ uint16_t(flags) \ } @@ -63,774 +54,774 @@ IRG: Insert Random Tag. INST_(Irg , BaseRRR , (0b1001101011000000000100, kX , kSP, kX , kSP, kX , kZR, true) , kRWI_W , 0 , 0 , 1 ), // #1 */ const InstInfo _instInfoTable[] = { - // +------------------+---------------------+--------------------------------------------------------------------------------------+-----------+---------------------------+----+-----+ - // | Instruction Id | Encoding | Opcode Data | RW Info | Instruction Flags |DatX|NameX| - // +------------------+---------------------+--------------------------------------------------------------------------------------+-----------+---------------------------+----+-----+ + // +------------------+---------------------+--------------------------------------------------------------------------------------+-----------+---------------------------+----+ + // | Instruction Id | Encoding | Opcode Data | RW Info | Instruction Flags |DatX| + // +------------------+---------------------+--------------------------------------------------------------------------------------+-----------+---------------------------+----+ // ${InstInfo:Begin} - INST(None , None , (_) , 0 , 0 , 0 , 0 ), // #0 - INST(Adc , BaseRRR , (0b0001101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 0 , 1 ), // #1 - INST(Adcs , BaseRRR , (0b0011101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 1 , 5 ), // #2 - INST(Add , BaseAddSub , (0b0001011000, 0b0001011001, 0b0010001) , kRWI_W , 0 , 0 , 978 ), // #3 - INST(Addg , BaseRRII , (0b1001000110000000000000, kX, kSP, kX, kSP, 6, 4, 16, 4, 0, 10) , kRWI_W , 0 , 0 , 10 ), // #4 - INST(Adds , BaseAddSub , (0b0101011000, 0b0101011001, 0b0110001) , kRWI_W , 0 , 1 , 15 ), // #5 - INST(Adr , BaseAdr , (0b0001000000000000000000, OffsetType::kAArch64_ADR) , kRWI_W , 0 , 0 , 25 ), // #6 - INST(Adrp , BaseAdr , (0b1001000000000000000000, OffsetType::kAArch64_ADRP) , kRWI_W , 0 , 1 , 29 ), // #7 - INST(And , BaseLogical , (0b0001010000, 0b00100100, 0) , kRWI_W , 0 , 0 , 57 ), // #8 - INST(Ands , BaseLogical , (0b1101010000, 0b11100100, 0) , kRWI_W , 0 , 1 , 61 ), // #9 - INST(Asr , BaseShift , (0b0001101011000000001010, 0b0001001100000000011111, 0) , kRWI_W , 0 , 0 , 66 ), // #10 - INST(Asrv , BaseShift , (0b0001101011000000001010, 0b0000000000000000000000, 0) , kRWI_W , 0 , 1 , 70 ), // #11 - INST(At , BaseAtDcIcTlbi , (0b00011111110000, 0b00001111000000, true) , kRWI_RX , 0 , 0 , 75 ), // #12 - INST(Autda , BaseRR , (0b11011010110000010001100000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 0 , 78 ), // #13 - INST(Autdza , BaseR , (0b11011010110000010011101111100000, kX, kZR, 0) , kRWI_X , 0 , 0 , 90 ), // #14 - INST(Autdb , BaseRR , (0b11011010110000010001110000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 1 , 84 ), // #15 - INST(Autdzb , BaseR , (0b11011010110000010011111111100000, kX, kZR, 0) , kRWI_X , 0 , 1 , 97 ), // #16 - INST(Autia , BaseRR , (0b11011010110000010001000000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 2 , 104 ), // #17 - INST(Autia1716 , BaseOp , (0b11010101000000110010000110011111) , 0 , 0 , 0 , 110 ), // #18 - INST(Autiasp , BaseOp , (0b11010101000000110010001110111111) , 0 , 0 , 1 , 120 ), // #19 - INST(Autiaz , BaseOp , (0b11010101000000110010001110011111) , 0 , 0 , 2 , 128 ), // #20 - INST(Autib , BaseRR , (0b11011010110000010001010000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 3 , 135 ), // #21 - INST(Autib1716 , BaseOp , (0b11010101000000110010000111011111) , 0 , 0 , 3 , 141 ), // #22 - INST(Autibsp , BaseOp , (0b11010101000000110010001111111111) , 0 , 0 , 4 , 151 ), // #23 - INST(Autibz , BaseOp , (0b11010101000000110010001111011111) , 0 , 0 , 5 , 159 ), // #24 - INST(Autiza , BaseR , (0b11011010110000010011001111100000, kX, kZR, 0) , kRWI_X , 0 , 2 , 166 ), // #25 - INST(Autizb , BaseR , (0b11011010110000010011011111100000, kX, kZR, 0) , kRWI_X , 0 , 3 , 173 ), // #26 - INST(Axflag , BaseOp , (0b11010101000000000100000001011111) , 0 , 0 , 6 , 180 ), // #27 - INST(B , BaseBranchRel , (0b00010100000000000000000000000000) , 0 , F(Cond) , 0 , 1738), // #28 - INST(Bfc , BaseBfc , (0b00110011000000000000001111100000) , kRWI_X , 0 , 0 , 192 ), // #29 - INST(Bfi , BaseBfi , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 , 223 ), // #30 - INST(Bfm , BaseBfm , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 , 2514), // #31 - INST(Bfxil , BaseBfx , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 , 250 ), // #32 - INST(Bic , BaseLogical , (0b0001010001, 0b00100100, 1) , kRWI_W , 0 , 2 , 256 ), // #33 - INST(Bics , BaseLogical , (0b1101010001, 0b11100100, 1) , kRWI_W , 0 , 3 , 260 ), // #34 - INST(Bl , BaseBranchRel , (0b10010100000000000000000000000000) , 0 , 0 , 1 , 2831), // #35 - INST(Blr , BaseBranchReg , (0b11010110001111110000000000000000) , kRWI_R , 0 , 0 , 269 ), // #36 - INST(Br , BaseBranchReg , (0b11010110000111110000000000000000) , kRWI_R , 0 , 1 , 273 ), // #37 - INST(Brk , BaseOpImm , (0b11010100001000000000000000000000, 16, 5) , 0 , 0 , 0 , 276 ), // #38 - INST(Cas , BaseAtomicOp , (0b1000100010100000011111, kWX, 30, 0) , kRWI_XRX , 0 , 0 , 284 ), // #39 - INST(Casa , BaseAtomicOp , (0b1000100011100000011111, kWX, 30, 1) , kRWI_XRX , 0 , 1 , 288 ), // #40 - INST(Casab , BaseAtomicOp , (0b0000100011100000011111, kW , 0 , 1) , kRWI_XRX , 0 , 2 , 293 ), // #41 - INST(Casah , BaseAtomicOp , (0b0100100011100000011111, kW , 0 , 1) , kRWI_XRX , 0 , 3 , 299 ), // #42 - INST(Casal , BaseAtomicOp , (0b1000100011100000111111, kWX, 30, 1) , kRWI_XRX , 0 , 4 , 305 ), // #43 - INST(Casalb , BaseAtomicOp , (0b0000100011100000111111, kW , 0 , 1) , kRWI_XRX , 0 , 5 , 311 ), // #44 - INST(Casalh , BaseAtomicOp , (0b0100100011100000111111, kW , 0 , 1) , kRWI_XRX , 0 , 6 , 318 ), // #45 - INST(Casb , BaseAtomicOp , (0b0000100010100000011111, kW , 0 , 0) , kRWI_XRX , 0 , 7 , 325 ), // #46 - INST(Cash , BaseAtomicOp , (0b0100100010100000011111, kW , 0 , 0) , kRWI_XRX , 0 , 8 , 330 ), // #47 - INST(Casl , BaseAtomicOp , (0b1000100010100000111111, kWX, 30, 0) , kRWI_XRX , 0 , 9 , 335 ), // #48 - INST(Caslb , BaseAtomicOp , (0b0000100010100000111111, kW , 0 , 0) , kRWI_XRX , 0 , 10 , 340 ), // #49 - INST(Caslh , BaseAtomicOp , (0b0100100010100000111111, kW , 0 , 0) , kRWI_XRX , 0 , 11 , 346 ), // #50 - INST(Casp , BaseAtomicCasp , (0b0000100000100000011111, kWX, 30) , kRWI_XXRRX, 0 , 0 , 352 ), // #51 - INST(Caspa , BaseAtomicCasp , (0b0000100001100000011111, kWX, 30) , kRWI_XXRRX, 0 , 1 , 357 ), // #52 - INST(Caspal , BaseAtomicCasp , (0b0000100001100000111111, kWX, 30) , kRWI_XXRRX, 0 , 2 , 363 ), // #53 - INST(Caspl , BaseAtomicCasp , (0b0000100000100000111111, kWX, 30) , kRWI_XXRRX, 0 , 3 , 370 ), // #54 - INST(Cbnz , BaseBranchCmp , (0b00110101000000000000000000000000) , kRWI_R , 0 , 0 , 376 ), // #55 - INST(Cbz , BaseBranchCmp , (0b00110100000000000000000000000000) , kRWI_R , 0 , 1 , 381 ), // #56 - INST(Ccmn , BaseCCmp , (0b00111010010000000000000000000000) , kRWI_R , 0 , 0 , 385 ), // #57 - INST(Ccmp , BaseCCmp , (0b01111010010000000000000000000000) , kRWI_R , 0 , 1 , 650 ), // #58 - INST(Cfinv , BaseOp , (0b11010101000000000100000000011111) , 0 , 0 , 7 , 390 ), // #59 - INST(Cinc , BaseCInc , (0b00011010100000000000010000000000) , kRWI_W , 0 , 0 , 396 ), // #60 - INST(Cinv , BaseCInc , (0b01011010100000000000000000000000) , kRWI_W , 0 , 1 , 401 ), // #61 - INST(Clrex , BaseOpImm , (0b11010101000000110011000001011111, 4, 8) , 0 , 0 , 1 , 406 ), // #62 - INST(Cls , BaseRR , (0b01011010110000000001010000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 4 , 412 ), // #63 - INST(Clz , BaseRR , (0b01011010110000000001000000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 5 , 416 ), // #64 - INST(Cmn , BaseCmpCmn , (0b0101011000, 0b0101011001, 0b0110001) , kRWI_R , 0 , 0 , 386 ), // #65 - INST(Cmp , BaseCmpCmn , (0b1101011000, 0b1101011001, 0b1110001) , kRWI_R , 0 , 1 , 651 ), // #66 - INST(Cmpp , BaseRR , (0b10111010110000000000000000011111, kX, kSP, 5, kX, kSP, 16, true) , kRWI_R , 0 , 6 , 430 ), // #67 - INST(Cneg , BaseCInc , (0b01011010100000000000010000000000) , kRWI_W , 0 , 2 , 441 ), // #68 - INST(Crc32b , BaseRRR , (0b0001101011000000010000, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 2 , 450 ), // #69 - INST(Crc32cb , BaseRRR , (0b0001101011000000010100, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 3 , 457 ), // #70 - INST(Crc32ch , BaseRRR , (0b0001101011000000010101, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 4 , 465 ), // #71 - INST(Crc32cw , BaseRRR , (0b0001101011000000010110, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 5 , 473 ), // #72 - INST(Crc32cx , BaseRRR , (0b1001101011000000010111, kW, kZR, kW, kZR, kX, kZR, false) , kRWI_W , 0 , 6 , 481 ), // #73 - INST(Crc32h , BaseRRR , (0b0001101011000000010001, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 7 , 489 ), // #74 - INST(Crc32w , BaseRRR , (0b0001101011000000010010, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 8 , 496 ), // #75 - INST(Crc32x , BaseRRR , (0b1001101011000000010011, kW, kZR, kW, kZR, kX, kZR, false) , kRWI_W , 0 , 9 , 503 ), // #76 - INST(Csdb , BaseOp , (0b11010101000000110010001010011111) , 0 , 0 , 8 , 510 ), // #77 - INST(Csel , BaseCSel , (0b00011010100000000000000000000000) , kRWI_W , 0 , 0 , 710 ), // #78 - INST(Cset , BaseCSet , (0b00011010100111110000011111100000) , kRWI_W , 0 , 0 , 515 ), // #79 - INST(Csetm , BaseCSet , (0b01011010100111110000001111100000) , kRWI_W , 0 , 1 , 520 ), // #80 - INST(Csinc , BaseCSel , (0b00011010100000000000010000000000) , kRWI_W , 0 , 1 , 526 ), // #81 - INST(Csinv , BaseCSel , (0b01011010100000000000000000000000) , kRWI_W , 0 , 2 , 532 ), // #82 - INST(Csneg , BaseCSel , (0b01011010100000000000010000000000) , kRWI_W , 0 , 3 , 538 ), // #83 - INST(Dc , BaseAtDcIcTlbi , (0b00011110000000, 0b00001110000000, true) , kRWI_RX , 0 , 1 , 2 ), // #84 - INST(Dcps1 , BaseOpImm , (0b11010100101000000000000000000001, 16, 5) , 0 , 0 , 2 , 544 ), // #85 - INST(Dcps2 , BaseOpImm , (0b11010100101000000000000000000010, 16, 5) , 0 , 0 , 3 , 550 ), // #86 - INST(Dcps3 , BaseOpImm , (0b11010100101000000000000000000011, 16, 5) , 0 , 0 , 4 , 556 ), // #87 - INST(Dgh , BaseOp , (0b11010101000000110010000011011111) , 0 , 0 , 9 , 562 ), // #88 - INST(Dmb , BaseOpImm , (0b11010101000000110011000010111111, 4, 8) , 0 , 0 , 5 , 566 ), // #89 - INST(Drps , BaseOp , (0b11010110101111110000001111100000) , 0 , 0 , 10 , 570 ), // #90 - INST(Dsb , BaseOpImm , (0b11010101000000110011000010011111, 4, 8) , 0 , 0 , 6 , 575 ), // #91 - INST(Eon , BaseLogical , (0b1001010001, 0b10100100, 1) , kRWI_W , 0 , 4 , 583 ), // #92 - INST(Eor , BaseLogical , (0b1001010000, 0b10100100, 0) , kRWI_W , 0 , 5 , 1418), // #93 - INST(Esb , BaseOp , (0b11010101000000110010001000011111) , 0 , 0 , 11 , 597 ), // #94 - INST(Extr , BaseExtract , (0b00010011100000000000000000000000) , kRWI_W , 0 , 0 , 605 ), // #95 - INST(Eret , BaseOp , (0b11010110100111110000001111100000) , 0 , 0 , 12 , 592 ), // #96 - INST(Gmi , BaseRRR , (0b1001101011000000000101, kX , kZR, kX , kSP, kX , kZR, true) , kRWI_W , 0 , 10 , 1128), // #97 - INST(Hint , BaseOpImm , (0b11010101000000110010000000011111, 7, 5) , 0 , 0 , 7 , 1132), // #98 - INST(Hlt , BaseOpImm , (0b11010100010000000000000000000000, 16, 5) , 0 , 0 , 8 , 1137), // #99 - INST(Hvc , BaseOpImm , (0b11010100000000000000000000000010, 16, 5) , 0 , 0 , 9 , 1141), // #100 - INST(Ic , BaseAtDcIcTlbi , (0b00011110000000, 0b00001110000000, false) , kRWI_RX , 0 , 2 , 257 ), // #101 - INST(Isb , BaseOpImm , (0b11010101000000110011000011011111, 4, 8) , 0 , 0 , 10 , 1149), // #102 - INST(Ldadd , BaseAtomicOp , (0b1011100000100000000000, kWX, 30, 0) , kRWI_WRX , 0 , 12 , 1189), // #103 - INST(Ldadda , BaseAtomicOp , (0b1011100010100000000000, kWX, 30, 1) , kRWI_WRX , 0 , 13 , 1195), // #104 - INST(Ldaddab , BaseAtomicOp , (0b0011100010100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 14 , 1202), // #105 - INST(Ldaddah , BaseAtomicOp , (0b0111100010100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 15 , 1210), // #106 - INST(Ldaddal , BaseAtomicOp , (0b1011100011100000000000, kWX, 30, 1) , kRWI_WRX , 0 , 16 , 1218), // #107 - INST(Ldaddalb , BaseAtomicOp , (0b0011100011100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 17 , 1226), // #108 - INST(Ldaddalh , BaseAtomicOp , (0b0111100011100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 18 , 1235), // #109 - INST(Ldaddb , BaseAtomicOp , (0b0011100000100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 19 , 1244), // #110 - INST(Ldaddh , BaseAtomicOp , (0b0111100000100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 20 , 1251), // #111 - INST(Ldaddl , BaseAtomicOp , (0b1011100001100000000000, kWX, 30, 0) , kRWI_WRX , 0 , 21 , 1258), // #112 - INST(Ldaddlb , BaseAtomicOp , (0b0011100001100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 22 , 1265), // #113 - INST(Ldaddlh , BaseAtomicOp , (0b0111100001100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 23 , 1273), // #114 - INST(Ldar , BaseRM_NoImm , (0b1000100011011111111111, kWX, kZR, 30) , kRWI_W , 0 , 0 , 1281), // #115 - INST(Ldarb , BaseRM_NoImm , (0b0000100011011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 1 , 1286), // #116 - INST(Ldarh , BaseRM_NoImm , (0b0100100011011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 2 , 1292), // #117 - INST(Ldaxp , BaseLdxp , (0b1000100001111111100000, kWX, 30) , kRWI_WW , 0 , 0 , 1298), // #118 - INST(Ldaxr , BaseRM_NoImm , (0b1000100001011111111111, kWX, kZR, 30) , kRWI_W , 0 , 3 , 1304), // #119 - INST(Ldaxrb , BaseRM_NoImm , (0b0000100001011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 4 , 1310), // #120 - INST(Ldaxrh , BaseRM_NoImm , (0b0100100001011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 5 , 1317), // #121 - INST(Ldclr , BaseAtomicOp , (0b1011100000100000000100, kWX, 30, 0) , kRWI_WRX , 0 , 24 , 1324), // #122 - INST(Ldclra , BaseAtomicOp , (0b1011100010100000000100, kWX, 30, 1) , kRWI_WRX , 0 , 25 , 1330), // #123 - INST(Ldclrab , BaseAtomicOp , (0b0011100010100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 26 , 1337), // #124 - INST(Ldclrah , BaseAtomicOp , (0b0111100010100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 27 , 1345), // #125 - INST(Ldclral , BaseAtomicOp , (0b1011100011100000000100, kWX, 30, 1) , kRWI_WRX , 0 , 28 , 1353), // #126 - INST(Ldclralb , BaseAtomicOp , (0b0011100011100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 29 , 1361), // #127 - INST(Ldclralh , BaseAtomicOp , (0b0111100011100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 30 , 1370), // #128 - INST(Ldclrb , BaseAtomicOp , (0b0011100000100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 31 , 1379), // #129 - INST(Ldclrh , BaseAtomicOp , (0b0111100000100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 32 , 1386), // #130 - INST(Ldclrl , BaseAtomicOp , (0b1011100001100000000100, kWX, 30, 0) , kRWI_WRX , 0 , 33 , 1393), // #131 - INST(Ldclrlb , BaseAtomicOp , (0b0011100001100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 34 , 1400), // #132 - INST(Ldclrlh , BaseAtomicOp , (0b0111100001100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 35 , 1408), // #133 - INST(Ldeor , BaseAtomicOp , (0b1011100000100000001000, kWX, 30, 0) , kRWI_WRX , 0 , 36 , 1416), // #134 - INST(Ldeora , BaseAtomicOp , (0b1011100010100000001000, kWX, 30, 1) , kRWI_WRX , 0 , 37 , 1422), // #135 - INST(Ldeorab , BaseAtomicOp , (0b0011100010100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 38 , 1429), // #136 - INST(Ldeorah , BaseAtomicOp , (0b0111100010100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 39 , 1437), // #137 - INST(Ldeoral , BaseAtomicOp , (0b1011100011100000001000, kWX, 30, 1) , kRWI_WRX , 0 , 40 , 1445), // #138 - INST(Ldeoralb , BaseAtomicOp , (0b0011100011100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 41 , 1453), // #139 - INST(Ldeoralh , BaseAtomicOp , (0b0111100011100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 42 , 1462), // #140 - INST(Ldeorb , BaseAtomicOp , (0b0011100000100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 43 , 1471), // #141 - INST(Ldeorh , BaseAtomicOp , (0b0111100000100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 44 , 1478), // #142 - INST(Ldeorl , BaseAtomicOp , (0b1011100001100000001000, kWX, 30, 0) , kRWI_WRX , 0 , 45 , 1485), // #143 - INST(Ldeorlb , BaseAtomicOp , (0b0011100001100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 46 , 1492), // #144 - INST(Ldeorlh , BaseAtomicOp , (0b0111100001100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 47 , 1500), // #145 - INST(Ldg , BaseRM_SImm9 , (0b1101100101100000000000, 0b0000000000000000000000, kX , kZR, 0, 4) , kRWI_W , 0 , 0 , 1508), // #146 - INST(Ldgm , BaseRM_NoImm , (0b1101100111100000000000, kX , kZR, 0 ) , kRWI_W , 0 , 6 , 1512), // #147 - INST(Ldlar , BaseRM_NoImm , (0b1000100011011111011111, kWX, kZR, 30) , kRWI_W , 0 , 7 , 1517), // #148 - INST(Ldlarb , BaseRM_NoImm , (0b0000100011011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 8 , 1523), // #149 - INST(Ldlarh , BaseRM_NoImm , (0b0100100011011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 9 , 1530), // #150 - INST(Ldnp , BaseLdpStp , (0b0010100001, 0 , kWX, 31, 2) , kRWI_WW , 0 , 0 , 1537), // #151 - INST(Ldp , BaseLdpStp , (0b0010100101, 0b0010100011, kWX, 31, 2) , kRWI_W , 0 , 1 , 1542), // #152 - INST(Ldpsw , BaseLdpStp , (0b0110100101, 0b0110100011, kX , 0 , 2) , kRWI_WW , 0 , 2 , 1546), // #153 - INST(Ldr , BaseLdSt , (0b1011100101, 0b10111000010, 0b10111000011, 0b00011000, kWX, 30, 2, Inst::kIdLdur) , kRWI_W , 0 , 0 , 1552), // #154 - INST(Ldraa , BaseRM_SImm10 , (0b1111100000100000000001, kX , kZR, 0, 3) , kRWI_W , 0 , 0 , 1556), // #155 - INST(Ldrab , BaseRM_SImm10 , (0b1111100010100000000001, kX , kZR, 0, 3) , kRWI_W , 0 , 1 , 1562), // #156 - INST(Ldrb , BaseLdSt , (0b0011100101, 0b00111000010, 0b00111000011, 0 , kW , 0 , 0, Inst::kIdLdurb) , kRWI_W , 0 , 1 , 1568), // #157 - INST(Ldrh , BaseLdSt , (0b0111100101, 0b01111000010, 0b01111000011, 0 , kW , 0 , 1, Inst::kIdLdurh) , kRWI_W , 0 , 2 , 1573), // #158 - INST(Ldrsb , BaseLdSt , (0b0011100111, 0b00111000100, 0b00111000101, 0 , kWX, 22, 0, Inst::kIdLdursb) , kRWI_W , 0 , 3 , 1578), // #159 - INST(Ldrsh , BaseLdSt , (0b0111100110, 0b01111000100, 0b01111000101, 0 , kWX, 22, 1, Inst::kIdLdursh) , kRWI_W , 0 , 4 , 1584), // #160 - INST(Ldrsw , BaseLdSt , (0b1011100110, 0b10111000100, 0b10111000101, 0b10011000, kX , 0 , 2, Inst::kIdLdursw) , kRWI_W , 0 , 5 , 1590), // #161 - INST(Ldset , BaseAtomicOp , (0b1011100000100000001100, kWX, 30, 0) , kRWI_WRX , 0 , 48 , 1596), // #162 - INST(Ldseta , BaseAtomicOp , (0b1011100010100000001100, kWX, 30, 1) , kRWI_WRX , 0 , 49 , 1602), // #163 - INST(Ldsetab , BaseAtomicOp , (0b0011100010100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 50 , 1609), // #164 - INST(Ldsetah , BaseAtomicOp , (0b0111100010100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 51 , 1617), // #165 - INST(Ldsetal , BaseAtomicOp , (0b1011100011100000001100, kWX, 30, 1) , kRWI_WRX , 0 , 52 , 1625), // #166 - INST(Ldsetalb , BaseAtomicOp , (0b0011100011100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 53 , 1633), // #167 - INST(Ldsetalh , BaseAtomicOp , (0b0111100011100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 54 , 1642), // #168 - INST(Ldsetb , BaseAtomicOp , (0b0011100000100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 55 , 1651), // #169 - INST(Ldseth , BaseAtomicOp , (0b0111100000100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 56 , 1658), // #170 - INST(Ldsetl , BaseAtomicOp , (0b1011100001100000001100, kWX, 30, 0) , kRWI_WRX , 0 , 57 , 1665), // #171 - INST(Ldsetlb , BaseAtomicOp , (0b0011100001100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 58 , 1672), // #172 - INST(Ldsetlh , BaseAtomicOp , (0b0111100001100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 59 , 1680), // #173 - INST(Ldsmax , BaseAtomicOp , (0b1011100000100000010000, kWX, 30, 0) , kRWI_WRX , 0 , 60 , 1688), // #174 - INST(Ldsmaxa , BaseAtomicOp , (0b1011100010100000010000, kWX, 30, 1) , kRWI_WRX , 0 , 61 , 1695), // #175 - INST(Ldsmaxab , BaseAtomicOp , (0b0011100010100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 62 , 1703), // #176 - INST(Ldsmaxah , BaseAtomicOp , (0b0111100010100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 63 , 1712), // #177 - INST(Ldsmaxal , BaseAtomicOp , (0b1011100011100000010000, kWX, 30, 1) , kRWI_WRX , 0 , 64 , 1721), // #178 - INST(Ldsmaxalb , BaseAtomicOp , (0b0011100011100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 65 , 1730), // #179 - INST(Ldsmaxalh , BaseAtomicOp , (0b0111100011100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 66 , 1740), // #180 - INST(Ldsmaxb , BaseAtomicOp , (0b0011100000100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 67 , 1750), // #181 - INST(Ldsmaxh , BaseAtomicOp , (0b0111100000100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 68 , 1758), // #182 - INST(Ldsmaxl , BaseAtomicOp , (0b1011100001100000010000, kWX, 30, 0) , kRWI_WRX , 0 , 69 , 1766), // #183 - INST(Ldsmaxlb , BaseAtomicOp , (0b0011100001100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 70 , 1774), // #184 - INST(Ldsmaxlh , BaseAtomicOp , (0b0111100001100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 71 , 1783), // #185 - INST(Ldsmin , BaseAtomicOp , (0b1011100000100000010100, kWX, 30, 0) , kRWI_WRX , 0 , 72 , 1792), // #186 - INST(Ldsmina , BaseAtomicOp , (0b1011100010100000010100, kWX, 30, 1) , kRWI_WRX , 0 , 73 , 1799), // #187 - INST(Ldsminab , BaseAtomicOp , (0b0011100010100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 74 , 1807), // #188 - INST(Ldsminah , BaseAtomicOp , (0b0111100010100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 75 , 1816), // #189 - INST(Ldsminal , BaseAtomicOp , (0b1011100011100000010100, kWX, 30, 1) , kRWI_WRX , 0 , 76 , 1825), // #190 - INST(Ldsminalb , BaseAtomicOp , (0b0011100011100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 77 , 1834), // #191 - INST(Ldsminalh , BaseAtomicOp , (0b0111100011100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 78 , 1844), // #192 - INST(Ldsminb , BaseAtomicOp , (0b0011100000100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 79 , 1854), // #193 - INST(Ldsminh , BaseAtomicOp , (0b0111100000100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 80 , 1862), // #194 - INST(Ldsminl , BaseAtomicOp , (0b1011100001100000010100, kWX, 30, 0) , kRWI_WRX , 0 , 81 , 1870), // #195 - INST(Ldsminlb , BaseAtomicOp , (0b0011100001100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 82 , 1878), // #196 - INST(Ldsminlh , BaseAtomicOp , (0b0111100001100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 83 , 1887), // #197 - INST(Ldtr , BaseRM_SImm9 , (0b1011100001000000000010, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_W , 0 , 1 , 1896), // #198 - INST(Ldtrb , BaseRM_SImm9 , (0b0011100001000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 2 , 1901), // #199 - INST(Ldtrh , BaseRM_SImm9 , (0b0111100001000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 3 , 1907), // #200 - INST(Ldtrsb , BaseRM_SImm9 , (0b0011100011000000000010, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 4 , 1913), // #201 - INST(Ldtrsh , BaseRM_SImm9 , (0b0111100011000000000010, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 5 , 1920), // #202 - INST(Ldtrsw , BaseRM_SImm9 , (0b1011100010000000000010, 0b0000000000000000000000, kX , kZR, 0 , 0) , kRWI_W , 0 , 6 , 1927), // #203 - INST(Ldumax , BaseAtomicOp , (0b1011100000100000011000, kWX, 30, 0) , kRWI_WRX , 0 , 84 , 1934), // #204 - INST(Ldumaxa , BaseAtomicOp , (0b1011100010100000011000, kWX, 30, 1) , kRWI_WRX , 0 , 85 , 1941), // #205 - INST(Ldumaxab , BaseAtomicOp , (0b0011100010100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 86 , 1949), // #206 - INST(Ldumaxah , BaseAtomicOp , (0b0111100010100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 87 , 1958), // #207 - INST(Ldumaxal , BaseAtomicOp , (0b1011100011100000011000, kWX, 30, 1) , kRWI_WRX , 0 , 88 , 1967), // #208 - INST(Ldumaxalb , BaseAtomicOp , (0b0011100011100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 89 , 1976), // #209 - INST(Ldumaxalh , BaseAtomicOp , (0b0111100011100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 90 , 1986), // #210 - INST(Ldumaxb , BaseAtomicOp , (0b0011100000100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 91 , 1996), // #211 - INST(Ldumaxh , BaseAtomicOp , (0b0111100000100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 92 , 2004), // #212 - INST(Ldumaxl , BaseAtomicOp , (0b1011100001100000011000, kWX, 30, 0) , kRWI_WRX , 0 , 93 , 2012), // #213 - INST(Ldumaxlb , BaseAtomicOp , (0b0011100001100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 94 , 2020), // #214 - INST(Ldumaxlh , BaseAtomicOp , (0b0111100001100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 95 , 2029), // #215 - INST(Ldumin , BaseAtomicOp , (0b1011100000100000011100, kWX, 30, 0) , kRWI_WRX , 0 , 96 , 2038), // #216 - INST(Ldumina , BaseAtomicOp , (0b1011100010100000011100, kWX, 30, 1) , kRWI_WRX , 0 , 97 , 2045), // #217 - INST(Lduminab , BaseAtomicOp , (0b0011100010100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 98 , 2053), // #218 - INST(Lduminah , BaseAtomicOp , (0b0111100010100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 99 , 2062), // #219 - INST(Lduminal , BaseAtomicOp , (0b1011100011100000011100, kWX, 30, 1) , kRWI_WRX , 0 , 100, 2071), // #220 - INST(Lduminalb , BaseAtomicOp , (0b0011100011100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 101, 2080), // #221 - INST(Lduminalh , BaseAtomicOp , (0b0111100011100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 102, 2090), // #222 - INST(Lduminb , BaseAtomicOp , (0b0011100000100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 103, 2100), // #223 - INST(Lduminh , BaseAtomicOp , (0b0111100000100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 104, 2108), // #224 - INST(Lduminl , BaseAtomicOp , (0b1011100001100000011100, kWX, 30, 0) , kRWI_WRX , 0 , 105, 2116), // #225 - INST(Lduminlb , BaseAtomicOp , (0b0011100001100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 106, 2124), // #226 - INST(Lduminlh , BaseAtomicOp , (0b0111100001100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 107, 2133), // #227 - INST(Ldur , BaseRM_SImm9 , (0b1011100001000000000000, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_W , 0 , 7 , 2142), // #228 - INST(Ldurb , BaseRM_SImm9 , (0b0011100001000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 8 , 2147), // #229 - INST(Ldurh , BaseRM_SImm9 , (0b0111100001000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 9 , 2153), // #230 - INST(Ldursb , BaseRM_SImm9 , (0b0011100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 10 , 2159), // #231 - INST(Ldursh , BaseRM_SImm9 , (0b0111100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 11 , 2166), // #232 - INST(Ldursw , BaseRM_SImm9 , (0b1011100010000000000000, 0b0000000000000000000000, kWX, kZR, 0 , 0) , kRWI_W , 0 , 12 , 2173), // #233 - INST(Ldxp , BaseLdxp , (0b1000100001111111000000, kWX, 30) , kRWI_WW , 0 , 1 , 2180), // #234 - INST(Ldxr , BaseRM_NoImm , (0b1000100001011111011111, kWX, kZR, 30) , kRWI_W , 0 , 10 , 2185), // #235 - INST(Ldxrb , BaseRM_NoImm , (0b0000100001011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 11 , 2190), // #236 - INST(Ldxrh , BaseRM_NoImm , (0b0100100001011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 12 , 2196), // #237 - INST(Lsl , BaseShift , (0b0001101011000000001000, 0b0101001100000000000000, 0) , kRWI_W , 0 , 2 , 2880), // #238 - INST(Lslv , BaseShift , (0b0001101011000000001000, 0b0000000000000000000000, 0) , kRWI_W , 0 , 3 , 2202), // #239 - INST(Lsr , BaseShift , (0b0001101011000000001001, 0b0101001100000000011111, 0) , kRWI_W , 0 , 4 , 2207), // #240 - INST(Lsrv , BaseShift , (0b0001101011000000001001, 0b0000000000000000000000, 0) , kRWI_W , 0 , 5 , 2211), // #241 - INST(Madd , BaseRRRR , (0b0001101100000000000000, kWX, kZR, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 0 , 977 ), // #242 - INST(Mneg , BaseRRR , (0b0001101100000000111111, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 11 , 2216), // #243 - INST(Mov , BaseMov , (_) , kRWI_W , 0 , 0 , 949 ), // #244 - INST(Movk , BaseMovKNZ , (0b01110010100000000000000000000000) , kRWI_X , 0 , 0 , 2226), // #245 - INST(Movn , BaseMovKNZ , (0b00010010100000000000000000000000) , kRWI_W , 0 , 1 , 2231), // #246 - INST(Movz , BaseMovKNZ , (0b01010010100000000000000000000000) , kRWI_W , 0 , 2 , 2236), // #247 - INST(Mrs , BaseMrs , (_) , kRWI_W , 0 , 0 , 2241), // #248 - INST(Msr , BaseMsr , (_) , kRWI_W , 0 , 0 , 2245), // #249 - INST(Msub , BaseRRRR , (0b0001101100000000100000, kWX, kZR, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 1 , 984 ), // #250 - INST(Mul , BaseRRR , (0b0001101100000000011111, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 12 , 991 ), // #251 - INST(Mvn , BaseMvnNeg , (0b00101010001000000000001111100000) , kRWI_W , 0 , 0 , 2249), // #252 - INST(Neg , BaseMvnNeg , (0b01001011000000000000001111100000) , kRWI_W , 0 , 1 , 540 ), // #253 - INST(Negs , BaseMvnNeg , (0b01101011000000000000001111100000) , kRWI_W , 0 , 2 , 2258), // #254 - INST(Ngc , BaseRR , (0b01011010000000000000001111100000, kWX, kZR, 0, kWX, kZR, 16, true) , kRWI_W , 0 , 7 , 2263), // #255 - INST(Ngcs , BaseRR , (0b01111010000000000000001111100000, kWX, kZR, 0, kWX, kZR, 16, true) , kRWI_W , 0 , 8 , 2267), // #256 - INST(Nop , BaseOp , (0b11010101000000110010000000011111) , 0 , 0 , 13 , 2272), // #257 - INST(Orn , BaseLogical , (0b0101010001, 0b01100100, 1) , kRWI_W , 0 , 6 , 2280), // #258 - INST(Orr , BaseLogical , (0b0101010000, 0b01100100, 0) , kRWI_W , 0 , 7 , 2284), // #259 - INST(Pacda , BaseRR , (0b11011010110000010000100000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 9 , 2288), // #260 - INST(Pacdb , BaseRR , (0b11011010110000010000110000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 10 , 2294), // #261 - INST(Pacdza , BaseR , (0b11011010110000010010101111100000, kX, kZR, 0) , kRWI_X , 0 , 4 , 2300), // #262 - INST(Pacdzb , BaseR , (0b11011010110000010010111111100000, kX, kZR, 0) , kRWI_X , 0 , 5 , 2307), // #263 - INST(Pacga , BaseRRR , (0b1001101011000000001100, kX, kZR, kX, kZR, kX, kSP, false) , kRWI_W , 0 , 13 , 2314), // #264 - INST(Pssbb , BaseOp , (0b11010101000000110011010010011111) , 0 , 0 , 14 , 2338), // #265 - INST(Rbit , BaseRR , (0b01011010110000000000000000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 11 , 2364), // #266 - INST(Ret , BaseBranchReg , (0b11010110010111110000000000000000) , kRWI_R , 0 , 2 , 593 ), // #267 - INST(Rev , BaseRev , (_) , kRWI_W , 0 , 0 , 2369), // #268 - INST(Rev16 , BaseRR , (0b01011010110000000000010000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 12 , 2373), // #269 - INST(Rev32 , BaseRR , (0b11011010110000000000100000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 13 , 2379), // #270 - INST(Rev64 , BaseRR , (0b11011010110000000000110000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 14 , 2385), // #271 - INST(Ror , BaseShift , (0b0001101011000000001011, 0b0001001110000000000000, 1) , kRWI_W , 0 , 6 , 2391), // #272 - INST(Rorv , BaseShift , (0b0001101011000000001011, 0b0000000000000000000000, 1) , kRWI_W , 0 , 7 , 2395), // #273 - INST(Sbc , BaseRRR , (0b0101101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 14 , 2498), // #274 - INST(Sbcs , BaseRRR , (0b0111101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 15 , 2502), // #275 - INST(Sbfiz , BaseBfi , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 , 2507), // #276 - INST(Sbfm , BaseBfm , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 , 2513), // #277 - INST(Sbfx , BaseBfx , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 , 2518), // #278 - INST(Sdiv , BaseRRR , (0b0001101011000000000011, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 16 , 2529), // #279 - INST(Setf8 , BaseR , (0b00111010000000000000100000001101, kW, kZR, 5) , 0 , 0 , 6 , 2541), // #280 - INST(Setf16 , BaseR , (0b00111010000000000100100000001101, kW, kZR, 5) , 0 , 0 , 7 , 2534), // #281 - INST(Sev , BaseOp , (0b11010101000000110010000010011111) , 0 , 0 , 15 , 2547), // #282 - INST(Sevl , BaseOp , (0b11010101000000110010000010111111) , 0 , 0 , 16 , 2551), // #283 - INST(Smaddl , BaseRRRR , (0b1001101100100000000000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 2 , 2758), // #284 - INST(Smc , BaseOpImm , (0b11010100000000000000000000000011, 16, 5) , 0 , 0 , 11 , 53 ), // #285 - INST(Smnegl , BaseRRR , (0b1001101100100000111111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 17 , 2815), // #286 - INST(Smsubl , BaseRRRR , (0b1001101100100000100000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 3 , 2827), // #287 - INST(Smulh , BaseRRR , (0b1001101101000000011111, kX , kZR, kX , kZR, kX , kZR, true) , kRWI_W , 0 , 18 , 2834), // #288 - INST(Smull , BaseRRR , (0b1001101100100000011111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 19 , 2840), // #289 - INST(Ssbb , BaseOp , (0b11010101000000110011000010011111) , 0 , 0 , 17 , 2339), // #290 - INST(St2g , BaseRM_SImm9 , (0b1101100110100000000010, 0b1101100110100000000001, kX, kSP, 0, 4) , kRWI_RW , 0 , 13 , 3164), // #291 - INST(Stadd , BaseAtomicSt , (0b1011100000100000000000, kWX, 30) , kRWI_RX , 0 , 0 , 3177), // #292 - INST(Staddl , BaseAtomicSt , (0b1011100001100000000000, kWX, 30) , kRWI_RX , 0 , 1 , 3197), // #293 - INST(Staddb , BaseAtomicSt , (0b0011100000100000000000, kW , 0 ) , kRWI_RX , 0 , 2 , 3183), // #294 - INST(Staddlb , BaseAtomicSt , (0b0011100001100000000000, kW , 0 ) , kRWI_RX , 0 , 3 , 3204), // #295 - INST(Staddh , BaseAtomicSt , (0b0111100000100000000000, kW , 0 ) , kRWI_RX , 0 , 4 , 3190), // #296 - INST(Staddlh , BaseAtomicSt , (0b0111100001100000000000, kW , 0 ) , kRWI_RX , 0 , 5 , 3212), // #297 - INST(Stclr , BaseAtomicSt , (0b1011100000100000000100, kWX, 30) , kRWI_RX , 0 , 6 , 3220), // #298 - INST(Stclrl , BaseAtomicSt , (0b1011100001100000000100, kWX, 30) , kRWI_RX , 0 , 7 , 3240), // #299 - INST(Stclrb , BaseAtomicSt , (0b0011100000100000000100, kW , 0 ) , kRWI_RX , 0 , 8 , 3226), // #300 - INST(Stclrlb , BaseAtomicSt , (0b0011100001100000000100, kW , 0 ) , kRWI_RX , 0 , 9 , 3247), // #301 - INST(Stclrh , BaseAtomicSt , (0b0111100000100000000100, kW , 0 ) , kRWI_RX , 0 , 10 , 3233), // #302 - INST(Stclrlh , BaseAtomicSt , (0b0111100001100000000100, kW , 0 ) , kRWI_RX , 0 , 11 , 3255), // #303 - INST(Steor , BaseAtomicSt , (0b1011100000100000001000, kWX, 30) , kRWI_RX , 0 , 12 , 3263), // #304 - INST(Steorl , BaseAtomicSt , (0b1011100001100000001000, kWX, 30) , kRWI_RX , 0 , 13 , 3283), // #305 - INST(Steorb , BaseAtomicSt , (0b0011100000100000001000, kW , 0 ) , kRWI_RX , 0 , 14 , 3269), // #306 - INST(Steorlb , BaseAtomicSt , (0b0011100001100000001000, kW , 0 ) , kRWI_RX , 0 , 15 , 3290), // #307 - INST(Steorh , BaseAtomicSt , (0b0111100000100000001000, kW , 0 ) , kRWI_RX , 0 , 16 , 3276), // #308 - INST(Steorlh , BaseAtomicSt , (0b0111100001100000001000, kW , 0 ) , kRWI_RX , 0 , 17 , 3298), // #309 - INST(Stg , BaseRM_SImm9 , (0b1101100100100000000010, 0b1101100100100000000001, kX, kSP, 0, 4) , kRWI_RW , 0 , 14 , 3306), // #310 - INST(Stgm , BaseRM_NoImm , (0b1101100110100000000000, kX , kZR, 0 ) , kRWI_RW , 0 , 13 , 3310), // #311 - INST(Stgp , BaseLdpStp , (0b0110100100, 0b0110100010, kX, 0, 4) , kRWI_RRW , 0 , 3 , 3315), // #312 - INST(Stllr , BaseRM_NoImm , (0b1000100010011111011111, kWX, kZR, 30) , kRWI_RW , 0 , 14 , 3320), // #313 - INST(Stllrb , BaseRM_NoImm , (0b0000100010011111011111, kW , kZR, 0 ) , kRWI_RW , 0 , 15 , 3326), // #314 - INST(Stllrh , BaseRM_NoImm , (0b0100100010011111011111, kW , kZR, 0 ) , kRWI_RW , 0 , 16 , 3333), // #315 - INST(Stlr , BaseRM_NoImm , (0b1000100010011111111111, kWX, kZR, 30) , kRWI_RW , 0 , 17 , 3340), // #316 - INST(Stlrb , BaseRM_NoImm , (0b0000100010011111111111, kW , kZR, 0 ) , kRWI_RW , 0 , 18 , 3345), // #317 - INST(Stlrh , BaseRM_NoImm , (0b0100100010011111111111, kW , kZR, 0 ) , kRWI_RW , 0 , 19 , 3351), // #318 - INST(Stlxp , BaseStxp , (0b1000100000100000100000, kWX, 30) , kRWI_WRRX , 0 , 0 , 3357), // #319 - INST(Stlxr , BaseAtomicOp , (0b1000100000000000111111, kWX, 30, 1) , kRWI_WRX , 0 , 108, 3363), // #320 - INST(Stlxrb , BaseAtomicOp , (0b0000100000000000111111, kW , 0 , 1) , kRWI_WRX , 0 , 109, 3369), // #321 - INST(Stlxrh , BaseAtomicOp , (0b0100100000000000111111, kW , 0 , 1) , kRWI_WRX , 0 , 110, 3376), // #322 - INST(Stnp , BaseLdpStp , (0b0010100000, 0 , kWX, 31, 2) , kRWI_RRW , 0 , 4 , 3383), // #323 - INST(Stp , BaseLdpStp , (0b0010100100, 0b0010100010, kWX, 31, 2) , kRWI_RRW , 0 , 5 , 3388), // #324 - INST(Str , BaseLdSt , (0b1011100100, 0b10111000000, 0b10111000001, 0 , kWX, 30, 2, Inst::kIdStur) , kRWI_RW , 0 , 6 , 3392), // #325 - INST(Strb , BaseLdSt , (0b0011100100, 0b00111000000, 0b00111000001, 0 , kW , 30, 0, Inst::kIdSturb) , kRWI_RW , 0 , 7 , 3396), // #326 - INST(Strh , BaseLdSt , (0b0111100100, 0b01111000000, 0b01111000001, 0 , kWX, 30, 1, Inst::kIdSturh) , kRWI_RW , 0 , 8 , 3401), // #327 - INST(Stset , BaseAtomicSt , (0b1011100000100000001100, kWX, 30) , kRWI_RX , 0 , 18 , 3406), // #328 - INST(Stsetl , BaseAtomicSt , (0b1011100001100000001100, kWX, 30) , kRWI_RX , 0 , 19 , 3426), // #329 - INST(Stsetb , BaseAtomicSt , (0b0011100000100000001100, kW , 0 ) , kRWI_RX , 0 , 20 , 3412), // #330 - INST(Stsetlb , BaseAtomicSt , (0b0011100001100000001100, kW , 0 ) , kRWI_RX , 0 , 21 , 3433), // #331 - INST(Stseth , BaseAtomicSt , (0b0111100000100000001100, kW , 0 ) , kRWI_RX , 0 , 22 , 3419), // #332 - INST(Stsetlh , BaseAtomicSt , (0b0111100001100000001100, kW , 0 ) , kRWI_RX , 0 , 23 , 3441), // #333 - INST(Stsmax , BaseAtomicSt , (0b1011100000100000010000, kWX, 30) , kRWI_RX , 0 , 24 , 3449), // #334 - INST(Stsmaxl , BaseAtomicSt , (0b1011100001100000010000, kWX, 30) , kRWI_RX , 0 , 25 , 3472), // #335 - INST(Stsmaxb , BaseAtomicSt , (0b0011100000100000010000, kW , 0 ) , kRWI_RX , 0 , 26 , 3456), // #336 - INST(Stsmaxlb , BaseAtomicSt , (0b0011100001100000010000, kW , 0 ) , kRWI_RX , 0 , 27 , 3480), // #337 - INST(Stsmaxh , BaseAtomicSt , (0b0111100000100000010000, kW , 0 ) , kRWI_RX , 0 , 28 , 3464), // #338 - INST(Stsmaxlh , BaseAtomicSt , (0b0111100001100000010000, kW , 0 ) , kRWI_RX , 0 , 29 , 3489), // #339 - INST(Stsmin , BaseAtomicSt , (0b1011100000100000010100, kWX, 30) , kRWI_RX , 0 , 30 , 3498), // #340 - INST(Stsminl , BaseAtomicSt , (0b1011100001100000010100, kWX, 30) , kRWI_RX , 0 , 31 , 3521), // #341 - INST(Stsminb , BaseAtomicSt , (0b0011100000100000010100, kW , 0 ) , kRWI_RX , 0 , 32 , 3505), // #342 - INST(Stsminlb , BaseAtomicSt , (0b0011100001100000010100, kW , 0 ) , kRWI_RX , 0 , 33 , 3529), // #343 - INST(Stsminh , BaseAtomicSt , (0b0111100000100000010100, kW , 0 ) , kRWI_RX , 0 , 34 , 3513), // #344 - INST(Stsminlh , BaseAtomicSt , (0b0111100001100000010100, kW , 0 ) , kRWI_RX , 0 , 35 , 3538), // #345 - INST(Sttr , BaseRM_SImm9 , (0b1011100000000000000010, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_RW , 0 , 15 , 3547), // #346 - INST(Sttrb , BaseRM_SImm9 , (0b0011100000000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 16 , 3552), // #347 - INST(Sttrh , BaseRM_SImm9 , (0b0111100000000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 17 , 3558), // #348 - INST(Stumax , BaseAtomicSt , (0b1011100000100000011000, kWX, 30) , kRWI_RX , 0 , 36 , 3564), // #349 - INST(Stumaxl , BaseAtomicSt , (0b1011100001100000011000, kWX, 30) , kRWI_RX , 0 , 37 , 3587), // #350 - INST(Stumaxb , BaseAtomicSt , (0b0011100000100000011000, kW , 0 ) , kRWI_RX , 0 , 38 , 3571), // #351 - INST(Stumaxlb , BaseAtomicSt , (0b0011100001100000011000, kW , 0 ) , kRWI_RX , 0 , 39 , 3595), // #352 - INST(Stumaxh , BaseAtomicSt , (0b0111100000100000011000, kW , 0 ) , kRWI_RX , 0 , 40 , 3579), // #353 - INST(Stumaxlh , BaseAtomicSt , (0b0111100001100000011000, kW , 0 ) , kRWI_RX , 0 , 41 , 3604), // #354 - INST(Stumin , BaseAtomicSt , (0b1011100000100000011100, kWX, 30) , kRWI_RX , 0 , 42 , 3613), // #355 - INST(Stuminl , BaseAtomicSt , (0b1011100001100000011100, kWX, 30) , kRWI_RX , 0 , 43 , 3636), // #356 - INST(Stuminb , BaseAtomicSt , (0b0011100000100000011100, kW , 0 ) , kRWI_RX , 0 , 44 , 3620), // #357 - INST(Stuminlb , BaseAtomicSt , (0b0011100001100000011100, kW , 0 ) , kRWI_RX , 0 , 45 , 3644), // #358 - INST(Stuminh , BaseAtomicSt , (0b0111100000100000011100, kW , 0 ) , kRWI_RX , 0 , 46 , 3628), // #359 - INST(Stuminlh , BaseAtomicSt , (0b0111100001100000011100, kW , 0 ) , kRWI_RX , 0 , 47 , 3653), // #360 - INST(Stur , BaseRM_SImm9 , (0b1011100000000000000000, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_RW , 0 , 18 , 3662), // #361 - INST(Sturb , BaseRM_SImm9 , (0b0011100000000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 19 , 3667), // #362 - INST(Sturh , BaseRM_SImm9 , (0b0111100000000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 20 , 3673), // #363 - INST(Stxp , BaseStxp , (0b1000100000100000000000, kWX, 30) , kRWI_WRRW , 0 , 1 , 3679), // #364 - INST(Stxr , BaseStx , (0b1000100000000000011111, kWX, 30) , kRWI_WRW , 0 , 0 , 3684), // #365 - INST(Stxrb , BaseStx , (0b0000100000000000011111, kW , 0 ) , kRWI_WRW , 0 , 1 , 3689), // #366 - INST(Stxrh , BaseStx , (0b0100100000000000011111, kW , 0 ) , kRWI_WRW , 0 , 2 , 3695), // #367 - INST(Stz2g , BaseRM_SImm9 , (0b1101100111100000000010, 0b1101100111100000000001, kX , kSP, 0, 4) , kRWI_RW , 0 , 21 , 3701), // #368 - INST(Stzg , BaseRM_SImm9 , (0b1101100101100000000010, 0b1101100101100000000001, kX , kSP, 0, 4) , kRWI_RW , 0 , 22 , 3707), // #369 - INST(Stzgm , BaseRM_NoImm , (0b1101100100100000000000, kX , kZR, 0) , kRWI_RW , 0 , 20 , 3712), // #370 - INST(Sub , BaseAddSub , (0b1001011000, 0b1001011001, 0b1010001) , kRWI_X , 0 , 2 , 985 ), // #371 - INST(Subg , BaseRRII , (0b1101000110000000000000, kX, kSP, kX, kSP, 6, 4, 16, 4, 0, 10) , kRWI_W , 0 , 1 , 3718), // #372 - INST(Subp , BaseRRR , (0b1001101011000000000000, kX, kZR, kX, kSP, kX, kSP, false) , kRWI_W , 0 , 20 , 3723), // #373 - INST(Subps , BaseRRR , (0b1011101011000000000000, kX, kZR, kX, kSP, kX, kSP, false) , kRWI_W , 0 , 21 , 3728), // #374 - INST(Subs , BaseAddSub , (0b1101011000, 0b1101011001, 0b1110001) , kRWI_X , 0 , 3 , 3734), // #375 - INST(Svc , BaseOpImm , (0b11010100000000000000000000000001, 16, 5) , 0 , 0 , 12 , 3752), // #376 - INST(Swp , BaseAtomicOp , (0b1011100000100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 111, 3756), // #377 - INST(Swpa , BaseAtomicOp , (0b1011100010100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 112, 3760), // #378 - INST(Swpab , BaseAtomicOp , (0b0011100010100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 113, 3765), // #379 - INST(Swpah , BaseAtomicOp , (0b0111100010100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 114, 3771), // #380 - INST(Swpal , BaseAtomicOp , (0b1011100011100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 115, 3777), // #381 - INST(Swpalb , BaseAtomicOp , (0b0011100011100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 116, 3783), // #382 - INST(Swpalh , BaseAtomicOp , (0b0111100011100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 117, 3790), // #383 - INST(Swpb , BaseAtomicOp , (0b0011100000100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 118, 3797), // #384 - INST(Swph , BaseAtomicOp , (0b0111100000100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 119, 3802), // #385 - INST(Swpl , BaseAtomicOp , (0b1011100001100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 120, 3807), // #386 - INST(Swplb , BaseAtomicOp , (0b0011100001100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 121, 3812), // #387 - INST(Swplh , BaseAtomicOp , (0b0111100001100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 122, 3818), // #388 - INST(Sxtb , BaseExtend , (0b0001001100000000000111, kWX, 0) , kRWI_W , 0 , 0 , 3824), // #389 - INST(Sxth , BaseExtend , (0b0001001100000000001111, kWX, 0) , kRWI_W , 0 , 1 , 3829), // #390 - INST(Sxtw , BaseExtend , (0b1001001101000000011111, kX , 0) , kRWI_W , 0 , 2 , 3845), // #391 - INST(Sys , BaseSys , (_) , kRWI_W , 0 , 0 , 3850), // #392 - INST(Tlbi , BaseAtDcIcTlbi , (0b00011110000000, 0b00010000000000, false) , kRWI_RX , 0 , 3 , 3871), // #393 - INST(Tst , BaseTst , (0b1101010000, 0b111001000) , kRWI_R , 0 , 0 , 437 ), // #394 - INST(Tbnz , BaseBranchTst , (0b00110111000000000000000000000000) , kRWI_R , 0 , 0 , 3858), // #395 - INST(Tbz , BaseBranchTst , (0b00110110000000000000000000000000) , kRWI_R , 0 , 1 , 3867), // #396 - INST(Ubfiz , BaseBfi , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 , 3969), // #397 - INST(Ubfm , BaseBfm , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 , 3975), // #398 - INST(Ubfx , BaseBfx , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 , 3980), // #399 - INST(Udf , BaseOpImm , (0b00000000000000000000000000000000, 16, 0) , 0 , 0 , 13 , 3991), // #400 - INST(Udiv , BaseRRR , (0b0001101011000000000010, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 22 , 3995), // #401 - INST(Umaddl , BaseRRRR , (0b1001101110100000000000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 4 , 4012), // #402 - INST(Umnegl , BaseRRR , (0b1001101110100000111111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 23 , 4075), // #403 - INST(Umull , BaseRRR , (0b1001101110100000011111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 24 , 4100), // #404 - INST(Umulh , BaseRRR , (0b1001101111000000011111, kX , kZR, kX , kZR, kX , kZR, false) , kRWI_W , 0 , 25 , 4094), // #405 - INST(Umsubl , BaseRRRR , (0b1001101110100000100000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 5 , 4087), // #406 - INST(Uxtb , BaseExtend , (0b0101001100000000000111, kW, 1) , kRWI_W , 0 , 3 , 4291), // #407 - INST(Uxth , BaseExtend , (0b0101001100000000001111, kW, 1) , kRWI_W , 0 , 4 , 4296), // #408 - INST(Wfe , BaseOp , (0b11010101000000110010000001011111) , 0 , 0 , 18 , 4322), // #409 - INST(Wfi , BaseOp , (0b11010101000000110010000001111111) , 0 , 0 , 19 , 4326), // #410 - INST(Xaflag , BaseOp , (0b11010101000000000100000000111111) , 0 , 0 , 20 , 4330), // #411 - INST(Xpacd , BaseR , (0b11011010110000010100011111100000, kX, kZR, 0) , kRWI_X , 0 , 8 , 4341), // #412 - INST(Xpaci , BaseR , (0b11011010110000010100001111100000, kX, kZR, 0) , kRWI_X , 0 , 9 , 4347), // #413 - INST(Xpaclri , BaseOp , (0b11010101000000110010000011111111) , kRWI_X , 0 , 21 , 4353), // #414 - INST(Yield , BaseOp , (0b11010101000000110010000000111111) , 0 , 0 , 22 , 4361), // #415 - INST(Abs_v , ISimdVV , (0b0000111000100000101110, kVO_V_Any) , kRWI_W , 0 , 0 , 2855), // #416 - INST(Add_v , ISimdVVV , (0b0000111000100000100001, kVO_V_Any) , kRWI_W , 0 , 0 , 978 ), // #417 - INST(Addhn_v , ISimdVVV , (0b0000111000100000010000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 1 , 2345), // #418 - INST(Addhn2_v , ISimdVVV , (0b0100111000100000010000, kVO_V_B16H8S4) , kRWI_W , F(Narrow) , 2 , 2352), // #419 - INST(Addp_v , ISimdPair , (0b0101111000110001101110, 0b0000111000100000101111, kVO_V_Any) , kRWI_W , F(Pair) , 0 , 638 ), // #420 - INST(Addv_v , ISimdSV , (0b0000111000110001101110, kVO_V_BH_4S) , kRWI_W , 0 , 0 , 20 ), // #421 - INST(Aesd_v , ISimdVVx , (0b0100111000101000010110, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 0 , 34 ), // #422 - INST(Aese_v , ISimdVVx , (0b0100111000101000010010, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 1 , 39 ), // #423 - INST(Aesimc_v , ISimdVVx , (0b0100111000101000011110, kOp_V16B, kOp_V16B) , kRWI_W , 0 , 2 , 44 ), // #424 - INST(Aesmc_v , ISimdVVx , (0b0100111000101000011010, kOp_V16B, kOp_V16B) , kRWI_W , 0 , 3 , 51 ), // #425 - INST(And_v , ISimdVVV , (0b0000111000100000000111, kVO_V_B) , kRWI_W , 0 , 3 , 57 ), // #426 - INST(Bcax_v , ISimdVVVV , (0b1100111000100000000000, kVO_V_B16) , kRWI_W , 0 , 0 , 187 ), // #427 - INST(Bfcvt_v , ISimdVVx , (0b0001111001100011010000, kOp_H, kOp_S) , kRWI_W , 0 , 4 , 196 ), // #428 - INST(Bfcvtn_v , ISimdVVx , (0b0000111010100001011010, kOp_V4H, kOp_V4S) , kRWI_W , F(Narrow) , 5 , 202 ), // #429 - INST(Bfcvtn2_v , ISimdVVx , (0b0100111010100001011010, kOp_V8H, kOp_V4S) , kRWI_W , F(Narrow) , 6 , 209 ), // #430 - INST(Bfdot_v , SimdDot , (0b0010111001000000111111, 0b0000111101000000111100, kET_S, kET_H, kET_2H) , kRWI_X , 0 , 0 , 217 ), // #431 - INST(Bfmlalb_v , SimdFmlal , (0b0010111011000000111111, 0b0000111111000000111100, 0, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 0 , 227 ), // #432 - INST(Bfmlalt_v , SimdFmlal , (0b0110111011000000111111, 0b0100111111000000111100, 0, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 1 , 235 ), // #433 - INST(Bfmmla_v , ISimdVVVx , (0b0110111001000000111011, kOp_V4S, kOp_V8H, kOp_V8H) , kRWI_X , F(Long) , 0 , 243 ), // #434 - INST(Bic_v , SimdBicOrr , (0b0000111001100000000111, 0b0010111100000000000001) , kRWI_W , 0 , 0 , 256 ), // #435 - INST(Bif_v , ISimdVVV , (0b0010111011100000000111, kVO_V_B) , kRWI_X , 0 , 4 , 265 ), // #436 - INST(Bit_v , ISimdVVV , (0b0010111010100000000111, kVO_V_B) , kRWI_X , 0 , 5 , 2365), // #437 - INST(Bsl_v , ISimdVVV , (0b0010111001100000000111, kVO_V_B) , kRWI_X , 0 , 6 , 280 ), // #438 - INST(Cls_v , ISimdVV , (0b0000111000100000010010, kVO_V_BHS) , kRWI_W , 0 , 1 , 412 ), // #439 - INST(Clz_v , ISimdVV , (0b0010111000100000010010, kVO_V_BHS) , kRWI_W , 0 , 2 , 416 ), // #440 - INST(Cmeq_v , SimdCmp , (0b0010111000100000100011, 0b0000111000100000100110, kVO_V_Any) , kRWI_W , 0 , 0 , 663 ), // #441 - INST(Cmge_v , SimdCmp , (0b0000111000100000001111, 0b0010111000100000100010, kVO_V_Any) , kRWI_W , 0 , 1 , 669 ), // #442 - INST(Cmgt_v , SimdCmp , (0b0000111000100000001101, 0b0000111000100000100010, kVO_V_Any) , kRWI_W , 0 , 2 , 675 ), // #443 - INST(Cmhi_v , SimdCmp , (0b0010111000100000001101, 0b0000000000000000000000, kVO_V_Any) , kRWI_W , 0 , 3 , 420 ), // #444 - INST(Cmhs_v , SimdCmp , (0b0010111000100000001111, 0b0000000000000000000000, kVO_V_Any) , kRWI_W , 0 , 4 , 425 ), // #445 - INST(Cmle_v , SimdCmp , (0b0000000000000000000000, 0b0010111000100000100110, kVO_V_Any) , kRWI_W , 0 , 5 , 687 ), // #446 - INST(Cmlt_v , SimdCmp , (0b0000000000000000000000, 0b0000111000100000101010, kVO_V_Any) , kRWI_W , 0 , 6 , 693 ), // #447 - INST(Cmtst_v , ISimdVVV , (0b0000111000100000100011, kVO_V_Any) , kRWI_W , 0 , 7 , 435 ), // #448 - INST(Cnt_v , ISimdVV , (0b0000111000100000010110, kVO_V_B) , kRWI_W , 0 , 3 , 446 ), // #449 - INST(Dup_v , SimdDup , (_) , kRWI_W , 0 , 0 , 579 ), // #450 - INST(Eor_v , ISimdVVV , (0b0010111000100000000111, kVO_V_B) , kRWI_W , 0 , 8 , 1418), // #451 - INST(Eor3_v , ISimdVVVV , (0b1100111000000000000000, kVO_V_B16) , kRWI_W , 0 , 1 , 587 ), // #452 - INST(Ext_v , ISimdVVVI , (0b0010111000000000000000, kVO_V_B, 4, 11, 1) , kRWI_W , 0 , 0 , 601 ), // #453 - INST(Fabd_v , FSimdVVV , (0b0111111010100000110101, kHF_C, 0b0010111010100000110101, kHF_C) , kRWI_W , 0 , 0 , 610 ), // #454 - INST(Fabs_v , FSimdVV , (0b0001111000100000110000, kHF_A, 0b0000111010100000111110, kHF_B) , kRWI_W , 0 , 0 , 615 ), // #455 - INST(Facge_v , FSimdVVV , (0b0111111000100000111011, kHF_C, 0b0010111000100000111011, kHF_C) , kRWI_W , 0 , 1 , 620 ), // #456 - INST(Facgt_v , FSimdVVV , (0b0111111010100000111011, kHF_C, 0b0010111010100000111011, kHF_C) , kRWI_W , 0 , 2 , 626 ), // #457 - INST(Fadd_v , FSimdVVV , (0b0001111000100000001010, kHF_A, 0b0000111000100000110101, kHF_C) , kRWI_W , 0 , 3 , 632 ), // #458 - INST(Faddp_v , FSimdPair , (0b0111111000110000110110, 0b0010111000100000110101) , kRWI_W , 0 , 0 , 637 ), // #459 - INST(Fcadd_v , SimdFcadd , (0b0010111000000000111001) , kRWI_W , 0 , 0 , 643 ), // #460 - INST(Fccmp_v , SimdFccmpFccmpe , (0b00011110001000000000010000000000) , kRWI_R , 0 , 0 , 649 ), // #461 - INST(Fccmpe_v , SimdFccmpFccmpe , (0b00011110001000000000010000010000) , kRWI_R , 0 , 1 , 655 ), // #462 - INST(Fcmeq_v , SimdFcm , (0b0000111000100000111001, kHF_C, 0b0000111010100000110110) , kRWI_W , 0 , 0 , 662 ), // #463 - INST(Fcmge_v , SimdFcm , (0b0010111000100000111001, kHF_C, 0b0010111010100000110010) , kRWI_W , 0 , 1 , 668 ), // #464 - INST(Fcmgt_v , SimdFcm , (0b0010111010100000111001, kHF_C, 0b0000111010100000110010) , kRWI_W , 0 , 2 , 674 ), // #465 - INST(Fcmla_v , SimdFcmla , (0b0010111000000000110001, 0b0010111100000000000100) , kRWI_X , 0 , 0 , 680 ), // #466 - INST(Fcmle_v , SimdFcm , (0b0000000000000000000000, kHF_C, 0b0010111010100000110110) , kRWI_W , 0 , 3 , 686 ), // #467 - INST(Fcmlt_v , SimdFcm , (0b0000000000000000000000, kHF_C, 0b0000111010100000111010) , kRWI_W , 0 , 4 , 692 ), // #468 - INST(Fcmp_v , SimdFcmpFcmpe , (0b00011110001000000010000000000000) , kRWI_R , 0 , 0 , 698 ), // #469 - INST(Fcmpe_v , SimdFcmpFcmpe , (0b00011110001000000010000000010000) , kRWI_R , 0 , 1 , 703 ), // #470 - INST(Fcsel_v , SimdFcsel , (_) , kRWI_W , 0 , 0 , 709 ), // #471 - INST(Fcvt_v , SimdFcvt , (_) , kRWI_W , 0 , 0 , 197 ), // #472 - INST(Fcvtas_v , SimdFcvtSV , (0b0000111000100001110010, 0b0000000000000000000000, 0b0001111000100100000000, 1) , kRWI_W , 0 , 0 , 715 ), // #473 - INST(Fcvtau_v , SimdFcvtSV , (0b0010111000100001110010, 0b0000000000000000000000, 0b0001111000100101000000, 1) , kRWI_W , 0 , 1 , 722 ), // #474 - INST(Fcvtl_v , SimdFcvtLN , (0b0000111000100001011110, 0, 0) , kRWI_W , F(Long) , 0 , 729 ), // #475 - INST(Fcvtl2_v , SimdFcvtLN , (0b0100111000100001011110, 0, 0) , kRWI_W , F(Long) , 1 , 735 ), // #476 - INST(Fcvtms_v , SimdFcvtSV , (0b0000111000100001101110, 0b0000000000000000000000, 0b0001111000110000000000, 1) , kRWI_W , 0 , 2 , 742 ), // #477 - INST(Fcvtmu_v , SimdFcvtSV , (0b0010111000100001101110, 0b0000000000000000000000, 0b0001111000110001000000, 1) , kRWI_W , 0 , 3 , 749 ), // #478 - INST(Fcvtn_v , SimdFcvtLN , (0b0000111000100001011010, 0, 0) , kRWI_W , F(Narrow) , 2 , 203 ), // #479 - INST(Fcvtn2_v , SimdFcvtLN , (0b0100111000100001011010, 0, 0) , kRWI_X , F(Narrow) , 3 , 210 ), // #480 - INST(Fcvtns_v , SimdFcvtSV , (0b0000111000100001101010, 0b0000000000000000000000, 0b0001111000100000000000, 1) , kRWI_W , 0 , 4 , 756 ), // #481 - INST(Fcvtnu_v , SimdFcvtSV , (0b0010111000100001101010, 0b0000000000000000000000, 0b0001111000100001000000, 1) , kRWI_W , 0 , 5 , 763 ), // #482 - INST(Fcvtps_v , SimdFcvtSV , (0b0000111010100001101010, 0b0000000000000000000000, 0b0001111000101000000000, 1) , kRWI_W , 0 , 6 , 770 ), // #483 - INST(Fcvtpu_v , SimdFcvtSV , (0b0010111010100001101010, 0b0000000000000000000000, 0b0001111000101001000000, 1) , kRWI_W , 0 , 7 , 777 ), // #484 - INST(Fcvtxn_v , SimdFcvtLN , (0b0010111000100001011010, 1, 1) , kRWI_W , F(Narrow) , 4 , 784 ), // #485 - INST(Fcvtxn2_v , SimdFcvtLN , (0b0110111000100001011010, 1, 0) , kRWI_X , F(Narrow) , 5 , 791 ), // #486 - INST(Fcvtzs_v , SimdFcvtSV , (0b0000111010100001101110, 0b0000111100000000111111, 0b0001111000111000000000, 1) , kRWI_W , 0 , 8 , 799 ), // #487 - INST(Fcvtzu_v , SimdFcvtSV , (0b0010111010100001101110, 0b0010111100000000111111, 0b0001111000111001000000, 1) , kRWI_W , 0 , 9 , 806 ), // #488 - INST(Fdiv_v , FSimdVVV , (0b0001111000100000000110, kHF_A, 0b0010111000100000111111, kHF_C) , kRWI_W , 0 , 4 , 813 ), // #489 - INST(Fjcvtzs_v , ISimdVVx , (0b0001111001111110000000, kOp_GpW, kOp_D) , kRWI_W , 0 , 7 , 818 ), // #490 - INST(Fmadd_v , FSimdVVVV , (0b0001111100000000000000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 0 , 826 ), // #491 - INST(Fmax_v , FSimdVVV , (0b0001111000100000010010, kHF_A, 0b0000111000100000111101, kHF_C) , kRWI_W , 0 , 5 , 832 ), // #492 - INST(Fmaxnm_v , FSimdVVV , (0b0001111000100000011010, kHF_A, 0b0000111000100000110001, kHF_C) , kRWI_W , 0 , 6 , 837 ), // #493 - INST(Fmaxnmp_v , FSimdPair , (0b0111111000110000110010, 0b0010111000100000110001) , kRWI_W , 0 , 1 , 844 ), // #494 - INST(Fmaxnmv_v , FSimdSV , (0b0010111000110000110010) , kRWI_W , 0 , 0 , 852 ), // #495 - INST(Fmaxp_v , FSimdPair , (0b0111111000110000111110, 0b0010111000100000111101) , kRWI_W , 0 , 2 , 860 ), // #496 - INST(Fmaxv_v , FSimdSV , (0b0010111000110000111110) , kRWI_W , 0 , 1 , 866 ), // #497 - INST(Fmin_v , FSimdVVV , (0b0001111000100000010110, kHF_A, 0b0000111010100000111101, kHF_C) , kRWI_W , 0 , 7 , 872 ), // #498 - INST(Fminnm_v , FSimdVVV , (0b0001111000100000011110, kHF_A, 0b0000111010100000110001, kHF_C) , kRWI_W , 0 , 8 , 877 ), // #499 - INST(Fminnmp_v , FSimdPair , (0b0111111010110000110010, 0b0010111010100000110001) , kRWI_W , 0 , 3 , 884 ), // #500 - INST(Fminnmv_v , FSimdSV , (0b0010111010110000110010) , kRWI_W , 0 , 2 , 892 ), // #501 - INST(Fminp_v , FSimdPair , (0b0111111010110000111110, 0b0010111010100000111101) , kRWI_W , 0 , 4 , 900 ), // #502 - INST(Fminv_v , FSimdSV , (0b0010111010110000111110) , kRWI_W , 0 , 3 , 906 ), // #503 - INST(Fmla_v , FSimdVVVe , (0b0000000000000000000000, kHF_N, 0b0000111000100000110011, 0b0000111110000000000100) , kRWI_X , F(VH0_15) , 0 , 912 ), // #504 - INST(Fmlal_v , SimdFmlal , (0b0000111000100000111011, 0b0000111110000000000000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 2 , 917 ), // #505 - INST(Fmlal2_v , SimdFmlal , (0b0010111000100000110011, 0b0010111110000000100000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 3 , 923 ), // #506 - INST(Fmls_v , FSimdVVVe , (0b0000000000000000000000, kHF_N, 0b0000111010100000110011, 0b0000111110000000010100) , kRWI_X , F(VH0_15) , 1 , 930 ), // #507 - INST(Fmlsl_v , SimdFmlal , (0b0000111010100000111011, 0b0000111110000000010000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 4 , 935 ), // #508 - INST(Fmlsl2_v , SimdFmlal , (0b0010111010100000110011, 0b0010111110000000110000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 5 , 941 ), // #509 - INST(Fmov_v , SimdFmov , (_) , kRWI_W , 0 , 0 , 948 ), // #510 - INST(Fmsub_v , FSimdVVVV , (0b0001111100000000100000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 1 , 953 ), // #511 - INST(Fmul_v , FSimdVVVe , (0b0001111000100000000010, kHF_A, 0b0010111000100000110111, 0b0000111110000000100100) , kRWI_W , F(VH0_15) , 2 , 959 ), // #512 - INST(Fmulx_v , FSimdVVVe , (0b0101111000100000110111, kHF_C, 0b0000111000100000110111, 0b0010111110000000100100) , kRWI_W , F(VH0_15) , 3 , 964 ), // #513 - INST(Fneg_v , FSimdVV , (0b0001111000100001010000, kHF_A, 0b0010111010100000111110, kHF_B) , kRWI_W , 0 , 1 , 970 ), // #514 - INST(Fnmadd_v , FSimdVVVV , (0b0001111100100000000000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 2 , 975 ), // #515 - INST(Fnmsub_v , FSimdVVVV , (0b0001111100100000100000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 3 , 982 ), // #516 - INST(Fnmul_v , FSimdVVV , (0b0001111000100000100010, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 9 , 989 ), // #517 - INST(Frecpe_v , FSimdVV , (0b0101111010100001110110, kHF_B, 0b0000111010100001110110, kHF_B) , kRWI_W , 0 , 2 , 995 ), // #518 - INST(Frecps_v , FSimdVVV , (0b0101111000100000111111, kHF_C, 0b0000111000100000111111, kHF_C) , kRWI_W , 0 , 10 , 1002), // #519 - INST(Frecpx_v , FSimdVV , (0b0101111010100001111110, kHF_B, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 3 , 1009), // #520 - INST(Frint32x_v , FSimdVV , (0b0001111000101000110000, kHF_N, 0b0010111000100001111010, kHF_N) , kRWI_W , 0 , 4 , 1016), // #521 - INST(Frint32z_v , FSimdVV , (0b0001111000101000010000, kHF_N, 0b0000111000100001111010, kHF_N) , kRWI_W , 0 , 5 , 1025), // #522 - INST(Frint64x_v , FSimdVV , (0b0001111000101001110000, kHF_N, 0b0010111000100001111110, kHF_N) , kRWI_W , 0 , 6 , 1034), // #523 - INST(Frint64z_v , FSimdVV , (0b0001111000101001010000, kHF_N, 0b0000111000100001111110, kHF_N) , kRWI_W , 0 , 7 , 1043), // #524 - INST(Frinta_v , FSimdVV , (0b0001111000100110010000, kHF_A, 0b0010111000100001100010, kHF_B) , kRWI_W , 0 , 8 , 1052), // #525 - INST(Frinti_v , FSimdVV , (0b0001111000100111110000, kHF_A, 0b0010111010100001100110, kHF_B) , kRWI_W , 0 , 9 , 1059), // #526 - INST(Frintm_v , FSimdVV , (0b0001111000100101010000, kHF_A, 0b0000111000100001100110, kHF_B) , kRWI_W , 0 , 10 , 1066), // #527 - INST(Frintn_v , FSimdVV , (0b0001111000100100010000, kHF_A, 0b0000111000100001100010, kHF_B) , kRWI_W , 0 , 11 , 1073), // #528 - INST(Frintp_v , FSimdVV , (0b0001111000100100110000, kHF_A, 0b0000111010100001100010, kHF_B) , kRWI_W , 0 , 12 , 1080), // #529 - INST(Frintx_v , FSimdVV , (0b0001111000100111010000, kHF_A, 0b0010111000100001100110, kHF_B) , kRWI_W , 0 , 13 , 1087), // #530 - INST(Frintz_v , FSimdVV , (0b0001111000100101110000, kHF_A, 0b0000111010100001100110, kHF_B) , kRWI_W , 0 , 14 , 1094), // #531 - INST(Frsqrte_v , FSimdVV , (0b0111111010100001110110, kHF_B, 0b0010111010100001110110, kHF_B) , kRWI_W , 0 , 15 , 1101), // #532 - INST(Frsqrts_v , FSimdVVV , (0b0101111010100000111111, kHF_C, 0b0000111010100000111111, kHF_C) , kRWI_W , 0 , 11 , 1109), // #533 - INST(Fsqrt_v , FSimdVV , (0b0001111000100001110000, kHF_A, 0b0010111010100001111110, kHF_B) , kRWI_W , 0 , 16 , 1117), // #534 - INST(Fsub_v , FSimdVVV , (0b0001111000100000001110, kHF_A, 0b0000111010100000110101, kHF_C) , kRWI_W , 0 , 12 , 1123), // #535 - INST(Ins_v , SimdIns , (_) , kRWI_X , 0 , 0 , 1145), // #536 - INST(Ld1_v , SimdLdNStN , (0b0000110101000000000000, 0b0000110001000000001000, 1, 0) , kRWI_LDn , F(Consecutive) , 0 , 1153), // #537 - INST(Ld1r_v , SimdLdNStN , (0b0000110101000000110000, 0b0000000000000000000000, 1, 1) , kRWI_LDn , F(Consecutive) , 1 , 1157), // #538 - INST(Ld2_v , SimdLdNStN , (0b0000110101100000000000, 0b0000110001000000100000, 2, 0) , kRWI_LDn , F(Consecutive) , 2 , 1162), // #539 - INST(Ld2r_v , SimdLdNStN , (0b0000110101100000110000, 0b0000000000000000000000, 2, 1) , kRWI_LDn , F(Consecutive) , 3 , 1166), // #540 - INST(Ld3_v , SimdLdNStN , (0b0000110101000000001000, 0b0000110001000000010000, 3, 0) , kRWI_LDn , F(Consecutive) , 4 , 1171), // #541 - INST(Ld3r_v , SimdLdNStN , (0b0000110101000000111000, 0b0000000000000000000000, 3, 1) , kRWI_LDn , F(Consecutive) , 5 , 1175), // #542 - INST(Ld4_v , SimdLdNStN , (0b0000110101100000001000, 0b0000110001000000000000, 4, 0) , kRWI_LDn , F(Consecutive) , 6 , 1180), // #543 - INST(Ld4r_v , SimdLdNStN , (0b0000110101100000111000, 0b0000000000000000000000, 4, 1) , kRWI_LDn , F(Consecutive) , 7 , 1184), // #544 - INST(Ldnp_v , SimdLdpStp , (0b0010110001, 0b0000000000) , kRWI_WW , 0 , 0 , 1537), // #545 - INST(Ldp_v , SimdLdpStp , (0b0010110101, 0b0010110011) , kRWI_WW , 0 , 1 , 1542), // #546 - INST(Ldr_v , SimdLdSt , (0b0011110101, 0b00111100010, 0b00111100011, 0b00011100, Inst::kIdLdur_v) , kRWI_W , 0 , 0 , 1552), // #547 - INST(Ldur_v , SimdLdurStur , (0b0011110001000000000000) , kRWI_W , 0 , 0 , 2142), // #548 - INST(Mla_v , ISimdVVVe , (0b0000111000100000100101, kVO_V_BHS, 0b0010111100000000000000, kVO_V_HS) , kRWI_X , F(VH0_15) , 0 , 246 ), // #549 - INST(Mls_v , ISimdVVVe , (0b0010111000100000100101, kVO_V_BHS, 0b0010111100000000010000, kVO_V_HS) , kRWI_X , F(VH0_15) , 1 , 931 ), // #550 - INST(Mov_v , SimdMov , (_) , kRWI_W , 0 , 0 , 949 ), // #551 - INST(Movi_v , SimdMoviMvni , (0b0000111100000000000001, 0) , kRWI_W , 0 , 0 , 2221), // #552 - INST(Mul_v , ISimdVVVe , (0b0000111000100000100111, kVO_V_BHS, 0b0000111100000000100000, kVO_V_HS) , kRWI_W , F(VH0_15) , 2 , 991 ), // #553 - INST(Mvn_v , ISimdVV , (0b0010111000100000010110, kVO_V_B) , kRWI_W , 0 , 4 , 2249), // #554 - INST(Mvni_v , SimdMoviMvni , (0b0000111100000000000001, 1) , kRWI_W , 0 , 1 , 2253), // #555 - INST(Neg_v , ISimdVV , (0b0010111000100000101110, kVO_V_Any) , kRWI_W , 0 , 5 , 540 ), // #556 - INST(Not_v , ISimdVV , (0b0010111000100000010110, kVO_V_B) , kRWI_W , 0 , 6 , 2276), // #557 - INST(Orn_v , ISimdVVV , (0b0000111011100000000111, kVO_V_B) , kRWI_W , 0 , 9 , 2280), // #558 - INST(Orr_v , SimdBicOrr , (0b0000111010100000000111, 0b0000111100000000000001) , kRWI_W , 0 , 1 , 2284), // #559 - INST(Pmul_v , ISimdVVV , (0b0010111000100000100111, kVO_V_B) , kRWI_W , 0 , 10 , 2320), // #560 - INST(Pmull_v , ISimdVVV , (0b0000111000100000111000, kVO_V_B8D1) , kRWI_W , F(Long) , 11 , 2325), // #561 - INST(Pmull2_v , ISimdVVV , (0b0100111000100000111000, kVO_V_B16D2) , kRWI_W , F(Long) , 12 , 2331), // #562 - INST(Raddhn_v , ISimdVVV , (0b0010111000100000010000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 13 , 2344), // #563 - INST(Raddhn2_v , ISimdVVV , (0b0110111000100000010000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 14 , 2351), // #564 - INST(Rax1_v , ISimdVVV , (0b1100111001100000100011, kVO_V_D2) , kRWI_W , 0 , 15 , 2359), // #565 - INST(Rbit_v , ISimdVV , (0b0010111001100000010110, kVO_V_B) , kRWI_W , 0 , 7 , 2364), // #566 - INST(Rev16_v , ISimdVV , (0b0000111000100000000110, kVO_V_B) , kRWI_W , 0 , 8 , 2373), // #567 - INST(Rev32_v , ISimdVV , (0b0010111000100000000010, kVO_V_BH) , kRWI_W , 0 , 9 , 2379), // #568 - INST(Rev64_v , ISimdVV , (0b0000111000100000000010, kVO_V_BHS) , kRWI_W , 0 , 10 , 2385), // #569 - INST(Rshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100011, 1, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 0 , 2960), // #570 - INST(Rshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100011, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 1 , 2968), // #571 - INST(Rsubhn_v , ISimdVVV , (0b0010111000100000011000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 16 , 2400), // #572 - INST(Rsubhn2_v , ISimdVVV , (0b0110111000100000011000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 17 , 2407), // #573 - INST(Saba_v , ISimdVVV , (0b0000111000100000011111, kVO_V_BHS) , kRWI_X , 0 , 18 , 2415), // #574 - INST(Sabal_v , ISimdVVV , (0b0000111000100000010100, kVO_V_B8H4S2) , kRWI_X , F(Long) , 19 , 2420), // #575 - INST(Sabal2_v , ISimdVVV , (0b0100111000100000010100, kVO_V_B16H8S4) , kRWI_X , F(Long) , 20 , 2426), // #576 - INST(Sabd_v , ISimdVVV , (0b0000111000100000011101, kVO_V_BHS) , kRWI_W , 0 , 21 , 2433), // #577 - INST(Sabdl_v , ISimdVVV , (0b0000111000100000011100, kVO_V_B8H4S2) , kRWI_W , F(Long) , 22 , 2438), // #578 - INST(Sabdl2_v , ISimdVVV , (0b0100111000100000011100, kVO_V_B16H8S4) , kRWI_W , F(Long) , 23 , 2444), // #579 - INST(Sadalp_v , ISimdVV , (0b0000111000100000011010, kVO_V_BHS) , kRWI_X , F(Long) | F(Pair) , 11 , 2451), // #580 - INST(Saddl_v , ISimdVVV , (0b0000111000100000000000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 24 , 2458), // #581 - INST(Saddl2_v , ISimdVVV , (0b0100111000100000000000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 25 , 2464), // #582 - INST(Saddlp_v , ISimdVV , (0b0000111000100000001010, kVO_V_BHS) , kRWI_W , F(Long) | F(Pair) , 12 , 2471), // #583 - INST(Saddlv_v , ISimdSV , (0b0000111000110000001110, kVO_V_BH_4S) , kRWI_W , F(Long) , 1 , 2478), // #584 - INST(Saddw_v , ISimdWWV , (0b0000111000100000000100, kVO_V_B8H4S2) , kRWI_W , 0 , 0 , 2485), // #585 - INST(Saddw2_v , ISimdWWV , (0b0000111000100000000100, kVO_V_B16H8S4) , kRWI_W , 0 , 1 , 2491), // #586 - INST(Scvtf_v , SimdFcvtSV , (0b0000111000100001110110, 0b0000111100000000111001, 0b0001111000100010000000, 0) , kRWI_W , 0 , 10 , 2523), // #587 - INST(Sdot_v , SimdDot , (0b0000111010000000100101, 0b0000111110000000111000, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 1 , 4218), // #588 - INST(Sha1c_v , ISimdVVVx , (0b0101111000000000000000, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 1 , 2556), // #589 - INST(Sha1h_v , ISimdVVx , (0b0101111000101000000010, kOp_S, kOp_S) , kRWI_W , 0 , 8 , 2562), // #590 - INST(Sha1m_v , ISimdVVVx , (0b0101111000000000001000, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 2 , 2568), // #591 - INST(Sha1p_v , ISimdVVVx , (0b0101111000000000000100, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 3 , 2574), // #592 - INST(Sha1su0_v , ISimdVVVx , (0b0101111000000000001100, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 4 , 2580), // #593 - INST(Sha1su1_v , ISimdVVx , (0b0101111000101000000110, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 9 , 2588), // #594 - INST(Sha256h_v , ISimdVVVx , (0b0101111000000000010000, kOp_Q, kOp_Q, kOp_V4S) , kRWI_X , 0 , 5 , 2596), // #595 - INST(Sha256h2_v , ISimdVVVx , (0b0101111000000000010100, kOp_Q, kOp_Q, kOp_V4S) , kRWI_X , 0 , 6 , 2604), // #596 - INST(Sha256su0_v , ISimdVVx , (0b0101111000101000001010, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 10 , 2613), // #597 - INST(Sha256su1_v , ISimdVVVx , (0b0101111000000000011000, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 7 , 2623), // #598 - INST(Sha512h_v , ISimdVVVx , (0b1100111001100000100000, kOp_Q, kOp_Q, kOp_V2D) , kRWI_X , 0 , 8 , 2633), // #599 - INST(Sha512h2_v , ISimdVVVx , (0b1100111001100000100001, kOp_Q, kOp_Q, kOp_V2D) , kRWI_X , 0 , 9 , 2641), // #600 - INST(Sha512su0_v , ISimdVVx , (0b1100111011000000100000, kOp_V2D, kOp_V2D) , kRWI_X , 0 , 11 , 2650), // #601 - INST(Sha512su1_v , ISimdVVVx , (0b1100111001100000100010, kOp_V2D, kOp_V2D, kOp_V2D) , kRWI_X , 0 , 10 , 2660), // #602 - INST(Shadd_v , ISimdVVV , (0b0000111000100000000001, kVO_V_BHS) , kRWI_W , 0 , 26 , 2670), // #603 - INST(Shl_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000010101, 0, kVO_V_Any) , kRWI_W , 0 , 2 , 2954), // #604 - INST(Shll_v , SimdShiftES , (0b0010111000100001001110, kVO_V_B8H4S2) , kRWI_W , F(Long) , 0 , 3108), // #605 - INST(Shll2_v , SimdShiftES , (0b0110111000100001001110, kVO_V_B16H8S4) , kRWI_W , F(Long) , 1 , 3114), // #606 - INST(Shrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100001, 1, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 3 , 2961), // #607 - INST(Shrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100001, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 4 , 2969), // #608 - INST(Shsub_v , ISimdVVV , (0b0000111000100000001001, kVO_V_BHS) , kRWI_W , 0 , 27 , 2676), // #609 - INST(Sli_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000010101, 0, kVO_V_Any) , kRWI_X , 0 , 5 , 2682), // #610 - INST(Sm3partw1_v , ISimdVVVx , (0b1100111001100000110000, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 11 , 2686), // #611 - INST(Sm3partw2_v , ISimdVVVx , (0b1100111001100000110001, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 12 , 2696), // #612 - INST(Sm3ss1_v , ISimdVVVVx , (0b1100111001000000000000, kOp_V4S, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_W , 0 , 0 , 2706), // #613 - INST(Sm3tt1a_v , SimdSm3tt , (0b1100111001000000100000) , kRWI_X , 0 , 0 , 2713), // #614 - INST(Sm3tt1b_v , SimdSm3tt , (0b1100111001000000100001) , kRWI_X , 0 , 1 , 2721), // #615 - INST(Sm3tt2a_v , SimdSm3tt , (0b1100111001000000100010) , kRWI_X , 0 , 2 , 2729), // #616 - INST(Sm3tt2b_v , SimdSm3tt , (0b1100111001000000100011) , kRWI_X , 0 , 3 , 2737), // #617 - INST(Sm4e_v , ISimdVVx , (0b1100111011000000100001, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 12 , 2745), // #618 - INST(Sm4ekey_v , ISimdVVVx , (0b1100111001100000110010, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 13 , 2750), // #619 - INST(Smax_v , ISimdVVV , (0b0000111000100000011001, kVO_V_BHS) , kRWI_W , 0 , 28 , 1690), // #620 - INST(Smaxp_v , ISimdVVV , (0b0000111000100000101001, kVO_V_BHS) , kRWI_W , 0 , 29 , 2765), // #621 - INST(Smaxv_v , ISimdSV , (0b0000111000110000101010, kVO_V_BH_4S) , kRWI_W , 0 , 2 , 2771), // #622 - INST(Smin_v , ISimdVVV , (0b0000111000100000011011, kVO_V_BHS) , kRWI_W , 0 , 30 , 1794), // #623 - INST(Sminp_v , ISimdVVV , (0b0000111000100000101011, kVO_V_BHS) , kRWI_W , 0 , 31 , 2777), // #624 - INST(Sminv_v , ISimdSV , (0b0000111000110001101010, kVO_V_BH_4S) , kRWI_W , 0 , 3 , 2783), // #625 - INST(Smlal_v , ISimdVVVe , (0b0000111000100000100000, kVO_V_B8H4S2, 0b0000111100000000001000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 3 , 2789), // #626 - INST(Smlal2_v , ISimdVVVe , (0b0100111000100000100000, kVO_V_B16H8S4, 0b0100111100000000001000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 4 , 2795), // #627 - INST(Smlsl_v , ISimdVVVe , (0b0000111000100000101000, kVO_V_B8H4S2, 0b0000111100000000011000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 5 , 2802), // #628 - INST(Smlsl2_v , ISimdVVVe , (0b0100111000100000101000, kVO_V_B16H8S4, 0b0100111100000000011000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 6 , 2808), // #629 - INST(Smmla_v , ISimdVVVx , (0b0100111010000000101001, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 14 , 4247), // #630 - INST(Smov_v , SimdSmovUmov , (0b0000111000000000001011, kVO_V_BHS, 1) , kRWI_W , 0 , 0 , 2822), // #631 - INST(Smull_v , ISimdVVVe , (0b0000111000100000110000, kVO_V_B8H4S2, 0b0000111100000000101000, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 7 , 2840), // #632 - INST(Smull2_v , ISimdVVVe , (0b0100111000100000110000, kVO_V_B16H8S4, 0b0100111100000000101000, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 8 , 2846), // #633 - INST(Sqabs_v , ISimdVV , (0b0000111000100000011110, kVO_SV_Any) , kRWI_W , 0 , 13 , 2853), // #634 - INST(Sqadd_v , ISimdVVV , (0b0000111000100000000011, kVO_SV_Any) , kRWI_W , 0 , 32 , 4254), // #635 - INST(Sqdmlal_v , ISimdVVVe , (0b0000111000100000100100, kVO_SV_BHS, 0b0000111100000000001100, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 9 , 2859), // #636 - INST(Sqdmlal2_v , ISimdVVVe , (0b0100111000100000100100, kVO_V_B16H8S4, 0b0100111100000000001100, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 10 , 2867), // #637 - INST(Sqdmlsl_v , ISimdVVVe , (0b0000111000100000101100, kVO_SV_BHS, 0b0000111100000000011100, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 11 , 2876), // #638 - INST(Sqdmlsl2_v , ISimdVVVe , (0b0100111000100000101100, kVO_V_B16H8S4, 0b0100111100000000011100, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 12 , 2884), // #639 - INST(Sqdmulh_v , ISimdVVVe , (0b0000111000100000101101, kVO_SV_HS, 0b0000111100000000110000, kVO_SV_HS) , kRWI_W , F(VH0_15) , 13 , 2893), // #640 - INST(Sqdmull_v , ISimdVVVe , (0b0000111000100000110100, kVO_SV_BHS, 0b0000111100000000101100, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 14 , 2901), // #641 - INST(Sqdmull2_v , ISimdVVVe , (0b0100111000100000110100, kVO_V_B16H8S4, 0b0100111100000000101100, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 15 , 2909), // #642 - INST(Sqneg_v , ISimdVV , (0b0010111000100000011110, kVO_SV_Any) , kRWI_W , 0 , 14 , 2918), // #643 - INST(Sqrdmlah_v , ISimdVVVe , (0b0010111000000000100001, kVO_SV_HS, 0b0010111100000000110100, kVO_SV_HS) , kRWI_X , F(VH0_15) , 16 , 2924), // #644 - INST(Sqrdmlsh_v , ISimdVVVe , (0b0010111000000000100011, kVO_SV_HS, 0b0010111100000000111100, kVO_SV_HS) , kRWI_X , F(VH0_15) , 17 , 2933), // #645 - INST(Sqrdmulh_v , ISimdVVVe , (0b0010111000100000101101, kVO_SV_HS, 0b0000111100000000110100, kVO_SV_HS) , kRWI_W , F(VH0_15) , 18 , 2942), // #646 - INST(Sqrshl_v , SimdShift , (0b0000111000100000010111, 0b0000000000000000000000, 1, kVO_SV_Any) , kRWI_W , 0 , 6 , 2951), // #647 - INST(Sqrshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100111, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 7 , 2958), // #648 - INST(Sqrshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100111, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 8 , 2966), // #649 - INST(Sqrshrun_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100011, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 9 , 2975), // #650 - INST(Sqrshrun2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100011, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 10 , 2984), // #651 - INST(Sqshl_v , SimdShift , (0b0000111000100000010011, 0b0000111100000000011101, 0, kVO_SV_Any) , kRWI_W , 0 , 11 , 2994), // #652 - INST(Sqshlu_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000011001, 0, kVO_SV_Any) , kRWI_W , 0 , 12 , 3000), // #653 - INST(Sqshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100101, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 13 , 3007), // #654 - INST(Sqshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100101, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 14 , 3014), // #655 - INST(Sqshrun_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100001, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 15 , 3022), // #656 - INST(Sqshrun2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100001, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 16 , 3030), // #657 - INST(Sqsub_v , ISimdVVV , (0b0000111000100000001011, kVO_SV_Any) , kRWI_W , 0 , 33 , 3039), // #658 - INST(Sqxtn_v , ISimdVV , (0b0000111000100001010010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 15 , 3045), // #659 - INST(Sqxtn2_v , ISimdVV , (0b0100111000100001010010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 16 , 3051), // #660 - INST(Sqxtun_v , ISimdVV , (0b0010111000100001001010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 17 , 3058), // #661 - INST(Sqxtun2_v , ISimdVV , (0b0110111000100001001010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 18 , 3065), // #662 - INST(Srhadd_v , ISimdVVV , (0b0000111000100000000101, kVO_V_BHS) , kRWI_W , 0 , 34 , 3073), // #663 - INST(Sri_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000010001, 1, kVO_V_Any) , kRWI_W , 0 , 17 , 3080), // #664 - INST(Srshl_v , SimdShift , (0b0000111000100000010101, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 18 , 3084), // #665 - INST(Srshr_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000001001, 1, kVO_V_Any) , kRWI_W , 0 , 19 , 3090), // #666 - INST(Srsra_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000001101, 1, kVO_V_Any) , kRWI_X , 0 , 20 , 3096), // #667 - INST(Sshl_v , SimdShift , (0b0000111000100000010001, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 21 , 3102), // #668 - INST(Sshll_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000101001, 0, kVO_V_B8H4S2) , kRWI_W , F(Long) , 22 , 3107), // #669 - INST(Sshll2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000101001, 0, kVO_V_B16H8S4) , kRWI_W , F(Long) , 23 , 3113), // #670 - INST(Sshr_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000000001, 1, kVO_V_Any) , kRWI_W , 0 , 24 , 3120), // #671 - INST(Ssra_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000000101, 1, kVO_V_Any) , kRWI_X , 0 , 25 , 3125), // #672 - INST(Ssubl_v , ISimdVVV , (0b0000111000100000001000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 35 , 3130), // #673 - INST(Ssubl2_v , ISimdVVV , (0b0100111000100000001000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 36 , 3136), // #674 - INST(Ssubw_v , ISimdWWV , (0b0000111000100000001100, kVO_V_B8H4S2) , kRWI_W , 0 , 2 , 3143), // #675 - INST(Ssubw2_v , ISimdWWV , (0b0000111000100000001100, kVO_V_B16H8S4) , kRWI_X , 0 , 3 , 3149), // #676 - INST(St1_v , SimdLdNStN , (0b0000110100000000000000, 0b0000110000000000001000, 1, 0) , kRWI_STn , F(Consecutive) , 8 , 3156), // #677 - INST(St2_v , SimdLdNStN , (0b0000110100100000000000, 0b0000110000000000100000, 2, 0) , kRWI_STn , F(Consecutive) , 9 , 3160), // #678 - INST(St3_v , SimdLdNStN , (0b0000110100000000001000, 0b0000110000000000010000, 3, 0) , kRWI_STn , F(Consecutive) , 10 , 3169), // #679 - INST(St4_v , SimdLdNStN , (0b0000110100100000001000, 0b0000110000000000000000, 4, 0) , kRWI_STn , F(Consecutive) , 11 , 3173), // #680 - INST(Stnp_v , SimdLdpStp , (0b0010110000, 0b0000000000) , kRWI_RRW , 0 , 2 , 3383), // #681 - INST(Stp_v , SimdLdpStp , (0b0010110100, 0b0010110010) , kRWI_RRW , 0 , 3 , 3388), // #682 - INST(Str_v , SimdLdSt , (0b0011110100, 0b00111100000, 0b00111100001, 0b00000000, Inst::kIdStur_v) , kRWI_RW , 0 , 1 , 3392), // #683 - INST(Stur_v , SimdLdurStur , (0b0011110000000000000000) , kRWI_RW , 0 , 1 , 3662), // #684 - INST(Sub_v , ISimdVVV , (0b0010111000100000100001, kVO_V_Any) , kRWI_W , 0 , 37 , 985 ), // #685 - INST(Subhn_v , ISimdVVV , (0b0000111000100000011000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 38 , 2401), // #686 - INST(Subhn2_v , ISimdVVV , (0b0000111000100000011000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 39 , 2408), // #687 - INST(Sudot_v , SimdDot , (0b0000000000000000000000, 0b0000111100000000111100, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 2 , 3739), // #688 - INST(Suqadd_v , ISimdVV , (0b0000111000100000001110, kVO_SV_Any) , kRWI_X , 0 , 19 , 3745), // #689 - INST(Sxtl_v , SimdSxtlUxtl , (0b0000111100000000101001, kVO_V_B8H4S2) , kRWI_W , F(Long) , 0 , 3834), // #690 - INST(Sxtl2_v , SimdSxtlUxtl , (0b0100111100000000101001, kVO_V_B16H8S4) , kRWI_W , F(Long) , 1 , 3839), // #691 - INST(Tbl_v , SimdTblTbx , (0b0000111000000000000000) , kRWI_W , 0 , 0 , 3854), // #692 - INST(Tbx_v , SimdTblTbx , (0b0000111000000000000100) , kRWI_W , 0 , 1 , 3863), // #693 - INST(Trn1_v , ISimdVVV , (0b0000111000000000001010, kVO_V_BHS_D2) , kRWI_W , 0 , 40 , 3876), // #694 - INST(Trn2_v , ISimdVVV , (0b0000111000000000011010, kVO_V_BHS_D2) , kRWI_W , 0 , 41 , 3881), // #695 - INST(Uaba_v , ISimdVVV , (0b0010111000100000011111, kVO_V_BHS) , kRWI_X , 0 , 42 , 3886), // #696 - INST(Uabal_v , ISimdVVV , (0b0010111000100000010100, kVO_V_B8H4S2) , kRWI_X , F(Long) , 43 , 3891), // #697 - INST(Uabal2_v , ISimdVVV , (0b0110111000100000010100, kVO_V_B16H8S4) , kRWI_X , F(Long) , 44 , 3897), // #698 - INST(Uabd_v , ISimdVVV , (0b0010111000100000011101, kVO_V_BHS) , kRWI_W , 0 , 45 , 3904), // #699 - INST(Uabdl_v , ISimdVVV , (0b0010111000100000011100, kVO_V_B8H4S2) , kRWI_W , F(Long) , 46 , 3909), // #700 - INST(Uabdl2_v , ISimdVVV , (0b0110111000100000011100, kVO_V_B16H8S4) , kRWI_W , F(Long) , 47 , 3915), // #701 - INST(Uadalp_v , ISimdVV , (0b0010111000100000011010, kVO_V_BHS) , kRWI_X , F(Long) | F(Pair) , 20 , 3922), // #702 - INST(Uaddl_v , ISimdVVV , (0b0010111000100000000000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 48 , 3929), // #703 - INST(Uaddl2_v , ISimdVVV , (0b0110111000100000000000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 49 , 3935), // #704 - INST(Uaddlp_v , ISimdVV , (0b0010111000100000001010, kVO_V_BHS) , kRWI_W , F(Long) | F(Pair) , 21 , 3942), // #705 - INST(Uaddlv_v , ISimdSV , (0b0010111000110000001110, kVO_V_BH_4S) , kRWI_W , F(Long) , 4 , 3949), // #706 - INST(Uaddw_v , ISimdWWV , (0b0010111000100000000100, kVO_V_B8H4S2) , kRWI_W , 0 , 4 , 3956), // #707 - INST(Uaddw2_v , ISimdWWV , (0b0010111000100000000100, kVO_V_B16H8S4) , kRWI_W , 0 , 5 , 3962), // #708 - INST(Ucvtf_v , SimdFcvtSV , (0b0010111000100001110110, 0b0010111100000000111001, 0b0001111000100011000000, 0) , kRWI_W , 0 , 11 , 3985), // #709 - INST(Udot_v , SimdDot , (0b0010111010000000100101, 0b0010111110000000111000, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 3 , 3740), // #710 - INST(Uhadd_v , ISimdVVV , (0b0010111000100000000001, kVO_V_BHS) , kRWI_W , 0 , 50 , 4000), // #711 - INST(Uhsub_v , ISimdVVV , (0b0010111000100000001001, kVO_V_BHS) , kRWI_W , 0 , 51 , 4006), // #712 - INST(Umax_v , ISimdVVV , (0b0010111000100000011001, kVO_V_BHS) , kRWI_W , 0 , 52 , 1936), // #713 - INST(Umaxp_v , ISimdVVV , (0b0010111000100000101001, kVO_V_BHS) , kRWI_W , 0 , 53 , 4019), // #714 - INST(Umaxv_v , ISimdSV , (0b0010111000110000101010, kVO_V_BH_4S) , kRWI_W , 0 , 5 , 4025), // #715 - INST(Umin_v , ISimdVVV , (0b0010111000100000011011, kVO_V_BHS) , kRWI_W , 0 , 54 , 2040), // #716 - INST(Uminp_v , ISimdVVV , (0b0010111000100000101011, kVO_V_BHS) , kRWI_W , 0 , 55 , 4031), // #717 - INST(Uminv_v , ISimdSV , (0b0010111000110001101010, kVO_V_BH_4S) , kRWI_W , 0 , 6 , 4037), // #718 - INST(Umlal_v , ISimdVVVe , (0b0010111000100000100000, kVO_V_B8H4S2, 0b0010111100000000001000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 19 , 4043), // #719 - INST(Umlal2_v , ISimdVVVe , (0b0110111000100000100000, kVO_V_B16H8S4, 0b0010111100000000001000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 20 , 4049), // #720 - INST(Umlsl_v , ISimdVVVe , (0b0010111000100000101000, kVO_V_B8H4S2, 0b0010111100000000011000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 21 , 4056), // #721 - INST(Umlsl2_v , ISimdVVVe , (0b0110111000100000101000, kVO_V_B16H8S4, 0b0110111100000000011000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 22 , 4062), // #722 - INST(Ummla_v , ISimdVVVx , (0b0110111010000000101001, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 15 , 4069), // #723 - INST(Umov_v , SimdSmovUmov , (0b0000111000000000001111, kVO_V_Any, 0) , kRWI_W , 0 , 1 , 4082), // #724 - INST(Umull_v , ISimdVVVe , (0b0010111000100000110000, kVO_V_B8H4S2, 0b0010111100000000101000, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 23 , 4100), // #725 - INST(Umull2_v , ISimdVVVe , (0b0110111000100000110000, kVO_V_B16H8S4, 0b0110111100000000101000, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 24 , 4106), // #726 - INST(Uqadd_v , ISimdVVV , (0b0010111000100000000011, kVO_SV_Any) , kRWI_W , 0 , 56 , 3746), // #727 - INST(Uqrshl_v , SimdShift , (0b0010111000100000010111, 0b0000000000000000000000, 0, kVO_SV_Any) , kRWI_W , 0 , 26 , 4113), // #728 - INST(Uqrshrn_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100111, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 27 , 4120), // #729 - INST(Uqrshrn2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100111, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 28 , 4128), // #730 - INST(Uqshl_v , SimdShift , (0b0010111000100000010011, 0b0010111100000000011101, 0, kVO_SV_Any) , kRWI_W , 0 , 29 , 4137), // #731 - INST(Uqshrn_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100101, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 30 , 4143), // #732 - INST(Uqshrn2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100101, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 31 , 4150), // #733 - INST(Uqsub_v , ISimdVVV , (0b0010111000100000001011, kVO_SV_Any) , kRWI_W , 0 , 57 , 4158), // #734 - INST(Uqxtn_v , ISimdVV , (0b0010111000100001010010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 22 , 4164), // #735 - INST(Uqxtn2_v , ISimdVV , (0b0110111000100001010010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 23 , 4170), // #736 - INST(Urecpe_v , ISimdVV , (0b0000111010100001110010, kVO_V_S) , kRWI_W , 0 , 24 , 4177), // #737 - INST(Urhadd_v , ISimdVVV , (0b0010111000100000000101, kVO_V_BHS) , kRWI_W , 0 , 58 , 4184), // #738 - INST(Urshl_v , SimdShift , (0b0010111000100000010101, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 32 , 4191), // #739 - INST(Urshr_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000001001, 1, kVO_V_Any) , kRWI_W , 0 , 33 , 4197), // #740 - INST(Ursqrte_v , ISimdVV , (0b0010111010100001110010, kVO_V_S) , kRWI_W , 0 , 25 , 4203), // #741 - INST(Ursra_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000001101, 1, kVO_V_Any) , kRWI_X , 0 , 34 , 4211), // #742 - INST(Usdot_v , SimdDot , (0b0000111010000000100111, 0b0000111110000000111100, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 4 , 4217), // #743 - INST(Ushl_v , SimdShift , (0b0010111000100000010001, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 35 , 4223), // #744 - INST(Ushll_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000101001, 0, kVO_V_B8H4S2) , kRWI_W , F(Long) , 36 , 4228), // #745 - INST(Ushll2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000101001, 0, kVO_V_B16H8S4) , kRWI_W , F(Long) , 37 , 4234), // #746 - INST(Ushr_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000000001, 1, kVO_V_Any) , kRWI_W , 0 , 38 , 4241), // #747 - INST(Usmmla_v , ISimdVVVx , (0b0100111010000000101011, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 16 , 4246), // #748 - INST(Usqadd_v , ISimdVV , (0b0010111000100000001110, kVO_SV_Any) , kRWI_X , 0 , 26 , 4253), // #749 - INST(Usra_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000000101, 1, kVO_V_Any) , kRWI_X , 0 , 39 , 4260), // #750 - INST(Usubl_v , ISimdVVV , (0b0010111000100000001000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 59 , 4265), // #751 - INST(Usubl2_v , ISimdVVV , (0b0110111000100000001000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 60 , 4271), // #752 - INST(Usubw_v , ISimdWWV , (0b0010111000100000001100, kVO_V_B8H4S2) , kRWI_W , 0 , 6 , 4278), // #753 - INST(Usubw2_v , ISimdWWV , (0b0010111000100000001100, kVO_V_B16H8S4) , kRWI_W , 0 , 7 , 4284), // #754 - INST(Uxtl_v , SimdSxtlUxtl , (0b0010111100000000101001, kVO_V_B8H4S2) , kRWI_W , F(Long) , 2 , 4301), // #755 - INST(Uxtl2_v , SimdSxtlUxtl , (0b0110111100000000101001, kVO_V_B16H8S4) , kRWI_W , F(Long) , 3 , 4306), // #756 - INST(Uzp1_v , ISimdVVV , (0b0000111000000000000110, kVO_V_BHS_D2) , kRWI_W , 0 , 61 , 4312), // #757 - INST(Uzp2_v , ISimdVVV , (0b0000111000000000010110, kVO_V_BHS_D2) , kRWI_W , 0 , 62 , 4317), // #758 - INST(Xar_v , ISimdVVVI , (0b1100111001100000100011, kVO_V_D2, 6, 10, 0) , kRWI_W , 0 , 1 , 4337), // #759 - INST(Xtn_v , ISimdVV , (0b0000111000100001001010, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 27 , 3047), // #760 - INST(Xtn2_v , ISimdVV , (0b0100111000100001001010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 28 , 3053), // #761 - INST(Zip1_v , ISimdVVV , (0b0000111000000000001110, kVO_V_BHS_D2) , kRWI_W , 0 , 63 , 4367), // #762 - INST(Zip2_v , ISimdVVV , (0b0000111000000000011110, kVO_V_BHS_D2) , kRWI_W , 0 , 64 , 4372) // #763 + INST(None , None , (_) , 0 , 0 , 0 ), // #0 + INST(Adc , BaseRRR , (0b0001101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 0 ), // #1 + INST(Adcs , BaseRRR , (0b0011101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 1 ), // #2 + INST(Add , BaseAddSub , (0b0001011000, 0b0001011001, 0b0010001) , kRWI_W , 0 , 0 ), // #3 + INST(Addg , BaseRRII , (0b1001000110000000000000, kX, kSP, kX, kSP, 6, 4, 16, 4, 0, 10) , kRWI_W , 0 , 0 ), // #4 + INST(Adds , BaseAddSub , (0b0101011000, 0b0101011001, 0b0110001) , kRWI_W , 0 , 1 ), // #5 + INST(Adr , BaseAdr , (0b0001000000000000000000, OffsetType::kAArch64_ADR) , kRWI_W , 0 , 0 ), // #6 + INST(Adrp , BaseAdr , (0b1001000000000000000000, OffsetType::kAArch64_ADRP) , kRWI_W , 0 , 1 ), // #7 + INST(And , BaseLogical , (0b0001010000, 0b00100100, 0) , kRWI_W , 0 , 0 ), // #8 + INST(Ands , BaseLogical , (0b1101010000, 0b11100100, 0) , kRWI_W , 0 , 1 ), // #9 + INST(Asr , BaseShift , (0b0001101011000000001010, 0b0001001100000000011111, 0) , kRWI_W , 0 , 0 ), // #10 + INST(Asrv , BaseShift , (0b0001101011000000001010, 0b0000000000000000000000, 0) , kRWI_W , 0 , 1 ), // #11 + INST(At , BaseAtDcIcTlbi , (0b00011111110000, 0b00001111000000, true) , kRWI_RX , 0 , 0 ), // #12 + INST(Autda , BaseRR , (0b11011010110000010001100000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 0 ), // #13 + INST(Autdza , BaseR , (0b11011010110000010011101111100000, kX, kZR, 0) , kRWI_X , 0 , 0 ), // #14 + INST(Autdb , BaseRR , (0b11011010110000010001110000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 1 ), // #15 + INST(Autdzb , BaseR , (0b11011010110000010011111111100000, kX, kZR, 0) , kRWI_X , 0 , 1 ), // #16 + INST(Autia , BaseRR , (0b11011010110000010001000000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 2 ), // #17 + INST(Autia1716 , BaseOp , (0b11010101000000110010000110011111) , 0 , 0 , 0 ), // #18 + INST(Autiasp , BaseOp , (0b11010101000000110010001110111111) , 0 , 0 , 1 ), // #19 + INST(Autiaz , BaseOp , (0b11010101000000110010001110011111) , 0 , 0 , 2 ), // #20 + INST(Autib , BaseRR , (0b11011010110000010001010000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 3 ), // #21 + INST(Autib1716 , BaseOp , (0b11010101000000110010000111011111) , 0 , 0 , 3 ), // #22 + INST(Autibsp , BaseOp , (0b11010101000000110010001111111111) , 0 , 0 , 4 ), // #23 + INST(Autibz , BaseOp , (0b11010101000000110010001111011111) , 0 , 0 , 5 ), // #24 + INST(Autiza , BaseR , (0b11011010110000010011001111100000, kX, kZR, 0) , kRWI_X , 0 , 2 ), // #25 + INST(Autizb , BaseR , (0b11011010110000010011011111100000, kX, kZR, 0) , kRWI_X , 0 , 3 ), // #26 + INST(Axflag , BaseOp , (0b11010101000000000100000001011111) , 0 , 0 , 6 ), // #27 + INST(B , BaseBranchRel , (0b00010100000000000000000000000000) , 0 , F(Cond) , 0 ), // #28 + INST(Bfc , BaseBfc , (0b00110011000000000000001111100000) , kRWI_X , 0 , 0 ), // #29 + INST(Bfi , BaseBfi , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 ), // #30 + INST(Bfm , BaseBfm , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 ), // #31 + INST(Bfxil , BaseBfx , (0b00110011000000000000000000000000) , kRWI_X , 0 , 0 ), // #32 + INST(Bic , BaseLogical , (0b0001010001, 0b00100100, 1) , kRWI_W , 0 , 2 ), // #33 + INST(Bics , BaseLogical , (0b1101010001, 0b11100100, 1) , kRWI_W , 0 , 3 ), // #34 + INST(Bl , BaseBranchRel , (0b10010100000000000000000000000000) , 0 , 0 , 1 ), // #35 + INST(Blr , BaseBranchReg , (0b11010110001111110000000000000000) , kRWI_R , 0 , 0 ), // #36 + INST(Br , BaseBranchReg , (0b11010110000111110000000000000000) , kRWI_R , 0 , 1 ), // #37 + INST(Brk , BaseOpImm , (0b11010100001000000000000000000000, 16, 5) , 0 , 0 , 0 ), // #38 + INST(Cas , BaseAtomicOp , (0b1000100010100000011111, kWX, 30, 0) , kRWI_XRX , 0 , 0 ), // #39 + INST(Casa , BaseAtomicOp , (0b1000100011100000011111, kWX, 30, 1) , kRWI_XRX , 0 , 1 ), // #40 + INST(Casab , BaseAtomicOp , (0b0000100011100000011111, kW , 0 , 1) , kRWI_XRX , 0 , 2 ), // #41 + INST(Casah , BaseAtomicOp , (0b0100100011100000011111, kW , 0 , 1) , kRWI_XRX , 0 , 3 ), // #42 + INST(Casal , BaseAtomicOp , (0b1000100011100000111111, kWX, 30, 1) , kRWI_XRX , 0 , 4 ), // #43 + INST(Casalb , BaseAtomicOp , (0b0000100011100000111111, kW , 0 , 1) , kRWI_XRX , 0 , 5 ), // #44 + INST(Casalh , BaseAtomicOp , (0b0100100011100000111111, kW , 0 , 1) , kRWI_XRX , 0 , 6 ), // #45 + INST(Casb , BaseAtomicOp , (0b0000100010100000011111, kW , 0 , 0) , kRWI_XRX , 0 , 7 ), // #46 + INST(Cash , BaseAtomicOp , (0b0100100010100000011111, kW , 0 , 0) , kRWI_XRX , 0 , 8 ), // #47 + INST(Casl , BaseAtomicOp , (0b1000100010100000111111, kWX, 30, 0) , kRWI_XRX , 0 , 9 ), // #48 + INST(Caslb , BaseAtomicOp , (0b0000100010100000111111, kW , 0 , 0) , kRWI_XRX , 0 , 10 ), // #49 + INST(Caslh , BaseAtomicOp , (0b0100100010100000111111, kW , 0 , 0) , kRWI_XRX , 0 , 11 ), // #50 + INST(Casp , BaseAtomicCasp , (0b0000100000100000011111, kWX, 30) , kRWI_XXRRX, 0 , 0 ), // #51 + INST(Caspa , BaseAtomicCasp , (0b0000100001100000011111, kWX, 30) , kRWI_XXRRX, 0 , 1 ), // #52 + INST(Caspal , BaseAtomicCasp , (0b0000100001100000111111, kWX, 30) , kRWI_XXRRX, 0 , 2 ), // #53 + INST(Caspl , BaseAtomicCasp , (0b0000100000100000111111, kWX, 30) , kRWI_XXRRX, 0 , 3 ), // #54 + INST(Cbnz , BaseBranchCmp , (0b00110101000000000000000000000000) , kRWI_R , 0 , 0 ), // #55 + INST(Cbz , BaseBranchCmp , (0b00110100000000000000000000000000) , kRWI_R , 0 , 1 ), // #56 + INST(Ccmn , BaseCCmp , (0b00111010010000000000000000000000) , kRWI_R , 0 , 0 ), // #57 + INST(Ccmp , BaseCCmp , (0b01111010010000000000000000000000) , kRWI_R , 0 , 1 ), // #58 + INST(Cfinv , BaseOp , (0b11010101000000000100000000011111) , 0 , 0 , 7 ), // #59 + INST(Cinc , BaseCInc , (0b00011010100000000000010000000000) , kRWI_W , 0 , 0 ), // #60 + INST(Cinv , BaseCInc , (0b01011010100000000000000000000000) , kRWI_W , 0 , 1 ), // #61 + INST(Clrex , BaseOpImm , (0b11010101000000110011000001011111, 4, 8) , 0 , 0 , 1 ), // #62 + INST(Cls , BaseRR , (0b01011010110000000001010000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 4 ), // #63 + INST(Clz , BaseRR , (0b01011010110000000001000000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 5 ), // #64 + INST(Cmn , BaseCmpCmn , (0b0101011000, 0b0101011001, 0b0110001) , kRWI_R , 0 , 0 ), // #65 + INST(Cmp , BaseCmpCmn , (0b1101011000, 0b1101011001, 0b1110001) , kRWI_R , 0 , 1 ), // #66 + INST(Cmpp , BaseRR , (0b10111010110000000000000000011111, kX, kSP, 5, kX, kSP, 16, true) , kRWI_R , 0 , 6 ), // #67 + INST(Cneg , BaseCInc , (0b01011010100000000000010000000000) , kRWI_W , 0 , 2 ), // #68 + INST(Crc32b , BaseRRR , (0b0001101011000000010000, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 2 ), // #69 + INST(Crc32cb , BaseRRR , (0b0001101011000000010100, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 3 ), // #70 + INST(Crc32ch , BaseRRR , (0b0001101011000000010101, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 4 ), // #71 + INST(Crc32cw , BaseRRR , (0b0001101011000000010110, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 5 ), // #72 + INST(Crc32cx , BaseRRR , (0b1001101011000000010111, kW, kZR, kW, kZR, kX, kZR, false) , kRWI_W , 0 , 6 ), // #73 + INST(Crc32h , BaseRRR , (0b0001101011000000010001, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 7 ), // #74 + INST(Crc32w , BaseRRR , (0b0001101011000000010010, kW, kZR, kW, kZR, kW, kZR, false) , kRWI_W , 0 , 8 ), // #75 + INST(Crc32x , BaseRRR , (0b1001101011000000010011, kW, kZR, kW, kZR, kX, kZR, false) , kRWI_W , 0 , 9 ), // #76 + INST(Csdb , BaseOp , (0b11010101000000110010001010011111) , 0 , 0 , 8 ), // #77 + INST(Csel , BaseCSel , (0b00011010100000000000000000000000) , kRWI_W , 0 , 0 ), // #78 + INST(Cset , BaseCSet , (0b00011010100111110000011111100000) , kRWI_W , 0 , 0 ), // #79 + INST(Csetm , BaseCSet , (0b01011010100111110000001111100000) , kRWI_W , 0 , 1 ), // #80 + INST(Csinc , BaseCSel , (0b00011010100000000000010000000000) , kRWI_W , 0 , 1 ), // #81 + INST(Csinv , BaseCSel , (0b01011010100000000000000000000000) , kRWI_W , 0 , 2 ), // #82 + INST(Csneg , BaseCSel , (0b01011010100000000000010000000000) , kRWI_W , 0 , 3 ), // #83 + INST(Dc , BaseAtDcIcTlbi , (0b00011110000000, 0b00001110000000, true) , kRWI_RX , 0 , 1 ), // #84 + INST(Dcps1 , BaseOpImm , (0b11010100101000000000000000000001, 16, 5) , 0 , 0 , 2 ), // #85 + INST(Dcps2 , BaseOpImm , (0b11010100101000000000000000000010, 16, 5) , 0 , 0 , 3 ), // #86 + INST(Dcps3 , BaseOpImm , (0b11010100101000000000000000000011, 16, 5) , 0 , 0 , 4 ), // #87 + INST(Dgh , BaseOp , (0b11010101000000110010000011011111) , 0 , 0 , 9 ), // #88 + INST(Dmb , BaseOpImm , (0b11010101000000110011000010111111, 4, 8) , 0 , 0 , 5 ), // #89 + INST(Drps , BaseOp , (0b11010110101111110000001111100000) , 0 , 0 , 10 ), // #90 + INST(Dsb , BaseOpImm , (0b11010101000000110011000010011111, 4, 8) , 0 , 0 , 6 ), // #91 + INST(Eon , BaseLogical , (0b1001010001, 0b10100100, 1) , kRWI_W , 0 , 4 ), // #92 + INST(Eor , BaseLogical , (0b1001010000, 0b10100100, 0) , kRWI_W , 0 , 5 ), // #93 + INST(Esb , BaseOp , (0b11010101000000110010001000011111) , 0 , 0 , 11 ), // #94 + INST(Extr , BaseExtract , (0b00010011100000000000000000000000) , kRWI_W , 0 , 0 ), // #95 + INST(Eret , BaseOp , (0b11010110100111110000001111100000) , 0 , 0 , 12 ), // #96 + INST(Gmi , BaseRRR , (0b1001101011000000000101, kX , kZR, kX , kSP, kX , kZR, true) , kRWI_W , 0 , 10 ), // #97 + INST(Hint , BaseOpImm , (0b11010101000000110010000000011111, 7, 5) , 0 , 0 , 7 ), // #98 + INST(Hlt , BaseOpImm , (0b11010100010000000000000000000000, 16, 5) , 0 , 0 , 8 ), // #99 + INST(Hvc , BaseOpImm , (0b11010100000000000000000000000010, 16, 5) , 0 , 0 , 9 ), // #100 + INST(Ic , BaseAtDcIcTlbi , (0b00011110000000, 0b00001110000000, false) , kRWI_RX , 0 , 2 ), // #101 + INST(Isb , BaseOpImm , (0b11010101000000110011000011011111, 4, 8) , 0 , 0 , 10 ), // #102 + INST(Ldadd , BaseAtomicOp , (0b1011100000100000000000, kWX, 30, 0) , kRWI_WRX , 0 , 12 ), // #103 + INST(Ldadda , BaseAtomicOp , (0b1011100010100000000000, kWX, 30, 1) , kRWI_WRX , 0 , 13 ), // #104 + INST(Ldaddab , BaseAtomicOp , (0b0011100010100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 14 ), // #105 + INST(Ldaddah , BaseAtomicOp , (0b0111100010100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 15 ), // #106 + INST(Ldaddal , BaseAtomicOp , (0b1011100011100000000000, kWX, 30, 1) , kRWI_WRX , 0 , 16 ), // #107 + INST(Ldaddalb , BaseAtomicOp , (0b0011100011100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 17 ), // #108 + INST(Ldaddalh , BaseAtomicOp , (0b0111100011100000000000, kW , 0 , 1) , kRWI_WRX , 0 , 18 ), // #109 + INST(Ldaddb , BaseAtomicOp , (0b0011100000100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 19 ), // #110 + INST(Ldaddh , BaseAtomicOp , (0b0111100000100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 20 ), // #111 + INST(Ldaddl , BaseAtomicOp , (0b1011100001100000000000, kWX, 30, 0) , kRWI_WRX , 0 , 21 ), // #112 + INST(Ldaddlb , BaseAtomicOp , (0b0011100001100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 22 ), // #113 + INST(Ldaddlh , BaseAtomicOp , (0b0111100001100000000000, kW , 0 , 0) , kRWI_WRX , 0 , 23 ), // #114 + INST(Ldar , BaseRM_NoImm , (0b1000100011011111111111, kWX, kZR, 30) , kRWI_W , 0 , 0 ), // #115 + INST(Ldarb , BaseRM_NoImm , (0b0000100011011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 1 ), // #116 + INST(Ldarh , BaseRM_NoImm , (0b0100100011011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 2 ), // #117 + INST(Ldaxp , BaseLdxp , (0b1000100001111111100000, kWX, 30) , kRWI_WW , 0 , 0 ), // #118 + INST(Ldaxr , BaseRM_NoImm , (0b1000100001011111111111, kWX, kZR, 30) , kRWI_W , 0 , 3 ), // #119 + INST(Ldaxrb , BaseRM_NoImm , (0b0000100001011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 4 ), // #120 + INST(Ldaxrh , BaseRM_NoImm , (0b0100100001011111111111, kW , kZR, 0 ) , kRWI_W , 0 , 5 ), // #121 + INST(Ldclr , BaseAtomicOp , (0b1011100000100000000100, kWX, 30, 0) , kRWI_WRX , 0 , 24 ), // #122 + INST(Ldclra , BaseAtomicOp , (0b1011100010100000000100, kWX, 30, 1) , kRWI_WRX , 0 , 25 ), // #123 + INST(Ldclrab , BaseAtomicOp , (0b0011100010100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 26 ), // #124 + INST(Ldclrah , BaseAtomicOp , (0b0111100010100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 27 ), // #125 + INST(Ldclral , BaseAtomicOp , (0b1011100011100000000100, kWX, 30, 1) , kRWI_WRX , 0 , 28 ), // #126 + INST(Ldclralb , BaseAtomicOp , (0b0011100011100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 29 ), // #127 + INST(Ldclralh , BaseAtomicOp , (0b0111100011100000000100, kW , 0 , 1) , kRWI_WRX , 0 , 30 ), // #128 + INST(Ldclrb , BaseAtomicOp , (0b0011100000100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 31 ), // #129 + INST(Ldclrh , BaseAtomicOp , (0b0111100000100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 32 ), // #130 + INST(Ldclrl , BaseAtomicOp , (0b1011100001100000000100, kWX, 30, 0) , kRWI_WRX , 0 , 33 ), // #131 + INST(Ldclrlb , BaseAtomicOp , (0b0011100001100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 34 ), // #132 + INST(Ldclrlh , BaseAtomicOp , (0b0111100001100000000100, kW , 0 , 0) , kRWI_WRX , 0 , 35 ), // #133 + INST(Ldeor , BaseAtomicOp , (0b1011100000100000001000, kWX, 30, 0) , kRWI_WRX , 0 , 36 ), // #134 + INST(Ldeora , BaseAtomicOp , (0b1011100010100000001000, kWX, 30, 1) , kRWI_WRX , 0 , 37 ), // #135 + INST(Ldeorab , BaseAtomicOp , (0b0011100010100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 38 ), // #136 + INST(Ldeorah , BaseAtomicOp , (0b0111100010100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 39 ), // #137 + INST(Ldeoral , BaseAtomicOp , (0b1011100011100000001000, kWX, 30, 1) , kRWI_WRX , 0 , 40 ), // #138 + INST(Ldeoralb , BaseAtomicOp , (0b0011100011100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 41 ), // #139 + INST(Ldeoralh , BaseAtomicOp , (0b0111100011100000001000, kW , 0 , 1) , kRWI_WRX , 0 , 42 ), // #140 + INST(Ldeorb , BaseAtomicOp , (0b0011100000100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 43 ), // #141 + INST(Ldeorh , BaseAtomicOp , (0b0111100000100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 44 ), // #142 + INST(Ldeorl , BaseAtomicOp , (0b1011100001100000001000, kWX, 30, 0) , kRWI_WRX , 0 , 45 ), // #143 + INST(Ldeorlb , BaseAtomicOp , (0b0011100001100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 46 ), // #144 + INST(Ldeorlh , BaseAtomicOp , (0b0111100001100000001000, kW , 0 , 0) , kRWI_WRX , 0 , 47 ), // #145 + INST(Ldg , BaseRM_SImm9 , (0b1101100101100000000000, 0b0000000000000000000000, kX , kZR, 0, 4) , kRWI_W , 0 , 0 ), // #146 + INST(Ldgm , BaseRM_NoImm , (0b1101100111100000000000, kX , kZR, 0 ) , kRWI_W , 0 , 6 ), // #147 + INST(Ldlar , BaseRM_NoImm , (0b1000100011011111011111, kWX, kZR, 30) , kRWI_W , 0 , 7 ), // #148 + INST(Ldlarb , BaseRM_NoImm , (0b0000100011011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 8 ), // #149 + INST(Ldlarh , BaseRM_NoImm , (0b0100100011011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 9 ), // #150 + INST(Ldnp , BaseLdpStp , (0b0010100001, 0 , kWX, 31, 2) , kRWI_WW , 0 , 0 ), // #151 + INST(Ldp , BaseLdpStp , (0b0010100101, 0b0010100011, kWX, 31, 2) , kRWI_W , 0 , 1 ), // #152 + INST(Ldpsw , BaseLdpStp , (0b0110100101, 0b0110100011, kX , 0 , 2) , kRWI_WW , 0 , 2 ), // #153 + INST(Ldr , BaseLdSt , (0b1011100101, 0b10111000010, 0b10111000011, 0b00011000, kWX, 30, 2, Inst::kIdLdur) , kRWI_W , 0 , 0 ), // #154 + INST(Ldraa , BaseRM_SImm10 , (0b1111100000100000000001, kX , kZR, 0, 3) , kRWI_W , 0 , 0 ), // #155 + INST(Ldrab , BaseRM_SImm10 , (0b1111100010100000000001, kX , kZR, 0, 3) , kRWI_W , 0 , 1 ), // #156 + INST(Ldrb , BaseLdSt , (0b0011100101, 0b00111000010, 0b00111000011, 0 , kW , 0 , 0, Inst::kIdLdurb) , kRWI_W , 0 , 1 ), // #157 + INST(Ldrh , BaseLdSt , (0b0111100101, 0b01111000010, 0b01111000011, 0 , kW , 0 , 1, Inst::kIdLdurh) , kRWI_W , 0 , 2 ), // #158 + INST(Ldrsb , BaseLdSt , (0b0011100111, 0b00111000100, 0b00111000111, 0 , kWX, 22, 0, Inst::kIdLdursb) , kRWI_W , 0 , 3 ), // #159 + INST(Ldrsh , BaseLdSt , (0b0111100111, 0b01111000100, 0b01111000111, 0 , kWX, 22, 1, Inst::kIdLdursh) , kRWI_W , 0 , 4 ), // #160 + INST(Ldrsw , BaseLdSt , (0b1011100110, 0b10111000100, 0b10111000101, 0b10011000, kX , 0 , 2, Inst::kIdLdursw) , kRWI_W , 0 , 5 ), // #161 + INST(Ldset , BaseAtomicOp , (0b1011100000100000001100, kWX, 30, 0) , kRWI_WRX , 0 , 48 ), // #162 + INST(Ldseta , BaseAtomicOp , (0b1011100010100000001100, kWX, 30, 1) , kRWI_WRX , 0 , 49 ), // #163 + INST(Ldsetab , BaseAtomicOp , (0b0011100010100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 50 ), // #164 + INST(Ldsetah , BaseAtomicOp , (0b0111100010100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 51 ), // #165 + INST(Ldsetal , BaseAtomicOp , (0b1011100011100000001100, kWX, 30, 1) , kRWI_WRX , 0 , 52 ), // #166 + INST(Ldsetalb , BaseAtomicOp , (0b0011100011100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 53 ), // #167 + INST(Ldsetalh , BaseAtomicOp , (0b0111100011100000001100, kW , 0 , 1) , kRWI_WRX , 0 , 54 ), // #168 + INST(Ldsetb , BaseAtomicOp , (0b0011100000100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 55 ), // #169 + INST(Ldseth , BaseAtomicOp , (0b0111100000100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 56 ), // #170 + INST(Ldsetl , BaseAtomicOp , (0b1011100001100000001100, kWX, 30, 0) , kRWI_WRX , 0 , 57 ), // #171 + INST(Ldsetlb , BaseAtomicOp , (0b0011100001100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 58 ), // #172 + INST(Ldsetlh , BaseAtomicOp , (0b0111100001100000001100, kW , 0 , 0) , kRWI_WRX , 0 , 59 ), // #173 + INST(Ldsmax , BaseAtomicOp , (0b1011100000100000010000, kWX, 30, 0) , kRWI_WRX , 0 , 60 ), // #174 + INST(Ldsmaxa , BaseAtomicOp , (0b1011100010100000010000, kWX, 30, 1) , kRWI_WRX , 0 , 61 ), // #175 + INST(Ldsmaxab , BaseAtomicOp , (0b0011100010100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 62 ), // #176 + INST(Ldsmaxah , BaseAtomicOp , (0b0111100010100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 63 ), // #177 + INST(Ldsmaxal , BaseAtomicOp , (0b1011100011100000010000, kWX, 30, 1) , kRWI_WRX , 0 , 64 ), // #178 + INST(Ldsmaxalb , BaseAtomicOp , (0b0011100011100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 65 ), // #179 + INST(Ldsmaxalh , BaseAtomicOp , (0b0111100011100000010000, kW , 0 , 1) , kRWI_WRX , 0 , 66 ), // #180 + INST(Ldsmaxb , BaseAtomicOp , (0b0011100000100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 67 ), // #181 + INST(Ldsmaxh , BaseAtomicOp , (0b0111100000100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 68 ), // #182 + INST(Ldsmaxl , BaseAtomicOp , (0b1011100001100000010000, kWX, 30, 0) , kRWI_WRX , 0 , 69 ), // #183 + INST(Ldsmaxlb , BaseAtomicOp , (0b0011100001100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 70 ), // #184 + INST(Ldsmaxlh , BaseAtomicOp , (0b0111100001100000010000, kW , 0 , 0) , kRWI_WRX , 0 , 71 ), // #185 + INST(Ldsmin , BaseAtomicOp , (0b1011100000100000010100, kWX, 30, 0) , kRWI_WRX , 0 , 72 ), // #186 + INST(Ldsmina , BaseAtomicOp , (0b1011100010100000010100, kWX, 30, 1) , kRWI_WRX , 0 , 73 ), // #187 + INST(Ldsminab , BaseAtomicOp , (0b0011100010100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 74 ), // #188 + INST(Ldsminah , BaseAtomicOp , (0b0111100010100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 75 ), // #189 + INST(Ldsminal , BaseAtomicOp , (0b1011100011100000010100, kWX, 30, 1) , kRWI_WRX , 0 , 76 ), // #190 + INST(Ldsminalb , BaseAtomicOp , (0b0011100011100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 77 ), // #191 + INST(Ldsminalh , BaseAtomicOp , (0b0111100011100000010100, kW , 0 , 1) , kRWI_WRX , 0 , 78 ), // #192 + INST(Ldsminb , BaseAtomicOp , (0b0011100000100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 79 ), // #193 + INST(Ldsminh , BaseAtomicOp , (0b0111100000100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 80 ), // #194 + INST(Ldsminl , BaseAtomicOp , (0b1011100001100000010100, kWX, 30, 0) , kRWI_WRX , 0 , 81 ), // #195 + INST(Ldsminlb , BaseAtomicOp , (0b0011100001100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 82 ), // #196 + INST(Ldsminlh , BaseAtomicOp , (0b0111100001100000010100, kW , 0 , 0) , kRWI_WRX , 0 , 83 ), // #197 + INST(Ldtr , BaseRM_SImm9 , (0b1011100001000000000010, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_W , 0 , 1 ), // #198 + INST(Ldtrb , BaseRM_SImm9 , (0b0011100001000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 2 ), // #199 + INST(Ldtrh , BaseRM_SImm9 , (0b0111100001000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 3 ), // #200 + INST(Ldtrsb , BaseRM_SImm9 , (0b0011100011000000000010, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 4 ), // #201 + INST(Ldtrsh , BaseRM_SImm9 , (0b0111100011000000000010, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 5 ), // #202 + INST(Ldtrsw , BaseRM_SImm9 , (0b1011100010000000000010, 0b0000000000000000000000, kX , kZR, 0 , 0) , kRWI_W , 0 , 6 ), // #203 + INST(Ldumax , BaseAtomicOp , (0b1011100000100000011000, kWX, 30, 0) , kRWI_WRX , 0 , 84 ), // #204 + INST(Ldumaxa , BaseAtomicOp , (0b1011100010100000011000, kWX, 30, 1) , kRWI_WRX , 0 , 85 ), // #205 + INST(Ldumaxab , BaseAtomicOp , (0b0011100010100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 86 ), // #206 + INST(Ldumaxah , BaseAtomicOp , (0b0111100010100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 87 ), // #207 + INST(Ldumaxal , BaseAtomicOp , (0b1011100011100000011000, kWX, 30, 1) , kRWI_WRX , 0 , 88 ), // #208 + INST(Ldumaxalb , BaseAtomicOp , (0b0011100011100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 89 ), // #209 + INST(Ldumaxalh , BaseAtomicOp , (0b0111100011100000011000, kW , 0 , 1) , kRWI_WRX , 0 , 90 ), // #210 + INST(Ldumaxb , BaseAtomicOp , (0b0011100000100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 91 ), // #211 + INST(Ldumaxh , BaseAtomicOp , (0b0111100000100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 92 ), // #212 + INST(Ldumaxl , BaseAtomicOp , (0b1011100001100000011000, kWX, 30, 0) , kRWI_WRX , 0 , 93 ), // #213 + INST(Ldumaxlb , BaseAtomicOp , (0b0011100001100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 94 ), // #214 + INST(Ldumaxlh , BaseAtomicOp , (0b0111100001100000011000, kW , 0 , 0) , kRWI_WRX , 0 , 95 ), // #215 + INST(Ldumin , BaseAtomicOp , (0b1011100000100000011100, kWX, 30, 0) , kRWI_WRX , 0 , 96 ), // #216 + INST(Ldumina , BaseAtomicOp , (0b1011100010100000011100, kWX, 30, 1) , kRWI_WRX , 0 , 97 ), // #217 + INST(Lduminab , BaseAtomicOp , (0b0011100010100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 98 ), // #218 + INST(Lduminah , BaseAtomicOp , (0b0111100010100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 99 ), // #219 + INST(Lduminal , BaseAtomicOp , (0b1011100011100000011100, kWX, 30, 1) , kRWI_WRX , 0 , 100), // #220 + INST(Lduminalb , BaseAtomicOp , (0b0011100011100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 101), // #221 + INST(Lduminalh , BaseAtomicOp , (0b0111100011100000011100, kW , 0 , 1) , kRWI_WRX , 0 , 102), // #222 + INST(Lduminb , BaseAtomicOp , (0b0011100000100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 103), // #223 + INST(Lduminh , BaseAtomicOp , (0b0111100000100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 104), // #224 + INST(Lduminl , BaseAtomicOp , (0b1011100001100000011100, kWX, 30, 0) , kRWI_WRX , 0 , 105), // #225 + INST(Lduminlb , BaseAtomicOp , (0b0011100001100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 106), // #226 + INST(Lduminlh , BaseAtomicOp , (0b0111100001100000011100, kW , 0 , 0) , kRWI_WRX , 0 , 107), // #227 + INST(Ldur , BaseRM_SImm9 , (0b1011100001000000000000, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_W , 0 , 7 ), // #228 + INST(Ldurb , BaseRM_SImm9 , (0b0011100001000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 8 ), // #229 + INST(Ldurh , BaseRM_SImm9 , (0b0111100001000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_W , 0 , 9 ), // #230 + INST(Ldursb , BaseRM_SImm9 , (0b0011100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 10 ), // #231 + INST(Ldursh , BaseRM_SImm9 , (0b0111100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0) , kRWI_W , 0 , 11 ), // #232 + INST(Ldursw , BaseRM_SImm9 , (0b1011100010000000000000, 0b0000000000000000000000, kX , kZR, 0 , 0) , kRWI_W , 0 , 12 ), // #233 + INST(Ldxp , BaseLdxp , (0b1000100001111111000000, kWX, 30) , kRWI_WW , 0 , 1 ), // #234 + INST(Ldxr , BaseRM_NoImm , (0b1000100001011111011111, kWX, kZR, 30) , kRWI_W , 0 , 10 ), // #235 + INST(Ldxrb , BaseRM_NoImm , (0b0000100001011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 11 ), // #236 + INST(Ldxrh , BaseRM_NoImm , (0b0100100001011111011111, kW , kZR, 0 ) , kRWI_W , 0 , 12 ), // #237 + INST(Lsl , BaseShift , (0b0001101011000000001000, 0b0101001100000000000000, 0) , kRWI_W , 0 , 2 ), // #238 + INST(Lslv , BaseShift , (0b0001101011000000001000, 0b0000000000000000000000, 0) , kRWI_W , 0 , 3 ), // #239 + INST(Lsr , BaseShift , (0b0001101011000000001001, 0b0101001100000000011111, 0) , kRWI_W , 0 , 4 ), // #240 + INST(Lsrv , BaseShift , (0b0001101011000000001001, 0b0000000000000000000000, 0) , kRWI_W , 0 , 5 ), // #241 + INST(Madd , BaseRRRR , (0b0001101100000000000000, kWX, kZR, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 0 ), // #242 + INST(Mneg , BaseRRR , (0b0001101100000000111111, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 11 ), // #243 + INST(Mov , BaseMov , (_) , kRWI_W , 0 , 0 ), // #244 + INST(Movk , BaseMovKNZ , (0b01110010100000000000000000000000) , kRWI_X , 0 , 0 ), // #245 + INST(Movn , BaseMovKNZ , (0b00010010100000000000000000000000) , kRWI_W , 0 , 1 ), // #246 + INST(Movz , BaseMovKNZ , (0b01010010100000000000000000000000) , kRWI_W , 0 , 2 ), // #247 + INST(Mrs , BaseMrs , (_) , kRWI_W , 0 , 0 ), // #248 + INST(Msr , BaseMsr , (_) , kRWI_W , 0 , 0 ), // #249 + INST(Msub , BaseRRRR , (0b0001101100000000100000, kWX, kZR, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 1 ), // #250 + INST(Mul , BaseRRR , (0b0001101100000000011111, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 12 ), // #251 + INST(Mvn , BaseMvnNeg , (0b00101010001000000000001111100000) , kRWI_W , 0 , 0 ), // #252 + INST(Neg , BaseMvnNeg , (0b01001011000000000000001111100000) , kRWI_W , 0 , 1 ), // #253 + INST(Negs , BaseMvnNeg , (0b01101011000000000000001111100000) , kRWI_W , 0 , 2 ), // #254 + INST(Ngc , BaseRR , (0b01011010000000000000001111100000, kWX, kZR, 0, kWX, kZR, 16, true) , kRWI_W , 0 , 7 ), // #255 + INST(Ngcs , BaseRR , (0b01111010000000000000001111100000, kWX, kZR, 0, kWX, kZR, 16, true) , kRWI_W , 0 , 8 ), // #256 + INST(Nop , BaseOp , (0b11010101000000110010000000011111) , 0 , 0 , 13 ), // #257 + INST(Orn , BaseLogical , (0b0101010001, 0b01100100, 1) , kRWI_W , 0 , 6 ), // #258 + INST(Orr , BaseLogical , (0b0101010000, 0b01100100, 0) , kRWI_W , 0 , 7 ), // #259 + INST(Pacda , BaseRR , (0b11011010110000010000100000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 9 ), // #260 + INST(Pacdb , BaseRR , (0b11011010110000010000110000000000, kX, kZR, 0, kX, kSP, 5, true) , kRWI_X , 0 , 10 ), // #261 + INST(Pacdza , BaseR , (0b11011010110000010010101111100000, kX, kZR, 0) , kRWI_X , 0 , 4 ), // #262 + INST(Pacdzb , BaseR , (0b11011010110000010010111111100000, kX, kZR, 0) , kRWI_X , 0 , 5 ), // #263 + INST(Pacga , BaseRRR , (0b1001101011000000001100, kX, kZR, kX, kZR, kX, kSP, false) , kRWI_W , 0 , 13 ), // #264 + INST(Pssbb , BaseOp , (0b11010101000000110011010010011111) , 0 , 0 , 14 ), // #265 + INST(Rbit , BaseRR , (0b01011010110000000000000000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 11 ), // #266 + INST(Ret , BaseBranchReg , (0b11010110010111110000000000000000) , kRWI_R , 0 , 2 ), // #267 + INST(Rev , BaseRev , (_) , kRWI_W , 0 , 0 ), // #268 + INST(Rev16 , BaseRR , (0b01011010110000000000010000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 12 ), // #269 + INST(Rev32 , BaseRR , (0b11011010110000000000100000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 13 ), // #270 + INST(Rev64 , BaseRR , (0b11011010110000000000110000000000, kWX, kZR, 0, kWX, kZR, 5, true) , kRWI_W , 0 , 14 ), // #271 + INST(Ror , BaseShift , (0b0001101011000000001011, 0b0001001110000000000000, 1) , kRWI_W , 0 , 6 ), // #272 + INST(Rorv , BaseShift , (0b0001101011000000001011, 0b0000000000000000000000, 1) , kRWI_W , 0 , 7 ), // #273 + INST(Sbc , BaseRRR , (0b0101101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 14 ), // #274 + INST(Sbcs , BaseRRR , (0b0111101000000000000000, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 15 ), // #275 + INST(Sbfiz , BaseBfi , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 ), // #276 + INST(Sbfm , BaseBfm , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 ), // #277 + INST(Sbfx , BaseBfx , (0b00010011000000000000000000000000) , kRWI_W , 0 , 1 ), // #278 + INST(Sdiv , BaseRRR , (0b0001101011000000000011, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 16 ), // #279 + INST(Setf8 , BaseR , (0b00111010000000000000100000001101, kW, kZR, 5) , 0 , 0 , 6 ), // #280 + INST(Setf16 , BaseR , (0b00111010000000000100100000001101, kW, kZR, 5) , 0 , 0 , 7 ), // #281 + INST(Sev , BaseOp , (0b11010101000000110010000010011111) , 0 , 0 , 15 ), // #282 + INST(Sevl , BaseOp , (0b11010101000000110010000010111111) , 0 , 0 , 16 ), // #283 + INST(Smaddl , BaseRRRR , (0b1001101100100000000000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 2 ), // #284 + INST(Smc , BaseOpImm , (0b11010100000000000000000000000011, 16, 5) , 0 , 0 , 11 ), // #285 + INST(Smnegl , BaseRRR , (0b1001101100100000111111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 17 ), // #286 + INST(Smsubl , BaseRRRR , (0b1001101100100000100000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 3 ), // #287 + INST(Smulh , BaseRRR , (0b1001101101000000011111, kX , kZR, kX , kZR, kX , kZR, true) , kRWI_W , 0 , 18 ), // #288 + INST(Smull , BaseRRR , (0b1001101100100000011111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 19 ), // #289 + INST(Ssbb , BaseOp , (0b11010101000000110011000010011111) , 0 , 0 , 17 ), // #290 + INST(St2g , BaseRM_SImm9 , (0b1101100110100000000010, 0b1101100110100000000001, kX, kSP, 0, 4) , kRWI_RW , 0 , 13 ), // #291 + INST(Stadd , BaseAtomicSt , (0b1011100000100000000000, kWX, 30) , kRWI_RX , 0 , 0 ), // #292 + INST(Staddl , BaseAtomicSt , (0b1011100001100000000000, kWX, 30) , kRWI_RX , 0 , 1 ), // #293 + INST(Staddb , BaseAtomicSt , (0b0011100000100000000000, kW , 0 ) , kRWI_RX , 0 , 2 ), // #294 + INST(Staddlb , BaseAtomicSt , (0b0011100001100000000000, kW , 0 ) , kRWI_RX , 0 , 3 ), // #295 + INST(Staddh , BaseAtomicSt , (0b0111100000100000000000, kW , 0 ) , kRWI_RX , 0 , 4 ), // #296 + INST(Staddlh , BaseAtomicSt , (0b0111100001100000000000, kW , 0 ) , kRWI_RX , 0 , 5 ), // #297 + INST(Stclr , BaseAtomicSt , (0b1011100000100000000100, kWX, 30) , kRWI_RX , 0 , 6 ), // #298 + INST(Stclrl , BaseAtomicSt , (0b1011100001100000000100, kWX, 30) , kRWI_RX , 0 , 7 ), // #299 + INST(Stclrb , BaseAtomicSt , (0b0011100000100000000100, kW , 0 ) , kRWI_RX , 0 , 8 ), // #300 + INST(Stclrlb , BaseAtomicSt , (0b0011100001100000000100, kW , 0 ) , kRWI_RX , 0 , 9 ), // #301 + INST(Stclrh , BaseAtomicSt , (0b0111100000100000000100, kW , 0 ) , kRWI_RX , 0 , 10 ), // #302 + INST(Stclrlh , BaseAtomicSt , (0b0111100001100000000100, kW , 0 ) , kRWI_RX , 0 , 11 ), // #303 + INST(Steor , BaseAtomicSt , (0b1011100000100000001000, kWX, 30) , kRWI_RX , 0 , 12 ), // #304 + INST(Steorl , BaseAtomicSt , (0b1011100001100000001000, kWX, 30) , kRWI_RX , 0 , 13 ), // #305 + INST(Steorb , BaseAtomicSt , (0b0011100000100000001000, kW , 0 ) , kRWI_RX , 0 , 14 ), // #306 + INST(Steorlb , BaseAtomicSt , (0b0011100001100000001000, kW , 0 ) , kRWI_RX , 0 , 15 ), // #307 + INST(Steorh , BaseAtomicSt , (0b0111100000100000001000, kW , 0 ) , kRWI_RX , 0 , 16 ), // #308 + INST(Steorlh , BaseAtomicSt , (0b0111100001100000001000, kW , 0 ) , kRWI_RX , 0 , 17 ), // #309 + INST(Stg , BaseRM_SImm9 , (0b1101100100100000000010, 0b1101100100100000000001, kX, kSP, 0, 4) , kRWI_RW , 0 , 14 ), // #310 + INST(Stgm , BaseRM_NoImm , (0b1101100110100000000000, kX , kZR, 0 ) , kRWI_RW , 0 , 13 ), // #311 + INST(Stgp , BaseLdpStp , (0b0110100100, 0b0110100010, kX, 0, 4) , kRWI_RRW , 0 , 3 ), // #312 + INST(Stllr , BaseRM_NoImm , (0b1000100010011111011111, kWX, kZR, 30) , kRWI_RW , 0 , 14 ), // #313 + INST(Stllrb , BaseRM_NoImm , (0b0000100010011111011111, kW , kZR, 0 ) , kRWI_RW , 0 , 15 ), // #314 + INST(Stllrh , BaseRM_NoImm , (0b0100100010011111011111, kW , kZR, 0 ) , kRWI_RW , 0 , 16 ), // #315 + INST(Stlr , BaseRM_NoImm , (0b1000100010011111111111, kWX, kZR, 30) , kRWI_RW , 0 , 17 ), // #316 + INST(Stlrb , BaseRM_NoImm , (0b0000100010011111111111, kW , kZR, 0 ) , kRWI_RW , 0 , 18 ), // #317 + INST(Stlrh , BaseRM_NoImm , (0b0100100010011111111111, kW , kZR, 0 ) , kRWI_RW , 0 , 19 ), // #318 + INST(Stlxp , BaseStxp , (0b1000100000100000100000, kWX, 30) , kRWI_WRRX , 0 , 0 ), // #319 + INST(Stlxr , BaseAtomicOp , (0b1000100000000000111111, kWX, 30, 1) , kRWI_WRX , 0 , 108), // #320 + INST(Stlxrb , BaseAtomicOp , (0b0000100000000000111111, kW , 0 , 1) , kRWI_WRX , 0 , 109), // #321 + INST(Stlxrh , BaseAtomicOp , (0b0100100000000000111111, kW , 0 , 1) , kRWI_WRX , 0 , 110), // #322 + INST(Stnp , BaseLdpStp , (0b0010100000, 0 , kWX, 31, 2) , kRWI_RRW , 0 , 4 ), // #323 + INST(Stp , BaseLdpStp , (0b0010100100, 0b0010100010, kWX, 31, 2) , kRWI_RRW , 0 , 5 ), // #324 + INST(Str , BaseLdSt , (0b1011100100, 0b10111000000, 0b10111000001, 0 , kWX, 30, 2, Inst::kIdStur) , kRWI_RW , 0 , 6 ), // #325 + INST(Strb , BaseLdSt , (0b0011100100, 0b00111000000, 0b00111000001, 0 , kW , 30, 0, Inst::kIdSturb) , kRWI_RW , 0 , 7 ), // #326 + INST(Strh , BaseLdSt , (0b0111100100, 0b01111000000, 0b01111000001, 0 , kWX, 30, 1, Inst::kIdSturh) , kRWI_RW , 0 , 8 ), // #327 + INST(Stset , BaseAtomicSt , (0b1011100000100000001100, kWX, 30) , kRWI_RX , 0 , 18 ), // #328 + INST(Stsetl , BaseAtomicSt , (0b1011100001100000001100, kWX, 30) , kRWI_RX , 0 , 19 ), // #329 + INST(Stsetb , BaseAtomicSt , (0b0011100000100000001100, kW , 0 ) , kRWI_RX , 0 , 20 ), // #330 + INST(Stsetlb , BaseAtomicSt , (0b0011100001100000001100, kW , 0 ) , kRWI_RX , 0 , 21 ), // #331 + INST(Stseth , BaseAtomicSt , (0b0111100000100000001100, kW , 0 ) , kRWI_RX , 0 , 22 ), // #332 + INST(Stsetlh , BaseAtomicSt , (0b0111100001100000001100, kW , 0 ) , kRWI_RX , 0 , 23 ), // #333 + INST(Stsmax , BaseAtomicSt , (0b1011100000100000010000, kWX, 30) , kRWI_RX , 0 , 24 ), // #334 + INST(Stsmaxl , BaseAtomicSt , (0b1011100001100000010000, kWX, 30) , kRWI_RX , 0 , 25 ), // #335 + INST(Stsmaxb , BaseAtomicSt , (0b0011100000100000010000, kW , 0 ) , kRWI_RX , 0 , 26 ), // #336 + INST(Stsmaxlb , BaseAtomicSt , (0b0011100001100000010000, kW , 0 ) , kRWI_RX , 0 , 27 ), // #337 + INST(Stsmaxh , BaseAtomicSt , (0b0111100000100000010000, kW , 0 ) , kRWI_RX , 0 , 28 ), // #338 + INST(Stsmaxlh , BaseAtomicSt , (0b0111100001100000010000, kW , 0 ) , kRWI_RX , 0 , 29 ), // #339 + INST(Stsmin , BaseAtomicSt , (0b1011100000100000010100, kWX, 30) , kRWI_RX , 0 , 30 ), // #340 + INST(Stsminl , BaseAtomicSt , (0b1011100001100000010100, kWX, 30) , kRWI_RX , 0 , 31 ), // #341 + INST(Stsminb , BaseAtomicSt , (0b0011100000100000010100, kW , 0 ) , kRWI_RX , 0 , 32 ), // #342 + INST(Stsminlb , BaseAtomicSt , (0b0011100001100000010100, kW , 0 ) , kRWI_RX , 0 , 33 ), // #343 + INST(Stsminh , BaseAtomicSt , (0b0111100000100000010100, kW , 0 ) , kRWI_RX , 0 , 34 ), // #344 + INST(Stsminlh , BaseAtomicSt , (0b0111100001100000010100, kW , 0 ) , kRWI_RX , 0 , 35 ), // #345 + INST(Sttr , BaseRM_SImm9 , (0b1011100000000000000010, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_RW , 0 , 15 ), // #346 + INST(Sttrb , BaseRM_SImm9 , (0b0011100000000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 16 ), // #347 + INST(Sttrh , BaseRM_SImm9 , (0b0111100000000000000010, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 17 ), // #348 + INST(Stumax , BaseAtomicSt , (0b1011100000100000011000, kWX, 30) , kRWI_RX , 0 , 36 ), // #349 + INST(Stumaxl , BaseAtomicSt , (0b1011100001100000011000, kWX, 30) , kRWI_RX , 0 , 37 ), // #350 + INST(Stumaxb , BaseAtomicSt , (0b0011100000100000011000, kW , 0 ) , kRWI_RX , 0 , 38 ), // #351 + INST(Stumaxlb , BaseAtomicSt , (0b0011100001100000011000, kW , 0 ) , kRWI_RX , 0 , 39 ), // #352 + INST(Stumaxh , BaseAtomicSt , (0b0111100000100000011000, kW , 0 ) , kRWI_RX , 0 , 40 ), // #353 + INST(Stumaxlh , BaseAtomicSt , (0b0111100001100000011000, kW , 0 ) , kRWI_RX , 0 , 41 ), // #354 + INST(Stumin , BaseAtomicSt , (0b1011100000100000011100, kWX, 30) , kRWI_RX , 0 , 42 ), // #355 + INST(Stuminl , BaseAtomicSt , (0b1011100001100000011100, kWX, 30) , kRWI_RX , 0 , 43 ), // #356 + INST(Stuminb , BaseAtomicSt , (0b0011100000100000011100, kW , 0 ) , kRWI_RX , 0 , 44 ), // #357 + INST(Stuminlb , BaseAtomicSt , (0b0011100001100000011100, kW , 0 ) , kRWI_RX , 0 , 45 ), // #358 + INST(Stuminh , BaseAtomicSt , (0b0111100000100000011100, kW , 0 ) , kRWI_RX , 0 , 46 ), // #359 + INST(Stuminlh , BaseAtomicSt , (0b0111100001100000011100, kW , 0 ) , kRWI_RX , 0 , 47 ), // #360 + INST(Stur , BaseRM_SImm9 , (0b1011100000000000000000, 0b0000000000000000000000, kWX, kZR, 30, 0) , kRWI_RW , 0 , 18 ), // #361 + INST(Sturb , BaseRM_SImm9 , (0b0011100000000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 19 ), // #362 + INST(Sturh , BaseRM_SImm9 , (0b0111100000000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0) , kRWI_RW , 0 , 20 ), // #363 + INST(Stxp , BaseStxp , (0b1000100000100000000000, kWX, 30) , kRWI_WRRW , 0 , 1 ), // #364 + INST(Stxr , BaseStx , (0b1000100000000000011111, kWX, 30) , kRWI_WRW , 0 , 0 ), // #365 + INST(Stxrb , BaseStx , (0b0000100000000000011111, kW , 0 ) , kRWI_WRW , 0 , 1 ), // #366 + INST(Stxrh , BaseStx , (0b0100100000000000011111, kW , 0 ) , kRWI_WRW , 0 , 2 ), // #367 + INST(Stz2g , BaseRM_SImm9 , (0b1101100111100000000010, 0b1101100111100000000001, kX , kSP, 0, 4) , kRWI_RW , 0 , 21 ), // #368 + INST(Stzg , BaseRM_SImm9 , (0b1101100101100000000010, 0b1101100101100000000001, kX , kSP, 0, 4) , kRWI_RW , 0 , 22 ), // #369 + INST(Stzgm , BaseRM_NoImm , (0b1101100100100000000000, kX , kZR, 0) , kRWI_RW , 0 , 20 ), // #370 + INST(Sub , BaseAddSub , (0b1001011000, 0b1001011001, 0b1010001) , kRWI_X , 0 , 2 ), // #371 + INST(Subg , BaseRRII , (0b1101000110000000000000, kX, kSP, kX, kSP, 6, 4, 16, 4, 0, 10) , kRWI_W , 0 , 1 ), // #372 + INST(Subp , BaseRRR , (0b1001101011000000000000, kX, kZR, kX, kSP, kX, kSP, false) , kRWI_W , 0 , 20 ), // #373 + INST(Subps , BaseRRR , (0b1011101011000000000000, kX, kZR, kX, kSP, kX, kSP, false) , kRWI_W , 0 , 21 ), // #374 + INST(Subs , BaseAddSub , (0b1101011000, 0b1101011001, 0b1110001) , kRWI_X , 0 , 3 ), // #375 + INST(Svc , BaseOpImm , (0b11010100000000000000000000000001, 16, 5) , 0 , 0 , 12 ), // #376 + INST(Swp , BaseAtomicOp , (0b1011100000100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 111), // #377 + INST(Swpa , BaseAtomicOp , (0b1011100010100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 112), // #378 + INST(Swpab , BaseAtomicOp , (0b0011100010100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 113), // #379 + INST(Swpah , BaseAtomicOp , (0b0111100010100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 114), // #380 + INST(Swpal , BaseAtomicOp , (0b1011100011100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 115), // #381 + INST(Swpalb , BaseAtomicOp , (0b0011100011100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 116), // #382 + INST(Swpalh , BaseAtomicOp , (0b0111100011100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 117), // #383 + INST(Swpb , BaseAtomicOp , (0b0011100000100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 118), // #384 + INST(Swph , BaseAtomicOp , (0b0111100000100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 119), // #385 + INST(Swpl , BaseAtomicOp , (0b1011100001100000100000, kWX, 30, 1) , kRWI_RWX , 0 , 120), // #386 + INST(Swplb , BaseAtomicOp , (0b0011100001100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 121), // #387 + INST(Swplh , BaseAtomicOp , (0b0111100001100000100000, kW , 0 , 1) , kRWI_RWX , 0 , 122), // #388 + INST(Sxtb , BaseExtend , (0b0001001100000000000111, kWX, 0) , kRWI_W , 0 , 0 ), // #389 + INST(Sxth , BaseExtend , (0b0001001100000000001111, kWX, 0) , kRWI_W , 0 , 1 ), // #390 + INST(Sxtw , BaseExtend , (0b1001001101000000011111, kX , 0) , kRWI_W , 0 , 2 ), // #391 + INST(Sys , BaseSys , (_) , kRWI_W , 0 , 0 ), // #392 + INST(Tlbi , BaseAtDcIcTlbi , (0b00011110000000, 0b00010000000000, false) , kRWI_RX , 0 , 3 ), // #393 + INST(Tst , BaseTst , (0b1101010000, 0b111001000) , kRWI_R , 0 , 0 ), // #394 + INST(Tbnz , BaseBranchTst , (0b00110111000000000000000000000000) , kRWI_R , 0 , 0 ), // #395 + INST(Tbz , BaseBranchTst , (0b00110110000000000000000000000000) , kRWI_R , 0 , 1 ), // #396 + INST(Ubfiz , BaseBfi , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 ), // #397 + INST(Ubfm , BaseBfm , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 ), // #398 + INST(Ubfx , BaseBfx , (0b01010011000000000000000000000000) , kRWI_W , 0 , 2 ), // #399 + INST(Udf , BaseOpImm , (0b00000000000000000000000000000000, 16, 0) , 0 , 0 , 13 ), // #400 + INST(Udiv , BaseRRR , (0b0001101011000000000010, kWX, kZR, kWX, kZR, kWX, kZR, true) , kRWI_W , 0 , 22 ), // #401 + INST(Umaddl , BaseRRRR , (0b1001101110100000000000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 4 ), // #402 + INST(Umnegl , BaseRRR , (0b1001101110100000111111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 23 ), // #403 + INST(Umull , BaseRRR , (0b1001101110100000011111, kX , kZR, kW , kZR, kW , kZR, false) , kRWI_W , 0 , 24 ), // #404 + INST(Umulh , BaseRRR , (0b1001101111000000011111, kX , kZR, kX , kZR, kX , kZR, false) , kRWI_W , 0 , 25 ), // #405 + INST(Umsubl , BaseRRRR , (0b1001101110100000100000, kX , kZR, kW , kZR, kW , kZR, kX , kZR, false) , kRWI_W , 0 , 5 ), // #406 + INST(Uxtb , BaseExtend , (0b0101001100000000000111, kW, 1) , kRWI_W , 0 , 3 ), // #407 + INST(Uxth , BaseExtend , (0b0101001100000000001111, kW, 1) , kRWI_W , 0 , 4 ), // #408 + INST(Wfe , BaseOp , (0b11010101000000110010000001011111) , 0 , 0 , 18 ), // #409 + INST(Wfi , BaseOp , (0b11010101000000110010000001111111) , 0 , 0 , 19 ), // #410 + INST(Xaflag , BaseOp , (0b11010101000000000100000000111111) , 0 , 0 , 20 ), // #411 + INST(Xpacd , BaseR , (0b11011010110000010100011111100000, kX, kZR, 0) , kRWI_X , 0 , 8 ), // #412 + INST(Xpaci , BaseR , (0b11011010110000010100001111100000, kX, kZR, 0) , kRWI_X , 0 , 9 ), // #413 + INST(Xpaclri , BaseOp , (0b11010101000000110010000011111111) , kRWI_X , 0 , 21 ), // #414 + INST(Yield , BaseOp , (0b11010101000000110010000000111111) , 0 , 0 , 22 ), // #415 + INST(Abs_v , ISimdVV , (0b0000111000100000101110, kVO_V_Any) , kRWI_W , 0 , 0 ), // #416 + INST(Add_v , ISimdVVV , (0b0000111000100000100001, kVO_V_Any) , kRWI_W , 0 , 0 ), // #417 + INST(Addhn_v , ISimdVVV , (0b0000111000100000010000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 1 ), // #418 + INST(Addhn2_v , ISimdVVV , (0b0100111000100000010000, kVO_V_B16H8S4) , kRWI_W , F(Narrow) , 2 ), // #419 + INST(Addp_v , ISimdPair , (0b0101111000110001101110, 0b0000111000100000101111, kVO_V_Any) , kRWI_W , F(Pair) , 0 ), // #420 + INST(Addv_v , ISimdSV , (0b0000111000110001101110, kVO_V_BH_4S) , kRWI_W , 0 , 0 ), // #421 + INST(Aesd_v , ISimdVVx , (0b0100111000101000010110, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 0 ), // #422 + INST(Aese_v , ISimdVVx , (0b0100111000101000010010, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 1 ), // #423 + INST(Aesimc_v , ISimdVVx , (0b0100111000101000011110, kOp_V16B, kOp_V16B) , kRWI_W , 0 , 2 ), // #424 + INST(Aesmc_v , ISimdVVx , (0b0100111000101000011010, kOp_V16B, kOp_V16B) , kRWI_W , 0 , 3 ), // #425 + INST(And_v , ISimdVVV , (0b0000111000100000000111, kVO_V_B) , kRWI_W , 0 , 3 ), // #426 + INST(Bcax_v , ISimdVVVV , (0b1100111000100000000000, kVO_V_B16) , kRWI_W , 0 , 0 ), // #427 + INST(Bfcvt_v , ISimdVVx , (0b0001111001100011010000, kOp_H, kOp_S) , kRWI_W , 0 , 4 ), // #428 + INST(Bfcvtn_v , ISimdVVx , (0b0000111010100001011010, kOp_V4H, kOp_V4S) , kRWI_W , F(Narrow) , 5 ), // #429 + INST(Bfcvtn2_v , ISimdVVx , (0b0100111010100001011010, kOp_V8H, kOp_V4S) , kRWI_W , F(Narrow) , 6 ), // #430 + INST(Bfdot_v , SimdDot , (0b0010111001000000111111, 0b0000111101000000111100, kET_S, kET_H, kET_2H) , kRWI_X , 0 , 0 ), // #431 + INST(Bfmlalb_v , SimdFmlal , (0b0010111011000000111111, 0b0000111111000000111100, 0, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 0 ), // #432 + INST(Bfmlalt_v , SimdFmlal , (0b0110111011000000111111, 0b0100111111000000111100, 0, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 1 ), // #433 + INST(Bfmmla_v , ISimdVVVx , (0b0110111001000000111011, kOp_V4S, kOp_V8H, kOp_V8H) , kRWI_X , F(Long) , 0 ), // #434 + INST(Bic_v , SimdBicOrr , (0b0000111001100000000111, 0b0010111100000000000001) , kRWI_W , 0 , 0 ), // #435 + INST(Bif_v , ISimdVVV , (0b0010111011100000000111, kVO_V_B) , kRWI_X , 0 , 4 ), // #436 + INST(Bit_v , ISimdVVV , (0b0010111010100000000111, kVO_V_B) , kRWI_X , 0 , 5 ), // #437 + INST(Bsl_v , ISimdVVV , (0b0010111001100000000111, kVO_V_B) , kRWI_X , 0 , 6 ), // #438 + INST(Cls_v , ISimdVV , (0b0000111000100000010010, kVO_V_BHS) , kRWI_W , 0 , 1 ), // #439 + INST(Clz_v , ISimdVV , (0b0010111000100000010010, kVO_V_BHS) , kRWI_W , 0 , 2 ), // #440 + INST(Cmeq_v , SimdCmp , (0b0010111000100000100011, 0b0000111000100000100110, kVO_V_Any) , kRWI_W , 0 , 0 ), // #441 + INST(Cmge_v , SimdCmp , (0b0000111000100000001111, 0b0010111000100000100010, kVO_V_Any) , kRWI_W , 0 , 1 ), // #442 + INST(Cmgt_v , SimdCmp , (0b0000111000100000001101, 0b0000111000100000100010, kVO_V_Any) , kRWI_W , 0 , 2 ), // #443 + INST(Cmhi_v , SimdCmp , (0b0010111000100000001101, 0b0000000000000000000000, kVO_V_Any) , kRWI_W , 0 , 3 ), // #444 + INST(Cmhs_v , SimdCmp , (0b0010111000100000001111, 0b0000000000000000000000, kVO_V_Any) , kRWI_W , 0 , 4 ), // #445 + INST(Cmle_v , SimdCmp , (0b0000000000000000000000, 0b0010111000100000100110, kVO_V_Any) , kRWI_W , 0 , 5 ), // #446 + INST(Cmlt_v , SimdCmp , (0b0000000000000000000000, 0b0000111000100000101010, kVO_V_Any) , kRWI_W , 0 , 6 ), // #447 + INST(Cmtst_v , ISimdVVV , (0b0000111000100000100011, kVO_V_Any) , kRWI_W , 0 , 7 ), // #448 + INST(Cnt_v , ISimdVV , (0b0000111000100000010110, kVO_V_B) , kRWI_W , 0 , 3 ), // #449 + INST(Dup_v , SimdDup , (_) , kRWI_W , 0 , 0 ), // #450 + INST(Eor_v , ISimdVVV , (0b0010111000100000000111, kVO_V_B) , kRWI_W , 0 , 8 ), // #451 + INST(Eor3_v , ISimdVVVV , (0b1100111000000000000000, kVO_V_B16) , kRWI_W , 0 , 1 ), // #452 + INST(Ext_v , ISimdVVVI , (0b0010111000000000000000, kVO_V_B, 4, 11, 1) , kRWI_W , 0 , 0 ), // #453 + INST(Fabd_v , FSimdVVV , (0b0111111010100000110101, kHF_C, 0b0010111010100000110101, kHF_C) , kRWI_W , 0 , 0 ), // #454 + INST(Fabs_v , FSimdVV , (0b0001111000100000110000, kHF_A, 0b0000111010100000111110, kHF_B) , kRWI_W , 0 , 0 ), // #455 + INST(Facge_v , FSimdVVV , (0b0111111000100000111011, kHF_C, 0b0010111000100000111011, kHF_C) , kRWI_W , 0 , 1 ), // #456 + INST(Facgt_v , FSimdVVV , (0b0111111010100000111011, kHF_C, 0b0010111010100000111011, kHF_C) , kRWI_W , 0 , 2 ), // #457 + INST(Fadd_v , FSimdVVV , (0b0001111000100000001010, kHF_A, 0b0000111000100000110101, kHF_C) , kRWI_W , 0 , 3 ), // #458 + INST(Faddp_v , FSimdPair , (0b0111111000110000110110, 0b0010111000100000110101) , kRWI_W , 0 , 0 ), // #459 + INST(Fcadd_v , SimdFcadd , (0b0010111000000000111001) , kRWI_W , 0 , 0 ), // #460 + INST(Fccmp_v , SimdFccmpFccmpe , (0b00011110001000000000010000000000) , kRWI_R , 0 , 0 ), // #461 + INST(Fccmpe_v , SimdFccmpFccmpe , (0b00011110001000000000010000010000) , kRWI_R , 0 , 1 ), // #462 + INST(Fcmeq_v , SimdFcm , (0b0000111000100000111001, kHF_C, 0b0000111010100000110110) , kRWI_W , 0 , 0 ), // #463 + INST(Fcmge_v , SimdFcm , (0b0010111000100000111001, kHF_C, 0b0010111010100000110010) , kRWI_W , 0 , 1 ), // #464 + INST(Fcmgt_v , SimdFcm , (0b0010111010100000111001, kHF_C, 0b0000111010100000110010) , kRWI_W , 0 , 2 ), // #465 + INST(Fcmla_v , SimdFcmla , (0b0010111000000000110001, 0b0010111100000000000100) , kRWI_X , 0 , 0 ), // #466 + INST(Fcmle_v , SimdFcm , (0b0000000000000000000000, kHF_C, 0b0010111010100000110110) , kRWI_W , 0 , 3 ), // #467 + INST(Fcmlt_v , SimdFcm , (0b0000000000000000000000, kHF_C, 0b0000111010100000111010) , kRWI_W , 0 , 4 ), // #468 + INST(Fcmp_v , SimdFcmpFcmpe , (0b00011110001000000010000000000000) , kRWI_R , 0 , 0 ), // #469 + INST(Fcmpe_v , SimdFcmpFcmpe , (0b00011110001000000010000000010000) , kRWI_R , 0 , 1 ), // #470 + INST(Fcsel_v , SimdFcsel , (_) , kRWI_W , 0 , 0 ), // #471 + INST(Fcvt_v , SimdFcvt , (_) , kRWI_W , 0 , 0 ), // #472 + INST(Fcvtas_v , SimdFcvtSV , (0b0000111000100001110010, 0b0000000000000000000000, 0b0001111000100100000000, 1) , kRWI_W , 0 , 0 ), // #473 + INST(Fcvtau_v , SimdFcvtSV , (0b0010111000100001110010, 0b0000000000000000000000, 0b0001111000100101000000, 1) , kRWI_W , 0 , 1 ), // #474 + INST(Fcvtl_v , SimdFcvtLN , (0b0000111000100001011110, 0, 0) , kRWI_W , F(Long) , 0 ), // #475 + INST(Fcvtl2_v , SimdFcvtLN , (0b0100111000100001011110, 0, 0) , kRWI_W , F(Long) , 1 ), // #476 + INST(Fcvtms_v , SimdFcvtSV , (0b0000111000100001101110, 0b0000000000000000000000, 0b0001111000110000000000, 1) , kRWI_W , 0 , 2 ), // #477 + INST(Fcvtmu_v , SimdFcvtSV , (0b0010111000100001101110, 0b0000000000000000000000, 0b0001111000110001000000, 1) , kRWI_W , 0 , 3 ), // #478 + INST(Fcvtn_v , SimdFcvtLN , (0b0000111000100001011010, 0, 0) , kRWI_W , F(Narrow) , 2 ), // #479 + INST(Fcvtn2_v , SimdFcvtLN , (0b0100111000100001011010, 0, 0) , kRWI_X , F(Narrow) , 3 ), // #480 + INST(Fcvtns_v , SimdFcvtSV , (0b0000111000100001101010, 0b0000000000000000000000, 0b0001111000100000000000, 1) , kRWI_W , 0 , 4 ), // #481 + INST(Fcvtnu_v , SimdFcvtSV , (0b0010111000100001101010, 0b0000000000000000000000, 0b0001111000100001000000, 1) , kRWI_W , 0 , 5 ), // #482 + INST(Fcvtps_v , SimdFcvtSV , (0b0000111010100001101010, 0b0000000000000000000000, 0b0001111000101000000000, 1) , kRWI_W , 0 , 6 ), // #483 + INST(Fcvtpu_v , SimdFcvtSV , (0b0010111010100001101010, 0b0000000000000000000000, 0b0001111000101001000000, 1) , kRWI_W , 0 , 7 ), // #484 + INST(Fcvtxn_v , SimdFcvtLN , (0b0010111000100001011010, 1, 1) , kRWI_W , F(Narrow) , 4 ), // #485 + INST(Fcvtxn2_v , SimdFcvtLN , (0b0110111000100001011010, 1, 0) , kRWI_X , F(Narrow) , 5 ), // #486 + INST(Fcvtzs_v , SimdFcvtSV , (0b0000111010100001101110, 0b0000111100000000111111, 0b0001111000111000000000, 1) , kRWI_W , 0 , 8 ), // #487 + INST(Fcvtzu_v , SimdFcvtSV , (0b0010111010100001101110, 0b0010111100000000111111, 0b0001111000111001000000, 1) , kRWI_W , 0 , 9 ), // #488 + INST(Fdiv_v , FSimdVVV , (0b0001111000100000000110, kHF_A, 0b0010111000100000111111, kHF_C) , kRWI_W , 0 , 4 ), // #489 + INST(Fjcvtzs_v , ISimdVVx , (0b0001111001111110000000, kOp_GpW, kOp_D) , kRWI_W , 0 , 7 ), // #490 + INST(Fmadd_v , FSimdVVVV , (0b0001111100000000000000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 0 ), // #491 + INST(Fmax_v , FSimdVVV , (0b0001111000100000010010, kHF_A, 0b0000111000100000111101, kHF_C) , kRWI_W , 0 , 5 ), // #492 + INST(Fmaxnm_v , FSimdVVV , (0b0001111000100000011010, kHF_A, 0b0000111000100000110001, kHF_C) , kRWI_W , 0 , 6 ), // #493 + INST(Fmaxnmp_v , FSimdPair , (0b0111111000110000110010, 0b0010111000100000110001) , kRWI_W , 0 , 1 ), // #494 + INST(Fmaxnmv_v , FSimdSV , (0b0010111000110000110010) , kRWI_W , 0 , 0 ), // #495 + INST(Fmaxp_v , FSimdPair , (0b0111111000110000111110, 0b0010111000100000111101) , kRWI_W , 0 , 2 ), // #496 + INST(Fmaxv_v , FSimdSV , (0b0010111000110000111110) , kRWI_W , 0 , 1 ), // #497 + INST(Fmin_v , FSimdVVV , (0b0001111000100000010110, kHF_A, 0b0000111010100000111101, kHF_C) , kRWI_W , 0 , 7 ), // #498 + INST(Fminnm_v , FSimdVVV , (0b0001111000100000011110, kHF_A, 0b0000111010100000110001, kHF_C) , kRWI_W , 0 , 8 ), // #499 + INST(Fminnmp_v , FSimdPair , (0b0111111010110000110010, 0b0010111010100000110001) , kRWI_W , 0 , 3 ), // #500 + INST(Fminnmv_v , FSimdSV , (0b0010111010110000110010) , kRWI_W , 0 , 2 ), // #501 + INST(Fminp_v , FSimdPair , (0b0111111010110000111110, 0b0010111010100000111101) , kRWI_W , 0 , 4 ), // #502 + INST(Fminv_v , FSimdSV , (0b0010111010110000111110) , kRWI_W , 0 , 3 ), // #503 + INST(Fmla_v , FSimdVVVe , (0b0000000000000000000000, kHF_N, 0b0000111000100000110011, 0b0000111110000000000100) , kRWI_X , F(VH0_15) , 0 ), // #504 + INST(Fmlal_v , SimdFmlal , (0b0000111000100000111011, 0b0000111110000000000000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 2 ), // #505 + INST(Fmlal2_v , SimdFmlal , (0b0010111000100000110011, 0b0010111110000000100000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 3 ), // #506 + INST(Fmls_v , FSimdVVVe , (0b0000000000000000000000, kHF_N, 0b0000111010100000110011, 0b0000111110000000010100) , kRWI_X , F(VH0_15) , 1 ), // #507 + INST(Fmlsl_v , SimdFmlal , (0b0000111010100000111011, 0b0000111110000000010000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 4 ), // #508 + INST(Fmlsl2_v , SimdFmlal , (0b0010111010100000110011, 0b0010111110000000110000, 1, kET_S, kET_H, kET_H) , kRWI_X , F(VH0_15) , 5 ), // #509 + INST(Fmov_v , SimdFmov , (_) , kRWI_W , 0 , 0 ), // #510 + INST(Fmsub_v , FSimdVVVV , (0b0001111100000000100000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 1 ), // #511 + INST(Fmul_v , FSimdVVVe , (0b0001111000100000000010, kHF_A, 0b0010111000100000110111, 0b0000111110000000100100) , kRWI_W , F(VH0_15) , 2 ), // #512 + INST(Fmulx_v , FSimdVVVe , (0b0101111000100000110111, kHF_C, 0b0000111000100000110111, 0b0010111110000000100100) , kRWI_W , F(VH0_15) , 3 ), // #513 + INST(Fneg_v , FSimdVV , (0b0001111000100001010000, kHF_A, 0b0010111010100000111110, kHF_B) , kRWI_W , 0 , 1 ), // #514 + INST(Fnmadd_v , FSimdVVVV , (0b0001111100100000000000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 2 ), // #515 + INST(Fnmsub_v , FSimdVVVV , (0b0001111100100000100000, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 3 ), // #516 + INST(Fnmul_v , FSimdVVV , (0b0001111000100000100010, kHF_A, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 9 ), // #517 + INST(Frecpe_v , FSimdVV , (0b0101111010100001110110, kHF_B, 0b0000111010100001110110, kHF_B) , kRWI_W , 0 , 2 ), // #518 + INST(Frecps_v , FSimdVVV , (0b0101111000100000111111, kHF_C, 0b0000111000100000111111, kHF_C) , kRWI_W , 0 , 10 ), // #519 + INST(Frecpx_v , FSimdVV , (0b0101111010100001111110, kHF_B, 0b0000000000000000000000, kHF_N) , kRWI_W , 0 , 3 ), // #520 + INST(Frint32x_v , FSimdVV , (0b0001111000101000110000, kHF_N, 0b0010111000100001111010, kHF_N) , kRWI_W , 0 , 4 ), // #521 + INST(Frint32z_v , FSimdVV , (0b0001111000101000010000, kHF_N, 0b0000111000100001111010, kHF_N) , kRWI_W , 0 , 5 ), // #522 + INST(Frint64x_v , FSimdVV , (0b0001111000101001110000, kHF_N, 0b0010111000100001111110, kHF_N) , kRWI_W , 0 , 6 ), // #523 + INST(Frint64z_v , FSimdVV , (0b0001111000101001010000, kHF_N, 0b0000111000100001111110, kHF_N) , kRWI_W , 0 , 7 ), // #524 + INST(Frinta_v , FSimdVV , (0b0001111000100110010000, kHF_A, 0b0010111000100001100010, kHF_B) , kRWI_W , 0 , 8 ), // #525 + INST(Frinti_v , FSimdVV , (0b0001111000100111110000, kHF_A, 0b0010111010100001100110, kHF_B) , kRWI_W , 0 , 9 ), // #526 + INST(Frintm_v , FSimdVV , (0b0001111000100101010000, kHF_A, 0b0000111000100001100110, kHF_B) , kRWI_W , 0 , 10 ), // #527 + INST(Frintn_v , FSimdVV , (0b0001111000100100010000, kHF_A, 0b0000111000100001100010, kHF_B) , kRWI_W , 0 , 11 ), // #528 + INST(Frintp_v , FSimdVV , (0b0001111000100100110000, kHF_A, 0b0000111010100001100010, kHF_B) , kRWI_W , 0 , 12 ), // #529 + INST(Frintx_v , FSimdVV , (0b0001111000100111010000, kHF_A, 0b0010111000100001100110, kHF_B) , kRWI_W , 0 , 13 ), // #530 + INST(Frintz_v , FSimdVV , (0b0001111000100101110000, kHF_A, 0b0000111010100001100110, kHF_B) , kRWI_W , 0 , 14 ), // #531 + INST(Frsqrte_v , FSimdVV , (0b0111111010100001110110, kHF_B, 0b0010111010100001110110, kHF_B) , kRWI_W , 0 , 15 ), // #532 + INST(Frsqrts_v , FSimdVVV , (0b0101111010100000111111, kHF_C, 0b0000111010100000111111, kHF_C) , kRWI_W , 0 , 11 ), // #533 + INST(Fsqrt_v , FSimdVV , (0b0001111000100001110000, kHF_A, 0b0010111010100001111110, kHF_B) , kRWI_W , 0 , 16 ), // #534 + INST(Fsub_v , FSimdVVV , (0b0001111000100000001110, kHF_A, 0b0000111010100000110101, kHF_C) , kRWI_W , 0 , 12 ), // #535 + INST(Ins_v , SimdIns , (_) , kRWI_X , 0 , 0 ), // #536 + INST(Ld1_v , SimdLdNStN , (0b0000110101000000000000, 0b0000110001000000001000, 1, 0) , kRWI_LDn , F(Consecutive) , 0 ), // #537 + INST(Ld1r_v , SimdLdNStN , (0b0000110101000000110000, 0b0000000000000000000000, 1, 1) , kRWI_LDn , F(Consecutive) , 1 ), // #538 + INST(Ld2_v , SimdLdNStN , (0b0000110101100000000000, 0b0000110001000000100000, 2, 0) , kRWI_LDn , F(Consecutive) , 2 ), // #539 + INST(Ld2r_v , SimdLdNStN , (0b0000110101100000110000, 0b0000000000000000000000, 2, 1) , kRWI_LDn , F(Consecutive) , 3 ), // #540 + INST(Ld3_v , SimdLdNStN , (0b0000110101000000001000, 0b0000110001000000010000, 3, 0) , kRWI_LDn , F(Consecutive) , 4 ), // #541 + INST(Ld3r_v , SimdLdNStN , (0b0000110101000000111000, 0b0000000000000000000000, 3, 1) , kRWI_LDn , F(Consecutive) , 5 ), // #542 + INST(Ld4_v , SimdLdNStN , (0b0000110101100000001000, 0b0000110001000000000000, 4, 0) , kRWI_LDn , F(Consecutive) , 6 ), // #543 + INST(Ld4r_v , SimdLdNStN , (0b0000110101100000111000, 0b0000000000000000000000, 4, 1) , kRWI_LDn , F(Consecutive) , 7 ), // #544 + INST(Ldnp_v , SimdLdpStp , (0b0010110001, 0b0000000000) , kRWI_WW , 0 , 0 ), // #545 + INST(Ldp_v , SimdLdpStp , (0b0010110101, 0b0010110011) , kRWI_WW , 0 , 1 ), // #546 + INST(Ldr_v , SimdLdSt , (0b0011110101, 0b00111100010, 0b00111100011, 0b00011100, Inst::kIdLdur_v) , kRWI_W , 0 , 0 ), // #547 + INST(Ldur_v , SimdLdurStur , (0b0011110001000000000000) , kRWI_W , 0 , 0 ), // #548 + INST(Mla_v , ISimdVVVe , (0b0000111000100000100101, kVO_V_BHS, 0b0010111100000000000000, kVO_V_HS) , kRWI_X , F(VH0_15) , 0 ), // #549 + INST(Mls_v , ISimdVVVe , (0b0010111000100000100101, kVO_V_BHS, 0b0010111100000000010000, kVO_V_HS) , kRWI_X , F(VH0_15) , 1 ), // #550 + INST(Mov_v , SimdMov , (_) , kRWI_W , 0 , 0 ), // #551 + INST(Movi_v , SimdMoviMvni , (0b0000111100000000000001, 0) , kRWI_W , 0 , 0 ), // #552 + INST(Mul_v , ISimdVVVe , (0b0000111000100000100111, kVO_V_BHS, 0b0000111100000000100000, kVO_V_HS) , kRWI_W , F(VH0_15) , 2 ), // #553 + INST(Mvn_v , ISimdVV , (0b0010111000100000010110, kVO_V_B) , kRWI_W , 0 , 4 ), // #554 + INST(Mvni_v , SimdMoviMvni , (0b0000111100000000000001, 1) , kRWI_W , 0 , 1 ), // #555 + INST(Neg_v , ISimdVV , (0b0010111000100000101110, kVO_V_Any) , kRWI_W , 0 , 5 ), // #556 + INST(Not_v , ISimdVV , (0b0010111000100000010110, kVO_V_B) , kRWI_W , 0 , 6 ), // #557 + INST(Orn_v , ISimdVVV , (0b0000111011100000000111, kVO_V_B) , kRWI_W , 0 , 9 ), // #558 + INST(Orr_v , SimdBicOrr , (0b0000111010100000000111, 0b0000111100000000000001) , kRWI_W , 0 , 1 ), // #559 + INST(Pmul_v , ISimdVVV , (0b0010111000100000100111, kVO_V_B) , kRWI_W , 0 , 10 ), // #560 + INST(Pmull_v , ISimdVVV , (0b0000111000100000111000, kVO_V_B8D1) , kRWI_W , F(Long) , 11 ), // #561 + INST(Pmull2_v , ISimdVVV , (0b0100111000100000111000, kVO_V_B16D2) , kRWI_W , F(Long) , 12 ), // #562 + INST(Raddhn_v , ISimdVVV , (0b0010111000100000010000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 13 ), // #563 + INST(Raddhn2_v , ISimdVVV , (0b0110111000100000010000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 14 ), // #564 + INST(Rax1_v , ISimdVVV , (0b1100111001100000100011, kVO_V_D2) , kRWI_W , 0 , 15 ), // #565 + INST(Rbit_v , ISimdVV , (0b0010111001100000010110, kVO_V_B) , kRWI_W , 0 , 7 ), // #566 + INST(Rev16_v , ISimdVV , (0b0000111000100000000110, kVO_V_B) , kRWI_W , 0 , 8 ), // #567 + INST(Rev32_v , ISimdVV , (0b0010111000100000000010, kVO_V_BH) , kRWI_W , 0 , 9 ), // #568 + INST(Rev64_v , ISimdVV , (0b0000111000100000000010, kVO_V_BHS) , kRWI_W , 0 , 10 ), // #569 + INST(Rshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100011, 1, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 0 ), // #570 + INST(Rshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100011, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 1 ), // #571 + INST(Rsubhn_v , ISimdVVV , (0b0010111000100000011000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 16 ), // #572 + INST(Rsubhn2_v , ISimdVVV , (0b0110111000100000011000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 17 ), // #573 + INST(Saba_v , ISimdVVV , (0b0000111000100000011111, kVO_V_BHS) , kRWI_X , 0 , 18 ), // #574 + INST(Sabal_v , ISimdVVV , (0b0000111000100000010100, kVO_V_B8H4S2) , kRWI_X , F(Long) , 19 ), // #575 + INST(Sabal2_v , ISimdVVV , (0b0100111000100000010100, kVO_V_B16H8S4) , kRWI_X , F(Long) , 20 ), // #576 + INST(Sabd_v , ISimdVVV , (0b0000111000100000011101, kVO_V_BHS) , kRWI_W , 0 , 21 ), // #577 + INST(Sabdl_v , ISimdVVV , (0b0000111000100000011100, kVO_V_B8H4S2) , kRWI_W , F(Long) , 22 ), // #578 + INST(Sabdl2_v , ISimdVVV , (0b0100111000100000011100, kVO_V_B16H8S4) , kRWI_W , F(Long) , 23 ), // #579 + INST(Sadalp_v , ISimdVV , (0b0000111000100000011010, kVO_V_BHS) , kRWI_X , F(Long) | F(Pair) , 11 ), // #580 + INST(Saddl_v , ISimdVVV , (0b0000111000100000000000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 24 ), // #581 + INST(Saddl2_v , ISimdVVV , (0b0100111000100000000000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 25 ), // #582 + INST(Saddlp_v , ISimdVV , (0b0000111000100000001010, kVO_V_BHS) , kRWI_W , F(Long) | F(Pair) , 12 ), // #583 + INST(Saddlv_v , ISimdSV , (0b0000111000110000001110, kVO_V_BH_4S) , kRWI_W , F(Long) , 1 ), // #584 + INST(Saddw_v , ISimdWWV , (0b0000111000100000000100, kVO_V_B8H4S2) , kRWI_W , 0 , 0 ), // #585 + INST(Saddw2_v , ISimdWWV , (0b0000111000100000000100, kVO_V_B16H8S4) , kRWI_W , 0 , 1 ), // #586 + INST(Scvtf_v , SimdFcvtSV , (0b0000111000100001110110, 0b0000111100000000111001, 0b0001111000100010000000, 0) , kRWI_W , 0 , 10 ), // #587 + INST(Sdot_v , SimdDot , (0b0000111010000000100101, 0b0000111110000000111000, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 1 ), // #588 + INST(Sha1c_v , ISimdVVVx , (0b0101111000000000000000, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 1 ), // #589 + INST(Sha1h_v , ISimdVVx , (0b0101111000101000000010, kOp_S, kOp_S) , kRWI_W , 0 , 8 ), // #590 + INST(Sha1m_v , ISimdVVVx , (0b0101111000000000001000, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 2 ), // #591 + INST(Sha1p_v , ISimdVVVx , (0b0101111000000000000100, kOp_Q, kOp_S, kOp_V4S) , kRWI_X , 0 , 3 ), // #592 + INST(Sha1su0_v , ISimdVVVx , (0b0101111000000000001100, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 4 ), // #593 + INST(Sha1su1_v , ISimdVVx , (0b0101111000101000000110, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 9 ), // #594 + INST(Sha256h_v , ISimdVVVx , (0b0101111000000000010000, kOp_Q, kOp_Q, kOp_V4S) , kRWI_X , 0 , 5 ), // #595 + INST(Sha256h2_v , ISimdVVVx , (0b0101111000000000010100, kOp_Q, kOp_Q, kOp_V4S) , kRWI_X , 0 , 6 ), // #596 + INST(Sha256su0_v , ISimdVVx , (0b0101111000101000001010, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 10 ), // #597 + INST(Sha256su1_v , ISimdVVVx , (0b0101111000000000011000, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 7 ), // #598 + INST(Sha512h_v , ISimdVVVx , (0b1100111001100000100000, kOp_Q, kOp_Q, kOp_V2D) , kRWI_X , 0 , 8 ), // #599 + INST(Sha512h2_v , ISimdVVVx , (0b1100111001100000100001, kOp_Q, kOp_Q, kOp_V2D) , kRWI_X , 0 , 9 ), // #600 + INST(Sha512su0_v , ISimdVVx , (0b1100111011000000100000, kOp_V2D, kOp_V2D) , kRWI_X , 0 , 11 ), // #601 + INST(Sha512su1_v , ISimdVVVx , (0b1100111001100000100010, kOp_V2D, kOp_V2D, kOp_V2D) , kRWI_X , 0 , 10 ), // #602 + INST(Shadd_v , ISimdVVV , (0b0000111000100000000001, kVO_V_BHS) , kRWI_W , 0 , 26 ), // #603 + INST(Shl_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000010101, 0, kVO_V_Any) , kRWI_W , 0 , 2 ), // #604 + INST(Shll_v , SimdShiftES , (0b0010111000100001001110, kVO_V_B8H4S2) , kRWI_W , F(Long) , 0 ), // #605 + INST(Shll2_v , SimdShiftES , (0b0110111000100001001110, kVO_V_B16H8S4) , kRWI_W , F(Long) , 1 ), // #606 + INST(Shrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100001, 1, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 3 ), // #607 + INST(Shrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100001, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 4 ), // #608 + INST(Shsub_v , ISimdVVV , (0b0000111000100000001001, kVO_V_BHS) , kRWI_W , 0 , 27 ), // #609 + INST(Sli_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000010101, 0, kVO_V_Any) , kRWI_X , 0 , 5 ), // #610 + INST(Sm3partw1_v , ISimdVVVx , (0b1100111001100000110000, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 11 ), // #611 + INST(Sm3partw2_v , ISimdVVVx , (0b1100111001100000110001, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 12 ), // #612 + INST(Sm3ss1_v , ISimdVVVVx , (0b1100111001000000000000, kOp_V4S, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_W , 0 , 0 ), // #613 + INST(Sm3tt1a_v , SimdSm3tt , (0b1100111001000000100000) , kRWI_X , 0 , 0 ), // #614 + INST(Sm3tt1b_v , SimdSm3tt , (0b1100111001000000100001) , kRWI_X , 0 , 1 ), // #615 + INST(Sm3tt2a_v , SimdSm3tt , (0b1100111001000000100010) , kRWI_X , 0 , 2 ), // #616 + INST(Sm3tt2b_v , SimdSm3tt , (0b1100111001000000100011) , kRWI_X , 0 , 3 ), // #617 + INST(Sm4e_v , ISimdVVx , (0b1100111011000000100001, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 12 ), // #618 + INST(Sm4ekey_v , ISimdVVVx , (0b1100111001100000110010, kOp_V4S, kOp_V4S, kOp_V4S) , kRWI_X , 0 , 13 ), // #619 + INST(Smax_v , ISimdVVV , (0b0000111000100000011001, kVO_V_BHS) , kRWI_W , 0 , 28 ), // #620 + INST(Smaxp_v , ISimdVVV , (0b0000111000100000101001, kVO_V_BHS) , kRWI_W , 0 , 29 ), // #621 + INST(Smaxv_v , ISimdSV , (0b0000111000110000101010, kVO_V_BH_4S) , kRWI_W , 0 , 2 ), // #622 + INST(Smin_v , ISimdVVV , (0b0000111000100000011011, kVO_V_BHS) , kRWI_W , 0 , 30 ), // #623 + INST(Sminp_v , ISimdVVV , (0b0000111000100000101011, kVO_V_BHS) , kRWI_W , 0 , 31 ), // #624 + INST(Sminv_v , ISimdSV , (0b0000111000110001101010, kVO_V_BH_4S) , kRWI_W , 0 , 3 ), // #625 + INST(Smlal_v , ISimdVVVe , (0b0000111000100000100000, kVO_V_B8H4S2, 0b0000111100000000001000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 3 ), // #626 + INST(Smlal2_v , ISimdVVVe , (0b0100111000100000100000, kVO_V_B16H8S4, 0b0100111100000000001000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 4 ), // #627 + INST(Smlsl_v , ISimdVVVe , (0b0000111000100000101000, kVO_V_B8H4S2, 0b0000111100000000011000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 5 ), // #628 + INST(Smlsl2_v , ISimdVVVe , (0b0100111000100000101000, kVO_V_B16H8S4, 0b0100111100000000011000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 6 ), // #629 + INST(Smmla_v , ISimdVVVx , (0b0100111010000000101001, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 14 ), // #630 + INST(Smov_v , SimdSmovUmov , (0b0000111000000000001011, kVO_V_BHS, 1) , kRWI_W , 0 , 0 ), // #631 + INST(Smull_v , ISimdVVVe , (0b0000111000100000110000, kVO_V_B8H4S2, 0b0000111100000000101000, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 7 ), // #632 + INST(Smull2_v , ISimdVVVe , (0b0100111000100000110000, kVO_V_B16H8S4, 0b0100111100000000101000, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 8 ), // #633 + INST(Sqabs_v , ISimdVV , (0b0000111000100000011110, kVO_SV_Any) , kRWI_W , 0 , 13 ), // #634 + INST(Sqadd_v , ISimdVVV , (0b0000111000100000000011, kVO_SV_Any) , kRWI_W , 0 , 32 ), // #635 + INST(Sqdmlal_v , ISimdVVVe , (0b0000111000100000100100, kVO_SV_BHS, 0b0000111100000000001100, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 9 ), // #636 + INST(Sqdmlal2_v , ISimdVVVe , (0b0100111000100000100100, kVO_V_B16H8S4, 0b0100111100000000001100, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 10 ), // #637 + INST(Sqdmlsl_v , ISimdVVVe , (0b0000111000100000101100, kVO_SV_BHS, 0b0000111100000000011100, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 11 ), // #638 + INST(Sqdmlsl2_v , ISimdVVVe , (0b0100111000100000101100, kVO_V_B16H8S4, 0b0100111100000000011100, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 12 ), // #639 + INST(Sqdmulh_v , ISimdVVVe , (0b0000111000100000101101, kVO_SV_HS, 0b0000111100000000110000, kVO_SV_HS) , kRWI_W , F(VH0_15) , 13 ), // #640 + INST(Sqdmull_v , ISimdVVVe , (0b0000111000100000110100, kVO_SV_BHS, 0b0000111100000000101100, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 14 ), // #641 + INST(Sqdmull2_v , ISimdVVVe , (0b0100111000100000110100, kVO_V_B16H8S4, 0b0100111100000000101100, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 15 ), // #642 + INST(Sqneg_v , ISimdVV , (0b0010111000100000011110, kVO_SV_Any) , kRWI_W , 0 , 14 ), // #643 + INST(Sqrdmlah_v , ISimdVVVe , (0b0010111000000000100001, kVO_SV_HS, 0b0010111100000000110100, kVO_SV_HS) , kRWI_X , F(VH0_15) , 16 ), // #644 + INST(Sqrdmlsh_v , ISimdVVVe , (0b0010111000000000100011, kVO_SV_HS, 0b0010111100000000111100, kVO_SV_HS) , kRWI_X , F(VH0_15) , 17 ), // #645 + INST(Sqrdmulh_v , ISimdVVVe , (0b0010111000100000101101, kVO_SV_HS, 0b0000111100000000110100, kVO_SV_HS) , kRWI_W , F(VH0_15) , 18 ), // #646 + INST(Sqrshl_v , SimdShift , (0b0000111000100000010111, 0b0000000000000000000000, 1, kVO_SV_Any) , kRWI_W , 0 , 6 ), // #647 + INST(Sqrshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100111, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 7 ), // #648 + INST(Sqrshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100111, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 8 ), // #649 + INST(Sqrshrun_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100011, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 9 ), // #650 + INST(Sqrshrun2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100011, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 10 ), // #651 + INST(Sqshl_v , SimdShift , (0b0000111000100000010011, 0b0000111100000000011101, 0, kVO_SV_Any) , kRWI_W , 0 , 11 ), // #652 + INST(Sqshlu_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000011001, 0, kVO_SV_Any) , kRWI_W , 0 , 12 ), // #653 + INST(Sqshrn_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000100101, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 13 ), // #654 + INST(Sqshrn2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000100101, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 14 ), // #655 + INST(Sqshrun_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100001, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 15 ), // #656 + INST(Sqshrun2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100001, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 16 ), // #657 + INST(Sqsub_v , ISimdVVV , (0b0000111000100000001011, kVO_SV_Any) , kRWI_W , 0 , 33 ), // #658 + INST(Sqxtn_v , ISimdVV , (0b0000111000100001010010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 15 ), // #659 + INST(Sqxtn2_v , ISimdVV , (0b0100111000100001010010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 16 ), // #660 + INST(Sqxtun_v , ISimdVV , (0b0010111000100001001010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 17 ), // #661 + INST(Sqxtun2_v , ISimdVV , (0b0110111000100001001010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 18 ), // #662 + INST(Srhadd_v , ISimdVVV , (0b0000111000100000000101, kVO_V_BHS) , kRWI_W , 0 , 34 ), // #663 + INST(Sri_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000010001, 1, kVO_V_Any) , kRWI_W , 0 , 17 ), // #664 + INST(Srshl_v , SimdShift , (0b0000111000100000010101, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 18 ), // #665 + INST(Srshr_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000001001, 1, kVO_V_Any) , kRWI_W , 0 , 19 ), // #666 + INST(Srsra_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000001101, 1, kVO_V_Any) , kRWI_X , 0 , 20 ), // #667 + INST(Sshl_v , SimdShift , (0b0000111000100000010001, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 21 ), // #668 + INST(Sshll_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000101001, 0, kVO_V_B8H4S2) , kRWI_W , F(Long) , 22 ), // #669 + INST(Sshll2_v , SimdShift , (0b0000000000000000000000, 0b0100111100000000101001, 0, kVO_V_B16H8S4) , kRWI_W , F(Long) , 23 ), // #670 + INST(Sshr_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000000001, 1, kVO_V_Any) , kRWI_W , 0 , 24 ), // #671 + INST(Ssra_v , SimdShift , (0b0000000000000000000000, 0b0000111100000000000101, 1, kVO_V_Any) , kRWI_X , 0 , 25 ), // #672 + INST(Ssubl_v , ISimdVVV , (0b0000111000100000001000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 35 ), // #673 + INST(Ssubl2_v , ISimdVVV , (0b0100111000100000001000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 36 ), // #674 + INST(Ssubw_v , ISimdWWV , (0b0000111000100000001100, kVO_V_B8H4S2) , kRWI_W , 0 , 2 ), // #675 + INST(Ssubw2_v , ISimdWWV , (0b0000111000100000001100, kVO_V_B16H8S4) , kRWI_X , 0 , 3 ), // #676 + INST(St1_v , SimdLdNStN , (0b0000110100000000000000, 0b0000110000000000001000, 1, 0) , kRWI_STn , F(Consecutive) , 8 ), // #677 + INST(St2_v , SimdLdNStN , (0b0000110100100000000000, 0b0000110000000000100000, 2, 0) , kRWI_STn , F(Consecutive) , 9 ), // #678 + INST(St3_v , SimdLdNStN , (0b0000110100000000001000, 0b0000110000000000010000, 3, 0) , kRWI_STn , F(Consecutive) , 10 ), // #679 + INST(St4_v , SimdLdNStN , (0b0000110100100000001000, 0b0000110000000000000000, 4, 0) , kRWI_STn , F(Consecutive) , 11 ), // #680 + INST(Stnp_v , SimdLdpStp , (0b0010110000, 0b0000000000) , kRWI_RRW , 0 , 2 ), // #681 + INST(Stp_v , SimdLdpStp , (0b0010110100, 0b0010110010) , kRWI_RRW , 0 , 3 ), // #682 + INST(Str_v , SimdLdSt , (0b0011110100, 0b00111100000, 0b00111100001, 0b00000000, Inst::kIdStur_v) , kRWI_RW , 0 , 1 ), // #683 + INST(Stur_v , SimdLdurStur , (0b0011110000000000000000) , kRWI_RW , 0 , 1 ), // #684 + INST(Sub_v , ISimdVVV , (0b0010111000100000100001, kVO_V_Any) , kRWI_W , 0 , 37 ), // #685 + INST(Subhn_v , ISimdVVV , (0b0000111000100000011000, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 38 ), // #686 + INST(Subhn2_v , ISimdVVV , (0b0000111000100000011000, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 39 ), // #687 + INST(Sudot_v , SimdDot , (0b0000000000000000000000, 0b0000111100000000111100, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 2 ), // #688 + INST(Suqadd_v , ISimdVV , (0b0000111000100000001110, kVO_SV_Any) , kRWI_X , 0 , 19 ), // #689 + INST(Sxtl_v , SimdSxtlUxtl , (0b0000111100000000101001, kVO_V_B8H4S2) , kRWI_W , F(Long) , 0 ), // #690 + INST(Sxtl2_v , SimdSxtlUxtl , (0b0100111100000000101001, kVO_V_B16H8S4) , kRWI_W , F(Long) , 1 ), // #691 + INST(Tbl_v , SimdTblTbx , (0b0000111000000000000000) , kRWI_W , 0 , 0 ), // #692 + INST(Tbx_v , SimdTblTbx , (0b0000111000000000000100) , kRWI_W , 0 , 1 ), // #693 + INST(Trn1_v , ISimdVVV , (0b0000111000000000001010, kVO_V_BHS_D2) , kRWI_W , 0 , 40 ), // #694 + INST(Trn2_v , ISimdVVV , (0b0000111000000000011010, kVO_V_BHS_D2) , kRWI_W , 0 , 41 ), // #695 + INST(Uaba_v , ISimdVVV , (0b0010111000100000011111, kVO_V_BHS) , kRWI_X , 0 , 42 ), // #696 + INST(Uabal_v , ISimdVVV , (0b0010111000100000010100, kVO_V_B8H4S2) , kRWI_X , F(Long) , 43 ), // #697 + INST(Uabal2_v , ISimdVVV , (0b0110111000100000010100, kVO_V_B16H8S4) , kRWI_X , F(Long) , 44 ), // #698 + INST(Uabd_v , ISimdVVV , (0b0010111000100000011101, kVO_V_BHS) , kRWI_W , 0 , 45 ), // #699 + INST(Uabdl_v , ISimdVVV , (0b0010111000100000011100, kVO_V_B8H4S2) , kRWI_W , F(Long) , 46 ), // #700 + INST(Uabdl2_v , ISimdVVV , (0b0110111000100000011100, kVO_V_B16H8S4) , kRWI_W , F(Long) , 47 ), // #701 + INST(Uadalp_v , ISimdVV , (0b0010111000100000011010, kVO_V_BHS) , kRWI_X , F(Long) | F(Pair) , 20 ), // #702 + INST(Uaddl_v , ISimdVVV , (0b0010111000100000000000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 48 ), // #703 + INST(Uaddl2_v , ISimdVVV , (0b0110111000100000000000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 49 ), // #704 + INST(Uaddlp_v , ISimdVV , (0b0010111000100000001010, kVO_V_BHS) , kRWI_W , F(Long) | F(Pair) , 21 ), // #705 + INST(Uaddlv_v , ISimdSV , (0b0010111000110000001110, kVO_V_BH_4S) , kRWI_W , F(Long) , 4 ), // #706 + INST(Uaddw_v , ISimdWWV , (0b0010111000100000000100, kVO_V_B8H4S2) , kRWI_W , 0 , 4 ), // #707 + INST(Uaddw2_v , ISimdWWV , (0b0010111000100000000100, kVO_V_B16H8S4) , kRWI_W , 0 , 5 ), // #708 + INST(Ucvtf_v , SimdFcvtSV , (0b0010111000100001110110, 0b0010111100000000111001, 0b0001111000100011000000, 0) , kRWI_W , 0 , 11 ), // #709 + INST(Udot_v , SimdDot , (0b0010111010000000100101, 0b0010111110000000111000, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 3 ), // #710 + INST(Uhadd_v , ISimdVVV , (0b0010111000100000000001, kVO_V_BHS) , kRWI_W , 0 , 50 ), // #711 + INST(Uhsub_v , ISimdVVV , (0b0010111000100000001001, kVO_V_BHS) , kRWI_W , 0 , 51 ), // #712 + INST(Umax_v , ISimdVVV , (0b0010111000100000011001, kVO_V_BHS) , kRWI_W , 0 , 52 ), // #713 + INST(Umaxp_v , ISimdVVV , (0b0010111000100000101001, kVO_V_BHS) , kRWI_W , 0 , 53 ), // #714 + INST(Umaxv_v , ISimdSV , (0b0010111000110000101010, kVO_V_BH_4S) , kRWI_W , 0 , 5 ), // #715 + INST(Umin_v , ISimdVVV , (0b0010111000100000011011, kVO_V_BHS) , kRWI_W , 0 , 54 ), // #716 + INST(Uminp_v , ISimdVVV , (0b0010111000100000101011, kVO_V_BHS) , kRWI_W , 0 , 55 ), // #717 + INST(Uminv_v , ISimdSV , (0b0010111000110001101010, kVO_V_BH_4S) , kRWI_W , 0 , 6 ), // #718 + INST(Umlal_v , ISimdVVVe , (0b0010111000100000100000, kVO_V_B8H4S2, 0b0010111100000000001000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 19 ), // #719 + INST(Umlal2_v , ISimdVVVe , (0b0110111000100000100000, kVO_V_B16H8S4, 0b0010111100000000001000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 20 ), // #720 + INST(Umlsl_v , ISimdVVVe , (0b0010111000100000101000, kVO_V_B8H4S2, 0b0010111100000000011000, kVO_V_H4S2) , kRWI_X , F(Long) | F(VH0_15) , 21 ), // #721 + INST(Umlsl2_v , ISimdVVVe , (0b0110111000100000101000, kVO_V_B16H8S4, 0b0110111100000000011000, kVO_V_H8S4) , kRWI_X , F(Long) | F(VH0_15) , 22 ), // #722 + INST(Ummla_v , ISimdVVVx , (0b0110111010000000101001, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 15 ), // #723 + INST(Umov_v , SimdSmovUmov , (0b0000111000000000001111, kVO_V_Any, 0) , kRWI_W , 0 , 1 ), // #724 + INST(Umull_v , ISimdVVVe , (0b0010111000100000110000, kVO_V_B8H4S2, 0b0010111100000000101000, kVO_V_H4S2) , kRWI_W , F(Long) | F(VH0_15) , 23 ), // #725 + INST(Umull2_v , ISimdVVVe , (0b0110111000100000110000, kVO_V_B16H8S4, 0b0110111100000000101000, kVO_V_H8S4) , kRWI_W , F(Long) | F(VH0_15) , 24 ), // #726 + INST(Uqadd_v , ISimdVVV , (0b0010111000100000000011, kVO_SV_Any) , kRWI_W , 0 , 56 ), // #727 + INST(Uqrshl_v , SimdShift , (0b0010111000100000010111, 0b0000000000000000000000, 0, kVO_SV_Any) , kRWI_W , 0 , 26 ), // #728 + INST(Uqrshrn_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100111, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 27 ), // #729 + INST(Uqrshrn2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100111, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 28 ), // #730 + INST(Uqshl_v , SimdShift , (0b0010111000100000010011, 0b0010111100000000011101, 0, kVO_SV_Any) , kRWI_W , 0 , 29 ), // #731 + INST(Uqshrn_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000100101, 1, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 30 ), // #732 + INST(Uqshrn2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000100101, 1, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 31 ), // #733 + INST(Uqsub_v , ISimdVVV , (0b0010111000100000001011, kVO_SV_Any) , kRWI_W , 0 , 57 ), // #734 + INST(Uqxtn_v , ISimdVV , (0b0010111000100001010010, kVO_SV_B8H4S2) , kRWI_W , F(Narrow) , 22 ), // #735 + INST(Uqxtn2_v , ISimdVV , (0b0110111000100001010010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 23 ), // #736 + INST(Urecpe_v , ISimdVV , (0b0000111010100001110010, kVO_V_S) , kRWI_W , 0 , 24 ), // #737 + INST(Urhadd_v , ISimdVVV , (0b0010111000100000000101, kVO_V_BHS) , kRWI_W , 0 , 58 ), // #738 + INST(Urshl_v , SimdShift , (0b0010111000100000010101, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 32 ), // #739 + INST(Urshr_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000001001, 1, kVO_V_Any) , kRWI_W , 0 , 33 ), // #740 + INST(Ursqrte_v , ISimdVV , (0b0010111010100001110010, kVO_V_S) , kRWI_W , 0 , 25 ), // #741 + INST(Ursra_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000001101, 1, kVO_V_Any) , kRWI_X , 0 , 34 ), // #742 + INST(Usdot_v , SimdDot , (0b0000111010000000100111, 0b0000111110000000111100, kET_S, kET_B, kET_4B) , kRWI_X , 0 , 4 ), // #743 + INST(Ushl_v , SimdShift , (0b0010111000100000010001, 0b0000000000000000000000, 0, kVO_V_Any) , kRWI_W , 0 , 35 ), // #744 + INST(Ushll_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000101001, 0, kVO_V_B8H4S2) , kRWI_W , F(Long) , 36 ), // #745 + INST(Ushll2_v , SimdShift , (0b0000000000000000000000, 0b0110111100000000101001, 0, kVO_V_B16H8S4) , kRWI_W , F(Long) , 37 ), // #746 + INST(Ushr_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000000001, 1, kVO_V_Any) , kRWI_W , 0 , 38 ), // #747 + INST(Usmmla_v , ISimdVVVx , (0b0100111010000000101011, kOp_V4S, kOp_V16B, kOp_V16B) , kRWI_X , 0 , 16 ), // #748 + INST(Usqadd_v , ISimdVV , (0b0010111000100000001110, kVO_SV_Any) , kRWI_X , 0 , 26 ), // #749 + INST(Usra_v , SimdShift , (0b0000000000000000000000, 0b0010111100000000000101, 1, kVO_V_Any) , kRWI_X , 0 , 39 ), // #750 + INST(Usubl_v , ISimdVVV , (0b0010111000100000001000, kVO_V_B8H4S2) , kRWI_W , F(Long) , 59 ), // #751 + INST(Usubl2_v , ISimdVVV , (0b0110111000100000001000, kVO_V_B16H8S4) , kRWI_W , F(Long) , 60 ), // #752 + INST(Usubw_v , ISimdWWV , (0b0010111000100000001100, kVO_V_B8H4S2) , kRWI_W , 0 , 6 ), // #753 + INST(Usubw2_v , ISimdWWV , (0b0010111000100000001100, kVO_V_B16H8S4) , kRWI_W , 0 , 7 ), // #754 + INST(Uxtl_v , SimdSxtlUxtl , (0b0010111100000000101001, kVO_V_B8H4S2) , kRWI_W , F(Long) , 2 ), // #755 + INST(Uxtl2_v , SimdSxtlUxtl , (0b0110111100000000101001, kVO_V_B16H8S4) , kRWI_W , F(Long) , 3 ), // #756 + INST(Uzp1_v , ISimdVVV , (0b0000111000000000000110, kVO_V_BHS_D2) , kRWI_W , 0 , 61 ), // #757 + INST(Uzp2_v , ISimdVVV , (0b0000111000000000010110, kVO_V_BHS_D2) , kRWI_W , 0 , 62 ), // #758 + INST(Xar_v , ISimdVVVI , (0b1100111001100000100011, kVO_V_D2, 6, 10, 0) , kRWI_W , 0 , 1 ), // #759 + INST(Xtn_v , ISimdVV , (0b0000111000100001001010, kVO_V_B8H4S2) , kRWI_W , F(Narrow) , 27 ), // #760 + INST(Xtn2_v , ISimdVV , (0b0100111000100001001010, kVO_V_B16H8S4) , kRWI_X , F(Narrow) , 28 ), // #761 + INST(Zip1_v , ISimdVVV , (0b0000111000000000001110, kVO_V_BHS_D2) , kRWI_W , 0 , 63 ), // #762 + INST(Zip2_v , ISimdVVV , (0b0000111000000000011110, kVO_V_BHS_D2) , kRWI_W , 0 , 64 ) // #763 // ${InstInfo:End} }; @@ -1132,8 +1123,8 @@ const BaseLdSt baseLdSt[9] = { { 0b1011100101, 0b10111000010, 0b10111000011, 0b00011000, kWX, 30, 2, Inst::kIdLdur }, // ldr { 0b0011100101, 0b00111000010, 0b00111000011, 0 , kW , 0 , 0, Inst::kIdLdurb }, // ldrb { 0b0111100101, 0b01111000010, 0b01111000011, 0 , kW , 0 , 1, Inst::kIdLdurh }, // ldrh - { 0b0011100111, 0b00111000100, 0b00111000101, 0 , kWX, 22, 0, Inst::kIdLdursb }, // ldrsb - { 0b0111100110, 0b01111000100, 0b01111000101, 0 , kWX, 22, 1, Inst::kIdLdursh }, // ldrsh + { 0b0011100111, 0b00111000100, 0b00111000111, 0 , kWX, 22, 0, Inst::kIdLdursb }, // ldrsb + { 0b0111100111, 0b01111000100, 0b01111000111, 0 , kWX, 22, 1, Inst::kIdLdursh }, // ldrsh { 0b1011100110, 0b10111000100, 0b10111000101, 0b10011000, kX , 0 , 2, Inst::kIdLdursw }, // ldrsw { 0b1011100100, 0b10111000000, 0b10111000001, 0 , kWX, 30, 2, Inst::kIdStur }, // str { 0b0011100100, 0b00111000000, 0b00111000001, 0 , kW , 30, 0, Inst::kIdSturb }, // strb @@ -1275,7 +1266,7 @@ const BaseRM_SImm9 baseRM_SImm9[23] = { { 0b0111100001000000000000, 0b0000000000000000000000, kW , kZR, 0 , 0 }, // ldurh { 0b0011100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0 }, // ldursb { 0b0111100011000000000000, 0b0000000000000000000000, kWX, kZR, 22, 0 }, // ldursh - { 0b1011100010000000000000, 0b0000000000000000000000, kWX, kZR, 0 , 0 }, // ldursw + { 0b1011100010000000000000, 0b0000000000000000000000, kX, kZR, 0 , 0 }, // ldursw { 0b1101100110100000000010, 0b1101100110100000000001, kX, kSP, 0, 4 }, // st2g { 0b1101100100100000000010, 0b1101100100100000000001, kX, kSP, 0, 4 }, // stg { 0b1011100000000000000010, 0b0000000000000000000000, kWX, kZR, 30, 0 }, // sttr @@ -1855,70 +1846,779 @@ const InstDB::CommonInfo InstDB::commonData[] = { #ifndef ASMJIT_DISABLE_TEXT // ${NameData:Begin} // ------------------- Automatically generated, do not edit ------------------- -const char InstDB::_nameData[] = - "\0" "adc\0" "adcs\0" "addg\0" "adds\0" "addv\0" "adr\0" "adrp\0" "aesd\0" "aese\0" "aesimc\0" "aesmc\0" "and\0" - "ands\0" "asr\0" "asrv\0" "at\0" "autda\0" "autdb\0" "autdza\0" "autdzb\0" "autia\0" "autia1716\0" "autiasp\0" - "autiaz\0" "autib\0" "autib1716\0" "autibsp\0" "autibz\0" "autiza\0" "autizb\0" "axflag\0" "bcax\0" "bfc\0" "bfcvt\0" - "bfcvtn\0" "bfcvtn2\0" "bfdot\0" "bfi\0" "bfmlalb\0" "bfmlalt\0" "bfmmla\0" "bfxil\0" "bic\0" "bics\0" "bif\0" - "blr\0" "br\0" "brk\0" "bsl\0" "cas\0" "casa\0" "casab\0" "casah\0" "casal\0" "casalb\0" "casalh\0" "casb\0" "cash\0" - "casl\0" "caslb\0" "caslh\0" "casp\0" "caspa\0" "caspal\0" "caspl\0" "cbnz\0" "cbz\0" "ccmn\0" "cfinv\0" "cinc\0" - "cinv\0" "clrex\0" "cls\0" "clz\0" "cmhi\0" "cmhs\0" "cmpp\0" "cmtst\0" "cneg\0" "cnt\0" "crc32b\0" "crc32cb\0" - "crc32ch\0" "crc32cw\0" "crc32cx\0" "crc32h\0" "crc32w\0" "crc32x\0" "csdb\0" "cset\0" "csetm\0" "csinc\0" "csinv\0" - "csneg\0" "dcps1\0" "dcps2\0" "dcps3\0" "dgh\0" "dmb\0" "drps\0" "dsb\0" "dup\0" "eon\0" "eor3\0" "eret\0" "esb\0" - "ext\0" "extr\0" "fabd\0" "fabs\0" "facge\0" "facgt\0" "fadd\0" "faddp\0" "fcadd\0" "fccmp\0" "fccmpe\0" "fcmeq\0" - "fcmge\0" "fcmgt\0" "fcmla\0" "fcmle\0" "fcmlt\0" "fcmp\0" "fcmpe\0" "fcsel\0" "fcvtas\0" "fcvtau\0" "fcvtl\0" - "fcvtl2\0" "fcvtms\0" "fcvtmu\0" "fcvtns\0" "fcvtnu\0" "fcvtps\0" "fcvtpu\0" "fcvtxn\0" "fcvtxn2\0" "fcvtzs\0" - "fcvtzu\0" "fdiv\0" "fjcvtzs\0" "fmadd\0" "fmax\0" "fmaxnm\0" "fmaxnmp\0" "fmaxnmv\0" "fmaxp\0" "fmaxv\0" "fmin\0" - "fminnm\0" "fminnmp\0" "fminnmv\0" "fminp\0" "fminv\0" "fmla\0" "fmlal\0" "fmlal2\0" "fmls\0" "fmlsl\0" "fmlsl2\0" - "fmov\0" "fmsub\0" "fmul\0" "fmulx\0" "fneg\0" "fnmadd\0" "fnmsub\0" "fnmul\0" "frecpe\0" "frecps\0" "frecpx\0" - "frint32x\0" "frint32z\0" "frint64x\0" "frint64z\0" "frinta\0" "frinti\0" "frintm\0" "frintn\0" "frintp\0" "frintx\0" - "frintz\0" "frsqrte\0" "frsqrts\0" "fsqrt\0" "fsub\0" "gmi\0" "hint\0" "hlt\0" "hvc\0" "ins\0" "isb\0" "ld1\0" - "ld1r\0" "ld2\0" "ld2r\0" "ld3\0" "ld3r\0" "ld4\0" "ld4r\0" "ldadd\0" "ldadda\0" "ldaddab\0" "ldaddah\0" "ldaddal\0" - "ldaddalb\0" "ldaddalh\0" "ldaddb\0" "ldaddh\0" "ldaddl\0" "ldaddlb\0" "ldaddlh\0" "ldar\0" "ldarb\0" "ldarh\0" - "ldaxp\0" "ldaxr\0" "ldaxrb\0" "ldaxrh\0" "ldclr\0" "ldclra\0" "ldclrab\0" "ldclrah\0" "ldclral\0" "ldclralb\0" - "ldclralh\0" "ldclrb\0" "ldclrh\0" "ldclrl\0" "ldclrlb\0" "ldclrlh\0" "ldeor\0" "ldeora\0" "ldeorab\0" "ldeorah\0" - "ldeoral\0" "ldeoralb\0" "ldeoralh\0" "ldeorb\0" "ldeorh\0" "ldeorl\0" "ldeorlb\0" "ldeorlh\0" "ldg\0" "ldgm\0" - "ldlar\0" "ldlarb\0" "ldlarh\0" "ldnp\0" "ldp\0" "ldpsw\0" "ldr\0" "ldraa\0" "ldrab\0" "ldrb\0" "ldrh\0" "ldrsb\0" - "ldrsh\0" "ldrsw\0" "ldset\0" "ldseta\0" "ldsetab\0" "ldsetah\0" "ldsetal\0" "ldsetalb\0" "ldsetalh\0" "ldsetb\0" - "ldseth\0" "ldsetl\0" "ldsetlb\0" "ldsetlh\0" "ldsmax\0" "ldsmaxa\0" "ldsmaxab\0" "ldsmaxah\0" "ldsmaxal\0" - "ldsmaxalb\0" "ldsmaxalh\0" "ldsmaxb\0" "ldsmaxh\0" "ldsmaxl\0" "ldsmaxlb\0" "ldsmaxlh\0" "ldsmin\0" "ldsmina\0" - "ldsminab\0" "ldsminah\0" "ldsminal\0" "ldsminalb\0" "ldsminalh\0" "ldsminb\0" "ldsminh\0" "ldsminl\0" "ldsminlb\0" - "ldsminlh\0" "ldtr\0" "ldtrb\0" "ldtrh\0" "ldtrsb\0" "ldtrsh\0" "ldtrsw\0" "ldumax\0" "ldumaxa\0" "ldumaxab\0" - "ldumaxah\0" "ldumaxal\0" "ldumaxalb\0" "ldumaxalh\0" "ldumaxb\0" "ldumaxh\0" "ldumaxl\0" "ldumaxlb\0" "ldumaxlh\0" - "ldumin\0" "ldumina\0" "lduminab\0" "lduminah\0" "lduminal\0" "lduminalb\0" "lduminalh\0" "lduminb\0" "lduminh\0" - "lduminl\0" "lduminlb\0" "lduminlh\0" "ldur\0" "ldurb\0" "ldurh\0" "ldursb\0" "ldursh\0" "ldursw\0" "ldxp\0" "ldxr\0" - "ldxrb\0" "ldxrh\0" "lslv\0" "lsr\0" "lsrv\0" "mneg\0" "movi\0" "movk\0" "movn\0" "movz\0" "mrs\0" "msr\0" "mvn\0" - "mvni\0" "negs\0" "ngc\0" "ngcs\0" "nop\0" "not\0" "orn\0" "orr\0" "pacda\0" "pacdb\0" "pacdza\0" "pacdzb\0" - "pacga\0" "pmul\0" "pmull\0" "pmull2\0" "pssbb\0" "raddhn\0" "raddhn2\0" "rax1\0" "rbit\0" "rev\0" "rev16\0" - "rev32\0" "rev64\0" "ror\0" "rorv\0" "rsubhn\0" "rsubhn2\0" "saba\0" "sabal\0" "sabal2\0" "sabd\0" "sabdl\0" - "sabdl2\0" "sadalp\0" "saddl\0" "saddl2\0" "saddlp\0" "saddlv\0" "saddw\0" "saddw2\0" "sbc\0" "sbcs\0" "sbfiz\0" - "sbfm\0" "sbfx\0" "scvtf\0" "sdiv\0" "setf16\0" "setf8\0" "sev\0" "sevl\0" "sha1c\0" "sha1h\0" "sha1m\0" "sha1p\0" - "sha1su0\0" "sha1su1\0" "sha256h\0" "sha256h2\0" "sha256su0\0" "sha256su1\0" "sha512h\0" "sha512h2\0" "sha512su0\0" - "sha512su1\0" "shadd\0" "shsub\0" "sli\0" "sm3partw1\0" "sm3partw2\0" "sm3ss1\0" "sm3tt1a\0" "sm3tt1b\0" "sm3tt2a\0" - "sm3tt2b\0" "sm4e\0" "sm4ekey\0" "smaddl\0" "smaxp\0" "smaxv\0" "sminp\0" "sminv\0" "smlal\0" "smlal2\0" "smlsl\0" - "smlsl2\0" "smnegl\0" "smov\0" "smsubl\0" "smulh\0" "smull\0" "smull2\0" "sqabs\0" "sqdmlal\0" "sqdmlal2\0" - "sqdmlsl\0" "sqdmlsl2\0" "sqdmulh\0" "sqdmull\0" "sqdmull2\0" "sqneg\0" "sqrdmlah\0" "sqrdmlsh\0" "sqrdmulh\0" - "sqrshl\0" "sqrshrn\0" "sqrshrn2\0" "sqrshrun\0" "sqrshrun2\0" "sqshl\0" "sqshlu\0" "sqshrn\0" "sqshrn2\0" - "sqshrun\0" "sqshrun2\0" "sqsub\0" "sqxtn\0" "sqxtn2\0" "sqxtun\0" "sqxtun2\0" "srhadd\0" "sri\0" "srshl\0" "srshr\0" - "srsra\0" "sshl\0" "sshll\0" "sshll2\0" "sshr\0" "ssra\0" "ssubl\0" "ssubl2\0" "ssubw\0" "ssubw2\0" "st1\0" "st2\0" - "st2g\0" "st3\0" "st4\0" "stadd\0" "staddb\0" "staddh\0" "staddl\0" "staddlb\0" "staddlh\0" "stclr\0" "stclrb\0" - "stclrh\0" "stclrl\0" "stclrlb\0" "stclrlh\0" "steor\0" "steorb\0" "steorh\0" "steorl\0" "steorlb\0" "steorlh\0" - "stg\0" "stgm\0" "stgp\0" "stllr\0" "stllrb\0" "stllrh\0" "stlr\0" "stlrb\0" "stlrh\0" "stlxp\0" "stlxr\0" "stlxrb\0" - "stlxrh\0" "stnp\0" "stp\0" "str\0" "strb\0" "strh\0" "stset\0" "stsetb\0" "stseth\0" "stsetl\0" "stsetlb\0" - "stsetlh\0" "stsmax\0" "stsmaxb\0" "stsmaxh\0" "stsmaxl\0" "stsmaxlb\0" "stsmaxlh\0" "stsmin\0" "stsminb\0" - "stsminh\0" "stsminl\0" "stsminlb\0" "stsminlh\0" "sttr\0" "sttrb\0" "sttrh\0" "stumax\0" "stumaxb\0" "stumaxh\0" - "stumaxl\0" "stumaxlb\0" "stumaxlh\0" "stumin\0" "stuminb\0" "stuminh\0" "stuminl\0" "stuminlb\0" "stuminlh\0" - "stur\0" "sturb\0" "sturh\0" "stxp\0" "stxr\0" "stxrb\0" "stxrh\0" "stz2g\0" "stzg\0" "stzgm\0" "subg\0" "subp\0" - "subps\0" "subs\0" "sudot\0" "suqadd\0" "svc\0" "swp\0" "swpa\0" "swpab\0" "swpah\0" "swpal\0" "swpalb\0" "swpalh\0" - "swpb\0" "swph\0" "swpl\0" "swplb\0" "swplh\0" "sxtb\0" "sxth\0" "sxtl\0" "sxtl2\0" "sxtw\0" "sys\0" "tbl\0" "tbnz\0" - "tbx\0" "tbz\0" "tlbi\0" "trn1\0" "trn2\0" "uaba\0" "uabal\0" "uabal2\0" "uabd\0" "uabdl\0" "uabdl2\0" "uadalp\0" - "uaddl\0" "uaddl2\0" "uaddlp\0" "uaddlv\0" "uaddw\0" "uaddw2\0" "ubfiz\0" "ubfm\0" "ubfx\0" "ucvtf\0" "udf\0" - "udiv\0" "uhadd\0" "uhsub\0" "umaddl\0" "umaxp\0" "umaxv\0" "uminp\0" "uminv\0" "umlal\0" "umlal2\0" "umlsl\0" - "umlsl2\0" "ummla\0" "umnegl\0" "umov\0" "umsubl\0" "umulh\0" "umull\0" "umull2\0" "uqrshl\0" "uqrshrn\0" - "uqrshrn2\0" "uqshl\0" "uqshrn\0" "uqshrn2\0" "uqsub\0" "uqxtn\0" "uqxtn2\0" "urecpe\0" "urhadd\0" "urshl\0" - "urshr\0" "ursqrte\0" "ursra\0" "usdot\0" "ushl\0" "ushll\0" "ushll2\0" "ushr\0" "usmmla\0" "usqadd\0" "usra\0" - "usubl\0" "usubl2\0" "usubw\0" "usubw2\0" "uxtb\0" "uxth\0" "uxtl\0" "uxtl2\0" "uzp1\0" "uzp2\0" "wfe\0" "wfi\0" - "xaflag\0" "xar\0" "xpacd\0" "xpaci\0" "xpaclri\0" "yield\0" "zip1\0" "zip2"; +const uint32_t InstDB::_instNameIndexTable[] = { + 0x80000000, // Small ''. + 0x80000C81, // Small 'adc'. + 0x80098C81, // Small 'adcs'. + 0x80001081, // Small 'add'. + 0x80039081, // Small 'addg'. + 0x80099081, // Small 'adds'. + 0x80004881, // Small 'adr'. + 0x80084881, // Small 'adrp'. + 0x800011C1, // Small 'and'. + 0x800991C1, // Small 'ands'. + 0x80004A61, // Small 'asr'. + 0x800B4A61, // Small 'asrv'. + 0x80000281, // Small 'at'. + 0x801252A1, // Small 'autda'. + 0x83A252A1, // Small 'autdza'. + 0x802252A1, // Small 'autdb'. + 0x85A252A1, // Small 'autdzb'. + 0x8014D2A1, // Small 'autia'. + 0x00009000, // Large 'autia1716'. + 0x20BF5000, // Large 'autia|sp'. + 0xB414D2A1, // Small 'autiaz'. + 0x8024D2A1, // Small 'autib'. + 0x40055009, // Large 'autib|1716'. + 0x20BF5009, // Large 'autib|sp'. + 0xB424D2A1, // Small 'autibz'. + 0x83A4D2A1, // Small 'autiza'. + 0x85A4D2A1, // Small 'autizb'. + 0x8E161B01, // Small 'axflag'. + 0x80000002, // Small 'b'. + 0x80000CC2, // Small 'bfc'. + 0x800024C2, // Small 'bfi'. + 0x800034C2, // Small 'bfm'. + 0x80C4E0C2, // Small 'bfxil'. + 0x80000D22, // Small 'bic'. + 0x80098D22, // Small 'bics'. + 0x80000182, // Small 'bl'. + 0x80004982, // Small 'blr'. + 0x80000242, // Small 'br'. + 0x80002E42, // Small 'brk'. + 0x80004C23, // Small 'cas'. + 0x8000CC23, // Small 'casa'. + 0x8020CC23, // Small 'casab'. + 0x8080CC23, // Small 'casah'. + 0x80C0CC23, // Small 'casal'. + 0x84C0CC23, // Small 'casalb'. + 0x90C0CC23, // Small 'casalh'. + 0x80014C23, // Small 'casb'. + 0x80044C23, // Small 'cash'. + 0x80064C23, // Small 'casl'. + 0x80264C23, // Small 'caslb'. + 0x80864C23, // Small 'caslh'. + 0x80084C23, // Small 'casp'. + 0x80184C23, // Small 'caspa'. + 0x98184C23, // Small 'caspal'. + 0x80C84C23, // Small 'caspl'. + 0x800D3843, // Small 'cbnz'. + 0x80006843, // Small 'cbz'. + 0x80073463, // Small 'ccmn'. + 0x80083463, // Small 'ccmp'. + 0x816724C3, // Small 'cfinv'. + 0x8001B923, // Small 'cinc'. + 0x800B3923, // Small 'cinv'. + 0x8182C983, // Small 'clrex'. + 0x80004D83, // Small 'cls'. + 0x80006983, // Small 'clz'. + 0x800039A3, // Small 'cmn'. + 0x800041A3, // Small 'cmp'. + 0x800841A3, // Small 'cmpp'. + 0x800395C3, // Small 'cneg'. + 0x85DF0E43, // Small 'crc32b'. + 0x100D60C1, // Large 'crc32c|b'. + 0x101660C1, // Large 'crc32c|h'. + 0x104860C1, // Large 'crc32c|w'. + 0x101360C1, // Large 'crc32c|x'. + 0x91DF0E43, // Small 'crc32h'. + 0xAFDF0E43, // Small 'crc32w'. + 0xB1DF0E43, // Small 'crc32x'. + 0x80011263, // Small 'csdb'. + 0x80061663, // Small 'csel'. + 0x800A1663, // Small 'cset'. + 0x80DA1663, // Small 'csetm'. + 0x80372663, // Small 'csinc'. + 0x81672663, // Small 'csinv'. + 0x8072BA63, // Small 'csneg'. + 0x80000064, // Small 'dc'. + 0x81C9C064, // Small 'dcps1'. + 0x81D9C064, // Small 'dcps2'. + 0x81E9C064, // Small 'dcps3'. + 0x800020E4, // Small 'dgh'. + 0x800009A4, // Small 'dmb'. + 0x8009C244, // Small 'drps'. + 0x80000A64, // Small 'dsb'. + 0x800039E5, // Small 'eon'. + 0x800049E5, // Small 'eor'. + 0x80000A65, // Small 'esb'. + 0x80095305, // Small 'extr'. + 0x800A1645, // Small 'eret'. + 0x800025A7, // Small 'gmi'. + 0x800A3928, // Small 'hint'. + 0x80005188, // Small 'hlt'. + 0x80000EC8, // Small 'hvc'. + 0x80000069, // Small 'ic'. + 0x80000A69, // Small 'isb'. + 0x8042048C, // Small 'ldadd'. + 0x8242048C, // Small 'ldadda'. + 0x100D6051, // Large 'ldadda|b'. + 0x10166051, // Large 'ldadda|h'. + 0x00007051, // Large 'ldaddal'. + 0x100D7051, // Large 'ldaddal|b'. + 0x10167051, // Large 'ldaddal|h'. + 0x8442048C, // Small 'ldaddb'. + 0x9042048C, // Small 'ldaddh'. + 0x9842048C, // Small 'ldaddl'. + 0x206D5051, // Large 'ldadd|lb'. + 0x20155051, // Large 'ldadd|lh'. + 0x8009048C, // Small 'ldar'. + 0x8029048C, // Small 'ldarb'. + 0x8089048C, // Small 'ldarh'. + 0x810C048C, // Small 'ldaxp'. + 0x812C048C, // Small 'ldaxr'. + 0x852C048C, // Small 'ldaxrb'. + 0x912C048C, // Small 'ldaxrh'. + 0x81260C8C, // Small 'ldclr'. + 0x83260C8C, // Small 'ldclra'. + 0x100D6058, // Large 'ldclra|b'. + 0x10166058, // Large 'ldclra|h'. + 0x00007058, // Large 'ldclral'. + 0x100D7058, // Large 'ldclral|b'. + 0x10167058, // Large 'ldclral|h'. + 0x85260C8C, // Small 'ldclrb'. + 0x91260C8C, // Small 'ldclrh'. + 0x99260C8C, // Small 'ldclrl'. + 0x206D5058, // Large 'ldclr|lb'. + 0x20155058, // Large 'ldclr|lh'. + 0x8127948C, // Small 'ldeor'. + 0x8327948C, // Small 'ldeora'. + 0x100D605F, // Large 'ldeora|b'. + 0x1016605F, // Large 'ldeora|h'. + 0x0000705F, // Large 'ldeoral'. + 0x100D705F, // Large 'ldeoral|b'. + 0x1016705F, // Large 'ldeoral|h'. + 0x8527948C, // Small 'ldeorb'. + 0x9127948C, // Small 'ldeorh'. + 0x9927948C, // Small 'ldeorl'. + 0x206D505F, // Large 'ldeor|lb'. + 0x2015505F, // Large 'ldeor|lh'. + 0x80001C8C, // Small 'ldg'. + 0x80069C8C, // Small 'ldgm'. + 0x8120B08C, // Small 'ldlar'. + 0x8520B08C, // Small 'ldlarb'. + 0x9120B08C, // Small 'ldlarh'. + 0x8008388C, // Small 'ldnp'. + 0x8000408C, // Small 'ldp'. + 0x8179C08C, // Small 'ldpsw'. + 0x8000488C, // Small 'ldr'. + 0x8010C88C, // Small 'ldraa'. + 0x8020C88C, // Small 'ldrab'. + 0x8001488C, // Small 'ldrb'. + 0x8004488C, // Small 'ldrh'. + 0x8029C88C, // Small 'ldrsb'. + 0x8089C88C, // Small 'ldrsh'. + 0x8179C88C, // Small 'ldrsw'. + 0x8142CC8C, // Small 'ldset'. + 0x8342CC8C, // Small 'ldseta'. + 0x100D6066, // Large 'ldseta|b'. + 0x10166066, // Large 'ldseta|h'. + 0x00007066, // Large 'ldsetal'. + 0x100D7066, // Large 'ldsetal|b'. + 0x10167066, // Large 'ldsetal|h'. + 0x8542CC8C, // Small 'ldsetb'. + 0x9142CC8C, // Small 'ldseth'. + 0x9942CC8C, // Small 'ldsetl'. + 0x206D5066, // Large 'ldset|lb'. + 0x20155066, // Large 'ldset|lh'. + 0xB016CC8C, // Small 'ldsmax'. + 0x0000700E, // Large 'ldsmaxa'. + 0x100D700E, // Large 'ldsmaxa|b'. + 0x1016700E, // Large 'ldsmaxa|h'. + 0x0000800E, // Large 'ldsmaxal'. + 0x100D800E, // Large 'ldsmaxal|b'. + 0x1016800E, // Large 'ldsmaxal|h'. + 0x100D600E, // Large 'ldsmax|b'. + 0x1016600E, // Large 'ldsmax|h'. + 0x100E600E, // Large 'ldsmax|l'. + 0x206D600E, // Large 'ldsmax|lb'. + 0x2015600E, // Large 'ldsmax|lh'. + 0x9C96CC8C, // Small 'ldsmin'. + 0x00007017, // Large 'ldsmina'. + 0x100D7017, // Large 'ldsmina|b'. + 0x10167017, // Large 'ldsmina|h'. + 0x00008017, // Large 'ldsminal'. + 0x100D8017, // Large 'ldsminal|b'. + 0x10168017, // Large 'ldsminal|h'. + 0x100D6017, // Large 'ldsmin|b'. + 0x10166017, // Large 'ldsmin|h'. + 0x100E6017, // Large 'ldsmin|l'. + 0x206D6017, // Large 'ldsmin|lb'. + 0x20156017, // Large 'ldsmin|lh'. + 0x8009508C, // Small 'ldtr'. + 0x8029508C, // Small 'ldtrb'. + 0x8089508C, // Small 'ldtrh'. + 0x8539508C, // Small 'ldtrsb'. + 0x9139508C, // Small 'ldtrsh'. + 0xAF39508C, // Small 'ldtrsw'. + 0xB016D48C, // Small 'ldumax'. + 0x0000701F, // Large 'ldumaxa'. + 0x100D701F, // Large 'ldumaxa|b'. + 0x1016701F, // Large 'ldumaxa|h'. + 0x0000801F, // Large 'ldumaxal'. + 0x100D801F, // Large 'ldumaxal|b'. + 0x1016801F, // Large 'ldumaxal|h'. + 0x100D601F, // Large 'ldumax|b'. + 0x1016601F, // Large 'ldumax|h'. + 0x100E601F, // Large 'ldumax|l'. + 0x206D601F, // Large 'ldumax|lb'. + 0x2015601F, // Large 'ldumax|lh'. + 0x9C96D48C, // Small 'ldumin'. + 0x00007027, // Large 'ldumina'. + 0x100D7027, // Large 'ldumina|b'. + 0x10167027, // Large 'ldumina|h'. + 0x00008027, // Large 'lduminal'. + 0x100D8027, // Large 'lduminal|b'. + 0x10168027, // Large 'lduminal|h'. + 0x100D6027, // Large 'ldumin|b'. + 0x10166027, // Large 'ldumin|h'. + 0x100E6027, // Large 'ldumin|l'. + 0x206D6027, // Large 'ldumin|lb'. + 0x20156027, // Large 'ldumin|lh'. + 0x8009548C, // Small 'ldur'. + 0x8029548C, // Small 'ldurb'. + 0x8089548C, // Small 'ldurh'. + 0x8539548C, // Small 'ldursb'. + 0x9139548C, // Small 'ldursh'. + 0xAF39548C, // Small 'ldursw'. + 0x8008608C, // Small 'ldxp'. + 0x8009608C, // Small 'ldxr'. + 0x8029608C, // Small 'ldxrb'. + 0x8089608C, // Small 'ldxrh'. + 0x8000326C, // Small 'lsl'. + 0x800B326C, // Small 'lslv'. + 0x80004A6C, // Small 'lsr'. + 0x800B4A6C, // Small 'lsrv'. + 0x8002102D, // Small 'madd'. + 0x800395CD, // Small 'mneg'. + 0x800059ED, // Small 'mov'. + 0x8005D9ED, // Small 'movk'. + 0x800759ED, // Small 'movn'. + 0x800D59ED, // Small 'movz'. + 0x80004E4D, // Small 'mrs'. + 0x80004A6D, // Small 'msr'. + 0x8001566D, // Small 'msub'. + 0x800032AD, // Small 'mul'. + 0x80003ACD, // Small 'mvn'. + 0x80001CAE, // Small 'neg'. + 0x80099CAE, // Small 'negs'. + 0x80000CEE, // Small 'ngc'. + 0x80098CEE, // Small 'ngcs'. + 0x800041EE, // Small 'nop'. + 0x80003A4F, // Small 'orn'. + 0x80004A4F, // Small 'orr'. + 0x80120C30, // Small 'pacda'. + 0x80220C30, // Small 'pacdb'. + 0x83A20C30, // Small 'pacdza'. + 0x85A20C30, // Small 'pacdzb'. + 0x80138C30, // Small 'pacga'. + 0x80214E70, // Small 'pssbb'. + 0x800A2452, // Small 'rbit'. + 0x800050B2, // Small 'ret'. + 0x800058B2, // Small 'rev'. + 0x20073138, // Large 'rev|16'. + 0x81DF58B2, // Small 'rev32'. + 0x208F3138, // Large 'rev|64'. + 0x800049F2, // Small 'ror'. + 0x800B49F2, // Small 'rorv'. + 0x80000C53, // Small 'sbc'. + 0x80098C53, // Small 'sbcs'. + 0x81A49853, // Small 'sbfiz'. + 0x80069853, // Small 'sbfm'. + 0x800C1853, // Small 'sbfx'. + 0x800B2493, // Small 'sdiv'. + 0x113B4134, // Large 'setf|8'. + 0x20074134, // Large 'setf|16'. + 0x800058B3, // Small 'sev'. + 0x800658B3, // Small 'sevl'. + 0x984205B3, // Small 'smaddl'. + 0x80000DB3, // Small 'smc'. + 0x9872B9B3, // Small 'smnegl'. + 0x982ACDB3, // Small 'smsubl'. + 0x808655B3, // Small 'smulh'. + 0x80C655B3, // Small 'smull'. + 0x80010A73, // Small 'ssbb'. + 0x8003F693, // Small 'st2g'. + 0x80420693, // Small 'stadd'. + 0x98420693, // Small 'staddl'. + 0x84420693, // Small 'staddb'. + 0x206D50C7, // Large 'stadd|lb'. + 0x90420693, // Small 'staddh'. + 0x201550C7, // Large 'stadd|lh'. + 0x81260E93, // Small 'stclr'. + 0x99260E93, // Small 'stclrl'. + 0x85260E93, // Small 'stclrb'. + 0x206D50CC, // Large 'stclr|lb'. + 0x91260E93, // Small 'stclrh'. + 0x201550CC, // Large 'stclr|lh'. + 0x81279693, // Small 'steor'. + 0x99279693, // Small 'steorl'. + 0x85279693, // Small 'steorb'. + 0x206D50D1, // Large 'steor|lb'. + 0x91279693, // Small 'steorh'. + 0x201550D1, // Large 'steor|lh'. + 0x80001E93, // Small 'stg'. + 0x80069E93, // Small 'stgm'. + 0x80081E93, // Small 'stgp'. + 0x81263293, // Small 'stllr'. + 0x85263293, // Small 'stllrb'. + 0x91263293, // Small 'stllrh'. + 0x80093293, // Small 'stlr'. + 0x80293293, // Small 'stlrb'. + 0x80893293, // Small 'stlrh'. + 0x810C3293, // Small 'stlxp'. + 0x812C3293, // Small 'stlxr'. + 0x852C3293, // Small 'stlxrb'. + 0x912C3293, // Small 'stlxrh'. + 0x80083A93, // Small 'stnp'. + 0x80004293, // Small 'stp'. + 0x80004A93, // Small 'str'. + 0x80014A93, // Small 'strb'. + 0x80044A93, // Small 'strh'. + 0x8142CE93, // Small 'stset'. + 0x9942CE93, // Small 'stsetl'. + 0x8542CE93, // Small 'stsetb'. + 0x206D50D6, // Large 'stset|lb'. + 0x9142CE93, // Small 'stseth'. + 0x201550D6, // Large 'stset|lh'. + 0xB016CE93, // Small 'stsmax'. + 0x100E606F, // Large 'stsmax|l'. + 0x100D606F, // Large 'stsmax|b'. + 0x206D606F, // Large 'stsmax|lb'. + 0x1016606F, // Large 'stsmax|h'. + 0x2015606F, // Large 'stsmax|lh'. + 0x9C96CE93, // Small 'stsmin'. + 0x100E6075, // Large 'stsmin|l'. + 0x100D6075, // Large 'stsmin|b'. + 0x206D6075, // Large 'stsmin|lb'. + 0x10166075, // Large 'stsmin|h'. + 0x20156075, // Large 'stsmin|lh'. + 0x80095293, // Small 'sttr'. + 0x80295293, // Small 'sttrb'. + 0x80895293, // Small 'sttrh'. + 0xB016D693, // Small 'stumax'. + 0x100E607B, // Large 'stumax|l'. + 0x100D607B, // Large 'stumax|b'. + 0x206D607B, // Large 'stumax|lb'. + 0x1016607B, // Large 'stumax|h'. + 0x2015607B, // Large 'stumax|lh'. + 0x9C96D693, // Small 'stumin'. + 0x100E6081, // Large 'stumin|l'. + 0x100D6081, // Large 'stumin|b'. + 0x206D6081, // Large 'stumin|lb'. + 0x10166081, // Large 'stumin|h'. + 0x20156081, // Large 'stumin|lh'. + 0x80095693, // Small 'stur'. + 0x80295693, // Small 'sturb'. + 0x80895693, // Small 'sturh'. + 0x80086293, // Small 'stxp'. + 0x80096293, // Small 'stxr'. + 0x80296293, // Small 'stxrb'. + 0x80896293, // Small 'stxrh'. + 0x807EEA93, // Small 'stz2g'. + 0x8003EA93, // Small 'stzg'. + 0x80D3EA93, // Small 'stzgm'. + 0x80000AB3, // Small 'sub'. + 0x80038AB3, // Small 'subg'. + 0x80080AB3, // Small 'subp'. + 0x81380AB3, // Small 'subps'. + 0x80098AB3, // Small 'subs'. + 0x80000ED3, // Small 'svc'. + 0x800042F3, // Small 'swp'. + 0x8000C2F3, // Small 'swpa'. + 0x8020C2F3, // Small 'swpab'. + 0x8080C2F3, // Small 'swpah'. + 0x80C0C2F3, // Small 'swpal'. + 0x84C0C2F3, // Small 'swpalb'. + 0x90C0C2F3, // Small 'swpalh'. + 0x800142F3, // Small 'swpb'. + 0x800442F3, // Small 'swph'. + 0x800642F3, // Small 'swpl'. + 0x802642F3, // Small 'swplb'. + 0x808642F3, // Small 'swplh'. + 0x80015313, // Small 'sxtb'. + 0x80045313, // Small 'sxth'. + 0x800BD313, // Small 'sxtw'. + 0x80004F33, // Small 'sys'. + 0x80048994, // Small 'tlbi'. + 0x80005274, // Small 'tst'. + 0x800D3854, // Small 'tbnz'. + 0x80006854, // Small 'tbz'. + 0x81A49855, // Small 'ubfiz'. + 0x80069855, // Small 'ubfm'. + 0x800C1855, // Small 'ubfx'. + 0x80001895, // Small 'udf'. + 0x800B2495, // Small 'udiv'. + 0x984205B5, // Small 'umaddl'. + 0x9872B9B5, // Small 'umnegl'. + 0x80C655B5, // Small 'umull'. + 0x808655B5, // Small 'umulh'. + 0x982ACDB5, // Small 'umsubl'. + 0x80015315, // Small 'uxtb'. + 0x80045315, // Small 'uxth'. + 0x800014D7, // Small 'wfe'. + 0x800024D7, // Small 'wfi'. + 0x8E161838, // Small 'xaflag'. + 0x80418618, // Small 'xpacd'. + 0x80918618, // Small 'xpaci'. + 0x208850DB, // Large 'xpacl|ri'. + 0x80461539, // Small 'yield'. + 0x80004C41, // Small 'abs'. + 0x80001081, // Small 'add'. + 0x80E41081, // Small 'addhn'. + 0xBAE41081, // Small 'addhn2'. + 0x80081081, // Small 'addp'. + 0x800B1081, // Small 'addv'. + 0x80024CA1, // Small 'aesd'. + 0x8002CCA1, // Small 'aese'. + 0x86D4CCA1, // Small 'aesimc'. + 0x8036CCA1, // Small 'aesmc'. + 0x800011C1, // Small 'and'. + 0x800C0462, // Small 'bcax'. + 0x814B0CC2, // Small 'bfcvt'. + 0x9D4B0CC2, // Small 'bfcvtn'. + 0x20B150E0, // Large 'bfcvt|n2'. + 0x814790C2, // Small 'bfdot'. + 0x206D50E5, // Large 'bfmla|lb'. + 0x20EA50E5, // Large 'bfmla|lt'. + 0x82C6B4C2, // Small 'bfmmla'. + 0x80000D22, // Small 'bic'. + 0x80001922, // Small 'bif'. + 0x80005122, // Small 'bit'. + 0x80003262, // Small 'bsl'. + 0x80004D83, // Small 'cls'. + 0x80006983, // Small 'clz'. + 0x800895A3, // Small 'cmeq'. + 0x80029DA3, // Small 'cmge'. + 0x800A1DA3, // Small 'cmgt'. + 0x8004A1A3, // Small 'cmhi'. + 0x8009A1A3, // Small 'cmhs'. + 0x8002B1A3, // Small 'cmle'. + 0x800A31A3, // Small 'cmlt'. + 0x8149D1A3, // Small 'cmtst'. + 0x800051C3, // Small 'cnt'. + 0x800042A4, // Small 'dup'. + 0x800049E5, // Small 'eor'. + 0x800F49E5, // Small 'eor3'. + 0x80005305, // Small 'ext'. + 0x80020826, // Small 'fabd'. + 0x80098826, // Small 'fabs'. + 0x80538C26, // Small 'facge'. + 0x81438C26, // Small 'facgt'. + 0x80021026, // Small 'fadd'. + 0x81021026, // Small 'faddp'. + 0x80420466, // Small 'fcadd'. + 0x81068C66, // Small 'fccmp'. + 0x8B068C66, // Small 'fccmpe'. + 0x8112B466, // Small 'fcmeq'. + 0x8053B466, // Small 'fcmge'. + 0x8143B466, // Small 'fcmgt'. + 0x80163466, // Small 'fcmla'. + 0x80563466, // Small 'fcmle'. + 0x81463466, // Small 'fcmlt'. + 0x80083466, // Small 'fcmp'. + 0x80583466, // Small 'fcmpe'. + 0x80C2CC66, // Small 'fcsel'. + 0x800A5866, // Small 'fcvt'. + 0xA61A5866, // Small 'fcvtas'. + 0xAA1A5866, // Small 'fcvtau'. + 0x80CA5866, // Small 'fcvtl'. + 0xBACA5866, // Small 'fcvtl2'. + 0xA6DA5866, // Small 'fcvtms'. + 0xAADA5866, // Small 'fcvtmu'. + 0x80EA5866, // Small 'fcvtn'. + 0xBAEA5866, // Small 'fcvtn2'. + 0xA6EA5866, // Small 'fcvtns'. + 0xAAEA5866, // Small 'fcvtnu'. + 0xA70A5866, // Small 'fcvtps'. + 0xAB0A5866, // Small 'fcvtpu'. + 0x9D8A5866, // Small 'fcvtxn'. + 0x20B150EC, // Large 'fcvtx|n2'. + 0xA7AA5866, // Small 'fcvtzs'. + 0xABAA5866, // Small 'fcvtzu'. + 0x800B2486, // Small 'fdiv'. + 0x101060F1, // Large 'fjcvtz|s'. + 0x804205A6, // Small 'fmadd'. + 0x800C05A6, // Small 'fmax'. + 0x9AEC05A6, // Small 'fmaxnm'. + 0x104460F7, // Large 'fmaxnm|p'. + 0x10E360F7, // Large 'fmaxnm|v'. + 0x810C05A6, // Small 'fmaxp'. + 0x816C05A6, // Small 'fmaxv'. + 0x800725A6, // Small 'fmin'. + 0x9AE725A6, // Small 'fminnm'. + 0x104460FD, // Large 'fminnm|p'. + 0x10E360FD, // Large 'fminnm|v'. + 0x810725A6, // Small 'fminp'. + 0x816725A6, // Small 'fminv'. + 0x8000B1A6, // Small 'fmla'. + 0x80C0B1A6, // Small 'fmlal'. + 0xBAC0B1A6, // Small 'fmlal2'. + 0x8009B1A6, // Small 'fmls'. + 0x80C9B1A6, // Small 'fmlsl'. + 0xBAC9B1A6, // Small 'fmlsl2'. + 0x800B3DA6, // Small 'fmov'. + 0x802ACDA6, // Small 'fmsub'. + 0x800655A6, // Small 'fmul'. + 0x818655A6, // Small 'fmulx'. + 0x800395C6, // Small 'fneg'. + 0x8840B5C6, // Small 'fnmadd'. + 0x8559B5C6, // Small 'fnmsub'. + 0x80CAB5C6, // Small 'fnmul'. + 0x8B019646, // Small 'frecpe'. + 0xA7019646, // Small 'frecps'. + 0xB1019646, // Small 'frecpx'. + 0x10137087, // Large 'frint32|x'. + 0x108E7087, // Large 'frint32|z'. + 0x308F5087, // Large 'frint|64x'. + 0x30925087, // Large 'frint|64z'. + 0x83472646, // Small 'frinta'. + 0x93472646, // Small 'frinti'. + 0x9B472646, // Small 'frintm'. + 0x9D472646, // Small 'frintn'. + 0xA1472646, // Small 'frintp'. + 0xB1472646, // Small 'frintx'. + 0xB5472646, // Small 'frintz'. + 0x20D25103, // Large 'frsqr|te'. + 0x20705103, // Large 'frsqr|ts'. + 0x81494666, // Small 'fsqrt'. + 0x80015666, // Small 'fsub'. + 0x80004DC9, // Small 'ins'. + 0x8000708C, // Small 'ld1'. + 0x8009708C, // Small 'ld1r'. + 0x8000748C, // Small 'ld2'. + 0x8009748C, // Small 'ld2r'. + 0x8000788C, // Small 'ld3'. + 0x8009788C, // Small 'ld3r'. + 0x80007C8C, // Small 'ld4'. + 0x80097C8C, // Small 'ld4r'. + 0x8008388C, // Small 'ldnp'. + 0x8000408C, // Small 'ldp'. + 0x8000488C, // Small 'ldr'. + 0x8009548C, // Small 'ldur'. + 0x8000058D, // Small 'mla'. + 0x80004D8D, // Small 'mls'. + 0x800059ED, // Small 'mov'. + 0x8004D9ED, // Small 'movi'. + 0x800032AD, // Small 'mul'. + 0x80003ACD, // Small 'mvn'. + 0x8004BACD, // Small 'mvni'. + 0x80001CAE, // Small 'neg'. + 0x800051EE, // Small 'not'. + 0x80003A4F, // Small 'orn'. + 0x80004A4F, // Small 'orr'. + 0x800655B0, // Small 'pmul'. + 0x80C655B0, // Small 'pmull'. + 0xBAC655B0, // Small 'pmull2'. + 0x9C821032, // Small 'raddhn'. + 0x30B04108, // Large 'radd|hn2'. + 0x800E6032, // Small 'rax1'. + 0x800A2452, // Small 'rbit'. + 0x20073138, // Large 'rev|16'. + 0x81DF58B2, // Small 'rev32'. + 0x208F3138, // Large 'rev|64'. + 0x80E92272, // Small 'rshrn'. + 0xBAE92272, // Small 'rshrn2'. + 0x9C815672, // Small 'rsubhn'. + 0x30B0410C, // Large 'rsub|hn2'. + 0x80008833, // Small 'saba'. + 0x80C08833, // Small 'sabal'. + 0xBAC08833, // Small 'sabal2'. + 0x80020833, // Small 'sabd'. + 0x80C20833, // Small 'sabdl'. + 0xBAC20833, // Small 'sabdl2'. + 0xA0C09033, // Small 'sadalp'. + 0x80C21033, // Small 'saddl'. + 0xBAC21033, // Small 'saddl2'. + 0xA0C21033, // Small 'saddlp'. + 0xACC21033, // Small 'saddlv'. + 0x81721033, // Small 'saddw'. + 0xBB721033, // Small 'saddw2'. + 0x806A5873, // Small 'scvtf'. + 0x800A3C93, // Small 'sdot'. + 0x803E0513, // Small 'sha1c'. + 0x808E0513, // Small 'sha1h'. + 0x80DE0513, // Small 'sha1m'. + 0x810E0513, // Small 'sha1p'. + 0x30354110, // Large 'sha1|su0'. + 0x303E4110, // Large 'sha1|su1'. + 0x1016602F, // Large 'sha256|h'. + 0x2095602F, // Large 'sha256|h2'. + 0x0000902F, // Large 'sha256su0'. + 0x1005802F, // Large 'sha256su|1'. + 0x10166038, // Large 'sha512|h'. + 0x20956038, // Large 'sha512|h2'. + 0x30356038, // Large 'sha512|su0'. + 0x303E6038, // Large 'sha512|su1'. + 0x80420513, // Small 'shadd'. + 0x80003113, // Small 'shl'. + 0x80063113, // Small 'shll'. + 0x81D63113, // Small 'shll2'. + 0x80074913, // Small 'shrn'. + 0x81D74913, // Small 'shrn2'. + 0x802ACD13, // Small 'shsub'. + 0x80002593, // Small 'sli'. + 0x10058041, // Large 'sm3partw|1'. + 0x10328041, // Large 'sm3partw|2'. + 0xB939F9B3, // Small 'sm3ss1'. + 0x10006114, // Large 'sm3tt1|a'. + 0x100D6114, // Large 'sm3tt1|b'. + 0x211A5114, // Large 'sm3tt|2a'. + 0x211C5114, // Large 'sm3tt|2b'. + 0x8002FDB3, // Small 'sm4e'. + 0x0000711E, // Large 'sm4ekey'. + 0x800C05B3, // Small 'smax'. + 0x810C05B3, // Small 'smaxp'. + 0x816C05B3, // Small 'smaxv'. + 0x800725B3, // Small 'smin'. + 0x810725B3, // Small 'sminp'. + 0x816725B3, // Small 'sminv'. + 0x80C0B1B3, // Small 'smlal'. + 0xBAC0B1B3, // Small 'smlal2'. + 0x80C9B1B3, // Small 'smlsl'. + 0xBAC9B1B3, // Small 'smlsl2'. + 0x801635B3, // Small 'smmla'. + 0x800B3DB3, // Small 'smov'. + 0x80C655B3, // Small 'smull'. + 0xBAC655B3, // Small 'smull2'. + 0x81310633, // Small 'sqabs'. + 0x80420633, // Small 'sqadd'. + 0x00007097, // Large 'sqdmlal'. + 0x10327097, // Large 'sqdmlal|2'. + 0x209E5097, // Large 'sqdml|sl'. + 0x309E5097, // Large 'sqdml|sl2'. + 0x101660A1, // Large 'sqdmul|h'. + 0x100E60A1, // Large 'sqdmul|l'. + 0x209F60A1, // Large 'sqdmul|l2'. + 0x8072BA33, // Small 'sqneg'. + 0x101670A7, // Large 'sqrdmla|h'. + 0x202F60A7, // Large 'sqrdml|sh'. + 0x30AE50A7, // Large 'sqrdm|ulh'. + 0x9889CA33, // Small 'sqrshl'. + 0x101C6049, // Large 'sqrshr|n'. + 0x20B16049, // Large 'sqrshr|n2'. + 0x00008049, // Large 'sqrshrun'. + 0x10328049, // Large 'sqrshrun|2'. + 0x80C44E33, // Small 'sqshl'. + 0xAAC44E33, // Small 'sqshlu'. + 0x9D244E33, // Small 'sqshrn'. + 0x20B150B3, // Large 'sqshr|n2'. + 0x101C60B3, // Large 'sqshru|n'. + 0x20B160B3, // Large 'sqshru|n2'. + 0x802ACE33, // Small 'sqsub'. + 0x80EA6233, // Small 'sqxtn'. + 0xBAEA6233, // Small 'sqxtn2'. + 0x9D5A6233, // Small 'sqxtun'. + 0x20B15125, // Large 'sqxtu|n2'. + 0x8840A253, // Small 'srhadd'. + 0x80002653, // Small 'sri'. + 0x80C44E53, // Small 'srshl'. + 0x81244E53, // Small 'srshr'. + 0x80194E53, // Small 'srsra'. + 0x80062273, // Small 'sshl'. + 0x80C62273, // Small 'sshll'. + 0xBAC62273, // Small 'sshll2'. + 0x80092273, // Small 'sshr'. + 0x8000CA73, // Small 'ssra'. + 0x80C15673, // Small 'ssubl'. + 0xBAC15673, // Small 'ssubl2'. + 0x81715673, // Small 'ssubw'. + 0xBB715673, // Small 'ssubw2'. + 0x80007293, // Small 'st1'. + 0x80007693, // Small 'st2'. + 0x80007A93, // Small 'st3'. + 0x80007E93, // Small 'st4'. + 0x80083A93, // Small 'stnp'. + 0x80004293, // Small 'stp'. + 0x80004A93, // Small 'str'. + 0x80095693, // Small 'stur'. + 0x80000AB3, // Small 'sub'. + 0x80E40AB3, // Small 'subhn'. + 0xBAE40AB3, // Small 'subhn2'. + 0x814792B3, // Small 'sudot'. + 0x8840C6B3, // Small 'suqadd'. + 0x80065313, // Small 'sxtl'. + 0x81D65313, // Small 'sxtl2'. + 0x80003054, // Small 'tbl'. + 0x80006054, // Small 'tbx'. + 0x800E3A54, // Small 'trn1'. + 0x800EBA54, // Small 'trn2'. + 0x80008835, // Small 'uaba'. + 0x80C08835, // Small 'uabal'. + 0xBAC08835, // Small 'uabal2'. + 0x80020835, // Small 'uabd'. + 0x80C20835, // Small 'uabdl'. + 0xBAC20835, // Small 'uabdl2'. + 0xA0C09035, // Small 'uadalp'. + 0x80C21035, // Small 'uaddl'. + 0xBAC21035, // Small 'uaddl2'. + 0xA0C21035, // Small 'uaddlp'. + 0xACC21035, // Small 'uaddlv'. + 0x81721035, // Small 'uaddw'. + 0xBB721035, // Small 'uaddw2'. + 0x806A5875, // Small 'ucvtf'. + 0x800A3C95, // Small 'udot'. + 0x80420515, // Small 'uhadd'. + 0x802ACD15, // Small 'uhsub'. + 0x800C05B5, // Small 'umax'. + 0x810C05B5, // Small 'umaxp'. + 0x816C05B5, // Small 'umaxv'. + 0x800725B5, // Small 'umin'. + 0x810725B5, // Small 'uminp'. + 0x816725B5, // Small 'uminv'. + 0x80C0B1B5, // Small 'umlal'. + 0xBAC0B1B5, // Small 'umlal2'. + 0x80C9B1B5, // Small 'umlsl'. + 0xBAC9B1B5, // Small 'umlsl2'. + 0x801635B5, // Small 'ummla'. + 0x800B3DB5, // Small 'umov'. + 0x80C655B5, // Small 'umull'. + 0xBAC655B5, // Small 'umull2'. + 0x80420635, // Small 'uqadd'. + 0x9889CA35, // Small 'uqrshl'. + 0x101C60B9, // Large 'uqrshr|n'. + 0x20B160B9, // Large 'uqrshr|n2'. + 0x80C44E35, // Small 'uqshl'. + 0x9D244E35, // Small 'uqshrn'. + 0x20B1512A, // Large 'uqshr|n2'. + 0x802ACE35, // Small 'uqsub'. + 0x80EA6235, // Small 'uqxtn'. + 0xBAEA6235, // Small 'uqxtn2'. + 0x8B019655, // Small 'urecpe'. + 0x8840A255, // Small 'urhadd'. + 0x80C44E55, // Small 'urshl'. + 0x81244E55, // Small 'urshr'. + 0x20D2512F, // Large 'ursqr|te'. + 0x80194E55, // Small 'ursra'. + 0x81479275, // Small 'usdot'. + 0x80062275, // Small 'ushl'. + 0x80C62275, // Small 'ushll'. + 0xBAC62275, // Small 'ushll2'. + 0x80092275, // Small 'ushr'. + 0x82C6B675, // Small 'usmmla'. + 0x8840C675, // Small 'usqadd'. + 0x8000CA75, // Small 'usra'. + 0x80C15675, // Small 'usubl'. + 0xBAC15675, // Small 'usubl2'. + 0x81715675, // Small 'usubw'. + 0xBB715675, // Small 'usubw2'. + 0x80065315, // Small 'uxtl'. + 0x81D65315, // Small 'uxtl2'. + 0x800E4355, // Small 'uzp1'. + 0x800EC355, // Small 'uzp2'. + 0x80004838, // Small 'xar'. + 0x80003A98, // Small 'xtn'. + 0x800EBA98, // Small 'xtn2'. + 0x800E413A, // Small 'zip1'. + 0x800EC13A // Small 'zip2'. +}; + +const char InstDB::_instNameStringTable[] = + "autia1716autibldsmaxalhldsminalldumaxallduminalsha256su0sha512su1sm3partwsqrshru" + "nldaddalldclralldeoralldsetallbstsmaxstsminstumaxstuminfrint32z64x64zh2sqdmlalsl" + "2sqdmulsqrdmlaulhn2sqshruuqrshrspcrc32cstaddstclrsteorstsetxpaclbfcvtbfmlaltfcvt" + "xfjcvtzfmaxnmfminnmfrsqrraddrsubsha1sm3tt12a2bsm4ekeysqxtuuqshrursqrsetfrev8"; + const InstDB::InstNameIndex InstDB::instNameIndex[26] = { { Inst::kIdAdc , Inst::kIdAnd_v + 1 }, diff --git a/erts/emulator/asmjit/arm/a64instdb.h b/erts/emulator/asmjit/arm/a64instdb.h index 0575d1a2fa65..fe9fcecae98c 100644 --- a/erts/emulator/asmjit/arm/a64instdb.h +++ b/erts/emulator/asmjit/arm/a64instdb.h @@ -39,9 +39,7 @@ struct InstInfo { uint32_t _encoding : 8; //! Index to data specific to each encoding type. uint32_t _encodingDataIndex : 8; - uint32_t _reserved : 2; - //! Index to \ref _nameData. - uint32_t _nameDataIndex : 14; + uint32_t _reserved : 16; uint16_t _rwInfoIndex; uint16_t _flags; diff --git a/erts/emulator/asmjit/arm/a64instdb_p.h b/erts/emulator/asmjit/arm/a64instdb_p.h index eb4f3f837667..ef557d3c7a6c 100644 --- a/erts/emulator/asmjit/arm/a64instdb_p.h +++ b/erts/emulator/asmjit/arm/a64instdb_p.h @@ -861,7 +861,8 @@ struct InstNameIndex { // ==================== #ifndef ASMJIT_NO_TEXT -extern const char _nameData[]; +extern const uint32_t _instNameIndexTable[]; +extern const char _instNameStringTable[]; extern const InstNameIndex instNameIndex[26]; #endif // !ASMJIT_NO_TEXT diff --git a/erts/emulator/asmjit/arm/a64rapass.cpp b/erts/emulator/asmjit/arm/a64rapass.cpp index ad78369eaa76..aaec1c90f997 100644 --- a/erts/emulator/asmjit/arm/a64rapass.cpp +++ b/erts/emulator/asmjit/arm/a64rapass.cpp @@ -102,7 +102,7 @@ class RACFGBuilder : public RACFGBuilderT { // TODO: [ARM] This is just a workaround... static InstControlFlow getControlFlowType(InstId instId) noexcept { - switch (instId) { + switch (BaseInst::extractRealId(instId)) { case Inst::kIdB: case Inst::kIdBr: if (BaseInst::extractARMCondCode(instId) == CondCode::kAL) @@ -127,8 +127,8 @@ static InstControlFlow getControlFlowType(InstId instId) noexcept { Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstBuilder& ib) noexcept { InstRWInfo rwInfo; - InstId instId = inst->id(); - if (Inst::isDefinedId(instId)) { + if (Inst::isDefinedId(inst->realId())) { + InstId instId = inst->id(); uint32_t opCount = inst->opCount(); const Operand* opArray = inst->operands(); ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo)); @@ -136,6 +136,8 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB const InstDB::InstInfo& instInfo = InstDB::infoById(instId); uint32_t singleRegOps = 0; + ib.addInstRWFlags(rwInfo.instFlags()); + if (opCount) { uint32_t consecutiveOffset = 0xFFFFFFFFu; uint32_t consecutiveParent = Globals::kInvalidId; @@ -715,6 +717,50 @@ ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) no } } } + + // Rewrite `loadAddressOf()` construct. + if (inst->realId() == Inst::kIdAdr && inst->opCount() == 2 && inst->op(1).isMem()) { + BaseMem mem = inst->op(1).as(); + int64_t offset = mem.offset(); + + if (!mem.hasBaseOrIndex()) { + inst->setId(Inst::kIdMov); + inst->setOp(1, Imm(offset)); + } + else { + if (mem.hasIndex()) + return DebugUtils::errored(kErrorInvalidAddressIndex); + + GpX dst(inst->op(0).as().id()); + GpX base(mem.baseId()); + + InstId arithInstId = offset < 0 ? Inst::kIdSub : Inst::kIdAdd; + uint64_t absOffset = offset < 0 ? Support::neg(uint64_t(offset)) : uint64_t(offset); + + inst->setId(arithInstId); + inst->setOpCount(3); + inst->setOp(1, base); + inst->setOp(2, Imm(absOffset)); + + // Use two operations if the offset cannot be encoded with ADD/SUB. + if (absOffset > 0xFFFu && (absOffset & ~uint64_t(0xFFF000u)) != 0) { + if (absOffset <= 0xFFFFFFu) { + cc()->_setCursor(inst->prev()); + ASMJIT_PROPAGATE(cc()->emit(arithInstId, dst, base, Imm(absOffset & 0xFFFu))); + + inst->setOp(1, dst); + inst->setOp(2, Imm(absOffset & 0xFFF000u)); + } + else { + cc()->_setCursor(inst->prev()); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, inst->op(0), Imm(absOffset))); + + inst->setOp(1, base); + inst->setOp(2, dst); + } + } + } + } } node = next; diff --git a/erts/emulator/asmjit/arm/armoperand.h b/erts/emulator/asmjit/arm/armoperand.h index e7803e952b61..a6322a097d88 100644 --- a/erts/emulator/asmjit/arm/armoperand.h +++ b/erts/emulator/asmjit/arm/armoperand.h @@ -110,14 +110,14 @@ class Reg : public BaseReg { static inline bool isVecQ(const Operand_& op) noexcept { return op.as().isVecQ(); } static inline bool isVecV(const Operand_& op) noexcept { return op.as().isVecV(); } - static inline bool isGpW(const Operand_& op, uint32_t id) noexcept { return isGpW(op) & (op.id() == id); } - static inline bool isGpX(const Operand_& op, uint32_t id) noexcept { return isGpX(op) & (op.id() == id); } - static inline bool isVecB(const Operand_& op, uint32_t id) noexcept { return isVecB(op) & (op.id() == id); } - static inline bool isVecH(const Operand_& op, uint32_t id) noexcept { return isVecH(op) & (op.id() == id); } - static inline bool isVecS(const Operand_& op, uint32_t id) noexcept { return isVecS(op) & (op.id() == id); } - static inline bool isVecD(const Operand_& op, uint32_t id) noexcept { return isVecD(op) & (op.id() == id); } - static inline bool isVecQ(const Operand_& op, uint32_t id) noexcept { return isVecQ(op) & (op.id() == id); } - static inline bool isVecV(const Operand_& op, uint32_t id) noexcept { return isVecV(op) & (op.id() == id); } + static inline bool isGpW(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpW(op)) & unsigned(op.id() == id)); } + static inline bool isGpX(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpX(op)) & unsigned(op.id() == id)); } + static inline bool isVecB(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecB(op)) & unsigned(op.id() == id)); } + static inline bool isVecH(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecH(op)) & unsigned(op.id() == id)); } + static inline bool isVecS(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecS(op)) & unsigned(op.id() == id)); } + static inline bool isVecD(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecD(op)) & unsigned(op.id() == id)); } + static inline bool isVecQ(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecQ(op)) & unsigned(op.id() == id)); } + static inline bool isVecV(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecV(op)) & unsigned(op.id() == id)); } }; //! General purpose register (ARM). @@ -455,11 +455,12 @@ class Mem : public BaseMem { //! \} - //! \name ARM Specific Features + //! \name Clone //! \{ //! Clones the memory operand. inline constexpr Mem clone() const noexcept { return Mem(*this); } + //! Gets new memory operand adjusted by `off`. inline Mem cloneAdjusted(int64_t off) const noexcept { Mem result(*this); @@ -467,6 +468,51 @@ class Mem : public BaseMem { return result; } + //! Clones the memory operand and makes it pre-index. + inline Mem pre() const noexcept { + Mem result(*this); + result.setPredicate(kOffsetPreIndex); + return result; + } + + //! Clones the memory operand, applies a given offset `off` and makes it pre-index. + inline Mem pre(int64_t off) const noexcept { + Mem result(*this); + result.setPredicate(kOffsetPreIndex); + result.addOffset(off); + return result; + } + + //! Clones the memory operand and makes it post-index. + inline Mem post() const noexcept { + Mem result(*this); + result.setPredicate(kOffsetPostIndex); + return result; + } + + //! Clones the memory operand, applies a given offset `off` and makes it post-index. + inline Mem post(int64_t off) const noexcept { + Mem result(*this); + result.setPredicate(kOffsetPostIndex); + result.addOffset(off); + return result; + } + + //! \} + + //! \name Base & Index + //! \{ + + //! Converts memory `baseType` and `baseId` to `arm::Reg` instance. + //! + //! The memory must have a valid base register otherwise the result will be wrong. + inline Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); } + + //! Converts memory `indexType` and `indexId` to `arm::Reg` instance. + //! + //! The memory must have a valid index register otherwise the result will be wrong. + inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); } + using BaseMem::setIndex; inline void setIndex(const BaseReg& index, uint32_t shift) noexcept { @@ -474,6 +520,11 @@ class Mem : public BaseMem { setShift(shift); } + //! \} + + //! \name ARM Specific Features + //! \{ + //! Gets whether the memory operand has shift (aka scale) constant. inline constexpr bool hasShift() const noexcept { return _signature.hasField(); } //! Gets the memory operand's shift (aka scale) constant. @@ -499,32 +550,6 @@ class Mem : public BaseMem { inline void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); } inline void makePostIndex() noexcept { setPredicate(kOffsetPostIndex); } - inline Mem pre() const noexcept { - Mem result(*this); - result.setPredicate(kOffsetPreIndex); - return result; - } - - inline Mem pre(int64_t off) const noexcept { - Mem result(*this); - result.setPredicate(kOffsetPreIndex); - result.addOffset(off); - return result; - } - - inline Mem post() const noexcept { - Mem result(*this); - result.setPredicate(kOffsetPreIndex); - return result; - } - - inline Mem post(int64_t off) const noexcept { - Mem result(*this); - result.setPredicate(kOffsetPostIndex); - result.addOffset(off); - return result; - } - //! \} }; diff --git a/erts/emulator/asmjit/core.h b/erts/emulator/asmjit/core.h index 4406ed89f300..e586734e4957 100644 --- a/erts/emulator/asmjit/core.h +++ b/erts/emulator/asmjit/core.h @@ -105,40 +105,37 @@ namespace asmjit { //! //! - Tested: //! -//! - **Clang** - Tested by GitHub Actions - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang -//! versions having C++11 support are probably fine, but are not regularly tested). +//! - **Clang** - Tested by GitHub Actions - Clang 10+ is officially supported and tested by CI, older Clang versions +//! having C++11 should work, but are not tested anymore due to upgraded CI images. //! -//! - **GNU** - Tested by GitHub Actions - GCC 4.8+ (with C++11 enabled) is officially supported. +//! - **GNU** - Tested by GitHub Actions - GCC 7+ is officially supported, older GCC versions from 4.8+ having C++11 +//! enabled should also work, but are not tested anymore due to upgraded CI images. //! -//! - **MINGW** - Should work, but it's not tested in our CI environment. +//! - **MINGW** - Reported to work, but not tested in our CI environment (help welcome). //! -//! - **MSVC** - Tested by GitHub Actions - VS2017+ is officially supported, VS2015 is reported to work. -//! -//! - Untested: -//! -//! - **Intel** - No maintainers and no CI environment to regularly test this compiler. -//! -//! - **Other** C++ compilers would require basic support in -//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h). +//! - **MSVC** - Tested by GitHub Actions - VS2019+ is officially supported, VS2015 and VS2017 is reported to work, +//! but not tested by CI anymore. //! //! ### Supported Operating Systems and Platforms //! //! - Tested: //! -//! - **Linux** - Tested by GitHub Actions (any distribution is generally supported). +//! - **BSD** - FreeBSD, NetBSD, and OpenBSD tested by GitHub Actions (only recent images are tested by CI). BSD +//! runners only test BSD images with clang compiler. //! -//! - **Mac OS** - Tested by GitHub Actions (any version is supported). +//! - **Linux** - Tested by GitHub Actions (only recent Ubuntu images are tested by CI, in general any distribution +//! should be supported as AsmJit has no dependencies). +//! +//! - **Mac OS** - Tested by GitHub Actions. //! //! - **Windows** - Tested by GitHub Actions - (Windows 7+ is officially supported). //! //! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit cannot generate WASM code, but can be -//! used to generate X86/X64 code within a browser, for example. +//! used to generate X86/X64/AArch64 code within a browser, for example. //! //! - Untested: //! -//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, but they should work out of box. -//! -//! - **Haiku** - Not regularly tested, but reported to work. +//! - **Haiku** - Reported to work, not tested by CI. //! //! - **Other** operating systems would require some testing and support in the following files: //! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h) @@ -149,7 +146,7 @@ namespace asmjit { //! //! - **X86** and **X86_64** - Both 32-bit and 64-bit backends tested on CI. //! - **AArch64** - AArch64 backend is currently only partially tested (there is no native AArch64 runner to test -//! AsmJit Builder/Compiler) +//! AsmJit Builder/Compiler). //! //! ### Static Builds and Embedding //! @@ -454,7 +451,8 @@ namespace asmjit { //! JitRuntime rt; // Runtime specialized for JIT code execution. //! //! CodeHolder code; // Holds code and relocation information. -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! a.mov(x86::eax, 1); // Move one to eax register. @@ -599,9 +597,10 @@ namespace asmjit { //! int main() { //! // Create a custom environment that matches the current host environment. //! Environment env = Environment::host(); +//! CpuFeatures cpuFeatures = CpuInfo::host().features(); //! //! CodeHolder code; // Create a CodeHolder. -//! code.init(env); // Initialize CodeHolder with environment. +//! code.init(env, cpuFeatures); // Initialize CodeHolder with environment. //! //! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. //! @@ -722,10 +721,11 @@ namespace asmjit { //! //! void initializeCodeHolder(CodeHolder& code) { //! Environment env = Environment::host(); +//! CpuFeatures cpuFeatures = CpuInfo::host().features(); //! uint64_t baseAddress = uint64_t(0x1234); //! //! // initialize CodeHolder with environment and custom base address. -//! code.init(env, baseAddress); +//! code.init(env, cpuFeatures, baseAddress); //! } //! ``` //! @@ -1346,7 +1346,8 @@ namespace asmjit { //! FileLogger logger(stdout); // Logger should always survive CodeHolder. //! //! CodeHolder code; // Holds code and relocation information. -//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! code.setLogger(&logger); // Attach the `logger` to `code` holder. //! //! // ... code as usual, everything emitted will be logged to `stdout` ... @@ -1369,7 +1370,8 @@ namespace asmjit { //! StringLogger logger; // Logger should always survive CodeHolder. //! //! CodeHolder code; // Holds code and relocation information. -//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! code.setLogger(&logger); // Attach the `logger` to `code` holder. //! //! // ... code as usual, logging will be concatenated to logger string ... @@ -1494,7 +1496,7 @@ namespace asmjit { //! using namespace asmjit; //! //! void formattingExample(BaseBuilder* builder) { -//! FormatFlags formatFlags = FormatFlags::kNone; +//! FormatOptions formatOptions {}; //! //! // This also shows how temporary strings can be used. //! StringTmp<512> sb; @@ -1503,7 +1505,7 @@ namespace asmjit { //! // were zero (no extra flags), and the builder instance, which we have //! // provided. An overloaded version also exists, which accepts begin and //! // and end nodes, which can be used to only format a range of nodes. -//! Formatter::formatNodeList(sb, formatFlags, builder); +//! Formatter::formatNodeList(sb, formatOptions, builder); //! //! // You can do whatever else with the string, it's always null terminated, //! // so it can be passed to C functions like printf(). @@ -1560,7 +1562,7 @@ namespace asmjit { //! MyErrorHandler myErrorHandler; //! CodeHolder code; //! -//! code.init(rt.environment()); +//! code.init(rt.environment(), rt.cpuFeatures()); //! code.setErrorHandler(&myErrorHandler); //! //! x86::Assembler a(&code); diff --git a/erts/emulator/asmjit/core/api-config.h b/erts/emulator/asmjit/core/api-config.h index a0fb979eb330..60c9d5244e98 100644 --- a/erts/emulator/asmjit/core/api-config.h +++ b/erts/emulator/asmjit/core/api-config.h @@ -13,7 +13,7 @@ //! \{ //! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format. -#define ASMJIT_LIBRARY_VERSION 0x010900 /* 1.9.0 */ +#define ASMJIT_LIBRARY_VERSION 0x010A00 /* 1.10.0 */ //! \def ASMJIT_ABI_NAMESPACE //! @@ -24,7 +24,7 @@ //! default, which makes it possible to use use multiple AsmJit libraries within a single project, totally controlled //! by the users. This is useful especially in cases in which some of such library comes from a third party. #ifndef ASMJIT_ABI_NAMESPACE - #define ASMJIT_ABI_NAMESPACE _abi_1_9 + #define ASMJIT_ABI_NAMESPACE _abi_1_10 #endif //! \} @@ -586,7 +586,7 @@ namespace asmjit { //! \def ASMJIT_DEFINE_ENUM_COMPARE(T) //! //! Defines comparison operations for enumeration flags. -#ifdef _DOXYGEN +#if defined(_DOXYGEN) || (defined(_MSC_VER) && _MSC_VER <= 1900) #define ASMJIT_DEFINE_ENUM_COMPARE(T) #else #define ASMJIT_DEFINE_ENUM_COMPARE(T) \ diff --git a/erts/emulator/asmjit/core/archtraits.h b/erts/emulator/asmjit/core/archtraits.h index 4d05c11096bc..192a826e5110 100644 --- a/erts/emulator/asmjit/core/archtraits.h +++ b/erts/emulator/asmjit/core/archtraits.h @@ -152,7 +152,7 @@ enum class InstHints : uint8_t { //! No feature hints. kNoHints = 0, - //! Architecture supports a register swap by using a single instructio. + //! Architecture supports a register swap by using a single instruction. kRegSwap = 0x01u, //! Architecture provides push/pop instructions. kPushPop = 0x02u diff --git a/erts/emulator/asmjit/core/builder.cpp b/erts/emulator/asmjit/core/builder.cpp index 5df243e7b8ae..77f94e7aeb37 100644 --- a/erts/emulator/asmjit/core/builder.cpp +++ b/erts/emulator/asmjit/core/builder.cpp @@ -594,10 +594,12 @@ Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1, Error err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount, validationFlags); if (ASMJIT_UNLIKELY(err)) { - resetInstOptions(); - resetExtraReg(); - resetInlineComment(); +#ifndef ASMJIT_NO_LOGGING + return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt); +#else + resetState(); return reportError(err); +#endif } } #endif diff --git a/erts/emulator/asmjit/core/builder_p.h b/erts/emulator/asmjit/core/builder_p.h new file mode 100644 index 000000000000..303358fc9b79 --- /dev/null +++ b/erts/emulator/asmjit/core/builder_p.h @@ -0,0 +1,35 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#ifndef ASMJIT_CORE_BUILDER_P_H_INCLUDED +#define ASMJIT_CORE_BUILDER_P_H_INCLUDED + +#include "../core/api-config.h" +#ifndef ASMJIT_NO_BUILDER + +#include "../core/builder.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_builder +//! \{ + +static inline void BaseBuilder_assignInlineComment(BaseBuilder* self, BaseNode* node, const char* comment) noexcept { + if (comment) + node->setInlineComment(static_cast(self->_dataZone.dup(comment, strlen(comment), true))); +} + +static inline void BaseBuilder_assignInstState(BaseBuilder* self, InstNode* node, const BaseEmitter::State& state) noexcept { + node->setOptions(state.options); + node->setExtraReg(state.extraReg); + BaseBuilder_assignInlineComment(self, node, state.comment); +} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // !ASMJIT_NO_BUILDER +#endif // ASMJIT_CORE_BUILDER_P_H_INCLUDED diff --git a/erts/emulator/asmjit/core/codebuffer.h b/erts/emulator/asmjit/core/codebuffer.h index 4946e7a06a13..2fe35a97720b 100644 --- a/erts/emulator/asmjit/core/codebuffer.h +++ b/erts/emulator/asmjit/core/codebuffer.h @@ -44,7 +44,7 @@ struct CodeBuffer { //! \name Overloaded Operators //! \{ - //! Returns a referebce to the byte at the given `index`. + //! Returns a reference to the byte at the given `index`. inline uint8_t& operator[](size_t index) noexcept { ASMJIT_ASSERT(index < _size); return _data[index]; diff --git a/erts/emulator/asmjit/core/codeholder.cpp b/erts/emulator/asmjit/core/codeholder.cpp index cf763cfff120..3f7f5f5394ef 100644 --- a/erts/emulator/asmjit/core/codeholder.cpp +++ b/erts/emulator/asmjit/core/codeholder.cpp @@ -74,6 +74,7 @@ static void CodeHolder_resetInternal(CodeHolder* self, ResetPolicy resetPolicy) // Reset everything into its construction state. self->_environment.reset(); + self->_cpuFeatures.reset(); self->_baseAddress = Globals::kNoBaseAddress; self->_logger = nullptr; self->_errorHandler = nullptr; @@ -118,6 +119,7 @@ static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept { CodeHolder::CodeHolder(const Support::Temporary* temporary) noexcept : _environment(), + _cpuFeatures{}, _baseAddress(Globals::kNoBaseAddress), _logger(nullptr), _errorHandler(nullptr), @@ -143,6 +145,10 @@ inline void CodeHolder_setSectionDefaultName( } Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noexcept { + return init(environment, CpuFeatures{}, baseAddress); +} + +Error CodeHolder::init(const Environment& environment, const CpuFeatures& cpuFeatures, uint64_t baseAddress) noexcept { // Cannot reinitialize if it's locked or there is one or more emitter attached. if (isInitialized()) return DebugUtils::errored(kErrorAlreadyInitialized); @@ -172,6 +178,7 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe } else { _environment = environment; + _cpuFeatures = cpuFeatures; _baseAddress = baseAddress; return kErrorOk; } diff --git a/erts/emulator/asmjit/core/codeholder.h b/erts/emulator/asmjit/core/codeholder.h index e3bd0d59239a..d663d3e340de 100644 --- a/erts/emulator/asmjit/core/codeholder.h +++ b/erts/emulator/asmjit/core/codeholder.h @@ -356,7 +356,7 @@ struct OffsetFormat { //! Returns the size of the region/instruction where the offset is encoded. inline uint32_t regionSize() const noexcept { return _regionSize; } - //! Returns the the offset of the word relative to the start of the region where the offset is. + //! Returns the offset of the word relative to the start of the region where the offset is. inline uint32_t valueOffset() const noexcept { return _valueOffset; } //! Returns the size of the data-type (word) that contains the offset, in bytes. @@ -640,6 +640,8 @@ class CodeHolder { //! Environment information. Environment _environment; + //! CPU features of the target architecture. + CpuFeatures _cpuFeatures; //! Base address or \ref Globals::kNoBaseAddress. uint64_t _baseAddress; @@ -698,6 +700,8 @@ class CodeHolder { //! Initializes CodeHolder to hold code described by the given `environment` and `baseAddress`. ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept; + //! Initializes CodeHolder to hold code described by the given `environment`, `cpuFeatures`, and `baseAddress`. + ASMJIT_API Error init(const Environment& environment, const CpuFeatures& cpuFeatures, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept; //! Detaches all code-generators attached and resets the `CodeHolder`. ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept; @@ -736,6 +740,9 @@ class CodeHolder { //! Returns the target sub-architecture. inline SubArch subArch() const noexcept { return environment().subArch(); } + //! Returns the minimum CPU features of the target architecture. + inline const CpuFeatures& cpuFeatures() const noexcept { return _cpuFeatures; } + //! Tests whether a static base-address is set. inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set. diff --git a/erts/emulator/asmjit/core/compiler.cpp b/erts/emulator/asmjit/core/compiler.cpp index b1c6b803b290..ee959f74aae8 100644 --- a/erts/emulator/asmjit/core/compiler.cpp +++ b/erts/emulator/asmjit/core/compiler.cpp @@ -7,6 +7,7 @@ #ifndef ASMJIT_NO_COMPILER #include "../core/assembler.h" +#include "../core/builder_p.h" #include "../core/compiler.h" #include "../core/cpuinfo.h" #include "../core/logger.h" @@ -103,9 +104,13 @@ Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature) } Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature) { + State state = _grabState(); + ASMJIT_PROPAGATE(newFuncNode(out, signature)); ASMJIT_ASSUME(*out != nullptr); + BaseBuilder_assignInlineComment(this, *out, state.comment); + addFunc(*out); return kErrorOk; } @@ -127,7 +132,13 @@ Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const } Error BaseCompiler::addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + State state = _grabState(); + ASMJIT_PROPAGATE(newFuncRetNode(out, o0, o1)); + ASMJIT_ASSUME(*out != nullptr); + + BaseBuilder_assignInlineComment(this, *out, state.comment); + addNode(*out); return kErrorOk; } @@ -146,6 +157,7 @@ FuncNode* BaseCompiler::addFunc(FuncNode* func) { Error BaseCompiler::endFunc() { FuncNode* func = _func; + resetState(); if (ASMJIT_UNLIKELY(!func)) return reportError(DebugUtils::errored(kErrorInvalidState)); @@ -196,7 +208,12 @@ Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand } Error BaseCompiler::addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) { + State state = _grabState(); + ASMJIT_PROPAGATE(newInvokeNode(out, instId, o0, signature)); + ASMJIT_ASSUME(*out != nullptr); + + BaseBuilder_assignInstState(this, *out, state); addNode(*out); return kErrorOk; } @@ -481,20 +498,13 @@ Error BaseCompiler::newJumpNode(JumpNode** out, InstId instId, InstOptions instO } Error BaseCompiler::emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation) { - InstOptions options = instOptions() | forcedInstOptions(); - RegOnly extra = extraReg(); - const char* comment = inlineComment(); - - resetInstOptions(); - resetInlineComment(); - resetExtraReg(); + State state = _grabState(); JumpNode* node; - ASMJIT_PROPAGATE(newJumpNode(&node, instId, options, o0, annotation)); + ASMJIT_PROPAGATE(newJumpNode(&node, instId, state.options, o0, annotation)); - node->setExtraReg(extra); - if (comment) - node->setInlineComment(static_cast(_dataZone.dup(comment, strlen(comment), true))); + node->setExtraReg(state.extraReg); + BaseBuilder_assignInlineComment(this, node, state.comment); addNode(node); return kErrorOk; diff --git a/erts/emulator/asmjit/core/cpuinfo.cpp b/erts/emulator/asmjit/core/cpuinfo.cpp index 7bf7407f005f..fb2acfc09b2f 100644 --- a/erts/emulator/asmjit/core/cpuinfo.cpp +++ b/erts/emulator/asmjit/core/cpuinfo.cpp @@ -295,6 +295,7 @@ static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept { features.addIf(bitTest(regs.ecx, 27), CpuFeatures::X86::kMOVDIRI); features.addIf(bitTest(regs.ecx, 28), CpuFeatures::X86::kMOVDIR64B); features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kENQCMD); + features.addIf(bitTest(regs.edx, 4), CpuFeatures::X86::kFSRM); features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kUINTR); features.addIf(bitTest(regs.edx, 14), CpuFeatures::X86::kSERIALIZE); features.addIf(bitTest(regs.edx, 16), CpuFeatures::X86::kTSXLDTRK); @@ -302,14 +303,14 @@ static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept { features.addIf(bitTest(regs.edx, 20), CpuFeatures::X86::kCET_IBT); // Detect 'TSX' - Requires at least one of `HLE` and `RTM` features. - if (features.hasHLE() || features.hasRTM()) + if (features.hasHLE() || features.hasRTM()) { features.add(CpuFeatures::X86::kTSX); + } - // Detect 'AVX2' - Requires AVX as well. - if (bitTest(regs.ebx, 5) && features.hasAVX()) + if (bitTest(regs.ebx, 5) && features.hasAVX()) { features.add(CpuFeatures::X86::kAVX2); + } - // Detect 'AVX512'. if (avx512EnabledByOS && bitTest(regs.ebx, 16)) { features.add(CpuFeatures::X86::kAVX512_F); @@ -331,7 +332,6 @@ static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept { features.addIf(bitTest(regs.edx, 23), CpuFeatures::X86::kAVX512_FP16); } - // Detect 'AMX'. if (amxEnabledByOS) { features.addIf(bitTest(regs.edx, 22), CpuFeatures::X86::kAMX_BF16); features.addIf(bitTest(regs.edx, 24), CpuFeatures::X86::kAMX_TILE); @@ -342,12 +342,35 @@ static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept { // CPUID EAX=7 ECX=1 // ----------------- - if (features.hasAVX512_F() && maxSubLeafId_0x7 >= 1) { + if (maxSubLeafId_0x7 >= 1) { cpuidQuery(®s, 0x7, 1); - features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kAVX_VNNI); - features.addIf(bitTest(regs.eax, 5), CpuFeatures::X86::kAVX512_BF16); + features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kRAO_INT); + features.addIf(bitTest(regs.eax, 7), CpuFeatures::X86::kCMPCCXADD); + features.addIf(bitTest(regs.eax, 10), CpuFeatures::X86::kFZRM); + features.addIf(bitTest(regs.eax, 11), CpuFeatures::X86::kFSRS); + features.addIf(bitTest(regs.eax, 12), CpuFeatures::X86::kFSRC); + features.addIf(bitTest(regs.eax, 19), CpuFeatures::X86::kWRMSRNS); features.addIf(bitTest(regs.eax, 22), CpuFeatures::X86::kHRESET); + features.addIf(bitTest(regs.eax, 26), CpuFeatures::X86::kLAM); + features.addIf(bitTest(regs.eax, 27), CpuFeatures::X86::kMSRLIST); + features.addIf(bitTest(regs.edx, 14), CpuFeatures::X86::kPREFETCHI); + features.addIf(bitTest(regs.edx, 18), CpuFeatures::X86::kCET_SSS); + + if (features.hasAVX2()) { + features.addIf(bitTest(regs.eax, 4), CpuFeatures::X86::kAVX_VNNI); + features.addIf(bitTest(regs.eax, 23), CpuFeatures::X86::kAVX_IFMA); + features.addIf(bitTest(regs.edx, 4), CpuFeatures::X86::kAVX_VNNI_INT8); + features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kAVX_NE_CONVERT); + } + + if (features.hasAVX512_F()) { + features.addIf(bitTest(regs.eax, 5), CpuFeatures::X86::kAVX512_BF16); + } + + if (amxEnabledByOS) { + features.addIf(bitTest(regs.eax, 21), CpuFeatures::X86::kAMX_FP16); + } } // CPUID EAX=13 ECX=0 diff --git a/erts/emulator/asmjit/core/cpuinfo.h b/erts/emulator/asmjit/core/cpuinfo.h index 4af5c3a82f93..f5437d4cc0ed 100644 --- a/erts/emulator/asmjit/core/cpuinfo.h +++ b/erts/emulator/asmjit/core/cpuinfo.h @@ -175,6 +175,7 @@ class CpuFeatures { kAESNI, //!< CPU has AESNI (AES encode/decode instructions). kALTMOVCR8, //!< CPU has LOCK MOV R<->CR0 (supports `MOV R<->CR8` via `LOCK MOV R<->CR0` in 32-bit mode) [AMD]. kAMX_BF16, //!< CPU has AMX_BF16 (advanced matrix extensions - BF16 instructions). + kAMX_FP16, //!< CPU has AMX_FP16 (advanced matrix extensions - FP16 instructions). kAMX_INT8, //!< CPU has AMX_INT8 (advanced matrix extensions - INT8 instructions). kAMX_TILE, //!< CPU has AMX_TILE (advanced matrix extensions). kAVX, //!< CPU has AVX (advanced vector extensions). @@ -197,17 +198,22 @@ class CpuFeatures { kAVX512_VNNI, //!< CPU has AVX512_VNNI (vector neural network instructions). kAVX512_VP2INTERSECT, //!< CPU has AVX512_VP2INTERSECT kAVX512_VPOPCNTDQ, //!< CPU has AVX512_VPOPCNTDQ (VPOPCNT[D|Q] instructions). + kAVX_IFMA, //!< CPU has AVX_IFMA (VEX encoding of vpmadd52huq/vpmadd52luq). + kAVX_NE_CONVERT, //!< CPU has AVX_NE_CONVERT. kAVX_VNNI, //!< CPU has AVX_VNNI (VEX encoding of vpdpbusd/vpdpbusds/vpdpwssd/vpdpwssds). + kAVX_VNNI_INT8, //!< CPU has AVX_VNNI_INT8. kBMI, //!< CPU has BMI (bit manipulation instructions #1). kBMI2, //!< CPU has BMI2 (bit manipulation instructions #2). kCET_IBT, //!< CPU has CET-IBT (indirect branch tracking). kCET_SS, //!< CPU has CET-SS. + kCET_SSS, //!< CPU has CET-SSS. kCLDEMOTE, //!< CPU has CLDEMOTE (cache line demote). kCLFLUSH, //!< CPU has CLFUSH (Cache Line flush). kCLFLUSHOPT, //!< CPU has CLFUSHOPT (Cache Line flush - optimized). kCLWB, //!< CPU has CLWB. kCLZERO, //!< CPU has CLZERO. kCMOV, //!< CPU has CMOV (CMOV and FCMOV instructions). + kCMPCCXADD, //!< CPU has CMPCCXADD. kCMPXCHG16B, //!< CPU has CMPXCHG16B (compare-exchange 16 bytes) [X86_64]. kCMPXCHG8B, //!< CPU has CMPXCHG8B (compare-exchange 8 bytes). kENCLV, //!< CPU has ENCLV. @@ -218,14 +224,19 @@ class CpuFeatures { kFMA4, //!< CPU has FMA4 (fused-multiply-add 4 operand form). kFPU, //!< CPU has FPU (FPU support). kFSGSBASE, //!< CPU has FSGSBASE. + kFSRM, //!< CPU has FSRM (fast short REP MOVSB). + kFSRC, //!< CPU has FSRC (fast short REP CMPSB|SCASB). + kFSRS, //!< CPU has FSRS (fast short REP STOSB) kFXSR, //!< CPU has FXSR (FXSAVE/FXRSTOR instructions). kFXSROPT, //!< CPU has FXSROTP (FXSAVE/FXRSTOR is optimized). + kFZRM, //!< CPU has FZRM (fast zero-length REP MOVSB). kGEODE, //!< CPU has GEODE extensions (3DNOW additions). kGFNI, //!< CPU has GFNI (Galois field instructions). kHLE, //!< CPU has HLE. kHRESET, //!< CPU has HRESET. kI486, //!< CPU has I486 features (I486+ support). kLAHFSAHF, //!< CPU has LAHF/SAHF (LAHF/SAHF in 64-bit mode) [X86_64]. + kLAM, //!< CPU has LAM (linear address masking) [X86_64]. kLWP, //!< CPU has LWP (lightweight profiling) [AMD]. kLZCNT, //!< CPU has LZCNT (LZCNT instruction). kMCOMMIT, //!< CPU has MCOMMIT (MCOMMIT instruction). @@ -238,15 +249,18 @@ class CpuFeatures { kMOVDIRI, //!< CPU has MOVDIRI (move dword/qword as direct store). kMPX, //!< CPU has MPX (memory protection extensions). kMSR, //!< CPU has MSR (RDMSR/WRMSR instructions). + kMSRLIST, //!< CPU has MSRLIST. kMSSE, //!< CPU has MSSE (misaligned SSE support). kOSXSAVE, //!< CPU has OSXSAVE (XSAVE enabled by OS). kOSPKE, //!< CPU has OSPKE (PKE enabled by OS). kPCLMULQDQ, //!< CPU has PCLMULQDQ (packed carry-less multiplication). kPCONFIG, //!< CPU has PCONFIG (PCONFIG instruction). kPOPCNT, //!< CPU has POPCNT (POPCNT instruction). + kPREFETCHI, //!< CPU has PREFETCHI. kPREFETCHW, //!< CPU has PREFETCHW. kPREFETCHWT1, //!< CPU has PREFETCHWT1. kPTWRITE, //!< CPU has PTWRITE. + kRAO_INT, //!< CPU has RAO_INT. kRDPID, //!< CPU has RDPID. kRDPRU, //!< CPU has RDPRU. kRDRAND, //!< CPU has RDRAND. @@ -278,6 +292,7 @@ class CpuFeatures { kVPCLMULQDQ, //!< CPU has VPCLMULQDQ (vector PCLMULQDQ 256|512-bit support). kWAITPKG, //!< CPU has WAITPKG (UMONITOR, UMWAIT, TPAUSE). kWBNOINVD, //!< CPU has WBNOINVD. + kWRMSRNS, //!< CPU has WRMSRNS. kXOP, //!< CPU has XOP (XOP instructions) [AMD]. kXSAVE, //!< CPU has XSAVE. kXSAVEC, //!< CPU has XSAVEC. @@ -299,6 +314,7 @@ class CpuFeatures { ASMJIT_X86_FEATURE(AESNI) ASMJIT_X86_FEATURE(ALTMOVCR8) ASMJIT_X86_FEATURE(AMX_BF16) + ASMJIT_X86_FEATURE(AMX_FP16) ASMJIT_X86_FEATURE(AMX_INT8) ASMJIT_X86_FEATURE(AMX_TILE) ASMJIT_X86_FEATURE(AVX) @@ -321,11 +337,15 @@ class CpuFeatures { ASMJIT_X86_FEATURE(AVX512_VNNI) ASMJIT_X86_FEATURE(AVX512_VP2INTERSECT) ASMJIT_X86_FEATURE(AVX512_VPOPCNTDQ) + ASMJIT_X86_FEATURE(AVX_IFMA) + ASMJIT_X86_FEATURE(AVX_NE_CONVERT) ASMJIT_X86_FEATURE(AVX_VNNI) + ASMJIT_X86_FEATURE(AVX_VNNI_INT8) ASMJIT_X86_FEATURE(BMI) ASMJIT_X86_FEATURE(BMI2) ASMJIT_X86_FEATURE(CET_IBT) ASMJIT_X86_FEATURE(CET_SS) + ASMJIT_X86_FEATURE(CET_SSS) ASMJIT_X86_FEATURE(CLDEMOTE) ASMJIT_X86_FEATURE(CLFLUSH) ASMJIT_X86_FEATURE(CLFLUSHOPT) @@ -342,14 +362,19 @@ class CpuFeatures { ASMJIT_X86_FEATURE(FMA4) ASMJIT_X86_FEATURE(FPU) ASMJIT_X86_FEATURE(FSGSBASE) + ASMJIT_X86_FEATURE(FSRM) + ASMJIT_X86_FEATURE(FSRC) + ASMJIT_X86_FEATURE(FSRS) ASMJIT_X86_FEATURE(FXSR) ASMJIT_X86_FEATURE(FXSROPT) + ASMJIT_X86_FEATURE(FZRM) ASMJIT_X86_FEATURE(GEODE) ASMJIT_X86_FEATURE(GFNI) ASMJIT_X86_FEATURE(HLE) ASMJIT_X86_FEATURE(HRESET) ASMJIT_X86_FEATURE(I486) ASMJIT_X86_FEATURE(LAHFSAHF) + ASMJIT_X86_FEATURE(LAM) ASMJIT_X86_FEATURE(LWP) ASMJIT_X86_FEATURE(LZCNT) ASMJIT_X86_FEATURE(MCOMMIT) @@ -362,15 +387,18 @@ class CpuFeatures { ASMJIT_X86_FEATURE(MOVDIRI) ASMJIT_X86_FEATURE(MPX) ASMJIT_X86_FEATURE(MSR) + ASMJIT_X86_FEATURE(MSRLIST) ASMJIT_X86_FEATURE(MSSE) ASMJIT_X86_FEATURE(OSXSAVE) ASMJIT_X86_FEATURE(OSPKE) ASMJIT_X86_FEATURE(PCLMULQDQ) ASMJIT_X86_FEATURE(PCONFIG) ASMJIT_X86_FEATURE(POPCNT) + ASMJIT_X86_FEATURE(PREFETCHI) ASMJIT_X86_FEATURE(PREFETCHW) ASMJIT_X86_FEATURE(PREFETCHWT1) ASMJIT_X86_FEATURE(PTWRITE) + ASMJIT_X86_FEATURE(RAO_INT) ASMJIT_X86_FEATURE(RDPID) ASMJIT_X86_FEATURE(RDPRU) ASMJIT_X86_FEATURE(RDRAND) @@ -402,6 +430,7 @@ class CpuFeatures { ASMJIT_X86_FEATURE(VPCLMULQDQ) ASMJIT_X86_FEATURE(WAITPKG) ASMJIT_X86_FEATURE(WBNOINVD) + ASMJIT_X86_FEATURE(WRMSRNS) ASMJIT_X86_FEATURE(XOP) ASMJIT_X86_FEATURE(XSAVE) ASMJIT_X86_FEATURE(XSAVEC) diff --git a/erts/emulator/asmjit/core/emitter.h b/erts/emulator/asmjit/core/emitter.h index b8afd6b8e068..6499c071bd68 100644 --- a/erts/emulator/asmjit/core/emitter.h +++ b/erts/emulator/asmjit/core/emitter.h @@ -233,6 +233,13 @@ class ASMJIT_VIRTAPI BaseEmitter { //! Native GP register signature and signature related information. OperandSignature _gpSignature {}; + //! Emitter state that can be used to specify options and inline comment of a next node or instruction. + struct State { + InstOptions options; + RegOnly extraReg; + const char* comment; + }; + //! Next instruction options (affects the next instruction). InstOptions _instOptions = InstOptions::kNone; //! Extra register (op-mask {k} on AVX-512) (affects the next instruction). @@ -530,6 +537,23 @@ class ASMJIT_VIRTAPI BaseEmitter { //! \} + //! \name Emitter State + //! \{ + + inline void resetState() noexcept { + resetInstOptions(); + resetExtraReg(); + resetInlineComment(); + } + + inline State _grabState() noexcept { + State s{_instOptions | _forcedInstOptions, _extraReg, _inlineComment}; + resetState(); + return s; + } + + //! \} + //! \name Sections //! \{ diff --git a/erts/emulator/asmjit/core/emitterutils.cpp b/erts/emulator/asmjit/core/emitterutils.cpp index f36a1b377455..d0a687244b35 100644 --- a/erts/emulator/asmjit/core/emitterutils.cpp +++ b/erts/emulator/asmjit/core/emitterutils.cpp @@ -96,7 +96,7 @@ void logInstructionEmitted( } Error logInstructionFailed( - BaseAssembler* self, + BaseEmitter* self, Error err, InstId instId, InstOptions options, @@ -109,16 +109,14 @@ Error logInstructionFailed( Operand_ opArray[Globals::kMaxOpCount]; opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); - self->_funcs.formatInstruction(sb, FormatFlags::kNone, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + self->_funcs.formatInstruction(sb, FormatFlags::kRegType, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); if (self->inlineComment()) { sb.append(" ; "); sb.append(self->inlineComment()); } - self->resetInstOptions(); - self->resetExtraReg(); - self->resetInlineComment(); + self->resetState(); return self->reportError(err, sb.data()); } diff --git a/erts/emulator/asmjit/core/emitterutils_p.h b/erts/emulator/asmjit/core/emitterutils_p.h index b7610e702618..8b6e1e0547e3 100644 --- a/erts/emulator/asmjit/core/emitterutils_p.h +++ b/erts/emulator/asmjit/core/emitterutils_p.h @@ -23,7 +23,7 @@ namespace EmitterUtils { //! Default paddings used by Emitter utils and Formatter. -static constexpr Operand noExt[3]; +static constexpr Operand noExt[3] = { {}, {}, {} }; enum kOpIndex : uint32_t { kOp3 = 0, @@ -71,7 +71,7 @@ void logInstructionEmitted( uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); Error logInstructionFailed( - BaseAssembler* self, + BaseEmitter* self, Error err, InstId instId, InstOptions options, diff --git a/erts/emulator/asmjit/core/errorhandler.h b/erts/emulator/asmjit/core/errorhandler.h index 5151d43304e3..3b0096f05b51 100644 --- a/erts/emulator/asmjit/core/errorhandler.h +++ b/erts/emulator/asmjit/core/errorhandler.h @@ -61,7 +61,7 @@ class BaseEmitter; //! SimpleErrorHandler eh; //! //! CodeHolder code; -//! code.init(rt.environment()); +//! code.init(rt.environment(), rt.cpuFeatures()); //! code.setErrorHandler(&eh); //! //! // Try to emit instruction that doesn't exist. @@ -117,7 +117,7 @@ class BaseEmitter; //! ThrowableErrorHandler eh; //! //! CodeHolder code; -//! code.init(rt.environment()); +//! code.init(rt.environment(), rt.cpuFeatures()); //! code.setErrorHandler(&eh); //! //! x86::Assembler a(&code); @@ -166,7 +166,7 @@ class BaseEmitter; //! LongJmpErrorHandler eh; //! //! CodeHolder code; -//! code.init(rt.rt.environment()); +//! code.init(rt.environment(), rt.cpuFeatures()); //! code.setErrorHandler(&eh); //! //! x86::Assembler a(&code); diff --git a/erts/emulator/asmjit/core/formatter.cpp b/erts/emulator/asmjit/core/formatter.cpp index 1c4b7b6c6fa9..56e96926623e 100644 --- a/erts/emulator/asmjit/core/formatter.cpp +++ b/erts/emulator/asmjit/core/formatter.cpp @@ -143,7 +143,7 @@ Error formatLabel( } if (le->type() == LabelType::kAnonymous) - ASMJIT_PROPAGATE(sb.append("L%u@", labelId)); + ASMJIT_PROPAGATE(sb.appendFormat("L%u@", labelId)); return sb.append(le->name()); } else { @@ -471,8 +471,7 @@ Error formatNode( case NodeType::kComment: { const CommentNode* commentNode = node->as(); - ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment())); - break; + return sb.appendFormat("; %s", commentNode->inlineComment()); } case NodeType::kSentinel: { diff --git a/erts/emulator/asmjit/core/formatter.h b/erts/emulator/asmjit/core/formatter.h index d7a4b93476ac..0ee6bde107cd 100644 --- a/erts/emulator/asmjit/core/formatter.h +++ b/erts/emulator/asmjit/core/formatter.h @@ -37,7 +37,9 @@ enum class FormatFlags : uint32_t { //! Show casts between virtual register types (Compiler output). kRegCasts = 0x00000010u, //! Show positions associated with nodes (Compiler output). - kPositions = 0x00000020u + kPositions = 0x00000020u, + //! Always format a register type (Compiler output). + kRegType = 0x00000040u }; ASMJIT_DEFINE_ENUM_FLAGS(FormatFlags) diff --git a/erts/emulator/asmjit/core/func.h b/erts/emulator/asmjit/core/func.h index 8ecf1487ad22..d09955573ad3 100644 --- a/erts/emulator/asmjit/core/func.h +++ b/erts/emulator/asmjit/core/func.h @@ -1120,6 +1120,15 @@ class FuncFrame { inline uint32_t redZoneSize() const noexcept { return _redZoneSize; } //! Returns the size of 'SpillZone'. inline uint32_t spillZoneSize() const noexcept { return _spillZoneSize; } + + //! Resets the size of red zone, which would disable it entirely. + //! + //! \note Red zone is currently only used by an AMD64 SystemV calling convention, which expects 128 + //! bytes of stack to be accessible below stack pointer. These bytes are then accessible within the + //! function and Compiler can use this space as a spill area. However, sometimes it's better to + //! disallow the use of red zone in case that a user wants to use this stack for a custom purpose. + inline void resetRedZone() noexcept { _redZoneSize = 0; } + //! Returns natural stack alignment (guaranteed stack alignment upon entry). inline uint32_t naturalStackAlignment() const noexcept { return _naturalStackAlignment; } //! Returns natural stack alignment (guaranteed stack alignment upon entry). @@ -1127,7 +1136,7 @@ class FuncFrame { //! Tests whether the callee must adjust SP before returning (X86-STDCALL only) inline bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; } - //! Returns home many bytes of the stack the the callee must adjust before returning (X86-STDCALL only) + //! Returns home many bytes of the stack the callee must adjust before returning (X86-STDCALL only) inline uint32_t calleeStackCleanup() const noexcept { return _calleeStackCleanup; } //! Returns call stack alignment. diff --git a/erts/emulator/asmjit/core/inst.h b/erts/emulator/asmjit/core/inst.h index 23106315619f..643678971a7b 100644 --- a/erts/emulator/asmjit/core/inst.h +++ b/erts/emulator/asmjit/core/inst.h @@ -312,6 +312,10 @@ class BaseInst { return id | (uint32_t(cc) << Support::ConstCTZ::value); } + static inline constexpr InstId extractRealId(uint32_t id) noexcept { + return id & uint32_t(InstIdParts::kRealId); + } + static inline constexpr arm::CondCode extractARMCondCode(uint32_t id) noexcept { return (arm::CondCode)((uint32_t(id) & uint32_t(InstIdParts::kARM_Cond)) >> Support::ConstCTZ::value); } @@ -614,13 +618,25 @@ struct OpRWInfo { //! \} }; +//! Flags used by \ref InstRWInfo. +enum class InstRWFlags : uint32_t { + //! No flags. + kNone = 0x00000000u, + + //! Describes a move operation. + //! + //! This flag is used by RA to eliminate moves that are guaranteed to be moves only. + kMovOp = 0x00000001u +}; +ASMJIT_DEFINE_ENUM_FLAGS(InstRWFlags) + //! Read/Write information of an instruction. struct InstRWInfo { //! \name Members //! \{ //! Instruction flags (there are no flags at the moment, this field is reserved). - uint32_t _instFlags; + InstRWFlags _instFlags; //! CPU flags read. CpuRWFlags _readFlags; //! CPU flags written. @@ -646,6 +662,20 @@ struct InstRWInfo { //! \} + //! \name Instruction Flags + //! \{ + + //! Returns flags associated with the instruction, see \ref InstRWFlags. + inline InstRWFlags instFlags() const noexcept { return _instFlags; } + + //! Tests whether the instruction flags contain `flag`. + inline bool hasInstFlag(InstRWFlags flag) const noexcept { return Support::test(_instFlags, flag); } + + //! Tests whether the instruction flags contain \ref InstRWFlags::kMovOp. + inline bool isMovOp() const noexcept { return hasInstFlag(InstRWFlags::kMovOp); } + + //! \} + //! \name CPU Flags Information //! \{ diff --git a/erts/emulator/asmjit/core/jitallocator.cpp b/erts/emulator/asmjit/core/jitallocator.cpp index 19fbe4b23387..2a4305f0692b 100644 --- a/erts/emulator/asmjit/core/jitallocator.cpp +++ b/erts/emulator/asmjit/core/jitallocator.cpp @@ -430,6 +430,15 @@ static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator:: if (ASMJIT_UNLIKELY(!p)) return nullptr; + VirtMem::HardenedRuntimeInfo hardenedRtInfo = VirtMem::hardenedRuntimeInfo(); + if (Support::test(hardenedRtInfo.flags, VirtMem::HardenedRuntimeFlags::kEnabled)) { + // If we are running within a hardened environment (mapping RWX is not allowed) then we have to use dual mapping + // or other runtime capabilities like Apple specific MAP_JIT. There is no point in not enabling these as otherwise + // the allocation would fail and JitAllocator would not be able to allocate memory. + if (!Support::test(hardenedRtInfo.flags, VirtMem::HardenedRuntimeFlags::kMapJit)) + options |= JitAllocatorOptions::kUseDualMapping; + } + JitAllocatorPool* pools = reinterpret_cast((uint8_t*)p + sizeof(JitAllocatorPrivateImpl)); JitAllocatorPrivateImpl* impl = new(p) JitAllocatorPrivateImpl(pools, poolCount); @@ -497,7 +506,7 @@ ASMJIT_FAVOR_SPEED static void JitAllocatorImpl_fillPattern(void* mem, uint32_t // // NOTE: The block doesn't have `kFlagEmpty` flag set, because the new block // is only allocated when it's actually needed, so it would be cleared anyway. -static JitAllocatorBlock* JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* impl, JitAllocatorPool* pool, size_t blockSize) noexcept { +static Error JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock** dst, JitAllocatorPool* pool, size_t blockSize) noexcept { using Support::BitWord; using Support::kBitWordSizeInBits; @@ -532,7 +541,10 @@ static JitAllocatorBlock* JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* imp if (block) ::free(block); - return nullptr; + if (err) + return err; + else + return kErrorOutOfMemory; } // Fill the memory if the secure mode is enabled. @@ -542,7 +554,8 @@ static JitAllocatorBlock* JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* imp } memset(bitWords, 0, size_t(numBitWords) * 2 * sizeof(BitWord)); - return new(block) JitAllocatorBlock(pool, virtMem, blockSize, blockFlags, bitWords, bitWords + numBitWords, areaSize); + *dst = new(block) JitAllocatorBlock(pool, virtMem, blockSize, blockFlags, bitWords, bitWords + numBitWords, areaSize); + return kErrorOk; } static void JitAllocatorImpl_deleteBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept { @@ -789,12 +802,9 @@ Error JitAllocator::alloc(void** rxPtrOut, void** rwPtrOut, size_t size) noexcep if (ASMJIT_UNLIKELY(!blockSize)) return DebugUtils::errored(kErrorOutOfMemory); - block = JitAllocatorImpl_newBlock(impl, pool, blockSize); + ASMJIT_PROPAGATE(JitAllocatorImpl_newBlock(impl, &block, pool, blockSize)); areaIndex = 0; - if (ASMJIT_UNLIKELY(!block)) - return DebugUtils::errored(kErrorOutOfMemory); - JitAllocatorImpl_insertBlock(impl, block); block->_searchStart = areaSize; block->_largestUnusedArea = block->areaSize() - areaSize; @@ -889,8 +899,12 @@ Error JitAllocator::shrink(void* rxPtr, size_t newSize) noexcept { // The first bit representing the allocated area and its size. uint32_t areaStart = uint32_t(offset >> pool->granularityLog2); - uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaStart, true)) + 1; + bool isUsed = Support::bitVectorGetBit(block->_usedBitVector, areaStart); + if (ASMJIT_UNLIKELY(!isUsed)) + return DebugUtils::errored(kErrorInvalidArgument); + + uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaStart, true)) + 1; uint32_t areaPrevSize = areaEnd - areaStart; uint32_t areaShrunkSize = pool->areaSizeFromByteSize(newSize); @@ -902,13 +916,55 @@ Error JitAllocator::shrink(void* rxPtr, size_t newSize) noexcept { block->markShrunkArea(areaStart + areaShrunkSize, areaEnd); // Fill released memory if the secure mode is enabled. - if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory)) - JitAllocatorImpl_fillPattern(block->rwPtr() + (areaStart + areaShrunkSize) * pool->granularity, fillPattern(), areaDiff * pool->granularity); + if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory)) { + uint8_t* spanPtr = block->rwPtr() + (areaStart + areaShrunkSize) * pool->granularity; + size_t spanSize = areaDiff * pool->granularity; + + VirtMem::ProtectJitReadWriteScope scope(spanPtr, spanSize); + JitAllocatorImpl_fillPattern(spanPtr, fillPattern(), spanSize); + } } return kErrorOk; } +Error JitAllocator::query(void* rxPtr, void** rxPtrOut, void** rwPtrOut, size_t* sizeOut) const noexcept { + *rxPtrOut = nullptr; + *rwPtrOut = nullptr; + *sizeOut = 0u; + + if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) + return DebugUtils::errored(kErrorNotInitialized); + + JitAllocatorPrivateImpl* impl = static_cast(_impl); + LockGuard guard(impl->lock); + JitAllocatorBlock* block = impl->tree.get(static_cast(rxPtr)); + + if (ASMJIT_UNLIKELY(!block)) + return DebugUtils::errored(kErrorInvalidArgument); + + // Offset relative to the start of the block. + JitAllocatorPool* pool = block->pool(); + size_t offset = (size_t)((uint8_t*)rxPtr - block->rxPtr()); + + // The first bit representing the allocated area and its size. + uint32_t areaStart = uint32_t(offset >> pool->granularityLog2); + + bool isUsed = Support::bitVectorGetBit(block->_usedBitVector, areaStart); + if (ASMJIT_UNLIKELY(!isUsed)) + return DebugUtils::errored(kErrorInvalidArgument); + + uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaStart, true)) + 1; + size_t byteOffset = pool->byteSizeFromAreaSize(areaStart); + size_t byteSize = pool->byteSizeFromAreaSize(areaEnd - areaStart); + + *rxPtrOut = static_cast(block->_mapping.rx) + byteOffset; + *rwPtrOut = static_cast(block->_mapping.rw) + byteOffset; + *sizeOut = byteSize; + + return kErrorOk; +} + // JitAllocator - Tests // ==================== @@ -963,6 +1019,34 @@ class Random { uint64_t _state[2]; }; +namespace JitAllocatorUtils { + static void fillPattern64(void* p_, uint64_t pattern, size_t sizeInBytes) noexcept { + uint64_t* p = static_cast(p_); + size_t n = sizeInBytes / 8u; + + for (size_t i = 0; i < n; i++) + p[i] = pattern; + } + + static bool verifyPattern64(const void* p_, uint64_t pattern, size_t sizeInBytes) noexcept { + const uint64_t* p = static_cast(p_); + size_t n = sizeInBytes / 8u; + + for (size_t i = 0; i < n; i++) { + if (p[i] != pattern) { + INFO("Pattern verification failed at 0x%p [%zu * 8]: value(0x%016llX) != expected(0x%016llX)", + p, + i, + (unsigned long long)p[i], + (unsigned long long)pattern); + return false; + } + } + + return true; + } +} + // Helper class to verify that JitAllocator doesn't return addresses that overlap. class JitAllocatorWrapper { public: @@ -980,9 +1064,19 @@ class JitAllocatorWrapper { class Record : public ZoneTreeNodeT, public Range { public: - inline Record(uint8_t* addr, size_t size) + //! Read/write address, in case this is a dual mapping. + void* _rw; + //! Describes a pattern used to fill the allocated memory. + uint64_t pattern; + + inline Record(void* rx, void* rw, size_t size, uint64_t pattern) : ZoneTreeNodeT(), - Range(addr, size) {} + Range(static_cast(rx), size), + _rw(rw), + pattern(pattern) {} + + inline void* rx() const noexcept { return addr; } + inline void* rw() const noexcept { return _rw; } inline bool operator<(const Record& other) const noexcept { return addr < other.addr; } inline bool operator>(const Record& other) const noexcept { return addr > other.addr; } @@ -995,14 +1089,16 @@ class JitAllocatorWrapper { ZoneAllocator _heap; ZoneTree _records; JitAllocator _allocator; + Random _rng; explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept : _zone(1024 * 1024), _heap(&_zone), - _allocator(params) {} + _allocator(params), + _rng(0x123456789u) {} - void _insert(void* p_, size_t size) noexcept { - uint8_t* p = static_cast(p_); + void _insert(void* pRX, void* pRW, size_t size) noexcept { + uint8_t* p = static_cast(pRX); uint8_t* pEnd = p + size - 1; Record* record; @@ -1015,9 +1111,18 @@ class JitAllocatorWrapper { if (record) EXPECT(record == nullptr, "Address [%p:%p] collides with a newly allocated [%p:%p]\n", record->addr, record->addr + record->size, p, p + size); - record = _heap.newT(p, size); + uint64_t pattern = _rng.nextUInt64(); + record = _heap.newT(pRX, pRW, size, pattern); EXPECT(record != nullptr, "Out of memory, cannot allocate 'Record'"); + { + VirtMem::ProtectJitReadWriteScope scope(pRW, size); + JitAllocatorUtils::fillPattern64(pRW, pattern, size); + } + + VirtMem::flushInstructionCache(pRX, size); + EXPECT(JitAllocatorUtils::verifyPattern64(pRX, pattern, size) == true); + _records.insert(record); } @@ -1025,6 +1130,9 @@ class JitAllocatorWrapper { Record* record = _records.get(static_cast(p)); EXPECT(record != nullptr, "Address [%p] doesn't exist\n", p); + EXPECT(JitAllocatorUtils::verifyPattern64(record->rx(), record->pattern, record->size) == true); + EXPECT(JitAllocatorUtils::verifyPattern64(record->rw(), record->pattern, record->size) == true); + _records.remove(record); _heap.release(record, sizeof(Record)); } @@ -1036,7 +1144,7 @@ class JitAllocatorWrapper { Error err = _allocator.alloc(&rxPtr, &rwPtr, size); EXPECT(err == kErrorOk, "JitAllocator failed to allocate %zu bytes\n", size); - _insert(rxPtr, size); + _insert(rxPtr, rwPtr, size); return rxPtr; } @@ -1100,8 +1208,8 @@ static void BitVectorRangeIterator_testRandom(Random& rnd, size_t count) noexcep } } -UNIT(jit_allocator) { - size_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 100000; +static void test_jit_allocator_alloc_release() noexcept { + size_t kCount = BrokenAPI::hasArg("--quick") ? 20000 : 100000; struct TestParams { const char* name; @@ -1235,8 +1343,34 @@ UNIT(jit_allocator) { ::free(ptrArray); } } -#endif + +static void test_jit_allocator_query() noexcept { + JitAllocator allocator; + + void* rxPtr = nullptr; + void* rwPtr = nullptr; + size_t size = 100; + + EXPECT(allocator.alloc(&rxPtr, &rwPtr, size) == kErrorOk); + EXPECT(rxPtr != nullptr); + EXPECT(rwPtr != nullptr); + + void* rxPtrQueried = nullptr; + void* rwPtrQueried = nullptr; + size_t sizeQueried; + + EXPECT(allocator.query(rxPtr, &rxPtrQueried, &rwPtrQueried, &sizeQueried) == kErrorOk); + EXPECT(rxPtrQueried == rxPtr); + EXPECT(rwPtrQueried == rwPtr); + EXPECT(sizeQueried == Support::alignUp(size, allocator.granularity())); +} + +UNIT(jit_allocator) { + test_jit_allocator_alloc_release(); + test_jit_allocator_query(); +} +#endif // ASMJIT_TEST ASMJIT_END_NAMESPACE -#endif +#endif // !ASMJIT_NO_JIT diff --git a/erts/emulator/asmjit/core/jitallocator.h b/erts/emulator/asmjit/core/jitallocator.h index e8fe69519eeb..40af92924c60 100644 --- a/erts/emulator/asmjit/core/jitallocator.h +++ b/erts/emulator/asmjit/core/jitallocator.h @@ -26,6 +26,10 @@ enum class JitAllocatorOptions : uint32_t { //! The first buffer has read and execute permissions and the second buffer has read+write permissions. //! //! See \ref VirtMem::allocDualMapping() for more details about this feature. + //! + //! \remarks Dual mapping would be automatically turned on by \ref JitAllocator in case of hardened runtime that + //! enforces `W^X` policy, so specifying this flag is essentually forcing to use dual mapped pages even when RWX + //! pages can be allocated and dual mapping is not necessary. kUseDualMapping = 0x00000001u, //! Enables the use of multiple pools with increasing granularity instead of a single pool. This flag would enable diff --git a/erts/emulator/asmjit/core/jitruntime.cpp b/erts/emulator/asmjit/core/jitruntime.cpp index 491c2040fbe5..814353f4b512 100644 --- a/erts/emulator/asmjit/core/jitruntime.cpp +++ b/erts/emulator/asmjit/core/jitruntime.cpp @@ -15,6 +15,7 @@ JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept : _allocator(params) { _environment = Environment::host(); _environment.setObjectFormat(ObjectFormat::kJIT); + _cpuFeatures = CpuInfo::host().features(); } JitRuntime::~JitRuntime() noexcept {} @@ -46,9 +47,6 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept { if (codeSize < estimatedCodeSize) _allocator.shrink(rx, codeSize); - if (codeSize < estimatedCodeSize) - _allocator.shrink(rx, codeSize); - { VirtMem::ProtectJitReadWriteScope rwScope(rx, codeSize); diff --git a/erts/emulator/asmjit/core/operand.h b/erts/emulator/asmjit/core/operand.h index 2f81a217f1bd..634acec85f2d 100644 --- a/erts/emulator/asmjit/core/operand.h +++ b/erts/emulator/asmjit/core/operand.h @@ -994,9 +994,9 @@ class BaseReg : public Operand { } //! Tests whether the `op` is a general purpose register of the given `id`. - static inline bool isGp(const Operand_& op, uint32_t id) noexcept { return isGp(op) & (op.id() == id); } + static inline bool isGp(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGp(op)) & unsigned(op.id() == id)); } //! Tests whether the `op` is a vector register of the given `id`. - static inline bool isVec(const Operand_& op, uint32_t id) noexcept { return isVec(op) & (op.id() == id); } + static inline bool isVec(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVec(op)) & unsigned(op.id() == id)); } //! \} }; @@ -1082,19 +1082,19 @@ template<> \ struct RegTraits { \ typedef REG RegT; \ \ - enum : uint32_t { \ - kValid = uint32_t(true), \ - kCount = uint32_t(COUNT), \ - kType = uint32_t(REG_TYPE), \ - kGroup = uint32_t(GROUP), \ - kSize = uint32_t(SIZE), \ - kTypeId = uint32_t(TYPE_ID), \ + static constexpr uint32_t kValid = 1; \ + static constexpr uint32_t kCount = COUNT; \ + static constexpr RegType kType = REG_TYPE; \ + static constexpr RegGroup kGroup = GROUP; \ + static constexpr uint32_t kSize = SIZE; \ + static constexpr TypeId kTypeId = TYPE_ID; \ + \ + static constexpr uint32_t kSignature = \ + (OperandSignature::fromOpType(OperandType::kReg) | \ + OperandSignature::fromRegType(kType) | \ + OperandSignature::fromRegGroup(kGroup) | \ + OperandSignature::fromSize(kSize)).bits(); \ \ - kSignature = (OperandSignature::fromOpType(OperandType::kReg) | \ - OperandSignature::fromRegType(REG_TYPE) | \ - OperandSignature::fromRegGroup(GROUP) | \ - OperandSignature::fromSize(kSize)).bits(), \ - }; \ } //! Adds constructors and member functions to a class that implements abstract register. Abstract register is register @@ -1135,12 +1135,10 @@ public: \ //! signature. #define ASMJIT_DEFINE_FINAL_REG(REG, BASE, TRAITS) \ public: \ - enum : uint32_t { \ - kThisType = TRAITS::kType, \ - kThisGroup = TRAITS::kGroup, \ - kThisSize = TRAITS::kSize, \ - kSignature = TRAITS::kSignature \ - }; \ + static constexpr RegType kThisType = TRAITS::kType; \ + static constexpr RegGroup kThisGroup = TRAITS::kGroup; \ + static constexpr uint32_t kThisSize = TRAITS::kSize; \ + static constexpr uint32_t kSignature = TRAITS::kSignature; \ \ ASMJIT_DEFINE_ABSTRACT_REG(REG, BASE) \ \ diff --git a/erts/emulator/asmjit/core/osutils.cpp b/erts/emulator/asmjit/core/osutils.cpp index fa900bfbb4ce..18aa2a0c6686 100644 --- a/erts/emulator/asmjit/core/osutils.cpp +++ b/erts/emulator/asmjit/core/osutils.cpp @@ -76,7 +76,7 @@ uint32_t OSUtils::getTickCount() noexcept { uint64_t t = (uint64_t(ts.tv_sec ) * 1000u) + (uint64_t(ts.tv_nsec) / 1000000u); return uint32_t(t & 0xFFFFFFFFu); #else - #pragma message("asmjit::OSUtils::getTickCount() doesn't have implementation for the target OS.") + #pragma message("[asmjit] OSUtils::getTickCount() doesn't have implementation for the target OS.") return 0; #endif } diff --git a/erts/emulator/asmjit/core/raassignment_p.h b/erts/emulator/asmjit/core/raassignment_p.h index 22a97e2b3692..54183293111a 100644 --- a/erts/emulator/asmjit/core/raassignment_p.h +++ b/erts/emulator/asmjit/core/raassignment_p.h @@ -82,6 +82,12 @@ class RAAssignment { size_t size = sizeOf(count); memcpy(this, other, size); } + + inline void unassign(RegGroup group, uint32_t physId, uint32_t indexInWorkIds) noexcept { + assigned.clear(group, Support::bitMask(physId)); + dirty.clear(group, Support::bitMask(physId)); + workIds[indexInWorkIds] = kWorkNone; + } }; struct WorkToPhysMap { @@ -304,6 +310,28 @@ class RAAssignment { _physToWorkIds.swap(other._physToWorkIds); } + inline void assignWorkIdsFromPhysIds() noexcept { + memset(_workToPhysMap, uint8_t(BaseReg::kIdBad), WorkToPhysMap::sizeOf(_layout.workCount)); + + for (RegGroup group : RegGroupVirtValues{}) { + uint32_t physBaseIndex = _layout.physIndex[group]; + Support::BitWordIterator it(_physToWorkMap->assigned[group]); + + while (it.hasNext()) { + uint32_t physId = it.next(); + uint32_t workId = _physToWorkMap->workIds[physBaseIndex + physId]; + + ASMJIT_ASSERT(workId != kWorkNone); + _workToPhysMap->physIds[workId] = uint8_t(physId); + } + } + } + + inline void copyFrom(const PhysToWorkMap* physToWorkMap) noexcept { + memcpy(_physToWorkMap, physToWorkMap, PhysToWorkMap::sizeOf(_layout.physTotal)); + assignWorkIdsFromPhysIds(); + } + inline void copyFrom(const PhysToWorkMap* physToWorkMap, const WorkToPhysMap* workToPhysMap) noexcept { memcpy(_physToWorkMap, physToWorkMap, PhysToWorkMap::sizeOf(_layout.physTotal)); memcpy(_workToPhysMap, workToPhysMap, WorkToPhysMap::sizeOf(_layout.workCount)); diff --git a/erts/emulator/asmjit/core/rabuilders_p.h b/erts/emulator/asmjit/core/rabuilders_p.h index 1b763030c455..9d9b4282d2bb 100644 --- a/erts/emulator/asmjit/core/rabuilders_p.h +++ b/erts/emulator/asmjit/core/rabuilders_p.h @@ -401,7 +401,7 @@ class RACFGBuilderT { if (node->type() == NodeType::kSentinel) { if (node == _funcNode->endNode()) { // Make sure we didn't flow here if this is the end of the function sentinel. - if (ASMJIT_UNLIKELY(_curBlock)) + if (ASMJIT_UNLIKELY(_curBlock && _hasCode)) return DebugUtils::errored(kErrorInvalidState); break; } diff --git a/erts/emulator/asmjit/core/radefs_p.h b/erts/emulator/asmjit/core/radefs_p.h index 426ac2926db3..091b6823674e 100644 --- a/erts/emulator/asmjit/core/radefs_p.h +++ b/erts/emulator/asmjit/core/radefs_p.h @@ -271,8 +271,12 @@ struct RARegMask { } template - inline void op(RegGroup group, uint32_t input) noexcept { - _masks[group] = Operator::op(_masks[group], input); + inline void op(RegGroup group, RegMask mask) noexcept { + _masks[group] = Operator::op(_masks[group], mask); + } + + inline void clear(RegGroup group, RegMask mask) noexcept { + _masks[group] = _masks[group] & ~mask; } //! \} @@ -662,7 +666,7 @@ struct LiveRegData { uint32_t id; inline explicit LiveRegData(uint32_t id = BaseReg::kIdBad) noexcept : id(id) {} - inline LiveRegData(const LiveRegData& other) noexcept : id(other.id) {} + inline LiveRegData(const LiveRegData& other) noexcept = default; inline void init(const LiveRegData& other) noexcept { id = other.id; } diff --git a/erts/emulator/asmjit/core/ralocal.cpp b/erts/emulator/asmjit/core/ralocal.cpp index 54bc524bf3bd..b4d92446b3c8 100644 --- a/erts/emulator/asmjit/core/ralocal.cpp +++ b/erts/emulator/asmjit/core/ralocal.cpp @@ -38,7 +38,9 @@ Error RALocalAllocator::init() noexcept { physToWorkMap = _pass->newPhysToWorkMap(); workToPhysMap = _pass->newWorkToPhysMap(); - if (!physToWorkMap || !workToPhysMap) + _tmpWorkToPhysMap = _pass->newWorkToPhysMap(); + + if (!physToWorkMap || !workToPhysMap || !_tmpWorkToPhysMap) return DebugUtils::errored(kErrorOutOfMemory); _tmpAssignment.initLayout(_pass->_physRegCount, _pass->workRegs()); @@ -122,26 +124,18 @@ Error RALocalAllocator::makeInitialAssignment() noexcept { return kErrorOk; } -Error RALocalAllocator::replaceAssignment( - const PhysToWorkMap* physToWorkMap, - const WorkToPhysMap* workToPhysMap) noexcept { - - _curAssignment.copyFrom(physToWorkMap, workToPhysMap); +Error RALocalAllocator::replaceAssignment(const PhysToWorkMap* physToWorkMap) noexcept { + _curAssignment.copyFrom(physToWorkMap); return kErrorOk; } -Error RALocalAllocator::switchToAssignment( - PhysToWorkMap* dstPhysToWorkMap, - WorkToPhysMap* dstWorkToPhysMap, - const ZoneBitVector& liveIn, - bool dstReadOnly, - bool tryMode) noexcept { - +Error RALocalAllocator::switchToAssignment(PhysToWorkMap* dstPhysToWorkMap, const ZoneBitVector& liveIn, bool dstReadOnly, bool tryMode) noexcept { RAAssignment dst; RAAssignment& cur = _curAssignment; dst.initLayout(_pass->_physRegCount, _pass->workRegs()); - dst.initMaps(dstPhysToWorkMap, dstWorkToPhysMap); + dst.initMaps(dstPhysToWorkMap, _tmpWorkToPhysMap); + dst.assignWorkIdsFromPhysIds(); if (tryMode) return kErrorOk; @@ -329,24 +323,27 @@ Error RALocalAllocator::switchToAssignment( if (!tryMode) { // Here is a code that dumps the conflicting part if something fails here: - // if (!dst.equals(cur)) { - // uint32_t physTotal = dst._layout.physTotal; - // uint32_t workCount = dst._layout.workCount; + // if (!dst.equals(cur)) { + // uint32_t physTotal = dst._layout.physTotal; + // uint32_t workCount = dst._layout.workCount; + // + // fprintf(stderr, "Dirty DST=0x%08X CUR=0x%08X\n", dst.dirty(RegGroup::kGp), cur.dirty(RegGroup::kGp)); + // fprintf(stderr, "Assigned DST=0x%08X CUR=0x%08X\n", dst.assigned(RegGroup::kGp), cur.assigned(RegGroup::kGp)); // - // for (uint32_t physId = 0; physId < physTotal; physId++) { - // uint32_t dstWorkId = dst._physToWorkMap->workIds[physId]; - // uint32_t curWorkId = cur._physToWorkMap->workIds[physId]; - // if (dstWorkId != curWorkId) - // fprintf(stderr, "[PhysIdWork] PhysId=%u WorkId[DST(%u) != CUR(%u)]\n", physId, dstWorkId, curWorkId); - // } + // for (uint32_t physId = 0; physId < physTotal; physId++) { + // uint32_t dstWorkId = dst._physToWorkMap->workIds[physId]; + // uint32_t curWorkId = cur._physToWorkMap->workIds[physId]; + // if (dstWorkId != curWorkId) + // fprintf(stderr, "[PhysIdWork] PhysId=%u WorkId[DST(%u) != CUR(%u)]\n", physId, dstWorkId, curWorkId); + // } // - // for (uint32_t workId = 0; workId < workCount; workId++) { - // uint32_t dstPhysId = dst._workToPhysMap->physIds[workId]; - // uint32_t curPhysId = cur._workToPhysMap->physIds[workId]; - // if (dstPhysId != curPhysId) - // fprintf(stderr, "[WorkToPhys] WorkId=%u PhysId[DST(%u) != CUR(%u)]\n", workId, dstPhysId, curPhysId); - // } + // for (uint32_t workId = 0; workId < workCount; workId++) { + // uint32_t dstPhysId = dst._workToPhysMap->physIds[workId]; + // uint32_t curPhysId = cur._workToPhysMap->physIds[workId]; + // if (dstPhysId != curPhysId) + // fprintf(stderr, "[WorkToPhys] WorkId=%u PhysId[DST(%u) != CUR(%u)]\n", workId, dstPhysId, curPhysId); // } + // } ASMJIT_ASSERT(dst.equals(cur)); } @@ -839,6 +836,34 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept { // STEP 9 // ------ // + // Vector registers can be cloberred partially by invoke - find if that's the case and clobber when necessary. + + if (node->isInvoke() && group == RegGroup::kVec) { + const InvokeNode* invokeNode = node->as(); + + RegMask maybeClobberedRegs = invokeNode->detail().callConv().preservedRegs(group) & _curAssignment.assigned(group); + if (maybeClobberedRegs) { + uint32_t saveRestoreVecSize = invokeNode->detail().callConv().saveRestoreRegSize(group); + Support::BitWordIterator it(maybeClobberedRegs); + + do { + uint32_t physId = it.next(); + uint32_t workId = _curAssignment.physToWorkId(group, physId); + + RAWorkReg* workReg = workRegById(workId); + uint32_t virtSize = workReg->virtReg()->virtSize(); + + if (virtSize > saveRestoreVecSize) { + ASMJIT_PROPAGATE(onSpillReg(group, workId, physId)); + } + + } while (it.hasNext()); + } + } + + // STEP 10 + // ------- + // // Assign OUT registers. if (outPending) { @@ -981,12 +1006,7 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co // Use TryMode of `switchToAssignment()` if possible. if (target->hasEntryAssignment()) { - ASMJIT_PROPAGATE(switchToAssignment( - target->entryPhysToWorkMap(), - target->entryWorkToPhysMap(), - target->liveIn(), - target->isAllocated(), - true)); + ASMJIT_PROPAGATE(switchToAssignment(target->entryPhysToWorkMap(), target->liveIn(), target->isAllocated(), true)); } ASMJIT_PROPAGATE(allocInst(node)); @@ -997,12 +1017,7 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co BaseNode* prevCursor = _cc->setCursor(injectionPoint); _tmpAssignment.copyFrom(_curAssignment); - ASMJIT_PROPAGATE(switchToAssignment( - target->entryPhysToWorkMap(), - target->entryWorkToPhysMap(), - target->liveIn(), - target->isAllocated(), - false)); + ASMJIT_PROPAGATE(switchToAssignment(target->entryPhysToWorkMap(), target->liveIn(), target->isAllocated(), false)); BaseNode* curCursor = _cc->cursor(); if (curCursor != injectionPoint) { @@ -1060,7 +1075,6 @@ Error RALocalAllocator::allocJumpTable(InstNode* node, const RABlocks& targets, if (!sharedAssignment.empty()) { ASMJIT_PROPAGATE(switchToAssignment( sharedAssignment.physToWorkMap(), - sharedAssignment.workToPhysMap(), sharedAssignment.liveIn(), true, // Read-only. false // Try-mode. diff --git a/erts/emulator/asmjit/core/ralocal_p.h b/erts/emulator/asmjit/core/ralocal_p.h index 05467c5b265c..b40e8674274d 100644 --- a/erts/emulator/asmjit/core/ralocal_p.h +++ b/erts/emulator/asmjit/core/ralocal_p.h @@ -57,6 +57,9 @@ class RALocalAllocator { //! TiedReg's total counter. RARegCount _tiedCount; + //! Temporary workToPhysMap that can be used freely by the allocator. + WorkToPhysMap* _tmpWorkToPhysMap; + //! \name Construction & Destruction //! \{ @@ -113,9 +116,7 @@ class RALocalAllocator { Error makeInitialAssignment() noexcept; - Error replaceAssignment( - const PhysToWorkMap* physToWorkMap, - const WorkToPhysMap* workToPhysMap) noexcept; + Error replaceAssignment(const PhysToWorkMap* physToWorkMap) noexcept; //! Switch to the given assignment by reassigning all register and emitting code that reassigns them. //! This is always used to switch to a previously stored assignment. @@ -123,12 +124,7 @@ class RALocalAllocator { //! If `tryMode` is true then the final assignment doesn't have to be exactly same as specified by `dstPhysToWorkMap` //! and `dstWorkToPhysMap`. This mode is only used before conditional jumps that already have assignment to generate //! a code sequence that is always executed regardless of the flow. - Error switchToAssignment( - PhysToWorkMap* dstPhysToWorkMap, - WorkToPhysMap* dstWorkToPhysMap, - const ZoneBitVector& liveIn, - bool dstReadOnly, - bool tryMode) noexcept; + Error switchToAssignment(PhysToWorkMap* dstPhysToWorkMap, const ZoneBitVector& liveIn, bool dstReadOnly, bool tryMode) noexcept; inline Error spillRegsBeforeEntry(RABlock* block) noexcept { return spillScratchGpRegsBeforeEntry(block->entryScratchGpRegs()); diff --git a/erts/emulator/asmjit/core/rapass.cpp b/erts/emulator/asmjit/core/rapass.cpp index 79709f69d63c..29b7dea9f893 100644 --- a/erts/emulator/asmjit/core/rapass.cpp +++ b/erts/emulator/asmjit/core/rapass.cpp @@ -114,11 +114,14 @@ Error BaseRAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) { #ifndef ASMJIT_NO_LOGGING _logger = logger; _formatOptions.reset(); - _diagnosticOptions = DiagnosticOptions::kNone; + _diagnosticOptions = _cb->diagnosticOptions(); if (logger) { _formatOptions = logger->options(); - _diagnosticOptions = _cb->diagnosticOptions(); + } + else { + _diagnosticOptions &= ~(DiagnosticOptions::kRADebugCFG | + DiagnosticOptions::kRADebugUnreachable); } #else DebugUtils::unused(logger); @@ -328,9 +331,14 @@ Error BaseRAPass::initSharedAssignments(const ZoneVector& sharedAssign RABlock* firstSuccessor = successors[0]; // NOTE: Shared assignments connect all possible successors so we only need the first to propagate exit scratch // GP registers. - ASMJIT_ASSERT(firstSuccessor->hasSharedAssignmentId()); - RASharedAssignment& sa = _sharedAssignments[firstSuccessor->sharedAssignmentId()]; - sa.addEntryScratchGpRegs(block->exitScratchGpRegs()); + if (firstSuccessor->hasSharedAssignmentId()) { + RASharedAssignment& sa = _sharedAssignments[firstSuccessor->sharedAssignmentId()]; + sa.addEntryScratchGpRegs(block->exitScratchGpRegs()); + } + else { + // This is only allowed if there is a single successor - in that case shared assignment is not necessary. + ASMJIT_ASSERT(successors.size() == 1u); + } } } if (block->hasSharedAssignmentId()) { @@ -1483,18 +1491,12 @@ Error BaseRAPass::runLocalAllocator() noexcept { cc()->_setCursor(unconditionalJump ? prev->prev() : prev); if (consecutive->hasEntryAssignment()) { - ASMJIT_PROPAGATE( - lra.switchToAssignment( - consecutive->entryPhysToWorkMap(), - consecutive->entryWorkToPhysMap(), - consecutive->liveIn(), - consecutive->isAllocated(), - false)); + ASMJIT_PROPAGATE(lra.switchToAssignment(consecutive->entryPhysToWorkMap(), consecutive->liveIn(), consecutive->isAllocated(), false)); } else { ASMJIT_PROPAGATE(lra.spillRegsBeforeEntry(consecutive)); ASMJIT_PROPAGATE(setBlockEntryAssignment(consecutive, block, lra._curAssignment)); - lra._curAssignment.copyFrom(consecutive->entryPhysToWorkMap(), consecutive->entryWorkToPhysMap()); + lra._curAssignment.copyFrom(consecutive->entryPhysToWorkMap()); } } @@ -1526,7 +1528,7 @@ Error BaseRAPass::runLocalAllocator() noexcept { } // If we switched to some block we have to update the local allocator. - lra.replaceAssignment(block->entryPhysToWorkMap(), block->entryWorkToPhysMap()); + lra.replaceAssignment(block->entryPhysToWorkMap()); } _clobberedRegs.op(lra._clobberedRegs); @@ -1546,12 +1548,10 @@ Error BaseRAPass::setBlockEntryAssignment(RABlock* block, const RABlock* fromBlo } PhysToWorkMap* physToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap()); - WorkToPhysMap* workToPhysMap = cloneWorkToPhysMap(fromAssignment.workToPhysMap()); - - if (ASMJIT_UNLIKELY(!physToWorkMap || !workToPhysMap)) + if (ASMJIT_UNLIKELY(!physToWorkMap)) return DebugUtils::errored(kErrorOutOfMemory); - block->setEntryAssignment(physToWorkMap, workToPhysMap); + block->setEntryAssignment(physToWorkMap); // True if this is the first (entry) block, nothing to do in this case. if (block == fromBlock) { @@ -1562,10 +1562,6 @@ Error BaseRAPass::setBlockEntryAssignment(RABlock* block, const RABlock* fromBlo return kErrorOk; } - RAAssignment as; - as.initLayout(_physRegCount, workRegs()); - as.initMaps(physToWorkMap, workToPhysMap); - const ZoneBitVector& liveOut = fromBlock->liveOut(); const ZoneBitVector& liveIn = block->liveIn(); @@ -1578,94 +1574,85 @@ Error BaseRAPass::setBlockEntryAssignment(RABlock* block, const RABlock* fromBlo RAWorkReg* workReg = workRegById(workId); RegGroup group = workReg->group(); - uint32_t physId = as.workToPhysId(group, workId); + uint32_t physId = fromAssignment.workToPhysId(group, workId); if (physId != RAAssignment::kPhysNone) - as.unassign(group, workId, physId); + physToWorkMap->unassign(group, physId, _physRegIndex.get(group) + physId); } } - return blockEntryAssigned(as); + return blockEntryAssigned(physToWorkMap); } Error BaseRAPass::setSharedAssignment(uint32_t sharedAssignmentId, const RAAssignment& fromAssignment) noexcept { ASMJIT_ASSERT(_sharedAssignments[sharedAssignmentId].empty()); PhysToWorkMap* physToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap()); - WorkToPhysMap* workToPhysMap = cloneWorkToPhysMap(fromAssignment.workToPhysMap()); - - if (ASMJIT_UNLIKELY(!physToWorkMap || !workToPhysMap)) + if (ASMJIT_UNLIKELY(!physToWorkMap)) return DebugUtils::errored(kErrorOutOfMemory); - _sharedAssignments[sharedAssignmentId].assignMaps(physToWorkMap, workToPhysMap); + _sharedAssignments[sharedAssignmentId].assignPhysToWorkMap(physToWorkMap); + ZoneBitVector& sharedLiveIn = _sharedAssignments[sharedAssignmentId]._liveIn; ASMJIT_PROPAGATE(sharedLiveIn.resize(allocator(), workRegCount())); - RAAssignment as; - as.initLayout(_physRegCount, workRegs()); - Support::Array sharedAssigned {}; - for (RABlock* block : blocks()) { if (block->sharedAssignmentId() == sharedAssignmentId) { ASMJIT_ASSERT(!block->hasEntryAssignment()); PhysToWorkMap* entryPhysToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap()); - WorkToPhysMap* entryWorkToPhysMap = cloneWorkToPhysMap(fromAssignment.workToPhysMap()); - - if (ASMJIT_UNLIKELY(!entryPhysToWorkMap || !entryWorkToPhysMap)) + if (ASMJIT_UNLIKELY(!entryPhysToWorkMap)) return DebugUtils::errored(kErrorOutOfMemory); - block->setEntryAssignment(entryPhysToWorkMap, entryWorkToPhysMap); - as.initMaps(entryPhysToWorkMap, entryWorkToPhysMap); + block->setEntryAssignment(entryPhysToWorkMap); const ZoneBitVector& liveIn = block->liveIn(); sharedLiveIn.or_(liveIn); for (RegGroup group : RegGroupVirtValues{}) { sharedAssigned[group] |= entryPhysToWorkMap->assigned[group]; + + uint32_t physBaseIndex = _physRegIndex.get(group); Support::BitWordIterator it(entryPhysToWorkMap->assigned[group]); while (it.hasNext()) { uint32_t physId = it.next(); - uint32_t workId = as.physToWorkId(group, physId); + uint32_t workId = entryPhysToWorkMap->workIds[physBaseIndex + physId]; if (!liveIn.bitAt(workId)) - as.unassign(group, workId, physId); + entryPhysToWorkMap->unassign(group, physId, physBaseIndex + physId); } } } } - { - as.initMaps(physToWorkMap, workToPhysMap); - - for (RegGroup group : RegGroupVirtValues{}) { - Support::BitWordIterator it(_availableRegs[group] & ~sharedAssigned[group]); + for (RegGroup group : RegGroupVirtValues{}) { + uint32_t physBaseIndex = _physRegIndex.get(group); + Support::BitWordIterator it(_availableRegs[group] & ~sharedAssigned[group]); - while (it.hasNext()) { - uint32_t physId = it.next(); - if (as.isPhysAssigned(group, physId)) { - uint32_t workId = as.physToWorkId(group, physId); - as.unassign(group, workId, physId); - } - } + while (it.hasNext()) { + uint32_t physId = it.next(); + if (Support::bitTest(physToWorkMap->assigned[group], physId)) + physToWorkMap->unassign(group, physId, physBaseIndex + physId); } } - return blockEntryAssigned(as); + return blockEntryAssigned(physToWorkMap); } -Error BaseRAPass::blockEntryAssigned(const RAAssignment& as) noexcept { +Error BaseRAPass::blockEntryAssigned(const PhysToWorkMap* physToWorkMap) noexcept { // Complex allocation strategy requires to record register assignments upon block entry (or per shared state). for (RegGroup group : RegGroupVirtValues{}) { if (!_strategy[group].isComplex()) continue; - Support::BitWordIterator it(as.assigned(group)); + uint32_t physBaseIndex = _physRegIndex[group]; + Support::BitWordIterator it(physToWorkMap->assigned[group]); + while (it.hasNext()) { uint32_t physId = it.next(); - uint32_t workId = as.physToWorkId(group, physId); + uint32_t workId = physToWorkMap->workIds[physBaseIndex + physId]; RAWorkReg* workReg = workRegById(workId); workReg->addAllocatedMask(Support::bitMask(physId)); diff --git a/erts/emulator/asmjit/core/rapass_p.h b/erts/emulator/asmjit/core/rapass_p.h index 098c5c9e1dc3..94738293667f 100644 --- a/erts/emulator/asmjit/core/rapass_p.h +++ b/erts/emulator/asmjit/core/rapass_p.h @@ -129,10 +129,8 @@ class RABlock { //! Scratch registers used at exit, by a terminator instruction. RegMask _exitScratchGpRegs = 0; - //! Register assignment (PhysToWork) on entry. + //! Register assignment on entry. PhysToWorkMap* _entryPhysToWorkMap = nullptr; - //! Register assignment (WorkToPhys) on entry. - WorkToPhysMap* _entryWorkToPhysMap = nullptr; //! \} @@ -247,13 +245,8 @@ class RABlock { } inline bool hasEntryAssignment() const noexcept { return _entryPhysToWorkMap != nullptr; } - inline WorkToPhysMap* entryWorkToPhysMap() const noexcept { return _entryWorkToPhysMap; } inline PhysToWorkMap* entryPhysToWorkMap() const noexcept { return _entryPhysToWorkMap; } - - inline void setEntryAssignment(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept { - _entryPhysToWorkMap = physToWorkMap; - _entryWorkToPhysMap = workToPhysMap; - } + inline void setEntryAssignment(PhysToWorkMap* physToWorkMap) noexcept { _entryPhysToWorkMap = physToWorkMap; } //! \} @@ -283,6 +276,8 @@ class RAInst { //! Parent block. RABlock* _block; + //! Instruction RW flags. + InstRWFlags _instRWFlags; //! Aggregated RATiedFlags from all operands & instruction specific flags. RATiedFlags _flags; //! Total count of RATiedReg's. @@ -305,9 +300,10 @@ class RAInst { //! \name Construction & Destruction //! \{ - inline RAInst(RABlock* block, RATiedFlags flags, uint32_t tiedTotal, const RARegMask& clobberedRegs) noexcept { + inline RAInst(RABlock* block, InstRWFlags instRWFlags, RATiedFlags tiedFlags, uint32_t tiedTotal, const RARegMask& clobberedRegs) noexcept { _block = block; - _flags = flags; + _instRWFlags = instRWFlags; + _flags = tiedFlags; _tiedTotal = tiedTotal; _tiedIndex.reset(); _tiedCount.reset(); @@ -321,6 +317,13 @@ class RAInst { //! \name Accessors //! \{ + //! Returns instruction RW flags. + inline InstRWFlags instRWFlags() const noexcept { return _instRWFlags; }; + //! Tests whether the given `flag` is present in instruction RW flags. + inline bool hasInstRWFlag(InstRWFlags flag) const noexcept { return Support::test(_instRWFlags, flag); } + //! Adds `flags` to instruction RW flags. + inline void addInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags |= flags; } + //! Returns the instruction flags. inline RATiedFlags flags() const noexcept { return _flags; } //! Tests whether the instruction has flag `flag`. @@ -383,6 +386,9 @@ class RAInstBuilder { //! \name Members //! \{ + //! Instruction RW flags. + InstRWFlags _instRWFlags; + //! Flags combined from all RATiedReg's. RATiedFlags _aggregatedFlags; //! Flags that will be cleared before storing the aggregated flags to `RAInst`. @@ -407,6 +413,7 @@ class RAInstBuilder { inline void init() noexcept { reset(); } inline void reset() noexcept { + _instRWFlags = InstRWFlags::kNone; _aggregatedFlags = RATiedFlags::kNone; _forbiddenFlags = RATiedFlags::kNone; _count.reset(); @@ -421,10 +428,15 @@ class RAInstBuilder { //! \name Accessors //! \{ - inline RATiedFlags aggregatedFlags() const noexcept { return _aggregatedFlags; } - inline RATiedFlags forbiddenFlags() const noexcept { return _forbiddenFlags; } + inline InstRWFlags instRWFlags() const noexcept { return _instRWFlags; } + inline bool hasInstRWFlag(InstRWFlags flag) const noexcept { return Support::test(_instRWFlags, flag); } + inline void addInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags |= flags; } + inline void clearInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags &= ~flags; } + inline RATiedFlags aggregatedFlags() const noexcept { return _aggregatedFlags; } inline void addAggregatedFlags(RATiedFlags flags) noexcept { _aggregatedFlags |= flags; } + + inline RATiedFlags forbiddenFlags() const noexcept { return _forbiddenFlags; } inline void addForbiddenFlags(RATiedFlags flags) noexcept { _forbiddenFlags |= flags; } //! Returns the number of tied registers added to the builder. @@ -616,8 +628,6 @@ class RASharedAssignment { ZoneBitVector _liveIn {}; //! Register assignment (PhysToWork). PhysToWorkMap* _physToWorkMap = nullptr; - //! Register assignment (WorkToPhys). - WorkToPhysMap* _workToPhysMap = nullptr; //! \} @@ -632,12 +642,7 @@ class RASharedAssignment { inline const ZoneBitVector& liveIn() const noexcept { return _liveIn; } inline PhysToWorkMap* physToWorkMap() const noexcept { return _physToWorkMap; } - inline WorkToPhysMap* workToPhysMap() const noexcept { return _workToPhysMap; } - - inline void assignMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept { - _physToWorkMap = physToWorkMap; - _workToPhysMap = workToPhysMap; - } + inline void assignPhysToWorkMap(PhysToWorkMap* physToWorkMap) noexcept { _physToWorkMap = physToWorkMap; } //! \} }; @@ -873,16 +878,16 @@ class BaseRAPass : public FuncPass { return _exits.append(allocator(), block); } - ASMJIT_FORCE_INLINE RAInst* newRAInst(RABlock* block, RATiedFlags flags, uint32_t tiedRegCount, const RARegMask& clobberedRegs) noexcept { + ASMJIT_FORCE_INLINE RAInst* newRAInst(RABlock* block, InstRWFlags instRWFlags, RATiedFlags flags, uint32_t tiedRegCount, const RARegMask& clobberedRegs) noexcept { void* p = zone()->alloc(RAInst::sizeOf(tiedRegCount)); if (ASMJIT_UNLIKELY(!p)) return nullptr; - return new(p) RAInst(block, flags, tiedRegCount, clobberedRegs); + return new(p) RAInst(block, instRWFlags, flags, tiedRegCount, clobberedRegs); } ASMJIT_FORCE_INLINE Error assignRAInst(BaseNode* node, RABlock* block, RAInstBuilder& ib) noexcept { uint32_t tiedRegCount = ib.tiedRegCount(); - RAInst* raInst = newRAInst(block, ib.aggregatedFlags(), tiedRegCount, ib._clobbered); + RAInst* raInst = newRAInst(block, ib.instRWFlags(), ib.aggregatedFlags(), tiedRegCount, ib._clobbered); if (ASMJIT_UNLIKELY(!raInst)) return DebugUtils::errored(kErrorOutOfMemory); @@ -1066,13 +1071,6 @@ class BaseRAPass : public FuncPass { return static_cast(zone()->dupAligned(map, size, sizeof(uint32_t))); } - inline WorkToPhysMap* cloneWorkToPhysMap(const WorkToPhysMap* map) noexcept { - size_t size = WorkToPhysMap::sizeOf(_workRegs.size()); - if (ASMJIT_UNLIKELY(size == 0)) - return const_cast(map); - return static_cast(zone()->dup(map, size)); - } - //! \name Liveness Analysis & Statistics //! \{ @@ -1110,7 +1108,7 @@ class BaseRAPass : public FuncPass { //! Called after the RA assignment has been assigned to a block. //! //! This cannot change the assignment, but can examine it. - Error blockEntryAssigned(const RAAssignment& as) noexcept; + Error blockEntryAssigned(const PhysToWorkMap* physToWorkMap) noexcept; //! \} diff --git a/erts/emulator/asmjit/core/rastack.cpp b/erts/emulator/asmjit/core/rastack.cpp index 2b7ed592df5e..318fbded4b37 100644 --- a/erts/emulator/asmjit/core/rastack.cpp +++ b/erts/emulator/asmjit/core/rastack.cpp @@ -62,7 +62,7 @@ Error RAStackAllocator::calculateStackFrame() noexcept { // STEP 1: // - // Update usage based on the size of the slot. We boost smaller slots in a way that 32-bit register has higher + // Update usage based on the size of the slot. We boost smaller slots in a way that 32-bit register has a higher // priority than a 128-bit register, however, if one 128-bit register is used 4 times more than some other 32-bit // register it will overweight it. for (RAStackSlot* slot : _slots) { diff --git a/erts/emulator/asmjit/core/support.h b/erts/emulator/asmjit/core/support.h index e55b8084dbf3..b155cdfa909b 100644 --- a/erts/emulator/asmjit/core/support.h +++ b/erts/emulator/asmjit/core/support.h @@ -939,6 +939,18 @@ static ASMJIT_FORCE_INLINE int cmpInstName(const char* a, const char* b, size_t return int(uint8_t(a[size])); } +//! Compares two string views. +static ASMJIT_FORCE_INLINE int compareStringViews(const char* aData, size_t aSize, const char* bData, size_t bSize) noexcept { + size_t size = Support::min(aSize, bSize); + + for (size_t i = 0; i < size; i++) { + int c = int(uint8_t(aData[i])) - int(uint8_t(bData[i])); + if (c != 0) + return c; + } + + return int(aSize) - int(bSize); +} // Support - Memory Read Access - 8 Bits // ===================================== @@ -1227,34 +1239,11 @@ class BitWordIterator { ASMJIT_FORCE_INLINE uint32_t next() noexcept { ASMJIT_ASSERT(_bitWord != 0); uint32_t index = ctz(_bitWord); - _bitWord ^= T(1u) << index; - return index; - } - - T _bitWord; -}; - -// Support - BitWordFlipIterator -// ============================= - -template -class BitWordFlipIterator { -public: - ASMJIT_FORCE_INLINE explicit BitWordFlipIterator(T bitWord) noexcept - : _bitWord(bitWord) {} - - ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; } - ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; } - - ASMJIT_FORCE_INLINE uint32_t nextAndFlip() noexcept { - ASMJIT_ASSERT(_bitWord != 0); - uint32_t index = ctz(_bitWord); - _bitWord ^= T(1u) << index; + _bitWord &= T(_bitWord - 1); return index; } T _bitWord; - T _xorMask; }; // Support - BitVectorOps @@ -1406,7 +1395,7 @@ class BitVectorIterator { ASMJIT_ASSERT(bitWord != T(0)); uint32_t bit = ctz(bitWord); - bitWord ^= T(1u) << bit; + bitWord &= T(bitWord - 1u); size_t n = _idx + bit; while (!bitWord && (_idx += bitSizeOf()) < _end) @@ -1471,7 +1460,7 @@ class BitVectorOpIterator { ASMJIT_ASSERT(bitWord != T(0)); uint32_t bit = ctz(bitWord); - bitWord ^= T(1u) << bit; + bitWord &= T(bitWord - 1u); size_t n = _idx + bit; while (!bitWord && (_idx += kTSizeInBits) < _end) diff --git a/erts/emulator/asmjit/core/support_p.h b/erts/emulator/asmjit/core/support_p.h new file mode 100644 index 000000000000..a3de944dc0c8 --- /dev/null +++ b/erts/emulator/asmjit/core/support_p.h @@ -0,0 +1,64 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#ifndef ASMJIT_CORE_SUPPORT_P_H_INCLUDED +#define ASMJIT_CORE_SUPPORT_P_H_INCLUDED + +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_utilities +//! \{ + +namespace Support { + +//! \cond INTERNAL + +static ASMJIT_FORCE_INLINE char decode5BitChar(uint32_t c) noexcept { + uint32_t base = c <= 26 ? uint32_t('a') - 1u : uint32_t('0') - 27u; + return char(base + c); +} + +static ASMJIT_FORCE_INLINE size_t decodeInstName(char nameOut[32], uint32_t index, const char* stringTable) noexcept { + size_t i; + + if (index & 0x80000000u) { + // Small string of 5-bit characters. + for (i = 0; i < 6; i++, index >>= 5) { + uint32_t c = index & 0x1F; + if (c == 0) + break; + nameOut[i] = decode5BitChar(c); + } + return i; + } + else { + size_t prefixBase = index & 0xFFFu; + size_t prefixSize = (index >> 12) & 0xFu; + + size_t suffixBase = (index >> 16) & 0xFFFu; + size_t suffixSize = (index >> 28) & 0x7u; + + for (i = 0; i < prefixSize; i++) + nameOut[i] = stringTable[prefixBase + i]; + + char* suffixOut = nameOut + prefixSize; + for (i = 0; i < suffixSize; i++) + suffixOut[i] = stringTable[suffixBase + i]; + + return prefixSize + suffixSize; + } +} + +//! \endcond + +} // {Support} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_SUPPORT_P_H_INCLUDED diff --git a/erts/emulator/asmjit/core/target.cpp b/erts/emulator/asmjit/core/target.cpp index fef025d709a1..cbc6ab51092f 100644 --- a/erts/emulator/asmjit/core/target.cpp +++ b/erts/emulator/asmjit/core/target.cpp @@ -8,7 +8,9 @@ ASMJIT_BEGIN_NAMESPACE -Target::Target() noexcept : _environment() {} +Target::Target() noexcept + : _environment{}, + _cpuFeatures{} {} Target::~Target() noexcept {} ASMJIT_END_NAMESPACE diff --git a/erts/emulator/asmjit/core/target.h b/erts/emulator/asmjit/core/target.h index 23b0c6294c98..322a338f97d7 100644 --- a/erts/emulator/asmjit/core/target.h +++ b/erts/emulator/asmjit/core/target.h @@ -7,6 +7,7 @@ #define ASMJIT_CORE_TARGET_H_INCLUDED #include "../core/archtraits.h" +#include "../core/cpuinfo.h" #include "../core/func.h" ASMJIT_BEGIN_NAMESPACE @@ -22,6 +23,8 @@ class ASMJIT_VIRTAPI Target { //! Target environment information. Environment _environment; + //! Target CPU features. + CpuFeatures _cpuFeatures; //! \name Construction & Destruction //! \{ @@ -43,6 +46,9 @@ class ASMJIT_VIRTAPI Target { //! Returns the target sub-architecture. inline SubArch subArch() const noexcept { return _environment.subArch(); } + //! Returns target CPU features. + inline const CpuFeatures& cpuFeatures() const noexcept { return _cpuFeatures; } + //! \} }; diff --git a/erts/emulator/asmjit/core/virtmem.cpp b/erts/emulator/asmjit/core/virtmem.cpp index 43766ef2cd23..103b51197bcb 100644 --- a/erts/emulator/asmjit/core/virtmem.cpp +++ b/erts/emulator/asmjit/core/virtmem.cpp @@ -42,33 +42,39 @@ #if !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif -#endif -#include + #define ASMJIT_ANONYMOUS_MEMORY_USE_FD -#if defined(__APPLE__) || defined(__BIONIC__) - #define ASMJIT_VM_SHM_DETECT 0 -#else - #define ASMJIT_VM_SHM_DETECT 1 -#endif + #if defined(__APPLE__) || defined(__BIONIC__) + #define ASMJIT_VM_SHM_DETECT 0 + #else + #define ASMJIT_VM_SHM_DETECT 1 + #endif -// Android NDK doesn't provide `shm_open()` and `shm_unlink()`. -#if defined(__BIONIC__) - #define ASMJIT_VM_SHM_AVAILABLE 0 -#else - #define ASMJIT_VM_SHM_AVAILABLE 1 -#endif + // Android NDK doesn't provide `shm_open()` and `shm_unlink()`. + #if !defined(__BIONIC__) + #define ASMJIT_HAS_SHM_OPEN_AND_UNLINK + #endif -#if defined(__APPLE__) && ASMJIT_ARCH_ARM >= 64 - #define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP + #if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 + #define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP + #endif + + #if defined(__NetBSD__) && defined(MAP_REMAPDUP) && defined(PROT_MPROTECT) + #undef ASMJIT_ANONYMOUS_MEMORY_USE_FD + #define ASMJIT_ANONYMOUS_MEMORY_USE_REMAPDUP + #endif #endif +#include + ASMJIT_BEGIN_SUB_NAMESPACE(VirtMem) // Virtual Memory Utilities // ======================== -static const MemoryFlags dualMappingFilter[2] = { +ASMJIT_MAYBE_UNUSED +static const constexpr MemoryFlags dualMappingFilter[2] = { MemoryFlags::kAccessWrite | MemoryFlags::kMMapMaxAccessWrite, MemoryFlags::kAccessExecute | MemoryFlags::kMMapMaxAccessExecute }; @@ -219,19 +225,8 @@ Error releaseDualMapping(DualMapping* dm, size_t size) noexcept { #if !defined(_WIN32) -static void getVMInfo(Info& vmInfo) noexcept { - uint32_t pageSize = uint32_t(::getpagesize()); - - vmInfo.pageSize = pageSize; - vmInfo.pageGranularity = Support::max(pageSize, 65536); -} - -#if !defined(SHM_ANON) -static const char* getTmpDir() noexcept { - const char* tmpDir = getenv("TMPDIR"); - return tmpDir ? tmpDir : "/tmp"; -} -#endif +// Virtual Memory [Posix] - Utilities +// ================================== // Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`. static Error asmjitErrorFromErrno(int e) noexcept { @@ -256,16 +251,61 @@ static Error asmjitErrorFromErrno(int e) noexcept { } } +static void getVMInfo(Info& vmInfo) noexcept { + uint32_t pageSize = uint32_t(::getpagesize()); + + vmInfo.pageSize = pageSize; + vmInfo.pageGranularity = Support::max(pageSize, 65536); +} + +#if defined(__APPLE__) && TARGET_OS_OSX +static int getOSXVersion() noexcept { + // MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave). + static std::atomic globalVersion; + + int ver = globalVersion.load(); + if (!ver) { + struct utsname osname {}; + uname(&osname); + ver = atoi(osname.release); + globalVersion.store(ver); + } + + return ver; +} +#endif // __APPLE__ && TARGET_OS_OSX + +// Returns `mmap()` protection flags from \ref MemoryFlags. +static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept { + int protection = 0; + if (Support::test(memoryFlags, MemoryFlags::kAccessRead)) protection |= PROT_READ; + if (Support::test(memoryFlags, MemoryFlags::kAccessWrite)) protection |= PROT_READ | PROT_WRITE; + if (Support::test(memoryFlags, MemoryFlags::kAccessExecute)) protection |= PROT_READ | PROT_EXEC; + return protection; +} + +// Virtual Memory [Posix] - Anonymus Memory +// ======================================== + +#if defined(ASMJIT_ANONYMOUS_MEMORY_USE_FD) + // Some operating systems don't allow /dev/shm to be executable. On Linux this happens when /dev/shm is mounted with // 'noexec', which is enforced by systemd. Other operating systems like MacOS also restrict executable permissions // regarding /dev/shm, so we use a runtime detection before attempting to allocate executable memory. Sometimes we -// don't need the detection as we know it would always result in `ShmStrategy::kTmpDir`. -enum class ShmStrategy : uint32_t { +// don't need the detection as we know it would always result in `AnonymousMemoryStrategy::kTmpDir`. +enum class AnonymousMemoryStrategy : uint32_t { kUnknown = 0, kDevShm = 1, kTmpDir = 2 }; +#if !defined(SHM_ANON) +static const char* getTmpDir() noexcept { + const char* tmpDir = getenv("TMPDIR"); + return tmpDir ? tmpDir : "/tmp"; +} +#endif + class AnonymousMemory { public: enum FileType : uint32_t { @@ -294,9 +334,13 @@ class AnonymousMemory { #if defined(__linux__) && defined(__NR_memfd_create) // Linux specific 'memfd_create' - if the syscall returns `ENOSYS` it means // it's not available and we will never call it again (would be pointless). + // + // NOTE: There is also memfd_create() libc function in FreeBSD, but it internally + // uses `shm_open(SHM_ANON, ...)` so it's not needed to add support for it (it's + // not a syscall as in Linux). // Zero initialized, if ever changed to '1' that would mean the syscall is not - // available and we must use `shm_open()` and `shm_unlink()`. + // available and we must use `shm_open()` and `shm_unlink()` (or regular `open()`). static volatile uint32_t memfd_create_not_supported; if (!memfd_create_not_supported) { @@ -347,7 +391,7 @@ class AnonymousMemory { return kErrorOk; } } -#if ASMJIT_VM_SHM_AVAILABLE +#ifdef ASMJIT_HAS_SHM_OPEN_AND_UNLINK else { _tmpName.assignFormat(kShmFormat, (unsigned long long)bits); _fd = ::shm_open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); @@ -371,7 +415,7 @@ class AnonymousMemory { FileType type = _fileType; _fileType = kFileTypeNone; -#if ASMJIT_VM_SHM_AVAILABLE +#ifdef ASMJIT_HAS_SHM_OPEN_AND_UNLINK if (type == kFileTypeShm) { ::shm_unlink(_tmpName.data()); return; @@ -400,21 +444,61 @@ class AnonymousMemory { } }; -// Returns `mmap()` protection flags from \ref MemoryFlags. -static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept { - int protection = 0; - if (Support::test(memoryFlags, MemoryFlags::kAccessRead)) protection |= PROT_READ; - if (Support::test(memoryFlags, MemoryFlags::kAccessWrite)) protection |= PROT_READ | PROT_WRITE; - if (Support::test(memoryFlags, MemoryFlags::kAccessExecute)) protection |= PROT_READ | PROT_EXEC; - return protection; +#if ASMJIT_VM_SHM_DETECT +static Error detectAnonymousMemoryStrategy(AnonymousMemoryStrategy* strategyOut) noexcept { + AnonymousMemory anonMem; + Info vmInfo = info(); + + ASMJIT_PROPAGATE(anonMem.open(false)); + ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize)); + + void* ptr = mmap(nullptr, vmInfo.pageSize, PROT_READ | PROT_EXEC, MAP_SHARED, anonMem.fd(), 0); + if (ptr == MAP_FAILED) { + int e = errno; + if (e == EINVAL) { + *strategyOut = AnonymousMemoryStrategy::kTmpDir; + return kErrorOk; + } + return DebugUtils::errored(asmjitErrorFromErrno(e)); + } + else { + munmap(ptr, vmInfo.pageSize); + *strategyOut = AnonymousMemoryStrategy::kDevShm; + return kErrorOk; + } } +#endif -#if defined(__APPLE__) -// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags cannot -// be allocated without MAP_JIT flag. -static inline bool hasHardenedRuntimeMacOS() noexcept { -#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 - // MacOS on AArch64 has always hardened runtime enabled. +static Error getAnonymousMemoryStrategy(AnonymousMemoryStrategy* strategyOut) noexcept { +#if ASMJIT_VM_SHM_DETECT + // Initially don't assume anything. It has to be tested whether '/dev/shm' was mounted with 'noexec' flag or not. + static std::atomic globalStrategy; + + AnonymousMemoryStrategy strategy = static_cast(globalStrategy.load()); + if (strategy == AnonymousMemoryStrategy::kUnknown) { + ASMJIT_PROPAGATE(detectAnonymousMemoryStrategy(&strategy)); + globalStrategy.store(static_cast(strategy)); + } + + *strategyOut = strategy; + return kErrorOk; +#else + *strategyOut = AnonymousMemoryStrategy::kTmpDir; + return kErrorOk; +#endif +} + +#endif // ASMJIT_ANONYMOUS_MEMORY_USE_FD + +// Virtual Memory [Posix] - Hardened Runtime & MAP_JIT +// =================================================== + +// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags +// cannot be normally allocated. On OSX + AArch64 such allocation requires MAP_JIT flag, other platforms don't +// support this combination. +static bool hasHardenedRuntime() noexcept { +#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 + // OSX on AArch64 has always hardened runtime enabled. return true; #else static std::atomic globalHardenedFlag; @@ -427,9 +511,9 @@ static inline bool hasHardenedRuntimeMacOS() noexcept { uint32_t flag = globalHardenedFlag.load(); if (flag == kHardenedFlagUnknown) { - size_t pageSize = ::getpagesize(); + uint32_t pageSize = uint32_t(::getpagesize()); - void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + void* ptr = mmap(nullptr, pageSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (ptr == MAP_FAILED) { flag = kHardenedFlagEnabled; } @@ -444,45 +528,16 @@ static inline bool hasHardenedRuntimeMacOS() noexcept { #endif } -static inline bool hasMapJitSupportMacOS() noexcept { -#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 - // MacOS for 64-bit AArch architecture always uses hardened runtime. Some documentation can be found here: - // - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon - return true; -#elif TARGET_OS_OSX - // MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave) and IOS. - static std::atomic globalVersion; - - int ver = globalVersion.load(); - if (!ver) { - struct utsname osname {}; - uname(&osname); - ver = atoi(osname.release); - globalVersion.store(ver); - } - return ver >= 18; -#else - // Assume it's available. - return true; -#endif -} -#endif // __APPLE__ - -// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags -// cannot be normally allocated. On MacOS such allocation requires MAP_JIT flag. -static inline bool hasHardenedRuntime() noexcept { -#if defined(__APPLE__) - return hasHardenedRuntimeMacOS(); -#else - return false; -#endif -} - // Detects whether MAP_JIT is available. static inline bool hasMapJitSupport() noexcept { -#if defined(__APPLE__) - return hasMapJitSupportMacOS(); +#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 + // OSX on AArch64 always uses hardened runtime + MAP_JIT: + // - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon + return true; +#elif defined(__APPLE__) && TARGET_OS_OSX + return getOSXVersion() >= 18; #else + // MAP_JIT is not available (it's only available on OSX). return false; #endif } @@ -493,7 +548,8 @@ static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept { // Always use MAP_JIT flag if user asked for it (could be used for testing on non-hardened processes) and detect // whether it must be used when the process is actually hardened (in that case it doesn't make sense to rely on // user `memoryFlags`). - bool useMapJit = Support::test(memoryFlags, MemoryFlags::kMMapEnableMapJit) || hasHardenedRuntime(); + bool useMapJit = (Support::test(memoryFlags, MemoryFlags::kMMapEnableMapJit) || hasHardenedRuntime()) + && !Support::test(memoryFlags, MemoryFlags::kMapShared); if (useMapJit) return hasMapJitSupport() ? int(MAP_JIT) : 0; else @@ -504,109 +560,144 @@ static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept { #endif } -// Returns BSD-specific `PROT_MAX()` flags. -static inline int mmMaxProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept { -#if defined(PROT_MAX) +ASMJIT_MAYBE_UNUSED +static MemoryFlags maxAccessFlagsToRegularAccessFlags(MemoryFlags memoryFlags) noexcept { static constexpr uint32_t kMaxProtShift = Support::ConstCTZ::value; - - if (Support::test(memoryFlags, MemoryFlags::kMMapMaxAccessReadWrite | MemoryFlags::kMMapMaxAccessExecute)) - return PROT_MAX(mmProtFromMemoryFlags((MemoryFlags)(uint32_t(memoryFlags) >> kMaxProtShift))); - else - return 0; -#else - DebugUtils::unused(memoryFlags); - return 0; -#endif + return MemoryFlags(uint32_t(memoryFlags & MemoryFlags::kMMapMaxAccessRWX) >> kMaxProtShift); } -#if ASMJIT_VM_SHM_DETECT -static Error detectShmStrategy(ShmStrategy* strategyOut) noexcept { - AnonymousMemory anonMem; - Info vmInfo = info(); - - ASMJIT_PROPAGATE(anonMem.open(false)); - ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize)); - - void* ptr = mmap(nullptr, vmInfo.pageSize, PROT_READ | PROT_EXEC, MAP_SHARED, anonMem.fd(), 0); - if (ptr == MAP_FAILED) { - int e = errno; - if (e == EINVAL) { - *strategyOut = ShmStrategy::kTmpDir; - return kErrorOk; - } - return DebugUtils::errored(asmjitErrorFromErrno(e)); - } - else { - munmap(ptr, vmInfo.pageSize); - *strategyOut = ShmStrategy::kDevShm; - return kErrorOk; - } +ASMJIT_MAYBE_UNUSED +static MemoryFlags regularAccessFlagsToMaxAccessFlags(MemoryFlags memoryFlags) noexcept { + static constexpr uint32_t kMaxProtShift = Support::ConstCTZ::value; + return MemoryFlags(uint32_t(memoryFlags & MemoryFlags::kAccessRWX) << kMaxProtShift); } -#endif -static Error getShmStrategy(ShmStrategy* strategyOut) noexcept { -#if ASMJIT_VM_SHM_DETECT - // Initially don't assume anything. It has to be tested whether '/dev/shm' was mounted with 'noexec' flag or not. - static std::atomic globalShmStrategy; - - ShmStrategy strategy = static_cast(globalShmStrategy.load()); - if (strategy == ShmStrategy::kUnknown) { - ASMJIT_PROPAGATE(detectShmStrategy(&strategy)); - globalShmStrategy.store(static_cast(strategy)); - } - - *strategyOut = strategy; - return kErrorOk; +// Returns maximum protection flags from `memoryFlags`. +// +// Uses: +// - `PROT_MPROTECT()` on NetBSD. +// - `PROT_MAX()` when available(BSD). +ASMJIT_MAYBE_UNUSED +static inline int mmMaxProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept { + MemoryFlags acc = maxAccessFlagsToRegularAccessFlags(memoryFlags); + if (acc != MemoryFlags::kNone) { +#if defined(__NetBSD__) && defined(PROT_MPROTECT) + return PROT_MPROTECT(mmProtFromMemoryFlags(acc)); +#elif defined(PROT_MAX) + return PROT_MAX(mmProtFromMemoryFlags(acc)); #else - *strategyOut = ShmStrategy::kTmpDir; - return kErrorOk; + return 0; #endif + } + + return 0; } static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept { - HardenedRuntimeFlags hrFlags = HardenedRuntimeFlags::kNone; + HardenedRuntimeFlags flags = HardenedRuntimeFlags::kNone; if (hasHardenedRuntime()) - hrFlags |= HardenedRuntimeFlags::kEnabled; + flags |= HardenedRuntimeFlags::kEnabled; if (hasMapJitSupport()) - hrFlags |= HardenedRuntimeFlags::kMapJit; + flags |= HardenedRuntimeFlags::kMapJit; - return hrFlags; + return flags; } -Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept { +static Error mapMemory(void** p, size_t size, MemoryFlags memoryFlags, int fd = -1, off_t offset = 0) noexcept { *p = nullptr; if (size == 0) return DebugUtils::errored(kErrorInvalidArgument); int protection = mmProtFromMemoryFlags(memoryFlags) | mmMaxProtFromMemoryFlags(memoryFlags); - int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | mmMapJitFromMemoryFlags(memoryFlags); + int mmFlags = mmMapJitFromMemoryFlags(memoryFlags); + + mmFlags |= Support::test(memoryFlags, MemoryFlags::kMapShared) ? MAP_SHARED : MAP_PRIVATE; + if (fd == -1) + mmFlags |= MAP_ANONYMOUS; - void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0); + void* ptr = mmap(nullptr, size, protection, mmFlags, fd, offset); if (ptr == MAP_FAILED) - return DebugUtils::errored(kErrorOutOfMemory); + return DebugUtils::errored(asmjitErrorFromErrno(errno)); *p = ptr; return kErrorOk; } -Error release(void* p, size_t size) noexcept { +static Error unmapMemory(void* p, size_t size) noexcept { if (ASMJIT_UNLIKELY(munmap(p, size) != 0)) - return DebugUtils::errored(kErrorInvalidArgument); + return DebugUtils::errored(asmjitErrorFromErrno(errno)); return kErrorOk; } +Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept { + return mapMemory(p, size, memoryFlags); +} + +Error release(void* p, size_t size) noexcept { + return unmapMemory(p, size); +} Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept { int protection = mmProtFromMemoryFlags(memoryFlags); if (mprotect(p, size, protection) == 0) return kErrorOk; - return DebugUtils::errored(kErrorInvalidArgument); + return DebugUtils::errored(asmjitErrorFromErrno(errno)); } +// Virtual Memory [Posix] - Dual Mapping +// ===================================== + +static Error unmapDualMapping(DualMapping* dm, size_t size) noexcept { + Error err1 = unmapMemory(dm->rx, size); + Error err2 = kErrorOk; + + if (dm->rx != dm->rw) + err2 = unmapMemory(dm->rw, size); + + // We can report only one error, so report the first... + if (err1 || err2) + return DebugUtils::errored(err1 ? err1 : err2); + + dm->rx = nullptr; + dm->rw = nullptr; + return kErrorOk; +} + +#if defined(ASMJIT_ANONYMOUS_MEMORY_USE_REMAPDUP) +static Error allocDualMappingUsingRemapdup(DualMapping* dmOut, size_t size, MemoryFlags memoryFlags) noexcept { + MemoryFlags maxAccessFlags = regularAccessFlagsToMaxAccessFlags(memoryFlags); + MemoryFlags finalFlags = memoryFlags | maxAccessFlags | MemoryFlags::kMapShared; + + MemoryFlags rxFlags = finalFlags & ~(MemoryFlags::kAccessWrite | MemoryFlags::kMMapMaxAccessWrite); + MemoryFlags rwFlags = finalFlags & ~(MemoryFlags::kAccessExecute); + + // Allocate RW mapping. + DualMapping dm {}; + ASMJIT_PROPAGATE(mapMemory(&dm.rw, size, rwFlags)); + + // Allocate RX mapping. + dm.rx = mremap(dm.rw, size, nullptr, size, MAP_REMAPDUP); + if (dm.rx == MAP_FAILED) { + int e = errno; + munmap(dm.rw, size); + return DebugUtils::errored(asmjitErrorFromErrno(e)); + } + + if (mprotect(dm.rx, size, mmProtFromMemoryFlags(rxFlags)) != 0) { + int e = errno; + unmapDualMapping(&dm, size); + return DebugUtils::errored(asmjitErrorFromErrno(e)); + } + + *dmOut = dm; + return kErrorOk; +} +#endif + Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept { dm->rx = nullptr; dm->rw = nullptr; @@ -614,11 +705,14 @@ Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) no if (off_t(size) <= 0) return DebugUtils::errored(size == 0 ? kErrorInvalidArgument : kErrorTooLarge); +#if defined(ASMJIT_ANONYMOUS_MEMORY_USE_REMAPDUP) + return allocDualMappingUsingRemapdup(dm, size, memoryFlags); +#elif defined(ASMJIT_ANONYMOUS_MEMORY_USE_FD) bool preferTmpOverDevShm = Support::test(memoryFlags, MemoryFlags::kMappingPreferTmp); if (!preferTmpOverDevShm) { - ShmStrategy strategy; - ASMJIT_PROPAGATE(getShmStrategy(&strategy)); - preferTmpOverDevShm = (strategy == ShmStrategy::kTmpDir); + AnonymousMemoryStrategy strategy; + ASMJIT_PROPAGATE(getAnonymousMemoryStrategy(&strategy)); + preferTmpOverDevShm = (strategy == AnonymousMemoryStrategy::kTmpDir); } AnonymousMemory anonMem; @@ -627,35 +721,25 @@ Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) no void* ptr[2]; for (uint32_t i = 0; i < 2; i++) { - MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i]; - int protection = mmProtFromMemoryFlags(accessFlags) | mmMaxProtFromMemoryFlags(accessFlags); - - ptr[i] = mmap(nullptr, size, protection, MAP_SHARED, anonMem.fd(), 0); - if (ptr[i] == MAP_FAILED) { - // Get the error now before `munmap()` has a chance to clobber it. - int e = errno; + MemoryFlags restrictedMemoryFlags = memoryFlags & ~dualMappingFilter[i]; + Error err = mapMemory(&ptr[i], size, restrictedMemoryFlags | MemoryFlags::kMapShared, anonMem.fd(), 0); + if (err != kErrorOk) { if (i == 1) - munmap(ptr[0], size); - return DebugUtils::errored(asmjitErrorFromErrno(e)); + unmapMemory(ptr[0], size); + return err; } } dm->rx = ptr[0]; dm->rw = ptr[1]; return kErrorOk; +#else + #error "[asmjit] VirtMem::allocDualMapping() has no implementation" +#endif } Error releaseDualMapping(DualMapping* dm, size_t size) noexcept { - Error err = release(dm->rx, size); - if (dm->rx != dm->rw) - err |= release(dm->rw, size); - - if (err) - return DebugUtils::errored(kErrorInvalidArgument); - - dm->rx = nullptr; - dm->rw = nullptr; - return kErrorOk; + return unmapDualMapping(dm, size); } #endif @@ -676,7 +760,7 @@ void flushInstructionCache(void* p, size_t size) noexcept { char* end = start + size; __builtin___clear_cache(start, end); #else - #pragma message("asmjit::VirtMem::flushInstructionCache() doesn't have implementation for the target OS and compiler") + #pragma message("[asmjit] VirtMem::flushInstructionCache() doesn't have implementation for the target OS and compiler") DebugUtils::unused(p, size); #endif } @@ -711,7 +795,7 @@ HardenedRuntimeInfo hardenedRuntimeInfo() noexcept { void protectJitMemory(ProtectJitAccess access) noexcept { #if defined(ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP) - pthread_jit_write_protect_np(static_cast(access)); + pthread_jit_write_protect_np(static_cast(access)); #else DebugUtils::unused(access); #endif @@ -719,4 +803,29 @@ void protectJitMemory(ProtectJitAccess access) noexcept { ASMJIT_END_SUB_NAMESPACE -#endif +// JitAllocator - Tests +// ==================== + +#if defined(ASMJIT_TEST) +ASMJIT_BEGIN_NAMESPACE + +UNIT(virt_mem) { + VirtMem::Info vmInfo = VirtMem::info(); + + INFO("VirtMem::info():"); + INFO(" pageSize: %zu", size_t(vmInfo.pageSize)); + INFO(" pageGranularity: %zu", size_t(vmInfo.pageGranularity)); + + VirtMem::HardenedRuntimeInfo hardenedRtInfo = VirtMem::hardenedRuntimeInfo(); + VirtMem::HardenedRuntimeFlags hardenedFlags = hardenedRtInfo.flags; + + INFO("VirtMem::hardenedRuntimeInfo():"); + INFO(" flags:"); + INFO(" kEnabled: %s", Support::test(hardenedFlags, VirtMem::HardenedRuntimeFlags::kEnabled) ? "true" : "false"); + INFO(" kMapJit: %s", Support::test(hardenedFlags, VirtMem::HardenedRuntimeFlags::kMapJit) ? "true" : "false"); +} + +ASMJIT_END_NAMESPACE +#endif // ASMJIT_TEST + +#endif // !ASMJIT_NO_JIT diff --git a/erts/emulator/asmjit/core/virtmem.h b/erts/emulator/asmjit/core/virtmem.h index 50f09457eba7..a5633a20811b 100644 --- a/erts/emulator/asmjit/core/virtmem.h +++ b/erts/emulator/asmjit/core/virtmem.h @@ -67,7 +67,7 @@ enum class MemoryFlags : uint32_t { //! in MAC bundles. This flag is not turned on by default, because when a process uses `fork()` the child process //! has no access to the pages mapped with `MAP_JIT`, which could break code that doesn't expect this behavior. //! - //! \note This flag can only be used with \ref VirtMem::alloc(). + //! \note This flag can only be used with \ref VirtMem::alloc(), `MAP_JIT` only works on OSX and not on iOS. kMMapEnableMapJit = 0x00000010u, //! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`. @@ -96,6 +96,13 @@ enum class MemoryFlags : uint32_t { //! MemoryFlags::kMMapMaxAccessExecute. kMMapMaxAccessRWX = kMMapMaxAccessRead | kMMapMaxAccessWrite | kMMapMaxAccessExecute, + //! Use `MAP_SHARED` when calling mmap(). + //! + //! \note In some cases `MAP_SHARED` may be set automatically. For example when using dual mapping it's important to + //! to use `MAP_SHARED` instead of `MAP_PRIVATE` to ensure that the OS would not copy pages on write (that would mean + //! updating only the RW mapped region and not RX mapped one). + kMapShared = 0x00000100u, + //! Not an access flag, only used by `allocDualMapping()` to override the default allocation strategy to always use //! a 'tmp' directory instead of "/dev/shm" (on POSIX platforms). Please note that this flag will be ignored if the //! operating system allows to allocate an executable memory by a different API than `open()` or `shm_open()`. For @@ -157,13 +164,13 @@ enum class HardenedRuntimeFlags : uint32_t { //! Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection. The runtime //! enforces W^X (either write or execute). //! - //! \note If the runtime is hardened it means that an operating system specific protection is used. For example on - //! MacOS platform it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()` + //! \note If the runtime is hardened it means that an operating system specific protection is used. For example + //! on Apple OSX it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()` //! to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64 //! architecture. kEnabled = 0x00000001u, - //! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific). + //! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific, only available on OSX). kMapJit = 0x00000002u }; ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags) diff --git a/erts/emulator/asmjit/core/zonevector.h b/erts/emulator/asmjit/core/zonevector.h index 447c08cb921c..9a655e65776b 100644 --- a/erts/emulator/asmjit/core/zonevector.h +++ b/erts/emulator/asmjit/core/zonevector.h @@ -480,7 +480,7 @@ class ZoneBitVector { //! Returns the capacity of the `BitWord[]` array in `BitWord` units. inline uint32_t capacityInBitWords() const noexcept { return _wordsPerBits(_capacity); } - //! REturns bit-vector data as `BitWord[]`. + //! Returns bit-vector data as `BitWord[]`. inline BitWord* data() noexcept { return _data; } //! \overload inline const BitWord* data() const noexcept { return _data; } diff --git a/erts/emulator/asmjit/x86/x86assembler.cpp b/erts/emulator/asmjit/x86/x86assembler.cpp index f11fea00238a..ee2f746f59ee 100644 --- a/erts/emulator/asmjit/x86/x86assembler.cpp +++ b/erts/emulator/asmjit/x86/x86assembler.cpp @@ -493,11 +493,11 @@ static ASMJIT_FORCE_INLINE uint32_t x86GetMovAbsInstSize64Bit(uint32_t regSize, static ASMJIT_FORCE_INLINE bool x86ShouldUseMovabs(Assembler* self, X86BufferWriter& writer, uint32_t regSize, InstOptions options, const Mem& rmRel) noexcept { if (self->is32Bit()) { // There is no relative addressing, just decide whether to use MOV encoded with MOD R/M or absolute. - return !Support::test(options, InstOptions::kX86_ModMR | InstOptions::kX86_ModMR); + return !Support::test(options, InstOptions::kX86_ModMR | InstOptions::kX86_ModRM); } else { // If the addressing type is REL or MOD R/M was specified then absolute mov won't be used. - if (rmRel.addrType() == Mem::AddrType::kRel || Support::test(options, InstOptions::kX86_ModMR)) + if (rmRel.addrType() == Mem::AddrType::kRel || Support::test(options, InstOptions::kX86_ModMR | InstOptions::kX86_ModRM)) return false; int64_t addrValue = rmRel.offset(); @@ -2259,7 +2259,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con goto EmitX86OpReg; } else { - // Encode 'xchg eax, eax' by by using a generic path. + // Encode 'xchg eax, eax' by using a generic path. } } else if (!Support::test(options, InstOptions::kLongForm)) { @@ -2716,7 +2716,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con case InstDB::kEncodingExtRm_P: if (isign3 == ENC_OPS2(Reg, Reg)) { - opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1)); + opcode.add66hIf(unsigned(Reg::isXmm(o0)) | unsigned(Reg::isXmm(o1))); opReg = o0.id(); rbReg = o1.id(); @@ -2760,7 +2760,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con case InstDB::kEncodingExtRmRi_P: if (isign3 == ENC_OPS2(Reg, Reg)) { - opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1)); + opcode.add66hIf(unsigned(Reg::isXmm(o0)) | unsigned(Reg::isXmm(o1))); opReg = o0.id(); rbReg = o1.id(); @@ -2812,7 +2812,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { - opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1)); + opcode.add66hIf(unsigned(Reg::isXmm(o0)) | unsigned(Reg::isXmm(o1))); opReg = o0.id(); rbReg = o1.id(); @@ -3040,7 +3040,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con goto CaseVexRm; case InstDB::kEncodingVexRm_Wx: - opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1)); + opcode.addWIf(unsigned(Reg::isGpq(o0)) | unsigned(Reg::isGpq(o1))); goto CaseVexRm; case InstDB::kEncodingVexRm_Lx_Narrow: @@ -3110,7 +3110,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con } case InstDB::kEncodingVexRmi_Wx: - opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1)); + opcode.addWIf(unsigned(Reg::isGpq(o0)) | unsigned(Reg::isGpq(o1))); goto CaseVexRmi; case InstDB::kEncodingVexRmi_Lx: @@ -3159,7 +3159,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con } case InstDB::kEncodingVexRvm_Wx: { - opcode.addWIf(Reg::isGpq(o0) | (o2.size() == 8)); + opcode.addWIf(unsigned(Reg::isGpq(o0)) | unsigned((o2.size() == 8))); goto CaseVexRvm; } @@ -3261,7 +3261,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con } case InstDB::kEncodingVexRmv_Wx: - opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o2)); + opcode.addWIf(unsigned(Reg::isGpq(o0)) | unsigned(Reg::isGpq(o2))); ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexRmv: @@ -3614,7 +3614,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con break; case InstDB::kEncodingVexVm_Wx: - opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1)); + opcode.addWIf(unsigned(Reg::isGpq(o0)) | unsigned(Reg::isGpq(o1))); ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexVm: @@ -4950,10 +4950,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con #endif } - resetExtraReg(); - resetInstOptions(); - resetInlineComment(); - + resetState(); writer.done(this); return kErrorOk; @@ -4987,9 +4984,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con #ifndef ASMJIT_NO_LOGGING return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt); #else - resetExtraReg(); - resetInstOptions(); - resetInlineComment(); + resetState(); return reportError(err); #endif } diff --git a/erts/emulator/asmjit/x86/x86assembler.h b/erts/emulator/asmjit/x86/x86assembler.h index dbffae62895d..dde27f40e7c3 100644 --- a/erts/emulator/asmjit/x86/x86assembler.h +++ b/erts/emulator/asmjit/x86/x86assembler.h @@ -38,7 +38,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create a runtime specialized for JIT. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! //! // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions: @@ -131,7 +132,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create a runtime specialized for JIT. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! //! // Enable strict validation. @@ -187,7 +189,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create a runtime specialized for JIT. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! //! // Let's get these registers from x86::Assembler. @@ -346,7 +349,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create JIT Runtime. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! //! // Decide which registers will be mapped to function arguments. Try changing @@ -453,7 +457,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create a runtime specialized for JIT. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Assembler a(&code); // Create and attach x86::Assembler to code. //! //! // Let's get these registers from x86::Assembler. diff --git a/erts/emulator/asmjit/x86/x86builder.h b/erts/emulator/asmjit/x86/x86builder.h index f3bb11a0ca22..4c56cba370fd 100644 --- a/erts/emulator/asmjit/x86/x86builder.h +++ b/erts/emulator/asmjit/x86/x86builder.h @@ -36,7 +36,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! // Small helper function to print the current content of `cb`. //! static void dumpCode(BaseBuilder& builder, const char* phase) { //! String sb; -//! builder.dump(sb); +//! formatOptions formatOptions {}; +//! +//! Formatter::formatNodeList(sb, formatOptions, &builder); //! printf("%s:\n%s\n", phase, sb.data()); //! } //! @@ -44,7 +46,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Create JIT Runtime. //! CodeHolder code; // Create a CodeHolder. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Builder cb(&code); // Create and attach x86::Builder to `code`. //! //! // Decide which registers will be mapped to function arguments. Try changing registers diff --git a/erts/emulator/asmjit/x86/x86compiler.h b/erts/emulator/asmjit/x86/x86compiler.h index d89aea02519e..8bb9a43cfb5c 100644 --- a/erts/emulator/asmjit/x86/x86compiler.h +++ b/erts/emulator/asmjit/x86/x86compiler.h @@ -38,7 +38,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Runtime specialized for JIT code execution. //! CodeHolder code; // Holds code and relocation information. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. //! //! cc.addFunc(FuncSignatureT());// Begin a function of `int fn(void)` signature. @@ -82,7 +83,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Runtime specialized for JIT code execution. //! CodeHolder code; // Holds code and relocation information. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. //! //! FuncNode* funcNode = cc.addFunc( // Begin the function of the following signature: @@ -164,7 +166,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Runtime specialized for JIT code execution. //! CodeHolder code; // Holds code and relocation information. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. //! //! FuncNode* funcNode = cc.addFunc(FuncSignatureT()); @@ -222,7 +225,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Runtime specialized for JIT code execution. //! CodeHolder code; // Holds code and relocation information. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. //! //! FuncNode* funcNode = cc.addFunc( // Begin of the Fibonacci function, addFunc() @@ -290,7 +294,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! JitRuntime rt; // Runtime specialized for JIT code execution. //! CodeHolder code; // Holds code and relocation information. //! -//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! code.init(rt.environment(), // Initialize code to match the JIT environment. +//! rt.cpuFeatures()); //! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. //! //! cc.addFunc(FuncSignatureT());// Create a function that returns int. diff --git a/erts/emulator/asmjit/x86/x86emithelper.cpp b/erts/emulator/asmjit/x86/x86emithelper.cpp index cc558e07c531..b541c048b049 100644 --- a/erts/emulator/asmjit/x86/x86emithelper.cpp +++ b/erts/emulator/asmjit/x86/x86emithelper.cpp @@ -30,7 +30,7 @@ static inline uint32_t getXmmMovInst(const FuncFrame& frame) { : (avx ? Inst::kIdVmovups : Inst::kIdMovups); } -//! Converts `size` to a 'kmov?' instructio. +//! Converts `size` to a 'kmov?' instruction. static inline uint32_t kmovInstFromSize(uint32_t size) noexcept { switch (size) { case 1: return Inst::kIdKmovb; diff --git a/erts/emulator/asmjit/x86/x86formatter.cpp b/erts/emulator/asmjit/x86/x86formatter.cpp index d62dd18b6389..715432e0ee37 100644 --- a/erts/emulator/asmjit/x86/x86formatter.cpp +++ b/erts/emulator/asmjit/x86/x86formatter.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: Zlib #include "../core/api-build_p.h" -#ifndef ASMJIT_NO_LOGGING +#if !defined(ASMJIT_NO_X86) && !defined(ASMJIT_NO_LOGGING) #include "../core/cpuinfo.h" #include "../core/misc_p.h" @@ -198,6 +198,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "AESNI\0" "ALTMOVCR8\0" "AMX_BF16\0" + "AMX_FP16\0" "AMX_INT8\0" "AMX_TILE\0" "AVX\0" @@ -220,17 +221,22 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "AVX512_VNNI\0" "AVX512_VP2INTERSECT\0" "AVX512_VPOPCNTDQ\0" + "AVX_IFMA\0" + "AVX_NE_CONVERT\0" "AVX_VNNI\0" + "AVX_VNNI_INT8\0" "BMI\0" "BMI2\0" "CET_IBT\0" "CET_SS\0" + "CET_SSS\0" "CLDEMOTE\0" "CLFLUSH\0" "CLFLUSHOPT\0" "CLWB\0" "CLZERO\0" "CMOV\0" + "CMPCCXADD\0" "CMPXCHG16B\0" "CMPXCHG8B\0" "ENCLV\0" @@ -241,14 +247,19 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "FMA4\0" "FPU\0" "FSGSBASE\0" + "FSRM\0" + "FSRC\0" + "FSRS\0" "FXSR\0" "FXSROPT\0" + "FZRM\0" "GEODE\0" "GFNI\0" "HLE\0" "HRESET\0" "I486\0" "LAHFSAHF\0" + "LAM\0" "LWP\0" "LZCNT\0" "MCOMMIT\0" @@ -261,15 +272,18 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "MOVDIRI\0" "MPX\0" "MSR\0" + "MSRLIST\0" "MSSE\0" "OSXSAVE\0" "OSPKE\0" "PCLMULQDQ\0" "PCONFIG\0" "POPCNT\0" + "PREFETCHI\0" "PREFETCHW\0" "PREFETCHWT1\0" "PTWRITE\0" + "RAO_INT\0" "RDPID\0" "RDPRU\0" "RDRAND\0" @@ -301,6 +315,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "VPCLMULQDQ\0" "WAITPKG\0" "WBNOINVD\0" + "WRMSRNS\0" "XOP\0" "XSAVE\0" "XSAVEC\0" @@ -309,14 +324,15 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept "\0"; static const uint16_t sFeatureIndex[] = { - 0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 62, 71, 75, 80, 94, 108, 120, 134, 144, - 155, 165, 176, 185, 197, 209, 220, 232, 245, 255, 267, 287, 304, 313, 317, - 322, 330, 337, 346, 354, 365, 370, 377, 382, 393, 403, 409, 416, 421, 426, - 430, 435, 439, 448, 453, 461, 467, 472, 476, 483, 488, 497, 501, 507, 515, - 519, 524, 532, 541, 547, 557, 565, 569, 573, 578, 586, 592, 602, 610, 617, - 627, 639, 647, 653, 659, 666, 673, 679, 686, 690, 700, 704, 711, 716, 721, - 725, 729, 733, 738, 743, 750, 757, 763, 769, 773, 777, 781, 790, 796, 801, - 805, 816, 824, 833, 837, 843, 850, 859, 866 + 0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 62, 71, 80, 84, 89, 103, 117, 129, 143, + 153, 164, 174, 185, 194, 206, 218, 229, 241, 254, 264, 276, 296, 313, 322, + 337, 346, 360, 364, 369, 377, 384, 392, 401, 409, 420, 425, 432, 437, 447, + 458, 468, 474, 481, 486, 491, 495, 500, 504, 513, 518, 523, 528, 533, 541, + 546, 552, 557, 561, 568, 573, 582, 586, 590, 596, 604, 608, 613, 621, 630, + 636, 646, 654, 658, 662, 670, 675, 683, 689, 699, 707, 714, 724, 734, 746, + 754, 762, 768, 774, 781, 788, 794, 801, 805, 815, 819, 826, 831, 836, 840, + 844, 848, 853, 858, 865, 872, 878, 884, 888, 892, 896, 905, 911, 916, 920, + 931, 939, 948, 956, 960, 966, 973, 982, 989 }; // @EnumStringEnd@ @@ -344,7 +360,10 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, FormatFlag else ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(id)))); - if (vReg->type() != type && uint32_t(type) <= uint32_t(RegType::kMaxValue) && Support::test(formatFlags, FormatFlags::kRegCasts)) { + bool formatType = (Support::test(formatFlags, FormatFlags::kRegType)) || + (Support::test(formatFlags, FormatFlags::kRegCasts) && vReg->type() != type); + + if (formatType && uint32_t(type) <= uint32_t(RegType::kMaxValue)) { const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[size_t(type)]; if (typeEntry.index) ASMJIT_PROPAGATE(sb.appendFormat("@%s", info.typeStrings + typeEntry.index)); @@ -496,13 +515,14 @@ struct ImmBits { char text[48 - 3]; }; -ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t imm8, uint32_t bits, uint32_t count) noexcept { uint32_t mask = (1 << bits) - 1; + uint32_t lastPredicateShift = bits * (count - 1u); - for (uint32_t i = 0; i < count; i++, u8 >>= bits) { - uint32_t value = u8 & mask; + for (uint32_t i = 0; i < count; i++, imm8 <<= bits) { + uint32_t index = (imm8 >> lastPredicateShift) & mask; ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); - ASMJIT_PROPAGATE(sb.appendUInt(value)); + ASMJIT_PROPAGATE(sb.appendUInt(index)); } if (kImmCharEnd) @@ -511,14 +531,14 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint3 return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t imm8, const ImmBits* bits, uint32_t count) noexcept { uint32_t n = 0; char buf[64]; for (uint32_t i = 0; i < count; i++) { const ImmBits& spec = bits[i]; - uint32_t value = (u8 & uint32_t(spec.mask)) >> spec.shift; + uint32_t value = (imm8 & uint32_t(spec.mask)) >> spec.shift; const char* str = nullptr; switch (spec.mode) { @@ -548,12 +568,12 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint3 return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t imm8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { uint32_t mask = (1u << bits) - 1; uint32_t pos = 0; - for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) { - uint32_t value = (u8 & mask) + pos; + for (uint32_t i = 0; i < count; i++, imm8 >>= bits, pos += advance) { + uint32_t value = (imm8 & mask) + pos; ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); ASMJIT_PROPAGATE(sb.append(Support::findPackedString(text, value))); } @@ -608,25 +628,25 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst( }; static const ImmBits vmpsadbw[] = { - { 0x04u, 2, ImmBits::kModeLookup, "BLK1[0]\0" "BLK1[1]\0" }, - { 0x03u, 0, ImmBits::kModeLookup, "BLK2[0]\0" "BLK2[1]\0" "BLK2[2]\0" "BLK2[3]\0" }, { 0x40u, 6, ImmBits::kModeLookup, "BLK1[4]\0" "BLK1[5]\0" }, - { 0x30u, 4, ImmBits::kModeLookup, "BLK2[4]\0" "BLK2[5]\0" "BLK2[6]\0" "BLK2[7]\0" } + { 0x30u, 4, ImmBits::kModeLookup, "BLK2[4]\0" "BLK2[5]\0" "BLK2[6]\0" "BLK2[7]\0" }, + { 0x04u, 2, ImmBits::kModeLookup, "BLK1[0]\0" "BLK1[1]\0" }, + { 0x03u, 0, ImmBits::kModeLookup, "BLK2[0]\0" "BLK2[1]\0" "BLK2[2]\0" "BLK2[3]\0" } }; static const ImmBits vpclmulqdq[] = { - { 0x01u, 0, ImmBits::kModeLookup, "LQ\0" "HQ\0" }, - { 0x10u, 4, ImmBits::kModeLookup, "LQ\0" "HQ\0" } + { 0x10u, 4, ImmBits::kModeLookup, "LQ\0" "HQ\0" }, + { 0x01u, 0, ImmBits::kModeLookup, "LQ\0" "HQ\0" } }; static const ImmBits vperm2x128[] = { - { 0x0Bu, 0, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" }, - { 0xB0u, 4, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" } + { 0xB0u, 4, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" }, + { 0x0Bu, 0, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" } }; static const ImmBits vrangexx[] = { - { 0x03u, 0, ImmBits::kModeLookup, "MIN\0" "MAX\0" "MIN_ABS\0" "MAX_ABS\0" }, - { 0x0Cu, 2, ImmBits::kModeLookup, "SIGN_A\0" "SIGN_B\0" "SIGN_0\0" "SIGN_1\0" } + { 0x0Cu, 2, ImmBits::kModeLookup, "SIGN_A\0" "SIGN_B\0" "SIGN_0\0" "SIGN_1\0" }, + { 0x03u, 0, ImmBits::kModeLookup, "MIN\0" "MAX\0" "MIN_ABS\0" "MAX_ABS\0" } }; static const ImmBits vreducexx_vrndscalexx[] = { @@ -941,4 +961,4 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction( ASMJIT_END_SUB_NAMESPACE -#endif // !ASMJIT_NO_LOGGING +#endif // !ASMJIT_NO_X86 && !ASMJIT_NO_LOGGING diff --git a/erts/emulator/asmjit/x86/x86globals.h b/erts/emulator/asmjit/x86/x86globals.h index 803c813ac534..7f1566da3b06 100644 --- a/erts/emulator/asmjit/x86/x86globals.h +++ b/erts/emulator/asmjit/x86/x86globals.h @@ -1933,7 +1933,7 @@ enum class RoundImm : uint8_t { kUp = 0x02u, //!< Round to up toward +INF (ceil). kTrunc = 0x03u, //!< Round toward zero (truncate). kCurrent = 0x04u, //!< Round to the current rounding mode set (ignores other RC bits). - kSuppress = 0x08u //!< Supress exceptions (avoids inexact exception, if set). + kSuppress = 0x08u //!< Suppress exceptions (avoids inexact exception, if set). }; ASMJIT_DEFINE_ENUM_FLAGS(RoundImm) diff --git a/erts/emulator/asmjit/x86/x86instapi.cpp b/erts/emulator/asmjit/x86/x86instapi.cpp index 3580fe6f771e..50d3e8393fe0 100644 --- a/erts/emulator/asmjit/x86/x86instapi.cpp +++ b/erts/emulator/asmjit/x86/x86instapi.cpp @@ -26,7 +26,7 @@ #include "../core/cpuinfo.h" #include "../core/misc_p.h" -#include "../core/support.h" +#include "../core/support_p.h" #include "../x86/x86instapi_p.h" #include "../x86/x86instdb_p.h" #include "../x86/x86opcode_p.h" @@ -44,8 +44,10 @@ Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noe if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId))) return DebugUtils::errored(kErrorInvalidInstruction); - const InstDB::InstInfo& info = InstDB::infoById(instId); - return output.append(InstDB::_nameData + info._nameDataIndex); + char nameData[32]; + size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable); + + return output.append(nameData, nameSize); } InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept { @@ -64,30 +66,28 @@ InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexce if (ASMJIT_UNLIKELY(prefix > 'z' - 'a')) return Inst::kIdNone; - uint32_t index = InstDB::instNameIndex[prefix].start; - if (ASMJIT_UNLIKELY(!index)) - return Inst::kIdNone; + size_t base = InstDB::instNameIndex[prefix].start; + size_t end = InstDB::instNameIndex[prefix].end; - const char* nameData = InstDB::_nameData; - const InstDB::InstInfo* table = InstDB::_instInfoTable; + if (ASMJIT_UNLIKELY(!base)) + return Inst::kIdNone; - const InstDB::InstInfo* base = table + index; - const InstDB::InstInfo* end = table + InstDB::instNameIndex[prefix].end; + char nameData[32]; + for (size_t lim = end - base; lim != 0; lim >>= 1) { + size_t instId = base + (lim >> 1); + size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable); - for (size_t lim = (size_t)(end - base); lim != 0; lim >>= 1) { - const InstDB::InstInfo* cur = base + (lim >> 1); - int result = Support::cmpInstName(nameData + cur[0]._nameDataIndex, s, len); + int result = Support::compareStringViews(s, len, nameData, nameSize); + if (result < 0) + continue; - if (result < 0) { - base = cur + 1; + if (result > 0) { + base = instId + 1; lim--; continue; } - if (result > 0) - continue; - - return InstId((size_t)(cur - table)); + return InstId(instId); } return Inst::kIdNone; @@ -776,6 +776,15 @@ static ASMJIT_FORCE_INLINE Error rwHandleAVX512(const BaseInst& inst, const Inst return kErrorOk; } +static ASMJIT_FORCE_INLINE bool hasSameRegType(const BaseReg* regs, size_t opCount) noexcept { + ASMJIT_ASSERT(opCount > 0); + RegType regType = regs[0].type(); + for (size_t i = 1; i < opCount; i++) + if (regs[i].type() != regType) + return false; + return true; +} + Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { // Only called when `arch` matches X86 family. ASMJIT_ASSERT(Environment::isFamilyX86(arch)); @@ -801,13 +810,14 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* : InstDB::rwInfoB[InstDB::rwInfoIndexB[instId]]; const InstDB::RWInfoRm& instRmInfo = InstDB::rwInfoRm[instRwInfo.rmInfo]; - out->_instFlags = 0; + out->_instFlags = InstDB::_instFlagsTable[additionalInfo._instFlagsIndex]; out->_opCount = uint8_t(opCount); out->_rmFeature = instRmInfo.rmFeature; out->_extraReg.reset(); out->_readFlags = CpuRWFlags(rwFlags.readFlags); out->_writeFlags = CpuRWFlags(rwFlags.writeFlags); + uint32_t opTypeMask = 0u; uint32_t nativeGpSize = Environment::registerSizeFromArch(arch); constexpr OpRWFlags R = OpRWFlags::kRead; @@ -827,6 +837,8 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* const Operand_& srcOp = operands[i]; const InstDB::RWInfoOp& rwOpData = InstDB::rwInfoOp[instRwInfo.opInfoIndex[i]]; + opTypeMask |= Support::bitMask(srcOp.opType()); + if (!srcOp.isRegOrMem()) { op.reset(); continue; @@ -878,6 +890,35 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* } } + // Only keep kMovOp if the instruction is actually register to register move of the same kind. + if (out->hasInstFlag(InstRWFlags::kMovOp)) { + if (!(opCount >= 2 && opTypeMask == Support::bitMask(OperandType::kReg) && hasSameRegType(reinterpret_cast(operands), opCount))) + out->_instFlags &= ~InstRWFlags::kMovOp; + } + + // Special cases require more logic. + if (instRmInfo.flags & (InstDB::RWInfoRm::kFlagMovssMovsd | InstDB::RWInfoRm::kFlagPextrw | InstDB::RWInfoRm::kFlagFeatureIfRMI)) { + if (instRmInfo.flags & InstDB::RWInfoRm::kFlagMovssMovsd) { + if (opCount == 2) { + if (operands[0].isReg() && operands[1].isReg()) { + // Doesn't zero extend the destination. + out->_operands[0]._extendByteMask = 0; + } + } + } + else if (instRmInfo.flags & InstDB::RWInfoRm::kFlagPextrw) { + if (opCount == 3 && Reg::isMm(operands[1])) { + out->_rmFeature = 0; + rmOpsMask = 0; + } + } + else if (instRmInfo.flags & InstDB::RWInfoRm::kFlagFeatureIfRMI) { + if (opCount != 3 || !operands[2].isImm()) { + out->_rmFeature = 0; + } + } + } + rmOpsMask &= instRmInfo.rmOpsMask; if (rmOpsMask) { Support::BitWordIterator it(rmOpsMask); @@ -916,6 +957,9 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* // used to move between GP, segment, control and debug registers. Moving between GP registers also allow to // use memory operand. + // We will again set the flag if it's actually a move from GP to GP register, otherwise this flag cannot be set. + out->_instFlags &= ~InstRWFlags::kMovOp; + if (opCount == 2) { if (operands[0].isReg() && operands[1].isReg()) { const Reg& o0 = operands[0].as(); @@ -926,6 +970,7 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* out->_operands[1].reset(R | RegM, operands[1].size()); rwZeroExtendGp(out->_operands[0], operands[0].as(), nativeGpSize); + out->_instFlags |= InstRWFlags::kMovOp; return kErrorOk; } @@ -1543,14 +1588,6 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand uint32_t mustUseEvex = 0; switch (instId) { - // Special case: VPSLLDQ and VPSRLDQ instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode, - // then AVX-512 introduced `reg, reg/mem, imm` combination that uses EVEX prefix. This means that if the - // second operand is memory then this is AVX-512_BW instruction and not AVX/AVX2 instruction. - case Inst::kIdVpslldq: - case Inst::kIdVpsrldq: - mustUseEvex = opCount >= 2 && operands[1].isMem(); - break; - // Special case: VPBROADCAST[B|D|Q|W] only supports r32/r64 with EVEX prefix. case Inst::kIdVpbroadcastb: case Inst::kIdVpbroadcastd: @@ -1559,6 +1596,29 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand mustUseEvex = opCount >= 2 && x86::Reg::isGp(operands[1]); break; + case Inst::kIdVcvtpd2dq: + case Inst::kIdVcvtpd2ps: + case Inst::kIdVcvttpd2dq: + mustUseEvex = opCount >= 2 && Reg::isYmm(operands[0]); + break; + + // Special case: These instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode, then + // AVX-512 introduced `reg, reg/mem, imm` combination that uses EVEX prefix. This means that if + // the second operand is memory then this is AVX-512_BW instruction and not AVX/AVX2 instruction. + case Inst::kIdVpslldq: + case Inst::kIdVpslld: + case Inst::kIdVpsllq: + case Inst::kIdVpsllw: + case Inst::kIdVpsrad: + case Inst::kIdVpsraq: + case Inst::kIdVpsraw: + case Inst::kIdVpsrld: + case Inst::kIdVpsrldq: + case Inst::kIdVpsrlq: + case Inst::kIdVpsrlw: + mustUseEvex = opCount >= 2 && operands[1].isMem(); + break; + // Special case: VPERMPD - AVX2 vs AVX512-F case. case Inst::kIdVpermpd: mustUseEvex = opCount >= 3 && !operands[2].isImm(); @@ -1618,6 +1678,68 @@ UNIT(x86_inst_api_text) { "Instructions do not match \"%s\" (#%u) != \"%s\" (#%u)", aName.data(), a, bName.data(), b); } } + +template +static Error queryRWInfoSimple(InstRWInfo* out, Arch arch, InstId instId, InstOptions options, Args&&... args) { + BaseInst inst(instId); + inst.addOptions(options); + Operand_ opArray[] = { std::forward(args)... }; + return InstInternal::queryRWInfo(arch, inst, opArray, sizeof...(args), out); +} + +UNIT(x86_inst_api_rm_feature) { + INFO("Verifying whether RM/feature is reported correctly for PEXTRW instruction"); + { + InstRWInfo rwi; + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdPextrw, InstOptions::kNone, eax, mm1, imm(1)); + EXPECT(rwi.rmFeature() == 0); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdPextrw, InstOptions::kNone, eax, xmm1, imm(1)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kSSE4_1); + } + + INFO("Verifying whether RM/feature is reported correctly for AVX512 shift instructions"); + { + InstRWInfo rwi; + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslld, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllq, InstOptions::kNone, ymm1, ymm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrad, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrld, InstOptions::kNone, ymm1, ymm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrlq, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslldq, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllw, InstOptions::kNone, ymm1, ymm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsraw, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrldq, InstOptions::kNone, ymm1, ymm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrlw, InstOptions::kNone, xmm1, xmm2, imm(8)); + EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslld, InstOptions::kNone, xmm1, xmm2, xmm3); + EXPECT(rwi.rmFeature() == 0); + + queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllw, InstOptions::kNone, xmm1, xmm2, xmm3); + EXPECT(rwi.rmFeature() == 0); + } +} #endif ASMJIT_END_SUB_NAMESPACE diff --git a/erts/emulator/asmjit/x86/x86instdb.cpp b/erts/emulator/asmjit/x86/x86instdb.cpp index 3bf5d23ffd0c..ef65910d4336 100644 --- a/erts/emulator/asmjit/x86/x86instdb.cpp +++ b/erts/emulator/asmjit/x86/x86instdb.cpp @@ -47,17 +47,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define E(PREFIX, OPCODE, ModO, LL, W, EvexW, N, TT) (O_ENCODE(Opcode::k##PREFIX, 0x##OPCODE, Opcode::kModO_##ModO, Opcode::kLL_##LL, Opcode::kW_##W, Opcode::kEvex_W_##EvexW, Opcode::kCDSHL_##N, Opcode::kCDTT_##TT) | Opcode::kMM_ForceEvex) #define O_FPU(PREFIX, OPCODE, ModO) (Opcode::kFPU_##PREFIX | (0x##OPCODE & 0xFFu) | ((0x##OPCODE >> 8) << Opcode::kFPU_2B_Shift) | Opcode::kModO_##ModO) -// Don't store `_nameDataIndex` if instruction names are disabled. Since some -// APIs can use `_nameDataIndex` it's much safer if it's zero if it's not defined. -#ifndef ASMJIT_NO_TEXT - #define NAME_DATA_INDEX(Index) Index -#else - #define NAME_DATA_INDEX(Index) 0 -#endif - // Defines an X86 instruction. -#define INST(id, encoding, opcode0, opcode1, mainOpcodeIndex, altOpcodeIndex, nameDataIndex, commomInfoIndex, additionalInfoIndex) { \ - uint32_t(NAME_DATA_INDEX(nameDataIndex)), \ +#define INST(id, encoding, opcode0, opcode1, mainOpcodeIndex, altOpcodeIndex, commomInfoIndex, additionalInfoIndex) { \ + uint32_t(0), \ uint32_t(commomInfoIndex), \ uint32_t(additionalInfoIndex), \ uint8_t(InstDB::kEncoding##encoding), \ @@ -67,1674 +59,1674 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) } const InstDB::InstInfo InstDB::_instInfoTable[] = { - /*--------------------+--------------------+------------------+--------+------------------+--------+----+----+------+----+----+ - | Instruction | Instruction | Main Opcode | EVEX |Alternative Opcode| EVEX |Op0X|Op1X|Name-X|IdxA|IdxB| - | Id & Name | Encoding | (pp+mmm|op/o|L|w|W|N|TT.)|--(pp+mmm|op/o|L|w|W|N|TT.)| (auto-generated) | - +---------------------+--------------------+---------+----+-+-+-+-+----+---------+----+-+-+-+-+----+----+----+------+----+---*/ + /*--------------------+--------------------+------------------+--------+------------------+--------+----+----+----+----+ + | Instruction | Instruction | Main Opcode | EVEX |Alternative Opcode| EVEX |Op0X|Op1X|IdxA|IdxB| + | Id & Name | Encoding | (pp+mmm|op/o|L|w|W|N|TT.)|--(pp+mmm|op/o|L|w|W|N|TT.)| (auto-generated) | + +---------------------+--------------------+---------+----+-+-+-+-+----+---------+----+-+-+-+-+----+----+----+----+---*/ // ${InstInfo:Begin} - INST(None , None , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), // #0 - INST(Aaa , X86Op_xAX , O(000000,37,_,_,_,_,_,_ ), 0 , 0 , 0 , 1 , 1 , 1 ), // #1 - INST(Aad , X86I_xAX , O(000000,D5,_,_,_,_,_,_ ), 0 , 0 , 0 , 5 , 2 , 1 ), // #2 - INST(Aam , X86I_xAX , O(000000,D4,_,_,_,_,_,_ ), 0 , 0 , 0 , 9 , 2 , 1 ), // #3 - INST(Aas , X86Op_xAX , O(000000,3F,_,_,_,_,_,_ ), 0 , 0 , 0 , 13 , 1 , 1 ), // #4 - INST(Adc , X86Arith , O(000000,10,2,_,x,_,_,_ ), 0 , 1 , 0 , 17 , 3 , 2 ), // #5 - INST(Adcx , X86Rm , O(660F38,F6,_,_,x,_,_,_ ), 0 , 2 , 0 , 21 , 4 , 3 ), // #6 - INST(Add , X86Arith , O(000000,00,0,_,x,_,_,_ ), 0 , 0 , 0 , 3146 , 3 , 1 ), // #7 - INST(Addpd , ExtRm , O(660F00,58,_,_,_,_,_,_ ), 0 , 3 , 0 , 5788 , 5 , 4 ), // #8 - INST(Addps , ExtRm , O(000F00,58,_,_,_,_,_,_ ), 0 , 4 , 0 , 5800 , 5 , 5 ), // #9 - INST(Addsd , ExtRm , O(F20F00,58,_,_,_,_,_,_ ), 0 , 5 , 0 , 6118 , 6 , 4 ), // #10 - INST(Addss , ExtRm , O(F30F00,58,_,_,_,_,_,_ ), 0 , 6 , 0 , 3283 , 7 , 5 ), // #11 - INST(Addsubpd , ExtRm , O(660F00,D0,_,_,_,_,_,_ ), 0 , 3 , 0 , 5410 , 5 , 6 ), // #12 - INST(Addsubps , ExtRm , O(F20F00,D0,_,_,_,_,_,_ ), 0 , 5 , 0 , 5422 , 5 , 6 ), // #13 - INST(Adox , X86Rm , O(F30F38,F6,_,_,x,_,_,_ ), 0 , 7 , 0 , 26 , 4 , 7 ), // #14 - INST(Aesdec , ExtRm , O(660F38,DE,_,_,_,_,_,_ ), 0 , 2 , 0 , 3352 , 5 , 8 ), // #15 - INST(Aesdeclast , ExtRm , O(660F38,DF,_,_,_,_,_,_ ), 0 , 2 , 0 , 3360 , 5 , 8 ), // #16 - INST(Aesenc , ExtRm , O(660F38,DC,_,_,_,_,_,_ ), 0 , 2 , 0 , 3372 , 5 , 8 ), // #17 - INST(Aesenclast , ExtRm , O(660F38,DD,_,_,_,_,_,_ ), 0 , 2 , 0 , 3380 , 5 , 8 ), // #18 - INST(Aesimc , ExtRm , O(660F38,DB,_,_,_,_,_,_ ), 0 , 2 , 0 , 3392 , 5 , 8 ), // #19 - INST(Aeskeygenassist , ExtRmi , O(660F3A,DF,_,_,_,_,_,_ ), 0 , 8 , 0 , 3400 , 8 , 8 ), // #20 - INST(And , X86Arith , O(000000,20,4,_,x,_,_,_ ), 0 , 9 , 0 , 2525 , 9 , 1 ), // #21 - INST(Andn , VexRvm_Wx , V(000F38,F2,_,0,x,_,_,_ ), 0 , 10 , 0 , 7789 , 10 , 9 ), // #22 - INST(Andnpd , ExtRm , O(660F00,55,_,_,_,_,_,_ ), 0 , 3 , 0 , 3433 , 5 , 4 ), // #23 - INST(Andnps , ExtRm , O(000F00,55,_,_,_,_,_,_ ), 0 , 4 , 0 , 3441 , 5 , 5 ), // #24 - INST(Andpd , ExtRm , O(660F00,54,_,_,_,_,_,_ ), 0 , 3 , 0 , 4745 , 11 , 4 ), // #25 - INST(Andps , ExtRm , O(000F00,54,_,_,_,_,_,_ ), 0 , 4 , 0 , 4755 , 11 , 5 ), // #26 - INST(Arpl , X86Mr_NoSize , O(000000,63,_,_,_,_,_,_ ), 0 , 0 , 0 , 31 , 12 , 10 ), // #27 - INST(Bextr , VexRmv_Wx , V(000F38,F7,_,0,x,_,_,_ ), 0 , 10 , 0 , 36 , 13 , 9 ), // #28 - INST(Blcfill , VexVm_Wx , V(XOP_M9,01,1,0,x,_,_,_ ), 0 , 11 , 0 , 42 , 14 , 11 ), // #29 - INST(Blci , VexVm_Wx , V(XOP_M9,02,6,0,x,_,_,_ ), 0 , 12 , 0 , 50 , 14 , 11 ), // #30 - INST(Blcic , VexVm_Wx , V(XOP_M9,01,5,0,x,_,_,_ ), 0 , 13 , 0 , 55 , 14 , 11 ), // #31 - INST(Blcmsk , VexVm_Wx , V(XOP_M9,02,1,0,x,_,_,_ ), 0 , 11 , 0 , 61 , 14 , 11 ), // #32 - INST(Blcs , VexVm_Wx , V(XOP_M9,01,3,0,x,_,_,_ ), 0 , 14 , 0 , 68 , 14 , 11 ), // #33 - INST(Blendpd , ExtRmi , O(660F3A,0D,_,_,_,_,_,_ ), 0 , 8 , 0 , 3483 , 8 , 12 ), // #34 - INST(Blendps , ExtRmi , O(660F3A,0C,_,_,_,_,_,_ ), 0 , 8 , 0 , 3492 , 8 , 12 ), // #35 - INST(Blendvpd , ExtRm_XMM0 , O(660F38,15,_,_,_,_,_,_ ), 0 , 2 , 0 , 3501 , 15 , 12 ), // #36 - INST(Blendvps , ExtRm_XMM0 , O(660F38,14,_,_,_,_,_,_ ), 0 , 2 , 0 , 3511 , 15 , 12 ), // #37 - INST(Blsfill , VexVm_Wx , V(XOP_M9,01,2,0,x,_,_,_ ), 0 , 15 , 0 , 73 , 14 , 11 ), // #38 - INST(Blsi , VexVm_Wx , V(000F38,F3,3,0,x,_,_,_ ), 0 , 16 , 0 , 81 , 14 , 9 ), // #39 - INST(Blsic , VexVm_Wx , V(XOP_M9,01,6,0,x,_,_,_ ), 0 , 12 , 0 , 86 , 14 , 11 ), // #40 - INST(Blsmsk , VexVm_Wx , V(000F38,F3,2,0,x,_,_,_ ), 0 , 17 , 0 , 92 , 14 , 9 ), // #41 - INST(Blsr , VexVm_Wx , V(000F38,F3,1,0,x,_,_,_ ), 0 , 18 , 0 , 99 , 14 , 9 ), // #42 - INST(Bndcl , X86Rm , O(F30F00,1A,_,_,_,_,_,_ ), 0 , 6 , 0 , 104 , 16 , 13 ), // #43 - INST(Bndcn , X86Rm , O(F20F00,1B,_,_,_,_,_,_ ), 0 , 5 , 0 , 110 , 16 , 13 ), // #44 - INST(Bndcu , X86Rm , O(F20F00,1A,_,_,_,_,_,_ ), 0 , 5 , 0 , 116 , 16 , 13 ), // #45 - INST(Bndldx , X86Rm , O(000F00,1A,_,_,_,_,_,_ ), 0 , 4 , 0 , 122 , 17 , 13 ), // #46 - INST(Bndmk , X86Rm , O(F30F00,1B,_,_,_,_,_,_ ), 0 , 6 , 0 , 129 , 18 , 13 ), // #47 - INST(Bndmov , X86Bndmov , O(660F00,1A,_,_,_,_,_,_ ), O(660F00,1B,_,_,_,_,_,_ ), 3 , 1 , 135 , 19 , 13 ), // #48 - INST(Bndstx , X86Mr , O(000F00,1B,_,_,_,_,_,_ ), 0 , 4 , 0 , 142 , 20 , 13 ), // #49 - INST(Bound , X86Rm , O(000000,62,_,_,_,_,_,_ ), 0 , 0 , 0 , 149 , 21 , 0 ), // #50 - INST(Bsf , X86Rm , O(000F00,BC,_,_,x,_,_,_ ), 0 , 4 , 0 , 155 , 22 , 1 ), // #51 - INST(Bsr , X86Rm , O(000F00,BD,_,_,x,_,_,_ ), 0 , 4 , 0 , 159 , 22 , 1 ), // #52 - INST(Bswap , X86Bswap , O(000F00,C8,_,_,x,_,_,_ ), 0 , 4 , 0 , 163 , 23 , 0 ), // #53 - INST(Bt , X86Bt , O(000F00,A3,_,_,x,_,_,_ ), O(000F00,BA,4,_,x,_,_,_ ), 4 , 2 , 169 , 24 , 14 ), // #54 - INST(Btc , X86Bt , O(000F00,BB,_,_,x,_,_,_ ), O(000F00,BA,7,_,x,_,_,_ ), 4 , 3 , 172 , 25 , 14 ), // #55 - INST(Btr , X86Bt , O(000F00,B3,_,_,x,_,_,_ ), O(000F00,BA,6,_,x,_,_,_ ), 4 , 4 , 176 , 25 , 14 ), // #56 - INST(Bts , X86Bt , O(000F00,AB,_,_,x,_,_,_ ), O(000F00,BA,5,_,x,_,_,_ ), 4 , 5 , 180 , 25 , 14 ), // #57 - INST(Bzhi , VexRmv_Wx , V(000F38,F5,_,0,x,_,_,_ ), 0 , 10 , 0 , 184 , 13 , 15 ), // #58 - INST(Call , X86Call , O(000000,FF,2,_,_,_,_,_ ), 0 , 1 , 0 , 3038 , 26 , 1 ), // #59 - INST(Cbw , X86Op_xAX , O(660000,98,_,_,_,_,_,_ ), 0 , 19 , 0 , 189 , 27 , 0 ), // #60 - INST(Cdq , X86Op_xDX_xAX , O(000000,99,_,_,_,_,_,_ ), 0 , 0 , 0 , 193 , 28 , 0 ), // #61 - INST(Cdqe , X86Op_xAX , O(000000,98,_,_,1,_,_,_ ), 0 , 20 , 0 , 197 , 29 , 0 ), // #62 - INST(Clac , X86Op , O(000F01,CA,_,_,_,_,_,_ ), 0 , 21 , 0 , 202 , 30 , 16 ), // #63 - INST(Clc , X86Op , O(000000,F8,_,_,_,_,_,_ ), 0 , 0 , 0 , 207 , 30 , 17 ), // #64 - INST(Cld , X86Op , O(000000,FC,_,_,_,_,_,_ ), 0 , 0 , 0 , 211 , 30 , 18 ), // #65 - INST(Cldemote , X86M_Only , O(000F00,1C,0,_,_,_,_,_ ), 0 , 4 , 0 , 215 , 31 , 19 ), // #66 - INST(Clflush , X86M_Only , O(000F00,AE,7,_,_,_,_,_ ), 0 , 22 , 0 , 224 , 31 , 20 ), // #67 - INST(Clflushopt , X86M_Only , O(660F00,AE,7,_,_,_,_,_ ), 0 , 23 , 0 , 232 , 31 , 21 ), // #68 - INST(Clgi , X86Op , O(000F01,DD,_,_,_,_,_,_ ), 0 , 21 , 0 , 243 , 30 , 22 ), // #69 - INST(Cli , X86Op , O(000000,FA,_,_,_,_,_,_ ), 0 , 0 , 0 , 248 , 30 , 23 ), // #70 - INST(Clrssbsy , X86M_Only , O(F30F00,AE,6,_,_,_,_,_ ), 0 , 24 , 0 , 252 , 32 , 24 ), // #71 - INST(Clts , X86Op , O(000F00,06,_,_,_,_,_,_ ), 0 , 4 , 0 , 261 , 30 , 0 ), // #72 - INST(Clui , X86Op , O(F30F01,EE,_,_,_,_,_,_ ), 0 , 25 , 0 , 266 , 33 , 25 ), // #73 - INST(Clwb , X86M_Only , O(660F00,AE,6,_,_,_,_,_ ), 0 , 26 , 0 , 271 , 31 , 26 ), // #74 - INST(Clzero , X86Op_MemZAX , O(000F01,FC,_,_,_,_,_,_ ), 0 , 21 , 0 , 276 , 34 , 27 ), // #75 - INST(Cmc , X86Op , O(000000,F5,_,_,_,_,_,_ ), 0 , 0 , 0 , 283 , 30 , 28 ), // #76 - INST(Cmova , X86Rm , O(000F00,47,_,_,x,_,_,_ ), 0 , 4 , 0 , 287 , 22 , 29 ), // #77 - INST(Cmovae , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 293 , 22 , 30 ), // #78 - INST(Cmovb , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 648 , 22 , 30 ), // #79 - INST(Cmovbe , X86Rm , O(000F00,46,_,_,x,_,_,_ ), 0 , 4 , 0 , 655 , 22 , 29 ), // #80 - INST(Cmovc , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 300 , 22 , 30 ), // #81 - INST(Cmove , X86Rm , O(000F00,44,_,_,x,_,_,_ ), 0 , 4 , 0 , 663 , 22 , 31 ), // #82 - INST(Cmovg , X86Rm , O(000F00,4F,_,_,x,_,_,_ ), 0 , 4 , 0 , 306 , 22 , 32 ), // #83 - INST(Cmovge , X86Rm , O(000F00,4D,_,_,x,_,_,_ ), 0 , 4 , 0 , 312 , 22 , 33 ), // #84 - INST(Cmovl , X86Rm , O(000F00,4C,_,_,x,_,_,_ ), 0 , 4 , 0 , 319 , 22 , 33 ), // #85 - INST(Cmovle , X86Rm , O(000F00,4E,_,_,x,_,_,_ ), 0 , 4 , 0 , 325 , 22 , 32 ), // #86 - INST(Cmovna , X86Rm , O(000F00,46,_,_,x,_,_,_ ), 0 , 4 , 0 , 332 , 22 , 29 ), // #87 - INST(Cmovnae , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 339 , 22 , 30 ), // #88 - INST(Cmovnb , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 670 , 22 , 30 ), // #89 - INST(Cmovnbe , X86Rm , O(000F00,47,_,_,x,_,_,_ ), 0 , 4 , 0 , 678 , 22 , 29 ), // #90 - INST(Cmovnc , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 347 , 22 , 30 ), // #91 - INST(Cmovne , X86Rm , O(000F00,45,_,_,x,_,_,_ ), 0 , 4 , 0 , 687 , 22 , 31 ), // #92 - INST(Cmovng , X86Rm , O(000F00,4E,_,_,x,_,_,_ ), 0 , 4 , 0 , 354 , 22 , 32 ), // #93 - INST(Cmovnge , X86Rm , O(000F00,4C,_,_,x,_,_,_ ), 0 , 4 , 0 , 361 , 22 , 33 ), // #94 - INST(Cmovnl , X86Rm , O(000F00,4D,_,_,x,_,_,_ ), 0 , 4 , 0 , 369 , 22 , 33 ), // #95 - INST(Cmovnle , X86Rm , O(000F00,4F,_,_,x,_,_,_ ), 0 , 4 , 0 , 376 , 22 , 32 ), // #96 - INST(Cmovno , X86Rm , O(000F00,41,_,_,x,_,_,_ ), 0 , 4 , 0 , 384 , 22 , 34 ), // #97 - INST(Cmovnp , X86Rm , O(000F00,4B,_,_,x,_,_,_ ), 0 , 4 , 0 , 391 , 22 , 35 ), // #98 - INST(Cmovns , X86Rm , O(000F00,49,_,_,x,_,_,_ ), 0 , 4 , 0 , 398 , 22 , 36 ), // #99 - INST(Cmovnz , X86Rm , O(000F00,45,_,_,x,_,_,_ ), 0 , 4 , 0 , 405 , 22 , 31 ), // #100 - INST(Cmovo , X86Rm , O(000F00,40,_,_,x,_,_,_ ), 0 , 4 , 0 , 412 , 22 , 34 ), // #101 - INST(Cmovp , X86Rm , O(000F00,4A,_,_,x,_,_,_ ), 0 , 4 , 0 , 418 , 22 , 35 ), // #102 - INST(Cmovpe , X86Rm , O(000F00,4A,_,_,x,_,_,_ ), 0 , 4 , 0 , 424 , 22 , 35 ), // #103 - INST(Cmovpo , X86Rm , O(000F00,4B,_,_,x,_,_,_ ), 0 , 4 , 0 , 431 , 22 , 35 ), // #104 - INST(Cmovs , X86Rm , O(000F00,48,_,_,x,_,_,_ ), 0 , 4 , 0 , 438 , 22 , 36 ), // #105 - INST(Cmovz , X86Rm , O(000F00,44,_,_,x,_,_,_ ), 0 , 4 , 0 , 444 , 22 , 31 ), // #106 - INST(Cmp , X86Arith , O(000000,38,7,_,x,_,_,_ ), 0 , 27 , 0 , 450 , 35 , 1 ), // #107 - INST(Cmppd , ExtRmi , O(660F00,C2,_,_,_,_,_,_ ), 0 , 3 , 0 , 3737 , 8 , 4 ), // #108 - INST(Cmpps , ExtRmi , O(000F00,C2,_,_,_,_,_,_ ), 0 , 4 , 0 , 3751 , 8 , 5 ), // #109 - INST(Cmps , X86StrMm , O(000000,A6,_,_,_,_,_,_ ), 0 , 0 , 0 , 454 , 36 , 37 ), // #110 - INST(Cmpsd , ExtRmi , O(F20F00,C2,_,_,_,_,_,_ ), 0 , 5 , 0 , 3758 , 37 , 4 ), // #111 - INST(Cmpss , ExtRmi , O(F30F00,C2,_,_,_,_,_,_ ), 0 , 6 , 0 , 3772 , 38 , 5 ), // #112 - INST(Cmpxchg , X86Cmpxchg , O(000F00,B0,_,_,x,_,_,_ ), 0 , 4 , 0 , 459 , 39 , 38 ), // #113 - INST(Cmpxchg16b , X86Cmpxchg8b_16b , O(000F00,C7,1,_,1,_,_,_ ), 0 , 28 , 0 , 467 , 40 , 39 ), // #114 - INST(Cmpxchg8b , X86Cmpxchg8b_16b , O(000F00,C7,1,_,_,_,_,_ ), 0 , 29 , 0 , 478 , 41 , 40 ), // #115 - INST(Comisd , ExtRm , O(660F00,2F,_,_,_,_,_,_ ), 0 , 3 , 0 , 11391, 6 , 41 ), // #116 - INST(Comiss , ExtRm , O(000F00,2F,_,_,_,_,_,_ ), 0 , 4 , 0 , 11409, 7 , 42 ), // #117 - INST(Cpuid , X86Op , O(000F00,A2,_,_,_,_,_,_ ), 0 , 4 , 0 , 488 , 42 , 43 ), // #118 - INST(Cqo , X86Op_xDX_xAX , O(000000,99,_,_,1,_,_,_ ), 0 , 20 , 0 , 494 , 43 , 0 ), // #119 - INST(Crc32 , X86Crc , O(F20F38,F0,_,_,x,_,_,_ ), 0 , 30 , 0 , 498 , 44 , 44 ), // #120 - INST(Cvtdq2pd , ExtRm , O(F30F00,E6,_,_,_,_,_,_ ), 0 , 6 , 0 , 3827 , 6 , 4 ), // #121 - INST(Cvtdq2ps , ExtRm , O(000F00,5B,_,_,_,_,_,_ ), 0 , 4 , 0 , 3847 , 5 , 4 ), // #122 - INST(Cvtpd2dq , ExtRm , O(F20F00,E6,_,_,_,_,_,_ ), 0 , 5 , 0 , 3886 , 5 , 4 ), // #123 - INST(Cvtpd2pi , ExtRm , O(660F00,2D,_,_,_,_,_,_ ), 0 , 3 , 0 , 504 , 45 , 4 ), // #124 - INST(Cvtpd2ps , ExtRm , O(660F00,5A,_,_,_,_,_,_ ), 0 , 3 , 0 , 3906 , 5 , 4 ), // #125 - INST(Cvtpi2pd , ExtRm , O(660F00,2A,_,_,_,_,_,_ ), 0 , 3 , 0 , 513 , 46 , 4 ), // #126 - INST(Cvtpi2ps , ExtRm , O(000F00,2A,_,_,_,_,_,_ ), 0 , 4 , 0 , 522 , 46 , 5 ), // #127 - INST(Cvtps2dq , ExtRm , O(660F00,5B,_,_,_,_,_,_ ), 0 , 3 , 0 , 4040 , 5 , 4 ), // #128 - INST(Cvtps2pd , ExtRm , O(000F00,5A,_,_,_,_,_,_ ), 0 , 4 , 0 , 4050 , 6 , 4 ), // #129 - INST(Cvtps2pi , ExtRm , O(000F00,2D,_,_,_,_,_,_ ), 0 , 4 , 0 , 531 , 47 , 5 ), // #130 - INST(Cvtsd2si , ExtRm_Wx_GpqOnly , O(F20F00,2D,_,_,x,_,_,_ ), 0 , 5 , 0 , 4153 , 48 , 4 ), // #131 - INST(Cvtsd2ss , ExtRm , O(F20F00,5A,_,_,_,_,_,_ ), 0 , 5 , 0 , 4163 , 6 , 4 ), // #132 - INST(Cvtsi2sd , ExtRm_Wx , O(F20F00,2A,_,_,x,_,_,_ ), 0 , 5 , 0 , 4225 , 49 , 4 ), // #133 - INST(Cvtsi2ss , ExtRm_Wx , O(F30F00,2A,_,_,x,_,_,_ ), 0 , 6 , 0 , 4245 , 49 , 5 ), // #134 - INST(Cvtss2sd , ExtRm , O(F30F00,5A,_,_,_,_,_,_ ), 0 , 6 , 0 , 4255 , 7 , 4 ), // #135 - INST(Cvtss2si , ExtRm_Wx_GpqOnly , O(F30F00,2D,_,_,x,_,_,_ ), 0 , 6 , 0 , 4275 , 50 , 5 ), // #136 - INST(Cvttpd2dq , ExtRm , O(660F00,E6,_,_,_,_,_,_ ), 0 , 3 , 0 , 4296 , 5 , 4 ), // #137 - INST(Cvttpd2pi , ExtRm , O(660F00,2C,_,_,_,_,_,_ ), 0 , 3 , 0 , 540 , 45 , 4 ), // #138 - INST(Cvttps2dq , ExtRm , O(F30F00,5B,_,_,_,_,_,_ ), 0 , 6 , 0 , 4409 , 5 , 4 ), // #139 - INST(Cvttps2pi , ExtRm , O(000F00,2C,_,_,_,_,_,_ ), 0 , 4 , 0 , 550 , 47 , 5 ), // #140 - INST(Cvttsd2si , ExtRm_Wx_GpqOnly , O(F20F00,2C,_,_,x,_,_,_ ), 0 , 5 , 0 , 4455 , 48 , 4 ), // #141 - INST(Cvttss2si , ExtRm_Wx_GpqOnly , O(F30F00,2C,_,_,x,_,_,_ ), 0 , 6 , 0 , 4501 , 50 , 5 ), // #142 - INST(Cwd , X86Op_xDX_xAX , O(660000,99,_,_,_,_,_,_ ), 0 , 19 , 0 , 560 , 51 , 0 ), // #143 - INST(Cwde , X86Op_xAX , O(000000,98,_,_,_,_,_,_ ), 0 , 0 , 0 , 564 , 52 , 0 ), // #144 - INST(Daa , X86Op , O(000000,27,_,_,_,_,_,_ ), 0 , 0 , 0 , 569 , 1 , 1 ), // #145 - INST(Das , X86Op , O(000000,2F,_,_,_,_,_,_ ), 0 , 0 , 0 , 573 , 1 , 1 ), // #146 - INST(Dec , X86IncDec , O(000000,FE,1,_,x,_,_,_ ), O(000000,48,_,_,x,_,_,_ ), 31 , 6 , 3355 , 53 , 45 ), // #147 - INST(Div , X86M_GPB_MulDiv , O(000000,F6,6,_,x,_,_,_ ), 0 , 32 , 0 , 810 , 54 , 1 ), // #148 - INST(Divpd , ExtRm , O(660F00,5E,_,_,_,_,_,_ ), 0 , 3 , 0 , 4652 , 5 , 4 ), // #149 - INST(Divps , ExtRm , O(000F00,5E,_,_,_,_,_,_ ), 0 , 4 , 0 , 4666 , 5 , 5 ), // #150 - INST(Divsd , ExtRm , O(F20F00,5E,_,_,_,_,_,_ ), 0 , 5 , 0 , 4673 , 6 , 4 ), // #151 - INST(Divss , ExtRm , O(F30F00,5E,_,_,_,_,_,_ ), 0 , 6 , 0 , 4687 , 7 , 5 ), // #152 - INST(Dppd , ExtRmi , O(660F3A,41,_,_,_,_,_,_ ), 0 , 8 , 0 , 4704 , 8 , 12 ), // #153 - INST(Dpps , ExtRmi , O(660F3A,40,_,_,_,_,_,_ ), 0 , 8 , 0 , 4710 , 8 , 12 ), // #154 - INST(Emms , X86Op , O(000F00,77,_,_,_,_,_,_ ), 0 , 4 , 0 , 778 , 55 , 46 ), // #155 - INST(Endbr32 , X86Op_Mod11RM , O(F30F00,1E,7,_,_,_,_,3 ), 0 , 33 , 0 , 577 , 30 , 47 ), // #156 - INST(Endbr64 , X86Op_Mod11RM , O(F30F00,1E,7,_,_,_,_,2 ), 0 , 34 , 0 , 585 , 30 , 47 ), // #157 - INST(Enqcmd , X86EnqcmdMovdir64b , O(F20F38,F8,_,_,_,_,_,_ ), 0 , 30 , 0 , 593 , 56 , 48 ), // #158 - INST(Enqcmds , X86EnqcmdMovdir64b , O(F30F38,F8,_,_,_,_,_,_ ), 0 , 7 , 0 , 600 , 56 , 48 ), // #159 - INST(Enter , X86Enter , O(000000,C8,_,_,_,_,_,_ ), 0 , 0 , 0 , 3046 , 57 , 0 ), // #160 - INST(Extractps , ExtExtract , O(660F3A,17,_,_,_,_,_,_ ), 0 , 8 , 0 , 4900 , 58 , 12 ), // #161 - INST(Extrq , ExtExtrq , O(660F00,79,_,_,_,_,_,_ ), O(660F00,78,0,_,_,_,_,_ ), 3 , 7 , 8625 , 59 , 49 ), // #162 - INST(F2xm1 , FpuOp , O_FPU(00,D9F0,_) , 0 , 35 , 0 , 608 , 30 , 0 ), // #163 - INST(Fabs , FpuOp , O_FPU(00,D9E1,_) , 0 , 35 , 0 , 614 , 30 , 0 ), // #164 - INST(Fadd , FpuArith , O_FPU(00,C0C0,0) , 0 , 36 , 0 , 2121 , 60 , 0 ), // #165 - INST(Faddp , FpuRDef , O_FPU(00,DEC0,_) , 0 , 37 , 0 , 619 , 61 , 0 ), // #166 - INST(Fbld , X86M_Only , O_FPU(00,00DF,4) , 0 , 38 , 0 , 625 , 62 , 0 ), // #167 - INST(Fbstp , X86M_Only , O_FPU(00,00DF,6) , 0 , 39 , 0 , 630 , 62 , 0 ), // #168 - INST(Fchs , FpuOp , O_FPU(00,D9E0,_) , 0 , 35 , 0 , 636 , 30 , 0 ), // #169 - INST(Fclex , FpuOp , O_FPU(9B,DBE2,_) , 0 , 40 , 0 , 641 , 30 , 0 ), // #170 - INST(Fcmovb , FpuR , O_FPU(00,DAC0,_) , 0 , 41 , 0 , 647 , 63 , 30 ), // #171 - INST(Fcmovbe , FpuR , O_FPU(00,DAD0,_) , 0 , 41 , 0 , 654 , 63 , 29 ), // #172 - INST(Fcmove , FpuR , O_FPU(00,DAC8,_) , 0 , 41 , 0 , 662 , 63 , 31 ), // #173 - INST(Fcmovnb , FpuR , O_FPU(00,DBC0,_) , 0 , 42 , 0 , 669 , 63 , 30 ), // #174 - INST(Fcmovnbe , FpuR , O_FPU(00,DBD0,_) , 0 , 42 , 0 , 677 , 63 , 29 ), // #175 - INST(Fcmovne , FpuR , O_FPU(00,DBC8,_) , 0 , 42 , 0 , 686 , 63 , 31 ), // #176 - INST(Fcmovnu , FpuR , O_FPU(00,DBD8,_) , 0 , 42 , 0 , 694 , 63 , 35 ), // #177 - INST(Fcmovu , FpuR , O_FPU(00,DAD8,_) , 0 , 41 , 0 , 702 , 63 , 35 ), // #178 - INST(Fcom , FpuCom , O_FPU(00,D0D0,2) , 0 , 43 , 0 , 709 , 64 , 0 ), // #179 - INST(Fcomi , FpuR , O_FPU(00,DBF0,_) , 0 , 42 , 0 , 714 , 63 , 50 ), // #180 - INST(Fcomip , FpuR , O_FPU(00,DFF0,_) , 0 , 44 , 0 , 720 , 63 , 50 ), // #181 - INST(Fcomp , FpuCom , O_FPU(00,D8D8,3) , 0 , 45 , 0 , 727 , 64 , 0 ), // #182 - INST(Fcompp , FpuOp , O_FPU(00,DED9,_) , 0 , 37 , 0 , 733 , 30 , 0 ), // #183 - INST(Fcos , FpuOp , O_FPU(00,D9FF,_) , 0 , 35 , 0 , 740 , 30 , 0 ), // #184 - INST(Fdecstp , FpuOp , O_FPU(00,D9F6,_) , 0 , 35 , 0 , 745 , 30 , 0 ), // #185 - INST(Fdiv , FpuArith , O_FPU(00,F0F8,6) , 0 , 46 , 0 , 753 , 60 , 0 ), // #186 - INST(Fdivp , FpuRDef , O_FPU(00,DEF8,_) , 0 , 37 , 0 , 758 , 61 , 0 ), // #187 - INST(Fdivr , FpuArith , O_FPU(00,F8F0,7) , 0 , 47 , 0 , 764 , 60 , 0 ), // #188 - INST(Fdivrp , FpuRDef , O_FPU(00,DEF0,_) , 0 , 37 , 0 , 770 , 61 , 0 ), // #189 - INST(Femms , X86Op , O(000F00,0E,_,_,_,_,_,_ ), 0 , 4 , 0 , 777 , 30 , 51 ), // #190 - INST(Ffree , FpuR , O_FPU(00,DDC0,_) , 0 , 48 , 0 , 783 , 63 , 0 ), // #191 - INST(Fiadd , FpuM , O_FPU(00,00DA,0) , 0 , 49 , 0 , 789 , 65 , 0 ), // #192 - INST(Ficom , FpuM , O_FPU(00,00DA,2) , 0 , 50 , 0 , 795 , 65 , 0 ), // #193 - INST(Ficomp , FpuM , O_FPU(00,00DA,3) , 0 , 51 , 0 , 801 , 65 , 0 ), // #194 - INST(Fidiv , FpuM , O_FPU(00,00DA,6) , 0 , 39 , 0 , 808 , 65 , 0 ), // #195 - INST(Fidivr , FpuM , O_FPU(00,00DA,7) , 0 , 52 , 0 , 814 , 65 , 0 ), // #196 - INST(Fild , FpuM , O_FPU(00,00DB,0) , O_FPU(00,00DF,5) , 49 , 8 , 821 , 66 , 0 ), // #197 - INST(Fimul , FpuM , O_FPU(00,00DA,1) , 0 , 53 , 0 , 826 , 65 , 0 ), // #198 - INST(Fincstp , FpuOp , O_FPU(00,D9F7,_) , 0 , 35 , 0 , 832 , 30 , 0 ), // #199 - INST(Finit , FpuOp , O_FPU(9B,DBE3,_) , 0 , 40 , 0 , 840 , 30 , 0 ), // #200 - INST(Fist , FpuM , O_FPU(00,00DB,2) , 0 , 50 , 0 , 846 , 65 , 0 ), // #201 - INST(Fistp , FpuM , O_FPU(00,00DB,3) , O_FPU(00,00DF,7) , 51 , 9 , 851 , 66 , 0 ), // #202 - INST(Fisttp , FpuM , O_FPU(00,00DB,1) , O_FPU(00,00DD,1) , 53 , 10 , 857 , 66 , 6 ), // #203 - INST(Fisub , FpuM , O_FPU(00,00DA,4) , 0 , 38 , 0 , 864 , 65 , 0 ), // #204 - INST(Fisubr , FpuM , O_FPU(00,00DA,5) , 0 , 54 , 0 , 870 , 65 , 0 ), // #205 - INST(Fld , FpuFldFst , O_FPU(00,00D9,0) , O_FPU(00,00DB,5) , 49 , 11 , 877 , 67 , 0 ), // #206 - INST(Fld1 , FpuOp , O_FPU(00,D9E8,_) , 0 , 35 , 0 , 881 , 30 , 0 ), // #207 - INST(Fldcw , X86M_Only , O_FPU(00,00D9,5) , 0 , 54 , 0 , 886 , 68 , 0 ), // #208 - INST(Fldenv , X86M_Only , O_FPU(00,00D9,4) , 0 , 38 , 0 , 892 , 69 , 0 ), // #209 - INST(Fldl2e , FpuOp , O_FPU(00,D9EA,_) , 0 , 35 , 0 , 899 , 30 , 0 ), // #210 - INST(Fldl2t , FpuOp , O_FPU(00,D9E9,_) , 0 , 35 , 0 , 906 , 30 , 0 ), // #211 - INST(Fldlg2 , FpuOp , O_FPU(00,D9EC,_) , 0 , 35 , 0 , 913 , 30 , 0 ), // #212 - INST(Fldln2 , FpuOp , O_FPU(00,D9ED,_) , 0 , 35 , 0 , 920 , 30 , 0 ), // #213 - INST(Fldpi , FpuOp , O_FPU(00,D9EB,_) , 0 , 35 , 0 , 927 , 30 , 0 ), // #214 - INST(Fldz , FpuOp , O_FPU(00,D9EE,_) , 0 , 35 , 0 , 933 , 30 , 0 ), // #215 - INST(Fmul , FpuArith , O_FPU(00,C8C8,1) , 0 , 55 , 0 , 2163 , 60 , 0 ), // #216 - INST(Fmulp , FpuRDef , O_FPU(00,DEC8,_) , 0 , 37 , 0 , 938 , 61 , 0 ), // #217 - INST(Fnclex , FpuOp , O_FPU(00,DBE2,_) , 0 , 42 , 0 , 944 , 30 , 0 ), // #218 - INST(Fninit , FpuOp , O_FPU(00,DBE3,_) , 0 , 42 , 0 , 951 , 30 , 0 ), // #219 - INST(Fnop , FpuOp , O_FPU(00,D9D0,_) , 0 , 35 , 0 , 958 , 30 , 0 ), // #220 - INST(Fnsave , X86M_Only , O_FPU(00,00DD,6) , 0 , 39 , 0 , 963 , 69 , 0 ), // #221 - INST(Fnstcw , X86M_Only , O_FPU(00,00D9,7) , 0 , 52 , 0 , 970 , 68 , 0 ), // #222 - INST(Fnstenv , X86M_Only , O_FPU(00,00D9,6) , 0 , 39 , 0 , 977 , 69 , 0 ), // #223 - INST(Fnstsw , FpuStsw , O_FPU(00,00DD,7) , O_FPU(00,DFE0,_) , 52 , 12 , 985 , 70 , 0 ), // #224 - INST(Fpatan , FpuOp , O_FPU(00,D9F3,_) , 0 , 35 , 0 , 992 , 30 , 0 ), // #225 - INST(Fprem , FpuOp , O_FPU(00,D9F8,_) , 0 , 35 , 0 , 999 , 30 , 0 ), // #226 - INST(Fprem1 , FpuOp , O_FPU(00,D9F5,_) , 0 , 35 , 0 , 1005 , 30 , 0 ), // #227 - INST(Fptan , FpuOp , O_FPU(00,D9F2,_) , 0 , 35 , 0 , 1012 , 30 , 0 ), // #228 - INST(Frndint , FpuOp , O_FPU(00,D9FC,_) , 0 , 35 , 0 , 1018 , 30 , 0 ), // #229 - INST(Frstor , X86M_Only , O_FPU(00,00DD,4) , 0 , 38 , 0 , 1026 , 69 , 0 ), // #230 - INST(Fsave , X86M_Only , O_FPU(9B,00DD,6) , 0 , 56 , 0 , 1033 , 69 , 0 ), // #231 - INST(Fscale , FpuOp , O_FPU(00,D9FD,_) , 0 , 35 , 0 , 1039 , 30 , 0 ), // #232 - INST(Fsin , FpuOp , O_FPU(00,D9FE,_) , 0 , 35 , 0 , 1046 , 30 , 0 ), // #233 - INST(Fsincos , FpuOp , O_FPU(00,D9FB,_) , 0 , 35 , 0 , 1051 , 30 , 0 ), // #234 - INST(Fsqrt , FpuOp , O_FPU(00,D9FA,_) , 0 , 35 , 0 , 1059 , 30 , 0 ), // #235 - INST(Fst , FpuFldFst , O_FPU(00,00D9,2) , 0 , 50 , 0 , 1065 , 71 , 0 ), // #236 - INST(Fstcw , X86M_Only , O_FPU(9B,00D9,7) , 0 , 57 , 0 , 1069 , 68 , 0 ), // #237 - INST(Fstenv , X86M_Only , O_FPU(9B,00D9,6) , 0 , 56 , 0 , 1075 , 69 , 0 ), // #238 - INST(Fstp , FpuFldFst , O_FPU(00,00D9,3) , O(000000,DB,7,_,_,_,_,_ ), 51 , 13 , 1082 , 67 , 0 ), // #239 - INST(Fstsw , FpuStsw , O_FPU(9B,00DD,7) , O_FPU(9B,DFE0,_) , 57 , 14 , 1087 , 70 , 0 ), // #240 - INST(Fsub , FpuArith , O_FPU(00,E0E8,4) , 0 , 58 , 0 , 2241 , 60 , 0 ), // #241 - INST(Fsubp , FpuRDef , O_FPU(00,DEE8,_) , 0 , 37 , 0 , 1093 , 61 , 0 ), // #242 - INST(Fsubr , FpuArith , O_FPU(00,E8E0,5) , 0 , 59 , 0 , 2247 , 60 , 0 ), // #243 - INST(Fsubrp , FpuRDef , O_FPU(00,DEE0,_) , 0 , 37 , 0 , 1099 , 61 , 0 ), // #244 - INST(Ftst , FpuOp , O_FPU(00,D9E4,_) , 0 , 35 , 0 , 1106 , 30 , 0 ), // #245 - INST(Fucom , FpuRDef , O_FPU(00,DDE0,_) , 0 , 48 , 0 , 1111 , 61 , 0 ), // #246 - INST(Fucomi , FpuR , O_FPU(00,DBE8,_) , 0 , 42 , 0 , 1117 , 63 , 50 ), // #247 - INST(Fucomip , FpuR , O_FPU(00,DFE8,_) , 0 , 44 , 0 , 1124 , 63 , 50 ), // #248 - INST(Fucomp , FpuRDef , O_FPU(00,DDE8,_) , 0 , 48 , 0 , 1132 , 61 , 0 ), // #249 - INST(Fucompp , FpuOp , O_FPU(00,DAE9,_) , 0 , 41 , 0 , 1139 , 30 , 0 ), // #250 - INST(Fwait , X86Op , O_FPU(00,009B,_) , 0 , 49 , 0 , 1147 , 30 , 0 ), // #251 - INST(Fxam , FpuOp , O_FPU(00,D9E5,_) , 0 , 35 , 0 , 1153 , 30 , 0 ), // #252 - INST(Fxch , FpuR , O_FPU(00,D9C8,_) , 0 , 35 , 0 , 1158 , 61 , 0 ), // #253 - INST(Fxrstor , X86M_Only , O(000F00,AE,1,_,_,_,_,_ ), 0 , 29 , 0 , 1163 , 69 , 52 ), // #254 - INST(Fxrstor64 , X86M_Only , O(000F00,AE,1,_,1,_,_,_ ), 0 , 28 , 0 , 1171 , 72 , 52 ), // #255 - INST(Fxsave , X86M_Only , O(000F00,AE,0,_,_,_,_,_ ), 0 , 4 , 0 , 1181 , 69 , 52 ), // #256 - INST(Fxsave64 , X86M_Only , O(000F00,AE,0,_,1,_,_,_ ), 0 , 60 , 0 , 1188 , 72 , 52 ), // #257 - INST(Fxtract , FpuOp , O_FPU(00,D9F4,_) , 0 , 35 , 0 , 1197 , 30 , 0 ), // #258 - INST(Fyl2x , FpuOp , O_FPU(00,D9F1,_) , 0 , 35 , 0 , 1205 , 30 , 0 ), // #259 - INST(Fyl2xp1 , FpuOp , O_FPU(00,D9F9,_) , 0 , 35 , 0 , 1211 , 30 , 0 ), // #260 - INST(Getsec , X86Op , O(000F00,37,_,_,_,_,_,_ ), 0 , 4 , 0 , 1219 , 30 , 53 ), // #261 - INST(Gf2p8affineinvqb , ExtRmi , O(660F3A,CF,_,_,_,_,_,_ ), 0 , 8 , 0 , 6789 , 8 , 54 ), // #262 - INST(Gf2p8affineqb , ExtRmi , O(660F3A,CE,_,_,_,_,_,_ ), 0 , 8 , 0 , 6807 , 8 , 54 ), // #263 - INST(Gf2p8mulb , ExtRm , O(660F38,CF,_,_,_,_,_,_ ), 0 , 2 , 0 , 6822 , 5 , 54 ), // #264 - INST(Haddpd , ExtRm , O(660F00,7C,_,_,_,_,_,_ ), 0 , 3 , 0 , 6833 , 5 , 6 ), // #265 - INST(Haddps , ExtRm , O(F20F00,7C,_,_,_,_,_,_ ), 0 , 5 , 0 , 6841 , 5 , 6 ), // #266 - INST(Hlt , X86Op , O(000000,F4,_,_,_,_,_,_ ), 0 , 0 , 0 , 1226 , 30 , 0 ), // #267 - INST(Hreset , X86Op_Mod11RM_I8 , O(F30F3A,F0,0,_,_,_,_,_ ), 0 , 61 , 0 , 1230 , 73 , 55 ), // #268 - INST(Hsubpd , ExtRm , O(660F00,7D,_,_,_,_,_,_ ), 0 , 3 , 0 , 6849 , 5 , 6 ), // #269 - INST(Hsubps , ExtRm , O(F20F00,7D,_,_,_,_,_,_ ), 0 , 5 , 0 , 6857 , 5 , 6 ), // #270 - INST(Idiv , X86M_GPB_MulDiv , O(000000,F6,7,_,x,_,_,_ ), 0 , 27 , 0 , 809 , 54 , 1 ), // #271 - INST(Imul , X86Imul , O(000000,F6,5,_,x,_,_,_ ), 0 , 62 , 0 , 827 , 74 , 1 ), // #272 - INST(In , X86In , O(000000,EC,_,_,_,_,_,_ ), O(000000,E4,_,_,_,_,_,_ ), 0 , 15 , 11572, 75 , 0 ), // #273 - INST(Inc , X86IncDec , O(000000,FE,0,_,x,_,_,_ ), O(000000,40,_,_,x,_,_,_ ), 0 , 16 , 1237 , 53 , 45 ), // #274 - INST(Incsspd , X86M , O(F30F00,AE,5,_,0,_,_,_ ), 0 , 63 , 0 , 1241 , 76 , 56 ), // #275 - INST(Incsspq , X86M , O(F30F00,AE,5,_,1,_,_,_ ), 0 , 64 , 0 , 1249 , 77 , 56 ), // #276 - INST(Ins , X86Ins , O(000000,6C,_,_,_,_,_,_ ), 0 , 0 , 0 , 1916 , 78 , 0 ), // #277 - INST(Insertps , ExtRmi , O(660F3A,21,_,_,_,_,_,_ ), 0 , 8 , 0 , 6993 , 38 , 12 ), // #278 - INST(Insertq , ExtInsertq , O(F20F00,79,_,_,_,_,_,_ ), O(F20F00,78,_,_,_,_,_,_ ), 5 , 17 , 1257 , 79 , 49 ), // #279 - INST(Int , X86Int , O(000000,CD,_,_,_,_,_,_ ), 0 , 0 , 0 , 1022 , 80 , 0 ), // #280 - INST(Int3 , X86Op , O(000000,CC,_,_,_,_,_,_ ), 0 , 0 , 0 , 1265 , 30 , 0 ), // #281 - INST(Into , X86Op , O(000000,CE,_,_,_,_,_,_ ), 0 , 0 , 0 , 1270 , 81 , 57 ), // #282 - INST(Invd , X86Op , O(000F00,08,_,_,_,_,_,_ ), 0 , 4 , 0 , 11501, 30 , 43 ), // #283 - INST(Invept , X86Rm_NoSize , O(660F38,80,_,_,_,_,_,_ ), 0 , 2 , 0 , 1275 , 82 , 58 ), // #284 - INST(Invlpg , X86M_Only , O(000F00,01,7,_,_,_,_,_ ), 0 , 22 , 0 , 1282 , 69 , 43 ), // #285 - INST(Invlpga , X86Op_xAddr , O(000F01,DF,_,_,_,_,_,_ ), 0 , 21 , 0 , 1289 , 83 , 22 ), // #286 - INST(Invpcid , X86Rm_NoSize , O(660F38,82,_,_,_,_,_,_ ), 0 , 2 , 0 , 1297 , 82 , 43 ), // #287 - INST(Invvpid , X86Rm_NoSize , O(660F38,81,_,_,_,_,_,_ ), 0 , 2 , 0 , 1305 , 82 , 58 ), // #288 - INST(Iret , X86Op , O(660000,CF,_,_,_,_,_,_ ), 0 , 19 , 0 , 3226 , 84 , 1 ), // #289 - INST(Iretd , X86Op , O(000000,CF,_,_,_,_,_,_ ), 0 , 0 , 0 , 1313 , 84 , 1 ), // #290 - INST(Iretq , X86Op , O(000000,CF,_,_,1,_,_,_ ), 0 , 20 , 0 , 1319 , 85 , 1 ), // #291 - INST(Ja , X86Jcc , O(000F00,87,_,_,_,_,_,_ ), O(000000,77,_,_,_,_,_,_ ), 4 , 18 , 1325 , 86 , 59 ), // #292 - INST(Jae , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 1328 , 86 , 60 ), // #293 - INST(Jb , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 1332 , 86 , 60 ), // #294 - INST(Jbe , X86Jcc , O(000F00,86,_,_,_,_,_,_ ), O(000000,76,_,_,_,_,_,_ ), 4 , 21 , 1335 , 86 , 59 ), // #295 - INST(Jc , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 1339 , 86 , 60 ), // #296 - INST(Je , X86Jcc , O(000F00,84,_,_,_,_,_,_ ), O(000000,74,_,_,_,_,_,_ ), 4 , 22 , 1342 , 86 , 61 ), // #297 - INST(Jecxz , X86JecxzLoop , 0 , O(000000,E3,_,_,_,_,_,_ ), 0 , 23 , 1345 , 87 , 0 ), // #298 - INST(Jg , X86Jcc , O(000F00,8F,_,_,_,_,_,_ ), O(000000,7F,_,_,_,_,_,_ ), 4 , 24 , 1351 , 86 , 62 ), // #299 - INST(Jge , X86Jcc , O(000F00,8D,_,_,_,_,_,_ ), O(000000,7D,_,_,_,_,_,_ ), 4 , 25 , 1354 , 86 , 63 ), // #300 - INST(Jl , X86Jcc , O(000F00,8C,_,_,_,_,_,_ ), O(000000,7C,_,_,_,_,_,_ ), 4 , 26 , 1358 , 86 , 63 ), // #301 - INST(Jle , X86Jcc , O(000F00,8E,_,_,_,_,_,_ ), O(000000,7E,_,_,_,_,_,_ ), 4 , 27 , 1361 , 86 , 62 ), // #302 - INST(Jmp , X86Jmp , O(000000,FF,4,_,_,_,_,_ ), O(000000,EB,_,_,_,_,_,_ ), 9 , 28 , 1861 , 88 , 0 ), // #303 - INST(Jna , X86Jcc , O(000F00,86,_,_,_,_,_,_ ), O(000000,76,_,_,_,_,_,_ ), 4 , 21 , 1365 , 86 , 59 ), // #304 - INST(Jnae , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 1369 , 86 , 60 ), // #305 - INST(Jnb , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 1374 , 86 , 60 ), // #306 - INST(Jnbe , X86Jcc , O(000F00,87,_,_,_,_,_,_ ), O(000000,77,_,_,_,_,_,_ ), 4 , 18 , 1378 , 86 , 59 ), // #307 - INST(Jnc , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 1383 , 86 , 60 ), // #308 - INST(Jne , X86Jcc , O(000F00,85,_,_,_,_,_,_ ), O(000000,75,_,_,_,_,_,_ ), 4 , 29 , 1387 , 86 , 61 ), // #309 - INST(Jng , X86Jcc , O(000F00,8E,_,_,_,_,_,_ ), O(000000,7E,_,_,_,_,_,_ ), 4 , 27 , 1391 , 86 , 62 ), // #310 - INST(Jnge , X86Jcc , O(000F00,8C,_,_,_,_,_,_ ), O(000000,7C,_,_,_,_,_,_ ), 4 , 26 , 1395 , 86 , 63 ), // #311 - INST(Jnl , X86Jcc , O(000F00,8D,_,_,_,_,_,_ ), O(000000,7D,_,_,_,_,_,_ ), 4 , 25 , 1400 , 86 , 63 ), // #312 - INST(Jnle , X86Jcc , O(000F00,8F,_,_,_,_,_,_ ), O(000000,7F,_,_,_,_,_,_ ), 4 , 24 , 1404 , 86 , 62 ), // #313 - INST(Jno , X86Jcc , O(000F00,81,_,_,_,_,_,_ ), O(000000,71,_,_,_,_,_,_ ), 4 , 30 , 1409 , 86 , 57 ), // #314 - INST(Jnp , X86Jcc , O(000F00,8B,_,_,_,_,_,_ ), O(000000,7B,_,_,_,_,_,_ ), 4 , 31 , 1413 , 86 , 64 ), // #315 - INST(Jns , X86Jcc , O(000F00,89,_,_,_,_,_,_ ), O(000000,79,_,_,_,_,_,_ ), 4 , 32 , 1417 , 86 , 65 ), // #316 - INST(Jnz , X86Jcc , O(000F00,85,_,_,_,_,_,_ ), O(000000,75,_,_,_,_,_,_ ), 4 , 29 , 1421 , 86 , 61 ), // #317 - INST(Jo , X86Jcc , O(000F00,80,_,_,_,_,_,_ ), O(000000,70,_,_,_,_,_,_ ), 4 , 33 , 1425 , 86 , 57 ), // #318 - INST(Jp , X86Jcc , O(000F00,8A,_,_,_,_,_,_ ), O(000000,7A,_,_,_,_,_,_ ), 4 , 34 , 1428 , 86 , 64 ), // #319 - INST(Jpe , X86Jcc , O(000F00,8A,_,_,_,_,_,_ ), O(000000,7A,_,_,_,_,_,_ ), 4 , 34 , 1431 , 86 , 64 ), // #320 - INST(Jpo , X86Jcc , O(000F00,8B,_,_,_,_,_,_ ), O(000000,7B,_,_,_,_,_,_ ), 4 , 31 , 1435 , 86 , 64 ), // #321 - INST(Js , X86Jcc , O(000F00,88,_,_,_,_,_,_ ), O(000000,78,_,_,_,_,_,_ ), 4 , 35 , 1439 , 86 , 65 ), // #322 - INST(Jz , X86Jcc , O(000F00,84,_,_,_,_,_,_ ), O(000000,74,_,_,_,_,_,_ ), 4 , 22 , 1442 , 86 , 61 ), // #323 - INST(Kaddb , VexRvm , V(660F00,4A,_,1,0,_,_,_ ), 0 , 65 , 0 , 1445 , 89 , 66 ), // #324 - INST(Kaddd , VexRvm , V(660F00,4A,_,1,1,_,_,_ ), 0 , 66 , 0 , 1451 , 89 , 67 ), // #325 - INST(Kaddq , VexRvm , V(000F00,4A,_,1,1,_,_,_ ), 0 , 67 , 0 , 1457 , 89 , 67 ), // #326 - INST(Kaddw , VexRvm , V(000F00,4A,_,1,0,_,_,_ ), 0 , 68 , 0 , 1463 , 89 , 66 ), // #327 - INST(Kandb , VexRvm , V(660F00,41,_,1,0,_,_,_ ), 0 , 65 , 0 , 1469 , 89 , 66 ), // #328 - INST(Kandd , VexRvm , V(660F00,41,_,1,1,_,_,_ ), 0 , 66 , 0 , 1475 , 89 , 67 ), // #329 - INST(Kandnb , VexRvm , V(660F00,42,_,1,0,_,_,_ ), 0 , 65 , 0 , 1481 , 89 , 66 ), // #330 - INST(Kandnd , VexRvm , V(660F00,42,_,1,1,_,_,_ ), 0 , 66 , 0 , 1488 , 89 , 67 ), // #331 - INST(Kandnq , VexRvm , V(000F00,42,_,1,1,_,_,_ ), 0 , 67 , 0 , 1495 , 89 , 67 ), // #332 - INST(Kandnw , VexRvm , V(000F00,42,_,1,0,_,_,_ ), 0 , 68 , 0 , 1502 , 89 , 68 ), // #333 - INST(Kandq , VexRvm , V(000F00,41,_,1,1,_,_,_ ), 0 , 67 , 0 , 1509 , 89 , 67 ), // #334 - INST(Kandw , VexRvm , V(000F00,41,_,1,0,_,_,_ ), 0 , 68 , 0 , 1515 , 89 , 68 ), // #335 - INST(Kmovb , VexKmov , V(660F00,90,_,0,0,_,_,_ ), V(660F00,92,_,0,0,_,_,_ ), 69 , 36 , 1521 , 90 , 66 ), // #336 - INST(Kmovd , VexKmov , V(660F00,90,_,0,1,_,_,_ ), V(F20F00,92,_,0,0,_,_,_ ), 70 , 37 , 9105 , 91 , 67 ), // #337 - INST(Kmovq , VexKmov , V(000F00,90,_,0,1,_,_,_ ), V(F20F00,92,_,0,1,_,_,_ ), 71 , 38 , 9116 , 92 , 67 ), // #338 - INST(Kmovw , VexKmov , V(000F00,90,_,0,0,_,_,_ ), V(000F00,92,_,0,0,_,_,_ ), 72 , 39 , 1527 , 93 , 68 ), // #339 - INST(Knotb , VexRm , V(660F00,44,_,0,0,_,_,_ ), 0 , 69 , 0 , 1533 , 94 , 66 ), // #340 - INST(Knotd , VexRm , V(660F00,44,_,0,1,_,_,_ ), 0 , 70 , 0 , 1539 , 94 , 67 ), // #341 - INST(Knotq , VexRm , V(000F00,44,_,0,1,_,_,_ ), 0 , 71 , 0 , 1545 , 94 , 67 ), // #342 - INST(Knotw , VexRm , V(000F00,44,_,0,0,_,_,_ ), 0 , 72 , 0 , 1551 , 94 , 68 ), // #343 - INST(Korb , VexRvm , V(660F00,45,_,1,0,_,_,_ ), 0 , 65 , 0 , 1557 , 89 , 66 ), // #344 - INST(Kord , VexRvm , V(660F00,45,_,1,1,_,_,_ ), 0 , 66 , 0 , 1562 , 89 , 67 ), // #345 - INST(Korq , VexRvm , V(000F00,45,_,1,1,_,_,_ ), 0 , 67 , 0 , 1567 , 89 , 67 ), // #346 - INST(Kortestb , VexRm , V(660F00,98,_,0,0,_,_,_ ), 0 , 69 , 0 , 1572 , 94 , 69 ), // #347 - INST(Kortestd , VexRm , V(660F00,98,_,0,1,_,_,_ ), 0 , 70 , 0 , 1581 , 94 , 70 ), // #348 - INST(Kortestq , VexRm , V(000F00,98,_,0,1,_,_,_ ), 0 , 71 , 0 , 1590 , 94 , 70 ), // #349 - INST(Kortestw , VexRm , V(000F00,98,_,0,0,_,_,_ ), 0 , 72 , 0 , 1599 , 94 , 71 ), // #350 - INST(Korw , VexRvm , V(000F00,45,_,1,0,_,_,_ ), 0 , 68 , 0 , 1608 , 89 , 68 ), // #351 - INST(Kshiftlb , VexRmi , V(660F3A,32,_,0,0,_,_,_ ), 0 , 73 , 0 , 1613 , 95 , 66 ), // #352 - INST(Kshiftld , VexRmi , V(660F3A,33,_,0,0,_,_,_ ), 0 , 73 , 0 , 1622 , 95 , 67 ), // #353 - INST(Kshiftlq , VexRmi , V(660F3A,33,_,0,1,_,_,_ ), 0 , 74 , 0 , 1631 , 95 , 67 ), // #354 - INST(Kshiftlw , VexRmi , V(660F3A,32,_,0,1,_,_,_ ), 0 , 74 , 0 , 1640 , 95 , 68 ), // #355 - INST(Kshiftrb , VexRmi , V(660F3A,30,_,0,0,_,_,_ ), 0 , 73 , 0 , 1649 , 95 , 66 ), // #356 - INST(Kshiftrd , VexRmi , V(660F3A,31,_,0,0,_,_,_ ), 0 , 73 , 0 , 1658 , 95 , 67 ), // #357 - INST(Kshiftrq , VexRmi , V(660F3A,31,_,0,1,_,_,_ ), 0 , 74 , 0 , 1667 , 95 , 67 ), // #358 - INST(Kshiftrw , VexRmi , V(660F3A,30,_,0,1,_,_,_ ), 0 , 74 , 0 , 1676 , 95 , 68 ), // #359 - INST(Ktestb , VexRm , V(660F00,99,_,0,0,_,_,_ ), 0 , 69 , 0 , 1685 , 94 , 69 ), // #360 - INST(Ktestd , VexRm , V(660F00,99,_,0,1,_,_,_ ), 0 , 70 , 0 , 1692 , 94 , 70 ), // #361 - INST(Ktestq , VexRm , V(000F00,99,_,0,1,_,_,_ ), 0 , 71 , 0 , 1699 , 94 , 70 ), // #362 - INST(Ktestw , VexRm , V(000F00,99,_,0,0,_,_,_ ), 0 , 72 , 0 , 1706 , 94 , 69 ), // #363 - INST(Kunpckbw , VexRvm , V(660F00,4B,_,1,0,_,_,_ ), 0 , 65 , 0 , 1713 , 89 , 68 ), // #364 - INST(Kunpckdq , VexRvm , V(000F00,4B,_,1,1,_,_,_ ), 0 , 67 , 0 , 1722 , 89 , 67 ), // #365 - INST(Kunpckwd , VexRvm , V(000F00,4B,_,1,0,_,_,_ ), 0 , 68 , 0 , 1731 , 89 , 67 ), // #366 - INST(Kxnorb , VexRvm , V(660F00,46,_,1,0,_,_,_ ), 0 , 65 , 0 , 1740 , 96 , 66 ), // #367 - INST(Kxnord , VexRvm , V(660F00,46,_,1,1,_,_,_ ), 0 , 66 , 0 , 1747 , 96 , 67 ), // #368 - INST(Kxnorq , VexRvm , V(000F00,46,_,1,1,_,_,_ ), 0 , 67 , 0 , 1754 , 96 , 67 ), // #369 - INST(Kxnorw , VexRvm , V(000F00,46,_,1,0,_,_,_ ), 0 , 68 , 0 , 1761 , 96 , 68 ), // #370 - INST(Kxorb , VexRvm , V(660F00,47,_,1,0,_,_,_ ), 0 , 65 , 0 , 1768 , 96 , 66 ), // #371 - INST(Kxord , VexRvm , V(660F00,47,_,1,1,_,_,_ ), 0 , 66 , 0 , 1774 , 96 , 67 ), // #372 - INST(Kxorq , VexRvm , V(000F00,47,_,1,1,_,_,_ ), 0 , 67 , 0 , 1780 , 96 , 67 ), // #373 - INST(Kxorw , VexRvm , V(000F00,47,_,1,0,_,_,_ ), 0 , 68 , 0 , 1786 , 96 , 68 ), // #374 - INST(Lahf , X86Op , O(000000,9F,_,_,_,_,_,_ ), 0 , 0 , 0 , 1792 , 97 , 72 ), // #375 - INST(Lar , X86Rm , O(000F00,02,_,_,_,_,_,_ ), 0 , 4 , 0 , 1797 , 98 , 10 ), // #376 - INST(Lcall , X86LcallLjmp , O(000000,FF,3,_,_,_,_,_ ), O(000000,9A,_,_,_,_,_,_ ), 75 , 40 , 1801 , 99 , 1 ), // #377 - INST(Lddqu , ExtRm , O(F20F00,F0,_,_,_,_,_,_ ), 0 , 5 , 0 , 7003 , 100, 6 ), // #378 - INST(Ldmxcsr , X86M_Only , O(000F00,AE,2,_,_,_,_,_ ), 0 , 76 , 0 , 7010 , 101, 5 ), // #379 - INST(Lds , X86Rm , O(000000,C5,_,_,_,_,_,_ ), 0 , 0 , 0 , 1807 , 102, 0 ), // #380 - INST(Ldtilecfg , AmxCfg , V(000F38,49,_,0,0,_,_,_ ), 0 , 10 , 0 , 1811 , 103, 73 ), // #381 - INST(Lea , X86Lea , O(000000,8D,_,_,x,_,_,_ ), 0 , 0 , 0 , 1821 , 104, 0 ), // #382 - INST(Leave , X86Op , O(000000,C9,_,_,_,_,_,_ ), 0 , 0 , 0 , 1825 , 30 , 0 ), // #383 - INST(Les , X86Rm , O(000000,C4,_,_,_,_,_,_ ), 0 , 0 , 0 , 1831 , 102, 0 ), // #384 - INST(Lfence , X86Fence , O(000F00,AE,5,_,_,_,_,_ ), 0 , 77 , 0 , 1835 , 30 , 4 ), // #385 - INST(Lfs , X86Rm , O(000F00,B4,_,_,_,_,_,_ ), 0 , 4 , 0 , 1842 , 105, 0 ), // #386 - INST(Lgdt , X86M_Only , O(000F00,01,2,_,_,_,_,_ ), 0 , 76 , 0 , 1846 , 69 , 0 ), // #387 - INST(Lgs , X86Rm , O(000F00,B5,_,_,_,_,_,_ ), 0 , 4 , 0 , 1851 , 105, 0 ), // #388 - INST(Lidt , X86M_Only , O(000F00,01,3,_,_,_,_,_ ), 0 , 78 , 0 , 1855 , 69 , 0 ), // #389 - INST(Ljmp , X86LcallLjmp , O(000000,FF,5,_,_,_,_,_ ), O(000000,EA,_,_,_,_,_,_ ), 62 , 41 , 1860 , 106, 0 ), // #390 - INST(Lldt , X86M_NoSize , O(000F00,00,2,_,_,_,_,_ ), 0 , 76 , 0 , 1865 , 107, 0 ), // #391 - INST(Llwpcb , VexR_Wx , V(XOP_M9,12,0,0,x,_,_,_ ), 0 , 79 , 0 , 1870 , 108, 74 ), // #392 - INST(Lmsw , X86M_NoSize , O(000F00,01,6,_,_,_,_,_ ), 0 , 80 , 0 , 1877 , 107, 0 ), // #393 - INST(Lods , X86StrRm , O(000000,AC,_,_,_,_,_,_ ), 0 , 0 , 0 , 1882 , 109, 75 ), // #394 - INST(Loop , X86JecxzLoop , 0 , O(000000,E2,_,_,_,_,_,_ ), 0 , 42 , 1887 , 110, 0 ), // #395 - INST(Loope , X86JecxzLoop , 0 , O(000000,E1,_,_,_,_,_,_ ), 0 , 43 , 1892 , 110, 61 ), // #396 - INST(Loopne , X86JecxzLoop , 0 , O(000000,E0,_,_,_,_,_,_ ), 0 , 44 , 1898 , 110, 61 ), // #397 - INST(Lsl , X86Rm , O(000F00,03,_,_,_,_,_,_ ), 0 , 4 , 0 , 1905 , 111, 10 ), // #398 - INST(Lss , X86Rm , O(000F00,B2,_,_,_,_,_,_ ), 0 , 4 , 0 , 7556 , 105, 0 ), // #399 - INST(Ltr , X86M_NoSize , O(000F00,00,3,_,_,_,_,_ ), 0 , 78 , 0 , 1909 , 107, 0 ), // #400 - INST(Lwpins , VexVmi4_Wx , V(XOP_MA,12,0,0,x,_,_,_ ), 0 , 81 , 0 , 1913 , 112, 74 ), // #401 - INST(Lwpval , VexVmi4_Wx , V(XOP_MA,12,1,0,x,_,_,_ ), 0 , 82 , 0 , 1920 , 112, 74 ), // #402 - INST(Lzcnt , X86Rm_Raw66H , O(F30F00,BD,_,_,x,_,_,_ ), 0 , 6 , 0 , 1927 , 22 , 76 ), // #403 - INST(Maskmovdqu , ExtRm_ZDI , O(660F00,F7,_,_,_,_,_,_ ), 0 , 3 , 0 , 7019 , 113, 4 ), // #404 - INST(Maskmovq , ExtRm_ZDI , O(000F00,F7,_,_,_,_,_,_ ), 0 , 4 , 0 , 9113 , 114, 77 ), // #405 - INST(Maxpd , ExtRm , O(660F00,5F,_,_,_,_,_,_ ), 0 , 3 , 0 , 7053 , 5 , 4 ), // #406 - INST(Maxps , ExtRm , O(000F00,5F,_,_,_,_,_,_ ), 0 , 4 , 0 , 7067 , 5 , 5 ), // #407 - INST(Maxsd , ExtRm , O(F20F00,5F,_,_,_,_,_,_ ), 0 , 5 , 0 , 9132 , 6 , 4 ), // #408 - INST(Maxss , ExtRm , O(F30F00,5F,_,_,_,_,_,_ ), 0 , 6 , 0 , 7088 , 7 , 5 ), // #409 - INST(Mcommit , X86Op , O(F30F01,FA,_,_,_,_,_,_ ), 0 , 25 , 0 , 1933 , 30 , 78 ), // #410 - INST(Mfence , X86Fence , O(000F00,AE,6,_,_,_,_,_ ), 0 , 80 , 0 , 1941 , 30 , 4 ), // #411 - INST(Minpd , ExtRm , O(660F00,5D,_,_,_,_,_,_ ), 0 , 3 , 0 , 7117 , 5 , 4 ), // #412 - INST(Minps , ExtRm , O(000F00,5D,_,_,_,_,_,_ ), 0 , 4 , 0 , 7131 , 5 , 5 ), // #413 - INST(Minsd , ExtRm , O(F20F00,5D,_,_,_,_,_,_ ), 0 , 5 , 0 , 9196 , 6 , 4 ), // #414 - INST(Minss , ExtRm , O(F30F00,5D,_,_,_,_,_,_ ), 0 , 6 , 0 , 7152 , 7 , 5 ), // #415 - INST(Monitor , X86Op , O(000F01,C8,_,_,_,_,_,_ ), 0 , 21 , 0 , 3232 , 115, 79 ), // #416 - INST(Monitorx , X86Op , O(000F01,FA,_,_,_,_,_,_ ), 0 , 21 , 0 , 1948 , 115, 80 ), // #417 - INST(Mov , X86Mov , 0 , 0 , 0 , 0 , 138 , 116, 0 ), // #418 - INST(Movabs , X86Movabs , 0 , 0 , 0 , 0 , 1957 , 117, 0 ), // #419 - INST(Movapd , ExtMov , O(660F00,28,_,_,_,_,_,_ ), O(660F00,29,_,_,_,_,_,_ ), 3 , 45 , 7183 , 118, 4 ), // #420 - INST(Movaps , ExtMov , O(000F00,28,_,_,_,_,_,_ ), O(000F00,29,_,_,_,_,_,_ ), 4 , 46 , 7191 , 118, 5 ), // #421 - INST(Movbe , ExtMovbe , O(000F38,F0,_,_,x,_,_,_ ), O(000F38,F1,_,_,x,_,_,_ ), 83 , 47 , 656 , 119, 81 ), // #422 - INST(Movd , ExtMovd , O(000F00,6E,_,_,_,_,_,_ ), O(000F00,7E,_,_,_,_,_,_ ), 4 , 48 , 9106 , 120, 82 ), // #423 - INST(Movddup , ExtMov , O(F20F00,12,_,_,_,_,_,_ ), 0 , 5 , 0 , 7205 , 6 , 6 ), // #424 - INST(Movdir64b , X86EnqcmdMovdir64b , O(660F38,F8,_,_,_,_,_,_ ), 0 , 2 , 0 , 1964 , 121, 83 ), // #425 - INST(Movdiri , X86MovntiMovdiri , O(000F38,F9,_,_,_,_,_,_ ), 0 , 83 , 0 , 1974 , 122, 84 ), // #426 - INST(Movdq2q , ExtMov , O(F20F00,D6,_,_,_,_,_,_ ), 0 , 5 , 0 , 1982 , 123, 4 ), // #427 - INST(Movdqa , ExtMov , O(660F00,6F,_,_,_,_,_,_ ), O(660F00,7F,_,_,_,_,_,_ ), 3 , 49 , 7214 , 118, 4 ), // #428 - INST(Movdqu , ExtMov , O(F30F00,6F,_,_,_,_,_,_ ), O(F30F00,7F,_,_,_,_,_,_ ), 6 , 50 , 7023 , 118, 4 ), // #429 - INST(Movhlps , ExtMov , O(000F00,12,_,_,_,_,_,_ ), 0 , 4 , 0 , 7289 , 124, 5 ), // #430 - INST(Movhpd , ExtMov , O(660F00,16,_,_,_,_,_,_ ), O(660F00,17,_,_,_,_,_,_ ), 3 , 51 , 7298 , 125, 4 ), // #431 - INST(Movhps , ExtMov , O(000F00,16,_,_,_,_,_,_ ), O(000F00,17,_,_,_,_,_,_ ), 4 , 52 , 7306 , 125, 5 ), // #432 - INST(Movlhps , ExtMov , O(000F00,16,_,_,_,_,_,_ ), 0 , 4 , 0 , 7314 , 124, 5 ), // #433 - INST(Movlpd , ExtMov , O(660F00,12,_,_,_,_,_,_ ), O(660F00,13,_,_,_,_,_,_ ), 3 , 53 , 7323 , 125, 4 ), // #434 - INST(Movlps , ExtMov , O(000F00,12,_,_,_,_,_,_ ), O(000F00,13,_,_,_,_,_,_ ), 4 , 54 , 7331 , 125, 5 ), // #435 - INST(Movmskpd , ExtMov , O(660F00,50,_,_,_,_,_,_ ), 0 , 3 , 0 , 7339 , 126, 4 ), // #436 - INST(Movmskps , ExtMov , O(000F00,50,_,_,_,_,_,_ ), 0 , 4 , 0 , 7349 , 126, 5 ), // #437 - INST(Movntdq , ExtMov , 0 , O(660F00,E7,_,_,_,_,_,_ ), 0 , 55 , 7359 , 127, 4 ), // #438 - INST(Movntdqa , ExtMov , O(660F38,2A,_,_,_,_,_,_ ), 0 , 2 , 0 , 7368 , 100, 12 ), // #439 - INST(Movnti , X86MovntiMovdiri , O(000F00,C3,_,_,x,_,_,_ ), 0 , 4 , 0 , 1990 , 122, 4 ), // #440 - INST(Movntpd , ExtMov , 0 , O(660F00,2B,_,_,_,_,_,_ ), 0 , 56 , 7378 , 127, 4 ), // #441 - INST(Movntps , ExtMov , 0 , O(000F00,2B,_,_,_,_,_,_ ), 0 , 57 , 7387 , 127, 5 ), // #442 - INST(Movntq , ExtMov , 0 , O(000F00,E7,_,_,_,_,_,_ ), 0 , 58 , 1997 , 128, 77 ), // #443 - INST(Movntsd , ExtMov , 0 , O(F20F00,2B,_,_,_,_,_,_ ), 0 , 59 , 2004 , 129, 49 ), // #444 - INST(Movntss , ExtMov , 0 , O(F30F00,2B,_,_,_,_,_,_ ), 0 , 60 , 2012 , 130, 49 ), // #445 - INST(Movq , ExtMovq , O(000F00,6E,_,_,x,_,_,_ ), O(000F00,7E,_,_,x,_,_,_ ), 4 , 48 , 9117 , 131, 82 ), // #446 - INST(Movq2dq , ExtRm , O(F30F00,D6,_,_,_,_,_,_ ), 0 , 6 , 0 , 2020 , 132, 4 ), // #447 - INST(Movs , X86StrMm , O(000000,A4,_,_,_,_,_,_ ), 0 , 0 , 0 , 439 , 133, 75 ), // #448 - INST(Movsd , ExtMov , O(F20F00,10,_,_,_,_,_,_ ), O(F20F00,11,_,_,_,_,_,_ ), 5 , 61 , 7402 , 134, 4 ), // #449 - INST(Movshdup , ExtRm , O(F30F00,16,_,_,_,_,_,_ ), 0 , 6 , 0 , 7416 , 5 , 6 ), // #450 - INST(Movsldup , ExtRm , O(F30F00,12,_,_,_,_,_,_ ), 0 , 6 , 0 , 7426 , 5 , 6 ), // #451 - INST(Movss , ExtMov , O(F30F00,10,_,_,_,_,_,_ ), O(F30F00,11,_,_,_,_,_,_ ), 6 , 62 , 7436 , 135, 5 ), // #452 - INST(Movsx , X86MovsxMovzx , O(000F00,BE,_,_,x,_,_,_ ), 0 , 4 , 0 , 2028 , 136, 0 ), // #453 - INST(Movsxd , X86Rm , O(000000,63,_,_,x,_,_,_ ), 0 , 0 , 0 , 2034 , 137, 0 ), // #454 - INST(Movupd , ExtMov , O(660F00,10,_,_,_,_,_,_ ), O(660F00,11,_,_,_,_,_,_ ), 3 , 63 , 7443 , 118, 4 ), // #455 - INST(Movups , ExtMov , O(000F00,10,_,_,_,_,_,_ ), O(000F00,11,_,_,_,_,_,_ ), 4 , 64 , 7451 , 118, 5 ), // #456 - INST(Movzx , X86MovsxMovzx , O(000F00,B6,_,_,x,_,_,_ ), 0 , 4 , 0 , 2041 , 136, 0 ), // #457 - INST(Mpsadbw , ExtRmi , O(660F3A,42,_,_,_,_,_,_ ), 0 , 8 , 0 , 7465 , 8 , 12 ), // #458 - INST(Mul , X86M_GPB_MulDiv , O(000000,F6,4,_,x,_,_,_ ), 0 , 9 , 0 , 828 , 54 , 1 ), // #459 - INST(Mulpd , ExtRm , O(660F00,59,_,_,_,_,_,_ ), 0 , 3 , 0 , 7519 , 5 , 4 ), // #460 - INST(Mulps , ExtRm , O(000F00,59,_,_,_,_,_,_ ), 0 , 4 , 0 , 7533 , 5 , 5 ), // #461 - INST(Mulsd , ExtRm , O(F20F00,59,_,_,_,_,_,_ ), 0 , 5 , 0 , 7540 , 6 , 4 ), // #462 - INST(Mulss , ExtRm , O(F30F00,59,_,_,_,_,_,_ ), 0 , 6 , 0 , 7554 , 7 , 5 ), // #463 - INST(Mulx , VexRvm_ZDX_Wx , V(F20F38,F6,_,0,x,_,_,_ ), 0 , 84 , 0 , 2047 , 138, 85 ), // #464 - INST(Mwait , X86Op , O(000F01,C9,_,_,_,_,_,_ ), 0 , 21 , 0 , 3241 , 139, 79 ), // #465 - INST(Mwaitx , X86Op , O(000F01,FB,_,_,_,_,_,_ ), 0 , 21 , 0 , 2052 , 140, 80 ), // #466 - INST(Neg , X86M_GPB , O(000000,F6,3,_,x,_,_,_ ), 0 , 75 , 0 , 2059 , 141, 1 ), // #467 - INST(Nop , X86M_Nop , O(000000,90,_,_,_,_,_,_ ), 0 , 0 , 0 , 959 , 142, 0 ), // #468 - INST(Not , X86M_GPB , O(000000,F6,2,_,x,_,_,_ ), 0 , 1 , 0 , 2063 , 141, 0 ), // #469 - INST(Or , X86Arith , O(000000,08,1,_,x,_,_,_ ), 0 , 31 , 0 , 3237 , 143, 1 ), // #470 - INST(Orpd , ExtRm , O(660F00,56,_,_,_,_,_,_ ), 0 , 3 , 0 , 11458, 11 , 4 ), // #471 - INST(Orps , ExtRm , O(000F00,56,_,_,_,_,_,_ ), 0 , 4 , 0 , 11465, 11 , 5 ), // #472 - INST(Out , X86Out , O(000000,EE,_,_,_,_,_,_ ), O(000000,E6,_,_,_,_,_,_ ), 0 , 65 , 2067 , 144, 0 ), // #473 - INST(Outs , X86Outs , O(000000,6E,_,_,_,_,_,_ ), 0 , 0 , 0 , 2071 , 145, 0 ), // #474 - INST(Pabsb , ExtRm_P , O(000F38,1C,_,_,_,_,_,_ ), 0 , 83 , 0 , 7636 , 146, 86 ), // #475 - INST(Pabsd , ExtRm_P , O(000F38,1E,_,_,_,_,_,_ ), 0 , 83 , 0 , 7643 , 146, 86 ), // #476 - INST(Pabsw , ExtRm_P , O(000F38,1D,_,_,_,_,_,_ ), 0 , 83 , 0 , 7657 , 146, 86 ), // #477 - INST(Packssdw , ExtRm_P , O(000F00,6B,_,_,_,_,_,_ ), 0 , 4 , 0 , 7664 , 146, 82 ), // #478 - INST(Packsswb , ExtRm_P , O(000F00,63,_,_,_,_,_,_ ), 0 , 4 , 0 , 7674 , 146, 82 ), // #479 - INST(Packusdw , ExtRm , O(660F38,2B,_,_,_,_,_,_ ), 0 , 2 , 0 , 7684 , 5 , 12 ), // #480 - INST(Packuswb , ExtRm_P , O(000F00,67,_,_,_,_,_,_ ), 0 , 4 , 0 , 7694 , 146, 82 ), // #481 - INST(Paddb , ExtRm_P , O(000F00,FC,_,_,_,_,_,_ ), 0 , 4 , 0 , 7704 , 146, 82 ), // #482 - INST(Paddd , ExtRm_P , O(000F00,FE,_,_,_,_,_,_ ), 0 , 4 , 0 , 7711 , 146, 82 ), // #483 - INST(Paddq , ExtRm_P , O(000F00,D4,_,_,_,_,_,_ ), 0 , 4 , 0 , 7718 , 146, 4 ), // #484 - INST(Paddsb , ExtRm_P , O(000F00,EC,_,_,_,_,_,_ ), 0 , 4 , 0 , 7725 , 146, 82 ), // #485 - INST(Paddsw , ExtRm_P , O(000F00,ED,_,_,_,_,_,_ ), 0 , 4 , 0 , 7733 , 146, 82 ), // #486 - INST(Paddusb , ExtRm_P , O(000F00,DC,_,_,_,_,_,_ ), 0 , 4 , 0 , 7741 , 146, 82 ), // #487 - INST(Paddusw , ExtRm_P , O(000F00,DD,_,_,_,_,_,_ ), 0 , 4 , 0 , 7750 , 146, 82 ), // #488 - INST(Paddw , ExtRm_P , O(000F00,FD,_,_,_,_,_,_ ), 0 , 4 , 0 , 7759 , 146, 82 ), // #489 - INST(Palignr , ExtRmi_P , O(000F3A,0F,_,_,_,_,_,_ ), 0 , 85 , 0 , 7766 , 147, 6 ), // #490 - INST(Pand , ExtRm_P , O(000F00,DB,_,_,_,_,_,_ ), 0 , 4 , 0 , 7775 , 148, 82 ), // #491 - INST(Pandn , ExtRm_P , O(000F00,DF,_,_,_,_,_,_ ), 0 , 4 , 0 , 7788 , 149, 82 ), // #492 - INST(Pause , X86Op , O(F30000,90,_,_,_,_,_,_ ), 0 , 86 , 0 , 3195 , 30 , 0 ), // #493 - INST(Pavgb , ExtRm_P , O(000F00,E0,_,_,_,_,_,_ ), 0 , 4 , 0 , 7818 , 146, 87 ), // #494 - INST(Pavgusb , Ext3dNow , O(000F0F,BF,_,_,_,_,_,_ ), 0 , 87 , 0 , 2076 , 150, 51 ), // #495 - INST(Pavgw , ExtRm_P , O(000F00,E3,_,_,_,_,_,_ ), 0 , 4 , 0 , 7825 , 146, 87 ), // #496 - INST(Pblendvb , ExtRm_XMM0 , O(660F38,10,_,_,_,_,_,_ ), 0 , 2 , 0 , 7881 , 15 , 12 ), // #497 - INST(Pblendw , ExtRmi , O(660F3A,0E,_,_,_,_,_,_ ), 0 , 8 , 0 , 7891 , 8 , 12 ), // #498 - INST(Pclmulqdq , ExtRmi , O(660F3A,44,_,_,_,_,_,_ ), 0 , 8 , 0 , 7984 , 8 , 88 ), // #499 - INST(Pcmpeqb , ExtRm_P , O(000F00,74,_,_,_,_,_,_ ), 0 , 4 , 0 , 8016 , 149, 82 ), // #500 - INST(Pcmpeqd , ExtRm_P , O(000F00,76,_,_,_,_,_,_ ), 0 , 4 , 0 , 8025 , 149, 82 ), // #501 - INST(Pcmpeqq , ExtRm , O(660F38,29,_,_,_,_,_,_ ), 0 , 2 , 0 , 8034 , 151, 12 ), // #502 - INST(Pcmpeqw , ExtRm_P , O(000F00,75,_,_,_,_,_,_ ), 0 , 4 , 0 , 8043 , 149, 82 ), // #503 - INST(Pcmpestri , ExtRmi , O(660F3A,61,_,_,_,_,_,_ ), 0 , 8 , 0 , 8052 , 152, 89 ), // #504 - INST(Pcmpestrm , ExtRmi , O(660F3A,60,_,_,_,_,_,_ ), 0 , 8 , 0 , 8063 , 153, 89 ), // #505 - INST(Pcmpgtb , ExtRm_P , O(000F00,64,_,_,_,_,_,_ ), 0 , 4 , 0 , 8074 , 149, 82 ), // #506 - INST(Pcmpgtd , ExtRm_P , O(000F00,66,_,_,_,_,_,_ ), 0 , 4 , 0 , 8083 , 149, 82 ), // #507 - INST(Pcmpgtq , ExtRm , O(660F38,37,_,_,_,_,_,_ ), 0 , 2 , 0 , 8092 , 151, 44 ), // #508 - INST(Pcmpgtw , ExtRm_P , O(000F00,65,_,_,_,_,_,_ ), 0 , 4 , 0 , 8101 , 149, 82 ), // #509 - INST(Pcmpistri , ExtRmi , O(660F3A,63,_,_,_,_,_,_ ), 0 , 8 , 0 , 8110 , 154, 89 ), // #510 - INST(Pcmpistrm , ExtRmi , O(660F3A,62,_,_,_,_,_,_ ), 0 , 8 , 0 , 8121 , 155, 89 ), // #511 - INST(Pconfig , X86Op , O(000F01,C5,_,_,_,_,_,_ ), 0 , 21 , 0 , 2084 , 30 , 90 ), // #512 - INST(Pdep , VexRvm_Wx , V(F20F38,F5,_,0,x,_,_,_ ), 0 , 84 , 0 , 2092 , 10 , 85 ), // #513 - INST(Pext , VexRvm_Wx , V(F30F38,F5,_,0,x,_,_,_ ), 0 , 88 , 0 , 2097 , 10 , 85 ), // #514 - INST(Pextrb , ExtExtract , O(000F3A,14,_,_,_,_,_,_ ), 0 , 85 , 0 , 8608 , 156, 12 ), // #515 - INST(Pextrd , ExtExtract , O(000F3A,16,_,_,_,_,_,_ ), 0 , 85 , 0 , 8616 , 58 , 12 ), // #516 - INST(Pextrq , ExtExtract , O(000F3A,16,_,_,1,_,_,_ ), 0 , 89 , 0 , 8624 , 157, 12 ), // #517 - INST(Pextrw , ExtPextrw , O(000F00,C5,_,_,_,_,_,_ ), O(000F3A,15,_,_,_,_,_,_ ), 4 , 66 , 8632 , 158, 91 ), // #518 - INST(Pf2id , Ext3dNow , O(000F0F,1D,_,_,_,_,_,_ ), 0 , 87 , 0 , 2102 , 150, 51 ), // #519 - INST(Pf2iw , Ext3dNow , O(000F0F,1C,_,_,_,_,_,_ ), 0 , 87 , 0 , 2108 , 150, 92 ), // #520 - INST(Pfacc , Ext3dNow , O(000F0F,AE,_,_,_,_,_,_ ), 0 , 87 , 0 , 2114 , 150, 51 ), // #521 - INST(Pfadd , Ext3dNow , O(000F0F,9E,_,_,_,_,_,_ ), 0 , 87 , 0 , 2120 , 150, 51 ), // #522 - INST(Pfcmpeq , Ext3dNow , O(000F0F,B0,_,_,_,_,_,_ ), 0 , 87 , 0 , 2126 , 150, 51 ), // #523 - INST(Pfcmpge , Ext3dNow , O(000F0F,90,_,_,_,_,_,_ ), 0 , 87 , 0 , 2134 , 150, 51 ), // #524 - INST(Pfcmpgt , Ext3dNow , O(000F0F,A0,_,_,_,_,_,_ ), 0 , 87 , 0 , 2142 , 150, 51 ), // #525 - INST(Pfmax , Ext3dNow , O(000F0F,A4,_,_,_,_,_,_ ), 0 , 87 , 0 , 2150 , 150, 51 ), // #526 - INST(Pfmin , Ext3dNow , O(000F0F,94,_,_,_,_,_,_ ), 0 , 87 , 0 , 2156 , 150, 51 ), // #527 - INST(Pfmul , Ext3dNow , O(000F0F,B4,_,_,_,_,_,_ ), 0 , 87 , 0 , 2162 , 150, 51 ), // #528 - INST(Pfnacc , Ext3dNow , O(000F0F,8A,_,_,_,_,_,_ ), 0 , 87 , 0 , 2168 , 150, 92 ), // #529 - INST(Pfpnacc , Ext3dNow , O(000F0F,8E,_,_,_,_,_,_ ), 0 , 87 , 0 , 2175 , 150, 92 ), // #530 - INST(Pfrcp , Ext3dNow , O(000F0F,96,_,_,_,_,_,_ ), 0 , 87 , 0 , 2183 , 150, 51 ), // #531 - INST(Pfrcpit1 , Ext3dNow , O(000F0F,A6,_,_,_,_,_,_ ), 0 , 87 , 0 , 2189 , 150, 51 ), // #532 - INST(Pfrcpit2 , Ext3dNow , O(000F0F,B6,_,_,_,_,_,_ ), 0 , 87 , 0 , 2198 , 150, 51 ), // #533 - INST(Pfrcpv , Ext3dNow , O(000F0F,86,_,_,_,_,_,_ ), 0 , 87 , 0 , 2207 , 150, 93 ), // #534 - INST(Pfrsqit1 , Ext3dNow , O(000F0F,A7,_,_,_,_,_,_ ), 0 , 87 , 0 , 2214 , 150, 51 ), // #535 - INST(Pfrsqrt , Ext3dNow , O(000F0F,97,_,_,_,_,_,_ ), 0 , 87 , 0 , 2223 , 150, 51 ), // #536 - INST(Pfrsqrtv , Ext3dNow , O(000F0F,87,_,_,_,_,_,_ ), 0 , 87 , 0 , 2231 , 150, 93 ), // #537 - INST(Pfsub , Ext3dNow , O(000F0F,9A,_,_,_,_,_,_ ), 0 , 87 , 0 , 2240 , 150, 51 ), // #538 - INST(Pfsubr , Ext3dNow , O(000F0F,AA,_,_,_,_,_,_ ), 0 , 87 , 0 , 2246 , 150, 51 ), // #539 - INST(Phaddd , ExtRm_P , O(000F38,02,_,_,_,_,_,_ ), 0 , 83 , 0 , 8711 , 146, 86 ), // #540 - INST(Phaddsw , ExtRm_P , O(000F38,03,_,_,_,_,_,_ ), 0 , 83 , 0 , 8728 , 146, 86 ), // #541 - INST(Phaddw , ExtRm_P , O(000F38,01,_,_,_,_,_,_ ), 0 , 83 , 0 , 8797 , 146, 86 ), // #542 - INST(Phminposuw , ExtRm , O(660F38,41,_,_,_,_,_,_ ), 0 , 2 , 0 , 8823 , 5 , 12 ), // #543 - INST(Phsubd , ExtRm_P , O(000F38,06,_,_,_,_,_,_ ), 0 , 83 , 0 , 8844 , 146, 86 ), // #544 - INST(Phsubsw , ExtRm_P , O(000F38,07,_,_,_,_,_,_ ), 0 , 83 , 0 , 8861 , 146, 86 ), // #545 - INST(Phsubw , ExtRm_P , O(000F38,05,_,_,_,_,_,_ ), 0 , 83 , 0 , 8870 , 146, 86 ), // #546 - INST(Pi2fd , Ext3dNow , O(000F0F,0D,_,_,_,_,_,_ ), 0 , 87 , 0 , 2253 , 150, 51 ), // #547 - INST(Pi2fw , Ext3dNow , O(000F0F,0C,_,_,_,_,_,_ ), 0 , 87 , 0 , 2259 , 150, 92 ), // #548 - INST(Pinsrb , ExtRmi , O(660F3A,20,_,_,_,_,_,_ ), 0 , 8 , 0 , 8887 , 159, 12 ), // #549 - INST(Pinsrd , ExtRmi , O(660F3A,22,_,_,_,_,_,_ ), 0 , 8 , 0 , 8895 , 160, 12 ), // #550 - INST(Pinsrq , ExtRmi , O(660F3A,22,_,_,1,_,_,_ ), 0 , 90 , 0 , 8903 , 161, 12 ), // #551 - INST(Pinsrw , ExtRmi_P , O(000F00,C4,_,_,_,_,_,_ ), 0 , 4 , 0 , 8911 , 162, 87 ), // #552 - INST(Pmaddubsw , ExtRm_P , O(000F38,04,_,_,_,_,_,_ ), 0 , 83 , 0 , 9081 , 146, 86 ), // #553 - INST(Pmaddwd , ExtRm_P , O(000F00,F5,_,_,_,_,_,_ ), 0 , 4 , 0 , 9092 , 146, 82 ), // #554 - INST(Pmaxsb , ExtRm , O(660F38,3C,_,_,_,_,_,_ ), 0 , 2 , 0 , 9123 , 11 , 12 ), // #555 - INST(Pmaxsd , ExtRm , O(660F38,3D,_,_,_,_,_,_ ), 0 , 2 , 0 , 9131 , 11 , 12 ), // #556 - INST(Pmaxsw , ExtRm_P , O(000F00,EE,_,_,_,_,_,_ ), 0 , 4 , 0 , 9147 , 148, 87 ), // #557 - INST(Pmaxub , ExtRm_P , O(000F00,DE,_,_,_,_,_,_ ), 0 , 4 , 0 , 9155 , 148, 87 ), // #558 - INST(Pmaxud , ExtRm , O(660F38,3F,_,_,_,_,_,_ ), 0 , 2 , 0 , 9163 , 11 , 12 ), // #559 - INST(Pmaxuw , ExtRm , O(660F38,3E,_,_,_,_,_,_ ), 0 , 2 , 0 , 9179 , 11 , 12 ), // #560 - INST(Pminsb , ExtRm , O(660F38,38,_,_,_,_,_,_ ), 0 , 2 , 0 , 9187 , 11 , 12 ), // #561 - INST(Pminsd , ExtRm , O(660F38,39,_,_,_,_,_,_ ), 0 , 2 , 0 , 9195 , 11 , 12 ), // #562 - INST(Pminsw , ExtRm_P , O(000F00,EA,_,_,_,_,_,_ ), 0 , 4 , 0 , 9211 , 148, 87 ), // #563 - INST(Pminub , ExtRm_P , O(000F00,DA,_,_,_,_,_,_ ), 0 , 4 , 0 , 9219 , 148, 87 ), // #564 - INST(Pminud , ExtRm , O(660F38,3B,_,_,_,_,_,_ ), 0 , 2 , 0 , 9227 , 11 , 12 ), // #565 - INST(Pminuw , ExtRm , O(660F38,3A,_,_,_,_,_,_ ), 0 , 2 , 0 , 9243 , 11 , 12 ), // #566 - INST(Pmovmskb , ExtRm_P , O(000F00,D7,_,_,_,_,_,_ ), 0 , 4 , 0 , 9321 , 163, 87 ), // #567 - INST(Pmovsxbd , ExtRm , O(660F38,21,_,_,_,_,_,_ ), 0 , 2 , 0 , 9418 , 7 , 12 ), // #568 - INST(Pmovsxbq , ExtRm , O(660F38,22,_,_,_,_,_,_ ), 0 , 2 , 0 , 9428 , 164, 12 ), // #569 - INST(Pmovsxbw , ExtRm , O(660F38,20,_,_,_,_,_,_ ), 0 , 2 , 0 , 9438 , 6 , 12 ), // #570 - INST(Pmovsxdq , ExtRm , O(660F38,25,_,_,_,_,_,_ ), 0 , 2 , 0 , 9448 , 6 , 12 ), // #571 - INST(Pmovsxwd , ExtRm , O(660F38,23,_,_,_,_,_,_ ), 0 , 2 , 0 , 9458 , 6 , 12 ), // #572 - INST(Pmovsxwq , ExtRm , O(660F38,24,_,_,_,_,_,_ ), 0 , 2 , 0 , 9468 , 7 , 12 ), // #573 - INST(Pmovzxbd , ExtRm , O(660F38,31,_,_,_,_,_,_ ), 0 , 2 , 0 , 9555 , 7 , 12 ), // #574 - INST(Pmovzxbq , ExtRm , O(660F38,32,_,_,_,_,_,_ ), 0 , 2 , 0 , 9565 , 164, 12 ), // #575 - INST(Pmovzxbw , ExtRm , O(660F38,30,_,_,_,_,_,_ ), 0 , 2 , 0 , 9575 , 6 , 12 ), // #576 - INST(Pmovzxdq , ExtRm , O(660F38,35,_,_,_,_,_,_ ), 0 , 2 , 0 , 9585 , 6 , 12 ), // #577 - INST(Pmovzxwd , ExtRm , O(660F38,33,_,_,_,_,_,_ ), 0 , 2 , 0 , 9595 , 6 , 12 ), // #578 - INST(Pmovzxwq , ExtRm , O(660F38,34,_,_,_,_,_,_ ), 0 , 2 , 0 , 9605 , 7 , 12 ), // #579 - INST(Pmuldq , ExtRm , O(660F38,28,_,_,_,_,_,_ ), 0 , 2 , 0 , 9615 , 5 , 12 ), // #580 - INST(Pmulhrsw , ExtRm_P , O(000F38,0B,_,_,_,_,_,_ ), 0 , 83 , 0 , 9623 , 146, 86 ), // #581 - INST(Pmulhrw , Ext3dNow , O(000F0F,B7,_,_,_,_,_,_ ), 0 , 87 , 0 , 2265 , 150, 51 ), // #582 - INST(Pmulhuw , ExtRm_P , O(000F00,E4,_,_,_,_,_,_ ), 0 , 4 , 0 , 9633 , 146, 87 ), // #583 - INST(Pmulhw , ExtRm_P , O(000F00,E5,_,_,_,_,_,_ ), 0 , 4 , 0 , 9642 , 146, 82 ), // #584 - INST(Pmulld , ExtRm , O(660F38,40,_,_,_,_,_,_ ), 0 , 2 , 0 , 9650 , 5 , 12 ), // #585 - INST(Pmullw , ExtRm_P , O(000F00,D5,_,_,_,_,_,_ ), 0 , 4 , 0 , 9666 , 146, 82 ), // #586 - INST(Pmuludq , ExtRm_P , O(000F00,F4,_,_,_,_,_,_ ), 0 , 4 , 0 , 9689 , 146, 4 ), // #587 - INST(Pop , X86Pop , O(000000,8F,0,_,_,_,_,_ ), O(000000,58,_,_,_,_,_,_ ), 0 , 67 , 2273 , 165, 0 ), // #588 - INST(Popa , X86Op , O(660000,61,_,_,_,_,_,_ ), 0 , 19 , 0 , 2277 , 81 , 0 ), // #589 - INST(Popad , X86Op , O(000000,61,_,_,_,_,_,_ ), 0 , 0 , 0 , 2282 , 81 , 0 ), // #590 - INST(Popcnt , X86Rm_Raw66H , O(F30F00,B8,_,_,x,_,_,_ ), 0 , 6 , 0 , 2288 , 22 , 94 ), // #591 - INST(Popf , X86Op , O(660000,9D,_,_,_,_,_,_ ), 0 , 19 , 0 , 2295 , 30 , 95 ), // #592 - INST(Popfd , X86Op , O(000000,9D,_,_,_,_,_,_ ), 0 , 0 , 0 , 2300 , 81 , 95 ), // #593 - INST(Popfq , X86Op , O(000000,9D,_,_,_,_,_,_ ), 0 , 0 , 0 , 2306 , 33 , 95 ), // #594 - INST(Por , ExtRm_P , O(000F00,EB,_,_,_,_,_,_ ), 0 , 4 , 0 , 9734 , 148, 82 ), // #595 - INST(Prefetch , X86M_Only , O(000F00,0D,0,_,_,_,_,_ ), 0 , 4 , 0 , 2312 , 31 , 51 ), // #596 - INST(Prefetchnta , X86M_Only , O(000F00,18,0,_,_,_,_,_ ), 0 , 4 , 0 , 2321 , 31 , 77 ), // #597 - INST(Prefetcht0 , X86M_Only , O(000F00,18,1,_,_,_,_,_ ), 0 , 29 , 0 , 2333 , 31 , 77 ), // #598 - INST(Prefetcht1 , X86M_Only , O(000F00,18,2,_,_,_,_,_ ), 0 , 76 , 0 , 2344 , 31 , 77 ), // #599 - INST(Prefetcht2 , X86M_Only , O(000F00,18,3,_,_,_,_,_ ), 0 , 78 , 0 , 2355 , 31 , 77 ), // #600 - INST(Prefetchw , X86M_Only , O(000F00,0D,1,_,_,_,_,_ ), 0 , 29 , 0 , 2366 , 31 , 96 ), // #601 - INST(Prefetchwt1 , X86M_Only , O(000F00,0D,2,_,_,_,_,_ ), 0 , 76 , 0 , 2376 , 31 , 97 ), // #602 - INST(Psadbw , ExtRm_P , O(000F00,F6,_,_,_,_,_,_ ), 0 , 4 , 0 , 4644 , 146, 87 ), // #603 - INST(Pshufb , ExtRm_P , O(000F38,00,_,_,_,_,_,_ ), 0 , 83 , 0 , 10060, 146, 86 ), // #604 - INST(Pshufd , ExtRmi , O(660F00,70,_,_,_,_,_,_ ), 0 , 3 , 0 , 10081, 8 , 4 ), // #605 - INST(Pshufhw , ExtRmi , O(F30F00,70,_,_,_,_,_,_ ), 0 , 6 , 0 , 10089, 8 , 4 ), // #606 - INST(Pshuflw , ExtRmi , O(F20F00,70,_,_,_,_,_,_ ), 0 , 5 , 0 , 10098, 8 , 4 ), // #607 - INST(Pshufw , ExtRmi_P , O(000F00,70,_,_,_,_,_,_ ), 0 , 4 , 0 , 2388 , 166, 77 ), // #608 - INST(Psignb , ExtRm_P , O(000F38,08,_,_,_,_,_,_ ), 0 , 83 , 0 , 10107, 146, 86 ), // #609 - INST(Psignd , ExtRm_P , O(000F38,0A,_,_,_,_,_,_ ), 0 , 83 , 0 , 10115, 146, 86 ), // #610 - INST(Psignw , ExtRm_P , O(000F38,09,_,_,_,_,_,_ ), 0 , 83 , 0 , 10123, 146, 86 ), // #611 - INST(Pslld , ExtRmRi_P , O(000F00,F2,_,_,_,_,_,_ ), O(000F00,72,6,_,_,_,_,_ ), 4 , 68 , 10131, 167, 82 ), // #612 - INST(Pslldq , ExtRmRi , 0 , O(660F00,73,7,_,_,_,_,_ ), 0 , 69 , 10138, 168, 4 ), // #613 - INST(Psllq , ExtRmRi_P , O(000F00,F3,_,_,_,_,_,_ ), O(000F00,73,6,_,_,_,_,_ ), 4 , 70 , 10146, 167, 82 ), // #614 - INST(Psllw , ExtRmRi_P , O(000F00,F1,_,_,_,_,_,_ ), O(000F00,71,6,_,_,_,_,_ ), 4 , 71 , 10177, 167, 82 ), // #615 - INST(Psmash , X86Op , O(F30F01,FF,_,_,_,_,_,_ ), 0 , 25 , 0 , 2395 , 33 , 98 ), // #616 - INST(Psrad , ExtRmRi_P , O(000F00,E2,_,_,_,_,_,_ ), O(000F00,72,4,_,_,_,_,_ ), 4 , 72 , 10184, 167, 82 ), // #617 - INST(Psraw , ExtRmRi_P , O(000F00,E1,_,_,_,_,_,_ ), O(000F00,71,4,_,_,_,_,_ ), 4 , 73 , 10222, 167, 82 ), // #618 - INST(Psrld , ExtRmRi_P , O(000F00,D2,_,_,_,_,_,_ ), O(000F00,72,2,_,_,_,_,_ ), 4 , 74 , 10229, 167, 82 ), // #619 - INST(Psrldq , ExtRmRi , 0 , O(660F00,73,3,_,_,_,_,_ ), 0 , 75 , 10236, 168, 4 ), // #620 - INST(Psrlq , ExtRmRi_P , O(000F00,D3,_,_,_,_,_,_ ), O(000F00,73,2,_,_,_,_,_ ), 4 , 76 , 10244, 167, 82 ), // #621 - INST(Psrlw , ExtRmRi_P , O(000F00,D1,_,_,_,_,_,_ ), O(000F00,71,2,_,_,_,_,_ ), 4 , 77 , 10275, 167, 82 ), // #622 - INST(Psubb , ExtRm_P , O(000F00,F8,_,_,_,_,_,_ ), 0 , 4 , 0 , 10282, 149, 82 ), // #623 - INST(Psubd , ExtRm_P , O(000F00,FA,_,_,_,_,_,_ ), 0 , 4 , 0 , 10289, 149, 82 ), // #624 - INST(Psubq , ExtRm_P , O(000F00,FB,_,_,_,_,_,_ ), 0 , 4 , 0 , 10296, 149, 4 ), // #625 - INST(Psubsb , ExtRm_P , O(000F00,E8,_,_,_,_,_,_ ), 0 , 4 , 0 , 10303, 149, 82 ), // #626 - INST(Psubsw , ExtRm_P , O(000F00,E9,_,_,_,_,_,_ ), 0 , 4 , 0 , 10311, 149, 82 ), // #627 - INST(Psubusb , ExtRm_P , O(000F00,D8,_,_,_,_,_,_ ), 0 , 4 , 0 , 10319, 149, 82 ), // #628 - INST(Psubusw , ExtRm_P , O(000F00,D9,_,_,_,_,_,_ ), 0 , 4 , 0 , 10328, 149, 82 ), // #629 - INST(Psubw , ExtRm_P , O(000F00,F9,_,_,_,_,_,_ ), 0 , 4 , 0 , 10337, 149, 82 ), // #630 - INST(Pswapd , Ext3dNow , O(000F0F,BB,_,_,_,_,_,_ ), 0 , 87 , 0 , 2402 , 150, 92 ), // #631 - INST(Ptest , ExtRm , O(660F38,17,_,_,_,_,_,_ ), 0 , 2 , 0 , 10366, 5 , 99 ), // #632 - INST(Ptwrite , X86M , O(F30F00,AE,4,_,_,_,_,_ ), 0 , 91 , 0 , 2409 , 169, 100), // #633 - INST(Punpckhbw , ExtRm_P , O(000F00,68,_,_,_,_,_,_ ), 0 , 4 , 0 , 10449, 146, 82 ), // #634 - INST(Punpckhdq , ExtRm_P , O(000F00,6A,_,_,_,_,_,_ ), 0 , 4 , 0 , 10460, 146, 82 ), // #635 - INST(Punpckhqdq , ExtRm , O(660F00,6D,_,_,_,_,_,_ ), 0 , 3 , 0 , 10471, 5 , 4 ), // #636 - INST(Punpckhwd , ExtRm_P , O(000F00,69,_,_,_,_,_,_ ), 0 , 4 , 0 , 10483, 146, 82 ), // #637 - INST(Punpcklbw , ExtRm_P , O(000F00,60,_,_,_,_,_,_ ), 0 , 4 , 0 , 10494, 170, 82 ), // #638 - INST(Punpckldq , ExtRm_P , O(000F00,62,_,_,_,_,_,_ ), 0 , 4 , 0 , 10505, 170, 82 ), // #639 - INST(Punpcklqdq , ExtRm , O(660F00,6C,_,_,_,_,_,_ ), 0 , 3 , 0 , 10516, 5 , 4 ), // #640 - INST(Punpcklwd , ExtRm_P , O(000F00,61,_,_,_,_,_,_ ), 0 , 4 , 0 , 10528, 170, 82 ), // #641 - INST(Push , X86Push , O(000000,FF,6,_,_,_,_,_ ), O(000000,50,_,_,_,_,_,_ ), 32 , 78 , 2417 , 171, 0 ), // #642 - INST(Pusha , X86Op , O(660000,60,_,_,_,_,_,_ ), 0 , 19 , 0 , 2422 , 81 , 0 ), // #643 - INST(Pushad , X86Op , O(000000,60,_,_,_,_,_,_ ), 0 , 0 , 0 , 2428 , 81 , 0 ), // #644 - INST(Pushf , X86Op , O(660000,9C,_,_,_,_,_,_ ), 0 , 19 , 0 , 2435 , 30 , 101), // #645 - INST(Pushfd , X86Op , O(000000,9C,_,_,_,_,_,_ ), 0 , 0 , 0 , 2441 , 81 , 101), // #646 - INST(Pushfq , X86Op , O(000000,9C,_,_,_,_,_,_ ), 0 , 0 , 0 , 2448 , 33 , 101), // #647 - INST(Pvalidate , X86Op , O(F20F01,FF,_,_,_,_,_,_ ), 0 , 92 , 0 , 2455 , 30 , 102), // #648 - INST(Pxor , ExtRm_P , O(000F00,EF,_,_,_,_,_,_ ), 0 , 4 , 0 , 10539, 149, 82 ), // #649 - INST(Rcl , X86Rot , O(000000,D0,2,_,x,_,_,_ ), 0 , 1 , 0 , 2465 , 172, 103), // #650 - INST(Rcpps , ExtRm , O(000F00,53,_,_,_,_,_,_ ), 0 , 4 , 0 , 10674, 5 , 5 ), // #651 - INST(Rcpss , ExtRm , O(F30F00,53,_,_,_,_,_,_ ), 0 , 6 , 0 , 10688, 7 , 5 ), // #652 - INST(Rcr , X86Rot , O(000000,D0,3,_,x,_,_,_ ), 0 , 75 , 0 , 2469 , 172, 103), // #653 - INST(Rdfsbase , X86M , O(F30F00,AE,0,_,x,_,_,_ ), 0 , 6 , 0 , 2473 , 173, 104), // #654 - INST(Rdgsbase , X86M , O(F30F00,AE,1,_,x,_,_,_ ), 0 , 93 , 0 , 2482 , 173, 104), // #655 - INST(Rdmsr , X86Op , O(000F00,32,_,_,_,_,_,_ ), 0 , 4 , 0 , 2491 , 174, 105), // #656 - INST(Rdpid , X86R_Native , O(F30F00,C7,7,_,_,_,_,_ ), 0 , 94 , 0 , 2497 , 175, 106), // #657 - INST(Rdpkru , X86Op , O(000F01,EE,_,_,_,_,_,_ ), 0 , 21 , 0 , 2503 , 174, 107), // #658 - INST(Rdpmc , X86Op , O(000F00,33,_,_,_,_,_,_ ), 0 , 4 , 0 , 2510 , 174, 0 ), // #659 - INST(Rdpru , X86Op , O(000F01,FD,_,_,_,_,_,_ ), 0 , 21 , 0 , 2516 , 174, 108), // #660 - INST(Rdrand , X86M , O(000F00,C7,6,_,x,_,_,_ ), 0 , 80 , 0 , 2522 , 23 , 109), // #661 - INST(Rdseed , X86M , O(000F00,C7,7,_,x,_,_,_ ), 0 , 22 , 0 , 2529 , 23 , 110), // #662 - INST(Rdsspd , X86M , O(F30F00,1E,1,_,_,_,_,_ ), 0 , 93 , 0 , 2536 , 76 , 56 ), // #663 - INST(Rdsspq , X86M , O(F30F00,1E,1,_,_,_,_,_ ), 0 , 93 , 0 , 2543 , 77 , 56 ), // #664 - INST(Rdtsc , X86Op , O(000F00,31,_,_,_,_,_,_ ), 0 , 4 , 0 , 2550 , 28 , 111), // #665 - INST(Rdtscp , X86Op , O(000F01,F9,_,_,_,_,_,_ ), 0 , 21 , 0 , 2556 , 174, 112), // #666 - INST(Ret , X86Ret , O(000000,C2,_,_,_,_,_,_ ), 0 , 0 , 0 , 3072 , 176, 0 ), // #667 - INST(Retf , X86Ret , O(000000,CA,_,_,x,_,_,_ ), 0 , 0 , 0 , 2563 , 177, 0 ), // #668 - INST(Rmpadjust , X86Op , O(F30F01,FE,_,_,_,_,_,_ ), 0 , 25 , 0 , 2568 , 33 , 98 ), // #669 - INST(Rmpupdate , X86Op , O(F20F01,FE,_,_,_,_,_,_ ), 0 , 92 , 0 , 2578 , 33 , 98 ), // #670 - INST(Rol , X86Rot , O(000000,D0,0,_,x,_,_,_ ), 0 , 0 , 0 , 2588 , 172, 113), // #671 - INST(Ror , X86Rot , O(000000,D0,1,_,x,_,_,_ ), 0 , 31 , 0 , 2592 , 172, 113), // #672 - INST(Rorx , VexRmi_Wx , V(F20F3A,F0,_,0,x,_,_,_ ), 0 , 95 , 0 , 2596 , 178, 85 ), // #673 - INST(Roundpd , ExtRmi , O(660F3A,09,_,_,_,_,_,_ ), 0 , 8 , 0 , 10827, 8 , 12 ), // #674 - INST(Roundps , ExtRmi , O(660F3A,08,_,_,_,_,_,_ ), 0 , 8 , 0 , 10836, 8 , 12 ), // #675 - INST(Roundsd , ExtRmi , O(660F3A,0B,_,_,_,_,_,_ ), 0 , 8 , 0 , 10845, 37 , 12 ), // #676 - INST(Roundss , ExtRmi , O(660F3A,0A,_,_,_,_,_,_ ), 0 , 8 , 0 , 10854, 38 , 12 ), // #677 - INST(Rsm , X86Op , O(000F00,AA,_,_,_,_,_,_ ), 0 , 4 , 0 , 2601 , 81 , 1 ), // #678 - INST(Rsqrtps , ExtRm , O(000F00,52,_,_,_,_,_,_ ), 0 , 4 , 0 , 10960, 5 , 5 ), // #679 - INST(Rsqrtss , ExtRm , O(F30F00,52,_,_,_,_,_,_ ), 0 , 6 , 0 , 10978, 7 , 5 ), // #680 - INST(Rstorssp , X86M_Only , O(F30F00,01,5,_,_,_,_,_ ), 0 , 63 , 0 , 2605 , 32 , 24 ), // #681 - INST(Sahf , X86Op , O(000000,9E,_,_,_,_,_,_ ), 0 , 0 , 0 , 2614 , 97 , 114), // #682 - INST(Sal , X86Rot , O(000000,D0,4,_,x,_,_,_ ), 0 , 9 , 0 , 2619 , 172, 1 ), // #683 - INST(Sar , X86Rot , O(000000,D0,7,_,x,_,_,_ ), 0 , 27 , 0 , 2623 , 172, 1 ), // #684 - INST(Sarx , VexRmv_Wx , V(F30F38,F7,_,0,x,_,_,_ ), 0 , 88 , 0 , 2627 , 13 , 85 ), // #685 - INST(Saveprevssp , X86Op , O(F30F01,EA,_,_,_,_,_,_ ), 0 , 25 , 0 , 2632 , 30 , 24 ), // #686 - INST(Sbb , X86Arith , O(000000,18,3,_,x,_,_,_ ), 0 , 75 , 0 , 2644 , 179, 2 ), // #687 - INST(Scas , X86StrRm , O(000000,AE,_,_,_,_,_,_ ), 0 , 0 , 0 , 2648 , 180, 37 ), // #688 - INST(Senduipi , X86M_NoSize , O(F30F00,C7,6,_,_,_,_,_ ), 0 , 24 , 0 , 2653 , 77 , 25 ), // #689 - INST(Serialize , X86Op , O(000F01,E8,_,_,_,_,_,_ ), 0 , 21 , 0 , 2662 , 30 , 115), // #690 - INST(Seta , X86Set , O(000F00,97,_,_,_,_,_,_ ), 0 , 4 , 0 , 2672 , 181, 59 ), // #691 - INST(Setae , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 2677 , 181, 60 ), // #692 - INST(Setb , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 2683 , 181, 60 ), // #693 - INST(Setbe , X86Set , O(000F00,96,_,_,_,_,_,_ ), 0 , 4 , 0 , 2688 , 181, 59 ), // #694 - INST(Setc , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 2694 , 181, 60 ), // #695 - INST(Sete , X86Set , O(000F00,94,_,_,_,_,_,_ ), 0 , 4 , 0 , 2699 , 181, 61 ), // #696 - INST(Setg , X86Set , O(000F00,9F,_,_,_,_,_,_ ), 0 , 4 , 0 , 2704 , 181, 62 ), // #697 - INST(Setge , X86Set , O(000F00,9D,_,_,_,_,_,_ ), 0 , 4 , 0 , 2709 , 181, 63 ), // #698 - INST(Setl , X86Set , O(000F00,9C,_,_,_,_,_,_ ), 0 , 4 , 0 , 2715 , 181, 63 ), // #699 - INST(Setle , X86Set , O(000F00,9E,_,_,_,_,_,_ ), 0 , 4 , 0 , 2720 , 181, 62 ), // #700 - INST(Setna , X86Set , O(000F00,96,_,_,_,_,_,_ ), 0 , 4 , 0 , 2726 , 181, 59 ), // #701 - INST(Setnae , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 2732 , 181, 60 ), // #702 - INST(Setnb , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 2739 , 181, 60 ), // #703 - INST(Setnbe , X86Set , O(000F00,97,_,_,_,_,_,_ ), 0 , 4 , 0 , 2745 , 181, 59 ), // #704 - INST(Setnc , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 2752 , 181, 60 ), // #705 - INST(Setne , X86Set , O(000F00,95,_,_,_,_,_,_ ), 0 , 4 , 0 , 2758 , 181, 61 ), // #706 - INST(Setng , X86Set , O(000F00,9E,_,_,_,_,_,_ ), 0 , 4 , 0 , 2764 , 181, 62 ), // #707 - INST(Setnge , X86Set , O(000F00,9C,_,_,_,_,_,_ ), 0 , 4 , 0 , 2770 , 181, 63 ), // #708 - INST(Setnl , X86Set , O(000F00,9D,_,_,_,_,_,_ ), 0 , 4 , 0 , 2777 , 181, 63 ), // #709 - INST(Setnle , X86Set , O(000F00,9F,_,_,_,_,_,_ ), 0 , 4 , 0 , 2783 , 181, 62 ), // #710 - INST(Setno , X86Set , O(000F00,91,_,_,_,_,_,_ ), 0 , 4 , 0 , 2790 , 181, 57 ), // #711 - INST(Setnp , X86Set , O(000F00,9B,_,_,_,_,_,_ ), 0 , 4 , 0 , 2796 , 181, 64 ), // #712 - INST(Setns , X86Set , O(000F00,99,_,_,_,_,_,_ ), 0 , 4 , 0 , 2802 , 181, 65 ), // #713 - INST(Setnz , X86Set , O(000F00,95,_,_,_,_,_,_ ), 0 , 4 , 0 , 2808 , 181, 61 ), // #714 - INST(Seto , X86Set , O(000F00,90,_,_,_,_,_,_ ), 0 , 4 , 0 , 2814 , 181, 57 ), // #715 - INST(Setp , X86Set , O(000F00,9A,_,_,_,_,_,_ ), 0 , 4 , 0 , 2819 , 181, 64 ), // #716 - INST(Setpe , X86Set , O(000F00,9A,_,_,_,_,_,_ ), 0 , 4 , 0 , 2824 , 181, 64 ), // #717 - INST(Setpo , X86Set , O(000F00,9B,_,_,_,_,_,_ ), 0 , 4 , 0 , 2830 , 181, 64 ), // #718 - INST(Sets , X86Set , O(000F00,98,_,_,_,_,_,_ ), 0 , 4 , 0 , 2836 , 181, 65 ), // #719 - INST(Setssbsy , X86Op , O(F30F01,E8,_,_,_,_,_,_ ), 0 , 25 , 0 , 2841 , 30 , 56 ), // #720 - INST(Setz , X86Set , O(000F00,94,_,_,_,_,_,_ ), 0 , 4 , 0 , 2850 , 181, 61 ), // #721 - INST(Sfence , X86Fence , O(000F00,AE,7,_,_,_,_,_ ), 0 , 22 , 0 , 2855 , 30 , 77 ), // #722 - INST(Sgdt , X86M_Only , O(000F00,01,0,_,_,_,_,_ ), 0 , 4 , 0 , 2862 , 69 , 0 ), // #723 - INST(Sha1msg1 , ExtRm , O(000F38,C9,_,_,_,_,_,_ ), 0 , 83 , 0 , 2867 , 5 , 116), // #724 - INST(Sha1msg2 , ExtRm , O(000F38,CA,_,_,_,_,_,_ ), 0 , 83 , 0 , 2876 , 5 , 116), // #725 - INST(Sha1nexte , ExtRm , O(000F38,C8,_,_,_,_,_,_ ), 0 , 83 , 0 , 2885 , 5 , 116), // #726 - INST(Sha1rnds4 , ExtRmi , O(000F3A,CC,_,_,_,_,_,_ ), 0 , 85 , 0 , 2895 , 8 , 116), // #727 - INST(Sha256msg1 , ExtRm , O(000F38,CC,_,_,_,_,_,_ ), 0 , 83 , 0 , 2905 , 5 , 116), // #728 - INST(Sha256msg2 , ExtRm , O(000F38,CD,_,_,_,_,_,_ ), 0 , 83 , 0 , 2916 , 5 , 116), // #729 - INST(Sha256rnds2 , ExtRm_XMM0 , O(000F38,CB,_,_,_,_,_,_ ), 0 , 83 , 0 , 2927 , 15 , 116), // #730 - INST(Shl , X86Rot , O(000000,D0,4,_,x,_,_,_ ), 0 , 9 , 0 , 2939 , 172, 1 ), // #731 - INST(Shld , X86ShldShrd , O(000F00,A4,_,_,x,_,_,_ ), 0 , 4 , 0 , 9938 , 182, 1 ), // #732 - INST(Shlx , VexRmv_Wx , V(660F38,F7,_,0,x,_,_,_ ), 0 , 96 , 0 , 2943 , 13 , 85 ), // #733 - INST(Shr , X86Rot , O(000000,D0,5,_,x,_,_,_ ), 0 , 62 , 0 , 2948 , 172, 1 ), // #734 - INST(Shrd , X86ShldShrd , O(000F00,AC,_,_,x,_,_,_ ), 0 , 4 , 0 , 2952 , 182, 1 ), // #735 - INST(Shrx , VexRmv_Wx , V(F20F38,F7,_,0,x,_,_,_ ), 0 , 84 , 0 , 2957 , 13 , 85 ), // #736 - INST(Shufpd , ExtRmi , O(660F00,C6,_,_,_,_,_,_ ), 0 , 3 , 0 , 11259, 8 , 4 ), // #737 - INST(Shufps , ExtRmi , O(000F00,C6,_,_,_,_,_,_ ), 0 , 4 , 0 , 11267, 8 , 5 ), // #738 - INST(Sidt , X86M_Only , O(000F00,01,1,_,_,_,_,_ ), 0 , 29 , 0 , 2962 , 69 , 0 ), // #739 - INST(Skinit , X86Op_xAX , O(000F01,DE,_,_,_,_,_,_ ), 0 , 21 , 0 , 2967 , 52 , 117), // #740 - INST(Sldt , X86M_NoMemSize , O(000F00,00,0,_,_,_,_,_ ), 0 , 4 , 0 , 2974 , 183, 0 ), // #741 - INST(Slwpcb , VexR_Wx , V(XOP_M9,12,1,0,x,_,_,_ ), 0 , 11 , 0 , 2979 , 108, 74 ), // #742 - INST(Smsw , X86M_NoMemSize , O(000F00,01,4,_,_,_,_,_ ), 0 , 97 , 0 , 2986 , 183, 0 ), // #743 - INST(Sqrtpd , ExtRm , O(660F00,51,_,_,_,_,_,_ ), 0 , 3 , 0 , 11275, 5 , 4 ), // #744 - INST(Sqrtps , ExtRm , O(000F00,51,_,_,_,_,_,_ ), 0 , 4 , 0 , 10961, 5 , 5 ), // #745 - INST(Sqrtsd , ExtRm , O(F20F00,51,_,_,_,_,_,_ ), 0 , 5 , 0 , 11299, 6 , 4 ), // #746 - INST(Sqrtss , ExtRm , O(F30F00,51,_,_,_,_,_,_ ), 0 , 6 , 0 , 10979, 7 , 5 ), // #747 - INST(Stac , X86Op , O(000F01,CB,_,_,_,_,_,_ ), 0 , 21 , 0 , 2991 , 30 , 16 ), // #748 - INST(Stc , X86Op , O(000000,F9,_,_,_,_,_,_ ), 0 , 0 , 0 , 2996 , 30 , 17 ), // #749 - INST(Std , X86Op , O(000000,FD,_,_,_,_,_,_ ), 0 , 0 , 0 , 7921 , 30 , 18 ), // #750 - INST(Stgi , X86Op , O(000F01,DC,_,_,_,_,_,_ ), 0 , 21 , 0 , 3000 , 30 , 117), // #751 - INST(Sti , X86Op , O(000000,FB,_,_,_,_,_,_ ), 0 , 0 , 0 , 3005 , 30 , 23 ), // #752 - INST(Stmxcsr , X86M_Only , O(000F00,AE,3,_,_,_,_,_ ), 0 , 78 , 0 , 11323, 101, 5 ), // #753 - INST(Stos , X86StrMr , O(000000,AA,_,_,_,_,_,_ ), 0 , 0 , 0 , 3009 , 184, 75 ), // #754 - INST(Str , X86M_NoMemSize , O(000F00,00,1,_,_,_,_,_ ), 0 , 29 , 0 , 3014 , 183, 0 ), // #755 - INST(Sttilecfg , AmxCfg , V(660F38,49,_,0,0,_,_,_ ), 0 , 96 , 0 , 3018 , 103, 73 ), // #756 - INST(Stui , X86Op , O(F30F01,EF,_,_,_,_,_,_ ), 0 , 25 , 0 , 3135 , 33 , 25 ), // #757 - INST(Sub , X86Arith , O(000000,28,5,_,x,_,_,_ ), 0 , 62 , 0 , 866 , 179, 1 ), // #758 - INST(Subpd , ExtRm , O(660F00,5C,_,_,_,_,_,_ ), 0 , 3 , 0 , 5413 , 5 , 4 ), // #759 - INST(Subps , ExtRm , O(000F00,5C,_,_,_,_,_,_ ), 0 , 4 , 0 , 5425 , 5 , 5 ), // #760 - INST(Subsd , ExtRm , O(F20F00,5C,_,_,_,_,_,_ ), 0 , 5 , 0 , 6392 , 6 , 4 ), // #761 - INST(Subss , ExtRm , O(F30F00,5C,_,_,_,_,_,_ ), 0 , 6 , 0 , 6402 , 7 , 5 ), // #762 - INST(Swapgs , X86Op , O(000F01,F8,_,_,_,_,_,_ ), 0 , 21 , 0 , 3028 , 33 , 0 ), // #763 - INST(Syscall , X86Op , O(000F00,05,_,_,_,_,_,_ ), 0 , 4 , 0 , 3035 , 33 , 0 ), // #764 - INST(Sysenter , X86Op , O(000F00,34,_,_,_,_,_,_ ), 0 , 4 , 0 , 3043 , 30 , 0 ), // #765 - INST(Sysexit , X86Op , O(000F00,35,_,_,_,_,_,_ ), 0 , 4 , 0 , 3052 , 30 , 0 ), // #766 - INST(Sysexitq , X86Op , O(000F00,35,_,_,1,_,_,_ ), 0 , 60 , 0 , 3060 , 30 , 0 ), // #767 - INST(Sysret , X86Op , O(000F00,07,_,_,_,_,_,_ ), 0 , 4 , 0 , 3069 , 33 , 0 ), // #768 - INST(Sysretq , X86Op , O(000F00,07,_,_,1,_,_,_ ), 0 , 60 , 0 , 3076 , 33 , 0 ), // #769 - INST(T1mskc , VexVm_Wx , V(XOP_M9,01,7,0,x,_,_,_ ), 0 , 98 , 0 , 3084 , 14 , 11 ), // #770 - INST(Tdpbf16ps , AmxRmv , V(F30F38,5C,_,0,0,_,_,_ ), 0 , 88 , 0 , 3091 , 185, 118), // #771 - INST(Tdpbssd , AmxRmv , V(F20F38,5E,_,0,0,_,_,_ ), 0 , 84 , 0 , 3101 , 185, 119), // #772 - INST(Tdpbsud , AmxRmv , V(F30F38,5E,_,0,0,_,_,_ ), 0 , 88 , 0 , 3109 , 185, 119), // #773 - INST(Tdpbusd , AmxRmv , V(660F38,5E,_,0,0,_,_,_ ), 0 , 96 , 0 , 3117 , 185, 119), // #774 - INST(Tdpbuud , AmxRmv , V(000F38,5E,_,0,0,_,_,_ ), 0 , 10 , 0 , 3125 , 185, 119), // #775 - INST(Test , X86Test , O(000000,84,_,_,x,_,_,_ ), O(000000,F6,_,_,x,_,_,_ ), 0 , 79 , 10367, 186, 1 ), // #776 - INST(Testui , X86Op , O(F30F01,ED,_,_,_,_,_,_ ), 0 , 25 , 0 , 3133 , 33 , 120), // #777 - INST(Tileloadd , AmxRm , V(F20F38,4B,_,0,0,_,_,_ ), 0 , 84 , 0 , 3140 , 187, 73 ), // #778 - INST(Tileloaddt1 , AmxRm , V(660F38,4B,_,0,0,_,_,_ ), 0 , 96 , 0 , 3150 , 187, 73 ), // #779 - INST(Tilerelease , VexOpMod , V(000F38,49,0,0,0,_,_,_ ), 0 , 10 , 0 , 3162 , 188, 73 ), // #780 - INST(Tilestored , AmxMr , V(F30F38,4B,_,0,0,_,_,_ ), 0 , 88 , 0 , 3174 , 189, 73 ), // #781 - INST(Tilezero , AmxR , V(F20F38,49,_,0,0,_,_,_ ), 0 , 84 , 0 , 3185 , 190, 73 ), // #782 - INST(Tpause , X86R32_EDX_EAX , O(660F00,AE,6,_,_,_,_,_ ), 0 , 26 , 0 , 3194 , 191, 121), // #783 - INST(Tzcnt , X86Rm_Raw66H , O(F30F00,BC,_,_,x,_,_,_ ), 0 , 6 , 0 , 3201 , 22 , 9 ), // #784 - INST(Tzmsk , VexVm_Wx , V(XOP_M9,01,4,0,x,_,_,_ ), 0 , 99 , 0 , 3207 , 14 , 11 ), // #785 - INST(Ucomisd , ExtRm , O(660F00,2E,_,_,_,_,_,_ ), 0 , 3 , 0 , 11390, 6 , 41 ), // #786 - INST(Ucomiss , ExtRm , O(000F00,2E,_,_,_,_,_,_ ), 0 , 4 , 0 , 11408, 7 , 42 ), // #787 - INST(Ud0 , X86Rm , O(000F00,FF,_,_,_,_,_,_ ), 0 , 4 , 0 , 3213 , 192, 0 ), // #788 - INST(Ud1 , X86Rm , O(000F00,B9,_,_,_,_,_,_ ), 0 , 4 , 0 , 3217 , 192, 0 ), // #789 - INST(Ud2 , X86Op , O(000F00,0B,_,_,_,_,_,_ ), 0 , 4 , 0 , 3221 , 30 , 0 ), // #790 - INST(Uiret , X86Op , O(F30F01,EC,_,_,_,_,_,_ ), 0 , 25 , 0 , 3225 , 33 , 25 ), // #791 - INST(Umonitor , X86R_FromM , O(F30F00,AE,6,_,_,_,_,_ ), 0 , 24 , 0 , 3231 , 193, 122), // #792 - INST(Umwait , X86R32_EDX_EAX , O(F20F00,AE,6,_,_,_,_,_ ), 0 , 100, 0 , 3240 , 191, 121), // #793 - INST(Unpckhpd , ExtRm , O(660F00,15,_,_,_,_,_,_ ), 0 , 3 , 0 , 11417, 5 , 4 ), // #794 - INST(Unpckhps , ExtRm , O(000F00,15,_,_,_,_,_,_ ), 0 , 4 , 0 , 11427, 5 , 5 ), // #795 - INST(Unpcklpd , ExtRm , O(660F00,14,_,_,_,_,_,_ ), 0 , 3 , 0 , 11437, 5 , 4 ), // #796 - INST(Unpcklps , ExtRm , O(000F00,14,_,_,_,_,_,_ ), 0 , 4 , 0 , 11447, 5 , 5 ), // #797 - INST(V4fmaddps , VexRm_T1_4X , E(F20F38,9A,_,2,_,0,4,T4X), 0 , 101, 0 , 3247 , 194, 123), // #798 - INST(V4fmaddss , VexRm_T1_4X , E(F20F38,9B,_,0,_,0,4,T4X), 0 , 102, 0 , 3257 , 195, 123), // #799 - INST(V4fnmaddps , VexRm_T1_4X , E(F20F38,AA,_,2,_,0,4,T4X), 0 , 101, 0 , 3267 , 194, 123), // #800 - INST(V4fnmaddss , VexRm_T1_4X , E(F20F38,AB,_,0,_,0,4,T4X), 0 , 102, 0 , 3278 , 195, 123), // #801 - INST(Vaddpd , VexRvm_Lx , V(660F00,58,_,x,I,1,4,FV ), 0 , 103, 0 , 3289 , 196, 124), // #802 - INST(Vaddph , VexRvm_Lx , E(00MAP5,58,_,_,_,0,4,FV ), 0 , 104, 0 , 3296 , 197, 125), // #803 - INST(Vaddps , VexRvm_Lx , V(000F00,58,_,x,I,0,4,FV ), 0 , 105, 0 , 3303 , 198, 124), // #804 - INST(Vaddsd , VexRvm , V(F20F00,58,_,I,I,1,3,T1S), 0 , 106, 0 , 3310 , 199, 126), // #805 - INST(Vaddsh , VexRvm , E(F3MAP5,58,_,_,_,0,1,T1S), 0 , 107, 0 , 3317 , 200, 127), // #806 - INST(Vaddss , VexRvm , V(F30F00,58,_,I,I,0,2,T1S), 0 , 108, 0 , 3324 , 201, 126), // #807 - INST(Vaddsubpd , VexRvm_Lx , V(660F00,D0,_,x,I,_,_,_ ), 0 , 69 , 0 , 3331 , 202, 128), // #808 - INST(Vaddsubps , VexRvm_Lx , V(F20F00,D0,_,x,I,_,_,_ ), 0 , 109, 0 , 3341 , 202, 128), // #809 - INST(Vaesdec , VexRvm_Lx , V(660F38,DE,_,x,I,_,4,FVM), 0 , 110, 0 , 3351 , 203, 129), // #810 - INST(Vaesdeclast , VexRvm_Lx , V(660F38,DF,_,x,I,_,4,FVM), 0 , 110, 0 , 3359 , 203, 129), // #811 - INST(Vaesenc , VexRvm_Lx , V(660F38,DC,_,x,I,_,4,FVM), 0 , 110, 0 , 3371 , 203, 129), // #812 - INST(Vaesenclast , VexRvm_Lx , V(660F38,DD,_,x,I,_,4,FVM), 0 , 110, 0 , 3379 , 203, 129), // #813 - INST(Vaesimc , VexRm , V(660F38,DB,_,0,I,_,_,_ ), 0 , 96 , 0 , 3391 , 204, 130), // #814 - INST(Vaeskeygenassist , VexRmi , V(660F3A,DF,_,0,I,_,_,_ ), 0 , 73 , 0 , 3399 , 205, 130), // #815 - INST(Valignd , VexRvmi_Lx , E(660F3A,03,_,x,_,0,4,FV ), 0 , 111, 0 , 3416 , 206, 131), // #816 - INST(Valignq , VexRvmi_Lx , E(660F3A,03,_,x,_,1,4,FV ), 0 , 112, 0 , 3424 , 207, 131), // #817 - INST(Vandnpd , VexRvm_Lx , V(660F00,55,_,x,I,1,4,FV ), 0 , 103, 0 , 3432 , 208, 132), // #818 - INST(Vandnps , VexRvm_Lx , V(000F00,55,_,x,I,0,4,FV ), 0 , 105, 0 , 3440 , 209, 132), // #819 - INST(Vandpd , VexRvm_Lx , V(660F00,54,_,x,I,1,4,FV ), 0 , 103, 0 , 3448 , 210, 132), // #820 - INST(Vandps , VexRvm_Lx , V(000F00,54,_,x,I,0,4,FV ), 0 , 105, 0 , 3455 , 211, 132), // #821 - INST(Vblendmpd , VexRvm_Lx , E(660F38,65,_,x,_,1,4,FV ), 0 , 113, 0 , 3462 , 212, 131), // #822 - INST(Vblendmps , VexRvm_Lx , E(660F38,65,_,x,_,0,4,FV ), 0 , 114, 0 , 3472 , 213, 131), // #823 - INST(Vblendpd , VexRvmi_Lx , V(660F3A,0D,_,x,I,_,_,_ ), 0 , 73 , 0 , 3482 , 214, 128), // #824 - INST(Vblendps , VexRvmi_Lx , V(660F3A,0C,_,x,I,_,_,_ ), 0 , 73 , 0 , 3491 , 214, 128), // #825 - INST(Vblendvpd , VexRvmr_Lx , V(660F3A,4B,_,x,0,_,_,_ ), 0 , 73 , 0 , 3500 , 215, 128), // #826 - INST(Vblendvps , VexRvmr_Lx , V(660F3A,4A,_,x,0,_,_,_ ), 0 , 73 , 0 , 3510 , 215, 128), // #827 - INST(Vbroadcastf128 , VexRm , V(660F38,1A,_,1,0,_,_,_ ), 0 , 115, 0 , 3520 , 216, 128), // #828 - INST(Vbroadcastf32x2 , VexRm_Lx , E(660F38,19,_,x,_,0,3,T2 ), 0 , 116, 0 , 3535 , 217, 133), // #829 - INST(Vbroadcastf32x4 , VexRm_Lx , E(660F38,1A,_,x,_,0,4,T4 ), 0 , 117, 0 , 3551 , 218, 68 ), // #830 - INST(Vbroadcastf32x8 , VexRm , E(660F38,1B,_,2,_,0,5,T8 ), 0 , 118, 0 , 3567 , 219, 66 ), // #831 - INST(Vbroadcastf64x2 , VexRm_Lx , E(660F38,1A,_,x,_,1,4,T2 ), 0 , 119, 0 , 3583 , 218, 133), // #832 - INST(Vbroadcastf64x4 , VexRm , E(660F38,1B,_,2,_,1,5,T4 ), 0 , 120, 0 , 3599 , 219, 68 ), // #833 - INST(Vbroadcasti128 , VexRm , V(660F38,5A,_,1,0,_,_,_ ), 0 , 115, 0 , 3615 , 216, 134), // #834 - INST(Vbroadcasti32x2 , VexRm_Lx , E(660F38,59,_,x,_,0,3,T2 ), 0 , 116, 0 , 3630 , 220, 133), // #835 - INST(Vbroadcasti32x4 , VexRm_Lx , E(660F38,5A,_,x,_,0,4,T4 ), 0 , 117, 0 , 3646 , 218, 131), // #836 - INST(Vbroadcasti32x8 , VexRm , E(660F38,5B,_,2,_,0,5,T8 ), 0 , 118, 0 , 3662 , 219, 66 ), // #837 - INST(Vbroadcasti64x2 , VexRm_Lx , E(660F38,5A,_,x,_,1,4,T2 ), 0 , 119, 0 , 3678 , 218, 133), // #838 - INST(Vbroadcasti64x4 , VexRm , E(660F38,5B,_,2,_,1,5,T4 ), 0 , 120, 0 , 3694 , 219, 68 ), // #839 - INST(Vbroadcastsd , VexRm_Lx , V(660F38,19,_,x,0,1,3,T1S), 0 , 121, 0 , 3710 , 221, 135), // #840 - INST(Vbroadcastss , VexRm_Lx , V(660F38,18,_,x,0,0,2,T1S), 0 , 122, 0 , 3723 , 222, 135), // #841 - INST(Vcmppd , VexRvmi_Lx_KEvex , V(660F00,C2,_,x,I,1,4,FV ), 0 , 103, 0 , 3736 , 223, 124), // #842 - INST(Vcmpph , VexRvmi_Lx_KEvex , E(000F3A,C2,_,_,_,0,4,FV ), 0 , 123, 0 , 3743 , 224, 125), // #843 - INST(Vcmpps , VexRvmi_Lx_KEvex , V(000F00,C2,_,x,I,0,4,FV ), 0 , 105, 0 , 3750 , 225, 124), // #844 - INST(Vcmpsd , VexRvmi_KEvex , V(F20F00,C2,_,I,I,1,3,T1S), 0 , 106, 0 , 3757 , 226, 126), // #845 - INST(Vcmpsh , VexRvmi_KEvex , E(F30F3A,C2,_,_,_,0,1,T1S), 0 , 124, 0 , 3764 , 227, 127), // #846 - INST(Vcmpss , VexRvmi_KEvex , V(F30F00,C2,_,I,I,0,2,T1S), 0 , 108, 0 , 3771 , 228, 126), // #847 - INST(Vcomisd , VexRm , V(660F00,2F,_,I,I,1,3,T1S), 0 , 125, 0 , 3778 , 229, 136), // #848 - INST(Vcomish , VexRm , E(00MAP5,2F,_,_,_,0,1,T1S), 0 , 126, 0 , 3786 , 230, 127), // #849 - INST(Vcomiss , VexRm , V(000F00,2F,_,I,I,0,2,T1S), 0 , 127, 0 , 3794 , 231, 136), // #850 - INST(Vcompresspd , VexMr_Lx , E(660F38,8A,_,x,_,1,3,T1S), 0 , 128, 0 , 3802 , 232, 131), // #851 - INST(Vcompressps , VexMr_Lx , E(660F38,8A,_,x,_,0,2,T1S), 0 , 129, 0 , 3814 , 232, 131), // #852 - INST(Vcvtdq2pd , VexRm_Lx , V(F30F00,E6,_,x,I,0,3,HV ), 0 , 130, 0 , 3826 , 233, 124), // #853 - INST(Vcvtdq2ph , VexRm_Lx , E(00MAP5,5B,_,_,_,0,4,FV ), 0 , 104, 0 , 3836 , 234, 125), // #854 - INST(Vcvtdq2ps , VexRm_Lx , V(000F00,5B,_,x,I,0,4,FV ), 0 , 105, 0 , 3846 , 235, 124), // #855 - INST(Vcvtne2ps2bf16 , VexRvm_Lx , E(F20F38,72,_,_,_,0,4,FV ), 0 , 131, 0 , 3856 , 213, 137), // #856 - INST(Vcvtneps2bf16 , VexRm_Lx_Narrow , E(F30F38,72,_,_,_,0,4,FV ), 0 , 132, 0 , 3871 , 236, 137), // #857 - INST(Vcvtpd2dq , VexRm_Lx_Narrow , V(F20F00,E6,_,x,I,1,4,FV ), 0 , 133, 0 , 3885 , 237, 124), // #858 - INST(Vcvtpd2ph , VexRm_Lx , E(66MAP5,5A,_,_,_,1,4,FV ), 0 , 134, 0 , 3895 , 238, 125), // #859 - INST(Vcvtpd2ps , VexRm_Lx_Narrow , V(660F00,5A,_,x,I,1,4,FV ), 0 , 103, 0 , 3905 , 237, 124), // #860 - INST(Vcvtpd2qq , VexRm_Lx , E(660F00,7B,_,x,_,1,4,FV ), 0 , 135, 0 , 3915 , 239, 133), // #861 - INST(Vcvtpd2udq , VexRm_Lx_Narrow , E(000F00,79,_,x,_,1,4,FV ), 0 , 136, 0 , 3925 , 240, 131), // #862 - INST(Vcvtpd2uqq , VexRm_Lx , E(660F00,79,_,x,_,1,4,FV ), 0 , 135, 0 , 3936 , 239, 133), // #863 - INST(Vcvtph2dq , VexRm_Lx , E(66MAP5,5B,_,_,_,0,3,HV ), 0 , 137, 0 , 3947 , 241, 125), // #864 - INST(Vcvtph2pd , VexRm_Lx , E(00MAP5,5A,_,_,_,0,2,QV ), 0 , 138, 0 , 3957 , 242, 125), // #865 - INST(Vcvtph2ps , VexRm_Lx , V(660F38,13,_,x,0,0,3,HVM), 0 , 139, 0 , 3967 , 243, 138), // #866 - INST(Vcvtph2psx , VexRm_Lx , E(66MAP6,13,_,_,_,0,3,HV ), 0 , 140, 0 , 3977 , 244, 125), // #867 - INST(Vcvtph2qq , VexRm_Lx , E(66MAP5,7B,_,_,_,0,2,QV ), 0 , 141, 0 , 3988 , 245, 125), // #868 - INST(Vcvtph2udq , VexRm_Lx , E(00MAP5,79,_,_,_,0,3,HV ), 0 , 142, 0 , 3998 , 241, 125), // #869 - INST(Vcvtph2uqq , VexRm_Lx , E(66MAP5,79,_,_,_,0,2,QV ), 0 , 141, 0 , 4009 , 245, 125), // #870 - INST(Vcvtph2uw , VexRm_Lx , E(00MAP5,7D,_,_,_,0,4,FV ), 0 , 104, 0 , 4020 , 246, 125), // #871 - INST(Vcvtph2w , VexRm_Lx , E(66MAP5,7D,_,_,_,0,4,FV ), 0 , 143, 0 , 4030 , 246, 125), // #872 - INST(Vcvtps2dq , VexRm_Lx , V(660F00,5B,_,x,I,0,4,FV ), 0 , 144, 0 , 4039 , 235, 124), // #873 - INST(Vcvtps2pd , VexRm_Lx , V(000F00,5A,_,x,I,0,3,HV ), 0 , 145, 0 , 4049 , 247, 124), // #874 - INST(Vcvtps2ph , VexMri_Lx , V(660F3A,1D,_,x,0,0,3,HVM), 0 , 146, 0 , 4059 , 248, 138), // #875 - INST(Vcvtps2phx , VexRm_Lx , E(66MAP5,1D,_,_,_,0,4,FV ), 0 , 143, 0 , 4069 , 234, 125), // #876 - INST(Vcvtps2qq , VexRm_Lx , E(660F00,7B,_,x,_,0,3,HV ), 0 , 147, 0 , 4080 , 249, 133), // #877 - INST(Vcvtps2udq , VexRm_Lx , E(000F00,79,_,x,_,0,4,FV ), 0 , 148, 0 , 4090 , 250, 131), // #878 - INST(Vcvtps2uqq , VexRm_Lx , E(660F00,79,_,x,_,0,3,HV ), 0 , 147, 0 , 4101 , 249, 133), // #879 - INST(Vcvtqq2pd , VexRm_Lx , E(F30F00,E6,_,x,_,1,4,FV ), 0 , 149, 0 , 4112 , 239, 133), // #880 - INST(Vcvtqq2ph , VexRm_Lx , E(00MAP5,5B,_,_,_,1,4,FV ), 0 , 150, 0 , 4122 , 238, 125), // #881 - INST(Vcvtqq2ps , VexRm_Lx_Narrow , E(000F00,5B,_,x,_,1,4,FV ), 0 , 136, 0 , 4132 , 240, 133), // #882 - INST(Vcvtsd2sh , VexRvm , E(F2MAP5,5A,_,_,_,1,3,T1S), 0 , 151, 0 , 4142 , 251, 127), // #883 - INST(Vcvtsd2si , VexRm_Wx , V(F20F00,2D,_,I,x,x,3,T1F), 0 , 152, 0 , 4152 , 252, 126), // #884 - INST(Vcvtsd2ss , VexRvm , V(F20F00,5A,_,I,I,1,3,T1S), 0 , 106, 0 , 4162 , 199, 126), // #885 - INST(Vcvtsd2usi , VexRm_Wx , E(F20F00,79,_,I,_,x,3,T1F), 0 , 153, 0 , 4172 , 253, 68 ), // #886 - INST(Vcvtsh2sd , VexRvm , E(F3MAP5,5A,_,_,_,0,1,T1S), 0 , 107, 0 , 4183 , 254, 127), // #887 - INST(Vcvtsh2si , VexRm_Wx , E(F3MAP5,2D,_,_,_,x,1,T1S), 0 , 107, 0 , 4193 , 255, 127), // #888 - INST(Vcvtsh2ss , VexRvm , E(00MAP6,13,_,_,_,0,1,T1S), 0 , 154, 0 , 4203 , 254, 127), // #889 - INST(Vcvtsh2usi , VexRm_Wx , E(F3MAP5,79,_,_,_,x,1,T1S), 0 , 107, 0 , 4213 , 255, 127), // #890 - INST(Vcvtsi2sd , VexRvm_Wx , V(F20F00,2A,_,I,x,x,2,T1W), 0 , 155, 0 , 4224 , 256, 126), // #891 - INST(Vcvtsi2sh , VexRvm_Wx , E(F3MAP5,2A,_,_,_,x,2,T1W), 0 , 156, 0 , 4234 , 257, 127), // #892 - INST(Vcvtsi2ss , VexRvm_Wx , V(F30F00,2A,_,I,x,x,2,T1W), 0 , 157, 0 , 4244 , 256, 126), // #893 - INST(Vcvtss2sd , VexRvm , V(F30F00,5A,_,I,I,0,2,T1S), 0 , 108, 0 , 4254 , 258, 126), // #894 - INST(Vcvtss2sh , VexRvm , E(00MAP5,1D,_,_,_,0,2,T1S), 0 , 158, 0 , 4264 , 259, 127), // #895 - INST(Vcvtss2si , VexRm_Wx , V(F30F00,2D,_,I,x,x,2,T1F), 0 , 108, 0 , 4274 , 260, 126), // #896 - INST(Vcvtss2usi , VexRm_Wx , E(F30F00,79,_,I,_,x,2,T1F), 0 , 159, 0 , 4284 , 261, 68 ), // #897 - INST(Vcvttpd2dq , VexRm_Lx_Narrow , V(660F00,E6,_,x,I,1,4,FV ), 0 , 103, 0 , 4295 , 262, 124), // #898 - INST(Vcvttpd2qq , VexRm_Lx , E(660F00,7A,_,x,_,1,4,FV ), 0 , 135, 0 , 4306 , 263, 131), // #899 - INST(Vcvttpd2udq , VexRm_Lx_Narrow , E(000F00,78,_,x,_,1,4,FV ), 0 , 136, 0 , 4317 , 264, 131), // #900 - INST(Vcvttpd2uqq , VexRm_Lx , E(660F00,78,_,x,_,1,4,FV ), 0 , 135, 0 , 4329 , 263, 133), // #901 - INST(Vcvttph2dq , VexRm_Lx , E(F3MAP5,5B,_,_,_,0,3,HV ), 0 , 160, 0 , 4341 , 244, 125), // #902 - INST(Vcvttph2qq , VexRm_Lx , E(66MAP5,7A,_,_,_,0,2,QV ), 0 , 141, 0 , 4352 , 242, 125), // #903 - INST(Vcvttph2udq , VexRm_Lx , E(00MAP5,78,_,_,_,0,3,HV ), 0 , 142, 0 , 4363 , 244, 125), // #904 - INST(Vcvttph2uqq , VexRm_Lx , E(66MAP5,78,_,_,_,0,2,QV ), 0 , 141, 0 , 4375 , 242, 125), // #905 - INST(Vcvttph2uw , VexRm_Lx , E(00MAP5,7C,_,_,_,0,4,FV ), 0 , 104, 0 , 4387 , 265, 125), // #906 - INST(Vcvttph2w , VexRm_Lx , E(66MAP5,7C,_,_,_,0,4,FV ), 0 , 143, 0 , 4398 , 265, 125), // #907 - INST(Vcvttps2dq , VexRm_Lx , V(F30F00,5B,_,x,I,0,4,FV ), 0 , 161, 0 , 4408 , 266, 124), // #908 - INST(Vcvttps2qq , VexRm_Lx , E(660F00,7A,_,x,_,0,3,HV ), 0 , 147, 0 , 4419 , 267, 133), // #909 - INST(Vcvttps2udq , VexRm_Lx , E(000F00,78,_,x,_,0,4,FV ), 0 , 148, 0 , 4430 , 268, 131), // #910 - INST(Vcvttps2uqq , VexRm_Lx , E(660F00,78,_,x,_,0,3,HV ), 0 , 147, 0 , 4442 , 267, 133), // #911 - INST(Vcvttsd2si , VexRm_Wx , V(F20F00,2C,_,I,x,x,3,T1F), 0 , 152, 0 , 4454 , 269, 126), // #912 - INST(Vcvttsd2usi , VexRm_Wx , E(F20F00,78,_,I,_,x,3,T1F), 0 , 153, 0 , 4465 , 270, 68 ), // #913 - INST(Vcvttsh2si , VexRm_Wx , E(F3MAP5,2C,_,_,_,x,1,T1S), 0 , 107, 0 , 4477 , 271, 127), // #914 - INST(Vcvttsh2usi , VexRm_Wx , E(F3MAP5,78,_,_,_,x,1,T1S), 0 , 107, 0 , 4488 , 271, 127), // #915 - INST(Vcvttss2si , VexRm_Wx , V(F30F00,2C,_,I,x,x,2,T1F), 0 , 108, 0 , 4500 , 272, 126), // #916 - INST(Vcvttss2usi , VexRm_Wx , E(F30F00,78,_,I,_,x,2,T1F), 0 , 159, 0 , 4511 , 273, 68 ), // #917 - INST(Vcvtudq2pd , VexRm_Lx , E(F30F00,7A,_,x,_,0,3,HV ), 0 , 162, 0 , 4523 , 274, 131), // #918 - INST(Vcvtudq2ph , VexRm_Lx , E(F2MAP5,7A,_,_,_,0,4,FV ), 0 , 163, 0 , 4534 , 234, 125), // #919 - INST(Vcvtudq2ps , VexRm_Lx , E(F20F00,7A,_,x,_,0,4,FV ), 0 , 164, 0 , 4545 , 250, 131), // #920 - INST(Vcvtuqq2pd , VexRm_Lx , E(F30F00,7A,_,x,_,1,4,FV ), 0 , 149, 0 , 4556 , 239, 133), // #921 - INST(Vcvtuqq2ph , VexRm_Lx , E(F2MAP5,7A,_,_,_,1,4,FV ), 0 , 165, 0 , 4567 , 238, 125), // #922 - INST(Vcvtuqq2ps , VexRm_Lx_Narrow , E(F20F00,7A,_,x,_,1,4,FV ), 0 , 166, 0 , 4578 , 240, 133), // #923 - INST(Vcvtusi2sd , VexRvm_Wx , E(F20F00,7B,_,I,_,x,2,T1W), 0 , 167, 0 , 4589 , 257, 68 ), // #924 - INST(Vcvtusi2sh , VexRvm_Wx , E(F3MAP5,7B,_,_,_,x,2,T1W), 0 , 156, 0 , 4600 , 257, 127), // #925 - INST(Vcvtusi2ss , VexRvm_Wx , E(F30F00,7B,_,I,_,x,2,T1W), 0 , 168, 0 , 4611 , 257, 68 ), // #926 - INST(Vcvtuw2ph , VexRm_Lx , E(F2MAP5,7D,_,_,_,0,4,FV ), 0 , 163, 0 , 4622 , 246, 125), // #927 - INST(Vcvtw2ph , VexRm_Lx , E(F3MAP5,7D,_,_,_,0,4,FV ), 0 , 169, 0 , 4632 , 246, 125), // #928 - INST(Vdbpsadbw , VexRvmi_Lx , E(660F3A,42,_,x,_,0,4,FVM), 0 , 111, 0 , 4641 , 275, 139), // #929 - INST(Vdivpd , VexRvm_Lx , V(660F00,5E,_,x,I,1,4,FV ), 0 , 103, 0 , 4651 , 196, 124), // #930 - INST(Vdivph , VexRvm_Lx , E(00MAP5,5E,_,_,_,0,4,FV ), 0 , 104, 0 , 4658 , 197, 125), // #931 - INST(Vdivps , VexRvm_Lx , V(000F00,5E,_,x,I,0,4,FV ), 0 , 105, 0 , 4665 , 198, 124), // #932 - INST(Vdivsd , VexRvm , V(F20F00,5E,_,I,I,1,3,T1S), 0 , 106, 0 , 4672 , 199, 126), // #933 - INST(Vdivsh , VexRvm , E(F3MAP5,5E,_,_,_,0,1,T1S), 0 , 107, 0 , 4679 , 200, 127), // #934 - INST(Vdivss , VexRvm , V(F30F00,5E,_,I,I,0,2,T1S), 0 , 108, 0 , 4686 , 201, 126), // #935 - INST(Vdpbf16ps , VexRvm_Lx , E(F30F38,52,_,_,_,0,4,FV ), 0 , 132, 0 , 4693 , 213, 137), // #936 - INST(Vdppd , VexRvmi_Lx , V(660F3A,41,_,x,I,_,_,_ ), 0 , 73 , 0 , 4703 , 276, 128), // #937 - INST(Vdpps , VexRvmi_Lx , V(660F3A,40,_,x,I,_,_,_ ), 0 , 73 , 0 , 4709 , 214, 128), // #938 - INST(Verr , X86M_NoSize , O(000F00,00,4,_,_,_,_,_ ), 0 , 97 , 0 , 4715 , 107, 10 ), // #939 - INST(Verw , X86M_NoSize , O(000F00,00,5,_,_,_,_,_ ), 0 , 77 , 0 , 4720 , 107, 10 ), // #940 - INST(Vexp2pd , VexRm , E(660F38,C8,_,2,_,1,4,FV ), 0 , 170, 0 , 4725 , 277, 140), // #941 - INST(Vexp2ps , VexRm , E(660F38,C8,_,2,_,0,4,FV ), 0 , 171, 0 , 4733 , 278, 140), // #942 - INST(Vexpandpd , VexRm_Lx , E(660F38,88,_,x,_,1,3,T1S), 0 , 128, 0 , 4741 , 279, 131), // #943 - INST(Vexpandps , VexRm_Lx , E(660F38,88,_,x,_,0,2,T1S), 0 , 129, 0 , 4751 , 279, 131), // #944 - INST(Vextractf128 , VexMri , V(660F3A,19,_,1,0,_,_,_ ), 0 , 172, 0 , 4761 , 280, 128), // #945 - INST(Vextractf32x4 , VexMri_Lx , E(660F3A,19,_,x,_,0,4,T4 ), 0 , 173, 0 , 4774 , 281, 131), // #946 - INST(Vextractf32x8 , VexMri , E(660F3A,1B,_,2,_,0,5,T8 ), 0 , 174, 0 , 4788 , 282, 66 ), // #947 - INST(Vextractf64x2 , VexMri_Lx , E(660F3A,19,_,x,_,1,4,T2 ), 0 , 175, 0 , 4802 , 281, 133), // #948 - INST(Vextractf64x4 , VexMri , E(660F3A,1B,_,2,_,1,5,T4 ), 0 , 176, 0 , 4816 , 282, 68 ), // #949 - INST(Vextracti128 , VexMri , V(660F3A,39,_,1,0,_,_,_ ), 0 , 172, 0 , 4830 , 280, 134), // #950 - INST(Vextracti32x4 , VexMri_Lx , E(660F3A,39,_,x,_,0,4,T4 ), 0 , 173, 0 , 4843 , 281, 131), // #951 - INST(Vextracti32x8 , VexMri , E(660F3A,3B,_,2,_,0,5,T8 ), 0 , 174, 0 , 4857 , 282, 66 ), // #952 - INST(Vextracti64x2 , VexMri_Lx , E(660F3A,39,_,x,_,1,4,T2 ), 0 , 175, 0 , 4871 , 281, 133), // #953 - INST(Vextracti64x4 , VexMri , E(660F3A,3B,_,2,_,1,5,T4 ), 0 , 176, 0 , 4885 , 282, 68 ), // #954 - INST(Vextractps , VexMri , V(660F3A,17,_,0,I,I,2,T1S), 0 , 177, 0 , 4899 , 283, 126), // #955 - INST(Vfcmaddcph , VexRvm_Lx , E(F2MAP6,56,_,_,_,0,4,FV ), 0 , 178, 0 , 4910 , 284, 125), // #956 - INST(Vfcmaddcsh , VexRvm , E(F2MAP6,57,_,_,_,0,2,T1S), 0 , 179, 0 , 4921 , 259, 125), // #957 - INST(Vfcmulcph , VexRvm_Lx , E(F2MAP6,D6,_,_,_,0,4,FV ), 0 , 178, 0 , 4932 , 284, 125), // #958 - INST(Vfcmulcsh , VexRvm , E(F2MAP6,D7,_,_,_,0,2,T1S), 0 , 179, 0 , 4942 , 259, 125), // #959 - INST(Vfixupimmpd , VexRvmi_Lx , E(660F3A,54,_,x,_,1,4,FV ), 0 , 112, 0 , 4952 , 285, 131), // #960 - INST(Vfixupimmps , VexRvmi_Lx , E(660F3A,54,_,x,_,0,4,FV ), 0 , 111, 0 , 4964 , 286, 131), // #961 - INST(Vfixupimmsd , VexRvmi , E(660F3A,55,_,I,_,1,3,T1S), 0 , 180, 0 , 4976 , 287, 68 ), // #962 - INST(Vfixupimmss , VexRvmi , E(660F3A,55,_,I,_,0,2,T1S), 0 , 181, 0 , 4988 , 288, 68 ), // #963 - INST(Vfmadd132pd , VexRvm_Lx , V(660F38,98,_,x,1,1,4,FV ), 0 , 182, 0 , 5000 , 196, 141), // #964 - INST(Vfmadd132ph , VexRvm_Lx , E(66MAP6,98,_,_,_,0,4,FV ), 0 , 183, 0 , 5012 , 197, 125), // #965 - INST(Vfmadd132ps , VexRvm_Lx , V(660F38,98,_,x,0,0,4,FV ), 0 , 110, 0 , 5024 , 198, 141), // #966 - INST(Vfmadd132sd , VexRvm , V(660F38,99,_,I,1,1,3,T1S), 0 , 184, 0 , 5036 , 199, 142), // #967 - INST(Vfmadd132sh , VexRvm , E(66MAP6,99,_,_,_,0,1,T1S), 0 , 185, 0 , 5048 , 200, 127), // #968 - INST(Vfmadd132ss , VexRvm , V(660F38,99,_,I,0,0,2,T1S), 0 , 122, 0 , 5060 , 201, 142), // #969 - INST(Vfmadd213pd , VexRvm_Lx , V(660F38,A8,_,x,1,1,4,FV ), 0 , 182, 0 , 5072 , 196, 141), // #970 - INST(Vfmadd213ph , VexRvm_Lx , E(66MAP6,A8,_,_,_,0,4,FV ), 0 , 183, 0 , 5084 , 197, 125), // #971 - INST(Vfmadd213ps , VexRvm_Lx , V(660F38,A8,_,x,0,0,4,FV ), 0 , 110, 0 , 5096 , 198, 141), // #972 - INST(Vfmadd213sd , VexRvm , V(660F38,A9,_,I,1,1,3,T1S), 0 , 184, 0 , 5108 , 199, 142), // #973 - INST(Vfmadd213sh , VexRvm , E(66MAP6,A9,_,_,_,0,1,T1S), 0 , 185, 0 , 5120 , 200, 127), // #974 - INST(Vfmadd213ss , VexRvm , V(660F38,A9,_,I,0,0,2,T1S), 0 , 122, 0 , 5132 , 201, 142), // #975 - INST(Vfmadd231pd , VexRvm_Lx , V(660F38,B8,_,x,1,1,4,FV ), 0 , 182, 0 , 5144 , 196, 141), // #976 - INST(Vfmadd231ph , VexRvm_Lx , E(66MAP6,B8,_,_,_,0,4,FV ), 0 , 183, 0 , 5156 , 197, 125), // #977 - INST(Vfmadd231ps , VexRvm_Lx , V(660F38,B8,_,x,0,0,4,FV ), 0 , 110, 0 , 5168 , 198, 141), // #978 - INST(Vfmadd231sd , VexRvm , V(660F38,B9,_,I,1,1,3,T1S), 0 , 184, 0 , 5180 , 199, 142), // #979 - INST(Vfmadd231sh , VexRvm , E(66MAP6,B9,_,_,_,0,1,T1S), 0 , 185, 0 , 5192 , 200, 127), // #980 - INST(Vfmadd231ss , VexRvm , V(660F38,B9,_,I,0,0,2,T1S), 0 , 122, 0 , 5204 , 201, 142), // #981 - INST(Vfmaddcph , VexRvm_Lx , E(F3MAP6,56,_,_,_,0,4,FV ), 0 , 186, 0 , 5216 , 284, 125), // #982 - INST(Vfmaddcsh , VexRvm , E(F3MAP6,57,_,_,_,0,2,T1S), 0 , 187, 0 , 5226 , 259, 125), // #983 - INST(Vfmaddpd , Fma4_Lx , V(660F3A,69,_,x,x,_,_,_ ), 0 , 73 , 0 , 5236 , 289, 143), // #984 - INST(Vfmaddps , Fma4_Lx , V(660F3A,68,_,x,x,_,_,_ ), 0 , 73 , 0 , 5245 , 289, 143), // #985 - INST(Vfmaddsd , Fma4 , V(660F3A,6B,_,0,x,_,_,_ ), 0 , 73 , 0 , 5254 , 290, 143), // #986 - INST(Vfmaddss , Fma4 , V(660F3A,6A,_,0,x,_,_,_ ), 0 , 73 , 0 , 5263 , 291, 143), // #987 - INST(Vfmaddsub132pd , VexRvm_Lx , V(660F38,96,_,x,1,1,4,FV ), 0 , 182, 0 , 5272 , 196, 141), // #988 - INST(Vfmaddsub132ph , VexRvm_Lx , E(66MAP6,96,_,_,_,0,4,FV ), 0 , 183, 0 , 5287 , 197, 125), // #989 - INST(Vfmaddsub132ps , VexRvm_Lx , V(660F38,96,_,x,0,0,4,FV ), 0 , 110, 0 , 5302 , 198, 141), // #990 - INST(Vfmaddsub213pd , VexRvm_Lx , V(660F38,A6,_,x,1,1,4,FV ), 0 , 182, 0 , 5317 , 196, 141), // #991 - INST(Vfmaddsub213ph , VexRvm_Lx , E(66MAP6,A6,_,_,_,0,4,FV ), 0 , 183, 0 , 5332 , 197, 125), // #992 - INST(Vfmaddsub213ps , VexRvm_Lx , V(660F38,A6,_,x,0,0,4,FV ), 0 , 110, 0 , 5347 , 198, 141), // #993 - INST(Vfmaddsub231pd , VexRvm_Lx , V(660F38,B6,_,x,1,1,4,FV ), 0 , 182, 0 , 5362 , 196, 141), // #994 - INST(Vfmaddsub231ph , VexRvm_Lx , E(66MAP6,B6,_,_,_,0,4,FV ), 0 , 183, 0 , 5377 , 197, 125), // #995 - INST(Vfmaddsub231ps , VexRvm_Lx , V(660F38,B6,_,x,0,0,4,FV ), 0 , 110, 0 , 5392 , 198, 141), // #996 - INST(Vfmaddsubpd , Fma4_Lx , V(660F3A,5D,_,x,x,_,_,_ ), 0 , 73 , 0 , 5407 , 289, 143), // #997 - INST(Vfmaddsubps , Fma4_Lx , V(660F3A,5C,_,x,x,_,_,_ ), 0 , 73 , 0 , 5419 , 289, 143), // #998 - INST(Vfmsub132pd , VexRvm_Lx , V(660F38,9A,_,x,1,1,4,FV ), 0 , 182, 0 , 5431 , 196, 141), // #999 - INST(Vfmsub132ph , VexRvm_Lx , E(66MAP6,9A,_,_,_,0,4,FV ), 0 , 183, 0 , 5443 , 197, 125), // #1000 - INST(Vfmsub132ps , VexRvm_Lx , V(660F38,9A,_,x,0,0,4,FV ), 0 , 110, 0 , 5455 , 198, 141), // #1001 - INST(Vfmsub132sd , VexRvm , V(660F38,9B,_,I,1,1,3,T1S), 0 , 184, 0 , 5467 , 199, 142), // #1002 - INST(Vfmsub132sh , VexRvm , E(66MAP6,9B,_,_,_,0,1,T1S), 0 , 185, 0 , 5479 , 200, 127), // #1003 - INST(Vfmsub132ss , VexRvm , V(660F38,9B,_,I,0,0,2,T1S), 0 , 122, 0 , 5491 , 201, 142), // #1004 - INST(Vfmsub213pd , VexRvm_Lx , V(660F38,AA,_,x,1,1,4,FV ), 0 , 182, 0 , 5503 , 196, 141), // #1005 - INST(Vfmsub213ph , VexRvm_Lx , E(66MAP6,AA,_,_,_,0,4,FV ), 0 , 183, 0 , 5515 , 197, 125), // #1006 - INST(Vfmsub213ps , VexRvm_Lx , V(660F38,AA,_,x,0,0,4,FV ), 0 , 110, 0 , 5527 , 198, 141), // #1007 - INST(Vfmsub213sd , VexRvm , V(660F38,AB,_,I,1,1,3,T1S), 0 , 184, 0 , 5539 , 199, 142), // #1008 - INST(Vfmsub213sh , VexRvm , E(66MAP6,AB,_,_,_,0,1,T1S), 0 , 185, 0 , 5551 , 200, 127), // #1009 - INST(Vfmsub213ss , VexRvm , V(660F38,AB,_,I,0,0,2,T1S), 0 , 122, 0 , 5563 , 201, 142), // #1010 - INST(Vfmsub231pd , VexRvm_Lx , V(660F38,BA,_,x,1,1,4,FV ), 0 , 182, 0 , 5575 , 196, 141), // #1011 - INST(Vfmsub231ph , VexRvm_Lx , E(66MAP6,BA,_,_,_,0,4,FV ), 0 , 183, 0 , 5587 , 197, 125), // #1012 - INST(Vfmsub231ps , VexRvm_Lx , V(660F38,BA,_,x,0,0,4,FV ), 0 , 110, 0 , 5599 , 198, 141), // #1013 - INST(Vfmsub231sd , VexRvm , V(660F38,BB,_,I,1,1,3,T1S), 0 , 184, 0 , 5611 , 199, 142), // #1014 - INST(Vfmsub231sh , VexRvm , E(66MAP6,BB,_,_,_,0,1,T1S), 0 , 185, 0 , 5623 , 200, 127), // #1015 - INST(Vfmsub231ss , VexRvm , V(660F38,BB,_,I,0,0,2,T1S), 0 , 122, 0 , 5635 , 201, 142), // #1016 - INST(Vfmsubadd132pd , VexRvm_Lx , V(660F38,97,_,x,1,1,4,FV ), 0 , 182, 0 , 5647 , 196, 141), // #1017 - INST(Vfmsubadd132ph , VexRvm_Lx , E(66MAP6,97,_,_,_,0,4,FV ), 0 , 183, 0 , 5662 , 197, 125), // #1018 - INST(Vfmsubadd132ps , VexRvm_Lx , V(660F38,97,_,x,0,0,4,FV ), 0 , 110, 0 , 5677 , 198, 141), // #1019 - INST(Vfmsubadd213pd , VexRvm_Lx , V(660F38,A7,_,x,1,1,4,FV ), 0 , 182, 0 , 5692 , 196, 141), // #1020 - INST(Vfmsubadd213ph , VexRvm_Lx , E(66MAP6,A7,_,_,_,0,4,FV ), 0 , 183, 0 , 5707 , 197, 125), // #1021 - INST(Vfmsubadd213ps , VexRvm_Lx , V(660F38,A7,_,x,0,0,4,FV ), 0 , 110, 0 , 5722 , 198, 141), // #1022 - INST(Vfmsubadd231pd , VexRvm_Lx , V(660F38,B7,_,x,1,1,4,FV ), 0 , 182, 0 , 5737 , 196, 141), // #1023 - INST(Vfmsubadd231ph , VexRvm_Lx , E(66MAP6,B7,_,_,_,0,4,FV ), 0 , 183, 0 , 5752 , 197, 125), // #1024 - INST(Vfmsubadd231ps , VexRvm_Lx , V(660F38,B7,_,x,0,0,4,FV ), 0 , 110, 0 , 5767 , 198, 141), // #1025 - INST(Vfmsubaddpd , Fma4_Lx , V(660F3A,5F,_,x,x,_,_,_ ), 0 , 73 , 0 , 5782 , 289, 143), // #1026 - INST(Vfmsubaddps , Fma4_Lx , V(660F3A,5E,_,x,x,_,_,_ ), 0 , 73 , 0 , 5794 , 289, 143), // #1027 - INST(Vfmsubpd , Fma4_Lx , V(660F3A,6D,_,x,x,_,_,_ ), 0 , 73 , 0 , 5806 , 289, 143), // #1028 - INST(Vfmsubps , Fma4_Lx , V(660F3A,6C,_,x,x,_,_,_ ), 0 , 73 , 0 , 5815 , 289, 143), // #1029 - INST(Vfmsubsd , Fma4 , V(660F3A,6F,_,0,x,_,_,_ ), 0 , 73 , 0 , 5824 , 290, 143), // #1030 - INST(Vfmsubss , Fma4 , V(660F3A,6E,_,0,x,_,_,_ ), 0 , 73 , 0 , 5833 , 291, 143), // #1031 - INST(Vfmulcph , VexRvm_Lx , E(F3MAP6,D6,_,_,_,0,4,FV ), 0 , 186, 0 , 5842 , 284, 125), // #1032 - INST(Vfmulcsh , VexRvm , E(F3MAP6,D7,_,_,_,0,2,T1S), 0 , 187, 0 , 5851 , 259, 125), // #1033 - INST(Vfnmadd132pd , VexRvm_Lx , V(660F38,9C,_,x,1,1,4,FV ), 0 , 182, 0 , 5860 , 196, 141), // #1034 - INST(Vfnmadd132ph , VexRvm_Lx , E(66MAP6,9C,_,_,_,0,4,FV ), 0 , 183, 0 , 5873 , 197, 125), // #1035 - INST(Vfnmadd132ps , VexRvm_Lx , V(660F38,9C,_,x,0,0,4,FV ), 0 , 110, 0 , 5886 , 198, 141), // #1036 - INST(Vfnmadd132sd , VexRvm , V(660F38,9D,_,I,1,1,3,T1S), 0 , 184, 0 , 5899 , 199, 142), // #1037 - INST(Vfnmadd132sh , VexRvm , E(66MAP6,9D,_,_,_,0,1,T1S), 0 , 185, 0 , 5912 , 200, 127), // #1038 - INST(Vfnmadd132ss , VexRvm , V(660F38,9D,_,I,0,0,2,T1S), 0 , 122, 0 , 5925 , 201, 142), // #1039 - INST(Vfnmadd213pd , VexRvm_Lx , V(660F38,AC,_,x,1,1,4,FV ), 0 , 182, 0 , 5938 , 196, 141), // #1040 - INST(Vfnmadd213ph , VexRvm_Lx , E(66MAP6,AC,_,_,_,0,4,FV ), 0 , 183, 0 , 5951 , 197, 125), // #1041 - INST(Vfnmadd213ps , VexRvm_Lx , V(660F38,AC,_,x,0,0,4,FV ), 0 , 110, 0 , 5964 , 198, 141), // #1042 - INST(Vfnmadd213sd , VexRvm , V(660F38,AD,_,I,1,1,3,T1S), 0 , 184, 0 , 5977 , 199, 142), // #1043 - INST(Vfnmadd213sh , VexRvm , E(66MAP6,AD,_,_,_,0,1,T1S), 0 , 185, 0 , 5990 , 200, 127), // #1044 - INST(Vfnmadd213ss , VexRvm , V(660F38,AD,_,I,0,0,2,T1S), 0 , 122, 0 , 6003 , 201, 142), // #1045 - INST(Vfnmadd231pd , VexRvm_Lx , V(660F38,BC,_,x,1,1,4,FV ), 0 , 182, 0 , 6016 , 196, 141), // #1046 - INST(Vfnmadd231ph , VexRvm_Lx , E(66MAP6,BC,_,_,_,0,4,FV ), 0 , 183, 0 , 6029 , 197, 125), // #1047 - INST(Vfnmadd231ps , VexRvm_Lx , V(660F38,BC,_,x,0,0,4,FV ), 0 , 110, 0 , 6042 , 198, 141), // #1048 - INST(Vfnmadd231sd , VexRvm , V(660F38,BD,_,I,1,1,3,T1S), 0 , 184, 0 , 6055 , 199, 142), // #1049 - INST(Vfnmadd231sh , VexRvm , E(66MAP6,BD,_,_,_,0,1,T1S), 0 , 185, 0 , 6068 , 200, 127), // #1050 - INST(Vfnmadd231ss , VexRvm , V(660F38,BD,_,I,0,0,2,T1S), 0 , 122, 0 , 6081 , 201, 142), // #1051 - INST(Vfnmaddpd , Fma4_Lx , V(660F3A,79,_,x,x,_,_,_ ), 0 , 73 , 0 , 6094 , 289, 143), // #1052 - INST(Vfnmaddps , Fma4_Lx , V(660F3A,78,_,x,x,_,_,_ ), 0 , 73 , 0 , 6104 , 289, 143), // #1053 - INST(Vfnmaddsd , Fma4 , V(660F3A,7B,_,0,x,_,_,_ ), 0 , 73 , 0 , 6114 , 290, 143), // #1054 - INST(Vfnmaddss , Fma4 , V(660F3A,7A,_,0,x,_,_,_ ), 0 , 73 , 0 , 6124 , 291, 143), // #1055 - INST(Vfnmsub132pd , VexRvm_Lx , V(660F38,9E,_,x,1,1,4,FV ), 0 , 182, 0 , 6134 , 196, 141), // #1056 - INST(Vfnmsub132ph , VexRvm_Lx , E(66MAP6,9E,_,_,_,0,4,FV ), 0 , 183, 0 , 6147 , 197, 125), // #1057 - INST(Vfnmsub132ps , VexRvm_Lx , V(660F38,9E,_,x,0,0,4,FV ), 0 , 110, 0 , 6160 , 198, 141), // #1058 - INST(Vfnmsub132sd , VexRvm , V(660F38,9F,_,I,1,1,3,T1S), 0 , 184, 0 , 6173 , 199, 142), // #1059 - INST(Vfnmsub132sh , VexRvm , E(66MAP6,9F,_,_,_,0,1,T1S), 0 , 185, 0 , 6186 , 200, 127), // #1060 - INST(Vfnmsub132ss , VexRvm , V(660F38,9F,_,I,0,0,2,T1S), 0 , 122, 0 , 6199 , 201, 142), // #1061 - INST(Vfnmsub213pd , VexRvm_Lx , V(660F38,AE,_,x,1,1,4,FV ), 0 , 182, 0 , 6212 , 196, 141), // #1062 - INST(Vfnmsub213ph , VexRvm_Lx , E(66MAP6,AE,_,_,_,0,4,FV ), 0 , 183, 0 , 6225 , 197, 125), // #1063 - INST(Vfnmsub213ps , VexRvm_Lx , V(660F38,AE,_,x,0,0,4,FV ), 0 , 110, 0 , 6238 , 198, 141), // #1064 - INST(Vfnmsub213sd , VexRvm , V(660F38,AF,_,I,1,1,3,T1S), 0 , 184, 0 , 6251 , 199, 142), // #1065 - INST(Vfnmsub213sh , VexRvm , E(66MAP6,AF,_,_,_,0,1,T1S), 0 , 185, 0 , 6264 , 200, 127), // #1066 - INST(Vfnmsub213ss , VexRvm , V(660F38,AF,_,I,0,0,2,T1S), 0 , 122, 0 , 6277 , 201, 142), // #1067 - INST(Vfnmsub231pd , VexRvm_Lx , V(660F38,BE,_,x,1,1,4,FV ), 0 , 182, 0 , 6290 , 196, 141), // #1068 - INST(Vfnmsub231ph , VexRvm_Lx , E(66MAP6,BE,_,_,_,0,4,FV ), 0 , 183, 0 , 6303 , 197, 125), // #1069 - INST(Vfnmsub231ps , VexRvm_Lx , V(660F38,BE,_,x,0,0,4,FV ), 0 , 110, 0 , 6316 , 198, 141), // #1070 - INST(Vfnmsub231sd , VexRvm , V(660F38,BF,_,I,1,1,3,T1S), 0 , 184, 0 , 6329 , 199, 142), // #1071 - INST(Vfnmsub231sh , VexRvm , E(66MAP6,BF,_,_,_,0,1,T1S), 0 , 185, 0 , 6342 , 200, 127), // #1072 - INST(Vfnmsub231ss , VexRvm , V(660F38,BF,_,I,0,0,2,T1S), 0 , 122, 0 , 6355 , 201, 142), // #1073 - INST(Vfnmsubpd , Fma4_Lx , V(660F3A,7D,_,x,x,_,_,_ ), 0 , 73 , 0 , 6368 , 289, 143), // #1074 - INST(Vfnmsubps , Fma4_Lx , V(660F3A,7C,_,x,x,_,_,_ ), 0 , 73 , 0 , 6378 , 289, 143), // #1075 - INST(Vfnmsubsd , Fma4 , V(660F3A,7F,_,0,x,_,_,_ ), 0 , 73 , 0 , 6388 , 290, 143), // #1076 - INST(Vfnmsubss , Fma4 , V(660F3A,7E,_,0,x,_,_,_ ), 0 , 73 , 0 , 6398 , 291, 143), // #1077 - INST(Vfpclasspd , VexRmi_Lx , E(660F3A,66,_,x,_,1,4,FV ), 0 , 112, 0 , 6408 , 292, 133), // #1078 - INST(Vfpclassph , VexRmi_Lx , E(000F3A,66,_,_,_,0,4,FV ), 0 , 123, 0 , 6419 , 293, 125), // #1079 - INST(Vfpclassps , VexRmi_Lx , E(660F3A,66,_,x,_,0,4,FV ), 0 , 111, 0 , 6430 , 294, 133), // #1080 - INST(Vfpclasssd , VexRmi , E(660F3A,67,_,I,_,1,3,T1S), 0 , 180, 0 , 6441 , 295, 66 ), // #1081 - INST(Vfpclasssh , VexRmi , E(000F3A,67,_,_,_,0,1,T1S), 0 , 188, 0 , 6452 , 296, 127), // #1082 - INST(Vfpclassss , VexRmi , E(660F3A,67,_,I,_,0,2,T1S), 0 , 181, 0 , 6463 , 297, 66 ), // #1083 - INST(Vfrczpd , VexRm_Lx , V(XOP_M9,81,_,x,0,_,_,_ ), 0 , 79 , 0 , 6474 , 298, 144), // #1084 - INST(Vfrczps , VexRm_Lx , V(XOP_M9,80,_,x,0,_,_,_ ), 0 , 79 , 0 , 6482 , 298, 144), // #1085 - INST(Vfrczsd , VexRm , V(XOP_M9,83,_,0,0,_,_,_ ), 0 , 79 , 0 , 6490 , 299, 144), // #1086 - INST(Vfrczss , VexRm , V(XOP_M9,82,_,0,0,_,_,_ ), 0 , 79 , 0 , 6498 , 300, 144), // #1087 - INST(Vgatherdpd , VexRmvRm_VM , V(660F38,92,_,x,1,_,_,_ ), E(660F38,92,_,x,_,1,3,T1S), 189, 80 , 6506 , 301, 145), // #1088 - INST(Vgatherdps , VexRmvRm_VM , V(660F38,92,_,x,0,_,_,_ ), E(660F38,92,_,x,_,0,2,T1S), 96 , 81 , 6517 , 302, 145), // #1089 - INST(Vgatherpf0dpd , VexM_VM , E(660F38,C6,1,2,_,1,3,T1S), 0 , 190, 0 , 6528 , 303, 146), // #1090 - INST(Vgatherpf0dps , VexM_VM , E(660F38,C6,1,2,_,0,2,T1S), 0 , 191, 0 , 6542 , 304, 146), // #1091 - INST(Vgatherpf0qpd , VexM_VM , E(660F38,C7,1,2,_,1,3,T1S), 0 , 190, 0 , 6556 , 305, 146), // #1092 - INST(Vgatherpf0qps , VexM_VM , E(660F38,C7,1,2,_,0,2,T1S), 0 , 191, 0 , 6570 , 305, 146), // #1093 - INST(Vgatherpf1dpd , VexM_VM , E(660F38,C6,2,2,_,1,3,T1S), 0 , 192, 0 , 6584 , 303, 146), // #1094 - INST(Vgatherpf1dps , VexM_VM , E(660F38,C6,2,2,_,0,2,T1S), 0 , 193, 0 , 6598 , 304, 146), // #1095 - INST(Vgatherpf1qpd , VexM_VM , E(660F38,C7,2,2,_,1,3,T1S), 0 , 192, 0 , 6612 , 305, 146), // #1096 - INST(Vgatherpf1qps , VexM_VM , E(660F38,C7,2,2,_,0,2,T1S), 0 , 193, 0 , 6626 , 305, 146), // #1097 - INST(Vgatherqpd , VexRmvRm_VM , V(660F38,93,_,x,1,_,_,_ ), E(660F38,93,_,x,_,1,3,T1S), 189, 82 , 6640 , 306, 145), // #1098 - INST(Vgatherqps , VexRmvRm_VM , V(660F38,93,_,x,0,_,_,_ ), E(660F38,93,_,x,_,0,2,T1S), 96 , 83 , 6651 , 307, 145), // #1099 - INST(Vgetexppd , VexRm_Lx , E(660F38,42,_,x,_,1,4,FV ), 0 , 113, 0 , 6662 , 263, 131), // #1100 - INST(Vgetexpph , VexRm_Lx , E(66MAP6,42,_,_,_,0,4,FV ), 0 , 183, 0 , 6672 , 265, 125), // #1101 - INST(Vgetexpps , VexRm_Lx , E(660F38,42,_,x,_,0,4,FV ), 0 , 114, 0 , 6682 , 268, 131), // #1102 - INST(Vgetexpsd , VexRvm , E(660F38,43,_,I,_,1,3,T1S), 0 , 128, 0 , 6692 , 308, 68 ), // #1103 - INST(Vgetexpsh , VexRvm , E(66MAP6,43,_,_,_,0,1,T1S), 0 , 185, 0 , 6702 , 254, 127), // #1104 - INST(Vgetexpss , VexRvm , E(660F38,43,_,I,_,0,2,T1S), 0 , 129, 0 , 6712 , 309, 68 ), // #1105 - INST(Vgetmantpd , VexRmi_Lx , E(660F3A,26,_,x,_,1,4,FV ), 0 , 112, 0 , 6722 , 310, 131), // #1106 - INST(Vgetmantph , VexRmi_Lx , E(000F3A,26,_,_,_,0,4,FV ), 0 , 123, 0 , 6733 , 311, 125), // #1107 - INST(Vgetmantps , VexRmi_Lx , E(660F3A,26,_,x,_,0,4,FV ), 0 , 111, 0 , 6744 , 312, 131), // #1108 - INST(Vgetmantsd , VexRvmi , E(660F3A,27,_,I,_,1,3,T1S), 0 , 180, 0 , 6755 , 287, 68 ), // #1109 - INST(Vgetmantsh , VexRvmi , E(000F3A,27,_,_,_,0,1,T1S), 0 , 188, 0 , 6766 , 313, 127), // #1110 - INST(Vgetmantss , VexRvmi , E(660F3A,27,_,I,_,0,2,T1S), 0 , 181, 0 , 6777 , 288, 68 ), // #1111 - INST(Vgf2p8affineinvqb, VexRvmi_Lx , V(660F3A,CF,_,x,1,1,4,FV ), 0 , 194, 0 , 6788 , 314, 147), // #1112 - INST(Vgf2p8affineqb , VexRvmi_Lx , V(660F3A,CE,_,x,1,1,4,FV ), 0 , 194, 0 , 6806 , 314, 147), // #1113 - INST(Vgf2p8mulb , VexRvm_Lx , V(660F38,CF,_,x,0,0,4,FV ), 0 , 110, 0 , 6821 , 315, 147), // #1114 - INST(Vhaddpd , VexRvm_Lx , V(660F00,7C,_,x,I,_,_,_ ), 0 , 69 , 0 , 6832 , 202, 128), // #1115 - INST(Vhaddps , VexRvm_Lx , V(F20F00,7C,_,x,I,_,_,_ ), 0 , 109, 0 , 6840 , 202, 128), // #1116 - INST(Vhsubpd , VexRvm_Lx , V(660F00,7D,_,x,I,_,_,_ ), 0 , 69 , 0 , 6848 , 202, 128), // #1117 - INST(Vhsubps , VexRvm_Lx , V(F20F00,7D,_,x,I,_,_,_ ), 0 , 109, 0 , 6856 , 202, 128), // #1118 - INST(Vinsertf128 , VexRvmi , V(660F3A,18,_,1,0,_,_,_ ), 0 , 172, 0 , 6864 , 316, 128), // #1119 - INST(Vinsertf32x4 , VexRvmi_Lx , E(660F3A,18,_,x,_,0,4,T4 ), 0 , 173, 0 , 6876 , 317, 131), // #1120 - INST(Vinsertf32x8 , VexRvmi , E(660F3A,1A,_,2,_,0,5,T8 ), 0 , 174, 0 , 6889 , 318, 66 ), // #1121 - INST(Vinsertf64x2 , VexRvmi_Lx , E(660F3A,18,_,x,_,1,4,T2 ), 0 , 175, 0 , 6902 , 317, 133), // #1122 - INST(Vinsertf64x4 , VexRvmi , E(660F3A,1A,_,2,_,1,5,T4 ), 0 , 176, 0 , 6915 , 318, 68 ), // #1123 - INST(Vinserti128 , VexRvmi , V(660F3A,38,_,1,0,_,_,_ ), 0 , 172, 0 , 6928 , 316, 134), // #1124 - INST(Vinserti32x4 , VexRvmi_Lx , E(660F3A,38,_,x,_,0,4,T4 ), 0 , 173, 0 , 6940 , 317, 131), // #1125 - INST(Vinserti32x8 , VexRvmi , E(660F3A,3A,_,2,_,0,5,T8 ), 0 , 174, 0 , 6953 , 318, 66 ), // #1126 - INST(Vinserti64x2 , VexRvmi_Lx , E(660F3A,38,_,x,_,1,4,T2 ), 0 , 175, 0 , 6966 , 317, 133), // #1127 - INST(Vinserti64x4 , VexRvmi , E(660F3A,3A,_,2,_,1,5,T4 ), 0 , 176, 0 , 6979 , 318, 68 ), // #1128 - INST(Vinsertps , VexRvmi , V(660F3A,21,_,0,I,0,2,T1S), 0 , 177, 0 , 6992 , 319, 126), // #1129 - INST(Vlddqu , VexRm_Lx , V(F20F00,F0,_,x,I,_,_,_ ), 0 , 109, 0 , 7002 , 320, 128), // #1130 - INST(Vldmxcsr , VexM , V(000F00,AE,2,0,I,_,_,_ ), 0 , 195, 0 , 7009 , 321, 128), // #1131 - INST(Vmaskmovdqu , VexRm_ZDI , V(660F00,F7,_,0,I,_,_,_ ), 0 , 69 , 0 , 7018 , 322, 128), // #1132 - INST(Vmaskmovpd , VexRvmMvr_Lx , V(660F38,2D,_,x,0,_,_,_ ), V(660F38,2F,_,x,0,_,_,_ ), 96 , 84 , 7030 , 323, 128), // #1133 - INST(Vmaskmovps , VexRvmMvr_Lx , V(660F38,2C,_,x,0,_,_,_ ), V(660F38,2E,_,x,0,_,_,_ ), 96 , 85 , 7041 , 323, 128), // #1134 - INST(Vmaxpd , VexRvm_Lx , V(660F00,5F,_,x,I,1,4,FV ), 0 , 103, 0 , 7052 , 324, 124), // #1135 - INST(Vmaxph , VexRvm_Lx , E(00MAP5,5F,_,_,_,0,4,FV ), 0 , 104, 0 , 7059 , 325, 125), // #1136 - INST(Vmaxps , VexRvm_Lx , V(000F00,5F,_,x,I,0,4,FV ), 0 , 105, 0 , 7066 , 326, 124), // #1137 - INST(Vmaxsd , VexRvm , V(F20F00,5F,_,I,I,1,3,T1S), 0 , 106, 0 , 7073 , 327, 124), // #1138 - INST(Vmaxsh , VexRvm , E(F3MAP5,5F,_,_,_,0,1,T1S), 0 , 107, 0 , 7080 , 254, 127), // #1139 - INST(Vmaxss , VexRvm , V(F30F00,5F,_,I,I,0,2,T1S), 0 , 108, 0 , 7087 , 258, 124), // #1140 - INST(Vmcall , X86Op , O(000F01,C1,_,_,_,_,_,_ ), 0 , 21 , 0 , 7094 , 30 , 58 ), // #1141 - INST(Vmclear , X86M_Only , O(660F00,C7,6,_,_,_,_,_ ), 0 , 26 , 0 , 7101 , 32 , 58 ), // #1142 - INST(Vmfunc , X86Op , O(000F01,D4,_,_,_,_,_,_ ), 0 , 21 , 0 , 7109 , 30 , 58 ), // #1143 - INST(Vminpd , VexRvm_Lx , V(660F00,5D,_,x,I,1,4,FV ), 0 , 103, 0 , 7116 , 324, 124), // #1144 - INST(Vminph , VexRvm_Lx , E(00MAP5,5D,_,_,_,0,4,FV ), 0 , 104, 0 , 7123 , 325, 125), // #1145 - INST(Vminps , VexRvm_Lx , V(000F00,5D,_,x,I,0,4,FV ), 0 , 105, 0 , 7130 , 326, 124), // #1146 - INST(Vminsd , VexRvm , V(F20F00,5D,_,I,I,1,3,T1S), 0 , 106, 0 , 7137 , 327, 124), // #1147 - INST(Vminsh , VexRvm , E(F3MAP5,5D,_,_,_,0,1,T1S), 0 , 107, 0 , 7144 , 254, 127), // #1148 - INST(Vminss , VexRvm , V(F30F00,5D,_,I,I,0,2,T1S), 0 , 108, 0 , 7151 , 258, 124), // #1149 - INST(Vmlaunch , X86Op , O(000F01,C2,_,_,_,_,_,_ ), 0 , 21 , 0 , 7158 , 30 , 58 ), // #1150 - INST(Vmload , X86Op_xAX , O(000F01,DA,_,_,_,_,_,_ ), 0 , 21 , 0 , 7167 , 328, 22 ), // #1151 - INST(Vmmcall , X86Op , O(000F01,D9,_,_,_,_,_,_ ), 0 , 21 , 0 , 7174 , 30 , 22 ), // #1152 - INST(Vmovapd , VexRmMr_Lx , V(660F00,28,_,x,I,1,4,FVM), V(660F00,29,_,x,I,1,4,FVM), 103, 86 , 7182 , 329, 124), // #1153 - INST(Vmovaps , VexRmMr_Lx , V(000F00,28,_,x,I,0,4,FVM), V(000F00,29,_,x,I,0,4,FVM), 105, 87 , 7190 , 329, 124), // #1154 - INST(Vmovd , VexMovdMovq , V(660F00,6E,_,0,0,0,2,T1S), V(660F00,7E,_,0,0,0,2,T1S), 196, 88 , 7198 , 330, 126), // #1155 - INST(Vmovddup , VexRm_Lx , V(F20F00,12,_,x,I,1,3,DUP), 0 , 197, 0 , 7204 , 331, 124), // #1156 - INST(Vmovdqa , VexRmMr_Lx , V(660F00,6F,_,x,I,_,_,_ ), V(660F00,7F,_,x,I,_,_,_ ), 69 , 89 , 7213 , 332, 128), // #1157 - INST(Vmovdqa32 , VexRmMr_Lx , E(660F00,6F,_,x,_,0,4,FVM), E(660F00,7F,_,x,_,0,4,FVM), 198, 90 , 7221 , 333, 131), // #1158 - INST(Vmovdqa64 , VexRmMr_Lx , E(660F00,6F,_,x,_,1,4,FVM), E(660F00,7F,_,x,_,1,4,FVM), 135, 91 , 7231 , 333, 131), // #1159 - INST(Vmovdqu , VexRmMr_Lx , V(F30F00,6F,_,x,I,_,_,_ ), V(F30F00,7F,_,x,I,_,_,_ ), 199, 92 , 7241 , 332, 128), // #1160 - INST(Vmovdqu16 , VexRmMr_Lx , E(F20F00,6F,_,x,_,1,4,FVM), E(F20F00,7F,_,x,_,1,4,FVM), 166, 93 , 7249 , 333, 139), // #1161 - INST(Vmovdqu32 , VexRmMr_Lx , E(F30F00,6F,_,x,_,0,4,FVM), E(F30F00,7F,_,x,_,0,4,FVM), 200, 94 , 7259 , 333, 131), // #1162 - INST(Vmovdqu64 , VexRmMr_Lx , E(F30F00,6F,_,x,_,1,4,FVM), E(F30F00,7F,_,x,_,1,4,FVM), 149, 95 , 7269 , 333, 131), // #1163 - INST(Vmovdqu8 , VexRmMr_Lx , E(F20F00,6F,_,x,_,0,4,FVM), E(F20F00,7F,_,x,_,0,4,FVM), 164, 96 , 7279 , 333, 139), // #1164 - INST(Vmovhlps , VexRvm , V(000F00,12,_,0,I,0,_,_ ), 0 , 72 , 0 , 7288 , 334, 126), // #1165 - INST(Vmovhpd , VexRvmMr , V(660F00,16,_,0,I,1,3,T1S), V(660F00,17,_,0,I,1,3,T1S), 125, 97 , 7297 , 335, 126), // #1166 - INST(Vmovhps , VexRvmMr , V(000F00,16,_,0,I,0,3,T2 ), V(000F00,17,_,0,I,0,3,T2 ), 201, 98 , 7305 , 335, 126), // #1167 - INST(Vmovlhps , VexRvm , V(000F00,16,_,0,I,0,_,_ ), 0 , 72 , 0 , 7313 , 334, 126), // #1168 - INST(Vmovlpd , VexRvmMr , V(660F00,12,_,0,I,1,3,T1S), V(660F00,13,_,0,I,1,3,T1S), 125, 99 , 7322 , 335, 126), // #1169 - INST(Vmovlps , VexRvmMr , V(000F00,12,_,0,I,0,3,T2 ), V(000F00,13,_,0,I,0,3,T2 ), 201, 100, 7330 , 335, 126), // #1170 - INST(Vmovmskpd , VexRm_Lx , V(660F00,50,_,x,I,_,_,_ ), 0 , 69 , 0 , 7338 , 336, 128), // #1171 - INST(Vmovmskps , VexRm_Lx , V(000F00,50,_,x,I,_,_,_ ), 0 , 72 , 0 , 7348 , 336, 128), // #1172 - INST(Vmovntdq , VexMr_Lx , V(660F00,E7,_,x,I,0,4,FVM), 0 , 144, 0 , 7358 , 337, 124), // #1173 - INST(Vmovntdqa , VexRm_Lx , V(660F38,2A,_,x,I,0,4,FVM), 0 , 110, 0 , 7367 , 338, 135), // #1174 - INST(Vmovntpd , VexMr_Lx , V(660F00,2B,_,x,I,1,4,FVM), 0 , 103, 0 , 7377 , 337, 124), // #1175 - INST(Vmovntps , VexMr_Lx , V(000F00,2B,_,x,I,0,4,FVM), 0 , 105, 0 , 7386 , 337, 124), // #1176 - INST(Vmovq , VexMovdMovq , V(660F00,6E,_,0,I,1,3,T1S), V(660F00,7E,_,0,I,1,3,T1S), 125, 101, 7395 , 339, 126), // #1177 - INST(Vmovsd , VexMovssMovsd , V(F20F00,10,_,I,I,1,3,T1S), V(F20F00,11,_,I,I,1,3,T1S), 106, 102, 7401 , 340, 126), // #1178 - INST(Vmovsh , VexMovssMovsd , E(F3MAP5,10,_,I,_,0,1,T1S), E(F3MAP5,11,_,I,_,0,1,T1S), 107, 103, 7408 , 341, 127), // #1179 - INST(Vmovshdup , VexRm_Lx , V(F30F00,16,_,x,I,0,4,FVM), 0 , 161, 0 , 7415 , 342, 124), // #1180 - INST(Vmovsldup , VexRm_Lx , V(F30F00,12,_,x,I,0,4,FVM), 0 , 161, 0 , 7425 , 342, 124), // #1181 - INST(Vmovss , VexMovssMovsd , V(F30F00,10,_,I,I,0,2,T1S), V(F30F00,11,_,I,I,0,2,T1S), 108, 104, 7435 , 343, 126), // #1182 - INST(Vmovupd , VexRmMr_Lx , V(660F00,10,_,x,I,1,4,FVM), V(660F00,11,_,x,I,1,4,FVM), 103, 105, 7442 , 329, 124), // #1183 - INST(Vmovups , VexRmMr_Lx , V(000F00,10,_,x,I,0,4,FVM), V(000F00,11,_,x,I,0,4,FVM), 105, 106, 7450 , 329, 124), // #1184 - INST(Vmovw , VexMovdMovq , E(66MAP5,6E,_,0,_,I,1,T1S), E(66MAP5,7E,_,0,_,I,1,T1S), 202, 107, 7458 , 344, 127), // #1185 - INST(Vmpsadbw , VexRvmi_Lx , V(660F3A,42,_,x,I,_,_,_ ), 0 , 73 , 0 , 7464 , 214, 148), // #1186 - INST(Vmptrld , X86M_Only , O(000F00,C7,6,_,_,_,_,_ ), 0 , 80 , 0 , 7473 , 32 , 58 ), // #1187 - INST(Vmptrst , X86M_Only , O(000F00,C7,7,_,_,_,_,_ ), 0 , 22 , 0 , 7481 , 32 , 58 ), // #1188 - INST(Vmread , X86Mr_NoSize , O(000F00,78,_,_,_,_,_,_ ), 0 , 4 , 0 , 7489 , 345, 58 ), // #1189 - INST(Vmresume , X86Op , O(000F01,C3,_,_,_,_,_,_ ), 0 , 21 , 0 , 7496 , 30 , 58 ), // #1190 - INST(Vmrun , X86Op_xAX , O(000F01,D8,_,_,_,_,_,_ ), 0 , 21 , 0 , 7505 , 328, 22 ), // #1191 - INST(Vmsave , X86Op_xAX , O(000F01,DB,_,_,_,_,_,_ ), 0 , 21 , 0 , 7511 , 328, 22 ), // #1192 - INST(Vmulpd , VexRvm_Lx , V(660F00,59,_,x,I,1,4,FV ), 0 , 103, 0 , 7518 , 196, 124), // #1193 - INST(Vmulph , VexRvm_Lx , E(00MAP5,59,_,_,_,0,4,FV ), 0 , 104, 0 , 7525 , 197, 125), // #1194 - INST(Vmulps , VexRvm_Lx , V(000F00,59,_,x,I,0,4,FV ), 0 , 105, 0 , 7532 , 198, 124), // #1195 - INST(Vmulsd , VexRvm , V(F20F00,59,_,I,I,1,3,T1S), 0 , 106, 0 , 7539 , 199, 126), // #1196 - INST(Vmulsh , VexRvm , E(F3MAP5,59,_,_,_,0,1,T1S), 0 , 107, 0 , 7546 , 200, 127), // #1197 - INST(Vmulss , VexRvm , V(F30F00,59,_,I,I,0,2,T1S), 0 , 108, 0 , 7553 , 201, 126), // #1198 - INST(Vmwrite , X86Rm_NoSize , O(000F00,79,_,_,_,_,_,_ ), 0 , 4 , 0 , 7560 , 346, 58 ), // #1199 - INST(Vmxon , X86M_Only , O(F30F00,C7,6,_,_,_,_,_ ), 0 , 24 , 0 , 7568 , 32 , 58 ), // #1200 - INST(Vorpd , VexRvm_Lx , V(660F00,56,_,x,I,1,4,FV ), 0 , 103, 0 , 7574 , 210, 132), // #1201 - INST(Vorps , VexRvm_Lx , V(000F00,56,_,x,I,0,4,FV ), 0 , 105, 0 , 7580 , 211, 132), // #1202 - INST(Vp2intersectd , VexRvm_Lx_2xK , E(F20F38,68,_,_,_,0,4,FV ), 0 , 131, 0 , 7586 , 347, 149), // #1203 - INST(Vp2intersectq , VexRvm_Lx_2xK , E(F20F38,68,_,_,_,1,4,FV ), 0 , 203, 0 , 7600 , 348, 149), // #1204 - INST(Vp4dpwssd , VexRm_T1_4X , E(F20F38,52,_,2,_,0,4,T4X), 0 , 101, 0 , 7614 , 194, 150), // #1205 - INST(Vp4dpwssds , VexRm_T1_4X , E(F20F38,53,_,2,_,0,4,T4X), 0 , 101, 0 , 7624 , 194, 150), // #1206 - INST(Vpabsb , VexRm_Lx , V(660F38,1C,_,x,I,_,4,FVM), 0 , 110, 0 , 7635 , 342, 151), // #1207 - INST(Vpabsd , VexRm_Lx , V(660F38,1E,_,x,I,0,4,FV ), 0 , 110, 0 , 7642 , 349, 135), // #1208 - INST(Vpabsq , VexRm_Lx , E(660F38,1F,_,x,_,1,4,FV ), 0 , 113, 0 , 7649 , 350, 131), // #1209 - INST(Vpabsw , VexRm_Lx , V(660F38,1D,_,x,I,_,4,FVM), 0 , 110, 0 , 7656 , 342, 151), // #1210 - INST(Vpackssdw , VexRvm_Lx , V(660F00,6B,_,x,I,0,4,FV ), 0 , 144, 0 , 7663 , 209, 151), // #1211 - INST(Vpacksswb , VexRvm_Lx , V(660F00,63,_,x,I,I,4,FVM), 0 , 144, 0 , 7673 , 315, 151), // #1212 - INST(Vpackusdw , VexRvm_Lx , V(660F38,2B,_,x,I,0,4,FV ), 0 , 110, 0 , 7683 , 209, 151), // #1213 - INST(Vpackuswb , VexRvm_Lx , V(660F00,67,_,x,I,I,4,FVM), 0 , 144, 0 , 7693 , 315, 151), // #1214 - INST(Vpaddb , VexRvm_Lx , V(660F00,FC,_,x,I,I,4,FVM), 0 , 144, 0 , 7703 , 315, 151), // #1215 - INST(Vpaddd , VexRvm_Lx , V(660F00,FE,_,x,I,0,4,FV ), 0 , 144, 0 , 7710 , 209, 135), // #1216 - INST(Vpaddq , VexRvm_Lx , V(660F00,D4,_,x,I,1,4,FV ), 0 , 103, 0 , 7717 , 208, 135), // #1217 - INST(Vpaddsb , VexRvm_Lx , V(660F00,EC,_,x,I,I,4,FVM), 0 , 144, 0 , 7724 , 315, 151), // #1218 - INST(Vpaddsw , VexRvm_Lx , V(660F00,ED,_,x,I,I,4,FVM), 0 , 144, 0 , 7732 , 315, 151), // #1219 - INST(Vpaddusb , VexRvm_Lx , V(660F00,DC,_,x,I,I,4,FVM), 0 , 144, 0 , 7740 , 315, 151), // #1220 - INST(Vpaddusw , VexRvm_Lx , V(660F00,DD,_,x,I,I,4,FVM), 0 , 144, 0 , 7749 , 315, 151), // #1221 - INST(Vpaddw , VexRvm_Lx , V(660F00,FD,_,x,I,I,4,FVM), 0 , 144, 0 , 7758 , 315, 151), // #1222 - INST(Vpalignr , VexRvmi_Lx , V(660F3A,0F,_,x,I,I,4,FVM), 0 , 204, 0 , 7765 , 314, 151), // #1223 - INST(Vpand , VexRvm_Lx , V(660F00,DB,_,x,I,_,_,_ ), 0 , 69 , 0 , 7774 , 351, 148), // #1224 - INST(Vpandd , VexRvm_Lx , E(660F00,DB,_,x,_,0,4,FV ), 0 , 198, 0 , 7780 , 352, 131), // #1225 - INST(Vpandn , VexRvm_Lx , V(660F00,DF,_,x,I,_,_,_ ), 0 , 69 , 0 , 7787 , 353, 148), // #1226 - INST(Vpandnd , VexRvm_Lx , E(660F00,DF,_,x,_,0,4,FV ), 0 , 198, 0 , 7794 , 354, 131), // #1227 - INST(Vpandnq , VexRvm_Lx , E(660F00,DF,_,x,_,1,4,FV ), 0 , 135, 0 , 7802 , 355, 131), // #1228 - INST(Vpandq , VexRvm_Lx , E(660F00,DB,_,x,_,1,4,FV ), 0 , 135, 0 , 7810 , 356, 131), // #1229 - INST(Vpavgb , VexRvm_Lx , V(660F00,E0,_,x,I,I,4,FVM), 0 , 144, 0 , 7817 , 315, 151), // #1230 - INST(Vpavgw , VexRvm_Lx , V(660F00,E3,_,x,I,I,4,FVM), 0 , 144, 0 , 7824 , 315, 151), // #1231 - INST(Vpblendd , VexRvmi_Lx , V(660F3A,02,_,x,0,_,_,_ ), 0 , 73 , 0 , 7831 , 214, 134), // #1232 - INST(Vpblendmb , VexRvm_Lx , E(660F38,66,_,x,_,0,4,FVM), 0 , 114, 0 , 7840 , 357, 139), // #1233 - INST(Vpblendmd , VexRvm_Lx , E(660F38,64,_,x,_,0,4,FV ), 0 , 114, 0 , 7850 , 213, 131), // #1234 - INST(Vpblendmq , VexRvm_Lx , E(660F38,64,_,x,_,1,4,FV ), 0 , 113, 0 , 7860 , 212, 131), // #1235 - INST(Vpblendmw , VexRvm_Lx , E(660F38,66,_,x,_,1,4,FVM), 0 , 113, 0 , 7870 , 357, 139), // #1236 - INST(Vpblendvb , VexRvmr_Lx , V(660F3A,4C,_,x,0,_,_,_ ), 0 , 73 , 0 , 7880 , 215, 148), // #1237 - INST(Vpblendw , VexRvmi_Lx , V(660F3A,0E,_,x,I,_,_,_ ), 0 , 73 , 0 , 7890 , 214, 148), // #1238 - INST(Vpbroadcastb , VexRm_Lx_Bcst , V(660F38,78,_,x,0,0,0,T1S), E(660F38,7A,_,x,0,0,0,T1S), 96 , 108, 7899 , 358, 152), // #1239 - INST(Vpbroadcastd , VexRm_Lx_Bcst , V(660F38,58,_,x,0,0,2,T1S), E(660F38,7C,_,x,0,0,0,T1S), 122, 109, 7912 , 359, 145), // #1240 - INST(Vpbroadcastmb2q , VexRm_Lx , E(F30F38,2A,_,x,_,1,_,_ ), 0 , 205, 0 , 7925 , 360, 153), // #1241 - INST(Vpbroadcastmw2d , VexRm_Lx , E(F30F38,3A,_,x,_,0,_,_ ), 0 , 206, 0 , 7941 , 360, 153), // #1242 - INST(Vpbroadcastq , VexRm_Lx_Bcst , V(660F38,59,_,x,0,1,3,T1S), E(660F38,7C,_,x,0,1,0,T1S), 121, 110, 7957 , 361, 145), // #1243 - INST(Vpbroadcastw , VexRm_Lx_Bcst , V(660F38,79,_,x,0,0,1,T1S), E(660F38,7B,_,x,0,0,0,T1S), 207, 111, 7970 , 362, 152), // #1244 - INST(Vpclmulqdq , VexRvmi_Lx , V(660F3A,44,_,x,I,_,4,FVM), 0 , 204, 0 , 7983 , 363, 154), // #1245 - INST(Vpcmov , VexRvrmRvmr_Lx , V(XOP_M8,A2,_,x,x,_,_,_ ), 0 , 208, 0 , 7994 , 289, 144), // #1246 - INST(Vpcmpb , VexRvmi_Lx , E(660F3A,3F,_,x,_,0,4,FVM), 0 , 111, 0 , 8001 , 364, 139), // #1247 - INST(Vpcmpd , VexRvmi_Lx , E(660F3A,1F,_,x,_,0,4,FV ), 0 , 111, 0 , 8008 , 365, 131), // #1248 - INST(Vpcmpeqb , VexRvm_Lx_KEvex , V(660F00,74,_,x,I,I,4,FV ), 0 , 144, 0 , 8015 , 366, 151), // #1249 - INST(Vpcmpeqd , VexRvm_Lx_KEvex , V(660F00,76,_,x,I,0,4,FVM), 0 , 144, 0 , 8024 , 367, 135), // #1250 - INST(Vpcmpeqq , VexRvm_Lx_KEvex , V(660F38,29,_,x,I,1,4,FVM), 0 , 209, 0 , 8033 , 368, 135), // #1251 - INST(Vpcmpeqw , VexRvm_Lx_KEvex , V(660F00,75,_,x,I,I,4,FV ), 0 , 144, 0 , 8042 , 366, 151), // #1252 - INST(Vpcmpestri , VexRmi , V(660F3A,61,_,0,I,_,_,_ ), 0 , 73 , 0 , 8051 , 369, 155), // #1253 - INST(Vpcmpestrm , VexRmi , V(660F3A,60,_,0,I,_,_,_ ), 0 , 73 , 0 , 8062 , 370, 155), // #1254 - INST(Vpcmpgtb , VexRvm_Lx_KEvex , V(660F00,64,_,x,I,I,4,FV ), 0 , 144, 0 , 8073 , 366, 151), // #1255 - INST(Vpcmpgtd , VexRvm_Lx_KEvex , V(660F00,66,_,x,I,0,4,FVM), 0 , 144, 0 , 8082 , 367, 135), // #1256 - INST(Vpcmpgtq , VexRvm_Lx_KEvex , V(660F38,37,_,x,I,1,4,FVM), 0 , 209, 0 , 8091 , 368, 135), // #1257 - INST(Vpcmpgtw , VexRvm_Lx_KEvex , V(660F00,65,_,x,I,I,4,FV ), 0 , 144, 0 , 8100 , 366, 151), // #1258 - INST(Vpcmpistri , VexRmi , V(660F3A,63,_,0,I,_,_,_ ), 0 , 73 , 0 , 8109 , 371, 155), // #1259 - INST(Vpcmpistrm , VexRmi , V(660F3A,62,_,0,I,_,_,_ ), 0 , 73 , 0 , 8120 , 372, 155), // #1260 - INST(Vpcmpq , VexRvmi_Lx , E(660F3A,1F,_,x,_,1,4,FV ), 0 , 112, 0 , 8131 , 373, 131), // #1261 - INST(Vpcmpub , VexRvmi_Lx , E(660F3A,3E,_,x,_,0,4,FVM), 0 , 111, 0 , 8138 , 364, 139), // #1262 - INST(Vpcmpud , VexRvmi_Lx , E(660F3A,1E,_,x,_,0,4,FV ), 0 , 111, 0 , 8146 , 365, 131), // #1263 - INST(Vpcmpuq , VexRvmi_Lx , E(660F3A,1E,_,x,_,1,4,FV ), 0 , 112, 0 , 8154 , 373, 131), // #1264 - INST(Vpcmpuw , VexRvmi_Lx , E(660F3A,3E,_,x,_,1,4,FVM), 0 , 112, 0 , 8162 , 373, 139), // #1265 - INST(Vpcmpw , VexRvmi_Lx , E(660F3A,3F,_,x,_,1,4,FVM), 0 , 112, 0 , 8170 , 373, 139), // #1266 - INST(Vpcomb , VexRvmi , V(XOP_M8,CC,_,0,0,_,_,_ ), 0 , 208, 0 , 8177 , 276, 144), // #1267 - INST(Vpcomd , VexRvmi , V(XOP_M8,CE,_,0,0,_,_,_ ), 0 , 208, 0 , 8184 , 276, 144), // #1268 - INST(Vpcompressb , VexMr_Lx , E(660F38,63,_,x,_,0,0,T1S), 0 , 210, 0 , 8191 , 232, 156), // #1269 - INST(Vpcompressd , VexMr_Lx , E(660F38,8B,_,x,_,0,2,T1S), 0 , 129, 0 , 8203 , 232, 131), // #1270 - INST(Vpcompressq , VexMr_Lx , E(660F38,8B,_,x,_,1,3,T1S), 0 , 128, 0 , 8215 , 232, 131), // #1271 - INST(Vpcompressw , VexMr_Lx , E(660F38,63,_,x,_,1,1,T1S), 0 , 211, 0 , 8227 , 232, 156), // #1272 - INST(Vpcomq , VexRvmi , V(XOP_M8,CF,_,0,0,_,_,_ ), 0 , 208, 0 , 8239 , 276, 144), // #1273 - INST(Vpcomub , VexRvmi , V(XOP_M8,EC,_,0,0,_,_,_ ), 0 , 208, 0 , 8246 , 276, 144), // #1274 - INST(Vpcomud , VexRvmi , V(XOP_M8,EE,_,0,0,_,_,_ ), 0 , 208, 0 , 8254 , 276, 144), // #1275 - INST(Vpcomuq , VexRvmi , V(XOP_M8,EF,_,0,0,_,_,_ ), 0 , 208, 0 , 8262 , 276, 144), // #1276 - INST(Vpcomuw , VexRvmi , V(XOP_M8,ED,_,0,0,_,_,_ ), 0 , 208, 0 , 8270 , 276, 144), // #1277 - INST(Vpcomw , VexRvmi , V(XOP_M8,CD,_,0,0,_,_,_ ), 0 , 208, 0 , 8278 , 276, 144), // #1278 - INST(Vpconflictd , VexRm_Lx , E(660F38,C4,_,x,_,0,4,FV ), 0 , 114, 0 , 8285 , 374, 153), // #1279 - INST(Vpconflictq , VexRm_Lx , E(660F38,C4,_,x,_,1,4,FV ), 0 , 113, 0 , 8297 , 374, 153), // #1280 - INST(Vpdpbusd , VexRvm_Lx , V(660F38,50,_,x,_,0,4,FV ), 0 , 110, 0 , 8309 , 375, 157), // #1281 - INST(Vpdpbusds , VexRvm_Lx , V(660F38,51,_,x,_,0,4,FV ), 0 , 110, 0 , 8318 , 375, 157), // #1282 - INST(Vpdpwssd , VexRvm_Lx , V(660F38,52,_,x,_,0,4,FV ), 0 , 110, 0 , 8328 , 375, 157), // #1283 - INST(Vpdpwssds , VexRvm_Lx , V(660F38,53,_,x,_,0,4,FV ), 0 , 110, 0 , 8337 , 375, 157), // #1284 - INST(Vperm2f128 , VexRvmi , V(660F3A,06,_,1,0,_,_,_ ), 0 , 172, 0 , 8347 , 376, 128), // #1285 - INST(Vperm2i128 , VexRvmi , V(660F3A,46,_,1,0,_,_,_ ), 0 , 172, 0 , 8358 , 376, 134), // #1286 - INST(Vpermb , VexRvm_Lx , E(660F38,8D,_,x,_,0,4,FVM), 0 , 114, 0 , 8369 , 357, 158), // #1287 - INST(Vpermd , VexRvm_Lx , V(660F38,36,_,x,0,0,4,FV ), 0 , 110, 0 , 8376 , 377, 145), // #1288 - INST(Vpermi2b , VexRvm_Lx , E(660F38,75,_,x,_,0,4,FVM), 0 , 114, 0 , 8383 , 357, 158), // #1289 - INST(Vpermi2d , VexRvm_Lx , E(660F38,76,_,x,_,0,4,FV ), 0 , 114, 0 , 8392 , 213, 131), // #1290 - INST(Vpermi2pd , VexRvm_Lx , E(660F38,77,_,x,_,1,4,FV ), 0 , 113, 0 , 8401 , 212, 131), // #1291 - INST(Vpermi2ps , VexRvm_Lx , E(660F38,77,_,x,_,0,4,FV ), 0 , 114, 0 , 8411 , 213, 131), // #1292 - INST(Vpermi2q , VexRvm_Lx , E(660F38,76,_,x,_,1,4,FV ), 0 , 113, 0 , 8421 , 212, 131), // #1293 - INST(Vpermi2w , VexRvm_Lx , E(660F38,75,_,x,_,1,4,FVM), 0 , 113, 0 , 8430 , 357, 139), // #1294 - INST(Vpermil2pd , VexRvrmiRvmri_Lx , V(660F3A,49,_,x,x,_,_,_ ), 0 , 73 , 0 , 8439 , 378, 144), // #1295 - INST(Vpermil2ps , VexRvrmiRvmri_Lx , V(660F3A,48,_,x,x,_,_,_ ), 0 , 73 , 0 , 8450 , 378, 144), // #1296 - INST(Vpermilpd , VexRvmRmi_Lx , V(660F38,0D,_,x,0,1,4,FV ), V(660F3A,05,_,x,0,1,4,FV ), 209, 112, 8461 , 379, 124), // #1297 - INST(Vpermilps , VexRvmRmi_Lx , V(660F38,0C,_,x,0,0,4,FV ), V(660F3A,04,_,x,0,0,4,FV ), 110, 113, 8471 , 380, 124), // #1298 - INST(Vpermpd , VexRvmRmi_Lx , E(660F38,16,_,x,1,1,4,FV ), V(660F3A,01,_,x,1,1,4,FV ), 212, 114, 8481 , 381, 145), // #1299 - INST(Vpermps , VexRvm_Lx , V(660F38,16,_,x,0,0,4,FV ), 0 , 110, 0 , 8489 , 377, 145), // #1300 - INST(Vpermq , VexRvmRmi_Lx , E(660F38,36,_,x,_,1,4,FV ), V(660F3A,00,_,x,1,1,4,FV ), 113, 115, 8497 , 381, 145), // #1301 - INST(Vpermt2b , VexRvm_Lx , E(660F38,7D,_,x,_,0,4,FVM), 0 , 114, 0 , 8504 , 357, 158), // #1302 - INST(Vpermt2d , VexRvm_Lx , E(660F38,7E,_,x,_,0,4,FV ), 0 , 114, 0 , 8513 , 213, 131), // #1303 - INST(Vpermt2pd , VexRvm_Lx , E(660F38,7F,_,x,_,1,4,FV ), 0 , 113, 0 , 8522 , 212, 131), // #1304 - INST(Vpermt2ps , VexRvm_Lx , E(660F38,7F,_,x,_,0,4,FV ), 0 , 114, 0 , 8532 , 213, 131), // #1305 - INST(Vpermt2q , VexRvm_Lx , E(660F38,7E,_,x,_,1,4,FV ), 0 , 113, 0 , 8542 , 212, 131), // #1306 - INST(Vpermt2w , VexRvm_Lx , E(660F38,7D,_,x,_,1,4,FVM), 0 , 113, 0 , 8551 , 357, 139), // #1307 - INST(Vpermw , VexRvm_Lx , E(660F38,8D,_,x,_,1,4,FVM), 0 , 113, 0 , 8560 , 357, 139), // #1308 - INST(Vpexpandb , VexRm_Lx , E(660F38,62,_,x,_,0,0,T1S), 0 , 210, 0 , 8567 , 279, 156), // #1309 - INST(Vpexpandd , VexRm_Lx , E(660F38,89,_,x,_,0,2,T1S), 0 , 129, 0 , 8577 , 279, 131), // #1310 - INST(Vpexpandq , VexRm_Lx , E(660F38,89,_,x,_,1,3,T1S), 0 , 128, 0 , 8587 , 279, 131), // #1311 - INST(Vpexpandw , VexRm_Lx , E(660F38,62,_,x,_,1,1,T1S), 0 , 211, 0 , 8597 , 279, 156), // #1312 - INST(Vpextrb , VexMri , V(660F3A,14,_,0,0,I,0,T1S), 0 , 73 , 0 , 8607 , 382, 159), // #1313 - INST(Vpextrd , VexMri , V(660F3A,16,_,0,0,0,2,T1S), 0 , 177, 0 , 8615 , 283, 160), // #1314 - INST(Vpextrq , VexMri , V(660F3A,16,_,0,1,1,3,T1S), 0 , 213, 0 , 8623 , 383, 160), // #1315 - INST(Vpextrw , VexMri_Vpextrw , V(660F3A,15,_,0,0,I,1,T1S), 0 , 214, 0 , 8631 , 384, 159), // #1316 - INST(Vpgatherdd , VexRmvRm_VM , V(660F38,90,_,x,0,_,_,_ ), E(660F38,90,_,x,_,0,2,T1S), 96 , 116, 8639 , 302, 145), // #1317 - INST(Vpgatherdq , VexRmvRm_VM , V(660F38,90,_,x,1,_,_,_ ), E(660F38,90,_,x,_,1,3,T1S), 189, 117, 8650 , 301, 145), // #1318 - INST(Vpgatherqd , VexRmvRm_VM , V(660F38,91,_,x,0,_,_,_ ), E(660F38,91,_,x,_,0,2,T1S), 96 , 118, 8661 , 307, 145), // #1319 - INST(Vpgatherqq , VexRmvRm_VM , V(660F38,91,_,x,1,_,_,_ ), E(660F38,91,_,x,_,1,3,T1S), 189, 119, 8672 , 306, 145), // #1320 - INST(Vphaddbd , VexRm , V(XOP_M9,C2,_,0,0,_,_,_ ), 0 , 79 , 0 , 8683 , 204, 144), // #1321 - INST(Vphaddbq , VexRm , V(XOP_M9,C3,_,0,0,_,_,_ ), 0 , 79 , 0 , 8692 , 204, 144), // #1322 - INST(Vphaddbw , VexRm , V(XOP_M9,C1,_,0,0,_,_,_ ), 0 , 79 , 0 , 8701 , 204, 144), // #1323 - INST(Vphaddd , VexRvm_Lx , V(660F38,02,_,x,I,_,_,_ ), 0 , 96 , 0 , 8710 , 202, 148), // #1324 - INST(Vphadddq , VexRm , V(XOP_M9,CB,_,0,0,_,_,_ ), 0 , 79 , 0 , 8718 , 204, 144), // #1325 - INST(Vphaddsw , VexRvm_Lx , V(660F38,03,_,x,I,_,_,_ ), 0 , 96 , 0 , 8727 , 202, 148), // #1326 - INST(Vphaddubd , VexRm , V(XOP_M9,D2,_,0,0,_,_,_ ), 0 , 79 , 0 , 8736 , 204, 144), // #1327 - INST(Vphaddubq , VexRm , V(XOP_M9,D3,_,0,0,_,_,_ ), 0 , 79 , 0 , 8746 , 204, 144), // #1328 - INST(Vphaddubw , VexRm , V(XOP_M9,D1,_,0,0,_,_,_ ), 0 , 79 , 0 , 8756 , 204, 144), // #1329 - INST(Vphaddudq , VexRm , V(XOP_M9,DB,_,0,0,_,_,_ ), 0 , 79 , 0 , 8766 , 204, 144), // #1330 - INST(Vphadduwd , VexRm , V(XOP_M9,D6,_,0,0,_,_,_ ), 0 , 79 , 0 , 8776 , 204, 144), // #1331 - INST(Vphadduwq , VexRm , V(XOP_M9,D7,_,0,0,_,_,_ ), 0 , 79 , 0 , 8786 , 204, 144), // #1332 - INST(Vphaddw , VexRvm_Lx , V(660F38,01,_,x,I,_,_,_ ), 0 , 96 , 0 , 8796 , 202, 148), // #1333 - INST(Vphaddwd , VexRm , V(XOP_M9,C6,_,0,0,_,_,_ ), 0 , 79 , 0 , 8804 , 204, 144), // #1334 - INST(Vphaddwq , VexRm , V(XOP_M9,C7,_,0,0,_,_,_ ), 0 , 79 , 0 , 8813 , 204, 144), // #1335 - INST(Vphminposuw , VexRm , V(660F38,41,_,0,I,_,_,_ ), 0 , 96 , 0 , 8822 , 204, 128), // #1336 - INST(Vphsubbw , VexRm , V(XOP_M9,E1,_,0,0,_,_,_ ), 0 , 79 , 0 , 8834 , 204, 144), // #1337 - INST(Vphsubd , VexRvm_Lx , V(660F38,06,_,x,I,_,_,_ ), 0 , 96 , 0 , 8843 , 202, 148), // #1338 - INST(Vphsubdq , VexRm , V(XOP_M9,E3,_,0,0,_,_,_ ), 0 , 79 , 0 , 8851 , 204, 144), // #1339 - INST(Vphsubsw , VexRvm_Lx , V(660F38,07,_,x,I,_,_,_ ), 0 , 96 , 0 , 8860 , 202, 148), // #1340 - INST(Vphsubw , VexRvm_Lx , V(660F38,05,_,x,I,_,_,_ ), 0 , 96 , 0 , 8869 , 202, 148), // #1341 - INST(Vphsubwd , VexRm , V(XOP_M9,E2,_,0,0,_,_,_ ), 0 , 79 , 0 , 8877 , 204, 144), // #1342 - INST(Vpinsrb , VexRvmi , V(660F3A,20,_,0,0,I,0,T1S), 0 , 73 , 0 , 8886 , 385, 159), // #1343 - INST(Vpinsrd , VexRvmi , V(660F3A,22,_,0,0,0,2,T1S), 0 , 177, 0 , 8894 , 386, 160), // #1344 - INST(Vpinsrq , VexRvmi , V(660F3A,22,_,0,1,1,3,T1S), 0 , 213, 0 , 8902 , 387, 160), // #1345 - INST(Vpinsrw , VexRvmi , V(660F00,C4,_,0,0,I,1,T1S), 0 , 215, 0 , 8910 , 388, 159), // #1346 - INST(Vplzcntd , VexRm_Lx , E(660F38,44,_,x,_,0,4,FV ), 0 , 114, 0 , 8918 , 374, 153), // #1347 - INST(Vplzcntq , VexRm_Lx , E(660F38,44,_,x,_,1,4,FV ), 0 , 113, 0 , 8927 , 350, 153), // #1348 - INST(Vpmacsdd , VexRvmr , V(XOP_M8,9E,_,0,0,_,_,_ ), 0 , 208, 0 , 8936 , 389, 144), // #1349 - INST(Vpmacsdqh , VexRvmr , V(XOP_M8,9F,_,0,0,_,_,_ ), 0 , 208, 0 , 8945 , 389, 144), // #1350 - INST(Vpmacsdql , VexRvmr , V(XOP_M8,97,_,0,0,_,_,_ ), 0 , 208, 0 , 8955 , 389, 144), // #1351 - INST(Vpmacssdd , VexRvmr , V(XOP_M8,8E,_,0,0,_,_,_ ), 0 , 208, 0 , 8965 , 389, 144), // #1352 - INST(Vpmacssdqh , VexRvmr , V(XOP_M8,8F,_,0,0,_,_,_ ), 0 , 208, 0 , 8975 , 389, 144), // #1353 - INST(Vpmacssdql , VexRvmr , V(XOP_M8,87,_,0,0,_,_,_ ), 0 , 208, 0 , 8986 , 389, 144), // #1354 - INST(Vpmacsswd , VexRvmr , V(XOP_M8,86,_,0,0,_,_,_ ), 0 , 208, 0 , 8997 , 389, 144), // #1355 - INST(Vpmacssww , VexRvmr , V(XOP_M8,85,_,0,0,_,_,_ ), 0 , 208, 0 , 9007 , 389, 144), // #1356 - INST(Vpmacswd , VexRvmr , V(XOP_M8,96,_,0,0,_,_,_ ), 0 , 208, 0 , 9017 , 389, 144), // #1357 - INST(Vpmacsww , VexRvmr , V(XOP_M8,95,_,0,0,_,_,_ ), 0 , 208, 0 , 9026 , 389, 144), // #1358 - INST(Vpmadcsswd , VexRvmr , V(XOP_M8,A6,_,0,0,_,_,_ ), 0 , 208, 0 , 9035 , 389, 144), // #1359 - INST(Vpmadcswd , VexRvmr , V(XOP_M8,B6,_,0,0,_,_,_ ), 0 , 208, 0 , 9046 , 389, 144), // #1360 - INST(Vpmadd52huq , VexRvm_Lx , E(660F38,B5,_,x,_,1,4,FV ), 0 , 113, 0 , 9056 , 212, 161), // #1361 - INST(Vpmadd52luq , VexRvm_Lx , E(660F38,B4,_,x,_,1,4,FV ), 0 , 113, 0 , 9068 , 212, 161), // #1362 - INST(Vpmaddubsw , VexRvm_Lx , V(660F38,04,_,x,I,I,4,FVM), 0 , 110, 0 , 9080 , 315, 151), // #1363 - INST(Vpmaddwd , VexRvm_Lx , V(660F00,F5,_,x,I,I,4,FVM), 0 , 144, 0 , 9091 , 315, 151), // #1364 - INST(Vpmaskmovd , VexRvmMvr_Lx , V(660F38,8C,_,x,0,_,_,_ ), V(660F38,8E,_,x,0,_,_,_ ), 96 , 120, 9100 , 323, 134), // #1365 - INST(Vpmaskmovq , VexRvmMvr_Lx , V(660F38,8C,_,x,1,_,_,_ ), V(660F38,8E,_,x,1,_,_,_ ), 189, 121, 9111 , 323, 134), // #1366 - INST(Vpmaxsb , VexRvm_Lx , V(660F38,3C,_,x,I,I,4,FVM), 0 , 110, 0 , 9122 , 390, 151), // #1367 - INST(Vpmaxsd , VexRvm_Lx , V(660F38,3D,_,x,I,0,4,FV ), 0 , 110, 0 , 9130 , 211, 135), // #1368 - INST(Vpmaxsq , VexRvm_Lx , E(660F38,3D,_,x,_,1,4,FV ), 0 , 113, 0 , 9138 , 212, 131), // #1369 - INST(Vpmaxsw , VexRvm_Lx , V(660F00,EE,_,x,I,I,4,FVM), 0 , 144, 0 , 9146 , 390, 151), // #1370 - INST(Vpmaxub , VexRvm_Lx , V(660F00,DE,_,x,I,I,4,FVM), 0 , 144, 0 , 9154 , 390, 151), // #1371 - INST(Vpmaxud , VexRvm_Lx , V(660F38,3F,_,x,I,0,4,FV ), 0 , 110, 0 , 9162 , 211, 135), // #1372 - INST(Vpmaxuq , VexRvm_Lx , E(660F38,3F,_,x,_,1,4,FV ), 0 , 113, 0 , 9170 , 212, 131), // #1373 - INST(Vpmaxuw , VexRvm_Lx , V(660F38,3E,_,x,I,I,4,FVM), 0 , 110, 0 , 9178 , 390, 151), // #1374 - INST(Vpminsb , VexRvm_Lx , V(660F38,38,_,x,I,I,4,FVM), 0 , 110, 0 , 9186 , 390, 151), // #1375 - INST(Vpminsd , VexRvm_Lx , V(660F38,39,_,x,I,0,4,FV ), 0 , 110, 0 , 9194 , 211, 135), // #1376 - INST(Vpminsq , VexRvm_Lx , E(660F38,39,_,x,_,1,4,FV ), 0 , 113, 0 , 9202 , 212, 131), // #1377 - INST(Vpminsw , VexRvm_Lx , V(660F00,EA,_,x,I,I,4,FVM), 0 , 144, 0 , 9210 , 390, 151), // #1378 - INST(Vpminub , VexRvm_Lx , V(660F00,DA,_,x,I,_,4,FVM), 0 , 144, 0 , 9218 , 390, 151), // #1379 - INST(Vpminud , VexRvm_Lx , V(660F38,3B,_,x,I,0,4,FV ), 0 , 110, 0 , 9226 , 211, 135), // #1380 - INST(Vpminuq , VexRvm_Lx , E(660F38,3B,_,x,_,1,4,FV ), 0 , 113, 0 , 9234 , 212, 131), // #1381 - INST(Vpminuw , VexRvm_Lx , V(660F38,3A,_,x,I,_,4,FVM), 0 , 110, 0 , 9242 , 390, 151), // #1382 - INST(Vpmovb2m , VexRm_Lx , E(F30F38,29,_,x,_,0,_,_ ), 0 , 206, 0 , 9250 , 391, 139), // #1383 - INST(Vpmovd2m , VexRm_Lx , E(F30F38,39,_,x,_,0,_,_ ), 0 , 206, 0 , 9259 , 391, 133), // #1384 - INST(Vpmovdb , VexMr_Lx , E(F30F38,31,_,x,_,0,2,QVM), 0 , 216, 0 , 9268 , 392, 131), // #1385 - INST(Vpmovdw , VexMr_Lx , E(F30F38,33,_,x,_,0,3,HVM), 0 , 217, 0 , 9276 , 393, 131), // #1386 - INST(Vpmovm2b , VexRm_Lx , E(F30F38,28,_,x,_,0,_,_ ), 0 , 206, 0 , 9284 , 360, 139), // #1387 - INST(Vpmovm2d , VexRm_Lx , E(F30F38,38,_,x,_,0,_,_ ), 0 , 206, 0 , 9293 , 360, 133), // #1388 - INST(Vpmovm2q , VexRm_Lx , E(F30F38,38,_,x,_,1,_,_ ), 0 , 205, 0 , 9302 , 360, 133), // #1389 - INST(Vpmovm2w , VexRm_Lx , E(F30F38,28,_,x,_,1,_,_ ), 0 , 205, 0 , 9311 , 360, 139), // #1390 - INST(Vpmovmskb , VexRm_Lx , V(660F00,D7,_,x,I,_,_,_ ), 0 , 69 , 0 , 9320 , 336, 148), // #1391 - INST(Vpmovq2m , VexRm_Lx , E(F30F38,39,_,x,_,1,_,_ ), 0 , 205, 0 , 9330 , 391, 133), // #1392 - INST(Vpmovqb , VexMr_Lx , E(F30F38,32,_,x,_,0,1,OVM), 0 , 218, 0 , 9339 , 394, 131), // #1393 - INST(Vpmovqd , VexMr_Lx , E(F30F38,35,_,x,_,0,3,HVM), 0 , 217, 0 , 9347 , 393, 131), // #1394 - INST(Vpmovqw , VexMr_Lx , E(F30F38,34,_,x,_,0,2,QVM), 0 , 216, 0 , 9355 , 392, 131), // #1395 - INST(Vpmovsdb , VexMr_Lx , E(F30F38,21,_,x,_,0,2,QVM), 0 , 216, 0 , 9363 , 392, 131), // #1396 - INST(Vpmovsdw , VexMr_Lx , E(F30F38,23,_,x,_,0,3,HVM), 0 , 217, 0 , 9372 , 393, 131), // #1397 - INST(Vpmovsqb , VexMr_Lx , E(F30F38,22,_,x,_,0,1,OVM), 0 , 218, 0 , 9381 , 394, 131), // #1398 - INST(Vpmovsqd , VexMr_Lx , E(F30F38,25,_,x,_,0,3,HVM), 0 , 217, 0 , 9390 , 393, 131), // #1399 - INST(Vpmovsqw , VexMr_Lx , E(F30F38,24,_,x,_,0,2,QVM), 0 , 216, 0 , 9399 , 392, 131), // #1400 - INST(Vpmovswb , VexMr_Lx , E(F30F38,20,_,x,_,0,3,HVM), 0 , 217, 0 , 9408 , 393, 139), // #1401 - INST(Vpmovsxbd , VexRm_Lx , V(660F38,21,_,x,I,I,2,QVM), 0 , 219, 0 , 9417 , 395, 135), // #1402 - INST(Vpmovsxbq , VexRm_Lx , V(660F38,22,_,x,I,I,1,OVM), 0 , 220, 0 , 9427 , 396, 135), // #1403 - INST(Vpmovsxbw , VexRm_Lx , V(660F38,20,_,x,I,I,3,HVM), 0 , 139, 0 , 9437 , 397, 151), // #1404 - INST(Vpmovsxdq , VexRm_Lx , V(660F38,25,_,x,I,0,3,HVM), 0 , 139, 0 , 9447 , 397, 135), // #1405 - INST(Vpmovsxwd , VexRm_Lx , V(660F38,23,_,x,I,I,3,HVM), 0 , 139, 0 , 9457 , 397, 135), // #1406 - INST(Vpmovsxwq , VexRm_Lx , V(660F38,24,_,x,I,I,2,QVM), 0 , 219, 0 , 9467 , 395, 135), // #1407 - INST(Vpmovusdb , VexMr_Lx , E(F30F38,11,_,x,_,0,2,QVM), 0 , 216, 0 , 9477 , 392, 131), // #1408 - INST(Vpmovusdw , VexMr_Lx , E(F30F38,13,_,x,_,0,3,HVM), 0 , 217, 0 , 9487 , 393, 131), // #1409 - INST(Vpmovusqb , VexMr_Lx , E(F30F38,12,_,x,_,0,1,OVM), 0 , 218, 0 , 9497 , 394, 131), // #1410 - INST(Vpmovusqd , VexMr_Lx , E(F30F38,15,_,x,_,0,3,HVM), 0 , 217, 0 , 9507 , 393, 131), // #1411 - INST(Vpmovusqw , VexMr_Lx , E(F30F38,14,_,x,_,0,2,QVM), 0 , 216, 0 , 9517 , 392, 131), // #1412 - INST(Vpmovuswb , VexMr_Lx , E(F30F38,10,_,x,_,0,3,HVM), 0 , 217, 0 , 9527 , 393, 139), // #1413 - INST(Vpmovw2m , VexRm_Lx , E(F30F38,29,_,x,_,1,_,_ ), 0 , 205, 0 , 9537 , 391, 139), // #1414 - INST(Vpmovwb , VexMr_Lx , E(F30F38,30,_,x,_,0,3,HVM), 0 , 217, 0 , 9546 , 393, 139), // #1415 - INST(Vpmovzxbd , VexRm_Lx , V(660F38,31,_,x,I,I,2,QVM), 0 , 219, 0 , 9554 , 395, 135), // #1416 - INST(Vpmovzxbq , VexRm_Lx , V(660F38,32,_,x,I,I,1,OVM), 0 , 220, 0 , 9564 , 396, 135), // #1417 - INST(Vpmovzxbw , VexRm_Lx , V(660F38,30,_,x,I,I,3,HVM), 0 , 139, 0 , 9574 , 397, 151), // #1418 - INST(Vpmovzxdq , VexRm_Lx , V(660F38,35,_,x,I,0,3,HVM), 0 , 139, 0 , 9584 , 397, 135), // #1419 - INST(Vpmovzxwd , VexRm_Lx , V(660F38,33,_,x,I,I,3,HVM), 0 , 139, 0 , 9594 , 397, 135), // #1420 - INST(Vpmovzxwq , VexRm_Lx , V(660F38,34,_,x,I,I,2,QVM), 0 , 219, 0 , 9604 , 395, 135), // #1421 - INST(Vpmuldq , VexRvm_Lx , V(660F38,28,_,x,I,1,4,FV ), 0 , 209, 0 , 9614 , 208, 135), // #1422 - INST(Vpmulhrsw , VexRvm_Lx , V(660F38,0B,_,x,I,I,4,FVM), 0 , 110, 0 , 9622 , 315, 151), // #1423 - INST(Vpmulhuw , VexRvm_Lx , V(660F00,E4,_,x,I,I,4,FVM), 0 , 144, 0 , 9632 , 315, 151), // #1424 - INST(Vpmulhw , VexRvm_Lx , V(660F00,E5,_,x,I,I,4,FVM), 0 , 144, 0 , 9641 , 315, 151), // #1425 - INST(Vpmulld , VexRvm_Lx , V(660F38,40,_,x,I,0,4,FV ), 0 , 110, 0 , 9649 , 209, 135), // #1426 - INST(Vpmullq , VexRvm_Lx , E(660F38,40,_,x,_,1,4,FV ), 0 , 113, 0 , 9657 , 212, 133), // #1427 - INST(Vpmullw , VexRvm_Lx , V(660F00,D5,_,x,I,I,4,FVM), 0 , 144, 0 , 9665 , 315, 151), // #1428 - INST(Vpmultishiftqb , VexRvm_Lx , E(660F38,83,_,x,_,1,4,FV ), 0 , 113, 0 , 9673 , 212, 158), // #1429 - INST(Vpmuludq , VexRvm_Lx , V(660F00,F4,_,x,I,1,4,FV ), 0 , 103, 0 , 9688 , 208, 135), // #1430 - INST(Vpopcntb , VexRm_Lx , E(660F38,54,_,x,_,0,4,FV ), 0 , 114, 0 , 9697 , 279, 162), // #1431 - INST(Vpopcntd , VexRm_Lx , E(660F38,55,_,x,_,0,4,FVM), 0 , 114, 0 , 9706 , 374, 163), // #1432 - INST(Vpopcntq , VexRm_Lx , E(660F38,55,_,x,_,1,4,FVM), 0 , 113, 0 , 9715 , 350, 163), // #1433 - INST(Vpopcntw , VexRm_Lx , E(660F38,54,_,x,_,1,4,FV ), 0 , 113, 0 , 9724 , 279, 162), // #1434 - INST(Vpor , VexRvm_Lx , V(660F00,EB,_,x,I,_,_,_ ), 0 , 69 , 0 , 9733 , 351, 148), // #1435 - INST(Vpord , VexRvm_Lx , E(660F00,EB,_,x,_,0,4,FV ), 0 , 198, 0 , 9738 , 352, 131), // #1436 - INST(Vporq , VexRvm_Lx , E(660F00,EB,_,x,_,1,4,FV ), 0 , 135, 0 , 9744 , 356, 131), // #1437 - INST(Vpperm , VexRvrmRvmr , V(XOP_M8,A3,_,0,x,_,_,_ ), 0 , 208, 0 , 9750 , 398, 144), // #1438 - INST(Vprold , VexVmi_Lx , E(660F00,72,1,x,_,0,4,FV ), 0 , 221, 0 , 9757 , 399, 131), // #1439 - INST(Vprolq , VexVmi_Lx , E(660F00,72,1,x,_,1,4,FV ), 0 , 222, 0 , 9764 , 400, 131), // #1440 - INST(Vprolvd , VexRvm_Lx , E(660F38,15,_,x,_,0,4,FV ), 0 , 114, 0 , 9771 , 213, 131), // #1441 - INST(Vprolvq , VexRvm_Lx , E(660F38,15,_,x,_,1,4,FV ), 0 , 113, 0 , 9779 , 212, 131), // #1442 - INST(Vprord , VexVmi_Lx , E(660F00,72,0,x,_,0,4,FV ), 0 , 198, 0 , 9787 , 399, 131), // #1443 - INST(Vprorq , VexVmi_Lx , E(660F00,72,0,x,_,1,4,FV ), 0 , 135, 0 , 9794 , 400, 131), // #1444 - INST(Vprorvd , VexRvm_Lx , E(660F38,14,_,x,_,0,4,FV ), 0 , 114, 0 , 9801 , 213, 131), // #1445 - INST(Vprorvq , VexRvm_Lx , E(660F38,14,_,x,_,1,4,FV ), 0 , 113, 0 , 9809 , 212, 131), // #1446 - INST(Vprotb , VexRvmRmvRmi , V(XOP_M9,90,_,0,x,_,_,_ ), V(XOP_M8,C0,_,0,x,_,_,_ ), 79 , 122, 9817 , 401, 144), // #1447 - INST(Vprotd , VexRvmRmvRmi , V(XOP_M9,92,_,0,x,_,_,_ ), V(XOP_M8,C2,_,0,x,_,_,_ ), 79 , 123, 9824 , 401, 144), // #1448 - INST(Vprotq , VexRvmRmvRmi , V(XOP_M9,93,_,0,x,_,_,_ ), V(XOP_M8,C3,_,0,x,_,_,_ ), 79 , 124, 9831 , 401, 144), // #1449 - INST(Vprotw , VexRvmRmvRmi , V(XOP_M9,91,_,0,x,_,_,_ ), V(XOP_M8,C1,_,0,x,_,_,_ ), 79 , 125, 9838 , 401, 144), // #1450 - INST(Vpsadbw , VexRvm_Lx , V(660F00,F6,_,x,I,I,4,FVM), 0 , 144, 0 , 9845 , 203, 151), // #1451 - INST(Vpscatterdd , VexMr_VM , E(660F38,A0,_,x,_,0,2,T1S), 0 , 129, 0 , 9853 , 402, 131), // #1452 - INST(Vpscatterdq , VexMr_VM , E(660F38,A0,_,x,_,1,3,T1S), 0 , 128, 0 , 9865 , 403, 131), // #1453 - INST(Vpscatterqd , VexMr_VM , E(660F38,A1,_,x,_,0,2,T1S), 0 , 129, 0 , 9877 , 404, 131), // #1454 - INST(Vpscatterqq , VexMr_VM , E(660F38,A1,_,x,_,1,3,T1S), 0 , 128, 0 , 9889 , 405, 131), // #1455 - INST(Vpshab , VexRvmRmv , V(XOP_M9,98,_,0,x,_,_,_ ), 0 , 79 , 0 , 9901 , 406, 144), // #1456 - INST(Vpshad , VexRvmRmv , V(XOP_M9,9A,_,0,x,_,_,_ ), 0 , 79 , 0 , 9908 , 406, 144), // #1457 - INST(Vpshaq , VexRvmRmv , V(XOP_M9,9B,_,0,x,_,_,_ ), 0 , 79 , 0 , 9915 , 406, 144), // #1458 - INST(Vpshaw , VexRvmRmv , V(XOP_M9,99,_,0,x,_,_,_ ), 0 , 79 , 0 , 9922 , 406, 144), // #1459 - INST(Vpshlb , VexRvmRmv , V(XOP_M9,94,_,0,x,_,_,_ ), 0 , 79 , 0 , 9929 , 406, 144), // #1460 - INST(Vpshld , VexRvmRmv , V(XOP_M9,96,_,0,x,_,_,_ ), 0 , 79 , 0 , 9936 , 406, 144), // #1461 - INST(Vpshldd , VexRvmi_Lx , E(660F3A,71,_,x,_,0,4,FV ), 0 , 111, 0 , 9943 , 206, 156), // #1462 - INST(Vpshldq , VexRvmi_Lx , E(660F3A,71,_,x,_,1,4,FV ), 0 , 112, 0 , 9951 , 207, 156), // #1463 - INST(Vpshldvd , VexRvm_Lx , E(660F38,71,_,x,_,0,4,FV ), 0 , 114, 0 , 9959 , 213, 156), // #1464 - INST(Vpshldvq , VexRvm_Lx , E(660F38,71,_,x,_,1,4,FV ), 0 , 113, 0 , 9968 , 212, 156), // #1465 - INST(Vpshldvw , VexRvm_Lx , E(660F38,70,_,x,_,1,4,FVM), 0 , 113, 0 , 9977 , 357, 156), // #1466 - INST(Vpshldw , VexRvmi_Lx , E(660F3A,70,_,x,_,1,4,FVM), 0 , 112, 0 , 9986 , 275, 156), // #1467 - INST(Vpshlq , VexRvmRmv , V(XOP_M9,97,_,0,x,_,_,_ ), 0 , 79 , 0 , 9994 , 406, 144), // #1468 - INST(Vpshlw , VexRvmRmv , V(XOP_M9,95,_,0,x,_,_,_ ), 0 , 79 , 0 , 10001, 406, 144), // #1469 - INST(Vpshrdd , VexRvmi_Lx , E(660F3A,73,_,x,_,0,4,FV ), 0 , 111, 0 , 10008, 206, 156), // #1470 - INST(Vpshrdq , VexRvmi_Lx , E(660F3A,73,_,x,_,1,4,FV ), 0 , 112, 0 , 10016, 207, 156), // #1471 - INST(Vpshrdvd , VexRvm_Lx , E(660F38,73,_,x,_,0,4,FV ), 0 , 114, 0 , 10024, 213, 156), // #1472 - INST(Vpshrdvq , VexRvm_Lx , E(660F38,73,_,x,_,1,4,FV ), 0 , 113, 0 , 10033, 212, 156), // #1473 - INST(Vpshrdvw , VexRvm_Lx , E(660F38,72,_,x,_,1,4,FVM), 0 , 113, 0 , 10042, 357, 156), // #1474 - INST(Vpshrdw , VexRvmi_Lx , E(660F3A,72,_,x,_,1,4,FVM), 0 , 112, 0 , 10051, 275, 156), // #1475 - INST(Vpshufb , VexRvm_Lx , V(660F38,00,_,x,I,I,4,FVM), 0 , 110, 0 , 10059, 315, 151), // #1476 - INST(Vpshufbitqmb , VexRvm_Lx , E(660F38,8F,_,x,0,0,4,FVM), 0 , 114, 0 , 10067, 407, 162), // #1477 - INST(Vpshufd , VexRmi_Lx , V(660F00,70,_,x,I,0,4,FV ), 0 , 144, 0 , 10080, 408, 135), // #1478 - INST(Vpshufhw , VexRmi_Lx , V(F30F00,70,_,x,I,I,4,FVM), 0 , 161, 0 , 10088, 409, 151), // #1479 - INST(Vpshuflw , VexRmi_Lx , V(F20F00,70,_,x,I,I,4,FVM), 0 , 223, 0 , 10097, 409, 151), // #1480 - INST(Vpsignb , VexRvm_Lx , V(660F38,08,_,x,I,_,_,_ ), 0 , 96 , 0 , 10106, 202, 148), // #1481 - INST(Vpsignd , VexRvm_Lx , V(660F38,0A,_,x,I,_,_,_ ), 0 , 96 , 0 , 10114, 202, 148), // #1482 - INST(Vpsignw , VexRvm_Lx , V(660F38,09,_,x,I,_,_,_ ), 0 , 96 , 0 , 10122, 202, 148), // #1483 - INST(Vpslld , VexRvmVmi_Lx_MEvex , V(660F00,F2,_,x,I,0,4,128), V(660F00,72,6,x,I,0,4,FV ), 224, 126, 10130, 410, 135), // #1484 - INST(Vpslldq , VexVmi_Lx_MEvex , V(660F00,73,7,x,I,I,4,FVM), 0 , 225, 0 , 10137, 411, 151), // #1485 - INST(Vpsllq , VexRvmVmi_Lx_MEvex , V(660F00,F3,_,x,I,1,4,128), V(660F00,73,6,x,I,1,4,FV ), 226, 127, 10145, 412, 135), // #1486 - INST(Vpsllvd , VexRvm_Lx , V(660F38,47,_,x,0,0,4,FV ), 0 , 110, 0 , 10152, 209, 145), // #1487 - INST(Vpsllvq , VexRvm_Lx , V(660F38,47,_,x,1,1,4,FV ), 0 , 182, 0 , 10160, 208, 145), // #1488 - INST(Vpsllvw , VexRvm_Lx , E(660F38,12,_,x,_,1,4,FVM), 0 , 113, 0 , 10168, 357, 139), // #1489 - INST(Vpsllw , VexRvmVmi_Lx_MEvex , V(660F00,F1,_,x,I,I,4,128), V(660F00,71,6,x,I,I,4,FVM), 224, 128, 10176, 413, 151), // #1490 - INST(Vpsrad , VexRvmVmi_Lx_MEvex , V(660F00,E2,_,x,I,0,4,128), V(660F00,72,4,x,I,0,4,FV ), 224, 129, 10183, 410, 135), // #1491 - INST(Vpsraq , VexRvmVmi_Lx_MEvex , E(660F00,E2,_,x,_,1,4,128), E(660F00,72,4,x,_,1,4,FV ), 227, 130, 10190, 414, 131), // #1492 - INST(Vpsravd , VexRvm_Lx , V(660F38,46,_,x,0,0,4,FV ), 0 , 110, 0 , 10197, 209, 145), // #1493 - INST(Vpsravq , VexRvm_Lx , E(660F38,46,_,x,_,1,4,FV ), 0 , 113, 0 , 10205, 212, 131), // #1494 - INST(Vpsravw , VexRvm_Lx , E(660F38,11,_,x,_,1,4,FVM), 0 , 113, 0 , 10213, 357, 139), // #1495 - INST(Vpsraw , VexRvmVmi_Lx_MEvex , V(660F00,E1,_,x,I,I,4,128), V(660F00,71,4,x,I,I,4,FVM), 224, 131, 10221, 413, 151), // #1496 - INST(Vpsrld , VexRvmVmi_Lx_MEvex , V(660F00,D2,_,x,I,0,4,128), V(660F00,72,2,x,I,0,4,FV ), 224, 132, 10228, 410, 135), // #1497 - INST(Vpsrldq , VexVmi_Lx_MEvex , V(660F00,73,3,x,I,I,4,FVM), 0 , 228, 0 , 10235, 411, 151), // #1498 - INST(Vpsrlq , VexRvmVmi_Lx_MEvex , V(660F00,D3,_,x,I,1,4,128), V(660F00,73,2,x,I,1,4,FV ), 226, 133, 10243, 412, 135), // #1499 - INST(Vpsrlvd , VexRvm_Lx , V(660F38,45,_,x,0,0,4,FV ), 0 , 110, 0 , 10250, 209, 145), // #1500 - INST(Vpsrlvq , VexRvm_Lx , V(660F38,45,_,x,1,1,4,FV ), 0 , 182, 0 , 10258, 208, 145), // #1501 - INST(Vpsrlvw , VexRvm_Lx , E(660F38,10,_,x,_,1,4,FVM), 0 , 113, 0 , 10266, 357, 139), // #1502 - INST(Vpsrlw , VexRvmVmi_Lx_MEvex , V(660F00,D1,_,x,I,I,4,128), V(660F00,71,2,x,I,I,4,FVM), 224, 134, 10274, 413, 151), // #1503 - INST(Vpsubb , VexRvm_Lx , V(660F00,F8,_,x,I,I,4,FVM), 0 , 144, 0 , 10281, 415, 151), // #1504 - INST(Vpsubd , VexRvm_Lx , V(660F00,FA,_,x,I,0,4,FV ), 0 , 144, 0 , 10288, 416, 135), // #1505 - INST(Vpsubq , VexRvm_Lx , V(660F00,FB,_,x,I,1,4,FV ), 0 , 103, 0 , 10295, 417, 135), // #1506 - INST(Vpsubsb , VexRvm_Lx , V(660F00,E8,_,x,I,I,4,FVM), 0 , 144, 0 , 10302, 415, 151), // #1507 - INST(Vpsubsw , VexRvm_Lx , V(660F00,E9,_,x,I,I,4,FVM), 0 , 144, 0 , 10310, 415, 151), // #1508 - INST(Vpsubusb , VexRvm_Lx , V(660F00,D8,_,x,I,I,4,FVM), 0 , 144, 0 , 10318, 415, 151), // #1509 - INST(Vpsubusw , VexRvm_Lx , V(660F00,D9,_,x,I,I,4,FVM), 0 , 144, 0 , 10327, 415, 151), // #1510 - INST(Vpsubw , VexRvm_Lx , V(660F00,F9,_,x,I,I,4,FVM), 0 , 144, 0 , 10336, 415, 151), // #1511 - INST(Vpternlogd , VexRvmi_Lx , E(660F3A,25,_,x,_,0,4,FV ), 0 , 111, 0 , 10343, 206, 131), // #1512 - INST(Vpternlogq , VexRvmi_Lx , E(660F3A,25,_,x,_,1,4,FV ), 0 , 112, 0 , 10354, 207, 131), // #1513 - INST(Vptest , VexRm_Lx , V(660F38,17,_,x,I,_,_,_ ), 0 , 96 , 0 , 10365, 298, 155), // #1514 - INST(Vptestmb , VexRvm_Lx , E(660F38,26,_,x,_,0,4,FVM), 0 , 114, 0 , 10372, 407, 139), // #1515 - INST(Vptestmd , VexRvm_Lx , E(660F38,27,_,x,_,0,4,FV ), 0 , 114, 0 , 10381, 418, 131), // #1516 - INST(Vptestmq , VexRvm_Lx , E(660F38,27,_,x,_,1,4,FV ), 0 , 113, 0 , 10390, 419, 131), // #1517 - INST(Vptestmw , VexRvm_Lx , E(660F38,26,_,x,_,1,4,FVM), 0 , 113, 0 , 10399, 407, 139), // #1518 - INST(Vptestnmb , VexRvm_Lx , E(F30F38,26,_,x,_,0,4,FVM), 0 , 132, 0 , 10408, 407, 139), // #1519 - INST(Vptestnmd , VexRvm_Lx , E(F30F38,27,_,x,_,0,4,FV ), 0 , 132, 0 , 10418, 418, 131), // #1520 - INST(Vptestnmq , VexRvm_Lx , E(F30F38,27,_,x,_,1,4,FV ), 0 , 229, 0 , 10428, 419, 131), // #1521 - INST(Vptestnmw , VexRvm_Lx , E(F30F38,26,_,x,_,1,4,FVM), 0 , 229, 0 , 10438, 407, 139), // #1522 - INST(Vpunpckhbw , VexRvm_Lx , V(660F00,68,_,x,I,I,4,FVM), 0 , 144, 0 , 10448, 315, 151), // #1523 - INST(Vpunpckhdq , VexRvm_Lx , V(660F00,6A,_,x,I,0,4,FV ), 0 , 144, 0 , 10459, 209, 135), // #1524 - INST(Vpunpckhqdq , VexRvm_Lx , V(660F00,6D,_,x,I,1,4,FV ), 0 , 103, 0 , 10470, 208, 135), // #1525 - INST(Vpunpckhwd , VexRvm_Lx , V(660F00,69,_,x,I,I,4,FVM), 0 , 144, 0 , 10482, 315, 151), // #1526 - INST(Vpunpcklbw , VexRvm_Lx , V(660F00,60,_,x,I,I,4,FVM), 0 , 144, 0 , 10493, 315, 151), // #1527 - INST(Vpunpckldq , VexRvm_Lx , V(660F00,62,_,x,I,0,4,FV ), 0 , 144, 0 , 10504, 209, 135), // #1528 - INST(Vpunpcklqdq , VexRvm_Lx , V(660F00,6C,_,x,I,1,4,FV ), 0 , 103, 0 , 10515, 208, 135), // #1529 - INST(Vpunpcklwd , VexRvm_Lx , V(660F00,61,_,x,I,I,4,FVM), 0 , 144, 0 , 10527, 315, 151), // #1530 - INST(Vpxor , VexRvm_Lx , V(660F00,EF,_,x,I,_,_,_ ), 0 , 69 , 0 , 10538, 353, 148), // #1531 - INST(Vpxord , VexRvm_Lx , E(660F00,EF,_,x,_,0,4,FV ), 0 , 198, 0 , 10544, 354, 131), // #1532 - INST(Vpxorq , VexRvm_Lx , E(660F00,EF,_,x,_,1,4,FV ), 0 , 135, 0 , 10551, 355, 131), // #1533 - INST(Vrangepd , VexRvmi_Lx , E(660F3A,50,_,x,_,1,4,FV ), 0 , 112, 0 , 10558, 285, 133), // #1534 - INST(Vrangeps , VexRvmi_Lx , E(660F3A,50,_,x,_,0,4,FV ), 0 , 111, 0 , 10567, 286, 133), // #1535 - INST(Vrangesd , VexRvmi , E(660F3A,51,_,I,_,1,3,T1S), 0 , 180, 0 , 10576, 287, 66 ), // #1536 - INST(Vrangess , VexRvmi , E(660F3A,51,_,I,_,0,2,T1S), 0 , 181, 0 , 10585, 288, 66 ), // #1537 - INST(Vrcp14pd , VexRm_Lx , E(660F38,4C,_,x,_,1,4,FV ), 0 , 113, 0 , 10594, 350, 131), // #1538 - INST(Vrcp14ps , VexRm_Lx , E(660F38,4C,_,x,_,0,4,FV ), 0 , 114, 0 , 10603, 374, 131), // #1539 - INST(Vrcp14sd , VexRvm , E(660F38,4D,_,I,_,1,3,T1S), 0 , 128, 0 , 10612, 420, 68 ), // #1540 - INST(Vrcp14ss , VexRvm , E(660F38,4D,_,I,_,0,2,T1S), 0 , 129, 0 , 10621, 421, 68 ), // #1541 - INST(Vrcp28pd , VexRm , E(660F38,CA,_,2,_,1,4,FV ), 0 , 170, 0 , 10630, 277, 140), // #1542 - INST(Vrcp28ps , VexRm , E(660F38,CA,_,2,_,0,4,FV ), 0 , 171, 0 , 10639, 278, 140), // #1543 - INST(Vrcp28sd , VexRvm , E(660F38,CB,_,I,_,1,3,T1S), 0 , 128, 0 , 10648, 308, 140), // #1544 - INST(Vrcp28ss , VexRvm , E(660F38,CB,_,I,_,0,2,T1S), 0 , 129, 0 , 10657, 309, 140), // #1545 - INST(Vrcpph , VexRm_Lx , E(66MAP6,4C,_,_,_,0,4,FV ), 0 , 183, 0 , 10666, 422, 127), // #1546 - INST(Vrcpps , VexRm_Lx , V(000F00,53,_,x,I,_,_,_ ), 0 , 72 , 0 , 10673, 298, 128), // #1547 - INST(Vrcpsh , VexRvm , E(66MAP6,4D,_,_,_,0,1,T1S), 0 , 185, 0 , 10680, 423, 127), // #1548 - INST(Vrcpss , VexRvm , V(F30F00,53,_,I,I,_,_,_ ), 0 , 199, 0 , 10687, 424, 128), // #1549 - INST(Vreducepd , VexRmi_Lx , E(660F3A,56,_,x,_,1,4,FV ), 0 , 112, 0 , 10694, 400, 133), // #1550 - INST(Vreduceph , VexRmi_Lx , E(000F3A,56,_,_,_,0,4,FV ), 0 , 123, 0 , 10704, 311, 125), // #1551 - INST(Vreduceps , VexRmi_Lx , E(660F3A,56,_,x,_,0,4,FV ), 0 , 111, 0 , 10714, 399, 133), // #1552 - INST(Vreducesd , VexRvmi , E(660F3A,57,_,I,_,1,3,T1S), 0 , 180, 0 , 10724, 425, 66 ), // #1553 - INST(Vreducesh , VexRvmi , E(000F3A,57,_,_,_,0,1,T1S), 0 , 188, 0 , 10734, 313, 127), // #1554 - INST(Vreducess , VexRvmi , E(660F3A,57,_,I,_,0,2,T1S), 0 , 181, 0 , 10744, 426, 66 ), // #1555 - INST(Vrndscalepd , VexRmi_Lx , E(660F3A,09,_,x,_,1,4,FV ), 0 , 112, 0 , 10754, 310, 131), // #1556 - INST(Vrndscaleph , VexRmi_Lx , E(000F3A,08,_,_,_,0,4,FV ), 0 , 123, 0 , 10766, 311, 125), // #1557 - INST(Vrndscaleps , VexRmi_Lx , E(660F3A,08,_,x,_,0,4,FV ), 0 , 111, 0 , 10778, 312, 131), // #1558 - INST(Vrndscalesd , VexRvmi , E(660F3A,0B,_,I,_,1,3,T1S), 0 , 180, 0 , 10790, 287, 68 ), // #1559 - INST(Vrndscalesh , VexRvmi , E(000F3A,0A,_,_,_,0,1,T1S), 0 , 188, 0 , 10802, 313, 127), // #1560 - INST(Vrndscaless , VexRvmi , E(660F3A,0A,_,I,_,0,2,T1S), 0 , 181, 0 , 10814, 288, 68 ), // #1561 - INST(Vroundpd , VexRmi_Lx , V(660F3A,09,_,x,I,_,_,_ ), 0 , 73 , 0 , 10826, 427, 128), // #1562 - INST(Vroundps , VexRmi_Lx , V(660F3A,08,_,x,I,_,_,_ ), 0 , 73 , 0 , 10835, 427, 128), // #1563 - INST(Vroundsd , VexRvmi , V(660F3A,0B,_,I,I,_,_,_ ), 0 , 73 , 0 , 10844, 428, 128), // #1564 - INST(Vroundss , VexRvmi , V(660F3A,0A,_,I,I,_,_,_ ), 0 , 73 , 0 , 10853, 429, 128), // #1565 - INST(Vrsqrt14pd , VexRm_Lx , E(660F38,4E,_,x,_,1,4,FV ), 0 , 113, 0 , 10862, 350, 131), // #1566 - INST(Vrsqrt14ps , VexRm_Lx , E(660F38,4E,_,x,_,0,4,FV ), 0 , 114, 0 , 10873, 374, 131), // #1567 - INST(Vrsqrt14sd , VexRvm , E(660F38,4F,_,I,_,1,3,T1S), 0 , 128, 0 , 10884, 420, 68 ), // #1568 - INST(Vrsqrt14ss , VexRvm , E(660F38,4F,_,I,_,0,2,T1S), 0 , 129, 0 , 10895, 421, 68 ), // #1569 - INST(Vrsqrt28pd , VexRm , E(660F38,CC,_,2,_,1,4,FV ), 0 , 170, 0 , 10906, 277, 140), // #1570 - INST(Vrsqrt28ps , VexRm , E(660F38,CC,_,2,_,0,4,FV ), 0 , 171, 0 , 10917, 278, 140), // #1571 - INST(Vrsqrt28sd , VexRvm , E(660F38,CD,_,I,_,1,3,T1S), 0 , 128, 0 , 10928, 308, 140), // #1572 - INST(Vrsqrt28ss , VexRvm , E(660F38,CD,_,I,_,0,2,T1S), 0 , 129, 0 , 10939, 309, 140), // #1573 - INST(Vrsqrtph , VexRm_Lx , E(66MAP6,4E,_,_,_,0,4,FV ), 0 , 183, 0 , 10950, 422, 125), // #1574 - INST(Vrsqrtps , VexRm_Lx , V(000F00,52,_,x,I,_,_,_ ), 0 , 72 , 0 , 10959, 298, 128), // #1575 - INST(Vrsqrtsh , VexRvm , E(66MAP6,4F,_,_,_,0,1,T1S), 0 , 185, 0 , 10968, 423, 127), // #1576 - INST(Vrsqrtss , VexRvm , V(F30F00,52,_,I,I,_,_,_ ), 0 , 199, 0 , 10977, 424, 128), // #1577 - INST(Vscalefpd , VexRvm_Lx , E(660F38,2C,_,x,_,1,4,FV ), 0 , 113, 0 , 10986, 430, 131), // #1578 - INST(Vscalefph , VexRvm_Lx , E(66MAP6,2C,_,_,_,0,4,FV ), 0 , 183, 0 , 10996, 197, 125), // #1579 - INST(Vscalefps , VexRvm_Lx , E(660F38,2C,_,x,_,0,4,FV ), 0 , 114, 0 , 11006, 284, 131), // #1580 - INST(Vscalefsd , VexRvm , E(660F38,2D,_,I,_,1,3,T1S), 0 , 128, 0 , 11016, 251, 68 ), // #1581 - INST(Vscalefsh , VexRvm , E(66MAP6,2D,_,_,_,0,1,T1S), 0 , 185, 0 , 11026, 200, 127), // #1582 - INST(Vscalefss , VexRvm , E(660F38,2D,_,I,_,0,2,T1S), 0 , 129, 0 , 11036, 259, 68 ), // #1583 - INST(Vscatterdpd , VexMr_VM , E(660F38,A2,_,x,_,1,3,T1S), 0 , 128, 0 , 11046, 403, 131), // #1584 - INST(Vscatterdps , VexMr_VM , E(660F38,A2,_,x,_,0,2,T1S), 0 , 129, 0 , 11058, 402, 131), // #1585 - INST(Vscatterpf0dpd , VexM_VM , E(660F38,C6,5,2,_,1,3,T1S), 0 , 230, 0 , 11070, 303, 146), // #1586 - INST(Vscatterpf0dps , VexM_VM , E(660F38,C6,5,2,_,0,2,T1S), 0 , 231, 0 , 11085, 304, 146), // #1587 - INST(Vscatterpf0qpd , VexM_VM , E(660F38,C7,5,2,_,1,3,T1S), 0 , 230, 0 , 11100, 305, 146), // #1588 - INST(Vscatterpf0qps , VexM_VM , E(660F38,C7,5,2,_,0,2,T1S), 0 , 231, 0 , 11115, 305, 146), // #1589 - INST(Vscatterpf1dpd , VexM_VM , E(660F38,C6,6,2,_,1,3,T1S), 0 , 232, 0 , 11130, 303, 146), // #1590 - INST(Vscatterpf1dps , VexM_VM , E(660F38,C6,6,2,_,0,2,T1S), 0 , 233, 0 , 11145, 304, 146), // #1591 - INST(Vscatterpf1qpd , VexM_VM , E(660F38,C7,6,2,_,1,3,T1S), 0 , 232, 0 , 11160, 305, 146), // #1592 - INST(Vscatterpf1qps , VexM_VM , E(660F38,C7,6,2,_,0,2,T1S), 0 , 233, 0 , 11175, 305, 146), // #1593 - INST(Vscatterqpd , VexMr_VM , E(660F38,A3,_,x,_,1,3,T1S), 0 , 128, 0 , 11190, 405, 131), // #1594 - INST(Vscatterqps , VexMr_VM , E(660F38,A3,_,x,_,0,2,T1S), 0 , 129, 0 , 11202, 404, 131), // #1595 - INST(Vshuff32x4 , VexRvmi_Lx , E(660F3A,23,_,x,_,0,4,FV ), 0 , 111, 0 , 11214, 431, 131), // #1596 - INST(Vshuff64x2 , VexRvmi_Lx , E(660F3A,23,_,x,_,1,4,FV ), 0 , 112, 0 , 11225, 432, 131), // #1597 - INST(Vshufi32x4 , VexRvmi_Lx , E(660F3A,43,_,x,_,0,4,FV ), 0 , 111, 0 , 11236, 431, 131), // #1598 - INST(Vshufi64x2 , VexRvmi_Lx , E(660F3A,43,_,x,_,1,4,FV ), 0 , 112, 0 , 11247, 432, 131), // #1599 - INST(Vshufpd , VexRvmi_Lx , V(660F00,C6,_,x,I,1,4,FV ), 0 , 103, 0 , 11258, 433, 124), // #1600 - INST(Vshufps , VexRvmi_Lx , V(000F00,C6,_,x,I,0,4,FV ), 0 , 105, 0 , 11266, 434, 124), // #1601 - INST(Vsqrtpd , VexRm_Lx , V(660F00,51,_,x,I,1,4,FV ), 0 , 103, 0 , 11274, 435, 124), // #1602 - INST(Vsqrtph , VexRm_Lx , E(00MAP5,51,_,_,_,0,4,FV ), 0 , 104, 0 , 11282, 246, 125), // #1603 - INST(Vsqrtps , VexRm_Lx , V(000F00,51,_,x,I,0,4,FV ), 0 , 105, 0 , 11290, 235, 124), // #1604 - INST(Vsqrtsd , VexRvm , V(F20F00,51,_,I,I,1,3,T1S), 0 , 106, 0 , 11298, 199, 126), // #1605 - INST(Vsqrtsh , VexRvm , E(F3MAP5,51,_,_,_,0,1,T1S), 0 , 107, 0 , 11306, 200, 127), // #1606 - INST(Vsqrtss , VexRvm , V(F30F00,51,_,I,I,0,2,T1S), 0 , 108, 0 , 11314, 201, 126), // #1607 - INST(Vstmxcsr , VexM , V(000F00,AE,3,0,I,_,_,_ ), 0 , 234, 0 , 11322, 321, 128), // #1608 - INST(Vsubpd , VexRvm_Lx , V(660F00,5C,_,x,I,1,4,FV ), 0 , 103, 0 , 11331, 196, 124), // #1609 - INST(Vsubph , VexRvm_Lx , E(00MAP5,5C,_,_,_,0,4,FV ), 0 , 104, 0 , 11338, 197, 125), // #1610 - INST(Vsubps , VexRvm_Lx , V(000F00,5C,_,x,I,0,4,FV ), 0 , 105, 0 , 11345, 198, 124), // #1611 - INST(Vsubsd , VexRvm , V(F20F00,5C,_,I,I,1,3,T1S), 0 , 106, 0 , 11352, 199, 126), // #1612 - INST(Vsubsh , VexRvm , E(F3MAP5,5C,_,_,_,0,1,T1S), 0 , 107, 0 , 11359, 200, 127), // #1613 - INST(Vsubss , VexRvm , V(F30F00,5C,_,I,I,0,2,T1S), 0 , 108, 0 , 11366, 201, 126), // #1614 - INST(Vtestpd , VexRm_Lx , V(660F38,0F,_,x,0,_,_,_ ), 0 , 96 , 0 , 11373, 298, 155), // #1615 - INST(Vtestps , VexRm_Lx , V(660F38,0E,_,x,0,_,_,_ ), 0 , 96 , 0 , 11381, 298, 155), // #1616 - INST(Vucomisd , VexRm , V(660F00,2E,_,I,I,1,3,T1S), 0 , 125, 0 , 11389, 229, 136), // #1617 - INST(Vucomish , VexRm , E(00MAP5,2E,_,_,_,0,1,T1S), 0 , 126, 0 , 11398, 230, 127), // #1618 - INST(Vucomiss , VexRm , V(000F00,2E,_,I,I,0,2,T1S), 0 , 127, 0 , 11407, 231, 136), // #1619 - INST(Vunpckhpd , VexRvm_Lx , V(660F00,15,_,x,I,1,4,FV ), 0 , 103, 0 , 11416, 208, 124), // #1620 - INST(Vunpckhps , VexRvm_Lx , V(000F00,15,_,x,I,0,4,FV ), 0 , 105, 0 , 11426, 209, 124), // #1621 - INST(Vunpcklpd , VexRvm_Lx , V(660F00,14,_,x,I,1,4,FV ), 0 , 103, 0 , 11436, 208, 124), // #1622 - INST(Vunpcklps , VexRvm_Lx , V(000F00,14,_,x,I,0,4,FV ), 0 , 105, 0 , 11446, 209, 124), // #1623 - INST(Vxorpd , VexRvm_Lx , V(660F00,57,_,x,I,1,4,FV ), 0 , 103, 0 , 11456, 417, 132), // #1624 - INST(Vxorps , VexRvm_Lx , V(000F00,57,_,x,I,0,4,FV ), 0 , 105, 0 , 11463, 416, 132), // #1625 - INST(Vzeroall , VexOp , V(000F00,77,_,1,I,_,_,_ ), 0 , 68 , 0 , 11470, 436, 128), // #1626 - INST(Vzeroupper , VexOp , V(000F00,77,_,0,I,_,_,_ ), 0 , 72 , 0 , 11479, 436, 128), // #1627 - INST(Wbinvd , X86Op , O(000F00,09,_,_,_,_,_,_ ), 0 , 4 , 0 , 11490, 30 , 0 ), // #1628 - INST(Wbnoinvd , X86Op , O(F30F00,09,_,_,_,_,_,_ ), 0 , 6 , 0 , 11497, 30 , 164), // #1629 - INST(Wrfsbase , X86M , O(F30F00,AE,2,_,x,_,_,_ ), 0 , 235, 0 , 11506, 173, 104), // #1630 - INST(Wrgsbase , X86M , O(F30F00,AE,3,_,x,_,_,_ ), 0 , 236, 0 , 11515, 173, 104), // #1631 - INST(Wrmsr , X86Op , O(000F00,30,_,_,_,_,_,_ ), 0 , 4 , 0 , 11524, 174, 105), // #1632 - INST(Wrssd , X86Mr , O(000F38,F6,_,_,_,_,_,_ ), 0 , 83 , 0 , 11530, 437, 56 ), // #1633 - INST(Wrssq , X86Mr , O(000F38,F6,_,_,1,_,_,_ ), 0 , 237, 0 , 11536, 438, 56 ), // #1634 - INST(Wrussd , X86Mr , O(660F38,F5,_,_,_,_,_,_ ), 0 , 2 , 0 , 11542, 437, 56 ), // #1635 - INST(Wrussq , X86Mr , O(660F38,F5,_,_,1,_,_,_ ), 0 , 238, 0 , 11549, 438, 56 ), // #1636 - INST(Xabort , X86Op_Mod11RM_I8 , O(000000,C6,7,_,_,_,_,_ ), 0 , 27 , 0 , 11556, 80 , 165), // #1637 - INST(Xadd , X86Xadd , O(000F00,C0,_,_,x,_,_,_ ), 0 , 4 , 0 , 11563, 439, 38 ), // #1638 - INST(Xbegin , X86JmpRel , O(000000,C7,7,_,_,_,_,_ ), 0 , 27 , 0 , 11568, 440, 165), // #1639 - INST(Xchg , X86Xchg , O(000000,86,_,_,x,_,_,_ ), 0 , 0 , 0 , 462 , 441, 0 ), // #1640 - INST(Xend , X86Op , O(000F01,D5,_,_,_,_,_,_ ), 0 , 21 , 0 , 11575, 30 , 165), // #1641 - INST(Xgetbv , X86Op , O(000F01,D0,_,_,_,_,_,_ ), 0 , 21 , 0 , 11580, 174, 166), // #1642 - INST(Xlatb , X86Op , O(000000,D7,_,_,_,_,_,_ ), 0 , 0 , 0 , 11587, 30 , 0 ), // #1643 - INST(Xor , X86Arith , O(000000,30,6,_,x,_,_,_ ), 0 , 32 , 0 , 10540, 179, 1 ), // #1644 - INST(Xorpd , ExtRm , O(660F00,57,_,_,_,_,_,_ ), 0 , 3 , 0 , 11457, 151, 4 ), // #1645 - INST(Xorps , ExtRm , O(000F00,57,_,_,_,_,_,_ ), 0 , 4 , 0 , 11464, 151, 5 ), // #1646 - INST(Xresldtrk , X86Op , O(F20F01,E9,_,_,_,_,_,_ ), 0 , 92 , 0 , 11593, 30 , 167), // #1647 - INST(Xrstor , X86M_Only_EDX_EAX , O(000F00,AE,5,_,_,_,_,_ ), 0 , 77 , 0 , 1164 , 442, 166), // #1648 - INST(Xrstor64 , X86M_Only_EDX_EAX , O(000F00,AE,5,_,1,_,_,_ ), 0 , 239, 0 , 1172 , 443, 166), // #1649 - INST(Xrstors , X86M_Only_EDX_EAX , O(000F00,C7,3,_,_,_,_,_ ), 0 , 78 , 0 , 11603, 442, 168), // #1650 - INST(Xrstors64 , X86M_Only_EDX_EAX , O(000F00,C7,3,_,1,_,_,_ ), 0 , 240, 0 , 11611, 443, 168), // #1651 - INST(Xsave , X86M_Only_EDX_EAX , O(000F00,AE,4,_,_,_,_,_ ), 0 , 97 , 0 , 1182 , 442, 166), // #1652 - INST(Xsave64 , X86M_Only_EDX_EAX , O(000F00,AE,4,_,1,_,_,_ ), 0 , 241, 0 , 1189 , 443, 166), // #1653 - INST(Xsavec , X86M_Only_EDX_EAX , O(000F00,C7,4,_,_,_,_,_ ), 0 , 97 , 0 , 11621, 442, 169), // #1654 - INST(Xsavec64 , X86M_Only_EDX_EAX , O(000F00,C7,4,_,1,_,_,_ ), 0 , 241, 0 , 11628, 443, 169), // #1655 - INST(Xsaveopt , X86M_Only_EDX_EAX , O(000F00,AE,6,_,_,_,_,_ ), 0 , 80 , 0 , 11637, 442, 170), // #1656 - INST(Xsaveopt64 , X86M_Only_EDX_EAX , O(000F00,AE,6,_,1,_,_,_ ), 0 , 242, 0 , 11646, 443, 170), // #1657 - INST(Xsaves , X86M_Only_EDX_EAX , O(000F00,C7,5,_,_,_,_,_ ), 0 , 77 , 0 , 11657, 442, 168), // #1658 - INST(Xsaves64 , X86M_Only_EDX_EAX , O(000F00,C7,5,_,1,_,_,_ ), 0 , 239, 0 , 11664, 443, 168), // #1659 - INST(Xsetbv , X86Op , O(000F01,D1,_,_,_,_,_,_ ), 0 , 21 , 0 , 11673, 174, 166), // #1660 - INST(Xsusldtrk , X86Op , O(F20F01,E8,_,_,_,_,_,_ ), 0 , 92 , 0 , 11680, 30 , 167), // #1661 - INST(Xtest , X86Op , O(000F01,D6,_,_,_,_,_,_ ), 0 , 21 , 0 , 11690, 30 , 171) // #1662 + INST(None , None , 0 , 0 , 0 , 0 , 0 , 0 ), // #0 + INST(Aaa , X86Op_xAX , O(000000,37,_,_,_,_,_,_ ), 0 , 0 , 0 , 1 , 1 ), // #1 + INST(Aad , X86I_xAX , O(000000,D5,_,_,_,_,_,_ ), 0 , 0 , 0 , 2 , 1 ), // #2 + INST(Aam , X86I_xAX , O(000000,D4,_,_,_,_,_,_ ), 0 , 0 , 0 , 2 , 1 ), // #3 + INST(Aas , X86Op_xAX , O(000000,3F,_,_,_,_,_,_ ), 0 , 0 , 0 , 1 , 1 ), // #4 + INST(Adc , X86Arith , O(000000,10,2,_,x,_,_,_ ), 0 , 1 , 0 , 3 , 2 ), // #5 + INST(Adcx , X86Rm , O(660F38,F6,_,_,x,_,_,_ ), 0 , 2 , 0 , 4 , 3 ), // #6 + INST(Add , X86Arith , O(000000,00,0,_,x,_,_,_ ), 0 , 0 , 0 , 3 , 1 ), // #7 + INST(Addpd , ExtRm , O(660F00,58,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #8 + INST(Addps , ExtRm , O(000F00,58,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #9 + INST(Addsd , ExtRm , O(F20F00,58,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #10 + INST(Addss , ExtRm , O(F30F00,58,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #11 + INST(Addsubpd , ExtRm , O(660F00,D0,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 6 ), // #12 + INST(Addsubps , ExtRm , O(F20F00,D0,_,_,_,_,_,_ ), 0 , 5 , 0 , 5 , 6 ), // #13 + INST(Adox , X86Rm , O(F30F38,F6,_,_,x,_,_,_ ), 0 , 7 , 0 , 4 , 7 ), // #14 + INST(Aesdec , ExtRm , O(660F38,DE,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 8 ), // #15 + INST(Aesdeclast , ExtRm , O(660F38,DF,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 8 ), // #16 + INST(Aesenc , ExtRm , O(660F38,DC,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 8 ), // #17 + INST(Aesenclast , ExtRm , O(660F38,DD,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 8 ), // #18 + INST(Aesimc , ExtRm , O(660F38,DB,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 8 ), // #19 + INST(Aeskeygenassist , ExtRmi , O(660F3A,DF,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 8 ), // #20 + INST(And , X86Arith , O(000000,20,4,_,x,_,_,_ ), 0 , 9 , 0 , 9 , 1 ), // #21 + INST(Andn , VexRvm_Wx , V(000F38,F2,_,0,x,_,_,_ ), 0 , 10 , 0 , 10 , 9 ), // #22 + INST(Andnpd , ExtRm , O(660F00,55,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #23 + INST(Andnps , ExtRm , O(000F00,55,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #24 + INST(Andpd , ExtRm , O(660F00,54,_,_,_,_,_,_ ), 0 , 3 , 0 , 11 , 4 ), // #25 + INST(Andps , ExtRm , O(000F00,54,_,_,_,_,_,_ ), 0 , 4 , 0 , 11 , 5 ), // #26 + INST(Arpl , X86Mr_NoSize , O(000000,63,_,_,_,_,_,_ ), 0 , 0 , 0 , 12 , 10 ), // #27 + INST(Bextr , VexRmv_Wx , V(000F38,F7,_,0,x,_,_,_ ), 0 , 10 , 0 , 13 , 9 ), // #28 + INST(Blcfill , VexVm_Wx , V(XOP_M9,01,1,0,x,_,_,_ ), 0 , 11 , 0 , 14 , 11 ), // #29 + INST(Blci , VexVm_Wx , V(XOP_M9,02,6,0,x,_,_,_ ), 0 , 12 , 0 , 14 , 11 ), // #30 + INST(Blcic , VexVm_Wx , V(XOP_M9,01,5,0,x,_,_,_ ), 0 , 13 , 0 , 14 , 11 ), // #31 + INST(Blcmsk , VexVm_Wx , V(XOP_M9,02,1,0,x,_,_,_ ), 0 , 11 , 0 , 14 , 11 ), // #32 + INST(Blcs , VexVm_Wx , V(XOP_M9,01,3,0,x,_,_,_ ), 0 , 14 , 0 , 14 , 11 ), // #33 + INST(Blendpd , ExtRmi , O(660F3A,0D,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #34 + INST(Blendps , ExtRmi , O(660F3A,0C,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #35 + INST(Blendvpd , ExtRm_XMM0 , O(660F38,15,_,_,_,_,_,_ ), 0 , 2 , 0 , 15 , 12 ), // #36 + INST(Blendvps , ExtRm_XMM0 , O(660F38,14,_,_,_,_,_,_ ), 0 , 2 , 0 , 15 , 12 ), // #37 + INST(Blsfill , VexVm_Wx , V(XOP_M9,01,2,0,x,_,_,_ ), 0 , 15 , 0 , 14 , 11 ), // #38 + INST(Blsi , VexVm_Wx , V(000F38,F3,3,0,x,_,_,_ ), 0 , 16 , 0 , 14 , 9 ), // #39 + INST(Blsic , VexVm_Wx , V(XOP_M9,01,6,0,x,_,_,_ ), 0 , 12 , 0 , 14 , 11 ), // #40 + INST(Blsmsk , VexVm_Wx , V(000F38,F3,2,0,x,_,_,_ ), 0 , 17 , 0 , 14 , 9 ), // #41 + INST(Blsr , VexVm_Wx , V(000F38,F3,1,0,x,_,_,_ ), 0 , 18 , 0 , 14 , 9 ), // #42 + INST(Bndcl , X86Rm , O(F30F00,1A,_,_,_,_,_,_ ), 0 , 6 , 0 , 16 , 13 ), // #43 + INST(Bndcn , X86Rm , O(F20F00,1B,_,_,_,_,_,_ ), 0 , 5 , 0 , 16 , 13 ), // #44 + INST(Bndcu , X86Rm , O(F20F00,1A,_,_,_,_,_,_ ), 0 , 5 , 0 , 16 , 13 ), // #45 + INST(Bndldx , X86Rm , O(000F00,1A,_,_,_,_,_,_ ), 0 , 4 , 0 , 17 , 13 ), // #46 + INST(Bndmk , X86Rm , O(F30F00,1B,_,_,_,_,_,_ ), 0 , 6 , 0 , 18 , 13 ), // #47 + INST(Bndmov , X86Bndmov , O(660F00,1A,_,_,_,_,_,_ ), O(660F00,1B,_,_,_,_,_,_ ), 3 , 1 , 19 , 13 ), // #48 + INST(Bndstx , X86Mr , O(000F00,1B,_,_,_,_,_,_ ), 0 , 4 , 0 , 20 , 13 ), // #49 + INST(Bound , X86Rm , O(000000,62,_,_,_,_,_,_ ), 0 , 0 , 0 , 21 , 0 ), // #50 + INST(Bsf , X86Rm , O(000F00,BC,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 1 ), // #51 + INST(Bsr , X86Rm , O(000F00,BD,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 1 ), // #52 + INST(Bswap , X86Bswap , O(000F00,C8,_,_,x,_,_,_ ), 0 , 4 , 0 , 23 , 0 ), // #53 + INST(Bt , X86Bt , O(000F00,A3,_,_,x,_,_,_ ), O(000F00,BA,4,_,x,_,_,_ ), 4 , 2 , 24 , 14 ), // #54 + INST(Btc , X86Bt , O(000F00,BB,_,_,x,_,_,_ ), O(000F00,BA,7,_,x,_,_,_ ), 4 , 3 , 25 , 14 ), // #55 + INST(Btr , X86Bt , O(000F00,B3,_,_,x,_,_,_ ), O(000F00,BA,6,_,x,_,_,_ ), 4 , 4 , 25 , 14 ), // #56 + INST(Bts , X86Bt , O(000F00,AB,_,_,x,_,_,_ ), O(000F00,BA,5,_,x,_,_,_ ), 4 , 5 , 25 , 14 ), // #57 + INST(Bzhi , VexRmv_Wx , V(000F38,F5,_,0,x,_,_,_ ), 0 , 10 , 0 , 13 , 15 ), // #58 + INST(Call , X86Call , O(000000,FF,2,_,_,_,_,_ ), 0 , 1 , 0 , 26 , 1 ), // #59 + INST(Cbw , X86Op_xAX , O(660000,98,_,_,_,_,_,_ ), 0 , 19 , 0 , 27 , 0 ), // #60 + INST(Cdq , X86Op_xDX_xAX , O(000000,99,_,_,_,_,_,_ ), 0 , 0 , 0 , 28 , 0 ), // #61 + INST(Cdqe , X86Op_xAX , O(000000,98,_,_,1,_,_,_ ), 0 , 20 , 0 , 29 , 0 ), // #62 + INST(Clac , X86Op , O(000F01,CA,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 16 ), // #63 + INST(Clc , X86Op , O(000000,F8,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 17 ), // #64 + INST(Cld , X86Op , O(000000,FC,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 18 ), // #65 + INST(Cldemote , X86M_Only , O(000F00,1C,0,_,_,_,_,_ ), 0 , 4 , 0 , 31 , 19 ), // #66 + INST(Clflush , X86M_Only , O(000F00,AE,7,_,_,_,_,_ ), 0 , 22 , 0 , 31 , 20 ), // #67 + INST(Clflushopt , X86M_Only , O(660F00,AE,7,_,_,_,_,_ ), 0 , 23 , 0 , 31 , 21 ), // #68 + INST(Clgi , X86Op , O(000F01,DD,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 22 ), // #69 + INST(Cli , X86Op , O(000000,FA,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 23 ), // #70 + INST(Clrssbsy , X86M_Only , O(F30F00,AE,6,_,_,_,_,_ ), 0 , 24 , 0 , 32 , 24 ), // #71 + INST(Clts , X86Op , O(000F00,06,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 0 ), // #72 + INST(Clui , X86Op , O(F30F01,EE,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 25 ), // #73 + INST(Clwb , X86M_Only , O(660F00,AE,6,_,_,_,_,_ ), 0 , 26 , 0 , 31 , 26 ), // #74 + INST(Clzero , X86Op_MemZAX , O(000F01,FC,_,_,_,_,_,_ ), 0 , 21 , 0 , 34 , 27 ), // #75 + INST(Cmc , X86Op , O(000000,F5,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 28 ), // #76 + INST(Cmova , X86Rm , O(000F00,47,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 29 ), // #77 + INST(Cmovae , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #78 + INST(Cmovb , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #79 + INST(Cmovbe , X86Rm , O(000F00,46,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 29 ), // #80 + INST(Cmovc , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #81 + INST(Cmove , X86Rm , O(000F00,44,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 31 ), // #82 + INST(Cmovg , X86Rm , O(000F00,4F,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 32 ), // #83 + INST(Cmovge , X86Rm , O(000F00,4D,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 33 ), // #84 + INST(Cmovl , X86Rm , O(000F00,4C,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 33 ), // #85 + INST(Cmovle , X86Rm , O(000F00,4E,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 32 ), // #86 + INST(Cmovna , X86Rm , O(000F00,46,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 29 ), // #87 + INST(Cmovnae , X86Rm , O(000F00,42,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #88 + INST(Cmovnb , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #89 + INST(Cmovnbe , X86Rm , O(000F00,47,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 29 ), // #90 + INST(Cmovnc , X86Rm , O(000F00,43,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 30 ), // #91 + INST(Cmovne , X86Rm , O(000F00,45,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 31 ), // #92 + INST(Cmovng , X86Rm , O(000F00,4E,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 32 ), // #93 + INST(Cmovnge , X86Rm , O(000F00,4C,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 33 ), // #94 + INST(Cmovnl , X86Rm , O(000F00,4D,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 33 ), // #95 + INST(Cmovnle , X86Rm , O(000F00,4F,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 32 ), // #96 + INST(Cmovno , X86Rm , O(000F00,41,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 34 ), // #97 + INST(Cmovnp , X86Rm , O(000F00,4B,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 35 ), // #98 + INST(Cmovns , X86Rm , O(000F00,49,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 36 ), // #99 + INST(Cmovnz , X86Rm , O(000F00,45,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 31 ), // #100 + INST(Cmovo , X86Rm , O(000F00,40,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 34 ), // #101 + INST(Cmovp , X86Rm , O(000F00,4A,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 35 ), // #102 + INST(Cmovpe , X86Rm , O(000F00,4A,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 35 ), // #103 + INST(Cmovpo , X86Rm , O(000F00,4B,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 35 ), // #104 + INST(Cmovs , X86Rm , O(000F00,48,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 36 ), // #105 + INST(Cmovz , X86Rm , O(000F00,44,_,_,x,_,_,_ ), 0 , 4 , 0 , 22 , 31 ), // #106 + INST(Cmp , X86Arith , O(000000,38,7,_,x,_,_,_ ), 0 , 27 , 0 , 35 , 1 ), // #107 + INST(Cmppd , ExtRmi , O(660F00,C2,_,_,_,_,_,_ ), 0 , 3 , 0 , 8 , 4 ), // #108 + INST(Cmpps , ExtRmi , O(000F00,C2,_,_,_,_,_,_ ), 0 , 4 , 0 , 8 , 5 ), // #109 + INST(Cmps , X86StrMm , O(000000,A6,_,_,_,_,_,_ ), 0 , 0 , 0 , 36 , 37 ), // #110 + INST(Cmpsd , ExtRmi , O(F20F00,C2,_,_,_,_,_,_ ), 0 , 5 , 0 , 37 , 4 ), // #111 + INST(Cmpss , ExtRmi , O(F30F00,C2,_,_,_,_,_,_ ), 0 , 6 , 0 , 38 , 5 ), // #112 + INST(Cmpxchg , X86Cmpxchg , O(000F00,B0,_,_,x,_,_,_ ), 0 , 4 , 0 , 39 , 38 ), // #113 + INST(Cmpxchg16b , X86Cmpxchg8b_16b , O(000F00,C7,1,_,1,_,_,_ ), 0 , 28 , 0 , 40 , 39 ), // #114 + INST(Cmpxchg8b , X86Cmpxchg8b_16b , O(000F00,C7,1,_,_,_,_,_ ), 0 , 29 , 0 , 41 , 40 ), // #115 + INST(Comisd , ExtRm , O(660F00,2F,_,_,_,_,_,_ ), 0 , 3 , 0 , 6 , 41 ), // #116 + INST(Comiss , ExtRm , O(000F00,2F,_,_,_,_,_,_ ), 0 , 4 , 0 , 7 , 42 ), // #117 + INST(Cpuid , X86Op , O(000F00,A2,_,_,_,_,_,_ ), 0 , 4 , 0 , 42 , 43 ), // #118 + INST(Cqo , X86Op_xDX_xAX , O(000000,99,_,_,1,_,_,_ ), 0 , 20 , 0 , 43 , 0 ), // #119 + INST(Crc32 , X86Crc , O(F20F38,F0,_,_,x,_,_,_ ), 0 , 30 , 0 , 44 , 44 ), // #120 + INST(Cvtdq2pd , ExtRm , O(F30F00,E6,_,_,_,_,_,_ ), 0 , 6 , 0 , 6 , 4 ), // #121 + INST(Cvtdq2ps , ExtRm , O(000F00,5B,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 4 ), // #122 + INST(Cvtpd2dq , ExtRm , O(F20F00,E6,_,_,_,_,_,_ ), 0 , 5 , 0 , 5 , 4 ), // #123 + INST(Cvtpd2pi , ExtRm , O(660F00,2D,_,_,_,_,_,_ ), 0 , 3 , 0 , 45 , 4 ), // #124 + INST(Cvtpd2ps , ExtRm , O(660F00,5A,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #125 + INST(Cvtpi2pd , ExtRm , O(660F00,2A,_,_,_,_,_,_ ), 0 , 3 , 0 , 46 , 4 ), // #126 + INST(Cvtpi2ps , ExtRm , O(000F00,2A,_,_,_,_,_,_ ), 0 , 4 , 0 , 46 , 5 ), // #127 + INST(Cvtps2dq , ExtRm , O(660F00,5B,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #128 + INST(Cvtps2pd , ExtRm , O(000F00,5A,_,_,_,_,_,_ ), 0 , 4 , 0 , 6 , 4 ), // #129 + INST(Cvtps2pi , ExtRm , O(000F00,2D,_,_,_,_,_,_ ), 0 , 4 , 0 , 47 , 5 ), // #130 + INST(Cvtsd2si , ExtRm_Wx_GpqOnly , O(F20F00,2D,_,_,x,_,_,_ ), 0 , 5 , 0 , 48 , 4 ), // #131 + INST(Cvtsd2ss , ExtRm , O(F20F00,5A,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #132 + INST(Cvtsi2sd , ExtRm_Wx , O(F20F00,2A,_,_,x,_,_,_ ), 0 , 5 , 0 , 49 , 4 ), // #133 + INST(Cvtsi2ss , ExtRm_Wx , O(F30F00,2A,_,_,x,_,_,_ ), 0 , 6 , 0 , 49 , 5 ), // #134 + INST(Cvtss2sd , ExtRm , O(F30F00,5A,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 4 ), // #135 + INST(Cvtss2si , ExtRm_Wx_GpqOnly , O(F30F00,2D,_,_,x,_,_,_ ), 0 , 6 , 0 , 50 , 5 ), // #136 + INST(Cvttpd2dq , ExtRm , O(660F00,E6,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #137 + INST(Cvttpd2pi , ExtRm , O(660F00,2C,_,_,_,_,_,_ ), 0 , 3 , 0 , 45 , 4 ), // #138 + INST(Cvttps2dq , ExtRm , O(F30F00,5B,_,_,_,_,_,_ ), 0 , 6 , 0 , 5 , 4 ), // #139 + INST(Cvttps2pi , ExtRm , O(000F00,2C,_,_,_,_,_,_ ), 0 , 4 , 0 , 47 , 5 ), // #140 + INST(Cvttsd2si , ExtRm_Wx_GpqOnly , O(F20F00,2C,_,_,x,_,_,_ ), 0 , 5 , 0 , 48 , 4 ), // #141 + INST(Cvttss2si , ExtRm_Wx_GpqOnly , O(F30F00,2C,_,_,x,_,_,_ ), 0 , 6 , 0 , 50 , 5 ), // #142 + INST(Cwd , X86Op_xDX_xAX , O(660000,99,_,_,_,_,_,_ ), 0 , 19 , 0 , 51 , 0 ), // #143 + INST(Cwde , X86Op_xAX , O(000000,98,_,_,_,_,_,_ ), 0 , 0 , 0 , 52 , 0 ), // #144 + INST(Daa , X86Op , O(000000,27,_,_,_,_,_,_ ), 0 , 0 , 0 , 1 , 1 ), // #145 + INST(Das , X86Op , O(000000,2F,_,_,_,_,_,_ ), 0 , 0 , 0 , 1 , 1 ), // #146 + INST(Dec , X86IncDec , O(000000,FE,1,_,x,_,_,_ ), O(000000,48,_,_,x,_,_,_ ), 31 , 6 , 53 , 45 ), // #147 + INST(Div , X86M_GPB_MulDiv , O(000000,F6,6,_,x,_,_,_ ), 0 , 32 , 0 , 54 , 1 ), // #148 + INST(Divpd , ExtRm , O(660F00,5E,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #149 + INST(Divps , ExtRm , O(000F00,5E,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #150 + INST(Divsd , ExtRm , O(F20F00,5E,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #151 + INST(Divss , ExtRm , O(F30F00,5E,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #152 + INST(Dppd , ExtRmi , O(660F3A,41,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #153 + INST(Dpps , ExtRmi , O(660F3A,40,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #154 + INST(Emms , X86Op , O(000F00,77,_,_,_,_,_,_ ), 0 , 4 , 0 , 55 , 46 ), // #155 + INST(Endbr32 , X86Op_Mod11RM , O(F30F00,1E,7,_,_,_,_,3 ), 0 , 33 , 0 , 30 , 47 ), // #156 + INST(Endbr64 , X86Op_Mod11RM , O(F30F00,1E,7,_,_,_,_,2 ), 0 , 34 , 0 , 30 , 47 ), // #157 + INST(Enqcmd , X86EnqcmdMovdir64b , O(F20F38,F8,_,_,_,_,_,_ ), 0 , 30 , 0 , 56 , 48 ), // #158 + INST(Enqcmds , X86EnqcmdMovdir64b , O(F30F38,F8,_,_,_,_,_,_ ), 0 , 7 , 0 , 56 , 48 ), // #159 + INST(Enter , X86Enter , O(000000,C8,_,_,_,_,_,_ ), 0 , 0 , 0 , 57 , 0 ), // #160 + INST(Extractps , ExtExtract , O(660F3A,17,_,_,_,_,_,_ ), 0 , 8 , 0 , 58 , 12 ), // #161 + INST(Extrq , ExtExtrq , O(660F00,79,_,_,_,_,_,_ ), O(660F00,78,0,_,_,_,_,_ ), 3 , 7 , 59 , 49 ), // #162 + INST(F2xm1 , FpuOp , O_FPU(00,D9F0,_) , 0 , 35 , 0 , 30 , 0 ), // #163 + INST(Fabs , FpuOp , O_FPU(00,D9E1,_) , 0 , 35 , 0 , 30 , 0 ), // #164 + INST(Fadd , FpuArith , O_FPU(00,C0C0,0) , 0 , 36 , 0 , 60 , 0 ), // #165 + INST(Faddp , FpuRDef , O_FPU(00,DEC0,_) , 0 , 37 , 0 , 61 , 0 ), // #166 + INST(Fbld , X86M_Only , O_FPU(00,00DF,4) , 0 , 38 , 0 , 62 , 0 ), // #167 + INST(Fbstp , X86M_Only , O_FPU(00,00DF,6) , 0 , 39 , 0 , 62 , 0 ), // #168 + INST(Fchs , FpuOp , O_FPU(00,D9E0,_) , 0 , 35 , 0 , 30 , 0 ), // #169 + INST(Fclex , FpuOp , O_FPU(9B,DBE2,_) , 0 , 40 , 0 , 30 , 0 ), // #170 + INST(Fcmovb , FpuR , O_FPU(00,DAC0,_) , 0 , 41 , 0 , 63 , 30 ), // #171 + INST(Fcmovbe , FpuR , O_FPU(00,DAD0,_) , 0 , 41 , 0 , 63 , 29 ), // #172 + INST(Fcmove , FpuR , O_FPU(00,DAC8,_) , 0 , 41 , 0 , 63 , 31 ), // #173 + INST(Fcmovnb , FpuR , O_FPU(00,DBC0,_) , 0 , 42 , 0 , 63 , 30 ), // #174 + INST(Fcmovnbe , FpuR , O_FPU(00,DBD0,_) , 0 , 42 , 0 , 63 , 29 ), // #175 + INST(Fcmovne , FpuR , O_FPU(00,DBC8,_) , 0 , 42 , 0 , 63 , 31 ), // #176 + INST(Fcmovnu , FpuR , O_FPU(00,DBD8,_) , 0 , 42 , 0 , 63 , 35 ), // #177 + INST(Fcmovu , FpuR , O_FPU(00,DAD8,_) , 0 , 41 , 0 , 63 , 35 ), // #178 + INST(Fcom , FpuCom , O_FPU(00,D0D0,2) , 0 , 43 , 0 , 64 , 0 ), // #179 + INST(Fcomi , FpuR , O_FPU(00,DBF0,_) , 0 , 42 , 0 , 63 , 50 ), // #180 + INST(Fcomip , FpuR , O_FPU(00,DFF0,_) , 0 , 44 , 0 , 63 , 50 ), // #181 + INST(Fcomp , FpuCom , O_FPU(00,D8D8,3) , 0 , 45 , 0 , 64 , 0 ), // #182 + INST(Fcompp , FpuOp , O_FPU(00,DED9,_) , 0 , 37 , 0 , 30 , 0 ), // #183 + INST(Fcos , FpuOp , O_FPU(00,D9FF,_) , 0 , 35 , 0 , 30 , 0 ), // #184 + INST(Fdecstp , FpuOp , O_FPU(00,D9F6,_) , 0 , 35 , 0 , 30 , 0 ), // #185 + INST(Fdiv , FpuArith , O_FPU(00,F0F8,6) , 0 , 46 , 0 , 60 , 0 ), // #186 + INST(Fdivp , FpuRDef , O_FPU(00,DEF8,_) , 0 , 37 , 0 , 61 , 0 ), // #187 + INST(Fdivr , FpuArith , O_FPU(00,F8F0,7) , 0 , 47 , 0 , 60 , 0 ), // #188 + INST(Fdivrp , FpuRDef , O_FPU(00,DEF0,_) , 0 , 37 , 0 , 61 , 0 ), // #189 + INST(Femms , X86Op , O(000F00,0E,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 51 ), // #190 + INST(Ffree , FpuR , O_FPU(00,DDC0,_) , 0 , 48 , 0 , 63 , 0 ), // #191 + INST(Fiadd , FpuM , O_FPU(00,00DA,0) , 0 , 49 , 0 , 65 , 0 ), // #192 + INST(Ficom , FpuM , O_FPU(00,00DA,2) , 0 , 50 , 0 , 65 , 0 ), // #193 + INST(Ficomp , FpuM , O_FPU(00,00DA,3) , 0 , 51 , 0 , 65 , 0 ), // #194 + INST(Fidiv , FpuM , O_FPU(00,00DA,6) , 0 , 39 , 0 , 65 , 0 ), // #195 + INST(Fidivr , FpuM , O_FPU(00,00DA,7) , 0 , 52 , 0 , 65 , 0 ), // #196 + INST(Fild , FpuM , O_FPU(00,00DB,0) , O_FPU(00,00DF,5) , 49 , 8 , 66 , 0 ), // #197 + INST(Fimul , FpuM , O_FPU(00,00DA,1) , 0 , 53 , 0 , 65 , 0 ), // #198 + INST(Fincstp , FpuOp , O_FPU(00,D9F7,_) , 0 , 35 , 0 , 30 , 0 ), // #199 + INST(Finit , FpuOp , O_FPU(9B,DBE3,_) , 0 , 40 , 0 , 30 , 0 ), // #200 + INST(Fist , FpuM , O_FPU(00,00DB,2) , 0 , 50 , 0 , 65 , 0 ), // #201 + INST(Fistp , FpuM , O_FPU(00,00DB,3) , O_FPU(00,00DF,7) , 51 , 9 , 66 , 0 ), // #202 + INST(Fisttp , FpuM , O_FPU(00,00DB,1) , O_FPU(00,00DD,1) , 53 , 10 , 66 , 6 ), // #203 + INST(Fisub , FpuM , O_FPU(00,00DA,4) , 0 , 38 , 0 , 65 , 0 ), // #204 + INST(Fisubr , FpuM , O_FPU(00,00DA,5) , 0 , 54 , 0 , 65 , 0 ), // #205 + INST(Fld , FpuFldFst , O_FPU(00,00D9,0) , O_FPU(00,00DB,5) , 49 , 11 , 67 , 0 ), // #206 + INST(Fld1 , FpuOp , O_FPU(00,D9E8,_) , 0 , 35 , 0 , 30 , 0 ), // #207 + INST(Fldcw , X86M_Only , O_FPU(00,00D9,5) , 0 , 54 , 0 , 68 , 0 ), // #208 + INST(Fldenv , X86M_Only , O_FPU(00,00D9,4) , 0 , 38 , 0 , 69 , 0 ), // #209 + INST(Fldl2e , FpuOp , O_FPU(00,D9EA,_) , 0 , 35 , 0 , 30 , 0 ), // #210 + INST(Fldl2t , FpuOp , O_FPU(00,D9E9,_) , 0 , 35 , 0 , 30 , 0 ), // #211 + INST(Fldlg2 , FpuOp , O_FPU(00,D9EC,_) , 0 , 35 , 0 , 30 , 0 ), // #212 + INST(Fldln2 , FpuOp , O_FPU(00,D9ED,_) , 0 , 35 , 0 , 30 , 0 ), // #213 + INST(Fldpi , FpuOp , O_FPU(00,D9EB,_) , 0 , 35 , 0 , 30 , 0 ), // #214 + INST(Fldz , FpuOp , O_FPU(00,D9EE,_) , 0 , 35 , 0 , 30 , 0 ), // #215 + INST(Fmul , FpuArith , O_FPU(00,C8C8,1) , 0 , 55 , 0 , 60 , 0 ), // #216 + INST(Fmulp , FpuRDef , O_FPU(00,DEC8,_) , 0 , 37 , 0 , 61 , 0 ), // #217 + INST(Fnclex , FpuOp , O_FPU(00,DBE2,_) , 0 , 42 , 0 , 30 , 0 ), // #218 + INST(Fninit , FpuOp , O_FPU(00,DBE3,_) , 0 , 42 , 0 , 30 , 0 ), // #219 + INST(Fnop , FpuOp , O_FPU(00,D9D0,_) , 0 , 35 , 0 , 30 , 0 ), // #220 + INST(Fnsave , X86M_Only , O_FPU(00,00DD,6) , 0 , 39 , 0 , 69 , 0 ), // #221 + INST(Fnstcw , X86M_Only , O_FPU(00,00D9,7) , 0 , 52 , 0 , 68 , 0 ), // #222 + INST(Fnstenv , X86M_Only , O_FPU(00,00D9,6) , 0 , 39 , 0 , 69 , 0 ), // #223 + INST(Fnstsw , FpuStsw , O_FPU(00,00DD,7) , O_FPU(00,DFE0,_) , 52 , 12 , 70 , 0 ), // #224 + INST(Fpatan , FpuOp , O_FPU(00,D9F3,_) , 0 , 35 , 0 , 30 , 0 ), // #225 + INST(Fprem , FpuOp , O_FPU(00,D9F8,_) , 0 , 35 , 0 , 30 , 0 ), // #226 + INST(Fprem1 , FpuOp , O_FPU(00,D9F5,_) , 0 , 35 , 0 , 30 , 0 ), // #227 + INST(Fptan , FpuOp , O_FPU(00,D9F2,_) , 0 , 35 , 0 , 30 , 0 ), // #228 + INST(Frndint , FpuOp , O_FPU(00,D9FC,_) , 0 , 35 , 0 , 30 , 0 ), // #229 + INST(Frstor , X86M_Only , O_FPU(00,00DD,4) , 0 , 38 , 0 , 69 , 0 ), // #230 + INST(Fsave , X86M_Only , O_FPU(9B,00DD,6) , 0 , 56 , 0 , 69 , 0 ), // #231 + INST(Fscale , FpuOp , O_FPU(00,D9FD,_) , 0 , 35 , 0 , 30 , 0 ), // #232 + INST(Fsin , FpuOp , O_FPU(00,D9FE,_) , 0 , 35 , 0 , 30 , 0 ), // #233 + INST(Fsincos , FpuOp , O_FPU(00,D9FB,_) , 0 , 35 , 0 , 30 , 0 ), // #234 + INST(Fsqrt , FpuOp , O_FPU(00,D9FA,_) , 0 , 35 , 0 , 30 , 0 ), // #235 + INST(Fst , FpuFldFst , O_FPU(00,00D9,2) , 0 , 50 , 0 , 71 , 0 ), // #236 + INST(Fstcw , X86M_Only , O_FPU(9B,00D9,7) , 0 , 57 , 0 , 68 , 0 ), // #237 + INST(Fstenv , X86M_Only , O_FPU(9B,00D9,6) , 0 , 56 , 0 , 69 , 0 ), // #238 + INST(Fstp , FpuFldFst , O_FPU(00,00D9,3) , O(000000,DB,7,_,_,_,_,_ ), 51 , 13 , 67 , 0 ), // #239 + INST(Fstsw , FpuStsw , O_FPU(9B,00DD,7) , O_FPU(9B,DFE0,_) , 57 , 14 , 70 , 0 ), // #240 + INST(Fsub , FpuArith , O_FPU(00,E0E8,4) , 0 , 58 , 0 , 60 , 0 ), // #241 + INST(Fsubp , FpuRDef , O_FPU(00,DEE8,_) , 0 , 37 , 0 , 61 , 0 ), // #242 + INST(Fsubr , FpuArith , O_FPU(00,E8E0,5) , 0 , 59 , 0 , 60 , 0 ), // #243 + INST(Fsubrp , FpuRDef , O_FPU(00,DEE0,_) , 0 , 37 , 0 , 61 , 0 ), // #244 + INST(Ftst , FpuOp , O_FPU(00,D9E4,_) , 0 , 35 , 0 , 30 , 0 ), // #245 + INST(Fucom , FpuRDef , O_FPU(00,DDE0,_) , 0 , 48 , 0 , 61 , 0 ), // #246 + INST(Fucomi , FpuR , O_FPU(00,DBE8,_) , 0 , 42 , 0 , 63 , 50 ), // #247 + INST(Fucomip , FpuR , O_FPU(00,DFE8,_) , 0 , 44 , 0 , 63 , 50 ), // #248 + INST(Fucomp , FpuRDef , O_FPU(00,DDE8,_) , 0 , 48 , 0 , 61 , 0 ), // #249 + INST(Fucompp , FpuOp , O_FPU(00,DAE9,_) , 0 , 41 , 0 , 30 , 0 ), // #250 + INST(Fwait , X86Op , O_FPU(00,009B,_) , 0 , 49 , 0 , 30 , 0 ), // #251 + INST(Fxam , FpuOp , O_FPU(00,D9E5,_) , 0 , 35 , 0 , 30 , 0 ), // #252 + INST(Fxch , FpuR , O_FPU(00,D9C8,_) , 0 , 35 , 0 , 61 , 0 ), // #253 + INST(Fxrstor , X86M_Only , O(000F00,AE,1,_,_,_,_,_ ), 0 , 29 , 0 , 69 , 52 ), // #254 + INST(Fxrstor64 , X86M_Only , O(000F00,AE,1,_,1,_,_,_ ), 0 , 28 , 0 , 72 , 52 ), // #255 + INST(Fxsave , X86M_Only , O(000F00,AE,0,_,_,_,_,_ ), 0 , 4 , 0 , 69 , 52 ), // #256 + INST(Fxsave64 , X86M_Only , O(000F00,AE,0,_,1,_,_,_ ), 0 , 60 , 0 , 72 , 52 ), // #257 + INST(Fxtract , FpuOp , O_FPU(00,D9F4,_) , 0 , 35 , 0 , 30 , 0 ), // #258 + INST(Fyl2x , FpuOp , O_FPU(00,D9F1,_) , 0 , 35 , 0 , 30 , 0 ), // #259 + INST(Fyl2xp1 , FpuOp , O_FPU(00,D9F9,_) , 0 , 35 , 0 , 30 , 0 ), // #260 + INST(Getsec , X86Op , O(000F00,37,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 53 ), // #261 + INST(Gf2p8affineinvqb , ExtRmi , O(660F3A,CF,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 54 ), // #262 + INST(Gf2p8affineqb , ExtRmi , O(660F3A,CE,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 54 ), // #263 + INST(Gf2p8mulb , ExtRm , O(660F38,CF,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 54 ), // #264 + INST(Haddpd , ExtRm , O(660F00,7C,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 6 ), // #265 + INST(Haddps , ExtRm , O(F20F00,7C,_,_,_,_,_,_ ), 0 , 5 , 0 , 5 , 6 ), // #266 + INST(Hlt , X86Op , O(000000,F4,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 0 ), // #267 + INST(Hreset , X86Op_Mod11RM_I8 , O(F30F3A,F0,0,_,_,_,_,_ ), 0 , 61 , 0 , 73 , 55 ), // #268 + INST(Hsubpd , ExtRm , O(660F00,7D,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 6 ), // #269 + INST(Hsubps , ExtRm , O(F20F00,7D,_,_,_,_,_,_ ), 0 , 5 , 0 , 5 , 6 ), // #270 + INST(Idiv , X86M_GPB_MulDiv , O(000000,F6,7,_,x,_,_,_ ), 0 , 27 , 0 , 54 , 1 ), // #271 + INST(Imul , X86Imul , O(000000,F6,5,_,x,_,_,_ ), 0 , 62 , 0 , 74 , 1 ), // #272 + INST(In , X86In , O(000000,EC,_,_,_,_,_,_ ), O(000000,E4,_,_,_,_,_,_ ), 0 , 15 , 75 , 0 ), // #273 + INST(Inc , X86IncDec , O(000000,FE,0,_,x,_,_,_ ), O(000000,40,_,_,x,_,_,_ ), 0 , 16 , 53 , 45 ), // #274 + INST(Incsspd , X86M , O(F30F00,AE,5,_,0,_,_,_ ), 0 , 63 , 0 , 76 , 56 ), // #275 + INST(Incsspq , X86M , O(F30F00,AE,5,_,1,_,_,_ ), 0 , 64 , 0 , 77 , 56 ), // #276 + INST(Ins , X86Ins , O(000000,6C,_,_,_,_,_,_ ), 0 , 0 , 0 , 78 , 0 ), // #277 + INST(Insertps , ExtRmi , O(660F3A,21,_,_,_,_,_,_ ), 0 , 8 , 0 , 38 , 12 ), // #278 + INST(Insertq , ExtInsertq , O(F20F00,79,_,_,_,_,_,_ ), O(F20F00,78,_,_,_,_,_,_ ), 5 , 17 , 79 , 49 ), // #279 + INST(Int , X86Int , O(000000,CD,_,_,_,_,_,_ ), 0 , 0 , 0 , 80 , 0 ), // #280 + INST(Int3 , X86Op , O(000000,CC,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 0 ), // #281 + INST(Into , X86Op , O(000000,CE,_,_,_,_,_,_ ), 0 , 0 , 0 , 81 , 57 ), // #282 + INST(Invd , X86Op , O(000F00,08,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 43 ), // #283 + INST(Invept , X86Rm_NoSize , O(660F38,80,_,_,_,_,_,_ ), 0 , 2 , 0 , 82 , 58 ), // #284 + INST(Invlpg , X86M_Only , O(000F00,01,7,_,_,_,_,_ ), 0 , 22 , 0 , 69 , 43 ), // #285 + INST(Invlpga , X86Op_xAddr , O(000F01,DF,_,_,_,_,_,_ ), 0 , 21 , 0 , 83 , 22 ), // #286 + INST(Invpcid , X86Rm_NoSize , O(660F38,82,_,_,_,_,_,_ ), 0 , 2 , 0 , 82 , 43 ), // #287 + INST(Invvpid , X86Rm_NoSize , O(660F38,81,_,_,_,_,_,_ ), 0 , 2 , 0 , 82 , 58 ), // #288 + INST(Iret , X86Op , O(660000,CF,_,_,_,_,_,_ ), 0 , 19 , 0 , 84 , 1 ), // #289 + INST(Iretd , X86Op , O(000000,CF,_,_,_,_,_,_ ), 0 , 0 , 0 , 84 , 1 ), // #290 + INST(Iretq , X86Op , O(000000,CF,_,_,1,_,_,_ ), 0 , 20 , 0 , 85 , 1 ), // #291 + INST(Ja , X86Jcc , O(000F00,87,_,_,_,_,_,_ ), O(000000,77,_,_,_,_,_,_ ), 4 , 18 , 86 , 59 ), // #292 + INST(Jae , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 86 , 60 ), // #293 + INST(Jb , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 86 , 60 ), // #294 + INST(Jbe , X86Jcc , O(000F00,86,_,_,_,_,_,_ ), O(000000,76,_,_,_,_,_,_ ), 4 , 21 , 86 , 59 ), // #295 + INST(Jc , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 86 , 60 ), // #296 + INST(Je , X86Jcc , O(000F00,84,_,_,_,_,_,_ ), O(000000,74,_,_,_,_,_,_ ), 4 , 22 , 86 , 61 ), // #297 + INST(Jecxz , X86JecxzLoop , 0 , O(000000,E3,_,_,_,_,_,_ ), 0 , 23 , 87 , 0 ), // #298 + INST(Jg , X86Jcc , O(000F00,8F,_,_,_,_,_,_ ), O(000000,7F,_,_,_,_,_,_ ), 4 , 24 , 86 , 62 ), // #299 + INST(Jge , X86Jcc , O(000F00,8D,_,_,_,_,_,_ ), O(000000,7D,_,_,_,_,_,_ ), 4 , 25 , 86 , 63 ), // #300 + INST(Jl , X86Jcc , O(000F00,8C,_,_,_,_,_,_ ), O(000000,7C,_,_,_,_,_,_ ), 4 , 26 , 86 , 63 ), // #301 + INST(Jle , X86Jcc , O(000F00,8E,_,_,_,_,_,_ ), O(000000,7E,_,_,_,_,_,_ ), 4 , 27 , 86 , 62 ), // #302 + INST(Jmp , X86Jmp , O(000000,FF,4,_,_,_,_,_ ), O(000000,EB,_,_,_,_,_,_ ), 9 , 28 , 88 , 0 ), // #303 + INST(Jna , X86Jcc , O(000F00,86,_,_,_,_,_,_ ), O(000000,76,_,_,_,_,_,_ ), 4 , 21 , 86 , 59 ), // #304 + INST(Jnae , X86Jcc , O(000F00,82,_,_,_,_,_,_ ), O(000000,72,_,_,_,_,_,_ ), 4 , 20 , 86 , 60 ), // #305 + INST(Jnb , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 86 , 60 ), // #306 + INST(Jnbe , X86Jcc , O(000F00,87,_,_,_,_,_,_ ), O(000000,77,_,_,_,_,_,_ ), 4 , 18 , 86 , 59 ), // #307 + INST(Jnc , X86Jcc , O(000F00,83,_,_,_,_,_,_ ), O(000000,73,_,_,_,_,_,_ ), 4 , 19 , 86 , 60 ), // #308 + INST(Jne , X86Jcc , O(000F00,85,_,_,_,_,_,_ ), O(000000,75,_,_,_,_,_,_ ), 4 , 29 , 86 , 61 ), // #309 + INST(Jng , X86Jcc , O(000F00,8E,_,_,_,_,_,_ ), O(000000,7E,_,_,_,_,_,_ ), 4 , 27 , 86 , 62 ), // #310 + INST(Jnge , X86Jcc , O(000F00,8C,_,_,_,_,_,_ ), O(000000,7C,_,_,_,_,_,_ ), 4 , 26 , 86 , 63 ), // #311 + INST(Jnl , X86Jcc , O(000F00,8D,_,_,_,_,_,_ ), O(000000,7D,_,_,_,_,_,_ ), 4 , 25 , 86 , 63 ), // #312 + INST(Jnle , X86Jcc , O(000F00,8F,_,_,_,_,_,_ ), O(000000,7F,_,_,_,_,_,_ ), 4 , 24 , 86 , 62 ), // #313 + INST(Jno , X86Jcc , O(000F00,81,_,_,_,_,_,_ ), O(000000,71,_,_,_,_,_,_ ), 4 , 30 , 86 , 57 ), // #314 + INST(Jnp , X86Jcc , O(000F00,8B,_,_,_,_,_,_ ), O(000000,7B,_,_,_,_,_,_ ), 4 , 31 , 86 , 64 ), // #315 + INST(Jns , X86Jcc , O(000F00,89,_,_,_,_,_,_ ), O(000000,79,_,_,_,_,_,_ ), 4 , 32 , 86 , 65 ), // #316 + INST(Jnz , X86Jcc , O(000F00,85,_,_,_,_,_,_ ), O(000000,75,_,_,_,_,_,_ ), 4 , 29 , 86 , 61 ), // #317 + INST(Jo , X86Jcc , O(000F00,80,_,_,_,_,_,_ ), O(000000,70,_,_,_,_,_,_ ), 4 , 33 , 86 , 57 ), // #318 + INST(Jp , X86Jcc , O(000F00,8A,_,_,_,_,_,_ ), O(000000,7A,_,_,_,_,_,_ ), 4 , 34 , 86 , 64 ), // #319 + INST(Jpe , X86Jcc , O(000F00,8A,_,_,_,_,_,_ ), O(000000,7A,_,_,_,_,_,_ ), 4 , 34 , 86 , 64 ), // #320 + INST(Jpo , X86Jcc , O(000F00,8B,_,_,_,_,_,_ ), O(000000,7B,_,_,_,_,_,_ ), 4 , 31 , 86 , 64 ), // #321 + INST(Js , X86Jcc , O(000F00,88,_,_,_,_,_,_ ), O(000000,78,_,_,_,_,_,_ ), 4 , 35 , 86 , 65 ), // #322 + INST(Jz , X86Jcc , O(000F00,84,_,_,_,_,_,_ ), O(000000,74,_,_,_,_,_,_ ), 4 , 22 , 86 , 61 ), // #323 + INST(Kaddb , VexRvm , V(660F00,4A,_,1,0,_,_,_ ), 0 , 65 , 0 , 89 , 66 ), // #324 + INST(Kaddd , VexRvm , V(660F00,4A,_,1,1,_,_,_ ), 0 , 66 , 0 , 89 , 67 ), // #325 + INST(Kaddq , VexRvm , V(000F00,4A,_,1,1,_,_,_ ), 0 , 67 , 0 , 89 , 67 ), // #326 + INST(Kaddw , VexRvm , V(000F00,4A,_,1,0,_,_,_ ), 0 , 68 , 0 , 89 , 66 ), // #327 + INST(Kandb , VexRvm , V(660F00,41,_,1,0,_,_,_ ), 0 , 65 , 0 , 89 , 66 ), // #328 + INST(Kandd , VexRvm , V(660F00,41,_,1,1,_,_,_ ), 0 , 66 , 0 , 89 , 67 ), // #329 + INST(Kandnb , VexRvm , V(660F00,42,_,1,0,_,_,_ ), 0 , 65 , 0 , 89 , 66 ), // #330 + INST(Kandnd , VexRvm , V(660F00,42,_,1,1,_,_,_ ), 0 , 66 , 0 , 89 , 67 ), // #331 + INST(Kandnq , VexRvm , V(000F00,42,_,1,1,_,_,_ ), 0 , 67 , 0 , 89 , 67 ), // #332 + INST(Kandnw , VexRvm , V(000F00,42,_,1,0,_,_,_ ), 0 , 68 , 0 , 89 , 68 ), // #333 + INST(Kandq , VexRvm , V(000F00,41,_,1,1,_,_,_ ), 0 , 67 , 0 , 89 , 67 ), // #334 + INST(Kandw , VexRvm , V(000F00,41,_,1,0,_,_,_ ), 0 , 68 , 0 , 89 , 68 ), // #335 + INST(Kmovb , VexKmov , V(660F00,90,_,0,0,_,_,_ ), V(660F00,92,_,0,0,_,_,_ ), 69 , 36 , 90 , 69 ), // #336 + INST(Kmovd , VexKmov , V(660F00,90,_,0,1,_,_,_ ), V(F20F00,92,_,0,0,_,_,_ ), 70 , 37 , 91 , 70 ), // #337 + INST(Kmovq , VexKmov , V(000F00,90,_,0,1,_,_,_ ), V(F20F00,92,_,0,1,_,_,_ ), 71 , 38 , 92 , 70 ), // #338 + INST(Kmovw , VexKmov , V(000F00,90,_,0,0,_,_,_ ), V(000F00,92,_,0,0,_,_,_ ), 72 , 39 , 93 , 71 ), // #339 + INST(Knotb , VexRm , V(660F00,44,_,0,0,_,_,_ ), 0 , 69 , 0 , 94 , 66 ), // #340 + INST(Knotd , VexRm , V(660F00,44,_,0,1,_,_,_ ), 0 , 70 , 0 , 94 , 67 ), // #341 + INST(Knotq , VexRm , V(000F00,44,_,0,1,_,_,_ ), 0 , 71 , 0 , 94 , 67 ), // #342 + INST(Knotw , VexRm , V(000F00,44,_,0,0,_,_,_ ), 0 , 72 , 0 , 94 , 68 ), // #343 + INST(Korb , VexRvm , V(660F00,45,_,1,0,_,_,_ ), 0 , 65 , 0 , 89 , 66 ), // #344 + INST(Kord , VexRvm , V(660F00,45,_,1,1,_,_,_ ), 0 , 66 , 0 , 89 , 67 ), // #345 + INST(Korq , VexRvm , V(000F00,45,_,1,1,_,_,_ ), 0 , 67 , 0 , 89 , 67 ), // #346 + INST(Kortestb , VexRm , V(660F00,98,_,0,0,_,_,_ ), 0 , 69 , 0 , 94 , 72 ), // #347 + INST(Kortestd , VexRm , V(660F00,98,_,0,1,_,_,_ ), 0 , 70 , 0 , 94 , 73 ), // #348 + INST(Kortestq , VexRm , V(000F00,98,_,0,1,_,_,_ ), 0 , 71 , 0 , 94 , 73 ), // #349 + INST(Kortestw , VexRm , V(000F00,98,_,0,0,_,_,_ ), 0 , 72 , 0 , 94 , 74 ), // #350 + INST(Korw , VexRvm , V(000F00,45,_,1,0,_,_,_ ), 0 , 68 , 0 , 89 , 68 ), // #351 + INST(Kshiftlb , VexRmi , V(660F3A,32,_,0,0,_,_,_ ), 0 , 73 , 0 , 95 , 66 ), // #352 + INST(Kshiftld , VexRmi , V(660F3A,33,_,0,0,_,_,_ ), 0 , 73 , 0 , 95 , 67 ), // #353 + INST(Kshiftlq , VexRmi , V(660F3A,33,_,0,1,_,_,_ ), 0 , 74 , 0 , 95 , 67 ), // #354 + INST(Kshiftlw , VexRmi , V(660F3A,32,_,0,1,_,_,_ ), 0 , 74 , 0 , 95 , 68 ), // #355 + INST(Kshiftrb , VexRmi , V(660F3A,30,_,0,0,_,_,_ ), 0 , 73 , 0 , 95 , 66 ), // #356 + INST(Kshiftrd , VexRmi , V(660F3A,31,_,0,0,_,_,_ ), 0 , 73 , 0 , 95 , 67 ), // #357 + INST(Kshiftrq , VexRmi , V(660F3A,31,_,0,1,_,_,_ ), 0 , 74 , 0 , 95 , 67 ), // #358 + INST(Kshiftrw , VexRmi , V(660F3A,30,_,0,1,_,_,_ ), 0 , 74 , 0 , 95 , 68 ), // #359 + INST(Ktestb , VexRm , V(660F00,99,_,0,0,_,_,_ ), 0 , 69 , 0 , 94 , 72 ), // #360 + INST(Ktestd , VexRm , V(660F00,99,_,0,1,_,_,_ ), 0 , 70 , 0 , 94 , 73 ), // #361 + INST(Ktestq , VexRm , V(000F00,99,_,0,1,_,_,_ ), 0 , 71 , 0 , 94 , 73 ), // #362 + INST(Ktestw , VexRm , V(000F00,99,_,0,0,_,_,_ ), 0 , 72 , 0 , 94 , 72 ), // #363 + INST(Kunpckbw , VexRvm , V(660F00,4B,_,1,0,_,_,_ ), 0 , 65 , 0 , 89 , 68 ), // #364 + INST(Kunpckdq , VexRvm , V(000F00,4B,_,1,1,_,_,_ ), 0 , 67 , 0 , 89 , 67 ), // #365 + INST(Kunpckwd , VexRvm , V(000F00,4B,_,1,0,_,_,_ ), 0 , 68 , 0 , 89 , 67 ), // #366 + INST(Kxnorb , VexRvm , V(660F00,46,_,1,0,_,_,_ ), 0 , 65 , 0 , 96 , 66 ), // #367 + INST(Kxnord , VexRvm , V(660F00,46,_,1,1,_,_,_ ), 0 , 66 , 0 , 96 , 67 ), // #368 + INST(Kxnorq , VexRvm , V(000F00,46,_,1,1,_,_,_ ), 0 , 67 , 0 , 96 , 67 ), // #369 + INST(Kxnorw , VexRvm , V(000F00,46,_,1,0,_,_,_ ), 0 , 68 , 0 , 96 , 68 ), // #370 + INST(Kxorb , VexRvm , V(660F00,47,_,1,0,_,_,_ ), 0 , 65 , 0 , 96 , 66 ), // #371 + INST(Kxord , VexRvm , V(660F00,47,_,1,1,_,_,_ ), 0 , 66 , 0 , 96 , 67 ), // #372 + INST(Kxorq , VexRvm , V(000F00,47,_,1,1,_,_,_ ), 0 , 67 , 0 , 96 , 67 ), // #373 + INST(Kxorw , VexRvm , V(000F00,47,_,1,0,_,_,_ ), 0 , 68 , 0 , 96 , 68 ), // #374 + INST(Lahf , X86Op , O(000000,9F,_,_,_,_,_,_ ), 0 , 0 , 0 , 97 , 75 ), // #375 + INST(Lar , X86Rm , O(000F00,02,_,_,_,_,_,_ ), 0 , 4 , 0 , 98 , 10 ), // #376 + INST(Lcall , X86LcallLjmp , O(000000,FF,3,_,_,_,_,_ ), O(000000,9A,_,_,_,_,_,_ ), 75 , 40 , 99 , 1 ), // #377 + INST(Lddqu , ExtRm , O(F20F00,F0,_,_,_,_,_,_ ), 0 , 5 , 0 , 100, 6 ), // #378 + INST(Ldmxcsr , X86M_Only , O(000F00,AE,2,_,_,_,_,_ ), 0 , 76 , 0 , 101, 5 ), // #379 + INST(Lds , X86Rm , O(000000,C5,_,_,_,_,_,_ ), 0 , 0 , 0 , 102, 0 ), // #380 + INST(Ldtilecfg , AmxCfg , V(000F38,49,_,0,0,_,_,_ ), 0 , 10 , 0 , 103, 76 ), // #381 + INST(Lea , X86Lea , O(000000,8D,_,_,x,_,_,_ ), 0 , 0 , 0 , 104, 0 ), // #382 + INST(Leave , X86Op , O(000000,C9,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 0 ), // #383 + INST(Les , X86Rm , O(000000,C4,_,_,_,_,_,_ ), 0 , 0 , 0 , 102, 0 ), // #384 + INST(Lfence , X86Fence , O(000F00,AE,5,_,_,_,_,_ ), 0 , 77 , 0 , 30 , 4 ), // #385 + INST(Lfs , X86Rm , O(000F00,B4,_,_,_,_,_,_ ), 0 , 4 , 0 , 105, 0 ), // #386 + INST(Lgdt , X86M_Only , O(000F00,01,2,_,_,_,_,_ ), 0 , 76 , 0 , 69 , 0 ), // #387 + INST(Lgs , X86Rm , O(000F00,B5,_,_,_,_,_,_ ), 0 , 4 , 0 , 105, 0 ), // #388 + INST(Lidt , X86M_Only , O(000F00,01,3,_,_,_,_,_ ), 0 , 78 , 0 , 69 , 0 ), // #389 + INST(Ljmp , X86LcallLjmp , O(000000,FF,5,_,_,_,_,_ ), O(000000,EA,_,_,_,_,_,_ ), 62 , 41 , 106, 0 ), // #390 + INST(Lldt , X86M_NoSize , O(000F00,00,2,_,_,_,_,_ ), 0 , 76 , 0 , 107, 0 ), // #391 + INST(Llwpcb , VexR_Wx , V(XOP_M9,12,0,0,x,_,_,_ ), 0 , 79 , 0 , 108, 77 ), // #392 + INST(Lmsw , X86M_NoSize , O(000F00,01,6,_,_,_,_,_ ), 0 , 80 , 0 , 107, 0 ), // #393 + INST(Lods , X86StrRm , O(000000,AC,_,_,_,_,_,_ ), 0 , 0 , 0 , 109, 78 ), // #394 + INST(Loop , X86JecxzLoop , 0 , O(000000,E2,_,_,_,_,_,_ ), 0 , 42 , 110, 0 ), // #395 + INST(Loope , X86JecxzLoop , 0 , O(000000,E1,_,_,_,_,_,_ ), 0 , 43 , 110, 61 ), // #396 + INST(Loopne , X86JecxzLoop , 0 , O(000000,E0,_,_,_,_,_,_ ), 0 , 44 , 110, 61 ), // #397 + INST(Lsl , X86Rm , O(000F00,03,_,_,_,_,_,_ ), 0 , 4 , 0 , 111, 10 ), // #398 + INST(Lss , X86Rm , O(000F00,B2,_,_,_,_,_,_ ), 0 , 4 , 0 , 105, 0 ), // #399 + INST(Ltr , X86M_NoSize , O(000F00,00,3,_,_,_,_,_ ), 0 , 78 , 0 , 107, 0 ), // #400 + INST(Lwpins , VexVmi4_Wx , V(XOP_MA,12,0,0,x,_,_,_ ), 0 , 81 , 0 , 112, 77 ), // #401 + INST(Lwpval , VexVmi4_Wx , V(XOP_MA,12,1,0,x,_,_,_ ), 0 , 82 , 0 , 112, 77 ), // #402 + INST(Lzcnt , X86Rm_Raw66H , O(F30F00,BD,_,_,x,_,_,_ ), 0 , 6 , 0 , 22 , 79 ), // #403 + INST(Maskmovdqu , ExtRm_ZDI , O(660F00,F7,_,_,_,_,_,_ ), 0 , 3 , 0 , 113, 4 ), // #404 + INST(Maskmovq , ExtRm_ZDI , O(000F00,F7,_,_,_,_,_,_ ), 0 , 4 , 0 , 114, 80 ), // #405 + INST(Maxpd , ExtRm , O(660F00,5F,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #406 + INST(Maxps , ExtRm , O(000F00,5F,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #407 + INST(Maxsd , ExtRm , O(F20F00,5F,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #408 + INST(Maxss , ExtRm , O(F30F00,5F,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #409 + INST(Mcommit , X86Op , O(F30F01,FA,_,_,_,_,_,_ ), 0 , 25 , 0 , 30 , 81 ), // #410 + INST(Mfence , X86Fence , O(000F00,AE,6,_,_,_,_,_ ), 0 , 80 , 0 , 30 , 4 ), // #411 + INST(Minpd , ExtRm , O(660F00,5D,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #412 + INST(Minps , ExtRm , O(000F00,5D,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #413 + INST(Minsd , ExtRm , O(F20F00,5D,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #414 + INST(Minss , ExtRm , O(F30F00,5D,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #415 + INST(Monitor , X86Op , O(000F01,C8,_,_,_,_,_,_ ), 0 , 21 , 0 , 115, 82 ), // #416 + INST(Monitorx , X86Op , O(000F01,FA,_,_,_,_,_,_ ), 0 , 21 , 0 , 115, 83 ), // #417 + INST(Mov , X86Mov , 0 , 0 , 0 , 0 , 116, 84 ), // #418 + INST(Movabs , X86Movabs , 0 , 0 , 0 , 0 , 117, 0 ), // #419 + INST(Movapd , ExtMov , O(660F00,28,_,_,_,_,_,_ ), O(660F00,29,_,_,_,_,_,_ ), 3 , 45 , 118, 85 ), // #420 + INST(Movaps , ExtMov , O(000F00,28,_,_,_,_,_,_ ), O(000F00,29,_,_,_,_,_,_ ), 4 , 46 , 118, 86 ), // #421 + INST(Movbe , ExtMovbe , O(000F38,F0,_,_,x,_,_,_ ), O(000F38,F1,_,_,x,_,_,_ ), 83 , 47 , 119, 87 ), // #422 + INST(Movd , ExtMovd , O(000F00,6E,_,_,_,_,_,_ ), O(000F00,7E,_,_,_,_,_,_ ), 4 , 48 , 120, 88 ), // #423 + INST(Movddup , ExtMov , O(F20F00,12,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 6 ), // #424 + INST(Movdir64b , X86EnqcmdMovdir64b , O(660F38,F8,_,_,_,_,_,_ ), 0 , 2 , 0 , 121, 89 ), // #425 + INST(Movdiri , X86MovntiMovdiri , O(000F38,F9,_,_,_,_,_,_ ), 0 , 83 , 0 , 122, 90 ), // #426 + INST(Movdq2q , ExtMov , O(F20F00,D6,_,_,_,_,_,_ ), 0 , 5 , 0 , 123, 4 ), // #427 + INST(Movdqa , ExtMov , O(660F00,6F,_,_,_,_,_,_ ), O(660F00,7F,_,_,_,_,_,_ ), 3 , 49 , 118, 85 ), // #428 + INST(Movdqu , ExtMov , O(F30F00,6F,_,_,_,_,_,_ ), O(F30F00,7F,_,_,_,_,_,_ ), 6 , 50 , 118, 85 ), // #429 + INST(Movhlps , ExtMov , O(000F00,12,_,_,_,_,_,_ ), 0 , 4 , 0 , 124, 5 ), // #430 + INST(Movhpd , ExtMov , O(660F00,16,_,_,_,_,_,_ ), O(660F00,17,_,_,_,_,_,_ ), 3 , 51 , 125, 4 ), // #431 + INST(Movhps , ExtMov , O(000F00,16,_,_,_,_,_,_ ), O(000F00,17,_,_,_,_,_,_ ), 4 , 52 , 125, 5 ), // #432 + INST(Movlhps , ExtMov , O(000F00,16,_,_,_,_,_,_ ), 0 , 4 , 0 , 124, 5 ), // #433 + INST(Movlpd , ExtMov , O(660F00,12,_,_,_,_,_,_ ), O(660F00,13,_,_,_,_,_,_ ), 3 , 53 , 125, 4 ), // #434 + INST(Movlps , ExtMov , O(000F00,12,_,_,_,_,_,_ ), O(000F00,13,_,_,_,_,_,_ ), 4 , 54 , 125, 5 ), // #435 + INST(Movmskpd , ExtMov , O(660F00,50,_,_,_,_,_,_ ), 0 , 3 , 0 , 126, 4 ), // #436 + INST(Movmskps , ExtMov , O(000F00,50,_,_,_,_,_,_ ), 0 , 4 , 0 , 126, 5 ), // #437 + INST(Movntdq , ExtMov , 0 , O(660F00,E7,_,_,_,_,_,_ ), 0 , 55 , 127, 4 ), // #438 + INST(Movntdqa , ExtMov , O(660F38,2A,_,_,_,_,_,_ ), 0 , 2 , 0 , 100, 12 ), // #439 + INST(Movnti , X86MovntiMovdiri , O(000F00,C3,_,_,x,_,_,_ ), 0 , 4 , 0 , 122, 4 ), // #440 + INST(Movntpd , ExtMov , 0 , O(660F00,2B,_,_,_,_,_,_ ), 0 , 56 , 127, 4 ), // #441 + INST(Movntps , ExtMov , 0 , O(000F00,2B,_,_,_,_,_,_ ), 0 , 57 , 127, 5 ), // #442 + INST(Movntq , ExtMov , 0 , O(000F00,E7,_,_,_,_,_,_ ), 0 , 58 , 128, 80 ), // #443 + INST(Movntsd , ExtMov , 0 , O(F20F00,2B,_,_,_,_,_,_ ), 0 , 59 , 129, 49 ), // #444 + INST(Movntss , ExtMov , 0 , O(F30F00,2B,_,_,_,_,_,_ ), 0 , 60 , 130, 49 ), // #445 + INST(Movq , ExtMovq , O(000F00,6E,_,_,x,_,_,_ ), O(000F00,7E,_,_,x,_,_,_ ), 4 , 48 , 131, 91 ), // #446 + INST(Movq2dq , ExtRm , O(F30F00,D6,_,_,_,_,_,_ ), 0 , 6 , 0 , 132, 4 ), // #447 + INST(Movs , X86StrMm , O(000000,A4,_,_,_,_,_,_ ), 0 , 0 , 0 , 133, 78 ), // #448 + INST(Movsd , ExtMov , O(F20F00,10,_,_,_,_,_,_ ), O(F20F00,11,_,_,_,_,_,_ ), 5 , 61 , 134, 85 ), // #449 + INST(Movshdup , ExtRm , O(F30F00,16,_,_,_,_,_,_ ), 0 , 6 , 0 , 5 , 6 ), // #450 + INST(Movsldup , ExtRm , O(F30F00,12,_,_,_,_,_,_ ), 0 , 6 , 0 , 5 , 6 ), // #451 + INST(Movss , ExtMov , O(F30F00,10,_,_,_,_,_,_ ), O(F30F00,11,_,_,_,_,_,_ ), 6 , 62 , 135, 86 ), // #452 + INST(Movsx , X86MovsxMovzx , O(000F00,BE,_,_,x,_,_,_ ), 0 , 4 , 0 , 136, 0 ), // #453 + INST(Movsxd , X86Rm , O(000000,63,_,_,x,_,_,_ ), 0 , 0 , 0 , 137, 0 ), // #454 + INST(Movupd , ExtMov , O(660F00,10,_,_,_,_,_,_ ), O(660F00,11,_,_,_,_,_,_ ), 3 , 63 , 118, 85 ), // #455 + INST(Movups , ExtMov , O(000F00,10,_,_,_,_,_,_ ), O(000F00,11,_,_,_,_,_,_ ), 4 , 64 , 118, 86 ), // #456 + INST(Movzx , X86MovsxMovzx , O(000F00,B6,_,_,x,_,_,_ ), 0 , 4 , 0 , 136, 0 ), // #457 + INST(Mpsadbw , ExtRmi , O(660F3A,42,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #458 + INST(Mul , X86M_GPB_MulDiv , O(000000,F6,4,_,x,_,_,_ ), 0 , 9 , 0 , 54 , 1 ), // #459 + INST(Mulpd , ExtRm , O(660F00,59,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #460 + INST(Mulps , ExtRm , O(000F00,59,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #461 + INST(Mulsd , ExtRm , O(F20F00,59,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #462 + INST(Mulss , ExtRm , O(F30F00,59,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #463 + INST(Mulx , VexRvm_ZDX_Wx , V(F20F38,F6,_,0,x,_,_,_ ), 0 , 84 , 0 , 138, 92 ), // #464 + INST(Mwait , X86Op , O(000F01,C9,_,_,_,_,_,_ ), 0 , 21 , 0 , 139, 82 ), // #465 + INST(Mwaitx , X86Op , O(000F01,FB,_,_,_,_,_,_ ), 0 , 21 , 0 , 140, 83 ), // #466 + INST(Neg , X86M_GPB , O(000000,F6,3,_,x,_,_,_ ), 0 , 75 , 0 , 141, 1 ), // #467 + INST(Nop , X86M_Nop , O(000000,90,_,_,_,_,_,_ ), 0 , 0 , 0 , 142, 0 ), // #468 + INST(Not , X86M_GPB , O(000000,F6,2,_,x,_,_,_ ), 0 , 1 , 0 , 141, 0 ), // #469 + INST(Or , X86Arith , O(000000,08,1,_,x,_,_,_ ), 0 , 31 , 0 , 143, 1 ), // #470 + INST(Orpd , ExtRm , O(660F00,56,_,_,_,_,_,_ ), 0 , 3 , 0 , 11 , 4 ), // #471 + INST(Orps , ExtRm , O(000F00,56,_,_,_,_,_,_ ), 0 , 4 , 0 , 11 , 5 ), // #472 + INST(Out , X86Out , O(000000,EE,_,_,_,_,_,_ ), O(000000,E6,_,_,_,_,_,_ ), 0 , 65 , 144, 0 ), // #473 + INST(Outs , X86Outs , O(000000,6E,_,_,_,_,_,_ ), 0 , 0 , 0 , 145, 0 ), // #474 + INST(Pabsb , ExtRm_P , O(000F38,1C,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #475 + INST(Pabsd , ExtRm_P , O(000F38,1E,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #476 + INST(Pabsw , ExtRm_P , O(000F38,1D,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #477 + INST(Packssdw , ExtRm_P , O(000F00,6B,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #478 + INST(Packsswb , ExtRm_P , O(000F00,63,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #479 + INST(Packusdw , ExtRm , O(660F38,2B,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 12 ), // #480 + INST(Packuswb , ExtRm_P , O(000F00,67,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #481 + INST(Paddb , ExtRm_P , O(000F00,FC,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #482 + INST(Paddd , ExtRm_P , O(000F00,FE,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #483 + INST(Paddq , ExtRm_P , O(000F00,D4,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 4 ), // #484 + INST(Paddsb , ExtRm_P , O(000F00,EC,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #485 + INST(Paddsw , ExtRm_P , O(000F00,ED,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #486 + INST(Paddusb , ExtRm_P , O(000F00,DC,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #487 + INST(Paddusw , ExtRm_P , O(000F00,DD,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #488 + INST(Paddw , ExtRm_P , O(000F00,FD,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #489 + INST(Palignr , ExtRmi_P , O(000F3A,0F,_,_,_,_,_,_ ), 0 , 85 , 0 , 147, 6 ), // #490 + INST(Pand , ExtRm_P , O(000F00,DB,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 88 ), // #491 + INST(Pandn , ExtRm_P , O(000F00,DF,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #492 + INST(Pause , X86Op , O(F30000,90,_,_,_,_,_,_ ), 0 , 86 , 0 , 30 , 0 ), // #493 + INST(Pavgb , ExtRm_P , O(000F00,E0,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 94 ), // #494 + INST(Pavgusb , Ext3dNow , O(000F0F,BF,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #495 + INST(Pavgw , ExtRm_P , O(000F00,E3,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 94 ), // #496 + INST(Pblendvb , ExtRm_XMM0 , O(660F38,10,_,_,_,_,_,_ ), 0 , 2 , 0 , 15 , 12 ), // #497 + INST(Pblendw , ExtRmi , O(660F3A,0E,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #498 + INST(Pclmulqdq , ExtRmi , O(660F3A,44,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 95 ), // #499 + INST(Pcmpeqb , ExtRm_P , O(000F00,74,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #500 + INST(Pcmpeqd , ExtRm_P , O(000F00,76,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #501 + INST(Pcmpeqq , ExtRm , O(660F38,29,_,_,_,_,_,_ ), 0 , 2 , 0 , 151, 12 ), // #502 + INST(Pcmpeqw , ExtRm_P , O(000F00,75,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #503 + INST(Pcmpestri , ExtRmi , O(660F3A,61,_,_,_,_,_,_ ), 0 , 8 , 0 , 152, 96 ), // #504 + INST(Pcmpestrm , ExtRmi , O(660F3A,60,_,_,_,_,_,_ ), 0 , 8 , 0 , 153, 96 ), // #505 + INST(Pcmpgtb , ExtRm_P , O(000F00,64,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #506 + INST(Pcmpgtd , ExtRm_P , O(000F00,66,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #507 + INST(Pcmpgtq , ExtRm , O(660F38,37,_,_,_,_,_,_ ), 0 , 2 , 0 , 151, 44 ), // #508 + INST(Pcmpgtw , ExtRm_P , O(000F00,65,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #509 + INST(Pcmpistri , ExtRmi , O(660F3A,63,_,_,_,_,_,_ ), 0 , 8 , 0 , 154, 96 ), // #510 + INST(Pcmpistrm , ExtRmi , O(660F3A,62,_,_,_,_,_,_ ), 0 , 8 , 0 , 155, 96 ), // #511 + INST(Pconfig , X86Op , O(000F01,C5,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 97 ), // #512 + INST(Pdep , VexRvm_Wx , V(F20F38,F5,_,0,x,_,_,_ ), 0 , 84 , 0 , 10 , 92 ), // #513 + INST(Pext , VexRvm_Wx , V(F30F38,F5,_,0,x,_,_,_ ), 0 , 88 , 0 , 10 , 92 ), // #514 + INST(Pextrb , ExtExtract , O(000F3A,14,_,_,_,_,_,_ ), 0 , 85 , 0 , 156, 12 ), // #515 + INST(Pextrd , ExtExtract , O(000F3A,16,_,_,_,_,_,_ ), 0 , 85 , 0 , 58 , 12 ), // #516 + INST(Pextrq , ExtExtract , O(000F3A,16,_,_,1,_,_,_ ), 0 , 89 , 0 , 157, 12 ), // #517 + INST(Pextrw , ExtPextrw , O(000F00,C5,_,_,_,_,_,_ ), O(000F3A,15,_,_,_,_,_,_ ), 4 , 66 , 158, 98 ), // #518 + INST(Pf2id , Ext3dNow , O(000F0F,1D,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #519 + INST(Pf2iw , Ext3dNow , O(000F0F,1C,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 99 ), // #520 + INST(Pfacc , Ext3dNow , O(000F0F,AE,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #521 + INST(Pfadd , Ext3dNow , O(000F0F,9E,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #522 + INST(Pfcmpeq , Ext3dNow , O(000F0F,B0,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #523 + INST(Pfcmpge , Ext3dNow , O(000F0F,90,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #524 + INST(Pfcmpgt , Ext3dNow , O(000F0F,A0,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #525 + INST(Pfmax , Ext3dNow , O(000F0F,A4,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #526 + INST(Pfmin , Ext3dNow , O(000F0F,94,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #527 + INST(Pfmul , Ext3dNow , O(000F0F,B4,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #528 + INST(Pfnacc , Ext3dNow , O(000F0F,8A,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 99 ), // #529 + INST(Pfpnacc , Ext3dNow , O(000F0F,8E,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 99 ), // #530 + INST(Pfrcp , Ext3dNow , O(000F0F,96,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #531 + INST(Pfrcpit1 , Ext3dNow , O(000F0F,A6,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #532 + INST(Pfrcpit2 , Ext3dNow , O(000F0F,B6,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #533 + INST(Pfrcpv , Ext3dNow , O(000F0F,86,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 100), // #534 + INST(Pfrsqit1 , Ext3dNow , O(000F0F,A7,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #535 + INST(Pfrsqrt , Ext3dNow , O(000F0F,97,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #536 + INST(Pfrsqrtv , Ext3dNow , O(000F0F,87,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 100), // #537 + INST(Pfsub , Ext3dNow , O(000F0F,9A,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #538 + INST(Pfsubr , Ext3dNow , O(000F0F,AA,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #539 + INST(Phaddd , ExtRm_P , O(000F38,02,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #540 + INST(Phaddsw , ExtRm_P , O(000F38,03,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #541 + INST(Phaddw , ExtRm_P , O(000F38,01,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #542 + INST(Phminposuw , ExtRm , O(660F38,41,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 12 ), // #543 + INST(Phsubd , ExtRm_P , O(000F38,06,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #544 + INST(Phsubsw , ExtRm_P , O(000F38,07,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #545 + INST(Phsubw , ExtRm_P , O(000F38,05,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #546 + INST(Pi2fd , Ext3dNow , O(000F0F,0D,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #547 + INST(Pi2fw , Ext3dNow , O(000F0F,0C,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 99 ), // #548 + INST(Pinsrb , ExtRmi , O(660F3A,20,_,_,_,_,_,_ ), 0 , 8 , 0 , 159, 12 ), // #549 + INST(Pinsrd , ExtRmi , O(660F3A,22,_,_,_,_,_,_ ), 0 , 8 , 0 , 160, 12 ), // #550 + INST(Pinsrq , ExtRmi , O(660F3A,22,_,_,1,_,_,_ ), 0 , 90 , 0 , 161, 12 ), // #551 + INST(Pinsrw , ExtRmi_P , O(000F00,C4,_,_,_,_,_,_ ), 0 , 4 , 0 , 162, 94 ), // #552 + INST(Pmaddubsw , ExtRm_P , O(000F38,04,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #553 + INST(Pmaddwd , ExtRm_P , O(000F00,F5,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #554 + INST(Pmaxsb , ExtRm , O(660F38,3C,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #555 + INST(Pmaxsd , ExtRm , O(660F38,3D,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #556 + INST(Pmaxsw , ExtRm_P , O(000F00,EE,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 94 ), // #557 + INST(Pmaxub , ExtRm_P , O(000F00,DE,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 94 ), // #558 + INST(Pmaxud , ExtRm , O(660F38,3F,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #559 + INST(Pmaxuw , ExtRm , O(660F38,3E,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #560 + INST(Pminsb , ExtRm , O(660F38,38,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #561 + INST(Pminsd , ExtRm , O(660F38,39,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #562 + INST(Pminsw , ExtRm_P , O(000F00,EA,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 94 ), // #563 + INST(Pminub , ExtRm_P , O(000F00,DA,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 94 ), // #564 + INST(Pminud , ExtRm , O(660F38,3B,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #565 + INST(Pminuw , ExtRm , O(660F38,3A,_,_,_,_,_,_ ), 0 , 2 , 0 , 11 , 12 ), // #566 + INST(Pmovmskb , ExtRm_P , O(000F00,D7,_,_,_,_,_,_ ), 0 , 4 , 0 , 163, 94 ), // #567 + INST(Pmovsxbd , ExtRm , O(660F38,21,_,_,_,_,_,_ ), 0 , 2 , 0 , 7 , 12 ), // #568 + INST(Pmovsxbq , ExtRm , O(660F38,22,_,_,_,_,_,_ ), 0 , 2 , 0 , 164, 12 ), // #569 + INST(Pmovsxbw , ExtRm , O(660F38,20,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #570 + INST(Pmovsxdq , ExtRm , O(660F38,25,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #571 + INST(Pmovsxwd , ExtRm , O(660F38,23,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #572 + INST(Pmovsxwq , ExtRm , O(660F38,24,_,_,_,_,_,_ ), 0 , 2 , 0 , 7 , 12 ), // #573 + INST(Pmovzxbd , ExtRm , O(660F38,31,_,_,_,_,_,_ ), 0 , 2 , 0 , 7 , 12 ), // #574 + INST(Pmovzxbq , ExtRm , O(660F38,32,_,_,_,_,_,_ ), 0 , 2 , 0 , 164, 12 ), // #575 + INST(Pmovzxbw , ExtRm , O(660F38,30,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #576 + INST(Pmovzxdq , ExtRm , O(660F38,35,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #577 + INST(Pmovzxwd , ExtRm , O(660F38,33,_,_,_,_,_,_ ), 0 , 2 , 0 , 6 , 12 ), // #578 + INST(Pmovzxwq , ExtRm , O(660F38,34,_,_,_,_,_,_ ), 0 , 2 , 0 , 7 , 12 ), // #579 + INST(Pmuldq , ExtRm , O(660F38,28,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 12 ), // #580 + INST(Pmulhrsw , ExtRm_P , O(000F38,0B,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #581 + INST(Pmulhrw , Ext3dNow , O(000F0F,B7,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 51 ), // #582 + INST(Pmulhuw , ExtRm_P , O(000F00,E4,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 94 ), // #583 + INST(Pmulhw , ExtRm_P , O(000F00,E5,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #584 + INST(Pmulld , ExtRm , O(660F38,40,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 12 ), // #585 + INST(Pmullw , ExtRm_P , O(000F00,D5,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #586 + INST(Pmuludq , ExtRm_P , O(000F00,F4,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 4 ), // #587 + INST(Pop , X86Pop , O(000000,8F,0,_,_,_,_,_ ), O(000000,58,_,_,_,_,_,_ ), 0 , 67 , 165, 0 ), // #588 + INST(Popa , X86Op , O(660000,61,_,_,_,_,_,_ ), 0 , 19 , 0 , 81 , 0 ), // #589 + INST(Popad , X86Op , O(000000,61,_,_,_,_,_,_ ), 0 , 0 , 0 , 81 , 0 ), // #590 + INST(Popcnt , X86Rm_Raw66H , O(F30F00,B8,_,_,x,_,_,_ ), 0 , 6 , 0 , 22 , 101), // #591 + INST(Popf , X86Op , O(660000,9D,_,_,_,_,_,_ ), 0 , 19 , 0 , 30 , 102), // #592 + INST(Popfd , X86Op , O(000000,9D,_,_,_,_,_,_ ), 0 , 0 , 0 , 81 , 102), // #593 + INST(Popfq , X86Op , O(000000,9D,_,_,_,_,_,_ ), 0 , 0 , 0 , 33 , 102), // #594 + INST(Por , ExtRm_P , O(000F00,EB,_,_,_,_,_,_ ), 0 , 4 , 0 , 148, 88 ), // #595 + INST(Prefetch , X86M_Only , O(000F00,0D,0,_,_,_,_,_ ), 0 , 4 , 0 , 31 , 51 ), // #596 + INST(Prefetchnta , X86M_Only , O(000F00,18,0,_,_,_,_,_ ), 0 , 4 , 0 , 31 , 80 ), // #597 + INST(Prefetcht0 , X86M_Only , O(000F00,18,1,_,_,_,_,_ ), 0 , 29 , 0 , 31 , 80 ), // #598 + INST(Prefetcht1 , X86M_Only , O(000F00,18,2,_,_,_,_,_ ), 0 , 76 , 0 , 31 , 80 ), // #599 + INST(Prefetcht2 , X86M_Only , O(000F00,18,3,_,_,_,_,_ ), 0 , 78 , 0 , 31 , 80 ), // #600 + INST(Prefetchw , X86M_Only , O(000F00,0D,1,_,_,_,_,_ ), 0 , 29 , 0 , 31 , 103), // #601 + INST(Prefetchwt1 , X86M_Only , O(000F00,0D,2,_,_,_,_,_ ), 0 , 76 , 0 , 31 , 104), // #602 + INST(Psadbw , ExtRm_P , O(000F00,F6,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 94 ), // #603 + INST(Pshufb , ExtRm_P , O(000F38,00,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #604 + INST(Pshufd , ExtRmi , O(660F00,70,_,_,_,_,_,_ ), 0 , 3 , 0 , 8 , 4 ), // #605 + INST(Pshufhw , ExtRmi , O(F30F00,70,_,_,_,_,_,_ ), 0 , 6 , 0 , 8 , 4 ), // #606 + INST(Pshuflw , ExtRmi , O(F20F00,70,_,_,_,_,_,_ ), 0 , 5 , 0 , 8 , 4 ), // #607 + INST(Pshufw , ExtRmi_P , O(000F00,70,_,_,_,_,_,_ ), 0 , 4 , 0 , 166, 80 ), // #608 + INST(Psignb , ExtRm_P , O(000F38,08,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #609 + INST(Psignd , ExtRm_P , O(000F38,0A,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #610 + INST(Psignw , ExtRm_P , O(000F38,09,_,_,_,_,_,_ ), 0 , 83 , 0 , 146, 93 ), // #611 + INST(Pslld , ExtRmRi_P , O(000F00,F2,_,_,_,_,_,_ ), O(000F00,72,6,_,_,_,_,_ ), 4 , 68 , 167, 88 ), // #612 + INST(Pslldq , ExtRmRi , 0 , O(660F00,73,7,_,_,_,_,_ ), 0 , 69 , 168, 4 ), // #613 + INST(Psllq , ExtRmRi_P , O(000F00,F3,_,_,_,_,_,_ ), O(000F00,73,6,_,_,_,_,_ ), 4 , 70 , 167, 88 ), // #614 + INST(Psllw , ExtRmRi_P , O(000F00,F1,_,_,_,_,_,_ ), O(000F00,71,6,_,_,_,_,_ ), 4 , 71 , 167, 88 ), // #615 + INST(Psmash , X86Op , O(F30F01,FF,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 105), // #616 + INST(Psrad , ExtRmRi_P , O(000F00,E2,_,_,_,_,_,_ ), O(000F00,72,4,_,_,_,_,_ ), 4 , 72 , 167, 88 ), // #617 + INST(Psraw , ExtRmRi_P , O(000F00,E1,_,_,_,_,_,_ ), O(000F00,71,4,_,_,_,_,_ ), 4 , 73 , 167, 88 ), // #618 + INST(Psrld , ExtRmRi_P , O(000F00,D2,_,_,_,_,_,_ ), O(000F00,72,2,_,_,_,_,_ ), 4 , 74 , 167, 88 ), // #619 + INST(Psrldq , ExtRmRi , 0 , O(660F00,73,3,_,_,_,_,_ ), 0 , 75 , 168, 4 ), // #620 + INST(Psrlq , ExtRmRi_P , O(000F00,D3,_,_,_,_,_,_ ), O(000F00,73,2,_,_,_,_,_ ), 4 , 76 , 167, 88 ), // #621 + INST(Psrlw , ExtRmRi_P , O(000F00,D1,_,_,_,_,_,_ ), O(000F00,71,2,_,_,_,_,_ ), 4 , 77 , 167, 88 ), // #622 + INST(Psubb , ExtRm_P , O(000F00,F8,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #623 + INST(Psubd , ExtRm_P , O(000F00,FA,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #624 + INST(Psubq , ExtRm_P , O(000F00,FB,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 4 ), // #625 + INST(Psubsb , ExtRm_P , O(000F00,E8,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #626 + INST(Psubsw , ExtRm_P , O(000F00,E9,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #627 + INST(Psubusb , ExtRm_P , O(000F00,D8,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #628 + INST(Psubusw , ExtRm_P , O(000F00,D9,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #629 + INST(Psubw , ExtRm_P , O(000F00,F9,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #630 + INST(Pswapd , Ext3dNow , O(000F0F,BB,_,_,_,_,_,_ ), 0 , 87 , 0 , 150, 99 ), // #631 + INST(Ptest , ExtRm , O(660F38,17,_,_,_,_,_,_ ), 0 , 2 , 0 , 5 , 106), // #632 + INST(Ptwrite , X86M , O(F30F00,AE,4,_,_,_,_,_ ), 0 , 91 , 0 , 169, 107), // #633 + INST(Punpckhbw , ExtRm_P , O(000F00,68,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #634 + INST(Punpckhdq , ExtRm_P , O(000F00,6A,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #635 + INST(Punpckhqdq , ExtRm , O(660F00,6D,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #636 + INST(Punpckhwd , ExtRm_P , O(000F00,69,_,_,_,_,_,_ ), 0 , 4 , 0 , 146, 88 ), // #637 + INST(Punpcklbw , ExtRm_P , O(000F00,60,_,_,_,_,_,_ ), 0 , 4 , 0 , 170, 88 ), // #638 + INST(Punpckldq , ExtRm_P , O(000F00,62,_,_,_,_,_,_ ), 0 , 4 , 0 , 170, 88 ), // #639 + INST(Punpcklqdq , ExtRm , O(660F00,6C,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #640 + INST(Punpcklwd , ExtRm_P , O(000F00,61,_,_,_,_,_,_ ), 0 , 4 , 0 , 170, 88 ), // #641 + INST(Push , X86Push , O(000000,FF,6,_,_,_,_,_ ), O(000000,50,_,_,_,_,_,_ ), 32 , 78 , 171, 0 ), // #642 + INST(Pusha , X86Op , O(660000,60,_,_,_,_,_,_ ), 0 , 19 , 0 , 81 , 0 ), // #643 + INST(Pushad , X86Op , O(000000,60,_,_,_,_,_,_ ), 0 , 0 , 0 , 81 , 0 ), // #644 + INST(Pushf , X86Op , O(660000,9C,_,_,_,_,_,_ ), 0 , 19 , 0 , 30 , 108), // #645 + INST(Pushfd , X86Op , O(000000,9C,_,_,_,_,_,_ ), 0 , 0 , 0 , 81 , 108), // #646 + INST(Pushfq , X86Op , O(000000,9C,_,_,_,_,_,_ ), 0 , 0 , 0 , 33 , 108), // #647 + INST(Pvalidate , X86Op , O(F20F01,FF,_,_,_,_,_,_ ), 0 , 92 , 0 , 30 , 109), // #648 + INST(Pxor , ExtRm_P , O(000F00,EF,_,_,_,_,_,_ ), 0 , 4 , 0 , 149, 88 ), // #649 + INST(Rcl , X86Rot , O(000000,D0,2,_,x,_,_,_ ), 0 , 1 , 0 , 172, 110), // #650 + INST(Rcpps , ExtRm , O(000F00,53,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #651 + INST(Rcpss , ExtRm , O(F30F00,53,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #652 + INST(Rcr , X86Rot , O(000000,D0,3,_,x,_,_,_ ), 0 , 75 , 0 , 172, 110), // #653 + INST(Rdfsbase , X86M , O(F30F00,AE,0,_,x,_,_,_ ), 0 , 6 , 0 , 173, 111), // #654 + INST(Rdgsbase , X86M , O(F30F00,AE,1,_,x,_,_,_ ), 0 , 93 , 0 , 173, 111), // #655 + INST(Rdmsr , X86Op , O(000F00,32,_,_,_,_,_,_ ), 0 , 4 , 0 , 174, 112), // #656 + INST(Rdpid , X86R_Native , O(F30F00,C7,7,_,_,_,_,_ ), 0 , 94 , 0 , 175, 113), // #657 + INST(Rdpkru , X86Op , O(000F01,EE,_,_,_,_,_,_ ), 0 , 21 , 0 , 174, 114), // #658 + INST(Rdpmc , X86Op , O(000F00,33,_,_,_,_,_,_ ), 0 , 4 , 0 , 174, 0 ), // #659 + INST(Rdpru , X86Op , O(000F01,FD,_,_,_,_,_,_ ), 0 , 21 , 0 , 174, 115), // #660 + INST(Rdrand , X86M , O(000F00,C7,6,_,x,_,_,_ ), 0 , 80 , 0 , 23 , 116), // #661 + INST(Rdseed , X86M , O(000F00,C7,7,_,x,_,_,_ ), 0 , 22 , 0 , 23 , 117), // #662 + INST(Rdsspd , X86M , O(F30F00,1E,1,_,_,_,_,_ ), 0 , 93 , 0 , 76 , 56 ), // #663 + INST(Rdsspq , X86M , O(F30F00,1E,1,_,_,_,_,_ ), 0 , 93 , 0 , 77 , 56 ), // #664 + INST(Rdtsc , X86Op , O(000F00,31,_,_,_,_,_,_ ), 0 , 4 , 0 , 28 , 118), // #665 + INST(Rdtscp , X86Op , O(000F01,F9,_,_,_,_,_,_ ), 0 , 21 , 0 , 174, 119), // #666 + INST(Ret , X86Ret , O(000000,C2,_,_,_,_,_,_ ), 0 , 0 , 0 , 176, 0 ), // #667 + INST(Retf , X86Ret , O(000000,CA,_,_,x,_,_,_ ), 0 , 0 , 0 , 177, 0 ), // #668 + INST(Rmpadjust , X86Op , O(F30F01,FE,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 105), // #669 + INST(Rmpupdate , X86Op , O(F20F01,FE,_,_,_,_,_,_ ), 0 , 92 , 0 , 33 , 105), // #670 + INST(Rol , X86Rot , O(000000,D0,0,_,x,_,_,_ ), 0 , 0 , 0 , 172, 120), // #671 + INST(Ror , X86Rot , O(000000,D0,1,_,x,_,_,_ ), 0 , 31 , 0 , 172, 120), // #672 + INST(Rorx , VexRmi_Wx , V(F20F3A,F0,_,0,x,_,_,_ ), 0 , 95 , 0 , 178, 92 ), // #673 + INST(Roundpd , ExtRmi , O(660F3A,09,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #674 + INST(Roundps , ExtRmi , O(660F3A,08,_,_,_,_,_,_ ), 0 , 8 , 0 , 8 , 12 ), // #675 + INST(Roundsd , ExtRmi , O(660F3A,0B,_,_,_,_,_,_ ), 0 , 8 , 0 , 37 , 12 ), // #676 + INST(Roundss , ExtRmi , O(660F3A,0A,_,_,_,_,_,_ ), 0 , 8 , 0 , 38 , 12 ), // #677 + INST(Rsm , X86Op , O(000F00,AA,_,_,_,_,_,_ ), 0 , 4 , 0 , 81 , 1 ), // #678 + INST(Rsqrtps , ExtRm , O(000F00,52,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #679 + INST(Rsqrtss , ExtRm , O(F30F00,52,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #680 + INST(Rstorssp , X86M_Only , O(F30F00,01,5,_,_,_,_,_ ), 0 , 63 , 0 , 32 , 24 ), // #681 + INST(Sahf , X86Op , O(000000,9E,_,_,_,_,_,_ ), 0 , 0 , 0 , 97 , 121), // #682 + INST(Sal , X86Rot , O(000000,D0,4,_,x,_,_,_ ), 0 , 9 , 0 , 172, 1 ), // #683 + INST(Sar , X86Rot , O(000000,D0,7,_,x,_,_,_ ), 0 , 27 , 0 , 172, 1 ), // #684 + INST(Sarx , VexRmv_Wx , V(F30F38,F7,_,0,x,_,_,_ ), 0 , 88 , 0 , 13 , 92 ), // #685 + INST(Saveprevssp , X86Op , O(F30F01,EA,_,_,_,_,_,_ ), 0 , 25 , 0 , 30 , 24 ), // #686 + INST(Sbb , X86Arith , O(000000,18,3,_,x,_,_,_ ), 0 , 75 , 0 , 179, 2 ), // #687 + INST(Scas , X86StrRm , O(000000,AE,_,_,_,_,_,_ ), 0 , 0 , 0 , 180, 37 ), // #688 + INST(Senduipi , X86M_NoSize , O(F30F00,C7,6,_,_,_,_,_ ), 0 , 24 , 0 , 77 , 25 ), // #689 + INST(Serialize , X86Op , O(000F01,E8,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 122), // #690 + INST(Seta , X86Set , O(000F00,97,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 59 ), // #691 + INST(Setae , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #692 + INST(Setb , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #693 + INST(Setbe , X86Set , O(000F00,96,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 59 ), // #694 + INST(Setc , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #695 + INST(Sete , X86Set , O(000F00,94,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 61 ), // #696 + INST(Setg , X86Set , O(000F00,9F,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 62 ), // #697 + INST(Setge , X86Set , O(000F00,9D,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 63 ), // #698 + INST(Setl , X86Set , O(000F00,9C,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 63 ), // #699 + INST(Setle , X86Set , O(000F00,9E,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 62 ), // #700 + INST(Setna , X86Set , O(000F00,96,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 59 ), // #701 + INST(Setnae , X86Set , O(000F00,92,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #702 + INST(Setnb , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #703 + INST(Setnbe , X86Set , O(000F00,97,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 59 ), // #704 + INST(Setnc , X86Set , O(000F00,93,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 60 ), // #705 + INST(Setne , X86Set , O(000F00,95,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 61 ), // #706 + INST(Setng , X86Set , O(000F00,9E,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 62 ), // #707 + INST(Setnge , X86Set , O(000F00,9C,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 63 ), // #708 + INST(Setnl , X86Set , O(000F00,9D,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 63 ), // #709 + INST(Setnle , X86Set , O(000F00,9F,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 62 ), // #710 + INST(Setno , X86Set , O(000F00,91,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 57 ), // #711 + INST(Setnp , X86Set , O(000F00,9B,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 64 ), // #712 + INST(Setns , X86Set , O(000F00,99,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 65 ), // #713 + INST(Setnz , X86Set , O(000F00,95,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 61 ), // #714 + INST(Seto , X86Set , O(000F00,90,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 57 ), // #715 + INST(Setp , X86Set , O(000F00,9A,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 64 ), // #716 + INST(Setpe , X86Set , O(000F00,9A,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 64 ), // #717 + INST(Setpo , X86Set , O(000F00,9B,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 64 ), // #718 + INST(Sets , X86Set , O(000F00,98,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 65 ), // #719 + INST(Setssbsy , X86Op , O(F30F01,E8,_,_,_,_,_,_ ), 0 , 25 , 0 , 30 , 56 ), // #720 + INST(Setz , X86Set , O(000F00,94,_,_,_,_,_,_ ), 0 , 4 , 0 , 181, 61 ), // #721 + INST(Sfence , X86Fence , O(000F00,AE,7,_,_,_,_,_ ), 0 , 22 , 0 , 30 , 80 ), // #722 + INST(Sgdt , X86M_Only , O(000F00,01,0,_,_,_,_,_ ), 0 , 4 , 0 , 69 , 0 ), // #723 + INST(Sha1msg1 , ExtRm , O(000F38,C9,_,_,_,_,_,_ ), 0 , 83 , 0 , 5 , 123), // #724 + INST(Sha1msg2 , ExtRm , O(000F38,CA,_,_,_,_,_,_ ), 0 , 83 , 0 , 5 , 123), // #725 + INST(Sha1nexte , ExtRm , O(000F38,C8,_,_,_,_,_,_ ), 0 , 83 , 0 , 5 , 123), // #726 + INST(Sha1rnds4 , ExtRmi , O(000F3A,CC,_,_,_,_,_,_ ), 0 , 85 , 0 , 8 , 123), // #727 + INST(Sha256msg1 , ExtRm , O(000F38,CC,_,_,_,_,_,_ ), 0 , 83 , 0 , 5 , 123), // #728 + INST(Sha256msg2 , ExtRm , O(000F38,CD,_,_,_,_,_,_ ), 0 , 83 , 0 , 5 , 123), // #729 + INST(Sha256rnds2 , ExtRm_XMM0 , O(000F38,CB,_,_,_,_,_,_ ), 0 , 83 , 0 , 15 , 123), // #730 + INST(Shl , X86Rot , O(000000,D0,4,_,x,_,_,_ ), 0 , 9 , 0 , 172, 1 ), // #731 + INST(Shld , X86ShldShrd , O(000F00,A4,_,_,x,_,_,_ ), 0 , 4 , 0 , 182, 1 ), // #732 + INST(Shlx , VexRmv_Wx , V(660F38,F7,_,0,x,_,_,_ ), 0 , 96 , 0 , 13 , 92 ), // #733 + INST(Shr , X86Rot , O(000000,D0,5,_,x,_,_,_ ), 0 , 62 , 0 , 172, 1 ), // #734 + INST(Shrd , X86ShldShrd , O(000F00,AC,_,_,x,_,_,_ ), 0 , 4 , 0 , 182, 1 ), // #735 + INST(Shrx , VexRmv_Wx , V(F20F38,F7,_,0,x,_,_,_ ), 0 , 84 , 0 , 13 , 92 ), // #736 + INST(Shufpd , ExtRmi , O(660F00,C6,_,_,_,_,_,_ ), 0 , 3 , 0 , 8 , 4 ), // #737 + INST(Shufps , ExtRmi , O(000F00,C6,_,_,_,_,_,_ ), 0 , 4 , 0 , 8 , 5 ), // #738 + INST(Sidt , X86M_Only , O(000F00,01,1,_,_,_,_,_ ), 0 , 29 , 0 , 69 , 0 ), // #739 + INST(Skinit , X86Op_xAX , O(000F01,DE,_,_,_,_,_,_ ), 0 , 21 , 0 , 52 , 124), // #740 + INST(Sldt , X86M_NoMemSize , O(000F00,00,0,_,_,_,_,_ ), 0 , 4 , 0 , 183, 0 ), // #741 + INST(Slwpcb , VexR_Wx , V(XOP_M9,12,1,0,x,_,_,_ ), 0 , 11 , 0 , 108, 77 ), // #742 + INST(Smsw , X86M_NoMemSize , O(000F00,01,4,_,_,_,_,_ ), 0 , 97 , 0 , 183, 0 ), // #743 + INST(Sqrtpd , ExtRm , O(660F00,51,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #744 + INST(Sqrtps , ExtRm , O(000F00,51,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #745 + INST(Sqrtsd , ExtRm , O(F20F00,51,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #746 + INST(Sqrtss , ExtRm , O(F30F00,51,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #747 + INST(Stac , X86Op , O(000F01,CB,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 16 ), // #748 + INST(Stc , X86Op , O(000000,F9,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 17 ), // #749 + INST(Std , X86Op , O(000000,FD,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 18 ), // #750 + INST(Stgi , X86Op , O(000F01,DC,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 124), // #751 + INST(Sti , X86Op , O(000000,FB,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 23 ), // #752 + INST(Stmxcsr , X86M_Only , O(000F00,AE,3,_,_,_,_,_ ), 0 , 78 , 0 , 101, 5 ), // #753 + INST(Stos , X86StrMr , O(000000,AA,_,_,_,_,_,_ ), 0 , 0 , 0 , 184, 78 ), // #754 + INST(Str , X86M_NoMemSize , O(000F00,00,1,_,_,_,_,_ ), 0 , 29 , 0 , 183, 0 ), // #755 + INST(Sttilecfg , AmxCfg , V(660F38,49,_,0,0,_,_,_ ), 0 , 96 , 0 , 103, 76 ), // #756 + INST(Stui , X86Op , O(F30F01,EF,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 25 ), // #757 + INST(Sub , X86Arith , O(000000,28,5,_,x,_,_,_ ), 0 , 62 , 0 , 179, 1 ), // #758 + INST(Subpd , ExtRm , O(660F00,5C,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #759 + INST(Subps , ExtRm , O(000F00,5C,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #760 + INST(Subsd , ExtRm , O(F20F00,5C,_,_,_,_,_,_ ), 0 , 5 , 0 , 6 , 4 ), // #761 + INST(Subss , ExtRm , O(F30F00,5C,_,_,_,_,_,_ ), 0 , 6 , 0 , 7 , 5 ), // #762 + INST(Swapgs , X86Op , O(000F01,F8,_,_,_,_,_,_ ), 0 , 21 , 0 , 33 , 0 ), // #763 + INST(Syscall , X86Op , O(000F00,05,_,_,_,_,_,_ ), 0 , 4 , 0 , 33 , 0 ), // #764 + INST(Sysenter , X86Op , O(000F00,34,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 0 ), // #765 + INST(Sysexit , X86Op , O(000F00,35,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 0 ), // #766 + INST(Sysexitq , X86Op , O(000F00,35,_,_,1,_,_,_ ), 0 , 60 , 0 , 30 , 0 ), // #767 + INST(Sysret , X86Op , O(000F00,07,_,_,_,_,_,_ ), 0 , 4 , 0 , 33 , 0 ), // #768 + INST(Sysretq , X86Op , O(000F00,07,_,_,1,_,_,_ ), 0 , 60 , 0 , 33 , 0 ), // #769 + INST(T1mskc , VexVm_Wx , V(XOP_M9,01,7,0,x,_,_,_ ), 0 , 98 , 0 , 14 , 11 ), // #770 + INST(Tdpbf16ps , AmxRmv , V(F30F38,5C,_,0,0,_,_,_ ), 0 , 88 , 0 , 185, 125), // #771 + INST(Tdpbssd , AmxRmv , V(F20F38,5E,_,0,0,_,_,_ ), 0 , 84 , 0 , 185, 126), // #772 + INST(Tdpbsud , AmxRmv , V(F30F38,5E,_,0,0,_,_,_ ), 0 , 88 , 0 , 185, 126), // #773 + INST(Tdpbusd , AmxRmv , V(660F38,5E,_,0,0,_,_,_ ), 0 , 96 , 0 , 185, 126), // #774 + INST(Tdpbuud , AmxRmv , V(000F38,5E,_,0,0,_,_,_ ), 0 , 10 , 0 , 185, 126), // #775 + INST(Test , X86Test , O(000000,84,_,_,x,_,_,_ ), O(000000,F6,_,_,x,_,_,_ ), 0 , 79 , 186, 1 ), // #776 + INST(Testui , X86Op , O(F30F01,ED,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 127), // #777 + INST(Tileloadd , AmxRm , V(F20F38,4B,_,0,0,_,_,_ ), 0 , 84 , 0 , 187, 76 ), // #778 + INST(Tileloaddt1 , AmxRm , V(660F38,4B,_,0,0,_,_,_ ), 0 , 96 , 0 , 187, 76 ), // #779 + INST(Tilerelease , VexOpMod , V(000F38,49,0,0,0,_,_,_ ), 0 , 10 , 0 , 188, 76 ), // #780 + INST(Tilestored , AmxMr , V(F30F38,4B,_,0,0,_,_,_ ), 0 , 88 , 0 , 189, 76 ), // #781 + INST(Tilezero , AmxR , V(F20F38,49,_,0,0,_,_,_ ), 0 , 84 , 0 , 190, 76 ), // #782 + INST(Tpause , X86R32_EDX_EAX , O(660F00,AE,6,_,_,_,_,_ ), 0 , 26 , 0 , 191, 128), // #783 + INST(Tzcnt , X86Rm_Raw66H , O(F30F00,BC,_,_,x,_,_,_ ), 0 , 6 , 0 , 22 , 9 ), // #784 + INST(Tzmsk , VexVm_Wx , V(XOP_M9,01,4,0,x,_,_,_ ), 0 , 99 , 0 , 14 , 11 ), // #785 + INST(Ucomisd , ExtRm , O(660F00,2E,_,_,_,_,_,_ ), 0 , 3 , 0 , 6 , 41 ), // #786 + INST(Ucomiss , ExtRm , O(000F00,2E,_,_,_,_,_,_ ), 0 , 4 , 0 , 7 , 42 ), // #787 + INST(Ud0 , X86Rm , O(000F00,FF,_,_,_,_,_,_ ), 0 , 4 , 0 , 192, 0 ), // #788 + INST(Ud1 , X86Rm , O(000F00,B9,_,_,_,_,_,_ ), 0 , 4 , 0 , 192, 0 ), // #789 + INST(Ud2 , X86Op , O(000F00,0B,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 0 ), // #790 + INST(Uiret , X86Op , O(F30F01,EC,_,_,_,_,_,_ ), 0 , 25 , 0 , 33 , 25 ), // #791 + INST(Umonitor , X86R_FromM , O(F30F00,AE,6,_,_,_,_,_ ), 0 , 24 , 0 , 193, 129), // #792 + INST(Umwait , X86R32_EDX_EAX , O(F20F00,AE,6,_,_,_,_,_ ), 0 , 100, 0 , 191, 128), // #793 + INST(Unpckhpd , ExtRm , O(660F00,15,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #794 + INST(Unpckhps , ExtRm , O(000F00,15,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #795 + INST(Unpcklpd , ExtRm , O(660F00,14,_,_,_,_,_,_ ), 0 , 3 , 0 , 5 , 4 ), // #796 + INST(Unpcklps , ExtRm , O(000F00,14,_,_,_,_,_,_ ), 0 , 4 , 0 , 5 , 5 ), // #797 + INST(V4fmaddps , VexRm_T1_4X , E(F20F38,9A,_,2,_,0,4,T4X), 0 , 101, 0 , 194, 130), // #798 + INST(V4fmaddss , VexRm_T1_4X , E(F20F38,9B,_,0,_,0,4,T4X), 0 , 102, 0 , 195, 130), // #799 + INST(V4fnmaddps , VexRm_T1_4X , E(F20F38,AA,_,2,_,0,4,T4X), 0 , 101, 0 , 194, 130), // #800 + INST(V4fnmaddss , VexRm_T1_4X , E(F20F38,AB,_,0,_,0,4,T4X), 0 , 102, 0 , 195, 130), // #801 + INST(Vaddpd , VexRvm_Lx , V(660F00,58,_,x,I,1,4,FV ), 0 , 103, 0 , 196, 131), // #802 + INST(Vaddph , VexRvm_Lx , E(00MAP5,58,_,_,_,0,4,FV ), 0 , 104, 0 , 197, 132), // #803 + INST(Vaddps , VexRvm_Lx , V(000F00,58,_,x,I,0,4,FV ), 0 , 105, 0 , 198, 131), // #804 + INST(Vaddsd , VexRvm , V(F20F00,58,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #805 + INST(Vaddsh , VexRvm , E(F3MAP5,58,_,_,_,0,1,T1S), 0 , 107, 0 , 200, 134), // #806 + INST(Vaddss , VexRvm , V(F30F00,58,_,I,I,0,2,T1S), 0 , 108, 0 , 201, 133), // #807 + INST(Vaddsubpd , VexRvm_Lx , V(660F00,D0,_,x,I,_,_,_ ), 0 , 69 , 0 , 202, 135), // #808 + INST(Vaddsubps , VexRvm_Lx , V(F20F00,D0,_,x,I,_,_,_ ), 0 , 109, 0 , 202, 135), // #809 + INST(Vaesdec , VexRvm_Lx , V(660F38,DE,_,x,I,_,4,FVM), 0 , 110, 0 , 203, 136), // #810 + INST(Vaesdeclast , VexRvm_Lx , V(660F38,DF,_,x,I,_,4,FVM), 0 , 110, 0 , 203, 136), // #811 + INST(Vaesenc , VexRvm_Lx , V(660F38,DC,_,x,I,_,4,FVM), 0 , 110, 0 , 203, 136), // #812 + INST(Vaesenclast , VexRvm_Lx , V(660F38,DD,_,x,I,_,4,FVM), 0 , 110, 0 , 203, 136), // #813 + INST(Vaesimc , VexRm , V(660F38,DB,_,0,I,_,_,_ ), 0 , 96 , 0 , 204, 137), // #814 + INST(Vaeskeygenassist , VexRmi , V(660F3A,DF,_,0,I,_,_,_ ), 0 , 73 , 0 , 205, 137), // #815 + INST(Valignd , VexRvmi_Lx , E(660F3A,03,_,x,_,0,4,FV ), 0 , 111, 0 , 206, 138), // #816 + INST(Valignq , VexRvmi_Lx , E(660F3A,03,_,x,_,1,4,FV ), 0 , 112, 0 , 207, 138), // #817 + INST(Vandnpd , VexRvm_Lx , V(660F00,55,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 139), // #818 + INST(Vandnps , VexRvm_Lx , V(000F00,55,_,x,I,0,4,FV ), 0 , 105, 0 , 209, 139), // #819 + INST(Vandpd , VexRvm_Lx , V(660F00,54,_,x,I,1,4,FV ), 0 , 103, 0 , 210, 139), // #820 + INST(Vandps , VexRvm_Lx , V(000F00,54,_,x,I,0,4,FV ), 0 , 105, 0 , 211, 139), // #821 + INST(Vblendmpd , VexRvm_Lx , E(660F38,65,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #822 + INST(Vblendmps , VexRvm_Lx , E(660F38,65,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #823 + INST(Vblendpd , VexRvmi_Lx , V(660F3A,0D,_,x,I,_,_,_ ), 0 , 73 , 0 , 214, 135), // #824 + INST(Vblendps , VexRvmi_Lx , V(660F3A,0C,_,x,I,_,_,_ ), 0 , 73 , 0 , 214, 135), // #825 + INST(Vblendvpd , VexRvmr_Lx , V(660F3A,4B,_,x,0,_,_,_ ), 0 , 73 , 0 , 215, 135), // #826 + INST(Vblendvps , VexRvmr_Lx , V(660F3A,4A,_,x,0,_,_,_ ), 0 , 73 , 0 , 215, 135), // #827 + INST(Vbroadcastf128 , VexRm , V(660F38,1A,_,1,0,_,_,_ ), 0 , 115, 0 , 216, 135), // #828 + INST(Vbroadcastf32x2 , VexRm_Lx , E(660F38,19,_,x,_,0,3,T2 ), 0 , 116, 0 , 217, 140), // #829 + INST(Vbroadcastf32x4 , VexRm_Lx , E(660F38,1A,_,x,_,0,4,T4 ), 0 , 117, 0 , 218, 68 ), // #830 + INST(Vbroadcastf32x8 , VexRm , E(660F38,1B,_,2,_,0,5,T8 ), 0 , 118, 0 , 219, 66 ), // #831 + INST(Vbroadcastf64x2 , VexRm_Lx , E(660F38,1A,_,x,_,1,4,T2 ), 0 , 119, 0 , 218, 140), // #832 + INST(Vbroadcastf64x4 , VexRm , E(660F38,1B,_,2,_,1,5,T4 ), 0 , 120, 0 , 219, 68 ), // #833 + INST(Vbroadcasti128 , VexRm , V(660F38,5A,_,1,0,_,_,_ ), 0 , 115, 0 , 216, 141), // #834 + INST(Vbroadcasti32x2 , VexRm_Lx , E(660F38,59,_,x,_,0,3,T2 ), 0 , 116, 0 , 220, 140), // #835 + INST(Vbroadcasti32x4 , VexRm_Lx , E(660F38,5A,_,x,_,0,4,T4 ), 0 , 117, 0 , 218, 138), // #836 + INST(Vbroadcasti32x8 , VexRm , E(660F38,5B,_,2,_,0,5,T8 ), 0 , 118, 0 , 219, 66 ), // #837 + INST(Vbroadcasti64x2 , VexRm_Lx , E(660F38,5A,_,x,_,1,4,T2 ), 0 , 119, 0 , 218, 140), // #838 + INST(Vbroadcasti64x4 , VexRm , E(660F38,5B,_,2,_,1,5,T4 ), 0 , 120, 0 , 219, 68 ), // #839 + INST(Vbroadcastsd , VexRm_Lx , V(660F38,19,_,x,0,1,3,T1S), 0 , 121, 0 , 221, 142), // #840 + INST(Vbroadcastss , VexRm_Lx , V(660F38,18,_,x,0,0,2,T1S), 0 , 122, 0 , 222, 142), // #841 + INST(Vcmppd , VexRvmi_Lx_KEvex , V(660F00,C2,_,x,I,1,4,FV ), 0 , 103, 0 , 223, 131), // #842 + INST(Vcmpph , VexRvmi_Lx_KEvex , E(000F3A,C2,_,_,_,0,4,FV ), 0 , 123, 0 , 224, 132), // #843 + INST(Vcmpps , VexRvmi_Lx_KEvex , V(000F00,C2,_,x,I,0,4,FV ), 0 , 105, 0 , 225, 131), // #844 + INST(Vcmpsd , VexRvmi_KEvex , V(F20F00,C2,_,I,I,1,3,T1S), 0 , 106, 0 , 226, 133), // #845 + INST(Vcmpsh , VexRvmi_KEvex , E(F30F3A,C2,_,_,_,0,1,T1S), 0 , 124, 0 , 227, 134), // #846 + INST(Vcmpss , VexRvmi_KEvex , V(F30F00,C2,_,I,I,0,2,T1S), 0 , 108, 0 , 228, 133), // #847 + INST(Vcomisd , VexRm , V(660F00,2F,_,I,I,1,3,T1S), 0 , 125, 0 , 229, 143), // #848 + INST(Vcomish , VexRm , E(00MAP5,2F,_,_,_,0,1,T1S), 0 , 126, 0 , 230, 134), // #849 + INST(Vcomiss , VexRm , V(000F00,2F,_,I,I,0,2,T1S), 0 , 127, 0 , 231, 143), // #850 + INST(Vcompresspd , VexMr_Lx , E(660F38,8A,_,x,_,1,3,T1S), 0 , 128, 0 , 232, 138), // #851 + INST(Vcompressps , VexMr_Lx , E(660F38,8A,_,x,_,0,2,T1S), 0 , 129, 0 , 232, 138), // #852 + INST(Vcvtdq2pd , VexRm_Lx , V(F30F00,E6,_,x,I,0,3,HV ), 0 , 130, 0 , 233, 131), // #853 + INST(Vcvtdq2ph , VexRm_Lx , E(00MAP5,5B,_,_,_,0,4,FV ), 0 , 104, 0 , 234, 132), // #854 + INST(Vcvtdq2ps , VexRm_Lx , V(000F00,5B,_,x,I,0,4,FV ), 0 , 105, 0 , 235, 131), // #855 + INST(Vcvtne2ps2bf16 , VexRvm_Lx , E(F20F38,72,_,_,_,0,4,FV ), 0 , 131, 0 , 213, 144), // #856 + INST(Vcvtneps2bf16 , VexRm_Lx_Narrow , E(F30F38,72,_,_,_,0,4,FV ), 0 , 132, 0 , 236, 144), // #857 + INST(Vcvtpd2dq , VexRm_Lx_Narrow , V(F20F00,E6,_,x,I,1,4,FV ), 0 , 133, 0 , 237, 131), // #858 + INST(Vcvtpd2ph , VexRm_Lx , E(66MAP5,5A,_,_,_,1,4,FV ), 0 , 134, 0 , 238, 132), // #859 + INST(Vcvtpd2ps , VexRm_Lx_Narrow , V(660F00,5A,_,x,I,1,4,FV ), 0 , 103, 0 , 237, 131), // #860 + INST(Vcvtpd2qq , VexRm_Lx , E(660F00,7B,_,x,_,1,4,FV ), 0 , 135, 0 , 239, 140), // #861 + INST(Vcvtpd2udq , VexRm_Lx_Narrow , E(000F00,79,_,x,_,1,4,FV ), 0 , 136, 0 , 240, 138), // #862 + INST(Vcvtpd2uqq , VexRm_Lx , E(660F00,79,_,x,_,1,4,FV ), 0 , 135, 0 , 239, 140), // #863 + INST(Vcvtph2dq , VexRm_Lx , E(66MAP5,5B,_,_,_,0,3,HV ), 0 , 137, 0 , 241, 132), // #864 + INST(Vcvtph2pd , VexRm_Lx , E(00MAP5,5A,_,_,_,0,2,QV ), 0 , 138, 0 , 242, 132), // #865 + INST(Vcvtph2ps , VexRm_Lx , V(660F38,13,_,x,0,0,3,HVM), 0 , 139, 0 , 243, 145), // #866 + INST(Vcvtph2psx , VexRm_Lx , E(66MAP6,13,_,_,_,0,3,HV ), 0 , 140, 0 , 244, 132), // #867 + INST(Vcvtph2qq , VexRm_Lx , E(66MAP5,7B,_,_,_,0,2,QV ), 0 , 141, 0 , 245, 132), // #868 + INST(Vcvtph2udq , VexRm_Lx , E(00MAP5,79,_,_,_,0,3,HV ), 0 , 142, 0 , 241, 132), // #869 + INST(Vcvtph2uqq , VexRm_Lx , E(66MAP5,79,_,_,_,0,2,QV ), 0 , 141, 0 , 245, 132), // #870 + INST(Vcvtph2uw , VexRm_Lx , E(00MAP5,7D,_,_,_,0,4,FV ), 0 , 104, 0 , 246, 132), // #871 + INST(Vcvtph2w , VexRm_Lx , E(66MAP5,7D,_,_,_,0,4,FV ), 0 , 143, 0 , 246, 132), // #872 + INST(Vcvtps2dq , VexRm_Lx , V(660F00,5B,_,x,I,0,4,FV ), 0 , 144, 0 , 235, 131), // #873 + INST(Vcvtps2pd , VexRm_Lx , V(000F00,5A,_,x,I,0,3,HV ), 0 , 145, 0 , 247, 131), // #874 + INST(Vcvtps2ph , VexMri_Lx , V(660F3A,1D,_,x,0,0,3,HVM), 0 , 146, 0 , 248, 145), // #875 + INST(Vcvtps2phx , VexRm_Lx , E(66MAP5,1D,_,_,_,0,4,FV ), 0 , 143, 0 , 234, 132), // #876 + INST(Vcvtps2qq , VexRm_Lx , E(660F00,7B,_,x,_,0,3,HV ), 0 , 147, 0 , 249, 140), // #877 + INST(Vcvtps2udq , VexRm_Lx , E(000F00,79,_,x,_,0,4,FV ), 0 , 148, 0 , 250, 138), // #878 + INST(Vcvtps2uqq , VexRm_Lx , E(660F00,79,_,x,_,0,3,HV ), 0 , 147, 0 , 249, 140), // #879 + INST(Vcvtqq2pd , VexRm_Lx , E(F30F00,E6,_,x,_,1,4,FV ), 0 , 149, 0 , 239, 140), // #880 + INST(Vcvtqq2ph , VexRm_Lx , E(00MAP5,5B,_,_,_,1,4,FV ), 0 , 150, 0 , 238, 132), // #881 + INST(Vcvtqq2ps , VexRm_Lx_Narrow , E(000F00,5B,_,x,_,1,4,FV ), 0 , 136, 0 , 240, 140), // #882 + INST(Vcvtsd2sh , VexRvm , E(F2MAP5,5A,_,_,_,1,3,T1S), 0 , 151, 0 , 251, 134), // #883 + INST(Vcvtsd2si , VexRm_Wx , V(F20F00,2D,_,I,x,x,3,T1F), 0 , 152, 0 , 252, 133), // #884 + INST(Vcvtsd2ss , VexRvm , V(F20F00,5A,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #885 + INST(Vcvtsd2usi , VexRm_Wx , E(F20F00,79,_,I,_,x,3,T1F), 0 , 153, 0 , 253, 68 ), // #886 + INST(Vcvtsh2sd , VexRvm , E(F3MAP5,5A,_,_,_,0,1,T1S), 0 , 107, 0 , 254, 134), // #887 + INST(Vcvtsh2si , VexRm_Wx , E(F3MAP5,2D,_,_,_,x,1,T1S), 0 , 107, 0 , 255, 134), // #888 + INST(Vcvtsh2ss , VexRvm , E(00MAP6,13,_,_,_,0,1,T1S), 0 , 154, 0 , 254, 134), // #889 + INST(Vcvtsh2usi , VexRm_Wx , E(F3MAP5,79,_,_,_,x,1,T1S), 0 , 107, 0 , 255, 134), // #890 + INST(Vcvtsi2sd , VexRvm_Wx , V(F20F00,2A,_,I,x,x,2,T1W), 0 , 155, 0 , 256, 133), // #891 + INST(Vcvtsi2sh , VexRvm_Wx , E(F3MAP5,2A,_,_,_,x,2,T1W), 0 , 156, 0 , 257, 134), // #892 + INST(Vcvtsi2ss , VexRvm_Wx , V(F30F00,2A,_,I,x,x,2,T1W), 0 , 157, 0 , 256, 133), // #893 + INST(Vcvtss2sd , VexRvm , V(F30F00,5A,_,I,I,0,2,T1S), 0 , 108, 0 , 258, 133), // #894 + INST(Vcvtss2sh , VexRvm , E(00MAP5,1D,_,_,_,0,2,T1S), 0 , 158, 0 , 259, 134), // #895 + INST(Vcvtss2si , VexRm_Wx , V(F30F00,2D,_,I,x,x,2,T1F), 0 , 108, 0 , 260, 133), // #896 + INST(Vcvtss2usi , VexRm_Wx , E(F30F00,79,_,I,_,x,2,T1F), 0 , 159, 0 , 261, 68 ), // #897 + INST(Vcvttpd2dq , VexRm_Lx_Narrow , V(660F00,E6,_,x,I,1,4,FV ), 0 , 103, 0 , 262, 131), // #898 + INST(Vcvttpd2qq , VexRm_Lx , E(660F00,7A,_,x,_,1,4,FV ), 0 , 135, 0 , 263, 138), // #899 + INST(Vcvttpd2udq , VexRm_Lx_Narrow , E(000F00,78,_,x,_,1,4,FV ), 0 , 136, 0 , 264, 138), // #900 + INST(Vcvttpd2uqq , VexRm_Lx , E(660F00,78,_,x,_,1,4,FV ), 0 , 135, 0 , 263, 140), // #901 + INST(Vcvttph2dq , VexRm_Lx , E(F3MAP5,5B,_,_,_,0,3,HV ), 0 , 160, 0 , 244, 132), // #902 + INST(Vcvttph2qq , VexRm_Lx , E(66MAP5,7A,_,_,_,0,2,QV ), 0 , 141, 0 , 242, 132), // #903 + INST(Vcvttph2udq , VexRm_Lx , E(00MAP5,78,_,_,_,0,3,HV ), 0 , 142, 0 , 244, 132), // #904 + INST(Vcvttph2uqq , VexRm_Lx , E(66MAP5,78,_,_,_,0,2,QV ), 0 , 141, 0 , 242, 132), // #905 + INST(Vcvttph2uw , VexRm_Lx , E(00MAP5,7C,_,_,_,0,4,FV ), 0 , 104, 0 , 265, 132), // #906 + INST(Vcvttph2w , VexRm_Lx , E(66MAP5,7C,_,_,_,0,4,FV ), 0 , 143, 0 , 265, 132), // #907 + INST(Vcvttps2dq , VexRm_Lx , V(F30F00,5B,_,x,I,0,4,FV ), 0 , 161, 0 , 266, 131), // #908 + INST(Vcvttps2qq , VexRm_Lx , E(660F00,7A,_,x,_,0,3,HV ), 0 , 147, 0 , 267, 140), // #909 + INST(Vcvttps2udq , VexRm_Lx , E(000F00,78,_,x,_,0,4,FV ), 0 , 148, 0 , 268, 138), // #910 + INST(Vcvttps2uqq , VexRm_Lx , E(660F00,78,_,x,_,0,3,HV ), 0 , 147, 0 , 267, 140), // #911 + INST(Vcvttsd2si , VexRm_Wx , V(F20F00,2C,_,I,x,x,3,T1F), 0 , 152, 0 , 269, 133), // #912 + INST(Vcvttsd2usi , VexRm_Wx , E(F20F00,78,_,I,_,x,3,T1F), 0 , 153, 0 , 270, 68 ), // #913 + INST(Vcvttsh2si , VexRm_Wx , E(F3MAP5,2C,_,_,_,x,1,T1S), 0 , 107, 0 , 271, 134), // #914 + INST(Vcvttsh2usi , VexRm_Wx , E(F3MAP5,78,_,_,_,x,1,T1S), 0 , 107, 0 , 271, 134), // #915 + INST(Vcvttss2si , VexRm_Wx , V(F30F00,2C,_,I,x,x,2,T1F), 0 , 108, 0 , 272, 133), // #916 + INST(Vcvttss2usi , VexRm_Wx , E(F30F00,78,_,I,_,x,2,T1F), 0 , 159, 0 , 273, 68 ), // #917 + INST(Vcvtudq2pd , VexRm_Lx , E(F30F00,7A,_,x,_,0,3,HV ), 0 , 162, 0 , 274, 138), // #918 + INST(Vcvtudq2ph , VexRm_Lx , E(F2MAP5,7A,_,_,_,0,4,FV ), 0 , 163, 0 , 234, 132), // #919 + INST(Vcvtudq2ps , VexRm_Lx , E(F20F00,7A,_,x,_,0,4,FV ), 0 , 164, 0 , 250, 138), // #920 + INST(Vcvtuqq2pd , VexRm_Lx , E(F30F00,7A,_,x,_,1,4,FV ), 0 , 149, 0 , 239, 140), // #921 + INST(Vcvtuqq2ph , VexRm_Lx , E(F2MAP5,7A,_,_,_,1,4,FV ), 0 , 165, 0 , 238, 132), // #922 + INST(Vcvtuqq2ps , VexRm_Lx_Narrow , E(F20F00,7A,_,x,_,1,4,FV ), 0 , 166, 0 , 240, 140), // #923 + INST(Vcvtusi2sd , VexRvm_Wx , E(F20F00,7B,_,I,_,x,2,T1W), 0 , 167, 0 , 257, 68 ), // #924 + INST(Vcvtusi2sh , VexRvm_Wx , E(F3MAP5,7B,_,_,_,x,2,T1W), 0 , 156, 0 , 257, 134), // #925 + INST(Vcvtusi2ss , VexRvm_Wx , E(F30F00,7B,_,I,_,x,2,T1W), 0 , 168, 0 , 257, 68 ), // #926 + INST(Vcvtuw2ph , VexRm_Lx , E(F2MAP5,7D,_,_,_,0,4,FV ), 0 , 163, 0 , 246, 132), // #927 + INST(Vcvtw2ph , VexRm_Lx , E(F3MAP5,7D,_,_,_,0,4,FV ), 0 , 169, 0 , 246, 132), // #928 + INST(Vdbpsadbw , VexRvmi_Lx , E(660F3A,42,_,x,_,0,4,FVM), 0 , 111, 0 , 275, 146), // #929 + INST(Vdivpd , VexRvm_Lx , V(660F00,5E,_,x,I,1,4,FV ), 0 , 103, 0 , 196, 131), // #930 + INST(Vdivph , VexRvm_Lx , E(00MAP5,5E,_,_,_,0,4,FV ), 0 , 104, 0 , 197, 132), // #931 + INST(Vdivps , VexRvm_Lx , V(000F00,5E,_,x,I,0,4,FV ), 0 , 105, 0 , 198, 131), // #932 + INST(Vdivsd , VexRvm , V(F20F00,5E,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #933 + INST(Vdivsh , VexRvm , E(F3MAP5,5E,_,_,_,0,1,T1S), 0 , 107, 0 , 200, 134), // #934 + INST(Vdivss , VexRvm , V(F30F00,5E,_,I,I,0,2,T1S), 0 , 108, 0 , 201, 133), // #935 + INST(Vdpbf16ps , VexRvm_Lx , E(F30F38,52,_,_,_,0,4,FV ), 0 , 132, 0 , 213, 144), // #936 + INST(Vdppd , VexRvmi_Lx , V(660F3A,41,_,x,I,_,_,_ ), 0 , 73 , 0 , 276, 135), // #937 + INST(Vdpps , VexRvmi_Lx , V(660F3A,40,_,x,I,_,_,_ ), 0 , 73 , 0 , 214, 135), // #938 + INST(Verr , X86M_NoSize , O(000F00,00,4,_,_,_,_,_ ), 0 , 97 , 0 , 107, 10 ), // #939 + INST(Verw , X86M_NoSize , O(000F00,00,5,_,_,_,_,_ ), 0 , 77 , 0 , 107, 10 ), // #940 + INST(Vexp2pd , VexRm , E(660F38,C8,_,2,_,1,4,FV ), 0 , 170, 0 , 277, 147), // #941 + INST(Vexp2ps , VexRm , E(660F38,C8,_,2,_,0,4,FV ), 0 , 171, 0 , 278, 147), // #942 + INST(Vexpandpd , VexRm_Lx , E(660F38,88,_,x,_,1,3,T1S), 0 , 128, 0 , 279, 138), // #943 + INST(Vexpandps , VexRm_Lx , E(660F38,88,_,x,_,0,2,T1S), 0 , 129, 0 , 279, 138), // #944 + INST(Vextractf128 , VexMri , V(660F3A,19,_,1,0,_,_,_ ), 0 , 172, 0 , 280, 135), // #945 + INST(Vextractf32x4 , VexMri_Lx , E(660F3A,19,_,x,_,0,4,T4 ), 0 , 173, 0 , 281, 138), // #946 + INST(Vextractf32x8 , VexMri , E(660F3A,1B,_,2,_,0,5,T8 ), 0 , 174, 0 , 282, 66 ), // #947 + INST(Vextractf64x2 , VexMri_Lx , E(660F3A,19,_,x,_,1,4,T2 ), 0 , 175, 0 , 281, 140), // #948 + INST(Vextractf64x4 , VexMri , E(660F3A,1B,_,2,_,1,5,T4 ), 0 , 176, 0 , 282, 68 ), // #949 + INST(Vextracti128 , VexMri , V(660F3A,39,_,1,0,_,_,_ ), 0 , 172, 0 , 280, 141), // #950 + INST(Vextracti32x4 , VexMri_Lx , E(660F3A,39,_,x,_,0,4,T4 ), 0 , 173, 0 , 281, 138), // #951 + INST(Vextracti32x8 , VexMri , E(660F3A,3B,_,2,_,0,5,T8 ), 0 , 174, 0 , 282, 66 ), // #952 + INST(Vextracti64x2 , VexMri_Lx , E(660F3A,39,_,x,_,1,4,T2 ), 0 , 175, 0 , 281, 140), // #953 + INST(Vextracti64x4 , VexMri , E(660F3A,3B,_,2,_,1,5,T4 ), 0 , 176, 0 , 282, 68 ), // #954 + INST(Vextractps , VexMri , V(660F3A,17,_,0,I,I,2,T1S), 0 , 177, 0 , 283, 133), // #955 + INST(Vfcmaddcph , VexRvm_Lx , E(F2MAP6,56,_,_,_,0,4,FV ), 0 , 178, 0 , 284, 132), // #956 + INST(Vfcmaddcsh , VexRvm , E(F2MAP6,57,_,_,_,0,2,T1S), 0 , 179, 0 , 259, 132), // #957 + INST(Vfcmulcph , VexRvm_Lx , E(F2MAP6,D6,_,_,_,0,4,FV ), 0 , 178, 0 , 284, 132), // #958 + INST(Vfcmulcsh , VexRvm , E(F2MAP6,D7,_,_,_,0,2,T1S), 0 , 179, 0 , 259, 132), // #959 + INST(Vfixupimmpd , VexRvmi_Lx , E(660F3A,54,_,x,_,1,4,FV ), 0 , 112, 0 , 285, 138), // #960 + INST(Vfixupimmps , VexRvmi_Lx , E(660F3A,54,_,x,_,0,4,FV ), 0 , 111, 0 , 286, 138), // #961 + INST(Vfixupimmsd , VexRvmi , E(660F3A,55,_,I,_,1,3,T1S), 0 , 180, 0 , 287, 68 ), // #962 + INST(Vfixupimmss , VexRvmi , E(660F3A,55,_,I,_,0,2,T1S), 0 , 181, 0 , 288, 68 ), // #963 + INST(Vfmadd132pd , VexRvm_Lx , V(660F38,98,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #964 + INST(Vfmadd132ph , VexRvm_Lx , E(66MAP6,98,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #965 + INST(Vfmadd132ps , VexRvm_Lx , V(660F38,98,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #966 + INST(Vfmadd132sd , VexRvm , V(660F38,99,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #967 + INST(Vfmadd132sh , VexRvm , E(66MAP6,99,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #968 + INST(Vfmadd132ss , VexRvm , V(660F38,99,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #969 + INST(Vfmadd213pd , VexRvm_Lx , V(660F38,A8,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #970 + INST(Vfmadd213ph , VexRvm_Lx , E(66MAP6,A8,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #971 + INST(Vfmadd213ps , VexRvm_Lx , V(660F38,A8,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #972 + INST(Vfmadd213sd , VexRvm , V(660F38,A9,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #973 + INST(Vfmadd213sh , VexRvm , E(66MAP6,A9,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #974 + INST(Vfmadd213ss , VexRvm , V(660F38,A9,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #975 + INST(Vfmadd231pd , VexRvm_Lx , V(660F38,B8,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #976 + INST(Vfmadd231ph , VexRvm_Lx , E(66MAP6,B8,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #977 + INST(Vfmadd231ps , VexRvm_Lx , V(660F38,B8,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #978 + INST(Vfmadd231sd , VexRvm , V(660F38,B9,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #979 + INST(Vfmadd231sh , VexRvm , E(66MAP6,B9,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #980 + INST(Vfmadd231ss , VexRvm , V(660F38,B9,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #981 + INST(Vfmaddcph , VexRvm_Lx , E(F3MAP6,56,_,_,_,0,4,FV ), 0 , 186, 0 , 284, 132), // #982 + INST(Vfmaddcsh , VexRvm , E(F3MAP6,57,_,_,_,0,2,T1S), 0 , 187, 0 , 259, 132), // #983 + INST(Vfmaddpd , Fma4_Lx , V(660F3A,69,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #984 + INST(Vfmaddps , Fma4_Lx , V(660F3A,68,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #985 + INST(Vfmaddsd , Fma4 , V(660F3A,6B,_,0,x,_,_,_ ), 0 , 73 , 0 , 290, 150), // #986 + INST(Vfmaddss , Fma4 , V(660F3A,6A,_,0,x,_,_,_ ), 0 , 73 , 0 , 291, 150), // #987 + INST(Vfmaddsub132pd , VexRvm_Lx , V(660F38,96,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #988 + INST(Vfmaddsub132ph , VexRvm_Lx , E(66MAP6,96,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #989 + INST(Vfmaddsub132ps , VexRvm_Lx , V(660F38,96,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #990 + INST(Vfmaddsub213pd , VexRvm_Lx , V(660F38,A6,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #991 + INST(Vfmaddsub213ph , VexRvm_Lx , E(66MAP6,A6,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #992 + INST(Vfmaddsub213ps , VexRvm_Lx , V(660F38,A6,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #993 + INST(Vfmaddsub231pd , VexRvm_Lx , V(660F38,B6,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #994 + INST(Vfmaddsub231ph , VexRvm_Lx , E(66MAP6,B6,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #995 + INST(Vfmaddsub231ps , VexRvm_Lx , V(660F38,B6,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #996 + INST(Vfmaddsubpd , Fma4_Lx , V(660F3A,5D,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #997 + INST(Vfmaddsubps , Fma4_Lx , V(660F3A,5C,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #998 + INST(Vfmsub132pd , VexRvm_Lx , V(660F38,9A,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #999 + INST(Vfmsub132ph , VexRvm_Lx , E(66MAP6,9A,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1000 + INST(Vfmsub132ps , VexRvm_Lx , V(660F38,9A,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1001 + INST(Vfmsub132sd , VexRvm , V(660F38,9B,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1002 + INST(Vfmsub132sh , VexRvm , E(66MAP6,9B,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1003 + INST(Vfmsub132ss , VexRvm , V(660F38,9B,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1004 + INST(Vfmsub213pd , VexRvm_Lx , V(660F38,AA,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1005 + INST(Vfmsub213ph , VexRvm_Lx , E(66MAP6,AA,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1006 + INST(Vfmsub213ps , VexRvm_Lx , V(660F38,AA,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1007 + INST(Vfmsub213sd , VexRvm , V(660F38,AB,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1008 + INST(Vfmsub213sh , VexRvm , E(66MAP6,AB,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1009 + INST(Vfmsub213ss , VexRvm , V(660F38,AB,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1010 + INST(Vfmsub231pd , VexRvm_Lx , V(660F38,BA,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1011 + INST(Vfmsub231ph , VexRvm_Lx , E(66MAP6,BA,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1012 + INST(Vfmsub231ps , VexRvm_Lx , V(660F38,BA,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1013 + INST(Vfmsub231sd , VexRvm , V(660F38,BB,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1014 + INST(Vfmsub231sh , VexRvm , E(66MAP6,BB,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1015 + INST(Vfmsub231ss , VexRvm , V(660F38,BB,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1016 + INST(Vfmsubadd132pd , VexRvm_Lx , V(660F38,97,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1017 + INST(Vfmsubadd132ph , VexRvm_Lx , E(66MAP6,97,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1018 + INST(Vfmsubadd132ps , VexRvm_Lx , V(660F38,97,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1019 + INST(Vfmsubadd213pd , VexRvm_Lx , V(660F38,A7,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1020 + INST(Vfmsubadd213ph , VexRvm_Lx , E(66MAP6,A7,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1021 + INST(Vfmsubadd213ps , VexRvm_Lx , V(660F38,A7,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1022 + INST(Vfmsubadd231pd , VexRvm_Lx , V(660F38,B7,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1023 + INST(Vfmsubadd231ph , VexRvm_Lx , E(66MAP6,B7,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1024 + INST(Vfmsubadd231ps , VexRvm_Lx , V(660F38,B7,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1025 + INST(Vfmsubaddpd , Fma4_Lx , V(660F3A,5F,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1026 + INST(Vfmsubaddps , Fma4_Lx , V(660F3A,5E,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1027 + INST(Vfmsubpd , Fma4_Lx , V(660F3A,6D,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1028 + INST(Vfmsubps , Fma4_Lx , V(660F3A,6C,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1029 + INST(Vfmsubsd , Fma4 , V(660F3A,6F,_,0,x,_,_,_ ), 0 , 73 , 0 , 290, 150), // #1030 + INST(Vfmsubss , Fma4 , V(660F3A,6E,_,0,x,_,_,_ ), 0 , 73 , 0 , 291, 150), // #1031 + INST(Vfmulcph , VexRvm_Lx , E(F3MAP6,D6,_,_,_,0,4,FV ), 0 , 186, 0 , 284, 132), // #1032 + INST(Vfmulcsh , VexRvm , E(F3MAP6,D7,_,_,_,0,2,T1S), 0 , 187, 0 , 259, 132), // #1033 + INST(Vfnmadd132pd , VexRvm_Lx , V(660F38,9C,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1034 + INST(Vfnmadd132ph , VexRvm_Lx , E(66MAP6,9C,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1035 + INST(Vfnmadd132ps , VexRvm_Lx , V(660F38,9C,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1036 + INST(Vfnmadd132sd , VexRvm , V(660F38,9D,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1037 + INST(Vfnmadd132sh , VexRvm , E(66MAP6,9D,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1038 + INST(Vfnmadd132ss , VexRvm , V(660F38,9D,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1039 + INST(Vfnmadd213pd , VexRvm_Lx , V(660F38,AC,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1040 + INST(Vfnmadd213ph , VexRvm_Lx , E(66MAP6,AC,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1041 + INST(Vfnmadd213ps , VexRvm_Lx , V(660F38,AC,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1042 + INST(Vfnmadd213sd , VexRvm , V(660F38,AD,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1043 + INST(Vfnmadd213sh , VexRvm , E(66MAP6,AD,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1044 + INST(Vfnmadd213ss , VexRvm , V(660F38,AD,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1045 + INST(Vfnmadd231pd , VexRvm_Lx , V(660F38,BC,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1046 + INST(Vfnmadd231ph , VexRvm_Lx , E(66MAP6,BC,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1047 + INST(Vfnmadd231ps , VexRvm_Lx , V(660F38,BC,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1048 + INST(Vfnmadd231sd , VexRvm , V(660F38,BD,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1049 + INST(Vfnmadd231sh , VexRvm , E(66MAP6,BD,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1050 + INST(Vfnmadd231ss , VexRvm , V(660F38,BD,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1051 + INST(Vfnmaddpd , Fma4_Lx , V(660F3A,79,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1052 + INST(Vfnmaddps , Fma4_Lx , V(660F3A,78,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1053 + INST(Vfnmaddsd , Fma4 , V(660F3A,7B,_,0,x,_,_,_ ), 0 , 73 , 0 , 290, 150), // #1054 + INST(Vfnmaddss , Fma4 , V(660F3A,7A,_,0,x,_,_,_ ), 0 , 73 , 0 , 291, 150), // #1055 + INST(Vfnmsub132pd , VexRvm_Lx , V(660F38,9E,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1056 + INST(Vfnmsub132ph , VexRvm_Lx , E(66MAP6,9E,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1057 + INST(Vfnmsub132ps , VexRvm_Lx , V(660F38,9E,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1058 + INST(Vfnmsub132sd , VexRvm , V(660F38,9F,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1059 + INST(Vfnmsub132sh , VexRvm , E(66MAP6,9F,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1060 + INST(Vfnmsub132ss , VexRvm , V(660F38,9F,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1061 + INST(Vfnmsub213pd , VexRvm_Lx , V(660F38,AE,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1062 + INST(Vfnmsub213ph , VexRvm_Lx , E(66MAP6,AE,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1063 + INST(Vfnmsub213ps , VexRvm_Lx , V(660F38,AE,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1064 + INST(Vfnmsub213sd , VexRvm , V(660F38,AF,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1065 + INST(Vfnmsub213sh , VexRvm , E(66MAP6,AF,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1066 + INST(Vfnmsub213ss , VexRvm , V(660F38,AF,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1067 + INST(Vfnmsub231pd , VexRvm_Lx , V(660F38,BE,_,x,1,1,4,FV ), 0 , 182, 0 , 196, 148), // #1068 + INST(Vfnmsub231ph , VexRvm_Lx , E(66MAP6,BE,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1069 + INST(Vfnmsub231ps , VexRvm_Lx , V(660F38,BE,_,x,0,0,4,FV ), 0 , 110, 0 , 198, 148), // #1070 + INST(Vfnmsub231sd , VexRvm , V(660F38,BF,_,I,1,1,3,T1S), 0 , 184, 0 , 199, 149), // #1071 + INST(Vfnmsub231sh , VexRvm , E(66MAP6,BF,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1072 + INST(Vfnmsub231ss , VexRvm , V(660F38,BF,_,I,0,0,2,T1S), 0 , 122, 0 , 201, 149), // #1073 + INST(Vfnmsubpd , Fma4_Lx , V(660F3A,7D,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1074 + INST(Vfnmsubps , Fma4_Lx , V(660F3A,7C,_,x,x,_,_,_ ), 0 , 73 , 0 , 289, 150), // #1075 + INST(Vfnmsubsd , Fma4 , V(660F3A,7F,_,0,x,_,_,_ ), 0 , 73 , 0 , 290, 150), // #1076 + INST(Vfnmsubss , Fma4 , V(660F3A,7E,_,0,x,_,_,_ ), 0 , 73 , 0 , 291, 150), // #1077 + INST(Vfpclasspd , VexRmi_Lx , E(660F3A,66,_,x,_,1,4,FV ), 0 , 112, 0 , 292, 140), // #1078 + INST(Vfpclassph , VexRmi_Lx , E(000F3A,66,_,_,_,0,4,FV ), 0 , 123, 0 , 293, 132), // #1079 + INST(Vfpclassps , VexRmi_Lx , E(660F3A,66,_,x,_,0,4,FV ), 0 , 111, 0 , 294, 140), // #1080 + INST(Vfpclasssd , VexRmi , E(660F3A,67,_,I,_,1,3,T1S), 0 , 180, 0 , 295, 66 ), // #1081 + INST(Vfpclasssh , VexRmi , E(000F3A,67,_,_,_,0,1,T1S), 0 , 188, 0 , 296, 134), // #1082 + INST(Vfpclassss , VexRmi , E(660F3A,67,_,I,_,0,2,T1S), 0 , 181, 0 , 297, 66 ), // #1083 + INST(Vfrczpd , VexRm_Lx , V(XOP_M9,81,_,x,0,_,_,_ ), 0 , 79 , 0 , 298, 151), // #1084 + INST(Vfrczps , VexRm_Lx , V(XOP_M9,80,_,x,0,_,_,_ ), 0 , 79 , 0 , 298, 151), // #1085 + INST(Vfrczsd , VexRm , V(XOP_M9,83,_,0,0,_,_,_ ), 0 , 79 , 0 , 299, 151), // #1086 + INST(Vfrczss , VexRm , V(XOP_M9,82,_,0,0,_,_,_ ), 0 , 79 , 0 , 300, 151), // #1087 + INST(Vgatherdpd , VexRmvRm_VM , V(660F38,92,_,x,1,_,_,_ ), E(660F38,92,_,x,_,1,3,T1S), 189, 80 , 301, 152), // #1088 + INST(Vgatherdps , VexRmvRm_VM , V(660F38,92,_,x,0,_,_,_ ), E(660F38,92,_,x,_,0,2,T1S), 96 , 81 , 302, 152), // #1089 + INST(Vgatherpf0dpd , VexM_VM , E(660F38,C6,1,2,_,1,3,T1S), 0 , 190, 0 , 303, 153), // #1090 + INST(Vgatherpf0dps , VexM_VM , E(660F38,C6,1,2,_,0,2,T1S), 0 , 191, 0 , 304, 153), // #1091 + INST(Vgatherpf0qpd , VexM_VM , E(660F38,C7,1,2,_,1,3,T1S), 0 , 190, 0 , 305, 153), // #1092 + INST(Vgatherpf0qps , VexM_VM , E(660F38,C7,1,2,_,0,2,T1S), 0 , 191, 0 , 305, 153), // #1093 + INST(Vgatherpf1dpd , VexM_VM , E(660F38,C6,2,2,_,1,3,T1S), 0 , 192, 0 , 303, 153), // #1094 + INST(Vgatherpf1dps , VexM_VM , E(660F38,C6,2,2,_,0,2,T1S), 0 , 193, 0 , 304, 153), // #1095 + INST(Vgatherpf1qpd , VexM_VM , E(660F38,C7,2,2,_,1,3,T1S), 0 , 192, 0 , 305, 153), // #1096 + INST(Vgatherpf1qps , VexM_VM , E(660F38,C7,2,2,_,0,2,T1S), 0 , 193, 0 , 305, 153), // #1097 + INST(Vgatherqpd , VexRmvRm_VM , V(660F38,93,_,x,1,_,_,_ ), E(660F38,93,_,x,_,1,3,T1S), 189, 82 , 306, 152), // #1098 + INST(Vgatherqps , VexRmvRm_VM , V(660F38,93,_,x,0,_,_,_ ), E(660F38,93,_,x,_,0,2,T1S), 96 , 83 , 307, 152), // #1099 + INST(Vgetexppd , VexRm_Lx , E(660F38,42,_,x,_,1,4,FV ), 0 , 113, 0 , 263, 138), // #1100 + INST(Vgetexpph , VexRm_Lx , E(66MAP6,42,_,_,_,0,4,FV ), 0 , 183, 0 , 265, 132), // #1101 + INST(Vgetexpps , VexRm_Lx , E(660F38,42,_,x,_,0,4,FV ), 0 , 114, 0 , 268, 138), // #1102 + INST(Vgetexpsd , VexRvm , E(660F38,43,_,I,_,1,3,T1S), 0 , 128, 0 , 308, 68 ), // #1103 + INST(Vgetexpsh , VexRvm , E(66MAP6,43,_,_,_,0,1,T1S), 0 , 185, 0 , 254, 134), // #1104 + INST(Vgetexpss , VexRvm , E(660F38,43,_,I,_,0,2,T1S), 0 , 129, 0 , 309, 68 ), // #1105 + INST(Vgetmantpd , VexRmi_Lx , E(660F3A,26,_,x,_,1,4,FV ), 0 , 112, 0 , 310, 138), // #1106 + INST(Vgetmantph , VexRmi_Lx , E(000F3A,26,_,_,_,0,4,FV ), 0 , 123, 0 , 311, 132), // #1107 + INST(Vgetmantps , VexRmi_Lx , E(660F3A,26,_,x,_,0,4,FV ), 0 , 111, 0 , 312, 138), // #1108 + INST(Vgetmantsd , VexRvmi , E(660F3A,27,_,I,_,1,3,T1S), 0 , 180, 0 , 287, 68 ), // #1109 + INST(Vgetmantsh , VexRvmi , E(000F3A,27,_,_,_,0,1,T1S), 0 , 188, 0 , 313, 134), // #1110 + INST(Vgetmantss , VexRvmi , E(660F3A,27,_,I,_,0,2,T1S), 0 , 181, 0 , 288, 68 ), // #1111 + INST(Vgf2p8affineinvqb, VexRvmi_Lx , V(660F3A,CF,_,x,1,1,4,FV ), 0 , 194, 0 , 314, 154), // #1112 + INST(Vgf2p8affineqb , VexRvmi_Lx , V(660F3A,CE,_,x,1,1,4,FV ), 0 , 194, 0 , 314, 154), // #1113 + INST(Vgf2p8mulb , VexRvm_Lx , V(660F38,CF,_,x,0,0,4,FV ), 0 , 110, 0 , 315, 154), // #1114 + INST(Vhaddpd , VexRvm_Lx , V(660F00,7C,_,x,I,_,_,_ ), 0 , 69 , 0 , 202, 135), // #1115 + INST(Vhaddps , VexRvm_Lx , V(F20F00,7C,_,x,I,_,_,_ ), 0 , 109, 0 , 202, 135), // #1116 + INST(Vhsubpd , VexRvm_Lx , V(660F00,7D,_,x,I,_,_,_ ), 0 , 69 , 0 , 202, 135), // #1117 + INST(Vhsubps , VexRvm_Lx , V(F20F00,7D,_,x,I,_,_,_ ), 0 , 109, 0 , 202, 135), // #1118 + INST(Vinsertf128 , VexRvmi , V(660F3A,18,_,1,0,_,_,_ ), 0 , 172, 0 , 316, 135), // #1119 + INST(Vinsertf32x4 , VexRvmi_Lx , E(660F3A,18,_,x,_,0,4,T4 ), 0 , 173, 0 , 317, 138), // #1120 + INST(Vinsertf32x8 , VexRvmi , E(660F3A,1A,_,2,_,0,5,T8 ), 0 , 174, 0 , 318, 66 ), // #1121 + INST(Vinsertf64x2 , VexRvmi_Lx , E(660F3A,18,_,x,_,1,4,T2 ), 0 , 175, 0 , 317, 140), // #1122 + INST(Vinsertf64x4 , VexRvmi , E(660F3A,1A,_,2,_,1,5,T4 ), 0 , 176, 0 , 318, 68 ), // #1123 + INST(Vinserti128 , VexRvmi , V(660F3A,38,_,1,0,_,_,_ ), 0 , 172, 0 , 316, 141), // #1124 + INST(Vinserti32x4 , VexRvmi_Lx , E(660F3A,38,_,x,_,0,4,T4 ), 0 , 173, 0 , 317, 138), // #1125 + INST(Vinserti32x8 , VexRvmi , E(660F3A,3A,_,2,_,0,5,T8 ), 0 , 174, 0 , 318, 66 ), // #1126 + INST(Vinserti64x2 , VexRvmi_Lx , E(660F3A,38,_,x,_,1,4,T2 ), 0 , 175, 0 , 317, 140), // #1127 + INST(Vinserti64x4 , VexRvmi , E(660F3A,3A,_,2,_,1,5,T4 ), 0 , 176, 0 , 318, 68 ), // #1128 + INST(Vinsertps , VexRvmi , V(660F3A,21,_,0,I,0,2,T1S), 0 , 177, 0 , 319, 133), // #1129 + INST(Vlddqu , VexRm_Lx , V(F20F00,F0,_,x,I,_,_,_ ), 0 , 109, 0 , 320, 135), // #1130 + INST(Vldmxcsr , VexM , V(000F00,AE,2,0,I,_,_,_ ), 0 , 195, 0 , 321, 135), // #1131 + INST(Vmaskmovdqu , VexRm_ZDI , V(660F00,F7,_,0,I,_,_,_ ), 0 , 69 , 0 , 322, 135), // #1132 + INST(Vmaskmovpd , VexRvmMvr_Lx , V(660F38,2D,_,x,0,_,_,_ ), V(660F38,2F,_,x,0,_,_,_ ), 96 , 84 , 323, 135), // #1133 + INST(Vmaskmovps , VexRvmMvr_Lx , V(660F38,2C,_,x,0,_,_,_ ), V(660F38,2E,_,x,0,_,_,_ ), 96 , 85 , 323, 135), // #1134 + INST(Vmaxpd , VexRvm_Lx , V(660F00,5F,_,x,I,1,4,FV ), 0 , 103, 0 , 324, 131), // #1135 + INST(Vmaxph , VexRvm_Lx , E(00MAP5,5F,_,_,_,0,4,FV ), 0 , 104, 0 , 325, 132), // #1136 + INST(Vmaxps , VexRvm_Lx , V(000F00,5F,_,x,I,0,4,FV ), 0 , 105, 0 , 326, 131), // #1137 + INST(Vmaxsd , VexRvm , V(F20F00,5F,_,I,I,1,3,T1S), 0 , 106, 0 , 327, 131), // #1138 + INST(Vmaxsh , VexRvm , E(F3MAP5,5F,_,_,_,0,1,T1S), 0 , 107, 0 , 254, 134), // #1139 + INST(Vmaxss , VexRvm , V(F30F00,5F,_,I,I,0,2,T1S), 0 , 108, 0 , 258, 131), // #1140 + INST(Vmcall , X86Op , O(000F01,C1,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 58 ), // #1141 + INST(Vmclear , X86M_Only , O(660F00,C7,6,_,_,_,_,_ ), 0 , 26 , 0 , 32 , 58 ), // #1142 + INST(Vmfunc , X86Op , O(000F01,D4,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 58 ), // #1143 + INST(Vminpd , VexRvm_Lx , V(660F00,5D,_,x,I,1,4,FV ), 0 , 103, 0 , 324, 131), // #1144 + INST(Vminph , VexRvm_Lx , E(00MAP5,5D,_,_,_,0,4,FV ), 0 , 104, 0 , 325, 132), // #1145 + INST(Vminps , VexRvm_Lx , V(000F00,5D,_,x,I,0,4,FV ), 0 , 105, 0 , 326, 131), // #1146 + INST(Vminsd , VexRvm , V(F20F00,5D,_,I,I,1,3,T1S), 0 , 106, 0 , 327, 131), // #1147 + INST(Vminsh , VexRvm , E(F3MAP5,5D,_,_,_,0,1,T1S), 0 , 107, 0 , 254, 134), // #1148 + INST(Vminss , VexRvm , V(F30F00,5D,_,I,I,0,2,T1S), 0 , 108, 0 , 258, 131), // #1149 + INST(Vmlaunch , X86Op , O(000F01,C2,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 58 ), // #1150 + INST(Vmload , X86Op_xAX , O(000F01,DA,_,_,_,_,_,_ ), 0 , 21 , 0 , 328, 22 ), // #1151 + INST(Vmmcall , X86Op , O(000F01,D9,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 22 ), // #1152 + INST(Vmovapd , VexRmMr_Lx , V(660F00,28,_,x,I,1,4,FVM), V(660F00,29,_,x,I,1,4,FVM), 103, 86 , 329, 155), // #1153 + INST(Vmovaps , VexRmMr_Lx , V(000F00,28,_,x,I,0,4,FVM), V(000F00,29,_,x,I,0,4,FVM), 105, 87 , 329, 155), // #1154 + INST(Vmovd , VexMovdMovq , V(660F00,6E,_,0,0,0,2,T1S), V(660F00,7E,_,0,0,0,2,T1S), 196, 88 , 330, 133), // #1155 + INST(Vmovddup , VexRm_Lx , V(F20F00,12,_,x,I,1,3,DUP), 0 , 197, 0 , 331, 131), // #1156 + INST(Vmovdqa , VexRmMr_Lx , V(660F00,6F,_,x,I,_,_,_ ), V(660F00,7F,_,x,I,_,_,_ ), 69 , 89 , 332, 156), // #1157 + INST(Vmovdqa32 , VexRmMr_Lx , E(660F00,6F,_,x,_,0,4,FVM), E(660F00,7F,_,x,_,0,4,FVM), 198, 90 , 333, 157), // #1158 + INST(Vmovdqa64 , VexRmMr_Lx , E(660F00,6F,_,x,_,1,4,FVM), E(660F00,7F,_,x,_,1,4,FVM), 135, 91 , 333, 157), // #1159 + INST(Vmovdqu , VexRmMr_Lx , V(F30F00,6F,_,x,I,_,_,_ ), V(F30F00,7F,_,x,I,_,_,_ ), 199, 92 , 332, 156), // #1160 + INST(Vmovdqu16 , VexRmMr_Lx , E(F20F00,6F,_,x,_,1,4,FVM), E(F20F00,7F,_,x,_,1,4,FVM), 166, 93 , 333, 158), // #1161 + INST(Vmovdqu32 , VexRmMr_Lx , E(F30F00,6F,_,x,_,0,4,FVM), E(F30F00,7F,_,x,_,0,4,FVM), 200, 94 , 333, 157), // #1162 + INST(Vmovdqu64 , VexRmMr_Lx , E(F30F00,6F,_,x,_,1,4,FVM), E(F30F00,7F,_,x,_,1,4,FVM), 149, 95 , 333, 157), // #1163 + INST(Vmovdqu8 , VexRmMr_Lx , E(F20F00,6F,_,x,_,0,4,FVM), E(F20F00,7F,_,x,_,0,4,FVM), 164, 96 , 333, 158), // #1164 + INST(Vmovhlps , VexRvm , V(000F00,12,_,0,I,0,_,_ ), 0 , 72 , 0 , 334, 133), // #1165 + INST(Vmovhpd , VexRvmMr , V(660F00,16,_,0,I,1,3,T1S), V(660F00,17,_,0,I,1,3,T1S), 125, 97 , 335, 133), // #1166 + INST(Vmovhps , VexRvmMr , V(000F00,16,_,0,I,0,3,T2 ), V(000F00,17,_,0,I,0,3,T2 ), 201, 98 , 335, 133), // #1167 + INST(Vmovlhps , VexRvm , V(000F00,16,_,0,I,0,_,_ ), 0 , 72 , 0 , 334, 133), // #1168 + INST(Vmovlpd , VexRvmMr , V(660F00,12,_,0,I,1,3,T1S), V(660F00,13,_,0,I,1,3,T1S), 125, 99 , 335, 133), // #1169 + INST(Vmovlps , VexRvmMr , V(000F00,12,_,0,I,0,3,T2 ), V(000F00,13,_,0,I,0,3,T2 ), 201, 100, 335, 133), // #1170 + INST(Vmovmskpd , VexRm_Lx , V(660F00,50,_,x,I,_,_,_ ), 0 , 69 , 0 , 336, 135), // #1171 + INST(Vmovmskps , VexRm_Lx , V(000F00,50,_,x,I,_,_,_ ), 0 , 72 , 0 , 336, 135), // #1172 + INST(Vmovntdq , VexMr_Lx , V(660F00,E7,_,x,I,0,4,FVM), 0 , 144, 0 , 337, 131), // #1173 + INST(Vmovntdqa , VexRm_Lx , V(660F38,2A,_,x,I,0,4,FVM), 0 , 110, 0 , 338, 142), // #1174 + INST(Vmovntpd , VexMr_Lx , V(660F00,2B,_,x,I,1,4,FVM), 0 , 103, 0 , 337, 131), // #1175 + INST(Vmovntps , VexMr_Lx , V(000F00,2B,_,x,I,0,4,FVM), 0 , 105, 0 , 337, 131), // #1176 + INST(Vmovq , VexMovdMovq , V(660F00,6E,_,0,I,1,3,T1S), V(660F00,7E,_,0,I,1,3,T1S), 125, 101, 339, 159), // #1177 + INST(Vmovsd , VexMovssMovsd , V(F20F00,10,_,I,I,1,3,T1S), V(F20F00,11,_,I,I,1,3,T1S), 106, 102, 340, 159), // #1178 + INST(Vmovsh , VexMovssMovsd , E(F3MAP5,10,_,I,_,0,1,T1S), E(F3MAP5,11,_,I,_,0,1,T1S), 107, 103, 341, 134), // #1179 + INST(Vmovshdup , VexRm_Lx , V(F30F00,16,_,x,I,0,4,FVM), 0 , 161, 0 , 342, 131), // #1180 + INST(Vmovsldup , VexRm_Lx , V(F30F00,12,_,x,I,0,4,FVM), 0 , 161, 0 , 342, 131), // #1181 + INST(Vmovss , VexMovssMovsd , V(F30F00,10,_,I,I,0,2,T1S), V(F30F00,11,_,I,I,0,2,T1S), 108, 104, 343, 159), // #1182 + INST(Vmovupd , VexRmMr_Lx , V(660F00,10,_,x,I,1,4,FVM), V(660F00,11,_,x,I,1,4,FVM), 103, 105, 329, 155), // #1183 + INST(Vmovups , VexRmMr_Lx , V(000F00,10,_,x,I,0,4,FVM), V(000F00,11,_,x,I,0,4,FVM), 105, 106, 329, 155), // #1184 + INST(Vmovw , VexMovdMovq , E(66MAP5,6E,_,0,_,I,1,T1S), E(66MAP5,7E,_,0,_,I,1,T1S), 202, 107, 344, 134), // #1185 + INST(Vmpsadbw , VexRvmi_Lx , V(660F3A,42,_,x,I,_,_,_ ), 0 , 73 , 0 , 214, 160), // #1186 + INST(Vmptrld , X86M_Only , O(000F00,C7,6,_,_,_,_,_ ), 0 , 80 , 0 , 32 , 58 ), // #1187 + INST(Vmptrst , X86M_Only , O(000F00,C7,7,_,_,_,_,_ ), 0 , 22 , 0 , 32 , 58 ), // #1188 + INST(Vmread , X86Mr_NoSize , O(000F00,78,_,_,_,_,_,_ ), 0 , 4 , 0 , 345, 58 ), // #1189 + INST(Vmresume , X86Op , O(000F01,C3,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 58 ), // #1190 + INST(Vmrun , X86Op_xAX , O(000F01,D8,_,_,_,_,_,_ ), 0 , 21 , 0 , 328, 22 ), // #1191 + INST(Vmsave , X86Op_xAX , O(000F01,DB,_,_,_,_,_,_ ), 0 , 21 , 0 , 328, 22 ), // #1192 + INST(Vmulpd , VexRvm_Lx , V(660F00,59,_,x,I,1,4,FV ), 0 , 103, 0 , 196, 131), // #1193 + INST(Vmulph , VexRvm_Lx , E(00MAP5,59,_,_,_,0,4,FV ), 0 , 104, 0 , 197, 132), // #1194 + INST(Vmulps , VexRvm_Lx , V(000F00,59,_,x,I,0,4,FV ), 0 , 105, 0 , 198, 131), // #1195 + INST(Vmulsd , VexRvm , V(F20F00,59,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #1196 + INST(Vmulsh , VexRvm , E(F3MAP5,59,_,_,_,0,1,T1S), 0 , 107, 0 , 200, 134), // #1197 + INST(Vmulss , VexRvm , V(F30F00,59,_,I,I,0,2,T1S), 0 , 108, 0 , 201, 133), // #1198 + INST(Vmwrite , X86Rm_NoSize , O(000F00,79,_,_,_,_,_,_ ), 0 , 4 , 0 , 346, 58 ), // #1199 + INST(Vmxon , X86M_Only , O(F30F00,C7,6,_,_,_,_,_ ), 0 , 24 , 0 , 32 , 58 ), // #1200 + INST(Vorpd , VexRvm_Lx , V(660F00,56,_,x,I,1,4,FV ), 0 , 103, 0 , 210, 139), // #1201 + INST(Vorps , VexRvm_Lx , V(000F00,56,_,x,I,0,4,FV ), 0 , 105, 0 , 211, 139), // #1202 + INST(Vp2intersectd , VexRvm_Lx_2xK , E(F20F38,68,_,_,_,0,4,FV ), 0 , 131, 0 , 347, 161), // #1203 + INST(Vp2intersectq , VexRvm_Lx_2xK , E(F20F38,68,_,_,_,1,4,FV ), 0 , 203, 0 , 348, 161), // #1204 + INST(Vp4dpwssd , VexRm_T1_4X , E(F20F38,52,_,2,_,0,4,T4X), 0 , 101, 0 , 194, 162), // #1205 + INST(Vp4dpwssds , VexRm_T1_4X , E(F20F38,53,_,2,_,0,4,T4X), 0 , 101, 0 , 194, 162), // #1206 + INST(Vpabsb , VexRm_Lx , V(660F38,1C,_,x,I,_,4,FVM), 0 , 110, 0 , 342, 163), // #1207 + INST(Vpabsd , VexRm_Lx , V(660F38,1E,_,x,I,0,4,FV ), 0 , 110, 0 , 349, 142), // #1208 + INST(Vpabsq , VexRm_Lx , E(660F38,1F,_,x,_,1,4,FV ), 0 , 113, 0 , 350, 138), // #1209 + INST(Vpabsw , VexRm_Lx , V(660F38,1D,_,x,I,_,4,FVM), 0 , 110, 0 , 342, 163), // #1210 + INST(Vpackssdw , VexRvm_Lx , V(660F00,6B,_,x,I,0,4,FV ), 0 , 144, 0 , 209, 163), // #1211 + INST(Vpacksswb , VexRvm_Lx , V(660F00,63,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1212 + INST(Vpackusdw , VexRvm_Lx , V(660F38,2B,_,x,I,0,4,FV ), 0 , 110, 0 , 209, 163), // #1213 + INST(Vpackuswb , VexRvm_Lx , V(660F00,67,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1214 + INST(Vpaddb , VexRvm_Lx , V(660F00,FC,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1215 + INST(Vpaddd , VexRvm_Lx , V(660F00,FE,_,x,I,0,4,FV ), 0 , 144, 0 , 209, 142), // #1216 + INST(Vpaddq , VexRvm_Lx , V(660F00,D4,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 142), // #1217 + INST(Vpaddsb , VexRvm_Lx , V(660F00,EC,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1218 + INST(Vpaddsw , VexRvm_Lx , V(660F00,ED,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1219 + INST(Vpaddusb , VexRvm_Lx , V(660F00,DC,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1220 + INST(Vpaddusw , VexRvm_Lx , V(660F00,DD,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1221 + INST(Vpaddw , VexRvm_Lx , V(660F00,FD,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1222 + INST(Vpalignr , VexRvmi_Lx , V(660F3A,0F,_,x,I,I,4,FVM), 0 , 204, 0 , 314, 163), // #1223 + INST(Vpand , VexRvm_Lx , V(660F00,DB,_,x,I,_,_,_ ), 0 , 69 , 0 , 351, 160), // #1224 + INST(Vpandd , VexRvm_Lx , E(660F00,DB,_,x,_,0,4,FV ), 0 , 198, 0 , 352, 138), // #1225 + INST(Vpandn , VexRvm_Lx , V(660F00,DF,_,x,I,_,_,_ ), 0 , 69 , 0 , 353, 160), // #1226 + INST(Vpandnd , VexRvm_Lx , E(660F00,DF,_,x,_,0,4,FV ), 0 , 198, 0 , 354, 138), // #1227 + INST(Vpandnq , VexRvm_Lx , E(660F00,DF,_,x,_,1,4,FV ), 0 , 135, 0 , 355, 138), // #1228 + INST(Vpandq , VexRvm_Lx , E(660F00,DB,_,x,_,1,4,FV ), 0 , 135, 0 , 356, 138), // #1229 + INST(Vpavgb , VexRvm_Lx , V(660F00,E0,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1230 + INST(Vpavgw , VexRvm_Lx , V(660F00,E3,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1231 + INST(Vpblendd , VexRvmi_Lx , V(660F3A,02,_,x,0,_,_,_ ), 0 , 73 , 0 , 214, 141), // #1232 + INST(Vpblendmb , VexRvm_Lx , E(660F38,66,_,x,_,0,4,FVM), 0 , 114, 0 , 357, 146), // #1233 + INST(Vpblendmd , VexRvm_Lx , E(660F38,64,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1234 + INST(Vpblendmq , VexRvm_Lx , E(660F38,64,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1235 + INST(Vpblendmw , VexRvm_Lx , E(660F38,66,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1236 + INST(Vpblendvb , VexRvmr_Lx , V(660F3A,4C,_,x,0,_,_,_ ), 0 , 73 , 0 , 215, 160), // #1237 + INST(Vpblendw , VexRvmi_Lx , V(660F3A,0E,_,x,I,_,_,_ ), 0 , 73 , 0 , 214, 160), // #1238 + INST(Vpbroadcastb , VexRm_Lx_Bcst , V(660F38,78,_,x,0,0,0,T1S), E(660F38,7A,_,x,0,0,0,T1S), 96 , 108, 358, 164), // #1239 + INST(Vpbroadcastd , VexRm_Lx_Bcst , V(660F38,58,_,x,0,0,2,T1S), E(660F38,7C,_,x,0,0,0,T1S), 122, 109, 359, 152), // #1240 + INST(Vpbroadcastmb2q , VexRm_Lx , E(F30F38,2A,_,x,_,1,_,_ ), 0 , 205, 0 , 360, 165), // #1241 + INST(Vpbroadcastmw2d , VexRm_Lx , E(F30F38,3A,_,x,_,0,_,_ ), 0 , 206, 0 , 360, 165), // #1242 + INST(Vpbroadcastq , VexRm_Lx_Bcst , V(660F38,59,_,x,0,1,3,T1S), E(660F38,7C,_,x,0,1,0,T1S), 121, 110, 361, 152), // #1243 + INST(Vpbroadcastw , VexRm_Lx_Bcst , V(660F38,79,_,x,0,0,1,T1S), E(660F38,7B,_,x,0,0,0,T1S), 207, 111, 362, 164), // #1244 + INST(Vpclmulqdq , VexRvmi_Lx , V(660F3A,44,_,x,I,_,4,FVM), 0 , 204, 0 , 363, 166), // #1245 + INST(Vpcmov , VexRvrmRvmr_Lx , V(XOP_M8,A2,_,x,x,_,_,_ ), 0 , 208, 0 , 289, 151), // #1246 + INST(Vpcmpb , VexRvmi_Lx , E(660F3A,3F,_,x,_,0,4,FVM), 0 , 111, 0 , 364, 146), // #1247 + INST(Vpcmpd , VexRvmi_Lx , E(660F3A,1F,_,x,_,0,4,FV ), 0 , 111, 0 , 365, 138), // #1248 + INST(Vpcmpeqb , VexRvm_Lx_KEvex , V(660F00,74,_,x,I,I,4,FV ), 0 , 144, 0 , 366, 163), // #1249 + INST(Vpcmpeqd , VexRvm_Lx_KEvex , V(660F00,76,_,x,I,0,4,FVM), 0 , 144, 0 , 367, 142), // #1250 + INST(Vpcmpeqq , VexRvm_Lx_KEvex , V(660F38,29,_,x,I,1,4,FVM), 0 , 209, 0 , 368, 142), // #1251 + INST(Vpcmpeqw , VexRvm_Lx_KEvex , V(660F00,75,_,x,I,I,4,FV ), 0 , 144, 0 , 366, 163), // #1252 + INST(Vpcmpestri , VexRmi , V(660F3A,61,_,0,I,_,_,_ ), 0 , 73 , 0 , 369, 167), // #1253 + INST(Vpcmpestrm , VexRmi , V(660F3A,60,_,0,I,_,_,_ ), 0 , 73 , 0 , 370, 167), // #1254 + INST(Vpcmpgtb , VexRvm_Lx_KEvex , V(660F00,64,_,x,I,I,4,FV ), 0 , 144, 0 , 366, 163), // #1255 + INST(Vpcmpgtd , VexRvm_Lx_KEvex , V(660F00,66,_,x,I,0,4,FVM), 0 , 144, 0 , 367, 142), // #1256 + INST(Vpcmpgtq , VexRvm_Lx_KEvex , V(660F38,37,_,x,I,1,4,FVM), 0 , 209, 0 , 368, 142), // #1257 + INST(Vpcmpgtw , VexRvm_Lx_KEvex , V(660F00,65,_,x,I,I,4,FV ), 0 , 144, 0 , 366, 163), // #1258 + INST(Vpcmpistri , VexRmi , V(660F3A,63,_,0,I,_,_,_ ), 0 , 73 , 0 , 371, 167), // #1259 + INST(Vpcmpistrm , VexRmi , V(660F3A,62,_,0,I,_,_,_ ), 0 , 73 , 0 , 372, 167), // #1260 + INST(Vpcmpq , VexRvmi_Lx , E(660F3A,1F,_,x,_,1,4,FV ), 0 , 112, 0 , 373, 138), // #1261 + INST(Vpcmpub , VexRvmi_Lx , E(660F3A,3E,_,x,_,0,4,FVM), 0 , 111, 0 , 364, 146), // #1262 + INST(Vpcmpud , VexRvmi_Lx , E(660F3A,1E,_,x,_,0,4,FV ), 0 , 111, 0 , 365, 138), // #1263 + INST(Vpcmpuq , VexRvmi_Lx , E(660F3A,1E,_,x,_,1,4,FV ), 0 , 112, 0 , 373, 138), // #1264 + INST(Vpcmpuw , VexRvmi_Lx , E(660F3A,3E,_,x,_,1,4,FVM), 0 , 112, 0 , 373, 146), // #1265 + INST(Vpcmpw , VexRvmi_Lx , E(660F3A,3F,_,x,_,1,4,FVM), 0 , 112, 0 , 373, 146), // #1266 + INST(Vpcomb , VexRvmi , V(XOP_M8,CC,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1267 + INST(Vpcomd , VexRvmi , V(XOP_M8,CE,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1268 + INST(Vpcompressb , VexMr_Lx , E(660F38,63,_,x,_,0,0,T1S), 0 , 210, 0 , 232, 168), // #1269 + INST(Vpcompressd , VexMr_Lx , E(660F38,8B,_,x,_,0,2,T1S), 0 , 129, 0 , 232, 138), // #1270 + INST(Vpcompressq , VexMr_Lx , E(660F38,8B,_,x,_,1,3,T1S), 0 , 128, 0 , 232, 138), // #1271 + INST(Vpcompressw , VexMr_Lx , E(660F38,63,_,x,_,1,1,T1S), 0 , 211, 0 , 232, 168), // #1272 + INST(Vpcomq , VexRvmi , V(XOP_M8,CF,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1273 + INST(Vpcomub , VexRvmi , V(XOP_M8,EC,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1274 + INST(Vpcomud , VexRvmi , V(XOP_M8,EE,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1275 + INST(Vpcomuq , VexRvmi , V(XOP_M8,EF,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1276 + INST(Vpcomuw , VexRvmi , V(XOP_M8,ED,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1277 + INST(Vpcomw , VexRvmi , V(XOP_M8,CD,_,0,0,_,_,_ ), 0 , 208, 0 , 276, 151), // #1278 + INST(Vpconflictd , VexRm_Lx , E(660F38,C4,_,x,_,0,4,FV ), 0 , 114, 0 , 374, 165), // #1279 + INST(Vpconflictq , VexRm_Lx , E(660F38,C4,_,x,_,1,4,FV ), 0 , 113, 0 , 374, 165), // #1280 + INST(Vpdpbusd , VexRvm_Lx , V(660F38,50,_,x,_,0,4,FV ), 0 , 110, 0 , 375, 169), // #1281 + INST(Vpdpbusds , VexRvm_Lx , V(660F38,51,_,x,_,0,4,FV ), 0 , 110, 0 , 375, 169), // #1282 + INST(Vpdpwssd , VexRvm_Lx , V(660F38,52,_,x,_,0,4,FV ), 0 , 110, 0 , 375, 169), // #1283 + INST(Vpdpwssds , VexRvm_Lx , V(660F38,53,_,x,_,0,4,FV ), 0 , 110, 0 , 375, 169), // #1284 + INST(Vperm2f128 , VexRvmi , V(660F3A,06,_,1,0,_,_,_ ), 0 , 172, 0 , 376, 135), // #1285 + INST(Vperm2i128 , VexRvmi , V(660F3A,46,_,1,0,_,_,_ ), 0 , 172, 0 , 376, 141), // #1286 + INST(Vpermb , VexRvm_Lx , E(660F38,8D,_,x,_,0,4,FVM), 0 , 114, 0 , 357, 170), // #1287 + INST(Vpermd , VexRvm_Lx , V(660F38,36,_,x,0,0,4,FV ), 0 , 110, 0 , 377, 152), // #1288 + INST(Vpermi2b , VexRvm_Lx , E(660F38,75,_,x,_,0,4,FVM), 0 , 114, 0 , 357, 170), // #1289 + INST(Vpermi2d , VexRvm_Lx , E(660F38,76,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1290 + INST(Vpermi2pd , VexRvm_Lx , E(660F38,77,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1291 + INST(Vpermi2ps , VexRvm_Lx , E(660F38,77,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1292 + INST(Vpermi2q , VexRvm_Lx , E(660F38,76,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1293 + INST(Vpermi2w , VexRvm_Lx , E(660F38,75,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1294 + INST(Vpermil2pd , VexRvrmiRvmri_Lx , V(660F3A,49,_,x,x,_,_,_ ), 0 , 73 , 0 , 378, 151), // #1295 + INST(Vpermil2ps , VexRvrmiRvmri_Lx , V(660F3A,48,_,x,x,_,_,_ ), 0 , 73 , 0 , 378, 151), // #1296 + INST(Vpermilpd , VexRvmRmi_Lx , V(660F38,0D,_,x,0,1,4,FV ), V(660F3A,05,_,x,0,1,4,FV ), 209, 112, 379, 131), // #1297 + INST(Vpermilps , VexRvmRmi_Lx , V(660F38,0C,_,x,0,0,4,FV ), V(660F3A,04,_,x,0,0,4,FV ), 110, 113, 380, 131), // #1298 + INST(Vpermpd , VexRvmRmi_Lx , E(660F38,16,_,x,1,1,4,FV ), V(660F3A,01,_,x,1,1,4,FV ), 212, 114, 381, 152), // #1299 + INST(Vpermps , VexRvm_Lx , V(660F38,16,_,x,0,0,4,FV ), 0 , 110, 0 , 377, 152), // #1300 + INST(Vpermq , VexRvmRmi_Lx , E(660F38,36,_,x,_,1,4,FV ), V(660F3A,00,_,x,1,1,4,FV ), 113, 115, 381, 152), // #1301 + INST(Vpermt2b , VexRvm_Lx , E(660F38,7D,_,x,_,0,4,FVM), 0 , 114, 0 , 357, 170), // #1302 + INST(Vpermt2d , VexRvm_Lx , E(660F38,7E,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1303 + INST(Vpermt2pd , VexRvm_Lx , E(660F38,7F,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1304 + INST(Vpermt2ps , VexRvm_Lx , E(660F38,7F,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1305 + INST(Vpermt2q , VexRvm_Lx , E(660F38,7E,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1306 + INST(Vpermt2w , VexRvm_Lx , E(660F38,7D,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1307 + INST(Vpermw , VexRvm_Lx , E(660F38,8D,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1308 + INST(Vpexpandb , VexRm_Lx , E(660F38,62,_,x,_,0,0,T1S), 0 , 210, 0 , 279, 168), // #1309 + INST(Vpexpandd , VexRm_Lx , E(660F38,89,_,x,_,0,2,T1S), 0 , 129, 0 , 279, 138), // #1310 + INST(Vpexpandq , VexRm_Lx , E(660F38,89,_,x,_,1,3,T1S), 0 , 128, 0 , 279, 138), // #1311 + INST(Vpexpandw , VexRm_Lx , E(660F38,62,_,x,_,1,1,T1S), 0 , 211, 0 , 279, 168), // #1312 + INST(Vpextrb , VexMri , V(660F3A,14,_,0,0,I,0,T1S), 0 , 73 , 0 , 382, 171), // #1313 + INST(Vpextrd , VexMri , V(660F3A,16,_,0,0,0,2,T1S), 0 , 177, 0 , 283, 172), // #1314 + INST(Vpextrq , VexMri , V(660F3A,16,_,0,1,1,3,T1S), 0 , 213, 0 , 383, 172), // #1315 + INST(Vpextrw , VexMri_Vpextrw , V(660F3A,15,_,0,0,I,1,T1S), 0 , 214, 0 , 384, 171), // #1316 + INST(Vpgatherdd , VexRmvRm_VM , V(660F38,90,_,x,0,_,_,_ ), E(660F38,90,_,x,_,0,2,T1S), 96 , 116, 302, 152), // #1317 + INST(Vpgatherdq , VexRmvRm_VM , V(660F38,90,_,x,1,_,_,_ ), E(660F38,90,_,x,_,1,3,T1S), 189, 117, 301, 152), // #1318 + INST(Vpgatherqd , VexRmvRm_VM , V(660F38,91,_,x,0,_,_,_ ), E(660F38,91,_,x,_,0,2,T1S), 96 , 118, 307, 152), // #1319 + INST(Vpgatherqq , VexRmvRm_VM , V(660F38,91,_,x,1,_,_,_ ), E(660F38,91,_,x,_,1,3,T1S), 189, 119, 306, 152), // #1320 + INST(Vphaddbd , VexRm , V(XOP_M9,C2,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1321 + INST(Vphaddbq , VexRm , V(XOP_M9,C3,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1322 + INST(Vphaddbw , VexRm , V(XOP_M9,C1,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1323 + INST(Vphaddd , VexRvm_Lx , V(660F38,02,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1324 + INST(Vphadddq , VexRm , V(XOP_M9,CB,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1325 + INST(Vphaddsw , VexRvm_Lx , V(660F38,03,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1326 + INST(Vphaddubd , VexRm , V(XOP_M9,D2,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1327 + INST(Vphaddubq , VexRm , V(XOP_M9,D3,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1328 + INST(Vphaddubw , VexRm , V(XOP_M9,D1,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1329 + INST(Vphaddudq , VexRm , V(XOP_M9,DB,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1330 + INST(Vphadduwd , VexRm , V(XOP_M9,D6,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1331 + INST(Vphadduwq , VexRm , V(XOP_M9,D7,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1332 + INST(Vphaddw , VexRvm_Lx , V(660F38,01,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1333 + INST(Vphaddwd , VexRm , V(XOP_M9,C6,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1334 + INST(Vphaddwq , VexRm , V(XOP_M9,C7,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1335 + INST(Vphminposuw , VexRm , V(660F38,41,_,0,I,_,_,_ ), 0 , 96 , 0 , 204, 135), // #1336 + INST(Vphsubbw , VexRm , V(XOP_M9,E1,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1337 + INST(Vphsubd , VexRvm_Lx , V(660F38,06,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1338 + INST(Vphsubdq , VexRm , V(XOP_M9,E3,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1339 + INST(Vphsubsw , VexRvm_Lx , V(660F38,07,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1340 + INST(Vphsubw , VexRvm_Lx , V(660F38,05,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1341 + INST(Vphsubwd , VexRm , V(XOP_M9,E2,_,0,0,_,_,_ ), 0 , 79 , 0 , 204, 151), // #1342 + INST(Vpinsrb , VexRvmi , V(660F3A,20,_,0,0,I,0,T1S), 0 , 73 , 0 , 385, 171), // #1343 + INST(Vpinsrd , VexRvmi , V(660F3A,22,_,0,0,0,2,T1S), 0 , 177, 0 , 386, 172), // #1344 + INST(Vpinsrq , VexRvmi , V(660F3A,22,_,0,1,1,3,T1S), 0 , 213, 0 , 387, 172), // #1345 + INST(Vpinsrw , VexRvmi , V(660F00,C4,_,0,0,I,1,T1S), 0 , 215, 0 , 388, 171), // #1346 + INST(Vplzcntd , VexRm_Lx , E(660F38,44,_,x,_,0,4,FV ), 0 , 114, 0 , 374, 165), // #1347 + INST(Vplzcntq , VexRm_Lx , E(660F38,44,_,x,_,1,4,FV ), 0 , 113, 0 , 350, 165), // #1348 + INST(Vpmacsdd , VexRvmr , V(XOP_M8,9E,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1349 + INST(Vpmacsdqh , VexRvmr , V(XOP_M8,9F,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1350 + INST(Vpmacsdql , VexRvmr , V(XOP_M8,97,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1351 + INST(Vpmacssdd , VexRvmr , V(XOP_M8,8E,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1352 + INST(Vpmacssdqh , VexRvmr , V(XOP_M8,8F,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1353 + INST(Vpmacssdql , VexRvmr , V(XOP_M8,87,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1354 + INST(Vpmacsswd , VexRvmr , V(XOP_M8,86,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1355 + INST(Vpmacssww , VexRvmr , V(XOP_M8,85,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1356 + INST(Vpmacswd , VexRvmr , V(XOP_M8,96,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1357 + INST(Vpmacsww , VexRvmr , V(XOP_M8,95,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1358 + INST(Vpmadcsswd , VexRvmr , V(XOP_M8,A6,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1359 + INST(Vpmadcswd , VexRvmr , V(XOP_M8,B6,_,0,0,_,_,_ ), 0 , 208, 0 , 389, 151), // #1360 + INST(Vpmadd52huq , VexRvm_Lx , E(660F38,B5,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 173), // #1361 + INST(Vpmadd52luq , VexRvm_Lx , E(660F38,B4,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 173), // #1362 + INST(Vpmaddubsw , VexRvm_Lx , V(660F38,04,_,x,I,I,4,FVM), 0 , 110, 0 , 315, 163), // #1363 + INST(Vpmaddwd , VexRvm_Lx , V(660F00,F5,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1364 + INST(Vpmaskmovd , VexRvmMvr_Lx , V(660F38,8C,_,x,0,_,_,_ ), V(660F38,8E,_,x,0,_,_,_ ), 96 , 120, 323, 141), // #1365 + INST(Vpmaskmovq , VexRvmMvr_Lx , V(660F38,8C,_,x,1,_,_,_ ), V(660F38,8E,_,x,1,_,_,_ ), 189, 121, 323, 141), // #1366 + INST(Vpmaxsb , VexRvm_Lx , V(660F38,3C,_,x,I,I,4,FVM), 0 , 110, 0 , 390, 163), // #1367 + INST(Vpmaxsd , VexRvm_Lx , V(660F38,3D,_,x,I,0,4,FV ), 0 , 110, 0 , 211, 142), // #1368 + INST(Vpmaxsq , VexRvm_Lx , E(660F38,3D,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1369 + INST(Vpmaxsw , VexRvm_Lx , V(660F00,EE,_,x,I,I,4,FVM), 0 , 144, 0 , 390, 163), // #1370 + INST(Vpmaxub , VexRvm_Lx , V(660F00,DE,_,x,I,I,4,FVM), 0 , 144, 0 , 390, 163), // #1371 + INST(Vpmaxud , VexRvm_Lx , V(660F38,3F,_,x,I,0,4,FV ), 0 , 110, 0 , 211, 142), // #1372 + INST(Vpmaxuq , VexRvm_Lx , E(660F38,3F,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1373 + INST(Vpmaxuw , VexRvm_Lx , V(660F38,3E,_,x,I,I,4,FVM), 0 , 110, 0 , 390, 163), // #1374 + INST(Vpminsb , VexRvm_Lx , V(660F38,38,_,x,I,I,4,FVM), 0 , 110, 0 , 390, 163), // #1375 + INST(Vpminsd , VexRvm_Lx , V(660F38,39,_,x,I,0,4,FV ), 0 , 110, 0 , 211, 142), // #1376 + INST(Vpminsq , VexRvm_Lx , E(660F38,39,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1377 + INST(Vpminsw , VexRvm_Lx , V(660F00,EA,_,x,I,I,4,FVM), 0 , 144, 0 , 390, 163), // #1378 + INST(Vpminub , VexRvm_Lx , V(660F00,DA,_,x,I,_,4,FVM), 0 , 144, 0 , 390, 163), // #1379 + INST(Vpminud , VexRvm_Lx , V(660F38,3B,_,x,I,0,4,FV ), 0 , 110, 0 , 211, 142), // #1380 + INST(Vpminuq , VexRvm_Lx , E(660F38,3B,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1381 + INST(Vpminuw , VexRvm_Lx , V(660F38,3A,_,x,I,_,4,FVM), 0 , 110, 0 , 390, 163), // #1382 + INST(Vpmovb2m , VexRm_Lx , E(F30F38,29,_,x,_,0,_,_ ), 0 , 206, 0 , 391, 146), // #1383 + INST(Vpmovd2m , VexRm_Lx , E(F30F38,39,_,x,_,0,_,_ ), 0 , 206, 0 , 391, 140), // #1384 + INST(Vpmovdb , VexMr_Lx , E(F30F38,31,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1385 + INST(Vpmovdw , VexMr_Lx , E(F30F38,33,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1386 + INST(Vpmovm2b , VexRm_Lx , E(F30F38,28,_,x,_,0,_,_ ), 0 , 206, 0 , 360, 146), // #1387 + INST(Vpmovm2d , VexRm_Lx , E(F30F38,38,_,x,_,0,_,_ ), 0 , 206, 0 , 360, 140), // #1388 + INST(Vpmovm2q , VexRm_Lx , E(F30F38,38,_,x,_,1,_,_ ), 0 , 205, 0 , 360, 140), // #1389 + INST(Vpmovm2w , VexRm_Lx , E(F30F38,28,_,x,_,1,_,_ ), 0 , 205, 0 , 360, 146), // #1390 + INST(Vpmovmskb , VexRm_Lx , V(660F00,D7,_,x,I,_,_,_ ), 0 , 69 , 0 , 336, 160), // #1391 + INST(Vpmovq2m , VexRm_Lx , E(F30F38,39,_,x,_,1,_,_ ), 0 , 205, 0 , 391, 140), // #1392 + INST(Vpmovqb , VexMr_Lx , E(F30F38,32,_,x,_,0,1,OVM), 0 , 218, 0 , 394, 138), // #1393 + INST(Vpmovqd , VexMr_Lx , E(F30F38,35,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1394 + INST(Vpmovqw , VexMr_Lx , E(F30F38,34,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1395 + INST(Vpmovsdb , VexMr_Lx , E(F30F38,21,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1396 + INST(Vpmovsdw , VexMr_Lx , E(F30F38,23,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1397 + INST(Vpmovsqb , VexMr_Lx , E(F30F38,22,_,x,_,0,1,OVM), 0 , 218, 0 , 394, 138), // #1398 + INST(Vpmovsqd , VexMr_Lx , E(F30F38,25,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1399 + INST(Vpmovsqw , VexMr_Lx , E(F30F38,24,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1400 + INST(Vpmovswb , VexMr_Lx , E(F30F38,20,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 146), // #1401 + INST(Vpmovsxbd , VexRm_Lx , V(660F38,21,_,x,I,I,2,QVM), 0 , 219, 0 , 395, 142), // #1402 + INST(Vpmovsxbq , VexRm_Lx , V(660F38,22,_,x,I,I,1,OVM), 0 , 220, 0 , 396, 142), // #1403 + INST(Vpmovsxbw , VexRm_Lx , V(660F38,20,_,x,I,I,3,HVM), 0 , 139, 0 , 397, 163), // #1404 + INST(Vpmovsxdq , VexRm_Lx , V(660F38,25,_,x,I,0,3,HVM), 0 , 139, 0 , 397, 142), // #1405 + INST(Vpmovsxwd , VexRm_Lx , V(660F38,23,_,x,I,I,3,HVM), 0 , 139, 0 , 397, 142), // #1406 + INST(Vpmovsxwq , VexRm_Lx , V(660F38,24,_,x,I,I,2,QVM), 0 , 219, 0 , 395, 142), // #1407 + INST(Vpmovusdb , VexMr_Lx , E(F30F38,11,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1408 + INST(Vpmovusdw , VexMr_Lx , E(F30F38,13,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1409 + INST(Vpmovusqb , VexMr_Lx , E(F30F38,12,_,x,_,0,1,OVM), 0 , 218, 0 , 394, 138), // #1410 + INST(Vpmovusqd , VexMr_Lx , E(F30F38,15,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 138), // #1411 + INST(Vpmovusqw , VexMr_Lx , E(F30F38,14,_,x,_,0,2,QVM), 0 , 216, 0 , 392, 138), // #1412 + INST(Vpmovuswb , VexMr_Lx , E(F30F38,10,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 146), // #1413 + INST(Vpmovw2m , VexRm_Lx , E(F30F38,29,_,x,_,1,_,_ ), 0 , 205, 0 , 391, 146), // #1414 + INST(Vpmovwb , VexMr_Lx , E(F30F38,30,_,x,_,0,3,HVM), 0 , 217, 0 , 393, 146), // #1415 + INST(Vpmovzxbd , VexRm_Lx , V(660F38,31,_,x,I,I,2,QVM), 0 , 219, 0 , 395, 142), // #1416 + INST(Vpmovzxbq , VexRm_Lx , V(660F38,32,_,x,I,I,1,OVM), 0 , 220, 0 , 396, 142), // #1417 + INST(Vpmovzxbw , VexRm_Lx , V(660F38,30,_,x,I,I,3,HVM), 0 , 139, 0 , 397, 163), // #1418 + INST(Vpmovzxdq , VexRm_Lx , V(660F38,35,_,x,I,0,3,HVM), 0 , 139, 0 , 397, 142), // #1419 + INST(Vpmovzxwd , VexRm_Lx , V(660F38,33,_,x,I,I,3,HVM), 0 , 139, 0 , 397, 142), // #1420 + INST(Vpmovzxwq , VexRm_Lx , V(660F38,34,_,x,I,I,2,QVM), 0 , 219, 0 , 395, 142), // #1421 + INST(Vpmuldq , VexRvm_Lx , V(660F38,28,_,x,I,1,4,FV ), 0 , 209, 0 , 208, 142), // #1422 + INST(Vpmulhrsw , VexRvm_Lx , V(660F38,0B,_,x,I,I,4,FVM), 0 , 110, 0 , 315, 163), // #1423 + INST(Vpmulhuw , VexRvm_Lx , V(660F00,E4,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1424 + INST(Vpmulhw , VexRvm_Lx , V(660F00,E5,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1425 + INST(Vpmulld , VexRvm_Lx , V(660F38,40,_,x,I,0,4,FV ), 0 , 110, 0 , 209, 142), // #1426 + INST(Vpmullq , VexRvm_Lx , E(660F38,40,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 140), // #1427 + INST(Vpmullw , VexRvm_Lx , V(660F00,D5,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1428 + INST(Vpmultishiftqb , VexRvm_Lx , E(660F38,83,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 170), // #1429 + INST(Vpmuludq , VexRvm_Lx , V(660F00,F4,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 142), // #1430 + INST(Vpopcntb , VexRm_Lx , E(660F38,54,_,x,_,0,4,FV ), 0 , 114, 0 , 279, 174), // #1431 + INST(Vpopcntd , VexRm_Lx , E(660F38,55,_,x,_,0,4,FVM), 0 , 114, 0 , 374, 175), // #1432 + INST(Vpopcntq , VexRm_Lx , E(660F38,55,_,x,_,1,4,FVM), 0 , 113, 0 , 350, 175), // #1433 + INST(Vpopcntw , VexRm_Lx , E(660F38,54,_,x,_,1,4,FV ), 0 , 113, 0 , 279, 174), // #1434 + INST(Vpor , VexRvm_Lx , V(660F00,EB,_,x,I,_,_,_ ), 0 , 69 , 0 , 351, 160), // #1435 + INST(Vpord , VexRvm_Lx , E(660F00,EB,_,x,_,0,4,FV ), 0 , 198, 0 , 352, 138), // #1436 + INST(Vporq , VexRvm_Lx , E(660F00,EB,_,x,_,1,4,FV ), 0 , 135, 0 , 356, 138), // #1437 + INST(Vpperm , VexRvrmRvmr , V(XOP_M8,A3,_,0,x,_,_,_ ), 0 , 208, 0 , 398, 151), // #1438 + INST(Vprold , VexVmi_Lx , E(660F00,72,1,x,_,0,4,FV ), 0 , 221, 0 , 399, 138), // #1439 + INST(Vprolq , VexVmi_Lx , E(660F00,72,1,x,_,1,4,FV ), 0 , 222, 0 , 400, 138), // #1440 + INST(Vprolvd , VexRvm_Lx , E(660F38,15,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1441 + INST(Vprolvq , VexRvm_Lx , E(660F38,15,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1442 + INST(Vprord , VexVmi_Lx , E(660F00,72,0,x,_,0,4,FV ), 0 , 198, 0 , 399, 138), // #1443 + INST(Vprorq , VexVmi_Lx , E(660F00,72,0,x,_,1,4,FV ), 0 , 135, 0 , 400, 138), // #1444 + INST(Vprorvd , VexRvm_Lx , E(660F38,14,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 138), // #1445 + INST(Vprorvq , VexRvm_Lx , E(660F38,14,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1446 + INST(Vprotb , VexRvmRmvRmi , V(XOP_M9,90,_,0,x,_,_,_ ), V(XOP_M8,C0,_,0,x,_,_,_ ), 79 , 122, 401, 151), // #1447 + INST(Vprotd , VexRvmRmvRmi , V(XOP_M9,92,_,0,x,_,_,_ ), V(XOP_M8,C2,_,0,x,_,_,_ ), 79 , 123, 401, 151), // #1448 + INST(Vprotq , VexRvmRmvRmi , V(XOP_M9,93,_,0,x,_,_,_ ), V(XOP_M8,C3,_,0,x,_,_,_ ), 79 , 124, 401, 151), // #1449 + INST(Vprotw , VexRvmRmvRmi , V(XOP_M9,91,_,0,x,_,_,_ ), V(XOP_M8,C1,_,0,x,_,_,_ ), 79 , 125, 401, 151), // #1450 + INST(Vpsadbw , VexRvm_Lx , V(660F00,F6,_,x,I,I,4,FVM), 0 , 144, 0 , 203, 163), // #1451 + INST(Vpscatterdd , VexMr_VM , E(660F38,A0,_,x,_,0,2,T1S), 0 , 129, 0 , 402, 138), // #1452 + INST(Vpscatterdq , VexMr_VM , E(660F38,A0,_,x,_,1,3,T1S), 0 , 128, 0 , 403, 138), // #1453 + INST(Vpscatterqd , VexMr_VM , E(660F38,A1,_,x,_,0,2,T1S), 0 , 129, 0 , 404, 138), // #1454 + INST(Vpscatterqq , VexMr_VM , E(660F38,A1,_,x,_,1,3,T1S), 0 , 128, 0 , 405, 138), // #1455 + INST(Vpshab , VexRvmRmv , V(XOP_M9,98,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1456 + INST(Vpshad , VexRvmRmv , V(XOP_M9,9A,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1457 + INST(Vpshaq , VexRvmRmv , V(XOP_M9,9B,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1458 + INST(Vpshaw , VexRvmRmv , V(XOP_M9,99,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1459 + INST(Vpshlb , VexRvmRmv , V(XOP_M9,94,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1460 + INST(Vpshld , VexRvmRmv , V(XOP_M9,96,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1461 + INST(Vpshldd , VexRvmi_Lx , E(660F3A,71,_,x,_,0,4,FV ), 0 , 111, 0 , 206, 168), // #1462 + INST(Vpshldq , VexRvmi_Lx , E(660F3A,71,_,x,_,1,4,FV ), 0 , 112, 0 , 207, 168), // #1463 + INST(Vpshldvd , VexRvm_Lx , E(660F38,71,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 168), // #1464 + INST(Vpshldvq , VexRvm_Lx , E(660F38,71,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 168), // #1465 + INST(Vpshldvw , VexRvm_Lx , E(660F38,70,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 168), // #1466 + INST(Vpshldw , VexRvmi_Lx , E(660F3A,70,_,x,_,1,4,FVM), 0 , 112, 0 , 275, 168), // #1467 + INST(Vpshlq , VexRvmRmv , V(XOP_M9,97,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1468 + INST(Vpshlw , VexRvmRmv , V(XOP_M9,95,_,0,x,_,_,_ ), 0 , 79 , 0 , 406, 151), // #1469 + INST(Vpshrdd , VexRvmi_Lx , E(660F3A,73,_,x,_,0,4,FV ), 0 , 111, 0 , 206, 168), // #1470 + INST(Vpshrdq , VexRvmi_Lx , E(660F3A,73,_,x,_,1,4,FV ), 0 , 112, 0 , 207, 168), // #1471 + INST(Vpshrdvd , VexRvm_Lx , E(660F38,73,_,x,_,0,4,FV ), 0 , 114, 0 , 213, 168), // #1472 + INST(Vpshrdvq , VexRvm_Lx , E(660F38,73,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 168), // #1473 + INST(Vpshrdvw , VexRvm_Lx , E(660F38,72,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 168), // #1474 + INST(Vpshrdw , VexRvmi_Lx , E(660F3A,72,_,x,_,1,4,FVM), 0 , 112, 0 , 275, 168), // #1475 + INST(Vpshufb , VexRvm_Lx , V(660F38,00,_,x,I,I,4,FVM), 0 , 110, 0 , 315, 163), // #1476 + INST(Vpshufbitqmb , VexRvm_Lx , E(660F38,8F,_,x,0,0,4,FVM), 0 , 114, 0 , 407, 174), // #1477 + INST(Vpshufd , VexRmi_Lx , V(660F00,70,_,x,I,0,4,FV ), 0 , 144, 0 , 408, 142), // #1478 + INST(Vpshufhw , VexRmi_Lx , V(F30F00,70,_,x,I,I,4,FVM), 0 , 161, 0 , 409, 163), // #1479 + INST(Vpshuflw , VexRmi_Lx , V(F20F00,70,_,x,I,I,4,FVM), 0 , 223, 0 , 409, 163), // #1480 + INST(Vpsignb , VexRvm_Lx , V(660F38,08,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1481 + INST(Vpsignd , VexRvm_Lx , V(660F38,0A,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1482 + INST(Vpsignw , VexRvm_Lx , V(660F38,09,_,x,I,_,_,_ ), 0 , 96 , 0 , 202, 160), // #1483 + INST(Vpslld , VexRvmVmi_Lx_MEvex , V(660F00,F2,_,x,I,0,4,128), V(660F00,72,6,x,I,0,4,FV ), 224, 126, 410, 142), // #1484 + INST(Vpslldq , VexVmi_Lx_MEvex , V(660F00,73,7,x,I,I,4,FVM), 0 , 225, 0 , 411, 163), // #1485 + INST(Vpsllq , VexRvmVmi_Lx_MEvex , V(660F00,F3,_,x,I,1,4,128), V(660F00,73,6,x,I,1,4,FV ), 226, 127, 412, 142), // #1486 + INST(Vpsllvd , VexRvm_Lx , V(660F38,47,_,x,0,0,4,FV ), 0 , 110, 0 , 209, 152), // #1487 + INST(Vpsllvq , VexRvm_Lx , V(660F38,47,_,x,1,1,4,FV ), 0 , 182, 0 , 208, 152), // #1488 + INST(Vpsllvw , VexRvm_Lx , E(660F38,12,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1489 + INST(Vpsllw , VexRvmVmi_Lx_MEvex , V(660F00,F1,_,x,I,I,4,128), V(660F00,71,6,x,I,I,4,FVM), 224, 128, 413, 163), // #1490 + INST(Vpsrad , VexRvmVmi_Lx_MEvex , V(660F00,E2,_,x,I,0,4,128), V(660F00,72,4,x,I,0,4,FV ), 224, 129, 410, 142), // #1491 + INST(Vpsraq , VexRvmVmi_Lx_MEvex , E(660F00,E2,_,x,_,1,4,128), E(660F00,72,4,x,_,1,4,FV ), 227, 130, 414, 138), // #1492 + INST(Vpsravd , VexRvm_Lx , V(660F38,46,_,x,0,0,4,FV ), 0 , 110, 0 , 209, 152), // #1493 + INST(Vpsravq , VexRvm_Lx , E(660F38,46,_,x,_,1,4,FV ), 0 , 113, 0 , 212, 138), // #1494 + INST(Vpsravw , VexRvm_Lx , E(660F38,11,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1495 + INST(Vpsraw , VexRvmVmi_Lx_MEvex , V(660F00,E1,_,x,I,I,4,128), V(660F00,71,4,x,I,I,4,FVM), 224, 131, 413, 163), // #1496 + INST(Vpsrld , VexRvmVmi_Lx_MEvex , V(660F00,D2,_,x,I,0,4,128), V(660F00,72,2,x,I,0,4,FV ), 224, 132, 410, 142), // #1497 + INST(Vpsrldq , VexVmi_Lx_MEvex , V(660F00,73,3,x,I,I,4,FVM), 0 , 228, 0 , 411, 163), // #1498 + INST(Vpsrlq , VexRvmVmi_Lx_MEvex , V(660F00,D3,_,x,I,1,4,128), V(660F00,73,2,x,I,1,4,FV ), 226, 133, 412, 142), // #1499 + INST(Vpsrlvd , VexRvm_Lx , V(660F38,45,_,x,0,0,4,FV ), 0 , 110, 0 , 209, 152), // #1500 + INST(Vpsrlvq , VexRvm_Lx , V(660F38,45,_,x,1,1,4,FV ), 0 , 182, 0 , 208, 152), // #1501 + INST(Vpsrlvw , VexRvm_Lx , E(660F38,10,_,x,_,1,4,FVM), 0 , 113, 0 , 357, 146), // #1502 + INST(Vpsrlw , VexRvmVmi_Lx_MEvex , V(660F00,D1,_,x,I,I,4,128), V(660F00,71,2,x,I,I,4,FVM), 224, 134, 413, 163), // #1503 + INST(Vpsubb , VexRvm_Lx , V(660F00,F8,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1504 + INST(Vpsubd , VexRvm_Lx , V(660F00,FA,_,x,I,0,4,FV ), 0 , 144, 0 , 416, 142), // #1505 + INST(Vpsubq , VexRvm_Lx , V(660F00,FB,_,x,I,1,4,FV ), 0 , 103, 0 , 417, 142), // #1506 + INST(Vpsubsb , VexRvm_Lx , V(660F00,E8,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1507 + INST(Vpsubsw , VexRvm_Lx , V(660F00,E9,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1508 + INST(Vpsubusb , VexRvm_Lx , V(660F00,D8,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1509 + INST(Vpsubusw , VexRvm_Lx , V(660F00,D9,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1510 + INST(Vpsubw , VexRvm_Lx , V(660F00,F9,_,x,I,I,4,FVM), 0 , 144, 0 , 415, 163), // #1511 + INST(Vpternlogd , VexRvmi_Lx , E(660F3A,25,_,x,_,0,4,FV ), 0 , 111, 0 , 206, 138), // #1512 + INST(Vpternlogq , VexRvmi_Lx , E(660F3A,25,_,x,_,1,4,FV ), 0 , 112, 0 , 207, 138), // #1513 + INST(Vptest , VexRm_Lx , V(660F38,17,_,x,I,_,_,_ ), 0 , 96 , 0 , 298, 167), // #1514 + INST(Vptestmb , VexRvm_Lx , E(660F38,26,_,x,_,0,4,FVM), 0 , 114, 0 , 407, 146), // #1515 + INST(Vptestmd , VexRvm_Lx , E(660F38,27,_,x,_,0,4,FV ), 0 , 114, 0 , 418, 138), // #1516 + INST(Vptestmq , VexRvm_Lx , E(660F38,27,_,x,_,1,4,FV ), 0 , 113, 0 , 419, 138), // #1517 + INST(Vptestmw , VexRvm_Lx , E(660F38,26,_,x,_,1,4,FVM), 0 , 113, 0 , 407, 146), // #1518 + INST(Vptestnmb , VexRvm_Lx , E(F30F38,26,_,x,_,0,4,FVM), 0 , 132, 0 , 407, 146), // #1519 + INST(Vptestnmd , VexRvm_Lx , E(F30F38,27,_,x,_,0,4,FV ), 0 , 132, 0 , 418, 138), // #1520 + INST(Vptestnmq , VexRvm_Lx , E(F30F38,27,_,x,_,1,4,FV ), 0 , 229, 0 , 419, 138), // #1521 + INST(Vptestnmw , VexRvm_Lx , E(F30F38,26,_,x,_,1,4,FVM), 0 , 229, 0 , 407, 146), // #1522 + INST(Vpunpckhbw , VexRvm_Lx , V(660F00,68,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1523 + INST(Vpunpckhdq , VexRvm_Lx , V(660F00,6A,_,x,I,0,4,FV ), 0 , 144, 0 , 209, 142), // #1524 + INST(Vpunpckhqdq , VexRvm_Lx , V(660F00,6D,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 142), // #1525 + INST(Vpunpckhwd , VexRvm_Lx , V(660F00,69,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1526 + INST(Vpunpcklbw , VexRvm_Lx , V(660F00,60,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1527 + INST(Vpunpckldq , VexRvm_Lx , V(660F00,62,_,x,I,0,4,FV ), 0 , 144, 0 , 209, 142), // #1528 + INST(Vpunpcklqdq , VexRvm_Lx , V(660F00,6C,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 142), // #1529 + INST(Vpunpcklwd , VexRvm_Lx , V(660F00,61,_,x,I,I,4,FVM), 0 , 144, 0 , 315, 163), // #1530 + INST(Vpxor , VexRvm_Lx , V(660F00,EF,_,x,I,_,_,_ ), 0 , 69 , 0 , 353, 160), // #1531 + INST(Vpxord , VexRvm_Lx , E(660F00,EF,_,x,_,0,4,FV ), 0 , 198, 0 , 354, 138), // #1532 + INST(Vpxorq , VexRvm_Lx , E(660F00,EF,_,x,_,1,4,FV ), 0 , 135, 0 , 355, 138), // #1533 + INST(Vrangepd , VexRvmi_Lx , E(660F3A,50,_,x,_,1,4,FV ), 0 , 112, 0 , 285, 140), // #1534 + INST(Vrangeps , VexRvmi_Lx , E(660F3A,50,_,x,_,0,4,FV ), 0 , 111, 0 , 286, 140), // #1535 + INST(Vrangesd , VexRvmi , E(660F3A,51,_,I,_,1,3,T1S), 0 , 180, 0 , 287, 66 ), // #1536 + INST(Vrangess , VexRvmi , E(660F3A,51,_,I,_,0,2,T1S), 0 , 181, 0 , 288, 66 ), // #1537 + INST(Vrcp14pd , VexRm_Lx , E(660F38,4C,_,x,_,1,4,FV ), 0 , 113, 0 , 350, 138), // #1538 + INST(Vrcp14ps , VexRm_Lx , E(660F38,4C,_,x,_,0,4,FV ), 0 , 114, 0 , 374, 138), // #1539 + INST(Vrcp14sd , VexRvm , E(660F38,4D,_,I,_,1,3,T1S), 0 , 128, 0 , 420, 68 ), // #1540 + INST(Vrcp14ss , VexRvm , E(660F38,4D,_,I,_,0,2,T1S), 0 , 129, 0 , 421, 68 ), // #1541 + INST(Vrcp28pd , VexRm , E(660F38,CA,_,2,_,1,4,FV ), 0 , 170, 0 , 277, 147), // #1542 + INST(Vrcp28ps , VexRm , E(660F38,CA,_,2,_,0,4,FV ), 0 , 171, 0 , 278, 147), // #1543 + INST(Vrcp28sd , VexRvm , E(660F38,CB,_,I,_,1,3,T1S), 0 , 128, 0 , 308, 147), // #1544 + INST(Vrcp28ss , VexRvm , E(660F38,CB,_,I,_,0,2,T1S), 0 , 129, 0 , 309, 147), // #1545 + INST(Vrcpph , VexRm_Lx , E(66MAP6,4C,_,_,_,0,4,FV ), 0 , 183, 0 , 422, 134), // #1546 + INST(Vrcpps , VexRm_Lx , V(000F00,53,_,x,I,_,_,_ ), 0 , 72 , 0 , 298, 135), // #1547 + INST(Vrcpsh , VexRvm , E(66MAP6,4D,_,_,_,0,1,T1S), 0 , 185, 0 , 423, 134), // #1548 + INST(Vrcpss , VexRvm , V(F30F00,53,_,I,I,_,_,_ ), 0 , 199, 0 , 424, 135), // #1549 + INST(Vreducepd , VexRmi_Lx , E(660F3A,56,_,x,_,1,4,FV ), 0 , 112, 0 , 400, 140), // #1550 + INST(Vreduceph , VexRmi_Lx , E(000F3A,56,_,_,_,0,4,FV ), 0 , 123, 0 , 311, 132), // #1551 + INST(Vreduceps , VexRmi_Lx , E(660F3A,56,_,x,_,0,4,FV ), 0 , 111, 0 , 399, 140), // #1552 + INST(Vreducesd , VexRvmi , E(660F3A,57,_,I,_,1,3,T1S), 0 , 180, 0 , 425, 66 ), // #1553 + INST(Vreducesh , VexRvmi , E(000F3A,57,_,_,_,0,1,T1S), 0 , 188, 0 , 313, 134), // #1554 + INST(Vreducess , VexRvmi , E(660F3A,57,_,I,_,0,2,T1S), 0 , 181, 0 , 426, 66 ), // #1555 + INST(Vrndscalepd , VexRmi_Lx , E(660F3A,09,_,x,_,1,4,FV ), 0 , 112, 0 , 310, 138), // #1556 + INST(Vrndscaleph , VexRmi_Lx , E(000F3A,08,_,_,_,0,4,FV ), 0 , 123, 0 , 311, 132), // #1557 + INST(Vrndscaleps , VexRmi_Lx , E(660F3A,08,_,x,_,0,4,FV ), 0 , 111, 0 , 312, 138), // #1558 + INST(Vrndscalesd , VexRvmi , E(660F3A,0B,_,I,_,1,3,T1S), 0 , 180, 0 , 287, 68 ), // #1559 + INST(Vrndscalesh , VexRvmi , E(000F3A,0A,_,_,_,0,1,T1S), 0 , 188, 0 , 313, 134), // #1560 + INST(Vrndscaless , VexRvmi , E(660F3A,0A,_,I,_,0,2,T1S), 0 , 181, 0 , 288, 68 ), // #1561 + INST(Vroundpd , VexRmi_Lx , V(660F3A,09,_,x,I,_,_,_ ), 0 , 73 , 0 , 427, 135), // #1562 + INST(Vroundps , VexRmi_Lx , V(660F3A,08,_,x,I,_,_,_ ), 0 , 73 , 0 , 427, 135), // #1563 + INST(Vroundsd , VexRvmi , V(660F3A,0B,_,I,I,_,_,_ ), 0 , 73 , 0 , 428, 135), // #1564 + INST(Vroundss , VexRvmi , V(660F3A,0A,_,I,I,_,_,_ ), 0 , 73 , 0 , 429, 135), // #1565 + INST(Vrsqrt14pd , VexRm_Lx , E(660F38,4E,_,x,_,1,4,FV ), 0 , 113, 0 , 350, 138), // #1566 + INST(Vrsqrt14ps , VexRm_Lx , E(660F38,4E,_,x,_,0,4,FV ), 0 , 114, 0 , 374, 138), // #1567 + INST(Vrsqrt14sd , VexRvm , E(660F38,4F,_,I,_,1,3,T1S), 0 , 128, 0 , 420, 68 ), // #1568 + INST(Vrsqrt14ss , VexRvm , E(660F38,4F,_,I,_,0,2,T1S), 0 , 129, 0 , 421, 68 ), // #1569 + INST(Vrsqrt28pd , VexRm , E(660F38,CC,_,2,_,1,4,FV ), 0 , 170, 0 , 277, 147), // #1570 + INST(Vrsqrt28ps , VexRm , E(660F38,CC,_,2,_,0,4,FV ), 0 , 171, 0 , 278, 147), // #1571 + INST(Vrsqrt28sd , VexRvm , E(660F38,CD,_,I,_,1,3,T1S), 0 , 128, 0 , 308, 147), // #1572 + INST(Vrsqrt28ss , VexRvm , E(660F38,CD,_,I,_,0,2,T1S), 0 , 129, 0 , 309, 147), // #1573 + INST(Vrsqrtph , VexRm_Lx , E(66MAP6,4E,_,_,_,0,4,FV ), 0 , 183, 0 , 422, 132), // #1574 + INST(Vrsqrtps , VexRm_Lx , V(000F00,52,_,x,I,_,_,_ ), 0 , 72 , 0 , 298, 135), // #1575 + INST(Vrsqrtsh , VexRvm , E(66MAP6,4F,_,_,_,0,1,T1S), 0 , 185, 0 , 423, 134), // #1576 + INST(Vrsqrtss , VexRvm , V(F30F00,52,_,I,I,_,_,_ ), 0 , 199, 0 , 424, 135), // #1577 + INST(Vscalefpd , VexRvm_Lx , E(660F38,2C,_,x,_,1,4,FV ), 0 , 113, 0 , 430, 138), // #1578 + INST(Vscalefph , VexRvm_Lx , E(66MAP6,2C,_,_,_,0,4,FV ), 0 , 183, 0 , 197, 132), // #1579 + INST(Vscalefps , VexRvm_Lx , E(660F38,2C,_,x,_,0,4,FV ), 0 , 114, 0 , 284, 138), // #1580 + INST(Vscalefsd , VexRvm , E(660F38,2D,_,I,_,1,3,T1S), 0 , 128, 0 , 251, 68 ), // #1581 + INST(Vscalefsh , VexRvm , E(66MAP6,2D,_,_,_,0,1,T1S), 0 , 185, 0 , 200, 134), // #1582 + INST(Vscalefss , VexRvm , E(660F38,2D,_,I,_,0,2,T1S), 0 , 129, 0 , 259, 68 ), // #1583 + INST(Vscatterdpd , VexMr_VM , E(660F38,A2,_,x,_,1,3,T1S), 0 , 128, 0 , 403, 138), // #1584 + INST(Vscatterdps , VexMr_VM , E(660F38,A2,_,x,_,0,2,T1S), 0 , 129, 0 , 402, 138), // #1585 + INST(Vscatterpf0dpd , VexM_VM , E(660F38,C6,5,2,_,1,3,T1S), 0 , 230, 0 , 303, 153), // #1586 + INST(Vscatterpf0dps , VexM_VM , E(660F38,C6,5,2,_,0,2,T1S), 0 , 231, 0 , 304, 153), // #1587 + INST(Vscatterpf0qpd , VexM_VM , E(660F38,C7,5,2,_,1,3,T1S), 0 , 230, 0 , 305, 153), // #1588 + INST(Vscatterpf0qps , VexM_VM , E(660F38,C7,5,2,_,0,2,T1S), 0 , 231, 0 , 305, 153), // #1589 + INST(Vscatterpf1dpd , VexM_VM , E(660F38,C6,6,2,_,1,3,T1S), 0 , 232, 0 , 303, 153), // #1590 + INST(Vscatterpf1dps , VexM_VM , E(660F38,C6,6,2,_,0,2,T1S), 0 , 233, 0 , 304, 153), // #1591 + INST(Vscatterpf1qpd , VexM_VM , E(660F38,C7,6,2,_,1,3,T1S), 0 , 232, 0 , 305, 153), // #1592 + INST(Vscatterpf1qps , VexM_VM , E(660F38,C7,6,2,_,0,2,T1S), 0 , 233, 0 , 305, 153), // #1593 + INST(Vscatterqpd , VexMr_VM , E(660F38,A3,_,x,_,1,3,T1S), 0 , 128, 0 , 405, 138), // #1594 + INST(Vscatterqps , VexMr_VM , E(660F38,A3,_,x,_,0,2,T1S), 0 , 129, 0 , 404, 138), // #1595 + INST(Vshuff32x4 , VexRvmi_Lx , E(660F3A,23,_,x,_,0,4,FV ), 0 , 111, 0 , 431, 138), // #1596 + INST(Vshuff64x2 , VexRvmi_Lx , E(660F3A,23,_,x,_,1,4,FV ), 0 , 112, 0 , 432, 138), // #1597 + INST(Vshufi32x4 , VexRvmi_Lx , E(660F3A,43,_,x,_,0,4,FV ), 0 , 111, 0 , 431, 138), // #1598 + INST(Vshufi64x2 , VexRvmi_Lx , E(660F3A,43,_,x,_,1,4,FV ), 0 , 112, 0 , 432, 138), // #1599 + INST(Vshufpd , VexRvmi_Lx , V(660F00,C6,_,x,I,1,4,FV ), 0 , 103, 0 , 433, 131), // #1600 + INST(Vshufps , VexRvmi_Lx , V(000F00,C6,_,x,I,0,4,FV ), 0 , 105, 0 , 434, 131), // #1601 + INST(Vsqrtpd , VexRm_Lx , V(660F00,51,_,x,I,1,4,FV ), 0 , 103, 0 , 435, 131), // #1602 + INST(Vsqrtph , VexRm_Lx , E(00MAP5,51,_,_,_,0,4,FV ), 0 , 104, 0 , 246, 132), // #1603 + INST(Vsqrtps , VexRm_Lx , V(000F00,51,_,x,I,0,4,FV ), 0 , 105, 0 , 235, 131), // #1604 + INST(Vsqrtsd , VexRvm , V(F20F00,51,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #1605 + INST(Vsqrtsh , VexRvm , E(F3MAP5,51,_,_,_,0,1,T1S), 0 , 107, 0 , 200, 134), // #1606 + INST(Vsqrtss , VexRvm , V(F30F00,51,_,I,I,0,2,T1S), 0 , 108, 0 , 201, 133), // #1607 + INST(Vstmxcsr , VexM , V(000F00,AE,3,0,I,_,_,_ ), 0 , 234, 0 , 321, 135), // #1608 + INST(Vsubpd , VexRvm_Lx , V(660F00,5C,_,x,I,1,4,FV ), 0 , 103, 0 , 196, 131), // #1609 + INST(Vsubph , VexRvm_Lx , E(00MAP5,5C,_,_,_,0,4,FV ), 0 , 104, 0 , 197, 132), // #1610 + INST(Vsubps , VexRvm_Lx , V(000F00,5C,_,x,I,0,4,FV ), 0 , 105, 0 , 198, 131), // #1611 + INST(Vsubsd , VexRvm , V(F20F00,5C,_,I,I,1,3,T1S), 0 , 106, 0 , 199, 133), // #1612 + INST(Vsubsh , VexRvm , E(F3MAP5,5C,_,_,_,0,1,T1S), 0 , 107, 0 , 200, 134), // #1613 + INST(Vsubss , VexRvm , V(F30F00,5C,_,I,I,0,2,T1S), 0 , 108, 0 , 201, 133), // #1614 + INST(Vtestpd , VexRm_Lx , V(660F38,0F,_,x,0,_,_,_ ), 0 , 96 , 0 , 298, 167), // #1615 + INST(Vtestps , VexRm_Lx , V(660F38,0E,_,x,0,_,_,_ ), 0 , 96 , 0 , 298, 167), // #1616 + INST(Vucomisd , VexRm , V(660F00,2E,_,I,I,1,3,T1S), 0 , 125, 0 , 229, 143), // #1617 + INST(Vucomish , VexRm , E(00MAP5,2E,_,_,_,0,1,T1S), 0 , 126, 0 , 230, 134), // #1618 + INST(Vucomiss , VexRm , V(000F00,2E,_,I,I,0,2,T1S), 0 , 127, 0 , 231, 143), // #1619 + INST(Vunpckhpd , VexRvm_Lx , V(660F00,15,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 131), // #1620 + INST(Vunpckhps , VexRvm_Lx , V(000F00,15,_,x,I,0,4,FV ), 0 , 105, 0 , 209, 131), // #1621 + INST(Vunpcklpd , VexRvm_Lx , V(660F00,14,_,x,I,1,4,FV ), 0 , 103, 0 , 208, 131), // #1622 + INST(Vunpcklps , VexRvm_Lx , V(000F00,14,_,x,I,0,4,FV ), 0 , 105, 0 , 209, 131), // #1623 + INST(Vxorpd , VexRvm_Lx , V(660F00,57,_,x,I,1,4,FV ), 0 , 103, 0 , 417, 139), // #1624 + INST(Vxorps , VexRvm_Lx , V(000F00,57,_,x,I,0,4,FV ), 0 , 105, 0 , 416, 139), // #1625 + INST(Vzeroall , VexOp , V(000F00,77,_,1,I,_,_,_ ), 0 , 68 , 0 , 436, 135), // #1626 + INST(Vzeroupper , VexOp , V(000F00,77,_,0,I,_,_,_ ), 0 , 72 , 0 , 436, 135), // #1627 + INST(Wbinvd , X86Op , O(000F00,09,_,_,_,_,_,_ ), 0 , 4 , 0 , 30 , 0 ), // #1628 + INST(Wbnoinvd , X86Op , O(F30F00,09,_,_,_,_,_,_ ), 0 , 6 , 0 , 30 , 176), // #1629 + INST(Wrfsbase , X86M , O(F30F00,AE,2,_,x,_,_,_ ), 0 , 235, 0 , 173, 111), // #1630 + INST(Wrgsbase , X86M , O(F30F00,AE,3,_,x,_,_,_ ), 0 , 236, 0 , 173, 111), // #1631 + INST(Wrmsr , X86Op , O(000F00,30,_,_,_,_,_,_ ), 0 , 4 , 0 , 174, 112), // #1632 + INST(Wrssd , X86Mr , O(000F38,F6,_,_,_,_,_,_ ), 0 , 83 , 0 , 437, 56 ), // #1633 + INST(Wrssq , X86Mr , O(000F38,F6,_,_,1,_,_,_ ), 0 , 237, 0 , 438, 56 ), // #1634 + INST(Wrussd , X86Mr , O(660F38,F5,_,_,_,_,_,_ ), 0 , 2 , 0 , 437, 56 ), // #1635 + INST(Wrussq , X86Mr , O(660F38,F5,_,_,1,_,_,_ ), 0 , 238, 0 , 438, 56 ), // #1636 + INST(Xabort , X86Op_Mod11RM_I8 , O(000000,C6,7,_,_,_,_,_ ), 0 , 27 , 0 , 80 , 177), // #1637 + INST(Xadd , X86Xadd , O(000F00,C0,_,_,x,_,_,_ ), 0 , 4 , 0 , 439, 38 ), // #1638 + INST(Xbegin , X86JmpRel , O(000000,C7,7,_,_,_,_,_ ), 0 , 27 , 0 , 440, 177), // #1639 + INST(Xchg , X86Xchg , O(000000,86,_,_,x,_,_,_ ), 0 , 0 , 0 , 441, 0 ), // #1640 + INST(Xend , X86Op , O(000F01,D5,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 177), // #1641 + INST(Xgetbv , X86Op , O(000F01,D0,_,_,_,_,_,_ ), 0 , 21 , 0 , 174, 178), // #1642 + INST(Xlatb , X86Op , O(000000,D7,_,_,_,_,_,_ ), 0 , 0 , 0 , 30 , 0 ), // #1643 + INST(Xor , X86Arith , O(000000,30,6,_,x,_,_,_ ), 0 , 32 , 0 , 179, 1 ), // #1644 + INST(Xorpd , ExtRm , O(660F00,57,_,_,_,_,_,_ ), 0 , 3 , 0 , 151, 4 ), // #1645 + INST(Xorps , ExtRm , O(000F00,57,_,_,_,_,_,_ ), 0 , 4 , 0 , 151, 5 ), // #1646 + INST(Xresldtrk , X86Op , O(F20F01,E9,_,_,_,_,_,_ ), 0 , 92 , 0 , 30 , 179), // #1647 + INST(Xrstor , X86M_Only_EDX_EAX , O(000F00,AE,5,_,_,_,_,_ ), 0 , 77 , 0 , 442, 178), // #1648 + INST(Xrstor64 , X86M_Only_EDX_EAX , O(000F00,AE,5,_,1,_,_,_ ), 0 , 239, 0 , 443, 178), // #1649 + INST(Xrstors , X86M_Only_EDX_EAX , O(000F00,C7,3,_,_,_,_,_ ), 0 , 78 , 0 , 442, 180), // #1650 + INST(Xrstors64 , X86M_Only_EDX_EAX , O(000F00,C7,3,_,1,_,_,_ ), 0 , 240, 0 , 443, 180), // #1651 + INST(Xsave , X86M_Only_EDX_EAX , O(000F00,AE,4,_,_,_,_,_ ), 0 , 97 , 0 , 442, 178), // #1652 + INST(Xsave64 , X86M_Only_EDX_EAX , O(000F00,AE,4,_,1,_,_,_ ), 0 , 241, 0 , 443, 178), // #1653 + INST(Xsavec , X86M_Only_EDX_EAX , O(000F00,C7,4,_,_,_,_,_ ), 0 , 97 , 0 , 442, 181), // #1654 + INST(Xsavec64 , X86M_Only_EDX_EAX , O(000F00,C7,4,_,1,_,_,_ ), 0 , 241, 0 , 443, 181), // #1655 + INST(Xsaveopt , X86M_Only_EDX_EAX , O(000F00,AE,6,_,_,_,_,_ ), 0 , 80 , 0 , 442, 182), // #1656 + INST(Xsaveopt64 , X86M_Only_EDX_EAX , O(000F00,AE,6,_,1,_,_,_ ), 0 , 242, 0 , 443, 182), // #1657 + INST(Xsaves , X86M_Only_EDX_EAX , O(000F00,C7,5,_,_,_,_,_ ), 0 , 77 , 0 , 442, 180), // #1658 + INST(Xsaves64 , X86M_Only_EDX_EAX , O(000F00,C7,5,_,1,_,_,_ ), 0 , 239, 0 , 443, 180), // #1659 + INST(Xsetbv , X86Op , O(000F01,D1,_,_,_,_,_,_ ), 0 , 21 , 0 , 174, 178), // #1660 + INST(Xsusldtrk , X86Op , O(F20F01,E8,_,_,_,_,_,_ ), 0 , 92 , 0 , 30 , 179), // #1661 + INST(Xtest , X86Op , O(000F01,D6,_,_,_,_,_,_ ), 0 , 21 , 0 , 30 , 183) // #1662 // ${InstInfo:End} }; #undef NAME_DATA_INDEX @@ -2373,12 +2365,12 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Evex)|F(Vec) , X(K)|X(Z) , 482, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #220 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 479, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #221 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 483, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #222 [ref=1x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B64)|X(ImplicitZ)|X(K)|X(SAE), 197, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #223 [ref=1x] - { F(Evex)|F(Vec) , X(B16)|X(ImplicitZ)|X(K)|X(SAE), 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #224 [ref=1x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B32)|X(ImplicitZ)|X(K)|X(SAE), 197, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #225 [ref=1x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(ImplicitZ)|X(K)|X(SAE) , 484, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #226 [ref=1x] - { F(Evex)|F(Vec) , X(ImplicitZ)|X(K)|X(SAE) , 485, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #227 [ref=1x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(ImplicitZ)|X(K)|X(SAE) , 486, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #228 [ref=1x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B64)|X(K)|X(SAE)|X(Z) , 197, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #223 [ref=1x] + { F(Evex)|F(Vec) , X(B16)|X(K)|X(SAE) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #224 [ref=1x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B32)|X(K)|X(SAE)|X(Z) , 197, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #225 [ref=1x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(K)|X(SAE)|X(Z) , 484, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #226 [ref=1x] + { F(Evex)|F(Vec) , X(K)|X(SAE) , 485, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #227 [ref=1x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(K)|X(SAE)|X(Z) , 486, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #228 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(SAE) , 106, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #229 [ref=2x] { F(Evex)|F(Vec) , X(SAE) , 263, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #230 [ref=2x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(SAE) , 212, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #231 [ref=2x] @@ -2442,12 +2434,12 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex) , 0 , 159, 4 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #289 [ref=13x] { F(Vec)|F(Vex) , 0 , 357, 2 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #290 [ref=4x] { F(Vec)|F(Vex) , 0 , 359, 2 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #291 [ref=4x] - { F(Evex)|F(Vec) , X(B64)|X(ImplicitZ)|X(K) , 493, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #292 [ref=1x] + { F(Evex)|F(Vec) , X(B64)|X(K) , 493, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #292 [ref=1x] { F(Evex)|F(Vec) , X(B16)|X(K) , 493, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #293 [ref=1x] - { F(Evex)|F(Vec) , X(B32)|X(ImplicitZ)|X(K) , 493, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #294 [ref=1x] - { F(Evex)|F(Vec) , X(ImplicitZ)|X(K) , 494, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #295 [ref=1x] + { F(Evex)|F(Vec) , X(B32)|X(K) , 493, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #294 [ref=1x] + { F(Evex)|F(Vec) , X(K) , 494, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #295 [ref=1x] { F(Evex)|F(Vec) , X(K) , 495, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #296 [ref=1x] - { F(Evex)|F(Vec) , X(ImplicitZ)|X(K) , 496, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #297 [ref=1x] + { F(Evex)|F(Vec) , X(K) , 496, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #297 [ref=1x] { F(Vec)|F(Vex) , 0 , 209, 2 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #298 [ref=7x] { F(Vec)|F(Vex) , 0 , 106, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #299 [ref=1x] { F(Vec)|F(Vex) , 0 , 212, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #300 [ref=1x] @@ -2514,16 +2506,16 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 248, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #361 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 506, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #362 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , 0 , 194, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #363 [ref=1x] - { F(Evex)|F(Vec) , X(ImplicitZ)|X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #364 [ref=2x] - { F(Evex)|F(Vec) , X(B32)|X(ImplicitZ)|X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #365 [ref=2x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(ImplicitZ)|X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #366 [ref=4x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B32)|X(ImplicitZ)|X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #367 [ref=2x] - { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B64)|X(ImplicitZ)|X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #368 [ref=2x] + { F(Evex)|F(Vec) , X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #364 [ref=2x] + { F(Evex)|F(Vec) , X(B32)|X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #365 [ref=2x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #366 [ref=4x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B32)|X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #367 [ref=2x] + { F(Evex)|F(EvexKReg)|F(Vec)|F(Vex) , X(B64)|X(K) , 251, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #368 [ref=2x] { F(Vec)|F(Vex) , 0 , 449, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #369 [ref=1x] { F(Vec)|F(Vex) , 0 , 450, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #370 [ref=1x] { F(Vec)|F(Vex) , 0 , 451, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #371 [ref=1x] { F(Vec)|F(Vex) , 0 , 452, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #372 [ref=1x] - { F(Evex)|F(Vec) , X(B64)|X(ImplicitZ)|X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #373 [ref=4x] + { F(Evex)|F(Vec) , X(B64)|X(K) , 200, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #373 [ref=4x] { F(Evex)|F(Vec) , X(B32)|X(K)|X(Z) , 209, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #374 [ref=6x] { F(Evex)|F(EvexCompat)|F(PreferEvex)|F(Vec)|F(Vex) , X(B32)|X(K)|X(Z) , 191, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #375 [ref=4x] { F(Vec)|F(Vex) , 0 , 195, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #376 [ref=2x] @@ -2557,7 +2549,7 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Evex)|F(Vec)|F(Vsib) , X(K) , 379, 2 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #404 [ref=2x] { F(Evex)|F(Vec)|F(Vsib) , X(K) , 269, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #405 [ref=2x] { F(Vec)|F(Vex) , 0 , 381, 2 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #406 [ref=8x] - { F(Evex)|F(Vec) , X(ImplicitZ)|X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #407 [ref=5x] + { F(Evex)|F(Vec) , X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #407 [ref=5x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(B32)|X(K)|X(Z) , 221, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #408 [ref=1x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 221, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #409 [ref=2x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(B32)|X(K)|X(Z) , 91 , 6 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #410 [ref=3x] @@ -2568,8 +2560,8 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(K)|X(Z) , 191, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #415 [ref=6x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(B32)|X(K)|X(Z) , 191, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #416 [ref=2x] { F(Evex)|F(EvexCompat)|F(Vec)|F(Vex) , X(B64)|X(K)|X(Z) , 191, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(WO)}, // #417 [ref=2x] - { F(Evex)|F(Vec) , X(B32)|X(ImplicitZ)|X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #418 [ref=2x] - { F(Evex)|F(Vec) , X(B64)|X(ImplicitZ)|X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #419 [ref=2x] + { F(Evex)|F(Vec) , X(B32)|X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #418 [ref=2x] + { F(Evex)|F(Vec) , X(B64)|X(K) , 272, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #419 [ref=2x] { F(Evex)|F(Vec) , X(K)|X(Z) , 475, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #420 [ref=2x] { F(Evex)|F(Vec) , X(K)|X(Z) , 477, 1 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #421 [ref=2x] { F(Evex)|F(Vec) , X(B16)|X(K)|X(Z) , 209, 3 , CONTROL_FLOW(Regular), SAME_REG_HINT(None)}, // #422 [ref=2x] @@ -2609,178 +2601,190 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { // ------------------- Automatically generated, do not edit ------------------- #define EXT(VAL) uint32_t(CpuFeatures::X86::k##VAL) const InstDB::AdditionalInfo InstDB::_additionalInfoTable[] = { - { { 0 }, 0, 0 }, // #0 [ref=149x] - { { 0 }, 1, 0 }, // #1 [ref=32x] - { { 0 }, 2, 0 }, // #2 [ref=2x] - { { EXT(ADX) }, 3, 0 }, // #3 [ref=1x] - { { EXT(SSE2) }, 0, 0 }, // #4 [ref=65x] - { { EXT(SSE) }, 0, 0 }, // #5 [ref=44x] - { { EXT(SSE3) }, 0, 0 }, // #6 [ref=12x] - { { EXT(ADX) }, 4, 0 }, // #7 [ref=1x] - { { EXT(AESNI) }, 0, 0 }, // #8 [ref=6x] - { { EXT(BMI) }, 1, 0 }, // #9 [ref=6x] - { { 0 }, 5, 0 }, // #10 [ref=5x] - { { EXT(TBM) }, 0, 0 }, // #11 [ref=9x] - { { EXT(SSE4_1) }, 0, 0 }, // #12 [ref=47x] - { { EXT(MPX) }, 0, 0 }, // #13 [ref=7x] - { { 0 }, 6, 0 }, // #14 [ref=4x] - { { EXT(BMI2) }, 1, 0 }, // #15 [ref=1x] - { { EXT(SMAP) }, 7, 0 }, // #16 [ref=2x] - { { 0 }, 8, 0 }, // #17 [ref=2x] - { { 0 }, 9, 0 }, // #18 [ref=2x] - { { EXT(CLDEMOTE) }, 0, 0 }, // #19 [ref=1x] - { { EXT(CLFLUSH) }, 0, 0 }, // #20 [ref=1x] - { { EXT(CLFLUSHOPT) }, 0, 0 }, // #21 [ref=1x] - { { EXT(SVM) }, 0, 0 }, // #22 [ref=6x] - { { 0 }, 10, 0 }, // #23 [ref=2x] - { { EXT(CET_SS) }, 1, 0 }, // #24 [ref=3x] - { { EXT(UINTR) }, 0, 0 }, // #25 [ref=4x] - { { EXT(CLWB) }, 0, 0 }, // #26 [ref=1x] - { { EXT(CLZERO) }, 0, 0 }, // #27 [ref=1x] - { { 0 }, 3, 0 }, // #28 [ref=1x] - { { EXT(CMOV) }, 11, 0 }, // #29 [ref=6x] - { { EXT(CMOV) }, 12, 0 }, // #30 [ref=8x] - { { EXT(CMOV) }, 13, 0 }, // #31 [ref=6x] - { { EXT(CMOV) }, 14, 0 }, // #32 [ref=4x] - { { EXT(CMOV) }, 15, 0 }, // #33 [ref=4x] - { { EXT(CMOV) }, 16, 0 }, // #34 [ref=2x] - { { EXT(CMOV) }, 17, 0 }, // #35 [ref=6x] - { { EXT(CMOV) }, 18, 0 }, // #36 [ref=2x] - { { 0 }, 19, 0 }, // #37 [ref=2x] - { { EXT(I486) }, 1, 0 }, // #38 [ref=2x] - { { EXT(CMPXCHG16B) }, 5, 0 }, // #39 [ref=1x] - { { EXT(CMPXCHG8B) }, 5, 0 }, // #40 [ref=1x] - { { EXT(SSE2) }, 1, 0 }, // #41 [ref=2x] - { { EXT(SSE) }, 1, 0 }, // #42 [ref=2x] - { { EXT(I486) }, 0, 0 }, // #43 [ref=4x] - { { EXT(SSE4_2) }, 0, 0 }, // #44 [ref=2x] - { { 0 }, 20, 0 }, // #45 [ref=2x] - { { EXT(MMX) }, 0, 0 }, // #46 [ref=1x] - { { EXT(CET_IBT) }, 0, 0 }, // #47 [ref=2x] - { { EXT(ENQCMD) }, 0, 0 }, // #48 [ref=2x] - { { EXT(SSE4A) }, 0, 0 }, // #49 [ref=4x] - { { 0 }, 21, 0 }, // #50 [ref=4x] - { { EXT(3DNOW) }, 0, 0 }, // #51 [ref=21x] - { { EXT(FXSR) }, 0, 0 }, // #52 [ref=4x] - { { EXT(SMX) }, 0, 0 }, // #53 [ref=1x] - { { EXT(GFNI) }, 0, 0 }, // #54 [ref=3x] - { { EXT(HRESET) }, 0, 0 }, // #55 [ref=1x] - { { EXT(CET_SS) }, 0, 0 }, // #56 [ref=9x] - { { 0 }, 16, 0 }, // #57 [ref=5x] - { { EXT(VMX) }, 0, 0 }, // #58 [ref=12x] - { { 0 }, 11, 0 }, // #59 [ref=8x] - { { 0 }, 12, 0 }, // #60 [ref=12x] - { { 0 }, 13, 0 }, // #61 [ref=10x] - { { 0 }, 14, 0 }, // #62 [ref=8x] - { { 0 }, 15, 0 }, // #63 [ref=8x] - { { 0 }, 17, 0 }, // #64 [ref=8x] - { { 0 }, 18, 0 }, // #65 [ref=4x] - { { EXT(AVX512_DQ) }, 0, 0 }, // #66 [ref=23x] - { { EXT(AVX512_BW) }, 0, 0 }, // #67 [ref=22x] - { { EXT(AVX512_F) }, 0, 0 }, // #68 [ref=37x] - { { EXT(AVX512_DQ) }, 1, 0 }, // #69 [ref=3x] - { { EXT(AVX512_BW) }, 1, 0 }, // #70 [ref=4x] - { { EXT(AVX512_F) }, 1, 0 }, // #71 [ref=1x] - { { EXT(LAHFSAHF) }, 22, 0 }, // #72 [ref=1x] - { { EXT(AMX_TILE) }, 0, 0 }, // #73 [ref=7x] - { { EXT(LWP) }, 0, 0 }, // #74 [ref=4x] - { { 0 }, 23, 0 }, // #75 [ref=3x] - { { EXT(LZCNT) }, 1, 0 }, // #76 [ref=1x] - { { EXT(MMX2) }, 0, 0 }, // #77 [ref=8x] - { { EXT(MCOMMIT) }, 1, 0 }, // #78 [ref=1x] - { { EXT(MONITOR) }, 0, 0 }, // #79 [ref=2x] - { { EXT(MONITORX) }, 0, 0 }, // #80 [ref=2x] - { { EXT(MOVBE) }, 0, 0 }, // #81 [ref=1x] - { { EXT(MMX), EXT(SSE2) }, 0, 0 }, // #82 [ref=46x] - { { EXT(MOVDIR64B) }, 0, 0 }, // #83 [ref=1x] - { { EXT(MOVDIRI) }, 0, 0 }, // #84 [ref=1x] - { { EXT(BMI2) }, 0, 0 }, // #85 [ref=7x] - { { EXT(SSSE3) }, 0, 0 }, // #86 [ref=15x] - { { EXT(MMX2), EXT(SSE2) }, 0, 0 }, // #87 [ref=10x] - { { EXT(PCLMULQDQ) }, 0, 0 }, // #88 [ref=1x] - { { EXT(SSE4_2) }, 1, 0 }, // #89 [ref=4x] - { { EXT(PCONFIG) }, 0, 0 }, // #90 [ref=1x] - { { EXT(MMX2), EXT(SSE2), EXT(SSE4_1) }, 0, 0 }, // #91 [ref=1x] - { { EXT(3DNOW2) }, 0, 0 }, // #92 [ref=5x] - { { EXT(GEODE) }, 0, 0 }, // #93 [ref=2x] - { { EXT(POPCNT) }, 1, 0 }, // #94 [ref=1x] - { { 0 }, 24, 0 }, // #95 [ref=3x] - { { EXT(PREFETCHW) }, 1, 0 }, // #96 [ref=1x] - { { EXT(PREFETCHWT1) }, 1, 0 }, // #97 [ref=1x] - { { EXT(SNP) }, 20, 0 }, // #98 [ref=3x] - { { EXT(SSE4_1) }, 1, 0 }, // #99 [ref=1x] - { { EXT(PTWRITE) }, 0, 0 }, // #100 [ref=1x] - { { 0 }, 25, 0 }, // #101 [ref=3x] - { { EXT(SNP) }, 1, 0 }, // #102 [ref=1x] - { { 0 }, 26, 0 }, // #103 [ref=2x] - { { EXT(FSGSBASE) }, 0, 0 }, // #104 [ref=4x] - { { EXT(MSR) }, 0, 0 }, // #105 [ref=2x] - { { EXT(RDPID) }, 0, 0 }, // #106 [ref=1x] - { { EXT(OSPKE) }, 0, 0 }, // #107 [ref=1x] - { { EXT(RDPRU) }, 0, 0 }, // #108 [ref=1x] - { { EXT(RDRAND) }, 1, 0 }, // #109 [ref=1x] - { { EXT(RDSEED) }, 1, 0 }, // #110 [ref=1x] - { { EXT(RDTSC) }, 0, 0 }, // #111 [ref=1x] - { { EXT(RDTSCP) }, 0, 0 }, // #112 [ref=1x] - { { 0 }, 27, 0 }, // #113 [ref=2x] - { { EXT(LAHFSAHF) }, 28, 0 }, // #114 [ref=1x] - { { EXT(SERIALIZE) }, 0, 0 }, // #115 [ref=1x] - { { EXT(SHA) }, 0, 0 }, // #116 [ref=7x] - { { EXT(SKINIT) }, 0, 0 }, // #117 [ref=2x] - { { EXT(AMX_BF16) }, 0, 0 }, // #118 [ref=1x] - { { EXT(AMX_INT8) }, 0, 0 }, // #119 [ref=4x] - { { EXT(UINTR) }, 1, 0 }, // #120 [ref=1x] - { { EXT(WAITPKG) }, 1, 0 }, // #121 [ref=2x] - { { EXT(WAITPKG) }, 0, 0 }, // #122 [ref=1x] - { { EXT(AVX512_4FMAPS) }, 0, 0 }, // #123 [ref=4x] - { { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL) }, 0, 0 }, // #124 [ref=46x] - { { EXT(AVX512_FP16), EXT(AVX512_VL) }, 0, 0 }, // #125 [ref=63x] - { { EXT(AVX), EXT(AVX512_F) }, 0, 0 }, // #126 [ref=32x] - { { EXT(AVX512_FP16) }, 0, 0 }, // #127 [ref=43x] - { { EXT(AVX) }, 0, 0 }, // #128 [ref=37x] - { { EXT(AESNI), EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(VAES) }, 0, 0 }, // #129 [ref=4x] - { { EXT(AESNI), EXT(AVX) }, 0, 0 }, // #130 [ref=2x] - { { EXT(AVX512_F), EXT(AVX512_VL) }, 0, 0 }, // #131 [ref=112x] - { { EXT(AVX), EXT(AVX512_DQ), EXT(AVX512_VL) }, 0, 0 }, // #132 [ref=8x] - { { EXT(AVX512_DQ), EXT(AVX512_VL) }, 0, 0 }, // #133 [ref=30x] - { { EXT(AVX2) }, 0, 0 }, // #134 [ref=7x] - { { EXT(AVX), EXT(AVX2), EXT(AVX512_F), EXT(AVX512_VL) }, 0, 0 }, // #135 [ref=39x] - { { EXT(AVX), EXT(AVX512_F) }, 1, 0 }, // #136 [ref=4x] - { { EXT(AVX512_BF16), EXT(AVX512_VL) }, 0, 0 }, // #137 [ref=3x] - { { EXT(AVX512_F), EXT(AVX512_VL), EXT(F16C) }, 0, 0 }, // #138 [ref=2x] - { { EXT(AVX512_BW), EXT(AVX512_VL) }, 0, 0 }, // #139 [ref=26x] - { { EXT(AVX512_ERI) }, 0, 0 }, // #140 [ref=10x] - { { EXT(AVX512_F), EXT(AVX512_VL), EXT(FMA) }, 0, 0 }, // #141 [ref=36x] - { { EXT(AVX512_F), EXT(FMA) }, 0, 0 }, // #142 [ref=24x] - { { EXT(FMA4) }, 0, 0 }, // #143 [ref=20x] - { { EXT(XOP) }, 0, 0 }, // #144 [ref=55x] - { { EXT(AVX2), EXT(AVX512_F), EXT(AVX512_VL) }, 0, 0 }, // #145 [ref=19x] - { { EXT(AVX512_PFI) }, 0, 0 }, // #146 [ref=16x] - { { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(GFNI) }, 0, 0 }, // #147 [ref=3x] - { { EXT(AVX), EXT(AVX2) }, 0, 0 }, // #148 [ref=17x] - { { EXT(AVX512_VP2INTERSECT) }, 0, 0 }, // #149 [ref=2x] - { { EXT(AVX512_4VNNIW) }, 0, 0 }, // #150 [ref=2x] - { { EXT(AVX), EXT(AVX2), EXT(AVX512_BW), EXT(AVX512_VL) }, 0, 0 }, // #151 [ref=54x] - { { EXT(AVX2), EXT(AVX512_BW), EXT(AVX512_VL) }, 0, 0 }, // #152 [ref=2x] - { { EXT(AVX512_CDI), EXT(AVX512_VL) }, 0, 0 }, // #153 [ref=6x] - { { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(PCLMULQDQ), EXT(VPCLMULQDQ) }, 0, 0 }, // #154 [ref=1x] - { { EXT(AVX) }, 1, 0 }, // #155 [ref=7x] - { { EXT(AVX512_VBMI2), EXT(AVX512_VL) }, 0, 0 }, // #156 [ref=16x] - { { EXT(AVX512_VL), EXT(AVX512_VNNI), EXT(AVX_VNNI) }, 0, 0 }, // #157 [ref=4x] - { { EXT(AVX512_VBMI), EXT(AVX512_VL) }, 0, 0 }, // #158 [ref=4x] - { { EXT(AVX), EXT(AVX512_BW) }, 0, 0 }, // #159 [ref=4x] - { { EXT(AVX), EXT(AVX512_DQ) }, 0, 0 }, // #160 [ref=4x] - { { EXT(AVX512_IFMA), EXT(AVX512_VL) }, 0, 0 }, // #161 [ref=2x] - { { EXT(AVX512_BITALG), EXT(AVX512_VL) }, 0, 0 }, // #162 [ref=3x] - { { EXT(AVX512_VL), EXT(AVX512_VPOPCNTDQ) }, 0, 0 }, // #163 [ref=2x] - { { EXT(WBNOINVD) }, 0, 0 }, // #164 [ref=1x] - { { EXT(RTM) }, 0, 0 }, // #165 [ref=3x] - { { EXT(XSAVE) }, 0, 0 }, // #166 [ref=6x] - { { EXT(TSXLDTRK) }, 0, 0 }, // #167 [ref=2x] - { { EXT(XSAVES) }, 0, 0 }, // #168 [ref=4x] - { { EXT(XSAVEC) }, 0, 0 }, // #169 [ref=2x] - { { EXT(XSAVEOPT) }, 0, 0 }, // #170 [ref=2x] - { { EXT(TSX) }, 1, 0 } // #171 [ref=1x] + { 0, 0, { 0 } }, // #0 [ref=148x] + { 0, 1, { 0 } }, // #1 [ref=32x] + { 0, 2, { 0 } }, // #2 [ref=2x] + { 0, 3, { EXT(ADX) } }, // #3 [ref=1x] + { 0, 0, { EXT(SSE2) } }, // #4 [ref=60x] + { 0, 0, { EXT(SSE) } }, // #5 [ref=41x] + { 0, 0, { EXT(SSE3) } }, // #6 [ref=12x] + { 0, 4, { EXT(ADX) } }, // #7 [ref=1x] + { 0, 0, { EXT(AESNI) } }, // #8 [ref=6x] + { 0, 1, { EXT(BMI) } }, // #9 [ref=6x] + { 0, 5, { 0 } }, // #10 [ref=5x] + { 0, 0, { EXT(TBM) } }, // #11 [ref=9x] + { 0, 0, { EXT(SSE4_1) } }, // #12 [ref=47x] + { 0, 0, { EXT(MPX) } }, // #13 [ref=7x] + { 0, 6, { 0 } }, // #14 [ref=4x] + { 0, 1, { EXT(BMI2) } }, // #15 [ref=1x] + { 0, 7, { EXT(SMAP) } }, // #16 [ref=2x] + { 0, 8, { 0 } }, // #17 [ref=2x] + { 0, 9, { 0 } }, // #18 [ref=2x] + { 0, 0, { EXT(CLDEMOTE) } }, // #19 [ref=1x] + { 0, 0, { EXT(CLFLUSH) } }, // #20 [ref=1x] + { 0, 0, { EXT(CLFLUSHOPT) } }, // #21 [ref=1x] + { 0, 0, { EXT(SVM) } }, // #22 [ref=6x] + { 0, 10, { 0 } }, // #23 [ref=2x] + { 0, 1, { EXT(CET_SS) } }, // #24 [ref=3x] + { 0, 0, { EXT(UINTR) } }, // #25 [ref=4x] + { 0, 0, { EXT(CLWB) } }, // #26 [ref=1x] + { 0, 0, { EXT(CLZERO) } }, // #27 [ref=1x] + { 0, 3, { 0 } }, // #28 [ref=1x] + { 0, 11, { EXT(CMOV) } }, // #29 [ref=6x] + { 0, 12, { EXT(CMOV) } }, // #30 [ref=8x] + { 0, 13, { EXT(CMOV) } }, // #31 [ref=6x] + { 0, 14, { EXT(CMOV) } }, // #32 [ref=4x] + { 0, 15, { EXT(CMOV) } }, // #33 [ref=4x] + { 0, 16, { EXT(CMOV) } }, // #34 [ref=2x] + { 0, 17, { EXT(CMOV) } }, // #35 [ref=6x] + { 0, 18, { EXT(CMOV) } }, // #36 [ref=2x] + { 0, 19, { 0 } }, // #37 [ref=2x] + { 0, 1, { EXT(I486) } }, // #38 [ref=2x] + { 0, 5, { EXT(CMPXCHG16B) } }, // #39 [ref=1x] + { 0, 5, { EXT(CMPXCHG8B) } }, // #40 [ref=1x] + { 0, 1, { EXT(SSE2) } }, // #41 [ref=2x] + { 0, 1, { EXT(SSE) } }, // #42 [ref=2x] + { 0, 0, { EXT(I486) } }, // #43 [ref=4x] + { 0, 0, { EXT(SSE4_2) } }, // #44 [ref=2x] + { 0, 20, { 0 } }, // #45 [ref=2x] + { 0, 0, { EXT(MMX) } }, // #46 [ref=1x] + { 0, 0, { EXT(CET_IBT) } }, // #47 [ref=2x] + { 0, 0, { EXT(ENQCMD) } }, // #48 [ref=2x] + { 0, 0, { EXT(SSE4A) } }, // #49 [ref=4x] + { 0, 21, { 0 } }, // #50 [ref=4x] + { 0, 0, { EXT(3DNOW) } }, // #51 [ref=21x] + { 0, 0, { EXT(FXSR) } }, // #52 [ref=4x] + { 0, 0, { EXT(SMX) } }, // #53 [ref=1x] + { 0, 0, { EXT(GFNI) } }, // #54 [ref=3x] + { 0, 0, { EXT(HRESET) } }, // #55 [ref=1x] + { 0, 0, { EXT(CET_SS) } }, // #56 [ref=9x] + { 0, 16, { 0 } }, // #57 [ref=5x] + { 0, 0, { EXT(VMX) } }, // #58 [ref=12x] + { 0, 11, { 0 } }, // #59 [ref=8x] + { 0, 12, { 0 } }, // #60 [ref=12x] + { 0, 13, { 0 } }, // #61 [ref=10x] + { 0, 14, { 0 } }, // #62 [ref=8x] + { 0, 15, { 0 } }, // #63 [ref=8x] + { 0, 17, { 0 } }, // #64 [ref=8x] + { 0, 18, { 0 } }, // #65 [ref=4x] + { 0, 0, { EXT(AVX512_DQ) } }, // #66 [ref=22x] + { 0, 0, { EXT(AVX512_BW) } }, // #67 [ref=20x] + { 0, 0, { EXT(AVX512_F) } }, // #68 [ref=36x] + { 1, 0, { EXT(AVX512_DQ) } }, // #69 [ref=1x] + { 1, 0, { EXT(AVX512_BW) } }, // #70 [ref=2x] + { 1, 0, { EXT(AVX512_F) } }, // #71 [ref=1x] + { 0, 1, { EXT(AVX512_DQ) } }, // #72 [ref=3x] + { 0, 1, { EXT(AVX512_BW) } }, // #73 [ref=4x] + { 0, 1, { EXT(AVX512_F) } }, // #74 [ref=1x] + { 0, 22, { EXT(LAHFSAHF) } }, // #75 [ref=1x] + { 0, 0, { EXT(AMX_TILE) } }, // #76 [ref=7x] + { 0, 0, { EXT(LWP) } }, // #77 [ref=4x] + { 0, 23, { 0 } }, // #78 [ref=3x] + { 0, 1, { EXT(LZCNT) } }, // #79 [ref=1x] + { 0, 0, { EXT(MMX2) } }, // #80 [ref=8x] + { 0, 1, { EXT(MCOMMIT) } }, // #81 [ref=1x] + { 0, 0, { EXT(MONITOR) } }, // #82 [ref=2x] + { 0, 0, { EXT(MONITORX) } }, // #83 [ref=2x] + { 1, 0, { 0 } }, // #84 [ref=1x] + { 1, 0, { EXT(SSE2) } }, // #85 [ref=5x] + { 1, 0, { EXT(SSE) } }, // #86 [ref=3x] + { 0, 0, { EXT(MOVBE) } }, // #87 [ref=1x] + { 0, 0, { EXT(MMX), EXT(SSE2) } }, // #88 [ref=45x] + { 0, 0, { EXT(MOVDIR64B) } }, // #89 [ref=1x] + { 0, 0, { EXT(MOVDIRI) } }, // #90 [ref=1x] + { 1, 0, { EXT(MMX), EXT(SSE2) } }, // #91 [ref=1x] + { 0, 0, { EXT(BMI2) } }, // #92 [ref=7x] + { 0, 0, { EXT(SSSE3) } }, // #93 [ref=15x] + { 0, 0, { EXT(MMX2), EXT(SSE2) } }, // #94 [ref=10x] + { 0, 0, { EXT(PCLMULQDQ) } }, // #95 [ref=1x] + { 0, 1, { EXT(SSE4_2) } }, // #96 [ref=4x] + { 0, 0, { EXT(PCONFIG) } }, // #97 [ref=1x] + { 0, 0, { EXT(MMX2), EXT(SSE2), EXT(SSE4_1) } }, // #98 [ref=1x] + { 0, 0, { EXT(3DNOW2) } }, // #99 [ref=5x] + { 0, 0, { EXT(GEODE) } }, // #100 [ref=2x] + { 0, 1, { EXT(POPCNT) } }, // #101 [ref=1x] + { 0, 24, { 0 } }, // #102 [ref=3x] + { 0, 1, { EXT(PREFETCHW) } }, // #103 [ref=1x] + { 0, 1, { EXT(PREFETCHWT1) } }, // #104 [ref=1x] + { 0, 20, { EXT(SNP) } }, // #105 [ref=3x] + { 0, 1, { EXT(SSE4_1) } }, // #106 [ref=1x] + { 0, 0, { EXT(PTWRITE) } }, // #107 [ref=1x] + { 0, 25, { 0 } }, // #108 [ref=3x] + { 0, 1, { EXT(SNP) } }, // #109 [ref=1x] + { 0, 26, { 0 } }, // #110 [ref=2x] + { 0, 0, { EXT(FSGSBASE) } }, // #111 [ref=4x] + { 0, 0, { EXT(MSR) } }, // #112 [ref=2x] + { 0, 0, { EXT(RDPID) } }, // #113 [ref=1x] + { 0, 0, { EXT(OSPKE) } }, // #114 [ref=1x] + { 0, 0, { EXT(RDPRU) } }, // #115 [ref=1x] + { 0, 1, { EXT(RDRAND) } }, // #116 [ref=1x] + { 0, 1, { EXT(RDSEED) } }, // #117 [ref=1x] + { 0, 0, { EXT(RDTSC) } }, // #118 [ref=1x] + { 0, 0, { EXT(RDTSCP) } }, // #119 [ref=1x] + { 0, 27, { 0 } }, // #120 [ref=2x] + { 0, 28, { EXT(LAHFSAHF) } }, // #121 [ref=1x] + { 0, 0, { EXT(SERIALIZE) } }, // #122 [ref=1x] + { 0, 0, { EXT(SHA) } }, // #123 [ref=7x] + { 0, 0, { EXT(SKINIT) } }, // #124 [ref=2x] + { 0, 0, { EXT(AMX_BF16) } }, // #125 [ref=1x] + { 0, 0, { EXT(AMX_INT8) } }, // #126 [ref=4x] + { 0, 1, { EXT(UINTR) } }, // #127 [ref=1x] + { 0, 1, { EXT(WAITPKG) } }, // #128 [ref=2x] + { 0, 0, { EXT(WAITPKG) } }, // #129 [ref=1x] + { 0, 0, { EXT(AVX512_4FMAPS) } }, // #130 [ref=4x] + { 0, 0, { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL) } }, // #131 [ref=42x] + { 0, 0, { EXT(AVX512_FP16), EXT(AVX512_VL) } }, // #132 [ref=63x] + { 0, 0, { EXT(AVX), EXT(AVX512_F) } }, // #133 [ref=29x] + { 0, 0, { EXT(AVX512_FP16) } }, // #134 [ref=43x] + { 0, 0, { EXT(AVX) } }, // #135 [ref=35x] + { 0, 0, { EXT(AESNI), EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(VAES) } }, // #136 [ref=4x] + { 0, 0, { EXT(AESNI), EXT(AVX) } }, // #137 [ref=2x] + { 0, 0, { EXT(AVX512_F), EXT(AVX512_VL) } }, // #138 [ref=108x] + { 0, 0, { EXT(AVX), EXT(AVX512_DQ), EXT(AVX512_VL) } }, // #139 [ref=8x] + { 0, 0, { EXT(AVX512_DQ), EXT(AVX512_VL) } }, // #140 [ref=30x] + { 0, 0, { EXT(AVX2) } }, // #141 [ref=7x] + { 0, 0, { EXT(AVX), EXT(AVX2), EXT(AVX512_F), EXT(AVX512_VL) } }, // #142 [ref=39x] + { 0, 1, { EXT(AVX), EXT(AVX512_F) } }, // #143 [ref=4x] + { 0, 0, { EXT(AVX512_BF16), EXT(AVX512_VL) } }, // #144 [ref=3x] + { 0, 0, { EXT(AVX512_F), EXT(AVX512_VL), EXT(F16C) } }, // #145 [ref=2x] + { 0, 0, { EXT(AVX512_BW), EXT(AVX512_VL) } }, // #146 [ref=24x] + { 0, 0, { EXT(AVX512_ERI) } }, // #147 [ref=10x] + { 0, 0, { EXT(AVX512_F), EXT(AVX512_VL), EXT(FMA) } }, // #148 [ref=36x] + { 0, 0, { EXT(AVX512_F), EXT(FMA) } }, // #149 [ref=24x] + { 0, 0, { EXT(FMA4) } }, // #150 [ref=20x] + { 0, 0, { EXT(XOP) } }, // #151 [ref=55x] + { 0, 0, { EXT(AVX2), EXT(AVX512_F), EXT(AVX512_VL) } }, // #152 [ref=19x] + { 0, 0, { EXT(AVX512_PFI) } }, // #153 [ref=16x] + { 0, 0, { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(GFNI) } }, // #154 [ref=3x] + { 1, 0, { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL) } }, // #155 [ref=4x] + { 1, 0, { EXT(AVX) } }, // #156 [ref=2x] + { 1, 0, { EXT(AVX512_F), EXT(AVX512_VL) } }, // #157 [ref=4x] + { 1, 0, { EXT(AVX512_BW), EXT(AVX512_VL) } }, // #158 [ref=2x] + { 1, 0, { EXT(AVX), EXT(AVX512_F) } }, // #159 [ref=3x] + { 0, 0, { EXT(AVX), EXT(AVX2) } }, // #160 [ref=17x] + { 0, 0, { EXT(AVX512_VP2INTERSECT) } }, // #161 [ref=2x] + { 0, 0, { EXT(AVX512_4VNNIW) } }, // #162 [ref=2x] + { 0, 0, { EXT(AVX), EXT(AVX2), EXT(AVX512_BW), EXT(AVX512_VL) } }, // #163 [ref=54x] + { 0, 0, { EXT(AVX2), EXT(AVX512_BW), EXT(AVX512_VL) } }, // #164 [ref=2x] + { 0, 0, { EXT(AVX512_CDI), EXT(AVX512_VL) } }, // #165 [ref=6x] + { 0, 0, { EXT(AVX), EXT(AVX512_F), EXT(AVX512_VL), EXT(PCLMULQDQ), EXT(VPCLMULQDQ) } }, // #166 [ref=1x] + { 0, 1, { EXT(AVX) } }, // #167 [ref=7x] + { 0, 0, { EXT(AVX512_VBMI2), EXT(AVX512_VL) } }, // #168 [ref=16x] + { 0, 0, { EXT(AVX512_VL), EXT(AVX512_VNNI), EXT(AVX_VNNI) } }, // #169 [ref=4x] + { 0, 0, { EXT(AVX512_VBMI), EXT(AVX512_VL) } }, // #170 [ref=4x] + { 0, 0, { EXT(AVX), EXT(AVX512_BW) } }, // #171 [ref=4x] + { 0, 0, { EXT(AVX), EXT(AVX512_DQ) } }, // #172 [ref=4x] + { 0, 0, { EXT(AVX512_IFMA), EXT(AVX512_VL) } }, // #173 [ref=2x] + { 0, 0, { EXT(AVX512_BITALG), EXT(AVX512_VL) } }, // #174 [ref=3x] + { 0, 0, { EXT(AVX512_VL), EXT(AVX512_VPOPCNTDQ) } }, // #175 [ref=2x] + { 0, 0, { EXT(WBNOINVD) } }, // #176 [ref=1x] + { 0, 0, { EXT(RTM) } }, // #177 [ref=3x] + { 0, 0, { EXT(XSAVE) } }, // #178 [ref=6x] + { 0, 0, { EXT(TSXLDTRK) } }, // #179 [ref=2x] + { 0, 0, { EXT(XSAVES) } }, // #180 [ref=4x] + { 0, 0, { EXT(XSAVEC) } }, // #181 [ref=2x] + { 0, 0, { EXT(XSAVEOPT) } }, // #182 [ref=2x] + { 0, 1, { EXT(TSX) } } // #183 [ref=1x] }; #undef EXT @@ -2817,6 +2821,13 @@ const InstDB::RWFlagsInfoTable InstDB::_rwFlagsInfoTable[] = { { 0, FLAG(AF) | FLAG(CF) | FLAG(PF) | FLAG(SF) | FLAG(ZF) } // #28 [ref=1x] }; #undef FLAG + +#define FLAG(VAL) uint32_t(InstRWFlags::k##VAL) +const InstRWFlags InstDB::_instFlagsTable[] = { + InstRWFlags(FLAG(None)), // #0 [ref=1634x] + InstRWFlags(FLAG(MovOp)) // #1 [ref=29x] +}; +#undef FLAG // ---------------------------------------------------------------------------- // ${AdditionalInfoTable:End} @@ -2826,161 +2837,1698 @@ const InstDB::RWFlagsInfoTable InstDB::_rwFlagsInfoTable[] = { #ifndef ASMJIT_NO_TEXT // ${NameData:Begin} // ------------------- Automatically generated, do not edit ------------------- -const char InstDB::_nameData[] = - "\0" "aaa\0" "aad\0" "aam\0" "aas\0" "adc\0" "adcx\0" "adox\0" "arpl\0" "bextr\0" "blcfill\0" "blci\0" "blcic\0" - "blcmsk\0" "blcs\0" "blsfill\0" "blsi\0" "blsic\0" "blsmsk\0" "blsr\0" "bndcl\0" "bndcn\0" "bndcu\0" "bndldx\0" - "bndmk\0" "bndmov\0" "bndstx\0" "bound\0" "bsf\0" "bsr\0" "bswap\0" "bt\0" "btc\0" "btr\0" "bts\0" "bzhi\0" "cbw\0" - "cdq\0" "cdqe\0" "clac\0" "clc\0" "cld\0" "cldemote\0" "clflush\0" "clflushopt\0" "clgi\0" "cli\0" "clrssbsy\0" - "clts\0" "clui\0" "clwb\0" "clzero\0" "cmc\0" "cmova\0" "cmovae\0" "cmovc\0" "cmovg\0" "cmovge\0" "cmovl\0" - "cmovle\0" "cmovna\0" "cmovnae\0" "cmovnc\0" "cmovng\0" "cmovnge\0" "cmovnl\0" "cmovnle\0" "cmovno\0" "cmovnp\0" - "cmovns\0" "cmovnz\0" "cmovo\0" "cmovp\0" "cmovpe\0" "cmovpo\0" "cmovs\0" "cmovz\0" "cmp\0" "cmps\0" "cmpxchg\0" - "cmpxchg16b\0" "cmpxchg8b\0" "cpuid\0" "cqo\0" "crc32\0" "cvtpd2pi\0" "cvtpi2pd\0" "cvtpi2ps\0" "cvtps2pi\0" - "cvttpd2pi\0" "cvttps2pi\0" "cwd\0" "cwde\0" "daa\0" "das\0" "endbr32\0" "endbr64\0" "enqcmd\0" "enqcmds\0" "f2xm1\0" - "fabs\0" "faddp\0" "fbld\0" "fbstp\0" "fchs\0" "fclex\0" "fcmovb\0" "fcmovbe\0" "fcmove\0" "fcmovnb\0" "fcmovnbe\0" - "fcmovne\0" "fcmovnu\0" "fcmovu\0" "fcom\0" "fcomi\0" "fcomip\0" "fcomp\0" "fcompp\0" "fcos\0" "fdecstp\0" "fdiv\0" - "fdivp\0" "fdivr\0" "fdivrp\0" "femms\0" "ffree\0" "fiadd\0" "ficom\0" "ficomp\0" "fidiv\0" "fidivr\0" "fild\0" - "fimul\0" "fincstp\0" "finit\0" "fist\0" "fistp\0" "fisttp\0" "fisub\0" "fisubr\0" "fld\0" "fld1\0" "fldcw\0" - "fldenv\0" "fldl2e\0" "fldl2t\0" "fldlg2\0" "fldln2\0" "fldpi\0" "fldz\0" "fmulp\0" "fnclex\0" "fninit\0" "fnop\0" - "fnsave\0" "fnstcw\0" "fnstenv\0" "fnstsw\0" "fpatan\0" "fprem\0" "fprem1\0" "fptan\0" "frndint\0" "frstor\0" - "fsave\0" "fscale\0" "fsin\0" "fsincos\0" "fsqrt\0" "fst\0" "fstcw\0" "fstenv\0" "fstp\0" "fstsw\0" "fsubp\0" - "fsubrp\0" "ftst\0" "fucom\0" "fucomi\0" "fucomip\0" "fucomp\0" "fucompp\0" "fwait\0" "fxam\0" "fxch\0" "fxrstor\0" - "fxrstor64\0" "fxsave\0" "fxsave64\0" "fxtract\0" "fyl2x\0" "fyl2xp1\0" "getsec\0" "hlt\0" "hreset\0" "inc\0" - "incsspd\0" "incsspq\0" "insertq\0" "int3\0" "into\0" "invept\0" "invlpg\0" "invlpga\0" "invpcid\0" "invvpid\0" - "iretd\0" "iretq\0" "ja\0" "jae\0" "jb\0" "jbe\0" "jc\0" "je\0" "jecxz\0" "jg\0" "jge\0" "jl\0" "jle\0" "jna\0" - "jnae\0" "jnb\0" "jnbe\0" "jnc\0" "jne\0" "jng\0" "jnge\0" "jnl\0" "jnle\0" "jno\0" "jnp\0" "jns\0" "jnz\0" "jo\0" - "jp\0" "jpe\0" "jpo\0" "js\0" "jz\0" "kaddb\0" "kaddd\0" "kaddq\0" "kaddw\0" "kandb\0" "kandd\0" "kandnb\0" - "kandnd\0" "kandnq\0" "kandnw\0" "kandq\0" "kandw\0" "kmovb\0" "kmovw\0" "knotb\0" "knotd\0" "knotq\0" "knotw\0" - "korb\0" "kord\0" "korq\0" "kortestb\0" "kortestd\0" "kortestq\0" "kortestw\0" "korw\0" "kshiftlb\0" "kshiftld\0" - "kshiftlq\0" "kshiftlw\0" "kshiftrb\0" "kshiftrd\0" "kshiftrq\0" "kshiftrw\0" "ktestb\0" "ktestd\0" "ktestq\0" - "ktestw\0" "kunpckbw\0" "kunpckdq\0" "kunpckwd\0" "kxnorb\0" "kxnord\0" "kxnorq\0" "kxnorw\0" "kxorb\0" "kxord\0" - "kxorq\0" "kxorw\0" "lahf\0" "lar\0" "lcall\0" "lds\0" "ldtilecfg\0" "lea\0" "leave\0" "les\0" "lfence\0" "lfs\0" - "lgdt\0" "lgs\0" "lidt\0" "ljmp\0" "lldt\0" "llwpcb\0" "lmsw\0" "lods\0" "loop\0" "loope\0" "loopne\0" "lsl\0" - "ltr\0" "lwpins\0" "lwpval\0" "lzcnt\0" "mcommit\0" "mfence\0" "monitorx\0" "movabs\0" "movdir64b\0" "movdiri\0" - "movdq2q\0" "movnti\0" "movntq\0" "movntsd\0" "movntss\0" "movq2dq\0" "movsx\0" "movsxd\0" "movzx\0" "mulx\0" - "mwaitx\0" "neg\0" "not\0" "out\0" "outs\0" "pavgusb\0" "pconfig\0" "pdep\0" "pext\0" "pf2id\0" "pf2iw\0" "pfacc\0" - "pfadd\0" "pfcmpeq\0" "pfcmpge\0" "pfcmpgt\0" "pfmax\0" "pfmin\0" "pfmul\0" "pfnacc\0" "pfpnacc\0" "pfrcp\0" - "pfrcpit1\0" "pfrcpit2\0" "pfrcpv\0" "pfrsqit1\0" "pfrsqrt\0" "pfrsqrtv\0" "pfsub\0" "pfsubr\0" "pi2fd\0" "pi2fw\0" - "pmulhrw\0" "pop\0" "popa\0" "popad\0" "popcnt\0" "popf\0" "popfd\0" "popfq\0" "prefetch\0" "prefetchnta\0" - "prefetcht0\0" "prefetcht1\0" "prefetcht2\0" "prefetchw\0" "prefetchwt1\0" "pshufw\0" "psmash\0" "pswapd\0" - "ptwrite\0" "push\0" "pusha\0" "pushad\0" "pushf\0" "pushfd\0" "pushfq\0" "pvalidate\0" "rcl\0" "rcr\0" "rdfsbase\0" - "rdgsbase\0" "rdmsr\0" "rdpid\0" "rdpkru\0" "rdpmc\0" "rdpru\0" "rdrand\0" "rdseed\0" "rdsspd\0" "rdsspq\0" "rdtsc\0" - "rdtscp\0" "retf\0" "rmpadjust\0" "rmpupdate\0" "rol\0" "ror\0" "rorx\0" "rsm\0" "rstorssp\0" "sahf\0" "sal\0" - "sar\0" "sarx\0" "saveprevssp\0" "sbb\0" "scas\0" "senduipi\0" "serialize\0" "seta\0" "setae\0" "setb\0" "setbe\0" - "setc\0" "sete\0" "setg\0" "setge\0" "setl\0" "setle\0" "setna\0" "setnae\0" "setnb\0" "setnbe\0" "setnc\0" "setne\0" - "setng\0" "setnge\0" "setnl\0" "setnle\0" "setno\0" "setnp\0" "setns\0" "setnz\0" "seto\0" "setp\0" "setpe\0" - "setpo\0" "sets\0" "setssbsy\0" "setz\0" "sfence\0" "sgdt\0" "sha1msg1\0" "sha1msg2\0" "sha1nexte\0" "sha1rnds4\0" - "sha256msg1\0" "sha256msg2\0" "sha256rnds2\0" "shl\0" "shlx\0" "shr\0" "shrd\0" "shrx\0" "sidt\0" "skinit\0" "sldt\0" - "slwpcb\0" "smsw\0" "stac\0" "stc\0" "stgi\0" "sti\0" "stos\0" "str\0" "sttilecfg\0" "swapgs\0" "syscall\0" - "sysenter\0" "sysexit\0" "sysexitq\0" "sysret\0" "sysretq\0" "t1mskc\0" "tdpbf16ps\0" "tdpbssd\0" "tdpbsud\0" - "tdpbusd\0" "tdpbuud\0" "testui\0" "tileloadd\0" "tileloaddt1\0" "tilerelease\0" "tilestored\0" "tilezero\0" - "tpause\0" "tzcnt\0" "tzmsk\0" "ud0\0" "ud1\0" "ud2\0" "uiret\0" "umonitor\0" "umwait\0" "v4fmaddps\0" "v4fmaddss\0" - "v4fnmaddps\0" "v4fnmaddss\0" "vaddpd\0" "vaddph\0" "vaddps\0" "vaddsd\0" "vaddsh\0" "vaddss\0" "vaddsubpd\0" - "vaddsubps\0" "vaesdec\0" "vaesdeclast\0" "vaesenc\0" "vaesenclast\0" "vaesimc\0" "vaeskeygenassist\0" "valignd\0" - "valignq\0" "vandnpd\0" "vandnps\0" "vandpd\0" "vandps\0" "vblendmpd\0" "vblendmps\0" "vblendpd\0" "vblendps\0" - "vblendvpd\0" "vblendvps\0" "vbroadcastf128\0" "vbroadcastf32x2\0" "vbroadcastf32x4\0" "vbroadcastf32x8\0" - "vbroadcastf64x2\0" "vbroadcastf64x4\0" "vbroadcasti128\0" "vbroadcasti32x2\0" "vbroadcasti32x4\0" - "vbroadcasti32x8\0" "vbroadcasti64x2\0" "vbroadcasti64x4\0" "vbroadcastsd\0" "vbroadcastss\0" "vcmppd\0" "vcmpph\0" - "vcmpps\0" "vcmpsd\0" "vcmpsh\0" "vcmpss\0" "vcomisd\0" "vcomish\0" "vcomiss\0" "vcompresspd\0" "vcompressps\0" - "vcvtdq2pd\0" "vcvtdq2ph\0" "vcvtdq2ps\0" "vcvtne2ps2bf16\0" "vcvtneps2bf16\0" "vcvtpd2dq\0" "vcvtpd2ph\0" - "vcvtpd2ps\0" "vcvtpd2qq\0" "vcvtpd2udq\0" "vcvtpd2uqq\0" "vcvtph2dq\0" "vcvtph2pd\0" "vcvtph2ps\0" "vcvtph2psx\0" - "vcvtph2qq\0" "vcvtph2udq\0" "vcvtph2uqq\0" "vcvtph2uw\0" "vcvtph2w\0" "vcvtps2dq\0" "vcvtps2pd\0" "vcvtps2ph\0" - "vcvtps2phx\0" "vcvtps2qq\0" "vcvtps2udq\0" "vcvtps2uqq\0" "vcvtqq2pd\0" "vcvtqq2ph\0" "vcvtqq2ps\0" "vcvtsd2sh\0" - "vcvtsd2si\0" "vcvtsd2ss\0" "vcvtsd2usi\0" "vcvtsh2sd\0" "vcvtsh2si\0" "vcvtsh2ss\0" "vcvtsh2usi\0" "vcvtsi2sd\0" - "vcvtsi2sh\0" "vcvtsi2ss\0" "vcvtss2sd\0" "vcvtss2sh\0" "vcvtss2si\0" "vcvtss2usi\0" "vcvttpd2dq\0" "vcvttpd2qq\0" - "vcvttpd2udq\0" "vcvttpd2uqq\0" "vcvttph2dq\0" "vcvttph2qq\0" "vcvttph2udq\0" "vcvttph2uqq\0" "vcvttph2uw\0" - "vcvttph2w\0" "vcvttps2dq\0" "vcvttps2qq\0" "vcvttps2udq\0" "vcvttps2uqq\0" "vcvttsd2si\0" "vcvttsd2usi\0" - "vcvttsh2si\0" "vcvttsh2usi\0" "vcvttss2si\0" "vcvttss2usi\0" "vcvtudq2pd\0" "vcvtudq2ph\0" "vcvtudq2ps\0" - "vcvtuqq2pd\0" "vcvtuqq2ph\0" "vcvtuqq2ps\0" "vcvtusi2sd\0" "vcvtusi2sh\0" "vcvtusi2ss\0" "vcvtuw2ph\0" "vcvtw2ph\0" - "vdbpsadbw\0" "vdivpd\0" "vdivph\0" "vdivps\0" "vdivsd\0" "vdivsh\0" "vdivss\0" "vdpbf16ps\0" "vdppd\0" "vdpps\0" - "verr\0" "verw\0" "vexp2pd\0" "vexp2ps\0" "vexpandpd\0" "vexpandps\0" "vextractf128\0" "vextractf32x4\0" - "vextractf32x8\0" "vextractf64x2\0" "vextractf64x4\0" "vextracti128\0" "vextracti32x4\0" "vextracti32x8\0" - "vextracti64x2\0" "vextracti64x4\0" "vextractps\0" "vfcmaddcph\0" "vfcmaddcsh\0" "vfcmulcph\0" "vfcmulcsh\0" - "vfixupimmpd\0" "vfixupimmps\0" "vfixupimmsd\0" "vfixupimmss\0" "vfmadd132pd\0" "vfmadd132ph\0" "vfmadd132ps\0" - "vfmadd132sd\0" "vfmadd132sh\0" "vfmadd132ss\0" "vfmadd213pd\0" "vfmadd213ph\0" "vfmadd213ps\0" "vfmadd213sd\0" - "vfmadd213sh\0" "vfmadd213ss\0" "vfmadd231pd\0" "vfmadd231ph\0" "vfmadd231ps\0" "vfmadd231sd\0" "vfmadd231sh\0" - "vfmadd231ss\0" "vfmaddcph\0" "vfmaddcsh\0" "vfmaddpd\0" "vfmaddps\0" "vfmaddsd\0" "vfmaddss\0" "vfmaddsub132pd\0" - "vfmaddsub132ph\0" "vfmaddsub132ps\0" "vfmaddsub213pd\0" "vfmaddsub213ph\0" "vfmaddsub213ps\0" "vfmaddsub231pd\0" - "vfmaddsub231ph\0" "vfmaddsub231ps\0" "vfmaddsubpd\0" "vfmaddsubps\0" "vfmsub132pd\0" "vfmsub132ph\0" "vfmsub132ps\0" - "vfmsub132sd\0" "vfmsub132sh\0" "vfmsub132ss\0" "vfmsub213pd\0" "vfmsub213ph\0" "vfmsub213ps\0" "vfmsub213sd\0" - "vfmsub213sh\0" "vfmsub213ss\0" "vfmsub231pd\0" "vfmsub231ph\0" "vfmsub231ps\0" "vfmsub231sd\0" "vfmsub231sh\0" - "vfmsub231ss\0" "vfmsubadd132pd\0" "vfmsubadd132ph\0" "vfmsubadd132ps\0" "vfmsubadd213pd\0" "vfmsubadd213ph\0" - "vfmsubadd213ps\0" "vfmsubadd231pd\0" "vfmsubadd231ph\0" "vfmsubadd231ps\0" "vfmsubaddpd\0" "vfmsubaddps\0" - "vfmsubpd\0" "vfmsubps\0" "vfmsubsd\0" "vfmsubss\0" "vfmulcph\0" "vfmulcsh\0" "vfnmadd132pd\0" "vfnmadd132ph\0" - "vfnmadd132ps\0" "vfnmadd132sd\0" "vfnmadd132sh\0" "vfnmadd132ss\0" "vfnmadd213pd\0" "vfnmadd213ph\0" - "vfnmadd213ps\0" "vfnmadd213sd\0" "vfnmadd213sh\0" "vfnmadd213ss\0" "vfnmadd231pd\0" "vfnmadd231ph\0" - "vfnmadd231ps\0" "vfnmadd231sd\0" "vfnmadd231sh\0" "vfnmadd231ss\0" "vfnmaddpd\0" "vfnmaddps\0" "vfnmaddsd\0" - "vfnmaddss\0" "vfnmsub132pd\0" "vfnmsub132ph\0" "vfnmsub132ps\0" "vfnmsub132sd\0" "vfnmsub132sh\0" "vfnmsub132ss\0" - "vfnmsub213pd\0" "vfnmsub213ph\0" "vfnmsub213ps\0" "vfnmsub213sd\0" "vfnmsub213sh\0" "vfnmsub213ss\0" - "vfnmsub231pd\0" "vfnmsub231ph\0" "vfnmsub231ps\0" "vfnmsub231sd\0" "vfnmsub231sh\0" "vfnmsub231ss\0" "vfnmsubpd\0" - "vfnmsubps\0" "vfnmsubsd\0" "vfnmsubss\0" "vfpclasspd\0" "vfpclassph\0" "vfpclassps\0" "vfpclasssd\0" "vfpclasssh\0" - "vfpclassss\0" "vfrczpd\0" "vfrczps\0" "vfrczsd\0" "vfrczss\0" "vgatherdpd\0" "vgatherdps\0" "vgatherpf0dpd\0" - "vgatherpf0dps\0" "vgatherpf0qpd\0" "vgatherpf0qps\0" "vgatherpf1dpd\0" "vgatherpf1dps\0" "vgatherpf1qpd\0" - "vgatherpf1qps\0" "vgatherqpd\0" "vgatherqps\0" "vgetexppd\0" "vgetexpph\0" "vgetexpps\0" "vgetexpsd\0" "vgetexpsh\0" - "vgetexpss\0" "vgetmantpd\0" "vgetmantph\0" "vgetmantps\0" "vgetmantsd\0" "vgetmantsh\0" "vgetmantss\0" - "vgf2p8affineinvqb\0" "vgf2p8affineqb\0" "vgf2p8mulb\0" "vhaddpd\0" "vhaddps\0" "vhsubpd\0" "vhsubps\0" - "vinsertf128\0" "vinsertf32x4\0" "vinsertf32x8\0" "vinsertf64x2\0" "vinsertf64x4\0" "vinserti128\0" "vinserti32x4\0" - "vinserti32x8\0" "vinserti64x2\0" "vinserti64x4\0" "vinsertps\0" "vlddqu\0" "vldmxcsr\0" "vmaskmovdqu\0" - "vmaskmovpd\0" "vmaskmovps\0" "vmaxpd\0" "vmaxph\0" "vmaxps\0" "vmaxsd\0" "vmaxsh\0" "vmaxss\0" "vmcall\0" - "vmclear\0" "vmfunc\0" "vminpd\0" "vminph\0" "vminps\0" "vminsd\0" "vminsh\0" "vminss\0" "vmlaunch\0" "vmload\0" - "vmmcall\0" "vmovapd\0" "vmovaps\0" "vmovd\0" "vmovddup\0" "vmovdqa\0" "vmovdqa32\0" "vmovdqa64\0" "vmovdqu\0" - "vmovdqu16\0" "vmovdqu32\0" "vmovdqu64\0" "vmovdqu8\0" "vmovhlps\0" "vmovhpd\0" "vmovhps\0" "vmovlhps\0" "vmovlpd\0" - "vmovlps\0" "vmovmskpd\0" "vmovmskps\0" "vmovntdq\0" "vmovntdqa\0" "vmovntpd\0" "vmovntps\0" "vmovq\0" "vmovsd\0" - "vmovsh\0" "vmovshdup\0" "vmovsldup\0" "vmovss\0" "vmovupd\0" "vmovups\0" "vmovw\0" "vmpsadbw\0" "vmptrld\0" - "vmptrst\0" "vmread\0" "vmresume\0" "vmrun\0" "vmsave\0" "vmulpd\0" "vmulph\0" "vmulps\0" "vmulsd\0" "vmulsh\0" - "vmulss\0" "vmwrite\0" "vmxon\0" "vorpd\0" "vorps\0" "vp2intersectd\0" "vp2intersectq\0" "vp4dpwssd\0" "vp4dpwssds\0" - "vpabsb\0" "vpabsd\0" "vpabsq\0" "vpabsw\0" "vpackssdw\0" "vpacksswb\0" "vpackusdw\0" "vpackuswb\0" "vpaddb\0" - "vpaddd\0" "vpaddq\0" "vpaddsb\0" "vpaddsw\0" "vpaddusb\0" "vpaddusw\0" "vpaddw\0" "vpalignr\0" "vpand\0" "vpandd\0" - "vpandn\0" "vpandnd\0" "vpandnq\0" "vpandq\0" "vpavgb\0" "vpavgw\0" "vpblendd\0" "vpblendmb\0" "vpblendmd\0" - "vpblendmq\0" "vpblendmw\0" "vpblendvb\0" "vpblendw\0" "vpbroadcastb\0" "vpbroadcastd\0" "vpbroadcastmb2q\0" - "vpbroadcastmw2d\0" "vpbroadcastq\0" "vpbroadcastw\0" "vpclmulqdq\0" "vpcmov\0" "vpcmpb\0" "vpcmpd\0" "vpcmpeqb\0" - "vpcmpeqd\0" "vpcmpeqq\0" "vpcmpeqw\0" "vpcmpestri\0" "vpcmpestrm\0" "vpcmpgtb\0" "vpcmpgtd\0" "vpcmpgtq\0" - "vpcmpgtw\0" "vpcmpistri\0" "vpcmpistrm\0" "vpcmpq\0" "vpcmpub\0" "vpcmpud\0" "vpcmpuq\0" "vpcmpuw\0" "vpcmpw\0" - "vpcomb\0" "vpcomd\0" "vpcompressb\0" "vpcompressd\0" "vpcompressq\0" "vpcompressw\0" "vpcomq\0" "vpcomub\0" - "vpcomud\0" "vpcomuq\0" "vpcomuw\0" "vpcomw\0" "vpconflictd\0" "vpconflictq\0" "vpdpbusd\0" "vpdpbusds\0" - "vpdpwssd\0" "vpdpwssds\0" "vperm2f128\0" "vperm2i128\0" "vpermb\0" "vpermd\0" "vpermi2b\0" "vpermi2d\0" - "vpermi2pd\0" "vpermi2ps\0" "vpermi2q\0" "vpermi2w\0" "vpermil2pd\0" "vpermil2ps\0" "vpermilpd\0" "vpermilps\0" - "vpermpd\0" "vpermps\0" "vpermq\0" "vpermt2b\0" "vpermt2d\0" "vpermt2pd\0" "vpermt2ps\0" "vpermt2q\0" "vpermt2w\0" - "vpermw\0" "vpexpandb\0" "vpexpandd\0" "vpexpandq\0" "vpexpandw\0" "vpextrb\0" "vpextrd\0" "vpextrq\0" "vpextrw\0" - "vpgatherdd\0" "vpgatherdq\0" "vpgatherqd\0" "vpgatherqq\0" "vphaddbd\0" "vphaddbq\0" "vphaddbw\0" "vphaddd\0" - "vphadddq\0" "vphaddsw\0" "vphaddubd\0" "vphaddubq\0" "vphaddubw\0" "vphaddudq\0" "vphadduwd\0" "vphadduwq\0" - "vphaddw\0" "vphaddwd\0" "vphaddwq\0" "vphminposuw\0" "vphsubbw\0" "vphsubd\0" "vphsubdq\0" "vphsubsw\0" "vphsubw\0" - "vphsubwd\0" "vpinsrb\0" "vpinsrd\0" "vpinsrq\0" "vpinsrw\0" "vplzcntd\0" "vplzcntq\0" "vpmacsdd\0" "vpmacsdqh\0" - "vpmacsdql\0" "vpmacssdd\0" "vpmacssdqh\0" "vpmacssdql\0" "vpmacsswd\0" "vpmacssww\0" "vpmacswd\0" "vpmacsww\0" - "vpmadcsswd\0" "vpmadcswd\0" "vpmadd52huq\0" "vpmadd52luq\0" "vpmaddubsw\0" "vpmaddwd\0" "vpmaskmovd\0" - "vpmaskmovq\0" "vpmaxsb\0" "vpmaxsd\0" "vpmaxsq\0" "vpmaxsw\0" "vpmaxub\0" "vpmaxud\0" "vpmaxuq\0" "vpmaxuw\0" - "vpminsb\0" "vpminsd\0" "vpminsq\0" "vpminsw\0" "vpminub\0" "vpminud\0" "vpminuq\0" "vpminuw\0" "vpmovb2m\0" - "vpmovd2m\0" "vpmovdb\0" "vpmovdw\0" "vpmovm2b\0" "vpmovm2d\0" "vpmovm2q\0" "vpmovm2w\0" "vpmovmskb\0" "vpmovq2m\0" - "vpmovqb\0" "vpmovqd\0" "vpmovqw\0" "vpmovsdb\0" "vpmovsdw\0" "vpmovsqb\0" "vpmovsqd\0" "vpmovsqw\0" "vpmovswb\0" - "vpmovsxbd\0" "vpmovsxbq\0" "vpmovsxbw\0" "vpmovsxdq\0" "vpmovsxwd\0" "vpmovsxwq\0" "vpmovusdb\0" "vpmovusdw\0" - "vpmovusqb\0" "vpmovusqd\0" "vpmovusqw\0" "vpmovuswb\0" "vpmovw2m\0" "vpmovwb\0" "vpmovzxbd\0" "vpmovzxbq\0" - "vpmovzxbw\0" "vpmovzxdq\0" "vpmovzxwd\0" "vpmovzxwq\0" "vpmuldq\0" "vpmulhrsw\0" "vpmulhuw\0" "vpmulhw\0" - "vpmulld\0" "vpmullq\0" "vpmullw\0" "vpmultishiftqb\0" "vpmuludq\0" "vpopcntb\0" "vpopcntd\0" "vpopcntq\0" - "vpopcntw\0" "vpor\0" "vpord\0" "vporq\0" "vpperm\0" "vprold\0" "vprolq\0" "vprolvd\0" "vprolvq\0" "vprord\0" - "vprorq\0" "vprorvd\0" "vprorvq\0" "vprotb\0" "vprotd\0" "vprotq\0" "vprotw\0" "vpsadbw\0" "vpscatterdd\0" - "vpscatterdq\0" "vpscatterqd\0" "vpscatterqq\0" "vpshab\0" "vpshad\0" "vpshaq\0" "vpshaw\0" "vpshlb\0" "vpshld\0" - "vpshldd\0" "vpshldq\0" "vpshldvd\0" "vpshldvq\0" "vpshldvw\0" "vpshldw\0" "vpshlq\0" "vpshlw\0" "vpshrdd\0" - "vpshrdq\0" "vpshrdvd\0" "vpshrdvq\0" "vpshrdvw\0" "vpshrdw\0" "vpshufb\0" "vpshufbitqmb\0" "vpshufd\0" "vpshufhw\0" - "vpshuflw\0" "vpsignb\0" "vpsignd\0" "vpsignw\0" "vpslld\0" "vpslldq\0" "vpsllq\0" "vpsllvd\0" "vpsllvq\0" - "vpsllvw\0" "vpsllw\0" "vpsrad\0" "vpsraq\0" "vpsravd\0" "vpsravq\0" "vpsravw\0" "vpsraw\0" "vpsrld\0" "vpsrldq\0" - "vpsrlq\0" "vpsrlvd\0" "vpsrlvq\0" "vpsrlvw\0" "vpsrlw\0" "vpsubb\0" "vpsubd\0" "vpsubq\0" "vpsubsb\0" "vpsubsw\0" - "vpsubusb\0" "vpsubusw\0" "vpsubw\0" "vpternlogd\0" "vpternlogq\0" "vptest\0" "vptestmb\0" "vptestmd\0" "vptestmq\0" - "vptestmw\0" "vptestnmb\0" "vptestnmd\0" "vptestnmq\0" "vptestnmw\0" "vpunpckhbw\0" "vpunpckhdq\0" "vpunpckhqdq\0" - "vpunpckhwd\0" "vpunpcklbw\0" "vpunpckldq\0" "vpunpcklqdq\0" "vpunpcklwd\0" "vpxor\0" "vpxord\0" "vpxorq\0" - "vrangepd\0" "vrangeps\0" "vrangesd\0" "vrangess\0" "vrcp14pd\0" "vrcp14ps\0" "vrcp14sd\0" "vrcp14ss\0" "vrcp28pd\0" - "vrcp28ps\0" "vrcp28sd\0" "vrcp28ss\0" "vrcpph\0" "vrcpps\0" "vrcpsh\0" "vrcpss\0" "vreducepd\0" "vreduceph\0" - "vreduceps\0" "vreducesd\0" "vreducesh\0" "vreducess\0" "vrndscalepd\0" "vrndscaleph\0" "vrndscaleps\0" - "vrndscalesd\0" "vrndscalesh\0" "vrndscaless\0" "vroundpd\0" "vroundps\0" "vroundsd\0" "vroundss\0" "vrsqrt14pd\0" - "vrsqrt14ps\0" "vrsqrt14sd\0" "vrsqrt14ss\0" "vrsqrt28pd\0" "vrsqrt28ps\0" "vrsqrt28sd\0" "vrsqrt28ss\0" "vrsqrtph\0" - "vrsqrtps\0" "vrsqrtsh\0" "vrsqrtss\0" "vscalefpd\0" "vscalefph\0" "vscalefps\0" "vscalefsd\0" "vscalefsh\0" - "vscalefss\0" "vscatterdpd\0" "vscatterdps\0" "vscatterpf0dpd\0" "vscatterpf0dps\0" "vscatterpf0qpd\0" - "vscatterpf0qps\0" "vscatterpf1dpd\0" "vscatterpf1dps\0" "vscatterpf1qpd\0" "vscatterpf1qps\0" "vscatterqpd\0" - "vscatterqps\0" "vshuff32x4\0" "vshuff64x2\0" "vshufi32x4\0" "vshufi64x2\0" "vshufpd\0" "vshufps\0" "vsqrtpd\0" - "vsqrtph\0" "vsqrtps\0" "vsqrtsd\0" "vsqrtsh\0" "vsqrtss\0" "vstmxcsr\0" "vsubpd\0" "vsubph\0" "vsubps\0" "vsubsd\0" - "vsubsh\0" "vsubss\0" "vtestpd\0" "vtestps\0" "vucomisd\0" "vucomish\0" "vucomiss\0" "vunpckhpd\0" "vunpckhps\0" - "vunpcklpd\0" "vunpcklps\0" "vxorpd\0" "vxorps\0" "vzeroall\0" "vzeroupper\0" "wbinvd\0" "wbnoinvd\0" "wrfsbase\0" - "wrgsbase\0" "wrmsr\0" "wrssd\0" "wrssq\0" "wrussd\0" "wrussq\0" "xabort\0" "xadd\0" "xbegin\0" "xend\0" "xgetbv\0" - "xlatb\0" "xresldtrk\0" "xrstors\0" "xrstors64\0" "xsavec\0" "xsavec64\0" "xsaveopt\0" "xsaveopt64\0" "xsaves\0" - "xsaves64\0" "xsetbv\0" "xsusldtrk\0" "xtest"; +const uint32_t InstDB::_instNameIndexTable[] = { + 0x80000000, // Small ''. + 0x80000421, // Small 'aaa'. + 0x80001021, // Small 'aad'. + 0x80003421, // Small 'aam'. + 0x80004C21, // Small 'aas'. + 0x80000C81, // Small 'adc'. + 0x800C0C81, // Small 'adcx'. + 0x80001081, // Small 'add'. + 0x80481081, // Small 'addpd'. + 0x81381081, // Small 'addps'. + 0x80499081, // Small 'addsd'. + 0x81399081, // Small 'addss'. + 0x20876079, // Large 'addsub|pd'. + 0x20706079, // Large 'addsub|ps'. + 0x800C3C81, // Small 'adox'. + 0x86524CA1, // Small 'aesdec'. + 0x3028718D, // Large 'aesdecl|ast'. + 0x86E2CCA1, // Small 'aesenc'. + 0x30287195, // Large 'aesencl|ast'. + 0x86D4CCA1, // Small 'aesimc'. + 0x0000F012, // Large 'aeskeygenassist'. + 0x800011C1, // Small 'and'. + 0x800711C1, // Small 'andn'. + 0x890711C1, // Small 'andnpd'. + 0xA70711C1, // Small 'andnps'. + 0x804811C1, // Small 'andpd'. + 0x813811C1, // Small 'andps'. + 0x80064241, // Small 'arpl'. + 0x812A60A2, // Small 'bextr'. + 0x261B5630, // Large 'blcfi|ll'. + 0x80048D82, // Small 'blci'. + 0x80348D82, // Small 'blcic'. + 0x97368D82, // Small 'blcmsk'. + 0x80098D82, // Small 'blcs'. + 0x208753E4, // Large 'blend|pd'. + 0x207053E4, // Large 'blend|ps'. + 0x33EA53E4, // Large 'blend|vpd'. + 0x315053E4, // Large 'blend|vps'. + 0x261B5635, // Large 'blsfi|ll'. + 0x8004CD82, // Small 'blsi'. + 0x8034CD82, // Small 'blsic'. + 0x9736CD82, // Small 'blsmsk'. + 0x80094D82, // Small 'blsr'. + 0x80C191C2, // Small 'bndcl'. + 0x80E191C2, // Small 'bndcn'. + 0x815191C2, // Small 'bndcu'. + 0xB04611C2, // Small 'bndldx'. + 0x80B691C2, // Small 'bndmk'. + 0xACF691C2, // Small 'bndmov'. + 0xB14991C2, // Small 'bndstx'. + 0x804755E2, // Small 'bound'. + 0x80001A62, // Small 'bsf'. + 0x80004A62, // Small 'bsr'. + 0x8100DE62, // Small 'bswap'. + 0x80000282, // Small 'bt'. + 0x80000E82, // Small 'btc'. + 0x80004A82, // Small 'btr'. + 0x80004E82, // Small 'bts'. + 0x8004A342, // Small 'bzhi'. + 0x80063023, // Small 'call'. + 0x80005C43, // Small 'cbw'. + 0x80004483, // Small 'cdq'. + 0x8002C483, // Small 'cdqe'. + 0x80018583, // Small 'clac'. + 0x80000D83, // Small 'clc'. + 0x80001183, // Small 'cld'. + 0x20BF6503, // Large 'cldemo|te'. + 0x0000724D, // Large 'clflush'. + 0x1020924D, // Large 'clflushop|t'. + 0x80049D83, // Small 'clgi'. + 0x80002583, // Small 'cli'. + 0x10177509, // Large 'clrssbs|y'. + 0x8009D183, // Small 'clts'. + 0x8004D583, // Small 'clui'. + 0x80015D83, // Small 'clwb'. + 0x9F22E983, // Small 'clzero'. + 0x80000DA3, // Small 'cmc'. + 0x801B3DA3, // Small 'cmova'. + 0x8A1B3DA3, // Small 'cmovae'. + 0x802B3DA3, // Small 'cmovb'. + 0x8A2B3DA3, // Small 'cmovbe'. + 0x803B3DA3, // Small 'cmovc'. + 0x805B3DA3, // Small 'cmove'. + 0x807B3DA3, // Small 'cmovg'. + 0x8A7B3DA3, // Small 'cmovge'. + 0x80CB3DA3, // Small 'cmovl'. + 0x8ACB3DA3, // Small 'cmovle'. + 0x82EB3DA3, // Small 'cmovna'. + 0x20125516, // Large 'cmovn|ae'. + 0x84EB3DA3, // Small 'cmovnb'. + 0x100B6516, // Large 'cmovnb|e'. + 0x86EB3DA3, // Small 'cmovnc'. + 0x8AEB3DA3, // Small 'cmovne'. + 0x8EEB3DA3, // Small 'cmovng'. + 0x20185516, // Large 'cmovn|ge'. + 0x98EB3DA3, // Small 'cmovnl'. + 0x217C5516, // Large 'cmovn|le'. + 0x9EEB3DA3, // Small 'cmovno'. + 0xA0EB3DA3, // Small 'cmovnp'. + 0xA6EB3DA3, // Small 'cmovns'. + 0xB4EB3DA3, // Small 'cmovnz'. + 0x80FB3DA3, // Small 'cmovo'. + 0x810B3DA3, // Small 'cmovp'. + 0x8B0B3DA3, // Small 'cmovpe'. + 0x9F0B3DA3, // Small 'cmovpo'. + 0x813B3DA3, // Small 'cmovs'. + 0x81AB3DA3, // Small 'cmovz'. + 0x800041A3, // Small 'cmp'. + 0x804841A3, // Small 'cmppd'. + 0x813841A3, // Small 'cmpps'. + 0x8009C1A3, // Small 'cmps'. + 0x8049C1A3, // Small 'cmpsd'. + 0x8139C1A3, // Small 'cmpss'. + 0x00007256, // Large 'cmpxchg'. + 0x10109256, // Large 'cmpxchg16|b'. + 0x23837256, // Large 'cmpxchg|8b'. + 0x8934B5E3, // Small 'comisd'. + 0xA734B5E3, // Small 'comiss'. + 0x8044D603, // Small 'cpuid'. + 0x80003E23, // Small 'cqo'. + 0x81DF0E43, // Small 'crc32'. + 0x208763EE, // Large 'cvtdq2|pd'. + 0x207063EE, // Large 'cvtdq2|ps'. + 0x20C5627F, // Large 'cvtpd2|dq'. + 0x21E2627F, // Large 'cvtpd2|pi'. + 0x2070627F, // Large 'cvtpd2|ps'. + 0x34875510, // Large 'cvtpi|2pd'. + 0x306F5510, // Large 'cvtpi|2ps'. + 0x20C56293, // Large 'cvtps2|dq'. + 0x10267293, // Large 'cvtps2p|d'. + 0x10097293, // Large 'cvtps2p|i'. + 0x201D629C, // Large 'cvtsd2|si'. + 0x201C629C, // Large 'cvtsd2|ss'. + 0x210E63FE, // Large 'cvtsi2|sd'. + 0x201C63FE, // Large 'cvtsi2|ss'. + 0x210E62AC, // Large 'cvtss2|sd'. + 0x201D62AC, // Large 'cvtss2|si'. + 0x20C571A6, // Large 'cvttpd2|dq'. + 0x21E271A6, // Large 'cvttpd2|pi'. + 0x20C571BA, // Large 'cvttps2|dq'. + 0x21E271BA, // Large 'cvttps2|pi'. + 0x201D71C3, // Large 'cvttsd2|si'. + 0x201D71D5, // Large 'cvttss2|si'. + 0x800012E3, // Small 'cwd'. + 0x800292E3, // Small 'cwde'. + 0x80000424, // Small 'daa'. + 0x80004C24, // Small 'das'. + 0x80000CA4, // Small 'dec'. + 0x80005924, // Small 'div'. + 0x80485924, // Small 'divpd'. + 0x81385924, // Small 'divps'. + 0x8049D924, // Small 'divsd'. + 0x8139D924, // Small 'divss'. + 0x80024204, // Small 'dppd'. + 0x8009C204, // Small 'dpps'. + 0x8009B5A5, // Small 'emms'. + 0x202C563A, // Large 'endbr|32'. + 0x2030563A, // Large 'endbr|64'. + 0x88D1C5C5, // Small 'enqcmd'. + 0x207B563F, // Large 'enqcm|ds'. + 0x8122D1C5, // Small 'enter'. + 0x207070F0, // Large 'extract|ps'. + 0x81195305, // Small 'extrq'. + 0x81C6E3A6, // Small 'f2xm1'. + 0x80098826, // Small 'fabs'. + 0x80021026, // Small 'fadd'. + 0x81021026, // Small 'faddp'. + 0x80023046, // Small 'fbld'. + 0x810A4C46, // Small 'fbstp'. + 0x8009A066, // Small 'fchs'. + 0x8182B066, // Small 'fclex'. + 0x8567B466, // Small 'fcmovb'. + 0x26445515, // Large 'fcmov|be'. + 0x8B67B466, // Small 'fcmove'. + 0x00007515, // Large 'fcmovnb'. + 0x100B7515, // Large 'fcmovnb|e'. + 0x100B6515, // Large 'fcmovn|e'. + 0x107D6515, // Large 'fcmovn|u'. + 0xAB67B466, // Small 'fcmovu'. + 0x8006BC66, // Small 'fcom'. + 0x8096BC66, // Small 'fcomi'. + 0xA096BC66, // Small 'fcomip'. + 0x8106BC66, // Small 'fcomp'. + 0xA106BC66, // Small 'fcompp'. + 0x8009BC66, // Small 'fcos'. + 0x21A95646, // Large 'fdecs|tp'. + 0x800B2486, // Small 'fdiv'. + 0x810B2486, // Small 'fdivp'. + 0x812B2486, // Small 'fdivr'. + 0xA12B2486, // Small 'fdivrp'. + 0x8136B4A6, // Small 'femms'. + 0x8052C8C6, // Small 'ffree'. + 0x80420526, // Small 'fiadd'. + 0x80D78D26, // Small 'ficom'. + 0xA0D78D26, // Small 'ficomp'. + 0x81649126, // Small 'fidiv'. + 0xA5649126, // Small 'fidivr'. + 0x80023126, // Small 'fild'. + 0x80CAB526, // Small 'fimul'. + 0x21A9564B, // Large 'fincs|tp'. + 0x8144B926, // Small 'finit'. + 0x800A4D26, // Small 'fist'. + 0x810A4D26, // Small 'fistp'. + 0xA14A4D26, // Small 'fisttp'. + 0x802ACD26, // Small 'fisub'. + 0xA42ACD26, // Small 'fisubr'. + 0x80001186, // Small 'fld'. + 0x800E1186, // Small 'fld1'. + 0x81719186, // Small 'fldcw'. + 0xACE29186, // Small 'fldenv'. + 0x8BD61186, // Small 'fldl2e'. + 0xA9D61186, // Small 'fldl2t'. + 0xBA761186, // Small 'fldlg2'. + 0xBAE61186, // Small 'fldln2'. + 0x80981186, // Small 'fldpi'. + 0x800D1186, // Small 'fldz'. + 0x800655A6, // Small 'fmul'. + 0x810655A6, // Small 'fmulp'. + 0xB0560DC6, // Small 'fnclex'. + 0xA89725C6, // Small 'fninit'. + 0x80083DC6, // Small 'fnop'. + 0x8B60CDC6, // Small 'fnsave'. + 0xAE3A4DC6, // Small 'fnstcw'. + 0x200D5650, // Large 'fnste|nv'. + 0xAF3A4DC6, // Small 'fnstsw'. + 0x9C1A0606, // Small 'fpatan'. + 0x80D2CA06, // Small 'fprem'. + 0xB8D2CA06, // Small 'fprem1'. + 0x80E0D206, // Small 'fptan'. + 0x31054655, // Large 'frnd|int'. + 0xA4FA4E46, // Small 'frstor'. + 0x805B0666, // Small 'fsave'. + 0x8AC08E66, // Small 'fscale'. + 0x80072666, // Small 'fsin'. + 0x221D5659, // Large 'fsinc|os'. + 0x81494666, // Small 'fsqrt'. + 0x80005266, // Small 'fst'. + 0x8171D266, // Small 'fstcw'. + 0xACE2D266, // Small 'fstenv'. + 0x80085266, // Small 'fstp'. + 0x8179D266, // Small 'fstsw'. + 0x80015666, // Small 'fsub'. + 0x81015666, // Small 'fsubp'. + 0x81215666, // Small 'fsubr'. + 0xA1215666, // Small 'fsubrp'. + 0x800A4E86, // Small 'ftst'. + 0x80D78EA6, // Small 'fucom'. + 0x92D78EA6, // Small 'fucomi'. + 0x2543565E, // Large 'fucom|ip'. + 0xA0D78EA6, // Small 'fucomp'. + 0x2663565E, // Large 'fucom|pp'. + 0x814486E6, // Small 'fwait'. + 0x80068706, // Small 'fxam'. + 0x80040F06, // Small 'fxch'. + 0x00007385, // Large 'fxrstor'. + 0x20307385, // Large 'fxrstor|64'. + 0x8B60CF06, // Small 'fxsave'. + 0x2030651C, // Large 'fxsave|64'. + 0x50F22385, // Large 'fx|tract'. + 0x818EB326, // Small 'fyl2x'. + 0x26025665, // Large 'fyl2x|p1'. + 0x8659D0A7, // Small 'getsec'. + 0x1010F001, // Large 'gf2p8affineinvq|b'. + 0x200FB001, // Large 'gf2p8affine|qb'. + 0x42E25001, // Large 'gf2p8|mulb'. + 0x89021028, // Small 'haddpd'. + 0xA7021028, // Small 'haddps'. + 0x80005188, // Small 'hlt'. + 0xA8599648, // Small 'hreset'. + 0x89015668, // Small 'hsubpd'. + 0xA7015668, // Small 'hsubps'. + 0x800B2489, // Small 'idiv'. + 0x800655A9, // Small 'imul'. + 0x800001C9, // Small 'in'. + 0x80000DC9, // Small 'inc'. + 0x2087566A, // Large 'incss|pd'. + 0x266F566A, // Large 'incss|pq'. + 0x80004DC9, // Small 'ins'. + 0x20706149, // Large 'insert|ps'. + 0x100F6149, // Large 'insert|q'. + 0x800051C9, // Small 'int'. + 0x800F51C9, // Small 'int3'. + 0x8007D1C9, // Small 'into'. + 0x800259C9, // Small 'invd'. + 0xA902D9C9, // Small 'invept'. + 0x8F0659C9, // Small 'invlpg'. + 0x33164671, // Large 'invl|pga'. + 0x23A05675, // Large 'invpc|id'. + 0x23A0567A, // Large 'invvp|id'. + 0x800A1649, // Small 'iret'. + 0x804A1649, // Small 'iretd'. + 0x811A1649, // Small 'iretq'. + 0x8000002A, // Small 'ja'. + 0x8000142A, // Small 'jae'. + 0x8000004A, // Small 'jb'. + 0x8000144A, // Small 'jbe'. + 0x8000006A, // Small 'jc'. + 0x800000AA, // Small 'je'. + 0x81AC0CAA, // Small 'jecxz'. + 0x800000EA, // Small 'jg'. + 0x800014EA, // Small 'jge'. + 0x8000018A, // Small 'jl'. + 0x8000158A, // Small 'jle'. + 0x800041AA, // Small 'jmp'. + 0x800005CA, // Small 'jna'. + 0x800285CA, // Small 'jnae'. + 0x800009CA, // Small 'jnb'. + 0x800289CA, // Small 'jnbe'. + 0x80000DCA, // Small 'jnc'. + 0x800015CA, // Small 'jne'. + 0x80001DCA, // Small 'jng'. + 0x80029DCA, // Small 'jnge'. + 0x800031CA, // Small 'jnl'. + 0x8002B1CA, // Small 'jnle'. + 0x80003DCA, // Small 'jno'. + 0x800041CA, // Small 'jnp'. + 0x80004DCA, // Small 'jns'. + 0x800069CA, // Small 'jnz'. + 0x800001EA, // Small 'jo'. + 0x8000020A, // Small 'jp'. + 0x8000160A, // Small 'jpe'. + 0x80003E0A, // Small 'jpo'. + 0x8000026A, // Small 'js'. + 0x8000034A, // Small 'jz'. + 0x8022102B, // Small 'kaddb'. + 0x8042102B, // Small 'kaddd'. + 0x8112102B, // Small 'kaddq'. + 0x8172102B, // Small 'kaddw'. + 0x8022382B, // Small 'kandb'. + 0x8042382B, // Small 'kandd'. + 0x84E2382B, // Small 'kandnb'. + 0x88E2382B, // Small 'kandnd'. + 0xA2E2382B, // Small 'kandnq'. + 0xAEE2382B, // Small 'kandnw'. + 0x8112382B, // Small 'kandq'. + 0x8172382B, // Small 'kandw'. + 0x802B3DAB, // Small 'kmovb'. + 0x804B3DAB, // Small 'kmovd'. + 0x811B3DAB, // Small 'kmovq'. + 0x817B3DAB, // Small 'kmovw'. + 0x802A3DCB, // Small 'knotb'. + 0x804A3DCB, // Small 'knotd'. + 0x811A3DCB, // Small 'knotq'. + 0x817A3DCB, // Small 'knotw'. + 0x800149EB, // Small 'korb'. + 0x800249EB, // Small 'kord'. + 0x8008C9EB, // Small 'korq'. + 0x10107522, // Large 'kortest|b'. + 0x10267522, // Large 'kortest|d'. + 0x100F7522, // Large 'kortest|q'. + 0x105F7522, // Large 'kortest|w'. + 0x800BC9EB, // Small 'korw'. + 0x22E46529, // Large 'kshift|lb'. + 0x234B6529, // Large 'kshift|ld'. + 0x22406529, // Large 'kshift|lq'. + 0x234E6529, // Large 'kshift|lw'. + 0x252F6529, // Large 'kshift|rb'. + 0x10267529, // Large 'kshiftr|d'. + 0x100F7529, // Large 'kshiftr|q'. + 0x105F7529, // Large 'kshiftr|w'. + 0x8549968B, // Small 'ktestb'. + 0x8949968B, // Small 'ktestd'. + 0xA349968B, // Small 'ktestq'. + 0xAF49968B, // Small 'ktestw'. + 0x23446531, // Large 'kunpck|bw'. + 0x20C56531, // Large 'kunpck|dq'. + 0x23466531, // Large 'kunpck|wd'. + 0x8527BB0B, // Small 'kxnorb'. + 0x8927BB0B, // Small 'kxnord'. + 0xA327BB0B, // Small 'kxnorq'. + 0xAF27BB0B, // Small 'kxnorw'. + 0x80293F0B, // Small 'kxorb'. + 0x80493F0B, // Small 'kxord'. + 0x81193F0B, // Small 'kxorq'. + 0x81793F0B, // Small 'kxorw'. + 0x8003202C, // Small 'lahf'. + 0x8000482C, // Small 'lar'. + 0x80C6046C, // Small 'lcall'. + 0x8158908C, // Small 'lddqu'. + 0x1023657B, // Large 'ldmxcs|r'. + 0x80004C8C, // Small 'lds'. + 0x1001838C, // Large 'ldtilecf|g'. + 0x800004AC, // Small 'lea'. + 0x805B04AC, // Small 'leave'. + 0x80004CAC, // Small 'les'. + 0x8A3714CC, // Small 'lfence'. + 0x80004CCC, // Small 'lfs'. + 0x800A10EC, // Small 'lgdt'. + 0x80004CEC, // Small 'lgs'. + 0x800A112C, // Small 'lidt'. + 0x8008354C, // Small 'ljmp'. + 0x800A118C, // Small 'lldt'. + 0x84385D8C, // Small 'llwpcb'. + 0x800BCDAC, // Small 'lmsw'. + 0x800991EC, // Small 'lods'. + 0x80083DEC, // Small 'loop'. + 0x80583DEC, // Small 'loope'. + 0x8AE83DEC, // Small 'loopne'. + 0x8000326C, // Small 'lsl'. + 0x80004E6C, // Small 'lss'. + 0x80004A8C, // Small 'ltr'. + 0xA6E4C2EC, // Small 'lwpins'. + 0x981B42EC, // Small 'lwpval'. + 0x81470F4C, // Small 'lzcnt'. + 0x107D91F9, // Large 'maskmovdq|u'. + 0x100F71F9, // Large 'maskmov|q'. + 0x8048602D, // Small 'maxpd'. + 0x8138602D, // Small 'maxps'. + 0x8049E02D, // Small 'maxsd'. + 0x8139E02D, // Small 'maxss'. + 0x2157567F, // Large 'mcomm|it'. + 0x8A3714CD, // Small 'mfence'. + 0x8048392D, // Small 'minpd'. + 0x8138392D, // Small 'minps'. + 0x8049B92D, // Small 'minsd'. + 0x8139B92D, // Small 'minss'. + 0x00007537, // Large 'monitor'. + 0x102E7537, // Large 'monitor|x'. + 0x800059ED, // Small 'mov'. + 0xA620D9ED, // Small 'movabs'. + 0x8900D9ED, // Small 'movapd'. + 0xA700D9ED, // Small 'movaps'. + 0x805159ED, // Small 'movbe'. + 0x800259ED, // Small 'movd'. + 0x358741FD, // Large 'movd|dup'. + 0x10108394, // Large 'movdir64|b'. + 0x10096394, // Large 'movdir|i'. + 0x25BD51FD, // Large 'movdq|2q'. + 0x831259ED, // Small 'movdqa'. + 0xAB1259ED, // Small 'movdqu'. + 0x34ED458D, // Large 'movh|lps'. + 0x890459ED, // Small 'movhpd'. + 0xA70459ED, // Small 'movhps'. + 0x20705592, // Large 'movlh|ps'. + 0x890659ED, // Small 'movlpd'. + 0xA70659ED, // Small 'movlps'. + 0x20876443, // Large 'movmsk|pd'. + 0x20706443, // Large 'movmsk|ps'. + 0x20C5544A, // Large 'movnt|dq'. + 0x3436544A, // Large 'movnt|dqa'. + 0x934759ED, // Small 'movnti'. + 0x2087544A, // Large 'movnt|pd'. + 0x2070544A, // Large 'movnt|ps'. + 0xA34759ED, // Small 'movntq'. + 0x210E544A, // Large 'movnt|sd'. + 0x201C544A, // Large 'movnt|ss'. + 0x8008D9ED, // Small 'movq'. + 0x20C55684, // Large 'movq2|dq'. + 0x8009D9ED, // Small 'movs'. + 0x8049D9ED, // Small 'movsd'. + 0x21E16450, // Large 'movshd|up'. + 0x21E16457, // Large 'movsld|up'. + 0x8139D9ED, // Small 'movss'. + 0x8189D9ED, // Small 'movsx'. + 0x8989D9ED, // Small 'movsxd'. + 0x890AD9ED, // Small 'movupd'. + 0xA70AD9ED, // Small 'movups'. + 0x818D59ED, // Small 'movzx'. + 0x23445598, // Large 'mpsad|bw'. + 0x800032AD, // Small 'mul'. + 0x804832AD, // Small 'mulpd'. + 0x813832AD, // Small 'mulps'. + 0x8049B2AD, // Small 'mulsd'. + 0x8139B2AD, // Small 'mulss'. + 0x800C32AD, // Small 'mulx'. + 0x814486ED, // Small 'mwait'. + 0xB14486ED, // Small 'mwaitx'. + 0x80001CAE, // Small 'neg'. + 0x800041EE, // Small 'nop'. + 0x800051EE, // Small 'not'. + 0x8000024F, // Small 'or'. + 0x8002424F, // Small 'orpd'. + 0x8009C24F, // Small 'orps'. + 0x800052AF, // Small 'out'. + 0x8009D2AF, // Small 'outs'. + 0x80298830, // Small 'pabsb'. + 0x80498830, // Small 'pabsd'. + 0x81798830, // Small 'pabsw'. + 0x0000845E, // Large 'packssdw'. + 0x2465645E, // Large 'packss|wb'. + 0x24646468, // Large 'packus|dw'. + 0x00008468, // Large 'packuswb'. + 0x80221030, // Small 'paddb'. + 0x80421030, // Small 'paddd'. + 0x81121030, // Small 'paddq'. + 0x85321030, // Small 'paddsb'. + 0xAF321030, // Small 'paddsw'. + 0x250D55A5, // Large 'paddu|sb'. + 0x232D55A5, // Large 'paddu|sw'. + 0x81721030, // Small 'paddw'. + 0x102365AB, // Large 'palign|r'. + 0x80023830, // Small 'pand'. + 0x80E23830, // Small 'pandn'. + 0x8059D430, // Small 'pause'. + 0x8023D830, // Small 'pavgb'. + 0x250D5689, // Large 'pavgu|sb'. + 0x8173D830, // Small 'pavgw'. + 0x20216471, // Large 'pblend|vb'. + 0x105F6471, // Large 'pblend|w'. + 0x424052EF, // Large 'pclmu|lqdq'. + 0x200F52F5, // Large 'pcmpe|qb'. + 0x223552F5, // Large 'pcmpe|qd'. + 0x21AE52F5, // Large 'pcmpe|qq'. + 0x24BB52F5, // Large 'pcmpe|qw'. + 0x100982F5, // Large 'pcmpestr|i'. + 0x105C82F5, // Large 'pcmpestr|m'. + 0x35B14255, // Large 'pcmp|gtb'. + 0x35B44255, // Large 'pcmp|gtd'. + 0x35B74255, // Large 'pcmp|gtq'. + 0x35BA4255, // Large 'pcmp|gtw'. + 0x100982FE, // Large 'pcmpistr|i'. + 0x105C82FE, // Large 'pcmpistr|m'. + 0x25AE520D, // Large 'pconf|ig'. + 0x80081490, // Small 'pdep'. + 0x800A60B0, // Small 'pext'. + 0x852A60B0, // Small 'pextrb'. + 0x892A60B0, // Small 'pextrd'. + 0xA32A60B0, // Small 'pextrq'. + 0xAF2A60B0, // Small 'pextrw'. + 0x8044F4D0, // Small 'pf2id'. + 0x8174F4D0, // Small 'pf2iw'. + 0x803184D0, // Small 'pfacc'. + 0x804204D0, // Small 'pfadd'. + 0x100F668E, // Large 'pfcmpe|q'. + 0x2018568E, // Large 'pfcmp|ge'. + 0x25B1568E, // Large 'pfcmp|gt'. + 0x8180B4D0, // Small 'pfmax'. + 0x80E4B4D0, // Small 'pfmin'. + 0x80CAB4D0, // Small 'pfmul'. + 0x8630B8D0, // Small 'pfnacc'. + 0x24245694, // Large 'pfpna|cc'. + 0x8101C8D0, // Small 'pfrcp'. + 0x2165653E, // Large 'pfrcpi|t1'. + 0x2261653E, // Large 'pfrcpi|t2'. + 0xAD01C8D0, // Small 'pfrcpv'. + 0x21656544, // Large 'pfrsqi|t1'. + 0x214D5544, // Large 'pfrsq|rt'. + 0x354A5544, // Large 'pfrsq|rtv'. + 0x802ACCD0, // Small 'pfsub'. + 0xA42ACCD0, // Small 'pfsubr'. + 0x88420510, // Small 'phaddd'. + 0x232D5498, // Large 'phadd|sw'. + 0xAE420510, // Small 'phaddw'. + 0x105F9217, // Large 'phminposu|w'. + 0x882ACD10, // Small 'phsubd'. + 0x232D55C4, // Large 'phsub|sw'. + 0xAE2ACD10, // Small 'phsubw'. + 0x80437530, // Small 'pi2fd'. + 0x81737530, // Small 'pi2fw'. + 0x8529B930, // Small 'pinsrb'. + 0x8929B930, // Small 'pinsrd'. + 0xA329B930, // Small 'pinsrq'. + 0xAF29B930, // Small 'pinsrw'. + 0x432F5221, // Large 'pmadd|ubsw'. + 0x23465221, // Large 'pmadd|wd'. + 0x853C05B0, // Small 'pmaxsb'. + 0x893C05B0, // Small 'pmaxsd'. + 0xAF3C05B0, // Small 'pmaxsw'. + 0x855C05B0, // Small 'pmaxub'. + 0x895C05B0, // Small 'pmaxud'. + 0xAF5C05B0, // Small 'pmaxuw'. + 0x853725B0, // Small 'pminsb'. + 0x893725B0, // Small 'pminsd'. + 0xAF3725B0, // Small 'pminsw'. + 0x855725B0, // Small 'pminub'. + 0x895725B0, // Small 'pminud'. + 0xAF5725B0, // Small 'pminuw'. + 0x101074A5, // Large 'pmovmsk|b'. + 0x102674AD, // Large 'pmovsxb|d'. + 0x100F74AD, // Large 'pmovsxb|q'. + 0x105F74AD, // Large 'pmovsxb|w'. + 0x20C564AD, // Large 'pmovsx|dq'. + 0x234664AD, // Large 'pmovsx|wd'. + 0x249F64AD, // Large 'pmovsx|wq'. + 0x102674BE, // Large 'pmovzxb|d'. + 0x100F74BE, // Large 'pmovzxb|q'. + 0x105F74BE, // Large 'pmovzxb|w'. + 0x20C564BE, // Large 'pmovzx|dq'. + 0x234664BE, // Large 'pmovzx|wd'. + 0x249F64BE, // Large 'pmovzx|wq'. + 0xA24655B0, // Small 'pmuldq'. + 0x232D64C6, // Large 'pmulhr|sw'. + 0x105F64C6, // Large 'pmulhr|w'. + 0x23F454C6, // Large 'pmulh|uw'. + 0xAE8655B0, // Small 'pmulhw'. + 0x88C655B0, // Small 'pmulld'. + 0xAEC655B0, // Small 'pmullw'. + 0x328F40AF, // Large 'pmul|udq'. + 0x800041F0, // Small 'pop'. + 0x8000C1F0, // Small 'popa'. + 0x8040C1F0, // Small 'popad'. + 0xA8E1C1F0, // Small 'popcnt'. + 0x800341F0, // Small 'popf'. + 0x804341F0, // Small 'popfd'. + 0x811341F0, // Small 'popfq'. + 0x800049F0, // Small 'por'. + 0x0000815A, // Large 'prefetch'. + 0x1006A15A, // Large 'prefetchnt|a'. + 0x225F815A, // Large 'prefetch|t0'. + 0x2165815A, // Large 'prefetch|t1'. + 0x2261815A, // Large 'prefetch|t2'. + 0x105F815A, // Large 'prefetch|w'. + 0x3164815A, // Large 'prefetch|wt1'. + 0xAE220670, // Small 'psadbw'. + 0x846AA270, // Small 'pshufb'. + 0x886AA270, // Small 'pshufd'. + 0x25F15151, // Large 'pshuf|hw'. + 0x234E5151, // Large 'pshuf|lw'. + 0xAE6AA270, // Small 'pshufw'. + 0x84E3A670, // Small 'psignb'. + 0x88E3A670, // Small 'psignd'. + 0xAEE3A670, // Small 'psignw'. + 0x80463270, // Small 'pslld'. + 0xA2463270, // Small 'pslldq'. + 0x81163270, // Small 'psllq'. + 0x81763270, // Small 'psllw'. + 0x9130B670, // Small 'psmash'. + 0x8040CA70, // Small 'psrad'. + 0x8170CA70, // Small 'psraw'. + 0x80464A70, // Small 'psrld'. + 0xA2464A70, // Small 'psrldq'. + 0x81164A70, // Small 'psrlq'. + 0x81764A70, // Small 'psrlw'. + 0x80215670, // Small 'psubb'. + 0x80415670, // Small 'psubd'. + 0x81115670, // Small 'psubq'. + 0x85315670, // Small 'psubsb'. + 0xAF315670, // Small 'psubsw'. + 0x250D55F4, // Large 'psubu|sb'. + 0x232D55F4, // Large 'psubu|sw'. + 0x81715670, // Small 'psubw'. + 0x8900DE70, // Small 'pswapd'. + 0x81499690, // Small 'ptest'. + 0x20BF5699, // Large 'ptwri|te'. + 0x23447238, // Large 'punpckh|bw'. + 0x20C57238, // Large 'punpckh|dq'. + 0x20C58238, // Large 'punpckhq|dq'. + 0x23467238, // Large 'punpckh|wd'. + 0x33486238, // Large 'punpck|lbw'. + 0x334B6238, // Large 'punpck|ldq'. + 0x42406238, // Large 'punpck|lqdq'. + 0x334E6238, // Large 'punpck|lwd'. + 0x80044EB0, // Small 'push'. + 0x80144EB0, // Small 'pusha'. + 0x88144EB0, // Small 'pushad'. + 0x80644EB0, // Small 'pushf'. + 0x88644EB0, // Small 'pushfd'. + 0xA2644EB0, // Small 'pushfq'. + 0x20BF739C, // Large 'pvalida|te'. + 0x80093F10, // Small 'pxor'. + 0x80003072, // Small 'rcl'. + 0x81384072, // Small 'rcpps'. + 0x8139C072, // Small 'rcpss'. + 0x80004872, // Small 'rcr'. + 0x33B0554D, // Large 'rdfsb|ase'. + 0x33B05552, // Large 'rdgsb|ase'. + 0x8129B492, // Small 'rdmsr'. + 0x8044C092, // Small 'rdpid'. + 0xAB25C092, // Small 'rdpkru'. + 0x8036C092, // Small 'rdpmc'. + 0x81594092, // Small 'rdpru'. + 0x88E0C892, // Small 'rdrand'. + 0x8852CC92, // Small 'rdseed'. + 0x8909CC92, // Small 'rdsspd'. + 0xA309CC92, // Small 'rdsspq'. + 0x8039D092, // Small 'rdtsc'. + 0xA039D092, // Small 'rdtscp'. + 0x800050B2, // Small 'ret'. + 0x800350B2, // Small 'retf'. + 0x201F73A3, // Large 'rmpadju|st'. + 0x20BF73AA, // Large 'rmpupda|te'. + 0x800031F2, // Small 'rol'. + 0x800049F2, // Small 'ror'. + 0x800C49F2, // Small 'rorx'. + 0x20875606, // Large 'round|pd'. + 0x20705606, // Large 'round|ps'. + 0x00007606, // Large 'roundsd'. + 0x10146606, // Large 'rounds|s'. + 0x80003672, // Small 'rsm'. + 0x20705352, // Large 'rsqrt|ps'. + 0x201C5352, // Large 'rsqrt|ss'. + 0x35575387, // Large 'rstor|ssp'. + 0x80032033, // Small 'sahf'. + 0x80003033, // Small 'sal'. + 0x80004833, // Small 'sar'. + 0x800C4833, // Small 'sarx'. + 0x1004A167, // Large 'saveprevss|p'. + 0x80000853, // Small 'sbb'. + 0x80098473, // Small 'scas'. + 0x21E2655A, // Large 'sendui|pi'. + 0x237573B1, // Large 'seriali|ze'. + 0x8000D0B3, // Small 'seta'. + 0x8050D0B3, // Small 'setae'. + 0x800150B3, // Small 'setb'. + 0x805150B3, // Small 'setbe'. + 0x8001D0B3, // Small 'setc'. + 0x8002D0B3, // Small 'sete'. + 0x8003D0B3, // Small 'setg'. + 0x8053D0B3, // Small 'setge'. + 0x800650B3, // Small 'setl'. + 0x805650B3, // Small 'setle'. + 0x801750B3, // Small 'setna'. + 0x8A1750B3, // Small 'setnae'. + 0x802750B3, // Small 'setnb'. + 0x8A2750B3, // Small 'setnbe'. + 0x803750B3, // Small 'setnc'. + 0x805750B3, // Small 'setne'. + 0x807750B3, // Small 'setng'. + 0x8A7750B3, // Small 'setnge'. + 0x80C750B3, // Small 'setnl'. + 0x8AC750B3, // Small 'setnle'. + 0x80F750B3, // Small 'setno'. + 0x810750B3, // Small 'setnp'. + 0x813750B3, // Small 'setns'. + 0x81A750B3, // Small 'setnz'. + 0x8007D0B3, // Small 'seto'. + 0x800850B3, // Small 'setp'. + 0x805850B3, // Small 'setpe'. + 0x80F850B3, // Small 'setpo'. + 0x8009D0B3, // Small 'sets'. + 0x10177560, // Large 'setssbs|y'. + 0x800D50B3, // Small 'setz'. + 0x8A3714D3, // Small 'sfence'. + 0x800A10F3, // Small 'sgdt'. + 0x426343B8, // Large 'sha1|msg1'. + 0x426743B8, // Large 'sha1|msg2'. + 0x20BF73B8, // Large 'sha1nex|te'. + 0x102F83BF, // Large 'sha1rnds|4'. + 0x42636171, // Large 'sha256|msg1'. + 0x42676171, // Large 'sha256|msg2'. + 0x20719171, // Large 'sha256rnd|s2'. + 0x80003113, // Small 'shl'. + 0x80023113, // Small 'shld'. + 0x800C3113, // Small 'shlx'. + 0x80004913, // Small 'shr'. + 0x80024913, // Small 'shrd'. + 0x800C4913, // Small 'shrx'. + 0x89035513, // Small 'shufpd'. + 0xA7035513, // Small 'shufps'. + 0x800A1133, // Small 'sidt'. + 0xA8972573, // Small 'skinit'. + 0x800A1193, // Small 'sldt'. + 0x84385D93, // Small 'slwpcb'. + 0x800BCDB3, // Small 'smsw'. + 0x890A4A33, // Small 'sqrtpd'. + 0xA70A4A33, // Small 'sqrtps'. + 0x893A4A33, // Small 'sqrtsd'. + 0xA73A4A33, // Small 'sqrtss'. + 0x80018693, // Small 'stac'. + 0x80000E93, // Small 'stc'. + 0x80001293, // Small 'std'. + 0x80049E93, // Small 'stgi'. + 0x80002693, // Small 'sti'. + 0x1023660E, // Large 'stmxcs|r'. + 0x8009BE93, // Small 'stos'. + 0x80004A93, // Small 'str'. + 0x100183C7, // Large 'sttilecf|g'. + 0x8004D693, // Small 'stui'. + 0x80000AB3, // Small 'sub'. + 0x80480AB3, // Small 'subpd'. + 0x81380AB3, // Small 'subps'. + 0x80498AB3, // Small 'subsd'. + 0x81398AB3, // Small 'subss'. + 0xA67806F3, // Small 'swapgs'. + 0x361A469E, // Large 'sysc|all'. + 0x41064567, // Large 'syse|nter'. + 0x2157556B, // Large 'sysex|it'. + 0x3157556B, // Large 'sysex|itq'. + 0xA8594F33, // Small 'sysret'. + 0x215856A2, // Large 'sysre|tq'. + 0x86B9B794, // Small 't1mskc'. + 0x207073CF, // Large 'tdpbf16|ps'. + 0x332243CF, // Large 'tdpb|ssd'. + 0x328E43CF, // Large 'tdpb|sud'. + 0x210E56A7, // Large 'tdpbu|sd'. + 0x228F56A7, // Large 'tdpbu|ud'. + 0x800A4CB4, // Small 'test'. + 0x935A4CB4, // Small 'testui'. + 0x0000917A, // Large 'tileloadd'. + 0x2165917A, // Large 'tileloadd|t1'. + 0x210A9183, // Large 'tilerelea|se'. + 0x1026926B, // Large 'tilestore|d'. + 0x4375417A, // Large 'tile|zero'. + 0x8B3A8614, // Small 'tpause'. + 0x81470F54, // Small 'tzcnt'. + 0x80B9B754, // Small 'tzmsk'. + 0x210E5615, // Large 'ucomi|sd'. + 0x201C5615, // Large 'ucomi|ss'. + 0x80006C95, // Small 'ud0'. + 0x80007095, // Small 'ud1'. + 0x80007495, // Small 'ud2'. + 0x8142C935, // Small 'uiret'. + 0x7537107D, // Large 'u|monitor'. + 0xA890DDB5, // Small 'umwait'. + 0x20876239, // Large 'unpckh|pd'. + 0x20706239, // Large 'unpckh|ps'. + 0x34EA5239, // Large 'unpck|lpd'. + 0x34ED5239, // Large 'unpck|lps'. + 0x30D163D6, // Large 'v4fmad|dps'. + 0x327B63D6, // Large 'v4fmad|dss'. + 0x30D17274, // Large 'v4fnmad|dps'. + 0x327B7274, // Large 'v4fnmad|dss'. + 0x89021036, // Small 'vaddpd'. + 0x91021036, // Small 'vaddph'. + 0xA7021036, // Small 'vaddps'. + 0x89321036, // Small 'vaddsd'. + 0x91321036, // Small 'vaddsh'. + 0xA7321036, // Small 'vaddss'. + 0x208773DC, // Large 'vaddsub|pd'. + 0x207073DC, // Large 'vaddsub|ps'. + 0x0000718C, // Large 'vaesdec'. + 0x3028818C, // Large 'vaesdecl|ast'. + 0x00007194, // Large 'vaesenc'. + 0x30288194, // Large 'vaesencl|ast'. + 0x267F56AC, // Large 'vaesi|mc'. + 0x1020F011, // Large 'vaeskeygenassis|t'. + 0x217856B1, // Large 'valig|nd'. + 0x264056B1, // Large 'valig|nq'. + 0x208756B6, // Large 'vandn|pd'. + 0x207056B6, // Large 'vandn|ps'. + 0x89023836, // Small 'vandpd'. + 0xA7023836, // Small 'vandps'. + 0x208773E3, // Large 'vblendm|pd'. + 0x207073E3, // Large 'vblendm|ps'. + 0x208763E3, // Large 'vblend|pd'. + 0x207063E3, // Large 'vblend|ps'. + 0x33EA63E3, // Large 'vblend|vpd'. + 0x315063E3, // Large 'vblend|vps'. + 0x3062B021, // Large 'vbroadcastf|128'. + 0x1003E021, // Large 'vbroadcastf32x|2'. + 0x102FE021, // Large 'vbroadcastf32x|4'. + 0x1005E021, // Large 'vbroadcastf32x|8'. + 0x4030B021, // Large 'vbroadcastf|64x2'. + 0x4034B021, // Large 'vbroadcastf|64x4'. + 0x4065A021, // Large 'vbroadcast|i128'. + 0x5038A021, // Large 'vbroadcast|i32x2'. + 0x503DA021, // Large 'vbroadcast|i32x4'. + 0x5042A021, // Large 'vbroadcast|i32x8'. + 0x5047A021, // Large 'vbroadcast|i64x2'. + 0x504CA021, // Large 'vbroadcast|i64x4'. + 0x210EA021, // Large 'vbroadcast|sd'. + 0x201CA021, // Large 'vbroadcast|ss'. + 0x89083476, // Small 'vcmppd'. + 0x91083476, // Small 'vcmpph'. + 0xA7083476, // Small 'vcmpps'. + 0x89383476, // Small 'vcmpsd'. + 0x91383476, // Small 'vcmpsh'. + 0xA7383476, // Small 'vcmpss'. + 0x210E56BB, // Large 'vcomi|sd'. + 0x20B556BB, // Large 'vcomi|sh'. + 0x201C56BB, // Large 'vcomi|ss'. + 0x2087919C, // Large 'vcompress|pd'. + 0x2070919C, // Large 'vcompress|ps'. + 0x208773ED, // Large 'vcvtdq2|pd'. + 0x208273ED, // Large 'vcvtdq2|ph'. + 0x207073ED, // Large 'vcvtdq2|ps'. + 0x1030D069, // Large 'vcvtne2ps2bf1|6'. + 0x1030C0DC, // Large 'vcvtneps2bf1|6'. + 0x20C5727E, // Large 'vcvtpd2|dq'. + 0x2082727E, // Large 'vcvtpd2|ph'. + 0x2070727E, // Large 'vcvtpd2|ps'. + 0x21AE727E, // Large 'vcvtpd2|qq'. + 0x20C5827E, // Large 'vcvtpd2u|dq'. + 0x21AE827E, // Large 'vcvtpd2u|qq'. + 0x20C57286, // Large 'vcvtph2|dq'. + 0x10268286, // Large 'vcvtph2p|d'. + 0x00009286, // Large 'vcvtph2ps'. + 0x102E9286, // Large 'vcvtph2ps|x'. + 0x21AE7286, // Large 'vcvtph2|qq'. + 0x328F7286, // Large 'vcvtph2|udq'. + 0x31AD7286, // Large 'vcvtph2|uqq'. + 0x23F47286, // Large 'vcvtph2|uw'. + 0x105F7286, // Large 'vcvtph2|w'. + 0x20C57292, // Large 'vcvtps2|dq'. + 0x10268292, // Large 'vcvtps2p|d'. + 0x00009292, // Large 'vcvtps2ph'. + 0x102E9292, // Large 'vcvtps2ph|x'. + 0x21AE7292, // Large 'vcvtps2|qq'. + 0x328F7292, // Large 'vcvtps2|udq'. + 0x31AD7292, // Large 'vcvtps2|uqq'. + 0x208773F6, // Large 'vcvtqq2|pd'. + 0x208273F6, // Large 'vcvtqq2|ph'. + 0x207073F6, // Large 'vcvtqq2|ps'. + 0x20B5729B, // Large 'vcvtsd2|sh'. + 0x201D729B, // Large 'vcvtsd2|si'. + 0x201C729B, // Large 'vcvtsd2|ss'. + 0x201D829B, // Large 'vcvtsd2u|si'. + 0x210E72A3, // Large 'vcvtsh2|sd'. + 0x201D72A3, // Large 'vcvtsh2|si'. + 0x201C72A3, // Large 'vcvtsh2|ss'. + 0x201D82A3, // Large 'vcvtsh2u|si'. + 0x210E73FD, // Large 'vcvtsi2|sd'. + 0x20B573FD, // Large 'vcvtsi2|sh'. + 0x201C73FD, // Large 'vcvtsi2|ss'. + 0x210E72AB, // Large 'vcvtss2|sd'. + 0x20B572AB, // Large 'vcvtss2|sh'. + 0x201D72AB, // Large 'vcvtss2|si'. + 0x201D82AB, // Large 'vcvtss2u|si'. + 0x20C581A5, // Large 'vcvttpd2|dq'. + 0x21AE81A5, // Large 'vcvttpd2|qq'. + 0x20C591A5, // Large 'vcvttpd2u|dq'. + 0x21AE91A5, // Large 'vcvttpd2u|qq'. + 0x20C581B0, // Large 'vcvttph2|dq'. + 0x21AE81B0, // Large 'vcvttph2|qq'. + 0x20C591B0, // Large 'vcvttph2u|dq'. + 0x21AE91B0, // Large 'vcvttph2u|qq'. + 0x105F91B0, // Large 'vcvttph2u|w'. + 0x105F81B0, // Large 'vcvttph2|w'. + 0x20C581B9, // Large 'vcvttps2|dq'. + 0x21AE81B9, // Large 'vcvttps2|qq'. + 0x20C591B9, // Large 'vcvttps2u|dq'. + 0x21AE91B9, // Large 'vcvttps2u|qq'. + 0x201D81C2, // Large 'vcvttsd2|si'. + 0x201D91C2, // Large 'vcvttsd2u|si'. + 0x201D81CB, // Large 'vcvttsh2|si'. + 0x201D91CB, // Large 'vcvttsh2u|si'. + 0x201D81D4, // Large 'vcvttss2|si'. + 0x201D91D4, // Large 'vcvttss2u|si'. + 0x208782B3, // Large 'vcvtudq2|pd'. + 0x208282B3, // Large 'vcvtudq2|ph'. + 0x207082B3, // Large 'vcvtudq2|ps'. + 0x208782BB, // Large 'vcvtuqq2|pd'. + 0x208282BB, // Large 'vcvtuqq2|ph'. + 0x207082BB, // Large 'vcvtuqq2|ps'. + 0x210E82C3, // Large 'vcvtusi2|sd'. + 0x20B582C3, // Large 'vcvtusi2|sh'. + 0x201C82C3, // Large 'vcvtusi2|ss'. + 0x30816404, // Large 'vcvtuw|2ph'. + 0x30815570, // Large 'vcvtw|2ph'. + 0x2344740A, // Large 'vdbpsad|bw'. + 0x890B2496, // Small 'vdivpd'. + 0x910B2496, // Small 'vdivph'. + 0xA70B2496, // Small 'vdivps'. + 0x893B2496, // Small 'vdivsd'. + 0x913B2496, // Small 'vdivsh'. + 0xA73B2496, // Small 'vdivss'. + 0x20707411, // Large 'vdpbf16|ps'. + 0x80484096, // Small 'vdppd'. + 0x81384096, // Small 'vdpps'. + 0x800948B6, // Small 'verr'. + 0x800BC8B6, // Small 'verw'. + 0x34874418, // Large 'vexp|2pd'. + 0x306F4418, // Large 'vexp|2ps'. + 0x30CD6418, // Large 'vexpan|dpd'. + 0x30D16418, // Large 'vexpan|dps'. + 0x306290EF, // Large 'vextractf|128'. + 0x602A70E8, // Large 'vextrac|tf32x4'. + 0x404390EF, // Large 'vextractf|32x8'. + 0x403090EF, // Large 'vextractf|64x2'. + 0x403490EF, // Large 'vextractf|64x4'. + 0x406580EF, // Large 'vextract|i128'. + 0x503D80EF, // Large 'vextract|i32x4'. + 0x504280EF, // Large 'vextract|i32x8'. + 0x504780EF, // Large 'vextract|i64x2'. + 0x504C80EF, // Large 'vextract|i64x4'. + 0x207080EF, // Large 'vextract|ps'. + 0x208282CB, // Large 'vfcmaddc|ph'. + 0x20B582CB, // Large 'vfcmaddc|sh'. + 0x2082741E, // Large 'vfcmulc|ph'. + 0x20B5741E, // Large 'vfcmulc|sh'. + 0x208791DD, // Large 'vfixupimm|pd'. + 0x207091DD, // Large 'vfixupimm|ps'. + 0x210E91DD, // Large 'vfixupimm|sd'. + 0x201C91DD, // Large 'vfixupimm|ss'. + 0x208791E6, // Large 'vfmadd132|pd'. + 0x208291E6, // Large 'vfmadd132|ph'. + 0x207091E6, // Large 'vfmadd132|ps'. + 0x210E91E6, // Large 'vfmadd132|sd'. + 0x20B591E6, // Large 'vfmadd132|sh'. + 0x201C91E6, // Large 'vfmadd132|ss'. + 0x50846076, // Large 'vfmadd|213pd'. + 0x50896076, // Large 'vfmadd|213ph'. + 0x508E6076, // Large 'vfmadd|213ps'. + 0x511A6076, // Large 'vfmadd|213sd'. + 0x511F6076, // Large 'vfmadd|213sh'. + 0x51246076, // Large 'vfmadd|213ss'. + 0x50936076, // Large 'vfmadd|231pd'. + 0x50986076, // Large 'vfmadd|231ph'. + 0x509D6076, // Large 'vfmadd|231ps'. + 0x51296076, // Large 'vfmadd|231sd'. + 0x512E6076, // Large 'vfmadd|231sh'. + 0x51336076, // Large 'vfmadd|231ss'. + 0x34256076, // Large 'vfmadd|cph'. + 0x34286076, // Large 'vfmadd|csh'. + 0x20876076, // Large 'vfmadd|pd'. + 0x20706076, // Large 'vfmadd|ps'. + 0x10267076, // Large 'vfmadds|d'. + 0x10147076, // Large 'vfmadds|s'. + 0x1026D076, // Large 'vfmaddsub132p|d'. + 0x1083D076, // Large 'vfmaddsub132p|h'. + 0x1014D076, // Large 'vfmaddsub132p|s'. + 0x50849076, // Large 'vfmaddsub|213pd'. + 0x50899076, // Large 'vfmaddsub|213ph'. + 0x508E9076, // Large 'vfmaddsub|213ps'. + 0x50939076, // Large 'vfmaddsub|231pd'. + 0x50989076, // Large 'vfmaddsub|231ph'. + 0x509D9076, // Large 'vfmaddsub|231ps'. + 0x20879076, // Large 'vfmaddsub|pd'. + 0x20709076, // Large 'vfmaddsub|ps'. + 0x208791EF, // Large 'vfmsub132|pd'. + 0x208291EF, // Large 'vfmsub132|ph'. + 0x207091EF, // Large 'vfmsub132|ps'. + 0x210E91EF, // Large 'vfmsub132|sd'. + 0x20B591EF, // Large 'vfmsub132|sh'. + 0x201C91EF, // Large 'vfmsub132|ss'. + 0x508460A2, // Large 'vfmsub|213pd'. + 0x508960A2, // Large 'vfmsub|213ph'. + 0x508E60A2, // Large 'vfmsub|213ps'. + 0x511A60A2, // Large 'vfmsub|213sd'. + 0x511F60A2, // Large 'vfmsub|213sh'. + 0x512460A2, // Large 'vfmsub|213ss'. + 0x509360A2, // Large 'vfmsub|231pd'. + 0x509860A2, // Large 'vfmsub|231ph'. + 0x509D60A2, // Large 'vfmsub|231ps'. + 0x512960A2, // Large 'vfmsub|231sd'. + 0x512E60A2, // Large 'vfmsub|231sh'. + 0x513360A2, // Large 'vfmsub|231ss'. + 0x2087C0A2, // Large 'vfmsubadd132|pd'. + 0x2082C0A2, // Large 'vfmsubadd132|ph'. + 0x2070C0A2, // Large 'vfmsubadd132|ps'. + 0x508490A2, // Large 'vfmsubadd|213pd'. + 0x508990A2, // Large 'vfmsubadd|213ph'. + 0x508E90A2, // Large 'vfmsubadd|213ps'. + 0x509390A2, // Large 'vfmsubadd|231pd'. + 0x509890A2, // Large 'vfmsubadd|231ph'. + 0x509D90A2, // Large 'vfmsubadd|231ps'. + 0x208790A2, // Large 'vfmsubadd|pd'. + 0x207090A2, // Large 'vfmsubadd|ps'. + 0x208760A2, // Large 'vfmsub|pd'. + 0x207060A2, // Large 'vfmsub|ps'. + 0x210E60A2, // Large 'vfmsub|sd'. + 0x201C60A2, // Large 'vfmsub|ss'. + 0x34255575, // Large 'vfmul|cph'. + 0x34285575, // Large 'vfmul|csh'. + 0x2087A110, // Large 'vfnmadd132|pd'. + 0x2082A110, // Large 'vfnmadd132|ph'. + 0x2070A110, // Large 'vfnmadd132|ps'. + 0x210EA110, // Large 'vfnmadd132|sd'. + 0x20B5A110, // Large 'vfnmadd132|sh'. + 0x201CA110, // Large 'vfnmadd132|ss'. + 0x50847110, // Large 'vfnmadd|213pd'. + 0x50897110, // Large 'vfnmadd|213ph'. + 0x508E7110, // Large 'vfnmadd|213ps'. + 0x511A7110, // Large 'vfnmadd|213sd'. + 0x511F7110, // Large 'vfnmadd|213sh'. + 0x51247110, // Large 'vfnmadd|213ss'. + 0x50937110, // Large 'vfnmadd|231pd'. + 0x50987110, // Large 'vfnmadd|231ph'. + 0x509D7110, // Large 'vfnmadd|231ps'. + 0x51297110, // Large 'vfnmadd|231sd'. + 0x512E7110, // Large 'vfnmadd|231sh'. + 0x51337110, // Large 'vfnmadd|231ss'. + 0x20877110, // Large 'vfnmadd|pd'. + 0x20707110, // Large 'vfnmadd|ps'. + 0x210E7110, // Large 'vfnmadd|sd'. + 0x201C7110, // Large 'vfnmadd|ss'. + 0x2087A138, // Large 'vfnmsub132|pd'. + 0x2082A138, // Large 'vfnmsub132|ph'. + 0x2070A138, // Large 'vfnmsub132|ps'. + 0x210EA138, // Large 'vfnmsub132|sd'. + 0x20B5A138, // Large 'vfnmsub132|sh'. + 0x201CA138, // Large 'vfnmsub132|ss'. + 0x50847138, // Large 'vfnmsub|213pd'. + 0x50897138, // Large 'vfnmsub|213ph'. + 0x508E7138, // Large 'vfnmsub|213ps'. + 0x511A7138, // Large 'vfnmsub|213sd'. + 0x511F7138, // Large 'vfnmsub|213sh'. + 0x51247138, // Large 'vfnmsub|213ss'. + 0x50937138, // Large 'vfnmsub|231pd'. + 0x50987138, // Large 'vfnmsub|231ph'. + 0x509D7138, // Large 'vfnmsub|231ps'. + 0x51297138, // Large 'vfnmsub|231sd'. + 0x512E7138, // Large 'vfnmsub|231sh'. + 0x51337138, // Large 'vfnmsub|231ss'. + 0x20877138, // Large 'vfnmsub|pd'. + 0x20707138, // Large 'vfnmsub|ps'. + 0x210E7138, // Large 'vfnmsub|sd'. + 0x201C7138, // Large 'vfnmsub|ss'. + 0x208782D3, // Large 'vfpclass|pd'. + 0x208282D3, // Large 'vfpclass|ph'. + 0x207082D3, // Large 'vfpclass|ps'. + 0x210E82D3, // Large 'vfpclass|sd'. + 0x20B582D3, // Large 'vfpclass|sh'. + 0x201C82D3, // Large 'vfpclass|ss'. + 0x208756C0, // Large 'vfrcz|pd'. + 0x207056C0, // Large 'vfrcz|ps'. + 0x210E56C0, // Large 'vfrcz|sd'. + 0x201C56C0, // Large 'vfrcz|ss'. + 0x30CD70F8, // Large 'vgather|dpd'. + 0x30D170F8, // Large 'vgather|dps'. + 0x30CDA0F8, // Large 'vgatherpf0|dpd'. + 0x30D1A0F8, // Large 'vgatherpf0|dps'. + 0x30C6A0F8, // Large 'vgatherpf0|qpd'. + 0x30C9A0F8, // Large 'vgatherpf0|qps'. + 0x40CC90F8, // Large 'vgatherpf|1dpd'. + 0x40D090F8, // Large 'vgatherpf|1dps'. + 0x40D490F8, // Large 'vgatherpf|1qpd'. + 0x40D890F8, // Large 'vgatherpf|1qps'. + 0x30C670F8, // Large 'vgather|qpd'. + 0x30C970F8, // Large 'vgather|qps'. + 0x2087742B, // Large 'vgetexp|pd'. + 0x2082742B, // Large 'vgetexp|ph'. + 0x2070742B, // Large 'vgetexp|ps'. + 0x210E742B, // Large 'vgetexp|sd'. + 0x20B5742B, // Large 'vgetexp|sh'. + 0x201C742B, // Large 'vgetexp|ss'. + 0x31A972DB, // Large 'vgetman|tpd'. + 0x31B472DB, // Large 'vgetman|tph'. + 0x31BD72DB, // Large 'vgetman|tps'. + 0x310D72DB, // Large 'vgetman|tsd'. + 0x31CF72DB, // Large 'vgetman|tsh'. + 0x31D872DB, // Large 'vgetman|tss'. + 0x200FF000, // Large 'vgf2p8affineinv|qb'. + 0x200FC000, // Large 'vgf2p8affine|qb'. + 0x42E26000, // Large 'vgf2p8|mulb'. + 0x30CD46C5, // Large 'vhad|dpd'. + 0x30D146C5, // Large 'vhad|dps'. + 0x208756C9, // Large 'vhsub|pd'. + 0x207056C9, // Large 'vhsub|ps'. + 0x30628148, // Large 'vinsertf|128'. + 0x602A6142, // Large 'vinser|tf32x4'. + 0x40438148, // Large 'vinsertf|32x8'. + 0x40308148, // Large 'vinsertf|64x2'. + 0x40348148, // Large 'vinsertf|64x4'. + 0x40657148, // Large 'vinsert|i128'. + 0x503D7148, // Large 'vinsert|i32x4'. + 0x50427148, // Large 'vinsert|i32x8'. + 0x50477148, // Large 'vinsert|i64x2'. + 0x504C7148, // Large 'vinsert|i64x4'. + 0x20707148, // Large 'vinsert|ps'. + 0xAB121196, // Small 'vlddqu'. + 0x1023757A, // Large 'vldmxcs|r'. + 0x107DA1F8, // Large 'vmaskmovdq|u'. + 0x208781F8, // Large 'vmaskmov|pd'. + 0x207081F8, // Large 'vmaskmov|ps'. + 0x890C05B6, // Small 'vmaxpd'. + 0x910C05B6, // Small 'vmaxph'. + 0xA70C05B6, // Small 'vmaxps'. + 0x893C05B6, // Small 'vmaxsd'. + 0x913C05B6, // Small 'vmaxsh'. + 0xA73C05B6, // Small 'vmaxss'. + 0x98C08DB6, // Small 'vmcall'. + 0x23A256CE, // Large 'vmcle|ar'. + 0x86EA99B6, // Small 'vmfunc'. + 0x890725B6, // Small 'vminpd'. + 0x910725B6, // Small 'vminph'. + 0xA70725B6, // Small 'vminps'. + 0x893725B6, // Small 'vminsd'. + 0x913725B6, // Small 'vminsh'. + 0xA73725B6, // Small 'vminss'. + 0x21606581, // Large 'vmlaun|ch'. + 0x8817B1B6, // Small 'vmload'. + 0x361A46D3, // Large 'vmmc|all'. + 0x208756D7, // Large 'vmova|pd'. + 0x207056D7, // Large 'vmova|ps'. + 0x804B3DB6, // Small 'vmovd'. + 0x35875432, // Large 'vmovd|dup'. + 0x00007432, // Large 'vmovdqa'. + 0x202C7432, // Large 'vmovdqa|32'. + 0x20307432, // Large 'vmovdqa|64'. + 0x107D6432, // Large 'vmovdq|u'. + 0x34396432, // Large 'vmovdq|u16'. + 0x343C6432, // Large 'vmovdq|u32'. + 0x343F6432, // Large 'vmovdq|u64'. + 0x258A6432, // Large 'vmovdq|u8'. + 0x34ED558C, // Large 'vmovh|lps'. + 0x2087558C, // Large 'vmovh|pd'. + 0x2070558C, // Large 'vmovh|ps'. + 0x20706591, // Large 'vmovlh|ps'. + 0x20875591, // Large 'vmovl|pd'. + 0x20705591, // Large 'vmovl|ps'. + 0x20877442, // Large 'vmovmsk|pd'. + 0x20707442, // Large 'vmovmsk|ps'. + 0x20C56449, // Large 'vmovnt|dq'. + 0x34366449, // Large 'vmovnt|dqa'. + 0x20876449, // Large 'vmovnt|pd'. + 0x20706449, // Large 'vmovnt|ps'. + 0x811B3DB6, // Small 'vmovq'. + 0x893B3DB6, // Small 'vmovsd'. + 0x913B3DB6, // Small 'vmovsh'. + 0x21E1744F, // Large 'vmovshd|up'. + 0x21E17456, // Large 'vmovsld|up'. + 0xA73B3DB6, // Small 'vmovss'. + 0x33AD4432, // Large 'vmov|upd'. + 0x207056DC, // Large 'vmovu|ps'. + 0x817B3DB6, // Small 'vmovw'. + 0x23446597, // Large 'vmpsad|bw'. + 0x338B46E1, // Large 'vmpt|rld'. + 0x338746E1, // Large 'vmpt|rst'. + 0x8812C9B6, // Small 'vmread'. + 0x100B759D, // Large 'vmresum|e'. + 0x80EAC9B6, // Small 'vmrun'. + 0x8B60CDB6, // Small 'vmsave'. + 0x890655B6, // Small 'vmulpd'. + 0x910655B6, // Small 'vmulph'. + 0xA70655B6, // Small 'vmulps'. + 0x893655B6, // Small 'vmulsd'. + 0x913655B6, // Small 'vmulsh'. + 0xA73655B6, // Small 'vmulss'. + 0x20BF56E5, // Large 'vmwri|te'. + 0x80E7E1B6, // Small 'vmxon'. + 0x804849F6, // Small 'vorpd'. + 0x813849F6, // Small 'vorps'. + 0x1026C102, // Large 'vp2intersect|d'. + 0x100FC102, // Large 'vp2intersect|q'. + 0x102682E6, // Large 'vp4dpwss|d'. + 0x207B82E6, // Large 'vp4dpwss|ds'. + 0x85310616, // Small 'vpabsb'. + 0x89310616, // Small 'vpabsd'. + 0xA3310616, // Small 'vpabsq'. + 0xAF310616, // Small 'vpabsw'. + 0x105F845D, // Large 'vpackssd|w'. + 0x2465745D, // Large 'vpackss|wb'. + 0x34636467, // Large 'vpacku|sdw'. + 0x346D6467, // Large 'vpacku|swb'. + 0x84420616, // Small 'vpaddb'. + 0x88420616, // Small 'vpaddd'. + 0xA2420616, // Small 'vpaddq'. + 0x250D55A4, // Large 'vpadd|sb'. + 0x232D55A4, // Large 'vpadd|sw'. + 0x250D65A4, // Large 'vpaddu|sb'. + 0x232D65A4, // Large 'vpaddu|sw'. + 0xAE420616, // Small 'vpaddw'. + 0x102375AA, // Large 'vpalign|r'. + 0x80470616, // Small 'vpand'. + 0x88470616, // Small 'vpandd'. + 0x9C470616, // Small 'vpandn'. + 0x217856EA, // Large 'vpand|nd'. + 0x264056EA, // Large 'vpand|nq'. + 0xA2470616, // Small 'vpandq'. + 0x847B0616, // Small 'vpavgb'. + 0xAE7B0616, // Small 'vpavgw'. + 0x10267470, // Large 'vpblend|d'. + 0x205C7470, // Large 'vpblend|mb'. + 0x24777470, // Large 'vpblend|md'. + 0x100F8470, // Large 'vpblendm|q'. + 0x105F8470, // Large 'vpblendm|w'. + 0x20217470, // Large 'vpblend|vb'. + 0x105F7470, // Large 'vpblend|w'. + 0x1010B051, // Large 'vpbroadcast|b'. + 0x1026B051, // Large 'vpbroadcast|d'. + 0x100FE051, // Large 'vpbroadcastmb2|q'. + 0x305FC051, // Large 'vpbroadcastm|w2d'. + 0x100FB051, // Large 'vpbroadcast|q'. + 0x105FB051, // Large 'vpbroadcast|w'. + 0x424062EE, // Large 'vpclmu|lqdq'. + 0xACF68E16, // Small 'vpcmov'. + 0x85068E16, // Small 'vpcmpb'. + 0x89068E16, // Small 'vpcmpd'. + 0x200F62F4, // Large 'vpcmpe|qb'. + 0x223562F4, // Large 'vpcmpe|qd'. + 0x21AE62F4, // Large 'vpcmpe|qq'. + 0x24BB62F4, // Large 'vpcmpe|qw'. + 0x100992F4, // Large 'vpcmpestr|i'. + 0x105C92F4, // Large 'vpcmpestr|m'. + 0x35B152F4, // Large 'vpcmp|gtb'. + 0x35B452F4, // Large 'vpcmp|gtd'. + 0x35B752F4, // Large 'vpcmp|gtq'. + 0x35BA52F4, // Large 'vpcmp|gtw'. + 0x100992FD, // Large 'vpcmpistr|i'. + 0x105C92FD, // Large 'vpcmpistr|m'. + 0xA3068E16, // Small 'vpcmpq'. + 0x207D52F4, // Large 'vpcmp|ub'. + 0x228F52F4, // Large 'vpcmp|ud'. + 0x21AD52F4, // Large 'vpcmp|uq'. + 0x23F452F4, // Large 'vpcmp|uw'. + 0xAF068E16, // Small 'vpcmpw'. + 0x84D78E16, // Small 'vpcomb'. + 0x88D78E16, // Small 'vpcomd'. + 0x1010A202, // Large 'vpcompress|b'. + 0x1026A202, // Large 'vpcompress|d'. + 0x100FA202, // Large 'vpcompress|q'. + 0x105FA202, // Large 'vpcompress|w'. + 0xA2D78E16, // Small 'vpcomq'. + 0x207D5202, // Large 'vpcom|ub'. + 0x228F5202, // Large 'vpcom|ud'. + 0x21AD5202, // Large 'vpcom|uq'. + 0x23F45202, // Large 'vpcom|uw'. + 0xAED78E16, // Small 'vpcomw'. + 0x1026A20C, // Large 'vpconflict|d'. + 0x100FA20C, // Large 'vpconflict|q'. + 0x10267479, // Large 'vpdpbus|d'. + 0x207B7479, // Large 'vpdpbus|ds'. + 0x10267480, // Large 'vpdpwss|d'. + 0x207B7480, // Large 'vpdpwss|ds'. + 0x30627306, // Large 'vperm2f|128'. + 0x40656306, // Large 'vperm2|i128'. + 0x84D91616, // Small 'vpermb'. + 0x88D91616, // Small 'vpermd'. + 0x2072630D, // Large 'vpermi|2b'. + 0x2060630D, // Large 'vpermi|2d'. + 0x3487630D, // Large 'vpermi|2pd'. + 0x306F630D, // Large 'vpermi|2ps'. + 0x25BD630D, // Large 'vpermi|2q'. + 0x205E630D, // Large 'vpermi|2w'. + 0x2087830D, // Large 'vpermil2|pd'. + 0x2070830D, // Large 'vpermil2|ps'. + 0x2087730D, // Large 'vpermil|pd'. + 0x2070730D, // Large 'vpermil|ps'. + 0x20875306, // Large 'vperm|pd'. + 0x20705306, // Large 'vperm|ps'. + 0xA2D91616, // Small 'vpermq'. + 0x2072648A, // Large 'vpermt|2b'. + 0x2060648A, // Large 'vpermt|2d'. + 0x3487648A, // Large 'vpermt|2pd'. + 0x306F648A, // Large 'vpermt|2ps'. + 0x25BD648A, // Large 'vpermt|2q'. + 0x205E648A, // Large 'vpermt|2w'. + 0xAED91616, // Small 'vpermw'. + 0x240B7490, // Large 'vpexpan|db'. + 0x207A7490, // Large 'vpexpan|dd'. + 0x20C57490, // Large 'vpexpan|dq'. + 0x24647490, // Large 'vpexpan|dw'. + 0x352E4490, // Large 'vpex|trb'. + 0x254D56EF, // Large 'vpext|rd'. + 0x223456EF, // Large 'vpext|rq'. + 0x26F456EF, // Large 'vpext|rw'. + 0x207A8315, // Large 'vpgather|dd'. + 0x20C58315, // Large 'vpgather|dq'. + 0x22358315, // Large 'vpgather|qd'. + 0x21AE8315, // Large 'vpgather|qq'. + 0x25BF6497, // Large 'vphadd|bd'. + 0x25C16497, // Large 'vphadd|bq'. + 0x23446497, // Large 'vphadd|bw'. + 0x10266497, // Large 'vphadd|d'. + 0x20C56497, // Large 'vphadd|dq'. + 0x232D6497, // Large 'vphadd|sw'. + 0x10268497, // Large 'vphaddub|d'. + 0x100F8497, // Large 'vphaddub|q'. + 0x105F8497, // Large 'vphaddub|w'. + 0x20C57497, // Large 'vphaddu|dq'. + 0x23467497, // Large 'vphaddu|wd'. + 0x249F7497, // Large 'vphaddu|wq'. + 0x105F6497, // Large 'vphadd|w'. + 0x23466497, // Large 'vphadd|wd'. + 0x249F6497, // Large 'vphadd|wq'. + 0x105FA216, // Large 'vphminposu|w'. + 0x234465C3, // Large 'vphsub|bw'. + 0x102665C3, // Large 'vphsub|d'. + 0x20C565C3, // Large 'vphsub|dq'. + 0x232D65C3, // Large 'vphsub|sw'. + 0x105F65C3, // Large 'vphsub|w'. + 0x234665C3, // Large 'vphsub|wd'. + 0x252F56F6, // Large 'vpins|rb'. + 0x254D56F6, // Large 'vpins|rd'. + 0x223456F6, // Large 'vpins|rq'. + 0x26F456F6, // Large 'vpins|rw'. + 0x23CF65C9, // Large 'vplzcn|td'. + 0x215865C9, // Large 'vplzcn|tq'. + 0x207A631D, // Large 'vpmacs|dd'. + 0x34A1631D, // Large 'vpmacs|dqh'. + 0x334C631D, // Large 'vpmacs|dql'. + 0x1026831D, // Large 'vpmacssd|d'. + 0x1083931D, // Large 'vpmacssdq|h'. + 0x10B2931D, // Large 'vpmacssdq|l'. + 0x2346731D, // Large 'vpmacss|wd'. + 0x2345731D, // Large 'vpmacss|ww'. + 0x2346631D, // Large 'vpmacs|wd'. + 0x2345631D, // Large 'vpmacs|ww'. + 0x10269326, // Large 'vpmadcssw|d'. + 0x23467326, // Large 'vpmadcs|wd'. + 0x21AD9220, // Large 'vpmadd52h|uq'. + 0x32298220, // Large 'vpmadd52|luq'. + 0x432F6220, // Large 'vpmadd|ubsw'. + 0x23466220, // Large 'vpmadd|wd'. + 0x61FB4220, // Large 'vpma|skmovd'. + 0x200E8333, // Large 'vpmaskmo|vq'. + 0x250D56FB, // Large 'vpmax|sb'. + 0x210E56FB, // Large 'vpmax|sd'. + 0x235356FB, // Large 'vpmax|sq'. + 0x232D56FB, // Large 'vpmax|sw'. + 0x207D56FB, // Large 'vpmax|ub'. + 0x228F56FB, // Large 'vpmax|ud'. + 0x21AD56FB, // Large 'vpmax|uq'. + 0x23F456FB, // Large 'vpmax|uw'. + 0x250D5700, // Large 'vpmin|sb'. + 0x210E5700, // Large 'vpmin|sd'. + 0x23535700, // Large 'vpmin|sq'. + 0x232D5700, // Large 'vpmin|sw'. + 0x207D5700, // Large 'vpmin|ub'. + 0x228F5700, // Large 'vpmin|ud'. + 0x21AD5700, // Large 'vpmin|uq'. + 0x23F45700, // Large 'vpmin|uw'. + 0x35CF54A4, // Large 'vpmov|b2m'. + 0x35D254A4, // Large 'vpmov|d2m'. + 0x240B54A4, // Large 'vpmov|db'. + 0x246454A4, // Large 'vpmov|dw'. + 0x207264A4, // Large 'vpmovm|2b'. + 0x206064A4, // Large 'vpmovm|2d'. + 0x25BD64A4, // Large 'vpmovm|2q'. + 0x205E64A4, // Large 'vpmovm|2w'. + 0x101084A4, // Large 'vpmovmsk|b'. + 0x35D554A4, // Large 'vpmov|q2m'. + 0x200F54A4, // Large 'vpmov|qb'. + 0x223554A4, // Large 'vpmov|qd'. + 0x24BB54A4, // Large 'vpmov|qw'. + 0x240B64AC, // Large 'vpmovs|db'. + 0x246464AC, // Large 'vpmovs|dw'. + 0x200F64AC, // Large 'vpmovs|qb'. + 0x223564AC, // Large 'vpmovs|qd'. + 0x24BB64AC, // Large 'vpmovs|qw'. + 0x246564AC, // Large 'vpmovs|wb'. + 0x102684AC, // Large 'vpmovsxb|d'. + 0x100F84AC, // Large 'vpmovsxb|q'. + 0x105F84AC, // Large 'vpmovsxb|w'. + 0x20C574AC, // Large 'vpmovsx|dq'. + 0x234674AC, // Large 'vpmovsx|wd'. + 0x249F74AC, // Large 'vpmovsx|wq'. + 0x240B74B4, // Large 'vpmovus|db'. + 0x246474B4, // Large 'vpmovus|dw'. + 0x200F74B4, // Large 'vpmovus|qb'. + 0x223574B4, // Large 'vpmovus|qd'. + 0x24BB74B4, // Large 'vpmovus|qw'. + 0x246574B4, // Large 'vpmovus|wb'. + 0x35D854A4, // Large 'vpmov|w2m'. + 0x246554A4, // Large 'vpmov|wb'. + 0x102684BD, // Large 'vpmovzxb|d'. + 0x100F84BD, // Large 'vpmovzxb|q'. + 0x105F84BD, // Large 'vpmovzxb|w'. + 0x20C574BD, // Large 'vpmovzx|dq'. + 0x234674BD, // Large 'vpmovzx|wd'. + 0x249F74BD, // Large 'vpmovzx|wq'. + 0x20C550AE, // Large 'vpmul|dq'. + 0x232D74C5, // Large 'vpmulhr|sw'. + 0x23F464C5, // Large 'vpmulh|uw'. + 0x105F64C5, // Large 'vpmulh|w'. + 0x234B50AE, // Large 'vpmul|ld'. + 0x224050AE, // Large 'vpmul|lq'. + 0x234E50AE, // Large 'vpmul|lw'. + 0x200FC0AE, // Large 'vpmultishift|qb'. + 0x328F50AE, // Large 'vpmul|udq'. + 0x25B265DB, // Large 'vpopcn|tb'. + 0x23CF65DB, // Large 'vpopcn|td'. + 0x215865DB, // Large 'vpopcn|tq'. + 0x216365DB, // Large 'vpopcn|tw'. + 0x80093E16, // Small 'vpor'. + 0x80493E16, // Small 'vpord'. + 0x81193E16, // Small 'vporq'. + 0x9B22C216, // Small 'vpperm'. + 0x88C7CA16, // Small 'vprold'. + 0xA2C7CA16, // Small 'vprolq'. + 0x21FF5705, // Large 'vprol|vd'. + 0x200E5705, // Large 'vprol|vq'. + 0x8927CA16, // Small 'vprord'. + 0xA327CA16, // Small 'vprorq'. + 0x21FF570A, // Large 'vpror|vd'. + 0x200E570A, // Large 'vpror|vq'. + 0x8547CA16, // Small 'vprotb'. + 0x8947CA16, // Small 'vprotd'. + 0xA347CA16, // Small 'vprotq'. + 0xAF47CA16, // Small 'vprotw'. + 0x2344570F, // Large 'vpsad|bw'. + 0x207A922C, // Large 'vpscatter|dd'. + 0x20C5922C, // Large 'vpscatter|dq'. + 0x2235922C, // Large 'vpscatter|qd'. + 0x100FA22C, // Large 'vpscatterq|q'. + 0x84144E16, // Small 'vpshab'. + 0x88144E16, // Small 'vpshad'. + 0xA2144E16, // Small 'vpshaq'. + 0xAE144E16, // Small 'vpshaw'. + 0x84C44E16, // Small 'vpshlb'. + 0x88C44E16, // Small 'vpshld'. + 0x102665E1, // Large 'vpshld|d'. + 0x100F65E1, // Large 'vpshld|q'. + 0x341055E1, // Large 'vpshl|dvd'. + 0x35E655E1, // Large 'vpshl|dvq'. + 0x105F75E1, // Large 'vpshldv|w'. + 0x105F65E1, // Large 'vpshld|w'. + 0xA2C44E16, // Small 'vpshlq'. + 0xAEC44E16, // Small 'vpshlw'. + 0x102665E9, // Large 'vpshrd|d'. + 0x100F65E9, // Large 'vpshrd|q'. + 0x341055E9, // Large 'vpshr|dvd'. + 0x35E655E9, // Large 'vpshr|dvq'. + 0x35EE55E9, // Large 'vpshr|dvw'. + 0x105F65E9, // Large 'vpshrd|w'. + 0x00007150, // Large 'vpshufb'. + 0x205CA150, // Large 'vpshufbitq|mb'. + 0x10266150, // Large 'vpshuf|d'. + 0x25F16150, // Large 'vpshuf|hw'. + 0x234E6150, // Large 'vpshuf|lw'. + 0x251A5714, // Large 'vpsig|nb'. + 0x21785714, // Large 'vpsig|nd'. + 0x26225714, // Large 'vpsig|nw'. + 0x88C64E16, // Small 'vpslld'. + 0x334B4719, // Large 'vpsl|ldq'. + 0xA2C64E16, // Small 'vpsllq'. + 0x21FF571D, // Large 'vpsll|vd'. + 0x200E571D, // Large 'vpsll|vq'. + 0x25EF571D, // Large 'vpsll|vw'. + 0xAEC64E16, // Small 'vpsllw'. + 0x88194E16, // Small 'vpsrad'. + 0xA2194E16, // Small 'vpsraq'. + 0x21FF5722, // Large 'vpsra|vd'. + 0x200E5722, // Large 'vpsra|vq'. + 0x25EF5722, // Large 'vpsra|vw'. + 0xAE194E16, // Small 'vpsraw'. + 0x88C94E16, // Small 'vpsrld'. + 0x334B4722, // Large 'vpsr|ldq'. + 0xA2C94E16, // Small 'vpsrlq'. + 0x21FF5727, // Large 'vpsrl|vd'. + 0x200E5727, // Large 'vpsrl|vq'. + 0x25EF5727, // Large 'vpsrl|vw'. + 0xAEC94E16, // Small 'vpsrlw'. + 0x842ACE16, // Small 'vpsubb'. + 0x882ACE16, // Small 'vpsubd'. + 0xA22ACE16, // Small 'vpsubq'. + 0x250D55F3, // Large 'vpsub|sb'. + 0x232D55F3, // Large 'vpsub|sw'. + 0x250D65F3, // Large 'vpsubu|sb'. + 0x232D65F3, // Large 'vpsubu|sw'. + 0xAE2ACE16, // Small 'vpsubw'. + 0x1026933B, // Large 'vpternlog|d'. + 0x100F933B, // Large 'vpternlog|q'. + 0xA932D216, // Small 'vptest'. + 0x205C64CC, // Large 'vptest|mb'. + 0x247764CC, // Large 'vptest|md'. + 0x24D364CC, // Large 'vptest|mq'. + 0x25D764CC, // Large 'vptest|mw'. + 0x205C74CC, // Large 'vptestn|mb'. + 0x247774CC, // Large 'vptestn|md'. + 0x24D374CC, // Large 'vptestn|mq'. + 0x105F84CC, // Large 'vptestnm|w'. + 0x23448237, // Large 'vpunpckh|bw'. + 0x20C58237, // Large 'vpunpckh|dq'. + 0x20C59237, // Large 'vpunpckhq|dq'. + 0x23468237, // Large 'vpunpckh|wd'. + 0x33487237, // Large 'vpunpck|lbw'. + 0x334B7237, // Large 'vpunpck|ldq'. + 0x42407237, // Large 'vpunpck|lqdq'. + 0x334E7237, // Large 'vpunpck|lwd'. + 0x8127E216, // Small 'vpxor'. + 0x8927E216, // Small 'vpxord'. + 0xA327E216, // Small 'vpxorq'. + 0x208765F9, // Large 'vrange|pd'. + 0x207065F9, // Large 'vrange|ps'. + 0x210E65F9, // Large 'vrange|sd'. + 0x201C65F9, // Large 'vrange|ss'. + 0x208765FF, // Large 'vrcp14|pd'. + 0x207065FF, // Large 'vrcp14|ps'. + 0x210E65FF, // Large 'vrcp14|sd'. + 0x201C65FF, // Large 'vrcp14|ss'. + 0x435945FF, // Large 'vrcp|28pd'. + 0x435D45FF, // Large 'vrcp|28ps'. + 0x436145FF, // Large 'vrcp|28sd'. + 0x436545FF, // Large 'vrcp|28ss'. + 0x91080E56, // Small 'vrcpph'. + 0xA7080E56, // Small 'vrcpps'. + 0x91380E56, // Small 'vrcpsh'. + 0xA7380E56, // Small 'vrcpss'. + 0x208774D5, // Large 'vreduce|pd'. + 0x208274D5, // Large 'vreduce|ph'. + 0x207074D5, // Large 'vreduce|ps'. + 0x210E74D5, // Large 'vreduce|sd'. + 0x20B574D5, // Large 'vreduce|sh'. + 0x201C74D5, // Large 'vreduce|ss'. + 0x20879244, // Large 'vrndscale|pd'. + 0x20829244, // Large 'vrndscale|ph'. + 0x20709244, // Large 'vrndscale|ps'. + 0x210E9244, // Large 'vrndscale|sd'. + 0x20B59244, // Large 'vrndscale|sh'. + 0x201C9244, // Large 'vrndscale|ss'. + 0x30CD5605, // Large 'vroun|dpd'. + 0x30D15605, // Large 'vroun|dps'. + 0x360A5605, // Large 'vroun|dsd'. + 0x10147605, // Large 'vrounds|s'. + 0x20878351, // Large 'vrsqrt14|pd'. + 0x20708351, // Large 'vrsqrt14|ps'. + 0x210E8351, // Large 'vrsqrt14|sd'. + 0x201C8351, // Large 'vrsqrt14|ss'. + 0x43596351, // Large 'vrsqrt|28pd'. + 0x435D6351, // Large 'vrsqrt|28ps'. + 0x43616351, // Large 'vrsqrt|28sd'. + 0x43656351, // Large 'vrsqrt|28ss'. + 0x20826351, // Large 'vrsqrt|ph'. + 0x20706351, // Large 'vrsqrt|ps'. + 0x20B56351, // Large 'vrsqrt|sh'. + 0x201C6351, // Large 'vrsqrt|ss'. + 0x208774DC, // Large 'vscalef|pd'. + 0x208274DC, // Large 'vscalef|ph'. + 0x207074DC, // Large 'vscalef|ps'. + 0x210E74DC, // Large 'vscalef|sd'. + 0x20B574DC, // Large 'vscalef|sh'. + 0x201C74DC, // Large 'vscalef|ss'. + 0x30CD80BA, // Large 'vscatter|dpd'. + 0x30D180BA, // Large 'vscatter|dps'. + 0x2087C0BA, // Large 'vscatterpf0d|pd'. + 0x2070C0BA, // Large 'vscatterpf0d|ps'. + 0x30C6B0BA, // Large 'vscatterpf0|qpd'. + 0x30C9B0BA, // Large 'vscatterpf0|qps'. + 0x40CCA0BA, // Large 'vscatterpf|1dpd'. + 0x40D0A0BA, // Large 'vscatterpf|1dps'. + 0x40D4A0BA, // Large 'vscatterpf|1qpd'. + 0x40D8A0BA, // Large 'vscatterpf|1qps'. + 0x30C680BA, // Large 'vscatter|qpd'. + 0x30C980BA, // Large 'vscatter|qps'. + 0x502B5369, // Large 'vshuf|f32x4'. + 0x4030636E, // Large 'vshuff|64x2'. + 0x503D5369, // Large 'vshuf|i32x4'. + 0x50475369, // Large 'vshuf|i64x2'. + 0x20875369, // Large 'vshuf|pd'. + 0x20705369, // Large 'vshuf|ps'. + 0x31A9472C, // Large 'vsqr|tpd'. + 0x31B4472C, // Large 'vsqr|tph'. + 0x31BD472C, // Large 'vsqr|tps'. + 0x310D472C, // Large 'vsqr|tsd'. + 0x31CF472C, // Large 'vsqr|tsh'. + 0x31D8472C, // Large 'vsqr|tss'. + 0x1023760D, // Large 'vstmxcs|r'. + 0x89015676, // Small 'vsubpd'. + 0x91015676, // Small 'vsubph'. + 0xA7015676, // Small 'vsubps'. + 0x89315676, // Small 'vsubsd'. + 0x91315676, // Small 'vsubsh'. + 0xA7315676, // Small 'vsubss'. + 0x31A94730, // Large 'vtes|tpd'. + 0x31BD4730, // Large 'vtes|tps'. + 0x210E6614, // Large 'vucomi|sd'. + 0x20B56614, // Large 'vucomi|sh'. + 0x201C6614, // Large 'vucomi|ss'. + 0x208774E3, // Large 'vunpckh|pd'. + 0x207074E3, // Large 'vunpckh|ps'. + 0x34EA64E3, // Large 'vunpck|lpd'. + 0x34ED64E3, // Large 'vunpck|lps'. + 0x89093F16, // Small 'vxorpd'. + 0xA7093F16, // Small 'vxorps'. + 0x361A5374, // Large 'vzero|all'. + 0x33077374, // Large 'vzeroup|per'. + 0x89672457, // Small 'wbinvd'. + 0x21FF661D, // Large 'wbnoin|vd'. + 0x33B05623, // Large 'wrfsb|ase'. + 0x33B05628, // Large 'wrgsb|ase'. + 0x8129B657, // Small 'wrmsr'. + 0x8049CE57, // Small 'wrssd'. + 0x8119CE57, // Small 'wrssq'. + 0x8939D657, // Small 'wrussd'. + 0xA339D657, // Small 'wrussq'. + 0xA9278838, // Small 'xabort'. + 0x80021038, // Small 'xadd'. + 0x9C939458, // Small 'xbegin'. + 0x8003A078, // Small 'xchg'. + 0x800238B8, // Small 'xend'. + 0xAC2A14F8, // Small 'xgetbv'. + 0x802A0598, // Small 'xlatb'. + 0x800049F8, // Small 'xor'. + 0x804849F8, // Small 'xorpd'. + 0x813849F8, // Small 'xorps'. + 0x101584F0, // Large 'xresldtr|k'. + 0xA4FA4E58, // Small 'xrstor'. + 0x20306386, // Large 'xrstor|64'. + 0x10146386, // Large 'xrstor|s'. + 0x34F86386, // Large 'xrstor|s64'. + 0x805B0678, // Small 'xsave'. + 0x2030537B, // Large 'xsave|64'. + 0x865B0678, // Small 'xsavec'. + 0x362D537B, // Large 'xsave|c64'. + 0x0000837B, // Large 'xsaveopt'. + 0x2030837B, // Large 'xsaveopt|64'. + 0xA65B0678, // Small 'xsaves'. + 0x34F8537B, // Large 'xsave|s64'. + 0xAC2A1678, // Small 'xsetbv'. + 0x101584FB, // Large 'xsusldtr|k'. + 0x81499698 // Small 'xtest'. +}; + +const char InstDB::_instNameStringTable[] = + "vgf2p8affineinvqbvaeskeygenassistvbroadcastf32x464x264x4i32x2i32x4i32x8i64x2i64x" + "4vpbroadcastmb2w2d128i128vcvtne2ps2bf1vfmaddsub132ph213pd213ph213ps231pd231ph231" + "psvfmsubadd132vpmultishiftvscatterpf0dqpdqps1dpd1dps1qpd1qpsvcvtneps2bf1vextracv" + "extractfvgatherpf0vp2intersectsdvfnmadd132213sd213sh213ss231sd231sh231ssvfnmsub1" + "32vinservinsertfvpshufbitqprefetchntwt1saveprevsssha256rndtileloaddtilereleavaes" + "declvaesenclvcompressvcvttpd2uqqvcvttph2uvcvttps2uvcvttsd2uvcvttsh2uvcvttss2uvfi" + "xupimmvfmadd132vfmsub132vmaskmovdqvpcompressvpconflictvphminposuvpmadd52hluqvpsc" + "atterqdvpunpckhqlqdqvrndscaleclflushopcmpxchg16t0t2msg1msg2tilestorev4fnmaddssvc" + "vtpd2uvcvtph2psudqvcvtps2phvcvtsd2uvcvtsh2uvcvtss2uvcvtudq2vcvtuqq2vcvtusi2vfcma" + "ddcvfpclassvgetmanmulbvp4dpwssvpclmuvpcmpestrvpcmpistrvperm2fvpermil2vpgathervpm" + "acssdqvpmadcsswubswvpmaskmovpternlogbwwdlbwldqlwdvrsqrt1428pd28ps28sd28ssvshufvs" + "huffvzeroupxsaveopt8bfxrstorldtilecfmovdir64pvalidarmpadjurmpupdaserialisha1nexs" + "ha1rndssttilecftdpbf16v4fmadvaddsubvblendmvpdvcvtdq2uwvcvtqq2vcvtsi2vcvtuwvdbpsa" + "dvdpbf16vexpanvfcmulccphcshvgetexpvmovdqau16u32u64vmovmskvmovntvmovshdvmovsldvpa" + "ckssdwbvpackuswbvpblendmdvpdpbusvpdpwss2pdvpermtvpexpanvphaddubwqdqhvpmovmskvpmo" + "vsxbvpmovusqwvpmovzxbvpmulhrvptestnmqvreducevscalefvunpckhlpdlpsxresldtrs64xsusl" + "dtrcldemoclrssbscvtpifcmovnbfxsavekortestkshiftrbkunpckmonitorpfrcpipfrsqirtvrdf" + "sbrdgsbsspsenduisetssbssysesysexvcvtwvfmulvldmxcsvmlaundupu8vmovhvmovlhvmpsadvmr" + "esumvpadduvpaligngtbgtdgtqgtw2qbdbqvphsubvplzcnb2md2mq2mw2mvpopcnvpshldvqvpshrdv" + "whwvpsubuvrangevrcp14vroundsdvstmxcsvucomiallwbnoinwrfsbwrgsbc64blcfiblsfiendbre" + "nqcmbefdecsfincsfnstefrndfsincfucomppfyl2xincsspqinvlinvpcinvvpmcommmovq2pavgupf" + "cmpepfpnaptwrisyscsysretdpbuvaesivaligvandnvcomivfrczvhadvhsubvmclevmmcvmovavmov" + "uvmptvmwrivpandvpextrwvpinsvpmaxvpminvprolvprorvpsadvpsigvpslvpsllvpsravpsrlvsqr" + "vtes"; + const InstDB::InstNameIndex InstDB::instNameIndex[26] = { { Inst::kIdAaa , Inst::kIdArpl + 1 }, @@ -3071,8 +4619,8 @@ const InstDB::InstSignature InstDB::_instSignatureTable[] = { ROW(3, 1, 1, 2, 34 , 33 , 27 , 0 , 0 , 0 ), // {, , r16|m16|mem} ROW(3, 1, 1, 2, 35 , 36 , 28 , 0 , 0 , 0 ), // {, , r32|m32|mem} ROW(3, 0, 1, 2, 37 , 38 , 15 , 0 , 0 , 0 ), // {, , r64|m64|mem} - ROW(2, 1, 1, 0, 4 , 39 , 0 , 0 , 0 , 0 ), // {r16, r16|m16|mem|i8|i16} - ROW(2, 1, 1, 0, 6 , 40 , 0 , 0 , 0 , 0 ), // {r32, r32|m32|mem|i8|i32} + ROW(2, 1, 1, 0, 4 , 39 , 0 , 0 , 0 , 0 ), // {r16, r16|m16|mem|i8|i16|u16} + ROW(2, 1, 1, 0, 6 , 40 , 0 , 0 , 0 , 0 ), // {r32, r32|m32|mem|i8|i32|u32} ROW(2, 0, 1, 0, 8 , 41 , 0 , 0 , 0 , 0 ), // {r64, r64|m64|mem|i8|i32} ROW(3, 1, 1, 0, 4 , 27 , 42 , 0 , 0 , 0 ), // {r16, r16|m16|mem, i8|i16|u16} ROW(3, 1, 1, 0, 6 , 28 , 43 , 0 , 0 , 0 ), // {r32, r32|m32|mem, i8|i32|u32} @@ -3589,8 +5137,8 @@ const InstDB::OpSignature InstDB::_opSignatureTable[] = { ROW(F(RegGpd) | F(FlagImplicit), 0x01), ROW(F(RegGpq) | F(FlagImplicit), 0x04), ROW(F(RegGpq) | F(FlagImplicit), 0x01), - ROW(F(RegGpw) | F(MemUnspecified) | F(Mem16) | F(ImmI8) | F(ImmI16), 0x00), - ROW(F(RegGpd) | F(MemUnspecified) | F(Mem32) | F(ImmI8) | F(ImmI32), 0x00), + ROW(F(RegGpw) | F(MemUnspecified) | F(Mem16) | F(ImmI8) | F(ImmI16) | F(ImmU16), 0x00), + ROW(F(RegGpd) | F(MemUnspecified) | F(Mem32) | F(ImmI8) | F(ImmI32) | F(ImmU32), 0x00), ROW(F(RegGpq) | F(MemUnspecified) | F(Mem64) | F(ImmI8) | F(ImmI32), 0x00), ROW(F(ImmI8) | F(ImmI16) | F(ImmU16), 0x00), ROW(F(ImmI8) | F(ImmI32) | F(ImmU32), 0x00), @@ -3761,59 +5309,59 @@ const uint8_t InstDB::rwInfoIndexA[Inst::_kIdCount] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 59, 0, 60, 0, 61, 0, 60, 0, 60, 0, 60, 0, 0, 0, 0, 0, 62, 63, 63, 63, 58, 60, 0, 0, 0, 9, 0, 0, 4, 4, 5, 6, 0, 0, 4, 4, 5, 6, 0, 0, 64, 65, 66, 66, 67, 47, 24, 36, 67, 52, 66, 66, 68, 69, 69, 70, - 71, 71, 72, 72, 59, 59, 67, 59, 59, 71, 71, 73, 48, 52, 74, 48, 7, 7, 47, 75, - 9, 66, 66, 75, 0, 35, 4, 4, 5, 6, 0, 76, 0, 0, 77, 0, 2, 4, 4, 78, 79, 9, 9, - 9, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 80, 3, 0, 0, 0, 3, 3, - 4, 3, 0, 0, 3, 3, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 27, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 27, 80, 80, 80, 27, 27, 80, 80, 80, 3, 3, 3, 81, 3, 3, 3, - 27, 27, 0, 0, 0, 0, 3, 3, 4, 4, 3, 3, 4, 4, 4, 4, 3, 3, 4, 4, 82, 83, 84, 24, - 24, 24, 83, 83, 84, 24, 24, 24, 83, 4, 3, 80, 3, 3, 4, 3, 3, 0, 0, 0, 9, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 85, 3, 3, 0, 3, 3, - 3, 85, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 86, 0, 3, 3, 4, 3, 87, 87, 4, 87, 0, - 0, 0, 0, 0, 0, 0, 3, 88, 7, 89, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, - 0, 0, 0, 88, 88, 0, 0, 0, 0, 0, 0, 7, 89, 0, 0, 88, 88, 0, 0, 2, 91, 0, 0, 0, + 71, 71, 72, 72, 59, 59, 67, 59, 59, 71, 71, 73, 48, 52, 74, 75, 7, 7, 76, 77, + 9, 66, 66, 77, 0, 35, 4, 4, 5, 6, 0, 78, 0, 0, 79, 0, 2, 4, 4, 80, 81, 9, 9, + 9, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 82, 3, 0, 0, 0, 3, 3, + 4, 3, 0, 0, 3, 3, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 83, 27, 27, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 27, 82, 82, 82, 27, 27, 82, 82, 82, 3, 3, 3, 84, 3, 3, 3, + 27, 27, 0, 0, 0, 0, 3, 3, 4, 4, 3, 3, 4, 4, 4, 4, 3, 3, 4, 4, 85, 86, 87, 24, + 24, 24, 86, 86, 87, 24, 24, 24, 86, 4, 3, 82, 3, 3, 4, 3, 3, 0, 0, 0, 9, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 88, 3, 3, 0, 3, 3, + 3, 88, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 89, 0, 3, 3, 4, 3, 90, 90, 4, 90, 0, + 0, 0, 0, 0, 0, 0, 3, 91, 7, 92, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 91, 91, 0, 0, 0, 0, 0, 0, 7, 92, 0, 0, 91, 91, 0, 0, 2, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 0, 88, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 7, 7, 26, 89, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 2, 4, 4, 5, 6, 0, 0, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 93, 93, 0, 94, 0, 0, 9, 9, 20, 21, 95, 95, 0, 0, - 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 28, 97, 98, 97, 98, 96, 28, 97, 98, 97, 98, - 99, 100, 0, 0, 0, 0, 0, 0, 20, 101, 21, 102, 102, 103, 75, 9, 0, 75, 104, 105, - 104, 9, 104, 9, 106, 107, 103, 106, 107, 106, 107, 9, 9, 9, 103, 0, 75, 103, - 9, 103, 9, 105, 104, 0, 28, 0, 28, 0, 108, 0, 108, 0, 0, 0, 0, 0, 33, 33, 104, - 9, 104, 9, 106, 107, 106, 107, 9, 9, 9, 103, 9, 103, 28, 28, 108, 108, 33, - 33, 103, 75, 9, 9, 105, 104, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 109, 109, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 0, 91, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 26, 92, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 2, 4, 4, 5, 6, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 96, 96, 0, 97, 0, 0, 9, 9, 20, 21, 98, 98, 0, + 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 28, 100, 101, 100, 101, 99, 28, 100, 101, + 100, 101, 102, 103, 0, 0, 0, 0, 0, 0, 20, 104, 21, 105, 105, 106, 77, 9, 0, 77, + 107, 108, 107, 9, 107, 9, 109, 110, 106, 109, 110, 109, 110, 9, 9, 9, 106, + 0, 77, 106, 9, 106, 9, 108, 107, 0, 28, 0, 28, 0, 111, 0, 111, 0, 0, 0, 0, 0, + 33, 33, 107, 9, 107, 9, 109, 110, 109, 110, 9, 9, 9, 106, 9, 106, 28, 28, 111, + 111, 33, 33, 106, 77, 9, 9, 108, 107, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 112, 112, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 27, 110, 60, 60, 0, 0, 0, 0, - 0, 0, 0, 0, 60, 111, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 112, 47, 113, 112, 112, 112, 112, 112, 112, 112, - 112, 0, 114, 114, 0, 71, 71, 115, 116, 67, 67, 67, 67, 117, 71, 118, 9, 9, - 73, 112, 112, 49, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, - 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 120, 33, 121, 121, 28, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 0, 0, 0, 0, - 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 60, 60, 111, 60, 7, 7, 7, 0, 7, 0, - 7, 7, 7, 7, 7, 7, 0, 7, 7, 81, 7, 0, 7, 0, 0, 7, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 27, 113, 60, 60, + 0, 0, 0, 0, 0, 0, 0, 0, 60, 114, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 115, 47, 116, 115, 115, 115, 115, 115, + 115, 115, 115, 0, 117, 117, 0, 71, 71, 118, 119, 67, 67, 67, 67, 120, 71, 121, + 9, 9, 73, 115, 115, 49, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 33, 124, 124, 28, 125, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 105, 105, 105, 0, + 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 60, 60, 114, 60, 7, 7, 7, + 0, 7, 0, 7, 7, 7, 7, 7, 7, 0, 7, 7, 84, 7, 0, 7, 0, 0, 7, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 123, 123, 124, 125, 121, 121, 121, 121, 82, 123, 126, 125, 124, 124, - 125, 126, 125, 124, 125, 127, 128, 103, 103, 103, 127, 124, 125, 126, 125, - 124, 125, 123, 125, 127, 128, 103, 103, 103, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, 129, 67, + 0, 0, 0, 0, 0, 0, 0, 126, 126, 127, 128, 124, 124, 124, 124, 85, 126, 129, 128, + 127, 127, 128, 129, 128, 127, 128, 130, 131, 106, 106, 106, 130, 127, 128, + 129, 128, 127, 128, 126, 128, 130, 131, 106, 106, 106, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 67, + 132, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 9, 0, 0, 109, 109, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 109, 109, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 67, 67, 0, 0, 0, 0, 0, 0, 0, 0, 67, 129, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 119, 119, 20, 101, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 130, 131, 0, 132, 0, 133, 0, 0, 0, 2, 4, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 112, 112, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 112, 112, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 67, 0, 0, 0, 0, 0, 0, 0, 0, 67, 132, 0, 0, 0, 0, 0, 0, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 20, 104, 21, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 133, 134, 133, 134, 0, 135, 0, 136, 0, 0, 0, 2, 4, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = { @@ -3836,68 +5384,68 @@ const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = { 0, 24, 0, 53, 0, 54, 0, 0, 0, 0, 0, 10, 0, 10, 24, 55, 56, 55, 0, 0, 0, 0, 0, 0, 55, 57, 57, 0, 58, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 61, 0, 0, 0, 0, 62, 0, 63, 20, 64, 20, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 6, - 5, 5, 0, 0, 0, 0, 66, 67, 0, 0, 0, 0, 68, 69, 0, 3, 3, 70, 22, 71, 72, 0, 0, + 0, 61, 0, 0, 61, 0, 0, 0, 0, 0, 5, 62, 0, 0, 0, 0, 63, 0, 64, 20, 65, 20, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, + 6, 5, 5, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 69, 70, 0, 3, 3, 71, 22, 72, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 73, 39, 74, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 10, - 10, 10, 10, 10, 10, 10, 0, 0, 2, 2, 2, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 79, 79, 80, 79, 80, 80, 80, 79, 79, 81, 82, 0, 83, 0, - 0, 0, 0, 0, 0, 84, 2, 2, 85, 86, 0, 0, 0, 11, 87, 0, 0, 4, 0, 0, 0, 88, 0, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 0, 0, 0, 74, 39, 75, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 10, + 10, 10, 10, 10, 10, 10, 0, 0, 2, 2, 2, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 79, 80, 79, 80, 80, 80, 79, 79, 81, 82, 0, 83, + 0, 0, 0, 0, 0, 0, 84, 2, 2, 85, 86, 0, 0, 0, 11, 87, 0, 0, 4, 0, 0, 0, 88, 0, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 89, 0, 32, 0, 0, 0, 5, 0, 0, 6, 0, 90, - 4, 0, 90, 4, 5, 5, 32, 19, 91, 79, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 91, 93, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 94, 94, 94, 94, 0, 0, 0, 0, 0, - 0, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 56, 96, 0, 0, 0, 0, 97, 98, 97, 98, 3, 3, - 3, 99, 100, 101, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 102, 102, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 103, 3, 104, 105, 106, 0, 0, + 4, 0, 90, 4, 5, 5, 32, 19, 91, 79, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 91, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 94, 94, 94, 94, 0, 0, 0, 0, + 0, 0, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 56, 96, 0, 0, 0, 0, 97, 98, 97, 98, 3, + 3, 3, 99, 100, 101, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 102, + 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 103, 3, 104, 105, 106, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 108, 0, 109, 0, 110, 0, 110, 0, 111, 112, 113, 114, 115, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 111, 112, 113, 0, 0, 3, 3, 3, 3, 99, 110, 101, 3, 116, 3, 55, 55, 0, 0, - 0, 0, 117, 118, 119, 118, 119, 117, 118, 119, 118, 119, 22, 120, 121, 120, 121, - 120, 120, 122, 123, 120, 120, 120, 124, 125, 126, 120, 120, 120, 124, 125, - 126, 120, 120, 120, 124, 125, 126, 120, 121, 127, 127, 128, 129, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 127, 127, 120, 120, 120, 124, 130, 126, 120, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 111, 112, 113, 0, 0, 3, 3, 3, 3, 99, 110, 101, 3, 116, 3, 55, 55, 0, + 0, 0, 0, 117, 118, 119, 118, 119, 117, 118, 119, 118, 119, 22, 120, 121, 120, + 121, 120, 120, 122, 123, 120, 120, 120, 124, 125, 126, 120, 120, 120, 124, 125, + 126, 120, 120, 120, 124, 125, 126, 120, 121, 127, 127, 128, 129, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 127, 127, 120, 120, 120, 124, 130, 126, 120, 120, 120, 124, 130, 126, 120, 120, 120, 124, 130, 126, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 127, 127, 127, 127, 128, 129, 120, 121, 120, 120, 120, 124, - 125, 126, 120, 120, 120, 124, 125, 126, 120, 120, 120, 124, 125, 126, 127, - 127, 128, 129, 120, 120, 120, 124, 130, 126, 120, 120, 120, 124, 130, 126, 120, - 120, 120, 131, 130, 132, 127, 127, 128, 129, 133, 133, 133, 77, 134, 135, 0, - 0, 0, 0, 136, 137, 10, 10, 10, 10, 10, 10, 10, 10, 137, 138, 0, 0, 0, 139, 140, - 141, 84, 84, 84, 139, 140, 141, 3, 3, 3, 3, 3, 3, 3, 142, 143, 144, 143, 144, - 142, 143, 144, 143, 144, 101, 0, 53, 58, 145, 145, 3, 3, 3, 99, 100, 101, + 120, 120, 120, 120, 127, 127, 127, 127, 128, 129, 120, 121, 120, 120, 120, + 124, 125, 126, 120, 120, 120, 124, 125, 126, 120, 120, 120, 124, 125, 126, 127, + 127, 128, 129, 120, 120, 120, 124, 130, 126, 120, 120, 120, 124, 130, 126, + 120, 120, 120, 131, 130, 132, 127, 127, 128, 129, 133, 133, 133, 78, 134, 135, + 0, 0, 0, 0, 136, 137, 10, 10, 10, 10, 10, 10, 10, 10, 137, 138, 0, 0, 0, 139, + 140, 141, 84, 84, 84, 139, 140, 141, 3, 3, 3, 3, 3, 3, 3, 142, 143, 144, 143, + 144, 142, 143, 144, 143, 144, 101, 0, 53, 58, 145, 145, 3, 3, 3, 99, 100, 101, 0, 146, 0, 3, 3, 3, 99, 100, 101, 0, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 149, 149, 150, 151, 151, 0, 0, 0, 0, 0, 0, 0, 152, 153, 0, 0, 154, 0, 0, 0, 3, 11, 146, 0, 0, 155, 147, 3, 3, 3, 99, 100, 101, 0, 11, 3, 3, 156, 156, 157, 157, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 102, 3, 0, 0, 0, 0, 0, 0, 3, 127, 103, 103, 3, 3, 3, 3, - 66, 67, 3, 3, 3, 3, 68, 69, 103, 103, 103, 103, 103, 103, 116, 116, 0, 0, 0, - 0, 116, 116, 116, 116, 116, 116, 0, 0, 120, 120, 120, 120, 158, 158, 3, 3, 3, - 120, 3, 3, 120, 120, 127, 127, 159, 159, 159, 3, 159, 3, 120, 120, 120, 120, - 120, 3, 0, 0, 0, 0, 70, 22, 71, 160, 137, 136, 138, 137, 0, 0, 0, 3, 0, 3, 0, + 3, 3, 3, 3, 3, 3, 3, 3, 102, 3, 0, 0, 0, 0, 0, 0, 3, 127, 103, 103, 3, 3, 3, + 3, 67, 68, 3, 3, 3, 3, 69, 70, 103, 103, 103, 103, 103, 103, 116, 116, 0, 0, + 0, 0, 116, 116, 116, 116, 116, 116, 0, 0, 120, 120, 120, 120, 158, 158, 3, 3, + 3, 120, 3, 3, 120, 120, 127, 127, 159, 159, 159, 3, 159, 3, 120, 120, 120, 120, + 120, 3, 0, 0, 0, 0, 71, 22, 72, 160, 137, 136, 138, 137, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 3, 3, 0, 161, 101, 99, 100, 0, 0, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 120, 120, 3, 3, 145, 145, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 163, 84, 84, 3, 3, 84, - 84, 3, 3, 164, 164, 164, 164, 3, 0, 0, 0, 0, 164, 164, 164, 164, 164, 164, 3, - 3, 120, 120, 120, 3, 164, 164, 3, 3, 120, 120, 120, 3, 3, 103, 84, 84, 84, 3, - 3, 3, 165, 166, 165, 3, 3, 3, 165, 165, 165, 3, 3, 3, 165, 165, 166, 165, 3, - 3, 3, 165, 3, 3, 3, 3, 3, 3, 3, 3, 120, 120, 0, 103, 103, 103, 103, 103, 103, - 103, 103, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 139, 141, 0, 0, 139, 141, 0, - 0, 139, 141, 0, 0, 140, 141, 84, 84, 84, 139, 140, 141, 84, 84, 84, 139, 140, + 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 163, 84, 84, 3, 3, + 84, 84, 3, 3, 164, 164, 164, 164, 3, 0, 0, 0, 0, 164, 164, 164, 164, 164, 164, + 3, 3, 120, 120, 120, 3, 164, 164, 3, 3, 120, 120, 120, 3, 3, 103, 84, 84, 84, + 3, 3, 3, 165, 166, 165, 3, 3, 3, 167, 165, 168, 3, 3, 3, 167, 165, 166, 165, + 3, 3, 3, 167, 3, 3, 3, 3, 3, 3, 3, 3, 120, 120, 0, 103, 103, 103, 103, 103, 103, + 103, 103, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 139, 141, 0, 0, 139, 141, + 0, 0, 139, 141, 0, 0, 140, 141, 84, 84, 84, 139, 140, 141, 84, 84, 84, 139, 140, 141, 84, 84, 139, 141, 0, 0, 139, 141, 0, 0, 139, 141, 0, 0, 140, 141, 3, 3, - 3, 99, 100, 101, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 3, 3, 3, 3, 3, 3, - 0, 0, 0, 139, 140, 141, 92, 3, 3, 3, 99, 100, 101, 0, 0, 0, 0, 0, 3, 3, 3, 3, - 3, 3, 0, 0, 0, 0, 56, 56, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, - 168, 168, 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, 167, 0, 0 + 3, 99, 100, 101, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 3, 3, 3, 3, 3, + 3, 0, 0, 0, 139, 140, 141, 92, 3, 3, 3, 99, 100, 101, 0, 0, 0, 0, 0, 3, 3, 3, + 3, 3, 3, 0, 0, 0, 0, 56, 56, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 170, 170, 170, 170, 171, 171, 171, 171, 171, 171, 171, 171, 169, 0, 0 }; const InstDB::RWInfo InstDB::rwInfoA[] = { - { InstDB::RWInfo::kCategoryGeneric , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #0 [ref=1008x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #0 [ref=1007x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 1 , 0 , 0 , 0 , 0 , 0 } }, // #1 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 1 , { 2 , 3 , 0 , 0 , 0 , 0 } }, // #2 [ref=7x] { InstDB::RWInfo::kCategoryGeneric , 2 , { 2 , 3 , 0 , 0 , 0 , 0 } }, // #3 [ref=96x] @@ -3944,8 +5492,8 @@ const InstDB::RWInfo InstDB::rwInfoA[] = { { InstDB::RWInfo::kCategoryGeneric , 0 , { 22, 29, 0 , 0 , 0 , 0 } }, // #44 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 55, 0 , 0 , 0 , 0 , 0 } }, // #45 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 23, { 56, 40, 0 , 0 , 0 , 0 } }, // #46 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 24, { 44, 9 , 0 , 0 , 0 , 0 } }, // #47 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 25, { 35, 7 , 0 , 0 , 0 , 0 } }, // #48 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 24, { 44, 9 , 0 , 0 , 0 , 0 } }, // #47 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 25, { 35, 7 , 0 , 0 , 0 , 0 } }, // #48 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 26, { 48, 13, 0 , 0 , 0 , 0 } }, // #49 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 56, 40, 0 , 0 , 0 , 0 } }, // #50 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 44, 9 , 0 , 0 , 0 , 0 } }, // #51 [ref=1x] @@ -3972,69 +5520,72 @@ const InstDB::RWInfo InstDB::rwInfoA[] = { { InstDB::RWInfo::kCategoryGeneric , 0 , { 56, 5 , 0 , 0 , 0 , 0 } }, // #72 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 28, { 44, 9 , 0 , 0 , 0 , 0 } }, // #73 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 63, 20, 0 , 0 , 0 , 0 } }, // #74 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 14, { 11, 3 , 0 , 0 , 0 , 0 } }, // #75 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 17, 29, 0 , 0 , 0 , 0 } }, // #76 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 3 , 3 , 0 , 0 , 0 , 0 } }, // #77 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 52, 22, 0 , 0 , 0 , 0 } }, // #78 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 52, 66, 0 , 0 , 0 , 0 } }, // #79 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 26, 7 , 0 , 0 , 0 , 0 } }, // #80 [ref=18x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 69, 5 , 0 , 0 , 0 , 0 } }, // #81 [ref=2x] - { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #82 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #83 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #84 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 4 , 0 , 0 , 0 , 0 , 0 } }, // #85 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #86 [ref=1x] - { InstDB::RWInfo::kCategoryPunpcklxx , 34, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #87 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 71, 0 , 0 , 0 , 0 } }, // #88 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 37, 9 , 0 , 0 , 0 , 0 } }, // #89 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 50, 0 , 0 , 0 , 0 } }, // #90 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 22, 21, 0 , 0 , 0 , 0 } }, // #91 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 63, 22, 0 , 0 , 0 , 0 } }, // #92 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 8 , { 74, 3 , 0 , 0 , 0 , 0 } }, // #93 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 8 , { 11, 43, 0 , 0 , 0 , 0 } }, // #94 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 53, 9 , 0 , 0 , 0 , 0 } }, // #95 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 13, { 80, 5 , 0 , 0 , 0 , 0 } }, // #96 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 13, { 11, 5 , 0 , 0 , 0 , 0 } }, // #97 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 39, { 74, 81, 0 , 0 , 0 , 0 } }, // #98 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 40, { 11, 7 , 0 , 0 , 0 , 0 } }, // #99 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 41, { 11, 9 , 0 , 0 , 0 , 0 } }, // #100 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 13, 13, 0 , 0 , 0 , 0 } }, // #101 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #102 [ref=7x] - { InstDB::RWInfo::kCategoryVmov2_1 , 42, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #103 [ref=14x] - { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #104 [ref=7x] - { InstDB::RWInfo::kCategoryGeneric , 14, { 10, 3 , 0 , 0 , 0 , 0 } }, // #105 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 42, { 11, 3 , 0 , 0 , 0 , 0 } }, // #106 [ref=5x] - { InstDB::RWInfo::kCategoryGeneric , 43, { 11, 5 , 0 , 0 , 0 , 0 } }, // #107 [ref=5x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 11, 5 , 0 , 0 , 0 , 0 } }, // #108 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 47, { 74, 43, 0 , 0 , 0 , 0 } }, // #109 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 44, 9 , 0 , 0 , 0 , 0 } }, // #110 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 18, { 2 , 3 , 0 , 0 , 0 , 0 } }, // #111 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 54, { 11, 3 , 0 , 0 , 0 , 0 } }, // #112 [ref=12x] - { InstDB::RWInfo::kCategoryVmovddup , 34, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #113 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 35, 61, 0 , 0 , 0 , 0 } }, // #114 [ref=2x] - { InstDB::RWInfo::kCategoryVmovmskpd , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #115 [ref=1x] - { InstDB::RWInfo::kCategoryVmovmskps , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #116 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 55, { 35, 7 , 0 , 0 , 0 , 0 } }, // #117 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 21, { 48, 13, 0 , 0 , 0 , 0 } }, // #118 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 2 , { 3 , 3 , 0 , 0 , 0 , 0 } }, // #119 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 15, { 11, 40, 0 , 0 , 0 , 0 } }, // #120 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 7 , 0 , 0 , 0 , 0 } }, // #121 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 11, 13, 0 , 0 , 0 , 0 } }, // #122 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 35, 3 , 0 , 0 , 0 , 0 } }, // #123 [ref=4x] - { InstDB::RWInfo::kCategoryVmov1_4 , 58, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #124 [ref=6x] - { InstDB::RWInfo::kCategoryVmov1_2 , 44, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #125 [ref=9x] - { InstDB::RWInfo::kCategoryVmov1_8 , 59, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #126 [ref=3x] - { InstDB::RWInfo::kCategoryVmov4_1 , 43, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #127 [ref=4x] - { InstDB::RWInfo::kCategoryVmov8_1 , 60, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #128 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 18, { 11, 3 , 0 , 0 , 0 , 0 } }, // #129 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 17, { 44, 9 , 0 , 0 , 0 , 0 } }, // #130 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 32, { 35, 7 , 0 , 0 , 0 , 0 } }, // #131 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 2 , 0 , 0 , 0 , 0 } }, // #132 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 54, { 2 , 2 , 0 , 0 , 0 , 0 } } // #133 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 31, { 35, 7 , 0 , 0 , 0 , 0 } }, // #75 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 33, { 44, 9 , 0 , 0 , 0 , 0 } }, // #76 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 14, { 11, 3 , 0 , 0 , 0 , 0 } }, // #77 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 17, 29, 0 , 0 , 0 , 0 } }, // #78 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 3 , 3 , 0 , 0 , 0 , 0 } }, // #79 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 52, 22, 0 , 0 , 0 , 0 } }, // #80 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 52, 66, 0 , 0 , 0 , 0 } }, // #81 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 26, 7 , 0 , 0 , 0 , 0 } }, // #82 [ref=18x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #83 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 69, 5 , 0 , 0 , 0 , 0 } }, // #84 [ref=2x] + { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #85 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #86 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #87 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 4 , 0 , 0 , 0 , 0 , 0 } }, // #88 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #89 [ref=1x] + { InstDB::RWInfo::kCategoryPunpcklxx , 38, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #90 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 70, 0 , 0 , 0 , 0 } }, // #91 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 37, 9 , 0 , 0 , 0 , 0 } }, // #92 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 50, 0 , 0 , 0 , 0 } }, // #93 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 22, 21, 0 , 0 , 0 , 0 } }, // #94 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 63, 22, 0 , 0 , 0 , 0 } }, // #95 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 8 , { 73, 3 , 0 , 0 , 0 , 0 } }, // #96 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 8 , { 11, 43, 0 , 0 , 0 , 0 } }, // #97 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 53, 9 , 0 , 0 , 0 , 0 } }, // #98 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 13, { 79, 5 , 0 , 0 , 0 , 0 } }, // #99 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 13, { 11, 5 , 0 , 0 , 0 , 0 } }, // #100 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 43, { 73, 80, 0 , 0 , 0 , 0 } }, // #101 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 44, { 11, 7 , 0 , 0 , 0 , 0 } }, // #102 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 45, { 11, 9 , 0 , 0 , 0 , 0 } }, // #103 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 13, 13, 0 , 0 , 0 , 0 } }, // #104 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #105 [ref=7x] + { InstDB::RWInfo::kCategoryVmov2_1 , 46, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #106 [ref=14x] + { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #107 [ref=7x] + { InstDB::RWInfo::kCategoryGeneric , 14, { 10, 3 , 0 , 0 , 0 , 0 } }, // #108 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 46, { 11, 3 , 0 , 0 , 0 , 0 } }, // #109 [ref=5x] + { InstDB::RWInfo::kCategoryGeneric , 47, { 11, 5 , 0 , 0 , 0 , 0 } }, // #110 [ref=5x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 11, 5 , 0 , 0 , 0 , 0 } }, // #111 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 51, { 73, 43, 0 , 0 , 0 , 0 } }, // #112 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 44, 9 , 0 , 0 , 0 , 0 } }, // #113 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 18, { 2 , 3 , 0 , 0 , 0 , 0 } }, // #114 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 58, { 11, 3 , 0 , 0 , 0 , 0 } }, // #115 [ref=12x] + { InstDB::RWInfo::kCategoryVmovddup , 38, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #116 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 35, 61, 0 , 0 , 0 , 0 } }, // #117 [ref=2x] + { InstDB::RWInfo::kCategoryVmovmskpd , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #118 [ref=1x] + { InstDB::RWInfo::kCategoryVmovmskps , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #119 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 59, { 35, 7 , 0 , 0 , 0 , 0 } }, // #120 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 21, { 48, 13, 0 , 0 , 0 , 0 } }, // #121 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 2 , { 3 , 3 , 0 , 0 , 0 , 0 } }, // #122 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 15, { 11, 40, 0 , 0 , 0 , 0 } }, // #123 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 7 , 0 , 0 , 0 , 0 } }, // #124 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 11, 13, 0 , 0 , 0 , 0 } }, // #125 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 35, 3 , 0 , 0 , 0 , 0 } }, // #126 [ref=4x] + { InstDB::RWInfo::kCategoryVmov1_4 , 62, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #127 [ref=6x] + { InstDB::RWInfo::kCategoryVmov1_2 , 48, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #128 [ref=9x] + { InstDB::RWInfo::kCategoryVmov1_8 , 63, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #129 [ref=3x] + { InstDB::RWInfo::kCategoryVmov4_1 , 47, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #130 [ref=4x] + { InstDB::RWInfo::kCategoryVmov8_1 , 64, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #131 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 18, { 11, 3 , 0 , 0 , 0 , 0 } }, // #132 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 17, { 44, 9 , 0 , 0 , 0 , 0 } }, // #133 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 35, 7 , 0 , 0 , 0 , 0 } }, // #134 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 2 , 0 , 0 , 0 , 0 } }, // #135 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 58, { 2 , 2 , 0 , 0 , 0 , 0 } } // #136 [ref=1x] }; const InstDB::RWInfo InstDB::rwInfoB[] = { - { InstDB::RWInfo::kCategoryGeneric , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #0 [ref=775x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #0 [ref=773x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 1 , 0 , 0 , 0 , 0 , 0 } }, // #1 [ref=5x] { InstDB::RWInfo::kCategoryGeneric , 3 , { 10, 5 , 0 , 0 , 0 , 0 } }, // #2 [ref=7x] { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 0 , 0 , 0 } }, // #3 [ref=193x] @@ -4095,24 +5646,24 @@ const InstDB::RWInfo InstDB::rwInfoB[] = { { InstDB::RWInfo::kCategoryGeneric , 0 , { 5 , 5 , 59, 0 , 0 , 0 } }, // #58 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 7 , 7 , 59, 0 , 0 , 0 } }, // #59 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 19, 29, 60, 0 , 0 , 0 } }, // #60 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 64, 42, 3 , 0 , 0 , 0 } }, // #61 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 65, 0 , 0 } }, // #62 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 17, 29, 30, 0 , 0 , 0 } }, // #63 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #64 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 2 , { 2 , 3 , 0 , 0 , 0 , 0 } }, // #65 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 67, 17, 60 } }, // #66 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 68, 17, 60 } }, // #67 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 67, 0 , 0 } }, // #68 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 68, 0 , 0 } }, // #69 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 56, 5 , 0 , 0 , 0 , 0 } }, // #70 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 32, { 35, 5 , 0 , 0 , 0 , 0 } }, // #71 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 33, { 48, 3 , 0 , 0 , 0 , 0 } }, // #72 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 40, 0 , 0 , 0 , 0 } }, // #73 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #74 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #75 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 70, 0 , 0 , 0 , 0 , 0 } }, // #76 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 35, 7 , 0 , 0 , 0 , 0 } }, // #77 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 65, 0 , 0 , 0 , 0 , 0 } }, // #78 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 32, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #61 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 64, 42, 3 , 0 , 0 , 0 } }, // #62 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 65, 0 , 0 } }, // #63 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 17, 29, 30, 0 , 0 , 0 } }, // #64 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #65 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 2 , { 2 , 3 , 0 , 0 , 0 , 0 } }, // #66 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 67, 17, 60 } }, // #67 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 68, 17, 60 } }, // #68 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 67, 0 , 0 } }, // #69 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 68, 0 , 0 } }, // #70 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 34, { 56, 5 , 0 , 0 , 0 , 0 } }, // #71 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 35, 5 , 0 , 0 , 0 , 0 } }, // #72 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 37, { 48, 3 , 0 , 0 , 0 , 0 } }, // #73 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 40, 0 , 0 , 0 , 0 } }, // #74 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #75 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #76 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 11, 0 , 0 , 0 , 0 , 0 } }, // #77 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 35, 7 , 0 , 0 , 0 , 0 } }, // #78 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 0 , 0 , 0 , 0 , 0 } }, // #79 [ref=6x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 50, 29, 0 , 0 , 0 } }, // #80 [ref=5x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 44, 0 , 0 , 0 , 0 , 0 } }, // #81 [ref=1x] @@ -4121,64 +5672,64 @@ const InstDB::RWInfo InstDB::rwInfoB[] = { { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 0 , 0 , 0 , 0 } }, // #84 [ref=19x] { InstDB::RWInfo::kCategoryGeneric , 4 , { 36, 7 , 0 , 0 , 0 , 0 } }, // #85 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 5 , { 37, 9 , 0 , 0 , 0 , 0 } }, // #86 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 72, 0 , 0 , 0 , 0 , 0 } }, // #87 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 71, 0 , 0 , 0 , 0 , 0 } }, // #87 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 7 , 0 , 0 , 0 , 0 , 0 } }, // #88 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 73, 0 , 0 , 0 , 0 , 0 } }, // #89 [ref=30x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 71, 0 , 0 , 0 } }, // #90 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 11, 0 , 0 , 0 , 0 , 0 } }, // #91 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 34, { 72, 0 , 0 , 0 , 0 , 0 } }, // #89 [ref=30x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 70, 0 , 0 , 0 } }, // #90 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 39, { 11, 0 , 0 , 0 , 0 , 0 } }, // #91 [ref=3x] { InstDB::RWInfo::kCategoryGeneric , 28, { 44, 0 , 0 , 0 , 0 , 0 } }, // #92 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 16, { 74, 0 , 0 , 0 , 0 , 0 } }, // #93 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 75, 43, 43, 0 , 0 , 0 } }, // #94 [ref=5x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 74, 0 , 0 , 0 , 0 , 0 } }, // #95 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 16, { 73, 0 , 0 , 0 , 0 , 0 } }, // #93 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 74, 43, 43, 0 , 0 , 0 } }, // #94 [ref=5x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 73, 0 , 0 , 0 , 0 , 0 } }, // #95 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 9 , 60, 17, 0 , 0 , 0 } }, // #96 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 13, { 75, 76, 77, 77, 77, 5 } }, // #97 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 13, { 4 , 78, 79, 79, 79, 5 } }, // #98 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 7 , 0 , 0 , 0 } }, // #99 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 10, 5 , 13, 0 , 0 , 0 } }, // #100 [ref=7x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 10, 5 , 9 , 0 , 0 , 0 } }, // #101 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 13, { 74, 75, 76, 76, 76, 5 } }, // #97 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 13, { 4 , 77, 78, 78, 78, 5 } }, // #98 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 10, 5 , 7 , 0 , 0 , 0 } }, // #99 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 10, 5 , 13, 0 , 0 , 0 } }, // #100 [ref=7x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 5 , 9 , 0 , 0 , 0 } }, // #101 [ref=9x] { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 3 , 0 , 0 } }, // #102 [ref=3x] { InstDB::RWInfo::kCategoryGeneric , 6 , { 35, 3 , 3 , 0 , 0 , 0 } }, // #103 [ref=18x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 11, 5 , 7 , 0 , 0 , 0 } }, // #104 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 35, 13, 13, 0 , 0 , 0 } }, // #105 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 11, 5 , 9 , 0 , 0 , 0 } }, // #106 [ref=1x] - { InstDB::RWInfo::kCategoryVmov1_2 , 44, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #107 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 5 , 0 , 0 , 0 } }, // #108 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 82, 7 , 0 , 0 , 0 } }, // #109 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 10, 5 , 5 , 0 , 0 , 0 } }, // #110 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 61, 3 , 0 , 0 , 0 } }, // #111 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 3 , 3 , 0 , 0 , 0 } }, // #112 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 82, 3 , 0 , 0 , 0 } }, // #113 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 10, 61, 9 , 0 , 0 , 0 } }, // #114 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 10, 5 , 5 , 0 , 0 , 0 } }, // #115 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 10, 5 , 5 , 0 , 0 , 0 } }, // #116 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 48, { 10, 81, 0 , 0 , 0 , 0 } }, // #117 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 48, { 10, 3 , 0 , 0 , 0 , 0 } }, // #118 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 49, { 80, 43, 0 , 0 , 0 , 0 } }, // #119 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 11, 5 , 7 , 0 , 0 , 0 } }, // #104 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 35, 13, 13, 0 , 0 , 0 } }, // #105 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 11, 5 , 9 , 0 , 0 , 0 } }, // #106 [ref=1x] + { InstDB::RWInfo::kCategoryVmov1_2 , 48, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #107 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 10, 5 , 5 , 0 , 0 , 0 } }, // #108 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 10, 81, 7 , 0 , 0 , 0 } }, // #109 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 10, 5 , 5 , 0 , 0 , 0 } }, // #110 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 49, { 10, 61, 3 , 0 , 0 , 0 } }, // #111 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 49, { 10, 3 , 3 , 0 , 0 , 0 } }, // #112 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 49, { 10, 81, 3 , 0 , 0 , 0 } }, // #113 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 61, 9 , 0 , 0 , 0 } }, // #114 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 5 , 5 , 0 , 0 , 0 } }, // #115 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 50, { 10, 5 , 5 , 0 , 0 , 0 } }, // #116 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 52, { 10, 80, 0 , 0 , 0 , 0 } }, // #117 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 52, { 10, 3 , 0 , 0 , 0 , 0 } }, // #118 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 53, { 79, 43, 0 , 0 , 0 , 0 } }, // #119 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 6 , { 2 , 3 , 3 , 0 , 0 , 0 } }, // #120 [ref=82x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 4 , 5 , 5 , 0 , 0 , 0 } }, // #121 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 4 , 61, 7 , 0 , 0 , 0 } }, // #122 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 4 , 82, 9 , 0 , 0 , 0 } }, // #123 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #124 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 4 , 5 , 5 , 0 , 0 , 0 } }, // #125 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #126 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 50, { 11, 3 , 3 , 3 , 0 , 0 } }, // #127 [ref=15x] - { InstDB::RWInfo::kCategoryGeneric , 51, { 35, 7 , 7 , 7 , 0 , 0 } }, // #128 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 52, { 44, 9 , 9 , 9 , 0 , 0 } }, // #129 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 4 , 5 , 13, 0 , 0 , 0 } }, // #130 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 26, 7 , 7 , 0 , 0 , 0 } }, // #131 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 53, 9 , 9 , 0 , 0 , 0 } }, // #132 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 4 , 5 , 5 , 0 , 0 , 0 } }, // #121 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 4 , 61, 7 , 0 , 0 , 0 } }, // #122 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 4 , 81, 9 , 0 , 0 , 0 } }, // #123 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #124 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 4 , 5 , 5 , 0 , 0 , 0 } }, // #125 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #126 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 54, { 11, 3 , 3 , 3 , 0 , 0 } }, // #127 [ref=15x] + { InstDB::RWInfo::kCategoryGeneric , 55, { 35, 7 , 7 , 7 , 0 , 0 } }, // #128 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 56, { 44, 9 , 9 , 9 , 0 , 0 } }, // #129 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 4 , 5 , 13, 0 , 0 , 0 } }, // #130 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 26, 7 , 7 , 0 , 0 , 0 } }, // #131 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 53, 9 , 9 , 0 , 0 , 0 } }, // #132 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 14, { 35, 3 , 0 , 0 , 0 , 0 } }, // #133 [ref=3x] { InstDB::RWInfo::kCategoryGeneric , 27, { 35, 13, 0 , 0 , 0 , 0 } }, // #134 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 5 , { 35, 9 , 0 , 0 , 0 , 0 } }, // #135 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 8 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #136 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #137 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 18, { 4 , 3 , 4 , 0 , 0 , 0 } }, // #138 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 61, 7 , 0 , 0 , 0 } }, // #139 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 10, 83, 13, 0 , 0 , 0 } }, // #140 [ref=7x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 10, 82, 9 , 0 , 0 , 0 } }, // #141 [ref=13x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 80, 81, 5 , 0 , 0 , 0 } }, // #142 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 11, 3 , 5 , 0 , 0 , 0 } }, // #143 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 53, { 74, 43, 81, 0 , 0 , 0 } }, // #144 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 40, { 10, 61, 7 , 0 , 0 , 0 } }, // #139 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 41, { 10, 82, 13, 0 , 0 , 0 } }, // #140 [ref=7x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 81, 9 , 0 , 0 , 0 } }, // #141 [ref=13x] + { InstDB::RWInfo::kCategoryGeneric , 50, { 79, 80, 5 , 0 , 0 , 0 } }, // #142 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 50, { 11, 3 , 5 , 0 , 0 , 0 } }, // #143 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 57, { 73, 43, 80, 0 , 0 , 0 } }, // #144 [ref=4x] { InstDB::RWInfo::kCategoryVmaskmov , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #145 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 12, { 35, 0 , 0 , 0 , 0 , 0 } }, // #146 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 22, 0 , 0 , 0 , 0 , 0 } }, // #147 [ref=2x] @@ -4187,30 +5738,32 @@ const InstDB::RWInfo InstDB::rwInfoB[] = { { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 7 , 7 , 0 , 0 , 0 } }, // #150 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 12, { 10, 61, 7 , 0 , 0 , 0 } }, // #151 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 61, 7 , 0 , 0 , 0 } }, // #152 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 83, 13, 0 , 0 , 0 } }, // #153 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 82, 9 , 0 , 0 , 0 } }, // #154 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 84, 0 , 0 , 0 , 0 , 0 } }, // #155 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 56, { 85, 86, 3 , 3 , 0 , 0 } }, // #156 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 13, { 74, 76, 77, 77, 77, 5 } }, // #157 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 53, { 80, 81, 81, 0 , 0 , 0 } }, // #158 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 82, 13, 0 , 0 , 0 } }, // #153 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 10, 81, 9 , 0 , 0 , 0 } }, // #154 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 83, 0 , 0 , 0 , 0 , 0 } }, // #155 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 60, { 84, 85, 3 , 3 , 0 , 0 } }, // #156 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 13, { 73, 75, 76, 76, 76, 5 } }, // #157 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 57, { 79, 80, 80, 0 , 0 , 0 } }, // #158 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 22, { 11, 3 , 3 , 0 , 0 , 0 } }, // #159 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 7 , { 48, 5 , 0 , 0 , 0 , 0 } }, // #160 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 57, { 10, 5 , 40, 0 , 0 , 0 } }, // #161 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 10, 5 , 5 , 5 , 0 , 0 } }, // #162 [ref=12x] - { InstDB::RWInfo::kCategoryGeneric , 61, { 10, 5 , 5 , 5 , 0 , 0 } }, // #163 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 62, { 10, 5 , 5 , 0 , 0 , 0 } }, // #164 [ref=12x] - { InstDB::RWInfo::kCategoryGeneric , 22, { 11, 3 , 5 , 0 , 0 , 0 } }, // #165 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 63, { 11, 3 , 0 , 0 , 0 , 0 } }, // #166 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 60, 17, 29, 0 , 0 , 0 } }, // #167 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 8 , { 3 , 60, 17, 0 , 0 , 0 } }, // #168 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 8 , { 11, 60, 17, 0 , 0 , 0 } } // #169 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 61, { 10, 5 , 40, 0 , 0 , 0 } }, // #161 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 50, { 10, 5 , 5 , 5 , 0 , 0 } }, // #162 [ref=12x] + { InstDB::RWInfo::kCategoryGeneric , 65, { 10, 5 , 5 , 5 , 0 , 0 } }, // #163 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 66, { 10, 5 , 5 , 0 , 0 , 0 } }, // #164 [ref=12x] + { InstDB::RWInfo::kCategoryGeneric , 67, { 11, 3 , 5 , 0 , 0 , 0 } }, // #165 [ref=5x] + { InstDB::RWInfo::kCategoryGeneric , 68, { 11, 3 , 0 , 0 , 0 , 0 } }, // #166 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 69, { 11, 3 , 5 , 0 , 0 , 0 } }, // #167 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 22, { 11, 3 , 5 , 0 , 0 , 0 } }, // #168 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 60, 17, 29, 0 , 0 , 0 } }, // #169 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 8 , { 3 , 60, 17, 0 , 0 , 0 } }, // #170 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 8 , { 11, 60, 17, 0 , 0 , 0 } } // #171 [ref=8x] }; const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kNone }, // #0 [ref=16519x] { 0x0000000000000003u, 0x0000000000000003u, 0x00, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kRegPhysId }, // #1 [ref=10x] { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt }, // #2 [ref=236x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #3 [ref=1077x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #3 [ref=1078x] { 0x000000000000FFFFu, 0x000000000000FFFFu, 0xFF, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt }, // #4 [ref=108x] { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #5 [ref=348x] { 0x00000000000000FFu, 0x00000000000000FFu, 0xFF, 0, { 0 }, OpRWFlags::kRW }, // #6 [ref=18x] @@ -4218,7 +5771,7 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x000000000000000Fu, 0x000000000000000Fu, 0xFF, 0, { 0 }, OpRWFlags::kRW }, // #8 [ref=18x] { 0x000000000000000Fu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #9 [ref=135x] { 0x0000000000000000u, 0x000000000000FFFFu, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #10 [ref=184x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #11 [ref=455x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #11 [ref=456x] { 0x0000000000000003u, 0x0000000000000003u, 0xFF, 0, { 0 }, OpRWFlags::kRW }, // #12 [ref=1x] { 0x0000000000000003u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #13 [ref=63x] { 0x000000000000FFFFu, 0x0000000000000000u, 0x00, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #14 [ref=4x] @@ -4272,32 +5825,31 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x0000000000000000u, 0x000000000000FF00u, 0xFF, 0, { 0 }, OpRWFlags::kWrite }, // #62 [ref=1x] { 0x0000000000000000u, 0x0000000000000000u, 0x07, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kMemBaseRW | OpRWFlags::kMemBasePostModify | OpRWFlags::kMemPhysId }, // #63 [ref=2x] { 0x0000000000000000u, 0x0000000000000000u, 0x02, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kRegPhysId | OpRWFlags::kZExt }, // #64 [ref=1x] - { 0x0000000000000000u, 0x0000000000000000u, 0x02, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #65 [ref=2x] + { 0x0000000000000000u, 0x0000000000000000u, 0x02, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #65 [ref=1x] { 0x0000000000000000u, 0x0000000000000000u, 0x06, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kMemPhysId }, // #66 [ref=1x] { 0x0000000000000000u, 0x000000000000000Fu, 0x01, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kRegPhysId }, // #67 [ref=5x] { 0x0000000000000000u, 0x000000000000FFFFu, 0x00, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kRegPhysId }, // #68 [ref=4x] { 0x0000000000000000u, 0x0000000000000007u, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #69 [ref=2x] - { 0x0000000000000000u, 0x0000000000000000u, 0x04, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kRegPhysId }, // #70 [ref=1x] - { 0x0000000000000001u, 0x0000000000000000u, 0x01, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #71 [ref=10x] - { 0x0000000000000001u, 0x0000000000000000u, 0x00, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #72 [ref=1x] - { 0x0000000000000000u, 0x0000000000000001u, 0xFF, 0, { 0 }, OpRWFlags::kWrite }, // #73 [ref=30x] - { 0x0000000000000000u, 0xFFFFFFFFFFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #74 [ref=20x] - { 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt }, // #75 [ref=7x] - { 0xFFFFFFFFFFFFFFFFu, 0x0000000000000000u, 0xFF, 4, { 0 }, OpRWFlags::kRead }, // #76 [ref=4x] - { 0xFFFFFFFFFFFFFFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kConsecutive }, // #77 [ref=12x] - { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, 4, { 0 }, OpRWFlags::kRead }, // #78 [ref=2x] - { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kConsecutive }, // #79 [ref=6x] - { 0x0000000000000000u, 0x00000000FFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #80 [ref=10x] - { 0x00000000FFFFFFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #81 [ref=16x] - { 0x000000000000FFF0u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #82 [ref=18x] - { 0x000000000000FFFCu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #83 [ref=8x] - { 0x0000000000000000u, 0x0000000000000000u, 0x00, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt | OpRWFlags::kRegPhysId }, // #84 [ref=1x] - { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, 2, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #85 [ref=2x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kConsecutive } // #86 [ref=2x] + { 0x0000000000000001u, 0x0000000000000000u, 0x01, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #70 [ref=10x] + { 0x0000000000000001u, 0x0000000000000000u, 0x00, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kRegPhysId }, // #71 [ref=1x] + { 0x0000000000000000u, 0x0000000000000001u, 0xFF, 0, { 0 }, OpRWFlags::kWrite }, // #72 [ref=30x] + { 0x0000000000000000u, 0xFFFFFFFFFFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #73 [ref=20x] + { 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt }, // #74 [ref=7x] + { 0xFFFFFFFFFFFFFFFFu, 0x0000000000000000u, 0xFF, 4, { 0 }, OpRWFlags::kRead }, // #75 [ref=4x] + { 0xFFFFFFFFFFFFFFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kConsecutive }, // #76 [ref=12x] + { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, 4, { 0 }, OpRWFlags::kRead }, // #77 [ref=2x] + { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead | OpRWFlags::kConsecutive }, // #78 [ref=6x] + { 0x0000000000000000u, 0x00000000FFFFFFFFu, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #79 [ref=10x] + { 0x00000000FFFFFFFFu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #80 [ref=16x] + { 0x000000000000FFF0u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #81 [ref=18x] + { 0x000000000000FFFCu, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kRead }, // #82 [ref=8x] + { 0x0000000000000000u, 0x0000000000000000u, 0x00, 0, { 0 }, OpRWFlags::kRW | OpRWFlags::kZExt | OpRWFlags::kRegPhysId }, // #83 [ref=1x] + { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, 2, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt }, // #84 [ref=2x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, 0, { 0 }, OpRWFlags::kWrite | OpRWFlags::kZExt | OpRWFlags::kConsecutive } // #85 [ref=2x] }; const InstDB::RWInfoRm InstDB::rwInfoRm[] = { - { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , 0, 0 }, // #0 [ref=2000x] + { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , 0, 0 }, // #0 [ref=1997x] { InstDB::RWInfoRm::kCategoryConsistent, 0x03, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #1 [ref=8x] { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, 0 }, // #2 [ref=204x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 16, 0, 0 }, // #3 [ref=122x] @@ -4319,48 +5871,54 @@ const InstDB::RWInfoRm InstDB::rwInfoRm[] = { { InstDB::RWInfoRm::kCategoryFixed , 0x00, 10, 0, 0 }, // #19 [ref=2x] { InstDB::RWInfoRm::kCategoryNone , 0x01, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #20 [ref=5x] { InstDB::RWInfoRm::kCategoryFixed , 0x00, 2 , 0, 0 }, // #21 [ref=4x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x06, 0 , 0, 0 }, // #22 [ref=14x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x06, 0 , 0, 0 }, // #22 [ref=6x] { InstDB::RWInfoRm::kCategoryFixed , 0x03, 1 , 0, 0 }, // #23 [ref=1x] - { InstDB::RWInfoRm::kCategoryFixed , 0x03, 4 , 0, 0 }, // #24 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x03, 8 , 0, 0 }, // #25 [ref=3x] + { InstDB::RWInfoRm::kCategoryFixed , 0x03, 4 , 0, 0 }, // #24 [ref=3x] + { InstDB::RWInfoRm::kCategoryFixed , 0x03, 8 , 0, 0 }, // #25 [ref=2x] { InstDB::RWInfoRm::kCategoryFixed , 0x03, 2 , 0, 0 }, // #26 [ref=2x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 2 , 0, 0 }, // #27 [ref=13x] { InstDB::RWInfoRm::kCategoryFixed , 0x00, 4 , 0, 0 }, // #28 [ref=6x] { InstDB::RWInfoRm::kCategoryNone , 0x03, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #29 [ref=1x] { InstDB::RWInfoRm::kCategoryFixed , 0x03, 16, 0, 0 }, // #30 [ref=6x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 1 , 0, 0 }, // #31 [ref=32x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 8 , 0, 0 }, // #32 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , 0, uint32_t(CpuFeatures::X86::kSSE4_1) }, // #33 [ref=1x] - { InstDB::RWInfoRm::kCategoryNone , 0x02, 0 , 0, 0 }, // #34 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #35 [ref=3x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 8 , 0, 0 }, // #36 [ref=35x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 2 , 0, 0 }, // #37 [ref=30x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 4 , 0, 0 }, // #38 [ref=42x] - { InstDB::RWInfoRm::kCategoryFixed , 0x00, 32, 0, 0 }, // #39 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x02, 8 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #40 [ref=1x] - { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #41 [ref=1x] - { InstDB::RWInfoRm::kCategoryHalf , 0x02, 0 , 0, 0 }, // #42 [ref=19x] - { InstDB::RWInfoRm::kCategoryQuarter , 0x02, 0 , 0, 0 }, // #43 [ref=9x] - { InstDB::RWInfoRm::kCategoryHalf , 0x01, 0 , 0, 0 }, // #44 [ref=10x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x04, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #45 [ref=6x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 16, 0, 0 }, // #46 [ref=27x] - { InstDB::RWInfoRm::kCategoryFixed , 0x02, 64, 0, 0 }, // #47 [ref=6x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 16, 0, 0 }, // #48 [ref=6x] - { InstDB::RWInfoRm::kCategoryFixed , 0x01, 32, 0, 0 }, // #49 [ref=4x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x0C, 0 , 0, 0 }, // #50 [ref=15x] - { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 8 , 0, 0 }, // #51 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 4 , 0, 0 }, // #52 [ref=4x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 32, 0, 0 }, // #53 [ref=6x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x03, 0 , 0, 0 }, // #54 [ref=13x] - { InstDB::RWInfoRm::kCategoryFixed , 0x03, 8 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #55 [ref=1x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x08, 0 , 0, 0 }, // #56 [ref=2x] - { InstDB::RWInfoRm::kCategoryFixed , 0x04, 1 , 0, 0 }, // #57 [ref=1x] - { InstDB::RWInfoRm::kCategoryQuarter , 0x01, 0 , 0, 0 }, // #58 [ref=6x] - { InstDB::RWInfoRm::kCategoryEighth , 0x01, 0 , 0, 0 }, // #59 [ref=3x] - { InstDB::RWInfoRm::kCategoryEighth , 0x02, 0 , 0, 0 }, // #60 [ref=2x] - { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 16, 0, 0 }, // #61 [ref=1x] - { InstDB::RWInfoRm::kCategoryFixed , 0x06, 16, 0, 0 }, // #62 [ref=12x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, uint32_t(CpuFeatures::X86::kAVX512_BW) } // #63 [ref=2x] + { InstDB::RWInfoRm::kCategoryFixed , 0x03, 8 , InstDB::RWInfoRm::kFlagMovssMovsd, 0 }, // #31 [ref=1x] + { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , InstDB::RWInfoRm::kFlagMovssMovsd, 0 }, // #32 [ref=2x] + { InstDB::RWInfoRm::kCategoryFixed , 0x03, 4 , InstDB::RWInfoRm::kFlagMovssMovsd, 0 }, // #33 [ref=1x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 1 , 0, 0 }, // #34 [ref=32x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 8 , 0, 0 }, // #35 [ref=4x] + { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , InstDB::RWInfoRm::kFlagPextrw, 0 }, // #36 [ref=1x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , InstDB::RWInfoRm::kFlagPextrw, uint32_t(CpuFeatures::X86::kSSE4_1) }, // #37 [ref=1x] + { InstDB::RWInfoRm::kCategoryNone , 0x02, 0 , 0, 0 }, // #38 [ref=4x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #39 [ref=3x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 8 , 0, 0 }, // #40 [ref=35x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 2 , 0, 0 }, // #41 [ref=30x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 4 , 0, 0 }, // #42 [ref=42x] + { InstDB::RWInfoRm::kCategoryFixed , 0x00, 32, 0, 0 }, // #43 [ref=4x] + { InstDB::RWInfoRm::kCategoryFixed , 0x02, 8 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #44 [ref=1x] + { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #45 [ref=1x] + { InstDB::RWInfoRm::kCategoryHalf , 0x02, 0 , 0, 0 }, // #46 [ref=19x] + { InstDB::RWInfoRm::kCategoryQuarter , 0x02, 0 , 0, 0 }, // #47 [ref=9x] + { InstDB::RWInfoRm::kCategoryHalf , 0x01, 0 , 0, 0 }, // #48 [ref=10x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x04, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #49 [ref=6x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 16, 0, 0 }, // #50 [ref=27x] + { InstDB::RWInfoRm::kCategoryFixed , 0x02, 64, 0, 0 }, // #51 [ref=6x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 16, 0, 0 }, // #52 [ref=6x] + { InstDB::RWInfoRm::kCategoryFixed , 0x01, 32, 0, 0 }, // #53 [ref=4x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x0C, 0 , 0, 0 }, // #54 [ref=15x] + { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 8 , 0, 0 }, // #55 [ref=4x] + { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 4 , 0, 0 }, // #56 [ref=4x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 32, 0, 0 }, // #57 [ref=6x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x03, 0 , 0, 0 }, // #58 [ref=13x] + { InstDB::RWInfoRm::kCategoryFixed , 0x03, 8 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #59 [ref=1x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x08, 0 , 0, 0 }, // #60 [ref=2x] + { InstDB::RWInfoRm::kCategoryFixed , 0x04, 1 , 0, 0 }, // #61 [ref=1x] + { InstDB::RWInfoRm::kCategoryQuarter , 0x01, 0 , 0, 0 }, // #62 [ref=6x] + { InstDB::RWInfoRm::kCategoryEighth , 0x01, 0 , 0, 0 }, // #63 [ref=3x] + { InstDB::RWInfoRm::kCategoryEighth , 0x02, 0 , 0, 0 }, // #64 [ref=2x] + { InstDB::RWInfoRm::kCategoryFixed , 0x0C, 16, 0, 0 }, // #65 [ref=1x] + { InstDB::RWInfoRm::kCategoryFixed , 0x06, 16, 0, 0 }, // #66 [ref=12x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x06, 0 , InstDB::RWInfoRm::kFlagFeatureIfRMI, uint32_t(CpuFeatures::X86::kAVX512_F) }, // #67 [ref=5x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , InstDB::RWInfoRm::kFlagFeatureIfRMI, uint32_t(CpuFeatures::X86::kAVX512_BW) }, // #68 [ref=2x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x06, 0 , InstDB::RWInfoRm::kFlagFeatureIfRMI, uint32_t(CpuFeatures::X86::kAVX512_BW) } // #69 [ref=3x] }; // ---------------------------------------------------------------------------- // ${InstRWInfoTable:End} diff --git a/erts/emulator/asmjit/x86/x86instdb.h b/erts/emulator/asmjit/x86/x86instdb.h index 99112891e029..c8a914f2b839 100644 --- a/erts/emulator/asmjit/x86/x86instdb.h +++ b/erts/emulator/asmjit/x86/x86instdb.h @@ -442,8 +442,8 @@ ASMJIT_VARAPI const CommonInfo _commonInfoTable[]; //! Instruction information. struct InstInfo { - //! Index to \ref _nameData. - uint32_t _nameDataIndex : 14; + //! Reserved for future use. + uint32_t _reserved : 14; //! Index to \ref _commonInfoTable. uint32_t _commonInfoIndex : 10; //! Index to \ref _additionalInfoTable. @@ -461,7 +461,7 @@ struct InstInfo { //! \name Accessors //! \{ - //! Returns common information, see `CommonInfo`. + //! Returns common information, see \ref CommonInfo. inline const CommonInfo& commonInfo() const noexcept { return _commonInfoTable[_commonInfoIndex]; } //! Returns instruction flags, see \ref Flags. diff --git a/erts/emulator/asmjit/x86/x86instdb_p.h b/erts/emulator/asmjit/x86/x86instdb_p.h index 9a6f780ea1c8..4bfa0b9183dd 100644 --- a/erts/emulator/asmjit/x86/x86instdb_p.h +++ b/erts/emulator/asmjit/x86/x86instdb_p.h @@ -189,12 +189,12 @@ enum EncodingId : uint32_t { //! Additional information table, provides CPU extensions required to execute an instruction and RW flags. struct AdditionalInfo { - //! Features vector. - uint8_t _features[6]; + //! Index to `_instFlagsTable`. + uint8_t _instFlagsIndex; //! Index to `_rwFlagsTable`. uint8_t _rwFlagsIndex; - //! Reserved for future use. - uint8_t _reserved; + //! Features vector. + uint8_t _features[6]; inline const uint8_t* featuresBegin() const noexcept { return _features; } inline const uint8_t* featuresEnd() const noexcept { return _features + ASMJIT_ARRAY_SIZE(_features); } @@ -259,7 +259,13 @@ struct RWInfoRm { }; enum Flags : uint8_t { - kFlagAmbiguous = 0x01 + kFlagAmbiguous = 0x01, + //! Special semantics for PEXTRW - memory operand can only be used with SSE4.1 instruction and it's forbidden in MMX. + kFlagPextrw = 0x02, + //! Special semantics for MOVSS and MOVSD - doesn't zero extend the destination if the operation is a reg to reg move. + kFlagMovssMovsd = 0x04, + //! Special semantics for AVX shift instructions that do not provide reg/mem in AVX/AVX2 mode (AVX-512 is required). + kFlagFeatureIfRMI = 0x08 }; uint8_t category; @@ -283,12 +289,14 @@ extern const RWInfo rwInfoB[]; extern const RWInfoOp rwInfoOp[]; extern const RWInfoRm rwInfoRm[]; extern const RWFlagsInfoTable _rwFlagsInfoTable[]; +extern const InstRWFlags _instFlagsTable[]; extern const uint32_t _mainOpcodeTable[]; extern const uint32_t _altOpcodeTable[]; #ifndef ASMJIT_NO_TEXT -extern const char _nameData[]; +extern const uint32_t _instNameIndexTable[]; +extern const char _instNameStringTable[]; extern const InstNameIndex instNameIndex[26]; #endif // !ASMJIT_NO_TEXT diff --git a/erts/emulator/asmjit/x86/x86operand.h b/erts/emulator/asmjit/x86/x86operand.h index 037d4af4ddf6..8781be1a4f4f 100644 --- a/erts/emulator/asmjit/x86/x86operand.h +++ b/erts/emulator/asmjit/x86/x86operand.h @@ -174,24 +174,24 @@ class Reg : public BaseReg { static inline bool isTmm(const Operand_& op) noexcept { return op.as().isTmm(); } static inline bool isRip(const Operand_& op) noexcept { return op.as().isRip(); } - static inline bool isGpb(const Operand_& op, uint32_t rId) noexcept { return isGpb(op) & (op.id() == rId); } - static inline bool isGpbLo(const Operand_& op, uint32_t rId) noexcept { return isGpbLo(op) & (op.id() == rId); } - static inline bool isGpbHi(const Operand_& op, uint32_t rId) noexcept { return isGpbHi(op) & (op.id() == rId); } - static inline bool isGpw(const Operand_& op, uint32_t rId) noexcept { return isGpw(op) & (op.id() == rId); } - static inline bool isGpd(const Operand_& op, uint32_t rId) noexcept { return isGpd(op) & (op.id() == rId); } - static inline bool isGpq(const Operand_& op, uint32_t rId) noexcept { return isGpq(op) & (op.id() == rId); } - static inline bool isXmm(const Operand_& op, uint32_t rId) noexcept { return isXmm(op) & (op.id() == rId); } - static inline bool isYmm(const Operand_& op, uint32_t rId) noexcept { return isYmm(op) & (op.id() == rId); } - static inline bool isZmm(const Operand_& op, uint32_t rId) noexcept { return isZmm(op) & (op.id() == rId); } - static inline bool isMm(const Operand_& op, uint32_t rId) noexcept { return isMm(op) & (op.id() == rId); } - static inline bool isKReg(const Operand_& op, uint32_t rId) noexcept { return isKReg(op) & (op.id() == rId); } - static inline bool isSReg(const Operand_& op, uint32_t rId) noexcept { return isSReg(op) & (op.id() == rId); } - static inline bool isCReg(const Operand_& op, uint32_t rId) noexcept { return isCReg(op) & (op.id() == rId); } - static inline bool isDReg(const Operand_& op, uint32_t rId) noexcept { return isDReg(op) & (op.id() == rId); } - static inline bool isSt(const Operand_& op, uint32_t rId) noexcept { return isSt(op) & (op.id() == rId); } - static inline bool isBnd(const Operand_& op, uint32_t rId) noexcept { return isBnd(op) & (op.id() == rId); } - static inline bool isTmm(const Operand_& op, uint32_t rId) noexcept { return isTmm(op) & (op.id() == rId); } - static inline bool isRip(const Operand_& op, uint32_t rId) noexcept { return isRip(op) & (op.id() == rId); } + static inline bool isGpb(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpb(op)) & unsigned(op.id() == rId)); } + static inline bool isGpbLo(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpbLo(op)) & unsigned(op.id() == rId)); } + static inline bool isGpbHi(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpbHi(op)) & unsigned(op.id() == rId)); } + static inline bool isGpw(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpw(op)) & unsigned(op.id() == rId)); } + static inline bool isGpd(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpd(op)) & unsigned(op.id() == rId)); } + static inline bool isGpq(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isGpq(op)) & unsigned(op.id() == rId)); } + static inline bool isXmm(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isXmm(op)) & unsigned(op.id() == rId)); } + static inline bool isYmm(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isYmm(op)) & unsigned(op.id() == rId)); } + static inline bool isZmm(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isZmm(op)) & unsigned(op.id() == rId)); } + static inline bool isMm(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isMm(op)) & unsigned(op.id() == rId)); } + static inline bool isKReg(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isKReg(op)) & unsigned(op.id() == rId)); } + static inline bool isSReg(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isSReg(op)) & unsigned(op.id() == rId)); } + static inline bool isCReg(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isCReg(op)) & unsigned(op.id() == rId)); } + static inline bool isDReg(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isDReg(op)) & unsigned(op.id() == rId)); } + static inline bool isSt(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isSt(op)) & unsigned(op.id() == rId)); } + static inline bool isBnd(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isBnd(op)) & unsigned(op.id() == rId)); } + static inline bool isTmm(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isTmm(op)) & unsigned(op.id() == rId)); } + static inline bool isRip(const Operand_& op, uint32_t rId) noexcept { return bool(unsigned(isRip(op)) & unsigned(op.id() == rId)); } }; //! General purpose register (X86). @@ -790,15 +790,23 @@ class Mem : public BaseMem { //! Clones the memory operand. inline constexpr Mem clone() const noexcept { return Mem(*this); } - //! Creates a new copy of this memory operand adjusted by `off`. + //! Creates a copy of this memory operand adjusted by `off`. inline Mem cloneAdjusted(int64_t off) const noexcept { Mem result(*this); result.addOffset(off); return result; } - inline constexpr Mem cloneBroadcasted(Broadcast b) const noexcept { - return Mem((_signature & ~Signature{kSignatureMemBroadcastMask}) | Signature::fromValue(b), _baseId, _data[0], int32_t(_data[1])); + //! Creates a copy of this memory operand resized to `size`. + inline Mem cloneResized(uint32_t size) const noexcept { + Mem result(*this); + result.setSize(size); + return result; + } + + //! Creates a copy of this memory operand with a broadcast `bcst`. + inline constexpr Mem cloneBroadcasted(Broadcast bcst) const noexcept { + return Mem((_signature & ~Signature{kSignatureMemBroadcastMask}) | Signature::fromValue(bcst), _baseId, _data[0], int32_t(_data[1])); } //! \} diff --git a/erts/emulator/asmjit/x86/x86rapass.cpp b/erts/emulator/asmjit/x86/x86rapass.cpp index 4f0325ad9f10..4d8f3aa069f2 100644 --- a/erts/emulator/asmjit/x86/x86rapass.cpp +++ b/erts/emulator/asmjit/x86/x86rapass.cpp @@ -126,6 +126,12 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& cf, RAInstBuilder& i bool hasGpbHiConstraint = false; uint32_t singleRegOps = 0; + // Copy instruction RW flags to instruction builder except kMovOp, which is propagated manually later. + ib.addInstRWFlags(rwInfo.instFlags() & ~InstRWFlags::kMovOp); + + // Mask of all operand types used by the instruction - can be used as an optimization later. + uint32_t opTypesMask = 0u; + if (opCount) { // The mask is for all registers, but we are mostly interested in AVX-512 registers at the moment. The mask // will be combined with all available registers of the Compiler at the end so we it never use more registers @@ -167,6 +173,8 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& cf, RAInstBuilder& i const Operand& op = opArray[i]; const OpRWInfo& opRwInfo = rwInfo.operand(i); + opTypesMask |= 1u << uint32_t(op.opType()); + if (op.isReg()) { // Register Operand // ---------------- @@ -212,9 +220,11 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& cf, RAInstBuilder& i } } - // Do not use RegMem flag if changing Reg to Mem requires additional CPU feature that may not be enabled. + // Do not use RegMem flag if changing Reg to Mem requires a CPU feature that is not available. if (rwInfo.rmFeature() && Support::test(flags, RATiedFlags::kUseRM | RATiedFlags::kOutRM)) { - flags &= ~(RATiedFlags::kUseRM | RATiedFlags::kOutRM); + if (!cc()->code()->cpuFeatures().has(rwInfo.rmFeature())) { + flags &= ~(RATiedFlags::kUseRM | RATiedFlags::kOutRM); + } } RegGroup group = workReg->group(); @@ -394,6 +404,24 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& cf, RAInstBuilder& i } } + // If this instruction has move semantics then check whether it could be eliminated if all virtual registers + // are allocated into the same register. Take into account the virtual size of the destination register as that's + // more important than a physical register size in this case. + if (rwInfo.hasInstFlag(InstRWFlags::kMovOp) && !inst->hasExtraReg() && Support::bitTest(opTypesMask, uint32_t(OperandType::kReg))) { + // AVX+ move instructions have 3 operand form - the first two operands must be the same to guarantee move semantics. + if (opCount == 2 || (opCount == 3 && opArray[0] == opArray[1])) { + uint32_t vIndex = Operand::virtIdToIndex(opArray[0].as().id()); + if (vIndex < Operand::kVirtIdCount) { + const VirtReg* vReg = _cc->virtRegByIndex(vIndex); + const OpRWInfo& opRwInfo = rwInfo.operand(0); + + uint64_t remainingByteMask = vReg->workReg()->regByteMask() & ~opRwInfo.writeByteMask(); + if (remainingByteMask == 0u || (remainingByteMask & opRwInfo.extendByteMask()) == 0) + ib.addInstRWFlags(InstRWFlags::kMovOp); + } + } + } + // Handle X86 constraints. if (hasGpbHiConstraint) { for (RATiedReg& tiedReg : ib) { @@ -1251,6 +1279,10 @@ ASMJIT_FAVOR_SPEED Error X86RAPass::_rewrite(BaseNode* first, BaseNode* stop) no // Rewrite virtual registers into physical registers. if (raInst) { + // This data is allocated by Zone passed to `runOnFunction()`, which will be reset after the RA pass finishes. + // So reset this data to prevent having a dead pointer after the RA pass is complete. + node->resetPassData(); + // If the instruction contains pass data (raInst) then it was a subject for register allocation and must be // rewritten to use physical regs. RATiedReg* tiedRegs = raInst->tiedRegs(); @@ -1274,16 +1306,25 @@ ASMJIT_FAVOR_SPEED Error X86RAPass::_rewrite(BaseNode* first, BaseNode* stop) no } } + // Transform VEX instruction to EVEX when necessary. if (raInst->isTransformable()) { if (maxRegId > 15) { - // Transform VEX instruction to EVEX. inst->setId(transformVexToEvex(inst->id())); } } - // This data is allocated by Zone passed to `runOnFunction()`, which will be reset after the RA pass finishes. - // So reset this data to prevent having a dead pointer after the RA pass is complete. - node->resetPassData(); + // Remove moves that do not do anything. + // + // Usually these moves are inserted during code generation and originally they used different registers. If RA + // allocated these into the same register such redundant mov would appear. + if (raInst->hasInstRWFlag(InstRWFlags::kMovOp) && !inst->hasExtraReg()) { + if (inst->opCount() == 2) { + if (inst->op(0) == inst->op(1)) { + cc()->removeNode(node); + goto Next; + } + } + } if (ASMJIT_UNLIKELY(node->type() != NodeType::kInst)) { // FuncRet terminates the flow, it must either be removed if the exit label is next to it (optimization) or @@ -1327,6 +1368,7 @@ ASMJIT_FAVOR_SPEED Error X86RAPass::_rewrite(BaseNode* first, BaseNode* stop) no } } +Next: node = next; } diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c index bcbed7746bb4..036816df2fae 100644 --- a/erts/emulator/beam/atom.c +++ b/erts/emulator/beam/atom.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -197,7 +197,6 @@ atom_alloc(Atom* tmpl) static void atom_free(Atom* obj) { - ASSERT(obj->slot.index == atom_val(am_ErtsSecretAtom)); } static void latin1_to_utf8(byte* conv_buf, Uint buf_sz, @@ -305,7 +304,7 @@ erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc) if (enc == ERTS_ATOM_ENC_UTF8) { /* Need to verify encoding and length */ - byte *err_pos; + const byte *err_pos; Uint no_chars; switch (erts_analyze_utf8_x((byte *) text, (Uint) tlen, @@ -347,7 +346,7 @@ erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc) Eterm erts_atom_put(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc) { - int aix = erts_atom_put_index(name, len, enc, trunc); + Sint aix = erts_atom_put_index(name, len, enc, trunc); if (aix >= 0) return make_atom(aix); else @@ -509,8 +508,6 @@ init_atom_table(void) atom_tab(ix)->name = (byte*)erl_atom_names[i]; } - /* Hide am_ErtsSecretAtom */ - hash_erase(&erts_atom_table.htable, atom_tab(atom_val(am_ErtsSecretAtom))); } void diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h index 2bc1f653ec08..681bd4586f06 100644 --- a/erts/emulator/beam/atom.h +++ b/erts/emulator/beam/atom.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2021. 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. @@ -36,7 +36,7 @@ /* Internal atom cache needs MAX_ATOM_TABLE_SIZE to be less than an unsigned 32 bit integer. See external.c(erts_encode_ext_dist_header_setup) for more details. */ -#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (UWORD_CONSTANT(1) << 32)) ? MAX_ATOM_INDEX + 1 : ((UWORD_CONSTANT(1) << 31) - 1)) /* Here we use maximum signed interger value to avoid integer overflow */ +#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (UWORD_CONSTANT(1) << 32)) ? MAX_ATOM_INDEX + 1 : ((UWORD_CONSTANT(1) << 31) - 1)) /* Here we use maximum signed integer value to avoid integer overflow */ #else #define MAX_ATOM_TABLE_SIZE (MAX_ATOM_INDEX + 1) #endif diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 839d52f578f4..f0fa834d493a 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2022. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -59,9 +59,10 @@ atom nocatch atom undefined_function atom undefined_lambda -# Secret internal atom that can never be found by string lookup -# and should never leak out to be seen by the user. -atom ErtsSecretAtom='3RT$' +# +# Other commonly used atoms. +# +atom nil no none # All other atoms. Try to keep the order alphabetic. # @@ -90,6 +91,7 @@ atom allocator atom allocator_sizes atom alloc_util_allocators atom allow_passive_connect +atom already_exists atom already_loaded atom amd64 atom anchored @@ -104,6 +106,7 @@ atom arg0 atom arity atom asn1 atom async +atom async_dist atom asynchronous atom atom atom atom_used @@ -118,7 +121,8 @@ atom await_sched_wall_time_modifications atom awaiting_load atom awaiting_unload atom backtrace backtrace_depth -atom badarg badarith badarity badfile badfun badkey badmap badmatch badsig +atom badarg badarith badarity badfile badfun badkey badmap badmatch +atom badrecord badsig atom badopt badtype atom bad_map_iterator atom bag @@ -157,8 +161,11 @@ atom busy_port atom call atom call_count atom call_error_handler +atom call_memory atom call_time +atom call_trace_return atom caller +atom caller_line atom capture atom case_clause atom caseless @@ -170,6 +177,7 @@ atom cflags atom CHANGE='CHANGE' atom characters_to_binary_int atom characters_to_list_int +atom check_gc atom clear atom clock_service atom close @@ -187,6 +195,7 @@ atom convert_time_unit atom connect atom connected atom connection_closed +atom connection_id atom const atom context_switches atom continue_exit @@ -243,6 +252,7 @@ atom dsend_continue_trap atom duplicate_bag atom duplicated atom dupnames +atom dynamic_node_name atom einval atom emu_flavor atom emu_type @@ -251,6 +261,7 @@ atom enable_trace atom enabled atom endian atom env +atom ensure_at_least ensure_exactly atom eof atom eol atom Eq='=:=' @@ -297,9 +308,11 @@ atom flags atom flush atom flush_monitor_messages atom force +atom format_bs_fail atom format_cpu_topology atom free atom fullsweep_after +atom function atom functions atom function_clause atom garbage_collect @@ -317,6 +330,7 @@ atom get_all_trap atom get_internal_state_blocked atom get_seq_token atom get_size +atom get_tail atom get_tcw atom gather_gc_info_result atom gather_io_bytes @@ -347,6 +361,7 @@ atom ignore atom in atom in_exiting atom inactive +atom include_shared_binaries atom incomplete atom inconsistent atom index @@ -358,6 +373,7 @@ atom inherit atom init atom initial_call atom input +atom integer atom internal atom internal_error atom instruction_counts @@ -476,6 +492,7 @@ atom nodeup atom noeol atom noproc atom normal +atom normal_exit atom nosuspend atom no_fail atom no_float @@ -524,6 +541,7 @@ atom owner atom packet atom packet_size atom parallelism +atom parent atom Plus='+' atom PlusPlus='++' atom pause @@ -546,6 +564,7 @@ atom prepare_on_load atom print atom priority atom private +atom private_append atom process atom processes atom processes_used @@ -587,10 +606,11 @@ atom reset_seq_trace atom restart atom resume atom return_from -atom return_time_trace atom return_to atom return_to_trace atom return_trace +atom reuse +atom run_process atom run_queue atom run_queue_lengths atom run_queue_lengths_all @@ -629,8 +649,10 @@ atom set_on_spawn atom set_seq_token atom set_tcw atom set_tcw_fake +atom short atom shutdown atom sighup +atom signed atom sigterm atom sigusr1 atom sigusr2 @@ -645,12 +667,14 @@ atom sigtstp atom sigquit atom silent atom size +atom skip atom spawn_executable atom spawn_driver atom spawn_init atom spawn_reply atom spawn_request atom spawn_request_yield +atom spawn_service atom spawned atom ssl_tls atom stack_size @@ -710,14 +734,16 @@ atom unregister atom urun atom use_stdio atom used -atom utf8 +atom utf8 utf16 utf32 atom unblock atom unblock_normal atom uniq +atom unit atom unless_suspending atom unloaded atom unloaded_only atom unload_cancelled +atom unsafe atom value atom version atom visible @@ -732,4 +758,6 @@ atom xor atom x86 atom yes atom yield -atom nifs \ No newline at end of file +atom nifs +atom auto +atom debug_hash_fixed_number_of_locks diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index aa36e40a622c..a4fc8632c631 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2021. All Rights Reserved. + * Copyright Ericsson AB 1999-2023. 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. @@ -57,7 +57,7 @@ static struct { ErlFunEntry **funs; ErlFunEntry *def_funs[10]; Uint fe_size; - Uint fe_ix; + Uint fe_count; struct erl_module_instance saved_old; } purge_state; @@ -88,7 +88,7 @@ init_purge_state(void) purge_state.funs = &purge_state.def_funs[0]; purge_state.fe_size = sizeof(purge_state.def_funs) / sizeof(purge_state.def_funs[0]); - purge_state.fe_ix = 0; + purge_state.fe_count = 0; purge_state.saved_old.code_hdr = 0; } @@ -302,15 +302,36 @@ struct m { Eterm exception; }; -static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int, int); -static void smp_code_ix_commiter(void*); -static struct /* Protected by code_write_permission */ +static struct /* Protected by code loading permission */ { Process* stager; - ErtsThrPrgrLaterOp lop; + ErtsCodeBarrier barrier; } committer_state; +static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int, int); + +static void commit_code_ix(void *null) +{ + Process* p = committer_state.stager; + + erts_commit_staging_code_ix(); + +#ifdef DEBUG + committer_state.stager = NULL; +#endif + + erts_release_code_load_permission(); + + erts_proc_lock(p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(p)) { + erts_resume(p, ERTS_PROC_LOCK_STATUS); + } + erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + + erts_proc_dec_refc(p); +} + static Eterm exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions) { @@ -340,8 +361,9 @@ finish_loading_1(BIF_ALIST_1) int is_blocking = 0; int do_commit = 0; - if (!erts_try_seize_code_write_permission(BIF_P)) { - ERTS_BIF_YIELD1(BIF_TRAP_EXPORT(BIF_finish_loading_1), BIF_P, BIF_ARG_1); + if (!erts_try_seize_code_load_permission(BIF_P)) { + ERTS_BIF_YIELD1(BIF_TRAP_EXPORT(BIF_finish_loading_1), + BIF_P, BIF_ARG_1); } /* @@ -356,11 +378,11 @@ finish_loading_1(BIF_ALIST_1) n = erts_list_length(BIF_ARG_1); if (n < 0) { badarg: - if (p) { - erts_free(ERTS_ALC_T_LOADER_TMP, p); - } - erts_release_code_write_permission(); - BIF_ERROR(BIF_P, BADARG); + if (p) { + erts_free(ERTS_ALC_T_LOADER_TMP, p); + } + erts_release_code_load_permission(); + BIF_ERROR(BIF_P, BADARG); } p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); @@ -392,13 +414,13 @@ finish_loading_1(BIF_ALIST_1) */ if (n > 1) { - for (i = 0; i < n; i++) { - if (erts_has_code_on_load(p[i].code) == am_true) { - erts_free(ERTS_ALC_T_LOADER_TMP, p); - erts_release_code_write_permission(); - BIF_ERROR(BIF_P, SYSTEM_LIMIT); - } - } + for (i = 0; i < n; i++) { + if (erts_has_code_on_load(p[i].code) == am_true) { + erts_free(ERTS_ALC_T_LOADER_TMP, p); + erts_release_code_load_permission(); + BIF_ERROR(BIF_P, SYSTEM_LIMIT); + } + } } /* @@ -503,17 +525,19 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, { if (is_blocking || !commit) { - if (commit) { - int i; - erts_end_staging_code_ix(); - erts_commit_staging_code_ix(); + if (commit) { + int i; + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); + + for (i=0; i < nmods; i++) { + if (mods[i].modp->curr.code_hdr + && mods[i].exception != am_on_load) { + set_default_trace_pattern(mods[i].module); + } + } - for (i=0; i < nmods; i++) { - if (mods[i].modp->curr.code_hdr - && mods[i].exception != am_on_load) { - set_default_trace_pattern(mods[i].module); - } - } + erts_blocking_code_barrier(); } else { erts_abort_staging_code_ix(); @@ -524,7 +548,7 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, if (is_blocking) { erts_thr_progress_unblock(); } - erts_release_code_write_permission(); + erts_release_code_load_permission(); return res; } else { @@ -542,37 +566,19 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, */ ASSERT(committer_state.stager == NULL); committer_state.stager = c_p; - erts_schedule_thr_prgr_later_op(smp_code_ix_commiter, NULL, &committer_state.lop); - erts_proc_inc_refc(c_p); - erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); - /* - * smp_code_ix_commiter() will do the rest "later" - * and resume this process to return 'res'. - */ - ERTS_BIF_YIELD_RETURN(c_p, res); - } -} + erts_schedule_code_barrier(&committer_state.barrier, + commit_code_ix, NULL); -static void smp_code_ix_commiter(void* null) -{ - Process* p = committer_state.stager; + erts_proc_inc_refc(c_p); + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); - erts_commit_staging_code_ix(); -#ifdef DEBUG - committer_state.stager = NULL; -#endif - erts_release_code_write_permission(); - erts_proc_lock(p, ERTS_PROC_LOCK_STATUS); - if (!ERTS_PROC_IS_EXITING(p)) { - erts_resume(p, ERTS_PROC_LOCK_STATUS); + /* commit_code_ix(NULL) will resume us when everything is finished, at + * which point we'll return `res`. */ + ERTS_BIF_YIELD_RETURN(c_p, res); } - erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); - erts_proc_dec_refc(p); } - - BIF_RETTYPE check_old_code_1(BIF_ALIST_1) { @@ -700,7 +706,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } - if (!erts_try_seize_code_write_permission(BIF_P)) { + if (!erts_try_seize_code_load_permission(BIF_P)) { ERTS_BIF_YIELD1(BIF_TRAP_EXPORT(BIF_delete_module_1), BIF_P, BIF_ARG_1); } @@ -804,6 +810,12 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { +#ifdef BEAMASM + /* This is implemented as an instruction. We've skipped providing a more + * helpful error message since it's undocumented and should never be called + * by the user. */ + BIF_ERROR(BIF_P, BADARG); +#else Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); const BeamCodeHeader *hdr; @@ -819,6 +831,7 @@ BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) } BIF_ERROR(BIF_P, BADARG); +#endif } BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) @@ -830,7 +843,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) BIF_ERROR(BIF_P, BADARG); } - if (!erts_try_seize_code_write_permission(BIF_P)) { + if (!erts_try_seize_code_load_permission(BIF_P)) { ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_finish_after_on_load_2), BIF_P, BIF_ARG_1, BIF_ARG_2); } @@ -841,7 +854,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) if (!modp || !modp->on_load || !(modp->on_load)->code_hdr || !((modp->on_load)->code_hdr)->on_load) { - erts_release_code_write_permission(); + erts_release_code_load_permission(); BIF_ERROR(BIF_P, BADARG); } @@ -877,7 +890,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) modp->on_load = 0; /* - * The on_load function succeded. Fix up export entries. + * The on_load function succeeded. Fix up export entries. */ num_exps = export_list_size(code_ix); for (i = 0; i < num_exps; i++) { @@ -890,7 +903,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) DBG_CHECK_EXPORT(ep, code_ix); if (ep->trampoline.not_loaded.deferred != 0) { - ep->addresses[code_ix] = (void*)ep->trampoline.not_loaded.deferred; + ep->dispatch.addresses[code_ix] = + (void*)ep->trampoline.not_loaded.deferred; ep->trampoline.not_loaded.deferred = 0; } else { if (ep->bif_number != -1) { @@ -905,10 +919,13 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) { BeamCodeHeader *code_hdr_rw; + erts_unseal_module(&modp->curr); + code_hdr_rw = erts_writable_code_ptr(&modp->curr, modp->curr.code_hdr); - code_hdr_rw->on_load = NULL; + + erts_seal_module(&modp->curr); } mods[0].modp = modp; @@ -937,7 +954,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) ep->trampoline.not_loaded.deferred = 0; } } - erts_release_code_write_permission(); + erts_release_code_load_permission(); BIF_RET(am_true); } @@ -967,12 +984,39 @@ set_default_trace_pattern(Eterm module) } int -erts_check_copy_literals_gc_need(Process *c_p, int *redsp, - char *literals, Uint lit_bsize) +erts_check_copy_literals_gc_need_max_reds(Process *c_p) { + Uint64 words, reds; + /* - * TODO: Implement yielding support! + * Calculate maximum amount of words that needs + * to be scanned... */ + words = 1; /* fvalue */ + words += c_p->hend - c_p->stop; /* stack */ + words += c_p->htop - c_p->heap; /* new heap */ + if (c_p->abandoned_heap) + words += c_p->heap_sz; /* abandoned heap */ + words += c_p->old_htop - c_p->old_heap; /* old heap */ + if (c_p->dictionary) { + Eterm* start = ERTS_PD_START(c_p->dictionary); + Eterm* end = start + ERTS_PD_SIZE(c_p->dictionary); + + words += end - start; /* dictionary */ + } + words += c_p->mbuf_sz; /* heap and message fragments */ + + /* Convert to reductions... */ + reds = ((words - 1)/ERTS_CLA_SCAN_WORDS_PER_RED) + 1; + if (reds > CONTEXT_REDS) + return CONTEXT_REDS+1; + return (int) reds; +} + +int +erts_check_copy_literals_gc_need(Process *c_p, int *redsp, + char *literals, Uint lit_bsize) +{ ErlHeapFragment *hfrag; ErtsMessage *mfp; Uint64 scanned = 0; @@ -1255,7 +1299,7 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) * - erts_internal:release_literal_area_switch() changes the set of * counters that blocks release of literal areas * - The literal area collector process gets suspended waiting thread - * progress in order to ensure that the change of counters is visable + * progress in order to ensure that the change of counters is visible * by all schedulers. * - When the literal area collector process is resumed after thread * progress has completed, erts_internal:release_literal_area_switch() @@ -1521,22 +1565,30 @@ erts_literal_area_collector_send_copy_request_3(BIF_ALIST_3) req_id = TUPLE3(&tmp_heap[0], BIF_ARG_2, BIF_ARG_3, BIF_ARG_1); - if (BIF_ARG_3 == am_false) { + switch (BIF_ARG_3) { + + case am_init: /* - * Will handle signal queue and check if GC if needed. If - * GC is needed operation will be continued by a GC (below). + * Will handle signal queue and if possible check if GC if needed. + * If GC is needed or needs to be checked the operation will be + * restarted later in the 'check_gc' or 'need_gc' case below... */ erts_proc_sig_send_cla_request(BIF_P, BIF_ARG_1, req_id); - } - else if (BIF_ARG_3 == am_true) { + break; + + case am_check_gc: + case am_need_gc: /* - * Will perform a literal GC. Note that this assumes that - * signal queue already has been handled... + * Will check and/or perform a literal GC. Note that this assumes that + * signal queue already has been handled by 'init' case above... */ - erts_schedule_cla_gc(BIF_P, BIF_ARG_1, req_id); - } - else + erts_schedule_cla_gc(BIF_P, BIF_ARG_1, req_id, + BIF_ARG_3 == am_check_gc); + break; + + default: BIF_ERROR(BIF_P, BADARG); + } BIF_RET(am_ok); } @@ -1708,19 +1760,19 @@ void erts_purge_state_add_fun(ErlFunEntry *fe) { ASSERT(is_value(purge_state.module)); - if (purge_state.fe_ix >= purge_state.fe_size) { + if (purge_state.fe_count >= purge_state.fe_size) { ErlFunEntry **funs; purge_state.fe_size += 100; funs = erts_alloc(ERTS_ALC_T_PURGE_DATA, sizeof(ErlFunEntry *)*purge_state.fe_size); sys_memcpy((void *) funs, (void *) purge_state.funs, - purge_state.fe_ix*sizeof(ErlFunEntry *)); + purge_state.fe_count*sizeof(ErlFunEntry *)); if (purge_state.funs != &purge_state.def_funs[0]) erts_free(ERTS_ALC_T_PURGE_DATA, purge_state.funs); purge_state.funs = funs; } - purge_state.funs[purge_state.fe_ix++] = fe; + purge_state.funs[purge_state.fe_count++] = fe; } Export * @@ -1803,7 +1855,7 @@ finalize_purge_operation(Process *c_p, int succeded) purge_state.fe_size = sizeof(purge_state.def_funs); purge_state.fe_size /= sizeof(purge_state.def_funs[0]); } - purge_state.fe_ix = 0; + purge_state.fe_count = 0; } @@ -1821,7 +1873,12 @@ resume_purger(void *unused) static void finalize_purge_abort(void *unused) { - erts_fun_purge_abort_finalize(purge_state.funs, purge_state.fe_ix); + /* We're not supposed to land here if we don't have any funs to abort + * purging for. */ + ASSERT(purge_state.fe_count > 0); + + erts_fun_purge_abort_finalize(purge_state.funs, purge_state.fe_count); + erts_release_code_stage_permission(); finalize_purge_operation(NULL, 0); @@ -1831,236 +1888,251 @@ finalize_purge_abort(void *unused) BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2) { - if (BIF_P != erts_code_purger) - BIF_ERROR(BIF_P, EXC_NOTSUP); + if (BIF_P != erts_code_purger) { + BIF_ERROR(BIF_P, EXC_NOTSUP); + } - if (is_not_atom(BIF_ARG_1)) - BIF_ERROR(BIF_P, BADARG); + if (is_not_atom(BIF_ARG_1)) { + goto raise_badarg; + } switch (BIF_ARG_2) { case am_prepare: case am_prepare_on_load: { - /* - * Prepare for purge by marking all fun - * entries referring to the code to purge - * with "pending purge" markers. - */ - ErtsCodeIndex code_ix; - Module* modp; - Eterm res; - - if (is_value(purge_state.module)) - BIF_ERROR(BIF_P, BADARG); + /* Prepare for purge by marking all fun entries referring to the code + * to purge with "pending purge" markers. */ + ErtsCodeIndex code_ix; + Module* modp; + Eterm res; + + if (is_value(purge_state.module)) { + goto raise_badarg; + } - code_ix = erts_active_code_ix(); + /* Fun purging requires that we don't stage new code while any purge + * markers are alive, lest we kill them by reloading a new module on + * top of an old instance of the same module. */ + if (!erts_try_seize_code_stage_permission(BIF_P)) { + ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_erts_internal_purge_module_2), + BIF_P, BIF_ARG_1, BIF_ARG_2); + } - /* - * Correct module? - */ - modp = erts_get_module(BIF_ARG_1, code_ix); - if (!modp) - res = am_false; - else { - /* - * Any code to purge? - */ + code_ix = erts_active_code_ix(); - if (BIF_ARG_2 == am_prepare_on_load) { + /* Correct module? */ + modp = erts_get_module(BIF_ARG_1, code_ix); + if (!modp) { + res = am_false; + } else { + /* Any code to purge? */ + if (BIF_ARG_2 == am_prepare_on_load) { erts_rwlock_old_code(code_ix); - } else { - erts_rlock_old_code(code_ix); - } + } else { + erts_rlock_old_code(code_ix); + } - if (BIF_ARG_2 == am_prepare_on_load) { - ASSERT(modp->on_load); - ASSERT(modp->on_load->code_hdr); - purge_state.saved_old = modp->old; - modp->old = *modp->on_load; - erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) modp->on_load); - modp->on_load = 0; - } + if (BIF_ARG_2 == am_prepare_on_load) { + ASSERT(modp->on_load); + ASSERT(modp->on_load->code_hdr); + purge_state.saved_old = modp->old; + modp->old = *modp->on_load; + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) modp->on_load); + modp->on_load = 0; + } - if (!modp->old.code_hdr) - res = am_false; - else { - erts_mtx_lock(&purge_state.mtx); - purge_state.module = BIF_ARG_1; - erts_mtx_unlock(&purge_state.mtx); - res = am_true; - erts_fun_purge_prepare(&modp->old); - } + if (!modp->old.code_hdr) { + res = am_false; + } else { + erts_mtx_lock(&purge_state.mtx); + purge_state.module = BIF_ARG_1; + erts_mtx_unlock(&purge_state.mtx); + + /* Set up "pending purge" markers for the funs in this module. + * Processes trying to call these funs will be suspended + * _before_ calling them, which will then either crash or + * succeed when resumed after the purge finishes or is aborted. + * + * This guarantees that we won't get any more direct references + * into the code while checking for such funs. */ + erts_fun_purge_prepare(&modp->old); + + res = am_true; + } if (BIF_ARG_2 == am_prepare_on_load) { erts_rwunlock_old_code(code_ix); - } else { + } else { erts_runlock_old_code(code_ix); - } - } - - if (res != am_true) - BIF_RET(res); - else { - /* - * We'll be resumed when all schedulers are guaranteed - * to see the "pending purge" markers that we've made on - * all fun entries of the code that we are about to purge. - * Processes trying to call these funs will be suspended - * before calling the funs. That is we are guaranteed not - * to get any more direct references into the code while - * checking for such references... - */ - erts_schedule_thr_prgr_later_op(resume_purger, - NULL, - &purger_lop_data); - erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL); - ERTS_BIF_YIELD_RETURN(BIF_P, am_true); - } - } - - case am_abort: { - /* - * Soft purge that detected direct references into the code - * we set out to purge. Abort the purge. - */ + } + } - if (purge_state.module != BIF_ARG_1) - BIF_ERROR(BIF_P, BADARG); + if (res == am_true) { + if (purge_state.fe_count == 0) { + /* No funs to purge, so we can safely release stage permission + * and allow code to be loaded while checking process code. */ + erts_release_code_stage_permission(); + } - erts_fun_purge_abort_prepare(purge_state.funs, purge_state.fe_ix); + /* Resume ourselves when all schedulers are guaranteed to either + * call the newest instance of the module, or see the "pending + * purge" markers that we set on all fun entries related to the + * code we're about to purge. */ + erts_schedule_thr_prgr_later_op(resume_purger, + NULL, + &purger_lop_data); + erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL); + ERTS_BIF_YIELD_RETURN(BIF_P, am_true); + } - /* - * We need to restore the code addresses of the funs in - * two stages in order to ensure that we do not get any - * stale suspended processes due to the purge abort. - * Restore address pointer (erts_fun_purge_abort_prepare); - * wait for thread progress; clear pending purge address - * pointer (erts_fun_purge_abort_finalize), and then - * resume processes that got suspended - * (finalize_purge_operation). - */ - erts_schedule_thr_prgr_later_op(finalize_purge_abort, - NULL, - &purger_lop_data); - erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL); - ERTS_BIF_YIELD_RETURN(BIF_P, am_false); + erts_release_code_stage_permission(); + BIF_RET(res); } - case am_complete: { - ErtsCodeIndex code_ix; - Module* modp; - int is_blocking = 0; - Eterm ret; - ErtsLiteralArea *literals = NULL; - + case am_abort: { + /* Soft purge that detected direct references into the code we set out + * to purge. Abort the purge. */ + if (purge_state.module != BIF_ARG_1) { + goto raise_badarg; + } - /* - * We have no direct references into the code. - * Complete to purge. - */ + if (purge_state.fe_count > 0) { + erts_fun_purge_abort_prepare(purge_state.funs, + purge_state.fe_count); + + /* We need to restore the code addresses of the funs in two stages + * to ensure that we do not get any stale suspended processes due + * to the purge abort. + * + * Restore address pointer (erts_fun_purge_abort_prepare); wait for + * thread progress; clear pending purge address pointer + * (erts_fun_purge_abort_finalize), and then resume processes that + * got suspended (finalize_purge_operation). */ + erts_schedule_thr_prgr_later_op(finalize_purge_abort, + NULL, + &purger_lop_data); + erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL); + ERTS_BIF_YIELD_RETURN(BIF_P, am_false); + } - if (purge_state.module != BIF_ARG_1) - BIF_ERROR(BIF_P, BADARG); + /* No funs to restore, just clean up and return. */ + finalize_purge_operation(NULL, 0); + BIF_RET(am_false); + } - if (!erts_try_seize_code_write_permission(BIF_P)) { - ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_erts_internal_purge_module_2), - BIF_P, BIF_ARG_1, BIF_ARG_2); - } + case am_complete: { + ErtsCodeIndex code_ix; + Module* modp; + int is_blocking = 0; + Eterm ret; + ErtsLiteralArea *literals = NULL; + + /* We have no direct references into the code. Go ahead with the + * purge. */ + if (purge_state.module != BIF_ARG_1) { + goto raise_badarg; + } - code_ix = erts_active_code_ix(); + if (!erts_try_seize_code_mod_permission(BIF_P)) { + ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_erts_internal_purge_module_2), + BIF_P, BIF_ARG_1, BIF_ARG_2); + } - /* - * Correct module? - */ + code_ix = erts_active_code_ix(); - if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { - ERTS_BIF_PREP_RET(ret, am_false); - } - else { + /* Correct module? */ + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + ERTS_BIF_PREP_RET(ret, am_false); + } else { + erts_rwlock_old_code(code_ix); - erts_rwlock_old_code(code_ix); + /* Any code to purge? */ + if (!modp->old.code_hdr) { + ERTS_BIF_PREP_RET(ret, am_false); + } else { + literals = (modp->old.code_hdr)->literal_area; - /* - * Any code to purge? - */ - if (!modp->old.code_hdr) { - ERTS_BIF_PREP_RET(ret, am_false); - } - else { - /* - * Unload any NIF library - */ + /* Unload any NIF library. */ if (modp->old.nif) { - erts_unload_nif(modp->old.nif); - modp->old.nif = NULL; + erts_unload_nif(modp->old.nif); + modp->old.nif = NULL; } - /* - * Remove the old code. - */ - ASSERT(erts_total_code_size >= modp->old.code_length); - erts_total_code_size -= modp->old.code_length; - erts_fun_purge_complete(purge_state.funs, purge_state.fe_ix); + /* Remove the old code. */ + ASSERT(erts_total_code_size >= modp->old.code_length); + erts_total_code_size -= modp->old.code_length; + + if (purge_state.fe_count > 0) { + erts_fun_purge_complete(purge_state.funs, + purge_state.fe_count); + } beam_catches_delmod(modp->old.catches, modp->old.code_hdr, modp->old.code_length, code_ix); - { - BeamCodeHeader *code_hdr_rw; - - code_hdr_rw = erts_writable_code_ptr(&modp->old, - modp->old.code_hdr); + erts_remove_from_ranges(modp->old.code_hdr); - literals = code_hdr_rw->literal_area; - code_hdr_rw->literal_area = NULL; + if (modp->old.code_hdr->are_nifs) { + erts_free(ERTS_ALC_T_PREPARED_CODE, + modp->old.code_hdr->are_nifs); } - erts_remove_from_ranges(modp->old.code_hdr); - #ifndef BEAMASM erts_free(ERTS_ALC_T_CODE, (void *) modp->old.code_hdr); #else -# ifdef ADDRESS_SANITIZER +# ifdef ADDRESS_SANITIZER __lsan_unregister_root_region(modp->old.code_hdr, modp->old.code_length); -# endif - beamasm_purge_module(modp->old.native_module_exec, - modp->old.native_module_rw); +# endif + beamasm_purge_module(modp->old.executable_region, + modp->old.writable_region, + modp->old.code_length); #endif - modp->old.code_hdr = NULL; - modp->old.code_length = 0; - modp->old.catches = BEAM_CATCHES_NIL; - ERTS_BIF_PREP_RET(ret, am_true); - } + modp->old.code_hdr = NULL; + modp->old.code_length = 0; + modp->old.catches = BEAM_CATCHES_NIL; + ERTS_BIF_PREP_RET(ret, am_true); + } - if (purge_state.saved_old.code_hdr) { - modp->old = purge_state.saved_old; - purge_state.saved_old.code_hdr = 0; - } - erts_rwunlock_old_code(code_ix); - } - if (is_blocking) { - erts_thr_progress_unblock(); - erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - } + if (purge_state.saved_old.code_hdr) { + modp->old = purge_state.saved_old; + purge_state.saved_old.code_hdr = 0; + } - erts_release_code_write_permission(); + erts_rwunlock_old_code(code_ix); + } - finalize_purge_operation(BIF_P, ret == am_true); + if (is_blocking) { + erts_thr_progress_unblock(); + erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + + erts_release_code_mod_permission(); + + if (purge_state.fe_count > 0) { + erts_release_code_stage_permission(); + } + + finalize_purge_operation(BIF_P, ret == am_true); - if (literals) { + if (literals) { erts_queue_release_literals(BIF_P, literals); - } + } - return ret; + return ret; } default: - BIF_ERROR(BIF_P, BADARG); + raise_badarg: + if (purge_state.fe_count > 0) { + ASSERT(is_value(purge_state.module)); + erts_release_code_stage_permission(); + } + BIF_ERROR(BIF_P, BADARG); } } diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 2142830ae8af..559a417128c4 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2020. All Rights Reserved. + * Copyright Ericsson AB 2000-2023. 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. @@ -58,8 +58,10 @@ #define ERTS_BPF_TIME_TRACE 0x20 #define ERTS_BPF_TIME_TRACE_ACTIVE 0x40 #define ERTS_BPF_GLOBAL_TRACE 0x80 +#define ERTS_BPF_MEM_TRACE 0x100 +#define ERTS_BPF_MEM_TRACE_ACTIVE 0x200 -#define ERTS_BPF_ALL 0xFF +#define ERTS_BPF_ALL 0x3FF erts_atomic32_t erts_active_bp_index; erts_atomic32_t erts_staging_bp_index; @@ -103,6 +105,12 @@ release_bp_sched_ix(Uint32 ix) /* ** Helpers */ +const ErtsCodeInfo* erts_trace_call(Process* c_p, + const ErtsCodeInfo *ci, + BpDataAccumulator accum, + int psd_ix, + BpDataCallTrace* bdt); + static ErtsTracer do_call_trace(Process* c_p, ErtsCodeInfo *info, Eterm* reg, int local, Binary* ms, ErtsTracer tracer); static void set_break(BpFunctions* f, Binary *match_spec, Uint break_flags, @@ -116,27 +124,30 @@ static void set_function_break(ErtsCodeInfo *ci, static void clear_break(BpFunctions* f, Uint break_flags); static int clear_function_break(const ErtsCodeInfo *ci, Uint break_flags); -static BpDataTime* get_time_break(const ErtsCodeInfo *ci); +static BpDataCallTrace* get_time_break(const ErtsCodeInfo *ci); +static BpDataCallTrace* get_memory_break(const ErtsCodeInfo *ci); static GenericBpData* check_break(const ErtsCodeInfo *ci, Uint break_flags); static void bp_meta_unref(BpMetaTracer *bmt); static void bp_count_unref(BpCount *bcp); -static void bp_time_unref(BpDataTime *bdt); -static void consolidate_bp_data(Module *modp, ErtsCodeInfo *ci, int local); -static void uninstall_breakpoint(ErtsCodeInfo *ci); +static void bp_calltrace_unref(BpDataCallTrace *bdt); +static void consolidate_bp_data(struct erl_module_instance *mi, + ErtsCodeInfo *ci, int local); +static void uninstall_breakpoint(ErtsCodeInfo *ci_rw, + const ErtsCodeInfo *ci_exec); /* bp_hash */ -#define BP_TIME_ADD(pi0, pi1) \ - do { \ - (pi0)->count += (pi1)->count; \ - (pi0)->time += (pi1)->time; \ +#define BP_ACCUMULATE(pi0, pi1) \ + do { \ + (pi0)->count += (pi1)->count; \ + (pi0)->accumulator += (pi1)->accumulator; \ } while(0) -static void bp_hash_init(bp_time_hash_t *hash, Uint n); -static void bp_hash_rehash(bp_time_hash_t *hash, Uint n); -static ERTS_INLINE bp_data_time_item_t * bp_hash_get(bp_time_hash_t *hash, bp_data_time_item_t *sitem); -static ERTS_INLINE bp_data_time_item_t * bp_hash_put(bp_time_hash_t *hash, bp_data_time_item_t *sitem); -static void bp_hash_delete(bp_time_hash_t *hash); +static void bp_hash_init(bp_trace_hash_t *hash, Uint n); +static void bp_hash_rehash(bp_trace_hash_t *hash, Uint n); +static ERTS_INLINE bp_data_trace_item_t * bp_hash_get(bp_trace_hash_t *hash, bp_data_trace_item_t *sitem); +static ERTS_INLINE bp_data_trace_item_t * bp_hash_put(bp_trace_hash_t *hash, bp_data_trace_item_t *sitem); +static void bp_hash_delete(bp_trace_hash_t *hash); /* ************************************************************************* ** External interfaces @@ -187,16 +198,11 @@ erts_bp_match_functions(BpFunctions* f, ErtsCodeMFA *mfa, int specified) } } - for (fi = 0; fi < num_functions; fi++) { - ErtsCodeInfo* ci; - void *w_ptr; - - w_ptr = erts_writable_code_ptr(&module[current]->curr, - code_hdr->functions[fi]); - ci = (ErtsCodeInfo*)w_ptr; + for (fi = 0; fi < num_functions; fi++) { + const ErtsCodeInfo* ci = code_hdr->functions[fi]; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif switch (specified) { case 3: @@ -212,10 +218,10 @@ erts_bp_match_functions(BpFunctions* f, ErtsCodeMFA *mfa, int specified) break; } /* Store match */ - f->matching[i].ci = ci; + f->matching[i].code_info = ci; f->matching[i].mod = module[current]; i++; - } + } } f->matched = i; Free(module); @@ -260,12 +266,12 @@ erts_bp_match_export(BpFunctions* f, ErtsCodeMFA *mfa, int specified) ASSERT(BeamIsOpCode(ep->trampoline.common.op, op_i_generic_breakpoint)); } - f->matching[ne].ci = &ep->info; - f->matching[ne].mod = erts_get_module(ep->info.mfa.module, code_ix); - - ne++; + f->matching[ne].code_info = &ep->info; + f->matching[ne].mod = erts_get_module(ep->info.mfa.module, code_ix); + ne++; } + f->matched = ne; } @@ -279,23 +285,76 @@ erts_bp_free_matched_functions(BpFunctions* f) } void -erts_consolidate_bp_data(BpFunctions* f, int local) +erts_consolidate_export_bp_data(BpFunctions* f) { BpFunction* fs = f->matching; - Uint i; - Uint n = f->matched; + Uint i, n; + + ERTS_LC_ASSERT(erts_has_code_mod_permission()); - ERTS_LC_ASSERT(erts_has_code_write_permission()); + n = f->matched; for (i = 0; i < n; i++) { - consolidate_bp_data(fs[i].mod, fs[i].ci, local); + struct erl_module_instance *mi; + ErtsCodeInfo *ci_rw; + + mi = fs[i].mod ? &fs[i].mod->curr : NULL; + + /* Export entries are always writable, discard const. */ + ci_rw = (ErtsCodeInfo*)fs[i].code_info; + + ASSERT(mi == NULL || + !ErtsInArea(ci_rw, + mi->executable_region, + mi->code_length)); + + consolidate_bp_data(mi, ci_rw, 0); + } +} + +void +erts_consolidate_local_bp_data(BpFunctions* f) +{ + struct erl_module_instance *prev_mi; + BpFunction* fs = f->matching; + Uint i, n; + + ERTS_LC_ASSERT(erts_has_code_mod_permission()); + + n = f->matched; + prev_mi = NULL; + + for (i = 0; i < n; i++) { + struct erl_module_instance *mi; + ErtsCodeInfo *ci_rw; + + ASSERT(fs[i].mod); + mi = &fs[i].mod->curr; + + if (prev_mi != mi) { + if (prev_mi != NULL) { + erts_seal_module(prev_mi); + } + + erts_unseal_module(mi); + prev_mi = mi; + } + + ci_rw = (ErtsCodeInfo*)erts_writable_code_ptr(mi, fs[i].code_info); + + consolidate_bp_data(mi, ci_rw, 1); + } + + if (prev_mi != NULL) { + erts_seal_module(prev_mi); } } static void -consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) +consolidate_bp_data(struct erl_module_instance *mi, + ErtsCodeInfo *ci_rw, int local) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci_rw->gen_bp; GenericBpData* src; GenericBpData* dst; Uint flags; @@ -324,7 +383,10 @@ consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) bp_count_unref(dst->count); } if (flags & ERTS_BPF_TIME_TRACE) { - bp_time_unref(dst->time); + bp_calltrace_unref(dst->time); + } + if (flags & ERTS_BPF_MEM_TRACE) { + bp_calltrace_unref(dst->memory); } /* @@ -333,24 +395,25 @@ consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) flags = dst->flags = src->flags; if (flags == 0) { - if (modp) { + if (mi) { if (local) { - modp->curr.num_breakpoints--; + mi->num_breakpoints--; } else { - modp->curr.num_traced_exports--; + mi->num_traced_exports--; } - ASSERT(modp->curr.num_breakpoints >= 0); - ASSERT(modp->curr.num_traced_exports >= 0); + ASSERT(mi->num_breakpoints >= 0); + ASSERT(mi->num_traced_exports >= 0); #if !defined(BEAMASM) && defined(DEBUG) { - BeamInstr instr = *(const BeamInstr*)erts_codeinfo_to_code(ci); + BeamInstr instr = *(const BeamInstr*)erts_codeinfo_to_code(ci_rw); ASSERT(!BeamIsOpCode(instr, op_i_generic_breakpoint)); } #endif - } - ci->u.gen_bp = NULL; - Free(g); - return; + } + + ci_rw->gen_bp = NULL; + Free(g); + return; } /* @@ -377,6 +440,11 @@ consolidate_bp_data(Module* modp, ErtsCodeInfo *ci, int local) erts_refc_inc(&dst->time->refc, 1); ASSERT(dst->time->hash); } + if (flags & ERTS_BPF_MEM_TRACE) { + dst->memory = src->memory; + erts_refc_inc(&dst->memory->refc, 1); + ASSERT(dst->memory->hash); + } } void @@ -392,32 +460,38 @@ erts_commit_staged_bp(void) void erts_install_breakpoints(BpFunctions* f) { - Uint i; - Uint n = f->matched; + struct erl_module_instance *prev_mi; + Uint i, n; + + n = f->matched; + prev_mi = NULL; for (i = 0; i < n; i++) { - ErtsCodeInfo* ci = f->matching[i].ci; - GenericBp* g = ci->u.gen_bp; - Module* modp = f->matching[i].mod; -#ifdef BEAMASM - if ((erts_asm_bp_get_flags(ci) & ERTS_ASM_BP_FLAG_BP) == 0 && g) { - /* - * The breakpoint must be disabled in the active data - * (it will enabled later by switching bp indices), - * and enabled in the staging data. - */ - ASSERT(g->data[erts_active_bp_ix()].flags == 0); - ASSERT(g->data[erts_staging_bp_ix()].flags != 0); + struct erl_module_instance *mi; + const ErtsCodeInfo *ci_exec; + ErtsCodeInfo *ci_rw; + GenericBp *g; + Module *modp; + + modp = f->matching[i].mod; + mi = &modp->curr; + + if (prev_mi != mi) { + if (prev_mi != NULL) { + erts_seal_module(prev_mi); + } - erts_asm_bp_set_flag(ci, ERTS_ASM_BP_FLAG_BP); - modp->curr.num_breakpoints++; + erts_unseal_module(mi); + prev_mi = mi; } -#else - BeamInstr volatile *pc = (BeamInstr*)erts_codeinfo_to_code(ci); - BeamInstr instr = *pc; - if (!BeamIsOpCode(instr, op_i_generic_breakpoint) && g) { - BeamInstr br = BeamOpCodeAddr(op_i_generic_breakpoint); + ci_exec = f->matching[i].code_info; + ci_rw = (ErtsCodeInfo*)erts_writable_code_ptr(mi, ci_exec); + + g = ci_rw->gen_bp; + +#ifdef BEAMASM + if ((erts_asm_bp_get_flags(ci_exec) & ERTS_ASM_BP_FLAG_BP) == 0 && g) { /* * The breakpoint must be disabled in the active data * (it will enabled later by switching bp indices), @@ -426,56 +500,109 @@ erts_install_breakpoints(BpFunctions* f) ASSERT(g->data[erts_active_bp_ix()].flags == 0); ASSERT(g->data[erts_staging_bp_ix()].flags != 0); - /* - * The following write is not protected by any lock. We - * assume that the hardware guarantees that a write of an - * aligned word-size writes is atomic (i.e. that other - * processes executing this code will not see a half - * pointer). - * - * The contents of *pc is marked 'volatile' to ensure that - * the compiler will do a single full-word write, and not - * try any fancy optimizations to write a half word. - */ - instr = BeamSetCodeAddr(instr, br); - *pc = instr; - modp->curr.num_breakpoints++; - } + erts_asm_bp_set_flag(ci_rw, ci_exec, ERTS_ASM_BP_FLAG_BP); + mi->num_breakpoints++; + } +#else + { + BeamInstr volatile *pc = (BeamInstr*)erts_codeinfo_to_code(ci_rw); + BeamInstr instr = *pc; + + ASSERT(ci_exec == ci_rw); + (void)ci_exec; + + if (!BeamIsOpCode(instr, op_i_generic_breakpoint) && g) { + BeamInstr br = BeamOpCodeAddr(op_i_generic_breakpoint); + + /* The breakpoint must be disabled in the active data + * (it will enabled later by switching bp indices), + * and enabled in the staging data. */ + ASSERT(g->data[erts_active_bp_ix()].flags == 0); + ASSERT(g->data[erts_staging_bp_ix()].flags != 0); + + /* The following write is not protected by any lock. We + * assume that the hardware guarantees that a write of an + * aligned word-size writes is atomic (i.e. that other + * processes executing this code will not see a half + * pointer). + * + * The contents of *pc is marked 'volatile' to ensure that + * the compiler will do a single full-word write, and not + * try any fancy optimizations to write a half word. + */ + instr = BeamSetCodeAddr(instr, br); + *pc = instr; + + mi->num_breakpoints++; + } + } #endif } + + if (prev_mi != NULL) { + erts_seal_module(prev_mi); + } } void erts_uninstall_breakpoints(BpFunctions* f) { - Uint i; - Uint n = f->matched; + struct erl_module_instance *prev_mi; + Uint i, n; + + n = f->matched; + prev_mi = NULL; for (i = 0; i < n; i++) { - uninstall_breakpoint(f->matching[i].ci); + struct erl_module_instance *mi = &f->matching[i].mod->curr; + const ErtsCodeInfo *ci_exec; + ErtsCodeInfo *ci_rw; + + mi = &f->matching[i].mod->curr; + + if (prev_mi != mi) { + if (prev_mi != NULL) { + erts_seal_module(prev_mi); + } + + erts_unseal_module(mi); + prev_mi = mi; + } + + ci_exec = f->matching[i].code_info; + ci_rw = erts_writable_code_ptr(mi, ci_exec); + + uninstall_breakpoint(ci_rw, ci_exec); + } + + if (prev_mi != NULL) { + erts_seal_module(prev_mi); } } #ifdef BEAMASM static void -uninstall_breakpoint(ErtsCodeInfo *ci) +uninstall_breakpoint(ErtsCodeInfo *ci_rw, const ErtsCodeInfo *ci_exec) { - if (erts_asm_bp_get_flags(ci) & ERTS_ASM_BP_FLAG_BP) { - GenericBp* g = ci->u.gen_bp; + if (erts_asm_bp_get_flags(ci_rw) & ERTS_ASM_BP_FLAG_BP) { + GenericBp* g = ci_rw->gen_bp; if (g->data[erts_active_bp_ix()].flags == 0) { - erts_asm_bp_unset_flag(ci, ERTS_ASM_BP_FLAG_BP); + erts_asm_bp_unset_flag(ci_rw, ci_exec, ERTS_ASM_BP_FLAG_BP); } } } #else static void -uninstall_breakpoint(ErtsCodeInfo *ci) +uninstall_breakpoint(ErtsCodeInfo *ci_rw, const ErtsCodeInfo *ci_exec) { - BeamInstr *pc = (BeamInstr*)erts_codeinfo_to_code(ci); + BeamInstr *pc = (BeamInstr*)erts_codeinfo_to_code(ci_rw); + + ASSERT(ci_rw == ci_exec); + (void)ci_exec; if (BeamIsOpCode(*pc, op_i_generic_breakpoint)) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci_rw->gen_bp; if (g->data[erts_active_bp_ix()].flags == 0) { /* @@ -530,6 +657,13 @@ erts_set_time_break(BpFunctions* f, enum erts_break_op count_op) count_op, erts_tracer_nil); } +void +erts_set_memory_break(BpFunctions* f, enum erts_break_op count_op) +{ + set_break(f, 0, ERTS_BPF_MEM_TRACE|ERTS_BPF_MEM_TRACE_ACTIVE, + count_op, erts_tracer_nil); +} + void erts_clear_trace_break(BpFunctions* f) { @@ -539,7 +673,7 @@ erts_clear_trace_break(BpFunctions* f) void erts_clear_export_trace(ErtsCodeInfo *ci, int local) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci->gen_bp; if (g) { Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE; @@ -575,6 +709,12 @@ erts_clear_time_break(BpFunctions* f) clear_break(f, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE); } +void +erts_clear_memory_break(BpFunctions* f) +{ + clear_break(f, ERTS_BPF_MEM_TRACE|ERTS_BPF_MEM_TRACE_ACTIVE); +} + void erts_clear_all_breaks(BpFunctions* f) { @@ -583,6 +723,7 @@ erts_clear_all_breaks(BpFunctions* f) int erts_clear_module_break(Module *modp) { + struct erl_module_instance *mi; const BeamCodeHeader* code_hdr; Uint n; Uint i; @@ -590,7 +731,9 @@ erts_clear_module_break(Module *modp) { ERTS_LC_ASSERT(erts_thr_progress_is_blocking()); ASSERT(modp); - code_hdr = modp->curr.code_hdr; + mi = &modp->curr; + + code_hdr = mi->code_hdr; if (!code_hdr) { return 0; } @@ -604,19 +747,23 @@ erts_clear_module_break(Module *modp) { erts_commit_staged_bp(); + erts_unseal_module(mi); + for (i = 0; i < n; ++i) { - ErtsCodeInfo* ci; - void *w_ptr; + const ErtsCodeInfo *ci_exec; + ErtsCodeInfo *ci_rw; - w_ptr = erts_writable_code_ptr(&modp->curr, - code_hdr->functions[i]); - ci = (ErtsCodeInfo*)w_ptr; + ci_exec = code_hdr->functions[i]; + ci_rw = (ErtsCodeInfo*)erts_writable_code_ptr(mi, ci_exec); - uninstall_breakpoint(ci); - consolidate_bp_data(modp, ci, 1); - ASSERT(ci->u.gen_bp == NULL); + uninstall_breakpoint(ci_rw, ci_exec); + consolidate_bp_data(mi, ci_rw, 1); + + ASSERT(ci_rw->gen_bp == NULL); } + erts_seal_module(mi); + return n; } @@ -638,8 +785,8 @@ erts_clear_export_break(Module* modp, Export *ep) clear_function_break(ci, ERTS_BPF_ALL); erts_commit_staged_bp(); - consolidate_bp_data(modp, ci, 0); - ASSERT(ci->u.gen_bp == NULL); + consolidate_bp_data(&modp->curr, ci, 0); + ASSERT(ci->gen_bp == NULL); } /* @@ -653,25 +800,59 @@ erts_clear_export_break(Module* modp, Export *ep) * being the function which is the caller, but rather the function * which we are about to return to. */ -static void fixup_cp_before_trace(Process *c_p, int *return_to_trace) +static void fixup_cp_before_trace(Process *c_p, + Eterm cp_save[2], + int *return_to_trace) { + const ErtsFrameLayout frame_layout = erts_frame_layout; Eterm *cpp = c_p->stop; + if (frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + ASSERT(is_CP(cpp[1])); + cp_save[1] = cpp[1]; + } + + ASSERT(is_CP(cpp[0])); + cp_save[0] = cpp[0]; + for (;;) { - ErtsCodePtr w = cp_val(*cpp); + ErtsCodePtr w; + + erts_inspect_frame(cpp, &w); + if (BeamIsReturnTrace(w)) { - cpp += 3; + cpp += CP_SIZE + BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(w)) { + cpp += CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; } else if (BeamIsReturnToTrace(w)) { *return_to_trace = 1; - cpp += 1; - } else if (BeamIsReturnTimeTrace(w)) { - cpp += 2; + cpp += CP_SIZE + BEAM_RETURN_TO_TRACE_FRAME_SZ; } else { - break; + if (frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + ASSERT(is_CP(cpp[1])); + c_p->stop[1] = cpp[1]; + } + + ASSERT(is_CP(cpp[0])); + c_p->stop[0] = cpp[0]; + + return; } } - c_p->stop[0] = (Eterm) cp_val(*cpp); - ASSERT(is_CP(*cpp)); +} + +static void restore_cp_after_trace(Process *c_p, const Eterm cp_save[2]) { + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + c_p->stop[1] = cp_save[1]; + } + + c_p->stop[0] = cp_save[0]; +} + +static ERTS_INLINE Uint get_allocated_words(Process *c_p, Sint allocated) { + if (c_p->abandoned_heap) + return allocated + c_p->htop - c_p->heap + c_p->mbuf_sz; + return allocated + c_p->htop - c_p->high_water + c_p->mbuf_sz; } BeamInstr @@ -683,21 +864,24 @@ erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg) ErtsBpIndex ix = erts_active_bp_ix(); #ifndef BEAMASM - ASSERT(BeamIsOpCode(info->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(info->u.op, op_i_func_info_IaaI)); #endif - g = info->u.gen_bp; + g = info->gen_bp; bp = &g->data[ix]; bp_flags = bp->flags; ASSERT((bp_flags & ~ERTS_BPF_ALL) == 0); if (bp_flags & (ERTS_BPF_LOCAL_TRACE| ERTS_BPF_GLOBAL_TRACE| - ERTS_BPF_TIME_TRACE_ACTIVE) && + ERTS_BPF_TIME_TRACE_ACTIVE| + ERTS_BPF_MEM_TRACE_ACTIVE) && !IS_TRACED_FL(c_p, F_TRACE_CALLS)) { bp_flags &= ~(ERTS_BPF_LOCAL_TRACE| ERTS_BPF_GLOBAL_TRACE| ERTS_BPF_TIME_TRACE| - ERTS_BPF_TIME_TRACE_ACTIVE); + ERTS_BPF_TIME_TRACE_ACTIVE| + ERTS_BPF_MEM_TRACE| + ERTS_BPF_MEM_TRACE_ACTIVE); if (bp_flags == 0) { /* Quick exit */ return g->orig_instr; } @@ -733,35 +917,69 @@ erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *info, Eterm* reg) erts_atomic_inc_nob(&bp->count->acount); } - if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { - const ErtsCodeInfo* prev_info; + if (bp_flags & (ERTS_BPF_TIME_TRACE_ACTIVE | ERTS_BPF_MEM_TRACE_ACTIVE)) { + const ErtsCodeInfo* prev_info = 0; ErtsCodePtr w; Eterm* E; - prev_info= erts_trace_time_call(c_p, info, bp->time); + if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { + BpDataAccumulator time = get_mtime(c_p); + prev_info = erts_trace_call(c_p, info, time, ERTS_PSD_CALL_TIME_BP, bp->time); + } + + if (bp_flags & ERTS_BPF_MEM_TRACE_ACTIVE) { + BpDataAccumulator allocated; + /* if this is initial call, ignore 'allocated' */ + if (c_p->u.initial.function == info->mfa.function && c_p->u.initial.module == info->mfa.module && + c_p->u.initial.arity == info->mfa.arity) + allocated = 0; + else { + process_breakpoint_trace_t * pbt = ERTS_PROC_GET_CALL_MEMORY(c_p); + allocated = get_allocated_words(c_p, pbt ? pbt->allocated : 0); + } + prev_info = erts_trace_call(c_p, info, allocated, ERTS_PSD_CALL_MEMORY_BP, bp->memory); + } + E = c_p->stop; - w = (ErtsCodePtr) E[0]; - if (!(BeamIsReturnTrace(w) || BeamIsReturnToTrace(w) || BeamIsReturnTimeTrace(w))) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (HeapWordsLeft(c_p) < 2) { - (void) erts_garbage_collect(c_p, 2, reg, info->mfa.arity); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - } - E = c_p->stop; - ASSERT(c_p->htop <= E && E <= c_p->hend); + erts_inspect_frame(E, &w); - E -= 2; - E[1] = prev_info ? make_cp(erts_codeinfo_to_code(prev_info)) : NIL; - E[0] = (Eterm) beam_return_time_trace; - c_p->stop = E; - } + if (!(BeamIsReturnTrace(w) || + BeamIsReturnToTrace(w) || + BeamIsReturnCallAccTrace(w))) { + int need = CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + + ASSERT(c_p->htop <= E && E <= c_p->hend); + + if (HeapWordsLeft(c_p) < need) { + (void) erts_garbage_collect(c_p, need, + reg, info->mfa.arity); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + } + + E = c_p->stop; + + ASSERT(c_p->htop <= E && E <= c_p->hend); + ERTS_CT_ASSERT(BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ == 2); + E -= 3; + E[2] = make_small(bp_flags); + E[1] = prev_info ? make_cp(erts_codeinfo_to_code(prev_info)) : NIL; + E[0] = make_cp(beam_call_trace_return); + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + E -= 1; + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + c_p->stop = E; + } } if (bp_flags & ERTS_BPF_DEBUG) { return BeamOpCodeAddr(op_i_debug_breakpoint); } else { - return g->orig_instr; + return g->orig_instr; } } @@ -769,67 +987,102 @@ static ErtsTracer do_call_trace(Process* c_p, ErtsCodeInfo* info, Eterm* reg, int local, Binary* ms, ErtsTracer tracer) { + Eterm cp_save[2] = {0, 0}; int return_to_trace = 0; Uint32 flags; Uint need = 0; - Eterm cp_save; - Eterm* E = c_p->stop; + Eterm* E; - cp_save = E[0]; + fixup_cp_before_trace(c_p, cp_save, &return_to_trace); - fixup_cp_before_trace(c_p, &return_to_trace); ERTS_UNREQ_PROC_MAIN_LOCK(c_p); flags = erts_call_trace(c_p, info, ms, reg, local, &tracer); ERTS_REQ_PROC_MAIN_LOCK(c_p); - E[0] = cp_save; + restore_cp_after_trace(c_p, cp_save); + + E = c_p->stop; ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { - need += 1; + need += CP_SIZE; } + if (flags & MATCH_SET_RX_TRACE) { - need += 3 + size_object(tracer); + need += CP_SIZE + 2 + size_object(tracer); } + if (need) { - ASSERT(c_p->htop <= E && E <= c_p->hend); - if (HeapWordsLeft(c_p) < need) { - (void) erts_garbage_collect(c_p, need, reg, info->mfa.arity); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - E = c_p->stop; - } - } - if (flags & MATCH_SET_RETURN_TO_TRACE && !return_to_trace) { - E -= 1; - ASSERT(c_p->htop <= E && E <= c_p->hend); - E[0] = (Eterm) beam_return_to_trace; - c_p->stop = E; - } - if (flags & MATCH_SET_RX_TRACE) { - E -= 3; - c_p->stop = E; - ASSERT(c_p->htop <= E && E <= c_p->hend); - ASSERT(is_CP((Eterm) (UWord) (&info->mfa.module))); - ASSERT(IS_TRACER_VALID(tracer)); - E[2] = copy_object(tracer, c_p); - E[1] = make_cp(&info->mfa.module); - E[0] = (Eterm) ((flags & MATCH_SET_EXCEPTION_TRACE) ? - beam_exception_trace : beam_return_trace); - erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); - ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE; - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + ASSERT(c_p->htop <= E && E <= c_p->hend); + + if (HeapWordsLeft(c_p) < need) { + (void) erts_garbage_collect(c_p, need, reg, info->mfa.arity); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + E = c_p->stop; + } + + if ((flags & MATCH_SET_RETURN_TO_TRACE) && !return_to_trace) { + E -= CP_SIZE; + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + E[0] = make_cp(beam_return_to_trace); + } else { + E[1] = make_cp(beam_return_to_trace); + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + ASSERT(c_p->htop <= E && E <= c_p->hend); + + c_p->stop = E; + } + + if (flags & MATCH_SET_RX_TRACE) { + ErtsCodePtr trace_cp; + + if (flags & MATCH_SET_EXCEPTION_TRACE) { + trace_cp = beam_exception_trace; + } else { + trace_cp = beam_return_trace; + } + + E -= 2; + E[1] = copy_object(tracer, c_p); + E[0] = make_cp(&info->mfa.module); + + E -= CP_SIZE; + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + E[0] = make_cp(trace_cp); + } else { + E[1] = make_cp(trace_cp); + E[0] = make_cp(FRAME_POINTER(c_p)); + FRAME_POINTER(c_p) = E; + } + + ASSERT(c_p->htop <= E && E <= c_p->hend); + ASSERT(is_CP((Eterm)(&info->mfa.module))); + ASSERT(IS_TRACER_VALID(tracer)); + + c_p->stop = E; + + erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE; + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); + } } + return tracer; } const ErtsCodeInfo* -erts_trace_time_call(Process* c_p, const ErtsCodeInfo *info, BpDataTime* bdt) +erts_trace_call(Process* c_p, const ErtsCodeInfo *info, BpDataAccumulator accum, + int psd_ix, BpDataCallTrace* bdt) { - ErtsMonotonicTime time; - process_breakpoint_time_t *pbt = NULL; - bp_data_time_item_t sitem, *item = NULL; - bp_time_hash_t *h = NULL; - BpDataTime *pbdt = NULL; + process_breakpoint_trace_t *pbt = NULL; + bp_data_trace_item_t sitem, *item = NULL; + bp_trace_hash_t *h = NULL; + BpDataCallTrace *pbdt = NULL; Uint32 six = acquire_bp_sched_ix(c_p); const ErtsCodeInfo* prev_info; @@ -837,32 +1090,33 @@ erts_trace_time_call(Process* c_p, const ErtsCodeInfo *info, BpDataTime* bdt) ASSERT(erts_atomic32_read_acqb(&c_p->state) & (ERTS_PSFLG_RUNNING | ERTS_PSFLG_DIRTY_RUNNING)); - /* get previous timestamp and breakpoint + /* get previous (timestamp or allocated memory size) and breakpoint * from the process psd */ - pbt = ERTS_PROC_GET_CALL_TIME(c_p); - time = get_mtime(c_p); + pbt = (process_breakpoint_trace_t *) erts_psd_get(c_p, psd_ix); /* get pbt - * timestamp = t0 + * timestamp/allocated = ta0 * lookup bdt from code - * set ts0 to pbt + * set ts0/alloc0 to pbt * add call count here? */ if (pbt == 0) { /* First call of process to instrumented function */ - pbt = Alloc(sizeof(process_breakpoint_time_t)); - (void) ERTS_PROC_SET_CALL_TIME(c_p, pbt); + pbt = Alloc(sizeof(process_breakpoint_trace_t)); + erts_psd_set(c_p, psd_ix, pbt); + pbt->allocated = 0; pbt->ci = NULL; } else if (pbt->ci) { - /* add time to previous code */ - sitem.time = time - pbt->time; + /* add time/allocation to previous code */ + sitem.accumulator = accum - pbt->accumulator; sitem.pid = c_p->common.id; sitem.count = 0; /* previous breakpoint */ - pbdt = get_time_break(pbt->ci); + pbdt = (psd_ix == ERTS_PSD_CALL_TIME_BP) ? + get_time_break(pbt->ci) : get_memory_break(pbt->ci); /* if null then the breakpoint was removed */ if (pbdt) { @@ -875,7 +1129,7 @@ erts_trace_time_call(Process* c_p, const ErtsCodeInfo *info, BpDataTime* bdt) if (!item) { item = bp_hash_put(h, &sitem); } else { - BP_TIME_ADD(item, &sitem); + BP_ACCUMULATE(item, &sitem); } } } @@ -884,7 +1138,7 @@ erts_trace_time_call(Process* c_p, const ErtsCodeInfo *info, BpDataTime* bdt) /* Add count to this code */ sitem.pid = c_p->common.id; sitem.count = 1; - sitem.time = 0; + sitem.accumulator = 0; /* this breakpoint */ ASSERT(bdt); @@ -897,79 +1151,96 @@ erts_trace_time_call(Process* c_p, const ErtsCodeInfo *info, BpDataTime* bdt) if (!item) { item = bp_hash_put(h, &sitem); } else { - BP_TIME_ADD(item, &sitem); + BP_ACCUMULATE(item, &sitem); } prev_info = pbt->ci; pbt->ci = info; - pbt->time = time; + pbt->accumulator = accum; release_bp_sched_ix(six); return prev_info; } -void -erts_trace_time_return(Process *p, const ErtsCodeInfo *prev_info) -{ - ErtsMonotonicTime time; - process_breakpoint_time_t *pbt = NULL; - bp_data_time_item_t sitem, *item = NULL; - bp_time_hash_t *h = NULL; - BpDataTime *pbdt = NULL; - Uint32 six = acquire_bp_sched_ix(p); - - ASSERT(p); - ASSERT(erts_atomic32_read_acqb(&p->state) & (ERTS_PSFLG_RUNNING - | ERTS_PSFLG_DIRTY_RUNNING)); - - /* get previous timestamp and breakpoint - * from the process psd */ - - pbt = ERTS_PROC_GET_CALL_TIME(p); - time = get_mtime(p); - - /* get pbt - * lookup bdt from code - * timestamp = t1 - * get ts0 from pbt - * get item from bdt->hash[bp_hash(p->id)] - * ack diff (t1, t0) to item - */ - if (pbt) { - - /* might have been removed due to - * trace_pattern(false) - */ - ASSERT(pbt->ci); +static void +call_trace_add(Process *p, BpDataCallTrace *pbdt, Uint32 six, + BpDataAccumulator accum, BpDataAccumulator prev_accum) +{ + bp_data_trace_item_t sitem, *item = NULL; + bp_trace_hash_t *h = NULL; - sitem.time = time - pbt->time; - sitem.pid = p->common.id; - sitem.count = 0; + sitem.accumulator = accum - prev_accum; + sitem.pid = p->common.id; + sitem.count = 0; - /* previous breakpoint */ - pbdt = get_time_break(pbt->ci); + /* beware, the trace_pattern might have been removed */ + if (pbdt) { - /* beware, the trace_pattern might have been removed */ - if (pbdt) { + h = &(pbdt->hash[six]); - h = &(pbdt->hash[six]); + ASSERT(h); + ASSERT(h->item); - ASSERT(h); - ASSERT(h->item); + item = bp_hash_get(h, &sitem); + if (!item) { + item = bp_hash_put(h, &sitem); + } else { + BP_ACCUMULATE(item, &sitem); + } + } +} - item = bp_hash_get(h, &sitem); - if (!item) { - item = bp_hash_put(h, &sitem); - } else { - BP_TIME_ADD(item, &sitem); - } +void +erts_call_trace_return(Process *p, const ErtsCodeInfo *prev_info, + Eterm bp_flags_term) +{ + process_breakpoint_trace_t *pbt = NULL; + BpDataCallTrace *pbdt; + Uint32 six = acquire_bp_sched_ix(p); + const Uint bp_flags = unsigned_val(bp_flags_term); - } + ASSERT(p); + ASSERT(erts_atomic32_read_acqb(&p->state) & (ERTS_PSFLG_RUNNING + | ERTS_PSFLG_DIRTY_RUNNING)); - pbt->ci = prev_info; - pbt->time = time; + /* get pbt + * lookup bdt from code + * timestamp/alloc = t1 + * get ts0/alloc from pbt + * get item from bdt->hash[bp_hash(p->id)] + * add diff (t1, t0) to item + */ + if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { + /* get previous timestamp and breakpoint + * from the process psd */ + pbt = ERTS_PROC_GET_CALL_TIME(p); + if (pbt) { + ErtsMonotonicTime time = get_mtime(p); + + /* might have been removed due to + * trace_pattern(false) + */ + ASSERT(pbt->ci); + /* previous breakpoint */ + pbdt = get_time_break(pbt->ci); + call_trace_add(p, pbdt, six, time, pbt->accumulator); + pbt->ci = prev_info; + pbt->accumulator = time; + } + } + if (bp_flags & ERTS_BPF_MEM_TRACE_ACTIVE) { + pbt = (process_breakpoint_trace_t *) erts_psd_get(p, ERTS_PSD_CALL_MEMORY_BP); + if (pbt) { + Sint allocated = get_allocated_words(p, pbt->allocated); + /* previous breakpoint */ + ASSERT(pbt->ci); + pbdt = get_memory_break(pbt->ci); + call_trace_add(p, pbdt, six, allocated, pbt->accumulator); + pbt->ci = prev_info; + pbt->accumulator = allocated; + } } release_bp_sched_ix(six); @@ -1022,65 +1293,76 @@ erts_is_count_break(const ErtsCodeInfo *ci, Uint *count_ret) return 0; } -int erts_is_time_break(Process *p, const ErtsCodeInfo *ci, Eterm *retval) { +int erts_is_call_break(Process *p, int is_time, const ErtsCodeInfo *ci, + Eterm *retval) { Uint i, ix; - bp_time_hash_t hash; - Uint size; - Eterm *hp, t; - bp_data_time_item_t *item = NULL; - BpDataTime *bdt = get_time_break(ci); - - if (bdt) { - if (retval) { - /* collect all hashes to one hash */ - bp_hash_init(&hash, 64); - /* foreach threadspecific hash */ - for (i = 0; i < bdt->n; i++) { - bp_data_time_item_t *sitem; - - /* foreach hash bucket not NIL*/ - for(ix = 0; ix < bdt->hash[i].n; ix++) { - item = &(bdt->hash[i].item[ix]); - if (item->pid != NIL) { - sitem = bp_hash_get(&hash, item); - if (sitem) { - BP_TIME_ADD(sitem, item); - } else { - bp_hash_put(&hash, item); - } - } - } - } - /* *retval should be NIL or term from previous bif in export entry */ - - if (hash.used > 0) { - size = (5 + 2)*hash.used; - hp = HAlloc(p, size); - - for(ix = 0; ix < hash.n; ix++) { - item = &(hash.item[ix]); - if (item->pid != NIL) { - ErtsMonotonicTime sec, usec; - usec = ERTS_MONOTONIC_TO_USEC(item->time); - sec = usec / 1000000; - usec = usec - sec*1000000; - t = TUPLE4(hp, item->pid, - make_small(item->count), - make_small((Uint) sec), - make_small((Uint) usec)); - hp += 5; - *retval = CONS(hp, t, *retval); hp += 2; - } - } - } - bp_hash_delete(&hash); - } - return 1; - } + bp_trace_hash_t hash; + bp_data_trace_item_t *item = NULL; + BpDataCallTrace *bdt = is_time ? get_time_break(ci) : get_memory_break(ci); - return 0; -} + if (!bdt) + return 0; + ASSERT(retval); + /* collect all hashes to one hash */ + bp_hash_init(&hash, 64); + /* foreach threadspecific hash */ + for (i = 0; i < bdt->n; i++) { + bp_data_trace_item_t *sitem; + + /* foreach hash bucket not NIL*/ + for(ix = 0; ix < bdt->hash[i].n; ix++) { + item = &(bdt->hash[i].item[ix]); + if (item->pid != NIL) { + sitem = bp_hash_get(&hash, item); + if (sitem) { + BP_ACCUMULATE(sitem, item); + } else { + bp_hash_put(&hash, item); + } + } + } + } + /* *retval should be NIL or term from previous bif in export entry */ + + if (hash.used > 0) { + Uint size; + Eterm *hp, *hp_end, t; + + size = hash.used * (is_time ? (2+5) : (2+4+ERTS_MAX_SINT64_HEAP_SIZE)); + hp = HAlloc(p, size); + hp_end = hp + size; + + for(ix = 0; ix < hash.n; ix++) { + item = &(hash.item[ix]); + if (item->pid != NIL) { + if (is_time) { + BpDataAccumulator sec, usec; + usec = ERTS_MONOTONIC_TO_USEC(item->accumulator); + sec = usec / 1000000; + usec = usec - sec*1000000; + t = TUPLE4(hp, item->pid, + make_small(item->count), + make_small((Uint) sec), + make_small((Uint) usec)); + hp += 5; + } + else { + Eterm words = erts_bld_sint64(&hp, NULL, item->accumulator); + t = TUPLE3(hp, item->pid, + make_small(item->count), + words); + hp += 4; + } + *retval = CONS(hp, t, *retval); hp += 2; + } + } + ASSERT(hp <= hp_end); + HRelease(p, hp_end, hp); + } + bp_hash_delete(&hash); + return 1; +} const ErtsCodeInfo * erts_find_local_func(const ErtsCodeMFA *mfa) { @@ -1097,7 +1379,7 @@ erts_find_local_func(const ErtsCodeMFA *mfa) { for (i = 0; i < n; ++i) { ci = code_hdr->functions[i]; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif ASSERT(mfa->module == ci->mfa.module || is_nil(ci->mfa.module)); if (mfa->function == ci->mfa.function && @@ -1108,14 +1390,14 @@ erts_find_local_func(const ErtsCodeMFA *mfa) { return NULL; } -static void bp_hash_init(bp_time_hash_t *hash, Uint n) { - Uint size = sizeof(bp_data_time_item_t)*n; +static void bp_hash_init(bp_trace_hash_t *hash, Uint n) { + Uint size = sizeof(bp_data_trace_item_t)*n; Uint i; hash->n = n; hash->used = 0; - hash->item = (bp_data_time_item_t *)Alloc(size); + hash->item = (bp_data_trace_item_t *)Alloc(size); sys_memzero(hash->item, size); for(i = 0; i < n; ++i) { @@ -1123,15 +1405,15 @@ static void bp_hash_init(bp_time_hash_t *hash, Uint n) { } } -static void bp_hash_rehash(bp_time_hash_t *hash, Uint n) { - bp_data_time_item_t *item = NULL; - Uint size = sizeof(bp_data_time_item_t)*n; +static void bp_hash_rehash(bp_trace_hash_t *hash, Uint n) { + bp_data_trace_item_t *item = NULL; + Uint size = sizeof(bp_data_trace_item_t)*n; Uint ix; Uint hval; ASSERT(n > 0); - item = (bp_data_time_item_t *)Alloc(size); + item = (bp_data_trace_item_t *)Alloc(size); sys_memzero(item, size); for( ix = 0; ix < n; ++ix) { @@ -1151,7 +1433,7 @@ static void bp_hash_rehash(bp_time_hash_t *hash, Uint n) { } item[hval].pid = hash->item[ix].pid; item[hval].count = hash->item[ix].count; - item[hval].time = hash->item[ix].time; + item[hval].accumulator = hash->item[ix].accumulator; } } @@ -1159,10 +1441,10 @@ static void bp_hash_rehash(bp_time_hash_t *hash, Uint n) { hash->n = n; hash->item = item; } -static ERTS_INLINE bp_data_time_item_t * bp_hash_get(bp_time_hash_t *hash, bp_data_time_item_t *sitem) { +static ERTS_INLINE bp_data_trace_item_t * bp_hash_get(bp_trace_hash_t *hash, bp_data_trace_item_t *sitem) { Eterm pid = sitem->pid; Uint hval = (pid >> 4) % hash->n; - bp_data_time_item_t *item = NULL; + bp_data_trace_item_t *item = NULL; item = hash->item; @@ -1174,10 +1456,10 @@ static ERTS_INLINE bp_data_time_item_t * bp_hash_get(bp_time_hash_t *hash, bp_da return &(item[hval]); } -static ERTS_INLINE bp_data_time_item_t * bp_hash_put(bp_time_hash_t *hash, bp_data_time_item_t* sitem) { +static ERTS_INLINE bp_data_trace_item_t * bp_hash_put(bp_trace_hash_t *hash, bp_data_trace_item_t* sitem) { Uint hval; float r = 0.0; - bp_data_time_item_t *item; + bp_data_trace_item_t *item; /* make sure that the hash is not saturated */ /* if saturated, rehash it */ @@ -1199,25 +1481,33 @@ static ERTS_INLINE bp_data_time_item_t * bp_hash_put(bp_time_hash_t *hash, bp_da item = &(hash->item[hval]); item->pid = sitem->pid; - item->time = sitem->time; + item->accumulator = sitem->accumulator; item->count = sitem->count; hash->used++; return item; } -static void bp_hash_delete(bp_time_hash_t *hash) { +static void bp_hash_delete(bp_trace_hash_t *hash) { hash->n = 0; hash->used = 0; Free(hash->item); hash->item = NULL; } +static void bp_hash_reset(BpDataCallTrace* bdt) { + Uint i; + for (i = 0; i < bdt->n; i++) { + bp_hash_delete(&(bdt->hash[i])); + bp_hash_init(&(bdt->hash[i]), 32); + } +} + void erts_schedule_time_break(Process *p, Uint schedule) { - process_breakpoint_time_t *pbt = NULL; - bp_data_time_item_t sitem, *item = NULL; - bp_time_hash_t *h = NULL; - BpDataTime *pbdt = NULL; + process_breakpoint_trace_t *pbt = NULL; + bp_data_trace_item_t sitem, *item = NULL; + bp_trace_hash_t *h = NULL; + BpDataCallTrace *pbdt = NULL; Uint32 six = acquire_bp_sched_ix(p); ASSERT(p); @@ -1238,7 +1528,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { if (pbt->ci) { pbdt = get_time_break(pbt->ci); if (pbdt) { - sitem.time = get_mtime(p) - pbt->time; + sitem.accumulator = get_mtime(p) - pbt->accumulator; sitem.pid = p->common.id; sitem.count = 0; @@ -1251,7 +1541,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { if (!item) { item = bp_hash_put(h, &sitem); } else { - BP_TIME_ADD(item, &sitem); + BP_ACCUMULATE(item, &sitem); } } } @@ -1261,7 +1551,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) { * timestamp it and remove the previous * timestamp in the psd. */ - pbt->time = get_mtime(p); + pbt->accumulator = get_mtime(p); break; default : ASSERT(0); @@ -1282,14 +1572,35 @@ static void set_break(BpFunctions* f, Binary *match_spec, Uint break_flags, enum erts_break_op count_op, ErtsTracer tracer) { - Uint i; - Uint n; + struct erl_module_instance *prev_mi = NULL; + BpFunction* fs = f->matching; + Uint i, n; n = f->matched; + prev_mi = NULL; + for (i = 0; i < n; i++) { - set_function_break(f->matching[i].ci, + struct erl_module_instance *mi = &fs[i].mod->curr; + ErtsCodeInfo *ci_rw; + + if (prev_mi != mi) { + if (prev_mi != NULL) { + erts_seal_module(prev_mi); + } + + erts_unseal_module(mi); + prev_mi = mi; + } + + ci_rw = (ErtsCodeInfo *)erts_writable_code_ptr(mi, fs[i].code_info); + + set_function_break(ci_rw, match_spec, break_flags, - count_op, tracer); + count_op, tracer); + } + + if (prev_mi != NULL) { + erts_seal_module(prev_mi); } } @@ -1302,8 +1613,8 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, Uint common; ErtsBpIndex ix = erts_staging_bp_ix(); - ERTS_LC_ASSERT(erts_has_code_write_permission()); - g = ci->u.gen_bp; + ERTS_LC_ASSERT(erts_has_code_mod_permission()); + g = ci->gen_bp; if (g == 0) { int i; if (count_op == ERTS_BREAK_RESTART || count_op == ERTS_BREAK_PAUSE) { @@ -1331,7 +1642,7 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, for (i = 0; i < ERTS_NUM_BP_IX; i++) { g->data[i].flags = 0; } - ci->u.gen_bp = g; + ci->gen_bp = g; } bp = &g->data[ix]; @@ -1355,17 +1666,20 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); return; } else if (common & ERTS_BPF_TIME_TRACE) { - BpDataTime* bdt = bp->time; - Uint i = 0; - if (count_op == ERTS_BREAK_PAUSE) { bp->flags &= ~ERTS_BPF_TIME_TRACE_ACTIVE; } else { bp->flags |= ERTS_BPF_TIME_TRACE_ACTIVE; - for (i = 0; i < bdt->n; i++) { - bp_hash_delete(&(bdt->hash[i])); - bp_hash_init(&(bdt->hash[i]), 32); - } + bp_hash_reset(bp->time); + } + ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); + return; + } else if (common & ERTS_BPF_MEM_TRACE) { + if (count_op == ERTS_BREAK_PAUSE) { + bp->flags &= ~ERTS_BPF_MEM_TRACE_ACTIVE; + } else { + bp->flags |= ERTS_BPF_MEM_TRACE_ACTIVE; + bp_hash_reset(bp->memory); } ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); return; @@ -1396,19 +1710,23 @@ set_function_break(ErtsCodeInfo *ci, Binary *match_spec, Uint break_flags, erts_refc_init(&bcp->refc, 1); erts_atomic_init_nob(&bcp->acount, 0); bp->count = bcp; - } else if (break_flags & ERTS_BPF_TIME_TRACE) { - BpDataTime* bdt; + } else if (break_flags & (ERTS_BPF_TIME_TRACE | ERTS_BPF_MEM_TRACE)) { + BpDataCallTrace* bdt; Uint i; - ASSERT((bp->flags & ERTS_BPF_TIME_TRACE) == 0); - bdt = Alloc(sizeof(BpDataTime)); + ASSERT((break_flags & bp->flags & ERTS_BPF_TIME_TRACE) == 0); + ASSERT((break_flags & bp->flags & ERTS_BPF_MEM_TRACE) == 0); + bdt = Alloc(sizeof(BpDataCallTrace)); erts_refc_init(&bdt->refc, 1); bdt->n = erts_no_schedulers + 1; - bdt->hash = Alloc(sizeof(bp_time_hash_t)*(bdt->n)); + bdt->hash = Alloc(sizeof(bp_trace_hash_t)*(bdt->n)); for (i = 0; i < bdt->n; i++) { bp_hash_init(&(bdt->hash[i]), 32); } - bp->time = bdt; + if (break_flags & ERTS_BPF_TIME_TRACE) + bp->time = bdt; + else + bp->memory = bdt; } bp->flags |= break_flags; @@ -1423,7 +1741,7 @@ clear_break(BpFunctions* f, Uint break_flags) n = f->matched; for (i = 0; i < n; i++) { - clear_function_break(f->matching[i].ci, break_flags); + clear_function_break(f->matching[i].code_info, break_flags); } } @@ -1435,9 +1753,9 @@ clear_function_break(const ErtsCodeInfo *ci, Uint break_flags) Uint common; ErtsBpIndex ix = erts_staging_bp_ix(); - ERTS_LC_ASSERT(erts_has_code_write_permission()); + ERTS_LC_ASSERT(erts_has_code_mod_permission()); - if ((g = ci->u.gen_bp) == NULL) { + if ((g = ci->gen_bp) == NULL) { return 1; } @@ -1458,7 +1776,11 @@ clear_function_break(const ErtsCodeInfo *ci, Uint break_flags) } if (common & ERTS_BPF_TIME_TRACE) { ASSERT((bp->flags & ERTS_BPF_TIME_TRACE_ACTIVE) == 0); - bp_time_unref(bp->time); + bp_calltrace_unref(bp->time); + } + if (common & ERTS_BPF_MEM_TRACE) { + ASSERT((bp->flags & ERTS_BPF_MEM_TRACE_ACTIVE) == 0); + bp_calltrace_unref(bp->memory); } ASSERT((bp->flags & ~ERTS_BPF_ALL) == 0); @@ -1484,7 +1806,7 @@ bp_count_unref(BpCount* bcp) } static void -bp_time_unref(BpDataTime* bdt) +bp_calltrace_unref(BpDataCallTrace* bdt) { if (erts_refc_dectest(&bdt->refc, 0) <= 0) { Uint i = 0; @@ -1497,20 +1819,27 @@ bp_time_unref(BpDataTime* bdt) } } -static BpDataTime* +static BpDataCallTrace* get_time_break(const ErtsCodeInfo *ci) { GenericBpData* bp = check_break(ci, ERTS_BPF_TIME_TRACE); return bp ? bp->time : 0; } +static BpDataCallTrace* +get_memory_break(const ErtsCodeInfo *ci) +{ + GenericBpData* bp = check_break(ci, ERTS_BPF_MEM_TRACE); + return bp ? bp->memory : 0; +} + static GenericBpData* check_break(const ErtsCodeInfo *ci, Uint break_flags) { - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci->gen_bp; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif if (g) { diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h index 9941533e2d64..83eac585f4ae 100644 --- a/erts/emulator/beam/beam_bp.h +++ b/erts/emulator/beam/beam_bp.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2020. All Rights Reserved. + * Copyright Ericsson AB 2000-2023. 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. @@ -26,28 +26,36 @@ #include "erl_vm.h" #include "global.h" +/* Use the same signed long long for both call_time and call_memory. +* There is not much value in future-proofing until there is a need +* to support anything other than a simple 8-byte number. When such +* a use-case is identified, this type could be turned into a union. +*/ +typedef ErtsMonotonicTime BpDataAccumulator; + typedef struct { Eterm pid; Sint count; - ErtsMonotonicTime time; -} bp_data_time_item_t; + BpDataAccumulator accumulator; +} bp_data_trace_item_t; typedef struct { Uint n; Uint used; - bp_data_time_item_t *item; -} bp_time_hash_t; + bp_data_trace_item_t *item; +} bp_trace_hash_t; -typedef struct bp_data_time { /* Call time */ +typedef struct bp_data_time { /* Call time, Memory trace */ Uint n; - bp_time_hash_t *hash; + bp_trace_hash_t *hash; erts_refc_t refc; -} BpDataTime; +} BpDataCallTrace; typedef struct { const ErtsCodeInfo *ci; - ErtsMonotonicTime time; -} process_breakpoint_time_t; /* used within psd */ + BpDataAccumulator accumulator; + BpDataAccumulator allocated; /* adjustment for GC and messages on the heap */ +} process_breakpoint_trace_t; /* used within psd */ typedef struct { erts_atomic_t acount; @@ -65,7 +73,8 @@ typedef struct generic_bp_data { Binary* meta_ms; /* Match spec for meta trace */ BpMetaTracer* meta_tracer; /* Meta tracer */ BpCount* count; /* For call count */ - BpDataTime* time; /* For time trace */ + BpDataCallTrace* time; /* For time trace */ + BpDataCallTrace* memory; /* For memory trace */ } GenericBpData; #define ERTS_NUM_BP_IX 2 @@ -91,7 +100,7 @@ enum erts_break_op{ typedef Uint32 ErtsBpIndex; typedef struct { - ErtsCodeInfo *ci; + const ErtsCodeInfo *code_info; Module* mod; } BpFunction; @@ -118,7 +127,9 @@ void erts_bp_free_matched_functions(BpFunctions* f); void erts_install_breakpoints(BpFunctions* f); void erts_uninstall_breakpoints(BpFunctions* f); -void erts_consolidate_bp_data(BpFunctions* f, int local); + +void erts_consolidate_local_bp_data(BpFunctions* f); +void erts_consolidate_export_bp_data(BpFunctions* f); void erts_set_trace_break(BpFunctions *f, Binary *match_spec); void erts_clear_trace_break(BpFunctions *f); @@ -149,15 +160,16 @@ int erts_is_mtrace_break(const ErtsCodeInfo *ci, Binary **match_spec_ret, ErtsTracer *tracer_ret); int erts_is_count_break(const ErtsCodeInfo *ci, Uint *count_ret); -int erts_is_time_break(Process *p, const ErtsCodeInfo *ci, Eterm *call_time); +int erts_is_call_break(Process *p, int is_time, const ErtsCodeInfo *ci, Eterm *call_time); -const ErtsCodeInfo* erts_trace_time_call(Process* c_p, - const ErtsCodeInfo *ci, - BpDataTime* bdt); -void erts_trace_time_return(Process* c_p, const ErtsCodeInfo *ci); +void erts_call_trace_return(Process* c_p, const ErtsCodeInfo *ci, Eterm bp_flags_term); void erts_schedule_time_break(Process *p, Uint out); +ERTS_GLB_INLINE void erts_adjust_memory_break(Process *p, Sint adjustment); +ERTS_GLB_INLINE void erts_adjust_message_break(Process *p, Eterm message); void erts_set_time_break(BpFunctions *f, enum erts_break_op); +void erts_set_memory_break(BpFunctions *f, enum erts_break_op); void erts_clear_time_break(BpFunctions *f); +void erts_clear_memory_break(BpFunctions *f); const ErtsCodeInfo *erts_find_local_func(const ErtsCodeMFA *mfa); @@ -175,6 +187,23 @@ ERTS_GLB_INLINE ErtsBpIndex erts_staging_bp_ix(void) { return erts_atomic32_read_nob(&erts_staging_bp_index); } + +ERTS_GLB_INLINE +void erts_adjust_memory_break(Process *p, Sint adjustment) +{ + process_breakpoint_trace_t * pbt = ERTS_PROC_GET_CALL_MEMORY(p); + if (pbt) + pbt->allocated += adjustment; +} + +ERTS_GLB_INLINE +void erts_adjust_message_break(Process *p, Eterm message) +{ + process_breakpoint_trace_t * pbt = ERTS_PROC_GET_CALL_MEMORY(p); + if (pbt) + pbt->allocated += size_object(message); +} + #endif #endif /* _BEAM_BP_H */ diff --git a/erts/emulator/beam/beam_code.h b/erts/emulator/beam/beam_code.h index 07344628f0cf..7e8d2c744bba 100644 --- a/erts/emulator/beam/beam_code.h +++ b/erts/emulator/beam/beam_code.h @@ -92,6 +92,13 @@ typedef struct beam_code_header { */ const byte *md5_ptr; + /* + * Boolean array with functions declared as -nifs(). + * Indexed same as functions[]. + * NULL if no -nifs(). + */ + byte* are_nifs; + /* * Start of function pointer table. This table contains pointers to * all functions in the module plus an additional pointer just beyond diff --git a/erts/emulator/beam/beam_common.c b/erts/emulator/beam/beam_common.c index 36f9d496292d..6eb97fc8649b 100644 --- a/erts/emulator/beam/beam_common.c +++ b/erts/emulator/beam/beam_common.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -34,6 +34,7 @@ #include "dist.h" #include "beam_catches.h" #include "beam_common.h" +#include "erl_global_literals.h" #ifdef USE_VM_PROBES #include "dtrace-wrapper.h" @@ -233,7 +234,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp) if (ERTS_PROC_IS_EXITING(c_p)) { sys_strcpy(fun_buf, ""); } else { - ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i); + const ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i); if (cmfa) { dtrace_fun_decode(c_p, cmfa, NULL, fun_buf); } else { @@ -394,6 +395,7 @@ Eterm error_atom[NUMBER_EXIT_CODES] = { am_notsup, /* 17 */ am_badmap, /* 18 */ am_badkey, /* 19 */ + am_badrecord, /* 20 */ }; /* Returns the return address at E[0] in printable form, skipping tracing in @@ -402,21 +404,24 @@ Eterm error_atom[NUMBER_EXIT_CODES] = { * This is needed to generate correct stacktraces when throwing errors from * instructions that return like an ordinary function, such as call_nif. */ ErtsCodePtr erts_printable_return_address(Process* p, Eterm *E) { - Eterm *ptr = E; + Eterm *stack_bottom = STACK_START(p); + Eterm *scanner = E; - ASSERT(is_CP(*ptr)); + ASSERT(is_CP(scanner[0])); - while (ptr < STACK_START(p)) { - ErtsCodePtr cp = cp_val(*ptr); + while (scanner < stack_bottom) { + ErtsCodePtr return_address; - if (BeamIsReturnTrace(cp)) { - ptr += 3; - } else if (BeamIsReturnTimeTrace(cp)) { - ptr += 2; - } else if (BeamIsReturnToTrace(cp)) { - ptr += 1; + erts_inspect_frame(scanner, &return_address); + + if (BeamIsReturnTrace(return_address)) { + scanner += CP_SIZE + BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(return_address)) { + scanner += CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } else if (BeamIsReturnToTrace(return_address)) { + scanner += CP_SIZE + BEAM_RETURN_TO_TRACE_FRAME_SZ; } else { - return cp; + return return_address; } } @@ -519,18 +524,20 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg, && !(c_p->freason & EXF_PANIC)) { ErtsCodePtr new_pc; /* The Beam handler code (catch_end or try_end) checks reg[0] - for THE_NON_VALUE to see if the previous code finished - abnormally. If so, reg[1], reg[2] and reg[3] should hold the - exception class, term and trace, respectively. (If the - handler is just a trap to native code, these registers will - be ignored.) */ + * for THE_NON_VALUE to see if the previous code finished + * abnormally. If so, reg[1], reg[2] and reg[3] should hold + * the term, trace, and exception class, respectively. Note + * that the handler code will only need to move the class + * to reg[0] to have all registers correctly set up for the + * code that follows. + */ reg[0] = THE_NON_VALUE; - reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)]; - reg[2] = Value; - reg[3] = c_p->ftrace; + reg[1] = Value; + reg[2] = c_p->ftrace; + reg[3] = exception_tag[GET_EXC_CLASS(c_p->freason)]; if ((new_pc = next_catch(c_p, reg))) { -#if defined(BEAMASM) && defined(NATIVE_ERLANG_STACK) +#if defined(BEAMASM) && (defined(NATIVE_ERLANG_STACK) || defined(__aarch64__)) /* In order to make use of native call and return * instructions, when beamasm uses the native stack it * doesn't include the CP in the current stack frame, @@ -539,7 +546,11 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg, * * Therefore, we need to bump the stack pointer as if this were an * ordinary return. */ - ASSERT(is_CP(c_p->stop[0])); + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + FRAME_POINTER(c_p) = (Eterm*)cp_val(c_p->stop[0]); + } + c_p->stop += CP_SIZE; #else /* To avoid keeping stale references. */ @@ -566,8 +577,10 @@ handle_error(Process* c_p, ErtsCodePtr pc, Eterm* reg, static ErtsCodePtr next_catch(Process* c_p, Eterm *reg) { int active_catches = c_p->catches > 0; + ErtsCodePtr return_to_trace_address = NULL; int have_return_to_trace = 0; - Eterm *ptr, *prev, *return_to_trace_ptr = NULL; + Eterm *ptr, *prev; + ErtsCodePtr handler; ptr = prev = c_p->stop; ASSERT(ptr <= STACK_START(c_p)); @@ -583,53 +596,81 @@ next_catch(Process* c_p, Eterm *reg) { } while (ptr < STACK_START(c_p)) { - if (is_catch(*ptr)) { - if (active_catches) goto found_catch; - ptr++; - } - else if (is_CP(*ptr)) { - prev = ptr; - if (BeamIsReturnTrace(cp_val(*prev))) { - if (cp_val(*prev) == beam_exception_trace) { - ErtsCodeMFA *mfa = (ErtsCodeMFA*)cp_val(ptr[1]); - erts_trace_exception(c_p, mfa, - reg[1], reg[2], - ERTS_TRACER_FROM_ETERM(ptr+2)); - } - /* Skip MFA, tracer, and CP. */ - ptr += 3; - } else if (BeamIsReturnToTrace(cp_val(*prev))) { - have_return_to_trace = !0; /* Record next cp */ - return_to_trace_ptr = NULL; - /* Skip CP. */ - ptr += 1; - } else if (BeamIsReturnTimeTrace(cp_val(*prev))) { - /* Skip prev_info and CP. */ - ptr += 2; - } else { - if (have_return_to_trace) { - /* Record this cp as possible return_to trace cp */ - have_return_to_trace = 0; - return_to_trace_ptr = ptr; - } else return_to_trace_ptr = NULL; - ptr++; - } - } else ptr++; + Eterm val = ptr[0]; + + if (is_catch(val)) { + if (active_catches) { + goto found_catch; + } + + ptr++; + } else if (is_CP(val)) { + ErtsCodePtr return_address; + const Eterm *frame; + + prev = ptr; + frame = erts_inspect_frame(ptr, &return_address); + + if (BeamIsReturnTrace(return_address)) { + if (return_address == beam_exception_trace) { + ErtsTracer *tracer; + ErtsCodeMFA *mfa; + + mfa = (ErtsCodeMFA*)cp_val(frame[0]); + tracer = ERTS_TRACER_FROM_ETERM(&frame[1]); + + ASSERT_MFA(mfa); + erts_trace_exception(c_p, mfa, reg[3], reg[1], tracer); + } + ptr += CP_SIZE + BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(return_address)) { + ptr += CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } else if (BeamIsReturnToTrace(return_address)) { + have_return_to_trace = 1; /* Record next cp */ + return_to_trace_address = NULL; + + ptr += CP_SIZE + BEAM_RETURN_TO_TRACE_FRAME_SZ; + } else { + /* This is an ordinary call frame: if the previous frame was a + * return_to trace we should record this CP as a return_to + * candidate. */ + if (have_return_to_trace) { + return_to_trace_address = return_address; + have_return_to_trace = 0; + } else { + return_to_trace_address = NULL; + } + + ptr += CP_SIZE; + } + } else { + ptr++; + } } + return NULL; found_catch: ASSERT(ptr < STACK_START(c_p)); c_p->stop = prev; - if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_ptr) { - /* The stackframe closest to the catch contained an - * return_to_trace entry, so since the execution now - * continues after the catch, a return_to trace message - * would be appropriate. - */ - erts_trace_return_to(c_p, cp_val(*return_to_trace_ptr)); + + if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_address) { + /* The stackframe closest to the catch contained an + * return_to_trace entry, so since the execution now + * continues after the catch, a return_to trace message + * would be appropriate. + */ + erts_trace_return_to(c_p, return_to_trace_address); } - return catch_pc(*ptr); + + /* Clear the try_tag or catch_tag in the stack frame so that we + * don't have to do it in the JITted code for the try_case + * instruction. (Unfortunately, a catch_end will still need to + * clear the catch_tag because it is executed even when no + * exception has occurred.) */ + handler = catch_pc(*ptr); + *ptr = NIL; + return handler; } /* @@ -712,6 +753,7 @@ expand_error_value(Process* c_p, Uint freason, Eterm Value) { case (GET_EXC_INDEX(EXC_BADARITY)): case (GET_EXC_INDEX(EXC_BADMAP)): case (GET_EXC_INDEX(EXC_BADKEY)): + case (GET_EXC_INDEX(EXC_BADRECORD)): /* Some common exceptions: value -> {atom, value} */ ASSERT(is_value(Value)); hp = HAlloc(c_p, 3); @@ -753,35 +795,39 @@ gather_stacktrace(Process* p, struct StackTrace* s, int depth) while (ptr < STACK_START(p) && depth > 0) { if (is_CP(*ptr)) { - ErtsCodePtr cp = cp_val(*ptr); - - if (BeamIsReturnTrace(cp)) { - ptr += 3; - } else if (BeamIsReturnTimeTrace(cp)) { - ptr += 2; - } else if (BeamIsReturnToTrace(cp)) { - ptr += 1; + ErtsCodePtr return_address; + + erts_inspect_frame(ptr, &return_address); + + if (BeamIsReturnTrace(return_address)) { + ptr += CP_SIZE + BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(return_address)) { + ptr += CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } else if (BeamIsReturnToTrace(return_address)) { + ptr += CP_SIZE + BEAM_RETURN_TO_TRACE_FRAME_SZ; } else { - if (cp != prev) { - void *adjusted_cp; + if (return_address != prev) { + ErtsCodePtr adjusted_address; /* Record non-duplicates only */ - prev = cp; + prev = return_address; + #ifdef BEAMASM - /* - * Some instructions (e.g. call) are shorter than one word, - * so we will need to subtract one byte from the pointer - * to avoid ending up before the start of the instruction. - */ - adjusted_cp = ((char *) cp) - 1; + /* Some instructions (e.g. call) are shorter than one word, + * so we will need to subtract one byte from the pointer + * to avoid ending up before the start of the + * instruction. */ + adjusted_address = ((char*)return_address) - 1; #else - /* Subtract one word from the pointer. */ - adjusted_cp = ((char *) cp) - sizeof(UWord); + /* Subtract one word from the pointer. */ + adjusted_address = ((char*)return_address) - sizeof(UWord); #endif - s->trace[s->depth++] = adjusted_cp; + + s->trace[s->depth++] = adjusted_address; depth--; } - ptr++; + + ptr += CP_SIZE; } } else { ptr++; @@ -796,7 +842,7 @@ gather_stacktrace(Process* p, struct StackTrace* s, int depth) * * There is an issue with line number information. Line number * information is associated with the address *before* an operation - * that may fail or be stored stored on the stack. But continuation + * that may fail or be stored on the stack. But continuation * pointers point after its call instruction, not before. To avoid * finding the wrong line number, we'll need to adjust them so that * they point at the beginning of the call instruction or inside the @@ -952,10 +998,13 @@ save_stacktrace(Process* c_p, ErtsCodePtr pc, Eterm* reg, args = make_arglist(c_p, reg, bif_mfa->arity); } else { + if (c_p->freason & EXF_HAS_EXT_INFO && is_map(c_p->fvalue)) { + error_info = c_p->fvalue; + } non_bif_stacktrace: - s->current = c_p->current; + /* * For a function_clause error, the arguments are in the beam * registers and c_p->current is set. @@ -1065,7 +1114,7 @@ static Eterm *get_freason_ptr_from_exc(Eterm exc) { if (exc == NIL) { /* - * Is is not exactly clear when exc can be NIL. Probably only + * It is not exactly clear when exc can be NIL. Probably only * when the exception has been generated from native code. * Return a pointer to an Eterm that can be safely written and * ignored. @@ -1351,7 +1400,7 @@ apply_bif_error_adjustment(Process *p, Export *ep, * error handling code. */ if (need == 0) { - need = 1; /* i_apply_only */ + need = CP_SIZE; /* i_apply_only */ } if (HeapWordsLeft(p) < need) { @@ -1365,7 +1414,17 @@ apply_bif_error_adjustment(Process *p, Export *ep, * Push the continuation pointer for the current function to the stack. */ p->stop -= need; - p->stop[0] = make_cp(I); + + switch (erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + p->stop[0] = make_cp(I); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + p->stop[0] = make_cp(FRAME_POINTER(p)); + p->stop[1] = make_cp(I); + FRAME_POINTER(p) = &p->stop[0]; + break; + } } else { /* * Called from an i_apply_last_* instruction. @@ -1377,7 +1436,17 @@ apply_bif_error_adjustment(Process *p, Export *ep, * and then add a dummy stackframe for the i_apply_last* instruction * to discard. */ - p->stop[0] = make_cp(I); + switch (erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + p->stop[0] = make_cp(I); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + p->stop[0] = make_cp(FRAME_POINTER(p)); + p->stop[1] = make_cp(I); + FRAME_POINTER(p) = &p->stop[0]; + break; + } + p->stop -= need; } } @@ -1596,10 +1665,21 @@ erts_hibernate(Process* c_p, Eterm* reg) c_p->arg_reg[0] = module; c_p->arg_reg[1] = function; c_p->arg_reg[2] = args; - c_p->stop = c_p->hend - CP_SIZE; /* Keep first continuation pointer */ - ASSERT(c_p->stop[0] == make_cp(beam_normal_exit)); + c_p->stop = c_p->hend - CP_SIZE; /* Keep first continuation pointer */ + + switch(erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + ASSERT(c_p->stop[0] == make_cp(beam_normal_exit)); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + FRAME_POINTER(c_p) = &c_p->stop[0]; + ASSERT(c_p->stop[0] == make_cp(NULL)); + ASSERT(c_p->stop[1] == make_cp(beam_normal_exit)); + break; + } + c_p->catches = 0; - c_p->i = beam_apply; + c_p->i = beam_run_process; /* * If there are no waiting messages, garbage collect and @@ -1628,171 +1708,133 @@ ErtsCodePtr call_fun(Process* p, /* Current process. */ int arity, /* Number of arguments for Fun. */ Eterm* reg, /* Contents of registers. */ - Eterm args, /* THE_NON_VALUE or pre-built list of arguments. */ - Export **epp) /* Export entry, if any. */ + Eterm args) /* THE_NON_VALUE or pre-built list of arguments. */ { - Eterm fun = reg[arity]; - Eterm hdr; - int i; - Eterm* hp; + ErtsCodeIndex code_ix; + ErtsCodePtr code_ptr; + ErlFunThing *funp; + Eterm fun; - if (!is_boxed(fun)) { - goto badfun; + fun = reg[arity]; + + if (is_not_any_fun(fun)) { + p->current = NULL; + p->freason = EXC_BADFUN; + p->fvalue = fun; + return NULL; } - hdr = *boxed_val(fun); - if (is_fun_header(hdr)) { - ErlFunThing* funp = (ErlFunThing *) fun_val(fun); - ErlFunEntry* fe = funp->fe; - ErtsCodePtr code_ptr = fe->address; - Eterm* var_ptr; - unsigned num_free = funp->num_free; - const ErtsCodeMFA *mfa = erts_code_to_codemfa(code_ptr); - int actual_arity = mfa->arity; + funp = (ErlFunThing*)fun_val(fun); - if (actual_arity == arity+num_free) { - DTRACE_LOCAL_CALL(p, mfa); - if (num_free == 0) { - return code_ptr; - } else { - var_ptr = funp->env; - reg += arity; - i = 0; - do { - reg[i] = var_ptr[i]; - i++; - } while (i < num_free); - reg[i] = fun; - return code_ptr; - } - return code_ptr; - } else { - /* - * Something wrong here. First build a list of the arguments. - */ + code_ix = erts_active_code_ix(); + code_ptr = (funp->entry.disp)->addresses[code_ix]; - if (is_non_value(args)) { - Uint sz = 2 * arity; - args = NIL; - if (HeapWordsLeft(p) < sz) { - erts_garbage_collect(p, sz, reg, arity+1); - fun = reg[arity]; - } - hp = HEAP_TOP(p); - HEAP_TOP(p) += sz; - for (i = arity-1; i >= 0; i--) { - args = CONS(hp, reg[i], args); - hp += 2; - } - } + if (ERTS_LIKELY(code_ptr != beam_unloaded_fun && funp->arity == arity)) { + for (int i = 0, num_free = funp->num_free; i < num_free; i++) { + reg[i + arity] = funp->env[i]; + } - if (actual_arity >= 0) { - /* - * There is a fun defined, but the call has the wrong arity. - */ - hp = HAlloc(p, 3); - p->freason = EXC_BADARITY; - p->fvalue = TUPLE2(hp, fun, args); - return NULL; - } else { - Export* ep; - Module* modp; - Eterm module; - ErtsCodeIndex code_ix = erts_active_code_ix(); - - /* - * No arity. There is no module loaded that defines the fun, - * either because the fun is newly created from the external - * representation (the module has never been loaded), - * or the module defining the fun has been unloaded. - */ - - module = fe->module; - - ERTS_THR_READ_MEMORY_BARRIER; - if (fe->pend_purge_address) { - /* - * The system is currently trying to purge the - * module containing this fun. Suspend the process - * and let it try again when the purge operation is - * done (may succeed or not). - */ - ep = erts_suspend_process_on_pending_purge_lambda(p, fe); - ASSERT(ep); - } - else { - if ((modp = erts_get_module(module, code_ix)) != NULL - && modp->curr.code_hdr != NULL) { - /* - * There is a module loaded, but obviously the fun is not - * defined in it. We must not call the error_handler - * (or we will get into an infinite loop). - */ - goto badfun; - } +#ifdef USE_VM_CALL_PROBES + if (is_local_fun(funp)) { + DTRACE_LOCAL_CALL(p, erts_code_to_codemfa(code_ptr)); + } else { + Export *ep = funp->entry.exp; + ASSERT(is_external_fun(funp) && funp->next == NULL); + DTRACE_GLOBAL_CALL(p, &ep->info.mfa); + } +#endif - /* - * No current code for this module. Call the error_handler module - * to attempt loading the module. - */ - - ep = erts_find_function(erts_proc_get_error_handler(p), - am_undefined_lambda, 3, code_ix); - if (ep == NULL) { /* No error handler */ - p->current = NULL; - p->freason = EXC_UNDEF; - return NULL; - } - } - reg[0] = module; - reg[1] = fun; - reg[2] = args; - reg[3] = NIL; - *epp = ep; - return ep->addresses[code_ix]; - } - } - } else if (is_export_header(hdr)) { - Export *ep; - int actual_arity; + return code_ptr; + } else { + /* Something wrong here. First build a list of the arguments. */ + if (is_non_value(args)) { + Uint sz = 2 * arity; + Eterm *hp; - ep = *((Export **) (export_val(fun) + 1)); - actual_arity = ep->info.mfa.arity; + args = NIL; - if (arity == actual_arity) { - DTRACE_GLOBAL_CALL(p, &ep->info.mfa); - *epp = ep; - return ep->addresses[erts_active_code_ix()]; - } else { - /* - * Wrong arity. First build a list of the arguments. - */ + if (HeapWordsLeft(p) < sz) { + erts_garbage_collect(p, sz, reg, arity+1); - if (is_non_value(args)) { - args = NIL; - hp = HAlloc(p, arity*2); - for (i = arity-1; i >= 0; i--) { - args = CONS(hp, reg[i], args); - hp += 2; - } - } + fun = reg[arity]; + funp = (ErlFunThing*)fun_val(fun); + } - hp = HAlloc(p, 3); - p->freason = EXC_BADARITY; - p->fvalue = TUPLE2(hp, fun, args); - return NULL; - } - } else { - badfun: - p->current = NULL; - p->freason = EXC_BADFUN; - p->fvalue = fun; - return NULL; + hp = HEAP_TOP(p); + HEAP_TOP(p) += sz; + + for (int i = arity - 1; i >= 0; i--) { + args = CONS(hp, reg[i], args); + hp += 2; + } + } + + if (funp->arity != arity) { + /* There is a fun defined, but the call has the wrong arity. */ + Eterm *hp = HAlloc(p, 3); + p->freason = EXC_BADARITY; + p->fvalue = TUPLE2(hp, fun, args); + return NULL; + } else { + ErlFunEntry *fe; + Eterm module; + Module *modp; + Export *ep; + + /* There is no module loaded that defines the fun, either because + * the fun is newly created from the external representation (the + * module has never been loaded), or the module defining the fun + * has been unloaded. */ + ASSERT(is_local_fun(funp) && code_ptr == beam_unloaded_fun); + fe = funp->entry.fun; + module = fe->module; + + ERTS_THR_READ_MEMORY_BARRIER; + if (fe->pend_purge_address) { + /* The system is currently trying to purge the + * module containing this fun. Suspend the process + * and let it try again when the purge operation is + * done (may succeed or not). */ + ep = erts_suspend_process_on_pending_purge_lambda(p, fe); + } else { + if ((modp = erts_get_module(module, code_ix)) != NULL + && modp->curr.code_hdr != NULL) { + /* There is a module loaded, but obviously the fun is + * not defined in it. We must not call the error_handler + * (or we will get into an infinite loop). */ + p->current = NULL; + p->freason = EXC_BADFUN; + p->fvalue = fun; + return NULL; + } + + /* No current code for this module. Call the error_handler + * module to attempt loading the module. */ + + ep = erts_find_function(erts_proc_get_error_handler(p), + am_undefined_lambda, 3, code_ix); + if (ep == NULL) { + /* No error handler */ + p->current = NULL; + p->freason = EXC_UNDEF; + return NULL; + } + } + + ASSERT(ep); + + reg[0] = module; + reg[1] = fun; + reg[2] = args; + reg[3] = NIL; + + return ep->dispatch.addresses[code_ix]; + } } } ErtsCodePtr -apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg, Export **epp) +apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg) { int arity; Eterm tmp; @@ -1819,41 +1861,17 @@ apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg, Export **epp) return NULL; } reg[arity] = fun; - return call_fun(p, arity, reg, args, epp); -} - -ErlFunThing* -new_fun_thing(Process* p, ErlFunEntry* fe, int num_free) -{ - const ErtsCodeMFA *mfa; - ErlFunThing* funp; - - mfa = erts_code_to_codemfa(fe->address); - funp = (ErlFunThing*) p->htop; - p->htop += ERL_FUN_SIZE + num_free; - erts_refc_inc(&fe->refc, 2); - - funp->thing_word = HEADER_FUN; - funp->next = MSO(p).first; - MSO(p).first = (struct erl_off_heap_header*) funp; - funp->fe = fe; - funp->num_free = num_free; - funp->creator = p->common.id; - funp->arity = mfa->arity - num_free; - - return funp; + return call_fun(p, arity, reg, args); } int is_function2(Eterm Term, Uint arity) { - if (is_fun(Term)) { - ErlFunThing* funp = (ErlFunThing *) fun_val(Term); - return funp->arity == arity; - } else if (is_export(Term)) { - Export* exp = (Export *) (export_val(Term)[1]); - return exp->info.mfa.arity == arity; + if (is_any_fun(Term)) { + ErlFunThing *funp = (ErlFunThing*)fun_val(Term); + return funp->arity == arity; } + return 0; } @@ -1985,11 +2003,14 @@ erts_gc_new_map(Process* p, Eterm* reg, Uint live, } thp = p->htop; - mhp = thp + 1 + n/2; + mhp = thp + (n == 0 ? 0 : 1) + n/2; E = p->stop; - keys = make_tuple(thp); - *thp++ = make_arityval(n/2); - + if (n == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + keys = make_tuple(thp); + *thp++ = make_arityval(n/2); + } mp = (flatmap_t *)mhp; mhp += MAP_HEADER_FLATMAP_SZ; mp->thing_word = MAP_HEADER_FLATMAP; mp->size = n/2; @@ -2054,6 +2075,8 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, Eterm new_key; Eterm* kp; Eterm map; + int changed_values = 0; + int changed_keys = 0; num_updates = n / 2; map = reg[live]; @@ -2105,35 +2128,46 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, * Build the skeleton for the map, ready to be filled in. * * +-----------------------------------+ - * | (Space for aritvyal for keys) | <-----------+ - * +-----------------------------------+ | - * | (Space for key 1) | | <-- kp - * +-----------------------------------+ | - * . | - * . | - * . | - * +-----------------------------------+ | - * | (Space for last key) | | - * +-----------------------------------+ | - * | MAP_HEADER | | - * +-----------------------------------+ | - * | (Space for number of keys/values) | | - * +-----------------------------------+ | + * | MAP_HEADER_FLATMAP | + * +-----------------------------------+ + * | (Space for number of keys/values) | + * +-----------------------------------+ * | Boxed tuple pointer >----------------+ + * +-----------------------------------+ | + * | (Space for value 1) | | <-- hp + * +-----------------------------------+ | + * . | + * . | + * . | + * +-----------------------------------+ | + * | (Space for last value) | | + * +-----------------------------------+ | + * +-----------------------------------+ | + * | (Space for aritvyal for keys) | <-----------+ * +-----------------------------------+ - * | (Space for value 1) | <-- hp + * | (Space for key 1) | <-- kp + * +-----------------------------------+ + * . + * . + * . + * +-----------------------------------+ + * | (Space for last key) | * +-----------------------------------+ */ + hp = p->htop; E = p->stop; - kp = p->htop + 1; /* Point to first key */ - hp = kp + num_old + num_updates; res = make_flatmap(hp); mp = (flatmap_t *)hp; hp += MAP_HEADER_FLATMAP_SZ; mp->thing_word = MAP_HEADER_FLATMAP; - mp->keys = make_tuple(kp-1); + + kp = hp + num_old + num_updates; /* Point to key tuple. */ + + mp->keys = make_tuple(kp); + + kp = kp + 1; /* Point to first key. */ old_vals = flatmap_get_values(old_mp); old_keys = flatmap_get_keys(old_mp); @@ -2150,21 +2184,25 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, Eterm key; Sint c; - ASSERT(kp < (Eterm *)mp); key = *old_keys; - if ((c = CMP_TERM(key, new_key)) < 0) { + if ((c = (key == new_key) ? 0 : erts_cmp_flatmap_keys(key, new_key)) < 0) { /* Copy old key and value */ *kp++ = key; *hp++ = *old_vals; old_keys++, old_vals++, num_old--; } else { /* Replace or insert new */ - GET_TERM(new_p[1], *hp++); - if (c > 0) { /* If new new key */ + GET_TERM(new_p[1], *hp); + if (c > 0) { /* If new key */ *kp++ = new_key; + changed_keys = 1; } else { /* If replacement */ + if (*old_vals != *hp) { + changed_values = 1; + } *kp++ = key; old_keys++, old_vals++, num_old--; } + hp++; n--; if (n == 0) { break; @@ -2196,6 +2234,28 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, GET_TERM(new_p[1], *hp++); new_p += 2; } + } else if (!changed_keys && !changed_values) { + /* + * All updates are now done, no new keys were introduced, and + * all new values were the same as old ones. We can just + * return the old map and skip committing the new allocation, + * effectively releasing it. + */ + ASSERT(n == 0); + return map; + } else if (!changed_keys) { + /* + * All updates are now done, no new keys were introduced, but + * some values were changed. We can retain the old key tuple. + */ + ASSERT(n == 0); + mp->size = old_mp->size; + mp->keys = old_mp->keys; + while (num_old-- > 0) { + *hp++ = *old_vals++; + } + p->htop = hp; + return res; } else { /* * All updates are now done. We may still have old @@ -2203,7 +2263,6 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, */ ASSERT(n == 0); while (num_old-- > 0) { - ASSERT(kp < (Eterm *)mp); *kp++ = *old_keys++; *hp++ = *old_vals++; } @@ -2211,20 +2270,22 @@ erts_gc_update_map_assoc(Process* p, Eterm* reg, Uint live, /* * Calculate how many values that are unused at the end of the - * key tuple and fill it out with a bignum header. + * value array and fill it out with a bignum header. */ - if ((n = (Eterm *)mp - kp) > 0) { - *kp = make_pos_bignum_header(n-1); + if ((n = boxed_val(mp->keys) - hp) > 0) { + ASSERT(n <= num_updates); + *hp = make_pos_bignum_header(n-1); } /* * Fill in the size of the map in both the key tuple and in the map. */ - n = kp - p->htop - 1; /* Actual number of keys/values */ - *p->htop = make_arityval(n); - p->htop = hp; + n = hp - (Eterm *)mp - MAP_HEADER_FLATMAP_SZ; /* Actual number of keys/values */ + ASSERT(n <= old_mp->size + num_updates); mp->size = n; + *(boxed_val(mp->keys)) = make_arityval(n); + p->htop = kp; /* The expensive case, need to build a hashmap */ if (n > MAP_SMALL_MAP_LIMIT) { diff --git a/erts/emulator/beam/beam_common.h b/erts/emulator/beam/beam_common.h index 52140c8a3eb6..0349d488ac44 100644 --- a/erts/emulator/beam/beam_common.h +++ b/erts/emulator/beam/beam_common.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -153,80 +153,81 @@ do { \ #ifdef USE_VM_CALL_PROBES -#define DTRACE_LOCAL_CALL(p, mfa) \ - if (DTRACE_ENABLED(local_function_entry)) { \ - DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ - DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - int depth = STACK_START(p) - STACK_TOP(p); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ - DTRACE3(local_function_entry, process_name, mfa_buf, depth); \ +#define DTRACE_LOCAL_CALL(p, cmfa) \ + if (DTRACE_ENABLED(local_function_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ + int depth = STACK_START(p) - STACK_TOP(p); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ + DTRACE3(local_function_entry, process_name, mfa_buf, depth); \ } -#define DTRACE_GLOBAL_CALL(p, mfa) \ - if (DTRACE_ENABLED(global_function_entry)) { \ - DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ - DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - int depth = STACK_START(p) - STACK_TOP(p); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ +#define DTRACE_GLOBAL_CALL(p, cmfa) \ + if (DTRACE_ENABLED(global_function_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ + int depth = STACK_START(p) - STACK_TOP(p); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE3(global_function_entry, process_name, mfa_buf, depth); \ } -#define DTRACE_RETURN(p, mfa) \ +#define DTRACE_RETURN(p, cmfa) \ if (DTRACE_ENABLED(function_return)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ int depth = STACK_START(p) - STACK_TOP(p); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE3(function_return, process_name, mfa_buf, depth); \ } -#define DTRACE_BIF_ENTRY(p, mfa) \ +#define DTRACE_BIF_ENTRY(p, cmfa) \ if (DTRACE_ENABLED(bif_entry)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE2(bif_entry, process_name, mfa_buf); \ } -#define DTRACE_BIF_RETURN(p, mfa) \ +#define DTRACE_BIF_RETURN(p, cmfa) \ if (DTRACE_ENABLED(bif_return)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE2(bif_return, process_name, mfa_buf); \ } -#define DTRACE_NIF_ENTRY(p, mfa) \ +#define DTRACE_NIF_ENTRY(p, cmfa) \ if (DTRACE_ENABLED(nif_entry)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE2(nif_entry, process_name, mfa_buf); \ } -#define DTRACE_NIF_RETURN(p, mfa) \ +#define DTRACE_NIF_RETURN(p, cmfa) \ if (DTRACE_ENABLED(nif_return)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa_buf, DTRACE_TERM_BUF_SIZE); \ - dtrace_fun_decode(p, mfa, process_name, mfa_buf); \ + dtrace_fun_decode(p, cmfa, process_name, mfa_buf); \ DTRACE2(nif_return, process_name, mfa_buf); \ } -#define DTRACE_GLOBAL_CALL_FROM_EXPORT(p,e) \ - do { \ - if (DTRACE_ENABLED(global_function_entry)) { \ - ErtsCodePtr fp__ = (((Export *) (e))->addresses[erts_active_code_ix()]); \ - DTRACE_GLOBAL_CALL((p), erts_code_to_codemfa(fp__)); \ - } \ +#define DTRACE_GLOBAL_CALL_FROM_EXPORT(p,e) \ + do { \ + if (DTRACE_ENABLED(global_function_entry)) { \ + ErtsDispatchable *disp__ = &(e)->dispatch; \ + ErtsCodePtr fp__ = disp__->addresses[erts_active_code_ix()]; \ + DTRACE_GLOBAL_CALL((p), erts_code_to_codemfa(fp__)); \ + } \ } while(0) -#define DTRACE_RETURN_FROM_PC(p, i) \ - do { \ - const ErtsCodeMFA* cmfa; \ - if (DTRACE_ENABLED(function_return) && (cmfa = erts_find_function_from_pc(i))) { \ - DTRACE_RETURN((p), cmfa); \ - } \ - } while(0) +#define DTRACE_RETURN_FROM_PC(p, i) \ + if (DTRACE_ENABLED(function_return)) { \ + const ErtsCodeMFA* cmfa = erts_find_function_from_pc(i); \ + if (cmfa) { \ + DTRACE_RETURN((p), cmfa); \ + } \ + } #else /* USE_VM_PROBES */ #define DTRACE_LOCAL_CALL(p, mfa) do {} while (0) @@ -255,13 +256,8 @@ Export* call_error_handler(Process* p, const ErtsCodeMFA* mfa, Export* fixed_apply(Process* p, Eterm* reg, Uint arity, ErtsCodePtr I, Uint offs); Export* apply(Process* p, Eterm* reg, ErtsCodePtr I, Uint offs); -ErtsCodePtr call_fun(Process* p, int arity, Eterm* reg, - Eterm args, Export **epp); -ErtsCodePtr apply_fun(Process* p, Eterm fun, Eterm args, - Eterm* reg, Export **epp); -Eterm new_fun(Process* p, Eterm* reg, - ErlFunEntry* fe, int num_free); -ErlFunThing* new_fun_thing(Process* p, ErlFunEntry* fe, int num_free); +ErtsCodePtr call_fun(Process* p, int arity, Eterm* reg, Eterm args); +ErtsCodePtr apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg); int is_function2(Eterm Term, Uint arity); Eterm erts_gc_new_map(Process* p, Eterm* reg, Uint live, Uint n, const Eterm* data); @@ -281,17 +277,42 @@ void copy_in_registers(Process *c_p, Eterm *reg); void check_monitor_long_schedule(Process *c_p, Uint64 start_time, ErtsCodePtr start_time_i); - -extern ErtsCodePtr beam_apply; +extern ErtsCodePtr beam_run_process; extern ErtsCodePtr beam_normal_exit; extern ErtsCodePtr beam_exit; -extern ErtsCodePtr beam_save_calls; +extern ErtsCodePtr beam_save_calls_export; +extern ErtsCodePtr beam_save_calls_fun; extern ErtsCodePtr beam_bif_export_trap; extern ErtsCodePtr beam_export_trampoline; extern ErtsCodePtr beam_continue_exit; +extern ErtsCodePtr beam_unloaded_fun; + extern ErtsCodePtr beam_return_to_trace; /* OpCode(i_return_to_trace) */ extern ErtsCodePtr beam_return_trace; /* OpCode(i_return_trace) */ extern ErtsCodePtr beam_exception_trace; /* OpCode(i_exception_trace) */ -extern ErtsCodePtr beam_return_time_trace; /* OpCode(i_return_time_trace) */ +extern ErtsCodePtr beam_call_trace_return; /* OpCode(i_call_trace_return) */ + +/** @brief Inspects an Erlang stack frame, returning the base of the data + * (first Y register). + * @param[in] frame The frame to inspect. Must point at a CP. + * @param[out] return_address The return address of \p frame */ +ERTS_GLB_INLINE +const Eterm *erts_inspect_frame(Eterm *frame, ErtsCodePtr *return_address); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE +const Eterm *erts_inspect_frame(Eterm *frame, ErtsCodePtr *return_address) { + ASSERT(is_CP(frame[0])); + + if (ERTS_LIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_RA)) { + *return_address = (ErtsCodePtr)cp_val(frame[0]); + return &frame[1]; + } + + ASSERT(cp_val(frame[0]) == NULL || frame < (Eterm*)cp_val(frame[0])); + *return_address = (ErtsCodePtr)cp_val(frame[1]); + return &frame[2]; +} +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ #endif /* _BEAM_COMMON_H_ */ diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index abf00ecaf831..3819de701fca 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2021. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -165,10 +165,11 @@ erts_debug_breakpoint_2(BIF_ALIST_2) mfa.arity = signed_val(tp[3]); } - if (!erts_try_seize_code_write_permission(BIF_P)) { + if (!erts_try_seize_code_mod_permission(BIF_P)) { ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_erts_debug_breakpoint_2), BIF_P, BIF_ARG_1, BIF_ARG_2); } + erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_thr_progress_block(); @@ -182,13 +183,17 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_commit_staged_bp(); erts_uninstall_breakpoints(&f); } - erts_consolidate_bp_data(&f, 1); + erts_consolidate_local_bp_data(&f); res = make_small(f.matched); erts_bp_free_matched_functions(&f); + erts_blocking_code_barrier(); + erts_thr_progress_unblock(); erts_proc_lock(p, ERTS_PROC_LOCK_MAIN); - erts_release_code_write_permission(); + + erts_release_code_mod_permission(); + return res; error: @@ -306,7 +311,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) * But this code_ptr will point to the start of the Export, * not the function's func_info instruction. BOOM !? */ - cmfa = erts_code_to_codemfa(ep->addresses[code_ix]); + cmfa = erts_code_to_codemfa(ep->dispatch.addresses[code_ix]); } else if (modp == NULL || (code_hdr = modp->curr.code_hdr) == NULL) { BIF_RET(am_undef); } else { @@ -624,7 +629,11 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) } break; default: +#ifdef ARCH_64 + erts_print(to, to_arg, "%ld", *ap); +#else erts_print(to, to_arg, "%d", *ap); +#endif } ap++; break; @@ -678,7 +687,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) case 'F': /* Function definition */ { ErlFunEntry* fe = (ErlFunEntry *) *ap; - const ErtsCodeMFA *cmfa = erts_find_function_from_pc(fe->address); + const ErtsCodeMFA *cmfa = erts_get_fun_mfa(fe, erts_active_code_ix()); erts_print(to, to_arg, "fun(`%T`:`%T`/%bpu)", cmfa->module, cmfa->function, cmfa->arity); ap++; @@ -885,7 +894,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_make_fun3_Fdt: + case op_i_make_fun3_Fdtt: { int n = unpacked[-1]; @@ -905,6 +914,55 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) } } break; + case op_i_bs_create_bin_jIWdW: + { + int n = unpacked[-1]; + int i = 0; + Eterm type = 0; + + while (n > 0) { + switch (i % 5) { + case 0: /* Type */ + type = ap[i]; + erts_print(to, to_arg, " `%d`", type); + break; + case 1: /* Unit */ + case 2: /* Flags */ + erts_print(to, to_arg, " `%d`", (Eterm) ap[i]); + break; + case 4: /* Size */ + if (type == BSC_BINARY_FIXED_SIZE || + type == BSC_FLOAT_FIXED_SIZE || + type == BSC_INTEGER_FIXED_SIZE || + type == BSC_STRING || + type == BSC_UTF32) { + erts_print(to, to_arg, " `%d`", ap[i]); + break; + } + + /*FALLTHROUGH*/ + case 3: /* Src */ + if (type == BSC_STRING) { + erts_print(to, to_arg, " "); + print_byte_string(to, to_arg, (byte *) ap[i], ap[i+1]); + break; + } + switch (loader_tag(ap[i])) { + case LOADER_X_REG: + erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[i])); + break; + case LOADER_Y_REG: + erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[i]) - CP_SIZE); + break; + default: + erts_print(to, to_arg, " `%T`", (Eterm) ap[i]); + break; + } + } + i++, size++, n--; + } + } + break; } erts_print(to, to_arg, "\n"); @@ -1085,7 +1143,7 @@ dirty_test(Process *c_p, Eterm type, Eterm arg1, Eterm arg2, ErtsCodePtr I) Eterm *hp, sz; Eterm cpy; /* We do not want this to be optimized, - but rather the oposite... */ + but rather the opposite... */ sz = size_object(arg2); hp = HAlloc(c_p, sz); cpy = copy_struct(arg2, sz, &hp, &c_p->off_heap); diff --git a/erts/emulator/beam/beam_file.c b/erts/emulator/beam/beam_file.c index 4bae61ceb77d..ede07f36ef62 100644 --- a/erts/emulator/beam/beam_file.c +++ b/erts/emulator/beam/beam_file.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -26,6 +26,9 @@ #include "beam_load.h" #include "erl_zlib.h" #include "big.h" +#include "erl_unicode.h" +#include "erl_binary.h" +#include "erl_global_literals.h" #define LoadError(Expr) \ do { \ @@ -57,7 +60,10 @@ struct BeamCodeReader__ { BeamFile *file; BeamOp *pending; - Uint first; + + BeamOpArg current_func_label; + BeamOpArg current_entry_label; + int first; }; typedef struct { @@ -230,7 +236,6 @@ static int beamreader_read_tagged(BeamReader *reader, TaggedNumber *val) { } static int parse_atom_chunk(BeamFile *beam, - ErtsAtomEncoding enc, IFF_Chunk *chunk) { BeamFile_AtomTable *atoms; BeamReader reader; @@ -255,7 +260,6 @@ static int parse_atom_chunk(BeamFile *beam, atoms->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, count * sizeof(atoms->entries[0])); atoms->entries[0] = THE_NON_VALUE; - atoms->encoding = enc; atoms->count = count; for (i = 1; i < count; i++) { @@ -266,7 +270,7 @@ static int parse_atom_chunk(BeamFile *beam, LoadAssert(beamreader_read_u8(&reader, &length)); LoadAssert(beamreader_read_bytes(&reader, length, &string)); - atom = erts_atom_put(string, length, enc, 1); + atom = erts_atom_put(string, length, ERTS_ATOM_ENC_UTF8, 1); LoadAssert(atom != THE_NON_VALUE); atoms->entries[i] = atom; @@ -320,24 +324,23 @@ static int parse_import_chunk(BeamFile *beam, IFF_Chunk *chunk) { return 1; } -static int parse_export_chunk(BeamFile *beam, IFF_Chunk *chunk) { - BeamFile_ExportTable *exports; +static int parse_export_table(BeamFile_ExportTable *dest, + BeamFile *beam, IFF_Chunk *chunk) { BeamFile_AtomTable *atoms; BeamReader reader; Sint32 count; int i; - exports = &beam->exports; - ASSERT(exports->entries == NULL); + ASSERT(dest->entries == NULL); beamreader_init(chunk->data, chunk->size, &reader); LoadAssert(beamreader_read_i32(&reader, &count)); - LoadAssert(CHECK_ITEM_COUNT(count, 0, sizeof(exports->entries[0]))); + LoadAssert(CHECK_ITEM_COUNT(count, 0, sizeof(dest->entries[0]))); - exports->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, - count * sizeof(exports->entries[0])); - exports->count = count; + dest->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + count * sizeof(dest->entries[0])); + dest->count = count; atoms = &beam->atoms; @@ -352,14 +355,24 @@ static int parse_export_chunk(BeamFile *beam, IFF_Chunk *chunk) { LoadAssert(arity >= 0 && arity <= MAX_ARG); LoadAssert(label >= 0); - exports->entries[i].function = atoms->entries[atom_index]; - exports->entries[i].arity = arity; - exports->entries[i].label = label; + dest->entries[i].function = atoms->entries[atom_index]; + dest->entries[i].arity = arity; + dest->entries[i].label = label; } return 1; } +static int parse_export_chunk(BeamFile *beam, IFF_Chunk *chunk) { + return parse_export_table(&beam->exports, beam, chunk); +} + +#ifdef BEAMASM +static int parse_locals_chunk(BeamFile *beam, IFF_Chunk *chunk) { + return parse_export_table(&beam->locals, beam, chunk); +} +#endif + static int parse_lambda_chunk(BeamFile *beam, IFF_Chunk *chunk) { BeamFile_LambdaTable *lambdas; BeamFile_AtomTable *atoms; @@ -436,6 +449,10 @@ static int parse_line_chunk(BeamFile *beam, IFF_Chunk *chunk) { LoadAssert(CHECK_ITEM_COUNT(item_count, 0, sizeof(lines->items[0]))); LoadAssert(CHECK_ITEM_COUNT(name_count, 0, sizeof(lines->names[0]))); + /* Include the implicit "module name with .erl suffix" entry so we don't + * have to special-case it anywhere else. */ + name_count++; + /* Flags are unused at the moment. */ (void)flags; @@ -448,17 +465,20 @@ static int parse_line_chunk(BeamFile *beam, IFF_Chunk *chunk) { item_count * sizeof(lines->items[0])); lines->item_count = item_count; - lines->names = erts_alloc(ERTS_ALC_T_PREPARED_CODE, - name_count * sizeof(lines->names[0])); - lines->name_count = name_count; - - lines->location_size = lines->name_count ? sizeof(Sint32) : sizeof(Sint16); - /* The zeroth entry in the line item table is always present and contains * the "undefined location." */ lines->items[0].name_index = 0; lines->items[0].location = 0; + lines->names = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + name_count * sizeof(lines->names[0])); + lines->name_count = name_count; + + /* We have to use the 32-bit representation if there's any names other than + * the implicit "module_name.erl" in the table, as we can't fit LOC_FILE in + * 16 bits. */ + lines->location_size = name_count > 1 ? sizeof(Sint32) : sizeof(Sint16); + name_index = 0; i = 1; @@ -494,23 +514,180 @@ static int parse_line_chunk(BeamFile *beam, IFF_Chunk *chunk) { } } - for (i = 0; i < name_count; i++) { - Sint16 name_length; - const byte *name_data; - Eterm name; + /* Add the implicit "module_name.erl" entry, followed by the rest of the + * name table. */ + { + Eterm default_name_buf[MAX_ATOM_CHARACTERS * 2]; + Eterm *name_heap = default_name_buf; + Eterm name, suffix; + Eterm *hp; + + suffix = erts_get_global_literal(ERTS_LIT_ERL_FILE_SUFFIX); + + hp = name_heap; + name = erts_atom_to_string(&hp, beam->module, suffix); + + lines->names[0] = beamfile_add_literal(beam, name, 1); + + for (i = 1; i < name_count; i++) { + Uint num_chars, num_built, num_eaten; + const byte *name_data, *err_pos; + Sint16 name_length; + Eterm *hp; + + LoadAssert(beamreader_read_i16(&reader, &name_length)); + LoadAssert(name_length >= 0); + + LoadAssert(beamreader_read_bytes(&reader, name_length, &name_data)); + + if (name_length > 0) { + LoadAssert(erts_analyze_utf8(name_data, name_length, + &err_pos, &num_chars, + NULL) == ERTS_UTF8_OK); + + if (num_chars < MAX_ATOM_CHARACTERS) { + name_heap = default_name_buf; + } else { + name_heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, + num_chars * sizeof(Eterm[2])); + } + + hp = name_heap; + name = erts_make_list_from_utf8_buf(&hp, num_chars, + name_data, + name_length, + &num_built, + &num_eaten, + NIL); + + ASSERT(num_built == num_chars); + ASSERT(num_eaten == name_length); + + lines->names[i] = beamfile_add_literal(beam, name, 1); + + if (name_heap != default_name_buf) { + erts_free(ERTS_ALC_T_LOADER_TMP, name_heap); + } + } else { + /* Empty file names are rather unusual and annoying to deal + * with since NIL isn't a valid literal, so we'll fake it with + * our module name instead. */ + lines->names[i] = lines->names[0]; + } + } + } + + return 1; +} + +/* We assume the presence of a type table to simplify loading, so we'll need to + * create a dummy table (with single entry for the "any type") when we don't + * have one. */ +static void init_fallback_type_table(BeamFile *beam) { + BeamFile_TypeTable *types; + + types = &beam->types; + ASSERT(types->entries == NULL); + + types->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + sizeof(types->entries[0])); + types->count = 1; + types->fallback = 1; + + types->entries[0].type_union = BEAM_TYPE_ANY; + types->entries[0].metadata_flags = 0; + types->entries[0].size_unit = 1; + types->entries[0].min = MAX_SMALL + 1; + types->entries[0].max = MIN_SMALL - 1; +} + +static int parse_type_chunk_otp_25(BeamFile *beam, BeamReader *p_reader) { + BeamFile_TypeTable *types; + + Sint32 count; + int i; + + types = &beam->types; + ASSERT(types->entries == NULL); + + LoadAssert(beamreader_read_i32(p_reader, &count)); + LoadAssert(CHECK_ITEM_COUNT(count, 0, sizeof(types->entries[0]))); + LoadAssert(count >= 1); + + types->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + count * sizeof(types->entries[0])); + types->count = count; + types->fallback = 0; + + for (i = 0; i < count; i++) { + const byte *type_data; + + LoadAssert(beamreader_read_bytes(p_reader, 18, &type_data)); + LoadAssert(beam_types_decode_otp_25(type_data, 18, &types->entries[i])); + } + + /* The first entry MUST be the "any type." */ + LoadAssert(types->entries[0].type_union == BEAM_TYPE_ANY); + LoadAssert(types->entries[0].min > types->entries[0].max); + + return 1; +} + +static int parse_type_chunk_otp_26(BeamFile *beam, BeamReader *p_reader) { + BeamFile_TypeTable *types; + + Sint32 count; + int i; - LoadAssert(beamreader_read_i16(&reader, &name_length)); - LoadAssert(beamreader_read_bytes(&reader, name_length, &name_data)); + types = &beam->types; + ASSERT(types->entries == NULL); - name = erts_atom_put(name_data, name_length, ERTS_ATOM_ENC_UTF8, 1); - LoadAssert(name != THE_NON_VALUE); + LoadAssert(beamreader_read_i32(p_reader, &count)); + LoadAssert(CHECK_ITEM_COUNT(count, 0, sizeof(types->entries[0]))); + LoadAssert(count >= 1); - lines->names[i] = name; + types->entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + count * sizeof(types->entries[0])); + types->count = count; + types->fallback = 0; + + for (i = 0; i < count; i++) { + const byte *type_data; + int extra; + + LoadAssert(beamreader_read_bytes(p_reader, 2, &type_data)); + extra = beam_types_decode_type_otp_26(type_data, &types->entries[i]); + LoadAssert(extra >= 0); + LoadAssert(beamreader_read_bytes(p_reader, extra, &type_data)); + beam_types_decode_extra_otp_26(type_data, &types->entries[i]); } + /* The first entry MUST be the "any type." */ + LoadAssert(types->entries[0].type_union == BEAM_TYPE_ANY); + LoadAssert(types->entries[0].min > types->entries[0].max); + return 1; } +static int parse_type_chunk(BeamFile *beam, IFF_Chunk *chunk) { + BeamReader reader; + Sint32 version; + + beamreader_init(chunk->data, chunk->size, &reader); + + LoadAssert(beamreader_read_i32(&reader, &version)); + switch (version) { + case 1: /* OTP 25 */ + return parse_type_chunk_otp_25(beam, &reader); + case BEAM_TYPES_VERSION: /* OTP 26 */ + return parse_type_chunk_otp_26(beam, &reader); + default: + /* Incompatible type format. */ + init_fallback_type_table(beam); + return 1; + } +} + static ErlHeapFragment *new_literal_fragment(Uint size) { ErlHeapFragment *bp; @@ -726,7 +903,7 @@ static int read_beam_chunks(const IFF_File *file, enum beamfile_read_result beamfile_read(const byte *data, size_t size, BeamFile *beam) { static const Uint chunk_iffs[] = { - MakeIffId('A', 't', 'o', 'm'), /* 0 */ + MakeIffId('A', 't', 'U', '8'), /* 0 */ MakeIffId('C', 'o', 'd', 'e'), /* 1 */ MakeIffId('S', 't', 'r', 'T'), /* 2 */ MakeIffId('I', 'm', 'p', 'T'), /* 3 */ @@ -736,10 +913,13 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { MakeIffId('A', 't', 't', 'r'), /* 7 */ MakeIffId('C', 'I', 'n', 'f'), /* 8 */ MakeIffId('L', 'i', 'n', 'e'), /* 9 */ - MakeIffId('A', 't', 'U', '8'), /* 10 */ + MakeIffId('L', 'o', 'c', 'T'), /* 10 */ + MakeIffId('A', 't', 'o', 'm'), /* 11 */ + MakeIffId('T', 'y', 'p', 'e'), /* 12 */ + MakeIffId('M', 'e', 't', 'a'), /* 13 */ }; - static const int ATOM_CHUNK = 0; + static const int UTF8_ATOM_CHUNK = 0; static const int CODE_CHUNK = 1; static const int STR_CHUNK = 2; static const int IMP_CHUNK = 3; @@ -749,7 +929,12 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { static const int ATTR_CHUNK = 7; static const int COMPILE_CHUNK = 8; static const int LINE_CHUNK = 9; - static const int UTF8_ATOM_CHUNK = 10; +#ifdef BEAMASM + static const int LOC_CHUNK = 10; +#endif + static const int OBSOLETE_ATOM_CHUNK = 11; + static const int TYPE_CHUNK = 12; + static const int META_CHUNK = 13; static const int NUM_CHUNKS = sizeof(chunk_iffs) / sizeof(chunk_iffs[0]); @@ -757,8 +942,6 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { /* MSVC doesn't like the use of NUM_CHUNKS here */ IFF_Chunk chunks[sizeof(chunk_iffs) / sizeof(chunk_iffs[0])]; - IFF_Chunk *atom_chunk; - ErtsAtomEncoding enc; sys_memset(beam, 0, sizeof(*beam)); @@ -780,18 +963,16 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { goto error; } - if (chunks[UTF8_ATOM_CHUNK].size > 0) { - atom_chunk = &chunks[UTF8_ATOM_CHUNK]; - enc = ERTS_ATOM_ENC_UTF8; - } else if (chunks[ATOM_CHUNK].size > 0) { - atom_chunk = &chunks[ATOM_CHUNK]; - enc = ERTS_ATOM_ENC_LATIN1; - } else { - error = BEAMFILE_READ_MISSING_ATOM_TABLE; + if (chunks[UTF8_ATOM_CHUNK].size == 0) { + if (chunks[OBSOLETE_ATOM_CHUNK].size == 0) { + /* Old atom table chunk is also missing. */ + error = BEAMFILE_READ_MISSING_ATOM_TABLE; + } else { + /* Old atom table chunk table exists. (OTP 20 or earlier.) */ + error = BEAMFILE_READ_OBSOLETE_ATOM_TABLE; + } goto error; - } - - if (!parse_atom_chunk(beam, enc, atom_chunk)) { + } else if (!parse_atom_chunk(beam, &chunks[UTF8_ATOM_CHUNK])) { error = BEAMFILE_READ_CORRUPT_ATOM_TABLE; goto error; } @@ -812,6 +993,15 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { goto error; } +#ifdef BEAMASM + if (erts_jit_asm_dump && chunks[LOC_CHUNK].size > 0) { + if (!parse_locals_chunk(beam, &chunks[LOC_CHUNK])) { + error = BEAMFILE_READ_CORRUPT_LOCALS_TABLE; + goto error; + } + } +#endif + if (chunks[LAMBDA_CHUNK].size > 0) { if (!parse_lambda_chunk(beam, &chunks[LAMBDA_CHUNK])) { error = BEAMFILE_READ_CORRUPT_LAMBDA_TABLE; @@ -833,6 +1023,15 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { } } + if (chunks[TYPE_CHUNK].size > 0) { + if (!parse_type_chunk(beam, &chunks[TYPE_CHUNK])) { + error = BEAMFILE_READ_CORRUPT_TYPE_TABLE; + goto error; + } + } else { + init_fallback_type_table(beam); + } + beam->strings.data = chunks[STR_CHUNK].data; beam->strings.size = chunks[STR_CHUNK].size; @@ -849,8 +1048,8 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { MD5Init(&md5); MD5Update(&md5, - (byte*)atom_chunk->data, - atom_chunk->size); + (byte*)chunks[UTF8_ATOM_CHUNK].data, + chunks[UTF8_ATOM_CHUNK].size); MD5Update(&md5, (byte*)chunks[CODE_CHUNK].data, chunks[CODE_CHUNK].size); @@ -902,6 +1101,12 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { chunks[LITERAL_CHUNK].size); } + if (chunks[META_CHUNK].size > 0) { + MD5Update(&md5, + (byte*)chunks[META_CHUNK].data, + chunks[META_CHUNK].size); + } + MD5Final(beam->checksum, &md5); } @@ -940,6 +1145,13 @@ void beamfile_free(BeamFile *beam) { beam->exports.entries = NULL; } +#ifdef BEAMASM + if (beam->locals.entries) { + erts_free(ERTS_ALC_T_PREPARED_CODE, beam->locals.entries); + beam->locals.entries = NULL; + } +#endif + if (beam->lambdas.entries) { erts_free(ERTS_ALC_T_PREPARED_CODE, beam->lambdas.entries); beam->lambdas.entries = NULL; @@ -955,6 +1167,11 @@ void beamfile_free(BeamFile *beam) { beam->lines.names = NULL; } + if (beam->types.entries) { + erts_free(ERTS_ALC_T_PREPARED_CODE, beam->types.entries); + beam->types.entries = NULL; + } + if (beam->static_literals.entries) { beamfile_literal_dtor(&beam->static_literals); } @@ -964,7 +1181,7 @@ void beamfile_free(BeamFile *beam) { } } -Sint beamfile_add_literal(BeamFile *beam, Eterm term) { +Sint beamfile_add_literal(BeamFile *beam, Eterm term, int deduplicate) { BeamFile_LiteralTable *literals; BeamFile_LiteralEntry *entries; @@ -976,22 +1193,17 @@ Sint beamfile_add_literal(BeamFile *beam, Eterm term) { literals = &beam->dynamic_literals; entries = literals->entries; - if (entries == NULL) { - literals->allocated = 32; - - entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, - literals->allocated * sizeof(*entries)); - - literals->entries = entries; - } else { - /* Return a matching index if this literal already exists. We search - * backwards since duplicates tend to be used close to one another, - * and skip searching static literals as the chances of overlap are - * pretty slim. */ - for (i = literals->count - 1; i >= 0; i--) { - if (EQ(term, entries[i].value)) { - /* Dynamic literal indexes are negative, starting at -1 */ - return ~i; + if (entries != NULL) { + if (deduplicate) { + /* Return a matching index if this literal already exists. + * We search backwards since duplicates tend to be used close to + * one another, and skip searching static literals as the chances + * of overlap are pretty slim. */ + for (i = literals->count - 1; i >= 0; i--) { + if (EQ(term, entries[i].value)) { + /* Dynamic literal indexes are negative, starting at -1 */ + return ~i; + } } } @@ -1003,6 +1215,13 @@ Sint beamfile_add_literal(BeamFile *beam, Eterm term) { literals->entries = entries; } + } else { + literals->allocated = 32; + + entries = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + literals->allocated * sizeof(*entries)); + + literals->entries = entries; } term_size = size_object(term); @@ -1101,6 +1320,16 @@ int iff_read_chunk(IFF_File *iff, Uint id, IFF_Chunk *chunk) return read_beam_chunks(iff, 1, &id, chunk); } +void beamfile_init(void) { + Eterm suffix; + Eterm *hp; + + hp = erts_alloc_global_literal(ERTS_LIT_ERL_FILE_SUFFIX, 8); + suffix = erts_bin_bytes_to_list(NIL, hp, (byte*)".erl", 4, 0); + + erts_register_global_literal(ERTS_LIT_ERL_FILE_SUFFIX, suffix); +} + /* * * * * * * */ void beamopallocator_init(BeamOpAllocator *allocator) { @@ -1239,7 +1468,8 @@ static int marshal_integer(BeamCodeReader *code_reader, TaggedNumber *value) { value->tag = TAG_q; value->size = 0; - value->word_value = beamfile_add_literal(code_reader->file, term); + value->word_value = beamfile_add_literal(code_reader->file, + term, 1); } else { /* Result doesn't fit into a bignum. */ value->tag = TAG_o; @@ -1313,8 +1543,7 @@ static int beamcodereader_read_next(BeamCodeReader *code_reader, BeamOp **out) { reader = &code_reader->reader; LoadAssert(beamreader_read_u8(reader, &opcode)); - LoadAssert(opcode <= MAX_GENERIC_OPCODE); - LoadAssert(gen_opc[opcode].name[0] != '\0'); + LoadAssert(opcode > 0 && opcode <= MAX_GENERIC_OPCODE); arity = gen_opc[opcode].arity; ASSERT(arity <= ERTS_BEAM_MAX_OPARGS); @@ -1354,12 +1583,6 @@ static int beamcodereader_read_next(BeamCodeReader *code_reader, BeamOp **out) { case TAG_i: LoadAssert(marshal_integer(code_reader, &raw_arg)); break; - case TAG_h: - /* Character, must be a valid unicode code point. */ - LoadAssert(raw_arg.word_value <= 0x10FFFF && - (raw_arg.word_value < 0xD800 || - raw_arg.word_value > 0xDFFFUL)); - break; case TAG_x: case TAG_y: LoadAssert(raw_arg.word_value < MAX_REG); @@ -1428,7 +1651,7 @@ static int beamcodereader_read_next(BeamCodeReader *code_reader, BeamOp **out) { case 4: /* Literal */ { - BeamFile_LiteralTable *literals; + const BeamFile_LiteralTable *literals; TaggedNumber index; LoadAssert(beamreader_read_tagged(reader, &index)); @@ -1442,6 +1665,31 @@ static int beamcodereader_read_next(BeamCodeReader *code_reader, BeamOp **out) { raw_arg.tag = TAG_q; raw_arg.word_value = index.word_value; + break; + } + case 5: + /* Register with type hint */ + { + const BeamFile_TypeTable *types; + TaggedNumber index; + + LoadAssert(beamreader_read_tagged(reader, &raw_arg)); + LoadAssert(raw_arg.tag == TAG_x || raw_arg.tag == TAG_y); + + LoadAssert(beamreader_read_tagged(reader, &index)); + LoadAssert(index.tag == TAG_u); + + types = &(code_reader->file)->types; + + /* We may land here without a table if it was stripped + * after compilation, in which case we want to treat these + * as ordinary registers. */ + if (!types->fallback) { + LoadAssert(index.word_value < types->count); + + ERTS_CT_ASSERT(REG_MASK < (1 << 10)); + raw_arg.word_value |= index.word_value << 10; + } break; } default: @@ -1465,82 +1713,101 @@ static int beamcodereader_read_next(BeamCodeReader *code_reader, BeamOp **out) { return 1; } +static void synthesize_func_end(BeamCodeReader *code_reader) { + BeamOp *func_end; + + func_end = beamopallocator_new_op(code_reader->allocator); + func_end->op = genop_int_func_end_2; + func_end->arity = 2; + + ASSERT(code_reader->current_func_label.type == TAG_u); + func_end->a[0].val = code_reader->current_func_label.val; + func_end->a[0].type = TAG_f; + + ASSERT(code_reader->current_entry_label.type == TAG_u); + func_end->a[1].val = code_reader->current_entry_label.val; + func_end->a[1].type = TAG_f; + + func_end->next = code_reader->pending; + code_reader->pending = func_end; +} int beamcodereader_next(BeamCodeReader *code_reader, BeamOp **out) { BeamOp *op; if (code_reader->pending) { - *out = code_reader->pending; - code_reader->pending = code_reader->pending->next; + op = code_reader->pending; + code_reader->pending = op->next; + + *out = op; return 1; } LoadAssert(beamcodereader_read_next(code_reader, &op)); - if (op->op != genop_label_1) { - *out = op; - return 1; - } else { - /* - * To simplify the rest of the loading process, attempt - * to synthesize int_func_start/5 and int_func_end/0 - * instructions. + switch (op->op) { + case genop_label_1: + /* To simplify the rest of the loading process, attempt to synthesize + * int_func_start/5 and int_func_end/2 instructions. * * We look for the following instruction sequence to * find function boundaries: label Lbl | line Loc | func_info M F A. * (Where the line instruction is optional.) * - * So far we have seen a label/0 instruction. Put this - * instruction into the pending queue and decode the next - * instruction. - */ + * So far we have seen a label/0 instruction. Put this instruction into + * the pending queue and decode the next instruction. */ code_reader->pending = op; LoadAssert(beamcodereader_read_next(code_reader, &op->next)); op = op->next; - /* - * If the current instruction is a line instruction, append it to - * the pending queue and decode the following instruction. - */ + /* If the current instruction is a line instruction, append it to + * the pending queue and decode the following instruction. */ if (op->op == genop_line_1) { LoadAssert(beamcodereader_read_next(code_reader, &op->next)); op = op->next; } - /* - * If the current instruction is a func_info instruction, we - * have found a function boundary. - */ - if (op->op == genop_func_info_3) { + /* The code must not end abruptly after a label. */ + LoadAssert(op->op != genop_int_code_end_0); + + /* If the current instruction is a func_info instruction, we + * have found a function boundary. */ + if (ERTS_LIKELY(op->op != genop_func_info_3)) { + op->next = NULL; + } else { + BeamOpArg func_label, entry_label; BeamOp *func_start; + BeamOp *entry_op; BeamOp *next; - /* - * Prepare to walk through the queue of pending instructions. - */ + /* The func_info/3 instruction must be followed by its entry + * label. */ + LoadAssert(beamcodereader_read_next(code_reader, &entry_op)); + LoadAssert(entry_op->op == genop_label_1); + entry_label = entry_op->a[0]; + LoadAssert(entry_label.type == TAG_u); + entry_op->next = NULL; + + /* Prepare to walk through the queue of pending instructions. */ op = code_reader->pending; - ASSERT(op->op == genop_label_1); - /* - * Allocate the int_func_start/0 function. - */ - func_start = beamopallocator_new_op(code_reader->allocator); - func_start->op = genop_int_func_start_5; - func_start->arity = 5; + /* Pick up the label from the first label/1 instruction. */ + ASSERT(op->op == genop_label_1); + func_label = op->a[0]; + LoadAssert(func_label.type == TAG_u); - /* - * Pick up the label from the label/1 instruction. - */ - func_start->a[0] = op->a[0]; next = op->next; beamopallocator_free_op(code_reader->allocator, op); op = next; - /* - * If the current instruction is a line/1 instruction, - * pick up the location from that instruction. - * Otherwise use NIL. - */ + /* Allocate the int_func_start/0 function. */ + func_start = beamopallocator_new_op(code_reader->allocator); + func_start->op = genop_int_func_start_5; + func_start->arity = 5; + func_start->a[0] = func_label; + + /* If the current instruction is a line/1 instruction, pick up the + * location from that instruction. Otherwise use NIL. */ func_start->a[1].type = TAG_n; if (op->op == genop_line_1) { func_start->a[1] = op->a[0]; @@ -1549,45 +1816,46 @@ int beamcodereader_next(BeamCodeReader *code_reader, BeamOp **out) { op = next; } - /* - * Pick up the MFA from the func_info/3 instruction. - */ + /* Pick up the MFA from the func_info/3 instruction. */ ASSERT(op->op == genop_func_info_3); func_start->a[2] = op->a[0]; func_start->a[3] = op->a[1]; func_start->a[4] = op->a[2]; beamopallocator_free_op(code_reader->allocator, op); - /* - * Put the int_func_start/5 instruction into the pending - * queue. - */ + /* Put the int_func_start/5 instruction into the pending queue, + * and link the entry label after it. */ code_reader->pending = func_start; - op = func_start; - - /* - * Unless this is the first function in the module, - * synthesize an int_func_end/0 instruction and prepend - * it to the pending queue. - */ - if (code_reader->first) { - code_reader->first = 0; - } else { - BeamOp *func_end; - func_end = beamopallocator_new_op(code_reader->allocator); - func_end->op = genop_int_func_end_0; - func_end->arity = 0; - func_end->next = code_reader->pending; - code_reader->pending = func_end; + func_start->next = entry_op; + + /* Unless this is the first function in the module, synthesize an + * int_func_end/2 instruction and prepend it to the pending + * queue. */ + if (!code_reader->first) { + synthesize_func_end(code_reader); } + + code_reader->current_func_label = func_label; + code_reader->current_entry_label = entry_label; + code_reader->first = 0; + } + + /* At this point, there is at least one instruction in the pending + * queue, and the op variable points to the last instruction in the + * queue. */ + return beamcodereader_next(code_reader, out); + case genop_int_code_end_0: + code_reader->pending = op; + + if (!code_reader->first) { + synthesize_func_end(code_reader); } - /* - * At this point, there is at least one instruction in the pending - * queue. The op variable points to the last instruction in the queue. - */ op->next = NULL; return beamcodereader_next(code_reader, out); + default: + *out = op; + return 1; } } diff --git a/erts/emulator/beam/beam_file.h b/erts/emulator/beam/beam_file.h index fe68447b8e0a..7168ffc793c0 100644 --- a/erts/emulator/beam/beam_file.h +++ b/erts/emulator/beam/beam_file.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -25,6 +25,7 @@ #include "sys.h" #include "atom.h" +#include "beam_types.h" #define CHECKSUM_SIZE 16 @@ -54,10 +55,6 @@ int iff_init(const byte *data, size_t size, IFF_File *iff); int iff_read_chunk(IFF_File *iff, Uint id, IFF_Chunk *chunk); typedef struct { - /* The encoding that was used to create this table. This is only used for - * version tests. */ - ErtsAtomEncoding encoding; - Sint32 count; Eterm *entries; } BeamFile_AtomTable; @@ -120,7 +117,7 @@ typedef struct { Sint32 flags; Sint32 name_count; - Eterm *names; + Sint *names; Sint32 location_size; Sint32 item_count; @@ -140,6 +137,14 @@ typedef struct { BeamFile_LiteralEntry *entries; } BeamFile_LiteralTable; +typedef struct { + /* To simplify code that queries types, the first entry (which must be + * present) is always the "any type." */ + Sint32 count; + char fallback; /* If this is a fallback type table */ + BeamType *entries; +} BeamFile_TypeTable; + typedef struct { IFF_File iff; @@ -150,8 +155,12 @@ typedef struct { BeamFile_AtomTable atoms; BeamFile_ImportTable imports; BeamFile_ExportTable exports; +#ifdef BEAMASM + BeamFile_ExportTable locals; +#endif BeamFile_LambdaTable lambdas; BeamFile_LineTable lines; + BeamFile_TypeTable types; /* Static literals are those defined in the file, and dynamic literals are * those created when loading. The former is positively indexed starting @@ -178,6 +187,7 @@ enum beamfile_read_result { /* Mandatory chunks */ BEAMFILE_READ_MISSING_ATOM_TABLE, + BEAMFILE_READ_OBSOLETE_ATOM_TABLE, BEAMFILE_READ_CORRUPT_ATOM_TABLE, BEAMFILE_READ_MISSING_CODE_CHUNK, BEAMFILE_READ_CORRUPT_CODE_CHUNK, @@ -185,17 +195,19 @@ enum beamfile_read_result { BEAMFILE_READ_CORRUPT_EXPORT_TABLE, BEAMFILE_READ_MISSING_IMPORT_TABLE, BEAMFILE_READ_CORRUPT_IMPORT_TABLE, + BEAMFILE_READ_CORRUPT_LOCALS_TABLE, /* Optional chunks */ BEAMFILE_READ_CORRUPT_LAMBDA_TABLE, BEAMFILE_READ_CORRUPT_LINE_TABLE, - BEAMFILE_READ_CORRUPT_LITERAL_TABLE + BEAMFILE_READ_CORRUPT_LITERAL_TABLE, + BEAMFILE_READ_CORRUPT_TYPE_TABLE }; typedef struct { /* TAG_xyz */ - int type; - BeamInstr val; + UWord type; + UWord val; } BeamOpArg; typedef struct beamop { @@ -230,6 +242,8 @@ typedef struct { #include "erl_process.h" #include "erl_message.h" +void beamfile_init(void); + /** @brief Reads the given module binary into \p beam and validates its * structural integrity. */ enum beamfile_read_result @@ -239,10 +253,14 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam); * it. */ void beamfile_free(BeamFile *beam); -/** @brief Copies a term into the dynamic literal table. +/** @brief Copies a term into the dynamic literal table + * + * @param[in] deduplicate Whether to try to deduplicate the term before + * insertion. Set to zero if you require a new unique literal, for example if + * it needs to be modified in the late stages of loading. * * @return A literal index that can be used in beamfile_get_literal */ -Sint beamfile_add_literal(BeamFile *beam, Eterm term); +Sint beamfile_add_literal(BeamFile *beam, Eterm term, int deduplicate); /** @brief Gets a term from the literal table. * diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 063b740c082b..d0510850234a 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -47,6 +47,8 @@ Uint erts_total_code_size; static int load_code(LoaderState *stp); +#define PLEASE_RECOMPILE "please re-compile this module with an Erlang/OTP " ERLANG_OTP_RELEASE " compiler or update your Erlang/OTP version" + /**********************************************************************/ void init_load(void) @@ -54,6 +56,20 @@ void init_load(void) erts_total_code_size = 0; beam_catches_init(); erts_init_ranges(); + +#ifdef DEBUG + { + int i; + + for (i = 1; i < NUM_GENERIC_OPS; i++) { + const GenOpEntry *op = &gen_opc[i]; + + ASSERT(op->name && op->name[0] != '\0'); + ASSERT(op->arity <= ERTS_BEAM_MAX_OPARGS); + ASSERT(op->num_specific <= 1 || op->arity <= 6); + } + } +#endif } Binary *erts_alloc_loader_state(void) { @@ -128,6 +144,8 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, BeamLoadError0(stp, "corrupt file header"); case BEAMFILE_READ_MISSING_ATOM_TABLE: BeamLoadError0(stp, "missing atom table"); + case BEAMFILE_READ_OBSOLETE_ATOM_TABLE: + BeamLoadError0(stp, PLEASE_RECOMPILE); case BEAMFILE_READ_CORRUPT_ATOM_TABLE: BeamLoadError0(stp, "corrupt atom table"); case BEAMFILE_READ_MISSING_CODE_CHUNK: @@ -148,6 +166,10 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, BeamLoadError0(stp, "corrupt line table"); case BEAMFILE_READ_CORRUPT_LITERAL_TABLE: BeamLoadError0(stp, "corrupt literal table"); + case BEAMFILE_READ_CORRUPT_LOCALS_TABLE: + BeamLoadError0(stp, "corrupt locals table"); + case BEAMFILE_READ_CORRUPT_TYPE_TABLE: + BeamLoadError0(stp, "corrupt type table"); case BEAMFILE_READ_SUCCESS: break; } @@ -161,16 +183,13 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, if (stp->beam.code.max_opcode > MAX_GENERIC_OPCODE) { BeamLoadError2(stp, "This BEAM file was compiled for a later version" - " of the run-time system than " ERLANG_OTP_RELEASE ".\n" - " To fix this, please recompile this module with an " - ERLANG_OTP_RELEASE " compiler.\n" + " of the runtime system than the current (Erlang/OTP " ERLANG_OTP_RELEASE ").\n" + " To fix this, " PLEASE_RECOMPILE ".\n" " (Use of opcode %d; this emulator supports " "only up to %d.)", stp->beam.code.max_opcode, MAX_GENERIC_OPCODE); } - stp->otp_20_or_higher = (stp->beam.atoms.encoding == ERTS_ATOM_ENC_UTF8); - if (!load_code(stp)) { goto load_error; } @@ -196,8 +215,8 @@ erts_finish_loading(Binary* magic, Process* c_p, struct erl_module_instance* inst_p; Module* mod_tab_p; - ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_write_permission() || - erts_thr_progress_is_blocking()); + ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_load_permission() || + erts_thr_progress_is_blocking()); /* Make current code for the module old and insert the new code * as current. This will fail if there already exists old code @@ -233,7 +252,7 @@ erts_finish_loading(Binary* magic, Process* c_p, erts_clear_export_break(mod_tab_p, ep); - ep->addresses[code_ix] = + ep->dispatch.addresses[code_ix] = (ErtsCodePtr)ep->trampoline.breakpoint.address; ep->trampoline.breakpoint.address = 0; @@ -369,10 +388,12 @@ static int load_code(LoaderState* stp) int num_specific; - beam_load_prepare_emit(stp); - op_reader = beamfile_get_code(&stp->beam, &stp->op_allocator); + if (!beam_load_prepare_emit(stp)) { + goto load_error; + } + for (;;) { get_next_instr: if (!beamcodereader_next(op_reader, &last_op)) { @@ -452,14 +473,10 @@ static int load_code(LoaderState* stp) * the possible specific instructions associated with this * specific instruction. */ - Uint32 mask[3] = {0, 0, 0}; - int specific, arity, arg, i; + Uint32 mask[3] = {0, 0, 0}; arity = gen_opc[tmp_op->op].arity; - if (arity > 6) { - BeamLoadError0(stp, "no specific operation found (arity > 6)"); - } for (arg = 0; arg < arity; arg++) { int type = tmp_op->a[arg].type; @@ -523,25 +540,15 @@ static int load_code(LoaderState* stp) /* * No specific operation found. */ - if (i == num_specific) { + if (ERTS_UNLIKELY(i == num_specific)) { stp->specific_op = -1; - for (arg = 0; arg < tmp_op->arity; arg++) { - /* - * We'll give the error message here (instead of earlier) - * to get a printout of the offending operation. - */ - if (tmp_op->a[arg].type == TAG_h) { - BeamLoadError0(stp, "the character data type is not supported"); - } - } /* * No specific operations and no transformations means that * the instruction is obsolete. */ if (num_specific == 0 && gen_opc[tmp_op->op].transform == -1) { - BeamLoadError0(stp, "please re-compile this module with an " - ERLANG_OTP_RELEASE " compiler "); + BeamLoadError0(stp, PLEASE_RECOMPILE); } /* @@ -550,8 +557,7 @@ static int load_code(LoaderState* stp) */ switch (stp->genop->op) { case genop_too_old_compiler_0: - BeamLoadError0(stp, "please re-compile this module with an " - ERLANG_OTP_RELEASE " compiler"); + BeamLoadError0(stp, PLEASE_RECOMPILE); case genop_unsupported_guard_bif_3: { Eterm Mod = (Eterm) stp->genop->a[0].val; @@ -565,6 +571,20 @@ static int load_code(LoaderState* stp) BeamLoadError3(stp, "unsupported guard BIF: %T:%T/%d\n", Mod, Name, arity); } + case genop_bad_bs_match_1: + { + BeamOpArg sub_command = stp->genop->a[0]; + beamopallocator_free_op(&stp->op_allocator, + stp->genop); + stp->genop = NULL; + if (sub_command.type == TAG_a) { + BeamLoadError1(stp, "bs_match: invalid sub instruction '%T' " + "(is this BEAM file generated by a future version of Erlang/OTP?)\n", + sub_command.val); + } else { + BeamLoadError0(stp, "bs_match: invalid operands (corrupt BEAM file?)\n"); + } + } default: BeamLoadError0(stp, "no specific operation found"); } @@ -626,7 +646,12 @@ erts_release_literal_area(ErtsLiteralArea* literal_area) } case FUN_SUBTAG: { - ErlFunEntry* fe = ((ErlFunThing*)oh)->fe; + /* We _KNOW_ that this is a local fun, otherwise it would not + * be part of the off-heap list. */ + ErlFunEntry* fe = ((ErlFunThing*)oh)->entry.fun; + + ASSERT(is_local_fun((ErlFunThing*)oh)); + if (erts_refc_dectest(&fe->refc, 0) == 0) { erts_erase_fun_entry(fe); } diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index fe3aeb44ad5a..0afdace2d387 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -56,7 +56,7 @@ typedef struct LoaderState_ LoaderState; int beam_load_prepared_dtor(Binary *magic); void beam_load_prepared_free(Binary *magic); -void beam_load_prepare_emit(LoaderState *stp); +int beam_load_prepare_emit(LoaderState *stp); int beam_load_emit_op(LoaderState *stp, BeamOp *op); int beam_load_finish_emit(LoaderState *stp); diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c index 22ae1ab81702..56cc106c5417 100644 --- a/erts/emulator/beam/beam_ranges.c +++ b/erts/emulator/beam/beam_ranges.c @@ -346,7 +346,6 @@ lookup_loc(FunctionInfo* fi, const void* pc, if (pc < mid[0]) { high = mid; } else if (pc < mid[1]) { - int file; int index = mid - lt->func_tab[0]; if (lt->loc_size == 2) { @@ -359,14 +358,6 @@ lookup_loc(FunctionInfo* fi, const void* pc, return; } fi->needed += 3+2+3+2; - file = LOC_FILE(fi->loc); - if (file == 0) { - /* Special case: Module name with ".erl" appended */ - Atom* mod_atom = atom_tab(atom_val(fi->mfa->module)); - fi->needed += 2*(mod_atom->len+4); - } else { - fi->needed += 2*erts_atom_to_string_length((fi->fname_ptr)[file-1]); - } return; } else { low = mid + 1; diff --git a/erts/emulator/beam/beam_transform_engine.c b/erts/emulator/beam/beam_transform_engine.c index 497d1e81b256..3ce934a48c78 100644 --- a/erts/emulator/beam/beam_transform_engine.c +++ b/erts/emulator/beam/beam_transform_engine.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2022. 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. @@ -128,20 +128,6 @@ erts_transform_engine(LoaderState* st) ap++; break; #endif - case TOP_is_same_var: - ASSERT(ap < instr->arity); - i = *pc++; - ASSERT(i < TE_MAX_VARS); - if (var[i].type != instr->a[ap].type) - goto restart; - switch (var[i].type) { - case TAG_n: - break; - default: - if (var[i].val != instr->a[ap].val) - goto restart; - } - break; #if defined(TOP_is_bif) case TOP_is_bif: { diff --git a/erts/emulator/beam/beam_transform_helpers.c b/erts/emulator/beam/beam_transform_helpers.c index 3a4ed5cd0bf6..01a0f6c28999 100644 --- a/erts/emulator/beam/beam_transform_helpers.c +++ b/erts/emulator/beam/beam_transform_helpers.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -150,7 +150,7 @@ oparg_compare(BeamOpArg* a, BeamOpArg* b) static int oparg_term_compare(SortBeamOpArg* a, SortBeamOpArg* b) { - Sint res = CMP_TERM(a->term, b->term); + Sint res = erts_cmp_flatmap_keys(a->term, b->term); if (res < 0) { return -1; diff --git a/erts/emulator/beam/beam_types.c b/erts/emulator/beam/beam_types.c new file mode 100644 index 000000000000..876db9f47b12 --- /dev/null +++ b/erts/emulator/beam/beam_types.c @@ -0,0 +1,142 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021-2023. 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% + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "beam_types.h" + +#include "global.h" +#include "erl_message.h" +#include "external.h" + +static Sint64 get_sint64(const byte *data); + +int beam_types_decode_type_otp_26(const byte *data, BeamType *out) { + int flags, extra; + + flags = (Uint16)data[0] << 8 | (Uint16)data[1]; + if (flags == BEAM_TYPE_NONE) { + return -1; + } + + extra = 0; + + out->type_union = flags & BEAM_TYPE_ANY; + out->metadata_flags = flags & BEAM_TYPE_METADATA_MASK; + + if (out->metadata_flags & BEAM_TYPE_HAS_LOWER_BOUND) { + if (!(out->type_union & (BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER))) { + return -1; + } + + extra += 8; + } + + if (out->metadata_flags & BEAM_TYPE_HAS_UPPER_BOUND) { + if (!(out->type_union & (BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER))) { + return -1; + } + + extra += 8; + } + + if (out->metadata_flags & BEAM_TYPE_HAS_UNIT) { + if (!(out->type_union & BEAM_TYPE_BITSTRING)) { + return -1; + } + + extra += 1; + } + + return extra; +} + +void beam_types_decode_extra_otp_26(const byte *data, BeamType *out) { + out->min = MAX_SMALL + 1; + out->max = MIN_SMALL - 1; + out->size_unit = 1; + + if (out->metadata_flags & BEAM_TYPE_HAS_LOWER_BOUND) { + ASSERT(out->type_union & (BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER)); + out->min = get_sint64(data); + data += 8; + } + + if (out->metadata_flags & BEAM_TYPE_HAS_UPPER_BOUND) { + ASSERT(out->type_union & (BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER)); + out->max = get_sint64(data); + data += 8; + } + + if (out->metadata_flags & BEAM_TYPE_HAS_UNIT) { + ASSERT(out->type_union & BEAM_TYPE_BITSTRING); + out->size_unit = data[0] + 1; + } +} + +int beam_types_decode_otp_25(const byte *data, Uint size, BeamType *out) { + int types; + + if (size != 18) { + return 0; + } + + types = (Uint16)data[0] << 8 | (Uint16)data[1]; + if (types == BEAM_TYPE_NONE) { + return 0; + } + + out->type_union = types; + + data += 2; + out->min = get_sint64(data); + data += 8; + out->max = get_sint64(data); + + if (out->min <= out->max) { + if (!(out->type_union & (BEAM_TYPE_FLOAT | BEAM_TYPE_INTEGER))) { + return -1; + } + + out->metadata_flags = (BEAM_TYPE_HAS_LOWER_BOUND | + BEAM_TYPE_HAS_UPPER_BOUND); + } else { + out->min = MAX_SMALL + 1; + out->max = MIN_SMALL - 1; + + out->metadata_flags = 0; + } + + out->size_unit = 1; + + return 1; +} + +static Sint64 get_sint64(const byte *data) { + Sint64 value = 0; + int i; + + for (i = 0; i < 8; i++) { + value = value << 8 | (Sint64)data[i]; + } + return value; +} diff --git a/erts/emulator/beam/beam_types.h b/erts/emulator/beam/beam_types.h new file mode 100644 index 000000000000..fe215a13408e --- /dev/null +++ b/erts/emulator/beam/beam_types.h @@ -0,0 +1,95 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021-2023. 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% + */ + +/** + * @description Basic type representation for BEAM instruction operands. + * @file beam_types.h + * + * While the compiler is good eliminating redundant type tests and simplifying + * instructions, we're limited by the available instructions and it's not + * always worthwhile to add new variants. + * + * The idea behind this module is to allow minor optimizations _inside_ + * instructions based on what we know about their operand types. For example, + * when we know that the source passed to `is_tagged_tuple` is always boxed, we + * can skip the boxed check. + */ + +#ifndef _BEAM_TYPES_H +#define _BEAM_TYPES_H + +#include "sys.h" + +#define BEAM_TYPES_VERSION 2 + +#define BEAM_TYPE_NONE (0) + +#define BEAM_TYPE_ATOM (1 << 0) +#define BEAM_TYPE_BITSTRING (1 << 1) +#define BEAM_TYPE_BS_MATCHSTATE (1 << 2) +#define BEAM_TYPE_CONS (1 << 3) +#define BEAM_TYPE_FLOAT (1 << 4) +#define BEAM_TYPE_FUN (1 << 5) +#define BEAM_TYPE_INTEGER (1 << 6) +#define BEAM_TYPE_MAP (1 << 7) +#define BEAM_TYPE_NIL (1 << 8) +#define BEAM_TYPE_PID (1 << 9) +#define BEAM_TYPE_PORT (1 << 10) +#define BEAM_TYPE_REFERENCE (1 << 11) +#define BEAM_TYPE_TUPLE (1 << 12) + +#define BEAM_TYPE_ANY ((1 << 13) - 1) + +/* This is not a part of the type union proper, but is present in the format + * to signal the presence of metadata. */ +#define BEAM_TYPE_HAS_LOWER_BOUND (1 << 13) +#define BEAM_TYPE_HAS_UPPER_BOUND (1 << 14) +#define BEAM_TYPE_HAS_UNIT (1 << 15) + +#define BEAM_TYPE_METADATA_MASK (BEAM_TYPE_HAS_LOWER_BOUND | \ + BEAM_TYPE_HAS_UPPER_BOUND | \ + BEAM_TYPE_HAS_UNIT) + +typedef struct { + /** @brief A set of the possible types (atom, tuple, etc) this term may + * be. When a single bit is set, the term will always be of that type. */ + int type_union; + + /** @brief A set of metadata presence flags, BEAM_TYPE_HAS_XYZ. */ + int metadata_flags; + + /** @brief Minimum numerical value. Only valid when the + * BEAM_TYPE_HAS_LOWER_BOUND metadata flag is present. */ + Sint64 min; + + /** @brief Maximum numerical value. Only valid when the + * BEAM_TYPE_HAS_UPPER_BOUND metadata flag is present. */ + Sint64 max; + + /** @brief Unit for bitstring size. Only valid when the BEAM_TYPE_HAS_UNIT + * metadata flag is present. */ + byte size_unit; +} BeamType; + +int beam_types_decode_type_otp_26(const byte *data, BeamType *out); +void beam_types_decode_extra_otp_26(const byte *data, BeamType *out); + +int beam_types_decode_otp_25(const byte *data, Uint size, BeamType *out); +#endif diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index ce0995f14141..f7594691e06a 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -23,6 +23,10 @@ #endif #include /* offsetof() */ +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#define WANT_NONBLOCKING #include "sys.h" #include "erl_vm.h" #include "erl_sys_driver.h" @@ -45,7 +49,10 @@ #include "erl_map.h" #include "erl_msacc.h" #include "erl_proc_sig_queue.h" +#include "erl_fun.h" +#include "ryu.h" #include "jit/beam_asm.h" +#include "erl_global_literals.h" #include "beam_load.h" Export *erts_await_result; @@ -129,8 +136,10 @@ BIF_RETTYPE link_1(BIF_ALIST_1) rlnk = erts_link_internal_create(ERTS_LNK_TYPE_PROC, BIF_P->common.id); - if (erts_proc_sig_send_link(BIF_P, BIF_ARG_1, rlnk)) + if (erts_proc_sig_send_link(&BIF_P->common, BIF_P->common.id, + BIF_ARG_1, rlnk)) { BIF_RET(am_true); + } erts_link_tree_delete(&ERTS_P_LINKS(BIF_P), lnk); erts_link_internal_release(lnk); @@ -251,8 +260,7 @@ BIF_RETTYPE link_1(BIF_ALIST_1) } erts_link_set_dead_dist(&elnk->ld.dist, dep->sysname); } - erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &elnk->ld.dist, - am_noconnection, NIL); + erts_proc_sig_send_link_exit_noconnection(&elnk->ld.dist); break; case ERTS_DSIG_PREP_PENDING: @@ -372,7 +380,6 @@ demonitor(Process *c_p, Eterm ref, Eterm *multip) } case ERTS_ML_STATE_ALIAS_ONCE: case ERTS_ML_STATE_ALIAS_DEMONITOR: - erts_pid_ref_delete(ref); /* fall through... */ default: erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p), mon); @@ -404,7 +411,7 @@ demonitor(Process *c_p, Eterm ref, Eterm *multip) } case ERTS_MON_TYPE_PROC: - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(&c_p->common, c_p->common.id, 0, mon); return am_true; case ERTS_MON_TYPE_DIST_PROC: { @@ -647,8 +654,10 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, erts_monitor_tree_insert(&ERTS_P_MONITORS(c_p), &mdp->origin); if (is_not_internal_pid(id) - || !erts_proc_sig_send_monitor(&mdp->u.target, id)) { - erts_proc_sig_send_monitor_down(&mdp->u.target, + || !erts_proc_sig_send_monitor(&c_p->common, c_p->common.id, + &mdp->u.target, id)) { + erts_proc_sig_send_monitor_down(NULL, id, + &mdp->u.target, am_noproc); } } @@ -674,7 +683,8 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, NIL, tag); mdp->origin.flags |= add_oflags; erts_monitor_tree_insert(&ERTS_P_MONITORS(c_p), &mdp->origin); - erts_proc_sig_send_monitor_down(&mdp->u.target, am_noproc); + erts_proc_sig_send_monitor_down(NULL, target, + &mdp->u.target, am_noproc); goto done; } @@ -696,7 +706,9 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, case ERTS_DSIG_PREP_NOT_ALIVE: case ERTS_DSIG_PREP_NOT_CONNECTED: erts_monitor_set_dead_dist(&mdp->u.target, dep->sysname); - erts_proc_sig_send_monitor_down(&mdp->u.target, am_noconnection); + erts_proc_sig_send_monitor_down(NULL, id, + &mdp->u.target, + am_noconnection); code = ERTS_DSIG_SEND_OK; break; @@ -730,7 +742,7 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, goto badarg; if (is_not_atom(tpl[1]) || is_not_atom(tpl[2])) goto badarg; - if (!erts_is_alive && tpl[2] != am_Noname) + if (tpl[2] != am_Noname && !erts_is_this_node_alive()) goto badarg; target = tpl[1]; dep = erts_find_or_insert_dist_entry(tpl[2]); @@ -760,8 +772,10 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, mdp->origin.flags |= add_oflags; erts_monitor_tree_insert(&ERTS_P_MONITORS(c_p), &mdp->origin); prt = erts_port_lookup(id, ERTS_PORT_SFLGS_INVALID_LOOKUP); - if (!prt || erts_port_monitor(c_p, prt, &mdp->u.target) == ERTS_PORT_OP_DROPPED) - erts_proc_sig_send_monitor_down(&mdp->u.target, am_noproc); + if (!prt || erts_port_monitor(c_p, prt, &mdp->u.target) == ERTS_PORT_OP_DROPPED) { + erts_proc_sig_send_monitor_down(prt ? &prt->common : NULL, id, + &mdp->u.target, am_noproc); + } goto done; } @@ -779,7 +793,7 @@ static BIF_RETTYPE monitor(Process *c_p, Eterm type, Eterm target, NIL, tag); mdp->origin.flags |= add_oflags; erts_monitor_tree_insert(&ERTS_P_MONITORS(c_p), &mdp->origin); - erts_proc_sig_send_monitor_down(&mdp->u.target, am_noproc); + erts_proc_sig_send_monitor_down(NULL, target, &mdp->u.target, am_noproc); goto done; } goto badarg; @@ -1062,7 +1076,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1) ilnk = (ErtsILink *) erts_link_tree_lookup(ERTS_P_LINKS(BIF_P), BIF_ARG_1); if (ilnk && !ilnk->unlinking) { - Uint64 id = erts_proc_sig_send_unlink(BIF_P, + Uint64 id = erts_proc_sig_send_unlink(&BIF_P->common, BIF_P->common.id, &ilnk->link); if (id) @@ -1095,7 +1109,8 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1) else { ErtsSigUnlinkOp *sulnk; - sulnk = erts_proc_sig_make_unlink_op(BIF_P, BIF_P->common.id); + sulnk = erts_proc_sig_make_unlink_op(&BIF_P->common, + BIF_P->common.id); ilnk->unlinking = sulnk->id; #ifdef DEBUG ref = NIL; @@ -1133,7 +1148,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1) if (elnk->unlinking) BIF_RET(am_true); - unlink_id = erts_proc_sig_new_unlink_id(BIF_P); + unlink_id = erts_proc_sig_new_unlink_id(&BIF_P->common); elnk->unlinking = unlink_id; code = erts_dsig_prepare(&ctx, dep, BIF_P, ERTS_PROC_LOCK_MAIN, @@ -1274,7 +1289,7 @@ BIF_RETTYPE error_3(BIF_ALIST_3) /**********************************************************************/ /* * This is like exactly like error/1. The only difference is - * that Dialyzer thinks that it it will return an arbitrary term. + * that Dialyzer thinks that it will return an arbitrary term. * It is useful in stub functions for NIFs. */ @@ -1287,7 +1302,7 @@ BIF_RETTYPE nif_error_1(BIF_ALIST_1) /**********************************************************************/ /* * This is like exactly like error/2. The only difference is - * that Dialyzer thinks that it it will return an arbitrary term. + * that Dialyzer thinks that it will return an arbitrary term. * It is useful in stub functions for NIFs. */ @@ -1357,7 +1372,7 @@ BIF_RETTYPE raise_3(BIF_ALIST_3) switch (arityval(tp[0])) { case 2: /* {Fun,Args} */ - if (is_fun(tp[1])) { + if (is_any_fun(tp[1])) { must_copy = 1; } else { goto error; @@ -1369,7 +1384,7 @@ BIF_RETTYPE raise_3(BIF_ALIST_3) * {Fun,Args,Location} * {M,F,A} */ - if (is_fun(tp[1])) { + if (is_any_fun(tp[1])) { location = tp[3]; } else if (is_atom(tp[1]) && is_atom(tp[2])) { must_copy = 1; @@ -1472,7 +1487,7 @@ erts_internal_await_exit_trap(BIF_ALIST_0) * terminated in order to ensure that signal order * is preserved. Yield if necessary. */ - erts_aint32_t state; + erts_aint32_t state = erts_atomic32_read_nob(&BIF_P->state); int reds = ERTS_BIF_REDS_LEFT(BIF_P); (void) erts_proc_sig_handle_incoming(BIF_P, &state, &reds, reds, !0); @@ -1507,7 +1522,7 @@ static BIF_RETTYPE send_exit_signal_bif(Process *c_p, Eterm id, Eterm reason, in && c_p->common.id == id && (reason == am_kill || !(c_p->flags & F_TRAP_EXIT))); - erts_proc_sig_send_exit(c_p, c_p->common.id, id, + erts_proc_sig_send_exit(&c_p->common, c_p->common.id, id, reason, NIL, exit2_suicide); if (!exit2_suicide) ERTS_BIF_PREP_RET(ret_val, am_true); @@ -1766,7 +1781,21 @@ static Eterm process_flag_aux(Process *c_p, int *redsp, Eterm flag, Eterm val) BIF_RETTYPE process_flag_2(BIF_ALIST_2) { Eterm old_value; - if (BIF_ARG_1 == am_error_handler) { + + if (BIF_ARG_1 == am_async_dist) { + old_value = (BIF_P->flags & F_ASYNC_DIST) ? am_true : am_false; + if (BIF_ARG_2 == am_false) { + BIF_P->flags &= ~F_ASYNC_DIST; + } + else if (BIF_ARG_2 == am_true) { + BIF_P->flags |= F_ASYNC_DIST; + } + else { + goto error; + } + BIF_RET(old_value); + } + else if (BIF_ARG_1 == am_error_handler) { if (is_not_atom(BIF_ARG_2)) { goto error; } @@ -1870,8 +1899,8 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) BIF_RET(old_value); } else if (BIF_ARG_1 == am_max_heap_size) { - Eterm *hp; - Uint sz = 0, max_heap_size, max_heap_flags; + ErtsHeapFactory factory; + Uint max_heap_size, max_heap_flags; if (!erts_max_heap_size(BIF_ARG_2, &max_heap_size, &max_heap_flags)) goto error; @@ -1879,9 +1908,11 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) if ((max_heap_size < MIN_HEAP_SIZE(BIF_P) && max_heap_size != 0)) goto error; - erts_max_heap_size_map(MAX_HEAP_SIZE_GET(BIF_P), MAX_HEAP_SIZE_FLAGS_GET(BIF_P), NULL, &sz); - hp = HAlloc(BIF_P, sz); - old_value = erts_max_heap_size_map(MAX_HEAP_SIZE_GET(BIF_P), MAX_HEAP_SIZE_FLAGS_GET(BIF_P), &hp, NULL); + erts_factory_proc_init(&factory, BIF_P); + old_value = erts_max_heap_size_map(&factory, + MAX_HEAP_SIZE_GET(BIF_P), + MAX_HEAP_SIZE_FLAGS_GET(BIF_P)); + erts_factory_close(&factory); MAX_HEAP_SIZE_SET(BIF_P, max_heap_size); MAX_HEAP_SIZE_FLAGS_SET(BIF_P, max_heap_flags); BIF_RET(old_value); @@ -2607,10 +2638,11 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) /**********************************************************************/ -/* returns the head of a list - this function is unecessary +/* returns the head of a list - this function is unnecessary and is only here to keep Robert happy (Even more, since it's OP as well) */ BIF_RETTYPE hd_1(BIF_ALIST_1) { + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_not_list(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } @@ -2623,6 +2655,7 @@ BIF_RETTYPE hd_1(BIF_ALIST_1) BIF_RETTYPE tl_1(BIF_ALIST_1) { + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_not_list(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } @@ -2899,6 +2932,7 @@ BIF_RETTYPE element_2(BIF_ALIST_2) BIF_RETTYPE tuple_size_1(BIF_ALIST_1) { + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_tuple(BIF_ARG_1)) { return make_small(arityval(*tuple_val(BIF_ARG_1))); } @@ -2948,6 +2982,9 @@ BIF_RETTYPE make_tuple_2(BIF_ALIST_2) if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0 || n > ERTS_MAX_TUPLE_SIZE) { BIF_ERROR(BIF_P, BADARG); } + if (n == 0) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } hp = HAlloc(BIF_P, n+1); res = make_tuple(hp); *hp++ = make_arityval(n); @@ -2964,17 +3001,21 @@ BIF_RETTYPE make_tuple_3(BIF_ALIST_3) Eterm* hp; Eterm res; Eterm list = BIF_ARG_3; - Eterm* tup; + Eterm* tup = NULL; if (is_not_small(BIF_ARG_1) || (n = signed_val(BIF_ARG_1)) < 0 || n > ERTS_MAX_TUPLE_SIZE) { error: BIF_ERROR(BIF_P, BADARG); } limit = (Uint) n; - hp = HAlloc(BIF_P, n+1); - res = make_tuple(hp); - *hp++ = make_arityval(n); - tup = hp; + if (n == 0) { + res = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + hp = HAlloc(BIF_P, n+1); + res = make_tuple(hp); + *hp++ = make_arityval(n); + tup = hp; + } while (n--) { *hp++ = BIF_ARG_2; } @@ -3091,6 +3132,10 @@ BIF_RETTYPE delete_element_2(BIF_ALIST_3) BIF_ERROR(BIF_P, BADARG); } + if (arity == 1) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } + hp = HAlloc(BIF_P, arity + 1 - 1); res = make_tuple(hp); *hp = make_arityval(arity - 1); @@ -3113,7 +3158,7 @@ BIF_RETTYPE atom_to_list_1(BIF_ALIST_1) { Atom* ap; Uint num_chars, num_built, num_eaten; - byte* err_pos; + const byte* err_pos; Eterm res; int ares; @@ -3145,8 +3190,8 @@ BIF_RETTYPE list_to_atom_1(BIF_ALIST_1) Eterm res; byte *buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_SZ_LIMIT); Sint written; - int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS, - &written); + int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_SZ_LIMIT, + MAX_ATOM_CHARACTERS, &written); if (i < 0) { erts_free(ERTS_ALC_T_TMP, (void *) buf); if (i == -2) { @@ -3166,8 +3211,8 @@ BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1) { byte *buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_SZ_LIMIT); Sint written; - int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS, - &written); + int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_SZ_LIMIT, + MAX_ATOM_CHARACTERS, &written); if (i < 0) { error: erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -3309,6 +3354,7 @@ static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list, int compact = 0; enum fmt_type_ { FMT_LEGACY, + FMT_SHORT, FMT_FIXED, FMT_SCIENTIFIC } fmt_type = FMT_LEGACY; @@ -3337,16 +3383,26 @@ static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list, continue; } } + } else if (arg == am_short) { + fmt_type = FMT_SHORT; + continue; } goto badarg; } + if (is_not_nil(list)) { goto badarg; } GET_DOUBLE(efloat, f); - if (fmt_type == FMT_FIXED) { + if (fmt_type == FMT_SHORT) { + const int index = d2s_buffered_n(f.fd, fbuf); + + /* Terminate the string. */ + fbuf[index] = '\0'; + return index; + } else if (fmt_type == FMT_FIXED) { return sys_double_to_chars_fast(f.fd, fbuf, sizeof_fbuf, decimals, compact); } else { @@ -3725,7 +3781,9 @@ BIF_RETTYPE list_to_tuple_1(BIF_ALIST_1) if ((len = erts_list_length(list)) < 0 || len > ERTS_MAX_TUPLE_SIZE) { BIF_ERROR(BIF_P, BADARG); } - + if (len == 0) { + BIF_RET(ERTS_GLOBAL_LIT_EMPTY_TUPLE); + } hp = HAlloc(BIF_P, len+1); res = make_tuple(hp); *hp++ = make_arityval(len); @@ -4056,52 +4114,150 @@ BIF_RETTYPE display_1(BIF_ALIST_1) } /* - * erts_debug:display/1 is for debugging erlang:display/1 + * erts_internal:term_to_string/2 is an internal and undocumented function for + * formatting terms during init or other times when io_lib is unavailable. + * It can also be used to debug functions that rely on the internal term + * printing such as erlang:display/1 */ -BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1) +BIF_RETTYPE erts_internal_term_to_string_2(BIF_ALIST_2) { + erts_dsprintf_buf_t *dsbufp; + int limit; int pres; Eterm res; Eterm *hp; - erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); - pres = erts_dsprintf(dsbufp, "%.*T\n", INT_MAX, BIF_ARG_1); - if (pres < 0) - erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to string: %d (%s)\n", - -pres, erl_errno_id(-pres)); - hp = HAlloc(BIF_P, 2*dsbufp->str_len); /* we need length * 2 heap words */ + + if (is_small(BIF_ARG_2) && + (signed_val(BIF_ARG_2) > 1 && + signed_val(BIF_ARG_2) < INT_MAX)) { + limit = signed_val(BIF_ARG_2); + } else if (BIF_ARG_2 == am_undefined) { + limit = INT_MAX; + } else { + BIF_ERROR(BIF_P, BADARG); + } + + dsbufp = erts_create_tmp_dsbuf(64); + pres = erts_dsprintf(dsbufp, "%.*T", limit, BIF_ARG_1); + + if (pres < 0) { + erts_exit(ERTS_ERROR_EXIT, + "Failed to convert term to string: %d (%s)\n", + -pres, + erl_errno_id(-pres)); + } + + hp = HAlloc(BIF_P, 2 * dsbufp->str_len); res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); - erts_printf("%s", dsbufp->str); + erts_destroy_tmp_dsbuf(dsbufp); + BIF_RET(res); } - -BIF_RETTYPE display_string_1(BIF_ALIST_1) +BIF_RETTYPE display_string_2(BIF_ALIST_2) { Process* p = BIF_P; - Eterm string = BIF_ARG_1; - Sint len = erts_unicode_list_to_buf_len(string); + Eterm string = BIF_ARG_2; + Sint len; Sint written; byte *str; int res; + byte *temp_alloc = NULL; - if (len < 0) { - BIF_ERROR(p, BADARG); +#ifdef __WIN32__ + HANDLE fd; + if (ERTS_IS_ATOM_STR("stdout", BIF_ARG_1)) { + fd = GetStdHandle(STD_OUTPUT_HANDLE); + } else if (ERTS_IS_ATOM_STR("stderr", BIF_ARG_1)) { + fd = GetStdHandle(STD_ERROR_HANDLE); + } +#else + int fd; + if (ERTS_IS_ATOM_STR("stdout", BIF_ARG_1)) { + fd = fileno(stdout); + } else if (ERTS_IS_ATOM_STR("stderr", BIF_ARG_1)) { + fd = fileno(stderr); + } +#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSTI) + else if (ERTS_IS_ATOM_STR("stdin", BIF_ARG_1)) { + const char stdin_fname[] = "/dev/tty"; + fd = open(stdin_fname,0); + if (fd < 0) { + fprintf(stderr,"failed to open %s (%s)\r\n", stdin_fname, + strerror(errno)); + goto error; + } + } +#endif +#endif + else { + BIF_ERROR(p, BADARG); + } + if (is_list(string) || is_nil(string)) { + len = erts_unicode_list_to_buf_len(string); + if (len < 0) BIF_ERROR(p, BADARG); + str = temp_alloc = (byte *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*len); + res = erts_unicode_list_to_buf(string, str, len, len, &written); + if (res != 0 || written != len) + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error (%d)\n", __FILE__, __LINE__, res); + } else if (is_binary(string)) { + Uint bitoffs, bitsize; + ERTS_GET_BINARY_BYTES(string, str, bitoffs, bitsize); + if (bitsize % 8 != 0) BIF_ERROR(p, BADARG); + len = binary_size(string); + if (bitoffs != 0) { + str = erts_get_aligned_binary_bytes(string, &temp_alloc); + } + } else { + BIF_ERROR(p, BADARG); } - str = (byte *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*(len + 1)); - res = erts_unicode_list_to_buf(string, str, len, &written); - if (res != 0 || written != len) - erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error (%d)\n", __FILE__, __LINE__, res); - str[len] = '\0'; - erts_fprintf(stderr, "%s", str); - erts_free(ERTS_ALC_T_TMP, (void *) str); - BIF_RET(am_true); -} -BIF_RETTYPE display_nl_0(BIF_ALIST_0) -{ - erts_fprintf(stderr, "\n"); +#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSTI) + if (ERTS_IS_ATOM_STR("stdin", BIF_ARG_1)) { + for (int i = 0; i < len; i++) { + if (ioctl(fd, TIOCSTI, str+i) < 0) { + fprintf(stderr,"failed to write to %s (%s)\r\n", "/proc/self/fd/0", + strerror(errno)); + close(fd); + goto error; + } + } + close(fd); + } else +#endif + { +#ifdef __WIN32__ + Uint32 w; + if (!WriteFile(fd, str, len, &w, NULL)) { + goto error; + } + written = (Sint)w; +#else + written = 0; + do { + res = write(fd, str+written, len-written); + if (res < 0 && errno != ERRNO_BLOCK && errno != EINTR) + goto error; + written += res; + } while (written < len); +#endif + } + if (temp_alloc) + erts_free(ERTS_ALC_T_TMP, (void *) temp_alloc); BIF_RET(am_true); + +error: { +#ifdef __WIN32__ + char *errnostr = last_error(); +#else + char *errnostr = erl_errno_id(errno); +#endif + BIF_P->fvalue = am_atom_put(errnostr, strlen(errnostr)); + if (temp_alloc) + erts_free(ERTS_ALC_T_TMP, (void *) temp_alloc); + BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO); + } } /**********************************************************************/ @@ -4169,8 +4325,8 @@ BIF_RETTYPE halt_2(BIF_ALIST_2) static byte halt_msg[4*HALT_MSG_SIZE+1]; Sint written; - if (erts_unicode_list_to_buf(BIF_ARG_1, halt_msg, HALT_MSG_SIZE, - &written) == -1 ) { + if (erts_unicode_list_to_buf(BIF_ARG_1, halt_msg, 4 * HALT_MSG_SIZE, + HALT_MSG_SIZE, &written) == -1 ) { goto error; } ASSERT(written >= 0 && written < sizeof(halt_msg)); @@ -4261,21 +4417,28 @@ BIF_RETTYPE ref_to_list_1(BIF_ALIST_1) BIF_RETTYPE make_fun_3(BIF_ALIST_3) { - Eterm* hp; + ErlFunThing *funp; + Eterm *hp; + Export *ep; Sint arity; - if (is_not_atom(BIF_ARG_1) || is_not_atom(BIF_ARG_2) || is_not_small(BIF_ARG_3)) { - error: - BIF_ERROR(BIF_P, BADARG); + if (is_not_atom(BIF_ARG_1) || + is_not_atom(BIF_ARG_2) || + is_not_small(BIF_ARG_3)) { + BIF_ERROR(BIF_P, BADARG); } + arity = signed_val(BIF_ARG_3); - if (arity < 0) { - goto error; + if (arity < 0 || arity > MAX_ARG) { + BIF_ERROR(BIF_P, BADARG); } - hp = HAlloc(BIF_P, 2); - hp[0] = HEADER_EXPORT; - hp[1] = (Eterm) erts_export_get_or_make_stub(BIF_ARG_1, BIF_ARG_2, (Uint) arity); - BIF_RET(make_export(hp)); + + hp = HAlloc(BIF_P, ERL_FUN_SIZE); + + ep = erts_export_get_or_make_stub(BIF_ARG_1, BIF_ARG_2, (Uint) arity); + funp = erts_new_export_fun_thing(&hp, ep, arity); + + BIF_RET(make_fun(funp)); } BIF_RETTYPE fun_to_list_1(BIF_ALIST_1) @@ -4283,8 +4446,10 @@ BIF_RETTYPE fun_to_list_1(BIF_ALIST_1) Process* p = BIF_P; Eterm fun = BIF_ARG_1; - if (is_not_any_fun(fun)) - BIF_ERROR(p, BADARG); + if (is_not_any_fun(fun)) { + BIF_ERROR(p, BADARG); + } + BIF_RET(term2list_dsprintf(p, fun)); } @@ -4310,7 +4475,7 @@ BIF_RETTYPE port_to_list_1(BIF_ALIST_1) /**********************************************************************/ -/* convert a list of ascii characeters of the form +/* convert a list of ascii characters of the form to a PID */ @@ -4559,7 +4724,7 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1) ErtsMagicBinary *mb; Uint32 sid; if (refn[0] >= MAX_REFERENCE) goto bad; - if (n != ERTS_REF_NUMBERS) goto bad; + if (n != ERTS_REF_NUMBERS && n != ERTS_PID_REF_NUMBERS) goto bad; sid = erts_get_ref_numbers_thr_id(refn); if (sid > erts_no_schedulers) goto bad; if (erts_is_ordinary_ref_numbers(refn)) { @@ -4570,12 +4735,15 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1) } else { /* Check if it is a pid reference... */ - Eterm pid = erts_pid_ref_lookup(refn); + Eterm pid = erts_pid_ref_lookup(refn, n); if (is_internal_pid(pid)) { hp = HAlloc(BIF_P, ERTS_PID_REF_THING_SIZE); write_pid_ref_thing(hp, refn[0], refn[1], refn[2], pid); res = make_internal_ref(hp); } + else if (is_non_value(pid)) { + goto bad; + } else { /* Check if it is a magic reference... */ mb = erts_magic_ref_lookup_bin(refn); @@ -4868,9 +5036,9 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) BIF_RET(make_small(oval)); } else if (BIF_ARG_1 == am_max_heap_size) { - - Eterm *hp, old_value; - Uint sz = 0, max_heap_size, max_heap_flags; + ErtsHeapFactory factory; + Eterm old_value; + Uint max_heap_size, max_heap_flags; if (!erts_max_heap_size(BIF_ARG_2, &max_heap_size, &max_heap_flags)) goto error; @@ -4878,9 +5046,9 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) if (max_heap_size < H_MIN_SIZE && max_heap_size != 0) goto error; - erts_max_heap_size_map(H_MAX_SIZE, H_MAX_FLAGS, NULL, &sz); - hp = HAlloc(BIF_P, sz); - old_value = erts_max_heap_size_map(H_MAX_SIZE, H_MAX_FLAGS, &hp, NULL); + erts_factory_proc_init(&factory, BIF_P); + old_value = erts_max_heap_size_map(&factory, H_MAX_SIZE, H_MAX_FLAGS); + erts_factory_close(&factory); erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_thr_progress_block(); @@ -5239,45 +5407,52 @@ static BIF_RETTYPE bif_return_trap(BIF_ALIST_2) } static BIF_RETTYPE -bif_handle_signals_return(BIF_ALIST_1) +bif_handle_signals_return(BIF_ALIST_2) { - int local_only = BIF_P->sig_qs.flags & FS_LOCAL_SIGS_ONLY; - int sres, sreds, reds_left; + int reds_left; erts_aint32_t state; - reds_left = ERTS_BIF_REDS_LEFT(BIF_P); - sreds = reds_left; - - if (!local_only) { - erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(BIF_P); - erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MSGQ); + if (BIF_P->sig_qs.flags & FS_FLUSHED_SIGS) { + flushed: + ASSERT(BIF_P->sig_qs.flags & FS_FLUSHING_SIGS); + BIF_P->sig_qs.flags &= ~(FS_FLUSHED_SIGS|FS_FLUSHING_SIGS); + erts_set_gc_state(BIF_P, !0); /* Allow GC again... */ + BIF_RET(BIF_ARG_2); } + + if (!(BIF_P->sig_qs.flags & FS_FLUSHING_SIGS)) { + int flags = ((is_internal_pid(BIF_ARG_1) + || is_internal_port(BIF_ARG_1)) + ? ERTS_PROC_SIG_FLUSH_FLG_FROM_ID + : ERTS_PROC_SIG_FLUSH_FLG_FROM_ALL); + erts_proc_sig_init_flush_signals(BIF_P, flags, BIF_ARG_1); + if (BIF_P->sig_qs.flags & FS_FLUSHED_SIGS) + goto flushed; + } + + ASSERT(BIF_P->sig_qs.flags & FS_FLUSHING_SIGS); - state = erts_atomic32_read_nob(&BIF_P->state); - sres = erts_proc_sig_handle_incoming(BIF_P, &state, &sreds, - sreds, !0); - - BUMP_REDS(BIF_P, (int) sreds); - reds_left -= sreds; + reds_left = ERTS_BIF_REDS_LEFT(BIF_P); - if (state & ERTS_PSFLG_EXITING) { - BIF_P->sig_qs.flags &= ~FS_LOCAL_SIGS_ONLY; - ERTS_BIF_EXITED(BIF_P); - } - if (!sres | (reds_left <= 0)) { - /* - * More signals to handle or out of reds; need - * to yield and continue. Prevent fetching of - * more signals by setting local-sigs-only flag. - */ - BIF_P->sig_qs.flags |= FS_LOCAL_SIGS_ONLY; - ERTS_BIF_YIELD1(&erts_bif_handle_signals_return_export, - BIF_P, BIF_ARG_1); - } + state = erts_atomic32_read_nob(&BIF_P->state); + do { + int sreds = reds_left; + (void) erts_proc_sig_handle_incoming(BIF_P, &state, &sreds, + sreds, !0); + BUMP_REDS(BIF_P, (int) sreds); + if (state & ERTS_PSFLG_EXITING) + ERTS_BIF_EXITED(BIF_P); + if (BIF_P->sig_qs.flags & FS_FLUSHED_SIGS) + goto flushed; + reds_left -= sreds; + } while (reds_left > 0); - BIF_P->sig_qs.flags &= ~FS_LOCAL_SIGS_ONLY; - BIF_RET(BIF_ARG_1); + /* + * More signals to handle, but out of reductions. Yield + * and come back here and continue... + */ + ERTS_BIF_YIELD2(&erts_bif_handle_signals_return_export, + BIF_P, BIF_ARG_1, BIF_ARG_2); } Export bif_return_trap_export; @@ -5295,11 +5470,10 @@ void erts_init_trap_export(Export *ep, Eterm m, Eterm f, Uint a, } #ifdef BEAMASM - ep->addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls; + ep->dispatch.addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls_export; #endif ep->bif_number = -1; - ep->info.op = op_i_func_info_IaaI; ep->info.mfa.module = m; ep->info.mfa.function = f; ep->info.mfa.arity = a; @@ -5319,7 +5493,7 @@ void erts_init_bif(void) &bif_return_trap); erts_init_trap_export(&erts_bif_handle_signals_return_export, - am_erlang, am_bif_handle_signals_return, 1, + am_erlang, am_bif_handle_signals_return, 2, &bif_handle_signals_return); erts_await_result = erts_export_put(am_erts_internal, @@ -5378,11 +5552,7 @@ schedule(Process *c_p, Process *dirty_shadow_proc, ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(c_p)); (void) erts_nfunc_schedule(c_p, dirty_shadow_proc, mfa, pc, -#ifdef BEAMASM - op_call_bif_W, -#else BeamOpCodeAddr(op_call_bif_W), -#endif dfunc, ifunc, module, function, argc, argv); @@ -5690,8 +5860,6 @@ BIF_RETTYPE unalias_1(BIF_ALIST_1) ASSERT(erts_monitor_is_origin(mon)); - erts_pid_ref_delete(BIF_ARG_1); - mon->flags &= ~ERTS_ML_STATE_ALIAS_MASK; if (mon->type == ERTS_MON_TYPE_ALIAS) { erts_monitor_tree_delete(&ERTS_P_MONITORS(BIF_P), mon); diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index 0bbe059887c9..59370c498b13 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -327,7 +327,7 @@ extern ErtsCodePtr beam_bif_export_trap; #define ERTS_BIF_PREP_TRAP(Export, Proc, Arity) \ do { \ - (Proc)->i = (Export)->addresses[erts_active_code_ix()]; \ + (Proc)->i = (Export)->dispatch.addresses[erts_active_code_ix()]; \ (Proc)->arity = (Arity); \ (Proc)->freason = TRAP; \ } while(0); @@ -522,23 +522,23 @@ do { \ extern Export erts_bif_handle_signals_return_export; -#define ERTS_BIF_HANDLE_SIGNALS_RETURN(P, VAL) \ - BIF_TRAP1(&erts_bif_handle_signals_return_export, (P), (VAL)) +#define ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(P, FROM, VAL) \ + BIF_TRAP2(&erts_bif_handle_signals_return_export, (P), (FROM), (VAL)) -#define ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(Ret, P, Val) \ - ERTS_BIF_PREP_TRAP1((Ret), &erts_bif_handle_signals_return_export, \ - (P), (Val)) +#define ERTS_BIF_PREP_HANDLE_SIGNALS_FROM_RETURN(Ret, P, From, Val) \ + ERTS_BIF_PREP_TRAP2((Ret), &erts_bif_handle_signals_return_export, \ + (P), (From), (Val)) #define ERTS_BIF_PREP_EXITED(RET, PROC) \ do { \ KILL_CATCHES((PROC)); \ - ERTS_BIF_PREP_ERROR((RET), (PROC), EXTAG_EXIT); \ + ERTS_BIF_PREP_ERROR((RET), (PROC), EXTAG_EXIT | EXF_PANIC); \ } while (0) -#define ERTS_BIF_EXITED(PROC) \ -do { \ - KILL_CATCHES((PROC)); \ - BIF_ERROR((PROC), EXTAG_EXIT); \ +#define ERTS_BIF_EXITED(PROC) \ +do { \ + KILL_CATCHES((PROC)); \ + BIF_ERROR((PROC), EXTAG_EXIT | EXF_PANIC); \ } while (0) #define ERTS_BIF_CHK_EXITED(PROC) \ diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 4e1e92a8d64b..6d2343050693 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -56,8 +56,7 @@ bif erlang:crc32_combine/3 bif erlang:date/0 bif erlang:delete_module/1 bif erlang:display/1 -bif erlang:display_string/1 -bif erlang:display_nl/0 +bif erlang:display_string/2 ubif erlang:element/2 bif erlang:erase/0 hbif erlang:erase/1 @@ -83,7 +82,6 @@ bif erlang:phash2/1 bif erlang:phash2/2 ubif erlang:hd/1 bif erlang:integer_to_list/1 -bif erlang:is_alive/0 ubif erlang:length/1 bif erlang:link/1 bif erlang:list_to_atom/1 @@ -109,7 +107,9 @@ bif erlang:monitor_node/2 bif erlang:monitor_node/3 ubif erlang:node/1 ubif erlang:node/0 +bif erlang:nodes/0 bif erlang:nodes/1 +bif erlang:nodes/2 bif erlang:now/0 bif erlang:monotonic_time/0 bif erlang:monotonic_time/1 @@ -360,6 +360,7 @@ bif ets:first/1 bif ets:is_compiled_ms/1 bif ets:lookup/2 bif ets:lookup_element/3 +bif ets:lookup_element/4 bif ets:info/1 bif ets:info/2 bif ets:last/1 @@ -444,7 +445,6 @@ bif erts_debug:same/2 bif erts_debug:flat_size/1 bif erts_debug:get_internal_state/1 bif erts_debug:set_internal_state/2 -bif erts_debug:display/1 bif erts_debug:dist_ext_to_term/2 bif erts_debug:instructions/0 bif erts_debug:interpreter_size/0 @@ -776,3 +776,10 @@ bif maps:from_keys/2 # New in 24 (in a patch) bif erts_internal:binary_to_integer/2 bif erts_internal:list_to_integer/2 + +# +# New in 26 +# +ubif erlang:min/2 +ubif erlang:max/2 +bif erts_internal:term_to_string/2 diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index b5c6703dee75..3c5a2bed4be0 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -609,7 +609,7 @@ static dsize_t Z_sub(ErtsDigit* y, dsize_t yl, ErtsDigit* r) /* ** Multiply digits in x with digits in y and store in r -** Assumption: digits in r must be 0 (upto the size of x) +** Assumption: digits in r must be 0 (up to the size of x) */ static dsize_t I_mul(ErtsDigit* x, dsize_t xl, ErtsDigit* y, dsize_t yl, ErtsDigit* r) { @@ -1162,7 +1162,7 @@ static ErtsDigit D_rem(ErtsDigit* x, dsize_t xl, ErtsDigit d) /* ** Remainder of x and y ** -** Assumtions: xl >= yl, yl > 1 +** Assumptions: xl >= yl, yl > 1 ** r must contain at least xl number of digits */ static dsize_t I_rem(ErtsDigit* x, dsize_t xl, ErtsDigit* y, dsize_t yl, ErtsDigit* r) @@ -1661,6 +1661,18 @@ erts_make_integer(Uint x, Process *p) return uint_to_big(x,hp); } } + +Eterm +erts_make_integer_fact(Uint x, ErtsHeapFactory *hf) +{ + Eterm* hp; + if (IS_USMALL(0,x)) + return make_small(x); + else { + hp = erts_produce_heap(hf, BIG_UINT_HEAP_SIZE, 0); + return uint_to_big(x, hp); + } +} /* * As erts_make_integer, but from a whole UWord. */ @@ -2790,7 +2802,7 @@ int term_equals_2pow32(Eterm x) if (!is_big(x)) return 0; bp = big_val(x); -#if D_EXP == 16 /* 16 bit platfrom not really supported!!! */ +#if D_EXP == 16 /* 16 bit platform not really supported!!! */ return (BIG_SIZE(bp) == 3) && !BIG_DIGIT(bp,0) && !BIG_DIGIT(bp,1) && BIG_DIGIT(bp,2) == 1; #elif D_EXP == 32 diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index f20a137a09e2..ceb35a84b83f 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -159,6 +159,7 @@ Eterm small_to_big(Sint, Eterm*); Eterm uint_to_big(Uint, Eterm*); Eterm uword_to_big(UWord, Eterm*); Eterm erts_make_integer(Uint, Process *); +Eterm erts_make_integer_fact(Uint, ErtsHeapFactory *); Eterm erts_make_integer_from_uword(UWord x, Process *p); dsize_t big_bytes(Eterm); diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index c23cc54c4c00..27eabb2d6f51 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -241,7 +241,7 @@ erts_get_aligned_binary_bytes_extra(Eterm bin, byte** base_ptr, ErtsAlcType_t al } Eterm -erts_bin_bytes_to_list(Eterm previous, Eterm* hp, byte* bytes, Uint size, Uint bitoffs) +erts_bin_bytes_to_list(Eterm previous, Eterm* hp, const byte* bytes, Uint size, Uint bitoffs) { if (bitoffs == 0) { while (size) { @@ -939,7 +939,7 @@ BIF_RETTYPE erts_list_to_binary_bif(Process *c_p, Eterm arg, Export *bif) break; /* done */ } if (!ERTS_IOLIST_TO_BUF_FAILED(res)) - ERTS_INTERNAL_ERROR("iolist_size/iolist_to_buf missmatch"); + ERTS_INTERNAL_ERROR("iolist_size/iolist_to_buf mismatch"); if (res == ERTS_IOLIST_TO_BUF_OVERFLOW) goto overflow; goto type_error; @@ -1049,7 +1049,7 @@ BIF_RETTYPE list_to_bitstring_1(BIF_ALIST_1) break; /* done */ } if (!ERTS_IOLIST_TO_BUF_FAILED(res)) - ERTS_INTERNAL_ERROR("iolist_size/iolist_to_buf missmatch"); + ERTS_INTERNAL_ERROR("iolist_size/iolist_to_buf mismatch"); if (res == ERTS_IOLIST_TO_BUF_OVERFLOW) goto overflow; goto type_error; diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index b1b0ed69718e..9efc79748175 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -134,12 +134,19 @@ process_killer(void) if ((j = sys_get_key(0)) <= 0) erts_exit(0, ""); switch(j) { - case 'k': + case 'k': + { + Process *init_proc; + ASSERT(erts_init_process_id != ERTS_INVALID_PID); + init_proc = erts_proc_lookup_raw(erts_init_process_id); + /* Send a 'kill' exit signal from init process */ - erts_proc_sig_send_exit(NULL, erts_init_process_id, - rp->common.id, am_kill, NIL, - 0); + erts_proc_sig_send_exit(&init_proc->common, + erts_init_process_id, + rp->common.id, + am_kill, NIL, 0); + } case 'n': br = 1; break; case 'r': return; default: return; @@ -301,7 +308,8 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock p->current->arity); } - erts_print(to, to_arg, "Spawned by: %T\n", p->parent); + erts_print(to, to_arg, "Spawned by: %T\n", + p->parent == am_undefined ? NIL : p->parent); if (locks & ERTS_PROC_LOCK_MAIN) { erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); @@ -393,12 +401,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock erts_print(to, to_arg, "OldHeap unused: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) ); erts_print(to, to_arg, "BinVHeap: %b64u\n", p->off_heap.overhead); - erts_print(to, to_arg, "OldBinVHeap: %b64u\n", BIN_OLD_VHEAP(p)); + erts_print(to, to_arg, "OldBinVHeap: %b64u\n", p->bin_old_vheap); erts_print(to, to_arg, "BinVHeap unused: %b64u\n", - BIN_VHEAP_SZ(p) - p->off_heap.overhead); - if (BIN_OLD_VHEAP_SZ(p) >= BIN_OLD_VHEAP(p)) { + p->bin_vheap_sz - p->off_heap.overhead); + if (p->bin_old_vheap_sz >= p->bin_old_vheap) { erts_print(to, to_arg, "OldBinVHeap unused: %b64u\n", - BIN_OLD_VHEAP_SZ(p) - BIN_OLD_VHEAP(p)); + p->bin_old_vheap_sz - p->bin_old_vheap); } else { erts_print(to, to_arg, "OldBinVHeap unused: overflow\n"); } @@ -568,19 +576,29 @@ do_break(void) " (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution\n"; int i; #ifdef __WIN32__ + char *clearscreen = "\033[J"; char *mode; /* enough for storing "window" */ /* check if we're in console mode and, if so, halt immediately if break is called */ mode = erts_read_env("ERL_CONSOLE_MODE"); - if (mode && sys_strcmp(mode, "window") != 0) + if (mode && sys_strcmp(mode, "detached") == 0) erts_exit(0, ""); erts_free_read_env(mode); -#endif /* __WIN32__ */ +#else + char *clearscreen = "\E[J"; +#endif ASSERT(erts_thr_progress_is_blocking()); - erts_printf("\n%s", helpstring); + /* If we are writing to something known to be a tty we clear the screen + after doing newline as the shell tab completion may have written + things there. */ + if (!isatty(fileno(stdin)) || !isatty(fileno(stdout))) { + clearscreen = ""; + } + + erts_printf("\n%s%s", clearscreen, helpstring); while (1) { if ((i = sys_get_key(0)) <= 0) @@ -706,25 +724,35 @@ bin_check(void) { Process *rp; struct erl_off_heap_header* hdr; + struct erl_off_heap_header* oh_list; int i, printed = 0, max = erts_ptab_max(&erts_proc); + for (i=0; i < max; i++) { rp = erts_pix2proc(i); if (!rp) continue; - for (hdr = rp->off_heap.first; hdr; hdr = hdr->next) { - if (hdr->thing_word == HEADER_PROC_BIN) { - ProcBin *bp = (ProcBin*) hdr; - if (!printed) { - erts_printf("Process %T holding binary data \n", rp->common.id); - printed = 1; - } - erts_printf("%p orig_size: %bpd, norefs = %bpd\n", - bp->val, - bp->val->orig_size, - erts_refc_read(&bp->val->intern.refc, 1)); - } - } + + oh_list = rp->off_heap.first; + for (;;) { + for (hdr = oh_list; hdr; hdr = hdr->next) { + if (hdr->thing_word == HEADER_PROC_BIN) { + ProcBin *bp = (ProcBin*) hdr; + if (!printed) { + erts_printf("Process %T holding binary data \n", rp->common.id); + printed = 1; + } + erts_printf("%p orig_size: %bpd, norefs = %bpd\n", + bp->val, + bp->val->orig_size, + erts_refc_read(&bp->val->intern.refc, 1)); + } + } + if (oh_list == rp->wrt_bins) + break; + oh_list = rp->wrt_bins; + } + if (printed) { erts_printf("--------------------------------------\n"); printed = 0; @@ -763,7 +791,7 @@ crash_dump_limited_writer(void* vfdp, char* buf, size_t len) } /* We assume that crash dump was called from erts_exit_vv() */ - erts_exit_epilogue(); + erts_exit_epilogue(0); } /* XXX THIS SHOULD BE IN SYSTEM !!!! */ diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index d1159dd144cb..d9fd133707ae 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2021. All Rights Reserved. + * Copyright Ericsson AB 2012-2023. 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. @@ -34,22 +34,39 @@ # define CIX_TRACE(text) #endif +#if defined(BEAMASM) && defined(ERTS_THR_INSTRUCTION_BARRIER) +# define CODE_IX_ISSUE_INSTRUCTION_BARRIERS +#endif + +/* If we need to issue a code barrier when thread progress is blocked, we use + * this counter to signal all managed threads to execute an instruction barrier + * when thread progress is unblocked. */ +erts_atomic32_t outstanding_blocking_code_barriers; + erts_atomic32_t the_active_code_index; erts_atomic32_t the_staging_code_index; -static int code_writing_seized = 0; -static Process* code_writing_process = NULL; -struct code_write_queue_item { - Process *p; - void (*aux_func)(void *); - void *aux_arg; - struct code_write_queue_item* next; +struct code_permission { + erts_mtx_t lock; + + ErtsSchedulerData *scheduler; + Process *owner; + + int seized; + struct code_permission_queue_item { + Process *p; + void (*aux_func)(void *); + void *aux_arg; + + struct code_permission_queue_item *next; + } *queue; }; -static struct code_write_queue_item* code_write_queue = NULL; -static erts_mtx_t code_write_permission_mtx; -#ifdef ERTS_ENABLE_LOCK_CHECK -static erts_tsd_key_t has_code_write_permission; +static struct code_permission code_mod_permission = {0}; +static struct code_permission code_stage_permission = {0}; + +#ifdef DEBUG +static erts_tsd_key_t needs_code_barrier; #endif void erts_code_ix_init(void) @@ -58,13 +75,20 @@ void erts_code_ix_init(void) * single threaded with active and staging set both to zero. * Preloading is finished by a commit that will set things straight. */ + erts_atomic32_init_nob(&outstanding_blocking_code_barriers, 0); erts_atomic32_init_nob(&the_active_code_index, 0); erts_atomic32_init_nob(&the_staging_code_index, 0); - erts_mtx_init(&code_write_permission_mtx, "code_write_permission", NIL, + + erts_mtx_init(&code_mod_permission.lock, + "code_mod_permission", NIL, ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC); -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_tsd_key_create(&has_code_write_permission, - "erts_has_code_write_permission"); + erts_mtx_init(&code_stage_permission.lock, + "code_stage_permission", NIL, + ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC); + +#ifdef DEBUG + erts_tsd_key_create(&needs_code_barrier, + "erts_needs_code_barrier"); #endif CIX_TRACE("init"); } @@ -72,16 +96,17 @@ void erts_code_ix_init(void) void erts_start_staging_code_ix(int num_new) { beam_catches_start_staging(); + erts_fun_start_staging(); export_start_staging(); module_start_staging(); erts_start_staging_ranges(num_new); CIX_TRACE("start"); } - void erts_end_staging_code_ix(void) { beam_catches_end_staging(1); + erts_fun_end_staging(1); export_end_staging(1); module_end_staging(1); erts_end_staging_ranges(1); @@ -105,121 +130,367 @@ void erts_commit_staging_code_ix(void) void erts_abort_staging_code_ix(void) { beam_catches_end_staging(0); + erts_fun_end_staging(0); export_end_staging(0); module_end_staging(0); erts_end_staging_ranges(0); CIX_TRACE("abort"); } -static int try_seize_cwp(Process* c_p, - void (*aux_func)(void *), - void *aux_arg); - #if defined(DEBUG) || defined(ADDRESS_SANITIZER) # define CWP_DBG_FORCE_TRAP #endif -/* - * Calller _must_ yield if we return 0 - */ -int erts_try_seize_code_write_permission(Process* c_p) -{ - ASSERT(c_p != NULL); - -#ifdef CWP_DBG_FORCE_TRAP - if (!(c_p->flags & F_DBG_FORCED_TRAP)) { - c_p->flags |= F_DBG_FORCED_TRAP; - return 0; - } else { - /* back from forced trap */ - c_p->flags &= ~F_DBG_FORCED_TRAP; - } +#ifdef ERTS_ENABLE_LOCK_CHECK +static int has_code_permission(struct code_permission *lock); #endif - return try_seize_cwp(c_p, NULL, NULL); -} - -int erts_try_seize_code_write_permission_aux(void (*aux_func)(void *), - void *aux_arg) -{ - ASSERT(aux_func != NULL); - return try_seize_cwp(NULL, aux_func, aux_arg); -} - -static int try_seize_cwp(Process* c_p, - void (*aux_func)(void *), - void *aux_arg) +static int try_seize_code_permission(struct code_permission *perm, + Process* c_p, + void (*aux_func)(void *), + void *aux_arg) { int success; - ASSERT(!erts_thr_progress_is_blocking()); /* to avoid deadlock */ - erts_mtx_lock(&code_write_permission_mtx); - success = !code_writing_seized; + ASSERT(!erts_thr_progress_is_blocking()); /* To avoid deadlock */ + + erts_mtx_lock(&perm->lock); + success = !perm->seized; + if (success) { - code_writing_seized = 1; - code_writing_process = c_p; -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_tsd_set(has_code_write_permission, (void *) 1); -#endif - } - else { /* Already locked */ - struct code_write_queue_item* qitem; + if (c_p == NULL) { + ASSERT(aux_func); + perm->scheduler = erts_get_scheduler_data(); + } + + perm->owner = c_p; + perm->seized = 1; + } else { /* Already locked */ + struct code_permission_queue_item* qitem; + qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem)); if (c_p) { - ASSERT(code_writing_process != c_p); + ERTS_LC_ASSERT(perm->owner != c_p); + qitem->p = c_p; qitem->aux_func = NULL; qitem->aux_arg = NULL; erts_proc_inc_refc(c_p); erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); - } - else { + } else { qitem->p = NULL; qitem->aux_func = aux_func; qitem->aux_arg = aux_arg; } - qitem->next = code_write_queue; - code_write_queue = qitem; + + qitem->next = perm->queue; + perm->queue = qitem; } - erts_mtx_unlock(&code_write_permission_mtx); - return success; + + erts_mtx_unlock(&perm->lock); + + return success; } -void erts_release_code_write_permission(void) -{ - erts_mtx_lock(&code_write_permission_mtx); - ERTS_LC_ASSERT(erts_has_code_write_permission()); - while (code_write_queue != NULL) { /* unleash the entire herd */ - struct code_write_queue_item* qitem = code_write_queue; +static void release_code_permission(struct code_permission *perm) { + ERTS_LC_ASSERT(has_code_permission(perm)); + + erts_mtx_lock(&perm->lock); + + /* Unleash the entire herd */ + while (perm->queue != NULL) { + struct code_permission_queue_item* qitem = perm->queue; + if (qitem->p) { erts_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(qitem->p)) { erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS); } + erts_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS); erts_proc_dec_refc(qitem->p); - } - else { /* aux work*/ + } else { /* aux work */ ErtsSchedulerData *esdp = erts_get_scheduler_data(); ASSERT(esdp && esdp->type == ERTS_SCHED_NORMAL); erts_schedule_misc_aux_work((int) esdp->no, qitem->aux_func, qitem->aux_arg); } - code_write_queue = qitem->next; - erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + + perm->queue = qitem->next; + erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + } + + perm->scheduler = NULL; + perm->owner = NULL; + perm->seized = 0; + + erts_mtx_unlock(&perm->lock); +} + +int erts_try_seize_code_mod_permission_aux(void (*aux_func)(void *), + void *aux_arg) +{ + ASSERT(aux_func != NULL); + return try_seize_code_permission(&code_mod_permission, NULL, + aux_func, aux_arg); +} + +int erts_try_seize_code_mod_permission(Process* c_p) +{ + ASSERT(c_p != NULL); + +#ifdef CWP_DBG_FORCE_TRAP + if (!(c_p->flags & F_DBG_FORCED_TRAP)) { + c_p->flags |= F_DBG_FORCED_TRAP; + return 0; + } else { + /* back from forced trap */ + c_p->flags &= ~F_DBG_FORCED_TRAP; + } +#endif + + return try_seize_code_permission(&code_mod_permission, c_p, NULL, NULL); +} + +void erts_release_code_mod_permission(void) +{ + release_code_permission(&code_mod_permission); +} + +int erts_try_seize_code_stage_permission(Process* c_p) +{ + ASSERT(c_p != NULL); + +#ifdef CWP_DBG_FORCE_TRAP + if (!(c_p->flags & F_DBG_FORCED_TRAP)) { + c_p->flags |= F_DBG_FORCED_TRAP; + return 0; + } else { + /* back from forced trap */ + c_p->flags &= ~F_DBG_FORCED_TRAP; } - code_writing_seized = 0; - code_writing_process = NULL; -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_tsd_set(has_code_write_permission, (void *) 0); #endif - erts_mtx_unlock(&code_write_permission_mtx); + + return try_seize_code_permission(&code_stage_permission, c_p, NULL, NULL); +} + +void erts_release_code_stage_permission(void) { + release_code_permission(&code_stage_permission); +} + +int erts_try_seize_code_load_permission(Process* c_p) { + ASSERT(c_p != NULL); + +#ifdef CWP_DBG_FORCE_TRAP + if (!(c_p->flags & F_DBG_FORCED_TRAP)) { + c_p->flags |= F_DBG_FORCED_TRAP; + return 0; + } else { + /* back from forced trap */ + c_p->flags &= ~F_DBG_FORCED_TRAP; + } +#endif + + if (try_seize_code_permission(&code_stage_permission, c_p, NULL, NULL)) { + if (try_seize_code_permission(&code_mod_permission, c_p, NULL, NULL)) { + return 1; + } + + erts_release_code_stage_permission(); + } + + return 0; +} + +void erts_release_code_load_permission(void) { + erts_release_code_mod_permission(); + erts_release_code_stage_permission(); } #ifdef ERTS_ENABLE_LOCK_CHECK -int erts_has_code_write_permission(void) +static int has_code_permission(struct code_permission *perm) +{ + const ErtsSchedulerData *esdp = erts_get_scheduler_data(); + + if (esdp && esdp->type == ERTS_SCHED_NORMAL) { + int res; + + erts_mtx_lock(&perm->lock); + + res = perm->seized; + + if (esdp->current_process != NULL) { + /* If we're running a process, it has to match the owner of the + * permission. We don't care about which scheduler we are running + * on in order to support holding permissions when yielding (such + * as in code purging). */ + res &= perm->owner == esdp->current_process; + } else { + /* If we're running an aux job, we crudely assume that this current + * job was started by the owner if there is one, and therefore has + * permission. + * + * If we don't have an owner, we assume that we have permission if + * we're running on the same scheduler that started the job. + * + * This is very blunt and only catches _some_ cases where we lack + * lack permission, but at least it's better than the old method of + * using thread-specific-data. */ + res &= perm->owner || perm->scheduler == esdp; + } + + erts_mtx_unlock(&perm->lock); + + return res; + } + + return 0; +} + +int erts_has_code_load_permission(void) { + return erts_has_code_stage_permission() && erts_has_code_mod_permission(); +} + +int erts_has_code_stage_permission(void) { + return has_code_permission(&code_stage_permission); +} + +int erts_has_code_mod_permission(void) { + return has_code_permission(&code_mod_permission); +} +#endif + +#ifdef DEBUG +void erts_debug_require_code_barrier(void) { + erts_tsd_set(needs_code_barrier, (void*)(1)); +} + +void erts_debug_check_code_barrier(void) { + ASSERT(erts_tsd_get(needs_code_barrier) == (void*)0); +} + +static void erts_debug_unrequire_code_barrier(void) { + erts_tsd_set(needs_code_barrier, (void*)(0)); +} +#endif + +static void schedule_code_barrier_later_op(void *barrier_) { + ErtsCodeBarrier *barrier = (ErtsCodeBarrier*)barrier_; + + if (barrier->size == 0) { + erts_schedule_thr_prgr_later_op(barrier->later_function, + barrier->later_data, + &barrier->later_op); + } else { + erts_schedule_thr_prgr_later_cleanup_op(barrier->later_function, + barrier->later_data, + &barrier->later_op, + barrier->size); + } +} + +#ifdef CODE_IX_ISSUE_INSTRUCTION_BARRIERS +static void issue_instruction_barrier(void *barrier_) { + ErtsCodeBarrier *barrier = (ErtsCodeBarrier*)barrier_; + + ERTS_THR_INSTRUCTION_BARRIER; + + if (erts_refc_dectest(&barrier->pending_schedulers, 0) == 0) { + schedule_code_barrier_later_op(barrier); + } +} +#endif + +void erts_schedule_code_barrier(ErtsCodeBarrier *barrier, + void (*later_function)(void *), + void *later_data) { + erts_schedule_code_barrier_cleanup(barrier, later_function, later_data, 0); +} + +void erts_schedule_code_barrier_cleanup(ErtsCodeBarrier *barrier, + void (*later_function)(void *), + void *later_data, + UWord size) { - return code_writing_seized && erts_tsd_get(has_code_write_permission); +#ifdef DEBUG + erts_debug_unrequire_code_barrier(); +#endif + + barrier->later_function = later_function; + barrier->later_data = later_data; + barrier->size = size; + +#ifdef CODE_IX_ISSUE_INSTRUCTION_BARRIERS + /* Issue instruction barriers on all normal schedulers, ensuring that they + * won't execute old code. + * + * The last scheduler to run the barrier gets the honor of scheduling a + * thread progress op to run the `later_function`. */ + erts_refc_init(&barrier->pending_schedulers, + (erts_aint_t)erts_no_schedulers); + erts_schedule_multi_misc_aux_work(1, 1, erts_no_schedulers, + issue_instruction_barrier, + barrier); + issue_instruction_barrier(barrier); +#else + schedule_code_barrier_later_op(barrier); +#endif +} + +#ifdef CODE_IX_ISSUE_INSTRUCTION_BARRIERS +static ErtsThrPrgrLaterOp global_code_barrier_lop; + +static void decrement_blocking_code_barriers(void *ignored) { + (void)ignored; + + if (erts_atomic32_dec_read_nob(&outstanding_blocking_code_barriers) > 0) { + /* We had more than one barrier in the same tick, and can't tell + * whether the later ones were issued before any of the managed threads + * were woken. Keep telling all managed threads to execute an + * instruction barrier on wake-up for one more tick. */ + erts_atomic32_set_nob(&outstanding_blocking_code_barriers, 1); + erts_schedule_thr_prgr_later_op(decrement_blocking_code_barriers, + NULL, + &global_code_barrier_lop); + } +} + +static void schedule_blocking_code_barriers(void *ignored) { + ERTS_THR_INSTRUCTION_BARRIER; + + /* Tell all managed threads to execute an instruction barrier as soon as we + * unblock thread progress, and schedule a thread progress job to clear the + * counter. + * + * Note that we increment and decrement instead of setting and clearing + * since we might schedule several blocking barriers in the same tick. */ + if (erts_atomic32_inc_read_nob(&outstanding_blocking_code_barriers) == 1) { + erts_schedule_thr_prgr_later_op(decrement_blocking_code_barriers, + NULL, + &global_code_barrier_lop); + } } #endif + +void erts_blocking_code_barrier(void) +{ +#ifdef DEBUG + erts_debug_unrequire_code_barrier(); +#endif + + ERTS_LC_ASSERT(erts_thr_progress_is_blocking()); + +#ifdef CODE_IX_ISSUE_INSTRUCTION_BARRIERS + schedule_blocking_code_barriers(NULL); +#endif +} + +void erts_code_ix_finalize_wait(void) { +#ifdef CODE_IX_ISSUE_INSTRUCTION_BARRIERS + if (erts_atomic32_read_nob(&outstanding_blocking_code_barriers) != 0) { + ERTS_THR_INSTRUCTION_BARRIER; + } +#endif +} diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 0345ccf1ef90..54ceefcc9b97 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2021. All Rights Reserved. + * Copyright Ericsson AB 2012-2023. 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. @@ -31,7 +31,7 @@ * The current 'active' code index is used to access the current running * code. The 'staging' code index is used by the process that performs * a code change operation. When a code change operation completes - * succesfully, the staging code index becomes the new active code index. + * successfully, the staging code index becomes the new active code index. * * The third code index is not explicitly used. It can be thought of as * the "previous active" or the "next staging" index. It is needed to make @@ -59,10 +59,29 @@ #include "beam_opcodes.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY +#define ERL_THR_PROGRESS_TSD_TYPE_ONLY +#include "erl_thr_progress.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY + struct process; #define ERTS_NUM_CODE_IX 3 + +#ifdef BEAMASM +#define ERTS_ADDRESSV_SIZE (ERTS_NUM_CODE_IX + 1) +#define ERTS_SAVE_CALLS_CODE_IX (ERTS_ADDRESSV_SIZE - 1) +#else +#define ERTS_ADDRESSV_SIZE ERTS_NUM_CODE_IX +#endif + +/* This structure lets `Export` entries and `ErlFunEntry` share dispatch code, + * which greatly improves the performance of fun calls. */ +typedef struct ErtsDispatchable_ { + ErtsCodePtr addresses[ERTS_ADDRESSV_SIZE]; +} ErtsDispatchable; + typedef unsigned ErtsCodeIndex; typedef struct ErtsCodeMFA_ { @@ -79,13 +98,35 @@ typedef struct ErtsCodeMFA_ { /* If you change the size of this, you also have to update the code in ops.tab to reflect the new func_info size */ typedef struct ErtsCodeInfo_ { - BeamInstr op; /* OpCode(i_func_info) */ - union { - struct generic_bp* gen_bp; /* Trace breakpoint */ + /* In both the JIT and interpreter, we may jump here to raise a + * function_clause error. + * + * In addition, the JIT also stores the current breakpoint flags here. */ + struct { +#ifndef BEAMASM + BeamInstr op; +#else + struct { + char raise_function_clause[sizeof(BeamInstr) - 1]; + char breakpoint_flag; + } metadata; +#endif } u; + + /* Trace breakpoint */ + struct generic_bp *gen_bp; ErtsCodeMFA mfa; } ErtsCodeInfo; +typedef struct { + erts_refc_t pending_schedulers; + ErtsThrPrgrLaterOp later_op; + UWord size; + + void (*later_function)(void *); + void *later_data; +} ErtsCodeBarrier; + /* Get the code associated with a ErtsCodeInfo ptr. */ ERTS_GLB_INLINE ErtsCodePtr erts_codeinfo_to_code(const ErtsCodeInfo *ci); @@ -116,37 +157,76 @@ ErtsCodeIndex erts_active_code_ix(void); /* Return staging code ix. * Only used by a process performing code loading/upgrading/deleting/purging. - * Code write permission must be seized. + * Code staging permission must be seized. */ ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void); -/* Try seize exclusive code write permission. Needed for code staging. +/** @brief Try to seize exclusive code loading permission. That is, both + * staging and modification permission. + * * Main process lock (only) must be held. * System thread progress must not be blocked. - * Caller must not already hold the code write permission. - * Caller is suspended and *must* yield if 0 is returned. + * Caller must not already have the code modification or staging permissions. + * Caller is suspended and *must* yield if 0 is returned. */ +int erts_try_seize_code_load_permission(struct process* c_p); + +/** @brief Release code loading permission. Resumes any suspended waiters. */ +void erts_release_code_load_permission(void); + +/** @brief Try to seize exclusive code staging permission. Needed for code + * loading and purging. + * + * This is kept separate from code modification permission to allow tracing and + * similar during long-running purge operations. + * + * * Main process lock (only) must be held. + * * System thread progress must not be blocked. + * * Caller is suspended and *must* yield if 0 is returned. + * * Caller must not already have the code modification or staging permissions. + * + * That is, it is _NOT_ possible to add code modification permission when you + * already have staging permission. The other way around is fine however. */ -int erts_try_seize_code_write_permission(struct process* c_p); +int erts_try_seize_code_stage_permission(struct process* c_p); + +/** @brief Release code stage permission. Resumes any suspended waiters. */ +void erts_release_code_stage_permission(void); -/* Try seize exclusive code write permission for aux work. +/** @brief Try to seize exclusive code modification permission. Needed for + * tracing, breakpoints, and so on. + * + * This used to be called code_write_permission, but was renamed to break + * merges of code that uses the old locking paradigm. + * + * * Main process lock (only) must be held. + * * System thread progress must not be blocked. + * * Caller is suspended and *must* yield if 0 is returned. + * * Caller must not already have the code modification permission, but may + * have staging permission. + */ +int erts_try_seize_code_mod_permission(struct process* c_p); + +/** @brief As \c erts_try_seize_code_mod_permission but for aux work. + * * System thread progress must not be blocked. * On success return true. * On failure return false and aux work func(arg) will be scheduled when - * permission is released. . + * permission is released. */ -int erts_try_seize_code_write_permission_aux(void (*func)(void *), - void *arg); +int erts_try_seize_code_mod_permission_aux(void (*func)(void *), + void *arg); -/* Release code write permission. - * Will resume any suspended waiters. - */ -void erts_release_code_write_permission(void); +/** @brief Release code modification permission. Resumes any suspended + * waiters. */ +void erts_release_code_mod_permission(void); /* Prepare the "staging area" to be a complete copy of the active code. - * Code write permission must have been seized. + * + * Code staging permission must have been seized. + * * Must be followed by calls to either "end" and "commit" or "abort" before - * code write permission can be released. + * code staging permission can be released. */ void erts_start_staging_code_ix(int num_new); @@ -165,8 +245,36 @@ void erts_commit_staging_code_ix(void); */ void erts_abort_staging_code_ix(void); +#ifdef DEBUG +void erts_debug_require_code_barrier(void); +void erts_debug_check_code_barrier(void); +#endif + +/* Schedules an operation to run after thread progress _and_ all schedulers + * have issued an instruction barrier. */ +void erts_schedule_code_barrier(ErtsCodeBarrier *barrier, + void (*later_function)(void *), + void *later_data); + +void erts_schedule_code_barrier_cleanup(ErtsCodeBarrier *barrier, + void (*later_function)(void *), + void *later_data, + UWord size); + +/* Issues a code barrier on the current thread, as well as all managed threads + * when they wake up after thread progress is unblocked. + * + * Requires that thread progress is blocked. */ +void erts_blocking_code_barrier(void); + +/* Helper function for the above: all managed threads should call this as soon + * as thread progress is unblocked, _BEFORE_ updating thread progress. */ +void erts_code_ix_finalize_wait(void); + #ifdef ERTS_ENABLE_LOCK_CHECK -int erts_has_code_write_permission(void); +int erts_has_code_load_permission(void); +int erts_has_code_stage_permission(void); +int erts_has_code_mod_permission(void); #endif /* module/function/arity can be NIL/NIL/-1 when the MFA is pointing to some @@ -185,7 +293,7 @@ ERTS_GLB_INLINE ErtsCodePtr erts_codeinfo_to_code(const ErtsCodeInfo *ci) { #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI) || !ci->op); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI) || !ci->u.op); #endif ASSERT_MFA(&ci->mfa); return (ErtsCodePtr)&ci[1]; @@ -197,7 +305,7 @@ const ErtsCodeInfo *erts_code_to_codeinfo(ErtsCodePtr I) const ErtsCodeInfo *ci = &((const ErtsCodeInfo *)I)[-1]; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI) || !ci->op); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI) || !ci->u.op); #endif ASSERT_MFA(&ci->mfa); diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 0d6343337276..a22317f6c1a6 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2022. 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. @@ -34,6 +34,7 @@ #include "erl_binary.h" #include "erl_bits.h" #include "dtrace-wrapper.h" +#include "erl_global_literals.h" static void move_one_frag(Eterm** hpp, ErlHeapFragment*, ErlOffHeap*, int); @@ -114,12 +115,20 @@ Uint size_object_x(Eterm obj, erts_literal_area_t *litopt) ASSERT(is_header(hdr)); switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: - ptr = tuple_val(obj); arity = header_arity(hdr); - sum += arity + 1; if (arity == 0) { /* Empty tuple -- unusual. */ + ASSERT(!litopt && + erts_is_literal(obj,ptr) && + obj == ERTS_GLOBAL_LIT_EMPTY_TUPLE); + /* + The empty tuple is always a global literal + constant so it does not take up any extra + space. + */ goto pop_next; } + ptr = tuple_val(obj); + sum += arity + 1; while (arity-- > 1) { obj = *++ptr; if (!IS_CONST(obj)) { @@ -154,6 +163,7 @@ Uint size_object_x(Eterm obj, erts_literal_area_t *litopt) mp = (flatmap_t*)flatmap_val(obj); ptr = (Eterm *)mp; n = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); sum += n + 2; ptr += 2; /* hdr + size words */ while (n--) { @@ -365,7 +375,10 @@ Uint size_shared(Eterm obj) int arity = header_arity(hdr); sum += arity + 1; if (arity == 0) { /* Empty tuple -- unusual. */ - goto pop_next; + ASSERT(COUNT_OFF_HEAP && + erts_is_literal(obj,ptr) && + obj == ERTS_GLOBAL_LIT_EMPTY_TUPLE); + goto pop_next; } while (arity-- > 0) { obj = *++ptr; @@ -418,6 +431,7 @@ Uint size_shared(Eterm obj) case MAP_HEADER_TAG_FLATMAP_HEAD : { flatmap_t *mp = (flatmap_t*)flatmap_val(obj); Uint n = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); ptr = (Eterm *)mp; sum += n + 2; ptr += 2; /* hdr + size words */ @@ -523,6 +537,9 @@ Uint size_shared(Eterm obj) case ARITYVAL_SUBTAG: { int arity = header_arity(hdr); if (arity == 0) { /* Empty tuple -- unusual. */ + ASSERT(COUNT_OFF_HEAP && + erts_is_literal(obj,ptr) && + obj == ERTS_GLOBAL_LIT_EMPTY_TUPLE); goto cleanup_next; } while (arity-- > 0) { @@ -551,6 +568,7 @@ Uint size_shared(Eterm obj) case MAP_HEADER_TAG_FLATMAP_HEAD : { flatmap_t *mp = (flatmap_t *) ptr; Uint n = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); ptr += 2; /* hdr + size words */ while (n--) { obj = *ptr++; @@ -601,7 +619,6 @@ Uint size_shared(Eterm obj) return sum; } - /* * Copy a structure to a heap. */ @@ -736,6 +753,13 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, { int const_flag = 1; /* assume constant tuple */ i = arityval(hdr); + if (i == 0) { + ASSERT(!litopt && + erts_is_literal(obj,objp) && + obj == ERTS_GLOBAL_LIT_EMPTY_TUPLE); + *argp = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + break; + } *argp = make_tuple(htop); tp = htop; /* tp is pointer to new arity value */ *htop++ = *objp++; /* copy arity value */ @@ -849,9 +873,15 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, *htop++ = *objp++; } funp = (ErlFunThing *) tp; - funp->next = off_heap->first; - off_heap->first = (struct erl_off_heap_header*) funp; - erts_refc_inc(&funp->fe->refc, 2); + + if (is_local_fun(funp)) { + funp->next = off_heap->first; + off_heap->first = (struct erl_off_heap_header*) funp; + erts_refc_inc(&funp->entry.fun->refc, 2); + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + } + *argp = make_fun(tp); } break; @@ -888,6 +918,7 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, switch (MAP_HEADER_TYPE(hdr)) { case MAP_HEADER_TAG_FLATMAP_HEAD : i = flatmap_get_size(objp) + 3; + ASSERT(flatmap_get_size(objp) <= MAP_SMALL_MAP_LIMIT); *argp = make_flatmap(htop); while (i--) { *htop++ = *objp++; @@ -1094,7 +1125,9 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) #ifdef DEBUG Eterm mypid = erts_get_current_pid(); #endif - + const Eterm empty_tuple_literal = + ERTS_GLOBAL_LIT_EMPTY_TUPLE; + DECLARE_EQUEUE_INIT_INFO(s, info); DECLARE_BITSTORE_INIT_INFO(b, info); DECLARE_SHTABLE_INIT_INFO(t, info); @@ -1184,10 +1217,12 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) case TAG_PRIMARY_BOXED: { Eterm hdr; ptr = boxed_val(obj); - /* off heap pointers to boxes are copied verbatim */ + /* off heap pointers to boxes (except pointers to the + empty tuple) are copied verbatim */ if (erts_is_literal(obj,ptr)) { VERBOSE(DEBUG_SHCOPY, ("[pid=%T] bypassed copying %p is %T\n", mypid, ptr, obj)); - if (copy_literals || in_literal_purge_area(ptr)) + if (obj != empty_tuple_literal && + (copy_literals || in_literal_purge_area(ptr))) info->literal_size += size_object(obj); goto pop_next; } @@ -1211,10 +1246,10 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: { int arity = header_arity(hdr); + /* arity cannot be 0 as the empty tuple is always a + global constant literal which is handled above */ + ASSERT(arity != 0); sum += arity + 1; - if (arity == 0) { /* Empty tuple -- unusual. */ - goto pop_next; - } while (arity-- > 0) { obj = *++ptr; if (!IS_CONST(obj)) { @@ -1286,6 +1321,7 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) case MAP_HEADER_TAG_FLATMAP_HEAD : { flatmap_t *mp = (flatmap_t *) ptr; Uint n = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); sum += n + 2; ptr += 2; /* hdr + size words */ while (n--) { @@ -1382,7 +1418,8 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, Eterm mypid = erts_get_current_pid(); Eterm saved_obj = obj; #endif - + const Eterm empty_tuple_literal = + ERTS_GLOBAL_LIT_EMPTY_TUPLE; DECLARE_EQUEUE_FROM_INFO(s, info); DECLARE_BITSTORE_FROM_INFO(b, info); DECLARE_SHTABLE_FROM_INFO(t, info); @@ -1499,7 +1536,8 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, ptr = boxed_val(obj); /* off heap pointers to boxes are copied verbatim */ if (erts_is_literal(obj,ptr)) { - if (!(copy_literals || in_literal_purge_area(ptr))) { + if (obj == empty_tuple_literal || + !(copy_literals || in_literal_purge_area(ptr))) { *resp = obj; } else { Uint bsz = 0; @@ -1577,9 +1615,15 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, *hp++ = HEAP_ELEM_TO_BE_FILLED; } } - funp->next = off_heap->first; - off_heap->first = (struct erl_off_heap_header*) funp; - erts_refc_inc(&funp->fe->refc, 2); + + if (is_local_fun(funp)) { + funp->next = off_heap->first; + off_heap->first = (struct erl_off_heap_header*) funp; + erts_refc_inc(&funp->entry.fun->refc, 2); + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + } + goto cleanup_next; } case MAP_SUBTAG: @@ -1589,6 +1633,7 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, case MAP_HEADER_TAG_FLATMAP_HEAD : { flatmap_t *mp = (flatmap_t *) ptr; Uint n = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); *hp++ = *++ptr; /* keys */ while (n--) { obj = *++ptr; @@ -1792,6 +1837,7 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, case MAP_HEADER_TAG_FLATMAP_HEAD : { flatmap_t *mp = (flatmap_t *) hscan; remaining = flatmap_get_size(mp) + 1; + ASSERT(flatmap_get_size(mp) <= MAP_SMALL_MAP_LIMIT); hscan += 2; break; } @@ -1885,21 +1931,55 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, * pointers are offsetted to point correctly in the new location. * * Typically used to copy a term from an ets table. + */ +Eterm copy_shallow_obj_x(Eterm obj, Uint sz, Eterm **hpp, ErlOffHeap *off_heap +#ifdef ERTS_COPY_REGISTER_LOCATION + , + char *file, int line +#endif +) { + Eterm *source_ptr; + Eterm *target_ptr; + + if (sz == 0) { + ASSERT(is_zero_sized(obj)); + return obj; + } + + ASSERT(is_boxed(obj) || is_list(obj)); + ASSERT(!is_zero_sized(obj)); + + source_ptr = ptr_val(obj); +#ifdef ERTS_COPY_REGISTER_LOCATION + target_ptr = copy_shallow_x(source_ptr, sz, hpp, off_heap, file, line); +#else + target_ptr = copy_shallow_x(source_ptr, sz, hpp, off_heap); +#endif + + return is_boxed(obj) ? make_boxed(target_ptr) : make_list(target_ptr); +} + + +/* + * Copy a term that is guaranteed to be contained in a single + * heap block. The heap block is copied word by word, and any + * pointers are offsetted to point correctly in the new location. * - * NOTE: Assumes that term is a tuple (ptr is an untagged tuple ptr). + * Typically used to copy a term from an ets table. */ -Eterm -copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap +Eterm* copy_shallow_x(Eterm *ERTS_RESTRICT ptr, Uint sz, Eterm **hpp, + ErlOffHeap *off_heap #ifdef ERTS_COPY_REGISTER_LOCATION - , char *file, int line + , + char *file, int line #endif - ) -{ - Eterm* tp = ptr; - Eterm* hp = *hpp; - const Eterm res = make_tuple(hp); +) { + Eterm *tp = ptr; + Eterm *hp = *hpp; + Eterm* res = hp; const Sint offs = (hp - tp) * sizeof(Eterm); - + const Eterm empty_tuple_literal = + ERTS_GLOBAL_LIT_EMPTY_TUPLE; while (sz--) { Eterm val = *tp++; @@ -1909,7 +1989,11 @@ copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_h break; case TAG_PRIMARY_LIST: case TAG_PRIMARY_BOXED: - *hp++ = byte_offset_ptr(val, offs); + if (val == empty_tuple_literal) { + *hp++ = empty_tuple_literal; + } else { + *hp++ = byte_offset_ptr(val, offs); + } break; case TAG_PRIMARY_HEADER: *hp++ = val; @@ -1924,12 +2008,18 @@ copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_h } goto off_heap_common; - case FUN_SUBTAG: - { - ErlFunThing* funp = (ErlFunThing *) (tp-1); - erts_refc_inc(&funp->fe->refc, 2); - } - goto off_heap_common; + case FUN_SUBTAG: + { + ErlFunThing* funp = (ErlFunThing *) (tp-1); + + if (is_local_fun(funp)) { + erts_refc_inc(&funp->entry.fun->refc, 2); + goto off_heap_common; + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + goto default_copy; + } + } case EXTERNAL_PID_SUBTAG: case EXTERNAL_PORT_SUBTAG: case EXTERNAL_REF_SUBTAG: @@ -1963,6 +2053,7 @@ copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_h } /* Fall through... */ } + default_copy: default: { int tari = header_arity(val); @@ -2054,34 +2145,49 @@ move_one_frag(Eterm** hpp, ErlHeapFragment* frag, ErlOffHeap* off_heap, int lite Eterm* hp = *hpp; while (ptr != end) { - Eterm val; - ASSERT(ptr < end); - val = *ptr; - ASSERT(val != ERTS_HOLE_MARKER); - if (is_header(val)) { - struct erl_off_heap_header* hdr = (struct erl_off_heap_header*)hp; - ASSERT(ptr + header_arity(val) < end); - ptr = move_boxed(ptr, val, &hp, &dummy_ref); - switch (val & _HEADER_SUBTAG_MASK) { - case REF_SUBTAG: - if (!is_magic_ref_thing(hdr)) - break; - case REFC_BINARY_SUBTAG: - case FUN_SUBTAG: - case EXTERNAL_PID_SUBTAG: - case EXTERNAL_PORT_SUBTAG: - case EXTERNAL_REF_SUBTAG: - hdr->next = off_heap->first; - off_heap->first = hdr; - break; - } - } - else { /* must be a cons cell */ - ASSERT(ptr+1 < end); - move_cons(ptr, val, &hp, &dummy_ref); - ptr += 2; - } + Eterm val; + ASSERT(ptr < end); + val = *ptr; + ASSERT(val != ERTS_HOLE_MARKER); + + if (is_header(val)) { + struct erl_off_heap_header* hdr = (struct erl_off_heap_header*)hp; + + ASSERT(ptr + header_arity(val) < end); + ptr = move_boxed(ptr, val, &hp, &dummy_ref); + + switch (val & _HEADER_SUBTAG_MASK) { + case REF_SUBTAG: + if (!is_magic_ref_thing(hdr)) { + break; + } + case REFC_BINARY_SUBTAG: + case EXTERNAL_PID_SUBTAG: + case EXTERNAL_PORT_SUBTAG: + case EXTERNAL_REF_SUBTAG: + hdr->next = off_heap->first; + off_heap->first = hdr; + break; + case FUN_SUBTAG: + { + ErlFunThing *funp = (ErlFunThing*)hdr; + + if (is_local_fun(funp)) { + hdr->next = off_heap->first; + off_heap->first = hdr; + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + } + } + break; + } + } else { /* must be a cons cell */ + ASSERT(ptr+1 < end); + move_cons(ptr, val, &hp, &dummy_ref); + ptr += 2; + } } + *hpp = hp; OH_OVERHEAD(off_heap, frag->off_heap.overhead); frag->off_heap.first = NULL; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index fec65a362344..158f7116a22a 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -47,6 +47,7 @@ #include "dtrace-wrapper.h" #include "erl_proc_sig_queue.h" #include "erl_global_literals.h" +#include "erl_map.h" #define DIST_CTL_DEFAULT_SIZE 64 @@ -192,7 +193,7 @@ static Export *dist_ctrl_put_data_trap; static void erts_schedule_dist_command(Port *, DistEntry *); static int dsig_send_exit(ErtsDSigSendContext *ctx, Eterm ctl, Eterm msg); static int dsig_send_ctl(ErtsDSigSendContext *ctx, Eterm ctl); -static void send_nodes_mon_msgs(Process *, Eterm, Eterm, Eterm, Eterm); +static void send_nodes_mon_msgs(Process *, Eterm, Eterm, Uint32, Eterm, Eterm); static void init_nodes_monitors(void); static Sint abort_pending_connection(DistEntry* dep, Uint32 conn_id, int *was_connected_p); @@ -210,6 +211,37 @@ struct { ErlHeapFragment *bp; } nodedown; +/* + * Dist entry queue flags are only modified while + * the dist entry queue lock is held... + */ +static ERTS_INLINE erts_aint32_t +de_qflags_read(DistEntry *dep) +{ + return erts_atomic32_read_nob(&dep->qflgs); +} + +static ERTS_INLINE erts_aint32_t +de_qflags_read_set(DistEntry *dep, erts_aint32_t set) +{ + erts_aint32_t qflgs, new_qflgs; + ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&dep->qlock)); + new_qflgs = qflgs = erts_atomic32_read_nob(&dep->qflgs); + new_qflgs |= set; + erts_atomic32_set_nob(&dep->qflgs, new_qflgs); + return qflgs; +} + +static ERTS_INLINE erts_aint32_t +de_qflags_read_unset(DistEntry *dep, erts_aint32_t unset) +{ + erts_aint32_t qflgs, new_qflgs; + ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&dep->qlock)); + new_qflgs = qflgs = erts_atomic32_read_nob(&dep->qflgs); + new_qflgs &= ~unset; + erts_atomic32_set_nob(&dep->qflgs, new_qflgs); + return qflgs; +} static void delete_cache(ErtsAtomCache *cache) @@ -249,7 +281,7 @@ get_suspended_on_de(DistEntry *dep, erts_aint32_t unset_qflgs) { erts_aint32_t qflgs; ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&dep->qlock)); - qflgs = erts_atomic32_read_band_acqb(&dep->qflgs, ~unset_qflgs); + qflgs = de_qflags_read_unset(dep, unset_qflgs); qflgs &= ~unset_qflgs; if (qflgs & ERTS_DE_QFLG_EXIT) { /* No resume when exit has been scheduled */ @@ -267,10 +299,23 @@ get_suspended_on_de(DistEntry *dep, erts_aint32_t unset_qflgs) static int monitor_connection_down(ErtsMonitor *mon, void *unused, Sint reds) { - if (erts_monitor_is_origin(mon)) - erts_proc_sig_send_demonitor(mon); - else - erts_proc_sig_send_monitor_down(mon, am_noconnection); + const ErtsMonitorData *data = erts_monitor_to_data(mon); + Eterm from; + + if (erts_monitor_is_origin(mon)) { + from = data->u.target.other.item; + } else { + from = data->origin.other.item; + } + + ASSERT(!is_internal_pid(from) && is_internal_pid(mon->other.item)); + + if (erts_monitor_is_origin(mon)) { + erts_proc_sig_send_demonitor(NULL, from, 0, mon); + } else { + erts_proc_sig_send_monitor_down(NULL, from, mon, am_noconnection); + } + return ERTS_MON_LNK_FIRE_REDS; } @@ -291,8 +336,7 @@ static int dist_pend_spawn_exit_connection_down(ErtsMonitor *mon, void *unused, static int link_connection_down(ErtsLink *lnk, void *vdist, Sint reds) { - erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, lnk, - am_noconnection, NIL); + erts_proc_sig_send_link_exit_noconnection(lnk); return ERTS_MON_LNK_FIRE_REDS; } @@ -308,6 +352,7 @@ typedef enum { typedef struct { ErtsConMonLnkSeqCleanupState state; DistEntry* dep; + Uint32 connection_id; ErtsMonLnkDist *dist; DistSeqNode *seq; void *yield_state; @@ -386,6 +431,7 @@ con_monitor_link_seq_cleanup(void *vcmlcp) send_nodes_mon_msgs(NULL, am_nodedown, cmlcp->nodename, + cmlcp->connection_id, cmlcp->visability, cmlcp->reason); erts_de_rwlock(cmlcp->dep); @@ -451,10 +497,13 @@ schedule_con_monitor_link_seq_cleanup(DistEntry* dep, cmlcp->yield_state = NULL; cmlcp->dist = dist; - if (!dist) + if (!dist) { cmlcp->state = ERTS_CML_CLEANUP_STATE_NODE_MONITORS; + cmlcp->connection_id = 0; + } else { cmlcp->state = ERTS_CML_CLEANUP_STATE_LINKS; + cmlcp->connection_id = dist->connection_id; erts_mtx_lock(&dist->mtx); ASSERT(dist->alive); dist->alive = 0; @@ -803,7 +852,8 @@ set_node_not_alive(void *unused) erts_thr_progress_block(); erts_set_this_node(am_Noname, 0); erts_is_alive = 0; - send_nodes_mon_msgs(NULL, am_nodedown, nodename, am_visible, nodedown.reason); + send_nodes_mon_msgs(NULL, am_nodedown, nodename, ~((Uint32) 0), + am_visible, nodedown.reason); nodedown.reason = NIL; bp = nodedown.bp; nodedown.bp = NULL; @@ -837,8 +887,10 @@ inc_no_nodes(void) static void kill_dist_ctrl_proc(void *vpid) { - erts_proc_sig_send_exit(NULL, (Eterm) vpid, (Eterm) vpid, - am_kill, NIL, 0); + /* Send a 'kill' exit signal from init process */ + Process *init_proc = erts_proc_lookup_raw(erts_init_process_id); + erts_proc_sig_send_exit(&init_proc->common, erts_init_process_id, + (Eterm)vpid, am_kill, NIL, 0); } static void @@ -989,14 +1041,14 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason) } if (dep->state == ERTS_DE_STATE_EXITING) { - ASSERT(erts_atomic32_read_nob(&dep->qflgs) & ERTS_DE_QFLG_EXIT); + ASSERT(de_qflags_read(dep) & ERTS_DE_QFLG_EXIT); } else { ASSERT(dep->state == ERTS_DE_STATE_CONNECTED); dep->state = ERTS_DE_STATE_EXITING; erts_mtx_lock(&dep->qlock); - ASSERT(!(erts_atomic32_read_nob(&dep->qflgs) & ERTS_DE_QFLG_EXIT)); - erts_atomic32_read_bor_relb(&dep->qflgs, ERTS_DE_QFLG_EXIT); + ASSERT(!(de_qflags_read(dep) & ERTS_DE_QFLG_EXIT)); + de_qflags_read_set(dep, ERTS_DE_QFLG_EXIT); erts_mtx_unlock(&dep->qlock); } @@ -1022,6 +1074,8 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason) suspendees = get_suspended_on_de(dep, ERTS_DE_QFLGS_ALL); erts_mtx_unlock(&dep->qlock); + + erts_atomic32_set_relb(&dep->notify, 0); erts_atomic_set_nob(&dep->dist_cmd_scheduled, 0); dep->send = NULL; @@ -1123,7 +1177,8 @@ void init_dist(void) static ERTS_INLINE ErtsDistOutputBuf * alloc_dist_obufs(byte **extp, TTBEncodeContext *ctx, - Uint data_size, Uint fragments, Uint vlen) + Uint data_size, Uint fragments, Uint vlen, + int ignore_busy) { int ix; ErtsDistOutputBuf *obuf; @@ -1154,6 +1209,7 @@ alloc_dist_obufs(byte **extp, TTBEncodeContext *ctx, erts_refc_add(&bin->intern.refc, fragments - 1, 1); for (ix = 0; ix < fragments; ix++) { + obuf[ix].ignore_busy = ignore_busy; obuf[ix].bin = bin; obuf[ix].eiov = &ctx->fragment_eiovs[ix]; #ifdef DEBUG @@ -1199,6 +1255,81 @@ size_obuf(ErtsDistOutputBuf *obuf) return sz; } +static ERTS_INLINE void +get_obuf_sizes(ErtsDistOutputBuf *obuf, Sint *size, Sint *ignore_size) +{ + Sint sz = size_obuf(obuf); + ASSERT(sz >= 0); + *size = sz; + *ignore_size = obuf->ignore_busy ? sz : 0; +} + +static ERTS_INLINE void +add_obuf_sizes(ErtsDistOutputBuf *obuf, Sint *size, Sint *ignore_size) +{ + Sint sz, isz; + get_obuf_sizes(obuf, &sz, &isz); + *size += sz; + *ignore_size += isz; +} + +static ERTS_INLINE void +subtract_obuf_sizes(ErtsDistOutputBuf *obuf, Sint *size, Sint *ignore_size) +{ + Sint sz, isz; + get_obuf_sizes(obuf, &sz, &isz); + *size -= sz; + *ignore_size -= isz; +} + +static ERTS_INLINE void +update_qsizes(DistEntry *dep, int *empty_fillp, Sint *qsizep, + Sint add_total_qsize, Sint ignore_qsize) +{ + /* + * All modifications of the 'total_qsize' and 'qsize' fields are + * made while holding the 'qlock', so read/modify/write of each + * field does not need to be atomic. Readers without the lock will + * still see consistent updates of each 'field'. + */ + erts_aint_t qsize, add_qsize; + + ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&dep->qlock)); + + if (empty_fillp) + *empty_fillp = 0; + + if (add_total_qsize) { + qsize = erts_atomic_read_nob(&dep->total_qsize); + qsize += (erts_aint_t) add_total_qsize; + if (empty_fillp && qsize == add_total_qsize) + *empty_fillp = !0; + erts_atomic_set_nob(&dep->total_qsize, (erts_aint_t) qsize); + } + + add_qsize = (erts_aint_t) (add_total_qsize - ignore_qsize); + if (add_qsize) { + qsize = erts_atomic_read_nob(&dep->qsize); + qsize += add_qsize; + if (qsizep) + *qsizep = qsize; + erts_atomic_set_nob(&dep->qsize, (erts_aint_t) qsize); + } + else if (qsizep) { + *qsizep = erts_atomic_read_nob(&dep->qsize); + } + +#ifdef DEBUG + { + erts_aint_t tqsize = erts_atomic_read_nob(&dep->total_qsize); + qsize = erts_atomic_read_nob(&dep->qsize); + ASSERT(tqsize >= 0); + ASSERT(qsize >= 0); + ASSERT(tqsize >= qsize); + } +#endif +} + static ErtsDistOutputBuf* clear_de_out_queues(DistEntry* dep) { ErtsDistOutputBuf *obuf; @@ -1229,21 +1360,19 @@ static ErtsDistOutputBuf* clear_de_out_queues(DistEntry* dep) static void free_de_out_queues(DistEntry* dep, ErtsDistOutputBuf *obuf) { - Sint obufsize = 0; + Sint obufsize = 0, ignore_obufsize = 0; while (obuf) { ErtsDistOutputBuf *fobuf; fobuf = obuf; obuf = obuf->next; - obufsize += size_obuf(fobuf); + add_obuf_sizes(fobuf, &obufsize, &ignore_obufsize); free_dist_obuf(fobuf, !0); } if (obufsize) { erts_mtx_lock(&dep->qlock); - ASSERT(erts_atomic_read_nob(&dep->qsize) >= obufsize); - erts_atomic_add_nob(&dep->qsize, - (erts_aint_t) -obufsize); + update_qsizes(dep, NULL, NULL, -obufsize, -ignore_obufsize); erts_mtx_unlock(&dep->qlock); } } @@ -1320,28 +1449,14 @@ erts_dsig_send_unlink(ErtsDSigSendContext *ctx, Eterm local, Eterm remote, Uint6 Eterm big_heap[ERTS_MAX_UINT64_HEAP_SIZE]; Eterm unlink_id; Eterm ctl; - if (ctx->dflags & DFLAG_UNLINK_ID) { - if (IS_USMALL(0, id)) - unlink_id = make_small(id); - else { - Eterm *hp = &big_heap[0]; - unlink_id = erts_uint64_to_big(id, &hp); - } - ctl = TUPLE4(&ctx->ctl_heap[0], make_small(DOP_UNLINK_ID), - unlink_id, local, remote); - } + if (IS_USMALL(0, id)) + unlink_id = make_small(id); else { - /* - * A node that isn't capable of talking the new link protocol. - * - * Send an old unlink op, and send ourselves an unlink-ack. We may - * end up in an inconsistent state as we could before the new link - * protocol was introduced... - */ - erts_proc_sig_send_dist_unlink_ack(ctx->c_p, ctx->dep, ctx->connection_id, - remote, local, id); - ctl = TUPLE3(&ctx->ctl_heap[0], make_small(DOP_UNLINK), local, remote); + Eterm *hp = &big_heap[0]; + unlink_id = erts_uint64_to_big(id, &hp); } + ctl = TUPLE4(&ctx->ctl_heap[0], make_small(DOP_UNLINK_ID), + unlink_id, local, remote); return dsig_send_ctl(ctx, ctl); } @@ -1352,11 +1467,6 @@ erts_dsig_send_unlink_ack(ErtsDSigSendContext *ctx, Eterm local, Eterm remote, U Eterm unlink_id; Eterm ctl; - if (!(ctx->dflags & DFLAG_UNLINK_ID)) { - /* Receiving node does not understand it, so drop it... */ - return ERTS_DSIG_SEND_OK; - } - if (IS_USMALL(0, id)) unlink_id = make_small(id); else { @@ -1724,7 +1834,7 @@ dsig_send_spawn_request(ErtsDSigSendContext *ctx, Eterm ref, Eterm from, * Present this as two messages for the sequence tracing. * All data except the argument list in the first message * and then the argument list as second message (which - * willl become an actual message). For more info see + * will become an actual message). For more info see * handling of seq-trace token in erl_create_process(). */ @@ -1984,10 +2094,14 @@ int erts_net_message(Port *prt, seq->ctl_len = ctl_len; seq->seq_id = ede.data->seq_id; seq->cnt = ede.data->frag_id; - if (dist_seq_rbt_lookup_insert(&dep->sequences, seq) != NULL) { + erts_de_rlock(dep); + if (dep->state != ERTS_DE_STATE_CONNECTED + || dep->connection_id != ede.connection_id + || dist_seq_rbt_lookup_insert(&dep->sequences, seq) != NULL) { free_message_buffer(&seq->hfrag); - goto data_error; + goto data_error_runlock; } + erts_de_runlock(dep); erts_make_dist_ext_copy(&ede, erts_get_dist_ext(&seq->hfrag)); @@ -1999,10 +2113,17 @@ int erts_net_message(Port *prt, /* fall through, the first fragment in the sequence was the last fragment */ case ERTS_PREP_DIST_EXT_FRAG_CONT: { - DistSeqNode *seq = dist_seq_rbt_lookup(dep->sequences, ede.data->seq_id); + DistSeqNode *seq; + erts_de_rlock(dep); + if (dep->state != ERTS_DE_STATE_CONNECTED + || dep->connection_id != ede.connection_id) { + goto data_error_runlock; + } + + seq = dist_seq_rbt_lookup(dep->sequences, ede.data->seq_id); if (!seq) - goto data_error; + goto data_error_runlock; /* If we did a fall-though we already did this */ if (res == ERTS_PREP_DIST_EXT_FRAG_CONT) @@ -2010,16 +2131,20 @@ int erts_net_message(Port *prt, /* Verify that the fragments have arrived in the correct order */ if (seq->cnt != ede.data->frag_id) - goto data_error; + goto data_error_runlock; seq->cnt--; /* Check if this was the last fragment */ - if (ede.data->frag_id > 1) + if (ede.data->frag_id > 1) { + erts_de_runlock(dep); return 0; + } /* Last fragment arrived, time to dispatch the signal */ + dist_seq_rbt_delete(&dep->sequences, seq); + erts_de_runlock(dep); ctl_len = seq->ctl_len; /* Now that we no longer need the DistSeqNode we re-use the heapfragment @@ -2100,11 +2225,10 @@ int erts_net_message(Port *prt, ASSERT(eq(ldp->proc.other.item, from)); code = erts_link_dist_insert(&ldp->dist, ede.mld); - if (erts_proc_sig_send_link(NULL, to, &ldp->proc)) { + if (erts_proc_sig_send_link(NULL, from, to, &ldp->proc)) { if (!code) { /* Race: connection already down => send link exit */ - erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->dist, - am_noconnection, NIL); + erts_proc_sig_send_link_exit_noconnection(&ldp->dist); } break; /* Done */ } @@ -2126,6 +2250,13 @@ int erts_net_message(Port *prt, break; } + case DOP_UNLINK: + /* + * DOP_UNLINK should never be passed. The new link protocol is + * mandatory as of OTP 26. + */ + goto invalid_message; + case DOP_UNLINK_ID: { Eterm *element; Uint64 id; @@ -2139,14 +2270,6 @@ int erts_net_message(Port *prt, if (id == 0) goto invalid_message; - if (0) { - case DOP_UNLINK: - if (tuple_arity != 3) - goto invalid_message; - element = &tuple[2]; - id = 0; - } - from = *(element++); to = *element; if (is_not_external_pid(from)) @@ -2187,8 +2310,7 @@ int erts_net_message(Port *prt, if (is_not_internal_pid(to)) goto invalid_message; - erts_proc_sig_send_dist_unlink_ack(NULL, dep, conn_id, - from, to, id); + erts_proc_sig_send_dist_unlink_ack(dep, conn_id, from, to, id); break; } @@ -2244,8 +2366,10 @@ int erts_net_message(Port *prt, break; } - if (erts_proc_sig_send_monitor(&mdp->u.target, pid)) + if (erts_proc_sig_send_monitor(NULL, watcher, + &mdp->u.target, pid)) { break; /* done */ + } /* Failed to send to local proc; cleanup reply noproc... */ @@ -2266,8 +2390,7 @@ int erts_net_message(Port *prt, case DOP_DEMONITOR_P: /* A remote node informs us that a local pid in no longer monitored - We get {DOP_DEMONITOR_P, Remote pid, Local pid or name, ref}, - We need only the ref of course */ + We get {DOP_DEMONITOR_P, Remote pid, Local pid or name, ref}. */ if (tuple_arity != 4) { goto invalid_message; @@ -2284,9 +2407,9 @@ int erts_net_message(Port *prt, if (is_not_external_pid(watcher) || external_pid_dist_entry(watcher) != dep) goto invalid_message; - if (is_internal_pid(watched)) - erts_proc_sig_send_dist_demonitor(watched, ref); - else if (is_external_pid(watched) + if (is_internal_pid(watched)) { + erts_proc_sig_send_dist_demonitor(watcher, watched, ref); + } else if (is_external_pid(watched) && external_pid_dist_entry(watched) == erts_this_dist_entry) { /* old incarnation; ignore it */ ; @@ -2299,13 +2422,14 @@ int erts_net_message(Port *prt, mon = erts_monitor_tree_lookup(ede.mld->orig_name_monitors, ref); if (mon) erts_monitor_tree_delete(&ede.mld->orig_name_monitors, mon); - } - else + } else { mon = NULL; + } erts_mtx_unlock(&ede.mld->mtx); - if (mon) - erts_proc_sig_send_demonitor(mon); + if (mon) { + erts_proc_sig_send_demonitor(NULL, watcher, 0, mon); + } } else goto invalid_message; @@ -2384,19 +2508,20 @@ int erts_net_message(Port *prt, * the atom '' (empty cookie). */ ASSERT((type == DOP_SEND_SENDER || type == DOP_SEND_SENDER_TT) - ? (is_pid(tuple[2]) && (dep->dflags & DFLAG_SEND_SENDER)) + ? is_pid(tuple[2]) : tuple[2] == am_Empty); #ifdef ERTS_DIST_MSG_DBG dist_msg_dbg(edep, "MSG", buf, orig_len); #endif - to = tuple[3]; - if (is_not_pid(to)) - goto invalid_message; - rp = erts_proc_lookup(to); + from = tuple[2]; + to = tuple[3]; + if (is_not_pid(to)) + goto invalid_message; + rp = erts_proc_lookup(to); - if (rp) { - erts_queue_dist_message(rp, 0, edep, ede_hfrag, token, am_Empty); + if (rp) { + erts_queue_dist_message(rp, 0, edep, ede_hfrag, token, from); } else if (ede_hfrag != NULL) { erts_free_dist_ext_copy(erts_get_dist_ext(ede_hfrag)); free_message_buffer(ede_hfrag); @@ -2421,12 +2546,12 @@ int erts_net_message(Port *prt, #ifdef ERTS_DIST_MSG_DBG dist_msg_dbg(edep, "ALIAS MSG", buf, orig_len); #endif - - to = tuple[3]; - if (is_not_ref(to)) - goto invalid_message; - - erts_proc_sig_send_dist_to_alias(to, edep, ede_hfrag, token); + from = tuple[2]; + to = tuple[3]; + if (is_not_ref(to)) { + goto invalid_message; + } + erts_proc_sig_send_dist_to_alias(from, to, edep, ede_hfrag, token); break; case DOP_PAYLOAD_MONITOR_P_EXIT: @@ -2862,12 +2987,10 @@ int erts_net_message(Port *prt, */ dist_pend_spawn_exit_save_child_result(result, ref, - dep->mld); + ede.mld); } - } - else if (lnk && !link_inserted) { - erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->dist, - am_noconnection, NIL); + } else if (lnk && !link_inserted) { + erts_proc_sig_send_link_exit_noconnection(&ldp->dist); } break; @@ -2908,6 +3031,9 @@ int erts_net_message(Port *prt, erts_kill_dist_connection(dep, conn_id); ERTS_CHK_NO_PROC_LOCKS; return -1; +data_error_runlock: + erts_de_runlock(dep); + goto data_error; } static int dsig_send_exit(ErtsDSigSendContext *ctx, Eterm ctl, Eterm msg) @@ -3013,11 +3139,17 @@ erts_dsig_prepare(ErtsDSigSendContext *ctx, goto fail; } - if (no_suspend && proc) { - if (erts_atomic32_read_acqb(&dep->qflgs) & ERTS_DE_QFLG_BUSY) { - res = ERTS_DSIG_PREP_WOULD_SUSPEND; - goto fail; - } + if (!proc || (proc->flags & F_ASYNC_DIST)) { + ctx->ignore_busy = !0; + } + else { + ctx->ignore_busy = 0; + if (no_suspend) { + if (de_qflags_read(dep) & ERTS_DE_QFLG_BUSY) { + res = ERTS_DSIG_PREP_WOULD_SUSPEND; + goto fail; + } + } } ctx->c_p = proc; @@ -3191,7 +3323,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx) + ((ctx->fragments - 1) * ERTS_DIST_FRAGMENT_HEADER_SIZE), ctx->fragments, - ctx->vlen); + ctx->vlen, + ctx->ignore_busy); ctx->alloced_fragments = ctx->fragments; /* Encode internal version of dist header */ ctx->dhdrp = ctx->extp; @@ -3342,20 +3475,23 @@ erts_dsig_send(ErtsDSigSendContext *ctx) ctx->fragments = 0; } else { - Sint qsize = erts_atomic_read_nob(&dep->qsize); + Sint qsize = (Sint) erts_atomic_read_nob(&dep->qsize); erts_aint32_t qflgs; ErtsProcList *plp = NULL; Eterm notify_proc = NIL; Sint obsz; - int fragments; + int fragments, empty_fill; /* Calculate how many fragments to send. This depends on the available space in the distr queue and the amount of remaining reductions. */ for (fragments = 0, obsz = 0; - fragments < ctx->fragments && - ((ctx->reds > 0 && (qsize + obsz) < erts_dist_buf_busy_limit) || - ctx->no_trap || ctx->no_suspend); + (fragments < ctx->fragments + && ((ctx->reds > 0 + && (ctx->ignore_busy + || (qsize + obsz < erts_dist_buf_busy_limit))) + || ctx->no_trap + || ctx->no_suspend)); fragments++) { #ifdef DEBUG int reds = 100; @@ -3371,33 +3507,27 @@ erts_dsig_send(ErtsDSigSendContext *ctx) (!ctx->no_trap && !ctx->no_suspend)); erts_mtx_lock(&dep->qlock); - qsize = erts_atomic_add_read_mb(&dep->qsize, (erts_aint_t) obsz); - ASSERT(qsize >= obsz); - qflgs = erts_atomic32_read_nob(&dep->qflgs); - if (!(qflgs & ERTS_DE_QFLG_BUSY) && qsize >= erts_dist_buf_busy_limit) { - erts_atomic32_read_bor_relb(&dep->qflgs, ERTS_DE_QFLG_BUSY); + update_qsizes(dep, &empty_fill, &qsize, obsz, + ctx->ignore_busy ? obsz : 0); + qflgs = de_qflags_read(dep); + if (!(qflgs & ERTS_DE_QFLG_BUSY) + && qsize >= erts_dist_buf_busy_limit) { + qflgs = de_qflags_read_set(dep, ERTS_DE_QFLG_BUSY); qflgs |= ERTS_DE_QFLG_BUSY; } - if (qsize == obsz && (qflgs & ERTS_DE_QFLG_REQ_INFO)) { - /* Previously empty queue and info requested... */ - qflgs = erts_atomic32_read_band_mb(&dep->qflgs, - ~ERTS_DE_QFLG_REQ_INFO); - if (qflgs & ERTS_DE_QFLG_REQ_INFO) { + if (empty_fill && is_internal_pid(dep->cid)) { + erts_aint32_t notify; + notify = erts_atomic32_xchg_mb(&dep->notify, + (erts_aint32_t) 0); + if (notify) { + /* + * Previously empty queue and notification + * requested... + */ notify_proc = dep->cid; ASSERT(is_internal_pid(notify_proc)); } - /* else: requester will send itself the message... */ - qflgs &= ~ERTS_DE_QFLG_REQ_INFO; } - if (!ctx->no_suspend && (qflgs & ERTS_DE_QFLG_BUSY)) { - erts_mtx_unlock(&dep->qlock); - - plp = erts_proclist_create(ctx->c_p); - - erts_suspend(ctx->c_p, ERTS_PROC_LOCK_MAIN, NULL); - suspended = 1; - erts_mtx_lock(&dep->qlock); - } ASSERT(fragments < 2 || (get_int64(&((char*)ctx->obuf->eiov->iov[1].iov_base)[10]) @@ -3415,30 +3545,41 @@ erts_dsig_send(ErtsDSigSendContext *ctx) ctx->obuf = &ctx->obuf[fragments]; } - if (!ctx->no_suspend) { - qflgs = erts_atomic32_read_nob(&dep->qflgs); - if (!(qflgs & ERTS_DE_QFLG_BUSY)) { - if (suspended) - resume = 1; /* was busy when we started, but isn't now */ + if ((qflgs & ERTS_DE_QFLG_BUSY) + && !ctx->ignore_busy + && !ctx->no_suspend) { + + erts_mtx_unlock(&dep->qlock); + + plp = erts_proclist_create(ctx->c_p); + + erts_suspend(ctx->c_p, ERTS_PROC_LOCK_MAIN, NULL); + suspended = 1; + + erts_mtx_lock(&dep->qlock); + + qflgs = de_qflags_read(dep); + if (qflgs & ERTS_DE_QFLG_BUSY) { + /* Enqueue suspended process on dist entry */ + ASSERT(plp); + erts_proclist_store_last(&dep->suspended, plp); + } + else { + resume = 1; /* was busy, but isn't now */ #ifdef USE_VM_PROBES - if (resume && DTRACE_ENABLED(dist_port_not_busy)) { - DTRACE_CHARBUF(port_str, 64); - DTRACE_CHARBUF(remote_str, 64); - - erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), - "%T", cid); - erts_snprintf(remote_str, sizeof(DTRACE_CHARBUF_NAME(remote_str)), - "%T", dep->sysname); - DTRACE3(dist_port_not_busy, erts_this_node_sysname, - port_str, remote_str); - } + if (resume && DTRACE_ENABLED(dist_port_not_busy)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + + erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), + "%T", cid); + erts_snprintf(remote_str, sizeof(DTRACE_CHARBUF_NAME(remote_str)), + "%T", dep->sysname); + DTRACE3(dist_port_not_busy, erts_this_node_sysname, + port_str, remote_str); + } #endif - } - else { - /* Enqueue suspended process on dist entry */ - ASSERT(plp); - erts_proclist_store_last(&dep->suspended, plp); - } + } } erts_mtx_unlock(&dep->qlock); @@ -3656,13 +3797,64 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) ? ((Sint) 1) \ : ((((Sint) (SZ)) >> 10) & ((Sint) ERTS_PORT_REDS_MASK__))) +#ifndef DEBUG +#define ERTS_DBG_CHK_DIST_QSIZE(DEP, PRT) +#else +#define ERTS_DBG_CHK_DIST_QSIZE(DEP, PRT) \ + dbg_check_dist_qsize((DEP), (PRT)) + +static void +dbg_check_dist_qsize(DistEntry *dep, Port *prt) +{ + int ix; + Sint sz = 0, isz = 0, tqsz, qsz; + ErtsDistOutputBuf *qs[2]; + + ERTS_LC_ASSERT(dep && erts_lc_mtx_is_locked(&dep->qlock)); + ASSERT(prt && erts_lc_is_port_locked(prt)); + ERTS_LC_ASSERT((erts_atomic32_read_nob(&prt->sched.flags) + & ERTS_PTS_FLG_EXIT) + || prt->common.id == dep->cid); + + tqsz = erts_atomic_read_nob(&dep->total_qsize); + qsz = erts_atomic_read_nob(&dep->qsize); + + ASSERT(tqsz >= 0); + ASSERT(qsz >= 0); + ASSERT(tqsz >= qsz); + + qs[0] = dep->out_queue.first; + qs[1] = dep->finalized_out_queue.first; + + for (ix = 0; ix < sizeof(qs)/sizeof(qs[0]); ix++) { + ErtsDistOutputBuf *obuf = qs[ix]; + while (obuf) { + add_obuf_sizes(obuf, &sz, &isz); + obuf = obuf->next; + } + } + + ASSERT(tqsz == sz); + ASSERT(qsz == sz - isz); +} + +#endif + int erts_dist_command(Port *prt, int initial_reds) { Sint reds = initial_reds - ERTS_PORT_REDS_DIST_CMD_START; enum dist_entry_state state; Uint64 flags; - Sint qsize, obufsize = 0; + /* + * 'obufsize' and 'ignore_obufsize' contains the number of bytes removed + * from the queue which will be updated (in dep->total_qsize and + * dep->qsize) before we return from this function. Note that + * 'obufsize' and 'ignore_obufsize' may be negative if we added to the + * queue size. This may occur since finalization of a buffer may increase + * buffer size. + */ + Sint qsize, obufsize = 0, ignore_obufsize = 0; ErtsDistOutputQueue oq, foq; DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY); Uint (*send)(Port *prt, ErtsDistOutputBuf *obuf); @@ -3698,6 +3890,7 @@ erts_dist_command(Port *prt, int initial_reds) */ erts_mtx_lock(&dep->qlock); + ERTS_DBG_CHK_DIST_QSIZE(dep, prt); oq.first = dep->out_queue.first; oq.last = dep->out_queue.last; dep->out_queue.first = NULL; @@ -3709,23 +3902,6 @@ erts_dist_command(Port *prt, int initial_reds) dep->finalized_out_queue.first = NULL; dep->finalized_out_queue.last = NULL; -#ifdef DEBUG - { - Uint sz = 0; - ErtsDistOutputBuf *curr = oq.first; - while (curr) { - sz += size_obuf(curr); - curr = curr->next; - } - curr = foq.first; - while (curr) { - sz += size_obuf(curr); - curr = curr->next; - } - ASSERT(sz <= erts_atomic_read_nob(&dep->qsize)); - } -#endif - sched_flags = erts_atomic32_read_nob(&prt->sched.flags); if (reds < 0) @@ -3736,7 +3912,7 @@ erts_dist_command(Port *prt, int initial_reds) do { Uint size; ErtsDistOutputBuf *fob; - obufsize += size_obuf(foq.first); + add_obuf_sizes(foq.first, &obufsize, &ignore_obufsize); size = (*send)(prt, foq.first); erts_atomic64_inc_nob(&dep->out); esdp->io.out += (Uint64) size; @@ -3764,9 +3940,9 @@ erts_dist_command(Port *prt, int initial_reds) ob = oq.first; ASSERT(ob); do { - obufsize += size_obuf(ob); + add_obuf_sizes(ob, &obufsize, &ignore_obufsize); reds = erts_encode_ext_dist_header_finalize(ob, dep, flags, reds); - obufsize -= size_obuf(ob); + subtract_obuf_sizes(ob, &obufsize, &ignore_obufsize); if (reds < 0) break; /* finalize needs to be restarted... */ last_finalized = ob; @@ -3804,12 +3980,11 @@ erts_dist_command(Port *prt, int initial_reds) int preempt = 0; while (oq.first && !preempt) { ErtsDistOutputBuf *fob; - Uint size, obsz; - obufsize += size_obuf(oq.first); + Uint size; + add_obuf_sizes(oq.first, &obufsize, &ignore_obufsize); reds = erts_encode_ext_dist_header_finalize(oq.first, dep, flags, reds); - obsz = size_obuf(oq.first); - obufsize -= obsz; if (reds < 0) { /* finalize needs to be restarted... */ + subtract_obuf_sizes(oq.first, &obufsize, &ignore_obufsize); preempt = 1; break; } @@ -3818,7 +3993,6 @@ erts_dist_command(Port *prt, int initial_reds) esdp->io.out += (Uint64) size; reds -= ERTS_PORT_REDS_DIST_CMD_DATA(size); fob = oq.first; - obufsize += obsz; oq.first = oq.first->next; free_dist_obuf(fob, !0); sched_flags = erts_atomic32_read_nob(&prt->sched.flags); @@ -3844,18 +4018,17 @@ erts_dist_command(Port *prt, int initial_reds) /* * Everything that was buffered when we started have now been * written to the port. If port isn't busy but dist entry is - * and we havn't got too muched queued on dist entry, set + * and we haven't got too muched queued on dist entry, set * dist entry in a non-busy state and resume suspended * processes. */ erts_mtx_lock(&dep->qlock); - de_busy = !!(erts_atomic32_read_nob(&dep->qflgs) & ERTS_DE_QFLG_BUSY); - qsize = (Sint) erts_atomic_add_read_nob(&dep->qsize, - (erts_aint_t) -obufsize); - ASSERT(qsize >= 0); - obufsize = 0; + de_busy = !!(de_qflags_read(dep) & ERTS_DE_QFLG_BUSY); + update_qsizes(dep, NULL, &qsize, -obufsize, -ignore_obufsize); + obufsize = ignore_obufsize = 0; if (!(sched_flags & ERTS_PTS_FLG_BUSY_PORT) - && de_busy && qsize < erts_dist_buf_busy_limit) { + && de_busy + && qsize < erts_dist_buf_busy_limit) { int resumed; ErtsProcList *suspendees = get_suspended_on_de(dep, ERTS_DE_QFLG_BUSY); erts_mtx_unlock(&dep->qlock); @@ -3871,17 +4044,7 @@ erts_dist_command(Port *prt, int initial_reds) done: - if (obufsize != 0) { - erts_mtx_lock(&dep->qlock); -#ifdef DEBUG - qsize = (Sint) erts_atomic_add_read_nob(&dep->qsize, - (erts_aint_t) -obufsize); - ASSERT(qsize >= 0); -#else - erts_atomic_add_nob(&dep->qsize, (erts_aint_t) -obufsize); -#endif - erts_mtx_unlock(&dep->qlock); - } + ASSERT(!ignore_obufsize || obufsize); ASSERT(!!foq.first == !!foq.last); ASSERT(!dep->finalized_out_queue.first); @@ -3892,7 +4055,21 @@ erts_dist_command(Port *prt, int initial_reds) dep->finalized_out_queue.last = foq.last; } - /* Avoid wrapping reduction counter... */ + if (obufsize != 0) { + erts_mtx_lock(&dep->qlock); + update_qsizes(dep, NULL, NULL, -obufsize, -ignore_obufsize); + ERTS_DBG_CHK_DIST_QSIZE(dep, prt); + erts_mtx_unlock(&dep->qlock); + } +#ifdef DEBUG + else { + erts_mtx_lock(&dep->qlock); + ERTS_DBG_CHK_DIST_QSIZE(dep, prt); + erts_mtx_unlock(&dep->qlock); + } +#endif + + /* Avoid wrapping reduction counter... */ if (reds < INT_MIN/2) reds = INT_MIN/2; @@ -3922,7 +4099,7 @@ erts_dist_command(Port *prt, int initial_reds) while (oq.first) { ErtsDistOutputBuf *fob = oq.first; oq.first = oq.first->next; - obufsize += size_obuf(fob); + add_obuf_sizes(fob, &obufsize, &ignore_obufsize); free_dist_obuf(fob, !0); } @@ -3931,14 +4108,15 @@ erts_dist_command(Port *prt, int initial_reds) } else { if (oq.first) { + erts_mtx_lock(&dep->qlock); + update_qsizes(dep, NULL, NULL, -obufsize, -ignore_obufsize); + obufsize = ignore_obufsize = 0; + /* - * Unhandle buffers need to be put back first + * Unhandled buffers need to be put back first * in out_queue. */ - erts_mtx_lock(&dep->qlock); - erts_atomic_add_nob(&dep->qsize, -obufsize); - obufsize = 0; - oq.last->next = dep->out_queue.first; + oq.last->next = dep->out_queue.first; dep->out_queue.first = oq.first; if (!dep->out_queue.last) dep->out_queue.last = oq.last; @@ -3954,7 +4132,7 @@ BIF_RETTYPE dist_ctrl_get_data_notification_1(BIF_ALIST_1) { DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P); - erts_aint32_t qflgs; + erts_aint32_t notify; erts_aint_t qsize; Eterm receiver = NIL; Uint32 conn_id; @@ -3967,7 +4145,7 @@ dist_ctrl_get_data_notification_1(BIF_ALIST_1) /* * Caller is the only one that can consume from this queue - * and the only one that can set the req-info flag... + * and the only one that can set the notify field... */ erts_de_rlock(dep); @@ -3979,23 +4157,21 @@ dist_ctrl_get_data_notification_1(BIF_ALIST_1) ASSERT(dep->cid == BIF_P->common.id); - qflgs = erts_atomic32_read_nob(&dep->qflgs); + notify = erts_atomic32_read_nob(&dep->notify); - if (!(qflgs & ERTS_DE_QFLG_REQ_INFO)) { + if (!notify) { ERTS_THR_READ_MEMORY_BARRIER; - qsize = erts_atomic_read_nob(&dep->qsize); + qsize = erts_atomic_read_nob(&dep->total_qsize); ASSERT(qsize >= 0); if (qsize > 0) receiver = BIF_P->common.id; /* Notify ourselves... */ - else { /* Empty queue; set req-info flag... */ - qflgs = erts_atomic32_read_bor_mb(&dep->qflgs, - ERTS_DE_QFLG_REQ_INFO); - qsize = erts_atomic_read_nob(&dep->qsize); + else { /* Empty queue; set the notify field... */ + notify = erts_atomic32_xchg_mb(&dep->notify, (erts_aint32_t) !0); + qsize = erts_atomic_read_nob(&dep->total_qsize); ASSERT(qsize >= 0); if (qsize > 0) { - qflgs = erts_atomic32_read_band_mb(&dep->qflgs, - ~ERTS_DE_QFLG_REQ_INFO); - if (qflgs & ERTS_DE_QFLG_REQ_INFO) + notify = erts_atomic32_xchg_mb(&dep->notify, (erts_aint32_t) 0); + if (notify) receiver = BIF_P->common.id; /* Notify ourselves... */ /* else: someone else will notify us... */ } @@ -4183,7 +4359,7 @@ dist_get_stat_1(BIF_ALIST_1) } read = (Sint64) erts_atomic64_read_nob(&dep->in); write = (Sint64) erts_atomic64_read_nob(&dep->out); - pend = (Sint64) erts_atomic_read_nob(&dep->qsize); + pend = (Sint64) erts_atomic_read_nob(&dep->total_qsize); erts_de_runlock(dep); @@ -4238,10 +4414,19 @@ dist_ctrl_get_data_1(BIF_ALIST_1) { DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P); const Sint initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); - Sint reds = initial_reds, obufsize = 0, ix, vlen; + Sint reds = initial_reds, ix, vlen; + /* + * 'obufsize' and 'ignore_obufsize' contains the number of bytes removed + * from the queue which will be updated (in dep->total_qsize and + * dep->qsize) before we return from this function. Note that + * 'obufsize' and 'ignore_obufsize' may be negative if we added to the + * queue size. This may occur since finalization of a buffer may increase + * buffer size. + */ + Sint obufsize = 0, ignore_obufsize = 0; ErtsDistOutputBuf *obuf; Eterm *hp, res; - erts_aint_t qsize; + Sint qsize; Uint32 conn_id, get_size; Uint hsz = 0, data_sz; SysIOVec *iov; @@ -4280,7 +4465,7 @@ dist_ctrl_get_data_1(BIF_ALIST_1) { if (!dep->tmp_out_queue.first) { ASSERT(!dep->tmp_out_queue.last); - qsize = erts_atomic_read_acqb(&dep->qsize); + qsize = (Sint) erts_atomic_read_acqb(&dep->total_qsize); if (qsize > 0) { erts_mtx_lock(&dep->qlock); dep->tmp_out_queue.first = dep->out_queue.first; @@ -4299,13 +4484,16 @@ dist_ctrl_get_data_1(BIF_ALIST_1) } obuf = dep->tmp_out_queue.first; - obufsize += size_obuf(obuf); + add_obuf_sizes(obuf, &obufsize, &ignore_obufsize); reds = erts_encode_ext_dist_header_finalize(obuf, dep, dep->dflags, reds); - obufsize -= size_obuf(obuf); + subtract_obuf_sizes(obuf, &obufsize, &ignore_obufsize); if (reds < 0) { /* finalize needs to be restarted... */ erts_de_runlock(dep); - if (obufsize) - erts_atomic_add_nob(&dep->qsize, (erts_aint_t) -obufsize); + if (obufsize) { + erts_mtx_lock(&dep->qlock); + update_qsizes(dep, NULL, NULL, -obufsize, -ignore_obufsize); + erts_mtx_unlock(&dep->qlock); + } ERTS_BIF_YIELD1(BIF_TRAP_EXPORT(BIF_dist_ctrl_get_data_1), BIF_P, BIF_ARG_1); } @@ -4386,16 +4574,18 @@ dist_ctrl_get_data_1(BIF_ALIST_1) hp += 2; } - obufsize += size_obuf(obuf); + add_obuf_sizes(obuf, &obufsize, &ignore_obufsize); - qsize = erts_atomic_add_read_nob(&dep->qsize, (erts_aint_t) -obufsize); + erts_mtx_lock(&dep->qlock); - ASSERT(qsize >= 0); + update_qsizes(dep, NULL, &qsize, -obufsize, -ignore_obufsize); - if (qsize < erts_dist_buf_busy_limit/2 - && (erts_atomic32_read_acqb(&dep->qflgs) & ERTS_DE_QFLG_BUSY)) { + if (qsize >= erts_dist_buf_busy_limit/2 + || !(de_qflags_read(dep) & ERTS_DE_QFLG_BUSY)) { + erts_mtx_unlock(&dep->qlock); + } + else { ErtsProcList *resume_procs = NULL; - erts_mtx_lock(&dep->qlock); resume_procs = get_suspended_on_de(dep, ERTS_DE_QFLG_BUSY); erts_mtx_unlock(&dep->qlock); if (resume_procs) { @@ -4450,8 +4640,8 @@ static void kill_connection(DistEntry *dep) dep->state = ERTS_DE_STATE_EXITING; erts_mtx_lock(&dep->qlock); - ASSERT(!(erts_atomic32_read_nob(&dep->qflgs) & ERTS_DE_QFLG_EXIT)); - erts_atomic32_read_bor_nob(&dep->qflgs, ERTS_DE_QFLG_EXIT); + ASSERT(!(de_qflags_read(dep) & ERTS_DE_QFLG_EXIT)); + de_qflags_read_set(dep, ERTS_DE_QFLG_EXIT); erts_mtx_unlock(&dep->qlock); if (is_internal_port(dep->cid)) @@ -4665,13 +4855,13 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) if (!is_node_name_atom(BIF_ARG_1)) goto error; - if (BIF_ARG_1 == am_Noname) /* cant use this name !! */ + if (BIF_ARG_1 == am_Noname) /* can't use this name !! */ goto error; if (erts_is_alive) /* must not be alive! */ goto error; /* Check that all trap functions are defined !! */ - if (dmonitor_node_trap->addresses[0] == NULL) { + if (dmonitor_node_trap->dispatch.addresses[0] == NULL) { goto error; } @@ -4694,7 +4884,7 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) erts_thr_progress_block(); success = (!ERTS_PROC_IS_EXITING(net_kernel) - & !ERTS_PROC_GET_DIST_ENTRY(net_kernel)); + && !ERTS_PROC_GET_DIST_ENTRY(net_kernel)); if (success) { /* * Ensure we don't use a nodename-creation pair with @@ -4713,7 +4903,8 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) erts_set_this_node(BIF_ARG_1, (Uint32) creation); erts_this_dist_entry->creation = creation; erts_is_alive = 1; - send_nodes_mon_msgs(NULL, am_nodeup, BIF_ARG_1, am_visible, NIL); + send_nodes_mon_msgs(NULL, am_nodeup, BIF_ARG_1, ~((Uint32) 0), + am_visible, NIL); erts_proc_lock(net_kernel, ERTS_PROC_LOCKS_ALL); /* By setting F_DISTRIBUTION on net_kernel, @@ -4745,6 +4936,36 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) BIF_ERROR(BIF_P, BADARG); } +/* + * erts_is_this_node_alive() returns the same result as erlang:is_alive() + */ +int +erts_is_this_node_alive(void) +{ + Eterm tmp_heap[3]; + Eterm dyn_name_key, dyn_name_value; + + /* + * erts_is_alive is only non zero if a node name has been set. Not if + * dynamic node name has been enabled. + */ + if (erts_is_alive) { + return !0; + } + + /* + * A persistent term with key '{erts_internal, dynamic_node_name}' has been + * set if dynamic node name has been enabled. + */ + dyn_name_key = TUPLE2(&tmp_heap[0], am_erts_internal, am_dynamic_node_name); + dyn_name_value = erts_persistent_term_get(dyn_name_key); + if (is_value(dyn_name_value) && dyn_name_value != am_false) { + return !0; + } + + return 0; +} + /* * erts_internal:create_dist_channel/4 is used by * erlang:setnode/3. @@ -4755,7 +4976,6 @@ typedef struct { int de_locked; Uint64 dflags; Uint32 creation; - Uint version; Eterm setup_pid; Process *net_kernel; } ErtsSetupConnDistCtrl; @@ -4774,7 +4994,6 @@ BIF_RETTYPE erts_internal_create_dist_channel_3(BIF_ALIST_3) { BIF_RETTYPE ret; Uint64 flags; - Uint version; Uint32 creation; Eterm *hp, res_tag = THE_NON_VALUE, res = THE_NON_VALUE; DistEntry *dep = NULL; @@ -4807,7 +5026,7 @@ BIF_RETTYPE erts_internal_create_dist_channel_3(BIF_ALIST_3) if (!is_internal_port(BIF_ARG_2) && !is_internal_pid(BIF_ARG_2)) goto badarg; - if (!is_tuple_arity(BIF_ARG_3, 3)) + if (!is_tuple_arity(BIF_ARG_3, 2)) goto badarg; tpl = tuple_val(BIF_ARG_3); @@ -4816,16 +5035,8 @@ BIF_RETTYPE erts_internal_create_dist_channel_3(BIF_ALIST_3) if (!term_to_Uint64(tpl[1], &flags)) goto badarg; - /* Version... */ - if (!is_small(tpl[2])) - goto badarg; - version = unsigned_val(tpl[2]); - - if (version == 0) - goto badarg; - /* Creation... */ - if (!term_to_Uint32(tpl[3], &creation)) + if (!term_to_Uint32(tpl[2], &creation)) goto badarg; if (~flags & DFLAG_DIST_MANDATORY) { @@ -4870,7 +5081,6 @@ BIF_RETTYPE erts_internal_create_dist_channel_3(BIF_ALIST_3) scdc.de_locked = 1; scdc.dflags = flags; scdc.creation = creation; - scdc.version = version; scdc.setup_pid = BIF_P->common.id; scdc.net_kernel = net_kernel; @@ -4900,7 +5110,6 @@ BIF_RETTYPE erts_internal_create_dist_channel_3(BIF_ALIST_3) scdcp->de_locked = 0; scdcp->dflags = flags; scdcp->creation = creation; - scdcp->version = version; scdcp->setup_pid = BIF_P->common.id; scdcp->net_kernel = net_kernel; @@ -5045,7 +5254,6 @@ setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep, Process *net_kernel) { Eterm notify_proc = NIL; - erts_aint32_t qflgs; ErtsProcLocks nk_locks; int success = 0; @@ -5081,17 +5289,18 @@ setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep, erts_set_dist_entry_connected(dep, ctrlr, flags); notify_proc = NIL; - if (erts_atomic_read_nob(&dep->qsize)) { + if (erts_atomic_read_nob(&dep->total_qsize)) { if (is_internal_port(dep->cid)) { erts_schedule_dist_command(NULL, dep); } else { + erts_aint32_t notify; ERTS_THR_READ_MEMORY_BARRIER; - qflgs = erts_atomic32_read_nob(&dep->qflgs); - if (qflgs & ERTS_DE_QFLG_REQ_INFO) { - qflgs = erts_atomic32_read_band_mb(&dep->qflgs, - ~ERTS_DE_QFLG_REQ_INFO); - if (qflgs & ERTS_DE_QFLG_REQ_INFO) { + notify = erts_atomic32_read_nob(&dep->notify); + if (notify) { + notify = erts_atomic32_xchg_mb(&dep->notify, + (erts_aint32_t) 0); + if (notify) { notify_proc = dep->cid; ASSERT(is_internal_pid(notify_proc)); } @@ -5109,6 +5318,7 @@ setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep, send_nodes_mon_msgs(c_p, am_nodeup, dep->sysname, + dep->connection_id, flags & DFLAG_PUBLISHED ? am_visible : am_hidden, NIL); @@ -5310,6 +5520,7 @@ Sint erts_abort_pending_connection_rwunlock(DistEntry* dep, ASSERT(!dep->finalized_out_queue.first); resume_procs = get_suspended_on_de(dep, ERTS_DE_QFLGS_ALL); erts_mtx_unlock(&dep->qlock); + erts_atomic32_set_relb(&dep->notify, 0); erts_atomic_set_nob(&dep->dist_cmd_scheduled, 0); dep->send = NULL; @@ -5391,6 +5602,9 @@ int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks) return 0; } + if (proc == net_kernel) + nk_locks |= ERTS_PROC_LOCK_MAIN; + /* * Send {auto_connect, Node, DHandle} to net_kernel */ @@ -5401,6 +5615,10 @@ int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks) msg = TUPLE3(hp, am_auto_connect, dep->sysname, dhandle); ERL_MESSAGE_TOKEN(mp) = am_undefined; erts_queue_proc_message(proc, net_kernel, nk_locks, mp, msg); + + if (proc == net_kernel) + nk_locks &= ~ERTS_PROC_LOCK_MAIN; + erts_proc_unlock(net_kernel, nk_locks); } @@ -5693,10 +5911,10 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) ok_result = ref; else { Eterm *hp = HAlloc(BIF_P, 3); - Eterm bool = ((monitor_oflags & ERTS_ML_FLG_SPAWN_MONITOR) + Eterm spawns_monitor = ((monitor_oflags & ERTS_ML_FLG_SPAWN_MONITOR) ? am_true : am_false); ASSERT(BIF_ARG_4 == am_spawn_opt); - ok_result = TUPLE2(hp, ref, bool); + ok_result = TUPLE2(hp, ref, spawns_monitor); } code = erts_dsig_prepare(&ctx, dep, @@ -5835,7 +6053,8 @@ BIF_RETTYPE erts_internal_dist_spawn_request_4(BIF_ALIST_4) /* node(Object) -> Node */ BIF_RETTYPE node_1(BIF_ALIST_1) -{ +{ + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_not_node_container(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); BIF_RET(node_container_node_name(BIF_ARG_1)); @@ -5849,38 +6068,54 @@ BIF_RETTYPE node_0(BIF_ALIST_0) BIF_RET(erts_this_dist_entry->sysname); } - /**********************************************************************/ /* nodes() -> [ Node ] */ -#if 0 /* Done in erlang.erl instead. */ +static BIF_RETTYPE nodes(Process *c_p, Eterm node_types, Eterm options); + BIF_RETTYPE nodes_0(BIF_ALIST_0) { - return nodes_1(BIF_P, am_visible); + return nodes(BIF_P, am_visible, THE_NON_VALUE); } -#endif - BIF_RETTYPE nodes_1(BIF_ALIST_1) { + return nodes(BIF_P, BIF_ARG_1, THE_NON_VALUE); +} + +BIF_RETTYPE nodes_2(BIF_ALIST_2) +{ + return nodes(BIF_P, BIF_ARG_1, BIF_ARG_2); +} + +typedef struct { + Eterm name; + Eterm type; + Uint32 cid; +} ErtsNodeInfo; + +static BIF_RETTYPE +nodes(Process *c_p, Eterm node_types, Eterm options) +{ + BIF_RETTYPE ret_val; + ErtsNodeInfo *eni, *eni_start = NULL, *eni_end; Eterm result; - int length; - Eterm* hp; + Uint length; int not_connected = 0; int visible = 0; int hidden = 0; int this = 0; - DeclareTmpHeap(buf,2,BIF_P); /* For one cons-cell */ + int node_type = 0; + int connection_id = 0; + int xinfo = 0; + Eterm tmp_heap[2]; /* For one cons-cell */ DistEntry *dep; - Eterm arg_list = BIF_ARG_1; -#ifdef DEBUG - Eterm* endp; -#endif - - UseTmpHeap(2,BIF_P); + Eterm arg_list; - if (is_atom(BIF_ARG_1)) - arg_list = CONS(buf, BIF_ARG_1, NIL); + if (is_atom(node_types)) + arg_list = CONS(&tmp_heap[0], node_types, NIL); + else + arg_list = node_types; while (is_list(arg_list)) { switch(CAR(list_val(arg_list))) { @@ -5889,13 +6124,43 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1) case am_known: visible = hidden = not_connected = this = 1; break; case am_this: this = 1; break; case am_connected: visible = hidden = 1; break; - default: goto error; break; + default: goto badarg; break; } arg_list = CDR(list_val(arg_list)); } if (is_not_nil(arg_list)) { - goto error; + goto badarg; + } + + if (is_value(options)) { + if (is_not_map(options)) { + goto badarg; + } + else { + Sint no_opts = 0; + const Eterm *conn_idp = erts_maps_get(am_connection_id, options); + const Eterm *node_typep = erts_maps_get(am_node_type, options); + if (conn_idp) { + switch (*conn_idp) { + case am_true: connection_id = !0; break; + case am_false: connection_id = 0; break; + default: goto badarg; + } + no_opts++; + } + if (node_typep) { + switch (*node_typep) { + case am_true: node_type = !0; break; + case am_false: node_type = 0; break; + default: goto badarg; + } + no_opts++; + } + if (no_opts != erts_map_size(options)) + goto badarg; /* got invalid options... */ + xinfo = !0; + } } length = 0; @@ -5920,59 +6185,130 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1) if (length == 0) { erts_rwmtx_runlock(&erts_dist_table_rwmtx); - goto done; + ERTS_BIF_PREP_RET(ret_val, NIL); + return ret_val; } - hp = HAlloc(BIF_P, 2*length); + eni_start = eni = erts_alloc(ERTS_ALC_T_TMP, sizeof(ErtsNodeInfo)*length); -#ifdef DEBUG - endp = hp + length*2; -#endif - if(not_connected) { - for(dep = erts_not_connected_dist_entries; dep; dep = dep->next) { - if (dep != erts_this_dist_entry) { - result = CONS(hp, dep->sysname, result); - hp += 2; - } + if (this) { + eni->name = erts_this_dist_entry->sysname; + eni->type = am_this; + eni->cid = ~((Uint32) 0); + eni++; + } + + if (visible) { + for (dep = erts_visible_dist_entries; dep; dep = dep->next) { + eni->name = dep->sysname; + eni->type = am_visible; + eni->cid = dep->connection_id; + ASSERT(eni->cid >= 0); + eni++; } - for(dep = erts_pending_dist_entries; dep; dep = dep->next) { - result = CONS(hp, dep->sysname, result); - hp += 2; - } } - if(hidden) - for(dep = erts_hidden_dist_entries; dep; dep = dep->next) { - result = CONS(hp, dep->sysname, result); - hp += 2; - } - if(visible) - for(dep = erts_visible_dist_entries; dep; dep = dep->next) { - result = CONS(hp, dep->sysname, result); - hp += 2; - } - if(this) { - result = CONS(hp, erts_this_dist_entry->sysname, result); - hp += 2; + + if (hidden) { + for (dep = erts_hidden_dist_entries; dep; dep = dep->next) { + eni->name = dep->sysname; + eni->type = am_hidden; + eni->cid = dep->connection_id; + eni++; + } + } + + if (not_connected) { + for (dep = erts_not_connected_dist_entries; dep; dep = dep->next) { + if (dep != erts_this_dist_entry) { + eni->name = dep->sysname; + eni->type = am_known; + eni->cid = ~((Uint32) 0); + eni++; + } + } + for (dep = erts_pending_dist_entries; dep; dep = dep->next) { + eni->name = dep->sysname; + eni->type = am_known; + eni->cid = ~((Uint32) 0); + eni++; + } } - ASSERT(endp == hp); + erts_rwmtx_runlock(&erts_dist_table_rwmtx); -done: - UnUseTmpHeap(2,BIF_P); - BIF_RET(result); + eni_end = eni; -error: - UnUseTmpHeap(2,BIF_P); - BIF_ERROR(BIF_P,BADARG); -} + result = NIL; + if (!xinfo) { + Eterm *hp = HAlloc(c_p, 2*length); + for (eni = eni_start; eni < eni_end; eni++) { + result = CONS(hp, eni->name, result); + hp += 2; + } + } + else { + Eterm ks[2], *hp; + Uint map_size = 0, el_xtra, xtra; + ErtsHeapFactory hfact; -/**********************************************************************/ -/* is_alive() -> Bool */ + erts_factory_proc_init(&hfact, c_p); -BIF_RETTYPE is_alive_0(BIF_ALIST_0) -{ - Eterm res = erts_is_alive ? am_true : am_false; - BIF_RET(res); + if (connection_id) { + ks[map_size++] = am_connection_id; + } + if (node_type) { + ks[map_size++] = am_node_type; + } + + el_xtra = 3 + 2 + MAP_HEADER_FLATMAP_SZ + map_size; + xtra = length*el_xtra; + + for (eni = eni_start; eni < eni_end; eni++) { + Eterm vs[2], info_map, tuple; + map_size = 0; + if (connection_id) { + Eterm cid; + if (eni->cid == ~((Uint32) 0)) + cid = am_undefined; + else if (IS_USMALL(0, (Uint) eni->cid)) + cid = make_small((Uint) eni->cid); + else { + hp = erts_produce_heap(&hfact, BIG_UINT_HEAP_SIZE, xtra); + cid = uint_to_big((Uint) eni->cid, hp); + } + vs[map_size++] = cid; + } + if (node_type) { + vs[map_size++] = eni->type; + } + + info_map = erts_map_from_ks_and_vs(&hfact, ks, vs, map_size); + ASSERT(is_value(info_map)); + + hp = erts_produce_heap(&hfact, 3+2, xtra); + + tuple = TUPLE2(hp, eni->name, info_map); + hp += 3; + result = CONS(hp, tuple, result); + xtra -= el_xtra; + } + + erts_factory_close(&hfact); + } + + erts_free(ERTS_ALC_T_TMP, (void *) eni_start); + + if (length > 10) { + Uint reds = length / 10; + BUMP_REDS(c_p, reds); + } + + ERTS_BIF_PREP_RET(ret_val, result); + return ret_val; + +badarg: + ERTS_BIF_PREP_ERROR(ret_val, c_p, BADARG); + return ret_val; } /**********************************************************************/ @@ -6008,7 +6344,7 @@ monitor_node(Process* p, Eterm Node, Eterm Bool, Eterm Options) if (is_not_atom(Node)) goto badarg; - if (erts_this_node->sysname == am_Noname && Node != am_Noname) { + if (Node != am_Noname && !erts_is_this_node_alive()) { ERTS_BIF_PREP_ERROR(ret, p, EXC_NOTALIVE); goto do_return; } @@ -6198,6 +6534,8 @@ BIF_RETTYPE net_kernel_dflag_unicode_io_1(BIF_ALIST_1) #define ERTS_NODES_MON_OPT_TYPE_VISIBLE (((Uint16) 1) << 0) #define ERTS_NODES_MON_OPT_TYPE_HIDDEN (((Uint16) 1) << 1) #define ERTS_NODES_MON_OPT_DOWN_REASON (((Uint16) 1) << 2) +#define ERTS_NODES_MON_OPT_INFO_MAP (((Uint16) 1) << 3) +#define ERTS_NODES_MON_OPT_CONN_ID (((Uint16) 1) << 4) #define ERTS_NODES_MON_OPT_TYPES \ (ERTS_NODES_MON_OPT_TYPE_VISIBLE|ERTS_NODES_MON_OPT_TYPE_HIDDEN) @@ -6227,10 +6565,10 @@ init_nodes_monitors(void) } Eterm -erts_monitor_nodes(Process *c_p, Eterm on, Eterm olist) +erts_monitor_nodes(Process *c_p, Eterm on, Eterm options) { - Eterm key, old_value, opts_list = olist; - Uint opts = (Uint) 0; + Eterm key, old_value; + Uint opts = (Uint) ERTS_NODES_MON_OPT_INFO_MAP; ASSERT(c_p); ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN); @@ -6238,55 +6576,63 @@ erts_monitor_nodes(Process *c_p, Eterm on, Eterm olist) if (on != am_true && on != am_false) return THE_NON_VALUE; - if (is_not_nil(opts_list)) { - int all = 0, visible = 0, hidden = 0; - - while (is_list(opts_list)) { - Eterm *cp = list_val(opts_list); - Eterm opt = CAR(cp); - opts_list = CDR(cp); - if (opt == am_nodedown_reason) + if (is_nil(options)) { + opts &= ~ERTS_NODES_MON_OPT_INFO_MAP; + } + else if (is_not_map(options)) { + return THE_NON_VALUE; + } + else { + Sint no_opts = 0; + const Eterm *l = erts_maps_get(am_list, options); + const Eterm *cid = erts_maps_get(am_connection_id, options); + const Eterm *nt = erts_maps_get(am_node_type, options); + const Eterm *nr = erts_maps_get(am_nodedown_reason, options); + if (l) { + if (*l == am_true) { + opts &= ~ERTS_NODES_MON_OPT_INFO_MAP; + } + else { + return THE_NON_VALUE; + } + no_opts++; + } + if (cid) { + if (*cid == am_true) { + opts |= ERTS_NODES_MON_OPT_CONN_ID; + } + else if (*cid != am_false) { + return THE_NON_VALUE; + } + no_opts++; + } + if (nt) { + switch (*nt) { + case am_visible: + opts |= ERTS_NODES_MON_OPT_TYPE_VISIBLE; + break; + case am_hidden: + opts |= ERTS_NODES_MON_OPT_TYPE_HIDDEN; + break; + case am_all: + opts |= ERTS_NODES_MON_OPT_TYPES; + break; + default: + return THE_NON_VALUE; + } + no_opts++; + } + if (nr) { + if (*nr == am_true) { opts |= ERTS_NODES_MON_OPT_DOWN_REASON; - else if (is_tuple(opt)) { - Eterm* tp = tuple_val(opt); - if (arityval(tp[0]) != 2) - return THE_NON_VALUE; - switch (tp[1]) { - case am_node_type: - switch (tp[2]) { - case am_visible: - if (hidden || all) - return THE_NON_VALUE; - opts |= ERTS_NODES_MON_OPT_TYPE_VISIBLE; - visible = 1; - break; - case am_hidden: - if (visible || all) - return THE_NON_VALUE; - opts |= ERTS_NODES_MON_OPT_TYPE_HIDDEN; - hidden = 1; - break; - case am_all: - if (visible || hidden) - return THE_NON_VALUE; - opts |= ERTS_NODES_MON_OPT_TYPES; - all = 1; - break; - default: - return THE_NON_VALUE; - } - break; - default: - return THE_NON_VALUE; - } - } - else { - return THE_NON_VALUE; - } - } - - if (is_not_nil(opts_list)) - return THE_NON_VALUE; + } + else if (*nr != am_false) { + return THE_NON_VALUE; + } + no_opts++; + } + if (no_opts != erts_map_size(options)) + return THE_NON_VALUE; /* got invalid options... */ } key = make_small(opts); @@ -6379,8 +6725,24 @@ save_nodes_monitor(ErtsMonitor *mon, void *vctxt, Sint reds) return 1; } +#define ERTS_MON_NODES_MAX_INFO_LIST_SZ__(MAX_ELEMS) \ + ((MAX_ELEMS)*(3 /* key/value 2-tuple */ + 2/* cons cell */) \ + + BIG_UINT_HEAP_SIZE /* connection id value */ \ + + 4 /* top 3-tuple */) +#define ERTS_MON_NODES_MAX_INFO_MAP_SZ__(MAX_ELEMS) \ + ((MAX_ELEMS)*2 /* keys and values */ \ + + 1 /* key tuple header */ + MAP_HEADER_FLATMAP_SZ /* 3 */ \ + + BIG_UINT_HEAP_SIZE /* connection id value */ \ + + 4 /* top 3-tuple */) +#define ERTS_MON_NODES_MAX_INFO_SZ__(MAX_ELEMS) \ + ((ERTS_MON_NODES_MAX_INFO_MAP_SZ__((MAX_ELEMS)) \ + > ERTS_MON_NODES_MAX_INFO_LIST_SZ__((MAX_ELEMS))) \ + ? ERTS_MON_NODES_MAX_INFO_MAP_SZ__((MAX_ELEMS)) \ + : ERTS_MON_NODES_MAX_INFO_LIST_SZ__((MAX_ELEMS))) + static void -send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reason) +send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, + Uint32 connection_id, Eterm type, Eterm reason) { Uint opts; Uint i, no, reason_size; @@ -6426,7 +6788,8 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas erts_mtx_unlock(&nodes_monitors_mtx); for (i = 0; i < no; i++) { - Eterm tmp_heap[3+2+3+2+4 /* max need */]; + ErtsHeapFactory hfact; + Eterm tmp_heap[ERTS_MON_NODES_MAX_INFO_SZ__(3/* max info elements */)]; Eterm *hp, msg; Uint hsz; @@ -6452,49 +6815,118 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas } } + /* + * tmp_heap[] is sized so there will be room for everything + * we need assuming no info, a two-tuple info list, or an info + * flat map is generated. In case there would be a greater heap + * need this will be taken care of by the heap factory... + */ + erts_factory_tmp_init(&hfact, + &tmp_heap[0], + sizeof(tmp_heap)/sizeof(Uint), + ERTS_ALC_T_TMP); hsz = 0; - hp = &tmp_heap[0]; if (!opts) { + hp = erts_produce_heap(&hfact, 3, 0); msg = TUPLE2(hp, what, node); - hp += 3; } - else { + else { /* Info list or map... */ Eterm tup; - Eterm info = NIL; + Eterm info; - if (opts & (ERTS_NODES_MON_OPT_TYPE_VISIBLE - | ERTS_NODES_MON_OPT_TYPE_HIDDEN)) { + if (opts & ERTS_NODES_MON_OPT_INFO_MAP) { /* Info map */ + Uint map_size = 0; + Eterm ks[3], vs[3]; - tup = TUPLE2(hp, am_node_type, type); - hp += 3; - info = CONS(hp, tup, info); - hp += 2; - } + if (opts & ERTS_NODES_MON_OPT_CONN_ID) { + Eterm cid; + if (connection_id == ~((Uint32) 0)) { + cid = am_undefined; + } + else if (IS_USMALL(0, (Uint) connection_id)) { + cid = make_small(connection_id); + } + else { + hp = erts_produce_heap(&hfact, BIG_UINT_HEAP_SIZE, 0); + cid = uint_to_big(connection_id, hp); + } + ks[map_size] = am_connection_id; + vs[map_size] = cid; + map_size++; + } + if (opts & (ERTS_NODES_MON_OPT_TYPE_VISIBLE + | ERTS_NODES_MON_OPT_TYPE_HIDDEN)) { + ks[map_size] = am_node_type; + vs[map_size] = type; + map_size++; + } + if (what == am_nodedown + && (opts & ERTS_NODES_MON_OPT_DOWN_REASON)) { + hsz += reason_size; + ks[map_size] = am_nodedown_reason; + vs[map_size] = reason; + map_size++; + } - if (what == am_nodedown - && (opts & ERTS_NODES_MON_OPT_DOWN_REASON)) { - hsz += reason_size; - tup = TUPLE2(hp, am_nodedown_reason, reason); - hp += 3; - info = CONS(hp, tup, info); - hp += 2; + info = erts_map_from_ks_and_vs(&hfact, ks, vs, map_size); + ASSERT(is_value(info)); } + else { /* Info list */ + + info = NIL; + if (opts & (ERTS_NODES_MON_OPT_TYPE_VISIBLE + | ERTS_NODES_MON_OPT_TYPE_HIDDEN)) { + hp = erts_produce_heap(&hfact, 3 + 2, 0); + tup = TUPLE2(hp, am_node_type, type); + hp += 3; + info = CONS(hp, tup, info); + } + if (what == am_nodedown + && (opts & ERTS_NODES_MON_OPT_DOWN_REASON)) { + hp = erts_produce_heap(&hfact, 3 + 2, 0); + hsz += reason_size; + tup = TUPLE2(hp, am_nodedown_reason, reason); + hp += 3; + info = CONS(hp, tup, info); + } + + if (opts & ERTS_NODES_MON_OPT_CONN_ID) { + Eterm cid; + if (connection_id == ~((Uint32) 0)) { + cid = am_undefined; + } + else if (IS_USMALL(0, (Uint) connection_id)) { + cid = make_small(connection_id); + } + else { + hp = erts_produce_heap(&hfact, BIG_UINT_HEAP_SIZE, 0); + cid = uint_to_big(connection_id, hp); + } + hp = erts_produce_heap(&hfact, 3 + 2, 0); + tup = TUPLE2(hp, am_connection_id, cid); + hp += 3; + info = CONS(hp, tup, info); + } + } + + hp = erts_produce_heap(&hfact, 4, 0); msg = TUPLE3(hp, what, node, info); - hp += 4; } - ASSERT(hp - &tmp_heap[0] <= sizeof(tmp_heap)/sizeof(tmp_heap[0])); - hsz += hp - &tmp_heap[0]; + hsz += hfact.hp - hfact.hp_start; + if (hfact.heap_frags) { + ErlHeapFragment *bp; + for (bp = hfact.heap_frags; bp; bp = bp->next) + hsz += bp->used_size; + } + + erts_proc_sig_send_monitor_nodes_msg(nmdp[i].options, nmdp[i].pid, + msg, hsz); - erts_proc_sig_send_persistent_monitor_msg(ERTS_MON_TYPE_NODES, - nmdp[i].options, - am_system, - nmdp[i].pid, - msg, - hsz); + erts_factory_close(&hfact); } if (nmdp != &def_buf[0]) diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h index bf1fe2b2a10d..475d87a09f2c 100644 --- a/erts/emulator/beam/dist.h +++ b/erts/emulator/beam/dist.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -25,33 +25,35 @@ #include "erl_node_tables.h" #include "zlib.h" -#define DFLAG_PUBLISHED ((Uint64)0x01) -#define DFLAG_ATOM_CACHE ((Uint64)0x02) -#define DFLAG_EXTENDED_REFERENCES ((Uint64)0x04) -#define DFLAG_DIST_MONITOR ((Uint64)0x08) -#define DFLAG_FUN_TAGS ((Uint64)0x10) -#define DFLAG_DIST_MONITOR_NAME ((Uint64)0x20) -#define DFLAG_HIDDEN_ATOM_CACHE ((Uint64)0x40) -#define DFLAG_NEW_FUN_TAGS ((Uint64)0x80) -#define DFLAG_EXTENDED_PIDS_PORTS ((Uint64)0x100) -#define DFLAG_EXPORT_PTR_TAG ((Uint64)0x200) -#define DFLAG_BIT_BINARIES ((Uint64)0x400) -#define DFLAG_NEW_FLOATS ((Uint64)0x800) -#define DFLAG_UNICODE_IO ((Uint64)0x1000) -#define DFLAG_DIST_HDR_ATOM_CACHE ((Uint64)0x2000) -#define DFLAG_SMALL_ATOM_TAGS ((Uint64)0x4000) -#define DFLAG_ETS_COMPRESSED ((Uint64)0x8000) /* internal */ -#define DFLAG_UTF8_ATOMS ((Uint64)0x10000) -#define DFLAG_MAP_TAG ((Uint64)0x20000) -#define DFLAG_BIG_CREATION ((Uint64)0x40000) -#define DFLAG_SEND_SENDER ((Uint64)0x80000) -#define DFLAG_BIG_SEQTRACE_LABELS ((Uint64)0x100000) -#define DFLAG_PENDING_CONNECT ((Uint64)0x200000) /* internal */ -#define DFLAG_EXIT_PAYLOAD ((Uint64)0x400000) -#define DFLAG_FRAGMENTS ((Uint64)0x800000) -#define DFLAG_HANDSHAKE_23 ((Uint64)0x1000000) -#define DFLAG_UNLINK_ID ((Uint64)0x2000000) -#define DFLAG_RESERVED ((Uint64)0xfc000000) +#define DFLAG_PUBLISHED ((Uint64)0x01) +#define DFLAG_ATOM_CACHE ((Uint64)0x02) +#define DFLAG_EXTENDED_REFERENCES ((Uint64)0x04) +#define DFLAG_DIST_MONITOR ((Uint64)0x08) +#define DFLAG_FUN_TAGS ((Uint64)0x10) +#define DFLAG_DIST_MONITOR_NAME ((Uint64)0x20) +#define DFLAG_HIDDEN_ATOM_CACHE ((Uint64)0x40) +#define DFLAG_NEW_FUN_TAGS ((Uint64)0x80) +#define DFLAG_EXTENDED_PIDS_PORTS ((Uint64)0x100) +#define DFLAG_EXPORT_PTR_TAG ((Uint64)0x200) +#define DFLAG_BIT_BINARIES ((Uint64)0x400) +#define DFLAG_NEW_FLOATS ((Uint64)0x800) +#define DFLAG_UNICODE_IO ((Uint64)0x1000) +#define DFLAG_DIST_HDR_ATOM_CACHE ((Uint64)0x2000) +#define DFLAG_SMALL_ATOM_TAGS ((Uint64)0x4000) +#define DFLAG_ETS_COMPRESSED ((Uint64)0x8000) /* internal */ +#define DFLAG_UTF8_ATOMS ((Uint64)0x10000) +#define DFLAG_MAP_TAG ((Uint64)0x20000) +#define DFLAG_BIG_CREATION ((Uint64)0x40000) +#define DFLAG_SEND_SENDER ((Uint64)0x80000) +#define DFLAG_BIG_SEQTRACE_LABELS ((Uint64)0x100000) +#define DFLAG_PENDING_CONNECT ((Uint64)0x200000) /* internal */ +#define DFLAG_EXIT_PAYLOAD ((Uint64)0x400000) +#define DFLAG_FRAGMENTS ((Uint64)0x800000) +#define DFLAG_HANDSHAKE_23 ((Uint64)0x1000000) +#define DFLAG_UNLINK_ID ((Uint64)0x2000000) +#define DFLAG_MANDATORY_25_DIGEST ((Uint64)0x4000000) +#define DFLAG_RESERVED ((Uint64)0xf8000000) + /* * As the old handshake only support 32 flag bits, we reserve the remaining * bits in the lower 32 for changes in the handshake protocol or potentially @@ -61,6 +63,7 @@ #define DFLAG_NAME_ME (((Uint64)0x2) << 32) #define DFLAG_V4_NC (((Uint64)0x4) << 32) #define DFLAG_ALIAS (((Uint64)0x8) << 32) +#define DFLAG_LOCAL_EXT (((Uint64)0x10) << 32) /* internal */ /* * In term_to_binary/2, we will use DFLAG_ATOM_CACHE to mean @@ -69,44 +72,49 @@ #define DFLAG_DETERMINISTIC DFLAG_ATOM_CACHE -/* Mandatory flags for distribution */ -#define DFLAG_DIST_MANDATORY (DFLAG_EXTENDED_REFERENCES \ - | DFLAG_EXTENDED_PIDS_PORTS \ - | DFLAG_UTF8_ATOMS \ - | DFLAG_NEW_FUN_TAGS \ - | DFLAG_BIG_CREATION) +/* Mandatory flags for distribution in OTP 25. */ +#define DFLAG_DIST_MANDATORY_25 (DFLAG_EXTENDED_REFERENCES \ + | DFLAG_FUN_TAGS \ + | DFLAG_EXTENDED_PIDS_PORTS \ + | DFLAG_UTF8_ATOMS \ + | DFLAG_NEW_FUN_TAGS \ + | DFLAG_BIG_CREATION \ + | DFLAG_NEW_FLOATS \ + | DFLAG_MAP_TAG \ + | DFLAG_EXPORT_PTR_TAG \ + | DFLAG_BIT_BINARIES \ + | DFLAG_HANDSHAKE_23) + +/* New mandatory flags for distribution in OTP 26 */ +#define DFLAG_DIST_MANDATORY_26 (DFLAG_V4_NC \ + | DFLAG_UNLINK_ID) + +/* Mandatory flags for distribution. */ +#define DFLAG_DIST_MANDATORY (DFLAG_DIST_MANDATORY_25 \ + | DFLAG_DIST_MANDATORY_26) /* * Additional optimistic flags when encoding toward pending connection. * If remote node (erl_interface) does not support these then we may need * to transcode messages enqueued before connection setup was finished. */ -#define DFLAG_DIST_HOPEFULLY (DFLAG_EXPORT_PTR_TAG \ - | DFLAG_BIT_BINARIES \ - | DFLAG_DIST_MONITOR \ +#define DFLAG_DIST_HOPEFULLY (DFLAG_DIST_MONITOR \ | DFLAG_DIST_MONITOR_NAME \ | DFLAG_SPAWN \ - | DFLAG_ALIAS \ - | DFLAG_UNLINK_ID) + | DFLAG_ALIAS) /* Our preferred set of flags. Used for connection setup handshake */ #define DFLAG_DIST_DEFAULT (DFLAG_DIST_MANDATORY | DFLAG_DIST_HOPEFULLY \ - | DFLAG_FUN_TAGS \ - | DFLAG_NEW_FLOATS \ | DFLAG_UNICODE_IO \ | DFLAG_DIST_HDR_ATOM_CACHE \ | DFLAG_SMALL_ATOM_TAGS \ - | DFLAG_UTF8_ATOMS \ - | DFLAG_MAP_TAG \ | DFLAG_SEND_SENDER \ | DFLAG_BIG_SEQTRACE_LABELS \ | DFLAG_EXIT_PAYLOAD \ | DFLAG_FRAGMENTS \ - | DFLAG_HANDSHAKE_23 \ | DFLAG_SPAWN \ - | DFLAG_V4_NC \ | DFLAG_ALIAS \ - | DFLAG_UNLINK_ID) + | DFLAG_MANDATORY_25_DIGEST) /* Flags addable by local distr implementations */ #define DFLAG_DIST_ADDABLE DFLAG_DIST_DEFAULT @@ -121,14 +129,8 @@ #define DFLAG_DIST_STRICT_ORDER DFLAG_DIST_HDR_ATOM_CACHE /* All flags that should be enabled when term_to_binary/1 is used. */ -#define TERM_TO_BINARY_DFLAGS (DFLAG_EXTENDED_REFERENCES \ - | DFLAG_NEW_FUN_TAGS \ - | DFLAG_NEW_FLOATS \ - | DFLAG_EXTENDED_PIDS_PORTS \ - | DFLAG_EXPORT_PTR_TAG \ - | DFLAG_BIT_BINARIES \ - | DFLAG_MAP_TAG \ - | DFLAG_BIG_CREATION) +#define TERM_TO_BINARY_DFLAGS (DFLAG_NEW_FLOATS \ + | DFLAG_UTF8_ATOMS) /* opcodes used in distribution messages */ enum dop { @@ -281,10 +283,17 @@ typedef struct TTBEncodeContext_ { SysIOVec* iov; ErlDrvBinary** binv; Eterm *termv; - int iovec; Uint fragment_size; Sint frag_ix; ErlIOVec *fragment_eiovs; + int iovec; + int continue_make_lext_hash; + int lext_vlen; + byte *lext_hash; + union { + ErtsBlockHashState block; + ErtsIovBlockHashState iov_block; + } lext_state; #ifdef DEBUG int debug_fragments; int debug_vlen; @@ -304,6 +313,8 @@ typedef struct TTBEncodeContext_ { (Ctx)->iov = NULL; \ (Ctx)->binv = NULL; \ (Ctx)->fragment_size = ~((Uint) 0); \ + (Ctx)->continue_make_lext_hash = 0; \ + (Ctx)->lext_vlen = -1; \ if ((Flags) & DFLAG_PENDING_CONNECT) { \ (Ctx)->hopefull_flags = 0; \ (Ctx)->hopefull_flagsp = NULL; \ @@ -344,6 +355,7 @@ typedef struct erts_dsig_send_context { int connect; int no_suspend; int no_trap; + int ignore_busy; Eterm ctl; Eterm msg; @@ -442,4 +454,7 @@ int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks); Uint erts_ttb_iov_size(int use_termv, Sint vlen, Uint fragments); void erts_ttb_iov_init(TTBEncodeContext *ctx, int use_termv, char *ptr, Sint vlen, Uint fragments, Uint fragments_size); + +int erts_is_this_node_alive(void); + #endif diff --git a/erts/emulator/beam/emu/arith_instrs.tab b/erts/emulator/beam/emu/arith_instrs.tab index 13c33b8f6bda..42f71f68fed8 100644 --- a/erts/emulator/beam/emu/arith_instrs.tab +++ b/erts/emulator/beam/emu/arith_instrs.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2017-2020. All Rights Reserved. +// Copyright Ericsson AB 2017-2021. 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. @@ -474,7 +474,7 @@ shift.execute(Fail, Dst) { HRelease(c_p, hp_end, hp); if (ERTS_UNLIKELY(is_nil(Op1))) { /* - * This result must have been only slighty larger + * This result must have been only slightly larger * than allowed since it wasn't caught by the * previous test. */ diff --git a/erts/emulator/beam/emu/beam_emu.c b/erts/emulator/beam/emu/beam_emu.c index 932e8a2108ac..0c91c1ec83ca 100644 --- a/erts/emulator/beam/emu/beam_emu.c +++ b/erts/emulator/beam/emu/beam_emu.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -107,9 +107,11 @@ * Special Beam instructions. */ -static BeamInstr beam_apply_[2]; -ErtsCodePtr beam_apply; /* beam_apply_[0]; */ -ErtsCodePtr beam_normal_exit; /* beam_apply_[1]; */ +static BeamInstr beam_run_process_[1]; +ErtsCodePtr beam_run_process; + +static BeamInstr beam_normal_exit_[1]; +ErtsCodePtr beam_normal_exit; static BeamInstr beam_exit_[1]; ErtsCodePtr beam_exit; @@ -120,7 +122,7 @@ ErtsCodePtr beam_continue_exit; /* NOTE These should be the only variables containing trace instructions. ** Sometimes tests are for the instruction value, and sometimes -** for the referring variable (one of these), and rouge references +** for the referring variable (one of these), and rogue references ** will most likely cause chaos. */ @@ -136,9 +138,15 @@ ErtsCodePtr beam_return_trace; static BeamInstr beam_exception_trace_[1]; ErtsCodePtr beam_exception_trace; -/* OpCode(i_return_time_trace) */ -static BeamInstr beam_return_time_trace_[1]; -ErtsCodePtr beam_return_time_trace; +/* OpCode(i_call_trace_return) */ +static BeamInstr beam_call_trace_return_[1]; +ErtsCodePtr beam_call_trace_return; + +/* The address field of every fun that has no loaded code will point to + * beam_unloaded_fun[]. The -1 in beam_unloaded_fun[0] will be interpreted + * as an illegal arity when attempting to call a fun. */ +static BeamInstr unloaded_fun_code[4] = {NIL, NIL, -1, 0}; +ErtsCodePtr beam_unloaded_fun = &unloaded_fun_code[3]; /* * All Beam instructions in numerical order. @@ -305,6 +313,8 @@ void process_main(ErtsSchedulerData *esdp) #endif #endif + Uint bitdata = 0; + Uint64 start_time = 0; /* Monitor long schedule */ ErtsCodePtr start_time_i = NULL; @@ -412,7 +422,7 @@ void process_main(ErtsSchedulerData *esdp) if (ERTS_PROC_IS_EXITING(c_p)) { sys_strcpy(fun_buf, ""); } else { - ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i); + const ErtsCodeMFA *cmfa = erts_find_function_from_pc(c_p->i); if (cmfa) { dtrace_fun_decode(c_p, cmfa, NULL, fun_buf); @@ -445,16 +455,12 @@ void process_main(ErtsSchedulerData *esdp) * can get the module, function, and arity for the function being * called from I[-3], I[-2], and I[-1] respectively. */ - context_switch_fun: - /* Add one for the environment of the fun */ - c_p->arity = erts_code_to_codemfa(I)->arity + 1; - goto context_switch2; - context_switch: - c_p->arity = erts_code_to_codemfa(I)->arity; - - context_switch2: /* Entry for fun calls. */ - c_p->current = erts_code_to_codemfa(I); + { + const ErtsCodeMFA *mfa = erts_code_to_codemfa(I); + c_p->arity = mfa->arity; + c_p->current = mfa; + } context_switch3: @@ -533,7 +539,7 @@ void process_main(ErtsSchedulerData *esdp) HEAVY_SWAPIN; if (error_handler) { - I = error_handler->addresses[erts_active_code_ix()]; + I = error_handler->dispatch.addresses[erts_active_code_ix()]; Goto(*I); } } @@ -575,7 +581,7 @@ void process_main(ErtsSchedulerData *esdp) OpCase(label_L): OpCase(on_load): OpCase(line_I): - OpCase(int_func_end): + OpCase(i_nif_padding): erts_exit(ERTS_ERROR_EXIT, "meta op\n"); /* @@ -627,7 +633,7 @@ static void install_bifs(void) { ep = erts_export_put(entry->module, entry->name, entry->arity); - ep->info.op = BeamOpCodeAddr(op_i_func_info_IaaI); + ep->info.u.op = BeamOpCodeAddr(op_i_func_info_IaaI); ep->info.mfa.module = entry->module; ep->info.mfa.function = entry->name; ep->info.mfa.arity = entry->arity; @@ -669,11 +675,11 @@ init_emulator_finish(void) } #endif - beam_apply_[0] = BeamOpCodeAddr(op_i_apply); - beam_apply_[1] = BeamOpCodeAddr(op_normal_exit); + beam_run_process_[0] = BeamOpCodeAddr(op_i_apply_only); + beam_run_process = (ErtsCodePtr)&beam_run_process_[0]; - beam_apply = (ErtsCodePtr)&beam_apply_[0]; - beam_normal_exit = (ErtsCodePtr)&beam_apply_[1]; + beam_normal_exit_[0] = BeamOpCodeAddr(op_normal_exit); + beam_normal_exit = (ErtsCodePtr)&beam_normal_exit_[0]; beam_exit_[0] = BeamOpCodeAddr(op_error_action_code); beam_exit = (ErtsCodePtr)&beam_exit_[0]; @@ -690,8 +696,8 @@ init_emulator_finish(void) beam_exception_trace_[0] = BeamOpCodeAddr(op_return_trace); /* UGLY */ beam_exception_trace = (ErtsCodePtr)&beam_exception_trace_[0]; - beam_return_time_trace_[0] = BeamOpCodeAddr(op_i_return_time_trace); - beam_return_time_trace = (ErtsCodePtr)&beam_return_time_trace_[0]; + beam_call_trace_return_[0] = BeamOpCodeAddr(op_i_call_trace_return); + beam_call_trace_return = (ErtsCodePtr)&beam_call_trace_return_[0]; install_bifs(); } @@ -705,3 +711,58 @@ erts_beam_jump_table(void) return 1; #endif } + +void +erts_prepare_bs_construct_fail_info(Process* c_p, const BeamInstr* p, Eterm reason, Eterm Info, Eterm value) +{ + Eterm* hp; + Eterm cause_tuple; + Eterm op; + Eterm error_info; + Uint segment; + + segment = p[2] >> 3; + + switch (p[0]) { + case BSC_APPEND: + case BSC_PRIVATE_APPEND: + case BSC_BINARY: + case BSC_BINARY_FIXED_SIZE: + case BSC_BINARY_ALL: + op = am_binary; + break; + case BSC_FLOAT: + case BSC_FLOAT_FIXED_SIZE: + op = am_float; + break; + case BSC_INTEGER: + case BSC_INTEGER_FIXED_SIZE: + op = am_integer; + break; + case BSC_STRING: + op = am_string; + break; + case BSC_UTF8: + op = am_utf8; + break; + case BSC_UTF16: + op = am_utf16; + break; + case BSC_UTF32: + op = am_utf32; + break; + default: + op = am_none; + break; + } + + hp = HeapFragOnlyAlloc(c_p, MAP3_SZ+4+1); + cause_tuple = TUPLE4(hp, make_small(segment), op, Info, value); + hp += 5; + error_info = MAP3(hp, + am_cause, cause_tuple, + am_function, am_format_bs_fail, + am_module, am_erl_erts_errors); + c_p->fvalue = error_info; + c_p->freason = reason | EXF_HAS_EXT_INFO; +} diff --git a/erts/emulator/beam/emu/bif_instrs.tab b/erts/emulator/beam/emu/bif_instrs.tab index 1afb7ac6dedb..d1ec68168ac6 100644 --- a/erts/emulator/beam/emu/bif_instrs.tab +++ b/erts/emulator/beam/emu/bif_instrs.tab @@ -307,7 +307,7 @@ call_light_bif(Bif, Exp) { // // Call a BIF tail-recursively, storing the result in x(0) and doing -// a return to the continuation poiner. +// a return to the continuation pointer. // call_light_bif_only(Bif, Exp) { ErlHeapFragment *live_hf_end; @@ -445,6 +445,9 @@ send() { } } +nif_start() { +} + call_nif_early() { HEAVY_SWAPOUT; I = erts_call_nif_early(c_p, erts_code_to_codeinfo(I)); @@ -625,12 +628,12 @@ nif_bif.epilogue() { i_load_nif() { //| -no_next - if (erts_try_seize_code_write_permission(c_p)) { + if (erts_try_seize_code_mod_permission(c_p)) { Eterm result; PRE_BIF_SWAPOUT(c_p); result = erts_load_nif(c_p, I, r(0), r(1)); - erts_release_code_write_permission(); + erts_release_code_mod_permission(); ERTS_REQ_PROC_MAIN_LOCK(c_p); SWAPIN; diff --git a/erts/emulator/beam/emu/bs_instrs.tab b/erts/emulator/beam/emu/bs_instrs.tab index a0251f92a462..a42c2eb331a0 100644 --- a/erts/emulator/beam/emu/bs_instrs.tab +++ b/erts/emulator/beam/emu/bs_instrs.tab @@ -125,7 +125,7 @@ BS_GET_UNCHECKED_FIELD_SIZE(Bits, Unit, Fail, Dst) { TEST_BIN_VHEAP(VNh, Nh, Live) { Uint need = $Nh; if ((E - HTOP < (need + S_RESERVED)) || - (MSO(c_p).overhead + $VNh >= BIN_VHEAP_SZ(c_p))) { + (MSO(c_p).overhead + $VNh >= c_p->bin_vheap_sz)) { $GC_SWAPOUT(); PROCESS_MAIN_CHK_LOCKS(c_p); FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, $Live, FCALLS); @@ -334,13 +334,13 @@ i_new_bs_put_float(Fail, Sz, Flags, Src) { Eterm flags = $Flags; Sint _size; $BS_GET_UNCHECKED_FIELD_SIZE(sz, (flags >> 3), $BADARG($Fail), _size); - if (!erts_new_bs_put_float(c_p, ($Src), _size, flags)) { + if (is_value(erts_new_bs_put_float(c_p, ($Src), _size, flags))) { $BADARG($Fail); } } i_new_bs_put_float_imm(Fail, Sz, Flags, Src) { - if (!erts_new_bs_put_float(c_p, ($Src), ($Sz), ($Flags))) { + if (is_value(erts_new_bs_put_float(c_p, ($Src), ($Sz), ($Flags)))) { $BADARG($Fail); } } @@ -427,13 +427,13 @@ bs_init.verify(Fail) { } bs_init.execute(Live, Dst) { + erts_bin_offset = 0; + if (BsOp1 <= ERL_ONHEAP_BIN_LIMIT) { ErlHeapBin* hb; Uint bin_need; bin_need = heap_bin_size(BsOp1); - erts_bin_offset = 0; - erts_writable_bin = 0; $GC_TEST(0, bin_need+BsOp2+ERL_SUB_BIN_SIZE, $Live); hb = (ErlHeapBin *) HTOP; HTOP += bin_need; @@ -445,10 +445,7 @@ bs_init.execute(Live, Dst) { Binary* bptr; ProcBin* pb; - erts_bin_offset = 0; - erts_writable_bin = 0; - $TEST_BIN_VHEAP(BsOp1 / sizeof(Eterm), - BsOp2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, $Live); + $TEST_BIN_VHEAP(BsOp1 / sizeof(Eterm), BsOp2 + PROC_BIN_SIZE, $Live); /* * Allocate the binary struct itself. @@ -540,7 +537,8 @@ bs_init_bits.execute(Live, Dst) { } else { alloc += PROC_BIN_SIZE; } - $test_heap(alloc, $Live); + + erts_bin_offset = 0; /* num_bits = Number of bits to build * num_bytes = Number of bytes to allocate in the binary @@ -550,38 +548,18 @@ bs_init_bits.execute(Live, Dst) { if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { ErlHeapBin* hb; - erts_bin_offset = 0; - erts_writable_bin = 0; + $test_heap(alloc, $Live); hb = (ErlHeapBin *) HTOP; HTOP += heap_bin_size(num_bytes); hb->thing_word = header_heap_bin(num_bytes); hb->size = num_bytes; erts_current_bin = (byte *) hb->data; new_binary = make_binary(hb); - - do_bits_sub_bin: - if (num_bits & 7) { - ErlSubBin* sb; - - sb = (ErlSubBin *) HTOP; - HTOP += ERL_SUB_BIN_SIZE; - sb->thing_word = HEADER_SUB_BIN; - sb->size = num_bytes - 1; - sb->bitsize = num_bits & 7; - sb->offs = 0; - sb->bitoffs = 0; - sb->is_writable = 0; - sb->orig = new_binary; - new_binary = make_binary(sb); - } - HEAP_SPACE_VERIFIED(0); - $Dst = new_binary; } else { Binary* bptr; ProcBin* pb; - erts_bin_offset = 0; - erts_writable_bin = 0; + $TEST_BIN_VHEAP(num_bytes / sizeof(Eterm), alloc, $Live); /* * Allocate the binary struct itself. @@ -603,8 +581,24 @@ bs_init_bits.execute(Live, Dst) { pb->flags = 0; OH_OVERHEAD(&(MSO(c_p)), pb->size / sizeof(Eterm)); new_binary = make_binary(pb); - goto do_bits_sub_bin; } + + if (num_bits & 7) { + ErlSubBin* sb; + + sb = (ErlSubBin *) HTOP; + HTOP += ERL_SUB_BIN_SIZE; + sb->thing_word = HEADER_SUB_BIN; + sb->size = num_bytes - 1; + sb->bitsize = num_bits & 7; + sb->offs = 0; + sb->bitoffs = 0; + sb->is_writable = 0; + sb->orig = new_binary; + new_binary = make_binary(sb); + } + HEAP_SPACE_VERIFIED(0); + $Dst = new_binary; } bs_add(Fail, Src1, Src2, Unit, Dst) { @@ -840,75 +834,453 @@ i_bs_validate_unicode_retract(Fail, Src, Ms) { } } +BS_GET_TERM(Term, Dst) { + $Dst = $Term; + switch (loader_tag($Dst)) { + case LOADER_X_REG: + $Dst = x(loader_x_reg_index($Dst)); + break; + case LOADER_Y_REG: + $Dst = y(loader_y_reg_index($Dst)); + break; + } +} -// -// Matching of binaries. -// +BS_LOAD_UNIT(Ptr, Dst) { + $Dst = $Ptr[1]; +} -i_bs_start_match2 := bs_start_match.fetch.execute; +BS_LOAD_FLAGS(Ptr, Dst) { + $Dst = $Ptr[2]; +} -bs_start_match.head() { - Eterm context; +BS_LOAD_SRC(Ptr, Dst) { + $BS_GET_TERM($Ptr[3], $Dst); } -bs_start_match.fetch(Src) { - context = $Src; +BS_LOAD_STRING_SRC(Ptr, Dst) { + $Dst = (byte *) $Ptr[3]; } -bs_start_match.execute(Fail, Live, Slots, Dst) { - Uint slots; - Uint live; - Eterm header; - if (!is_boxed(context)) { - $FAIL($Fail); +BS_LOAD_SIZE(Ptr, Dst) { + $BS_GET_TERM($Ptr[4], $Dst); +} + +BS_LOAD_FIXED_SIZE(Ptr, Dst) { + $Dst = $Ptr[4]; +} + +// Implicitly uses the c_p and p variables (for convenience). +BS_FAIL_INFO(Fail, Reason, ErrorType, Value) { + erts_prepare_bs_construct_fail_info(c_p, p, $Reason, $ErrorType, $Value); + $FAIL_HEAD_OR_BODY($Fail); +} + +// Implicitly uses the Size variable because of limitations of parsing in +// beam_makeops of nested macro call; a nested macro call can only have one +// argument. +BS_FAIL_INFO_SYSTEM_LIMIT(Fail) { + $BS_FAIL_INFO($Fail, SYSTEM_LIMIT, am_size, Size); +} + +i_bs_create_bin(Fail, Alloc, Live, Dst, N) { + //| -no_prefetch + int n = $N; + const BeamInstr* p_start = $NEXT_INSTRUCTION; + const BeamInstr* p_end = p_start + n; + const BeamInstr* p; + Uint num_bytes; + Uint alloc = $Alloc; + Eterm new_binary; + + /* We count the total number of bits in an unsigned integer. To avoid + * having to check for overflow when adding to `num_bits`, we ensure that the + * signed size of each segment fits in a word. */ + Uint num_bits = 0; + + /* Calculate size of binary in bits. */ + for (p = p_start; p < p_end; p += BSC_NUM_ARGS) { + Eterm Src; + Eterm Size; + Uint unit; + Uint fixed_size; + + switch (p[0]) { + case BSC_APPEND: + case BSC_PRIVATE_APPEND: + break; + case BSC_BINARY_ALL: + { + Uint byte_size; + Uint bit_size; + + $BS_LOAD_SRC(p, Src); + if (is_not_binary(Src)) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + byte_size = binary_size(Src); +#ifndef ARCH_64 + if ((byte_size >> 28) != 0) { + /* The size of the binary in bits will not fit in + * a 32-bit signed integer. */ + $BS_FAIL_INFO($Fail, SYSTEM_LIMIT, am_binary, am_size); + } +#endif + bit_size = (byte_size << 3) + binary_bitsize(Src); + num_bits += bit_size; + } + break; + case BSC_BINARY_FIXED_SIZE: + case BSC_FLOAT_FIXED_SIZE: + case BSC_INTEGER_FIXED_SIZE: + $BS_LOAD_FIXED_SIZE(p, fixed_size); + num_bits += fixed_size; + break; + case BSC_STRING: + $BS_LOAD_FIXED_SIZE(p, fixed_size); + num_bits += fixed_size * 8; + break; + case BSC_BINARY: + case BSC_FLOAT: + case BSC_INTEGER: + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_SIZE(p, Size); + if (is_small(Size)) { + Sint signed_size = signed_val(Size); + Uint size; + if (signed_size >= 0) { + $BS_SAFE_MUL(signed_size, unit, $BS_FAIL_INFO_SYSTEM_LIMIT($Fail), size); + if (size >> (sizeof(Uint) * 8 - 1) != 0) { + /* The signed size does not fit in a word. */ + $BS_FAIL_INFO($Fail, SYSTEM_LIMIT, am_size, Size); + } + num_bits += size; + } else { + $BS_FAIL_INFO($Fail, BADARG, am_size, Size); + } + } else { +#ifdef ARCH_64 + /* The size must fit in a small on 64-bit platforms. */ + if (is_big(Size)) { + if (!big_sign(Size)) { + $BS_FAIL_INFO($Fail, SYSTEM_LIMIT, am_size, Size); + } else { + $BS_FAIL_INFO($Fail, BADARG, am_size, Size); + } + } else { + /* Not an integer. */ + $BS_FAIL_INFO($Fail, BADARG, am_size, Size); + } +#else + Uint size; + + if (!term_to_Uint(Size, &size)) { + if (size == BADARG) { + /* Not an integer or a negative integer. Determine which. */ + if (is_big(Size)) { + /* Negative integer. */ + $BS_FAIL_INFO($Fail, BADARG, am_size, Size); + } + /* Not an integer. */ + $BS_FAIL_INFO($Fail, BADARG, am_size, Size); + } + /* Huge positive integer. */ + $BS_FAIL_INFO_SYSTEM_LIMIT($Fail); + } + $BS_SAFE_MUL(size, unit, $BS_FAIL_INFO_SYSTEM_LIMIT($Fail), size); + if ((size >> 31) != 0) { + $BS_FAIL_INFO_SYSTEM_LIMIT($Fail); + } else { + num_bits += size; + } +#endif + } + break; + case BSC_UTF8: + { + int num_bytes; + + /* + * Calculate the number of bits needed to encode the + * source operand to UTF-8. If the source operand is + * invalid (e.g. wrong type or range) we return a + * nonsense integer result (32). We can get away + * with that because we KNOW that full error checking + * will be done in the construction phase. + */ + + $BS_LOAD_SRC(p, Src); + if (Src < make_small(0x80UL)) { + num_bytes = 1; + } else if (Src < make_small(0x800UL)) { + num_bytes = 2; + } else if (Src < make_small(0x10000UL)) { + num_bytes = 3; + } else { + num_bytes = 4; + } + num_bits += num_bytes * 8; + } + break; + case BSC_UTF16: + { + int num_bytes = 2; + + /* + * Calculate the number of bits needed to encode the + * source operarand to UTF-16. If the source operand + * is invalid (e.g. wrong type or range) we return a + * nonsense integer result (16 or 32). We can get away + * with that because we KNOW that full error checking + * will be done in the construction phase. + */ + + $BS_LOAD_SRC(p, Src); + if (Src >= make_small(0x10000UL)) { + num_bytes = 4; + } + num_bits += num_bytes * 8; + } + break; + case BSC_UTF32: + $BS_LOAD_SRC(p, Src); + + /* + * There is no need to untag the integer, but it IS + * necessary to make sure it is small (if the term is a + * bignum, it could slip through the test, and there is no + * further test that would catch it, since bit syntax + * construction silently masks too big numbers). + */ + if (is_not_small(Src) || Src > make_small(0x10FFFFUL) || + (make_small(0xD800UL) <= Src && Src <= make_small(0xDFFFUL))) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + num_bits += 4 * 8; + break; + default: + ASSERT(0); + break; + } } - header = *boxed_val(context); - /* Reserve a slot for the start position. */ - slots = $Slots + 1; - live = $Live; + /* Allocate binary. */ + p = p_start; + if (p[0] == BSC_APPEND) { + Uint live = $Live; + Uint unit; + Eterm Src; + + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_SRC(p, Src); + HEAVY_SWAPOUT; + reg[live] = Src; + new_binary = erts_bs_append_checked(c_p, reg, live, num_bits, alloc, unit); + HEAVY_SWAPIN; + if (is_non_value(new_binary)) { + $BS_FAIL_INFO($Fail, c_p->freason, c_p->fvalue, reg[live]); + } + p_start += BSC_NUM_ARGS; + } else if (p[0] == BSC_PRIVATE_APPEND) { + Uint unit; + Eterm Src; - if (header_is_bin_matchstate(header)) { - ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(context); - Uint actual_slots = HEADER_NUM_SLOTS(header); - - /* We're not compatible with contexts created by bs_start_match3. */ - ASSERT(actual_slots >= 1); - - ms->save_offset[0] = ms->mb.offset; - if (ERTS_UNLIKELY(actual_slots < slots)) { - ErlBinMatchState* expanded; - Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots); - $GC_TEST_PRESERVE(wordsneeded, live, context); - ms = (ErlBinMatchState *) boxed_val(context); - expanded = (ErlBinMatchState *) HTOP; - *expanded = *ms; - *HTOP = HEADER_BIN_MATCHSTATE(slots); - HTOP += wordsneeded; - HEAP_SPACE_VERIFIED(0); - context = make_matchstate(expanded); - $REFRESH_GEN_DEST(); + if (alloc) { + $test_heap(alloc, $Live); } - $Dst = context; - } else if (is_binary_header(header)) { - Eterm result; - Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots); - $GC_TEST_PRESERVE(wordsneeded, live, context); - HEAP_TOP(c_p) = HTOP; -#ifdef DEBUG - c_p->stop = E; /* Needed for checking in HeapOnlyAlloc(). */ -#endif - result = erts_bs_start_match_2(c_p, context, slots); - HTOP = HEAP_TOP(c_p); - HEAP_SPACE_VERIFIED(0); - $REFRESH_GEN_DEST(); - $Dst = result; + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_SRC(p, Src); + new_binary = erts_bs_private_append_checked(c_p, Src, num_bits, unit); + if (is_non_value(new_binary)) { + $BS_FAIL_INFO($Fail, c_p->freason, c_p->fvalue, Src); + } + p_start += BSC_NUM_ARGS; } else { - $FAIL($Fail); + num_bytes = ((Uint64)num_bits+(Uint64)7) >> 3; + if (num_bits & 7) { + alloc += ERL_SUB_BIN_SIZE; + } + if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { + alloc += heap_bin_size(num_bytes); + } else { + alloc += PROC_BIN_SIZE; + } + + /* num_bits = Number of bits to build + * num_bytes = Number of bytes to allocate in the binary + * alloc = Total number of words to allocate on heap + */ + erts_bin_offset = 0; + if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { + ErlHeapBin* hb; + + $test_heap(alloc, $Live); + hb = (ErlHeapBin *) HTOP; + HTOP += heap_bin_size(num_bytes); + hb->thing_word = header_heap_bin(num_bytes); + hb->size = num_bytes; + erts_current_bin = (byte *) hb->data; + new_binary = make_binary(hb); + } else { + Binary* bptr; + ProcBin* pb; + + $TEST_BIN_VHEAP(num_bytes / sizeof(Eterm), alloc, $Live); + + /* + * Allocate the binary struct itself. + */ + bptr = erts_bin_nrml_alloc(num_bytes); + erts_current_bin = (byte *) bptr->orig_bytes; + + /* + * Now allocate the ProcBin on the heap. + */ + pb = (ProcBin *) HTOP; + HTOP += PROC_BIN_SIZE; + pb->thing_word = HEADER_PROC_BIN; + pb->size = num_bytes; + pb->next = MSO(c_p).first; + MSO(c_p).first = (struct erl_off_heap_header*) pb; + pb->val = bptr; + pb->bytes = (byte*) bptr->orig_bytes; + pb->flags = 0; + OH_OVERHEAD(&(MSO(c_p)), pb->size / sizeof(Eterm)); + new_binary = make_binary(pb); + } + + if (num_bits & 7) { + ErlSubBin* sb; + + sb = (ErlSubBin *) HTOP; + HTOP += ERL_SUB_BIN_SIZE; + sb->thing_word = HEADER_SUB_BIN; + sb->size = num_bytes - 1; + sb->bitsize = num_bits & 7; + sb->offs = 0; + sb->bitoffs = 0; + sb->is_writable = 0; + sb->orig = new_binary; + new_binary = make_binary(sb); + } + HEAP_SPACE_VERIFIED(0); + } + + c_p->fcalls = FCALLS; + + /* Construct the segments. */ + for (p = p_start; p < p_end; p += BSC_NUM_ARGS) { + Eterm Src; + Eterm Size; + Eterm flags; + Eterm unit; + Sint _size; + + if(p[0] == BSC_STRING) { + byte* string; + $BS_LOAD_STRING_SRC(p, string); + $BS_LOAD_FIXED_SIZE(p, Size); + erts_new_bs_put_string(ERL_BITS_ARGS_2(string, Size)); + continue; + } + + $BS_LOAD_SRC(p, Src); + + switch (p[0]) { + case BSC_BINARY_ALL: + $BS_LOAD_UNIT(p, unit); + if (!erts_new_bs_put_binary_all(c_p, Src, unit)) { + $BS_FAIL_INFO($Fail, BADARG, am_unit, Src); + } + break; + case BSC_BINARY: + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_SIZE(p, Size); + $BS_GET_UNCHECKED_FIELD_SIZE(Size, unit, $BADARG($Fail), _size); + if (!erts_new_bs_put_binary(c_p, Src, _size)) { + Eterm reason = is_binary(Src) ? am_short : am_type; + $BS_FAIL_INFO($Fail, BADARG, reason, Src); + } + break; + case BSC_BINARY_FIXED_SIZE: + $BS_LOAD_FIXED_SIZE(p, Size); + if (!erts_new_bs_put_binary(c_p, Src, Size)) { + Eterm reason = is_binary(Src) ? am_short : am_type; + $BS_FAIL_INFO($Fail, BADARG, reason, Src); + } + break; + case BSC_FLOAT: + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_SIZE(p, Size); + $BS_GET_UNCHECKED_FIELD_SIZE(Size, unit, $BADARG($Fail), _size); + Src = erts_new_bs_put_float(c_p, Src, _size, flags); + if (is_value(Src)) { + $BS_FAIL_INFO($Fail, BADARG, c_p->fvalue, Src); + } + break; + case BSC_FLOAT_FIXED_SIZE: + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_FIXED_SIZE(p, Size); + Src = erts_new_bs_put_float(c_p, Src, Size, flags); + if (is_value(Src)) { + $BS_FAIL_INFO($Fail, BADARG, c_p->fvalue, Src); + } + break; + case BSC_INTEGER: + { + Sint _size; + + $BS_LOAD_UNIT(p, unit); + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_SIZE(p, Size); + $BS_GET_UNCHECKED_FIELD_SIZE(Size, unit, $BADARG($Fail), _size); + if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3(Src, _size, flags))) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + } + break; + case BSC_INTEGER_FIXED_SIZE: + case BSC_UTF32: + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_FIXED_SIZE(p, Size); + if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3(Src, Size, flags))) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + break; + case BSC_UTF8: + if (!erts_bs_put_utf8(ERL_BITS_ARGS_1(Src))) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + break; + case BSC_UTF16: + $BS_LOAD_FLAGS(p, flags); + $BS_LOAD_SRC(p, Src); + if (!erts_bs_put_utf16(ERL_BITS_ARGS_2(Src, flags))) { + $BS_FAIL_INFO($Fail, BADARG, am_type, Src); + } + break; + default: + ASSERT(0); + break; + } } + + FCALLS = c_p->fcalls; + + /* Return the resulting binary. */ + $REFRESH_GEN_DEST(); + $Dst = new_binary; + I += n; } + +// +// Matching of binaries. +// + bs_test_zero_tail2(Fail, Ctx) { ErlBinMatchBuffer *_mb; _mb = (ErlBinMatchBuffer*) ms_matchbuffer($Ctx); @@ -1030,10 +1402,19 @@ bs_get_integer.head() { bs_get_integer.fetch(Ctx, Size, Live) { Uint wordsneeded; + ErlBinMatchBuffer* mb; Ms = $Ctx; Sz = $Size; wordsneeded = 1+WSIZE(NBYTES(Sz)); - $GC_TEST_PRESERVE(wordsneeded, $Live, Ms); + + /* Check bits size before potential GC. We do not want a GC + * and then realize we don't need the allocated space (if the + * op fails). + */ + mb = ms_matchbuffer(Ms); + if (mb->size - mb->offset >= Sz) { + $GC_TEST_PRESERVE(wordsneeded, $Live, Ms); + } } bs_get_integer.fetch_small(Ctx, Size) { @@ -1158,49 +1539,6 @@ i_bs_get_utf16.execute(Fail, Flags, Dst) { $Dst = result; } -bs_context_to_binary := ctx_to_bin.fetch.execute; - -ctx_to_bin.head() { - Eterm context; - ErlBinMatchBuffer* mb; - Uint size; - Uint offs; -} - -ctx_to_bin.fetch(Src) { - context = $Src; - if (is_boxed(context) && - header_is_bin_matchstate(*boxed_val(context))) { - ErlBinMatchState* ms; - ms = (ErlBinMatchState *) boxed_val(context); - mb = &ms->mb; - offs = ms->save_offset[0]; - size = mb->size - offs; - } else { - $NEXT0(); - } -} - -ctx_to_bin.execute() { - Uint hole_size; - Uint orig = mb->orig; - ErlSubBin* sb = (ErlSubBin *) boxed_val(context); - /* Since we're going to overwrite the match state with the result, an - * ErlBinMatchState must be at least as large as an ErlSubBin. */ - ERTS_CT_ASSERT(sizeof(ErlSubBin) <= sizeof(ErlBinMatchState)); - hole_size = 1 + header_arity(sb->thing_word) - ERL_SUB_BIN_SIZE; - sb->thing_word = HEADER_SUB_BIN; - sb->size = BYTE_OFFSET(size); - sb->bitsize = BIT_OFFSET(size); - sb->offs = BYTE_OFFSET(offs); - sb->bitoffs = BIT_OFFSET(offs); - sb->is_writable = 0; - sb->orig = orig; - if (hole_size) { - sb[1].thing_word = make_pos_bignum_header(hole_size-1); - } -} - i_bs_match_string(Ctx, Fail, Bits, Ptr) { byte* bytes = (byte *) $Ptr; Uint bits = $Bits; @@ -1222,18 +1560,6 @@ i_bs_match_string(Ctx, Fail, Bits, Ptr) { mb->offset += bits; } -i_bs_save2(Src, Slot) { - ErlBinMatchState* _ms = (ErlBinMatchState*) boxed_val((Eterm) $Src); - ASSERT(HEADER_NUM_SLOTS(_ms->thing_word) > $Slot); - _ms->save_offset[$Slot] = _ms->mb.offset; -} - -i_bs_restore2(Src, Slot) { - ErlBinMatchState* _ms = (ErlBinMatchState*) boxed_val((Eterm) $Src); - ASSERT(HEADER_NUM_SLOTS(_ms->thing_word) > $Slot); - _ms->mb.offset = _ms->save_offset[$Slot]; -} - bs_get_tail := bs_get_tail.fetch.execute; bs_get_tail.head() { @@ -1246,31 +1572,22 @@ bs_get_tail.fetch(Src) { bs_get_tail.execute(Dst, Live) { ErlBinMatchBuffer* mb; - Uint size, offs; - ErlSubBin* sb; + Eterm bin, *htop; ASSERT(header_is_bin_matchstate(*boxed_val(context))); - $GC_TEST_PRESERVE(ERL_SUB_BIN_SIZE, $Live, context); - - mb = ms_matchbuffer(context); + $GC_TEST_PRESERVE(EXTRACT_SUB_BIN_HEAP_NEED, $Live, context); - offs = mb->offset; - size = mb->size - offs; + htop = HTOP; - sb = (ErlSubBin *) HTOP; - HTOP += ERL_SUB_BIN_SIZE; + mb = ms_matchbuffer(context); - sb->thing_word = HEADER_SUB_BIN; - sb->size = BYTE_OFFSET(size); - sb->bitsize = BIT_OFFSET(size); - sb->offs = BYTE_OFFSET(offs); - sb->bitoffs = BIT_OFFSET(offs); - sb->is_writable = 0; - sb->orig = mb->orig; + bin = erts_extract_sub_binary(&htop,mb->orig,mb->base, + mb->offset,mb->size - mb->offset); + HTOP = htop; $REFRESH_GEN_DEST(); - $Dst = make_binary(sb); + $Dst = bin; } @@ -1546,3 +1863,286 @@ i_bs_start_match3.execute(Live, Fail, Dst) { } %endif + +// +// New instructions introduced in OTP 26 for matching of integers and +// binaries of fixed sizes follow. +// + +// +// i_bs_ensure_bits Ctx Size Fail +// + +i_bs_ensure_bits := i_bs_ensure_bits.fetch.execute; + +i_bs_ensure_bits.head() { + Eterm context; +} + +i_bs_ensure_bits.fetch(Src) { + context = $Src; +} + +i_bs_ensure_bits.execute(NumBits, Fail) { + ErlBinMatchBuffer* mb = ms_matchbuffer(context); + Uint size = $NumBits; + if (mb->size - mb->offset < size) { + $FAIL($Fail); + } +} + +// +// i_bs_ensure_bits_unit Ctx Size Unit Fail +// + +i_bs_ensure_bits_unit := i_bs_ensure_bits_unit.fetch.execute; + +i_bs_ensure_bits_unit.head() { + Eterm context; +} + +i_bs_ensure_bits_unit.fetch(Src) { + context = $Src; +} + +i_bs_ensure_bits_unit.execute(NumBits, Unit, Fail) { + ErlBinMatchBuffer* mb = ms_matchbuffer(context); + Uint size = $NumBits; + Uint diff; + + if ((diff = mb->size - mb->offset) < size) { + $FAIL($Fail); + } + if ((diff - size) % $Unit != 0) { + $FAIL($Fail); + } +} + +// +// i_bs_read_bits Ctx Size +// i_bs_ensure_bits_read Ctx Size Fail +// + +i_bs_read_bits := i_bs_read_bits.fetch.execute; +i_bs_ensure_bits_read := i_bs_read_bits.fetch.ensure_bits.execute; + +i_bs_read_bits.head() { + ErlBinMatchBuffer* mb; + Uint size; +} + +i_bs_read_bits.fetch(Src, NumBits) { + mb = ms_matchbuffer($Src); + size = $NumBits; +} + +i_bs_read_bits.ensure_bits(Fail) { + if (mb->size - mb->offset < size) { + $FAIL($Fail); + } +} + +i_bs_read_bits.execute() { + byte *byte_ptr; + Uint bit_offset = mb->offset % 8; + Uint num_bytes_to_read = (size + 7) / 8; + Uint num_partial = size % 8; + + if ((num_partial == 0 && bit_offset != 0) || + (num_partial != 0 && bit_offset > 8 - num_partial)) { + num_bytes_to_read++; + } + + bitdata = 0; + byte_ptr = mb->base + (mb->offset >> 3); + mb->offset += size; + switch (num_bytes_to_read) { +#ifdef ARCH_64 + case 9: + case 8: + bitdata = bitdata << 8 | *byte_ptr++; + case 7: + bitdata = bitdata << 8 | *byte_ptr++; + case 6: + bitdata = bitdata << 8 | *byte_ptr++; + case 5: + bitdata = bitdata << 8 | *byte_ptr++; +#else + case 5: +#endif + case 4: + bitdata = bitdata << 8 | *byte_ptr++; + case 3: + bitdata = bitdata << 8 | *byte_ptr++; + case 2: + bitdata = bitdata << 8 | *byte_ptr++; + case 1: + bitdata = bitdata << 8 | *byte_ptr++; + } + + if (num_bytes_to_read <= sizeof(Uint)) { + bitdata <<= 8 * (sizeof(Uint) - num_bytes_to_read) + bit_offset; + } else { + bitdata <<= bit_offset; + bitdata = bitdata | ((*byte_ptr << bit_offset) >> 8); + } +} + +// i_bs_eq Fail Size Value +i_bs_eq(Fail, NumBits, Value) { + Uint size = $NumBits; + Eterm result; + + result = bitdata >> (8 * sizeof(Uint) - size); + bitdata <<= size; + if (result != $Value) { + $FAIL($Fail); + } +} + +// i_bs_extract_integer Size Dst +i_bs_extract_integer(NumBits, Dst) { + Uint size = $NumBits; + Eterm result; + + result = bitdata >> (8 * sizeof(Uint) - size); + result = make_small(result); + bitdata <<= size; + $Dst = result; +} + +// i_bs_read_integer_8 Ctx Dst +i_bs_read_integer_8(Ctx, Dst) { + ErlBinMatchBuffer* mb = ms_matchbuffer($Ctx); + byte *byte_ptr; + Uint bit_offset = mb->offset % 8; + Eterm result; + + byte_ptr = mb->base + (mb->offset >> 3); + mb->offset += 8; + result = byte_ptr[0]; + if (bit_offset != 0) { + result = result << 8 | byte_ptr[1]; + result = ((result << bit_offset) >> 8) & 0xff; + } + result = make_small(result); + $Dst = result; +} + +// +// i_bs_get_fixed_integer Ctx Size Flags Dst +// + +i_bs_get_fixed_integer := i_bs_get_fixed_integer.fetch.execute; + +i_bs_get_fixed_integer.head() { + Eterm context; +} + +i_bs_get_fixed_integer.fetch(Src) { + context = $Src; +} + +i_bs_get_fixed_integer.execute(Size, Flags, Dst) { + ErlBinMatchBuffer* mb; + Uint size = $Size; + Eterm result; + + mb = ms_matchbuffer(context); + LIGHT_SWAPOUT; + result = erts_bs_get_integer_2(c_p, size, $Flags, mb); + LIGHT_SWAPIN; + HEAP_SPACE_VERIFIED(0); + $Dst = result; +} + +// +// i_get_fixed_binary Ctx Size Dst +// + +i_bs_get_fixed_binary := i_bs_get_fixed_binary.fetch.execute; + +i_bs_get_fixed_binary.head() { + Eterm context; +} + +i_bs_get_fixed_binary.fetch(Src) { + context = $Src; +} + +i_bs_get_fixed_binary.execute(Size, Dst) { + ErlBinMatchBuffer* mb; + Uint size = $Size; + Eterm* htop; + Eterm result; + + ASSERT(header_is_bin_matchstate(*boxed_val(context))); + + htop = HTOP; + mb = ms_matchbuffer(context); + result = erts_extract_sub_binary(&htop, mb->orig, mb->base, + mb->offset, size); + HTOP = htop; + + mb->offset += size; + + $Dst = result; +} + +// +// i_get_tail Ctx Dst +// + +i_bs_get_tail := i_bs_get_tail.fetch.execute; + +i_bs_get_tail.head() { + Eterm context; +} + +i_bs_get_tail.fetch(Src) { + context = $Src; +} + +i_bs_get_tail.execute(Dst) { + ErlBinMatchBuffer* mb; + Eterm* htop; + Eterm result; + + ASSERT(header_is_bin_matchstate(*boxed_val(context))); + + htop = HTOP; + mb = ms_matchbuffer(context); + result = erts_extract_sub_binary(&htop, mb->orig, mb->base, + mb->offset, mb->size - mb->offset); + HTOP = htop; + + $Dst = result; +} + +// +// i_bs_skip Ctx Size +// + +i_bs_skip := i_bs_skip.fetch.execute; + +i_bs_skip.head() { + Eterm context; +} + +i_bs_skip.fetch(Src) { + context = $Src; +} + +i_bs_skip.execute(Size) { + ErlBinMatchBuffer* mb; + Uint size = $Size; + + ASSERT(header_is_bin_matchstate(*boxed_val(context))); + mb = ms_matchbuffer(context); + mb->offset += size; +} + +// i_bs_drop Size +i_bs_drop(Size) { + bitdata <<= $Size; +} diff --git a/erts/emulator/beam/emu/emu_load.c b/erts/emulator/beam/emu/emu_load.c index 35937754d9b0..8395a87076aa 100644 --- a/erts/emulator/beam/emu/emu_load.c +++ b/erts/emulator/beam/emu/emu_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -57,7 +57,7 @@ extern void check_allocated_block(Uint type, void *blk); static void init_label(Label* lp); -void beam_load_prepare_emit(LoaderState *stp) { +int beam_load_prepare_emit(LoaderState *stp) { BeamCodeHeader *hdr; int i; @@ -76,6 +76,7 @@ void beam_load_prepare_emit(LoaderState *stp) { hdr->compile_size_on_heap = 0; hdr->literal_area = NULL; hdr->md5_ptr = NULL; + hdr->are_nifs = NULL; stp->code_hdr = hdr; @@ -92,6 +93,12 @@ void beam_load_prepare_emit(LoaderState *stp) { init_label(&stp->labels[i]); } + stp->lambda_literals = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->beam.lambdas.count * sizeof(SWord)); + for (i = 0; i < stp->beam.lambdas.count; i++) { + stp->lambda_literals[i] = ERTS_SWORD_MAX; + } + stp->import_patches = erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->beam.imports.count * sizeof(BeamInstr)); @@ -136,6 +143,8 @@ void beam_load_prepare_emit(LoaderState *stp) { stp->beam.code.function_count * sizeof(unsigned int)); } + + return 1; } void beam_load_prepared_free(Binary* magic) @@ -155,11 +164,6 @@ int beam_load_prepared_dtor(Binary* magic) beamfile_free(&stp->beam); beamopallocator_dtor(&stp->op_allocator); - if (stp->bin) { - driver_free_binary(stp->bin); - stp->bin = NULL; - } - if (stp->code_hdr) { BeamCodeHeader *hdr = stp->code_hdr; @@ -167,6 +171,10 @@ int beam_load_prepared_dtor(Binary* magic) erts_release_literal_area(hdr->literal_area); hdr->literal_area = NULL; } + if (hdr->are_nifs) { + erts_free(ERTS_ALC_T_PREPARED_CODE, hdr->are_nifs); + hdr->are_nifs = NULL; + } erts_free(ERTS_ALC_T_CODE, hdr); stp->code_hdr = NULL; @@ -182,6 +190,11 @@ int beam_load_prepared_dtor(Binary* magic) stp->labels = NULL; } + if (stp->lambda_literals != NULL) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *)stp->lambda_literals); + stp->lambda_literals = NULL; + } + if (stp->import_patches != NULL) { erts_free(ERTS_ALC_T_PREPARED_CODE, (void*)stp->import_patches); stp->import_patches = NULL; @@ -330,6 +343,7 @@ int beam_load_finish_emit(LoaderState *stp) { BeamCodeLineTab* const line_tab = (BeamCodeLineTab *) (codev+stp->ci); const unsigned int ftab_size = stp->beam.code.function_count; const unsigned int num_instrs = stp->current_li; + const unsigned int num_names = stp->beam.lines.name_count; const void** const line_items = (const void**) &line_tab->func_tab[ftab_size + 1]; const void *locp_base; @@ -346,10 +360,10 @@ int beam_load_finish_emit(LoaderState *stp) { } line_items[i] = codev + stp->ci - 1; - line_tab->fname_ptr = (Eterm*) &line_items[i + 1]; - if (stp->beam.lines.name_count) { - sys_memcpy((void*)line_tab->fname_ptr, stp->beam.lines.names, - stp->beam.lines.name_count*sizeof(Eterm)); + line_tab->fname_ptr = (Eterm*)&line_items[i + 1]; + for (i = 0; i < num_names; i++) { + Eterm *fname = (Eterm*)&line_tab->fname_ptr[i]; + *fname = beamfile_get_literal(&stp->beam, stp->beam.lines.names[i]); } locp_base = &line_tab->fname_ptr[stp->beam.lines.name_count]; @@ -527,7 +541,7 @@ int beam_load_finish_emit(LoaderState *stp) { CHKBLK(ERTS_ALC_T_CODE,code_hdr); /* - * Save the updated code code size. + * Save the updated code size. */ stp->loaded_size = size; @@ -540,6 +554,7 @@ int beam_load_finish_emit(LoaderState *stp) { void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_p) { + ErtsCodeIndex staging_ix; unsigned int i; int on_load = stp->on_load; unsigned catches; @@ -551,6 +566,13 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ inst_p->code_hdr = stp->code_hdr; inst_p->code_length = size; + inst_p->writable_region = (void*)inst_p->code_hdr; + inst_p->executable_region = inst_p->writable_region; + + staging_ix = erts_staging_code_ix(); + + ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_load_permission() || + erts_thr_progress_is_blocking()); /* Update ranges (used for finding a function from a PC value). */ erts_update_ranges(inst_p->code_hdr, size); @@ -601,6 +623,7 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ */ if (stp->beam.lambdas.count) { BeamFile_LambdaTable *lambda_table; + ErtsLiteralArea *literal_area; ErlFunEntry **fun_entries; LambdaPatch* lp; int i; @@ -609,6 +632,8 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ fun_entries = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(ErlFunEntry*) * lambda_table->count); + literal_area = (stp->code_hdr)->literal_area; + for (i = 0; i < lambda_table->count; i++) { BeamFile_LambdaEntry *lambda; ErlFunEntry *fun_entry; @@ -623,14 +648,39 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ lambda->arity - lambda->num_free); fun_entries[i] = fun_entry; - if (erts_is_fun_loaded(fun_entry)) { + if (erts_is_fun_loaded(fun_entry, staging_ix)) { /* We've reloaded a module over itself and inherited the old * instance's fun entries, so we need to undo the reference * bump in `erts_put_fun_entry2` to make fun purging work. */ erts_refc_dectest(&fun_entry->refc, 1); } - fun_entry->address = stp->codev + stp->labels[lambda->label].value; + /* Finalize the literal we've created for this lambda, if any, + * converting it from an external fun to a local one with the newly + * created fun entry. */ + if (stp->lambda_literals[i] != ERTS_SWORD_MAX) { + ErlFunThing *funp; + Eterm literal; + + literal = beamfile_get_literal(&stp->beam, + stp->lambda_literals[i]); + funp = (ErlFunThing *)fun_val(literal); + ASSERT(funp->creator == am_external); + + funp->entry.fun = fun_entry; + + funp->next = literal_area->off_heap; + literal_area->off_heap = (struct erl_off_heap_header *)funp; + + ASSERT(erts_init_process_id != ERTS_INVALID_PID); + funp->creator = erts_init_process_id; + + erts_refc_inc(&fun_entry->refc, 2); + } + + erts_set_fun_code(fun_entry, + staging_ix, + stp->codev + stp->labels[lambda->label].value); } lp = stp->lambda_patches; @@ -686,7 +736,7 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ */ ep->trampoline.not_loaded.deferred = (BeamInstr) address; } else { - ep->addresses[erts_staging_code_ix()] = address; + ep->dispatch.addresses[staging_ix] = address; } } @@ -699,7 +749,8 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ Export *ep = erts_export_put(entry->module, entry->name, entry->arity); - const BeamInstr *addr = ep->addresses[erts_staging_code_ix()]; + const BeamInstr *addr = + ep->dispatch.addresses[staging_ix]; if (!ErtsInArea(addr, stp->codev, stp->ci * sizeof(BeamInstr))) { erts_exit(ERTS_ABORT_EXIT, @@ -716,18 +767,6 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ stp->code_hdr = NULL; } -static int -is_bif(Eterm mod, Eterm func, unsigned arity) -{ - Export *e = erts_active_export_entry(mod, func, arity); - - if (e != NULL) { - return e->bif_number != -1; - } - - return 0; -} - static void init_label(Label* lp) { lp->value = 0; @@ -843,11 +882,11 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'x': /* x(N) */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); - code[ci++] = tmp_op->a[arg].val * sizeof(Eterm); + code[ci++] = (tmp_op->a[arg].val & REG_MASK) * sizeof(Eterm); break; case 'y': /* y(N) */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); - code[ci++] = (tmp_op->a[arg].val + CP_SIZE) * sizeof(Eterm); + code[ci++] = ((tmp_op->a[arg].val & REG_MASK) + CP_SIZE) * sizeof(Eterm); break; case 'a': /* Tagged atom */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); @@ -877,10 +916,10 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { case 's': /* Any source (tagged constant or register) */ switch (tag) { case TAG_x: - code[ci++] = make_loader_x_reg(tmp_op->a[arg].val); + code[ci++] = make_loader_x_reg(tmp_op->a[arg].val & REG_MASK); break; case TAG_y: - code[ci++] = make_loader_y_reg(tmp_op->a[arg].val + CP_SIZE); + code[ci++] = make_loader_y_reg((tmp_op->a[arg].val & REG_MASK) + CP_SIZE); break; case TAG_i: code[ci++] = (BeamInstr) make_small((Uint)tmp_op->a[arg].val); @@ -915,10 +954,10 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { case 'S': /* Source (x(N), y(N)) */ switch (tag) { case TAG_x: - code[ci++] = tmp_op->a[arg].val * sizeof(Eterm); + code[ci++] = (tmp_op->a[arg].val & REG_MASK) * sizeof(Eterm); break; case TAG_y: - code[ci++] = (tmp_op->a[arg].val + CP_SIZE) * sizeof(Eterm) + 1; + code[ci++] = ((tmp_op->a[arg].val & REG_MASK) + CP_SIZE) * sizeof(Eterm) + 1; break; default: BeamLoadError1(stp, "bad tag %d for destination", @@ -949,7 +988,7 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'A': /* Arity value. */ BeamLoadVerifyTag(stp, tag, TAG_u); - code[ci++] = make_arityval(tmp_op->a[arg].val); + code[ci++] = make_arityval_unchecked(tmp_op->a[arg].val); break; case 'f': /* Destination label */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); @@ -1233,10 +1272,10 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { ci++; break; case TAG_x: - code[ci++] = make_loader_x_reg(tmp_op->a[arg].val); + code[ci++] = make_loader_x_reg(tmp_op->a[arg].val & REG_MASK); break; case TAG_y: - code[ci++] = make_loader_y_reg(tmp_op->a[arg].val + CP_SIZE); + code[ci++] = make_loader_y_reg((tmp_op->a[arg].val & REG_MASK) + CP_SIZE); break; case TAG_n: code[ci++] = NIL; @@ -1356,38 +1395,43 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { #endif } break; - case op_int_func_end: - { - /* - * Native function calls may be larger than their stubs, so - * we'll need to make sure any potentially-native function stub - * is padded with enough room. - */ - int padding_required; - - ci--; /* Get rid of the instruction */ - - padding_required = stp->may_load_nif || - is_bif(stp->module, stp->function, stp->arity); - - ASSERT(stp->last_func_start); - if (padding_required) { - Sint pad = BEAM_NATIVE_MIN_FUNC_SZ - (ci - stp->last_func_start); - if (pad > 0) { - ASSERT(pad < BEAM_NATIVE_MIN_FUNC_SZ); - CodeNeed(pad); - while (pad-- > 0) { - /* - * Filling with actual instructions (instead - * of zeroes) will look nicer in a disassembly - * listing. - */ - code[ci++] = BeamOpCodeAddr(op_padding); - } - } - } - } - break; + case op_nif_start: + if (!stp->code_hdr->are_nifs) { + int bytes = stp->beam.code.function_count * sizeof(byte); + stp->code_hdr->are_nifs = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + bytes); + sys_memzero(stp->code_hdr->are_nifs, bytes); + } + ASSERT(stp->function_number > 0); + ASSERT(stp->function_number <= stp->beam.code.function_count); + stp->code_hdr->are_nifs[stp->function_number-1] = 1; + + ci -= 1; /* Get rid of the instruction */ + break; + case op_i_nif_padding: + { + /* Native function calls may be larger than their stubs, so we'll + * need to make sure any potentially-native function stub is padded + * with enough room. */ + Sint pad; + + ci -= 1; /* Get rid of the instruction */ + + ASSERT(stp->last_func_start); + pad = BEAM_NATIVE_MIN_FUNC_SZ - (ci - stp->last_func_start); + + if (pad > 0) { + ASSERT(pad < BEAM_NATIVE_MIN_FUNC_SZ); + CodeNeed(pad); + + while (pad-- > 0) { + /* Filling with actual instructions (instead of zeroes) will + * look nicer in a disassembly listing. */ + code[ci++] = BeamOpCodeAddr(op_padding); + } + } + } + break; case op_on_load: ci--; /* Get rid of the instruction */ @@ -1399,6 +1443,21 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { case op_i_bs_match_string_yfWW: new_string_patch(stp, ci-1); break; + case op_i_bs_create_bin_jIWdW: + { + int n = tmp_op->arity; + BeamInstr* p = &code[ci-n]; + BeamInstr* end_p = &code[ci]; + while (p < end_p) { + switch (*p) { + case BSC_STRING: + new_string_patch(stp, p+3-code); + break; + } + p += 5; + } + } + break; case op_catch_yf: /* code[ci-3] &&lb_catch_yf * code[ci-2] y-register offset in E diff --git a/erts/emulator/beam/emu/float_instrs.tab b/erts/emulator/beam/emu/float_instrs.tab index ce0101f98e30..500a647d2b75 100644 --- a/erts/emulator/beam/emu/float_instrs.tab +++ b/erts/emulator/beam/emu/float_instrs.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2017-2021. All Rights Reserved. +// Copyright Ericsson AB 2017-2023. 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. @@ -74,9 +74,9 @@ i_fdiv(Src1, Src2, Dst) { } i_fnegate(Src, Dst) { + /* Note that there is no need to check for errors since flipping the sign + * of a finite float is guaranteed to produce a finite float. */ + ASSERT(erts_isfinite($Src)); $Dst = -$Src; - - if (!erts_isfinite($Dst)) { - $BADARITH0(); - } + ASSERT(erts_isfinite($Dst)); } diff --git a/erts/emulator/beam/emu/generators.tab b/erts/emulator/beam/emu/generators.tab index f9988f2399ad..5e516fc7d8b9 100644 --- a/erts/emulator/beam/emu/generators.tab +++ b/erts/emulator/beam/emu/generators.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. 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. @@ -19,6 +19,36 @@ // %CopyrightEnd% // +// Rewrites call_fun2 as call_fun: we're not yet helped by the Tag parameter, +// and can't do anything clever with Func either. +gen.call_fun2(Tag, Arity, Func) { + BeamOp *call; + + (void)Tag; + + $NewBeamOp(S, call); + $BeamOpNameArity(call, call_fun, 1); + call->a[0] = Arity; + call->next = NULL; + + /* Move the fun in place when needed. We don't generate this at the moment, + * but a future version of the compiler might keep Func in a Y register. */ + if (Func.type != TAG_x || Arity.val != Func.val) { + BeamOp *move; + + $NewBeamOp(S, move); + $BeamOpNameArity(move, move, 2); + move->a[0] = Func; + move->a[1].type = TAG_x; + move->a[1].val = Arity.val; + move->next = call; + + return move; + } + + return call; +} + // Generate the fastest instruction to fetch an integer from a binary. gen.get_integer2(Fail, Ms, Live, Size, Unit, Flags, Dst) { BeamOp* op; @@ -493,7 +523,7 @@ gen.select_tuple_arity(Src, Fail, Size, Rest) { for (i = 3; i < arity - 2*align; i+=2) { tmp[i-3].type = TAG_v; - tmp[i-3].val = make_arityval(Rest[i-3].val); + tmp[i-3].val = make_arityval_unchecked(Rest[i-3].val); tmp[i-2] = Rest[i-2]; } @@ -531,9 +561,13 @@ gen.new_small_map_lit(Dst, Live, Size, Rest) { $BeamOpArity(op, 3 + size/2); op->next = NULL; - tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, (1 + size/2) * sizeof(*tmp)); - keys = make_tuple(thp); - *thp++ = make_arityval(size/2); + tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, ((size == 0 ? 0 : 1) + size/2) * sizeof(*tmp)); + if (size == 0) { + keys = erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); + } else { + keys = make_tuple(thp); + *thp++ = make_arityval(size/2); + } dst = op->a+3; @@ -556,7 +590,7 @@ gen.new_small_map_lit(Dst, Live, Size, Rest) { *dst++ = Rest[i + 1]; } - lit = beamfile_add_literal(&S->beam, keys); + lit = beamfile_add_literal(&S->beam, keys, 1); erts_free(ERTS_ALC_T_LOADER_TMP, tmp); op->a[0] = Dst; @@ -831,3 +865,572 @@ gen.init_yregs(N, Yregs) { $INIT_YREGS(S, N.val); return first; } + +gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { + BeamOp* op; + int fixed_args; + BeamOpArg* src; + BeamOpArg* dst; + BeamOpArg* endp; + + endp = Segments + N.val; + N.val = 5*N.val/6; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_create_bin, 5); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Alloc; + op->a[2] = Live; + op->a[3] = Dst; + op->a[4] = N; + + for (src = Segments, dst = op->a+fixed_args; src < endp; src += 6, dst += 5) { + UWord unit; + BeamOpArg Flags; + Uint flags = 0; + BeamOpArg Size; + Uint type; + Uint segment; + + ASSERT(src[0].type = TAG_a); + ASSERT(src[1].type == TAG_u); + ASSERT(src[2].type == TAG_u); + segment = src[1].val; + + /* Get unit. */ + dst[1] = src[2]; + unit = dst[1].val; + + /* Translate flags. */ + Flags = src[3]; /* Flags */ + if (Flags.type != TAG_n) { + if (Flags.type == TAG_q) { + Eterm term = beamfile_get_literal(&S->beam, Flags.val); + while (is_list(term)) { + Eterm* consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + flags |= BSF_LITTLE; + break; + case am_native: + flags |= BSF_NATIVE; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + } + } + Flags.type = TAG_u; + Flags.val = flags; + $NativeEndian(Flags); + Flags.val = (segment << 3) | Flags.val; + dst[2] = Flags; + + /* Store source. */ + dst[3] = src[4]; /* Src */ + + /* Get size */ + Size = src[5]; /* Size */ + + /* Translate type. */ + switch (src[0].val) { + case am_append: + type = BSC_APPEND; + break; + case am_private_append: + type = BSC_PRIVATE_APPEND; + break; + case am_binary: + { + UWord bits; + type = BSC_BINARY; + if (Size.type == TAG_a && Size.val == am_all) { + type = BSC_BINARY_ALL; + } else if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_BINARY_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_float: + { + UWord bits; + type = BSC_FLOAT; + if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_FLOAT_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_integer: + { + UWord bits; + type = BSC_INTEGER; + if (Size.type == TAG_i && + (Sint) Size.val >= 0 && + beam_load_safe_mul(Size.val, unit, &bits) && + (bits >> (sizeof(Uint)-1)*8) == 0) { + type = BSC_INTEGER_FIXED_SIZE; + Size.type = TAG_u; + Size.val = bits; + unit = 0; + } + } + break; + case am_string: + type = BSC_STRING; + ASSERT(Size.type == TAG_i); + ASSERT(unit == 8); + Size.type = TAG_u; + Size.val = Size.val; /* Size of string in bytes. */ + unit = 0; + break; + case am_utf8: + type = BSC_UTF8; + break; + case am_utf16: + type = BSC_UTF16; + break; + case am_utf32: + type = BSC_UTF32; + Size.type = TAG_u; + Size.val = 32; + break; + default: + abort(); + } + dst[0].type = TAG_u; + dst[0].val = type; + + /* Store value of unit. */ + dst[1].val = unit; + + /* Store size. */ + dst[4] = Size; + } + return op; +} + +gen.update_record(Size, Src, Dst, N, Updates) { + BeamOp *begin, *prev; + Sint count, i; + + ASSERT(Size.type == TAG_u && Size.val < SCRATCH_X_REG); + ASSERT(N.type == TAG_u && !(N.val % 2) && (N.val / 2) <= Size.val); + + $NewBeamOp(S, begin); + $BeamOpNameArity(begin, i_update_record, 5); + + begin->a[0] = Size; + begin->a[1] = Src; + begin->a[2] = Dst; + begin->a[3] = Updates[0]; + begin->a[4] = Updates[1]; + + count = N.val; + prev = begin; + + for (i = 2; i < count; i += 2) { + BeamOp *next; + + $NewBeamOp(S, next); + $BeamOpNameArity(next, i_update_record_continue, 2); + + /* Encode the offset from the _end_ of the tuple so that we can act + * relative to HTOP. */ + next->a[0].type = TAG_u; + next->a[0].val = (Size.val + 1) - Updates[i].val; + + /* The first instruction overwrites the destination register after + * stashing its contents to SCRATCH_X_REG, so all updates must be + * rewritten accordingly. */ + if (Updates[i + 1].type == Dst.type && Updates[i + 1].val == Dst.val) { + next->a[1].type = TAG_x; + next->a[1].val = SCRATCH_X_REG; + } else { + next->a[1] = Updates[i + 1]; + } + + next->next = NULL; + prev->next = next; + + prev = next; + } + + return begin; +} + +gen.bs_match(Fail, Ctx, N, List) { + BeamOp* first_op = 0; + BeamOp** next_ptr = &first_op; + BeamOp* test_heap_op = 0; + BeamOp* read_op = 0; +#ifdef ARCH_64 + BeamOp* eq_op = 0; +#endif + int src; + + src = 0; + while (src < N.val) { + Uint unit; + Uint size; + Uint words_needed; + BeamOp* op; + + /* Calculate the number of heap words needed for this + * instruction. */ + words_needed = 0; + switch (List[src].val) { + case am_binary: + ASSERT(List[src+3].type == TAG_u); + ASSERT(List[src+4].type == TAG_u); + size = List[src+3].val * List[src+4].val; + words_needed = erts_extracted_binary_size(size); + break; + case am_integer: + ASSERT(List[src+3].type == TAG_u); + ASSERT(List[src+4].type == TAG_u); + size = List[src+3].val * List[src+4].val; + if (size >= SMALL_BITS) { + words_needed = BIG_NEED_FOR_BITS(size); + } + break; + case am_get_tail: + words_needed = EXTRACT_SUB_BIN_HEAP_NEED; + break; + } + + /* Emit a test_heap instrution if needed and there is + * no previous one. */ + if ((List[src].val == am_Eq || words_needed) && test_heap_op == 0 && + List[src+1].type == TAG_u) { + $NewBeamOp(S, test_heap_op); + $BeamOpNameArity(test_heap_op, test_heap, 2); + + test_heap_op->a[0].type = TAG_u; + test_heap_op->a[0].val = 0; /* Number of heap words */ + test_heap_op->a[1] = List[src+1]; /* Live */ + + *next_ptr = test_heap_op; + next_ptr = &test_heap_op->next; + } + + if (words_needed) { + test_heap_op->a[0].val += words_needed; + } + + /* Translate this sub-instruction to a BEAM instruction. */ + op = 0; + switch (List[src].val) { + case am_ensure_at_least: { + Uint size = List[src+1].val; + unit = List[src+2].val; + if (size != 0 && unit == 1) { + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_ensure_bits, 3); + op->a[0] = Ctx; + op->a[1].type = TAG_u; + op->a[1].val = size; + op->a[2] = Fail; + } else if (size != 0 && unit != 1) { + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_ensure_bits_unit, 4); + + op->a[0] = Ctx; + op->a[1].type = TAG_u; + op->a[1].val = size; /* Size */ + op->a[2].type = TAG_u; + op->a[2].val = unit; /* Unit */ + op->a[3] = Fail; + } else if (size == 0 && unit != 1) { + $NewBeamOp(S, op); + $BeamOpNameArity(op, bs_test_unit, 3); + + op->a[0] = Fail; + op->a[1] = Ctx; + op->a[2].type = TAG_u; + op->a[2].val = unit; + } else if (size == 0 && unit == 1) { + /* This test is redundant because it always + * succeeds. This should only happen for unoptimized + * code. Generate a dummy instruction to ensure that + * we don't trigger the sanity check at the end of + * this generator. */ + $NewBeamOp(S, op); + $BeamOpNameArity(op, delete_me, 0); + } + src += 3; + break; + } + case am_ensure_exactly: { + $NewBeamOp(S, op); + $BeamOpNameArity(op, bs_test_tail2, 3); + + op->a[0] = Fail; + op->a[1] = Ctx; + op->a[2]= List[src+1]; /* Size */ + + src += 2; + break; + } + case am_binary: { + ASSERT(List[src+3].type == TAG_u); + ASSERT(List[src+4].type == TAG_u); + size = List[src+3].val; + unit = List[src+4].val; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_get_fixed_binary, 3); + + op->a[0] = Ctx; + op->a[1].type = TAG_u; + op->a[1].val = size * unit; /* Size */ + op->a[2] = List[src+5]; /* Dst */ + + read_op = 0; + src += 6; + break; + } + case am_integer: { + Uint flags = 0; + BeamOpArg Flags; + + /* Translate flags. */ + Flags = List[src+2]; + if (Flags.type == TAG_n) { + Flags.type = TAG_u; + Flags.val = 0; + } else if (Flags.type == TAG_q) { + Eterm term = beamfile_get_literal(&S->beam, Flags.val); + while (is_list(term)) { + Eterm* consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + flags |= BSF_LITTLE; + break; + case am_native: + flags |= BSF_NATIVE; + break; + case am_signed: + flags |= BSF_SIGNED; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + Flags.type = TAG_u; + Flags.val = flags; + $NativeEndian(Flags); + } + + ASSERT(List[src+3].type == TAG_u); + ASSERT(List[src+4].type == TAG_u); + size = List[src+3].val * List[src+4].val; + +#define READ_OP_SIZE 1 + if (size < SMALL_BITS && flags == 0) { + /* This is a suitable segment -- an unsigned big + * endian integer that fits in a small. */ + if (read_op == 0 || read_op->a[READ_OP_SIZE].val + size > 8*sizeof(Uint)) { + /* There is either no previous i_bs_read_bits instruction or + * the size of this segment don't fit into it. */ + $NewBeamOp(S, read_op); + $BeamOpNameArity(read_op, i_bs_read_bits, 2); + + read_op->a[0] = Ctx; + read_op->a[1].type = TAG_u; + read_op->a[1].val = 0; + + *next_ptr = read_op; + next_ptr = &read_op->next; + } + + read_op->a[READ_OP_SIZE].val += size; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_extract_integer, 2); + op->a[0].type = TAG_u; + op->a[0].val = size; + op->a[1] = List[src+5]; /* Dst */ + } else { + /* Little endian, signed, or might not fit in a small. */ + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_get_fixed_integer, 4); + + op->a[0] = Ctx; + op->a[1].type = TAG_u; + op->a[1].val = size; /* Size */ + op->a[2] = Flags; /* Flags */ + op->a[3] = List[src+5]; /* Dst */ + + read_op = 0; + } + + src += 6; + break; + } + case am_Eq: { + ASSERT(List[src+2].type == TAG_u); + ASSERT(List[src+3].type == TAG_u); + size = List[src+2].val; + + if (read_op == 0 || read_op->a[READ_OP_SIZE].val + size > 8*sizeof(Uint)) { + /* There is either no previous i_bs_read_bits instruction or + * the size of this segment don't fit into it. */ + $NewBeamOp(S, read_op); + $BeamOpNameArity(read_op, i_bs_read_bits, 2); + + read_op->a[0] = Ctx; + read_op->a[1].type = TAG_u; + read_op->a[1].val = 0; + + *next_ptr = read_op; + next_ptr = &read_op->next; + } + + read_op->a[READ_OP_SIZE].val += size; + +#ifdef ARCH_64 + if (eq_op && + eq_op->next == 0 && /* Previous instruction? */ + eq_op->a[1].val + size <= 8*sizeof(Uint)) { + /* Coalesce with the previous `=:=` instruction. */ + eq_op->a[1].val += size; + eq_op->a[2].val = eq_op->a[2].val << size | List[src+3].val; + } +#else + if (0) { + ; + } +#endif + else { + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_eq, 3); + +#ifdef ARCH_64 + eq_op = op; +#endif + + op->a[0] = Fail; + op->a[1] = List[src+2]; /* Size */ + op->a[2] = List[src+3]; /* Value */ + } + + src += 4; + break; + } + case am_get_tail: + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_get_tail, 2); + + op->a[0] = Ctx; + op->a[1] = List[src+3]; /* Dst */ + + read_op = 0; + src += 4; + break; + case am_skip: + ASSERT(List[src+1].type == TAG_u); + size = List[src+1].val; + + $NewBeamOp(S, op); + + if (read_op && read_op->a[READ_OP_SIZE].val + size <= 8*sizeof(Uint)) { + read_op->a[READ_OP_SIZE].val += size; + $BeamOpNameArity(op, i_bs_drop, 1); + op->a[0] = List[src+1]; /* Size */ + } else { + $BeamOpNameArity(op, i_bs_skip, 2); + op->a[0] = Ctx; + op->a[1] = List[src+1]; /* Size */ + read_op = 0; + } + + src += 2; + break; + default: + /* + * This is an unknown sub command. It was probably produced by a later + * release of Erlang/OTP than the current one. Fail loading. + */ + + $NewBeamOp(S, op); + $BeamOpNameArity(op, bad_bs_match, 1); + op->a[0] = List[src]; + *next_ptr = op; + return first_op; + } + + if (op) { + *next_ptr = op; + next_ptr = &op->next; + } + } + + if (test_heap_op && test_heap_op->a[0].val == 0) { + /* This test_heap instruction was forced by the `=:=` sub + * instruction, but it turned out that no test_heap instruction was + * needed. */ + $BeamOpNameArity(test_heap_op, delete_me, 0); + } + + if (first_op == 0) { + erts_exit(ERTS_ERROR_EXIT, "loading bs_match in %T:%T/%d: no instructions loaded", + S->module, S->function, S->arity); + } + + ASSERT(first_op); + return first_op; +} + +gen_increment(stp, reg, val, dst) { + BeamOp* op; + $NewBeamOp($stp, op); + $BeamOpNameArity(op, i_increment, 3); + op->a[0] = $reg; + op->a[1].type = TAG_u; + op->a[1].val = $val; + op->a[2] = $dst; + return op; +} + +gen.increment(Reg, Integer, Dst) { + $gen_increment(S, Reg, Integer.val, Dst); +} + +gen.increment_from_minus(Reg, Integer, Dst) { + $gen_increment(S, Reg, -Integer.val, Dst); +} + +gen.plus_from_minus(Fail, Live, Src, Integer, Dst) { + BeamOp* op; + + ASSERT(Integer.type == TAG_i && IS_SSMALL(-(Sint)Integer.val)); + + $NewBeamOp(S, op); + $BeamOpNameArity(op, gen_plus, 5); + op->a[0] = Fail; + op->a[1] = Live; + op->a[2] = Src; + op->a[3].type = TAG_i; + op->a[3].val = -(Sint)Integer.val; + op->a[4] = Dst; + + return op; +} diff --git a/erts/emulator/beam/emu/instrs.tab b/erts/emulator/beam/emu/instrs.tab index 62ee76a7fb13..88e6da9bf159 100644 --- a/erts/emulator/beam/emu/instrs.tab +++ b/erts/emulator/beam/emu/instrs.tab @@ -243,7 +243,7 @@ APPLY(I, Deallocate, Next) { save_calls(c_p, ep); } - $Next = ep->addresses[erts_active_code_ix()]; + $Next = ep->dispatch.addresses[erts_active_code_ix()]; } HANDLE_APPLY_ERROR() { @@ -290,7 +290,7 @@ FIXED_APPLY(Arity, I, Deallocate, Next) { save_calls(c_p, ep); } - $Next = ep->addresses[erts_active_code_ix()]; + $Next = ep->dispatch.addresses[erts_active_code_ix()]; } apply(Arity) { @@ -310,10 +310,8 @@ apply_last(Arity, Deallocate) { } APPLY_FUN(Next) { - Export *ignored; - HEAVY_SWAPOUT; - $Next = apply_fun(c_p, r(0), x(1), reg, &ignored); + $Next = apply_fun(c_p, r(0), x(1), reg); HEAVY_SWAPIN; if (ERTS_UNLIKELY(next == NULL)) { @@ -350,10 +348,9 @@ i_apply_fun_only() { CALL_FUN(Fun, Next) { //| -no_next - Export *ignored; HEAVY_SWAPOUT; - $Next = call_fun(c_p, $Fun, reg, THE_NON_VALUE, &ignored); + $Next = call_fun(c_p, $Fun, reg, THE_NON_VALUE); HEAVY_SWAPIN; if (ERTS_UNLIKELY(next == NULL)) { @@ -543,12 +540,13 @@ init3(Y1, Y2, Y3) { make_blank($Y3); } -i_make_fun3(FunP, Dst, NumFree) { +i_make_fun3(FunP, Dst, Arity, NumFree) { ErlFunThing* funp; + ErlFunEntry *fe = (ErlFunEntry *) $FunP; int i, num_free = $NumFree; //| -no_next SWAPOUT; - funp = new_fun_thing(c_p, (ErlFunEntry *) $FunP, num_free); + funp = erts_new_local_fun_thing(c_p, fe, $Arity, num_free); SWAPIN; I = $NEXT_INSTRUCTION; for (i = 0; i < num_free; i++) { @@ -764,6 +762,30 @@ self(Dst) { $Dst = c_p->common.id; } +i_update_record(Size, Src, Dst, Offset, Element) { + Eterm *untagged_source = tuple_val($Src); + Uint size_on_heap = $Size + 1; + + /* Copy the entire tuple up-front, mimicking the behavior of the old + * setelement/3 + set_tuple_element method. This overwrites every field + * we're setting, but that cost is generally pretty small. */ + sys_memcpy(HTOP, untagged_source, size_on_heap * sizeof(Eterm)); + HTOP[$Offset] = $Element; + + /* We stash the contents of the destination register in SCRATCH_X_REG in + * case it's used in subsequent `i_update_record_continue` instructions. + * The updates have been rewritten accordingly. */ + reg[SCRATCH_X_REG] = $Dst; + $Dst = make_tuple(HTOP); + + HTOP += size_on_heap; +} + +i_update_record_continue(OffsetFromEnd, Element) { + Sint offset = -(Sint)$OffsetFromEnd; + HTOP[offset] = $Element; +} + set_tuple_element(Element, Tuple, Offset) { Eterm* p; @@ -1076,6 +1098,13 @@ if_end() { //| -no_next; } +badrecord(Src) { + c_p->fvalue = $Src; + c_p->freason = EXC_BADRECORD; + goto find_func_info; + //| -no_next; +} + system_limit_body() { c_p->freason = SYSTEM_LIMIT; $FAIL_BODY(); @@ -1088,29 +1117,40 @@ catch(Y, Fail) { } catch_end(Y) { + /* + * At entry: + * + * x0 = Result of expression or THE_NON_VALUE + * + * If x0 is THE_NON_VALUE, the following registers are also set: + * + * x1 = Error reason/thrown value + * x2 = Stacktrace + * x3 = Exception class + */ $try_end($Y); if (is_non_value(r(0))) { - c_p->fvalue = NIL; - c_p->ftrace = NIL; - if (x(1) == am_throw) { - r(0) = x(2); + ASSERT(c_p->fvalue == NIL); + ASSERT(c_p->ftrace == NIL); + if (x(3) == am_throw) { + r(0) = x(1); } else { - if (x(1) == am_error) { + if (x(3) == am_error) { SWAPOUT; - x(2) = add_stacktrace(c_p, x(2), x(3)); + x(1) = add_stacktrace(c_p, x(1), x(2)); SWAPIN; } - /* only x(2) is included in the rootset here */ + /* only x(1) is included in the rootset here */ if ((E - HTOP) < (3 + S_RESERVED)) { $GC_SWAPOUT(); PROCESS_MAIN_CHK_LOCKS(c_p); - FCALLS -= erts_garbage_collect_nobump(c_p, 3, reg+2, 1, FCALLS); + FCALLS -= erts_garbage_collect_nobump(c_p, 3, reg+1, 1, FCALLS); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; $MAYBE_EXIT_AFTER_GC(); } - r(0) = TUPLE2(HTOP, am_EXIT, x(2)); + r(0) = TUPLE2(HTOP, am_EXIT, x(1)); HTOP += 3; } } @@ -1127,9 +1167,7 @@ try_case(Y) { ASSERT(is_non_value(r(0))); ASSERT(c_p->fvalue == NIL); ASSERT(c_p->ftrace == NIL); - r(0) = x(1); - x(1) = x(2); - x(2) = x(3); + r(0) = x(3); } try_case_end(Src) { diff --git a/erts/emulator/beam/emu/load.h b/erts/emulator/beam/emu/load.h index 83e8ace504ab..6de420a5dc31 100644 --- a/erts/emulator/beam/emu/load.h +++ b/erts/emulator/beam/emu/load.h @@ -2,7 +2,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -93,11 +93,6 @@ typedef struct { * This structure contains all information about the module being loaded. */ struct LoaderState_ { - /* - * The current logical file within the binary. - */ - ErlDrvBinary* bin; /* Binary holding BEAM file (or NULL) */ - /* * The following are used mainly for diagnostics. */ @@ -147,6 +142,11 @@ struct LoaderState_ { unsigned int current_li; /* Current line instruction */ unsigned int* func_line; /* Mapping from function to first line instr */ + /* Translates lambda indexes to their literals, if any. Lambdas that lack + * a literal (for example if they have an environment) are represented by + * ERTS_SWORD_MAX. */ + SWord *lambda_literals; + int otp_20_or_higher; Uint last_func_start; diff --git a/erts/emulator/beam/emu/macros.tab b/erts/emulator/beam/emu/macros.tab index 99597f3495b3..c4353583ef0c 100644 --- a/erts/emulator/beam/emu/macros.tab +++ b/erts/emulator/beam/emu/macros.tab @@ -178,7 +178,7 @@ DISPATCH_EXPORT(Export) { DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, ep); - SET_I(ep->addresses[erts_active_code_ix()]); + SET_I(ep->dispatch.addresses[erts_active_code_ix()]); CHECK_ARGS(I); dis_next = *I; @@ -206,7 +206,7 @@ DISPATCH_FUN(I) { FCALLS--; Goto(dis_next); } else { - goto context_switch_fun; + goto context_switch; } } diff --git a/erts/emulator/beam/emu/map_instrs.tab b/erts/emulator/beam/emu/map_instrs.tab index efebd37fb3d5..9cd64662f859 100644 --- a/erts/emulator/beam/emu/map_instrs.tab +++ b/erts/emulator/beam/emu/map_instrs.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2017-2020. All Rights Reserved. +// Copyright Ericsson AB 2017-2021. 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. @@ -19,14 +19,6 @@ // %CopyrightEnd% // -ensure_map(Map) { - if (is_not_map($Map)) { - c_p->freason = BADMAP; - c_p->fvalue = $Map; - $FAIL_BODY(); - } -} - new_map(Dst, Live, N) { Eterm res; diff --git a/erts/emulator/beam/emu/ops.tab b/erts/emulator/beam/emu/ops.tab index 5899aca19694..7c4447d1450d 100644 --- a/erts/emulator/beam/emu/ops.tab +++ b/erts/emulator/beam/emu/ops.tab @@ -37,7 +37,7 @@ FORBIDDEN_TYPES=h # needs to be re-compiled with a modern compiler. too_old_compiler/0 -too_old_compiler | never() => +too_old_compiler | never() => _ # In R9C and earlier, the loader used to insert special instructions inside # the module_info/0,1 functions. (In R10B and later, the compiler inserts @@ -45,8 +45,10 @@ too_old_compiler | never() => # necessary.) Since the instructions don't work correctly in R12B, simply # refuse to load the module. -func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler -func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler +func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => + too_old_compiler +func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => + too_old_compiler # The undocumented and unsupported guard BIF is_constant/1 was removed # in R13. The is_constant/2 operation is marked as obsolete in genop.tab, @@ -55,12 +57,6 @@ func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compil bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler -# Since the constant pool was introduced in R12B, empty tuples ({}) -# are literals. Therefore we no longer need to allow put_tuple/2 -# with a tuple size of zero. - -put_tuple u==0 d => too_old_compiler - # # All the other instructions. # @@ -69,10 +65,11 @@ put_tuple u==0 d => too_old_compiler label L i_func_info I a a I int_code_end +nif_start i_generic_breakpoint i_debug_breakpoint -i_return_time_trace +i_call_trace_return i_return_to_trace i_yield trace_jump W @@ -85,8 +82,11 @@ int_func_start/5 int_func_start Lbl Line M F A => label Lbl | i_func_info u M F A | line Line # The end of a function. -int_func_end/0 -int_func_end +int_func_end/2 +int_func_end Func Entry | needs_nif_padding() => i_nif_padding +int_func_end Func Entry => _ + +i_nif_padding # Instruction used for padding functions that use native code. %cold @@ -99,14 +99,14 @@ padding # BIF, so we can omit the line instruction for non-BIFs. # -move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ +move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => move S X0 | call_ext_last Ar Func D -move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \ +move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => move S X0 | call_ext_only Ar Func -move S X0=x==0 | line Loc | call_last Ar Func D => \ +move S X0=x==0 | line Loc | call_last Ar Func D => move S X0 | call_last Ar Func D -move S X0=x==0 | line Loc | call_only Ar Func => \ +move S X0=x==0 | line Loc | call_only Ar Func => move S X0 | call_only Ar Func # To ensure that a "move Src x(0)" instruction can be combined with @@ -119,16 +119,19 @@ move S X0=x==0 | line Loc | call_only Ar Func => \ move S X0=x==0 | line Loc => line Loc | move S X0 # The line number in int_func_start/5 can be NIL. -line n => +line n => _ line I # For the JIT, the init_yregs/1 instruction allows generation of better code. # For the BEAM interpreter, though, it will probably be more efficient to # translate all uses of init_yregs/1 back to the instructions that the compiler # would emit before OTP 24. -allocate Ns Live | init_yregs N Yregs=* => allocate(Ns, Live, N, Yregs) -allocate_heap Ns Nh Live | init_yregs N Yregs=* => allocate_heap(Ns, Nh, Live, N, Yregs) -init_yregs N Yregs=* => init_yregs(N, Yregs) +allocate Ns Live | init_yregs N Yregs=* => + allocate(Ns, Live, N, Yregs) +allocate_heap Ns Nh Live | init_yregs N Yregs=* => + allocate_heap(Ns, Nh, Live, N, Yregs) +init_yregs N Yregs=* => + init_yregs(N, Yregs) allocate t t? allocate_heap t I t? @@ -170,36 +173,44 @@ init3 y y y select_val S=aiq Fail=f Size=u Rest=* => const_select_val(S, Fail, Size, Rest) -select_val S=s Fail=f Size=u Rest=* | use_jump_tab(Size, Rest, 2) => \ - jump_tab(S, Fail, Size, Rest) +select_val S=s Fail=f Size=u Rest=* | use_jump_tab(Size, Rest, 2) => + jump_tab(S, Fail, Size, Rest) -is_integer Fail=f S | select_val S=s Fail=f Size=u Rest=* | use_jump_tab(Size, Rest, 2) => \ - jump_tab(S, Fail, Size, Rest) +is_integer Fail=f S | select_val S2=s Fail2=f Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + use_jump_tab(Size, Rest, 2) => + jump_tab(S, Fail, Size, Rest) -is_integer TypeFail=f S | select_val S=s Fail=f Size=u Rest=* | \ - mixed_types(Size, Rest) => \ - split_values(S, TypeFail, Fail, Size, Rest) +is_integer TypeFail=f S | select_val S2=s Fail=f Size=u Rest=* | + equal(S, S2) | + mixed_types(Size, Rest) => + split_values(S, TypeFail, Fail, Size, Rest) -select_val S=s Fail=f Size=u Rest=* | mixed_types(Size, Rest) => \ - split_values(S, Fail, Fail, Size, Rest) +select_val S=s Fail=f Size=u Rest=* | mixed_types(Size, Rest) => + split_values(S, Fail, Fail, Size, Rest) -is_integer Fail=f S | select_val S=d Fail=f Size=u Rest=* | \ - fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) +is_integer Fail=f S | select_val S2=d Fail2=f Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -is_atom Fail=f S | select_val S=d Fail=f Size=u Rest=* | \ - fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) +is_atom Fail=f S | select_val S2=d Fail2=f Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -select_val S=s Fail=f Size=u Rest=* | floats_or_bignums(Size, Rest) => \ - select_literals(S, Fail, Size, Rest) +select_val S=s Fail=f Size=u Rest=* | floats_or_bignums(Size, Rest) => + select_literals(S, Fail, Size, Rest) -select_val S=d Fail=f Size=u Rest=* | fixed_size_values(Size, Rest) => \ - select_val(S, Fail, Size, Rest) +select_val S=d Fail=f Size=u Rest=* | fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \ - select_tuple_arity(S, Fail, Size, Rest) +is_tuple Fail=f S | select_tuple_arity S2=d Fail2=f Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) => + select_tuple_arity(S, Fail, Size, Rest) -select_tuple_arity S=d Fail=f Size=u Rest=* => \ - select_tuple_arity(S, Fail, Size, Rest) +select_tuple_arity S=d Fail=f Size=u Rest=* => + select_tuple_arity(S, Fail, Size, Rest) i_select_val_bins xy f? I * @@ -260,14 +271,15 @@ i_get_tuple_element3 x P x is_number f? xy %hot -is_number Fail=f i => +is_number Fail=f i => _ + is_number Fail=f na => jump Fail is_number Fail Literal=q => move Literal x | is_number Fail x jump f # -# Expection rasing instructions. Infrequently executed. +# Exception raising instructions. Infrequently executed. # %cold @@ -280,6 +292,8 @@ badmatch x if_end +badrecord s + # Operands for raise/2 are almost always in x(2) and x(1). # Optimize for that case. raise x==2 x==1 => i_raise @@ -288,9 +302,10 @@ raise Trace Value => move Trace x | move Value x=1 | move x x=2 | i_raise i_raise -# Workaround the limitation that generators must always return at least one instruction. +# Workaround the limitation that generators must always return at least one +# instruction. delete_me/0 -delete_me => +delete_me => _ system_limit/1 system_limit p => system_limit_body @@ -315,16 +330,16 @@ move_jump f c r # x -> y -move X1=x Y1=y | move X2=x Y2=y | succ(Y1, Y2) => \ +move X1=x Y1=y | move X2=x Y2=y | succ(Y1, Y2) => move_window2 X1 X2 Y1 -move_window2 X1 X2 Y1 | move X3=x Y3=y | is_offset(Y1, Y3, 2) => \ +move_window2 X1 X2 Y1 | move X3=x Y3=y | is_offset(Y1, Y3, 2) => move_window3 X1 X2 X3 Y1 -move_window3 X1 X2 X3 Y1 | move X4=x Y4=y | is_offset(Y1, Y4, 3) => \ +move_window3 X1 X2 X3 Y1 | move X4=x Y4=y | is_offset(Y1, Y4, 3) => move_window4 X1 X2 X3 X4 Y1 -move_window4 X1 X2 X3 X4 Y1=y | move X5=x Y5=y | is_offset(Y1, Y5, 4) => \ +move_window4 X1 X2 X3 X4 Y1=y | move X5=x Y5=y | is_offset(Y1, Y5, 4) => move_window5 X1 X2 X3 X4 X5 Y1 move_window2 x x y @@ -337,17 +352,17 @@ move_window5 x x x x x y move_src_window/4 move_src_window/5 -move Y1=y X1=x | move Y2=y X2=x | succ(Y1, Y2) => \ +move Y1=y X1=x | move Y2=y X2=x | succ(Y1, Y2) => move_src_window Y1 Y2 X1 X2 -move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | succ(Y2, Y3) => \ +move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | succ(Y2, Y3) => move_src_window Y1 Y3 X1 X2 X3 -move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | move Y4=y X4=x | succ(Y3, Y4) => \ +move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | move Y4=y X4=x | succ(Y3, Y4) => move_src_window2 Y1 X1 X2 | move_src_window Y3 Y4 X3 X4 -move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x => \ +move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3 -move_src_window Y1 Y3 X1 X2 X3 | move Y4=y X4=x | succ(Y3, Y4) => \ +move_src_window Y1 Y3 X1 X2 X3 | move Y4=y X4=x | succ(Y3, Y4) => move_src_window4 Y1 X1 X2 X3 X4 move_src_window Y1 y X1 X2 => move_src_window2 Y1 X1 X2 @@ -362,17 +377,31 @@ swap R1=x R2=y => swap R2 R1 swap xy x swap y y -swap R1=x R2=x | swap R3=x R1 => swap2 R1 R2 R3 +swap R1=x R2=x | swap R3=x R1Other | equal(R1, R1Other) => swap2 R1 R2 R3 swap2 x x x # move_shift -move SD=x D=x | move Src=cxy SD=x | distinct(D, Src) => move_shift Src SD D -move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D -move SD=y D=x | init SD | => move_shift n SD D -move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D -move SD=x==0 D=y | move Src=y SD=x==0 | distinct(D, Src) => move_shift Src SD D +move SD=x D=x | move Src=cxy SDOther=x | + equal(SD, SDOther) | distinct(D, Src) => + move_shift Src SD D + +move SD=y D=x | move Src=x SDOther=y | + equal(SD, SDOther) | distinct(D, Src) => + move_shift Src SD D + +move SD=y D=x | init SDOther | + equal(SD, SDOther) => + move_shift n SD D + +move SD=x D=y | move Src=x SDOther=x | + equal(SD, SDOther) | distinct(D, Src) => + move_shift Src SD D + +move SD=x==0 D=y | move Src=y SDOther | + equal(SD, SDOther) | distinct(D, Src) => + move_shift Src SD D move_shift cxy x x move_shift nx y x @@ -381,15 +410,15 @@ move_shift y r y # move2_par x x x x -move X1=x X2=x | move X3=x X4=x | independent_moves(X1, X2, X3, X4) => \ +move X1=x X2=x | move X3=x X4=x | independent_moves(X1, X2, X3, X4) => move2_par X1 X2 X3 X4 move2_par x x x x # move2_par x x x y -move X1=x X2=x | move X3=x Y1=y | independent_moves(X1, X2, X3, Y1) => \ +move X1=x X2=x | move X3=x Y1=y | independent_moves(X1, X2, X3, Y1) => move2_par X1 X2 X3 Y1 -move X3=x Y1=y | move X1=x X2=x | independent_moves(X3, Y1, X1, X2) => \ +move X3=x Y1=y | move X1=x X2=x | independent_moves(X3, Y1, X1, X2) => move2_par X1 X2 X3 Y1 move2_par x x x y @@ -400,23 +429,23 @@ move2_par y x y x # move2_par y x x y -move S1=y S2=x | move X1=x Y1=y | independent_moves(S1, S2, X1, Y1) => \ +move S1=y S2=x | move X1=x Y1=y | independent_moves(S1, S2, X1, Y1) => move2_par S1 S2 X1 Y1 -move X1=x Y1=y | move S1=y S2=x | independent_moves(S1, S2, X1, Y1) => \ +move X1=x Y1=y | move S1=y S2=x | independent_moves(S1, S2, X1, Y1) => move2_par S1 S2 X1 Y1 move2_par y x x y # move2_par y x x x -move Y1=y X1=x | move S1=x D1=x | independent_moves(Y1, X1, S1, D1) => \ +move Y1=y X1=x | move S1=x D1=x | independent_moves(Y1, X1, S1, D1) => move2_par Y1 X1 S1 D1 -move S1=x D1=x | move Y1=y X1=x | independent_moves(Y1, X1, S1, D1) => \ +move S1=x D1=x | move Y1=y X1=x | independent_moves(Y1, X1, S1, D1) => move2_par Y1 X1 S1 D1 move2_par y x x x # move2_par y y y y -move Y1=y Y2=y | move Y3=y Y4=y | independent_moves(Y1, Y2, Y3, Y4) => \ +move Y1=y Y2=y | move Y3=y Y4=y | independent_moves(Y1, Y2, Y3, Y4) => move2_par Y1 Y2 Y3 Y4 move2_par y y y y @@ -444,7 +473,7 @@ move r y loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail -label L | wait_timeout Fail Src | smp_already_locked(L) => \ +label L | wait_timeout Fail Src | smp_already_locked(L) => label L | wait_timeout_locked Src Fail wait_timeout Fail Src => wait_timeout_unlocked Src Fail @@ -481,7 +510,8 @@ send # Optimized comparisons with one immediate/literal operand. # -is_eq_exact Lbl S S => +is_eq_exact Lbl LHS RHS | equal(LHS, RHS) => _ + is_eq_exact Lbl C1=c C2=c => move C1 x | is_eq_exact Lbl x C2 is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C @@ -489,7 +519,7 @@ is_eq_exact Lbl R=xy n => is_nil Lbl R is_eq_exact Lbl R=xy C=ia => i_is_eq_exact_immed Lbl R C is_eq_exact Lbl R=xy C=q => i_is_eq_exact_literal Lbl R C -is_ne_exact Lbl S S => jump Lbl +is_ne_exact Lbl LHS RHS | equal(LHS, RHS) => jump Lbl is_ne_exact Lbl C1=c C2=c => move C1 x | is_ne_exact Lbl x C2 is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C @@ -549,21 +579,6 @@ is_ne f? S s # Code compiled with OTP 22 and later uses put_tuple2 to # to construct a tuple. # -# Code compiled before OTP 22 uses put_tuple + one put instruction -# per element. Translate to put_tuple2. -# - -i_put_tuple/2 -put_tuple Arity Dst => i_put_tuple Dst u - -i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \ - put S3 | put S4 | put S5 => \ - tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5) - -i_put_tuple Dst Arity Puts=* | put S => \ - tuple_append_put(Arity, Dst, Puts, S) - -i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts put_tuple2 xy I * @@ -576,7 +591,7 @@ put_tuple2 xy I * # put_list Const=c n Dst => move Const x | put_list x n Dst -put_list Src Dst=x Dst => update_list Src Dst +put_list Head Tail=x Dst | equal(Tail, Dst) => update_list Head Dst update_list xyc x @@ -627,7 +642,8 @@ return_trace # # Note: There is no 'move_return y r', since there never are any y registers -# when we do move_return (if we have y registers, we must do move_deallocate_return). +# when we do move_return (if we have y registers, we must do +# move_deallocate_return). move S x==0 | return => move_return S @@ -661,7 +677,7 @@ test_heap_1_put_list I y # is_tagged_tuple Fail=f Src=rxy Arity Atom=a # -is_tagged_tuple Fail Literal=q Arity Atom => \ +is_tagged_tuple Fail Literal=q Arity Atom => move Literal x | is_tagged_tuple Fail x Arity Atom is_tagged_tuple Fail=f c Arity Atom => jump Fail @@ -671,7 +687,9 @@ is_tagged_tuple f? rxy A a is_tuple Fail Literal=q => move Literal x | is_tuple Fail x is_tuple Fail=f c => jump Fail -is_tuple Fail=f S=xy | test_arity Fail=f S=xy Arity => is_tuple_of_arity Fail S Arity +is_tuple Fail=f S=xy | test_arity Fail2=f S2=xy Arity | + equal(Fail, Fail2) | equal(S, S2) => + is_tuple_of_arity Fail S Arity is_tuple_of_arity f? rxy A @@ -679,50 +697,58 @@ is_tuple f? rxy test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity test_arity Fail=f c Arity => jump Fail -test_arity Fail Tuple=x Arity | get_tuple_element Tuple Pos Dst=x => \ - test_arity_get_tuple_element Fail Tuple Arity Pos Dst +test_arity Fail Tuple=x Arity | get_tuple_element Tuple2 Pos Dst=x | + equal(Tuple, Tuple2) => + test_arity_get_tuple_element Fail Tuple Arity Pos Dst test_arity f? xy A test_arity_get_tuple_element f? x A P x -is_tuple NotTupleFail Tuple=x | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \ - is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom +is_tuple NotTupleFail Src=x | + is_tagged_tuple WrongRecordFail Tuple Arity Atom | + equal(Src, Tuple) => + is_tagged_tuple_ff NotTupleFail WrongRecordFail Src Arity Atom is_tagged_tuple_ff f? f? rx A a -get_tuple_element Reg=x P1 D1=x | \ - get_tuple_element Reg=x P2 D2=x | \ - get_tuple_element Reg=x P3 D3=x | \ - succ(P1, P2) | succ(P2, P3) | succ(D1, D2) | succ(D2, D3) | \ - distinct(D1, Reg) | distinct(D2, Reg) => \ - i_get_tuple_element3 Reg P1 D1 - -get_tuple_element Reg=x P1 D1=x | \ - get_tuple_element Reg=x P2 D2=x | \ - succ(P1, P2) | succ(D1, D2) | \ - distinct(D1, Reg) => \ - i_get_tuple_element2 Reg P1 D1 - -get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \ - succ(P1, P2) | distinct(D1, Reg) => i_get_tuple_element2_dst Reg P1 D1 D2 - -get_tuple_element Reg=x P1 D1=y | get_tuple_element Reg=x P2 D2=y | \ - succ(P1, P2) => i_get_tuple_element2_dst Reg P1 D1 D2 +get_tuple_element Reg=x P1 D1=x | + get_tuple_element Reg2 P2 D2=x | + get_tuple_element Reg3 P3 D3=x | + equal(Reg, Reg2) | equal(Reg, Reg3) | + succ(P1, P2) | succ(P2, P3) | succ(D1, D2) | succ(D2, D3) | + distinct(D1, Reg) | distinct(D2, Reg) => + i_get_tuple_element3 Reg P1 D1 + +get_tuple_element Reg=x P1 D1=x | + get_tuple_element Reg2 P2 D2=x | + equal(Reg, Reg2) | + succ(P1, P2) | succ(D1, D2) | + distinct(D1, Reg) => + i_get_tuple_element2 Reg P1 D1 + +get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg2=x P2 D2=x | + equal(Reg, Reg2) | succ(P1, P2) | distinct(D1, Reg) => + i_get_tuple_element2_dst Reg P1 D1 D2 + +get_tuple_element Reg=x P1 D1=y | get_tuple_element Reg2=x P2 D2=y | + equal(Reg, Reg2) | succ(P1, P2) => + i_get_tuple_element2_dst Reg P1 D1 D2 get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst -is_integer Fail=f i => +is_integer Fail=f i => _ is_integer Fail=f an => jump Fail is_integer Fail Literal=q => move Literal x | is_integer Fail x -is_integer Fail=f S=x | allocate Need Regs => is_integer_allocate Fail S Need Regs +is_integer Fail=f S=x | allocate Need Regs => + is_integer_allocate Fail S Need Regs is_integer_allocate f? x t t is_integer f? xy -is_list Fail=f n => +is_list Fail=f n => _ is_list Fail Literal=q => move Literal x | is_list Fail x is_list Fail=f c => jump Fail is_list f? x @@ -730,16 +756,20 @@ is_list f? x is_list f? y %hot -is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs +is_nonempty_list Fail=f S=x | allocate Need Rs => + is_nonempty_list_allocate Fail S Need Rs -is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \ - is_nonempty_list_get_list Fail S D1 D2 +is_nonempty_list Fail=f S=x | get_list S2 D1=x D2=x | + equal(S, S2) => + is_nonempty_list_get_list Fail S D1 D2 -is_nonempty_list Fail=f S=x | get_hd S Dst=x => \ - is_nonempty_list_get_hd Fail S Dst +is_nonempty_list Fail=f S=x | get_hd S2 Dst=x | + equal(S, S2) => + is_nonempty_list_get_hd Fail S Dst -is_nonempty_list Fail=f S=x | get_tl S Dst=x => \ - is_nonempty_list_get_tl Fail S Dst +is_nonempty_list Fail=f S=x | get_tl S2 Dst=x | + equal(S, S2) => + is_nonempty_list_get_tl Fail S Dst is_nonempty_list_allocate f? rx t t @@ -753,7 +783,7 @@ is_atom f? x %cold is_atom f? y %hot -is_atom Fail=f a => +is_atom Fail=f a => _ is_atom Fail=f niq => jump Fail is_float f? x @@ -763,7 +793,7 @@ is_float f? y is_float Fail=f nai => jump Fail is_float Fail Literal=q => move Literal x | is_float Fail x -is_nil Fail=f n => +is_nil Fail=f n => _ is_nil Fail=f qia => jump Fail is_nil f? xy @@ -803,8 +833,8 @@ is_port f? x is_port f? y %hot -is_boolean Fail=f a==am_true => -is_boolean Fail=f a==am_false => +is_boolean Fail=f a==am_true => _ +is_boolean Fail=f a==am_false => _ is_boolean Fail=f ac => jump Fail %cold @@ -837,9 +867,12 @@ call_light_bif_last/2 # The load_nif/2 BIF is an instruction. # -call_ext u==2 u$func:erlang:load_nif/2 => i_load_nif -call_ext_last u==2 u$func:erlang:load_nif/2 D => i_load_nif | deallocate_return D -call_ext_only u==2 u$func:erlang:load_nif/2 => i_load_nif | return +call_ext u==2 u$func:erlang:load_nif/2 => + i_load_nif +call_ext_last u==2 u$func:erlang:load_nif/2 D => + i_load_nif | deallocate_return D +call_ext_only u==2 u$func:erlang:load_nif/2 => + i_load_nif | return %cold i_load_nif @@ -876,11 +909,11 @@ call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate -call_ext u==0 u$func:os:perf_counter/0 => \ +call_ext u==0 u$func:os:perf_counter/0 => i_perf_counter -call_ext_last u==0 u$func:os:perf_counter/0 D => \ +call_ext_last u==0 u$func:os:perf_counter/0 D => i_perf_counter | deallocate_return D -call_ext_only u==0 u$func:os:perf_counter/0 => \ +call_ext_only u==0 u$func:os:perf_counter/0 => i_perf_counter | return # @@ -888,11 +921,11 @@ call_ext_only u==0 u$func:os:perf_counter/0 => \ # emulator state, which the ordinary call_light_bif instruction doesn't save. # -call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => \ +call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => i_call_ext Bif -call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => \ +call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => i_call_ext Bif | deallocate_return D -call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => \ +call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => allocate u Ar | i_call_ext Bif | deallocate_return u # @@ -910,9 +943,12 @@ call_ext_only Ar=u Bif=u$is_bif => call_light_bif_only Bif # with call instructions. # -move S=c x==0 | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S Func -move S=c x==0 | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S -move S=c x==0 | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S +move S=c x==0 | call_ext Ar=u Func=u$is_not_bif => + i_move_call_ext S Func +move S=c x==0 | call_ext_last Ar=u Func=u$is_not_bif D => + i_move_call_ext_last Func D S +move S=c x==0 | call_ext_only Ar=u Func=u$is_not_bif => + i_move_call_ext_only Func S call_ext Ar Func => i_call_ext Func call_ext_last Ar Func D => i_call_ext_last Func D @@ -934,13 +970,13 @@ i_apply_fun_only # stack frame before returning. # -call_light_bif Bif=u$is_bif => \ +call_light_bif Bif=u$is_bif => call_light_bif Bif Bif -call_light_bif_last Bif=u$is_bif D => \ +call_light_bif_last Bif=u$is_bif D => call_light_bif Bif Bif | deallocate_return D -call_light_bif_only Bif=u$is_bif => \ +call_light_bif_only Bif=u$is_bif => call_light_bif_only Bif Bif | deallocate_return u call_light_bif b e @@ -960,12 +996,16 @@ i_perf_counter bif0 u$bif:erlang:self/0 Dst=d => self Dst bif0 u$bif:erlang:node/0 Dst=d => node Dst -bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=x Dst=x => is_nonempty_list_get_hd Fail Src Dst -bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=x Dst=x => is_nonempty_list_get_tl Fail Src Dst +bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=x Dst=x => + is_nonempty_list_get_hd Fail Src Dst +bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=x Dst=x => + is_nonempty_list_get_tl Fail Src Dst -bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst) +bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => + get(Src, Dst) -bif2 Jump=j u$bif:erlang:element/2 S1=s S2=xy Dst=d => element(Jump, S1, S2, Dst) +bif2 Jump=j u$bif:erlang:element/2 S1=s S2=xy Dst=d => + element(Jump, S1, S2, Dst) bif1 p Bif S1 Dst => i_bif1_body S1 Bif Dst bif1 Fail=f Bif S1 Dst => i_bif1 S1 Fail Bif Dst @@ -1039,17 +1079,21 @@ call_fun Arity => i_call_fun Arity i_call_fun t i_call_fun_last t Q +call_fun2 Tag Arity Func => call_fun2(Tag, Arity, Func) + # # A fun with an empty environment can be converted to a literal. # As a further optimization, the we try to move the fun to its # final destination directly. -make_fun2 OldIndex=u => make_fun2(OldIndex) -make_fun3 OldIndex=u Dst=d NumFree=u Env=* => make_fun3(OldIndex, Dst, NumFree, Env) +make_fun2 OldIndex=u => + make_fun2(OldIndex) +make_fun3 OldIndex=u Dst=d NumFree=u Env=* => + make_fun3(OldIndex, Dst, NumFree, Env) %cold -i_make_fun3 F d t * +i_make_fun3 F d t t * # Psuedo-instruction for signalling lambda load errors. Never actually runs. i_lambda_error t @@ -1062,48 +1106,88 @@ is_function Fail=f c => jump Fail func_info M F A => i_func_info u M F A # ================================================================ -# Bit syntax matching obsoleted in OTP 22. +# New bit syntax matching for fixed sizes (from OTP 26). # ================================================================ -%cold -bs_start_match2 Fail=f ica X Y D => jump Fail -bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D -i_bs_start_match2 xy f t t d - -bs_save2 Y=y Index => move Y x | bs_save2 x Index -bs_save2 Reg Index => bs_save(Reg, Index) -i_bs_save2 x t - -bs_restore2 Y=y Index => move Y x | bs_restore2 x Index -bs_restore2 Reg Index => bs_restore(Reg, Index) -i_bs_restore2 x t - -bs_context_to_binary Y=y | line L | badmatch Y => \ - move Y x | bs_context_to_binary x | line L | badmatch x -bs_context_to_binary Y=y => move Y x | bs_context_to_binary x -bs_context_to_binary x %warm +bs_match Fail Ctx Size Rest=* => bs_match(Fail, Ctx, Size, Rest) + +# The bs_match generator breaks the bs_match instruction into +# the instructions that follow. + +i_bs_ensure_bits xy I f +i_bs_ensure_bits_unit xy I t f + +i_bs_read_bits xy t + +i_bs_eq f t W + +i_bs_extract_integer t d + +i_bs_read_bits Ctx=x u==8 | i_bs_extract_integer u==8 Dst=x => + i_bs_read_integer_8 Ctx Dst + +i_bs_read_integer_8 x x + +i_bs_get_fixed_integer xy I t d + +i_bs_get_fixed_binary xy I d + +i_bs_get_tail xy d + +i_bs_skip xy I + +i_bs_drop I + +i_bs_ensure_bits Ctx1 Size1 Fail | i_bs_read_bits Ctx2 Size2 | + equal(Ctx1, Ctx2) | equal(Size1, Size2) => + i_bs_ensure_bits_read Ctx1 Size1 Fail + +i_bs_ensure_bits_read xy t f + +# Optimize extraction of a single segment for some popular sizes. + +i_bs_ensure_bits Ctx1 u==8 Fail | i_bs_read_bits Ctx2 u==8 | + i_bs_extract_integer u==8 Dst=x | equal(Ctx1, Ctx2) => + i_bs_get_integer_8 Ctx1 Fail Dst + +i_bs_ensure_bits Ctx1 u==16 Fail | i_bs_read_bits Ctx2 u==16 | + i_bs_extract_integer u==16 Dst=x | equal(Ctx1, Ctx2) => + i_bs_get_integer_16 Ctx1 Fail Dst + +%if ARCH_64 +i_bs_ensure_bits Ctx1 u==32 Fail | i_bs_read_bits Ctx2 u==32 | + i_bs_extract_integer u==32 Dst=x | equal(Ctx1, Ctx2) => + i_bs_get_integer_32 Ctx1 Fail Dst +%endif + +# +# The following instruction is specially handled in beam_load.c +# to produce a user-friendly message if a bad bs_match instruction +# is encountered. +# +bad_bs_match/1 +bad_bs_match A | never() => _ + # ================================================================ -# New bit syntax matching (R11B). +# Bit syntax matching (from R11B). # ================================================================ -%warm - # Matching integers bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val i_bs_match_string xy f W W # Fetching integers from binaries. -bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ - get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) +bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => + get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) -i_bs_get_integer_small_imm Ms Bits Fail Flags Y=y => \ - i_bs_get_integer_small_imm Ms Bits Fail Flags x | move x Y +i_bs_get_integer_small_imm Ms Bits Fail Flags Y=y => + i_bs_get_integer_small_imm Ms Bits Fail Flags x | move x Y -i_bs_get_integer_imm Ms Bits Live Fail Flags Y=y => \ - i_bs_get_integer_imm Ms Bits Live Fail Flags x | move x Y +i_bs_get_integer_imm Ms Bits Live Fail Flags Y=y => + i_bs_get_integer_imm Ms Bits Live Fail Flags x | move x Y i_bs_get_integer_small_imm xy W f? t x i_bs_get_integer_imm xy W t f? t x @@ -1116,30 +1200,33 @@ i_bs_get_integer_32 xy f? d %endif # Fetching binaries from binaries. -bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ - get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) +bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => + get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) i_bs_get_binary_imm2 xy f? t W t d i_bs_get_binary2 xy f t? S t d i_bs_get_binary_all2 xy f? t t d # Fetching float from binaries. -bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \ - get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) +bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => + get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail i_bs_get_float2 xy f? t s t d -# Miscellanous +# Miscellaneous -bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => skip_bits2(Fail, Ms, Sz, Unit, Flags) +bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => + skip_bits2(Fail, Ms, Sz, Unit, Flags) i_bs_skip_bits_imm2 f? xy W i_bs_skip_bits2 xy xy f? t +bs_test_tail2 Fail=f Ms=xy o => jump Fail bs_test_tail2 Fail=f Ms=xy Bits=u==0 => bs_test_zero_tail2 Fail Ms bs_test_tail2 Fail=f Ms=xy Bits=u => bs_test_tail_imm2 Fail Ms Bits + bs_test_zero_tail2 f? xy bs_test_tail_imm2 f? xy W @@ -1156,24 +1243,25 @@ bs_get_tail xy d t # "slots" in the context itself, which lets us continue matching even after # we've passed it off to another function. -bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => \ +bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => bs_start_match3 p Src Live Ctx -bs_start_match4 Fail=f Live=u Src=xy Ctx=d => \ +bs_start_match4 Fail=f Live=u Src=xy Ctx=d => bs_start_match3 Fail Src Live Ctx %if ARCH_64 # This instruction nops on 64-bit platforms -bs_start_match4 a==am_resume Live Same Same => +bs_start_match4 a==am_resume Live Ctx Dst | equal(Ctx, Dst) => _ bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst -bs_start_match3 Fail Bin Live Ctx | bs_get_position Ctx Pos=x Ignored => \ +bs_start_match3 Fail Bin Live Ctx | bs_get_position Ctx2 Pos=x Ignored | + equal(Ctx, Ctx2) => i_bs_start_match3_gp Bin Live Fail Ctx Pos i_bs_start_match3_gp xy t j d x %else -bs_start_match4 a==am_resume Live Ctx Dst => \ +bs_start_match4 a==am_resume Live Ctx Dst => bs_start_match4 a=am_no_fail Live Ctx Dst %endif @@ -1208,39 +1296,51 @@ bs_skip_utf16 Fail=f Ms=xy Unit=u Flags=u => bs_get_utf16 Fail Ms Unit Flags x i_bs_get_utf16 xy f? t d -bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Ms=d => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ - i_bs_validate_unicode_retract Fail x Ms | \ - move x Ms -bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \ - i_bs_validate_unicode_retract Fail Dst Ms -bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ - i_bs_validate_unicode_retract Fail x Ms +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst | equal(Ms, Dst) => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms | + move x Dst + +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | + i_bs_validate_unicode_retract Fail Dst Ms + +bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms i_bs_validate_unicode_retract j s S %hot -# -# Constructing binaries -# +# ================================================================ +# New binary construction (OTP 25). +# ================================================================ + +bs_create_bin Fail Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => + create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) + +i_bs_create_bin j I W d W * + +# ================================================================ +# Old instruction for constructing binaries (up to OTP 24). +# ================================================================ + %warm bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail -bs_init2 Fail Sz Words Regs Flags Dst=y => \ - bs_init2 Fail Sz Words Regs Flags x | move x Dst +bs_init2 Fail Sz Words Regs Flags Dst=y => + bs_init2 Fail Sz Words Regs Flags x | move x Dst bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst -bs_init2 Fail Sz=u Words Regs Flags Dst => \ - i_bs_init_heap Sz Words Regs Dst +bs_init2 Fail Sz=u Words Regs Flags Dst => + i_bs_init_heap Sz Words Regs Dst -bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \ - i_bs_init_fail Sz Fail Regs Dst -bs_init2 Fail Sz Words Regs Flags Dst => \ - i_bs_init_fail_heap Sz Words Fail Regs Dst +bs_init2 Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_fail Sz Fail Regs Dst +bs_init2 Fail Sz Words Regs Flags Dst => + i_bs_init_fail_heap Sz Words Fail Regs Dst i_bs_init_fail xy j? t? x @@ -1252,16 +1352,18 @@ i_bs_init_heap W I t? x bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail -bs_init_bits Fail Sz Words Regs Flags Dst=y => \ - bs_init_bits Fail Sz Words Regs Flags x | move x Dst +bs_init_bits Fail Sz Words Regs Flags Dst=y => + bs_init_bits Fail Sz Words Regs Flags x | move x Dst -bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init_bits Sz Regs Dst -bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Regs Dst +bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => + i_bs_init_bits Sz Regs Dst +bs_init_bits Fail Sz=u Words Regs Flags Dst => + i_bs_init_bits_heap Sz Words Regs Dst -bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \ - i_bs_init_bits_fail Sz Fail Regs Dst -bs_init_bits Fail Sz Words Regs Flags Dst => \ - i_bs_init_bits_fail_heap Sz Words Fail Regs Dst +bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_bits_fail Sz Fail Regs Dst +bs_init_bits Fail Sz Words Regs Flags Dst => + i_bs_init_bits_fail_heap Sz Words Fail Regs Dst i_bs_init_bits_fail xy j? t? x @@ -1274,14 +1376,14 @@ bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D bs_add j? s s t? x -bs_append Fail Size Extra Live Unit Bin Flags Dst => \ - move Bin x | i_bs_append Fail Extra Live Unit Size Dst +bs_append Fail Size Extra Live Unit Bin Flags Dst => + move Bin x | i_bs_append Fail Extra Live Unit Size Dst -bs_private_append Fail Size Unit Bin Flags Dst => \ - i_bs_private_append Fail Unit Size Bin Dst +bs_private_append Fail Size Unit Bin Flags Dst => + i_bs_private_append Fail Unit Size Bin Dst -i_bs_private_append Fail Unit Size Bin Dst=y => \ - i_bs_private_append Fail Unit Size Bin x | move x Dst +i_bs_private_append Fail Unit Size Bin Dst=y => + i_bs_private_append Fail Unit Size Bin x | move x Dst bs_init_writable @@ -1292,8 +1394,8 @@ i_bs_private_append j? t s S x # Storing integers into binaries. # -bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \ - put_integer(Fail, Sz, Unit, Flags, Src) +bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => + put_integer(Fail, Sz, Unit, Flags, Src) i_new_bs_put_integer j? S t s i_new_bs_put_integer_imm xyc j? W t @@ -1309,8 +1411,8 @@ bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) -bs_put_utf32 Fail=j Flags=u Src=s => \ - i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src +bs_put_utf32 Fail=j Flags=u Src=s => + i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src i_bs_utf8_size S x i_bs_utf16_size S x @@ -1333,10 +1435,10 @@ i_bs_validate_unicode Fail Src=c => move Src x | i_bs_validate_unicode Fail x # Will fail. No need to keep the instruction, because bs_add or # bs_init* would already have raised an exception. -bs_put_float Fail Sz=q Unit Flags Val => +bs_put_float Fail Sz=q Unit Flags Val => _ -bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \ - put_float(Fail, Sz, Unit, Flags, Src) +bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => + put_float(Fail, Sz, Unit, Flags, Src) i_new_bs_put_float j? S t s i_new_bs_put_float_imm j? W t s @@ -1345,17 +1447,17 @@ i_new_bs_put_float_imm j? W t s # Storing binaries into binaries. # -bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \ - put_binary(Fail, Sz, Unit, Flags, Src) +bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => + put_binary(Fail, Sz, Unit, Flags, Src) -# In unoptimized code, the binary argument could be a literal. (In optimized code, -# there would be a bs_put_string instruction.) -i_new_bs_put_binary Fail Size Unit Lit=c => \ - move Lit x | i_new_bs_put_binary Fail Size Unit x -i_new_bs_put_binary_imm Fail Size Lit=c => \ - move Lit x | i_new_bs_put_binary_imm Fail Size x -i_new_bs_put_binary_all Lit=c Fail Unit => \ - move Lit x | i_new_bs_put_binary_all x Fail Unit +# In unoptimized code, the binary argument could be a literal. (In optimized +# code, there would be a bs_put_string instruction.) +i_new_bs_put_binary Fail Size Unit Lit=c => + move Lit x | i_new_bs_put_binary Fail Size Unit x +i_new_bs_put_binary_imm Fail Size Lit=c => + move Lit x | i_new_bs_put_binary_imm Fail Size x +i_new_bs_put_binary_all Lit=c Fail Unit => + move Lit x | i_new_bs_put_binary_all x Fail Unit i_new_bs_put_binary j? S t S i_new_bs_put_binary_imm j? W S @@ -1399,8 +1501,8 @@ i_fnegate l l # FPE signals were disabled in OTP 21 and we don't intend to ever # enable them again. # -fclearerror => -fcheckerror p => +fclearerror => _ +fcheckerror p => _ %hot @@ -1412,68 +1514,48 @@ apply t apply_last t Q # -# Handle compatibility with OTP 17 here. +# Map instructions. First introduced in R17. # -i_put_map_assoc/4 - -# We KNOW that in OTP 20 (actually OTP 18 and higher), a put_map_assoc instruction -# is always preceded by an is_map test. That means that put_map_assoc can never -# fail and does not need any failure label. - -put_map_assoc Fail Map Dst Live Size Rest=* | compiled_with_otp_20_or_higher() => \ - i_put_map_assoc Map Dst Live Size Rest - -# Translate the put_map_assoc instruction if the module was compiled by a compiler -# before 20. This is only necessary if the OTP 17 compiler was used, but we -# have no safe and relatively easy way to know whether OTP 18/19 was used. +# We KNOW that in OTP 18 and higher, a put_map_assoc instruction is +# always preceded by an is_map test. That means that put_map_assoc can +# never fail and does not need any failure label. -put_map_assoc Fail=p Map Dst Live Size Rest=* => \ - ensure_map Map | i_put_map_assoc Map Dst Live Size Rest -put_map_assoc Fail=f Map Dst Live Size Rest=* => \ - is_map Fail Map | i_put_map_assoc Map Dst Live Size Rest +put_map_assoc Fail Map Dst Live Size Rest=* => + i_put_map_assoc Map Dst Live Size Rest -ensure_map Lit=q | literal_is_map(Lit) => -ensure_map Src=cqy => move Src x | ensure_map x - -%cold -ensure_map x -%hot - -# -# Map instructions. First introduced in R17. -# +i_put_map_assoc/4 sorted_put_map_assoc/4 -i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ - sorted_put_map_assoc Map Dst Live Size Rest +i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_assoc Map Dst Live Size Rest sorted_put_map_exact/5 -put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ - sorted_put_map_exact F Map Dst Live Size Rest +put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_exact F Map Dst Live Size Rest -sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \ - new_map Dst Live Size Rest -sorted_put_map_assoc Src=xyc Dst Live Size Rest=* => \ - update_map_assoc Src Dst Live Size Rest +sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => + new_map Dst Live Size Rest +sorted_put_map_assoc Src=xyc Dst Live Size Rest=* => + update_map_assoc Src Dst Live Size Rest + +sorted_put_map_exact Fail Src=xy Dst Live Size Rest=* => + update_map_exact Src Fail Dst Live Size Rest -sorted_put_map_exact Fail Src=xy Dst Live Size Rest=* => \ - update_map_exact Src Fail Dst Live Size Rest # Literal map arguments for an exact update operation are extremely rare. -sorted_put_map_exact Fail Src Dst Live Size Rest=* => \ - move Src x | update_map_exact x Fail Dst Live Size Rest +sorted_put_map_exact Fail Src Dst Live Size Rest=* => + move Src x | update_map_exact x Fail Dst Live Size Rest -new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \ - new_small_map_lit(Dst, Live, Size, Rest) +new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => + new_small_map_lit(Dst, Live, Size, Rest) new_map d t I * i_new_small_map_lit d t q * update_map_assoc xyc d t I * update_map_exact xy j? d t I * -is_map Fail Lit=q | literal_is_map(Lit) => +is_map Fail Lit=q | literal_is_map(Lit) => _ is_map Fail cq => jump Fail - is_map f? xy ## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements @@ -1482,18 +1564,18 @@ has_map_fields Fail Src Size Rest=* => has_map_fields(Fail, Src, Size, Rest) ## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } -get_map_elements Fail Src Size=u==2 Rest=* => \ +get_map_elements Fail Src Size=u==2 Rest=* => get_map_element(Fail, Src, Size, Rest) -get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \ - get_map_elements(Fail, Src, Size, Rest) +get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => + get_map_elements(Fail, Src, Size, Rest) i_get_map_elements f? s I * -i_get_map_element_hash Fail Src=c Key Hash Dst => \ +i_get_map_element_hash Fail Src=c Key Hash Dst => move Src x | i_get_map_element_hash Fail x Key Hash Dst i_get_map_element_hash f? xy c I xy -i_get_map_element Fail Src=c Key Dst => \ +i_get_map_element Fail Src=c Key Dst => move Src x | i_get_map_element Fail x Key Dst i_get_map_element f? xy xy xy @@ -1503,28 +1585,28 @@ i_get_map_element f? xy xy xy gen_plus/5 gen_minus/5 -gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \ - gen_plus Fail Live Src i Dst -gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ - gen_plus Fail Live S1 S2 Dst +gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => + gen_plus Fail Live Src i Dst +gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => + gen_plus Fail Live S1 S2 Dst -gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \ - i_unary_minus Src Fail Dst -gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \ - gen_minus Fail Live S1 S2 Dst +gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => + i_unary_minus Src Fail Dst +gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => + gen_minus Fail Live S1 S2 Dst # # Optimize addition and subtraction of small literals using # the i_increment/3 instruction (in bodies, not in guards). # -gen_plus p Live Int=i Reg=d Dst => \ - increment(Reg, Int, Dst) -gen_plus p Live Reg=d Int=i Dst => \ - increment(Reg, Int, Dst) +gen_plus p Live Int=i Reg=d Dst => + increment(Reg, Int, Dst) +gen_plus p Live Reg=d Int=i Dst => + increment(Reg, Int, Dst) -gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ - increment_from_minus(Reg, Int, Dst) +gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => + increment_from_minus(Reg, Int, Dst) # # Arithmetic instructions. @@ -1533,39 +1615,40 @@ gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ # It is OK to swap arguments for '+' in a guard. It is also # OK to turn minus into plus in a guard. gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst -gen_minus Fail=f Live S1 S2=i Dst | negation_is_small(S2) => \ +gen_minus Fail=f Live S1 S2=i Dst | negation_is_small(S2) => plus_from_minus(Fail, Live, S1, S2, Dst) gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \ - i_times Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => + i_times Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \ - i_m_div Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \ - i_int_div Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => + i_m_div Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => + i_int_div Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \ - i_rem S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => + i_rem S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \ - i_bsl S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \ - i_bsr S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => + i_bsl S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => + i_bsr S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \ - i_band S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => + i_band S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \ - i_bor Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => + i_bor Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \ - i_bxor Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => + i_bxor Fail S1 S2 Dst -gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src Dst +gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst=d => + i_int_bnot Fail Src Dst i_increment rxy W d @@ -1621,8 +1704,8 @@ bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler # Handle the length/1 guard BIF specially to make it trappable. # -gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \ - i_length_setup Live Src | i_length Fail Live Dst +gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => + i_length_setup Live Src | i_length Fail Live Dst i_length_setup Live Src=c => move Src x | i_length_setup Live x @@ -1647,7 +1730,7 @@ gc_bif3 Fail=f Live Bif S1 S2 S3 Dst => i_bif3 S3 S2 S1 Fail Bif Dst # encountered. # unsupported_guard_bif/3 -unsupported_guard_bif A B C | never() => +unsupported_guard_bif A B C | never() => _ # # R13B03 @@ -1663,8 +1746,8 @@ on_load recv_mark f => i_recv_mark i_recv_mark -recv_set Fail | label Lbl | loop_rec Lf Reg => \ - i_recv_set | label Lbl | loop_rec Lf Reg +recv_set Fail | label Lbl | loop_rec Lf Reg => + i_recv_set | label Lbl | loop_rec Lf Reg i_recv_set # @@ -1699,3 +1782,15 @@ recv_marker_reserve S recv_marker_bind S S recv_marker_clear S recv_marker_use S + +# +# OTP 26 +# + +update_record Hint=a Size=u Src=s Dst=d N=u Updates=* => + update_record(Size, Src, Dst, N, Updates) + +i_update_record Size=u Src=c Dst=xy Offset=u Element=s => + move Src x | i_update_record Size x Dst Offset Element +i_update_record t xy xy t s +i_update_record_continue t s diff --git a/erts/emulator/beam/emu/predicates.tab b/erts/emulator/beam/emu/predicates.tab index 4542d8bf0fab..927e4e504ff6 100644 --- a/erts/emulator/beam/emu/predicates.tab +++ b/erts/emulator/beam/emu/predicates.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. 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. @@ -45,3 +45,39 @@ pred.independent_moves(Src1, Dst1, Src2, Dst2) { (Src2.type != Dst1.type || Src2.val != Dst1.val) && (Dst1.type != Dst2.type ||Dst1.val != Dst2.val); } + +pred.needs_nif_padding() { + Export *e = erts_active_export_entry(S->module, S->function, S->arity); + + if (e != NULL && e->bif_number != -1) { + return 1; + } + + /* If the module may load a NIF lib, all functions or functions declared as + * -nifs() must be able to hold a NIF stub. So we'll pad to that size at the + * end of every potential NIF function. + */ + return S->may_load_nif && + (S->code_hdr->are_nifs == NULL || + S->code_hdr->are_nifs[S->function_number-1]); +} + +// Test whether the given literal is a map. +pred.literal_is_map(Lit) { + Eterm term; + + ASSERT(Lit.type == TAG_q); + term = beamfile_get_literal(&S->beam, Lit.val); + return is_map(term); +} + +// Test whether the negation of the given number is small. +pred.negation_is_small(Int) { + /* + * Check for the rare case of overflow in BeamInstr (UWord) -> Sint. + * Cast to the correct type before using IS_SSMALL (Sint). + */ + return Int.type == TAG_i && + !(Int.val & ~((((BeamInstr)1) << ((sizeof(Sint)*8)-1))-1)) && + IS_SSMALL(-((Sint)Int.val)); +} diff --git a/erts/emulator/beam/emu/trace_instrs.tab b/erts/emulator/beam/emu/trace_instrs.tab index 630a9eb2d93a..9b0b377ed77c 100644 --- a/erts/emulator/beam/emu/trace_instrs.tab +++ b/erts/emulator/beam/emu/trace_instrs.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2017-2020. All Rights Reserved. +// Copyright Ericsson AB 2017-2023. 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. @@ -27,7 +27,7 @@ return_trace() { erts_trace_return(c_p, mfa, r(0), ERTS_TRACER_FROM_ETERM(E+2)/* tracer */); ERTS_REQ_PROC_MAIN_LOCK(c_p); SWAPIN; - E += 3; + E += 1 + BEAM_RETURN_TRACE_FRAME_SZ; $RETURN(); Goto(*I); //| -no_next @@ -49,7 +49,7 @@ i_generic_breakpoint() { //| -no_next } -i_return_time_trace() { +i_call_trace_return() { const ErtsCodeInfo *cinfo; if (is_CP(E[1])) { @@ -59,10 +59,10 @@ i_return_time_trace() { } SWAPOUT; - erts_trace_time_return(c_p, cinfo); + erts_call_trace_return(c_p, cinfo, E[2]); SWAPIN; - E += 2; + E += 1 + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; $RETURN(); Goto(*I); //| -no_next @@ -94,7 +94,7 @@ i_return_to_trace() { ERTS_REQ_PROC_MAIN_LOCK(c_p); SWAPIN; } - E += 1; + E += 1 + BEAM_RETURN_TO_TRACE_FRAME_SZ; $RETURN(); Goto(*I); //| -no_next @@ -165,7 +165,7 @@ i_debug_breakpoint() { HEAVY_SWAPIN; if (breakpoint_handler) { - I = breakpoint_handler->addresses[erts_active_code_ix()]; + I = breakpoint_handler->dispatch.addresses[erts_active_code_ix()]; Goto(*I); } diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index bbe0e90ae1b1..a344b585aeef 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2022. All Rights Reserved. + * Copyright Ericsson AB 2002-2023. 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. @@ -38,7 +38,6 @@ #include "erl_db.h" #include "erl_binary.h" #include "erl_bits.h" -#include "erl_mtrace.h" #include "erl_mseg.h" #include "erl_monitor_link.h" #include "erl_hl_timer.h" @@ -80,6 +79,9 @@ #define ERTS_ALC_DEFAULT_ACUL_EHEAP_ALLOC ERTS_ALC_DEFAULT_ENABLED_ACUL_EHEAP_ALLOC #define ERTS_ALC_DEFAULT_ACUL_LL_ALLOC ERTS_ALC_DEFAULT_ENABLED_ACUL_LL_ALLOC +#define ERTS_ALC_DEFAULT_ENABLED_ACFUL ERTS_ALC_DEFAULT_ENABLED_ACUL - 20 +#define ERTS_ALC_DEFAULT_ENABLED_ACFUL_EHEAP_ALLOC ERTS_ALC_DEFAULT_ENABLED_ACUL_EHEAP_ALLOC - 20 +#define ERTS_ALC_DEFAULT_ENABLED_ACFUL_LL_ALLOC ERTS_ALC_DEFAULT_ENABLED_ACUL_LL_ALLOC - 20 #ifdef DEBUG static Uint install_debug_functions(void); @@ -183,7 +185,6 @@ struct au_init { } typedef struct { - int erts_alloc_config; #if HAVE_ERTS_MSEG ErtsMsegInit_t mseg; #endif @@ -191,10 +192,6 @@ typedef struct { int top_pad; int dirty_alloc_insts; AlcUInit_t alloc_util; - struct { - char *mtrace; - char *nodename; - } instr; struct au_init sl_alloc; struct au_init std_alloc; struct au_init ll_alloc; @@ -315,6 +312,7 @@ set_default_literal_alloc_opts(struct au_init *ip) ip->init.util.rsbcmt = 0; ip->init.util.rmbcmt = 0; ip->init.util.acul = 0; + ip->init.util.acful = 0; #if defined(ARCH_32) # if HAVE_ERTS_MSEG @@ -597,6 +595,9 @@ adjust_carrier_migration_support(struct au_init *auip) auip->init.aoff.blk_order = FF_BF; } } + if (auip->init.util.acful > auip->init.util.acul) { + auip->init.util.acful = auip->init.util.acul; + } } void @@ -605,7 +606,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) UWord extra_block_size = 0; int i, ncpu; erts_alc_hndl_args_init_t init = { - 0, #if HAVE_ERTS_MSEG ERTS_MSEG_INIT_DEFAULT_INITIALIZER, #endif @@ -644,6 +644,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) = ERTS_MAGIC_BIN_UNALIGNED_SIZE(sizeof(ErtsMagicIndirectionWord)); fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_RECV_MARK_BLK)] = sizeof(ErtsRecvMarkerBlock); + fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_SIGQ_BUFFERS)] + = sizeof(ErtsSignalInQueueBufferArray); #ifdef HARD_DEBUG hdbg_init(); @@ -657,9 +659,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) if (ncpu < 1) ncpu = 1; - erts_tsd_key_create(&erts_allctr_prelock_tsd_key, - "erts_allctr_prelock_tsd_key"); - erts_sys_alloc_init(); erts_init_utils_mem(); @@ -697,6 +696,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) /* Make adjustments for carrier migration support */ init.temp_alloc.init.util.acul = 0; + init.temp_alloc.init.util.acful = 0; adjust_carrier_migration_support(&init.sl_alloc); adjust_carrier_migration_support(&init.std_alloc); adjust_carrier_migration_support(&init.ll_alloc); @@ -707,34 +707,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) adjust_carrier_migration_support(&init.fix_alloc); adjust_carrier_migration_support(&init.literal_alloc); - if (init.erts_alloc_config) { - /* Adjust flags that erts_alloc_config won't like */ - - /* No thread specific instances */ - init.temp_alloc.thr_spec = 0; - init.sl_alloc.thr_spec = 0; - init.std_alloc.thr_spec = 0; - init.ll_alloc.thr_spec = 0; - init.eheap_alloc.thr_spec = 0; - init.binary_alloc.thr_spec = 0; - init.ets_alloc.thr_spec = 0; - init.driver_alloc.thr_spec = 0; - init.fix_alloc.thr_spec = 0; - init.literal_alloc.thr_spec = 0; - - /* No carrier migration */ - init.temp_alloc.init.util.acul = 0; - init.sl_alloc.init.util.acul = 0; - init.std_alloc.init.util.acul = 0; - init.ll_alloc.init.util.acul = 0; - init.eheap_alloc.init.util.acul = 0; - init.binary_alloc.init.util.acul = 0; - init.ets_alloc.init.util.acul = 0; - init.driver_alloc.init.util.acul = 0; - init.fix_alloc.init.util.acul = 0; - init.literal_alloc.init.util.acul = 0; - } - /* Only temp_alloc can use thread specific interface */ if (init.temp_alloc.thr_spec) init.temp_alloc.thr_spec = erts_no_schedulers + init.dirty_alloc_insts; @@ -770,7 +742,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) if (!init.temp_alloc.thr_spec) refuse_af_strategy(&init.temp_alloc); - erts_mtrace_pre_init(); #if HAVE_ERTS_MSEG init.mseg.nos = erts_no_schedulers; init.mseg.ndai = init.dirty_alloc_insts; @@ -826,8 +797,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) sys_alloc_opt(SYS_ALLOC_OPT_TRIM_THRESHOLD, init.trim_threshold); sys_alloc_opt(SYS_ALLOC_OPT_TOP_PAD, init.top_pad); - erts_mtrace_init(init.instr.mtrace, init.instr.nodename); - start_au_allocator(ERTS_ALC_A_TEMPORARY, &init.temp_alloc, &temp_alloc_state); @@ -869,8 +838,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) &init.test_alloc, &test_alloc_state); - erts_mtrace_install_wrapper_functions(); - init_aireq_alloc(); #ifdef DEBUG @@ -1286,6 +1253,30 @@ get_acul_value(struct au_init *auip, char *param_end, char** argv, int* ip) return (Uint) tmp; } +static Uint +get_acful_value(struct au_init *auip, char *param_end, char** argv, int* ip) +{ + Sint tmp; + char *rest; + char *param = argv[*ip]+1; + char *value = get_value(param_end, argv, ip); + if (sys_strcmp(value, "de") == 0) { + switch (auip->init.util.alloc_no) { + case ERTS_ALC_A_LONG_LIVED: + return ERTS_ALC_DEFAULT_ENABLED_ACFUL_LL_ALLOC; + case ERTS_ALC_A_EHEAP: + return ERTS_ALC_DEFAULT_ENABLED_ACFUL_EHEAP_ALLOC; + default: + return ERTS_ALC_DEFAULT_ENABLED_ACFUL; + } + } + errno = 0; + tmp = (Sint) ErtsStrToSint(value, &rest, 10); + if (errno != 0 || rest == value || tmp < 0 || 100 < tmp) + bad_value(param, param_end, value); + return (Uint) tmp; +} + static void handle_au_arg(struct au_init *auip, char* sub_param, @@ -1315,6 +1306,10 @@ handle_au_arg(struct au_init *auip, value = get_amount_value(sub_param + 5, argv, ip); wp = &auip->init.util.acfml; } + else if (has_prefix("acful", sub_param)) { + value = get_acful_value(auip, sub_param + 5, argv, ip); + wp = &auip->init.util.acful; + } else goto bad_switch; @@ -1381,8 +1376,10 @@ handle_au_arg(struct au_init *auip, bad_value(param, sub_param + 1, alg); } } - if (!strategy_support_carrier_migration(auip)) + if (!strategy_support_carrier_migration(auip)) { auip->init.util.acul = 0; + auip->init.util.acful = 0; + } } else if (has_prefix("atags", sub_param)) { auip->init.util.atags = get_bool_value(sub_param + 5, argv, ip); } @@ -1514,6 +1511,7 @@ handle_au_arg(struct au_init *auip, else if (res == 0) { auip->thr_spec = 0; auip->init.util.acul = 0; + auip->init.util.acful = 0; break; } goto bad_switch; @@ -1698,9 +1696,6 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) for (a = 0; a < aui_sz; a++) aui[a]->enable = 1; } - else if (sys_strcmp("config", arg) == 0) { - init->erts_alloc_config = 1; - } else if (sys_strcmp("r9c", arg) == 0 || sys_strcmp("r10b", arg) == 0 || sys_strcmp("r11b", arg) == 0) { @@ -1725,6 +1720,7 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) for (a = 0; a < aui_sz; a++) { aui[a]->thr_spec = 0; aui[a]->init.util.acul = 0; + aui[a]->init.util.acful = 0; aui[a]->init.util.ramv = 0; aui[a]->init.util.lmbcs = 5*1024*1024; } @@ -1738,15 +1734,6 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) bad_param(param, param+1); } break; - case 'i': - switch (argv[i][3]) { - case 't': - init->instr.mtrace = get_value(argv[i]+4, argv, &i); - break; - default: - bad_param(param, param+2); - } - break; case 'l': if (has_prefix("pm", param+2)) { arg = get_value(argv[i]+5, argv, &i); @@ -1816,18 +1803,6 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init) case '-': if (argv[i][2] == '\0') { /* End of system flags reached */ - if (init->instr.mtrace) { - while (i < *argc) { - if(sys_strcmp(argv[i], "-sname") == 0 - || sys_strcmp(argv[i], "-name") == 0) { - if (i + 1 <*argc) { - init->instr.nodename = argv[i+1]; - break; - } - } - i++; - } - } goto args_parsed; } break; @@ -2202,7 +2177,7 @@ erts_memory(fmtfn_t *print_to_p, void *print_to_arg, void *proc, Eterm earg) ERTS_LC_ASSERT(erts_thr_progress_is_blocking()); - /* Figure out whats wanted... */ + /* Figure out what's wanted... */ length = 0; if (is_non_value(earg)) { /* i.e. wants all */ @@ -2870,9 +2845,6 @@ erts_allocator_info(fmtfn_t to, void *arg) erts_print(to, arg, "=allocator:instr\n"); - erts_print(to, arg, "option t: %s\n", - erts_mtrace_enabled ? "true" : "false"); - } Eterm @@ -2974,14 +2946,6 @@ erts_allocator_options(void *proc) terms[length++] = erts_mmap_info_options(&erts_dflt_mmapper, NULL, NULL, NULL, hpp, szp); #endif - { - Eterm o[1], v[1]; - o[0] = ERTS_MAKE_AM("t"); - v[0] = erts_mtrace_enabled ? am_true : am_false; - - atoms[length] = ERTS_MAKE_AM("instr"); - terms[length++] = erts_bld_2tup_list(hpp, szp, 1, o, v); - } atoms[length] = ERTS_MAKE_AM("lock_physical_memory"); terms[length++] = (lock_all_physical_memory ? am_all : am_no); @@ -3139,7 +3103,7 @@ reply_alloc_info(void *vair) if (hpp) sys_alloc_stat(&sas); if (szp) { - /* ensure ehough heap */ + /* ensure enough heap */ sas.top_pad = INT_MAX; sas.trim_threshold = INT_MAX; } @@ -3480,54 +3444,6 @@ Eterm erts_alloc_set_dyn_param(Process* c_p, Eterm tuple) return res; } -/* - * The allocator wrapper prelocking stuff below is about the locking order. - * It only affects wrappers (erl_mtrace.c) that keep locks during - * alloc/realloc/free. - * - * Some query functions in erl_alloc_util.c lock the allocator mutex and then - * use erts_printf that in turn may call the sys allocator through the wrappers. - * To avoid breaking locking order these query functions first "pre-locks" all - * allocator wrappers. - */ -ErtsAllocatorWrapper_t *erts_allctr_wrappers; -int erts_allctr_wrapper_prelocked = 0; -erts_tsd_key_t erts_allctr_prelock_tsd_key; - -void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper) -{ - ASSERT(wrapper->lock && wrapper->unlock); - wrapper->next = erts_allctr_wrappers; - erts_allctr_wrappers = wrapper; -} - -void erts_allctr_wrapper_pre_lock(void) -{ - if (erts_allctr_wrappers) { - ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers; - for ( ; wrapper; wrapper = wrapper->next) { - wrapper->lock(); - } - ASSERT(!erts_allctr_wrapper_prelocked); - erts_allctr_wrapper_prelocked = 1; - erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)1); - } -} - -void erts_allctr_wrapper_pre_unlock(void) -{ - if (erts_allctr_wrappers) { - ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers; - - erts_allctr_wrapper_prelocked = 0; - erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)0); - for ( ; wrapper; wrapper = wrapper->next) { - wrapper->unlock(); - } - } -} - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * NOTE: erts_alc_test() is only supposed to be used for testing. * * * diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h index c0c1890b0a94..00ab6284d78b 100644 --- a/erts/emulator/beam/erl_alloc.h +++ b/erts/emulator/beam/erl_alloc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2021. All Rights Reserved. + * Copyright Ericsson AB 2002-2022. 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. @@ -164,18 +164,6 @@ typedef struct { extern ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1]; -typedef struct ErtsAllocatorWrapper_t_ { - void (*lock)(void); - void (*unlock)(void); - struct ErtsAllocatorWrapper_t_* next; -}ErtsAllocatorWrapper_t; -extern ErtsAllocatorWrapper_t *erts_allctr_wrappers; -extern int erts_allctr_wrapper_prelocked; -extern erts_tsd_key_t erts_allctr_prelock_tsd_key; -void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper); -void erts_allctr_wrapper_pre_lock(void); -void erts_allctr_wrapper_pre_unlock(void); - void erts_alloc_register_scheduler(void *vesdp); void erts_alloc_register_delayed_dealloc_handler_thread(ErtsThrAllocData *tadp, int ix); @@ -225,11 +213,11 @@ Eterm erts_alloc_set_dyn_param(struct process*, Eterm); #if !ERTS_ALC_DO_INLINE -void *erts_alloc(ErtsAlcType_t type, Uint size); -void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size); void erts_free(ErtsAlcType_t type, void *ptr); -void *erts_alloc_fnf(ErtsAlcType_t type, Uint size); -void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size); +void *erts_alloc(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_USD(2,erts_free,2); +void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size) ERTS_ATTR_ALLOC_SIZE(3); +void *erts_alloc_fnf(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_USD(2,erts_free,2); +void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size) ERTS_ATTR_ALLOC_SIZE(3); int erts_is_allctr_wrapper_prelocked(void); #ifdef ERTS_HAVE_IS_IN_LITERAL_RANGE int erts_is_in_literal_range(void* ptr); @@ -239,7 +227,7 @@ int erts_get_thr_alloc_ix(void); #endif /* #if !ERTS_ALC_DO_INLINE */ -void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size); +void *erts_alloc_permanent_cache_aligned(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2); #ifndef ERTS_CACHE_LINE_SIZE /* Assumed cache line size */ @@ -320,13 +308,6 @@ void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size) return res; } -ERTS_ALC_INLINE -int erts_is_allctr_wrapper_prelocked(void) -{ - return erts_allctr_wrapper_prelocked /* locked */ - && !!erts_tsd_get(erts_allctr_prelock_tsd_key); /* by me */ -} - ERTS_ALC_INLINE ErtsThrAllocData *erts_get_thr_alloc_data(void) { diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index f01d1a96d319..1be51c037311 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2021. All Rights Reserved. +# Copyright Ericsson AB 2003-2023. 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. @@ -254,6 +254,7 @@ type BINARY_FIND SHORT_LIVED PROCESSES binary_find type CRASH_DUMP STANDARD SYSTEM crash_dump type DIST_TRANSCODE SHORT_LIVED SYSTEM dist_transcode_context type RLA_BLOCK_CNTRS LONG_LIVED SYSTEM release_literal_area_block_counters +type SIGQ_BUFFERS FIXED_SIZE PROCESSES process_signal_queue_buffers type THR_Q_EL STANDARD SYSTEM thr_q_element type THR_Q_EL_SL FIXED_SIZE SYSTEM sl_thr_q_element @@ -273,6 +274,7 @@ type THR_PRGR_DATA LONG_LIVED SYSTEM thr_prgr_data type T_THR_PRGR_DATA SHORT_LIVED SYSTEM temp_thr_prgr_data type RELEASE_LAREA SHORT_LIVED SYSTEM release_literal_area type SIG_DATA SHORT_LIVED PROCESSES signal_data +type SIG_YIELD_DATA SHORT_LIVED PROCESSES signal_yield_data type DIST_DEMONITOR SHORT_LIVED PROCESSES dist_demonitor type CML_CLEANUP SHORT_LIVED SYSTEM connection_ml_cleanup type ML_YIELD_STATE SHORT_LIVED SYSTEM monitor_link_yield_state @@ -304,6 +306,8 @@ type SL_MPATHS SHORT_LIVED SYSTEM sl_migration_paths type T2B_DETERMINISTIC SHORT_LIVED PROCESSES term_to_binary_deterministic +type DSIG_HNDL_NTFY SHORT_LIVED PROCESSES dirty_signal_handler_notification + # # Types used for special emulators # diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index 6584bbc74360..be5705c63750 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -43,7 +43,6 @@ #include "global.h" #include "big.h" #include "erl_mmap.h" -#include "erl_mtrace.h" #define GET_ERL_ALLOC_UTIL_IMPL #include "erl_alloc_util.h" #include "erl_mseg.h" @@ -51,6 +50,7 @@ #include "erl_thr_progress.h" #include "erl_bif_unique.h" #include "erl_nif.h" +#include "erl_global_literals.h" #ifdef ERTS_ENABLE_LOCK_COUNT #include "erl_lock_count.h" @@ -1090,8 +1090,6 @@ erts_alcu_sys_alloc(Allctr_t *allctr, Uint* size_p, int superalign) #endif res = erts_sys_alloc(0, NULL, size); INC_CC(allctr->calls.sys_alloc); - if (erts_mtrace_enabled) - erts_mtrace_crr_alloc(res, allctr->alloc_no, ERTS_ALC_A_SYSTEM, size); return res; } @@ -1108,12 +1106,6 @@ erts_alcu_sys_realloc(Allctr_t *allctr, void *ptr, Uint *size_p, Uint old_size, #endif res = erts_sys_realloc(0, NULL, ptr, size); INC_CC(allctr->calls.sys_realloc); - if (erts_mtrace_enabled) - erts_mtrace_crr_realloc(res, - allctr->alloc_no, - ERTS_ALC_A_SYSTEM, - ptr, - size); return res; } @@ -1127,8 +1119,6 @@ erts_alcu_sys_dealloc(Allctr_t *allctr, void *ptr, Uint size, int superalign) #endif erts_sys_free(0, NULL, ptr); INC_CC(allctr->calls.sys_free); - if (erts_mtrace_enabled) - erts_mtrace_crr_free(allctr->alloc_no, ERTS_ALC_A_SYSTEM, ptr); } #ifdef ARCH_32 @@ -1703,7 +1693,7 @@ dealloc_mbc(Allctr_t *allctr, Carrier_t *crr) } -static UWord allctr_abandon_limit(Allctr_t *allctr); +static UWord allctr_abandon_limit(Allctr_t *allctr, UWord); static void set_new_allctr_abandon_limit(Allctr_t*); static void abandon_carrier(Allctr_t*, Carrier_t*); static void poolify_my_carrier(Allctr_t*, Carrier_t*); @@ -1780,7 +1770,7 @@ get_used_allctr(Allctr_t *pref_allctr, int pref_lock, void *p, UWord *sizep, * This carrier has just been given back to us by writing * to crr->allctr with a write barrier (see abandon_carrier). * - * We need a mathing read barrier to guarantee a correct view + * We need a matching read barrier to guarantee a correct view * of the carrier for deallocation work. */ act = erts_atomic_cmpxchg_rb(&crr->allctr, @@ -2261,7 +2251,7 @@ check_abandon_carrier(Allctr_t *allctr, Block_t *fblk, Carrier_t **busy_pcrr_pp) if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr)) return; - ASSERT(allctr->cpool.abandon_limit == allctr_abandon_limit(allctr)); + ASSERT(allctr->cpool.abandon_limit == allctr_abandon_limit(allctr, allctr->cpool.util_limit)); ASSERT(erts_thr_progress_is_managed_thread()); if (allctr->cpool.disable_abandon) @@ -2665,6 +2655,9 @@ carrier_mem_discard_free_blocks(Allctr_t *allocator, Carrier_t *carrier) Block_t *block; int i; + if (carrier->cpool.total_blocks_size > carrier->cpool.discard_limit) + return; + block = allocator->first_fblk_in_mbc(allocator, carrier); i = 0; @@ -2733,7 +2726,7 @@ mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp blk = PREV_BLK(blk); (*allctr->unlink_free_block)(allctr, blk); - if (discard) { + if (discard && crr->cpool.total_blocks_size <= crr->cpool.discard_limit) { mem_discard_coalesce(allctr, blk, &discard_region); } @@ -2753,7 +2746,7 @@ mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp /* Coalesce with next block... */ (*allctr->unlink_free_block)(allctr, nxt_blk); - if (discard) { + if (discard && crr->cpool.total_blocks_size <= crr->cpool.discard_limit) { mem_discard_coalesce(allctr, nxt_blk, &discard_region); } @@ -2793,7 +2786,7 @@ mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp (*allctr->link_free_block)(allctr, blk); HARD_CHECK_BLK_CARRIER(allctr, blk); - if (discard) { + if (discard && crr->cpool.total_blocks_size <= crr->cpool.discard_limit) { mem_discard_finish(allctr, blk, &discard_region); } @@ -3079,7 +3072,7 @@ mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size, } if (cand_blk_sz < get_blk_sz) { - /* We wont fit in cand_blk get a new one */ + /* We won't fit in cand_blk get a new one */ #endif /* !MBC_REALLOC_ALWAYS_MOVES */ @@ -3153,7 +3146,7 @@ mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size, /* * Copy user-data then update new blocks in mbc_alloc_finalize(). * mbc_alloc_finalize() may write headers at old location of - * user data; therfore, order is important. + * user data; therefore, order is important. */ new_p = BLK2UMEM(new_blk); @@ -3876,6 +3869,17 @@ static void dealloc_my_carrier(Allctr_t *allctr, Carrier_t *crr) erts_alloc_ensure_handle_delayed_dealloc_call(allctr->ix); } +static ERTS_INLINE UWord +cpoll_init_carrier_limit(Carrier_t *crr, UWord percent_limit) { + UWord csz = CARRIER_SZ(crr); + UWord limit = percent_limit*csz; + if (limit > csz) + limit /= 100; + else + limit = (csz/100)*percent_limit; + return limit; +} + static ERTS_INLINE void cpool_init_carrier_data(Allctr_t *allctr, Carrier_t *crr) { @@ -3888,16 +3892,12 @@ cpool_init_carrier_data(Allctr_t *allctr, Carrier_t *crr) sys_memset(&crr->cpool.blocks_size, 0, sizeof(crr->cpool.blocks_size)); sys_memset(&crr->cpool.blocks, 0, sizeof(crr->cpool.blocks)); crr->cpool.total_blocks_size = 0; - if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr)) + if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr)) { crr->cpool.abandon_limit = 0; - else { - UWord csz = CARRIER_SZ(crr); - UWord limit = csz*allctr->cpool.util_limit; - if (limit > csz) - limit /= 100; - else - limit = (csz/100)*allctr->cpool.util_limit; - crr->cpool.abandon_limit = limit; + crr->cpool.discard_limit = 0; + } else { + crr->cpool.abandon_limit = cpoll_init_carrier_limit(crr, allctr->cpool.util_limit); + crr->cpool.discard_limit = cpoll_init_carrier_limit(crr, allctr->cpool.free_util_limit); } crr->cpool.state = ERTS_MBC_IS_HOME; } @@ -3905,7 +3905,7 @@ cpool_init_carrier_data(Allctr_t *allctr, Carrier_t *crr) static UWord -allctr_abandon_limit(Allctr_t *allctr) +allctr_abandon_limit(Allctr_t *allctr, UWord percent_limit) { UWord limit; UWord csz; @@ -3916,11 +3916,11 @@ allctr_abandon_limit(Allctr_t *allctr) csz += allctr->mbcs.carriers[i].size; } - limit = csz*allctr->cpool.util_limit; + limit = csz*percent_limit; if (limit > csz) limit /= 100; else - limit = (csz/100)*allctr->cpool.util_limit; + limit = (csz/100)*percent_limit; return limit; } @@ -3928,7 +3928,7 @@ allctr_abandon_limit(Allctr_t *allctr) static void ERTS_INLINE set_new_allctr_abandon_limit(Allctr_t *allctr) { - allctr->cpool.abandon_limit = allctr_abandon_limit(allctr); + allctr->cpool.abandon_limit = allctr_abandon_limit(allctr, allctr->cpool.util_limit); } static void @@ -4580,6 +4580,7 @@ static struct { Eterm smbcs; Eterm mbcgs; Eterm acul; + Eterm acful; Eterm acnl; Eterm acfml; Eterm cp; @@ -4690,6 +4691,7 @@ init_atoms(Allctr_t *allctr) AM_INIT(smbcs); AM_INIT(mbcgs); AM_INIT(acul); + AM_INIT(acful); AM_INIT(acnl); AM_INIT(acfml); AM_INIT(cp); @@ -5449,7 +5451,7 @@ info_options(Allctr_t *allctr, Uint *szp) { Eterm res = THE_NON_VALUE; - UWord acul, acnl, acfml; + UWord acul, acful, acnl, acfml; char *cp_str; Eterm cp_atom; @@ -5464,6 +5466,7 @@ info_options(Allctr_t *allctr, } acul = allctr->cpool.util_limit; + acful = allctr->cpool.free_util_limit; acnl = allctr->cpool.in_pool_limit; acfml = allctr->cpool.fblk_min_limit; ASSERT(allctr->cpool.carrier_pool <= ERTS_ALC_A_MAX); @@ -5512,6 +5515,7 @@ info_options(Allctr_t *allctr, "option smbcs: %beu\n" "option mbcgs: %beu\n" "option acul: %bpu\n" + "option acful: %bpu\n" "option acnl: %bpu\n" "option acfml: %bpu\n" "option cp: %s\n", @@ -5534,6 +5538,7 @@ info_options(Allctr_t *allctr, allctr->smallest_mbc_size, allctr->mbc_growth_stages, acul, + acful, acnl, acfml, cp_str); @@ -5553,6 +5558,9 @@ info_options(Allctr_t *allctr, add_2tup(hpp, szp, &res, am.acul, bld_uint(hpp, szp, acul)); + add_2tup(hpp, szp, &res, + am.acful, + bld_uint(hpp, szp, acful)); add_2tup(hpp, szp, &res, am.mbcgs, bld_uint(hpp, szp, allctr->mbc_growth_stages)); @@ -5709,13 +5717,11 @@ erts_alcu_info_options(Allctr_t *allctr, ensure_atoms_initialized(allctr); if (allctr->thread_safe) { - erts_allctr_wrapper_pre_lock(); erts_mtx_lock(&allctr->mutex); } res = info_options(allctr, print_to_p, print_to_arg, hpp, szp); if (allctr->thread_safe) { erts_mtx_unlock(&allctr->mutex); - erts_allctr_wrapper_pre_unlock(); } return res; } @@ -5748,7 +5754,6 @@ erts_alcu_sz_info(Allctr_t *allctr, ensure_atoms_initialized(allctr); if (allctr->thread_safe) { - erts_allctr_wrapper_pre_lock(); erts_mtx_lock(&allctr->mutex); } @@ -5786,7 +5791,6 @@ erts_alcu_sz_info(Allctr_t *allctr, if (allctr->thread_safe) { erts_mtx_unlock(&allctr->mutex); - erts_allctr_wrapper_pre_unlock(); } return res; @@ -5819,7 +5823,6 @@ erts_alcu_info(Allctr_t *allctr, ensure_atoms_initialized(allctr); if (allctr->thread_safe) { - erts_allctr_wrapper_pre_lock(); erts_mtx_lock(&allctr->mutex); } @@ -5874,7 +5877,6 @@ erts_alcu_info(Allctr_t *allctr, if (allctr->thread_safe) { erts_mtx_unlock(&allctr->mutex); - erts_allctr_wrapper_pre_unlock(); } return res; @@ -6811,6 +6813,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) ASSERT(allctr->next_fblk_in_mbc); allctr->cpool.util_limit = init->acul; + allctr->cpool.free_util_limit = init->acful; allctr->cpool.in_pool_limit = init->acnl; allctr->cpool.fblk_min_limit = init->acfml; allctr->cpool.carrier_pool = init->cp; @@ -6824,6 +6827,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) } else { allctr->cpool.util_limit = 0; + allctr->cpool.free_util_limit = 0; allctr->cpool.in_pool_limit = 0; allctr->cpool.fblk_min_limit = 0; allctr->cpool.carrier_pool = -1; @@ -7682,17 +7686,23 @@ static int gather_ahist_append_result(hist_tree_t *node, void *arg, Sint reds) ASSERT(state->building_result); - hp = erts_produce_heap(&state->msg_factory, 7 + state->hist_slot_count, 0); + hp = erts_produce_heap(&state->msg_factory, + 7 + state->hist_slot_count + + (state->hist_slot_count == 0 ? -1 : 0), + 0); + if (state->hist_slot_count == 0) { + histogram_tuple = erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); + } else { + hp[0] = make_arityval(state->hist_slot_count); - hp[0] = make_arityval(state->hist_slot_count); + for (ix = 0; ix < state->hist_slot_count; ix++) { + hp[1 + ix] = make_small(node->histogram[ix]); + } - for (ix = 0; ix < state->hist_slot_count; ix++) { - hp[1 + ix] = make_small(node->histogram[ix]); + histogram_tuple = make_tuple(hp); + hp += 1 + state->hist_slot_count; } - histogram_tuple = make_tuple(hp); - hp += 1 + state->hist_slot_count; - hp[0] = make_arityval(3); hp[1] = ATAG_ID(node->tag); hp[2] = alloc_type_atoms[ATAG_TYPE(node->tag)]; @@ -7959,7 +7969,7 @@ static void gather_cinfo_append_result(gather_cinfo_t *state, term_size = 0; /* Free block histogram. */ - term_size += 1 + state->hist_slot_count; + term_size += (state->hist_slot_count == 0 ? 0 : 1) + state->hist_slot_count; /* Per-type block list. */ for (ix = ERTS_ALC_A_MIN; ix <= ERTS_ALC_A_MAX; ix++) { @@ -8010,13 +8020,16 @@ static void gather_cinfo_append_result(gather_cinfo_t *state, hp += 2; } } - - hp[0] = make_arityval(state->hist_slot_count); - for (ix = 0; ix < state->hist_slot_count; ix++) { - hp[1 + ix] = make_small(info->free_histogram[ix]); + if (state->hist_slot_count == 0) { + histogram_tuple = erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); + } else { + hp[0] = make_arityval(state->hist_slot_count); + for (ix = 0; ix < state->hist_slot_count; ix++) { + hp[1 + ix] = make_small(info->free_histogram[ix]); + } + histogram_tuple = make_tuple(hp); + hp += 1 + state->hist_slot_count; } - histogram_tuple = make_tuple(hp); - hp += 1 + state->hist_slot_count; carrier_size = bld_unstable_uint(&hp, NULL, info->carrier_size); unscanned_size = bld_unstable_uint(&hp, NULL, info->unscanned_size); diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h index d4f695443a0f..84d215e0f08f 100644 --- a/erts/emulator/beam/erl_alloc_util.h +++ b/erts/emulator/beam/erl_alloc_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2021. All Rights Reserved. + * Copyright Ericsson AB 2002-2022. 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. @@ -67,6 +67,7 @@ typedef struct { UWord smbcs; UWord mbcgs; UWord acul; + UWord acful; UWord acnl; UWord acfml; @@ -127,6 +128,7 @@ typedef struct { 1024*1024, /* (bytes) smbcs: smallest mbc size */\ 10, /* (amount) mbcgs: mbc growth stages */\ 0, /* (%) acul: abandon carrier utilization limit */\ + 0, /* (%) acful: carrier free utilization limit */\ 1000, /* (amount) acnl: abandoned carriers number limit */\ 0, /* (bytes) acfml: abandoned carrier fblk min limit */\ /* --- Data not options -------------------------------------------- */\ @@ -167,6 +169,7 @@ typedef struct { 128*1024, /* (bytes) smbcs: smallest mbc size */\ 10, /* (amount) mbcgs: mbc growth stages */\ 0, /* (%) acul: abandon carrier utilization limit */\ + 0, /* (%) acful: carrier free utilization limit */\ 1000, /* (amount) acnl: abandoned carriers number limit */\ 0, /* (bytes) acfml: abandoned carrier fblk min limit */\ /* --- Data not options -------------------------------------------- */\ @@ -476,6 +479,7 @@ typedef struct { ErtsThrPrgrVal thr_prgr; erts_atomic_t max_size; UWord abandon_limit; + UWord discard_limit; UWord blocks[ERTS_ALC_A_COUNT]; UWord blocks_size[ERTS_ALC_A_COUNT]; UWord total_blocks_size; @@ -697,6 +701,7 @@ struct Allctr_t_ { int disable_abandon; int check_limit_count; UWord util_limit; /* acul */ + UWord free_util_limit; /* acful */ UWord in_pool_limit; /* acnl */ UWord fblk_min_limit; /* acmfl */ int carrier_pool; /* cp */ diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c index 46aacf7642cf..7970ed914bee 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.c +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c @@ -1279,10 +1279,10 @@ static void print_tree(AOFF_RBTree_t*); /* * Checks that the order between parent and children are correct, - * and that the Red-Black Tree properies are satisfied. if size > 0, + * and that the Red-Black Tree properties are satisfied. if size > 0, * check_tree() returns the node that satisfies "address order first fit" * - * The Red-Black Tree properies are: + * The Red-Black Tree properties are: * 1. Every node is either red or black. * 2. Every leaf (NIL) is black. * 3. If a node is red, then both its children are black. diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c index 8aef640ff6ed..3e7f023e5ada 100644 --- a/erts/emulator/beam/erl_arith.c +++ b/erts/emulator/beam/erl_arith.c @@ -710,7 +710,7 @@ erts_mixed_times(Process* p, Eterm arg1, Eterm arg2) return res; } else { /* - * The result is a a big number. + * The result is a big number. * Allocate a heap fragment and copy the result. * Be careful to allocate exactly what we need * to not leave any holes. @@ -1318,6 +1318,6 @@ Eterm erts_bnot(Process* p, Eterm arg) } /* Needed to remove compiler optimization */ -double erts_get_positive_zero_float() { +double erts_get_positive_zero_float(void) { return 0.0f; } diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index 51591557c1bb..1dd6ef18f0bf 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2021. All Rights Reserved. + * Copyright Ericsson AB 2000-2023. 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. @@ -115,17 +115,6 @@ typedef struct { ErtsAlgndAsyncReadyQ *ready_queue; } ErtsAsyncData; -#if defined(USE_VM_PROBES) - -/* - * Some compilers, e.g. GCC 4.2.1 and -O3, will optimize away DTrace - * calls if they're the last thing in the function. :-( - * Many thanks to Trond Norbye, via: - * https://github.com/memcached/memcached/commit/6298b3978687530bc9d219b6ac707a1b681b2a46 - */ -static unsigned gcc_optimizer_hack = 0; -#endif - int erts_async_max_threads; /* Initialized by erl_init.c */ int erts_async_thread_suggested_stack_size; /* Initialized by erl_init.c */ @@ -210,7 +199,7 @@ erts_init_async(void) for (i = 0; i < erts_async_max_threads; i++) { ErtsAsyncQ *aq = async_q(i); - erts_snprintf(thr_opts.name, sizeof(thr_name), "async_%d", i+1); + erts_snprintf(thr_opts.name, sizeof(thr_name), "erts_async_%d", i+1); erts_thr_create(&aq->thr_id, async_main, (void*) aq, &thr_opts); } @@ -238,10 +227,6 @@ erts_get_async_ready_queue(Uint sched_id) static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) { -#ifdef USE_VM_PROBES - int len; -#endif - if (is_internal_port(a->port)) { ErtsAsyncReadyQ *arq = async_ready_q(a->sched_id); a->q.prep_enq = erts_thr_q_prepare_enqueue(&arq->thr_q); @@ -263,9 +248,6 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, { int saved_fin_deq = 0; ErtsThrQFinDeQ_t fin_deq; -#ifdef USE_VM_PROBES - int len; -#endif while (1) { ErtsAsync *a = (ErtsAsync *) erts_thr_q_dequeue(q); @@ -386,7 +368,12 @@ static ERTS_INLINE void async_reply(ErtsAsync *a, ErtsThrQPrepEnQ_t *prep_enq) static void async_wakeup(void *vtse) { - erts_tse_set((erts_tse_t *) vtse); + /* + * 'vtse' might be NULL if we are called after an async thread + * has unregistered from thread progress prior to termination. + */ + if (vtse) + erts_tse_set((erts_tse_t *) vtse); } static erts_tse_t *async_thread_init(ErtsAsyncQ *aq) @@ -448,6 +435,7 @@ static void *async_main(void* arg) async_reply(a, prep_enq); } + erts_thr_progress_unregister_unmanaged_thread(); return NULL; } @@ -546,7 +534,7 @@ unsigned int driver_async_port_key(ErlDrvPort port) ** key pointer to secedule queue (NULL means round robin) ** async_invoke function to run in thread ** async_data data to pass to invoke function -** async_free function for relase async_data in case of failure +** async_free function for release async_data in case of failure */ long driver_async(ErlDrvPort ix, unsigned int* key, void (*async_invoke)(void*), void* async_data, diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c index b3b3baf9a3bf..d171c5c3a2ba 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.c +++ b/erts/emulator/beam/erl_bestfit_alloc.c @@ -735,7 +735,7 @@ bf_link_free_block(Allctr_t *allctr, Block_t *block) BF_LIST_PREV(BF_LIST_NEXT(x)) = blk; BF_LIST_NEXT(x) = blk; - return; /* Finnished */ + return; /* Finished */ } else if (blk_sz < size) { if (!x->left) { @@ -1009,11 +1009,11 @@ static void print_tree(RBTree_t *, int); /* * Checks that the order between parent and children are correct, - * and that the Red-Black Tree properies are satisfied. if size > 0, + * and that the Red-Black Tree properties are satisfied. if size > 0, * check_tree() returns a node that satisfies "best fit" resp. * "address order best fit". * - * The Red-Black Tree properies are: + * The Red-Black Tree properties are: * 1. Every node is either red or black. * 2. Every leaf (NIL) is black. * 3. If a node is red, then both its children are black. diff --git a/erts/emulator/beam/erl_bif_atomics.c b/erts/emulator/beam/erl_bif_atomics.c index 3fd0fc8dcd27..13b6b2aea973 100644 --- a/erts/emulator/beam/erl_bif_atomics.c +++ b/erts/emulator/beam/erl_bif_atomics.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2021. All Rights Reserved. + * Copyright Ericsson AB 2018-2022. 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. @@ -227,16 +227,19 @@ BIF_RETTYPE atomics_compare_exchange_4(BIF_ALIST_4) BIF_RETTYPE atomics_info_1(BIF_ALIST_1) { AtomicsRef* p; - Uint hsz = MAP4_SZ; + Uint hsz = 0; Eterm *hp; Uint64 max; Sint64 min; UWord memory; - Eterm max_val, min_val, sz_val, mem_val; + Eterm keys[4], values[4], res; + ErtsHeapFactory factory; if (!get_ref(BIF_ARG_1, &p)) BIF_ERROR(BIF_P, BADARG); + erts_factory_proc_init(&factory, BIF_P); + max = p->is_signed ? ERTS_SINT64_MAX : ERTS_UINT64_MAX; min = p->is_signed ? ERTS_SINT64_MIN : 0; memory = erts_magic_ref2bin(BIF_ARG_1)->orig_size; @@ -246,14 +249,17 @@ BIF_RETTYPE atomics_info_1(BIF_ALIST_1) erts_bld_uword(NULL, &hsz, p->vlen); erts_bld_uword(NULL, &hsz, memory); - hp = HAlloc(BIF_P, hsz); - max_val = erts_bld_uint64(&hp, NULL, max); - min_val = erts_bld_sint64(&hp, NULL, min); - sz_val = erts_bld_uword(&hp, NULL, p->vlen); - mem_val = erts_bld_uword(&hp, NULL, memory); - - return MAP4(hp, am_max, max_val, - am_memory, mem_val, - am_min, min_val, - am_size, sz_val); + hp = erts_produce_heap(&factory, hsz, MAP4_SZ); + keys[0] = am_max; + values[0] = erts_bld_uint64(&hp, NULL, max); + keys[1] = am_min; + values[1] = erts_bld_sint64(&hp, NULL, min); + keys[2] = am_size; + values[2] = erts_bld_uword(&hp, NULL, p->vlen); + keys[3] = am_memory; + values[3] = erts_bld_uword(&hp, NULL, memory); + + res = erts_map_from_ks_and_vs(&factory, keys, values, 4); + erts_factory_close(&factory); + return res; } diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index 13fac27ce831..a76f902a0faa 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2021. All Rights Reserved. + * Copyright Ericsson AB 2010-2023. 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. @@ -646,7 +646,7 @@ static BFReturn ac_find_first_match(BinaryFindContext *ctx, byte *haystack) register Uint reds = *reductions; while (i < len) { - if (--reds == 0) { + if (reds == 0) { state->q = q; state->pos = i; state->len = len; @@ -655,6 +655,8 @@ static BFReturn ac_find_first_match(BinaryFindContext *ctx, byte *haystack) return BF_RESTART; } + reds--; + while (q->g[haystack[i]] == NULL && q->h != q) { q = q->h; } @@ -844,23 +846,22 @@ static BFReturn bm_find_first_match(BinaryFindContext *ctx, byte *haystack) Sint mem_read = len - needle_last - j; if (mem_read <= 0) { - return BF_NOT_FOUND; + return BF_NOT_FOUND; } - mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR); + + /* Save at least one reduction for the loop below. */ + mem_read = MIN(mem_read, 1 + (reds - 1) * MC_LOOP_FACTOR); ASSERT(mem_read > 0); pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read); if (pos_pointer == NULL) { - reds -= mem_read / MC_LOOP_FACTOR; - j += mem_read; + reds -= mem_read / MC_LOOP_FACTOR; + j += mem_read; } else { - reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR; - j = pos_pointer - haystack - needle_last; + reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR; + j = pos_pointer - haystack - needle_last; } - // Ensure we have at least one reduction before entering the loop - ++reds; - for(;;) { if (j > len - blen) { *reductions = reds; @@ -934,7 +935,8 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta if(mem_read <= 0) { goto done; } - mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR); + /* Save at least one reduction for the loop below. */ + mem_read = MIN(mem_read, 1 + (reds - 1) * MC_LOOP_FACTOR); ASSERT(mem_read > 0); pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read); if (pos_pointer == NULL) { @@ -944,8 +946,6 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR; j = pos_pointer - haystack - needle_last; } - // Ensure we have at least one reduction when resuming the loop - ++reds; } if (j > len - blen) { goto done; @@ -1322,7 +1322,7 @@ static int parse_match_opts_list(Eterm l, Eterm bin, Uint *posp, Uint *endp) return 0; } else { badarg: - /* Ensure intialization. */ + /* Ensure initialization. */ *posp = 0; *endp = 0; return 1; @@ -1463,7 +1463,6 @@ static BFReturn do_binary_find(Process *p, Eterm subject, BinaryFindContext **ct } erts_free_aligned_binary_bytes(temp_alloc); *res_term = THE_NON_VALUE; - BUMP_ALL_REDS(p); return BF_RESTART; } else { *res_term = ctx->found(p, subject, &ctx); @@ -1474,7 +1473,6 @@ static BFReturn do_binary_find(Process *p, Eterm subject, BinaryFindContext **ct if (is_first_call) { erts_set_gc_state(p, 0); } - BUMP_ALL_REDS(p); return BF_RESTART; } if (ctx->search->done != NULL) { @@ -1494,7 +1492,6 @@ static BFReturn do_binary_find(Process *p, Eterm subject, BinaryFindContext **ct if (is_first_call) { erts_set_gc_state(p, 0); } - BUMP_ALL_REDS(p); return BF_RESTART; } if (ctx->search->done != NULL) { @@ -1555,6 +1552,7 @@ binary_match(Process *p, Eterm arg1, Eterm arg2, Eterm arg3, Uint flags) case BF_OK: BIF_RET(result); case BF_RESTART: + BUMP_ALL_REDS(p); ASSERT(result == THE_NON_VALUE && ctx->trap_term != result && ctx->pat_term != result); BIF_TRAP3(&binary_find_trap_export, p, arg1, ctx->trap_term, ctx->pat_term); default: @@ -1616,6 +1614,7 @@ binary_split(Process *p, Eterm arg1, Eterm arg2, Eterm arg3) case BF_OK: BIF_RET(result); case BF_RESTART: + BUMP_ALL_REDS(p); ASSERT(result == THE_NON_VALUE && ctx->trap_term != result && ctx->pat_term != result); BIF_TRAP3(&binary_find_trap_export, p, arg1, ctx->trap_term, ctx->pat_term); default: diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c index 8671d36acb26..0827321099c3 100644 --- a/erts/emulator/beam/erl_bif_chksum.c +++ b/erts/emulator/beam/erl_bif_chksum.c @@ -230,7 +230,7 @@ static Eterm do_chksum(ChksumFun sumfun, Process *p, Eterm ioterm, int left, if (!left) { #ifdef ALLOW_BYTE_TAIL if (is_byte(ioterm)) { - /* inproper list with byte tail*/ + /* improper list with byte tail*/ Eterm *hp; hp = HAlloc(p, 2); ioterm = CONS(hp, ioterm, NIL); @@ -239,7 +239,7 @@ static Eterm do_chksum(ChksumFun sumfun, Process *p, Eterm ioterm, int left, ; #endif } else if (!is_list(ioterm) && !is_nil(ioterm)) { - /* inproper list end */ + /* improper list end */ #ifdef ALLOW_BYTE_TAIL if (is_byte(ioterm)) { unsigned char b[1]; diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index 927211e736c7..b4caaf6e3893 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2021. All Rights Reserved. + * Copyright Ericsson AB 2006-2023. 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. @@ -289,7 +289,7 @@ Eterm erts_trapping_length_1(Process* p, Eterm* args) if (is_list(list)) { /* - * We have exceeded the alloted number of iterations. + * We have exceeded the allotted number of iterations. * Save the result so far and signal a trap. */ args[0] = list; @@ -338,6 +338,8 @@ BIF_RETTYPE bit_size_1(BIF_ALIST_1) Uint low_bits; Uint bytesize; Uint high_bits; + + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_binary(BIF_ARG_1)) { bytesize = binary_size(BIF_ARG_1); high_bits = bytesize >> ((sizeof(Uint) * 8)-3); @@ -367,6 +369,7 @@ BIF_RETTYPE bit_size_1(BIF_ALIST_1) BIF_RETTYPE byte_size_1(BIF_ALIST_1) { + /* NOTE: The JIT has its own implementation of this BIF. */ if (is_binary(BIF_ARG_1)) { Uint bytesize = binary_size(BIF_ARG_1); if (binary_bitsize(BIF_ARG_1) > 0) { @@ -462,3 +465,15 @@ BIF_RETTYPE binary_part_2(BIF_ALIST_2) badarg: BIF_ERROR(BIF_P,BADARG); } + +BIF_RETTYPE min_2(BIF_ALIST_2) +{ + /* NOTE: The JIT has its own implementation of this BIF. */ + return CMP_GT(BIF_ARG_1, BIF_ARG_2) ? BIF_ARG_2 : BIF_ARG_1; +} + +BIF_RETTYPE max_2(BIF_ALIST_2) +{ + /* NOTE: The JIT has its own implementation of this BIF. */ + return CMP_LT(BIF_ARG_1, BIF_ARG_2) ? BIF_ARG_2 : BIF_ARG_1; +} diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 3c770edcedf3..867db56f390c 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -38,7 +38,6 @@ #include "erl_message.h" #include "erl_binary.h" #include "erl_db.h" -#include "erl_mtrace.h" #include "dist.h" #include "erl_gc.h" #include "erl_cpu_topology.h" @@ -93,8 +92,12 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE " [source]" #endif #endif -#ifdef ARCH_64 +#if defined(ARCH_64) " [64-bit]" +#elif defined(ARCH_32) + " [32-bit]" +#else +# error "Unknown ARCH_?" #endif " [smp:%beu:%beu]" " [ds:%beu:%beu:%beu]" @@ -104,9 +107,9 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE " [async-threads:%d]" #ifdef BEAMASM #ifdef NATIVE_ERLANG_STACK - " [jit]" + " [jit:ns%s]" #else - " [jit:no-native-stack]" + " [jit%s]" #endif #endif #ifdef ET_DEBUG @@ -170,7 +173,7 @@ erts_bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh, Eterm tail) union erl_off_heap_ptr u; Eterm res = tail; Eterm tuple; - struct erts_tmp_aligned_offheap tmp; + union erts_tmp_aligned_offheap tmp; for (u.hdr = oh->first; u.hdr; u.hdr = u.hdr->next) { erts_align_offheap(&u, &tmp); @@ -433,7 +436,7 @@ static int make_one_lnk_element(ErtsLink *lnk, void * vpllc, Sint reds) break; } default: - ERTS_INTERNAL_ERROR("Unkown link type"); + ERTS_INTERNAL_ERROR("Unknown link type"); t = am_undefined; break; } @@ -499,6 +502,7 @@ erts_print_system_version(fmtfn_t to, void *arg, Process *c_p) , total, online , dirty_cpu, dirty_cpu_onln, dirty_io , erts_async_max_threads + , (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA ? ":fp" : "") ); } @@ -772,6 +776,8 @@ collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp, Sint reds) #define ERTS_PI_IX_GARBAGE_COLLECTION_INFO 33 #define ERTS_PI_IX_MAGIC_REF 34 #define ERTS_PI_IX_FULLSWEEP_AFTER 35 +#define ERTS_PI_IX_PARENT 36 +#define ERTS_PI_IX_ASYNC_DIST 37 #define ERTS_PI_FLAG_SINGELTON (1 << 0) #define ERTS_PI_FLAG_ALWAYS_WRAP (1 << 1) @@ -827,7 +833,9 @@ static ErtsProcessInfoArgs pi_args[] = { {am_message_queue_data, 0, 0, ERTS_PROC_LOCK_MAIN}, {am_garbage_collection_info, ERTS_PROCESS_GC_INFO_MAX_SIZE, 0, ERTS_PROC_LOCK_MAIN}, {am_magic_ref, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, - {am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN} + {am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_parent, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_async_dist, 0, 0, ERTS_PROC_LOCK_MAIN} }; #define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(pi_args[0]))) @@ -946,6 +954,10 @@ pi_arg2ix(Eterm arg) return ERTS_PI_IX_MAGIC_REF; case am_fullsweep_after: return ERTS_PI_IX_FULLSWEEP_AFTER; + case am_parent: + return ERTS_PI_IX_PARENT; + case am_async_dist: + return ERTS_PI_IX_ASYNC_DIST; default: return -1; } @@ -1006,6 +1018,7 @@ process_info_aux(Process *c_p, Process *rp, ErtsProcLocks rp_locks, int item_ix, + Sint *msgq_len_p, int flags, Uint *reserve_sizep, Uint *reds); @@ -1024,11 +1037,12 @@ erts_process_info(Process *c_p, Eterm res; Eterm part_res[ERTS_PI_ARGS]; int item_ix_ix, ix; + Sint msgq_len = -1; if (ERTS_PI_FLAG_SINGELTON & flags) { ASSERT(item_ix_len == 1); res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0], - flags, &reserve_size, reds); + &msgq_len, flags, &reserve_size, reds); return res; } @@ -1046,7 +1060,7 @@ erts_process_info(Process *c_p, ix = pi_arg2ix(am_messages); ASSERT(part_res[ix] == THE_NON_VALUE); res = process_info_aux(c_p, hfact, rp, rp_locks, ix, - flags, &reserve_size, reds); + &msgq_len, flags, &reserve_size, reds); ASSERT(res != am_undefined); ASSERT(res != THE_NON_VALUE); part_res[ix] = res; @@ -1056,7 +1070,7 @@ erts_process_info(Process *c_p, ix = item_ix[item_ix_ix]; if (part_res[ix] == THE_NON_VALUE) { res = process_info_aux(c_p, hfact, rp, rp_locks, ix, - flags, &reserve_size, reds); + &msgq_len, flags, &reserve_size, reds); ASSERT(res != am_undefined); ASSERT(res != THE_NON_VALUE); part_res[ix] = res; @@ -1091,6 +1105,121 @@ erts_process_info(Process *c_p, static void pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix); +#ifdef DEBUG +static int +empty_or_adj_msgq_signals_only(ErtsMessage *sig) +{ + ErtsSignal *s = (ErtsSignal *) sig; + for (s = (ErtsSignal *) sig; s; s = (ErtsSignal *) s->common.next) { + if (!ERTS_SIG_IS_NON_MSG(s)) + return 0; + if (ERTS_PROC_SIG_OP(s->common.tag) != ERTS_SIG_Q_OP_ADJ_MSGQ) + return 0; + } + return !0; +} +#endif + +static ERTS_INLINE int +pi_maybe_flush_signals(Process *c_p, int pi_flags) +{ + int reds_left; + erts_aint32_t state; + + /* + * pi_maybe_flush_signals() flush signals in callers + * signal queue for two different reasons: + * + * 1. If we need 'message_queue_len', but not 'messages', we need + * to handle all signals in the middle queue in order for + * 'c_p->sig_qs.len' to reflect the amount of messages in the + * message queue. We could count traverse the queues, but it + * is better to handle all signals in the queue instead since + * this is work we anyway need to do at some point. + * + * 2. Ensures that all signals that the caller might have sent to + * itself are handled before we gather information. + * + * This is, however, not strictly necessary. process_info() is + * not documented to send itself a signal when gathering + * information about itself. That is, the operation is not + * bound by the signal order guarantee when gathering + * information about itself. If we do not handle outstanding + * signals before gathering the information, outstanding signals + * from the caller to itself will not be part of the result. + * This would not be wrong, but perhaps surprising for the user. + * We continue doing it this way for now, since this is how it + * has been done for a very long time. We should, however, + * consider changing this in a future release, since this signal + * handling is not for free, although quite cheap since these + * signals anyway must be handled at some point. + */ + + if (c_p->sig_qs.flags & FS_FLUSHED_SIGS) { + flushed: + + /* + * Even though we've requested a clean sig queue + * the middle queue may contain adjust-message-queue + * signals since those may be reinserted if yielding. + * Such signals does not effect us though. + */ + ASSERT(((pi_flags & (ERTS_PI_FLAG_WANT_MSGS + | ERTS_PI_FLAG_NEED_MSGQ_LEN)) + != ERTS_PI_FLAG_NEED_MSGQ_LEN) + || empty_or_adj_msgq_signals_only(c_p->sig_qs.cont)); + + ASSERT(c_p->sig_qs.flags & FS_FLUSHING_SIGS); + + c_p->sig_qs.flags &= ~(FS_FLUSHED_SIGS|FS_FLUSHING_SIGS); + erts_set_gc_state(c_p, !0); /* Allow GC again... */ + return 0; /* done, all signals handled... */ + } + + state = erts_atomic32_read_nob(&c_p->state); + + if (!(c_p->sig_qs.flags & FS_FLUSHING_SIGS)) { + int flush_flags = 0; + if (erts_atomic32_read_nob(&c_p->xstate) + & ERTS_PXSFLG_MAYBE_SELF_SIGS) { + flush_flags |= ERTS_PROC_SIG_FLUSH_FLG_FROM_ID; + } + else if (state & ERTS_PSFLG_MSG_SIG_IN_Q) { + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(c_p); + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + } + if (((pi_flags & (ERTS_PI_FLAG_WANT_MSGS + | ERTS_PI_FLAG_NEED_MSGQ_LEN)) + == ERTS_PI_FLAG_NEED_MSGQ_LEN) + && (flush_flags || c_p->sig_qs.cont)) { + flush_flags |= ERTS_PROC_SIG_FLUSH_FLG_CLEAN_SIGQ; + } + if (!flush_flags) + return 0; /* done; no need to flush... */ + erts_proc_sig_init_flush_signals(c_p, flush_flags, c_p->common.id); + if (c_p->sig_qs.flags & FS_FLUSHED_SIGS) + goto flushed; + } + + ASSERT(c_p->sig_qs.flags & FS_FLUSHING_SIGS); + reds_left = ERTS_BIF_REDS_LEFT(c_p); + + do { + int sreds = reds_left; + (void) erts_proc_sig_handle_incoming(c_p, &state, &sreds, + sreds, !0); + BUMP_REDS(c_p, (int) sreds); + if (state & ERTS_PSFLG_EXITING) + return -1; /* process exiting... */ + if (c_p->sig_qs.flags & FS_FLUSHED_SIGS) + goto flushed; + reds_left -= sreds; + } while (reds_left > 0); + + return 1; /* yield and continue here later... */ +} + static BIF_RETTYPE process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) { @@ -1109,41 +1238,6 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) ERTS_CT_ASSERT(ERTS_PI_DEF_ARR_SZ > 0); - if (c_p->common.id == pid) { - int local_only = c_p->sig_qs.flags & FS_LOCAL_SIGS_ONLY; - int sres, sreds, reds_left; - - reds_left = ERTS_BIF_REDS_LEFT(c_p); - sreds = reds_left; - - if (!local_only) { - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(c_p); - erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); - } - - sres = erts_proc_sig_handle_incoming(c_p, &state, &sreds, sreds, !0); - - BUMP_REDS(c_p, (int) sreds); - reds_left -= sreds; - - if (state & ERTS_PSFLG_EXITING) { - c_p->sig_qs.flags &= ~FS_LOCAL_SIGS_ONLY; - goto exited; - } - if (!sres | (reds_left <= 0)) { - /* - * More signals to handle or out of reds; need - * to yield and continue. Prevent fetching of - * more signals by setting local-sigs-only flag. - */ - c_p->sig_qs.flags |= FS_LOCAL_SIGS_ONLY; - goto yield; - } - - c_p->sig_qs.flags &= ~FS_LOCAL_SIGS_ONLY; - } - if (is_atom(opt)) { int ix = pi_arg2ix(opt); item_ix[0] = ix; @@ -1189,7 +1283,16 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) goto badarg; } - if (is_not_internal_pid(pid)) { + if (c_p->common.id == pid) { + int res = pi_maybe_flush_signals(c_p, flags); + if (res != 0) { + if (res > 0) + goto yield; + else + goto exited; + } + } + else if (is_not_internal_pid(pid)) { if (is_external_pid(pid) && external_pid_dist_entry(pid) == erts_this_dist_entry) goto undefined; @@ -1225,7 +1328,11 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) } if (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN) { ASSERT(locks & ERTS_PROC_LOCK_MAIN); - erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); + if (rp->sig_qs.flags & FS_FLUSHING_SIGS) { + erts_proc_unlock(rp, locks); + goto send_signal; + } + erts_proc_sig_queue_lock(rp); erts_proc_sig_fetch(rp); if (rp->sig_qs.cont) { erts_proc_unlock(rp, locks|ERTS_PROC_LOCK_MSGQ); @@ -1263,7 +1370,8 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) if (c_p == rp || !ERTS_PROC_HAS_INCOMING_SIGNALS(c_p)) ERTS_BIF_PREP_RET(ret, res); else - ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(ret, c_p, res); + ERTS_BIF_PREP_HANDLE_SIGNALS_FROM_RETURN(ret, c_p, + pid, res); done: @@ -1303,7 +1411,7 @@ send_signal: { flags |= ERTS_PI_FLAG_REQUEST_FOR_OTHER; need_msgq_len = (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); /* - * Set save pointer to the end of the message queue so we wont + * Set save pointer to the end of the message queue so we won't * have to scan the whole* message queue for the result. Note * that caller unconditionally has to enter a receive only * matching messages containing 'ref', or restore save pointer. @@ -1354,6 +1462,7 @@ process_info_aux(Process *c_p, Process *rp, ErtsProcLocks rp_locks, int item_ix, + Sint *msgq_len_p, int flags, Uint *reserve_sizep, Uint *reds) @@ -1451,7 +1560,7 @@ process_info_aux(Process *c_p, ASSERT(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER); if (!(state & (ERTS_PSFLG_ACTIVE | ERTS_PSFLG_SIG_Q - | ERTS_PSFLG_SIG_IN_Q))) { + | ERTS_PSFLG_NMSG_SIG_IN_Q))) { int sys_tasks = 0; if (state & ERTS_PSFLG_SYS_TASKS) sys_tasks = erts_have_non_prio_elev_sys_tasks(rp, @@ -1472,8 +1581,10 @@ process_info_aux(Process *c_p, case ERTS_PI_IX_MESSAGES: { ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); - if (rp->sig_qs.len == 0 || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) + if (rp->sig_qs.len == 0 || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) { + *msgq_len_p = 0; res = NIL; + } else { int info_on_self = !(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER); ErtsMessageInfo *mip; @@ -1491,8 +1602,8 @@ process_info_aux(Process *c_p, heap_need = erts_proc_sig_prep_msgq_for_inspection(c_p, rp, rp_locks, info_on_self, - mip); - len = rp->sig_qs.len; + mip, msgq_len_p); + len = *msgq_len_p; heap_need += len*2; /* Cons cells */ @@ -1521,9 +1632,13 @@ process_info_aux(Process *c_p, } case ERTS_PI_IX_MESSAGE_QUEUE_LEN: { - Sint len = rp->sig_qs.len; + Sint len = *msgq_len_p; + if (len < 0) { + ASSERT((flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER) + || !rp->sig_qs.cont); + len = rp->sig_qs.len; + } ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); - ASSERT((flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER) || !rp->sig_qs.cont); ASSERT(len >= 0); if (len <= MAX_SMALL) res = make_small(len); @@ -1785,21 +1900,16 @@ process_info_aux(Process *c_p, case ERTS_PI_IX_MIN_BIN_VHEAP_SIZE: { Uint hsz = 0; - (void) erts_bld_uint(NULL, &hsz, MIN_VHEAP_SIZE(rp)); + (void) erts_bld_uint(NULL, &hsz, rp->min_vheap_size); hp = erts_produce_heap(hfact, hsz, reserve_size); - res = erts_bld_uint(&hp, NULL, MIN_VHEAP_SIZE(rp)); + res = erts_bld_uint(&hp, NULL, rp->min_vheap_size); break; } case ERTS_PI_IX_MAX_HEAP_SIZE: { - Uint hsz = 0; - (void) erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), - MAX_HEAP_SIZE_FLAGS_GET(rp), - NULL, &hsz); - hp = erts_produce_heap(hfact, hsz, reserve_size); - res = erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), - MAX_HEAP_SIZE_FLAGS_GET(rp), - &hp, NULL); + res = erts_max_heap_size_map(hfact, + MAX_HEAP_SIZE_GET(rp), + MAX_HEAP_SIZE_FLAGS_GET(rp)); break; } @@ -1856,12 +1966,12 @@ process_info_aux(Process *c_p, case ERTS_PI_IX_GARBAGE_COLLECTION: { DECL_AM(minor_gcs); - Eterm t; - Uint map_sz = 0; + Eterm t, mhs_map; - erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), MAX_HEAP_SIZE_FLAGS_GET(rp), NULL, &map_sz); + mhs_map = erts_max_heap_size_map(hfact, MAX_HEAP_SIZE_GET(rp), + MAX_HEAP_SIZE_FLAGS_GET(rp)); - hp = erts_produce_heap(hfact, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + map_sz, reserve_size); + hp = erts_produce_heap(hfact, 5*(3+2), reserve_size); t = TUPLE2(hp, AM_minor_gcs, make_small(GEN_GCS(rp))); hp += 3; res = CONS(hp, t, NIL); hp += 2; @@ -1870,12 +1980,10 @@ process_info_aux(Process *c_p, t = TUPLE2(hp, am_min_heap_size, make_small(MIN_HEAP_SIZE(rp))); hp += 3; res = CONS(hp, t, res); hp += 2; - t = TUPLE2(hp, am_min_bin_vheap_size, make_small(MIN_VHEAP_SIZE(rp))); hp += 3; + t = TUPLE2(hp, am_min_bin_vheap_size, make_small(rp->min_vheap_size)); hp += 3; res = CONS(hp, t, res); hp += 2; - t = erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), MAX_HEAP_SIZE_FLAGS_GET(rp), &hp, NULL); - - t = TUPLE2(hp, am_max_heap_size, t); hp += 3; + t = TUPLE2(hp, am_max_heap_size, mhs_map); hp += 3; res = CONS(hp, t, res); hp += 2; break; } @@ -1921,12 +2029,15 @@ process_info_aux(Process *c_p, case ERTS_PI_IX_BINARY: { ErlHeapFragment *hfrag; + ErlOffHeap wrt_bins; Uint sz; res = NIL; sz = 0; + wrt_bins.first = rp->wrt_bins; (void)erts_bld_bin_list(NULL, &sz, &MSO(rp), NIL); + (void)erts_bld_bin_list(NULL, &sz, &wrt_bins, NIL); for (hfrag = rp->mbuf; hfrag != NULL; hfrag = hfrag->next) { (void)erts_bld_bin_list(NULL, &sz, &hfrag->off_heap, NIL); } @@ -1934,6 +2045,7 @@ process_info_aux(Process *c_p, hp = erts_produce_heap(hfact, sz, reserve_size); res = erts_bld_bin_list(&hp, NULL, &MSO(rp), NIL); + res = erts_bld_bin_list(&hp, NULL, &wrt_bins, res); for (hfrag = rp->mbuf; hfrag != NULL; hfrag = hfrag->next) { res = erts_bld_bin_list(&hp, NULL, &hfrag->off_heap, res); } @@ -2034,6 +2146,24 @@ process_info_aux(Process *c_p, } break; + case ERTS_PI_IX_PARENT: + if (is_immed(rp->parent)) { + ASSERT(is_internal_pid(rp->parent) || rp->parent == am_undefined); + res = rp->parent; + } + else { + Uint sz; + ASSERT(is_external_pid(rp->parent)); + sz = size_object(rp->parent); + hp = erts_produce_heap(hfact, sz, reserve_size); + res = copy_struct(rp->parent, sz, &hp, hfact->off_heap); + } + break; + + case ERTS_PI_IX_ASYNC_DIST: + res = (rp->flags & F_ASYNC_DIST) ? am_true : am_false; + break; + case ERTS_PI_IX_MAGIC_REF: { Uint sz = 0; (void) bld_magic_ref_bin_list(NULL, &sz, &MSO(rp)); @@ -2645,10 +2775,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) res = TUPLE2(hp, am_min_heap_size,make_small(H_MIN_SIZE)); BIF_RET(res); } else if (BIF_ARG_1 == am_max_heap_size) { - Uint sz = 0; - erts_max_heap_size_map(H_MAX_SIZE, H_MAX_FLAGS, NULL, &sz); - hp = HAlloc(BIF_P, sz); - res = erts_max_heap_size_map(H_MAX_SIZE, H_MAX_FLAGS, &hp, NULL); + ErtsHeapFactory factory; + erts_factory_proc_init(&factory, BIF_P); + res = erts_max_heap_size_map(&factory, H_MAX_SIZE, H_MAX_FLAGS); + erts_factory_close(&factory); BIF_RET(res); } else if (BIF_ARG_1 == am_min_bin_vheap_size) { hp = HAlloc(BIF_P, 3); @@ -2690,6 +2820,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) res = new_binary(BIF_P, (byte *) dsbufp->str, dsbufp->str_len); erts_destroy_info_dsbuf(dsbufp); BIF_RET(res); + } else if (am_async_dist == BIF_ARG_1) { + BIF_RET((erts_default_spo_flags & SPO_ASYNC_DIST) + ? am_true + : am_false); } else if (ERTS_IS_ATOM_STR("dist_ctrl", BIF_ARG_1)) { DistEntry *dep; i = 0; @@ -3068,9 +3202,6 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) if (sz) hp = HAlloc(BIF_P, sz); BIF_RET(c_compiler_used(&hp, NULL)); - } else if (ERTS_IS_ATOM_STR("stop_memory_trace", BIF_ARG_1)) { - erts_mtrace_stop(); - BIF_RET(am_true); } else if (ERTS_IS_ATOM_STR("context_reductions", BIF_ARG_1)) { BIF_RET(make_small(CONTEXT_REDS)); } else if (ERTS_IS_ATOM_STR("kernel_poll", BIF_ARG_1)) { @@ -3549,126 +3680,96 @@ fun_info_2(BIF_ALIST_2) Process* p = BIF_P; Eterm fun = BIF_ARG_1; Eterm what = BIF_ARG_2; + + const ErtsCodeMFA *mfa; + ErlFunThing *funp; + ErlFunEntry *fe; Eterm* hp; Eterm val; - if (is_fun(fun)) { - ErlFunThing* funp = (ErlFunThing *) fun_val(fun); + if (is_not_any_fun(fun)) { + BIF_ERROR(p, BADARG); + } - switch (what) { - case am_type: - hp = HAlloc(p, 3); - val = am_local; - break; - case am_pid: - hp = HAlloc(p, 3); - val = funp->creator; - break; - case am_module: - hp = HAlloc(p, 3); - val = funp->fe->module; - break; - case am_new_index: - hp = HAlloc(p, 3); - val = make_small(funp->fe->index); - break; - case am_new_uniq: - val = new_binary(p, funp->fe->uniq, 16); - hp = HAlloc(p, 3); - break; - case am_index: - hp = HAlloc(p, 3); - val = make_small(funp->fe->old_index); - break; - case am_uniq: - hp = HAlloc(p, 3); - val = make_small(funp->fe->old_uniq); - break; - case am_env: - { - Uint num_free = funp->num_free; - int i; - - hp = HAlloc(p, 3 + 2*num_free); - val = NIL; - for (i = num_free-1; i >= 0; i--) { - val = CONS(hp, funp->env[i], val); - hp += 2; - } - } - break; - case am_refc: - val = erts_make_integer(erts_atomic_read_nob(&funp->fe->refc), p); - hp = HAlloc(p, 3); - break; - case am_arity: - hp = HAlloc(p, 3); - val = make_small(funp->arity); - break; - case am_name: - { - const ErtsCodeMFA *mfa = erts_code_to_codemfa((funp->fe)->address); - hp = HAlloc(p, 3); - val = mfa->function; - } - break; - default: - goto error; - } - } else if (is_export(fun)) { - Export* exp = (Export *) ((UWord) (export_val(fun))[1]); - switch (what) { - case am_type: - hp = HAlloc(p, 3); - val = am_external; - break; - case am_pid: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_module: - hp = HAlloc(p, 3); - val = exp->info.mfa.module; - break; - case am_new_index: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_new_uniq: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_index: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_uniq: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_env: - hp = HAlloc(p, 3); - val = NIL; - break; - case am_refc: - hp = HAlloc(p, 3); - val = am_undefined; - break; - case am_arity: - hp = HAlloc(p, 3); - val = make_small(exp->info.mfa.arity); - break; - case am_name: - hp = HAlloc(p, 3); - val = exp->info.mfa.function; - break; - default: - goto error; - } + funp = (ErlFunThing *) fun_val(fun); + + if (is_local_fun(funp)) { + fe = funp->entry.fun; + mfa = erts_get_fun_mfa(fe, erts_active_code_ix()); } else { - error: - BIF_ERROR(p, BADARG); + ASSERT(is_external_fun(funp) && funp->next == NULL); + mfa = &(funp->entry.exp)->info.mfa; + fe = NULL; } + + switch (what) { + case am_type: + val = is_local_fun(funp) ? am_local : am_external; + hp = HAlloc(p, 3); + break; + case am_pid: + val = is_local_fun(funp) ? funp->creator : am_undefined; + hp = HAlloc(p, 3); + break; + case am_module: + /* Unloaded funs must report their module even though we can't find + * their full MFA. */ + val = (mfa != NULL) ? mfa->module : fe->module; + hp = HAlloc(p, 3); + break; + case am_new_index: + val = is_local_fun(funp) ? make_small(fe->index) : am_undefined; + hp = HAlloc(p, 3); + break; + case am_new_uniq: + val = is_local_fun(funp) ? new_binary(p, fe->uniq, 16) : + am_undefined; + hp = HAlloc(p, 3); + break; + case am_index: + val = is_local_fun(funp) ? make_small(fe->old_index) : am_undefined; + hp = HAlloc(p, 3); + break; + case am_uniq: + val = is_local_fun(funp) ? make_small(fe->old_uniq) : am_undefined; + hp = HAlloc(p, 3); + break; + case am_env: + { + Uint num_free = funp->num_free; + int i; + + hp = HAlloc(p, 3 + 2 * num_free); + val = NIL; + + for (i = num_free - 1; i >= 0; i--) { + val = CONS(hp, funp->env[i], val); + hp += 2; + } + } + break; + case am_refc: + if (is_local_fun(funp)) { + val = erts_make_integer(erts_atomic_read_nob(&fe->refc), p); + } else { + val = am_undefined; + } + + hp = HAlloc(p, 3); + break; + case am_arity: + val = make_small(funp->arity); + hp = HAlloc(p, 3); + break; + case am_name: + /* Name must be `[]` for unloaded funs. */ + val = (mfa != NULL) ? mfa->function : NIL; + hp = HAlloc(p, 3); + break; + default: + BIF_ERROR(p, BADARG); + } + return TUPLE2(hp, what, val); } @@ -3677,26 +3778,38 @@ fun_info_mfa_1(BIF_ALIST_1) { Process* p = BIF_P; Eterm fun = BIF_ARG_1; - Eterm* hp; - if (is_fun(fun)) { + if (is_any_fun(fun)) { const ErtsCodeMFA *mfa; ErlFunThing* funp; - funp = (ErlFunThing *) fun_val(fun); - mfa = erts_code_to_codemfa((funp->fe)->address); + Eterm* hp; + funp = (ErlFunThing *) fun_val(fun); hp = HAlloc(p, 4); + + if (is_local_fun(funp)) { + mfa = erts_get_fun_mfa(funp->entry.fun, erts_active_code_ix()); + + if (mfa == NULL) { + /* Unloaded funs must report their module even though we can't + * find their full MFA, and their function name must be + * `[]`. */ + BIF_RET(TUPLE3(hp, + funp->entry.fun->module, + NIL, + make_small(funp->arity))); + } + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + mfa = &(funp->entry.exp)->info.mfa; + } + BIF_RET(TUPLE3(hp, - (funp->fe)->module, + mfa->module, mfa->function, make_small(funp->arity))); - } else if (is_export(fun)) { - Export* exp = (Export *) ((UWord) (export_val(fun))[1]); - hp = HAlloc(p, 4); - BIF_RET(TUPLE3(hp,exp->info.mfa.module, - exp->info.mfa.function, - make_small(exp->info.mfa.arity))); } + BIF_ERROR(p, BADARG); } @@ -3706,42 +3819,55 @@ BIF_RETTYPE erts_internal_is_process_alive_2(BIF_ALIST_2) BIF_ERROR(BIF_P, BADARG); if (!erts_proc_sig_send_is_alive_request(BIF_P, BIF_ARG_1, BIF_ARG_2)) { if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, am_ok); + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, BIF_ARG_1, am_ok); } BIF_RET(am_ok); } BIF_RETTYPE is_process_alive_1(BIF_ALIST_1) { + if (is_internal_pid(BIF_ARG_1)) { - erts_aint32_t state; + BIF_RETTYPE result; Process *rp; if (BIF_ARG_1 == BIF_P->common.id) BIF_RET(am_true); rp = erts_proc_lookup_raw(BIF_ARG_1); - if (!rp) - BIF_RET(am_false); + if (!rp) { + result = am_false; + } + else { + erts_aint32_t state = erts_atomic32_read_acqb(&rp->state); + if (state & (ERTS_PSFLG_EXITING + | ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_MSG_SIG_IN_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q)) { + /* + * If in exiting state, trap out and send 'is alive' + * request and wait for it to complete termination. + * + * If process has signals enqueued, we need to + * send it an 'is alive' request via its signal + * queue in order to ensure that signal order is + * preserved (we may earlier have sent it an + * exit signal that has not been processed yet). + */ + BIF_TRAP1(is_process_alive_trap, BIF_P, BIF_ARG_1); + } - state = erts_atomic32_read_acqb(&rp->state); - if (state & (ERTS_PSFLG_EXITING - | ERTS_PSFLG_SIG_Q - | ERTS_PSFLG_SIG_IN_Q)) { + result = am_true; + } + + if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) { /* - * If in exiting state, trap out and send 'is alive' - * request and wait for it to complete termination. - * - * If process has signals enqueued, we need to - * send it an 'is alive' request via its signal - * queue in order to ensure that signal order is - * preserved (we may earlier have sent it an - * exit signal that has not been processed yet). + * Ensure that signal order of signals from inspected + * process to us is preserved... */ - BIF_TRAP1(is_process_alive_trap, BIF_P, BIF_ARG_1); + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, BIF_ARG_1, result); } - - BIF_RET(am_true); + BIF_RET(result); } if (is_external_pid(BIF_ARG_1)) { @@ -3750,6 +3876,8 @@ BIF_RETTYPE is_process_alive_1(BIF_ALIST_1) } BIF_ERROR(BIF_P, BADARG); + + } static Eterm @@ -4167,16 +4295,21 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) else if (ERTS_IS_ATOM_STR("persistent_term", BIF_ARG_1)) { BIF_RET(erts_debug_persistent_term_xtra_info(BIF_P)); } - else if (ERTS_IS_ATOM_STR("pid_ref_table_size", BIF_ARG_1)) { - Uint size = erts_pid_ref_table_size(); - if (IS_SSMALL(size)) - BIF_RET(make_small(size)); - else { - Uint hsz = BIG_UWORD_HEAP_SIZE(size); - Eterm *hp = HAlloc(BIF_P, hsz); - BIF_RET(uword_to_big(size, hp)); - } +#ifdef DEBUG + else if (ERTS_IS_ATOM_STR("check_no_empty_boxed_non_literal_on_heap", BIF_ARG_1)) { + /* + There is an optimization that assumes that it is always + safe to read the word after the arity word of boxed + terms. This checks if there is a boxed term with nothing + after the arity word that is not a literal. Such + literals needs to be padded to make the above mentioned + optimization safe. Debug builds also do this check every + time the GC is run. + */ + erts_dbg_check_no_empty_boxed_non_literal_on_heap(BIF_P, NULL); + BIF_RET(am_ok); } +#endif else if (ERTS_IS_ATOM_STR("hashmap_collision_bonanza", BIF_ARG_1)) { #ifdef DBG_HASHMAP_COLLISION_BONANZA return am_true; @@ -4236,10 +4369,10 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) ERTS_ASSERT_IS_NOT_EXITING(BIF_P); BIF_RET(am_undefined); } - erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); erts_proc_sig_fetch(p); erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + state = erts_atomic32_read_nob(&BIF_P->state); do { int reds = CONTEXT_REDS; sigs_done = erts_proc_sig_handle_incoming(p, @@ -4302,10 +4435,11 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) ERTS_ASSERT_IS_NOT_EXITING(BIF_P); BIF_RET(am_undefined); } - + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); erts_proc_sig_fetch(p); erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + state = erts_atomic32_read_nob(&BIF_P->state); do { int reds = CONTEXT_REDS; sigs_done = erts_proc_sig_handle_incoming(p, @@ -4395,15 +4529,6 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) BIF_RET(res); } } - else if (ERTS_IS_ATOM_STR("term_to_binary_tuple_fallbacks", tp[1])) { - Uint64 dflags = (TERM_TO_BINARY_DFLAGS - & ~DFLAG_EXPORT_PTR_TAG - & ~DFLAG_BIT_BINARIES); - Eterm res = erts_term_to_binary(BIF_P, tp[2], 0, dflags); - if (is_value(res)) - BIF_RET(res); - BIF_ERROR(BIF_P, SYSTEM_LIMIT); - } else if (ERTS_IS_ATOM_STR("dist_ctrl", tp[1])) { Eterm res = am_undefined; DistEntry *dep = erts_sysname_to_connected_dist_entry(tp[2]); @@ -4969,20 +5094,20 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_RET(am_ok); } - else if (ERTS_IS_ATOM_STR("code_write_permission", BIF_ARG_1)) { + else if (ERTS_IS_ATOM_STR("code_mod_permission", BIF_ARG_1)) { /* * Warning: This is a unsafe way of seizing the "lock" * as there is no automatic unlock if caller terminates. */ switch(BIF_ARG_2) { case am_true: - if (!erts_try_seize_code_write_permission(BIF_P)) { + if (!erts_try_seize_code_mod_permission(BIF_P)) { ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_erts_debug_set_internal_state_2), BIF_P, BIF_ARG_1, BIF_ARG_2); } BIF_RET(am_true); case am_false: - erts_release_code_write_permission(); + erts_release_code_mod_permission(); BIF_RET(am_true); } } @@ -4997,6 +5122,37 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) (void *) BIF_P); BIF_RET(am_ok); } + } else if (ERTS_IS_ATOM_STR("jit_asm_dump", BIF_ARG_1)) { +#ifdef BEAMASM + /* Undocumented debug option for the JIT, changing the +JDdump + * setting at runtime. This saves us from dumping half of OTP every + * time we want to debug the loading of a single module. */ + Eterm res = erts_jit_asm_dump ? am_true : am_false; + switch (BIF_ARG_2) + { + case am_false: + erts_jit_asm_dump = 0; + BIF_RET(res); + case am_true: + erts_jit_asm_dump = 1; + BIF_RET(res); + default: + break; + } +#else + BIF_RET(am_notsup); +#endif + } else if (ERTS_IS_ATOM_STR("proc_sig_buffers", BIF_ARG_1)) { + switch (BIF_ARG_2) + { + case am_true: { + int has_buffers = erts_proc_sig_queue_force_buffers(BIF_P); + BIF_RET(has_buffers ? am_true : am_false); + } + default: + break; + } + BIF_RET(am_notsup); } else if (ERTS_IS_ATOM_STR("process_uniq_counter", BIF_ARG_1)) { Sint64 counter; diff --git a/erts/emulator/beam/erl_bif_op.c b/erts/emulator/beam/erl_bif_op.c index a594ec1493ff..7113d9e8902f 100644 --- a/erts/emulator/beam/erl_bif_op.c +++ b/erts/emulator/beam/erl_bif_op.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2016. All Rights Reserved. + * Copyright Ericsson AB 1999-2021. 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. @@ -251,19 +251,14 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2) goto error; } - if (is_fun(arg1)) { + if (is_any_fun(arg1)) { ErlFunThing* funp = (ErlFunThing *) fun_val(arg1); if (funp->arity == (Uint) arity) { BIF_RET(am_true); } - } else if (is_export(arg1)) { - Export* exp = (Export *) (export_val(arg1)[1]); - - if (exp->info.mfa.arity == (Uint) arity) { - BIF_RET(am_true); - } } + BIF_RET(am_false); } diff --git a/erts/emulator/beam/erl_bif_persistent.c b/erts/emulator/beam/erl_bif_persistent.c index 9d9ac45266c3..08e15f55d693 100644 --- a/erts/emulator/beam/erl_bif_persistent.c +++ b/erts/emulator/beam/erl_bif_persistent.c @@ -474,9 +474,9 @@ BIF_RETTYPE persistent_term_get_0(BIF_ALIST_0) } } -BIF_RETTYPE persistent_term_get_1(BIF_ALIST_1) +static ERTS_INLINE Eterm +persistent_term_get(Eterm key) { - Eterm key = BIF_ARG_1; HashTable* hash_table = (HashTable *) erts_atomic_read_nob(&the_hash_table); Eterm bucket; @@ -484,24 +484,33 @@ BIF_RETTYPE persistent_term_get_1(BIF_ALIST_1) if (is_boxed(bucket)) { ASSERT(is_tuple_arity(bucket, 2)); - BIF_RET(tuple_val(bucket)[2]); + return tuple_val(bucket)[2]; } - BIF_ERROR(BIF_P, BADARG); + return THE_NON_VALUE; } -BIF_RETTYPE persistent_term_get_2(BIF_ALIST_2) +Eterm +erts_persistent_term_get(Eterm key) { - Eterm key = BIF_ARG_1; - Eterm result = BIF_ARG_2; - HashTable* hash_table = (HashTable *) erts_atomic_read_nob(&the_hash_table); - Eterm bucket; + return persistent_term_get(key); +} - (void)lookup(hash_table, key, &bucket); +BIF_RETTYPE persistent_term_get_1(BIF_ALIST_1) +{ + Eterm result = persistent_term_get(BIF_ARG_1); + if (is_non_value(result)) { + BIF_ERROR(BIF_P, BADARG); + } - if (is_boxed(bucket)) { - ASSERT(is_tuple_arity(bucket, 2)); - result = tuple_val(bucket)[2]; + BIF_RET(result); +} + +BIF_RETTYPE persistent_term_get_2(BIF_ALIST_2) +{ + Eterm result = persistent_term_get(BIF_ARG_1); + if (is_non_value(result)) { + result = BIF_ARG_2; } BIF_RET(result); diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 0570d604ebe7..5c32ba2cd6bc 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2021. All Rights Reserved. + * Copyright Ericsson AB 2001-2023. 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. @@ -104,7 +104,7 @@ BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2) port->async_open_port->to = BIF_P->common.id; /* - * We unconditionaly *must* do a receive on a message + * We unconditionally *must* do a receive on a message * containing the reference after this... */ erts_msgq_set_save_end(BIF_P); @@ -238,8 +238,19 @@ BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3) } else { /* Ensure signal order is preserved... */ - if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) - ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(res, BIF_P, res); + if (state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_PREP_HANDLE_SIGNALS_FROM_RETURN(res, BIF_P, + from, res); + } } return res; @@ -287,8 +298,18 @@ BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3) ERTS_BIF_EXITED(BIF_P); else { /* Ensure signal order is preserved... */ - if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } } BIF_RET(retval); @@ -335,8 +356,18 @@ BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3) ERTS_BIF_EXITED(BIF_P); else { /* Ensure signal order is preserved... */ - if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } } BIF_RET(retval); @@ -382,8 +413,16 @@ BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1) } /* Ensure signal order is preserved... */ - if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } BIF_RET(retval); } @@ -426,8 +465,16 @@ BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2) } /* Ensure signal order is preserved... */ - if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } BIF_RET(retval); } @@ -435,7 +482,7 @@ BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2) BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1) { Eterm retval; - Port* prt; + Port* prt = NULL; if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) { prt = sig_lookup_port(BIF_P, BIF_ARG_1); @@ -474,8 +521,16 @@ BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1) } /* Ensure signal order is preserved... */ - if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } BIF_RET(retval); } @@ -484,7 +539,7 @@ BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1) BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2) { Eterm retval; - Port* prt; + Port* prt = NULL; if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) { prt = sig_lookup_port(BIF_P, BIF_ARG_1); @@ -523,8 +578,16 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2) } /* Ensure signal order is preserved... */ - if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) - ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval); + if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P)) { + Eterm from; + if (is_internal_port(BIF_ARG_1)) + from = BIF_ARG_1; + else if (prt) + from = prt->common.id; + else + from = NIL; + ERTS_BIF_HANDLE_SIGNALS_FROM_RETURN(BIF_P, from, retval); + } BIF_RET(retval); } @@ -988,7 +1051,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) tp = tuple_val(name); arity = *tp++; - if (arity == make_arityval(0)) { + if (arity == make_arityval_zero()) { goto badarg; } @@ -1000,7 +1063,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) name = tp[1]; encoding = erts_get_native_filename_encoding(); /* Do not convert the command to utf-16le yet, do that in win32 specific code */ - /* since the cmd is used for comparsion with drivers names and copied to port info */ + /* since the cmd is used for comparison with drivers names and copied to port info */ if (encoding == ERL_FILENAME_WIN_WCHAR) { encoding = ERL_FILENAME_UTF8; } @@ -1124,7 +1187,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) goto do_return; } -/* Merges the the global environment and the given {Key, Value} list into env, +/* Merges the global environment and the given {Key, Value} list into env, * unsetting all keys whose value is either 'false' or NIL. The behavior on * NIL is undocumented and perhaps surprising, but the previous implementation * worked in this manner. */ diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 8e834e9c3cd1..f274b767e1a1 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2021. All Rights Reserved. + * Copyright Ericsson AB 1999-2023. 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. @@ -47,7 +47,7 @@ const struct trace_pattern_flags erts_trace_pattern_flags_off = {0, 0, 0, 0, 0}; /* - * The following variables are protected by code write permission. + * The following variables are protected by code modification permission. */ static int erts_default_trace_pattern_is_on; static Binary *erts_default_match_spec; @@ -55,14 +55,14 @@ static Binary *erts_default_meta_match_spec; static struct trace_pattern_flags erts_default_trace_pattern_flags; static ErtsTracer erts_default_meta_tracer; -static struct { /* Protected by code write permission */ +static struct { /* Protected by code modification permission */ int current; int install; int local; BpFunctions f; /* Local functions */ BpFunctions e; /* Export entries */ Process* stager; - ErtsThrPrgrLaterOp lop; + ErtsCodeBarrier barrier; } finish_bp; static Eterm @@ -130,7 +130,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) ErtsTracer meta_tracer = erts_tracer_nil; Uint freason = BADARG; - if (!erts_try_seize_code_write_permission(p)) { + if (!erts_try_seize_code_mod_permission(p)) { ERTS_BIF_YIELD3(BIF_TRAP_EXPORT(BIF_erts_internal_trace_pattern_3), p, MFA, Pattern, flaglist); } finish_bp.current = -1; @@ -213,6 +213,13 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) flags.breakpoint = 1; flags.call_time = 1; break; + case am_call_memory: + if (is_global) { + goto error; + } + flags.breakpoint = 1; + flags.call_memory = 1; + break; default: goto error; @@ -225,8 +232,8 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) p->fvalue = am_none; - if (match_prog_set && !flags.local && !flags.meta && (flags.call_count || flags.call_time)) { - /* A match prog is not allowed with just call_count or call_time*/ + if (match_prog_set && !flags.local && !flags.meta && (flags.call_count || flags.call_time || flags.call_memory)) { + /* A match prog is not allowed with just call_count or call_time or call_memory */ p->fvalue = am_call_count; goto error; } @@ -350,13 +357,13 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) ASSERT(matches >= 0); ASSERT(finish_bp.stager == NULL); finish_bp.stager = p; - erts_schedule_thr_prgr_later_op(smp_bp_finisher, NULL, &finish_bp.lop); + erts_schedule_code_barrier(&finish_bp.barrier, smp_bp_finisher, NULL); erts_proc_inc_refc(p); erts_suspend(p, ERTS_PROC_LOCK_MAIN, NULL); ERTS_BIF_YIELD_RETURN(p, make_small(matches)); } - erts_release_code_write_permission(); + erts_release_code_mod_permission(); if (matches >= 0) { return make_small(matches); @@ -369,15 +376,15 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) static void smp_bp_finisher(void* null) { if (erts_finish_breakpointing()) { /* Not done */ - /* Arrange for being called again */ - erts_schedule_thr_prgr_later_op(smp_bp_finisher, NULL, &finish_bp.lop); + /* Arrange for being called again */ + erts_schedule_code_barrier(&finish_bp.barrier, smp_bp_finisher, NULL); } else { /* Done */ Process* p = finish_bp.stager; #ifdef DEBUG finish_bp.stager = NULL; #endif - erts_release_code_write_permission(); + erts_release_code_mod_permission(); erts_proc_lock(p, ERTS_PROC_LOCK_STATUS); if (!ERTS_PROC_IS_EXITING(p)) { erts_resume(p, ERTS_PROC_LOCK_STATUS); @@ -394,8 +401,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, struct trace_pattern_flags *trace_pattern_flags, ErtsTracer *meta_tracer) { - ERTS_LC_ASSERT(erts_has_code_write_permission() || - erts_thr_progress_is_blocking()); + ERTS_LC_ASSERT(erts_has_code_mod_permission() || + erts_thr_progress_is_blocking()); if (trace_pattern_is_on) *trace_pattern_is_on = erts_default_trace_pattern_is_on; if (match_spec) @@ -410,8 +417,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, int erts_is_default_trace_enabled(void) { - ERTS_LC_ASSERT(erts_has_code_write_permission() || - erts_thr_progress_is_blocking()); + ERTS_LC_ASSERT(erts_has_code_mod_permission() || + erts_thr_progress_is_blocking()); return erts_default_trace_pattern_is_on; } @@ -496,6 +503,7 @@ erts_trace_flags(Eterm List, static ERTS_INLINE int start_trace(Process *c_p, ErtsTracer tracer, ErtsPTabElementCommon *common, + ErtsProcLocks locks, int on, int mask) { /* We can use the common part of both port+proc without checking what it is @@ -521,10 +529,17 @@ start_trace(Process *c_p, ErtsTracer tracer, } } - if (on) - ERTS_TRACE_FLAGS(port) |= mask; - else + if (!on) ERTS_TRACE_FLAGS(port) &= ~mask; + else { + ERTS_TRACE_FLAGS(port) |= mask; + if ((mask & F_TRACE_RECEIVE) && is_internal_pid(common->id)) { + Process *proc = (Process *) common; + erts_aint32_t state = erts_atomic32_read_nob(&proc->state); + if (state & ERTS_PSFLG_MSG_SIG_IN_Q) + erts_proc_notify_new_message(proc, locks); + } + } if ((ERTS_TRACE_FLAGS(port) & TRACEE_FLAGS) == 0) { tracer = erts_tracer_nil; @@ -553,7 +568,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO); } - if (!erts_try_seize_code_write_permission(BIF_P)) { + if (!erts_try_seize_code_mod_permission(BIF_P)) { ERTS_TRACER_CLEAR(&tracer); ERTS_BIF_YIELD3(BIF_TRAP_EXPORT(BIF_erts_internal_trace_3), BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); @@ -599,7 +614,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) if (!tracee_port) goto error; - if (start_trace(p, tracer, &tracee_port->common, on, mask)) { + if (start_trace(p, tracer, &tracee_port->common, 0, on, mask)) { erts_port_release(tracee_port); goto already_traced; } @@ -622,7 +637,8 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) if (!tracee_p) goto error; - if (start_trace(tracee_p, tracer, &tracee_p->common, on, mask)) { + if (start_trace(tracee_p, tracer, &tracee_p->common, + ERTS_PROC_LOCKS_ALL, on, mask)) { erts_proc_unlock(tracee_p, (tracee_p == p ? ERTS_PROC_LOCKS_ALL_MINOR @@ -714,7 +730,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) Process* tracee_p = erts_pix2proc(i); if (! tracee_p) continue; - if (!start_trace(p, tracer, &tracee_p->common, on, mask)) + if (!start_trace(p, tracer, &tracee_p->common, 0, on, mask)) matches++; } } @@ -729,7 +745,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) state = erts_atomic32_read_nob(&tracee_port->state); if (state & ERTS_PORT_SFLGS_DEAD) continue; - if (!start_trace(p, tracer, &tracee_port->common, on, mask)) + if (!start_trace(p, tracer, &tracee_port->common, 0, on, mask)) matches++; } } @@ -771,7 +787,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) erts_thr_progress_unblock(); erts_proc_lock(p, ERTS_PROC_LOCK_MAIN); } - erts_release_code_write_permission(); + erts_release_code_mod_permission(); ERTS_TRACER_CLEAR(&tracer); BIF_RET(make_small(matches)); @@ -788,7 +804,7 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) erts_thr_progress_unblock(); erts_proc_lock(p, ERTS_PROC_LOCK_MAIN); } - erts_release_code_write_permission(); + erts_release_code_mod_permission(); BIF_ERROR(p, BADARG); } @@ -804,7 +820,7 @@ Eterm trace_info_2(BIF_ALIST_2) Eterm Key = BIF_ARG_2; Eterm res; - if (!erts_try_seize_code_write_permission(p)) { + if (!erts_try_seize_code_mod_permission(p)) { ERTS_BIF_YIELD2(BIF_TRAP_EXPORT(BIF_trace_info_2), p, What, Key); } @@ -818,10 +834,10 @@ Eterm trace_info_2(BIF_ALIST_2) res = trace_info_func(p, What, Key); } else { p->fvalue = am_badopt; - erts_release_code_write_permission(); + erts_release_code_mod_permission(); BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO); } - erts_release_code_write_permission(); + erts_release_code_mod_permission(); if (is_value(res) && is_internal_ref(res)) BIF_TRAP1(erts_await_result, BIF_P, res); @@ -1029,6 +1045,7 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key) #define FUNC_TRACE_META_TRACE (1<<3) #define FUNC_TRACE_COUNT_TRACE (1<<4) #define FUNC_TRACE_TIME_TRACE (1<<5) +#define FUNC_TRACE_MEMORY_TRACE (1<<6) /* * Returns either FUNC_TRACE_NOEXIST, FUNC_TRACE_UNTRACED, * FUNC_TRACE_GLOBAL_TRACE, or, @@ -1049,7 +1066,8 @@ static int function_is_traced(Process *p, Binary **ms_meta, /* out */ ErtsTracer *tracer_pid_meta, /* out */ Uint *count, /* out */ - Eterm *call_time) /* out */ + Eterm *call_time, /* out */ + Eterm *call_memory) /* out */ { const ErtsCodeInfo *ci; Export e; @@ -1077,9 +1095,12 @@ static int function_is_traced(Process *p, if (erts_is_mtrace_break(&ep->info, ms_meta, tracer_pid_meta)) { r |= FUNC_TRACE_META_TRACE; } - if (erts_is_time_break(p, &ep->info, call_time)) { + if (erts_is_call_break(p, 1, &ep->info, call_time)) { r |= FUNC_TRACE_TIME_TRACE; } + if (erts_is_call_break(p, 0, &ep->info, call_memory)) { + r |= FUNC_TRACE_MEMORY_TRACE; + } return r ? r : FUNC_TRACE_UNTRACED; } } @@ -1093,8 +1114,10 @@ static int function_is_traced(Process *p, ? FUNC_TRACE_META_TRACE : 0) | (erts_is_count_break(ci, count) ? FUNC_TRACE_COUNT_TRACE : 0) - | (erts_is_time_break(p, ci, call_time) - ? FUNC_TRACE_TIME_TRACE : 0); + | (erts_is_call_break(p, 1, ci, call_time) + ? FUNC_TRACE_TIME_TRACE : 0) + | (erts_is_call_break(p, 0, ci, call_memory) + ? FUNC_TRACE_MEMORY_TRACE : 0); return r ? r : FUNC_TRACE_UNTRACED; } @@ -1114,6 +1137,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) Eterm retval = am_false; ErtsTracer meta = erts_tracer_nil; Eterm call_time = NIL; + Eterm call_memory = NIL; int r; @@ -1133,7 +1157,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) mfa[1] = tp[2]; mfa[2] = signed_val(tp[3]); - if ( (key == am_call_time) || (key == am_all)) { + if ( (key == am_call_time) || (key == am_call_memory) || (key == am_all)) { erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_thr_progress_block(); erts_proc_lock(p, ERTS_PROC_LOCK_MAIN); @@ -1141,10 +1165,10 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) erts_mtx_lock(&erts_dirty_bp_ix_mtx); - r = function_is_traced(p, mfa, &ms, &ms_meta, &meta, &count, &call_time); + r = function_is_traced(p, mfa, &ms, &ms_meta, &meta, &count, &call_time, &call_memory); erts_mtx_unlock(&erts_dirty_bp_ix_mtx); - if ( (key == am_call_time) || (key == am_all)) { + if ( (key == am_call_time) || (key == am_call_memory) || (key == am_all)) { erts_thr_progress_unblock(); } @@ -1206,10 +1230,18 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) retval = call_time; } break; + case am_call_memory: + if (r & FUNC_TRACE_MEMORY_TRACE) { + retval = call_memory; + } + break; case am_all: { - Eterm match_spec_meta = am_false, c = am_false, t, ct = am_false, - m = am_false; + Eterm match_spec_meta = am_false; + Eterm call_count = am_false; + Eterm t, m; + /* ToDo: Rewrite this to loop and reuse the above cases */ + if (ms) { match_spec = MatchSetGetSource(ms); match_spec = copy_object(match_spec, p); @@ -1222,19 +1254,24 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key) match_spec_meta = NIL; } if (r & FUNC_TRACE_COUNT_TRACE) { - c = erts_make_integer(count, p); + call_count = erts_make_integer(count, p); } - if (r & FUNC_TRACE_TIME_TRACE) { - ct = call_time; + if (!(r & FUNC_TRACE_TIME_TRACE)) { + call_time = am_false; + } + if (!(r & FUNC_TRACE_MEMORY_TRACE)) { + call_memory = am_false; } m = erts_tracer_to_term(p, meta); - hp = HAlloc(p, (3+2)*6); + hp = HAlloc(p, (3+2)*7); retval = NIL; - t = TUPLE2(hp, am_call_count, c); hp += 3; + t = TUPLE2(hp, am_call_count, call_count); hp += 3; retval = CONS(hp, t, retval); hp += 2; - t = TUPLE2(hp, am_call_time, ct); hp += 3; + t = TUPLE2(hp, am_call_time, call_time); hp += 3; + retval = CONS(hp, t, retval); hp += 2; + t = TUPLE2(hp, am_call_memory, call_memory); hp += 3; retval = CONS(hp, t, retval); hp += 2; t = TUPLE2(hp, am_meta_match_spec, match_spec_meta); hp += 3; retval = CONS(hp, t, retval); hp += 2; @@ -1432,20 +1469,22 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified, ErtsTracer meta_tracer, int is_blocking) { const ErtsCodeIndex code_ix = erts_active_code_ix(); - int matches = 0; - int i; - int n; + Uint i, n, matches; BpFunction* fp; erts_bp_match_export(&finish_bp.e, mfa, specified); + fp = finish_bp.e.matching; n = finish_bp.e.matched; + matches = 0; for (i = 0; i < n; i++) { - ErtsCodeInfo *ci = fp[i].ci; + ErtsCodeInfo *ci_rw; Export* ep; - ep = ErtsContainerStruct(ci, Export, info); + /* Export entries are always writable, discard const. */ + ci_rw = (ErtsCodeInfo *)fp[i].code_info; + ep = ErtsContainerStruct(ci_rw, Export, info); if (ep->bif_number != -1) { ep->is_bif_traced = !!on; @@ -1455,14 +1494,15 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified, /* Turn on global call tracing */ if (!erts_is_export_trampoline_active(ep, code_ix)) { fp[i].mod->curr.num_traced_exports++; -#ifdef DEBUG - ep->info.op = BeamOpCodeAddr(op_i_func_info_IaaI); +#if defined(DEBUG) && !defined(BEAMASM) + ep->info.u.op = BeamOpCodeAddr(op_i_func_info_IaaI); #endif ep->trampoline.common.op = BeamOpCodeAddr(op_trace_jump_W); - ep->trampoline.trace.address = (BeamInstr) ep->addresses[code_ix]; + ep->trampoline.trace.address = + (BeamInstr) ep->dispatch.addresses[code_ix]; } - erts_set_export_trace(ci, match_prog_set, 0); + erts_set_export_trace(ci_rw, match_prog_set, 0); if (!erts_is_export_trampoline_active(ep, code_ix)) { ep->trampoline.common.op = BeamOpCodeAddr(op_i_generic_breakpoint); @@ -1474,7 +1514,7 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified, * Turn off global tracing, either explicitly or implicitly * before turning on breakpoint tracing. */ - erts_clear_export_trace(ci, 0); + erts_clear_export_trace(ci_rw, 0); if (BeamIsOpCode(ep->trampoline.common.op, op_i_generic_breakpoint)) { ep->trampoline.common.op = BeamOpCodeAddr(op_trace_jump_W); } @@ -1503,6 +1543,9 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified, if (flags.call_time) { erts_set_time_break(&finish_bp.f, on); } + if (flags.call_memory) { + erts_set_memory_break(&finish_bp.f, on); + } } } else { if (flags.local) { @@ -1517,6 +1560,9 @@ erts_set_trace_pattern(Process*p, ErtsCodeMFA *mfa, int specified, if (flags.call_time) { erts_clear_time_break(&finish_bp.f); } + if (flags.call_memory) { + erts_clear_memory_break(&finish_bp.f); + } } finish_bp.current = 0; @@ -1582,13 +1628,13 @@ consolidate_event_tracing(ErtsTracingEvent te[]) int erts_finish_breakpointing(void) { - ERTS_LC_ASSERT(erts_has_code_write_permission()); + ERTS_LC_ASSERT(erts_has_code_mod_permission()); /* - * Memory barriers will be issued for all schedulers *before* - * each of the stages below. (Unless the other schedulers - * are blocked, in which case memory barriers will be issued - * when they are awaken.) + * Memory and instruction barriers will be issued for all schedulers + * *before* each of the stages below. (Unless the other schedulers + * are blocked, in which case memory barriers will be issued when + * they are awakened.) */ switch (finish_bp.current++) { case 0: @@ -1647,13 +1693,17 @@ erts_finish_breakpointing(void) * deallocate the GenericBp structs for them. */ clean_export_entries(&finish_bp.e); - erts_consolidate_bp_data(&finish_bp.e, 0); - erts_consolidate_bp_data(&finish_bp.f, 1); + erts_consolidate_export_bp_data(&finish_bp.e); + erts_consolidate_local_bp_data(&finish_bp.f); erts_bp_free_matched_functions(&finish_bp.e); erts_bp_free_matched_functions(&finish_bp.f); consolidate_event_tracing(erts_send_tracing); consolidate_event_tracing(erts_receive_tracing); - return 0; + return 1; + case 4: + /* All schedulers have run a code barrier (or will as soon as they + * awaken) after updating all breakpoints, it's safe to return now. */ + return 0; default: ASSERT(0); } @@ -1669,7 +1719,9 @@ install_exp_breakpoints(BpFunctions* f) Uint i; for (i = 0; i < ne; i++) { - Export* ep = ErtsContainerStruct(fp[i].ci, Export, info); + /* Export entries are always writable, discard const. */ + ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info; + Export* ep = ErtsContainerStruct(ci_rw, Export, info); erts_activate_export_trampoline(ep, code_ix); } } @@ -1683,11 +1735,14 @@ uninstall_exp_breakpoints(BpFunctions* f) Uint i; for (i = 0; i < ne; i++) { - Export* ep = ErtsContainerStruct(fp[i].ci, Export, info); + /* Export entries are always writable, discard const. */ + ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info; + Export* ep = ErtsContainerStruct(ci_rw, Export, info); if (erts_is_export_trampoline_active(ep, code_ix)) { ASSERT(BeamIsOpCode(ep->trampoline.common.op, op_trace_jump_W)); - ep->addresses[code_ix] = (ErtsCodePtr)ep->trampoline.trace.address; + ep->dispatch.addresses[code_ix] = + (ErtsCodePtr)ep->trampoline.trace.address; } } } @@ -1701,7 +1756,9 @@ clean_export_entries(BpFunctions* f) Uint i; for (i = 0; i < ne; i++) { - Export* ep = ErtsContainerStruct(fp[i].ci, Export, info); + /* Export entries are always writable, discard const. */ + ErtsCodeInfo *ci_rw = (ErtsCodeInfo*)fp[i].code_info; + Export* ep = ErtsContainerStruct(ci_rw, Export, info); if (erts_is_export_trampoline_active(ep, code_ix)) { continue; @@ -1857,8 +1914,7 @@ new_seq_trace_token(Process* p, int ensure_new_heap) Uint mature_size = p->high_water - mature; Eterm* tpl = tuple_val(SEQ_TRACE_TOKEN(p)); ASSERT(arityval(tpl[0]) == 5); - if (ErtsInArea(tpl, OLD_HEAP(p), - (OLD_HEND(p) - OLD_HEAP(p))*sizeof(Eterm)) || + if (ErtsInBetween(tpl, OLD_HEAP(p), OLD_HEND(p)) || ErtsInArea(tpl, mature, mature_size*sizeof(Eterm))) { hp = HAlloc(p, 6); sys_memcpy(hp, tpl, 6*sizeof(Eterm)); diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c index e1686c6f938c..c5bc5943325f 100644 --- a/erts/emulator/beam/erl_bif_unique.c +++ b/erts/emulator/beam/erl_bif_unique.c @@ -62,7 +62,6 @@ static Uint32 max_thr_id; #endif static void init_magic_ref_tables(void); -static void init_pid_ref_tables(void); static Uint64 ref_init_value; @@ -84,7 +83,6 @@ init_reference(void) erts_atomic64_init_nob(&global_reference.count, (erts_aint64_t) ref_init_value); init_magic_ref_tables(); - init_pid_ref_tables(); } static ERTS_INLINE void @@ -146,8 +144,6 @@ Eterm erts_make_ref(Process *c_p) return make_internal_ref(hp); } -static void pid_ref_save(Uint32 refn[ERTS_REF_NUMBERS], Eterm pid); - Eterm erts_make_pid_ref(Process *c_p) { Eterm* hp; @@ -167,8 +163,6 @@ Eterm erts_make_pid_ref(Process *c_p) write_pid_ref_thing(hp, ref[0], ref[1], ref[2], pid); - pid_ref_save(ref, pid); - return make_internal_ref(hp); } @@ -439,290 +433,6 @@ void erts_ref_bin_free(ErtsMagicBinary *mb) erts_bin_free((Binary *) mb); } - -/* - * Pid reference tables. - * - * These tables are intended to be temporary until huge - * references (containing the pid) can be mandatory in - * the external format. - */ - -typedef struct { - HashBucket hash; - Eterm pid; - Uint64 value; - Uint32 thr_id; -} ErtsPidRefTableEntry; - -typedef struct { - erts_rwmtx_t rwmtx; - Hash hash; - char name[32]; -} ErtsPidRefTable; - -typedef struct { - union { - ErtsPidRefTable table; - char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsPidRefTable))]; - } u; -} ErtsAlignedPidRefTable; - -ErtsAlignedPidRefTable *pid_ref_table; - -Eterm -erts_pid_ref_lookup__(Uint32 refn[ERTS_REF_NUMBERS]) -{ - ErtsPidRefTableEntry tmpl; - ErtsPidRefTableEntry *tep; - ErtsPidRefTable *tblp; - Eterm pid; - - ASSERT(erts_is_pid_ref_numbers(refn)); - - tmpl.value = erts_get_ref_numbers_value(refn); - tmpl.thr_id = erts_get_ref_numbers_thr_id(refn); - if (tmpl.thr_id > erts_no_schedulers) - tblp = &pid_ref_table[0].u.table; - else - tblp = &pid_ref_table[tmpl.thr_id].u.table; - - erts_rwmtx_rlock(&tblp->rwmtx); - - tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl); - pid = tep ? tep->pid : THE_NON_VALUE; - - erts_rwmtx_runlock(&tblp->rwmtx); - - return pid; -} - -static void -pid_ref_save(Uint32 refn[ERTS_REF_NUMBERS], Eterm pid) -{ - ErtsPidRefTableEntry tmpl; - ErtsPidRefTableEntry *tep; - ErtsPidRefTable *tblp; - - ASSERT(erts_is_pid_ref_numbers(refn)); - - tmpl.value = erts_get_ref_numbers_value(refn); - tmpl.thr_id = erts_get_ref_numbers_thr_id(refn); - tmpl.pid = pid; - - if (tmpl.thr_id > erts_no_schedulers) - tblp = &pid_ref_table[0].u.table; - else - tblp = &pid_ref_table[tmpl.thr_id].u.table; - - erts_rwmtx_rlock(&tblp->rwmtx); - - tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl); - - erts_rwmtx_runlock(&tblp->rwmtx); - - if (!tep) { - ErtsPidRefTableEntry *used_tep; - - ASSERT(tmpl.value == erts_get_ref_numbers_value(refn)); - ASSERT(tmpl.thr_id == erts_get_ref_numbers_thr_id(refn)); - - if (tblp != &pid_ref_table[0].u.table) { - tep = erts_alloc(ERTS_ALC_T_PREF_NSCHED_ENT, - sizeof(ErtsNSchedPidRefTableEntry)); - } - else { - tep = erts_alloc(ERTS_ALC_T_PREF_ENT, - sizeof(ErtsPidRefTableEntry)); - tep->thr_id = tmpl.thr_id; - } - - tep->value = tmpl.value; - tep->pid = pid; - - erts_rwmtx_rwlock(&tblp->rwmtx); - - used_tep = hash_put(&tblp->hash, tep); - - erts_rwmtx_rwunlock(&tblp->rwmtx); - - if (used_tep != tep) { - if (tblp != &pid_ref_table[0].u.table) - erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep); - else - erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep); - } - } -} - -void -erts_pid_ref_delete(Eterm ref) -{ - ErtsPidRefTableEntry tmpl; - ErtsPidRefTableEntry *tep; - ErtsPidRefTable *tblp; - Uint32 *refn; - - ASSERT(is_internal_pid_ref(ref)); - - refn = internal_pid_ref_numbers(ref); - - ASSERT(erts_is_pid_ref_numbers(refn)); - - tmpl.value = erts_get_ref_numbers_value(refn); - tmpl.thr_id = erts_get_ref_numbers_thr_id(refn); - - if (tmpl.thr_id > erts_no_schedulers) - tblp = &pid_ref_table[0].u.table; - else - tblp = &pid_ref_table[tmpl.thr_id].u.table; - - erts_rwmtx_rlock(&tblp->rwmtx); - - tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl); - - erts_rwmtx_runlock(&tblp->rwmtx); - - if (tep) { - - ASSERT(tmpl.value == erts_get_ref_numbers_value(refn)); - ASSERT(tmpl.thr_id == erts_get_ref_numbers_thr_id(refn)); - - erts_rwmtx_rwlock(&tblp->rwmtx); - - tep = hash_remove(&tblp->hash, &tmpl); - - erts_rwmtx_rwunlock(&tblp->rwmtx); - - if (tep) { - if (tblp != &pid_ref_table[0].u.table) - erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep); - else - erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep); - } - } -} - -static int nsched_preft_cmp(void *ve1, void *ve2) -{ - ErtsNSchedPidRefTableEntry *e1 = ve1; - ErtsNSchedPidRefTableEntry *e2 = ve2; - return e1->value != e2->value; -} - -static int non_nsched_preft_cmp(void *ve1, void *ve2) -{ - ErtsPidRefTableEntry *e1 = ve1; - ErtsPidRefTableEntry *e2 = ve2; - return e1->value != e2->value || e1->thr_id != e2->thr_id; -} - -static HashValue nsched_preft_hash(void *ve) -{ - ErtsNSchedPidRefTableEntry *e = ve; - return (HashValue) e->value; -} - -static HashValue non_nsched_preft_hash(void *ve) -{ - ErtsPidRefTableEntry *e = ve; - HashValue h; - h = (HashValue) e->thr_id; - h *= 268440163; - h += (HashValue) e->value; - return h; -} - -static void *preft_alloc(void *ve) -{ - /* - * We allocate the element before - * hash_put() and pass it as - * template which we get as - * input... - */ - return ve; -} - -static void preft_free(void *ve) -{ - /* - * We free the element ourselves - * after hash_remove()... - */ -} - -static void *preft_meta_alloc(int i, size_t size) -{ - return erts_alloc(ERTS_ALC_T_PREF_TAB_BKTS, size); -} - -static void preft_meta_free(int i, void *ptr) -{ - erts_free(ERTS_ALC_T_PREF_TAB_BKTS, ptr); -} - -static void -init_pid_ref_tables(void) -{ - HashFunctions hash_funcs; - int i; - ErtsPidRefTable *tblp; - - pid_ref_table = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_PREF_TAB, - (sizeof(ErtsAlignedPidRefTable) - * (erts_no_schedulers + 1))); - - hash_funcs.hash = non_nsched_preft_hash; - hash_funcs.cmp = non_nsched_preft_cmp; - - hash_funcs.alloc = preft_alloc; - hash_funcs.free = preft_free; - hash_funcs.meta_alloc = preft_meta_alloc; - hash_funcs.meta_free = preft_meta_free; - hash_funcs.meta_print = erts_print; - - tblp = &pid_ref_table[0].u.table; - erts_snprintf(&tblp->name[0], sizeof(tblp->name), - "pid_ref_table_0"); - hash_init(0, &tblp->hash, &tblp->name[0], 1, hash_funcs); - erts_rwmtx_init(&tblp->rwmtx, "pid_ref_table", NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC); - - hash_funcs.hash = nsched_preft_hash; - hash_funcs.cmp = nsched_preft_cmp; - - for (i = 1; i <= erts_no_schedulers; i++) { - ErtsPidRefTable *tblp = &pid_ref_table[i].u.table; - erts_snprintf(&tblp->name[0], sizeof(tblp->name), - "pid_ref_table_%d", i); - hash_init(0, &tblp->hash, &tblp->name[0], 1, hash_funcs); - erts_rwmtx_init(&tblp->rwmtx, "pid_ref_table", NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC); - } -} - - -Uint -erts_pid_ref_table_size(void) -{ - int i; - Uint sz = 0; - - for (i = 0; i <= erts_no_schedulers; i++) { - HashInfo hi; - ErtsPidRefTable *tblp = &pid_ref_table[i].u.table; - erts_rwmtx_rlock(&tblp->rwmtx); - hash_get_info(&hi, &tblp->hash); - erts_rwmtx_runlock(&tblp->rwmtx); - sz += (Uint) hi.objs; - } - - return sz; -} - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Unique Integer * \* */ diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h index bcbcfaee0dd8..def05f0d53bc 100644 --- a/erts/emulator/beam/erl_bif_unique.h +++ b/erts/emulator/beam/erl_bif_unique.h @@ -40,9 +40,7 @@ void erts_make_magic_ref_in_array(Uint32 ref[ERTS_REF_NUMBERS]); void erts_magic_ref_remove_bin(Uint32 refn[ERTS_REF_NUMBERS]); void erts_magic_ref_save_bin__(Eterm ref); ErtsMagicBinary *erts_magic_ref_lookup_bin__(Uint32 refn[ERTS_REF_NUMBERS]); -void erts_pid_ref_delete(Eterm ref); -Eterm erts_pid_ref_lookup__(Uint32 refn[ERTS_REF_NUMBERS]); -Uint erts_pid_ref_table_size(void); + /* strict monotonic counter */ @@ -96,7 +94,7 @@ ERTS_GLB_INLINE Eterm erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *mb ERTS_GLB_INLINE Binary *erts_magic_ref2bin(Eterm mref); ERTS_GLB_INLINE void erts_magic_ref_save_bin(Eterm ref); ERTS_GLB_INLINE ErtsMagicBinary *erts_magic_ref_lookup_bin(Uint32 ref[ERTS_REF_NUMBERS]); -ERTS_GLB_INLINE Eterm erts_pid_ref_lookup(Uint32 *refn); +ERTS_GLB_INLINE Eterm erts_pid_ref_lookup(Uint32 *refn, int len); ERTS_GLB_INLINE Eterm erts_get_pid_of_ref(Eterm ref); #define ERTS_REF1_MAGIC_MARKER_BIT_NO__ \ @@ -256,11 +254,24 @@ erts_magic_ref_lookup_bin(Uint32 ref[ERTS_REF_NUMBERS]) * from the outside world... */ ERTS_GLB_INLINE Eterm -erts_pid_ref_lookup(Uint32 *refn) +erts_pid_ref_lookup(Uint32 *refn, int len) { + Eterm pid; + if (len != ERTS_PID_REF_NUMBERS) + return am_undefined; if (!erts_is_pid_ref_numbers(refn)) - return THE_NON_VALUE; - return erts_pid_ref_lookup__(refn); + return am_undefined; + + pid = (((Eterm) refn[3]) +#ifdef ARCH_64 + | (((Eterm) refn[4]) << 32) +#endif + ); + + if (!is_internal_pid(pid)) + return THE_NON_VALUE; /* We got garbage; we have not created this... */ + + return pid; } ERTS_GLB_INLINE Eterm erts_get_pid_of_ref(Eterm ref) diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h index 4cf0e487f254..50affdf2b722 100644 --- a/erts/emulator/beam/erl_binary.h +++ b/erts/emulator/beam/erl_binary.h @@ -271,7 +271,7 @@ void erts_init_binary(void); byte* erts_get_aligned_binary_bytes_extra(Eterm, byte**, ErtsAlcType_t, unsigned extra); /* Used by unicode module */ -Eterm erts_bin_bytes_to_list(Eterm previous, Eterm* hp, byte* bytes, Uint size, Uint bitoffs); +Eterm erts_bin_bytes_to_list(Eterm previous, Eterm* hp, const byte* bytes, Uint size, Uint bitoffs); /* * Common implementation for erlang:list_to_binary/1 and binary:list_to_bin/1 @@ -281,14 +281,7 @@ BIF_RETTYPE erts_list_to_binary_bif(Process *p, Eterm arg, Export *bif); BIF_RETTYPE erts_binary_part(Process *p, Eterm binary, Eterm epos, Eterm elen); -typedef union { - /* - * These two are almost always of - * the same size, but when fallback - * atomics are used they might - * differ in size. - */ - erts_atomic_t smp_atomic_word; +typedef struct { erts_atomic_t atomic_word; } ErtsMagicIndirectionWord; @@ -563,7 +556,7 @@ erts_binary_to_magic_indirection(Binary *bp) ASSERT(bp->intern.flags & BIN_FLAG_MAGIC); ASSERT(ERTS_MAGIC_BIN_ATYPE(bp) == ERTS_ALC_T_MINDIRECTION); mip = (ErtsMagicIndirectionWord*)ERTS_MAGIC_BIN_UNALIGNED_DATA(bp); - return &mip->smp_atomic_word; + return &mip->atomic_word; } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 0814ab3a4415..d993674f7bea 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -78,6 +78,11 @@ typedef Uint16 erlfp16; static byte get_bit(byte b, size_t a_offs); +/* If the proc bin is larger than 16 MB, + we only increase by 20% instead of doubling */ +#define GROW_PROC_BIN_SIZE(size) \ + (((size) > (1ull << 24)) ? 1.2*(size) : 2*(size)) + /* the state resides in the current process' scheduler data */ #define byte_buf (ErlBitsState.byte_buf_) @@ -1016,10 +1021,12 @@ erts_new_bs_put_binary(Process *c_p, Eterm arg, Uint num_bits) ERL_BITS_DEFINE_STATEP(c_p); if (!is_binary(arg)) { - return 0; + c_p->fvalue = arg; + return 0; } ERTS_GET_BINARY_BYTES(arg, bptr, bitoffs, bitsize); if (num_bits > 8*binary_size(arg)+bitsize) { + c_p->fvalue = arg; return 0; } copy_binary_to_buffer(erts_current_bin, erts_bin_offset, bptr, bitoffs, num_bits); @@ -1038,24 +1045,20 @@ erts_new_bs_put_binary_all(Process *c_p, Eterm arg, Uint unit) ERL_BITS_DEFINE_STATEP(c_p); /* - * This type test is not needed if the code was compiled with - * an R12B or later compiler, since there would have been a - * call to bit_size/1 or byte_size/1 that would have failed if - * 'arg' was not a binary. However, in R11B and earlier releases, - * size/1 was use for calculating the size of the binary, and - * therefore 'arg' could be a tuple. + * This instruction is always preceded by a size calculation that + * will guarantee that 'arg' is a binary. */ - if (!is_binary(arg)) { - return 0; - } + ASSERT(is_binary(arg)); ERTS_GET_BINARY_BYTES(arg, bptr, bitoffs, bitsize); num_bits = 8*binary_size(arg)+bitsize; if (unit == 8) { if (bitsize != 0) { + c_p->fvalue = arg; return 0; } } else if (unit != 1 && num_bits % unit != 0) { + c_p->fvalue = arg; return 0; } copy_binary_to_buffer(erts_current_bin, erts_bin_offset, bptr, bitoffs, num_bits); @@ -1064,7 +1067,13 @@ erts_new_bs_put_binary_all(Process *c_p, Eterm arg, Uint unit) return 1; } -int +/* + * Returns THE_NON_VALUE on success. + * + * On failure, returns whichever was wrong of the value or the size, + * and sets c_p-fvalue to 'type', 'no_float', or 'invalid'. + */ +Eterm erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) { ERL_BITS_DEFINE_STATEP(c_p); @@ -1099,7 +1108,8 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) #endif } else if (is_big(arg)) { if (big_to_double(arg, &u.f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN a = u.i32[1]; @@ -1109,7 +1119,8 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) b = u.i32[1]; #endif } else { - return 0; + c_p->fvalue = am_type; + return arg; } } else if (num_bits == 32) { union { @@ -1131,14 +1142,16 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { double f64; if (big_to_double(arg, &f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } ERTS_FP_CHECK_INIT(c_p); u.f32 = (float) f64; ERTS_FP_ERROR(c_p,u.f32,;); a = u.i32; } else { - return 0; + c_p->fvalue = am_type; + return arg; } } else if (num_bits == 16) { union { @@ -1160,17 +1173,20 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } else if (is_big(arg)) { double f64; if (big_to_double(arg, &f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } ERTS_FP_CHECK_INIT(c_p); ERTS_FP_ERROR(c_p,f64,;); u.f16 = FP16_FROM_FP64(f64); a = u.i16; } else { - return 0; + c_p->fvalue = am_type; + return arg; } } else { - return 0; + c_p->fvalue = am_invalid; + return make_small(num_bits); } if (BIT_IS_MACHINE_ENDIAN(flags)) { @@ -1266,7 +1282,8 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) #endif } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN ftmp.fd = f64; @@ -1274,7 +1291,8 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) bptr = (byte *) &f64; #endif } else { - return 0; + c_p->fvalue = am_type; + return arg; } #ifdef DOUBLE_MIDDLE_ENDIAN fbuf.fw[0] = ftmp.fw[1]; @@ -1294,14 +1312,16 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) bptr = (byte *) &f32; } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } ERTS_FP_CHECK_INIT(c_p); f32 = (float) f64; ERTS_FP_ERROR(c_p,f32,;); bptr = (byte *) &f32; } else { - return 0; + c_p->fvalue = am_type; + return arg; } } else if (num_bits == 16) { if (is_float(arg)) { @@ -1316,17 +1336,20 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) bptr = (byte *) &f16; } else if (is_big(arg)) { if (big_to_double(arg, &f64) < 0) { - return 0; + c_p->fvalue = am_no_float; + return arg; } ERTS_FP_CHECK_INIT(c_p); ERTS_FP_ERROR(c_p,f64,;); f16 = FP16_FROM_FP64(f64); bptr = (byte *) &f16; } else { - return 0; + c_p->fvalue = am_type; + return arg; } } else { - return 0; + c_p->fvalue = am_invalid; + return make_small(num_bits); } if (BIT_IS_MACHINE_ENDIAN(flags)) { erts_copy_bits(bptr, 0, 1, @@ -1339,7 +1362,7 @@ erts_new_bs_put_float(Process *c_p, Eterm arg, Uint num_bits, int flags) } } erts_bin_offset += num_bits; - return 1; + return THE_NON_VALUE; } void @@ -1353,21 +1376,30 @@ erts_new_bs_put_string(ERL_BITS_PROTO_2(byte* iptr, Uint num_bytes)) erts_bin_offset += num_bytes*8; } +static ERTS_INLINE +void increase_proc_bin_sz(Process* p, ProcBin* pb, Uint new_size) +{ + if (new_size > pb->size) { + const Uint incr = (new_size / sizeof(Eterm) - + pb->size / sizeof(Eterm)); + if (ErtsInBetween(pb, OLD_HEAP(p), OLD_HTOP(p))) { + p->bin_old_vheap += incr; + } + else { + OH_OVERHEAD(&MSO(p), incr); + } + pb->size = new_size; + } + else + ASSERT(new_size == pb->size); +} + Eterm erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, - Uint extra_words, Uint unit) + Uint extra_words, Uint unit) { - Eterm bin; /* Given binary */ - Eterm* ptr; - Eterm hdr; - ErlSubBin* sb; - ProcBin* pb; - Binary* binp; - Uint heap_need; - Uint build_size_in_bits; - Uint used_size_in_bits; Uint unsigned_bits; - ERL_BITS_DEFINE_STATEP(c_p); + Uint build_size_in_bits; /* * Check and untag the requested build size. @@ -1375,7 +1407,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, if (is_small(build_size_term)) { Sint signed_bits = signed_val(build_size_term); if (signed_bits < 0) { - goto badarg; + c_p->freason = BADARG; + return THE_NON_VALUE; } build_size_in_bits = (Uint) signed_bits; } else if (term_to_Uint(build_size_term, &unsigned_bits)) { @@ -1384,12 +1417,33 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, c_p->freason = unsigned_bits; return THE_NON_VALUE; } + return erts_bs_append_checked(c_p, reg, live, build_size_in_bits, + extra_words, unit); +} + +Eterm +erts_bs_append_checked(Process* c_p, Eterm* reg, Uint live, + Uint build_size_in_bits, Uint extra_words, + Uint unit) +{ + Eterm bin; /* Given binary */ + Eterm* ptr; + Eterm hdr; + ErlSubBin* sb; + ProcBin* pb; + Binary* binp; + Uint heap_need; + Uint used_size_in_bits; + ERL_BITS_DEFINE_STATEP(c_p); /* * Check the binary argument. */ bin = reg[live]; if (!is_boxed(bin)) { + type_error: + c_p->fvalue = am_type; + badarg: c_p->freason = BADARG; return THE_NON_VALUE; @@ -1397,7 +1451,7 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, ptr = boxed_val(bin); hdr = *ptr; if (!is_binary_header(hdr)) { - goto badarg; + goto type_error; } if (hdr != HEADER_SUB_BIN) { goto not_writable; @@ -1420,6 +1474,7 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, if (unit > 1) { if ((unit == 8 && (erts_bin_offset & 7) != 0) || (unit != 8 && (erts_bin_offset % unit) != 0)) { + c_p->fvalue = am_unit; goto badarg; } } @@ -1433,6 +1488,7 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, } if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) { + c_p->fvalue = am_size; c_p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } @@ -1440,7 +1496,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, used_size_in_bits = erts_bin_offset + build_size_in_bits; sb->is_writable = 0; /* Make sure that no one else can write. */ - pb->size = NBYTES(used_size_in_bits); + + increase_proc_bin_sz(c_p, pb, NBYTES(used_size_in_bits)); pb->flags |= PB_ACTIVE_WRITER; /* @@ -1448,7 +1505,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, */ binp = pb->val; if (binp->orig_size < pb->size) { - Uint new_size = 2*pb->size; + Uint new_size = GROW_PROC_BIN_SIZE(pb->size); + binp = erts_bin_realloc(binp, new_size); pb->val = binp; pb->bytes = (byte *) binp->orig_bytes; @@ -1509,7 +1567,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, erts_bin_offset = 8*binary_size(bin) + bitsize; if (unit > 1) { if ((unit == 8 && (erts_bin_offset & 7) != 0) || - (unit != 8 && (erts_bin_offset % unit) != 0)) { + (unit != 8 && (erts_bin_offset % unit) != 0)) { + c_p->fvalue = am_unit; goto badarg; } } @@ -1519,6 +1578,7 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, } if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) { + c_p->fvalue = am_size; c_p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } @@ -1527,7 +1587,7 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, used_size_in_bytes = NBYTES(used_size_in_bits); if(used_size_in_bits < (ERTS_UINT_MAX / 2)) { - bin_size = 2 * used_size_in_bytes; + bin_size = GROW_PROC_BIN_SIZE(used_size_in_bytes); } else { bin_size = NBYTES(ERTS_UINT_MAX); } @@ -1547,8 +1607,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, hp += PROC_BIN_SIZE; pb->thing_word = HEADER_PROC_BIN; pb->size = used_size_in_bytes; - pb->next = MSO(c_p).first; - MSO(c_p).first = (struct erl_off_heap_header*)pb; + pb->next = c_p->wrt_bins; + c_p->wrt_bins = (struct erl_off_heap_header*)pb; pb->val = bptr; pb->bytes = (byte*) bptr->orig_bytes; pb->flags = PB_IS_WRITABLE | PB_ACTIVE_WRITER; @@ -1583,14 +1643,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, Eterm erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit) { - Eterm* ptr; - ErlSubBin* sb; - ProcBin* pb; - Binary* binp; - Uint build_size_in_bits; - Uint pos_in_bits_after_build; Uint unsigned_bits; - ERL_BITS_DEFINE_STATEP(p); + Uint build_size_in_bits; /* * Check and untag the requested build size. @@ -1608,6 +1662,18 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit) p->freason = unsigned_bits; return THE_NON_VALUE; } + return erts_bs_private_append_checked(p, bin, build_size_in_bits, unit); +} + +Eterm +erts_bs_private_append_checked(Process* p, Eterm bin, Uint build_size_in_bits, Uint unit) +{ + Eterm* ptr; + ErlSubBin* sb; + ProcBin* pb; + Binary* binp; + Uint pos_in_bits_after_build; + ERL_BITS_DEFINE_STATEP(p); ptr = boxed_val(bin); ASSERT(*ptr == HEADER_SUB_BIN); @@ -1624,20 +1690,20 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit) erts_bin_offset = 8*sb->size + sb->bitsize; if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) { + p->fvalue = am_size; p->freason = SYSTEM_LIMIT; return THE_NON_VALUE; } pos_in_bits_after_build = erts_bin_offset + build_size_in_bits; - pb->size = (pos_in_bits_after_build+7) >> 3; - pb->flags |= PB_ACTIVE_WRITER; + increase_proc_bin_sz(p, pb, (pos_in_bits_after_build+7) >> 3); /* * Reallocate the binary if it is too small. */ binp = pb->val; if (binp->orig_size < pb->size) { - Uint new_size = 2*pb->size; + Uint new_size = GROW_PROC_BIN_SIZE(pb->size); BUMP_REDS(p, pb->size / BITS_PER_REDUCTION); if (pb->flags & PB_IS_WRITABLE) { @@ -1656,16 +1722,45 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit) * on. That means that a trace process now has (or have * had) a reference to the binary, so we are not allowed * to reallocate the binary. Instead, we must allocate a new - * binary and copy the contents of the old binary into it. + * binary and copy the contents of the old binary into it. + * + * Also make a new ProcBin as the old one may have been moved + * from the 'wrt_bins' list to the regular 'off_heap' list by + * the GC. To move it back would mean traversing the off_heap list + * from the start. So instead create a new ProcBin for this + * (hopefully) rare case. */ Binary* bptr = erts_bin_nrml_alloc(new_size); - sys_memcpy(bptr->orig_bytes, binp->orig_bytes, binp->orig_size); - pb->flags |= PB_IS_WRITABLE | PB_ACTIVE_WRITER; - pb->val = bptr; - pb->bytes = (byte *) bptr->orig_bytes; - erts_bin_release(binp); + ProcBin* new_pb; + Uint sz = PROC_BIN_SIZE; + + sys_memcpy(bptr->orig_bytes, binp->orig_bytes, binp->orig_size); + + /* If the subbinary is on the mature or old heap, we need to also move it */ + if (ErtsInBetween(sb, OLD_HEAP(p), OLD_HTOP(p)) || + ErtsInBetween(sb, HEAP_START(p), HIGH_WATER(p))) { + sz += ERL_SUB_BIN_SIZE; + } + + new_pb = (ProcBin*) HeapFragOnlyAlloc(p, sz); + new_pb->thing_word = HEADER_PROC_BIN; + new_pb->size = pb->size; + new_pb->val = bptr; + new_pb->bytes = (byte *) bptr->orig_bytes; + new_pb->next = p->wrt_bins; + p->wrt_bins = (struct erl_off_heap_header*) new_pb; + pb = new_pb; + if (sz != PROC_BIN_SIZE) { + ErlSubBin *new_sb = (ErlSubBin*)(new_pb+1); + sys_memcpy(new_sb, sb, sizeof(*new_sb)); + sb = new_sb; + bin = make_binary(sb); + } + sb->orig = make_binary(new_pb); } } + pb->flags = PB_IS_WRITABLE | PB_ACTIVE_WRITER; + erts_current_bin = pb->bytes; sb->size = pos_in_bits_after_build >> 3; @@ -1711,8 +1806,8 @@ erts_bs_init_writable(Process* p, Eterm sz) hp += PROC_BIN_SIZE; pb->thing_word = HEADER_PROC_BIN; pb->size = 0; - pb->next = MSO(p).first; - MSO(p).first = (struct erl_off_heap_header*) pb; + pb->next = p->wrt_bins; + p->wrt_bins = (struct erl_off_heap_header*) pb; pb->val = bptr; pb->bytes = (byte*) bptr->orig_bytes; pb->flags = PB_IS_WRITABLE | PB_ACTIVE_WRITER; @@ -2193,6 +2288,22 @@ erts_copy_bits(byte* src, /* Base pointer to source. */ } } +/* + * Calculate sufficient heap space for a binary extracted by + * erts_extract_sub_binary(). + */ +Uint erts_extracted_binary_size(Uint bit_size) +{ + Uint byte_size = BYTE_OFFSET(bit_size); + ERTS_CT_ASSERT(ERL_SUB_BIN_SIZE <= ERL_ONHEAP_BIN_LIMIT); + + if (BIT_OFFSET(bit_size) == 0 && byte_size <= ERL_ONHEAP_BIN_LIMIT) { + return heap_bin_size(byte_size); + } else { + return ERL_SUB_BIN_SIZE; + } +} + Eterm erts_extract_sub_binary(Eterm **hp, Eterm base_bin, byte *base_data, Uint bit_offset, Uint bit_size) { diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h index d211bbe456d5..2e83b462de68 100644 --- a/erts/emulator/beam/erl_bits.h +++ b/erts/emulator/beam/erl_bits.h @@ -51,23 +51,20 @@ typedef struct erl_bin_match_buffer { struct erl_bits_state { /* - * Used for building binaries. + * Temporary buffer sometimes used by erts_new_bs_put_integer(). */ byte *byte_buf_; Uint byte_buf_len_; + /* - * Used for building binaries using the new instruction set. + * Pointer to the beginning of the current binary. */ - byte* erts_current_bin_; /* Pointer to beginning of current binary. */ + byte* erts_current_bin_; + /* - * Offset in bits into the current binary (new instruction set) or - * buffer (old instruction set). + * Offset in bits into the current binary. */ Uint erts_bin_offset_; - /* - * Whether the current binary is writable. - */ - unsigned erts_writable_bin_; }; typedef struct erl_bin_match_struct{ @@ -117,7 +114,6 @@ typedef struct erl_bin_match_struct{ #define erts_bin_offset (ErlBitsState.erts_bin_offset_) #define erts_current_bin (ErlBitsState.erts_current_bin_) -#define erts_writable_bin (ErlBitsState.erts_writable_bin_) #define copy_binary_to_buffer(DstBuffer, DstBufOffset, SrcBuffer, SrcBufferOffset, NumBits) \ do { \ @@ -150,6 +146,11 @@ void erts_bits_destroy_state(ERL_BITS_PROTO_0); */ #define WSIZE(n) ((n + sizeof(Eterm) - 1) / sizeof(Eterm)) +/* + * Define the maximum number of bits in a unit for the binary syntax. + */ +#define ERL_UNIT_BITS 8 + /* * Binary matching. */ @@ -173,7 +174,7 @@ int erts_bs_put_utf8(ERL_BITS_PROTO_1(Eterm Integer)); int erts_bs_put_utf16(ERL_BITS_PROTO_2(Eterm Integer, Uint flags)); int erts_new_bs_put_binary(Process *c_p, Eterm Bin, Uint num_bits); int erts_new_bs_put_binary_all(Process *c_p, Eterm Bin, Uint unit); -int erts_new_bs_put_float(Process *c_p, Eterm Float, Uint num_bits, int flags); +Eterm erts_new_bs_put_float(Process *c_p, Eterm Float, Uint num_bits, int flags); void erts_new_bs_put_string(ERL_BITS_PROTO_2(byte* iptr, Uint num_bytes)); Uint erts_bits_bufs_size(void); @@ -182,29 +183,43 @@ Eterm erts_bs_get_utf8(ErlBinMatchBuffer* mb); Eterm erts_bs_get_utf16(ErlBinMatchBuffer* mb, Uint flags); Eterm erts_bs_append(Process* p, Eterm* reg, Uint live, Eterm build_size_term, Uint extra_words, Uint unit); +Eterm erts_bs_append_checked(Process* p, Eterm* reg, Uint live, Uint size, + Uint extra_words, Uint unit); Eterm erts_bs_private_append(Process* p, Eterm bin, Eterm sz, Uint unit); +Eterm erts_bs_private_append_checked(Process* p, Eterm bin, Uint size, Uint unit); Eterm erts_bs_init_writable(Process* p, Eterm sz); /* * Common utilities. */ void erts_copy_bits(byte* src, size_t soffs, int sdir, - byte* dst, size_t doffs,int ddir, size_t n); + byte* dst, size_t doffs,int ddir, size_t n); int erts_cmp_bits(byte* a_ptr, size_t a_offs, byte* b_ptr, size_t b_offs, size_t size); +/* + * Calculate the heap space for a binary extracted by + * erts_extract_sub_binary(). + */ +Uint erts_extracted_binary_size(Uint bit_size); /* Extracts a region from base_bin as a sub-binary or heap binary, whichever * is the most appropriate. * - * The caller must ensure that there's enough free space at *hp */ + * The caller must ensure that there's enough free space at *hp by using + * erts_extracted_binary_size(). + * */ Eterm erts_extract_sub_binary(Eterm **hp, Eterm base_bin, byte *base_data, Uint bit_offset, Uint num_bits); -/* Pessimistic estimate of the words required for erts_extract_sub_binary */ -#define EXTRACT_SUB_BIN_HEAP_NEED (heap_bin_size(ERL_ONHEAP_BIN_LIMIT)) +/* + * Conservative estimate of the number of words required for + * erts_extract_sub_binary() when the number of bits is unknown. + */ +#define EXTRACT_SUB_BIN_HEAP_NEED \ + (MAX(ERL_SUB_BIN_SIZE, heap_bin_size(ERL_ONHEAP_BIN_LIMIT))) /* - * Flags for bs_get_* / bs_put_* / bs_init* instructions. + * Flags for bs_create_bin / bs_get_* / bs_put_* / bs_init* instructions. */ #define BSF_ALIGNED 1 /* Field is guaranteed to be byte-aligned. */ @@ -213,4 +228,24 @@ Eterm erts_extract_sub_binary(Eterm **hp, Eterm base_bin, byte *base_data, #define BSF_EXACT 8 /* Size in bs_init is exact. */ #define BSF_NATIVE 16 /* Native endian. */ +/* + * Binary construction operations. + */ + +#define BSC_APPEND 0 +#define BSC_PRIVATE_APPEND 1 +#define BSC_BINARY 2 +#define BSC_BINARY_FIXED_SIZE 3 +#define BSC_BINARY_ALL 4 +#define BSC_FLOAT 5 +#define BSC_FLOAT_FIXED_SIZE 6 +#define BSC_INTEGER 7 +#define BSC_INTEGER_FIXED_SIZE 8 +#define BSC_STRING 9 +#define BSC_UTF8 10 +#define BSC_UTF16 11 +#define BSC_UTF32 12 + +#define BSC_NUM_ARGS 5 + #endif /* __ERL_BITS_H__ */ diff --git a/erts/emulator/beam/erl_bits_f16.h b/erts/emulator/beam/erl_bits_f16.h index 653239d64d47..cda52ab7196d 100644 --- a/erts/emulator/beam/erl_bits_f16.h +++ b/erts/emulator/beam/erl_bits_f16.h @@ -33,7 +33,7 @@ * 1. uint16_t and uint32_t have been rewritten to Uint16 and Uint32 * 2. Mixed declarations were moved to the top to avoid warnings * 3. inline was rewritten as ERTS_INLINE - * 4. UINT16_C(x) and UINT32_C(x) were rewriten to xU as we don't support 16bits platform + * 4. UINT16_C(x) and UINT32_C(x) were rewritten to xU as we don't support 16bits platform */ static ERTS_INLINE float fp32_from_bits(Uint32 w) { @@ -180,7 +180,7 @@ static ERTS_INLINE float fp16_ieee_to_fp32_value(Uint16 h) { * A normalized single-precision floating-point number is represented as: * FP32 = (1 + mantissa * 2**(-23)) * 2**(exponent - 127) * Therefore, when the biased exponent is 126, a unit change in the mantissa of the input denormalized half-precision - * number causes a change of the constructud single-precision number by 2**(-24), i.e. the same ammount. + * number causes a change of the constructud single-precision number by 2**(-24), i.e. the same amount. * * The last step is to adjust the bias of the constructed single-precision number. When the input half-precision number * is zero, the constructed single-precision number has the value of diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index 91a99077f893..ad07f989b6b0 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2020. All Rights Reserved. + * Copyright Ericsson AB 2010-2021. 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. @@ -35,6 +35,7 @@ #include "bif.h" #include "erl_cpu_topology.h" #include "erl_flxctr.h" +#include "erl_global_literals.h" #define ERTS_MAX_READER_GROUPS 64 @@ -907,12 +908,15 @@ erts_fake_scheduler_bindings(Process *p, Eterm how) erts_fprintf(stderr, " %2d", cpudata[i].logical); erts_fprintf(stderr, "\n"); #endif - - hp = HAlloc(p, cpudata_size+1); - ERTS_BIF_PREP_RET(res, make_tuple(hp)); - *hp++ = make_arityval((Uint) cpudata_size); - for (i = 0; i < cpudata_size; i++) - *hp++ = make_small((Uint) cpudata[i].logical); + if (cpudata_size == 0) { + ERTS_BIF_PREP_RET(res, ERTS_GLOBAL_LIT_EMPTY_TUPLE); + } else { + hp = HAlloc(p, cpudata_size+1); + ERTS_BIF_PREP_RET(res, make_tuple(hp)); + *hp++ = make_arityval((Uint) cpudata_size); + for (i = 0; i < cpudata_size; i++) + *hp++ = make_small((Uint) cpudata[i].logical); + } } destroy_tmp_cpu_topology_copy(cpudata); @@ -1674,8 +1678,10 @@ erts_early_init_cpu_topology(int no_schedulers, int max_reader_groups, int *reader_groups_p, int max_decentralized_counter_groups, - int *decentralized_counter_groups_p) + int *decentralized_counter_groups_p, + int skip_read_topology) { + erts_cpu_info_update(cpuinfo, skip_read_topology); user_cpudata = NULL; user_cpudata_size = 0; @@ -1758,7 +1764,7 @@ erts_update_cpu_info(void) { int changed; erts_rwmtx_rwlock(&cpuinfo_rwmtx); - changed = erts_cpu_info_update(cpuinfo); + changed = erts_cpu_info_update(cpuinfo, 0); if (changed) { erts_cpu_topology_t *cpudata; int cpudata_size; diff --git a/erts/emulator/beam/erl_cpu_topology.h b/erts/emulator/beam/erl_cpu_topology.h index 62bd0e73b60e..9c9c8d2200fe 100644 --- a/erts/emulator/beam/erl_cpu_topology.h +++ b/erts/emulator/beam/erl_cpu_topology.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2020. All Rights Reserved. + * Copyright Ericsson AB 2010-2021. 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. @@ -40,7 +40,8 @@ erts_early_init_cpu_topology(int no_schedulers, int max_reader_groups, int *reader_groups_p, int max_decentralized_counter_groups, - int *decentralized_counter_groups_p); + int *decentralized_counter_groups_p, + int skip_read_topology); void erts_init_cpu_topology(void); diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 532e99227ff5..8f5e1a9543d2 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -57,6 +57,10 @@ #define EXI_POSITION am_position /* The position is out of range. */ #define EXI_OWNER am_owner /* The receiving process is already the owner. */ #define EXI_NOT_OWNER am_not_owner /* The current process is not the owner. */ +#define EXI_ALREADY_EXISTS am_already_exists /* The table identifier already exists. */ + +#define DB_WRITE_CONCURRENCY_MIN_LOCKS 1 +#define DB_WRITE_CONCURRENCY_MAX_LOCKS 32768 erts_atomic_t erts_ets_misc_mem_size; @@ -241,9 +245,16 @@ static void table_dec_refc(DbTable *tb, erts_aint_t min_val) schedule_free_dbtable(tb); } +static ERTS_INLINE DbTable* btid2tab(Binary* btid) +{ + erts_atomic_t *tbref = erts_binary_to_magic_indirection(btid); + return (DbTable *) erts_atomic_read_nob(tbref); +} + static int -db_table_tid_destructor(Binary *unused) +db_table_tid_destructor(Binary *btid) { + ASSERT(btid2tab(btid) == NULL); return 1; } @@ -255,19 +266,13 @@ make_btid(DbTable *tb) erts_atomic_init_nob(tbref, (erts_aint_t) tb); tb->common.btid = btid; /* - * Table and magic indirection refer eachother, - * and table is refered once by being alive... + * Table and magic indirection refer each other, + * and table is referred once by being alive... */ erts_refc_init(&tb->common.refc, 2); erts_refc_inc(&btid->intern.refc, 1); } -static ERTS_INLINE DbTable* btid2tab(Binary* btid) -{ - erts_atomic_t *tbref = erts_binary_to_magic_indirection(btid); - return (DbTable *) erts_atomic_read_nob(tbref); -} - static DbTable * tid2tab(Eterm tid, Eterm *error_info_p) { @@ -334,11 +339,24 @@ tid_clear(Process *c_p, DbTable *tb) } } +static ERTS_INLINE Eterm +make_tid_heap(Eterm **hp, ErlOffHeap *oh, DbTable *tb) +{ + return erts_mk_magic_ref(hp, oh, tb->common.btid); +} + static ERTS_INLINE Eterm make_tid(Process *c_p, DbTable *tb) { Eterm *hp = HAlloc(c_p, ERTS_MAGIC_REF_THING_SIZE); - return erts_mk_magic_ref(&hp, &c_p->off_heap, tb->common.btid); + return make_tid_heap(&hp, &c_p->off_heap, tb); +} + +static Eterm +make_tid_fact(ErtsHeapFactory *hf, DbTable *tb) +{ + Eterm *hp = erts_produce_heap(hf, ERTS_MAGIC_REF_THING_SIZE, 0); + return make_tid_heap(&hp, hf->off_heap, tb); } Eterm @@ -347,8 +365,6 @@ erts_db_make_tid(Process *c_p, DbTableCommon *tb) return make_tid(c_p, (DbTable*)tb); } - - /* ** The meta hash table of all NAMED ets tables */ @@ -388,7 +404,7 @@ typedef enum { LCK_READ=1, /* read only access */ LCK_WRITE=2, /* exclusive table write access */ LCK_WRITE_REC=3, /* record write access */ - NOLCK_ACCESS=4 /* Used to access the table structure + LCK_NOLOCK_ACCESS=4 /* Used to access the table structure without acquiring the table lock */ } db_lock_kind_t; @@ -419,12 +435,14 @@ static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1); static BIF_RETTYPE ets_select_replace_1(BIF_ALIST_1); static BIF_RETTYPE ets_select_trap_1(BIF_ALIST_1); static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1); -static Eterm table_info(Process* p, DbTable* tb, Eterm What); +static Eterm table_info(ErtsHeapFactory* hf, DbTable* tb, Eterm What); static BIF_RETTYPE ets_select1(Process* p, int bif_ix, Eterm arg1); static BIF_RETTYPE ets_select2(Process* p, DbTable*, Eterm tid, Eterm ms); static BIF_RETTYPE ets_select3(Process* p, DbTable*, Eterm tid, Eterm ms, Sint chunk_size); +static BIF_RETTYPE ets_insert_2_list_continuation(Process* p, + struct ets_insert_2_list_info* ctx); /* * Exported global @@ -447,18 +465,20 @@ free_dbtable(void *vtb) erts_flxctr_add(&tb->common.counters, ERTS_DB_TABLE_MEM_COUNTER_ID, -((Sint)erts_flxctr_nr_of_allocated_bytes(&tb->common.counters))); - ASSERT(erts_flxctr_is_snapshot_ongoing(&tb->common.counters) || - sizeof(DbTable) == DB_GET_APPROX_MEM_CONSUMED(tb)); - - ASSERT(is_immed(tb->common.heir_data)); if (!DB_LOCK_FREE(tb)) { + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(&tb->common.rwlock), 0); erts_rwmtx_destroy(&tb->common.rwlock); erts_mtx_destroy(&tb->common.fixlock); } - if (tb->common.btid) - erts_bin_release(tb->common.btid); + ASSERT(is_immed(tb->common.heir_data)); + + ASSERT(erts_flxctr_is_snapshot_ongoing(&tb->common.counters) || + sizeof(DbTable) == DB_GET_APPROX_MEM_CONSUMED(tb)); + + ASSERT(tb->common.btid); + erts_bin_release(tb->common.btid); erts_flxctr_destroy(&tb->common.counters, ERTS_ALC_T_ETS_CTRS); erts_free(ERTS_ALC_T_DB_TABLE, tb); @@ -466,10 +486,7 @@ free_dbtable(void *vtb) static void schedule_free_dbtable(DbTable* tb) { - /* - * NON-SMP case: Caller is *not* allowed to access the *tb - * structure after this function has returned! - * SMP case: Caller is allowed to access the *common* part of the *tb + /* SMP case: Caller is allowed to access the *common* part of the *tb * structure until the bif has returned (we typically need to * unlock the table lock after this function has returned). * Caller is *not* allowed to access the specialized part @@ -490,13 +507,13 @@ save_sched_table(Process *c_p, DbTable *tb) DbTable *first; ASSERT(esdp); - erts_atomic_inc_nob(&esdp->ets_tables.count); + erts_atomic_inc_nob(&esdp->u.ets_tables.count); erts_refc_inc(&tb->common.refc, 1); - first = esdp->ets_tables.clist; + first = esdp->u.ets_tables.clist; if (!first) { tb->common.all.next = tb->common.all.prev = tb; - esdp->ets_tables.clist = tb; + esdp->u.ets_tables.clist = tb; } else { tb->common.all.prev = first->common.all.prev; @@ -514,14 +531,14 @@ remove_sched_table(ErtsSchedulerData *esdp, DbTable *tb) ASSERT(erts_get_ref_numbers_thr_id(ERTS_MAGIC_BIN_REFN(tb->common.btid)) == (Uint32) esdp->no); - ASSERT(erts_atomic_read_nob(&esdp->ets_tables.count) > 0); - erts_atomic_dec_nob(&esdp->ets_tables.count); + ASSERT(erts_atomic_read_nob(&esdp->u.ets_tables.count) > 0); + erts_atomic_dec_nob(&esdp->u.ets_tables.count); eaydp = ERTS_SCHED_AUX_YIELD_DATA(esdp, ets_all); if (eaydp->ongoing) { /* ets:all() op process list from last to first... */ if (eaydp->tab == tb) { - if (eaydp->tab == esdp->ets_tables.clist) + if (eaydp->tab == esdp->u.ets_tables.clist) eaydp->tab = NULL; else eaydp->tab = tb->common.all.prev; @@ -530,23 +547,23 @@ remove_sched_table(ErtsSchedulerData *esdp, DbTable *tb) if (tb->common.all.next == tb) { ASSERT(tb->common.all.prev == tb); - ASSERT(esdp->ets_tables.clist == tb); - esdp->ets_tables.clist = NULL; + ASSERT(esdp->u.ets_tables.clist == tb); + esdp->u.ets_tables.clist = NULL; } else { #ifdef DEBUG - DbTable *tmp = esdp->ets_tables.clist; + DbTable *tmp = esdp->u.ets_tables.clist; do { if (tmp == tb) break; tmp = tmp->common.all.next; - } while (tmp != esdp->ets_tables.clist); + } while (tmp != esdp->u.ets_tables.clist); ASSERT(tmp == tb); #endif tb->common.all.prev->common.all.next = tb->common.all.next; tb->common.all.next->common.all.prev = tb->common.all.prev; - if (esdp->ets_tables.clist == tb) - esdp->ets_tables.clist = tb->common.all.next; + if (esdp->u.ets_tables.clist == tb) + esdp->u.ets_tables.clist = tb->common.all.next; } @@ -641,6 +658,7 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock) if (!DB_LOCK_FREE(tb)) { erts_rwmtx_init_opt(&tb->common.rwlock, &rwmtx_opt, "db_tab", tb->common.the_name, ERTS_LOCK_FLAGS_CATEGORY_DB); + ERTS_DB_ALC_MEM_UPDATE_(tb, 0, erts_rwmtx_size(&tb->common.rwlock)); erts_mtx_init(&tb->common.fixlock, "db_tab_fix", tb->common.the_name, ERTS_LOCK_FLAGS_CATEGORY_DB); } @@ -650,13 +668,15 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock) static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind) { + ASSERT(kind != LCK_NOLOCK_ACCESS); if (DB_LOCK_FREE(tb)) return; if (tb->common.type & DB_FINE_LOCKED) { if (kind == LCK_WRITE) { erts_rwmtx_rwlock(&tb->common.rwlock); tb->common.is_thread_safe = 1; - } else if (kind != NOLCK_ACCESS) { + } + else { erts_rwmtx_rlock(&tb->common.rwlock); ASSERT(!tb->common.is_thread_safe); } @@ -668,8 +688,6 @@ static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind) case LCK_WRITE_REC: erts_rwmtx_rwlock(&tb->common.rwlock); break; - case NOLCK_ACCESS: - return; default: erts_rwmtx_rlock(&tb->common.rwlock); } @@ -679,7 +697,7 @@ static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind) static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind) { - if (DB_LOCK_FREE(tb) || kind == NOLCK_ACCESS) + if (DB_LOCK_FREE(tb) || kind == LCK_NOLOCK_ACCESS) return; if (tb->common.type & DB_FINE_LOCKED) { if (kind == LCK_WRITE) { @@ -712,7 +730,7 @@ static ERTS_INLINE int db_is_exclusive(DbTable* tb, db_lock_kind_t kind) return kind != LCK_READ && - kind != NOLCK_ACCESS && + kind != LCK_NOLOCK_ACCESS && tb->common.is_thread_safe; } @@ -721,24 +739,12 @@ static DbTable* handle_lacking_permission(Process* p, DbTable* tb, Uint* freason_p) { if (tb->common.status & DB_BUSY) { - void* continuation_state; if (!db_is_exclusive(tb, kind)) { db_unlock(tb, kind); db_lock(tb, LCK_WRITE); } - continuation_state = (void*)erts_atomic_read_nob(&tb->common.continuation_state); - if (continuation_state != NULL) { - const long iterations_per_red = 10; - const long reds = iterations_per_red * ERTS_BIF_REDS_LEFT(p); - long nr_of_reductions = DBG_RANDOM_REDS(reds, (Uint)freason_p); - const long init_reds = nr_of_reductions; - tb->common.continuation(&nr_of_reductions, - &continuation_state, - NULL); - if (continuation_state == NULL) { - erts_atomic_set_relb(&tb->common.continuation_state, (Sint)NULL); - } - BUMP_REDS(p, (init_reds - nr_of_reductions) / iterations_per_red); + if (tb->common.continuation_ctx) { + ets_insert_2_list_continuation(p, tb->common.continuation_ctx); } else { delete_all_objects_continue(p, tb); } @@ -763,10 +769,11 @@ DbTable* db_get_table_aux(Process *p, Eterm id, int what, db_lock_kind_t kind, - int meta_already_locked, + int name_already_locked, Uint* freason_p) { DbTable *tb; + erts_rwmtx_t *name_lck = NULL; /* * IMPORTANT: Only non-dirty scheduler threads are allowed @@ -774,22 +781,22 @@ DbTable* db_get_table_aux(Process *p, */ ASSERT(erts_get_scheduler_data() && !ERTS_SCHEDULER_IS_DIRTY(erts_get_scheduler_data())); - ASSERT((what == DB_READ_TBL_STRUCT) == (kind == NOLCK_ACCESS)); + ASSERT((what == DB_READ_TBL_STRUCT) == (kind == LCK_NOLOCK_ACCESS)); if (META_DB_LOCK_FREE()) - meta_already_locked = 1; + name_already_locked = 1; if (is_not_atom(id)) { tb = tid2tab(id, &p->fvalue); } else { - erts_rwmtx_t *mtl; - struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&mtl); - if (!meta_already_locked) - erts_rwmtx_rlock(mtl); + struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&name_lck); + if (!name_already_locked) + erts_rwmtx_rlock(name_lck); else { ERTS_LC_ASSERT(META_DB_LOCK_FREE() - || erts_lc_rwmtx_is_rlocked(mtl) - || erts_lc_rwmtx_is_rwlocked(mtl)); + || erts_lc_rwmtx_is_rlocked(name_lck) + || erts_lc_rwmtx_is_rwlocked(name_lck)); + name_lck = NULL; } tb = NULL; if (bucket->pu.tb != NULL) { @@ -808,22 +815,32 @@ DbTable* db_get_table_aux(Process *p, } } } - if (!meta_already_locked) - erts_rwmtx_runlock(mtl); if (tb == NULL) { + if (name_lck) + erts_rwmtx_runlock(name_lck); p->fvalue = EXI_ID; } } if (tb) { + if (what == DB_READ_TBL_STRUCT) { + if (name_lck) + erts_rwmtx_runlock(name_lck); + return tb; + } + + DB_HASH_ADAPT_NUMBER_OF_LOCKS(tb); db_lock(tb, kind); + if (name_lck) + erts_rwmtx_runlock(name_lck); + #ifdef ETS_DBG_FORCE_TRAP /* * The ets_SUITE uses this to verify that all table lookups calls * can handle a failed TRAP return correctly. */ - if (what != DB_READ_TBL_STRUCT && tb->common.dbg_force_trap) { + if (tb->common.dbg_force_trap) { if (!(p->flags & F_DBG_FORCED_TRAP)) { db_unlock(tb, kind); tb = NULL; @@ -837,11 +854,7 @@ DbTable* db_get_table_aux(Process *p, } } #endif - if (what != DB_READ_TBL_STRUCT - /* IMPORTANT: the above check is necessary as the status field - might be in an intermediate state when - kind==NOLCK_ACCESS */ - && ERTS_UNLIKELY(!(tb->common.status & what))) { + if (ERTS_UNLIKELY(!(tb->common.status & what))) { tb = handle_lacking_permission(p, tb, kind, freason_p); } } @@ -862,15 +875,31 @@ DbTable* db_get_table(Process *p, return db_get_table_aux(p, id, what, kind, 0, freason_p); } -static BIF_RETTYPE db_get_table_or_fail_return(DbTable **tb, /* out */ - Eterm table_id, - Uint32 what, - db_lock_kind_t kind, - Uint bif_ix, - Process* p) +static DbTable* db_get_table_or_fail_return(Binary* btid, + Uint32 what, + db_lock_kind_t kind, + Uint bif_ix, + Process* p) { - DB_GET_TABLE(*tb, table_id, what, kind, bif_ix, NULL, p); - return THE_NON_VALUE; + DbTable* tb = btid2tab(btid); + if (!tb) { + p->freason = BADARG | EXF_HAS_EXT_INFO; + p->fvalue = EXI_ID; + } + else { + /* The lock has to be taken to complete the operation */ + db_lock(tb, LCK_WRITE); + if (!(tb->common.status & what)) { + Uint freason; + tb = handle_lacking_permission(p, tb, kind, &freason); + if (!tb) { + BIF_RETTYPE ret = db_bif_fail(p, freason, bif_ix, NULL); + ASSERT(ret == THE_NON_VALUE); (void)ret; + } + } + } + + return tb; } static int insert_named_tab(Eterm name_atom, DbTable* tb, int have_lock) @@ -1262,9 +1291,9 @@ BIF_RETTYPE ets_update_element_3(BIF_ALIST_3) case DB_ERROR_UNSPEC: BIF_ERROR(BIF_P, BADARG | EXF_HAS_EXT_INFO); default: - BIF_ERROR(BIF_P, BADARG); break; } + BIF_ERROR(BIF_P, BADARG); } static BIF_RETTYPE @@ -1459,9 +1488,9 @@ do_update_counter(Process *p, DbTable* tb, case DB_ERROR_BADPARAM: BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO); default: - BIF_ERROR(p, BADARG); break; } + BIF_ERROR(p, BADARG); } /* @@ -1502,20 +1531,38 @@ BIF_RETTYPE ets_update_counter_4(BIF_ALIST_4) } typedef enum { + /* + * Prepare phase. Done only by the process calling ets:insert/insert_new. + * All tuples to insert are allocated and copied without table lock. + */ ETS_INSERT_2_LIST_PROCESS_LOCAL, - ETS_INSERT_2_LIST_FAILED_TO_GET_LOCK, - ETS_INSERT_2_LIST_FAILED_TO_GET_LOCK_DESTROY, + + /* + * Commit phase. May be assisted by other calling processes. + * Prepared tuples inserted with table lock. + */ ETS_INSERT_2_LIST_GLOBAL } ets_insert_2_list_status; -typedef struct { +typedef struct ets_insert_2_list_info { ets_insert_2_list_status status; - BIF_RETTYPE destroy_return_value; - DbTable* tb; + Binary* btid; /* identifies the table between traps */ + Eterm tid; /* arg1, also used to detect table name change */ + Eterm list; /* arg2 */ + DbTable* tb; /* cached tb, does not keep table alive between traps */ void* continuation_state; - Binary* continuation_res_bin; + erts_atomic_t return_value; /* Eterm: 'true', 'false' or THE_NON_VALUE */ } ets_insert_2_list_info; +static void cancel_trap_continuation(DbTable* tb) +{ + ets_insert_2_list_info* ctx = tb->common.continuation_ctx; + + if (ctx) { + tb->common.continuation_ctx = NULL; + erts_bin_release(&(ERTS_MAGIC_BIN_FROM_DATA(ctx)->binary)); + } +} static ERTS_INLINE BIF_RETTYPE ets_cret_to_return_value(Process* p, int cret) @@ -1635,17 +1682,18 @@ static void* ets_insert_2_list_copy_term_list(DbTableMethod* meth, { void* db_term_list = NULL; void *term; + void *last_term; Eterm lst; for (lst = list; is_list(lst); lst = CDR(list_val(lst))) { term = meth->db_eterm_to_dbterm(compress, keypos, CAR(list_val(lst))); if (db_term_list != NULL) { - db_term_list = - meth->db_dbterm_list_prepend(db_term_list, - term); + last_term = + meth->db_dbterm_list_append(last_term, term); } else { db_term_list = term; + last_term = term; } } @@ -1679,63 +1727,77 @@ static int ets_insert_new_2_dbterm_list_has_member(DbTable* tb, void* db_term_li } static void ets_insert_2_list_insert_db_term_list(DbTable* tb, - void* list) + void* db_term_list) { - void* lst = list; + void* tail = db_term_list; void* term = NULL; DbTableMethod* meth = tb->common.meth; + int compress = tb->common.compress; do { LOCAL_VARIABLE(SWord, consumed_reds); consumed_reds = 1; - term = meth->db_dbterm_list_remove_first(&lst); + term = meth->db_dbterm_list_remove_first(&tail); meth->db_put_dbterm(tb, term, 0, &consumed_reds); YCF_CONSUME_REDS(consumed_reds); - } while (lst != NULL); + } while (tail != NULL); return; + + YCF_SPECIAL_CODE_START(ON_DESTROY_STATE); { + ets_insert_2_list_destroy_copied_dbterms(meth, + compress, + tail); + } YCF_SPECIAL_CODE_END(); + } -static void ets_insert_2_list_lock_tbl(Eterm table_id, - Process* p, - Uint bif_ix, - ets_insert_2_list_status on_success_status) +static int ets_insert_2_list_lock_tbl(Binary *btid, + Process* p, + Uint bif_ix, + ets_insert_2_list_status on_success_status) { - BIF_RETTYPE fail_ret; DbTable* tb; + do { - fail_ret = db_get_table_or_fail_return(&tb, - table_id, - DB_WRITE, - LCK_WRITE, - bif_ix, - p); + LOCAL_VARIABLE(ets_insert_2_list_info*,ctx); + ctx = YCF_GET_EXTRA_CONTEXT(); + ASSERT(ctx->status != ETS_INSERT_2_LIST_GLOBAL); + + tb = db_get_table_or_fail_return(btid, + DB_WRITE, + LCK_WRITE, + bif_ix, + p); + ASSERT(ctx->status != ETS_INSERT_2_LIST_GLOBAL); + if (tb == NULL) { - ets_insert_2_list_info *ctx = YCF_GET_EXTRA_CONTEXT(); if (p->freason == TRAP) { - ctx->status = ETS_INSERT_2_LIST_FAILED_TO_GET_LOCK; + YCF_YIELD(); } else { - ctx->status = ETS_INSERT_2_LIST_FAILED_TO_GET_LOCK_DESTROY; - ctx->destroy_return_value = fail_ret; + return 0; } -#ifdef DEBUG + } + else if (is_atom(ctx->tid) && tb->common.the_name != ctx->tid) { /* - * Setting ctx to NULL to avoid that YCF crashes with a - * pointer to stack error when running a debug - * build. YCF_GET_EXTRA_CONTEXT() may change between - * yields as we use stack allocated data for the context - * before the first yield so it is important that the - * context is obtained again with YCF_GET_EXTRA_CONTEXT() - * if a yield might have happened. + * The table has been renamed. We have to fail. This named + * insert op might otherwise be observable as if it happened + * AFTER the table was renamed. + * + * Note that we are allowed to fail here as long as there is no + * atomic name change op from one table to another. */ - ctx = NULL; -#endif - YCF_YIELD(); - } else { - ets_insert_2_list_info *ctx = YCF_GET_EXTRA_CONTEXT(); + p->freason = BADARG | EXF_HAS_EXT_INFO; + p->fvalue = EXI_ID; + db_unlock(tb, LCK_WRITE); + return 0; + } + else { ctx->status = on_success_status; - ASSERT(DB_LOCK_FREE(tb) || erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock)); - ASSERT(!(tb->common.status & DB_DELETE)); } } while (tb == NULL); + + ERTS_LC_ASSERT(DB_LOCK_FREE(tb) || erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock)); + ASSERT(!(tb->common.status & (DB_DELETE|DB_BUSY))); + return 1; } #endif /* YCF_FUNCTIONS */ @@ -1756,13 +1818,14 @@ static ERTS_INLINE int can_insert_without_yield(Uint32 tb_type, #ifdef YCF_FUNCTIONS static BIF_RETTYPE ets_insert_2_list(Process* p, Eterm table_id, + Binary* btid, DbTable *tb, Eterm list, int is_insert_new) { int cret = DB_ERROR_NONE; - void* db_term_list = NULL; /* OBS: memory managements depends on that - db_term_list is initialized to NULL */ + void* db_term_list = NULL; + void* destroy_list = NULL; DbTableMethod* meth = tb->common.meth; int compressed = tb->common.compress; int keypos = tb->common.keypos; @@ -1780,16 +1843,18 @@ static BIF_RETTYPE ets_insert_2_list(Process* p, * table. This is necessary to ensure that the correct reason * for the failure will be available in stack backtrace. */ - ets_insert_2_list_lock_tbl(table_id, p, bif_ix, ETS_INSERT_2_LIST_PROCESS_LOCAL); - db_unlock(tb, LCK_WRITE); - ERTS_BIF_PREP_ERROR_TRAPPED2(ret, p, BADARG, BIF_TRAP_EXPORT(bif_ix), table_id, list); - return ret; + if (ets_insert_2_list_lock_tbl(btid, p, bif_ix, ETS_INSERT_2_LIST_PROCESS_LOCAL)) { + db_unlock(tb, LCK_WRITE); + p->freason = BADARG; + } + return THE_NON_VALUE; } if (can_insert_without_yield(tb_type, list_len, YCF_NR_OF_REDS_LEFT())) { long reds_boost; /* There is enough reductions left to do the inserts directly from the heap without yielding */ - ets_insert_2_list_lock_tbl(table_id, p, bif_ix, ETS_INSERT_2_LIST_PROCESS_LOCAL); + if (!ets_insert_2_list_lock_tbl(btid, p, bif_ix, ETS_INSERT_2_LIST_PROCESS_LOCAL)) + return THE_NON_VALUE; /* Ensure that we will not yield while inserting from heap */ reds_boost = YCF_MAX_NR_OF_REDS - YCF_NR_OF_REDS_LEFT(); YCF_SET_NR_OF_REDS_LEFT(YCF_MAX_NR_OF_REDS); @@ -1809,44 +1874,46 @@ static BIF_RETTYPE ets_insert_2_list(Process* p, /* Copy term list from heap so that other processes can help */ db_term_list = ets_insert_2_list_copy_term_list(meth, compressed, keypos, list); + destroy_list = db_term_list; /* Lock table */ - ets_insert_2_list_lock_tbl(table_id, p, bif_ix, ETS_INSERT_2_LIST_GLOBAL); - /* The operation must complete after this point */ + if (!ets_insert_2_list_lock_tbl(btid, p, bif_ix, ETS_INSERT_2_LIST_GLOBAL)) { + const Eterm fvalue = p->fvalue; + ASSERT(p->freason == (BADARG | EXF_HAS_EXT_INFO)); + + destroy_list = NULL; + ets_insert_2_list_destroy_copied_dbterms(meth, + compressed, + db_term_list); + /* Restore failure reason as we may have trapped during destroy */ + p->freason = BADARG | EXF_HAS_EXT_INFO; + p->fvalue = fvalue; + return THE_NON_VALUE; + } + if (is_insert_new) { if (ets_insert_new_2_dbterm_list_has_member(tb, db_term_list)) { + destroy_list = NULL; ets_insert_2_list_destroy_copied_dbterms(meth, compressed, db_term_list); cret = DB_ERROR_NONE_FALSE; - } else { + } + else { + destroy_list = NULL; ets_insert_2_list_insert_db_term_list(tb, db_term_list); } - } else { - ets_insert_2_list_insert_db_term_list(tb, db_term_list); } - if (tb->common.continuation != NULL) { - /* Uninstall the continuation from the table struct */ - tb->common.continuation = NULL; - if (is_insert_new) { - int* result_ptr = - ERTS_MAGIC_BIN_DATA(tb->common.continuation_res_bin); - *result_ptr = cret; - erts_bin_release(tb->common.continuation_res_bin); - } - tb->common.status |= tb->common.type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC); - tb->common.status &= ~DB_BUSY; - erts_atomic_set_relb(&tb->common.continuation_state, (Sint)NULL); + else { + destroy_list = NULL; + ets_insert_2_list_insert_db_term_list(tb, db_term_list); } return ets_cret_to_return_value(NULL, cret); - /* The following code will be executed if the initiating process - is killed before an ets_insert_2_list_lock_tbl call has - succeeded */ YCF_SPECIAL_CODE_START(ON_DESTROY_STATE); { ets_insert_2_list_destroy_copied_dbterms(meth, compressed, - db_term_list); + destroy_list); } YCF_SPECIAL_CODE_END(); } #endif /* YCF_FUNCTIONS */ @@ -1881,48 +1948,76 @@ static void ets_insert_2_yield_free(void* data, void* ctx) static int ets_insert_2_list_yield_dtor(Binary* bin) { ets_insert_2_list_info* ctx = ERTS_MAGIC_BIN_DATA(bin); - if (ctx->status != ETS_INSERT_2_LIST_GLOBAL && - ctx->continuation_state != NULL) { - /* The operation has not been committed to the table and has - not completed*/ + if (ctx->continuation_state) { ets_insert_2_list_ycf_gen_destroy(ctx->continuation_state); } + erts_bin_release(ctx->btid); return 1; } -static void ets_insert_2_list_continuation(long *reds_ptr, - void** state, - void* extra_context) +#define ITERATIONS_PER_RED 8 + +static BIF_RETTYPE +ets_insert_2_list_continuation(Process* p, + ets_insert_2_list_info* ctx) { + long reds = ITERATIONS_PER_RED * ERTS_BIF_REDS_LEFT(p); + long init_reds; + BIF_RETTYPE ret; + + reds = DBG_RANDOM_REDS(reds, (Uint)ctx); + init_reds = reds; + + ERTS_LC_ASSERT(ctx->status != ETS_INSERT_2_LIST_GLOBAL + || DB_LOCK_FREE(tb) + || erts_lc_rwmtx_is_rwlocked(&ctx->tb->common.rwlock)); + ASSERT(ctx->continuation_state); + #if defined(DEBUG) && defined(ARCH_64) - ycf_debug_set_stack_start(reds_ptr); + ycf_debug_set_stack_start(&reds); #endif - ets_insert_2_list_ycf_gen_continue(reds_ptr, state, extra_context); + ret = ets_insert_2_list_ycf_gen_continue(&reds, + &ctx->continuation_state, + ctx); #if defined(DEBUG) && defined(ARCH_64) ycf_debug_reset_stack_start(); #endif -} -static int db_insert_new_2_res_bin_dtor(Binary *context_bin) -{ - (void)context_bin; - return 1; + if (ctx->continuation_state == NULL) { + if (is_value(ret)) { + ASSERT(ret == am_true || ret == am_false); + erts_atomic_set_nob(&ctx->return_value, ret); + } + if (ctx->status == ETS_INSERT_2_LIST_GLOBAL) { + DbTableCommon *tb = &ctx->tb->common; + if (tb->continuation_ctx) { + /* Uninstall the continuation from the table struct */ + ASSERT(!(tb->status & DB_DELETE)); + tb->status |= tb->type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC); + tb->status &= ~DB_BUSY; + tb->continuation_ctx = NULL; + erts_bin_release(&(ERTS_MAGIC_BIN_FROM_DATA(ctx)->binary)); + } + } + } + BUMP_REDS(p, (init_reds - reds) / ITERATIONS_PER_RED); + return ret; } -#define ITERATIONS_PER_RED 8 - static BIF_RETTYPE ets_insert_2_list_driver(Process* p, Eterm tid, Eterm list, int is_insert_new) { - const long reds = ITERATIONS_PER_RED * ERTS_BIF_REDS_LEFT(p); - long nr_of_reductions = DBG_RANDOM_REDS(reds, (Uint)&p); - const long init_reds = nr_of_reductions; +#if defined(DEBUG) && defined(ARCH_64) + int dbg_ycf_stack_start; +#endif ets_insert_2_list_info* ctx = NULL; - ets_insert_2_list_info ictx; BIF_RETTYPE ret = THE_NON_VALUE; Eterm state_mref = list; Uint bix = (is_insert_new ? BIF_ets_insert_new_2 : BIF_ets_insert_2); + ets_insert_2_list_info ictx; + int do_trap; + if (is_internal_magic_ref(state_mref)) { Binary* state_bin = erts_magic_ref2bin(state_mref); if (ERTS_MAGIC_BIN_DESTRUCTOR(state_bin) != ets_insert_2_list_yield_dtor) { @@ -1932,57 +2027,60 @@ static BIF_RETTYPE ets_insert_2_list_driver(Process* p, erts_set_gc_state(p, 1); ctx = ERTS_MAGIC_BIN_DATA(state_bin); if (ctx->status == ETS_INSERT_2_LIST_GLOBAL) { - /* An operation that can be helped by other operations is - handled here */ - Uint freason; - int cret = DB_ERROR_NONE; - DbTable* tb; - /* First check if another process has completed the - operation without acquiring the lock */ - tb = db_get_table(p, tid, DB_READ_TBL_STRUCT, NOLCK_ACCESS, &freason); - ASSERT(tb || freason != TRAP); - if (tb != NULL && - (void*)erts_atomic_read_acqb(&tb->common.continuation_state) == - ctx->continuation_state) { - /* The lock has to be taken to complete the operation */ - if (NULL == (tb = db_get_table(p, tid, DB_WRITE, LCK_WRITE, &freason))) { - if (freason == TRAP){ - erts_set_gc_state(p, 0); - return db_bif_fail(p, freason, bix, NULL); - } - } - /* Must be done since the db_get_table call did not trap */ - if (tb != NULL) { + DbTable* tb = btid2tab(ctx->btid); + if (tb) { + db_lock(tb, LCK_WRITE); + if (ctx != tb->common.continuation_ctx) { db_unlock(tb, LCK_WRITE); + tb = NULL; } } - if (is_insert_new) { - int* res = ERTS_MAGIC_BIN_DATA(ctx->continuation_res_bin); - cret = *res; + if (!tb) { + /* + * Operation completed/aborted by someone else. + * Note: If insert was successful but table has been deleted, + * we still return success. It would be wrong to fail the insert + * if someone have seen the result (before the table was deleted). + */ + ret = erts_atomic_read_nob(&ctx->return_value); + if (is_value(ret)) { + ASSERT(ret == am_true || + (ret == am_false && is_insert_new)); + return ret; + } + else { + ASSERT(!tb || tb->common.status & DB_DELETE); + BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO); + } } - return ets_cret_to_return_value(NULL, cret); - } else { -#if defined(DEBUG) && defined(ARCH_64) - ycf_debug_set_stack_start(&nr_of_reductions); -#endif - ret = ets_insert_2_list_ycf_gen_continue(&nr_of_reductions, - &ctx->continuation_state, - ctx); -#if defined(DEBUG) && defined(ARCH_64) - ycf_debug_reset_stack_start(); -#endif + ASSERT((tb->common.status & (DB_WRITE|DB_BUSY)) + == DB_BUSY); } + ret = ets_insert_2_list_continuation(p, ctx); + ASSERT(ctx->continuation_state + || ret == am_true || ret == am_false || ret == THE_NON_VALUE); } else { /* Start call */ + long reds = ITERATIONS_PER_RED * ERTS_BIF_REDS_LEFT(p); + long init_reds; + + reds = DBG_RANDOM_REDS(reds, (Uint)p); + init_reds = reds; + ictx.continuation_state = NULL; ictx.status = ETS_INSERT_2_LIST_PROCESS_LOCAL; + erts_atomic_init_nob(&ictx.return_value, THE_NON_VALUE); ictx.tb = NULL; + ictx.tid = tid; + ictx.list = list; + DB_GET_TABLE(ictx.tb, tid, DB_READ_TBL_STRUCT, LCK_NOLOCK_ACCESS, bix, + NULL, p); + ictx.btid = ictx.tb->common.btid; ctx = &ictx; - DB_GET_TABLE(ctx->tb, tid, DB_READ_TBL_STRUCT, NOLCK_ACCESS, bix, NULL, p); #if defined(DEBUG) && defined(ARCH_64) - ycf_debug_set_stack_start(&nr_of_reductions); + ycf_debug_set_stack_start(&dbg_ycf_stack_start); #endif - ret = ets_insert_2_list_ycf_gen_yielding(&nr_of_reductions, + ret = ets_insert_2_list_ycf_gen_yielding(&reds, &ctx->continuation_state, ctx, ets_insert_2_yield_alloc, @@ -1992,12 +2090,16 @@ static BIF_RETTYPE ets_insert_2_list_driver(Process* p, NULL, p, tid, + ctx->btid, ctx->tb, list, is_insert_new); #if defined(DEBUG) && defined(ARCH_64) ycf_debug_reset_stack_start(); #endif + ASSERT(ctx->continuation_state + || ret == am_true || ret == am_false || ret == THE_NON_VALUE); + if (ctx->continuation_state != NULL) { Binary* state_bin = erts_create_magic_binary(sizeof(ets_insert_2_list_info), ets_insert_2_list_yield_dtor); @@ -2005,40 +2107,37 @@ static BIF_RETTYPE ets_insert_2_list_driver(Process* p, state_mref = erts_mk_magic_ref(&hp, &MSO(p), state_bin); ctx = ERTS_MAGIC_BIN_DATA(state_bin); *ctx = ictx; + erts_refc_inc(&ctx->btid->intern.refc, 2); } - } - BUMP_REDS(p, (init_reds - nr_of_reductions) / ITERATIONS_PER_RED); - if (ctx->status == ETS_INSERT_2_LIST_GLOBAL && - ctx->continuation_state != NULL && - ctx->tb->common.continuation == NULL) { - /* Install the continuation in the table structure so other - threads can help */ - if (is_insert_new) { - Binary* bin = - erts_create_magic_binary(sizeof(int), - db_insert_new_2_res_bin_dtor); - Eterm* hp = HAlloc(p, ERTS_MAGIC_REF_THING_SIZE); - erts_mk_magic_ref(&hp, &MSO(p), bin); - erts_refc_inctest(&bin->intern.refc, 2); - ctx->tb->common.continuation_res_bin = bin; - ctx->continuation_res_bin = bin; + BUMP_REDS(p, (init_reds - reds) / ITERATIONS_PER_RED); + } + do_trap = (ctx->continuation_state != NULL); + if (do_trap) { + if (ctx->status == ETS_INSERT_2_LIST_GLOBAL && + !ctx->tb->common.continuation_ctx) { + /* Install the continuation in the table structure so other + threads can help */ + ctx->tb->common.status &= ~(DB_PRIVATE|DB_PROTECTED|DB_PUBLIC); + ctx->tb->common.status |= DB_BUSY; + ASSERT(ctx != &ictx); + erts_refc_inc(&(ERTS_MAGIC_BIN_FROM_DATA(ctx)->binary.intern.refc), 2); + ctx->tb->common.continuation_ctx = ctx; } - ctx->tb->common.continuation = ets_insert_2_list_continuation; - ctx->tb->common.status &= ~(DB_PRIVATE|DB_PROTECTED|DB_PUBLIC); - ctx->tb->common.status |= DB_BUSY; - erts_atomic_set_relb(&ctx->tb->common.continuation_state, - (Sint)ctx->continuation_state); } - if (ctx->status == ETS_INSERT_2_LIST_FAILED_TO_GET_LOCK_DESTROY) { - return ctx->destroy_return_value; + else if (is_non_value(ret)) { + ASSERT(p->freason != TRAP); + ERTS_BIF_ERROR_TRAPPED2(p, p->freason, BIF_TRAP_EXPORT(bix), + ctx->tid, ctx->list); } if (ctx->status == ETS_INSERT_2_LIST_GLOBAL) { db_unlock(ctx->tb, LCK_WRITE); } - if (ctx->continuation_state != NULL) { + if (do_trap) { erts_set_gc_state(p, 0); BIF_TRAP2(BIF_TRAP_EXPORT(bix), p, tid, state_mref); } + + ASSERT(ret == am_true || ret == am_false); return ret; } @@ -2170,13 +2269,13 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) db_unlock(tb, LCK_READ); BIF_ERROR(BIF_P, BADARG); } - +retry: (void) meta_name_tab_bucket(BIF_ARG_2, &lck1); if (is_atom(BIF_ARG_1)) { old_name = BIF_ARG_1; named_tab: - (void) meta_name_tab_bucket(old_name, &lck2); + (void)meta_name_tab_bucket(old_name, &lck2); if (lck1 == lck2) lck2 = NULL; else if (lck1 > lck2) { @@ -2190,15 +2289,17 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) if (!tb) BIF_ERROR(BIF_P, BADARG | EXF_HAS_EXT_INFO); else { + old_name = tb->common.the_name; if (is_table_named(tb)) { - old_name = tb->common.the_name; goto named_tab; } + lck1 = NULL; lck2 = NULL; } } - erts_rwmtx_rwlock(lck1); + if (lck1) + erts_rwmtx_rwlock(lck1); if (lck2) erts_rwmtx_rwlock(lck2); @@ -2207,6 +2308,16 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) goto fail; if (is_table_named(tb)) { + if (tb->common.the_name != old_name) { + /* Wow! Racing rename op. Unlock all and retry. */ + ASSERT(is_not_atom(BIF_ARG_1)); + if (lck1) + erts_rwmtx_rwunlock(lck1); + if (lck2) + erts_rwmtx_rwunlock(lck2); + db_unlock(tb, LCK_WRITE); + goto retry; + } if (!insert_named_tab(BIF_ARG_2, tb, 1)) goto badarg; @@ -2220,7 +2331,8 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) tb->common.the_name = BIF_ARG_2; db_unlock(tb, LCK_WRITE); - erts_rwmtx_rwunlock(lck1); + if (lck1) + erts_rwmtx_rwunlock(lck1); if (lck2) erts_rwmtx_rwunlock(lck2); BIF_RET(ret); @@ -2231,7 +2343,8 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) fail: if (tb) db_unlock(tb, LCK_WRITE); - erts_rwmtx_rwunlock(lck1); + if (lck1) + erts_rwmtx_rwunlock(lck1); if (lck2) erts_rwmtx_rwunlock(lck2); @@ -2256,8 +2369,11 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) Sint keypos; int is_named, is_compressed; int is_fine_locked, frequent_read; + int number_of_locks; int is_decentralized_counters; int is_decentralized_counters_option; + int is_explicit_lock_granularity; + int is_write_concurrency_auto; int cret; DbTableMethod* meth; @@ -2278,6 +2394,9 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) heir = am_none; heir_data = (UWord) am_undefined; is_compressed = erts_ets_always_compress; + number_of_locks = -1; + is_explicit_lock_granularity = 0; + is_write_concurrency_auto = 0; list = BIF_ARG_2; while(is_list(list)) { @@ -2303,10 +2422,41 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) keypos = signed_val(tp[2]); } else if (tp[1] == am_write_concurrency) { - if (tp[2] == am_true) { + if (tp[2] == am_auto) { + is_decentralized_counters = 1; + is_write_concurrency_auto = 1; + is_fine_locked = 1; + is_explicit_lock_granularity = 0; + number_of_locks = -1; + } else if (tp[2] == am_true) { + if (!(status & DB_ORDERED_SET)) { + is_decentralized_counters = 0; + } is_fine_locked = 1; + is_explicit_lock_granularity = 0; + is_write_concurrency_auto = 0; + number_of_locks = -1; } else if (tp[2] == am_false) { is_fine_locked = 0; + is_explicit_lock_granularity = 0; + is_write_concurrency_auto = 0; + number_of_locks = -1; + } else if (is_tuple(tp[2])) { + Eterm *stp = tuple_val(tp[2]); + Sint number_of_locks_param; + if (arityval(stp[0]) == 2 && + stp[1] == am_debug_hash_fixed_number_of_locks && + term_to_Sint(stp[2], &number_of_locks_param) && + number_of_locks_param >= DB_WRITE_CONCURRENCY_MIN_LOCKS && + number_of_locks_param <= DB_WRITE_CONCURRENCY_MAX_LOCKS) { + + is_decentralized_counters = 1; + is_fine_locked = 1; + is_explicit_lock_granularity = 1; + is_write_concurrency_auto = 0; + number_of_locks = number_of_locks_param; + + } else break; } else break; if (DB_LOCK_FREE(NULL)) is_fine_locked = 0; @@ -2370,15 +2520,43 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) status |= DB_CA_ORDERED_SET; status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG | DB_ORDERED_SET); status |= DB_FINE_LOCKED; + if (is_explicit_lock_granularity) { + /* + * The hidden debug option to explicitly set the number of locks, + * currently doesn't make sense for ordered_set. + */ + BIF_ERROR(BIF_P, BADARG); + } else if (is_write_concurrency_auto) { + /* + * ordered_set tables that are configured with + * {write_concurrency, true} or {write_concurrency, auto} + * currently get the same implementation but we record + * that the auto option was used anyway so that + * ets:info(T, write_concurrency) can return auto when the + * table has been configured with {write_concurrency, + * auto}. + */ + status |= DB_FINE_LOCKED_AUTO; + } } else if (IS_HASH_TABLE(status)) { meth = &db_hash; if (is_fine_locked && !(status & DB_PRIVATE)) { status |= DB_FINE_LOCKED; - } + if (is_explicit_lock_granularity) { + status |= DB_EXPLICIT_LOCK_GRANULARITY; + } else if (is_write_concurrency_auto) { + status |= DB_FINE_LOCKED_AUTO; + } + } else { + number_of_locks = -1; + } } else if (IS_TREE_TABLE(status)) { meth = &db_tree; + if (is_explicit_lock_granularity) { + BIF_ERROR(BIF_P, BADARG); + } } else { BIF_ERROR(BIF_P, BADARG); @@ -2388,7 +2566,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) status |= DB_FREQ_READ; /* we create table outside any table lock - * and take the unusal cost of destroy table if it + * and take the unusual cost of destroy table if it * fails to find a slot */ { @@ -2411,8 +2589,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) tb->common.status = status; tb->common.type = status; /* Note, 'type' is *read only* from now on... */ - tb->common.continuation = NULL; - erts_atomic_set_nob(&tb->common.continuation_state, (Sint)NULL); + tb->common.continuation_ctx = NULL; erts_refc_init(&tb->common.fix_count, 0); db_init_lock(tb, status & (DB_FINE_LOCKED|DB_FREQ_READ)); tb->common.keypos = keypos; @@ -2425,6 +2602,10 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) tb->common.dbg_force_trap = erts_ets_dbg_force_trap; #endif + if (IS_HASH_TABLE(status)) { + DbTableHash* hash_db = (DbTableHash*) tb; + hash_db->nlocks = number_of_locks; + } cret = meth->db_create(BIF_P, tb); ASSERT(cret == DB_ERROR_NONE); (void)cret; @@ -2447,7 +2628,8 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) tb->common.meth->db_free_empty_table(tb); db_unlock(tb,LCK_WRITE); table_dec_refc(tb, 0); - BIF_ERROR(BIF_P, BADARG); + BIF_P->fvalue = EXI_ALREADY_EXISTS; + BIF_ERROR(BIF_P, BADARG | EXF_HAS_EXT_INFO); } BIF_P->flags |= F_USING_DB; /* So we can remove tb if p dies */ @@ -2583,8 +2765,44 @@ BIF_RETTYPE ets_lookup_element_3(BIF_ALIST_3) } } -/* - * BIF to erase a whole table and release all memory it holds +/* +** Get an element from a term +** get_element_4(Tab, Key, Index, Default) +** return the element or a list of elements if bag or Default if the element is not present +*/ +BIF_RETTYPE ets_lookup_element_4(BIF_ALIST_4) +{ + DbTable* tb; + Sint index; + int cret; + Eterm ret; + + CHECK_TABLES(); + + DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_lookup_element_4); + + if (is_not_small(BIF_ARG_3) || ((index = signed_val(BIF_ARG_3)) < 1)) { + db_unlock(tb, LCK_READ); + BIF_ERROR(BIF_P, BADARG); + } + + cret = tb->common.meth->db_get_element(BIF_P, tb, + BIF_ARG_2, index, &ret); + db_unlock(tb, LCK_READ); + switch (cret) { + case DB_ERROR_NONE: + BIF_RET(ret); + case DB_ERROR_BADKEY: + BIF_RET(BIF_ARG_4); + case DB_ERROR_SYSRES: + BIF_ERROR(BIF_P, SYSTEM_LIMIT); + default: + BIF_ERROR(BIF_P, BADARG); + } +} + +/* + * BIF to erase a whole table and release all memory it holds */ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) { @@ -2607,8 +2825,9 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) * Clear all access bits to prevent any ets operation to access the * table while it is being deleted. */ - tb->common.status &= ~(DB_PROTECTED|DB_PUBLIC|DB_PRIVATE); + tb->common.status &= ~(DB_PROTECTED | DB_PUBLIC | DB_PRIVATE | DB_BUSY); tb->common.status |= DB_DELETE; + cancel_trap_continuation(tb); if (tb->common.owner != BIF_P->common.id) { @@ -2834,15 +3053,23 @@ BIF_RETTYPE ets_internal_delete_all_2(BIF_ALIST_2) * the table and instead pitch in deleting objects * (in delete_all_objects_continue) and then trap to self. */ + Eterm tid; ASSERT((tb->common.status & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC)) == (tb->common.type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC))); tb->common.status &= ~(DB_PRIVATE|DB_PROTECTED|DB_PUBLIC); tb->common.status |= DB_BUSY; db_unlock(tb, LCK_WRITE); + + if (is_atom(BIF_ARG_1)) { + ASSERT(is_table_named(tb)); + tid = make_tid(BIF_P, tb); + } else { + tid = BIF_ARG_1; + } BUMP_ALL_REDS(BIF_P); BIF_TRAP2(BIF_TRAP_EXPORT(BIF_ets_internal_delete_all_2), BIF_P, - BIF_ARG_1, nitems_holder); + tid, nitems_holder); } else { /* Done, no trapping needed */ @@ -3106,7 +3333,7 @@ ets_all_reply(ErtsSchedulerData *esdp, ErtsEtsAllReq **reqpp, * - save_sched_table() inserts at end of circular list. * * - This function scans from the end so we know that - * the amount of tables to scan wont grow even if we + * the amount of tables to scan won't grow even if we * yield. * * - remove_sched_table() updates the table we yielded @@ -3120,7 +3347,7 @@ ets_all_reply(ErtsSchedulerData *esdp, ErtsEtsAllReq **reqpp, hp = &hfragp->mem[hfragp->used_size]; list = *hp; hfragp->used_size = hfragp->alloc_size; - first = esdp->ets_tables.clist; + first = esdp->u.ets_tables.clist; tb = *tablepp; } else { @@ -3128,7 +3355,7 @@ ets_all_reply(ErtsSchedulerData *esdp, ErtsEtsAllReq **reqpp, ASSERT(!*tablepp); /* Max heap size needed... */ - sz = erts_atomic_read_nob(&esdp->ets_tables.count); + sz = erts_atomic_read_nob(&esdp->u.ets_tables.count); sz *= ERTS_MAGIC_REF_THING_SIZE + 2; sz += 3 + ERTS_REF_THING_SIZE; hfragp = new_message_buffer(sz); @@ -3136,7 +3363,7 @@ ets_all_reply(ErtsSchedulerData *esdp, ErtsEtsAllReq **reqpp, hp = &hfragp->mem[0]; ohp = &hfragp->off_heap; list = NIL; - first = esdp->ets_tables.clist; + first = esdp->u.ets_tables.clist; tb = first ? first->common.all.prev : NULL; } @@ -3222,7 +3449,7 @@ erts_handle_yielded_ets_all_request(ErtsAuxWorkData *awdp) return 0; /* All work completed! */ if (yc < ERTS_ETS_ALL_TB_YCNT_START && - yc > erts_atomic_read_nob(&esdp->ets_tables.count)) + yc > erts_atomic_read_nob(&esdp->u.ets_tables.count)) return 1; /* Yield! */ eaydp->ongoing = ongoing = eaydp->queue; @@ -4061,7 +4288,10 @@ BIF_RETTYPE ets_info_1(BIF_ALIST_1) Sint words = (Sint) ((memory + sizeof(Sint) - 1) / sizeof(Sint)); results[i] = erts_make_integer(words, BIF_P); } else { - results[i] = table_info(BIF_P, tb, fields[i]); + ErtsHeapFactory hf; + erts_factory_proc_init(&hf, BIF_P); + results[i] = table_info(&hf, tb, fields[i]); + erts_factory_close(&hf); ASSERT(is_value(results[i])); } } @@ -4132,7 +4362,10 @@ BIF_RETTYPE ets_info_2(BIF_ALIST_2) ret = erts_make_integer(r, BIF_P); } } else { - ret = table_info(BIF_P, tb, BIF_ARG_2); + ErtsHeapFactory hf; + erts_factory_proc_init(&hf, BIF_P); + ret = table_info(&hf, tb, BIF_ARG_2); + erts_factory_close(&hf); } db_unlock(tb, LCK_READ); if (is_non_value(ret)) { @@ -4361,7 +4594,7 @@ void init_db(ErtsDbSpinCount db_spin_count) } /* - * We don't have ony hard limit for number of tables anymore, . + * We don't have only hard limit for number of tables anymore, . * but we use 'db_max_tabs' to determine size of name hash table. */ meta_name_tab_mask = (((Uint) 1)<hfrag = NULL; eaydp->tab = NULL; eaydp->queue = NULL; - esdp->ets_tables.clist = NULL; - erts_atomic_init_nob(&esdp->ets_tables.count, 0); + esdp->u.ets_tables.clist = NULL; + erts_atomic_init_nob(&esdp->u.ets_tables.count, 0); } @@ -4638,8 +4871,10 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks, void **yield_stat break; } /* Clear all access bits. */ - tb->common.status &= ~(DB_PROTECTED | DB_PUBLIC | DB_PRIVATE); + tb->common.status &= ~(DB_PROTECTED | DB_PUBLIC | DB_PRIVATE + | DB_BUSY); tb->common.status |= DB_DELETE; + cancel_trap_continuation(tb); if (is_table_named(tb)) remove_named_tab(tb, 0); @@ -4979,7 +5214,7 @@ static SWord free_table_continue(Process *p, DbTable *tb, SWord reds) struct fixing_procs_info_ctx { - Process* p; + ErtsHeapFactory* hf; Eterm list; }; @@ -4989,21 +5224,23 @@ static int fixing_procs_info_op(DbFixation* fix, void* vctx, Sint reds) Eterm* hp; Eterm tpl; - hp = HAllocX(ctx->p, 5, 100); + hp = erts_produce_heap(ctx->hf, 5, 100); tpl = TUPLE2(hp, fix->procs.p->common.id, make_small(fix->counter)); hp += 3; ctx->list = CONS(hp, tpl, ctx->list); return 1; } -static Eterm table_info(Process* p, DbTable* tb, Eterm What) +static Eterm table_info(ErtsHeapFactory *hf, DbTable* tb, Eterm What) { Eterm ret = THE_NON_VALUE; int use_monotonic; + ASSERT(hf != NULL); + if (What == am_size) { Uint size = (Uint) (DB_GET_APPROX_NITEMS(tb)); - ret = erts_make_integer(size, p); + ret = erts_make_integer_fact(size, hf); } else if (What == am_type) { if (tb->common.status & DB_SET) { ret = am_set; @@ -5022,7 +5259,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) + sizeof(Uint) - 1) / sizeof(Uint)); - ret = erts_make_integer(words, p); + ret = erts_make_integer_fact(words, hf); } else if (What == am_owner) { ret = tb->common.owner; } else if (What == am_heir) { @@ -5035,7 +5272,20 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) else if (tb->common.status & DB_PUBLIC) ret = am_public; } else if (What == am_write_concurrency) { - ret = tb->common.status & DB_FINE_LOCKED ? am_true : am_false; + if ((tb->common.status & DB_FINE_LOCKED) && + (tb->common.status & (DB_SET | DB_BAG | DB_DUPLICATE_BAG)) && + (tb->common.status & DB_EXPLICIT_LOCK_GRANULARITY)) { + Eterm* hp = erts_produce_heap(hf, 3, 0); + ret = make_tuple(hp); + *hp++ = make_arityval(2); + *hp++ = am_debug_hash_fixed_number_of_locks; + *hp++ = erts_make_integer_fact(tb->hash.nlocks, hf); + } else if ((tb->common.status & DB_FINE_LOCKED) && + (tb->common.status & DB_FINE_LOCKED_AUTO)) { + ret = am_auto; + } else { + ret = tb->common.status & DB_FINE_LOCKED ? am_true : am_false; + } } else if (What == am_read_concurrency) { ret = tb->common.status & DB_FREQ_READ ? am_true : am_false; } else if (What == am_name) { @@ -5049,7 +5299,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) } else if (What == am_compressed) { ret = tb->common.compress ? am_true : am_false; } else if (What == am_id) { - ret = make_tid(p, tb); + ret = make_tid_fact(hf, tb); } else if (What == am_decentralized_counters) { ret = tb->common.counters.is_decentralized ? am_true : am_false; } @@ -5089,13 +5339,13 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) mtime = 0; need += 4; } - ctx.p = p; + ctx.hf = hf; ctx.list = NIL; fixing_procs_rbt_foreach(tb->common.fixing_procs, fixing_procs_info_op, &ctx); - hp = HAlloc(p, need); + hp = erts_produce_heap(hf, need, 0); if (use_monotonic) time = (IS_SSMALL(mtime) ? make_small(mtime) @@ -5122,7 +5372,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) Eterm* hp; db_calc_stats_hash(&tb->hash, &stats); - hp = HAlloc(p, 1 + 7 + FLOAT_SIZE_OBJECT*3); + hp = erts_produce_heap(hf, 1 + 8 + FLOAT_SIZE_OBJECT*3, 0); f.fd = stats.avg_chain_len; avg = make_float(hp); PUT_DOUBLE(f, hp); @@ -5137,18 +5387,19 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) std_dev_exp = make_float(hp); PUT_DOUBLE(f, hp); hp += FLOAT_SIZE_OBJECT; - ret = TUPLE7(hp, make_small(erts_atomic_read_nob(&tb->hash.nactive)), + ret = TUPLE8(hp, make_small(erts_atomic_read_nob(&tb->hash.nactive)), avg, std_dev_real, std_dev_exp, make_small(stats.min_chain_len), make_small(stats.max_chain_len), - make_small(stats.kept_items)); + make_small(stats.kept_items), + make_small(tb->hash.nlocks)); } else if (IS_CATREE_TABLE(tb->common.status)) { DbCATreeStats stats; Eterm* hp; db_calc_stats_catree(&tb->catree, &stats); - hp = HAlloc(p, 4); + hp = erts_produce_heap(hf, 4, 0); ret = TUPLE3(hp, make_small(stats.route_nodes), make_small(stats.base_nodes), @@ -5164,12 +5415,14 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What) static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb) { Eterm tid; - Eterm heap[ERTS_MAGIC_REF_THING_SIZE]; + ErtsHeapFactory hf; + erts_factory_tmp_init(&hf, NULL, 0, ERTS_ALC_T_TMP); if (is_table_named(tb)) { tid = tb->common.the_name; } else { ErlOffHeap oh; + Eterm *heap = erts_produce_heap(&hf, ERTS_MAGIC_REF_THING_SIZE, 0); ERTS_INIT_OFF_HEAP(&oh); write_magic_ref_thing(heap, &oh, (ErtsMagicBinary *) tb->common.btid); tid = make_internal_ref(heap); @@ -5186,11 +5439,12 @@ static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb) + sizeof(Uint) - 1) / sizeof(Uint))); - erts_print(to, to_arg, "Type: %T\n", table_info(NULL, tb, am_type)); - erts_print(to, to_arg, "Protection: %T\n", table_info(NULL, tb, am_protection)); - erts_print(to, to_arg, "Compressed: %T\n", table_info(NULL, tb, am_compressed)); - erts_print(to, to_arg, "Write Concurrency: %T\n", table_info(NULL, tb, am_write_concurrency)); - erts_print(to, to_arg, "Read Concurrency: %T\n", table_info(NULL, tb, am_read_concurrency)); + erts_print(to, to_arg, "Type: %T\n", table_info(&hf, tb, am_type)); + erts_print(to, to_arg, "Protection: %T\n", table_info(&hf, tb, am_protection)); + erts_print(to, to_arg, "Compressed: %T\n", table_info(&hf, tb, am_compressed)); + erts_print(to, to_arg, "Write Concurrency: %T\n", table_info(&hf, tb, am_write_concurrency)); + erts_print(to, to_arg, "Read Concurrency: %T\n", table_info(&hf, tb, am_read_concurrency)); + erts_factory_close(&hf); } typedef struct { @@ -5237,7 +5491,7 @@ erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg, int alive_only for (ix = 0; ix < erts_no_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix); - DbTable *first = esdp->ets_tables.clist; + DbTable *first = esdp->u.ets_tables.clist; if (first) { DbTable *tb = first; do { @@ -5269,7 +5523,7 @@ erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *), /* retrieve max number of ets tables */ Uint -erts_db_get_max_tabs() +erts_db_get_max_tabs(void) { return db_max_tabs; } @@ -5281,7 +5535,7 @@ Uint erts_ets_table_count(void) for (six = 0; six < erts_no_schedulers; six++) { ErtsSchedulerData *esdp = &erts_aligned_scheduler_data[six].esd; - tb_count += erts_atomic_read_nob(&esdp->ets_tables.count); + tb_count += erts_atomic_read_nob(&esdp->u.ets_tables.count); } return tb_count; } @@ -5348,7 +5602,7 @@ static void lcnt_update_db_locks_per_sched(void *enable) { DbTable *head; esdp = erts_get_scheduler_data(); - head = esdp->ets_tables.clist; + head = esdp->u.ets_tables.clist; if(head) { DbTable *iterator = head; diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h index 9f21728ca128..19379dcdbed3 100644 --- a/erts/emulator/beam/erl_db.h +++ b/erts/emulator/beam/erl_db.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2022. 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. @@ -94,7 +94,7 @@ union db_table { /*TT*/ }; -#define DB_DEF_MAX_TABS 8192 /* Superseeded by environment variable +#define DB_DEF_MAX_TABS 8192 /* Superseded by environment variable "ERL_MAX_ETS_TABLES" */ #define ERL_MAX_ETS_TABLES_ENV "ERL_MAX_ETS_TABLES" @@ -173,12 +173,15 @@ do { \ ERTS_GLB_INLINE void *erts_db_alloc(ErtsAlcType_t type, DbTable *tab, - Uint size); + Uint size) ERTS_ATTR_MALLOC_US(3); ERTS_GLB_INLINE void *erts_db_alloc_fnf(ErtsAlcType_t type, DbTable *tab, - Uint size); -ERTS_GLB_INLINE void *erts_db_alloc_nt(ErtsAlcType_t type, Uint size); -ERTS_GLB_INLINE void *erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size); + Uint size) ERTS_ATTR_MALLOC_US(3); +ERTS_GLB_INLINE void* +erts_db_alloc_nt(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2); + +ERTS_GLB_INLINE void* +erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size) ERTS_ATTR_MALLOC_US(2); #if ERTS_GLB_INLINE_INCL_FUNC_DEF diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c index d2c3772913d7..700003438c65 100644 --- a/erts/emulator/beam/erl_db_catree.c +++ b/erts/emulator/beam/erl_db_catree.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB and Kjell Winblad 1998-2022. All Rights Reserved. + * Copyright Ericsson AB and Kjell Winblad 1998-2023. 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. @@ -79,6 +79,7 @@ #include "erl_db_catree.h" #include "erl_db_tree.h" #include "erl_db_tree_util.h" +#include "erl_global_literals.h" #ifdef DEBUG # define IF_DEBUG(X) X @@ -219,7 +220,7 @@ DbTableMethod db_catree = db_lookup_dbterm_catree, db_finalize_dbterm_catree, db_eterm_to_dbterm_tree_common, - db_dbterm_list_prepend_tree_common, + db_dbterm_list_append_tree_common, db_dbterm_list_remove_first_tree_common, db_put_dbterm_catree, db_free_dbterm_tree_common, @@ -873,7 +874,8 @@ Eterm copy_route_key(DbRouteKey* dst, Eterm key, Uint key_size) dst->oh = tmp_offheap.first; } else { - ASSERT(is_immed(key)); + ASSERT(is_immed(key) || + key == ERTS_GLOBAL_LIT_EMPTY_TUPLE); dst->term = key; dst->oh = NULL; } @@ -1032,6 +1034,7 @@ static DbTableCATreeNode *create_base_node(DbTableCATree *tb, "erl_db_catree_base_node", NIL, ERTS_LOCK_FLAGS_CATEGORY_DB); + ERTS_DB_ALC_MEM_UPDATE_((DbTable *) tb, 0, erts_rwmtx_size(&p->u.base.lock)); BASE_NODE_STAT_SET(p, ((tb->common.status & DB_CATREE_FORCE_SPLIT) ? INT_MAX : 0)); p->u.base.is_valid = 1; @@ -1090,7 +1093,7 @@ static void do_free_base_node(void* vptr) static void free_catree_base_node(DbTableCATree* tb, DbTableCATreeNode* p) { ASSERT(p->is_base_node); - ERTS_DB_ALC_MEM_UPDATE_(tb, sizeof_base_node(), 0); + ERTS_DB_ALC_MEM_UPDATE_(tb, sizeof_base_node() + erts_rwmtx_size(&p->u.base.lock), 0); do_free_base_node(p); } @@ -1257,7 +1260,7 @@ static void join_catree(DbTableCATree *tb, neighbor_parent = leftmost_route_node(GET_RIGHT(parent)); } } - } else { /* Symetric case */ + } else { /* Symmetric case */ ASSERT(GET_RIGHT(parent) == thiz); neighbor = rightmost_base_node(GET_LEFT_ACQB(parent)); if (try_wlock_base_node(&neighbor->u.base)) { @@ -1332,11 +1335,13 @@ static void join_catree(DbTableCATree *tb, thiz, &thiz->u.base.free_item, sizeof_base_node()); + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(&thiz->u.base.lock), 0); erts_schedule_db_free(&tb->common, do_free_base_node, neighbor, &neighbor->u.base.free_item, sizeof_base_node()); + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(&neighbor->u.base.lock), 0); } static void split_catree(DbTableCATree *tb, @@ -1381,6 +1386,7 @@ static void split_catree(DbTableCATree *tb, base, &base->u.base.free_item, sizeof_base_node()); + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(&base->u.base.lock), 0); } } diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 6eb7bde1b4f9..b94ff2ccd25d 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -87,57 +87,71 @@ #define IS_DECENTRALIZED_CTRS(DB) ((DB)->common.counters.is_decentralized) -#define NITEMS_ESTIMATE_FROM_LCK_CTR(LCK_CTR_P) \ - (LCK_CTR_P->nitems <= 0 ? 1: LCK_CTR_P->nitems) - -#define NITEMS_ESTIMATE(DB, LCK_CTR, HASH) \ - (IS_DECENTRALIZED_CTRS(DB) ? \ - (DB_HASH_LOCK_CNT * \ - (LCK_CTR != NULL ? \ - NITEMS_ESTIMATE_FROM_LCK_CTR(LCK_CTR) : \ - NITEMS_ESTIMATE_FROM_LCK_CTR(GET_LOCK_AND_CTR(DB, HASH)))) : \ - erts_flxctr_read_centralized(&(DB)->common.counters, \ - ERTS_DB_TABLE_NITEMS_COUNTER_ID)) - -#define ADD_NITEMS(DB, LCK_CTR, HASH, TO_ADD) \ - do { \ - if (IS_DECENTRALIZED_CTRS(DB)) { \ - if (LCK_CTR != NULL) { \ - LCK_CTR->nitems += TO_ADD; \ - } else { \ - GET_LOCK_AND_CTR(DB,HASH)->nitems += TO_ADD; \ - } \ - } \ - erts_flxctr_add(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID, TO_ADD); \ - } while(0) -#define INC_NITEMS(DB, LCK_CTR, HASH) \ - do { \ - if (IS_DECENTRALIZED_CTRS(DB)) { \ - if (LCK_CTR != NULL) { \ - LCK_CTR->nitems++; \ - } else { \ - GET_LOCK_AND_CTR(DB,HASH)->nitems++; \ - } \ - } \ - erts_flxctr_inc(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID); \ - } while(0) -#define DEC_NITEMS(DB, LCK_CTR, HASH) \ - do { \ - if (IS_DECENTRALIZED_CTRS(DB)) { \ - if (LCK_CTR != NULL) { \ - LCK_CTR->nitems--; \ - } else { \ - GET_LOCK_AND_CTR(DB,HASH)->nitems--; \ - } \ - } \ - erts_flxctr_dec(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID); \ - } while(0) +/* + * To get reasonable estimate of table load for grow/shrink decisions + * we limit the number of lock structs that hold (used) item counters. + * To simplify, this is also the minimum number of locks. + */ +#define NLOCKS_WITH_ITEM_COUNTERS 64 + +#define LCK_AUTO_MAX_LOCKS 8192 +#define LCK_AUTO_MIN_LOCKS NLOCKS_WITH_ITEM_COUNTERS +#define LCK_AUTO_DEFAULT_NUMBER_OF_LOCKS LCK_AUTO_MIN_LOCKS +#define LCK_AUTO_MAX_LOCKS_FREQ_READ_RW_LOCKS 128 + + +static ERTS_INLINE int +NITEMS_ESTIMATE(DbTableHash* DB, DbTableHashLockAndCounter* LCK_CTR, HashValue HASH) +{ + if (IS_DECENTRALIZED_CTRS(DB)) { + Sint nitems = erts_atomic_read_nob(&DB->locks[HASH % NLOCKS_WITH_ITEM_COUNTERS].u.lck_ctr.nitems); + return nitems * NLOCKS_WITH_ITEM_COUNTERS; + } + else { + return erts_flxctr_read_centralized(&(DB)->common.counters, + ERTS_DB_TABLE_NITEMS_COUNTER_ID); + } +} + +static ERTS_INLINE void +ADD_NITEMS(DbTableHash* DB, DbTableHashLockAndCounter* LCK_CTR, HashValue HASH, + Sint to_add) +{ + if (IS_DECENTRALIZED_CTRS(DB)) { + erts_atomic_add_nob(&DB->locks[HASH % NLOCKS_WITH_ITEM_COUNTERS].u.lck_ctr.nitems, + to_add); + } + erts_flxctr_add(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID, + to_add); +} + + +static ERTS_INLINE void +INC_NITEMS(DbTableHash* DB, DbTableHashLockAndCounter* LCK_CTR, HashValue HASH) +{ + if (IS_DECENTRALIZED_CTRS(DB)) { + erts_atomic_inc_nob(&DB->locks[HASH % NLOCKS_WITH_ITEM_COUNTERS].u.lck_ctr.nitems); + } + erts_flxctr_inc(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID); +} + +static ERTS_INLINE void +DEC_NITEMS(DbTableHash* DB, DbTableHashLockAndCounter* LCK_CTR, HashValue HASH) +{ + if (IS_DECENTRALIZED_CTRS(DB)) { + erts_atomic_dec_nob(&DB->locks[HASH % NLOCKS_WITH_ITEM_COUNTERS].u.lck_ctr.nitems); + } + erts_flxctr_dec(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID); +} + #define RESET_NITEMS(DB) \ erts_flxctr_reset(&(DB)->common.counters, ERTS_DB_TABLE_NITEMS_COUNTER_ID) #define GROW_LIMIT(NACTIVE) ((NACTIVE)*1) #define SHRINK_LIMIT(TB) erts_atomic_read_nob(&(TB)->shrink_limit) +#define IS_POW2(x) ((x) && !((x) & ((x)-1))) + /* ** We want the first mandatory segment to be small (to reduce minimal footprint) ** and larger extra segments (to reduce number of alloc/free calls). @@ -174,7 +188,7 @@ #define BUCKET(tb, i) SEGTAB(tb)[SLOT_IX_TO_SEG_IX(i)]->buckets[(i) & EXT_SEGSZ_MASK] #ifdef DEBUG -# define DBG_BUCKET_INACTIVE ((HashDbTerm*)0xdead5107) +# define DBG_BUCKET_INACTIVE ((HashDbTerm*)(UWord)0xdead5107) #endif @@ -264,11 +278,125 @@ static ERTS_INLINE int is_pseudo_deleted(HashDbTerm* p) ((is_atom(term) ? (atom_tab(atom_val(term))->slot.bucket.hvalue) : \ make_internal_hash(term, 0)) & MAX_HASH_MASK) -# define DB_HASH_LOCK_MASK (DB_HASH_LOCK_CNT-1) -# define GET_LOCK(tb,hval) (&(tb)->locks->lck_vec[(hval) & DB_HASH_LOCK_MASK].lck_ctr.lck) -# define GET_LOCK_AND_CTR(tb,hval) (&(tb)->locks->lck_vec[(hval) & DB_HASH_LOCK_MASK].lck_ctr) +# define GET_LOCK_MASK(NUMBER_OF_LOCKS) ((NUMBER_OF_LOCKS)-1) + +# define GET_LOCK(tb,hval) (&(tb)->locks[(hval) & GET_LOCK_MASK(tb->nlocks)].u.lck_ctr.lck) +# define GET_LOCK_AND_CTR(tb,hval) (&(tb)->locks[(hval) & GET_LOCK_MASK(tb->nlocks)].u.lck_ctr) # define GET_LOCK_MAYBE(tb,hval) ((tb)->common.is_thread_safe ? NULL : GET_LOCK(tb,hval)) +# define LCK_AUTO_CONTENDED_STAT_CONTRIB 100 +# define LCK_AUTO_UNCONTENDED_STAT_CONTRIB -1 +# define LCK_AUTO_GROW_LIMIT 1000 +# define LCK_AUTO_SHRINK_LIMIT -10000000 + +static void calc_shrink_limit(DbTableHash* tb); + +void db_hash_adapt_number_of_locks(DbTable* tb) { + db_hash_lock_array_resize_state current_state; + DbTableHash* tbl; + int new_number_of_locks; + + ASSERT(IS_HASH_WITH_AUTO_TABLE(tb->common.type)); + + tbl = &tb->hash; + erts_rwmtx_rwlock(&tb->common.rwlock); + current_state = erts_atomic_read_nob(&tb->hash.lock_array_resize_state); + if (current_state == DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL) { + /* Another thread did the lock array resize job before us */ + erts_rwmtx_rwunlock(&tb->common.rwlock); + return; + } + if (IS_FIXED(tb)) { + /* + Do not do any adaptation if the table is fixed as this can + lead to missed slots when traversing over the table. + + The lock statistics is kept as it is likely that we want to + adapt when the table is not fixed any more. + */ + erts_atomic_set_nob(&tbl->lock_array_resize_state, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL); + erts_rwmtx_rwunlock(&tb->common.rwlock); + return; + } + if (current_state == DB_HASH_LOCK_ARRAY_RESIZE_STATUS_GROW && + erts_atomic_read_nob(&tbl->nactive) >= (2*tbl->nlocks)) { + new_number_of_locks = 2*tbl->nlocks; + } else if (current_state == DB_HASH_LOCK_ARRAY_RESIZE_STATUS_SHRINK) { + new_number_of_locks = tbl->nlocks / 2; + } else { + /* + Do not do any adaptation if the number of active buckets is + smaller than the resulting number of locks. + + We do not want to make the table unnecessary large just to + potentially reduce contention. + */ + int i; + for (i = 0; i < tbl->nlocks; i++) { + tbl->locks[i].u.lck_ctr.lck_stat = 0; + } + erts_atomic_set_nob(&tbl->lock_array_resize_state, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL); + erts_rwmtx_rwunlock(&tb->common.rwlock); + return; + } + { + erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER; + int i; + DbTableHashFineLockSlot* old_locks = tbl->locks; + Uint old_number_of_locks = tbl->nlocks; + ASSERT(new_number_of_locks != 0); + tbl->nlocks = new_number_of_locks; + if (tb->common.type & DB_FREQ_READ && + new_number_of_locks <= LCK_AUTO_MAX_LOCKS_FREQ_READ_RW_LOCKS) { + rwmtx_opt.type = ERTS_RWMTX_TYPE_FREQUENT_READ; + } + if (erts_ets_rwmtx_spin_count >= 0) { + rwmtx_opt.main_spincount = erts_ets_rwmtx_spin_count; + } + tbl->locks = (DbTableHashFineLockSlot*) erts_db_alloc(ERTS_ALC_T_DB_SEG, + (DbTable *) tb, + sizeof(DbTableHashFineLockSlot) * tbl->nlocks); + for (i=0; i < tbl->nlocks; i++) { + erts_aint_t nitems; + erts_rwmtx_init_opt(GET_LOCK(tbl, i), &rwmtx_opt, + "db_hash_slot", tb->common.the_name, ERTS_LOCK_FLAGS_CATEGORY_DB); + ERTS_DB_ALC_MEM_UPDATE_(tb, 0, erts_rwmtx_size(GET_LOCK(tbl,i))); + nitems = (i >= NLOCKS_WITH_ITEM_COUNTERS ? 0 : + erts_atomic_read_nob(&old_locks[i].u.lck_ctr.nitems)); + erts_atomic_init_nob(&tbl->locks[i].u.lck_ctr.nitems, nitems); + tbl->locks[i].u.lck_ctr.lck_stat = 0; + } +/* #define HARD_DEBUG_ITEM_CNT_LOCK_CHANGE 1 */ +#ifdef HARD_DEBUG_ITEM_CNT_LOCK_CHANGE + { + Sint total_old = 0; + Sint total_new = 0; + int i; + for (i=0; i < old_number_of_locks; i++) { + total_old += old_locks[i].u.lck_ctr.nitems; + } + for (i=0; i < tbl->nlocks; i++) { + total_new += tbl->locks[i].u.lck_ctr.nitems; + } + /* erts_printf("%ld %ld %d\n", total_new, total_old, tbl->nlocks); */ + ERTS_ASSERT(total_new == total_old); + } +#endif + + calc_shrink_limit(tbl); + + erts_atomic_set_nob(&tbl->lock_array_resize_state, DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL); + erts_rwmtx_rwunlock(&tb->common.rwlock); + for (i = 0; i < old_number_of_locks; i++) { + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(&old_locks[i].u.lck_ctr.lck), 0); + erts_rwmtx_destroy(&old_locks[i].u.lck_ctr.lck); + } + erts_db_free(ERTS_ALC_T_DB_SEG, tb, old_locks, sizeof(DbTableHashFineLockSlot) * old_number_of_locks); + } +} + /* Fine grained read lock */ static ERTS_INLINE erts_rwmtx_t* RLOCK_HASH(DbTableHash* tb, HashValue hval) { @@ -281,16 +409,38 @@ static ERTS_INLINE erts_rwmtx_t* RLOCK_HASH(DbTableHash* tb, HashValue hval) return lck; } } -/* Fine grained write lock */ -static ERTS_INLINE erts_rwmtx_t* WLOCK_HASH(DbTableHash* tb, HashValue hval) + +static void +wlock_after_failed_trylock(DbTableHash* tb, DbTableHashLockAndCounter* lock) { - if (tb->common.is_thread_safe) { - return NULL; - } else { - erts_rwmtx_t* lck = GET_LOCK(tb,hval); - ASSERT(tb->common.type & DB_FINE_LOCKED); - erts_rwmtx_rwlock(lck); - return lck; + erts_rwmtx_rwlock(&lock->lck); + lock->lck_stat += LCK_AUTO_CONTENDED_STAT_CONTRIB; + if (lock->lck_stat > LCK_AUTO_GROW_LIMIT) { + /* + * Do not do any adaptation if the table is + * fixed as this can lead to missed slots when + * traversing over the table. + */ + if (!IS_FIXED(tb)) { + if (tb->nlocks < LCK_AUTO_MAX_LOCKS && + (DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL == + erts_atomic_read_nob(&tb->lock_array_resize_state))) { + /* + * Trigger lock array increase later when we + * can take the table lock + */ + erts_atomic_set_nob(&tb->lock_array_resize_state, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_GROW); + } + else { + /* + * The lock statistics is kept if the table is + * fixed as it is likely that we want to adapt + * when the table is not fixed any more. + */ + lock->lck_stat = 0; + } + } } } @@ -301,11 +451,48 @@ DbTableHashLockAndCounter* WLOCK_HASH_GET_LCK_AND_CTR(DbTableHash* tb, HashValue if (tb->common.is_thread_safe) { return NULL; } else { - DbTableHashLockAndCounter* lck_ctr = GET_LOCK_AND_CTR(tb,hval); ASSERT(tb->common.type & DB_FINE_LOCKED); - erts_rwmtx_rwlock(&lck_ctr->lck); - return lck_ctr; + if (tb->common.type & DB_FINE_LOCKED_AUTO) { + DbTableHashLockAndCounter* lck_couter = GET_LOCK_AND_CTR(tb, hval); + if (EBUSY == erts_rwmtx_tryrwlock(&lck_couter->lck)) { + wlock_after_failed_trylock(tb, lck_couter); + } else { + lck_couter->lck_stat += LCK_AUTO_UNCONTENDED_STAT_CONTRIB; + if (lck_couter->lck_stat < LCK_AUTO_SHRINK_LIMIT + && !IS_FIXED(tb)) { + if(tb->nlocks > LCK_AUTO_MIN_LOCKS && + (DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL == + erts_atomic_read_nob(&tb->lock_array_resize_state))) { + /* + Trigger lock array increase later when we + can take the table lock + */ + erts_atomic_set_nob(&tb->lock_array_resize_state, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_SHRINK); + } else { + lck_couter->lck_stat = 0; + } + } + } + return lck_couter; + } else { + DbTableHashLockAndCounter* lck_ctr = GET_LOCK_AND_CTR(tb,hval); + ASSERT(tb->common.type & DB_FINE_LOCKED); + erts_rwmtx_rwlock(&lck_ctr->lck); + return lck_ctr; + } + } +} + +/* Fine grained write lock */ +static ERTS_INLINE erts_rwmtx_t* WLOCK_HASH(DbTableHash* tb, HashValue hval) +{ + DbTableHashLockAndCounter* lck_cntr = + WLOCK_HASH_GET_LCK_AND_CTR(tb, hval); + if (lck_cntr == NULL) { + return NULL; } + return &lck_cntr->lck; } static ERTS_INLINE void RUNLOCK_HASH(erts_rwmtx_t* lck) @@ -349,10 +536,17 @@ static ERTS_INLINE void WUNLOCK_HASH_LCK_CTR(DbTableHashLockAndCounter* lck_ctr) static ERTS_INLINE Sint next_slot(DbTableHash* tb, Uint ix, erts_rwmtx_t** lck_ptr) { - ix += DB_HASH_LOCK_CNT; + /* + * To minimize locking ops, we jump to next bucket using same lock. + * In case of {write_concurrency,auto} this is safe as 'nlocks' does not + * change as long as table is fixed, which all single call select/match do. + * Unfixed next,prev and select/1 calls are also "safe" in the sence that + * we will seize correct locks as 'nlocks' will not change during the calls. + */ + ix += tb->nlocks; if (ix < NACTIVE(tb)) return ix; RUNLOCK_HASH(*lck_ptr); - ix = (ix + 1) & DB_HASH_LOCK_MASK; + ix = (ix + 1) & GET_LOCK_MASK(tb->nlocks); if (ix != 0) *lck_ptr = RLOCK_HASH(tb,ix); return ix; } @@ -360,10 +554,10 @@ static ERTS_INLINE Sint next_slot(DbTableHash* tb, Uint ix, static ERTS_INLINE Sint next_slot_w(DbTableHash* tb, Uint ix, erts_rwmtx_t** lck_ptr) { - ix += DB_HASH_LOCK_CNT; + ix += tb->nlocks; if (ix < NACTIVE(tb)) return ix; WUNLOCK_HASH(*lck_ptr); - ix = (ix + 1) & DB_HASH_LOCK_MASK; + ix = (ix + 1) & GET_LOCK_MASK(tb->nlocks); if (ix != 0) *lck_ptr = WLOCK_HASH(tb,ix); return ix; } @@ -439,7 +633,7 @@ typedef int ExtraMatchValidatorF(int keypos, Eterm match, Eterm guard, Eterm bod ** Forward decl's (static functions) */ static struct ext_segtab* alloc_ext_segtab(DbTableHash* tb, unsigned seg_ix); -static void alloc_seg(DbTableHash *tb); +static void alloc_seg(DbTableHash *tb, int activate_new_seg); static int free_seg(DbTableHash *tb); static HashDbTerm* next_live(DbTableHash *tb, Uint *iptr, erts_rwmtx_t** lck_ptr, HashDbTerm *list); @@ -532,7 +726,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj, static void db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle); static void* db_eterm_to_dbterm_hash(int compress, int keypos, Eterm obj); -static void* db_dbterm_list_prepend_hash(void* list, void* db_term); +static void* db_dbterm_list_append_hash(void* last_term, void* db_term); static void* db_dbterm_list_remove_first_hash(void** list); static int db_put_dbterm_hash(DbTable* tb, void* obj, @@ -672,7 +866,7 @@ DbTableMethod db_hash = db_lookup_dbterm_hash, db_finalize_dbterm_hash, db_eterm_to_dbterm_hash, - db_dbterm_list_prepend_hash, + db_dbterm_list_append_hash, db_dbterm_list_remove_first_hash, db_put_dbterm_hash, db_free_dbterm_hash, @@ -807,28 +1001,72 @@ int db_create_hash(Process *p, DbTable *tbl) sys_memset(tb->first_segtab[0], 0, SIZEOF_SEGMENT(FIRST_SEGSZ)); erts_atomic_init_nob(&tb->is_resizing, 0); - if (tb->common.type & DB_FINE_LOCKED) { - erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER; - int i; + erts_atomic_init_nob(&tb->lock_array_resize_state, + (erts_aint_t)DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL); + if (!(tb->common.type & DB_FINE_LOCKED)) { + /* + The number of locks needs to be set even if fine grained + locking is not used as this variable is used as increment + when iterating over the table. + */ + tb->nlocks = 1; + tb->locks = NULL; + } + else { + erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER; + int i; + + if (tb->common.type & DB_FINE_LOCKED_AUTO) { + tb->nlocks = LCK_AUTO_DEFAULT_NUMBER_OF_LOCKS; + } + else { + if (tb->nlocks < 1) { + tb->nlocks = DB_HASH_LOCK_CNT; + } + /* + * nlocks needs to be a power of two so we round down to + * nearest power of two + */ + tb->nlocks = 1 << (erts_fit_in_bits_int64(tb->nlocks)-1); + if (tb->nlocks < NLOCKS_WITH_ITEM_COUNTERS) { + tb->nlocks = NLOCKS_WITH_ITEM_COUNTERS; + } + } + + /* + The table needs to be at least as big as the number of locks + so we expand until this properly is satisfied. + */ + while (tb->nlocks > tb->nslots) { + alloc_seg(tb, 1); + } + if (tb->common.type & DB_FREQ_READ) rwmtx_opt.type = ERTS_RWMTX_TYPE_FREQUENT_READ; if (erts_ets_rwmtx_spin_count >= 0) rwmtx_opt.main_spincount = erts_ets_rwmtx_spin_count; - tb->locks = (DbTableHashFineLocks*) erts_db_alloc(ERTS_ALC_T_DB_SEG, /* Other type maybe? */ - (DbTable *) tb, - sizeof(DbTableHashFineLocks)); - for (i=0; ilocks->lck_vec[i].lck_ctr.lck, &rwmtx_opt, + tb->locks = (DbTableHashFineLockSlot*) erts_db_alloc(ERTS_ALC_T_DB_SEG, /* Other type maybe? */ + (DbTable *) tb, + sizeof(DbTableHashFineLockSlot) * tb->nlocks); + for (i=0; inlocks; ++i) { + erts_rwmtx_init_opt( + GET_LOCK(tb,i), &rwmtx_opt, "db_hash_slot", tb->common.the_name, ERTS_LOCK_FLAGS_CATEGORY_DB); - tb->locks->lck_vec[i].lck_ctr.nitems = 0; + ERTS_DB_ALC_MEM_UPDATE_(tb, 0, erts_rwmtx_size(GET_LOCK(tb,i))); + erts_atomic_init_nob(&tb->locks[i].u.lck_ctr.nitems, 0); + tb->locks[i].u.lck_ctr.lck_stat = 0; } - /* This important property is needed to guarantee the two buckets - * involved in a grow/shrink operation it protected by the same lock: - */ - ASSERT(erts_atomic_read_nob(&tb->nactive) % DB_HASH_LOCK_CNT == 0); - } - else { /* coarse locking */ - tb->locks = NULL; + /* + * These properties are needed to guarantee that the buckets + * involved in a grow/shrink operation it protected by the + * same lock: + */ + ASSERT((erts_atomic_read_nob(&tb->szm) + 1) % tb->nlocks == 0); + ASSERT(tb->nlocks <= erts_atomic_read_nob(&tb->nactive)); + ASSERT(erts_atomic_read_nob(&tb->nactive) <= tb->nslots); + ASSERT(tb->nslots <= (erts_atomic_read_nob(&tb->szm) + 1)); + ASSERT(IS_POW2(tb->nlocks)); + ASSERT(IS_POW2(erts_atomic_read_nob(&tb->szm) + 1)); } ERTS_THR_MEMORY_BARRIER; return DB_ERROR_NONE; @@ -1697,7 +1935,8 @@ static int match_traverse_continue(traverse_context_t* ctx, } lck = ctx->on_lock_hash(tb, slot_ix); - if (slot_ix >= NACTIVE(tb)) { /* Is this possible? */ + if (slot_ix >= NACTIVE(tb)) { + /* Is this possible? Yes, for ets:select/1 without safe_fixtable */ ctx->on_unlock_hash(lck); *ret = NIL; ret_value = DB_ERROR_BADPARAM; @@ -2354,9 +2593,14 @@ static Sint get_nitems_from_locks_or_counter(DbTableHash* tb) if (IS_DECENTRALIZED_CTRS(tb)) { int i; Sint total = 0; - for (i=0; i < DB_HASH_LOCK_CNT; ++i) { - total += tb->locks->lck_vec[i].lck_ctr.nitems; + for (i=0; i < NLOCKS_WITH_ITEM_COUNTERS; ++i) { + total += erts_atomic_read_nob(&tb->locks[i].u.lck_ctr.nitems); + } +#ifdef DEBUG + for ( ; i < tb->nlocks; ++i) { + ASSERT(erts_atomic_read_nob(&tb->locks[i].u.lck_ctr.nitems) == 0); } +#endif return total; } else { return erts_flxctr_read_centralized(&tb->common.counters, @@ -2728,7 +2972,7 @@ static SWord db_mark_all_deleted_hash(DbTable *tbl, SWord reds) if (i < NACTIVE(tb)) { /* Yield */ fixdel->slot = i; - fixdel->all = 0; + fixdel->all = 1; fixdel->trap = 1; return -1; } @@ -2837,15 +3081,16 @@ static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds) } if (tb->locks != NULL) { int i; - for (i=0; inlocks; ++i) { + ERTS_DB_ALC_MEM_UPDATE_(tb, erts_rwmtx_size(GET_LOCK(tb,i)), 0); + erts_rwmtx_destroy(GET_LOCK(tb,i)); } erts_db_free(ERTS_ALC_T_DB_SEG, (DbTable *)tb, - (void*)tb->locks, sizeof(DbTableHashFineLocks)); + (void*)tb->locks, tb->nlocks * sizeof(DbTableHashFineLockSlot)); tb->locks = NULL; } ASSERT(erts_flxctr_is_snapshot_ongoing(&tb->common.counters) || - ((sizeof(DbTable) + + ((sizeof(DbTable) + (!DB_LOCK_FREE(tb) ? erts_rwmtx_size(&tb->common.rwlock) : 0) + erts_flxctr_nr_of_allocated_bytes(&tb->common.counters)) == erts_flxctr_read_approx(&tb->common.counters, ERTS_DB_TABLE_MEM_COUNTER_ID))); @@ -3046,7 +3291,7 @@ static void calc_shrink_limit(DbTableHash* tb) */ /* square of z-score 95% confidence */ /* const double z2 = 1.96*1.96; */ - /* Estimated propotion used buckets */ + /* Estimated proportion used buckets */ /* const double p = 0.5; */ /* margin of error */ /* const double moe = 0.1; */ @@ -3058,13 +3303,13 @@ static void calc_shrink_limit(DbTableHash* tb) /* const double d = n*x / (x + n - 1) + 1; */ /* printf("Cochran_formula=%f size=%d mod_with_size=%f\n", x, n, d); */ /* } */ - const int needed_slots = 100 * DB_HASH_LOCK_CNT; + const int needed_slots = 100 * NLOCKS_WITH_ITEM_COUNTERS; if (tb->nslots < needed_slots) { sample_size_is_enough = 0; } } - if (sample_size_is_enough && tb->nslots >= (FIRST_SEGSZ + 2*EXT_SEGSZ)) { + if (sample_size_is_enough && tb->nslots >= MAX(tb->nlocks + EXT_SEGSZ, (FIRST_SEGSZ + 2*EXT_SEGSZ))) { /* * Start shrink when the sample size is big enough for * decentralized counters if decentralized counters are used @@ -3092,7 +3337,7 @@ static void calc_shrink_limit(DbTableHash* tb) /* Extend table with one new segment */ -static void alloc_seg(DbTableHash *tb) +static void alloc_seg(DbTableHash *tb, int activate_buckets) { int seg_ix = SLOT_IX_TO_SEG_IX(tb->nslots); struct segment** segtab; @@ -3117,6 +3362,18 @@ static void alloc_seg(DbTableHash *tb) } #endif tb->nslots += EXT_SEGSZ; + if (activate_buckets) { + erts_aint_t nactive_before = erts_atomic_read_nob(&tb->nactive); + erts_aint_t nactive_now = nactive_before + EXT_SEGSZ; + erts_aint_t floor_2_mult = 1 << (erts_fit_in_bits_int64(nactive_now)-1); + if (floor_2_mult != nactive_now) { + erts_atomic_set_nob(&tb->szm, (floor_2_mult << 1) - 1); + } else { + erts_atomic_set_nob(&tb->szm, floor_2_mult - 1); + } + sys_memset(segtab[seg_ix], 0, SIZEOF_SEGMENT(EXT_SEGSZ)); + erts_atomic_set_nob(&tb->nactive, nactive_now); + } calc_shrink_limit(tb); } @@ -3341,7 +3598,7 @@ static void grow(DbTableHash* tb, int nitems) if (nactive == tb->nslots) { /* Time to get a new segment */ ASSERT(((nactive-FIRST_SEGSZ) & EXT_SEGSZ_MASK) == 0); - alloc_seg(tb); + alloc_seg(tb, 0); } ASSERT(nactive < tb->nslots); @@ -3620,6 +3877,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj, handle->flags = flags; handle->new_size = b->dbterm.size; handle->u.hash.lck_ctr = lck_ctr; + handle->old_tpl = NULL; return 1; } @@ -3751,6 +4009,12 @@ void db_calc_stats_hash(DbTableHash* tb, DbHashStats* stats) int ix; int len; + if (tb->nslots < NACTIVE(tb)) { + ASSERT(ERTS_IS_CRASH_DUMPING); + sys_memzero(stats, sizeof(*stats)); + return; + } + stats->min_chain_len = INT_MAX; stats->max_chain_len = 0; ix = 0; @@ -3771,7 +4035,7 @@ void db_calc_stats_hash(DbTableHash* tb, DbHashStats* stats) stats->avg_chain_len = (float)sum / NACTIVE(tb); stats->std_dev_chain_len = sqrt((sq_sum - stats->avg_chain_len*sum) / NACTIVE(tb)); /* Expected standard deviation from a good uniform hash function, - ie binomial distribution (not taking the linear hashing into acount) */ + ie binomial distribution (not taking the linear hashing into account) */ stats->std_dev_expected = sqrt(stats->avg_chain_len * (1 - 1.0/NACTIVE(tb))); stats->kept_items = kept_items; } @@ -3907,11 +4171,11 @@ static void* db_eterm_to_dbterm_hash(int compress, int keypos, Eterm obj) return term; } -static void* db_dbterm_list_prepend_hash(void* list, void* db_term) +static void* db_dbterm_list_append_hash(void* last_term, void* db_term) { - HashDbTerm* l = list; + HashDbTerm* l = last_term; HashDbTerm* t = db_term; - t->next = l; + l->next = t; return t; } @@ -3963,8 +4227,8 @@ void erts_lcnt_enable_db_hash_lock_count(DbTableHash *tb, int enable) { return; } - for(i = 0; i < DB_HASH_LOCK_CNT; i++) { - erts_lcnt_ref_t *ref = &tb->locks->lck_vec[i].lck_ctr.lck.lcnt; + for (i = 0; i < tb->nlocks; i++) { + erts_lcnt_ref_t *ref = &tb->locks[i].u.lck_ctr.lck.lcnt; if(enable) { erts_lcnt_install_new_lock_info(ref, "db_hash_slot", tb->common.the_name, diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h index 830dc77114be..974715f5d2ea 100644 --- a/erts/emulator/beam/erl_db_hash.h +++ b/erts/emulator/beam/erl_db_hash.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -25,8 +25,11 @@ typedef struct fixed_deletion { UWord slot : sizeof(UWord)*8 - 2; - UWord all : 1; + + /* Used by delete_all_objects: */ + UWord all : 1; /* marks [0 -> slot] */ UWord trap : 1; + struct fixed_deletion *next; } FixedDeletion; @@ -54,20 +57,21 @@ typedef struct hash_db_term { #endif typedef struct DbTableHashLockAndCounter { - Sint nitems; + erts_atomic_t nitems; + Sint lck_stat; erts_rwmtx_t lck; } DbTableHashLockAndCounter; -typedef struct db_table_hash_fine_locks { +typedef struct db_table_hash_fine_lock_slot { union { DbTableHashLockAndCounter lck_ctr; - byte _cache_line_alignment[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_rwmtx_t))]; - }lck_vec[DB_HASH_LOCK_CNT]; -} DbTableHashFineLocks; + byte _cache_line_alignment[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(DbTableHashLockAndCounter))]; + } u; +} DbTableHashFineLockSlot; typedef struct db_table_hash { DbTableCommon common; - + erts_atomic_t lock_array_resize_state; /* szm, nactive, shrink_limit are write-protected by is_resizing or table write lock */ erts_atomic_t szm; /* current size mask. */ erts_atomic_t nactive; /* Number of "active" slots */ @@ -77,16 +81,32 @@ typedef struct db_table_hash { struct segment* first_segtab[1]; /* SMP: nslots and nsegs are protected by is_resizing or table write lock */ + int nlocks; /* Needs to be smaller or equal to nactive */ int nslots; /* Total number of slots */ int nsegs; /* Size of segment table */ /* List of slots where elements have been deleted while table was fixed */ erts_atomic_t fixdel; /* (FixedDeletion*) */ erts_atomic_t is_resizing; /* grow/shrink in progress */ - DbTableHashFineLocks* locks; + DbTableHashFineLockSlot* locks; } DbTableHash; - +typedef enum { + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL = 0, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_GROW = 1, + DB_HASH_LOCK_ARRAY_RESIZE_STATUS_SHRINK = 2 +} db_hash_lock_array_resize_state; + +/* To adapt number of locks if hash table with {write_concurrency, auto} */ +void db_hash_adapt_number_of_locks(DbTable* tb); +#define DB_HASH_ADAPT_NUMBER_OF_LOCKS(TB) \ + do { \ + if (IS_HASH_WITH_AUTO_TABLE(TB->common.type) \ + && (erts_atomic_read_nob(&tb->hash.lock_array_resize_state) \ + != DB_HASH_LOCK_ARRAY_RESIZE_STATUS_NORMAL)) { \ + db_hash_adapt_number_of_locks(tb); \ + } \ + }while(0) /* ** Function prototypes, looks the same (except the suffix) for all ** table types. The process is always an [in out] parameter. diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index a439b974a7a1..31834d413117 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -519,7 +519,7 @@ DbTableMethod db_tree = db_lookup_dbterm_tree, db_finalize_dbterm_tree, db_eterm_to_dbterm_tree_common, - db_dbterm_list_prepend_tree_common, + db_dbterm_list_append_tree_common, db_dbterm_list_remove_first_tree_common, db_put_dbterm_tree, db_free_dbterm_tree_common, @@ -2467,9 +2467,11 @@ static SWord db_free_table_continue_tree(DbTable *tbl, SWord reds) ASSERT(erts_flxctr_is_snapshot_ongoing(&tb->common.counters) || ((APPROX_MEM_CONSUMED(tb) == (sizeof(DbTable) + + (!DB_LOCK_FREE(tb) ? erts_rwmtx_size(&tb->common.rwlock) : 0) + erts_flxctr_nr_of_allocated_bytes(&tb->common.counters))) || (APPROX_MEM_CONSUMED(tb) == (sizeof(DbTable) + + (!DB_LOCK_FREE(tb) ? erts_rwmtx_size(&tb->common.rwlock) : 0) + sizeof(DbFixation) + erts_flxctr_nr_of_allocated_bytes(&tb->common.counters))))); } @@ -3097,7 +3099,7 @@ static TreeDbTerm *find_next(DbTableCommon *tb, TreeDbTerm *root, for (;;) { PUSH_NODE(stack, this); if (( c = cmp_key(tb,key,this) ) > 0) { - if (this->right == NULL) /* We are at the previos + if (this->right == NULL) /* We are at the previous and the element does not exist */ break; @@ -3444,6 +3446,7 @@ int db_lookup_dbterm_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root, handle->flags = flags; handle->bp = (void**) pp; handle->new_size = (*pp)->dbterm.size; + handle->old_tpl = NULL; return 1; } @@ -3531,11 +3534,11 @@ void* db_eterm_to_dbterm_tree_common(int compress, int keypos, Eterm obj) return term; } -void* db_dbterm_list_prepend_tree_common(void *list, void *db_term) +void* db_dbterm_list_append_tree_common(void *last_term, void *db_term) { - TreeDbTerm* l = list; + TreeDbTerm* l = last_term; TreeDbTerm* t = db_term; - t->left = l; + l->left = t; return t; } @@ -4273,7 +4276,7 @@ static void check_slot_pos(DbTableTree *tb) return; t = traverse_until(tb->root, &pos, tb->stack.slot); if (t != tb->stack.array[tb->stack.pos - 1]) { - erts_fprintf(stderr, "Slot position does not correspont with stack, " + erts_fprintf(stderr, "Slot position does not correspond with stack, " "element position %d is really 0x%08X, when stack says " "it's 0x%08X\n", tb->stack.slot, t, tb->stack.array[tb->stack.pos - 1]); diff --git a/erts/emulator/beam/erl_db_tree_util.h b/erts/emulator/beam/erl_db_tree_util.h index 75c82003b2e4..08d55e337315 100644 --- a/erts/emulator/beam/erl_db_tree_util.h +++ b/erts/emulator/beam/erl_db_tree_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -172,7 +172,7 @@ void db_finalize_dbterm_tree_common(int cret, TreeDbTerm **root, DbTableTree *stack_container); void* db_eterm_to_dbterm_tree_common(int compress, int keypos, Eterm obj); -void* db_dbterm_list_prepend_tree_common(void* list, void* db_term); +void* db_dbterm_list_append_tree_common(void* last_term, void* db_term); void* db_dbterm_list_remove_first_tree_common(void **list); int db_put_dbterm_tree_common(DbTableCommon *tb, TreeDbTerm **root, TreeDbTerm *value_to_insert, int key_clash_fail, DbTableTree *stack_container); diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index f77845a5e521..5fe0ba6bf743 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -39,6 +39,7 @@ #include "erl_map.h" #include "erl_thr_progress.h" #include "erl_proc_sig_queue.h" +#include "erl_global_literals.h" #include "erl_db_util.h" @@ -292,7 +293,9 @@ typedef enum { matchSilent, matchSetSeqTokenFake, matchTrace2, - matchTrace3 + matchTrace3, + matchCallerLine, + matchCurrentStacktrace } MatchOps; /* @@ -586,16 +589,34 @@ static DMCGuardBif guard_tab[] = DBIF_ALL }, { - am_is_binary, - &is_binary_1, - 1, - DBIF_ALL + am_is_binary, + &is_binary_1, + 1, + DBIF_ALL }, { - am_is_function, - &is_function_1, - 1, - DBIF_ALL + am_is_bitstring, + &is_bitstring_1, + 1, + DBIF_ALL + }, + { + am_is_boolean, + &is_boolean_1, + 1, + DBIF_ALL + }, + { + am_is_function, + &is_function_1, + 1, + DBIF_ALL + }, + { + am_is_function, + &is_function_2, + 2, + DBIF_ALL }, { am_is_record, @@ -627,6 +648,18 @@ static DMCGuardBif guard_tab[] = 1, DBIF_ALL }, + { + am_max, + &max_2, + 2, + DBIF_ALL + }, + { + am_min, + &min_2, + 2, + DBIF_ALL + }, { am_node, &node_1, @@ -675,6 +708,30 @@ static DMCGuardBif guard_tab[] = 1, DBIF_ALL }, + { + am_byte_size, + &byte_size_1, + 1, + DBIF_ALL + }, + { + am_tuple_size, + &tuple_size_1, + 1, + DBIF_ALL + }, + { + am_binary_part, + &binary_part_2, + 2, + DBIF_ALL + }, + { + am_binary_part, + &binary_part_3, + 3, + DBIF_ALL + }, { am_tl, &tl_1, @@ -688,10 +745,22 @@ static DMCGuardBif guard_tab[] = DBIF_ALL }, { - am_float, - &float_1, - 1, - DBIF_ALL + am_float, + &float_1, + 1, + DBIF_ALL + }, + { + am_ceil, + &ceil_1, + 1, + DBIF_ALL + }, + { + am_floor, + &floor_1, + 1, + DBIF_ALL }, { am_Plus, @@ -1143,14 +1212,18 @@ Binary *db_match_set_compile(Process *p, Eterm matchexpr, if (l2 != NIL) { goto error; } - hp = HAlloc(p, n + 1); - t = make_tuple(hp); - *hp++ = make_arityval((Uint) n); - l2 = tp[1]; - while (n--) { - *hp++ = CAR(list_val(l2)); - l2 = CDR(list_val(l2)); - } + if (n == 0) { + t = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + hp = HAlloc(p, n + 1); + t = make_tuple(hp); + *hp++ = make_arityval((Uint) n); + l2 = tp[1]; + while (n--) { + *hp++ = CAR(list_val(l2)); + l2 = CDR(list_val(l2)); + } + } } matches[i] = t; guards[i] = tp[2]; @@ -1430,14 +1503,18 @@ static Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags) goto done; } - hp = HAlloc(p, n + 1); - t = make_tuple(hp); - *hp++ = make_arityval((Uint) n); - l2 = tp[1]; - while (n--) { - *hp++ = CAR(list_val(l2)); - l2 = CDR(list_val(l2)); - } + if (n == 0) { + t = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + hp = HAlloc(p, n + 1); + t = make_tuple(hp); + *hp++ = make_arityval((Uint) n); + l2 = tp[1]; + while (n--) { + *hp++ = CAR(list_val(l2)); + l2 = CDR(list_val(l2)); + } + } } matches[i] = t; guards[i] = tp[2]; @@ -1902,7 +1979,7 @@ Binary *db_match_compile(Eterm *matchexpr, ** stack ---> + + ** .......... ** +-------------+ - ** The stack is expected to grow towards *higher* adresses. + ** The stack is expected to grow towards *higher* addresses. ** A special case is when the match expression is a single binding ** (i.e '$1'). */ @@ -2014,6 +2091,7 @@ Eterm db_prog_match(Process *c_p, Eterm *esp; MatchVariable* variables; const ErtsCodeMFA *cp; + FunctionInfo fi; const UWord *pc = prog->text; Eterm *ehp; Eterm ret; @@ -2295,13 +2373,18 @@ Eterm db_prog_match(Process *c_p, break; case matchMkTuple: n = *pc++; - ehp = HAllocX(build_proc, n+1, HEAP_XTRA); - t = make_tuple(ehp); - *ehp++ = make_arityval(n); - while (n--) { - *ehp++ = *--esp; - } - *esp++ = t; + if (n == 0) { + t = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + *esp++ = t; + } else { + ehp = HAllocX(build_proc, n+1, HEAP_XTRA); + t = make_tuple(ehp); + *ehp++ = make_arityval(n); + while (n--) { + *ehp++ = *--esp; + } + *esp++ = t; + } break; case matchMkFlatMap: n = *pc++; @@ -2348,9 +2431,13 @@ Eterm db_prog_match(Process *c_p, erts_factory_proc_init(&factory, build_proc); /* build flat structure */ - hp = erts_produce_heap(&factory, 3 + 1 + (2 * n), 0); - keys = make_tuple(hp); - *hp++ = make_arityval(n); + hp = erts_produce_heap(&factory, 3 + (n==0 ? 0 : 1) + (2 * n), 0); + if (n == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + keys = make_tuple(hp); + *hp++ = make_arityval(n); + } ks = hp; hp += n; mp = (flatmap_t*)hp; @@ -2364,6 +2451,7 @@ Eterm db_prog_match(Process *c_p, hashmap_iterator_init(&wstack, t, 0); while ((kv=hashmap_iterator_next(&wstack)) != NULL) { + ASSERT(n != 0); *ks++ = CAR(kv); *vs++ = CDR(kv); } @@ -2456,7 +2544,8 @@ Eterm db_prog_match(Process *c_p, top = HAllocX(build_proc, sz, HEAP_XTRA); if (in_flags & ERTS_PAM_CONTIGUOUS_TUPLE) { ASSERT(is_tuple(term)); - *esp++ = copy_shallow(tuple_val(term), sz, &top, &MSO(build_proc)); + *esp++ = make_tuple(copy_shallow(tuple_val(term), sz, &top, + &MSO(build_proc))); } else { *esp++ = copy_struct(term, sz, &top, &MSO(build_proc)); @@ -2689,7 +2778,16 @@ Eterm db_prog_match(Process *c_p, break; case matchCaller: ASSERT(c_p == self); - t = c_p->stop[0]; + + /* Note that we can't use `erts_inspect_frame` here as the top of + * the stack could point at something other than a frame. */ + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + t = c_p->stop[0]; + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + t = c_p->stop[1]; + } + if (is_not_CP(t)) { *esp++ = am_undefined; } else if (!(cp = erts_find_function_from_pc(cp_val(t)))) { @@ -2703,6 +2801,105 @@ Eterm db_prog_match(Process *c_p, ehp[3] = make_small((Uint) cp->arity); } break; + case matchCallerLine: + ASSERT(c_p == self); + + /* Note that we can't use `erts_inspect_frame` here as the top of + * the stack could point at something other than a frame. */ + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + t = c_p->stop[0]; + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + t = c_p->stop[1]; + } + + if (is_not_CP(t)) { + *esp++ = am_undefined; + break; + } + + erts_lookup_function_info(&fi, cp_val(t), 1); + if (!fi.mfa) { + *esp++ = am_undefined; + } else { + if (fi.loc == LINE_INVALID_LOCATION) { + ehp = HAllocX(build_proc, 5, HEAP_XTRA); + } else { + ehp = HAllocX(build_proc, 8, HEAP_XTRA); + } + *esp++ = make_tuple(ehp); + ehp[0] = make_arityval(4); + ehp[1] = fi.mfa->module; + ehp[2] = fi.mfa->function; + ehp[3] = make_small((Uint) fi.mfa->arity); + if (fi.loc == LINE_INVALID_LOCATION) { + ehp[4] = am_undefined; + } else { + ehp[4] = make_tuple(&ehp[5]); + ehp[5] = make_arityval(2); + ehp[6] = fi.fname_ptr[LOC_FILE(fi.loc)]; + ehp[7] = make_small(LOC_LINE(fi.loc)); + } + } + break; + case matchCurrentStacktrace: { + Uint sz; + Uint heap_size; + Eterm mfa; + Eterm res; + struct StackTrace *s; + int depth; + FunctionInfo* stk; + FunctionInfo* stkp; + + ASSERT(c_p == self); + + depth = unsigned_val(esp[-1]); + esp--; + + sz = offsetof(struct StackTrace, trace) + sizeof(ErtsCodePtr) * depth; + s = (struct StackTrace *) erts_alloc(ERTS_ALC_T_TMP, sz); + s->depth = 0; + s->pc = NULL; + + erts_save_stacktrace(c_p, s, depth); + + depth = s->depth; + stk = stkp = (FunctionInfo *) erts_alloc(ERTS_ALC_T_TMP, + depth*sizeof(FunctionInfo)); + + heap_size = 0; + for (i = 0; i < depth; i++) { + erts_lookup_function_info(stkp, s->trace[i], 1); + if (stkp->mfa) { + heap_size += stkp->needed + 2; + stkp++; + } + } + + res = NIL; + + if (heap_size > 0) { + int count = stkp - stk; + + ASSERT(count > 0 && count <= MAX_BACKTRACE_SIZE); + + ehp = HAllocX(build_proc, heap_size, HEAP_XTRA); + + for (i = count - 1; i >= 0; i--) { + ehp = erts_build_mfa_item(&stk[i], ehp, am_true, &mfa, NIL); + res = CONS(ehp, mfa, res); + ehp += 2; + } + } + + *esp++ = res; + + erts_free(ERTS_ALC_T_TMP, stk); + erts_free(ERTS_ALC_T_TMP, s); + + break; + } case matchSilent: ASSERT(c_p == self); --esp; @@ -3036,9 +3233,27 @@ void db_do_update_element(DbUpdateHandle* handle, handle->new_size = handle->new_size - oldval_sz + newval_sz; - /* write new value in old dbterm, finalize will make a flat copy */ + /* + * Write new value in old dbterm, finalize will make a flat copy. + */ + if (!(handle->flags & DB_MUST_RESIZE)) { + const size_t nbytes = (arityval(handle->dbterm->tpl[0]) + 1) * sizeof(Eterm); + /* + * First time here. Save the original tuple array in order to make + * fast size calculations of untouched elements. + */ + ASSERT(!handle->tb->common.compress); + ASSERT(!handle->old_tpl); + if (nbytes > sizeof(handle->old_tpl_dflt)) { + handle->old_tpl = erts_alloc(ERTS_ALC_T_TMP, nbytes); + } else { + handle->old_tpl = handle->old_tpl_dflt; + } + sys_memcpy(handle->old_tpl, handle->dbterm->tpl, nbytes); + handle->flags |= DB_MUST_RESIZE; + } + ASSERT(!!handle->old_tpl != !!handle->tb->common.compress); handle->dbterm->tpl[position] = newval; - handle->flags |= DB_MUST_RESIZE; } static ERTS_INLINE byte* db_realloc_term(DbTableCommon* tb, void* old, @@ -3192,6 +3407,38 @@ static void* copy_to_comp(int keypos, Eterm obj, DbTerm* dest, return top.cp; } +static ERTS_INLINE +Eterm copy_ets_element(Eterm obj, int sz, Eterm **hpp, ErlOffHeap *off_heap) +{ +#ifdef DEBUG + const Eterm* const hp_start = *hpp; +#endif + Eterm copy; + + if (sz == 0) { + ASSERT(is_immed(obj) || obj == ERTS_GLOBAL_LIT_EMPTY_TUPLE); + return obj; + } + ASSERT(is_not_immed(obj)); + + if (is_list(obj) && is_immed(CAR(list_val(obj)))) { + /* copy_struct() would put this last, + but we need the top term to be first in block */ + Eterm* src = list_val(obj); + Eterm* dst = *hpp; + + CAR(dst) = CAR(src); + *hpp += 2; + CDR(dst) = copy_struct(CDR(src), sz-2, hpp, off_heap); + copy = make_list(dst); + } + else { + copy = copy_struct(obj, sz, hpp, off_heap); + } + ASSERT(ptr_val(copy) == hp_start); + return copy; +} + /* ** Copy the object into a possibly new DbTerm, ** offset is the offset of the DbTerm from the start @@ -3204,8 +3451,24 @@ void* db_store_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj) byte* basep; DbTerm* newp; Eterm* top; - int size = size_object(obj); + Eterm* source_ptr; + Eterm* dest_ptr; + int arity, i, size; ErlOffHeap tmp_offheap; + Uint elem_sizes_dflt[8]; + Uint* elem_sizes = elem_sizes_dflt; + + /* Calculate sizes of all elements and total size */ + source_ptr = tuple_val(obj); + arity = arityval(*source_ptr); + if (arity > sizeof(elem_sizes_dflt) / sizeof(elem_sizes_dflt[0])) { + elem_sizes = erts_alloc(ERTS_ALC_T_TMP, arity * sizeof(*elem_sizes)); + } + size = arity + 1; + for (i = 0; i < arity; i++) { + elem_sizes[i] = size_object(source_ptr[i+1]); + size += elem_sizes[i]; + } if (old != 0) { basep = ((byte*) old) - offset; @@ -3228,14 +3491,26 @@ void* db_store_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj) (offset + sizeof(DbTerm) + sizeof(Eterm)*(size-1))); newp = (DbTerm*) (basep + offset); } + + /* + * Do the actual copy. Lay out elements in order after the top tuple. + * This is relied upon by db_copy_element_from_ets. + */ newp->size = size; top = newp->tpl; - tmp_offheap.first = NULL; - copy_struct(obj, size, &top, &tmp_offheap); + tmp_offheap.first = NULL; + *top++ = *source_ptr++; // copy the header + dest_ptr = top + arity; + for (i = 0; i < arity; ++i) { + *top++ = copy_ets_element(source_ptr[i], elem_sizes[i], &dest_ptr, + &tmp_offheap); + } newp->first_oh = tmp_offheap.first; #ifdef DEBUG_CLONE newp->debug_clone = NULL; #endif + if (elem_sizes != elem_sizes_dflt) + erts_free(ERTS_ALC_T_TMP, elem_sizes); return basep; } @@ -3278,6 +3553,7 @@ void* db_store_term_comp(DbTableCommon *tb, /* May be NULL */ return basep; } +static Uint db_element_size(DbTerm *obj, Eterm* tpl, Uint pos); void db_finalize_resize(DbUpdateHandle* handle, Uint offset) { @@ -3290,6 +3566,8 @@ void db_finalize_resize(DbUpdateHandle* handle, Uint offset) byte* newp = erts_db_alloc(ERTS_ALC_T_DB_TERM, tbl, alloc_sz); byte* oldp = *(handle->bp); + ASSERT(handle->flags & DB_MUST_RESIZE); + sys_memcpy(newp, oldp, offset); /* copy only hash/tree header */ *(handle->bp) = newp; newDbTerm = (DbTerm*) (newp + offset); @@ -3307,16 +3585,36 @@ void db_finalize_resize(DbUpdateHandle* handle, Uint offset) } else { ErlOffHeap tmp_offheap; - Eterm* tpl = handle->dbterm->tpl; - Eterm* top = newDbTerm->tpl; + DbTerm* src = handle->dbterm; + const Uint arity = arityval(src->tpl[0]); + Eterm* top = &newDbTerm->tpl[arity+1]; + int i; + + ASSERT(handle->old_tpl); tmp_offheap.first = NULL; + newDbTerm->tpl[0] = src->tpl[0]; + for (i = 1; i <= arity; ++i) { + Uint sz; + if (is_immed(src->tpl[i])) { + newDbTerm->tpl[i] = src->tpl[i]; + } + else { + if (src->tpl[i] != handle->old_tpl[i]) { + sz = size_object(src->tpl[i]); + } + else { + sz = db_element_size(src, handle->old_tpl, i); + } + newDbTerm->tpl[i] = copy_ets_element(src->tpl[i], sz, &top, + &tmp_offheap); + } + } + ASSERT((byte*)top == (newp + alloc_sz)); + newDbTerm->first_oh = tmp_offheap.first; - { - copy_struct(make_tuple(tpl), handle->new_size, &top, &tmp_offheap); - newDbTerm->first_oh = tmp_offheap.first; - ASSERT((byte*)top == (newp + alloc_sz)); - } + if (handle->old_tpl != handle->old_tpl_dflt) + erts_free(ERTS_ALC_T_TMP, handle->old_tpl); } } @@ -3357,70 +3655,116 @@ Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp, return make_tuple(hp); } -Eterm db_copy_element_from_ets(DbTableCommon* tb, Process* p, - DbTerm* obj, Uint pos, - Eterm** hpp, Uint extra) -{ +Eterm db_copy_element_from_ets(DbTableCommon *tb, Process *p, DbTerm *obj, + Uint pos, Eterm **hpp, Uint extra) { if (is_immed(obj->tpl[pos])) { - *hpp = HAlloc(p, extra); - return obj->tpl[pos]; - } - if (tb->compress && pos != tb->keypos) { - byte* ext = elem2ext(obj->tpl, pos); - Sint sz = erts_decode_ext_size_ets(ext, db_alloced_size_comp(obj)) + extra; - Eterm copy; - ErtsHeapFactory factory; - - erts_factory_proc_prealloc_init(&factory, p, sz); - copy = erts_decode_ext_ets(&factory, ext); - *hpp = erts_produce_heap(&factory, extra, 0); - erts_factory_close(&factory); + *hpp = HAlloc(p, extra); + return obj->tpl[pos]; + } + if (tb->compress) { + if (pos == tb->keypos) { + Uint sz = size_object(obj->tpl[pos]); + *hpp = HAlloc(p, sz + extra); + return copy_struct(obj->tpl[pos], sz, hpp, &MSO(p)); + } + else { + byte *ext = elem2ext(obj->tpl, pos); + Sint sz = + erts_decode_ext_size_ets(ext, db_alloced_size_comp(obj)) + extra; + Eterm copy; + ErtsHeapFactory factory; + + erts_factory_proc_prealloc_init(&factory, p, sz); + copy = erts_decode_ext_ets(&factory, ext); + *hpp = erts_produce_heap(&factory, extra, 0); + erts_factory_close(&factory); #ifdef DEBUG_CLONE - ASSERT(EQ(copy, obj->debug_clone[pos])); + ASSERT(EQ(copy, obj->debug_clone[pos])); #endif - return copy; - } - else { - Uint sz = size_object(obj->tpl[pos]); - *hpp = HAlloc(p, sz + extra); - return copy_struct(obj->tpl[pos], sz, hpp, &MSO(p)); + return copy; + } + } else { + Uint sz = db_element_size(obj, obj->tpl, pos); + *hpp = HAlloc(p, sz + extra); + return copy_shallow_obj(obj->tpl[pos], sz, hpp, &MSO(p)); } } +/* + * Return the size of an element of an uncompressed ETS record. + * Relies on each element of the ETS record being laid out contiguously, + * and starting with the top term. + */ +static Uint db_element_size(DbTerm *obj, Eterm* tpl, Uint pos) { + Eterm *start_ptr; + Eterm *end_ptr; + Eterm elem; + Uint arity, i, sz; + + elem = tpl[pos]; + if (is_zero_sized(elem)) + return 0; + + ASSERT(is_boxed(elem) || is_list(elem)); + start_ptr = ptr_val(elem); + ASSERT(!erts_is_literal(elem, start_ptr)); + + arity = arityval(tpl[0]); + for (i = pos + 1; i <= arity; ++i) { + elem = tpl[i]; + if (!is_zero_sized(elem)) { + ASSERT(is_boxed(elem) || is_list(elem)); + end_ptr = ptr_val(elem); + ASSERT(!erts_is_literal(elem, end_ptr)); + goto done; + } + } + end_ptr = obj->tpl + obj->size; + +done: + sz = end_ptr - start_ptr; + ASSERT(sz == size_object(tpl[pos])); + return sz; + +} /* Our own "cleanup_offheap" - * as refc-binaries may be unaligned in compressed terms + * as ProcBin and ErtsMRefThing may be unaligned in compressed terms */ void db_cleanup_offheap_comp(DbTerm* obj) { union erl_off_heap_ptr u; - struct erts_tmp_aligned_offheap tmp; + union erts_tmp_aligned_offheap tmp; for (u.hdr = obj->first_oh; u.hdr; u.hdr = u.hdr->next) { erts_align_offheap(&u, &tmp); - switch (thing_subtag(u.hdr->thing_word)) { - case REFC_BINARY_SUBTAG: + switch (thing_subtag(u.hdr->thing_word)) { + case REFC_BINARY_SUBTAG: erts_bin_release(u.pb->val); - break; - case FUN_SUBTAG: - if (erts_refc_dectest(&u.fun->fe->refc, 0) == 0) { - erts_erase_fun_entry(u.fun->fe); - } - break; - case REF_SUBTAG: - ASSERT(is_magic_ref_thing(u.hdr)); + break; + case FUN_SUBTAG: + /* We _KNOW_ that this is a local fun, otherwise it would not + * be part of the off-heap list. */ + ASSERT(is_local_fun(u.fun)); + if (erts_refc_dectest(&u.fun->entry.fun->refc, 0) == 0) { + erts_erase_fun_entry(u.fun->entry.fun); + } + break; + case REF_SUBTAG: + ASSERT(is_magic_ref_thing(u.hdr)); erts_bin_release((Binary *)u.mref->mb); - break; - default: - ASSERT(is_external_header(u.hdr->thing_word)); - erts_deref_node_entry(u.ext->node, make_boxed(u.ep)); - break; - } + break; + default: + ASSERT(is_external_header(u.hdr->thing_word)); + erts_deref_node_entry(u.ext->node, make_boxed(u.ep)); + break; + } } + #ifdef DEBUG_CLONE if (obj->debug_clone != NULL) { - erts_free(ERTS_ALC_T_DB_TERM, obj->debug_clone); - obj->debug_clone = NULL; + erts_free(ERTS_ALC_T_DB_TERM, obj->debug_clone); + obj->debug_clone = NULL; } #endif } @@ -3795,9 +4139,9 @@ static void do_emit_constant(DMCContext *context, DMC_STACK_TYPE(UWord) *text, context->save = emb; } else { - /* must be {const, Immed} */ + /* must be {const, Immed} or the empty tuple*/ ASSERT(is_tuple_arity(t,2) && tuple_val(t)[1] == am_const); - ASSERT(is_immed(tuple_val(t)[2])); + ASSERT(is_tuple_arity(tuple_val(t)[2],0) || is_immed(tuple_val(t)[2])); tmp = tuple_val(t)[2]; } } @@ -4891,8 +5235,81 @@ static DMCRet dmc_caller(DMCContext *context, return retOk; } +static DMCRet dmc_caller_line(DMCContext *context, + DMCHeap *heap, + DMC_STACK_TYPE(UWord) *text, + Eterm t, + int *constant) +{ + Eterm *p = tuple_val(t); + DMCRet ret; + + if (!check_trace("caller_line", context, constant, + (DCOMP_CALL_TRACE|DCOMP_ALLOW_TRACE_OPS), 0, &ret)) + return ret; + + if (p[0] != make_arityval(1)) { + RETURN_TERM_ERROR("Special form 'caller_line' called with " + "arguments in %T.", t, context, *constant); + } + *constant = 0; + DMC_PUSH(*text, matchCallerLine); /* Creates binary */ + if (++context->stack_used > context->stack_need) + context->stack_need = context->stack_used; + return retOk; +} + +static DMCRet dmc_current_stacktrace(DMCContext *context, + DMCHeap *heap, + DMC_STACK_TYPE(UWord) *text, + Eterm t, + int *constant) +{ + Eterm *p = tuple_val(t); + Uint a = arityval(*p); + DMCRet ret; + int depth; + + if (!check_trace("current_stacktrace", context, constant, + (DCOMP_CALL_TRACE|DCOMP_ALLOW_TRACE_OPS), 0, &ret)) + return ret; + + switch (a) { + case 1: + *constant = 0; + do_emit_constant(context, text, make_small(erts_backtrace_depth)); + DMC_PUSH(*text, matchCurrentStacktrace); + break; + case 2: + *constant = 0; + + if (!is_small(p[2])) { + RETURN_ERROR("Special form 'current_stacktrace' called with non " + "small argument.", context, *constant); + } + + depth = signed_val(p[2]); + + if (depth < 0) { + RETURN_ERROR("Special form 'current_stacktrace' called with " + "negative integer argument.", context, *constant); + } + + if (depth > erts_backtrace_depth) { + p[2] = make_small(erts_backtrace_depth); + } + + do_emit_constant(context, text, p[2]); + DMC_PUSH(*text, matchCurrentStacktrace); + break; + default: + RETURN_TERM_ERROR("Special form 'current_stacktrace' called with wrong " + "number of arguments in %T.", t, context, + *constant); + } + return retOk; +} - static DMCRet dmc_silent(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text, @@ -4978,7 +5395,11 @@ static DMCRet dmc_fun(DMCContext *context, case am_trace: return dmc_trace(context, heap, text, t, constant); case am_caller: - return dmc_caller(context, heap, text, t, constant); + return dmc_caller(context, heap, text, t, constant); + case am_caller_line: + return dmc_caller_line(context, heap, text, t, constant); + case am_current_stacktrace: + return dmc_current_stacktrace(context, heap, text, t, constant); case am_silent: return dmc_silent(context, heap, text, t, constant); case am_set_tcw: @@ -5415,13 +5836,17 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap, erts_exit(ERTS_ERROR_EXIT, "Trying to constant-copy non constant expression " "0x%bex in (d)ets:match compilation.", t); } - savep = *hp; - ret = make_tuple(savep); n = arityval(tpl[0]); - *hp += n + 1; - *savep++ = tpl[0]; - for(i = 1; i <= n; ++i) - *savep++ = my_copy_struct(tpl[i], hp, off_heap, 0); + if (n == 0) { + ret = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + savep = *hp; + ret = make_tuple(savep); + *hp += n + 1; + *savep++ = tpl[0]; + for(i = 1; i <= n; ++i) + *savep++ = my_copy_struct(tpl[i], hp, off_heap, 0); + } } else if (is_map(t)) { if (is_flatmap(t)) { @@ -5433,15 +5858,18 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap, mp = (flatmap_t*)flatmap_val(t); /* Copy keys */ - savep = *hp; - keys = make_tuple(savep); - p = tuple_val(mp->keys); + p = tuple_val(mp->keys); n = arityval(p[0]); - *hp += n + 1; - *savep++ = make_arityval(n); - for(i = 1; i <= n; ++i) - *savep++ = my_copy_struct(p[i], hp, off_heap, 0); - + if (n == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + savep = *hp; + keys = make_tuple(savep); + *hp += n + 1; + *savep++ = make_arityval(n); + for(i = 1; i <= n; ++i) + *savep++ = my_copy_struct(p[i], hp, off_heap, 0); + } savep = *hp; ret = make_flatmap(savep); n = flatmap_get_size(mp); @@ -6051,6 +6479,14 @@ void db_match_dis(Binary *bp) ++t; erts_printf("Caller\n"); break; + case matchCallerLine: + ++t; + erts_printf("CallerLine\n"); + break; + case matchCurrentStacktrace: + ++t; + erts_printf("CurrentStacktrace\n"); + break; default: erts_printf("??? (0x%bpx)\n", *t); ++t; diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 6ed1e151049e..12e0228d6a6a 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2021. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -101,6 +101,12 @@ typedef struct { int current_level; } catree; } u; + Eterm* old_tpl; +#ifdef DEBUG + Eterm old_tpl_dflt[2]; +#else + Eterm old_tpl_dflt[8]; +#endif } DbUpdateHandle; /* How safe are we from double-hits or missed objects @@ -237,7 +243,7 @@ typedef struct db_table_method ** not DB_ERROR_NONE, the object is removed from the table. */ void (*db_finalize_dbterm)(int cret, DbUpdateHandle* handle); void* (*db_eterm_to_dbterm)(int compress, int keypos, Eterm obj); - void* (*db_dbterm_list_prepend)(void* list, void* db_term); + void* (*db_dbterm_list_append)(void* last_term, void* db_term); void* (*db_dbterm_list_remove_first)(void** list); int (*db_put_dbterm)(DbTable* tb, /* [in out] */ void* obj, @@ -302,7 +308,7 @@ typedef struct db_table_common { UWord heir_data; /* To send in ETS-TRANSFER (is_immed or (DbTerm*) */ Uint64 heir_started_interval; /* To further identify the heir */ Eterm the_name; /* an atom */ - Binary *btid; + Binary *btid; /* table magic ref, read only after creation */ DbTableMethod* meth; /* table methods */ /* The ErtsFlxCtr below contains: * - Total number of items in table @@ -321,11 +327,7 @@ typedef struct db_table_common { int compress; /* For unfinished operations that needs to be helped */ - void (*continuation)(long *reds_ptr, - void** state, - void* extra_context); /* To help yielded process */ - erts_atomic_t continuation_state; - Binary* continuation_res_bin; + struct ets_insert_2_list_info* continuation_ctx; #ifdef ETS_DBG_FORCE_TRAP int dbg_force_trap; /* force trap on table lookup */ #endif @@ -345,12 +347,17 @@ typedef struct db_table_common { #define DB_FREQ_READ (1 << 10) /* read_concurrency */ #define DB_NAMED_TABLE (1 << 11) #define DB_BUSY (1 << 12) +#define DB_EXPLICIT_LOCK_GRANULARITY (1 << 13) +#define DB_FINE_LOCKED_AUTO (1 << 14) #define DB_CATREE_FORCE_SPLIT (1 << 31) /* erts_debug */ #define DB_CATREE_DEBUG_RANDOM_SPLIT_JOIN (1 << 30) /* erts_debug */ -#define IS_HASH_TABLE(Status) (!!((Status) & \ - (DB_BAG | DB_SET | DB_DUPLICATE_BAG))) +#define IS_HASH_TABLE(Status) (!!((Status) & \ + (DB_BAG | DB_SET | DB_DUPLICATE_BAG))) +#define IS_HASH_WITH_AUTO_TABLE(Status) \ + (((Status) & \ + (DB_ORDERED_SET | DB_CA_ORDERED_SET | DB_FINE_LOCKED_AUTO)) == DB_FINE_LOCKED_AUTO) #define IS_TREE_TABLE(Status) (!!((Status) & \ DB_ORDERED_SET)) #define IS_CATREE_TABLE(Status) (!!((Status) & \ @@ -399,10 +406,10 @@ ERTS_GLB_INLINE Eterm db_copy_object_from_ets(DbTableCommon* tb, DbTerm* bp, Eterm** hpp, ErlOffHeap* off_heap) { if (tb->compress) { - return db_copy_from_comp(tb, bp, hpp, off_heap); + return db_copy_from_comp(tb, bp, hpp, off_heap); } else { - return copy_shallow(bp->tpl, bp->size, hpp, off_heap); + return make_tuple(copy_shallow(bp->tpl, bp->size, hpp, off_heap)); } } @@ -516,7 +523,7 @@ typedef struct dmc_err_info { ** Compilation flags ** ** The dialect is in the 3 least significant bits and are to be interspaced by -** by at least 2 (decimal), thats why ((Uint) 2) isn't used. This is to be +** by at least 2 (decimal), that's why ((Uint) 2) isn't used. This is to be ** able to add DBIF_GUARD or DBIF BODY to it to use in the match_spec bif ** table. The rest of the word is used like ordinary flags, one bit for each ** flag. Note that DCOMP_TABLE and DCOMP_TRACE are mutually exclusive. @@ -570,14 +577,15 @@ ERTS_GLB_INLINE Binary *erts_db_get_match_prog_binary_unchecked(Eterm term); /** @brief Ensure off-heap header is word aligned, make a temporary copy if * not. Needed when inspecting ETS off-heap lists that may contain unaligned - * ProcBins if table is 'compressed'. + * ProcBin and ErtsMRefThing if table is 'compressed'. */ -struct erts_tmp_aligned_offheap +union erts_tmp_aligned_offheap { ProcBin proc_bin; + ErtsMRefThing mref_thing; }; ERTS_GLB_INLINE void erts_align_offheap(union erl_off_heap_ptr*, - struct erts_tmp_aligned_offheap* tmp); + union erts_tmp_aligned_offheap* tmp); #if ERTS_GLB_INLINE_INCL_FUNC_DEF @@ -613,20 +621,27 @@ erts_db_get_match_prog_binary(Eterm term) ERTS_GLB_INLINE void erts_align_offheap(union erl_off_heap_ptr* ohp, - struct erts_tmp_aligned_offheap* tmp) + union erts_tmp_aligned_offheap* tmp) { if ((UWord)ohp->voidp % sizeof(UWord) != 0) { /* - * ETS store word unaligned ProcBins in its compressed format. - * Make a temporary aligned copy. + * ETS store word unaligned ProcBin and ErtsMRefThing in its compressed + * format. Make a temporary aligned copy. * * Warning, must pass (void*)-variable to memcpy. Otherwise it will * cause Bus error on Sparc due to false compile time assumptions * about word aligned memory (type cast is not enough). */ - sys_memcpy(tmp, ohp->voidp, sizeof(*tmp)); - ASSERT(tmp->proc_bin.thing_word == HEADER_PROC_BIN); - ohp->pb = &tmp->proc_bin; + sys_memcpy(tmp, ohp->voidp, sizeof(Eterm)); /* thing_word */ + if (tmp->proc_bin.thing_word == HEADER_PROC_BIN) { + sys_memcpy(tmp, ohp->voidp, sizeof(tmp->proc_bin)); + ohp->pb = &tmp->proc_bin; + } + else { + sys_memcpy(tmp, ohp->voidp, sizeof(tmp->mref_thing)); + ASSERT(is_magic_ref_thing(&tmp->mref_thing)); + ohp->mref = &tmp->mref_thing; + } } } diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c index 0f4843561269..487042932fac 100644 --- a/erts/emulator/beam/erl_debug.c +++ b/erts/emulator/beam/erl_debug.c @@ -469,7 +469,7 @@ void print_untagged_memory(Eterm *pos, Eterm *end) * is). This function knows about forwarding pointers to be able to * print a heap during garbage collection. erts_printf("%T",val) * do not know about forwarding pointers though, so it will still - * crash if they are encoutered... + * crash if they are encountered... */ void print_tagged_memory(Eterm *pos, Eterm *end) { diff --git a/erts/emulator/beam/erl_dirty_bif.tab b/erts/emulator/beam/erl_dirty_bif.tab index 3f16f3e0f330..6e4dbfb30f6e 100644 --- a/erts/emulator/beam/erl_dirty_bif.tab +++ b/erts/emulator/beam/erl_dirty_bif.tab @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2016-2020. All Rights Reserved. +# Copyright Ericsson AB 2016-2023. 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. @@ -50,6 +50,7 @@ dirty-io erts_debug:dirty_io/2 dirty-cpu erts_debug:lcnt_control/2 dirty-cpu erts_debug:lcnt_collect/0 dirty-cpu erts_debug:lcnt_clear/0 +dirty-cpu erlang:display_string/2 # --- TEST of Dirty BIF functionality --- # Functions below will execute on dirty schedulers when emulator has diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index d5379a40d53f..69f586254541 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2017. All Rights Reserved. + * Copyright Ericsson AB 1999-2022. 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. @@ -404,19 +404,23 @@ EXTERN int get_port_flags(ErlDrvPort port); * since the binary is a shared object it MUST be written once. */ -EXTERN ErlDrvBinary* driver_alloc_binary(ErlDrvSizeT size); -EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size); EXTERN void driver_free_binary(ErlDrvBinary *bin); +EXTERN ErlDrvBinary* driver_alloc_binary(ErlDrvSizeT size) + ERL_NAPI_ATTR_MALLOC_UD(driver_free_binary,1); +EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size) + ERL_NAPI_ATTR_WUR; -/* Referenc count on driver binaries */ +/* Reference count on driver binaries */ EXTERN ErlDrvSInt driver_binary_get_refc(ErlDrvBinary *dbp); EXTERN ErlDrvSInt driver_binary_inc_refc(ErlDrvBinary *dbp); EXTERN ErlDrvSInt driver_binary_dec_refc(ErlDrvBinary *dbp); /* Allocation interface */ -EXTERN void *driver_alloc(ErlDrvSizeT size); -EXTERN void *driver_realloc(void *ptr, ErlDrvSizeT size); EXTERN void driver_free(void *ptr); +EXTERN void *driver_alloc(ErlDrvSizeT size) + ERL_NAPI_ATTR_MALLOC_USD(1, driver_free, 1); +EXTERN void *driver_realloc(void *ptr, ErlDrvSizeT size) + ERL_NAPI_ATTR_ALLOC_SIZE(2); /* Queue interface */ EXTERN int driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len); @@ -448,18 +452,18 @@ EXTERN void driver_system_info(ErlDrvSysInfo *sip, size_t si_size); * erl driver thread functions. */ -EXTERN ErlDrvMutex *erl_drv_mutex_create(char *name); EXTERN void erl_drv_mutex_destroy(ErlDrvMutex *mtx); +EXTERN ErlDrvMutex *erl_drv_mutex_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_mutex_destroy,1); EXTERN int erl_drv_mutex_trylock(ErlDrvMutex *mtx); EXTERN void erl_drv_mutex_lock(ErlDrvMutex *mtx); EXTERN void erl_drv_mutex_unlock(ErlDrvMutex *mtx); -EXTERN ErlDrvCond *erl_drv_cond_create(char *name); EXTERN void erl_drv_cond_destroy(ErlDrvCond *cnd); +EXTERN ErlDrvCond *erl_drv_cond_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_cond_destroy,1); EXTERN void erl_drv_cond_signal(ErlDrvCond *cnd); EXTERN void erl_drv_cond_broadcast(ErlDrvCond *cnd); EXTERN void erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx); -EXTERN ErlDrvRWLock *erl_drv_rwlock_create(char *name); EXTERN void erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck); +EXTERN ErlDrvRWLock *erl_drv_rwlock_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_rwlock_destroy,1); EXTERN int erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck); EXTERN void erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck); EXTERN void erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck); @@ -470,8 +474,8 @@ EXTERN int erl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key); EXTERN void erl_drv_tsd_key_destroy(ErlDrvTSDKey key); EXTERN void erl_drv_tsd_set(ErlDrvTSDKey key, void *data); EXTERN void *erl_drv_tsd_get(ErlDrvTSDKey key); -EXTERN ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name); EXTERN void erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts); +EXTERN ErlDrvThreadOpts *erl_drv_thread_opts_create(char *name) ERL_NAPI_ATTR_MALLOC_D(erl_drv_thread_opts_destroy,1); EXTERN int erl_drv_thread_create(char *name, ErlDrvTid *tid, void * (*func)(void *), diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h index 53d1a3a5316e..735ffa380caf 100644 --- a/erts/emulator/beam/erl_drv_nif.h +++ b/erts/emulator/beam/erl_drv_nif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2020. All Rights Reserved. + * Copyright Ericsson AB 2010-2022. 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. @@ -168,4 +168,58 @@ typedef struct { # endif #endif +#define ERL_NAPI_ATTR_WUR +#define ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS) +#define ERL_NAPI_ATTR_MALLOC_U +#define ERL_NAPI_ATTR_MALLOC_US(SZPOS) +#define ERL_NAPI_ATTR_MALLOC_UD(DTOR, PTRPOS) +#define ERL_NAPI_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) +#define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) + +/* ERL_NAPI_ATTR_MALLOC_xxx: + * U: Returns pointer to Undefined data. ((malloc)) + * S: Has Size argument with nr of bytes of returned data. ((alloc_size(SZPOS))) + * D: Has 1-to-1 Deallocator function with ptr argument. ((malloc(DTOR,PTRPOS))) + */ + +#ifdef __has_attribute +# if __has_attribute(warn_unused_result) +# undef ERL_NAPI_ATTR_WUR +# define ERL_NAPI_ATTR_WUR __attribute__((warn_unused_result)) +# endif +# if __has_attribute(alloc_size) +# undef ERL_NAPI_ATTR_ALLOC_SIZE +# define ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS) \ + __attribute__((alloc_size(SZPOS))) ERL_NAPI_ATTR_WUR +# endif +# if __has_attribute(malloc) +# undef ERL_NAPI_ATTR_MALLOC_U +# define ERL_NAPI_ATTR_MALLOC_U __attribute__((malloc)) ERL_NAPI_ATTR_WUR + +# undef ERL_NAPI_ATTR_MALLOC_US +# define ERL_NAPI_ATTR_MALLOC_US(SZPOS) \ + __attribute__((malloc)) ERL_NAPI_ATTR_ALLOC_SIZE(SZPOS) + +# undef ERL_NAPI_ATTR_MALLOC_D +# if defined(__GNUC__) && __GNUC__ >= 11 +# define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) \ + __attribute__((malloc(DTOR,PTRPOS))) \ + ERL_NAPI_ATTR_WUR +# else +# define ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) \ + ERL_NAPI_ATTR_WUR +# endif + +# undef ERL_NAPI_ATTR_MALLOC_UD +# define ERL_NAPI_ATTR_MALLOC_UD(DTOR, PTRPOS) \ + ERL_NAPI_ATTR_MALLOC_U \ + ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) + +# undef ERL_NAPI_ATTR_MALLOC_USD +# define ERL_NAPI_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) \ + ERL_NAPI_ATTR_MALLOC_US(SZPOS) \ + ERL_NAPI_ATTR_MALLOC_D(DTOR, PTRPOS) +# endif +#endif + #endif /* __ERL_DRV_NIF_H__ */ diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c index 949d89232a74..c8e6b9906b3a 100644 --- a/erts/emulator/beam/erl_drv_thread.c +++ b/erts/emulator/beam/erl_drv_thread.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2020. All Rights Reserved. + * Copyright Ericsson AB 2007-2023. 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. @@ -609,6 +609,7 @@ erl_drv_thread_create(char *name, struct ErlDrvTid_ *dtid; ethr_thr_opts ethr_opts = ETHR_THR_OPTS_DEFAULT_INITER; ethr_thr_opts *use_opts; + char name_buff[ETHR_THR_NAME_MAX + 1]; if (!opts && !name) use_opts = NULL; @@ -616,7 +617,8 @@ erl_drv_thread_create(char *name, if(opts) ethr_opts.suggested_stack_size = opts->suggested_stack_size; - ethr_opts.name = name; + erts_snprintf(name_buff, sizeof(name_buff), "%s", name); + ethr_opts.name = name_buff; use_opts = ðr_opts; } diff --git a/erts/emulator/beam/erl_flxctr.h b/erts/emulator/beam/erl_flxctr.h index df60f3651e10..6109705b4516 100644 --- a/erts/emulator/beam/erl_flxctr.h +++ b/erts/emulator/beam/erl_flxctr.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2019. All Rights Reserved. + * Copyright Ericsson AB 2019-2021. 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. @@ -140,7 +140,7 @@ void erts_flxctr_dec(ErtsFlxCtr* c, * @param c The ErtsFlxCtr instance to operate on * @param counter_nr The number of the counter within c to operate on * - * @return A snapshot of the specifed counter if c is centralized or a + * @return A snapshot of the specified counter if c is centralized or a * possibly incorrect estimate of the counter value if c is * decentralized */ diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c index c9eb42a0bd66..ae6116ec19c3 100644 --- a/erts/emulator/beam/erl_fun.c +++ b/erts/emulator/beam/erl_fun.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2021. All Rights Reserved. + * Copyright Ericsson AB 2000-2022. 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. @@ -27,6 +27,22 @@ #include "global.h" #include "erl_fun.h" #include "hash.h" +#include "beam_common.h" + +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +/* Container structure for fun entries, allowing us to start `ErlFunEntry` with + * a field other than its `HashBucket`. */ +typedef struct erl_fun_entry_container { + /* !! MUST BE THE FIRST FIELD !! */ + HashBucket bucket; + + ErlFunEntry entry; +} ErlFunEntryContainer; static Hash erts_fun_table; @@ -37,18 +53,10 @@ static erts_rwmtx_t erts_fun_table_lock; #define erts_fun_write_lock() erts_rwmtx_rwlock(&erts_fun_table_lock) #define erts_fun_write_unlock() erts_rwmtx_rwunlock(&erts_fun_table_lock) -static HashValue fun_hash(ErlFunEntry* obj); -static int fun_cmp(ErlFunEntry* obj1, ErlFunEntry* obj2); -static ErlFunEntry* fun_alloc(ErlFunEntry* template); -static void fun_free(ErlFunEntry* obj); - -/* - * The address field of every fun that has no loaded code will point - * to unloaded_fun[]. The -1 in unloaded_fun[0] will be interpreted - * as an illegal arity when attempting to call a fun. - */ -static BeamInstr unloaded_fun_code[4] = {NIL, NIL, -1, 0}; -static ErtsCodePtr unloaded_fun = &unloaded_fun_code[3]; +static HashValue fun_hash(ErlFunEntryContainer* obj); +static int fun_cmp(ErlFunEntryContainer* obj1, ErlFunEntryContainer* obj2); +static ErlFunEntryContainer* fun_alloc(ErlFunEntryContainer* template); +static void fun_free(ErlFunEntryContainer* obj); void erts_init_fun_table(void) @@ -76,116 +84,146 @@ void erts_fun_info(fmtfn_t to, void *to_arg) { int lock = !ERTS_IS_CRASH_DUMPING; - if (lock) - erts_fun_read_lock(); + + if (lock) { + erts_fun_read_lock(); + } + hash_info(to, to_arg, &erts_fun_table); - if (lock) - erts_fun_read_unlock(); + + if (lock) { + erts_fun_read_unlock(); + } } int erts_fun_table_sz(void) { int sz; int lock = !ERTS_IS_CRASH_DUMPING; - if (lock) - erts_fun_read_lock(); + + if (lock) { + erts_fun_read_lock(); + } + sz = hash_table_sz(&erts_fun_table); - if (lock) - erts_fun_read_unlock(); + + if (lock) { + erts_fun_read_unlock(); + } + return sz; } ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, - const byte* uniq, int index, int arity) + const byte* uniq, int index, int arity) { - ErlFunEntry template; - ErlFunEntry* fe; + ErlFunEntryContainer template; + ErlFunEntryContainer *fc; + ErlFunEntry *tp; erts_aint_t refc; + tp = &template.entry; + + /* All fields are copied from the template when inserting a new entry. */ ASSERT(is_atom(mod)); - template.old_uniq = old_uniq; - template.index = index; - template.module = mod; + tp->old_index = old_index; + tp->old_uniq = old_uniq; + tp->index = index; + tp->module = mod; + tp->arity = arity; + + sys_memcpy(tp->uniq, uniq, sizeof(tp->uniq)); + erts_fun_write_lock(); - fe = (ErlFunEntry *) hash_put(&erts_fun_table, (void*) &template); - sys_memcpy(fe->uniq, uniq, sizeof(fe->uniq)); - fe->old_index = old_index; - fe->arity = arity; - refc = erts_refc_inctest(&fe->refc, 0); - if (refc < 2) /* New or pending delete */ - erts_refc_inc(&fe->refc, 1); + fc = (ErlFunEntryContainer*)hash_put(&erts_fun_table, (void*)&template); + refc = erts_refc_inctest(&fc->entry.refc, 0); + if (refc < 2) { + /* New or pending delete */ + erts_refc_inc(&fc->entry.refc, 1); + } erts_fun_write_unlock(); - return fe; + + return &fc->entry; } -ErlFunEntry* -erts_get_fun_entry(Eterm mod, int uniq, int index) -{ - ErlFunEntry template; - ErlFunEntry *ret; +const ErtsCodeMFA *erts_get_fun_mfa(const ErlFunEntry *fe, ErtsCodeIndex ix) { + ErtsCodePtr address = fe->dispatch.addresses[ix]; - ASSERT(is_atom(mod)); - template.old_uniq = uniq; - template.index = index; - template.module = mod; - erts_fun_read_lock(); - ret = (ErlFunEntry *) hash_get(&erts_fun_table, (void*) &template); - if (ret) { - erts_aint_t refc = erts_refc_inctest(&ret->refc, 1); - if (refc < 2) /* Pending delete */ - erts_refc_inc(&ret->refc, 1); + if (address != beam_unloaded_fun) { + return erts_find_function_from_pc(address); } - erts_fun_read_unlock(); - return ret; -} -int erts_is_fun_loaded(ErlFunEntry* fe) { - int res = fe->address != unloaded_fun; + return NULL; +} - ASSERT(res == (0 != ((const BeamInstr*)fe->address)[0])); +void erts_set_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix, ErtsCodePtr address) { + /* Fun entries MUST NOT be updated during a purge! */ + ASSERT(fe->pend_purge_address == NULL); + fe->dispatch.addresses[ix] = address; +} - return res; +int erts_is_fun_loaded(const ErlFunEntry* fe, ErtsCodeIndex ix) { + return fe->dispatch.addresses[ix] != beam_unloaded_fun; } static void erts_erase_fun_entry_unlocked(ErlFunEntry* fe) { - hash_erase(&erts_fun_table, (void *) fe); + ErlFunEntryContainer *fc = ErtsContainerStruct(fe, ErlFunEntryContainer, + entry); + + hash_erase(&erts_fun_table, (void *) fc); } void erts_erase_fun_entry(ErlFunEntry* fe) { erts_fun_write_lock(); - /* - * We have to check refc again since someone might have looked up - * the fun entry and incremented refc after last check. - */ - if (erts_refc_dectest(&fe->refc, -1) <= 0) - { - if (fe->address != unloaded_fun) - erts_exit(ERTS_ERROR_EXIT, - "Internal error: " - "Invalid reference count found on #Fun<%T.%d.%d>: " - " About to erase fun still referred by code.\n", - fe->module, fe->old_index, fe->old_uniq); - erts_erase_fun_entry_unlocked(fe); + + /* We have to check refc again since someone might have looked up + * the fun entry and incremented refc after last check. */ + if (erts_refc_dectest(&fe->refc, -1) <= 0) { + ErtsCodeIndex code_ix = erts_active_code_ix(); + + if (erts_is_fun_loaded(fe, code_ix)) { + erts_exit(ERTS_ERROR_EXIT, + "Internal error: " + "Invalid reference count found on #Fun<%T.%d.%d>: " + " About to erase fun still referred by code.\n", + fe->module, fe->old_index, fe->old_uniq); + } + + erts_erase_fun_entry_unlocked(fe); } + erts_fun_write_unlock(); } -static void fun_purge_foreach(ErlFunEntry *fe, struct erl_module_instance* modp) +struct fun_prepare_purge_args { + struct erl_module_instance* modp; + ErtsCodeIndex code_ix; +}; + +static void fun_purge_foreach(ErlFunEntryContainer *fc, + struct fun_prepare_purge_args *args) { - const char *fun_addr, *mod_start; + struct erl_module_instance* modp = args->modp; + ErlFunEntry *fe = &fc->entry; + const char *mod_start; + ErtsCodePtr fun_addr; - fun_addr = (const char*)fe->address; + fun_addr = fe->dispatch.addresses[args->code_ix]; mod_start = (const char*)modp->code_hdr; - if (ErtsInArea(fun_addr, mod_start, modp->code_length)) { - fe->pend_purge_address = fe->address; + if (ErtsInArea((const char*)fun_addr, mod_start, modp->code_length)) { + ASSERT(fe->pend_purge_address == NULL); + + fe->pend_purge_address = fun_addr; ERTS_THR_WRITE_MEMORY_BARRIER; - fe->address = unloaded_fun; + + fe->dispatch.addresses[args->code_ix] = beam_unloaded_fun; + erts_purge_state_add_fun(fe); } } @@ -193,121 +231,262 @@ static void fun_purge_foreach(ErlFunEntry *fe, struct erl_module_instance* modp) void erts_fun_purge_prepare(struct erl_module_instance* modp) { - erts_fun_read_lock(); - hash_foreach(&erts_fun_table, (HFOREACH_FUN)fun_purge_foreach, modp); - erts_fun_read_unlock(); + struct fun_prepare_purge_args args = {modp, erts_active_code_ix()}; + + ERTS_LC_ASSERT(erts_has_code_stage_permission()); + + erts_fun_write_lock(); + hash_foreach(&erts_fun_table, (HFOREACH_FUN)fun_purge_foreach, &args); + erts_fun_write_unlock(); } void erts_fun_purge_abort_prepare(ErlFunEntry **funs, Uint no) { - Uint ix; + ErtsCodeIndex code_ix = erts_active_code_ix(); + Uint fun_ix; - for (ix = 0; ix < no; ix++) { - ErlFunEntry *fe = funs[ix]; + ERTS_LC_ASSERT(erts_has_code_stage_permission()); - if (fe->address == unloaded_fun) { - fe->address = fe->pend_purge_address; - } + for (fun_ix = 0; fun_ix < no; fun_ix++) { + ErlFunEntry *fe = funs[fun_ix]; + + ASSERT(fe->dispatch.addresses[code_ix] == beam_unloaded_fun); + fe->dispatch.addresses[code_ix] = fe->pend_purge_address; } } void erts_fun_purge_abort_finalize(ErlFunEntry **funs, Uint no) { - Uint ix; + IF_DEBUG(ErtsCodeIndex code_ix = erts_active_code_ix();) + Uint fun_ix; - for (ix = 0; ix < no; ix++) { - funs[ix]->pend_purge_address = NULL; + ERTS_LC_ASSERT(erts_has_code_stage_permission()); + + for (fun_ix = 0; fun_ix < no; fun_ix++) { + ErlFunEntry *fe = funs[fun_ix]; + + /* The abort_prepare step should have set the active address to the + * actual one. */ + ASSERT(fe->dispatch.addresses[code_ix] != beam_unloaded_fun); + fe->pend_purge_address = NULL; } } void erts_fun_purge_complete(ErlFunEntry **funs, Uint no) { + IF_DEBUG(ErtsCodeIndex code_ix = erts_active_code_ix();) Uint ix; + ERTS_LC_ASSERT(erts_has_code_stage_permission()); + for (ix = 0; ix < no; ix++) { - ErlFunEntry *fe = funs[ix]; - fe->pend_purge_address = NULL; - if (erts_refc_dectest(&fe->refc, 0) == 0) - erts_erase_fun_entry(fe); + ErlFunEntry *fe = funs[ix]; + + ASSERT(fe->dispatch.addresses[code_ix] == beam_unloaded_fun); + fe->pend_purge_address = NULL; + + if (erts_refc_dectest(&fe->refc, 0) == 0) { + erts_erase_fun_entry(fe); + } } + ERTS_THR_WRITE_MEMORY_BARRIER; } + +ErlFunThing *erts_new_export_fun_thing(Eterm **hpp, Export *exp, int arity) +{ + ErlFunThing *funp; + + funp = (ErlFunThing*)(*hpp); + *hpp += ERL_FUN_SIZE; + + funp->thing_word = HEADER_FUN; + funp->next = NULL; + funp->entry.exp = exp; + funp->num_free = 0; + funp->creator = am_external; + funp->arity = arity; + +#ifdef DEBUG + { + const ErtsCodeMFA *mfa = &exp->info.mfa; + ASSERT(arity == mfa->arity); + } +#endif + + return funp; +} + +ErlFunThing *erts_new_local_fun_thing(Process *p, ErlFunEntry *fe, + int arity, int num_free) +{ + ErlFunThing *funp; + + funp = (ErlFunThing*) p->htop; + p->htop += ERL_FUN_SIZE + num_free; + erts_refc_inc(&fe->refc, 2); + + funp->thing_word = HEADER_FUN; + funp->next = MSO(p).first; + MSO(p).first = (struct erl_off_heap_header*) funp; + funp->entry.fun = fe; + funp->num_free = num_free; + funp->creator = p->common.id; + funp->arity = arity; + +#ifdef DEBUG + { + /* Note that `mfa` may be NULL if the fun is currently being purged. We + * ignore this since it's not an error and we only need `mfa` to + * sanity-check the arity at this point. If the fun is called while in + * this state, the `error_handler` module will take care of it. */ + const ErtsCodeMFA *mfa = erts_get_fun_mfa(fe, erts_active_code_ix()); + ASSERT(!mfa || funp->arity == mfa->arity - num_free); + ASSERT(arity == fe->arity); + } +#endif + + return funp; +} + + struct dump_fun_foreach_args { fmtfn_t to; void *to_arg; + ErtsCodeIndex code_ix; }; static void -dump_fun_foreach(ErlFunEntry *fe, struct dump_fun_foreach_args *args) +dump_fun_foreach(ErlFunEntryContainer *fc, struct dump_fun_foreach_args *args) { + ErlFunEntry *fe = &fc->entry; + erts_print(args->to, args->to_arg, "=fun\n"); erts_print(args->to, args->to_arg, "Module: %T\n", fe->module); erts_print(args->to, args->to_arg, "Uniq: %d\n", fe->old_uniq); erts_print(args->to, args->to_arg, "Index: %d\n",fe->old_index); - erts_print(args->to, args->to_arg, "Address: %p\n", fe->address); - erts_print(args->to, args->to_arg, "Refc: %ld\n", erts_refc_read(&fe->refc, 1)); + erts_print(args->to, args->to_arg, "Address: %p\n", + fe->dispatch.addresses[args->code_ix]); + erts_print(args->to, args->to_arg, "Refc: %ld\n", + erts_refc_read(&fe->refc, 1)); } void erts_dump_fun_entries(fmtfn_t to, void *to_arg) { - struct dump_fun_foreach_args args = {to, to_arg}; + struct dump_fun_foreach_args args = {to, to_arg, erts_active_code_ix()}; int lock = !ERTS_IS_CRASH_DUMPING; - if (lock) - erts_fun_read_lock(); + if (lock) { + erts_fun_read_lock(); + } + hash_foreach(&erts_fun_table, (HFOREACH_FUN)dump_fun_foreach, &args); - if (lock) - erts_fun_read_unlock(); + + if (lock) { + erts_fun_read_unlock(); + } } static HashValue -fun_hash(ErlFunEntry* obj) +fun_hash(ErlFunEntryContainer* obj) { - return (HashValue) (obj->old_uniq ^ obj->index ^ atom_val(obj->module)); + ErlFunEntry *fe = &obj->entry; + + return (HashValue) (fe->old_uniq ^ fe->index ^ atom_val(fe->module)); } static int -fun_cmp(ErlFunEntry* obj1, ErlFunEntry* obj2) +fun_cmp(ErlFunEntryContainer* obj1, ErlFunEntryContainer* obj2) { - /* - * OTP 23: Use 'index' (instead of 'old_index') when comparing fun - * entries. In OTP 23, multiple make_fun2 instructions may refer to the - * the same 'index' (for the wrapper function generated for the - * 'fun F/A' syntax). - * - * This is safe when loading code compiled with OTP R15 and later, - * because since R15 (2011), the 'index' has been reliably equal - * to 'old_index'. The loader refuses to load modules compiled before - * OTP R15. - */ - - return !(obj1->module == obj2->module && - obj1->old_uniq == obj2->old_uniq && - obj1->index == obj2->index); + ErlFunEntry* fe1 = &obj1->entry; + ErlFunEntry* fe2 = &obj2->entry; + + return !(fe1->old_index == fe2->old_index && + fe1->old_uniq == fe2->old_uniq && + fe1->module == fe2->module && + fe1->index == fe2->index && + fe1->arity == fe2->arity && + !sys_memcmp(fe1->uniq, fe2->uniq, sizeof(fe1->uniq))); } -static ErlFunEntry* -fun_alloc(ErlFunEntry* template) +static ErlFunEntryContainer* +fun_alloc(ErlFunEntryContainer* template) { - ErlFunEntry* obj = (ErlFunEntry *) erts_alloc(ERTS_ALC_T_FUN_ENTRY, - sizeof(ErlFunEntry)); - - obj->old_uniq = template->old_uniq; - obj->index = template->index; - obj->module = template->module; - erts_refc_init(&obj->refc, -1); - obj->address = unloaded_fun; - obj->pend_purge_address = NULL; + ErlFunEntryContainer *obj; + ErtsDispatchable *disp; + ErtsCodeIndex ix; + + obj = (ErlFunEntryContainer *) erts_alloc(ERTS_ALC_T_FUN_ENTRY, + sizeof(ErlFunEntryContainer)); + + sys_memcpy(obj, template, sizeof(ErlFunEntryContainer)); + + erts_refc_init(&obj->entry.refc, -1); + + disp = &obj->entry.dispatch; + for (ix = 0; ix < ERTS_NUM_CODE_IX; ix++) { + disp->addresses[ix] = beam_unloaded_fun; + } + +#ifdef BEAMASM + disp->addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls_fun; +#endif + + obj->entry.pend_purge_address = NULL; + return obj; } static void -fun_free(ErlFunEntry* obj) +fun_free(ErlFunEntryContainer* obj) { erts_free(ERTS_ALC_T_FUN_ENTRY, (void *) obj); } + +struct fun_stage_args { + ErtsCodeIndex src_ix; + ErtsCodeIndex dst_ix; +}; + +static void fun_stage_foreach(ErlFunEntryContainer *fc, + struct fun_stage_args *args) +{ + ErtsDispatchable *disp = &fc->entry.dispatch; + + /* Fun entries MUST NOT be updated during a purge! */ + ASSERT(fc->entry.pend_purge_address == NULL); + + disp->addresses[args->dst_ix] = disp->addresses[args->src_ix]; +} + +IF_DEBUG(static ErtsCodeIndex debug_fun_load_ix = 0;) + +void erts_fun_start_staging(void) +{ + ErtsCodeIndex dst_ix = erts_staging_code_ix(); + ErtsCodeIndex src_ix = erts_active_code_ix(); + struct fun_stage_args args = {src_ix, dst_ix}; + + ERTS_LC_ASSERT(erts_has_code_stage_permission()); + ASSERT(dst_ix != src_ix); + ASSERT(debug_fun_load_ix == ~0); + + erts_fun_write_lock(); + hash_foreach(&erts_fun_table, (HFOREACH_FUN)fun_stage_foreach, &args); + erts_fun_write_unlock(); + + IF_DEBUG(debug_fun_load_ix = dst_ix); +} + +void erts_fun_end_staging(int commit) +{ + ERTS_LC_ASSERT((erts_active_code_ix() == erts_active_code_ix()) || + erts_has_code_stage_permission()); + ASSERT(debug_fun_load_ix == erts_staging_code_ix()); + IF_DEBUG(debug_fun_load_ix = ~0); +} diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h index 995fb41de285..4c9ff5cda1fe 100644 --- a/erts/emulator/beam/erl_fun.h +++ b/erts/emulator/beam/erl_fun.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2021. All Rights Reserved. + * Copyright Ericsson AB 2000-2023. 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. @@ -26,53 +26,86 @@ /* * Fun entry. */ - typedef struct erl_fun_entry { - HashBucket bucket; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ - - byte uniq[16]; /* MD5 for module. */ - int index; /* New style index. */ - int old_uniq; /* Unique number (old_style) */ - int old_index; /* Old style index */ - ErtsCodePtr address; /* Pointer to code for fun */ + /* We start with an `ErtsDispatchable`, similar to export entries, so that + * we can mostly use the same code for both. This greatly reduces the + * complexity of instructions like `call_fun` and `is_function2`. */ + ErtsDispatchable dispatch; - Uint arity; /* The arity of the fun. */ + /* These fields identify the function and must not be altered after fun + * creation. */ Eterm module; /* Tagged atom for module. */ + Uint arity; /* The arity of the fun. */ + int index; /* New style index. */ + byte uniq[16]; /* MD5 for module. */ + int old_uniq; /* Unique number (old_style) */ + int old_index; /* Old style index */ + erts_refc_t refc; /* Reference count: One for code + one for * each fun object in each process. */ ErtsCodePtr pend_purge_address; /* Address during a pending purge */ } ErlFunEntry; -/* - * This structure represents a 'fun' (lambda). It is stored on - * process heaps. It has variable size depending on the size - * of the environment. - */ +/* This structure represents a 'fun' (lambda), whether local or external. It is + * stored on process heaps, and has variable size depending on the size of the + * environment. */ typedef struct erl_fun_thing { - Eterm thing_word; /* Subtag FUN_SUBTAG. */ - ErlFunEntry* fe; /* Pointer to fun entry. */ - struct erl_off_heap_header* next; - Uint arity; /* The arity of the fun. */ - Uint num_free; /* Number of free variables (in env). */ - /* -- The following may be compound Erlang terms ---------------------- */ - Eterm creator; /* Pid of creator process (contains node). */ - Eterm env[1]; /* Environment (free variables). */ + Eterm thing_word; /* Subtag FUN_SUBTAG. */ + + union { + /* Both `ErlFunEntry` and `Export` begin with an `ErtsDispatchable`, so + * code that doesn't really care which (e.g. calls) can use this + * pointer to improve performance. */ + ErtsDispatchable *disp; + + /* Pointer to function entry, valid iff `creator != am_external`.*/ + ErlFunEntry *fun; + + /* Pointer to export entry, valid iff `creator == am_external`.*/ + Export *exp; + } entry; + + /* Next off-heap object, must be NULL when this is an external fun. */ + struct erl_off_heap_header *next; + + byte arity; /* The _apparent_ arity of the fun. */ + byte num_free; /* Number of free variables (in env). */ + + /* -- The following may be compound Erlang terms ---------------------- */ + Eterm creator; /* Pid of creator process (contains node). */ + Eterm env[]; /* Environment (free variables). */ } ErlFunThing; -/* ERL_FUN_SIZE does _not_ include space for the environment */ -#define ERL_FUN_SIZE ((sizeof(ErlFunThing)/sizeof(Eterm))-1) +#define is_local_fun(FunThing) ((FunThing)->creator != am_external) +#define is_external_fun(FunThing) ((FunThing)->creator == am_external) + +/* ERL_FUN_SIZE does _not_ include space for the environment which is a + * C99-style flexible array */ +#define ERL_FUN_SIZE ((sizeof(ErlFunThing)/sizeof(Eterm))) + +ErlFunThing *erts_new_export_fun_thing(Eterm **hpp, Export *exp, int arity); +ErlFunThing *erts_new_local_fun_thing(Process *p, + ErlFunEntry *fe, + int arity, + int num_free); void erts_init_fun_table(void); void erts_fun_info(fmtfn_t, void *); int erts_fun_table_sz(void); -ErlFunEntry* erts_get_fun_entry(Eterm mod, int uniq, int index); - +/* Finds or inserts a fun entry that matches the given signature. */ ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, - const byte* uniq, int index, int arity); + const byte* uniq, int index, int arity); + +const ErtsCodeMFA *erts_get_fun_mfa(const ErlFunEntry *fe, ErtsCodeIndex ix); + +void erts_set_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix, ErtsCodePtr address); + +ERTS_GLB_INLINE +ErtsCodePtr erts_get_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix); -int erts_is_fun_loaded(ErlFunEntry* fe); +int erts_is_fun_loaded(const ErlFunEntry* fe, ErtsCodeIndex ix); void erts_erase_fun_entry(ErlFunEntry* fe); void erts_cleanup_funs(ErlFunThing* funp); @@ -84,4 +117,17 @@ void erts_fun_purge_abort_finalize(ErlFunEntry **funs, Uint no); void erts_fun_purge_complete(ErlFunEntry **funs, Uint no); void erts_dump_fun_entries(fmtfn_t, void *); + +void erts_fun_start_staging(void); +void erts_fun_end_staging(int commit); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE +ErtsCodePtr erts_get_fun_code(ErlFunEntry *fe, ErtsCodeIndex ix) { + return fe->dispatch.addresses[ix]; +} + +#endif + #endif diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 325ca8f98e1c..4b41d87ad5ac 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -41,6 +41,7 @@ #include "erl_nfunc_sched.h" #include "erl_proc_sig_queue.h" #include "beam_common.h" +#include "beam_bp.h" #define ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT 1 #define ERTS_INACT_WR_PB_LEAVE_MUCH_PERCENTAGE 20 @@ -113,6 +114,7 @@ typedef struct { int num_roots; /* Number of root arrays. */ } Rootset; +static void copy_erlang_stack(Process *p, Eterm *new_heap, SWord new_sz); static Uint setup_rootset(Process*, Eterm*, int, Rootset*); static void cleanup_rootset(Rootset *rootset); static Eterm *full_sweep_heaps(Process *p, @@ -122,13 +124,13 @@ static Eterm *full_sweep_heaps(Process *p, char *oh, Uint oh_size, Eterm *objv, int nobj); static int garbage_collect(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, int fcalls, + Uint need, Eterm* objv, int nobj, int fcalls, Uint max_young_gen_usage); static int major_collection(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, + Uint need, Eterm* objv, int nobj, Uint ygen_usage, Uint *recl); static int minor_collection(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, + Uint need, Eterm* objv, int nobj, Uint ygen_usage, Uint *recl); static void do_minor(Process *p, ErlHeapFragment *live_hf_end, char *mature, Uint mature_size, @@ -148,12 +150,16 @@ static int adjust_after_fullsweep(Process *p, int need, Eterm *objv, int nobj); static void shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj); static void grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj); static void sweep_off_heap(Process *p, int fullsweep); -static void offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size); -static void offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size); -static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size, - Eterm* objv, int nobj); -static void offset_off_heap(Process* p, Sint offs, char* area, Uint area_size); -static void offset_mqueue(Process *p, Sint offs, char* area, Uint area_size); +static void offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_sz); +static void offset_stack(Eterm *stack, Uint sz, + Sint heap_offset, Sint stack_offset, + char* area, Uint area_sz); +static void offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_sz); +static void offset_rootset(Process *p, Sint heap_offs, Sint stack_offs, + char* area, Uint area_sz, Eterm* objv, int nobj); +static void offset_off_heap(Process* p, Sint offs, char* area, Uint area_sz); +static void offset_mqueue(Process *p, Sint offs, char* area, Uint area_sz); +static int has_reached_max_heap_size(Process *p, Uint total_heap_size); static int reached_max_heap_size(Process *p, Uint total_heap_size, Uint extra_heap_size, Uint extra_old_heap_size); static void init_gc_info(ErtsGCInfo *gcip); @@ -331,7 +337,7 @@ erts_next_heap_size(Uint size, Uint offset) /* * Return the next heap size to use. Make sure we never return * a smaller heap size than the minimum heap size for the process. - * (Use of the erlang:hibernate/3 BIF could have shrinked the + * (Use of the erlang:hibernate/3 BIF could have shrunk the * heap below the minimum heap size.) */ static Uint @@ -456,9 +462,11 @@ erts_gc_after_bif_call_lhf(Process* p, ErlHeapFragment *live_hf_end, cost = garbage_collect(p, live_hf_end, 0, val, 1, p->fcalls, 0); if (ERTS_PROC_IS_EXITING(p)) { result = THE_NON_VALUE; - } else { + } + else { result = val[0]; } + } BUMP_REDS(p, cost); @@ -475,14 +483,11 @@ erts_gc_after_bif_call(Process* p, Eterm result, Eterm* regs, Uint arity) static ERTS_INLINE void assert_no_active_writers(Process *p) { #ifdef DEBUG - struct erl_off_heap_header* ptr; - ptr = MSO(p).first; - while (ptr) { - if (ptr->thing_word == HEADER_PROC_BIN) { - ProcBin *pbp = (ProcBin*) ptr; - ERTS_ASSERT(!(pbp->flags & PB_ACTIVE_WRITER)); - } - ptr = ptr->next; + ProcBin *pb = (ProcBin*) p->wrt_bins; + while (pb) { + ASSERT(pb->thing_word == HEADER_PROC_BIN); + ERTS_ASSERT(!(pb->flags & PB_ACTIVE_WRITER)); + pb = (ProcBin*) pb->next; } #endif } @@ -495,7 +500,7 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int { ErlHeapFragment *hfrag; Eterm *orig_heap, *orig_hend, *orig_htop, *orig_stop; - Eterm *stop, *hend; + Eterm *hend; Uint hsz, ssz; int reds_left; @@ -522,10 +527,11 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int hsz = ssz + need + ERTS_DELAY_GC_EXTRA_FREE + S_RESERVED; hfrag = new_message_buffer(hsz); + + copy_erlang_stack(p, &hfrag->mem[0], hsz); + p->heap = p->htop = &hfrag->mem[0]; p->hend = hend = &hfrag->mem[hsz]; - p->stop = stop = hend - ssz; - sys_memcpy((void *) stop, (void *) orig_stop, ssz * sizeof(Eterm)); if (p->abandoned_heap) { /* @@ -553,6 +559,7 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int } } p->abandoned_heap = orig_heap; + erts_adjust_memory_break(p, orig_htop - p->high_water); } #ifdef CHECK_FOR_HOLES @@ -676,7 +683,7 @@ check_for_possibly_long_gc(Process *p, Uint ygen_usage) */ static int garbage_collect(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, int fcalls, + Uint need, Eterm* objv, int nobj, int fcalls, Uint max_young_gen_usage) { Uint reclaimed_now = 0; @@ -726,7 +733,9 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, ERTS_CHK_OFFHEAP(p); ErtsGcQuickSanityCheck(p); - +#ifdef DEBUG + erts_dbg_check_no_empty_boxed_non_literal_on_heap(p, NULL); +#endif #ifdef USE_VM_PROBES *pidbuf = '\0'; if (DTRACE_ENABLED(gc_major_start) @@ -736,6 +745,12 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, dtrace_proc_str(p, pidbuf); } #endif + + if (p->abandoned_heap) + erts_adjust_memory_break(p, p->htop - p->heap + p->mbuf_sz); + else + erts_adjust_memory_break(p, p->htop - p->high_water + p->mbuf_sz); + /* * Test which type of GC to do. */ @@ -779,16 +794,6 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, ERTS_MSACC_SET_STATE_CACHED_X(ERTS_MSACC_STATE_GC); } - assert_no_active_writers(p); - - /* - * Finish. - */ - - ERTS_CHK_OFFHEAP(p); - - ErtsGcQuickSanityCheck(p); - /* Max heap size has been reached and the process was configured to be killed, so we kill it and set it in a delayed garbage collecting state. There should be no gc_end trace or @@ -810,6 +815,13 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, return res; } + /* + * Finish. + */ + assert_no_active_writers(p); + ERTS_CHK_OFFHEAP(p); + ErtsGcQuickSanityCheck(p); + erts_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC); if (IS_TRACED_FL(p, F_TRACE_GC)) { @@ -879,7 +891,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, } int -erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj, int fcalls) +erts_garbage_collect_nobump(Process* p, Uint need, Eterm* objv, int nobj, int fcalls) { int reds, reds_left; if (p->sig_qs.flags & (FS_ON_HEAP_MSGQ|FS_OFF_HEAP_MSGQ_CHNG)) { @@ -896,7 +908,7 @@ erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj, int fca } void -erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) +erts_garbage_collect(Process* p, Uint need, Eterm* objv, int nobj) { int reds; if (p->sig_qs.flags & (FS_ON_HEAP_MSGQ|FS_OFF_HEAP_MSGQ_CHNG)) { @@ -923,7 +935,7 @@ garbage_collect_hibernate(Process* p, int check_long_gc) Eterm* htop; Uint actual_size; char* area; - Uint area_size; + Uint area_sz; Sint offs; int reds; @@ -962,7 +974,17 @@ garbage_collect_hibernate(Process* p, int check_long_gc) /* Only allow one continuation pointer. */ ASSERT(p->stop == p->hend - CP_SIZE); - ASSERT(p->stop[0] == make_cp(beam_normal_exit)); + + switch (erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + ASSERT(p->stop[0] == make_cp(beam_normal_exit)); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + ASSERT(p->stop[0] == make_cp(NULL)); + ASSERT(p->stop[1] == make_cp(beam_normal_exit)); + ASSERT(FRAME_POINTER(p) == &p->stop[0]); + break; + } /* * Do it. @@ -1026,14 +1048,24 @@ garbage_collect_hibernate(Process* p, int check_long_gc) p->hend = heap + heap_size; p->stop = p->hend - CP_SIZE; - p->stop[0] = make_cp(beam_normal_exit); + + switch (erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + p->stop[0] = make_cp(beam_normal_exit); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + p->stop[0] = make_cp(NULL); + p->stop[1] = make_cp(beam_normal_exit); + FRAME_POINTER(p) = &p->stop[0]; + break; + } offs = heap - p->heap; area = (char *) p->heap; - area_size = ((char *) p->htop) - area; - offset_heap(heap, actual_size, offs, area, area_size); + area_sz = ((char *) p->htop) - area; + offset_heap(heap, actual_size, offs, area, area_sz); p->high_water = heap + (p->high_water - p->heap); - offset_rootset(p, offs, area, area_size, p->arg_reg, p->arity); + offset_rootset(p, offs, 0, area, area_sz, p->arg_reg, p->arity); p->htop = heap + actual_size; p->heap = heap; p->heap_sz = heap_size; @@ -1068,11 +1100,6 @@ erts_garbage_collect_hibernate(Process* p) BUMP_REDS(p, reds); } -#define fullsweep_nstack(p,n_htop) (n_htop) -#define GENSWEEP_NSTACK(p,old_htop,n_htop) do{}while(0) -#define offset_nstack(p,offs,area,area_size) do{}while(0) -#define sweep_literals_nstack(p,old_htop,area,area_size) (old_htop) - int erts_garbage_collect_literals(Process* p, Eterm* literals, Uint byte_lit_size, @@ -1086,7 +1113,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, Rootset rootset; /* Rootset for GC (stack, dictionary, etc). */ Roots* roots; char* area; - Uint area_size; + Uint area_sz; Eterm* old_htop; Uint n; Uint ygen_usage = 0; @@ -1143,7 +1170,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, new_heap_size = HEAP_END(p) - HEAP_START(p); old_heap_size = erts_next_heap_size(lit_size, 0); total_heap_size = new_heap_size + old_heap_size; - if (MAX_HEAP_SIZE_GET(p) < total_heap_size && + if (has_reached_max_heap_size(p, total_heap_size) && reached_max_heap_size(p, total_heap_size, new_heap_size, old_heap_size)) { erts_set_self_exiting(p, am_killed); @@ -1178,7 +1205,8 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, offs = temp_lit - literals; offset_heap(temp_lit, lit_size, offs, (char *) literals, byte_lit_size); offset_heap(p->heap, p->htop - p->heap, offs, (char *) literals, byte_lit_size); - offset_rootset(p, offs, (char *) literals, byte_lit_size, p->arg_reg, p->arity); + offset_rootset(p, offs, 0, (char *) literals, byte_lit_size, + p->arg_reg, p->arity); if (oh) { oh = (struct erl_off_heap_header *) ((Eterm *)(void *) oh + offs); } @@ -1190,10 +1218,10 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, */ area = (char *) temp_lit; - area_size = byte_lit_size; + area_sz = byte_lit_size; n = setup_rootset(p, p->arg_reg, p->arity, &rootset); roots = rootset.roots; - old_htop = sweep_literals_nstack(p, p->old_htop, area, area_size); + old_htop = p->old_htop; while (n--) { Eterm* g_ptr = roots->v; Uint g_sz = roots->sz; @@ -1212,7 +1240,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, if (IS_MOVED_BOXED(val)) { ASSERT(is_boxed(val)); *g_ptr = val; - } else if (ErtsInArea(ptr, area, area_size)) { + } else if (ErtsInArea(ptr, area, area_sz)) { move_boxed(ptr,val,&old_htop,g_ptr); } break; @@ -1221,7 +1249,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, val = *ptr; if (IS_MOVED_CONS(val)) { /* Moved */ *g_ptr = ptr[1]; - } else if (ErtsInArea(ptr, area, area_size)) { + } else if (ErtsInArea(ptr, area, area_sz)) { move_cons(ptr,val,&old_htop,g_ptr); } break; @@ -1238,10 +1266,10 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, * Now we'll have to go through all heaps updating all other references. */ - old_htop = sweep_literals_to_old_heap(p->heap, p->htop, old_htop, area, area_size); + old_htop = sweep_literals_to_old_heap(p->heap, p->htop, old_htop, area, area_sz); old_htop = sweep_literal_area(p->old_heap, old_htop, (char *) p->old_heap, sizeof(Eterm)*old_heap_size, - area, area_size); + area, area_sz); ASSERT(p->old_htop <= old_htop && old_htop <= p->old_hend); p->old_htop = old_htop; @@ -1263,16 +1291,14 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, */ while (oh) { - if (IS_MOVED_BOXED(oh->thing_word)) { - struct erl_off_heap_header* ptr; + if (IS_MOVED_BOXED(oh->thing_word)) { + struct erl_off_heap_header* ptr; - /* - * This off-heap object has been copied to the heap. - * We must increment its reference count and - * link it into the MSO list for the process. - */ + /* This off-heap object has been copied to the heap. + * We must increment its reference count and + * link it into the MSO list for the process.*/ - ptr = (struct erl_off_heap_header*) boxed_val(oh->thing_word); + ptr = (struct erl_off_heap_header*) boxed_val(oh->thing_word); switch (thing_subtag(ptr->thing_word)) { case REFC_BINARY_SUBTAG: { @@ -1282,7 +1308,10 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, } case FUN_SUBTAG: { - ErlFunEntry* fe = ((ErlFunThing*)ptr)->fe; + /* We _KNOW_ that this is a local fun, otherwise it would + * not be part of the off-heap list. */ + ErlFunEntry* fe = ((ErlFunThing*)ptr)->entry.fun; + ASSERT(is_local_fun((ErlFunThing*)ptr)); erts_refc_inc(&fe->refc, 2); break; } @@ -1304,10 +1333,12 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, break; } } - *prev = ptr; - prev = &ptr->next; - } - oh = oh->next; + + *prev = ptr; + prev = &ptr->next; + } + + oh = oh->next; } if (prev) { @@ -1338,7 +1369,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, static int minor_collection(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, + Uint need, Eterm* objv, int nobj, Uint ygen_usage, Uint *recl) { Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap; @@ -1348,6 +1379,8 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, Uint debug_tmp = 0; #endif + need += S_RESERVED; + /* * Check if we have gone past the max heap size limit */ @@ -1368,10 +1401,10 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, heap_size += OLD_HEND(p) - OLD_HEAP(p); /* Add potential new young heap size */ - extra_heap_size = next_heap_size(p, stack_size + size_before, 0); + extra_heap_size = next_heap_size(p, stack_size + MAX(size_before,need), 0); heap_size += extra_heap_size; - if (heap_size > MAX_HEAP_SIZE_GET(p)) + if (has_reached_max_heap_size(p, heap_size)) if (reached_max_heap_size(p, heap_size, extra_heap_size, extra_old_heap_size)) return -2; } @@ -1388,13 +1421,13 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, * This improved Estone by more than 1200 estones on my computer * (Ultra Sparc 10). */ - Uint new_sz = erts_next_heap_size(size_before, 1); + Uint n_old_sz = erts_next_heap_size(size_before, 1); /* Create new, empty old_heap */ n_old = (Eterm *) ERTS_HEAP_ALLOC(ERTS_ALC_T_OLD_HEAP, - sizeof(Eterm)*new_sz); + sizeof(Eterm)*n_old_sz); - OLD_HEND(p) = n_old + new_sz; + OLD_HEND(p) = n_old + n_old_sz; OLD_HEAP(p) = OLD_HTOP(p) = n_old; } @@ -1405,12 +1438,12 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, if (OLD_HEAP(p) && ((mature_size <= OLD_HEND(p) - OLD_HTOP(p)) && - ((BIN_OLD_VHEAP_SZ(p) > BIN_OLD_VHEAP(p))) ) ) { + ((p->bin_old_vheap_sz > p->bin_old_vheap)) ) ) { Eterm *prev_old_htop; Uint stack_size, size_after, adjust_size, need_after, new_sz, new_mature; stack_size = STACK_START(p) - STACK_TOP(p); - new_sz = stack_size + size_before; + new_sz = stack_size + MAX(size_before, need); new_sz = next_heap_size(p, new_sz, 0); prev_old_htop = p->old_htop; @@ -1431,8 +1464,7 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, GEN_GCS(p)++; need_after = ((HEAP_TOP(p) - HEAP_START(p)) + need - + stack_size - + S_RESERVED); + + stack_size); /* * Excessively large heaps should be shrunk, but @@ -1497,6 +1529,65 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, return -1; } +/* Copies the Erlang stack to the end of the new heap, adjusting continuation + * pointers as needed. */ +static ERTS_INLINE void copy_erlang_stack(Process *p, + Eterm *new_heap, + SWord new_sz) { + const ErtsFrameLayout frame_layout = erts_frame_layout; + + Eterm *prev_stack_top, *prev_stack_end; + Eterm *new_stack_top; + SWord stack_size; + + ASSERT(new_heap != HEAP_START(p)); + + prev_stack_top = STACK_TOP(p); + prev_stack_end = STACK_START(p); + + stack_size = prev_stack_end - prev_stack_top; + new_stack_top = &new_heap[new_sz - stack_size]; + +#if defined(DEBUG) && defined(ERLANG_FRAME_POINTERS) + erts_validate_stack(p, FRAME_POINTER(p), prev_stack_top); +#endif + + if (frame_layout == ERTS_FRAME_LAYOUT_RA) { + sys_memcpy(new_stack_top, prev_stack_top, stack_size * sizeof(Eterm)); + } else { + Eterm *new_p, *old_p; + SWord stack_offset; + + ASSERT(frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + + old_p = prev_stack_top; + new_p = new_stack_top; + + stack_offset = new_stack_top - prev_stack_top; + + while (old_p < prev_stack_end) { + Eterm val = old_p[0]; + + if (is_CP(val)) { + Eterm *frame_ptr = (Eterm*)cp_val(val); + + if (old_p < frame_ptr && frame_ptr < prev_stack_end) { + val = offset_ptr(val, stack_offset); + } + } + + new_p[0] = val; + + new_p++; + old_p++; + } + + FRAME_POINTER(p) += stack_offset; + } + + p->stop = new_stack_top; +} + static void do_minor(Process *p, ErlHeapFragment *live_hf_end, char *mature, Uint mature_size, @@ -1536,7 +1627,6 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end, n_htop = collect_live_heap_frags(p, live_hf_end, n_htop); } - GENSWEEP_NSTACK(p, old_htop, n_htop); while (n--) { Eterm* g_ptr = roots->v; Uint g_sz = roots->sz; @@ -1671,7 +1761,7 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end, OLD_HTOP(p) = old_htop; HIGH_WATER(p) = n_htop; - if (MSO(p).first) { + if (MSO(p).first || p->wrt_bins) { sweep_off_heap(p, 0); } @@ -1684,10 +1774,7 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end, disallow_heap_frag_ref_in_old_heap(p); #endif - /* Copy stack to end of new heap */ - n = p->hend - p->stop; - sys_memcpy(n_heap + new_sz - n, p->stop, n * sizeof(Eterm)); - p->stop = n_heap + new_sz - n; + copy_erlang_stack(p, n_heap, new_sz); #ifdef HARDDEBUG disallow_heap_frag_ref_in_heap(p, n_heap, n_htop); @@ -1718,7 +1805,7 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end, static int major_collection(Process* p, ErlHeapFragment *live_hf_end, - int need, Eterm* objv, int nobj, + Uint need, Eterm* objv, int nobj, Uint ygen_usage, Uint *recl) { Uint size_before, size_after, stack_size; @@ -1726,7 +1813,7 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end, Eterm* n_htop; char* oh = (char *) OLD_HEAP(p); Uint oh_size = (char *) OLD_HTOP(p) - oh; - Uint new_sz, stk_sz; + Uint new_sz; int adjusted; VERBOSE(DEBUG_SHCOPY, ("[pid=%T] MAJOR GC: %p %p %p %p\n", p->common.id, @@ -1765,7 +1852,7 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end, /* Add size of new young heap */ heap_size += new_sz; - if (MAX_HEAP_SIZE_GET(p) < heap_size) + if (has_reached_max_heap_size(p, heap_size)) if (reached_max_heap_size(p, heap_size, new_sz, 0)) return -2; } @@ -1777,10 +1864,7 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end, n_htop = full_sweep_heaps(p, live_hf_end, 0, n_heap, n_htop, oh, oh_size, objv, nobj); - /* Move the stack to the end of the heap */ - stk_sz = HEAP_END(p) - p->stop; - sys_memcpy(n_heap + new_sz - stk_sz, p->stop, stk_sz * sizeof(Eterm)); - p->stop = n_heap + new_sz - stk_sz; + copy_erlang_stack(p, n_heap, new_sz); #ifdef HARDDEBUG disallow_heap_frag_ref_in_heap(p, n_heap, n_htop); @@ -1912,7 +1996,7 @@ full_sweep_heaps(Process *p, n_htop = sweep_heaps(n_heap, n_htop, oh, oh_size); - if (MSO(p).first) { + if (MSO(p).first || p->wrt_bins) { sweep_off_heap(p, 1); } @@ -1932,7 +2016,7 @@ adjust_after_fullsweep(Process *p, int need, Eterm *objv, int nobj) int adjusted = 0; Uint wanted, sz, need_after; Uint stack_size = STACK_SZ_ON_HEAP(p); - + /* * Resize the heap if needed. */ @@ -1942,7 +2026,7 @@ adjust_after_fullsweep(Process *p, int need, Eterm *objv, int nobj) /* Too small - grow to match requested need */ sz = next_heap_size(p, need_after, 0); grow_new_heap(p, sz, objv, nobj); - adjusted = 1; + adjusted = 1; } else if (3 * HEAP_SIZE(p) < 4 * need_after){ /* Need more than 75% of current, postpone to next GC.*/ FLAGS(p) |= F_HEAP_GROW; @@ -2427,13 +2511,25 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, if (!is_magic_ref_thing(fhp - 1)) goto the_default; case REFC_BINARY_SUBTAG: - case FUN_SUBTAG: case EXTERNAL_PID_SUBTAG: case EXTERNAL_PORT_SUBTAG: case EXTERNAL_REF_SUBTAG: oh = (struct erl_off_heap_header*) (hp-1); cpy_sz = thing_arityval(val); goto cpy_words; + case FUN_SUBTAG: + { + ErlFunThing *funp = (ErlFunThing*) (fhp - 1); + + if (is_local_fun(funp)) { + oh = (struct erl_off_heap_header*) (hp - 1); + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + } + + cpy_sz = thing_arityval(val); + goto cpy_words; + } default: the_default: cpy_sz = header_arity(val); @@ -2522,6 +2618,14 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) n++; } + ASSERT(p->parent == am_undefined + || is_pid(follow_moved(p->parent, (Eterm) 0))); + if (is_not_immed(p->parent)) { + roots[n].v = &p->parent; + roots[n].sz = 1; + n++; + } + /* * The process may be garbage-collected while it is terminating. * fvalue contains the EXIT reason. @@ -2546,7 +2650,7 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) roots[n].sz = ERTS_RECV_MARKER_BLOCK_SIZE; n++; } - + /* * If a NIF or BIF has saved arguments, they need to be added */ @@ -2655,100 +2759,116 @@ void cleanup_rootset(Rootset* rootset) } } -static void -grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj) +static void resize_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj) { - Eterm* new_heap; - Uint heap_size = HEAP_TOP(p) - HEAP_START(p); - Uint stack_size = p->hend - p->stop; - Sint offs; + Eterm *new_stack, *prev_stack; + Eterm *new_heap, *prev_heap; + Sint heap_offs, stack_offs; + Uint heap_used, stack_used; + Uint prev_sz; + Uint area_sz; + char* area; - ASSERT(HEAP_SIZE(p) < new_sz); - new_heap = (Eterm *) ERTS_HEAP_REALLOC(ERTS_ALC_T_HEAP, - (void *) HEAP_START(p), - sizeof(Eterm)*(HEAP_SIZE(p)), - sizeof(Eterm)*new_sz); - - if ((offs = new_heap - HEAP_START(p)) == 0) { /* No move. */ - HEAP_END(p) = new_heap + new_sz; - sys_memmove(p->hend - stack_size, p->stop, stack_size * sizeof(Eterm)); - p->stop = p->hend - stack_size; - } else { - char* area = (char *) HEAP_START(p); - Uint area_size = (char *) HEAP_TOP(p) - area; - Eterm* prev_stop = p->stop; + prev_heap = HEAP_START(p); + prev_sz = HEAP_SIZE(p); + + stack_used = STACK_START(p) - STACK_TOP(p); + prev_stack = &prev_heap[prev_sz - stack_used]; + + if (new_sz <= prev_sz) { + /* When shrinking, we need to move the stack prior to reallocating as + * the upper part of the stack will disappear. */ + sys_memmove(prev_stack - (prev_sz - new_sz), + prev_stack, stack_used * sizeof(Eterm)); + } + + new_heap = ERTS_HEAP_REALLOC(ERTS_ALC_T_HEAP, prev_heap, + prev_sz * sizeof(Eterm), + new_sz * sizeof(Eterm)); + new_stack = &new_heap[new_sz - stack_used]; + + if (new_sz > prev_sz) { + /* We've grown and the previous stack has either remained in place or + * been copied over to its _previous position_ as part of reallocation, + * so we need to copy it to its new position at the end of the heap. + * + * Note that its pointers are still unchanged, so offset calculation + * should still use `prev_stack` as set above.*/ + sys_memmove(new_stack, + &new_heap[prev_sz - stack_used], + stack_used * sizeof(Eterm)); + } + + heap_used = HEAP_TOP(p) - HEAP_START(p); + + heap_offs = new_heap - prev_heap; + stack_offs = new_stack - prev_stack; - offset_heap(new_heap, heap_size, offs, area, area_size); + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + FRAME_POINTER(p) += stack_offs; + } + + HEAP_TOP(p) = &new_heap[heap_used]; + HEAP_START(p) = new_heap; - HIGH_WATER(p) = new_heap + (HIGH_WATER(p) - HEAP_START(p)); + STACK_START(p) = &new_heap[new_sz]; + STACK_TOP(p) = new_stack; - HEAP_END(p) = new_heap + new_sz; - prev_stop = new_heap + (p->stop - p->heap); - p->stop = p->hend - stack_size; - sys_memmove(p->stop, prev_stop, stack_size * sizeof(Eterm)); + HIGH_WATER(p) = &new_heap[HIGH_WATER(p) - prev_heap]; + HEAP_END(p) = &new_heap[new_sz]; - offset_rootset(p, offs, area, area_size, objv, nobj); - HEAP_TOP(p) = new_heap + heap_size; - HEAP_START(p) = new_heap; + HEAP_SIZE(p) = new_sz; + + area = (char *) prev_heap; + area_sz = prev_sz * sizeof(Eterm); + + if (new_heap == prev_heap) { + offset_stack(new_stack, stack_used, heap_offs, stack_offs, + area, area_sz); + } else { + offset_heap(new_heap, heap_used, heap_offs, area, area_sz); + offset_rootset(p, heap_offs, stack_offs, area, area_sz, objv, nobj); } +} + +static void +grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj) +{ +#ifdef USE_VM_PROBES + Uint prev_sz = HEAP_SIZE(p); +#endif + + ASSERT(HEAP_SIZE(p) < new_sz); + resize_new_heap(p, new_sz, objv, nobj); #ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_heap_grow)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); - DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); + DTRACE3(process_heap_grow, pidbuf, prev_sz, new_sz); } #endif - - HEAP_SIZE(p) = new_sz; } static void shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) { - Eterm* new_heap; - Uint heap_size = HEAP_TOP(p) - HEAP_START(p); - Sint offs; - Uint stack_size = p->hend - p->stop; - - ASSERT(new_sz < p->heap_sz); - sys_memmove(p->heap + new_sz - stack_size, p->stop, stack_size * - sizeof(Eterm)); - new_heap = (Eterm *) ERTS_HEAP_REALLOC(ERTS_ALC_T_HEAP, - (void*)p->heap, - sizeof(Eterm)*(HEAP_SIZE(p)), - sizeof(Eterm)*new_sz); - p->hend = new_heap + new_sz; - p->stop = p->hend - stack_size; - - if ((offs = new_heap - HEAP_START(p)) != 0) { - char* area = (char *) HEAP_START(p); - Uint area_size = (char *) HEAP_TOP(p) - area; - - /* - * Normally, we don't expect a shrunk heap to move, but you never - * know on some strange embedded systems... - */ +#ifdef USE_VM_PROBES + Uint prev_sz = HEAP_SIZE(p); +#endif - offset_heap(new_heap, heap_size, offs, area, area_size); - - HIGH_WATER(p) = new_heap + (HIGH_WATER(p) - HEAP_START(p)); - offset_rootset(p, offs, area, area_size, objv, nobj); - HEAP_TOP(p) = new_heap + heap_size; - HEAP_START(p) = new_heap; - } + ASSERT(HEAP_SIZE(p) > new_sz); + resize_new_heap(p, new_sz, objv, nobj); #ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_heap_shrink)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); - DTRACE3(process_heap_shrink, pidbuf, HEAP_SIZE(p), new_sz); + DTRACE3(process_heap_shrink, pidbuf, prev_sz, new_sz); } #endif - - HEAP_SIZE(p) = new_sz; } static Uint64 @@ -2798,55 +2918,21 @@ next_vheap_size(Process* p, Uint64 vheap, Uint64 vheap_sz) { return new_vheap_sz < p->min_vheap_size ? p->min_vheap_size : new_vheap_sz; } -struct shrink_cand_data { - struct erl_off_heap_header* new_candidates; - struct erl_off_heap_header* new_candidates_end; - struct erl_off_heap_header* old_candidates; - Uint no_of_candidates; - Uint no_of_active; -}; - static ERTS_INLINE void -link_live_proc_bin(struct shrink_cand_data *shrink, - struct erl_off_heap_header*** prevppp, - struct erl_off_heap_header** currpp, - int new_heap) +shrink_writable_bin(ProcBin *pb, Uint leave_unused) { - ProcBin *pbp = (ProcBin*) *currpp; - ASSERT(**prevppp == *currpp); - - *currpp = pbp->next; - if (pbp->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE)) { - ASSERT(pbp->flags & PB_IS_WRITABLE); - - if (pbp->flags & PB_ACTIVE_WRITER) { - pbp->flags &= ~PB_ACTIVE_WRITER; - shrink->no_of_active++; - } - else { /* inactive */ - Uint unused = pbp->val->orig_size - pbp->size; - /* Our allocators are 8 byte aligned, i.e., shrinking with - less than 8 bytes will have no real effect */ - if (unused >= 8) { /* A shrink candidate; save in candidate list */ - **prevppp = pbp->next; - if (new_heap) { - if (!shrink->new_candidates) - shrink->new_candidates_end = (struct erl_off_heap_header*)pbp; - pbp->next = shrink->new_candidates; - shrink->new_candidates = (struct erl_off_heap_header*)pbp; - } - else { - pbp->next = shrink->old_candidates; - shrink->old_candidates = (struct erl_off_heap_header*)pbp; - } - shrink->no_of_candidates++; - return; - } - } + Uint new_size = pb->size; + + if (leave_unused) { + new_size += (new_size * 100) / leave_unused; + /* Our allocators are 8 byte aligned, i.e., shrinking with + less than 8 bytes will have no real effect */ + if (new_size + 8 >= pb->val->orig_size) + return; } - - /* Not a shrink candidate; keep in original mso list */ - *prevppp = &pbp->next; + ASSERT(erts_refc_read(&pb->val->intern.refc, 1) == 1); + pb->val = erts_bin_realloc(pb->val, new_size); + pb->bytes = (byte *) pb->val->orig_bytes; } #ifdef ERTS_MAGIC_REF_THING_HEADER @@ -2863,23 +2949,26 @@ link_live_proc_bin(struct shrink_cand_data *shrink, static void sweep_off_heap(Process *p, int fullsweep) { - struct shrink_cand_data shrink = {0}; struct erl_off_heap_header* ptr; struct erl_off_heap_header** prev; + struct erl_off_heap_header** insert_old_here; char* oheap = NULL; Uint oheap_sz = 0; Uint64 bin_vheap = 0; #ifdef DEBUG + Uint64 orig_bin_old_vheap = p->bin_old_vheap; int seen_mature = 0; #endif + Uint shrink_ncandidates; + Uint shrink_nactive; + ProcBin* shrink_unresolved_end; + ProcBin* pb; if (fullsweep == 0) { oheap = (char *) OLD_HEAP(p); oheap_sz = (char *) OLD_HEND(p) - oheap; } - BIN_OLD_VHEAP(p) = 0; - prev = &MSO(p).first; ptr = MSO(p).first; @@ -2903,9 +2992,9 @@ sweep_off_heap(Process *p, int fullsweep) if (to_new_heap) { bin_vheap += ptr->size / sizeof(Eterm); } else { - BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/ - } - link_live_proc_bin(&shrink, &prev, &ptr, to_new_heap); + p->bin_old_vheap += ptr->size / sizeof(Eterm); + } + ASSERT(!(((ProcBin*)ptr)->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE))); break; } case ERTS_USED_MAGIC_REF_THING_HEADER__: { @@ -2917,7 +3006,7 @@ sweep_off_heap(Process *p, int fullsweep) if (to_new_heap) bin_vheap += size / sizeof(Eterm); else - BIN_OLD_VHEAP(p) += size / sizeof(Eterm); /* for binary gc (words)*/ + p->bin_old_vheap += size / sizeof(Eterm); /* for binary gc (words)*/ /* fall through... */ } default: @@ -2926,27 +3015,39 @@ sweep_off_heap(Process *p, int fullsweep) make_boxed(&ptr->thing_word), ERL_NODE_INC, __FILE__, __LINE__); } - prev = &ptr->next; - ptr = ptr->next; } + prev = &ptr->next; + ptr = ptr->next; } - else if (ErtsInArea(ptr, oheap, oheap_sz)) - break; /* and let old-heap loop continue */ + else if (ErtsInArea(ptr, oheap, oheap_sz)) { + /* + * The rest of the list resides on the old heap and needs no + * attention during a minor gc. + */ + ASSERT(!fullsweep); + break; + } else { /* garbage */ switch (thing_subtag(ptr->thing_word)) { case REFC_BINARY_SUBTAG: { - Binary* bptr = ((ProcBin*)ptr)->val; - erts_bin_release(bptr); + erts_bin_release(((ProcBin*)ptr)->val); break; } case FUN_SUBTAG: { - ErlFunEntry* fe = ((ErlFunThing*)ptr)->fe; - if (erts_refc_dectest(&fe->refc, 0) == 0) { - erts_erase_fun_entry(fe); - } + ErlFunThing* funp = ((ErlFunThing*)ptr); + + if (is_local_fun(funp)) { + ErlFunEntry* fe = funp->entry.fun; + + if (erts_refc_dectest(&fe->refc, 0) == 0) { + erts_erase_fun_entry(fe); + } + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + } break; } case REF_SUBTAG: @@ -2966,94 +3067,164 @@ sweep_off_heap(Process *p, int fullsweep) } } - /* The rest of the list resides on old-heap, and we just did a - * generational collection - keep objects in list. - */ - while (ptr) { - ASSERT(ErtsInArea(ptr, oheap, oheap_sz)); - ASSERT(!IS_MOVED_BOXED(ptr->thing_word)); - switch (ptr->thing_word) { - case HEADER_PROC_BIN: - BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/ - link_live_proc_bin(&shrink, &prev, &ptr, 0); - break; - case ERTS_USED_MAGIC_REF_THING_HEADER__: - ASSERT(is_magic_ref_thing(ptr)); - BIN_OLD_VHEAP(p) += - (((Uint) ((ErtsMRefThing *) ptr)->mb->orig_size) - / sizeof(Eterm)); /* for binary gc (words)*/ - /* fall through... */ - default: - ASSERT(is_fun_header(ptr->thing_word) || - is_external_header(ptr->thing_word) - || is_magic_ref_thing(ptr)); - prev = &ptr->next; - ptr = ptr->next; - break; - } - } + insert_old_here = prev; +#ifdef DEBUG if (fullsweep) { - BIN_OLD_VHEAP_SZ(p) = next_vheap_size(p, BIN_OLD_VHEAP(p) + MSO(p).overhead, BIN_OLD_VHEAP_SZ(p)); + ASSERT(ptr == NULL); + ASSERT(p->bin_old_vheap == orig_bin_old_vheap); } - BIN_VHEAP_SZ(p) = next_vheap_size(p, bin_vheap, BIN_VHEAP_SZ(p)); - MSO(p).overhead = bin_vheap; + else { + /* The rest of the list resides on the old heap and needs no + * attention during a minor gc. In a DEBUG build, verify + * that the binaries in the list are not writable and that + * the other terms are of the allowed types. + */ + while (ptr) { + ASSERT(ErtsInArea(ptr, oheap, oheap_sz)); + ASSERT(!IS_MOVED_BOXED(ptr->thing_word)); + switch (ptr->thing_word) { + case HEADER_PROC_BIN: + ASSERT(!(((ProcBin*)ptr)->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE))); + break; + default: + ASSERT(is_fun_header(ptr->thing_word) || + is_external_header(ptr->thing_word) || + is_magic_ref_thing(ptr)); + break; + } + ptr = ptr->next; + } + } +#endif /* DEBUG */ /* - * If we got any shrink candidates, check them out. + * Traverse writable binaries. + * As writable binaries may reside on the old heap we traverse + * the entire wrt_bins list even during minor gc. */ + shrink_nactive = 0; /* number of active writable binaries */ + shrink_ncandidates = 0; /* number of candidates for shrinking */ + shrink_unresolved_end = NULL; /* end marker for second traversal */ + + pb = (ProcBin*) p->wrt_bins; + prev = &p->wrt_bins; + while (pb) { + int on_old_heap; + if (IS_MOVED_BOXED(pb->thing_word)) { + ASSERT(!ErtsInArea(pb, oheap, oheap_sz)); + pb = (ProcBin*) boxed_val(pb->thing_word); + *prev = (struct erl_off_heap_header*) pb; + ASSERT(pb->thing_word == HEADER_PROC_BIN); + on_old_heap = ErtsInArea(pb, oheap, oheap_sz); + if (!on_old_heap) { + bin_vheap += pb->size / sizeof(Eterm); + } else { + p->bin_old_vheap += pb->size / sizeof(Eterm); + } + } + else { + ASSERT(pb->thing_word == HEADER_PROC_BIN); + on_old_heap = ErtsInArea(pb, oheap, oheap_sz); + if (!on_old_heap) { + /* garbage */ + erts_bin_release(pb->val); + pb = (ProcBin*) pb->next; + *prev = (struct erl_off_heap_header*) pb; + continue; + } + } + if (pb->flags) { + ASSERT(pb->flags & PB_IS_WRITABLE); + + /* + * How to shrink writable binaries. There are two distinct cases: + * + * + There are one or more active writers. We will shrink all + * writable binaries without active writers down to their + * original sizes. + * + * + There are no active writers. We will shrink all writable + * binaries, but not fully. How much margin we will leave + * depends on the number of writable binaries. + * + * That is, we don't know how to shrink the binaries before either + * + finding the first active writer, or + * + finding more than ERTS_INACT_WR_PB_LEAVE_LIMIT + * shrink candidates + */ + + if (pb->flags & PB_ACTIVE_WRITER) { + pb->flags &= ~PB_ACTIVE_WRITER; + shrink_nactive++; + if (!shrink_unresolved_end) + shrink_unresolved_end = pb; + } + else { /* inactive */ + Uint unused = pb->val->orig_size - pb->size; + /* Our allocators are 8 byte aligned, i.e., shrinking with + less than 8 bytes will have no real effect */ + if (unused >= 8) { /* A shrink candidate */ + if (shrink_unresolved_end) { + shrink_writable_bin(pb, 0); + } + else if (++shrink_ncandidates > ERTS_INACT_WR_PB_LEAVE_LIMIT) { + shrink_unresolved_end = pb; + shrink_writable_bin(pb, 0); + } + /* else unresolved, handle in second traversal below */ + } + } + prev = &pb->next; + pb = (ProcBin*) pb->next; + } + else { /* emasculated, move to regular off-heap list */ + struct erl_off_heap_header* next = pb->next; + if (on_old_heap) { + pb->next = *insert_old_here; + *insert_old_here = (struct erl_off_heap_header*)pb; + } + else { + pb->next = p->off_heap.first; + p->off_heap.first = (struct erl_off_heap_header*)pb; + if (insert_old_here == &p->off_heap.first) + insert_old_here = &pb->next; + } + pb = (ProcBin*) next; + *prev = next; + } + } - if (shrink.no_of_candidates) { - ProcBin *candlist[] = { (ProcBin*)shrink.new_candidates, - (ProcBin*)shrink.old_candidates }; + /* + * Handle any unresolved shrink candidates left at the head of wrt_bins. + */ + if (shrink_ncandidates) { Uint leave_unused = 0; - int i; - if (shrink.no_of_active == 0) { - if (shrink.no_of_candidates <= ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT) + if (shrink_nactive == 0) { + if (shrink_ncandidates <= ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT) leave_unused = ERTS_INACT_WR_PB_LEAVE_MUCH_PERCENTAGE; - else if (shrink.no_of_candidates <= ERTS_INACT_WR_PB_LEAVE_LIMIT) - leave_unused = ERTS_INACT_WR_PB_LEAVE_PERCENTAGE; + else if (shrink_ncandidates <= ERTS_INACT_WR_PB_LEAVE_LIMIT) + leave_unused = ERTS_INACT_WR_PB_LEAVE_PERCENTAGE; } - for (i = 0; i < sizeof(candlist)/sizeof(candlist[0]); i++) { - ProcBin* pb; - for (pb = candlist[i]; pb; pb = (ProcBin*)pb->next) { - Uint new_size = pb->size; - - if (leave_unused) { - new_size += (new_size * 100) / leave_unused; - /* Our allocators are 8 byte aligned, i.e., shrinking with - less than 8 bytes will have no real effect */ - if (new_size + 8 >= pb->val->orig_size) - continue; - } - - pb->val = erts_bin_realloc(pb->val, new_size); - pb->bytes = (byte *) pb->val->orig_bytes; - } + for (pb = (ProcBin *)p->wrt_bins; + pb != shrink_unresolved_end; + pb = (ProcBin *)pb->next) { + ASSERT(pb); + ASSERT(pb->flags == PB_IS_WRITABLE); + shrink_writable_bin(pb, leave_unused); } + } - - /* - * We now potentially have the mso list divided into three lists: - * - shrink candidates on new heap (inactive writable with unused data) - * - shrink candidates on old heap (inactive writable with unused data) - * - other binaries (read only + active writable ...) + funs and externals - * - * Put them back together: new candidates -> other -> old candidates - * This order will ensure that the list only refers from new - * generation to old and never from old to new *which is important*. - */ - if (shrink.new_candidates) { - if (prev == &MSO(p).first) /* empty other binaries list */ - prev = &shrink.new_candidates_end->next; - else - shrink.new_candidates_end->next = MSO(p).first; - MSO(p).first = shrink.new_candidates; - } + if (fullsweep) { + ASSERT(p->bin_old_vheap == orig_bin_old_vheap); + p->bin_old_vheap = 0; + p->bin_old_vheap_sz = next_vheap_size(p, MSO(p).overhead, + p->bin_old_vheap_sz); } - *prev = shrink.old_candidates; + p->bin_vheap_sz = next_vheap_size(p, bin_vheap, p->bin_vheap_sz); + MSO(p).overhead = bin_vheap; } /* @@ -3130,19 +3301,57 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size) } } -/* - * Offset pointers to heap from stack. - */ +/* Offset on-stack pointers to stack and heap. */ +static void +offset_stack(Eterm *stack, Uint sz, + Sint heap_offset, Sint stack_offset, + char* area, Uint area_sz) { + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA || stack_offset == 0) { + /* No need to update self-references, just update pointers to the + * heap. */ + offset_heap_ptr(stack, sz, heap_offset, area, area_sz); + } else { + Sint i = 0; -static void -offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size) + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + + while (i < sz) { + Eterm val = stack[i]; + + switch (primary_tag(val)) { + case TAG_PRIMARY_HEADER: + if (ErtsInArea(val, area, area_sz)) { + stack[i] = offset_ptr(val, stack_offset); + } + + i++; + break; + case TAG_PRIMARY_LIST: + case TAG_PRIMARY_BOXED: + if (ErtsInArea(ptr_val(val), area, area_sz)) { + stack[i] = offset_ptr(val, heap_offset); + } + + i++; + break; + default: + i++; + break; + } + } + } +} + +/* Offset pointers to heap from a root set. */ +static void +offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_sz) { while (sz--) { Eterm val = *hp; switch (primary_tag(val)) { case TAG_PRIMARY_LIST: case TAG_PRIMARY_BOXED: - if (ErtsInArea(ptr_val(val), area, area_size)) { + if (ErtsInArea(ptr_val(val), area, area_sz)) { *hp = offset_ptr(val, offs); } hp++; @@ -3161,6 +3370,10 @@ offset_off_heap(Process* p, Sint offs, char* area, Uint area_size) Eterm** uptr = (Eterm**) (void *) &MSO(p).first; *uptr += offs; } + if (p->wrt_bins && ErtsInArea(p->wrt_bins, area, area_size)) { + Eterm** uptr = (Eterm**) (void *) &p->wrt_bins; + *uptr += offs; + } } #ifndef USE_VM_PROBES @@ -3218,43 +3431,47 @@ offset_mqueue(Process *p, Sint offs, char* area, Uint area_size) } static void ERTS_INLINE -offset_one_rootset(Process *p, Sint offs, char* area, Uint area_size, - Eterm* objv, int nobj) +offset_one_rootset(Process *p, Sint heap_offs, Sint stack_offs, + char* area, Uint area_sz, Eterm* objv, int nobj) { Eterm *v; Uint sz; if (p->dictionary) { - offset_heap(ERTS_PD_START(p->dictionary), - ERTS_PD_SIZE(p->dictionary), - offs, area, area_size); + offset_heap(ERTS_PD_START(p->dictionary), + ERTS_PD_SIZE(p->dictionary), + heap_offs, area, area_sz); } - offset_heap_ptr(&p->fvalue, 1, offs, area, area_size); - offset_heap_ptr(&p->ftrace, 1, offs, area, area_size); - offset_heap_ptr(&p->seq_trace_token, 1, offs, area, area_size); + offset_heap_ptr(&p->fvalue, 1, heap_offs, area, area_sz); + offset_heap_ptr(&p->ftrace, 1, heap_offs, area, area_sz); + offset_heap_ptr(&p->seq_trace_token, 1, heap_offs, area, area_sz); #ifdef USE_VM_PROBES - offset_heap_ptr(&p->dt_utag, 1, offs, area, area_size); + offset_heap_ptr(&p->dt_utag, 1, heap_offs, area, area_sz); #endif - offset_heap_ptr(&p->group_leader, 1, offs, area, area_size); - if (p->sig_qs.recv_mrk_blk) - offset_heap_ptr(&p->sig_qs.recv_mrk_blk->ref[0], - ERTS_RECV_MARKER_BLOCK_SIZE, offs, area, area_size); - offset_mqueue(p, offs, area, area_size); - offset_heap_ptr(p->stop, (STACK_START(p) - p->stop), offs, area, area_size); - offset_nstack(p, offs, area, area_size); + offset_heap_ptr(&p->group_leader, 1, heap_offs, area, area_sz); + offset_heap_ptr(&p->parent, 1, heap_offs, area, area_sz); + if (p->sig_qs.recv_mrk_blk) { + offset_heap_ptr(&p->sig_qs.recv_mrk_blk->ref[0], + ERTS_RECV_MARKER_BLOCK_SIZE, heap_offs, + area, area_sz); + } + offset_mqueue(p, heap_offs, area, area_sz); + offset_stack(p->stop, (STACK_START(p) - p->stop), heap_offs, stack_offs, + area, area_sz); if (nobj > 0) { - offset_heap_ptr(objv, nobj, offs, area, area_size); + offset_heap_ptr(objv, nobj, heap_offs, area, area_sz); + } + offset_off_heap(p, heap_offs, area, area_sz); + if (erts_setup_nfunc_rootset(p, &v, &sz)) { + offset_heap_ptr(v, sz, heap_offs, area, area_sz); } - offset_off_heap(p, offs, area, area_size); - if (erts_setup_nfunc_rootset(p, &v, &sz)) - offset_heap_ptr(v, sz, offs, area, area_size); } static void -offset_rootset(Process *p, Sint offs, char* area, Uint area_size, - Eterm* objv, int nobj) +offset_rootset(Process *p, Sint heap_offs, Sint stack_offs, + char* area, Uint area_sz, Eterm* objv, int nobj) { - offset_one_rootset(p, offs, area, area_size, objv, nobj); + offset_one_rootset(p, heap_offs, stack_offs, area, area_sz, objv, nobj); } static void @@ -3434,9 +3651,9 @@ erts_process_gc_info(Process *p, Uint *sizep, Eterm **hpp, OLD_HEAP(p) ? OLD_HTOP(p) - OLD_HEAP(p) : 0, HEAP_TOP(p) - HEAP_START(p), MSO(p).overhead, - BIN_VHEAP_SZ(p), - BIN_OLD_VHEAP(p), - BIN_OLD_VHEAP_SZ(p) + p->bin_vheap_sz, + p->bin_old_vheap, + p->bin_old_vheap_sz }; Eterm res = THE_NON_VALUE; @@ -3478,6 +3695,16 @@ erts_process_gc_info(Process *p, Uint *sizep, Eterm **hpp, return res; } +static int has_reached_max_heap_size(Process *p, Uint total_heap_size) +{ + Uint used = total_heap_size; + + if (MAX_HEAP_SIZE_FLAGS_GET(p) & MAX_HEAP_SIZE_INCLUDE_OH_BINS) { + used += p->bin_old_vheap + p->off_heap.overhead; + } + return (used > MAX_HEAP_SIZE_GET(p)); +} + static int reached_max_heap_size(Process *p, Uint total_heap_size, Uint extra_heap_size, Uint extra_old_heap_size) @@ -3538,28 +3765,21 @@ reached_max_heap_size(Process *p, Uint total_heap_size, } Eterm -erts_max_heap_size_map(Sint max_heap_size, Uint max_heap_flags, - Eterm **hpp, Uint *sz) +erts_max_heap_size_map(ErtsHeapFactory *factory, + Sint max_heap_size, Uint max_heap_flags) { - if (!hpp) { - *sz += ERTS_MAX_HEAP_SIZE_MAP_SZ; - return THE_NON_VALUE; - } else { - Eterm *hp = *hpp; - Eterm keys = TUPLE3(hp, am_error_logger, am_kill, am_size); - flatmap_t *mp; - hp += 4; - mp = (flatmap_t*) hp; - mp->thing_word = MAP_HEADER_FLATMAP; - mp->size = 3; - mp->keys = keys; - hp += MAP_HEADER_FLATMAP_SZ; - *hp++ = max_heap_flags & MAX_HEAP_SIZE_LOG ? am_true : am_false; - *hp++ = max_heap_flags & MAX_HEAP_SIZE_KILL ? am_true : am_false; - *hp++ = make_small(max_heap_size); - *hpp = hp; - return make_flatmap(mp); - } + Eterm keys[] = { + am_error_logger, am_include_shared_binaries, am_kill, am_size + }; + Eterm values[] = { + max_heap_flags & MAX_HEAP_SIZE_LOG ? am_true : am_false, + max_heap_flags & MAX_HEAP_SIZE_INCLUDE_OH_BINS ? am_true : am_false, + max_heap_flags & MAX_HEAP_SIZE_KILL ? am_true : am_false, + make_small(max_heap_size) + }; + ERTS_CT_ASSERT(sizeof(keys) == sizeof(values)); + return erts_map_from_ks_and_vs(factory, keys, values, + sizeof(keys) / sizeof(keys[0])); } int @@ -3574,6 +3794,7 @@ erts_max_heap_size(Eterm arg, Uint *max_heap_size, Uint *max_heap_flags) const Eterm *size = erts_maps_get(am_size, arg); const Eterm *kill = erts_maps_get(am_kill, arg); const Eterm *log = erts_maps_get(am_error_logger, arg); + const Eterm *incl_bins = erts_maps_get(am_include_shared_binaries, arg); if (size && is_small(*size)) { sz = signed_val(*size); } else { @@ -3596,6 +3817,14 @@ erts_max_heap_size(Eterm arg, Uint *max_heap_size, Uint *max_heap_flags) else return 0; } + if (incl_bins) { + if (*incl_bins == am_true) + *max_heap_flags |= MAX_HEAP_SIZE_INCLUDE_OH_BINS; + else if (*incl_bins == am_false) + *max_heap_flags &= ~MAX_HEAP_SIZE_INCLUDE_OH_BINS; + else + return 0; + } } else return 0; if (sz < 0) @@ -3604,6 +3833,62 @@ erts_max_heap_size(Eterm arg, Uint *max_heap_size, Uint *max_heap_flags) return 1; } +#ifdef DEBUG +void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top) { + Eterm *stack_bottom = HEAP_END(p); + Eterm *next_fp = frame_ptr; + Eterm *scanner = stack_top; + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + return; + } + + /* We must have a frame pointer or an empty stack, but not both. */ + ASSERT((next_fp != NULL) ^ (stack_top == stack_bottom)); + + /* If the GC happens when we are about to execute a trace we + need to skip the trace instructions */ + if (BeamIsReturnTrace(p->i)) { + /* Skip MFA and tracer. */ + ASSERT_MFA((ErtsCodeMFA*)cp_val(scanner[0])); + ASSERT(IS_TRACER_VALID(scanner[1])); + scanner += BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(p->i)) { + /* Skip prev_info. */ + scanner += BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } + ERTS_CT_ASSERT(BEAM_RETURN_TO_TRACE_FRAME_SZ == 0); + + while (next_fp) { + ASSERT(next_fp >= stack_top && next_fp <= stack_bottom); + + /* We may not skip any frames. */ + while (scanner < next_fp) { + ASSERT(is_not_CP(scanner[0])); + scanner++; + } + + /* {Next frame, Return address} or vice versa */ + ASSERT(is_CP(scanner[0]) && is_CP(scanner[1])); + next_fp = (Eterm*)cp_val(scanner[0]); + + /* Call tracing may store raw pointers on the stack. This is explicitly + * handled in all routines that deal with the stack. */ + if (BeamIsReturnTrace((ErtsCodePtr)scanner[1])) { + /* Skip MFA and tracer. */ + ASSERT_MFA((ErtsCodeMFA*)cp_val(scanner[2])); + ASSERT(IS_TRACER_VALID(scanner[3])); + scanner += BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace((ErtsCodePtr)scanner[1])) { + /* Skip prev_info. */ + scanner += BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } + + scanner += CP_SIZE; + } +} +#endif + #if defined(DEBUG) || defined(ERTS_OFFHEAP_DEBUG) int @@ -3655,6 +3940,156 @@ erts_dbg_within_proc(Eterm *ptr, Process *p, Eterm *real_htop) #endif +#ifdef DEBUG + +#include "erl_global_literals.h" + +static int +check_all_heap_terms_in_range(int (*check_eterm)(Eterm), + Eterm* region_start, + Eterm* region_end) +{ + Eterm* tp = region_start; + while (tp < region_end) { + Eterm val = *tp++; + + switch (primary_tag(val)) { + case TAG_PRIMARY_IMMED1: + if (!check_eterm(val)) { + return 0; + } + break; + case TAG_PRIMARY_LIST: + case TAG_PRIMARY_BOXED: + if (!check_eterm(val)) { + return 0; + } + break; + case TAG_PRIMARY_HEADER: + switch (val & _HEADER_SUBTAG_MASK) { + case ARITYVAL_SUBTAG: + break; + case REFC_BINARY_SUBTAG: + goto off_heap_common; + case FUN_SUBTAG: + goto off_heap_common; + case EXTERNAL_PID_SUBTAG: + case EXTERNAL_PORT_SUBTAG: + case EXTERNAL_REF_SUBTAG: + off_heap_common: + { + int tari = thing_arityval(val); + tp += tari; + } + break; + case REF_SUBTAG: { + ErtsRefThing *rtp = (ErtsRefThing *) (tp - 1); + if (is_magic_ref_thing(rtp)) { + goto off_heap_common; + } + /* Fall through... */ + } + default: + { + int tari = header_arity(val); + tp += tari; + } + break; + } + break; + } + } + return 1; +} + +int +erts_dbg_check_heap_terms(int (*check_eterm)(Eterm), + Process *p, + Eterm *real_htop) +{ + ErlHeapFragment* bp; + ErtsMessage* mp; + Eterm *htop, *heap; + + if (p->abandoned_heap) { + ERTS_GET_ORIG_HEAP(p, heap, htop); + if (!check_all_heap_terms_in_range(check_eterm, + heap, htop)) + return 0; + } + + heap = p->heap; + htop = real_htop ? real_htop : HEAP_TOP(p); + + if (OLD_HEAP(p) && + !check_all_heap_terms_in_range(check_eterm, + OLD_HEAP(p), OLD_HTOP(p) /*OLD_HEND(p)*/)) { + return 0; + } + + if (!check_all_heap_terms_in_range(check_eterm, heap, htop)) { + return 0; + } + + mp = p->msg_frag; + bp = p->mbuf; + + if (bp) + goto search_heap_frags; + + while (mp) { + + bp = erts_message_to_heap_frag(mp); + mp = mp->next; + + search_heap_frags: + + while (bp) { + if (!check_all_heap_terms_in_range(check_eterm, + bp->mem, + bp->mem + bp->used_size)) { + return 0; + } + bp = bp->next; + } + } + + return 1; +} + +static int check_no_empty_boxed_non_literal_term(Eterm term) { + if (is_boxed(term)) { + Uint arity = header_arity(*boxed_val(term)); + + /* Maps can have 0 arity even though they have something after the + * arity word. */ + if (arity == 0 && !is_map(term)) { + if (term != ERTS_GLOBAL_LIT_EMPTY_TUPLE) { + /* Empty tuples are the only type of boxed value that can + * have an arity of 0. This can change in the feature and + * the condition above needs to be changed if it does. */ + erts_exit(ERTS_ABORT_EXIT, + "Non-literal empty tuple found in heap.\n" + "This is not allowed due to an optimization\n" + "that assumes that the word after the arity\n" + "word is allocated.\n"); + } + } + } + return 1; +} + +void +erts_dbg_check_no_empty_boxed_non_literal_on_heap(Process *p, + Eterm *real_htop) +{ + erts_dbg_check_heap_terms(check_no_empty_boxed_non_literal_term, + p, + real_htop); +} + +#endif + #ifdef ERTS_OFFHEAP_DEBUG #define ERTS_CHK_OFFHEAP_ASSERT(EXP) \ @@ -3675,18 +4110,26 @@ erts_check_off_heap2(Process *p, Eterm *htop) { Eterm *oheap = (Eterm *) OLD_HEAP(p); Eterm *ohtop = (Eterm *) OLD_HTOP(p); - int old; + enum { NEW_PART, OLD_PART, WRT_BIN_PART} part; union erl_off_heap_ptr u; - old = 0; - for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next) { + part = NEW_PART; + u.hdr = MSO(p).first; +repeat: + for (; u.hdr; u.hdr = u.hdr->next) { erts_aint_t refc; switch (thing_subtag(u.hdr->thing_word)) { case REFC_BINARY_SUBTAG: refc = erts_refc_read(&u.pb->val->intern.refc, 1); break; - case FUN_SUBTAG: - refc = erts_refc_read(&u.fun->fe->refc, 1); + case FUN_SUBTAG: + if (is_local_fun(u.fun)) { + refc = erts_refc_read(&u.fun->entry.fun->refc, 1); + } else { + /* Export fun, fake a valid refc. */ + ASSERT(is_external_fun(u.fun) && u.fun->next == NULL); + refc = 1; + } break; case EXTERNAL_PID_SUBTAG: case EXTERNAL_PORT_SUBTAG: @@ -3705,19 +4148,26 @@ erts_check_off_heap2(Process *p, Eterm *htop) ERTS_CHK_OFFHEAP_ASSERT(!(u.hdr->thing_word & ERTS_OFFHEAP_VISITED_BIT)); u.hdr->thing_word |= ERTS_OFFHEAP_VISITED_BIT; #endif - if (old) { - ERTS_CHK_OFFHEAP_ASSERT(oheap <= u.ep && u.ep < ohtop); - } - else if (oheap <= u.ep && u.ep < ohtop) - old = 1; - else { - ERTS_CHK_OFFHEAP_ASSERT(erts_dbg_within_proc(u.ep, p, htop)); - } + if (part == OLD_PART) + ERTS_CHK_OFFHEAP_ASSERT(oheap <= u.ep && u.ep < ohtop); + else if (part == NEW_PART && oheap <= u.ep && u.ep < ohtop) + part = OLD_PART; + else + ERTS_CHK_OFFHEAP_ASSERT(erts_dbg_within_proc(u.ep, p, htop)); } + if (part != WRT_BIN_PART) { + part = WRT_BIN_PART; + u.hdr = p->wrt_bins; + goto repeat; + } + + #ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next) u.hdr->thing_word &= ~ERTS_OFFHEAP_VISITED_BIT; + for (u.hdr = p->wrt_bins; u.hdr; u.hdr = u.hdr->next) + u.hdr->thing_word &= ~ERTS_OFFHEAP_VISITED_BIT; #endif } diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h index 347f099fa5d3..c1760562c950 100644 --- a/erts/emulator/beam/erl_gc.h +++ b/erts/emulator/beam/erl_gc.h @@ -160,7 +160,7 @@ typedef struct { Uint64 garbage_cols; } ErtsGCInfo; -#define ERTS_MAX_HEAP_SIZE_MAP_SZ (2*3 + 1 + MAP_HEADER_FLATMAP_SZ) +#define ERTS_MAX_HEAP_SIZE_MAP_SZ (2*4 + 1 + MAP_HEADER_FLATMAP_SZ) #define ERTS_PROCESS_GC_INFO_MAX_TERMS (11) /* number of elements in process_gc_info*/ #define ERTS_PROCESS_GC_INFO_MAX_SIZE \ @@ -169,8 +169,8 @@ Eterm erts_process_gc_info(struct process*, Uint *, Eterm **, Uint, Uint); void erts_gc_info(ErtsGCInfo *gcip); void erts_init_gc(void); -int erts_garbage_collect_nobump(struct process*, int, Eterm*, int, int); -void erts_garbage_collect(struct process*, int, Eterm*, int); +int erts_garbage_collect_nobump(struct process*, Uint, Eterm*, int, int); +void erts_garbage_collect(struct process*, Uint, Eterm*, int); void erts_garbage_collect_hibernate(struct process* p); Eterm erts_gc_after_bif_call_lhf(struct process* p, ErlHeapFragment *live_hf_end, Eterm result, Eterm* regs, Uint arity); @@ -186,7 +186,7 @@ void erts_offset_off_heap(struct erl_off_heap*, Sint, Eterm*, Eterm*); void erts_offset_heap_ptr(Eterm*, Uint, Sint, Eterm*, Eterm*); void erts_offset_heap(Eterm*, Uint, Sint, Eterm*, Eterm*); void erts_free_heap_frags(struct process* p); -Eterm erts_max_heap_size_map(Sint, Uint, Eterm **, Uint *); +Eterm erts_max_heap_size_map(ErtsHeapFactory *factory, Sint, Uint); int erts_max_heap_size(Eterm, Uint *, Uint *); void erts_deallocate_young_generation(Process *c_p); void erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, @@ -195,4 +195,17 @@ void erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, int erts_dbg_within_proc(Eterm *ptr, Process *p, Eterm* real_htop); #endif +#ifdef DEBUG +/* Validates the frame chain, ensuring that it always points within the stack + * and that no frames are skipped. */ +void erts_validate_stack(Process *p, Eterm *frame_ptr, Eterm *stack_top); +int +erts_dbg_check_heap_terms(int (*check_eterm)(Eterm), + Process *p, + Eterm *real_htop); +void +erts_dbg_check_no_empty_boxed_non_literal_on_heap(Process *p, + Eterm *real_htop); +#endif + #endif /* __ERL_GC_H__ */ diff --git a/erts/emulator/beam/erl_global_literals.c b/erts/emulator/beam/erl_global_literals.c index c3e7b8a70bcc..a05c1031426b 100644 --- a/erts/emulator/beam/erl_global_literals.c +++ b/erts/emulator/beam/erl_global_literals.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2021. 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. @@ -33,6 +33,12 @@ struct literal { static struct literal literals[ERTS_NUM_GLOBAL_LITERALS]; +/* + * Global Constant Literals + */ +Eterm ERTS_WRITE_UNLIKELY(ERTS_GLOBAL_LIT_EMPTY_TUPLE); + + Eterm* erts_alloc_global_literal(Uint index, Uint sz) { ErtsLiteralArea* area; diff --git a/erts/emulator/beam/erl_global_literals.h b/erts/emulator/beam/erl_global_literals.h index 15e873479d41..9d17c16e66dc 100644 --- a/erts/emulator/beam/erl_global_literals.h +++ b/erts/emulator/beam/erl_global_literals.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2021. 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. @@ -24,11 +24,16 @@ #define ERTS_LIT_OS_TYPE 0 #define ERTS_LIT_OS_VERSION 1 #define ERTS_LIT_DFLAGS_RECORD 2 +#define ERTS_LIT_EMPTY_TUPLE 3 +#define ERTS_LIT_ERL_FILE_SUFFIX 4 -#define ERTS_NUM_GLOBAL_LITERALS 3 +#define ERTS_NUM_GLOBAL_LITERALS 5 + +extern Eterm ERTS_GLOBAL_LIT_EMPTY_TUPLE; Eterm* erts_alloc_global_literal(Uint index, Uint sz); void erts_register_global_literal(Uint index, Eterm term); Eterm erts_get_global_literal(Uint index); ErtsLiteralArea* erts_get_global_literal_area(Uint index); + #endif diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c index c8c9e5e38876..f77b6fd60408 100644 --- a/erts/emulator/beam/erl_hl_timer.c +++ b/erts/emulator/beam/erl_hl_timer.c @@ -2182,7 +2182,7 @@ access_bif_timer(Process *c_p, Eterm tref, int cancel, int async, int info) * callers message queue to the end of the queue. * * NOTE: It is of vital importance that the caller - * immediately do a receive unconditionaly + * immediately do a receive unconditionally * waiting for the message with the reference; * otherwise, next receive will *not* work * as expected! diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index ef822dbe8ce7..7df1e6a841bc 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2022. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -37,7 +37,6 @@ #include "erl_mseg.h" #include "erl_threads.h" #include "erl_hl_timer.h" -#include "erl_mtrace.h" #include "erl_printf_term.h" #include "erl_misc_utils.h" #include "packet_parser.h" @@ -53,6 +52,7 @@ #include "erl_osenv.h" #include "erl_proc_sig_queue.h" #include "beam_load.h" +#include "erl_global_literals.h" #include "jit/beam_asm.h" @@ -132,12 +132,6 @@ static int modified_sched_thread_suggested_stack_size = 0; Eterm erts_init_process_id = ERTS_INVALID_PID; -/* - * Note about VxWorks: All variables must be initialized by executable code, - * not by an initializer. Otherwise a new instance of the emulator will - * inherit previous values. - */ - extern void erl_crash_dump_v(char *, int, const char *, va_list); #ifdef __WIN32__ extern void ConNormalExit(void); @@ -168,7 +162,7 @@ int erts_initialized = 0; int H_MIN_SIZE; /* The minimum heap grain */ int BIN_VH_MIN_SIZE; /* The minimum binary virtual*/ -int H_MAX_SIZE; /* The maximum heap size */ +Uint H_MAX_SIZE; /* The maximum heap size */ int H_MAX_FLAGS; /* The maximum heap flags */ Uint32 erts_debug_flags; /* Debug flags. */ @@ -281,7 +275,7 @@ static ERTS_INLINE void set_default_time_adj(int *time_correction_p, ErtsTimeWarpMode *time_warp_mode_p) { *time_correction_p = 1; - *time_warp_mode_p = ERTS_NO_TIME_WARP_MODE; + *time_warp_mode_p = ERTS_MULTI_TIME_WARP_MODE; if (!erts_check_time_adj_support(*time_correction_p, *time_warp_mode_p)) { *time_correction_p = 0; @@ -302,6 +296,17 @@ void erl_error(const char *fmt, va_list args) static int early_init(int *argc, char **argv); +static void init_constant_literals(void) { + Eterm* hp = erts_alloc_global_literal(ERTS_LIT_EMPTY_TUPLE, 2); + Eterm tuple; + hp[0] = make_arityval_zero(); + hp[1] = make_arityval_zero(); + tuple = make_tuple(hp); + erts_register_global_literal(ERTS_LIT_EMPTY_TUPLE, tuple); + ERTS_GLOBAL_LIT_EMPTY_TUPLE = + erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); +} + static void erl_init(int ncpu, int proc_tab_sz, @@ -315,6 +320,7 @@ erl_init(int ncpu, int node_tab_delete_delay, ErtsDbSpinCount db_spin_count) { + init_constant_literals(); erts_monitor_link_init(); erts_bif_unique_init(); erts_proc_sig_queue_init(); /* Must be after erts_bif_unique_init(); */ @@ -381,6 +387,8 @@ erl_init(int ncpu, packet_parser_init(); erl_nif_init(); erts_msacc_init(); + beamfile_init(); + erts_late_init_external(); } static Eterm @@ -624,6 +632,7 @@ void erts_usage(void) H_DEFAULT_MAX_SIZE); erts_fprintf(stderr, "-hmaxk bool enable or disable kill at max heap size (default true)\n"); erts_fprintf(stderr, "-hmaxel bool enable or disable error_logger report at max heap size (default true)\n"); + erts_fprintf(stderr, "-hmaxib bool enable or disable including off-heap binaries into max heap size (default false)\n"); erts_fprintf(stderr, "-hpds size set initial process dictionary size (default %d)\n", erts_pd_initial_size); erts_fprintf(stderr, "-hmqd val set default message queue data flag for processes;\n"); @@ -644,7 +653,8 @@ void erts_usage(void) #ifdef BEAMASM erts_fprintf(stderr, "-JDdump bool enable or disable dumping of generated assembly code for each module loaded\n"); - erts_fprintf(stderr, "-JPperf bool enable or disable support for perf on Linux\n"); + erts_fprintf(stderr, "-JPperf true|false|dump|map|fp|no_fp enable or disable support for perf on Linux\n"); + erts_fprintf(stderr, "-JMsingle bool enable the use of single-mapped RWX memory for JIT:ed code\n"); erts_fprintf(stderr, "\n"); #endif @@ -656,6 +666,7 @@ void erts_usage(void) erts_fprintf(stderr, "\n"); erts_fprintf(stderr, "-pc control what characters are considered printable (default latin1)\n"); + erts_fprintf(stderr, "-pad bool set default process async data (default false)\n"); erts_fprintf(stderr, "-P number set maximum number of processes on this node;\n"); erts_fprintf(stderr, " valid range is [%d-%d]\n", ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES); @@ -683,6 +694,7 @@ void erts_usage(void) erts_fprintf(stderr, " none | very_short | short | medium | long | very_long\n"); erts_fprintf(stderr, "-scl bool enable/disable compaction of scheduler load\n"); erts_fprintf(stderr, "-sct cput set cpu topology\n"); + erts_fprintf(stderr, "-ssrct skip reading cpu topology\n"); erts_fprintf(stderr, "-secio bool enable or disable eager check I/O scheduling\n"); #if ERTS_HAVE_SCHED_UTIL_BALANCING_SUPPORT_OPT erts_fprintf(stderr, "-sub bool enable or disable scheduler utilization balancing\n"); @@ -834,6 +846,7 @@ early_init(int *argc, char **argv) /* int decentralized_counter_groups; char envbuf[21]; /* enough for any 64-bit integer */ size_t envbufsz; + int skip_read_topology = 0; erts_save_emu_args(*argc, argv); @@ -973,7 +986,18 @@ early_init(int *argc, char **argv) /* } break; } - + case 's' : { + char *sub_param = argv[i]+2; + if (has_prefix("srct", sub_param)) { + /* skip reading cpu topology */ + skip_read_topology = 1; + } + else if (has_prefix("ct", sub_param)) { + /* cpu topology */ + skip_read_topology = 1; + } + break; + } case 'S' : if (argv[i][2] == 'P') { int ptot, ponln; @@ -1270,7 +1294,8 @@ early_init(int *argc, char **argv) /* max_reader_groups, &reader_groups, max_decentralized_counter_groups, - &decentralized_counter_groups); + &decentralized_counter_groups, + skip_read_topology); erts_flxctr_setup(decentralized_counter_groups); { erts_thr_late_init_data_t elid = ERTS_THR_LATE_INIT_DATA_DEF_INITER; @@ -1396,11 +1421,28 @@ erl_start(int argc, char **argv) erts_usage(); } erts_set_printable_characters(printable_chars); - break; - } else { - erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); - erts_usage(); } + else { + char *sub_param = argv[i]+2; + if (has_prefix("ad", sub_param)) { + arg = get_arg(sub_param+2, argv[i+1], &i); + if (sys_strcmp("true", arg) == 0) { + erts_default_spo_flags |= SPO_ASYNC_DIST; + } + else if (sys_strcmp("false", arg) == 0) { + erts_default_spo_flags &= ~SPO_ASYNC_DIST; + } + else { + erts_fprintf(stderr, "bad async dist value %s\n", arg); + erts_usage(); + } + } + else { + erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); + erts_usage(); + } + } + break; case 'f': if (!sys_strncmp(argv[i],"-fn",3)) { int warning_type = ERL_FILENAME_WARNING_WARNING; @@ -1540,6 +1582,8 @@ erl_start(int argc, char **argv) * h|max - max_heap_size * h|maxk - max_heap_kill * h|maxel - max_heap_error_logger + * h|maxib - map_heap_include_shared_binaries + * * */ if (has_prefix("mbs", sub_param)) { @@ -1602,9 +1646,23 @@ erl_start(int argc, char **argv) erts_usage(); } VERBOSE(DEBUG_SYSTEM, ("using max heap log %d\n", H_MAX_FLAGS)); + } else if (has_prefix("maxib", sub_param)) { + arg = get_arg(sub_param+5, argv[i+1], &i); + if (sys_strcmp(arg,"true") == 0) { + H_MAX_FLAGS |= MAX_HEAP_SIZE_INCLUDE_OH_BINS; + } else if (sys_strcmp(arg,"false") == 0) { + H_MAX_FLAGS &= ~MAX_HEAP_SIZE_INCLUDE_OH_BINS; + } else { + erts_fprintf(stderr, "bad max heap include bins %s\n", arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, ("using max heap log %d\n", H_MAX_FLAGS)); } else if (has_prefix("max", sub_param)) { + Sint hMaxSize; + char *rest; arg = get_arg(sub_param+3, argv[i+1], &i); - if ((H_MAX_SIZE = atoi(arg)) < 0) { + hMaxSize = ErtsStrToSint(arg, &rest, 10); + if (hMaxSize < 0 || hMaxSize > MAX_SMALL) { erts_fprintf(stderr, "bad max heap size %s\n", arg); erts_usage(); } @@ -1614,6 +1672,7 @@ erl_start(int argc, char **argv) arg, H_MIN_SIZE); erts_usage(); } + H_MAX_SIZE = hMaxSize; VERBOSE(DEBUG_SYSTEM, ("using max heap size %d\n", H_MAX_SIZE)); } else { /* backward compatibility */ @@ -1688,13 +1747,18 @@ erl_start(int argc, char **argv) #ifdef HAVE_LINUX_PERF_SUPPORT if (sys_strcmp(arg, "true") == 0) { - erts_jit_perf_support = BEAMASM_PERF_DUMP|BEAMASM_PERF_MAP; + erts_jit_perf_support |= BEAMASM_PERF_ENABLED; } else if (sys_strcmp(arg, "false") == 0) { - erts_jit_perf_support = 0; + erts_jit_perf_support &= ~BEAMASM_PERF_ENABLED; } else if (sys_strcmp(arg, "dump") == 0) { - erts_jit_perf_support = BEAMASM_PERF_DUMP; + erts_jit_perf_support |= BEAMASM_PERF_DUMP; } else if (sys_strcmp(arg, "map") == 0) { - erts_jit_perf_support = BEAMASM_PERF_MAP; + erts_jit_perf_support |= BEAMASM_PERF_MAP | + BEAMASM_PERF_FP; + } else if (sys_strcmp(arg, "fp") == 0) { + erts_jit_perf_support |= BEAMASM_PERF_FP; + } else if (sys_strcmp(arg, "no_fp") == 0) { + erts_jit_perf_support &= ~BEAMASM_PERF_FP; } else { erts_fprintf(stderr, "bad +JPperf support flag %s\n", arg); erts_usage(); @@ -1705,6 +1769,23 @@ erl_start(int argc, char **argv) #endif } break; + case 'M': + sub_param++; + if (has_prefix("single", sub_param)) { + arg = get_arg(sub_param+6, argv[i + 1], &i); + if (sys_strcmp(arg, "true") == 0) { + erts_jit_single_map = 1; + } else if (sys_strcmp(arg, "false") == 0) { + erts_jit_single_map = 0; + } else { + erts_fprintf(stderr, "bad +JMsingle support flag %s\n", arg); + erts_usage(); + } + } else { + erts_fprintf(stderr, "bad +JM sub-option %s\n", arg); + erts_usage(); + } + break; default: erts_fprintf(stderr, "invalid JIT option %s\n", argv[i]); break; @@ -1789,8 +1870,8 @@ erl_start(int argc, char **argv) errno = 0; port_tab_sz = strtol(arg, NULL, 10); if (errno != 0 - || port_tab_sz < ERTS_MIN_PROCESSES - || ERTS_MAX_PROCESSES < port_tab_sz) { + || port_tab_sz < ERTS_MIN_PORTS + || ERTS_MAX_PORTS < port_tab_sz) { erts_fprintf(stderr, "bad number of ports %s\n", arg); erts_usage(); } @@ -2099,6 +2180,9 @@ erl_start(int argc, char **argv) } erts_runq_supervision_interval = val; } + else if (has_prefix("srct", sub_param)) { + /* skip reading cpu topology, already handled */ + } else { erts_fprintf(stderr, "bad scheduling option %s\n", argv[i]); erts_usage(); @@ -2491,18 +2575,26 @@ erl_start(int argc, char **argv) __decl_noreturn void erts_thr_fatal_error(int err, const char *what) { const char *errstr = err ? strerror(err) : NULL; - erts_fprintf(stderr, - "Failed to %s: %s%s(%d)\n", - what, - errstr ? errstr : "", - errstr ? " " : "", - err); - abort(); + if (err == ENOMEM) { + erts_exit(ERTS_DUMP_EXIT, "Failed to %s: %s%s(%d)\n", + what, + errstr ? errstr : "", + errstr ? " " : "", + err); + } else { + erts_fprintf(stderr, + "Failed to %s: %s%s(%d)\n", + what, + errstr ? errstr : "", + errstr ? " " : "", + err); + abort(); + } } static void -system_cleanup(int flush_async) +system_cleanup(int flush) { /* * Make sure only one thread exits the runtime system. @@ -2532,27 +2624,43 @@ system_cleanup(int flush_async) * (in threaded non smp case). */ - if (!flush_async - || !erts_initialized - ) + if (!flush || !erts_initialized) return; + /* + * We only flush as a result of calling erts_halt() (which in turn + * is called from the erlang:halt() BIF when flushing is enabled); + * otherwise, flushing wont work properly. If erts_halt() has + * been called, 'erts_halt_code' won't equal INT_MIN... + */ + ASSERT(erts_halt_code != INT_MIN); + + /* + * Nif on-halt handlers may have been added after we initiated + * a halt. If so, make sure that these late added handlers are + * executed as well.. + */ + erts_nif_execute_on_halt(); + #ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_check_exact(NULL, 0); #endif erts_exit_flush_async(); + + /* + * Wait for all NIF calls with delayed halt functionality + * enabled to complete before we continue... + */ + erts_nif_wait_calls(); } static int erts_exit_code; static __decl_noreturn void __noreturn -erts_exit_vv(int n, int flush_async, const char *fmt, va_list args1, va_list args2) +erts_exit_vv(int n, int flush, const char *fmt, va_list args1, va_list args2) { - system_cleanup(flush_async); - - if (erts_mtrace_enabled) - erts_mtrace_exit((Uint32) n); + system_cleanup(flush); if (fmt != NULL && *fmt != '\0') erl_error(fmt, args2); /* Print error message. */ @@ -2565,25 +2673,25 @@ erts_exit_vv(int n, int flush_async, const char *fmt, va_list args1, va_list arg erl_crash_dump_v((char*) NULL, 0, fmt, args1); } - erts_exit_epilogue(); + erts_exit_epilogue(flush); } -__decl_noreturn void __noreturn erts_exit_epilogue(void) +__decl_noreturn void __noreturn erts_exit_epilogue(int flush) { int n = erts_exit_code; sys_tty_reset(n); if (n == ERTS_INTR_EXIT) - exit(0); + (void) (flush ? exit(0) : _exit(0)); else if (n == ERTS_DUMP_EXIT) ERTS_EXIT_AFTER_DUMP(1); else if (n == ERTS_ERROR_EXIT || n == ERTS_ABORT_EXIT) abort(); - exit(n); + (void) (flush ? exit(n) : _exit(n)); } -/* Exit without flushing async threads */ +/* Exit without flushing */ __decl_noreturn void __noreturn erts_exit(int n, const char *fmt, ...) { va_list args1, args2; @@ -2594,8 +2702,12 @@ __decl_noreturn void __noreturn erts_exit(int n, const char *fmt, ...) va_end(args1); } -/* Exit after flushing async threads */ -__decl_noreturn void __noreturn erts_flush_async_exit(int n, char *fmt, ...) +/* + * Exit after flushing. This is a continuation of erts_halt() and wont + * work properly if called by its own without proper initialization + * as made in erts_halt(). + */ +__decl_noreturn void __noreturn erts_flush_exit(int n, char *fmt, ...) { va_list args1, args2; va_start(args1, fmt); diff --git a/erts/emulator/beam/erl_io_queue.c b/erts/emulator/beam/erl_io_queue.c index 8010b223e9e2..c931e5ffdba9 100644 --- a/erts/emulator/beam/erl_io_queue.c +++ b/erts/emulator/beam/erl_io_queue.c @@ -413,7 +413,7 @@ SysIOVec* erts_ioq_peekq(ErtsIOQueue *q, int* vlenp) /* length of io-vector */ /* Fills a possibly deep list of chars and binaries into vec ** Small characters are first stored in the buffer buf of length ln ** binaries found are copied and linked into msoh -** Return vector length on succsess, +** Return vector length on success, ** -1 on overflow ** -2 on type error */ diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index db1e6e0e666b..75cfd3408b9f 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2021. All Rights Reserved. + * Copyright Ericsson AB 2005-2023. 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. @@ -33,9 +33,6 @@ # include "config.h" #endif -/* Needed for VxWorks va_arg */ -#include "sys.h" - #ifdef ERTS_ENABLE_LOCK_CHECK #include "erl_lock_check.h" @@ -61,7 +58,7 @@ typedef struct { * on initialization. Locks with small immediate Erlang terms should * be locked before locks with large immediate Erlang terms, and * locks with small addresses should be locked before locks with - * large addresses. The immediate terms and adresses (boxed pointers) + * large addresses. The immediate terms and addresses (boxed pointers) * are compared as unsigned integers not as Erlang terms. * * Once a spinlock or rw(spin)lock has been locked, the thread is not @@ -98,9 +95,11 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "proc_msgq", "pid" }, { "proc_btm", "pid" }, { "dist_entry_links", "address" }, + { "nif_load", NULL }, { "update_persistent_term_permission", NULL }, { "persistent_term_delete_permission", NULL }, - { "code_write_permission", NULL }, + { "code_stage_permission", NULL }, + { "code_mod_permission", NULL }, { "purge_state", NULL }, { "proc_status", "pid" }, { "proc_trace", "pid" }, @@ -111,6 +110,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "fun_tab", NULL }, { "environ", NULL }, { "release_literal_areas", NULL }, + { "on_halt", NULL }, { "drv_ev_state_grow", NULL, }, { "drv_ev_state", "address" }, { "safe_hash", "address" }, @@ -144,11 +144,9 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "port_table", NULL }, { "magic_ref_table", "address" }, { "pid_ref_table", "address" }, - { "mtrace_op", NULL }, { "instr_x", NULL }, { "instr", NULL }, { "dyn_lock_check", NULL }, - { "nif_load", NULL }, { "alcu_allocator", "index" }, { "mseg", NULL }, { "get_time", NULL }, @@ -162,13 +160,13 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "save_ops_lock", NULL }, #endif #endif - { "mtrace_buf", NULL }, { "os_monotonic_time", NULL }, { "erts_alloc_hard_debug", NULL }, { "hard_dbg_mseg", NULL }, { "perf", NULL }, { "jit_debug_descriptor", NULL }, - { "erts_mmap", NULL } + { "erts_mmap", NULL }, + { "proc_sig_queue_buffer", "address" } }; #define ERTS_LOCK_ORDER_SIZE \ @@ -532,7 +530,7 @@ unlock_of_not_locked(lc_thread_t *thr, erts_lc_lock_t *lck) static void lock_order_violation(lc_thread_t *thr, erts_lc_lock_t *lck) { - print_lock("Lock order violation occured when locking ", lck, "!\n"); + print_lock("Lock order violation occurred when locking ", lck, "!\n"); print_curr_locks(thr); print_lock_order(); lc_abort(); @@ -542,7 +540,7 @@ static void type_order_violation(char *op, lc_thread_t *thr, erts_lc_lock_t *lck) { - erts_fprintf(stderr, "Lock type order violation occured when "); + erts_fprintf(stderr, "Lock type order violation occurred when "); print_lock(op, lck, "!\n"); ASSERT(thr); print_curr_locks(thr); diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h index 4c50bd11f03e..a42fde3546f7 100644 --- a/erts/emulator/beam/erl_lock_count.h +++ b/erts/emulator/beam/erl_lock_count.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2020. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -78,7 +78,7 @@ typedef struct { } erts_lcnt_time_t; typedef struct { - /** @brief log2 array of nano seconds occurences */ + /** @brief log2 array of nano seconds occurrences */ Uint32 ns[ERTS_LCNT_HISTOGRAM_SLOT_SIZE]; } erts_lcnt_hist_t; @@ -261,12 +261,14 @@ int erts_lcnt_check_ref_installed(erts_lcnt_ref_t *ref); /** @brief Convenience macro to re/enable counting on an already initialized * reference. Don't forget to specify the lock type in \c flags! */ -#define erts_lcnt_install_new_lock_info(ref, name, id, flags) \ - if(!erts_lcnt_check_ref_installed(ref)) { \ - erts_lcnt_lock_info_carrier_t *__carrier; \ - __carrier = erts_lcnt_create_lock_info_carrier(1);\ - erts_lcnt_init_lock_info_idx(__carrier, 0, name, id, flags); \ - erts_lcnt_install(ref, __carrier);\ +#define erts_lcnt_install_new_lock_info(ref, name, id, flags) \ + do { \ + if(!erts_lcnt_check_ref_installed(ref)) { \ + erts_lcnt_lock_info_carrier_t *__carrier; \ + __carrier = erts_lcnt_create_lock_info_carrier(1); \ + erts_lcnt_init_lock_info_idx(__carrier, 0, name, id, flags); \ + erts_lcnt_install(ref, __carrier); \ + } \ } while(0) erts_lcnt_lock_info_carrier_t *erts_lcnt_create_lock_info_carrier(int count); diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 5ab8b3075de5..0a7d724ebe5e 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -34,6 +34,7 @@ #include "error.h" #include "bif.h" #include "erl_binary.h" +#include "erl_global_literals.h" #include "erl_map.h" @@ -149,28 +150,38 @@ void erts_init_map(void) { */ BIF_RETTYPE map_size_1(BIF_ALIST_1) { - if (is_flatmap(BIF_ARG_1)) { - flatmap_t *mp = (flatmap_t*)flatmap_val(BIF_ARG_1); - BIF_RET(make_small(flatmap_get_size(mp))); - } else if (is_hashmap(BIF_ARG_1)) { - Eterm *head; - Uint size; + Sint size = erts_map_size(BIF_ARG_1); - head = hashmap_val(BIF_ARG_1); - size = head[1]; + /* NOTE: The JIT has its own implementation of this BIF. */ - /* - * As long as a small has 28 bits (on a 32-bit machine) for - * the integer itself, it is impossible to build a map whose - * size would not fit in a small. Add an assertion in case we - * ever decreases the number of bits in a small. - */ - ASSERT(IS_USMALL(0, size)); - BIF_RET(make_small(size)); + if (size < 0) { + BIF_P->fvalue = BIF_ARG_1; + BIF_ERROR(BIF_P, BADMAP); } - BIF_P->fvalue = BIF_ARG_1; - BIF_ERROR(BIF_P, BADMAP); + /* + * As long as a small has 28 bits (on a 32-bit machine) for + * the integer itself, it is impossible to build a map whose + * size would not fit in a small. Add an assertion in case we + * ever decreases the number of bits in a small. + */ + ASSERT(IS_USMALL(0, size)); + BIF_RET(make_small(size)); +} + +Sint +erts_map_size(Eterm map) +{ + if (is_flatmap(map)) { + flatmap_t *mp = (flatmap_t*)flatmap_val(map); + return (Sint) flatmap_get_size(mp); + } + else if (is_hashmap(map)) { + Eterm *head = hashmap_val(map); + return (Sint) head[1]; + } + + return -1; } /* maps:find/2 @@ -259,6 +270,7 @@ BIF_RETTYPE maps_get_2(BIF_ALIST_2) { } BIF_RETTYPE map_get_2(BIF_ALIST_2) { + /* NOTE: The JIT has its own implementation of this BIF. */ BIF_RET(maps_get_2(BIF_CALL_ARGS)); } @@ -367,10 +379,14 @@ static Eterm flatmap_from_validated_list(Process *p, Eterm list, Eterm fill_valu Sint idx = 0; - hp = HAlloc(p, 3 + 1 + (2 * size)); + hp = HAlloc(p, 3 + (size == 0 ? 0 : 1) + (2 * size)); thp = hp; - keys = make_tuple(hp); - *hp++ = make_arityval(size); + if (size == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + keys = make_tuple(hp); + *hp++ = make_arityval(size); + } ks = hp; hp += size; mp = (flatmap_t*)hp; @@ -421,7 +437,9 @@ static Eterm flatmap_from_validated_list(Process *p, Eterm list, Eterm fill_valu idx = size; - while(idx > 0 && (c = CMP_TERM(key,ks[idx-1])) < 0) { idx--; } + while(idx > 0 && (c = erts_cmp_flatmap_keys(key,ks[idx-1])) < 0) { + idx--; + } if (c == 0) { /* last compare was equal, @@ -526,14 +544,14 @@ static Eterm hashmap_from_validated_list(Process *p, YCF_SPECIAL_CODE_START(ON_DESTROY_STATE); { if (hxns != NULL) { - /* Execution of this function got destoyed while yielding in + /* Execution of this function got destroyed while yielding in the loop above */ erts_free(ERTS_ALC_T_MAP_TRAP, (void *) hxns); } } YCF_SPECIAL_CODE_END(); erts_free(ERTS_ALC_T_MAP_TRAP, (void *) hxns); - /* Memory managment depends on the line below */ + /* Memory management depends on the line below */ hxns = NULL; ERTS_VERIFY_UNUSED_TEMP_ALLOC(p); @@ -548,7 +566,7 @@ static Eterm hashmap_from_validated_list(Process *p, flatmap_t *mp; Eterm keys; Uint n = hashmap_size(res); - + ASSERT(n > 0); /* build flat structure */ hp = HAlloc(p, 3 + 1 + (2 * n)); keys = make_tuple(hp); @@ -656,40 +674,62 @@ Eterm erts_hashmap_from_array(ErtsHeapFactory* factory, Eterm *leafs, Uint n, return res; } -Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0, Uint n) +static ERTS_INLINE Eterm +from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks, Eterm *vs, + Uint n, flatmap_t **fmpp) { if (n <= MAP_SMALL_MAP_LIMIT) { - Eterm *ks, *vs, *hp; - flatmap_t *mp; + Eterm *hp; + flatmap_t *fmp; Eterm keys; - hp = erts_produce_heap(factory, 3 + 1 + (2 * n), 0); - keys = make_tuple(hp); - *hp++ = make_arityval(n); - ks = hp; - hp += n; - mp = (flatmap_t*)hp; - hp += MAP_HEADER_FLATMAP_SZ; - vs = hp; + if (n == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + hp = erts_produce_heap(factory, MAP_HEADER_FLATMAP_SZ + n, 0); + } + else { + hp = erts_produce_heap(factory, 1 + MAP_HEADER_FLATMAP_SZ + 2*n, 0); + keys = make_tuple(hp); + *hp++ = make_arityval(n); + sys_memcpy((void *) hp, + (void *) ks, + n * sizeof(Eterm)); + hp += n; + } - mp->thing_word = MAP_HEADER_FLATMAP; - mp->size = n; - mp->keys = keys; + fmp = (flatmap_t*)hp; + hp += MAP_HEADER_FLATMAP_SZ; - sys_memcpy(ks, ks0, n * sizeof(Eterm)); - sys_memcpy(vs, vs0, n * sizeof(Eterm)); + fmp->thing_word = MAP_HEADER_FLATMAP; + fmp->size = n; + fmp->keys = keys; - if (!erts_validate_and_sort_flatmap(mp)) { - return THE_NON_VALUE; - } + sys_memcpy((void *) hp, (void *) vs, n * sizeof(Eterm)); - return make_flatmap(mp); + *fmpp = fmp; + return THE_NON_VALUE; } else { - return erts_hashmap_from_ks_and_vs(factory, ks0, vs0, n); + *fmpp = NULL; + return erts_hashmap_from_ks_and_vs(factory, ks, vs, n); } - return THE_NON_VALUE; } +Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks, Eterm *vs, Uint n) +{ + Eterm res; + flatmap_t *fmp; + + res = from_ks_and_vs(factory, ks, vs, n, &fmp); + if (fmp) { + if (erts_validate_and_sort_flatmap(fmp)) { + res = make_flatmap(fmp); + } + else { + res = THE_NON_VALUE; + } + } + return res; +} Eterm erts_hashmap_from_ks_and_vs_extra(ErtsHeapFactory *factory, Eterm *ks, Eterm *vs, Uint n, @@ -747,14 +787,7 @@ static Eterm hashmap_from_unsorted_array(ErtsHeapFactory* factory, Uint cx; Eterm res; - if (n == 0) { - Eterm *hp; - hp = erts_produce_heap(factory, 2, 0); - hp[0] = MAP_HEADER_HAMT_HEAD_BITMAP(0); - hp[1] = 0; - - return make_hashmap(hp); - } + ASSERT(n > 0); /* sort and compact array (remove non-unique entries) */ erts_qsort(hxns, n, sizeof(hxnode_t), hxnodecmp); @@ -882,7 +915,7 @@ static Eterm hashmap_from_sorted_unique_array(ErtsHeapFactory* factory, YCF_SPECIAL_CODE_START(ON_DESTROY_STATE); { if (tmp != NULL) { - /* Execution of this function got destoyed while yielding in + /* Execution of this function got destroyed while yielding in the loop above */ erts_free(temp_memory_allocator, (void *) tmp); } @@ -1171,6 +1204,7 @@ BIF_RETTYPE maps_is_key_2(BIF_ALIST_2) { } BIF_RETTYPE is_map_key_2(BIF_ALIST_2) { + /* NOTE: The JIT has its own implementation of this BIF. */ BIF_RET(maps_is_key_2(BIF_CALL_ARGS)); } @@ -1262,34 +1296,31 @@ BIF_RETTYPE maps_merge_2(BIF_ALIST_2) { BIF_ERROR(BIF_P, BADMAP); } -static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { +static Eterm flatmap_merge(Process *p, Eterm map1, Eterm map2) { Eterm *hp,*thp; - Eterm tup; Eterm *ks,*vs,*ks1,*vs1,*ks2,*vs2; flatmap_t *mp1,*mp2,*mp_new; Uint n,n1,n2,i1,i2,need,unused_size=0; Sint c = 0; - mp1 = (flatmap_t*)flatmap_val(nodeA); - mp2 = (flatmap_t*)flatmap_val(nodeB); + mp1 = (flatmap_t*)flatmap_val(map1); + mp2 = (flatmap_t*)flatmap_val(map2); n1 = flatmap_get_size(mp1); n2 = flatmap_get_size(mp2); - if (n1 == 0) return nodeB; - if (n2 == 0) return nodeA; + if (n1 == 0) return map2; + if (n2 == 0) return map1; need = MAP_HEADER_FLATMAP_SZ + 1 + 2 * (n1 + n2); hp = HAlloc(p, need); - thp = hp; - tup = make_tuple(thp); - ks = hp + 1; hp += 1 + n1 + n2; mp_new = (flatmap_t*)hp; hp += MAP_HEADER_FLATMAP_SZ; vs = hp; hp += n1 + n2; + thp = hp; + ks = hp + 1; hp += 1 + n1 + n2; mp_new->thing_word = MAP_HEADER_FLATMAP; - mp_new->size = 0; - mp_new->keys = tup; + mp_new->keys = make_tuple(thp); i1 = 0; i2 = 0; ks1 = flatmap_get_keys(mp1); @@ -1298,7 +1329,7 @@ static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { vs2 = flatmap_get_values(mp2); while(i1 < n1 && i2 < n2) { - c = CMP_TERM(ks1[i1],ks2[i2]); + c = (ks1[i1] == ks2[i2]) ? 0 : erts_cmp_flatmap_keys(ks1[i1],ks2[i2]); if (c == 0) { /* use righthand side arguments map value, * but advance both maps */ @@ -1329,20 +1360,42 @@ static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { i2++; } - if (unused_size) { - /* the key tuple is embedded in the heap, write a bignum to clear it. - * - * release values as normal since they are on the top of the heap - * size = n1 + n1 - unused_size - */ - - *ks = make_pos_bignum_header(unused_size - 1); - HRelease(p, vs + unused_size, vs); - } - n = n1 + n2 - unused_size; - *thp = make_arityval(n); mp_new->size = n; + *thp = make_arityval(n); + + if (unused_size ) { + Eterm* hp_release; + + if (n == n2) { + /* Reuse entire map2 */ + if (n == n1 + && erts_is_literal(mp1->keys, boxed_val(mp1->keys)) + && !erts_is_literal(mp2->keys, boxed_val(mp2->keys))) { + /* + * We want map2, but map1 has a nice literal key tuple. + * Solution: MUTATE HEAP to get both. + */ + ASSERT(eq(mp1->keys, mp2->keys)); + mp2->keys = mp1->keys; + } + HRelease(p, hp, (Eterm *)mp_new); + return map2; + } + else if (n == n1) { + /* Reuse key tuple of map1 */ + mp_new->keys = mp1->keys; + /* Release key tuple and unused values */ + hp_release = thp - unused_size; + } + else { + /* Unused values are embedded in the heap, write bignum to clear them */ + *vs = make_pos_bignum_header(unused_size - 1); + /* Release unused keys */ + hp_release = ks; + } + HRelease(p, hp, hp_release); + } /* Reshape map to a hashmap if the map exceeds the limit */ @@ -1921,14 +1974,16 @@ int erts_maps_take(Process *p, Eterm key, Eterm map, * Allocate key tuple first. */ - need = n + 1 - 1 + 3 + n - 1; /* tuple - 1 + map - 1 */ + need = n + ((n-1) == 0 ? 0 : 1) - 1 + 3 + n - 1; /* tuple - 1 + map - 1 */ hp_start = HAlloc(p, need); thp = hp_start; - mhp = thp + n; /* offset with tuple heap size */ - - tup = make_tuple(thp); - *thp++ = make_arityval(n - 1); - + mhp = thp + n + ((n-1) == 0 ? -1 : 0); /* offset with tuple heap size */ + if ((n-1) == 0) { + tup = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + tup = make_tuple(thp); + *thp++ = make_arityval(n - 1); + } *res = make_flatmap(mhp); *mhp++ = MAP_HEADER_FLATMAP; *mhp++ = n - 1; @@ -2145,7 +2200,7 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) { ASSERT(n >= 0); /* copy map in order */ - while (n && ((c = CMP_TERM(*ks, key)) < 0)) { + while (n && ((c = erts_cmp_flatmap_keys(*ks, key)) < 0)) { *shp++ = *ks++; *hp++ = *vs++; n--; @@ -2929,7 +2984,7 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, } unroll: - /* the size is bounded and atleast one less than the previous size */ + /* the size is bounded and at least one less than the previous size */ size -= 1; n = hashmap_size(map) - 1; @@ -3144,7 +3199,7 @@ int erts_validate_and_sort_flatmap(flatmap_t* mp) for (ix = 1; ix < sz; ix++) { jx = ix; - while( jx > 0 && (c = CMP_TERM(ks[jx],ks[jx-1])) <= 0 ) { + while( jx > 0 && (c = erts_cmp_flatmap_keys(ks[jx],ks[jx-1])) <= 0 ) { /* identical key -> error */ if (c == 0) return 0; @@ -3175,7 +3230,7 @@ void erts_usort_flatmap(flatmap_t* mp) for (ix = 1; ix < sz; ix++) { jx = ix; - while( jx > 0 && (c = CMP_TERM(ks[jx],ks[jx-1])) <= 0 ) { + while( jx > 0 && (c = erts_cmp_flatmap_keys(ks[jx],ks[jx-1])) <= 0 ) { /* identical key -> remove it */ if (c == 0) { sys_memmove(ks+jx-1,ks+jx,(sz-ix)*sizeof(Eterm)); @@ -3291,10 +3346,17 @@ BIF_RETTYPE erts_internal_term_type_1(BIF_ALIST_1) { switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: BIF_RET(ERTS_MAKE_AM("tuple")); - case EXPORT_SUBTAG: - BIF_RET(ERTS_MAKE_AM("export")); case FUN_SUBTAG: - BIF_RET(ERTS_MAKE_AM("fun")); + { + ErlFunThing *funp = (ErlFunThing *)fun_val(obj); + + if (is_local_fun(funp)) { + BIF_RET(ERTS_MAKE_AM("fun")); + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + BIF_RET(ERTS_MAKE_AM("export")); + } + } case MAP_SUBTAG: switch (MAP_HEADER_TYPE(hdr)) { case MAP_HEADER_TAG_FLATMAP_HEAD : @@ -3541,7 +3603,7 @@ static Eterm hashmap_bld_tuple_uint(Uint **hpp, Uint *szp, Uint n, Uint nums[]) * we avoid yielding in collision nodes. * * Once the leaf has been found, the return value is created - * by traversing the tree using the the stack that was built + * by traversing the tree using the stack that was built * when searching for the first leaf to return. * * The index can become a bignum, which complicates the code @@ -3593,6 +3655,60 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) { BIF_ERROR(BIF_P, BADARG); } + /* Handle an ordered iterator. */ + if (type == iterator && (is_list(path) || is_nil(path))) { +#ifdef DEBUG +#define ORDERED_ITER_FACTOR 200 +#else +#define ORDERED_ITER_FACTOR 32 +#endif + int orig_elems = MAX(1, ERTS_BIF_REDS_LEFT(BIF_P) / ORDERED_ITER_FACTOR); + int elems = orig_elems; + Uint needed = 4 * elems + 2; + Eterm *hp = HAlloc(BIF_P, needed); + Eterm *hp_end = hp + needed; + Eterm result = am_none; + Eterm *patch_ptr = &result; + + while (is_list(path) && elems > 0) { + Eterm *lst = list_val(path); + Eterm key = CAR(lst); + Eterm res = make_tuple(hp); + const Eterm *value = erts_maps_get(key, map); + if (!value) { + ordered_badarg: + HRelease(BIF_P, hp_end, hp); + BIF_ERROR(BIF_P, BADARG); + } + hp[0] = make_arityval(3); + hp[1] = key; + hp[2] = *value; + *patch_ptr = res; + patch_ptr = &hp[3]; + hp += 4; + path = CDR(lst); + elems--; + } + + if (is_list(path)) { + Eterm next = CONS(hp, path, map); + hp += 2; + ASSERT(hp == hp_end); + *patch_ptr = next; + BUMP_ALL_REDS(BIF_P); + ASSERT(is_tuple(result)); + BIF_RET(result); + } else if (is_nil(path)) { + HRelease(BIF_P, hp_end, hp); + *patch_ptr = am_none; + BUMP_REDS(BIF_P, ORDERED_ITER_FACTOR * (orig_elems - elems)); + ASSERT(result == am_none || is_tuple(result)); + BIF_RET(result); + } else { + goto ordered_badarg; + } + } + if (is_flatmap(map)) { Uint n; Eterm *ks,*vs, res, *hp; diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index 9832cd9765d9..f046ae2093db 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -24,7 +24,7 @@ #include "sys.h" -/* instrinsic wrappers */ +/* intrinsic wrappers */ #if ERTS_AT_LEAST_GCC_VSN__(3, 4, 0) #define hashmap_clz(x) ((Uint32) __builtin_clz((unsigned int)(x))) #define hashmap_bitcount(x) ((Uint32) __builtin_popcount((unsigned int) (x))) @@ -112,6 +112,8 @@ const Eterm *erts_maps_get(Eterm key, Eterm map); const Eterm *erts_hashmap_get(Uint32 hx, Eterm key, Eterm map); +Sint erts_map_size(Eterm map); + /* hamt nodes v2.0 * * node :: leaf | array | bitmap diff --git a/erts/emulator/beam/erl_md5.c b/erts/emulator/beam/erl_md5.c index 8d0352a3673f..2a4e026d9ca1 100644 --- a/erts/emulator/beam/erl_md5.c +++ b/erts/emulator/beam/erl_md5.c @@ -129,10 +129,9 @@ void MD5Init(MD5_CTX* context) * operation, processing another message block, and updating the * context. */ -void MD5Update (context, input, inputLen) - MD5_CTX *context; /* context */ - unsigned char *input; /* input block */ - unsigned int inputLen; /* length of input block */ +void MD5Update (MD5_CTX *context, + unsigned char *input, /* input block */ + unsigned int inputLen) /* length of input block */ { unsigned int i, index, partLen; @@ -172,12 +171,11 @@ void MD5Update (context, input, inputLen) } /* - * MD5 finalization. Ends an MD5 message-digest operation, writing the + * MD5 finalization. Ends an MD5 message-digest operation, writing the message digest and zeroizing the context. */ -void MD5Final (digest, context) - unsigned char digest[16]; /* message digest */ - MD5_CTX *context; /* context */ +void MD5Final (unsigned char digest[16], /* message digest */ + MD5_CTX *context) /* context */ { unsigned char bits[8]; unsigned int index, padLen; @@ -213,9 +211,7 @@ void MD5Final (digest, context) /* * MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform (state, block) - Uint32 state[4]; - unsigned char block[64]; +static void MD5Transform (Uint32 state[4], unsigned char block[64]) { Uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; @@ -308,10 +304,7 @@ static void MD5Transform (state, block) * Encodes input (Uint32) into output (unsigned char). Assumes len is * a multiple of 4. */ -static void Encode (output, input, len) - unsigned char *output; - Uint32 *input; - unsigned int len; +static void Encode (unsigned char *output, Uint32 *input, unsigned int len) { unsigned int i, j; @@ -327,10 +320,7 @@ static void Encode (output, input, len) * Decodes input (unsigned char) into output (Uint32). Assumes len is * a multiple of 4. */ -static void Decode (output, input, len) - Uint32 *output; - unsigned char *input; - unsigned int len; +static void Decode (Uint32 *output, unsigned char *input, unsigned int len) { unsigned int i, j; diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 2e2cccf5ce3d..e9d70f377053 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2022. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -161,19 +161,22 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size, void -erts_cleanup_offheap(ErlOffHeap *offheap) +erts_cleanup_offheap_list(struct erl_off_heap_header* first) { union erl_off_heap_ptr u; - for (u.hdr = offheap->first; u.hdr; u.hdr = u.hdr->next) { + for (u.hdr = first; u.hdr; u.hdr = u.hdr->next) { switch (thing_subtag(u.hdr->thing_word)) { case REFC_BINARY_SUBTAG: erts_bin_release(u.pb->val); break; case FUN_SUBTAG: - if (erts_refc_dectest(&u.fun->fe->refc, 0) == 0) { - erts_erase_fun_entry(u.fun->fe); - } + /* We _KNOW_ that this is a local fun, otherwise it would not + * be part of the off-heap list. */ + ASSERT(is_local_fun(u.fun)); + if (erts_refc_dectest(&u.fun->entry.fun->refc, 0) == 0) { + erts_erase_fun_entry(u.fun->entry.fun); + } break; case REF_SUBTAG: ASSERT(is_magic_ref_thing(u.hdr)); @@ -187,6 +190,13 @@ erts_cleanup_offheap(ErlOffHeap *offheap) } } +void +erts_cleanup_offheap(ErlOffHeap *offheap) +{ + erts_cleanup_offheap_list(offheap->first); +} + + void free_message_buffer(ErlHeapFragment* bp) { @@ -268,14 +278,14 @@ erts_realloc_shrink_message(ErtsMessage *mp, Uint sz, Eterm *brefs, Uint brefs_s void erts_queue_dist_message(Process *rcvr, - ErtsProcLocks rcvr_locks, - ErtsDistExternal *dist_ext, + ErtsProcLocks rcvr_locks, + ErtsDistExternal *dist_ext, ErlHeapFragment *hfrag, - Eterm token, + Eterm token, Eterm from) { - ErtsMessage* mp; erts_aint_t state; + ErtsMessage *mp; ERTS_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); @@ -310,40 +320,63 @@ erts_queue_dist_message(Process *rcvr, #endif ERL_MESSAGE_TOKEN(mp) = token; - if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { - if (erts_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) { - ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; - ErtsProcLocks unlocks = - rcvr_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ); - if (unlocks) { - erts_proc_unlock(rcvr, unlocks); - need_locks |= unlocks; - } - erts_proc_lock(rcvr, need_locks); - } + /* If the sender is known, try to enqueue to an outer signal queue buffer + * instead of directly to the outer signal queue. + * + * Otherwise, the code below flushes the buffer before adding the message + * to ensure the signal order is maintained. This should only happen for + * the relatively uncommon DOP_SEND/DOP_SEND_TT operations. */ + if (is_external_pid(from) && + erts_proc_sig_queue_try_enqueue_to_buffer(from, rcvr, rcvr_locks, + mp, &mp->next, + NULL, 1)) { + return; } + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { + ErtsProcLocks unlocks; + + unlocks = rcvr_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ); + erts_proc_unlock(rcvr, unlocks); + + erts_proc_sig_queue_lock(rcvr); + } state = erts_atomic32_read_acqb(&rcvr->state); if (state & ERTS_PSFLG_EXITING) { - if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) - erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); - /* Drop message if receiver is exiting or has a pending exit ... */ - erts_cleanup_messages(mp); - } - else { - LINK_MESSAGE(rcvr, mp); + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { + erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); + } - if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) - erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); + /* Drop message if receiver is exiting or has a pending exit ... */ + erts_cleanup_messages(mp); + } else { + if (state & ERTS_PSFLG_OFF_HEAP_MSGQ) { + /* Install buffers for the outer message if the heuristic + * indicates that this is beneficial. It is best to do this as + * soon as possible to avoid as much contention as possible. */ + erts_proc_sig_queue_maybe_install_buffers(rcvr, state); + + /* Flush outer signal queue buffers, if such buffers are + * installed, to ensure that messages from the same + * process cannot be reordered. */ + erts_proc_sig_queue_flush_buffers(rcvr); + } + + LINK_MESSAGE(rcvr, mp, state); - erts_proc_notify_new_message(rcvr, rcvr_locks); + if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { + erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); + } + + erts_proc_notify_new_message(rcvr, rcvr_locks); } } /* Add messages last in message queue */ static void -queue_messages(Process* receiver, +queue_messages(Eterm from, + Process* receiver, ErtsProcLocks receiver_locks, ErtsMessage* first, ErtsMessage** last, @@ -367,8 +400,17 @@ queue_messages(Process* receiver, ERTS_LC_ASSERT((erts_proc_lc_my_proc_locks(receiver) & ERTS_PROC_LOCK_MSGQ) == (receiver_locks & ERTS_PROC_LOCK_MSGQ)); + /* + * Try to enqueue to an outer signal queue buffer instead of + * directly to the outer signal queue + */ + if (erts_proc_sig_queue_try_enqueue_to_buffer(from, receiver, receiver_locks, + first, last, NULL, len)) { + return; + } + if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) { - erts_proc_lock(receiver, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(receiver); locked_msgq = 1; } @@ -390,12 +432,27 @@ queue_messages(Process* receiver, return; } + /* + * Install buffers for the outer message if the heuristic + * indicates that this is beneficial. It is best to do this as + * soon as possible to avoid as much contention as possible. + */ + erts_proc_sig_queue_maybe_install_buffers(receiver, state); + if (last == &first->next) { ASSERT(len == 1); - LINK_MESSAGE(receiver, first); + if (state & ERTS_PSFLG_OFF_HEAP_MSGQ) { + /* + * Flush outer signal queue buffers, if such buffers are + * installed, to ensure that messages from the same + * process cannot be reordered. + */ + erts_proc_sig_queue_flush_buffers(receiver); + } + LINK_MESSAGE(receiver, first, state); } else { - erts_enqueue_signals(receiver, first, last, NULL, len, state); + state = erts_enqueue_signals(receiver, first, last, len, state); } if (locked_msgq) { @@ -446,7 +503,7 @@ erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks, ERL_MESSAGE_TERM(mp) = msg; ERL_MESSAGE_FROM(mp) = from; ERL_MESSAGE_TOKEN(mp) = am_undefined; - queue_messages(receiver, receiver_locks, mp, &mp->next, 1); + queue_messages(from, receiver, receiver_locks, mp, &mp->next, 1); } /** @@ -463,7 +520,7 @@ erts_queue_message_token(Process* receiver, ErtsProcLocks receiver_locks, ERL_MESSAGE_TERM(mp) = msg; ERL_MESSAGE_FROM(mp) = from; ERL_MESSAGE_TOKEN(mp) = token; - queue_messages(receiver, receiver_locks, mp, &mp->next, 1); + queue_messages(from, receiver, receiver_locks, mp, &mp->next, 1); } @@ -482,9 +539,13 @@ erts_queue_proc_message(Process* sender, Process* receiver, ErtsProcLocks receiver_locks, ErtsMessage* mp, Eterm msg) { + if (sender == receiver) + (void) erts_atomic32_read_bor_nob(&sender->xstate, + ERTS_PXSFLG_MAYBE_SELF_SIGS); + ERL_MESSAGE_TERM(mp) = msg; ERL_MESSAGE_FROM(mp) = sender->common.id; - queue_messages(receiver, receiver_locks, + queue_messages(sender->common.id, receiver, receiver_locks, prepend_pending_sig_maybe(sender, receiver, mp), &mp->next, 1); } @@ -495,7 +556,11 @@ erts_queue_proc_messages(Process* sender, Process* receiver, ErtsProcLocks receiver_locks, ErtsMessage* first, ErtsMessage** last, Uint len) { - queue_messages(receiver, receiver_locks, + if (sender == receiver) + (void) erts_atomic32_read_bor_nob(&sender->xstate, + ERTS_PXSFLG_MAYBE_SELF_SIGS); + + queue_messages(sender->common.id, receiver, receiver_locks, prepend_pending_sig_maybe(sender, receiver, first), last, len); } @@ -597,6 +662,7 @@ erts_try_alloc_message_on_heap(Process *pp, mp = erts_alloc_message(0, NULL); mp->data.attached = NULL; *on_heap_p = !0; + erts_adjust_memory_break(pp, -sz); } else if (pp && erts_proc_trylock(pp, ERTS_PROC_LOCK_MAIN) == 0) { locked_main = 1; @@ -912,6 +978,7 @@ void erts_save_message_in_proc(Process *p, ErtsMessage *msgp) hfp = msgp->data.heap_frag; } else { + erts_adjust_message_break(p, ERL_MESSAGE_TERM(msgp)); erts_free_message(msgp); return; /* Nothing to save */ } @@ -953,7 +1020,7 @@ change_off_heap_msgq(void *vcohmq) * process to complete this change itself. */ cohmq = (ErtsChangeOffHeapMessageQueue *) vcohmq; - erts_proc_sig_send_move_msgq_off_heap(NULL, cohmq->pid); + erts_proc_sig_send_move_msgq_off_heap(cohmq->pid); erts_free(ERTS_ALC_T_MSGQ_CHNG, vcohmq); } @@ -988,8 +1055,19 @@ erts_change_message_queue_management(Process *c_p, Eterm new_state) case am_off_heap: break; case am_on_heap: - c_p->sig_qs.flags |= FS_ON_HEAP_MSGQ; + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + /* + * The flags are changed while holding the + * ERTS_PROC_LOCK_MSGQ lock so that it is guaranteed that + * there are no messages in buffers if (c_p->sig_qs.flags + * & FS_ON_HEAP_MSGQ) and the ERTS_PROC_LOCK_MSGQ is held. + */ + erts_proc_sig_queue_flush_and_deinstall_buffers(c_p); + + c_p->sig_qs.flags |= FS_ON_HEAP_MSGQ; c_p->sig_qs.flags &= ~FS_OFF_HEAP_MSGQ; + + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); /* * We are not allowed to clear ERTS_PSFLG_OFF_HEAP_MSGQ * if a off heap change is ongoing. It will be adjusted @@ -1099,8 +1177,8 @@ void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory, { ErlHeapFragment *bp = p->mbuf; - /* `bp->used_size` must be set _BEFORE_ we call `HAlloc`, as that will - * update the used size and prevent us from undoing the changes later + /* `heap_frags_saved_used` must be set _BEFORE_ we call `HAlloc`, as that + * may update `bp->used_size` and prevent us from undoing the changes later * on. */ factory->heap_frags_saved = bp; factory->heap_frags_saved_used = bp ? bp->used_size : 0; @@ -1518,7 +1596,6 @@ void erts_factory_undo(ErtsHeapFactory* factory) ASSERT(factory->original_htop <= HEAP_LIMIT(factory->p)); HEAP_TOP(factory->p) = factory->original_htop; - /* Fix last heap frag */ if (factory->heap_frags_saved) { ASSERT(factory->heap_frags_saved == factory->p->mbuf); diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 0c06bab9c2ef..ee6c1b95c17b 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2021. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -33,6 +33,28 @@ #define ERTS_MSG_COPY_WORDS_PER_REDUCTION 64 #endif +/* The number of buffers have to be 64 or less because we currently + use a single word to implement a bitset with information about + non-empty buffers */ +#ifdef DEBUG +#define ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS 64 +#define ERTS_PROC_SIG_INQ_BUFFERED_CONTENTION_INSTALL_LIMIT 250 +#define ERTS_PROC_SIG_INQ_BUFFERED_ALWAYS_TURN_ON 1 +#define ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE 2 +#define ERTS_PROC_SIG_INQ_BUFFERED_MIN_NO_ENQUEUES_TO_KEEP \ + (ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE + \ + ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE / 2) +#else +#define ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS 64 +#define ERTS_PROC_SIG_INQ_BUFFERED_CONTENTION_INSTALL_LIMIT 50 +#define ERTS_PROC_SIG_INQ_BUFFERED_ALWAYS_TURN_ON 0 +#define ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE 8192 +/* At least 1.5 enqueues per flush all op */ +#define ERTS_PROC_SIG_INQ_BUFFERED_MIN_NO_ENQUEUES_TO_KEEP \ + (ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE + \ + ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE / 2) +#endif + struct proc_bin; struct external_thing_; @@ -214,7 +236,7 @@ struct erl_mesg { /* * The ErtsMessage struct is only one special type * of signal. All signal structs have a common - * begining and can be differentiated by looking + * beginning and can be differentiated by looking * at the ErtsSignal 'common.tag' field. * * - An ordinary message will have a value @@ -262,6 +284,7 @@ typedef struct { typedef struct { ErtsSignal sig; ErtsMessage **prev_next; + signed char is_yield_mark; signed char pass; signed char set_save; signed char in_sigq; @@ -350,7 +373,7 @@ typedef struct { Uint32 flags; } ErtsSignalPrivQueues; -typedef struct { +typedef struct ErtsSignalInQueue_ { ErtsMessage* first; ErtsMessage** last; /* point to the last next pointer */ Sint len; /* number of messages in queue */ @@ -360,6 +383,47 @@ typedef struct { #endif } ErtsSignalInQueue; +typedef union { + struct ___ErtsSignalInQueueBufferFields { + erts_mtx_t lock; + /* + * Boolean value indicateing if the buffer is alive. An + * enqueue attempt to a dead buffer has to be canceled + */ + int alive; + /* + * The number of enqueues that has been performed to this + * buffer. This value is used to decide if we should adapt + * back to an unbuffered state + */ + Uint nr_of_enqueues; + ErtsSignalInQueue queue; + } b; + byte align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(struct ___ErtsSignalInQueueBufferFields))]; +} ErtsSignalInQueueBuffer; + +#if ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS > 64 +#error The data structure holding information about which slots that are non-empty (the nonempty_slots field in the struct below) needs to be changed (it currently only supports up to 64 slots) +#endif + +typedef struct { + ErtsSignalInQueueBuffer slots[ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS]; + ErtsThrPrgrLaterOp free_item; + erts_atomic64_t nonempty_slots; + erts_atomic32_t nonmsgs_in_slots; + erts_atomic32_t msgs_in_slots; + /* + * dirty_refc is incremented by dirty schedulers that access the + * buffer array to prevent deallocation while they are accessing + * the buffer array. This is needed since dirty schedulers are not + * part of the thread progress system. + */ + erts_refc_t dirty_refc; + Uint nr_of_rounds_left; + Uint nr_of_enqueues; + int alive; +} ErtsSignalInQueueBufferArray; + typedef struct erl_trace_message_queue__ { struct erl_trace_message_queue__ *next; /* point to the next receiver */ Eterm receiver; @@ -387,14 +451,17 @@ typedef struct erl_trace_message_queue__ { #endif /* Add one message last in message queue */ -#define LINK_MESSAGE(p, msg) \ +#define LINK_MESSAGE(p, msg, ps) \ do { \ ASSERT(ERTS_SIG_IS_MSG(msg)); \ - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), "before"); \ + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), &(p)->sig_inq, "before");\ *(p)->sig_inq.last = (msg); \ (p)->sig_inq.last = &(msg)->next; \ (p)->sig_inq.len++; \ - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), "after"); \ + if (!((ps) & ERTS_PSFLG_MSG_SIG_IN_Q)) \ + (void) erts_atomic32_read_bor_nob(&(p)->state, \ + ERTS_PSFLG_MSG_SIG_IN_Q); \ + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), &(p)->sig_inq, "after"); \ } while(0) #define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \ @@ -443,6 +510,7 @@ void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp); Uint erts_msg_attached_data_size_aux(ErtsMessage *msg); +void erts_cleanup_offheap_list(struct erl_off_heap_header* first); void erts_cleanup_offheap(ErlOffHeap *offheap); void erts_save_message_in_proc(Process *p, ErtsMessage *msg); Sint erts_move_messages_off_heap(Process *c_p); @@ -451,30 +519,8 @@ Eterm erts_change_message_queue_management(Process *c_p, Eterm new_state); void erts_cleanup_messages(ErtsMessage *mp); -void *erts_alloc_message_ref(void); void erts_free_message_ref(void *); - -#define ERTS_SMALL_FIX_MSG_SZ 10 -#define ERTS_MEDIUM_FIX_MSG_SZ 20 -#define ERTS_LARGE_FIX_MSG_SZ 30 - -void *erts_alloc_small_message(void); -void erts_free_small_message(void *mp); - -typedef struct { - ErtsMessage m; - Eterm data[ERTS_SMALL_FIX_MSG_SZ-1]; -} ErtsSmallFixSzMessage; - -typedef struct { - ErtsMessage m; - Eterm data[ERTS_MEDIUM_FIX_MSG_SZ-1]; -} ErtsMediumFixSzMessage; - -typedef struct { - ErtsMessage m; - Eterm data[ERTS_LARGE_FIX_MSG_SZ-1]; -} ErtsLargeFixSzMessage; +void *erts_alloc_message_ref(void) ERTS_ATTR_MALLOC_D(erts_free_message_ref,1); ErtsMessage *erts_try_alloc_message_on_heap(Process *pp, erts_aint32_t *psp, diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c index 6c86089ec716..85d880dda354 100644 --- a/erts/emulator/beam/erl_monitor_link.c +++ b/erts/emulator/beam/erl_monitor_link.c @@ -198,8 +198,7 @@ ml_cmp_keys(Eterm key1, Eterm key2) if (n1->sysname != n2->sysname) return n1->sysname < n2->sysname ? -1 : 1; ASSERT(n1->creation != n2->creation); - if (n1->creation != 0 && n2->creation != 0) - return n1->creation < n2->creation ? -1 : 1; + return n1->creation < n2->creation ? -1 : 1; } ndw1 = external_thing_data_words(et1); @@ -704,10 +703,15 @@ erts_debug_monitor_tree_destroying_foreach(ErtsMonitor *root, void *arg, void *vysp) { - void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE, - sizeof(ErtsMonLnkYieldState)); + void *tmp_vysp; Sint reds; - sys_memcpy(tmp_vysp, tmp_vysp, sizeof(ErtsMonLnkYieldState)); + if (!vysp) + tmp_vysp = NULL; + else { + tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE, + sizeof(ErtsMonLnkYieldState)); + sys_memcpy(tmp_vysp, tmp_vysp, sizeof(ErtsMonLnkYieldState)); + } do { reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root, (ErtsMonLnkNodeFunc) func, @@ -916,7 +920,7 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name, else { /* Pending spawn_request() */ pending_flag = ERTS_ML_FLG_SPAWN_PENDING; - /* Prepare for storage of exteral pid */ + /* Prepare for storage of external pid */ tsz = EXTERNAL_PID_HEAP_SIZE; /* name contains tag */ @@ -1096,16 +1100,6 @@ erts_monitor_destroy__(ErtsMonitorData *mdp) || ((mdp->origin.flags & ERTS_ML_FLGS_SAME) == (mdp->u.target.flags & ERTS_ML_FLGS_SAME))); - if (mdp->origin.flags & ERTS_ML_STATE_ALIAS_MASK) { - ASSERT(mdp->origin.type == ERTS_MON_TYPE_ALIAS - || mdp->origin.type == ERTS_MON_TYPE_PROC - || mdp->origin.type == ERTS_MON_TYPE_PORT - || mdp->origin.type == ERTS_MON_TYPE_TIME_OFFSET - || mdp->origin.type == ERTS_MON_TYPE_DIST_PROC - || mdp->origin.type == ERTS_MON_TYPE_DIST_PORT); - erts_pid_ref_delete(mdp->ref); - } - switch (mdp->origin.type) { case ERTS_MON_TYPE_ALIAS: ERTS_ML_ASSERT(!(mdp->origin.flags & ERTS_ML_FLG_TAG)); @@ -1349,10 +1343,15 @@ erts_debug_link_tree_destroying_foreach(ErtsLink *root, void *arg, void *vysp) { - void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE, - sizeof(ErtsMonLnkYieldState)); + void *tmp_vysp; Sint reds; - sys_memcpy(tmp_vysp, vysp, sizeof(ErtsMonLnkYieldState)); + if (!vysp) + tmp_vysp = NULL; + else { + tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE, + sizeof(ErtsMonLnkYieldState)); + sys_memcpy(tmp_vysp, vysp, sizeof(ErtsMonLnkYieldState)); + } do { reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root, (ErtsMonLnkNodeFunc) func, diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h index 1e429e168476..c61b0dd16f60 100644 --- a/erts/emulator/beam/erl_monitor_link.h +++ b/erts/emulator/beam/erl_monitor_link.h @@ -1341,7 +1341,7 @@ ERTS_GLB_INLINE int erts_monitor_dist_insert(ErtsMonitor *mon, ErtsMonLnkDist *d * @brief Delete monitor from dist monitor tree or list * * When the function is called it is assumed that: - * - 'mon' monitor earler has been inserted into 'dist' + * - 'mon' monitor earlier has been inserted into 'dist' * If the above is not true, bad things will happen. * * @param[in] mon Pointer to monitor @@ -1766,7 +1766,7 @@ void erts_link_tree_replace(ErtsLink **root, ErtsLink *old, ErtsLink *new_); /** * - * @brief Replace a link in a link tree if key already exist based on adress + * @brief Replace a link in a link tree if key already exist based on address * * Inserts the link 'lnk' in the tree if no link with the same key * already exists in tree. If a link with the same key exists in @@ -2193,7 +2193,7 @@ ErtsLinkData *erts_link_external_create(Uint16 type, Eterm this_, Eterm other); * * @param[in] id Id of the entity linked. * - * @returns A pointer to the link stucture. + * @returns A pointer to the link structure. */ ErtsLink *erts_link_internal_create(Uint16 type, Eterm id); @@ -2314,7 +2314,7 @@ ERTS_GLB_INLINE int erts_link_dist_insert(ErtsLink *lnk, ErtsMonLnkDist *dist); * @brief Delete link from dist link list * * When the function is called it is assumed that: - * - 'lnk' link earler has been inserted into 'dist' + * - 'lnk' link earlier has been inserted into 'dist' * If the above is not true, bad things will happen. * * @param[in] lnk Pointer to link diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c index 73edb7b7d288..6bb50e6088e0 100644 --- a/erts/emulator/beam/erl_msacc.c +++ b/erts/emulator/beam/erl_msacc.c @@ -130,11 +130,13 @@ void erts_msacc_update_cache(ErtsMsAcc **cache) { #ifdef ERTS_MSACC_EXTENDED_STATES -void erts_msacc_set_bif_state(ErtsMsAcc *__erts_msacc_cache, Eterm mod, void *fn) { +const void *erts_msacc_set_bif_state(ErtsMsAcc *__erts_msacc_cache, + Eterm mod, + const void *bif) { #ifdef ERTS_MSACC_EXTENDED_BIFS -#define BIF_LIST(Mod,Func,Arity,BifFuncAddr,FuncAddr,Num) \ - if (fn == &BifFuncAddr) { \ +#define BIF_LIST(Mod,Func,Arity,BifFuncAddr,FuncAddr,Num) \ + if (bif == &BifFuncAddr) { \ ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATIC_STATE_COUNT + Num); \ } else #include "erl_bif_list.h" @@ -150,6 +152,8 @@ void erts_msacc_set_bif_state(ErtsMsAcc *__erts_msacc_cache, Eterm mod, void *fn ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_BIF); } #endif + + return bif; } #endif diff --git a/erts/emulator/beam/erl_msacc.h b/erts/emulator/beam/erl_msacc.h index 409392aad665..1907f600f51a 100644 --- a/erts/emulator/beam/erl_msacc.h +++ b/erts/emulator/beam/erl_msacc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2014-2021. All Rights Reserved. + * Copyright Ericsson AB 2014-2022. 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. @@ -414,7 +414,11 @@ void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) { #else -void erts_msacc_set_bif_state(ErtsMsAcc *msacc, Eterm mod, void *addr); +/* Enters BIF state, returning the given `bif` so we don't have to spill it in + * jitted code. */ +const void *erts_msacc_set_bif_state(ErtsMsAcc *msacc, + Eterm mod, + const void *bif); #define ERTS_MSACC_PUSH_STATE_X() ERTS_MSACC_PUSH_STATE() #define ERTS_MSACC_POP_STATE_X() ERTS_MSACC_POP_STATE() @@ -431,9 +435,10 @@ void erts_msacc_set_bif_state(ErtsMsAcc *msacc, Eterm mod, void *addr); #define ERTS_MSACC_SET_STATE_CACHED_M_X(state) ERTS_MSACC_SET_STATE_CACHED_M(state) #define ERTS_MSACC_POP_STATE_M_X() ERTS_MSACC_POP_STATE_M() #define ERTS_MSACC_PUSH_AND_SET_STATE_M_X(state) ERTS_MSACC_PUSH_AND_SET_STATE_M(state) -#define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) \ - if (ERTS_MSACC_IS_ENABLED_CACHED_X()) \ - erts_msacc_set_bif_state(__erts_msacc_cache, Mod, Addr) +#define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) \ + if (ERTS_MSACC_IS_ENABLED_CACHED_X()) { \ + (void)erts_msacc_set_bif_state(__erts_msacc_cache, Mod, Addr); \ + } #endif /* !ERTS_MSACC_EXTENDED_STATES */ diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c deleted file mode 100644 index 6e0a0dcff7d5..000000000000 --- a/erts/emulator/beam/erl_mtrace.c +++ /dev/null @@ -1,1268 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2018. 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% - */ - -/* - * Description: Memory allocation trace. The trace is sent over a - * tcp/ip connection. - * - * The trace format is not intended to be documented. - * Instead a library for parsing the trace will be - * distributed. This in order to more easily be able - * to make changes in the trace format. The library - * for parsing the trace is currently not included in - * the OTP distribution, but will be in the future. - * - * Author: Rickard Green - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "global.h" -#include "erl_sock.h" -#include "erl_threads.h" -#include "erl_memory_trace_protocol.h" -#include "erl_mtrace.h" - -#if defined(MAXHOSTNAMELEN) && MAXHOSTNAMELEN > 255 -# undef MAXHOSTNAMELEN -#endif - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 255 -#endif - -#define TRACE_PRINTOUTS 0 -#ifdef TRACE_PRINTOUTS -#define MSB2BITS(X) ((((unsigned)(X))+1)*8) -#endif - -static erts_mtx_t mtrace_op_mutex; -static erts_mtx_t mtrace_buf_mutex; - -#define TRACE_BUF_SZ (16*1024) - - -#define UI8_MSB_EHF_SZ ERTS_MT_UI8_MSB_EHDR_FLD_SZ -#define UI16_MSB_EHF_SZ ERTS_MT_UI16_MSB_EHDR_FLD_SZ -#define UI32_MSB_EHF_SZ ERTS_MT_UI32_MSB_EHDR_FLD_SZ -#define UI64_MSB_EHF_SZ ERTS_MT_UI64_MSB_EHDR_FLD_SZ -#define UI_MSB_EHF_SZ ERTS_MT_UI64_MSB_EHDR_FLD_SZ -#define TAG_EHF_SZ ERTS_MT_TAG_EHDR_FLD_SZ - -#define UI8_MSB_EHF_MSK ERTS_MT_UI8_MSB_EHDR_FLD_MSK -#define UI16_MSB_EHF_MSK ERTS_MT_UI16_MSB_EHDR_FLD_MSK -#define UI32_MSB_EHF_MSK ERTS_MT_UI32_MSB_EHDR_FLD_MSK -#define UI_MSB_EHF_MSK ERTS_MT_UI64_MSB_EHDR_FLD_MSK -#define UI64_MSB_EHF_MSK ERTS_MT_UI64_MSB_EHDR_FLD_MSK -#define TAG_EHF_MSK ERTS_MT_TAG_EHDR_FLD_MSK - -#define UI8_SZ (1) -#define UI16_SZ (2) -#define UI32_SZ (4) -#define UI64_SZ (8) -#ifdef ARCH_64 /* XXX:PaN Halfword? (whole file...) */ -# define UI_SZ UI64_SZ -#else -# define UI_SZ UI32_SZ -#endif - -#define WRITE_UI8(P, V) (*(P) = (byte) ((V) & 0xff)) - -#define WRITE_UI16(P, V) \ - ((P)[0] = (byte) (((V) >> 8) & 0xff), \ - (P)[1] = (byte) ( (V) & 0xff)) - -#define WRITE_UI32(P, V) \ - ((P)[0] = (byte) (((V) >> 24) & 0xff), \ - (P)[1] = (byte) (((V) >> 16) & 0xff), \ - (P)[2] = (byte) (((V) >> 8) & 0xff), \ - (P)[3] = (byte) ( (V) & 0xff)) - -#define WRITE_UI64(P, V) \ - ((P)[0] = (byte) (((V) >> 56) & 0xff), \ - (P)[1] = (byte) (((V) >> 48) & 0xff), \ - (P)[2] = (byte) (((V) >> 40) & 0xff), \ - (P)[3] = (byte) (((V) >> 32) & 0xff), \ - (P)[4] = (byte) (((V) >> 24) & 0xff), \ - (P)[5] = (byte) (((V) >> 16) & 0xff), \ - (P)[6] = (byte) (((V) >> 8) & 0xff), \ - (P)[7] = (byte) ( (V) & 0xff)) - -#define PUT_UI8(P, V) (WRITE_UI8((P), (V)), (P) += UI8_SZ) -#define PUT_UI16(P, V) (WRITE_UI16((P), (V)), (P) += UI16_SZ) -#define PUT_UI32(P, V) (WRITE_UI32((P), (V)), (P) += UI32_SZ) -#define PUT_UI64(P, V) (WRITE_UI64((P), (V)), (P) += UI64_SZ) - -#define PUT_VSZ_UI16(P, M, V) \ -do { \ - Uint16 v__ = (Uint16) (V); \ - if (v__ >= (((Uint16) 1) << 8)) (M) = 1; else (M) = 0; \ - switch ((M)) { \ - case 1: *((P)++) = (byte) ((v__ >> 8) & 0xff); \ - case 0: *((P)++) = (byte) ( v__ & 0xff); \ - } \ -} while (0) - -#define PUT_VSZ_UI32(P, M, V) \ -do { \ - Uint32 v__ = (Uint32) (V); \ - if (v__ >= (((Uint32) 1) << 16)) { \ - if (v__ >= (((Uint32) 1) << 24)) (M) = 3; else (M) = 2; \ - } else { \ - if (v__ >= (((Uint32) 1) << 8)) (M) = 1; else (M) = 0; \ - } \ - switch ((M)) { \ - case 3: *((P)++) = (byte) ((v__ >> 24) & 0xff); \ - case 2: *((P)++) = (byte) ((v__ >> 16) & 0xff); \ - case 1: *((P)++) = (byte) ((v__ >> 8) & 0xff); \ - case 0: *((P)++) = (byte) ( v__ & 0xff); \ - } \ -} while (0) - -#ifdef ARCH_64 - -#define PUT_VSZ_UI64(P, M, V) \ -do { \ - Uint64 v__ = (Uint64) (V); \ - if (v__ >= (((Uint64) 1) << 32)) { \ - if (v__ >= (((Uint64) 1) << 48)) { \ - if (v__ >= (((Uint64) 1) << 56)) (M) = 7; else (M) = 6; \ - } else { \ - if (v__ >= (((Uint64) 1) << 40)) (M) = 5; else (M) = 4; \ - } \ - } else { \ - if (v__ >= (((Uint64) 1) << 16)) { \ - if (v__ >= (((Uint64) 1) << 24)) (M) = 3; else (M) = 2; \ - } else { \ - if (v__ >= (((Uint64) 1) << 8)) (M) = 1; else (M) = 0; \ - } \ - } \ - switch ((M)) { \ - case 7: *((P)++) = (byte) ((v__ >> 56) & 0xff); \ - case 6: *((P)++) = (byte) ((v__ >> 48) & 0xff); \ - case 5: *((P)++) = (byte) ((v__ >> 40) & 0xff); \ - case 4: *((P)++) = (byte) ((v__ >> 32) & 0xff); \ - case 3: *((P)++) = (byte) ((v__ >> 24) & 0xff); \ - case 2: *((P)++) = (byte) ((v__ >> 16) & 0xff); \ - case 1: *((P)++) = (byte) ((v__ >> 8) & 0xff); \ - case 0: *((P)++) = (byte) ( v__ & 0xff); \ - } \ -} while (0) - -#define PUT_VSZ_UI PUT_VSZ_UI64 -#else /* #ifdef ARCH_64 */ -#define PUT_VSZ_UI PUT_VSZ_UI32 -#endif /* #ifdef ARCH_64 */ - -#define MAKE_TBUF_SZ(SZ) \ - (TRACE_BUF_SZ < (SZ) \ - ? (disable_trace(1, "Internal buffer overflow", 0), 0) \ - : (endp - tracep < (SZ) ? send_trace_buffer() : 1)) - - -static void disable_trace(int error, char *reason, int eno); -static int send_trace_buffer(void); - -#ifdef DEBUG -void -check_alloc_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 type, int type_n, - UWord res, int res_n, - Uint size, int size_n, - Uint32 ti,int ti_n); -void -check_realloc_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 type, int type_n, - UWord res, int res_n, - UWord ptr, int ptr_n, - Uint size, int size_n, - Uint32 ti,int ti_n); -void -check_free_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 t_no, int t_no_n, - UWord ptr, int ptr_n, - Uint32 ti,int ti_n); -void -check_time_inc_entry(byte *sp, byte *ep, - Uint32 secs, int secs_n, - Uint32 usecs, int usecs_n); -#endif - - - -int erts_mtrace_enabled; -static erts_sock_t socket_desc; -static byte trace_buffer[TRACE_BUF_SZ]; -static byte *tracep; -static byte *endp; -static SysTimeval last_tv; - -static ErtsAllocatorWrapper_t mtrace_wrapper; - -#if ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0 -#error ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0 -#endif - -char* erl_errno_id(int error); - -#define INVALID_TIME_INC (0xffffffff) - -static ERTS_INLINE Uint32 -get_time_inc(void) -{ - Sint32 secs; - Sint32 usecs; - Uint32 res; - SysTimeval tv; - sys_gettimeofday(&tv); - - secs = tv.tv_sec - last_tv.tv_sec; - if (tv.tv_usec >= last_tv.tv_usec) - usecs = tv.tv_usec - last_tv.tv_usec; - else { - secs--; - usecs = 1000000 + tv.tv_usec - last_tv.tv_usec; - } - - ASSERT(0 <= usecs); - ASSERT(usecs < 1000000); - - if (secs < 0) { - /* Clock stepped backwards; we pretend that no time has past. */ - res = 0; - } - else if (secs < ERTS_MT_TIME_INC_SECS_MASK) { - res = ((((Uint32) secs) << ERTS_MT_TIME_INC_SECS_SHIFT) - | (((Uint32) usecs) << ERTS_MT_TIME_INC_USECS_SHIFT)); - } - else { - /* Increment too large to fit in a 32-bit integer; - put a time inc entry in trace ... */ - if (MAKE_TBUF_SZ(UI8_SZ + UI16_SZ + 2*UI32_SZ)) { - byte *hdrp; - Uint16 hdr; - int secs_n, usecs_n; - - *(tracep++) = ERTS_MT_TIME_INC_BDY_TAG; - - hdrp = tracep; - tracep += 2; - - PUT_VSZ_UI32(tracep, secs_n, secs); - PUT_VSZ_UI32(tracep, usecs_n, usecs); - - hdr = usecs_n; - - hdr <<= UI32_MSB_EHF_SZ; - hdr |= secs_n; - - WRITE_UI16(hdrp, hdr); -#ifdef DEBUG - check_time_inc_entry(hdrp-1, tracep, - (Uint32) secs, secs_n, - (Uint32) usecs, usecs_n); -#endif - res = 0; - } - else { - res = INVALID_TIME_INC; - } - } - - last_tv = tv; - return res; -} - - -static void -disable_trace(int error, char *reason, int eno) -{ - char *mt_dis = "Memory trace disabled"; - char *eno_str; - - erts_mtrace_enabled = 0; - erts_sock_close(socket_desc); - socket_desc = ERTS_SOCK_INVALID_SOCKET; - - if (eno == 0) - erts_fprintf(stderr, "%s: %s\n", mt_dis, reason); - else { - eno_str = erl_errno_id(eno); - if (sys_strcmp(eno_str, "unknown") == 0) - erts_fprintf(stderr, "%s: %s: %d\n", mt_dis, reason, eno); - else - erts_fprintf(stderr, "%s: %s: %s\n", mt_dis, reason, eno_str); - } -} - -static int -send_trace_buffer(void) -{ - ssize_t ssz; - size_t sz; - - sz = tracep - trace_buffer; - tracep = trace_buffer; - - do { - ssz = erts_sock_send(socket_desc, (void *) tracep, sz); - if (ssz < 0) { - int socket_errno = erts_sock_errno(); - -#ifdef EINTR - if (socket_errno == EINTR) - continue; -#endif - disable_trace(0, "Connection lost", socket_errno); - return 0; - } - if (ssz > sz) { - disable_trace(1, "Unexpected error", 0); - return 0; - } - tracep += ssz; - sz -= ssz; - } while (sz); - - tracep = trace_buffer; - return 1; -} - -#if ERTS_ALC_N_MAX >= (1 << 16) -#error "Excessively large type numbers" -#endif - - -static int -write_trace_header(char *nodename, char *pid, char *hostname) -{ -#ifdef DEBUG - byte *startp; -#endif - Uint16 entry_sz; - Uint32 flags, n_len, h_len, p_len, hdr_prolog_len; - int i, no, str_len; - const char *str; - struct { - Uint32 gsec; - Uint32 sec; - Uint32 usec; - } start_time; - - sys_gettimeofday(&last_tv); - - start_time.gsec = (Uint32) (last_tv.tv_sec / 1000000000); - start_time.sec = (Uint32) (last_tv.tv_sec % 1000000000); - start_time.usec = (Uint32) last_tv.tv_usec; - - if (!MAKE_TBUF_SZ(3*UI32_SZ)) - return 0; - - flags = 0; -#ifdef ARCH_64 - flags |= ERTS_MT_64_BIT_FLAG; -#endif - flags |= ERTS_MT_CRR_INFO; -#ifdef ERTS_CAN_TRACK_MALLOC - flags |= ERTS_MT_SEG_CRR_INFO; -#endif - - /* - * The following 3 ui32 words *always* have to come - * first in the trace. - */ - PUT_UI32(tracep, ERTS_MT_START_WORD); - PUT_UI32(tracep, ERTS_MT_MAJOR_VSN); - PUT_UI32(tracep, ERTS_MT_MINOR_VSN); - - n_len = sys_strlen(nodename); - h_len = sys_strlen(hostname); - p_len = sys_strlen(pid); - hdr_prolog_len = (2*UI32_SZ - + 3*UI16_SZ - + 3*UI32_SZ - + 3*UI8_SZ - + n_len - + h_len - + p_len); - - if (!MAKE_TBUF_SZ(hdr_prolog_len)) - return 0; - - /* - * New stuff can be added at the end the of header prolog - * (EOHP). The reader should skip stuff at the end, that it - * doesn't understand. - */ - -#ifdef DEBUG - startp = tracep; -#endif - - PUT_UI32(tracep, hdr_prolog_len); - PUT_UI32(tracep, flags); - PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); - PUT_UI16(tracep, ERTS_ALC_A_MAX); - PUT_UI16(tracep, ERTS_ALC_N_MAX); - - PUT_UI32(tracep, start_time.gsec); - PUT_UI32(tracep, start_time.sec); - PUT_UI32(tracep, start_time.usec); - - PUT_UI8(tracep, (byte) n_len); - sys_memcpy((void *) tracep, (void *) nodename, n_len); - tracep += n_len; - - PUT_UI8(tracep, (byte) h_len); - sys_memcpy((void *) tracep, (void *) hostname, h_len); - tracep += h_len; - - PUT_UI8(tracep, (byte) p_len); - sys_memcpy((void *) tracep, (void *) pid, p_len); - tracep += p_len; - - ASSERT(startp + hdr_prolog_len == tracep); - - /* - * EOHP - */ - - /* - * All tags from here on should be followed by an Uint16 size - * field containing the total size of the entry. - * - * New stuff can eigther be added at the end of an entry, or - * as a new tagged entry. The reader should skip stuff at the - * end, that it doesn't understand. - */ - - for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { - Uint16 aflags = 0; - -#ifndef ERTS_CAN_TRACK_MALLOC - if (i != ERTS_ALC_A_SYSTEM) -#endif - aflags |= ERTS_MT_ALLCTR_USD_CRR_INFO; - - str = ERTS_ALC_A2AD(i); - ASSERT(str); - str_len = sys_strlen(str); - if (str_len >= (1 << 8)) { - disable_trace(1, "Excessively large allocator string", 0); - return 0; - } - - entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ; - entry_sz += (erts_allctrs_info[i].alloc_util ? 2 : 1)*UI16_SZ; - entry_sz += UI8_SZ + str_len; - - if (!MAKE_TBUF_SZ(entry_sz)) - return 0; - -#ifdef DEBUG - startp = tracep; -#endif - PUT_UI8(tracep, ERTS_MT_ALLOCATOR_HDR_TAG); - PUT_UI16(tracep, entry_sz); - PUT_UI16(tracep, aflags); - PUT_UI16(tracep, (Uint16) i); - PUT_UI8( tracep, (byte) str_len); - sys_memcpy((void *) tracep, (void *) str, str_len); - tracep += str_len; - if (erts_allctrs_info[i].alloc_util) { - PUT_UI8(tracep, 2); - PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); - PUT_UI16(tracep, ERTS_ALC_A_SYSTEM); - } - else { - PUT_UI8(tracep, 1); - switch (i) { - case ERTS_ALC_A_SYSTEM: - PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); - break; - default: - PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); - break; - } - } - ASSERT(startp + entry_sz == tracep); - } - - for (i = ERTS_ALC_N_MIN; i <= ERTS_ALC_N_MAX; i++) { - Uint16 nflags = 0; - str = ERTS_ALC_N2TD(i); - ASSERT(str); - - str_len = sys_strlen(str); - if (str_len >= (1 << 8)) { - disable_trace(1, "Excessively large type string", 0); - return 0; - } - - no = ERTS_ALC_T2A(ERTS_ALC_N2T(i)); - if (!erts_allctrs_info[no].enabled) - no = ERTS_ALC_A_SYSTEM; - ASSERT(ERTS_ALC_A_MIN <= no && no <= ERTS_ALC_A_MAX); - - entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ + str_len + UI16_SZ; - - if (!MAKE_TBUF_SZ(entry_sz)) - return 0; - -#ifdef DEBUG - startp = tracep; -#endif - PUT_UI8(tracep, ERTS_MT_BLOCK_TYPE_HDR_TAG); - PUT_UI16(tracep, entry_sz); - PUT_UI16(tracep, nflags); - PUT_UI16(tracep, (Uint16) i); - PUT_UI8(tracep, (byte) str_len); - sys_memcpy((void *) tracep, (void *) str, str_len); - tracep += str_len; - PUT_UI16(tracep, no); - ASSERT(startp + entry_sz == tracep); - } - - entry_sz = UI8_SZ + UI16_SZ; - if (!MAKE_TBUF_SZ(entry_sz)) - return 0; - PUT_UI8(tracep, ERTS_MT_END_OF_HDR_TAG); - PUT_UI16(tracep, entry_sz); - - return 1; -} - -static void mtrace_pre_lock(void); -static void mtrace_pre_unlock(void); -static void *mtrace_alloc(ErtsAlcType_t, void *, Uint); -static void *mtrace_realloc(ErtsAlcType_t, void *, void *, Uint); -static void mtrace_free(ErtsAlcType_t, void *, void *); - -static ErtsAllocatorFunctions_t real_allctrs[ERTS_ALC_A_MAX+1]; - -void erts_mtrace_pre_init(void) -{ -} - -void erts_mtrace_init(char *receiver, char *nodename) -{ - char hostname[MAXHOSTNAMELEN + 1]; - char pid[21]; /* enough for a 64 bit number */ - - socket_desc = ERTS_SOCK_INVALID_SOCKET; - erts_mtrace_enabled = receiver != NULL; - - if (erts_mtrace_enabled) { - unsigned a, b, c, d, p; - byte ip_addr[4]; - Uint16 port; - - erts_mtx_init(&mtrace_buf_mutex, "mtrace_buf", NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DEBUG); - erts_mtx_init(&mtrace_op_mutex, "mtrace_op", NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DEBUG); - - socket_desc = erts_sock_open(); - if (socket_desc == ERTS_SOCK_INVALID_SOCKET) { - disable_trace(1, "Failed to open socket", erts_sock_errno()); - return; - } - - if (5 != sscanf(receiver, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &p) - || a >= (1 << 8) || b >= (1 << 8)|| c >= (1 << 8) || d >= (1 << 8) - || p >= (1 << 16)) { - disable_trace(1, "Invalid receiver address", 0); - return; - } - - ip_addr[0] = (byte) a; - ip_addr[1] = (byte) b; - ip_addr[2] = (byte) c; - ip_addr[3] = (byte) d; - - port = (Uint16) p; - - if (!erts_sock_connect(socket_desc, ip_addr, 4, port)) { - disable_trace(1, "Failed to connect to receiver", - erts_sock_errno()); - return; - } - tracep = trace_buffer; - endp = trace_buffer + TRACE_BUF_SZ; - /* gethostname requires that the len is max(hostname) + 1 */ - if (erts_sock_gethostname(hostname, MAXHOSTNAMELEN + 1) != 0) - hostname[0] = '\0'; - hostname[MAXHOSTNAMELEN] = '\0'; - sys_get_pid(pid, sizeof(pid)); - write_trace_header(nodename ? nodename : "", pid, hostname); - erts_mtrace_update_heap_size(); - } -} - -void -erts_mtrace_install_wrapper_functions(void) -{ - if (erts_mtrace_enabled) { - int i; - /* Install trace functions */ - ERTS_CT_ASSERT(sizeof(erts_allctrs) == sizeof(real_allctrs)); - - sys_memcpy((void *) real_allctrs, - (void *) erts_allctrs, - sizeof(erts_allctrs)); - - for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { - erts_allctrs[i].alloc = mtrace_alloc; - erts_allctrs[i].realloc = mtrace_realloc; - erts_allctrs[i].free = mtrace_free; - erts_allctrs[i].extra = (void *) &real_allctrs[i]; - } - mtrace_wrapper.lock = mtrace_pre_lock; - mtrace_wrapper.unlock = mtrace_pre_unlock; - erts_allctr_wrapper_prelock_init(&mtrace_wrapper); - } -} - -void -erts_mtrace_stop(void) -{ - ASSERT(!erts_is_allctr_wrapper_prelocked()); - erts_mtx_lock(&mtrace_op_mutex); - erts_mtx_lock(&mtrace_buf_mutex); - if (erts_mtrace_enabled) { - Uint32 ti = get_time_inc(); - - if (ti != INVALID_TIME_INC - && MAKE_TBUF_SZ(UI8_SZ + UI16_SZ + UI32_SZ)) { - byte *hdrp; - Uint16 hdr; - int ti_n; - - *(tracep++) = ERTS_MT_STOP_BDY_TAG; - - hdrp = tracep; - tracep += 2; - - PUT_VSZ_UI32(tracep, ti_n, ti); - - hdr = ti_n; - - WRITE_UI16(hdrp, hdr); - - if(send_trace_buffer()) { - erts_mtrace_enabled = 0; - erts_sock_close(socket_desc); - socket_desc = ERTS_SOCK_INVALID_SOCKET; - } - } - } - erts_mtx_unlock(&mtrace_buf_mutex); - erts_mtx_unlock(&mtrace_op_mutex); -} - -void -erts_mtrace_exit(Uint32 exit_value) -{ - ASSERT(!erts_is_allctr_wrapper_prelocked()); - erts_mtx_lock(&mtrace_op_mutex); - erts_mtx_lock(&mtrace_buf_mutex); - if (erts_mtrace_enabled) { - Uint32 ti = get_time_inc(); - - if (ti != INVALID_TIME_INC - && MAKE_TBUF_SZ(UI8_SZ + UI16_SZ + 2*UI32_SZ)) { - byte *hdrp; - Uint16 hdr; - int ti_n, exit_value_n; - - *(tracep++) = ERTS_MT_EXIT_BDY_TAG; - - hdrp = tracep; - tracep += 2; - - PUT_VSZ_UI32(tracep, exit_value_n, exit_value); - PUT_VSZ_UI32(tracep, ti_n, ti); - - hdr = ti_n; - - hdr <<= UI32_MSB_EHF_SZ; - hdr |= exit_value_n; - - WRITE_UI16(hdrp, hdr); - - if(send_trace_buffer()) { - erts_mtrace_enabled = 0; - erts_sock_close(socket_desc); - socket_desc = ERTS_SOCK_INVALID_SOCKET; - } - } - } - erts_mtx_unlock(&mtrace_buf_mutex); - erts_mtx_unlock(&mtrace_op_mutex); -} - -static ERTS_INLINE void -write_alloc_entry(byte tag, - void *res, - ErtsAlcType_t x, - ErtsAlcType_t y, - Uint size) -{ - erts_mtx_lock(&mtrace_buf_mutex); - if (erts_mtrace_enabled) { - Uint32 ti = get_time_inc(); - - if (ti != INVALID_TIME_INC - && MAKE_TBUF_SZ(UI8_SZ + 2*UI16_SZ + 2*UI_SZ + UI32_SZ)) { - Uint16 hdr, t_no = (Uint16) x, ct_no = (Uint16) y; - byte *hdrp; - int t_no_n, ct_no_n = 0, res_n, size_n, ti_n; - - *(tracep++) = tag; - - hdrp = tracep; - tracep += 2; - - if (tag == ERTS_MT_CRR_ALLOC_BDY_TAG) { - PUT_VSZ_UI16(tracep, ct_no_n, ct_no); - } - PUT_VSZ_UI16(tracep, t_no_n, t_no); - PUT_VSZ_UI( tracep, res_n, res); - PUT_VSZ_UI( tracep, size_n, size); - PUT_VSZ_UI32(tracep, ti_n, ti); - - hdr = ti_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= size_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= res_n; - - hdr <<= UI16_MSB_EHF_SZ; - hdr |= t_no_n; - - if (tag == ERTS_MT_CRR_ALLOC_BDY_TAG) { - hdr <<= UI16_MSB_EHF_SZ; - hdr |= ct_no_n; - } - - WRITE_UI16(hdrp, hdr); - -#if TRACE_PRINTOUTS - print_trace_entry(tag, - ct_no, ct_no_n, - t_no, t_no_n, - (Uint) res, res_n, - 0, 0, - size, size_n, - ti, ti_n); -#endif - -#ifdef DEBUG - check_alloc_entry(hdrp-1, tracep, - tag, - ct_no, ct_no_n, - t_no, t_no_n, - (UWord) res, res_n, - size, size_n, - ti, ti_n); -#endif - - } - - } - erts_mtx_unlock(&mtrace_buf_mutex); - -} - -static ERTS_INLINE void -write_realloc_entry(byte tag, - void *res, - ErtsAlcType_t x, - ErtsAlcType_t y, - void *ptr, - Uint size) -{ - erts_mtx_lock(&mtrace_buf_mutex); - if (erts_mtrace_enabled) { - Uint32 ti = get_time_inc(); - - if (ti != INVALID_TIME_INC - && MAKE_TBUF_SZ(UI8_SZ + 2*UI16_SZ + 3*UI_SZ + UI32_SZ)) { - Uint16 hdr, t_no = (Uint16) x, ct_no = (Uint16) y; - byte *hdrp; - int t_no_n, ct_no_n = 0, res_n, ptr_n, size_n, ti_n; - - *(tracep++) = tag; - - hdrp = tracep; - tracep += 2; - - if (tag == ERTS_MT_CRR_REALLOC_BDY_TAG) { - PUT_VSZ_UI16(tracep, ct_no_n, ct_no); - } - PUT_VSZ_UI16(tracep, t_no_n, t_no); - PUT_VSZ_UI( tracep, res_n, res); - PUT_VSZ_UI( tracep, ptr_n, ptr); - PUT_VSZ_UI( tracep, size_n, size); - PUT_VSZ_UI32(tracep, ti_n, ti); - - hdr = ti_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= size_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= ptr_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= res_n; - - hdr <<= UI16_MSB_EHF_SZ; - hdr |= t_no_n; - - if (tag == ERTS_MT_CRR_REALLOC_BDY_TAG) { - hdr <<= UI16_MSB_EHF_SZ; - hdr |= ct_no_n; - } - - WRITE_UI16(hdrp, hdr); - -#if TRACE_PRINTOUTS - print_trace_entry(tag, - ct_no, ct_no_n, - t_no, t_no_n, - (Uint) res, res_n, - (Uint) ptr, ptr_n, - size, size_n, - ti, ti_n); -#endif - -#ifdef DEBUG - check_realloc_entry(hdrp-1, tracep, - tag, - ct_no, ct_no_n, - t_no, t_no_n, - (UWord) res, res_n, - (UWord) ptr, ptr_n, - size, size_n, - ti, ti_n); -#endif - - } - } - erts_mtx_unlock(&mtrace_buf_mutex); -} - -static ERTS_INLINE void -write_free_entry(byte tag, - ErtsAlcType_t x, - ErtsAlcType_t y, - void *ptr) -{ - erts_mtx_lock(&mtrace_buf_mutex); - if (erts_mtrace_enabled) { - Uint32 ti = get_time_inc(); - - if (ti != INVALID_TIME_INC - && MAKE_TBUF_SZ(UI8_SZ + 2*UI16_SZ + UI_SZ + UI32_SZ)) { - Uint16 hdr, t_no = (Uint16) x, ct_no = (Uint16) y; - byte *hdrp; - int t_no_n, ct_no_n = 0, ptr_n, ti_n; - - *(tracep++) = tag; - - hdrp = tracep; - tracep += 2; - - if (tag == ERTS_MT_CRR_FREE_BDY_TAG) { - PUT_VSZ_UI16(tracep, ct_no_n, ct_no); - } - PUT_VSZ_UI16(tracep, t_no_n, t_no); - PUT_VSZ_UI( tracep, ptr_n, ptr); - PUT_VSZ_UI32(tracep, ti_n, ti); - - hdr = ti_n; - - hdr <<= UI_MSB_EHF_SZ; - hdr |= ptr_n; - - hdr <<= UI16_MSB_EHF_SZ; - hdr |= t_no_n; - - if (tag == ERTS_MT_CRR_FREE_BDY_TAG) { - hdr <<= UI16_MSB_EHF_SZ; - hdr |= ct_no_n; - } - - WRITE_UI16(hdrp, hdr); - -#if TRACE_PRINTOUTS - print_trace_entry(tag, - ct_no, ct_no_n, - t_no, t_no_n, - (Uint) 0, 0, - (Uint) ptr, ptr_n, - 0, 0, - ti, ti_n); -#endif - -#ifdef DEBUG - check_free_entry(hdrp-1, tracep, - tag, - ct_no, ct_no_n, - t_no, t_no_n, - (UWord) ptr, ptr_n, - ti, ti_n); -#endif - } - - } - erts_mtx_unlock(&mtrace_buf_mutex); -} - -static void mtrace_pre_lock(void) -{ - erts_mtx_lock(&mtrace_op_mutex); -} - -static void mtrace_pre_unlock(void) -{ - erts_mtx_unlock(&mtrace_op_mutex); -} - - -static void * -mtrace_alloc(ErtsAlcType_t n, void *extra, Uint size) -{ - ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; - void *res; - - if (!erts_is_allctr_wrapper_prelocked()) { - erts_mtx_lock(&mtrace_op_mutex); - } - - res = (*real_af->alloc)(n, real_af->extra, size); - write_alloc_entry(ERTS_MT_ALLOC_BDY_TAG, res, n, 0, size); - - if (!erts_is_allctr_wrapper_prelocked()) { - erts_mtx_unlock(&mtrace_op_mutex); - } - - return res; -} - -static void * -mtrace_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size) -{ - ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; - void *res; - - if (!erts_is_allctr_wrapper_prelocked()) { - erts_mtx_lock(&mtrace_op_mutex); - } - - res = (*real_af->realloc)(n, real_af->extra, ptr, size); - write_realloc_entry(ERTS_MT_REALLOC_BDY_TAG, res, n, 0, ptr, size); - - if (!erts_is_allctr_wrapper_prelocked()) { - erts_mtx_unlock(&mtrace_op_mutex); - } - - return res; - -} - -static void -mtrace_free(ErtsAlcType_t n, void *extra, void *ptr) -{ - ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; - - if (!erts_is_allctr_wrapper_prelocked()) { - erts_mtx_lock(&mtrace_op_mutex); - } - - (*real_af->free)(n, real_af->extra, ptr); - if (!erts_is_allctr_wrapper_prelocked()) { - write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr); - } - - erts_mtx_unlock(&mtrace_op_mutex); -} - - -void -erts_mtrace_crr_alloc(void *res, ErtsAlcType_t n, ErtsAlcType_t m, Uint size) -{ - write_alloc_entry(ERTS_MT_CRR_ALLOC_BDY_TAG, res, n, m, size); -} - -void -erts_mtrace_crr_realloc(void *res, ErtsAlcType_t n, ErtsAlcType_t m, void *ptr, - Uint size) -{ - write_realloc_entry(ERTS_MT_CRR_REALLOC_BDY_TAG, res, n, m, ptr, size); -} - -void -erts_mtrace_crr_free(ErtsAlcType_t n, ErtsAlcType_t m, void *ptr) -{ - write_free_entry(ERTS_MT_CRR_FREE_BDY_TAG, n, m, ptr); -} - - -#if TRACE_PRINTOUTS -static void -print_trace_entry(byte tag, - Uint16 t_no, int t_no_n, - Uint16 ct_no, int ct_no_n, - Uint res, int res_n, - Uint ptr, int ptr_n, - Uint size, int size_n, - Uint32 ti,int ti_n) -{ - switch (tag) { - case ERTS_MT_ALLOC_BDY_TAG: - fprintf(stderr, - "{alloc, {%lu, %lu, %lu}, {%u, %u, %u, %u}}\n\r", - - (unsigned long) t_no, (unsigned long) res, - (unsigned long) size, - - MSB2BITS(t_no_n), MSB2BITS(res_n), - MSB2BITS(size_n), MSB2BITS(ti_n)); - break; - case ERTS_MT_REALLOC_BDY_TAG: - fprintf(stderr, - "{realloc, {%lu, %lu, %lu, %lu}, {%u, %u, %u, %u, %u}}\n\r", - - (unsigned long) t_no, (unsigned long) res, - (unsigned long) ptr, (unsigned long) size, - - MSB2BITS(t_no_n), MSB2BITS(res_n), - MSB2BITS(ptr_n), MSB2BITS(size_n), MSB2BITS(ti_n)); - break; - case ERTS_MT_FREE_BDY_TAG: - fprintf(stderr, - "{free, {%lu, %lu}, {%u, %u, %u, %u, %u}}\n\r", - - (unsigned long) t_no, (unsigned long) ptr, - - MSB2BITS(t_no_n), MSB2BITS(ptr_n), MSB2BITS(ti_n)); - break; - case ERTS_MT_CRR_ALLOC_BDY_TAG: - fprintf(stderr, - "{crr_alloc, {%lu, %lu, %lu, %lu}, {%u, %u, %u, %u, %u}}\n\r", - - (unsigned long) ct_no, (unsigned long) t_no, - (unsigned long) res, (unsigned long) size, - - MSB2BITS(ct_no_n), MSB2BITS(t_no_n), - MSB2BITS(res_n), MSB2BITS(size_n), - MSB2BITS(ti_n)); - break; - case ERTS_MT_CRR_REALLOC_BDY_TAG: - fprintf(stderr, - "{crr_realloc, {%lu, %lu, %lu, %lu, %lu}, " - "{%u, %u, %u, %u, %u, %u}}\n\r", - - (unsigned long) ct_no, (unsigned long) t_no, - (unsigned long) res, (unsigned long) ptr, - (unsigned long) size, - - MSB2BITS(ct_no_n), MSB2BITS(t_no_n), - MSB2BITS(res_n), MSB2BITS(ptr_n), - MSB2BITS(size_n), MSB2BITS(ti_n)); - break; - case ERTS_MT_CRR_FREE_BDY_TAG: - fprintf(stderr, - "{crr_free, {%lu, %lu, %lu}, {%u, %u, %u, %u}}\n\r", - - (unsigned long) ct_no, (unsigned long) t_no, - (unsigned long) ptr, - - MSB2BITS(ct_no_n), MSB2BITS(t_no_n), - MSB2BITS(ptr_n), MSB2BITS(ti_n)); - break; - default: - fprintf(stderr, "{'\?\?\?'}\n\r"); - break; - } -} - -#endif /* #if TRACE_PRINTOUTS */ - -#ifdef DEBUG - -#define GET_UI16(P) ((P) += UI16_SZ, \ - (((Uint16) (*((P) - 2) << 8)) | ((Uint16) (*((P) - 1))))) - -static void -check_ui(Uint16 *hdrp, byte **pp, Uint ui, int msb, - Uint16 f_mask, Uint16 f_size) -{ - Uint x; - int n; - - ASSERT((msb & ~f_mask) == 0); - - n = (int) (*hdrp & f_mask); - - ASSERT(n == msb); - - *hdrp >>= f_size; - - x = 0; - switch (n) { -#ifdef ARCH_64 - case 7: x |= *((*pp)++); x <<= 8; - case 6: x |= *((*pp)++); x <<= 8; - case 5: x |= *((*pp)++); x <<= 8; - case 4: x |= *((*pp)++); x <<= 8; -#endif - case 3: x |= *((*pp)++); x <<= 8; - case 2: x |= *((*pp)++); x <<= 8; - case 1: x |= *((*pp)++); x <<= 8; - case 0: x |= *((*pp)++); break; - default: ASSERT(0); - } - - ASSERT(x == ui); -} - - -void -check_alloc_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 t_no, int t_no_n, - UWord res, int res_n, - Uint size, int size_n, - Uint32 ti,int ti_n) -{ - byte *p = sp; - Uint16 hdr; - - ASSERT(*p == tag); - p++; - - hdr = GET_UI16(p); - - if (tag == ERTS_MT_CRR_ALLOC_BDY_TAG) - check_ui(&hdr, &p, ct_no, ct_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, t_no, t_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, res, res_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, size, size_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, ti, ti_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ); - - ASSERT(hdr == 0); - ASSERT(p == ep); -} - -void -check_realloc_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 t_no, int t_no_n, - UWord res, int res_n, - UWord ptr, int ptr_n, - Uint size, int size_n, - Uint32 ti,int ti_n) -{ - byte *p = sp; - Uint16 hdr; - - ASSERT(*p == tag); - p++; - - hdr = GET_UI16(p); - - if (tag == ERTS_MT_CRR_REALLOC_BDY_TAG) - check_ui(&hdr, &p, ct_no, ct_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, t_no, t_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, res, res_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, ptr, ptr_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, size, size_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, ti, ti_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ); - - ASSERT(hdr == 0); - ASSERT(p == ep); -} - -void -check_free_entry(byte *sp, byte *ep, - byte tag, - Uint16 ct_no, int ct_no_n, - Uint16 t_no, int t_no_n, - UWord ptr, int ptr_n, - Uint32 ti,int ti_n) -{ - byte *p = sp; - Uint16 hdr; - - ASSERT(*p == tag); - p++; - - hdr = GET_UI16(p); - - if (tag == ERTS_MT_CRR_FREE_BDY_TAG) - check_ui(&hdr, &p, ct_no, ct_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, t_no, t_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ); - check_ui(&hdr, &p, ptr, ptr_n, UI_MSB_EHF_MSK, UI_MSB_EHF_SZ); - check_ui(&hdr, &p, ti, ti_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ); - - ASSERT(hdr == 0); - ASSERT(p == ep); - -} - -void -check_time_inc_entry(byte *sp, byte *ep, - Uint32 secs, int secs_n, - Uint32 usecs, int usecs_n) -{ - byte *p = sp; - Uint16 hdr; - - ASSERT(*p == ERTS_MT_TIME_INC_BDY_TAG); - p++; - - hdr = GET_UI16(p); - - check_ui(&hdr, &p, secs, secs_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ); - check_ui(&hdr, &p, usecs, usecs_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ); - - ASSERT(hdr == 0); - ASSERT(p == ep); - -} - -#endif /* #ifdef DEBUG */ - diff --git a/erts/emulator/beam/erl_mtrace.h b/erts/emulator/beam/erl_mtrace.h deleted file mode 100644 index 776c70a819db..000000000000 --- a/erts/emulator/beam/erl_mtrace.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2016. 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% - */ - -#ifndef ERL_MTRACE_H__ -#define ERL_MTRACE_H__ - -#include "erl_alloc_types.h" - -#if (defined(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC) \ - || defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC)) -#undef ERTS_CAN_TRACK_MALLOC -#define ERTS_CAN_TRACK_MALLOC -#endif - -#define ERTS_MTRACE_SEGMENT_ID ERTS_ALC_A_INVALID - -extern int erts_mtrace_enabled; - -void erts_mtrace_pre_init(void); -void erts_mtrace_init(char *receiver, char *nodename); -void erts_mtrace_install_wrapper_functions(void); -void erts_mtrace_stop(void); -void erts_mtrace_exit(Uint32 exit_value); - -void erts_mtrace_crr_alloc(void*, ErtsAlcType_t, ErtsAlcType_t, Uint); -void erts_mtrace_crr_realloc(void*, ErtsAlcType_t, ErtsAlcType_t, void*, Uint); -void erts_mtrace_crr_free(ErtsAlcType_t, ErtsAlcType_t, void*); - - -void erts_mtrace_update_heap_size(void); /* Implemented in - * ../sys/common/erl_mtrace_sys_wrap.c - */ - -#endif /* #ifndef ERL_MTRACE_H__ */ - diff --git a/erts/emulator/beam/erl_nfunc_sched.c b/erts/emulator/beam/erl_nfunc_sched.c index 79ba08876a49..a1732468d3e4 100644 --- a/erts/emulator/beam/erl_nfunc_sched.c +++ b/erts/emulator/beam/erl_nfunc_sched.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2016-2021. All Rights Reserved. + * Copyright Ericsson AB 2016-2023. 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. @@ -130,20 +130,17 @@ erts_nfunc_schedule(Process *c_p, Process *dirty_shadow_proc, nep->trampoline.info.mfa.module = mod; nep->trampoline.info.mfa.function = func; nep->trampoline.info.mfa.arity = (Uint) argc; -#ifdef BEAMASM - nep->trampoline.trace[0] = (BeamInstr) instr; /* call_bif || call_nif */ -#endif - nep->trampoline.call_op = (BeamInstr) instr; /* call_bif || call_nif */ nep->trampoline.dfunc = (BeamInstr) dfunc; nep->func = ifunc; used_proc->arity = argc; used_proc->freason = TRAP; -#ifndef BEAMASM - used_proc->i = (ErtsCodePtr)&nep->trampoline.call_op; -#else - ERTS_CT_ASSERT(sizeof(nep->trampoline.trace) == BEAM_ASM_FUNC_PROLOGUE_SIZE); - used_proc->i = (ErtsCodePtr)&nep->trampoline.trace; + + /* call_bif || call_nif */ + ERTS_CT_ASSERT(sizeof(nep->trampoline.call_bif_nif) >= sizeof(instr)); + sys_memcpy(&nep->trampoline.call_bif_nif, &instr, sizeof(instr)); + + used_proc->i = (ErtsCodePtr)&nep->trampoline.call_bif_nif; ASSERT_MFA(erts_code_to_codemfa(used_proc->i)); -#endif + return nep; } diff --git a/erts/emulator/beam/erl_nfunc_sched.h b/erts/emulator/beam/erl_nfunc_sched.h index c016bc035a8d..c97525ad78a1 100644 --- a/erts/emulator/beam/erl_nfunc_sched.h +++ b/erts/emulator/beam/erl_nfunc_sched.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2016-2021. All Rights Reserved. + * Copyright Ericsson AB 2016-2023. 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. @@ -24,6 +24,7 @@ #include "erl_process.h" #include "bif.h" #include "error.h" +#include "jit/beam_asm.h" /* * Native function wrappers are used to schedule native functions on both @@ -40,10 +41,10 @@ typedef struct { struct { ErtsCodeInfo info; #ifdef BEAMASM - // Code used by tracing/nif load - BeamInstr trace[1]; + char call_bif_nif[BEAM_ASM_NFUNC_SIZE]; +#else + BeamInstr call_bif_nif; /* call_bif || call_nif */ #endif - BeamInstr call_op; /* call_bif || call_nif */ BeamInstr dfunc; } trampoline; @@ -176,17 +177,11 @@ erts_proc_shadow2real(Process *c_p) #if defined(ERTS_WANT_NFUNC_SCHED_INTERNALS__) && !defined(ERTS_NFUNC_SCHED_INTERNALS__) #define ERTS_NFUNC_SCHED_INTERNALS__ -#ifdef BEAMASM -#define NFUNC_FIELD__ trampoline.trace -#else -#define NFUNC_FIELD__ trampoline.call_op -#endif - #define ERTS_I_BEAM_OP_TO_NFUNC(I) \ (ASSERT(BeamIsOpCode(*(const BeamInstr*)(I), op_call_bif_W) || \ BeamIsOpCode(*(const BeamInstr*)(I), op_call_nif_WWW)), \ ((ErtsNativeFunc *) (((char *) (I)) - \ - offsetof(ErtsNativeFunc, NFUNC_FIELD__)))) + offsetof(ErtsNativeFunc, trampoline.call_bif_nif)))) #include "erl_message.h" #include @@ -244,6 +239,8 @@ erts_flush_dirty_shadow_proc(Process *sproc) } c_p->off_heap.overhead += sproc->off_heap.overhead; + + ASSERT(sproc->wrt_bins == NULL); } ERTS_GLB_INLINE void @@ -268,6 +265,7 @@ erts_cache_dirty_shadow_proc(Process *sproc) sproc->mbuf = NULL; sproc->mbuf_sz = 0; ERTS_INIT_OFF_HEAP(&sproc->off_heap); + sproc->wrt_bins = NULL; } ERTS_GLB_INLINE Process * diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 776300ae7326..a9661dc78032 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2022. All Rights Reserved. + * Copyright Ericsson AB 2009-2023. 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. @@ -58,6 +58,7 @@ #include "erl_utils.h" #include "erl_io_queue.h" #include "erl_proc_sig_queue.h" +#include "beam_common.h" #undef ERTS_WANT_NFUNC_SCHED_INTERNALS__ #define ERTS_WANT_NFUNC_SCHED_INTERNALS__ #include "erl_nfunc_sched.h" @@ -65,10 +66,22 @@ #define HAVE_USE_DTRACE 1 #endif #include "jit/beam_asm.h" +#include "erl_global_literals.h" #include #include /* offsetof */ +#define ERTS_NIF_HALT_INFO_FLAG_BLOCK (1 << 0) +#define ERTS_NIF_HALT_INFO_FLAG_HALTING (1 << 1) +#define ERTS_NIF_HALT_INFO_FLAG_WAITING (1 << 2) + +typedef struct ErtsNifOnHaltData_ ErtsNifOnHaltData; +struct ErtsNifOnHaltData_ { + ErtsNifOnHaltData *next; + ErtsNifOnHaltData *prev; + ErlNifOnHaltCallback *callback; +}; + /* Information about a loaded nif library. * Each successful call to erlang:load_nif will allocate an instance of * erl_module_nif. Two calls opening the same library will thus have the same @@ -83,21 +96,36 @@ struct erl_module_nif { */ erts_mtx_t load_mtx; /* protects load finish from unload */ struct ErtsNifFinish_* finish; - ErtsThrPrgrLaterOp lop; + ErtsCodeBarrier barrier; void* priv_data; - void* handle; /* "dlopen" */ + void* handle; /* "dlopen", NULL for static linked */ struct enif_entry_t entry; erts_refc_t dynlib_refc; /* References to loaded native code +1 erl_module_instance +1 for each owned resource type with callbacks +1 for each ongoing dirty NIF call */ + int flags; + ErtsNifOnHaltData on_halt; Module* mod; /* Can be NULL if purged and dynlib_refc > 0 */ + /* Holds a copy of the `erl_module_instance` we're loading the module into, + * which may be freed (and moved into the staging table) if there's an + * on_load function that finishes before we're done loading the NIF. */ + struct erl_module_instance mi_copy; + ErlNifFunc _funcs_copy_[1]; /* only used for old libs */ }; +#define ERTS_MOD_NIF_FLG_LOADING (1 << 0) +#define ERTS_MOD_NIF_FLG_DELAY_HALT (1 << 1) +#define ERTS_MOD_NIF_FLG_ON_HALT (1 << 2) + +static erts_atomic_t halt_tse; +static erts_mtx_t on_halt_mtx; +static ErtsNifOnHaltData *on_halt_requests; + typedef ERL_NIF_TERM (*NativeFunPtr)(ErlNifEnv*, int, const ERL_NIF_TERM[]); #ifdef DEBUG @@ -129,6 +157,8 @@ void dtrace_nifenv_str(ErlNifEnv *, char *); #define MIN_HEAP_FRAG_SZ 200 static Eterm* alloc_heap_heavy(ErlNifEnv* env, size_t need, Eterm* hp); +static void install_on_halt_callback(ErtsNifOnHaltData *ohdp); +static void uninstall_on_halt_callback(ErtsNifOnHaltData *ohdp); static ERTS_INLINE int is_scheduler(void) @@ -335,6 +365,7 @@ schedule(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirect_fp, { ErtsNativeFunc *ep; Process *c_p, *dirty_shadow_proc; + ErtsCodePtr caller; execution_state(env, &c_p, NULL); ASSERT(c_p); @@ -346,14 +377,12 @@ schedule(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirect_fp, ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(c_p)); + erts_inspect_frame(c_p->stop, &caller); + ep = erts_nfunc_schedule(c_p, dirty_shadow_proc, c_p->current, - cp_val(c_p->stop[0]), - #ifdef BEAMASM - op_call_nif_WWW, - #else + caller, BeamOpCodeAddr(op_call_nif_WWW), - #endif direct_fp, indirect_fp, mod, func_name, argc, (const Eterm *) argv); @@ -365,6 +394,25 @@ schedule(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirect_fp, return (ERL_NIF_TERM) THE_NON_VALUE; } +static ERTS_NOINLINE void +eternal_sleep(void) +{ + while (!0) + erts_milli_sleep(1000*1000); +} + +static ERTS_NOINLINE void +handle_halting_unblocked_halt(erts_aint32_t info) +{ + if (info & ERTS_NIF_HALT_INFO_FLAG_WAITING) { + erts_tse_t *tse; + ERTS_THR_MEMORY_BARRIER; + tse = (erts_tse_t *) erts_atomic_read_nob(&halt_tse); + ASSERT(tse); + erts_tse_set(tse); + } + eternal_sleep(); +} static ERL_NIF_TERM dirty_nif_finalizer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dirty_nif_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -414,7 +462,34 @@ erts_call_dirty_nif(ErtsSchedulerData *esdp, erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); - result = (*dirty_nif)(&env, codemfa->arity, argv); /* Call dirty NIF */ + if (!(env.mod_nif->flags & ERTS_MOD_NIF_FLG_DELAY_HALT)) { + result = (*dirty_nif)(&env, codemfa->arity, argv); /* Call dirty NIF */ + } + else { + erts_atomic32_t *dirty_nif_halt_info = &esdp->u.dirty_nif_halt_info; + erts_aint32_t info; + info = erts_atomic32_cmpxchg_nob(dirty_nif_halt_info, + ERTS_NIF_HALT_INFO_FLAG_BLOCK, + 0); + if (info != 0) { + ASSERT(info == ERTS_NIF_HALT_INFO_FLAG_HALTING + || info == (ERTS_NIF_HALT_INFO_FLAG_HALTING + | ERTS_NIF_HALT_INFO_FLAG_WAITING)); + eternal_sleep(); + } + result = (*dirty_nif)(&env, codemfa->arity, argv); /* Call dirty NIF */ + info = erts_atomic32_read_band_relb(dirty_nif_halt_info, + ~ERTS_NIF_HALT_INFO_FLAG_BLOCK); + if (info & ERTS_NIF_HALT_INFO_FLAG_HALTING) { + ASSERT(info == (ERTS_NIF_HALT_INFO_FLAG_BLOCK + | ERTS_NIF_HALT_INFO_FLAG_HALTING) + || info == (ERTS_NIF_HALT_INFO_FLAG_BLOCK + | ERTS_NIF_HALT_INFO_FLAG_HALTING + | ERTS_NIF_HALT_INFO_FLAG_WAITING)); + handle_halting_unblocked_halt(info); + } + ASSERT(info == ERTS_NIF_HALT_INFO_FLAG_BLOCK); + } erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); @@ -552,22 +627,15 @@ struct enif_msg_environment_t Process phony_proc; }; -#if S_REDZONE == 0 -/* - * Arrays of size zero are not allowed (although some compilers do - * allow it). Be sure to set the array size to 1 if there is no - * redzone to ensure that the code can be compiled with any compiler. - */ -static Eterm phony_heap[1]; -#else -static Eterm phony_heap[S_REDZONE]; -#endif +static Eterm phony_heap[32]; static ERTS_INLINE void setup_nif_env(struct enif_msg_environment_t* msg_env, struct erl_module_nif* mod, Process* tracee) { + ASSERT(sizeof(phony_heap) > (S_REDZONE * sizeof(Eterm))); + msg_env->env.hp = &phony_heap[0]; msg_env->env.hp_end = &phony_heap[0]; msg_env->env.heap_frag = NULL; @@ -646,6 +714,7 @@ void enif_clear_env(ErlNifEnv* env) menv->env.hp = menv->env.hp_end = HEAP_TOP(p); ASSERT(!is_offheap(&MSO(p))); + ASSERT(!p->wrt_bins); } #ifdef DEBUG @@ -1169,7 +1238,7 @@ int enif_is_empty_list(ErlNifEnv* env, ERL_NIF_TERM term) int enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM term) { - return is_fun(term); + return is_any_fun(term); } int enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term) @@ -1217,7 +1286,6 @@ ErlNifTermType enif_term_type(ErlNifEnv* env, ERL_NIF_TERM term) { return ERL_NIF_TERM_TYPE_BITSTRING; case FLOAT_DEF: return ERL_NIF_TERM_TYPE_FLOAT; - case EXPORT_DEF: case FUN_DEF: return ERL_NIF_TERM_TYPE_FUN; case BIG_DEF: @@ -1491,36 +1559,104 @@ int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, const Eterm** array) return 1; } -int enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char* buf, unsigned len, - ErlNifCharEncoding encoding) +int enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char *buf, unsigned len, + ErlNifCharEncoding encoding) { - Eterm* listptr; - int n = 0; - - ASSERT(encoding == ERL_NIF_LATIN1); + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); if (len < 1) { - return 0; + return 0; } - while (is_not_nil(list)) { - if (is_not_list(list)) { - buf[n] = '\0'; - return 0; - } - listptr = list_val(list); - - if (!is_byte(*listptr)) { - buf[n] = '\0'; - return 0; - } - buf[n++] = unsigned_val(*listptr); - if (n >= len) { - buf[n-1] = '\0'; /* truncate */ - return -len; - } - list = CDR(listptr); + if (encoding == ERL_NIF_LATIN1) { + Eterm *listptr; + int n = 0; + while (is_not_nil(list)) { + if (is_not_list(list)) { + buf[n] = '\0'; + return 0; + } + listptr = list_val(list); + + if (!is_byte(*listptr)) { + buf[n] = '\0'; + return 0; + } + buf[n++] = unsigned_val(*listptr); + if (n >= len) { + buf[n-1] = '\0'; /* truncate */ + return -len; + } + list = CDR(listptr); + } + buf[n] = '\0'; + return n + 1; + } else if (encoding == ERL_NIF_UTF8) { + int retval; + Sint written = 0; + if (is_nil(list)) { + buf[0] = '\0'; + return 1; + } + if (is_not_list(list)) { + buf[0] = '\0'; + return 0; + } + retval = erts_unicode_list_to_buf(list, (byte *)buf, (Sint)(len - 1), (Sint)len, &written); + if (retval == 0) { + if (len > 0 && written == 0) { + buf[written] = '\0'; + return 1; + } + buf[written] = '\0'; /* success */ + return (int)(written + 1); + } + if (retval == -2) { + buf[written] = '\0'; /* truncate */ + return -(int)(written + 1); + } + buf[0] = '\0'; /* failure */ + return 0; } - buf[n] = '\0'; - return n + 1; + return 0; +} + +int enif_get_string_length(ErlNifEnv *env, ERL_NIF_TERM list, unsigned *len, + ErlNifCharEncoding encoding) +{ + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (encoding == ERL_NIF_LATIN1) { + Eterm *listptr = NULL; + unsigned n = 0; + while (is_not_nil(list)) { + if (is_not_list(list)) { + return 0; + } + listptr = list_val(list); + + if (!is_byte(*listptr)) { + return 0; + } + n++; + list = CDR(listptr); + } + *len = n; + return 1; + } else if (encoding == ERL_NIF_UTF8) { + Sint sz = 0; + if (is_nil(list)) { + *len = (unsigned)(sz); + return 1; + } + if (is_not_list(list)) { + return 0; + } + sz = erts_unicode_list_to_buf_len(list); + if (sz < 0) { + return 0; + } + *len = (unsigned)(sz); + return 1; + } + return 0; } Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin) @@ -1620,27 +1756,36 @@ int enif_has_pending_exception(ErlNifEnv* env, ERL_NIF_TERM* reason) } int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len, - ErlNifCharEncoding encoding) + ErlNifCharEncoding encoding) { Atom* ap; - ASSERT(encoding == ERL_NIF_LATIN1); - if (is_not_atom(atom) || len==0) { - return 0; + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (is_not_atom(atom) || len == 0) { + return 0; } ap = atom_tab(atom_val(atom)); - if (ap->latin1_chars < 0 || ap->latin1_chars >= len) { - return 0; - } - if (ap->latin1_chars == ap->len) { - sys_memcpy(buf, ap->name, ap->len); - } - else { - int dlen = erts_utf8_to_latin1((byte*)buf, ap->name, ap->len); - ASSERT(dlen == ap->latin1_chars); (void)dlen; + if (encoding == ERL_NIF_LATIN1) { + if (ap->latin1_chars < 0 || ap->latin1_chars >= len) { + return 0; + } + if (ap->latin1_chars == ap->len) { + sys_memcpy(buf, ap->name, ap->len); + } else { + int dlen = erts_utf8_to_latin1((byte*)buf, ap->name, ap->len); + ASSERT(dlen == ap->latin1_chars); (void)dlen; + } + buf[ap->latin1_chars] = '\0'; + return ap->latin1_chars + 1; + } else if (encoding == ERL_NIF_UTF8) { + if (ap->len >= len) { + return 0; + } + sys_memcpy(buf, ap->name, ap->len); + buf[ap->len] = '\0'; + return ap->len + 1; } - buf[ap->latin1_chars] = '\0'; - return ap->latin1_chars + 1; + return 0; } int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) @@ -1736,17 +1881,24 @@ int enif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp) } int enif_get_atom_length(ErlNifEnv* env, Eterm atom, unsigned* len, - ErlNifCharEncoding enc) + ErlNifCharEncoding encoding) { - Atom* ap; - ASSERT(enc == ERL_NIF_LATIN1); - if (is_not_atom(atom)) return 0; + Atom *ap = NULL; + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (is_not_atom(atom)) + return 0; ap = atom_tab(atom_val(atom)); - if (ap->latin1_chars < 0) { - return 0; + if (encoding == ERL_NIF_LATIN1) { + if (ap->latin1_chars < 0) { + return 0; + } + *len = ap->latin1_chars; + return 1; + } else if (encoding == ERL_NIF_UTF8) { + *len = ap->len; + return 1; } - *len = ap->latin1_chars; - return 1; + return 0; } int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail) @@ -1858,68 +2010,107 @@ ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d) return make_float(hp); } -ERL_NIF_TERM enif_make_atom(ErlNifEnv* env, const char* name) +ERL_NIF_TERM enif_make_atom(ErlNifEnv *env, const char *name) { return enif_make_atom_len(env, name, sys_strlen(name)); } -ERL_NIF_TERM enif_make_atom_len(ErlNifEnv* env, const char* name, size_t len) +ERL_NIF_TERM enif_make_atom_len(ErlNifEnv *env, const char *name, size_t len) { - if (len > MAX_ATOM_CHARACTERS) + ERL_NIF_TERM atom = THE_NON_VALUE; + if (!enif_make_new_atom_len(env, name, len, &atom, ERL_NIF_LATIN1)) { return enif_make_badarg(env); - return erts_atom_put((byte*)name, len, ERTS_ATOM_ENC_LATIN1, 1); + } + return atom; } -int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom, - ErlNifCharEncoding enc) +int enif_make_new_atom(ErlNifEnv *env, const char *name, ERL_NIF_TERM *atom, + ErlNifCharEncoding encoding) { - return enif_make_existing_atom_len(env, name, sys_strlen(name), atom, enc); + return enif_make_new_atom_len(env, name, sys_strlen(name), atom, encoding); } -int enif_make_existing_atom_len(ErlNifEnv* env, const char* name, size_t len, - ERL_NIF_TERM* atom, ErlNifCharEncoding encoding) +int enif_make_new_atom_len(ErlNifEnv *env, const char *name, size_t len, + ERL_NIF_TERM *atom, ErlNifCharEncoding encoding) { - ASSERT(encoding == ERL_NIF_LATIN1); - if (len > MAX_ATOM_CHARACTERS) + ERL_NIF_TERM atom_term = THE_NON_VALUE; + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (encoding == ERL_NIF_LATIN1) { + atom_term = erts_atom_put((byte *)name, len, ERTS_ATOM_ENC_LATIN1, 0); + } else if (encoding == ERL_NIF_UTF8) { + atom_term = erts_atom_put((byte *)name, len, ERTS_ATOM_ENC_UTF8, 0); + } + if (atom_term == THE_NON_VALUE) return 0; - return erts_atom_get(name, len, atom, ERTS_ATOM_ENC_LATIN1); + *atom = atom_term; + return 1; +} + +int enif_make_existing_atom(ErlNifEnv *env, const char *name, ERL_NIF_TERM *atom, + ErlNifCharEncoding encoding) +{ + return enif_make_existing_atom_len(env, name, sys_strlen(name), atom, encoding); +} + +int enif_make_existing_atom_len(ErlNifEnv *env, const char *name, size_t len, + ERL_NIF_TERM *atom, ErlNifCharEncoding encoding) +{ + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (encoding == ERL_NIF_LATIN1) { + if (len > MAX_ATOM_CHARACTERS) + return 0; + return erts_atom_get(name, len, atom, ERTS_ATOM_ENC_LATIN1); + } else if (encoding == ERL_NIF_UTF8) { + if (len > MAX_ATOM_SZ_LIMIT) + return 0; + return erts_atom_get(name, len, atom, ERTS_ATOM_ENC_UTF8); + } + return 0; } ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...) { + if (cnt == 0) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { #ifdef ERTS_NIF_ASSERT_IN_ENV - int nr = 0; + int nr = 0; #endif - Eterm* hp = alloc_heap(env,cnt+1); - Eterm ret = make_tuple(hp); - va_list ap; - - *hp++ = make_arityval(cnt); - va_start(ap,cnt); - while (cnt--) { - Eterm elem = va_arg(ap,Eterm); - ASSERT_IN_ENV(env, elem, ++nr, "tuple"); - *hp++ = elem; + Eterm* hp = alloc_heap(env,cnt+1); + Eterm ret = make_tuple(hp); + va_list ap; + + *hp++ = make_arityval(cnt); + va_start(ap,cnt); + while (cnt--) { + Eterm elem = va_arg(ap,Eterm); + ASSERT_IN_ENV(env, elem, ++nr, "tuple"); + *hp++ = elem; + } + va_end(ap); + return ret; } - va_end(ap); - return ret; } ERL_NIF_TERM enif_make_tuple_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt) { + if (cnt == 0) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { #ifdef ERTS_NIF_ASSERT_IN_ENV - int nr = 0; + int nr = 0; #endif - Eterm* hp = alloc_heap(env,cnt+1); - Eterm ret = make_tuple(hp); - const Eterm* src = arr; - - *hp++ = make_arityval(cnt); - while (cnt--) { - ASSERT_IN_ENV(env, *src, ++nr, "tuple"); - *hp++ = *src++; + Eterm* hp = alloc_heap(env,cnt+1); + Eterm ret = make_tuple(hp); + const Eterm* src = arr; + + *hp++ = make_arityval(cnt); + while (cnt--) { + ASSERT_IN_ENV(env, *src, ++nr, "tuple"); + *hp++ = *src++; + } + return ret; } - return ret; } ERL_NIF_TERM enif_make_list_cell(ErlNifEnv* env, Eterm car, Eterm cdr) @@ -1985,18 +2176,32 @@ ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], return ret; } -ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string, - ErlNifCharEncoding encoding) +ERL_NIF_TERM enif_make_string(ErlNifEnv *env, const char *string, + ErlNifCharEncoding encoding) { return enif_make_string_len(env, string, sys_strlen(string), encoding); } -ERL_NIF_TERM enif_make_string_len(ErlNifEnv* env, const char* string, - size_t len, ErlNifCharEncoding encoding) -{ - Eterm* hp = alloc_heap(env,len*2); - ASSERT(encoding == ERL_NIF_LATIN1); - return erts_bld_string_n(&hp,NULL,string,len); +ERL_NIF_TERM enif_make_string_len(ErlNifEnv *env, const char *string, + size_t len, ErlNifCharEncoding encoding) +{ + Eterm *hp = NULL; + ASSERT(encoding == ERL_NIF_LATIN1 || encoding == ERL_NIF_UTF8); + if (encoding == ERL_NIF_LATIN1) { + hp = alloc_heap(env, len * 2); + return erts_bld_string_n(&hp, NULL, string, len); + } else if (encoding == ERL_NIF_UTF8) { + const byte *err_pos; + Uint num_chars; + Uint num_built; /* characters */ + Uint num_eaten; /* bytes */ + if (erts_analyze_utf8((byte *)string, (Uint)len, &err_pos, &num_chars, NULL) != ERTS_UTF8_OK) { + return enif_make_badarg(env); + } + hp = alloc_heap(env, num_chars * 2); + return erts_make_list_from_utf8_buf(&hp, num_chars, (byte *)string, (Uint)len, &num_built, &num_eaten, NIL); + } + return enif_make_badarg(env); } ERL_NIF_TERM enif_make_ref(ErlNifEnv* env) @@ -2227,7 +2432,7 @@ int enif_vsnprintf(char* buffer, size_t size, const char *format, va_list ap) /* * Sentinel node in circular list of all resource types. - * List protected by code_write_permission. + * List protected by code modification permission. */ struct enif_resource_type_t resource_type_list; @@ -2262,23 +2467,28 @@ static void deref_nifmod(struct erl_module_nif* lib) } } +static ErtsStaticNif* is_static_nif_module(Eterm mod_atom); + static void close_dynlib(struct erl_module_nif* lib) { ASSERT(lib != NULL); ASSERT(lib->mod == NULL); - ASSERT(lib->handle != NULL); ASSERT(erts_refc_read(&lib->dynlib_refc,0) == 0); + if (lib->flags & ERTS_MOD_NIF_FLG_ON_HALT) + uninstall_on_halt_callback(&lib->on_halt); + if (lib->entry.unload != NULL) { struct enif_msg_environment_t msg_env; pre_nif_noproc(&msg_env, lib, NULL); lib->entry.unload(&msg_env.env, lib->priv_data); post_nif_noproc(&msg_env); } - if (!erts_is_static_nif(lib->handle)) + if (lib->handle) { erts_sys_ddll_close(lib->handle); + lib->handle = NULL; + } - lib->handle = NULL; deref_nifmod(lib); } @@ -2370,7 +2580,10 @@ ErlNifResourceType* open_resource_type(ErlNifEnv* env, ErlNifResourceFlags op = flags; Eterm module_am, name_am; - ERTS_LC_ASSERT(erts_has_code_write_permission()); + if (!env->mod_nif || !(env->mod_nif->flags & ERTS_MOD_NIF_FLG_LOADING)) + goto done; + + ERTS_LC_ASSERT(erts_has_code_mod_permission()); module_am = make_atom(env->mod_nif->mod->module); name_am = enif_make_atom(env, name_str); @@ -2426,6 +2639,7 @@ ErlNifResourceType* open_resource_type(ErlNifEnv* env, ort->next = opened_rt_list; opened_rt_list = ort; } +done: if (tried != NULL) { *tried = op; } @@ -2601,7 +2815,8 @@ static int dtor_demonitor(ErtsMonitor* mon, void* context, Sint reds) ASSERT(erts_monitor_is_origin(mon)); ASSERT(is_internal_pid(mon->other.item)); - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(NULL, am_system, 1, mon); + return 1; } @@ -2707,7 +2922,7 @@ void erts_nif_demonitored(ErtsResource* resource) ASSERT(resource->type->fn.down); erts_mtx_lock(&rmp->lock); - free_me = ((rmon_refc_dec_read(rmp) == 0) & !!rmon_is_dying(rmp)); + free_me = ((rmon_refc_dec_read(rmp) == 0) && !!rmon_is_dying(rmp)); erts_mtx_unlock(&rmp->lock); if (free_me) @@ -3282,12 +3497,11 @@ int enif_get_map_size(ErlNifEnv* env, ERL_NIF_TERM term, size_t *size) ERL_NIF_TERM enif_make_new_map(ErlNifEnv* env) { - Eterm* hp = alloc_heap(env,MAP_HEADER_FLATMAP_SZ+1); + Eterm* hp = alloc_heap(env,MAP_HEADER_FLATMAP_SZ); Eterm tup; flatmap_t *mp; - tup = make_tuple(hp); - *hp++ = make_arityval(0); + tup = ERTS_GLOBAL_LIT_EMPTY_TUPLE; mp = (flatmap_t*)hp; mp->thing_word = MAP_HEADER_FLATMAP; mp->size = 0; @@ -3621,7 +3835,8 @@ int enif_monitor_process(ErlNifEnv* env, void* obj, const ErlNifPid* target_pid, rmon_refc_inc(rm); erts_mtx_unlock(&rm->lock); - if (!erts_proc_sig_send_monitor(&mdp->u.target, target_pid->pid)) { + if (!erts_proc_sig_send_monitor(NULL, am_system, &mdp->u.target, + target_pid->pid)) { /* Failed to send monitor signal; cleanup... */ #ifdef DEBUG ErtsBinary* bin = ERTS_MAGIC_BIN_FROM_UNALIGNED_DATA(rsrc); @@ -3680,7 +3895,7 @@ int enif_demonitor_process(ErlNifEnv* env, void* obj, const ErlNifMonitor* monit ASSERT(erts_monitor_is_origin(mon)); ASSERT(is_internal_pid(mon->other.item)); - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(NULL, am_system, 1, mon); return 0; } @@ -4119,8 +4334,8 @@ SysIOVec *enif_ioq_peek(ErlNifIOQueue *q, int *iovlen) ** load_nif/2 ** ***************************************************************************/ -static const ErtsCodeInfo * const * get_func_pp(const BeamCodeHeader* mod_code, - Eterm f_atom, unsigned arity) +static int get_func_ix(const BeamCodeHeader* mod_code, + Eterm f_atom, unsigned arity) { int n = (int) mod_code->num_functions; int j; @@ -4129,16 +4344,15 @@ static const ErtsCodeInfo * const * get_func_pp(const BeamCodeHeader* mod_code, const ErtsCodeInfo* ci = mod_code->functions[j]; #ifndef BEAMASM - ASSERT(BeamIsOpCode(ci->op, op_i_func_info_IaaI)); + ASSERT(BeamIsOpCode(ci->u.op, op_i_func_info_IaaI)); #endif - if (f_atom == ci->mfa.function - && arity == ci->mfa.arity) { - return &mod_code->functions[j]; + if (f_atom == ci->mfa.function && arity == ci->mfa.arity) { + return j; } } - return NULL; + return -1; } static Eterm mkatom(const char *str) @@ -4162,7 +4376,7 @@ void erts_add_taint(Eterm mod_atom) struct tainted_module_t *first, *t; ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_driver_list_lock) - || erts_has_code_write_permission()); + || erts_has_code_mod_permission()); first = (struct tainted_module_t*) erts_atomic_read_nob(&first_taint); for (t=first ; t; t=t->next) { @@ -4312,15 +4526,13 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) { typedef struct { HashBucket bucket; - const ErtsCodeInfo *code_info_exec; - ErtsCodeInfo *code_info_rw; + const ErtsCodeInfo *code_info_ptr; ErtsCodeInfo info; struct { /* data */ #ifdef BEAMASM - BeamInstr prologue[BEAM_ASM_FUNC_PROLOGUE_SIZE / sizeof(UWord)]; - BeamInstr call_nif[10]; + char call_nif[64]; #else BeamInstr call_nif[4]; #endif @@ -4345,12 +4557,12 @@ struct hash erts_nif_call_tab; static HashValue nif_call_hash(ErtsNifBeamStub* obj) { - return ((HashValue)obj->code_info_exec / sizeof(BeamInstr)); + return ((HashValue)obj->code_info_ptr / sizeof(BeamInstr)); } static int nif_call_cmp(ErtsNifBeamStub* tmpl, ErtsNifBeamStub* obj) { - return tmpl->code_info_exec != obj->code_info_exec; + return tmpl->code_info_ptr != obj->code_info_ptr; } static ErtsNifBeamStub* nif_call_alloc(ErtsNifBeamStub* tmpl) @@ -4384,6 +4596,12 @@ static void nif_call_table_init(void) hash_init(ERTS_ALC_T_NIF, &erts_nif_call_tab, "nif_call_tab", 100, f); } +static int check_is_nifable(const BeamCodeHeader* mod_code, + int func_ix) +{ + return !mod_code->are_nifs || mod_code->are_nifs[func_ix]; +} + static void patch_call_nif_early(ErlNifEntry*, struct erl_module_instance*); Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) @@ -4398,13 +4616,12 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) int i, err, encoding; Module* module_p; Eterm mod_atom; - const Atom* mod_atomp; Eterm f_atom; const ErtsCodeMFA* caller; ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT; Eterm ret = am_ok; int veto; - int taint = 1; + int is_static = 0; struct erl_module_nif* lib = NULL; struct erl_module_instance* this_mi; struct erl_module_instance* prev_mi; @@ -4430,14 +4647,11 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) module_p = erts_get_module(mod_atom, erts_active_code_ix()); ASSERT(module_p != NULL); - mod_atomp = atom_tab(atom_val(mod_atom)); { - ErtsStaticNifEntry* sne; - sne = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len); + ErtsStaticNif* sne = is_static_nif_module(mod_atom); if (sne != NULL) { - init_func = sne->nif_init; - handle = init_func; - taint = sne->taint; + entry = sne->entry; + is_static = 1; } } this_mi = &module_p->curr; @@ -4460,7 +4674,7 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) ret = load_nif_error(c_p,"reload","NIF library already loaded" " (reload disallowed since OTP 20)."); } - else if (init_func == NULL && + else if (!is_static && (err=erts_sys_ddll_open(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) { const char slogan[] = "Failed to load NIF library"; if (strstr(errdesc.str, lib_name) != NULL) { @@ -4470,14 +4684,15 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) ret = load_nif_error(c_p, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str); } } - else if (init_func == NULL && + else if (!is_static && erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) { ret = load_nif_error(c_p, bad_lib, "Failed to find library init" " function: '%s'", errdesc.str); } - else if ((taint ? erts_add_taint(mod_atom) : 0, - (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) { + else if (!is_static && + (erts_add_taint(mod_atom), + (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) { ret = load_nif_error(c_p, bad_lib, "Library init-call unsuccessful"); } else if (entry->major > ERL_NIF_MAJOR_VERSION @@ -4512,8 +4727,11 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) lib->handle = handle; erts_refc_init(&lib->refc, 2); /* Erlang code + NIF code */ erts_refc_init(&lib->dynlib_refc, 1); + lib->flags = 0; + lib->on_halt.callback = NULL; ASSERT(opened_rt_list == NULL); lib->mod = module_p; + lib->mi_copy = *this_mi; lib->finish = erts_alloc(ERTS_ALC_T_NIF, sizeof_ErtsNifFinish(entry->num_of_funcs)); @@ -4521,21 +4739,27 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) erts_rwmtx_rwlock(&erts_nif_call_tab_lock); for (i=0; i < entry->num_of_funcs; i++) { - const ErtsCodeInfo * const * ci_pp; + int func_ix; const ErtsCodeInfo* ci; ErlNifFunc* f = &entry->funcs[i]; ErtsNifBeamStub* stub = &lib->finish->beam_stubv[i]; - stub->code_info_exec = NULL; /* end marker in case we fail */ + stub->code_info_ptr = NULL; /* end marker in case we fail */ if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom, ERTS_ATOM_ENC_LATIN1) - || (ci_pp = get_func_pp(this_mi->code_hdr, f_atom, f->arity))==NULL) { + || (func_ix = get_func_ix(this_mi->code_hdr, f_atom, f->arity)) < 0) { ret = load_nif_error(c_p,bad_lib,"Function not found %T:%s/%u", mod_atom, f->name, f->arity); break; } - ci = *ci_pp; + ci = this_mi->code_hdr->functions[func_ix]; + + if (!check_is_nifable(this_mi->code_hdr, func_ix)) { + ret = load_nif_error(c_p,bad_lib,"Function not declared as nif %T:%s/%u", + mod_atom, f->name, f->arity); + break; + } if (f->flags != 0 && f->flags != ERL_NIF_DIRTY_JOB_IO_BOUND && @@ -4550,8 +4774,8 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) { ErtsCodePtr curr_func, next_func; - curr_func = erts_codeinfo_to_code((ErtsCodeInfo*)ci_pp[0]); - next_func = erts_codeinfo_to_code((ErtsCodeInfo*)ci_pp[1]); + curr_func = erts_codeinfo_to_code(this_mi->code_hdr->functions[func_ix]); + next_func = erts_codeinfo_to_code(this_mi->code_hdr->functions[func_ix+1]); ASSERT(!ErtsInArea(next_func, curr_func, @@ -4562,8 +4786,7 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) ERTS_CT_ASSERT(sizeof(stub->code) <= BEAM_NATIVE_MIN_FUNC_SZ * sizeof(Eterm)); - stub->code_info_exec = ci; - stub->code_info_rw = erts_writable_code_ptr(this_mi, ci); + stub->code_info_ptr = ci; stub->info = *ci; if (hash_put(&erts_nif_call_tab, stub) != stub) { @@ -4613,18 +4836,18 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) #endif } erts_rwmtx_rwunlock(&erts_nif_call_tab_lock); - ASSERT(lib->finish->nstubs_hashed == lib->entry.num_of_funcs); } if (ret != am_ok) { goto error; } + ASSERT(lib); + ASSERT(lib->finish->nstubs_hashed == lib->entry.num_of_funcs); /* Call load or upgrade: */ - ASSERT(lib); env.mod_nif = lib; - + lib->flags |= ERTS_MOD_NIF_FLG_LOADING; lib->priv_data = NULL; if (prev_mi->nif != NULL) { /**************** Upgrade ***************/ void* prev_old_data = prev_mi->nif->priv_data; @@ -4658,12 +4881,17 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) ret = load_nif_error(c_p, "load", "Library load-call unsuccessful (%d).", veto); } } + lib->flags &= ~ERTS_MOD_NIF_FLG_LOADING; if (ret == am_ok) { /* * Everything ok, make NIF code callable. */ - this_mi->nif = lib; + if (lib->flags & ERTS_MOD_NIF_FLG_ON_HALT) + install_on_halt_callback(&lib->on_halt); + + this_mi->nif = lib; + prepare_opened_rt(lib); /* * The call table lock will make sure all NIFs and callbacks in module @@ -4677,13 +4905,12 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) cleanup_opened_rt(); /* - * Now we wait thread progress, to make sure no process is still - * executing the beam code of the NIFs, before we can patch in the - * final fast multi word call_nif_WWW instructions. + * Schedule a code barrier to make sure that no process is executing + * the to-be-patched functions, and that the `erts_call_nif_early` + * breakpoints are in effect before we try to patch module code. */ erts_refc_inc(&lib->refc, 2); - erts_schedule_thr_prgr_later_op(load_nif_1st_finisher, lib, - &lib->lop); + erts_schedule_code_barrier(&lib->barrier, load_nif_1st_finisher, lib); } else { error: @@ -4696,7 +4923,7 @@ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args) } erts_free(ERTS_ALC_T_NIF, lib); } - if (handle != NULL && !erts_is_static_nif(handle)) { + if (handle != NULL) { erts_sys_ddll_close(handle); } erts_sys_ddll_free_error(&errdesc); @@ -4721,20 +4948,25 @@ static void patch_call_nif_early(ErlNifEntry* entry, { int i; - ERTS_LC_ASSERT(erts_has_code_write_permission()); + ERTS_LC_ASSERT(erts_has_code_mod_permission()); ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&erts_nif_call_tab_lock)); + erts_unseal_module(this_mi); + for (i=0; i < entry->num_of_funcs; i++) { ErlNifFunc* f = &entry->funcs[i]; - const ErtsCodeInfo * const * ci_pp; - ErtsCodeInfo* ci; + const ErtsCodeInfo *ci_exec; + ErtsCodeInfo *ci_rw; Eterm f_atom; + int func_ix; erts_atom_get(f->name, sys_strlen(f->name), &f_atom, ERTS_ATOM_ENC_LATIN1); - ci_pp = get_func_pp(this_mi->code_hdr, f_atom, f->arity); - ci = erts_writable_code_ptr(this_mi, *ci_pp); + func_ix = get_func_ix(this_mi->code_hdr, f_atom, f->arity); + ci_exec = this_mi->code_hdr->functions[func_ix]; + + ci_rw = erts_writable_code_ptr(this_mi, ci_exec); #ifndef BEAMASM { @@ -4742,14 +4974,14 @@ static void patch_call_nif_early(ErlNifEntry* entry, BeamInstr volatile *code_ptr; /* `ci` is writable. */ - code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci); + code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci_rw); - if (ci->u.gen_bp) { + if (ci_rw->gen_bp) { /* * Function traced, patch the original instruction word * Code write permission protects against racing breakpoint writes. */ - GenericBp* g = ci->u.gen_bp; + GenericBp* g = ci_rw->gen_bp; g->orig_instr = BeamSetCodeAddr(g->orig_instr, call_nif_early); if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)) continue; @@ -4761,9 +4993,11 @@ static void patch_call_nif_early(ErlNifEntry* entry, } #else /* See beam_asm.h for details on how the nif load trampoline works */ - erts_asm_bp_set_flag(ci, ERTS_ASM_BP_FLAG_CALL_NIF_EARLY); + erts_asm_bp_set_flag(ci_rw, ci_exec, ERTS_ASM_BP_FLAG_CALL_NIF_EARLY); #endif } + + erts_seal_module(this_mi); } ErtsCodePtr erts_call_nif_early(Process* c_p, const ErtsCodeInfo* ci) @@ -4771,7 +5005,7 @@ ErtsCodePtr erts_call_nif_early(Process* c_p, const ErtsCodeInfo* ci) ErtsNifBeamStub* bs; ErtsNifBeamStub tmpl; - tmpl.code_info_exec = ci; + tmpl.code_info_ptr = ci; erts_rwmtx_rlock(&erts_nif_call_tab_lock); bs = (ErtsNifBeamStub*) hash_get(&erts_nif_call_tab, &tmpl); @@ -4783,48 +5017,71 @@ ErtsCodePtr erts_call_nif_early(Process* c_p, const ErtsCodeInfo* ci) static void load_nif_1st_finisher(void* vlib) { - struct erl_module_nif* lib = (struct erl_module_nif*) vlib; + struct erl_module_nif* lib = (struct erl_module_nif*)vlib; ErtsNifFinish* fin; int i; + /* Seize code modification permission to ensure that we're the only one + * unsealing modules. */ + if (!erts_try_seize_code_mod_permission_aux(load_nif_1st_finisher, + vlib)) { + return; + } + erts_mtx_lock(&lib->load_mtx); fin = lib->finish; if (fin) { + erts_unseal_module(&lib->mi_copy); + for (i=0; i < lib->entry.num_of_funcs; i++) { - ErtsCodeInfo *ci = fin->beam_stubv[i].code_info_rw; + const ErtsCodeInfo *ci_exec = fin->beam_stubv[i].code_info_ptr; + ErtsCodeInfo *ci_rw; + + ci_rw = erts_writable_code_ptr(&lib->mi_copy, ci_exec); #ifdef BEAMASM - char *code_ptr = (char*)erts_codeinfo_to_code(ci); - sys_memcpy(&code_ptr[BEAM_ASM_FUNC_PROLOGUE_SIZE], - fin->beam_stubv[i].code.call_nif, - sizeof(fin->beam_stubv[0].code.call_nif)); + { + char *code_rw = (char*)erts_codeinfo_to_code(ci_rw); + const char *src = fin->beam_stubv[i].code.call_nif; + + size_t cpy_sz = sizeof(fin->beam_stubv[0].code.call_nif) - + BEAM_ASM_FUNC_PROLOGUE_SIZE; + + sys_memcpy(&code_rw[BEAM_ASM_FUNC_PROLOGUE_SIZE], + &src[BEAM_ASM_FUNC_PROLOGUE_SIZE], + cpy_sz); + } #else - BeamInstr *code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci); + { + BeamInstr *code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci_rw); - /* called function */ - code_ptr[1] = fin->beam_stubv[i].code.call_nif[1]; + (void)ci_exec; - /* erl_module_nif */ - code_ptr[2] = fin->beam_stubv[i].code.call_nif[2]; + /* called function */ + code_ptr[1] = fin->beam_stubv[i].code.call_nif[1]; - if (lib->entry.funcs[i].flags) { - /* real NIF */ - code_ptr[3] = fin->beam_stubv[i].code.call_nif[3]; + /* erl_module_nif */ + code_ptr[2] = fin->beam_stubv[i].code.call_nif[2]; + + if (lib->entry.funcs[i].flags) { + /* real NIF */ + code_ptr[3] = fin->beam_stubv[i].code.call_nif[3]; + } } #endif } + + erts_seal_module(&lib->mi_copy); } erts_mtx_unlock(&lib->load_mtx); + erts_release_code_mod_permission(); + if (fin) { - /* - * A second thread progress to get a memory barrier between the - * arguments of call_nif_WWW (written above) and the instruction word - * itself. - */ - erts_schedule_thr_prgr_later_op(load_nif_2nd_finisher, lib, - &lib->lop); + /* Schedule a code barrier to ensure that the `call_nif_WWW` sequence + * is visible before we start disabling the breakpoints. */ + erts_schedule_code_barrier(&lib->barrier, load_nif_2nd_finisher, lib); } else { /* Unloaded */ deref_nifmod(lib); @@ -4837,58 +5094,72 @@ static void load_nif_2nd_finisher(void* vlib) ErtsNifFinish* fin; int i; - /* - * We seize code write permission only to avoid any trace breakpoints - * to change while we patch the op_call_nif_WWW instruction. - */ - if (!erts_try_seize_code_write_permission_aux(load_nif_2nd_finisher, vlib)) { + /* Seize code modification permission only to prevent any trace breakpoints + * from changing while we patch the op_call_nif_WWW instruction. */ + if (!erts_try_seize_code_mod_permission_aux(load_nif_2nd_finisher, + vlib)) { return; } erts_mtx_lock(&lib->load_mtx); fin = lib->finish; if (fin) { + erts_unseal_module(&lib->mi_copy); + for (i=0; i < lib->entry.num_of_funcs; i++) { - ErtsCodeInfo *ci = fin->beam_stubv[i].code_info_rw; + const ErtsCodeInfo *ci_exec = fin->beam_stubv[i].code_info_ptr; + ErtsCodeInfo *ci_rw; + + ci_rw = erts_writable_code_ptr(&lib->mi_copy, ci_exec); #ifndef BEAMASM - BeamInstr volatile *code_ptr; + { + BeamInstr volatile *code_ptr; - code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci); + ASSERT(ci_exec == ci_rw); + (void)ci_exec; - if (ci->u.gen_bp) { - /* - * Function traced, patch the original instruction word - */ - GenericBp* g = ci->u.gen_bp; - ASSERT(BeamIsOpCode(g->orig_instr, op_call_nif_early)); - g->orig_instr = BeamOpCodeAddr(op_call_nif_WWW); - if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)) - continue; - } + code_ptr = (BeamInstr*)erts_codeinfo_to_code(ci_rw); + + if (ci_rw->gen_bp) { + /* + * Function traced, patch the original instruction word + */ + GenericBp* g = ci_rw->gen_bp; + ASSERT(BeamIsOpCode(g->orig_instr, op_call_nif_early)); + g->orig_instr = BeamOpCodeAddr(op_call_nif_WWW); - ASSERT(BeamIsOpCode(code_ptr[0], op_call_nif_early)); - code_ptr[0] = BeamOpCodeAddr(op_call_nif_WWW); + if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)) { + continue; + } + } + + ASSERT(BeamIsOpCode(code_ptr[0], op_call_nif_early)); + code_ptr[0] = BeamOpCodeAddr(op_call_nif_WWW); + } #else /* See beam_asm.h for details on how the nif load trampoline works */ - erts_asm_bp_unset_flag(ci, ERTS_ASM_BP_FLAG_CALL_NIF_EARLY); + erts_asm_bp_unset_flag(ci_rw, ci_exec, + ERTS_ASM_BP_FLAG_CALL_NIF_EARLY); #endif } + + erts_seal_module(&lib->mi_copy); } erts_mtx_unlock(&lib->load_mtx); - erts_release_code_write_permission(); + erts_release_code_mod_permission(); if (fin) { UWord bytes = sizeof_ErtsNifFinish(lib->entry.num_of_funcs); /* - * A third and final thread progress, to make sure no one is executing - * the call_nif_early instructions anymore, before we can deallocate - * the beam stubs. + * A third and final code barrier to make that the removal of the + * breakpoints is visible and that no one is executing them while we + * remove them. */ - erts_schedule_thr_prgr_later_cleanup_op(load_nif_3rd_finisher, lib, - &lib->lop, - bytes); + erts_schedule_code_barrier_cleanup(&lib->barrier, + load_nif_3rd_finisher, lib, + bytes); } else { /* Unloaded */ deref_nifmod(lib); @@ -4930,6 +5201,29 @@ static void erase_hashed_stubs(ErtsNifFinish* fin) erts_rwmtx_rwunlock(&erts_nif_call_tab_lock); } +static void static_nifs_init(void) +{ + ErtsStaticNif* p; + + for (p = erts_static_nif_tab; p->nif_init != NULL; p++) { + ASSERT(p->entry == NULL && p->mod_atom == THE_NON_VALUE); + p->entry = erts_sys_ddll_call_nif_init(p->nif_init); + p->mod_atom = mkatom(p->entry->name); + if (p->taint) + erts_add_taint(p->mod_atom); + } +} + +static ErtsStaticNif* is_static_nif_module(Eterm mod_atom) +{ + ErtsStaticNif* p; + for (p = erts_static_nif_tab; p->nif_init != NULL; p++) + if (mod_atom == p->mod_atom) + return p; + return NULL; +} + + void erts_unload_nif(struct erl_module_nif* lib) { @@ -4938,7 +5232,8 @@ erts_unload_nif(struct erl_module_nif* lib) ASSERT(lib != NULL); ASSERT(lib->mod != NULL); - ERTS_LC_ASSERT(erts_has_code_write_permission()); + + ERTS_LC_ASSERT(erts_has_code_mod_permission()); erts_tracer_nif_clear(); @@ -4970,7 +5265,7 @@ erts_unload_nif(struct erl_module_nif* lib) deref_nifmod(lib); } -void erl_nif_init() +void erl_nif_init(void) { ERTS_CT_ASSERT((offsetof(ErtsResource,data) % 8) == ERTS_MAGIC_BIN_BYTES_TO_ALIGN); @@ -4984,6 +5279,21 @@ void erl_nif_init() resource_type_list.name = THE_NON_VALUE; nif_call_table_init(); + static_nifs_init(); + + erts_atomic_init_nob(&halt_tse, (erts_aint_t) NULL); + erts_mtx_init(&on_halt_mtx, "on_halt", NIL, + ERTS_LOCK_FLAGS_CATEGORY_GENERIC); + on_halt_requests = NULL; +} + +void +erts_nif_sched_init(ErtsSchedulerData *esdp) +{ + if (esdp->type == ERTS_SCHED_DIRTY_CPU + || esdp->type == ERTS_SCHED_DIRTY_IO) { + erts_atomic32_init_nob(&esdp->u.dirty_nif_halt_info, 0); + } } int erts_nif_get_funcs(struct erl_module_nif* mod, @@ -5025,6 +5335,9 @@ Eterm erts_nif_call_function(Process *p, Process *tracee, ErlHeapFragment *orig_hf = MBUF(p); ErlOffHeap orig_oh = MSO(p); Eterm *orig_htop = HEAP_TOP(p); +#ifdef DEBUG + struct erl_off_heap_header* orig_wrt_bins = p->wrt_bins; +#endif ASSERT(is_internal_pid(p->common.id)); MBUF(p) = NULL; clear_offheap(&MSO(p)); @@ -5050,6 +5363,7 @@ Eterm erts_nif_call_function(Process *p, Process *tracee, MBUF(p) = orig_hf; MSO(p) = orig_oh; HEAP_TOP(p) = orig_htop; + ASSERT(p->wrt_bins == orig_wrt_bins); } else { /* Nif call was done without a process context, so we create a phony one. */ @@ -5067,6 +5381,191 @@ Eterm erts_nif_call_function(Process *p, Process *tracee, return nif_result; } +/* + * Set options... + */ + +int +enif_set_option(ErlNifEnv *env, ErlNifOption opt, ...) +{ + if (!env) + return EINVAL; + + switch (opt) { + + case ERL_NIF_OPT_DELAY_HALT: { + struct erl_module_nif *m = env->mod_nif; + + if (!m || !(m->flags & ERTS_MOD_NIF_FLG_LOADING) + || (m->flags & ERTS_MOD_NIF_FLG_DELAY_HALT)) { + return EINVAL; + } + + m->flags |= ERTS_MOD_NIF_FLG_DELAY_HALT; + + return 0; + } + + case ERL_NIF_OPT_ON_HALT: { + struct erl_module_nif *m = env->mod_nif; + ErlNifOnHaltCallback *on_halt; + va_list argp; + + if (!m || ((m->flags & (ERTS_MOD_NIF_FLG_LOADING + | ERTS_MOD_NIF_FLG_ON_HALT)) + != ERTS_MOD_NIF_FLG_LOADING)) { + return EINVAL; + } + + ASSERT(!m->on_halt.callback); + + va_start(argp, opt); + on_halt = va_arg(argp, ErlNifOnHaltCallback *); + va_end(argp); + if (!on_halt) + return EINVAL; + + m->on_halt.callback = on_halt; + m->flags |= ERTS_MOD_NIF_FLG_ON_HALT; + + return 0; + } + + default: + return EINVAL; + + } +} + +/* + * Halt functionality... + */ + +void +erts_nif_execute_on_halt(void) +{ + ErtsNifOnHaltData *ohdp; + + erts_mtx_lock(&on_halt_mtx); + for (ohdp = on_halt_requests; ohdp; ohdp = ohdp->next) { + struct erl_module_nif *m; + m = ErtsContainerStruct(ohdp, struct erl_module_nif, on_halt); + ohdp->callback(m->priv_data); + } + on_halt_requests = NULL; + erts_mtx_unlock(&on_halt_mtx); +} + +void +erts_nif_notify_halt(void) +{ + int ix; + + erts_nif_execute_on_halt(); + + for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++) { + ErtsSchedulerData *esdp = ERTS_DIRTY_CPU_SCHEDULER_IX(ix); + ASSERT(esdp->type == ERTS_SCHED_DIRTY_CPU); + (void) erts_atomic32_read_bor_nob(&esdp->u.dirty_nif_halt_info, + ERTS_NIF_HALT_INFO_FLAG_HALTING); + } + for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) { + ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix); + ASSERT(esdp->type == ERTS_SCHED_DIRTY_IO); + (void) erts_atomic32_read_bor_nob(&esdp->u.dirty_nif_halt_info, + ERTS_NIF_HALT_INFO_FLAG_HALTING); + } +} + +static ERTS_INLINE void +wait_dirty_call_blocking_halt(ErtsSchedulerData *esdp, erts_tse_t *tse) +{ + erts_atomic32_t *dirty_nif_halt_info = &esdp->u.dirty_nif_halt_info; + erts_aint32_t info = erts_atomic32_read_acqb(dirty_nif_halt_info); + ASSERT(info & ERTS_NIF_HALT_INFO_FLAG_HALTING); + if (!(info & ERTS_NIF_HALT_INFO_FLAG_BLOCK)) + return; + info = erts_atomic32_read_bor_mb(dirty_nif_halt_info, + ERTS_NIF_HALT_INFO_FLAG_WAITING); + if (!(info & ERTS_NIF_HALT_INFO_FLAG_BLOCK)) + return; + while (!0) { + erts_tse_reset(tse); + info = erts_atomic32_read_acqb(dirty_nif_halt_info); + if (!(info & ERTS_NIF_HALT_INFO_FLAG_BLOCK)) + return; + while (!0) { + if (erts_tse_wait(tse) != EINTR) + break; + } + } +} + +void +erts_nif_wait_calls(void) +{ + erts_tse_t *tse; + int ix; + + tse = erts_tse_fetch(); + erts_atomic_set_nob(&halt_tse, (erts_aint_t) tse); + + for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++) { + ErtsSchedulerData *esdp = ERTS_DIRTY_CPU_SCHEDULER_IX(ix); + ASSERT(esdp->type == ERTS_SCHED_DIRTY_CPU); + wait_dirty_call_blocking_halt(esdp, tse); + } + for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) { + ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix); + ASSERT(esdp->type == ERTS_SCHED_DIRTY_IO); + wait_dirty_call_blocking_halt(esdp, tse); + } +} + +static void +install_on_halt_callback(ErtsNifOnHaltData *ohdp) +{ + ASSERT(ohdp->callback); + + erts_mtx_lock(&on_halt_mtx); + ohdp->next = on_halt_requests; + ohdp->prev = NULL; + if (on_halt_requests) + on_halt_requests->prev = ohdp; + on_halt_requests = ohdp; + erts_mtx_unlock(&on_halt_mtx); +} + +static void +uninstall_on_halt_callback(ErtsNifOnHaltData *ohdp) +{ + erts_mtx_lock(&on_halt_mtx); + ohdp->callback = NULL; + if (ohdp->prev) { + ASSERT(on_halt_requests != ohdp); + ohdp->prev->next = ohdp->next; + } + else if (on_halt_requests == ohdp) { + ASSERT(erts_halt_code == INT_MIN); + on_halt_requests = ohdp->next; + } + else { + /* + * Uninstall during halt; and our callback + * has already been called... + */ + ASSERT(erts_halt_code != INT_MIN); + } + if (ohdp->next) { + ohdp->next->prev = ohdp->prev; + } + erts_mtx_unlock(&on_halt_mtx); +} + +/* + * End of halt functionality... + */ + #ifdef USE_VM_PROBES void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf) { diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index e7858a5e3af2..e2e631e8d64f 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2021. All Rights Reserved. + * Copyright Ericsson AB 2009-2023. 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. @@ -57,9 +57,11 @@ ** 2.15: 22.0 ERL_NIF_SELECT_CANCEL, enif_select_(read|write) ** enif_term_type ** 2.16: 24.0 enif_init_resource_type, enif_dynamic_resource_call +** 2.17: 26.0 enif_set_option, enif_get_string_length, enif_make_new_atom, +** enif_make_new_atom_len, ERL_NIF_UTF8 */ #define ERL_NIF_MAJOR_VERSION 2 -#define ERL_NIF_MINOR_VERSION 16 +#define ERL_NIF_MINOR_VERSION 17 /* * WHEN CHANGING INTERFACE VERSION, also replace erts version below with @@ -70,7 +72,7 @@ * If you're not on the OTP team, you should use a placeholder like * erts-@MyName@ instead. */ -#define ERL_NIF_MIN_ERTS_VERSION "erts-12.0" +#define ERL_NIF_MIN_ERTS_VERSION "erts-14.0" /* * The emulator will refuse to load a nif-lib with a major version @@ -186,7 +188,8 @@ typedef enum typedef enum { - ERL_NIF_LATIN1 = 1 + ERL_NIF_LATIN1 = 1, + ERL_NIF_UTF8 = 2, }ErlNifCharEncoding; typedef struct @@ -201,6 +204,8 @@ typedef struct typedef ErlDrvMonitor ErlNifMonitor; +typedef void ErlNifOnHaltCallback(void *priv_data); + typedef struct enif_resource_type_t ErlNifResourceType; typedef void ErlNifResourceDtor(ErlNifEnv*, void*); typedef void ErlNifResourceStop(ErlNifEnv*, void*, ErlNifEvent, int is_direct_call); @@ -325,6 +330,11 @@ typedef enum { #define ERL_NIF_THR_DIRTY_CPU_SCHEDULER 2 #define ERL_NIF_THR_DIRTY_IO_SCHEDULER 3 +typedef enum { + ERL_NIF_OPT_DELAY_HALT = 1, + ERL_NIF_OPT_ON_HALT = 2 +} ErlNifOption; + #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS typedef struct { @@ -335,6 +345,10 @@ extern TWinDynNifCallbacks WinDynNifCallbacks; # undef ERL_NIF_API_FUNC_DECL #endif +#ifdef STATIC_ERLANG_NIF_LIBNAME +# define STATIC_ERLANG_NIF +#endif + #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) && !defined(STATIC_ERLANG_DRIVER) && !defined(STATIC_ERLANG_NIF) # define ERL_NIF_API_FUNC_MACRO(NAME) (WinDynNifCallbacks.NAME) # include "erl_nif_api_funcs.h" @@ -342,6 +356,16 @@ extern TWinDynNifCallbacks WinDynNifCallbacks; #else /* non windows or included from emulator itself */ +/* Redundant declaration of deallocator functions as they are referred to by + * __attribute__(malloc) of allocator functions and we cannot change + * the declaration order in erl_nif_api_funcs.h due to Windows. */ +extern void enif_free(void* ptr); +extern void enif_mutex_destroy(ErlNifMutex *mtx); +extern void enif_cond_destroy(ErlNifCond *cnd); +extern void enif_rwlock_destroy(ErlNifRWLock *rwlck); +extern void enif_thread_opts_destroy(ErlNifThreadOpts *opts); +extern void enif_ioq_destroy(ErlNifIOQueue *q); + # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) extern RET_TYPE NAME ARGS # include "erl_nif_api_funcs.h" # undef ERL_NIF_API_FUNC_DECL @@ -365,12 +389,23 @@ extern TWinDynNifCallbacks WinDynNifCallbacks; # endif #endif + #ifdef STATIC_ERLANG_NIF -# define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* MODNAME ## _nif_init(ERL_NIF_INIT_ARGS) +# ifdef STATIC_ERLANG_NIF_LIBNAME +# define ERL_NIF_INIT_NAME(MODNAME) ERL_NIF_INIT_NAME2(STATIC_ERLANG_NIF_LIBNAME) +# define ERL_NIF_INIT_NAME2(LIB) ERL_NIF_INIT_NAME3(LIB) +# define ERL_NIF_INIT_NAME3(LIB) LIB ## _nif_init +# else +# define ERL_NIF_INIT_NAME(MODNAME) MODNAME ## _nif_init +# endif +# define ERL_NIF_INIT_DECL(MODNAME) \ + ErlNifEntry* ERL_NIF_INIT_NAME(MODNAME)(ERL_NIF_INIT_ARGS) #else -# define ERL_NIF_INIT_DECL(MODNAME) ERL_NIF_INIT_EXPORT ErlNifEntry* nif_init(ERL_NIF_INIT_ARGS) +# define ERL_NIF_INIT_DECL(MODNAME) \ + ERL_NIF_INIT_EXPORT ErlNifEntry* nif_init(ERL_NIF_INIT_ARGS) #endif + #ifdef __cplusplus } # define ERL_NIF_INIT_PROLOGUE extern "C" { diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 27fa953099ef..998bfebd8baa 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2021. All Rights Reserved. + * Copyright Ericsson AB 2009-2022. 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. @@ -31,7 +31,7 @@ */ #ifdef ERL_NIF_API_FUNC_DECL ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*)); -ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size)); +ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size) ERL_NAPI_ATTR_MALLOC_USD(1,enif_free,1)); ERL_NIF_API_FUNC_DECL(void,enif_free,(void* ptr)); ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term)); ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term)); @@ -60,17 +60,17 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string, ErlNifCharEncoding)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env)); -ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name)); +ERL_NIF_API_FUNC_DECL(ErlNifMutex*,enif_mutex_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_mutex_destroy,1)); ERL_NIF_API_FUNC_DECL(void,enif_mutex_destroy,(ErlNifMutex *mtx)); ERL_NIF_API_FUNC_DECL(int,enif_mutex_trylock,(ErlNifMutex *mtx)); ERL_NIF_API_FUNC_DECL(void,enif_mutex_lock,(ErlNifMutex *mtx)); ERL_NIF_API_FUNC_DECL(void,enif_mutex_unlock,(ErlNifMutex *mtx)); -ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name)); +ERL_NIF_API_FUNC_DECL(ErlNifCond*,enif_cond_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_cond_destroy,1)); ERL_NIF_API_FUNC_DECL(void,enif_cond_destroy,(ErlNifCond *cnd)); ERL_NIF_API_FUNC_DECL(void,enif_cond_signal,(ErlNifCond *cnd)); ERL_NIF_API_FUNC_DECL(void,enif_cond_broadcast,(ErlNifCond *cnd)); ERL_NIF_API_FUNC_DECL(void,enif_cond_wait,(ErlNifCond *cnd, ErlNifMutex *mtx)); -ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name)); +ERL_NIF_API_FUNC_DECL(ErlNifRWLock*,enif_rwlock_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_rwlock_destroy,1)); ERL_NIF_API_FUNC_DECL(void,enif_rwlock_destroy,(ErlNifRWLock *rwlck)); ERL_NIF_API_FUNC_DECL(int,enif_rwlock_tryrlock,(ErlNifRWLock *rwlck)); ERL_NIF_API_FUNC_DECL(void,enif_rwlock_rlock,(ErlNifRWLock *rwlck)); @@ -82,7 +82,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_tsd_key_create,(char *name, ErlNifTSDKey *key)); ERL_NIF_API_FUNC_DECL(void,enif_tsd_key_destroy,(ErlNifTSDKey key)); ERL_NIF_API_FUNC_DECL(void,enif_tsd_set,(ErlNifTSDKey key, void *data)); ERL_NIF_API_FUNC_DECL(void*,enif_tsd_get,(ErlNifTSDKey key)); -ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name)); +ERL_NIF_API_FUNC_DECL(ErlNifThreadOpts*,enif_thread_opts_create,(char *name) ERL_NAPI_ATTR_MALLOC_D(enif_thread_opts_destroy,1)); ERL_NIF_API_FUNC_DECL(void,enif_thread_opts_destroy,(ErlNifThreadOpts *opts)); ERL_NIF_API_FUNC_DECL(int,enif_thread_create,(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)); ERL_NIF_API_FUNC_DECL(ErlNifTid,enif_thread_self,(void)); @@ -90,7 +90,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_equal_tids,(ErlNifTid tid1, ErlNifTid tid2)); ERL_NIF_API_FUNC_DECL(void,enif_thread_exit,(void *resp)); ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp)); -ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size)); +ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size) ERL_NAPI_ATTR_ALLOC_SIZE(2)); ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size)); ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(FILE* filep, const char *format, ...)); ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin)); @@ -108,7 +108,7 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple_from_array,(ErlNifEnv*, const ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_from_array,(ErlNifEnv*, const ERL_NIF_TERM arr[], unsigned cnt)); ERL_NIF_API_FUNC_DECL(int,enif_is_empty_list,(ErlNifEnv*, ERL_NIF_TERM term)); ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_open_resource_type,(ErlNifEnv*, const char* module_str, const char* name_str, void (*dtor)(ErlNifEnv*,void *), ErlNifResourceFlags flags, ErlNifResourceFlags* tried)); -ERL_NIF_API_FUNC_DECL(void*,enif_alloc_resource,(ErlNifResourceType* type, size_t size)); +ERL_NIF_API_FUNC_DECL(void *, enif_alloc_resource, (ErlNifResourceType *type, size_t size) ERL_NAPI_ATTR_MALLOC_US(2)); ERL_NIF_API_FUNC_DECL(void,enif_release_resource,(void* obj)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj)); ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp)); @@ -121,7 +121,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM ter ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len)); ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding)); -ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void)); +ERL_NIF_API_FUNC_DECL(ErlNifEnv*,enif_alloc_env,(void) ERL_NAPI_ATTR_WUR); ERL_NIF_API_FUNC_DECL(void,enif_free_env,(ErlNifEnv* env)); ERL_NIF_API_FUNC_DECL(void,enif_clear_env,(ErlNifEnv* env)); ERL_NIF_API_FUNC_DECL(int,enif_send,(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg)); @@ -184,7 +184,7 @@ ERL_NIF_API_FUNC_DECL(ErlNifUInt64,enif_hash,(ErlNifHash type, ERL_NIF_TERM term ERL_NIF_API_FUNC_DECL(int, enif_whereis_pid, (ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPid *pid)); ERL_NIF_API_FUNC_DECL(int, enif_whereis_port, (ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPort *port)); -ERL_NIF_API_FUNC_DECL(ErlNifIOQueue *,enif_ioq_create,(ErlNifIOQueueOpts opts)); +ERL_NIF_API_FUNC_DECL(ErlNifIOQueue *,enif_ioq_create,(ErlNifIOQueueOpts opts) ERL_NAPI_ATTR_MALLOC_D(enif_ioq_destroy,1)); ERL_NIF_API_FUNC_DECL(void,enif_ioq_destroy,(ErlNifIOQueue *q)); ERL_NIF_API_FUNC_DECL(int,enif_ioq_enq_binary,(ErlNifIOQueue *q, ErlNifBinary *bin, size_t skip)); @@ -219,6 +219,11 @@ ERL_NIF_API_FUNC_DECL(ErlNifTermType,enif_term_type,(ErlNifEnv* env, ERL_NIF_TER ERL_NIF_API_FUNC_DECL(ErlNifResourceType*,enif_init_resource_type,(ErlNifEnv*, const char* name_str, const ErlNifResourceTypeInit*, ErlNifResourceFlags flags, ErlNifResourceFlags* tried)); ERL_NIF_API_FUNC_DECL(int,enif_dynamic_resource_call,(ErlNifEnv*, ERL_NIF_TERM mod, ERL_NIF_TERM name, ERL_NIF_TERM rsrc, void* call_data)); +ERL_NIF_API_FUNC_DECL(int, enif_get_string_length, (ErlNifEnv *env, ERL_NIF_TERM list, unsigned *len, ErlNifCharEncoding encoding)); +ERL_NIF_API_FUNC_DECL(int, enif_make_new_atom, (ErlNifEnv *env, const char *name, ERL_NIF_TERM *atom, ErlNifCharEncoding encoding)); +ERL_NIF_API_FUNC_DECL(int, enif_make_new_atom_len, (ErlNifEnv *env, const char *name, size_t len, ERL_NIF_TERM *atom, ErlNifCharEncoding encoding)); +ERL_NIF_API_FUNC_DECL(int, enif_set_option, (ErlNifEnv *env, ErlNifOption opt, ...)); + /* ** ADD NEW ENTRIES HERE (before this comment) !!! */ @@ -408,6 +413,10 @@ ERL_NIF_API_FUNC_DECL(int,enif_dynamic_resource_call,(ErlNifEnv*, ERL_NIF_TERM m # define enif_term_type ERL_NIF_API_FUNC_MACRO(enif_term_type) # define enif_init_resource_type ERL_NIF_API_FUNC_MACRO(enif_init_resource_type) # define enif_dynamic_resource_call ERL_NIF_API_FUNC_MACRO(enif_dynamic_resource_call) +# define enif_get_string_length ERL_NIF_API_FUNC_MACRO(enif_get_string_length) +# define enif_make_new_atom ERL_NIF_API_FUNC_MACRO(enif_make_new_atom) +# define enif_make_new_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_new_atom_len) +# define enif_set_option ERL_NIF_API_FUNC_MACRO(enif_set_option) /* ** ADD NEW ENTRIES HERE (before this comment) */ diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h index 56ba8bbdb999..a72c97cc4d83 100644 --- a/erts/emulator/beam/erl_node_container_utils.h +++ b/erts/emulator/beam/erl_node_container_utils.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2021. All Rights Reserved. + * Copyright Ericsson AB 2001-2023. 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. @@ -58,7 +58,7 @@ * are used as 'serial'. In the "emulator interface" (external format, * list_to_pid, etc) the least significant 15 bits are presented as * 'number' and the most significant 3 bits are presented as 'serial', - * though. The makro internal_pid_index() can be used for retrieving + * though. The macro internal_pid_index() can be used for retrieving * index into the process table. Do *not* use the result from * pid_number() as an index into the process table. The pid_number() and * pid_serial() (and friends) fetch the old fixed size 'number' and @@ -106,7 +106,7 @@ */ #define dist_entry_channel_no(x) \ ((x) == erts_this_dist_entry \ - ? ((Uint) 0) \ + ? ((Uint) ERST_INTERNAL_CHANNEL_NO) \ : (ASSERT(is_atom((x)->sysname)), \ (Uint) atom_val((x)->sysname))) #define internal_channel_no(x) ((Uint) ERST_INTERNAL_CHANNEL_NO) @@ -176,9 +176,9 @@ extern ErtsPTab erts_proc; */ #define ERTS_MAX_PROCESSES (ERTS_PTAB_MAX_SIZE-1) -#define ERTS_MAX_INTERNAL_PID_DATA ((1 << _PID_DATA_SIZE) - 1) -#define ERTS_MAX_INTERNAL_PID_NUMBER ((1 << _PID_NUM_SIZE) - 1) -#define ERTS_MAX_INTERNAL_PID_SERIAL ((1 << _PID_SER_SIZE) - 1) +#define ERTS_MAX_INTERNAL_PID_DATA ((UWORD_CONSTANT(1) << _PID_DATA_SIZE) - 1) +#define ERTS_MAX_INTERNAL_PID_NUMBER ((UWORD_CONSTANT(1) << _PID_NUM_SIZE) - 1) +#define ERTS_MAX_INTERNAL_PID_SERIAL ((UWORD_CONSTANT(1) << _PID_SER_SIZE) - 1) #define ERTS_INTERNAL_PROC_BITS (_PID_SER_SIZE + _PID_NUM_SIZE) @@ -244,9 +244,9 @@ extern ErtsPTab erts_port; in the Erlang node. ERTS_MAX_PORTS is a hard upper limit. */ #define ERTS_MAX_PORTS (ERTS_PTAB_MAX_SIZE-1) -#define ERTS_MAX_PORT_DATA ((1 << _PORT_DATA_SIZE) - 1) -#define ERTS_MAX_INTERNAL_PORT_NUMBER ((1 << _PORT_NUM_SIZE) - 1) -#define ERTS_MAX_V3_PORT_NUMBER ((1 << _PORT_NUM_SIZE) - 1) +#define ERTS_MAX_PORT_DATA ((UWORD_CONSTANT(1) << _PORT_DATA_SIZE) - 1) +#define ERTS_MAX_INTERNAL_PORT_NUMBER ((UWORD_CONSTANT(1) << _PORT_NUM_SIZE) - 1) +#define ERTS_MAX_V3_PORT_NUMBER ((UWORD_CONSTANT(1) << 28) - 1) #define ERTS_PORTS_BITS (_PORT_NUM_SIZE) @@ -256,7 +256,9 @@ extern ErtsPTab erts_port; * Refs * \* */ -#define internal_ref_no_numbers(x) ERTS_REF_NUMBERS +#define internal_ref_no_numbers(x) (is_internal_pid_ref((x)) \ + ? ERTS_PID_REF_NUMBERS \ + : ERTS_REF_NUMBERS) #define internal_ref_numbers(x) (is_internal_magic_ref((x)) \ ? internal_magic_ref_numbers((x)) \ : internal_non_magic_ref_numbers((x))) diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index e4907cfcd10a..c31d26aaf11f 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -152,9 +152,13 @@ dist_table_alloc(void *dep_tmpl) Eterm sysname; Binary *bin; DistEntry *dep; + Uint32 init_connection_id; erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_RWMTX_TYPE_FREQUENT_READ; + init_connection_id = (Uint32) erts_get_monotonic_time(NULL); + init_connection_id &= ERTS_DIST_CON_ID_MASK; + sysname = ((DistEntry *) dep_tmpl)->sysname; bin = erts_create_magic_binary_x(sizeof(DistEntry), @@ -175,7 +179,7 @@ dist_table_alloc(void *dep_tmpl) dep->creation = 0; /* undefined */ dep->cid = NIL; erts_atomic_init_nob(&dep->input_handler, (erts_aint_t) NIL); - dep->connection_id = 0; + dep->connection_id = init_connection_id; dep->state = ERTS_DE_STATE_IDLE; dep->pending_nodedown = 0; dep->suspended_nodeup = NULL; @@ -187,6 +191,8 @@ dist_table_alloc(void *dep_tmpl) erts_mtx_init(&dep->qlock, "dist_entry_out_queue", sysname, ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); erts_atomic32_init_nob(&dep->qflgs, 0); + erts_atomic32_init_nob(&dep->notify, 0); + erts_atomic_init_nob(&dep->total_qsize, 0); erts_atomic_init_nob(&dep->qsize, 0); erts_atomic64_init_nob(&dep->in, 0); erts_atomic64_init_nob(&dep->out, 0); @@ -725,8 +731,6 @@ erts_set_dist_entry_pending(DistEntry *dep) void erts_set_dist_entry_connected(DistEntry *dep, Eterm cid, Uint64 flags) { - erts_aint32_t set_qflgs; - ASSERT(dep->mld); ERTS_LC_ASSERT(erts_lc_is_de_rwlocked(dep)); @@ -763,9 +767,6 @@ erts_set_dist_entry_connected(DistEntry *dep, Eterm cid, Uint64 flags) erts_atomic64_set_nob(&dep->in, 0); erts_atomic64_set_nob(&dep->out, 0); - set_qflgs = (is_internal_port(cid) ? - ERTS_DE_QFLG_PORT_CTRL : ERTS_DE_QFLG_PROC_CTRL); - erts_atomic32_read_bor_nob(&dep->qflgs, set_qflgs); if(flags & DFLAG_PUBLISHED) { dep->next = erts_visible_dist_entries; @@ -1526,7 +1527,7 @@ static void insert_offheap(ErlOffHeap *oh, int type, Eterm id) { union erl_off_heap_ptr u; - struct erts_tmp_aligned_offheap tmp; + union erts_tmp_aligned_offheap tmp; struct insert_offheap2_arg a; a.type = BIN_REF; @@ -1579,6 +1580,20 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id) } } +static ERTS_INLINE ErlHeapFragment * +get_hidden_heap_frag(Eterm val) +{ + ErlHeapFragment *hfp; + if (is_immed(val)) + hfp = NULL; + else { + ASSERT(is_CP(val)); + hfp = (ErlHeapFragment *) cp_val(val); + ASSERT(hfp->alloc_size == hfp->used_size + 1); + } + return hfp; +} + static void insert_monitor_data(ErtsMonitor *mon, int type, Eterm id) { ErtsMonitorData *mdp = erts_monitor_to_data(mon); @@ -1593,6 +1608,23 @@ static void insert_monitor_data(ErtsMonitor *mon, int type, Eterm id) oh.first = mdep->uptr.ohhp; insert_offheap(&oh, type, id); } + if (mdp->origin.flags & ERTS_ML_FLG_TAG) { + ErlHeapFragment *hfp; + Eterm tag_storage; + if (mdp->origin.flags & ERTS_ML_FLG_EXTENDED) + tag_storage = ((ErtsMonitorDataExtended *) mdp)->heap[0]; + else + tag_storage = ((ErtsMonitorDataTagHeap *) mdp)->heap[0]; + hfp = get_hidden_heap_frag(tag_storage); + if (hfp) + insert_offheap(&hfp->off_heap, type, id); + } + if (mdp->origin.flags & ERTS_ML_FLG_SPAWN_PENDING) { + ErtsMonitorDataExtended *mdep = (ErtsMonitorDataExtended *) mdp; + ErlHeapFragment *hfp = get_hidden_heap_frag(mdep->u.name); + if (hfp) + insert_offheap(&hfp->off_heap, type, id); + } } } mdp->origin.flags |= ERTS_ML_FLG_DBG_VISITED; diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h index 1c6988f22002..56696586c606 100644 --- a/erts/emulator/beam/erl_node_tables.h +++ b/erts/emulator/beam/erl_node_tables.h @@ -77,15 +77,9 @@ enum dist_entry_state { #define ERTS_DE_QFLG_BUSY (((erts_aint32_t) 1) << 0) #define ERTS_DE_QFLG_EXIT (((erts_aint32_t) 1) << 1) -#define ERTS_DE_QFLG_REQ_INFO (((erts_aint32_t) 1) << 2) -#define ERTS_DE_QFLG_PORT_CTRL (((erts_aint32_t) 1) << 3) -#define ERTS_DE_QFLG_PROC_CTRL (((erts_aint32_t) 1) << 4) #define ERTS_DE_QFLGS_ALL (ERTS_DE_QFLG_BUSY \ - | ERTS_DE_QFLG_EXIT \ - | ERTS_DE_QFLG_REQ_INFO \ - | ERTS_DE_QFLG_PORT_CTRL \ - | ERTS_DE_QFLG_PROC_CTRL) + | ERTS_DE_QFLG_EXIT) #if defined(ARCH_64) #define ERTS_DIST_OUTPUT_BUF_DBG_PATTERN ((Uint) 0xf713f713f713f713UL) @@ -105,6 +99,7 @@ struct ErtsDistOutputBuf_ { * iov[2 ... vsize-1] data */ ErlIOVec *eiov; + int ignore_busy; }; struct ErtsDistOutputBufsContainer_ { @@ -153,7 +148,9 @@ struct dist_entry_ { erts_mtx_t qlock; /* Protects qflgs and out_queue */ erts_atomic32_t qflgs; - erts_atomic_t qsize; + erts_atomic32_t notify; /* User wants queue notification? */ + erts_atomic_t qsize; /* Size of data in queue respecting busy dist */ + erts_atomic_t total_qsize; /* Total size of data in queue */ erts_atomic64_t in; erts_atomic64_t out; ErtsDistOutputQueue out_queue; @@ -200,7 +197,7 @@ Accs = lists:foldl(fun({V,<<"ERL_NODE_INC">>,_},M) -> Val = maps:get(V,M,0), M#{ lists:usort(lists:filter(fun({V,N}) -> N /= 0 end, maps:to_list(Accs))). * There are bound to be bugs in the the instrumentation code, but - * atleast this is a place to start when hunting refc bugs. + * at least this is a place to start when hunting refc bugs. * */ #ifdef ERL_NODE_BOOKKEEP diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 27ecee8d09e0..26a2231749f3 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2020. All Rights Reserved. + * Copyright Ericsson AB 2006-2022. 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. @@ -1326,22 +1326,22 @@ erts_port_task_abort(ErtsPortTaskHandle *pthp) res = - 1; /* Task already aborted, executing, or executed */ else { reset_port_task_handle(pthp); - #if ERTS_POLL_USE_SCHEDULER_POLLING - switch (ptp->type) { - case ERTS_PORT_TASK_INPUT: - case ERTS_PORT_TASK_OUTPUT: - if (ptp->u.alive.td.io.is_scheduler_event) { - ASSERT(erts_atomic_read_nob( - &erts_port_task_outstanding_io_tasks) > 0); - erts_atomic_dec_relb(&erts_port_task_outstanding_io_tasks); + if (erts_sched_poll_enabled()) { + switch (ptp->type) { + case ERTS_PORT_TASK_INPUT: + case ERTS_PORT_TASK_OUTPUT: + if (ptp->u.alive.td.io.is_scheduler_event) { + ASSERT(erts_atomic_read_nob( + &erts_port_task_outstanding_io_tasks) > 0); + erts_atomic_dec_relb(&erts_port_task_outstanding_io_tasks); + } + break; + default: + break; } - break; - default: - break; - } + } #endif - res = 0; } } @@ -1844,16 +1844,14 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) } ERTS_MSACC_POP_STATE_M(); - #if ERTS_POLL_USE_SCHEDULER_POLLING - if (io_tasks_executed) { + if (erts_sched_poll_enabled() && io_tasks_executed) { ASSERT(erts_atomic_read_nob(&erts_port_task_outstanding_io_tasks) >= io_tasks_executed); erts_atomic_add_relb(&erts_port_task_outstanding_io_tasks, -1*io_tasks_executed); } #endif - ASSERT(runq == erts_get_runq_port(pp)); active = finalize_exec(pp, &execq, processing_busy_q); diff --git a/erts/emulator/beam/erl_posix_str.c b/erts/emulator/beam/erl_posix_str.c index 5b515d6e7893..c57c269095a9 100644 --- a/erts/emulator/beam/erl_posix_str.c +++ b/erts/emulator/beam/erl_posix_str.c @@ -47,8 +47,7 @@ */ char * -erl_errno_id(error) - int error; /* Posix error number (as from errno). */ +erl_errno_id(int error /* Posix error number (as from errno). */) { switch (error) { #ifdef E2BIG diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 9f020559d04b..18858a21bc9c 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2021. All Rights Reserved. + * Copyright Ericsson AB 2005-2023. 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. @@ -644,58 +644,61 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { } } break; - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(wobj) + 1)); - long tdcount; - int tres; - - PRINT_STRING(res, fn, arg, "fun "); - - /* We pass a temporary 'dcount' and adjust the real one later to ensure - * that the fun doesn't get split up between the module and function - * name. */ - tdcount = MAX_ATOM_SZ_LIMIT; - tres = print_atom_name(fn, arg, ep->info.mfa.module, &tdcount); - if (tres < 0) { - res = tres; - goto L_done; - } - *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); - res += tres; - - PRINT_CHAR(res, fn, arg, ':'); + case FUN_DEF: + { + ErlFunThing *funp = (ErlFunThing *) fun_val(wobj); + + if (is_local_fun(funp)) { + ErlFunEntry *fe = funp->entry.fun; + Atom *ap = atom_tab(atom_val(fe->module)); + + PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_BUF(res, fn, arg, ap->name, ap->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) fe->old_index); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) fe->old_uniq); + PRINT_CHAR(res, fn, arg, '>'); + } else { + Export* ep = funp->entry.exp; + long tdcount; + int tres; + + ASSERT(is_external_fun(funp) && funp->next == NULL); + + PRINT_STRING(res, fn, arg, "fun "); + + /* We pass a temporary 'dcount' and adjust the real one + * later to ensure that the fun doesn't get split up + * between the module and function name. */ + tdcount = MAX_ATOM_SZ_LIMIT; + tres = print_atom_name(fn, arg, ep->info.mfa.module, &tdcount); + if (tres < 0) { + res = tres; + goto L_done; + } + *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); + res += tres; - tdcount = MAX_ATOM_SZ_LIMIT; - tres = print_atom_name(fn, arg, ep->info.mfa.function, &tdcount); - if (tres < 0) { - res = tres; - goto L_done; - } - *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); - res += tres; + PRINT_CHAR(res, fn, arg, ':'); - PRINT_CHAR(res, fn, arg, '/'); - PRINT_SWORD(res, fn, arg, 'd', 0, 1, - (ErlPfSWord) ep->info.mfa.arity); - } - break; - case FUN_DEF: - { - ErlFunThing *funp = (ErlFunThing *) fun_val(wobj); - Atom *ap = atom_tab(atom_val(funp->fe->module)); + tdcount = MAX_ATOM_SZ_LIMIT; + tres = print_atom_name(fn, arg, ep->info.mfa.function, &tdcount); + if (tres < 0) { + res = tres; + goto L_done; + } + *dcount -= (MAX_ATOM_SZ_LIMIT - tdcount); + res += tres; - PRINT_STRING(res, fn, arg, "#Fun<"); - PRINT_BUF(res, fn, arg, ap->name, ap->len); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_SWORD(res, fn, arg, 'd', 0, 1, - (ErlPfSWord) funp->fe->old_index); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_SWORD(res, fn, arg, 'd', 0, 1, - (ErlPfSWord) funp->fe->old_uniq); - PRINT_CHAR(res, fn, arg, '>'); - } - break; + PRINT_CHAR(res, fn, arg, '/'); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) ep->info.mfa.arity); + } + } + break; case MAP_DEF: { Eterm *head = boxed_val(wobj); @@ -719,45 +722,46 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { } } else { Uint n, mapval; + Eterm* assoc; + Eterm key, val; + mapval = MAP_HEADER_VAL(*head); switch (MAP_HEADER_TYPE(*head)) { case MAP_HEADER_TAG_HAMT_HEAD_ARRAY: case MAP_HEADER_TAG_HAMT_HEAD_BITMAP: - PRINT_STRING(res, fn, arg, "#<"); - PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); - PRINT_STRING(res, fn, arg, ">{"); - WSTACK_PUSH(s,PRT_CLOSE_TUPLE); - n = hashmap_bitcount(mapval); - ASSERT(n < 17); - head += 2; - if (n > 0) { - n--; - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - while (n--) { - WSTACK_PUSH(s, PRT_COMMA); - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - } - } - break; + PRINT_STRING(res, fn, arg, "#{"); + WSTACK_PUSH(s, PRT_CLOSE_TUPLE); + head++; + /* fall through */ case MAP_HEADER_TAG_HAMT_NODE_BITMAP: n = hashmap_bitcount(mapval); - head++; - PRINT_CHAR(res, fn, arg, '<'); - PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); - PRINT_STRING(res, fn, arg, ">{"); - WSTACK_PUSH(s,PRT_CLOSE_TUPLE); - ASSERT(n < 17); - if (n > 0) { - n--; - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - while (n--) { - WSTACK_PUSH(s, PRT_COMMA); - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); + ASSERT(0 < n && n < 17); + while (1) { + if (is_list(head[n])) { + assoc = list_val(head[n]); + key = CAR(assoc); + val = CDR(assoc); + WSTACK_PUSH5(s, val, PRT_TERM, PRT_ASSOC, key, PRT_TERM); + } + else if (is_tuple(head[n])) { /* collision node */ + Eterm *tpl = tuple_val(head[n]); + Uint arity = arityval(tpl[0]); + ASSERT(arity >= 2); + while (1) { + assoc = list_val(tpl[arity]); + key = CAR(assoc); + val = CDR(assoc); + WSTACK_PUSH5(s, val, PRT_TERM, PRT_ASSOC, key, PRT_TERM); + if (--arity == 0) + break; + WSTACK_PUSH(s, PRT_COMMA); + } + } else { + WSTACK_PUSH2(s, head[n], PRT_TERM); } + if (--n == 0) + break; + WSTACK_PUSH(s, PRT_COMMA); } break; } diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index ad37555ef5af..c35729edfd01 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -216,10 +216,25 @@ typedef struct { } ErtsProcSigRPC; typedef struct { + ErtsRecvMarker next; + ErtsRecvMarker last; +} ErtsYieldAdjMsgQ; + +typedef struct { + ErtsYieldAdjMsgQ *yield; Eterm requester; Eterm request_id; } ErtsCLAData; +typedef struct { + ErtsYieldAdjMsgQ *yield; +} ErtsAdjOffHeapMsgQData; + +typedef struct { + ErtsMessage *first; + ErtsMessage **last; +} ErtsSavedNMSignals; + static void wake_handle_signals(Process *proc); static int handle_msg_tracing(Process *c_p, @@ -242,17 +257,30 @@ static int handle_cla(Process *c_p, ErtsMessage *sig, ErtsMessage ***next_nm_sig, - int exiting); + int exiting, + int limit, + ErtsSavedNMSignals *saved_nm_sigs); + static int handle_move_msgq_off_heap(Process *c_p, ErtsMessage *sig, ErtsMessage ***next_nm_sig, - int exiting); + int exiting, + int limit, + ErtsSavedNMSignals *saved_nm_sigs); static void send_cla_reply(Process *c_p, ErtsMessage *sig, Eterm to, Eterm req_id, Eterm result); static void handle_missing_spawn_reply(Process *c_p, ErtsMonitor *omon); +static Uint proc_sig_queue_flush_buffer(Process* proc, + Uint buffer_index, + ErtsSignalInQueueBufferArray* buffers); +static void proc_sig_queue_flush_buffers(Process *proc, + ErtsSignalInQueueBufferArray *buffers); +static void proc_sig_queue_lock_buffer(ErtsSignalInQueueBuffer* slot); +static void proc_sig_queue_unlock_buffer(ErtsSignalInQueueBuffer* slot); + #ifdef ERTS_PROC_SIG_HARD_DEBUG #define ERTS_PROC_SIG_HDBG_PRIV_CHKQ(P, T, NMN) \ do { \ @@ -270,7 +298,8 @@ static void handle_missing_spawn_reply(Process *c_p, ErtsMonitor *omon); nm_last__, \ (T), \ NULL, \ - ERTS_PSFLG_FREE); \ + 0, \ + 0); \ } while (0); static Sint proc_sig_hdbg_check_queue(Process *c_p, @@ -281,11 +310,82 @@ proc_sig_hdbg_check_queue(Process *c_p, ErtsMessage **sig_nm_last, ErtsSigRecvTracing *tracing, int *found_saved_last_p, - erts_aint32_t sig_psflg); + erts_aint32_t nmsig_psflg, + erts_aint32_t msig_psflg); #else #define ERTS_PROC_SIG_HDBG_PRIV_CHKQ(P, T, NMN) #endif +static void +save_delayed_nm_signal(ErtsSavedNMSignals *saved_sigs, ErtsMessage *sig) +{ + ErtsSignal *nm_sig = (ErtsSignal *) sig; + nm_sig->common.next = NULL; + nm_sig->common.specific.next = NULL; + if (!saved_sigs->first) { + ASSERT(!saved_sigs->last); + saved_sigs->first = sig; + saved_sigs->last = &saved_sigs->first; + } + else { + ErtsSignal *last; + ASSERT(saved_sigs->last); + last = (ErtsSignal *) *saved_sigs->last; + last->common.next = sig; + last->common.specific.next = &last->common.next; + saved_sigs->last = &last->common.next; + } +} + +static erts_aint32_t +restore_delayed_nm_signals(Process *c_p, ErtsSavedNMSignals *saved_sigs) +{ + erts_aint32_t state; + ErtsSignal *lsig; + + ASSERT(saved_sigs->first && saved_sigs->last); + + lsig = (ErtsSignal *) *saved_sigs->last; + if (!c_p->sig_qs.cont) { + ASSERT(!c_p->sig_qs.nmsigs.next); + ASSERT(!c_p->sig_qs.nmsigs.last); + if (saved_sigs->last == &saved_sigs->first) + c_p->sig_qs.nmsigs.last = &c_p->sig_qs.cont; + else + c_p->sig_qs.nmsigs.last = saved_sigs->last; + c_p->sig_qs.cont_last = &lsig->common.next; + } + else { + lsig->common.next = c_p->sig_qs.cont; + if (c_p->sig_qs.nmsigs.next) { + ASSERT(c_p->sig_qs.nmsigs.last); + if (c_p->sig_qs.nmsigs.next == &c_p->sig_qs.cont) + lsig->common.specific.next = &lsig->common.next; + else + lsig->common.specific.next = c_p->sig_qs.nmsigs.next; + if (c_p->sig_qs.nmsigs.last == &c_p->sig_qs.cont) + c_p->sig_qs.nmsigs.last = &lsig->common.next; + } + else { + ASSERT(!c_p->sig_qs.nmsigs.last); + if (saved_sigs->last == &saved_sigs->first) + c_p->sig_qs.nmsigs.last = &c_p->sig_qs.cont; + else + c_p->sig_qs.nmsigs.last = saved_sigs->last; + if (c_p->sig_qs.cont_last == &c_p->sig_qs.cont) + c_p->sig_qs.cont_last = &lsig->common.next; + } + } + + c_p->sig_qs.cont = saved_sigs->first; + c_p->sig_qs.nmsigs.next = &c_p->sig_qs.cont; + + state = erts_atomic32_read_bor_nob(&c_p->state, + ERTS_PSFLG_SIG_Q); + state |= ERTS_PSFLG_SIG_Q; + return state; +} + typedef struct { ErtsSignalCommon common; Eterm ref; @@ -382,6 +482,18 @@ get_cla_data(ErtsMessage *sig) + sig->hfrag.used_size); } +static ERTS_INLINE ErtsAdjOffHeapMsgQData * +get_move_msgq_off_heap_data(ErtsMessage *sig) +{ + ASSERT(ERTS_SIG_IS_NON_MSG(sig)); + ASSERT(ERTS_PROC_SIG_OP(((ErtsSignal *) sig)->common.tag) + == ERTS_SIG_Q_OP_ADJ_MSGQ); + ASSERT(ERTS_PROC_SIG_TYPE(((ErtsSignal *) sig)->common.tag) + == ERTS_SIG_Q_TYPE_OFF_HEAP); + return (ErtsAdjOffHeapMsgQData *) (char *) (&sig->hfrag.mem[0] + + sig->hfrag.used_size); +} + static ERTS_INLINE void destroy_trace_info(ErtsSigTraceInfo *ti) { @@ -398,9 +510,18 @@ destroy_sig_group_leader(ErtsSigGroupLeader *sgl) } static ERTS_INLINE void -sig_enqueue_trace(Process *c_p, ErtsMessage **sigp, int op, - Process *rp, ErtsMessage ***last_next) +sig_enqueue_trace(ErtsPTabElementCommon *sender, Eterm from, + ErtsMessage **sigp, int op, Process *rp, + ErtsMessage ***last_next) { + Process *c_p; + + if (sender == NULL || !is_internal_pid(from)) { + return; + } + + c_p = ErtsContainerStruct(sender, Process, common); + switch (op) { case ERTS_SIG_Q_OP_LINK: if (c_p @@ -423,25 +544,27 @@ sig_enqueue_trace(Process *c_p, ErtsMessage **sigp, int op, ti->common.specific.next = &ti->common.next; ti->common.tag = tag; ti->flags_on = ERTS_TRACE_FLAGS(c_p) & TRACEE_FLAGS; - if (!(ti->flags_on & F_TRACE_SOL1)) + + if (!(ti->flags_on & F_TRACE_SOL1)) { ti->flags_off = 0; - else { + } else { ti->flags_off = F_TRACE_SOL1|F_TRACE_SOL; erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); ERTS_TRACE_FLAGS(c_p) &= ~(F_TRACE_SOL1|F_TRACE_SOL); erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } + erts_tracer_update(&ti->tracer, ERTS_TRACER(c_p)); *sigp = (ErtsMessage *) ti; - if (!*last_next || *last_next == sigp) + + if (!*last_next || *last_next == sigp) { *last_next = &ti->common.next; + } } break; - #ifdef USE_VM_PROBES case ERTS_SIG_Q_OP_EXIT: case ERTS_SIG_Q_OP_EXIT_LINKED: - if (DTRACE_ENABLED(process_exit_signal)) { ErtsMessage* sig = *sigp; Uint16 type = ERTS_PROC_SIG_TYPE(((ErtsSignal *) sig)->common.tag); @@ -449,6 +572,7 @@ sig_enqueue_trace(Process *c_p, ErtsMessage **sigp, int op, ErtsExitSignalData *xsigd; ASSERT(type == ERTS_SIG_Q_TYPE_GEN_EXIT); + (void)type; xsigd = get_exit_signal_data(sig); reason = xsigd->reason; @@ -471,9 +595,7 @@ sig_enqueue_trace(Process *c_p, ErtsMessage **sigp, int op, } } break; - #endif - default: break; } @@ -526,85 +648,164 @@ static int dbg_count_nmsigs(ErtsMessage *first) } #endif +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_BUFFERS +static int dbg_count_all(ErtsMessage *first) +{ + ErtsMessage *sig; + int cnt = 0; + + for (sig = first; sig; sig = sig->next) { + ++cnt; + } + return cnt; +} + +static int dbg_check_non_msg(ErtsSignalInQueue* q) +{ + ErtsMessage** m = q->nmsigs.next; + int cnt = 0; + ErtsMessage** prev_m = NULL; + while (m != NULL) { + ERTS_ASSERT(ERTS_SIG_IS_NON_MSG(*m)); + cnt++; + prev_m = m; + m = ((ErtsSignal *) (*m))->common.specific.next; + } + if (cnt > 0) { + ERTS_ASSERT(prev_m == q->nmsigs.last); + } + return cnt; +} +#endif /* ERTS_PROC_SIG_HARD_DEBUG_SIGQ_BUFFERS */ + + +/** + * @brief Enqueue a sequence of signals on an *in* signal queue. + * + * The *only* valid scenarios: + * * One or more message signals and no non-message signals. + * * One non-message signal followed by one or more message signals + * * One or more non-message signals and no message signals. + * + * Appart from next pointers between the signals in the sequence also: + * * next pointer pointers between non-message signals must have been + * correctly set up. + * + * @param is_to_buffer Non-zero if not enqueue on processes in signal + * queue. + * @param rp[in] Process to which the in signal queue belong. + * @param first[in] Pointer to the first signal in signal sequence. + * @param last[in] Pointer to the next pointer of the last signal + * in the sequence. This next pointer should equal + * NULL. + * @param last_next[in] Pointer to the next pointer which points to the + * last signal in the sequence if more than one + * non-message signal is in the sequence. NULL if + * no or only one non-message signal in the seqence. + * @param state[in] State of rp upon call. This state *must* have + * been while holding the msgq lock or buffer lock + * prior to calling this function. + * @param dest_queue In signal queue to enqueue on. This might + * be the in signal queue of rp or an in signal + * queue buffer of rp. The in signal queue has to + * be apropriately locked when calling + * enqueue_signals() by the caller. + * + * @return Possibly changed state of rp. + */ static ERTS_INLINE erts_aint32_t -enqueue_signals(Process *rp, ErtsMessage *first, +enqueue_signals(int is_to_buffer, Process *rp, ErtsMessage *first, ErtsMessage **last, ErtsMessage **last_next, Uint num_msgs, - erts_aint32_t in_state) + erts_aint32_t state, + ErtsSignalInQueue* dest_queue) { - erts_aint32_t state = in_state; - ErtsMessage **this = rp->sig_inq.last; + ErtsMessage **this; + erts_aint32_t set_flags; + int nmsig = ERTS_SIG_IS_NON_MSG(first); + int flush_buffers = (!is_to_buffer) && (state & ERTS_PSFLG_OFF_HEAP_MSGQ); + + ASSERT(!!is_to_buffer == (dest_queue != &rp->sig_inq)); + + if (flush_buffers) { + erts_proc_sig_queue_flush_buffers(rp); + } + + this = dest_queue->last; - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(rp); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(rp, dest_queue); ASSERT(!*this); *this = first; - rp->sig_inq.last = last; + dest_queue->last = last; - if (!rp->sig_inq.nmsigs.next) { - ASSERT(!rp->sig_inq.nmsigs.last); - if (ERTS_SIG_IS_NON_MSG(first)) { - rp->sig_inq.nmsigs.next = this; - } - else if (last_next) { - ASSERT(first->next && ERTS_SIG_IS_NON_MSG(first->next)); - rp->sig_inq.nmsigs.next = &first->next; + set_flags = num_msgs ? ERTS_PSFLG_MSG_SIG_IN_Q : 0; + + if (!dest_queue->nmsigs.next) { + ASSERT(!dest_queue->nmsigs.last); + if (nmsig) { + dest_queue->nmsigs.next = this; + set_flags |= ERTS_PSFLG_NMSG_SIG_IN_Q; } - else - goto no_nmsig; - state = erts_atomic32_read_bor_nob(&rp->state, - ERTS_PSFLG_SIG_IN_Q); - no_nmsig: - ASSERT(!(state & ERTS_PSFLG_SIG_IN_Q)); } else { ErtsSignal *sig; - ASSERT(rp->sig_inq.nmsigs.last); + ASSERT(dest_queue->nmsigs.last); - sig = (ErtsSignal *) *rp->sig_inq.nmsigs.last; + sig = (ErtsSignal *) *dest_queue->nmsigs.last; ASSERT(sig && !sig->common.specific.next); - ASSERT(state & ERTS_PSFLG_SIG_IN_Q); - if (ERTS_SIG_IS_NON_MSG(first)) { + if (nmsig) { sig->common.specific.next = this; } - else if (last_next) { - ASSERT(first->next && ERTS_SIG_IS_NON_MSG(first->next)); - sig->common.specific.next = &first->next; - } } + if ((state & set_flags) != set_flags) + state = erts_atomic32_read_bor_nob(&rp->state, set_flags); + +#ifdef DEBUG + if (!is_to_buffer) { + erts_aint32_t a = erts_atomic32_read_nob(&rp->state); + erts_aint32_t e = 0; + if (num_msgs) + e |= ERTS_PSFLG_MSG_SIG_IN_Q; + if (nmsig) + e |= ERTS_PSFLG_NMSG_SIG_IN_Q; + ASSERT((a & e) == e); + } +#endif + if (last_next) { ASSERT(dbg_count_nmsigs(first) >= 2); - rp->sig_inq.nmsigs.last = last_next; + dest_queue->nmsigs.last = last_next; } - else if (ERTS_SIG_IS_NON_MSG(first)) { + else if (nmsig) { ASSERT(dbg_count_nmsigs(first) == 1); - rp->sig_inq.nmsigs.last = this; + dest_queue->nmsigs.last = this; } else ASSERT(dbg_count_nmsigs(first) == 0); - rp->sig_inq.len += num_msgs; + dest_queue->len += num_msgs; - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(rp); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(rp, dest_queue); return state; } erts_aint32_t erts_enqueue_signals(Process *rp, ErtsMessage *first, - ErtsMessage **last, ErtsMessage **last_next, - Uint num_msgs, + ErtsMessage **last, Uint num_msgs, erts_aint32_t in_state) { - return enqueue_signals(rp, first, last, last_next, num_msgs, in_state); + return enqueue_signals(0, rp, first, last, NULL, num_msgs, in_state, + &rp->sig_inq); } -void -erts_make_dirty_proc_handled(Eterm pid, - erts_aint32_t state, - erts_aint32_t prio) +static ERTS_INLINE void +notify_dirty_signal_handler(Eterm pid, + erts_aint32_t state, + erts_aint32_t prio) { Eterm *hp; ErtsMessage *mp; @@ -632,12 +833,81 @@ erts_make_dirty_proc_handled(Eterm pid, erts_queue_message(sig_handler, 0, mp, pid, am_system); } +typedef struct { + Eterm pid; + erts_aint32_t prio; +} ErtsDirtySignalHandlerNotification; + +static void +delayed_notify_dirty_signal_handler(void *vdshnp) +{ + ErtsDirtySignalHandlerNotification *dshnp + = (ErtsDirtySignalHandlerNotification *) vdshnp; + Process *proc; + + ASSERT(dshnp); + + proc = erts_proc_lookup(dshnp->pid); + if (proc) { + erts_aint32_t state = erts_atomic32_read_acqb(&proc->state); + /* + * Notify the dirty signal handler if it is still running + * dirty and still have signals to handle... + */ + if (!!(state & ERTS_PSFLG_DIRTY_RUNNING) + & !!(state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q))) { + notify_dirty_signal_handler(dshnp->pid, state, dshnp->prio); + } + } + erts_free(ERTS_ALC_T_DSIG_HNDL_NTFY, vdshnp); +} + +void +erts_ensure_dirty_proc_signals_handled(Process *proc, + erts_aint32_t state, + erts_aint32_t prio, + ErtsProcLocks locks) +{ + /* + * All minor locks need to be accurately reported... + */ + ERTS_LC_ASSERT((locks & ERTS_PROC_LOCKS_ALL_MINOR) + == (erts_proc_lc_my_proc_locks(proc) + & ERTS_PROC_LOCKS_ALL_MINOR)); + + if (!(locks & ERTS_PROC_LOCKS_ALL_MINOR)) { + notify_dirty_signal_handler(proc->common.id, state, prio); + } + else { + /* + * We need to schedule the notification since we cannot + * safely acquire the msgq lock on the dirty signal + * handler process while other minor process locks are + * held... + */ + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + int tid = esdp && esdp->type == ERTS_SCHED_NORMAL ? (int) esdp->no : 1; + ErtsDirtySignalHandlerNotification *dshnp = + (ErtsDirtySignalHandlerNotification *) + erts_alloc(ERTS_ALC_T_DSIG_HNDL_NTFY, + sizeof(ErtsDirtySignalHandlerNotification)); + dshnp->pid = proc->common.id; + dshnp->prio = prio; + erts_schedule_misc_aux_work(tid, + delayed_notify_dirty_signal_handler, + (void *) dshnp); + } +} + static void check_push_msgq_len_offs_marker(Process *rp, ErtsSignal *sig); static int -proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) +proc_queue_signal(ErtsPTabElementCommon *sender, Eterm from, Eterm pid, + ErtsSignal *sig, int force_flush, int op) { int res; Process *rp; @@ -647,6 +917,20 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) erts_aint32_t state; ErtsSignal *pend_sig; + ASSERT(sender == NULL || sender->id == from); + + /* Tracing requires sender for local procs and ports. The assertions below + * will not catch errors after time-of-death, but ought to find most + * problems. */ + ASSERT(sender != NULL || op == ERTS_SIG_Q_OP_FLUSH || + (is_normal_sched && esdp->pending_signal.sig == sig) || + (!(is_internal_pid(from) && + erts_proc_lookup(from) != NULL) && + !(is_internal_port(from) && + erts_port_lookup(from, ERTS_PORT_SFLGS_INVALID_LOOKUP) != NULL))); + + ASSERT(is_value(from) && is_internal_pid(pid)); + if (is_normal_sched) { pend_sig = esdp->pending_signal.sig; if (op == ERTS_SIG_Q_OP_MONITOR @@ -665,8 +949,10 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) if (pend_sig != sig) { /* Switch them and send previously pending signal instead */ Eterm pend_to = esdp->pending_signal.to; + esdp->pending_signal.sig = sig; esdp->pending_signal.to = pid; + sig = pend_sig; pid = pend_to; } @@ -680,9 +966,12 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) #endif pend_sig = NULL; } + rp = erts_proc_lookup_raw(pid); if (!rp) { - erts_proc_sig_send_monitor_down((ErtsMonitor*)sig, am_noproc); + erts_proc_sig_send_monitor_down(sender, from, + (ErtsMonitor*)sig, + am_noproc); return 1; } } @@ -693,7 +982,9 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) rp = erts_proc_lookup_raw(pid); if (!rp) { - erts_proc_sig_send_monitor_down((ErtsMonitor*)pend_sig, am_noproc); + erts_proc_sig_send_monitor_down(sender, from, + (ErtsMonitor*)pend_sig, + am_noproc); return 0; } @@ -708,14 +999,16 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) else { pend_sig = NULL; rp = erts_proc_lookup_raw(pid); - if (!rp) + if (!rp) { return 0; + } } } else { rp = erts_proc_lookup_raw_inc_refc(pid); - if (!rp) + if (!rp) { return 0; + } pend_sig = NULL; } @@ -724,21 +1017,44 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) sigp = &first; first_last_done: + + if ((void *) sender == (void *) rp) + (void) erts_atomic32_read_bor_nob(&((Process *) sender)->xstate, + ERTS_PXSFLG_MAYBE_SELF_SIGS); + sig->common.specific.next = NULL; /* may add signals before sig */ - sig_enqueue_trace(c_p, sigp, op, rp, &last_next); + sig_enqueue_trace(sender, from, sigp, op, rp, &last_next); last->next = NULL; - erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); + if (!force_flush && op != ERTS_SIG_Q_OP_PROCESS_INFO && + erts_proc_sig_queue_try_enqueue_to_buffer(from, rp, 0, first, + &last->next, last_next, 0)) { + if (!is_normal_sched) { + erts_proc_dec_refc(rp); + } + + return 1; + } + + erts_proc_sig_queue_lock(rp); state = erts_atomic32_read_nob(&rp->state); - if (ERTS_PSFLG_FREE & state) + if (force_flush) { + erts_proc_sig_queue_flush_buffers(rp); + } else { + erts_proc_sig_queue_maybe_install_buffers(rp, state); + } + + if (ERTS_PSFLG_FREE & state) { res = 0; - else { - state = enqueue_signals(rp, first, &last->next, last_next, 0, state); + } else { + state = enqueue_signals(0, rp, first, &last->next, + last_next, 0, state, + &rp->sig_inq); if (ERTS_UNLIKELY(op == ERTS_SIG_Q_OP_PROCESS_INFO)) check_push_msgq_len_offs_marker(rp, sig); res = !0; @@ -749,38 +1065,42 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) if (res == 0) { sig_enqueue_trace_cleanup(first, sig); if (pend_sig) { - erts_proc_sig_send_monitor_down((ErtsMonitor*)pend_sig, am_noproc); + erts_proc_sig_send_monitor_down(sender, from, + (ErtsMonitor*)pend_sig, am_noproc); if (sig == pend_sig) { /* We did a switch, callers signal is now pending (still ok) */ ASSERT(esdp->pending_signal.sig); res = 1; } } - } - else + } else { erts_proc_notify_new_sig(rp, state, 0); + } - if (!is_normal_sched) + if (!is_normal_sched) { erts_proc_dec_refc(rp); + } return res; } -void erts_proc_sig_send_pending(ErtsSchedulerData* esdp) +void erts_proc_sig_send_pending(Process *c_p, ErtsSchedulerData* esdp) { - ErtsSignal* sig = esdp->pending_signal.sig; + ErtsSignal *sig = esdp->pending_signal.sig; + Eterm to = esdp->pending_signal.to; int op; ASSERT(esdp && esdp->type == ERTS_SCHED_NORMAL); + ASSERT(c_p && c_p == esdp->pending_signal.dbg_from); ASSERT(sig); - ASSERT(is_internal_pid(esdp->pending_signal.to)); + ASSERT(is_internal_pid(to)); op = ERTS_SIG_Q_OP_MONITOR; ASSERT(op == ERTS_PROC_SIG_OP(sig->common.tag)); - if (!proc_queue_signal(NULL, esdp->pending_signal.to, sig, op)) { + if (!proc_queue_signal(&c_p->common, c_p->common.id, to, sig, 0, op)) { ErtsMonitor* mon = (ErtsMonitor*)sig; - erts_proc_sig_send_monitor_down(mon, am_noproc); + erts_proc_sig_send_monitor_down(NULL, to, mon, am_noproc); } } @@ -827,7 +1147,8 @@ maybe_elevate_sig_handling_prio(Process *c_p, int prio, Eterm other) * in erl_process.c. */ if (state & ERTS_PSFLG_DIRTY_RUNNING) - erts_make_dirty_proc_handled(other, state, min_prio); + erts_ensure_dirty_proc_signals_handled(rp, state, + min_prio, 0); } } } @@ -835,120 +1156,171 @@ maybe_elevate_sig_handling_prio(Process *c_p, int prio, Eterm other) } void -erts_proc_sig_fetch__(Process *proc) +erts_proc_sig_fetch__(Process *proc, + ErtsSignalInQueueBufferArray *buffers, + int need_unget_buffers) { - ASSERT(proc->sig_inq.first); - - if (!proc->sig_inq.nmsigs.next) { - ASSERT(!(ERTS_PSFLG_SIG_IN_Q - & erts_atomic32_read_nob(&proc->state))); - ASSERT(!proc->sig_inq.nmsigs.last); + const erts_aint32_t clear_flags = (ERTS_PSFLG_MSG_SIG_IN_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q); + erts_aint32_t set_flags = 0; - if (proc->sig_qs.cont || ERTS_MSG_RECV_TRACED(proc)) { - *proc->sig_qs.cont_last = proc->sig_inq.first; - proc->sig_qs.cont_last = proc->sig_inq.last; - } - else { - *proc->sig_qs.last = proc->sig_inq.first; - proc->sig_qs.last = proc->sig_inq.last; + if (buffers) + proc_sig_queue_flush_buffers(proc, buffers); + if (!proc->sig_inq.first) { + /* + * 'clear_flags' may be set even though in-queue is empty and + * if so needs to be cleared... + */ + if (!(clear_flags & erts_atomic32_read_nob(&proc->state))) { + if (buffers) + goto unget_buffers_return; + return; } + /* + * This can only happen when buffers are used. However, they may + * recently have been used but just been uninstalled, so we must be + * prepared for this scenario also without buffers installed... + */ } else { - erts_aint32_t s; - ASSERT(proc->sig_inq.nmsigs.last); - if (!proc->sig_qs.nmsigs.last) { - ASSERT(!proc->sig_qs.nmsigs.next); - if (proc->sig_inq.nmsigs.next == &proc->sig_inq.first) - proc->sig_qs.nmsigs.next = proc->sig_qs.cont_last; - else - proc->sig_qs.nmsigs.next = proc->sig_inq.nmsigs.next; - s = erts_atomic32_read_bset_nob(&proc->state, - (ERTS_PSFLG_SIG_Q - | ERTS_PSFLG_SIG_IN_Q), - ERTS_PSFLG_SIG_Q); + if (!proc->sig_inq.nmsigs.next) { + ASSERT(!proc->sig_inq.nmsigs.last); - ASSERT((s & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) - == ERTS_PSFLG_SIG_IN_Q); (void)s; + if (!proc->sig_qs.cont && !ERTS_MSG_RECV_TRACED(proc)) { + *proc->sig_qs.last = proc->sig_inq.first; + proc->sig_qs.last = proc->sig_inq.last; + } + else { + *proc->sig_qs.cont_last = proc->sig_inq.first; + proc->sig_qs.cont_last = proc->sig_inq.last; + set_flags = ERTS_PSFLG_SIG_Q; + } } else { - ErtsSignal *sig; - ASSERT(proc->sig_qs.nmsigs.next); - sig = ((ErtsSignal *) *proc->sig_qs.nmsigs.last); - ASSERT(ERTS_SIG_IS_NON_MSG(sig)); - ASSERT(!sig->common.specific.next); - if (proc->sig_inq.nmsigs.next == &proc->sig_inq.first) - sig->common.specific.next = proc->sig_qs.cont_last; - else - sig->common.specific.next = proc->sig_inq.nmsigs.next; + ASSERT(proc->sig_inq.nmsigs.last); + if (!proc->sig_qs.nmsigs.last) { + ASSERT(!proc->sig_qs.nmsigs.next); + if (proc->sig_inq.nmsigs.next == &proc->sig_inq.first) + proc->sig_qs.nmsigs.next = proc->sig_qs.cont_last; + else + proc->sig_qs.nmsigs.next = proc->sig_inq.nmsigs.next; - s = erts_atomic32_read_band_nob(&proc->state, - ~ERTS_PSFLG_SIG_IN_Q); + set_flags = ERTS_PSFLG_SIG_Q; + } + else { + ErtsSignal *sig; + ASSERT(proc->sig_qs.nmsigs.next); + sig = ((ErtsSignal *) *proc->sig_qs.nmsigs.last); + ASSERT(ERTS_SIG_IS_NON_MSG(sig)); + ASSERT(!sig->common.specific.next); + if (proc->sig_inq.nmsigs.next == &proc->sig_inq.first) + sig->common.specific.next = proc->sig_qs.cont_last; + else + sig->common.specific.next = proc->sig_inq.nmsigs.next; + } + if (proc->sig_inq.nmsigs.last == &proc->sig_inq.first) + proc->sig_qs.nmsigs.last = proc->sig_qs.cont_last; + else + proc->sig_qs.nmsigs.last = proc->sig_inq.nmsigs.last; + proc->sig_inq.nmsigs.next = NULL; + proc->sig_inq.nmsigs.last = NULL; - ASSERT((s & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) - == (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)); (void)s; + *proc->sig_qs.cont_last = proc->sig_inq.first; + proc->sig_qs.cont_last = proc->sig_inq.last; } - if (proc->sig_inq.nmsigs.last == &proc->sig_inq.first) - proc->sig_qs.nmsigs.last = proc->sig_qs.cont_last; - else - proc->sig_qs.nmsigs.last = proc->sig_inq.nmsigs.last; - proc->sig_inq.nmsigs.next = NULL; - proc->sig_inq.nmsigs.last = NULL; - *proc->sig_qs.cont_last = proc->sig_inq.first; - proc->sig_qs.cont_last = proc->sig_inq.last; - } + proc->sig_qs.len += proc->sig_inq.len; - proc->sig_qs.len += proc->sig_inq.len; + proc->sig_inq.first = NULL; + proc->sig_inq.last = &proc->sig_inq.first; + proc->sig_inq.len = 0; + } - proc->sig_inq.first = NULL; - proc->sig_inq.last = &proc->sig_inq.first; - proc->sig_inq.len = 0; + ASSERT((set_flags & clear_flags) == 0); + if (!buffers) { + (void) (!set_flags + ? erts_atomic32_read_band_nob(&proc->state, + ~clear_flags) + : erts_atomic32_read_bset_nob(&proc->state, + set_flags | clear_flags, + set_flags)); + } + else { + (void) (!set_flags + ? erts_atomic32_read_band_acqb(&proc->state, + ~clear_flags) + : erts_atomic32_read_bset_acqb(&proc->state, + set_flags | clear_flags, + set_flags)); + if (erts_atomic64_read_acqb(&buffers->nonempty_slots)) { + set_flags = 0; + /* + * We raced with a signal being inserted into a buffer; + * need to adjust accordingly. Note that 'nonmsgs_in_slots' + * or 'msgs_in_slots' may be set even though corresponding + * signals aren't present in the buffers. This will however + * sort itself out when no such signals appears in a + * future call to erts_proc_sig_fetch(). + */ + if (erts_atomic32_read_nob(&buffers->nonmsgs_in_slots)) + set_flags |= ERTS_PSFLG_ACTIVE_SYS|ERTS_PSFLG_NMSG_SIG_IN_Q; + if (erts_atomic32_read_nob(&buffers->msgs_in_slots)) + set_flags |= ERTS_PSFLG_ACTIVE|ERTS_PSFLG_MSG_SIG_IN_Q; + if (set_flags) + (void) erts_atomic32_read_bor_relb(&proc->state, set_flags); + /* else: + * Another thread is currently operating on a buffer and + * will soon set appropriate. + */ + } + unget_buffers_return: + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers); + } } Sint -erts_proc_sig_fetch_msgq_len_offs__(Process *proc) +erts_proc_sig_fetch_msgq_len_offs__(Process *proc, + ErtsSignalInQueueBufferArray *buffers, + int need_unget_buffers) { - ErtsProcSigMsgQLenOffsetMarker *marker - = (ErtsProcSigMsgQLenOffsetMarker *) proc->sig_inq.first; + ErtsProcSigMsgQLenOffsetMarker *marker; + Sint len; + marker = (ErtsProcSigMsgQLenOffsetMarker *) proc->sig_inq.first; + ASSERT(marker); ASSERT(marker->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK); - if (marker->common.next) { - Sint len; - - proc->sig_qs.flags |= FS_DELAYED_PSIGQS_LEN; - - /* - * Prevent update of sig_qs.len in fetch. These - * updates are done via process-info signal(s) - * instead... - */ - len = proc->sig_inq.len; - marker->delayed_len += len; - marker->len_offset -= len; - proc->sig_inq.len = 0; + proc->sig_qs.flags |= FS_DELAYED_PSIGQS_LEN; - /* - * Temorarily remove marker during fetch... - */ + /* + * Prevent update of sig_qs.len in fetch. These + * updates are done via process-info signal(s) + * instead... + */ + len = proc->sig_inq.len; + marker->delayed_len += len; + marker->len_offset -= len; + proc->sig_inq.len = 0; - proc->sig_inq.first = marker->common.next; - if (proc->sig_inq.last == &marker->common.next) - proc->sig_inq.last = &proc->sig_inq.first; - if (proc->sig_inq.nmsigs.next == &marker->common.next) - proc->sig_inq.nmsigs.next = &proc->sig_inq.first; - if (proc->sig_inq.nmsigs.last == &marker->common.next) - proc->sig_inq.nmsigs.last = &proc->sig_inq.first; + /* + * Temporarily remove marker during fetch... + */ - erts_proc_sig_fetch__(proc); + proc->sig_inq.first = marker->common.next; + if (proc->sig_inq.last == &marker->common.next) + proc->sig_inq.last = &proc->sig_inq.first; + if (proc->sig_inq.nmsigs.next == &marker->common.next) + proc->sig_inq.nmsigs.next = &proc->sig_inq.first; + if (proc->sig_inq.nmsigs.last == &marker->common.next) + proc->sig_inq.nmsigs.last = &proc->sig_inq.first; - marker->common.next = NULL; - proc->sig_inq.first = (ErtsMessage *) marker; - proc->sig_inq.last = &marker->common.next; + erts_proc_sig_fetch__(proc, buffers, need_unget_buffers); - } + marker->common.next = NULL; + proc->sig_inq.first = (ErtsMessage *) marker; + proc->sig_inq.last = &marker->common.next; return marker->delayed_len; } @@ -1052,7 +1424,7 @@ erts_proc_sig_get_external(ErtsMessage *msgp) static void do_seq_trace_output(Eterm to, Eterm token, Eterm msg); static void -send_gen_exit_signal(Process *c_p, Eterm from_tag, +send_gen_exit_signal(ErtsPTabElementCommon *sender, Eterm from_tag, Eterm from, Eterm to, Sint16 op, Eterm reason, ErtsDistExternal *dist_ext, ErlHeapFragment *dist_ext_hfrag, @@ -1066,11 +1438,18 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, ErlOffHeap *ohp; Uint hsz, from_sz, reason_sz, ref_sz, token_sz, dist_ext_sz = 0; int seq_trace; + Process *c_p; #ifdef USE_VM_PROBES Eterm s_utag, utag; Uint utag_sz; #endif + if (sender && is_internal_pid(from)) { + c_p = ErtsContainerStruct(sender, Process, common); + } else { + c_p = NULL; + } + ASSERT((is_value(reason) && dist_ext == NULL) || (is_non_value(reason) && dist_ext != NULL)); @@ -1079,8 +1458,9 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, hsz = sizeof(ErtsExitSignalData)/sizeof(Eterm); seq_trace = c_p && have_seqtrace(token); - if (seq_trace) + if (seq_trace) { seq_trace_update_serial(c_p); + } #ifdef USE_VM_PROBES utag_sz = 0; @@ -1217,12 +1597,20 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, ASSERT(hp == mp->hfrag.mem + mp->hfrag.alloc_size); - if (seq_trace) + if (seq_trace) { do_seq_trace_output(to, s_token, s_message); + } - if (!proc_queue_signal(c_p, to, (ErtsSignal *) mp, op)) { - mp->next = NULL; - erts_cleanup_messages(mp); + { + /* Ensure that we're ordered relative to the sender process if one + * exists, and not `from` as it may be a name instead of a pid. */ + Eterm order_by = sender ? sender->id : from; + + if (!proc_queue_signal(sender, order_by, to, (ErtsSignal *)mp, + !(is_pid(order_by) || is_port(order_by)), op)) { + mp->next = NULL; + erts_cleanup_messages(mp); + } } } @@ -1329,23 +1717,18 @@ erts_proc_sig_cleanup_non_msg_signal(ErtsMessage *sig) Eterm tag = ((ErtsSignal *) sig)->common.tag; /* - * Heap alias message, heap frag alias message and - * adjust message queue signals are the only non-message - * signals, which are allocated as messages, which do not - * use a combined message / heap fragment. + * Heap alias message and heap frag alias message are + * the only non-message signals, which are allocated as + * messages, which do not use a combined message / heap + * fragment. */ - if (ERTS_SIG_IS_HEAP_ALIAS_MSG_TAG(tag) - || tag == ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_ADJ_MSGQ, - ERTS_SIG_Q_TYPE_OFF_HEAP, - 0)) { + if (ERTS_SIG_IS_HEAP_ALIAS_MSG_TAG(tag)) { sig->data.heap_frag = NULL; return; } - - - if(ERTS_SIG_IS_HEAP_FRAG_ALIAS_MSG_TAG(tag)) { - /* Retreive pointer to heap fragment (may not be NULL). */ + if (ERTS_SIG_IS_HEAP_FRAG_ALIAS_MSG_TAG(tag)) { + /* Retrieve pointer to heap fragment (may not be NULL). */ void *attached; (void) get_alias_msg_data(sig, NULL, NULL, NULL, &attached); sig->data.heap_frag = hfrag = (ErlHeapFragment *) attached; @@ -1355,10 +1738,45 @@ erts_proc_sig_cleanup_non_msg_signal(ErtsMessage *sig) /* * Using a combined heap fragment... */ - ErtsDistExternal *edep = get_external_non_msg_signal(sig); - if (edep) - erts_free_dist_ext_copy(edep); - + switch (ERTS_PROC_SIG_OP(tag)) { + + case ERTS_SIG_Q_OP_ADJ_MSGQ: { + /* We need to deallocate yield markers if such has been used... */ + ErtsYieldAdjMsgQ *yp; + switch (ERTS_PROC_SIG_TYPE(tag)) { + case ERTS_SIG_Q_TYPE_CLA: { + ErtsCLAData *cla = get_cla_data(sig); + yp = cla->yield; + cla->yield = NULL; + break; + } + case ERTS_SIG_Q_TYPE_OFF_HEAP: { + ErtsAdjOffHeapMsgQData *ohdp = get_move_msgq_off_heap_data(sig); + yp = ohdp->yield; + ohdp->yield = NULL; + break; + } + default: + ERTS_INTERNAL_ERROR("Invalid adjust-message-queue signal type"); + yp = NULL; + break; + } + if (yp) { + ASSERT(!yp->next.in_msgq && !yp->next.in_sigq); + ASSERT(!yp->last.in_msgq && !yp->last.in_sigq); + erts_free(ERTS_ALC_T_SIG_YIELD_DATA, yp); + } + break; + } + + default: { + ErtsDistExternal *edep = get_external_non_msg_signal(sig); + if (edep) + erts_free_dist_ext_copy(edep); + break; + } + } + sig->data.attached = ERTS_MSG_COMBINED_HFRAG; hfrag = sig->hfrag.next; erts_cleanup_offheap(&sig->hfrag.off_heap); @@ -1535,7 +1953,7 @@ erts_proc_sig_send_to_alias(Process *c_p, Eterm from, Eterm to, Eterm msg, Eterm hfrag_low, hfrag_high); } - if (!proc_queue_signal(c_p, pid, (ErtsSignal *) mp, + if (!proc_queue_signal(&c_p->common, from, pid, (ErtsSignal *) mp, 0, ERTS_SIG_Q_OP_ALIAS_MSG)) { mp->next = NULL; erts_cleanup_messages(mp); @@ -1554,7 +1972,8 @@ erts_proc_sig_send_to_alias(Process *c_p, Eterm from, Eterm to, Eterm msg, Eterm } void -erts_proc_sig_send_dist_to_alias(Eterm alias, ErtsDistExternal *edep, +erts_proc_sig_send_dist_to_alias(Eterm from, Eterm alias, + ErtsDistExternal *edep, ErlHeapFragment *hfrag, Eterm token) { ErtsMessage* mp; @@ -1617,20 +2036,24 @@ erts_proc_sig_send_dist_to_alias(Eterm alias, ErtsDistExternal *edep, ERTS_SIG_Q_TYPE_DIST, 0); - if (!proc_queue_signal(NULL, pid, (ErtsSignal *) mp, + if (!proc_queue_signal(NULL, from, pid, (ErtsSignal *) mp, 0, ERTS_SIG_Q_OP_ALIAS_MSG)) { mp->next = NULL; erts_cleanup_messages(mp); } - } - -void +/** + * @brief Send a persistent monitor triggered signal to a process. + * + * Used by monitors that are not auto disabled such as for + * example 'time_offset' monitors. + */ +static void erts_proc_sig_send_persistent_monitor_msg(Uint16 type, Eterm key, Eterm from, Eterm to, - Eterm msg, Uint msg_sz) -{ + Eterm msg, Uint msg_sz, + int force_flush) { ErtsPersistMonMsg *prst_mon; ErtsMessage *mp; ErlHeapFragment *hfrag; @@ -1682,13 +2105,30 @@ erts_proc_sig_send_persistent_monitor_msg(Uint16 type, Eterm key, ERL_MESSAGE_FROM(mp) = from; ERL_MESSAGE_TOKEN(mp) = am_undefined; - if (!proc_queue_signal(NULL, to, (ErtsSignal *) mp, + if (!proc_queue_signal(NULL, from, to, (ErtsSignal *) mp, force_flush, ERTS_SIG_Q_OP_PERSISTENT_MON_MSG)) { mp->next = NULL; erts_cleanup_messages(mp); } } +void +erts_proc_sig_send_monitor_nodes_msg(Eterm key, Eterm to, + Eterm msg, Uint msg_sz) { + erts_proc_sig_send_persistent_monitor_msg(ERTS_MON_TYPE_NODES, + key, am_system, to, + msg, msg_sz, 1); +} + +void +erts_proc_sig_send_monitor_time_offset_msg(Eterm key, Eterm to, + Eterm msg, Uint msg_sz) { + erts_proc_sig_send_persistent_monitor_msg(ERTS_MON_TYPE_TIME_OFFSET, + key, am_clock_service, to, + msg, msg_sz, 0); + +} + static ERTS_INLINE Eterm get_persist_mon_msg(ErtsMessage *sig, Eterm *msg) { @@ -1701,12 +2141,14 @@ get_persist_mon_msg(ErtsMessage *sig, Eterm *msg) } void -erts_proc_sig_send_exit(Process *c_p, Eterm from, Eterm to, +erts_proc_sig_send_exit(ErtsPTabElementCommon *sender, Eterm from, Eterm to, Eterm reason, Eterm token, int normal_kills) { Eterm from_tag; - ASSERT(!c_p || c_p->common.id == from); + + ASSERT(sender == NULL || sender->id == from); + if (is_immed(from)) { ASSERT(is_internal_pid(from) || is_internal_port(from)); from_tag = from; @@ -1717,7 +2159,8 @@ erts_proc_sig_send_exit(Process *c_p, Eterm from, Eterm to, dep = external_pid_dist_entry(from); from_tag = dep->sysname; } - send_gen_exit_signal(c_p, from_tag, from, to, ERTS_SIG_Q_OP_EXIT, + + send_gen_exit_signal(sender, from_tag, from, to, ERTS_SIG_Q_OP_EXIT, reason, NULL, NULL, NIL, token, normal_kills, 0, 0); } @@ -1734,87 +2177,84 @@ erts_proc_sig_send_dist_exit(DistEntry *dep, } void -erts_proc_sig_send_link_exit(Process *c_p, Eterm from, ErtsLink *lnk, - Eterm reason, Eterm token) +erts_proc_sig_send_link_exit_noconnection(ErtsLink *lnk) { Eterm to, from_tag, from_item; - int conn_lost; + ErtsLink *olnk; + ErtsELink *elnk; Uint32 conn_id; - ASSERT(!c_p || c_p->common.id == from); + + to = lnk->other.item; + + ASSERT(lnk->flags & ERTS_ML_FLG_EXTENDED); + ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC); + + olnk = erts_link_to_other(lnk, &elnk); + + from_item = olnk->other.item; + from_tag = elnk->dist->nodename; + conn_id = elnk->dist->connection_id; + + send_gen_exit_signal(NULL, from_tag, from_item, to, ERTS_SIG_Q_OP_EXIT_LINKED, + am_noconnection, NULL, NULL, NIL, NIL, 0, !0, conn_id); + + erts_link_release(lnk); +} + +void +erts_proc_sig_send_link_exit(ErtsPTabElementCommon *sender, Eterm from, + ErtsLink *lnk, Eterm reason, Eterm token) +{ + Eterm to; + + ASSERT(sender == NULL || sender->id == from); ASSERT(lnk); + to = lnk->other.item; - if (is_value(from)) { - ASSERT(is_internal_pid(from) || is_internal_port(from)); - from_tag = from_item = from; - conn_id = 0; - conn_lost = 0; - } - else { - ErtsLink *olnk; - ErtsELink *elnk; - ASSERT(reason == am_noconnection); - ASSERT(lnk->flags & ERTS_ML_FLG_EXTENDED); - ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC); + ASSERT(is_internal_pid(from) || is_internal_port(from)); - olnk = erts_link_to_other(lnk, &elnk); + send_gen_exit_signal(sender, from, from, to, ERTS_SIG_Q_OP_EXIT_LINKED, + reason, NULL, NULL, NIL, token, 0, 0, 0); - from_item = olnk->other.item; - from_tag = elnk->dist->nodename; - conn_id = elnk->dist->connection_id; - conn_lost = !0; - } - send_gen_exit_signal(c_p, from_tag, from_item, to, ERTS_SIG_Q_OP_EXIT_LINKED, - reason, NULL, NULL, NIL, token, 0, conn_lost, conn_id); erts_link_release(lnk); } int -erts_proc_sig_send_link(Process *c_p, Eterm to, ErtsLink *lnk) +erts_proc_sig_send_link(ErtsPTabElementCommon *sender, Eterm from, + Eterm to, ErtsLink *lnk) { ErtsSignal *sig; Uint16 type = lnk->type; - ASSERT(!c_p || c_p->common.id == lnk->other.item); - ASSERT(lnk); + ASSERT(!sender || sender->id == from); + ASSERT(lnk && eq(from, lnk->other.item)); ASSERT(is_internal_pid(to)); sig = (ErtsSignal *) lnk; sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_LINK, type, 0); - return proc_queue_signal(c_p, to, sig, ERTS_SIG_Q_OP_LINK); + return proc_queue_signal(sender, from, to, sig, 0, ERTS_SIG_Q_OP_LINK); } ErtsSigUnlinkOp * -erts_proc_sig_make_unlink_op(Process *c_p, Eterm from) +erts_proc_sig_make_unlink_op(ErtsPTabElementCommon *sender, Eterm from) { - Uint64 id; ErtsSigUnlinkOp *sulnk; - if (c_p) - id = erts_proc_sig_new_unlink_id(c_p); - else { - /* - * *Only* ports are allowed to call without current - * process pointer... - */ - ASSERT(is_internal_port(from)); - id = (Uint64) erts_raw_get_unique_monotonic_integer(); - if (id == 0) - id = (Uint64) erts_raw_get_unique_monotonic_integer(); - } - - ASSERT(id != 0); + + ASSERT(sender->id == from); sulnk = erts_alloc(ERTS_ALC_T_SIG_DATA, sizeof(ErtsSigUnlinkOp)); sulnk->from = from; - sulnk->id = id; + sulnk->id = erts_proc_sig_new_unlink_id(sender); return sulnk; } Uint64 -erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk) +erts_proc_sig_send_unlink(ErtsPTabElementCommon *sender, Eterm from, + ErtsLink *lnk) { int res; ErtsSignal *sig; @@ -1826,7 +2266,7 @@ erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk) || lnk->type != ERTS_LNK_TYPE_PORT); ASSERT(lnk->flags & ERTS_ML_FLG_IN_TABLE); - sulnk = erts_proc_sig_make_unlink_op(c_p, from); + sulnk = erts_proc_sig_make_unlink_op(sender, from); id = sulnk->id; sig = (ErtsSignal *) sulnk; to = lnk->other.item; @@ -1834,7 +2274,7 @@ erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk) lnk->type, 0); ASSERT(is_internal_pid(to)); - res = proc_queue_signal(c_p, to, sig, ERTS_SIG_Q_OP_UNLINK); + res = proc_queue_signal(sender, from, to, sig, 0, ERTS_SIG_Q_OP_UNLINK); if (res == 0) { erts_proc_sig_destroy_unlink_op(sulnk); return 0; @@ -1843,7 +2283,8 @@ erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk) } void -erts_proc_sig_send_unlink_ack(Process *c_p, Eterm from, ErtsSigUnlinkOp *sulnk) +erts_proc_sig_send_unlink_ack(ErtsPTabElementCommon *sender, Eterm from, + ErtsSigUnlinkOp *sulnk) { ErtsSignal *sig = (ErtsSignal *) sulnk; Eterm to = sulnk->from; @@ -1856,8 +2297,10 @@ erts_proc_sig_send_unlink_ack(Process *c_p, Eterm from, ErtsSigUnlinkOp *sulnk) type = is_internal_pid(from) ? ERTS_LNK_TYPE_PROC : ERTS_LNK_TYPE_PORT; sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_UNLINK_ACK, type, 0); - if (!proc_queue_signal(c_p, to, sig, ERTS_SIG_Q_OP_UNLINK_ACK)) - erts_proc_sig_destroy_unlink_op(sulnk); + + if (!proc_queue_signal(sender, from, to, sig, 0, ERTS_SIG_Q_OP_UNLINK_ACK)) { + erts_proc_sig_destroy_unlink_op(sulnk); + } } void @@ -1890,12 +2333,14 @@ erts_proc_sig_send_dist_unlink(DistEntry *dep, Uint32 conn_id, dep->sysname, conn_id, to, from, id); - if (!proc_queue_signal(NULL, to, sig, ERTS_SIG_Q_OP_UNLINK)) + if (!proc_queue_signal(NULL, from, to, sig, 0, + ERTS_SIG_Q_OP_UNLINK)) { reply_dist_unlink_ack(NULL, (ErtsSigDistUnlinkOp *) sig); + } } void -erts_proc_sig_send_dist_unlink_ack(Process *c_p, DistEntry *dep, +erts_proc_sig_send_dist_unlink_ack(DistEntry *dep, Uint32 conn_id, Eterm from, Eterm to, Uint64 id) { @@ -1910,8 +2355,10 @@ erts_proc_sig_send_dist_unlink_ack(Process *c_p, DistEntry *dep, dep->sysname, conn_id, to, from, id); - if (!proc_queue_signal(c_p, to, sig, ERTS_SIG_Q_OP_UNLINK_ACK)) + if (!proc_queue_signal(NULL, from, to, sig, 0, + ERTS_SIG_Q_OP_UNLINK_ACK)) { destroy_sig_dist_unlink_op((ErtsSigDistUnlinkOp *) sig); + } } static void @@ -1964,17 +2411,20 @@ erts_proc_sig_send_dist_monitor_down(DistEntry *dep, Eterm ref, Eterm reason) { Eterm monitored, heap[3]; + if (is_atom(from)) monitored = TUPLE2(&heap[0], from, dep->sysname); else monitored = from; + send_gen_exit_signal(NULL, dep->sysname, monitored, to, ERTS_SIG_Q_OP_MONITOR_DOWN, reason, dist_ext, hfrag, ref, NIL, 0, 0, 0); } void -erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason) +erts_proc_sig_send_monitor_down(ErtsPTabElementCommon *sender, Eterm from, + ErtsMonitor *mon, Eterm reason) { Eterm to; @@ -1994,8 +2444,11 @@ erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason) sig = (ErtsSignal *) mon; sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_MONITOR_DOWN, mon->type, 0); - if (proc_queue_signal(NULL, to, sig, ERTS_SIG_Q_OP_MONITOR_DOWN)) + if (proc_queue_signal(sender, from, to, sig, + !(is_pid(from) || is_port(from)), + ERTS_SIG_Q_OP_MONITOR_DOWN)) { return; /* receiver will destroy mon structure */ + } } else { ErtsMonitorData *mdp = erts_monitor_to_data(mon); @@ -2039,16 +2492,18 @@ erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason) || is_atom(from_tag)); monitored = TUPLE2(&heap[0], name, node); } - send_gen_exit_signal(NULL, from_tag, monitored, + + send_gen_exit_signal(sender, from_tag, monitored, to, ERTS_SIG_Q_OP_MONITOR_DOWN, reason, NULL, NULL, mdp->ref, NIL, 0, 0, 0); } + erts_monitor_release(mon); } void -erts_proc_sig_send_dist_demonitor(Eterm to, Eterm ref) +erts_proc_sig_send_dist_demonitor(Eterm from, Eterm to, Eterm ref) { ErtsSigDistProcDemonitor *dmon; ErtsSignal *sig; @@ -2058,6 +2513,7 @@ erts_proc_sig_send_dist_demonitor(Eterm to, Eterm ref) ERTS_INIT_OFF_HEAP(&oh); + ASSERT(is_external_pid(from)); ASSERT(is_internal_pid(to)); size = sizeof(ErtsSigDistProcDemonitor) - sizeof(Eterm); @@ -2074,12 +2530,14 @@ erts_proc_sig_send_dist_demonitor(Eterm to, Eterm ref) ERTS_SIG_Q_TYPE_DIST_PROC_DEMONITOR, 0); - if (!proc_queue_signal(NULL, to, sig, ERTS_SIG_Q_OP_DEMONITOR)) + if (!proc_queue_signal(NULL, from, to, sig, 0, ERTS_SIG_Q_OP_DEMONITOR)) { destroy_dist_proc_demonitor(dmon); + } } void -erts_proc_sig_send_demonitor(ErtsMonitor *mon) +erts_proc_sig_send_demonitor(ErtsPTabElementCommon *sender, Eterm from, + int system, ErtsMonitor *mon) { ErtsSignal *sig = (ErtsSignal *) mon; Uint16 type = mon->type; @@ -2088,18 +2546,22 @@ erts_proc_sig_send_demonitor(ErtsMonitor *mon) ASSERT(is_internal_pid(to) || to == am_undefined); ASSERT(erts_monitor_is_origin(mon)); ASSERT(!erts_monitor_is_in_table(mon)); + ASSERT(!system || sender == NULL); sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_DEMONITOR, type, 0); - + if (is_not_internal_pid(to) - || !proc_queue_signal(NULL, to, sig, ERTS_SIG_Q_OP_DEMONITOR)) { + || !proc_queue_signal(sender, from, to, sig, + !(system || (is_pid(from) || is_port(from))), + ERTS_SIG_Q_OP_DEMONITOR)) { erts_monitor_release(mon); } } int -erts_proc_sig_send_monitor(ErtsMonitor *mon, Eterm to) +erts_proc_sig_send_monitor(ErtsPTabElementCommon *sender, Eterm from, + ErtsMonitor *mon, Eterm to) { ErtsSignal *sig = (ErtsSignal *) mon; Uint16 type = mon->type; @@ -2109,31 +2571,8 @@ erts_proc_sig_send_monitor(ErtsMonitor *mon, Eterm to) sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_MONITOR, type, 0); - - return proc_queue_signal(NULL, to, sig, ERTS_SIG_Q_OP_MONITOR); -} - -void -erts_proc_sig_send_trace_change(Eterm to, Uint on, Uint off, Eterm tracer) -{ - ErtsSigTraceInfo *ti; - Eterm tag; - ti = erts_alloc(ERTS_ALC_T_SIG_DATA, sizeof(ErtsSigTraceInfo)); - tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_TRACE_CHANGE_STATE, - ERTS_SIG_Q_TYPE_ADJUST_TRACE_INFO, - 0); - - ti->common.tag = tag; - ti->flags_off = off; - ti->flags_on = on; - ti->tracer = NIL; - if (is_not_nil(tracer)) - erts_tracer_update(&ti->tracer, tracer); - - if (!proc_queue_signal(NULL, to, (ErtsSignal *) ti, - ERTS_SIG_Q_OP_TRACE_CHANGE_STATE)) - destroy_trace_info(ti); + return proc_queue_signal(sender, from, to, sig, 0, ERTS_SIG_Q_OP_MONITOR); } void @@ -2172,12 +2611,12 @@ erts_proc_sig_send_group_leader(Process *c_p, Eterm to, Eterm gl, Eterm ref) ERTS_SIG_Q_TYPE_UNDEFINED, 0); - res = proc_queue_signal(c_p, to, (ErtsSignal *) sgl, - ERTS_SIG_Q_OP_GROUP_LEADER); + res = proc_queue_signal(c_p ? &c_p->common : NULL, sgl->reply_to, to, + (ErtsSignal *)sgl, 0, ERTS_SIG_Q_OP_GROUP_LEADER); - if (!res) + if (!res) { destroy_sig_group_leader(sgl); - else if (c_p) { + } else if (c_p) { erts_aint_t flags, rm_flags = ERTS_SIG_GL_FLG_SENDER; int prio_res = maybe_elevate_sig_handling_prio(c_p, -1, to); if (!prio_res) @@ -2227,7 +2666,8 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref) ERTS_SIG_Q_TYPE_UNDEFINED, 0); - if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_IS_ALIVE)) { + if (proc_queue_signal(&c_p->common, c_p->common.id, to, + (ErtsSignal *)mp, 0, ERTS_SIG_Q_OP_IS_ALIVE)) { (void) maybe_elevate_sig_handling_prio(c_p, -1, to); return !0; } @@ -2284,12 +2724,15 @@ erts_proc_sig_send_process_info_request(Process *c_p, sys_memcpy((void *) &pis->item_ix[0], (void *) item_ix, sizeof(int)*len); - res = proc_queue_signal(c_p, to, (ErtsSignal *) pis, - ERTS_SIG_Q_OP_PROCESS_INFO); - if (res) + + res = proc_queue_signal(&c_p->common, c_p->common.id, to, + (ErtsSignal *)pis, 0, ERTS_SIG_Q_OP_PROCESS_INFO); + if (res) { (void) maybe_elevate_sig_handling_prio(c_p, -1, to); - else + } else { erts_free(ERTS_ALC_T_SIG_DATA, pis); + } + return res; } @@ -2333,9 +2776,10 @@ erts_proc_sig_send_sync_suspend(Process *c_p, Eterm to, Eterm tag, Eterm reply) ERTS_SIG_Q_TYPE_UNDEFINED, 0); - if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_SYNC_SUSPEND)) + if (proc_queue_signal(&c_p->common, c_p->common.id, to, + (ErtsSignal *)mp, 0, ERTS_SIG_Q_OP_SYNC_SUSPEND)) { (void) maybe_elevate_sig_handling_prio(c_p, -1, to); - else { + } else { Eterm *tp; /* It wasn't alive; reply to ourselves... */ mp->next = NULL; @@ -2362,11 +2806,13 @@ erts_proc_sig_send_dist_spawn_reply(Eterm node, ErlHeapFragment *hfrag; ErlOffHeap *ohp; ErtsMessage *mp; + Eterm ordered_from; + int force_flush; ASSERT(is_atom(node)); /* - * A respons message to a spawn_request() operation + * A response message to a spawn_request() operation * looks like this: * {Tag, Ref, ok|error, Pid|ErrorAtom} * @@ -2433,8 +2879,23 @@ erts_proc_sig_send_dist_spawn_reply(Eterm node, 0); ERL_MESSAGE_FROM(mp) = node; ERL_MESSAGE_TOKEN(mp) = token_copy; - if (!proc_queue_signal(NULL, to, (ErtsSignal *) mp, - ERTS_SIG_Q_OP_DIST_SPAWN_REPLY)) { + + /* + * Sent from spawn-service at node, but we need to order this + * signal against signals sent from the spawned process, so + * we need to pass the pid of the spawned process as from + * parameter or flush if connection was lost... + */ + if (is_external_pid(result)) { + force_flush = 0; + ordered_from = result; + } + else { + force_flush = result == am_noconnection; + ordered_from = am_spawn_service; + } + if (!proc_queue_signal(NULL, ordered_from, to, (ErtsSignal *)mp, + force_flush, ERTS_SIG_Q_OP_DIST_SPAWN_REPLY)) { mp->next = NULL; mp->data.attached = ERTS_MSG_COMBINED_HFRAG; ERL_MESSAGE_TERM(mp) = msg; @@ -2489,9 +2950,10 @@ erts_proc_sig_send_rpc_request_prio(Process *c_p, erts_msgq_set_save_end(c_p); } - if (proc_queue_signal(c_p, to, (ErtsSignal *) sig, ERTS_SIG_Q_OP_RPC)) + if (proc_queue_signal(&c_p->common, c_p->common.id, to, (ErtsSignal *)sig, + 0, ERTS_SIG_Q_OP_RPC)) { (void) maybe_elevate_sig_handling_prio(c_p, prio, to); - else { + } else { erts_free(ERTS_ALC_T_SIG_DATA, sig); res = THE_NON_VALUE; if (reply) @@ -2535,6 +2997,7 @@ erts_proc_sig_send_cla_request(Process *c_p, Eterm to, Eterm req_id) cla = (ErtsCLAData *) (char *) hp; hfrag->used_size = hp - start_hp; + cla->yield = NULL; cla->requester = c_p->common.id; cla->request_id = req_id_cpy; @@ -2547,15 +3010,29 @@ erts_proc_sig_send_cla_request(Process *c_p, Eterm to, Eterm req_id) ERL_MESSAGE_DT_UTAG(sig) = NIL; #endif - if (!proc_queue_signal(c_p, to, (ErtsSignal *) sig, ERTS_SIG_Q_OP_ADJ_MSGQ)) + if (!proc_queue_signal(&c_p->common, c_p->common.id, to, (ErtsSignal *)sig, + 0, ERTS_SIG_Q_OP_ADJ_MSGQ)) { send_cla_reply(c_p, sig, c_p->common.id, req_id_cpy, am_ok); + } } void -erts_proc_sig_send_move_msgq_off_heap(Process *c_p, Eterm to) +erts_proc_sig_send_move_msgq_off_heap(Eterm to) { - ErtsMessage *sig = erts_alloc_message(0, NULL); + ErtsMessage *sig; + Eterm *hp; + Uint hsz; + ErtsAdjOffHeapMsgQData *ohdp; ASSERT(is_internal_pid(to)); + + hsz = sizeof(ErtsAdjOffHeapMsgQData)/sizeof(Uint); + sig = erts_alloc_message(hsz, &hp); + + ohdp = (ErtsAdjOffHeapMsgQData *) (char *) hp; + ohdp->yield = NULL; + + sig->hfrag.used_size = 0; + ERL_MESSAGE_TERM(sig) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_ADJ_MSGQ, ERTS_SIG_Q_TYPE_OFF_HEAP, 0); @@ -2564,10 +3041,89 @@ erts_proc_sig_send_move_msgq_off_heap(Process *c_p, Eterm to) #ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(sig) = NIL; #endif - if (!proc_queue_signal(c_p, to, (ErtsSignal *) sig, ERTS_SIG_Q_OP_ADJ_MSGQ)) { - sig->next = NULL; - erts_cleanup_messages(sig); + + if (!proc_queue_signal(NULL, am_system, to, (ErtsSignal *)sig, 0, + ERTS_SIG_Q_OP_ADJ_MSGQ)) { + sig->next = NULL; + erts_cleanup_messages(sig); + } +} + +void +erts_proc_sig_init_flush_signals(Process *c_p, int flags, Eterm id) +{ + int force_flush_buffers = 0, enqueue_mq, fetch_sigs; + ErtsSignal *sig; + + ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p)); + + ASSERT(!(c_p->sig_qs.flags & (FS_FLUSHING_SIGS|FS_FLUSHED_SIGS))); + ASSERT(flags); + ASSERT((flags & ~ERTS_PROC_SIG_FLUSH_FLGS) == 0); + ASSERT(!(flags & ERTS_PROC_SIG_FLUSH_FLG_FROM_ID) + || is_internal_pid(id) || is_internal_port(id)); + + sig = erts_alloc(ERTS_ALC_T_SIG_DATA, sizeof(ErtsSignalCommon)); + sig->common.next = NULL; + sig->common.specific.attachment = NULL; + sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_FLUSH, + ERTS_SIG_Q_TYPE_UNDEFINED, + 0); + switch (flags) { + case ERTS_PROC_SIG_FLUSH_FLG_FROM_ALL: + id = c_p->common.id; + force_flush_buffers = !0; + /* Fall through... */ + case ERTS_PROC_SIG_FLUSH_FLG_FROM_ID: + if (!proc_queue_signal(NULL, id, c_p->common.id, sig, + force_flush_buffers, ERTS_SIG_Q_OP_FLUSH)) + ERTS_INTERNAL_ERROR("Failed to send flush signal to ourselves"); + enqueue_mq = 0; + fetch_sigs = !0; + break; + case ERTS_PROC_SIG_FLUSH_FLG_CLEAN_SIGQ: + enqueue_mq = !0; + fetch_sigs = 0; + break; + default: + enqueue_mq = !!(flags & ERTS_PROC_SIG_FLUSH_FLG_CLEAN_SIGQ); + fetch_sigs = !0; + break; + } + + erts_set_gc_state(c_p, 0); + + if (fetch_sigs) { + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(c_p); + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + } + + c_p->sig_qs.flags |= FS_FLUSHING_SIGS; + + if (enqueue_mq) { + if (!c_p->sig_qs.cont) { + c_p->sig_qs.flags |= FS_FLUSHED_SIGS; + erts_free(ERTS_ALC_T_SIG_DATA, sig); + } + else { + if (!c_p->sig_qs.nmsigs.last) { + ASSERT(!c_p->sig_qs.nmsigs.next); + c_p->sig_qs.nmsigs.next = c_p->sig_qs.cont_last; + } + else { + ErtsSignal *lsig = (ErtsSignal *) *c_p->sig_qs.nmsigs.last; + ASSERT(c_p->sig_qs.nmsigs.next); + ASSERT(lsig && !lsig->common.specific.next); + lsig->common.specific.next = c_p->sig_qs.cont_last; + } + + c_p->sig_qs.nmsigs.last = c_p->sig_qs.cont_last; + *c_p->sig_qs.cont_last = (ErtsMessage *) sig; + c_p->sig_qs.cont_last = &sig->common.next; + } } + } static int @@ -2756,7 +3312,7 @@ remove_iq_sig(Process *c_p, ErtsMessage *sig, ErtsMessage **next_sig) static ERTS_INLINE void remove_mq_sig(Process *c_p, ErtsMessage *sig, - ErtsMessage **next_sig, ErtsMessage ***next_nm_sig) + ErtsMessage **next_sig, ErtsMessage ***next_nm_sig) { /* * Remove signal from (middle) signal queue. @@ -2984,6 +3540,8 @@ recv_marker_deallocate(Process *c_p, ErtsRecvMarker *markp) ErtsRecvMarkerBlock *blkp = c_p->sig_qs.recv_mrk_blk; int ix, nix; + ASSERT(!markp->is_yield_mark); + ASSERT(blkp); ERTS_HDBG_CHK_RECV_MRKS(c_p); @@ -3034,6 +3592,7 @@ recv_marker_dequeue(Process *c_p, ErtsRecvMarker *markp) { ErtsMessage *sigp; + ASSERT(!markp->is_yield_mark); ASSERT(markp->proc == c_p); if (markp->in_sigq <= 0) { @@ -3099,6 +3658,7 @@ recv_marker_alloc_block(Process *c_p, ErtsRecvMarkerBlock **blkpp, /* Allocate marker for 'uniqp' in index zero... */ *ixp = 0; blkp->ref[0] = recv_marker_uniq(c_p, uniqp); + blkp->marker[0].is_yield_mark = 0; markp = &blkp->marker[0]; markp->next_ix = markp->prev_ix = 0; blkp->used_ix = 0; @@ -3114,6 +3674,7 @@ recv_marker_alloc_block(Process *c_p, ErtsRecvMarkerBlock **blkpp, blkp->free_ix = 1; for (ix = 1; ix < ERTS_RECV_MARKER_BLOCK_SIZE; ix++) { blkp->ref[ix] = am_free; + blkp->marker[ix].is_yield_mark = 0; if (ix == ERTS_RECV_MARKER_BLOCK_SIZE - 1) blkp->marker[ix].next_ix = -1; /* End of list */ else @@ -3381,20 +3942,29 @@ erts_msgq_recv_marker_create_insert_set_save(Process *c_p, Eterm id) } void -erts_msgq_remove_leading_recv_markers(Process *c_p) +erts_msgq_remove_leading_recv_markers_set_save_first(Process *c_p) { + ErtsMessage **save; /* * Receive markers in the front of the queue does not - * add any value, so we just remove them... + * add any value, so we just remove them. We need to + * keep and pass yield markers though... */ ASSERT(c_p->sig_qs.first && ERTS_SIG_IS_RECV_MARKER(c_p->sig_qs.first)); ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); + save = &c_p->sig_qs.first; do { - ErtsRecvMarker *markp = (ErtsRecvMarker *) c_p->sig_qs.first; - recv_marker_dequeue(c_p, markp); - } while (c_p->sig_qs.first - && ERTS_SIG_IS_RECV_MARKER(c_p->sig_qs.first)); + ErtsRecvMarker *markp = (ErtsRecvMarker *) *save; + if (markp->is_yield_mark) + save = &markp->sig.common.next; + else + recv_marker_dequeue(c_p, markp); + } while (*save && ERTS_SIG_IS_RECV_MARKER(*save)); + + c_p->sig_qs.save = save; + + ASSERT(!*save || ERTS_SIG_IS_MSG(*save)); ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); } @@ -3406,7 +3976,8 @@ erts_msgq_pass_recv_markers(Process *c_p, ErtsMessage **markpp) ASSERT(ERTS_SIG_IS_RECV_MARKER(sigp)); do { ErtsRecvMarker *markp = (ErtsRecvMarker *) sigp; - if (++markp->pass > ERTS_RECV_MARKER_PASS_MAX) { + if (!markp->is_yield_mark + && ++markp->pass > ERTS_RECV_MARKER_PASS_MAX) { recv_marker_dequeue(c_p, markp); sigp = *sigpp; } @@ -3611,7 +4182,7 @@ convert_to_down_message(Process *c_p, if (mdp->origin.flags & (ERTS_ML_FLG_SPAWN_ABANDONED | ERTS_ML_FLG_SPAWN_NO_EMSG)) { /* - * Operation has been been abandoned or + * Operation has been abandoned or * error message has been disabled... */ erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p), *omon); @@ -4194,6 +4765,7 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing, *c_p->sig_qs.last = c_p->sig_qs.cont; c_p->sig_qs.last = *next_nm_sig; + ASSERT(*next_nm_sig); c_p->sig_qs.cont = **next_nm_sig; if (c_p->sig_qs.nmsigs.last == *next_nm_sig) c_p->sig_qs.nmsigs.last = &c_p->sig_qs.cont; @@ -4885,15 +5457,13 @@ handle_alias_message(Process *c_p, ErtsMessage *sig, ErtsMessage ***next_nm_sig) erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p), mon); - erts_pid_ref_delete(alias); - switch (mon->type) { case ERTS_MON_TYPE_DIST_PORT: case ERTS_MON_TYPE_ALIAS: erts_monitor_release(mon); break; case ERTS_MON_TYPE_PROC: - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(&c_p->common, c_p->common.id, 0, mon); break; case ERTS_MON_TYPE_DIST_PROC: { ErtsMonitorData *mdp; @@ -4991,20 +5561,20 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, int *redsp, int max_reds, int local_only) { Eterm tag; - erts_aint32_t state; + erts_aint32_t state = *statep; int yield, cnt, limit, abs_lim, msg_tracing, save_in_msgq; ErtsMessage *sig, ***next_nm_sig; ErtsSigRecvTracing tracing; + ErtsSavedNMSignals delayed_nm_signals = {0}; ASSERT(!(c_p->sig_qs.flags & (FS_WAIT_HANDLE_SIGS|FS_HANDLING_SIGS))); ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p)); - state = erts_atomic32_read_nob(&c_p->state); - if (!local_only) { - if (ERTS_PSFLG_SIG_IN_Q & state) { - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + if (!local_only && !(c_p->sig_qs.flags & FS_FLUSHING_SIGS)) { + if ((ERTS_PSFLG_NMSG_SIG_IN_Q|ERTS_PSFLG_MSG_SIG_IN_Q) & state) { + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); } @@ -5211,7 +5781,6 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, case ERTS_ML_STATE_ALIAS_ONCE: case ERTS_ML_STATE_ALIAS_DEMONITOR: ASSERT(is_internal_pid_ref(mdp->ref)); - erts_pid_ref_delete(mdp->ref); /* fall through... */ default: if (type != ERTS_MON_TYPE_NODE) @@ -5248,7 +5817,6 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, if ((mon->flags & ERTS_ML_STATE_ALIAS_MASK) == ERTS_ML_STATE_ALIAS_ONCE) { mon->flags &= ~ERTS_ML_STATE_ALIAS_MASK; - erts_pid_ref_delete(key); } } else { @@ -5419,9 +5987,10 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, erts_link_release(llnk); cnt += 4; } - if (is_internal_pid(sulnk->from)) - erts_proc_sig_send_unlink_ack(c_p, c_p->common.id, sulnk); - else { + if (is_internal_pid(sulnk->from)) { + erts_proc_sig_send_unlink_ack(&c_p->common, c_p->common.id, + sulnk); + } else { Port *prt; ASSERT(is_internal_port(sulnk->from)); prt = erts_port_lookup(sulnk->from, @@ -5519,21 +6088,57 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); break; - case ERTS_SIG_Q_OP_ADJ_MSGQ: + case ERTS_SIG_Q_OP_ADJ_MSGQ: { + int adj_limit, adj_cnt, min_adj_limit; + /* + * This may require a substantial amount of work and we + * want to get it over and done with in a reasonable + * amount of time, so we bump up the limit for it a bit... + */ + min_adj_limit = ERTS_SIG_REDS_CNT_FACTOR*CONTEXT_REDS/6; + if (sig->next) + adj_limit = min_adj_limit; + else { + adj_limit = limit - cnt; + if (adj_limit < min_adj_limit) + adj_limit = min_adj_limit; + } ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); switch (ERTS_PROC_SIG_TYPE(tag)) { case ERTS_SIG_Q_TYPE_CLA: - cnt += handle_cla(c_p, sig, next_nm_sig, 0); + adj_cnt = handle_cla(c_p, sig, next_nm_sig, 0, adj_limit, + &delayed_nm_signals); break; case ERTS_SIG_Q_TYPE_OFF_HEAP: - cnt += handle_move_msgq_off_heap(c_p, sig, next_nm_sig, 0); + adj_cnt = handle_move_msgq_off_heap(c_p, sig, next_nm_sig, + 0, adj_limit, + &delayed_nm_signals); break; default: - ERTS_INTERNAL_ERROR("Invalid 'adjust-message-queue' signal type"); + ERTS_INTERNAL_ERROR("Invalid adjust-message-queue signal type"); break; } + cnt += adj_cnt; + limit += adj_cnt; + if (limit > abs_lim) + abs_lim = limit; ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); break; + } + + case ERTS_SIG_Q_OP_FLUSH: + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + ASSERT(c_p->sig_qs.flags & FS_FLUSHING_SIGS); + c_p->sig_qs.flags |= FS_FLUSHED_SIGS; + remove_nm_sig(c_p, sig, next_nm_sig); + erts_free(ERTS_ALC_T_SIG_DATA, sig); + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + /* + * The caller has been exclusively handling signals until this + * point. Break out and let the process continue with other + * things as well... + */ + goto stop; case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: { Uint16 type = ERTS_PROC_SIG_TYPE(tag); @@ -5564,6 +6169,7 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, case ERTS_SIG_Q_OP_RECV_MARK: { ErtsRecvMarker *markp = (ErtsRecvMarker *) sig; ASSERT(markp->in_sigq); + ASSERT(!markp->is_yield_mark); if (markp->in_sigq < 0) { /* Marked for removal... */ @@ -5651,7 +6257,7 @@ stop: { *next_nm_sig = &c_p->sig_qs.cont; if (c_p->sig_qs.nmsigs.last == tracing.messages.next) c_p->sig_qs.nmsigs.last = &c_p->sig_qs.cont; - *statep = erts_atomic32_read_nob(&c_p->state); + state = erts_atomic32_read_nob(&c_p->state); } else { ASSERT(!c_p->sig_qs.nmsigs.next); @@ -5659,7 +6265,6 @@ stop: { state = erts_atomic32_read_band_nob(&c_p->state, ~ERTS_PSFLG_SIG_Q); state &= ~ERTS_PSFLG_SIG_Q; - *statep = state; } if (tracing.messages.next != &c_p->sig_qs.cont) { @@ -5705,7 +6310,7 @@ stop: { ASSERT(c_p->sig_qs.cont); - *statep = erts_atomic32_read_nob(&c_p->state); + state = erts_atomic32_read_nob(&c_p->state); res = 0; } @@ -5738,10 +6343,36 @@ stop: { state = erts_atomic32_read_band_nob(&c_p->state, ~ERTS_PSFLG_SIG_Q); state &= ~ERTS_PSFLG_SIG_Q; - *statep = state; res = !0; } + if (!(state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q))) { + /* + * We know we do not have any outstanding signals + * from ourselves... + */ + (void) erts_atomic32_read_band_nob(&c_p->xstate, + ~ERTS_PXSFLG_MAYBE_SELF_SIGS); + } + + if (delayed_nm_signals.first) { + /* + * We do this after clearing ERTS_PXSFLG_MAYBE_SELF_SIGS + * since there currently are no signals that can be delayed + * that should be counted as originating from the process + * itself. If such signals appear in the future this has to + * be accounted for... + * + * The adjust message queue data "signal" does originate from + * the process itself, but it is not conseptually a signal. + */ + state = restore_delayed_nm_signals(c_p, &delayed_nm_signals); + } + + *statep = state; + /* Ensure that 'save' doesn't point to a receive marker... */ if (*c_p->sig_qs.save && ERTS_SIG_IS_RECV_MARKER(*c_p->sig_qs.save)) { @@ -5751,7 +6382,7 @@ stop: { ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); - *redsp = cnt/4 + 1; + *redsp = cnt/ERTS_SIG_REDS_CNT_FACTOR + 1; if (yield) { int vreds = max_reds - *redsp; @@ -5854,6 +6485,7 @@ int erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, ErtsProcExitContext *pe_ctxt_p) { + int yield = 0; int cnt; Sint limit; ErtsMessage *sig, ***next_nm_sig; @@ -5861,8 +6493,6 @@ erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN); - ASSERT(!(ERTS_PSFLG_SIG_IN_Q & erts_atomic32_read_nob(&c_p->state))); - limit = *redsp; limit *= ERTS_SIG_REDS_CNT_FACTOR; @@ -5958,12 +6588,12 @@ erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, } case ERTS_SIG_Q_OP_UNLINK: - if (type == ERTS_SIG_Q_TYPE_DIST_LINK) + if (type == ERTS_SIG_Q_TYPE_DIST_LINK) { reply_dist_unlink_ack(c_p, (ErtsSigDistUnlinkOp *) sig); - else if (is_internal_pid(((ErtsSigUnlinkOp *) sig)->from)) - erts_proc_sig_send_unlink_ack(c_p, c_p->common.id, + } else if (is_internal_pid(((ErtsSigUnlinkOp *) sig)->from)) { + erts_proc_sig_send_unlink_ack(&c_p->common, c_p->common.id, (ErtsSigUnlinkOp *) sig); - else { + } else { Port *prt; ASSERT(is_internal_port(((ErtsSigUnlinkOp *) sig)->from)); prt = erts_port_lookup(((ErtsSigUnlinkOp *) sig)->from, @@ -6000,12 +6630,11 @@ erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, handle_sync_suspend(c_p, sig); break; - case ERTS_SIG_Q_OP_RPC: { - int yield = 0; - handle_rpc(c_p, (ErtsProcSigRPC *) sig, - cnt, limit, &yield); + case ERTS_SIG_Q_OP_RPC: + yield = 0; + cnt += handle_rpc(c_p, (ErtsProcSigRPC *) sig, + cnt, limit, &yield); break; - } case ERTS_SIG_Q_OP_DIST_SPAWN_REPLY: { cnt += handle_dist_spawn_reply_exiting(c_p, sig, pe_ctxt_p); @@ -6016,23 +6645,31 @@ erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, case ERTS_SIG_Q_OP_ADJ_MSGQ: switch (ERTS_PROC_SIG_TYPE(tag)) { case ERTS_SIG_Q_TYPE_CLA: - handle_cla(c_p, sig, next_nm_sig, !0); + handle_cla(c_p, sig, next_nm_sig, !0, limit, NULL); break; case ERTS_SIG_Q_TYPE_OFF_HEAP: - handle_move_msgq_off_heap(c_p, sig, next_nm_sig, !0); + handle_move_msgq_off_heap(c_p, sig, next_nm_sig, !0, + limit, NULL); break; default: - ERTS_INTERNAL_ERROR("Invalid 'adjust-message-queue' signal type"); + ERTS_INTERNAL_ERROR("Invalid adjust-message-queue signal type"); break; } break; + case ERTS_SIG_Q_OP_FLUSH: + ASSERT(c_p->sig_qs.flags & FS_FLUSHING_SIGS); + c_p->sig_qs.flags |= FS_FLUSHED_SIGS; + erts_free(ERTS_ALC_T_SIG_DATA, sig); + break; + case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: destroy_trace_info((ErtsSigTraceInfo *) sig); break; case ERTS_SIG_Q_OP_RECV_MARK: { ErtsRecvMarker *markp = (ErtsRecvMarker *) sig; + ASSERT(!markp->is_yield_mark); markp->in_msgq = markp->in_sigq = markp->set_save = 0; recv_marker_deallocate(c_p, markp); break; @@ -6043,7 +6680,7 @@ erts_proc_sig_handle_exit(Process *c_p, Sint *redsp, break; } - } while (cnt >= limit && *next_nm_sig); + } while (cnt <= limit && !yield && *next_nm_sig); *redsp += cnt / ERTS_SIG_REDS_CNT_FACTOR; @@ -6125,6 +6762,7 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_SIG_Q_OP_RPC: case ERTS_SIG_Q_OP_RECV_MARK: case ERTS_SIG_Q_OP_ADJ_MSGQ: + case ERTS_SIG_Q_OP_FLUSH: break; default: @@ -6137,8 +6775,33 @@ clear_seq_trace_token(ErtsMessage *sig) void erts_proc_sig_clear_seq_trace_tokens(Process *c_p) { - erts_proc_sig_fetch(c_p); - ERTS_FOREACH_SIG_PRIVQS(c_p, sig, clear_seq_trace_token(sig)); + int ix; + ErtsSignalInQueueBufferArray *bap; + int unget_info; + ErtsMessage *qs[] = {c_p->sig_qs.first, + c_p->sig_qs.cont, + c_p->sig_inq.first}; + + ERTS_LC_ASSERT(erts_thr_progress_is_blocking()); + + for (ix = 0; ix < sizeof(qs)/sizeof(qs[0]); ix++) { + ErtsMessage *sigp; + for (sigp = qs[ix]; sigp; sigp = sigp->next) + clear_seq_trace_token(sigp); + } + + bap = erts_proc_sig_queue_get_buffers(c_p, &unget_info); + if (bap) { + for (ix = 0; ix < ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; ix++) { + ErtsSignalInQueueBuffer* bp = &bap->slots[ix]; + if (bp->b.alive) { + ErtsMessage *sigp; + for (sigp = bp->b.queue.first; sigp; sigp = sigp->next) + clear_seq_trace_token(sigp); + } + } + erts_proc_sig_queue_unget_buffers(bap, unget_info); + } } Uint @@ -6186,11 +6849,6 @@ erts_proc_sig_signal_size(ErtsSignal *sig) break; case ERTS_SIG_Q_OP_ADJ_MSGQ: - if (type == ERTS_SIG_Q_TYPE_OFF_HEAP) { - size = sizeof(ErtsMessageRef); - break; - } - /* Fall through... */ case ERTS_SIG_Q_OP_SYNC_SUSPEND: case ERTS_SIG_Q_OP_PERSISTENT_MON_MSG: case ERTS_SIG_Q_OP_IS_ALIVE: @@ -6265,6 +6923,10 @@ erts_proc_sig_signal_size(ErtsSignal *sig) break; } + case ERTS_SIG_Q_OP_FLUSH: + size = sizeof(ErtsSignalCommon); + break; + case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: size = sizeof(ErtsSigTraceInfo); break; @@ -6338,7 +7000,7 @@ erts_proc_sig_receive_helper(Process *c_p, consumed_reds += 4; left_reds -= 4; - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); /* * Messages may have been moved directly to @@ -6383,6 +7045,7 @@ erts_proc_sig_receive_helper(Process *c_p, if (max_reds < reds) max_reds = reds; #endif + state = erts_atomic32_read_nob(&c_p->state); (void) erts_proc_sig_handle_incoming(c_p, &state, &reds, max_reds, !0); consumed_reds += reds; @@ -6421,7 +7084,6 @@ erts_proc_sig_receive_helper(Process *c_p, if (left_reds <= 0) break; /* yield */ - ASSERT(!c_p->sig_qs.cont); /* Go fetch again... */ } @@ -6434,6 +7096,127 @@ erts_proc_sig_receive_helper(Process *c_p, return consumed_reds; } +static void +init_yield_marker(Process *c_p, ErtsRecvMarker *mrkp) +{ + mrkp->prev_next = NULL; + mrkp->is_yield_mark = (char) !0; + mrkp->pass = (char) 100; + mrkp->set_save = (char) 0; + mrkp->in_sigq = (char) 0; + mrkp->in_msgq = (char) 0; + mrkp->prev_ix = (char) -100; + mrkp->next_ix = (char) -100; +#ifdef DEBUG + mrkp->used = (char) !0; + mrkp->proc = c_p; +#endif + mrkp->sig.common.next = NULL; + mrkp->sig.common.specific.attachment = NULL; + mrkp->sig.common.tag = ERTS_RECV_MARKER_TAG; +} + +static void +remove_yield_marker(Process *c_p, ErtsRecvMarker *mrkp) +{ + ASSERT(mrkp); + ASSERT(mrkp->is_yield_mark); + ASSERT(mrkp->in_msgq); + remove_iq_sig(c_p, (ErtsMessage *) mrkp, mrkp->prev_next); + mrkp->in_msgq = 0; + mrkp->in_sigq = 0; + mrkp->prev_next = NULL; + mrkp->sig.common.next = NULL; +} + +static ErtsYieldAdjMsgQ * +create_yield_adj_msgq_data(Process *c_p) +{ + ErtsYieldAdjMsgQ *yp = erts_alloc(ERTS_ALC_T_SIG_YIELD_DATA, + sizeof(ErtsYieldAdjMsgQ)); + init_yield_marker(c_p, &yp->next); + init_yield_marker(c_p, &yp->last); + return yp; +} + +static ERTS_INLINE void +insert_adj_msgq_yield_markers(Process *c_p, + ErtsYieldAdjMsgQ *yp, + ErtsMessage **nextpp, + ErtsMessage ***next_nm_sig, + ErtsSavedNMSignals *saved_sigs) +{ + ErtsMessage *sig, *nextp; + + ASSERT(yp); + ASSERT(nextpp); + ASSERT(next_nm_sig && *next_nm_sig && **next_nm_sig); + ASSERT(!yp->next.in_msgq); + + sig = **next_nm_sig; + + ASSERT(ERTS_PROC_SIG_OP(ERL_MESSAGE_TERM(sig)) + == ERTS_SIG_Q_OP_ADJ_MSGQ); + + /* + * Insert 'next' yield marker. This is in the inner queue or + * in the beginning of the middle queue where we've already + * begun using 'prev_next' pointers for receive markers, + * so if a receive marker follow, we need to update it. + */ + yp->next.in_msgq = !0; + yp->next.in_sigq = !0; + yp->next.prev_next = nextpp; + yp->next.sig.common.next = nextp = *nextpp; + *nextpp = (ErtsMessage *) &yp->next; + + ERTS_SIG_DBG_RECV_MARK_SET_HANDLED(&yp->next); + + if (nextp && ERTS_SIG_IS_RECV_MARKER(nextp)) { + ErtsRecvMarker *next_mrkp = (ErtsRecvMarker *) nextp; + next_mrkp->prev_next = &yp->next.sig.common.next; + } + + if (yp->last.in_msgq) { + remove_nm_sig(c_p, sig, next_nm_sig); + } + else { + /* + * Replace adj-msgq signal with 'last' yield marker. + * + * This is in the middle queue after the point where + * we've begun using 'prev_next' pointers for receive + * markers, so if a receive marker follow, we do not + * need to adjust its 'prev_next'. + */ + ErtsMessage **next_sig = *next_nm_sig; + yp->last.in_msgq = (char) !0; + yp->last.in_sigq = (char) !0; + yp->last.prev_next = next_sig; + *next_nm_sig = ((ErtsSignal *) sig)->common.specific.next; + *next_sig = (ErtsMessage *) &yp->last; + remove_mq_sig(c_p, sig, &yp->last.sig.common.next, next_nm_sig); + + ERTS_SIG_DBG_RECV_MARK_SET_HANDLED(&yp->last); + } + + save_delayed_nm_signal(saved_sigs, sig); +} + +static ERTS_INLINE void +destroy_adj_msgq_yield_markers(Process *c_p, ErtsYieldAdjMsgQ **ypp) +{ + ErtsYieldAdjMsgQ *yp = *ypp; + if (yp) { + if (yp->next.in_msgq) + remove_yield_marker(c_p, &yp->next); + if (yp->last.in_msgq) + remove_yield_marker(c_p, &yp->last); + erts_free(ERTS_ALC_T_SIG_YIELD_DATA, yp); + *ypp = NULL; + } +} + static Uint area_literal_size(Eterm* start, Eterm* end, char* lit_start, Uint lit_size) { @@ -6555,17 +7338,16 @@ static int handle_cla(Process *c_p, ErtsMessage *sig, ErtsMessage ***next_nm_sig, - int exiting) + int exiting, + int limit, + ErtsSavedNMSignals *saved_nm_sigs) { - /* - * TODO: Implement yielding support! - */ ErtsCLAData *cla; - ErtsMessage *msg; + ErtsMessage *msg, *endp; ErtsLiteralArea *la; char *literals; Uint lit_bsize; - int nmsgs, reds; + int nmsgs, reds, stretch_yield_limit = 0; Eterm result = am_ok; Uint64 cnt = 0; @@ -6586,6 +7368,30 @@ handle_cla(Process *c_p, * can therefore occur behind this signal. */ + msg = c_p->sig_qs.first; + if (!msg) + msg = c_p->sig_qs.cont; + + if (!cla->yield) { + endp = sig; + } + else { + if (!cla->yield->next.in_msgq) { + /* All messages already handled... */ + ASSERT(!cla->yield->last.in_msgq); + stretch_yield_limit = !0; + endp = msg = sig; + } + else { + ASSERT(!!cla->yield->last.in_msgq); + msg = cla->yield->next.sig.common.next; + endp = (ErtsMessage *) &cla->yield->last; + remove_yield_marker(c_p, &cla->yield->next); + } + } + + ASSERT(!cla->yield || !cla->yield->next.in_msgq); + la = ERTS_COPY_LITERAL_AREA(); if (!la) { ASSERT(0); @@ -6598,12 +7404,8 @@ handle_cla(Process *c_p, literals = (char *) &la->start[0]; lit_bsize = (char *) la->end - literals; - msg = c_p->sig_qs.first; - if (!msg) - msg = c_p->sig_qs.cont; - nmsgs = 0; - while (msg != sig) { + while (msg != endp) { ASSERT(!!msg); nmsgs++; if (nmsgs >= ERTS_PROC_SIG_ADJ_MSGQ_MSGS_FACTOR) { @@ -6618,7 +7420,7 @@ handle_cla(Process *c_p, /* * If a literal to copy is found in the message, we make * an explicit copy of it in a heap fragment and attach - * that heap fragment to the messag. Each message needs + * that heap fragment to the message. Each message needs * to be self contained, we cannot save the literal at * any other place than in the message itself. */ @@ -6698,6 +7500,18 @@ handle_cla(Process *c_p, } } + if (cnt > limit) { /* yield... */ + ErtsMessage **nextpp = !msg->next ? &c_p->sig_qs.cont : &msg->next; + ASSERT(*nextpp); + if (*nextpp == endp) + break; /* we're at the end; no point yielding here... */ + if (!cla->yield) + cla->yield = create_yield_adj_msgq_data(c_p); + insert_adj_msgq_yield_markers(c_p, cla->yield, nextpp, + next_nm_sig, saved_nm_sigs); + return cnt; + } + msg = msg->next; if (!msg) msg = c_p->sig_qs.cont; @@ -6705,18 +7519,36 @@ handle_cla(Process *c_p, remove_nm_sig(c_p, sig, next_nm_sig); - reds = 0; - if (erts_check_copy_literals_gc_need(c_p, &reds, literals, lit_bsize)) - result = am_need_gc; - - cnt += reds * ERTS_SIG_REDS_CNT_FACTOR; + reds = erts_check_copy_literals_gc_need_max_reds(c_p); + cnt++; + if (reds > CONTEXT_REDS) + result = am_check_gc; + else if (stretch_yield_limit + || cnt + reds*ERTS_SIG_REDS_CNT_FACTOR <= limit) { + reds = 0; + if (erts_check_copy_literals_gc_need(c_p, &reds, literals, lit_bsize)) + result = am_need_gc; + cnt += reds * ERTS_SIG_REDS_CNT_FACTOR; + } + else { + /* yield... */ + if (!cla->yield) + cla->yield = create_yield_adj_msgq_data(c_p); + else if (!!cla->yield->last.in_msgq) + remove_yield_marker(c_p, &cla->yield->last); + ASSERT(!cla->yield->next.in_msgq); + save_delayed_nm_signal(saved_nm_sigs, sig); + return cnt; + } done: + destroy_adj_msgq_yield_markers(c_p, &cla->yield); + send_cla_reply(c_p, sig, cla->requester, cla->request_id, result); - if (cnt > CONTEXT_REDS) - return CONTEXT_REDS; + if (cnt > CONTEXT_REDS*ERTS_SIG_REDS_CNT_FACTOR) + return CONTEXT_REDS*ERTS_SIG_REDS_CNT_FACTOR; return cnt; } @@ -6724,12 +7556,12 @@ static int handle_move_msgq_off_heap(Process *c_p, ErtsMessage *sig, ErtsMessage ***next_nm_sig, - int exiting) + int exiting, + int limit, + ErtsSavedNMSignals *saved_nm_sigs) { - /* - * TODO: Implement yielding support! - */ - ErtsMessage *msg; + ErtsAdjOffHeapMsgQData *ohdp; + ErtsMessage *msg, *endp; int nmsgs; Uint64 cnt = 0; @@ -6749,6 +7581,8 @@ handle_move_msgq_off_heap(Process *c_p, cnt++; + ohdp = get_move_msgq_off_heap_data(sig); + if (exiting) { /* signal already removed from queue... */ goto cleanup; @@ -6769,8 +7603,21 @@ handle_move_msgq_off_heap(Process *c_p, if (!msg) msg = c_p->sig_qs.cont; + if (!ohdp->yield) { + endp = sig; + } + else { + ASSERT(!!ohdp->yield->next.in_msgq); + ASSERT(!!ohdp->yield->last.in_msgq); + msg = ohdp->yield->next.sig.common.next; + endp = (ErtsMessage *) &ohdp->yield->last; + remove_yield_marker(c_p, &ohdp->yield->next); + } + + ASSERT(!ohdp->yield || !ohdp->yield->next.in_msgq); + nmsgs = 0; - while (msg != sig) { + while (msg != endp) { ASSERT(!!msg); nmsgs++; if (nmsgs >= ERTS_PROC_SIG_ADJ_MSGQ_MSGS_FACTOR) { @@ -6847,6 +7694,18 @@ handle_move_msgq_off_heap(Process *c_p, cnt += h_sz/ERTS_PROC_SIG_ADJ_MSGQ_COPY_FACTOR; } + if (cnt > limit) { /* yield... */ + ErtsMessage **nextpp = !msg->next ? &c_p->sig_qs.cont : &msg->next; + ASSERT(*nextpp); + if (*nextpp == endp) + break; /* we're at the end; no point yielding... */ + if (!ohdp->yield) + ohdp->yield = create_yield_adj_msgq_data(c_p); + insert_adj_msgq_yield_markers(c_p, ohdp->yield, nextpp, + next_nm_sig, saved_nm_sigs); + return cnt; + } + msg = msg->next; if (!msg) msg = c_p->sig_qs.cont; @@ -6858,13 +7717,15 @@ handle_move_msgq_off_heap(Process *c_p, cleanup: + destroy_adj_msgq_yield_markers(c_p, &ohdp->yield); sig->next = NULL; + sig->data.attached = ERTS_MSG_COMBINED_HFRAG; erts_cleanup_messages(sig); c_p->sig_qs.flags &= ~FS_OFF_HEAP_MSGQ_CHNG; - if (cnt > CONTEXT_REDS) - return CONTEXT_REDS; + if (cnt > CONTEXT_REDS*ERTS_SIG_REDS_CNT_FACTOR) + return CONTEXT_REDS*ERTS_SIG_REDS_CNT_FACTOR; return cnt; } @@ -7092,7 +7953,8 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, ErtsProcLocks rp_locks, int info_on_self, - ErtsMessageInfo *mip) + ErtsMessageInfo *mip, + Sint *msgq_len_p) { Uint tot_heap_size; ErtsMessage *mp, **mpp; @@ -7166,7 +8028,11 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, mp = mp->next; } - ASSERT(c_p->sig_qs.len == i); + + ASSERT(info_on_self || c_p->sig_qs.len == i); + ASSERT(!info_on_self || c_p->sig_qs.len >= i); + + *msgq_len_p = i; return tot_heap_size; } @@ -7231,7 +8097,7 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1) if (!rp) BIF_RET(am_noproc); - state = erts_atomic32_read_nob(&rp->state); + state = erts_atomic32_read_acqb(&rp->state); dirty = (state & ERTS_PSFLG_DIRTY_RUNNING); /* * Ignore ERTS_PSFLG_DIRTY_RUNNING_SYS (see @@ -7241,6 +8107,12 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1) if (!dirty) BIF_RET(am_normal); + if (!(state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q))) { + BIF_RET(am_ok); + } + busy = erts_proc_trylock(rp, ERTS_PROC_LOCK_MAIN) == EBUSY; state = erts_atomic32_read_mb(&rp->state); @@ -7255,7 +8127,6 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1) BIF_RET(am_normal); /* will handle signals itself... */ } else { - erts_aint32_t state; int done; Eterm res = am_false; int reds = 0; @@ -7301,9 +8172,13 @@ erts_proc_sig_cleanup_queues(Process *c_p) while (sig) { ErtsMessage *free_sig = sig; sig = sig->next; - if (ERTS_SIG_IS_RECV_MARKER(free_sig)) - recv_marker_deallocate(c_p, (ErtsRecvMarker *) free_sig); + if (ERTS_SIG_IS_RECV_MARKER(free_sig)) { + ErtsRecvMarker *recv_mark = (ErtsRecvMarker *) free_sig; + ASSERT(!recv_mark->is_yield_mark); + recv_marker_deallocate(c_p, recv_mark); + } else { + ASSERT(ERTS_SIG_IS_MSG(free_sig)); free_sig->next = NULL; erts_cleanup_messages(free_sig); } @@ -7506,14 +8381,24 @@ erts_proc_sig_debug_foreach_sig(Process *c_p, break; case ERTS_SIG_Q_OP_ADJ_MSGQ: - if (type == ERTS_SIG_Q_TYPE_OFF_HEAP) - break; - /* Fall through... */ case ERTS_SIG_Q_OP_PERSISTENT_MON_MSG: - case ERTS_SIG_Q_OP_ALIAS_MSG: debug_foreach_sig_heap_frags(&sig->hfrag, oh_func, arg); break; + case ERTS_SIG_Q_OP_ALIAS_MSG: { + void *attached; + ErlHeapFragment *hfp; + (void) get_alias_msg_data(sig, NULL, NULL, NULL, &attached); + if (!attached) + break; + if (attached == ERTS_MSG_COMBINED_HFRAG) + hfp = &sig->hfrag; + else + hfp = (ErlHeapFragment *) attached; + debug_foreach_sig_heap_frags(hfp, oh_func, arg); + break; + } + case ERTS_SIG_Q_OP_DEMONITOR: if (type == ERTS_SIG_Q_TYPE_DIST_PROC_DEMONITOR) { debug_foreach_sig_fake_oh(((ErtsSigDistProcDemonitor *) sig)->ref, @@ -7551,6 +8436,7 @@ erts_proc_sig_debug_foreach_sig(Process *c_p, case ERTS_SIG_Q_OP_PROCESS_INFO: case ERTS_SIG_Q_OP_RECV_MARK: case ERTS_SIG_Q_OP_MSGQ_LEN_OFFS_MARK: + case ERTS_SIG_Q_OP_FLUSH: break; default: @@ -7689,7 +8575,8 @@ proc_sig_hdbg_check_queue(Process *proc, ErtsMessage **sig_nm_last, ErtsSigRecvTracing *tracing, int *found_set_save_recv_marker_p, - erts_aint32_t sig_psflg) + erts_aint32_t nmsig_psflg, + erts_aint32_t msig_psflg) { ErtsMessage **next, *sig, **nm_next, **nm_last; int last_nm_sig_found, nm_sigs = 0, found_next_trace = 0, @@ -7721,7 +8608,7 @@ proc_sig_hdbg_check_queue(Process *proc, ErtsSignal *nm_sig; if (next == sig_last) { - ASSERT(!*next); + ERTS_ASSERT(!*next); last_sig_found = 1; } @@ -7740,7 +8627,7 @@ proc_sig_hdbg_check_queue(Process *proc, if (ERTS_SIG_IS_RECV_MARKER(sig)) { ErtsRecvMarker *markp = (ErtsRecvMarker *) sig; recv_marker++; - ASSERT(!markp->set_save); + ERTS_ASSERT(!markp->set_save); ERTS_ASSERT(next == markp->prev_next); } else { @@ -7757,7 +8644,7 @@ proc_sig_hdbg_check_queue(Process *proc, sig = sig->next; if (next == sig_last) { - ASSERT(!*next); + ERTS_ASSERT(!*next); last_sig_found = 1; } @@ -7802,7 +8689,7 @@ proc_sig_hdbg_check_queue(Process *proc, ERTS_ASSERT(nm_next == next); if (nm_last == next) { - ASSERT(!nm_sig->common.specific.next); + ERTS_ASSERT(!nm_sig->common.specific.next); last_nm_sig_found = 1; } @@ -7838,9 +8725,19 @@ proc_sig_hdbg_check_queue(Process *proc, ERTS_ASSERT(last_nm_sig_found); ERTS_ASSERT(last_sig_found); - if (sig_psflg != ERTS_PSFLG_FREE) { + if (nmsig_psflg|msig_psflg) { erts_aint32_t state = erts_atomic32_read_nob(&proc->state); - ERTS_ASSERT(nm_sigs ? !!(state & sig_psflg) : !(state & sig_psflg)); + int using_buffers = !!erts_atomic_read_nob(&proc->sig_inq_buffers); + if (nmsig_psflg) { + ERTS_ASSERT(nm_sigs + ? !!(state & nmsig_psflg) + : (!(state & nmsig_psflg) || using_buffers)); + } + if (msig_psflg) { + ERTS_ASSERT(msg_len + ? !!(state & msig_psflg) + : (!(state & msig_psflg) || using_buffers)); + } } return msg_len; @@ -7865,7 +8762,8 @@ erts_proc_sig_hdbg_check_priv_queue(Process *p, int qlock, char *what, char *fil NULL, NULL, &found_set_save_recv_marker, - ERTS_PSFLG_FREE); + 0, + 0); len2 = proc_sig_hdbg_check_queue(p, 1, &p->sig_qs.cont, @@ -7874,7 +8772,8 @@ erts_proc_sig_hdbg_check_priv_queue(Process *p, int qlock, char *what, char *fil p->sig_qs.nmsigs.last, NULL, &found_set_save_recv_marker, - ERTS_PSFLG_SIG_Q); + ERTS_PSFLG_SIG_Q, + 0); ERTS_ASSERT(found_set_save_recv_marker == 1 || found_set_save_recv_marker == 0); ERTS_ASSERT(found_set_save_recv_marker || !blkp || blkp->pending_set_save_ix < 0); @@ -7884,13 +8783,25 @@ erts_proc_sig_hdbg_check_priv_queue(Process *p, int qlock, char *what, char *fil } void -erts_proc_sig_hdbg_check_in_queue(Process *p, char *what, char *file, int line) +erts_proc_sig_hdbg_check_in_queue(Process *p, struct ErtsSignalInQueue_ *buffer, + char *what, char *file, int line) { Sint len; - ERTS_LC_ASSERT(erts_thr_progress_is_blocking() + int nmsig_flag, msig_flag; + ERTS_LC_ASSERT(&p->sig_inq != buffer + || erts_thr_progress_is_blocking() || ERTS_PROC_IS_EXITING(p) || (ERTS_PROC_LOCK_MSGQ & erts_proc_lc_my_proc_locks(p))); + if (buffer != &p->sig_inq) { + nmsig_flag = 0; + msig_flag = 0; + } + else { + nmsig_flag = ERTS_PSFLG_NMSG_SIG_IN_Q; + msig_flag = ERTS_PSFLG_MSG_SIG_IN_Q; + } + len = proc_sig_hdbg_check_queue(p, 0, &p->sig_inq.first, @@ -7899,8 +8810,474 @@ erts_proc_sig_hdbg_check_in_queue(Process *p, char *what, char *file, int line) p->sig_inq.nmsigs.last, NULL, NULL, - ERTS_PSFLG_SIG_IN_Q); - ASSERT(p->sig_inq.len == len); (void)len; + nmsig_flag, + msig_flag); + ERTS_ASSERT(p->sig_inq.len == len); (void)len; } #endif /* ERTS_PROC_SIG_HARD_DEBUG */ + +void erts_proc_sig_queue_lock(Process* proc) +{ + if (EBUSY == erts_proc_trylock(proc, ERTS_PROC_LOCK_MSGQ)) { + erts_proc_lock(proc, ERTS_PROC_LOCK_MSGQ); + proc->sig_inq_contention_counter += 1; + } else if(proc->sig_inq_contention_counter > 0) { + proc->sig_inq_contention_counter -= 1; + } +} + +static void proc_sig_queue_lock_buffer(ErtsSignalInQueueBuffer* slot) +{ + erts_mtx_lock(&slot->b.lock); +} + +static void proc_sig_queue_unlock_buffer(ErtsSignalInQueueBuffer* slot) +{ + erts_mtx_unlock(&slot->b.lock); +} + +int +erts_proc_sig_queue_try_enqueue_to_buffer(Eterm from, + Process* receiver, + ErtsProcLocks receiver_locks, + ErtsMessage* first, + ErtsMessage** last, + ErtsMessage** last_next, + Uint len) +{ + int need_unget_buffers; + ErtsSignalInQueueBufferArray* buffers; + if ((receiver_locks & ERTS_PROC_LOCK_MSGQ) || + NULL == (buffers = erts_proc_sig_queue_get_buffers(receiver, &need_unget_buffers))) { + /* We never need to unget the buffers array if we do not get it */ + return 0; + } else { + int nonmsg = ERTS_SIG_IS_NON_MSG(first); + ErtsSignalInQueueBuffer* buffer; + Uint64 nonempty_slots_before; + Uint32 slot, state; + + ASSERT(is_value(from)); + + /* Use the sender id to hash to an outer signal queue buffer. This + * guarantees that all signals from the same process are ordered in + * send order. */ + slot = make_internal_hash(from, 0) % + ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; + buffer = &buffers->slots[slot]; + + proc_sig_queue_lock_buffer(buffer); + + if ( ! buffer->b.alive ) { + /* + * The enqueue attempt fails if the buffer is dead. This + * means that the buffer array has got uninstalled. + */ + proc_sig_queue_unlock_buffer(buffer); + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers); + return 0; + } + + /* + * The buffer is alive and locked. This means that it is safe + * to insert signals to it + */ + + while (!0) { + /* + * This loop body is only executed more than once if another + * thread is currently flushing buffers at the same time as + * this operation is performed. The restart of the loop + * prevents info in 'msgs_in_slots' and 'nonmsgs_in_slots' + * from being lost. The loop can at most be restarted twice + * since we have the lock on the buffer. Restarting twice is, + * however, extremely unlikely to happen... + */ + + if (len && !erts_atomic32_read_nob(&buffers->msgs_in_slots)) { + erts_atomic32_set_nob(&buffers->msgs_in_slots, !0); + } + + if (nonmsg && !erts_atomic32_read_nob(&buffers->nonmsgs_in_slots)) { + erts_atomic32_set_nob(&buffers->nonmsgs_in_slots, !0); + } + + if (&buffer->b.queue.first == buffer->b.queue.last) { + /* The buffer is empty so we need to notify the receiver + * unless some other slot is nonempty (in that case + * another enqueuer has already (or will) notified the + * receiver). + */ + nonempty_slots_before = + (Uint64)erts_atomic64_read_bor_mb(&buffers->nonempty_slots, + (erts_aint64_t)(((Uint64)1) << slot)); + } + else { + nonempty_slots_before = + (Uint64)erts_atomic64_read_mb(&buffers->nonempty_slots); + if (!(nonempty_slots_before & (((Uint64)1) << slot))) { + /* + * Someone is flushing buffers and has not yet handled + * this buffers. That is, it is no point in continuing + * with verification of 'msgs_in_slots' and + * 'nonmsgs_in_slots'. We only need this information + * while signals are in the buffer and we have not yet + * decided to fetch it. We know that it soon *will* be + * emptied by the flush operation. + */ + break; + } + } + + if (len) { + if (!erts_atomic32_read_nob(&buffers->msgs_in_slots)) + continue; /* restart loop */ + } + + if (nonmsg) { + if (!erts_atomic32_read_nob(&buffers->nonmsgs_in_slots)) + continue; /* restart loop */ + } + + break; + } + + state = erts_atomic32_read_nob(&receiver->state); + + state = enqueue_signals(!0, + receiver, + first, + last, + last_next, + len, + state, + &buffer->b.queue); + buffer->b.nr_of_enqueues += 1; + + proc_sig_queue_unlock_buffer(buffer); + + /* + * The signal(s) are inserted into a buffer. However, we are + * not done because we need to notify the scheduler about that + * we have new signals. + */ + + if (len && !nonempty_slots_before) { + + /* + * There is one situation in which we need to synchronize + * with the ERTS_PROC_LOCK_MSGQ lock: + * + * The buffer we inserted to was empty before we inserted + * to it, and no other buffer was marked as nonempty. In + * this case the process might hold the + * ERTS_PROC_LOCK_MSGQ to check if there are any more + * messages. If the process does not find any messages, + * it tells the scheduler to put the process to sleep + * while still holding the lock. Therefore, we wait until + * the ERTS_PROC_LOCK_MSGQ is released before we requests + * the scheduler to schedule the process (with a call to + * erts_proc_notify_new_message or + * erts_proc_notify_new_sig) so the request does not get + * overwritten by the sleep request. + * + */ + + erts_proc_lock_wait_until_released(receiver, ERTS_PROC_LOCK_MSGQ); + } + + if (nonmsg) { + erts_proc_notify_new_sig(receiver, state, + len ? ERTS_PSFLG_ACTIVE : 0); + } + else { + ASSERT(len); + erts_proc_notify_new_message(receiver, receiver_locks); + } + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers); + return 1; + } +} + + +static void sig_inq_concat(ErtsSignalInQueue* q1, ErtsSignalInQueue* q2) +{ + ErtsMessage** first_queue_last = q1->last; + /* Second queue should not be empty */ + ASSERT(q2->last != &q2->first); + if (NULL == q1->nmsigs.next) { + /* There is no non-message signals in q1 but maybe in q2 */ + if (q2->nmsigs.next != NULL) { + /* There is non-message signals in q2 but not in q1 */ + if (q2->nmsigs.next == &q2->first) { + /* The first message in q2 is a non-message signal + (The next pointer to the first non-message signal + comes from the first queue) */ + q1->nmsigs.next = first_queue_last; + } else { + /* Internal message in q2 is the first non-message signal */ + q1->nmsigs.next = q2->nmsigs.next; + } + if (q2->nmsigs.next == q2->nmsigs.last) { + /* Only one non-message signal in q2 (q1->nmsigs.last + should be the same as q1->nmsigs.next which is + already set up correctly) */ + q1->nmsigs.last = q1->nmsigs.next; + } else { + /* More than one non-message signals in q2 */ + q1->nmsigs.last = q2->nmsigs.last; + } + } + } else if (NULL != q2->nmsigs.next) { + ErtsMessage** first_nmsig_in_q2; + /* We have non-message signals in both queues */ + if (q2->nmsigs.next == &q2->first) { + /* The first signal in q2 is a non-message signal */ + ErtsSignal *sig; + sig = (ErtsSignal *) *q1->nmsigs.last; + sig->common.specific.next = first_queue_last; + first_nmsig_in_q2 = first_queue_last; + } else { + /* The first signal in q2 is a message signal */ + ErtsSignal *sig; + sig = (ErtsSignal *) *q1->nmsigs.last; + sig->common.specific.next = q2->nmsigs.next; + first_nmsig_in_q2 = q2->nmsigs.next; + } + if (q2->nmsigs.last == &q2->first) { + /* Only one non-message signal in q2 */ + q1->nmsigs.last = first_nmsig_in_q2; + } else { + q1->nmsigs.last = q2->nmsigs.last; + } + } + *q1->last = q2->first; + q1->last = q2->last; + q1->len += q2->len; + ASSERT((!q1->nmsigs.next && !q1->nmsigs.last) || (q1->nmsigs.next && q1->nmsigs.last)); +} + +static Uint proc_sig_queue_flush_buffer(Process* proc, + Uint buffer_index, + ErtsSignalInQueueBufferArray* buffers) +{ + Uint nr_of_enqueues; + ErtsSignalInQueueBuffer* buf = &buffers->slots[buffer_index]; + proc_sig_queue_lock_buffer(buf); + if (!buf->b.queue.first) { +#ifdef ERTS_PROC_SIG_HARD_DEBUG + if (buf->b.alive) { + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &buf->b.queue); + } +#endif + nr_of_enqueues = buf->b.nr_of_enqueues; + ASSERT(nr_of_enqueues == 0); + } + else { + nr_of_enqueues = buf->b.nr_of_enqueues; + buf->b.nr_of_enqueues = 0; + ASSERT(nr_of_enqueues > 0); + if (buf->b.alive) { + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &proc->sig_inq); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &buf->b.queue); + sig_inq_concat(&proc->sig_inq, &buf->b.queue); + buf->b.queue.first = NULL; + buf->b.queue.last = &buf->b.queue.first; + buf->b.queue.len = 0; + buf->b.queue.nmsigs.next = NULL; + buf->b.queue.nmsigs.last = NULL; + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &buf->b.queue); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &proc->sig_inq); + } + } + proc_sig_queue_unlock_buffer(buf); + return nr_of_enqueues; +} + + +static void proc_sig_queue_flush_buffers(Process *proc, ErtsSignalInQueueBufferArray *buffers) +{ + Uint i; + Uint64 nonempty_slots; + + ASSERT(buffers); + erts_atomic32_set_nob(&buffers->msgs_in_slots, 0); + erts_atomic32_set_nob(&buffers->nonmsgs_in_slots, 0); + nonempty_slots = (Uint64)erts_atomic64_xchg_mb(&buffers->nonempty_slots, + (erts_aint64_t)((Uint64)0)); + if (nonempty_slots != 0) { + for(i = 0; i < ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; i++) { + Uint64 slot_mask = (((Uint64)1) << i); + if (nonempty_slots & slot_mask) { + buffers->nr_of_enqueues += + proc_sig_queue_flush_buffer(proc, i, buffers); + } + } + } + if (--buffers->nr_of_rounds_left == 0) { + /* Take decision if we should adapt back to the normal state */ + if(buffers->nr_of_enqueues < + ERTS_PROC_SIG_INQ_BUFFERED_MIN_NO_ENQUEUES_TO_KEEP) { + erts_proc_sig_queue_flush_and_deinstall_buffers(proc); + } else { + buffers->nr_of_rounds_left = + ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE; + buffers->nr_of_enqueues = 0; + } + } +} + + +void +erts_proc_sig_queue_flush_buffers(Process* proc) +{ + ErtsSignalInQueueBufferArray* buffers; + int need_unget_buffers; + + ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc) || + (erts_proc_lc_my_proc_locks(proc) & ERTS_PROC_LOCK_MSGQ)); + + buffers = erts_proc_sig_queue_get_buffers(proc, &need_unget_buffers); + if (buffers) { + proc_sig_queue_flush_buffers(proc, buffers); + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers); + } +} + +static void sigq_buffer_array_refc_dec(void *buffers_p) +{ + ErtsSignalInQueueBufferArray* buffers = buffers_p; + erts_proc_sig_queue_unget_buffers(buffers, 1); +} + + +static void schedule_sigq_buffer_array_refc_dec(void *buffers_p) +{ + ErtsSignalInQueueBufferArray* buffers = buffers_p; + erts_schedule_thr_prgr_later_cleanup_op(sigq_buffer_array_refc_dec, + buffers, + &buffers->free_item, + sizeof(ErtsSignalInQueueBufferArray)); +} + +void erts_proc_sig_queue_flush_and_deinstall_buffers(Process* proc) +{ + Uint i; + ErtsSignalInQueueBufferArray* buffers; + int need_unget_buffers; + ErtsSchedulerData *esdp; + + ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc) || + (erts_proc_lc_my_proc_locks(proc) & ERTS_PROC_LOCK_MSGQ)); + buffers = erts_proc_sig_queue_get_buffers(proc, &need_unget_buffers); + + if (buffers == NULL) { + return; + } + + if (!buffers->alive) { + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers);; + return; + } + + buffers->alive = 0; + proc->sig_inq_contention_counter = 0; + + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &proc->sig_inq); + for (i = 0; i < ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; i++) { + proc_sig_queue_lock_buffer(&buffers->slots[i]); + + if (buffers->slots[i].b.queue.first != NULL) { + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &buffers->slots[i].b.queue); + sig_inq_concat(&proc->sig_inq, &buffers->slots[i].b.queue); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &proc->sig_inq); + } + + buffers->slots[i].b.alive = 0; + + proc_sig_queue_unlock_buffer(&buffers->slots[i]); + } + + /* Nothing can be enqueued to the buffer array beyond this point. */ + + erts_atomic32_set_nob(&buffers->nonmsgs_in_slots, 0); + erts_atomic32_set_nob(&buffers->msgs_in_slots, 0); + erts_atomic64_set_nob(&buffers->nonempty_slots, (erts_aint64_t)0); + erts_atomic_set_mb(&proc->sig_inq_buffers, (erts_aint_t)NULL); + + erts_proc_sig_queue_unget_buffers(buffers, need_unget_buffers); + + /* Release the buffer array through thread progress, as a managed thread + * may be holding a reference to it. */ + esdp = erts_get_scheduler_data(); + if (esdp != NULL && esdp->type == ERTS_SCHED_NORMAL) { + schedule_sigq_buffer_array_refc_dec((void*)buffers); + } else { + /* We can't issue cleanup jobs on anything other than normal + * schedulers, so we move to the first scheduler if required. */ + erts_schedule_misc_aux_work(1, + schedule_sigq_buffer_array_refc_dec, + buffers); + } +} + +void erts_proc_sig_queue_maybe_install_buffers(Process* p, erts_aint32_t state) +{ + int i; + ErtsSignalInQueueBufferArray* buffers; + if (!(state & ERTS_PSFLG_OFF_HEAP_MSGQ) || + (((ErtsSignalInQueueBufferArray*)erts_atomic_read_nob(&p->sig_inq_buffers)) != NULL) || + (!ERTS_PROC_SIG_INQ_BUFFERED_ALWAYS_TURN_ON && + p->sig_inq_contention_counter <= ERTS_PROC_SIG_INQ_BUFFERED_CONTENTION_INSTALL_LIMIT)) { + return; + } + p->sig_inq_contention_counter = 0; + buffers = erts_alloc(ERTS_ALC_T_SIGQ_BUFFERS, + sizeof(ErtsSignalInQueueBufferArray)); + erts_atomic64_init_nob(&buffers->nonempty_slots, (erts_aint64_t)(Uint64)0); + erts_atomic32_init_nob(&buffers->nonmsgs_in_slots, 0); + erts_atomic32_init_nob(&buffers->msgs_in_slots, 0); + erts_refc_init(&buffers->dirty_refc, 1); + buffers->nr_of_enqueues = 0; + buffers->nr_of_rounds_left = + ERTS_PROC_SIG_INQ_BUFFERED_MIN_FLUSH_ALL_OPS_BEFORE_CHANGE; + buffers->alive = 1; + /* Initialize slots */ + for(i = 0; i < ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; i++) { + buffers->slots[i].b.alive = 1; + erts_mtx_init(&buffers->slots[i].b.lock, + "proc_sig_queue_buffer", + NIL, + ERTS_LOCK_FLAGS_CATEGORY_PROCESS); + buffers->slots[i].b.queue.first = NULL; + buffers->slots[i].b.queue.last = &buffers->slots[i].b.queue.first; + buffers->slots[i].b.queue.len = 0; + buffers->slots[i].b.queue.nmsigs.next = NULL; + buffers->slots[i].b.queue.nmsigs.last = NULL; + buffers->slots[i].b.nr_of_enqueues = 0; + } + erts_atomic_set_relb(&p->sig_inq_buffers, (erts_aint_t)buffers); +} + +/* Only for test purposes */ +int erts_proc_sig_queue_force_buffers(Process* p) +{ + erts_aint32_t state; + ErtsSignalInQueueBufferArray* buffers; + + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + state = erts_atomic32_read_nob(&p->state); + /* Fake contention */ + p->sig_inq_contention_counter = + 1 + ERTS_PROC_SIG_INQ_BUFFERED_CONTENTION_INSTALL_LIMIT; + erts_proc_sig_queue_maybe_install_buffers(p, state); + buffers = ((ErtsSignalInQueueBufferArray*) + erts_atomic_read_nob(&p->sig_inq_buffers)); + if (buffers) { + /* "Prevent" buffer deinstallation */ + buffers->nr_of_rounds_left = ERTS_UINT_MAX; + } + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + return buffers != NULL; +} diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h index 2156990e4d12..663d42d59fad 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.h +++ b/erts/emulator/beam/erl_proc_sig_queue.h @@ -91,6 +91,9 @@ #if 0 # define ERTS_PROC_SIG_HARD_DEBUG_RECV_MARKER #endif +#if 0 +# define ERTS_PROC_SIG_HARD_DEBUG_SIGQ_BUFFERS +#endif struct erl_mesg; struct erl_dist_external; @@ -107,7 +110,7 @@ typedef struct { * Note that not all signal are handled using this functionality! */ -#define ERTS_SIG_Q_OP_MAX 18 +#define ERTS_SIG_Q_OP_MAX 19 #define ERTS_SIG_Q_OP_EXIT 0 /* Exit signal due to bif call */ #define ERTS_SIG_Q_OP_EXIT_LINKED 1 /* Exit signal due to link break*/ @@ -127,7 +130,8 @@ typedef struct { #define ERTS_SIG_Q_OP_ALIAS_MSG 15 #define ERTS_SIG_Q_OP_RECV_MARK 16 #define ERTS_SIG_Q_OP_UNLINK_ACK 17 -#define ERTS_SIG_Q_OP_ADJ_MSGQ ERTS_SIG_Q_OP_MAX +#define ERTS_SIG_Q_OP_ADJ_MSGQ 18 +#define ERTS_SIG_Q_OP_FLUSH ERTS_SIG_Q_OP_MAX #define ERTS_SIG_Q_TYPE_MAX (ERTS_MON_LNK_TYPE_MAX + 10) @@ -201,23 +205,25 @@ extern Eterm erts_old_recv_marker_id; #endif #ifdef ERTS_PROC_SIG_HARD_DEBUG -# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P) \ - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((P), "") +# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P, B) \ + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((P), (B), "") # define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P, QL) \ ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((P), (QL), "") -# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, What) \ - erts_proc_sig_hdbg_check_in_queue((P), (What), __FILE__, __LINE__) +# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, B , What) \ + erts_proc_sig_hdbg_check_in_queue((P), (B), (What), __FILE__, __LINE__) # define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, QL, What) \ erts_proc_sig_hdbg_check_priv_queue((P), (QL), (What), __FILE__, __LINE__) struct process; void erts_proc_sig_hdbg_check_priv_queue(struct process *c_p, int qlock, char *what, char *file, int line); -void erts_proc_sig_hdbg_check_in_queue(struct process *c_p, char *what, - char *file, int line); +struct ErtsSignalInQueue_; +void erts_proc_sig_hdbg_check_in_queue(struct process *c_p, + struct ErtsSignalInQueue_ *buffer, + char *what, char *file, int line); #else -# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P) +# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P, B) # define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P, QL) -# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, What) +# define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, B, What) #define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, QL, What) #endif @@ -238,6 +244,25 @@ void erl_proc_sig_hdbg_chk_recv_marker_block(struct process *c_p); #include "erl_process.h" #include "erl_bif_unique.h" + +void erts_proc_sig_queue_maybe_install_buffers(Process* p, erts_aint32_t state); +void erts_proc_sig_queue_flush_and_deinstall_buffers(Process* proc); +void erts_proc_sig_queue_flush_buffers(Process* proc); +void erts_proc_sig_queue_lock(Process* proc); +ERTS_GLB_INLINE ErtsSignalInQueueBufferArray* +erts_proc_sig_queue_get_buffers(Process* p, int *need_unread); +ERTS_GLB_INLINE void +erts_proc_sig_queue_unget_buffers(ErtsSignalInQueueBufferArray* buffers, + int need_unget); +int erts_proc_sig_queue_try_enqueue_to_buffer(Eterm from, + Process* receiver, + ErtsProcLocks receiver_locks, + ErtsMessage* first, + ErtsMessage** last, + ErtsMessage** last_next, + Uint len); +int erts_proc_sig_queue_force_buffers(Process*); + #define ERTS_SIG_Q_OP_BITS 8 #define ERTS_SIG_Q_OP_SHIFT 0 #define ERTS_SIG_Q_OP_MASK ((1 << ERTS_SIG_Q_OP_BITS) - 1) @@ -293,7 +318,9 @@ struct dist_entry_; #define ERTS_PROC_HAS_INCOMING_SIGNALS(P) \ (!!(erts_atomic32_read_nob(&(P)->state) \ - & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))) + & (ERTS_PSFLG_SIG_Q \ + | ERTS_PSFLG_NMSG_SIG_IN_Q \ + | ERTS_PSFLG_MSG_SIG_IN_Q))) /* * Send operations of currently supported process signals follow... @@ -304,8 +331,10 @@ struct dist_entry_; * @brief Send an exit signal to a process. * * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] from Identifier of sender. * @@ -322,7 +351,7 @@ struct dist_entry_; * */ void -erts_proc_sig_send_exit(Process *c_p, Eterm from, Eterm to, +erts_proc_sig_send_exit(ErtsPTabElementCommon *sender, Eterm from, Eterm to, Eterm reason, Eterm token, int normal_kills); /** @@ -357,13 +386,28 @@ erts_proc_sig_send_dist_exit(DistEntry *dep, ErlHeapFragment *hfrag, Eterm reason, Eterm token); +/** + * + * @brief Send an exit signal due to a link to a process being + * broken by connection loss. + * + * @param[in] lnk Pointer to link structure + * from the sending side. It + * should contain information + * about receiver. + */ +void +erts_proc_sig_send_link_exit_noconnection(ErtsLink *lnk); + /** * * @brief Send an exit signal due to broken link to a process. * * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] from Identifier of sender. * @@ -378,16 +422,18 @@ erts_proc_sig_send_dist_exit(DistEntry *dep, * */ void -erts_proc_sig_send_link_exit(Process *c_p, Eterm from, ErtsLink *lnk, - Eterm reason, Eterm token); +erts_proc_sig_send_link_exit(ErtsPTabElementCommon *sender, Eterm from, + ErtsLink *lnk, Eterm reason, Eterm token); /** * * @brief Send an link signal to a process. * * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] to Identifier of receiver. * @@ -405,7 +451,8 @@ erts_proc_sig_send_link_exit(Process *c_p, Eterm from, ErtsLink *lnk, * */ int -erts_proc_sig_send_link(Process *c_p, Eterm to, ErtsLink *lnk); +erts_proc_sig_send_link(ErtsPTabElementCommon *sender, Eterm from, + Eterm to, ErtsLink *lnk); /** * @@ -414,15 +461,15 @@ erts_proc_sig_send_link(Process *c_p, Eterm to, ErtsLink *lnk); * The newly created unlink identifier is to be used in an * unlink operation. * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * @param[in] sender Pointer to the sending process/port. * * @return A new 64-bit unlink identifier * unique in context of the * calling process. The identifier * may be any value but zero. */ -ERTS_GLB_INLINE Uint64 erts_proc_sig_new_unlink_id(Process *c_p); +ERTS_GLB_INLINE +Uint64 erts_proc_sig_new_unlink_id(ErtsPTabElementCommon *sender); /** * @@ -431,13 +478,10 @@ ERTS_GLB_INLINE Uint64 erts_proc_sig_new_unlink_id(Process *c_p); * The structure will contain a newly created unlink * identifier to be used in the operation. * - * @param[in] c_p Pointer to process struct of - * currently executing process - * ('from' is a process - * identifier), or NULL if not - * called in the context of an - * executing process ('from' is - * a port identifier). + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] from Id (as an erlang term) of * entity sending the unlink @@ -447,7 +491,7 @@ ERTS_GLB_INLINE Uint64 erts_proc_sig_new_unlink_id(Process *c_p); * structure. */ ErtsSigUnlinkOp * -erts_proc_sig_make_unlink_op(Process *c_p, Eterm from); +erts_proc_sig_make_unlink_op(ErtsPTabElementCommon *sender, Eterm from); /** * @@ -464,8 +508,10 @@ erts_proc_sig_destroy_unlink_op(ErtsSigUnlinkOp *sulnk); * @brief Send an unlink signal to a process. * * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] from Id (as an erlang term) of * entity sending the unlink @@ -477,15 +523,18 @@ erts_proc_sig_destroy_unlink_op(ErtsSigUnlinkOp *sulnk); * receiver. */ Uint64 -erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk); +erts_proc_sig_send_unlink(ErtsPTabElementCommon *sender, Eterm from, + ErtsLink *lnk); /** * * @brief Send an unlink acknowledgment signal to a process. * - * - * @param[in] c_p Pointer to process struct of - * currently executing process. + * + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * * @param[in] from Id (as an erlang term) of * entity sending the unlink @@ -498,7 +547,7 @@ erts_proc_sig_send_unlink(Process *c_p, Eterm from, ErtsLink *lnk); * signal. */ void -erts_proc_sig_send_unlink_ack(Process *c_p, Eterm from, +erts_proc_sig_send_unlink_ack(ErtsPTabElementCommon *sender, Eterm from, ErtsSigUnlinkOp *sulnk); /** @@ -560,11 +609,6 @@ erts_proc_sig_send_dist_unlink(DistEntry *dep, Uint32 conn_id, * This function is used instead of erts_proc_sig_send_unlink_ack() * when the signal arrives via the distribution. * - * @param[in] c_p Pointer to process struct of - * currently executing process or - * NULL if not called in the context - * of an executing process. - * * @param[in] dep Distribution entry of channel * that the signal arrived on. * @@ -575,7 +619,7 @@ erts_proc_sig_send_dist_unlink(DistEntry *dep, Uint32 conn_id, * @param[in] id Identifier of unlink operation. */ void -erts_proc_sig_send_dist_unlink_ack(Process *c_p, DistEntry *dep, +erts_proc_sig_send_dist_unlink_ack(DistEntry *dep, Uint32 conn_id, Eterm from, Eterm to, Uint64 id); @@ -583,6 +627,14 @@ erts_proc_sig_send_dist_unlink_ack(Process *c_p, DistEntry *dep, * * @brief Send a monitor down signal to a process. * + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). + * + * @param[in] from Sending entity, must be provided + * to maintain signal order. + * * @param[in] mon Pointer to target monitor * structure from the sending * side. It should contain @@ -592,27 +644,48 @@ erts_proc_sig_send_dist_unlink_ack(Process *c_p, DistEntry *dep, * */ void -erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason); +erts_proc_sig_send_monitor_down(ErtsPTabElementCommon *sender, Eterm from, + ErtsMonitor *mon, Eterm reason); /** * * @brief Send a demonitor signal to a process. * - * @param[in] mon Pointer to origin monitor - * structure from the sending - * side. It should contain - * information about receiver. + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). * - * @param[in] reason Exit reason. + * @param[in] from Sending entity, must be provided + * to maintain signal order. + * + * @param[in] system Whether the sender is considered a + * system service, e.g. a NIF monitor, + * and it's okay to order by `from` + * even when it's not a pid or port. + * + * @param[in] mon Pointer to origin monitor + * structure from the sending + * side. It should contain + * information about receiver. * */ void -erts_proc_sig_send_demonitor(ErtsMonitor *mon); +erts_proc_sig_send_demonitor(ErtsPTabElementCommon *sender, Eterm from, + int system, ErtsMonitor *mon); /** * * @brief Send a monitor signal to a process. * + * @param[in] sender Pointer to the sending process/port, + * if any, as it may not be possible to + * resolve the sender (e.g. after it's + * dead). + * + * @param[in] from Sending entity, must be provided + * to maintain signal order. + * * @param[in] mon Pointer to target monitor * structure to insert on * receiver side. @@ -630,7 +703,8 @@ erts_proc_sig_send_demonitor(ErtsMonitor *mon); * */ int -erts_proc_sig_send_monitor(ErtsMonitor *mon, Eterm to); +erts_proc_sig_send_monitor(ErtsPTabElementCommon *sender, Eterm from, + ErtsMonitor *mon, Eterm to); /** * @@ -673,27 +747,22 @@ erts_proc_sig_send_dist_monitor_down(DistEntry *dep, Eterm ref, * when the signal arrives via the distribution and * no monitor structure is available. * + * @param[in] from Identifier of sender. + * * @param[in] to Identifier of receiver. * * @param[in] ref Reference identifying the monitor. * */ void -erts_proc_sig_send_dist_demonitor(Eterm to, Eterm ref); +erts_proc_sig_send_dist_demonitor(Eterm from, Eterm to, Eterm ref); /** * - * @brief Send a persistent monitor triggered signal to a process. - * - * Used by monitors that are not auto disabled such as for - * example 'time_offset' monitors. - * - * @param[in] type Monitor type. + * @brief Send a persistent "node down" monitor signal to a process * * @param[in] key Monitor key. * - * @param[in] from Identifier of sender. - * * @param[in] to Identifier of receiver. * * @param[in] msg Message template. @@ -702,27 +771,25 @@ erts_proc_sig_send_dist_demonitor(Eterm to, Eterm ref); * */ void -erts_proc_sig_send_persistent_monitor_msg(Uint16 type, Eterm key, - Eterm from, Eterm to, - Eterm msg, Uint msg_sz); +erts_proc_sig_send_monitor_nodes_msg(Eterm key, Eterm to, + Eterm msg, Uint msg_sz); /** * - * @brief Send a trace change signal to a process. + * @brief Send a persistent "time offset changed" monitor signal to a process * - * @param[in] to Identifier of receiver. + * @param[in] key Monitor key. * - * @param[in] on Trace flags to enable. + * @param[in] to Identifier of receiver. * - * @param[in] off Trace flags to disable. + * @param[in] msg Message template. * - * @param[in] tracer Tracer to set. If the non-value, - * tracer will not be changed. + * @param[in] msg_sz Heap size of message template. * */ void -erts_proc_sig_send_trace_change(Eterm to, Uint on, Uint off, - Eterm tracer); +erts_proc_sig_send_monitor_time_offset_msg(Eterm key, Eterm to, + Eterm msg, Uint msg_sz); /** * @@ -799,7 +866,7 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, * @param[in] item_ix Info index array to pass to * erts_process_info() * - * @param[in] len Lenght of info index array + * @param[in] len Length of info index array * * @param[in] need_msgq_len Non-zero if message queue * length is needed; otherwise, @@ -1043,14 +1110,11 @@ erts_proc_sig_send_cla_request(Process *c_p, Eterm to, Eterm req_id); * * When received, all on heap messages will be moved off heap. * - * @param[in] c_p Pointer to process struct of - * currently executing process. - * * @param[in] to Identifier of receiver. * */ void -erts_proc_sig_send_move_msgq_off_heap(Process *c_p, Eterm to); +erts_proc_sig_send_move_msgq_off_heap(Eterm to); /* * End of send operations of currently supported process signals. @@ -1072,6 +1136,9 @@ erts_proc_sig_send_move_msgq_off_heap(Process *c_p, Eterm to); * * @param[out] statep Pointer to process state after * signal handling. May not be NULL. + * The state should recently have + * been updated before calling + * this function. * * @param[in,out] redsp Pointer to an integer containing * reductions. On input, the amount @@ -1192,6 +1259,58 @@ erts_proc_sig_receive_helper(Process *c_p, int fcalls, int neg_o_reds, ErtsMessage **msgpp, int *get_outp); +/* + * CLEAN_SIGQ - Flush until middle queue is empty, i.e. + * the content of inner+middle queue equals + * the message queue. + */ +#define ERTS_PROC_SIG_FLUSH_FLG_CLEAN_SIGQ (1 << 0) +/* + * FROM_ALL - Flush signals from all local senders (processes + * and ports). + */ +#define ERTS_PROC_SIG_FLUSH_FLG_FROM_ALL (1 << 1) +/* + * FROM_ID - Flush signals from process or port identified + * by 'id'. + */ +#define ERTS_PROC_SIG_FLUSH_FLG_FROM_ID (1 << 2) + +/* + * All erts_proc_sig_init_flush_signals() flags. + */ +#define ERTS_PROC_SIG_FLUSH_FLGS \ + (ERTS_PROC_SIG_FLUSH_FLG_CLEAN_SIGQ \ + | ERTS_PROC_SIG_FLUSH_FLG_FROM_ALL \ + | ERTS_PROC_SIG_FLUSH_FLG_FROM_ID) + +/** + * + * @brief Initialize flush of signals from another process or port + * + * Inserts a flush signal in the outer signal queue of + * current process and sets the FS_FLUSHING_SIGS flag in + * 'c_p->sig_qs.flags'. When the flush signal has been + * handled the FS_FLUSHED_SIGS flag is set as well. + * + * While the flushing is ongoing the process *should* only + * handle incoming signals and not execute Erlang code. When + * the functionality that initiated the flush detects that + * the flush is done by the FS_FLUSHED_SIGS flag being set, + * it should clear both the FS_FLUSHED_SIGS flag and the + * FS_FLUSHING_SIGS flag. + * + * @param[in] c_p Pointer to process struct of + * currently executing process. + * flags Flags indicating how to flush. + * (see above). + * from Identifier of sender to flush + * signals from in case the + * FROM_ID flag is set. + */ +void +erts_proc_sig_init_flush_signals(Process *c_p, int flags, Eterm from); + /** * * @brief Fetch signals from the outer queue @@ -1229,25 +1348,29 @@ ERTS_GLB_INLINE Sint erts_proc_sig_fetch(Process *p); Sint erts_proc_sig_privqs_len(Process *c_p); - /** - * @brief Enqueue list of signals on process. - * - * Message queue must be locked on receiving process. - * - * @param rp Receiving process. - * @param first First signal in list. - * @param last Last signal in list. - * @param last_next Pointer to next-pointer to last non-message signal - * or NULL if no non-message signal after 'first'. - * @param msg_cnt Number of message signals in list. - * @param in_state 'state' of rp. - * - * @return 'state' of rp. + * @brief Enqueue a sequence of signals on an in signal queue of + * a process + * + * The *only* valid scenarios: + * * One or more message signals and no non-message signals. + * * One non-message signal followed by one or more message signals + * + * @param rp[in] Process to which the in signal queue + * belong. + * @param first[in] Pointer to the first signal in signal + * sequence. + * @param last[in] Pointer to the next pointer of the + * last signal in the sequence. This + * next pointer should equal NULL. + * @param msg_cnt[in] Number of message signals in seqence + * @param in_state[in] state of rp upon call. + * + * @return Possibly changed state of rp. */ erts_aint32_t erts_enqueue_signals(Process *rp, ErtsMessage *first, - ErtsMessage **last, ErtsMessage **last_next, + ErtsMessage **last, Uint msg_cnt, erts_aint32_t in_state); @@ -1257,7 +1380,7 @@ erts_enqueue_signals(Process *rp, ErtsMessage *first, * */ void -erts_proc_sig_send_pending(ErtsSchedulerData* esdp); +erts_proc_sig_send_pending(Process *c_p, ErtsSchedulerData* esdp); void @@ -1265,7 +1388,8 @@ erts_proc_sig_send_to_alias(Process *c_p, Eterm from, Eterm to, Eterm msg, Eterm token); void -erts_proc_sig_send_dist_to_alias(Eterm alias, ErtsDistExternal *edep, +erts_proc_sig_send_dist_to_alias(Eterm from, Eterm alias, + ErtsDistExternal *edep, ErlHeapFragment *hfrag, Eterm token); /** @@ -1279,10 +1403,14 @@ erts_proc_sig_send_dist_to_alias(Eterm alias, ErtsDistExternal *edep, */ ERTS_GLB_INLINE void erts_proc_notify_new_sig(Process* rp, erts_aint32_t state, erts_aint32_t enable_flag); +ERTS_GLB_INLINE void erts_proc_notify_new_message(Process *p, + ErtsProcLocks locks); -void erts_make_dirty_proc_handled(Eterm pid, erts_aint32_t state, - erts_aint32_t prio); - +void +erts_ensure_dirty_proc_signals_handled(Process *proc, + erts_aint32_t state, + erts_aint32_t prio, + ErtsProcLocks locks); typedef struct { Uint size; @@ -1308,12 +1436,16 @@ typedef struct { * * @param[in] mip Pointer to array of * ErtsMessageInfo structures. + * + * @param[out] msgq_lenp Pointer to integer containing + * amount of messages. */ Uint erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, ErtsProcLocks rp_locks, int info_on_self, - ErtsMessageInfo *mip); + ErtsMessageInfo *mip, + Sint *msgq_lenp); /** * @@ -1623,8 +1755,12 @@ extern Process *erts_dirty_process_signal_handler_high; extern Process *erts_dirty_process_signal_handler_max; /* Helpers... */ -void erts_proc_sig_fetch__(Process *proc); -Sint erts_proc_sig_fetch_msgq_len_offs__(Process *proc); +void erts_proc_sig_fetch__(Process *proc, + ErtsSignalInQueueBufferArray* buffers, + int need_unget_buffers); +Sint erts_proc_sig_fetch_msgq_len_offs__(Process *proc, + ErtsSignalInQueueBufferArray* buffers, + int need_unget_buffers); ERTS_GLB_INLINE int erts_msgq_eq_recv_mark_id__(Eterm term1, Eterm term2); ERTS_GLB_INLINE void erts_msgq_recv_marker_set_save__(Process *c_p, ErtsRecvMarkerBlock *blkp, @@ -1634,7 +1770,7 @@ Eterm erts_msgq_recv_marker_create_insert(Process *c_p, Eterm id); void erts_msgq_recv_marker_create_insert_set_save(Process *c_p, Eterm id); ErtsMessage **erts_msgq_pass_recv_markers(Process *c_p, ErtsMessage **markpp); -void erts_msgq_remove_leading_recv_markers(Process *c_p); +void erts_msgq_remove_leading_recv_markers_set_save_first(Process *c_p); #define ERTS_RECV_MARKER_IX__(BLKP, MRKP) \ ((int) ((MRKP) - &(BLKP)->marker[0])) @@ -1642,41 +1778,115 @@ void erts_msgq_remove_leading_recv_markers(Process *c_p); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE Uint64 -erts_proc_sig_new_unlink_id(Process *c_p) +erts_proc_sig_new_unlink_id(ErtsPTabElementCommon *sender) { Uint64 id; - ASSERT(c_p); - id = (Uint64) c_p->uniq++; - if (id == 0) + ASSERT(sender); + + if (is_internal_pid(sender->id)) { + Process *c_p = ErtsContainerStruct(sender, Process, common); id = (Uint64) c_p->uniq++; + + if (id == 0) { + id = (Uint64) c_p->uniq++; + } + } else { + ASSERT(is_internal_port(sender->id)); + + id = (Uint64) erts_raw_get_unique_monotonic_integer(); + if (id == 0) { + id = (Uint64) erts_raw_get_unique_monotonic_integer(); + } + } + + ASSERT(id != 0); + return id; } +ERTS_GLB_INLINE ErtsSignalInQueueBufferArray* +erts_proc_sig_queue_get_buffers(Process* p, int *need_unread) +{ + ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay(); + ErtsSignalInQueueBufferArray* buffers = + (ErtsSignalInQueueBufferArray*)erts_atomic_read_acqb(&p->sig_inq_buffers); + *need_unread = 0; + if (ERTS_THR_PRGR_DHANDLE_MANAGED == dhndl) { + erts_thr_progress_unmanaged_continue(dhndl); + return buffers; + } + if (buffers == NULL) { + erts_thr_progress_unmanaged_continue(dhndl); + return NULL; + } + erts_refc_inc(&buffers->dirty_refc, 2); + erts_thr_progress_unmanaged_continue(dhndl); + *need_unread = 1; + return buffers; +} + +ERTS_GLB_INLINE void +erts_proc_sig_queue_unget_buffers(ErtsSignalInQueueBufferArray* buffers, + int need_unget) +{ + if (!need_unget) { + return; + } else { + int i; + erts_aint_t refc = erts_refc_dectest(&buffers->dirty_refc, 0); + if (refc != 0) { + return; + } + ASSERT(!buffers->alive); + for (i = 0; i < ERTS_PROC_SIG_INQ_BUFFERED_NR_OF_BUFFERS; i++) { + ASSERT(!buffers->slots[i].b.alive); + erts_mtx_destroy(&buffers->slots[i].b.lock); + } + erts_free(ERTS_ALC_T_SIGQ_BUFFERS, buffers); + } +} + ERTS_GLB_INLINE Sint erts_proc_sig_fetch(Process *proc) { Sint res = 0; ErtsSignal *sig; - - ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc) - || ((erts_proc_lc_my_proc_locks(proc) - & (ERTS_PROC_LOCK_MAIN - | ERTS_PROC_LOCK_MSGQ)) - == (ERTS_PROC_LOCK_MAIN - | ERTS_PROC_LOCK_MSGQ))); + ErtsSignalInQueueBufferArray* buffers; + int need_unget_buffers; + ERTS_LC_ASSERT((erts_proc_lc_my_proc_locks(proc) + & (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ)) + == (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ)); + + ASSERT(!(proc->sig_qs.flags & FS_FLUSHING_SIGS) + || ERTS_PROC_IS_EXITING(proc) + || ERTS_IS_CRASH_DUMPING); ASSERT(!(proc->sig_qs.flags & FS_HANDLING_SIGS)); - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc); + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc, &proc->sig_inq); ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(proc, !0); + proc->sig_qs.flags &= ~FS_NON_FETCH_CNT_MASK; + + buffers = erts_proc_sig_queue_get_buffers(proc, &need_unget_buffers); + sig = (ErtsSignal *) proc->sig_inq.first; - if (sig) { - if (ERTS_LIKELY(sig->common.tag != ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK)) - erts_proc_sig_fetch__(proc); - else - res = erts_proc_sig_fetch_msgq_len_offs__(proc); + + if (!sig) { + if (buffers) + goto fetch; + } + else if (ERTS_UNLIKELY(sig->common.tag + == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK)) { + res = erts_proc_sig_fetch_msgq_len_offs__(proc, buffers, + need_unget_buffers); + } + else { + fetch: + erts_proc_sig_fetch__(proc, buffers, need_unget_buffers); } res += proc->sig_qs.len; @@ -1703,10 +1913,8 @@ ERTS_GLB_INLINE void erts_proc_notify_new_sig(Process* rp, erts_aint32_t state, erts_aint32_t enable_flag) { - if (~(state & (ERTS_PSFLG_EXITING - | ERTS_PSFLG_ACTIVE_SYS - | ERTS_PSFLG_SIG_IN_Q)) - | (~state & enable_flag)) { + if ((!(state & (ERTS_PSFLG_EXITING + | ERTS_PSFLG_ACTIVE_SYS))) | (~state & enable_flag)) { /* Schedule process... */ state = erts_proc_sys_schedule(rp, state, enable_flag); } @@ -1717,10 +1925,28 @@ erts_proc_notify_new_sig(Process* rp, erts_aint32_t state, * more info see erts_execute_dirty_system_task() * in erl_process.c. */ - erts_make_dirty_proc_handled(rp->common.id, state, -1); + erts_ensure_dirty_proc_signals_handled(rp, state, -1, 0); } } +ERTS_GLB_INLINE void +erts_proc_notify_new_message(Process *p, ErtsProcLocks locks) +{ + /* No barrier needed, due to msg lock */ + erts_aint32_t state = erts_atomic32_read_nob(&p->state); + if (!(state & ERTS_PSFLG_ACTIVE)) + erts_schedule_process(p, state, locks); + if (state & ERTS_PSFLG_DIRTY_RUNNING) { + /* + * We ignore ERTS_PSFLG_DIRTY_RUNNING_SYS. For + * more info see erts_execute_dirty_system_task() + * in erl_process.c. + */ + erts_ensure_dirty_proc_signals_handled(p, state, -1, locks); + } +} + + #undef ERTS_PROC_SIG_RECV_MARK_CLEAR_PENDING_SET_SAVE__ #define ERTS_PROC_SIG_RECV_MARK_CLEAR_PENDING_SET_SAVE__(BLKP) \ do { \ @@ -1857,7 +2083,7 @@ ERTS_GLB_INLINE Eterm erts_msgq_recv_marker_insert(Process *c_p) { ASSERT(!(c_p->sig_qs.flags & FS_HANDLING_SIGS)); - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); @@ -1908,7 +2134,7 @@ erts_msgq_recv_marker_insert_bind(Process *c_p, Eterm id) ERTS_PROC_SIG_RECV_MARK_CLEAR_OLD_MARK__(blkp); #endif - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); @@ -1983,8 +2209,9 @@ erts_msgq_set_save_first(Process *c_p) * anymore... */ if (c_p->sig_qs.first && ERTS_SIG_IS_RECV_MARKER(c_p->sig_qs.first)) - erts_msgq_remove_leading_recv_markers(c_p); - c_p->sig_qs.save = &c_p->sig_qs.first; + erts_msgq_remove_leading_recv_markers_set_save_first(c_p); + else + c_p->sig_qs.save = &c_p->sig_qs.first; } ERTS_GLB_INLINE void @@ -2022,7 +2249,7 @@ erts_msgq_set_save_end(Process *c_p) /* Set save pointer to end of message queue... */ ASSERT(!(c_p->sig_qs.flags & FS_HANDLING_SIGS)); - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index faf10b593e9c..cab471661d3b 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1715,8 +1715,8 @@ haw_thr_prgr_current_check_progress(ErtsAuxWorkData *awdp) if (current != ERTS_THR_PRGR_INVALID && !erts_thr_progress_equal(current, erts_thr_progress_current())) { /* - * We have used a previouly read current value that isn't the - * latest; need to poke ourselfs in order to guarantee no loss + * We have used a previously read current value that isn't the + * latest; need to poke ourselves in order to guarantee no loss * of wakeups. */ erts_sched_poke(awdp->ssi); @@ -2258,17 +2258,24 @@ handle_canceled_timers_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, i /* * Handle scheduled thread progress later operations. */ -#define ERTS_MAX_THR_PRGR_LATER_OPS 50 +#define ERTS_MIN_THR_PRGR_LATER_OPS 50 static ERTS_INLINE erts_aint32_t handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { - int lops; + int lops, limit; ErtsThrPrgrVal current = haw_thr_prgr_current(awdp); ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); - for (lops = 0; lops < ERTS_MAX_THR_PRGR_LATER_OPS; lops++) { + /* + * Boost loop limit proportional to number of queued later ops + * in order to always keep up. + */ + limit = (awdp->later_op.list_len / 8 + + ERTS_MIN_THR_PRGR_LATER_OPS); + + for (lops = 0; lops < limit; lops++) { ErtsThrPrgrLaterOp *lop = awdp->later_op.first; if (!erts_thr_progress_has_reached_this(current, lop->later)) @@ -2277,6 +2284,7 @@ handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int wait if (!awdp->later_op.first) { awdp->later_op.last = NULL; } + awdp->later_op.list_len--; lop->func(lop->data); if (!awdp->later_op.first) { awdp->later_op.size = thr_prgr_later_cleanup_op_threshold; @@ -2297,17 +2305,19 @@ enqueue_later_op(ErtsSchedulerData *esdp, ErtsThrPrgrLaterOp *lop) { ErtsThrPrgrVal later = erts_thr_progress_later(esdp); + ErtsAuxWorkData* awdp = &esdp->aux_work_data; ASSERT(esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp)); lop->func = later_func; lop->data = later_data; lop->later = later; lop->next = NULL; - if (!esdp->aux_work_data.later_op.last) - esdp->aux_work_data.later_op.first = lop; + if (!awdp->later_op.last) + awdp->later_op.first = lop; else - esdp->aux_work_data.later_op.last->next = lop; - esdp->aux_work_data.later_op.last = lop; + awdp->later_op.last->next = lop; + awdp->later_op.last = lop; + awdp->later_op.list_len++; set_aux_work_flags_wakeup_nob(esdp->ssi, ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP); return later; @@ -2498,7 +2508,7 @@ notify_reap_ports_relb(void) } erts_atomic32_t erts_halt_progress; -int erts_halt_code; +int erts_halt_code = INT_MIN; static ERTS_INLINE erts_aint32_t handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) @@ -2543,7 +2553,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) erts_port_release(prt); } if (erts_atomic32_dec_read_nob(&erts_halt_progress) == 0) { - erts_flush_async_exit(erts_halt_code, ""); + erts_flush_exit(erts_halt_code, ""); } } return aux_work & ~ERTS_SSI_AUX_WORK_REAP_PORTS; @@ -2657,7 +2667,7 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) /* * Handlers are *only* allowed to modify flags in return value - * and ssi flags that are explicity handled by the handler. + * and ssi flags that are explicitly handled by the handler. * Handlers are, e.g., not allowed to read the ssi flag field and * then unconditionally return that value. * @@ -2667,7 +2677,7 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) /* * Keep ERTS_SSI_AUX_WORK flags in expected frequency order relative - * eachother. Most frequent first. + * each other. Most frequent first. */ HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP, handle_delayed_aux_work_wakeup); @@ -3194,11 +3204,11 @@ aux_thread(void *vix) #if ERTS_POLL_USE_FALLBACK if (ix == 0) { -#if ERTS_POLL_USE_SCHEDULER_POLLING - ssi->psi = erts_create_pollset_thread(-2, tpd); -#else - ssi->psi = erts_create_pollset_thread(-1, tpd); -#endif + if (erts_sched_poll_enabled()) { + ssi->psi = erts_create_pollset_thread(-2, tpd); + } else { + ssi->psi = erts_create_pollset_thread(-1, tpd); + } } #endif @@ -3365,11 +3375,13 @@ try_set_sys_scheduling(void) static ERTS_INLINE int prepare_for_sys_schedule(void) { - while (!erts_port_task_have_outstanding_io_tasks() - && try_set_sys_scheduling()) { - if (!erts_port_task_have_outstanding_io_tasks()) - return 1; - clear_sys_scheduling(); + if (erts_sched_poll_enabled()) { + while (!erts_port_task_have_outstanding_io_tasks() + && try_set_sys_scheduling()) { + if (!erts_port_task_have_outstanding_io_tasks()) + return 1; + clear_sys_scheduling(); + } } return 0; } @@ -3698,7 +3710,7 @@ wake_scheduler(ErtsRunQueue *rq) * The unlocked run queue is not strictly necessary * from a thread safety or deadlock prevention * perspective. It will, however, cost us performance - * if it is locked during wakup of another scheduler, + * if it is locked during wakeup of another scheduler, * so all code *should* handle this without having * the lock on the run queue. */ @@ -4249,12 +4261,12 @@ clear_proc_dirty_queue_bit(Process *p, ErtsRunQueue *rq, int prio_bit) erts_aint32_t old; erts_aint32_t qb = prio_bit; if (rq == ERTS_DIRTY_CPU_RUNQ) - qb <<= ERTS_PDSFLGS_IN_CPU_PRQ_MASK_OFFSET; + qb <<= ERTS_PXSFLGS_IN_CPU_PRQ_MASK_OFFSET; else { ASSERT(rq == ERTS_DIRTY_IO_RUNQ); - qb <<= ERTS_PDSFLGS_IN_IO_PRQ_MASK_OFFSET; + qb <<= ERTS_PXSFLGS_IN_IO_PRQ_MASK_OFFSET; } - old = (int) erts_atomic32_read_band_mb(&p->dirty_state, ~qb); + old = (int) erts_atomic32_read_band_mb(&p->xstate, ~qb); ASSERT(old & qb); (void)old; } @@ -5834,6 +5846,8 @@ init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp, awdp->later_op.size = 0; awdp->later_op.first = NULL; awdp->later_op.last = NULL; + awdp->later_op.list_len = 0; + awdp->async_ready.need_thr_prgr = 0; awdp->async_ready.thr_prgr = ERTS_THR_PRGR_VAL_WAITING; awdp->async_ready.queue = NULL; @@ -6021,7 +6035,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th rq->ix = ix; - /* make sure that the "extra" id correponds to the schedulers + /* make sure that the "extra" id corresponds to the schedulers * id if the esdp->no <-> ix+1 mapping change. */ @@ -6288,15 +6302,12 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th erts_atomic32_set_nob(&schdlr_sspnd.changing, set_schdlr_sspnd_change_flags); - init_misc_aux_work(); - - /* init port tasks */ erts_port_task_init(); erts_atomic32_init_relb(&erts_halt_progress, -1); - erts_halt_code = 0; + erts_halt_code = INT_MIN; } @@ -6393,20 +6404,20 @@ check_dirty_enqueue_in_prio_queue(Process *c_p, * If we have system tasks, we enqueue on ordinary run-queue * and take care of those system tasks first. */ - if ((*newp) & ERTS_PSFLG_ACTIVE_SYS) + if ((*newp) & ERTS_PSFLG_SYS_TASKS) return ERTS_ENQUEUE_NORMAL_QUEUE; - dact = erts_atomic32_read_mb(&c_p->dirty_state); + dact = erts_atomic32_read_mb(&c_p->xstate); if (actual & (ERTS_PSFLG_DIRTY_ACTIVE_SYS | ERTS_PSFLG_DIRTY_CPU_PROC)) { - max_qbit = ((dact >> ERTS_PDSFLGS_IN_CPU_PRQ_MASK_OFFSET) - & ERTS_PDSFLGS_QMASK); + max_qbit = ((dact >> ERTS_PXSFLGS_IN_CPU_PRQ_MASK_OFFSET) + & ERTS_PXSFLGS_QMASK); queue = ERTS_ENQUEUE_DIRTY_CPU_QUEUE; } else { ASSERT(actual & ERTS_PSFLG_DIRTY_IO_PROC); - max_qbit = ((dact >> ERTS_PDSFLGS_IN_IO_PRQ_MASK_OFFSET) - & ERTS_PDSFLGS_QMASK); + max_qbit = ((dact >> ERTS_PXSFLGS_IN_IO_PRQ_MASK_OFFSET) + & ERTS_PXSFLGS_QMASK); queue = ERTS_ENQUEUE_DIRTY_IO_QUEUE; } @@ -6441,7 +6452,7 @@ fin_dirty_enq_s_change(Process *p, erts_aint32_t qbit = 1 << enq_prio; qbit <<= qmask_offset; - if (qbit & erts_atomic32_read_bor_mb(&p->dirty_state, qbit)) { + if (qbit & erts_atomic32_read_bor_mb(&p->xstate, qbit)) { /* Already enqueue by someone else... */ if (pstruct_reserved) { /* We reserved process struct for enqueue; clear it... */ @@ -6483,7 +6494,10 @@ check_enqueue_in_prio_queue(Process *c_p, *prq_prio_p = aprio; - if (actual & ERTS_PSFLGS_DIRTY_WORK) { + if (((actual & (ERTS_PSFLG_SUSPENDED + | ERTS_PSFLG_ACTIVE_SYS)) != (ERTS_PSFLG_SUSPENDED + | ERTS_PSFLG_ACTIVE_SYS)) + & (!!(actual & ERTS_PSFLGS_DIRTY_WORK))) { int res = check_dirty_enqueue_in_prio_queue(c_p, newp, actual, aprio, qbit); if (res != ERTS_ENQUEUE_NORMAL_QUEUE) @@ -6536,7 +6550,7 @@ select_enqueue_run_queue(int enqueue, int enq_prio, Process *p, erts_aint32_t st case -ERTS_ENQUEUE_DIRTY_CPU_QUEUE: if (fin_dirty_enq_s_change(p, enqueue > 0, enq_prio, - ERTS_PDSFLGS_IN_CPU_PRQ_MASK_OFFSET)) + ERTS_PXSFLGS_IN_CPU_PRQ_MASK_OFFSET)) return ERTS_DIRTY_CPU_RUNQ; return NULL; @@ -6546,7 +6560,7 @@ select_enqueue_run_queue(int enqueue, int enq_prio, Process *p, erts_aint32_t st case -ERTS_ENQUEUE_DIRTY_IO_QUEUE: if (fin_dirty_enq_s_change(p, enqueue > 0, enq_prio, - ERTS_PDSFLGS_IN_IO_PRQ_MASK_OFFSET)) + ERTS_PXSFLGS_IN_IO_PRQ_MASK_OFFSET)) return ERTS_DIRTY_IO_RUNQ; return NULL; @@ -6604,7 +6618,7 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p, n = e = a; if (a & ERTS_PSFLG_ACTIVE_SYS) { if (a & (ERTS_PSFLG_SIG_Q - | ERTS_PSFLG_SIG_IN_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q | ERTS_PSFLG_SYS_TASKS)) break; /* Clear active-sys */ @@ -6629,10 +6643,12 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p, */ /* - * No normal execution until dirty CLA or hibernat has + * No normal execution until dirty CLA or hibernate has * been handled... */ - ASSERT(!(p->flags & (F_DIRTY_CLA | F_DIRTY_GC_HIBERNATE))); + ASSERT(!(p->flags & (F_DIRTY_CHECK_CLA + | F_DIRTY_CLA + | F_DIRTY_GC_HIBERNATE))); a = erts_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_DIRTY_ACTIVE_SYS); @@ -6854,7 +6870,7 @@ change_proc_schedule_state(Process *p, | ERTS_PSFLG_RUNNING_SYS | ERTS_PSFLG_DIRTY_RUNNING | ERTS_PSFLG_DIRTY_RUNNING_SYS))) { - /* We activated a prevously inactive process */ + /* We activated a previously inactive process */ profile_runnable_proc(p, am_active); } @@ -6966,7 +6982,7 @@ active_sys_enqueue(Process *p, ErtsProcSysTask *sys_task, | ERTS_PSFLG_DIRTY_RUNNING | ERTS_PSFLG_DIRTY_RUNNING_SYS)) && (!(a & ERTS_PSFLG_ACTIVE) || (a & ERTS_PSFLG_SUSPENDED))) { - /* We activated a prevously inactive process */ + /* We activated a previously inactive process */ profile_runnable_proc(p, am_active); } } @@ -7384,7 +7400,7 @@ static ERTS_INLINE int have_dirty_work(void) { return !(ERTS_EMPTY_RUNQ(ERTS_DIRTY_CPU_RUNQ) - | ERTS_EMPTY_RUNQ(ERTS_DIRTY_IO_RUNQ)); + || ERTS_EMPTY_RUNQ(ERTS_DIRTY_IO_RUNQ)); } #define ERTS_MSB_NONE_PRIO_BIT PORT_BIT @@ -7502,7 +7518,7 @@ msb_scheduler_type_switch(ErtsSchedType sched_type, /* * Make sure to alternate between dirty types - * inbetween normal execution if highest + * between normal execution if highest * priorities are equal. */ @@ -8621,9 +8637,9 @@ sched_thread_func(void *vesdp) erts_thr_progress_register_managed_thread(esdp, &callbacks, 0, 0); -#if ERTS_POLL_USE_SCHEDULER_POLLING - esdp->ssi->psi = erts_create_pollset_thread(-1, NULL); -#endif + if (erts_sched_poll_enabled()) { + esdp->ssi->psi = erts_create_pollset_thread(-1, NULL); + } #ifdef ERTS_ENABLE_LOCK_CHECK { @@ -8652,6 +8668,7 @@ sched_thread_func(void *vesdp) erts_ets_sched_spec_data_init(esdp); erts_utils_sched_spec_data_init(); + erts_nif_sched_init(esdp); process_main(esdp); @@ -8702,6 +8719,8 @@ sched_dirty_cpu_thread_func(void *vesdp) erts_proc_lock_prepare_proc_lock_waiter(); + erts_nif_sched_init(esdp); + erts_dirty_process_main(esdp); /* No schedulers should *ever* terminate */ erts_exit(ERTS_ABORT_EXIT, @@ -8750,6 +8769,8 @@ sched_dirty_io_thread_func(void *vesdp) erts_proc_lock_prepare_proc_lock_waiter(); + erts_nif_sched_init(esdp); + erts_dirty_process_main(esdp); /* No schedulers should *ever* terminate */ erts_exit(ERTS_ABORT_EXIT, @@ -8763,7 +8784,7 @@ erts_start_schedulers(void) { ethr_tid tid; int res = 0; - char name[32]; + char name[ETHR_THR_NAME_MAX + 1]; ethr_thr_opts opts = ETHR_THR_OPTS_DEFAULT_INITER; int ix; @@ -8773,7 +8794,7 @@ erts_start_schedulers(void) if (erts_runq_supervision_interval) { opts.suggested_stack_size = 16; - erts_snprintf(opts.name, sizeof(name), "runq_supervisor"); + erts_snprintf(opts.name, sizeof(name), "erts_runq_sup"); erts_atomic_init_nob(&runq_supervisor_sleeping, 0); if (0 != ethr_event_init(&runq_supervision_event)) erts_exit(ERTS_ABORT_EXIT, "Failed to create run-queue supervision event\n"); @@ -8794,7 +8815,7 @@ erts_start_schedulers(void) for (ix = 0; ix < erts_no_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix); ASSERT(ix == esdp->no - 1); - erts_snprintf(opts.name, sizeof(name), "%lu_scheduler", ix + 1); + erts_snprintf(opts.name, sizeof(name), "erts_sched_%d", ix + 1); res = ethr_thr_create(&esdp->tid, sched_thread_func, (void*)esdp, &opts); if (res != 0) { erts_exit(ERTS_ABORT_EXIT, "Failed to create scheduler thread %d, error = %d\n", ix, res); @@ -8808,7 +8829,7 @@ erts_start_schedulers(void) { for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_DIRTY_CPU_SCHEDULER_IX(ix); - erts_snprintf(opts.name, sizeof(name), "%d_dirty_cpu_scheduler", ix + 1); + erts_snprintf(opts.name, sizeof(name), "erts_dcpus_%d", ix + 1); opts.suggested_stack_size = erts_dcpu_sched_thread_suggested_stack_size; res = ethr_thr_create(&esdp->tid,sched_dirty_cpu_thread_func,(void*)esdp,&opts); if (res != 0) @@ -8816,7 +8837,7 @@ erts_start_schedulers(void) } for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix); - erts_snprintf(opts.name, sizeof(name), "%d_dirty_io_scheduler", ix + 1); + erts_snprintf(opts.name, sizeof(name), "erts_dios_%d", ix + 1); opts.suggested_stack_size = erts_dio_sched_thread_suggested_stack_size; res = ethr_thr_create(&esdp->tid,sched_dirty_io_thread_func,(void*)esdp,&opts); if (res != 0) @@ -8827,7 +8848,7 @@ erts_start_schedulers(void) ix = 0; while (ix < erts_no_aux_work_threads) { int id = ix == 0 ? 1 : ix + 1 - (int) erts_no_schedulers; - erts_snprintf(opts.name, sizeof(name), "%d_aux", id); + erts_snprintf(opts.name, sizeof(name), "erts_aux_%d", id); res = ethr_thr_create(&tid, aux_thread, (void *) (Sint) ix, &opts); if (res != 0) @@ -8854,7 +8875,7 @@ erts_start_schedulers(void) bpt->blocked = 0; bpt->id = ix; - erts_snprintf(opts.name, sizeof(name), "%d_poller", ix); + erts_snprintf(opts.name, sizeof(name), "erts_poll_%d", ix); res = ethr_thr_create(&tid, poll_thread, (void*) bpt, &opts); if (res != 0) @@ -8990,8 +9011,10 @@ erts_internal_suspend_process_2(BIF_ALIST_2) erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); } if (send_sig) { - if (erts_proc_sig_send_monitor(&mdp->u.target, BIF_ARG_1)) + if (erts_proc_sig_send_monitor(&BIF_P->common, BIF_P->common.id, + &mdp->u.target, BIF_ARG_1)) { sync = !async; + } else { noproc: erts_monitor_tree_delete(&ERTS_P_MONITORS(BIF_P), &mdp->origin); @@ -9048,7 +9071,7 @@ resume_process_1(BIF_ALIST_1) if ((mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK) == 0) { erts_monitor_tree_delete(&ERTS_P_MONITORS(BIF_P), mon); - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(&BIF_P->common, BIF_P->common.id, 0, mon); } BIF_RET(am_true); @@ -9449,8 +9472,9 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) int actual_reds; int reds; Uint32 flags; - erts_aint32_t state = 0; /* Supress warning... */ + erts_aint32_t state = 0; /* Suppress warning... */ int is_normal_sched; + ErtsSchedType sched_type; #ifdef DEBUG int aborted_execution = 0; #endif @@ -9490,6 +9514,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) else { ASSERT(ERTS_SCHEDULER_IS_DIRTY(esdp)); } + sched_type = esdp->type; rq = erts_get_runq_current(esdp); ASSERT(esdp); actual_reds = reds = 0; @@ -9501,8 +9526,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) ASSERT(!ERTS_SCHEDULER_IS_DIRTY(esdp)); if (esdp->pending_signal.sig) { - ASSERT(esdp->pending_signal.dbg_from == p); - erts_proc_sig_send_pending(esdp); + erts_proc_sig_send_pending(p, esdp); } } else { @@ -9511,6 +9535,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) ASSERT(esdp->current_process == p || esdp->free_process == p); + sched_type = esdp->type; reds = actual_reds = calls - esdp->virtual_reds; @@ -9525,7 +9550,9 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) esdp->virtual_reds = 0; #if ERTS_POLL_USE_SCHEDULER_POLLING - fcalls = (int) erts_atomic32_add_read_acqb(&function_calls, reds); + if (erts_sched_poll_enabled()) { + fcalls = (int)erts_atomic32_add_read_acqb(&function_calls, reds); + } #endif ASSERT(esdp && esdp == erts_get_scheduler_data()); @@ -9536,6 +9563,24 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) state = erts_atomic32_read_nob(&p->state); + if ((state & ERTS_PSFLG_MSG_SIG_IN_Q) + && ERTS_MSG_RECV_TRACED(p) + && !(p->sig_qs.flags & FS_FLUSHING_SIGS)) { + if (!(state & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_ACTIVE_SYS))) { + goto sched_out_fetch_signals; + } + else if ((p->sig_qs.flags + & FS_NON_FETCH_CNT_MASK) != FS_NON_FETCH_CNT_MASK) { + p->sig_qs.flags += FS_NON_FETCH_CNT1; + } + else { + sched_out_fetch_signals: + erts_proc_sig_queue_lock(p); + erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + } + } + if (IS_TRACED(p)) trace_schedule_out(p, state); @@ -9570,8 +9615,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) p->scheduler_data = NULL; erts_proc_unlock(p, (ERTS_PROC_LOCK_MAIN - | ERTS_PROC_LOCK_STATUS - | ERTS_PROC_LOCK_TRACE)); + | ERTS_PROC_LOCK_STATUS + | ERTS_PROC_LOCK_TRACE)); ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_OTHER); @@ -9602,7 +9647,6 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) ERTS_LC_ASSERT(!is_normal_sched || !erts_thr_progress_is_blocking()); check_activities_to_run: { - erts_aint32_t psflg_running, psflg_running_sys; ErtsMigrationPaths *mps; ErtsMigrationPath *mp; @@ -9851,14 +9895,10 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) #endif if (is_normal_sched) { - psflg_running = ERTS_PSFLG_RUNNING; - psflg_running_sys = ERTS_PSFLG_RUNNING_SYS; psflg_band_mask = ~(((erts_aint32_t) 1) << (ERTS_PSFLGS_GET_PRQ_PRIO(state) + ERTS_PSFLGS_IN_PRQ_MASK_OFFSET)); } else { - psflg_running = ERTS_PSFLG_DIRTY_RUNNING; - psflg_running_sys = ERTS_PSFLG_DIRTY_RUNNING_SYS; psflg_band_mask = ~((erts_aint32_t) 0); qbit = ((erts_aint32_t) 1) << ERTS_PSFLGS_GET_PRQ_PRIO(state); } @@ -9920,12 +9960,29 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) & ((!is_running) | need_forced_exit)); if (run_process) { - if (state & (ERTS_PSFLG_ACTIVE_SYS - | ERTS_PSFLG_DIRTY_ACTIVE_SYS)) - new |= psflg_running_sys; - else - new |= psflg_running; - } + switch (sched_type) { + case ERTS_SCHED_NORMAL: + if (state & ERTS_PSFLG_ACTIVE_SYS) + new |= ERTS_PSFLG_RUNNING_SYS; + else + new |= ERTS_PSFLG_RUNNING; + break; + case ERTS_SCHED_DIRTY_CPU: + if (state & ERTS_PSFLG_DIRTY_ACTIVE_SYS) + new |= ERTS_PSFLG_DIRTY_RUNNING_SYS; + else + new |= ERTS_PSFLG_DIRTY_RUNNING; + break; + case ERTS_SCHED_DIRTY_IO: + new |= ERTS_PSFLG_DIRTY_RUNNING; + break; +#ifdef DEBUG + default: + ASSERT(0); + break; +#endif + } + } state = erts_atomic32_cmpxchg_relb(&p->state, new, exp); if (state == exp) { if (!run_process) { @@ -9946,6 +10003,18 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) ASSERT(state & ERTS_PSFLG_IN_RUNQ); erts_proc_dec_refc(p); } + if (state & ERTS_PSFLG_MSG_SIG_IN_Q) { + erts_runq_unlock(rq); + erts_proc_lock(p, (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ)); + if (ERTS_MSG_RECV_TRACED(p) + && !(p->sig_qs.flags & FS_FLUSHING_SIGS)) { + erts_proc_sig_fetch(p); + } + erts_proc_unlock(p, (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ)); + erts_runq_lock(rq); + } if (!is_normal_sched) erts_proc_dec_refc(p); goto pick_next_process; @@ -9999,7 +10068,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) state = erts_atomic32_read_nob(&p->state); - if (is_normal_sched) { + switch (sched_type) { + case ERTS_SCHED_NORMAL: ASSERT(!p->scheduler_data); p->scheduler_data = esdp; if ((!!(state & ERTS_PSFLGS_DIRTY_WORK)) @@ -10014,41 +10084,51 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) #endif goto sched_out_proc; } - } - else { - /* On dirty scheduler */ - if (!(state & ERTS_PSFLGS_DIRTY_WORK) - | !!(state & (ERTS_PSFLG_SYS_TASKS - | ERTS_PSFLG_EXITING - | ERTS_PSFLG_DIRTY_ACTIVE_SYS))) { - - if (!(state & ERTS_PSFLGS_DIRTY_WORK)) { - /* Dirty work completed... */ - goto sunlock_sched_out_proc; - } - if (state & (ERTS_PSFLG_SYS_TASKS - | ERTS_PSFLG_EXITING)) { - /* - * IMPORTANT! We need to take care of - * scheduled check-process-code requests - * before continuing with dirty execution! - */ - /* Migrate to normal scheduler... */ - goto sunlock_sched_out_proc; - } - if ((state & ERTS_PSFLG_DIRTY_ACTIVE_SYS) - && rq == ERTS_DIRTY_IO_RUNQ) { - /* Migrate to dirty cpu scheduler... */ - goto sunlock_sched_out_proc; - } + break; + case ERTS_SCHED_DIRTY_IO: + + /* + * IMPORTANT! We need to take care of + * scheduled check-process-code sys-tasks + * before continuing with dirty execution! + */ + + if ((state & (ERTS_PSFLG_SYS_TASKS + | ERTS_PSFLG_EXITING + | ERTS_PSFLG_DIRTY_ACTIVE_SYS + | ERTS_PSFLG_SUSPENDED)) + | !(state & ERTS_PSFLG_DIRTY_IO_PROC)) { + /* Migrate to another type of scheduler... */ + goto sunlock_sched_out_proc; } - ASSERT(rq == ERTS_DIRTY_CPU_RUNQ - ? (state & (ERTS_PSFLG_DIRTY_CPU_PROC - | ERTS_PSFLG_DIRTY_ACTIVE_SYS)) - : (rq == ERTS_DIRTY_IO_RUNQ - && (state & ERTS_PSFLG_DIRTY_IO_PROC))); + ASSERT((state & ERTS_PSFLG_DIRTY_RUNNING)); + break; + + case ERTS_SCHED_DIRTY_CPU: + + /* + * IMPORTANT! We need to take care of + * scheduled check-process-code sys-tasks + * before continuing with dirty execution! + */ + + if ((state & (ERTS_PSFLG_SYS_TASKS + | ERTS_PSFLG_EXITING)) + | (!(state & ERTS_PSFLG_DIRTY_ACTIVE_SYS) + & ((state & (ERTS_PSFLG_DIRTY_CPU_PROC + | ERTS_PSFLG_SUSPENDED)) + != ERTS_PSFLG_DIRTY_CPU_PROC))) { + /* Migrate to another type of scheduler... */ + goto sunlock_sched_out_proc; + } + + ASSERT((state & ERTS_PSFLG_DIRTY_ACTIVE_SYS) + ? (state & ERTS_PSFLG_DIRTY_RUNNING_SYS) + : (state & ERTS_PSFLG_DIRTY_RUNNING)); + + break; } erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); @@ -10059,10 +10139,15 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (!is_normal_sched) { /* On dirty scheduler */ if (!!(state & ERTS_PSFLG_DIRTY_RUNNING) - & !!(state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))) { + & !!(state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q))) { /* Ensure signals are handled while executing dirty... */ int prio = ERTS_PSFLGS_GET_ACT_PRIO(state); - erts_make_dirty_proc_handled(p->common.id, state, prio); + erts_ensure_dirty_proc_signals_handled(p, + state, + prio, + ERTS_PROC_LOCK_MAIN); } } else { @@ -10075,28 +10160,36 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) state = erts_proc_sig_check_wait_dirty_handle_signals(p, state); if (state & ERTS_PSFLG_RUNNING_SYS) { - if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) { - int local_only = (!!(p->sig_qs.flags & FS_LOCAL_SIGS_ONLY) - & !(state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLGS_DIRTY_WORK))); - if (!local_only | !!(state & ERTS_PSFLG_SIG_Q)) { - int sig_reds; + if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_NMSG_SIG_IN_Q)) { + int sig_reds; + /* + * If we have dirty work scheduled we allow + * usage of all reductions since we need to + * handle all signals before doing dirty + * work... + * + * If a BIF is flushing signals, we also allow + * usage of all reductions since the BIF cannot + * continue exectution until the flush + * completes... + */ + sig_reds = reds; + if (((state & (ERTS_PSFLGS_DIRTY_WORK + | ERTS_PSFLG_ACTIVE)) == ERTS_PSFLG_ACTIVE) + && !(p->sig_qs.flags & FS_FLUSHING_SIGS)) { /* - * If we have dirty work scheduled we allow - * usage of all reductions since we need to - * handle all signals before doing dirty - * work... + * We are active, i.e., have erlang work to do, + * and have no dirty work and are not flushing + * limit amount of signal handling work... */ - if (state & ERTS_PSFLGS_DIRTY_WORK) - sig_reds = reds; - else - sig_reds = ERTS_SIG_HANDLE_REDS_MAX_PREFERED; - (void) erts_proc_sig_handle_incoming(p, - &state, - &sig_reds, - sig_reds, - local_only); - reds -= sig_reds; + sig_reds = ERTS_SIG_HANDLE_REDS_MAX_PREFERED; } + (void) erts_proc_sig_handle_incoming(p, + &state, + &sig_reds, + sig_reds, + 0); + reds -= sig_reds; } if ((state & (ERTS_PSFLG_SYS_TASKS | ERTS_PSFLG_EXITING)) == ERTS_PSFLG_SYS_TASKS) { @@ -10106,8 +10199,14 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) * hand written beam assembly in * prim_eval:'receive'. If GC is delayed we are * not allowed to execute system tasks. + * + * We also don't allow execution of system tasks + * if a BIF is flushing signals, since there are + * system tasks that might need to fetch from the + * outer signal queue... */ - if (!(p->flags & F_DELAY_GC)) { + if (!(p->flags & F_DELAY_GC) + && !(p->sig_qs.flags & FS_FLUSHING_SIGS)) { int cost = execute_sys_tasks(p, &state, reds); calls += cost; reds -= cost; @@ -10117,8 +10216,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (reds <= 0 || (state & ERTS_PSFLGS_DIRTY_WORK)) goto sched_out_proc; - ASSERT(state & psflg_running_sys); - ASSERT(!(state & psflg_running)); + ASSERT(state & ERTS_PSFLG_RUNNING_SYS); + ASSERT(!(state & ERTS_PSFLG_RUNNING)); while (1) { erts_aint32_t n, e; @@ -10141,8 +10240,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) } n = e = state; - n &= ~psflg_running_sys; - n |= psflg_running; + n &= ~ERTS_PSFLG_RUNNING_SYS; + n |= ERTS_PSFLG_RUNNING; state = erts_atomic32_cmpxchg_mb(&p->state, n, e); if (state == e) { @@ -10150,8 +10249,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) break; } - ASSERT(state & psflg_running_sys); - ASSERT(!(state & psflg_running)); + ASSERT(state & ERTS_PSFLG_RUNNING_SYS); + ASSERT(!(state & ERTS_PSFLG_RUNNING)); } } @@ -10159,6 +10258,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (!(state & ERTS_PSFLG_EXITING) && !(p->flags & (F_DELAY_GC|F_DISABLE_GC))) { int cost = scheduler_gc_proc(p, reds); + state = erts_atomic32_read_nob(&p->state); calls += cost; reds -= cost; if (reds <= 0) @@ -10604,25 +10704,49 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) int fcalls; int cla_reds = 0; - if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) - fcalls = reds; - else - fcalls = reds - CONTEXT_REDS; - st_res = erts_copy_literals_gc(c_p, &cla_reds, fcalls); - reds -= cla_reds; - if (is_non_value(st_res)) { - if (c_p->flags & F_DIRTY_CLA) { - save_dirty_task(c_p, st); - st = NULL; - break; - } - /* Needed gc, but gc was disabled */ - save_gc_task(c_p, st, st_prio); - st = NULL; - break; - } - /* We did a major gc */ - minor_gc = major_gc = 1; + if (st->arg[0] == am_true) { + /* + * Check if copy literal area GC is needed and only + * do GC if needed. This check is never requested unless + * we know that this is to much work to do on a normal + * scheduler, so we do not even try to check it here + * but instead unconditionally schedule this as dirty + * work... + */ + if (c_p->flags & F_DISABLE_GC) { + /* We might need to GC, but GC was disabled */ + save_gc_task(c_p, st, st_prio); + st = NULL; + } + else { + c_p->flags |= F_DIRTY_CHECK_CLA; + save_dirty_task(c_p, st); + st = NULL; + erts_schedule_dirty_sys_execution(c_p); + } + } + else { + /* Copy literal area GC needed... */ + if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) + fcalls = reds; + else + fcalls = reds - CONTEXT_REDS; + st_res = erts_copy_literals_gc(c_p, &cla_reds, fcalls); + reds -= cla_reds; + if (is_non_value(st_res)) { + if (c_p->flags & F_DIRTY_CLA) { + save_dirty_task(c_p, st); + st = NULL; + break; + } + /* Needed gc, but gc was disabled */ + save_gc_task(c_p, st, st_prio); + st = NULL; + break; + } + /* We did a major gc */ + minor_gc = major_gc = 1; + } break; } case ERTS_PSTT_FTMQ: @@ -10635,15 +10759,19 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) break; case ERTS_PSTT_PRIO_SIG: { erts_aint32_t fail_state, state; - int sig_res, sig_reds = reds; + int sig_res, sig_reds; st_res = am_false; + ASSERT(!(c_p->sig_qs.flags & FS_FLUSHING_SIGS)); + if (st->arg[0] == am_false) { - erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_lock(c_p); erts_proc_sig_fetch(c_p); erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + st->arg[0] = am_true; } + state = erts_atomic32_read_nob(&c_p->state); sig_reds = reds; sig_res = erts_proc_sig_handle_incoming(c_p, &state, &sig_reds, reds, !0); @@ -10657,8 +10785,6 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) if (sig_res) break; - st->arg[0] = am_true; - fail_state = ERTS_PSFLG_EXITING; if (schedule_process_sys_task(c_p, st_prio, st, &fail_state)) { @@ -10669,6 +10795,7 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) state = erts_atomic32_read_nob(&c_p->state); exit_permanent_prio_elevation(c_p, state, st_prio); } + break; } case ERTS_PSTT_TEST: @@ -10824,10 +10951,12 @@ erts_execute_dirty_system_task(Process *c_p) /* * If multiple operations, perform them in the following * order (in order to avoid unnecessary GC): - * 1. Copy Literal Area (implies major GC). - * 2. GC Hibernate (implies major GC if not woken). - * 3. Major GC (implies minor GC). - * 4. Minor GC. + * 1. Check for Copy Literals Area GC need. This may + * trigger a Copy Literals Area GC. + * 2. Copy Literal Area GC (implies major GC). + * 3. GC Hibernate (implies major GC if not woken). + * 4. Major GC (implies minor GC). + * 5. Minor GC. * * System task requests are handled after the actual * operations have been performed... @@ -10835,6 +10964,37 @@ erts_execute_dirty_system_task(Process *c_p) ASSERT(!(c_p->flags & (F_DELAY_GC|F_DISABLE_GC))); + if (c_p->flags & F_DIRTY_CHECK_CLA) { + ErtsLiteralArea *la = ERTS_COPY_LITERAL_AREA(); + + ASSERT(!(c_p->flags & F_DIRTY_CLA)); + c_p->flags &= ~F_DIRTY_CHECK_CLA; + if (!la) + cla_res = am_ok; + else { + int check_cla_reds = 0; + char *literals = (char *) &la->start[0]; + Uint lit_bsize = (char *) la->end - literals; + if (erts_check_copy_literals_gc_need(c_p, + &check_cla_reds, + literals, + lit_bsize)) { + /* + * We had references to this literal area on the heap; + * need a copy literals GC... + */ + c_p->flags |= F_DIRTY_CLA; + } + else { + /* + * We have no references to this literal area on the + * heap; no copy literals GC needed... + */ + cla_res = am_ok; + } + } + } + if (c_p->flags & F_DIRTY_CLA) { int cla_reds = 0; cla_res = erts_copy_literals_gc(c_p, &cla_reds, c_p->fcalls); @@ -10863,7 +11023,8 @@ erts_execute_dirty_system_task(Process *c_p) c_p->arity, c_p->fcalls); } - ASSERT(!(c_p->flags & (F_DIRTY_CLA + ASSERT(!(c_p->flags & (F_DIRTY_CHECK_CLA + | F_DIRTY_CLA | F_DIRTY_GC_HIBERNATE | F_DIRTY_MAJOR_GC | F_DIRTY_MINOR_GC))); @@ -11123,7 +11284,9 @@ request_system_task(Process *c_p, Eterm requester, Eterm target, state = erts_atomic32_read_acqb(&rp->state); if (state & fail_state & ERTS_PSFLG_EXITING) goto noproc; - if (state & (ERTS_PSFLG_SIG_Q | ERTS_PSFLG_SIG_IN_Q)) { + if (state & (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q)) { /* * Send rpc request signal without reply, * and reply from the system task... @@ -11139,7 +11302,7 @@ request_system_task(Process *c_p, Eterm requester, Eterm target, return ret; /* signal sent... */ } /* - * schedule system task directly since we wont violate + * schedule system task directly since we won't violate * signal order... */ } @@ -11247,7 +11410,7 @@ erts_internal_request_system_task_4(BIF_ALIST_4) } void -erts_schedule_cla_gc(Process *c_p, Eterm to, Eterm req_id) +erts_schedule_cla_gc(Process *c_p, Eterm to, Eterm req_id, int check) { Process *rp; ErtsProcSysTask *st; @@ -11273,7 +11436,8 @@ erts_schedule_cla_gc(Process *c_p, Eterm to, Eterm req_id) req_id_sz, &hp, &st->off_heap); - for (i = 0; i < ERTS_MAX_PROC_SYS_TASK_ARGS; i++) + st->arg[0] = check ? am_true : am_false; + for (i = 1; i < ERTS_MAX_PROC_SYS_TASK_ARGS; i++) st->arg[i] = THE_NON_VALUE; rp = erts_proc_lookup_raw(to); @@ -11821,9 +11985,11 @@ static void early_init_process_struct(void *varg, Eterm data) Process *proc = arg->proc; proc->common.id = make_internal_pid(data); - erts_atomic32_init_nob(&proc->dirty_state, 0); + erts_atomic32_init_nob(&proc->xstate, 0); proc->dirty_sys_tasks = NULL; erts_init_runq_proc(proc, arg->run_queue, arg->bound); + erts_atomic_init_nob(&proc->sig_inq_buffers, (erts_aint_t)NULL); + erts_atomic32_init_relb(&proc->state, arg->state); erts_proc_lock_init(proc); /* All locks locked */ @@ -11943,6 +12109,22 @@ erts_parse_spawn_opts(ErlSpawnOpts *sop, Eterm opts_list, Eterm *tag, sop->priority = PRIORITY_LOW; else result = -1; + } else if (arg == am_async_dist) { + if (val == am_true) { + if (sop->flags & SPO_ASYNC_DIST) + sop->multi_set = !0; + else + sop->flags |= SPO_ASYNC_DIST; + } + else if (val == am_false) { + if (!(sop->flags & SPO_ASYNC_DIST)) + sop->multi_set = !0; + else + sop->flags &= ~SPO_ASYNC_DIST; + } + else { + result = -1; + } } else if (arg == am_message_queue_data) { if (sop->flags & (SPO_OFF_HEAP_MSGQ|SPO_ON_HEAP_MSGQ)) sop->multi_set = !0; @@ -12180,6 +12362,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). /* Reserve place for continuation pointer, redzone, etc */ heap_need = arg_size + S_RESERVED; + if (so->flags & SPO_ASYNC_DIST) + flags |= F_ASYNC_DIST; + p->flags = flags; p->sig_qs.flags = qs_flags; @@ -12207,6 +12392,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). */ p->off_heap.first = NULL; p->off_heap.overhead = 0; + p->wrt_bins = NULL; if (is_not_immed(group_leader)) heap_need += NC_HEAP_SIZE(group_leader); @@ -12222,7 +12408,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->high_water = p->heap; p->gen_gcs = 0; p->hend = p->heap + sz; - p->stop = p->hend - 1; /* Reserve place for continuation pointer */ + p->stop = p->hend - CP_SIZE; /* Reserve place for continuation pointer. */ p->htop = p->heap; p->heap_sz = sz; p->abandoned_heap = NULL; @@ -12239,8 +12425,19 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->current = &p->u.initial; - p->i = beam_apply; - p->stop[0] = make_cp(beam_normal_exit); + p->i = beam_run_process; + + switch (erts_frame_layout) { + case ERTS_FRAME_LAYOUT_RA: + p->stop[0] = make_cp(beam_normal_exit); + break; + case ERTS_FRAME_LAYOUT_FP_RA: + p->stop[0] = make_cp(NULL); + p->stop[1] = make_cp(beam_normal_exit); + + FRAME_POINTER(p) = &p->stop[0]; + break; + } p->arg_reg = p->def_arg_reg; p->max_arg_reg = sizeof(p->def_arg_reg)/sizeof(p->def_arg_reg[0]); @@ -12290,11 +12487,13 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->sig_qs.len = 0; p->sig_qs.nmsigs.next = NULL; p->sig_qs.nmsigs.last = NULL; + p->sig_inq_contention_counter = 0; p->sig_inq.first = NULL; p->sig_inq.last = &p->sig_inq.first; p->sig_inq.len = 0; p->sig_inq.nmsigs.next = NULL; p->sig_inq.nmsigs.last = NULL; + ASSERT(erts_atomic_read_nob(&p->sig_inq_buffers) == (erts_aint_t)NULL); #ifdef ERTS_PROC_SIG_HARD_DEBUG p->sig_inq.may_contain_heap_terms = 0; #endif @@ -12308,9 +12507,20 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). DT_UTAG(p) = NIL; DT_UTAG_FLAGS(p) = 0; #endif - p->parent = (!parent || parent->common.id == ERTS_INVALID_PID - ? NIL - : parent->common.id); + + if (parent_id == ERTS_INVALID_PID) { + p->parent = am_undefined; + } + else if (is_internal_pid(parent_id)) { + p->parent = parent_id; + } + else { + Eterm sz, *hp; + ASSERT(is_external_pid(parent_id)); + sz = size_object(parent_id); + hp = HAlloc(p, sz); + p->parent = copy_struct(parent_id, sz, &hp, &MSO(p)); + } INIT_HOLE_CHECK(p); #ifdef DEBUG @@ -12602,8 +12812,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->common.id, parent_id); erts_link_tree_insert(&ERTS_P_LINKS(p), &ldp->proc); if (!erts_link_dist_insert(&ldp->dist, so->mld)) { - erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->dist, - am_noconnection, NIL); + erts_proc_sig_send_link_exit_noconnection(&ldp->dist); } } @@ -12771,6 +12980,7 @@ void erts_init_empty_process(Process *p) p->next = NULL; p->off_heap.first = NULL; p->off_heap.overhead = 0; + p->wrt_bins = NULL; p->common.u.alive.reg = NULL; p->heap_sz = 0; p->high_water = NULL; @@ -12794,11 +13004,13 @@ void erts_init_empty_process(Process *p) p->sig_qs.len = 0; p->sig_qs.nmsigs.next = NULL; p->sig_qs.nmsigs.last = NULL; + p->sig_inq_contention_counter = 0; p->sig_inq.first = NULL; p->sig_inq.last = &p->sig_inq.first; p->sig_inq.len = 0; p->sig_inq.nmsigs.next = NULL; p->sig_inq.nmsigs.last = NULL; + erts_atomic_init_nob(&p->sig_inq_buffers, (erts_aint_t)NULL); #ifdef ERTS_PROC_SIG_HARD_DEBUG p->sig_inq.may_contain_heap_terms = 0; #endif @@ -12827,7 +13039,7 @@ void erts_init_empty_process(Process *p) p->def_arg_reg[4] = 0; p->def_arg_reg[5] = 0; - p->parent = NIL; + p->parent = am_undefined; p->static_flags = 0; p->common.u.alive.started_interval = 0; @@ -12837,7 +13049,7 @@ void erts_init_empty_process(Process *p) p->last_old_htop = NULL; #endif - erts_atomic32_init_nob(&p->dirty_state, 0); + erts_atomic32_init_nob(&p->xstate, 0); p->dirty_sys_tasks = NULL; erts_atomic32_init_nob(&p->state, (erts_aint32_t) PRIORITY_NORMAL); @@ -12882,7 +13094,7 @@ erts_debug_verify_clean_empty_process(Process* p) ASSERT(p->i == NULL); ASSERT(p->current == NULL); - ASSERT(p->parent == NIL); + ASSERT(p->parent == am_undefined); ASSERT(p->sig_inq.first == NULL); ASSERT(p->sig_inq.len == 0); @@ -12891,6 +13103,7 @@ erts_debug_verify_clean_empty_process(Process* p) ASSERT(p->off_heap.first == NULL); ASSERT(p->off_heap.overhead == 0); + ASSERT(p->wrt_bins == NULL); ASSERT(p->mbuf == NULL); } @@ -12902,9 +13115,11 @@ erts_cleanup_empty_process(Process* p) { /* We only check fields that are known to be used... */ - erts_cleanup_offheap(&p->off_heap); + erts_cleanup_offheap_list(p->off_heap.first); p->off_heap.first = NULL; p->off_heap.overhead = 0; + erts_cleanup_offheap_list(p->wrt_bins); + p->wrt_bins = NULL; if (p->mbuf != NULL) { free_message_buffer(p->mbuf); @@ -12921,7 +13136,7 @@ delete_process(Process* p) { ErtsPSD *psd; struct saved_calls *scb; - process_breakpoint_time_t *pbt; + process_breakpoint_trace_t *pbt; Uint32 block_rla_ref = (Uint32) (Uint) p->u.terminate; VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->common.id)); @@ -12942,6 +13157,9 @@ delete_process(Process* p) } pbt = ERTS_PROC_SET_CALL_TIME(p, NULL); + if (pbt) + erts_free(ERTS_ALC_T_BPD, (void *) pbt); + pbt = ERTS_PROC_SET_CALL_MEMORY(p, NULL); if (pbt) erts_free(ERTS_ALC_T_BPD, (void *) pbt); @@ -12958,6 +13176,7 @@ delete_process(Process* p) /* Clean binaries and funs */ erts_cleanup_offheap(&p->off_heap); + erts_cleanup_offheap_list(p->wrt_bins); /* * The mso list should not be used anymore, but if it is, make sure that @@ -13038,7 +13257,7 @@ erts_set_self_exiting(Process *c_p, Eterm reason) erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); set_self_exiting(c_p, reason, &enqueue, &enq_prio, &state); - c_p->freason = EXTAG_EXIT; + c_p->freason = EXTAG_EXIT | EXF_PANIC; KILL_CATCHES(c_p); c_p->i = beam_exit; @@ -13319,7 +13538,9 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt, Sint reds) switch (mon->type) { case ERTS_MON_TYPE_SUSPEND: case ERTS_MON_TYPE_PROC: - erts_proc_sig_send_monitor_down(mon, reason); + erts_proc_sig_send_monitor_down(&c_p->common, + c_p->common.id, + mon, reason); mon = NULL; break; case ERTS_MON_TYPE_PORT: { @@ -13400,7 +13621,7 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt, Sint reds) switch (mon->type) { case ERTS_MON_TYPE_SUSPEND: case ERTS_MON_TYPE_PROC: - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(&c_p->common, c_p->common.id, 0, mon); mon = NULL; break; case ERTS_MON_TYPE_TIME_OFFSET: @@ -13584,7 +13805,7 @@ erts_proc_exit_handle_link(ErtsLink *lnk, void *vctxt, Sint reds) ASSERT(is_internal_pid(lnk->other.item)); if (((ErtsILink *) lnk)->unlinking) break; - erts_proc_sig_send_link_exit(c_p, c_p->common.id, lnk, + erts_proc_sig_send_link_exit(&c_p->common, c_p->common.id, lnk, reason, SEQ_TRACE_TOKEN(c_p)); lnk = NULL; break; @@ -13869,7 +14090,7 @@ erts_continue_exit_process(Process *p) * * - A non-immediate exit reason may refer to literals. * - A process executing dirty while terminated, might access - * any term on the heap, and therfore literals, until it has + * any term on the heap, and therefore literals, until it has * stopped executing dirty. */ if (!trap_state->block_rla_ref @@ -14015,6 +14236,7 @@ erts_continue_exit_process(Process *p) erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_queue_flush_and_deinstall_buffers(p); erts_proc_sig_fetch(p); erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); @@ -14309,7 +14531,9 @@ erts_try_lock_sig_free_proc(Eterm pid, ErtsProcLocks locks, erts_aint32_t *statep) { Process *rp = erts_proc_lookup_raw(pid); - erts_aint32_t fail_state = ERTS_PSFLG_SIG_IN_Q|ERTS_PSFLG_SIG_Q; + erts_aint32_t fail_state = (ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_NMSG_SIG_IN_Q + | ERTS_PSFLG_MSG_SIG_IN_Q); erts_aint32_t state; ErtsProcLocks tmp_locks = ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ; @@ -14710,6 +14934,7 @@ void erts_halt(int code) ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING); ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING); erts_halt_code = code; + erts_nif_notify_halt(); } } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 21799577296a..b266dc556182 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -283,7 +283,7 @@ typedef enum { /* * Keep ERTS_SSI_AUX_WORK flags ordered in expected frequency - * order relative eachother. Most frequent at lowest at lowest + * order relative each other. Most frequent at lowest at lowest * index. * * ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED_IX *need* to be @@ -581,6 +581,7 @@ typedef struct ErtsAuxWorkData_ { UWord size; ErtsThrPrgrLaterOp *first; ErtsThrPrgrLaterOp *last; + Uint list_len; } later_op; struct { int need_thr_prgr; @@ -664,11 +665,11 @@ typedef struct ErtsSchedulerRegisters_ { ErtsCodePtr start_time_i; UWord start_time; -#if !defined(NATIVE_ERLANG_STACK) && defined(JIT_HARD_DEBUG) +#if (!defined(NATIVE_ERLANG_STACK) || defined(__aarch64__)) && defined(JIT_HARD_DEBUG) /* Holds the initial thread stack pointer. Used to ensure that everything * that is pushed to the stack is also popped. */ UWord *initial_sp; -#elif defined(NATIVE_ERLANG_STACK) && defined(DEBUG) +#elif defined(NATIVE_ERLANG_STACK) && defined(DEBUG) && !defined(__aarch64__) /* Raw pointers to the start and end of the stack. Used to test bounds * without clobbering any registers. */ UWord *runtime_stack_start; @@ -727,7 +728,10 @@ struct ErtsSchedulerData_ { ErtsSchedWallTime sched_wall_time; ErtsGCInfo gc_info; ErtsPortTaskHandle nosuspend_port_task_handle; - ErtsEtsTables ets_tables; + union { + ErtsEtsTables ets_tables; + erts_atomic32_t dirty_nif_halt_info; + } u; #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC erts_alloc_verify_func_t verify_unused_temp_alloc; Allctr_t *verify_unused_temp_alloc_data; @@ -867,9 +871,10 @@ erts_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi) #define ERTS_PSD_ETS_OWNED_TABLES 6 #define ERTS_PSD_ETS_FIXED_TABLES 7 #define ERTS_PSD_DIST_ENTRY 8 -#define ERTS_PSD_PENDING_SUSPEND 9 /* keep last... */ +#define ERTS_PSD_PENDING_SUSPEND 9 +#define ERTS_PSD_CALL_MEMORY_BP 10 -#define ERTS_PSD_SIZE 10 +#define ERTS_PSD_SIZE 11 typedef struct { void *data[ERTS_PSD_SIZE]; @@ -957,6 +962,21 @@ typedef struct ErtsProcSysTaskQs_ ErtsProcSysTaskQs; (ASSERT((p)->htop <= (p)->stop), \ MAX((p)->htop, (p)->stop - S_REDZONE)) +#ifdef ERLANG_FRAME_POINTERS +/* The current frame pointer on the Erlang stack. */ +# define FRAME_POINTER(p) (p)->frame_pointer +#else +/* We define this to a trapping lvalue when frame pointers are unsupported to + * provoke crashes when used without checking `erts_frame_layout`. The checks + * will always be optimized out because the variable is hardcoded to + * `ERTS_FRAME_LAYOUT_RA`. */ +# define FRAME_POINTER(p) (((Eterm ** volatile)0xbadf00d)[0]) + +# ifndef erts_frame_layout +# error "erts_frame_layout has not been hardcoded to ERTS_FRAME_LAYOUT_RA" +# endif +#endif + # define HEAP_END(p) (p)->hend # define HEAP_SIZE(p) (p)->heap_sz # define STACK_START(p) (p)->hend @@ -974,19 +994,15 @@ typedef struct ErtsProcSysTaskQs_ ErtsProcSysTaskQs; # define MSO(p) (p)->off_heap # define MIN_HEAP_SIZE(p) (p)->min_heap_size -# define MIN_VHEAP_SIZE(p) (p)->min_vheap_size -# define BIN_VHEAP_SZ(p) (p)->bin_vheap_sz -# define BIN_OLD_VHEAP_SZ(p) (p)->bin_old_vheap_sz -# define BIN_OLD_VHEAP(p) (p)->bin_old_vheap - -# define MAX_HEAP_SIZE_GET(p) ((p)->max_heap_size >> 2) -# define MAX_HEAP_SIZE_SET(p, sz) ((p)->max_heap_size = ((sz) << 2) | \ +# define MAX_HEAP_SIZE_GET(p) ((p)->max_heap_size >> 3) +# define MAX_HEAP_SIZE_SET(p, sz) ((p)->max_heap_size = ((sz) << 3) | \ MAX_HEAP_SIZE_FLAGS_GET(p)) -# define MAX_HEAP_SIZE_FLAGS_GET(p) ((p)->max_heap_size & 0x3) +# define MAX_HEAP_SIZE_FLAGS_GET(p) ((p)->max_heap_size & 0x7) # define MAX_HEAP_SIZE_FLAGS_SET(p, flags) ((p)->max_heap_size = flags | \ - ((p)->max_heap_size & ~0x3)) + ((p)->max_heap_size & ~0x7)) # define MAX_HEAP_SIZE_KILL 1 # define MAX_HEAP_SIZE_LOG 2 +# define MAX_HEAP_SIZE_INCLUDE_OH_BINS 4 struct process { ErtsPTabElementCommon common; /* *Need* to be first in struct */ @@ -996,8 +1012,13 @@ struct process { * shorter instruction can be used to access them. */ - Eterm* htop; /* Heap top */ - Eterm* stop; /* Stack top */ + Eterm *htop; /* Heap top */ + Eterm *stop; /* Stack top */ + +#ifdef ERLANG_FRAME_POINTERS + Eterm *frame_pointer; /* Frame pointer */ +#endif + Sint fcalls; /* Number of reductions left to execute. * Only valid for the current process. */ @@ -1046,7 +1067,7 @@ struct process { Eterm seq_trace_token; /* Sequential trace token (tuple size 5 see below) */ #ifdef USE_VM_PROBES - Eterm dt_utag; /* Place to store the dynamc trace user tag */ + Eterm dt_utag; /* Place to store the dynamic trace user tag */ Uint dt_utag_flags; /* flag field for the dt_utag */ #endif union { @@ -1083,6 +1104,7 @@ struct process { Uint16 gen_gcs; /* Number of (minor) generational GCs. */ Uint16 max_gen_gcs; /* Max minor gen GCs before fullsweep. */ ErlOffHeap off_heap; /* Off-heap data updated by copy_struct(). */ + struct erl_off_heap_header* wrt_bins; /* Writable binaries */ ErlHeapFragment* mbuf; /* Pointer to heap fragment list */ ErlHeapFragment* live_hf_end; ErtsMessage *msg_frag; /* Pointer to message fragment list */ @@ -1096,10 +1118,11 @@ struct process { ErtsProcSysTaskQs *sys_task_qs; ErtsProcSysTask *dirty_sys_tasks; - erts_atomic32_t state; /* Process state flags (see ERTS_PSFLG_*) */ - erts_atomic32_t dirty_state; /* Process dirty state flags (see ERTS_PDSFLG_*) */ - + erts_atomic32_t state; /* Process state flags (see ERTS_PSFLG_*) */ + erts_atomic32_t xstate; /* Process extra state flags (see ERTS_PXSFLG_*) */ + Uint sig_inq_contention_counter; ErtsSignalInQueue sig_inq; + erts_atomic_t sig_inq_buffers; ErlTraceMessageQueue *trace_msg_q; erts_proc_lock_t lock; ErtsSchedulerData *scheduler_data; @@ -1224,8 +1247,9 @@ void erts_check_for_holes(Process* p); process table. Always ACTIVE while EXITING. Never SUSPENDED unless also FREE. */ #define ERTS_PSFLG_EXITING ERTS_PSFLG_BIT(5) -/* UNUSED */ -#define ERTS_PSFLG_UNUSED ERTS_PSFLG_BIT(6) +/* MSG_SIG_IN_Q - Have unhandled message signals in signal + in-queue */ +#define ERTS_PSFLG_MSG_SIG_IN_Q ERTS_PSFLG_BIT(6) /* ACTIVE - Process "wants" to execute */ #define ERTS_PSFLG_ACTIVE ERTS_PSFLG_BIT(7) /* IN_RUNQ - Real process (not proxy) struct used in a @@ -1233,15 +1257,16 @@ void erts_check_for_holes(Process* p); #define ERTS_PSFLG_IN_RUNQ ERTS_PSFLG_BIT(8) /* RUNNING - Executing in process_main() */ #define ERTS_PSFLG_RUNNING ERTS_PSFLG_BIT(9) -/* SUSPENDED - Process suspended; supress active but +/* SUSPENDED - Process suspended; suppress active but not active-sys nor dirty-active-sys */ #define ERTS_PSFLG_SUSPENDED ERTS_PSFLG_BIT(10) /* GC - gc */ #define ERTS_PSFLG_GC ERTS_PSFLG_BIT(11) /* SYS_TASKS - Have normal system tasks scheduled */ #define ERTS_PSFLG_SYS_TASKS ERTS_PSFLG_BIT(12) -/* SIG_IN_Q - Have unhandled signals in signal in-queue */ -#define ERTS_PSFLG_SIG_IN_Q ERTS_PSFLG_BIT(13) +/* NMSG_SIG_IN_Q - Have unhandled non-message signals in + signal in-queue */ +#define ERTS_PSFLG_NMSG_SIG_IN_Q ERTS_PSFLG_BIT(13) /* ACTIVE_SYS - Process "wants" to execute normal system tasks or handle signals */ #define ERTS_PSFLG_ACTIVE_SYS ERTS_PSFLG_BIT(14) @@ -1298,30 +1323,33 @@ void erts_check_for_holes(Process* p); /* - * Flags in the dirty_state field. + * Flags in the xstate field. */ -#define ERTS_PDSFLG_IN_CPU_PRQ_MAX (((erts_aint32_t) 1) << 0) -#define ERTS_PDSFLG_IN_CPU_PRQ_HIGH (((erts_aint32_t) 1) << 1) -#define ERTS_PDSFLG_IN_CPU_PRQ_NORMAL (((erts_aint32_t) 1) << 2) -#define ERTS_PDSFLG_IN_CPU_PRQ_LOW (((erts_aint32_t) 1) << 3) -#define ERTS_PDSFLG_IN_IO_PRQ_MAX (((erts_aint32_t) 1) << 4) -#define ERTS_PDSFLG_IN_IO_PRQ_HIGH (((erts_aint32_t) 1) << 5) -#define ERTS_PDSFLG_IN_IO_PRQ_NORMAL (((erts_aint32_t) 1) << 6) -#define ERTS_PDSFLG_IN_IO_PRQ_LOW (((erts_aint32_t) 1) << 7) - -#define ERTS_PDSFLGS_QMASK ERTS_PSFLGS_QMASK -#define ERTS_PDSFLGS_IN_CPU_PRQ_MASK_OFFSET 0 -#define ERTS_PDSFLGS_IN_IO_PRQ_MASK_OFFSET ERTS_PSFLGS_QMASK_BITS - -#define ERTS_PDSFLG_IN_CPU_PRQ_MASK (ERTS_PDSFLG_IN_CPU_PRQ_MAX \ - | ERTS_PDSFLG_IN_CPU_PRQ_HIGH \ - | ERTS_PDSFLG_IN_CPU_PRQ_NORMAL\ - | ERTS_PDSFLG_IN_CPU_PRQ_LOW) -#define ERTS_PDSFLG_IN_IO_PRQ_MASK (ERTS_PDSFLG_IN_CPU_PRQ_MAX \ - | ERTS_PDSFLG_IN_CPU_PRQ_HIGH \ - | ERTS_PDSFLG_IN_CPU_PRQ_NORMAL\ - | ERTS_PDSFLG_IN_CPU_PRQ_LOW) +#define ERTS_PXSFLG_IN_CPU_PRQ_MAX (((erts_aint32_t) 1) << 0) +#define ERTS_PXSFLG_IN_CPU_PRQ_HIGH (((erts_aint32_t) 1) << 1) +#define ERTS_PXSFLG_IN_CPU_PRQ_NORMAL (((erts_aint32_t) 1) << 2) +#define ERTS_PXSFLG_IN_CPU_PRQ_LOW (((erts_aint32_t) 1) << 3) +#define ERTS_PXSFLG_IN_IO_PRQ_MAX (((erts_aint32_t) 1) << 4) +#define ERTS_PXSFLG_IN_IO_PRQ_HIGH (((erts_aint32_t) 1) << 5) +#define ERTS_PXSFLG_IN_IO_PRQ_NORMAL (((erts_aint32_t) 1) << 6) +#define ERTS_PXSFLG_IN_IO_PRQ_LOW (((erts_aint32_t) 1) << 7) +/* MAYBE_SELF_SIGS - We might have outstanding signals + from ourselves to ourselves. */ +#define ERTS_PXSFLG_MAYBE_SELF_SIGS (((erts_aint32_t) 1) << 8) + +#define ERTS_PXSFLGS_QMASK ERTS_PSFLGS_QMASK +#define ERTS_PXSFLGS_IN_CPU_PRQ_MASK_OFFSET 0 +#define ERTS_PXSFLGS_IN_IO_PRQ_MASK_OFFSET ERTS_PSFLGS_QMASK_BITS + +#define ERTS_PXSFLG_IN_CPU_PRQ_MASK (ERTS_PXSFLG_IN_CPU_PRQ_MAX \ + | ERTS_PXSFLG_IN_CPU_PRQ_HIGH \ + | ERTS_PXSFLG_IN_CPU_PRQ_NORMAL\ + | ERTS_PXSFLG_IN_CPU_PRQ_LOW) +#define ERTS_PXSFLG_IN_IO_PRQ_MASK (ERTS_PXSFLG_IN_CPU_PRQ_MAX \ + | ERTS_PXSFLG_IN_CPU_PRQ_HIGH \ + | ERTS_PXSFLG_IN_CPU_PRQ_NORMAL\ + | ERTS_PXSFLG_IN_CPU_PRQ_LOW) /* @@ -1386,8 +1414,9 @@ void erts_check_for_holes(Process* p); #define SPO_IX_ASYNC 11 #define SPO_IX_NO_SMSG 12 #define SPO_IX_NO_EMSG 13 +#define SPO_IX_ASYNC_DIST 14 -#define SPO_NO_INDICES (SPO_IX_ASYNC+1) +#define SPO_NO_INDICES (SPO_IX_ASYNC_DIST+1) #define SPO_LINK (1 << SPO_IX_LINK) #define SPO_MONITOR (1 << SPO_IX_MONITOR) @@ -1403,8 +1432,9 @@ void erts_check_for_holes(Process* p); #define SPO_ASYNC (1 << SPO_IX_ASYNC) #define SPO_NO_SMSG (1 << SPO_IX_NO_SMSG) #define SPO_NO_EMSG (1 << SPO_IX_NO_EMSG) +#define SPO_ASYNC_DIST (1 << SPO_IX_ASYNC_DIST) -#define SPO_MAX_FLAG SPO_NO_EMSG +#define SPO_MAX_FLAG SPO_ASYNC_DIST #define SPO_USE_ARGS \ (SPO_MIN_HEAP_SIZE \ @@ -1545,15 +1575,25 @@ extern int erts_system_profile_ts_type; #define F_TRAP_EXIT (1 << 22) /* Trapping exit */ #define F_FRAGMENTED_SEND (1 << 23) /* Process is doing a distributed fragmented send */ #define F_DBG_FORCED_TRAP (1 << 24) /* DEBUG: Last BIF call was a forced trap */ +#define F_DIRTY_CHECK_CLA (1 << 25) /* Check if copy literal area GC scheduled */ +#define F_ASYNC_DIST (1 << 26) /* Truly asynchronous distribution */ /* Signal queue flags */ #define FS_OFF_HEAP_MSGQ (1 << 0) /* Off heap msg queue */ #define FS_ON_HEAP_MSGQ (1 << 1) /* On heap msg queue */ #define FS_OFF_HEAP_MSGQ_CHNG (1 << 2) /* Off heap msg queue changing */ -#define FS_LOCAL_SIGS_ONLY (1 << 3) /* Handle privq sigs only */ +#define FS_UNUSED (1 << 3) /* Unused */ #define FS_HANDLING_SIGS (1 << 4) /* Process is handling signals */ #define FS_WAIT_HANDLE_SIGS (1 << 5) /* Process is waiting to handle signals */ #define FS_DELAYED_PSIGQS_LEN (1 << 6) /* Delayed update of sig_qs.len */ +#define FS_FLUSHING_SIGS (1 << 7) /* Currently flushing signals */ +#define FS_FLUSHED_SIGS (1 << 8) /* Flushing of signals completed */ +#define FS_NON_FETCH_CNT1 (1 << 9) /* First bit of non-fetch signals counter */ +#define FS_NON_FETCH_CNT2 (1 << 10)/* Second bit of non-fetch signals counter */ +#define FS_NON_FETCH_CNT4 (1 << 11)/* Third bit of non-fetch signals counter */ + +#define FS_NON_FETCH_CNT_MASK \ + (FS_NON_FETCH_CNT1|FS_NON_FETCH_CNT2|FS_NON_FETCH_CNT4) /* * F_DISABLE_GC and F_DELAY_GC are similar. Both will prevent @@ -1725,9 +1765,9 @@ Uint64 erts_get_proc_interval(void); Uint64 erts_ensure_later_proc_interval(Uint64); Uint64 erts_step_proc_interval(void); -ErtsProcList *erts_proclist_create(Process *); -ErtsProcList *erts_proclist_copy(ErtsProcList *); void erts_proclist_destroy(ErtsProcList *); +ErtsProcList *erts_proclist_create(Process *) ERTS_ATTR_MALLOC_D(erts_proclist_destroy,1); +ErtsProcList *erts_proclist_copy(ErtsProcList *); void erts_proclist_dump(fmtfn_t to, void *to_arg, ErtsProcList*); ERTS_GLB_INLINE int erts_proclist_same(ErtsProcList *, Process *); @@ -1909,7 +1949,7 @@ void erts_schedule_thr_prgr_later_cleanup_op(void (*)(void *), ErtsThrPrgrLaterOp *, UWord); void erts_schedule_complete_off_heap_message_queue_change(Eterm pid); -void erts_schedule_cla_gc(Process *c_p, Eterm to, Eterm req_id); +void erts_schedule_cla_gc(Process *c_p, Eterm to, Eterm req_id, int check); struct db_fixation; void erts_schedule_ets_free_fixation(Eterm pid, struct db_fixation*); void erts_schedule_flush_trace_messages(Process *proc, int force_on_proc); @@ -2066,18 +2106,9 @@ erts_aint32_t erts_proc_sys_schedule(Process *p, erts_aint32_t state, erts_aint32_t enable_flag); int erts_have_non_prio_elev_sys_tasks(Process *c_p, ErtsProcLocks locks); -ERTS_GLB_INLINE void erts_proc_notify_new_message(Process *p, ErtsProcLocks locks); ERTS_GLB_INLINE void erts_schedule_dirty_sys_execution(Process *c_p); #if ERTS_GLB_INLINE_INCL_FUNC_DEF -ERTS_GLB_INLINE void -erts_proc_notify_new_message(Process *p, ErtsProcLocks locks) -{ - /* No barrier needed, due to msg lock */ - erts_aint32_t state = erts_atomic32_read_nob(&p->state); - if (!(state & ERTS_PSFLG_ACTIVE)) - erts_schedule_process(p, state, locks); -} ERTS_GLB_INLINE void erts_schedule_dirty_sys_execution(Process *c_p) @@ -2204,9 +2235,9 @@ erts_psd_set(Process *p, int ix, void *data) ((struct saved_calls *) erts_psd_set((P), ERTS_PSD_SAVED_CALLS_BUF, (void *) (SCB))) #define ERTS_PROC_GET_CALL_TIME(P) \ - ((process_breakpoint_time_t *) erts_psd_get((P), ERTS_PSD_CALL_TIME_BP)) + ((process_breakpoint_trace_t *) erts_psd_get((P), ERTS_PSD_CALL_TIME_BP)) #define ERTS_PROC_SET_CALL_TIME(P, PBT) \ - ((process_breakpoint_time_t *) erts_psd_set((P), ERTS_PSD_CALL_TIME_BP, (void *) (PBT))) + ((process_breakpoint_trace_t *) erts_psd_set((P), ERTS_PSD_CALL_TIME_BP, (void *) (PBT))) #define ERTS_PROC_GET_DELAYED_GC_TASK_QS(P) \ ((ErtsProcSysTaskQs *) erts_psd_get((P), ERTS_PSD_DELAYED_GC_TASK_QS)) @@ -2228,6 +2259,11 @@ erts_psd_set(Process *p, int ix, void *data) #define ERTS_PROC_SET_PENDING_SUSPEND(P, PS) \ ((void *) erts_psd_set((P), ERTS_PSD_PENDING_SUSPEND, (void *) (PS))) +#define ERTS_PROC_GET_CALL_MEMORY(P) \ + ((process_breakpoint_trace_t *) erts_psd_get((P), ERTS_PSD_CALL_MEMORY_BP)) +#define ERTS_PROC_SET_CALL_MEMORY(P, PBT) \ + ((process_breakpoint_trace_t *) erts_psd_set((P), ERTS_PSD_CALL_MEMORY_BP, (void *) (PBT))) + ERTS_GLB_INLINE Eterm erts_proc_get_error_handler(Process *p); ERTS_GLB_INLINE Eterm erts_proc_set_error_handler(Process *p, Eterm handler); @@ -2495,7 +2531,7 @@ erts_init_runq_proc(Process *p, ErtsRunQueue *rq, int bnd) * @param bndp[in,out] Pointer to integer. On input non-zero * value causes the process to be bound to * the run-queue. On output, indicating - * wether process previously was bound or + * whether process previously was bound or * not. * @return Previous run-queue. */ @@ -2574,7 +2610,7 @@ erts_bind_runq_proc(Process *p, int bind) } /** - * Determine wether a process is bound to a run-queue or not. + * Determine whether a process is bound to a run-queue or not. * * @return Returns a non-zero value if bound, * and zero of not bound. @@ -2596,7 +2632,7 @@ erts_proc_runq_is_bound(Process *p) * value if the process is bound to the * run-queue. * @return Pointer to the normal run-queue that - * the process currently is assigend to. + * the process currently is assigned to. * A process is always assigned to a * normal run-queue. */ diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index ce46af8fbab4..d1b8b46fd3c9 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2021. All Rights Reserved. + * Copyright Ericsson AB 2003-2023. 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. @@ -159,9 +159,12 @@ Uint erts_process_memory(Process *p, int include_sigs_in_transit) * Size of message queue plus size of all signals * in transit to the process! */ - erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(p); - erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + if (!(p->sig_qs.flags & FS_FLUSHING_SIGS) + || ERTS_IS_CRASH_DUMPING) { + erts_proc_sig_queue_lock(p); + erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + } ERTS_FOREACH_SIG_PRIVQS( p, mp, @@ -228,7 +231,9 @@ dump_process_info(fmtfn_t to, void *to_arg, Process *p) if (ERTS_TRACE_FLAGS(p) & F_SENSITIVE) return; - erts_proc_sig_fetch(p); + if (!(p->sig_qs.flags & FS_FLUSHING_SIGS) || ERTS_IS_CRASH_DUMPING) { + erts_proc_sig_fetch(p); + } if (p->sig_qs.first || p->sig_qs.cont) { erts_print(to, to_arg, "=proc_messages:%T\n", p->common.id); @@ -708,7 +713,7 @@ dump_externally(fmtfn_t to, void *to_arg, Eterm term) byte* s; byte* p; - if (is_fun(term)) { + if (is_any_fun(term)) { /* * The fun's environment used to cause trouble. There were * two kind of problems: @@ -1123,8 +1128,8 @@ erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg) erts_print(to, to_arg, "FREE"); break; case ERTS_PSFLG_EXITING: erts_print(to, to_arg, "EXITING"); break; - case ERTS_PSFLG_UNUSED: - erts_print(to, to_arg, "UNUSED"); break; + case ERTS_PSFLG_MSG_SIG_IN_Q: + erts_print(to, to_arg, "MSG_SIG_IN_Q"); break; case ERTS_PSFLG_ACTIVE: erts_print(to, to_arg, "ACTIVE"); break; case ERTS_PSFLG_IN_RUNQ: @@ -1137,8 +1142,8 @@ erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg) erts_print(to, to_arg, "GC"); break; case ERTS_PSFLG_SYS_TASKS: erts_print(to, to_arg, "SYS_TASKS"); break; - case ERTS_PSFLG_SIG_IN_Q: - erts_print(to, to_arg, "SIG_IN_Q"); break; + case ERTS_PSFLG_NMSG_SIG_IN_Q: + erts_print(to, to_arg, "NMSG_SIG_IN_Q"); break; case ERTS_PSFLG_ACTIVE_SYS: erts_print(to, to_arg, "ACTIVE_SYS"); break; case ERTS_PSFLG_RUNNING_SYS: diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index 5cd7c14b91d2..ae7a25e2fbad 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -31,7 +31,7 @@ * queues. * The bit field contains of a number of lock flags (L1, L2, ...) * and a number of wait flags (W1, W2, ...). Each lock flag has a - * corresponding wait flag. The bit field isn't guarranteed to be + * corresponding wait flag. The bit field isn't guaranteed to be * larger than 32-bits which sets a maximum of 16 different locks * per process. Currently, only 4 locks per process are used. The * bit field is operated on by use of atomic operations (custom @@ -221,9 +221,9 @@ dequeue_waiter(erts_proc_lock_t *lck, int ix) } /* - * Tries to aquire as many locks as possible in lock order, + * Tries to acquire as many locks as possible in lock order, * and sets the wait flag on the first lock not possible to - * aquire. + * acquire. * * Note: We need the pix lock during this operation. Wait * flags are only allowed to be manipulated under pix @@ -274,7 +274,7 @@ try_aquire(erts_proc_lock_t *lck, erts_tse_t *wtr) /* * Transfer 'trnsfr_lcks' held by this executing thread to other * threads waiting for the locks. When a lock has been transferred - * we also have to try to aquire as many lock as possible for the + * we also have to try to acquire as many lock as possible for the * other thread. */ static int @@ -416,7 +416,7 @@ wait_for_locks(Process *p, check_queue(&p->lock); #endif - /* Try to aquire locks one at a time in lock order and set wait flag */ + /* Try to acquire locks one at a time in lock order and set wait flag */ try_aquire(&p->lock, wtr); ASSERT((wtr->uflgs & ~ERTS_PROC_LOCKS_ALL) == 0); @@ -444,7 +444,7 @@ wait_for_locks(Process *p, /* * Wait for needed locks. When we are woken all needed locks have - * have been acquired by other threads and transfered to us. + * have been acquired by other threads and transferred to us. * However, we need to be prepared for spurious wakeups. */ do { diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 70ff3baf4963..76e8616280e3 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2021. All Rights Reserved. + * Copyright Ericsson AB 2007-2023. 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. @@ -229,7 +229,7 @@ typedef struct erts_proc_lock_t_ { #ifndef ERTS_PROC_LOCK_LOCK_CHECK__ #define ERTS_PROC_LOCK_LOCK_CHECK__ -/* Lock counter implemetation */ +/* Lock counter implementation */ #ifdef ERTS_ENABLE_LOCK_POSITION #define erts_proc_lock__(P,I,L) erts_proc_lock_x__(P,I,L,__FILE__,__LINE__) @@ -462,6 +462,9 @@ typedef struct { #define ERTS_PROC_LOCK_FLGS_READ_(L) \ ((ErtsProcLocks) erts_atomic32_read_nob(&(L)->flags)) +#define ERTS_PROC_LOCK_FLGS_READ_ACQB_(L) \ + ((ErtsProcLocks) erts_atomic32_read_acqb(&(L)->flags)) + #else /* no opt atomic ops */ ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_band(erts_proc_lock_t *, @@ -509,6 +512,7 @@ erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *lck, ErtsProcLocks new, #define ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(L, NEW, EXPECTED) \ erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED)) #define ERTS_PROC_LOCK_FLGS_READ_(L) ((L)->flags) +#define ERTS_PROC_LOCK_FLGS_READ_ACQB_(L) ((L)->flags) #endif /* end no opt atomic ops */ #endif /* ERTS_PROC_LOCK_OWN_IMPL */ @@ -918,6 +922,8 @@ ERTS_GLB_INLINE void erts_proc_lock(Process *, ErtsProcLocks); #endif ERTS_GLB_INLINE void erts_proc_unlock(Process *, ErtsProcLocks); ERTS_GLB_INLINE int erts_proc_trylock(Process *, ErtsProcLocks); +ERTS_GLB_INLINE void +erts_proc_lock_wait_until_released(Process *p, ErtsProcLocks locks); ERTS_GLB_INLINE void erts_proc_inc_refc(Process *); ERTS_GLB_INLINE void erts_proc_dec_refc(Process *); @@ -979,6 +985,51 @@ erts_proc_trylock(Process *p, ErtsProcLocks locks) locks); } +ERTS_GLB_INLINE void +erts_proc_lock_wait_until_released(Process *p, ErtsProcLocks locks) +{ +#if ERTS_PROC_LOCK_OWN_IMPL +#if !ERTS_PROC_LOCK_ATOMIC_IMPL + Uint32 was_locked; + erts_pix_lock_t *pix_lck = ERTS_PID2PIXLOCK(p->common.id); + erts_pix_lock(pix_lck); + was_locked = (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks); + erts_pix_unlock(pix_lck); + if (was_locked) { + erts_proc_lock(p, locks); + erts_proc_unlock(p, locks); + } +#else + ETHR_MEMBAR(ETHR_StoreLoad | ETHR_LoadLoad); + if (ERTS_PROC_LOCK_FLGS_READ_ACQB_(&p->lock) & locks) { + erts_proc_lock(p, locks); + erts_proc_unlock(p, locks); + } +#endif +#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL + if (locks & ERTS_PROC_LOCK_MAIN) { + erts_mtx_lock(&p->lock.main); + erts_mtx_unlock(&p->lock.main); + } + if (locks & ERTS_PROC_LOCK_MSGQ) { + erts_mtx_lock(&p->lock.msgq); + erts_mtx_unlock(&p->lock.msgq); + } + if (locks & ERTS_PROC_LOCK_BTM) { + erts_mtx_lock(&p->lock.btm); + erts_mtx_unlock(&p->lock.btm); + } + if (locks & ERTS_PROC_LOCK_STATUS) { + erts_mtx_lock(&p->lock.status); + erts_mtx_unlock(&p->lock.status); + } + if (locks & ERTS_PROC_LOCK_TRACE) { + erts_mtx_lock(&p->lock.trace); + erts_mtx_unlock(&p->lock.trace); + } +#endif +} + ERTS_GLB_INLINE void erts_proc_inc_refc(Process *p) { ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY)); diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index cc91bdbf0a38..37408860918c 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2021. All Rights Reserved. + * Copyright Ericsson AB 2012-2023. 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. @@ -391,7 +391,7 @@ erts_ptab_init_table(ErtsPTab *ptab, tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic_t)); alloc_sz = tab_sz; if (!legacy) - alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic32_t)); + alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic_t)); ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, alloc_sz); tab_end = ((char *) ptab->r.o.tab) + tab_sz; tab_entry = ptab->r.o.tab; @@ -429,11 +429,11 @@ erts_ptab_init_table(ErtsPTab *ptab, } else { - tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic32_t)); - ptab->r.o.free_id_data = (erts_atomic32_t *) tab_end; + tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic_t)); + ptab->r.o.free_id_data = (erts_atomic_t *) tab_end; tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE; - ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_atomic32_t)); + ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_atomic_t)); ptab->r.o.dix_cl_mask = tab_cache_lines-1; ptab->r.o.dix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1); @@ -448,9 +448,9 @@ erts_ptab_init_table(ErtsPTab *ptab, ix = 0; for (cl = 0; cl < tab_cache_lines; cl++) { for (cli = 0; cli < ix_per_cache_line; cli++) { - erts_atomic32_init_nob(&ptab->r.o.free_id_data[ix], - cli*tab_cache_lines+cl); - ASSERT(erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data); + erts_atomic_init_nob(&ptab->r.o.free_id_data[ix], + cli*tab_cache_lines+cl); + ASSERT(erts_atomic_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data); ix++; } } @@ -500,7 +500,8 @@ erts_ptab_new_element(ErtsPTab *ptab, void *init_arg, void (*init_ptab_el)(void *, Eterm)) { - Uint32 pix, ix, data; + Uint32 pix, ix; + Uint data; erts_aint32_t count; erts_aint_t invalid = (erts_aint_t) ptab->r.o.invalid_element; @@ -532,8 +533,8 @@ erts_ptab_new_element(ErtsPTab *ptab, ix = (Uint32) erts_atomic32_inc_read_acqb(&ptab->vola.tile.aid_ix); ix = ix_to_free_id_data_ix(ptab, ix); - data = erts_atomic32_xchg_nob(&ptab->r.o.free_id_data[ix], - (erts_aint32_t)ptab->r.o.invalid_data); + data = erts_atomic_xchg_nob(&ptab->r.o.free_id_data[ix], + (erts_aint_t) ptab->r.o.invalid_data); }while ((Eterm)data == ptab->r.o.invalid_data); init_ptab_el(init_arg, (Eterm) data); @@ -673,7 +674,8 @@ erts_ptab_delete_element(ErtsPTab *ptab, ErtsPTabElementCommon *ptab_el) { int maybe_save; - Uint32 pix, ix, data; + Uint32 pix, ix; + Uint data; pix = erts_ptab_id2pix(ptab, ptab_el->id); @@ -690,14 +692,14 @@ erts_ptab_delete_element(ErtsPTab *ptab, erts_atomic_set_relb(&ptab->r.o.tab[pix], ERTS_AINT_NULL); if (ptab->r.o.free_id_data) { - Uint32 prev_data; + Uint prev_data; /* Next data for this slot... */ - data = (Uint32) erts_ptab_id2data(ptab, ptab_el->id); + data = erts_ptab_id2data(ptab, ptab_el->id); data += ptab->r.o.max; - data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE); + data &= ~(~UWORD_CONSTANT(0) << ERTS_PTAB_ID_DATA_SIZE); if (data == ptab->r.o.invalid_data) { /* make sure not invalid */ data += ptab->r.o.max; - data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE); + data &= ~(~UWORD_CONSTANT(0) << ERTS_PTAB_ID_DATA_SIZE); } ASSERT(data != ptab->r.o.invalid_data); ASSERT(pix == erts_ptab_data2pix(ptab, data)); @@ -706,9 +708,9 @@ erts_ptab_delete_element(ErtsPTab *ptab, ix = (Uint32) erts_atomic32_inc_read_relb(&ptab->vola.tile.fid_ix); ix = ix_to_free_id_data_ix(ptab, ix); - prev_data = erts_atomic32_cmpxchg_nob(&ptab->r.o.free_id_data[ix], - data, - ptab->r.o.invalid_data); + prev_data = erts_atomic_cmpxchg_nob(&ptab->r.o.free_id_data[ix], + data, + ptab->r.o.invalid_data); }while ((Eterm)prev_data != ptab->r.o.invalid_data); } @@ -828,8 +830,8 @@ cleanup_ptab_list_bif_data(Binary *bp) if (ptdep->prev) { /* - * Only remove this bif invokation when we - * have preceding invokations. + * Only remove this bif invocation when we + * have preceding invocations. */ ptdep->prev->next = ptdep->next; if (ptdep->next) @@ -851,7 +853,7 @@ cleanup_ptab_list_bif_data(Binary *bp) } else { /* - * Free all elements until next bif invokation + * Free all elements until next bif invocation * is found. */ ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep); @@ -1326,14 +1328,15 @@ static void assert_ptab_consistency(ErtsPTab *ptab) { #ifdef DEBUG if (ptab->r.o.free_id_data) { - Uint32 ix, pix, data; + Uint32 ix, pix; + Uint data; int free_pids = 0; int null_slots = 0; for (ix=0; ix < ptab->r.o.max; ix++) { - if (erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data) { + if (erts_atomic_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data) { ++free_pids; - data = erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]); + data = erts_atomic_read_nob(&ptab->r.o.free_id_data[ix]); pix = erts_ptab_data2pix(ptab, (Eterm) data); ASSERT(erts_ptab_pix2intptr_nob(ptab, pix) == ERTS_AINT_NULL); } @@ -1363,7 +1366,8 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next) Uint32 id_ix, dix; if (set) { - Uint32 i, max_ix, num, stop_id_ix; + Uint32 i, max_ix, stop_id_ix; + Uint num; max_ix = ptab->r.o.max - 1; num = next; id_ix = (Uint32) erts_atomic32_read_nob(&ptab->vola.tile.aid_ix); @@ -1371,16 +1375,16 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next) for (i=0; i <= max_ix; ++i) { Uint32 pix; ++num; - num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE); + num &= ~(~UWORD_CONSTANT(0) << ERTS_PTAB_ID_DATA_SIZE); if (num == ptab->r.o.invalid_data) { num += ptab->r.o.max; - num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE); + num &= ~(~UWORD_CONSTANT(0) << ERTS_PTAB_ID_DATA_SIZE); } pix = erts_ptab_data2pix(ptab, num); if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) { ++id_ix; dix = ix_to_free_id_data_ix(ptab, id_ix); - erts_atomic32_set_nob(&ptab->r.o.free_id_data[dix], num); + erts_atomic_set_nob(&ptab->r.o.free_id_data[dix], num); ASSERT(pix == erts_ptab_data2pix(ptab, num)); } } @@ -1393,13 +1397,13 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next) if (id_ix == stop_id_ix) break; dix = ix_to_free_id_data_ix(ptab, id_ix); - erts_atomic32_set_nob(&ptab->r.o.free_id_data[dix], - ptab->r.o.invalid_data); + erts_atomic_set_nob(&ptab->r.o.free_id_data[dix], + ptab->r.o.invalid_data); } } id_ix = (Uint32) erts_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1; dix = ix_to_free_id_data_ix(ptab, id_ix); - res = (Sint) erts_atomic32_read_nob(&ptab->r.o.free_id_data[dix]); + res = (Sint) erts_atomic_read_nob(&ptab->r.o.free_id_data[dix]); } else { /* Deprecated legacy algorithm... */ @@ -1477,7 +1481,7 @@ erts_debug_ptab_list(Process *c_p, ErtsPTab *ptab) hp = HAlloc(c_p, need); /* we need two heap words for each id */ hp_end = hp + need; - /* make the list by scanning bakward */ + /* make the list by scanning backward */ for (i = ptab->r.o.max-1; i >= 0; i--) { diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h index c30a68400210..a95b81162af9 100644 --- a/erts/emulator/beam/erl_ptab.h +++ b/erts/emulator/beam/erl_ptab.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2018. All Rights Reserved. + * Copyright Ericsson AB 2012-2023. 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. @@ -101,16 +101,16 @@ typedef struct { typedef struct { erts_atomic_t *tab; - erts_atomic32_t *free_id_data; + erts_atomic_t *free_id_data; Uint32 max; - Uint32 pix_mask; - Uint32 pix_cl_mask; + Uint pix_mask; + Uint pix_cl_mask; + Uint pix_cli_mask; Uint32 pix_cl_shift; - Uint32 pix_cli_mask; Uint32 pix_cli_shift; - Uint32 dix_cl_mask; + Uint dix_cl_mask; + Uint dix_cli_mask; Uint32 dix_cl_shift; - Uint32 dix_cli_mask; Uint32 dix_cli_shift; ErtsPTabElementCommon *invalid_element; Eterm invalid_data; @@ -146,10 +146,10 @@ typedef struct { } r; } ErtsPTab; -#define ERTS_PTAB_ID_DATA_SIZE 28 +#define ERTS_PTAB_ID_DATA_SIZE (ERTS_SIZEOF_TERM*8 - _TAG_IMMED1_SIZE) #define ERTS_PTAB_ID_DATA_SHIFT (_TAG_IMMED1_SIZE) /* ERTS_PTAB_MAX_SIZE must be a power of 2 */ -#define ERTS_PTAB_MAX_SIZE (SWORD_CONSTANT(1) << 27) +#define ERTS_PTAB_MAX_SIZE (UWORD_CONSTANT(1) << 27) #if (ERTS_PTAB_MAX_SIZE-1) > MAX_SMALL # error "The maximum number of processes/ports must fit in a SMALL." #endif @@ -173,7 +173,8 @@ typedef struct { #define ERTS_PTAB_INVALID_ID(TAG) \ ((Eterm) \ - ((((1U << ERTS_PTAB_ID_DATA_SIZE) - 1) << ERTS_PTAB_ID_DATA_SHIFT) \ + ((((UWORD_CONSTANT(1) << ERTS_PTAB_ID_DATA_SIZE) - 1) \ + << ERTS_PTAB_ID_DATA_SHIFT) \ | (TAG))) #define erts_ptab_is_valid_id(ID) \ @@ -202,8 +203,8 @@ ERTS_GLB_INLINE erts_interval_t *erts_ptab_interval(ErtsPTab *ptab); ERTS_GLB_INLINE int erts_ptab_max(ErtsPTab *ptab); ERTS_GLB_INLINE int erts_ptab_count(ErtsPTab *ptab); ERTS_GLB_INLINE Uint erts_ptab_pixdata2data(ErtsPTab *ptab, Eterm pixdata); -ERTS_GLB_INLINE Uint32 erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata); -ERTS_GLB_INLINE Uint32 erts_ptab_data2pix(ErtsPTab *ptab, Eterm data); +ERTS_GLB_INLINE Uint erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata); +ERTS_GLB_INLINE Uint erts_ptab_data2pix(ErtsPTab *ptab, Eterm data); ERTS_GLB_INLINE Uint erts_ptab_data2pixdata(ErtsPTab *ptab, Eterm data); ERTS_GLB_INLINE Eterm erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag); ERTS_GLB_INLINE int erts_ptab_id2pix(ErtsPTab *ptab, Eterm id); @@ -264,21 +265,21 @@ erts_ptab_count(ErtsPTab *ptab) ERTS_GLB_INLINE Uint erts_ptab_pixdata2data(ErtsPTab *ptab, Eterm pixdata) { - Uint32 data = ((Uint32) pixdata) & ~ptab->r.o.pix_mask; + Uint data = ((Uint) pixdata) & ~ptab->r.o.pix_mask; data |= (pixdata >> ptab->r.o.pix_cl_shift) & ptab->r.o.pix_cl_mask; data |= (pixdata & ptab->r.o.pix_cli_mask) << ptab->r.o.pix_cli_shift; return data; } -ERTS_GLB_INLINE Uint32 erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata) +ERTS_GLB_INLINE Uint erts_ptab_pixdata2pix(ErtsPTab *ptab, Eterm pixdata) { - return ((Uint32) pixdata) & ptab->r.o.pix_mask; + return ((Uint) pixdata) & ptab->r.o.pix_mask; } -ERTS_GLB_INLINE Uint32 erts_ptab_data2pix(ErtsPTab *ptab, Eterm data) +ERTS_GLB_INLINE Uint erts_ptab_data2pix(ErtsPTab *ptab, Eterm data) { - Uint32 n, pix; - n = (Uint32) data; + Uint n, pix; + n = (Uint) data; pix = ((n & ptab->r.o.pix_cl_mask) << ptab->r.o.pix_cl_shift); pix += ((n >> ptab->r.o.pix_cli_shift) & ptab->r.o.pix_cli_mask); ASSERT(0 <= pix && pix < ptab->r.o.max); @@ -293,43 +294,11 @@ ERTS_GLB_INLINE Uint erts_ptab_data2pixdata(ErtsPTab *ptab, Eterm data) return pixdata; } -#if ERTS_SIZEOF_TERM == 8 - -ERTS_GLB_INLINE Eterm -erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag) -{ - HUint huint; - Uint32 low_data = (Uint32) data; - low_data &= (1 << ERTS_PTAB_ID_DATA_SIZE) - 1; - low_data <<= ERTS_PTAB_ID_DATA_SHIFT; - huint.hval[ERTS_HUINT_HVAL_HIGH] = erts_ptab_data2pix(ptab, data); - huint.hval[ERTS_HUINT_HVAL_LOW] = low_data | ((Uint32) tag); - return (Eterm) huint.val; -} - -ERTS_GLB_INLINE int -erts_ptab_id2pix(ErtsPTab *ptab, Eterm id) -{ - HUint huint; - huint.val = id; - return (int) huint.hval[ERTS_HUINT_HVAL_HIGH]; -} - -ERTS_GLB_INLINE Uint -erts_ptab_id2data(ErtsPTab *ptab, Eterm id) -{ - HUint huint; - huint.val = id; - return (Uint) (huint.hval[ERTS_HUINT_HVAL_LOW] >> ERTS_PTAB_ID_DATA_SHIFT); -} - -#elif ERTS_SIZEOF_TERM == 4 - ERTS_GLB_INLINE Eterm erts_ptab_make_id(ErtsPTab *ptab, Eterm data, Eterm tag) { Eterm id; - data &= ((1 << ERTS_PTAB_ID_DATA_SIZE) - 1); + data &= ((UWORD_CONSTANT(1) << ERTS_PTAB_ID_DATA_SIZE) - 1); id = (Eterm) erts_ptab_data2pixdata(ptab, data); return (id << ERTS_PTAB_ID_DATA_SHIFT) | tag; } @@ -350,10 +319,6 @@ erts_ptab_id2data(ErtsPTab *ptab, Eterm id) return erts_ptab_pixdata2data(ptab, pixdata); } -#else -#error "Unsupported size of term" -#endif - ERTS_GLB_INLINE erts_aint_t erts_ptab_pix2intptr_nob(ErtsPTab *ptab, int ix) { ASSERT(0 <= ix && ix < ptab->r.o.max); diff --git a/erts/emulator/beam/erl_rbtree.h b/erts/emulator/beam/erl_rbtree.h index ce401fa7e758..3767239da28a 100644 --- a/erts/emulator/beam/erl_rbtree.h +++ b/erts/emulator/beam/erl_rbtree.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2015-2018. All Rights Reserved. + * Copyright Ericsson AB 2015-2021. 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. @@ -359,7 +359,7 @@ * int indent, * (void)(*print_node)(ERTS_RBT_T *)); * Prints the tree. Note that this function is recursive. - * Should only be used for debuging. + * Should only be used for debugging. */ #ifdef ERTS_RBT_CMP_KEYS diff --git a/erts/emulator/beam/erl_sock.h b/erts/emulator/beam/erl_sock.h deleted file mode 100644 index 3429a52d7e76..000000000000 --- a/erts/emulator/beam/erl_sock.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2016. 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% - */ - -/* - * A *very* limited socket interface exported by inet_drv.c. - * Used by the erl_mtrace.c. - */ - -#ifndef ERL_SOCK_H_ -#define ERL_SOCK_H_ - -#ifdef __WIN32__ -#include -typedef SOCKET erts_sock_t; -#else -typedef int erts_sock_t; -#endif - -#define ERTS_SOCK_INVALID_SOCKET -1 - -erts_sock_t erts_sock_open(void); -void erts_sock_close(erts_sock_t); -int erts_sock_connect(erts_sock_t, byte *, int, Uint16); -Sint erts_sock_send(erts_sock_t, const void *, Sint); -int erts_sock_gethostname(char *, int); -int erts_sock_errno(void); - -#endif diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c index bf2e0b80102a..65f7d0f28041 100644 --- a/erts/emulator/beam/erl_term.c +++ b/erts/emulator/beam/erl_term.c @@ -121,7 +121,7 @@ ET_DEFINE_CHECKED(Uint,arityval,Eterm,is_sane_arity_value); ET_DEFINE_CHECKED(Uint,thing_arityval,Eterm,is_thing); ET_DEFINE_CHECKED(Uint,thing_subtag,Eterm,is_thing); ET_DEFINE_CHECKED(Eterm*,binary_val,Wterm,is_binary); -ET_DEFINE_CHECKED(Eterm*,fun_val,Wterm,is_fun); +ET_DEFINE_CHECKED(Eterm*,fun_val,Wterm,is_any_fun); ET_DEFINE_CHECKED(int,bignum_header_is_neg,Eterm,_is_bignum_header); ET_DEFINE_CHECKED(Eterm,bignum_header_neg,Eterm,_is_bignum_header); ET_DEFINE_CHECKED(Uint,bignum_header_arity,Eterm,_is_bignum_header); @@ -144,7 +144,6 @@ ET_DEFINE_CHECKED(struct erl_node_*,external_port_node,Wterm,is_external_port); ET_DEFINE_CHECKED(Uint,external_ref_data_words,Wterm,is_external_ref); ET_DEFINE_CHECKED(Uint32*,external_ref_data,Wterm,is_external_ref); ET_DEFINE_CHECKED(struct erl_node_*,external_ref_node,Eterm,is_external_ref); -ET_DEFINE_CHECKED(Eterm*,export_val,Wterm,is_export); ET_DEFINE_CHECKED(Uint,external_thing_data_words,ExternalThing*,is_thing_ptr); ET_DEFINE_CHECKED(Eterm,make_cp,ErtsCodePtr,_is_legal_cp); diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index c0545047fc35..a744dd905426 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -129,7 +129,6 @@ struct erl_node_; /* Declared in erl_node_tables.h */ #define REF_SUBTAG (0x4 << _TAG_PRIMARY_SIZE) /* REF */ #define FUN_SUBTAG (0x5 << _TAG_PRIMARY_SIZE) /* FUN */ #define FLOAT_SUBTAG (0x6 << _TAG_PRIMARY_SIZE) /* FLOAT */ -#define EXPORT_SUBTAG (0x7 << _TAG_PRIMARY_SIZE) /* FLOAT */ #define _BINARY_XXX_MASK (0x3 << _TAG_PRIMARY_SIZE) #define REFC_BINARY_SUBTAG (0x8 << _TAG_PRIMARY_SIZE) /* BINARY */ #define HEAP_BINARY_SUBTAG (0x9 << _TAG_PRIMARY_SIZE) /* BINARY */ @@ -146,7 +145,6 @@ struct erl_node_; /* Declared in erl_node_tables.h */ #define _TAG_HEADER_POS_BIG (TAG_PRIMARY_HEADER|POS_BIG_SUBTAG) #define _TAG_HEADER_NEG_BIG (TAG_PRIMARY_HEADER|NEG_BIG_SUBTAG) #define _TAG_HEADER_FLOAT (TAG_PRIMARY_HEADER|FLOAT_SUBTAG) -#define _TAG_HEADER_EXPORT (TAG_PRIMARY_HEADER|EXPORT_SUBTAG) #define _TAG_HEADER_REF (TAG_PRIMARY_HEADER|REF_SUBTAG) #define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG) #define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG) @@ -181,6 +179,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */ #endif #define is_not_both_immed(x,y) (!is_both_immed((x),(y))) +#define is_zero_sized(x) (is_immed(x) || (x) == ERTS_GLOBAL_LIT_EMPTY_TUPLE) /* boxed object access methods */ @@ -313,8 +312,21 @@ _ET_DECLARE_CHECKED(Uint,header_arity,Eterm) #define MAX_ARITYVAL ((((Uint)1) << 24) - 1) #define ERTS_MAX_TUPLE_SIZE MAX_ARITYVAL +/* + Due to an optimization that assumes that the word after the arity + word is allocated, one should generally not create tuples of arity + zero. One should instead use the literal that can be obtained by + calling erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE). + + If one really wants to create a zero arityval one should use + make_arityval_zero() or make_arityval_unchecked(sz) + */ +#define make_arityval_zero() (_make_header(0,_TAG_HEADER_ARITYVAL)) #define make_arityval(sz) (ASSERT((sz) <= MAX_ARITYVAL), \ + ASSERT((sz) > 0), \ _make_header((sz),_TAG_HEADER_ARITYVAL)) +#define make_arityval_unchecked(sz) (ASSERT((sz) <= MAX_ARITYVAL), \ + _make_header((sz),_TAG_HEADER_ARITYVAL)) #define is_arity_value(x) (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL) #define is_sane_arity_value(x) ((((x) & _TAG_HEADER_MASK) == _TAG_HEADER_ARITYVAL) && \ (((x) >> _HEADER_ARITY_OFFS) <= MAX_ARITYVAL)) @@ -374,30 +386,16 @@ _ET_DECLARE_CHECKED(Eterm*,binary_val,Wterm) /* process binaries stuff (special case of binaries) */ #define HEADER_PROC_BIN _make_header(PROC_BIN_SIZE-1,_TAG_HEADER_REFC_BIN) -/* fun & export objects */ -#define is_any_fun(x) (is_fun((x)) || is_export((x))) -#define is_not_any_fun(x) (!is_any_fun((x))) - /* fun objects */ -#define HEADER_FUN _make_header(ERL_FUN_SIZE-2,_TAG_HEADER_FUN) -#define is_fun_header(x) ((x) == HEADER_FUN) -#define make_fun(x) make_boxed((Eterm*)(x)) -#define is_fun(x) (is_boxed((x)) && is_fun_header(*boxed_val((x)))) -#define is_not_fun(x) (!is_fun((x))) +#define HEADER_FUN _make_header(ERL_FUN_SIZE-2,_TAG_HEADER_FUN) +#define is_fun_header(x) ((x) == HEADER_FUN) +#define make_fun(x) make_boxed((Eterm*)(x)) +#define is_any_fun(x) (is_boxed((x)) && is_fun_header(*boxed_val((x)))) +#define is_not_any_fun(x) (!is_any_fun((x))) #define _unchecked_fun_val(x) _unchecked_boxed_val((x)) _ET_DECLARE_CHECKED(Eterm*,fun_val,Wterm) #define fun_val(x) _ET_APPLY(fun_val,(x)) -/* export access methods */ -#define make_export(x) make_boxed((x)) -#define is_export(x) (is_boxed((x)) && is_export_header(*boxed_val((x)))) -#define is_not_export(x) (!is_export((x))) -#define _unchecked_export_val(x) _unchecked_boxed_val(x) -_ET_DECLARE_CHECKED(Eterm*,export_val,Wterm) -#define export_val(x) _ET_APPLY(export_val,(x)) -#define is_export_header(x) ((x) == HEADER_EXPORT) -#define HEADER_EXPORT _make_header(1,_TAG_HEADER_EXPORT) - /* bignum access methods */ #define make_pos_bignum_header(sz) _make_header((sz),_TAG_HEADER_POS_BIG) #define make_neg_bignum_header(sz) _make_header((sz),_TAG_HEADER_NEG_BIG) @@ -482,15 +480,18 @@ typedef union float_def #define is_tuple(x) (is_boxed((x)) && is_arity_value(*boxed_val((x)))) #define is_not_tuple(x) (!is_tuple((x))) #define is_tuple_arity(x, a) \ - (is_boxed((x)) && *boxed_val((x)) == make_arityval((a))) + (is_boxed((x)) && *boxed_val((x)) == make_arityval_unchecked((a))) #define is_not_tuple_arity(x, a) (!is_tuple_arity((x),(a))) #define _unchecked_tuple_val(x) _unchecked_boxed_val(x) _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm) #define tuple_val(x) _ET_APPLY(tuple_val,(x)) -#define TUPLE0(t) \ - ((t)[0] = make_arityval(0), \ - make_tuple(t)) +/* + Due to an optimization that assumes that the word after the arity + word is allocated, one should generally not create tuples of arity + zero on heaps. One should instead use the literal that can be + obtained by calling erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE). + */ #define TUPLE1(t,e1) \ ((t)[0] = make_arityval(1), \ (t)[1] = (e1), \ @@ -590,9 +591,9 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm) */ #define _PID_SER_SIZE (_PID_DATA_SIZE - _PID_NUM_SIZE) -#define _PID_NUM_SIZE 15 +#define _PID_NUM_SIZE 28 -#define _PID_DATA_SIZE 28 +#define _PID_DATA_SIZE (ERTS_SIZEOF_TERM*8 - _TAG_IMMED1_SIZE) #define _PID_DATA_SHIFT (_TAG_IMMED1_SIZE) #define _GET_PID_DATA(X) _GETBITS((X),_PID_DATA_SHIFT,_PID_DATA_SIZE) @@ -640,7 +641,7 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_pid_node,Eterm) */ #define _PORT_NUM_SIZE _PORT_DATA_SIZE -#define _PORT_DATA_SIZE 28 +#define _PORT_DATA_SIZE (ERTS_SIZEOF_TERM*8 - _TAG_IMMED1_SIZE) #define _PORT_DATA_SHIFT (_TAG_IMMED1_SIZE) #define _GET_PORT_DATA(X) _GETBITS((X),_PORT_DATA_SHIFT,_PORT_DATA_SIZE) @@ -958,12 +959,12 @@ typedef union { #define is_ordinary_ref_thing(x) \ ((*((Eterm *)(x)) == ERTS_REF_THING_HEADER) \ - & (((ErtsRefThing *) (x))->o.marker == ERTS_ORDINARY_REF_MARKER)) + && (((ErtsRefThing *) (x))->o.marker == ERTS_ORDINARY_REF_MARKER)) /* the _with_hdr variant usable when header word may be broken (copy_shared) */ #define is_magic_ref_thing_with_hdr(PTR,HDR) \ (((HDR) == ERTS_REF_THING_HEADER) \ - & (((ErtsRefThing *) (PTR))->o.marker != ERTS_ORDINARY_REF_MARKER)) + && (((ErtsRefThing *) (PTR))->o.marker != ERTS_ORDINARY_REF_MARKER)) #else /* Ordinary and magic references of different sizes... */ @@ -1272,15 +1273,12 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #define MAP_SZ(sz) (MAP_HEADER_FLATMAP_SZ + 2*sz + 1) -#define MAP0_SZ MAP_SZ(0) #define MAP1_SZ MAP_SZ(1) #define MAP2_SZ MAP_SZ(2) #define MAP3_SZ MAP_SZ(3) #define MAP4_SZ MAP_SZ(4) #define MAP5_SZ MAP_SZ(5) -#define MAP0(hp) \ - (MAP_HEADER(hp, 0, TUPLE0(hp+MAP_HEADER_FLATMAP_SZ)), \ - make_flatmap(hp)) + #define MAP1(hp, k1, v1) \ (MAP_HEADER(hp, 1, TUPLE1(hp+1+MAP_HEADER_FLATMAP_SZ, k1)), \ (hp)[MAP_HEADER_FLATMAP_SZ+0] = v1, \ @@ -1296,22 +1294,8 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) (hp)[MAP_HEADER_FLATMAP_SZ+1] = v2, \ (hp)[MAP_HEADER_FLATMAP_SZ+2] = v3, \ make_flatmap(hp)) -#define MAP4(hp, k1, v1, k2, v2, k3, v3, k4, v4) \ - (MAP_HEADER(hp, 4, TUPLE4(hp+4+MAP_HEADER_FLATMAP_SZ, k1, k2, k3, k4)), \ - (hp)[MAP_HEADER_FLATMAP_SZ+0] = v1, \ - (hp)[MAP_HEADER_FLATMAP_SZ+1] = v2, \ - (hp)[MAP_HEADER_FLATMAP_SZ+2] = v3, \ - (hp)[MAP_HEADER_FLATMAP_SZ+3] = v4, \ - make_flatmap(hp)) -#define MAP5(hp, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5) \ - (MAP_HEADER(hp, 5, TUPLE5(hp+5+MAP_HEADER_FLATMAP_SZ, k1, k2, k3, k4, k5)), \ - (hp)[MAP_HEADER_FLATMAP_SZ+0] = v1, \ - (hp)[MAP_HEADER_FLATMAP_SZ+1] = v2, \ - (hp)[MAP_HEADER_FLATMAP_SZ+2] = v3, \ - (hp)[MAP_HEADER_FLATMAP_SZ+3] = v4, \ - (hp)[MAP_HEADER_FLATMAP_SZ+4] = v5, \ - make_flatmap(hp)) - +/* MAP4 and greater have to be created with erts_map_from_ks_and_vs as in the + debug emulator maps > 3 are hashmaps. */ /* number tests */ @@ -1407,7 +1391,6 @@ _ET_DECLARE_CHECKED(Uint,loader_y_reg_index,Uint) #define EXTERNAL_PID_DEF 0x6 #define PORT_DEF 0x7 #define EXTERNAL_PORT_DEF 0x8 -#define EXPORT_DEF 0x9 #define FUN_DEF 0xa #define REF_DEF 0xb #define EXTERNAL_REF_DEF 0xc @@ -1477,7 +1460,6 @@ ERTS_GLB_INLINE unsigned tag_val_def(Wterm x) case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): return BIG_DEF; case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE): return REF_DEF; case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): return FLOAT_DEF; - case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE): return EXPORT_DEF; case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): return FUN_DEF; case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE): return EXTERNAL_PID_DEF; case (_TAG_HEADER_EXTERNAL_PORT >> _TAG_PRIMARY_SIZE): return EXTERNAL_PORT_DEF; diff --git a/erts/emulator/beam/erl_term_hashing.c b/erts/emulator/beam/erl_term_hashing.c new file mode 100644 index 000000000000..848757c2f266 --- /dev/null +++ b/erts/emulator/beam/erl_term_hashing.c @@ -0,0 +1,2014 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "global.h" +#include "erl_term_hashing.h" + +#include "big.h" +#include "bif.h" +#include "erl_map.h" +#include "erl_binary.h" +#include "erl_bits.h" + +#ifdef ERL_INTERNAL_HASH_CRC32C +# if defined(__x86_64__) +# include +# elif defined(__aarch64__) +# include +# endif +#endif + +/* *\ + * * +\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* make a hash index from an erlang term */ + +/* +** There are two hash functions. +** +** make_hash: A hash function that will give the same values for the same +** terms regardless of the internal representation. Small integers are +** hashed using the same algorithm as bignums and bignums are hashed +** independent of the CPU endianess. +** Make_hash also hashes pids, ports and references like 32 bit numbers +** (but with different constants). +** make_hash() is called from the bif erlang:phash/2 +** +** The idea behind the hash algorithm is to produce values suitable for +** linear dynamic hashing. We cannot choose the range at all while hashing +** (it's not even supplied to the hashing functions). The good old algorithm +** [H = H*C+X mod M, where H is the hash value, C is a "random" constant(or M), +** M is the range, preferably a prime, and X is each byte value] is therefore +** modified to: +** H = H*C+X mod 2^32, where C is a large prime. This gives acceptable +** "spreading" of the hashes, so that later modulo calculations also will give +** acceptable "spreading" in the range. +** We really need to hash on bytes, otherwise the +** upper bytes of a word will be less significant than the lower ones. That's +** not acceptable at all. For internal use one could maybe optimize by using +** another hash function, that is less strict but faster. That is, however, not +** implemented. +** +** Short semi-formal description of make_hash: +** +** In make_hash, the number N is treated like this: +** Abs(N) is hashed bytewise with the least significant byte, B(0), first. +** The number of bytes (J) to calculate hash on in N is +** (the number of _32_ bit words needed to store the unsigned +** value of abs(N)) * 4. +** X = FUNNY_NUMBER2 +** If N < 0, Y = FUNNY_NUMBER4 else Y = FUNNY_NUMBER3. +** The hash value is Y*h(J) mod 2^32 where h(J) is calculated like +** h(0) = +** h(i) = h(i-1)*X + B(i-1) +** The above should hold regardless of internal representation. +** Pids are hashed like small numbers but with different constants, as are +** ports. +** References are hashed like ports but only on the least significant byte. +** Binaries are hashed on all bytes (not on the 15 first as in +** make_broken_hash()). +** Bytes in lists (possibly text strings) use a simpler multiplication inlined +** in the handling of lists, that is an optimization. +** Everything else is like in the old hash (make_broken_hash()). +** +** make_hash2() is faster than make_hash, in particular for bignums +** and binaries, and produces better hash values. +*/ + +/* some prime numbers just above 2 ^ 28 */ + +#define FUNNY_NUMBER1 268440163 +#define FUNNY_NUMBER2 268439161 +#define FUNNY_NUMBER3 268435459 +#define FUNNY_NUMBER4 268436141 +#define FUNNY_NUMBER5 268438633 +#define FUNNY_NUMBER6 268437017 +#define FUNNY_NUMBER7 268438039 +#define FUNNY_NUMBER8 268437511 +#define FUNNY_NUMBER9 268439627 +#define FUNNY_NUMBER10 268440479 +#define FUNNY_NUMBER11 268440577 +#define FUNNY_NUMBER12 268440581 +#define FUNNY_NUMBER13 268440593 +#define FUNNY_NUMBER14 268440611 + +static Uint32 +hash_binary_bytes(Eterm bin, Uint sz, Uint32 hash) +{ + byte* ptr; + Uint bitoffs; + Uint bitsize; + + ERTS_GET_BINARY_BYTES(bin, ptr, bitoffs, bitsize); + if (bitoffs == 0) { + while (sz--) { + hash = hash*FUNNY_NUMBER1 + *ptr++; + } + if (bitsize > 0) { + byte b = *ptr; + + b >>= 8 - bitsize; + hash = (hash*FUNNY_NUMBER1 + b) * FUNNY_NUMBER12 + bitsize; + } + } else { + Uint previous = *ptr++; + Uint b; + Uint lshift = bitoffs; + Uint rshift = 8 - lshift; + + while (sz--) { + b = (previous << lshift) & 0xFF; + previous = *ptr++; + b |= previous >> rshift; + hash = hash*FUNNY_NUMBER1 + b; + } + if (bitsize > 0) { + b = (previous << lshift) & 0xFF; + previous = *ptr++; + b |= previous >> rshift; + + b >>= 8 - bitsize; + hash = (hash*FUNNY_NUMBER1 + b) * FUNNY_NUMBER12 + bitsize; + } + } + return hash; +} + +Uint32 make_hash(Eterm term_arg) +{ + DECLARE_WSTACK(stack); + Eterm term = term_arg; + Eterm hash = 0; + unsigned op; + +#define MAKE_HASH_TUPLE_OP (FIRST_VACANT_TAG_DEF) +#define MAKE_HASH_TERM_ARRAY_OP (FIRST_VACANT_TAG_DEF+1) +#define MAKE_HASH_CDR_PRE_OP (FIRST_VACANT_TAG_DEF+2) +#define MAKE_HASH_CDR_POST_OP (FIRST_VACANT_TAG_DEF+3) + + /* + ** Convenience macro for calculating a bytewise hash on an unsigned 32 bit + ** integer. + ** If the endianess is known, we could be smarter here, + ** but that gives no significant speedup (on a sparc at least) + */ +#define UINT32_HASH_STEP(Expr, Prime1) \ + do { \ + Uint32 x = (Uint32) (Expr); \ + hash = \ + (((((hash)*(Prime1) + (x & 0xFF)) * (Prime1) + \ + ((x >> 8) & 0xFF)) * (Prime1) + \ + ((x >> 16) & 0xFF)) * (Prime1) + \ + (x >> 24)); \ + } while(0) + +#define UINT32_HASH_RET(Expr, Prime1, Prime2) \ + UINT32_HASH_STEP(Expr, Prime1); \ + hash = hash * (Prime2); \ + break + + + /* + * Significant additions needed for real 64 bit port with larger fixnums. + */ + + /* + * Note, for the simple 64bit port, not utilizing the + * larger word size this function will work without modification. + */ +tail_recur: + op = tag_val_def(term); + + for (;;) { + switch (op) { + case NIL_DEF: + hash = hash*FUNNY_NUMBER3 + 1; + break; + case ATOM_DEF: + hash = hash*FUNNY_NUMBER1 + + (atom_tab(atom_val(term))->slot.bucket.hvalue); + break; + case SMALL_DEF: + { + Sint y1 = signed_val(term); + Uint y2 = y1 < 0 ? -(Uint)y1 : y1; + + UINT32_HASH_STEP(y2, FUNNY_NUMBER2); +#if defined(ARCH_64) + if (y2 >> 32) + UINT32_HASH_STEP(y2 >> 32, FUNNY_NUMBER2); +#endif + hash *= (y1 < 0 ? FUNNY_NUMBER4 : FUNNY_NUMBER3); + break; + } + case BINARY_DEF: + { + Uint sz = binary_size(term); + + hash = hash_binary_bytes(term, sz, hash); + hash = hash*FUNNY_NUMBER4 + sz; + break; + } + case FUN_DEF: + { + ErlFunThing* funp = (ErlFunThing *) fun_val(term); + + if (is_local_fun(funp)) { + + ErlFunEntry* fe = funp->entry.fun; + Uint num_free = funp->num_free; + + hash = hash * FUNNY_NUMBER10 + num_free; + hash = hash*FUNNY_NUMBER1 + + (atom_tab(atom_val(fe->module))->slot.bucket.hvalue); + hash = hash*FUNNY_NUMBER2 + fe->index; + hash = hash*FUNNY_NUMBER2 + fe->old_uniq; + + if (num_free > 0) { + if (num_free > 1) { + WSTACK_PUSH3(stack, (UWord) &funp->env[1], + (num_free-1), MAKE_HASH_TERM_ARRAY_OP); + } + + term = funp->env[0]; + goto tail_recur; + } + } else { + const ErtsCodeMFA *mfa = &funp->entry.exp->info.mfa; + + ASSERT(is_external_fun(funp) && funp->next == NULL); + + hash = hash * FUNNY_NUMBER11 + mfa->arity; + hash = hash*FUNNY_NUMBER1 + + (atom_tab(atom_val(mfa->module))->slot.bucket.hvalue); + hash = hash*FUNNY_NUMBER1 + + (atom_tab(atom_val(mfa->function))->slot.bucket.hvalue); + } + break; + } + case PID_DEF: + /* only 15 bits... */ + UINT32_HASH_RET(internal_pid_number(term),FUNNY_NUMBER5,FUNNY_NUMBER6); + case EXTERNAL_PID_DEF: + /* only 15 bits... */ + UINT32_HASH_RET(external_pid_number(term),FUNNY_NUMBER5,FUNNY_NUMBER6); + case PORT_DEF: + case EXTERNAL_PORT_DEF: { + Uint64 number = port_number(term); + Uint32 low = (Uint32) (number & 0xffffffff); + Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); + if (high) + UINT32_HASH_STEP(high, FUNNY_NUMBER11); + UINT32_HASH_RET(low,FUNNY_NUMBER9,FUNNY_NUMBER10); + } + case REF_DEF: + UINT32_HASH_RET(internal_ref_numbers(term)[0],FUNNY_NUMBER9,FUNNY_NUMBER10); + case EXTERNAL_REF_DEF: + UINT32_HASH_RET(external_ref_numbers(term)[0],FUNNY_NUMBER9,FUNNY_NUMBER10); + case FLOAT_DEF: + { + FloatDef ff; + GET_DOUBLE(term, ff); + if (ff.fd == 0.0f) { + /* ensure positive 0.0 */ + ff.fd = erts_get_positive_zero_float(); + } + hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]); + break; + } + case MAKE_HASH_CDR_PRE_OP: + term = (Eterm) WSTACK_POP(stack); + if (is_not_list(term)) { + WSTACK_PUSH(stack, (UWord) MAKE_HASH_CDR_POST_OP); + goto tail_recur; + } + /* fall through */ + case LIST_DEF: + { + Eterm* list = list_val(term); + while(is_byte(*list)) { + /* Optimization for strings. + ** Note that this hash is different from a 'small' hash, + ** as multiplications on a Sparc is so slow. + */ + hash = hash*FUNNY_NUMBER2 + unsigned_val(*list); + + if (is_not_list(CDR(list))) { + WSTACK_PUSH(stack, MAKE_HASH_CDR_POST_OP); + term = CDR(list); + goto tail_recur; + } + list = list_val(CDR(list)); + } + WSTACK_PUSH2(stack, CDR(list), MAKE_HASH_CDR_PRE_OP); + term = CAR(list); + goto tail_recur; + } + case MAKE_HASH_CDR_POST_OP: + hash *= FUNNY_NUMBER8; + break; + + case BIG_DEF: + /* Note that this is the exact same thing as the hashing of smalls.*/ + { + Eterm* ptr = big_val(term); + Uint n = BIG_SIZE(ptr); + Uint k = n-1; + ErtsDigit d; + int is_neg = BIG_SIGN(ptr); + Uint i; + int j; + + for (i = 0; i < k; i++) { + d = BIG_DIGIT(ptr, i); + for(j = 0; j < sizeof(ErtsDigit); ++j) { + hash = (hash*FUNNY_NUMBER2) + (d & 0xff); + d >>= 8; + } + } + d = BIG_DIGIT(ptr, k); + k = sizeof(ErtsDigit); +#if defined(ARCH_64) + if (!(d >> 32)) + k /= 2; +#endif + for(j = 0; j < (int)k; ++j) { + hash = (hash*FUNNY_NUMBER2) + (d & 0xff); + d >>= 8; + } + hash *= is_neg ? FUNNY_NUMBER4 : FUNNY_NUMBER3; + break; + } + case MAP_DEF: + hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); + break; + case TUPLE_DEF: + { + Eterm* ptr = tuple_val(term); + Uint arity = arityval(*ptr); + + WSTACK_PUSH3(stack, (UWord) arity, (UWord)(ptr+1), (UWord) arity); + op = MAKE_HASH_TUPLE_OP; + }/*fall through*/ + case MAKE_HASH_TUPLE_OP: + case MAKE_HASH_TERM_ARRAY_OP: + { + Uint i = (Uint) WSTACK_POP(stack); + Eterm* ptr = (Eterm*) WSTACK_POP(stack); + if (i != 0) { + term = *ptr; + WSTACK_PUSH3(stack, (UWord)(ptr+1), (UWord) i-1, (UWord) op); + goto tail_recur; + } + if (op == MAKE_HASH_TUPLE_OP) { + Uint32 arity = (Uint32) WSTACK_POP(stack); + hash = hash*FUNNY_NUMBER9 + arity; + } + break; + } + + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); + return 0; + } + if (WSTACK_ISEMPTY(stack)) break; + op = WSTACK_POP(stack); + } + DESTROY_WSTACK(stack); + return hash; + +#undef MAKE_HASH_TUPLE_OP +#undef MAKE_HASH_TERM_ARRAY_OP +#undef MAKE_HASH_CDR_PRE_OP +#undef MAKE_HASH_CDR_POST_OP +#undef UINT32_HASH_STEP +#undef UINT32_HASH_RET +} + +/* Hash function suggested by Bob Jenkins. */ +#define MIX(a,b,c) \ + do { \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ + } while(0) + +#define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */ + +#define BLOCK_HASH_BYTES_PER_ITER 12 + +/* The three functions below are separated into different functions even + though they are always used together to make trapping and handling + of unaligned binaries easier. Examples of how they are used can be + found in block_hash and make_hash2_helper.*/ +static ERTS_INLINE +void block_hash_setup(Uint32 initval, + ErtsBlockHashHelperCtx* ctx /* out parameter */) +{ + ctx->a = ctx->b = HCONST; + ctx->c = initval; /* the previous hash value */ +} + +static ERTS_INLINE +void block_hash_buffer(byte *buf, + Uint buf_length, + ErtsBlockHashHelperCtx* ctx /* out parameter */) +{ + Uint len = buf_length; + byte *k = buf; + ASSERT(buf_length % BLOCK_HASH_BYTES_PER_ITER == 0); + while (len >= BLOCK_HASH_BYTES_PER_ITER) { + ctx->a += (k[0] +((Uint32)k[1]<<8) +((Uint32)k[2]<<16) +((Uint32)k[3]<<24)); + ctx->b += (k[4] +((Uint32)k[5]<<8) +((Uint32)k[6]<<16) +((Uint32)k[7]<<24)); + ctx->c += (k[8] +((Uint32)k[9]<<8) +((Uint32)k[10]<<16)+((Uint32)k[11]<<24)); + MIX(ctx->a,ctx->b,ctx->c); + k += BLOCK_HASH_BYTES_PER_ITER; len -= BLOCK_HASH_BYTES_PER_ITER; + } +} + +static ERTS_INLINE +Uint32 block_hash_final_bytes(byte *buf, + Uint buf_length, + Uint full_length, + ErtsBlockHashHelperCtx* ctx) +{ + Uint len = buf_length; + byte *k = buf; + ctx->c += full_length; + switch(len) + { /* all the case statements fall through */ + case 11: ctx->c+=((Uint32)k[10]<<24); + case 10: ctx->c+=((Uint32)k[9]<<16); + case 9 : ctx->c+=((Uint32)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : ctx->b+=((Uint32)k[7]<<24); + case 7 : ctx->b+=((Uint32)k[6]<<16); + case 6 : ctx->b+=((Uint32)k[5]<<8); + case 5 : ctx->b+=k[4]; + case 4 : ctx->a+=((Uint32)k[3]<<24); + case 3 : ctx->a+=((Uint32)k[2]<<16); + case 2 : ctx->a+=((Uint32)k[1]<<8); + case 1 : ctx->a+=k[0]; + /* case 0: nothing left to add */ + } + MIX(ctx->a,ctx->b,ctx->c); + return ctx->c; +} + +static +Uint32 +block_hash(byte *block, Uint block_length, Uint32 initval) +{ + ErtsBlockHashHelperCtx ctx; + Uint no_bytes_not_in_loop = + (block_length % BLOCK_HASH_BYTES_PER_ITER); + Uint no_bytes_to_process_in_loop = + block_length - no_bytes_not_in_loop; + byte *final_bytes = block + no_bytes_to_process_in_loop; + block_hash_setup(initval, &ctx); + block_hash_buffer(block, + no_bytes_to_process_in_loop, + &ctx); + return block_hash_final_bytes(final_bytes, + no_bytes_not_in_loop, + block_length, + &ctx); +} + +/* + * Note! erts_block_hash() and erts_iov_block_hash() *must* produce + * the same result if the I/O vector is flattened and contain the + * same bytes as the array. + */ + +void +erts_block_hash_init(ErtsBlockHashState *state, const byte *ptr, + Uint len, Uint32 initval) +{ + block_hash_setup(initval, &state->hctx); + state->ptr = ptr; + state->len = len; + state->tot_len = len; +} + +int +erts_block_hash(Uint32 *hashp, Uint *sizep, ErtsBlockHashState *state) +{ + byte *ptr = (byte *) state->ptr; + Uint len = state->len; + Sint flen; + Uint llen; + + do { + + if (*sizep < len) { + llen = *sizep; + llen -= llen % BLOCK_HASH_BYTES_PER_ITER; + if (len > llen + BLOCK_HASH_BYTES_PER_ITER) { + llen += BLOCK_HASH_BYTES_PER_ITER; + flen = -1; + break; + } + } + + /* do it all... */ + flen = len % BLOCK_HASH_BYTES_PER_ITER; + llen = len - flen; + + } while (0); + + block_hash_buffer(ptr, llen, &state->hctx); + + ptr += llen; + + if (flen < 0) { + state->ptr = ptr; + state->len -= llen; + *sizep = llen; + return 0; /* yield */ + } + + *hashp = block_hash_final_bytes(ptr, (Uint) flen, + state->tot_len, &state->hctx); + + *sizep = llen + flen; + + state->ptr = ptr + flen; + state->len = 0; + + return !0; /* done */ +} + +/* + * Note! erts_block_hash() and erts_iov_block_hash() *must* produce + * the same result if the I/O vector is flattened and contain the + * same bytes as the array. + */ + +void +erts_iov_block_hash_init(ErtsIovBlockHashState *state, SysIOVec *iov, + Uint vlen, Uint32 initval) +{ + block_hash_setup(initval, &state->hctx); + state->iov = iov; + state->vlen = vlen; + state->tot_len = 0; + state->vix = 0; + state->ix = 0; +} + +int +erts_iov_block_hash(Uint32 *hashp, Uint *sizep, ErtsIovBlockHashState *state) +{ + byte buf[BLOCK_HASH_BYTES_PER_ITER]; + ErtsBlockHashHelperCtx *hctx = &state->hctx; + SysIOVec *iov = state->iov; + Uint vlen = state->vlen; + int vix = state->vix; + int ix = state->ix; + Uint cix = 0; + byte *final_bytes; + Uint no_final_bytes; + Uint chunk_sz = (*sizep + - *sizep % BLOCK_HASH_BYTES_PER_ITER + + BLOCK_HASH_BYTES_PER_ITER); + + do { + Uint bsz, csz; + int left; + byte *ptr; + + ASSERT((cix % BLOCK_HASH_BYTES_PER_ITER) == 0); + + /* + * We may have empty vectors... + */ + while (ix == iov[vix].iov_len) { + vix++; + if (vix == vlen) { + final_bytes = NULL; + no_final_bytes = 0; + goto finalize; + } + ix = 0; + } + + csz = chunk_sz - cix; + left = iov[vix].iov_len - ix; + ptr = iov[vix].iov_base; + + if (left >= BLOCK_HASH_BYTES_PER_ITER) { + if (csz <= left) + bsz = csz; + else + bsz = left - (left % BLOCK_HASH_BYTES_PER_ITER); + block_hash_buffer(ptr + ix, bsz, hctx); + cix += bsz; + ix += bsz; + } + else { + int bix = 0; + bsz = left; + while (!0) { + sys_memcpy(&buf[bix], ptr + ix, bsz); + bix += bsz; + cix += bsz; + ix += bsz; + if (bix == BLOCK_HASH_BYTES_PER_ITER) { + block_hash_buffer(&buf[0], + (Uint) BLOCK_HASH_BYTES_PER_ITER, + hctx); + break; + } + ASSERT(ix == iov[vix].iov_len); + vix++; + if (vix == vlen) { + final_bytes = &buf[0]; + no_final_bytes = (Uint) bsz; + goto finalize; + } + ix = 0; + ptr = iov[vix].iov_base; + bsz = iov[vix].iov_len; + if (bsz > BLOCK_HASH_BYTES_PER_ITER - bix) + bsz = BLOCK_HASH_BYTES_PER_ITER - bix; + } + } + + } while (cix < chunk_sz); + + ASSERT((cix % BLOCK_HASH_BYTES_PER_ITER) == 0); + + /* yield */ + + *sizep = cix; + + state->tot_len += cix; + state->vix = vix; + state->ix = ix; + + return 0; + +finalize: + + state->tot_len += cix; + *sizep = cix; + + *hashp = block_hash_final_bytes(final_bytes, no_final_bytes, + state->tot_len, hctx); + return !0; /* done */ +} + + + +typedef enum { + tag_primary_list, + arityval_subtag, + hamt_subtag_head_flatmap, + map_subtag, + fun_subtag, + neg_big_subtag, + sub_binary_subtag_1, + sub_binary_subtag_2, + hash2_common_1, + hash2_common_2, + hash2_common_3, +} ErtsMakeHash2TrapLocation; + +typedef struct { + int c; + Uint32 sh; + Eterm* ptr; +} ErtsMakeHash2Context_TAG_PRIMARY_LIST; + +typedef struct { + int i; + int arity; + Eterm* elem; +} ErtsMakeHash2Context_ARITYVAL_SUBTAG; + +typedef struct { + Eterm *ks; + Eterm *vs; + int i; + Uint size; +} ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP; + +typedef struct { + Eterm* ptr; + int i; +} ErtsMakeHash2Context_MAP_SUBTAG; + +typedef struct { + Uint num_free; + Eterm* bptr; +} ErtsMakeHash2Context_FUN_SUBTAG; + +typedef struct { + Eterm* ptr; + Uint i; + Uint n; + Uint32 con; +} ErtsMakeHash2Context_NEG_BIG_SUBTAG; + +typedef struct { + byte* bptr; + Uint sz; + Uint bitsize; + Uint bitoffs; + Uint no_bytes_processed; + ErtsBlockHashHelperCtx block_hash_ctx; + /* The following fields are only used when bitoffs != 0 */ + byte* buf; + int done; + +} ErtsMakeHash2Context_SUB_BINARY_SUBTAG; + +typedef struct { + int dummy__; /* Empty structs are not supported on all platforms */ +} ErtsMakeHash2Context_EMPTY; + +typedef struct { + ErtsMakeHash2TrapLocation trap_location; + /* specific to the trap location: */ + union { + ErtsMakeHash2Context_TAG_PRIMARY_LIST tag_primary_list; + ErtsMakeHash2Context_ARITYVAL_SUBTAG arityval_subtag; + ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP hamt_subtag_head_flatmap; + ErtsMakeHash2Context_MAP_SUBTAG map_subtag; + ErtsMakeHash2Context_FUN_SUBTAG fun_subtag; + ErtsMakeHash2Context_NEG_BIG_SUBTAG neg_big_subtag; + ErtsMakeHash2Context_SUB_BINARY_SUBTAG sub_binary_subtag_1; + ErtsMakeHash2Context_SUB_BINARY_SUBTAG sub_binary_subtag_2; + ErtsMakeHash2Context_EMPTY hash2_common_1; + ErtsMakeHash2Context_EMPTY hash2_common_2; + ErtsMakeHash2Context_EMPTY hash2_common_3; + } trap_location_state; + /* same for all trap locations: */ + Eterm term; + Uint32 hash; + Uint32 hash_xor_pairs; + ErtsEStack stack; +} ErtsMakeHash2Context; + +static int make_hash2_ctx_bin_dtor(Binary *context_bin) { + ErtsMakeHash2Context* context = ERTS_MAGIC_BIN_DATA(context_bin); + DESTROY_SAVED_ESTACK(&context->stack); + if (context->trap_location == sub_binary_subtag_2 && + context->trap_location_state.sub_binary_subtag_2.buf != NULL) { + erts_free(ERTS_ALC_T_PHASH2_TRAP, context->trap_location_state.sub_binary_subtag_2.buf); + } + return 1; +} + +/* hash2_save_trap_state is called seldom so we want to avoid inlining */ +static ERTS_NOINLINE +Eterm hash2_save_trap_state(Eterm state_mref, + Uint32 hash_xor_pairs, + Uint32 hash, + Process* p, + Eterm term, + Eterm* ESTK_DEF_STACK(s), + ErtsEStack s, + ErtsMakeHash2TrapLocation trap_location, + void* trap_location_state_ptr, + size_t trap_location_state_size) { + Binary* state_bin; + ErtsMakeHash2Context* context; + if (state_mref == THE_NON_VALUE) { + Eterm* hp; + state_bin = erts_create_magic_binary(sizeof(ErtsMakeHash2Context), + make_hash2_ctx_bin_dtor); + hp = HAlloc(p, ERTS_MAGIC_REF_THING_SIZE); + state_mref = erts_mk_magic_ref(&hp, &MSO(p), state_bin); + } else { + state_bin = erts_magic_ref2bin(state_mref); + } + context = ERTS_MAGIC_BIN_DATA(state_bin); + context->term = term; + context->hash = hash; + context->hash_xor_pairs = hash_xor_pairs; + ESTACK_SAVE(s, &context->stack); + context->trap_location = trap_location; + sys_memcpy(&context->trap_location_state, + trap_location_state_ptr, + trap_location_state_size); + erts_set_gc_state(p, 0); + BUMP_ALL_REDS(p); + return state_mref; +} +#undef NOINLINE_HASH2_SAVE_TRAP_STATE + +/* Writes back a magic reference to *state_mref_write_back when the + function traps */ +static ERTS_INLINE Uint32 +make_hash2_helper(Eterm term_param, const int can_trap, Eterm* state_mref_write_back, Process* p) +{ + static const Uint ITERATIONS_PER_RED = 64; + Uint32 hash; + Uint32 hash_xor_pairs; + Eterm term = term_param; + ERTS_UNDEF(hash_xor_pairs, 0); + +/* (HCONST * {2, ..., 22}) mod 2^32 */ +#define HCONST_2 0x3c6ef372UL +#define HCONST_3 0xdaa66d2bUL +#define HCONST_4 0x78dde6e4UL +#define HCONST_5 0x1715609dUL +#define HCONST_6 0xb54cda56UL +#define HCONST_7 0x5384540fUL +#define HCONST_8 0xf1bbcdc8UL +#define HCONST_9 0x8ff34781UL +#define HCONST_10 0x2e2ac13aUL +#define HCONST_11 0xcc623af3UL +#define HCONST_12 0x6a99b4acUL +#define HCONST_13 0x08d12e65UL +#define HCONST_14 0xa708a81eUL +#define HCONST_15 0x454021d7UL +#define HCONST_16 0xe3779b90UL +#define HCONST_17 0x81af1549UL +#define HCONST_18 0x1fe68f02UL +#define HCONST_19 0xbe1e08bbUL +#define HCONST_20 0x5c558274UL +#define HCONST_21 0xfa8cfc2dUL +#define HCONST_22 0x98c475e6UL + +#define HASH_MAP_TAIL (_make_header(1,_TAG_HEADER_REF)) +#define HASH_MAP_PAIR (_make_header(2,_TAG_HEADER_REF)) +#define HASH_CDR (_make_header(3,_TAG_HEADER_REF)) + +#define UINT32_HASH_2(Expr1, Expr2, AConst) \ + do { \ + Uint32 a,b; \ + a = AConst + (Uint32) (Expr1); \ + b = AConst + (Uint32) (Expr2); \ + MIX(a,b,hash); \ + } while(0) + +#define UINT32_HASH(Expr, AConst) UINT32_HASH_2(Expr, 0, AConst) + +#define SINT32_HASH(Expr, AConst) \ + do { \ + Sint32 y = (Sint32) (Expr); \ + if (y < 0) { \ + UINT32_HASH(-y, AConst); \ + /* Negative numbers are unnecessarily mixed twice. */ \ + } \ + UINT32_HASH(y, AConst); \ + } while(0) + +#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2) + +#define NOT_SSMALL28_HASH(SMALL) \ + do { \ + Uint64 t; \ + Uint32 x, y; \ + Uint32 con; \ + if (SMALL < 0) { \ + con = HCONST_10; \ + t = (Uint64)(SMALL * (-1)); \ + } else { \ + con = HCONST_11; \ + t = SMALL; \ + } \ + x = t & 0xffffffff; \ + y = t >> 32; \ + UINT32_HASH_2(x, y, con); \ + } while(0) + +#ifdef ARCH_64 +# define POINTER_HASH(Ptr, AConst) UINT32_HASH_2((Uint32)(UWord)(Ptr), (((UWord)(Ptr)) >> 32), AConst) +#else +# define POINTER_HASH(Ptr, AConst) UINT32_HASH(Ptr, AConst) +#endif + +#define TRAP_LOCATION_NO_RED(location_name) \ + do { \ + if(can_trap && iterations_until_trap <= 0) { \ + *state_mref_write_back = \ + hash2_save_trap_state(state_mref, \ + hash_xor_pairs, \ + hash, \ + p, \ + term, \ + ESTK_DEF_STACK(s), \ + s, \ + location_name, \ + &ctx, \ + sizeof(ctx)); \ + return 0; \ + L_##location_name: \ + ctx = context->trap_location_state. location_name; \ + } \ + } while(0) + +#define TRAP_LOCATION(location_name) \ + do { \ + if (can_trap) { \ + iterations_until_trap--; \ + TRAP_LOCATION_NO_RED(location_name); \ + } \ + } while(0) + +#define TRAP_LOCATION_NO_CTX(location_name) \ + do { \ + ErtsMakeHash2Context_EMPTY ctx; \ + TRAP_LOCATION(location_name); \ + } while(0) + + /* Optimization. Simple cases before declaration of estack. */ + if (primary_tag(term) == TAG_PRIMARY_IMMED1) { + switch (term & _TAG_IMMED1_MASK) { + case _TAG_IMMED1_IMMED2: + switch (term & _TAG_IMMED2_MASK) { + case _TAG_IMMED2_ATOM: + /* Fast, but the poor hash value should be mixed. */ + return atom_tab(atom_val(term))->slot.bucket.hvalue; + } + break; + case _TAG_IMMED1_SMALL: + { + Sint small = signed_val(term); + if (SMALL_BITS > 28 && !IS_SSMALL28(small)) { + hash = 0; + NOT_SSMALL28_HASH(small); + return hash; + } + hash = 0; + SINT32_HASH(small, HCONST); + return hash; + } + } + }; + { + Eterm tmp; + long max_iterations = 0; + long iterations_until_trap = 0; + Eterm state_mref = THE_NON_VALUE; + ErtsMakeHash2Context* context = NULL; + DECLARE_ESTACK(s); + ESTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK); + if(can_trap){ +#ifdef DEBUG + (void)ITERATIONS_PER_RED; + iterations_until_trap = max_iterations = + (1103515245 * (ERTS_BIF_REDS_LEFT(p)) + 12345) % 227; +#else + iterations_until_trap = max_iterations = + ITERATIONS_PER_RED * ERTS_BIF_REDS_LEFT(p); +#endif + } + if (can_trap && is_internal_magic_ref(term)) { + Binary* state_bin; + state_mref = term; + state_bin = erts_magic_ref2bin(state_mref); + if (ERTS_MAGIC_BIN_DESTRUCTOR(state_bin) == make_hash2_ctx_bin_dtor) { + /* Restore state after a trap */ + context = ERTS_MAGIC_BIN_DATA(state_bin); + term = context->term; + hash = context->hash; + hash_xor_pairs = context->hash_xor_pairs; + ESTACK_RESTORE(s, &context->stack); + ASSERT(p->flags & F_DISABLE_GC); + erts_set_gc_state(p, 1); + switch (context->trap_location) { + case hash2_common_3: goto L_hash2_common_3; + case tag_primary_list: goto L_tag_primary_list; + case arityval_subtag: goto L_arityval_subtag; + case hamt_subtag_head_flatmap: goto L_hamt_subtag_head_flatmap; + case map_subtag: goto L_map_subtag; + case fun_subtag: goto L_fun_subtag; + case neg_big_subtag: goto L_neg_big_subtag; + case sub_binary_subtag_1: goto L_sub_binary_subtag_1; + case sub_binary_subtag_2: goto L_sub_binary_subtag_2; + case hash2_common_1: goto L_hash2_common_1; + case hash2_common_2: goto L_hash2_common_2; + } + } + } + hash = 0; + for (;;) { + switch (primary_tag(term)) { + case TAG_PRIMARY_LIST: + { + ErtsMakeHash2Context_TAG_PRIMARY_LIST ctx = { + .c = 0, + .sh = 0, + .ptr = list_val(term)}; + while (is_byte(*ctx.ptr)) { + /* Optimization for strings. */ + ctx.sh = (ctx.sh << 8) + unsigned_val(*ctx.ptr); + if (ctx.c == 3) { + UINT32_HASH(ctx.sh, HCONST_4); + ctx.c = ctx.sh = 0; + } else { + ctx.c++; + } + term = CDR(ctx.ptr); + if (is_not_list(term)) + break; + ctx.ptr = list_val(term); + TRAP_LOCATION(tag_primary_list); + } + if (ctx.c > 0) + UINT32_HASH(ctx.sh, HCONST_4); + if (is_list(term)) { + tmp = CDR(ctx.ptr); + ESTACK_PUSH(s, tmp); + term = CAR(ctx.ptr); + } + } + break; + case TAG_PRIMARY_BOXED: + { + Eterm hdr = *boxed_val(term); + ASSERT(is_header(hdr)); + switch (hdr & _TAG_HEADER_MASK) { + case ARITYVAL_SUBTAG: + { + ErtsMakeHash2Context_ARITYVAL_SUBTAG ctx = { + .i = 0, + .arity = header_arity(hdr), + .elem = tuple_val(term)}; + UINT32_HASH(ctx.arity, HCONST_9); + if (ctx.arity == 0) /* Empty tuple */ + goto hash2_common; + for (ctx.i = ctx.arity; ; ctx.i--) { + term = ctx.elem[ctx.i]; + if (ctx.i == 1) + break; + ESTACK_PUSH(s, term); + TRAP_LOCATION(arityval_subtag); + } + } + break; + case MAP_SUBTAG: + { + Uint size; + ErtsMakeHash2Context_MAP_SUBTAG ctx = { + .ptr = boxed_val(term) + 1, + .i = 0}; + switch (hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_FLATMAP: + { + flatmap_t *mp = (flatmap_t *)flatmap_val(term); + ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP ctx = { + .ks = flatmap_get_keys(mp), + .vs = flatmap_get_values(mp), + .i = 0, + .size = flatmap_get_size(mp)}; + UINT32_HASH(ctx.size, HCONST_16); + if (ctx.size == 0) + goto hash2_common; + + /* We want a portable hash function that is *independent* of + * the order in which keys and values are encountered. + * We therefore calculate context independent hashes for all + * key-value pairs and then xor them together. + */ + ESTACK_PUSH(s, hash_xor_pairs); + ESTACK_PUSH(s, hash); + ESTACK_PUSH(s, HASH_MAP_TAIL); + hash = 0; + hash_xor_pairs = 0; + for (ctx.i = ctx.size - 1; ctx.i >= 0; ctx.i--) { + ESTACK_PUSH(s, HASH_MAP_PAIR); + ESTACK_PUSH(s, ctx.vs[ctx.i]); + ESTACK_PUSH(s, ctx.ks[ctx.i]); + TRAP_LOCATION(hamt_subtag_head_flatmap); + } + goto hash2_common; + } + + case HAMT_SUBTAG_HEAD_ARRAY: + case HAMT_SUBTAG_HEAD_BITMAP: + size = *ctx.ptr++; + UINT32_HASH(size, HCONST_16); + if (size == 0) + goto hash2_common; + ESTACK_PUSH(s, hash_xor_pairs); + ESTACK_PUSH(s, hash); + ESTACK_PUSH(s, HASH_MAP_TAIL); + hash = 0; + hash_xor_pairs = 0; + } + switch (hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_ARRAY: + ctx.i = 16; + break; + case HAMT_SUBTAG_HEAD_BITMAP: + case HAMT_SUBTAG_NODE_BITMAP: + ctx.i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); + break; + default: + erts_exit(ERTS_ERROR_EXIT, "bad header"); + } + while (ctx.i) { + if (is_list(*ctx.ptr)) { + Eterm* cons = list_val(*ctx.ptr); + ESTACK_PUSH(s, HASH_MAP_PAIR); + ESTACK_PUSH(s, CDR(cons)); + ESTACK_PUSH(s, CAR(cons)); + } + else { + ASSERT(is_boxed(*ctx.ptr)); + if (is_tuple(*ctx.ptr)) { /* collision node */ + Eterm *coll_ptr = tuple_val(*ctx.ptr); + Uint n = arityval(*coll_ptr); + ASSERT(n >= 2); + coll_ptr++; + for (; n; n--, coll_ptr++) { + Eterm* cons = list_val(*coll_ptr); + ESTACK_PUSH3(s, HASH_MAP_PAIR, CDR(cons), CAR(cons)); + } + } + else + ESTACK_PUSH(s, *ctx.ptr); + } + ctx.i--; ctx.ptr++; + TRAP_LOCATION(map_subtag); + } + goto hash2_common; + } + break; + + case FUN_SUBTAG: + { + ErlFunThing* funp = (ErlFunThing *) fun_val(term); + + if (is_local_fun(funp)) { + ErlFunEntry* fe = funp->entry.fun; + ErtsMakeHash2Context_FUN_SUBTAG ctx = { + .num_free = funp->num_free, + .bptr = NULL}; + + UINT32_HASH_2 + (ctx.num_free, + atom_tab(atom_val(fe->module))->slot.bucket.hvalue, + HCONST); + UINT32_HASH_2 + (fe->index, fe->old_uniq, HCONST); + if (ctx.num_free == 0) { + goto hash2_common; + } else { + ctx.bptr = funp->env + ctx.num_free - 1; + while (ctx.num_free-- > 1) { + term = *ctx.bptr--; + ESTACK_PUSH(s, term); + TRAP_LOCATION(fun_subtag); + } + term = *ctx.bptr; + } + } else { + Export *ep = funp->entry.exp; + + ASSERT(is_external_fun(funp) && funp->next == NULL); + + UINT32_HASH_2 + (ep->info.mfa.arity, + atom_tab(atom_val(ep->info.mfa.module))->slot.bucket.hvalue, + HCONST); + UINT32_HASH + (atom_tab(atom_val(ep->info.mfa.function))->slot.bucket.hvalue, + HCONST_14); + + goto hash2_common; + } + } + break; + case REFC_BINARY_SUBTAG: + case HEAP_BINARY_SUBTAG: + case SUB_BINARY_SUBTAG: + { +#define BYTE_BITS 8 + ErtsMakeHash2Context_SUB_BINARY_SUBTAG ctx = { + .bptr = 0, + /* !!!!!!!!!!!!!!!!!!!! OBS !!!!!!!!!!!!!!!!!!!! + * + * The size is truncated to 32 bits on the line + * below so that the code is compatible with old + * versions of the code. This means that hash + * values for binaries with a size greater than + * 4GB do not take all bytes in consideration. + * + * !!!!!!!!!!!!!!!!!!!! OBS !!!!!!!!!!!!!!!!!!!! + */ + .sz = (0xFFFFFFFF & binary_size(term)), + .bitsize = 0, + .bitoffs = 0, + .no_bytes_processed = 0 + }; + Uint32 con = HCONST_13 + hash; + Uint iters_for_bin = MAX(1, ctx.sz / BLOCK_HASH_BYTES_PER_ITER); + ERTS_GET_BINARY_BYTES(term, ctx.bptr, ctx.bitoffs, ctx.bitsize); + if (ctx.sz == 0 && ctx.bitsize == 0) { + hash = con; + } else if (ctx.bitoffs == 0 && + (!can_trap || + (iterations_until_trap - iters_for_bin) > 0)) { + /* No need to trap while hashing binary */ + if (can_trap) iterations_until_trap -= iters_for_bin; + hash = block_hash(ctx.bptr, ctx.sz, con); + if (ctx.bitsize > 0) { + UINT32_HASH_2(ctx.bitsize, + (ctx.bptr[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), + HCONST_15); + } + } else if (ctx.bitoffs == 0) { + /* Need to trap while hashing binary */ + ErtsBlockHashHelperCtx* block_hash_ctx = &ctx.block_hash_ctx; + block_hash_setup(con, block_hash_ctx); + do { + Uint max_bytes_to_process = + iterations_until_trap <= 0 ? BLOCK_HASH_BYTES_PER_ITER : + iterations_until_trap * BLOCK_HASH_BYTES_PER_ITER; + Uint bytes_left = ctx.sz - ctx.no_bytes_processed; + Uint even_bytes_left = + bytes_left - (bytes_left % BLOCK_HASH_BYTES_PER_ITER); + Uint bytes_to_process = + MIN(max_bytes_to_process, even_bytes_left); + block_hash_buffer(&ctx.bptr[ctx.no_bytes_processed], + bytes_to_process, + block_hash_ctx); + ctx.no_bytes_processed += bytes_to_process; + iterations_until_trap -= + MAX(1, bytes_to_process / BLOCK_HASH_BYTES_PER_ITER); + TRAP_LOCATION_NO_RED(sub_binary_subtag_1); + block_hash_ctx = &ctx.block_hash_ctx; /* Restore after trap */ + } while ((ctx.sz - ctx.no_bytes_processed) >= + BLOCK_HASH_BYTES_PER_ITER); + hash = block_hash_final_bytes(ctx.bptr + + ctx.no_bytes_processed, + ctx.sz - ctx.no_bytes_processed, + ctx.sz, + block_hash_ctx); + if (ctx.bitsize > 0) { + UINT32_HASH_2(ctx.bitsize, + (ctx.bptr[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), + HCONST_15); + } + } else if (/* ctx.bitoffs != 0 && */ + (!can_trap || + (iterations_until_trap - iters_for_bin) > 0)) { + /* No need to trap while hashing binary */ + Uint nr_of_bytes = ctx.sz + (ctx.bitsize != 0); + byte *buf = erts_alloc(ERTS_ALC_T_TMP, nr_of_bytes); + Uint nr_of_bits_to_copy = ctx.sz*BYTE_BITS+ctx.bitsize; + if (can_trap) iterations_until_trap -= iters_for_bin; + erts_copy_bits(ctx.bptr, + ctx.bitoffs, 1, buf, 0, 1, nr_of_bits_to_copy); + hash = block_hash(buf, ctx.sz, con); + if (ctx.bitsize > 0) { + UINT32_HASH_2(ctx.bitsize, + (buf[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), + HCONST_15); + } + erts_free(ERTS_ALC_T_TMP, buf); + } else /* ctx.bitoffs != 0 && */ { +#ifdef DEBUG +#define BINARY_BUF_SIZE (BLOCK_HASH_BYTES_PER_ITER * 3) +#else +#define BINARY_BUF_SIZE (BLOCK_HASH_BYTES_PER_ITER * 256) +#endif +#define BINARY_BUF_SIZE_BITS (BINARY_BUF_SIZE*BYTE_BITS) + /* Need to trap while hashing binary */ + ErtsBlockHashHelperCtx* block_hash_ctx = &ctx.block_hash_ctx; + Uint nr_of_bytes = ctx.sz + (ctx.bitsize != 0); + ERTS_CT_ASSERT(BINARY_BUF_SIZE % BLOCK_HASH_BYTES_PER_ITER == 0); + ctx.buf = erts_alloc(ERTS_ALC_T_PHASH2_TRAP, + MIN(nr_of_bytes, BINARY_BUF_SIZE)); + block_hash_setup(con, block_hash_ctx); + do { + Uint bytes_left = + ctx.sz - ctx.no_bytes_processed; + Uint even_bytes_left = + bytes_left - (bytes_left % BLOCK_HASH_BYTES_PER_ITER); + Uint bytes_to_process = + MIN(BINARY_BUF_SIZE, even_bytes_left); + Uint nr_of_bits_left = + (ctx.sz*BYTE_BITS+ctx.bitsize) - + ctx.no_bytes_processed*BYTE_BITS; + Uint nr_of_bits_to_copy = + MIN(nr_of_bits_left, BINARY_BUF_SIZE_BITS); + ctx.done = nr_of_bits_left == nr_of_bits_to_copy; + erts_copy_bits(ctx.bptr + ctx.no_bytes_processed, + ctx.bitoffs, 1, ctx.buf, 0, 1, + nr_of_bits_to_copy); + block_hash_buffer(ctx.buf, + bytes_to_process, + block_hash_ctx); + ctx.no_bytes_processed += bytes_to_process; + iterations_until_trap -= + MAX(1, bytes_to_process / BLOCK_HASH_BYTES_PER_ITER); + TRAP_LOCATION_NO_RED(sub_binary_subtag_2); + block_hash_ctx = &ctx.block_hash_ctx; /* Restore after trap */ + } while (!ctx.done); + nr_of_bytes = ctx.sz + (ctx.bitsize != 0); + hash = block_hash_final_bytes(ctx.buf + + (ctx.no_bytes_processed - + ((nr_of_bytes-1) / BINARY_BUF_SIZE) * BINARY_BUF_SIZE), + ctx.sz - ctx.no_bytes_processed, + ctx.sz, + block_hash_ctx); + if (ctx.bitsize > 0) { + Uint last_byte_index = + nr_of_bytes - (((nr_of_bytes-1) / BINARY_BUF_SIZE) * BINARY_BUF_SIZE) -1; + UINT32_HASH_2(ctx.bitsize, + (ctx.buf[last_byte_index] >> (BYTE_BITS - ctx.bitsize)), + HCONST_15); + } + erts_free(ERTS_ALC_T_PHASH2_TRAP, ctx.buf); + context->trap_location_state.sub_binary_subtag_2.buf = NULL; + } + goto hash2_common; +#undef BYTE_BITS +#undef BINARY_BUF_SIZE +#undef BINARY_BUF_SIZE_BITS + } + break; + case POS_BIG_SUBTAG: + case NEG_BIG_SUBTAG: + { + Eterm* big_val_ptr = big_val(term); + ErtsMakeHash2Context_NEG_BIG_SUBTAG ctx = { + .ptr = big_val_ptr, + .i = 0, + .n = BIG_SIZE(big_val_ptr), + .con = BIG_SIGN(big_val_ptr) ? HCONST_10 : HCONST_11}; +#if D_EXP == 16 + do { + Uint32 x, y; + x = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; + x += (Uint32)(ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0) << 16; + y = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; + y += (Uint32)(ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0) << 16; + UINT32_HASH_2(x, y, ctx.con); + TRAP_LOCATION(neg_big_subtag); + } while (ctx.i < ctx.n); +#elif D_EXP == 32 + do { + Uint32 x, y; + x = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; + y = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; + UINT32_HASH_2(x, y, ctx.con); + TRAP_LOCATION(neg_big_subtag); + } while (ctx.i < ctx.n); +#elif D_EXP == 64 + do { + Uint t; + Uint32 x, y; + ASSERT(ctx.i < ctx.n); + t = BIG_DIGIT(ctx.ptr, ctx.i++); + x = t & 0xffffffff; + y = t >> 32; + UINT32_HASH_2(x, y, ctx.con); + TRAP_LOCATION(neg_big_subtag); + } while (ctx.i < ctx.n); +#else +#error "unsupported D_EXP size" +#endif + goto hash2_common; + } + break; + case REF_SUBTAG: + /* All parts of the ref should be hashed. */ + UINT32_HASH(internal_ref_numbers(term)[0], HCONST_7); + goto hash2_common; + break; + case EXTERNAL_REF_SUBTAG: + /* All parts of the ref should be hashed. */ + UINT32_HASH(external_ref_numbers(term)[0], HCONST_7); + goto hash2_common; + break; + case EXTERNAL_PID_SUBTAG: + /* Only 15 bits are hashed. */ + UINT32_HASH(external_pid_number(term), HCONST_5); + goto hash2_common; + case EXTERNAL_PORT_SUBTAG: { + Uint64 number = external_port_number(term); + Uint32 low = (Uint32) (number & 0xffffffff); + Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); + UINT32_HASH_2(low, high, HCONST_6); + goto hash2_common; + } + case FLOAT_SUBTAG: + { + FloatDef ff; + GET_DOUBLE(term, ff); + if (ff.fd == 0.0f) { + /* ensure positive 0.0 */ + ff.fd = erts_get_positive_zero_float(); + } +#if defined(WORDS_BIGENDIAN) || defined(DOUBLE_MIDDLE_ENDIAN) + UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12); +#else + UINT32_HASH_2(ff.fw[1], ff.fw[0], HCONST_12); +#endif + goto hash2_common; + } + break; + + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); + } + } + break; + case TAG_PRIMARY_IMMED1: + switch (term & _TAG_IMMED1_MASK) { + case _TAG_IMMED1_PID: + /* Only 15 bits are hashed. */ + UINT32_HASH(internal_pid_number(term), HCONST_5); + goto hash2_common; + case _TAG_IMMED1_PORT: { + Uint64 number = internal_port_number(term); + Uint32 low = (Uint32) (number & 0xffffffff); + Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); + UINT32_HASH_2(low, high, HCONST_6); + goto hash2_common; + } + case _TAG_IMMED1_IMMED2: + switch (term & _TAG_IMMED2_MASK) { + case _TAG_IMMED2_ATOM: + if (hash == 0) + /* Fast, but the poor hash value should be mixed. */ + hash = atom_tab(atom_val(term))->slot.bucket.hvalue; + else + UINT32_HASH(atom_tab(atom_val(term))->slot.bucket.hvalue, + HCONST_3); + goto hash2_common; + case _TAG_IMMED2_NIL: + if (hash == 0) + hash = 3468870702UL; + else + UINT32_HASH(NIL_DEF, HCONST_2); + goto hash2_common; + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); + } + case _TAG_IMMED1_SMALL: + { + Sint small = signed_val(term); + if (SMALL_BITS > 28 && !IS_SSMALL28(small)) { + NOT_SSMALL28_HASH(small); + } else { + SINT32_HASH(small, HCONST); + } + + goto hash2_common; + } + } + break; + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); + hash2_common: + + /* Uint32 hash always has the hash value of the previous term, + * compounded or otherwise. + */ + + if (ESTACK_ISEMPTY(s)) { + DESTROY_ESTACK(s); + if (can_trap) { + BUMP_REDS(p, (max_iterations - iterations_until_trap) / ITERATIONS_PER_RED); + ASSERT(!(p->flags & F_DISABLE_GC)); + } + return hash; + } + + term = ESTACK_POP(s); + + switch (term) { + case HASH_MAP_TAIL: { + hash = (Uint32) ESTACK_POP(s); + UINT32_HASH(hash_xor_pairs, HCONST_19); + hash_xor_pairs = (Uint32) ESTACK_POP(s); + TRAP_LOCATION_NO_CTX(hash2_common_1); + goto hash2_common; + } + case HASH_MAP_PAIR: + hash_xor_pairs ^= hash; + hash = 0; + TRAP_LOCATION_NO_CTX(hash2_common_2); + goto hash2_common; + default: + break; + } + + } + TRAP_LOCATION_NO_CTX(hash2_common_3); + } + } +#undef TRAP_LOCATION_NO_RED +#undef TRAP_LOCATION +#undef TRAP_LOCATION_NO_CTX +} + +Uint32 +make_hash2(Eterm term) +{ + return make_hash2_helper(term, 0, NULL, NULL); +} + +Uint32 +trapping_make_hash2(Eterm term, Eterm* state_mref_write_back, Process* p) +{ + return make_hash2_helper(term, 1, state_mref_write_back, p); +} + +/* Term hash function for internal use. + * + * Limitation #1: Is not "portable" in any way between different VM instances. + * + * Limitation #2: The hash value is only valid as long as the term exists + * somewhere in the VM. Why? Because external pids, ports and refs are hashed + * by mixing the node *pointer* value. If a node disappears and later reappears + * with a new ErlNode struct, externals from that node will hash different than + * before. + * + * The property "EVERY BIT of the term that is significant for equality + * MUST BE USED AS INPUT FOR THE HASH" is nice but no longer crucial for the + * hashmap implementation that now uses collision nodes at the bottom of + * the HAMT when all hash bits are exhausted. + * + */ + +/* Use a better mixing function if available. */ +#if defined(ERL_INTERNAL_HASH_CRC32C) +# undef MIX +# if defined(__x86_64__) +# define MIX(a,b,c) \ + do { \ + Uint32 initial_hash = c; \ + c = __builtin_ia32_crc32si(c, a); \ + c = __builtin_ia32_crc32si(c + initial_hash, b); \ + } while(0) +# elif defined(__aarch64__) +# define MIX(a,b,c) \ + do { \ + Uint32 initial_hash = c; \ + c = __crc32cw(c, a); \ + c = __crc32cw(c + initial_hash, b); \ + } while(0) +# else +# error "No suitable CRC32 intrinsic available." +# endif +#endif + +#define CONST_HASH(AConst) \ + do { /* Lightweight mixing of constant (type info) */ \ + hash ^= AConst; \ + hash = (hash << 17) ^ (hash >> (32-17)); \ + } while (0) + +/* + * Start with salt, 32-bit prime number, to avoid getting same hash as phash2 + * which can cause bad hashing in distributed ETS tables for example. + */ +#define INTERNAL_HASH_SALT 3432918353U + +Uint32 +make_internal_hash(Eterm term, Uint32 salt) +{ + Uint32 hash = salt ^ INTERNAL_HASH_SALT; + + /* Optimization. Simple cases before declaration of estack. */ + if (primary_tag(term) == TAG_PRIMARY_IMMED1) { + #if ERTS_SIZEOF_ETERM == 8 + UINT32_HASH_2((Uint32)term, (Uint32)(term >> 32), HCONST); + #elif ERTS_SIZEOF_ETERM == 4 + UINT32_HASH(term, HCONST); + #else + # error "No you don't" + #endif + return hash; + } + { + Eterm tmp; + DECLARE_ESTACK(s); + + for (;;) { + switch (primary_tag(term)) { + case TAG_PRIMARY_LIST: + { + int c = 0; + Uint32 sh = 0; + Eterm* ptr = list_val(term); + while (is_byte(*ptr)) { + /* Optimization for strings. */ + sh = (sh << 8) + unsigned_val(*ptr); + if (c == 3) { + UINT32_HASH(sh, HCONST_4); + c = sh = 0; + } else { + c++; + } + term = CDR(ptr); + if (is_not_list(term)) + break; + ptr = list_val(term); + } + if (c > 0) + UINT32_HASH_2(sh, (Uint32)c, HCONST_22); + + if (is_list(term)) { + tmp = CDR(ptr); + CONST_HASH(HCONST_17); /* Hash CAR in cons cell */ + ESTACK_PUSH(s, tmp); + if (is_not_list(tmp)) { + ESTACK_PUSH(s, HASH_CDR); + } + term = CAR(ptr); + } + } + break; + case TAG_PRIMARY_BOXED: + { + Eterm hdr = *boxed_val(term); + ASSERT(is_header(hdr)); + switch (hdr & _TAG_HEADER_MASK) { + case ARITYVAL_SUBTAG: + { + int i; + int arity = header_arity(hdr); + Eterm* elem = tuple_val(term); + UINT32_HASH(arity, HCONST_9); + if (arity == 0) /* Empty tuple */ + goto pop_next; + for (i = arity; ; i--) { + term = elem[i]; + if (i == 1) + break; + ESTACK_PUSH(s, term); + } + } + break; + + case MAP_SUBTAG: + { + Eterm* ptr = boxed_val(term) + 1; + Uint size; + int i; + + /* + * We rely on key-value iteration order being constant + * for identical maps (in this VM instance). + */ + switch (hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_FLATMAP: + { + flatmap_t *mp = (flatmap_t *)flatmap_val(term); + Eterm *ks = flatmap_get_keys(mp); + Eterm *vs = flatmap_get_values(mp); + size = flatmap_get_size(mp); + UINT32_HASH(size, HCONST_16); + if (size == 0) + goto pop_next; + + for (i = size - 1; i >= 0; i--) { + ESTACK_PUSH(s, vs[i]); + ESTACK_PUSH(s, ks[i]); + } + goto pop_next; + } + case HAMT_SUBTAG_HEAD_ARRAY: + case HAMT_SUBTAG_HEAD_BITMAP: + size = *ptr++; + UINT32_HASH(size, HCONST_16); + if (size == 0) + goto pop_next; + } + switch (hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_ARRAY: + i = 16; + break; + case HAMT_SUBTAG_HEAD_BITMAP: + case HAMT_SUBTAG_NODE_BITMAP: + i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); + break; + default: + erts_exit(ERTS_ERROR_EXIT, "bad header"); + } + while (i) { + if (is_list(*ptr)) { + Eterm* cons = list_val(*ptr); + ESTACK_PUSH(s, CDR(cons)); + ESTACK_PUSH(s, CAR(cons)); + } + else { + ASSERT(is_boxed(*ptr)); + /* no special treatment of collision nodes needed, + hash them as the tuples they are */ + ESTACK_PUSH(s, *ptr); + } + i--; ptr++; + } + goto pop_next; + } + break; + case FUN_SUBTAG: + { + ErlFunThing* funp = (ErlFunThing *) fun_val(term); + + if (is_local_fun(funp)) { + ErlFunEntry* fe = funp->entry.fun; + Uint num_free = funp->num_free; + UINT32_HASH_2(num_free, fe->module, HCONST_20); + UINT32_HASH_2(fe->index, fe->old_uniq, HCONST_21); + if (num_free == 0) { + goto pop_next; + } else { + Eterm* bptr = funp->env + num_free - 1; + while (num_free-- > 1) { + term = *bptr--; + ESTACK_PUSH(s, term); + } + term = *bptr; + } + } else { + ASSERT(is_external_fun(funp) && funp->next == NULL); + + /* Assumes Export entries never move */ + POINTER_HASH(funp->entry.exp, HCONST_14); + goto pop_next; + } + } + break; + case REFC_BINARY_SUBTAG: + case HEAP_BINARY_SUBTAG: + case SUB_BINARY_SUBTAG: + { + byte* bptr; + Uint sz = binary_size(term); + Uint32 con = HCONST_13 + hash; + Uint bitoffs; + Uint bitsize; + + ERTS_GET_BINARY_BYTES(term, bptr, bitoffs, bitsize); + if (sz == 0 && bitsize == 0) { + hash = con; + } else { + if (bitoffs == 0) { + hash = block_hash(bptr, sz, con); + if (bitsize > 0) { + UINT32_HASH_2(bitsize, (bptr[sz] >> (8 - bitsize)), + HCONST_15); + } + } else { + byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, + sz + (bitsize != 0)); + erts_copy_bits(bptr, bitoffs, 1, buf, 0, 1, sz*8+bitsize); + hash = block_hash(buf, sz, con); + if (bitsize > 0) { + UINT32_HASH_2(bitsize, (buf[sz] >> (8 - bitsize)), + HCONST_15); + } + erts_free(ERTS_ALC_T_TMP, (void *) buf); + } + } + goto pop_next; + } + break; + case POS_BIG_SUBTAG: + case NEG_BIG_SUBTAG: + { + Eterm* ptr = big_val(term); + Uint i = 0; + Uint n = BIG_SIZE(ptr); + Uint32 con = BIG_SIGN(ptr) ? HCONST_10 : HCONST_11; +#if D_EXP == 16 + do { + Uint32 x, y; + x = i < n ? BIG_DIGIT(ptr, i++) : 0; + x += (Uint32)(i < n ? BIG_DIGIT(ptr, i++) : 0) << 16; + y = i < n ? BIG_DIGIT(ptr, i++) : 0; + y += (Uint32)(i < n ? BIG_DIGIT(ptr, i++) : 0) << 16; + UINT32_HASH_2(x, y, con); + } while (i < n); +#elif D_EXP == 32 + do { + Uint32 x, y; + x = i < n ? BIG_DIGIT(ptr, i++) : 0; + y = i < n ? BIG_DIGIT(ptr, i++) : 0; + UINT32_HASH_2(x, y, con); + } while (i < n); +#elif D_EXP == 64 + do { + Uint t; + Uint32 x, y; + ASSERT(i < n); + t = BIG_DIGIT(ptr, i++); + x = t & 0xffffffff; + y = t >> 32; + UINT32_HASH_2(x, y, con); + } while (i < n); +#else +#error "unsupported D_EXP size" +#endif + goto pop_next; + } + break; + case REF_SUBTAG: { + Uint32 *numbers = internal_ref_numbers(term); + ASSERT(internal_ref_no_numbers(term) >= 3); + UINT32_HASH(numbers[0], HCONST_7); + UINT32_HASH_2(numbers[1], numbers[2], HCONST_8); + if (is_internal_pid_ref(term)) { +#ifdef ARCH_64 + ASSERT(internal_ref_no_numbers(term) == 5); + UINT32_HASH_2(numbers[3], numbers[4], HCONST_9); +#else + ASSERT(internal_ref_no_numbers(term) == 4); + UINT32_HASH(numbers[3], HCONST_9); +#endif + } + goto pop_next; + } + case EXTERNAL_REF_SUBTAG: + { + ExternalThing* thing = external_thing_ptr(term); + Uint n = external_thing_ref_no_numbers(thing); + Uint32 *numbers = external_thing_ref_numbers(thing); + + /* Can contain 0 to 5 32-bit numbers... */ + + /* See limitation #2 */ + switch (n) { + case 5: { + Uint32 num4 = numbers[4]; + if (0) { + case 4: + num4 = 0; + /* Fall through... */ + } + UINT32_HASH_2(numbers[3], num4, HCONST_9); + /* Fall through... */ + } + case 3: { + Uint32 num2 = numbers[2]; + if (0) { + case 2: + num2 = 0; + /* Fall through... */ + } + UINT32_HASH_2(numbers[1], num2, HCONST_8); + /* Fall through... */ + } + case 1: +#ifdef ARCH_64 + POINTER_HASH(thing->node, HCONST_7); + UINT32_HASH(numbers[0], HCONST_7); +#else + UINT32_HASH_2(thing->node, numbers[0], HCONST_7); +#endif + break; + case 0: + POINTER_HASH(thing->node, HCONST_7); + break; + default: + ASSERT(!"Invalid amount of external reference numbers"); + break; + } + goto pop_next; + } + case EXTERNAL_PID_SUBTAG: { + ExternalThing* thing = external_thing_ptr(term); + /* See limitation #2 */ + POINTER_HASH(thing->node, HCONST_5); + UINT32_HASH_2(thing->data.pid.num, thing->data.pid.ser, HCONST_5); + goto pop_next; + } + case EXTERNAL_PORT_SUBTAG: { + ExternalThing* thing = external_thing_ptr(term); + /* See limitation #2 */ + POINTER_HASH(thing->node, HCONST_6); + UINT32_HASH_2(thing->data.ui32[0], thing->data.ui32[1], HCONST_6); + goto pop_next; + } + case FLOAT_SUBTAG: + { + FloatDef ff; + GET_DOUBLE(term, ff); + if (ff.fd == 0.0f) { + /* ensure positive 0.0 */ + ff.fd = erts_get_positive_zero_float(); + } + UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12); + goto pop_next; + } + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_internal_hash(0x%X, %lu)\n", term, salt); + } + } + break; + case TAG_PRIMARY_IMMED1: + #if ERTS_SIZEOF_ETERM == 8 + UINT32_HASH_2((Uint32)term, (Uint32)(term >> 32), HCONST); + #else + UINT32_HASH(term, HCONST); + #endif + goto pop_next; + + default: + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_internal_hash(0x%X, %lu)\n", term, salt); + + pop_next: + if (ESTACK_ISEMPTY(s)) { + DESTROY_ESTACK(s); + + return hash; + } + + term = ESTACK_POP(s); + + switch (term) { + case HASH_CDR: + CONST_HASH(HCONST_18); /* Hash CDR i cons cell */ + goto pop_next; + default: + break; + } + } + } + } + +} + +#ifdef DBG_HASHMAP_COLLISION_BONANZA +Uint32 erts_dbg_hashmap_collision_bonanza(Uint32 hash, Eterm key) +{ +/*{ + static Uint32 hashvec[7] = { + 0x02345678, + 0x12345678, + 0xe2345678, + 0xf2345678, + 0x12abcdef, + 0x13abcdef, + 0xcafebabe + }; + hash = hashvec[hash % (sizeof(hashvec) / sizeof(hashvec[0]))]; + }*/ + const Uint32 bad_hash = (hash & 0x12482481) * 1442968193; + const Uint32 bad_bits = hash % 67; + if (bad_bits < 32) { + /* Mix in a number of high good bits to get "randomly" close + to the collision nodes */ + const Uint32 bad_mask = (1 << bad_bits) - 1; + return (hash & ~bad_mask) | (bad_hash & bad_mask); + } + return bad_hash; +} +#endif + +/* Term hash function for hashmaps */ +Uint32 make_map_hash(Eterm key) { + Uint32 hash; + + hash = make_internal_hash(key, 0); + +#ifdef DBG_HASHMAP_COLLISION_BONANZA + hash = erts_dbg_hashmap_collision_bonanza(hash, key); +#endif + return hash; +} + +#undef CONST_HASH +#undef HASH_MAP_TAIL +#undef HASH_MAP_PAIR +#undef HASH_CDR + +#undef UINT32_HASH_2 +#undef UINT32_HASH +#undef SINT32_HASH + +#undef HCONST +#undef MIX diff --git a/erts/emulator/beam/erl_term_hashing.h b/erts/emulator/beam/erl_term_hashing.h new file mode 100644 index 000000000000..8a898b7c52f1 --- /dev/null +++ b/erts/emulator/beam/erl_term_hashing.h @@ -0,0 +1,79 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + */ + +#ifndef ERL_TERM_HASHING_H__ +#define ERL_TERM_HASHING_H__ + +#include "sys.h" +#include "erl_drv_nif.h" + +#if (defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)) || \ + (defined(__x86_64__) && defined(__SSE4_2__)) +# define ERL_INTERNAL_HASH_CRC32C +#endif + +typedef struct { + Uint32 a,b,c; +} ErtsBlockHashHelperCtx; + +typedef struct { + ErtsBlockHashHelperCtx hctx; + const byte *ptr; + Uint len; + Uint tot_len; +} ErtsBlockHashState; + +typedef struct { + ErtsBlockHashHelperCtx hctx; + SysIOVec* iov; + Uint vlen; + Uint tot_len; + int vix; + int ix; +} ErtsIovBlockHashState; + +Uint32 make_hash2(Eterm); +Uint32 trapping_make_hash2(Eterm, Eterm*, struct process*); +Uint32 make_hash(Eterm); +Uint32 make_internal_hash(Eterm, Uint32 salt); +#ifdef DEBUG +# define DBG_HASHMAP_COLLISION_BONANZA +#endif +#ifdef DBG_HASHMAP_COLLISION_BONANZA +Uint32 erts_dbg_hashmap_collision_bonanza(Uint32 hash, Eterm key); +#endif +Uint32 make_map_hash(Eterm key); +void erts_block_hash_init(ErtsBlockHashState *state, + const byte *ptr, + Uint len, + Uint32 initval); +int erts_block_hash(Uint32 *hashp, + Uint *sizep, + ErtsBlockHashState *state); +void erts_iov_block_hash_init(ErtsIovBlockHashState *state, + SysIOVec *iov, + Uint vlen, + Uint32 initval); +int erts_iov_block_hash(Uint32 *hashp, + Uint *sizep, + ErtsIovBlockHashState *state); + + +#endif diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index b7f0069eb00e..ccd0b3aea1b2 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2022. All Rights Reserved. + * Copyright Ericsson AB 2011-2023. 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. @@ -554,6 +554,22 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks) intrnl->unmanaged.callbacks[tpd->id] = *callbacks; } +void +erts_thr_progress_unregister_unmanaged_thread(void) +{ + /* + * If used, the previously registered wakeup callback + * must be prepared for NULL passed as argument. This since + * the callback might be called after this unregistration + * in case of an outstanding wakeup request when unregistration + * is made. + */ + ErtsThrPrgrData* tpd = erts_thr_progress_data(); + ASSERT(tpd->id >= 0); + intrnl->unmanaged.callbacks[tpd->id].arg = NULL; + erts_free(ERTS_ALC_T_THR_PRGR_DATA, tpd); +} + ErtsThrPrgrData * erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp, @@ -847,6 +863,12 @@ update(ErtsThrPrgrData *tpd) int erts_thr_progress_update(ErtsThrPrgrData *tpd) { +#ifdef DEBUG + /* If we've run any code that requires a code barrier, it must have been + * scheduled prior to this point. */ + erts_debug_check_code_barrier(); +#endif + return update(tpd); } @@ -911,10 +933,18 @@ erts_thr_progress_finalize_wait(ErtsThrPrgrData *tpd) break; current = val; } - if (block_count_inc()) - block_thread(tpd); - if (update(tpd)) - leader_update(tpd); + + if (block_count_inc()) { + block_thread(tpd); + } else { + /* Issue a code barrier if one was requested while thread progress was + * blocked. */ + erts_code_ix_finalize_wait(); + } + + if (update(tpd)) { + leader_update(tpd); + } } void @@ -1124,7 +1154,7 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) ASSERT(!erts_thr_progress_has_reached(value)); /* - * This thread is guarranteed to issue a full memory barrier: + * This thread is guaranteed to issue a full memory barrier: * - after the request has been written, but * - before the global thread progress reach the (possibly * increased) requested wakeup value. @@ -1293,6 +1323,10 @@ block_thread(ErtsThrPrgrData *tpd) } while (block_count_inc()); + /* Issue a code barrier if one was requested while thread progress was + * blocked. */ + erts_code_ix_finalize_wait(); + cbp->finalize_wait(cbp->arg); return lflgs; @@ -1383,7 +1417,7 @@ erts_thr_progress_fatal_error_wait(SWord timeout) { /* * Counting poll intervals may give us a too long timeout * if cpu is busy. We use timeout time to try to prevent - * this. In case we havn't got time correction this may + * this. In case we haven't got time correction this may * however fail too... */ timeout_time = erts_get_monotonic_time(esdp); diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h index 82a5f1811d03..3adc8e32c69a 100644 --- a/erts/emulator/beam/erl_thr_progress.h +++ b/erts/emulator/beam/erl_thr_progress.h @@ -127,6 +127,7 @@ void erts_thr_progress_init(int no_schedulers, int managed, int unmanaged); ErtsThrPrgrData *erts_thr_progress_register_managed_thread( ErtsSchedulerData *esdp, ErtsThrPrgrCallbacks *, int, int); void erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *); +void erts_thr_progress_unregister_unmanaged_thread(void); void erts_thr_progress_active(ErtsThrPrgrData *, int on); void erts_thr_progress_wakeup(ErtsThrPrgrData *, ErtsThrPrgrVal value); diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c index aab7c199d2e4..0813c5530e67 100644 --- a/erts/emulator/beam/erl_thr_queue.c +++ b/erts/emulator/beam/erl_thr_queue.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2018. All Rights Reserved. + * Copyright Ericsson AB 2011-2022. 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. @@ -52,7 +52,7 @@ * deallocation. Memory allocation can be moved to another more suitable * thread using erts_thr_q_prepare_enqueue() together with * erts_thr_q_enqueue_prepared() instead of using erts_thr_q_enqueue(). - * Memory deallocation can can be moved to another more suitable thread by + * Memory deallocation can be moved to another more suitable thread by * disabling auto_finalize_dequeue when initializing the queue and then use * erts_thr_q_get_finalize_dequeue_data() together * erts_thr_q_finalize_dequeue() after dequeuing or cleaning. diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index e6f0300e7c6c..ec43772bca7e 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2020. All Rights Reserved. + * Copyright Ericsson AB 2001-2023. 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. @@ -44,6 +44,10 @@ * - ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER * Data dependency read barrier. Orders *only* loads * according to data dependency across the barrier. + * - ERTS_THR_INSTRUCTION_BARRIER + * Instruction synchronization barrier. Orders *only* + * instruction fetches. These are not allowed to be + * reordered over the barrier. * * --- Atomic operations --- * @@ -266,6 +270,23 @@ #define ERTS_THR_READ_MEMORY_BARRIER ETHR_READ_MEMORY_BARRIER #define ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER ETHR_READ_DEPEND_MEMORY_BARRIER +#ifdef ETHR_INSTRUCTION_BARRIER +# define ERTS_THR_INSTRUCTION_BARRIER ETHR_INSTRUCTION_BARRIER +#else +/* !! Note that we DO NOT define a fallback !! + * + * If we cannot issue an instruction barrier ourselves, we are most likely + * running on an operating system that disallows this operation from user-space + * (e.g. MacOS). In that case, we either: + * + * 1. Rely on a system call to do everything for us, including core + * synchronization. + * 2. Lack a way to control instruction cache, and therefore can't use the JIT + * begin with. + * + * In either case we want a compile-time error when this barrier is used. */ +#endif + #ifdef ERTS_ENABLE_LOCK_POSITION #define erts_mtx_lock(L) erts_mtx_lock_x(L, __FILE__, __LINE__) #define erts_mtx_trylock(L) erts_mtx_trylock_x(L, __FILE__, __LINE__) @@ -409,6 +430,7 @@ ERTS_GLB_INLINE void erts_thr_exit(void *res); ERTS_GLB_INLINE void erts_thr_install_exit_handler(void (*exit_handler)(void)); ERTS_GLB_INLINE erts_tid_t erts_thr_self(void); ERTS_GLB_INLINE int erts_thr_getname(erts_tid_t tid, char *buf, size_t len); +ERTS_GLB_INLINE void erts_thr_setname(char *buf); ERTS_GLB_INLINE int erts_equal_tids(erts_tid_t x, erts_tid_t y); ERTS_GLB_INLINE void erts_mtx_init(erts_mtx_t *mtx, const char *name, @@ -445,6 +467,7 @@ ERTS_GLB_INLINE void erts_rwmtx_init(erts_rwmtx_t *rwmtx, char *name, Eterm extra, erts_lock_flags_t flags); +ERTS_GLB_INLINE size_t erts_rwmtx_size(erts_rwmtx_t *rwmtx); ERTS_GLB_INLINE void erts_rwmtx_destroy(erts_rwmtx_t *rwmtx); #ifdef ERTS_ENABLE_LOCK_POSITION ERTS_GLB_INLINE int erts_rwmtx_tryrlock_x(erts_rwmtx_t *rwmtx, const char *file, unsigned int line); @@ -1601,6 +1624,13 @@ erts_thr_getname(erts_tid_t tid, char *buf, size_t len) return ethr_getname(tid, buf, len); } +ERTS_GLB_INLINE void +erts_thr_setname(char *buf) +{ + if (strlen(buf) > ETHR_THR_NAME_MAX) + erts_thr_fatal_error(EINVAL, "too long thread name"); + ethr_setname(buf); +} ERTS_GLB_INLINE int erts_equal_tids(erts_tid_t x, erts_tid_t y) @@ -1883,6 +1913,11 @@ erts_rwmtx_init(erts_rwmtx_t *rwmtx, char *name, Eterm extra, erts_rwmtx_init_opt(rwmtx, NULL, name, extra, flags); } +ERTS_GLB_INLINE size_t +erts_rwmtx_size(erts_rwmtx_t *rwmtx) { + return ethr_rwmutex_size(&rwmtx->rwmtx); +} + ERTS_GLB_INLINE void erts_rwmtx_destroy(erts_rwmtx_t *rwmtx) { diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index cafe7c4af0e6..7af829e738ba 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -216,6 +216,15 @@ update_last_mtime(ErtsSchedulerData *esdp, ErtsMonotonicTime mtime) if (!esdp) esdp = erts_get_scheduler_data(); if (esdp) { +#if 1 + if (mtime < esdp->last_monotonic_time) + erts_exit(ERTS_ABORT_EXIT, + "Monotonic time stepped backwards!\n" + "Previous time: %b64d\n" + "Current time: %b64d\n", + esdp->last_monotonic_time, + mtime); +#endif ASSERT(mtime >= esdp->last_monotonic_time); esdp->last_monotonic_time = mtime; esdp->check_time_reds = 0; @@ -1982,12 +1991,10 @@ send_time_offset_changed_notifications(void *new_offsetp) for (mix = 0; mix < no_monitors; mix++) { *patch_refp = to_mon_info[mix].ref; - erts_proc_sig_send_persistent_monitor_msg(ERTS_MON_TYPE_TIME_OFFSET, - *patch_refp, - am_clock_service, - to_mon_info[mix].pid, - message_template, - hsz); + erts_proc_sig_send_monitor_time_offset_msg(*patch_refp, + to_mon_info[mix].pid, + message_template, + hsz); } erts_free(ERTS_ALC_T_TMP, tmp); @@ -2338,7 +2345,7 @@ erts_napi_convert_time_unit(ErtsMonotonicTime val, int from, int to) { ErtsMonotonicTime ffreq, tfreq, denom; /* - * Convertion between time units using floor function. + * Conversion between time units using floor function. * * Note that this needs to work also for negative * values. Ordinary integer division on a negative @@ -2438,7 +2445,7 @@ BIF_RETTYPE timestamp_0(BIF_ALIST_0) /* * Mega seconds is the only value that potentially - * ever could be a bignum. However, that wont happen + * ever could be a bignum. However, that won't happen * during at least the next 4 million years... * * (System time will also have wrapped in the diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 3ea796e0e3b6..2dd6c99d4c8c 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2021. All Rights Reserved. + * Copyright Ericsson AB 1999-2023. 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. @@ -53,6 +53,7 @@ #include "erl_thr_progress.h" #include "erl_bif_unique.h" #include "erl_map.h" +#include "erl_global_literals.h" #if 0 #define DEBUG_PRINTOUTS @@ -1121,7 +1122,7 @@ erts_call_trace(Process* p, ErtsCodeInfo *info, Binary *match_spec, * use process flags */ tracee_flags = &ERTS_TRACE_FLAGS(p); - /* Is is not ideal at all to call this check twice, + /* It is not ideal at all to call this check twice, it should be optimized so that only one call is made. */ if (!is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif, TRACE_FUN_ENABLED, am_trace_status) @@ -1245,7 +1246,7 @@ erts_call_trace(Process* p, ErtsCodeInfo *info, Binary *match_spec, ASSERT(!ERTS_TRACER_IS_NIL(*tracer)); /* - * Build the the {M,F,A} tuple in the local heap. + * Build the {M,F,A} tuple in the local heap. * (A is arguments or arity.) */ @@ -2472,7 +2473,7 @@ init_sys_msg_dispatcher(void) { erts_thr_opts_t thr_opts = ERTS_THR_OPTS_DEFAULT_INITER; thr_opts.detached = 1; - thr_opts.name = "sys_msg_dispatcher"; + thr_opts.name = "erts_smsg_disp"; init_smq_element_alloc(); sys_message_queue = NULL; sys_message_queue_end = NULL; @@ -2632,6 +2633,9 @@ lookup_tracer_nif(const ErtsTracer tracer) { ErtsTracerNif tnif_tmpl; ErtsTracerNif *tnif; + if (tracer == erts_tracer_nil) { + return NULL; + } tnif_tmpl.module = ERTS_TRACER_MODULE(tracer); ERTS_LC_ASSERT(erts_thr_progress_lc_is_delaying() || erts_get_scheduler_id() > 0); erts_rwmtx_rlock(&tracer_mtx); @@ -2793,8 +2797,12 @@ send_to_tracer_nif_raw(Process *c_p, Process *tracee, map_values[map_elem_count++] = am_monotonic; map->size = map_elem_count; - map->keys = make_tuple(local_heap); - local_heap[0] = make_arityval(map_elem_count); + if (map_elem_count == 0) { + map->keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + map->keys = make_tuple(local_heap); + local_heap[0] = make_arityval(map_elem_count); + } #undef MAP_SIZE erts_nif_call_function(c_p, tracee ? tracee : c_p, @@ -3071,7 +3079,7 @@ erts_tracer_update(ErtsTracer *tracer, const ErtsTracer new_tracer) } } -static void init_tracer_nif() +static void init_tracer_nif(void) { erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ; @@ -3084,7 +3092,7 @@ static void init_tracer_nif() } -int erts_tracer_nif_clear() +int erts_tracer_nif_clear(void) { erts_rwmtx_rlock(&tracer_mtx); diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index 1fcc0f1a1365..e67011e46b3d 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2020. All Rights Reserved. + * Copyright Ericsson AB 2012-2023. 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. @@ -34,7 +34,7 @@ /* * The bits used effects trace flags (of processes and ports) * as well as sequential trace flags. If changed make sure - * these arn't messed up... + * these aren't messed up... */ #define ERTS_TRACE_TS_TYPE_BITS 3 #define ERTS_TRACE_TS_TYPE_MASK \ @@ -172,6 +172,7 @@ struct trace_pattern_flags { unsigned int meta : 1; /* Metadata trace breakpoint */ unsigned int call_count : 1; /* Fast call count breakpoint */ unsigned int call_time : 1; /* Fast call time breakpoint */ + unsigned int call_memory: 1; /* Fast memory tracing breakpoint */ }; extern const struct trace_pattern_flags erts_trace_pattern_flags_off; extern int erts_call_time_breakpoint_tracing; diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 992ef9e3e457..945a22a63283 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2020. All Rights Reserved. + * Copyright Ericsson AB 2008-2021. 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. @@ -478,7 +478,7 @@ static Sint utf8_need(Eterm ioterm, int latin1, Uint *costp) } /* is_list(ioterm) */ if (!is_list(ioterm) && !is_nil(ioterm)) { - /* inproper list end */ + /* improper list end */ if (is_binary(ioterm)) { Sint x; if (latin1) { @@ -764,7 +764,7 @@ static Eterm do_build_utf8(Process *p, Eterm ioterm, Sint *left, int latin1, } /* is_list(ioterm) */ if ((*left) && !is_list(ioterm) && !is_nil(ioterm)) { - /* inproper list end */ + /* improper list end */ if (is_binary(ioterm)) { ioterm = do_build_utf8(p,ioterm,left,latin1,target,pos,characters,err,leftover,num_leftovers); if ((*err) != 0) { @@ -939,7 +939,7 @@ static int is_valid_utf8(Eterm orig_bin) Uint bitsize; Uint size; byte *temp_alloc = NULL; - byte *endpos; + const byte *endpos; Uint numchar; byte *bytes; int ret; @@ -1188,7 +1188,7 @@ BIF_RETTYPE unicode_characters_to_list_2(BIF_ALIST_2) * a faster analyze and size count with this function. */ static ERTS_INLINE int -analyze_utf8(byte *source, Uint size, byte **err_pos, Uint *num_chars, int *left, +analyze_utf8(const byte *source, Uint size, const byte **err_pos, Uint *num_chars, int *left, Sint *num_latin1_chars, Uint max_chars) { int res = ERTS_UTF8_OK; @@ -1288,29 +1288,29 @@ analyze_utf8(byte *source, Uint size, byte **err_pos, Uint *num_chars, int *left return res; } -int erts_analyze_utf8(byte *source, Uint size, - byte **err_pos, Uint *num_chars, int *left) +int erts_analyze_utf8(const byte *source, Uint size, + const byte **err_pos, Uint *num_chars, int *left) { return analyze_utf8(source, size, err_pos, num_chars, left, NULL, 0); } -int erts_analyze_utf8_x(byte *source, Uint size, - byte **err_pos, Uint *num_chars, int *left, +int erts_analyze_utf8_x(const byte *source, Uint size, + const byte **err_pos, Uint *num_chars, int *left, Sint *num_latin1_chars, Uint max_chars) { return analyze_utf8(source, size, err_pos, num_chars, left, num_latin1_chars, max_chars); } -static ERTS_INLINE Eterm -make_list_from_utf8_buf(Eterm **hpp, Uint num, - byte *bytes, Uint sz, - Uint *num_built, Uint *num_eaten, - Eterm tail) +Eterm +erts_make_list_from_utf8_buf(Eterm **hpp, Uint num, + const byte *bytes, Uint sz, + Uint *num_built, Uint *num_eaten, + Eterm tail) { Eterm *hp; Eterm ret; Uint left = num; - byte *source, *ssource; + const byte *source, *ssource; Uint unipoint; hp = *hpp; ret = tail; @@ -1369,9 +1369,9 @@ static Eterm do_utf8_to_list(Process *p, Uint num, byte *bytes, Uint sz, hp = HAlloc(p,num * 2); - return make_list_from_utf8_buf(&hp, num, bytes, sz, - num_built, num_eaten, - tail); + return erts_make_list_from_utf8_buf(&hp, num, bytes, sz, + num_built, num_eaten, + tail); } Eterm erts_utf8_to_list(Process *p, Uint num, byte *bytes, Uint sz, Uint left, Uint *num_built, Uint *num_eaten, Eterm tail) @@ -1389,7 +1389,7 @@ Uint erts_atom_to_string_length(Eterm atom) if (ap->latin1_chars >= 0) return (Uint) ap->len; else { - byte* err_pos; + const byte* err_pos; Uint num_chars; int ares = erts_analyze_utf8(ap->name, ap->len, &err_pos, &num_chars, NULL); @@ -1399,17 +1399,17 @@ Uint erts_atom_to_string_length(Eterm atom) } } -Eterm erts_atom_to_string(Eterm **hpp, Eterm atom) +Eterm erts_atom_to_string(Eterm **hpp, Eterm atom, Eterm tail) { Atom *ap; ASSERT(is_atom(atom)); ap = atom_tab(atom_val(atom)); if (ap->latin1_chars >= 0) - return buf_to_intlist(hpp, (char*)ap->name, ap->len, NIL); + return buf_to_intlist(hpp, (char*)ap->name, ap->len, tail); else { Eterm res; - byte* err_pos; + const byte* err_pos; Uint num_chars, num_built, num_eaten; #ifdef DEBUG Eterm *hp_start = *hpp; @@ -1418,8 +1418,8 @@ Eterm erts_atom_to_string(Eterm **hpp, Eterm atom) erts_analyze_utf8(ap->name, ap->len, &err_pos, &num_chars, NULL); ASSERT(ares == ERTS_UTF8_OK); - res = make_list_from_utf8_buf(hpp, num_chars, ap->name, ap->len, - &num_built, &num_eaten, NIL); + res = erts_make_list_from_utf8_buf(hpp, num_chars, ap->name, ap->len, + &num_built, &num_eaten, tail); ASSERT(num_built == num_chars); ASSERT(num_eaten == ap->len); @@ -1756,7 +1756,7 @@ static BIF_RETTYPE do_bif_utf8_to_list(Process *p, Eterm *hp; Eterm ret; byte *temp_alloc = NULL; - byte *endpos; + const byte *endpos; Uint numchar; Uint b_sz; /* size of the non analyzed tail */ @@ -2158,7 +2158,7 @@ char* erts_convert_filename_to_wchar(byte* bytes, Uint size, ErtsAlcType_t alloc_type, Sint* used, Uint extra_wchars) { - byte *err_pos; + const byte *err_pos; Uint num_chars; char* name_buf = NULL; Sint need; @@ -2200,7 +2200,7 @@ Eterm erts_convert_native_to_filename(Process *p, size_t size, byte *bytes) { Uint num_chars; Eterm *hp; - byte *err_pos; + const byte *err_pos; Uint num_built; /* characters */ Uint num_eaten; /* bytes */ Eterm ret; @@ -2379,7 +2379,7 @@ Sint erts_native_filename_need(Eterm ioterm, int encoding) if (x <= 0xffff) { need += 2; break; - } /* else fall throug to error */ + } /* else fall through to error */ default: DESTROY_ESTACK(stack); return ((Sint) -1); @@ -2420,7 +2420,7 @@ Sint erts_native_filename_need(Eterm ioterm, int encoding) } /* is_list(ioterm) */ if (!is_list(ioterm) && !is_nil(ioterm)) { - /* inproper list end */ + /* improper list end */ DESTROY_ESTACK(stack); return ((Sint) -1); } @@ -2678,7 +2678,7 @@ BIF_RETTYPE prim_file_internal_name2native_1(BIF_ALIST_1) if (is_binary(BIF_ARG_1)) { byte *temp_alloc = NULL; byte *bytes; - byte *err_pos; + const byte *err_pos; Uint size,num_chars; /* Uninterpreted encoding except if windows widechar, in case we convert from utf8 to win_wchar */ @@ -2763,7 +2763,7 @@ BIF_RETTYPE prim_file_internal_native2name_1(BIF_ALIST_1) Eterm *hp; byte *temp_alloc = NULL; byte *bytes; - byte *err_pos; + const byte *err_pos; Uint num_built; /* characters */ Uint num_eaten; /* bytes */ Eterm ret; @@ -2857,7 +2857,7 @@ BIF_RETTYPE prim_file_internal_normalize_utf8_1(BIF_ALIST_1) Eterm ret; byte *temp_alloc = NULL; byte *bytes; - byte *err_pos; + const byte *err_pos; if (is_not_binary(BIF_ARG_1)) { BIF_ERROR(BIF_P,BADARG); @@ -2890,7 +2890,7 @@ BIF_RETTYPE prim_file_is_translatable_1(BIF_ALIST_1) ERTS_DECLARE_DUMMY(Uint bitoffs); byte *temp_alloc = NULL; byte *bytes; - byte *err_pos; + const byte *err_pos; int status; if (is_not_binary(BIF_ARG_1)) { diff --git a/erts/emulator/beam/erl_unicode.h b/erts/emulator/beam/erl_unicode.h index 31369fc8f913..930fc1f600cf 100644 --- a/erts/emulator/beam/erl_unicode.h +++ b/erts/emulator/beam/erl_unicode.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2018. All Rights Reserved. + * Copyright Ericsson AB 2008-2021. 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. @@ -22,6 +22,6 @@ #define _ERL_UNICODE_H Uint erts_atom_to_string_length(Eterm atom); -Eterm erts_atom_to_string(Eterm **hpp, Eterm atom); +Eterm erts_atom_to_string(Eterm **hpp, Eterm atom, Eterm tail); #endif /* _ERL_UNICODE_H */ diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h index 5ca0992d96ff..dce3665a8d8e 100644 --- a/erts/emulator/beam/erl_utils.h +++ b/erts/emulator/beam/erl_utils.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012-2023. All Rights Reserved. + * Copyright Ericsson AB 2012-2022. 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. @@ -24,6 +24,7 @@ #include "sys.h" #include "atom.h" #include "erl_printf.h" +#include "erl_term_hashing.h" struct process; @@ -63,23 +64,11 @@ erts_current_interval_acqb(erts_interval_t *icp) */ void erts_silence_warn_unused_result(long unused); - int erts_fit_in_bits_int64(Sint64); int erts_fit_in_bits_int32(Sint32); int erts_fit_in_bits_uint(Uint); Sint erts_list_length(Eterm); int erts_is_builtin(Eterm, Eterm, int); -Uint32 make_hash2(Eterm); -Uint32 trapping_make_hash2(Eterm, Eterm*, struct process*); -#ifdef DEBUG -# define DBG_HASHMAP_COLLISION_BONANZA -#endif -#ifdef DBG_HASHMAP_COLLISION_BONANZA -Uint32 erts_dbg_hashmap_collision_bonanza(Uint32 hash, Eterm key); -#endif -Uint32 make_hash(Eterm); -Uint32 make_internal_hash(Eterm, Uint32 salt); -Uint32 make_map_hash(Eterm key); void erts_save_emu_args(int argc, char **argv); Eterm erts_get_emu_args(struct process *c_p); @@ -114,8 +103,8 @@ void erts_init_utils(void); void erts_init_utils_mem(void); void erts_utils_sched_spec_data_init(void); -erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint); void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *); +erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint) ERTS_ATTR_MALLOC_D(erts_destroy_tmp_dsbuf,1); int eq(Eterm, Eterm); @@ -123,6 +112,7 @@ int eq(Eterm, Eterm); ERTS_GLB_INLINE Sint erts_cmp(Eterm, Eterm, int, int); ERTS_GLB_INLINE int erts_cmp_atoms(Eterm a, Eterm b); +ERTS_GLB_INLINE Sint erts_cmp_flatmap_keys(Eterm, Eterm); Sint erts_cmp_compound(Eterm, Eterm, int, int); @@ -242,6 +232,17 @@ ERTS_GLB_INLINE Sint erts_cmp(Eterm a, Eterm b, int exact, int eq_only) { return erts_cmp_compound(a,b,exact,eq_only); } +/* + * Only to be used for the *internal* sort order of flatmap keys. + */ +ERTS_GLB_INLINE Sint erts_cmp_flatmap_keys(Eterm key_a, Eterm key_b) { + if (is_atom(key_a) && is_atom(key_b)) { + return key_a - key_b; + } + return erts_cmp(key_a, key_b, 1, 0); +} + + #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ #endif diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 50e3fdc9f242..faf6190e3924 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -27,9 +27,17 @@ */ /* #define FORCE_HEAP_FRAGS */ -/* valgrind can't handle stack switching, so we will turn off native stack. */ +/* `valgrind` can't handle stack switching, so we will turn off native + * stack. */ #ifdef VALGRIND #undef NATIVE_ERLANG_STACK +#undef ERLANG_FRAME_POINTERS +#endif + +/* Frame pointer support costs an extra word per process even when unused, so + * it's worth disabling for compact builds. */ +#ifdef CODE_MODEL_SMALL +#undef ERLANG_FRAME_POINTERS #endif #if defined(DEBUG) && !defined(CHECK_FOR_HOLES) && !defined(__WIN32__) @@ -40,9 +48,10 @@ #define EMULATOR "BEAM" #define SEQ_TRACE 1 -#define CONTEXT_REDS 4000 /* Swap process out after this number */ -#define MAX_ARG 255 /* Max number of arguments allowed */ -#define MAX_REG 1024 /* Max number of x(N) registers used */ +#define CONTEXT_REDS 4000 /* Swap process out after this number */ +#define MAX_ARG 255 /* Max number of arguments allowed */ +#define MAX_REG 1024 /* Max number of x(N) registers used */ +#define REG_MASK (MAX_REG - 1) /* * Guard BIFs and the new trapping length/1 implementation need 3 extra @@ -54,7 +63,23 @@ #define VH_DEFAULT_SIZE 32768 /* default virtual (bin) heap min size (words) */ #define H_DEFAULT_MAX_SIZE 0 /* default max heap size is off */ -#define CP_SIZE 1 +typedef enum { + /* Return address only */ + ERTS_FRAME_LAYOUT_RA, + /* Frame pointer, return address */ + ERTS_FRAME_LAYOUT_FP_RA +} ErtsFrameLayout; + +ERTS_GLB_INLINE +int erts_cp_size(void); + +#if defined(BEAMASM) && defined(ERLANG_FRAME_POINTERS) +extern ErtsFrameLayout ERTS_WRITE_UNLIKELY(erts_frame_layout); +# define CP_SIZE erts_cp_size() +#else +# define erts_frame_layout ERTS_FRAME_LAYOUT_RA +# define CP_SIZE 1 +#endif /* In the JIT we're not guaranteed to have allocated a word for the CP when * allocating a stack frame (it's still reserved however), as the `call` and @@ -76,6 +101,8 @@ #if defined(BEAMASM) && defined(NATIVE_ERLANG_STACK) #define S_REDZONE (CP_SIZE * 3) +#elif defined(BEAMASM) && defined(__aarch64__) +#define S_REDZONE (CP_SIZE * 3) #elif defined(DEBUG) /* Ensure that a redzone won't cause problems in the interpreter. */ #define S_REDZONE CP_SIZE @@ -227,14 +254,12 @@ extern Uint erts_instr_count[]; extern int H_MIN_SIZE; /* minimum (heap + stack) */ extern int BIN_VH_MIN_SIZE; /* minimum virtual (bin) heap */ -extern int H_MAX_SIZE; /* maximum (heap + stack) */ +extern Uint H_MAX_SIZE; /* maximum (heap + stack) */ extern int H_MAX_FLAGS; /* maximum heap flags */ extern int erts_atom_table_size;/* Atom table size */ extern int erts_pd_initial_size;/* Initial Process dictionary table size */ -#define ORIG_CREATION 0 - /* macros for extracting bytes from uint16's */ #define hi_byte(a) ((a) >> 8) @@ -273,8 +298,8 @@ extern void** beam_ops; #ifndef BEAMASM -#define BeamIsReturnTimeTrace(w) \ - BeamIsOpCode(*(const BeamInstr*)(w), op_i_return_time_trace) +#define BeamIsReturnCallAccTrace(w) \ + BeamIsOpCode(*(const BeamInstr*)(w), op_i_call_trace_return) #define BeamIsReturnToTrace(w) \ BeamIsOpCode(*(const BeamInstr*)(w), op_i_return_to_trace) #define BeamIsReturnTrace(w) \ @@ -282,8 +307,8 @@ extern void** beam_ops; #else /* BEAMASM */ -#define BeamIsReturnTimeTrace(w) \ - ((w) == beam_return_time_trace) +#define BeamIsReturnCallAccTrace(w) \ + ((w) == beam_call_trace_return) #define BeamIsReturnToTrace(w) \ ((w) == beam_return_to_trace) #define BeamIsReturnTrace(w) \ @@ -291,4 +316,22 @@ extern void** beam_ops; #endif /* BEAMASM */ +/* Stack frame sizes (not including CP_SIZE) */ +#define BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ 2 +#define BEAM_RETURN_TO_TRACE_FRAME_SZ 0 +#define BEAM_RETURN_TRACE_FRAME_SZ 2 + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE +int erts_cp_size(void) +{ + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + return 1; + } + + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + return 2; +} +#endif + #endif /* __ERL_VM_H__ */ diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d index 4f0b61fb616b..bc73432f1073 100644 --- a/erts/emulator/beam/erlang_dtrace.d +++ b/erts/emulator/beam/erlang_dtrace.d @@ -23,7 +23,7 @@ * A note on probe naming: if "__" appears in a provider probe * definition, then two things happen during compilation: * - * 1. The "__" will turn into a hypen, "-", for the probe name. + * 1. The "__" will turn into a hyphen, "-", for the probe name. * 2. The "__" will turn into a single underscore, "_", for the * macro names and function definitions that the compiler and * C developers will see. diff --git a/erts/emulator/beam/error.h b/erts/emulator/beam/error.h index 2067505edae1..e307f3ed6dbe 100644 --- a/erts/emulator/beam/error.h +++ b/erts/emulator/beam/error.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2022. 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. @@ -165,8 +165,10 @@ /* Bad map */ #define EXC_BADKEY ((19 << EXC_OFFSET) | EXC_ERROR) /* Bad key in map */ +#define EXC_BADRECORD ((20 << EXC_OFFSET) | EXC_ERROR) + /* Bad key in map */ -#define NUMBER_EXIT_CODES 20 /* The number of exit code indices */ +#define NUMBER_EXIT_CODES 21 /* The number of exit code indices */ /* * Internal pseudo-error codes. diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 8ed54ea1c276..af5df9ece712 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -123,15 +123,15 @@ export_alloc(struct export_entry* tmpl_e) blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); erts_atomic_add_nob(&total_entries_bytes, sizeof(*blob)); obj = &blob->exp; - obj->info.op = 0; - obj->info.u.gen_bp = NULL; + sys_memset(&obj->info.u, 0, sizeof(obj->info.u)); + obj->info.gen_bp = NULL; obj->info.mfa.module = tmpl->info.mfa.module; obj->info.mfa.function = tmpl->info.mfa.function; obj->info.mfa.arity = tmpl->info.mfa.arity; obj->bif_number = -1; obj->is_bif_traced = 0; - memset(&obj->trampoline, 0, sizeof(obj->trampoline)); + sys_memset(&obj->trampoline, 0, sizeof(obj->trampoline)); if (BeamOpsAreInitialized()) { obj->trampoline.common.op = BeamOpCodeAddr(op_call_error_handler); @@ -293,7 +293,7 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) res = ee->ep; #ifdef BEAMASM - res->addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls; + res->dispatch.addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls_export; #endif return res; @@ -336,7 +336,8 @@ erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) ep = entry->ep; #ifdef BEAMASM - ep->addresses[ERTS_SAVE_CALLS_CODE_IX] = beam_save_calls; + ep->dispatch.addresses[ERTS_SAVE_CALLS_CODE_IX] = + beam_save_calls_export; #endif ASSERT(ep); @@ -386,7 +387,7 @@ Export *export_get(Export *e) return entry ? entry->ep : NULL; } -IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) +IF_DEBUG(static ErtsCodeIndex debug_export_load_ix = 0;) void export_start_staging(void) @@ -395,36 +396,42 @@ void export_start_staging(void) ErtsCodeIndex src_ix = erts_active_code_ix(); IndexTable* dst = &export_tables[dst_ix]; IndexTable* src = &export_tables[src_ix]; - struct export_entry* src_entry; -#ifdef DEBUG - struct export_entry* dst_entry; -#endif int i; ASSERT(dst_ix != src_ix); - ASSERT(debug_start_load_ix == -1); + ASSERT(debug_export_load_ix == ~0); export_staging_lock(); /* * Insert all entries in src into dst table */ for (i = 0; i < src->entries; i++) { - src_entry = (struct export_entry*) erts_index_lookup(src, i); - src_entry->ep->addresses[dst_ix] = src_entry->ep->addresses[src_ix]; -#ifdef DEBUG - dst_entry = (struct export_entry*) + struct export_entry* src_entry; + ErtsDispatchable *disp; + + src_entry = (struct export_entry*) erts_index_lookup(src, i); + disp = &src_entry->ep->dispatch; + + disp->addresses[dst_ix] = disp->addresses[src_ix]; + +#ifndef DEBUG + index_put_entry(dst, src_entry); +#else /* DEBUG */ + { + struct export_entry* dst_entry = + (struct export_entry*)index_put_entry(dst, src_entry); + ASSERT(entry_to_blob(src_entry) == entry_to_blob(dst_entry)); + } #endif - index_put_entry(dst, src_entry); - ASSERT(entry_to_blob(src_entry) == entry_to_blob(dst_entry)); } export_staging_unlock(); - IF_DEBUG(debug_start_load_ix = dst_ix); + IF_DEBUG(debug_export_load_ix = dst_ix); } void export_end_staging(int commit) { - ASSERT(debug_start_load_ix == erts_staging_code_ix()); - IF_DEBUG(debug_start_load_ix = -1); + ASSERT(debug_export_load_ix == erts_staging_code_ix()); + IF_DEBUG(debug_export_load_ix = ~0); } diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index 699f67da95fb..93b2b7a67391 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -32,30 +32,25 @@ #ifdef BEAMASM #define OP_PAD BeamInstr __pad[1]; #define DISPATCH_SIZE 1 -#define ERTS_ADDRESSV_SIZE (ERTS_NUM_CODE_IX + 1) -#define ERTS_SAVE_CALLS_CODE_IX (ERTS_ADDRESSV_SIZE - 1) #else #define OP_PAD #define DISPATCH_SIZE 0 -#define ERTS_ADDRESSV_SIZE ERTS_NUM_CODE_IX #endif typedef struct export_ { - /* Pointer to code for function. - * - * !! THIS WAS DELIBERATELY RENAMED TO CAUSE ERRORS WHEN MERGING !! + /* !! WARNING !! * * The JIT has a special calling convention for export entries, assuming * the entry itself is in a certain register. Blindly setting `c_p->i` to - * one of these addresses will crash the emulator when the entry is traced, - * which is unlikely to be caught in our tests. + * one of the addresses in `dispatch` will crash the emulator when the + * entry is traced, which is unlikely to be caught in our tests. * * Use the `BIF_TRAP` macros if at all possible, and be _very_ careful when - * accessing these directly. + * accessing this field directly. * - * See `BeamAssembler::emit_setup_export_call` for details. */ - ErtsCodePtr addresses[ERTS_ADDRESSV_SIZE]; + * See `BeamAssembler::emit_setup_dispatchable_call` for details. */ + ErtsDispatchable dispatch; /* Index into bif_table[], or -1 if not a BIF. */ int bif_number; @@ -167,7 +162,7 @@ ERTS_GLB_INLINE void erts_activate_export_trampoline(Export *ep, int code_ix) { trampoline_address = (ErtsCodePtr)&ep->trampoline.raw[0]; #endif - ep->addresses[code_ix] = trampoline_address; + ep->dispatch.addresses[code_ix] = trampoline_address; } ERTS_GLB_INLINE int erts_is_export_trampoline_active(Export *ep, int code_ix) { @@ -180,7 +175,7 @@ ERTS_GLB_INLINE int erts_is_export_trampoline_active(Export *ep, int code_ix) { trampoline_address = (ErtsCodePtr)&ep->trampoline.raw[0]; #endif - return ep->addresses[code_ix] == trampoline_address; + return ep->dispatch.addresses[code_ix] == trampoline_address; } ERTS_GLB_INLINE Export* diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 697b9c0b8c13..36dad669d911 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -46,6 +46,9 @@ #include "erl_map.h" #include "erl_proc_sig_queue.h" #include "erl_trace.h" +#include "erl_global_literals.h" +#include "erl_term_hashing.h" + #define PASS_THROUGH 'p' @@ -65,19 +68,6 @@ #define ERTS_MAX_TINY_CREATION (3) #define is_tiny_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_TINY_CREATION) -/* - * When 0 is used as creation, the real creation - * is unknown. Creation 0 on data will be changed to current - * creation of the node which it belongs to when it enters - * that node. - * This typically happens when a remote pid is created with - * list_to_pid/1 and then sent to the remote node. This behavior - * has the undesirable effect that a pid can be passed between nodes, - * and as a result of that not being equal to itself (the pid that - * comes back isn't equal to the original pid). - * - */ - #undef ERTS_DEBUG_USE_DIST_SEP #ifdef DEBUG # if 0 @@ -107,8 +97,8 @@ static byte* enc_atom(ErtsAtomCacheMap *, Eterm, byte*, Uint64); static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint64); struct B2TContext_t; static const byte* dec_term(ErtsDistExternal*, ErtsHeapFactory*, const byte*, Eterm*, struct B2TContext_t*, int); -static const byte* dec_atom(ErtsDistExternal *, const byte*, Eterm*); -static const byte* dec_pid(ErtsDistExternal *, ErtsHeapFactory*, const byte*, Eterm*, byte tag); +static const byte* dec_atom(ErtsDistExternal *, const byte*, Eterm*, int); +static const byte* dec_pid(ErtsDistExternal *, ErtsHeapFactory*, const byte*, Eterm*, byte tag, int); static Sint decoded_size(const byte *ep, const byte* endp, int internal_tags, struct B2TContext_t*); static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1); @@ -116,19 +106,12 @@ static Eterm erts_term_to_binary_int(Process* p, Sint bif_ix, Eterm Term, Eterm Uint64 dflags, Binary *context_b, int iovec, Uint fragment_size); -static Uint encode_size_struct2(ErtsAtomCacheMap *, Eterm, Uint64); static ErtsExtSzRes encode_size_struct_int(TTBSizeContext*, ErtsAtomCacheMap *acmp, Eterm obj, Uint64 dflags, Sint *reds, Uint *res); static Export binary_to_term_trap_export; static BIF_RETTYPE binary_to_term_trap_1(BIF_ALIST_1); static Sint transcode_dist_obuf(ErtsDistOutputBuf*, DistEntry*, Uint64 dflags, Sint reds); -static byte *begin_hopefull_data(TTBEncodeContext *ctx, byte *ep); -static byte *end_hopefull_data(TTBEncodeContext *ctx, byte *ep, Uint fallback_size); -static byte *hopefull_bit_binary(TTBEncodeContext* ctx, byte **epp, Binary *pb_val, Eterm pb_term, - byte *bytes, byte bitoffs, byte bitsize, Uint sz); -static void hopefull_export(TTBEncodeContext* ctx, byte **epp, Export* exp, Uint32 dflags, - struct erl_off_heap_header** off_heap); static void store_in_vec(TTBEncodeContext *ctx, byte *ep, Binary *ohbin, Eterm ohpb, byte *ohp, Uint ohsz); static Uint32 calc_iovec_fun_size(SysIOVec* iov, Uint32 fun_high_ix, byte* size_p); @@ -144,6 +127,74 @@ void erts_init_external(void) { return; } +static Uint32 local_node_hash; + +void erts_late_init_external(void) +{ + char hname[256], pidstr[21]; + size_t hname_len, pidstr_len; + ErtsMonotonicTime mtime, toffs; + ErtsBlockHashState hstate; + byte *lnid; + Uint lnid_ix, chunk_size; + int res; + + res = sys_get_hostname(&hname[0], sizeof(hname)); + if (res == 0) { + hname_len = strlen(hname); + } + else { + hname[0] = '\0'; + hname_len = 0; + } + + sys_get_pid(&pidstr[0], sizeof(pidstr)); + pidstr[20] = '\0'; + + pidstr_len = strlen(pidstr); + + toffs = erts_get_time_offset(); + mtime = erts_get_monotonic_time(NULL); + + lnid = (byte *) erts_alloc(ERTS_ALC_T_TMP, 8 + hname_len + pidstr_len); + + lnid_ix = 0; + + /* time offset... */ + lnid[lnid_ix++] = (byte) toffs & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 8) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 16) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 24) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 32) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 40) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 48) & 0xff; + lnid[lnid_ix++] = (byte) (toffs >> 56) & 0xff; + + /* hostname... */ + + sys_memcpy(&lnid[lnid_ix], &hname[0], hname_len); + + lnid_ix += hname_len; + + /* pid... */ + memcpy(&lnid[lnid_ix], &pidstr[0], pidstr_len); + + lnid_ix += pidstr_len; + + /* + * Use least significant 32 bits of monotonic time as initial + * value to hash... + */ + erts_block_hash_init(&hstate, &lnid[0], lnid_ix, + (Uint32) (mtime & 0xffffffff)); + chunk_size = ERTS_UINT_MAX; + res = erts_block_hash(&local_node_hash, &chunk_size, &hstate); + ASSERT(res); (void) res; + ASSERT(chunk_size == lnid_ix); + + erts_free(ERTS_ALC_T_TMP, lnid); +} + #define ERTS_MAX_INTERNAL_ATOM_CACHE_ENTRIES 255 #define ERTS_DIST_HDR_ATOM_CACHE_FLAG_BYTE_IX(IIX) \ @@ -233,7 +284,6 @@ insert_acache_map(ErtsAtomCacheMap *acmp, Eterm atom, Uint64 dflags) if (acmp && acmp->sz < ERTS_MAX_INTERNAL_ATOM_CACHE_ENTRIES) { int ix; ASSERT(acmp->hdr_sz < 0); - ASSERT(dflags & DFLAG_UTF8_ATOMS); ix = atom2cix(atom); if (acmp->cache[ix].iix < 0) { acmp->cache[ix].iix = acmp->sz; @@ -271,7 +321,6 @@ erts_finalize_atom_cache_map(ErtsAtomCacheMap *acmp, Uint64 dflags) int i; int sz = 0; int min_sz; - ASSERT(dflags & DFLAG_UTF8_ATOMS); ASSERT(acmp->hdr_sz < 0); /* Make sure cache update instructions fit */ min_sz = (2+4)*acmp->sz; @@ -441,7 +490,6 @@ Sint erts_encode_ext_dist_header_finalize(ErtsDistOutputBuf* ob, int long_atoms; Uint64 seq_id = 0, frag_id = 0; register byte *ep = ob->eiov->iov[1].iov_base; - ASSERT(dflags & DFLAG_UTF8_ATOMS); /* * The buffer can have different layouts at this point depending on @@ -680,7 +728,7 @@ erts_encode_dist_ext_size(Eterm term, return res; } -ErtsExtSzRes erts_encode_ext_size_2(Eterm term, unsigned dflags, Uint *szp) +ErtsExtSzRes erts_encode_ext_size_2(Eterm term, Uint64 dflags, Uint *szp) { ErtsExtSzRes res; *szp = 0; @@ -696,8 +744,14 @@ ErtsExtSzRes erts_encode_ext_size(Eterm term, Uint *szp) Uint erts_encode_ext_size_ets(Eterm term) { - return encode_size_struct2(NULL, term, - TERM_TO_BINARY_DFLAGS|DFLAG_ETS_COMPRESSED); + ErtsExtSzRes res; + Uint sz = 0; + + res = encode_size_struct_int(NULL, NULL, term, + TERM_TO_BINARY_DFLAGS|DFLAG_ETS_COMPRESSED, + NULL, &sz); + ASSERT(res == ERTS_EXT_SZ_OK); (void) res; + return sz; } @@ -855,9 +909,6 @@ erts_prepare_dist_ext(ErtsDistExternal *edep, ASSERT(dep); erts_de_rlock(dep); - ASSERT(dep->dflags & DFLAG_UTF8_ATOMS); - - if ((dep->state != ERTS_DE_STATE_CONNECTED && dep->state != ERTS_DE_STATE_PENDING) || dep->connection_id != conn_id) { @@ -1363,7 +1414,7 @@ static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1) 0, 0,bin, 0, ~((Uint) 0)); if (is_non_value(res)) { if (erts_set_gc_state(BIF_P, 1) - || MSO(BIF_P).overhead > BIN_VHEAP_SZ(BIF_P)) { + || MSO(BIF_P).overhead > BIF_P->bin_vheap_sz) { ERTS_VBUMP_ALL_REDS(BIF_P); } if (Opts == am_undefined) @@ -1378,7 +1429,7 @@ static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1) BIF_TRAP1(&term_to_binary_trap_export,BIF_P,res); } else { if (erts_set_gc_state(BIF_P, 1) - || MSO(BIF_P).overhead > BIN_VHEAP_SZ(BIF_P)) + || MSO(BIF_P).overhead > BIF_P->bin_vheap_sz) ERTS_BIF_YIELD_RETURN(BIF_P, res); else BIF_RET(res); @@ -1424,12 +1475,12 @@ BIF_RETTYPE term_to_iovec_1(BIF_ALIST_1) } static ERTS_INLINE int -parse_t2b_opts(Eterm opts, Uint *flagsp, int *levelp, int *iovecp, Uint *fsizep) +parse_t2b_opts(Eterm opts, Uint64 *flagsp, int *levelp, int *iovecp, Uint *fsizep) { int level = 0; int iovec = 0; - Uint flags = TERM_TO_BINARY_DFLAGS; - int deterministic = 0; + Uint64 flags = TERM_TO_BINARY_DFLAGS; + int deterministic = 0, local = 0; Uint fsize = ~((Uint) 0); /* one fragment */ while (is_list(opts)) { @@ -1442,17 +1493,20 @@ parse_t2b_opts(Eterm opts, Uint *flagsp, int *levelp, int *iovecp, Uint *fsizep) iovec = !0; } else if (arg == am_deterministic) { deterministic = 1; + } else if (arg == am_local) { + local = !0; } else if (is_tuple(arg) && *(tp = tuple_val(arg)) == make_arityval(2)) { if (tp[1] == am_minor_version && is_small(tp[2])) { switch (signed_val(tp[2])) { case 0: - flags = TERM_TO_BINARY_DFLAGS & ~DFLAG_NEW_FLOATS; + flags = (TERM_TO_BINARY_DFLAGS + & ~(DFLAG_NEW_FLOATS | DFLAG_UTF8_ATOMS)); break; case 1: /* Current default... */ - flags = TERM_TO_BINARY_DFLAGS; + flags = TERM_TO_BINARY_DFLAGS & ~DFLAG_UTF8_ATOMS; break; case 2: - flags = TERM_TO_BINARY_DFLAGS | DFLAG_UTF8_ATOMS; + flags = TERM_TO_BINARY_DFLAGS; break; default: return 0; /* badarg */ @@ -1483,6 +1537,14 @@ parse_t2b_opts(Eterm opts, Uint *flagsp, int *levelp, int *iovecp, Uint *fsizep) return 0; /* badarg */ } + if (deterministic && local) { + return 0; /* badarg */ + } + + if (local) { + flags |= DFLAG_LOCAL_EXT; + } + if (deterministic) { flags |= DFLAG_DETERMINISTIC; } @@ -1500,7 +1562,7 @@ parse_t2b_opts(Eterm opts, Uint *flagsp, int *levelp, int *iovecp, Uint *fsizep) BIF_RETTYPE term_to_binary_2(BIF_ALIST_2) { int level; - Uint flags; + Uint64 flags; Eterm res; if (!parse_t2b_opts(BIF_ARG_2, &flags, &level, NULL, NULL)) { @@ -1527,7 +1589,7 @@ BIF_RETTYPE term_to_binary_2(BIF_ALIST_2) BIF_RETTYPE term_to_iovec_2(BIF_ALIST_2) { int level; - Uint flags; + Uint64 flags; Eterm res; if (!parse_t2b_opts(BIF_ARG_2, &flags, &level, NULL, NULL)) { @@ -1556,7 +1618,7 @@ erts_debug_term_to_binary(Process *p, Eterm term, Eterm opts) { Eterm ret; int level, iovec; - Uint flags; + Uint64 flags; Uint fsize; if (!parse_t2b_opts(opts, &flags, &level, &iovec, &fsize)) { @@ -1603,9 +1665,12 @@ enum B2TState { /* order is somewhat significant */ typedef struct { Sint heap_size; - int terms; - const byte* ep; + Uint32 terms; int atom_extra_skip; + const byte* ep; + ErtsBlockHashState lext_state; + const byte *lext_hash; + Uint32 lext_term_end; } B2TSizeContext; typedef struct { @@ -1614,6 +1679,7 @@ typedef struct { Eterm* next; ErtsHeapFactory factory; int remaining_n; + int internal_nc; char* remaining_bytes; ErtsPStack map_array; } B2TDecodeContext; @@ -1843,7 +1909,6 @@ static BIF_RETTYPE binary_to_term_trap_1(BIF_ALIST_1) return binary_to_term_int(BIF_P, THE_NON_VALUE, ERTS_MAGIC_BIN_DATA(context_bin)); } - #define B2T_BYTES_PER_REDUCTION 128 #define B2T_MEMCPY_FACTOR 8 @@ -1970,6 +2035,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Eterm bin, B2TContext *ctx) ctx->u.dc.ep = ctx->b2ts.extp; ctx->u.dc.res = (Eterm) (UWord) NULL; ctx->u.dc.next = &ctx->u.dc.res; + ctx->u.dc.internal_nc = 0; erts_factory_proc_prealloc_init(&ctx->u.dc.factory, p, ctx->heap_size); ctx->u.dc.map_array.pstart = NULL; ctx->state = B2TDecode; @@ -2141,34 +2207,11 @@ Eterm external_size_2(BIF_ALIST_2) { Uint size = 0; - Uint flags = TERM_TO_BINARY_DFLAGS; - - while (is_list(BIF_ARG_2)) { - Eterm arg = CAR(list_val(BIF_ARG_2)); - Eterm* tp; + int level; + Uint64 flags; - if (is_tuple(arg) && *(tp = tuple_val(arg)) == make_arityval(2)) { - if (tp[1] == am_minor_version && is_small(tp[2])) { - switch (signed_val(tp[2])) { - case 0: - flags &= ~DFLAG_NEW_FLOATS; - break; - case 1: - break; - default: - goto error; - } - } else { - goto error; - } - } else { - error: - BIF_ERROR(BIF_P, BADARG); - } - BIF_ARG_2 = CDR(list_val(BIF_ARG_2)); - } - if (is_not_nil(BIF_ARG_2)) { - goto error; + if (!parse_t2b_opts(BIF_ARG_2, &flags, &level, NULL, NULL)) { + BIF_ERROR(BIF_P, BADARG); } switch (erts_encode_ext_size_2(BIF_ARG_1, flags, &size)) { @@ -2840,45 +2883,80 @@ enc_atom(ErtsAtomCacheMap *acmp, Eterm atom, byte *ep, Uint64 dflags) } /* - * We use this atom as sysname in local pid/port/refs - * for the ETS compressed format + * We use INTERNAL_LOCAL_SYSNAME to mark internal node for pid/port/refs + * in the ETS compressed format and local format. * */ -#define INTERNAL_LOCAL_SYSNAME am_ErtsSecretAtom +#define INTERNAL_LOCAL_SYSNAME NIL -static byte* -enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint64 dflags) +static ERTS_INLINE byte * +enc_internal_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint64 dflags) { - Uint on, os; - Eterm sysname = ((is_internal_pid(pid) && (dflags & DFLAG_ETS_COMPRESSED)) - ? INTERNAL_LOCAL_SYSNAME : pid_node_name(pid)); - Uint32 creation = pid_creation(pid); + Uint32 number, serial, creation; - *ep++ = NEW_PID_EXT; + ASSERT(is_internal_pid(pid)); - ep = enc_atom(acmp, sysname, ep, dflags); + *ep++ = NEW_PID_EXT; - if (is_internal_pid(pid)) { - on = internal_pid_number(pid); - os = internal_pid_serial(pid); + number = internal_pid_number(pid); + serial = internal_pid_serial(pid); + if (dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) { + *ep++ = NIL_EXT; /* INTERNAL_LOCAL_NODE */ + creation = 0; } else { - on = external_pid_number(pid); - os = external_pid_serial(pid); + Eterm sysname = internal_pid_node_name(pid); + creation = internal_pid_creation(pid); + ep = enc_atom(acmp, sysname, ep, dflags); } - put_int32(on, ep); + put_int32(number, ep); + ep += 4; + put_int32(serial, ep); + ep += 4; + put_int32(creation, ep); + ep += 4; + return ep; + +} + +static ERTS_INLINE byte * +enc_external_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint64 dflags) +{ + Uint32 number, serial, creation; + Eterm sysname; + + ASSERT(is_external_pid(pid)); + + *ep++ = NEW_PID_EXT; + + ASSERT(is_external_pid(pid)); + number = external_pid_number(pid); + serial = external_pid_serial(pid); + sysname = external_pid_node_name(pid); + creation = external_pid_creation(pid); + ep = enc_atom(acmp, sysname, ep, dflags); + + put_int32(number, ep); ep += 4; - put_int32(os, ep); + put_int32(serial, ep); ep += 4; put_int32(creation, ep); ep += 4; return ep; } +static byte* +enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint64 dflags) +{ + if (is_internal_pid(pid)) + return enc_internal_pid(acmp, pid, ep, dflags); + return enc_external_pid(acmp, pid, ep, dflags); +} + /* Expect an atom in plain text or cached */ static const byte* -dec_atom(ErtsDistExternal *edep, const byte* ep, Eterm* objp) +dec_atom(ErtsDistExternal *edep, const byte* ep, Eterm* objp, int internal_nc) { Uint len; int n; @@ -2943,7 +3021,12 @@ dec_atom(ErtsDistExternal *edep, const byte* ep, Eterm* objp) } *objp = make_atom(n); break; - + case NIL_EXT: + if (internal_nc) { + *objp = INTERNAL_LOCAL_SYSNAME; + break; + } + /* else: fail... */ default: error: *objp = NIL; /* Don't leave a hole in the heap */ @@ -2956,9 +3039,8 @@ static ERTS_INLINE int dec_is_this_node(Eterm sysname, Uint32 creation) { return (sysname == INTERNAL_LOCAL_SYSNAME || - (sysname == erts_this_node->sysname - && (creation == erts_this_node->creation - || creation == ORIG_CREATION))); + (sysname == erts_this_node->sysname && + creation == erts_this_node->creation)); } @@ -2972,7 +3054,7 @@ static ERTS_INLINE ErlNode* dec_get_node(Eterm sysname, Uint32 creation, Eterm b static const byte* dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, const byte* ep, - Eterm* objp, byte tag) + Eterm* objp, byte tag, int internal_nc) { Eterm sysname; Uint data; @@ -2983,7 +3065,7 @@ dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, const byte* ep, *objp = NIL; /* In case we fail, don't leave a hole in the heap */ /* eat first atom */ - if ((ep = dec_atom(edep, ep, &sysname)) == NULL) + if ((ep = dec_atom(edep, ep, &sysname, internal_nc)) == NULL) return NULL; num = get_uint32(ep); ep += 4; @@ -3096,6 +3178,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, FloatDef f; register Sint r = 0; int use_iov = 0; + byte *lext_hash = NULL; /* initialize to avoid faulty warning... */ /* The following variables are only used during encoding of * a map when the `deterministic` option is active. */ @@ -3113,10 +3196,39 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, obj = ctx->obj; map_array = ctx->map_array; next_map_element = ctx->next_map_element; + lext_hash = ctx->lext_hash; if (is_non_value(obj)) { goto outer_loop; } + else { + goto L_jump_start; + } } + if (ctx->continue_make_lext_hash) { + lext_hash = ctx->lext_hash; + ep = ctx->ep; + if (use_iov) { + goto continue_make_lext_hash_iov; + } + else { + goto continue_make_lext_hash_bin; + } + } + } + + /* We only pass here once at the start of the encoding... */ + if (dflags & DFLAG_LOCAL_EXT) { + *ep++ = LOCAL_EXT; + lext_hash = ep; + if (ctx) + ctx->lext_hash = ep; + ep += 4; /* 32-bit hash */ + if (use_iov) { + ASSERT(ctx); + store_in_vec(ctx, ep, NULL, THE_NON_VALUE, NULL, 0); + /* current vlen is now where to start calculating the hash */ + ctx->lext_vlen = ctx->vlen; + } } goto L_jump_start; @@ -3159,33 +3271,6 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, ASSERT(ctx->vlen > 0); fun_sz = (ep - ctx->cptr) + calc_iovec_fun_size(ctx->iov, ctx->vlen-1, size_p); - - if (dflags & DFLAG_PENDING_CONNECT) { - /* - * Problem: The fun may contain hopefully encoded stuff - * in its environment. This makes the correct fun size - * may not be known until a final fallback transcoding - * has been done in transcode_dist_obuf(). - */ - ep = begin_hopefull_data(ctx, ep); - *ep++ = HOPEFUL_END_OF_FUN; - sys_memcpy(ep, &size_p, sizeof(size_p)); - ep += sizeof(size_p); - ep = end_hopefull_data(ctx, ep, 0); - ASSERT(ctx->iov[ctx->vlen - 1].iov_len - == 1 + sizeof(size_p)); - ASSERT(*(byte*)ctx->iov[ctx->vlen - 1].iov_base - == HOPEFUL_END_OF_FUN); - /* - * The HOPEFUL_END_OF_FUN iovec data entry encoded above - * contains no actual payload, only meta data to patch - * the correct fun size in transcode_dist_obuf(). - * Therefor reset its iov_len to zero to avoid output as - * payload. - */ - ctx->fragment_eiovs[ctx->frag_ix].size -= 1 + sizeof(size_p); - ctx->iov[ctx->vlen - 1].iov_len = 0; - } } else { /* No iovec encoding or still in same iovec buffer as start @@ -3262,7 +3347,6 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, long num_reductions = r; n = next_map_element - map_array; - ASSERT(n > MAP_SMALL_MAP_LIMIT); if (ctx == NULL) { /* No context means that the external representation of term * being encoded will fit in a heap binary (64 bytes). This @@ -3427,56 +3511,103 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, } break; - case PID_DEF: case EXTERNAL_PID_DEF: - ep = enc_pid(acmp, obj, ep, dflags); + ep = enc_external_pid(acmp, obj, ep, dflags); + break; + + case PID_DEF: + ep = enc_internal_pid(acmp, obj, ep, dflags); break; - case REF_DEF: case EXTERNAL_REF_DEF: { + Eterm sysname; Uint32 *ref_num; - Eterm sysname = (((dflags & DFLAG_ETS_COMPRESSED) && is_internal_ref(obj)) - ? INTERNAL_LOCAL_SYSNAME : ref_node_name(obj)); - Uint32 creation = ref_creation(obj); + Uint32 creation; + + *ep++ = NEWER_REFERENCE_EXT; + + ref_num = external_ref_numbers(obj); + i = external_ref_no_numbers(obj); + put_int16(i, ep); + ep += 2; - ASSERT(dflags & DFLAG_EXTENDED_REFERENCES); + sysname = external_ref_node_name(obj); + creation = external_ref_creation(obj); + goto ref_common; - erts_magic_ref_save_bin(obj); + case REF_DEF: + if ((dflags & DFLAG_ETS_COMPRESSED) && is_internal_magic_ref(obj)) { + ErtsMRefThing tmp; + ErtsMRefThing *mrtp = (ErtsMRefThing *) internal_ref_val(obj); + + erts_refc_inc(&mrtp->mb->intern.refc, 2); + + *ep++ = MAGIC_REF_INTERNAL_REF; + sys_memcpy(&tmp, mrtp, sizeof(ErtsMRefThing)); + tmp.next = *off_heap; + sys_memcpy(ep, &tmp, sizeof(ErtsMRefThing)); + *off_heap = (struct erl_off_heap_header*) ep; + ep += sizeof(ErtsMRefThing); + break; + } *ep++ = NEWER_REFERENCE_EXT; - i = ref_no_numbers(obj); - put_int16(i, ep); - ep += 2; - ep = enc_atom(acmp, sysname, ep, dflags); + + erts_magic_ref_save_bin(obj); + + ref_num = internal_ref_numbers(obj); + i = internal_ref_no_numbers(obj); + put_int16(i, ep); + ep += 2; + + if (dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) { + *ep++ = NIL_EXT; /* INTERNAL_LOCAL_NODE */ + creation = 0; + } + else { + sysname = internal_ref_node_name(obj); + creation = internal_ref_creation(obj); + ref_common: + ep = enc_atom(acmp, sysname, ep, dflags); + } + put_int32(creation, ep); ep += 4; - ref_num = ref_numbers(obj); for (j = 0; j < i; j++) { put_int32(ref_num[j], ep); ep += 4; } break; } - case PORT_DEF: case EXTERNAL_PORT_DEF: { - Eterm sysname = (((dflags & DFLAG_ETS_COMPRESSED) && is_internal_port(obj)) - ? INTERNAL_LOCAL_SYSNAME : port_node_name(obj)); - Uint32 creation = port_creation(obj); - byte *tagp = ep++; - Uint64 num; - - ep = enc_atom(acmp, sysname, ep, dflags); - num = port_number(obj); - if (num > ERTS_MAX_V3_PORT_NUMBER) { - *tagp = V4_PORT_EXT; - put_int64(num, ep); - ep += 8; - } - else { - *tagp = NEW_PORT_EXT; - put_int32(num, ep); - ep += 4; - } + Eterm sysname; + Uint64 number; + Uint32 creation; + + *ep++ = V4_PORT_EXT; + number = external_port_number(obj); + sysname = external_port_node_name(obj); + creation = external_port_creation(obj); + + goto port_common; + + case PORT_DEF: + + *ep++ = V4_PORT_EXT; + number = internal_port_number(obj); + if (dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) { + *ep++ = NIL_EXT; /* INTERNAL_LOCAL_NODE */ + creation = 0; + } + else { + sysname = internal_port_node_name(obj); + creation = internal_port_creation(obj); + port_common: + ep = enc_atom(acmp, sysname, ep, dflags); + } + + put_int64(number, ep); + ep += 8; put_int32(creation, ep); ep += 4; break; @@ -3535,9 +3666,20 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Eterm *kptr = flatmap_get_keys(mp); Eterm *vptr = flatmap_get_values(mp); - WSTACK_PUSH4(s, (UWord)kptr, (UWord)vptr, - ENC_MAP_PAIR, size); - } + if (dflags & DFLAG_DETERMINISTIC) { + ASSERT(map_array == NULL); + next_map_element = map_array = alloc_map_array(size); + while (size--) { + *next_map_element++ = *kptr++; + *next_map_element++ = *vptr++; + } + WSTACK_PUSH2(s, ENC_START_SORTING_MAP, THE_NON_VALUE); + } + else { + WSTACK_PUSH4(s, (UWord)kptr, (UWord)vptr, + ENC_MAP_PAIR, size); + } + } } else { Eterm hdr; Uint node_sz; @@ -3710,72 +3852,23 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, data_dst = ep; ep += j; } - } else if (dflags & DFLAG_BIT_BINARIES) { - /* Bit-level binary. */ - if (dflags & DFLAG_PENDING_CONNECT) { - ASSERT(ctx); - j = off_heap_bytesize; - if (!j) { - pb_val = NULL; - pb_term = THE_NON_VALUE; - j = binary_size(obj); - } - data_dst = hopefull_bit_binary(ctx, &ep, pb_val, pb_term, - bytes, bitoffs, bitsize, j); - if (!data_dst) - break; /* off heap binary referred... */ - ASSERT(!off_heap_bytesize); - off_heap_tail = 0; - /* - * Trailing bits already written by hopefull_bit_binary(); - * now go copy all whole octets... - */ - bitsize = 0; - } - else { - *ep++ = BIT_BINARY_EXT; - j = binary_size(obj); - put_int32((j+1), ep); - ep += 4; - *ep++ = bitsize; - if (off_heap_bytesize) { - /* trailing bits */ - ep[0] = 0; - copy_binary_to_buffer(ep, 0, bytes + j, 0, bitsize); - off_heap_tail = 1; - } - else { - ep[j] = 0; /* Zero unused bits at end of binary */ - data_dst = ep; - ep += j + 1; - } - } } else { - /* - * Bit-level binary, but the receiver doesn't support it. - * Build a tuple instead. - */ - *ep++ = SMALL_TUPLE_EXT; - *ep++ = 2; - *ep++ = BINARY_EXT; - j = binary_size(obj); - put_int32((j+1), ep); - ep += 4; - + /* Bit-level binary. */ + *ep++ = BIT_BINARY_EXT; + j = binary_size(obj); + put_int32((j+1), ep); + ep += 4; + *ep++ = bitsize; if (off_heap_bytesize) { /* trailing bits */ ep[0] = 0; copy_binary_to_buffer(ep, 0, bytes + j, 0, bitsize); - ep[1] = SMALL_INTEGER_EXT; - ep[2] = bitsize; - off_heap_tail = 3; + off_heap_tail = 1; } else { - ep[j] = 0; /* Zero unused bits at end of binary */ + ep[j] = 0; /* Zero unused bits at end of binary */ data_dst = ep; - ep += j+1; - *ep++ = SMALL_INTEGER_EXT; - *ep++ = bitsize; + ep += j + 1; } } if (off_heap_bytesize) { @@ -3793,64 +3886,49 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, } } break; - case EXPORT_DEF: - { - Export* exp = *((Export **) (export_val(obj) + 1)); - if (dflags & DFLAG_PENDING_CONNECT) { - ASSERT(ctx); - hopefull_export(ctx, &ep, exp, dflags, off_heap); - } - else if ((dflags & DFLAG_EXPORT_PTR_TAG) != 0) { - *ep++ = EXPORT_EXT; - ep = enc_atom(acmp, exp->info.mfa.module, ep, dflags); - ep = enc_atom(acmp, exp->info.mfa.function, ep, dflags); - ep = enc_term(acmp, make_small(exp->info.mfa.arity), - ep, dflags, off_heap); - } else { - /* Tag, arity */ - *ep++ = SMALL_TUPLE_EXT; - put_int8(2, ep); - ep += 1; + case FUN_DEF: + { + ErlFunThing* funp = (ErlFunThing *) fun_val(obj); - /* Module name */ - ep = enc_atom(acmp, exp->info.mfa.module, ep, dflags); + if (is_local_fun(funp)) { + ErlFunEntry* fe = funp->entry.fun; + int ei; - /* Function name */ - ep = enc_atom(acmp, exp->info.mfa.function, ep, dflags); - } - break; - } - break; - case FUN_DEF: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(obj); - int ei; - - ASSERT(dflags & DFLAG_NEW_FUN_TAGS); - - *ep++ = NEW_FUN_EXT; - WSTACK_PUSH2(s, ENC_PATCH_FUN_SIZE, - (UWord) ep); /* Position for patching in size */ - ep += 4; - *ep = funp->arity; - ep += 1; - sys_memcpy(ep, funp->fe->uniq, 16); - ep += 16; - put_int32(funp->fe->index, ep); - ep += 4; - put_int32(funp->num_free, ep); - ep += 4; - ep = enc_atom(acmp, funp->fe->module, ep, dflags); - ep = enc_term(acmp, make_small(funp->fe->old_index), ep, dflags, off_heap); - ep = enc_term(acmp, make_small(funp->fe->old_uniq), ep, dflags, off_heap); - ep = enc_pid(acmp, funp->creator, ep, dflags); - - for (ei = funp->num_free-1; ei >= 0; ei--) { - WSTACK_PUSH2(s, ENC_TERM, (UWord) funp->env[ei]); - } - } - break; - } + *ep++ = NEW_FUN_EXT; + WSTACK_PUSH2(s, ENC_PATCH_FUN_SIZE, + (UWord) ep); /* Position for patching in size */ + ep += 4; + *ep = funp->arity; + ep += 1; + sys_memcpy(ep, fe->uniq, 16); + ep += 16; + put_int32(fe->index, ep); + ep += 4; + put_int32((Uint32)funp->num_free, ep); + ep += 4; + ep = enc_atom(acmp, fe->module, ep, dflags); + ep = enc_term(acmp, make_small(fe->old_index), ep, dflags, off_heap); + ep = enc_term(acmp, make_small(fe->old_uniq), ep, dflags, off_heap); + ep = enc_pid(acmp, funp->creator, ep, dflags); + + for (ei = funp->num_free-1; ei >= 0; ei--) { + WSTACK_PUSH2(s, ENC_TERM, (UWord) funp->env[ei]); + } + } else { + Export *exp = funp->entry.exp; + + ASSERT(is_external_fun(funp) && funp->next == NULL); + + *ep++ = EXPORT_EXT; + ep = enc_atom(acmp, exp->info.mfa.module, ep, dflags); + ep = enc_atom(acmp, exp->info.mfa.function, ep, dflags); + ep = enc_term(acmp, make_small(exp->info.mfa.arity), + ep, dflags, off_heap); + + } + } + break; + } } DESTROY_WSTACK(s); if (ctx) { @@ -3859,6 +3937,68 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, if (use_iov) store_in_vec(ctx, ep, NULL, THE_NON_VALUE, NULL, 0); } + if (dflags & DFLAG_LOCAL_EXT) { + int done; + Uint32 hash; + Uint chunk_len; + + if (use_iov) { + ASSERT(ctx); + erts_iov_block_hash_init(&ctx->lext_state.iov_block, + &ctx->iov[ctx->lext_vlen], + ctx->vlen - ctx->lext_vlen, + local_node_hash); + + continue_make_lext_hash_iov: + /* Do 128 bytes per reduction... */ + chunk_len = (Uint) r*128; + + done = erts_iov_block_hash(&hash, &chunk_len, + &ctx->lext_state.iov_block); + } + else { + ErtsBlockHashState lext_state_buf, *lext_state; + byte *ep_start = lext_hash + 4 /* 32 bit hash value */; + Sint len = ep - ep_start; + + ASSERT(len >= 0); + + lext_state = ctx ? &ctx->lext_state.block : &lext_state_buf; + + erts_block_hash_init(lext_state, ep_start, len, local_node_hash); + + if (!ctx) { + /* Do it all at once... */ + chunk_len = ERTS_UINT_MAX; + } + else { + continue_make_lext_hash_bin: + lext_state = &ctx->lext_state.block; + /* Do 128 bytes per reduction... */ + chunk_len = (Uint) r*128; + } + + done = erts_block_hash(&hash, &chunk_len, lext_state); + } + + if (!ctx) { + ASSERT(done); + } + else { + if (!done) { + /* yield; more work calculating hash... */ + ctx->ep = ep; + ctx->continue_make_lext_hash = !0; + *reds = 0; + return -1; + } + r -= chunk_len/128; + *reds = r; + } + + put_int32(hash, lext_hash); + } + *res = ep; return 0; } @@ -3988,123 +4128,6 @@ store_in_vec(TTBEncodeContext *ctx, } } -static byte * -begin_hopefull_data(TTBEncodeContext *ctx, byte *ep) -{ - store_in_vec(ctx, ep, NULL, THE_NON_VALUE, NULL, 0); - ASSERT(ERTS_NO_HIX == get_uint32(ctx->hopefull_ixp)); - put_int32(ctx->vlen, ctx->hopefull_ixp); - ctx->hopefull_ixp = ep; - put_int32(ERTS_NO_HIX, ep); - ep += 4; - ctx->cptr = ep; - return ep; -} - -static byte * -end_hopefull_data(TTBEncodeContext *ctx, byte *ep, Uint fallback_size) -{ - Uint sz; - store_in_vec(ctx, ep, NULL, THE_NON_VALUE, NULL, 0); - /* - * Reserve extra room for fallback if needed. The four - * bytes used for hopefull index can be used for - * fallback encoding... - */ - sz = ep - ctx->hopefull_ixp; - if (fallback_size > sz) { - ep += fallback_size - sz; - ctx->cptr = ep; - } - return ep; -} - -static byte * -hopefull_bit_binary(TTBEncodeContext* ctx, byte **epp, Binary *pb_val, Eterm pb_term, - byte *bytes, byte bitoffs, byte bitsize, Uint sz) -{ - byte *octets, *ep = *epp; - - ctx->hopefull_flags |= DFLAG_BIT_BINARIES; - - /* - * The fallback: - * - * SMALL_TUPLE_EXT - 1 byte - * 2 - 1 byte - * BINARY_EXT - 1 byte - * whole octet size ('sz') - 4 byte - * whole octets - 'sz' bytes - * trailing bits - 1 byte - * SMALL_INTEGER_EXT - 1 byte - * bitsize - 1 byte - */ - - /* bit binary prelude in one hopefull data element */ - ep = begin_hopefull_data(ctx, ep); - *ep++ = BIT_BINARY_EXT; - put_int32((sz+1), ep); - ep += 4; - *ep++ = bitsize; - ep = end_hopefull_data(ctx, ep, 1+1+1+4); - - /* All whole octets... */ - if (pb_val) { - octets = NULL; - store_in_vec(ctx, ep, pb_val, pb_term, bytes, sz); - } - else { - /* ... will be copied here afterwards */ - octets = ep; - ep += sz; - } - - /* copy trailing bits into new hopefull data element */ - ep = begin_hopefull_data(ctx, ep); - *ep = 0; /* Clear the bit in the byte */ - - copy_binary_to_buffer(ep, 0, bytes + sz, bitoffs, bitsize); - ep++; - - ep = end_hopefull_data(ctx, ep, 1+1+1); - *epp = ep; - - return octets; -} - -static void -hopefull_export(TTBEncodeContext* ctx, byte **epp, Export* exp, Uint32 dflags, - struct erl_off_heap_header** off_heap) -{ - Uint fallback_sz; - byte *ep = *epp, *mod_start; - - /* - * The fallback: - * - * SMALL_TUPLE_EXT - 1 byte - * 2 - 1 byte - * module atom... - M bytes - * function atom... - F bytes - */ - - ctx->hopefull_flags |= DFLAG_EXPORT_PTR_TAG; - - ep = begin_hopefull_data(ctx, ep); - - *ep++ = EXPORT_EXT; - mod_start = ep; - ep = enc_atom(NULL, exp->info.mfa.module, ep, dflags); - ep = enc_atom(NULL, exp->info.mfa.function, ep, dflags); - fallback_sz = 2 + (ep - mod_start); - ep = enc_term(NULL, make_small(exp->info.mfa.arity), - ep, dflags, off_heap); - - ep = end_hopefull_data(ctx, ep, fallback_sz); - - *epp = ep; -} - /** @brief Is it a list of bytes not longer than MAX_STRING_LEN? * @param lenp out: string length or number of list cells traversed * @return true/false @@ -4159,7 +4182,7 @@ dec_term(ErtsDistExternal *edep, { #define PSTACK_TYPE struct dec_term_map PSTACK_DECLARE(map_array, 10); - int n; + int n, internal_nc = ets_decode; ErtsAtomEncoding char_enc; register Eterm* hp; /* Please don't take the address of hp */ Eterm* next; @@ -4173,6 +4196,7 @@ dec_term(ErtsDistExternal *edep, next = ctx->u.dc.next; ep = ctx->u.dc.ep; factory = &ctx->u.dc.factory; + internal_nc = ctx->u.dc.internal_nc; if (ctx->state != B2TDecode) { int n_limit = reds; @@ -4264,6 +4288,8 @@ dec_term(ErtsDistExternal *edep, objp = next; next = (Eterm *) *objp; + continue_this_obj: + switch (*ep++) { case INTEGER_EXT: { @@ -4374,10 +4400,18 @@ dec_term(ErtsDistExternal *edep, case LARGE_TUPLE_EXT: n = get_int32(ep); ep += 4; + if (n == 0) { + *objp = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + break; + } goto tuple_loop; case SMALL_TUPLE_EXT: n = get_int8(ep); ep++; + if (n == 0) { + *objp = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + break; + } tuple_loop: *objp = make_tuple(hp); *hp++ = make_arityval(n); @@ -4499,7 +4533,7 @@ dec_term(ErtsDistExternal *edep, case PID_EXT: case NEW_PID_EXT: factory->hp = hp; - ep = dec_pid(edep, factory, ep, objp, ep[-1]); + ep = dec_pid(edep, factory, ep, objp, ep[-1], internal_nc); hp = factory->hp; if (ep == NULL) { goto error; @@ -4515,7 +4549,7 @@ dec_term(ErtsDistExternal *edep, Uint32 cre; byte tag = ep[-1]; - if ((ep = dec_atom(edep, ep, &sysname)) == NULL) { + if ((ep = dec_atom(edep, ep, &sysname, internal_nc)) == NULL) { goto error; } if (tag == V4_PORT_EXT) { @@ -4575,7 +4609,7 @@ dec_term(ErtsDistExternal *edep, ref_words = 1; - if ((ep = dec_atom(edep, ep, &sysname)) == NULL) + if ((ep = dec_atom(edep, ep, &sysname, internal_nc)) == NULL) goto error; if ((r0 = get_int32(ep)) >= MAX_REFERENCE ) goto error; @@ -4592,7 +4626,7 @@ dec_term(ErtsDistExternal *edep, ref_words = get_int16(ep); ep += 2; - if ((ep = dec_atom(edep, ep, &sysname)) == NULL) + if ((ep = dec_atom(edep, ep, &sysname, internal_nc)) == NULL) goto error; cre = get_int8(ep); @@ -4610,7 +4644,7 @@ dec_term(ErtsDistExternal *edep, ref_words = get_int16(ep); ep += 2; - if ((ep = dec_atom(edep, ep, &sysname)) == NULL) + if ((ep = dec_atom(edep, ep, &sysname, internal_nc)) == NULL) goto error; cre = get_int32(ep); @@ -4643,7 +4677,7 @@ dec_term(ErtsDistExternal *edep, } if (ref_words != ERTS_REF_NUMBERS) { int i; - if (ref_words > ERTS_REF_NUMBERS) + if (ref_words > ERTS_MAX_REF_NUMBERS) goto error; /* Not a ref that we created... */ for (i = ref_words; i < ERTS_REF_NUMBERS; i++) ref_num[i] = 0; @@ -4655,12 +4689,15 @@ dec_term(ErtsDistExternal *edep, } else { /* Check if it is a pid reference... */ - Eterm pid = erts_pid_ref_lookup(ref_num); + Eterm pid = erts_pid_ref_lookup(ref_num, ref_words); if (is_internal_pid(pid)) { write_pid_ref_thing(hp, ref_num[0], ref_num[1], ref_num[2], pid); hp += ERTS_PID_REF_THING_SIZE; } + else if (is_non_value(pid)) { + goto error; /* invalid reference... */ + } else { /* Check if it is a magic reference... */ ErtsMagicBinary *mb = erts_magic_ref_lookup_bin(ref_num); @@ -4714,7 +4751,7 @@ dec_term(ErtsDistExternal *edep, } case BINARY_EXT: { - Uint32 nu = get_uint32(ep); + Uint nu = get_uint32(ep); ep += 4; ASSERT(IS_BINARY_SIZE_OK(nu)); @@ -4780,7 +4817,7 @@ dec_term(ErtsDistExternal *edep, Eterm bin; ErlSubBin* sb; Uint bitsize; - Uint32 nu = get_uint32(ep); + Uint nu = get_uint32(ep); ASSERT(IS_BINARY_SIZE_OK(nu)); @@ -4836,42 +4873,45 @@ dec_term(ErtsDistExternal *edep, } break; } - case EXPORT_EXT: - { - Eterm mod; - Eterm name; - Eterm temp; - Sint arity; - - if ((ep = dec_atom(edep, ep, &mod)) == NULL) { - goto error; - } - if ((ep = dec_atom(edep, ep, &name)) == NULL) { - goto error; - } - factory->hp = hp; - ep = dec_term(edep, factory, ep, &temp, NULL, 0); - hp = factory->hp; - if (ep == NULL) { - goto error; - } - if (!is_small(temp)) { - goto error; - } - arity = signed_val(temp); - if (arity < 0) { - goto error; - } - if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { - if (!erts_active_export_entry(mod, name, arity)) - goto error; + case EXPORT_EXT: + { + ErlFunThing *funp; + Export *export; + Eterm mod; + Eterm name; + Eterm temp; + Sint arity; + + if ((ep = dec_atom(edep, ep, &mod, 0)) == NULL) { + goto error; } - *objp = make_export(hp); - *hp++ = HEADER_EXPORT; - *hp++ = (Eterm) erts_export_get_or_make_stub(mod, name, arity); - break; - } - break; + if ((ep = dec_atom(edep, ep, &name, 0)) == NULL) { + goto error; + } + factory->hp = hp; + ep = dec_term(edep, factory, ep, &temp, NULL, 0); + if (ep == NULL) { + goto error; + } + if (!is_small(temp)) { + goto error; + } + arity = signed_val(temp); + if (arity < 0) { + goto error; + } + if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { + if (!erts_active_export_entry(mod, name, arity)) { + goto error; + } + } + + export = erts_export_get_or_make_stub(mod, name, arity); + funp = erts_new_export_fun_thing(&factory->hp, export, arity); + hp = factory->hp; + *objp = make_fun(funp); + } + break; case MAP_EXT: { Uint32 size,n; @@ -4883,10 +4923,13 @@ dec_term(ErtsDistExternal *edep, if (size <= MAP_SMALL_MAP_LIMIT) { flatmap_t *mp; - - keys = make_tuple(hp); - *hp++ = make_arityval(size); - hp += size; + if (size == 0) { + keys = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } else { + keys = make_tuple(hp); + *hp++ = make_arityval(size); + hp += size; + } kptr = hp - 1; mp = (flatmap_t*)hp; @@ -4957,7 +5000,7 @@ dec_term(ErtsDistExternal *edep, *objp = make_fun(funp); /* Module */ - if ((ep = dec_atom(edep, ep, &module)) == NULL) { + if ((ep = dec_atom(edep, ep, &module, 0)) == NULL) { goto error; } factory->hp = hp; @@ -4986,8 +5029,9 @@ dec_term(ErtsDistExternal *edep, funp->next = factory->off_heap->first; factory->off_heap->first = (struct erl_off_heap_header*)funp; - funp->fe = erts_put_fun_entry2(module, old_uniq, old_index, - uniq, index, arity); + funp->entry.fun = erts_put_fun_entry2(module, old_uniq, + old_index, uniq, + index, arity); funp->arity = arity; hp = factory->hp; @@ -5068,6 +5112,26 @@ dec_term(ErtsDistExternal *edep, *objp = make_binary(sub); break; } + case MAGIC_REF_INTERNAL_REF: + { + ErtsMRefThing* mrtp = (ErtsMRefThing*) hp; + sys_memcpy(mrtp, ep, sizeof(ErtsMRefThing)); + ep += sizeof(ErtsMRefThing); + erts_refc_inc(&mrtp->mb->intern.refc, 2); + hp += ERTS_MAGIC_REF_THING_SIZE; + mrtp->next = factory->off_heap->first; + factory->off_heap->first = (struct erl_off_heap_header*)mrtp; + *objp = make_internal_ref(mrtp); + ASSERT(is_internal_magic_ref(*objp)); + break; + } + + case LOCAL_EXT: + internal_nc = !0; + if (ctx) + ctx->u.dc.internal_nc = !0; + ep += 4; /* 32-bit hash (verified in decoded_size()) */ + goto continue_this_obj; default: goto error; @@ -5134,7 +5198,7 @@ dec_term(ErtsDistExternal *edep, } while (!PSTACK_IS_EMPTY(map_array)); } - /* Now that no more errors can occur, the stacks can be destroyed safely. */ + /* Now that no more errors can occur, the stack can be destroyed safely. */ PSTACK_DESTROY(map_array); ASSERT((Eterm*)*dbg_resultp != NULL); @@ -5169,23 +5233,88 @@ dec_term(ErtsDistExternal *edep, return NULL; } -/* returns the number of bytes needed to encode an object - to a sequence of bytes - N.B. That this must agree with to_external2() above!!! - (except for cached atoms) */ -static Uint encode_size_struct2(ErtsAtomCacheMap *acmp, - Eterm obj, - Uint64 dflags) { - Uint size = 0; - ErtsExtSzRes res = encode_size_struct_int(NULL, acmp, obj, - dflags, NULL, - &size); - /* - * encode_size_struct2() only allowed when - * we know the result will always be OK! - */ - ASSERT(res == ERTS_EXT_SZ_OK); (void) res; - return (Uint) size; +static Uint +encode_atom_size(ErtsAtomCacheMap *acmp, Eterm atom, Uint64 dflags) +{ + ASSERT(is_atom(atom)); + if (dflags & DFLAG_ETS_COMPRESSED) { + if (atom_val(atom) >= (1<<16)) { + return (Uint) 1 + 3; + } + else { + return (Uint) 1 + 2; + } + } + else { + Atom *a = atom_tab(atom_val(atom)); + int alen; + Uint result; + if ((dflags & DFLAG_UTF8_ATOMS) || a->latin1_chars < 0) { + alen = a->len; + result = (Uint) 1 + 1 + alen; + if (alen > 255) { + result++; /* ATOM_UTF8_EXT (not small) */ + } + } + else { + alen = a->latin1_chars; + result = (Uint) 1 + 1 + alen; + if (alen > 255 || !(dflags & DFLAG_SMALL_ATOM_TAGS)) + result++; /* ATOM_EXT (not small) */ + } + insert_acache_map(acmp, atom, dflags); + return result; + } +} + +static Uint +encode_internal_pid_size(ErtsAtomCacheMap *acmp, Eterm pid, Uint64 dflags) +{ + int nlen; + ASSERT(is_internal_pid(pid)); + nlen = ((dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) + ? 1 + : encode_atom_size(acmp, internal_pid_node_name(pid), dflags)); + return (Uint) 1 + nlen + 4 + 4 + 4; +} + +static Uint +encode_external_pid_size(ErtsAtomCacheMap *acmp, Eterm pid, Uint64 dflags) +{ + int nlen; + ASSERT(is_external_pid(pid)); + nlen = encode_atom_size(acmp, external_pid_node_name(pid), dflags); + return (Uint) 1 + nlen + 4 + 4 + 4; +} + +static Uint +encode_pid_size(ErtsAtomCacheMap *acmp, Eterm pid, Uint64 dflags) +{ + if (is_internal_pid(pid)) + return encode_internal_pid_size(acmp, pid, dflags); + ASSERT(is_external_pid(pid)); + return encode_external_pid_size(acmp, pid, dflags); +} + +static Uint +encode_small_size(ErtsAtomCacheMap *acmp, Eterm pid, Uint64 dflags) +{ + Sint val = signed_val(pid); + Uint result; + + if ((Uint)val < 256) + result = (Uint) 1 + 1; /* SMALL_INTEGER_EXT */ + else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) + result = (Uint) 1 + 4; /* INTEGER_EXT */ + else { + int i; + DeclareTmpHeapNoproc(tmp_big,2); + UseTmpHeapNoproc(2); + i = big_bytes(small_to_big(val, tmp_big)); + result = (Uint) 1 + 1 + 1 + i; /* SMALL_BIG_EXT */ + UnUseTmpHeapNoproc(2); + } + return result; } static ErtsExtSzRes @@ -5198,14 +5327,24 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, Sint r = 0; int vlen = -1; - if (ctx) { + if (!ctx) { + if (dflags & DFLAG_LOCAL_EXT) + result += 5; + } + else { WSTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK); r = *reds; vlen = ctx->vlen; - if (!ctx->wstack.wstart) + if (!ctx->wstack.wstart) { ctx->last_result = result; + if (dflags & DFLAG_LOCAL_EXT) { + result += 5; + if (vlen >= 0) + vlen++; + } + } else { /* restore saved stack */ WSTACK_RESTORE(s, &ctx->wstack); result = ctx->result; @@ -5214,8 +5353,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, } #define LIST_TAIL_OP ((0 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) -#define PATCH_FUN_SIZE_OP ((1 << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) -#define TERM_ARRAY_OP(N) (((N+1) << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) +#define TERM_ARRAY_OP(N) (((N) << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) #define TERM_ARRAY_OP_DEC(OP) ((OP) - (1 << _TAG_PRIMARY_SIZE)) @@ -5235,49 +5373,10 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, result++; break; case ATOM_DEF: - if (dflags & DFLAG_ETS_COMPRESSED) { - if (atom_val(obj) >= (1<<16)) { - result += 1 + 3; - } - else { - result += 1 + 2; - } - } - else { - Atom *a = atom_tab(atom_val(obj)); - int alen; - if ((dflags & DFLAG_UTF8_ATOMS) || a->latin1_chars < 0) { - alen = a->len; - result += 1 + 1 + alen; - if (alen > 255) { - result++; /* ATOM_UTF8_EXT (not small) */ - } - } - else { - alen = a->latin1_chars; - result += 1 + 1 + alen; - if (alen > 255 || !(dflags & DFLAG_SMALL_ATOM_TAGS)) - result++; /* ATOM_EXT (not small) */ - } - insert_acache_map(acmp, obj, dflags); - } + result += encode_atom_size(acmp, obj, dflags); break; case SMALL_DEF: - { - Sint val = signed_val(obj); - - if ((Uint)val < 256) - result += 1 + 1; /* SMALL_INTEGER_EXT */ - else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) - result += 1 + 4; /* INTEGER_EXT */ - else { - DeclareTmpHeapNoproc(tmp_big,2); - UseTmpHeapNoproc(2); - i = big_bytes(small_to_big(val, tmp_big)); - result += 1 + 1 + 1 + i; /* SMALL_BIG_EXT */ - UnUseTmpHeapNoproc(2); - } - } + result += encode_small_size(acmp, obj, dflags); break; case BIG_DEF: i = big_bytes(obj); @@ -5289,23 +5388,51 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, result += 1 + 4 + 1 + i; /* tag,size,sign,digits */ break; case EXTERNAL_PID_DEF: + result += encode_external_pid_size(acmp, obj, dflags); + break; case PID_DEF: - result += (1 + encode_size_struct2(acmp, pid_node_name(obj), dflags) + - 4 + 4 + 4); + result += encode_internal_pid_size(acmp, obj, dflags); + break; + case EXTERNAL_REF_DEF: { + int nlen = encode_atom_size(acmp, + external_ref_node_name(obj), + dflags); + i = external_ref_no_numbers(obj); + result += (1 + 2 + nlen + 4 + 4*i); break; - case EXTERNAL_REF_DEF: + } case REF_DEF: - ASSERT(dflags & DFLAG_EXTENDED_REFERENCES); - i = ref_no_numbers(obj); - result += (1 + 2 + encode_size_struct2(acmp, ref_node_name(obj), dflags) + - 4 + 4*i); + if ((dflags & DFLAG_ETS_COMPRESSED) && is_internal_magic_ref(obj)) { + result += 1 + sizeof(ErtsMRefThing); + } + else { + int nlen; + i = internal_ref_no_numbers(obj); + if (dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) { + nlen = 1; + } + else { + nlen = encode_atom_size(acmp, + internal_ref_node_name(obj), + dflags); + } + result += (1 + 2 + nlen + 4 + 4*i); + } + break; + case EXTERNAL_PORT_DEF: { + int nlen = encode_atom_size(acmp, + external_port_node_name(obj), + dflags); + result += (1 + nlen + 8 + 4); break; - case EXTERNAL_PORT_DEF: + } case PORT_DEF: { - Uint64 num = port_number(obj); - result += (num > ERTS_MAX_V3_PORT_NUMBER) ? 8 : 4; - result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) - /* num */ + 4); + int nlen = ((dflags & (DFLAG_ETS_COMPRESSED|DFLAG_LOCAL_EXT)) + ? 1 + : encode_atom_size(acmp, + internal_port_node_name(obj), + dflags)); + result += (1 + nlen + 8 + 4); break; } case LIST_DEF: { @@ -5451,22 +5578,12 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, + 4 /* size */); trailing_result = 0; } - else if (dflags & DFLAG_BIT_BINARIES) { + else { result += (1 /* BIT_BINARY_EXT */ + 4 /* size */ + 1 /* trailing bitsize */); trailing_result = 1 /* trailing bits */; } - else { - /* sigh... */ - result += (1 /* SMALL_TUPLE_EXT */ - + 1 /* 2 tuple size */ - + 1 /* BINARY_EXT */ - + 4 /* binary size */); - trailing_result = (1 /* trailing bits */ - + 1 /* SMALL_INTEGER_EXT */ - + 1 /* bitsize */); - } csz = result - ctx->last_result; ctx->last_result = result; result += trailing_result; @@ -5477,123 +5594,60 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, /* potentially multiple elements for binary */ vlen += bin_size/MAX_SYSIOVEC_IOVLEN; ctx->extra_size += bin_size; - - if (dflags & DFLAG_PENDING_CONNECT) { - ASSERT(dflags & DFLAG_BIT_BINARIES); - ASSERT(ctx); - vlen += 2; /* for hopefull prolog and epilog */ - result += (4 /* for hopefull prolog (see below) */ - + 4); /* for hopefull epilog (see below) */ - ctx->last_result = result; - } break; } } } if (bitsize == 0) { - result += (1 /* BIT_BINARY_EXT */ - + 4 /* size */ - + bin_size); - } - else if (dflags & DFLAG_PENDING_CONNECT) { - /* This is the odd case when we have an un-aligned bit-string - during a pending connect. */ - Uint csz; - ASSERT(dflags & DFLAG_BIT_BINARIES); - ASSERT(vlen >= 0); - ASSERT(ctx); - csz = result - ctx->last_result; - /* potentially multiple elements leading up to binary */ - vlen += (csz + MAX_SYSIOVEC_IOVLEN - 1)/MAX_SYSIOVEC_IOVLEN; - - vlen++; /* hopefull prolog */ - /* - * Size for hopefull prolog is max of - * - fallback: 1 + 1 + 1 + 4 - * - hopfull index + bit binary prolog: 4 + 1 + 4 + 1 - */ - result += 4 + 1 + 4 + 1; - /* potentially multiple elements for binary */ - vlen += bin_size/MAX_SYSIOVEC_IOVLEN + 1; - result += bin_size; - vlen++; /* hopefull epiolog */ - /* - * Size for hopefull epiolog is max of - * - fallback: 1 + 1 + 1 - * - hopfull index + bit binary epilog: 4 + 1 - */ - result += 4 + 1; - ctx->last_result = result; - } - else if (dflags & DFLAG_BIT_BINARIES) { - result += 1 + 4 + 1 + bin_size + 1; + result += (1 /* BINARY_EXT */ + + 4); /* size */ } else { - /* Sigh... */ - result += 1 + 1 + 1 + 4 + bin_size + 1 + 1 + 1; + result += (1 /* BIT_BINARY_EXT */ + + 4 /* size */ + + 1 /* bits */ + + 1); /* trailing bits */ } + result += bin_size; break; } - case FUN_DEF: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(obj); - - ASSERT(dflags & DFLAG_NEW_FUN_TAGS); - if (dflags & DFLAG_PENDING_CONNECT) { - ASSERT(vlen >= 0); - WSTACK_PUSH(s, PATCH_FUN_SIZE_OP); - } - result += 20+1+1+4; /* New ID + Tag */ - result += 4; /* Length field (number of free variables */ - result += encode_size_struct2(acmp, funp->creator, dflags); - result += encode_size_struct2(acmp, funp->fe->module, dflags); - result += 2 * (1+4); /* Index, Uniq */ - if (funp->num_free > 1) { - WSTACK_PUSH2(s, (UWord) (funp->env + 1), - (UWord) TERM_ARRAY_OP(funp->num_free-1)); - } - if (funp->num_free != 0) { - obj = funp->env[0]; - continue; /* big loop */ - } - break; - } + case FUN_DEF: + { + ErlFunThing *funp = (ErlFunThing *) fun_val(obj); + + if (is_local_fun(funp)) { + result += 20+1+1+4; /* New ID + Tag */ + result += 4; /* Length field (number of free variables */ + result += encode_pid_size(acmp, funp->creator, dflags); + result += encode_atom_size(acmp, funp->entry.fun->module, dflags); + result += 2 * (1+4); /* Index, Uniq */ + if (funp->num_free > 1) { + WSTACK_PUSH2(s, (UWord) (funp->env + 1), + (UWord) TERM_ARRAY_OP(funp->num_free-1)); + } + if (funp->num_free != 0) { + obj = funp->env[0]; + continue; /* big loop */ + } + } else { + Export* ep = funp->entry.exp; - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(obj) + 1)); - Uint tmp_result = result; - result += 1; - result += encode_size_struct2(acmp, ep->info.mfa.module, dflags); - result += encode_size_struct2(acmp, ep->info.mfa.function, dflags); - result += encode_size_struct2(acmp, make_small(ep->info.mfa.arity), dflags); - if (dflags & DFLAG_PENDING_CONNECT) { - Uint csz; - ASSERT(ctx); + ASSERT(is_external_fun(funp) && funp->next == NULL); - /* - * Fallback is 1 + 1 + Module size + Function size, that is, - * the hopefull index + hopefull encoding is larger... - */ - ASSERT(dflags & DFLAG_EXPORT_PTR_TAG); - ASSERT(vlen >= 0); - csz = tmp_result - ctx->last_result; - /* potentially multiple elements leading up to hopefull entry */ - vlen += (csz/MAX_SYSIOVEC_IOVLEN + 1 - + 1); /* hopefull entry */ - result += 4; /* hopefull index */ - ctx->last_result = result; + result += 1; + result += encode_atom_size(acmp, ep->info.mfa.module, dflags); + result += encode_atom_size(acmp, ep->info.mfa.function, dflags); + result += encode_small_size(acmp, make_small(ep->info.mfa.arity), dflags); } - } - break; + break; + } default: erts_exit(ERTS_ERROR_EXIT,"Internal data structure error (in encode_size_struct_int) %x\n", obj); } - pop_next: if (WSTACK_ISEMPTY(s)) { break; } @@ -5610,20 +5664,6 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, obj = CAR(cons); } break; - - case PATCH_FUN_SIZE_OP: { - Uint csz; - ASSERT(vlen >= 0 && (dflags & DFLAG_PENDING_CONNECT)); - csz = result - ctx->last_result; - /* potentially multiple elements leading up to hopefull entry */ - vlen += (csz/MAX_SYSIOVEC_IOVLEN + 1 - + 1); /* hopefull entry */ - result += (4 /* hopefull index */ - + 1 /* HOPEFUL_END_OF_FUN */ - + sizeof(byte*)); /* size_p */ - ctx->last_result = result; - goto pop_next; - } case TERM_ARRAY_OP(1): obj = *(Eterm*)WSTACK_POP(s); break; @@ -5654,34 +5694,26 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, return ERTS_EXT_SZ_OK; } - - static Sint decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ctx) { Sint heap_size; - int terms; int atom_extra_skip; Uint n; SWord reds; + const byte *lext_hash; + Uint32 lext_term_end; - if (ctx) { - reds = ctx->reds; - if (ctx->u.sc.ep) { - heap_size = ctx->u.sc.heap_size; - terms = ctx->u.sc.terms; - ep = ctx->u.sc.ep; - atom_extra_skip = ctx->u.sc.atom_extra_skip; - goto init_done; - } - } - else - ERTS_UNDEF(reds, 0); - - heap_size = 0; - terms = 1; - atom_extra_skip = 0; -init_done: + /* Keep track of the current number of sub terms remaining to be decoded. + * + * We limit the number of sub terms to 2^32-1, even on 64-bit + * machines, because a term that has many sub-terms must be truly + * ginormous and is proably a mistake. + * + * This means that a map with 2^31 or more elements cannot be decoded, + * even on a 64-bit machine. + */ + Uint32 terms; #define SKIP(sz) \ do { \ @@ -5703,13 +5735,47 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct if ((sz) > endp-ep) { goto error; } \ } while (0) +/* Increment the number of terms that remain to decode + * and check for the term counter wrapping around. */ #define ADDTERMS(n) \ do { \ - int before = terms; \ + Uint32 before = terms; \ terms += (n); \ if (terms < before) goto error; \ } while (0) + + if (ctx) { + reds = ctx->reds; + if (ctx->u.sc.ep) { + ep = ctx->u.sc.ep; + atom_extra_skip = ctx->u.sc.atom_extra_skip; + heap_size = ctx->u.sc.heap_size; + lext_hash = ctx->u.sc.lext_hash; + lext_term_end = ctx->u.sc.lext_term_end; + terms = ctx->u.sc.terms; + if (terms == lext_term_end) { + ASSERT(lext_hash); + goto continue_check_lext; + } + goto init_done; + } + } + else + ERTS_UNDEF(reds, 0); + + heap_size = 0; + terms = 1; + atom_extra_skip = 0; + /* + * lext_hash != NULL and local_term_end != ~0 when decoding local external + * term format... + */ + lext_hash = NULL; + lext_term_end = ~0; + +init_done: + ASSERT(terms > 0); do { int tag; @@ -5790,7 +5856,7 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct case_PID: /* In case it is an external pid */ heap_size += EXTERNAL_PID_HEAP_SIZE; - terms++; + ADDTERMS(1); break; case V4_PORT_EXT: atom_extra_skip = 12; @@ -5803,7 +5869,7 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct case_PORT: /* In case it is an external port */ heap_size += EXTERNAL_PORT_HEAP_SIZE; - terms++; + ADDTERMS(1); break; case NEWER_REFERENCE_EXT: atom_extra_skip = 4; @@ -5828,7 +5894,7 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct #else heap_size += EXTERNAL_THING_HEAD_SIZE + id_words; #endif - terms++; + ADDTERMS(1); break; } case REFERENCE_EXT: @@ -5838,25 +5904,40 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct terms++; break; case NIL_EXT: + if (atom_extra_skip) { + /* + * atom_extra_skip != 0 should only appear due to local encoding, + * or compressed ets encoding, of a node name in internal + * pids/ports/refs. If not currently inside a local encoding, + * this is an error... + */ + if (!lext_hash && !internal_tags) + goto error; + SKIP(atom_extra_skip); + atom_extra_skip = 0; + } break; case LIST_EXT: CHKSIZE(4); n = get_uint32(ep); ep += 4; - ADDTERMS(n); - terms++; + CHKSIZE(n); /* Fail faster if the binary is too short. */ + /* Count terms in two operations to avoid overflow. */ + ADDTERMS(n); + ADDTERMS(1); heap_size += 2 * n; break; case SMALL_TUPLE_EXT: CHKSIZE(1); n = *ep++; - terms += n; + ADDTERMS(n); heap_size += n + 1; break; case LARGE_TUPLE_EXT: CHKSIZE(4); n = get_uint32(ep); ep += 4; + CHKSIZE(n); /* Fail faster if the binary is too short. */ ADDTERMS(n); heap_size += n + 1; break; @@ -5864,19 +5945,25 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct CHKSIZE(4); n = get_uint32(ep); ep += 4; - ADDTERMS(2*n); if (n <= MAP_SMALL_MAP_LIMIT) { heap_size += 3 + n + 1 + n; - } else { -#if !defined(ARCH_64) - if ((n >> 30) != 0) { - /* Can't possibly fit in memory. */ - goto error; - } +#if defined(ARCH_64) + } else if ((n >> 31) != 0) { + /* Avoid overflow by limiting the number of elements in + * a map to 2^31-1 (about 2 billions). */ + goto error; +#else + } else if ((n >> 30) != 0) { + /* Can't possibly fit in memory on 32-bit machine. */ + goto error; #endif - CHKSIZE(2*n); /* Conservative size check */ + } else { + CHKSIZE(2*(Uint)n); /* Fail faster if the binary is too short. */ heap_size += HASHMAP_ESTIMATED_HEAP_SIZE(n); } + /* Count terms in two operations to avoid overflow. */ + ADDTERMS(n); + ADDTERMS(n); break; case STRING_EXT: CHKSIZE(2); @@ -5923,8 +6010,8 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct } break; case EXPORT_EXT: - terms += 3; - heap_size += 2; + ADDTERMS(3); + heap_size += ERL_FUN_SIZE; break; case NEW_FUN_EXT: { @@ -5942,7 +6029,7 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct if (num_free > MAX_ARG) { goto error; } - terms += 4 + num_free; + ADDTERMS(4 + num_free); heap_size += ERL_FUN_SIZE + num_free; break; } @@ -5975,23 +6062,92 @@ decoded_size(const byte *ep, const byte* endp, int internal_tags, B2TContext* ct SKIP(2+sizeof(ProcBin)); heap_size += PROC_BIN_SIZE + ERL_SUB_BIN_SIZE; break; + case MAGIC_REF_INTERNAL_REF: + if (!internal_tags) + goto error; + SKIP(sizeof(ErtsMRefThing)); + heap_size += ERTS_MAGIC_REF_THING_SIZE; + break; + case LOCAL_EXT: + /* + * Currently the hash is 4 bytes large... + */ + CHKSIZE(4); + lext_hash = ep; + lext_term_end = terms - 1; + terms++; + ep += 4; + break; default: goto error; } terms--; - if (ctx && --reds <= 0 && terms > 0) { + if (terms == lext_term_end) { + ErtsBlockHashState lext_state_buf, *lext_state; + const byte *ep_start = lext_hash + 4 /* 32 bit hash value */; + Sint len = ep - ep_start; + Uint chunk_len; + Uint32 hash; + + ASSERT(lext_hash); + + if (len <= 0) { + /* no terms */ + goto error; + } + + lext_state = ctx ? &ctx->u.sc.lext_state : &lext_state_buf; + + erts_block_hash_init(lext_state, ep_start, len, local_node_hash); + + if (!ctx) { + /* Do it all at once... */ + chunk_len = ERTS_UINT_MAX; + } + else { + continue_check_lext: + lext_state = &ctx->u.sc.lext_state; + /* 'reds' has been scaled up to "bytes per reds"... */ + chunk_len = (Uint) reds; + } + + if (!erts_block_hash(&hash, &chunk_len, lext_state)) { + /* yield; more work calculating hash... */ + ASSERT(ctx); + reds = 0; + } + else { + reds -= chunk_len; + if (hash != get_int32(lext_hash)) { + /* + * Hash presented in external format did not match the + * calculated hash... + */ + goto error; + } + lext_hash = NULL; + lext_term_end = ~0; + } + + } + + ASSERT(terms != ~0); + + if (ctx && --reds <= 0 && terms != 0) { ctx->u.sc.heap_size = heap_size; ctx->u.sc.terms = terms; ctx->u.sc.ep = ep; ctx->u.sc.atom_extra_skip = atom_extra_skip; + ctx->u.sc.lext_hash = lext_hash; + ctx->u.sc.lext_term_end = lext_term_end; ctx->reds = 0; return 0; } - }while (terms > 0); + } while (terms != 0); - /* 'terms' may be non-zero if it has wrapped around */ if (terms == 0) { + if (ctx) { ctx->state = B2TDecodeInit; ctx->reds = reds; @@ -6101,10 +6257,8 @@ Sint transcode_dist_obuf(ErtsDistOutputBuf* ob, ErlIOVec* eiov = ob->eiov; SysIOVec* iov = eiov->iov; byte *hdr; - Uint64 hopefull_flags; - Uint32 hopefull_ix, payload_ix; + Uint32 payload_ix; Sint start_r, r; - Uint new_len; byte *ep; if (reds < 0) @@ -6170,11 +6324,9 @@ Sint transcode_dist_obuf(ErtsDistOutputBuf* ob, return reds; } + /* Currently, the hopefull flags and IX are not used. */ hdr++; - hopefull_flags = get_int64(hdr); - hdr += 8; - hopefull_ix = get_int32(hdr); if ((~dflags & DFLAG_SPAWN) && ep[0] == SMALL_TUPLE_EXT @@ -6236,296 +6388,9 @@ Sint transcode_dist_obuf(ErtsDistOutputBuf* ob, return 0; return reds; } - - if ((~dflags & DFLAG_UNLINK_ID) - && ep[0] == SMALL_TUPLE_EXT - && ep[1] == 4 - && ep[2] == SMALL_INTEGER_EXT - && (ep[3] == DOP_UNLINK_ID_ACK || ep[3] == DOP_UNLINK_ID)) { - - if (ep[3] == DOP_UNLINK_ID_ACK) { - /* Drop DOP_UNLINK_ID_ACK signal... */ - int i; - for (i = 1; i < ob->eiov->vsize; i++) { - if (ob->eiov->binv[i]) - driver_free_binary(ob->eiov->binv[i]); - } - ob->eiov->vsize = 1; - ob->eiov->size = 0; - } - else { - Eterm ctl_msg, remote, local, *tp; - ErtsTranscodeDecodeState tds; - Uint64 id; - byte *ptr; - ASSERT(ep[3] == DOP_UNLINK_ID); - /* - * Rewrite the DOP_UNLINK_ID signal into a - * DOP_UNLINK signal and send an unlink ack - * to the local sender. - */ - - /* - * decode control message so we get info - * needed for unlink ack signal to send... - */ - ASSERT(get_int32(hdr + 4) == 0); /* No payload */ - ctl_msg = transcode_decode_ctl_msg(&tds, iov, eiov->vsize); - - ASSERT(is_tuple_arity(ctl_msg, 4)); - - tp = tuple_val(ctl_msg); - ASSERT(tp[1] == make_small(DOP_UNLINK_ID)); - - if (!term_to_Uint64(tp[2], &id)) - ERTS_INTERNAL_ERROR("Invalid encoding of DOP_UNLINK_ID signal"); - - local = tp[3]; - remote = tp[4]; - - ASSERT(is_internal_pid(local)); - ASSERT(is_external_pid(remote)); - - /* - * Rewrite buffer to an unlink signal by removing - * second element and change first element to - * DOP_UNLINK. That is, to: {DOP_UNLINK, local, remote} - */ - - ptr = &ep[4]; - switch (*ptr) { - case SMALL_INTEGER_EXT: - ptr += 1; - break; - case INTEGER_EXT: - ptr += 4; - break; - case SMALL_BIG_EXT: - ptr += 1; - ASSERT(*ptr <= 8); - ptr += *ptr + 1; - break; - default: - ERTS_INTERNAL_ERROR("Invalid encoding of DOP_UNLINK_ID signal"); - break; - } - - ASSERT((ptr - ep) <= 16); - ASSERT((ptr - ep) <= iov[2].iov_len); - - *(ptr--) = DOP_UNLINK; - *(ptr--) = SMALL_INTEGER_EXT; - *(ptr--) = 3; - *ptr = SMALL_TUPLE_EXT; - - iov[2].iov_base = ptr; - iov[2].iov_len -= (ptr - ep); - -#ifdef DEBUG - { - ErtsTranscodeDecodeState dbg_tds; - Eterm new_ctl_msg = transcode_decode_ctl_msg(&dbg_tds, - iov, - eiov->vsize); - ASSERT(is_tuple_arity(new_ctl_msg, 3)); - tp = tuple_val(new_ctl_msg); - ASSERT(tp[1] == make_small(DOP_UNLINK)); - ASSERT(tp[2] == local); - ASSERT(eq(tp[3], remote)); - transcode_decode_state_destroy(&dbg_tds); - } -#endif - - /* Send unlink ack to local sender... */ - erts_proc_sig_send_dist_unlink_ack(NULL, dep, - dep->connection_id, - remote, local, id); - - transcode_decode_state_destroy(&tds); - - reds -= 5; - } - if (reds < 0) - return 0; - return reds; - } start_r = r = reds*ERTS_TRANSCODE_REDS_FACT; - if (~dflags & hopefull_flags) { - - while (hopefull_ix != ERTS_NO_HIX) { - Uint32 new_hopefull_ix; - - if (r <= 0) { /* yield... */ - /* save current hopefull_ix... */ - ep = (byte *) iov[1].iov_base; - ep += 5; - put_int32(hopefull_ix, ep); - return -1; - } - - /* Read next hopefull index */ - ep = (byte *) iov[hopefull_ix].iov_base; - ep -= 4; - new_hopefull_ix = get_int32(ep); - ASSERT(new_hopefull_ix == ERTS_NO_HIX - || (hopefull_ix < new_hopefull_ix - && new_hopefull_ix < eiov->vsize)); - - ep = (byte *) iov[hopefull_ix].iov_base; - switch (*ep) { - - case EXPORT_EXT: { - byte *start_ep, *end_ep; - Eterm module, function; - if (dflags & DFLAG_EXPORT_PTR_TAG) - break; - /* Read original encoding... */ - ep++; - start_ep = ep; - ep = (byte*)dec_atom(NULL, ep, &module); - ASSERT(ep && is_atom(module)); - ep = (byte*)dec_atom(NULL, ep, &function); - ASSERT(ep && is_atom(function)); - end_ep = ep; - ASSERT(*ep == SMALL_INTEGER_EXT - || *ep == INTEGER_EXT - || *ep == SMALL_BIG_EXT - || *ep == LARGE_BIG_EXT); - - /* - * module and function atoms are encoded - * between start_ep and end_ep. Prepend a - * 2-tuple tag before the atoms and - * remove arity at end. - */ - - /* write fallback */ - - ep = start_ep; - ep--; - put_int8(2, ep); - ep--; - *ep = SMALL_TUPLE_EXT; - - iov[hopefull_ix].iov_base = ep; - - /* Update iov sizes... */ - new_len = end_ep - ep; - eiov->size -= iov[hopefull_ix].iov_len; - eiov->size += new_len; - iov[hopefull_ix].iov_len = new_len; - r--; - break; - } - - case BIT_BINARY_EXT: { - Uint bin_sz; - byte bitsize, epilog_byte; - ASSERT(hopefull_ix != ERTS_NO_HIX); - if (dflags & DFLAG_BIT_BINARIES) { - /* skip to epilog... */ - hopefull_ix = new_hopefull_ix; - ep = (byte *) iov[hopefull_ix].iov_base; - ep -= 4; - new_hopefull_ix = get_int32(ep); - ASSERT(new_hopefull_ix == ERTS_NO_HIX - || (hopefull_ix < new_hopefull_ix - && new_hopefull_ix < eiov->vsize)); - break; - } - - /* read original encoded prolog... */ - ep++; - bin_sz = get_uint32(ep); - ep += 4; - bitsize = *ep++; - - /* write fallback prolog... */ - iov[hopefull_ix].iov_base = &((byte*)iov[hopefull_ix].iov_base)[-4]; - ep = (byte *) iov[hopefull_ix].iov_base; - - *ep++ = SMALL_TUPLE_EXT; - *ep++ = 2; - *ep++ = BINARY_EXT; - put_int32(bin_sz, ep); - ep += 4; - - /* Update iov sizes... */ - new_len = ep - (byte *) iov[hopefull_ix].iov_base; - eiov->size -= iov[hopefull_ix].iov_len; - eiov->size += new_len; - iov[hopefull_ix].iov_len = new_len; - r--; -#ifdef DEBUG - /* - * The binary data between the prolog and the - * epilog should be of size 'bin_sz - 1' and - * exists in the iov elements between prolog - * and epilog... - */ - { - Uint ix, debug_bin_sz = 0; - for (ix = hopefull_ix+1; ix < new_hopefull_ix; ix++) - debug_bin_sz += iov[ix].iov_len; - ASSERT(debug_bin_sz == bin_sz - 1); - } -#endif - /* jump to epilog... */ - hopefull_ix = new_hopefull_ix; - ep = (byte *) iov[hopefull_ix].iov_base; - - /* read original encoded epilog... */ - epilog_byte = *ep; - - ASSERT(1 == iov[hopefull_ix].iov_len); - - iov[hopefull_ix].iov_base = &((byte*)iov[hopefull_ix].iov_base)[-4]; - ep = (byte *) iov[hopefull_ix].iov_base; - new_hopefull_ix = get_int32(ep); - ASSERT(new_hopefull_ix == ERTS_NO_HIX - || (hopefull_ix < new_hopefull_ix - && new_hopefull_ix < eiov->vsize)); - - /* write fallback epilog... */ - - *ep++ = epilog_byte; - *ep++ = SMALL_INTEGER_EXT; - *ep++ = bitsize; - - /* Update iov sizes... */ - new_len = ep - (byte *) iov[hopefull_ix].iov_base; - eiov->size -= iov[hopefull_ix].iov_len; - eiov->size += new_len; - iov[hopefull_ix].iov_len = new_len; - r--; - break; - } - - case HOPEFUL_END_OF_FUN: { - byte* size_p; - Uint32 fun_sz; - - ASSERT(iov[hopefull_ix].iov_len == 0); - ep++; - sys_memcpy(&size_p, ep, sizeof(size_p)); - - fun_sz = calc_iovec_fun_size(iov, hopefull_ix-1, size_p); - put_int32(fun_sz, size_p); - break; - } - - default: - ERTS_INTERNAL_ERROR("Unexpected external tag"); - break; - } - - hopefull_ix = new_hopefull_ix; - r--; - } - } - /* * Replace hopefull data header with actual header... */ diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h index 1e5a55d42f74..ce27423ff6ae 100644 --- a/erts/emulator/beam/external.h +++ b/erts/emulator/beam/external.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -57,17 +57,18 @@ #define ATOM_UTF8_EXT 'v' #define SMALL_ATOM_UTF8_EXT 'w' #define V4_PORT_EXT 'x' +#define LOCAL_EXT 'y' #define DIST_HEADER 'D' #define DIST_FRAG_HEADER 'E' #define DIST_FRAG_CONT 'F' #define HOPEFUL_DATA 'H' -#define HOPEFUL_END_OF_FUN 'Q' #define ATOM_CACHE_REF 'R' #define ATOM_INTERNAL_REF2 'I' #define ATOM_INTERNAL_REF3 'K' #define BINARY_INTERNAL_REF 'J' #define BIT_BINARY_INTERNAL_REF 'L' +#define MAGIC_REF_INTERNAL_REF 'N' #define COMPRESSED 'P' #if 0 @@ -188,7 +189,7 @@ int erts_encode_dist_ext(Eterm, byte **, Uint64, ErtsAtomCacheMap *, struct TTBEncodeContext_ *, Uint *, Sint *); ErtsExtSzRes erts_encode_ext_size(Eterm, Uint *szp); -ErtsExtSzRes erts_encode_ext_size_2(Eterm, unsigned, Uint *szp); +ErtsExtSzRes erts_encode_ext_size_2(Eterm, Uint64, Uint *szp); Uint erts_encode_ext_size_ets(Eterm); void erts_encode_ext(Eterm, byte **); byte* erts_encode_ext_ets(Eterm, byte *, struct erl_off_heap_header** ext_off_heap); diff --git a/erts/emulator/beam/generators.tab b/erts/emulator/beam/generators.tab index 546b3b18b207..a737228c444f 100644 --- a/erts/emulator/beam/generators.tab +++ b/erts/emulator/beam/generators.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020-2021. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. 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. @@ -51,31 +51,6 @@ NativeEndian(flags) { #endif } -gen_bs_save_restore(reg, index, instr) { - BeamOp* op; - - $NewBeamOp(S, op); - $BeamOpNameArity(op, $instr, 2); - op->a[0] = $reg; - op->a[1] = $index; - if (Index.type == TAG_u) { - op->a[1].val = $index.val+1; - } else if ($index.type == TAG_a && $index.val == am_start) { - op->a[1].type = TAG_u; - op->a[1].val = 0; - } - return op; -} - -gen.bs_save(Reg, Index) { - $gen_bs_save_restore(Reg, Index, i_bs_save2); -} - -gen.bs_restore(Reg, Index) { - $gen_bs_save_restore(Reg, Index, i_bs_restore2); -} - - // Generate an instruction to fetch a float from a binary. gen.get_float2(Fail, Ms, Live, Size, Unit, Flags, Dst) { BeamOp* op; @@ -325,149 +300,136 @@ gen.skip_bits2(Fail, Ms, Size, Unit, Flags) { return op; } -gen_increment(stp, reg, val, dst) { - BeamOp* op; - $NewBeamOp($stp, op); - $BeamOpNameArity(op, i_increment, 3); - op->a[0] = $reg; - op->a[1].type = TAG_u; - op->a[1].val = $val; - op->a[2] = $dst; - return op; -} - -gen.increment(Reg, Integer, Dst) { - $gen_increment(S, Reg, Integer.val, Dst); -} +// Creates an instruction that moves a literal lambda to a register. +MakeLiteralLambda(Op, Index, DstType, DstVal) { + BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val]; + SWord literal; + + ASSERT(entry->num_free == 0); + + /* If we haven't already done so, we need to create a placeholder for the + * lambda. */ + if (S->lambda_literals[$Index] == ERTS_SWORD_MAX) { + Eterm tmp_hp[ERL_FUN_SIZE]; + ErlFunThing *funp; + + /* The placeholder is an external fun with the export field set to + * NULL, preventing it from colliding with external fun literals + * created by the user. We also disable deduplication to prevent it + * from colliding with other placeholder lambdas of the same arity. */ + funp = (ErlFunThing*)tmp_hp; + funp->thing_word = HEADER_FUN; + funp->entry.exp = NULL; + funp->next = NULL; + funp->arity = entry->arity; + funp->num_free = 0; + funp->creator = am_external; + + literal = beamfile_add_literal(&S->beam, make_fun(tmp_hp), 0); + S->lambda_literals[$Index] = literal; + } else { + literal = S->lambda_literals[$Index]; + } -gen.increment_from_minus(Reg, Integer, Dst) { - $gen_increment(S, Reg, -Integer.val, Dst); + $BeamOpNameArity($Op, move, 2); + ($Op)->a[0].type = TAG_q; + ($Op)->a[0].val = literal; + ($Op)->a[1].type = $DstType; + ($Op)->a[1].val = $DstVal; } -gen.plus_from_minus(Fail, Live, Src, Integer, Dst) { - BeamOp* op; - - ASSERT(Integer.type == TAG_i && IS_SSMALL(-(Sint)Integer.val)); - - $NewBeamOp(S, op); - $BeamOpNameArity(op, gen_plus, 5); - op->a[0] = Fail; - op->a[1] = Live; - op->a[2] = Src; - op->a[3].type = TAG_i; - op->a[3].val = -(Sint)Integer.val; - op->a[4] = Dst; - - return op; -} - -gen.make_fun2(idx) { +gen.make_fun2(Idx) { BeamOp* op; BeamOp* th; $NewBeamOp(S, op); - if (idx.val >= S->beam.lambdas.count) { + if (Idx.val >= S->beam.lambdas.count) { $BeamOpNameArity(op, i_lambda_error, 1); op->a[0].type = TAG_o; op->a[0].val = 0; - return op; + return op; } else { - int i; - BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[idx.val]; - unsigned num_free = entry->num_free; - - $NewBeamOp(S, th); - - $BeamOpNameArity(th, test_heap, 2); - th->a[0].type = TAG_u; - th->a[0].val = ERL_FUN_SIZE + num_free; - th->a[1].type = TAG_u; - th->a[1].val = num_free; - th->next = op; - - $BeamOpNameArity(op, i_make_fun3, 3); - $BeamOpArity(op, 3 + num_free); - op->a[0].type = TAG_u; - op->a[0].val = idx.val; - op->a[1].type = TAG_x; - op->a[1].val = 0; - op->a[2].type = TAG_u; - op->a[2].val = num_free; - for (i = 0; i < num_free; i++) { - op->a[i+3].type = TAG_x; - op->a[i+3].val = i; - } - return th; - } -} + BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val]; + unsigned num_free = entry->num_free; + unsigned arity = entry->arity; + int i; + + /* Literal lambdas are all owned by the init process as a workaround + * for all local funs needing a creator pid. Skip the optimization if + * this module is being loaded before said process has started + * (just preloaded modules, really). */ + if (num_free == 0 && erts_init_process_id != ERTS_INVALID_PID) { + $MakeLiteralLambda(op, Idx.val, TAG_x, 0); + return op; + } -gen.make_fun3(idx, Dst, NumFree, Env) { - BeamOp* op; + $NewBeamOp(S, th); - $NewBeamOp(S, op); + $BeamOpNameArity(th, test_heap, 2); + th->a[0].type = TAG_u; + th->a[0].val = ERL_FUN_SIZE + num_free; + th->a[1].type = TAG_u; + th->a[1].val = num_free; + th->next = op; - if (idx.val < S->beam.lambdas.count) { - BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[idx.val]; - if (NumFree.val == entry->num_free) { - int i; - - $BeamOpNameArity(op, i_make_fun3, 3); - $BeamOpArity(op, 3 + NumFree.val); - op->a[0].type = TAG_u; - op->a[0].val = idx.val; - op->a[1] = Dst; - op->a[2].type = TAG_u; - op->a[2].val = entry->num_free; - for (i = 0; i < NumFree.val; i++) { - op->a[i+3] = Env[i]; - } - return op; - } - } - $BeamOpNameArity(op, i_lambda_error, 1); - op->a[0].type = TAG_o; - op->a[0].val = 0; - return op; -} + $BeamOpNameArity(op, i_make_fun3, 4); + $BeamOpArity(op, 4 + num_free); + op->a[0].type = TAG_u; + op->a[0].val = Idx.val; + op->a[1].type = TAG_x; + op->a[1].val = 0; + op->a[2].type = TAG_u; + op->a[2].val = arity - num_free; + op->a[3].type = TAG_u; + op->a[3].val = num_free; -gen.tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5) { - BeamOp* op; - int arity = Arity.val; /* Arity of tuple, not the instruction */ - int i; + for (i = 0; i < num_free; i++) { + op->a[i+4].type = TAG_x; + op->a[i+4].val = i; + } - $NewBeamOp(S, op); - $BeamOpNameArity(op, i_put_tuple, 2); - $BeamOpArity(op, arity+2+5); - op->a[0] = Dst; - op->a[1].type = TAG_u; - op->a[1].val = arity + 5; - for (i = 0; i < arity; i++) { - op->a[i+2] = Puts[i]; + return th; } - op->a[arity+2] = S1; - op->a[arity+3] = S2; - op->a[arity+4] = S3; - op->a[arity+5] = S4; - op->a[arity+6] = S5; - return op; } -gen.tuple_append_put(Arity, Dst, Puts, Src) { +gen.make_fun3(Idx, Dst, NumFree, Env) { BeamOp* op; - int arity = Arity.val; /* Arity of tuple, not the instruction */ - int i; $NewBeamOp(S, op); - $BeamOpNameArity(op, i_put_tuple, 2); - $BeamOpArity(op, arity+2+1); - op->a[0] = Dst; - op->a[1].type = TAG_u; - op->a[1].val = arity + 1; - for (i = 0; i < arity; i++) { - op->a[i+2] = Puts[i]; + + if (Idx.val < S->beam.lambdas.count) { + BeamFile_LambdaEntry *entry = &S->beam.lambdas.entries[Idx.val]; + + if (NumFree.val == entry->num_free) { + int i; + + if (NumFree.val == 0 && erts_init_process_id != ERTS_INVALID_PID) { + $MakeLiteralLambda(op, Idx.val, Dst.type, Dst.val); + } else { + $BeamOpNameArity(op, i_make_fun3, 4); + $BeamOpArity(op, 4 + NumFree.val); + + op->a[0].type = TAG_u; + op->a[0].val = Idx.val; + op->a[1] = Dst; + op->a[2].type = TAG_u; + op->a[2].val = entry->arity - entry->num_free; + op->a[3].type = TAG_u; + op->a[3].val = entry->num_free; + + for (i = 0; i < NumFree.val; i++) { + op->a[i+4] = Env[i]; + } + } + + return op; + } } - op->a[arity+2] = Src; + + $BeamOpNameArity(op, i_lambda_error, 1); + op->a[0].type = TAG_o; + op->a[0].val = 0; return op; } diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 200d74c78671..3170cebe951b 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -122,11 +122,16 @@ extern void erts_add_taint(Eterm mod_atom); extern Eterm erts_nif_taints(Process* p); extern void erts_print_nif_taints(fmtfn_t to, void* to_arg); -/* Loads the specified NIF. The caller must have code write permission. */ +/* Loads the specified NIF. The caller must have code modification + * permission. */ Eterm erts_load_nif(Process *c_p, ErtsCodePtr I, Eterm filename, Eterm args); void erts_unload_nif(struct erl_module_nif* nif); extern void erl_nif_init(void); +extern void erts_nif_sched_init(ErtsSchedulerData *esdp); +extern void erts_nif_execute_on_halt(void); +extern void erts_nif_notify_halt(void); +extern void erts_nif_wait_calls(void); extern int erts_nif_get_funcs(struct erl_module_nif*, struct enif_func_t **funcs); extern Module *erts_nif_get_module(struct erl_module_nif*); @@ -950,6 +955,7 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2); Eterm erts_check_process_code(Process *c_p, Eterm module, int *redsp, int fcalls); #define ERTS_CLA_SCAN_WORDS_PER_RED 512 +int erts_check_copy_literals_gc_need_max_reds(Process *c_p); int erts_check_copy_literals_gc_need(Process *c_p, int *redsp, char *literals, Uint lit_bsize); Eterm erts_copy_literals_gc(Process *c_p, int *redsp, int fcalls); @@ -969,7 +975,7 @@ typedef struct ErtsLiteralArea_ { void erts_queue_release_literals(Process *c_p, ErtsLiteralArea* literals); #define ERTS_LITERAL_AREA_ALLOC_SIZE(N) \ - (sizeof(ErtsLiteralArea) + sizeof(Eterm)*((N) - 1)) + (sizeof(ErtsLiteralArea) + sizeof(Eterm)*(N - 1)) #define ERTS_LITERAL_AREA_SIZE(AP) \ (ERTS_LITERAL_AREA_ALLOC_SIZE((AP)->end - (AP)->start)) @@ -1043,9 +1049,9 @@ double erts_get_positive_zero_float(void); /* config.c */ -__decl_noreturn void __noreturn erts_exit_epilogue(void); +__decl_noreturn void __noreturn erts_exit_epilogue(int flush); __decl_noreturn void __noreturn erts_exit(int n, const char*, ...); -__decl_noreturn void __noreturn erts_flush_async_exit(int n, char*, ...); +__decl_noreturn void __noreturn erts_flush_exit(int n, char*, ...); void erl_error(const char*, va_list); /* This controls whether sharing-preserving copy is used by Erlang */ @@ -1141,10 +1147,10 @@ Uint size_shared(Eterm); #ifdef ERTS_COPY_REGISTER_LOCATION -#define copy_shared_perform(U, V, X, Y, Z) \ - copy_shared_perform_x((U), (V), (X), (Y), (Z), __FILE__, __LINE__) Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*, char *file, int line); +#define copy_shared_perform(U, V, X, Y, Z) \ + copy_shared_perform_x((U), (V), (X), (Y), (Z), __FILE__, __LINE__) Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*, char *file, int line); @@ -1153,16 +1159,21 @@ Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_ #define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \ copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea,__FILE__,__LINE__) +Eterm* copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*, + char *file, int line); #define copy_shallow(R, SZ, HPP, OH) \ copy_shallow_x((R), (SZ), (HPP), (OH), __FILE__, __LINE__) -Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*, + +Eterm copy_shallow_obj_x(Eterm, Uint, Eterm**, ErlOffHeap*, char *file, int line); +#define copy_shallow_obj(R, SZ, HPP, OH) \ + copy_shallow_obj_x((R), (SZ), (HPP), (OH), __FILE__, __LINE__) #else +Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*); #define copy_shared_perform(U, V, X, Y, Z) \ copy_shared_perform_x((U), (V), (X), (Y), (Z)) -Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*); Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*); #define copy_struct(Obj,Sz,HPP,OH) \ @@ -1170,9 +1181,13 @@ Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_ #define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \ copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea) +Eterm* copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*); #define copy_shallow(R, SZ, HPP, OH) \ copy_shallow_x((R), (SZ), (HPP), (OH)) -Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*); + +Eterm copy_shallow_obj_x(Eterm, Uint, Eterm**, ErlOffHeap*); +#define copy_shallow_obj(R, SZ, HPP, OH) \ + copy_shallow_obj_x((R), (SZ), (HPP), (OH)) #endif @@ -1209,6 +1224,7 @@ void print_pass_through(int, byte*, int); int catchlevel(Process*); void init_emulator(void); void process_main(ErtsSchedulerData *); +void erts_prepare_bs_construct_fail_info(Process* c_p, const BeamInstr* p, Eterm reason, Eterm Info, Eterm value); void erts_dirty_process_main(ErtsSchedulerData *); Eterm build_stacktrace(Process* c_p, Eterm exc); Eterm expand_error_value(Process* c_p, Uint freason, Eterm Value); @@ -1300,14 +1316,15 @@ typedef struct { ErlDrvEntry* de; int taint; } ErtsStaticDriver; -typedef void *(*ErtsStaticNifInitFPtr)(void); -typedef struct ErtsStaticNifEntry_ { - const char *nif_name; - ErtsStaticNifInitFPtr nif_init; - int taint; -} ErtsStaticNifEntry; -ErtsStaticNifEntry* erts_static_nif_get_nif_init(const char *name, int len); -int erts_is_static_nif(void *handle); +typedef void* ErtsStaticNifInitF(void); +typedef struct { + ErtsStaticNifInitF* const nif_init; + const int taint; + + Eterm mod_atom; + ErlNifEntry* entry; +} ErtsStaticNif; +extern ErtsStaticNif erts_static_nif_tab[]; void erts_init_static_drivers(void); /* erl_drv_thread.c */ @@ -1436,6 +1453,7 @@ void erts_init_bif_binary(void); Sint erts_binary_set_loop_limit(Sint limit); /* erl_bif_persistent.c */ +Eterm erts_persistent_term_get(Eterm key); void erts_init_bif_persistent_term(void); void erts_init_persistent_dumping(void); extern ErtsLiteralArea** erts_persistent_areas; @@ -1448,6 +1466,7 @@ Eterm erts_debug_persistent_term_xtra_info(Process* c_p); /* external.c */ void erts_init_external(void); +void erts_late_init_external(void); /* erl_map.c */ void erts_init_map(void); @@ -1464,10 +1483,10 @@ Sint erts_unicode_set_loop_limit(Sint limit); void erts_native_filename_put(Eterm ioterm, int encoding, byte *p) ; Sint erts_native_filename_need(Eterm ioterm, int encoding); void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars); -int erts_analyze_utf8(byte *source, Uint size, - byte **err_pos, Uint *num_chars, int *left); -int erts_analyze_utf8_x(byte *source, Uint size, - byte **err_pos, Uint *num_chars, int *left, +int erts_analyze_utf8(const byte *source, Uint size, + const byte **err_pos, Uint *num_chars, int *left); +int erts_analyze_utf8_x(const byte *source, Uint size, + const byte **err_pos, Uint *num_chars, int *left, Sint *num_latin1_chars, Uint max_chars); char *erts_convert_filename_to_native(Eterm name, char *statbuf, size_t statbuf_size, @@ -1488,6 +1507,11 @@ char* erts_convert_filename_to_wchar(byte* bytes, Uint size, Eterm erts_convert_native_to_filename(Process *p, size_t size, byte *bytes); Eterm erts_utf8_to_list(Process *p, Uint num, byte *bytes, Uint sz, Uint left, Uint *num_built, Uint *num_eaten, Eterm tail); +Eterm +erts_make_list_from_utf8_buf(Eterm **hpp, Uint num, + const byte *bytes, Uint sz, + Uint *num_built, Uint *num_eaten, + Eterm tail); int erts_utf8_to_latin1(byte* dest, const byte* source, int slen); #define ERTS_UTF8_OK 0 #define ERTS_UTF8_INCOMPLETE 1 @@ -1497,7 +1521,7 @@ int erts_utf8_to_latin1(byte* dest, const byte* source, int slen); void bin_write(fmtfn_t, void*, byte*, size_t); Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */ -int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written); +int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint capacity, Sint len, Sint* written); Sint erts_unicode_list_to_buf_len(Eterm list); int Sint_to_buf(Sint num, int base, char **buf_p, size_t buf_size); @@ -1705,8 +1729,10 @@ int erts_beam_jump_table(void); ERTS_GLB_INLINE void dtrace_pid_str(Eterm pid, char *process_buf); ERTS_GLB_INLINE void dtrace_proc_str(Process *process, char *process_buf); ERTS_GLB_INLINE void dtrace_port_str(Port *port, char *port_buf); -ERTS_GLB_INLINE void dtrace_fun_decode(Process *process, ErtsCodeMFA *mfa, - char *process_buf, char *mfa_buf); +ERTS_GLB_INLINE void dtrace_fun_decode(Process *process, + const ErtsCodeMFA *mfa, + char *process_buf, + char *mfa_buf); #if ERTS_GLB_INLINE_INCL_FUNC_DEF @@ -1739,7 +1765,7 @@ dtrace_port_str(Port *port, char *port_buf) } ERTS_GLB_INLINE void -dtrace_fun_decode(Process *process, ErtsCodeMFA *mfa, +dtrace_fun_decode(Process *process, const ErtsCodeMFA *mfa, char *process_buf, char *mfa_buf) { if (process_buf) { diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c index 777a2cda5dd7..5c8b43e6e26d 100644 --- a/erts/emulator/beam/hash.c +++ b/erts/emulator/beam/hash.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -64,6 +64,7 @@ void hash_get_info(HashInfo *hi, Hash *h) } } ASSERT(objects == h->nobjs); + (void)objects; hi->name = h->name; hi->size = hash_get_slots(h); @@ -110,7 +111,7 @@ static ERTS_INLINE void set_thresholds(Hash* h) if (h->shift < h->max_shift) h->shrink_threshold = hash_get_slots(h) / 5; /* shrink at 20% load */ else - h->shrink_threshold = -1; /* never shrink below inital size */ + h->shrink_threshold = -1; /* never shrink below initial size */ } /* diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 616fd7bf428f..a79bce3d772f 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -54,6 +54,7 @@ #include "erl_time.h" #include "erl_io_queue.h" #include "erl_proc_sig_queue.h" +#include "erl_global_literals.h" extern ErlDrvEntry fd_driver_entry; extern ErlDrvEntry vanilla_driver_entry; @@ -569,7 +570,12 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ if (!(opts->spawn_type & ERTS_SPAWN_EXECUTABLE)) { /* No spawn driver default */ driver = NULL; - } + } else { +#ifdef __IOS__ + erts_rwmtx_runlock(&erts_driver_list_lock); + ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG); +#endif + } if (opts->spawn_type != ERTS_SPAWN_EXECUTABLE) { @@ -813,7 +819,8 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ port_lnk = erts_link_internal_create(ERTS_LNK_TYPE_PORT, pid); erts_link_tree_insert(&ERTS_P_LINKS(port), port_lnk); proc_lnk = erts_link_internal_create(ERTS_LNK_TYPE_PORT, port->common.id); - if (!erts_proc_sig_send_link(NULL, pid, proc_lnk)) { + if (!erts_proc_sig_send_link(&port->common, port->common.id, + pid, proc_lnk)) { erts_link_tree_delete(&ERTS_P_LINKS(port), port_lnk); erts_link_internal_release(proc_lnk); erts_link_internal_release(port_lnk); @@ -1170,7 +1177,7 @@ erts_schedule_proc2port_signal(Process *c_p, * callers message queue to the end of the queue. * * NOTE: It is of vital importance that the caller - * immediately do a receive unconditionaly + * immediately do a receive unconditionally * waiting for the message with the reference; * otherwise, next receive will *not* work * as expected! @@ -1224,7 +1231,7 @@ send_badsig(Port *prt) { ERTS_CHK_NO_PROC_LOCKS; ERTS_LC_ASSERT(erts_get_scheduler_id()); ASSERT(is_internal_pid(connected)); - erts_proc_sig_send_exit(NULL, prt->common.id, connected, + erts_proc_sig_send_exit(&prt->common, prt->common.id, connected, am_badsig, NIL, 0); } /* send_badsig */ @@ -1637,7 +1644,7 @@ erts_port_output_async(Port *prt, Eterm from, Eterm list) ErlDrvSizeT ERTS_DECLARE_DUMMY(r); /* - * Apperently there exist code that write 1 byte to + * Apparently there exist code that write 1 byte to * much in buffer. Where it resides I don't know, but * we can live with one byte extra allocated... */ @@ -1971,7 +1978,7 @@ erts_port_output(Process *c_p, ErlDrvSizeT r; /* - * Apperently there exist code that write 1 byte to + * Apparently there exist code that write 1 byte to * much in buffer. Where it resides I don't know, but * we can live with one byte extra allocated... */ @@ -2344,7 +2351,8 @@ set_port_connected(int bang_op, if (created) { ErtsLink *olnk = erts_link_internal_create(ERTS_LNK_TYPE_PORT, prt->common.id); - if (!erts_proc_sig_send_link(NULL, connect, olnk)) { + if (!erts_proc_sig_send_link(&prt->common, prt->common.id, + connect, olnk)) { erts_link_tree_delete(&ERTS_P_LINKS(prt), lnk); erts_link_internal_release(lnk); erts_link_internal_release(olnk); @@ -2465,39 +2473,47 @@ erts_port_connect(Process *c_p, } static void -port_unlink_failure(Eterm port_id, ErtsSigUnlinkOp *sulnk) +port_unlink_failure(Port *prt, Eterm port_id, ErtsSigUnlinkOp *sulnk) { - erts_proc_sig_send_unlink_ack(NULL, port_id, sulnk); + erts_proc_sig_send_unlink_ack(prt ? &prt->common : NULL, port_id, sulnk); } static void port_unlink(Port *prt, erts_aint32_t state, ErtsSigUnlinkOp *sulnk) { - if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) - port_unlink_failure(prt->common.id, sulnk); - else { + if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) { + port_unlink_failure(prt, prt->common.id, sulnk); + } else { ErtsILink *ilnk; + ilnk = (ErtsILink *) erts_link_tree_lookup(ERTS_P_LINKS(prt), sulnk->from); + if (ilnk && !ilnk->unlinking) { if (IS_TRACED_FL(prt, F_TRACE_PORTS)) trace_port(prt, am_getting_unlinked, sulnk->from); erts_link_tree_delete(&ERTS_P_LINKS(prt), &ilnk->link); erts_link_internal_release(&ilnk->link); } - erts_proc_sig_send_unlink_ack(NULL, prt->common.id, sulnk); + + erts_proc_sig_send_unlink_ack(&prt->common, prt->common.id, sulnk); } } static int port_sig_unlink(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp) { - if (op == ERTS_PROC2PORT_SIG_EXEC) - port_unlink(prt, state, sigdp->u.unlink.sulnk); - else - port_unlink_failure(sigdp->u.unlink.port_id, sigdp->u.unlink.sulnk); - if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); + if (op == ERTS_PROC2PORT_SIG_EXEC) { + port_unlink(prt, state, sigdp->u.unlink.sulnk); + } else { + port_unlink_failure(prt, sigdp->u.unlink.port_id, + sigdp->u.unlink.sulnk); + } + + if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) { + port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); + } + return ERTS_PORT_REDS_UNLINK; } @@ -2522,7 +2538,7 @@ erts_port_unlink(Process *c_p, Port *prt, ErtsSigUnlinkOp *sulnk, Eterm *refp) BUMP_REDS(c_p, ERTS_PORT_REDS_UNLINK); return ERTS_PORT_OP_DONE; case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT: - port_unlink_failure(prt->common.id, sulnk); + port_unlink_failure(prt, prt->common.id, sulnk); return ERTS_PORT_OP_DROPPED; default: /* Schedule call instead... */ @@ -2622,17 +2638,17 @@ erts_port_unlink_ack(Process *c_p, Port *prt, ErtsSigUnlinkOp *sulnk) } static void -port_link_failure(Eterm port_id, ErtsLink *lnk) +port_link_failure(Port *port, Eterm port_id, ErtsLink *lnk) { - erts_proc_sig_send_link_exit(NULL, port_id, lnk, am_noproc, NIL); + erts_proc_sig_send_link_exit(&port->common, port_id, lnk, am_noproc, NIL); } static void port_link(Port *prt, erts_aint32_t state, ErtsLink *nlnk) { - if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) - port_link_failure(prt->common.id, nlnk); - else { + if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) { + port_link_failure(prt, prt->common.id, nlnk); + } else { ErtsLink *lnk; lnk = erts_link_tree_lookup_insert(&ERTS_P_LINKS(prt), nlnk); if (lnk) @@ -2645,12 +2661,16 @@ port_link(Port *prt, erts_aint32_t state, ErtsLink *nlnk) static int port_sig_link(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp) { - if (op == ERTS_PROC2PORT_SIG_EXEC) - port_link(prt, state, sigdp->u.link.lnk); - else - port_link_failure(sigdp->u.link.port_id, sigdp->u.link.lnk); - if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) - port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); + if (op == ERTS_PROC2PORT_SIG_EXEC) { + port_link(prt, state, sigdp->u.link.lnk); + } else { + port_link_failure(prt, sigdp->u.link.port_id, sigdp->u.link.lnk); + } + + if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY) { + port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt); + } + return ERTS_PORT_REDS_LINK; } @@ -2695,9 +2715,11 @@ erts_port_link(Process *c_p, Port *prt, ErtsLink *lnk, Eterm *refp) } static void -port_monitor_failure(Eterm port_id, ErtsMonitor *mon) +port_monitor_failure(Port *prt, Eterm port_id, ErtsMonitor *mon) { - erts_proc_sig_send_monitor_down(mon, am_noproc); + ASSERT(prt == NULL || prt->common.id == port_id); + erts_proc_sig_send_monitor_down(prt ? &prt->common : NULL, port_id, + mon, am_noproc); } /* Origin wants to monitor port Prt. State contains possible error, which has @@ -2707,9 +2729,10 @@ static void port_monitor(Port *prt, erts_aint32_t state, ErtsMonitor *mon) { ASSERT(prt); - if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) - port_monitor_failure(prt->common.id, mon); - else { + + if (state & ERTS_PORT_SFLGS_INVALID_LOOKUP) { + port_monitor_failure(prt, prt->common.id, mon); + } else { ASSERT(erts_monitor_is_target(mon)); erts_monitor_list_insert(&ERTS_P_LT_MONITORS(prt), mon); } @@ -2719,11 +2742,12 @@ static int port_sig_monitor(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigdp) { - if (op == ERTS_PROC2PORT_SIG_EXEC) + if (op == ERTS_PROC2PORT_SIG_EXEC) { port_monitor(prt, state, sigdp->u.monitor.mon); - else - port_monitor_failure(sigdp->u.monitor.port_id, - sigdp->u.monitor.mon); + } else { + port_monitor_failure(prt, sigdp->u.monitor.port_id, sigdp->u.monitor.mon); + } + return ERTS_PORT_REDS_MONITOR; } @@ -2852,7 +2876,7 @@ unlink_proc(Port *prt, Eterm pid) ilnk = (ErtsILink *) erts_link_tree_lookup(ERTS_P_LINKS(prt), pid); if (ilnk && !ilnk->unlinking) { - Uint64 id = erts_proc_sig_send_unlink(NULL, + Uint64 id = erts_proc_sig_send_unlink(&prt->common, prt->common.id, &ilnk->link); if (id != 0) @@ -3102,8 +3126,7 @@ void erts_lcnt_update_port_locks(int enable) { * Parameters: * bufsiz - The (maximum) size of the line buffer. */ -LineBuf *allocate_linebuf(bufsiz) -int bufsiz; +LineBuf *allocate_linebuf(int bufsiz) { int ovsiz = (bufsiz < LINEBUF_INITIAL) ? bufsiz : LINEBUF_INITIAL; LineBuf *lb = (LineBuf *) erts_alloc(ERTS_ALC_T_LINEBUF, @@ -3190,7 +3213,7 @@ static int flush_linebuf(LineBufContext *bp) * Returns: LINEBUF_EMPTY if there is no more data that can be * determined as a line (only part of a line left), LINEBUF_EOL if a whole * line could be delivered and LINEBUF_NOEOL if the buffer size has been - * exceeded. The data and the data length can be accesed through the + * exceeded. The data and the data length can be accessed through the * LINEBUF_DATA and the LINEBUF_DATALEN macros applied to the LineBufContext. * Parameters: * bp - A LineBufContext that is initialized with @@ -3304,7 +3327,7 @@ deliver_result(Port *prt, Eterm sender, Eterm pid, Eterm res) /* * Deliver a "read" message. - * hbuf -- byte that are always formated as a list + * hbuf -- byte that are always formatted as a list * hlen -- number of byte in header * buf -- data * len -- length of data @@ -3748,7 +3771,7 @@ terminate_port(Port *prt) if ((state & ERTS_PORT_SFLG_HALT) && (erts_atomic32_dec_read_nob(&erts_halt_progress) == 0)) { erts_port_release(prt); /* We will exit and never return */ - erts_flush_async_exit(erts_halt_code, ""); + erts_flush_exit(erts_halt_code, ""); } if (is_internal_port(send_closed_port_id)) deliver_result(NULL, send_closed_port_id, connected_id, am_closed); @@ -3761,17 +3784,19 @@ erts_terminate_port(Port *pp) } typedef struct { - Eterm port_id; + Port *port; Eterm reason; } ErtsPortExitContext; static int link_port_exit(ErtsLink *lnk, void *vpectxt, Sint reds) { ErtsPortExitContext *pectxt = vpectxt; + Port *port = pectxt->port; + if (((ErtsILink *) lnk)->unlinking) erts_link_release(lnk); else - erts_proc_sig_send_link_exit(NULL, pectxt->port_id, + erts_proc_sig_send_link_exit(&port->common, port->common.id, lnk, pectxt->reason, NIL); return 1; } @@ -3779,10 +3804,15 @@ static int link_port_exit(ErtsLink *lnk, void *vpectxt, Sint reds) static int monitor_port_exit(ErtsMonitor *mon, void *vpectxt, Sint reds) { ErtsPortExitContext *pectxt = vpectxt; - if (erts_monitor_is_target(mon)) - erts_proc_sig_send_monitor_down(mon, pectxt->reason); - else - erts_proc_sig_send_demonitor(mon); + Port *port = pectxt->port; + + if (erts_monitor_is_target(mon)) { + erts_proc_sig_send_monitor_down(&port->common, port->common.id, mon, + pectxt->reason); + } else { + erts_proc_sig_send_demonitor(&port->common, port->common.id, 0, mon); + } + return 1; } @@ -3863,8 +3893,8 @@ erts_deliver_port_exit(Port *prt, Eterm from, Eterm reason, int send_closed, if (prt->common.u.alive.reg != NULL) (void) erts_unregister_name(NULL, 0, prt, prt->common.u.alive.reg->name); - pectxt.port_id = prt->common.id; pectxt.reason = modified_reason; + pectxt.port = prt; if (state & ERTS_PORT_SFLG_DISTRIBUTION) { DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY); @@ -6012,18 +6042,24 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len) case ERL_DRV_TUPLE: { /* int */ int size = (int)ptr[0]; - Eterm* tp = erts_produce_heap(&factory, size+1, HEAP_EXTRA); + if (size == 0) { + mess = ERTS_GLOBAL_LIT_EMPTY_TUPLE; + ptr++; + break; + } else { + Eterm* tp = erts_produce_heap(&factory, size+1, HEAP_EXTRA); - *tp = make_arityval(size); - mess = make_tuple(tp); + *tp = make_arityval(size); + mess = make_tuple(tp); - tp += size; /* point at last element */ + tp += size; /* point at last element */ - while(size--) { - *tp-- = ESTACK_POP(stack); - } - ptr++; - break; + while(size--) { + *tp-- = ESTACK_POP(stack); + } + ptr++; + break; + } } case ERL_DRV_PID: /* pid argument */ @@ -6071,15 +6107,15 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len) Eterm* vp; flatmap_t *mp; Eterm* tp = erts_produce_heap(&factory, - 2*size + 1 + MAP_HEADER_FLATMAP_SZ, + 2*size + (size==0 ? 0 : 1) + MAP_HEADER_FLATMAP_SZ, HEAP_EXTRA); - - *tp = make_arityval(size); - - mp = (flatmap_t*) (tp + 1 + size); + if (size != 0) { + *tp = make_arityval(size); + } + mp = (flatmap_t*) (tp + (size==0 ? 0 : 1) + size); mp->thing_word = MAP_HEADER_FLATMAP; mp->size = size; - mp->keys = make_tuple(tp); + mp->keys = (size!= 0 ? make_tuple(tp) : ERTS_GLOBAL_LIT_EMPTY_TUPLE); mess = make_flatmap(mp); tp += size; /* point at last key */ @@ -6955,7 +6991,8 @@ static int do_driver_monitor_process(Port *prt, prt->common.id, process, NIL, THE_NON_VALUE); - if (!erts_proc_sig_send_monitor(&mdp->u.target, process)) { + if (!erts_proc_sig_send_monitor(&prt->common, prt->common.id, + &mdp->u.target, process)) { erts_monitor_release_both(mdp); return 1; } @@ -7004,7 +7041,8 @@ static int do_driver_demonitor_process(Port *prt, const ErlDrvMonitor *monitor) return 1; erts_monitor_tree_delete(&ERTS_P_MONITORS(prt), mon); - erts_proc_sig_send_demonitor(mon); + erts_proc_sig_send_demonitor(&prt->common, prt->common.id, 0, mon); + return 0; } diff --git a/erts/emulator/beam/jit/arm/beam_asm.hpp b/erts/emulator/beam/jit/arm/beam_asm.hpp new file mode 100644 index 000000000000..8ef609f4b2aa --- /dev/null +++ b/erts/emulator/beam/jit/arm/beam_asm.hpp @@ -0,0 +1,1620 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ASMJIT_ASMJIT_H_INCLUDED +# include +#endif + +#include + +extern "C" +{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "erl_vm.h" +#include "global.h" +#include "beam_catches.h" +#include "big.h" + +#include "beam_asm.h" +} + +#include "beam_jit_common.hpp" + +/* Is it safe to STP or LDP `Struct->Field1` and `Struct->Field2`? */ +#define ERTS_CT_ASSERT_FIELD_PAIR(Struct, Field1, Field2) \ + static_assert(std::is_standard_layout::value && \ + (offsetof(Struct, Field2) - offsetof(Struct, Field1) == \ + sizeof(((Struct *)nullptr)->Field1)) && \ + (sizeof(((Struct *)nullptr)->Field1) == \ + sizeof(((Struct *)nullptr)->Field2))) + +using namespace asmjit; + +struct BeamAssembler : public BeamAssemblerCommon { + BeamAssembler() : BeamAssemblerCommon(a) { + Error err = code.attach(&a); + ERTS_ASSERT(!err && "Failed to attach codeHolder"); + } + + BeamAssembler(const std::string &log) : BeamAssembler() { + if (erts_jit_asm_dump) { + setLogger(log + ".asm"); + } + } + +protected: + a64::Assembler a; + + /* Points at x_reg_array inside an ErtsSchedulerRegisters struct, allowing + * the aux_regs field to be addressed with an 8-bit displacement. */ + const arm::Gp scheduler_registers = a64::x19; + + const arm::Gp E = a64::x20; + const arm::Gp c_p = a64::x21; + const arm::Gp FCALLS = a64::x22; + const arm::Gp HTOP = a64::x23; + + /* Local copy of the active code index. + * + * This is set to ERTS_SAVE_CALLS_CODE_IX when save_calls is active, which + * routes us to a common handler routine that calls save_calls before + * jumping to the actual code. */ + const arm::Gp active_code_ix = a64::x24; + + /* X registers */ +#if defined(DEBUG) + /* + * To ensure that we thoroughly test flushing of caller-save X + * registers, define more caller-save X registers in a DEBUG + * build. + */ +# define ERTS_HIGHEST_CALLEE_SAVE_XREG 2 +# define ERTS_HIGHEST_CALLER_SAVE_XREG 5 + const arm::Gp XREG0 = a64::x25; + const arm::Gp XREG1 = a64::x26; + const arm::Gp XREG2 = a64::x27; + + /* + * Caller-save X registers. Must be flushed before calling C + * code. + */ + const arm::Gp XREG3 = a64::x15; + const arm::Gp XREG4 = a64::x16; + const arm::Gp XREG5 = a64::x17; +#else +# define ERTS_HIGHEST_CALLEE_SAVE_XREG 3 +# define ERTS_HIGHEST_CALLER_SAVE_XREG 5 + const arm::Gp XREG0 = a64::x25; + const arm::Gp XREG1 = a64::x26; + const arm::Gp XREG2 = a64::x27; + const arm::Gp XREG3 = a64::x28; + + /* + * Caller-save X registers. Must be flushed before calling C + * code. + */ + const arm::Gp XREG4 = a64::x15; + const arm::Gp XREG5 = a64::x16; +#endif + +#define ERTS_LOWEST_CALLEE_SAVE_XREG (0) +#define ERTS_LOWEST_CALLER_SAVE_XREG (ERTS_HIGHEST_CALLEE_SAVE_XREG + 1) + + static const int num_register_backed_xregs = 6; + const arm::Gp register_backed_xregs[num_register_backed_xregs] = + {XREG0, XREG1, XREG2, XREG3, XREG4, XREG5}; + +#ifdef ERTS_MSACC_EXTENDED_STATES + const arm::Mem erts_msacc_cache = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.erts_msacc_cache)); +#endif + + /* * * * * * * * * */ + const arm::Gp ZERO = a64::xzr; + + /* + * All of the following registers are caller-save. + * + * Note that ARG1 is also the register for the return value. + */ + const arm::Gp ARG1 = a64::x0; + const arm::Gp ARG2 = a64::x1; + const arm::Gp ARG3 = a64::x2; + const arm::Gp ARG4 = a64::x3; + const arm::Gp ARG5 = a64::x4; + const arm::Gp ARG6 = a64::x5; + const arm::Gp ARG7 = a64::x6; + const arm::Gp ARG8 = a64::x7; + + const arm::Gp TMP1 = a64::x8; + const arm::Gp TMP2 = a64::x9; + const arm::Gp TMP3 = a64::x10; + const arm::Gp TMP4 = a64::x11; + const arm::Gp TMP5 = a64::x12; + const arm::Gp TMP6 = a64::x13; + + /* + * Assume that SUPER_TMP will be destroyed by any helper function. + */ + const arm::Gp SUPER_TMP = a64::x14; + + /* + * Note that x18 is reserved on Apple platforms and must not be used. + */ + + /* Callee-saved floating-point registers. + * + * Note that only the bottom 64 bits of these (128-bit) registers are + * callee-save, so we cannot pack two floats into each register. */ + const arm::VecD FREG0 = a64::d8; + const arm::VecD FREG1 = a64::d9; + const arm::VecD FREG2 = a64::d10; + const arm::VecD FREG3 = a64::d11; + const arm::VecD FREG4 = a64::d12; + const arm::VecD FREG5 = a64::d13; + const arm::VecD FREG6 = a64::d14; + const arm::VecD FREG7 = a64::d15; + static const int num_register_backed_fregs = 8; + const arm::VecD register_backed_fregs[num_register_backed_fregs] = + {FREG0, FREG1, FREG2, FREG3, FREG4, FREG5, FREG6, FREG7}; + + const arm::Mem TMP_MEM1q = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.TMP_MEM[0])); + const arm::Mem TMP_MEM2q = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.TMP_MEM[1])); + const arm::Mem TMP_MEM3q = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.TMP_MEM[2])); + const arm::Mem TMP_MEM4q = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.TMP_MEM[3])); + const arm::Mem TMP_MEM5q = getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, aux_regs.d.TMP_MEM[4])); + + /* Fill registers with undefined contents to find bugs faster. + * A boxed value is most likely to cause noticeable trouble. */ + static const Uint64 bad_boxed_ptr = 0xcafebad0000002UL; + + /* Number of highest element displacement for L/SDP and L/STR. */ + static const size_t MAX_LDP_STP_DISPLACEMENT = 0x3F; + static const size_t MAX_LDR_STR_DISPLACEMENT = 0xFFF; + static const size_t MAX_LDUR_STUR_DISPLACEMENT = 0xFF; + + /* Constants for "alternate flag state" operands, which are distinct from + * `arm::CondCode::xyz`. Mainly used in `CCMP` instructions. */ + enum NZCV : int { + kNF = 8, + kSigned = kNF, + + kZF = 4, + kEqual = kZF, + + kCF = 2, + kCarry = kCF, + + kVF = 1, + kOverflow = kVF, + + kNone = 0 + }; + +#ifdef JIT_HARD_DEBUG + constexpr arm::Mem getInitialSPRef() const { + int base = offsetof(ErtsSchedulerRegisters, initial_sp); + + return getSchedulerRegRef(base); + } +#endif + + constexpr arm::Mem getSchedulerRegRef(int offset) const { + ASSERT((offset & (sizeof(Eterm) - 1)) == 0); + return arm::Mem(scheduler_registers, offset); + } + + constexpr arm::Mem getFRef(int index, size_t size = sizeof(UWord)) const { + int base = offsetof(ErtsSchedulerRegisters, f_reg_array.d); + int offset = index * sizeof(FloatDef); + + ASSERT(0 <= index && index <= 1023); + return getSchedulerRegRef(base + offset); + } + + constexpr arm::Mem getXRef(int index) const { + int base = offsetof(ErtsSchedulerRegisters, x_reg_array.d); + int offset = index * sizeof(Eterm); + + ASSERT(0 <= index && index < ERTS_X_REGS_ALLOCATED); + return getSchedulerRegRef(base + offset); + } + + constexpr arm::Mem getYRef(int index) const { + ASSERT(0 <= index && index <= 1023); + + return arm::Mem(E, index * sizeof(Eterm)); + } + + constexpr arm::Mem getCARRef(arm::Gp Src) const { + return arm::Mem(Src, -TAG_PRIMARY_LIST); + } + + constexpr arm::Mem getCDRRef(arm::Gp Src, + size_t size = sizeof(UWord)) const { + return arm::Mem(Src, -TAG_PRIMARY_LIST + sizeof(Eterm)); + } + + /* Loads the X register array into `to`. Remember to sync the registers in + * `emit_enter_runtime`. */ + void load_x_reg_array(arm::Gp to) { + int offset = offsetof(ErtsSchedulerRegisters, x_reg_array.d); + + lea(to, getSchedulerRegRef(offset)); + } + + void load_erl_bits_state(arm::Gp to) { + int offset = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state); + + lea(to, getSchedulerRegRef(offset)); + } + + void emit_assert_redzone_unused() { +#ifdef JIT_HARD_DEBUG + const int REDZONE_BYTES = S_REDZONE * sizeof(Eterm); + Label next = a.newLabel(); + + a.sub(SUPER_TMP, E, imm(REDZONE_BYTES)); + a.cmp(HTOP, SUPER_TMP); + + a.b_ls(next); + a.udf(0xbeef); + + a.bind(next); +#endif + } + + /* + * Calls an Erlang function. + */ + template + void erlang_call(Any Target) { + emit_assert_redzone_unused(); + aligned_call(Target); + } + + void branch(arm::Mem target) { + a.ldr(SUPER_TMP, target); + a.br(SUPER_TMP); + } + + template + void aligned_call(FuncPtr(*target)) { + mov_imm(SUPER_TMP, target); + a.blr(SUPER_TMP); + } + + void aligned_call(Label target) { + a.bl(target); + } + + void aligned_call(arm::Gp target) { + a.blr(target); + } + + /* Calls the given address. In DEBUG builds, make + * sure that the CP is aligned. */ + template + void aligned_call(OperandType target) { + ERTS_CT_ASSERT(_CPMASK == 3); + ASSERT(is_CP(a.offset())); + a.ldr(TMP1, target); + a.blr(TMP1); + } + + void runtime_call(arm::Gp func, unsigned args) { + ASSERT(args < 5); + a.blr(func); + } + + template + struct function_arity; + template + struct function_arity + : std::integral_constant {}; + + template + void runtime_call(T(*func)) { + static_assert(expected_arity == function_arity()); + + a.mov(TMP1, func); + a.blr(TMP1); + } + + /* Explicitly position-independent absolute jump, for use in fragments that + * need to be memcpy'd for performance reasons (e.g. NIF stubs) */ + template + void pic_jmp(T(*addr)) { + a.mov(SUPER_TMP, addr); + a.br(SUPER_TMP); + } + + constexpr arm::Mem getArgRef(const ArgRegister &arg) const { + if (arg.isXRegister()) { + return getXRef(arg.as().get()); + } else if (arg.isYRegister()) { + return getYRef(arg.as().get()); + } + + return getFRef(arg.as().get()); + } + + /* Returns the current code address for the `Export` or `ErlFunEntry` in + * `Src`. + * + * Export tracing, save_calls, etc are implemented by shared fragments that + * assume that the respective entry is in ARG1, so we have to copy it over + * if it isn't already. */ + arm::Mem emit_setup_dispatchable_call(const arm::Gp &Src) { + return emit_setup_dispatchable_call(Src, active_code_ix); + } + + arm::Mem emit_setup_dispatchable_call(const arm::Gp &Src, + const arm::Gp &CodeIndex) { + if (ARG1 != Src) { + a.mov(ARG1, Src); + } + + ERTS_CT_ASSERT(offsetof(ErlFunEntry, dispatch) == 0); + ERTS_CT_ASSERT(offsetof(Export, dispatch) == 0); + ERTS_CT_ASSERT(offsetof(ErtsDispatchable, addresses) == 0); + + return arm::Mem(ARG1, CodeIndex, arm::lsl(3)); + } + + /* Prefer `eHeapAlloc` over `eStack | eHeap` when calling + * functions in the runtime system that allocate heap + * memory (`HAlloc`, heap factories, etc). + * + * Prefer `eHeapOnlyAlloc` over `eHeapAlloc` for functions + * that assume there's already a certain amount of free + * space on the heap, such as those using `HeapOnlyAlloc` + * or similar. It's slightly cheaper in release builds, + * and in debug builds it updates `eStack` to ensure that + * we can make heap size assertions. */ + enum Update : int { + eStack = (1 << 0), + eHeap = (1 << 1), + eReductions = (1 << 2), + eCodeIndex = (1 << 3), + eXRegs = (1 << 4), + eHeapAlloc = Update::eHeap | Update::eStack, +#ifndef DEBUG + eHeapOnlyAlloc = Update::eHeap, +#else + eHeapOnlyAlloc = Update::eHeapAlloc +#endif + }; + + void emit_enter_erlang_frame() { + a.str(a64::x30, arm::Mem(E, -8).pre()); + } + + void emit_leave_erlang_frame() { + a.ldr(a64::x30, arm::Mem(E).post(8)); + } + + void emit_enter_runtime_frame() { + a.stp(a64::x29, a64::x30, arm::Mem(a64::sp, -16).pre()); + a.mov(a64::x29, a64::sp); + } + + void emit_leave_runtime_frame() { + a.mov(a64::sp, a64::x29); + a.ldp(a64::x29, a64::x30, arm::Mem(a64::sp).post(16)); + } + + /* We keep the first six X registers in machine registers. Some of those + * registers are callee-saved and some are caller-saved. + * + * We ignore the ones above `live` to reduce the save/restore traffic on + * these registers. It's enough for this figure to be at least as high as + * the number of actually live registers, and we default to all six + * registers when we don't know the exact number. + * + * Furthermore, we only save the callee-save registers when told to sync + * all registers with the `Update::eXRegs` flag, as this is very rarely + * needed. */ + + template + void emit_enter_runtime(int live = num_register_backed_xregs) { + ERTS_CT_ASSERT((Spec & (Update::eReductions | Update::eStack | + Update::eHeap | Update::eXRegs)) == Spec); + + if ((Spec & Update::eStack) && (Spec & Update::eHeap)) { + /* Store HTOP and E in one go. */ + ERTS_CT_ASSERT_FIELD_PAIR(Process, htop, stop); + a.stp(HTOP, E, arm::Mem(c_p, offsetof(Process, htop))); + } else if (Spec & Update::eStack) { + a.str(E, arm::Mem(c_p, offsetof(Process, stop))); + } else if (Spec & Update::eHeap) { + a.str(HTOP, arm::Mem(c_p, offsetof(Process, htop))); + } + + if (Spec & Update::eReductions) { + a.str(FCALLS, arm::Mem(c_p, offsetof(Process, fcalls))); + } + + /* Save register-backed X registers to the X register array when + * needed. The backing registers must NOT be used afterwards. + * + * In a DEBUG build, the backing X registers will be overwritten with + * garbage values. */ + if (live > 0) { + int num_to_save = MIN(live, ERTS_HIGHEST_CALLER_SAVE_XREG + 1); + int i; + + if (Spec & Update::eXRegs) { + i = ERTS_LOWEST_CALLEE_SAVE_XREG; + } else { + /* If we don't need to sync the X register array, then we can + * get away with saving only the fragile X registers. */ + i = ERTS_LOWEST_CALLER_SAVE_XREG; + } + +#ifdef DEBUG + /* Destroy the saved X registers to find bugs sooner.*/ + if (i < num_to_save) { + mov_imm(SUPER_TMP, bad_boxed_ptr + 0x20 + (Spec << 8)); + } +#endif + + while (i < num_to_save - 1) { + a.stp(register_backed_xregs[i + 0], + register_backed_xregs[i + 1], + getXRef(i)); + +#ifdef DEBUG + a.mov(register_backed_xregs[i + 0], SUPER_TMP); + a.mov(register_backed_xregs[i + 1], SUPER_TMP); +#endif + + i += 2; + } + + if (i < num_to_save) { + a.str(register_backed_xregs[i], getXRef(i)); + +#ifdef DEBUG + a.mov(register_backed_xregs[i], SUPER_TMP); +#endif + } + } + } + + template + void emit_leave_runtime(int live = num_register_backed_xregs) { + ERTS_CT_ASSERT( + (Spec & (Update::eReductions | Update::eStack | Update::eHeap | + Update::eXRegs | Update::eCodeIndex)) == Spec); + + if ((Spec & Update::eStack) && (Spec & Update::eHeap)) { + /* Load HTOP and E in one go. */ + ERTS_CT_ASSERT_FIELD_PAIR(Process, htop, stop); + a.ldp(HTOP, E, arm::Mem(c_p, offsetof(Process, htop))); + } else if (Spec & Update::eHeap) { + a.ldr(HTOP, arm::Mem(c_p, offsetof(Process, htop))); + } else if (Spec & Update::eStack) { + a.ldr(E, arm::Mem(c_p, offsetof(Process, stop))); + } + + if (Spec & Update::eReductions) { + a.ldr(FCALLS, arm::Mem(c_p, offsetof(Process, fcalls))); + } + + if (Spec & Update::eCodeIndex) { + /* Updates the local copy of the active code index, retaining + * save_calls if active. */ + mov_imm(SUPER_TMP, &the_active_code_index); + a.ldr(SUPER_TMP.w(), arm::Mem(SUPER_TMP)); + a.cmp(active_code_ix, imm(ERTS_SAVE_CALLS_CODE_IX)); + a.csel(active_code_ix, + active_code_ix, + SUPER_TMP, + arm::CondCode::kEQ); + } + + /* Restore register-backed X registers from the X register array when + * needed. The register array must NOT be used afterwards. + * + * In a DEBUG build, the register array will be overwritten with + * garbage values. */ + if (live > 0) { + int num_to_restore = MIN(live, ERTS_HIGHEST_CALLER_SAVE_XREG + 1); + int i; + + if (Spec & Update::eXRegs) { + i = ERTS_LOWEST_CALLEE_SAVE_XREG; + } else { + /* If we don't need to sync the X register array, then we can + * get away with loading only the fragile X registers. */ + i = ERTS_LOWEST_CALLER_SAVE_XREG; + } + +#ifdef DEBUG + /* Destroy the restored X registers to find bugs sooner.*/ + if (i < num_to_restore) { + mov_imm(SUPER_TMP, bad_boxed_ptr + 0x80 + (Spec << 8)); + } +#endif + + while (i < num_to_restore - 1) { + a.ldp(register_backed_xregs[i], + register_backed_xregs[i + 1], + getXRef(i)); + +#ifdef DEBUG + a.stp(SUPER_TMP, SUPER_TMP, getXRef(i)); +#endif + + i += 2; + } + + if (i < num_to_restore) { + a.ldr(register_backed_xregs[i], getXRef(i)); + +#ifdef DEBUG + a.str(SUPER_TMP, getXRef(i)); +#endif + } + } + } + + void emit_is_boxed(Label Fail, arm::Gp Src) { + const int bitNumber = 0; + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED == + (1 << bitNumber)); + a.tbnz(Src, imm(bitNumber), Fail); + } + + void emit_is_not_boxed(Label Fail, arm::Gp Src) { + const int bitNumber = 0; + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED == + (1 << bitNumber)); + a.tbz(Src, imm(bitNumber), Fail); + } + + arm::Gp emit_ptr_val(arm::Gp Dst, arm::Gp Src) { +#if !defined(TAG_LITERAL_PTR) + return Src; +#else + /* We intentionally skip TAG_PTR_MASK__ here, as we want to use + * plain `emit_boxed_val` when we know the argument can't be a literal, + * such as in bit-syntax matching. + * + * This comes at very little cost as `emit_boxed_val` nearly always has + * a displacement. */ + a.and_(Dst, Src, imm(~TAG_LITERAL_PTR)); + return Dst; +#endif + } + + void emit_untag_ptr(arm::Gp Dst, arm::Gp Src) { + a.and_(Dst, Src, imm(~TAG_PTR_MASK__)); + } + + constexpr arm::Mem emit_boxed_val(arm::Gp Src, int32_t bytes = 0) const { + ASSERT(bytes % sizeof(Eterm) == 0); + return arm::Mem(Src, bytes - TAG_PRIMARY_BOXED); + } + + void emit_branch_if_not_value(arm::Gp reg, Label lbl) { + emit_branch_if_eq(reg, THE_NON_VALUE, lbl); + } + + void emit_branch_if_value(arm::Gp reg, Label lbl) { + emit_branch_if_ne(reg, THE_NON_VALUE, lbl); + } + + void emit_branch_if_eq(arm::Gp reg, Uint value, Label lbl) { + if (value == 0) { + a.cbz(reg, lbl); + } else { + a.cmp(reg, imm(value)); + a.b_eq(lbl); + } + } + + void emit_branch_if_ne(arm::Gp reg, Uint value, Label lbl) { + if (value == 0) { + a.cbnz(reg, lbl); + } else { + a.cmp(reg, imm(value)); + a.b_ne(lbl); + } + } + + /* Set the Z flag if Reg1 and Reg2 are both immediates. */ + void emit_are_both_immediate(arm::Gp Reg1, arm::Gp Reg2) { + ERTS_CT_ASSERT(TAG_PRIMARY_IMMED1 == _TAG_PRIMARY_MASK); + a.and_(SUPER_TMP, Reg1, Reg2); + a.and_(SUPER_TMP, SUPER_TMP, imm(_TAG_PRIMARY_MASK)); + a.cmp(SUPER_TMP, imm(TAG_PRIMARY_IMMED1)); + } + + /* Set the Z flag if Reg1 and Reg2 are definitely not equal based + * on their tags alone. (They may still be equal if both are + * immediates and all other bits are equal too.) */ + void emit_is_unequal_based_on_tags(arm::Gp Reg1, arm::Gp Reg2) { + ERTS_CT_ASSERT(TAG_PRIMARY_IMMED1 == _TAG_PRIMARY_MASK); + ERTS_CT_ASSERT((TAG_PRIMARY_LIST | TAG_PRIMARY_BOXED) == + TAG_PRIMARY_IMMED1); + a.orr(SUPER_TMP, Reg1, Reg2); + a.and_(SUPER_TMP, SUPER_TMP, imm(_TAG_PRIMARY_MASK)); + + /* + * SUPER_TMP will be now be TAG_PRIMARY_IMMED1 if either + * one or both registers are immediates, or if one register + * is a list and the other a boxed. + */ + a.cmp(SUPER_TMP, imm(TAG_PRIMARY_IMMED1)); + } + + template + void mov_imm(arm::Gp to, T value) { + static_assert(std::is_integral::value || std::is_pointer::value); + if (value) { + a.mov(to, imm(value)); + } else { + a.mov(to, ZERO); + } + } + + void mov_imm(arm::Gp to, std::nullptr_t value) { + (void)value; + mov_imm(to, 0); + } + + void sub(arm::Gp to, arm::Gp src, int64_t val) { + if (val < 0) { + add(to, src, -val); + } else if (val == 0 && to != src) { + a.mov(to, src); + } else if (val < (1 << 24)) { + if (val & 0xFFF) { + a.sub(to, src, imm(val & 0xFFF)); + src = to; + } + + if (val & 0xFFF000) { + a.sub(to, src, imm(val & 0xFFF000)); + } + } else { + mov_imm(SUPER_TMP, val); + a.sub(to, src, SUPER_TMP); + } + } + + void add(arm::Gp to, arm::Gp src, int64_t val) { + if (val < 0) { + sub(to, src, -val); + } else if (val == 0 && to != src) { + a.mov(to, src); + } else if (val < (1 << 24)) { + if (val & 0xFFF) { + a.add(to, src, imm(val & 0xFFF)); + src = to; + } + + if (val & 0xFFF000) { + a.add(to, src, imm(val & 0xFFF000)); + } + } else { + mov_imm(SUPER_TMP, val); + a.add(to, src, SUPER_TMP); + } + } + + void subs(arm::Gp to, arm::Gp src, int64_t val) { + if (Support::isUInt12(val)) { + a.subs(to, src, imm(val)); + } else if (Support::isUInt12(-val)) { + a.adds(to, src, imm(-val)); + } else { + mov_imm(SUPER_TMP, val); + a.subs(to, src, SUPER_TMP); + } + } + + void cmp(arm::Gp src, int64_t val) { + if (Support::isUInt12(val)) { + a.cmp(src, imm(val)); + } else if (Support::isUInt12(-val)) { + a.cmn(src, imm(-val)); + } else if (src.isGpW()) { + mov_imm(SUPER_TMP.w(), val); + a.cmp(src, SUPER_TMP.w()); + } else { + ERTS_ASSERT(src.isGpX()); + mov_imm(SUPER_TMP, val); + a.cmp(src, SUPER_TMP); + } + } + + void ldur(arm::Gp reg, arm::Mem mem) { + safe_9bit_imm(a64::Inst::kIdLdur, reg, mem); + } + + void stur(arm::Gp reg, arm::Mem mem) { + safe_9bit_imm(a64::Inst::kIdStur, reg, mem); + } + + void safe_9bit_imm(uint32_t instId, arm::Gp reg, arm::Mem mem) { + int64_t offset = mem.offset(); + + ASSERT(mem.hasBaseReg() && !mem.hasIndex()); + + if (Support::isInt9(offset)) { + a.emit(instId, reg, mem); + } else { + lea(SUPER_TMP, mem); + a.emit(instId, reg, arm::Mem(SUPER_TMP)); + } + } + + /* + * ARM has no LEA instruction. Implement our own to enable us + * to use helpers based on getSchedulerRegRef() that return an + * arm::Mem class. + */ + void lea(arm::Gp to, arm::Mem mem) { + int64_t offset = mem.offset(); + + ASSERT(mem.hasBaseReg() && !mem.hasIndex()); + + if (offset == 0) { + a.mov(to, arm::GpX(mem.baseId())); + } else { + add(to, arm::GpX(mem.baseId()), offset); + } + } +}; + +#include "beam_asm_global.hpp" + +class BeamModuleAssembler : public BeamAssembler, + public BeamModuleAssemblerCommon { + BeamGlobalAssembler *ga; + + /* Sequence number used to create unique named labels by + * resolve_label(). Only used when assembly output has been + * requested. */ + long labelSeq = 0; + + /* Save the last PC for an error. */ + size_t last_error_offset = 0; + + static constexpr ptrdiff_t STUB_CHECK_INTERVAL = 4 << 10; + size_t last_stub_check_offset = 0; + + enum Displacement : size_t { + /* Pessimistic estimate for helper functions, where we don't know the + * branch displacement or whether it will be used near label + * resolution. + * + * Note that we subtract the size of one instruction to handle + * backward displacements. */ + dispUnknown = (32 << 10) - sizeof(Uint32) - STUB_CHECK_INTERVAL, + + /* +- 32KB: `tbz`, `tbnz`, `ldr` of 8-byte literal. */ + disp32K = (32 << 10) - sizeof(Uint32), + + /* +- 1MB: `adr`, `b.cond`, `cb.cond` */ + disp1MB = (1 << 20) - sizeof(Uint32), + + /* +- 128MB: `b`, `blr` */ + disp128MB = (128 << 20) - sizeof(Uint32), + + dispMin = dispUnknown, + dispMax = disp128MB + }; + + static_assert(dispMin <= dispUnknown && dispMax >= disp128MB); + static_assert(STUB_CHECK_INTERVAL < dispMin / 2); + + struct Veneer { + ssize_t latestOffset; + Label anchor; + + Label target; + + constexpr bool operator>(const Veneer &other) const { + return latestOffset > other.latestOffset; + } + }; + + struct Constant { + ssize_t latestOffset; + Label anchor; + + ArgVal value; + + constexpr bool operator>(const Constant &other) const { + return latestOffset > other.latestOffset; + } + }; + + /* ArgVal -> Constant + * + * `_pending_constants` points directly into this container, which is + * documented to be safe as long as we only insert elements. */ + std::unordered_multimap _constants; + + /* Label::id() -> Veneer + * + * `_pending_veneers` points directly into this container. */ + std::unordered_multimap _veneers; + + template + using PendingStubs = + std::priority_queue, + std::deque>, + std::greater>; + + /* All pending stubs, segregated by type and sorted by `latestOffset` in + * ascending order. + * + * We use separate queues to avoid interleaving them, as they have + * different sizes and alignment requirements. */ + PendingStubs _pending_constants; + PendingStubs _pending_veneers; + + /* Maps code pointers to thunks that jump to them, letting us treat global + * fragments as if they were local. */ + std::unordered_map _dispatchTable; + + /* Skip unnecessary moves in load_source(), load_sources(), and + * mov_arg(). Don't use these variables directly. */ + size_t last_destination_offset = 0; + arm::Gp last_destination_from1, last_destination_from2; + arm::Mem last_destination_to1, last_destination_to2; + + /* Private helper. */ + void preserve__cache(arm::Gp dst) { + last_destination_offset = a.offset(); + invalidate_cache(dst); + } + + /* Works as the STR instruction, but also updates the cache. */ + void str_cache(arm::Gp src, arm::Mem dst) { + if (a.offset() == last_destination_offset && + dst != last_destination_to1) { + /* Something is already cached in the first slot. Use the + * second slot. */ + a.str(src, dst); + last_destination_offset = a.offset(); + last_destination_to2 = dst; + last_destination_from2 = src; + } else { + /* Nothing cached yet, or the first slot has the same + * memory address as we will store into. Use the first + * slot and invalidate the second slot. */ + a.str(src, dst); + last_destination_offset = a.offset(); + last_destination_to1 = dst; + last_destination_from1 = src; + last_destination_to2 = arm::Mem(); + } + } + + /* Works as the STP instruction, but also updates the cache. */ + void stp_cache(arm::Gp src1, arm::Gp src2, arm::Mem dst) { + safe_stp(src1, src2, dst); + last_destination_offset = a.offset(); + last_destination_to1 = dst; + last_destination_from1 = src1; + last_destination_to2 = + arm::Mem(arm::GpX(dst.baseId()), dst.offset() + 8); + last_destination_from2 = src2; + } + + void invalidate_cache(arm::Gp dst) { + if (dst == last_destination_from1) { + last_destination_to1 = arm::Mem(); + last_destination_from1 = arm::Gp(); + } + if (dst == last_destination_from2) { + last_destination_to2 = arm::Mem(); + last_destination_from2 = arm::Gp(); + } + } + + /* Works like LDR, but looks in the cache first. */ + void ldr_cached(arm::Gp dst, arm::Mem mem) { + if (a.offset() == last_destination_offset) { + arm::Gp cached_reg; + if (mem == last_destination_to1) { + cached_reg = last_destination_from1; + } else if (mem == last_destination_to2) { + cached_reg = last_destination_from2; + } + + if (cached_reg.isValid()) { + /* This memory location is cached. */ + if (cached_reg != dst) { + comment("simplified fetching of BEAM register"); + a.mov(dst, cached_reg); + preserve__cache(dst); + } else { + comment("skipped fetching of BEAM register"); + invalidate_cache(dst); + } + } else { + /* Not cached. Load and preserve the cache. */ + a.ldr(dst, mem); + preserve__cache(dst); + } + } else { + /* The cache is invalid. */ + a.ldr(dst, mem); + } + } + + void mov_preserve_cache(arm::VecD dst, arm::VecD src) { + a.mov(dst, src); + } + + void mov_preserve_cache(arm::Gp dst, arm::Gp src) { + if (a.offset() == last_destination_offset) { + a.mov(dst, src); + preserve__cache(dst); + } else { + a.mov(dst, src); + } + } + + void mov_imm_preserve_cache(arm::Gp dst, UWord value) { + if (a.offset() == last_destination_offset) { + mov_imm(dst, value); + preserve__cache(dst); + } else { + mov_imm(dst, value); + } + } + +public: + BeamModuleAssembler(BeamGlobalAssembler *ga, + Eterm mod, + int num_labels, + const BeamFile *file = NULL); + BeamModuleAssembler(BeamGlobalAssembler *ga, + Eterm mod, + int num_labels, + int num_functions, + const BeamFile *file = NULL); + + bool emit(unsigned op, const Span &args); + + void codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr, + const BeamCodeHeader *in_hdr, + const BeamCodeHeader **out_exec_hdr, + BeamCodeHeader **out_rw_hdr); + + void codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr); + + void codegen(char *buff, size_t len); + + void register_metadata(const BeamCodeHeader *header); + + ErtsCodePtr getCode(unsigned label); + ErtsCodePtr getLambda(unsigned index); + + void *getCode(Label label) { + return BeamAssembler::getCode(label); + } + + byte *getCode(char *labelName) { + return BeamAssembler::getCode(labelName); + } + + void embed_vararg_rodata(const Span &args, a64::Gp reg); + + unsigned getCodeSize() { + ASSERT(code.hasBaseAddress()); + return code.codeSize(); + } + + void copyCodeHeader(BeamCodeHeader *hdr); + BeamCodeHeader *getCodeHeader(void); + const ErtsCodeInfo *getOnLoad(void); + + unsigned patchCatches(char *rw_base); + void patchLambda(char *rw_base, unsigned index, const ErlFunEntry *fe); + void patchLiteral(char *rw_base, unsigned index, Eterm lit); + void patchImport(char *rw_base, unsigned index, const Export *import); + void patchStrings(char *rw_base, const byte *string); + +protected: + void emit_gc_test(const ArgWord &Stack, + const ArgWord &Heap, + const ArgWord &Live); + void emit_gc_test_preserve(const ArgWord &Need, + const ArgWord &Live, + const ArgSource &Preserve, + arm::Gp preserve_reg); + + arm::Mem emit_variable_apply(bool includeI); + arm::Mem emit_fixed_apply(const ArgWord &arity, bool includeI); + + arm::Gp emit_call_fun(bool skip_box_test = false, + bool skip_fun_test = false, + bool skip_arity_test = false); + + void emit_is_boxed(Label Fail, arm::Gp Src) { + BeamAssembler::emit_is_boxed(Fail, Src); + } + + void emit_is_boxed(Label Fail, const ArgVal &Arg, arm::Gp Src) { + if (always_one_of(Arg)) { + comment("skipped box test since argument is always boxed"); + return; + } + + BeamAssembler::emit_is_boxed(Fail, Src); + } + + /* Copies `count` words from the address at `from`, to the address at `to`. + * + * Clobbers v30 and v31. */ + void emit_copy_words_increment(arm::Gp from, arm::Gp to, size_t count); + + void emit_get_list(const arm::Gp boxed_ptr, + const ArgRegister &Hd, + const ArgRegister &Tl); + + void emit_add_sub_types(bool is_small_result, + const ArgSource &LHS, + const a64::Gp lhs_reg, + const ArgSource &RHS, + const a64::Gp rhs_reg, + const Label next); + + void emit_are_both_small(const ArgSource &LHS, + const a64::Gp lhs_reg, + const ArgSource &RHS, + const a64::Gp rhs_reg, + const Label next); + + void emit_div_rem(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ErtsCodeMFA *error_mfa, + const ArgRegister &Quotient, + const ArgRegister &Remainder, + bool need_div, + bool need_rem); + + void emit_i_bif(const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst); + + void emit_error(int code); + void emit_error(int reason, const ArgSource &Src); + + int emit_bs_get_field_size(const ArgSource &Size, + int unit, + Label Fail, + const arm::Gp &out); + + void emit_bs_get_utf8(const ArgRegister &Ctx, const ArgLabel &Fail); + void emit_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags); + void update_bin_state(arm::Gp bin_offset, + Sint bit_offset, + Sint size, + arm::Gp size_reg); + void set_zero(Sint effectiveSize); + void emit_construct_utf8(const ArgVal &Src, + Sint bit_offset, + bool is_byte_aligned); + + void emit_read_bits(Uint bits, + const arm::Gp bin_offset, + const arm::Gp bin_base, + const arm::Gp bitdata); + + void emit_extract_integer(const arm::Gp bitdata, + Uint flags, + Uint bits, + const ArgRegister &Dst); + + void emit_extract_binary(const arm::Gp bitdata, + Uint bits, + const ArgRegister &Dst); + + UWord bs_get_flags(const ArgVal &val); + + void emit_raise_exception(); + void emit_raise_exception(const ErtsCodeMFA *exp); + void emit_raise_exception(Label I, const ErtsCodeMFA *exp); + + void emit_validate(const ArgWord &Arity); + void emit_bs_skip_bits(const ArgLabel &Fail, const ArgRegister &Ctx); + + void emit_linear_search(arm::Gp val, Label fail, const Span &args); + + void emit_float_instr(uint32_t instId, + const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst); + + void emit_validate_unicode(Label next, Label fail, arm::Gp value); + + void ubif_comment(const ArgWord &Bif); + + void emit_cmp_immed_to_bool(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst); + + void emit_cond_to_bool(arm::CondCode cc, const ArgRegister &Dst); + void emit_bif_is_ge_lt(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst); + void emit_bif_min_max(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst); + + void emit_proc_lc_unrequire(void); + void emit_proc_lc_require(void); + + void emit_nyi(const char *msg); + void emit_nyi(void); + + /* Returns a vector of the untagged and rebased `args`. The adjusted + * `comparand` is stored in ARG1. */ + const std::vector emit_select_untag(const ArgSource &Src, + const Span &args, + a64::Gp comparand, + Label fail, + UWord base, + int shift); + + void emit_binsearch_nodes(arm::Gp reg, + size_t Left, + size_t Right, + Label fail, + const Span &args); + + bool emit_optimized_three_way_select(arm::Gp reg, + Label fail, + const Span &args); + +#ifdef DEBUG + void emit_tuple_assertion(const ArgSource &Src, arm::Gp tuple_reg); +#endif + +#include "beamasm_protos.h" + + /* Resolves a BEAM label. + * + * When the branch type is not `dispUnknown`, this must be used + * _IMMEDIATELY BEFORE_ the instruction that the label is used in. */ + const Label &resolve_beam_label(const ArgLabel &Label, + enum Displacement disp); + const Label &resolve_label(const Label &target, + enum Displacement disp, + const char *name = nullptr); + + /* Resolves a shared fragment, creating a trampoline that loads the + * appropriate address before jumping there. + * + * When the branch type is not `dispUnknown`, this must be used + * _IMMEDIATELY BEFORE_ the instruction that the label is used in. */ + const Label &resolve_fragment(void (*fragment)(), enum Displacement disp); + + /* Embeds a constant argument and returns its address. All kinds of + * constants are accepted, including labels and export entries. + * + * When the branch type is not `dispUnknown`, this must be used + * _IMMEDIATELY BEFORE_ the instruction that the label is used in. */ + arm::Mem embed_constant(const ArgVal &value, enum Displacement disp); + + /* Convenience wrapper for embedding raw pointers or immediates. */ + template::value || + std::is_pointer::value, + bool> = true> + arm::Mem embed_constant(T data, enum Displacement disp) { + return embed_constant(ArgWord((UWord)data), disp); + } + + /* Binds a label and all related veneers that are within reach of it. */ + void bind_veneer_target(const Label &target); + + void emit_constant(const Constant &constant); + void emit_veneer(const Veneer &veneer); + + /* Unconditionally emits all veneers and constants that are due within + * `range` bytes. */ + void flush_pending_stubs(size_t range); + + /* Emits pending veneers when appropriate. Must be called at least once + * every `STUB_CHECK_INTERVAL` bytes for veneers and constants to work. */ + void check_pending_stubs(); + + /* Calls the given shared fragment, ensuring that the redzone is unused and + * that the return address forms a valid CP. */ + template + void fragment_call(Any target) { + emit_assert_redzone_unused(); + +#if defined(JIT_HARD_DEBUG) + /* Verify that the stack has not grown. */ + Label next = a.newLabel(); + a.ldr(SUPER_TMP, getInitialSPRef()); + a.cmp(a64::sp, SUPER_TMP); + a.b_eq(next); + a.udf(0xdead); + a.bind(next); +#endif + + a.bl(resolve_fragment((void (*)())target, disp128MB)); + } + + template + struct function_arity; + template + struct function_arity + : std::integral_constant {}; + + template + void runtime_call(T(*func)) { + static_assert(expected_arity == function_arity()); + + a.bl(resolve_fragment((void (*)())func, disp128MB)); + } + + bool isRegisterBacked(const ArgVal &arg) { + if (arg.isXRegister()) { + return arg.as().get() < num_register_backed_xregs; + } else if (arg.isFRegister()) { + return arg.as().get() < num_register_backed_fregs; + } + + return false; + } + + template + struct Variable { + RegType reg; + arm::Mem mem; + + Variable(RegType _r) : Variable(_r, arm::Mem()) { + } + Variable(RegType _r, arm::Mem _mem) : reg(_r), mem(_mem) { + } + }; + + Variable init_destination(const ArgVal &arg, arm::Gp tmp) { + /* We don't support storing into GpW since their maximum displacement + * is 16K, which means we have to check stubs far more often. */ + ASSERT(tmp.isGpX()); + + if (isRegisterBacked(arg)) { + auto index = arg.as().get(); + return Variable(register_backed_xregs[index]); + } else { + return Variable(tmp, getArgRef(arg)); + } + } + + Variable init_destination(const ArgVal &arg, arm::VecD tmp) { + if (isRegisterBacked(arg)) { + auto index = arg.as().get(); + return Variable(register_backed_fregs[index]); + } else { + return Variable(tmp, getArgRef(arg)); + } + } + + Variable load_source(const ArgVal &arg, arm::Gp tmp) { + /* We don't support loading into GpW since their maximum displacement + * is 16K, which means we have to check stubs far more often. */ + ASSERT(tmp.isGpX()); + + if (arg.isLiteral()) { + a.ldr(tmp, embed_constant(arg, disp32K)); + return Variable(tmp); + } else if (arg.isRegister()) { + if (isRegisterBacked(arg)) { + auto index = arg.as().get(); + arm::Gp reg = register_backed_xregs[index]; + invalidate_cache(reg); + return Variable(reg); + } + + auto ref = getArgRef(arg); + ldr_cached(tmp, ref); + return Variable(tmp, ref); + } else { + if (arg.isImmed() || arg.isWord()) { + auto val = arg.isImmed() ? arg.as().get() + : arg.as().get(); + + if (Support::isIntOrUInt32(val)) { + mov_imm_preserve_cache(tmp, val); + return Variable(tmp); + } + } + + a.ldr(tmp, embed_constant(arg, disp32K)); + return Variable(tmp); + } + } + + auto load_sources(const ArgVal &Src1, + arm::Gp tmp1, + const ArgVal &Src2, + arm::Gp tmp2) { + if (!isRegisterBacked(Src1) && !isRegisterBacked(Src2)) { + switch (ArgVal::memory_relation(Src1, Src2)) { + case ArgVal::Relation::consecutive: + safe_ldp(tmp1, tmp2, Src1, Src2); + return std::make_pair(Variable(tmp1, getArgRef(Src1)), + Variable(tmp2, getArgRef(Src2))); + case ArgVal::Relation::reverse_consecutive: + safe_ldp(tmp2, tmp1, Src2, Src1); + return std::make_pair(Variable(tmp1, getArgRef(Src1)), + Variable(tmp2, getArgRef(Src2))); + case ArgVal::Relation::none: + break; + } + } + + return std::make_pair(load_source(Src1, tmp1), load_source(Src2, tmp2)); + } + + Variable load_source(const ArgVal &arg, arm::VecD tmp) { + if (isRegisterBacked(arg)) { + auto index = arg.as().get(); + return Variable(register_backed_fregs[index]); + } + + a.ldr(tmp, getArgRef(arg)); + return Variable(tmp); + } + + template + void mov_var(const Variable &to, const Variable &from) { + mov_var(to.reg, from); + } + + template + void mov_var(const Variable &to, Reg from) { + if (to.reg != from) { + mov_preserve_cache(to.reg, from); + } + } + + template + void mov_var(Reg to, const Variable &from) { + if (to != from.reg) { + mov_preserve_cache(to, from.reg); + } + } + + void flush_var(const Variable &to) { + if (to.mem.hasBase()) { + str_cache(to.reg, to.mem); + } + } + + void flush_var(const Variable &to) { + if (to.mem.hasBase()) { + a.str(to.reg, to.mem); + } + } + + void flush_vars(const Variable &to1, + const Variable &to2) { + const arm::Mem &mem1 = to1.mem; + const arm::Mem &mem2 = to2.mem; + + if (mem1.hasBaseReg() && mem2.hasBaseReg() && + mem1.baseId() == mem2.baseId()) { + if (mem1.offset() + 8 == mem2.offset()) { + stp_cache(to1.reg, to2.reg, mem1); + return; + } else if (mem1.offset() == mem2.offset() + 8) { + stp_cache(to2.reg, to1.reg, mem2); + return; + } + } + + /* Not possible to optimize with stp. */ + flush_var(to1); + flush_var(to2); + } + + void mov_arg(const ArgVal &To, const ArgVal &From) { + if (isRegisterBacked(To)) { + auto to = init_destination(To, SUPER_TMP); + auto from = load_source(From, to.reg); + mov_var(to, from); + flush_var(to); + } else { + auto from = load_source(From, SUPER_TMP); + auto to = init_destination(To, from.reg); + mov_var(to, from); + flush_var(to); + } + } + + void mov_arg(const ArgVal &To, arm::Mem From) { + auto to = init_destination(To, SUPER_TMP); + a.ldr(to.reg, From); + flush_var(to); + } + + void mov_arg(arm::Mem To, const ArgVal &From) { + auto from = load_source(From, SUPER_TMP); + auto to = Variable(from.reg, To); + flush_var(to); + } + + void mov_arg(arm::Gp to, const ArgVal &from) { + auto r = load_source(from, to); + if (r.reg != to) { + a.mov(to, r.reg); + } + } + + void mov_arg(const ArgVal &to, arm::Gp from) { + auto r = init_destination(to, from); + if (r.reg != from) { + a.mov(r.reg, from); + } + flush_var(r); + } + + void cmp_arg(arm::Gp gp, const ArgVal &arg) { + if (arg.isImmed() || arg.isWord()) { + Sint val = arg.isImmed() ? arg.as().get() + : arg.as().get(); + cmp(gp, val); + return; + } + + auto tmp = load_source(arg, SUPER_TMP); + a.cmp(gp, tmp.reg); + } + + void safe_stp(arm::Gp gp1, + arm::Gp gp2, + const ArgVal &Dst1, + const ArgVal &Dst2) { + ASSERT(ArgVal::memory_relation(Dst1, Dst2) == + ArgVal::Relation::consecutive); + safe_stp(gp1, gp2, getArgRef(Dst1)); + } + + void safe_stp(arm::Gp gp1, arm::Gp gp2, arm::Mem mem) { + size_t abs_offset = std::abs(mem.offset()); + auto offset = mem.offset(); + + ASSERT(gp1.isGpX() && gp2.isGpX()); + + if (abs_offset <= sizeof(Eterm) * MAX_LDP_STP_DISPLACEMENT) { + a.stp(gp1, gp2, mem); + } else if (abs_offset < sizeof(Eterm) * MAX_LDR_STR_DISPLACEMENT) { + /* Note that we used `<` instead of `<=`, as we're loading two + * elements rather than one. */ + a.str(gp1, mem); + a.str(gp2, mem.cloneAdjusted(sizeof(Eterm))); + } else { + add(SUPER_TMP, arm::GpX(mem.baseId()), offset); + a.stp(gp1, gp2, arm::Mem(SUPER_TMP)); + } + } + + void safe_ldr(arm::Gp gp, arm::Mem mem) { + size_t abs_offset = std::abs(mem.offset()); + auto offset = mem.offset(); + + ASSERT(mem.hasBaseReg() && !mem.hasIndex()); + ASSERT(gp.isGpX()); + + if (abs_offset <= sizeof(Eterm) * MAX_LDR_STR_DISPLACEMENT) { + a.ldr(gp, mem); + } else { + add(SUPER_TMP, arm::GpX(mem.baseId()), offset); + a.ldr(gp, arm::Mem(SUPER_TMP)); + } + } + + void safe_ldur(arm::Gp gp, arm::Mem mem) { + size_t abs_offset = std::abs(mem.offset()); + auto offset = mem.offset(); + + ASSERT(mem.hasBaseReg() && !mem.hasIndex()); + ASSERT(gp.isGpX()); + + if (abs_offset <= MAX_LDUR_STUR_DISPLACEMENT) { + a.ldur(gp, mem); + } else { + add(SUPER_TMP, arm::GpX(mem.baseId()), offset); + a.ldr(gp, arm::Mem(SUPER_TMP)); + } + } + + void safe_ldp(arm::Gp gp1, + arm::Gp gp2, + const ArgVal &Src1, + const ArgVal &Src2) { + ASSERT(ArgVal::memory_relation(Src1, Src2) == + ArgVal::Relation::consecutive); + + safe_ldp(gp1, gp2, getArgRef(Src1)); + } + + void safe_ldp(arm::Gp gp1, arm::Gp gp2, arm::Mem mem) { + size_t abs_offset = std::abs(mem.offset()); + auto offset = mem.offset(); + + ASSERT(gp1.isGpX() && gp2.isGpX()); + ASSERT(gp1 != gp2); + + if (abs_offset <= sizeof(Eterm) * MAX_LDP_STP_DISPLACEMENT) { + a.ldp(gp1, gp2, mem); + } else if (abs_offset < sizeof(Eterm) * MAX_LDR_STR_DISPLACEMENT) { + /* Note that we used `<` instead of `<=`, as we're loading two + * elements rather than one. */ + a.ldr(gp1, mem); + a.ldr(gp2, mem.cloneAdjusted(sizeof(Eterm))); + } else { + add(SUPER_TMP, arm::GpX(mem.baseId()), offset); + a.ldp(gp1, gp2, arm::Mem(SUPER_TMP)); + } + } +}; + +void beamasm_metadata_update(std::string module_name, + ErtsCodePtr base_address, + size_t code_size, + const std::vector &ranges); +void beamasm_metadata_early_init(); +void beamasm_metadata_late_init(); diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.cpp b/erts/emulator/beam/jit/arm/beam_asm_global.cpp new file mode 100644 index 000000000000..a4d20a9356dd --- /dev/null +++ b/erts/emulator/beam/jit/arm/beam_asm_global.cpp @@ -0,0 +1,351 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#define ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS +#include "beam_asm.hpp" +#undef ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS + +using namespace asmjit; + +extern "C" +{ +#include "bif.h" +#include "beam_common.h" +} + +BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) + : BeamAssembler("beam_asm_global") { + labels.reserve(emitPtrs.size()); + + /* These labels are defined up-front so global functions can refer to each + * other freely without any order dependencies. */ + for (auto val : labelNames) { + std::string name = "global::" + val.second; + labels[val.first] = a.newNamedLabel(name.c_str()); + } + + /* Emit all of the code and bind all of the labels */ + for (auto val : emitPtrs) { + a.align(AlignMode::kCode, 8); + a.bind(labels[val.first]); + /* This funky syntax calls the function pointer within this instance + * of BeamGlobalAssembler */ + (this->*val.second)(); + } + + { + const void *executable_region; + void *writable_region; + + BeamAssembler::codegen(allocator, &executable_region, &writable_region); + VirtMem::flushInstructionCache((void *)executable_region, + code.codeSize()); + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute); + } + + std::vector ranges; + + ranges.reserve(emitPtrs.size()); + + for (auto val : emitPtrs) { + ErtsCodePtr start = (ErtsCodePtr)getCode(labels[val.first]); + ErtsCodePtr stop; + + if (val.first + 1 < emitPtrs.size()) { + stop = (ErtsCodePtr)getCode(labels[(GlobalLabels)(val.first + 1)]); + } else { + stop = (ErtsCodePtr)((char *)getBaseAddress() + code.codeSize()); + } + + ranges.push_back({.start = start, + .stop = stop, + .name = code.labelEntry(labels[val.first])->name()}); + } + + beamasm_metadata_update("global", + (ErtsCodePtr)getBaseAddress(), + code.codeSize(), + ranges); + + /* `this->get_xxx` are populated last to ensure that we crash if we use + * them instead of labels in global code. */ + for (auto val : labelNames) { + ptrs[val.first] = (fptr)getCode(labels[val.first]); + } +} + +/* ARG3 = (HTOP + S_RESERVED + bytes needed) !! + * ARG4 = Live registers */ +void BeamGlobalAssembler::emit_garbage_collect() { + emit_enter_runtime_frame(); + + /* Convert ARG3 to words needed and move it to the correct argument slot. + * + * Note that we cancel out the S_RESERVED that we added in the GC check, as + * the GC routines handle that separately and we don't want it to be added + * twice. */ + a.sub(ARG2, ARG3, HTOP); + a.lsr(ARG2, ARG2, imm(3)); + a.sub(ARG2, ARG2, imm(S_RESERVED)); + + /* Save our return address in c_p->i so we can tell where we crashed if we + * did so during GC. */ + a.str(a64::x30, arm::Mem(c_p, offsetof(Process, i))); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + /* ARG2 is already loaded. */ + load_x_reg_array(ARG3); + /* ARG4 (live registers) is already loaded. */ + a.mov(ARG5, FCALLS); + runtime_call<5>(erts_garbage_collect_nobump); + a.sub(FCALLS, FCALLS, ARG1); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, state.value))); + a.tst(TMP1, imm(ERTS_PSFLG_EXITING)); + a.b_ne(labels[do_schedule]); + + a.ret(a64::x30); +} + +/* Handles trapping to exports from C code, setting registers up in the same + * manner a normal call_ext instruction would so that save_calls, tracing, and + * so on will work. + * + * Our return address is on the stack as we always come here from a BIF, so we + * must pop it into LR (x30) to convert this into an ordinary call. The + * callee will then push LR to the stack in its prologue, cancelling this out. + * + * Assumes that c_p->current points into the MFA of an export entry. */ +void BeamGlobalAssembler::emit_bif_export_trap() { + int export_offset = offsetof(Export, info.mfa); + + a.ldr(ARG1, arm::Mem(c_p, offsetof(Process, current))); + a.sub(ARG1, ARG1, export_offset); + + emit_leave_erlang_frame(); + + branch(emit_setup_dispatchable_call(ARG1)); +} + +/* Handles export breakpoints, error handler, jump tracing, and so on. + * + * We must be careful with LR (x30) and the stack as this runs between the + * caller and callee, and the latter pushes LR to the stack as part of its + * prologue. + * + * ARG1 = export entry + */ +void BeamGlobalAssembler::emit_export_trampoline() { + Label call_bif = a.newLabel(), error_handler = a.newLabel(), + jump_trace = a.newLabel(); + + /* What are we supposed to do? */ + a.ldr(TMP1, arm::Mem(ARG1, offsetof(Export, trampoline.common.op))); + + /* We test the generic bp first as it is most likely to be triggered in a + * loop. */ + a.cmp(TMP1, imm(op_i_generic_breakpoint)); + a.b_eq(labels[generic_bp_global]); + + a.cmp(TMP1, imm(op_call_bif_W)); + a.b_eq(call_bif); + + a.cmp(TMP1, imm(op_call_error_handler)); + a.b_eq(error_handler); + + a.cmp(TMP1, imm(op_trace_jump_W)); + a.b_eq(jump_trace); + + /* Must never happen. */ + a.udf(0xffff); + + a.bind(call_bif); + { + /* Emulate a `call_bif` instruction. + * + * Note that we don't check reductions: yielding here is very tricky + * and error-prone, and there's little point in doing so as we can only + * land here directly after being scheduled in. */ + ssize_t func_offset = offsetof(Export, trampoline.bif.address); + + lea(ARG2, arm::Mem(ARG1, offsetof(Export, info.mfa))); + a.ldr(ARG3, arm::Mem(c_p, offsetof(Process, i))); + a.ldr(ARG4, arm::Mem(ARG1, func_offset)); + + /* `call_bif_shared` assumes that the return address has been pushed to + * the stack as part of the prologue, so we have to do that manually + * now. */ + emit_enter_erlang_frame(); + a.b(labels[call_bif_shared]); + } + + a.bind(jump_trace); + { + a.ldr(TMP1, arm::Mem(ARG1, offsetof(Export, trampoline.trace.address))); + a.br(TMP1); + } + + a.bind(error_handler); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + lea(ARG2, arm::Mem(ARG1, offsetof(Export, info.mfa))); + a.mov(ARG1, c_p); + load_x_reg_array(ARG3); + mov_imm(ARG4, am_undefined_function); + runtime_call<4>(call_error_handler); + + /* If there is no error_handler, any number of X registers + * can be live. */ + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.cbz(ARG1, labels[process_exit]); + + branch(emit_setup_dispatchable_call(ARG1)); + } +} + +/* + * Get the error address implicitly by calling the shared fragment and using + * the return address as the error address. + */ +void BeamModuleAssembler::emit_raise_exception() { + emit_raise_exception(nullptr); +} + +void BeamModuleAssembler::emit_raise_exception(const ErtsCodeMFA *exp) { + if (exp) { + a.ldr(ARG4, embed_constant(exp, disp32K)); + } else { + a.mov(ARG4, ZERO); + } + + fragment_call(ga->get_raise_exception()); + + /* `line` instructions need to know the latest offset that may throw an + * exception. See the `line` instruction for details. */ + last_error_offset = a.offset(); +} + +void BeamModuleAssembler::emit_raise_exception(Label I, + const ErtsCodeMFA *exp) { + a.adr(ARG2, I); + + if (exp) { + a.ldr(ARG4, embed_constant(exp, disp32K)); + } else { + a.mov(ARG4, ZERO); + } + + a.b(resolve_fragment(ga->get_raise_exception_shared(), disp128MB)); +} + +void BeamGlobalAssembler::emit_process_exit() { + emit_enter_runtime(); + + a.mov(ARG1, c_p); + mov_imm(ARG2, 0); + mov_imm(ARG4, 0); + load_x_reg_array(ARG3); + runtime_call<4>(handle_error); + + emit_leave_runtime(); + + a.cbz(ARG1, labels[do_schedule]); + a.udf(0xdead); +} + +/* You must have already done emit_leave_runtime_frame()! */ +void BeamGlobalAssembler::emit_raise_exception() { + a.mov(ARG2, a64::x30); + a.b(labels[raise_exception_shared]); +} + +void BeamGlobalAssembler::emit_raise_exception_shared() { + Label crash = a.newLabel(); + + /* Push a fake CP to ensure that we can handle a topmost frame + * with `catch` and an instruction raising and exception. + * + * The fake CP is discarded by handle_error() before jumping to + * a catch handler, and is ignored as a duplicate in stack + * traces because it's equal to the error address. */ + a.str(ARG2, arm::Mem(E, -8).pre()); + + emit_enter_runtime(); + + /* The error address must be a valid CP or NULL. */ + a.tst(ARG2, imm(_CPMASK)); + a.b_ne(crash); + + /* ARG2 and ARG4 must be set prior to jumping here! */ + a.mov(ARG1, c_p); + load_x_reg_array(ARG3); + runtime_call<4>(handle_error); + + emit_leave_runtime(); + + a.cbz(ARG1, labels[do_schedule]); + + /* XREG0 = THE_NON_VALUE + * XREG1 = class + * XREG2 = error reason/thrown value + * XREG3 = raw stacktrace. */ + a.br(ARG1); + + a.bind(crash); + a.udf(0xbad); +} + +void BeamModuleAssembler::emit_proc_lc_unrequire(void) { +#ifdef ERTS_ENABLE_LOCK_CHECK + a.mov(ARG1, c_p); + mov_imm(ARG2, ERTS_PROC_LOCK_MAIN); + runtime_call<2>(erts_proc_lc_unrequire_lock); +#endif +} + +void BeamModuleAssembler::emit_proc_lc_require(void) { +#ifdef ERTS_ENABLE_LOCK_CHECK + a.mov(ARG1, c_p); + mov_imm(ARG2, ERTS_PROC_LOCK_MAIN); + runtime_call<4>(erts_proc_lc_require_lock); +#endif +} + +extern "C" +{ + /* GDB puts a breakpoint in this function. + * + * Has to be on another file than the caller as otherwise gcc may + * optimize away the call. */ + void ERTS_NOINLINE __jit_debug_register_code(void); + void ERTS_NOINLINE __jit_debug_register_code(void) { + } +} diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl new file mode 100644 index 000000000000..b2478bd56d5c --- /dev/null +++ b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl @@ -0,0 +1,226 @@ +#!/usr/bin/env perl -W +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2022-2023. 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% +# +use strict; + +# Please keep the names in the list in alphabetical order. +my @beam_global_funcs = qw( + apply_fun_shared + arith_compare_shared + bif_nif_epilogue + bif_export_trap + bif_bit_size_body + bif_bit_size_guard + bif_byte_size_body + bif_byte_size_guard + bif_element_body_shared + bif_element_guard_shared + bif_is_eq_exact_shared + bif_is_ne_exact_shared + bif_tuple_size_body + bif_tuple_size_guard + bs_add_guard_shared + bs_add_body_shared + bs_bit_size_shared + bs_create_bin_error_shared + bs_get_tail_shared + bs_get_utf8_shared + bs_get_utf8_short_shared + bs_size_check_shared + call_bif_shared + call_light_bif_shared + call_nif_yield_helper + catch_end_shared + call_nif_early + call_nif_shared + check_float_error + construct_utf8_shared + debug_bp + dispatch_bif + dispatch_nif + dispatch_return + dispatch_save_calls_export + dispatch_save_calls_fun + export_trampoline + fconv_shared + get_sint64_shared + handle_and_error + handle_call_fun_error + handle_element_error_shared + handle_hd_error + handle_map_get_badkey + handle_map_get_badmap + handle_map_size_error + handle_node_error + handle_not_error + handle_or_error + handle_tl_error + garbage_collect + generic_bp_global + generic_bp_local + i_band_body_shared + i_bnot_body_shared + i_bnot_guard_shared + i_bor_body_shared + i_bif_body_shared + i_bif_guard_shared + i_breakpoint_trampoline_shared + i_bsr_body_shared + i_bsl_body_shared + i_func_info_shared + i_get_map_element_shared + i_get_map_element_hash_shared + i_length_guard_shared + i_length_body_shared + i_loop_rec_shared + i_test_yield_shared + i_bxor_body_shared + int_div_rem_body_shared + int_div_rem_guard_shared + internal_hash_helper + is_in_range_shared + is_ge_lt_shared + minus_body_shared + new_map_shared + update_map_assoc_shared + unloaded_fun + plus_body_shared + process_exit + process_main + raise_exception + raise_exception_shared + store_unaligned + times_body_shared + times_guard_shared + unary_minus_body_shared + update_map_exact_guard_shared + update_map_exact_body_shared + ); + + +# Labels exported from within process_main +my @process_main_labels = qw( + context_switch + context_switch_simplified + do_schedule + ); + +my $decl_enums = + gen_list(' %s,', @beam_global_funcs, '', @process_main_labels); + +my $decl_emit_funcs = + gen_list(' void emit_%s(void);', @beam_global_funcs); + +my $decl_get_funcs = + gen_list(' void (*get_%s(void))() { return get(%s); }', + @beam_global_funcs, '', @process_main_labels); + +my $decl_emitPtrs = + gen_list(' {%s, &BeamGlobalAssembler::emit_%s},', @beam_global_funcs); + +my $decl_label_names = + gen_list(' {%s, "%s"},', @beam_global_funcs, '', @process_main_labels); + +sub gen_list { + my ($format, @strings) = @_; + my $out = ''; + foreach my $str (@strings) { + if ($str eq '') { + $out .= "\n"; + } + else { + my $subst = $format; + $subst =~ s/%s/$str/g; + $out .= "$subst\n"; + } + } + $out; +} + + +my $this_source_file = __FILE__; + +print < labelNames; + static const std::map emitPtrs; + std::unordered_map labels; + std::unordered_map ptrs; + +$decl_emit_funcs + + template + void emit_bitwise_fallback_body(T(*func_ptr), const ErtsCodeMFA *mfa); + + void emit_i_length_common(Label fail, int state_size); + + void emit_raise_badarg(const ErtsCodeMFA *mfa); + + void emit_bif_bit_size_helper(Label fail); + void emit_bif_byte_size_helper(Label fail); + void emit_bif_element_helper(Label fail); + void emit_bif_tuple_size_helper(Label fail); + + void emit_flatmap_get_element(); + void emit_hashmap_get_element(); + +public: + BeamGlobalAssembler(JitAllocator *allocator); + + void (*get(GlobalLabels lbl))(void) { + ASSERT(ptrs[lbl]); + return ptrs[lbl]; + } + +$decl_get_funcs +}; + +#ifdef ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS + +const std::map +BeamGlobalAssembler::emitPtrs = { +$decl_emitPtrs +}; + +const std::map +BeamGlobalAssembler::labelNames = { +$decl_label_names +}; + +#endif /* ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS */ + +#endif /* !_BEAM_ASM_GLOBAL_HPP */ +END_OF_FILE diff --git a/erts/emulator/beam/jit/arm/beam_asm_module.cpp b/erts/emulator/beam/jit/arm/beam_asm_module.cpp new file mode 100644 index 000000000000..57f5746a8c42 --- /dev/null +++ b/erts/emulator/beam/jit/arm/beam_asm_module.cpp @@ -0,0 +1,770 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include +#include +#include + +#include "beam_asm.hpp" +using namespace asmjit; + +#ifdef BEAMASM_DUMP_SIZES +# include + +typedef std::pair op_stats; + +static std::unordered_map sizes; +static std::mutex size_lock; + +extern "C" void beamasm_dump_sizes() { + std::lock_guard lock(size_lock); + + std::vector> flat(sizes.cbegin(), sizes.cend()); + double total_size = 0.0; + + for (const auto &op : flat) { + total_size += op.second.second; + } + + /* Sort instructions by total size, in descending order. */ + std::sort( + flat.begin(), + flat.end(), + [](std::pair &a, std::pair &b) { + return a.second.second > b.second.second; + }); + + for (const auto &op : flat) { + fprintf(stderr, + "%34s:\t%zu\t%f\t%zu\t%zu\r\n", + op.first, + op.second.second, + op.second.second / total_size, + op.second.first, + op.second.first ? (op.second.second / op.second.first) : 0); + } +} +#endif + +ErtsCodePtr BeamModuleAssembler::getCode(BeamLabel label) { + ASSERT(label < rawLabels.size() + 1); + return (ErtsCodePtr)getCode(rawLabels[label]); +} + +ErtsCodePtr BeamModuleAssembler::getLambda(unsigned index) { + const auto &lambda = lambdas[index]; + return (ErtsCodePtr)getCode(lambda.trampoline); +} + +BeamModuleAssembler::BeamModuleAssembler(BeamGlobalAssembler *ga, + Eterm mod, + int num_labels, + int num_functions, + const BeamFile *file) + : BeamModuleAssembler(ga, mod, num_labels, file) { + _veneers.reserve(num_labels + 1); + + code_header = a.newLabel(); + a.align(AlignMode::kCode, 8); + a.bind(code_header); + + embed_zeros(sizeof(BeamCodeHeader) + + sizeof(ErtsCodeInfo *) * num_functions); + +#ifdef DEBUG + last_stub_check_offset = a.offset(); +#endif +} + +void BeamModuleAssembler::embed_vararg_rodata(const Span &args, + a64::Gp reg) { + /* Short sequences are inlined in the .text section for slightly better + * speed. */ + bool inlineData = args.size() <= 6; + + Label data = a.newLabel(), next = a.newLabel(); + + if (inlineData) { + a.adr(reg, data); + a.b(next); + } else { + Label pointer = a.newLabel(); + + a.ldr(reg, arm::Mem(pointer)); + a.b(next); + + a.align(AlignMode::kCode, 8); + a.bind(pointer); + a.embedLabel(data, 8); + + a.section(rodata); + } + + a.align(AlignMode::kData, 8); + a.bind(data); + + for (const ArgVal &arg : args) { + union { + BeamInstr as_beam; + char as_char[1]; + } data; + + a.align(AlignMode::kData, 8); + switch (arg.getType()) { + case ArgVal::Literal: { + auto &patches = literals[arg.as().get()].patches; + Label patch = a.newLabel(); + + a.bind(patch); + a.embedUInt64(LLONG_MAX); + patches.push_back({patch, 0}); + break; + } + case ArgVal::XReg: + data.as_beam = make_loader_x_reg(arg.as().get()); + a.embed(&data.as_char, sizeof(data.as_beam)); + break; + case ArgVal::YReg: + data.as_beam = make_loader_y_reg(arg.as().get()); + a.embed(&data.as_char, sizeof(data.as_beam)); + break; + case ArgVal::Label: + a.embedLabel(rawLabels[arg.as().get()]); + break; + case ArgVal::Immediate: + data.as_beam = arg.as().get(); + a.embed(&data.as_char, sizeof(data.as_beam)); + break; + case ArgVal::Word: + data.as_beam = arg.as().get(); + a.embed(&data.as_char, sizeof(data.as_beam)); + break; + default: + ERTS_ASSERT(!"error"); + } + } + + if (!inlineData) { + a.section(code.textSection()); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_i_nif_padding() { + const size_t minimum_size = sizeof(UWord[BEAM_NATIVE_MIN_FUNC_SZ]); + size_t prev_func_start, diff; + + prev_func_start = code.labelOffsetFromBase(rawLabels[functions.back() + 1]); + diff = a.offset() - prev_func_start; + + if (diff < minimum_size) { + embed_zeros(minimum_size - diff); + } +} + +void BeamGlobalAssembler::emit_i_breakpoint_trampoline_shared() { + constexpr ssize_t flag_offset = + sizeof(ErtsCodeInfo) + BEAM_ASM_FUNC_PROLOGUE_SIZE - + offsetof(ErtsCodeInfo, u.metadata.breakpoint_flag); + + Label bp_and_nif = a.newLabel(), bp_only = a.newLabel(), + nif_only = a.newLabel(); + + a.ldrb(ARG1.w(), arm::Mem(a64::x30, -flag_offset)); + + a.cmp(ARG1, imm(ERTS_ASM_BP_FLAG_BP_NIF_CALL_NIF_EARLY)); + a.b_eq(bp_and_nif); + ERTS_CT_ASSERT((1 << 0) == ERTS_ASM_BP_FLAG_CALL_NIF_EARLY); + a.tbnz(ARG1, imm(0), nif_only); + ERTS_CT_ASSERT((1 << 1) == ERTS_ASM_BP_FLAG_BP); + a.tbnz(ARG1, imm(1), bp_only); + +#ifndef DEBUG + a.ret(a64::x30); +#else + Label error = a.newLabel(); + + /* ARG1 must be a valid breakpoint flag. */ + a.cbnz(ARG1, error); + a.ret(a64::x30); + + a.bind(error); + a.udf(0xBC0D); +#endif + + a.bind(bp_and_nif); + { + emit_enter_runtime_frame(); + a.bl(labels[generic_bp_local]); + emit_leave_runtime_frame(); + + /* !! FALL THROUGH !! */ + } + + a.bind(nif_only); + { + /* call_nif_early returns on its own, unlike generic_bp_local. */ + a.b(labels[call_nif_early]); + } + + a.bind(bp_only); + { + emit_enter_runtime_frame(); + a.bl(labels[generic_bp_local]); + emit_leave_runtime_frame(); + + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_i_breakpoint_trampoline() { + /* This little prologue is used by nif loading and tracing to insert + * alternative instructions. */ + Label next = a.newLabel(); + + emit_enter_erlang_frame(); + + /* This branch is modified to jump to the BL instruction when the + * breakpoint is enabled. */ + a.b(next); + + if (code_header.isValid()) { + a.bl(resolve_fragment(ga->get_i_breakpoint_trampoline_shared(), + disp128MB)); + } else { + /* NIF or BIF stub; we're not going to use this trampoline as-is, but + * we need to reserve space for it. */ + a.udf(0xB1F); + } + + a.bind(next); + + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + BEAM_ASM_FUNC_PROLOGUE_SIZE); +} + +static void i_emit_nyi(char *msg) { + erts_exit(ERTS_ERROR_EXIT, "NYI: %s\n", msg); +} + +void BeamModuleAssembler::emit_nyi(const char *msg) { + emit_enter_runtime(0); + + a.mov(ARG1, imm(msg)); + runtime_call<1>(i_emit_nyi); + + /* Never returns */ +} + +void BeamModuleAssembler::emit_nyi() { + emit_nyi(""); +} + +bool BeamModuleAssembler::emit(unsigned specific_op, const Span &args) { + check_pending_stubs(); + +#ifdef BEAMASM_DUMP_SIZES + size_t before = a.offset(); +#endif + + comment(opc[specific_op].name); + +#define InstrCnt() + switch (specific_op) { +#include "beamasm_emit.h" + default: + ERTS_ASSERT(0 && "Invalid instruction"); + break; + } + +#ifdef BEAMASM_DUMP_SIZES + { + std::lock_guard lock(size_lock); + + sizes[opc[specific_op].name].first++; + sizes[opc[specific_op].name].second += a.offset() - before; + } +#endif + + return true; +} + +/* + * Here follows meta instructions. + */ + +void BeamGlobalAssembler::emit_i_func_info_shared() { + /* a64::x30 now points 4 bytes into the ErtsCodeInfo struct for the + * function. Put the address of the MFA into ARG1. */ + a.add(ARG1, a64::x30, offsetof(ErtsCodeInfo, mfa) - 4); + mov_imm(TMP1, EXC_FUNCTION_CLAUSE); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ARG1, arm::Mem(c_p, offsetof(Process, current))); + + mov_imm(ARG2, 0); + mov_imm(ARG4, 0); + + a.b(labels[raise_exception_shared]); +} + +void BeamModuleAssembler::emit_i_func_info(const ArgWord &Label, + const ArgAtom &Module, + const ArgAtom &Function, + const ArgWord &Arity) { + ErtsCodeInfo info; + + /* `op_i_func_info_IaaI` is used in various places in the emulator, so this + * label is always encoded as a word, even though the signature ought to + * be `op_i_func_info_LaaI`. */ + functions.push_back(Label.get()); + + info.mfa.module = Module.get(); + info.mfa.function = Function.get(); + info.mfa.arity = Arity.get(); + info.gen_bp = NULL; + + comment("%T:%T/%d", info.mfa.module, info.mfa.function, info.mfa.arity); + + /* This is an ErtsCodeInfo structure that has a valid ARM opcode as its `op` + * field, which *calls* the `raise_function_clause` fragment so we can trace + * it back to this particular function. + * + * We also use this field to store the current breakpoint flag, as ARM is a + * bit more strict about modifying code than x86: only branch instructions + * can be safely modified without issuing an ISB. By storing the flag here + * and reading it in the fragment, we don't have to change any code other + * than the branch instruction. */ + if (code_header.isValid()) { + /* We avoid using the `fragment_call` helper to ensure a constant + * layout, as it adds code in certain debug configurations. */ + a.bl(resolve_fragment(ga->get_i_func_info_shared(), disp128MB)); + } else { + a.udf(0xF1F0); + } + + ERTS_CT_ASSERT(ERTS_ASM_BP_FLAG_NONE == 0); + a.embedUInt32(0); + + ASSERT(a.offset() % sizeof(UWord) == 0); + a.embed(&info.gen_bp, sizeof(info.gen_bp)); + a.embed(&info.mfa, sizeof(info.mfa)); +} + +void BeamModuleAssembler::emit_label(const ArgLabel &Label) { + ASSERT(Label.isLabel()); + + current_label = rawLabels[Label.get()]; + bind_veneer_target(current_label); + + last_destination_offset = ~0; +} + +void BeamModuleAssembler::emit_aligned_label(const ArgLabel &Label, + const ArgWord &Alignment) { + a.align(AlignMode::kCode, Alignment.get()); + emit_label(Label); +} + +void BeamModuleAssembler::emit_on_load() { + on_load = current_label; +} + +void BeamModuleAssembler::bind_veneer_target(const Label &target) { + auto veneer_range = _veneers.equal_range(target.id()); + for (auto it = veneer_range.first; it != veneer_range.second; it++) { + const Veneer &veneer = it->second; + + ASSERT(veneer.target == target); + + if (!code.isLabelBound(veneer.anchor)) { + ASSERT(a.offset() <= veneer.latestOffset); + a.bind(veneer.anchor); + + /* TODO: remove from pending stubs? */ + } + } + + a.bind(target); +} + +void BeamModuleAssembler::emit_int_code_end() { + /* This label is used to figure out the end of the last function */ + code_end = a.newLabel(); + a.bind(code_end); + + emit_nyi("int_code_end"); + + /* We emit the dispatch table before all remaining stubs to bind veneers + * directly in the table itself, avoiding a painful extra jump. + * + * Since the table is potentially very large, we'll emit all stubs that are + * due within it so we won't have to check on every iteration. */ + flush_pending_stubs(_dispatchTable.size() * sizeof(Uint32[8]) + + dispUnknown); + + for (auto pair : _dispatchTable) { + bind_veneer_target(pair.second); + + a.mov(SUPER_TMP, imm(pair.first)); + a.br(SUPER_TMP); + } + + /* Emit all remaining stubs. */ + flush_pending_stubs(dispMax); +} + +void BeamModuleAssembler::emit_line(const ArgWord &Loc) { + /* There is no need to align the line instruction. In the loaded code, the + * type of the pointer will be void* and that pointer will only be used in + * comparisons. + * + * We only need to do something when there's a possibility of raising an + * exception at the very end of the preceding instruction (and thus + * pointing at the start of this one). If we were to do nothing, the error + * would erroneously refer to this instead of the preceding line. + * + * Since line addresses are taken _after_ line instructions we can avoid + * this by adding a nop when we detect this condition. */ + if (a.offset() == last_error_offset) { + a.nop(); + } +} + +void BeamModuleAssembler::emit_func_line(const ArgWord &Loc) { + emit_line(Loc); +} + +void BeamModuleAssembler::emit_empty_func_line() { +} + +/* + * Here follows stubs for instructions that should never be called. + */ + +void BeamModuleAssembler::emit_i_debug_breakpoint() { + emit_nyi("i_debug_breakpoint should never be called"); +} + +void BeamModuleAssembler::emit_i_generic_breakpoint() { + emit_nyi("i_generic_breakpoint should never be called"); +} + +void BeamModuleAssembler::emit_trace_jump(const ArgWord &) { + emit_nyi("trace_jump should never be called"); +} + +void BeamModuleAssembler::emit_call_error_handler() { + emit_nyi("call_error_handler should never be called"); +} + +const Label &BeamModuleAssembler::resolve_beam_label(const ArgLabel &Lbl, + enum Displacement disp) { + ASSERT(Lbl.isLabel()); + + const Label &beamLabel = rawLabels.at(Lbl.get()); + const auto &labelEntry = code.labelEntry(beamLabel); + + if (labelEntry->hasName()) { + return resolve_label(rawLabels.at(Lbl.get()), disp, labelEntry->name()); + } else { + return resolve_label(rawLabels.at(Lbl.get()), disp); + } +} + +const Label &BeamModuleAssembler::resolve_label(const Label &target, + enum Displacement disp, + const char *labelName) { + ssize_t currOffset = a.offset(); + + ssize_t minOffset = currOffset - disp; + ssize_t maxOffset = currOffset + disp; + + ASSERT(disp >= dispMin && disp <= dispMax); + ASSERT(target.isValid()); + + if (code.isLabelBound(target)) { + ssize_t targetOffset = code.labelOffsetFromBase(target); + + /* Backward reference: skip veneers if it's already in range. */ + if (targetOffset >= minOffset) { + return target; + } + } + + /* If a previously created veneer is reachable from this point, we can use + * it instead of creating a new one. */ + auto range = _veneers.equal_range(target.id()); + for (auto it = range.first; it != range.second; it++) { + const Veneer &veneer = it->second; + + if (code.isLabelBound(veneer.anchor)) { + ssize_t veneerOffset = code.labelOffsetFromBase(veneer.anchor); + + if (veneerOffset >= minOffset && veneerOffset <= maxOffset) { + return veneer.anchor; + } + } else if (veneer.latestOffset <= maxOffset) { + return veneer.anchor; + } + } + + Label anchor; + + if (!labelName) { + anchor = a.newLabel(); + } else { + /* This is the entry label for a function. Create an unique + * name for the anchor label. It is necessary to include a + * sequence number in the label name because if the module is + * huge more than one veneer can be created for each entry + * label. */ + std::stringstream name; + name << '@' << labelName << '-' << labelSeq++; + anchor = a.newNamedLabel(name.str().c_str()); + } + + auto it = _veneers.emplace(target.id(), + Veneer{.latestOffset = maxOffset, + .anchor = anchor, + .target = target}); + + const Veneer &veneer = it->second; + _pending_veneers.emplace(veneer); + + return veneer.anchor; +} + +const Label &BeamModuleAssembler::resolve_fragment(void (*fragment)(), + enum Displacement disp) { + auto it = _dispatchTable.find(fragment); + + if (it == _dispatchTable.end()) { + it = _dispatchTable.emplace(fragment, a.newLabel()).first; + } + + return resolve_label(it->second, disp); +} + +arm::Mem BeamModuleAssembler::embed_constant(const ArgVal &value, + enum Displacement disp) { + ssize_t currOffset = a.offset(); + + ssize_t minOffset = currOffset - disp; + ssize_t maxOffset = currOffset + disp; + + ASSERT(disp >= dispMin && disp <= dispMax); + ASSERT(!value.isRegister()); + + /* If a previously embedded constant is reachable from this point, we + * can use it instead of creating a new one. */ + auto range = _constants.equal_range(value); + for (auto it = range.first; it != range.second; it++) { + const Constant &constant = it->second; + + if (code.isLabelBound(constant.anchor)) { + ssize_t constOffset = code.labelOffsetFromBase(constant.anchor); + + if (constOffset >= minOffset && constOffset <= maxOffset) { + return arm::Mem(constant.anchor); + } + } else if (constant.latestOffset <= maxOffset) { + return arm::Mem(constant.anchor); + } + } + + auto it = _constants.emplace(value, + Constant{.latestOffset = maxOffset, + .anchor = a.newLabel(), + .value = value}); + + const Constant &constant = it->second; + _pending_constants.emplace(constant); + + return arm::Mem(constant.anchor); +} + +void BeamModuleAssembler::emit_i_flush_stubs() { + /* Flush all stubs that are due within the next two check intervals + * to prevent them from being emitted inside function prologues or + * NIF padding. */ + flush_pending_stubs(STUB_CHECK_INTERVAL * 2); + last_stub_check_offset = a.offset(); +} + +void BeamModuleAssembler::check_pending_stubs() { + size_t currOffset = a.offset(); + + /* We shouldn't let too much space pass between checks. */ + ASSERT((last_stub_check_offset + dispMin) >= currOffset); + + if ((last_stub_check_offset + STUB_CHECK_INTERVAL) < currOffset) { + last_stub_check_offset = currOffset; + + flush_pending_stubs(STUB_CHECK_INTERVAL * 2); + } +} + +void BeamModuleAssembler::flush_pending_stubs(size_t range) { + ssize_t effective_offset = a.offset() + range; + Label next; + + while (!_pending_veneers.empty()) { + const Veneer &veneer = _pending_veneers.top(); + + if (veneer.latestOffset > effective_offset) { + break; + } + + if (!code.isLabelBound(veneer.anchor)) { + if (!next.isValid()) { + next = a.newLabel(); + + comment("Begin stub section"); + a.b(next); + } + + emit_veneer(veneer); + + effective_offset = a.offset() + range; + } + + _pending_veneers.pop(); + } + + while (!_pending_constants.empty()) { + const Constant &constant = _pending_constants.top(); + + if (constant.latestOffset > effective_offset) { + break; + } + + /* Unlike veneers, we never bind constants ahead of time. */ + ASSERT(!code.isLabelBound(constant.anchor)); + + if (!next.isValid()) { + next = a.newLabel(); + + comment("Begin stub section"); + a.b(next); + } + + emit_constant(constant); + + effective_offset = a.offset() + range; + + _pending_constants.pop(); + } + + if (next.isValid()) { + comment("End stub section"); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_veneer(const Veneer &veneer) { + const Label &anchor = veneer.anchor; + const Label &target = veneer.target; + bool directBranch; + + ASSERT(!code.isLabelBound(anchor)); + a.bind(anchor); + + /* Prefer direct branches when possible. */ + if (code.isLabelBound(target)) { + auto targetOffset = code.labelOffsetFromBase(target); + directBranch = (a.offset() - targetOffset) <= disp128MB; + } else { + directBranch = false; + } + +#ifdef DEBUG + directBranch &= (a.offset() % 512) >= 256; +#endif + + if (ERTS_LIKELY(directBranch)) { + a.b(target); + } else { + Label pointer = a.newLabel(); + + a.ldr(SUPER_TMP, arm::Mem(pointer)); + a.br(SUPER_TMP); + + a.align(AlignMode::kCode, 8); + a.bind(pointer); + a.embedLabel(veneer.target); + } +} + +void BeamModuleAssembler::emit_constant(const Constant &constant) { + const Label &anchor = constant.anchor; + const ArgVal &value = constant.value; + + ASSERT(!code.isLabelBound(anchor)); + a.align(AlignMode::kData, 8); + a.bind(anchor); + + ASSERT(!value.isRegister()); + + if (value.isImmed()) { + a.embedUInt64(value.as().get()); + } else if (value.isWord()) { + a.embedUInt64(value.as().get()); + } else if (value.isLabel()) { + a.embedLabel(rawLabels.at(value.as().get())); + } else { + switch (value.getType()) { + case ArgVal::BytePtr: + strings.push_back({anchor, 0, value.as().get()}); + a.embedUInt64(LLONG_MAX); + break; + case ArgVal::Catch: { + auto handler = rawLabels[value.as().get()]; + catches.push_back({{anchor, 0, 0}, handler}); + + /* Catches are limited to 32 bits, but since we don't want to load + * 32-bit argument values due to displacement limits, we'll store + * this as a 64-bit value with the upper bits cleared. */ + a.embedUInt64(INT_MAX); + break; + } + case ArgVal::Export: { + auto index = value.as().get(); + imports[index].patches.push_back({anchor, 0, 0}); + a.embedUInt64(LLONG_MAX); + break; + } + case ArgVal::FunEntry: { + auto index = value.as().get(); + lambdas[index].patches.push_back({anchor, 0, 0}); + a.embedUInt64(LLONG_MAX); + break; + } + case ArgVal::Literal: { + auto index = value.as().get(); + literals[index].patches.push_back({anchor, 0, 0}); + a.embedUInt64(LLONG_MAX); + break; + } + default: + ASSERT(!"error"); + } + } +} diff --git a/erts/emulator/beam/jit/arm/generators.tab b/erts/emulator/beam/jit/arm/generators.tab new file mode 100644 index 000000000000..2ae1582d4bb5 --- /dev/null +++ b/erts/emulator/beam/jit/arm/generators.tab @@ -0,0 +1,641 @@ +// -*- c -*- +// +// %CopyrightBegin% +// +// Copyright Ericsson AB 2020-2023. 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% +// + +gen.select_tuple_arity(Src, Fail, Size, Rest) { + BeamOp* op; + BeamOpArg *tmp; + int size = Size.val / 2; + int arity = Size.val + 3; + int i, j; + + /* Verify the validity of the list. */ + if (Size.val % 2 != 0) { + return NULL; + } + + for (i = 0; i < Size.val; i += 2) { + if (Rest[i].type != TAG_u || Rest[i+1].type != TAG_f) { + return NULL; + } + } + + /* + * Generate the generic instruction. + * Assumption: + * Few different tuple arities to select on (fewer than 20). + * Use linear scan approach. + */ + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_select_tuple_arity, 3); + $BeamOpArity(op, arity); + op->next = NULL; + op->a[0] = Src; + op->a[1] = Fail; + + /* Variable argument count */ + op->a[2].type = TAG_u; + op->a[2].val = Size.val; + + tmp = (BeamOpArg*)erts_alloc(ERTS_ALC_T_LOADER_TMP, + sizeof(BeamOpArg) * arity); + + for (i = 3; i < arity; i += 2) { + tmp[i - 2] = Rest[i - 2]; + tmp[i - 3].type = TAG_v; + tmp[i - 3].val = make_arityval_unchecked(Rest[i - 3].val); + } + + /* Sort the values to make them useful for a binary or sentinel search. */ + beam_load_sort_select_vals(tmp, size); + + j = 3; + for (i = 3; i < arity; i += 2) { + op->a[j + size] = tmp[i - 2]; + op->a[j] = tmp[i - 3]; + j++; + } + + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) tmp); + + return op; +} + +gen.split_values(Src, TypeFail, Fail, Size, Rest) { + BeamOp* op1; + BeamOp* op2; + BeamOp* is_integer; + int i; + + ASSERT(Size.val >= 2 && Size.val % 2 == 0); + + $NewBeamOp(S, is_integer); + $BeamOpNameArity(is_integer, is_integer, 2); + is_integer->a[0] = TypeFail; + is_integer->a[1] = Src; + + $NewBeamOp(S, op1); + $BeamOpNameArity(op1, select_val, 3); + $BeamOpArity(op1, 3 + Size.val); + op1->a[0] = Src; + /* We use [] instead of a failure label to indicate a fallthrough + * to next instruction if none of the values match. That way, we + * don't have to create a new label dynamically, which would be + * tricky in BeamAsm. */ + op1->a[1].type = TAG_n; + op1->a[1].val = 0; + op1->a[2].type = TAG_u; + op1->a[2].val = 0; + + $NewBeamOp(S, op2); + $BeamOpNameArity(op2, select_val, 3); + $BeamOpArity(op2, 3 + Size.val); + op2->a[0] = Src; + op2->a[1] = Fail; + op2->a[2].type = TAG_u; + op2->a[2].val = 0; + + /* + * Split the list. + */ + + ASSERT(Size.type == TAG_u); + for (i = 0; i < Size.val; i += 2) { + BeamOp* op = (Rest[i].type == TAG_q) ? op2 : op1; + int dst = 3 + op->a[2].val; + + ASSERT(Rest[i+1].type == TAG_f); + op->a[dst] = Rest[i]; + op->a[dst+1] = Rest[i+1]; + op->arity += 2; + op->a[2].val += 2; + } + ASSERT(op1->a[2].val > 0); + ASSERT(op2->a[2].val > 0); + + /* + * Order the instruction sequence appropriately. + */ + + if (TypeFail.val == Fail.val) { + /* + * select_val Src [] S ... (small numbers) + * is_integer Fail S + * select_val Src Fail S ... (bignums) + */ + op1->next = is_integer; + is_integer->next = op2; + } else { + /* + * is_integer TypeFail S + * select_val Src [] S ... (small numbers) + * select_val Src Fail S ... (bignums) + */ + is_integer->next = op1; + op1->next = op2; + op1 = is_integer; + } + op2->next = NULL; + + return op1; +} + +// +// Generate a select_val instruction. We know that a jump table +// is not suitable, and that all values are of the same type +// (integer or atoms). +// +gen.select_val(Src, Fail, Size, Rest) { + BeamOp* op; + BeamOpArg *tmp; + int arity = Size.val + 3; + int size = Size.val / 2; + int i, j; + + $NewBeamOp(S, op); + op->next = NULL; + + /* Use linear search for small search spaces */ + if (size <= 10) { + $BeamOpNameArity(op, i_select_val_lins, 3); + } else { + $BeamOpNameArity(op, i_select_val_bins, 3); + } + + $BeamOpArity(op, arity); + op->a[0] = Src; + op->a[1] = Fail; + + /* Variable argument count */ + op->a[2].type = TAG_u; + op->a[2].val = Size.val; + + tmp = (BeamOpArg *) erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(BeamOpArg)*(arity)); + + for (i = 3; i < arity; i++) { + tmp[i-3] = Rest[i-3]; + } + + /* Sort the values to make them useful for a binary or sentinel search. */ + beam_load_sort_select_vals(tmp, size); + + j = 3; + for (i = 3; i < arity; i += 2) { + op->a[j] = tmp[i-3]; + op->a[j+size] = tmp[i-2]; + j++; + } + + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) tmp); + +#ifdef DEBUG + for (i = 0; i < size - 1; i++) { + ASSERT(op->a[i+3].val <= op->a[i+4].val); + } +#endif + + return op; +} + +// +// Generate a select_val instruction for big numbers. +// +gen.select_literals(Src, Fail, Size, Rest) { + BeamOp* op; + BeamOp* jump; + BeamOp** prev_next = &op; + + int i; + + for (i = 0; i < Size.val; i += 2) { + BeamOp* op; + ASSERT(Rest[i].type == TAG_q); + + $NewBeamOp(S, op); + $BeamOpNameArity(op, is_ne_exact, 3); + op->a[0] = Rest[i+1]; + op->a[1] = Src; + op->a[2] = Rest[i]; + *prev_next = op; + prev_next = &op->next; + } + + $NewBeamOp(S, jump); + $BeamOpNameArity(jump, jump, 1); + jump->next = NULL; + jump->a[0] = Fail; + *prev_next = jump; + return op; +} + +gen.new_small_map_lit(Dst, Live, Size, Rest) { + unsigned size = Size.val; + Uint lit; + unsigned i; + BeamOp* op; + BeamOpArg* dst; + Eterm* tmp; + Eterm* thp; + Eterm keys; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_new_small_map_lit, 4); + $BeamOpArity(op, 4 + size/2); + op->next = NULL; + + tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, ((size == 0 ? 0 : 1) + size/2) * sizeof(*tmp)); + if (size == 0) { + keys = erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); + } else { + keys = make_tuple(thp); + *thp++ = make_arityval(size/2); + } + + dst = op->a+4; + + for (i = 0; i < size; i += 2) { + switch (Rest[i].type) { + case TAG_a: + *thp++ = Rest[i].val; + ASSERT(is_atom(Rest[i].val)); + break; + case TAG_i: + *thp++ = make_small(Rest[i].val); + break; + case TAG_n: + *thp++ = NIL; + break; + case TAG_q: + *thp++ = beamfile_get_literal(&S->beam, Rest[i].val); + break; + } + *dst++ = Rest[i + 1]; + } + + lit = beamfile_add_literal(&S->beam, keys, 1); + erts_free(ERTS_ALC_T_LOADER_TMP, tmp); + + op->a[0] = Dst; + op->a[1] = Live; + op->a[2].type = TAG_q; + op->a[2].val = lit; + op->a[3].type = TAG_u; + op->a[3].val = size / 2; + + return op; +} + +// Generate the fastest instruction to fetch a binary from a binary. +gen.get_binary2(Fail, Ms, Live, Size, Unit, Flags, Dst) { + BeamOp* op; + + $NewBeamOp(S, op); + $NativeEndian(Flags); + + if (Size.type == TAG_a && Size.val == am_all) { + $BeamOpNameArity(op, i_bs_get_binary_all2, 5); + op->a[0] = Ms; + op->a[1] = Fail; + op->a[2] = Live; + op->a[3] = Unit; + op->a[4] = Dst; + } else { + $BeamOpNameArity(op, i_bs_get_binary2, 6); + op->a[0] = Ms; + op->a[1] = Fail; + op->a[2] = Live; + op->a[3] = Size; + op->a[4].type = TAG_u; + op->a[4].val = (Unit.val << 3) | Flags.val; + op->a[5] = Dst; + } + + op->next = NULL; + return op; +} + +gen.skip_utf16(Fail, Ms, Flags) { + BeamOp* op; + $NewBeamOp(S, op); + + $NativeEndian(Flags); + $BeamOpNameArity(op, i_bs_skip_utf16, 3); + op->a[0] = Ms; + op->a[1] = Fail; + op->a[2] = Flags; + return op; +} + +gen.allocate_heap_zero(Ns, Nh, Live) { + BeamOp* alloc; + BeamOp* init; + int i; + + $NewBeamOp(S, alloc); + $NewBeamOp(S, init); + + $BeamOpNameArity(alloc, allocate_heap, 3); + alloc->a[0] = Ns; + alloc->a[1] = Nh; + alloc->a[2] = Live; + alloc->next = init; + + $BeamOpNameArity(init, init_yregs, 1); + $BeamOpArity(init, Ns.val+1); + init->a[0] = Ns; + for (i = 0; i < Ns.val; i++) { + init->a[i+1].type = TAG_y; + init->a[i+1].val = i; + } + + return alloc; +} + +gen.jump_tab(Src, Fail, Size, Rest) { + Sint min, max; + Sint i; + Sint size; + Sint arity; + int fixed_args; + BeamOp* op; + + /* + * The rule in ops.tab must ensure that there are more than + * two values. + */ + ASSERT(Size.val > 2); + ASSERT(Size.val % 2 == 0); + + /* Calculate the minimum and maximum values and size of jump table. */ + ASSERT(Rest[0].type == TAG_i); + min = max = Rest[0].val; + for (i = 2; i < Size.val; i += 2) { + ASSERT(Rest[i].type == TAG_i && Rest[i+1].type == TAG_f); + if (Rest[i].val < min) { + min = Rest[i].val; + } else if (max < Rest[i].val) { + max = Rest[i].val; + } + } + size = max - min + 1; + + /* Allocate structure and fill in the fixed fields. */ + $NewBeamOp(S, op); + op->next = NULL; + $BeamOpNameArity(op, i_jump_on_val, 4); + fixed_args = op->arity; + arity = fixed_args + size; + $BeamOpArity(op, arity); + op->a[0] = Src; + op->a[1] = Fail; + op->a[2].type = TAG_u; + op->a[2].val = min; + op->a[3].type = TAG_u; + op->a[3].val = size; + + /* Fill in the jump table. */ + for (i = fixed_args; i < arity; i++) { + op->a[i] = Fail; + } + + for (i = 0; i < Size.val; i += 2) { + Sint index = fixed_args + Rest[i].val - min; + ASSERT(fixed_args <= index && index < arity); + op->a[index] = Rest[i+1]; + } + + return op; +} + +gen.func_end(Func_Label, Entry_Label) { + BeamOp *op = NULL; + + if (S->labels[Entry_Label.val].lambda_index != -1) { + int index = S->labels[Entry_Label.val].lambda_index; + BeamFile_LambdaEntry *lambda_entry; + + lambda_entry = &S->beam.lambdas.entries[index]; + + if (lambda_entry->num_free > 0) { + BeamOp *lambda; + + $NewBeamOp(S, lambda); + $BeamOpNameArity(lambda, i_lambda_trampoline, 4); + + lambda->a[0].type = TAG_u; + lambda->a[0].val = index; + lambda->a[1] = Entry_Label; + lambda->a[2].type = TAG_u; + lambda->a[2].val = lambda_entry->arity; + lambda->a[3].type = TAG_u; + lambda->a[3].val = lambda_entry->num_free; + + lambda->next = op; + op = lambda; + } + } + + if (S->may_load_nif && (S->load_hdr->are_nifs == NULL || + S->load_hdr->are_nifs[S->function_number-1])) { + BeamOp *padding; + + $NewBeamOp(S, padding); + $BeamOpNameArity(padding, i_nif_padding, 0); + + padding->next = op; + op = padding; + } + + if (op == NULL) { + /* Workaround for the fact that we have to return an instruction from + * generators. The loader will remove this dummy instruction. */ + $NewBeamOp(S, op); + $BeamOpNameArity(op, delete_me, 0); + + op->next = NULL; + } + + return op; +} + +gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { + BeamOp* op; + int fixed_args; + int i; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_create_bin, 4); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Alloc; + op->a[2] = Live; + op->a[3] = Dst; + + for (i = 0; i < N.val; i += 6) { + BeamOpArg Flags; + Uint flags = 0; + + /* Copy all but flags. */ + op->a[i+fixed_args+0] = Segments[i+0]; + op->a[i+fixed_args+1] = Segments[i+1]; + op->a[i+fixed_args+2] = Segments[i+2]; + op->a[i+fixed_args+4] = Segments[i+4]; + op->a[i+fixed_args+5] = Segments[i+5]; + + /* Translate flags. */ + Flags = Segments[i+3]; /* Flags */ + if (Flags.type != TAG_n) { + if (Flags.type == TAG_q) { + Eterm term = beamfile_get_literal(&S->beam, Flags.val); + while (is_list(term)) { + Eterm* consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + flags |= BSF_LITTLE; + break; + case am_native: + flags |= BSF_NATIVE; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + } + } + Flags.type = TAG_u; + Flags.val = flags; + $NativeEndian(Flags); + op->a[i+fixed_args+3] = Flags; + + /* + * Replace short string segments with integer segments. + * Integer segments can be combined with adjacent integer + * segments for better performance. + */ + if (op->a[i+fixed_args+0].val == am_string) { + Sint num_chars = op->a[i+fixed_args+5].val; + if (num_chars <= 4) { + Sint index = op->a[i+fixed_args+4].val; + const byte* s = S->beam.strings.data + index; + Uint num = 0; + op->a[i+fixed_args+0].val = am_integer; + op->a[i+fixed_args+2].val = 8; + op->a[i+fixed_args+5].val = num_chars; + while (num_chars-- > 0) { + num = num << 8 | *s++; + } + op->a[i+fixed_args+4].type = TAG_i; + op->a[i+fixed_args+4].val = num; + } + } + } + + if (op->a[4].val == am_private_append && Alloc.val != 0) { + BeamOp* th; + $NewBeamOp(S, th); + $BeamOpNameArity(th, test_heap, 2); + th->a[0] = Alloc; + th->a[1] = Live; + th->next = op; + + op->a[1].val = 0; + + op = th; + } + + return op; +} + +gen.bs_match(Fail, Ctx, N, List) { + BeamOp* op; + int fixed_args; + int i; + + /* + * If a BEAM file produced by a later version of Erlang/OTP + * is accidentally loaded into an earlier version, ensure + * that the loading fails (as opposed to crashing the runtime) + * if there are any unknown sub commands. + */ + i = 0; + while (i < N.val) { + BeamOpArg current = List[i++]; + + if (current.type != TAG_a) { + goto error; + } + + switch (current.val) { + case am_ensure_exactly: + case am_skip: + i += 1; + break; + case am_ensure_at_least: + i += 2; + break; + case am_get_tail: + case am_Eq: + i += 3; + break; + case am_binary: + case am_integer: + i += 5; + break; + default: { + error: + $NewBeamOp(S, op); + $BeamOpNameArity(op, bad_bs_match, 1); + op->a[0] = current; + return op; + } + } + } + + /* + * Make sure that we don't attempt to pass any overflow tags to the JIT. + */ + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_match, 2); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Ctx; + + for (i = 0; i < N.val; i++) { + BeamOpArg current; + + current = List[i]; + if (current.type == TAG_o) { + /* An overflow tag (in ensure_at_least or ensure_exactly) + * means that the match will always fail. */ + $BeamOpNameArity(op, jump, 1); + op->a[0] = Fail; + return op; + } + op->a[i+fixed_args] = current; + } + + return op; +} diff --git a/erts/emulator/beam/jit/arm/instr_arith.cpp b/erts/emulator/beam/jit/arm/instr_arith.cpp new file mode 100644 index 000000000000..485f93956d1e --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_arith.cpp @@ -0,0 +1,1451 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "erl_bif_table.h" +#include "big.h" +} + +void BeamModuleAssembler::emit_add_sub_types(bool is_small_result, + const ArgSource &LHS, + const a64::Gp lhs_reg, + const ArgSource &RHS, + const a64::Gp rhs_reg, + const Label next) { + if (exact_type(LHS) && + exact_type(RHS) && is_small_result) { + comment("skipped overflow test because the result is always small"); + emit_are_both_small(LHS, lhs_reg, RHS, rhs_reg, next); + } else { + if (always_small(RHS)) { + a.and_(TMP1, lhs_reg, imm(_TAG_IMMED1_MASK)); + } else if (always_small(LHS)) { + a.and_(TMP1, rhs_reg, imm(_TAG_IMMED1_MASK)); + } else { + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs_reg, rhs_reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + } + + comment("test for not overflow and small operands"); + a.ccmp(TMP1, + imm(_TAG_IMMED1_SMALL), + imm(NZCV::kNone), + imm(arm::CondCode::kVC)); + a.b_eq(next); + } +} + +void BeamModuleAssembler::emit_are_both_small(const ArgSource &LHS, + const a64::Gp lhs_reg, + const ArgSource &RHS, + const a64::Gp rhs_reg, + const Label next) { + if (always_small(RHS) && + always_one_of(LHS)) { + comment("simplified test for small operand since other types are " + "boxed"); + emit_is_boxed(next, lhs_reg); + } else if (always_small(LHS) && + always_one_of( + RHS)) { + comment("simplified test for small operand since other types are " + "boxed"); + emit_is_boxed(next, rhs_reg); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + comment("simplified test for small operands since other types are " + "boxed"); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs_reg, rhs_reg); + emit_is_boxed(next, TMP1); + } else { + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs_reg, rhs_reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_eq(next); + } +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_plus_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_Plus, 2}; + + Label error = a.newLabel(); + + /* Save original arguments for the error path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + + emit_enter_runtime_frame(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_plus); + + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + + a.ret(a64::x30); + + a.bind(error); + { + /* emit_enter_runtime() was done in the module code. */ + emit_leave_runtime(0); + + /* Place the original arguments in X registers. */ + a.ldp(XREG0, XREG1, TMP_MEM1q); + mov_imm(ARG4, &bif_mfa); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_plus(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + bool rhs_is_arm_literal = + RHS.isSmall() && Support::isUInt12(RHS.as().get()); + bool is_small_result = is_sum_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && is_small_result) { + auto dst = init_destination(Dst, ARG1); + if (rhs_is_arm_literal) { + auto lhs = load_source(LHS, ARG2); + Uint cleared_tag = RHS.as().get() & ~_TAG_IMMED1_MASK; + comment("add small constant without overflow check"); + a.add(dst.reg, lhs.reg, imm(cleared_tag)); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + comment("addition without overflow check"); + a.and_(TMP1, rhs.reg, imm(~_TAG_IMMED1_MASK)); + a.add(dst.reg, lhs.reg, TMP1); + } + flush_var(dst); + return; + } + + Label next = a.newLabel(); + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + + if (rhs_is_arm_literal) { + Uint cleared_tag = RHS.as().get() & ~_TAG_IMMED1_MASK; + a.adds(ARG1, lhs.reg, imm(cleared_tag)); + } else { + a.and_(TMP1, rhs.reg, imm(~_TAG_IMMED1_MASK)); + a.adds(ARG1, lhs.reg, TMP1); + } + + emit_add_sub_types(is_small_result, LHS, lhs.reg, RHS, rhs.reg, next); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_plus); + emit_leave_runtime(Live.get()); + + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_plus_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_arg(Dst, ARG1); +} + +/* + * ARG2 = Src + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_unary_minus_body_shared() { + Label error = a.newLabel(); + + /* Save original argument for the error path. */ + a.str(ARG2, TMP_MEM1q); + + emit_enter_runtime_frame(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_unary_minus); + + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + + a.ret(a64::x30); + + a.bind(error); + { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_Minus, 1}; + + /* emit_enter_runtime() was done in the module code. */ + emit_leave_runtime(0); + + /* Place the original argument in an X registers. */ + a.ldr(XREG0, TMP_MEM1q); + mov_imm(ARG4, &bif_mfa); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_unary_minus(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Src, + const ArgRegister &Dst) { + auto src = load_source(Src, ARG2); + auto zero = ArgImmed(make_small(0)); + bool is_small_result = is_diff_small_if_args_are_small(zero, Src); + + a.mov(TMP1, imm(_TAG_IMMED1_SMALL)); + a.and_(TMP2, src.reg, imm(~_TAG_IMMED1_MASK)); + + if (always_small(Src) && is_small_result) { + auto dst = init_destination(Dst, ARG1); + comment("no overflow test because result is always small"); + a.sub(dst.reg, TMP1, TMP2); + flush_var(dst); + return; + } + + Label next = a.newLabel(); + + a.subs(ARG1, TMP1, TMP2); + + /* Test for not overflow AND small operands. */ + a.ccmp(TMP2, + imm(_TAG_IMMED1_SMALL), + imm(NZCV::kNone), + imm(arm::CondCode::kVC)); + a.b_eq(next); + + mov_var(ARG2, src); + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<2>(erts_unary_minus); + emit_leave_runtime(Live.get()); + + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_unary_minus_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_arg(Dst, ARG1); +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_minus_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_Minus, 2}; + + Label error = a.newLabel(); + + /* Save original arguments for the error path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + + emit_enter_runtime_frame(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_minus); + + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + + a.ret(a64::x30); + + a.bind(error); + { + /* emit_enter_runtime() was done in the module code. */ + emit_leave_runtime(0); + + /* Place the original arguments in X registers. */ + a.ldp(XREG0, XREG1, TMP_MEM1q); + mov_imm(ARG4, &bif_mfa); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_minus(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + bool rhs_is_arm_literal = + RHS.isSmall() && Support::isUInt12(RHS.as().get()); + bool is_small_result = is_diff_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && is_small_result) { + auto dst = init_destination(Dst, ARG1); + if (rhs_is_arm_literal) { + auto lhs = load_source(LHS, ARG2); + Uint cleared_tag = RHS.as().get() & ~_TAG_IMMED1_MASK; + comment("subtract small constant without overflow check"); + a.sub(dst.reg, lhs.reg, imm(cleared_tag)); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + comment("subtraction without overflow check"); + a.and_(TMP1, rhs.reg, imm(~_TAG_IMMED1_MASK)); + a.sub(dst.reg, lhs.reg, TMP1); + } + flush_var(dst); + return; + } + + Label next = a.newLabel(); + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + + if (rhs_is_arm_literal) { + Uint cleared_tag = RHS.as().get() & ~_TAG_IMMED1_MASK; + a.subs(ARG1, lhs.reg, imm(cleared_tag)); + } else { + a.and_(TMP1, rhs.reg, imm(~_TAG_IMMED1_MASK)); + a.subs(ARG1, lhs.reg, TMP1); + } + + emit_add_sub_types(is_small_result, LHS, lhs.reg, RHS, rhs.reg, next); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_minus); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_minus_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_arg(Dst, ARG1); +} + +/* ARG2 = LHS + * ARG3 = RHS + * + * The result is returned in ARG1 (set to THE_NON_VALUE if + * the call failed). + */ +void BeamGlobalAssembler::emit_times_guard_shared() { + Label generic = a.newLabel(); + + /* Speculatively untag and multiply. */ + a.and_(TMP1, ARG2, imm(~_TAG_IMMED1_MASK)); + a.asr(TMP2, ARG3, imm(_TAG_IMMED1_SIZE)); + a.mul(TMP3, TMP1, TMP2); + a.smulh(TMP4, TMP1, TMP2); + + /* Check that both operands are small integers. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + /* The high 65 bits of result will all be the same if no overflow + * occurred. Another way to say that is that the sign bit of the + * low 64 bits repeated 64 times must be equal to the high 64 bits + * of the product. */ + a.cmp(TMP4, TMP3, arm::asr(63)); + a.b_ne(generic); + + a.orr(ARG1, TMP3, imm(_TAG_IMMED1_SMALL)); + a.ret(a64::x30); + + a.bind(generic); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_times); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +/* ARG2 = LHS + * ARG3 = RHS + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_times_body_shared() { + Label generic = a.newLabel(), error = a.newLabel(); + + /* Speculatively untag and multiply. */ + a.and_(TMP1, ARG2, imm(~_TAG_IMMED1_MASK)); + a.asr(TMP2, ARG3, imm(_TAG_IMMED1_SIZE)); + a.mul(TMP3, TMP1, TMP2); + a.smulh(TMP4, TMP1, TMP2); + + /* Check that both operands are integers. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + /* The high 65 bits of result will all be the same if no overflow + * occurred. Another way to say that is that the sign bit of the + * low 64 bits repeated 64 times must be equal to the high 64 bits + * of the product. */ + a.cmp(TMP4, TMP3, arm::asr(63)); + a.b_ne(generic); + + a.orr(ARG1, TMP3, imm(_TAG_IMMED1_SMALL)); + a.ret(a64::x30); + + a.bind(generic); + + /* Save original arguments for the error path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_times); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + + a.ret(a64::x30); + + a.bind(error); + { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_Times, 2}; + + /* Place the original arguments in x-registers. */ + a.ldp(XREG0, XREG1, TMP_MEM1q); + mov_imm(ARG4, &bif_mfa); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_times(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + bool is_small_result = is_product_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && is_small_result) { + auto dst = init_destination(Dst, ARG1); + comment("multiplication without overflow check"); + if (RHS.isSmall()) { + auto lhs = load_source(LHS, ARG2); + Sint factor = RHS.as().getSigned(); + + a.and_(TMP1, lhs.reg, imm(~_TAG_IMMED1_MASK)); + if (Support::isPowerOf2(factor)) { + int trailing_bits = Support::ctz(factor); + comment("optimized multiplication by replacing with left " + "shift"); + a.lsl(TMP1, TMP1, imm(trailing_bits)); + } else { + mov_imm(TMP2, factor); + a.mul(TMP1, TMP1, TMP2); + } + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + a.and_(TMP1, lhs.reg, imm(~_TAG_IMMED1_MASK)); + a.asr(TMP2, rhs.reg, imm(_TAG_IMMED1_SIZE)); + a.mul(TMP1, TMP1, TMP2); + } + a.orr(dst.reg, TMP1, imm(_TAG_IMMED1_SMALL)); + flush_var(dst); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + fragment_call(ga->get_times_guard_shared()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + fragment_call(ga->get_times_body_shared()); + } + + mov_arg(Dst, ARG1); + } +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * Quotient is returned in ARG1, remainder in ARG2. + * Error is indicated by the Z flag. + */ +void BeamGlobalAssembler::emit_int_div_rem_guard_shared() { + Label exit = a.newLabel(), generic = a.newLabel(); + + /* Speculatively go ahead with the division. */ + a.asr(TMP1, ARG2, imm(_TAG_IMMED1_SIZE)); + a.asr(TMP2, ARG3, imm(_TAG_IMMED1_SIZE)); + a.sdiv(TMP3, TMP1, TMP2); + a.msub(TMP4, TMP3, TMP2, TMP1); + + a.cmp(ARG3, imm(make_small(0))); + a.b_eq(exit); + + /* Check whether both operands are small integers. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + /* MIN_SMALL divided by -1 will overflow, and we'll need to fall + * back to the generic handler in that case. */ + a.asr(TMP1, TMP3, imm(SMALL_BITS - 1)); + a.cmp(TMP1, imm(1)); + a.b_ge(generic); + + /* The Z flag is now clear (meaning no error). */ + + mov_imm(TMP1, _TAG_IMMED1_SMALL); + arm::Shift tagShift = arm::lsl(_TAG_IMMED1_SIZE); + a.orr(ARG1, TMP1, TMP3, tagShift); + a.orr(ARG2, TMP1, TMP4, tagShift); + + a.bind(exit); + { a.ret(a64::x30); } + + a.bind(generic); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + lea(ARG4, TMP_MEM4q); + lea(ARG5, TMP_MEM5q); + runtime_call<5>(erts_int_div_rem); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.tst(ARG1, ARG1); + a.ldp(ARG1, ARG2, TMP_MEM4q); + + a.ret(a64::x30); + } +} + +/* ARG2 = LHS + * ARG3 = RHS + * ARG4 = error MFA + * + * Quotient is returned in ARG1, remainder in ARG2. + */ +void BeamGlobalAssembler::emit_int_div_rem_body_shared() { + Label div_zero = a.newLabel(), generic_div = a.newLabel(), + generic_error = a.newLabel(); + + /* Speculatively go ahead with the division. */ + a.asr(TMP1, ARG2, imm(_TAG_IMMED1_SIZE)); + a.asr(TMP2, ARG3, imm(_TAG_IMMED1_SIZE)); + a.sdiv(TMP3, TMP1, TMP2); + a.msub(TMP4, TMP3, TMP2, TMP1); + + a.cmp(ARG3, imm(make_small(0))); + a.b_eq(div_zero); + + /* Check whether both operands are small integers. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic_div); + + /* MIN_SMALL divided by -1 will overflow, and we'll need to fall + * back to the generic handler in that case. */ + a.asr(TMP1, TMP3, imm(SMALL_BITS - 1)); + a.cmp(TMP1, imm(1)); + a.b_ge(generic_div); + + mov_imm(TMP1, _TAG_IMMED1_SMALL); + arm::Shift tagShift = arm::lsl(_TAG_IMMED1_SIZE); + a.orr(ARG1, TMP1, TMP3, tagShift); + a.orr(ARG2, TMP1, TMP4, tagShift); + + a.ret(a64::x30); + + a.bind(generic_div); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + /* Save MFA and original arguments for the error path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + a.str(ARG4, TMP_MEM3q); + + a.mov(ARG1, c_p); + lea(ARG4, TMP_MEM4q); + lea(ARG5, TMP_MEM5q); + runtime_call<5>(erts_int_div_rem); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.tst(ARG1, ARG1); + a.ldp(ARG1, ARG2, TMP_MEM4q); + a.b_eq(generic_error); + + a.ret(a64::x30); + } + + a.bind(div_zero); + { + mov_imm(TMP1, EXC_BADARITH); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.mov(XREG0, ARG2); + a.mov(XREG1, ARG3); + a.b(labels[raise_exception]); + } + + a.bind(generic_error); + { + a.ldp(XREG0, XREG1, TMP_MEM1q); + a.ldr(ARG4, TMP_MEM3q); // MFA + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_div_rem(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ErtsCodeMFA *error_mfa, + const ArgRegister &Quotient, + const ArgRegister &Remainder, + bool need_div, + bool need_rem) { + Sint divisor = 0; + + if (RHS.isSmall()) { + divisor = RHS.as().getSigned(); + } + + if (always_small(LHS) && divisor != (Sint)0 && divisor != (Sint)-1) { + auto lhs = load_source(LHS, ARG3); + auto quotient = init_destination(Quotient, ARG1); + auto remainder = init_destination(Remainder, ARG2); + + comment("skipped test for smalls operands and overflow"); + if (Support::isPowerOf2(divisor) && + std::get<0>(getClampedRange(LHS)) >= 0) { + int trailing_bits = Support::ctz(divisor); + arm::Gp LHS_reg = lhs.reg; + if (need_div) { + comment("optimized div by replacing with right shift"); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + if (need_rem && quotient.reg == lhs.reg) { + LHS_reg = TMP1; + a.mov(LHS_reg, lhs.reg); + } + a.lsr(quotient.reg, lhs.reg, imm(trailing_bits)); + a.orr(quotient.reg, quotient.reg, imm(_TAG_IMMED1_SMALL)); + } + if (need_rem) { + comment("optimized rem by replacing with masking"); + auto mask = Support::lsbMask(trailing_bits + + _TAG_IMMED1_SIZE); + a.and_(remainder.reg, LHS_reg, imm(mask)); + } + } else { + a.asr(TMP1, lhs.reg, imm(_TAG_IMMED1_SIZE)); + mov_imm(TMP2, divisor); + a.sdiv(quotient.reg, TMP1, TMP2); + if (need_rem) { + a.msub(remainder.reg, quotient.reg, TMP2, TMP1); + } + + mov_imm(TMP3, _TAG_IMMED1_SMALL); + const arm::Shift tagShift = arm::lsl(_TAG_IMMED1_SIZE); + if (need_div) { + a.orr(quotient.reg, TMP3, quotient.reg, tagShift); + } + if (need_rem) { + a.orr(remainder.reg, TMP3, remainder.reg, tagShift); + } + } + + if (need_div) { + flush_var(quotient); + } + if (need_rem) { + flush_var(remainder); + } + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + fragment_call(ga->get_int_div_rem_guard_shared()); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + } else { + a.mov(ARG4, imm(error_mfa)); + fragment_call(ga->get_int_div_rem_body_shared()); + } + + if (need_div) { + mov_arg(Quotient, ARG1); + } + if (need_rem) { + mov_arg(Remainder, ARG2); + } + } +} + +void BeamModuleAssembler::emit_i_rem_div(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Remainder, + const ArgRegister &Quotient) { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_rem, 2}; + bool need_rem = Quotient != Remainder; + + emit_div_rem(Fail, LHS, RHS, &bif_mfa, Quotient, Remainder, true, need_rem); +} + +void BeamModuleAssembler::emit_i_div_rem(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Quotient, + const ArgRegister &Remainder) { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_div, 2}; + bool need_div = Quotient != Remainder; + + emit_div_rem(Fail, LHS, RHS, &bif_mfa, Quotient, Remainder, need_div, true); +} + +void BeamModuleAssembler::emit_i_int_div(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Quotient) { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_div, 2}; + ArgYRegister Dummy(0); + + emit_div_rem(Fail, LHS, RHS, &bif_mfa, Quotient, Dummy, true, false); +} + +void BeamModuleAssembler::emit_i_rem(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Remainder) { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_rem, 2}; + ArgYRegister Dummy(0); + + emit_div_rem(Fail, LHS, RHS, &bif_mfa, Dummy, Remainder, false, true); +} + +void BeamModuleAssembler::emit_i_m_div(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_Div, 2}; + + Label next = a.newLabel(); + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_div); + + emit_leave_runtime(Live.get()); + + a.cmp(ARG1, imm(THE_NON_VALUE)); + + if (Fail.get() != 0) { + a.b_eq(resolve_beam_label(Fail, disp1MB)); + } else { + a.b_ne(next); + + mov_arg(XREG0, LHS); + mov_arg(XREG1, RHS); + + emit_raise_exception(&bif_mfa); + } + + a.bind(next); + mov_arg(Dst, ARG1); +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +template +void BeamGlobalAssembler::emit_bitwise_fallback_body(T(*func_ptr), + const ErtsCodeMFA *mfa) { + Label error = a.newLabel(); + + emit_enter_runtime_frame(); + + /* Save original arguments for the error path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + + a.mov(ARG1, c_p); + runtime_call<3>(func_ptr); + + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + + a.ret(a64::x30); + + a.bind(error); + { + /* emit_enter_runtime() was done in the module code. */ + emit_leave_runtime(0); + + /* Place the original arguments in X registers. */ + a.ldp(XREG0, XREG1, TMP_MEM1q); + a.mov(ARG4, imm(mfa)); + a.b(labels[raise_exception]); + } +} + +void BeamGlobalAssembler::emit_i_band_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_band, 2}; + emit_bitwise_fallback_body(erts_band, &bif_mfa); +} + +void BeamModuleAssembler::emit_i_band(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_small(LHS) && RHS.isSmall()) { + a64::Utils::LogicalImm ignore; + if (a64::Utils::encodeLogicalImm(RHS.as().get(), + 64, + &ignore)) { + comment("skipped test for small operands since they are always " + "small"); + auto lhs = load_source(LHS, ARG2); + auto dst = init_destination(Dst, ARG1); + + /* TAG & TAG = TAG, so we don't need to tag it again. */ + a.and_(dst.reg, lhs.reg, RHS.as().get()); + flush_var(dst); + return; + } + } + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + auto dst = init_destination(Dst, ARG1); + + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + + /* TAG & TAG = TAG, so we don't need to tag it again. */ + a.and_(dst.reg, lhs.reg, rhs.reg); + flush_var(dst); + } else { + Label next = a.newLabel(); + + /* TAG & TAG = TAG, so we don't need to tag it again. */ + a.and_(ARG1, lhs.reg, rhs.reg); + + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + if (always_one_of(LHS) && + always_one_of(RHS)) { + comment("simplified test for small operands since other types are " + "boxed"); + emit_is_boxed(next, ARG1); + } else { + /* All other term types has at least one zero in the low 4 + * bits. Therefore, the result will be a small iff both + * operands are small. */ + a.and_(TMP1, ARG1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_eq(next); + } + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_band); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_band_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_var(dst, ARG1); + flush_var(dst); + } +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * Result is returned in RET. + */ +void BeamGlobalAssembler::emit_i_bor_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_bor, 2}; + emit_bitwise_fallback_body(erts_bor, &bif_mfa); +} + +void BeamModuleAssembler::emit_i_bor(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_small(LHS) && RHS.isSmall()) { + a64::Utils::LogicalImm ignore; + Uint64 rhs = RHS.as().get() & ~_TAG_IMMED1_SMALL; + if (a64::Utils::encodeLogicalImm(rhs, 64, &ignore)) { + comment("skipped test for small operands since they are always " + "small"); + auto lhs = load_source(LHS, ARG2); + auto dst = init_destination(Dst, ARG1); + + a.orr(dst.reg, lhs.reg, rhs); + flush_var(dst); + return; + } + } + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + auto dst = init_destination(Dst, ARG1); + + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + + /* TAG | TAG = TAG, so we don't need to tag it again. */ + a.orr(dst.reg, lhs.reg, rhs.reg); + flush_var(dst); + } else { + Label next = a.newLabel(); + + /* TAG | TAG = TAG, so we don't need to tag it again. */ + a.orr(ARG1, lhs.reg, rhs.reg); + + emit_are_both_small(LHS, lhs.reg, RHS, rhs.reg, next); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_bor); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bor_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_var(dst, ARG1); + flush_var(dst); + } +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_i_bxor_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_bxor, 2}; + emit_bitwise_fallback_body(erts_bxor, &bif_mfa); +} + +void BeamModuleAssembler::emit_i_bxor(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + auto dst = init_destination(Dst, ARG1); + + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands because they are always " + "small"); + + /* TAG ^ TAG = 0, so we'll need to tag it again. */ + a.eor(dst.reg, lhs.reg, rhs.reg); + a.orr(dst.reg, dst.reg, imm(_TAG_IMMED1_SMALL)); + flush_var(dst); + return; + } + + Label next = a.newLabel(); + + /* TAG ^ TAG = 0, so we'll need to tag it again. */ + a.eor(ARG1, lhs.reg, rhs.reg); + a.orr(ARG1, ARG1, imm(_TAG_IMMED1_SMALL)); + + emit_are_both_small(LHS, lhs.reg, RHS, rhs.reg, next); + + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_bxor); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bxor_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + { + mov_var(dst, ARG1); + flush_var(dst); + } +} + +/* + * ARG1 = Src + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. Error is indicated by + * THE_NON_VALUE. + */ +void BeamGlobalAssembler::emit_i_bnot_guard_shared() { + emit_enter_runtime_frame(); + + /* Undo the speculative inversion in module code. */ + a.eor(ARG2, ARG1, imm(~_TAG_IMMED1_MASK)); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_bnot); + + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +/* + * ARG1 = Src + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_i_bnot_body_shared() { + Label error = a.newLabel(); + + emit_enter_runtime_frame(); + + /* Undo the speculative inversion in module code. */ + a.eor(ARG2, ARG1, imm(~_TAG_IMMED1_MASK)); + + /* Save original arguments for the error path. */ + a.str(ARG2, TMP_MEM1q); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_bnot); + + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + a.ret(a64::x30); + + a.bind(error); + { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_bnot, 1}; + + /* emit_enter_runtime() was done in the module code. */ + emit_leave_runtime(0); + + /* Place the original arguments in X registers. */ + a.ldr(XREG0, TMP_MEM1q); + mov_imm(ARG4, &bif_mfa); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_bnot(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Src, + const ArgRegister &Dst) { + Label next = a.newLabel(); + auto src = load_source(Src, TMP2); + auto dst = init_destination(Dst, ARG1); + + /* Invert everything except the tag so we don't have to tag it again. */ + a.eor(ARG1, src.reg, imm(~_TAG_IMMED1_MASK)); + + if (always_one_of(Src)) { + comment("simplified test for small operand since it is a number"); + emit_is_boxed(next, Src, ARG1); + } else { + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_eq(next); + } + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bnot_guard_shared()); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bnot_body_shared()); + emit_leave_runtime(Live.get()); + } + + a.bind(next); + mov_var(dst, ARG1); + flush_var(dst); +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_i_bsr_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_bsr, 2}; + emit_bitwise_fallback_body(erts_bsr, &bif_mfa); +} + +void BeamModuleAssembler::emit_i_bsr(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + Label generic = a.newLabel(), next = a.newLabel(); + auto lhs = load_source(LHS, ARG2); + auto dst = init_destination(Dst, ARG1); + bool need_generic = true; + + if (RHS.isSmall()) { + Sint shift = RHS.as().getSigned(); + + if (shift >= 0 && shift < SMALL_BITS - 1) { + if (always_small(LHS)) { + comment("skipped test for small left operand because it is " + "always small"); + need_generic = false; + } else if (always_one_of(LHS)) { + comment("simplified test for small operand since it is a " + "number"); + emit_is_not_boxed(generic, lhs.reg); + } else { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + } + + /* We don't need to clear the mask after shifting because + * _TAG_IMMED1_SMALL will set all the bits anyway. */ + ERTS_CT_ASSERT(_TAG_IMMED1_MASK == _TAG_IMMED1_SMALL); + a.asr(TMP1, lhs.reg, imm(shift)); + a.orr(dst.reg, TMP1, imm(_TAG_IMMED1_SMALL)); + + if (need_generic) { + a.b(next); + } + } else { + /* Constant shift is negative or too big to fit the `asr` + * instruction; fall back to the generic path. */ + } + } + + a.bind(generic); + if (need_generic) { + mov_var(ARG2, lhs); + mov_arg(ARG3, RHS); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_bsr); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bsr_body_shared()); + emit_leave_runtime(Live.get()); + } + + mov_var(dst, ARG1); + } + + a.bind(next); + flush_var(dst); +} + +/* + * ARG2 = LHS + * ARG3 = RHS + * + * The module code must have executed emit_enter_runtime() + * before calling this function. + * + * The result is returned in ARG1. + */ +void BeamGlobalAssembler::emit_i_bsl_body_shared() { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_bsl, 2}; + emit_bitwise_fallback_body(erts_bsl, &bif_mfa); +} + +static int count_leading_zeroes(UWord value) { + const int word_bits = sizeof(value) * CHAR_BIT; + + if (value == 0) { + return word_bits; + } + + return Support::clz(value); +} + +void BeamModuleAssembler::emit_i_bsl(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + auto dst = init_destination(Dst, ARG1); + + if (is_bsl_small(LHS, RHS)) { + comment("skipped tests because operands and result are always small"); + if (RHS.isSmall()) { + auto lhs = load_source(LHS, ARG2); + a.and_(TMP1, lhs.reg, imm(~_TAG_IMMED1_MASK)); + a.lsl(TMP1, TMP1, imm(RHS.as().getSigned())); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + a.and_(TMP1, lhs.reg, imm(~_TAG_IMMED1_MASK)); + a.lsr(TMP2, rhs.reg, imm(_TAG_IMMED1_SIZE)); + a.lsl(TMP1, TMP1, TMP2); + } + a.orr(dst.reg, TMP1, imm(_TAG_IMMED1_SMALL)); + flush_var(dst); + return; + } + + auto [lhs, rhs] = load_sources(LHS, ARG2, RHS, ARG3); + Label generic = a.newLabel(), next = a.newLabel(); + bool inline_shift = true; + + if (LHS.isImmed() && RHS.isImmed()) { + /* The compiler should've optimized this away, so we'll fall + * back to the generic path to simplify the inline + * implementation. */ + inline_shift = false; + } else if (LHS.isLiteral() || RHS.isLiteral()) { + /* At least one argument is not a small. */ + inline_shift = false; + } else if (LHS.isImmed() && !LHS.isSmall()) { + /* Invalid constant. */ + inline_shift = false; + } else if (RHS.isImmed() && + (!RHS.isSmall() || RHS.as().getSigned() < 0 || + RHS.as().getSigned() >= SMALL_BITS - 1)) { + /* Constant shift is invalid or always produces a bignum. */ + inline_shift = false; + } + + if (inline_shift) { + /* shiftLimit will be calculated as the number of leading sign + * bits not counting the sign bit. Note that this value is one + * lower than the number of leading zeros as used by the + * x86_64 JIT. */ + Operand shiftLimit, shiftCount; + + ASSERT(!(LHS.isImmed() && RHS.isImmed())); + if (LHS.isRegister()) { + /* Count the number of leading sign bits so we can test + * whether the shift will overflow. (The count does not + * include the sign bit.) To ensure that the tag bits are + * not counted, we must make sure that the topmost tag bit + * is equal to the inverted value of the sign bit. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.eor(TMP1, lhs.reg, lhs.reg, arm::lsr(64 - _TAG_IMMED1_SIZE)); + a.cls(ARG4, TMP1); + shiftLimit = ARG4; + + if (always_small(LHS)) { + comment("skipped test for small operand since it is always " + "small"); + } else if (always_one_of(LHS)) { + comment("simplified test for small operand since it is a " + "number"); + emit_is_not_boxed(generic, TMP1); + } else { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + } + } else { + UWord value = LHS.as().get(); + + if (signed_val(value) < 0) { + value ^= ~(UWord)_TAG_IMMED1_MASK; + } + + shiftLimit = imm(count_leading_zeroes(value) - 1); + } + + if (RHS.isRegister()) { + /* Negate the tag bits and then rotate them out, forcing the + * comparison below to fail for non-smalls. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.eor(ARG5, rhs.reg, imm(_TAG_IMMED1_SMALL)); + a.ror(ARG5, ARG5, imm(_TAG_IMMED1_SIZE)); + shiftCount = ARG5; + + /* Fall back to generic path when the shift magnitude is negative or + * greater than the leading zero count. + * + * The raw emit form is used since `shiftLimit` may be a register + * or immediate, and the `cmp` helper doesn't accept untyped + * `Operand`s. */ + a.emit(a64::Inst::kIdCmp, ARG5, shiftLimit); + a.b_hi(generic); + } else { + ASSERT(!shiftLimit.isImm()); + + shiftCount = imm(RHS.as().getSigned()); + + a.emit(a64::Inst::kIdCmp, shiftLimit, shiftCount); + a.b_lo(generic); + } + + a.and_(TMP1, lhs.reg, imm(~_TAG_IMMED1_MASK)); + a.emit(a64::Inst::kIdLsl, TMP1, TMP1, shiftCount); + a.orr(dst.reg, TMP1, imm(_TAG_IMMED1_SMALL)); + + flush_var(dst); + a.b(next); + } + + a.bind(generic); + { + mov_var(ARG2, lhs); + mov_var(ARG3, rhs); + + if (Fail.get() != 0) { + emit_enter_runtime(Live.get()); + a.mov(ARG1, c_p); + runtime_call<3>(erts_bsl); + emit_leave_runtime(Live.get()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + emit_enter_runtime(Live.get()); + fragment_call(ga->get_i_bsl_body_shared()); + emit_leave_runtime(Live.get()); + } + + mov_var(dst, ARG1); + flush_var(dst); + } + + a.bind(next); +} diff --git a/erts/emulator/beam/jit/arm/instr_bif.cpp b/erts/emulator/beam/jit/arm/instr_bif.cpp new file mode 100644 index 000000000000..d12ea50cef3e --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_bif.cpp @@ -0,0 +1,1017 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "beam_common.h" +#include "code_ix.h" +#include "erl_bif_table.h" +#include "erl_nfunc_sched.h" +#include "bif.h" +#include "erl_msacc.h" +} + +void BeamModuleAssembler::ubif_comment(const ArgWord &Bif) { + if (logger.file()) { + ErtsCodeMFA *mfa = ubif2mfa((void *)Bif.get()); + if (mfa) { + comment("UBIF: %T/%d", mfa->function, mfa->arity); + } + } +} + +/* ARG2 = argument vector, ARG4 (!) = bif function pointer + * + * Result is returned in ARG1 (will be THE_NON_VALUE if the BIF call failed). */ +void BeamGlobalAssembler::emit_i_bif_guard_shared() { + /* We use the X register array for the arguments for the BIF. The + * actual contents of the first three X registers are kept safe in + * callee-saved machine registers (XREG0 through XREG2). + */ + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 2); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + lea(ARG2, getXRef(0)); + mov_imm(ARG3, 0); + runtime_call(ARG4, 3); /* ARG3 is never used by guard BIFs. */ + + emit_leave_runtime(); + emit_leave_runtime_frame(); + a.ret(a64::x30); +} + +/* ARG2 = argument vector, ARG4 (!) = bif function pointer + * + * Result is returned in RET. */ +void BeamGlobalAssembler::emit_i_bif_body_shared() { + Label error = a.newLabel(); + + /* See comment in emit_i_bif_guard_shared. */ + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 2); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + /* Save current BIF for the error path. */ + a.mov(ARG1, c_p); + lea(ARG2, getXRef(0)); + a.str(ARG4, TMP_MEM1q); + mov_imm(ARG3, 0); /* ARG3 is never used by guard BIFs. */ + + runtime_call(ARG4, 3); + emit_branch_if_not_value(ARG1, error); + + emit_leave_runtime(); + + emit_leave_runtime_frame(); + a.ret(a64::x30); + + a.bind(error); + { + /* Find the correct MFA from the BIF's function address. */ + a.ldr(ARG1, TMP_MEM1q); + runtime_call<1>(ubif2mfa); + + /* The argument registers must be reloaded on error, as the machine + * registers may contain garbage, which will later be swapped into the + * register array in the `raise_exception` fragment. */ + emit_leave_runtime(3); + emit_leave_runtime_frame(); + + a.mov(ARG4, ARG1); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_i_bif1(const ArgSource &Src1, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { + auto src1 = load_source(Src1, TMP1); + + a.str(src1.reg, getXRef(0)); + + ubif_comment(Bif); + emit_i_bif(Fail, Bif, Dst); +} + +void BeamModuleAssembler::emit_i_bif2(const ArgSource &Src1, + const ArgSource &Src2, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + + a.stp(src1.reg, src2.reg, getXRef(0)); + + ubif_comment(Bif); + emit_i_bif(Fail, Bif, Dst); +} + +void BeamModuleAssembler::emit_i_bif3(const ArgSource &Src1, + const ArgSource &Src2, + const ArgSource &Src3, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + auto src3 = load_source(Src3, TMP3); + + a.stp(src1.reg, src2.reg, getXRef(0)); + a.str(src3.reg, getXRef(2)); + + ubif_comment(Bif); + emit_i_bif(Fail, Bif, Dst); +} + +void BeamModuleAssembler::emit_i_bif(const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { + mov_arg(ARG4, Bif); + + if (Fail.get() != 0) { + fragment_call(ga->get_i_bif_guard_shared()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + fragment_call(ga->get_i_bif_body_shared()); + } + + mov_arg(Dst, ARG1); +} + +/* + * Emit code for guard BIFs that can't fail (e.g. is_list/1). We + * don't need to test for failure. + */ + +void BeamModuleAssembler::emit_nofail_bif1(const ArgSource &Src1, + const ArgWord &Bif, + const ArgRegister &Dst) { + auto src1 = load_source(Src1, TMP1); + + a.str(src1.reg, getXRef(0)); + + ubif_comment(Bif); + mov_arg(ARG4, Bif); + fragment_call(ga->get_i_bif_guard_shared()); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_nofail_bif2(const ArgSource &Src1, + const ArgSource &Src2, + const ArgWord &Bif, + const ArgRegister &Dst) { + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + + a.stp(src1.reg, src2.reg, getXRef(0)); + + ubif_comment(Bif); + mov_arg(ARG4, Bif); + fragment_call(ga->get_i_bif_guard_shared()); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_length_setup(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Src) { + mov_arg(TMP1, Src); + mov_imm(TMP2, make_small(0)); + + /* Store trap state after the currently live registers. There are + * 3 extra registers beyond the ordinary ones that we're free to + * use for whatever purpose. */ + ERTS_CT_ASSERT(ERTS_X_REGS_ALLOCATED - MAX_REG >= 3); + mov_arg(ArgXRegister(Live.get() + 0), TMP1); + mov_arg(ArgXRegister(Live.get() + 1), TMP2); + + /* Store original argument. This is only needed for exceptions and can be + * safely skipped in guards. */ + if (Fail.get() == 0) { + mov_arg(ArgXRegister(Live.get() + 2), TMP1); + } +} + +/* ARG2 = live registers, ARG3 = entry address + * + * Result is returned in RET. */ +void BeamGlobalAssembler::emit_i_length_common(Label fail, int state_size) { + Label trap_or_error = a.newLabel(); + + ASSERT(state_size >= 2 && state_size <= ERTS_X_REGS_ALLOCATED - MAX_REG); + + /* Save arguments for error/trapping path. */ + a.stp(ARG2, ARG3, TMP_MEM1q); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + lea(TMP1, getXRef(0)); + a.add(ARG2, TMP1, ARG2, arm::lsl(3)); + runtime_call<2>(erts_trapping_length_1); + + emit_branch_if_not_value(ARG1, trap_or_error); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); + + a.bind(trap_or_error); + { + a.ldp(ARG2, ARG3, TMP_MEM1q); + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.cmp(TMP1, imm(TRAP)); + a.b_ne(fail); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + /* The trap state is stored in the registers above the current live + * ones, so we add the state size (in words) to keep it alive. */ + a.add(ARG2, ARG2, imm(state_size)); + + a.str(ZERO, arm::Mem(c_p, offsetof(Process, current))); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, arity))); + + /* We'll find our way back through the entry address (ARG3). */ + a.b(labels[context_switch_simplified]); + } +} + +/* ARG2 = live registers, ARG3 = entry address + * + * Result is returned in RET. */ +void BeamGlobalAssembler::emit_i_length_body_shared() { + Label error = a.newLabel(); + /* `state_size = 3` to include the original argument. */ + emit_i_length_common(error, 3); + + a.bind(error); + { + static const ErtsCodeMFA bif_mfa = {am_erlang, am_length, 1}; + + /* Move the original argument to x0. It's stored in the third word of + * the trap state. */ + lea(TMP1, getXRef(0)); + a.add(ARG2, TMP1, ARG2, arm::lsl(3)); + a.ldr(TMP1, arm::Mem(ARG2, sizeof(Eterm[2]))); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.mov(XREG0, TMP1); + + mov_imm(ARG4, &bif_mfa); + emit_raise_exception(); + } +} + +/* ARG2 = live registers, ARG3 = entry address + * + * Result is returned in ARG. Error is indicated by THE_NON_VALUE. */ +void BeamGlobalAssembler::emit_i_length_guard_shared() { + Label error = a.newLabel(); + + emit_i_length_common(error, 2); + + a.bind(error); + { + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_i_length(const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + Label entry = a.newLabel(); + + a.bind(entry); + + mov_arg(ARG2, Live); + a.adr(ARG3, entry); + if (Fail.get() != 0) { + fragment_call(ga->get_i_length_guard_shared()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + fragment_call(ga->get_i_length_body_shared()); + } + + mov_arg(Dst, ARG1); +} + +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) + +static Eterm debug_call_light_bif(Process *c_p, + Eterm *reg, + ErtsCodePtr I, + ErtsBifFunc vbf) { + Eterm result; + + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + { + ERTS_CHK_MBUF_SZ(c_p); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + result = vbf(c_p, reg, I); + ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result)); + ERTS_CHK_MBUF_SZ(c_p); + + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + ERTS_HOLE_CHECK(c_p); + } + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + + return result; +} +#endif + +/* It is important that the below code is as optimized as possible. + * When doing any changes, make sure to look at the estone bif_dispatch + * benchmark to make sure you don't introduce any regressions. + * + * ARG3 = entry + * ARG4 = export entry + * ARG8 = BIF pointer + */ +void BeamGlobalAssembler::emit_call_light_bif_shared() { + /* We use the HTOP, FCALLS, and XREG1 registers as they are not + * used on the runtime-stack and are caller save. */ + + arm::Mem entry_mem = TMP_MEM1q, export_mem = TMP_MEM2q, + mbuf_mem = TMP_MEM3q; + + Label trace = a.newLabel(), yield = a.newLabel(); + + /* Spill everything we may need on the error and GC paths. */ + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, mbuf))); + a.stp(ARG3, ARG4, TMP_MEM1q); + a.str(TMP1, mbuf_mem); + + /* Check if we should trace this bif call or handle save_calls. Both + * variants dispatch through the export entry. */ + a.ldr(TMP1.w(), arm::Mem(ARG4, offsetof(Export, is_bif_traced))); + a.cmp(TMP1, imm(0)); + a.ccmp(active_code_ix, + imm(ERTS_SAVE_CALLS_CODE_IX), + imm(NZCV::kZF), + imm(arm::CondCode::kEQ)); + a.b_eq(trace); + + a.subs(FCALLS, FCALLS, imm(1)); + a.b_le(yield); + { + Label check_bif_return = a.newLabel(), gc_after_bif_call = a.newLabel(); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + +#ifdef ERTS_MSACC_EXTENDED_STATES + { + Label skip_msacc = a.newLabel(); + + a.ldr(TMP1, erts_msacc_cache); + a.cbz(TMP1, skip_msacc); + + /* The values of the X registers are in the X register array, so we + * use XREG0 to save the entry pointer (ARG3) over this call. */ + a.mov(XREG0, ARG3); + + a.ldr(ARG1, erts_msacc_cache); + a.ldr(ARG2, arm::Mem(ARG4, offsetof(Export, info.mfa.module))); + a.mov(ARG3, ARG8); + runtime_call<3>(erts_msacc_set_bif_state); + + a.mov(ARG8, ARG1); + a.mov(ARG3, XREG0); + + a.bind(skip_msacc); + } +#endif + + { + /* Call the BIF proper. ARG3 and ARG8 have been set earlier. */ + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) + a.mov(ARG4, ARG8); + runtime_call<4>(debug_call_light_bif); +#else + runtime_call(ARG8, 3); +#endif + } + +#ifdef ERTS_MSACC_EXTENDED_STATES + { + Label skip_msacc = a.newLabel(); + + a.mov(XREG0, ARG1); + + a.ldr(TMP1, erts_msacc_cache); + a.cbz(TMP1, skip_msacc); + + lea(ARG1, erts_msacc_cache); + runtime_call<1>(erts_msacc_update_cache); + + /* Set state to emulator if msacc has been enabled */ + a.ldr(ARG1, erts_msacc_cache); + a.cbz(ARG1, skip_msacc); + + mov_imm(ARG2, ERTS_MSACC_STATE_EMULATOR); + mov_imm(ARG3, 1); + runtime_call<3>(erts_msacc_set_state_m__); + + a.bind(skip_msacc); + a.mov(ARG1, XREG0); + } +#endif + + /* We must update the active code index in case another process has + * loaded new code, as the result of this BIF may be observable on both + * ends. + * + * It doesn't matter whether the BIF modifies anything; if process A + * loads new code and calls erlang:monotonic_time/0 soon after, we'd + * break the illusion of atomic upgrades if process B still ran old code + * after seeing a later timestamp from its own call to + * erlang:monotonic_time/0. */ + emit_leave_runtime(); + emit_leave_runtime_frame(); + + /* ERTS_IS_GC_DESIRED_INTERNAL */ + { + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, flags))); + a.tst(TMP1, imm(F_FORCE_GC | F_DISABLE_GC)); + + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, bin_vheap_sz))); + a.ldr(TMP2, arm::Mem(c_p, offsetof(Process, off_heap.overhead))); + + /* If neither F_FORCE_GC nor F_DISABLE_GC were set, + * test whether binary heap size should trigger GC. + * + * Otherwise, set the flags as if `off_heap.overhead > bin_vheap_sz` + * to force a GC. */ + a.ccmp(TMP2, TMP1, imm(NZCV::kCF), imm(arm::CondCode::kEQ)); + + a.sub(TMP1, E, HTOP); + a.asr(TMP1, TMP1, imm(3)); + a.ldr(TMP2, arm::Mem(c_p, offsetof(Process, mbuf_sz))); + + /* If our binary heap size was small enough not to need a GC, check + * whether the heap fragment size is larger than the remaining heap + * size. + * + * Otherwise, set the flags as if it is to force a GC. */ + a.ccmp(TMP1, TMP2, imm(NZCV::kVF), imm(arm::CondCode::kLS)); + a.b_lt(gc_after_bif_call); + } + + a.bind(check_bif_return); + { + Label error = a.newLabel(), trap = a.newLabel(); + + emit_branch_if_not_value(ARG1, trap); + + a.mov(XREG0, ARG1); + a.ret(a64::x30); + + a.bind(trap); + { + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + emit_branch_if_ne(TMP1, TRAP, error); + + /* Push our return address to the Erlang stack and trap out. + * + * The BIF_TRAP macros all set up c_p->arity and c_p->current, + * so we can use a simplified context switch. */ + emit_enter_erlang_frame(); + a.ldr(ARG3, arm::Mem(c_p, offsetof(Process, i))); + a.b(labels[context_switch_simplified]); + } + + a.bind(error); + { + /* raise_exception_shared expects current PC in ARG2 and MFA in + * ARG4. */ + a.ldp(ARG2, ARG4, entry_mem); + add(ARG4, ARG4, offsetof(Export, info.mfa)); + a.b(labels[raise_exception_shared]); + } + } + + a.bind(gc_after_bif_call); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG3, ARG1); + + a.mov(ARG1, c_p); + a.ldr(ARG2, mbuf_mem); + load_x_reg_array(ARG4); + a.ldr(ARG5, export_mem); + a.ldr(ARG5, arm::Mem(ARG5, offsetof(Export, info.mfa.arity))); + runtime_call<5>(erts_gc_after_bif_call_lhf); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.b(check_bif_return); + } + } + + a.bind(trace); + { + /* Call the export entry instead of the BIF. */ + branch(emit_setup_dispatchable_call(ARG4)); + } + + a.bind(yield); + { + a.ldr(ARG2, arm::Mem(ARG4, offsetof(Export, info.mfa.arity))); + lea(ARG4, arm::Mem(ARG4, offsetof(Export, info.mfa))); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, arity))); + a.str(ARG4, arm::Mem(c_p, offsetof(Process, current))); + + /* We'll find our way back through ARG3 (entry address). */ + a.b(labels[context_switch_simplified]); + } +} + +void BeamModuleAssembler::emit_call_light_bif(const ArgWord &Bif, + const ArgExport &Exp) { + Label entry = a.newLabel(); + + a.bind(entry); + + mov_arg(ARG4, Exp); + mov_arg(ARG8, Bif); + a.adr(ARG3, entry); + + if (logger.file()) { + BeamFile_ImportEntry *e = &beam->imports.entries[Exp.get()]; + comment("BIF: %T:%T/%d", e->module, e->function, e->arity); + } + fragment_call(ga->get_call_light_bif_shared()); +} + +void BeamModuleAssembler::emit_send() { + Label entry = a.newLabel(); + + /* This is essentially a mirror of call_light_bif, there's no point to + * specializing send/2 anymore. We do it here because it's far more work to + * do it in the loader. */ + a.bind(entry); + + a.ldr(ARG4, embed_constant(BIF_TRAP_EXPORT(BIF_send_2), disp32K)); + a.ldr(ARG8, embed_constant(send_2, disp32K)); + a.adr(ARG3, entry); + + fragment_call(ga->get_call_light_bif_shared()); +} + +void BeamModuleAssembler::emit_nif_start() { + /* load time only instruction */ +} + +void BeamGlobalAssembler::emit_bif_nif_epilogue(void) { + Label check_trap = a.newLabel(), trap = a.newLabel(), error = a.newLabel(); + +#ifdef ERTS_MSACC_EXTENDED_STATES + { + Label skip_msacc = a.newLabel(); + + a.ldr(TMP1, erts_msacc_cache); + a.cbz(TMP1, skip_msacc); + + /* The values of the X registers are in the X register array, + * so we can use XREG0 to save the contents of ARG1 during the + * call. */ + a.mov(XREG0, ARG1); + a.ldr(ARG1, erts_msacc_cache); + mov_imm(ARG2, ERTS_MSACC_STATE_EMULATOR); + mov_imm(ARG3, 1); + runtime_call<3>(erts_msacc_set_state_m__); + a.mov(ARG1, XREG0); + + a.bind(skip_msacc); + } +#endif + + /* Another process may have loaded new code and somehow notified us through + * this call, so we must update the active code index. */ + emit_leave_runtime(); + + emit_branch_if_not_value(ARG1, check_trap); + + comment("Do return and dispatch to it"); + a.mov(XREG0, ARG1); + + emit_leave_erlang_frame(); + a.ret(a64::x30); + + a.bind(check_trap); + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.cmp(TMP1, imm(TRAP)); + a.b_ne(error); + { + comment("yield"); + + comment("test trap to hibernate"); + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, flags))); + a.tbz(TMP1, imm(Support::ctz(F_HIBERNATE_SCHED)), trap); + + comment("do hibernate trap"); + a.and_(TMP1, TMP1, imm(~F_HIBERNATE_SCHED)); + a.str(TMP1.w(), arm::Mem(c_p, offsetof(Process, flags))); + a.b(labels[do_schedule]); + } + + a.bind(trap); + { + comment("do normal trap"); + + /* The BIF_TRAP macros all set up c_p->arity and c_p->current, so we + * can use a simplified context switch. */ + a.ldr(ARG3, arm::Mem(c_p, offsetof(Process, i))); + a.b(labels[context_switch_simplified]); + } + + a.bind(error); + { + a.mov(ARG2, E); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_printable_return_address); + + emit_leave_runtime(); + + a.mov(ARG2, ARG1); + a.ldr(ARG4, arm::Mem(c_p, offsetof(Process, current))); + a.b(labels[raise_exception_shared]); + } +} + +/* Used by call_bif, dispatch_bif, and export_trampoline. + * + * Note that we don't check reductions here as we may have jumped here through + * interpreted code (e.g. an ErtsNativeFunc or export entry) and it's very + * tricky to yield back. Reductions are checked in module code instead. + * + * ARG2 = BIF MFA + * ARG3 = I (rip), doesn't need to point past an MFA + * ARG4 = function to be called */ +void BeamGlobalAssembler::emit_call_bif_shared(void) { + /* "Heavy" BIFs need up-to-date values for `c_p->i`, `c_p->current`, and + * `c_p->arity`. */ + + emit_enter_runtime_frame(); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, current))); + /* `call_bif` wants arity in ARG5. */ + a.ldr(ARG5, arm::Mem(ARG2, offsetof(ErtsCodeMFA, arity))); + a.str(ARG5, arm::Mem(c_p, offsetof(Process, arity))); + a.str(ARG3, arm::Mem(c_p, offsetof(Process, i))); + + /* The corresponding leave can be found in the epilogue. */ + emit_enter_runtime(); + +#ifdef ERTS_MSACC_EXTENDED_STATES + { + Label skip_msacc = a.newLabel(); + + a.ldr(TMP1, erts_msacc_cache); + a.cbz(TMP1, skip_msacc); + + /* The values of the X registers are in the X register array, so we can + * use XREG0 and XREG1 to save the contents of the ARG* registers + * during the call. */ + a.mov(XREG0, ARG3); + a.mov(XREG1, ARG5); + + a.ldr(ARG1, erts_msacc_cache); + a.ldr(ARG2, arm::Mem(ARG2, offsetof(ErtsCodeMFA, module))); + a.mov(ARG3, ARG4); + runtime_call<3>(erts_msacc_set_bif_state); + a.mov(ARG4, ARG1); + + a.mov(ARG3, XREG0); + a.mov(ARG5, XREG1); + + a.bind(skip_msacc); + } +#endif + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + /* ARG3 (I), ARG4 (func), and ARG5 (arity) have already been provided. */ + runtime_call<5>(beam_jit_call_bif); + +#ifdef ERTS_MSACC_EXTENDED_STATES + /* The values of the X registers are in the X register array, so we can use + * XREG0 to save the contents of ARG1 during the call. */ + a.mov(XREG0, ARG1); + lea(ARG1, erts_msacc_cache); + runtime_call<1>(erts_msacc_update_cache); + a.mov(ARG1, XREG0); +#endif + + emit_leave_runtime_frame(); + emit_bif_nif_epilogue(); +} + +void BeamGlobalAssembler::emit_dispatch_bif(void) { + /* c_p->i points into the trampoline of a ErtsNativeFunc, right after the + * `info` structure. */ + a.ldr(ARG3, arm::Mem(c_p, offsetof(Process, i))); + + ERTS_CT_ASSERT(offsetof(ErtsNativeFunc, trampoline.call_bif_nif) == + sizeof(ErtsCodeInfo)); + + ssize_t mfa_offset = offsetof(ErtsNativeFunc, trampoline.call_bif_nif) - + offsetof(ErtsNativeFunc, trampoline.info.mfa); + + a.sub(ARG2, ARG3, imm(mfa_offset)); + + ssize_t dfunc_offset = offsetof(ErtsNativeFunc, trampoline.dfunc) - + offsetof(ErtsNativeFunc, trampoline.call_bif_nif); + a.ldr(ARG4, arm::Mem(ARG3, dfunc_offset)); + + a.b(labels[call_bif_shared]); +} + +/* This is only used for opcode compatibility with the interpreter, it's never + * actually called. */ +void BeamModuleAssembler::emit_call_bif(const ArgWord &Func) { + (void)Func; + + emit_nyi("emit_call_bif"); +} + +void BeamModuleAssembler::emit_call_bif_mfa(const ArgAtom &M, + const ArgAtom &F, + const ArgWord &A) { + BeamInstr func; + Export *e; + + e = erts_active_export_entry(M.get(), F.get(), A.get()); + ASSERT(e != NULL && e->bif_number != -1); + + func = (BeamInstr)bif_table[e->bif_number].f; + + a.adr(ARG3, current_label); + a.sub(ARG2, ARG3, imm(sizeof(ErtsCodeMFA))); + comment("HBIF: %T:%T/%d", + e->info.mfa.module, + e->info.mfa.function, + A.get()); + a.mov(ARG4, imm(func)); + + a.b(resolve_fragment(ga->get_call_bif_shared(), disp128MB)); +} + +void BeamGlobalAssembler::emit_call_nif_early() { + a.mov(ARG2, a64::x30); + a.sub(ARG2, ARG2, imm(BEAM_ASM_FUNC_PROLOGUE_SIZE + sizeof(ErtsCodeInfo))); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_call_nif_early); + + emit_leave_runtime(); + + /* Emulate `emit_call_nif`, loading the current (phony) instruction + * pointer into ARG3. + * + * Note that we "inherit" the frame that was pushed to the stack prior to + * running the breakpoint instruction, discarding the current content of + * LR (x30). */ + a.mov(ARG3, ARG1); + a.b(labels[call_nif_shared]); +} + +/* Used by call_nif, call_nif_early, and dispatch_nif. + * + * Note that we don't check reductions here as we may have jumped here through + * interpreted code (e.g. an ErtsNativeFunc or export entry) and it's very + * tricky to yield back. Reductions are checked in module code instead. + * + * ARG3 = current I, just past the end of an ErtsCodeInfo. */ +void BeamGlobalAssembler::emit_call_nif_shared(void) { + /* The corresponding leave can be found in the epilogue. */ + emit_enter_runtime(); + +#ifdef ERTS_MSACC_EXTENDED_STATES + { + Label skip_msacc = a.newLabel(); + + a.ldr(TMP1, erts_msacc_cache); + a.cbz(TMP1, skip_msacc); + + /* The values of the X registers are in the X register array, + * so we can use XREG0 to save the contents of ARG3 during the + * call. */ + a.mov(XREG0, ARG3); + a.ldr(ARG1, erts_msacc_cache); + mov_imm(ARG2, ERTS_MSACC_STATE_NIF); + mov_imm(ARG3, 1); + runtime_call<3>(erts_msacc_set_state_m__); + a.mov(ARG3, XREG0); + + a.bind(skip_msacc); + } +#endif + + a.mov(ARG1, c_p); + a.mov(ARG2, ARG3); + load_x_reg_array(ARG3); + ERTS_CT_ASSERT((4 + BEAM_ASM_FUNC_PROLOGUE_SIZE) % sizeof(UWord) == 0); + a.ldr(ARG4, arm::Mem(ARG2, 4 + BEAM_ASM_FUNC_PROLOGUE_SIZE)); + a.ldr(ARG5, arm::Mem(ARG2, 12 + BEAM_ASM_FUNC_PROLOGUE_SIZE)); + a.ldr(ARG6, arm::Mem(ARG2, 16 + BEAM_ASM_FUNC_PROLOGUE_SIZE)); + runtime_call<5>(beam_jit_call_nif); + + emit_bif_nif_epilogue(); +} + +void BeamGlobalAssembler::emit_dispatch_nif(void) { + /* c_p->i points into the trampoline of a ErtsNativeFunc, right after the + * `info` structure. + * + * ErtsNativeFunc already follows the NIF call layout, so we don't need to + * do anything beyond loading the address. */ + a.ldr(ARG3, arm::Mem(c_p, offsetof(Process, i))); + a.b(labels[call_nif_shared]); +} + +void BeamGlobalAssembler::emit_call_nif_yield_helper() { + Label yield = a.newLabel(); + + a.subs(FCALLS, FCALLS, imm(1)); + a.b_le(yield); + a.b(labels[call_nif_shared]); + + a.bind(yield); + { + int mfa_offset = sizeof(ErtsCodeMFA); + int arity_offset = offsetof(ErtsCodeMFA, arity) - mfa_offset; + + a.ldur(TMP1, arm::Mem(ARG3, arity_offset)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, arity))); + + a.sub(TMP1, ARG3, imm(mfa_offset)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, current))); + + /* Yield to `dispatch` rather than `entry` to avoid pushing too many + * frames to the stack. See `emit_call_nif` for details. */ + a.add(ARG3, ARG3, imm(BEAM_ASM_NFUNC_SIZE + sizeof(UWord[3]))); + a.b(labels[context_switch_simplified]); + } +} + +/* WARNING: This stub is memcpy'd, so all code herein must be explicitly + * position-independent. */ +void BeamModuleAssembler::emit_call_nif(const ArgWord &Func, + const ArgWord &NifMod, + const ArgWord &DirtyFunc) { + Label entry = a.newLabel(), dispatch = a.newLabel(); + + /* The start of this function must mimic the layout of ErtsNativeFunc. + * + * We jump here on the very first entry. */ + a.bind(entry); + { + a.b(dispatch); + + /* Everything prior to this, including the breakpoint, is part of the + * `call_bif_nif` field. */ + ASSERT(a.offset() % sizeof(UWord) == 0); + + /* ErtsNativeFunc.func */ + a.embedUInt64(Func.get()); + + /* ErtsNativeFunc.m */ + a.embedUInt64(NifMod.get()); + + /* ErtsNativeFunc.dfunc */ + a.embedUInt64(DirtyFunc.get()); + } + + /* `emit_call_nif_yield_helper` relies on this to compute the address of + * `dispatch` */ + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + BEAM_ASM_NFUNC_SIZE + sizeof(UWord[3])); + + a.bind(dispatch); + { + a.adr(ARG3, current_label); + pic_jmp(ga->get_call_nif_yield_helper()); + } +} + +static ErtsCodePtr get_on_load_address(Process *c_p, Eterm module) { + const Module *modp = erts_get_module(module, erts_active_code_ix()); + + if (modp && modp->on_load) { + const BeamCodeHeader *hdr = (modp->on_load)->code_hdr; + + if (hdr) { + return erts_codeinfo_to_code(hdr->on_load); + } + } + + c_p->freason = BADARG; + + return NULL; +} + +/* Implements the internal and undocumented erlang:call_on_load_function/1, + * which is very tricky to implement as a BIF. */ +void BeamModuleAssembler::emit_i_call_on_load_function() { + static ErtsCodeMFA mfa = {am_erlang, am_call_on_load_function, 1}; + Label next = a.newLabel(); + + a.mov(ARG2, XREG0); + + /* The first X register must be preserved for the error path. */ + emit_enter_runtime(1); + + a.mov(ARG1, c_p); + runtime_call<2>(get_on_load_address); + + emit_leave_runtime(1); + + a.cbnz(ARG1, next); + emit_raise_exception(&mfa); + + a.bind(next); + erlang_call(ARG1); +} + +void BeamModuleAssembler::emit_i_load_nif() { + static ErtsCodeMFA mfa = {am_erlang, am_load_nif, 2}; + + Label entry = a.newLabel(), next = a.newLabel(), schedule = a.newLabel(); + + a.bind(entry); + + emit_enter_runtime(2); + + a.mov(ARG1, c_p); + a.adr(ARG2, current_label); + load_x_reg_array(ARG3); + runtime_call<3>(beam_jit_load_nif); + + emit_leave_runtime(2); + + a.cmp(ARG1, imm(RET_NIF_yield)); + a.b_eq(schedule); + + a.cmp(ARG1, imm(RET_NIF_success)); + a.b_eq(next); + + emit_raise_exception(current_label, &mfa); + + a.bind(schedule); + { + a.adr(ARG3, entry); + a.b(resolve_fragment(ga->get_context_switch_simplified(), disp128MB)); + } + + a.bind(next); +} diff --git a/erts/emulator/beam/jit/arm/instr_bs.cpp b/erts/emulator/beam/jit/arm/instr_bs.cpp new file mode 100644 index 000000000000..e2485ed16ec7 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_bs.cpp @@ -0,0 +1,4168 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" +#include + +extern "C" +{ +#include "erl_binary.h" +#include "erl_bits.h" +#include "beam_common.h" +} + +/* Clobbers TMP1+TMP2 + * + * Returns -1 when the field check always fails, 1 if it may fail, and 0 if it + * never fails. */ +int BeamModuleAssembler::emit_bs_get_field_size(const ArgSource &Size, + int unit, + Label fail, + const arm::Gp &out) { + if (Size.isImmed()) { + if (Size.isSmall()) { + Sint sval = Size.as().getSigned(); + + if (sval < 0) { + /* badarg */ + } else if (sval > (MAX_SMALL / unit)) { + /* system_limit */ + } else { + mov_imm(out, sval * unit); + return 0; + } + } + + a.b(fail); + return -1; + } else { + auto size_reg = load_source(Size, TMP2); + bool can_fail = true; + + if (always_small(Size)) { + auto [min, max] = getClampedRange(Size); + can_fail = + !(0 <= min && (max >> (SMALL_BITS - ERL_UNIT_BITS)) == 0); + } + + /* Negating the tag bits lets us guard against non-smalls, negative + * numbers, and overflow with a single `tst` instruction. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + ASSERT(unit <= 1024); + + if (!can_fail) { + comment("simplified segment size checks because " + "the types are known"); + } + + if (unit == 1 && !can_fail) { + a.lsr(out, size_reg.reg, imm(_TAG_IMMED1_SIZE)); + } else { + a.eor(out, size_reg.reg, imm(_TAG_IMMED1_SMALL)); + } + + if (can_fail) { + a.tst(out, imm(0xFFF0000000000000UL | _TAG_IMMED1_MASK)); + } + + if (unit == 0) { + /* Silly but legal.*/ + mov_imm(out, 0); + } else if (unit == 1 && !can_fail) { + /* The result is already in the out register. */ + ; + } else if (Support::isPowerOf2(unit)) { + int trailing_bits = Support::ctz(unit); + + /* The tag bits were cleared out by the argument check, so all we + * need to do is shift the result into place. */ + if (trailing_bits < _TAG_IMMED1_SIZE) { + a.lsr(out, out, imm(_TAG_IMMED1_SIZE - trailing_bits)); + } else if (trailing_bits > _TAG_IMMED1_SIZE) { + a.lsl(out, out, imm(trailing_bits - _TAG_IMMED1_SIZE)); + } + } else { + if (unit >= (1 << _TAG_IMMED1_SIZE)) { + mov_imm(TMP1, unit >> _TAG_IMMED1_SIZE); + } else { + a.lsr(out, out, imm(_TAG_IMMED1_SIZE)); + mov_imm(TMP1, unit); + } + + a.mul(out, out, TMP1); + } + + if (can_fail) { + a.b_ne(fail); + } + + return can_fail; + } +} + +void BeamModuleAssembler::emit_i_bs_init_heap(const ArgWord &Size, + const ArgWord &Heap, + const ArgWord &Live, + const ArgRegister &Dst) { + mov_arg(ARG4, Size); + mov_arg(ARG5, Heap); + mov_arg(ARG6, Live); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + load_erl_bits_state(ARG3); + runtime_call<6>(beam_jit_bs_init); + + emit_leave_runtime(Live.get()); + + mov_arg(Dst, ARG1); +} + +/* Set the error reason when a size check has failed. */ +void BeamGlobalAssembler::emit_bs_size_check_shared() { + emit_enter_runtime_frame(); + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<2>(beam_jit_bs_field_size_argument_error); + + emit_leave_runtime(0); + emit_leave_runtime_frame(); + + mov_imm(ARG4, 0); + a.b(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgSource &Size, + const ArgWord &Heap, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + Label fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + } + + if (emit_bs_get_field_size(Size, 1, fail, ARG4) >= 0) { + mov_arg(ARG5, Heap); + mov_arg(ARG6, Live); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + load_erl_bits_state(ARG3); + runtime_call<6>(beam_jit_bs_init); + + emit_leave_runtime(Live.get()); + + mov_arg(Dst, ARG1); + } + + if (Fail.get() == 0) { + Label next = a.newLabel(); + + a.b(next); + + a.bind(fail); + { + mov_arg(ARG2, Size); + fragment_call(ga->get_bs_size_check_shared()); + } + + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_bs_init(const ArgWord &Size, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); + emit_i_bs_init_heap(Size, Heap, Live, Dst); +} + +void BeamModuleAssembler::emit_i_bs_init_fail(const ArgRegister &Size, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); + emit_i_bs_init_fail_heap(Size, Heap, Fail, Live, Dst); +} + +void BeamModuleAssembler::emit_i_bs_init_bits(const ArgWord &NumBits, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal heap(ArgVal::Word, 0); + emit_i_bs_init_bits_heap(NumBits, heap, Live, Dst); +} + +void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgWord &NumBits, + const ArgWord &Alloc, + const ArgWord &Live, + const ArgRegister &Dst) { + mov_arg(ARG4, NumBits); + mov_arg(ARG5, Alloc); + mov_arg(ARG6, Live); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + load_erl_bits_state(ARG3); + runtime_call<6>(beam_jit_bs_init_bits); + + emit_leave_runtime(Live.get()); + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_bs_init_bits_fail(const ArgRegister &NumBits, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); + + emit_i_bs_init_bits_fail_heap(NumBits, Heap, Fail, Live, Dst); +} + +void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap( + const ArgSource &NumBits, + const ArgWord &Alloc, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + Label fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + } + + if (emit_bs_get_field_size(NumBits, 1, fail, ARG4) >= 0) { + mov_arg(ARG5, Alloc); + mov_arg(ARG6, Live); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + load_erl_bits_state(ARG3); + runtime_call<6>(beam_jit_bs_init_bits); + + emit_leave_runtime(Live.get()); + + mov_arg(Dst, ARG1); + } + + if (Fail.get() == 0) { + Label next = a.newLabel(); + + a.b(next); + a.bind(fail); + { + mov_arg(ARG2, NumBits); + fragment_call(ga->get_bs_size_check_shared()); + } + + a.bind(next); + } +} + +void BeamModuleAssembler::emit_bs_put_string(const ArgWord &Size, + const ArgBytePtr &Ptr) { + mov_arg(ARG2, Ptr); + mov_arg(ARG3, Size); + + emit_enter_runtime(); + + load_erl_bits_state(ARG1); + runtime_call<3>(erts_new_bs_put_string); + + emit_leave_runtime(); +} + +void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgSource &Src, + const ArgLabel &Fail, + const ArgWord &Sz, + const ArgWord &Flags) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Sz); + mov_arg(ARG4, Flags); + + emit_enter_runtime(); + + load_erl_bits_state(ARG1); + runtime_call<4>(erts_new_bs_put_integer); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } else { + Label next = a.newLabel(); + + a.cbnz(ARG1, next); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgLabel &Fail, + const ArgRegister &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; + Label next, fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + next = a.newLabel(); + } + + /* Clobbers RET + ARG3 */ + if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { + mov_arg(ARG2, Src); + mov_arg(ARG4, Flags); + + emit_enter_runtime(); + + load_erl_bits_state(ARG1); + runtime_call<4>(erts_new_bs_put_integer); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + a.cbz(ARG1, fail); + } else { + a.cbnz(ARG1, next); + } + } + + if (Fail.get() == 0) { + a.bind(fail); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgLabel &Fail, + const ArgSource &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; + Label next, fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + next = a.newLabel(); + } + + if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { + mov_arg(ARG2, Src); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + a.cbz(ARG1, fail); + } else { + a.cbnz(ARG1, next); + } + } + + if (Fail.get() == 0) { + a.bind(fail); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgSource &Src, + const ArgLabel &Fail, + const ArgWord &Unit) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Unit); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary_all); + + emit_leave_runtime(); + + if (Fail.get() == 0) { + Label next = a.newLabel(); + + a.cbnz(ARG1, next); + emit_error(BADARG); + a.bind(next); + } else { + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgLabel &Fail, + const ArgWord &Sz, + const ArgSource &Src) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Sz); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary); + + emit_leave_runtime(); + + if (Fail.get() == 0) { + Label next = a.newLabel(); + + a.cbnz(ARG1, next); + emit_error(BADARG); + a.bind(next); + } else { + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgLabel &Fail, + const ArgRegister &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; + Label next, fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + next = a.newLabel(); + } + + if (emit_bs_get_field_size(Sz, unit, fail, ARG3) >= 0) { + mov_arg(ARG2, Src); + mov_arg(ARG4, Flags); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<4>(erts_new_bs_put_float); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + emit_branch_if_value(ARG1, fail); + } else { + emit_branch_if_not_value(ARG1, next); + } + } + + if (Fail.get() == 0) { + a.bind(fail); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgLabel &Fail, + const ArgWord &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Sz); + mov_arg(ARG4, Flags); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<4>(erts_new_bs_put_float); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + emit_branch_if_value(ARG1, resolve_beam_label(Fail, disp1MB)); + } else { + Label next = a.newLabel(); + + emit_branch_if_not_value(ARG1, next); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_i_bs_start_match3(const ArgRegister &Src, + const ArgWord &Live, + const ArgLabel &Fail, + const ArgRegister &Dst) { + Label is_binary = a.newLabel(), next = a.newLabel(); + + mov_arg(ARG2, Src); + + if (Fail.get() != 0) { + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, ARG2); + } else { + /* bs_start_match3 may not throw, and the compiler will only emit {f,0} + * when it knows that the source is a match state or binary, so we're + * free to skip the binary tests. */ + } + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, ARG2); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, 0)); + + a.and_(TMP1, TMP1, imm(_HEADER_SUBTAG_MASK)); + a.cmp(TMP1, imm(BIN_MATCHSTATE_SUBTAG)); + a.b_eq(next); + + if (Fail.get() != 0) { + comment("is_binary_header"); + a.cmp(TMP1, _TAG_HEADER_SUB_BIN); + a.b_eq(is_binary); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(TMP1, TMP1, imm(~4)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(is_binary); + { + emit_gc_test_preserve(ArgWord(ERL_BIN_MATCHSTATE_SIZE(0)), + Live, + Src, + ARG2); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + /* ARG2 was set above */ + runtime_call<2>(erts_bs_start_match_3); + + emit_leave_runtime(Live.get()); + + a.add(ARG2, ARG1, imm(TAG_PRIMARY_BOXED)); + } + + a.bind(next); + mov_arg(Dst, ARG2); +} + +void BeamModuleAssembler::emit_i_bs_match_string(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Bits, + const ArgBytePtr &Ptr) { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + const int base_offset = offsetof(ErlBinMatchState, mb.base); + + const auto size = Bits.get(); + + { + auto ctx_reg = load_source(Ctx, TMP1); + + a.ldur(TMP2, emit_boxed_val(ctx_reg.reg, position_offset)); + a.ldur(TMP3, emit_boxed_val(ctx_reg.reg, size_offset)); + add(TMP4, TMP2, size); + a.cmp(TMP4, TMP3); + a.b_hi(resolve_beam_label(Fail, disp1MB)); + + /* ARG4 = mb->offset & 7 */ + a.and_(ARG4, TMP2, imm(7)); + + /* ARG3 = mb->base + (mb->offset >> 3) */ + a.ldur(TMP1, emit_boxed_val(ctx_reg.reg, base_offset)); + a.add(ARG3, TMP1, TMP2, arm::lsr(3)); + } + + emit_enter_runtime(); + + mov_arg(ARG1, Ptr); + mov_imm(ARG2, 0); + mov_imm(ARG5, size); + runtime_call<5>(erts_cmp_bits); + + emit_leave_runtime(); + a.cbnz(ARG1, resolve_beam_label(Fail, disp1MB)); + + { + auto ctx_reg = load_source(Ctx, TMP1); + + a.ldur(TMP2, emit_boxed_val(ctx_reg.reg, position_offset)); + add(TMP2, TMP2, size); + a.stur(TMP2, emit_boxed_val(ctx_reg.reg, position_offset)); + } +} + +void BeamModuleAssembler::emit_i_bs_get_position(const ArgRegister &Ctx, + const ArgRegister &Dst) { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + auto ctx_reg = load_source(Ctx, TMP1); + auto dst_reg = init_destination(Dst, TMP2); + + /* Match contexts can never be literals, so we can skip clearing literal + * tags. */ + a.ldur(dst_reg.reg, emit_boxed_val(ctx_reg.reg, position_offset)); + a.lsl(dst_reg.reg, dst_reg.reg, imm(_TAG_IMMED1_SIZE)); + a.orr(dst_reg.reg, dst_reg.reg, imm(_TAG_IMMED1_SMALL)); + + flush_var(dst_reg); +} + +void BeamModuleAssembler::emit_bs_get_integer2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Live, + const ArgSource &Sz, + const ArgWord &Unit, + const ArgWord &Flags, + const ArgRegister &Dst) { + Uint size; + Uint flags = Flags.get(); + + if (flags & BSF_NATIVE) { + flags &= ~BSF_NATIVE; + flags |= BSF_LITTLE; + } + + if (Sz.isSmall() && Sz.as().getUnsigned() < 8 * sizeof(Uint) && + (size = Sz.as().getUnsigned() * Unit.get()) < + 8 * sizeof(Uint)) { + /* Segment of a fixed size supported by bs_match. */ + const ArgVal match[] = {ArgAtom(am_ensure_at_least), + ArgWord(size), + ArgWord(1), + ArgAtom(am_integer), + Live, + ArgWord(flags), + ArgWord(size), + ArgWord(1), + Dst}; + + const Span args(match, sizeof(match) / sizeof(match[0])); + emit_i_bs_match(Fail, Ctx, args); + } else { + Label fail = resolve_beam_label(Fail, dispUnknown); + int unit = Unit.get(); + + if (emit_bs_get_field_size(Sz, unit, fail, ARG5) >= 0) { + /* This operation can be expensive if a bignum can be + * created because there can be a garbage collection. */ + auto max = std::get<1>(getClampedRange(Sz)); + bool potentially_expensive = + max >= SMALL_BITS || (max * Unit.get()) >= SMALL_BITS; + + mov_arg(ARG3, Ctx); + mov_imm(ARG4, flags); + if (potentially_expensive) { + mov_arg(ARG6, Live); + } else { +#ifdef DEBUG + /* Never actually used. */ + mov_imm(ARG6, 1023); +#endif + } + + if (potentially_expensive) { + emit_enter_runtime(Live.get()); + } else { + comment("simplified entering runtime because result is always " + "small"); + emit_enter_runtime(Live.get()); + } + + a.mov(ARG1, c_p); + if (potentially_expensive) { + load_x_reg_array(ARG2); + } else { +#ifdef DEBUG + /* Never actually used. */ + mov_imm(ARG2, 0); +#endif + } + runtime_call<6>(beam_jit_bs_get_integer); + + if (potentially_expensive) { + emit_leave_runtime(Live.get()); + } else { + emit_leave_runtime(Live.get()); + } + + emit_branch_if_not_value(ARG1, fail); + mov_arg(Dst, ARG1); + } + } +} + +void BeamModuleAssembler::emit_bs_test_tail2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Offset) { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + + auto ctx_reg = load_source(Ctx, TMP1); + + ASSERT(Offset.isWord()); + + a.ldur(TMP2, emit_boxed_val(ctx_reg.reg, size_offset)); + a.ldur(TMP3, emit_boxed_val(ctx_reg.reg, position_offset)); + a.sub(TMP2, TMP2, TMP3); + + if (Offset.get() != 0) { + cmp(TMP2, Offset.get()); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + a.cbnz(TMP2, resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_bs_set_position(const ArgRegister &Ctx, + const ArgRegister &Pos) { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + auto [ctx, pos] = load_sources(Ctx, TMP1, Pos, TMP2); + + a.lsr(TMP2, pos.reg, imm(_TAG_IMMED1_SIZE)); + a.stur(TMP2, emit_boxed_val(ctx.reg, position_offset)); +} + +void BeamModuleAssembler::emit_i_bs_get_binary_all2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgWord &Unit, + const ArgRegister &Dst) { + unsigned unit = Unit.get(); + + mov_arg(ARG1, Ctx); + + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), Live, Ctx, ARG1); + + /* Make field fetching slightly more compact by pre-loading the match + * buffer into the right argument slot for `erts_bs_get_binary_all_2`. */ + lea(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); + + ERTS_CT_ASSERT_FIELD_PAIR(ErlBinMatchBuffer, offset, size); + a.ldp(TMP2, TMP3, arm::Mem(ARG2, offsetof(ErlBinMatchBuffer, offset))); + + /* Remainder = Size - Offset */ + a.sub(TMP1, TMP3, TMP2); + + /* Unit may be 1 if compiling with +no_bsm3, which lacks the + * bs_get_tail instruction. */ + if (unit > 1) { + if ((unit & (unit - 1))) { + mov_imm(TMP2, unit); + + a.udiv(TMP3, TMP1, TMP2); + a.msub(TMP1, TMP3, TMP2, TMP1); + + a.cbnz(TMP1, resolve_beam_label(Fail, disp1MB)); + } else { + a.tst(TMP1, imm(unit - 1)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + } + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + /* ARG2 was set above. */ + runtime_call<2>(erts_bs_get_binary_all_2); + + emit_leave_runtime(Live.get()); + + mov_arg(Dst, ARG1); +} + +void BeamGlobalAssembler::emit_bs_get_tail_shared() { + lea(TMP1, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); + + ERTS_CT_ASSERT_FIELD_PAIR(ErlBinMatchBuffer, orig, base); + a.ldp(ARG2, ARG3, arm::Mem(TMP1, offsetof(ErlBinMatchBuffer, orig))); + + ERTS_CT_ASSERT_FIELD_PAIR(ErlBinMatchBuffer, offset, size); + a.ldp(ARG4, TMP1, arm::Mem(TMP1, offsetof(ErlBinMatchBuffer, offset))); + + lea(ARG1, arm::Mem(c_p, offsetof(Process, htop))); + + /* Extracted size = mb->size - mb->offset */ + a.sub(ARG5, TMP1, ARG4); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + runtime_call<5>(erts_extract_sub_binary); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_bs_get_tail(const ArgRegister &Ctx, + const ArgRegister &Dst, + const ArgWord &Live) { + mov_arg(ARG1, Ctx); + + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), Live, Ctx, ARG1); + + fragment_call(ga->get_bs_get_tail_shared()); + + mov_arg(Dst, ARG1); +} + +/* Bits to skip are passed in ARG1 */ +void BeamModuleAssembler::emit_bs_skip_bits(const ArgLabel &Fail, + const ArgRegister &Ctx) { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + + auto ctx_reg = load_source(Ctx, TMP1); + + a.ldur(TMP2, emit_boxed_val(ctx_reg.reg, position_offset)); + a.ldur(TMP3, emit_boxed_val(ctx_reg.reg, size_offset)); + + a.add(TMP2, TMP2, ARG1); + a.cmp(TMP2, TMP3); + a.b_hi(resolve_beam_label(Fail, disp1MB)); + + a.stur(TMP2, emit_boxed_val(ctx_reg.reg, position_offset)); +} + +void BeamModuleAssembler::emit_i_bs_skip_bits2(const ArgRegister &Ctx, + const ArgRegister &Size, + const ArgLabel &Fail, + const ArgWord &Unit) { + Label fail = resolve_beam_label(Fail, dispUnknown); + + bool can_fail = true; + + if (always_small(Size)) { + auto [min, max] = getClampedRange(Size); + can_fail = !(0 <= min && (max >> (SMALL_BITS - ERL_UNIT_BITS)) == 0); + } + + if (!can_fail && Unit.get() == 1) { + comment("simplified skipping because the types are known"); + + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + auto [ctx, size] = load_sources(Ctx, TMP1, Size, TMP2); + + a.ldur(TMP3, emit_boxed_val(ctx.reg, position_offset)); + a.ldur(TMP4, emit_boxed_val(ctx.reg, size_offset)); + + a.add(TMP3, TMP3, size.reg, arm::lsr(_TAG_IMMED1_SIZE)); + a.cmp(TMP3, TMP4); + a.b_hi(resolve_beam_label(Fail, disp1MB)); + + a.stur(TMP3, emit_boxed_val(ctx.reg, position_offset)); + } else if (emit_bs_get_field_size(Size, Unit.get(), fail, ARG1) >= 0) { + emit_bs_skip_bits(Fail, Ctx); + } +} + +void BeamModuleAssembler::emit_i_bs_skip_bits_imm2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Bits) { + mov_arg(ARG1, Bits); + emit_bs_skip_bits(Fail, Ctx); +} + +void BeamModuleAssembler::emit_i_bs_get_binary2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Size, + const ArgWord &Flags, + const ArgRegister &Dst) { + Label fail; + int unit; + + fail = resolve_beam_label(Fail, dispUnknown); + unit = Flags.get() >> 3; + + if (emit_bs_get_field_size(Size, unit, fail, ARG2) >= 0) { + a.str(ARG2, TMP_MEM1q); + + mov_arg(ARG4, Ctx); + + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), + Live, + Ctx, + ARG4); + + lea(ARG4, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb))); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + a.ldr(ARG2, TMP_MEM1q); + mov_imm(ARG3, Flags.get()); + runtime_call<4>(erts_bs_get_binary_2); + + emit_leave_runtime(Live.get()); + + emit_branch_if_not_value(ARG1, fail); + + mov_arg(Dst, ARG1); + } +} + +void BeamModuleAssembler::emit_i_bs_get_float2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Sz, + const ArgWord &Flags, + const ArgRegister &Dst) { + Label fail; + Sint unit; + + fail = resolve_beam_label(Fail, dispUnknown); + unit = Flags.get() >> 3; + + mov_arg(ARG4, Ctx); + + emit_gc_test_preserve(ArgWord(FLOAT_SIZE_OBJECT), Live, Ctx, ARG4); + + if (emit_bs_get_field_size(Sz, unit, fail, ARG2) >= 0) { + lea(ARG4, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb))); + + emit_enter_runtime(Live.get()); + + a.mov(ARG1, c_p); + mov_imm(ARG3, Flags.get()); + runtime_call<4>(erts_bs_get_float_2); + + emit_leave_runtime(Live.get()); + + emit_branch_if_not_value(ARG1, fail); + + mov_arg(Dst, ARG1); + } +} + +void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgSource &Src, + const ArgXRegister &Dst) { + auto src_reg = load_source(Src, TMP1); + auto dst_reg = init_destination(Dst, TMP2); + + Label next = a.newLabel(); + + /* Note that the source and destination registers could be the + * same register. Therefore, we must copy the source register + * before writing to the destination register. */ + a.lsr(TMP1, src_reg.reg, imm(_TAG_IMMED1_SIZE)); + mov_imm(dst_reg.reg, make_small(1)); + a.cmp(TMP1, imm(0x7F)); + a.b_ls(next); + + mov_imm(dst_reg.reg, make_small(2)); + a.cmp(TMP1, imm(0x7FFUL)); + a.b_ls(next); + + a.cmp(TMP1, imm(0x10000UL)); + mov_imm(TMP2, make_small(3)); + mov_imm(TMP3, make_small(4)); + a.csel(dst_reg.reg, TMP2, TMP3, arm::CondCode::kLO); + + a.bind(next); + flush_var(dst_reg); +} + +void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgLabel &Fail, + const ArgSource &Src) { + mov_arg(ARG2, Src); + + emit_enter_runtime(); + + load_erl_bits_state(ARG1); + runtime_call<2>(erts_bs_put_utf8); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } else { + Label next = a.newLabel(); + + a.cbnz(ARG1, next); + emit_error(BADARG); + a.bind(next); + } +} + +/* + * ARG1 = pointer to match state + * ARG2 = number of bits left in binary (< 32) + * ARG3 = position in binary in bits + * ARG4 = base pointer to binary data + * + * See the comment for emit_bs_get_utf8_shared() for details about the + * return value. + */ +void BeamGlobalAssembler::emit_bs_get_utf8_short_shared() { + const int position_offset = offsetof(ErlBinMatchBuffer, offset); + + const arm::Gp match_state = ARG1; + const arm::Gp bitdata = ARG2; + const arm::Gp bin_position = ARG3; + const arm::Gp bin_base = ARG4; + + Label two = a.newLabel(); + Label three_or_more = a.newLabel(); + Label four = a.newLabel(); + Label read_done = a.newLabel(); + Label ascii = a.newLabel(); + Label error = a.newLabel(); + + /* Calculate the number of bytes remaining in the binary and error + * out if less than one. */ + a.lsr(bitdata, bitdata, imm(3)); + a.cbz(bitdata, error); + + /* Calculate a byte mask so we can zero out trailing garbage. */ + a.neg(TMP5, bitdata, arm::lsl(3)); + mov_imm(TMP4, -1); + a.lsl(TMP4, TMP4, TMP5); + + /* If the position in the binary is not byte-aligned, we'll need + * to read one more byte. */ + a.ands(TMP1, bin_position, imm(7)); + a.cinc(bitdata, bitdata, imm(arm::CondCode::kNE)); + + /* Set up pointer to the first byte to read. */ + a.add(TMP2, bin_base, bin_position, arm::lsr(3)); + + a.cmp(bitdata, 2); + a.b_eq(two); + a.b_hi(three_or_more); + + /* Read one byte (always byte-aligned). */ + a.ldrb(bitdata.w(), arm::Mem(TMP2)); + a.b(read_done); + + /* Read two bytes. */ + a.bind(two); + a.ldrh(bitdata.w(), arm::Mem(TMP2)); + a.b(read_done); + + a.bind(three_or_more); + a.cmp(bitdata, 3); + a.b_ne(four); + + /* Read three bytes. */ + a.ldrh(bitdata.w(), arm::Mem(TMP2)); + a.ldrb(TMP3.w(), arm::Mem(TMP2, 2)); + a.orr(bitdata, bitdata, TMP3, arm::lsl(16)); + a.b(read_done); + + /* Read four bytes (always unaligned). */ + a.bind(four); + a.ldr(bitdata.w(), arm::Mem(TMP2)); + + /* Handle the bytes read. */ + a.bind(read_done); + a.rev64(bitdata, bitdata); + a.lsl(bitdata, bitdata, TMP1); + a.and_(bitdata, bitdata, TMP4); + a.tbz(bitdata, imm(63), ascii); + a.b(labels[bs_get_utf8_shared]); + + /* Handle plain old ASCII (code point < 128). */ + a.bind(ascii); + a.add(bin_position, bin_position, imm(8)); + a.str(bin_position, arm::Mem(match_state, position_offset)); + a.mov(ARG1, imm(_TAG_IMMED1_SMALL)); + a.orr(ARG1, ARG1, bitdata, arm::lsr(56 - _TAG_IMMED1_SIZE)); + a.ret(a64::x30); + + /* Signal error. */ + a.bind(error); + mov_imm(ARG1, 0); + a.ret(a64::x30); +} + +/* + * ARG1 = pointer to match state + * ARG2 = 4 bytes read from the binary in big-endian order + * ARG3 = position in binary in bits + * + * On successful return, the extracted code point is a term tagged + * small in ARG1 and the position in the match state has been updated. On + * failure, ARG1 contains an invalid term where the tags bits are zero. + */ +void BeamGlobalAssembler::emit_bs_get_utf8_shared() { + const int position_offset = offsetof(ErlBinMatchBuffer, offset); + + const arm::Gp match_state = ARG1; + const arm::Gp bitdata = ARG2; + const arm::Gp bin_position = ARG3; + + const arm::Gp byte_count = ARG4; + + const arm::Gp shift = TMP4; + const arm::Gp control_mask = TMP5; + const arm::Gp error_mask = TMP6; + + /* UTF-8 has the following layout, where 'x' are data bits: + * + * 1 byte: 0xxxxxxx (not handled by this path) + * 2 bytes: 110xxxxx, 10xxxxxx + * 3 bytes: 1110xxxx, 10xxxxxx 10xxxxxx + * 4 bytes: 11110xxx, 10xxxxxx 10xxxxxx 10xxxxxx + * + * Note that the number of leading bits is equal to the number of bytes, + * which makes it very easy to create masks for extraction and error + * checking. */ + + /* Calculate the number of bytes. */ + a.cls(byte_count, bitdata); + a.add(byte_count, byte_count, imm(1)); + + /* Get rid of the prefix bits. */ + a.lsl(bitdata, bitdata, byte_count); + a.lsr(bitdata, bitdata, byte_count); + + /* Calculate the bit shift now before we start to corrupt the + * byte_count. */ + mov_imm(shift, 64); + a.sub(shift, shift, byte_count, arm::lsl(3)); + + /* Shift down the value to the least significant part of the word. */ + a.lsr(bitdata, bitdata, shift); + + /* Matches the '10xxxxxx' components, leaving the header byte alone. */ + mov_imm(error_mask, 0x00808080ull << 32); + a.lsr(error_mask, error_mask, shift); + + /* Construct the control mask '0x00C0C0C0' (already shifted). */ + a.orr(control_mask, error_mask, error_mask, arm::lsr(1)); + + /* Assert that the header bits of each '10xxxxxx' component are correct, + * signaling errors by trashing the byte count with an illegal + * value (0). */ + a.and_(TMP3, bitdata, control_mask); + a.cmp(TMP3, error_mask); + + a.ubfx(TMP1, bitdata, imm(8), imm(6)); + a.ubfx(TMP2, bitdata, imm(16), imm(6)); + a.ubfx(TMP3, bitdata, imm(24), imm(3)); + a.ubfx(bitdata, bitdata, imm(0), imm(6)); + + a.orr(bitdata, bitdata, TMP1, arm::lsl(6)); + a.orr(bitdata, bitdata, TMP2, arm::lsl(12)); + a.orr(bitdata, bitdata, TMP3, arm::lsl(18)); + + /* Check for too large code point. */ + mov_imm(TMP1, 0x10FFFF); + a.ccmp(bitdata, TMP1, imm(NZCV::kCF), arm::CondCode::kEQ); + + /* Check for the illegal range 16#D800 - 16#DFFF. */ + a.lsr(TMP1, bitdata, imm(11)); + a.ccmp(TMP1, imm(0xD800 >> 11), imm(NZCV::kZF), arm::CondCode::kLS); + a.csel(byte_count, byte_count, ZERO, imm(arm::CondCode::kNE)); + + /* Test for overlong UTF-8 sequence. That can be done by testing + * that the bits marked y below are all zero. + * + * 1 byte: 0xxxxxxx (not handled by this path) + * 2 bytes: 110yyyyx, 10xxxxxx + * 3 bytes: 1110yyyy, 10yxxxxx 10xxxxxx + * 4 bytes: 11110yyy, 10yyxxxx 10xxxxxx 10xxxxxx + * + * 1 byte: xx'xxxxx + * 2 bytes: y'yyyxx'xxxxx + * 3 bytes: y'yyyyx'xxxxx'xxxxx + * 4 bytes: y'yyyyx'xxxxx'xxxxx'xxxxx + * + * The y bits can be isolated by shifting down by the number of bits + * shown in this table: + * + * 2: 7 (byte_count * 4 - 1) + * 3: 11 (byte_count * 4 - 1) + * 4: 16 (byte_count * 4) + */ + + /* Calculate number of bits to shift. */ + a.lsl(TMP1, byte_count, imm(2)); + a.cmp(byte_count, imm(4)); + a.csetm(TMP2, imm(arm::CondCode::kNE)); + a.add(TMP1, TMP1, TMP2); + + /* Pre-fill the tag bits so that we can clear them on error. */ + mov_imm(TMP2, _TAG_IMMED1_SMALL); + + /* Now isolate the y bits and compare to zero. This check will + * be used in a CCMP further down. */ + a.lsr(TMP1, bitdata, TMP1); + a.cmp(TMP1, 0); + + /* Byte count must be 2, 3, or 4. */ + a.sub(TMP1, byte_count, imm(2)); + a.ccmp(TMP1, imm(2), imm(NZCV::kCF), imm(arm::CondCode::kNE)); + + /* If we have failed, we set byte_count to zero to ensure that the + * position update nops, and set the pre-tagged result to zero so + * that we can check for error in module code by testing the tag + * bits. */ + a.csel(byte_count, byte_count, ZERO, imm(arm::CondCode::kLS)); + a.csel(TMP2, TMP2, ZERO, imm(arm::CondCode::kLS)); + + a.add(bin_position, bin_position, byte_count, arm::lsl(3)); + a.str(bin_position, arm::Mem(match_state, position_offset)); + a.orr(ARG1, TMP2, bitdata, arm::lsl(_TAG_IMMED1_SIZE)); + + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_bs_get_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail) { + const int base_offset = offsetof(ErlBinMatchBuffer, base); + const int position_offset = offsetof(ErlBinMatchBuffer, offset); + + const arm::Gp match_state = ARG1; + const arm::Gp bitdata = ARG2; + const arm::Gp bin_position = ARG3; + const arm::Gp bin_base = ARG4; + const arm::Gp bin_size = ARG5; + + auto ctx = load_source(Ctx, ARG6); + + Label non_ascii = a.newLabel(); + Label fallback = a.newLabel(); + Label check = a.newLabel(); + Label done = a.newLabel(); + + lea(match_state, emit_boxed_val(ctx.reg, offsetof(ErlBinMatchState, mb))); + ERTS_CT_ASSERT_FIELD_PAIR(ErlBinMatchBuffer, offset, size); + a.ldp(bin_position, bin_size, arm::Mem(ARG1, position_offset)); + a.ldr(bin_base, arm::Mem(ARG1, base_offset)); + a.sub(bitdata, bin_size, bin_position); + a.cmp(bitdata, imm(32)); + a.b_lo(fallback); + + emit_read_bits(32, bin_base, bin_position, bitdata); + a.tbnz(bitdata, imm(63), non_ascii); + + /* Handle plain old ASCII (code point < 128). */ + a.add(bin_position, bin_position, imm(8)); + a.str(bin_position, arm::Mem(ARG1, position_offset)); + a.mov(ARG1, imm(_TAG_IMMED1_SMALL)); + a.orr(ARG1, ARG1, bitdata, arm::lsr(56 - _TAG_IMMED1_SIZE)); + a.b(done); + + /* Handle code point >= 128. */ + a.bind(non_ascii); + fragment_call(ga->get_bs_get_utf8_shared()); + a.b(check); + + /* + * Handle the case that there are not 4 bytes available in the binary. + */ + + a.bind(fallback); + fragment_call(ga->get_bs_get_utf8_short_shared()); + + a.bind(check); + ERTS_CT_ASSERT((_TAG_IMMED1_SMALL & 1) != 0); + a.tbz(ARG1, imm(0), resolve_beam_label(Fail, disp32K)); + + a.bind(done); +} + +void BeamModuleAssembler::emit_i_bs_get_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgRegister &Dst) { + emit_bs_get_utf8(Ctx, Fail); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_bs_skip_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail) { + emit_bs_get_utf8(Ctx, Fail); +} + +void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgSource &Src, + const ArgXRegister &Dst) { + auto src_reg = load_source(Src, TMP1); + auto dst_reg = init_destination(Dst, TMP2); + + /* erts_bs_put_utf16 errors out whenever something's fishy, so we can + * return garbage (2 or 4) if our input is not a small. */ + a.asr(TMP1, src_reg.reg, imm(_TAG_IMMED1_SIZE)); + a.cmp(TMP1, imm(0x10000UL)); + mov_imm(TMP1, make_small(2)); + mov_imm(TMP2, make_small(4)); + a.csel(dst_reg.reg, TMP1, TMP2, arm::CondCode::kLO); + + flush_var(dst_reg); +} + +void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgLabel &Fail, + const ArgWord &Flags, + const ArgSource &Src) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Flags); + + emit_enter_runtime(); + + load_erl_bits_state(ARG1); + runtime_call<3>(erts_bs_put_utf16); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } else { + Label next = a.newLabel(); + + a.cbnz(ARG1, next); + emit_error(BADARG); + a.bind(next); + } +} + +void BeamModuleAssembler::emit_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags) { + auto ctx_reg = load_source(Ctx, TMP1); + + lea(ARG1, emit_boxed_val(ctx_reg.reg, offsetof(ErlBinMatchState, mb))); + + emit_enter_runtime(); + + mov_imm(ARG2, Flags.get()); + runtime_call<2>(erts_bs_get_utf16); + + emit_leave_runtime(); + + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); +} + +void BeamModuleAssembler::emit_i_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags, + const ArgRegister &Dst) { + emit_bs_get_utf16(Ctx, Fail, Flags); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_bs_skip_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags) { + emit_bs_get_utf16(Ctx, Fail, Flags); +} + +void BeamModuleAssembler::emit_validate_unicode(Label next, + Label fail, + arm::Gp value) { + ASSERT(value != TMP2); + + a.and_(TMP2, value, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_ne(fail); + + mov_imm(TMP2, make_small(0xD800UL)); + a.cmp(value, TMP2); + a.b_lo(next); + + mov_imm(TMP2, make_small(0xDFFFUL)); + a.cmp(value, TMP2); + a.b_ls(fail); + + mov_imm(TMP2, make_small(0x10FFFFUL)); + a.cmp(value, TMP2); + a.b_hi(fail); + + a.b(next); +} + +void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgLabel &Fail, + const ArgSource &Src) { + auto src_reg = load_source(Src, TMP1); + Label fail, next = a.newLabel(); + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else { + fail = a.newLabel(); + } + + emit_validate_unicode(next, fail, src_reg.reg); + + if (Fail.get() == 0) { + a.bind(fail); + emit_error(BADARG); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_i_bs_validate_unicode_retract( + const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Ms) { + Label fail = a.newLabel(), next = a.newLabel(); + auto src_reg = load_source(Src, TMP1); + + emit_validate_unicode(next, fail, src_reg.reg); + + a.bind(fail); + { + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + auto ctx_reg = load_source(Ms, TMP2); + + a.ldur(TMP1, emit_boxed_val(ctx_reg.reg, position_offset)); + a.sub(TMP1, TMP1, imm(32)); + a.stur(TMP1, emit_boxed_val(ctx_reg.reg, position_offset)); + + if (Fail.get() != 0) { + a.b(resolve_beam_label(Fail, disp128MB)); + } else { + emit_error(BADARG); + } + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_bs_test_unit(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Unit) { + auto ctx_reg = load_source(Ctx, TMP1); + unsigned int unit = Unit.get(); + + a.ldur(TMP2, + emit_boxed_val(ctx_reg.reg, offsetof(ErlBinMatchState, mb.size))); + a.ldur(TMP3, + emit_boxed_val(ctx_reg.reg, offsetof(ErlBinMatchState, mb.offset))); + + a.sub(TMP1, TMP2, TMP3); + + if ((unit & (unit - 1))) { + mov_imm(TMP2, unit); + + a.udiv(TMP3, TMP1, TMP2); + a.msub(TMP1, TMP3, TMP2, TMP1); + + a.cbnz(TMP1, resolve_beam_label(Fail, disp1MB)); + } else { + a.tst(TMP1, imm(unit - 1)); + a.b_ne(resolve_beam_label(Fail, dispUnknown)); + } +} + +/* ARG2 = current `Size`, + * ARG3 = elements to `Add`, + * ARG4 = element `Unit` + * + * Error is indicated through cond_ne() */ +void BeamGlobalAssembler::emit_bs_add_guard_shared() { + Label error = a.newLabel(); + + /* Since `Unit` is guaranteed to be less than 1024, we can check overflow + * and negative numbers by testing whether any of the highest 12 value bits + * are set on either argument. */ + a.orr(TMP1, ARG2, ARG3); + a.tst(TMP1, imm(0xFFF0000000000000UL)); + + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.ccmp(TMP1, + imm(_TAG_IMMED1_SMALL), + imm(NZCV::kNone), + imm(arm::CondCode::kEQ)); + a.b_ne(error); + + /* Return `Size` + `Add` * `Unit` + * + * Note that the result takes the tag bits from `Size` */ + a.and_(TMP2, ARG3, imm(~_TAG_IMMED1_SMALL)); + a.mul(TMP2, TMP2, ARG4); + a.add(ARG1, TMP2, ARG2); + + a.bind(error); + a.ret(a64::x30); +} + +/* ARG2 = current `Size`, + * ARG3 = elements to `Add`, + * ARG4 = element `Unit` */ +void BeamGlobalAssembler::emit_bs_add_body_shared() { + Label error = a.newLabel(); + + /* Since `Unit` is guaranteed to be less than 1024, we can check overflow + * and negative numbers by testing whether any of the highest 12 value bits + * are set on either argument. */ + a.orr(TMP1, ARG2, ARG3); + a.tst(TMP1, imm(0xFFF0000000000000UL)); + + a.and_(TMP1, ARG2, ARG3); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + a.ccmp(TMP1, + imm(_TAG_IMMED1_SMALL), + imm(NZCV::kNone), + imm(arm::CondCode::kEQ)); + a.b_ne(error); + + /* Return `Size` + `Add` * `Unit` + * + * Note that the result takes the tag bits from `Size` */ + a.and_(TMP2, ARG3, imm(~_TAG_IMMED1_SMALL)); + a.mul(TMP2, TMP2, ARG4); + a.add(ARG1, TMP2, ARG2); + a.ret(a64::x30); + + a.bind(error); + { + emit_enter_runtime_frame(); + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<3>(beam_jit_bs_add_argument_error); + + emit_leave_runtime(0); + emit_leave_runtime_frame(); + + mov_imm(ARG4, 0); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_bs_add(const ArgLabel &Fail, + const ArgSource &Size, + const ArgSource &Add, + const ArgWord &Unit, + const ArgXRegister &Dst) { + ASSERT(Unit.get() < 1024); + + mov_arg(ARG2, Size); + mov_arg(ARG3, Add); + mov_arg(ARG4, Unit); + + if (Fail.get() == 0) { + fragment_call(ga->get_bs_add_body_shared()); + } else { + fragment_call(ga->get_bs_add_guard_shared()); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_bs_append(const ArgLabel &Fail, + const ArgWord &ExtraHeap, + const ArgWord &Live, + const ArgWord &Unit, + const ArgSource &Size, + const ArgSource &Bin, + const ArgRegister &Dst) { + mov_arg(ARG3, Live); + mov_arg(ARG4, Size); + mov_arg(ARG5, ExtraHeap); + mov_arg(ARG6, Unit); + + mov_arg(ArgXRegister(Live.get()), Bin); + + emit_enter_runtime(Live.get() + 1); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<6>(erts_bs_append); + + emit_leave_runtime(Live.get() + 1); + + if (Fail.get() != 0) { + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + Label next = a.newLabel(); + + emit_branch_if_value(ARG1, next); + /* The error has been prepared in `erts_bs_append` */ + emit_raise_exception(); + + a.bind(next); + } + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_bs_private_append(const ArgLabel &Fail, + const ArgWord &Unit, + const ArgSource &Size, + const ArgRegister &Src, + const ArgXRegister &Dst) { + mov_arg(ARG2, Src); + mov_arg(ARG3, Size); + mov_arg(ARG4, Unit); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<4>(erts_bs_private_append); + + emit_leave_runtime(); + + if (Fail.get() != 0) { + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + Label next = a.newLabel(); + + emit_branch_if_value(ARG1, next); + /* The error has been prepared in `erts_bs_private_append` */ + emit_raise_exception(); + + a.bind(next); + } + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_bs_init_writable() { + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 0); + + a.mov(ARG1, c_p); + a.mov(ARG2, XREG0); + + /* We have an implicit liveness of 0, so we don't need to stash X + * registers. */ + emit_enter_runtime(0); + + runtime_call<2>(erts_bs_init_writable); + + emit_leave_runtime(0); + + a.mov(XREG0, ARG1); +} + +void BeamGlobalAssembler::emit_bs_create_bin_error_shared() { + a.mov(XREG0, a64::x30); + + emit_enter_runtime(0); + + /* ARG3 is already set by the caller */ + a.mov(ARG2, ARG4); + a.mov(ARG4, ARG1); + a.mov(ARG1, c_p); + runtime_call<4>(beam_jit_bs_construct_fail_info); + + emit_leave_runtime(0); + + a.mov(ARG4, ZERO); + a.mov(ARG2, XREG0); + a.b(labels[raise_exception_shared]); +} + +/* + * ARG1 = term + * + * If the term in ARG1 is a binary on entry, on return + * ARG1 will contain the size of the binary in bits and + * sign flag will be cleared. + * + * If the term is not a binary, the sign flag will be set. + */ +void BeamGlobalAssembler::emit_bs_bit_size_shared() { + Label not_sub_bin = a.newLabel(); + Label fail = a.newLabel(); + + arm::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + + emit_is_boxed(fail, boxed_ptr); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_SUB_BIN)); + a.b_ne(not_sub_bin); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.ldurb(TMP2.w(), emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + + a.adds(ARG1, TMP2, TMP1, arm::lsl(3)); + a.ret(a64::x30); + + a.bind(not_sub_bin); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(TMP1, TMP1, imm(~4)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(fail); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.lsl(ARG1, TMP1, imm(3)); + a.tst(ARG1, ARG1); + + a.ret(a64::x30); + + a.bind(fail); + mov_imm(ARG1, -1); + a.tst(ARG1, ARG1); + + a.ret(a64::x30); +} + +/* + * ARG1 = tagged bignum term + */ +void BeamGlobalAssembler::emit_get_sint64_shared() { + Label success = a.newLabel(); + Label fail = a.newLabel(); + + emit_is_boxed(fail, ARG1); + arm::Gp boxed_ptr = emit_ptr_val(TMP3, ARG1); + a.ldr(TMP1, emit_boxed_val(boxed_ptr)); + a.ldr(TMP2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(POS_BIG_SUBTAG)); + a.b_eq(success); + + a.cmp(TMP1, imm(NEG_BIG_SUBTAG)); + a.b_ne(fail); + + a.neg(TMP2, TMP2); + + a.bind(success); + { + a.mov(ARG1, TMP2); + /* Clear Z flag. + * + * TMP1 is known to be POS_BIG_SUBTAG or NEG_BIG_SUBTAG at this point. + */ + ERTS_CT_ASSERT(POS_BIG_SUBTAG != 0 && NEG_BIG_SUBTAG != 0); + a.tst(TMP1, TMP1); + a.ret(a64::x30); + } + + a.bind(fail); + { + a.tst(ZERO, ZERO); + a.ret(a64::x30); + } +} + +struct BscSegment { + BscSegment() + : type(am_false), unit(1), flags(0), src(ArgNil()), size(ArgNil()), + error_info(0), effectiveSize(-1), action(action::DIRECT) { + } + + Eterm type; + Uint unit; + Uint flags; + ArgVal src; + ArgVal size; + + Uint error_info; + Sint effectiveSize; + + /* Here are sub actions for storing integer segments. + * + * We use the ACCUMULATE_FIRST and ACCUMULATE actions to shift the + * values of segments with known, small sizes (no more than 64 bits) + * into an accumulator register. + * + * When no more segments can be accumulated, the STORE action is + * used to store the value of the accumulator into the binary. + * + * The DIRECT action is used when it is not possible to use the + * accumulator (for unknown or too large sizes). + */ + enum class action { DIRECT, ACCUMULATE_FIRST, ACCUMULATE, STORE } action; +}; + +static std::vector bs_combine_segments( + const std::vector segments) { + std::vector segs; + + for (auto seg : segments) { + switch (seg.type) { + case am_integer: { + if (!(0 < seg.effectiveSize && seg.effectiveSize <= 64)) { + /* Unknown or too large size. Handle using the default + * DIRECT action. */ + segs.push_back(seg); + continue; + } + + if (seg.flags & BSF_LITTLE || segs.size() == 0 || + segs.back().action == BscSegment::action::DIRECT) { + /* There are no previous compatible ACCUMULATE / STORE + * actions. Create the first ones. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + continue; + } + + auto prev = segs.back(); + if (prev.flags & BSF_LITTLE) { + /* Little-endian segments cannot be combined with other + * segments. Create new ACCUMULATE_FIRST / STORE actions. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + continue; + } + + /* The current segment is compatible with the previous + * segment. Try combining them. */ + if (prev.effectiveSize + seg.effectiveSize <= 64) { + /* The combined values of the segments fit in the + * accumulator. Insert an ACCUMULATE action for the + * current segment before the pre-existing STORE + * action. */ + segs.pop_back(); + prev.effectiveSize += seg.effectiveSize; + seg.action = BscSegment::action::ACCUMULATE; + segs.push_back(seg); + segs.push_back(prev); + } else { + /* The size exceeds 64 bits. Can't combine. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + } + break; + } + default: + segs.push_back(seg); + break; + } + } + return segs; +} + +/* + * In: + * bin_offset = register to store the bit offset into the binary + * bit_offset = current bit offset into binary, or -1 if unknown + * size = size of segment to be constructed + * (ignored if size_reg is valid register) + * size_reg = if a valid register, it contains the size of + * the segment to be constructed + * + * Out: + * bin_offset register = if bit_offset is not byte aligned, the bit + * offset into the binary + * TMP1 = pointer to the current byte in the binary + * + * Preserves all other ARG* registers. + */ +void BeamModuleAssembler::update_bin_state(arm::Gp bin_offset, + Sint bit_offset, + Sint size, + arm::Gp size_reg) { + int cur_bin_offset = offsetof(ErtsSchedulerRegisters, + aux_regs.d.erl_bits_state.erts_current_bin_); + arm::Mem mem_bin_base = arm::Mem(scheduler_registers, cur_bin_offset); + arm::Mem mem_bin_offset = + arm::Mem(scheduler_registers, cur_bin_offset + sizeof(Eterm)); + + if (bit_offset % 8 != 0) { + /* The bit offset is unknown or not byte-aligned. */ + ERTS_CT_ASSERT_FIELD_PAIR(struct erl_bits_state, + erts_current_bin_, + erts_bin_offset_); + a.ldp(TMP2, bin_offset, mem_bin_base); + + if (size_reg.isValid()) { + a.add(TMP1, bin_offset, size_reg); + } else { + add(TMP1, bin_offset, size); + } + a.str(TMP1, mem_bin_offset); + + a.add(TMP1, TMP2, bin_offset, arm::lsr(3)); + } else { + comment("optimized updating of binary construction state"); + ASSERT(size >= 0 || size_reg.isValid()); + ASSERT(bit_offset % 8 == 0); + a.ldr(TMP1, mem_bin_base); + if (size_reg.isValid()) { + if (bit_offset == 0) { + a.str(size_reg, mem_bin_offset); + } else { + add(TMP2, size_reg, bit_offset); + a.str(TMP2, mem_bin_offset); + } + } else { + mov_imm(TMP2, bit_offset + size); + a.str(TMP2, mem_bin_offset); + } + if (bit_offset != 0) { + add(TMP1, TMP1, bit_offset >> 3); + } + } +} + +/* + * The size of the segment is assumed to be in ARG3. + */ +void BeamModuleAssembler::set_zero(Sint effectiveSize) { + Label store_units = a.newLabel(); + Label less_than_a_store_unit = a.newLabel(); + Sint store_unit = 1; + + update_bin_state(ARG2, -1, -1, ARG3); + + if (effectiveSize >= 256) { + /* Store four 64-bit words machine words when the size is + * known and at least 256 bits. */ + store_unit = 4; + a.movi(a64::d31, 0); + } else if (effectiveSize >= 128) { + /* Store two 64-bit words machine words when the size is + * known and at least 128 bits. */ + store_unit = 2; + } + + if (effectiveSize < Sint(store_unit * 8 * sizeof(Eterm))) { + /* The size is either not known or smaller than a word. */ + a.cmp(ARG3, imm(store_unit * 8 * sizeof(Eterm))); + a.b_lt(less_than_a_store_unit); + } + + a.bind(store_units); + if (store_unit == 4) { + a.stp(a64::q31, a64::q31, arm::Mem(TMP1).post(sizeof(Eterm[4]))); + } else if (store_unit == 2) { + a.stp(ZERO, ZERO, arm::Mem(TMP1).post(sizeof(Eterm[2]))); + } else { + a.str(ZERO, arm::Mem(TMP1).post(sizeof(Eterm))); + } + a.sub(ARG3, ARG3, imm(store_unit * 8 * sizeof(Eterm))); + + a.cmp(ARG3, imm(store_unit * 8 * sizeof(Eterm))); + a.b_ge(store_units); + + a.bind(less_than_a_store_unit); + if (effectiveSize < 0) { + /* Unknown size. */ + Label byte_loop = a.newLabel(); + Label done = a.newLabel(); + + ASSERT(store_unit = 1); + + a.cbz(ARG3, done); + + a.bind(byte_loop); + a.strb(ZERO.w(), arm::Mem(TMP1).post(1)); + a.subs(ARG3, ARG3, imm(8)); + a.b_gt(byte_loop); + + a.bind(done); + } else if (effectiveSize % (store_unit * 8 * sizeof(Eterm)) != 0) { + /* The size is known, and we know that there are less than + * 256 bits to initialize. */ + if (store_unit == 4 && (effectiveSize & 255) >= 128) { + a.stp(ZERO, ZERO, arm::Mem(TMP1).post(16)); + } + + if ((effectiveSize & 127) >= 64) { + a.str(ZERO, arm::Mem(TMP1).post(8)); + } + + if ((effectiveSize & 63) >= 32) { + a.str(ZERO.w(), arm::Mem(TMP1).post(4)); + } + + if ((effectiveSize & 31) >= 16) { + a.strh(ZERO.w(), arm::Mem(TMP1).post(2)); + } + + if ((effectiveSize & 15) >= 8) { + a.strb(ZERO.w(), arm::Mem(TMP1).post(1)); + } + + if ((effectiveSize & 7) > 0) { + a.strb(ZERO.w(), arm::Mem(TMP1)); + } + } +} + +/* + * In: + * + * ARG1 = valid unicode code point (=> 0x80) to encode + * + * Out: + * + * ARG1 = the code point encoded in UTF-8. + * ARG4 = number of bits of result (16, 24, or 32) + * + * Preserves other ARG* registers, clobbers TMP* registers + */ +void BeamGlobalAssembler::emit_construct_utf8_shared() { + Label more_than_two_bytes = a.newLabel(); + Label four_bytes = a.newLabel(); + const arm::Gp value = ARG1; + const arm::Gp num_bits = ARG4; + + a.cmp(value, imm(0x800)); + a.b_hs(more_than_two_bytes); + + /* Encode Unicode code point in two bytes. */ + a.ubfiz(TMP1, value, imm(8), imm(6)); + mov_imm(TMP2, 0x80c0); + a.orr(TMP1, TMP1, value, arm::lsr(6)); + mov_imm(num_bits, 16); + a.orr(value, TMP1, TMP2); + a.ret(a64::x30); + + /* Test whether the value should be encoded in four bytes. */ + a.bind(more_than_two_bytes); + a.lsr(TMP1, value, imm(16)); + a.cbnz(TMP1, four_bytes); + + /* Encode Unicode code point in three bytes. */ + a.lsl(TMP1, value, imm(2)); + a.ubfiz(TMP2, value, imm(16), imm(6)); + a.and_(TMP1, TMP1, imm(0x3f00)); + mov_imm(num_bits, 24); + a.orr(TMP1, TMP1, value, arm::lsr(12)); + a.orr(TMP1, TMP1, TMP2); + mov_imm(TMP2, 0x8080e0); + a.orr(value, TMP1, TMP2); + a.ret(a64::x30); + + /* Encode Unicode code point in four bytes. */ + a.bind(four_bytes); + a.lsl(TMP1, value, imm(10)); + a.lsr(TMP2, value, imm(4)); + a.and_(TMP1, TMP1, imm(0x3f0000)); + a.and_(TMP2, TMP2, imm(0x3f00)); + a.bfxil(TMP1, value, imm(18), imm(14)); + mov_imm(num_bits, 32); + a.bfi(TMP1, value, imm(24), imm(6)); + a.orr(TMP1, TMP1, TMP2); + mov_imm(TMP2, 0x808080f0); + a.orr(value, TMP1, TMP2); + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_construct_utf8(const ArgVal &Src, + Sint bit_offset, + bool is_byte_aligned) { + Label prepare_store = a.newLabel(); + Label store = a.newLabel(); + Label next = a.newLabel(); + + comment("construct utf8 segment"); + auto src = load_source(Src, ARG1); + + a.lsr(ARG1, src.reg, imm(_TAG_IMMED1_SIZE)); + mov_imm(ARG4, 8); + a.cmp(ARG1, imm(0x80)); + a.b_lo(prepare_store); + + fragment_call(ga->get_construct_utf8_shared()); + + a.bind(prepare_store); + arm::Gp bin_offset = ARG3; + update_bin_state(bin_offset, bit_offset, -1, ARG4); + + if (!is_byte_aligned) { + /* Not known to be byte-aligned. Must test alignment. */ + a.ands(TMP2, bin_offset, imm(7)); + a.b_eq(store); + + /* We must combine the last partial byte with the UTF-8 + * encoded code point. */ + a.ldrb(TMP5.w(), arm::Mem(TMP1)); + + a.rev64(TMP4, ARG1); + a.lsr(TMP4, TMP4, TMP2); + a.rev64(TMP4, TMP4); + + a.lsl(TMP5, TMP5, TMP2); + a.and_(TMP5, TMP5, imm(~0xff)); + a.lsr(TMP5, TMP5, TMP2); + + a.orr(ARG1, TMP4, TMP5); + + a.add(ARG4, ARG4, imm(8)); + } + + a.bind(store); + if (bit_offset % (4 * 8) == 0) { + /* This segment is aligned on a 4-byte boundary. This implies + * that a 4-byte write will be inside the allocated binary. */ + a.str(ARG1.w(), arm::Mem(TMP1)); + } else { + Label do_store_1 = a.newLabel(); + Label do_store_2 = a.newLabel(); + + /* Unsuitable or unknown alignment. We must be careful not + * to write beyound the allocated end of the binary. */ + a.cmp(ARG4, imm(8)); + a.b_ne(do_store_1); + + a.strb(ARG1.w(), arm::Mem(TMP1)); + a.b(next); + + a.bind(do_store_1); + a.cmp(ARG4, imm(24)); + a.b_hi(do_store_2); + + a.strh(ARG1.w(), arm::Mem(TMP1)); + a.cmp(ARG4, imm(16)); + a.b_eq(next); + + a.lsr(ARG1, ARG1, imm(16)); + a.strb(ARG1.w(), arm::Mem(TMP1, 2)); + a.b(next); + + a.bind(do_store_2); + a.str(ARG1.w(), arm::Mem(TMP1)); + + if (!is_byte_aligned) { + a.cmp(ARG4, imm(32)); + a.b_eq(next); + + a.lsr(ARG1, ARG1, imm(32)); + a.strb(ARG1.w(), arm::Mem(TMP1, 4)); + } + } + + a.bind(next); +} + +/* + * In: + * TMP1 = pointer to current byte + * ARG3 = bit offset + * ARG4 = number of bits to write + * ARG8 = data to write + */ +void BeamGlobalAssembler::emit_store_unaligned() { + Label loop = a.newLabel(); + Label done = a.newLabel(); + const arm::Gp left_bit_offset = ARG3; + const arm::Gp right_bit_offset = TMP6; + const arm::Gp num_bits = ARG4; + const arm::Gp bitdata = ARG8; + + a.ldrb(TMP5.w(), arm::Mem(TMP1)); + + a.and_(TMP4, bitdata, imm(0xff)); + a.lsr(TMP4, TMP4, left_bit_offset); + + a.lsl(TMP5, TMP5, left_bit_offset); + a.and_(TMP5, TMP5, imm(~0xff)); + a.lsr(TMP5, TMP5, left_bit_offset); + + a.orr(TMP5, TMP4, TMP5); + + a.strb(TMP5.w(), arm::Mem(TMP1).post(1)); + + mov_imm(right_bit_offset, 8); + a.sub(right_bit_offset, right_bit_offset, left_bit_offset); + + a.rev64(bitdata, bitdata); + a.lsl(bitdata, bitdata, right_bit_offset); + + a.subs(num_bits, num_bits, right_bit_offset); + a.b_le(done); + + a.bind(loop); + a.ror(bitdata, bitdata, imm(56)); + a.strb(bitdata.w(), arm::Mem(TMP1).post(1)); + a.subs(num_bits, num_bits, imm(8)); + a.b_gt(loop); + + a.bind(done); + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_i_bs_create_bin(const ArgLabel &Fail, + const ArgWord &Alloc, + const ArgWord &Live0, + const ArgRegister &Dst, + const Span &args) { + Uint num_bits = 0; + Uint estimated_num_bits = 0; + std::size_t n = args.size(); + std::vector segments; + Label error; /* Intentionally uninitialized */ + ArgWord Live = Live0; + arm::Gp sizeReg; + Sint allocated_size = -1; + bool need_error_handler = false; + + /* + * Collect information about each segment and calculate sizes of + * fixed segments. + */ + for (std::size_t i = 0; i < n; i += 6) { + BscSegment seg; + JitBSCOp bsc_op; + Uint bsc_segment; + + seg.type = args[i].as().get(); + bsc_segment = args[i + 1].as().get(); + seg.unit = args[i + 2].as().get(); + seg.flags = args[i + 3].as().get(); + seg.src = args[i + 4]; + seg.size = args[i + 5]; + + switch (seg.type) { + case am_float: + bsc_op = BSC_OP_FLOAT; + break; + case am_integer: + bsc_op = BSC_OP_INTEGER; + break; + case am_utf8: + bsc_op = BSC_OP_UTF8; + break; + case am_utf16: + bsc_op = BSC_OP_UTF16; + break; + case am_utf32: + bsc_op = BSC_OP_UTF32; + break; + default: + bsc_op = BSC_OP_BINARY; + break; + } + + /* + * Save segment number and operation for use in extended + * error information. + */ + seg.error_info = beam_jit_set_bsc_segment_op(bsc_segment, bsc_op); + + /* + * Test whether we can omit the code for the error handler. + */ + switch (seg.type) { + case am_append: + if (!(exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit)) { + need_error_handler = true; + } + break; + case am_binary: + if (!(seg.size.isAtom() && seg.size.as().get() == am_all && + exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit)) { + need_error_handler = true; + } + break; + case am_integer: + if (!exact_type(seg.src)) { + need_error_handler = true; + } + break; + case am_private_append: + case am_string: + break; + default: + need_error_handler = true; + break; + } + + /* + * Attempt to calculate the effective size of this segment. + * Give up if variable or invalid. + */ + if (seg.size.isSmall() && seg.unit != 0) { + Uint unsigned_size = seg.size.as().getUnsigned(); + + if ((unsigned_size >> (sizeof(Eterm) - 1) * 8) != 0) { + /* Suppress creation of heap binary. */ + estimated_num_bits += (ERL_ONHEAP_BIN_LIMIT + 1) * 8; + } else { + /* This multiplication cannot overflow. */ + Uint seg_size = seg.unit * unsigned_size; + seg.effectiveSize = seg_size; + num_bits += seg_size; + estimated_num_bits += seg_size; + } + } else if (seg.unit > 0) { + if ((seg.unit % 8) == 0) { + auto max = std::min(std::get<1>(getClampedRange(seg.size)), + Sint((ERL_ONHEAP_BIN_LIMIT + 1) * 8)); + estimated_num_bits += max * seg.unit; + } else { + /* May create a non-binary bitstring in some cases, suppress + * creation of heap binary. */ + estimated_num_bits += (ERL_ONHEAP_BIN_LIMIT + 1) * 8; + } + } else { + switch (seg.type) { + case am_utf8: + case am_utf16: + case am_utf32: + estimated_num_bits += 32; + break; + default: + /* Suppress creation of heap binary. */ + estimated_num_bits += (ERL_ONHEAP_BIN_LIMIT + 1) * 8; + break; + } + } + + if (seg.effectiveSize < 0 && seg.type != am_append && + seg.type != am_private_append) { + /* At least one segment will need a dynamic size + * calculation. */ + sizeReg = ARG8; + need_error_handler = true; + } + + segments.insert(segments.end(), seg); + } + + if (need_error_handler && Fail.get() != 0) { + error = resolve_beam_label(Fail, dispUnknown); + } else if (need_error_handler) { + Label past_error = a.newLabel(); + + a.b(past_error); + + error = a.newLabel(); + a.bind(error); + { + /* + * ARG1 = optional bad size value; valid if BSC_VALUE_ARG1 is set in + * ARG4 + * + * ARG3 = optional bad size value; valid if BSC_VALUE_ARG3 is + * set in ARG4 + * + * ARG4 = packed error information + */ + comment("handle error"); + fragment_call(ga->get_bs_create_bin_error_shared()); + last_error_offset = a.offset(); + } + + a.bind(past_error); + } else { + comment("(cannot fail)"); + } + + /* We count the total number of bits in an unsigned integer. To + * avoid having to check for overflow when adding to the counter, + * we ensure that the signed size of each segment fits in a + * word. */ + if (sizeReg.isValid()) { + comment("calculate sizes"); + mov_imm(sizeReg, num_bits); + } + + /* Generate code for calculating the size of the binary to be + * created. */ + for (auto seg : segments) { + if (seg.effectiveSize >= 0) { + continue; + } + + if (seg.type == am_append || seg.type == am_private_append) { + continue; + } + + if (seg.size.isAtom() && seg.size.as().get() == am_all && + seg.type == am_binary) { + comment("size of an entire binary"); + if (exact_type(seg.src)) { + auto src = load_source(seg.src, ARG1); + arm::Gp boxed_ptr = emit_ptr_val(ARG1, src.reg); + auto unit = getSizeUnit(seg.src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + + if (is_bitstring) { + comment("inlined size code because the value is always " + "a bitstring"); + } else { + comment("inlined size code because the value is always " + "a binary"); + } + + a.ldur(TMP2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + + if (is_bitstring) { + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + } + + a.add(sizeReg, sizeReg, TMP2, arm::lsl(3)); + + if (is_bitstring) { + Label not_sub_bin = a.newLabel(); + const int bit_number = 3; + ERTS_CT_ASSERT( + (_TAG_HEADER_SUB_BIN & (1 << bit_number)) != 0 && + (_TAG_HEADER_REFC_BIN & (1 << bit_number)) == 0 && + (_TAG_HEADER_HEAP_BIN & (1 << bit_number)) == 0); + + a.tbz(TMP1, imm(bit_number), not_sub_bin); + + a.ldurb(TMP2.w(), + emit_boxed_val(boxed_ptr, + offsetof(ErlSubBin, bitsize))); + a.add(sizeReg, sizeReg, TMP2); + + a.bind(not_sub_bin); + } + } else { + mov_arg(ARG1, seg.src); + a.mov(ARG3, ARG1); + fragment_call(ga->get_bs_bit_size_shared()); + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + a.b_mi(resolve_label(error, disp1MB)); + a.add(sizeReg, sizeReg, ARG1); + } + } else if (seg.unit != 0) { + bool can_fail = true; + comment("size binary/integer/float/string"); + + if (always_small(seg.size)) { + auto min = std::get<0>(getClampedRange(seg.size)); + if (min >= 0) { + can_fail = false; + } + } + + mov_arg(ARG3, seg.size); + + if (can_fail && Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_DEPENDS, + BSC_INFO_SIZE, + BSC_VALUE_ARG3)); + } + + if (always_small(seg.size)) { + comment("skipped test for small size since it is always small"); + } else if (always_one_of(seg.size)) { + comment("simplified test for small size since it is a number"); + emit_is_not_boxed(error, ARG3); + } else { + a.and_(TMP2, ARG3, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_ne(resolve_label(error, disp1MB)); + } + if (can_fail) { + a.tbnz(ARG3, 63, resolve_label(error, disp32K)); + } + if (seg.unit == 1) { + a.add(sizeReg, sizeReg, ARG3, arm::asr(_TAG_IMMED1_SIZE)); + } else { + a.asr(TMP1, ARG3, imm(_TAG_IMMED1_SIZE)); + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_SYSTEM_LIMIT, + BSC_INFO_SIZE, + BSC_VALUE_ARG3)); + } + a.tst(TMP1, imm(0xffful << (SMALL_BITS - ERL_UNIT_BITS))); + a.b_ne(resolve_label(error, disp1MB)); + mov_imm(TMP2, seg.unit); + a.madd(sizeReg, TMP1, TMP2, sizeReg); + } + } else { + switch (seg.type) { + case am_utf8: { + comment("size utf8"); + Label next = a.newLabel(); + + mov_arg(ARG3, seg.src); + + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + + if (always_small(seg.src)) { + comment("skipped test for small value since it is always " + "small"); + } else if (always_one_of(seg.src)) { + comment("simplified test for small operand since other " + "types are boxed"); + emit_is_not_boxed(resolve_label(error, dispUnknown), ARG3); + } else { + a.and_(TMP1, ARG3, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(resolve_label(error, disp1MB)); + } + + a.asr(TMP1, ARG3, imm(_TAG_IMMED1_SIZE)); + mov_imm(TMP2, 1); + a.cmp(TMP1, imm(0x7F)); + a.b_ls(next); + + mov_imm(TMP2, 2); + a.cmp(TMP1, imm(0x7FFUL)); + a.b_ls(next); + + /* Ensure that the value is not in the invalid range + * 0xD800 through 0xDFFF. */ + a.lsr(TMP3, TMP1, imm(11)); + a.cmp(TMP3, 0x1b); + a.b_eq(resolve_label(error, disp1MB)); + + a.cmp(TMP1, imm(0x10000UL)); + a.cset(TMP2, arm::CondCode::kHS); + a.add(TMP2, TMP2, imm(3)); + + auto [min, max] = getClampedRange(seg.src); + if (0 <= min && max < 0x110000) { + comment("skipped range check for unicode code point"); + } else { + a.cmp(TMP1, 0x110000); + a.b_hs(resolve_label(error, disp1MB)); + } + + a.bind(next); + a.add(sizeReg, sizeReg, TMP2, arm::lsl(3)); + break; + } + case am_utf16: { + /* erts_bs_put_utf16 errors out whenever something's + * fishy, so we can return garbage (16 or 32) if our + * input is not a small. */ + comment("size utf16"); + auto src_reg = load_source(seg.src, TMP1); + + a.asr(TMP1, src_reg.reg, imm(_TAG_IMMED1_SIZE)); + a.cmp(TMP1, imm(0x10000UL)); + mov_imm(TMP1, 2 * 8); + mov_imm(TMP2, 4 * 8); + a.csel(TMP1, TMP1, TMP2, arm::CondCode::kLO); + a.add(sizeReg, sizeReg, TMP1); + break; + } + case am_utf32: { + Label next = a.newLabel(); + + comment("size utf32"); + mov_arg(ARG3, seg.src); + + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + + a.add(sizeReg, sizeReg, imm(4 * 8)); + + a.and_(TMP2, ARG3, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_ne(error); + + mov_imm(TMP2, make_small(0xD800UL)); + a.cmp(ARG3, TMP2); + a.b_lo(next); + + mov_imm(TMP2, make_small(0xDFFFUL)); + a.cmp(ARG3, TMP2); + a.b_ls(error); + + mov_imm(TMP2, make_small(0x10FFFFUL)); + a.cmp(ARG3, TMP2); + a.b_hi(error); + + a.bind(next); + break; + } + default: + ASSERT(0); + break; + } + } + } + + /* Allocate the binary. */ + if (segments[0].type == am_append) { + BscSegment seg = segments[0]; + comment("append to binary"); + mov_arg(ARG3, Live); + if (sizeReg.isValid()) { + a.mov(ARG4, sizeReg); + } else { + mov_imm(ARG4, num_bits); + } + mov_arg(ARG5, Alloc); + mov_imm(ARG6, seg.unit); + mov_arg(ArgXRegister(Live.get()), seg.src); + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + + emit_enter_runtime(Live.get() + 1); + runtime_call<6>(erts_bs_append_checked); + emit_leave_runtime(Live.get() + 1); + + if (exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit) { + /* There is no way the call can fail with a system_limit + * exception on a 64-bit architecture. */ + comment("skipped test for success because units are compatible"); + } else { + if (Fail.get() == 0) { + mov_arg(ARG3, ArgXRegister(Live.get())); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_FVALUE, + BSC_VALUE_ARG3)); + } + emit_branch_if_not_value(ARG1, resolve_label(error, dispUnknown)); + } + } else if (segments[0].type == am_private_append) { + BscSegment seg = segments[0]; + comment("private append to binary"); + ASSERT(Alloc.get() == 0); + mov_arg(ARG2, seg.src); + if (sizeReg.isValid()) { + a.mov(ARG3, sizeReg); + } else { + mov_imm(ARG3, num_bits); + } + a.mov(ARG4, seg.unit); + a.mov(ARG1, c_p); + emit_enter_runtime(Live.get()); + runtime_call<4>(erts_bs_private_append_checked); + emit_leave_runtime(Live.get()); + /* There is no way the call can fail on a 64-bit architecture. */ + } else if (estimated_num_bits % 8 == 0 && + estimated_num_bits / 8 <= ERL_ONHEAP_BIN_LIMIT) { + static constexpr auto cur_bin_offset = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state) + + offsetof(struct erl_bits_state, erts_current_bin_); + Uint need; + + arm::Mem mem_bin_base = arm::Mem(scheduler_registers, cur_bin_offset); + + if (sizeReg.isValid()) { + Label after_gc_check = a.newLabel(); + + comment("allocate heap binary of dynamic size (=< %ld bits)", + estimated_num_bits); + + /* Calculate number of bytes to allocate. */ + need = (heap_bin_size(0) + Alloc.get() + S_RESERVED); + a.lsr(sizeReg, sizeReg, imm(3)); + a.add(TMP3, sizeReg, imm(7)); + a.and_(TMP3, TMP3, imm(-8)); + a.add(TMP1, TMP3, imm(need * sizeof(Eterm))); + + /* Do a GC test. */ + a.add(ARG3, HTOP, TMP1); + a.cmp(ARG3, E); + a.b_ls(after_gc_check); + + a.stp(sizeReg, TMP3, TMP_MEM1q); + + mov_imm(ARG4, Live.get()); + fragment_call(ga->get_garbage_collect()); + + a.ldp(sizeReg, TMP3, TMP_MEM1q); + + a.bind(after_gc_check); + + mov_imm(TMP1, header_heap_bin(0)); + a.lsr(TMP4, TMP3, imm(3)); + a.add(TMP1, TMP1, TMP4, arm::lsl(_HEADER_ARITY_OFFS)); + + /* Create the heap binary. */ + a.add(ARG1, HTOP, imm(TAG_PRIMARY_BOXED)); + a.stp(TMP1, sizeReg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + + /* Initialize the erl_bin_state struct. */ + a.stp(HTOP, ZERO, mem_bin_base); + + /* Update HTOP. */ + a.add(HTOP, HTOP, TMP3); + } else { + Uint num_bytes = num_bits / 8; + + comment("allocate heap binary of static size"); + + allocated_size = (num_bytes + 7) & (-8); + + /* Ensure that there is sufficient room on the heap. */ + need = heap_bin_size(num_bytes) + Alloc.get(); + emit_gc_test(ArgWord(0), ArgWord(need), Live); + + mov_imm(TMP1, header_heap_bin(num_bytes)); + mov_imm(TMP2, num_bytes); + + /* Create the heap binary. */ + a.add(ARG1, HTOP, imm(TAG_PRIMARY_BOXED)); + a.stp(TMP1, TMP2, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + + /* Initialize the erl_bin_state struct. */ + ERTS_CT_ASSERT_FIELD_PAIR(struct erl_bits_state, + erts_current_bin_, + erts_bin_offset_); + a.stp(HTOP, ZERO, mem_bin_base); + + /* Update HTOP. */ + a.add(HTOP, HTOP, imm(allocated_size)); + } + } else { + comment("allocate binary"); + mov_arg(ARG5, Alloc); + mov_arg(ARG6, Live); + load_erl_bits_state(ARG3); + load_x_reg_array(ARG2); + a.mov(ARG1, c_p); + emit_enter_runtime(Live.get()); + if (sizeReg.isValid()) { + comment("(size in bits)"); + a.mov(ARG4, sizeReg); + runtime_call<6>(beam_jit_bs_init_bits); + } else { + allocated_size = (num_bits + 7) / 8; + if (allocated_size <= ERL_ONHEAP_BIN_LIMIT) { + allocated_size = (allocated_size + 7) & (-8); + } + mov_imm(ARG4, num_bits); + runtime_call<6>(beam_jit_bs_init_bits); + } + emit_leave_runtime(Live.get()); + } + a.str(ARG1, TMP_MEM1q); + + segments = bs_combine_segments(segments); + + /* Keep track of the bit offset from the being of the binary. + * Set to -1 if offset is not known (when a segment of unknown + * size has been seen). */ + Sint bit_offset = 0; + + /* Keep track of whether the current segment is byte-aligned. (A + * segment can be known to be byte-aligned even if the bit offset + * is unknown.) */ + bool is_byte_aligned = true; + + /* Build each segment of the binary. */ + for (auto seg : segments) { + switch (seg.type) { + case am_append: + case am_private_append: + bit_offset = -1; + break; + case am_binary: { + Uint error_info; + bool can_fail = true; + + comment("construct a binary segment"); + if (seg.effectiveSize >= 0) { + /* The segment has a literal size. */ + mov_imm(ARG3, seg.effectiveSize); + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + emit_enter_runtime(Live.get()); + runtime_call<3>(erts_new_bs_put_binary); + emit_leave_runtime(Live.get()); + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); + } else if (seg.size.isAtom() && + seg.size.as().get() == am_all) { + /* Include the entire binary/bitstring in the + * resulting binary. */ + a.mov(ARG3, seg.unit); + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + + emit_enter_runtime(Live.get()); + runtime_call<3>(erts_new_bs_put_binary_all); + emit_leave_runtime(Live.get()); + + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_UNIT, + BSC_VALUE_FVALUE); + if (exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit) { + comment("skipped test for success because units are " + "compatible"); + can_fail = false; + } + } else { + /* The size is a variable. We have verified that + * the value is a non-negative small in the + * appropriate range. Multiply the size with the + * unit. */ + auto r = load_source(seg.size, ARG3); + a.asr(ARG3, r.reg, imm(_TAG_IMMED1_SIZE)); + if (seg.unit != 1) { + mov_imm(TMP1, seg.unit); + a.mul(ARG3, ARG3, TMP1); + } + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + + emit_enter_runtime(Live.get()); + runtime_call<3>(erts_new_bs_put_binary); + emit_leave_runtime(Live.get()); + + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); + } + + if (can_fail) { + if (Fail.get() == 0) { + mov_imm(ARG4, error_info); + } + a.cbz(ARG1, resolve_label(error, disp1MB)); + } + break; + } + case am_float: + comment("construct float segment"); + if (seg.effectiveSize >= 0) { + mov_imm(ARG3, seg.effectiveSize); + } else { + auto r = load_source(seg.size, ARG3); + a.asr(ARG3, r.reg, imm(_TAG_IMMED1_SIZE)); + if (seg.unit != 1) { + mov_imm(TMP1, seg.unit); + a.mul(ARG3, ARG3, TMP1); + } + } + mov_arg(ARG2, seg.src); + mov_imm(ARG4, seg.flags); + a.mov(ARG1, c_p); + + emit_enter_runtime(Live.get()); + runtime_call<4>(erts_new_bs_put_float); + emit_leave_runtime(Live.get()); + + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_FVALUE, + BSC_VALUE_ARG1)); + } + emit_branch_if_value(ARG1, resolve_label(error, dispUnknown)); + break; + case am_integer: + switch (seg.action) { + case BscSegment::action::ACCUMULATE_FIRST: + case BscSegment::action::ACCUMULATE: { + /* Shift an integer of known size (no more than 64 bits) + * into a word-size accumulator. */ + Label value_is_small = a.newLabel(); + Label done = a.newLabel(); + + comment("accumulate value for integer segment"); + auto src = load_source(seg.src, ARG1); + if (seg.effectiveSize < 64 && + seg.action == BscSegment::action::ACCUMULATE) { + a.lsl(ARG8, ARG8, imm(seg.effectiveSize)); + } + + if (!always_small(seg.src)) { + if (always_one_of(seg.src)) { + comment("simplified small test since all other types " + "are boxed"); + emit_is_boxed(value_is_small, seg.src, src.reg); + } else { + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_eq(value_is_small); + } + + /* The value is boxed. If it is a bignum, extract the + * least significant 64 bits. */ + mov_var(ARG1, src); + fragment_call(ga->get_get_sint64_shared()); + if (seg.effectiveSize == 64) { + a.mov(ARG8, ARG1); + } else { + a.bfxil(ARG8, + ARG1, + arm::lsr(0), + imm(seg.effectiveSize)); + } + + if (exact_type(seg.src)) { + a.b(done); + } else { + a.b_ne(done); + + /* Not a bignum. Signal error. */ + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.b(resolve_label(error, disp128MB)); + } + } + + a.bind(value_is_small); + if (seg.effectiveSize == 64) { + a.asr(ARG8, src.reg, imm(_TAG_IMMED1_SIZE)); + } else if (seg.effectiveSize + _TAG_IMMED1_SIZE > 64) { + a.asr(TMP1, src.reg, imm(_TAG_IMMED1_SIZE)); + a.bfxil(ARG8, TMP1, arm::lsr(0), imm(seg.effectiveSize)); + } else { + a.bfxil(ARG8, + src.reg, + arm::lsr(_TAG_IMMED1_SIZE), + imm(seg.effectiveSize)); + } + + a.bind(done); + break; + } + case BscSegment::action::STORE: { + /* The accumulator is now full or the next segment is + * not possible to accumulate, so it's time to store + * the accumulator to the current position in the + * binary. */ + Label store = a.newLabel(); + Label done = a.newLabel(); + + comment("construct integer segment from accumulator"); + + /* First we'll need to ensure that the value in the + * accumulator is in little endian format. */ + ASSERT(seg.effectiveSize >= 0); + if (seg.effectiveSize % 8) { + Uint complete_bytes = 8 * (seg.effectiveSize / 8); + Uint num_partial = seg.effectiveSize % 8; + if (seg.flags & BSF_LITTLE) { + a.ubfx(TMP1, + ARG8, + imm(complete_bytes), + imm(num_partial)); + a.bfc(ARG8, + arm::lsr(complete_bytes), + imm(64 - complete_bytes)); + a.bfi(ARG8, + TMP1, + imm(complete_bytes + 8 - num_partial), + imm(num_partial)); + } else { + a.lsl(ARG8, ARG8, imm(64 - seg.effectiveSize)); + a.rev64(ARG8, ARG8); + } + } else if ((seg.flags & BSF_LITTLE) == 0) { + switch (seg.effectiveSize) { + case 8: + break; + case 16: + a.rev16(ARG8, ARG8); + break; + case 32: + a.rev32(ARG8, ARG8); + break; + case 64: + a.rev64(ARG8, ARG8); + break; + default: + a.rev64(ARG8, ARG8); + a.lsr(ARG8, ARG8, imm(64 - seg.effectiveSize)); + } + } + + arm::Gp bin_offset = ARG3; + arm::Gp bin_data = ARG8; + + update_bin_state(bin_offset, + bit_offset, + seg.effectiveSize, + arm::Gp()); + + if (!is_byte_aligned) { + if (bit_offset < 0) { + /* Bit offset is unknown. Must test alignment. */ + a.ands(bin_offset, bin_offset, imm(7)); + a.b_eq(store); + } else if (bit_offset >= 0) { + /* Alignment is known to be unaligned. */ + mov_imm(bin_offset, bit_offset & 7); + } + + /* Bit offset is tested or known to be unaligned. */ + mov_imm(ARG4, seg.effectiveSize); + fragment_call(ga->get_store_unaligned()); + + if (bit_offset < 0) { + /* The bit offset is unknown, which implies that + * there exists store code that we will need to + * branch past. */ + a.b(done); + } + } + + a.bind(store); + + if (bit_offset < 0 || is_byte_aligned) { + /* Bit offset is tested or known to be + * byte-aligned. Emit inline code to store the + * value of the accumulator into the binary. */ + int num_bytes = (seg.effectiveSize + 7) / 8; + + /* If more than one instruction is required for + * doing the store, test whether it would be safe + * to do a single 32 or 64 bit store. */ + switch (num_bytes) { + case 3: + if (bit_offset >= 0 && + allocated_size * 8 - bit_offset >= 32) { + comment("simplified complicated store"); + num_bytes = 4; + } + break; + case 5: + case 6: + case 7: + if (bit_offset >= 0 && + allocated_size * 8 - bit_offset >= 64) { + comment("simplified complicated store"); + num_bytes = 8; + } + break; + } + + do { + switch (num_bytes) { + case 1: + a.strb(bin_data.w(), arm::Mem(TMP1)); + break; + case 2: + a.strh(bin_data.w(), arm::Mem(TMP1)); + break; + case 3: + a.strh(bin_data.w(), arm::Mem(TMP1)); + a.lsr(bin_data, bin_data, imm(16)); + a.strb(bin_data.w(), arm::Mem(TMP1, 2)); + break; + case 4: + a.str(bin_data.w(), arm::Mem(TMP1)); + break; + case 5: + case 6: + case 7: + a.str(bin_data.w(), arm::Mem(TMP1).post(4)); + a.lsr(bin_data, bin_data, imm(32)); + break; + case 8: + a.str(bin_data, arm::Mem(TMP1)); + num_bytes = 0; + break; + } + num_bytes -= 4; + } while (num_bytes > 0); + } + + a.bind(done); + break; + } + case BscSegment::action::DIRECT: + /* This segment either has a size exceeding the maximum + * accumulator size of 64 bits or has a variable size. + * + * First load the effective size (size * unit) into ARG3. + */ + comment("construct integer segment"); + if (seg.effectiveSize >= 0) { + mov_imm(ARG3, seg.effectiveSize); + } else { + auto size = load_source(seg.size, TMP1); + a.lsr(ARG3, size.reg, imm(_TAG_IMMED1_SIZE)); + if (Support::isPowerOf2(seg.unit)) { + Uint trailing_bits = Support::ctz(seg.unit); + if (trailing_bits) { + a.lsl(ARG3, ARG3, imm(trailing_bits)); + } + } else { + mov_imm(TMP1, seg.unit); + a.mul(ARG3, ARG3, TMP1); + } + } + + if (is_byte_aligned && seg.src.isSmall() && + seg.src.as().getSigned() == 0) { + /* Optimize the special case of setting a known + * byte-aligned segment to zero. */ + comment("optimized setting segment to 0"); + set_zero(seg.effectiveSize); + } else { + /* Call the helper function to fetch and store the + * integer into the binary. */ + mov_arg(ARG2, seg.src); + mov_imm(ARG4, seg.flags); + load_erl_bits_state(ARG1); + + emit_enter_runtime(Live.get()); + runtime_call<4>(erts_new_bs_put_integer); + emit_leave_runtime(Live.get()); + + if (exact_type(seg.src)) { + comment("skipped test for success because construction " + "can't fail"); + } else { + if (Fail.get() == 0) { + mov_arg(ARG3, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + a.cbz(ARG1, resolve_label(error, disp1MB)); + } + } + } + break; + case am_string: { + ArgBytePtr string_ptr( + ArgVal(ArgVal::BytePtr, seg.src.as().get())); + + comment("insert string"); + ASSERT(seg.effectiveSize >= 0); + mov_imm(ARG3, seg.effectiveSize / 8); + mov_arg(ARG2, string_ptr); + load_erl_bits_state(ARG1); + + emit_enter_runtime(Live.get()); + runtime_call<3>(erts_new_bs_put_string); + emit_leave_runtime(Live.get()); + break; + } + case am_utf8: { + emit_construct_utf8(seg.src, bit_offset, is_byte_aligned); + break; + } + case am_utf16: + comment("construct utf16 segment"); + mov_arg(ARG2, seg.src); + a.mov(ARG3, seg.flags); + load_erl_bits_state(ARG1); + + emit_enter_runtime(Live.get()); + runtime_call<3>(erts_bs_put_utf16); + emit_leave_runtime(Live.get()); + + if (Fail.get() == 0) { + mov_arg(ARG3, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + a.cbz(ARG1, resolve_label(error, disp1MB)); + break; + case am_utf32: + mov_arg(ARG2, seg.src); + mov_imm(ARG3, 4 * 8); + a.mov(ARG4, seg.flags); + load_erl_bits_state(ARG1); + + emit_enter_runtime(Live.get()); + runtime_call<4>(erts_new_bs_put_integer); + emit_leave_runtime(Live.get()); + + if (Fail.get() == 0) { + mov_arg(ARG3, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG3)); + } + a.cbz(ARG1, resolve_label(error, disp1MB)); + break; + default: + ASSERT(0); + break; + } + + /* Try to keep track of the bit offset. */ + if (bit_offset >= 0 && (seg.action == BscSegment::action::DIRECT || + seg.action == BscSegment::action::STORE)) { + if (seg.effectiveSize >= 0) { + bit_offset += seg.effectiveSize; + } else { + bit_offset = -1; + } + } + + /* Try to keep track whether the next segment is byte + * aligned. */ + if (seg.type == am_append || seg.type == am_private_append) { + if (!exact_type(seg.src) || + std::gcd(getSizeUnit(seg.src), 8) != 8) { + is_byte_aligned = false; + } + } else if (bit_offset % 8 == 0) { + is_byte_aligned = true; + } else if (seg.effectiveSize >= 0) { + if (seg.effectiveSize % 8 != 0) { + is_byte_aligned = false; + } + } else if (std::gcd(seg.unit, 8) != 8) { + is_byte_aligned = false; + } + } + + comment("done"); + mov_arg(Dst, TMP_MEM1q); +} + +/* + * Here follows the bs_match instruction and friends. + */ + +struct BsmSegment { + BsmSegment() + : action(action::TEST_HEAP), live(ArgNil()), size(0), unit(1), + flags(0), dst(ArgXRegister(0)){}; + + enum class action { + TEST_HEAP, + ENSURE_AT_LEAST, + ENSURE_EXACTLY, + READ, + EXTRACT_BINARY, + EXTRACT_INTEGER, + GET_INTEGER, + GET_BINARY, + SKIP, + DROP, + GET_TAIL, + EQ + } action; + ArgVal live; + Uint size; + Uint unit; + Uint flags; + ArgRegister dst; +}; + +void BeamModuleAssembler::emit_read_bits(Uint bits, + const arm::Gp bin_base, + const arm::Gp bin_offset, + const arm::Gp bitdata) { + Label handle_partial = a.newLabel(); + Label rev64 = a.newLabel(); + Label shift = a.newLabel(); + Label read_done = a.newLabel(); + + bool need_rev64 = false; + + const arm::Gp bin_byte_ptr = TMP2; + const arm::Gp bit_offset = TMP4; + const arm::Gp tmp = TMP5; + + auto num_partial = bits % 8; + + ASSERT(1 <= bits && bits <= 64); + + a.add(bin_byte_ptr, bin_base, bin_offset, arm::lsr(3)); + + if (bits <= 8) { + a.ands(bit_offset, bin_offset, imm(7)); + + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, + * this segment always spans two bytes. */ + a.b_ne(handle_partial); + } else if (num_partial > 1) { + /* The segment is smaller than one byte but more than one + * bit. Test whether it fits within the current byte. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_gt(handle_partial); + } + + /* The segment fits in the current byte. */ + a.ldrb(bitdata.w(), arm::Mem(bin_byte_ptr)); + if (num_partial == 0) { + a.rev64(bitdata, bitdata); + a.b(read_done); + } else if (num_partial > 1) { + a.b(rev64); + } + + /* The segment is unaligned and spans two bytes. */ + a.bind(handle_partial); + if (num_partial != 1) { + a.ldrh(bitdata.w(), arm::Mem(bin_byte_ptr)); + } + need_rev64 = true; + } else if (bits <= 16) { + a.ands(bit_offset, bin_offset, imm(7)); + + /* We always need to read at least two bytes. */ + a.ldrh(bitdata.w(), arm::Mem(bin_byte_ptr)); + a.rev64(bitdata, bitdata); + a.b_eq(read_done); /* Done if segment is byte-aligned. */ + + /* The segment is unaligned. If its size is 9, it always fits + * in two bytes and we fall through to the shift instruction. */ + a.bind(handle_partial); + if (num_partial > 1) { + /* If segment size is less than 15 bits or less, it is + * possible that it fits into two bytes. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_le(shift); + } + + if (num_partial != 1) { + /* The segment spans three bytes. Read an additional byte and + * shift into place (right below the already read two bytes a + * the top of the word). */ + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 2)); + a.orr(bitdata, bitdata, tmp, arm::lsl(40)); + } + } else if (bits <= 24) { + a.ands(bit_offset, bin_offset, imm(7)); + + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, + * this segment always spans four bytes. */ + a.b_ne(handle_partial); + } else if (num_partial > 1) { + /* The segment is smaller than three bytes. Test whether + * it spans three or four bytes. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_gt(handle_partial); + } + + /* This segment spans three bytes. */ + a.ldrh(bitdata.w(), arm::Mem(bin_byte_ptr)); + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 2)); + a.orr(bitdata, bitdata, tmp, arm::lsl(16)); + if (num_partial == 0) { + a.rev64(bitdata, bitdata); + a.b(read_done); + } else if (num_partial > 1) { + a.b(rev64); + } + + /* This segment spans four bytes. */ + a.bind(handle_partial); + if (num_partial != 1) { + a.ldr(bitdata.w(), arm::Mem(bin_byte_ptr)); + } + need_rev64 = true; + } else if (bits <= 32) { + a.ands(bit_offset, bin_offset, imm(7)); + + /* We always need to read at least four bytes. */ + a.ldr(bitdata.w(), arm::Mem(bin_byte_ptr)); + a.rev64(bitdata, bitdata); + a.b_eq(read_done); + + a.bind(handle_partial); + if (num_partial > 0) { + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_le(shift); + } + + if (num_partial != 1) { + /* The segment spans five bytes. Read an additional byte and + * shift into place. */ + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 4)); + a.orr(bitdata, bitdata, tmp, arm::lsl(24)); + } + } else if (bits <= 40) { + a.ands(bit_offset, bin_offset, imm(7)); + + /* We always need to read four bytes. */ + a.ldr(bitdata.w(), arm::Mem(bin_byte_ptr)); + a.rev64(bitdata, bitdata); + + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, + * this segment always spans six bytes. */ + a.b_ne(handle_partial); + } else if (num_partial > 1) { + /* The segment is smaller than five bytes. Test whether it + * spans five or six bytes. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_gt(handle_partial); + } + + /* This segment spans five bytes. Read an additional byte. */ + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 4)); + a.orr(bitdata, bitdata, tmp, arm::lsl(24)); + if (num_partial == 0) { + a.b(read_done); + } else if (num_partial > 1) { + a.b(shift); + } + + a.bind(handle_partial); + if (num_partial != 1) { + /* This segment spans six bytes. Read two additional bytes. */ + a.ldrh(tmp.w(), arm::Mem(bin_byte_ptr, 4)); + a.rev16(tmp.w(), tmp.w()); + a.orr(bitdata, bitdata, tmp, arm::lsl(16)); + } + } else if (bits <= 48) { + a.ands(bit_offset, bin_offset, imm(7)); + a.ldr(bitdata.w(), arm::Mem(bin_byte_ptr)); + a.ldrh(tmp.w(), arm::Mem(bin_byte_ptr, 4)); + a.orr(bitdata, bitdata, tmp, arm::lsl(32)); + a.rev64(bitdata, bitdata); + a.b_eq(read_done); + + a.bind(handle_partial); + if (num_partial > 1) { + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_le(shift); + } + + if (num_partial != 1) { + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 6)); + a.orr(bitdata, bitdata, tmp, arm::lsl(8)); + } + } else if (bits <= 56) { + a.ands(bit_offset, bin_offset, imm(7)); + + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, + * this segment always spans 8 bytes. */ + a.b_ne(handle_partial); + } else if (num_partial > 1) { + /* The segment is smaller than 8 bytes. Test whether it + * spans 7 or 8 bytes. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_gt(handle_partial); + } + + /* This segment spans 7 bytes. */ + a.ldr(bitdata, arm::Mem(bin_byte_ptr, -1)); + a.lsr(bitdata, bitdata, imm(8)); + a.b(rev64); + + /* This segment spans 8 bytes. */ + a.bind(handle_partial); + if (num_partial != 1) { + a.ldr(bitdata, arm::Mem(bin_byte_ptr)); + } + need_rev64 = true; + } else if (bits <= 64) { + a.ands(bit_offset, bin_offset, imm(7)); + a.ldr(bitdata, arm::Mem(bin_byte_ptr)); + a.rev64(bitdata, bitdata); + + if (num_partial == 0) { + /* Byte-sized segment. If it is aligned it spans 8 bytes + * and we are done. */ + a.b_eq(read_done); + } else if (num_partial == 1) { + /* This segment is 57 bits wide. It always spans 8 bytes. */ + a.b(shift); + } else { + /* The segment is smaller than 8 bytes. Test whether it + * spans 8 or 9 bytes. */ + a.cmp(bit_offset, imm(8 - num_partial)); + a.b_le(shift); + } + + /* This segments spans 9 bytes. Read an additional byte. */ + a.bind(handle_partial); + if (num_partial != 1) { + a.ldrb(tmp.w(), arm::Mem(bin_byte_ptr, 8)); + a.lsl(bitdata, bitdata, bit_offset); + a.lsl(tmp, tmp, bit_offset); + a.orr(bitdata, bitdata, tmp, arm::lsr(8)); + a.b(read_done); + } + } + + a.bind(rev64); + if (need_rev64) { + a.rev64(bitdata, bitdata); + } + + /* Shift the read data into the most significant bits of the + * word. */ + a.bind(shift); + a.lsl(bitdata, bitdata, bit_offset); + + a.bind(read_done); +} + +void BeamModuleAssembler::emit_extract_integer(const arm::Gp bitdata, + Uint flags, + Uint bits, + const ArgRegister &Dst) { + Label big = a.newLabel(); + Label done = a.newLabel(); + arm::Gp data_reg; + auto dst = init_destination(Dst, TMP1); + Uint num_partial = bits % 8; + Uint num_complete = 8 * (bits / 8); + + if (bits <= 8) { + /* Endian does not matter for values that fit in a byte. */ + flags &= ~BSF_LITTLE; + } + + /* If this segment is little-endian, reverse endianness. */ + if ((flags & BSF_LITTLE) != 0) { + comment("reverse endian for a little-endian segment"); + } + data_reg = TMP2; + if ((flags & BSF_LITTLE) == 0) { + data_reg = bitdata; + } else if (bits == 16) { + a.rev16(TMP2, bitdata); + } else if (bits == 32) { + a.rev32(TMP2, bitdata); + } else if (num_partial == 0) { + a.rev64(TMP2, bitdata); + a.lsr(TMP2, TMP2, arm::lsr(64 - bits)); + } else { + a.ubfiz(TMP3, bitdata, imm(num_complete), imm(num_partial)); + a.ubfx(TMP2, bitdata, imm(num_partial), imm(num_complete)); + a.rev64(TMP2, TMP2); + a.orr(TMP2, TMP3, TMP2, arm::lsr(64 - num_complete)); + } + + /* Sign-extend the number if the segment is signed. */ + if ((flags & BSF_SIGNED) != 0) { + if (0 < bits && bits < 64) { + comment("sign extend extracted value"); + a.lsl(TMP2, data_reg, imm(64 - bits)); + a.asr(TMP2, TMP2, imm(64 - bits)); + data_reg = TMP2; + } + } + + /* Handle segments whose values might not fit in a small integer. */ + if (bits >= SMALL_BITS) { + comment("test whether it fits in a small"); + if (bits < 64 && (flags & BSF_SIGNED) == 0) { + a.and_(TMP2, data_reg, imm((1ull << bits) - 1)); + data_reg = TMP2; + } + if ((flags & BSF_SIGNED) != 0) { + /* Signed segment. */ + a.adds(TMP3, ZERO, data_reg, arm::lsr(SMALL_BITS - 1)); + a.ccmp(TMP3, + imm(_TAG_IMMED1_MASK << 1 | 1), + imm(NZCV::kEqual), + imm(arm::CondCode::kNE)); + a.b_ne(big); + } else { + /* Unsigned segment. */ + a.lsr(TMP3, data_reg, imm(SMALL_BITS - 1)); + a.cbnz(TMP3, big); + } + } + + /* Tag and store the extracted small integer. */ + comment("store extracted integer as a small"); + mov_imm(dst.reg, _TAG_IMMED1_SMALL); + if ((flags & BSF_SIGNED) != 0) { + a.orr(dst.reg, dst.reg, data_reg, arm::lsl(_TAG_IMMED1_SIZE)); + } else { + if (bits >= SMALL_BITS) { + a.bfi(dst.reg, + data_reg, + arm::lsl(_TAG_IMMED1_SIZE), + imm(SMALL_BITS)); + } else if (bits != 0) { + a.bfi(dst.reg, data_reg, arm::lsl(_TAG_IMMED1_SIZE), imm(bits)); + } + } + + if (bits >= SMALL_BITS) { + a.b(done); + } + + /* Handle a bignum (up to 64 bits). */ + a.bind(big); + if (bits >= SMALL_BITS) { + comment("store extracted integer as a bignum"); + a.add(dst.reg, HTOP, imm(TAG_PRIMARY_BOXED)); + mov_imm(TMP3, make_pos_bignum_header(1)); + if ((flags & BSF_SIGNED) == 0) { + /* Unsigned. */ + a.stp(TMP3, data_reg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } else { + /* Signed. */ + Label store = a.newLabel(); + a.adds(TMP2, data_reg, ZERO); + a.b_pl(store); + + mov_imm(TMP3, make_neg_bignum_header(1)); + a.neg(TMP2, TMP2); + + a.bind(store); + a.stp(TMP3, TMP2, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } + } + + a.bind(done); + flush_var(dst); +} + +void BeamModuleAssembler::emit_extract_binary(const arm::Gp bitdata, + Uint bits, + const ArgRegister &Dst) { + auto dst = init_destination(Dst, TMP1); + Uint num_bytes = bits / 8; + + a.add(dst.reg, HTOP, imm(TAG_PRIMARY_BOXED)); + mov_imm(TMP2, header_heap_bin(num_bytes)); + mov_imm(TMP3, num_bytes); + a.rev64(TMP4, bitdata); + a.stp(TMP2, TMP3, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + if (num_bytes != 0) { + a.str(TMP4, arm::Mem(HTOP).post(sizeof(Eterm[1]))); + } + flush_var(dst); +} + +static std::vector opt_bsm_segments( + const std::vector segments, + const ArgWord &Need, + const ArgWord &Live) { + std::vector segs; + + Uint heap_need = Need.get(); + + /* + * First calculate the total number of heap words needed for + * bignums and binaries. + */ + for (auto seg : segments) { + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + if (seg.size >= SMALL_BITS) { + heap_need += BIG_NEED_FOR_BITS(seg.size); + } + break; + case BsmSegment::action::GET_BINARY: + heap_need += erts_extracted_binary_size(seg.size); + break; + case BsmSegment::action::GET_TAIL: + heap_need += EXTRACT_SUB_BIN_HEAP_NEED; + break; + default: + break; + } + } + + int index = 0; + int read_action_pos = -1; + + index = 0; + for (auto seg : segments) { + if (heap_need != 0 && seg.live.isWord()) { + BsmSegment s = seg; + + read_action_pos = -1; + s.action = BsmSegment::action::TEST_HEAP; + s.size = heap_need; + segs.push_back(s); + index++; + heap_need = 0; + } + + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + case BsmSegment::action::GET_BINARY: + if (seg.size > 64) { + read_action_pos = -1; + } else if (seg.action == BsmSegment::action::GET_BINARY && + seg.size % 8 != 0) { + read_action_pos = -1; + } else { + if ((seg.flags & BSF_LITTLE) != 0 || read_action_pos < 0 || + seg.size + segs.at(read_action_pos).size > 64) { + BsmSegment s; + + /* Create a new READ action. */ + read_action_pos = index; + s.action = BsmSegment::action::READ; + s.size = seg.size; + segs.push_back(s); + index++; + } else { + /* Reuse previous READ action. */ + segs.at(read_action_pos).size += seg.size; + } + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + seg.action = BsmSegment::action::EXTRACT_INTEGER; + break; + case BsmSegment::action::GET_BINARY: + seg.action = BsmSegment::action::EXTRACT_BINARY; + break; + default: + break; + } + } + segs.push_back(seg); + break; + case BsmSegment::action::EQ: { + if (read_action_pos < 0 || + seg.size + segs.at(read_action_pos).size > 64) { + BsmSegment s; + + /* Create a new READ action. */ + read_action_pos = index; + s.action = BsmSegment::action::READ; + s.size = seg.size; + segs.push_back(s); + index++; + } else { + /* Reuse previous READ action. */ + segs.at(read_action_pos).size += seg.size; + } + auto &prev = segs.back(); + if (prev.action == BsmSegment::action::EQ && + prev.size + seg.size <= 64) { + /* Coalesce with the previous EQ instruction. */ + prev.size += seg.size; + prev.unit = prev.unit << seg.size | seg.unit; + index--; + } else { + segs.push_back(seg); + } + break; + } + case BsmSegment::action::SKIP: + if (read_action_pos >= 0 && + seg.size + segs.at(read_action_pos).size <= 64) { + segs.at(read_action_pos).size += seg.size; + seg.action = BsmSegment::action::DROP; + } else { + read_action_pos = -1; + } + segs.push_back(seg); + break; + default: + read_action_pos = -1; + segs.push_back(seg); + break; + } + index++; + } + + /* Handle a trailing test_heap instruction (for the + * i_bs_match_test_heap instruction). */ + if (heap_need) { + BsmSegment seg; + + seg.action = BsmSegment::action::TEST_HEAP; + seg.size = heap_need; + seg.live = Live; + segs.push_back(seg); + } + return segs; +} + +UWord BeamModuleAssembler::bs_get_flags(const ArgVal &val) { + if (val.isNil()) { + return 0; + } else if (val.isLiteral()) { + Eterm term = beamfile_get_literal(beam, val.as().get()); + UWord flags = 0; + + while (is_list(term)) { + Eterm *consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + case am_native: + flags |= BSF_LITTLE; + break; + case am_signed: + flags |= BSF_SIGNED; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + return flags; + } else if (val.isWord()) { + /* Originates from bs_get_integer2 instruction. */ + return val.as().get(); + } else { + ASSERT(0); /* Should not happen. */ + return 0; + } +} + +void BeamModuleAssembler::emit_i_bs_match(ArgLabel const &Fail, + ArgRegister const &Ctx, + Span const &List) { + emit_i_bs_match_test_heap(Fail, Ctx, ArgWord(0), ArgWord(0), List); +} + +void BeamModuleAssembler::emit_i_bs_match_test_heap(ArgLabel const &Fail, + ArgRegister const &Ctx, + ArgWord const &Need, + ArgWord const &Live, + Span const &List) { + const int orig_offset = offsetof(ErlBinMatchState, mb.orig); + const int base_offset = offsetof(ErlBinMatchState, mb.base); + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + + std::vector segments; + + auto current = List.begin(); + auto end = List.begin() + List.size(); + + while (current < end) { + auto cmd = current++->as().get(); + BsmSegment seg; + + switch (cmd) { + case am_ensure_at_least: { + seg.action = BsmSegment::action::ENSURE_AT_LEAST; + seg.size = current[0].as().get(); + seg.unit = current[1].as().get(); + current += 2; + break; + } + case am_ensure_exactly: { + seg.action = BsmSegment::action::ENSURE_EXACTLY; + seg.size = current[0].as().get(); + current += 1; + break; + } + case am_binary: + case am_integer: { + auto size = current[2].as().get(); + auto unit = current[3].as().get(); + + switch (cmd) { + case am_integer: + seg.action = BsmSegment::action::GET_INTEGER; + break; + case am_binary: + seg.action = BsmSegment::action::GET_BINARY; + break; + } + + seg.live = current[0]; + seg.size = size * unit; + seg.unit = unit; + seg.flags = bs_get_flags(current[1]); + seg.dst = current[4].as(); + current += 5; + break; + } + case am_get_tail: { + seg.action = BsmSegment::action::GET_TAIL; + seg.live = current[0].as(); + seg.dst = current[2].as(); + current += 3; + break; + } + case am_skip: { + seg.action = BsmSegment::action::SKIP; + seg.size = current[0].as().get(); + seg.flags = 0; + current += 1; + break; + } + case am_Eq: { + seg.action = BsmSegment::action::EQ; + seg.live = current[0]; + seg.size = current[1].as().get(); + seg.unit = current[2].as().get(); + current += 3; + break; + } + default: + abort(); + break; + } + segments.push_back(seg); + } + + segments = opt_bsm_segments(segments, Need, Live); + + const arm::Gp bin_base = ARG2; + const arm::Gp bin_position = ARG3; + const arm::Gp bin_size = ARG4; + const arm::Gp bitdata = ARG8; + bool position_is_valid = false; + + for (auto seg : segments) { + switch (seg.action) { + case BsmSegment::action::ENSURE_AT_LEAST: { + comment("ensure_at_least %ld %ld", seg.size, seg.unit); + auto ctx_reg = load_source(Ctx, TMP1); + auto stride = seg.size; + auto unit = seg.unit; + + a.ldur(bin_position, emit_boxed_val(ctx_reg.reg, position_offset)); + a.ldur(bin_size, emit_boxed_val(ctx_reg.reg, size_offset)); + a.sub(TMP5, bin_size, bin_position); + if (stride != 0) { + cmp(TMP5, stride); + a.b_lo(resolve_beam_label(Fail, disp1MB)); + } + + if (unit != 1) { + if (stride % unit != 0) { + sub(TMP5, TMP5, stride); + } + + if ((unit & (unit - 1)) != 0) { + mov_imm(TMP4, unit); + + a.udiv(TMP3, TMP5, TMP4); + a.msub(TMP5, TMP3, TMP4, TMP5); + + a.cbnz(TMP5, resolve_beam_label(Fail, disp1MB)); + } else { + a.tst(TMP5, imm(unit - 1)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + } + + position_is_valid = true; + break; + } + case BsmSegment::action::ENSURE_EXACTLY: { + comment("ensure_exactly %ld", seg.size); + auto ctx_reg = load_source(Ctx, TMP1); + auto size = seg.size; + + a.ldur(bin_position, emit_boxed_val(ctx_reg.reg, position_offset)); + a.ldur(TMP3, emit_boxed_val(ctx_reg.reg, size_offset)); + if (size != 0) { + a.sub(TMP1, TMP3, bin_position); + cmp(TMP1, size); + } else { + a.subs(TMP1, TMP3, bin_position); + } + a.b_ne(resolve_beam_label(Fail, disp1MB)); + position_is_valid = true; + break; + } + case BsmSegment::action::EQ: { + comment("=:= %ld %ld", seg.size, seg.unit); + if (seg.size != 0 && seg.size != 64) { + a.ror(bitdata, bitdata, imm(64 - seg.size)); + } + if (seg.size == 64) { + cmp(bitdata, seg.unit); + } else if (seg.size == 32) { + cmp(bitdata.w(), seg.unit); + } else if (seg.unit == 0) { + a.tst(bitdata, imm((1ull << seg.size) - 1)); + } else { + a.and_(TMP1, bitdata, imm((1ull << seg.size) - 1)); + cmp(TMP1, seg.unit); + } + a.b_ne(resolve_beam_label(Fail, disp1MB)); + break; + } + case BsmSegment::action::TEST_HEAP: { + comment("test_heap %ld", seg.size); + emit_gc_test(ArgWord(0), ArgWord(seg.size), seg.live); + position_is_valid = false; + break; + } + case BsmSegment::action::READ: { + comment("read %ld", seg.size); + if (seg.size == 0) { + comment("(nothing to do)"); + } else { + auto ctx = load_source(Ctx, ARG1); + + if (!position_is_valid) { + a.ldur(bin_position, + emit_boxed_val(ctx.reg, position_offset)); + position_is_valid = true; + } + a.ldur(bin_base, emit_boxed_val(ctx.reg, base_offset)); + + emit_read_bits(seg.size, bin_base, bin_position, bitdata); + + a.add(bin_position, bin_position, imm(seg.size)); + a.stur(bin_position, emit_boxed_val(ctx.reg, position_offset)); + } + break; + } + case BsmSegment::action::EXTRACT_BINARY: { + auto bits = seg.size; + auto Dst = seg.dst; + + comment("extract binary %ld", bits); + emit_extract_binary(bitdata, bits, Dst); + if (bits != 0 && bits != 64) { + a.ror(bitdata, bitdata, imm(64 - bits)); + } + break; + } + case BsmSegment::action::EXTRACT_INTEGER: { + auto bits = seg.size; + auto flags = seg.flags; + auto Dst = seg.dst; + + comment("extract integer %ld", bits); + if (bits != 0 && bits != 64) { + a.ror(bitdata, bitdata, imm(64 - bits)); + } + emit_extract_integer(bitdata, flags, bits, Dst); + break; + } + case BsmSegment::action::GET_INTEGER: { + Uint live = seg.live.as().get(); + Uint flags = seg.flags; + auto bits = seg.size; + auto Dst = seg.dst; + + comment("get integer %ld", bits); + auto ctx = load_source(Ctx, TMP1); + + a.mov(ARG1, c_p); + a.mov(ARG2, bits); + a.mov(ARG3, flags); + lea(ARG4, emit_boxed_val(ctx.reg, offsetof(ErlBinMatchState, mb))); + + if (bits >= SMALL_BITS) { + emit_enter_runtime(live); + } else { + emit_enter_runtime(live); + } + + runtime_call<4>(erts_bs_get_integer_2); + + if (bits >= SMALL_BITS) { + emit_leave_runtime(live); + } else { + emit_leave_runtime(live); + } + + mov_arg(Dst, ARG1); + + position_is_valid = false; + break; + } + case BsmSegment::action::GET_BINARY: { + auto Live = seg.live; + comment("get binary %ld", seg.size); + auto ctx = load_source(Ctx, TMP1); + + lea(ARG1, arm::Mem(c_p, offsetof(Process, htop))); + a.ldur(ARG2, emit_boxed_val(ctx.reg, orig_offset)); + a.ldur(ARG3, emit_boxed_val(ctx.reg, base_offset)); + a.ldur(ARG4, emit_boxed_val(ctx.reg, position_offset)); + mov_imm(ARG5, seg.size); + a.add(TMP2, ARG4, ARG5); + a.stur(TMP2, emit_boxed_val(ctx.reg, position_offset)); + + emit_enter_runtime( + Live.as().get()); + + runtime_call<5>(erts_extract_sub_binary); + + emit_leave_runtime( + Live.as().get()); + + mov_arg(seg.dst, ARG1); + position_is_valid = false; + break; + } + case BsmSegment::action::GET_TAIL: { + comment("get_tail"); + + mov_arg(ARG1, Ctx); + fragment_call(ga->get_bs_get_tail_shared()); + mov_arg(seg.dst, ARG1); + position_is_valid = false; + break; + } + case BsmSegment::action::SKIP: { + comment("skip %ld", seg.size); + auto ctx = load_source(Ctx, TMP1); + if (!position_is_valid) { + a.ldur(bin_position, emit_boxed_val(ctx.reg, position_offset)); + position_is_valid = true; + } + add(bin_position, bin_position, seg.size); + a.stur(bin_position, emit_boxed_val(ctx.reg, position_offset)); + break; + } + case BsmSegment::action::DROP: + auto bits = seg.size; + comment("drop %ld", bits); + if (bits != 0 && bits != 64) { + a.ror(bitdata, bitdata, imm(64 - bits)); + } + break; + } + } +} diff --git a/erts/emulator/beam/jit/arm/instr_call.cpp b/erts/emulator/beam/jit/arm/instr_call.cpp new file mode 100644 index 000000000000..8f755df54bc4 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_call.cpp @@ -0,0 +1,255 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2022. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "beam_common.h" +} + +void BeamGlobalAssembler::emit_dispatch_return() { + a.mov(ARG3, a64::x30); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, current))); + mov_imm(TMP1, 1); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, arity))); + a.b(labels[context_switch_simplified]); +} + +void BeamModuleAssembler::emit_return() { + emit_leave_erlang_frame(); + +#ifdef JIT_HARD_DEBUG + /* Validate return address and {x,0} */ + emit_validate(ArgVal(ArgVal::Word, 1)); +#endif + + /* The reduction test is kept in module code because moving it to a shared + * fragment caused major performance regressions in dialyzer. */ + a.subs(FCALLS, FCALLS, imm(1)); + a.b_mi(resolve_fragment(ga->get_dispatch_return(), disp1MB)); + + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_i_call(const ArgLabel &CallTarget) { + erlang_call(resolve_beam_label(CallTarget, disp128MB)); +} + +void BeamModuleAssembler::emit_i_call_last(const ArgLabel &CallTarget, + const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + emit_i_call_only(CallTarget); +} + +void BeamModuleAssembler::emit_move_call_last(const ArgYRegister &Src, + const ArgRegister &Dst, + const ArgLabel &CallTarget, + const ArgWord &Deallocate) { + auto src_index = Src.get(); + Sint deallocate = Deallocate.get() * sizeof(Eterm); + + if (src_index == 0 && Support::isInt9(deallocate)) { + auto dst = init_destination(Dst, TMP1); + const arm::Mem src_ref = arm::Mem(E).post(deallocate); + a.ldr(dst.reg, src_ref); + flush_var(dst); + } else { + mov_arg(Dst, Src); + emit_deallocate(Deallocate); + } + emit_i_call_only(CallTarget); +} + +void BeamModuleAssembler::emit_i_call_only(const ArgLabel &CallTarget) { + emit_leave_erlang_frame(); + a.b(resolve_beam_label(CallTarget, disp128MB)); +} + +/* Handles save_calls for remote calls. When the active code index is + * ERTS_SAVE_CALLS_CODE_IX, all remote calls will land here. + * + * Export entry is in ARG1, return address is in LR (x30). Both of these must + * be preserved since this runs between caller and callee. */ +void BeamGlobalAssembler::emit_dispatch_save_calls_export() { + a.str(ARG1, TMP_MEM1q); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG2, ARG1); + a.mov(ARG1, c_p); + runtime_call<2>(save_calls); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ldr(ARG1, TMP_MEM1q); + + /* Keep going with the actual code index. */ + a.mov(TMP1, imm(&the_active_code_index)); + a.ldr(TMP1.w(), arm::Mem(TMP1)); + + branch(emit_setup_dispatchable_call(ARG1, TMP1)); +} + +void BeamModuleAssembler::emit_i_call_ext(const ArgExport &Exp) { + mov_arg(ARG1, Exp); + + arm::Mem target = emit_setup_dispatchable_call(ARG1); + erlang_call(target); +} + +void BeamModuleAssembler::emit_i_call_ext_only(const ArgExport &Exp) { + mov_arg(ARG1, Exp); + + arm::Mem target = emit_setup_dispatchable_call(ARG1); + emit_leave_erlang_frame(); + branch(target); +} + +void BeamModuleAssembler::emit_i_call_ext_last(const ArgExport &Exp, + const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + emit_i_call_ext_only(Exp); +} + +void BeamModuleAssembler::emit_move_call_ext_last(const ArgYRegister &Src, + const ArgRegister &Dst, + const ArgExport &Exp, + const ArgWord &Deallocate) { + auto src_index = Src.get(); + Sint deallocate = Deallocate.get() * sizeof(Eterm); + + if (src_index == 0 && Support::isInt9(deallocate)) { + auto dst = init_destination(Dst, TMP1); + const arm::Mem src_ref = arm::Mem(E).post(deallocate); + a.ldr(dst.reg, src_ref); + flush_var(dst); + } else { + mov_arg(Dst, Src); + emit_deallocate(Deallocate); + } + emit_i_call_ext_only(Exp); +} + +static ErtsCodeMFA apply3_mfa = {am_erlang, am_apply, 3}; + +arm::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) { + Label dispatch = a.newLabel(), entry = a.newLabel(); + + a.bind(entry); + + emit_enter_runtime(3); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + + if (includeI) { + a.adr(ARG3, entry); + } else { + mov_imm(ARG3, 0); + } + + mov_imm(ARG4, 0); + + comment("apply()"); + runtime_call<4>(apply); + + /* Any number of X registers can be live at this point. */ + emit_leave_runtime(); + + a.cbnz(ARG1, dispatch); + emit_raise_exception(entry, &apply3_mfa); + + a.bind(dispatch); + return emit_setup_dispatchable_call(ARG1); +} + +void BeamModuleAssembler::emit_i_apply() { + arm::Mem target = emit_variable_apply(false); + erlang_call(target); +} + +void BeamModuleAssembler::emit_i_apply_last(const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + emit_i_apply_only(); +} + +void BeamModuleAssembler::emit_i_apply_only() { + arm::Mem target = emit_variable_apply(true); + + emit_leave_erlang_frame(); + branch(target); +} + +arm::Mem BeamModuleAssembler::emit_fixed_apply(const ArgWord &Arity, + bool includeI) { + Label dispatch = a.newLabel(), entry = a.newLabel(); + + a.bind(entry); + + mov_arg(ARG3, Arity); + + emit_enter_runtime(Arity.get() + 2); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + + if (includeI) { + a.adr(ARG4, entry); + } else { + mov_imm(ARG4, 0); + } + + mov_imm(ARG5, 0); + + runtime_call<5>(fixed_apply); + + /* We will need to reload all X registers in case there has been + * an error. */ + emit_leave_runtime(); + + a.cbnz(ARG1, dispatch); + emit_raise_exception(entry, &apply3_mfa); + + a.bind(dispatch); + + return emit_setup_dispatchable_call(ARG1); +} + +void BeamModuleAssembler::emit_apply(const ArgWord &Arity) { + arm::Mem target = emit_fixed_apply(Arity, false); + erlang_call(target); +} + +void BeamModuleAssembler::emit_apply_last(const ArgWord &Arity, + const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + + arm::Mem target = emit_fixed_apply(Arity, true); + + emit_leave_erlang_frame(); + branch(target); +} diff --git a/erts/emulator/beam/jit/arm/instr_common.cpp b/erts/emulator/beam/jit/arm/instr_common.cpp new file mode 100644 index 000000000000..06ebae04b9c2 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_common.cpp @@ -0,0 +1,2553 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +/* + * Notes. + * + * The immediate operand for the and, orr, eor, and tst instructions + * follow special rules. + * + * For our purposes, only bit patterns consisting of 1 through 63 ones + * at any position in a word are possible to encode as an + * immediate. Other patterns must be loaded into a tempoary register. + * + * Here are some examples of possible immediate values: + * + * 0b00000011 + * 0b00001111 + * 0b00111100 + * + * 0xFFFFFFFFFFFFFFF0 + * 0x100000000000000F + * + * The last one is possible because it is the pattern 0x1F + * (0b00011111) rotated right one position. + * + * Here is an example of mask that is not a possible to encode as an + * immediate: + * + * 0b111011 + * + * For more about the encoding rules, see: + * + * https://stackoverflow.com/questions/30904718/range-of-immediate-values-in-armv8-a64-assembly + * + */ + +#include +#include +#include "beam_asm.hpp" + +extern "C" +{ +#include "erl_bif_table.h" +#include "big.h" +#include "beam_catches.h" +#include "beam_common.h" +#include "code_ix.h" +#include "erl_binary.h" +} + +using namespace asmjit; + +/* Helpers */ + +void BeamModuleAssembler::emit_error(int reason) { + mov_imm(TMP1, reason); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + emit_raise_exception(); +} + +void BeamModuleAssembler::emit_error(int reason, const ArgSource &Src) { + auto src = load_source(Src, TMP2); + + ERTS_CT_ASSERT_FIELD_PAIR(Process, freason, fvalue); + mov_imm(TMP1, reason); + a.stp(TMP1, src.reg, arm::Mem(c_p, offsetof(Process, freason))); + emit_raise_exception(); +} + +void BeamModuleAssembler::emit_gc_test_preserve(const ArgWord &Need, + const ArgWord &Live, + const ArgSource &Preserve, + arm::Gp preserve_reg) { + const int32_t bytes_needed = (Need.get() + S_RESERVED) * sizeof(Eterm); + Label after_gc_check = a.newLabel(); + +#ifdef DEBUG + comment("(debug: fill dead X registers with garbage)"); + const arm::Gp garbage_reg = preserve_reg == ARG4 ? ARG3 : ARG4; + mov_imm(garbage_reg, ERTS_HOLE_MARKER); + if (!(Preserve.isXRegister() && + Preserve.as().get() >= Live.get())) { + mov_arg(ArgXRegister(Live.get()), garbage_reg); + mov_arg(ArgXRegister(Live.get() + 1), garbage_reg); + } else { + mov_imm(garbage_reg, ERTS_HOLE_MARKER); + mov_arg(ArgXRegister(Live.get() + 1), garbage_reg); + mov_arg(ArgXRegister(Live.get() + 2), garbage_reg); + } +#endif + + add(ARG3, HTOP, bytes_needed); + a.cmp(ARG3, E); + a.b_ls(after_gc_check); + + ASSERT(Live.get() < ERTS_X_REGS_ALLOCATED); + + /* We don't need to stash the preserved term if it's currently live, making + * the code slightly shorter. */ + if (!(Preserve.isXRegister() && + Preserve.as().get() >= Live.get())) { + mov_imm(ARG4, Live.get()); + fragment_call(ga->get_garbage_collect()); + mov_arg(preserve_reg, Preserve); + } else { + mov_arg(ArgXRegister(Live.get()), preserve_reg); + + mov_imm(ARG4, Live.get() + 1); + fragment_call(ga->get_garbage_collect()); + + mov_arg(preserve_reg, ArgXRegister(Live.get())); + } + + a.bind(after_gc_check); +} + +void BeamModuleAssembler::emit_gc_test(const ArgWord &Ns, + const ArgWord &Nh, + const ArgWord &Live) { + int32_t bytes_needed = (Ns.get() + Nh.get() + S_RESERVED) * sizeof(Eterm); + Label after_gc_check = a.newLabel(); + +#ifdef DEBUG + comment("(debug: fill dead X registers with garbage)"); + mov_imm(ARG4, ERTS_HOLE_MARKER); + mov_arg(ArgXRegister(Live.get()), ARG4); + mov_arg(ArgXRegister(Live.get() + 1), ARG4); +#endif + + add(ARG3, HTOP, bytes_needed); + a.cmp(ARG3, E); + a.b_ls(after_gc_check); + + mov_imm(ARG4, Live.get()); + fragment_call(ga->get_garbage_collect()); + + a.bind(after_gc_check); +} + +void BeamModuleAssembler::emit_validate(const ArgWord &Arity) { +#ifdef DEBUG + Label next = a.newLabel(), crash = a.newLabel(); + + /* Crash if the Erlang heap is not word-aligned */ + a.tst(HTOP, imm(sizeof(Eterm) - 1)); + a.b_ne(crash); + + /* Crash if the Erlang stack is not word-aligned */ + a.tst(E, imm(sizeof(Eterm) - 1)); + a.b_ne(crash); + + /* Crash if we've overrun the stack */ + lea(TMP1, arm::Mem(E, -(int32_t)(S_REDZONE * sizeof(Eterm)))); + a.cmp(HTOP, TMP1); + a.b_hi(crash); + + a.b(next); + + a.bind(crash); + a.udf(0xbad); + a.bind(next); + +# ifdef JIT_HARD_DEBUG + emit_enter_runtime_frame(); + + for (unsigned i = 0; i < arity.get(); i++) { + mov_arg(ARG1, ArgVal(ArgVal::XReg, i)); + + emit_enter_runtime(); + runtime_call<1>(beam_jit_validate_term); + emit_leave_runtime(); + } + + emit_leave_runtime_frame(); +# endif + +#endif +} + +/* Instrs */ + +void BeamModuleAssembler::emit_i_validate(const ArgWord &Arity) { + emit_validate(Arity); +} + +void BeamModuleAssembler::emit_allocate_heap(const ArgWord &NeedStack, + const ArgWord &NeedHeap, + const ArgWord &Live) { + ASSERT(NeedStack.get() <= MAX_REG); + + emit_gc_test(NeedStack, NeedHeap, Live); + + if (NeedStack.get() > 0) { + sub(E, E, NeedStack.get() * sizeof(Eterm)); + } +} + +void BeamModuleAssembler::emit_allocate(const ArgWord &NeedStack, + const ArgWord &Live) { + emit_allocate_heap(NeedStack, ArgWord(0), Live); +} + +void BeamModuleAssembler::emit_deallocate(const ArgWord &Deallocate) { + ASSERT(Deallocate.get() <= 1023); + + if (Deallocate.get() > 0) { + add(E, E, Deallocate.get() * sizeof(Eterm)); + } +} + +void BeamModuleAssembler::emit_test_heap(const ArgWord &Nh, + const ArgWord &Live) { + emit_gc_test(ArgWord(0), Nh, Live); +} + +void BeamModuleAssembler::emit_normal_exit() { + /* This is implicitly global; it does not normally appear in modules and + * doesn't require size optimization. */ + + emit_enter_runtime(); + emit_proc_lc_unrequire(); + + mov_imm(TMP1, EXC_NORMAL); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, arity))); + a.mov(ARG1, c_p); + mov_imm(ARG2, am_normal); + runtime_call<2>(erts_do_exit_process); + + emit_proc_lc_require(); + emit_leave_runtime(); + + a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); +} + +void BeamModuleAssembler::emit_continue_exit() { + /* This is implicitly global; it does not normally appear in modules and + * doesn't require size optimization. */ + + emit_enter_runtime(0); + emit_proc_lc_unrequire(); + + a.mov(ARG1, c_p); + runtime_call<1>(erts_continue_exit_process); + + emit_proc_lc_require(); + emit_leave_runtime(0); + + a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); +} + +void BeamModuleAssembler::emit_get_list(const ArgRegister &Src, + const ArgRegister &Hd, + const ArgRegister &Tl) { + auto src = load_source(Src, TMP1); + auto hd = init_destination(Hd, TMP2); + auto tl = init_destination(Tl, TMP3); + arm::Gp cons_ptr = emit_ptr_val(TMP1, src.reg); + + /* The `ldp` instruction does not accept a negative offset, so we + * will need subtract the LIST tag beforehand. (This also nicely + * take care of the potential overwriting issue when Src == Hd.) */ + a.sub(TMP1, cons_ptr, imm(TAG_PRIMARY_LIST)); + if (hd.reg == tl.reg) { + /* ldp with two identical registers is an illegal + * instruction. Produce the same result at the interpreter. */ + a.ldr(tl.reg, arm::Mem(TMP1, sizeof(Eterm))); + flush_var(tl); + } else { + a.ldp(hd.reg, tl.reg, arm::Mem(TMP1)); + flush_vars(hd, tl); + } +} + +void BeamModuleAssembler::emit_get_hd(const ArgRegister &Src, + const ArgRegister &Hd) { + auto src = load_source(Src, TMP1); + auto hd = init_destination(Hd, TMP2); + arm::Gp cons_ptr = emit_ptr_val(TMP1, src.reg); + + a.ldur(hd.reg, getCARRef(cons_ptr)); + flush_var(hd); +} + +void BeamModuleAssembler::emit_get_tl(const ArgRegister &Src, + const ArgRegister &Tl) { + auto src = load_source(Src, TMP1); + auto tl = init_destination(Tl, TMP2); + arm::Gp cons_ptr = emit_ptr_val(TMP1, src.reg); + + a.ldur(tl.reg, getCDRRef(cons_ptr)); + flush_var(tl); +} + +void BeamModuleAssembler::emit_i_get(const ArgSource &Src, + const ArgRegister &Dst) { + mov_arg(ARG2, Src); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_pd_hash_get); + + emit_leave_runtime(); + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_get_hash(const ArgConstant &Src, + const ArgWord &Hash, + const ArgRegister &Dst) { + mov_arg(ARG2, Hash); + mov_arg(ARG3, Src); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_pd_hash_get_with_hx); + + emit_leave_runtime(); + + mov_arg(Dst, ARG1); +} + +/* Store the untagged pointer to a tuple in ARG1. */ +void BeamModuleAssembler::emit_load_tuple_ptr(const ArgSource &Src) { + auto src = load_source(Src, ARG1); + emit_untag_ptr(ARG1, src.reg); +} + +#ifdef DEBUG +/* Emit an assertion to ensure that tuple_reg points into the same + * tuple as Src. */ +void BeamModuleAssembler::emit_tuple_assertion(const ArgSource &Src, + arm::Gp tuple_reg) { + Label ok = a.newLabel(), fatal = a.newLabel(); + ASSERT(tuple_reg != TMP1); + mov_arg(TMP1, Src); + emit_is_boxed(fatal, TMP1); + emit_untag_ptr(TMP1, TMP1); + a.cmp(TMP1, tuple_reg); + a.b_eq(ok); + + a.bind(fatal); + a.udf(0xaaaa); + a.bind(ok); +} +#endif + +/* Fetch an element from the tuple pointed to by the untagged pointer + * in ARG1. */ +void BeamModuleAssembler::emit_i_get_tuple_element(const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst) { +#ifdef DEBUG + emit_tuple_assertion(Src, ARG1); +#endif + + auto dst = init_destination(Dst, TMP1); + safe_ldr(dst.reg, arm::Mem(ARG1, Element.get())); + flush_var(dst); +} + +void BeamModuleAssembler::emit_get_tuple_element_swap( + const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst, + const ArgRegister &OtherDst) { +#ifdef DEBUG + emit_tuple_assertion(Src, ARG1); +#endif + + mov_arg(Dst, OtherDst); + + auto dst = init_destination(OtherDst, TMP1); + safe_ldr(dst.reg, arm::Mem(ARG1, Element.get())); + flush_var(dst); +} + +/* Fetch two consecutive tuple elements from the tuple pointed to by + * the boxed pointer in ARG1. */ +void BeamModuleAssembler::emit_get_two_tuple_elements(const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst1, + const ArgRegister &Dst2) { +#ifdef DEBUG + emit_tuple_assertion(Src, ARG1); +#endif + + auto dst1 = init_destination(Dst1, TMP1); + auto dst2 = init_destination(Dst2, TMP2); + + arm::Mem element_ptr = arm::Mem(ARG1, Element.get()); + safe_ldp(dst1.reg, dst2.reg, element_ptr); + flush_vars(dst1, dst2); +} + +void BeamModuleAssembler::emit_init(const ArgYRegister &Y) { + mov_imm(TMP1, NIL); + a.str(TMP1, getArgRef(Y)); +} + +void BeamModuleAssembler::emit_init_yregs(const ArgWord &Size, + const Span &args) { + unsigned count = Size.get(); + ASSERT(count == args.size()); + + unsigned i = 0; + + mov_imm(TMP1, NIL); + + while (i < count) { + unsigned first_y = args[i].as().get(); + unsigned slots = 1; + + while (i + slots < count) { + unsigned current_y = args[i + slots].as().get(); + + if (first_y + slots != current_y) { + break; + } + slots++; + } + + i += slots; + + /* Now first_y is the number of the first y register to be initialized + * and slots is the number of y registers to be initialized. */ + while (slots >= 2) { + /* `stp` can only address the first 64 Y registers. */ + if (first_y <= MAX_LDP_STP_DISPLACEMENT) { + a.stp(TMP1, TMP1, getYRef(first_y)); + first_y += 2; + slots -= 2; + } else { + a.str(TMP1, getYRef(first_y)); + first_y += 1; + slots -= 1; + } + } + + if (slots == 1) { + a.str(TMP1, getYRef(first_y)); + } + } +} + +void BeamModuleAssembler::emit_trim(const ArgWord &Words, + const ArgWord &Remaining) { + ASSERT(Words.get() <= 1023); + + if (Words.get() > 0) { + add(E, E, Words.get() * sizeof(Eterm)); + } +} + +void BeamModuleAssembler::emit_i_move(const ArgSource &Src, + const ArgRegister &Dst) { + mov_arg(Dst, Src); +} + +void BeamModuleAssembler::emit_move_trim(const ArgSource &Src, + const ArgRegister &Dst, + const ArgWord &Words) { + Sint trim = Words.get() * sizeof(Eterm); + ASSERT(Words.get() <= 1023); + + if (Src.isYRegister()) { + auto src_index = Src.as().get(); + if (src_index == 0 && Support::isInt9(trim)) { + const arm::Mem src_ref = arm::Mem(E).post(trim); + if (Dst.isXRegister()) { + auto dst = init_destination(Dst, TMP1); + a.ldr(dst.reg, src_ref); + flush_var(dst); + } else { + auto dst_index = Dst.as().get() - Words.get(); + auto dst = init_destination(ArgYRegister(dst_index), TMP1); + a.ldr(dst.reg, src_ref); + flush_var(dst); + } + + return; + } + } + + if (Dst.isYRegister()) { + auto dst_index = Dst.as().get(); + if (dst_index == Words.get() && Support::isInt9(trim)) { + auto src = load_source(Src, TMP1); + const arm::Mem dst_ref = arm::Mem(E, trim).pre(); + a.str(src.reg, dst_ref); + + return; + } + } + + /* Fallback. */ + mov_arg(Dst, Src); + if (Words.get() > 0) { + add(E, E, trim); + } +} + +void BeamModuleAssembler::emit_store_two_xregs(const ArgXRegister &Src1, + const ArgYRegister &Dst1, + const ArgXRegister &Src2, + const ArgYRegister &Dst2) { + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + auto dst1 = init_destination(Dst1, src1.reg); + auto dst2 = init_destination(Dst2, src2.reg); + + flush_vars(dst1, dst2); +} + +void BeamModuleAssembler::emit_load_two_xregs(const ArgYRegister &Src1, + const ArgXRegister &Dst1, + const ArgYRegister &Src2, + const ArgXRegister &Dst2) { + ASSERT(ArgVal::memory_relation(Src1, Src2) == + ArgVal::Relation::consecutive); + auto dst1 = init_destination(Dst1, TMP1); + auto dst2 = init_destination(Dst2, TMP2); + + safe_ldp(dst1.reg, dst2.reg, Src1, Src2); + flush_vars(dst1, dst2); +} + +void BeamModuleAssembler::emit_move_two_yregs(const ArgYRegister &Src1, + const ArgYRegister &Dst1, + const ArgYRegister &Src2, + const ArgYRegister &Dst2) { + /* Optimize fetching of source Y registers. */ + switch (ArgVal::memory_relation(Src1, Src2)) { + case ArgVal::Relation::consecutive: + safe_ldp(TMP1, TMP2, Src1, Src2); + break; + case ArgVal::Relation::reverse_consecutive: + safe_ldp(TMP2, TMP1, Src2, Src1); + break; + case ArgVal::Relation::none: + a.ldr(TMP1, getArgRef(Src1)); + a.ldr(TMP2, getArgRef(Src2)); + break; + } + + /* Destination registers are always in consecutive order. */ + safe_stp(TMP1, TMP2, Dst1, Dst2); +} + +void BeamModuleAssembler::emit_swap(const ArgRegister &R1, + const ArgRegister &R2) { + if (isRegisterBacked(R1)) { + auto r1 = load_source(R1, ZERO); + mov_arg(TMP1, R2); + mov_arg(R2, R1); + a.mov(r1.reg, TMP1); + } else if (isRegisterBacked(R2)) { + return emit_swap(R2, R1); + } else { + /* Both BEAM registers are stored in memory. */ + auto [r1, r2] = load_sources(R1, TMP1, R2, TMP2); + auto dst1 = init_destination(R2, r1.reg); + auto dst2 = init_destination(R1, r2.reg); + flush_vars(dst1, dst2); + } +} + +void BeamModuleAssembler::emit_swap2(const ArgRegister &R1, + const ArgRegister &R2, + const ArgRegister &R3) { + auto [arg1, arg2] = load_sources(R1, TMP1, R2, TMP2); + auto arg3 = load_source(R3, TMP3); + + mov_var(TMP4, arg1); + mov_var(arg1, arg2); + mov_var(arg2, arg3); + mov_var(arg3, TMP4); + + flush_vars(arg1, arg2); + flush_var(arg3); +} + +void BeamModuleAssembler::emit_swap3(const ArgRegister &R1, + const ArgRegister &R2, + const ArgRegister &R3, + const ArgRegister &R4) { + auto [arg1, arg2] = load_sources(R1, TMP1, R2, TMP2); + auto [arg3, arg4] = load_sources(R3, TMP3, R4, TMP4); + + mov_var(TMP5, arg1); + mov_var(arg1, arg2); + mov_var(arg2, arg3); + mov_var(arg3, arg4); + mov_var(arg4, TMP5); + + flush_vars(arg1, arg2); + flush_vars(arg3, arg4); +} + +void BeamModuleAssembler::emit_swap4(const ArgRegister &R1, + const ArgRegister &R2, + const ArgRegister &R3, + const ArgRegister &R4, + const ArgRegister &R5) { + auto [arg1, arg2] = load_sources(R1, TMP1, R2, TMP2); + auto [arg3, arg4] = load_sources(R3, TMP3, R4, TMP4); + auto arg5 = load_source(R5, TMP5); + + mov_var(TMP6, arg1); + mov_var(arg1, arg2); + mov_var(arg2, arg3); + mov_var(arg3, arg4); + mov_var(arg4, arg5); + mov_var(arg5, TMP6); + + flush_vars(arg1, arg2); + flush_vars(arg3, arg4); + flush_var(arg5); +} + +void BeamModuleAssembler::emit_node(const ArgRegister &Dst) { + a.ldr(TMP1, embed_constant(&erts_this_node, disp32K)); + a.ldr(TMP1, arm::Mem(TMP1)); + mov_arg(Dst, arm::Mem(TMP1, offsetof(ErlNode, sysname))); +} + +void BeamModuleAssembler::emit_put_list(const ArgSource &Hd, + const ArgSource &Tl, + const ArgRegister &Dst) { + auto [hd, tl] = load_sources(Hd, TMP1, Tl, TMP2); + auto dst = init_destination(Dst, TMP3); + + a.stp(hd.reg, tl.reg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + a.sub(dst.reg, HTOP, imm(sizeof(Eterm[2]) - TAG_PRIMARY_LIST)); + + flush_var(dst); +} + +void BeamModuleAssembler::emit_put_list2(const ArgSource &Hd1, + const ArgSource &Hd2, + const ArgSource &Tl, + const ArgRegister &Dst) { + const arm::Mem put_cons = arm::Mem(HTOP).post(sizeof(Eterm[2])); + + auto [hd1, hd2] = load_sources(Hd1, TMP1, Hd2, TMP2); + auto tl = load_source(Tl, TMP3); + auto dst = init_destination(Dst, TMP4); + + a.stp(hd1.reg, tl.reg, put_cons); + a.sub(dst.reg, HTOP, imm(sizeof(Eterm[2]) - TAG_PRIMARY_LIST)); + + a.stp(hd2.reg, dst.reg, put_cons); + a.sub(dst.reg, HTOP, imm(sizeof(Eterm[2]) - TAG_PRIMARY_LIST)); + + flush_var(dst); +} + +void BeamModuleAssembler::emit_put_tuple2(const ArgRegister &Dst, + const ArgWord &Arity, + const Span &args) { + ASSERT(arityval(Arity.get()) == args.size()); + + std::vector data; + data.reserve(args.size() + 1); + data.push_back(Arity); + + bool dst_is_src = false; + for (auto arg : args) { + data.push_back(arg); + dst_is_src |= (arg == Dst); + } + + if (dst_is_src) { + a.add(TMP1, HTOP, TAG_PRIMARY_BOXED); + } else { + auto ptr = init_destination(Dst, TMP1); + a.add(ptr.reg, HTOP, TAG_PRIMARY_BOXED); + flush_var(ptr); + } + + size_t size = data.size(); + unsigned i; + for (i = 0; i < size - 1; i += 2) { + if ((i % 128) == 0) { + check_pending_stubs(); + } + + auto [first, second] = load_sources(data[i], TMP2, data[i + 1], TMP3); + a.stp(first.reg, second.reg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } + + if (i < size) { + mov_arg(arm::Mem(HTOP).post(sizeof(Eterm)), data[i]); + } + + if (dst_is_src) { + auto ptr = init_destination(Dst, TMP1); + mov_var(ptr, TMP1); + flush_var(ptr); + } +} + +void BeamModuleAssembler::emit_self(const ArgRegister &Dst) { + mov_arg(Dst, arm::Mem(c_p, offsetof(Process, common.id))); +} + +void BeamModuleAssembler::emit_copy_words_increment(arm::Gp from, + arm::Gp to, + size_t count) { + check_pending_stubs(); + + /* Copy the words inline if we can, otherwise use a loop with the largest + * vector size we're capable of. */ + if (count <= 16) { + while (count >= 4) { + a.ldp(a64::q30, a64::q31, arm::Mem(from).post(sizeof(UWord[4]))); + a.stp(a64::q30, a64::q31, arm::Mem(to).post(sizeof(UWord[4]))); + count -= 4; + } + } else { + Label copy_next = a.newLabel(); + + ASSERT(Support::isUInt16(count / 4)); + mov_imm(SUPER_TMP, count / 4); + a.bind(copy_next); + { + a.ldp(a64::q30, a64::q31, arm::Mem(from).post(sizeof(UWord[4]))); + a.stp(a64::q30, a64::q31, arm::Mem(to).post(sizeof(UWord[4]))); + a.subs(SUPER_TMP, SUPER_TMP, imm(1)); + a.b_ne(copy_next); + } + + count = count % 4; + } + + if (count >= 2) { + a.ldr(a64::q30, arm::Mem(from).post(sizeof(UWord[2]))); + a.str(a64::q30, arm::Mem(to).post(sizeof(UWord[2]))); + count -= 2; + } + + if (count == 1) { + a.ldr(SUPER_TMP, arm::Mem(from).post(sizeof(UWord))); + a.str(SUPER_TMP, arm::Mem(to).post(sizeof(UWord))); + count -= 1; + } + + ASSERT(count == 0); + (void)count; +} + +void BeamModuleAssembler::emit_update_record(const ArgAtom &Hint, + const ArgWord &TupleSize, + const ArgSource &Src, + const ArgRegister &Dst, + const ArgWord &UpdateCount, + const Span &updates) { + const size_t size_on_heap = TupleSize.get() + 1; + Label next = a.newLabel(); + + ASSERT(UpdateCount.get() == updates.size()); + ASSERT((UpdateCount.get() % 2) == 0); + + ASSERT(size_on_heap > 2); + + auto destination = init_destination(Dst, ARG1); + auto src = load_source(Src, ARG2); + + arm::Gp untagged_src = ARG3; + emit_untag_ptr(untagged_src, src.reg); + + /* Setting a field to the same value is pretty common, so we'll check for + * that since it's vastly cheaper than copying if we're right, and doesn't + * cost much if we're wrong. */ + if (Hint.get() == am_reuse && updates.size() == 2) { + const auto next_index = updates[0].as().get(); + const auto &next_value = updates[1].as(); + + safe_ldr(TMP1, arm::Mem(untagged_src, next_index * sizeof(Eterm))); + cmp_arg(TMP1, next_value); + + if (destination.reg != src.reg) { + a.csel(destination.reg, + destination.reg, + src.reg, + imm(arm::CondCode::kNE)); + } + a.b_eq(next); + } + + size_t copy_index = 0; + + for (size_t i = 0; i < updates.size(); i += 2) { + const auto next_index = updates[i].as().get(); + const auto &next_value = updates[i + 1].as(); + bool odd_copy; + + ASSERT(next_index > 0 && next_index >= copy_index); + + /* If we need to copy an odd number of elements, we'll do the last one + * ourselves to save us from having to increment `untagged_src` + * separately. */ + odd_copy = (next_index - copy_index) & 1; + emit_copy_words_increment(untagged_src, + HTOP, + (next_index - copy_index) & ~1); + + if ((i + 2) < updates.size()) { + const auto adjacent_index = updates[i + 2].as().get(); + const auto &adjacent_value = updates[i + 3].as(); + + if (adjacent_index == next_index + 1) { + auto [first, second] = + load_sources(next_value, TMP1, adjacent_value, TMP2); + + if (odd_copy) { + a.ldr(TMP3, arm::Mem(untagged_src).post(sizeof(Eterm[3]))); + a.stp(TMP3, + first.reg, + arm::Mem(HTOP).post(sizeof(Eterm[2]))); + a.str(second.reg, arm::Mem(HTOP).post(sizeof(Eterm))); + } else { + a.add(untagged_src, untagged_src, imm(sizeof(Eterm[2]))); + a.stp(first.reg, + second.reg, + arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } + + copy_index = next_index + 2; + i += 2; + continue; + } + } + + auto value = load_source(next_value, TMP1); + + if ((next_index - copy_index) & 1) { + a.ldr(TMP2, arm::Mem(untagged_src).post(sizeof(Eterm[2]))); + a.stp(TMP2, value.reg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } else { + a.add(untagged_src, untagged_src, imm(sizeof(Eterm))); + a.str(value.reg, arm::Mem(HTOP).post(sizeof(Eterm))); + } + + copy_index = next_index + 1; + } + + emit_copy_words_increment(untagged_src, HTOP, size_on_heap - copy_index); + + sub(destination.reg, + HTOP, + (size_on_heap * sizeof(Eterm)) - TAG_PRIMARY_BOXED); + + a.bind(next); + flush_var(destination); +} + +void BeamModuleAssembler::emit_set_tuple_element(const ArgSource &Element, + const ArgRegister &Tuple, + const ArgWord &Offset) { + auto tuple = load_source(Tuple, TMP1); + auto element = load_source(Element, TMP2); + arm::Gp boxed_ptr = emit_ptr_val(TMP1, tuple.reg); + arm::Mem boxed_val = emit_boxed_val(boxed_ptr, Offset.get()); + + stur(element.reg, boxed_val); +} + +void BeamModuleAssembler::emit_is_nonempty_list(const ArgLabel &Fail, + const ArgRegister &Src) { + auto list_ptr = load_source(Src, TMP1); + const int bitNumber = 1; + + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST == (1 << bitNumber)); + a.tbnz(list_ptr.reg, imm(bitNumber), resolve_beam_label(Fail, disp32K)); +} + +void BeamModuleAssembler::emit_jump(const ArgLabel &Fail) { + a.b(resolve_beam_label(Fail, disp128MB)); +} + +void BeamModuleAssembler::emit_is_atom(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + a.and_(TMP1, src.reg, imm(_TAG_IMMED2_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED2_ATOM)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +void BeamModuleAssembler::emit_is_boolean(const ArgLabel &Fail, + const ArgSource &Src) { + /* Since am_true and am_false differ by a single bit, we can simplify the + * check by clearing said bit and comparing against the lesser one. */ + ERTS_CT_ASSERT(am_false == make_atom(0)); + ERTS_CT_ASSERT(am_true == make_atom(1)); + + auto src = load_source(Src, TMP1); + a.and_(TMP1, src.reg, imm(~(am_true & ~_TAG_IMMED2_MASK))); + a.cmp(TMP1, imm(am_false)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +void BeamModuleAssembler::emit_is_binary(const ArgLabel &Fail, + const ArgSource &Src) { + Label is_binary = a.newLabel(), next = a.newLabel(); + + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + arm::Gp boxed_ptr = emit_ptr_val(ARG1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + if (masked_types(Src) == BeamTypeId::Bitstring) { + const int bit_number = 3; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & (1 << bit_number)) != 0 && + (_TAG_HEADER_REFC_BIN & (1 << bit_number)) == 0 && + (_TAG_HEADER_HEAP_BIN & (1 << bit_number)) == 0); + comment("simplified binary test since source is always a bitstring " + "when boxed"); + a.tbz(TMP1, imm(bit_number), next); + } else { + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_SUB_BIN)); + a.b_ne(is_binary); + } + + /* This is a sub binary. */ + a.ldrb(TMP1.w(), emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + a.cbnz(TMP1, resolve_beam_label(Fail, disp1MB)); + if (masked_types(Src) != BeamTypeId::Bitstring) { + a.b(next); + } + + a.bind(is_binary); + if (masked_types(Src) != BeamTypeId::Bitstring) { + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(TMP1, TMP1, imm(~4)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_bitstring(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + arm::Gp boxed_ptr = emit_ptr_val(ARG1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + + /* The header mask with the binary sub tag bits removed (0b110011) + * is not possible to use as an immediate operand for 'and'. (See + * the note at the beginning of the file.) Therefore, use a + * simpler mask (0b110000) that will also clear the primary tag + * bits. That works because we KNOW that a boxed pointer always + * points to a header word and that the primary tag for a header + * is 0. + */ + const auto mask = _HEADER_SUBTAG_MASK - _BINARY_XXX_MASK; + ERTS_CT_ASSERT(TAG_PRIMARY_HEADER == 0); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN == (_TAG_HEADER_REFC_BIN & mask)); + a.and_(TMP1, TMP1, imm(mask)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +void BeamModuleAssembler::emit_is_float(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + if (masked_types(Src) == BeamTypeId::Float) { + comment("skipped header test since we know it's a float when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + + a.cmp(TMP1, imm(HEADER_FLONUM)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_is_function(const ArgLabel &Fail, + const ArgRegister &Src) { + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + if (masked_types(Src) == BeamTypeId::Fun) { + comment("skipped header test since we know it's a fun when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.cmp(TMP1, imm(HEADER_FUN)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_is_function2(const ArgLabel &Fail, + const ArgSource &Src, + const ArgSource &Arity) { + if (!Arity.isSmall()) { + /* + * Non-literal arity - extremely uncommon. Generate simple code. + */ + mov_arg(ARG2, Src); + mov_arg(ARG3, Arity); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erl_is_function); + + emit_leave_runtime(); + + a.cmp(ARG1, imm(am_true)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + + return; + } + + unsigned arity = Arity.as().getUnsigned(); + if (arity > MAX_ARG) { + /* Arity is negative or too large. */ + a.b(resolve_beam_label(Fail, disp128MB)); + + return; + } + + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + + if (masked_types(Src) == BeamTypeId::Fun) { + comment("skipped header test since we know it's a fun when boxed"); + } else { + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + a.cmp(TMP2, imm(HEADER_FUN)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.ldurb(TMP2.w(), emit_boxed_val(boxed_ptr, offsetof(ErlFunThing, arity))); + emit_branch_if_ne(TMP2, arity, resolve_beam_label(Fail, dispUnknown)); +} + +void BeamModuleAssembler::emit_is_integer(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + if (always_immediate(Src)) { + comment("skipped test for boxed since the value is always immediate"); + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + + return; + } + + Label next = a.newLabel(); + + if (always_one_of(Src)) { + comment("simplified small test since all other types are boxed"); + emit_is_boxed(next, Src, src.reg); + } else { + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_eq(next); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, TMP2); + } + + if (masked_types(Src) == BeamTypeId::Integer) { + comment("skipped header test since we know it's a bignum when " + "boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + + /* The header mask with the sign bit removed (0b111011) is not + * possible to use as an immediate operand for 'and'. (See the + * note at the beginning of the file.) Therefore, use a + * simpler mask (0b111000) that will also clear the primary + * tag bits. That works because we KNOW that a boxed pointer + * always points to a header word and that the primary tag for + * a header is 0. + */ + auto mask = _HEADER_SUBTAG_MASK - _BIG_SIGN_BIT; + ERTS_CT_ASSERT(TAG_PRIMARY_HEADER == 0); + a.and_(TMP1, TMP1, imm(mask)); + a.cmp(TMP1, imm(_TAG_HEADER_POS_BIG)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_list(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + a.tst(src.reg, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); + a.mov(TMP2, NIL); + a.ccmp(src.reg, TMP2, imm(NZCV::kEqual), imm(arm::CondCode::kNE)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +void BeamModuleAssembler::emit_is_map(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + /* As an optimization for the `error | #{}` case, skip checking the header + * word when we know that the only possible boxed type is a map. */ + if (masked_types(Src) == BeamTypeId::Map) { + comment("skipped header test since we know it's a map when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_MAP)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_is_nil(const ArgLabel &Fail, + const ArgRegister &Src) { + auto src = load_source(Src, TMP1); + + if (always_one_of(Src)) { + const int bitNumber = 1; + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST == + (1 << bitNumber)); + comment("simplified is_nil test because its argument is always a list"); + a.tbz(src.reg, imm(bitNumber), resolve_beam_label(Fail, disp32K)); + } else { + a.cmp(src.reg, imm(NIL)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_is_number(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + Label next = a.newLabel(); + + if (always_one_of(Src)) { + comment("simplified small test since all other types are boxed"); + emit_is_boxed(next, Src, src.reg); + } else { + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_eq(next); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + } + + if (masked_types(Src) == BeamTypeId::Number) { + comment("skipped header test since we know it's a number when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + + /* The header mask with the sign bit removed (0b111011) is not + * possible to use as an immediate operand for 'and'. (See the + * note at the beginning of the file.) Therefore, use a + * simpler mask (0b111000) that will also clear the primary + * tag bits. That works because we KNOW that a boxed pointer + * always points to a header word and that the primary tag for + * a header is 0. + */ + auto mask = _HEADER_SUBTAG_MASK - _BIG_SIGN_BIT; + ERTS_CT_ASSERT(TAG_PRIMARY_HEADER == 0); + a.and_(TMP2, TMP1, imm(mask)); + a.cmp(TMP2, imm(_TAG_HEADER_POS_BIG)); + + a.mov(TMP3, imm(HEADER_FLONUM)); + a.ccmp(TMP1, TMP3, imm(NZCV::kEqual), imm(arm::CondCode::kNE)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_pid(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + Label next = a.newLabel(); + + if (always_one_of(Src)) { + comment("simplified local pid test since all other types are boxed"); + emit_is_boxed(next, Src, src.reg); + } else { + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_PID)); + a.b_eq(next); + + /* Reuse TMP2 as the important bits are still available. */ + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, TMP2); + } + + if (masked_types(Src) == BeamTypeId::Pid) { + comment("skipped header test since we know it's a pid when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + a.and_(TMP2, TMP2, imm(_TAG_HEADER_MASK)); + a.cmp(TMP2, imm(_TAG_HEADER_EXTERNAL_PID)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_port(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + Label next = a.newLabel(); + + if (always_one_of(Src)) { + comment("simplified local port test since all other types are boxed"); + emit_is_boxed(next, Src, src.reg); + } else { + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_PORT)); + a.b_eq(next); + + /* Reuse TMP2 as the important bits are still available. */ + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, TMP2); + } + + if (masked_types(Src) == BeamTypeId::Port) { + comment("skipped header test since we know it's a port when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + a.and_(TMP2, TMP2, imm(_TAG_HEADER_MASK)); + a.cmp(TMP2, imm(_TAG_HEADER_EXTERNAL_PORT)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_reference(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + if (masked_types(Src) == BeamTypeId::Reference) { + comment("skipped header test since we know it's a ref when boxed"); + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_EXTERNAL_REF)); + a.ccmp(TMP1, + imm(_TAG_HEADER_REF), + imm(NZCV::kEqual), + imm(arm::CondCode::kNE)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +/* Note: This instruction leaves the untagged pointer to the tuple in + * ARG1. */ +void BeamModuleAssembler::emit_i_is_tagged_tuple(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity, + const ArgAtom &Tag) { + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + emit_untag_ptr(ARG1, src.reg); + + /* It is safe to fetch the both the header word and the first + * element of the tuple with ldp because the empty tuple is always + * a literal that is padded so that the word after arity is + * allocated. */ + a.ldp(TMP1, TMP2, arm::Mem(ARG1)); + + if (Arity.get() < 32) { + cmp_arg(TMP2, Tag); + a.ccmp(TMP1, + imm(Arity.get()), + imm(NZCV::kNone), + imm(arm::CondCode::kEQ)); + } else { + cmp_arg(TMP1, Arity); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + cmp_arg(TMP2, Tag); + } + + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +/* Note: This instruction leaves the untagged pointer to the tuple in + * ARG2. */ +void BeamModuleAssembler::emit_i_is_tagged_tuple_ff(const ArgLabel &NotTuple, + const ArgLabel &NotRecord, + const ArgSource &Src, + const ArgWord &Arity, + const ArgAtom &Tag) { + Label correct_arity = a.newLabel(); + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(NotTuple, dispUnknown), Src, src.reg); + + emit_untag_ptr(ARG1, src.reg); + + /* It is safe to fetch the both the header word and the first + * element of the tuple with ldp because the empty tuple is always + * a literal that is padded so that the word after arity is + * allocated. */ + a.ldp(TMP1, TMP2, arm::Mem(ARG1)); + + cmp_arg(TMP1, Arity); + a.b_eq(correct_arity); + + /* Not a tuple or the wrong arity. Decide which. */ + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.tst(TMP1, imm(_TAG_HEADER_MASK)); + a.b_eq(resolve_beam_label(NotRecord, disp1MB)); + a.b(resolve_beam_label(NotTuple, disp128MB)); + + a.bind(correct_arity); + { + cmp_arg(TMP2, Tag); + a.b_ne(resolve_beam_label(NotRecord, disp1MB)); + } +} + +/* Note: This instruction leaves the untagged pointer to the tuple in + * ARG1. */ +void BeamModuleAssembler::emit_i_is_tuple(const ArgLabel &Fail, + const ArgSource &Src) { + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + emit_untag_ptr(ARG1, src.reg); + + /* As an optimization for the `error | {ok, Value}` case, skip checking the + * header word when we know that the only possible boxed type is a tuple. */ + if (masked_types(Src) == BeamTypeId::Tuple) { + comment("skipped header test since we know it's a tuple when boxed"); + } else { + a.ldr(TMP1, arm::Mem(ARG1)); + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.tst(TMP1, imm(_TAG_HEADER_MASK)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } +} + +/* Note: This instruction leaves the untagged pointer to the tuple in + * ARG1. */ +void BeamModuleAssembler::emit_i_is_tuple_of_arity(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity) { + auto src = load_source(Src, ARG1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + emit_untag_ptr(ARG1, src.reg); + + a.ldr(TMP1, arm::Mem(ARG1)); + cmp_arg(TMP1, Arity); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +/* Note: This instruction leaves the untagged pointer to the tuple in + * ARG1. */ +void BeamModuleAssembler::emit_i_test_arity(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity) { + auto src = load_source(Src, ARG1); + emit_untag_ptr(ARG1, src.reg); + + a.ldr(TMP1, arm::Mem(ARG1)); + cmp_arg(TMP1, Arity); + a.b_ne(resolve_beam_label(Fail, disp1MB)); +} + +void BeamModuleAssembler::emit_is_eq_exact(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + auto x = load_source(X, ARG1); + + bool is_empty_binary = false; + if (exact_type(X) && Y.isLiteral()) { + auto unit = getSizeUnit(X); + if (unit != 0 && std::gcd(unit, 8) == 8) { + Eterm literal = + beamfile_get_literal(beam, Y.as().get()); + is_empty_binary = is_binary(literal) && binary_size(literal) == 0; + } + } + + if (is_empty_binary) { + auto unit = getSizeUnit(X); + + comment("simplified equality test with empty binary"); + if (unit != 0 && std::gcd(unit, 8) == 8) { + arm::Gp boxed_ptr = emit_ptr_val(ARG1, x.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.cbnz(TMP1, resolve_beam_label(Fail, disp1MB)); + } else { + Label next = a.newLabel(); + + emit_untag_ptr(ARG1, x.reg); + ERTS_CT_ASSERT_FIELD_PAIR(ErlHeapBin, thing_word, size); + a.ldp(TMP1, TMP2, arm::Mem(ARG1)); + a.cbnz(TMP2, resolve_beam_label(Fail, disp1MB)); + + const int bit_number = 3; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & (1 << bit_number)) != 0 && + (_TAG_HEADER_REFC_BIN & (1 << bit_number)) == 0 && + (_TAG_HEADER_HEAP_BIN & (1 << bit_number)) == 0); + a.tbz(TMP1, imm(bit_number), next); + + a.ldrb(TMP1.w(), arm::Mem(ARG1, offsetof(ErlSubBin, bitsize))); + a.cbnz(TMP1, resolve_beam_label(Fail, disp1MB)); + + a.bind(next); + } + + return; + } + + /* If either argument is known to be an immediate, we can fail immediately + * if they're not equal. */ + if (always_immediate(X) || always_immediate(Y)) { + if (!X.isImmed() && !Y.isImmed()) { + comment("simplified check since one argument is an immediate"); + } + + cmp_arg(x.reg, Y); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + + return; + } + + /* Both operands are registers or literals. */ + Label next = a.newLabel(); + auto y = load_source(Y, ARG2); + + a.cmp(x.reg, y.reg); + a.b_eq(next); + + if (always_same_types(X, Y)) { + comment("skipped tag test since they are always equal"); + } else if (Y.isLiteral()) { + /* Fail immediately unless X is the same type of pointer as + * the literal Y. + */ + Eterm literal = beamfile_get_literal(beam, Y.as().get()); + Uint tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); + int bitNumber = Support::ctz(tag_test); + a.tbnz(x.reg, imm(bitNumber), resolve_beam_label(Fail, disp32K)); + } else { + /* Fail immediately if the pointer tags are not equal. */ + emit_is_unequal_based_on_tags(x.reg, y.reg); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + } + + /* Both operands are pointers having the same tag. Must do a + * deeper comparison. */ + mov_var(ARG1, x); + mov_var(ARG2, y); + + emit_enter_runtime(); + runtime_call<2>(eq); + emit_leave_runtime(); + + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_ne_exact(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + auto x = load_source(X, ARG1); + + bool is_empty_binary = false; + if (exact_type(X) && Y.isLiteral()) { + auto unit = getSizeUnit(X); + if (unit != 0 && std::gcd(unit, 8) == 8) { + Eterm literal = + beamfile_get_literal(beam, Y.as().get()); + is_empty_binary = is_binary(literal) && binary_size(literal) == 0; + } + } + + if (is_empty_binary) { + arm::Gp boxed_ptr = emit_ptr_val(ARG1, x.reg); + + comment("simplified non-equality test with empty binary"); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.cbz(TMP1, resolve_beam_label(Fail, disp1MB)); + + return; + } + + /* If either argument is known to be an immediate, we can fail immediately + * if they're equal. */ + if (always_immediate(X) || always_immediate(Y)) { + if (!X.isImmed() && !Y.isImmed()) { + comment("simplified check since one argument is an immediate"); + } + + cmp_arg(x.reg, Y); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + return; + } + + /* Both operands are registers or literals. */ + Label next = a.newLabel(); + auto y = load_source(Y, ARG2); + + a.cmp(x.reg, y.reg); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + if (always_same_types(X, Y)) { + comment("skipped tag test since they are always equal"); + } else if (Y.isLiteral()) { + /* Succeed immediately if X is not the same type of pointer as + * the literal Y. + */ + Eterm literal = beamfile_get_literal(beam, Y.as().get()); + Uint tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); + int bitNumber = Support::ctz(tag_test); + a.tbnz(x.reg, imm(bitNumber), next); + } else { + /* Test whether the terms are definitely unequal based on the tags + * alone. */ + emit_is_unequal_based_on_tags(x.reg, y.reg); + a.b_eq(next); + } + + /* Both operands are pointers having the same tag. Must do a + * deeper comparison. */ + mov_var(ARG1, x); + mov_var(ARG2, y); + + emit_enter_runtime(); + + runtime_call<2>(eq); + + emit_leave_runtime(); + + a.cbnz(ARG1, resolve_beam_label(Fail, disp1MB)); + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_eq(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + Label next = a.newLabel(); + + auto x = load_source(X, ARG1); + auto y = load_source(Y, ARG2); + + a.cmp(x.reg, y.reg); + a.b_eq(next); + + /* We can skip deep comparisons when both args are immediates. */ + emit_are_both_immediate(x.reg, y.reg); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + mov_var(ARG1, x); + mov_var(ARG2, y); + fragment_call(ga->get_arith_compare_shared()); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + + a.bind(next); +} + +void BeamModuleAssembler::emit_is_ne(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + Label next = a.newLabel(); + + auto x = load_source(X, ARG1); + auto y = load_source(Y, ARG2); + + a.cmp(x.reg, y.reg); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + /* We can skip deep comparisons when both args are immediates. */ + emit_are_both_immediate(x.reg, y.reg); + a.b_eq(next); + + mov_var(ARG1, x); + mov_var(ARG2, y); + fragment_call(ga->get_arith_compare_shared()); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + a.bind(next); +} + +/* + * ARG1 = LHS + * ARG2 = RHS + * + * Result is returned in the flags. + */ +void BeamGlobalAssembler::emit_arith_compare_shared() { + Label atom_compare = a.newLabel(), generic_compare = a.newLabel(); + + /* Are both floats? + * + * This is done first as relative comparisons on atoms doesn't make much + * sense. */ + a.orr(TMP1, ARG1, ARG2); + emit_is_boxed(atom_compare, TMP1); + + arm::Gp boxed_ptr1 = emit_ptr_val(TMP1, ARG1); + a.ldur(TMP3, emit_boxed_val(boxed_ptr1)); + arm::Gp boxed_ptr2 = emit_ptr_val(TMP2, ARG2); + a.ldur(TMP4, emit_boxed_val(boxed_ptr2)); + + mov_imm(TMP5, HEADER_FLONUM); + a.cmp(TMP3, TMP5); + a.ccmp(TMP4, TMP5, imm(NZCV::kNone), imm(arm::CondCode::kEQ)); + a.b_ne(generic_compare); + + a.ldur(a64::d0, emit_boxed_val(boxed_ptr1, sizeof(Eterm))); + a.ldur(a64::d1, emit_boxed_val(boxed_ptr2, sizeof(Eterm))); + a.fcmpe(a64::d0, a64::d1); + a.ret(a64::x30); + + a.bind(atom_compare); + { + a.and_(TMP1, ARG1, imm(_TAG_IMMED2_MASK)); + a.and_(TMP2, ARG2, imm(_TAG_IMMED2_MASK)); + a.sub(TMP1, TMP1, imm(_TAG_IMMED2_ATOM)); + a.sub(TMP2, TMP2, imm(_TAG_IMMED2_ATOM)); + a.orr(TMP1, TMP1, TMP2); + a.cbnz(TMP1, generic_compare); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + runtime_call<2>(erts_cmp_atoms); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + /* Note: erts_cmp_atoms() returns int, not Sint. */ + a.tst(ARG1.w(), ARG1.w()); + a.ret(a64::x30); + } + + a.bind(generic_compare); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + comment("erts_cmp_compound(X, Y, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.tst(ARG1, ARG1); + + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_is_lt(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS) { + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + a.cmp(lhs.reg, rhs.reg); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + } else if (always_small(LHS) && exact_type(RHS) && + hasLowerBound(RHS)) { + Label next = a.newLabel(); + comment("simplified test because it always succeeds when RHS is a " + "bignum"); + emit_is_not_boxed(next, rhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + a.bind(next); + } else if (always_small(LHS) && exact_type(RHS) && + hasUpperBound(RHS)) { + comment("simplified test because it always fails when RHS is a bignum"); + emit_is_not_boxed(resolve_beam_label(Fail, dispUnknown), rhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + } else if (exact_type(LHS) && hasLowerBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always fails when LHS is a bignum"); + emit_is_not_boxed(resolve_beam_label(Fail, dispUnknown), lhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + } else if (exact_type(LHS) && hasUpperBound(LHS) && + always_small(RHS)) { + Label next = a.newLabel(); + comment("simplified test because it always succeeds when LHS is a " + "bignum"); + emit_is_not_boxed(next, rhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + a.bind(next); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + Label branch_compare = a.newLabel(); + + a.cmp(lhs.reg, rhs.reg); + + /* The only possible kind of immediate is a small and all other values + * are boxed, so we can test for smalls by testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_boxed(branch_compare, rhs.reg); + } else if (always_small(RHS)) { + emit_is_boxed(branch_compare, lhs.reg); + } else { + a.and_(TMP1, lhs.reg, rhs.reg); + emit_is_boxed(branch_compare, TMP1); + } + + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + + /* The flags will either be from the initial comparison, or from the + * shared fragment. */ + a.bind(branch_compare); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + } else { + Label generic = a.newLabel(), next = a.newLabel(); + + /* Relative comparisons are overwhelmingly likely to be used on smalls, + * so we'll specialize those and keep the rest in a shared fragment. */ + if (always_small(RHS)) { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + } else if (always_small(LHS)) { + a.and_(TMP1, rhs.reg, imm(_TAG_IMMED1_MASK)); + } else { + /* Avoid the expensive generic comparison for equal terms. */ + a.cmp(lhs.reg, rhs.reg); + a.b_eq(next); + + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs.reg, rhs.reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + } + + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + a.cmp(lhs.reg, rhs.reg); + a.b(next); + + a.bind(generic); + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + + a.bind(next); + a.b_ge(resolve_beam_label(Fail, disp1MB)); + } +} + +void BeamModuleAssembler::emit_is_ge(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS) { + if (always_small(LHS) && RHS.isSmall() && RHS.isImmed()) { + auto lhs = load_source(LHS, ARG1); + comment("simplified compare because one operand is an immediate small"); + cmp(lhs.reg, RHS.as().get()); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + return; + } else if (LHS.isSmall() && LHS.isImmed() && always_small(RHS)) { + auto rhs = load_source(RHS, ARG1); + comment("simplified compare because one operand is an immediate small"); + cmp(rhs.reg, LHS.as().get()); + a.b_gt(resolve_beam_label(Fail, disp1MB)); + return; + } + + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + a.cmp(lhs.reg, rhs.reg); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + } else if (always_small(LHS) && exact_type(RHS) && + hasLowerBound(RHS)) { + comment("simplified test because it always fails when RHS is a bignum"); + emit_is_not_boxed(resolve_beam_label(Fail, dispUnknown), rhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + } else if (always_small(LHS) && exact_type(RHS) && + hasUpperBound(RHS)) { + Label next = a.newLabel(); + comment("simplified test because it always succeeds when RHS is a " + "bignum"); + emit_is_not_boxed(next, rhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + a.bind(next); + } else if (exact_type(LHS) && hasUpperBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always fails when LHS is a bignum"); + emit_is_not_boxed(resolve_beam_label(Fail, dispUnknown), lhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + } else if (exact_type(LHS) && hasLowerBound(LHS) && + always_small(RHS)) { + Label next = a.newLabel(); + comment("simplified test because it always succeeds when LHS is a " + "bignum"); + emit_is_not_boxed(next, lhs.reg); + a.cmp(lhs.reg, rhs.reg); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + a.bind(next); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + Label branch_compare = a.newLabel(); + + a.cmp(lhs.reg, rhs.reg); + + /* The only possible kind of immediate is a small and all other values + * are boxed, so we can test for smalls by testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_boxed(branch_compare, rhs.reg); + } else if (always_small(RHS)) { + emit_is_boxed(branch_compare, lhs.reg); + } else { + a.and_(TMP1, lhs.reg, rhs.reg); + emit_is_boxed(branch_compare, TMP1); + } + + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + + /* The flags will either be from the initial comparison, or from the + * shared fragment. */ + a.bind(branch_compare); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + } else { + Label generic = a.newLabel(), next = a.newLabel(); + + /* Relative comparisons are overwhelmingly likely to be used on smalls, + * so we'll specialize those and keep the rest in a shared fragment. */ + if (always_small(RHS)) { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + } else if (always_small(LHS)) { + a.and_(TMP1, rhs.reg, imm(_TAG_IMMED1_MASK)); + } else { + /* Avoid the expensive generic comparison for equal terms. */ + a.cmp(lhs.reg, rhs.reg); + a.b_eq(next); + + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs.reg, rhs.reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + } + + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + a.cmp(lhs.reg, rhs.reg); + a.b(next); + + a.bind(generic); + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + + a.bind(next); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + } +} + +/* + * ARG1 = Src + * ARG2 = Min + * ARG3 = Max + * + * Result is returned in the flags. + */ +void BeamGlobalAssembler::emit_is_in_range_shared() { + Label immediate = a.newLabel(), generic_compare = a.newLabel(), + float_done = a.newLabel(), done = a.newLabel(); + + /* Is the source a float? */ + emit_is_boxed(immediate, ARG1); + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, ARG1); + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + + mov_imm(TMP3, HEADER_FLONUM); + a.cmp(TMP2, TMP3); + a.b_ne(generic_compare); + + a.ldur(a64::d0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.asr(TMP1, ARG2, imm(_TAG_IMMED1_SIZE)); + a.scvtf(a64::d1, TMP1); + + a.fcmpe(a64::d0, a64::d1); + a.b_mi(float_done); + + a.asr(TMP1, ARG3, imm(_TAG_IMMED1_SIZE)); + a.scvtf(a64::d1, TMP1); + a.fcmpe(a64::d0, a64::d1); + a.b_gt(float_done); + a.tst(ZERO, ZERO); + + a.bind(float_done); + a.ret(a64::x30); + + a.bind(immediate); + { + /* + * Src is an immediate (such as ATOM) but not SMALL. + * That means that Src must be greater than the upper + * limit. + */ + mov_imm(TMP1, 1); + a.cmp(TMP1, imm(0)); + a.ret(a64::x30); + } + + a.bind(generic_compare); + { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.stp(ARG1, ARG3, TMP_MEM1q); + + comment("erts_cmp_compound(X, Y, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.tst(ARG1, ARG1); + a.b_mi(done); + + a.ldp(ARG1, ARG2, TMP_MEM1q); + + comment("erts_cmp_compound(X, Y, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.tst(ARG1, ARG1); + + a.bind(done); + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); + } +} + +/* + * 1121 occurrences in OTP at the time of writing. + */ +void BeamModuleAssembler::emit_is_in_range(ArgLabel const &Small, + ArgLabel const &Large, + ArgRegister const &Src, + ArgConstant const &Min, + ArgConstant const &Max) { + Label next = a.newLabel(), generic = a.newLabel(); + bool need_generic = true; + auto src = load_source(Src, ARG1); + + if (always_small(Src)) { + need_generic = false; + comment("skipped test for small operand since it always small"); + } else if (always_one_of( + Src)) { + /* The only possible kind of immediate is a small and all + * other values are boxed, so we can test for smalls by + * testing boxed. */ + comment("simplified small test since all other types are boxed"); + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED == (1 << 0)); + if (Small == Large && never_one_of(Src)) { + /* Src is never a float and the failure labels are + * equal. Therefore, since a bignum will never be within + * the range, we can fail immediately if Src is not a + * small. */ + need_generic = false; + a.tbz(src.reg, imm(0), resolve_beam_label(Small, disp32K)); + } else { + /* Src can be a float or the failures labels are distinct. + * We need to call the generic routine if Src is not a small. */ + a.tbz(src.reg, imm(0), generic); + } + } else if (Small == Large) { + /* We can save one instruction if we incorporate the test for + * small into the range check. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + comment("simplified small & range tests since failure labels are " + "equal"); + sub(TMP1, src.reg, Min.as().get()); + + /* Since we have subtracted the (tagged) lower bound, the + * tag bits of the difference is 0 if and only if Src is + * a small. Testing for a tag of 0 can be done in two + * instructions. */ + a.tst(TMP1, imm(_TAG_IMMED1_MASK)); + a.b_ne(generic); + + /* Now do the range check. */ + cmp(TMP1, Max.as().get() - Min.as().get()); + a.b_hi(resolve_beam_label(Small, disp1MB)); + + /* Bypass the test code. */ + goto test_done; + } else { + /* We have no applicable type information and the failure + * labels are distinct. Emit the standard test for small + * and call the generic routine if Src is not a small. */ + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + } + + /* We have now established that the operand is small. */ + if (Small == Large) { + comment("simplified range test since failure labels are equal"); + sub(TMP1, src.reg, Min.as().get()); + cmp(TMP1, Max.as().get() - Min.as().get()); + a.b_hi(resolve_beam_label(Small, disp1MB)); + } else { + cmp(src.reg, Min.as().get()); + a.b_lt(resolve_beam_label(Small, disp1MB)); + cmp(src.reg, Max.as().get()); + a.b_gt(resolve_beam_label(Large, disp1MB)); + } + +test_done: + if (need_generic) { + a.b(next); + } + + a.bind(generic); + if (!need_generic) { + comment("skipped generic comparison because it is not needed"); + } else { + mov_var(ARG1, src); + mov_arg(ARG2, Min); + mov_arg(ARG3, Max); + fragment_call(ga->get_is_in_range_shared()); + if (Small == Large) { + a.b_ne(resolve_beam_label(Small, disp1MB)); + } else { + a.b_lt(resolve_beam_label(Small, disp1MB)); + a.b_gt(resolve_beam_label(Large, disp1MB)); + } + } + + a.bind(next); +} + +/* + * ARG1 = Src + * ARG2 = A + * ARG3 = B + * + * Result is returned in the flags. + */ +void BeamGlobalAssembler::emit_is_ge_lt_shared() { + Label done = a.newLabel(); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.stp(ARG1, ARG3, TMP_MEM1q); + + comment("erts_cmp_compound(Src, A, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.tst(ARG1, ARG1); + a.b_mi(done); + + comment("erts_cmp_compound(B, Src, 0, 0);"); + a.ldp(ARG2, ARG1, TMP_MEM1q); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.cmp(ARG1, imm(0)); + + /* Make sure that ARG1 is -1, 0, or 1. */ + a.cset(ARG1, imm(arm::CondCode::kNE)); + a.csinv(ARG1, ARG1, ZERO, imm(arm::CondCode::kGE)); + + /* Prepare return value and flags. */ + a.adds(ARG1, ARG1, imm(1)); + + /* We now have: + * ARG1 == 0 if B < SRC + * ARG1 > 0 if B => SRC + * and flags set accordingly. */ + + a.bind(done); + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +/* + * The instruction sequence: + * + * is_ge Fail1 Src A + * is_lt Fail1 B Src + * + * is common (1841 occurrences in OTP at the time of writing). + * + * is_ge + is_lt is 18 instructions, while is_ge_lt is + * 14 instructions. + */ +void BeamModuleAssembler::emit_is_ge_lt(ArgLabel const &Fail1, + ArgLabel const &Fail2, + ArgRegister const &Src, + ArgConstant const &A, + ArgConstant const &B) { + Label generic = a.newLabel(), next = a.newLabel(); + auto src = load_source(Src, ARG1); + + mov_arg(ARG2, A); + mov_arg(ARG3, B); + + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + + a.cmp(src.reg, ARG2); + a.b_lt(resolve_beam_label(Fail1, disp1MB)); + a.cmp(ARG3, src.reg); + a.b_ge(resolve_beam_label(Fail2, disp1MB)); + a.b(next); + + a.bind(generic); + mov_var(ARG1, src); + fragment_call(ga->get_is_ge_lt_shared()); + a.b_lt(resolve_beam_label(Fail1, disp1MB)); + a.b_gt(resolve_beam_label(Fail2, disp1MB)); + + a.bind(next); +} + +/* + * 1190 occurrences in OTP at the time of writing. + */ +void BeamModuleAssembler::emit_is_ge_ge(ArgLabel const &Fail1, + ArgLabel const &Fail2, + ArgRegister const &Src, + ArgConstant const &A, + ArgConstant const &B) { + if (!always_small(Src)) { + /* In practice, it is uncommon that Src is not a known small + * integer, so we will not bother optimizing that case. */ + emit_is_ge(Fail1, Src, A); + emit_is_ge(Fail2, Src, B); + return; + } + + auto src = load_source(Src, ARG1); + subs(TMP1, src.reg, A.as().get()); + a.b_lt(resolve_beam_label(Fail1, disp1MB)); + cmp(TMP1, B.as().get() - A.as().get()); + a.b_lo(resolve_beam_label(Fail2, disp1MB)); +} + +/* + * 60 occurrences in OTP at the time of writing. Seems to be common in + * Elixir code. + * + * Currently not very frequent in OTP but very nice reduction in code + * size when it happens. We expect this combination of instructions + * to become more common in the future. + */ +void BeamModuleAssembler::emit_is_int_in_range(ArgLabel const &Fail, + ArgRegister const &Src, + ArgConstant const &Min, + ArgConstant const &Max) { + auto src = load_source(Src, ARG1); + + sub(TMP1, src.reg, Min.as().get()); + + /* Since we have subtracted the (tagged) lower bound, the + * tag bits of the difference is 0 if and only if Src is + * a small. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.tst(TMP1, imm(_TAG_IMMED1_MASK)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + cmp(TMP1, Max.as().get() - Min.as().get()); + a.b_hi(resolve_beam_label(Fail, disp1MB)); +} + +/* + * 428 occurrences in OTP at the time of writing. + */ +void BeamModuleAssembler::emit_is_int_ge(ArgLabel const &Fail, + ArgRegister const &Src, + ArgConstant const &Min) { + auto src = load_source(Src, ARG1); + Label small = a.newLabel(), next = a.newLabel(); + + if (always_one_of(Src)) { + comment("simplified small test since all other types are boxed"); + emit_is_boxed(small, Src, src.reg); + } else { + a.and_(TMP2, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP2, imm(_TAG_IMMED1_SMALL)); + a.b_eq(small); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, TMP2); + } + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_POS_BIG)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + a.b(next); + + a.bind(small); + cmp(src.reg, Min.as().get()); + a.b_lt(resolve_beam_label(Fail, disp1MB)); + + a.bind(next); +} + +void BeamModuleAssembler::emit_badmatch(const ArgSource &Src) { + emit_error(BADMATCH, Src); +} + +void BeamModuleAssembler::emit_case_end(const ArgSource &Src) { + emit_error(EXC_CASE_CLAUSE, Src); +} + +void BeamModuleAssembler::emit_system_limit_body() { + emit_error(SYSTEM_LIMIT); +} + +void BeamModuleAssembler::emit_if_end() { + emit_error(EXC_IF_CLAUSE); +} + +void BeamModuleAssembler::emit_badrecord(const ArgSource &Src) { + emit_error(EXC_BADRECORD, Src); +} + +void BeamModuleAssembler::emit_catch(const ArgYRegister &Y, + const ArgCatch &Handler) { + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + a.add(TMP1, TMP1, imm(1)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + + mov_arg(Y, Handler); +} + +void BeamGlobalAssembler::emit_catch_end_shared() { + Label not_throw = a.newLabel(), not_error = a.newLabel(), + after_gc = a.newLabel(); + + /* XREG0 = THE_NON_VALUE + * XREG1 = error reason/thrown value + * XREG2 = raw stacktrace. + * XREG3 = class + */ + + a.mov(XREG0, XREG1); + a.cmp(XREG3, imm(am_throw)); + + a.b_ne(not_throw); + + /* Return thrown value. */ + a.ret(a64::x30); + + a.bind(not_throw); + { + emit_enter_runtime_frame(); + + a.mov(ARG1, XREG0); + + a.cmp(XREG3, imm(am_error)); + a.b_ne(not_error); + + a.mov(ARG2, XREG0); + a.mov(ARG3, XREG2); + + /* This is an error, attach a stacktrace to the reason. */ + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 2); + emit_enter_runtime(2); + + a.mov(ARG1, c_p); + runtime_call<3>(add_stacktrace); + + emit_leave_runtime(2); + + /* Fall through! */ + } + + /* Error term from exit/1 or stack backtrace from error/{1,2,3} is + * now in ARG1. */ + a.bind(not_error); + { + const int32_t bytes_needed = (3 + S_RESERVED) * sizeof(Eterm); + add(ARG3, HTOP, bytes_needed); + a.cmp(ARG3, E); + + a.b_ls(after_gc); + { + /* Preserve stacktrace / reason. */ + a.mov(XREG0, ARG1); + + mov_imm(ARG4, 1); + a.bl(labels[garbage_collect]); + + a.mov(ARG1, XREG0); + } + a.bind(after_gc); + + a.add(XREG0, HTOP, imm(TAG_PRIMARY_BOXED)); + mov_imm(TMP1, make_arityval(2)); + mov_imm(TMP2, am_EXIT); + a.stp(TMP1, TMP2, arm::Mem(HTOP).post(2 * sizeof(Eterm))); + a.str(ARG1, arm::Mem(HTOP).post(sizeof(Eterm))); + } + + emit_leave_runtime_frame(); + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_catch_end(const ArgYRegister &CatchTag) { + Label next = a.newLabel(); + + /* XREG0 = THE_NON_VALUE + * XREG1 = class + * XREG2 = error reason/thrown value + * XREG3 = raw stacktrace. */ + + emit_try_end(CatchTag); + emit_branch_if_value(XREG0, next); + fragment_call(ga->get_catch_end_shared()); + a.bind(next); +} + +void BeamModuleAssembler::emit_try_end(const ArgYRegister &CatchTag) { + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + a.sub(TMP1, TMP1, imm(1)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + + emit_init(CatchTag); +} + +void BeamModuleAssembler::emit_try_case(const ArgYRegister &CatchTag) { + /* XREG0 = THE_NON_VALUE + * XREG1 = error reason/thrown value + * XREG2 = raw stacktrace. + * XREG3 = class */ + + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + a.mov(XREG0, XREG3); + a.sub(TMP1, TMP1, imm(1)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, catches))); + + /* The try_tag in the Y slot in the stack frame has already been + * cleared. */ + +#ifdef DEBUG + Label ok = a.newLabel(); + comment("Start of assertion code"); + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, fvalue))); + a.ldr(TMP2, arm::Mem(c_p, offsetof(Process, ftrace))); + mov_imm(TMP3, NIL); + a.cmp(TMP1, TMP3); + a.ccmp(TMP2, TMP3, imm(NZCV::kNone), imm(arm::CondCode::kEQ)); + a.b_eq(ok); + + comment("Assertion c_p->fvalue == NIL && c_p->ftrace == NIL failed"); + a.udf(0x42); + + a.bind(ok); +#endif +} + +void BeamModuleAssembler::emit_try_case_end(const ArgSource &Src) { + emit_error(EXC_TRY_CLAUSE, Src); +} + +void BeamModuleAssembler::emit_raise(const ArgSource &Trace, + const ArgSource &Value) { + auto value = load_source(Value, TMP1); + mov_arg(ARG2, Trace); + + /* This is an error, attach a stacktrace to the reason. */ + a.str(value.reg, arm::Mem(c_p, offsetof(Process, fvalue))); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, ftrace))); + + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_sanitize_freason); + + emit_leave_runtime(0); + + emit_raise_exception(); +} + +void BeamModuleAssembler::emit_build_stacktrace() { + a.mov(ARG2, XREG0); + + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<2>(build_stacktrace); + + emit_leave_runtime(0); + + a.mov(XREG0, ARG1); +} + +/* This instruction has the same semantics as the erlang:raise/3 BIF, + * except that it can rethrow a raw stack backtrace. */ +void BeamModuleAssembler::emit_raw_raise() { + Label next = a.newLabel(); + + a.mov(ARG1, XREG2); + a.mov(ARG2, XREG0); + a.mov(ARG3, XREG1); + a.mov(ARG4, c_p); + + emit_enter_runtime(0); + runtime_call<4>(raw_raise); + emit_leave_runtime(0); + + a.cbnz(ARG1, next); + + emit_raise_exception(); + + a.bind(next); + mov_imm(XREG0, am_badarg); +} + +#define TEST_YIELD_RETURN_OFFSET \ + (BEAM_ASM_FUNC_PROLOGUE_SIZE + sizeof(Uint32[3])) + +/* ARG3 = current_label */ +void BeamGlobalAssembler::emit_i_test_yield_shared() { + a.sub(ARG2, ARG3, imm(sizeof(ErtsCodeMFA))); + a.add(ARG3, ARG3, imm(TEST_YIELD_RETURN_OFFSET)); + + a.str(ARG2, arm::Mem(c_p, offsetof(Process, current))); + a.ldr(ARG2, arm::Mem(ARG2, offsetof(ErtsCodeMFA, arity))); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, arity))); + + a.b(labels[context_switch_simplified]); +} + +void BeamModuleAssembler::emit_i_test_yield() { + /* When present, this is guaranteed to be the first instruction after the + * breakpoint trampoline. */ + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + BEAM_ASM_FUNC_PROLOGUE_SIZE); + + a.adr(ARG3, current_label); + a.subs(FCALLS, FCALLS, imm(1)); + a.b_le(resolve_fragment(ga->get_i_test_yield_shared(), disp1MB)); + + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + TEST_YIELD_RETURN_OFFSET); +} + +void BeamModuleAssembler::emit_i_yield() { + mov_imm(XREG0, am_true); + fragment_call(ga->get_dispatch_return()); +} + +void BeamModuleAssembler::emit_i_perf_counter() { + Label next = a.newLabel(), small = a.newLabel(); + + emit_enter_runtime_frame(); + runtime_call<0>(erts_sys_time_data__.r.o.perf_counter); + emit_leave_runtime_frame(); + + a.asr(TMP1, ARG1, imm(SMALL_BITS - 1)); + a.add(TMP1, TMP1, imm(1)); + a.cmp(TMP1, imm(1)); + a.b_ls(small); + + { + a.mov(XREG0, ARG1); + + emit_gc_test(ArgWord(0), + ArgWord(ERTS_MAX_UINT64_HEAP_SIZE), + ArgWord(0)); + + mov_imm(TMP1, make_pos_bignum_header(1)); + a.stp(TMP1, XREG0, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + a.sub(XREG0, HTOP, imm(sizeof(Eterm[2]) - TAG_PRIMARY_BOXED)); + a.b(next); + } + + a.bind(small); + { + a.lsl(ARG1, ARG1, imm(_TAG_IMMED1_SIZE)); + a.orr(XREG0, ARG1, imm(_TAG_IMMED1_SMALL)); + } + + a.bind(next); +} diff --git a/erts/emulator/beam/jit/arm/instr_float.cpp b/erts/emulator/beam/jit/arm/instr_float.cpp new file mode 100644 index 000000000000..9cb910bff77b --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_float.cpp @@ -0,0 +1,230 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "big.h" +} + +/* Checks whether d0 contains a finite value. + * + * Clobbers d30 and d31. */ +void BeamGlobalAssembler::emit_check_float_error() { + Label double_max = a.newLabel(), error = a.newLabel(); + + a.fabs(a64::d30, a64::d0); + a.ldr(a64::d31, arm::Mem(double_max)); + a.fcmp(a64::d30, a64::d31); + a.b_hi(error); + a.ret(a64::x30); + + a.align(AlignMode::kCode, 8); + a.bind(double_max); + a.embedUInt64(0x7FEFFFFFFFFFFFFFul); + + a.bind(error); + { + mov_imm(ARG4, 0); + mov_imm(TMP1, EXC_BADARITH); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_float_instr(uint32_t instId, + const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + auto lhs = load_source(LHS, a64::d0); + auto rhs = load_source(RHS, a64::d1); + auto dst = init_destination(Dst, a64::d2); + + a.emit(instId, a64::d0, lhs.reg, rhs.reg); + fragment_call(ga->get_check_float_error()); + a.mov(dst.reg, a64::d0); + flush_var(dst); +} + +/* * * * */ + +void BeamModuleAssembler::emit_fload(const ArgSource &Src, + const ArgFRegister &Dst) { + auto src = load_source(Src, TMP1); + auto dst = init_destination(Dst, a64::d0); + arm::Gp float_ptr = emit_ptr_val(TMP1, src.reg); + + a.ldur(dst.reg, emit_boxed_val(float_ptr, sizeof(Eterm))); + flush_var(dst); +} + +void BeamModuleAssembler::emit_fstore(const ArgFRegister &Src, + const ArgRegister &Dst) { + auto src = load_source(Src, a64::d0); + auto dst = init_destination(Dst, TMP1); + + a.add(dst.reg, HTOP, imm(TAG_PRIMARY_BOXED)); + + mov_imm(TMP2, HEADER_FLONUM); + a.str(TMP2, arm::Mem(HTOP).post(sizeof(Eterm))); + a.str(src.reg, arm::Mem(HTOP).post(sizeof(Eterm))); + + flush_var(dst); +} + +/* ARG1 = source term */ +void BeamGlobalAssembler::emit_fconv_shared() { + Label error = a.newLabel(); + + /* Is the source a bignum? */ + { + emit_is_boxed(error, ARG1); + + emit_untag_ptr(TMP1, ARG1); + a.ldr(TMP1, arm::Mem(TMP1)); + + /* The mask (0b111011) cannot be encoded as an immediate operand for + * 'and'. */ + mov_imm(TMP2, _TAG_HEADER_MASK - _BIG_SIGN_BIT); + a.and_(TMP2, TMP1, TMP2); + a.cmp(TMP2, imm(_TAG_HEADER_POS_BIG)); + a.b_ne(error); + } + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + /* ARG1 already contains the source term. */ + lea(ARG2, TMP_MEM1q); + runtime_call<2>(big_to_double); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.tbnz(ARG1.w(), imm(31), error); + + a.ldr(a64::d0, TMP_MEM1q); + a.ret(a64::x30); + + a.bind(error); + { + mov_imm(ARG4, 0); + mov_imm(TMP1, EXC_BADARITH); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_fconv(const ArgSource &Src, + const ArgFRegister &Dst) { + auto dst = init_destination(Dst, a64::d0); + auto src = load_source(Src, ARG1); + + if (always_small(Src)) { + comment("skipped test for small operand since it is always small"); + a.asr(TMP1, src.reg, imm(_TAG_IMMED1_SIZE)); + a.scvtf(dst.reg, TMP1); + flush_var(dst); + return; + } + + Label next = a.newLabel(), not_small = a.newLabel(), + fallback = a.newLabel(); + + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_MASK)); + a.b_ne(not_small); + + a.asr(TMP1, src.reg, imm(_TAG_IMMED1_SIZE)); + a.scvtf(dst.reg, TMP1); + a.b(next); + + a.bind(not_small); + { + if (never_one_of(Src)) { + comment("skipped float path since source cannot be a float"); + } else { + /* If the source is always a number, we can skip the box test when + * it's not a small. */ + if (always_one_of(Src)) { + comment("skipped box test since source is always a number"); + } else { + emit_is_boxed(fallback, Src, src.reg); + } + + emit_untag_ptr(TMP1, src.reg); + + /* Speculatively load the float value, this is safe since all boxed + * terms are at least two words long. */ + a.ldr(dst.reg, arm::Mem(TMP1, sizeof(Eterm))); + + a.ldr(TMP1, arm::Mem(TMP1)); + a.cmp(TMP1, imm(HEADER_FLONUM)); + a.b_eq(next); + } + + a.bind(fallback); + { + mov_var(ARG1, src); + fragment_call(ga->get_fconv_shared()); + mov_var(dst, a64::d0); + } + } + + a.bind(next); + flush_var(dst); +} + +void BeamModuleAssembler::emit_i_fadd(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(a64::Inst::kIdFadd_v, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_i_fsub(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(a64::Inst::kIdFsub_v, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_i_fmul(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(a64::Inst::kIdFmul_v, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_i_fdiv(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(a64::Inst::kIdFdiv_v, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_i_fnegate(const ArgFRegister &Src, + const ArgFRegister &Dst) { + auto src = load_source(Src, a64::d0); + auto dst = init_destination(Dst, a64::d1); + + /* Note that there is no need to check for errors since flipping the sign + * of a finite float is guaranteed to produce a finite float. */ + a.fneg(a64::d0, src.reg); + a.mov(dst.reg, a64::d0); + flush_var(dst); +} diff --git a/erts/emulator/beam/jit/arm/instr_fun.cpp b/erts/emulator/beam/jit/arm/instr_fun.cpp new file mode 100644 index 000000000000..f2e0792f26d0 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_fun.cpp @@ -0,0 +1,466 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021-2023. 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% + */ + +#include "beam_asm.hpp" + +/* Calls to functions that are being purged (but haven't finished) land here. + * + * Keep in mind that this runs in the limbo between caller and callee. It must + * not clobber LR (x30). + * + * ARG3 = arity + * ARG4 = fun thing + * ARG5 = address of the call_fun instruction that got us here. Note that we + * can't use LR (x30) for this because tail calls point elsewhere. */ +void BeamGlobalAssembler::emit_unloaded_fun() { + Label error = a.newLabel(); + + a.str(ARG5, TMP_MEM1q); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + /* ARG3 and ARG4 have already been set. */ + runtime_call<4>(beam_jit_handle_unloaded_fun); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.cbz(ARG1, error); + + a.ldr(TMP1, emit_setup_dispatchable_call(ARG1)); + a.br(TMP1); + + a.bind(error); + { + a.ldr(ARG2, TMP_MEM1q); + mov_imm(ARG4, nullptr); + a.b(labels[raise_exception_shared]); + } +} + +/* Handles errors for `call_fun`. Assumes that we're running on the Erlang + * stack with a valid stack frame. + * + * ARG3 = arity + * ARG4 = fun thing + * ARG5 = address of the call_fun instruction that got us here. Note that we + * can't use LR (x30) for this because tail calls point elsewhere. */ +void BeamGlobalAssembler::emit_handle_call_fun_error() { + Label bad_arity = a.newLabel(), bad_fun = a.newLabel(); + + emit_is_boxed(bad_fun, ARG4); + + arm::Gp fun_thing = emit_ptr_val(TMP1, ARG4); + a.ldur(TMP1, emit_boxed_val(fun_thing)); + a.cmp(TMP1, imm(HEADER_FUN)); + a.b_eq(bad_arity); + + a.bind(bad_fun); + { + mov_imm(TMP1, EXC_BADFUN); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ARG4, arm::Mem(c_p, offsetof(Process, fvalue))); + + a.mov(ARG2, ARG5); + mov_imm(ARG4, nullptr); + a.b(labels[raise_exception_shared]); + } + + a.bind(bad_arity); + { + a.stp(ARG4, ARG5, TMP_MEM1q); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + /* ARG3 is already set */ + runtime_call<3>(beam_jit_build_argument_list); + + emit_leave_runtime(); + + a.ldr(XREG0, TMP_MEM1q); + a.mov(XREG1, ARG1); + + /* Create the {Fun, Args} tuple. */ + { + const int32_t bytes_needed = (3 + S_RESERVED) * sizeof(Eterm); + Label after_gc = a.newLabel(); + + add(ARG3, HTOP, bytes_needed); + a.cmp(ARG3, E); + a.b_ls(after_gc); + { + mov_imm(ARG4, 2); + a.bl(labels[garbage_collect]); + } + a.bind(after_gc); + + a.add(ARG1, HTOP, imm(TAG_PRIMARY_BOXED)); + + mov_imm(TMP1, make_arityval(2)); + a.str(TMP1, arm::Mem(HTOP).post(sizeof(Eterm))); + a.stp(XREG0, XREG1, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } + + a.mov(TMP1, imm(EXC_BADARITY)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ARG1, arm::Mem(c_p, offsetof(Process, fvalue))); + + a.ldr(ARG2, TMP_MEM2q); + mov_imm(ARG4, nullptr); + a.b(labels[raise_exception_shared]); + } +} + +/* Handles save_calls for local funs, which is a side-effect of our calling + * convention. Fun entry is in ARG1. + * + * When the active code index is ERTS_SAVE_CALLS_CODE_IX, all local fun calls + * will land here. */ +void BeamGlobalAssembler::emit_dispatch_save_calls_fun() { + /* Keep going with the actual code index. */ + a.mov(TMP1, imm(&the_active_code_index)); + a.ldr(TMP1.w(), arm::Mem(TMP1)); + + branch(emit_setup_dispatchable_call(ARG1, TMP1)); +} + +/* `call_fun` instructions land here to set up their environment before jumping + * to the actual implementation. + * + * Keep in mind that this runs in the limbo between caller and callee. It must + * not clobber LR (x30). + * + * ARG4 = fun thing */ +void BeamModuleAssembler::emit_i_lambda_trampoline(const ArgLambda &Lambda, + const ArgLabel &Lbl, + const ArgWord &Arity, + const ArgWord &NumFree) { + const ssize_t env_offset = offsetof(ErlFunThing, env) - TAG_PRIMARY_BOXED; + const ssize_t fun_arity = Arity.get() - NumFree.get(); + const ssize_t total_arity = Arity.get(); + + const auto &lambda = lambdas[Lambda.get()]; + a.bind(lambda.trampoline); + + if (NumFree.get() == 1) { + auto first = init_destination(ArgXRegister(fun_arity), TMP1); + + /* Don't bother untagging when there's only a single element, it's + * guaranteed to be within range of LDUR. */ + emit_ptr_val(ARG4, ARG4); + a.ldur(first.reg, arm::Mem(ARG4, env_offset)); + flush_var(first); + } else if (NumFree.get() >= 2) { + ssize_t i; + + emit_ptr_val(ARG4, ARG4); + a.add(ARG4, ARG4, imm(env_offset)); + + for (i = fun_arity; i < total_arity - 1; i += 2) { + auto first = init_destination(ArgXRegister(i), TMP1); + auto second = init_destination(ArgXRegister(i + 1), TMP2); + + a.ldp(first.reg, second.reg, arm::Mem(ARG4).post(sizeof(Eterm[2]))); + flush_vars(first, second); + } + + if (i < total_arity) { + auto last = init_destination(ArgXRegister(i), TMP1); + a.ldr(last.reg, arm::Mem(ARG4)); + flush_var(last); + } + } + + a.b(resolve_beam_label(Lbl, disp128MB)); +} + +void BeamModuleAssembler::emit_i_make_fun3(const ArgLambda &Lambda, + const ArgRegister &Dst, + const ArgWord &Arity, + const ArgWord &NumFree, + const Span &env) { + const ssize_t num_free = NumFree.get(); + ssize_t i; + + ASSERT(num_free == env.size()); + + a.mov(ARG1, c_p); + mov_arg(ARG2, Lambda); + mov_arg(ARG3, Arity); + mov_arg(ARG4, NumFree); + + emit_enter_runtime(); + + runtime_call<4>(erts_new_local_fun_thing); + + emit_leave_runtime(); + + if (num_free) { + comment("Move fun environment"); + } + + for (i = 0; i < num_free - 1; i += 2) { + ssize_t offset = offsetof(ErlFunThing, env) + i * sizeof(Eterm); + + if ((i % 128) == 0) { + check_pending_stubs(); + } + + auto [first, second] = load_sources(env[i], TMP1, env[i + 1], TMP2); + safe_stp(first.reg, second.reg, arm::Mem(ARG1, offset)); + } + + if (i < num_free) { + ssize_t offset = offsetof(ErlFunThing, env) + i * sizeof(Eterm); + mov_arg(arm::Mem(ARG1, offset), env[i]); + } + + comment("Create boxed ptr"); + auto dst = init_destination(Dst, TMP1); + a.orr(dst.reg, ARG1, imm(TAG_PRIMARY_BOXED)); + flush_var(dst); +} + +void BeamGlobalAssembler::emit_apply_fun_shared() { + Label finished = a.newLabel(); + + /* Put the arity and fun into the right registers for `call_fun`, and stash + * the argument list in ARG5 for the error path. We'll bump the arity as + * we go through the argument list. */ + mov_imm(ARG3, 0); + a.mov(ARG4, XREG0); + a.mov(ARG5, XREG1); + + { + Label unpack_next = a.newLabel(), malformed_list = a.newLabel(), + raise_error = a.newLabel(); + + /* apply/2 is rarely used on a hot code path, so we'll simplify things + * by switching to the runtime environment where we can operate + * entirely on the X register array. + * + * Note that we don't have any live registers at this point. */ + emit_enter_runtime(0); + + a.mov(TMP1, ARG5); + lea(TMP2, getXRef(0)); + + a.bind(unpack_next); + { + a.cmp(TMP1, imm(NIL)); + a.b_eq(finished); + + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST == (1 << 1)); + a.tbnz(TMP1, imm(1), malformed_list); + + emit_ptr_val(TMP1, TMP1); + a.sub(TMP1, TMP1, imm(TAG_PRIMARY_LIST)); + a.ldp(TMP3, TMP1, arm::Mem(TMP1)); + a.str(TMP3, arm::Mem(TMP2).post(sizeof(Eterm))); + + /* We bail at MAX_REG-1 rather than MAX_REG as the highest register + * is reserved for the loader. */ + a.add(ARG3, ARG3, imm(1)); + a.cmp(ARG3, imm(MAX_REG - 1)); + a.b_lo(unpack_next); + } + + a.mov(TMP1, imm(SYSTEM_LIMIT)); + a.b(raise_error); + + a.bind(malformed_list); + a.mov(TMP1, imm(BADARG)); + + a.bind(raise_error); + { + static const ErtsCodeMFA apply_mfa = {am_erlang, am_apply, 2}; + + emit_leave_runtime(0); + + a.mov(XREG0, ARG4); + a.mov(XREG1, ARG5); + + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + mov_imm(ARG4, &apply_mfa); + a.b(labels[raise_exception]); + } + } + + a.bind(finished); + { + emit_leave_runtime(); + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_i_apply_fun() { + fragment_call(ga->get_apply_fun_shared()); + erlang_call(emit_call_fun()); +} + +void BeamModuleAssembler::emit_i_apply_fun_last(const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + emit_i_apply_fun_only(); +} + +void BeamModuleAssembler::emit_i_apply_fun_only() { + fragment_call(ga->get_apply_fun_shared()); + emit_leave_erlang_frame(); + a.br(emit_call_fun()); +} + +/* Assumes that: + * ARG3 = arity + * ARG4 = fun thing */ +arm::Gp BeamModuleAssembler::emit_call_fun(bool skip_box_test, + bool skip_fun_test, + bool skip_arity_test) { + const bool never_fails = skip_box_test && skip_fun_test && skip_arity_test; + Label next = a.newLabel(); + + /* Speculatively untag the ErlFunThing. */ + emit_untag_ptr(TMP2, ARG4); + + if (!never_fails) { + /* Load the error fragment into TMP3 so we can CSEL ourselves there on + * error. */ + a.adr(TMP3, resolve_fragment(ga->get_handle_call_fun_error(), disp1MB)); + } + + /* The `handle_call_fun_error` and `unloaded_fun` fragments expect current + * PC in ARG5. */ + a.adr(ARG5, next); + + if (!skip_box_test) { + /* As emit_is_boxed(), but explicitly sets ZF so we can rely on that + * for error checking in `next`. */ + a.tst(ARG4, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + a.b_ne(next); + } else { + comment("skipped box test since source is always boxed"); + } + + if (!skip_fun_test) { + /* Load header word and `ErlFunThing->entry`. We can safely do this + * before testing the header because boxed terms are guaranteed to be + * at least two words long. */ + ERTS_CT_ASSERT_FIELD_PAIR(ErlFunThing, thing_word, entry); + a.ldp(TMP1, ARG1, arm::Mem(TMP2)); + + a.cmp(TMP1, imm(HEADER_FUN)); + a.b_ne(next); + } else { + comment("skipped fun test since source is always a fun when boxed"); + a.ldr(ARG1, arm::Mem(TMP2, offsetof(ErlFunThing, entry))); + } + + if (!skip_arity_test) { + a.ldrb(TMP2.w(), arm::Mem(TMP2, offsetof(ErlFunThing, arity))); + a.cmp(TMP2, ARG3); + } else { + comment("skipped arity test since source always has right arity"); + } + + a.ldr(TMP1, emit_setup_dispatchable_call(ARG1)); + + /* Assumes that ZF is set on success and clear on error, overwriting our + * destination with the error fragment's address. */ + a.bind(next); + + if (!never_fails) { + a.csel(TMP1, TMP1, TMP3, imm(arm::CondCode::kEQ)); + } + + return TMP1; +} + +void BeamModuleAssembler::emit_i_call_fun2(const ArgVal &Tag, + const ArgWord &Arity, + const ArgRegister &Func) { + mov_arg(ARG4, Func); + + if (Tag.isAtom()) { + mov_imm(ARG3, Arity.get()); + + auto target = emit_call_fun( + always_one_of(Func), + masked_types(Func) == BeamTypeId::Fun, + Tag.as().get() == am_safe); + + erlang_call(target); + } else { + const auto &trampoline = lambdas[Tag.as().get()].trampoline; + erlang_call(resolve_label(trampoline, disp128MB)); + } +} + +void BeamModuleAssembler::emit_i_call_fun2_last(const ArgVal &Tag, + const ArgWord &Arity, + const ArgRegister &Func, + const ArgWord &Deallocate) { + mov_arg(ARG4, Func); + + if (Tag.isAtom()) { + mov_imm(ARG3, Arity.get()); + + auto target = emit_call_fun( + always_one_of(Func), + masked_types(Func) == BeamTypeId::Fun, + Tag.as().get() == am_safe); + + emit_deallocate(Deallocate); + emit_leave_erlang_frame(); + + a.br(target); + } else { + emit_deallocate(Deallocate); + emit_leave_erlang_frame(); + + const auto &trampoline = lambdas[Tag.as().get()].trampoline; + a.b(resolve_label(trampoline, disp128MB)); + } +} + +void BeamModuleAssembler::emit_i_call_fun(const ArgWord &Arity) { + const ArgXRegister Func(Arity.get()); + const ArgAtom Tag(am_unsafe); + + emit_i_call_fun2(Tag, Arity, Func); +} + +void BeamModuleAssembler::emit_i_call_fun_last(const ArgWord &Arity, + const ArgWord &Deallocate) { + const ArgXRegister Func(Arity.get()); + const ArgAtom Tag(am_unsafe); + + emit_i_call_fun2_last(Tag, Arity, Func, Deallocate); +} + +/* Psuedo-instruction for signalling lambda load errors. Never actually runs. */ +void BeamModuleAssembler::emit_i_lambda_error(const ArgWord &Dummy) { + emit_nyi("emit_i_lambda_error"); +} diff --git a/erts/emulator/beam/jit/arm/instr_guard_bifs.cpp b/erts/emulator/beam/jit/arm/instr_guard_bifs.cpp new file mode 100644 index 000000000000..c24ca4831f08 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_guard_bifs.cpp @@ -0,0 +1,1365 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +/* + * Guard BIF calls using the generic bif1, bif2, and bif3 instructions + * are expensive. Not only are there two indirect calls (one to the + * fragment, one to the BIF itself), but the caller-saved X registers + * must also be saved and restored, and the BIF operands that are + * usually in CPU registers must be written out to memory. + * + * Therefore, guard BIFs that are used fairly frequently and can + * be implemented entirely in assembly language without any calls to + * C function are implemented in this source file. + */ + +#include +#include +#include "beam_asm.hpp" + +extern "C" +{ +#include "erl_bif_table.h" +#include "big.h" +#include "beam_catches.h" +#include "beam_common.h" +#include "code_ix.h" +#include "erl_map.h" +} + +using namespace asmjit; + +/* Raise a badarg exception for the given MFA. */ +void BeamGlobalAssembler::emit_raise_badarg(const ErtsCodeMFA *mfa) { + mov_imm(TMP1, BADARG); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + mov_imm(ARG4, mfa); + a.b(labels[raise_exception]); +} + +/* ================================================================ + * '=:='/2 + * '=/='/2 + * '>='/2 + * '<'/2 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_bif_is_eq_exact_shared() { + Label succ = a.newLabel(), fail = a.newLabel(); + + a.cmp(ARG1, ARG2); + a.b_eq(succ); + + /* The terms could still be equal if both operands are pointers + * having the same tag. */ + emit_is_unequal_based_on_tags(ARG1, ARG2); + a.b_eq(fail); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + runtime_call<2>(eq); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.cbz(ARG1, fail); + + a.bind(succ); + { + mov_imm(ARG1, am_true); + a.ret(a64::x30); + } + + a.bind(fail); + { + mov_imm(ARG1, am_false); + a.ret(a64::x30); + } +} + +void BeamGlobalAssembler::emit_bif_is_ne_exact_shared() { + Label succ = a.newLabel(), fail = a.newLabel(); + + a.cmp(ARG1, ARG2); + a.b_eq(fail); + + emit_is_unequal_based_on_tags(ARG1, ARG2); + a.b_eq(succ); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + runtime_call<2>(eq); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.cbnz(ARG1, fail); + + a.bind(succ); + { + mov_imm(ARG1, am_true); + a.ret(a64::x30); + } + + a.bind(fail); + { + mov_imm(ARG1, am_false); + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_cond_to_bool(arm::CondCode cc, + const ArgRegister &Dst) { + auto dst = init_destination(Dst, TMP2); + + mov_imm(TMP3, am_true); + mov_imm(TMP4, am_false); + a.csel(dst.reg, TMP3, TMP4, cc); + flush_var(dst); +} + +void BeamModuleAssembler::emit_cmp_immed_to_bool(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (RHS.isImmed()) { + auto lhs = load_source(LHS, TMP1); + cmp_arg(lhs.reg, RHS); + } else { + auto [lhs, rhs] = load_sources(LHS, TMP1, RHS, TMP2); + a.cmp(lhs.reg, rhs.reg); + } + emit_cond_to_bool(cc, Dst); +} + +void BeamModuleAssembler::emit_bif_is_eq_exact(const ArgRegister &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_immediate(LHS) || always_immediate(RHS)) { + if (!LHS.isImmed() && !RHS.isImmed()) { + comment("simplified check since one argument is an immediate"); + } + emit_cmp_immed_to_bool(arm::CondCode::kEQ, LHS, RHS, Dst); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + auto dst = init_destination(Dst, ARG1); + + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_bif_is_eq_exact_shared()); + mov_var(dst, ARG1); + flush_var(dst); + } +} + +void BeamModuleAssembler::emit_bif_is_ne_exact(const ArgRegister &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_immediate(LHS) || always_immediate(RHS)) { + if (!LHS.isImmed() && !RHS.isImmed()) { + comment("simplified check since one argument is an immediate"); + } + emit_cmp_immed_to_bool(arm::CondCode::kNE, LHS, RHS, Dst); + } else { + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + auto dst = init_destination(Dst, ARG1); + + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_bif_is_ne_exact_shared()); + mov_var(dst, ARG1); + flush_var(dst); + } +} + +void BeamModuleAssembler::emit_bif_is_ge_lt(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + + Label generic = a.newLabel(), next = a.newLabel(); + + if (always_one_of(LHS) && + always_one_of(RHS)) { + /* The only possible kind of immediate is a small and all + * other values are boxed, so we can test for smalls by + * testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_not_boxed(generic, rhs.reg); + } else if (always_small(RHS)) { + emit_is_not_boxed(generic, lhs.reg); + } else { + a.and_(TMP1, lhs.reg, rhs.reg); + emit_is_not_boxed(generic, TMP1); + } + } else { + /* Relative comparisons are overwhelmingly likely to be used + * on smalls, so we'll specialize those and keep the rest in a + * shared fragment. */ + if (always_small(RHS)) { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + } else if (always_small(LHS)) { + a.and_(TMP1, rhs.reg, imm(_TAG_IMMED1_MASK)); + } else { + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs.reg, rhs.reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + } + + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + } + + a.cmp(lhs.reg, rhs.reg); + a.b(next); + + a.bind(generic); + { + a.cmp(lhs.reg, rhs.reg); + a.b_eq(next); + + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + } + + a.bind(next); + emit_cond_to_bool(cc, Dst); +} + +void BeamModuleAssembler::emit_bif_is_ge(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_small(LHS) && RHS.isSmall() && RHS.isImmed()) { + auto lhs = load_source(LHS, ARG1); + + comment("simplified compare because one operand is an immediate small"); + cmp(lhs.reg, RHS.as().get()); + emit_cond_to_bool(arm::CondCode::kGE, Dst); + + return; + } else if (LHS.isSmall() && LHS.isImmed() && always_small(RHS)) { + auto rhs = load_source(RHS, ARG1); + + comment("simplified compare because one operand is an immediate small"); + cmp(rhs.reg, LHS.as().get()); + emit_cond_to_bool(arm::CondCode::kLE, Dst); + + return; + } + + emit_bif_is_ge_lt(arm::CondCode::kGE, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_bif_is_lt(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_is_ge_lt(arm::CondCode::kLT, LHS, RHS, Dst); +} + +/* ================================================================ + * and/2 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_and_error() { + static ErtsCodeMFA mfa = {am_erlang, am_and, 2}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_and(const ArgLabel &Fail, + const ArgSource &Src1, + const ArgSource &Src2, + const ArgRegister &Dst) { + static const Uint diff_bit = am_true - am_false; + Label next = a.newLabel(); + + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + auto dst = init_destination(Dst, TMP3); + + ERTS_CT_ASSERT(am_false == make_atom(0)); + ERTS_CT_ASSERT(am_true == make_atom(1)); + + if (exact_type(Src1) && + exact_type(Src2)) { + comment("simplified type check because operands are atoms"); + a.orr(TMP3, src1.reg, src2.reg); + a.tst(TMP3, imm(-1ull << (_TAG_IMMED2_SIZE + 1))); + } else { + a.and_(TMP3, src1.reg, imm(_TAG_IMMED2_MASK | ~diff_bit)); + a.and_(TMP4, src2.reg, imm(_TAG_IMMED2_MASK | ~diff_bit)); + a.cmp(TMP3, imm(_TAG_IMMED2_ATOM)); + a.ccmp(TMP3, TMP4, imm(NZCV::kNone), imm(arm::CondCode::kEQ)); + } + + if (Fail.get()) { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + a.b_eq(next); + mov_var(XREG0, src1); + mov_var(XREG1, src2); + fragment_call(ga->get_handle_or_error()); + } + + a.bind(next); + { + a.and_(dst.reg, src1.reg, src2.reg); + flush_var(dst); + } +} + +/* ================================================================ + * bit_size/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_bif_bit_size_helper(Label fail) { + Label not_sub_bin = a.newLabel(); + arm::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + + emit_is_boxed(fail, boxed_ptr); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_SUB_BIN)); + a.b_ne(not_sub_bin); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.ldurb(TMP2.w(), emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + + mov_imm(ARG1, _TAG_IMMED1_SMALL); + a.add(TMP1, TMP2, TMP1, arm::lsl(3)); + a.bfi(ARG1, TMP1, imm(_TAG_IMMED1_SIZE), imm(SMALL_BITS)); + a.ret(a64::x30); + + a.bind(not_sub_bin); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(TMP1, TMP1, imm(~4)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(fail); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + mov_imm(ARG1, _TAG_IMMED1_SMALL); + a.bfi(ARG1, TMP1, imm(_TAG_IMMED1_SIZE + 3), imm(SMALL_BITS - 3)); + + a.ret(a64::x30); +} + +void BeamGlobalAssembler::emit_bif_bit_size_body() { + Label error = a.newLabel(); + + emit_bif_bit_size_helper(error); + + a.bind(error); + { + static ErtsCodeMFA mfa = {am_erlang, am_bit_size, 1}; + a.mov(XREG0, ARG1); + emit_raise_badarg(&mfa); + } +} + +void BeamGlobalAssembler::emit_bif_bit_size_guard() { + Label error = a.newLabel(); + + emit_bif_bit_size_helper(error); + + a.bind(error); + { + mov_imm(ARG1, THE_NON_VALUE); + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_bif_bit_size(const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + auto src = load_source(Src, ARG1); + auto dst = init_destination(Dst, ARG1); + + if (exact_type(Src)) { + Label not_sub_bin = a.newLabel(); + arm::Gp boxed_ptr = emit_ptr_val(ARG1, src.reg); + auto unit = getSizeUnit(Src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + + if (is_bitstring) { + comment("inlined bit_size/1 because " + "its argument is a bitstring"); + } else { + comment("inlined and simplified bit_size/1 because " + "its argument is a binary"); + } + + if (is_bitstring) { + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + } + + a.ldur(TMP2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.lsl(TMP2, TMP2, imm(_TAG_IMMED1_SIZE + 3)); + + if (is_bitstring) { + const int bit_number = 3; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & (1 << bit_number)) != 0 && + (_TAG_HEADER_REFC_BIN & (1 << bit_number)) == 0 && + (_TAG_HEADER_HEAP_BIN & (1 << bit_number)) == 0); + a.tbz(TMP1, imm(bit_number), not_sub_bin); + + a.ldurb(TMP1.w(), + emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + a.add(TMP2, TMP2, TMP1, imm(_TAG_IMMED1_SIZE)); + } + + a.bind(not_sub_bin); + a.orr(dst.reg, TMP2, _TAG_IMMED1_SMALL); + } else { + mov_var(ARG1, src); + + if (Fail.get() == 0) { + fragment_call(ga->get_bif_bit_size_body()); + } else { + fragment_call(ga->get_bif_bit_size_guard()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } + mov_var(dst, ARG1); + } + + flush_var(dst); +} + +/* ================================================================ + * byte_size/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_bif_byte_size_helper(Label fail) { + Label not_sub_bin = a.newLabel(); + arm::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + + emit_is_boxed(fail, boxed_ptr); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_SUB_BIN)); + a.b_ne(not_sub_bin); + + a.ldurb(TMP2.w(), emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.cmp(TMP2, imm(0)); + a.cinc(TMP1, TMP1, arm::CondCode::kNE); + + mov_imm(ARG1, _TAG_IMMED1_SMALL); + a.bfi(ARG1, TMP1, imm(_TAG_IMMED1_SIZE), imm(SMALL_BITS)); + a.ret(a64::x30); + + a.bind(not_sub_bin); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(TMP1, TMP1, imm(~4)); + a.cmp(TMP1, imm(_TAG_HEADER_REFC_BIN)); + a.b_ne(fail); + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + mov_imm(ARG1, _TAG_IMMED1_SMALL); + a.bfi(ARG1, TMP1, imm(_TAG_IMMED1_SIZE), imm(SMALL_BITS)); + + a.ret(a64::x30); +} + +void BeamGlobalAssembler::emit_bif_byte_size_body() { + Label error = a.newLabel(); + + emit_bif_byte_size_helper(error); + + a.bind(error); + { + static ErtsCodeMFA mfa = {am_erlang, am_byte_size, 1}; + a.mov(XREG0, ARG1); + emit_raise_badarg(&mfa); + } +} + +void BeamGlobalAssembler::emit_bif_byte_size_guard() { + Label error = a.newLabel(); + + emit_bif_byte_size_helper(error); + + a.bind(error); + { + mov_imm(ARG1, THE_NON_VALUE); + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_bif_byte_size(const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + auto src = load_source(Src, ARG1); + auto dst = init_destination(Dst, ARG1); + + if (exact_type(Src)) { + Label not_sub_bin = a.newLabel(); + arm::Gp boxed_ptr = emit_ptr_val(ARG1, src.reg); + auto unit = getSizeUnit(Src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + + if (is_bitstring) { + comment("inlined byte_size/1 because " + "its argument is a bitstring"); + } else { + comment("inlined and simplified byte_size/1 because " + "its argument is a binary"); + } + + if (is_bitstring) { + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + } + + a.ldur(TMP2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + + if (is_bitstring) { + const int bit_number = 3; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & (1 << bit_number)) != 0 && + (_TAG_HEADER_REFC_BIN & (1 << bit_number)) == 0 && + (_TAG_HEADER_HEAP_BIN & (1 << bit_number)) == 0); + a.tbz(TMP1, imm(bit_number), not_sub_bin); + + a.ldurb(TMP1.w(), + emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize))); + a.cmp(TMP1.w(), imm(0)); + a.cinc(TMP2, TMP2, arm::CondCode::kNE); + } + + a.bind(not_sub_bin); + mov_imm(dst.reg, _TAG_IMMED1_SMALL); + a.bfi(dst.reg, TMP2, imm(_TAG_IMMED1_SIZE), imm(SMALL_BITS)); + } else { + mov_var(ARG1, src); + + if (Fail.get() == 0) { + fragment_call(ga->get_bif_byte_size_body()); + } else { + fragment_call(ga->get_bif_byte_size_guard()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } + mov_var(dst, ARG1); + } + + flush_var(dst); +} + +/* ================================================================ + * element/2 + * ================================================================ + */ + +/* ARG1 = Position (1-based) + * ARG2 = Tuple + * + * Will return the result in ARG1, or jump to the label `fail` if + * the operation fails. + */ +void BeamGlobalAssembler::emit_bif_element_helper(Label fail) { + a.and_(TMP1, ARG1, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(fail); + + /* Ensure that ARG2 contains a tuple. */ + emit_is_boxed(fail, ARG2); + arm::Gp boxed_ptr = emit_ptr_val(TMP1, ARG2); + lea(TMP1, emit_boxed_val(boxed_ptr)); + a.ldr(TMP2, arm::Mem(TMP1)); + ERTS_CT_ASSERT(make_arityval_zero() == 0); + a.tst(TMP2, imm(_TAG_HEADER_MASK)); + a.b_ne(fail); + + /* Ensure that the position points within the tuple. */ + a.lsr(TMP2, TMP2, imm(_HEADER_ARITY_OFFS)); + a.asr(TMP3, ARG1, imm(_TAG_IMMED1_SIZE)); + a.cmp(TMP3, imm(1)); + a.b_mi(fail); + a.cmp(TMP2, TMP3); + a.b_lo(fail); + + a.ldr(ARG1, arm::Mem(TMP1, TMP3, arm::lsl(3))); + a.ret(a64::x30); +} + +void BeamGlobalAssembler::emit_bif_element_body_shared() { + Label error = a.newLabel(); + + emit_bif_element_helper(error); + + a.bind(error); + { + static ErtsCodeMFA mfa = {am_erlang, am_element, 2}; + a.mov(XREG0, ARG1); + a.mov(XREG1, ARG2); + emit_raise_badarg(&mfa); + } +} + +void BeamGlobalAssembler::emit_bif_element_guard_shared() { + Label error = a.newLabel(); + + emit_bif_element_helper(error); + + a.bind(error); + { + mov_imm(ARG1, THE_NON_VALUE); + a.ret(a64::x30); + } +} + +void BeamGlobalAssembler::emit_handle_element_error_shared() { + static ErtsCodeMFA mfa = {am_erlang, am_element, 2}; + a.mov(XREG0, ARG1); + a.mov(XREG1, ARG2); + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_element(const ArgLabel &Fail, + const ArgSource &Pos, + const ArgSource &Tuple, + const ArgRegister &Dst) { + /* + * Try to optimize the use of a tuple as a lookup table. + */ + if (exact_type(Pos) && Tuple.isLiteral()) { + Eterm tuple_literal = + beamfile_get_literal(beam, Tuple.as().get()); + + if (is_tuple(tuple_literal)) { + Label next = a.newLabel(), fail = a.newLabel(); + Sint size = Sint(arityval(*tuple_val(tuple_literal))); + auto [min, max] = getClampedRange(Pos); + bool can_fail = min < 1 || size < max; + auto [pos, tuple] = load_sources(Pos, ARG3, Tuple, ARG4); + auto dst = init_destination(Dst, ARG1); + + if (always_small(Pos)) { + comment("skipped test for small position since it is always " + "small"); + } else { + comment("simplified test for small position since it is an " + "integer"); + emit_is_not_boxed(fail, pos.reg); + } + + comment("skipped tuple test since source is always a literal " + "tuple"); + arm::Gp boxed_ptr = emit_ptr_val(TMP1, tuple.reg); + lea(TMP1, emit_boxed_val(boxed_ptr)); + + a.asr(TMP3, pos.reg, imm(_TAG_IMMED1_SIZE)); + + if (min >= 1) { + comment("skipped check for position >= 1"); + } else { + a.cmp(TMP3, imm(1)); + a.b_mi(fail); + } + + if (size >= max) { + comment("skipped check for position beyond tuple"); + } else { + mov_imm(TMP2, size); + a.cmp(TMP2, TMP3); + a.b_lo(fail); + } + + a.ldr(dst.reg, arm::Mem(TMP1, TMP3, arm::lsl(3))); + + if (can_fail) { + a.b(next); + } + + a.bind(fail); + if (can_fail) { + if (Fail.get() != 0) { + a.b(resolve_beam_label(Fail, disp128MB)); + } else { + a.mov(ARG1, pos.reg); + a.mov(ARG2, tuple.reg); + fragment_call(ga->get_handle_element_error_shared()); + } + } + + a.bind(next); + flush_var(dst); + + return; + } + } + + bool const_position; + + const_position = Pos.isSmall() && Pos.as().getSigned() > 0 && + Pos.as().getSigned() <= (Sint)MAX_ARITYVAL; + + if (const_position && exact_type(Tuple)) { + comment("simplified element/2 because arguments are known types"); + auto tuple = load_source(Tuple, ARG2); + auto dst = init_destination(Dst, ARG1); + Uint position = Pos.as().getUnsigned(); + arm::Gp boxed_ptr = emit_ptr_val(TMP1, tuple.reg); + + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + ERTS_CT_ASSERT(make_arityval_zero() == 0); + cmp(TMP2, position << _HEADER_ARITY_OFFS); + if (Fail.get() != 0) { + a.b_lo(resolve_beam_label(Fail, disp1MB)); + } else { + Label good = a.newLabel(); + a.b_hs(good); + mov_arg(ARG1, Pos); + mov_var(ARG2, tuple); + fragment_call(ga->get_handle_element_error_shared()); + a.bind(good); + } + + safe_ldur(dst.reg, emit_boxed_val(boxed_ptr, position << 3)); + flush_var(dst); + } else { + /* Too much code to inline. Call a helper fragment. */ + mov_arg(ARG1, Pos); + mov_arg(ARG2, Tuple); + + if (Fail.get() != 0) { + fragment_call(ga->get_bif_element_guard_shared()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } else { + fragment_call(ga->get_bif_element_body_shared()); + } + + auto dst = init_destination(Dst, ARG1); + mov_var(dst, ARG1); + flush_var(dst); + } +} + +/* ================================================================ + * hd/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_hd_error() { + static ErtsCodeMFA mfa = {am_erlang, am_hd, 1}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_hd(const ArgSource &Src, + const ArgRegister &Hd) { + Label good_cons = a.newLabel(); + auto src = load_source(Src, TMP1); + auto hd = init_destination(Hd, TMP2); + const int bitNumber = 1; + + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST == (1 << bitNumber)); + + a.tbz(src.reg, imm(bitNumber), good_cons); + mov_var(XREG0, src); + fragment_call(ga->get_handle_hd_error()); + + a.bind(good_cons); + { + arm::Gp cons_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(hd.reg, getCARRef(cons_ptr)); + flush_var(hd); + } +} + +/* ================================================================ + * is_map_key/2 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_is_map_key(const ArgWord &Bif, + const ArgLabel &Fail, + const ArgSource &Key, + const ArgSource &Src, + const ArgRegister &Dst) { + if (!exact_type(Src)) { + emit_i_bif2(Key, Src, Fail, Bif, Dst); + return; + } + + comment("inlined BIF is_map_key/2"); + + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + + if (maybe_one_of(Key)) { + fragment_call(ga->get_i_get_map_element_shared()); + emit_cond_to_bool(arm::CondCode::kEQ, Dst); + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + cmp(ARG1, THE_NON_VALUE); + emit_cond_to_bool(arm::CondCode::kNE, Dst); + } +} + +/* ================================================================ + * map_get/2 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_map_get_badmap() { + static ErtsCodeMFA mfa = {am_erlang, am_map_get, 2}; + mov_imm(TMP1, BADMAP); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ARG1, arm::Mem(c_p, offsetof(Process, fvalue))); + a.mov(XREG0, ARG2); + a.mov(XREG1, ARG1); + mov_imm(ARG4, &mfa); + a.b(labels[raise_exception]); +} + +void BeamGlobalAssembler::emit_handle_map_get_badkey() { + static ErtsCodeMFA mfa = {am_erlang, am_map_get, 2}; + mov_imm(TMP1, BADKEY); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(ARG2, arm::Mem(c_p, offsetof(Process, fvalue))); + a.mov(XREG0, ARG2); + a.mov(XREG1, ARG1); + mov_imm(ARG4, &mfa); + a.b(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_bif_map_get(const ArgLabel &Fail, + const ArgSource &Key, + const ArgSource &Src, + const ArgRegister &Dst) { + Label good_key = a.newLabel(); + + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + + if (exact_type(Src)) { + comment("skipped test for map for known map argument"); + } else { + Label bad_map = a.newLabel(); + Label good_map = a.newLabel(); + + if (Fail.get() == 0) { + emit_is_boxed(bad_map, Src, ARG1); + } else { + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, ARG1); + } + + /* As an optimization for the `error | #{}` case, skip checking the + * header word when we know that the only possible boxed type + * is a map. */ + if (masked_types(Src) == BeamTypeId::Map) { + comment("skipped header test since we know it's a map when boxed"); + if (Fail.get() == 0) { + a.b(good_map); + } + } else { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, ARG1); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.and_(TMP1, TMP1, imm(_TAG_HEADER_MASK)); + a.cmp(TMP1, imm(_TAG_HEADER_MAP)); + if (Fail.get() == 0) { + a.b_eq(good_map); + } else { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + } + + a.bind(bad_map); + if (Fail.get() == 0) { + fragment_call(ga->get_handle_map_get_badmap()); + } + + a.bind(good_map); + } + + if (maybe_one_of(Key)) { + fragment_call(ga->get_i_get_map_element_shared()); + if (Fail.get() == 0) { + a.b_eq(good_key); + } else { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + if (Fail.get() == 0) { + emit_branch_if_value(ARG1, good_key); + } else { + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } + } + + if (Fail.get() == 0) { + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + fragment_call(ga->get_handle_map_get_badkey()); + } + + a.bind(good_key); + mov_arg(Dst, ARG1); +} + +/* ================================================================ + * map_size/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_map_size_error() { + static ErtsCodeMFA mfa = {am_erlang, am_map_size, 1}; + mov_imm(TMP1, BADMAP); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, freason))); + a.str(XREG0, arm::Mem(c_p, offsetof(Process, fvalue))); + mov_imm(ARG4, &mfa); + a.b(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_bif_map_size(const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + Label error = a.newLabel(), good_map = a.newLabel(); + auto src = load_source(Src, TMP1); + auto dst = init_destination(Dst, TMP2); + + if (Fail.get() == 0) { + emit_is_boxed(error, Src, src.reg); + } else { + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + } + + arm::Gp boxed_ptr = emit_ptr_val(TMP3, src.reg); + + if (exact_type(Src)) { + comment("skipped type check because the argument is always a map"); + a.bind(error); /* Never referenced. */ + } else { + a.ldur(TMP4, emit_boxed_val(boxed_ptr)); + a.and_(TMP4, TMP4, imm(_TAG_HEADER_MASK)); + a.cmp(TMP4, imm(_TAG_HEADER_MAP)); + + if (Fail.get() == 0) { + a.b_eq(good_map); + a.bind(error); + { + mov_var(XREG0, src); + fragment_call(ga->get_handle_map_size_error()); + } + } else { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + a.bind(error); /* Never referenced. */ + } + } + + a.bind(good_map); + { + ERTS_CT_ASSERT(offsetof(flatmap_t, size) == sizeof(Eterm)); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + mov_imm(dst.reg, _TAG_IMMED1_SMALL); + a.bfi(dst.reg, TMP1, imm(_TAG_IMMED1_SIZE), imm(SMALL_BITS)); + flush_var(dst); + } +} + +/* ================================================================ + * min/2 + * max/2 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_min_max(arm::CondCode cc, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + auto [lhs, rhs] = load_sources(LHS, ARG1, RHS, ARG2); + auto dst = init_destination(Dst, ARG1); + bool both_small = always_small(LHS) && always_small(RHS); + bool need_generic = !both_small; + Label generic = a.newLabel(), next = a.newLabel(); + + if (both_small) { + comment("skipped test for small operands since they are always small"); + } else if (always_small(RHS) && + always_one_of( + LHS)) { + comment("simplified test for small operand"); + emit_is_not_boxed(generic, lhs.reg); + } else if (always_small(LHS) && + always_one_of( + RHS)) { + comment("simplified test for small operand"); + emit_is_not_boxed(generic, rhs.reg); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + comment("simplified test for small operands"); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs.reg, rhs.reg); + emit_is_not_boxed(generic, TMP1); + } else { + if (RHS.isSmall()) { + a.and_(TMP1, lhs.reg, imm(_TAG_IMMED1_MASK)); + } else if (LHS.isSmall()) { + a.and_(TMP1, rhs.reg, imm(_TAG_IMMED1_MASK)); + } else { + /* Avoid the expensive generic comparison for equal terms. */ + a.cmp(lhs.reg, rhs.reg); + a.b_eq(next); + + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.and_(TMP1, lhs.reg, rhs.reg); + a.and_(TMP1, TMP1, imm(_TAG_IMMED1_MASK)); + } + + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + a.b_ne(generic); + } + + /* Both arguments are smalls. */ + a.cmp(lhs.reg, rhs.reg); + if (need_generic) { + a.b(next); + } + + a.bind(generic); + if (need_generic) { + mov_var(ARG1, lhs); + mov_var(ARG2, rhs); + fragment_call(ga->get_arith_compare_shared()); + load_sources(LHS, ARG1, RHS, ARG2); + } + + a.bind(next); + a.csel(dst.reg, rhs.reg, lhs.reg, cc); + flush_var(dst); +} + +void BeamModuleAssembler::emit_bif_max(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_min_max(arm::CondCode::kLT, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_bif_min(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_min_max(arm::CondCode::kGT, LHS, RHS, Dst); +} + +/* ================================================================ + * node/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_node_error() { + static ErtsCodeMFA mfa = {am_erlang, am_node, 1}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_node(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Dst) { + bool always_identifier = always_one_of(Src); + Label test_internal = a.newLabel(); + Label internal = a.newLabel(); + Label next = a.newLabel(); + auto src = load_source(Src, ARG2); + Label fail; + + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail, dispUnknown); + } else if (!always_identifier) { + fail = a.newLabel(); + } + + emit_is_boxed(test_internal, Src, src.reg); + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + + if (!always_one_of(Src)) { + a.ldur(TMP2, emit_boxed_val(boxed_ptr)); + a.and_(TMP2, TMP2, imm(_TAG_HEADER_MASK)); + } + + if (maybe_one_of(Src)) { + a.cmp(TMP2, imm(_TAG_HEADER_REF)); + a.b_eq(internal); + } + + if (!always_identifier) { + Label external = a.newLabel(); + ERTS_CT_ASSERT((_TAG_HEADER_EXTERNAL_PORT - _TAG_HEADER_EXTERNAL_PID) >> + _TAG_PRIMARY_SIZE == + 1); + ERTS_CT_ASSERT((_TAG_HEADER_EXTERNAL_REF - _TAG_HEADER_EXTERNAL_PORT) >> + _TAG_PRIMARY_SIZE == + 1); + a.sub(TMP3, TMP2, imm(_TAG_HEADER_EXTERNAL_PID)); + a.cmp(TMP3, imm(_TAG_HEADER_EXTERNAL_REF - _TAG_HEADER_EXTERNAL_PID)); + + if (Fail.get() != 0) { + a.b_hi(fail); + } else { + a.b_ls(external); + + a.bind(fail); + { + mov_var(XREG0, src); + fragment_call(ga->get_handle_node_error()); + } + } + + a.bind(external); + } + + a.ldur(TMP1, emit_boxed_val(boxed_ptr, offsetof(ExternalThing, node))); + a.b(next); + + a.bind(test_internal); + if (!always_identifier) { + a.and_(TMP1, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_PID)); + a.ccmp(TMP1, + imm(_TAG_IMMED1_PORT), + imm(NZCV::kEqual), + imm(arm::CondCode::kNE)); + a.b_ne(fail); + } + + a.bind(internal); + a.ldr(TMP1, embed_constant(&erts_this_node, disp32K)); + a.ldr(TMP1, arm::Mem(TMP1)); + + a.bind(next); + mov_arg(Dst, arm::Mem(TMP1, offsetof(ErlNode, sysname))); +} + +/* ================================================================ + * not/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_not_error() { + static ErtsCodeMFA mfa = {am_erlang, am_not, 1}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_not(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Dst) { + Label next = a.newLabel(); + auto src = load_source(Src, TMP1); + auto dst = init_destination(Dst, TMP2); + ERTS_CT_ASSERT(am_false == make_atom(0)); + ERTS_CT_ASSERT(am_true == make_atom(1)); + Uint diff_bit = am_true - am_false; + + a.and_(TMP3, src.reg, imm(_TAG_IMMED2_MASK | ~diff_bit)); + a.cmp(TMP3, imm(_TAG_IMMED2_ATOM)); + + if (Fail.get() == 0) { + a.b_eq(next); + mov_var(XREG0, src); + fragment_call(ga->get_handle_not_error()); + } else { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); + { + a.eor(dst.reg, src.reg, imm(diff_bit)); + flush_var(dst); + } +} + +/* ================================================================ + * or/2 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_or_error() { + static ErtsCodeMFA mfa = {am_erlang, am_or, 2}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_or(const ArgLabel &Fail, + const ArgSource &Src1, + const ArgSource &Src2, + const ArgRegister &Dst) { + static const Uint diff_bit = am_true - am_false; + Label next = a.newLabel(); + + auto [src1, src2] = load_sources(Src1, TMP1, Src2, TMP2); + auto dst = init_destination(Dst, TMP3); + + ERTS_CT_ASSERT(am_false == make_atom(0)); + ERTS_CT_ASSERT(am_true == make_atom(1)); + + if (exact_type(Src1) && + exact_type(Src2)) { + comment("simplified type check because operands are atoms"); + a.orr(TMP3, src1.reg, src2.reg); + a.tst(TMP3, imm(-1ull << (_TAG_IMMED2_SIZE + 1))); + } else { + a.and_(TMP3, src1.reg, imm(_TAG_IMMED2_MASK | ~diff_bit)); + a.and_(TMP4, src2.reg, imm(_TAG_IMMED2_MASK | ~diff_bit)); + a.cmp(TMP3, imm(_TAG_IMMED2_ATOM)); + a.ccmp(TMP3, TMP4, imm(NZCV::kNone), imm(arm::CondCode::kEQ)); + } + + if (Fail.get()) { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + a.b_eq(next); + mov_var(XREG0, src1); + mov_var(XREG1, src2); + fragment_call(ga->get_handle_or_error()); + } + + a.bind(next); + { + a.orr(dst.reg, src1.reg, src2.reg); + flush_var(dst); + } +} + +/* ================================================================ + * tl/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_tl_error() { + static ErtsCodeMFA mfa = {am_erlang, am_tl, 1}; + emit_raise_badarg(&mfa); +} + +void BeamModuleAssembler::emit_bif_tl(const ArgSource &Src, + const ArgRegister &Tl) { + Label good_cons = a.newLabel(); + auto src = load_source(Src, TMP1); + auto tl = init_destination(Tl, TMP2); + const int bitNumber = 1; + + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST == (1 << bitNumber)); + + a.tbz(src.reg, imm(bitNumber), good_cons); + mov_var(XREG0, src); + fragment_call(ga->get_handle_tl_error()); + + a.bind(good_cons); + { + arm::Gp cons_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(tl.reg, getCDRRef(cons_ptr)); + flush_var(tl); + } +} + +/* ================================================================ + * tuple_size/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_bif_tuple_size_helper(Label fail) { + arm::Gp boxed_ptr = emit_ptr_val(TMP1, ARG1); + + emit_is_boxed(fail, boxed_ptr); + + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + a.tst(TMP1, imm(_TAG_HEADER_MASK)); + a.b_ne(fail); + + ERTS_CT_ASSERT(_HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE > 0); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.lsr(TMP1, TMP1, _HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE); + a.orr(ARG1, TMP1, imm(_TAG_IMMED1_SMALL)); + + a.ret(a64::x30); +} + +void BeamGlobalAssembler::emit_bif_tuple_size_body() { + Label error = a.newLabel(); + + emit_bif_tuple_size_helper(error); + + a.bind(error); + { + static ErtsCodeMFA mfa = {am_erlang, am_tuple_size, 1}; + a.mov(XREG0, ARG1); + emit_raise_badarg(&mfa); + } +} + +void BeamGlobalAssembler::emit_bif_tuple_size_guard() { + Label error = a.newLabel(); + + emit_bif_tuple_size_helper(error); + + a.bind(error); + { + mov_imm(ARG1, THE_NON_VALUE); + a.ret(a64::x30); + } +} + +void BeamModuleAssembler::emit_bif_tuple_size(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Dst) { + auto src = load_source(Src, ARG1); + auto dst = init_destination(Dst, ARG1); + + if (exact_type(Src)) { + comment("simplifed tuple_size/1 because the argument is always a " + "tuple"); + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr)); + ERTS_CT_ASSERT(_HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE > 0); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.lsr(TMP1, TMP1, _HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE); + a.orr(dst.reg, TMP1, imm(_TAG_IMMED1_SMALL)); + } else { + mov_var(ARG1, src); + + if (Fail.get() == 0) { + fragment_call(ga->get_bif_tuple_size_body()); + } else { + fragment_call(ga->get_bif_tuple_size_guard()); + emit_branch_if_not_value(ARG1, + resolve_beam_label(Fail, dispUnknown)); + } + + mov_var(dst, ARG1); + } + flush_var(dst); +} diff --git a/erts/emulator/beam/jit/arm/instr_map.cpp b/erts/emulator/beam/jit/arm/instr_map.cpp new file mode 100644 index 000000000000..8d7ad6f45f8d --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_map.cpp @@ -0,0 +1,676 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ +#include +#include "beam_asm.hpp" + +using namespace asmjit; + +extern "C" +{ +#include "erl_map.h" +#include "erl_term_hashing.h" +#include "beam_common.h" +} + +static const Uint32 INTERNAL_HASH_SALT = 3432918353; +static const Uint32 HCONST = 0x9E3779B9; + +/* ARG6 = lower 32 + * ARG7 = upper 32 + * + * Helper function for calculating the internal hash of keys before looking + * them up in a map. + * + * This is essentially just a manual expansion of the `UINT32_HASH_2` macro. + * Whenever the internal hash algorithm is updated, this and all of its users + * must follow suit. + * + * Result is returned in ARG3. All arguments are clobbered. */ +void BeamGlobalAssembler::emit_internal_hash_helper() { + a64::Gp hash = ARG3.w(), lower = ARG6.w(), upper = ARG7.w(), + constant = ARG8.w(); + + mov_imm(hash, INTERNAL_HASH_SALT); + mov_imm(constant, HCONST); + + a.add(lower, lower, constant); + a.add(upper, upper, constant); + +#if defined(ERL_INTERNAL_HASH_CRC32C) + a.crc32cw(lower, hash, lower); + a.add(hash, hash, lower); + a.crc32cw(hash, hash, upper); +#else + using rounds = + std::initializer_list>; + for (const auto &round : rounds{{lower, upper, hash, 13}, + {upper, hash, lower, -8}, + {hash, lower, upper, 13}, + {lower, upper, hash, 12}, + {upper, hash, lower, -16}, + {hash, lower, upper, 5}, + {lower, upper, hash, 3}, + {upper, hash, lower, -10}, + {hash, lower, upper, 15}}) { + const auto &[r_a, r_b, r_c, shift] = round; + + a.sub(r_a, r_a, r_b); + a.sub(r_a, r_a, r_c); + + if (shift > 0) { + a.eor(r_a, r_a, r_c, arm::lsr(shift)); + } else { + a.eor(r_a, r_a, r_c, arm::lsl(-shift)); + } + } +#endif + +#ifdef DBG_HASHMAP_COLLISION_BONANZA + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.stp(ARG1, ARG2, TMP_MEM1q); + a.str(ARG4, TMP_MEM3q); + + a.mov(ARG1, ARG3); + runtime_call<2>(erts_dbg_hashmap_collision_bonanza); + a.mov(ARG3, ARG1); + + a.ldp(ARG1, ARG2, TMP_MEM1q); + a.ldr(ARG4, TMP_MEM3q); + + emit_leave_runtime(); + emit_leave_runtime_frame(); +#endif + + a.ret(a64::x30); +} + +/* ARG1 = untagged hash map root + * ARG2 = key + * ARG3 = key hash + * ARG4 = node header + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_hashmap_get_element() { + Label node_loop = a.newLabel(); + + arm::Gp node = ARG1, key = ARG2, key_hash = ARG3, header_val = ARG4, + depth = TMP5, index = TMP6; + + const int header_shift = + (_HEADER_ARITY_OFFS + MAP_HEADER_TAG_SZ + MAP_HEADER_ARITY_SZ); + + /* Skip the root header, which is two words long (child headers are one + * word). */ + a.add(node, node, imm(sizeof(Eterm[2]))); + mov_imm(depth, 0); + + a.bind(node_loop); + { + Label done = a.newLabel(), leaf_node = a.newLabel(), + skip_index_adjustment = a.newLabel(), + collision_node = a.newLabel(); + + /* Find out which child we should follow, and shift the hash for the + * next round. */ + a.and_(index, key_hash, imm(0xF)); + a.lsr(key_hash, key_hash, imm(4)); + a.add(depth, depth, imm(1)); + + /* The entry offset is always equal to the index on fully populated + * nodes, so we'll skip adjusting them. */ + ERTS_CT_ASSERT(header_shift == 16); + a.asr(header_val.w(), header_val.w(), imm(header_shift)); + a.cmn(header_val.w(), imm(1)); + a.b_eq(skip_index_adjustment); + { + /* If our bit isn't set on this node, the key can't be found. + * + * Note that we jump directly to the return sequence as ZF is clear + * at this point. */ + a.lsr(TMP1, header_val, index); + a.tbz(TMP1, imm(0), done); + + /* The actual offset of our entry is the number of bits set (in + * essence "entries present") before our index in the bitmap. Clear + * the upper bits and count the remainder. */ + a.lsl(TMP2, TMP1, index); + a.eor(TMP1, TMP2, header_val); + a.fmov(a64::d0, TMP1); + a.cnt(a64::v0.b8(), a64::v0.b8()); + a.addv(a64::b0, a64::v0.b8()); + a.fmov(index, a64::d0); + } + a.bind(skip_index_adjustment); + + a.ldr(TMP1, arm::Mem(node, index, arm::lsl(3))); + emit_untag_ptr(node, TMP1); + + /* Have we found our leaf? */ + emit_is_boxed(leaf_node, TMP1); + + /* Nope, we have to search another node. Read and skip past the header + * word. */ + a.ldr(header_val, arm::Mem(node).post(sizeof(Eterm))); + + /* After 8 nodes we've run out of the 32 bits we started with + * and we end up in a collision node. */ + a.cmp(depth, imm(HAMT_MAX_LEVEL)); + a.b_ne(node_loop); + a.b(collision_node); + + a.bind(leaf_node); + { + /* We've arrived at a leaf, set ZF according to whether its key + * matches ours and speculatively place the element in ARG1. */ + a.ldp(TMP1, ARG1, arm::Mem(node)); + a.cmp(TMP1, key); + + /* See comment at the jump. */ + a.bind(done); + a.ret(a64::x30); + } + + /* A collision node is a tuple of leafs where we do linear search.*/ + a.bind(collision_node); + { + Label linear_loop = a.newLabel(); + + a.lsr(TMP1, header_val, imm(_HEADER_ARITY_OFFS - 3)); + + a.bind(linear_loop); + { + a.sub(TMP1, TMP1, imm(8)); + + a.ldr(TMP2, arm::Mem(node, TMP1)); + + emit_untag_ptr(TMP2, TMP2); + a.ldp(TMP3, TMP4, arm::Mem(TMP2)); + a.cmp(key, TMP3); + a.csel(ARG1, node, TMP4, imm(arm::CondCode::kNE)); + a.b_eq(done); + + a.cbnz(TMP1, linear_loop); + } + + a.ret(a64::x30); + } + } +} + +/* ARG1 = untagged flat map + * ARG2 = key + * ARG5 = size + * + * Result is returned in ARG1. ZF is set on success. */ +void BeamGlobalAssembler::emit_flatmap_get_element() { + Label fail = a.newLabel(), loop = a.newLabel(); + + /* Bump size by 1 to slide past the `keys` field in the map, and the header + * word in the key array. Also set flags to ensure ZF == 0 when entering + * the loop. */ + a.adds(ARG5, ARG5, imm(1)); + + /* Adjust our map pointer to the `keys` field before loading it. This + * saves us from having to bump it to point at the values later on. */ + a.ldr(TMP1, arm::Mem(ARG1).pre(offsetof(flatmap_t, keys))); + emit_untag_ptr(TMP1, TMP1); + + a.bind(loop); + { + a.sub(ARG5, ARG5, imm(1)); + a.cbz(ARG5, fail); + + a.ldr(TMP4, arm::Mem(TMP1, ARG5, arm::lsl(3))); + a.cmp(ARG2, TMP4); + a.b_ne(loop); + } + + a.ldr(ARG1, arm::Mem(ARG1, ARG5, arm::lsl(3))); + + a.bind(fail); + a.ret(a64::x30); +} + +void BeamGlobalAssembler::emit_new_map_shared() { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<5>(erts_gc_new_map); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_new_map(const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { + embed_vararg_rodata(args, ARG5); + + mov_arg(ARG3, Live); + mov_imm(ARG4, args.size()); + fragment_call(ga->get_new_map_shared()); + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_i_new_small_map_lit(const ArgRegister &Dst, + const ArgWord &Live, + const ArgLiteral &Keys, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + + emit_gc_test(ArgWord(0), + ArgWord(args.size() + MAP_HEADER_FLATMAP_SZ + 1), + Live); + + std::vector data; + data.reserve(args.size() + MAP_HEADER_FLATMAP_SZ + 1); + data.push_back(ArgWord(MAP_HEADER_FLATMAP)); + data.push_back(Size); + data.push_back(Keys); + + bool dst_is_src = false; + for (auto arg : args) { + data.push_back(arg); + dst_is_src |= (arg == Dst); + } + + if (dst_is_src) { + a.add(TMP1, HTOP, TAG_PRIMARY_BOXED); + } else { + auto ptr = init_destination(Dst, TMP1); + a.add(ptr.reg, HTOP, TAG_PRIMARY_BOXED); + flush_var(ptr); + } + + size_t size = data.size(); + unsigned i; + for (i = 0; i < size - 1; i += 2) { + if ((i % 128) == 0) { + check_pending_stubs(); + } + + auto [first, second] = load_sources(data[i], TMP2, data[i + 1], TMP3); + a.stp(first.reg, second.reg, arm::Mem(HTOP).post(sizeof(Eterm[2]))); + } + + if (i < size) { + mov_arg(arm::Mem(HTOP).post(sizeof(Eterm)), data[i]); + } + + if (dst_is_src) { + auto ptr = init_destination(Dst, TMP1); + mov_var(ptr, TMP1); + flush_var(ptr); + } +} + +/* ARG1 = map + * ARG2 = key + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_i_get_map_element_shared() { + Label generic = a.newLabel(), hashmap = a.newLabel(); + + a.and_(TMP1, ARG2, imm(_TAG_PRIMARY_MASK)); + a.cmp(TMP1, imm(TAG_PRIMARY_IMMED1)); + a.b_ne(generic); + + emit_untag_ptr(ARG1, ARG1); + + /* hashmap_get_element expects node header in ARG4, flatmap_get_element + * expects size in ARG5 */ + ERTS_CT_ASSERT_FIELD_PAIR(flatmap_t, thing_word, size); + a.ldp(ARG4, ARG5, arm::Mem(ARG1)); + a.and_(TMP1, ARG4, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(TMP1, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.b_ne(hashmap); + + emit_flatmap_get_element(); + + a.bind(generic); + { + emit_enter_runtime_frame(); + + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + a.cmp(ARG1, imm(THE_NON_VALUE)); + + /* Invert ZF, we want it to be set when RET is a value. */ + a.cset(TMP1, arm::CondCode::kEQ); + a.tst(TMP1, TMP1); + + emit_leave_runtime_frame(); + a.ret(a64::x30); + } + + a.bind(hashmap); + { + emit_enter_runtime_frame(); + + /* Calculate the internal hash of ARG2 before diving into the HAMT. */ + a.mov(ARG6.w(), ARG2.w()); + a.lsr(ARG7, ARG2, imm(32)); + a.bl(labels[internal_hash_helper]); + + emit_leave_runtime_frame(); + + emit_hashmap_get_element(); + } +} + +void BeamModuleAssembler::emit_i_get_map_element(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Key, + const ArgRegister &Dst) { + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + + if (maybe_one_of(Key)) { + fragment_call(ga->get_i_get_map_element_shared()); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } + + /* + * Don't store the result if the destination is the scratch X register. + * (This instruction was originally a has_map_fields instruction.) + */ + if (!(Dst.isXRegister() && Dst.as().get() == SCRATCH_X_REG)) { + mov_arg(Dst, ARG1); + } +} + +void BeamModuleAssembler::emit_i_get_map_elements(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Size, + const Span &args) { + Label generic = a.newLabel(), next = a.newLabel(); + + /* We're not likely to gain much from inlining huge extractions, and the + * resulting code is quite large, so we'll cut it off after a handful + * elements. + * + * Note that the arguments come in flattened triplets of + * `{Key, Dst, KeyHash}` */ + bool can_inline = args.size() < (8 * 3); + + ASSERT(Size.get() == args.size()); + ASSERT((Size.get() % 3) == 0); + + for (size_t i = 0; i < args.size(); i += 3) { + can_inline &= args[i].isImmed(); + } + + mov_arg(ARG1, Src); + + if (can_inline) { + comment("simplified multi-element lookup"); + + emit_untag_ptr(TMP1, ARG1); + + ERTS_CT_ASSERT_FIELD_PAIR(flatmap_t, thing_word, size); + a.ldp(TMP2, TMP3, arm::Mem(TMP1, offsetof(flatmap_t, thing_word))); + a.and_(TMP2, TMP2, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(TMP2, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.b_ne(generic); + + check_pending_stubs(); + + /* Bump size by 1 to slide past the `keys` field in the map, and the + * header word in the key array. */ + a.add(TMP3, TMP3, imm(1)); + + /* Adjust our map pointer to the `keys` field before loading it. This + * saves us from having to bump it to point at the values later on. */ + ERTS_CT_ASSERT(sizeof(flatmap_t) == + offsetof(flatmap_t, keys) + sizeof(Eterm)); + a.ldr(TMP2, arm::Mem(TMP1).pre(offsetof(flatmap_t, keys))); + emit_untag_ptr(TMP2, TMP2); + + for (ssize_t i = args.size() - 3; i >= 0; i -= 3) { + Label loop = a.newLabel(); + + a.bind(loop); + { + a.subs(TMP3, TMP3, imm(1)); + a.b_eq(resolve_beam_label(Fail, disp1MB)); + + a.ldr(TMP4, arm::Mem(TMP2, TMP3, arm::lsl(3))); + + const auto &Comparand = args[i]; + cmp_arg(TMP4, Comparand); + a.b_ne(loop); + } + + /* Don't store the result if the destination is the scratch X + * register. (This instruction was originally a has_map_fields + * instruction.) */ + const auto &Dst = args[i + 1]; + if (!(Dst.isXRegister() && + Dst.as().get() == SCRATCH_X_REG)) { + mov_arg(Dst, arm::Mem(TMP1, TMP3, arm::lsl(3))); + } + } + + a.b(next); + } + + a.bind(generic); + { + embed_vararg_rodata(args, ARG5); + + a.mov(ARG3, E); + + emit_enter_runtime(); + + mov_imm(ARG4, args.size() / 3); + load_x_reg_array(ARG2); + runtime_call<5>(beam_jit_get_map_elements); + + emit_leave_runtime(); + + a.cbz(ARG1, resolve_beam_label(Fail, disp1MB)); + } + + a.bind(next); +} + +/* ARG1 = map + * ARG2 = key + * ARG3 = key hash + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_i_get_map_element_hash_shared() { + Label hashmap = a.newLabel(); + + emit_untag_ptr(ARG1, ARG1); + + /* hashmap_get_element expects node header in ARG4, flatmap_get_element + * expects size in ARG5 */ + ERTS_CT_ASSERT_FIELD_PAIR(flatmap_t, thing_word, size); + a.ldp(ARG4, ARG5, arm::Mem(ARG1)); + a.and_(TMP1, ARG4, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(TMP1, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.b_ne(hashmap); + + emit_flatmap_get_element(); + + a.bind(hashmap); + emit_hashmap_get_element(); +} + +void BeamModuleAssembler::emit_i_get_map_element_hash(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgConstant &Key, + const ArgWord &Hx, + const ArgRegister &Dst) { + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + mov_arg(ARG3, Hx); + + if (Key.isImmed()) { + fragment_call(ga->get_i_get_map_element_hash_shared()); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + emit_enter_runtime(); + runtime_call<3>(get_map_element_hash); + emit_leave_runtime(); + + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } + + /* + * Don't store the result if the destination is the scratch X register. + * (This instruction was originally a has_map_fields instruction.) + */ + if (!(Dst.isXRegister() && Dst.as().get() == SCRATCH_X_REG)) { + mov_arg(Dst, ARG1); + } +} + +/* ARG3 = live registers, ARG4 = update vector size, ARG5 = update vector. */ +void BeamGlobalAssembler::emit_update_map_assoc_shared() { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<5>(erts_gc_update_map_assoc); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src, + const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { + auto src_reg = load_source(Src, TMP1); + + ASSERT(Size.get() == args.size()); + + embed_vararg_rodata(args, ARG5); + + mov_arg(ArgXRegister(Live.get()), src_reg.reg); + mov_arg(ARG3, Live); + mov_imm(ARG4, args.size()); + + fragment_call(ga->get_update_map_assoc_shared()); + + mov_arg(Dst, ARG1); +} + +/* ARG3 = live registers, ARG4 = update vector size, ARG5 = update vector. + * + * Result is returned in RET, error is indicated by ZF. */ +void BeamGlobalAssembler::emit_update_map_exact_guard_shared() { + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<5>(erts_gc_update_map_exact); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + a.ret(a64::x30); +} + +/* ARG3 = live registers, ARG4 = update vector size, ARG5 = update vector. + * + * Does not return on error. */ +void BeamGlobalAssembler::emit_update_map_exact_body_shared() { + Label error = a.newLabel(); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<5>(erts_gc_update_map_exact); + + emit_leave_runtime(); + emit_leave_runtime_frame(); + + emit_branch_if_not_value(ARG1, error); + a.ret(a64::x30); + + a.bind(error); + { + mov_imm(ARG4, 0); + a.b(labels[raise_exception]); + } +} + +void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src, + const ArgLabel &Fail, + const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { + auto src_reg = load_source(Src, TMP1); + + ASSERT(Size.get() == args.size()); + + embed_vararg_rodata(args, ARG5); + + /* We _KNOW_ Src is a map */ + + mov_arg(ArgXRegister(Live.get()), src_reg.reg); + mov_arg(ARG3, Live); + mov_imm(ARG4, args.size()); + + if (Fail.get() != 0) { + fragment_call(ga->get_update_map_exact_guard_shared()); + emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown)); + } else { + fragment_call(ga->get_update_map_exact_body_shared()); + } + + mov_arg(Dst, ARG1); +} diff --git a/erts/emulator/beam/jit/arm/instr_msg.cpp b/erts/emulator/beam/jit/arm/instr_msg.cpp new file mode 100644 index 000000000000..dd99af59c2c4 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_msg.cpp @@ -0,0 +1,384 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "bif.h" +#include "code_ix.h" +#include "erl_proc_sig_queue.h" +#ifdef USE_VM_PROBES +# include "dtrace-wrapper.h" +#endif +} + +#ifdef ERTS_SUPPORT_OLD_RECV_MARK_INSTRS + +static void recv_mark(Process *p) { + /* inlined here... */ + erts_msgq_recv_marker_insert_bind(p, erts_old_recv_marker_id); +} + +static void recv_mark_set(Process *p) { + /* inlined here... */ + erts_msgq_recv_marker_set_save(p, erts_old_recv_marker_id); +} + +void BeamModuleAssembler::emit_i_recv_mark() { + /* + * OLD INSTRUCTION: This instruction is to be removed + * in OTP 26. + * + * Save the current end of message queue + */ + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<1>(recv_mark); + + emit_leave_runtime(); +} + +void BeamModuleAssembler::emit_i_recv_set() { + /* + * OLD INSTRUCTION: This instruction is to be removed + * in OTP 26. + * + * If previously saved recv mark, set save pointer to it + */ + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<1>(recv_mark_set); + + emit_leave_runtime(); +} + +#endif /* ERTS_SUPPORT_OLD_RECV_MARK_INSTRS */ + +void BeamModuleAssembler::emit_recv_marker_reserve(const ArgRegister &Dst) { + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<1>(erts_msgq_recv_marker_insert); + + emit_leave_runtime(); + + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_recv_marker_bind(const ArgRegister &Marker, + const ArgRegister &Reference) { + mov_arg(ARG2, Marker); + mov_arg(ARG3, Reference); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_msgq_recv_marker_bind); + + emit_leave_runtime(); +} + +void BeamModuleAssembler::emit_recv_marker_clear(const ArgRegister &Reference) { + mov_arg(ARG2, Reference); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_msgq_recv_marker_clear); + + emit_leave_runtime(); +} + +void BeamModuleAssembler::emit_recv_marker_use(const ArgRegister &Reference) { + mov_arg(ARG2, Reference); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<2>(erts_msgq_recv_marker_set_save); + + emit_leave_runtime(); +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_lc_proc_sig_receive_helper(Process *c_p, + int fcalls, + int neg_o_reds, + ErtsMessage **msgpp, + int *get_outp) { + int res; + /* + * erts_proc_sig_receive_helper() may temporarliy release + * its own main lock... + */ + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + res = erts_proc_sig_receive_helper(c_p, + fcalls, + neg_o_reds, + msgpp, + get_outp); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + return res; +} +#endif + +void BeamGlobalAssembler::emit_i_loop_rec_shared() { + Label restart = a.newLabel(), peek_message = a.newLabel(), + schedule_out = a.newLabel(), check_is_distributed = a.newLabel(), + done = a.newLabel(); + + arm::Mem await_addr = TMP_MEM1q, message_ptr = TMP_MEM2q, + get_out = TMP_MEM3q; + arm::Mem flags = arm::Mem(c_p, offsetof(Process, flags)); + + a.mov(XREG1, a64::x30); + + a.ldr(TMP1.w(), flags); + a.orr(TMP1, TMP1, imm(F_DELAY_GC)); + a.str(TMP1.w(), flags); + a.str(ARG1, arm::Mem(c_p, offsetof(Process, i))); + a.str(ARG2, await_addr); + + a.bind(restart); + { + a.tst(FCALLS, FCALLS); + a.b_le(schedule_out); + + /* !! FALL THROUGH !! */ + } + + comment("Peek next message"); + a.bind(peek_message); + { + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, sig_qs.save))); + a.ldr(ARG1, arm::Mem(TMP1)); + a.cbnz(ARG1, check_is_distributed); + comment("Inner queue empty, fetch more from outer/middle queues"); + + emit_enter_runtime(0); + + a.str(ZERO, message_ptr); + a.mov(ARG1, c_p); + a.mov(ARG2, FCALLS); + mov_imm(ARG3, 0); + lea(ARG4, message_ptr); + lea(ARG5, get_out); +#ifdef ERTS_ENABLE_LOCK_CHECK + runtime_call<5>(erts_lc_proc_sig_receive_helper); +#else + runtime_call<5>(erts_proc_sig_receive_helper); +#endif + + /* erts_proc_sig_receive_helper merely inspects FCALLS, so we don't + * need to update it here. + * + * Also note that another process may have loaded new code and sent us + * a message to notify us about it, so we must update the active code + * index. */ + emit_leave_runtime(0); + + a.sub(FCALLS, FCALLS, ARG1); + + /* Need to spill message_ptr to ARG1 as check_is_distributed uses it. */ + a.ldr(ARG1, message_ptr); + a.cbnz(ARG1, check_is_distributed); + + /* Did we receive a signal or run out of reds? */ + a.ldr(TMP1.w(), get_out); + a.cbnz(TMP1, schedule_out); + + /* The queue is empty and we're not yielding or exiting, so we'll jump + * to our wait/timeout instruction. + * + * Note that the message queue lock is still held in this case. */ + a.ldr(TMP1.w(), flags); + a.and_(TMP1, TMP1, imm(~F_DELAY_GC)); + a.str(TMP1.w(), flags); + + a.ldr(TMP1, await_addr); + a.br(TMP1); + } + + a.bind(schedule_out); + { + /* We either ran out of reductions or received an exit signal; schedule + * ourselves out. The yield address (`c_p->i`) was set on ingress. */ + a.ldr(TMP1.w(), flags); + a.and_(TMP1, TMP1, imm(~F_DELAY_GC)); + a.str(TMP1.w(), flags); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, arity))); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, current))); + + a.b(labels[do_schedule]); + } + + /* + * ARG1 now contains the pointer to a message. + */ + comment("Check if message is distributed"); + a.bind(check_is_distributed); + { + a.ldr(TMP1, arm::Mem(ARG1, offsetof(ErtsSignal, common.tag))); + emit_branch_if_value(TMP1, done); + + sub(FCALLS, FCALLS, 10); + + emit_enter_runtime(0); + + a.mov(ARG2, ARG1); + a.mov(ARG1, c_p); + runtime_call<2>(beam_jit_decode_dist); + + emit_leave_runtime(0); + + a.cbz(ARG1, restart); + + /* !! FALL THROUGH !! */ + } + + a.bind(done); + { + a.ldr(XREG0, arm::Mem(ARG1, offsetof(ErtsMessage, m[0]))); + a.ret(XREG1); + } +} + +void BeamModuleAssembler::emit_i_loop_rec(const ArgLabel &Wait) { + Label entry = a.newLabel(); + + a.bind(entry); + a.adr(ARG1, entry); + a.ldr(ARG2, embed_constant(Wait, disp32K)); + fragment_call(ga->get_i_loop_rec_shared()); +} + +void BeamModuleAssembler::emit_remove_message() { + /* HTOP and E are passed explicitly and only read from, so we don't need to + * swap them out. */ + a.mov(ARG3, HTOP); + a.mov(ARG4, E); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + a.mov(ARG2, FCALLS); + a.mov(ARG5, active_code_ix); + runtime_call<5>(beam_jit_remove_message); + a.mov(FCALLS, ARG1); + + emit_leave_runtime(); +} + +void BeamModuleAssembler::emit_loop_rec_end(const ArgLabel &Dest) { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<1>(erts_msgq_set_save_next); + + emit_leave_runtime(0); + + a.sub(FCALLS, FCALLS, imm(1)); + a.b(resolve_beam_label(Dest, disp128MB)); +} + +void BeamModuleAssembler::emit_wait_unlocked(const ArgLabel &Dest) { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + a.ldr(ARG2, embed_constant(Dest, disp32K)); + runtime_call<2>(beam_jit_wait_unlocked); + + emit_leave_runtime(0); + + a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); +} + +void BeamModuleAssembler::emit_wait_locked(const ArgLabel &Dest) { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + a.ldr(ARG2, embed_constant(Dest, disp32K)); + runtime_call<2>(beam_jit_wait_locked); + + emit_leave_runtime(0); + + a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); +} + +void BeamModuleAssembler::emit_wait_timeout_unlocked(const ArgSource &Src, + const ArgLabel &Dest) { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<1>(beam_jit_take_receive_lock); + + emit_leave_runtime(0); + + emit_wait_timeout_locked(Src, Dest); +} + +void BeamModuleAssembler::emit_wait_timeout_locked(const ArgSource &Src, + const ArgLabel &Dest) { + Label wait = a.newLabel(), next = a.newLabel(); + + mov_arg(ARG2, Src); + + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + a.adr(ARG3, next); + runtime_call<3>(beam_jit_wait_timeout); + + emit_leave_runtime(0); + + ERTS_CT_ASSERT(RET_next < RET_wait && RET_wait < RET_badarg); + a.cmp(ARG1, imm(RET_wait)); + a.b_eq(wait); + a.b_lt(next); + + emit_raise_exception(current_label, (ErtsCodeMFA *)nullptr); + + a.bind(wait); + emit_wait_locked(Dest); + + a.bind(next); +} + +void BeamModuleAssembler::emit_timeout_locked() { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<1>(beam_jit_timeout_locked); + + emit_leave_runtime(0); +} + +void BeamModuleAssembler::emit_timeout() { + emit_enter_runtime(0); + + a.mov(ARG1, c_p); + runtime_call<1>(beam_jit_timeout); + + emit_leave_runtime(0); +} diff --git a/erts/emulator/beam/jit/arm/instr_select.cpp b/erts/emulator/beam/jit/arm/instr_select.cpp new file mode 100644 index 000000000000..b5a4bb290cb0 --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_select.cpp @@ -0,0 +1,510 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include +#include + +#include "beam_asm.hpp" + +using namespace asmjit; + +template +static constexpr bool isInt13(T value) { + typedef typename std::make_unsigned::type U; + typedef typename std::make_signed::type S; + + return Support::isUInt12(U(value)) || Support::isUInt12(-S(value)); +} + +/* The `cmp`/`cmn` instructions in AArch64 only accept 12-bit unsigned immediate + * values (`cmn` negating said immediate, giving us an effective range of 13 + * bit signed). That means that to compare most atoms, the atom number to be + * compared must be loaded into a temporary register. + * + * We can use the immediate form of `cmp`/`cmn` for more values if we untag + * both the source value and the values to be compared. + * + * This function finds the `base` and `shift` that result in the most number + * of elements fitting in a 13-bit immediate. */ +static std::pair plan_untag(const Span &args) { + auto left = args.begin(), right = args.begin(); + auto best_left = left, best_right = right; + int count, shift; + + count = args.size() / 2; + + ASSERT(left->isImmed() && (args.begin() + count)->isLabel()); + ASSERT(left->isSmall() || right->isAtom()); + + shift = left->isSmall() ? _TAG_IMMED1_SIZE : _TAG_IMMED2_SIZE; + + while (right < (args.begin() + count)) { + auto distance = std::distance(left, right); + UWord left_value, mid_value, right_value; + + left_value = left->as().get() >> shift; + mid_value = (left + distance / 2)->as().get() >> shift; + right_value = right->as().get() >> shift; + + if (isInt13(left_value - mid_value) && + isInt13(right_value - mid_value)) { + if (distance > std::distance(best_left, best_right)) { + best_right = right; + best_left = left; + } + + right++; + } else { + left++; + } + } + + auto distance = std::distance(best_left, best_right); + + /* Skip everything if the best run is too short, untagging has its costs + * too. */ + if (distance <= 6) { + return std::make_pair(0, 0); + } + + /* Apply neither shift nor base if the best run doesn't need it: we're more + * likely to lose by rebasing/shifting. */ + if (isInt13(best_left->as().get()) && + isInt13(best_right->as().get())) { + return std::make_pair(0, 0); + } + + /* Skip rebasing if the best run doesn't need it after shifting. */ + if (isInt13(best_left->as().get() >> shift) && + isInt13(best_right->as().get() >> shift)) { + return std::make_pair(0, shift); + } + + auto mid_value = (best_left + distance / 2)->as().get(); + return std::make_pair(mid_value, shift); +} + +const std::vector BeamModuleAssembler::emit_select_untag( + const ArgSource &Src, + const Span &args, + a64::Gp comparand, + Label fail, + UWord base, + int shift) { + ASSERT(base != 0 || shift > 0); + + /* Emit code to test that the source value has the correct type and + * untag it. */ + comment("(comparing untagged+rebased values)"); + if ((args.front().isSmall() && always_small(Src)) || + (args.front().isAtom() && exact_type(Src))) { + comment("(skipped type test)"); + } else { + if (args.front().isSmall()) { + a.and_(TMP1, comparand, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED1_SMALL)); + } else { + ASSERT(args.front().isAtom()); + a.and_(TMP1, comparand, imm(_TAG_IMMED2_MASK)); + a.cmp(TMP1, imm(_TAG_IMMED2_ATOM)); + } + + a.b_ne(resolve_label(fail, disp1MB)); + } + + if (shift != 0) { + a.lsr(ARG1, comparand, imm(shift)); + base >>= shift; + + comparand = ARG1; + } + + std::vector result(args.begin(), args.end()); + int count = args.size() / 2; + + if (base != 0) { + sub(ARG1, comparand, base); + + /* The values will always be ordered differently after adjusting the + * base, so we have to sort them again. + * + * This is rather annoying because the labels and values can't be + * sorted together. Perhaps we should diverge from the other platforms, + * keeping them together just on ARM? */ + std::vector sorted_indexes(count); + std::iota(sorted_indexes.begin(), sorted_indexes.end(), 0); + std::sort(sorted_indexes.begin(), + sorted_indexes.end(), + [&](int lhs, int rhs) { + auto lhs_value = + (args[lhs].as().get() >> shift) - base; + auto rhs_value = + (args[rhs].as().get() >> shift) - base; + return lhs_value < rhs_value; + }); + + for (auto i = 0; i < count; i++) { + const auto &src_value = args[sorted_indexes[i]]; + const auto &src_label = args[sorted_indexes[i] + count]; + auto &dst_value = result[i]; + auto &dst_label = result[i + count]; + + /* The value won't be a valid immediate after shifting, so we + * change it to a word. */ + dst_value = + ArgWord((src_value.as().get() >> shift) - base); + dst_label = src_label; + } + } else { + /* Fast-path for when a shift alone is enough, it won't affect the + * order. */ + for (auto i = 0; i < count; i++) { + auto &dst_value = result[i]; + auto &dst_label = result[i + count]; + + dst_value = ArgWord(args[i].as().get() >> shift); + dst_label = args[i + count]; + } + } + + ASSERT(std::is_sorted(result.begin(), + result.begin() + count, + [](const ArgWord &lhs, const ArgWord &rhs) { + return lhs.get() < rhs.get(); + })); + + return result; +} + +void BeamModuleAssembler::emit_linear_search(arm::Gp comparand, + Label fail, + const Span &args) { + int count = args.size() / 2; + + for (int i = 0; i < count; i++) { + const ArgVal &value = args[i]; + const ArgVal &label = args[i + count]; + + if ((i % 128) == 0) { + /* Checking veneers on the first element is intentional. */ + check_pending_stubs(); + } + + cmp_arg(comparand, value); + a.b_eq(resolve_beam_label(label, disp1MB)); + } + + /* An invalid label means fallthrough to the next instruction. */ + if (fail.isValid()) { + a.b(resolve_label(fail, disp128MB)); + } +} + +void BeamModuleAssembler::emit_i_select_tuple_arity(const ArgRegister &Src, + const ArgLabel &Fail, + const ArgWord &Size, + const Span &args) { + auto src = load_source(Src, TMP1); + + emit_is_boxed(resolve_beam_label(Fail, dispUnknown), Src, src.reg); + + arm::Gp boxed_ptr = emit_ptr_val(TMP1, src.reg); + a.ldur(TMP1, emit_boxed_val(boxed_ptr, 0)); + + if (masked_types(Src) == BeamTypeId::Tuple) { + comment("simplified tuple test since the source is always a tuple " + "when boxed"); + } else { + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.tst(TMP1, imm(_TAG_HEADER_MASK)); + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } + + Label fail = rawLabels[Fail.get()]; + emit_linear_search(TMP1, fail, args); +} + +void BeamModuleAssembler::emit_i_select_val_lins(const ArgSource &Src, + const ArgVal &Fail, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + Label fail, next; + + /* + * To keep the code simpler, we will drop down a level and + * use rawLabels. That will allow us to use Label to represent + * a label present in the BEAM file or a label created here. + */ + + if (Fail.isLabel()) { + next = fail = rawLabels[Fail.as().get()]; + } else { + ASSERT(Fail.isNil()); + + /* Fail is [], meaning that if none of the values match, + * we should fall through to the next instruction. + * + * We set `next` to a label that will be located after the + * instructions for the linear search. That label is needed if + * values are untagged and a type test is emitted to skip the + * comparisons of the untagged values in case the type is + * wrong. + * + * We intentionally do not initialize the Label `fail` + * as an indication for emit_optimized_three_way_select() and + * emit_linear_search() that not branch is needed at the end + * of the linear search. + */ + next = a.newLabel(); + } + + auto src = load_source(Src, ARG1); + + auto plan = plan_untag(args); + auto base = plan.first; + auto shift = plan.second; + + if (base == 0 && shift == 0) { + if (!emit_optimized_three_way_select(src.reg, fail, args)) { + emit_linear_search(src.reg, fail, args); + } + } else { + auto untagged = + emit_select_untag(Src, args, src.reg, next, base, shift); + + if (!emit_optimized_three_way_select(ARG1, fail, untagged)) { + emit_linear_search(ARG1, fail, untagged); + } + } + + if (!Fail.isLabel()) { + bind_veneer_target(next); + } +} + +void BeamModuleAssembler::emit_i_select_val_bins(const ArgSource &Src, + const ArgVal &Fail, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + + int count = args.size() / 2; + Label fail; + + /* See the comment in emit_i_select_val_lins() for an explanation + * why we use raw labels. */ + if (Fail.isLabel()) { + fail = rawLabels[Fail.as().get()]; + } else { + ASSERT(Fail.isNil()); + fail = a.newLabel(); + } + + comment("Binary search in table of %lu elements", count); + + auto src = load_source(Src, ARG1); + + auto plan = plan_untag(args); + auto base = plan.first; + auto shift = plan.second; + + if (base == 0 && shift == 0) { + emit_binsearch_nodes(src.reg, 0, count - 1, fail, args); + } else { + auto untagged = + emit_select_untag(Src, args, src.reg, fail, base, shift); + emit_binsearch_nodes(ARG1, 0, count - 1, fail, untagged); + } + + if (!Fail.isLabel()) { + bind_veneer_target(fail); + } +} + +/* + * Emit code for a binary search through an interval Left <= Right of + * the i_select_val argument vector `args`. + */ +void BeamModuleAssembler::emit_binsearch_nodes(arm::Gp reg, + size_t Left, + size_t Right, + Label fail, + const Span &args) { + ASSERT(Left <= Right); + ASSERT(Right < args.size() / 2); + + const size_t remaining = (Right - Left + 1); + const size_t mid = (Left + Right) >> 1; + const size_t count = args.size() / 2; + + if (remaining <= 10) { + /* Measurements on randomly generated select_val instructions + have shown that linear search is faster than binary search + when there are ten or less elements. + */ + std::vector shrunk; + + comment("Linear search in [%lu..%lu], %lu elements", + Left, + Right, + remaining); + + shrunk.reserve(remaining * 2); + shrunk.insert(shrunk.end(), + args.begin() + Left, + args.begin() + Left + remaining); + shrunk.insert(shrunk.end(), + args.begin() + Left + count, + args.begin() + count + Left + remaining); + + emit_linear_search(reg, fail, shrunk); + + return; + } + + comment("Subtree [%lu..%lu], pivot %lu", Left, Right, mid); + + check_pending_stubs(); + + cmp_arg(reg, args[mid]); + + auto &lbl = args[mid + count]; + + /* The search has failed if Left == Right, but that should never + * happen since we revert to a linear search when there are + * ten or less elements. */ + ASSERT(Left != Right); + ASSERT(Left != mid); + + a.b_eq(resolve_beam_label(lbl, disp1MB)); + + Label right_tree = a.newLabel(); + a.b_hs(resolve_label(right_tree, disp1MB)); + + emit_binsearch_nodes(reg, Left, mid - 1, fail, args); + + bind_veneer_target(right_tree); + emit_binsearch_nodes(reg, mid + 1, Right, fail, args); +} + +void BeamModuleAssembler::emit_i_jump_on_val(const ArgSource &Src, + const ArgVal &Fail, + const ArgWord &Base, + const ArgWord &Size, + const Span &args) { + Label fail; + auto src = load_source(Src, TMP1); + + ASSERT(Size.get() == args.size()); + + if (always_small(Src)) { + comment("(skipped type test)"); + } else { + a.and_(TMP3, src.reg, imm(_TAG_IMMED1_MASK)); + a.cmp(TMP3, imm(_TAG_IMMED1_SMALL)); + + if (Fail.isLabel()) { + a.b_ne(resolve_beam_label(Fail, disp1MB)); + } else { + /* NIL means fallthrough to the next instruction. */ + ASSERT(Fail.isNil()); + + fail = a.newLabel(); + a.b_ne(fail); + } + } + + a.asr(TMP1, src.reg, imm(_TAG_IMMED1_SIZE)); + + if (Base.get() != 0) { + if (Support::isUInt12((Sint)Base.get())) { + a.sub(TMP1, TMP1, imm(Base.get())); + } else { + mov_imm(TMP3, Base.get()); + a.sub(TMP1, TMP1, TMP3); + } + } + + a.cmp(TMP1, imm(args.size())); + if (Fail.isLabel()) { + a.b_hs(resolve_beam_label(Fail, disp1MB)); + } else { + a.b_hs(fail); + } + + embed_vararg_rodata(args, TMP2); + a.ldr(TMP3, arm::Mem(TMP2, TMP1, arm::lsl(3))); + a.br(TMP3); + + if (Fail.getType() == ArgVal::Immediate) { + a.bind(fail); + } +} + +/* + * Attempt to optimize the case when a select_val has exactly two + * values which only differ by one bit and they both branch to the + * same label. + * + * The optimization makes use of the observation that (V == X || V == + * Y) is equivalent to (V | (X ^ Y)) == (X | Y) when (X ^ Y) has only + * one bit set. + * + * Return true if the optimization was possible. + */ +bool BeamModuleAssembler::emit_optimized_three_way_select( + arm::Gp reg, + Label fail, + const Span &args) { + if (args.size() != 4 || (args[2] != args[3])) { + return false; + } + + uint64_t x = args[0].isImmed() ? args[0].as().get() + : args[0].as().get(); + uint64_t y = args[1].isImmed() ? args[1].as().get() + : args[1].as().get(); + uint64_t combined = x | y; + uint64_t diff = x ^ y; + + ArgWord val(combined); + + if ((diff & (diff - 1)) != 0) { + return false; + } + + comment("(Src == 0x%x || Src == 0x%x) <=> (Src | 0x%x) == 0x%x", + x, + y, + diff, + combined); + + a.orr(TMP1, reg, imm(diff)); + cmp_arg(TMP1, val); + a.b_eq(resolve_beam_label(args[2], disp1MB)); + + /* An invalid label means fallthrough to the next instruction. */ + if (fail.isValid()) { + a.b(resolve_label(fail, disp128MB)); + } + + return true; +} diff --git a/erts/emulator/beam/jit/arm/instr_trace.cpp b/erts/emulator/beam/jit/arm/instr_trace.cpp new file mode 100644 index 000000000000..1db21b74460f --- /dev/null +++ b/erts/emulator/beam/jit/arm/instr_trace.cpp @@ -0,0 +1,218 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "beam_common.h" +#include "erl_bif_table.h" +#include "beam_bp.h" +}; + +/* This function is jumped to from the export entry of a function. + * + * ARG1 = export entry */ +void BeamGlobalAssembler::emit_generic_bp_global() { + /* Enter an Erlang frame to make the stack consistent with local + * breakpoints. */ + emit_enter_erlang_frame(); + + lea(ARG2, arm::Mem(ARG1, offsetof(Export, info))); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + /* ARG2 is already set above */ + load_x_reg_array(ARG3); + runtime_call<3>(erts_generic_breakpoint); + + emit_leave_runtime(); + + /* This is technically a tail call so we must leave the current frame + * before jumping. Note that we might not leave the frame we entered + * earlier in this function, but one added by erts_generic_breakpoint. */ + emit_leave_erlang_frame(); + a.br(ARG1); +} + +/* This function is called from the module header, which is in turn called from + * the prologue of the traced function. As such, the real return address is at + * SP+8 rather than LR (x30). + * + * See beam_asm.h for more details */ +void BeamGlobalAssembler::emit_generic_bp_local() { + a.ldr(ARG2, arm::Mem(a64::sp, 8)); + + /* Stash return address for later use in `debug_bp` */ + a.str(ARG2, TMP_MEM1q); + + /* Our actual return address is valid (and word-aligned), but it points + * just after the trampoline word so we'll need to skip that to find our + * ErtsCodeInfo. */ + a.sub(ARG2, ARG2, imm(BEAM_ASM_FUNC_PROLOGUE_SIZE + sizeof(ErtsCodeInfo))); + + emit_enter_runtime_frame(); + emit_enter_runtime(); + + a.mov(ARG1, c_p); + /* ARG2 is already set above */ + load_x_reg_array(ARG3); + runtime_call<3>(erts_generic_breakpoint); + + emit_leave_runtime(); + + a.cmp(ARG1, imm(BeamOpCodeAddr(op_i_debug_breakpoint))); + a.b_eq(labels[debug_bp]); + + emit_leave_runtime_frame(); + a.ret(a64::x30); +} + +/* This function is called from the module header which is called from the + * prologue of the function to trace. See beam_asm.h for more details + * + * The only place that we can come to here is from generic_bp_local */ +void BeamGlobalAssembler::emit_debug_bp() { + Label error = a.newLabel(); + + /* Read and adjust the return address we saved in generic_bp_local. */ + a.ldr(ARG2, TMP_MEM1q); + a.sub(ARG2, ARG2, imm(BEAM_ASM_FUNC_PROLOGUE_SIZE + sizeof(ErtsCodeMFA))); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG3); + a.mov(ARG4, imm(am_breakpoint)); + runtime_call<4>(call_error_handler); + + emit_leave_runtime(); + + /* We skip two runtime frames (ours and the one entered in the module + * header) so that we can call the error handler's code instead of + * `call_nif_early`, if necessary. */ + emit_leave_runtime_frame(); + emit_leave_runtime_frame(); + + a.cbz(ARG1, error); + + emit_leave_erlang_frame(); + branch(emit_setup_dispatchable_call(ARG1)); + + a.bind(error); + { + a.ldr(ARG2, TMP_MEM1q); + mov_imm(ARG4, 0); + + a.b(labels[raise_exception_shared]); + } +} + +static void return_trace(Process *c_p, + ErtsCodeMFA *mfa, + Eterm val, + ErtsTracer *tracer) { + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + erts_trace_return(c_p, mfa, val, tracer); + ERTS_REQ_PROC_MAIN_LOCK(c_p); +} + +void BeamModuleAssembler::emit_return_trace() { + a.ldr(ARG2, getYRef(0)); + a.mov(ARG3, XREG0); + lea(ARG4, getYRef(1)); + + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 1); + emit_enter_runtime(1); + + a.mov(ARG1, c_p); + runtime_call<4>(return_trace); + + emit_leave_runtime(1); + + emit_deallocate(ArgVal(ArgVal::Word, BEAM_RETURN_TRACE_FRAME_SZ)); + emit_return(); +} + +void BeamModuleAssembler::emit_i_call_trace_return() { + /* Pass prev_info if present (is a CP), otherwise null. */ + a.ldr(ARG2, getYRef(0)); + mov_imm(ARG4, 0); + + a.tst(ARG2, imm(_CPMASK)); + a.sub(ARG2, ARG2, imm(sizeof(ErtsCodeInfo))); + a.csel(ARG2, ARG2, ARG4, arm::CondCode::kEQ); + a.ldr(ARG3, getYRef(1)); + + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 1); + emit_enter_runtime(1); + + a.mov(ARG1, c_p); + runtime_call<3>(erts_call_trace_return); + + emit_leave_runtime(1); + + emit_deallocate(ArgVal(ArgVal::Word, BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ)); + emit_return(); +} + +void BeamModuleAssembler::emit_i_return_to_trace() { + ERTS_CT_ASSERT(ERTS_HIGHEST_CALLEE_SAVE_XREG >= 1); + emit_enter_runtime(1); + + a.mov(ARG1, c_p); + runtime_call<1>(beam_jit_return_to_trace); + + emit_leave_runtime(1); + + emit_deallocate(ArgVal(ArgVal::Word, BEAM_RETURN_TO_TRACE_FRAME_SZ)); + emit_return(); +} + +void BeamModuleAssembler::emit_i_hibernate() { + Label error = a.newLabel(); + + emit_enter_runtime(3); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<2>(erts_hibernate); + + emit_leave_runtime(3); + + a.cbz(ARG1, error); + + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, flags))); + a.and_(TMP1, TMP1, imm(~F_HIBERNATE_SCHED)); + a.str(TMP1.w(), arm::Mem(c_p, offsetof(Process, flags))); + a.b(resolve_fragment(ga->get_do_schedule(), disp128MB)); + + a.bind(error); + emit_raise_exception(&BIF_TRAP_EXPORT(BIF_hibernate_3)->info.mfa); +} diff --git a/erts/emulator/beam/jit/arm/ops.tab b/erts/emulator/beam/jit/arm/ops.tab new file mode 100644 index 000000000000..6d27a18c2db4 --- /dev/null +++ b/erts/emulator/beam/jit/arm/ops.tab @@ -0,0 +1,1489 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2023. 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% +# + +# +# Types that should never be used in specific operations. +# + +FORBIDDEN_TYPES=hQ + +# +# The instructions that follows are only known by the loader and the emulator. +# They can be changed without recompiling old Beam files. +# +# Instructions starting with a "i_" prefix are instructions produced by +# instruction transformations; thus, they never occur in BEAM files. +# + +# The too_old_compiler/0 instruction is specially handled in beam_load.c +# to produce a user-friendly message informing the user that the module +# needs to be re-compiled with a modern compiler. + +too_old_compiler/0 +too_old_compiler | never() => _ + +# In R9C and earlier, the loader used to insert special instructions inside +# the module_info/0,1 functions. (In R10B and later, the compiler inserts +# an explicit call to an undocumented BIF, so that no loader trickery is +# necessary.) Since the instructions don't work correctly in R12B, simply +# refuse to load the module. + +func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler +func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler + +# The undocumented and unsupported guard BIF is_constant/1 was removed +# in R13. The is_constant/2 operation is marked as obsolete in genop.tab, +# so the loader will automatically generate a too_old_compiler message +# it is used, but we need to handle the is_constant/1 BIF specially here. + +bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler + +# +# All the other instructions. +# + +%cold +# An unaligned label. The address of an unaligned label must never be saved +# on the stack or used in a context where it can be confused with an Erlang term. + +label L + +# An label aligned to a certain boundary. This is used in two cases: +# +# * When the label points to the start of a function, as the ErtsCodeInfo +# struct must be word-aligned. +# * When the address is stored on the stack or otherwise needs to be properly +# tagged as a continuation pointer. +aligned_label L t + +i_func_info I a a I +int_code_end +nif_start + +i_generic_breakpoint +i_debug_breakpoint +i_call_trace_return +i_return_to_trace +trace_jump W +i_yield +%hot + +return + +# +# A tail call will not refer to the current function on error unless it's a +# BIF, so we can omit the line instruction for non-BIFs. +# + +move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => + move S X0 | call_ext_last Ar Func D +move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => + move S X0 | call_ext_only Ar Func + +move S X0=x==0 | line Loc | call_last Ar Func D => + move S X0 | call_last Ar Func D +move S X0=x==0 | line Loc | call_only Ar Func => + move S X0 | call_only Ar Func + +# The line number in int_func_start/5 can be NIL. +func_line n => empty_func_line + +empty_func_line +func_line I + +line n => _ +line I + +allocate t t +allocate_heap t I t + +deallocate t + +init y + +trim t t + +test_heap I t + +# Translate instructions generated by a compiler before OTP 24. +allocate_zero Ns Live => allocate_heap_zero Ns u Live +allocate_heap_zero Ns Nh Live => allocate_heap_zero(Ns, Nh, Live) + +init_yregs I * + +# Selecting values. + +# The size of the dispatch code for a jump table is at least 40 bytes +# (8 instructions + one 64-bit word for the pointer to the +# table). Therefore we shouldn't use a jump table if there are too few +# values. + +select_val S Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => + jump_tab(S, Fail, Size, Rest) + +is_integer Fail=f S=s | select_val S2 Fail2 Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + use_jump_tab(Size, Rest, 6) => + jump_tab(S, Fail, Size, Rest) + +is_integer TypeFail=f S=s | select_val S2 Fail=fn Size=u Rest=* | + equal(S, S2) | + mixed_types(Size, Rest) => + split_values(S, TypeFail, Fail, Size, Rest) + +select_val S Fail=fn Size=u Rest=* | mixed_types(Size, Rest) => + split_values(S, Fail, Fail, Size, Rest) + +is_integer Fail=f S=d | select_val S2 Fail2 Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) + +is_atom Fail=f S=d | select_val S2 Fail2 Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) + +select_val S Fail=fn Size=u Rest=* | floats_or_bignums(Size, Rest) => + select_literals(S, Fail, Size, Rest) + +select_val S Fail=fn Size=u Rest=* | fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) + +is_tuple Fail=f S=d | select_tuple_arity S2 Fail2 Size=u Rest=* | + equal(Fail, Fail2) | equal(S, S2) => + select_tuple_arity(S, Fail, Size, Rest) + +select_tuple_arity S=d Fail=f Size=u Rest=* => + select_tuple_arity(S, Fail, Size, Rest) + +i_select_val_bins s fn I * + +i_select_val_lins s fn I * + +i_select_tuple_arity S f I * + +i_jump_on_val s fn W I * + +is_number f s + +jump f + +# +# List matching instructions. The combination of test for a nonempty list +# followed by get_{list/hd/tl} are common, so we will optimize that. +# +is_nonempty_list Fail nqia => jump Fail + +is_nonempty_list f S + +get_list S d d +get_hd S d +get_tl S d + +# Old-style catch. +catch y H +catch_end y + +# Try/catch. +try Y F => catch Y F + +try_case y +try_end y + +try_case_end s + +# Destructive set tuple element + +set_tuple_element s S P + +# +# Get tuple element. Since this instruction is frequently used, we will try +# to only fetch the pointer to the tuple once for a sequence of BEAM +# instructions that fetch multiple elements from the same tuple. +# + +current_tuple/1 +current_tuple/2 + +is_tuple Fail=f Src | test_arity Fail2 Src2 Arity | + equal(Fail, Fail2) | equal(Src, Src) => + i_is_tuple_of_arity Fail Src Arity | current_tuple Src + +test_arity Fail Src Arity => i_test_arity Fail Src Arity | current_tuple Src + +is_tuple NotTupleFail Src | + is_tagged_tuple WrongRecordFail Tuple Arity Atom | + equal(Src, Tuple) => + i_is_tagged_tuple_ff NotTupleFail WrongRecordFail Src Arity Atom | + current_tuple Src + +is_tagged_tuple Fail Tuple Arity Atom => + i_is_tagged_tuple Fail Tuple Arity Atom | current_tuple Tuple + +is_tuple Fail=f Src => i_is_tuple Fail Src | current_tuple Src + +i_is_tuple_of_arity f s A +i_test_arity f s A + +i_is_tagged_tuple f s A a +i_is_tagged_tuple_ff f f s A a + +i_is_tuple f s + +# Generate instruction sequence for fetching the tuple element and remember +# that we have a current tuple pointer. + +get_tuple_element Tuple Pos Dst => + load_tuple_ptr Tuple | + i_get_tuple_element Tuple Pos Dst | + current_tuple Tuple + +current_tuple Tuple | get_tuple_element Tuple2 Pos Dst | + equal(Tuple, Tuple2) => + i_get_tuple_element Tuple Pos Dst | + current_tuple Tuple + +# Drop the current_tuple instruction if the tuple is overwritten. +i_get_tuple_element Tuple Pos Tuple2 | current_tuple Tuple3 | + equal(Tuple, Tuple2) | equal(Tuple, Tuple3) => + i_get_tuple_element Tuple Pos Tuple + +# This is a current_tuple instruction instruction not followed by +# get_tuple_element. Invalidate the current tuple pointer. + +current_tuple Tuple => _ + +i_get_tuple_element Tuple Pos Dst | current_tuple d | swap R1 R2 => + i_get_tuple_element Tuple Pos Dst | swap R1 R2 + +load_tuple_ptr s + +# If positions are in consecutive memory, fetch and store two words at +# once. +## FIXME: Fix this bug in maint, too. +i_get_tuple_element Tuple Pos1 Dst1 | + current_tuple Tuple2 | + get_tuple_element Tuple3 Pos2 Dst2 | + equal(Tuple, Tuple2) | equal(Tuple, Tuple3) | + consecutive_words(Pos1, Pos2) | distinct(Dst1, Dst2) => + get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | + current_tuple Tuple Dst2 + +# Drop the current_tuple instruction if the tuple is overwritten. +current_tuple Tuple Tuple2 | equal(Tuple, Tuple2) => _ +current_tuple Tuple Dst => current_tuple Tuple + +# The first operand will only be used in the debug-compiled runtime +# system to verify that the register holding the tuple pointer agrees +# with the source tuple operand. +i_get_tuple_element s P S +get_two_tuple_elements s P S S + +i_get_tuple_element Tuple Pos Dst | swap Reg1 Reg2 | equal(Dst, Reg1) => + get_tuple_element_swap Tuple Pos Dst Reg2 + +i_get_tuple_element Tuple Pos Dst | swap Reg2 Reg1 | equal(Dst, Reg1) => + get_tuple_element_swap Tuple Pos Dst Reg2 + +get_tuple_element_swap s P d d + +# +# Exception raising instructions. Infrequently executed. +# + +%cold +case_end s + +badmatch s + +if_end + +badrecord s + +raise s s + +# Workaround the limitation that generators must always return at least one +# instruction. +delete_me/0 +delete_me => _ + +system_limit/1 +system_limit p => system_limit_body +system_limit Fail=f => jump Fail + +system_limit_body + +%hot + +# +# Optimize moves of consecutive memory addresses. +# +move Src=c Dst => i_move Src Dst +move Src SrcDst | move SrcDst2 Dst | + equal(SrcDst, SrcDst2) => + i_move Src SrcDst | move SrcDst Dst + +# Optimize two moves from X registers to Y registers when destination +# Y registers are consecutive. + +move S1=x D1=y | move S2=x D2=y | consecutive_words(D1, D2) => + store_two_xregs S1 D1 S2 D2 +move S1=x D1=y | move S2=x D2=y | consecutive_words(D2, D1) => + store_two_xregs S2 D2 S1 D1 + +# Optimize two moves from Y registers to X registers when source Y +# registers are consecutive. + +move S1=y D1=x | move S2=y D2=x | + consecutive_words(S1, S2) | + distinct(D1, D2) => + load_two_xregs S1 D1 S2 D2 + +move S1=y D1=x | move S2=y D2=x | + consecutive_words(S2, S1) | + distinct(D1, D2) => + load_two_xregs S2 D2 S1 D1 + +# Optimize two moves of Y registers when destinations are consecutive. +move S1=y D1=y | move S2=y D2=y | + consecutive_words(D1, D2) => + move_two_yregs S1 D1 S2 D2 + +move S1=y D1=y | move S2=y D2=y | + consecutive_words(D2, D1) => + move_two_yregs S2 D2 S1 D1 + +move Src Dst | trim N u => move_trim Src Dst N + +move_trim s d t + +move Src Dst => i_move Src Dst + +i_move s d +store_two_xregs x y x y +load_two_xregs y x y x +move_two_yregs y y y y + +# +# Swap instructions. +# + +swap R1 R2 | swap R2Other R3 | equal(R2, R2Other) => swap2 R1 R2 R3 +swap R1 R2 | swap R1Other R3 | equal(R1, R1Other) => swap2 R2 R1 R3 +swap R1 R2 | swap R3 R1Other | equal(R1, R1Other) => swap2 R2 R1 R3 +swap R1 R2 | swap R3 R2Other | equal(R2, R2Other) => swap2 R1 R2 R3 + +swap2 R1 R2 R3 | swap R3Other R4 | + equal(R3, R3Other) => + swap3 R1 R2 R3 R4 +swap2 R1 R2 R3 | swap R4 R3Other | + equal(R3, R3Other) => + swap3 R1 R2 R3 R4 + +swap3 R1 R2 R3 R4 | swap R4Other R5 | + equal(R4, R4Other) => + swap4 R1 R2 R3 R4 R5 +swap3 R1 R2 R3 R4 | swap R5 R4Other | + equal(R4, R4Other) => + swap4 R1 R2 R3 R4 R5 + +swap d d +swap2 d d d +swap3 d d d d +swap4 d d d d d + +# +# Receive operations. We conservatively align all labels before any +# of the receive instructions. +# +# As the labels may be stored in the process structure, we must align them to +# the nearest 4-byte boundary to ensure they're properly tagged as continuation +# pointers. +# + +label L | loop_rec Fail Reg => + aligned_label L u=4 | loop_rec Fail Reg +label L | wait_timeout Fail Src => + aligned_label L u=4 | wait_timeout Fail Src +label L | wait Fail => + aligned_label L u=4 | wait Fail +label L | timeout => + aligned_label L u=4 | timeout + +loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail + +aligned_label L A | wait_timeout Fail Src | smp_already_locked(L) => + aligned_label L A | wait_timeout_locked Src Fail +wait_timeout Fail Src => wait_timeout_unlocked Src Fail + +aligned_label L A | wait Fail | smp_already_locked(L) => + aligned_label L A | wait_locked Fail +wait Fail => wait_unlocked Fail + +aligned_label L A | timeout | smp_already_locked(L) => + aligned_label L A | timeout_locked + +remove_message +timeout +timeout_locked +i_loop_rec f +loop_rec_end f +wait_locked f +wait_unlocked f + +# Note that a timeout value must fit in 32 bits. +wait_timeout_unlocked s f +wait_timeout_locked s f + +send + +# +# Optimized comparisons with one immediate/literal operand. +# + +is_eq_exact Lbl LHS RHS | equal(LHS, RHS) => _ +is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C + +is_eq_exact Lbl R=xy n => is_nil Lbl R + +is_ne_exact Lbl LHS RHS | equal(LHS, RHS) => jump Lbl +is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C + +is_eq_exact f s s + +is_ne_exact f s s + +is_integer NotInt N0 | is_ge Small N1=xy Min=i | is_ge Large Max=i N2=xy | + equal(N0, N1) | equal(N1, N2) | + equal(NotInt, Small) | equal(Small, Large) => + is_int_in_range NotInt N0 Min Max + +is_integer NotInt N0 | is_ge Large Max=i N2=xy | is_ge Small N1=xy Min=i | + equal(N0, N1) | equal(N1, N2) | + equal(NotInt, Small) | equal(Small, Large) => + is_int_in_range NotInt N0 Min Max + +is_integer NotInt N0 | is_ge Fail N1=xy Min=i | + equal(N0, N1) | equal(NotInt, Fail) => + is_int_ge NotInt N0 Min + +is_int_in_range f S c c +is_int_ge f S c + +is_ge Small N1=xy Min=i | is_ge Large Max=i N2=xy | equal(N1, N2) => + is_in_range Small Large N1 Min Max + +is_ge Large Max=i N2=xy | is_ge Small N1=xy Min=i | equal(N1, N2) => + is_in_range Small Large N2 Min Max + +is_in_range f f S c c + +is_ge Small N1=xy A=i | is_lt Large B=i N2=xy | equal(N1, N2) => + is_ge_lt Small Large N1 A B + +is_ge_lt f f S c c + +is_ge Fail1 N1=xy A=i | is_ge Fail2 N2=xy B=i | equal(N1, N2) => + is_ge_ge Fail1 Fail2 N1 A B + +is_ge_ge f f S c c + +is_lt f s s +is_ge f s s + +is_eq Fail=f Const=c Reg=xy => is_eq Fail Reg Const +is_eq f s s + +is_ne Fail=f Const=c Reg=xy => is_ne Fail Reg Const +is_ne f s s + +# +# Putting tuples. +# +# Code compiled with OTP 22 and later uses put_tuple2 to +# to construct a tuple. +# + +put_tuple2 S A * + +# +# Putting lists. +# + +put_list Hd1=y Tl Dst | put_list Hd2=y Dst2 Dst3 | + equal(Dst, Dst2) | equal(Dst, Dst3) | + consecutive_words(Hd1, Hd2) => + put_list2 Hd1 Hd2 Tl Dst + +put_list s s d +put_list2 s s s d + +# +# Some more only used by the emulator +# + +%cold +normal_exit +continue_exit +call_bif W +call_bif_mfa a a I +call_nif W W W +call_error_handler +return_trace +%hot + +# +# Type tests. Note that the operands for most type tests are `s` to +# ensure that literal operands will work. The BEAM compiler starting +# from OTP 22 will never emit type tests with literal operands even if +# all optimizations are turned off, but loading unoptimized code from +# older releases and code generated by alternative code generators. +# + +is_integer f s +is_list f s +is_atom f s +is_float f s + +is_nil Fail=f n => _ +is_nil Fail=f qia => jump Fail +is_nil f S + +# XXX Deprecated. +is_bitstr Fail Term => is_bitstring Fail Term + +is_binary f s +is_bitstring f s + +is_reference f s +is_pid f s +is_port f s + +is_boolean f s + +is_function2 f s s + +################################################################# +# External function and bif calls. +################################################################# + +# Expands into call_light_bif/2 +call_light_bif/1 + +# +# The load_nif/2 BIF is an instruction. +# + +call_ext u==2 u$func:erlang:load_nif/2 => + i_load_nif +call_ext_last u==2 u$func:erlang:load_nif/2 D => + i_load_nif | deallocate D | return +call_ext_only u==2 u$func:erlang:load_nif/2 => + i_load_nif | return + +%cold +i_load_nif +%hot + +# +# The call_on_load_function/1 BIF is an instruction. +# + +call_ext u==1 u$func:erlang:call_on_load_function/1 => + i_call_on_load_function +call_ext_last u==1 u$func:erlang:call_on_load_function/1 D => + i_call_on_load_function | deallocate D | return +call_ext_only u==1 u$func:erlang:call_on_load_function/1 => + i_call_on_load_function | return + +%cold +i_call_on_load_function +%hot + +# +# apply/2 is an instruction, not a BIF. +# + +call_ext u==2 u$func:erlang:apply/2 => i_apply_fun +call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D +call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only + +# +# The apply/3 BIF is an instruction. +# + +call_ext u==3 u$func:erlang:apply/3 => i_apply +call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D +call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only + +# +# The yield/0 BIF is an instruction +# + +call_ext u==0 u$func:erlang:yield/0 => i_yield +call_ext_last u==0 u$func:erlang:yield/0 D => i_yield | deallocate D | return +call_ext_only u==0 u$func:erlang:yield/0 => i_yield | return + +# +# The hibernate/3 BIF is an instruction. +# +call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate +call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate +call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate + +call_ext u==0 u$func:os:perf_counter/0 => + i_perf_counter +call_ext_last u==0 u$func:os:perf_counter/0 D => + i_perf_counter | deallocate D | return +call_ext_only u==0 u$func:os:perf_counter/0 => + i_perf_counter | return + +# +# BIFs like process_info/1,2 require up-to-date information about the current +# emulator state, which the ordinary call_light_bif instruction doesn't save. +# + +call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => + i_call_ext Bif +call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => + i_call_ext Bif | deallocate D | return +call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => + allocate u Ar | i_call_ext Bif | deallocate u | return + +# +# The general case for BIFs that have no special requirements. +# + +call_ext u Bif=u$is_bif => + call_light_bif Bif +call_ext_last u Bif=u$is_bif D => + call_light_bif Bif | deallocate D | return +call_ext_only Ar=u Bif=u$is_bif => + allocate u Ar | call_light_bif Bif | deallocate u | return + +# +# Any remaining calls are calls to Erlang functions, not BIFs. +# We rename the instructions to internal names. This is necessary, +# to avoid an end-less loop, because we want to call a few BIFs +# with call instructions. +# + +call_ext Ar Func => i_call_ext Func +call_ext_last Ar Func D => i_call_ext_last Func D +call_ext_only Ar Func => i_call_ext_only Func + +i_validate t + +i_apply +i_apply_last t +i_apply_only + +i_apply_fun +i_apply_fun_last t +i_apply_fun_only + +call_light_bif Bif => call_light_bif Bif Bif +call_light_bif b e + +%cold + +i_hibernate +i_perf_counter + +%hot + +# +# Calls to non-building and guard BIFs. +# + +bif0 u$bif:erlang:self/0 Dst=d => self Dst +bif0 u$bif:erlang:node/0 Dst=d => node Dst + +bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=xy Dst => + is_nonempty_list Fail Src | get_hd Src Dst +bif1 Fail=p Bif=u$bif:erlang:hd/1 Src Dst => + bif_hd Src Dst + +bif_hd s d + +bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=xy Dst => + is_nonempty_list Fail Src | get_tl Src Dst +bif1 Fail=p Bif=u$bif:erlang:tl/1 Src Dst => + bif_tl Src Dst + +bif_tl s d + +bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst) + +bif2 Fail u$bif:erlang:element/2 S1 S2 Dst => bif_element Fail S1 S2 Dst +bif_element j s s d + +bif2 Fail Bif=u$bif:erlang:and/2 Src1 Src2 Dst=d => bif_and Fail Src1 Src2 Dst +bif_and j s s d + +bif2 Fail Bif=u$bif:erlang:or/2 Src1 Src2 Dst=d => bif_or Fail Src1 Src2 Dst +bif_or j s s d + +bif1 Fail Bif=u$bif:erlang:not/1 Src=d Dst=d => bif_not Fail Src Dst +bif_not j S d + +bif1 Fail Bif=u$bif:erlang:node/1 Src=d Dst=d => bif_node Fail Src Dst +bif_node j S d + +gc_bif1 Fail Live Bif=u$bif:erlang:bit_size/1 Src Dst=d => + bif_bit_size Fail Src Dst +bif_bit_size j s d + +gc_bif1 Fail Live Bif=u$bif:erlang:byte_size/1 Src Dst=d => + bif_byte_size Fail Src Dst +bif_byte_size j s d + +bif1 Fail Bif=u$bif:erlang:tuple_size/1 Src=d Dst=d => + bif_tuple_size Fail Src Dst +bif_tuple_size j S d + +bif2 Fail Bif=u$bif:erlang:map_get/2 Src1 Src2=xy Dst=d => + bif_map_get Fail Src1 Src2 Dst +bif_map_get j s s d + +bif2 Fail Bif=u$bif:erlang:is_map_key/2 Key Map=xy Dst=d => + bif_is_map_key Bif Fail Key Map Dst +bif_is_map_key b j s s d + +bif2 Fail Bif=u$bif:erlang:max/2 Src1 Src2 Dst => + bif_max Src1 Src2 Dst +bif2 Fail Bif=u$bif:erlang:min/2 Src1 Src2 Dst => + bif_min Src1 Src2 Dst +bif_max s s d +bif_min s s d + +bif1 Fail Bif S1 Dst | never_fails(Bif) => nofail_bif1 S1 Bif Dst +bif2 Fail Bif S1 S2 Dst | never_fails(Bif) => nofail_bif2 S1 S2 Bif Dst + +bif1 Fail Bif S1 Dst => i_bif1 S1 Fail Bif Dst +bif2 Fail Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst + +nofail_bif2 S1=d S2 Bif Dst | is_eq_exact_bif(Bif) => bif_is_eq_exact S1 S2 Dst +nofail_bif2 S1=d S2 Bif Dst | is_ne_exact_bif(Bif) => bif_is_ne_exact S1 S2 Dst +nofail_bif2 S1 S2 Bif Dst | is_ge_bif(Bif) => bif_is_ge S1 S2 Dst +nofail_bif2 S1 S2 Bif Dst | is_lt_bif(Bif) => bif_is_lt S1 S2 Dst + +i_get_hash c I d +i_get s d + +self d + +node d + +nofail_bif1 s b d +nofail_bif2 s s b d + +i_bif1 s j b d +i_bif2 s s j b d +i_bif3 s s s j b d + +bif_is_eq_exact S s d +bif_is_ne_exact S s d +bif_is_ge s s d +bif_is_lt s s d + +# +# Internal calls. +# + +i_move S=y==0 Dst | call_last Ar P D => move_call_last S Dst P D +i_move S=y==0 Dst | call_ext_last Ar P=u$is_not_bif D => move_call_ext_last S Dst P D + +move_call_last y d f t +move_call_ext_last y d e t + +call Ar Func => i_call Func +call_last Ar Func D => i_call_last Func D +call_only Ar Func => i_call_only Func + +i_call f +i_call_last f t +i_call_only f + +i_call_ext e +i_call_ext_last e t +i_call_ext_only e + +# Fun calls. + +call_fun Arity | deallocate D | return => i_call_fun_last Arity D +call_fun Arity => i_call_fun Arity + +i_call_fun t +i_call_fun_last t t + +call_fun2 Safe Arity Func | deallocate D | return => + i_call_fun2_last Safe Arity Func D +call_fun2 Safe Arity Func => + i_call_fun2 Safe Arity Func + +i_call_fun2 aF t S +i_call_fun2_last aF t S t + +# +# A fun with an empty environment can be converted to a literal. +# As a further optimization, the we try to move the fun to its +# final destination directly. + +make_fun2 OldIndex=u => + make_fun2(OldIndex) +make_fun3 OldIndex=u Dst=d NumFree=u Env=* => + make_fun3(OldIndex, Dst, NumFree, Env) + +%cold + +i_make_fun3 F S t t * + +# Psuedo-instruction for signalling lambda load errors. Never actually runs. +i_lambda_error t + +%hot + +is_function f S +is_function Fail=f c => jump Fail + +# The start and end of a function. +int_func_start/5 +int_func_end/2 + +func_prologue/2 + +int_func_start Func_Label Func_Line M F A | + label Entry_Label | line Entry_Line => + int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label Entry_Line + +int_func_start Func_Label Func_Line M F A | + label Entry_Label => + int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label n + +int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label Entry_Line | + is_mfa_bif(M, F, A) => + i_flush_stubs | + func_line Func_Line | + aligned_label Func_Label u=8 | + i_func_info Func_Label M F A | + aligned_label Entry_Label u=8 | + i_breakpoint_trampoline | + line Entry_Line | + call_bif_mfa M F A + +int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label Entry_Line => + i_flush_stubs | + func_line Func_Line | + aligned_label Func_Label u=8 | + i_func_info Func_Label M F A | + aligned_label Entry_Label u=8 | + i_breakpoint_trampoline | + line Entry_Line | + i_test_yield + +int_func_end Func_Label Entry_Label => + func_end(Func_Label, Entry_Label) + +# Handles yielding on function ingress (rather than on each call). +i_test_yield + +# Ensures that the prior function is large enough to allow NIF patching. +i_nif_padding + +# Flushes veneers prior to entering a new function so we don't have to worry +# about them being emitted in the prologue or NIF padding. +i_flush_stubs + +# Handles tracing, early NIF calls, and so on. +i_breakpoint_trampoline + +# ================================================================ +# New bit syntax matching for fixed sizes (from OTP 26). +# ================================================================ + +bs_match Fail Ctx Size Rest=* => bs_match(Fail, Ctx, Size, Rest) + +i_bs_match Fail Ctx Rest=* | test_heap Need Live => + i_bs_match_test_heap Fail Ctx Need Live Rest + +i_bs_match f S * +i_bs_match_test_heap f S I t * + +# +# The following instruction is specially handled in beam_load.c +# to produce a user-friendly message if a bad bs_match instruction +# is encountered. +# +bad_bs_match/1 +bad_bs_match A | never() => _ + +# ================================================================ +# Bit syntax matching (from R11B). +# ================================================================ + +%warm + +# Matching integers. +bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val + +i_bs_match_string S f W M + +# Fetching integers from binaries. +bs_get_integer2 f S t s t t d + +# Fetching binaries from binaries. +bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => + get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) + +i_bs_get_binary2 S f t s t d +i_bs_get_binary_all2 S f t t d + +# Fetching float from binaries. +bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => + get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) + +bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail + +i_bs_get_float2 S f t s t d + +# Miscellaneous + +bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => + skip_bits2(Fail, Ms, Sz, Unit, Flags) + +i_bs_skip_bits_imm2 f S W +i_bs_skip_bits2 S S f t + +bs_test_tail2 Fail=f Ms=xy o => jump Fail + +bs_test_tail2 f S W + +bs_test_unit f S t + +# Gets a bitstring from the tail of a context. +bs_get_tail S d t + +# New bs_start_match variant for contexts with external position storage. +# +# bs_get/set_position is used to save positions into registers instead of +# "slots" in the context itself, which lets us continue matching even after +# we've passed it off to another function. + +bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => + bs_start_match3 p Src Live Ctx +bs_start_match4 Fail=f Live=u Src=xy Ctx=d => + bs_start_match3 Fail Src Live Ctx + +%if ARCH_64 + +# This instruction nops on 64-bit platforms +bs_start_match4 a==am_resume Live Ctx Dst | equal(Ctx, Dst) => _ +bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst + +%else + +bs_start_match4 a==am_resume Live Ctx Dst => + bs_start_match4 a=am_no_fail Live Ctx Dst + +%endif + +bs_start_match3 Fail=j ica Live Dst => jump Fail +bs_start_match3 Fail Bin Live Dst => i_bs_start_match3 Bin Live Fail Dst + +i_bs_start_match3 S t j d + +# Match context position instructions. 64-bit assumes that all positions can +# fit into an unsigned small. + +%if ARCH_64 + bs_get_position Src Dst Live => i_bs_get_position Src Dst + i_bs_get_position S S + bs_set_position S S +%else + bs_get_position S d t + bs_set_position S S +%endif + +# +# Utf8/utf16/utf32 support. (R12B-5) +# +bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst +i_bs_get_utf8 S f d + +bs_skip_utf8 Fail=f Ms=xy u u => i_bs_skip_utf8 Ms Fail +i_bs_skip_utf8 S f + +bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => get_utf16(Fail, Ms, Flags, Dst) +bs_skip_utf16 Fail=f Ms=xy u Flags=u => skip_utf16(Fail, Ms, Flags) + +i_bs_get_utf16 S f t d +i_bs_skip_utf16 S f t + +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst | equal(Ms, Dst) => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms | + move x Dst +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | + i_bs_validate_unicode_retract Fail Dst Ms +bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms + +i_bs_validate_unicode_retract j s S +%hot + +# ================================================================ +# New binary construction (OTP 25). +# ================================================================ + +bs_create_bin Fail=j Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => + create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) + +i_bs_create_bin j I t d * + +# ================================================================ +# Old instruction for constructing binaries (up to OTP 24). +# ================================================================ + +%warm + +bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail + +bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst + +bs_init2 Fail Sz=u Words Regs Flags Dst => + i_bs_init_heap Sz Words Regs Dst + +bs_init2 Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_fail Sz Fail Regs Dst +bs_init2 Fail Sz Words Regs Flags Dst => + i_bs_init_fail_heap Sz Words Fail Regs Dst + +i_bs_init_fail S j t S + +i_bs_init_fail_heap s I j t S + +i_bs_init W t S + +i_bs_init_heap W I t S + + +bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail + +bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => + i_bs_init_bits Sz Regs Dst +bs_init_bits Fail Sz=u Words Regs Flags Dst => + i_bs_init_bits_heap Sz Words Regs Dst + +bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_bits_fail Sz Fail Regs Dst +bs_init_bits Fail Sz Words Regs Flags Dst => + i_bs_init_bits_fail_heap Sz Words Fail Regs Dst + +i_bs_init_bits_fail S j t S + +i_bs_init_bits_fail_heap s I j t S + +i_bs_init_bits W t S +i_bs_init_bits_heap W I t S + +bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D + +bs_add j s s t x + +bs_append Fail Size Extra Live Unit Bin Flags Dst => + i_bs_append Fail Extra Live Unit Size Bin Dst + +bs_private_append Fail Size Unit Bin Flags Dst => + i_bs_private_append Fail Unit Size Bin Dst + +i_bs_private_append Fail Unit Size Bin Dst=y => + i_bs_private_append Fail Unit Size Bin x | move x Dst + +bs_init_writable + +i_bs_append j I t t s s S +i_bs_private_append j t s S x + +# +# Storing integers into binaries. +# + +bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => + put_integer(Fail, Sz, Unit, Flags, Src) + +i_new_bs_put_integer j S t s +i_new_bs_put_integer_imm s j W t + +# +# Utf8/utf16/utf32 support. (R12B-5) +# + +bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst +bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst + +bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src +bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) + +bs_put_utf32 Fail=j Flags=u Src=s => + i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src + +i_bs_utf8_size s x +i_bs_utf16_size s x + +i_bs_put_utf8 j s +i_bs_put_utf16 j t s + +i_bs_validate_unicode j s + +# +# Storing floats into binaries. +# + +# Will fail. No need to keep the instruction, because bs_add or +# bs_init* would already have raised an exception. +bs_put_float Fail Sz=q Unit Flags Val => _ + +bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => + put_float(Fail, Sz, Unit, Flags, Src) + +i_new_bs_put_float j S t s +i_new_bs_put_float_imm j W t s + +# +# Storing binaries into binaries. +# + +bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => + put_binary(Fail, Sz, Unit, Flags, Src) + +i_new_bs_put_binary j s t s +i_new_bs_put_binary_imm j W s +i_new_bs_put_binary_all s j t + +# +# Warning: The i_bs_put_string and i_new_bs_put_string instructions +# are specially treated in the loader. +# Don't change the instruction format unless you change the loader too. +# + +bs_put_string W M + +# +# New floating point instructions (R8). +# + +fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3 +fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3 +fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3 +fdiv p FR1 FR2 FR3 => i_fdiv FR1 FR2 FR3 +fnegate p FR1 FR2 => i_fnegate FR1 FR2 + +fmove Arg=l Dst=d => fstore Arg Dst +fmove Arg=dq Dst=l => fload Arg Dst + +fstore l d +fload Sq l + +fconv s l + +i_fadd l l l +i_fsub l l l +i_fmul l l l +i_fdiv l l l +i_fnegate l l + +fclearerror => _ +fcheckerror p => _ + +%hot + +# +# New apply instructions in R10B. +# + +apply t +apply_last t t + +# +# Map instructions. First introduced in R17. +# + +# We KNOW that in OTP 18 and higher, a put_map_assoc instruction is +# always preceded by an is_map test. That means that put_map_assoc can +# never fail and does not need any failure label. + +put_map_assoc Fail Map Dst Live Size Rest=* => + i_put_map_assoc Map Dst Live Size Rest +i_put_map_assoc/4 + +sorted_put_map_assoc/4 +i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_assoc Map Dst Live Size Rest + +sorted_put_map_exact/5 +put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_exact F Map Dst Live Size Rest + +sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => + new_map Dst Live Size Rest +sorted_put_map_assoc Src=s Dst Live Size Rest=* => + update_map_assoc Src Dst Live Size Rest + +sorted_put_map_exact Fail Src Dst Live Size Rest=* => + update_map_exact Src Fail Dst Live Size Rest + +new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => + new_small_map_lit(Dst, Live, Size, Rest) + +new_map d t I * +i_new_small_map_lit d t q I * +update_map_assoc s d t I * +update_map_exact s j d t I * + +is_map f s + +## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements + +has_map_fields Fail Src Size Rest=* => + has_map_fields(Fail, Src, Size, Rest) + +## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } + +get_map_elements Fail Src Size=u==2 Rest=* => + get_map_element(Fail, Src, Size, Rest) +get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => + get_map_elements(Fail, Src, Size, Rest) + +i_get_map_elements f s I * + +i_get_map_element_hash Fail Src=c Key Hash Dst => + move Src x | i_get_map_element_hash Fail x Key Hash Dst +i_get_map_element_hash f S c I S + +i_get_map_element Fail Src=c Key Dst => + move Src x | i_get_map_element Fail x Key Dst +i_get_map_element f S S S + +# +# Arithmetic instructions. +# + +gc_bif2 Fail Live u$bif:erlang:splus/2 Src1 Src2 Dst => + i_plus Fail Live Src1 Src2 Dst + +gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => + i_unary_minus Fail Live Src Dst + +gc_bif2 Fail Live u$bif:erlang:sminus/2 Src1 Src2 Dst => + i_minus Fail Live Src1 Src2 Dst + +gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => + i_times Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => + i_m_div Fail Live S1 S2 Dst + +# Fused 'rem'/'div' pair. +gc_bif2 Fail Live u$bif:erlang:rem/2 LHS1 RHS1 Remainder | + gc_bif2 A B u$bif:erlang:intdiv/2 LHS2 RHS2 Quotient | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Remainder) | + distinct(RHS1, Remainder) => + i_rem_div Fail Live LHS1 RHS1 Remainder Quotient + +# As above but with a `line` in between +gc_bif2 Fail Live u$bif:erlang:rem/2 LHS1 RHS1 Remainder | + line Loc | + gc_bif2 A B u$bif:erlang:intdiv/2 LHS2 RHS2 Quotient | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Remainder) | + distinct(RHS1, Remainder) => + i_rem_div Fail Live LHS1 RHS1 Remainder Quotient + +# Fused 'div'/'rem' pair +gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS1 RHS1 Quotient | + gc_bif2 A B u$bif:erlang:rem/2 LHS2 RHS2 Remainder | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Quotient) | + distinct(RHS1, Quotient) => + i_div_rem Fail Live LHS1 RHS1 Quotient Remainder + +# As above but with a `line` in between +gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS1 RHS1 Quotient | + line Loc | + gc_bif2 A B u$bif:erlang:rem/2 LHS2 RHS2 Remainder | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Quotient) | + distinct(RHS1, Quotient) => + i_div_rem Fail Live LHS1 RHS1 Quotient Remainder + +gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => + i_int_div Fail Live S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => + i_rem Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => + i_band Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => + i_bor Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => + i_bxor Fail Live S1 S2 Dst + +gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst => + i_bnot Fail Live Src Dst + +gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => + i_bsr Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => + i_bsl Fail Live S1 S2 Dst + +i_plus j I s s d +i_unary_minus j I s d +i_minus j I s s d +i_times j I s s d + +i_m_div j I s s d + +i_rem_div j I s s d d +i_div_rem j I s s d d +i_int_div j I s s d +i_rem j I s s d + +i_band j I s s d +i_bor j I s s d +i_bxor j I s s d + +i_bnot j I s d + +i_bsr j I s s d +i_bsl j I s s d + +# +# Old guard BIFs that creates heap fragments are no longer allowed. +# +bif1 Fail u$bif:erlang:length/1 s d => too_old_compiler +bif1 Fail u$bif:erlang:size/1 s d => too_old_compiler +bif1 Fail u$bif:erlang:abs/1 s d => too_old_compiler +bif1 Fail u$bif:erlang:float/1 s d => too_old_compiler +bif1 Fail u$bif:erlang:round/1 s d => too_old_compiler +bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler + +# +# Handle the length/1 guard BIF specially to make it trappable. +# + +gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => + i_length_setup Fail Live Src | i_length Fail Live Dst + +i_length_setup j t s +i_length j t d + +# +# Specialized guard BIFs. +# + +gc_bif1 Fail Live Bif=u$bif:erlang:map_size/1 Src Dst=d => bif_map_size Fail Src Dst +bif_map_size j s d + +# +# Guard BIFs. +# +gc_bif1 Fail Live Bif Src Dst => i_bif1 Src Fail Bif Dst +gc_bif2 Fail Live Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst +gc_bif3 Fail Live Bif S1 S2 S3 Dst => i_bif3 S1 S2 S3 Fail Bif Dst + +# +# The following instruction is specially handled in beam_load.c +# to produce a user-friendly message if an unsupported guard BIF is +# encountered. +# +unsupported_guard_bif/3 +unsupported_guard_bif A B C | never() => _ + +# +# R13B03 +# +on_load + +# +# R14A. +# +# Superseded in OTP 24 by 'recv_marker_reserve' and friends. +# + +recv_mark f => i_recv_mark +i_recv_mark + +recv_set Fail | label Lbl | loop_rec Lf Reg => + i_recv_set | label Lbl | loop_rec Lf Reg +i_recv_set + +# +# OTP 21. +# + +build_stacktrace +raw_raise + +# +# Specialized move instructions. Since they don't require a second +# instruction, we have intentionally placed them after any other +# transformation rules that starts with a move instruction in order to +# produce better code for the transformation engine. +# + +move n D=y => init D + +# +# OTP 24 +# + +recv_marker_reserve S +recv_marker_bind S S +recv_marker_clear S +recv_marker_use S + +# +# Mark all intentionally unused macros, predicates, and generators. +# + +# Landing pad for fun calls/apply where we set up arguments and check errors +i_lambda_trampoline F f W W + +# +# OTP 26 +# + +update_record a I s d I * diff --git a/erts/emulator/beam/jit/arm/predicates.tab b/erts/emulator/beam/jit/arm/predicates.tab new file mode 100644 index 000000000000..3a1fa0219b9f --- /dev/null +++ b/erts/emulator/beam/jit/arm/predicates.tab @@ -0,0 +1,130 @@ +// -*- c -*- +// +// %CopyrightBegin% +// +// Copyright Ericsson AB 2020-2023. 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% +// + +pred.is_mfa_bif(M, F, A) { + Export *e; + + ASSERT(M.type == TAG_a && F.type == TAG_a && A.type == TAG_u); + e = erts_active_export_entry(M.val, F.val, A.val); + + if (e != NULL) { + return e->bif_number != -1; + } + + return 0; +} + +pred.never_fails(Bif) { + static Eterm nofail_bifs[] = + {am_Neqeq, + am_Lt, + am_Neq, + am_Eq, + am_Le, + am_Eqeq, + am_Gt, + am_Ge, + am_is_atom, + am_is_boolean, + am_is_binary, + am_is_bitstring, + am_is_float, + am_is_integer, + am_is_list, + am_is_map, + am_is_number, + am_is_pid, + am_is_port, + am_is_reference, + am_is_tuple, + }; + + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + int i; + + if (entry->module != am_erlang) { + return 0; + } + + if (entry->function == am_is_function) { + /* Note that is_function/2 may fail. */ + return entry->arity == 1; + } + + for (i = 0; i < sizeof(nofail_bifs) / sizeof(nofail_bifs[0]); i++) { + if (entry->function == nofail_bifs[i]) { + return 1; + } + } + } + return 0; +} + +pred.consecutive_words(A1, A2) { + return A1.type == A2.type && A1.val + 1 == A2.val; +} + +pred.is_eq_exact_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Eq && entry->arity == 2; + } + return 0; +} + +pred.is_ne_exact_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Neq && entry->arity == 2; + } + return 0; +} + +pred.is_ge_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Ge && entry->arity == 2; + } + return 0; +} + +pred.is_lt_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Lt && entry->arity == 2; + } + return 0; +} diff --git a/erts/emulator/beam/jit/arm/process_main.cpp b/erts/emulator/beam/jit/arm/process_main.cpp new file mode 100644 index 000000000000..8b7ddfa17dee --- /dev/null +++ b/erts/emulator/beam/jit/arm/process_main.cpp @@ -0,0 +1,314 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2022. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "bif.h" +#include "beam_common.h" +#include "code_ix.h" +#include "export.h" +} + +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) +static Process *erts_debug_schedule(ErtsSchedulerData *esdp, + Process *c_p, + int calls) { + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + c_p = erts_schedule(esdp, c_p, calls); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + PROCESS_MAIN_CHK_LOCKS(c_p); + return c_p; +} +#endif + +/* void process_main(ErtsSchedulerData *esdp); */ +void BeamGlobalAssembler::emit_process_main() { + Label context_switch_local = a.newLabel(), + context_switch_simplified_local = a.newLabel(), + do_schedule_local = a.newLabel(), schedule_next = a.newLabel(); + + const arm::Mem start_time_i = + getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time_i)); + const arm::Mem start_time = + getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time)); + + /* Be kind to debuggers and `perf` by setting up a proper stack frame. */ + a.stp(a64::x29, a64::x30, arm::Mem(a64::sp, -16).pre()); + + /* Allocate the register structure on the stack to allow computing the + * runtime stack address from it, greatly reducing the cost of stack + * swapping. */ + a.mov(TMP1, a64::sp); + sub(TMP1, TMP1, sizeof(ErtsSchedulerRegisters) + ERTS_CACHE_LINE_SIZE); + a.and_(TMP1, TMP1, imm(~ERTS_CACHE_LINE_MASK)); + a.mov(a64::sp, TMP1); + a.mov(a64::x29, a64::sp); + + a.str(TMP1, arm::Mem(ARG1, offsetof(ErtsSchedulerData, registers))); + + a.mov(scheduler_registers, a64::sp); + + load_erl_bits_state(ARG1); + runtime_call<1>(erts_bits_init_state); + + /* Save the initial SP of the thread so that we can verify that it + * doesn't grow. */ +#ifdef JIT_HARD_DEBUG + a.mov(TMP1, a64::sp); + a.str(TMP1, getInitialSPRef()); +#endif + + a.str(a64::xzr, start_time_i); + a.str(a64::xzr, start_time); + + mov_imm(c_p, 0); + mov_imm(FCALLS, 0); + mov_imm(ARG3, 0); /* Set reds_used for erts_schedule call */ + + a.b(schedule_next); + + a.bind(do_schedule_local); + { + /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, def_arg_reg[5]))); + a.sub(ARG3, TMP1, FCALLS); + a.b(schedule_next); + } + + /* + * The *next* instruction pointer is provided in ARG3, and must be preceded + * by an ErtsCodeMFA. + */ + a.bind(context_switch_local); + comment("Context switch, unknown arity/MFA"); + { + Sint arity_offset = offsetof(ErtsCodeMFA, arity) - sizeof(ErtsCodeMFA); + + a.ldur(TMP1, arm::Mem(ARG3, arity_offset)); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, arity))); + + a.sub(TMP1, ARG3, imm((Uint)sizeof(ErtsCodeMFA))); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, current))); + + /* !! Fall through !! */ + } + + a.bind(context_switch_simplified_local); + comment("Context switch, known arity and MFA"); + { + Label not_exiting = a.newLabel(); + +#ifdef DEBUG + Label check_i = a.newLabel(); + /* Check that ARG3 is set to a valid CP. */ + a.tst(ARG3, imm(_CPMASK)); + a.b_eq(check_i); + a.udf(1); + a.bind(check_i); +#endif + + a.str(ARG3, arm::Mem(c_p, offsetof(Process, i))); + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, state.value))); + + a.tst(TMP1, imm(ERTS_PSFLG_EXITING)); + a.b_eq(not_exiting); + { + comment("Process exiting"); + + a.adr(TMP1, labels[process_exit]); + a.str(TMP1, arm::Mem(c_p, offsetof(Process, i))); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, arity))); + a.str(ZERO, arm::Mem(c_p, offsetof(Process, current))); + a.b(do_schedule_local); + } + + a.bind(not_exiting); + + /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, def_arg_reg[5]))); + a.sub(FCALLS, TMP1, FCALLS); + + comment("Copy out X registers"); + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<2>(copy_out_registers); + + /* Restore reds_used from FCALLS */ + a.mov(ARG3, FCALLS); + + /* !! Fall through !! */ + } + + a.bind(schedule_next); + comment("schedule_next"); + + { + Label schedule = a.newLabel(), skip_long_schedule = a.newLabel(); + + /* ARG3 contains reds_used at this point */ + + a.ldr(TMP1, start_time); + a.cbz(TMP1, schedule); + { + a.mov(ARG1, c_p); + a.ldr(ARG2, start_time); + + /* Spill reds_used in start_time slot */ + a.str(ARG3, start_time); + + a.ldr(ARG3, start_time_i); + runtime_call<3>(check_monitor_long_schedule); + + /* Restore reds_used */ + a.ldr(ARG3, start_time); + } + + a.bind(schedule); + mov_imm(ARG1, 0); + a.mov(ARG2, c_p); +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) + runtime_call<3>(erts_debug_schedule); +#else + runtime_call<3>(erts_schedule); +#endif + a.mov(c_p, ARG1); + +#ifdef ERTS_MSACC_EXTENDED_STATES + lea(ARG1, erts_msacc_cache); + runtime_call<1>(erts_msacc_update_cache); +#endif + + a.str(ZERO, start_time); + mov_imm(ARG1, &erts_system_monitor_long_schedule); + a.ldr(TMP1, arm::Mem(ARG1)); + a.cbz(TMP1, skip_long_schedule); + + { + /* Enable long schedule test */ + runtime_call<0>(erts_timestamp_millis); + a.str(ARG1, start_time); + a.ldr(TMP1, arm::Mem(c_p, offsetof(Process, i))); + a.str(TMP1, start_time_i); + } + + a.bind(skip_long_schedule); + comment("skip_long_schedule"); + + /* Copy arguments */ + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<2>(copy_in_registers); + + /* Setup reduction counting */ + a.ldr(FCALLS, arm::Mem(c_p, offsetof(Process, fcalls))); + a.str(FCALLS, arm::Mem(c_p, offsetof(Process, def_arg_reg[5]))); + +#ifdef DEBUG + a.str(FCALLS, a64::Mem(c_p, offsetof(Process, debug_reds_in))); +#endif + + comment("check whether save calls is on"); + a.mov(ARG1, c_p); + mov_imm(ARG2, ERTS_PSD_SAVED_CALLS_BUF); + runtime_call<2>(erts_psd_get); + + /* Read the active code index, overriding it with + * ERTS_SAVE_CALLS_CODE_IX when save_calls is enabled (ARG1 != 0). */ + mov_imm(TMP1, &the_active_code_index); + a.ldr(TMP1.w(), arm::Mem(TMP1)); + a.mov(TMP2, imm(ERTS_SAVE_CALLS_CODE_IX)); + a.cmp(ARG1, ZERO); + a.csel(active_code_ix, TMP1, TMP2, arm::CondCode::kEQ); + + /* Start executing the Erlang process. Note that reductions have + * already been set up above. */ + emit_leave_runtime(); + + /* Check if we are just returning from a dirty nif/bif call and if so we + * need to do a bit of cleaning up before continuing. + * + * This relies on `op_call_nif_WWW` / `op_call_bif_W` being encoded as + * UDF(opcode) followed by UDF(0), which we will never emit. */ + a.ldr(ARG1, arm::Mem(c_p, offsetof(Process, i))); + a.ldr(TMP1, arm::Mem(ARG1)); + + ERTS_CT_ASSERT((op_call_nif_WWW & 0xFFFF0000) == 0); + a.cmp(TMP1, imm(op_call_nif_WWW)); + a.b_eq(labels[dispatch_nif]); + + ERTS_CT_ASSERT((op_call_bif_W & 0xFFFF0000) == 0); + a.cmp(TMP1, imm(op_call_bif_W)); + a.b_eq(labels[dispatch_bif]); + + a.br(ARG1); + } + + /* Processes may jump to the exported entry points below, executing on the + * Erlang stack when entering. These are separate from the `_local` labels + * above as we don't want to worry about which stack we're on when the + * cases overlap. */ + + /* `ga->get_context_switch()` + * + * The *next* instruction pointer is provided in ARG3, and must be preceded + * by an ErtsCodeMFA. + * + * The X registers are expected to be in CPU registers. + */ + a.bind(labels[context_switch]); + { + emit_enter_runtime(); + + a.b(context_switch_local); + } + + /* `ga->get_context_switch_simplified()` + * + * The next instruction pointer is provided in ARG3, which does not need to + * point past an ErtsCodeMFA as the process structure has already been + * updated. + * + * The X registers are expected to be in CPU registers. + */ + a.bind(labels[context_switch_simplified]); + { + emit_enter_runtime(); + + a.b(context_switch_simplified_local); + } + + /* `ga->get_do_schedule()` + * + * `c_p->i` must be set prior to jumping here. + * + * The X registers are expected to be in CPU registers. + */ + a.bind(labels[do_schedule]); + { + emit_enter_runtime(); + + a.b(do_schedule_local); + } +} diff --git a/erts/emulator/beam/jit/asm_load.c b/erts/emulator/beam/jit/asm_load.c index 24fae1896c95..023f08405162 100644 --- a/erts/emulator/beam/jit/asm_load.c +++ b/erts/emulator/beam/jit/asm_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -36,15 +36,18 @@ # include #endif +#define INVALID_LAMBDA_INDEX -1 + static void init_label(Label *lp); -void beam_load_prepare_emit(LoaderState *stp) { +int beam_load_prepare_emit(LoaderState *stp) { BeamCodeHeader *hdr; int i; stp->ba = beamasm_new_assembler(stp->module, stp->beam.code.label_count, - stp->beam.code.function_count); + stp->beam.code.function_count, + &stp->beam); /* Initialize code header */ stp->codev_size = stp->beam.code.function_count + 1; @@ -64,6 +67,7 @@ void beam_load_prepare_emit(LoaderState *stp) { hdr->compile_size_on_heap = 0; hdr->literal_area = NULL; hdr->md5_ptr = NULL; + hdr->are_nifs = NULL; stp->load_hdr = hdr; @@ -73,6 +77,27 @@ void beam_load_prepare_emit(LoaderState *stp) { init_label(&stp->labels[i]); } + stp->lambda_literals = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->beam.lambdas.count * sizeof(SWord)); + + for (i = 0; i < stp->beam.lambdas.count; i++) { + BeamFile_LambdaEntry *lambda = &stp->beam.lambdas.entries[i]; + + if (stp->labels[lambda->label].lambda_index == INVALID_LAMBDA_INDEX) { + stp->labels[lambda->label].lambda_index = i; + stp->lambda_literals[i] = ERTS_SWORD_MAX; + } else { + beam_load_report_error(__LINE__, + stp, + "lambda already defined for label %i. To " + "fix this, please recompile this module " + "with an OTP " ERLANG_OTP_RELEASE + " compiler.", + lambda->label); + return 0; + } + } + stp->bif_imports = erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->beam.imports.count * sizeof(BifEntry **)); @@ -111,10 +136,13 @@ void beam_load_prepare_emit(LoaderState *stp) { stp->beam.code.function_count * sizeof(unsigned int)); } + + return 1; } static void init_label(Label *lp) { sys_memset(lp, 0, sizeof(*lp)); + lp->lambda_index = INVALID_LAMBDA_INDEX; } void beam_load_prepared_free(Binary *magic) { @@ -132,11 +160,6 @@ int beam_load_prepared_dtor(Binary *magic) { beamfile_free(&stp->beam); beamopallocator_dtor(&stp->op_allocator); - if (stp->bin) { - driver_free_binary(stp->bin); - stp->bin = NULL; - } - if (stp->load_hdr) { BeamCodeHeader *hdr = stp->load_hdr; @@ -144,6 +167,10 @@ int beam_load_prepared_dtor(Binary *magic) { erts_release_literal_area(hdr->literal_area); hdr->literal_area = NULL; } + if (hdr->are_nifs) { + erts_free(ERTS_ALC_T_PREPARED_CODE, hdr->are_nifs); + hdr->are_nifs = NULL; + } erts_free(ERTS_ALC_T_PREPARED_CODE, hdr); stp->load_hdr = NULL; @@ -154,6 +181,11 @@ int beam_load_prepared_dtor(Binary *magic) { stp->labels = NULL; } + if (stp->lambda_literals) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *)stp->lambda_literals); + stp->lambda_literals = NULL; + } + if (stp->bif_imports) { erts_free(ERTS_ALC_T_PREPARED_CODE, stp->bif_imports); stp->bif_imports = NULL; @@ -174,13 +206,15 @@ int beam_load_prepared_dtor(Binary *magic) { stp->ba = NULL; } - if (stp->native_module_exec) { - ASSERT(stp->native_module_rw != NULL); + if (stp->executable_region) { + ASSERT(stp->writable_region != NULL); - beamasm_purge_module(stp->native_module_exec, stp->native_module_rw); + beamasm_purge_module(stp->executable_region, + stp->writable_region, + stp->loaded_size); - stp->native_module_exec = NULL; - stp->native_module_rw = NULL; + stp->executable_region = NULL; + stp->writable_region = NULL; } return 1; @@ -252,7 +286,7 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { switch (*sign) { case 'n': /* Nil */ ASSERT(tag != TAG_r); - curr->type = TAG_i; + curr->type = 'I'; curr->val = NIL; BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); break; @@ -262,19 +296,20 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'a': /* Tagged atom */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); - curr->type = TAG_i; + curr->type = 'I'; break; case 'c': /* Tagged constant */ switch (tag) { case TAG_i: curr->val = make_small((Uint)curr->val); + curr->type = 'I'; break; case TAG_a: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_n: curr->val = NIL; - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_q: break; @@ -294,12 +329,13 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case TAG_i: curr->val = (BeamInstr)make_small(curr->val); + curr->type = 'I'; break; case TAG_a: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_n: - curr->type = TAG_i; + curr->type = 'I'; curr->val = NIL; break; case TAG_q: { @@ -354,7 +390,8 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'A': /* Arity value. */ BeamLoadVerifyTag(stp, tag, TAG_u); - curr->val = make_arityval(curr->val); + curr->val = curr->val == 0 ? make_arityval_zero() + : make_arityval(curr->val); break; case 'f': /* Destination label */ BeamLoadVerifyTag(stp, tag_to_letter[tag], *sign); @@ -394,13 +431,14 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { stp->last_label); } stp->labels[stp->last_label].value = 1; + curr->type = TAG_f; break; case 'e': /* Export entry */ BeamLoadVerifyTag(stp, tag, TAG_u); if (curr->val >= stp->beam.imports.count) { BeamLoadError1(stp, "invalid import table index %d", curr->val); } - curr->type = TAG_r; + curr->type = 'E'; break; case 'b': { int i = tmp_op->a[arg].val; @@ -426,10 +464,26 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { break; case 'F': /* Fun entry */ BeamLoadVerifyTag(stp, tag, TAG_u); + curr->type = 'F'; + break; + case 'H': /* Exception handler */ + BeamLoadVerifyTag(stp, tag, TAG_f); + curr->type = 'H'; + break; + case 'M': + curr->type = 'M'; + break; + case 'i': + curr->type = 'I'; break; default: BeamLoadError1(stp, "bad argument tag: %d", *sign); } + + /* These types must have been translated to 'I' */ + ASSERT(curr->type != TAG_i && curr->type != TAG_n && + curr->type != TAG_a && curr->type != TAG_v); + sign++; arg++; } @@ -437,7 +491,7 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { /* * Verify and massage any list arguments according to the primitive tags. * - * TAG_i will denote a tagged immediate value (NIL, small integer, + * 'I' will denote a tagged immediate value (NIL, small integer, * atom, or tuple arity). TAG_n, TAG_a, and TAG_v will no longer be used. */ for (; arg < tmp_op->arity; arg++) { @@ -446,14 +500,15 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { switch (tmp_op->a[arg].type) { case TAG_i: curr->val = make_small(tmp_op->a[arg].val); + curr->type = 'I'; break; case TAG_n: curr->val = NIL; - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_a: case TAG_v: - curr->type = TAG_i; + curr->type = 'I'; break; case TAG_u: case TAG_f: @@ -496,6 +551,17 @@ int beam_load_emit_op(LoaderState *stp, BeamOp *tmp_op) { stp->func_line[stp->function_number] = stp->current_li; } + break; + case op_nif_start: + if (!stp->load_hdr->are_nifs) { + int bytes = stp->beam.code.function_count * sizeof(byte); + stp->load_hdr->are_nifs = + erts_alloc(ERTS_ALC_T_PREPARED_CODE, bytes); + sys_memzero(stp->load_hdr->are_nifs, bytes); + } + ASSERT(stp->function_number > 0); + ASSERT(stp->function_number <= stp->beam.code.function_count); + stp->load_hdr->are_nifs[stp->function_number - 1] = 1; break; } @@ -567,6 +633,7 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, const void **line_items_ro; void **line_items_rw; + const unsigned int num_names = stp->beam.lines.name_count; const Eterm *fname_base_ro; Eterm *fname_base_rw; @@ -584,17 +651,17 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, fname_base_ro = (Eterm *)&line_items_ro[num_instrs + 1]; locp_base_ro = &fname_base_ro[stp->beam.lines.name_count]; - line_tab_rw = get_writable_ptr(stp->native_module_exec, - stp->native_module_rw, + line_tab_rw = get_writable_ptr(stp->executable_region, + stp->writable_region, line_tab_ro); - line_items_rw = get_writable_ptr(stp->native_module_exec, - stp->native_module_rw, + line_items_rw = get_writable_ptr(stp->executable_region, + stp->writable_region, line_items_ro); - locp_base_rw = get_writable_ptr(stp->native_module_exec, - stp->native_module_rw, + locp_base_rw = get_writable_ptr(stp->executable_region, + stp->writable_region, locp_base_ro); - fname_base_rw = get_writable_ptr(stp->native_module_exec, - stp->native_module_rw, + fname_base_rw = get_writable_ptr(stp->executable_region, + stp->writable_region, fname_base_ro); line_tab_rw->loc_size = stp->beam.lines.location_size; @@ -611,10 +678,9 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, line_items_rw[i] = (void *)&module_base[module_size]; - if (stp->beam.lines.name_count) { - sys_memcpy(fname_base_rw, - stp->beam.lines.names, - stp->beam.lines.name_count * sizeof(Eterm)); + for (i = 0; i < num_names; i++) { + fname_base_rw[i] = + beamfile_get_literal(&stp->beam, stp->beam.lines.names[i]); } if (stp->beam.lines.location_size == sizeof(Uint16)) { @@ -655,11 +721,12 @@ static const BeamCodeLineTab *finish_line_table(LoaderState *stp, int beam_load_finish_emit(LoaderState *stp) { const BeamCodeHeader *code_hdr_ro = NULL; BeamCodeHeader *code_hdr_rw = NULL; + size_t module_size; + char *module_base; Sint decoded_size; - int i; + int ret; - char *module_base; - size_t module_size; + ret = 0; if (stp->line_instr != 0) { Uint line_size = offsetof(BeamCodeLineTab, func_tab); @@ -700,27 +767,19 @@ int beam_load_finish_emit(LoaderState *stp) { /* Move the code to its final location. */ beamasm_codegen(stp->ba, - &stp->native_module_exec, - &stp->native_module_rw, + &stp->executable_region, + &stp->writable_region, stp->load_hdr, &code_hdr_ro, &code_hdr_rw); - stp->code_hdr = code_hdr_ro; - + stp->on_load = beamasm_get_on_load(stp->ba); module_base = beamasm_get_base(stp->ba); module_size = beamasm_get_offset(stp->ba); - stp->on_load = beamasm_get_on_load(stp->ba); - - /* If there is line information, place it here. This must be done after - * code generation to make sure the addresses are correct. - * - * Ideally we'd want this to be embedded in the module itself just like the - * string table is and use offsets rather than absolute addresses, but this - * will do for now. */ - - code_hdr_rw->line_table = finish_line_table(stp, module_base, module_size); + /* Save the updated code pointer and code size. */ + stp->code_hdr = code_hdr_ro; + stp->loaded_size = module_size; /* * Place the literals in their own allocated heap (for fast range check) @@ -732,6 +791,7 @@ int beam_load_finish_emit(LoaderState *stp) { ErtsLiteralArea *literal_area; Uint tot_lit_size; Uint lit_asize; + int i; tot_lit_size = stp->beam.static_literals.heap_size + stp->beam.dynamic_literals.heap_size; @@ -749,12 +809,12 @@ int beam_load_finish_emit(LoaderState *stp) { * more like string patching. */ for (i = 0; i < stp->beam.static_literals.count; i++) { Eterm lit = beamfile_get_literal(&stp->beam, i); - beamasm_patch_literal(stp->ba, stp->native_module_rw, i, lit); + beamasm_patch_literal(stp->ba, stp->writable_region, i, lit); } for (i = 0; i < stp->beam.dynamic_literals.count; i++) { Eterm lit = beamfile_get_literal(&stp->beam, ~i); - beamasm_patch_literal(stp->ba, stp->native_module_rw, ~i, lit); + beamasm_patch_literal(stp->ba, stp->writable_region, ~i, lit); } literal_area->off_heap = code_off_heap.first; @@ -765,6 +825,10 @@ int beam_load_finish_emit(LoaderState *stp) { (stp->load_hdr)->literal_area = literal_area; } + /* Line information must be added after moving literals, since source file + * names are literal lists. */ + code_hdr_rw->line_table = finish_line_table(stp, module_base, module_size); + if (stp->beam.attributes.size) { const byte *attr = beamasm_get_rodata(stp->ba, "attr"); @@ -806,30 +870,45 @@ int beam_load_finish_emit(LoaderState *stp) { /* Patch all instructions that refer to the string table. */ if (stp->beam.strings.size) { const byte *string_table = beamasm_get_rodata(stp->ba, "str"); - beamasm_patch_strings(stp->ba, stp->native_module_rw, string_table); + beamasm_patch_strings(stp->ba, stp->writable_region, string_table); } - /* Save the updated code pointer and code size. */ - - stp->loaded_size = module_size; + ret = 1; +load_error: - return 1; + /* Some platforms use per-thread global permissions where a thread can + * either write to or execute _ALL_ JITed pages, so we must seal the module + * before yielding or this thread won't be able to execute any other JITed + * code. + * + * Note that we have to do this regardless of whether we've succeeded or + * not, as the module is unsealed after code generation. */ + beamasm_seal_module(stp->executable_region, + stp->writable_region, + stp->loaded_size); -load_error: - return 0; + return ret; } void beam_load_finalize_code(LoaderState *stp, struct erl_module_instance *inst_p) { - int staging_ix, code_size, i; + ErtsCodeIndex staging_ix; + int code_size, i; + + ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_load_permission() || + erts_thr_progress_is_blocking()); code_size = beamasm_get_header(stp->ba, &stp->code_hdr); erts_total_code_size += code_size; - inst_p->native_module_exec = stp->native_module_exec; - inst_p->native_module_rw = stp->native_module_rw; + inst_p->executable_region = stp->executable_region; + inst_p->writable_region = stp->writable_region; inst_p->code_hdr = stp->code_hdr; inst_p->code_length = code_size; + inst_p->unsealed = 0; + + erts_unseal_module(inst_p); + #ifdef ADDRESS_SANITIZER /* * LeakSanitizer ignores directly mmap'ed memory by default. This causes @@ -845,7 +924,7 @@ void beam_load_finalize_code(LoaderState *stp, erts_update_ranges(inst_p->code_hdr, code_size); /* Allocate catch indices and fix up all catch_yf instructions. */ - inst_p->catches = beamasm_patch_catches(stp->ba, stp->native_module_rw); + inst_p->catches = beamasm_patch_catches(stp->ba, stp->writable_region); /* Exported functions */ staging_ix = erts_staging_code_ix(); @@ -864,7 +943,7 @@ void beam_load_finalize_code(LoaderState *stp, * code callable. */ ep->trampoline.not_loaded.deferred = (BeamInstr)address; } else { - ep->addresses[staging_ix] = address; + ep->dispatch.addresses[staging_ix] = address; } } @@ -872,17 +951,16 @@ void beam_load_finalize_code(LoaderState *stp, * the module may remote-call itself*/ for (i = 0; i < stp->beam.imports.count; i++) { BeamFile_ImportEntry *entry = &stp->beam.imports.entries[i]; - BeamInstr import; + Export *import; - import = (BeamInstr)erts_export_put(entry->module, - entry->function, - entry->arity); + import = erts_export_put(entry->module, entry->function, entry->arity); - beamasm_patch_import(stp->ba, stp->native_module_rw, i, import); + beamasm_patch_import(stp->ba, stp->writable_region, i, import); } /* Patch fun creation. */ if (stp->beam.lambdas.count) { + ErtsLiteralArea *literal_area = (stp->code_hdr)->literal_area; BeamFile_LambdaTable *lambda_table = &stp->beam.lambdas; for (i = 0; i < lambda_table->count; i++) { @@ -898,25 +976,53 @@ void beam_load_finalize_code(LoaderState *stp, lambda->index, lambda->arity - lambda->num_free); - if (erts_is_fun_loaded(fun_entry)) { + if (erts_is_fun_loaded(fun_entry, staging_ix)) { /* We've reloaded a module over itself and inherited the old * instance's fun entries, so we need to undo the reference * bump in `erts_put_fun_entry2` to make fun purging work. */ erts_refc_dectest(&fun_entry->refc, 1); } - fun_entry->address = beamasm_get_code(stp->ba, lambda->label); + erts_set_fun_code(fun_entry, + staging_ix, + beamasm_get_lambda(stp->ba, i)); + + /* Finalize the literal we've created for this lambda, if any, + * converting it from an external fun to a local one with the newly + * created fun entry. */ + if (stp->lambda_literals[i] != ERTS_SWORD_MAX) { + ErlFunThing *funp; + Eterm literal; + + literal = beamfile_get_literal(&stp->beam, + stp->lambda_literals[i]); + funp = (ErlFunThing *)fun_val(literal); + ASSERT(funp->creator == am_external); - beamasm_patch_lambda(stp->ba, - stp->native_module_rw, - i, - (BeamInstr)fun_entry); + funp->entry.fun = fun_entry; + + funp->next = literal_area->off_heap; + literal_area->off_heap = (struct erl_off_heap_header *)funp; + + ASSERT(erts_init_process_id != ERTS_INVALID_PID); + funp->creator = erts_init_process_id; + + erts_refc_inc(&fun_entry->refc, 2); + } + + beamasm_patch_lambda(stp->ba, stp->writable_region, i, fun_entry); } } + /* Register debug / profiling info with external tools. */ + beamasm_register_metadata(stp->ba, stp->code_hdr); + + erts_seal_module(inst_p); + /* Prevent literals and code from being freed. */ (stp->load_hdr)->literal_area = NULL; - stp->native_module_exec = NULL; - stp->native_module_rw = NULL; + stp->load_hdr->are_nifs = NULL; + stp->executable_region = NULL; + stp->writable_region = NULL; stp->code_hdr = NULL; } diff --git a/erts/emulator/beam/jit/beam_asm.h b/erts/emulator/beam/jit/beam_asm.h index 4a61c87fe063..a0d82f82e1a2 100644 --- a/erts/emulator/beam/jit/beam_asm.h +++ b/erts/emulator/beam/jit/beam_asm.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -18,36 +18,55 @@ * %CopyrightEnd% */ -#ifdef BEAMASM +#if defined(BEAMASM) && !defined(__BEAM_ASM_H__) +# define __BEAM_ASM_H__ # include "sys.h" # include "bif.h" +# include "erl_fun.h" # include "erl_process.h" # include "beam_code.h" # include "beam_file.h" # include "beam_common.h" +# if defined(__APPLE__) +# include +# endif + /* Global configuration variables */ # ifdef HAVE_LINUX_PERF_SUPPORT -# define BEAMASM_PERF_DUMP (1 << 0) -# define BEAMASM_PERF_MAP (1 << 1) -extern int erts_jit_perf_support; +enum beamasm_perf_flags { + BEAMASM_PERF_DUMP = (1 << 0), + BEAMASM_PERF_MAP = (1 << 1), + BEAMASM_PERF_FP = (1 << 2), + + BEAMASM_PERF_ENABLED = + BEAMASM_PERF_DUMP | BEAMASM_PERF_MAP | BEAMASM_PERF_FP, + BEAMASM_PERF_DISABLED = 0, +}; +extern enum beamasm_perf_flags erts_jit_perf_support; # endif +extern int erts_jit_single_map; void beamasm_init(void); -void beamasm_init_perf(void); -void *beamasm_new_assembler(Eterm mod, int num_labels, int num_functions); +void *beamasm_new_assembler(Eterm mod, + int num_labels, + int num_functions, + BeamFile *beam); void beamasm_codegen(void *ba, - const void **native_module_exec, - void **native_module_rw, + const void **executable_region, + void **writable_region, const BeamCodeHeader *in_hdr, const BeamCodeHeader **out_exec_hdr, BeamCodeHeader **out_rw_hdr); -void beamasm_purge_module(const void *native_module_exec, - void *native_module_rw); +void beamasm_register_metadata(void *ba, const BeamCodeHeader *hdr); +void beamasm_purge_module(const void *executable_region, + void *writable_region, + size_t size); void beamasm_delete_assembler(void *ba); int beamasm_emit(void *ba, unsigned specific_op, BeamOp *op); ErtsCodePtr beamasm_get_code(void *ba, int label); +ErtsCodePtr beamasm_get_lambda(void *ba, int index); const byte *beamasm_get_rodata(void *ba, char *label); void beamasm_embed_rodata(void *ba, const char *labelName, @@ -56,15 +75,17 @@ void beamasm_embed_rodata(void *ba, void beamasm_embed_bss(void *ba, char *labelName, size_t size); unsigned int beamasm_patch_catches(void *ba, char *rw_base); -void beamasm_patch_import(void *ba, char *rw_base, int index, BeamInstr import); +void beamasm_patch_import(void *ba, + char *rw_base, + int index, + const Export *import); void beamasm_patch_literal(void *ba, char *rw_base, int index, Eterm lit); -void beamasm_patch_lambda(void *ba, char *rw_base, int index, BeamInstr fe); +void beamasm_patch_lambda(void *ba, + char *rw_base, + int index, + const ErlFunEntry *fe); void beamasm_patch_strings(void *ba, char *rw_base, const byte *strtab); -void beamasm_emit_call_bif(const ErtsCodeInfo *info, - Eterm (*bif)(BIF_ALIST), - char *buff, - unsigned buff_len); void beamasm_emit_call_nif(const ErtsCodeInfo *info, void *normal_fptr, void *lib, @@ -80,47 +101,61 @@ char *beamasm_get_base(void *instance); /* Return current instruction offset, for line information. */ size_t beamasm_get_offset(void *ba); -// Number of bytes emitted at first label in order to support trace and nif load -# define BEAM_ASM_FUNC_PROLOGUE_SIZE 8 +void beamasm_unseal_module(const void *executable_region, + void *writable_region, + size_t size); +void beamasm_seal_module(const void *executable_region, + void *writable_region, + size_t size); +void beamasm_flush_icache(const void *address, size_t size); + +/* Number of bytes emitted at first label in order to support trace and nif + * load. */ +# if defined(__aarch64__) +# define BEAM_ASM_FUNC_PROLOGUE_SIZE 12 +# else +# define BEAM_ASM_FUNC_PROLOGUE_SIZE 8 +# endif + +/* Size (in bytes) of a ErtsNativeFunc/call_nif prologue. */ +# if defined(__aarch64__) +# define BEAM_ASM_NFUNC_SIZE (BEAM_ASM_FUNC_PROLOGUE_SIZE + 4) +# else +# define BEAM_ASM_NFUNC_SIZE (BEAM_ASM_FUNC_PROLOGUE_SIZE + 8) +# endif /* - * The code below is used to deal with intercepting the execution of - * a process at the start of a function. It is used by tracing and nif loading. + * The code below is used to deal with intercepting the execution of a process + * at the start of a function. It is used by tracing and nif loading. * * In the interpreter this is solved by simply writing a new instruction as * the first instruction in a function. In asm mode it is not as simple as * our code changes have to be to executing native code. * - * The solution is as follows: + * On x86, the solution is as follows: * * When emitting a function the first word (or function prologue) is: - * 0x0: jmp 6 - * 0x2: ERTS_ASM_BP_FLAG_NONE - * 0x3: relative near call - * 0x4: &genericBPTramp + * 0x0: short jmp 6 + * 0x2: nop + * 0x3: relative near call to shared breakpoint fragment * 0x8: actual code for function * - * When code starts to execute it will simply see the "jmp 6" instruction - * which skips the prologue and starts to execute the code directly. + * When code starts to execute it will simply see the `short jmp 6` + * instruction which skips the prologue and starts to execute the code + * directly. * - * When we want to enable a certain breakpoint we set the jmp target to - * be 1 (which means it will land on the call instruction) and will call - * genericBPTramp. genericBPTramp is a label at the top of each module - * that contains trampolines for all flag combinations. + * When we want to enable a certain breakpoint we set the jmp target to be 1, + * which means it will land on the call to the shared breakpoint fragment. + * This fragment checks the current `breakpoint_flag` stored in the + * ErtsCodeInfo of this function, and then calls `erts_call_nif_early` and + * `erts_generic_breakpoint` accordingly. * - * genericBPTramp: - * 0x0: ret - * 0x10: jmp call_nif_early - * 0x20: call generic_bp_local - * 0x30: call generic_bp_local - * 0x35: jmp call_nif_early + * Note that the update of the branch and `breakpoint_flag` does not need to + * be atomic: it's fine if a process only sees one of these being updated, as + * the code that sets breakpoints/loads NIFs doesn't rely on the trampoline + * being active until thread progress has been made. * - * Note that each target is 16 byte aligned. This is because the call target - * in the function prologue is updated to target the correct place when a flag - * is updated. So if CALL_NIF_EARLY is set, then it is updated to be - * genericBPTramp + 0x10. If BP is set, it is updated to genericBPTramp + 0x20 - * and the combination makes it be genericBPTramp + 0x30. - */ + * The solution for AArch64 is similar. */ enum erts_asm_bp_flag { ERTS_ASM_BP_FLAG_NONE = 0, @@ -130,39 +165,73 @@ enum erts_asm_bp_flag { ERTS_ASM_BP_FLAG_CALL_NIF_EARLY | ERTS_ASM_BP_FLAG_BP }; -static inline void erts_asm_bp_set_flag(ErtsCodeInfo *ci, - enum erts_asm_bp_flag flag) { - BeamInstr volatile *code_ptr = (BeamInstr *)erts_codeinfo_to_code(ci); - BeamInstr code = *code_ptr; - byte *codebytes = (byte *)&code; - Uint32 *code32 = (Uint32 *)(codebytes + 4); - /* 0xEB = relative jmp, 0xE8 = relative call */ - ASSERT(codebytes[0] == 0xEB && codebytes[3] == 0xE8); - codebytes[1] = 1; - codebytes[2] |= flag; - *code32 += flag * 16; - code_ptr[0] = code; +static inline enum erts_asm_bp_flag erts_asm_bp_get_flags( + const ErtsCodeInfo *ci_exec) { + return (enum erts_asm_bp_flag)ci_exec->u.metadata.breakpoint_flag; } -static inline enum erts_asm_bp_flag erts_asm_bp_get_flags(ErtsCodeInfo *ci) { - byte *codebytes = (byte *)erts_codeinfo_to_code(ci); - return (enum erts_asm_bp_flag)codebytes[2]; +static inline void erts_asm_bp_set_flag(ErtsCodeInfo *ci_rw, + const ErtsCodeInfo *ci_exec, + enum erts_asm_bp_flag flag) { + ASSERT(flag != ERTS_ASM_BP_FLAG_NONE); + (void)ci_exec; + + if (ci_rw->u.metadata.breakpoint_flag == ERTS_ASM_BP_FLAG_NONE) { +# if defined(__aarch64__) + Uint32 volatile *rw_code = (Uint32 *)erts_codeinfo_to_code(ci_rw); + + /* B .next, .enabled: BL breakpoint_handler, .next: */ + ASSERT(rw_code[1] == 0x14000002); + + /* Reroute the initial jump instruction to `.enabled`. */ + rw_code[1] = 0x14000001; +# else /* x86_64 */ + byte volatile *rw_code = (byte *)erts_codeinfo_to_code(ci_rw); + + /* SHORT JMP .next, NOP, .enabled: CALL breakpoint_handler, .next: */ + ASSERT(rw_code[0] == 0xEB && rw_code[1] == 0x06 && rw_code[2] == 0x90 && + rw_code[3] == 0xE8); + + /* Reroute the initial jump instruction to `.enabled`. */ + rw_code[1] = 1; +# endif + } + + ci_rw->u.metadata.breakpoint_flag |= flag; } -static inline void erts_asm_bp_unset_flag(ErtsCodeInfo *ci, +static inline void erts_asm_bp_unset_flag(ErtsCodeInfo *ci_rw, + const ErtsCodeInfo *ci_exec, enum erts_asm_bp_flag flag) { - BeamInstr volatile *code_ptr = (BeamInstr *)erts_codeinfo_to_code(ci); - BeamInstr code = *code_ptr; - byte *codebytes = (byte *)&code; - Uint32 *code32 = (Uint32 *)(codebytes + 4); - /* 0xEB = relative jmp, 0xE8 = relative call */ - ASSERT(codebytes[0] == 0xEB && codebytes[3] == 0xE8); - codebytes[2] &= ~flag; - *code32 -= flag * 16; - if (codebytes[2] == ERTS_ASM_BP_FLAG_NONE) { - codebytes[1] = 6; + ASSERT(flag != ERTS_ASM_BP_FLAG_NONE); + (void)ci_exec; + + ci_rw->u.metadata.breakpoint_flag &= ~flag; + + if (ci_rw->u.metadata.breakpoint_flag == ERTS_ASM_BP_FLAG_NONE) { + /* We've removed the last flag, route the branch instruction back + * past the prologue. */ + +# if defined(__aarch64__) + Uint32 volatile *rw_code = (Uint32 *)erts_codeinfo_to_code(ci_rw); + + /* B .enabled, .enabled: BL breakpoint_handler, .next: */ + ASSERT(rw_code[1] == 0x14000001); + + /* Reroute the initial jump instruction back to `.next`. */ + ERTS_CT_ASSERT(BEAM_ASM_FUNC_PROLOGUE_SIZE == sizeof(Uint32[3])); + rw_code[1] = 0x14000002; +# else /* x86_64 */ + byte volatile *rw_code = (byte *)erts_codeinfo_to_code(ci_rw); + + /* SHORT JMP .enabled, NOP, .enabled: CALL breakpoint_handler, .next: */ + ASSERT(rw_code[0] == 0xEB && rw_code[1] == 0x01 && rw_code[2] == 0x90 && + rw_code[3] == 0xE8); + + /* Reroute the initial jump instruction back to `.next`. */ + rw_code[1] = BEAM_ASM_FUNC_PROLOGUE_SIZE - 2; +# endif } - code_ptr[0] = code; } #endif diff --git a/erts/emulator/beam/jit/beam_jit_args.hpp b/erts/emulator/beam/jit/beam_jit_args.hpp new file mode 100644 index 000000000000..4dba1b3f4fd7 --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_args.hpp @@ -0,0 +1,385 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#ifndef __BEAM_JIT_ARGS_HPP__ +#define __BEAM_JIT_ARGS_HPP__ + +struct ArgVal : public BeamOpArg { + enum TYPE : UWord { + Word = TAG_u, + XReg = TAG_x, + YReg = TAG_y, + FReg = TAG_l, + Label = TAG_f, + Literal = TAG_q, + + BytePtr = 'M', + Catch = 'H', + Export = 'E', + FunEntry = 'F', + Immediate = 'I' + }; + + constexpr ArgVal(UWord t, UWord value) : BeamOpArg{t, value} { + ASSERT(t == TYPE::Word || t == TYPE::XReg || t == TYPE::YReg || + t == TYPE::FReg || t == TYPE::Label || t == TYPE::Literal || + t == TYPE::BytePtr || t == TYPE::Catch || t == TYPE::Export || + t == TYPE::FunEntry || t == TYPE::Immediate); + } + + constexpr enum TYPE getType() const { + return (enum TYPE)type; + } + + /* */ + + constexpr bool isAtom() const { + return isImmed() && is_atom(val); + } + + constexpr bool isBytePtr() const { + return getType() == TYPE::BytePtr; + } + + constexpr bool isCatch() const { + return getType() == TYPE::Catch; + } + + constexpr bool isConstant() const { + return isImmed() || isLiteral(); + } + + constexpr bool isExport() const { + return getType() == TYPE::Export; + } + + constexpr bool isImmed() const { + return getType() == TYPE::Immediate; + } + + constexpr bool isLabel() const { + return getType() == TYPE::Label; + } + + constexpr bool isLambda() const { + return getType() == TYPE::FunEntry; + } + + constexpr bool isLiteral() const { + return getType() == TYPE::Literal; + } + + constexpr bool isNil() const { + return isImmed() && val == NIL; + } + + constexpr bool isSmall() const { + return isImmed() && is_small(val); + } + + constexpr bool isSource() const { + return isConstant() || isRegister(); + } + + constexpr bool isRegister() const { + return isXRegister() || isYRegister() || isFRegister(); + } + + constexpr bool isXRegister() const { + return getType() == TYPE::XReg; + } + + constexpr bool isYRegister() const { + return getType() == TYPE::YReg; + } + + constexpr bool isFRegister() const { + return getType() == TYPE::FReg; + } + + constexpr bool isWord() const { + return getType() == TYPE::Word; + } + + struct Hash { + constexpr size_t operator()(const ArgVal &key) const { + return ((size_t)key.getType() << 48) ^ (size_t)key.val; + } + }; + + constexpr bool operator==(const ArgVal &other) const { + return getType() == other.getType() && val == other.val; + } + + constexpr bool operator!=(const ArgVal &other) const { + return !(*this == other); + } + + enum Relation { none, consecutive, reverse_consecutive }; + + static Relation memory_relation(const ArgVal &lhs, const ArgVal &rhs) { + if (lhs.isRegister() && lhs.getType() == rhs.getType()) { + if ((lhs.val & REG_MASK) + 1 == (rhs.val & REG_MASK)) { + return consecutive; + } else if ((lhs.val & REG_MASK) == (rhs.val & REG_MASK) + 1) { + return reverse_consecutive; + } + } + + return none; + }; + + template + constexpr T as() const { + return static_cast(*this); + } +}; + +struct ArgBytePtr : public ArgVal { + template + constexpr ArgBytePtr(const T &other) : ArgVal(other) { + ASSERT(isBytePtr()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgCatch : public ArgVal { + template + constexpr ArgCatch(const T &other) : ArgVal(other) { + ASSERT(isCatch()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgExport : public ArgVal { + template + constexpr ArgExport(const T &other) : ArgVal(other) { + ASSERT(isExport()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgLabel : public ArgVal { + template + constexpr ArgLabel(const T &other) : ArgVal(other) { + ASSERT(isLabel()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgLambda : public ArgVal { + template + constexpr ArgLambda(const T &other) : ArgVal(other) { + ASSERT(isLambda()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgWord : public ArgVal { + /* Allows explicit construction from any integral type. */ + template::value, bool> = true> + constexpr explicit ArgWord(T value) : ArgVal(ArgVal::Word, value) { + } + + template::value, bool> = true> + constexpr ArgWord(const T &other) : ArgVal(other) { + ASSERT(isWord()); + } + + template + constexpr ArgWord operator+(T value) const { + return ArgWord(val + value); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgSource : public ArgVal { + template + constexpr ArgSource(const T &other) : ArgVal(other) { + ASSERT(isSource()); + } +}; + +struct ArgRegister : public ArgSource { + template + constexpr ArgRegister(const T &other) : ArgSource(other) { + ASSERT(isRegister()); + } + + constexpr int typeIndex() const { + return (int)(val >> 10); + } + + template + constexpr T copy(int n) const { + return T(n | (val & ~REG_MASK)); + } +}; + +struct ArgXRegister : public ArgRegister { + /* Allows explicit construction from any integral type. */ + template::value, bool> = true> + constexpr explicit ArgXRegister(T reg) + : ArgRegister(ArgVal(ArgVal::XReg, reg)) { + } + + template::value, bool> = true> + constexpr ArgXRegister(const T &other) : ArgRegister(other) { + ASSERT(isXRegister()); + } + + constexpr auto get() const { + return val & REG_MASK; + } +}; + +struct ArgYRegister : public ArgRegister { + /* Allows explicit construction from any integral type. */ + template::value, bool> = true> + constexpr explicit ArgYRegister(T reg) + : ArgRegister(ArgVal(ArgVal::YReg, reg)) { + } + + template::value, bool> = true> + constexpr ArgYRegister(const T &other) : ArgRegister(other) { + ASSERT(isYRegister()); + } + + constexpr auto get() const { + return val & REG_MASK; + } +}; + +struct ArgFRegister : public ArgRegister { + template + constexpr ArgFRegister(const T &other) : ArgRegister(other) { + ASSERT(isFRegister()); + } + + constexpr auto get() const { + return val & REG_MASK; + } +}; + +struct ArgConstant : public ArgSource { + template + constexpr ArgConstant(const T &other) : ArgSource(other) { + ASSERT(isConstant()); + } +}; + +struct ArgImmed : public ArgConstant { + constexpr explicit ArgImmed(Eterm term) + : ArgConstant(ArgVal(ArgVal::Immediate, term)) { + ASSERT(isImmed()); + } + + template + constexpr ArgImmed(const T &other) : ArgConstant(other) { + ASSERT(isImmed()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgLiteral : public ArgConstant { + template + constexpr ArgLiteral(const T &other) : ArgConstant(other) { + ASSERT(isLiteral()); + } + + constexpr auto get() const { + return val; + } +}; + +struct ArgAtom : public ArgImmed { + template + constexpr ArgAtom(const T &other) : ArgImmed(other) { + ASSERT(isAtom()); + } + + constexpr Eterm get() const { + return val; + } +}; + +struct ArgNil : public ArgImmed { + constexpr explicit ArgNil() : ArgImmed(ArgVal(ArgVal::Immediate, NIL)) { + } + + template + constexpr ArgNil(const T &other) : ArgImmed(other) { + ASSERT(isNil()); + } + + constexpr Eterm get() const { + return val; + } +}; + +struct ArgSmall : public ArgImmed { + template + constexpr ArgSmall(const T &other) : ArgImmed(other) { + ASSERT(isSmall()); + } + + constexpr Sint getSigned() const { + /* `signed_val` is not constexpr in debug builds, so we'll do it + * manually as we already know for certain that this is a small. */ + return ((Sint)val) >> _TAG_IMMED1_SIZE; + } + + constexpr Uint getUnsigned() const { + return ((Uint)val) >> _TAG_IMMED1_SIZE; + } + + constexpr Eterm get() const { + return val; + } +}; + +#endif diff --git a/erts/emulator/beam/jit/beam_jit_common.c b/erts/emulator/beam/jit/beam_jit_common.c deleted file mode 100644 index 98b27e16f42e..000000000000 --- a/erts/emulator/beam/jit/beam_jit_common.c +++ /dev/null @@ -1,756 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2021-2022. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "erl_vm.h" -#include "global.h" -#include "bif.h" -#include "code_ix.h" -#include "erl_proc_sig_queue.h" -#include "erl_binary.h" -#include "erl_bits.h" -#include "erl_map.h" -#include "beam_common.h" -#ifdef USE_VM_PROBES -# include "dtrace-wrapper.h" -#endif - -#include "beam_jit_common.h" - -#if defined(DEBUG) && defined(JIT_HARD_DEBUG) -void beam_jit_validate_term(Eterm term) { - if (is_boxed(term)) { - Eterm header = *boxed_val(term); - - if (header_is_bin_matchstate(header)) { - return; - } - } - - size_object_x(term, NULL); -} -#endif - -Eterm beam_jit_call_bif(Process *c_p, - Eterm *reg, - ErtsCodePtr I, - ErtsBifFunc vbf, - Uint arity) { - ErlHeapFragment *live_hf_end; - Eterm result; - - ERTS_UNREQ_PROC_MAIN_LOCK(c_p); - { - live_hf_end = c_p->mbuf; - - ERTS_CHK_MBUF_SZ(c_p); - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - result = vbf(c_p, reg, I); - ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result)); - ERTS_CHK_MBUF_SZ(c_p); - - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - ERTS_HOLE_CHECK(c_p); - } - PROCESS_MAIN_CHK_LOCKS(c_p); - ERTS_REQ_PROC_MAIN_LOCK(c_p); - - if (ERTS_IS_GC_AFTER_BIF_DESIRED(c_p)) { - result = erts_gc_after_bif_call_lhf(c_p, - live_hf_end, - result, - reg, - arity); - } - - return result; -} - -Eterm beam_jit_call_nif(Process *c_p, - ErtsCodePtr I, - Eterm *reg, - BeamJitNifF *fp, - struct erl_module_nif *NifMod) { - Eterm nif_bif_result; - Eterm bif_nif_arity; - ErlHeapFragment *live_hf_end; - const ErtsCodeMFA *codemfa; - - codemfa = erts_code_to_codemfa(I); - - c_p->current = codemfa; /* current and vbf set to please handle_error */ - - bif_nif_arity = codemfa->arity; - ERTS_UNREQ_PROC_MAIN_LOCK(c_p); - - { - struct enif_environment_t env; - ASSERT(c_p->scheduler_data); - live_hf_end = c_p->mbuf; - ERTS_CHK_MBUF_SZ(c_p); - erts_pre_nif(&env, c_p, NifMod, NULL); - - ASSERT((c_p->scheduler_data)->current_nif == NULL); - (c_p->scheduler_data)->current_nif = &env; - - nif_bif_result = (*fp)(&env, bif_nif_arity, reg); - if (env.exception_thrown) - nif_bif_result = THE_NON_VALUE; - - ASSERT((c_p->scheduler_data)->current_nif == &env); - (c_p->scheduler_data)->current_nif = NULL; - - erts_post_nif(&env); - ERTS_CHK_MBUF_SZ(c_p); - - PROCESS_MAIN_CHK_LOCKS(c_p); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - ASSERT(!env.exiting); - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - } - ERTS_REQ_PROC_MAIN_LOCK(c_p); - ERTS_HOLE_CHECK(c_p); - - if (ERTS_IS_GC_AFTER_BIF_DESIRED(c_p)) { - nif_bif_result = erts_gc_after_bif_call_lhf(c_p, - live_hf_end, - nif_bif_result, - reg, - bif_nif_arity); - } - - return nif_bif_result; -} - -enum beam_jit_nif_load_ret beam_jit_load_nif(Process *c_p, - ErtsCodePtr I, - Eterm *reg) { - if (erts_try_seize_code_write_permission(c_p)) { - Eterm result; - - PROCESS_MAIN_CHK_LOCKS((c_p)); - ERTS_UNREQ_PROC_MAIN_LOCK((c_p)); - result = erts_load_nif(c_p, I, reg[0], reg[1]); - erts_release_code_write_permission(); - ERTS_REQ_PROC_MAIN_LOCK(c_p); - - if (ERTS_LIKELY(is_value(result))) { - reg[0] = result; - return RET_NIF_success; - } else { - c_p->freason = BADARG; - return RET_NIF_error; - } - } else { - /* Yield and try again. */ - c_p->current = NULL; - c_p->arity = 2; - return RET_NIF_yield; - } -} - -Uint beam_jit_get_map_elements(Eterm map, - Eterm *reg, - Eterm *E, - Uint n, - Eterm *fs) { - Uint sz; - - /* This instruction assumes Arg1 is a map, i.e. that it follows a test - * is_map if needed. */ - - if (is_flatmap(map)) { - flatmap_t *mp; - Eterm *ks; - Eterm *vs; - - mp = (flatmap_t *)flatmap_val(map); - sz = flatmap_get_size(mp); - - if (sz == 0) { - return 0; - } - - ks = flatmap_get_keys(mp); - vs = flatmap_get_values(mp); - - while (sz) { - if (EQ(fs[0], *ks)) { - PUT_TERM_REG(*vs, fs[1]); - - n--; - fs += 3; - - /* no more values to fetch, we are done */ - if (n == 0) { - return 1; - } - } - - ks++, sz--, vs++; - } - return 0; - } else { - ASSERT(is_hashmap(map)); - - while (n--) { - const Eterm *v; - Uint32 hx; - - hx = fs[2]; - ASSERT(hx == hashmap_make_hash(fs[0])); - - if ((v = erts_hashmap_get(hx, fs[0], map)) == NULL) { - return 0; - } - - PUT_TERM_REG(*v, fs[1]); - fs += 3; - } - - return 1; - } -} - -static void test_bin_vheap(Process *c_p, - Eterm *reg, - Uint VNh, - Uint Nh, - Uint Live) { - int need = Nh; - - if (c_p->stop - c_p->htop < (need + S_RESERVED) || - MSO(c_p).overhead + VNh >= BIN_VHEAP_SZ(c_p)) { - c_p->fcalls -= - erts_garbage_collect_nobump(c_p, need, reg, Live, c_p->fcalls); - } -} - -static void gc_test(Process *c_p, Eterm *reg, Uint Ns, Uint Nh, Uint Live) { - int need = Nh + Ns; - - if (ERTS_UNLIKELY(c_p->stop - c_p->htop < (need + S_RESERVED))) { - c_p->fcalls -= - erts_garbage_collect_nobump(c_p, need, reg, Live, c_p->fcalls); - } -} - -void beam_jit_bs_field_size_argument_error(Process *c_p, Eterm size) { - if (((is_small(size) && signed_val(size) >= 0) || - (is_big(size) && !big_sign(size)))) { - /* If the argument is a positive integer, we must've had a system_limit - * error. */ - c_p->freason = SYSTEM_LIMIT; - } else { - c_p->freason = BADARG; - } -} - -/* Set the exception code for bs_add argument errors after the fact, which is - * much easier and more compact than discriminating within module code. */ -void beam_jit_bs_add_argument_error(Process *c_p, Eterm A, Eterm B) { - if (((is_small(A) && signed_val(A) >= 0) || (is_big(A) && !big_sign(A))) && - ((is_small(B) && signed_val(B) >= 0) || (is_big(B) && !big_sign(B)))) { - /* If all arguments are positive integers, we must've had a system_limit - * error. */ - c_p->freason = SYSTEM_LIMIT; - } else { - c_p->freason = BADARG; - } -} - -static Eterm i_bs_start_match2_gc_test_preserve(Process *c_p, - Eterm *reg, - Uint need, - Uint live, - Eterm preserve) { - Uint words_left = (Uint)(STACK_TOP(c_p) - HEAP_TOP(c_p)); - - if (ERTS_UNLIKELY(words_left < need + S_RESERVED)) { - reg[live] = preserve; - PROCESS_MAIN_CHK_LOCKS(c_p); - c_p->fcalls -= erts_garbage_collect_nobump(c_p, - need, - reg, - live + 1, - c_p->fcalls); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - preserve = reg[live]; - } - - return preserve; -} - -Eterm beam_jit_bs_start_match2(Eterm context, - Uint live, - Uint slots, - Process *c_p, - Eterm *reg) { - Eterm header; - if (!is_boxed(context)) { - return THE_NON_VALUE; - } - header = *boxed_val(context); - - slots++; - - if (header_is_bin_matchstate(header)) { - ErlBinMatchState *ms = (ErlBinMatchState *)boxed_val(context); - Uint actual_slots = HEADER_NUM_SLOTS(header); - - /* We're not compatible with contexts created by bs_start_match3. */ - ASSERT(actual_slots >= 1); - - ms->save_offset[0] = ms->mb.offset; - if (ERTS_UNLIKELY(actual_slots < slots)) { - ErlBinMatchState *expanded; - Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots); - context = i_bs_start_match2_gc_test_preserve(c_p, - reg, - wordsneeded, - live, - context); - ms = (ErlBinMatchState *)boxed_val(context); - expanded = (ErlBinMatchState *)HEAP_TOP(c_p); - *expanded = *ms; - *HEAP_TOP(c_p) = HEADER_BIN_MATCHSTATE(slots); - HEAP_TOP(c_p) += wordsneeded; - context = make_matchstate(expanded); - } - return context; - } else if (is_binary_header(header)) { - Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots); - context = i_bs_start_match2_gc_test_preserve(c_p, - reg, - wordsneeded, - live, - context); - return erts_bs_start_match_2(c_p, context, slots); - } else { - return THE_NON_VALUE; - } -} - -Eterm beam_jit_bs_init(Process *c_p, - Eterm *reg, - ERL_BITS_DECLARE_STATEP, - Eterm BsOp1, - Eterm BsOp2, - unsigned Live) { - if (BsOp1 <= ERL_ONHEAP_BIN_LIMIT) { - ErlHeapBin *hb; - Uint bin_need; - - bin_need = heap_bin_size(BsOp1); - erts_bin_offset = 0; - erts_writable_bin = 0; - gc_test(c_p, reg, 0, bin_need + BsOp2 + ERL_SUB_BIN_SIZE, Live); - hb = (ErlHeapBin *)c_p->htop; - c_p->htop += bin_need; - hb->thing_word = header_heap_bin(BsOp1); - hb->size = BsOp1; - erts_current_bin = (byte *)hb->data; - return make_binary(hb); - } else { - Binary *bptr; - ProcBin *pb; - - erts_bin_offset = 0; - erts_writable_bin = 0; - test_bin_vheap(c_p, - reg, - BsOp1 / sizeof(Eterm), - BsOp2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, - Live); - - /* - * Allocate the binary struct itself. - */ - bptr = erts_bin_nrml_alloc(BsOp1); - erts_current_bin = (byte *)bptr->orig_bytes; - - /* - * Now allocate the ProcBin on the heap. - */ - pb = (ProcBin *)c_p->htop; - c_p->htop += PROC_BIN_SIZE; - pb->thing_word = HEADER_PROC_BIN; - pb->size = BsOp1; - pb->next = MSO(c_p).first; - MSO(c_p).first = (struct erl_off_heap_header *)pb; - pb->val = bptr; - pb->bytes = (byte *)bptr->orig_bytes; - pb->flags = 0; - - OH_OVERHEAD(&(MSO(c_p)), BsOp1 / sizeof(Eterm)); - - return make_binary(pb); - } -} - -Eterm beam_jit_bs_init_bits(Process *c_p, - Eterm *reg, - ERL_BITS_DECLARE_STATEP, - Uint num_bits, - Uint alloc, - unsigned Live) { - Eterm new_binary; - Uint num_bytes = ((Uint64)num_bits + (Uint64)7) >> 3; - - if (num_bits & 7) { - alloc += ERL_SUB_BIN_SIZE; - } - if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { - alloc += heap_bin_size(num_bytes); - } else { - alloc += PROC_BIN_SIZE; - } - gc_test(c_p, reg, 0, alloc, Live); - - /* num_bits = Number of bits to build - * num_bytes = Number of bytes to allocate in the binary - * alloc = Total number of words to allocate on heap - * Operands: NotUsed NotUsed Dst - */ - if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { - ErlHeapBin *hb; - - erts_bin_offset = 0; - erts_writable_bin = 0; - hb = (ErlHeapBin *)c_p->htop; - c_p->htop += heap_bin_size(num_bytes); - hb->thing_word = header_heap_bin(num_bytes); - hb->size = num_bytes; - erts_current_bin = (byte *)hb->data; - new_binary = make_binary(hb); - - do_bits_sub_bin: - if (num_bits & 7) { - ErlSubBin *sb; - - sb = (ErlSubBin *)c_p->htop; - c_p->htop += ERL_SUB_BIN_SIZE; - sb->thing_word = HEADER_SUB_BIN; - sb->size = num_bytes - 1; - sb->bitsize = num_bits & 7; - sb->offs = 0; - sb->bitoffs = 0; - sb->is_writable = 0; - sb->orig = new_binary; - new_binary = make_binary(sb); - } - /* HEAP_SPACE_VERIFIED(0); */ - return new_binary; - } else { - Binary *bptr; - ProcBin *pb; - - erts_bin_offset = 0; - erts_writable_bin = 0; - - /* - * Allocate the binary struct itself. - */ - bptr = erts_bin_nrml_alloc(num_bytes); - erts_current_bin = (byte *)bptr->orig_bytes; - - /* - * Now allocate the ProcBin on the heap. - */ - pb = (ProcBin *)c_p->htop; - c_p->htop += PROC_BIN_SIZE; - pb->thing_word = HEADER_PROC_BIN; - pb->size = num_bytes; - pb->next = MSO(c_p).first; - MSO(c_p).first = (struct erl_off_heap_header *)pb; - pb->val = bptr; - pb->bytes = (byte *)bptr->orig_bytes; - pb->flags = 0; - OH_OVERHEAD(&(MSO(c_p)), pb->size / sizeof(Eterm)); - new_binary = make_binary(pb); - goto do_bits_sub_bin; - } -} - -Eterm beam_jit_bs_get_integer(Process *c_p, - Eterm *reg, - Eterm context, - Uint flags, - Uint size, - Uint Live) { - ErlBinMatchBuffer *mb; - - if (size >= SMALL_BITS) { - Uint wordsneeded; - - /* Check bits size before potential gc. - * We do not want a gc and then realize we don't need - * the allocated space (i.e. if the op fails). - * - * Remember to re-acquire the matchbuffer after gc. - */ - mb = ms_matchbuffer(context); - if (mb->size - mb->offset < size) { - return THE_NON_VALUE; - } - - wordsneeded = 1 + WSIZE(NBYTES((Uint)size)); - reg[Live] = context; - gc_test(c_p, reg, 0, wordsneeded, Live + 1); - context = reg[Live]; - } - - mb = ms_matchbuffer(context); - return erts_bs_get_integer_2(c_p, size, flags, mb); -} - -void beam_jit_bs_context_to_binary(Eterm context) { - if (is_boxed(context) && header_is_bin_matchstate(*boxed_val(context))) { - Uint orig, size, offs, hole_size; - ErlBinMatchBuffer *mb; - ErlBinMatchState *ms; - ErlSubBin *sb; - ms = (ErlBinMatchState *)boxed_val(context); - mb = &ms->mb; - offs = ms->save_offset[0]; - size = mb->size - offs; - orig = mb->orig; - sb = (ErlSubBin *)boxed_val(context); - /* Since we're going to overwrite the match state with the result, an - * ErlBinMatchState must be at least as large as an ErlSubBin. */ - ERTS_CT_ASSERT(sizeof(ErlSubBin) <= sizeof(ErlBinMatchState)); - hole_size = 1 + header_arity(sb->thing_word) - ERL_SUB_BIN_SIZE; - sb->thing_word = HEADER_SUB_BIN; - sb->size = BYTE_OFFSET(size); - sb->bitsize = BIT_OFFSET(size); - sb->offs = BYTE_OFFSET(offs); - sb->bitoffs = BIT_OFFSET(offs); - sb->is_writable = 0; - sb->orig = orig; - if (hole_size) { - sb[1].thing_word = make_pos_bignum_header(hole_size - 1); - } - } -} - -ErtsMessage *beam_jit_decode_dist(Process *c_p, ErtsMessage *msgp) { - if (!erts_proc_sig_decode_dist(c_p, ERTS_PROC_LOCK_MAIN, msgp, 0)) { - /* - * A corrupt distribution message that we weren't able to decode; - * remove it... - */ - - /* TODO: Add DTrace probe for this bad message situation? */ - erts_msgq_unlink_msg(c_p, msgp); - msgp->next = NULL; - erts_cleanup_messages(msgp); - - return NULL; - } - - return msgp; -} - -/* Remove a (matched) message from the message queue. */ -Sint beam_jit_remove_message(Process *c_p, - Sint FCALLS, - Eterm *HTOP, - Eterm *E, - Uint32 active_code_ix) { - ErtsMessage *msgp; - - ERTS_CHK_MBUF_SZ(c_p); - - if (active_code_ix == ERTS_SAVE_CALLS_CODE_IX) { - save_calls(c_p, &exp_receive); - } - - msgp = erts_msgq_peek_msg(c_p); - - if (ERL_MESSAGE_TOKEN(msgp) == NIL) { -#ifdef USE_VM_PROBES - if (DT_UTAG(c_p) != NIL) { - if (DT_UTAG_FLAGS(c_p) & DT_UTAG_PERMANENT) { - SEQ_TRACE_TOKEN(c_p) = am_have_dt_utag; - } else { - DT_UTAG(c_p) = NIL; - SEQ_TRACE_TOKEN(c_p) = NIL; - } - } else { -#endif - SEQ_TRACE_TOKEN(c_p) = NIL; -#ifdef USE_VM_PROBES - } - DT_UTAG_FLAGS(c_p) &= ~DT_UTAG_SPREADING; -#endif - } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) { - Eterm msg; - SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp); -#ifdef USE_VM_PROBES - if (ERL_MESSAGE_TOKEN(msgp) == am_have_dt_utag) { - if (DT_UTAG(c_p) == NIL) { - DT_UTAG(c_p) = ERL_MESSAGE_DT_UTAG(msgp); - } - DT_UTAG_FLAGS(c_p) |= DT_UTAG_SPREADING; - } else { -#endif - ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p))); - ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); - ASSERT(is_small(SEQ_TRACE_TOKEN_SERIAL(c_p))); - ASSERT(is_small(SEQ_TRACE_TOKEN_LASTCNT(c_p))); - ASSERT(is_small(SEQ_TRACE_TOKEN_FLAGS(c_p))); - ASSERT(is_pid(SEQ_TRACE_TOKEN_SENDER(c_p)) || - is_atom(SEQ_TRACE_TOKEN_SENDER(c_p))); - c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); - if (c_p->seq_trace_clock < - unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) { - c_p->seq_trace_clock = - unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); - } - msg = ERL_MESSAGE_TERM(msgp); - seq_trace_output(SEQ_TRACE_TOKEN(c_p), - msg, - SEQ_TRACE_RECEIVE, - c_p->common.id, - c_p); -#ifdef USE_VM_PROBES - } -#endif - } -#ifdef USE_VM_PROBES - if (DTRACE_ENABLED(message_receive)) { - Eterm token2 = NIL; - DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - Sint tok_label = 0; - Sint tok_lastcnt = 0; - Sint tok_serial = 0; - Sint len = erts_proc_sig_privqs_len(c_p); - - dtrace_proc_str(c_p, receiver_name); - token2 = SEQ_TRACE_TOKEN(c_p); - if (have_seqtrace(token2)) { - tok_label = SEQ_TRACE_T_DTRACE_LABEL(token2); - tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); - tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); - } - DTRACE6(message_receive, - receiver_name, - size_object(ERL_MESSAGE_TERM(msgp)), - len, /* This is NOT message queue len, but its something... */ - tok_label, - tok_lastcnt, - tok_serial); - } -#endif - erts_msgq_unlink_msg_set_save_first(c_p, msgp); - CANCEL_TIMER(c_p); - - erts_save_message_in_proc(c_p, msgp); - c_p->flags &= ~F_DELAY_GC; - - if (ERTS_IS_GC_DESIRED_INTERNAL(c_p, HTOP, E, 0)) { - /* - * We want to GC soon but we leave a few - * reductions giving the message some time - * to turn into garbage. - */ - ERTS_VBUMP_LEAVE_REDS_INTERNAL(c_p, 5, FCALLS); - } - - ERTS_CHK_MBUF_SZ(c_p); - - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - return FCALLS; -} - -void beam_jit_take_receive_lock(Process *c_p) { - erts_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); -} - -void beam_jit_wait_locked(Process *c_p, ErtsCodePtr cp) { - c_p->arity = 0; - if (!ERTS_PTMR_IS_TIMED_OUT(c_p)) { - erts_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); - } - ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); - c_p->current = NULL; - c_p->i = cp; -} - -void beam_jit_wait_unlocked(Process *c_p, ErtsCodePtr cp) { - beam_jit_take_receive_lock(c_p); - beam_jit_wait_locked(c_p, cp); -} - -enum beam_jit_tmo_ret beam_jit_wait_timeout(Process *c_p, - Eterm timeout_value, - ErtsCodePtr next) { - /* - * If we have already set the timer, we must NOT set it again. Therefore, - * we must test the F_INSLPQUEUE flag as well as the F_TIMO flag. - */ - if ((c_p->flags & (F_INSLPQUEUE | F_TIMO)) == 0) { - if (timeout_value == make_small(0)) { - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); - return RET_next; - } else if (timeout_value == am_infinity) { - c_p->flags |= F_TIMO; - } else { - int tres = erts_set_proc_timer_term(c_p, timeout_value); - if (tres == 0) { - /* - * The timer routiner will set c_p->i to the value in - * c_p->def_arg_reg[0]. Note that it is safe to use this - * location because there are no living x registers in - * a receive statement. - */ - c_p->def_arg_reg[0] = (Eterm)next; - } else { /* Wrong time */ - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); - c_p->freason = EXC_TIMEOUT_VALUE; - erts_msgq_set_save_first(c_p); - return RET_badarg; - } - } - } - return RET_wait; -} - -void beam_jit_timeout(Process *c_p) { - if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { - trace_receive(c_p, am_clock_service, am_timeout, NULL); - } - if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { - save_calls(c_p, &exp_timeout); - } - c_p->flags &= ~F_TIMO; - erts_msgq_set_save_first(c_p); -} - -void beam_jit_timeout_locked(Process *c_p) { - erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); - beam_jit_timeout(c_p); -} diff --git a/erts/emulator/beam/jit/beam_jit_common.cpp b/erts/emulator/beam/jit/beam_jit_common.cpp new file mode 100644 index 000000000000..3200f75407c2 --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_common.cpp @@ -0,0 +1,1391 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021-2023. 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% + */ + +#include "beam_jit_common.hpp" +#include "beam_asm.hpp" + +extern "C" +{ +#include "sys.h" +#include "erl_vm.h" +#include "global.h" +#include "code_ix.h" +#include "erl_proc_sig_queue.h" +#include "erl_binary.h" +#include "erl_bits.h" +#include "erl_map.h" +#include "beam_common.h" +#ifdef USE_VM_PROBES +# include "dtrace-wrapper.h" +#endif +} + +static std::string getAtom(Eterm atom) { + Atom *ap = atom_tab(atom_val(atom)); + return std::string((char *)ap->name, ap->len); +} + +BeamAssemblerCommon::BeamAssemblerCommon(BaseAssembler &assembler_) + : assembler(assembler_), code() { + /* Setup with default code info */ + Error err = code.init(Environment::host()); + ERTS_ASSERT(!err && "Failed to init codeHolder"); + + err = code.newSection(&rodata, + ".rodata", + SIZE_MAX, + SectionFlags::kReadOnly, + 8); + ERTS_ASSERT(!err && "Failed to create .rodata section"); + +#ifdef DEBUG + assembler.addDiagnosticOptions(DiagnosticOptions::kValidateAssembler); +#endif + assembler.addEncodingOptions(EncodingOptions::kOptimizeForSize | + EncodingOptions::kOptimizedAlign); + code.setErrorHandler(this); +} + +BeamAssemblerCommon::~BeamAssemblerCommon() { + if (logger.file()) { + fclose(logger.file()); + } +} + +void *BeamAssemblerCommon::getBaseAddress() { + ASSERT(code.hasBaseAddress()); + return (void *)code.baseAddress(); +} + +size_t BeamAssemblerCommon::getOffset() { + return assembler.offset(); +} + +void BeamAssemblerCommon::codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr) { + Error err; + + err = code.flatten(); + ERTS_ASSERT(!err && "Could not flatten code"); + err = code.resolveUnresolvedLinks(); + ERTS_ASSERT(!err && "Could not resolve all links"); + + /* Verify that all labels are bound */ +#ifdef DEBUG + for (auto e : code.labelEntries()) { + if (!e->isBound()) { + if (e->hasName()) { + erts_exit(ERTS_ABORT_EXIT, + "Label %d with name %s is not bound\n", + e->id(), + e->name()); + } else { + erts_exit(ERTS_ABORT_EXIT, "Label %d is not bound\n", e->id()); + } + } + } +#endif + + err = allocator->alloc(const_cast(executable_ptr), + writable_ptr, + code.codeSize() + 16); + + if (err == ErrorCode::kErrorTooManyHandles) { + ERTS_ASSERT(!"Failed to allocate module code: " + "out of file descriptors"); + } else if (err) { + ERTS_ASSERT("Failed to allocate module code"); + } + + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite); + + code.relocateToBase((uint64_t)*executable_ptr); + code.copyFlattenedData(*writable_ptr, + code.codeSize(), + CopySectionFlags::kPadSectionBuffer); + +#ifdef DEBUG + if (FileLogger *l = dynamic_cast(code.logger())) + if (FILE *f = l->file()) + fprintf(f, "; CODE_SIZE: %zd\n", code.codeSize()); +#endif +} + +void *BeamAssemblerCommon::getCode(Label label) { + ASSERT(label.isValid()); + return (char *)getBaseAddress() + code.labelOffsetFromBase(label); +} + +byte *BeamAssemblerCommon::getCode(char *labelName) { + return (byte *)getCode(code.labelByName(labelName, strlen(labelName))); +} + +void BeamAssemblerCommon::handleError(Error err, + const char *message, + BaseEmitter *origin) { + comment(message); + + if (logger.file() != NULL) { + fflush(logger.file()); + } + + ASSERT(0 && "Failed to encode instruction"); +} + +void BeamAssemblerCommon::embed_rodata(const char *labelName, + const char *buff, + size_t size) { + Label label = assembler.newNamedLabel(labelName); + + assembler.section(rodata); + assembler.bind(label); + assembler.embed(buff, size); + assembler.section(code.textSection()); +} + +void BeamAssemblerCommon::embed_bss(const char *labelName, size_t size) { + Label label = assembler.newNamedLabel(labelName); + + /* Reuse rodata section for now */ + assembler.section(rodata); + assembler.bind(label); + embed_zeros(size); + assembler.section(code.textSection()); +} + +void BeamAssemblerCommon::embed_zeros(size_t size) { + static constexpr size_t buf_size = 16384; + static const char zeros[buf_size] = {}; + + while (size >= buf_size) { + assembler.embed(zeros, buf_size); + size -= buf_size; + } + + if (size > 0) { + assembler.embed(zeros, size); + } +} + +void BeamAssemblerCommon::setLogger(const std::string &log) { + FILE *f = fopen(log.data(), "w+"); + + /* FIXME: Don't crash when loading multiple modules with the same name. + * + * setLogger(nullptr) disables logging. */ + if (f) { + setvbuf(f, NULL, _IONBF, 0); + } + + setLogger(f); +} + +void BeamAssemblerCommon::setLogger(FILE *log) { + logger.setFile(log); + logger.setIndentation(FormatIndentationGroup::kCode, 4); + code.setLogger(&logger); +} + +void BeamModuleAssembler::codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr, + const BeamCodeHeader *in_hdr, + const BeamCodeHeader **out_exec_hdr, + BeamCodeHeader **out_rw_hdr) { + const BeamCodeHeader *code_hdr_exec; + BeamCodeHeader *code_hdr_rw; + + BeamAssembler::codegen(allocator, executable_ptr, writable_ptr); + + { + auto offset = code.labelOffsetFromBase(code_header); + + auto base_exec = (const char *)(*executable_ptr); + code_hdr_exec = (const BeamCodeHeader *)&base_exec[offset]; + + auto base_rw = (const char *)(*writable_ptr); + code_hdr_rw = (BeamCodeHeader *)&base_rw[offset]; + } + + sys_memcpy(code_hdr_rw, in_hdr, sizeof(BeamCodeHeader)); + code_hdr_rw->on_load = getOnLoad(); + + for (unsigned i = 0; i < functions.size(); i++) { + ErtsCodeInfo *ci = (ErtsCodeInfo *)getCode(functions[i]); + code_hdr_rw->functions[i] = ci; + } + + char *module_end = (char *)code.baseAddress() + a.offset(); + code_hdr_rw->functions[functions.size()] = (ErtsCodeInfo *)module_end; + + /* Note that we don't make the module executable yet since we're going to + * patch literals et cetera and it's pointless to ping-pong the page + * permissions. The user will call `beamasm_seal_module` to do so later + * on. */ + + *out_exec_hdr = code_hdr_exec; + *out_rw_hdr = code_hdr_rw; +} + +void BeamModuleAssembler::codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr) { + BeamAssembler::codegen(allocator, executable_ptr, writable_ptr); + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute); +} + +void BeamModuleAssembler::codegen(char *buff, size_t len) { + code.flatten(); + code.resolveUnresolvedLinks(); + ERTS_ASSERT(code.codeSize() <= len); + code.relocateToBase((uint64_t)buff); + code.copyFlattenedData(buff, + code.codeSize(), + CopySectionFlags::kPadSectionBuffer); +} + +BeamModuleAssembler::BeamModuleAssembler(BeamGlobalAssembler *_ga, + Eterm _mod, + int num_labels, + const BeamFile *file) + : BeamAssembler(getAtom(_mod)), BeamModuleAssemblerCommon(file, _mod), + ga(_ga) { + rawLabels.reserve(num_labels + 1); + + if (logger.file() && beam) { + /* Dig out all named labels from the BEAM-file and sort them on the + * label id. */ + const int named_count = beam->exports.count + beam->locals.count; + BeamFile_ExportEntry *entries; + + entries = (BeamFile_ExportEntry *)erts_alloc( + ERTS_ALC_T_PREPARED_CODE, + (named_count + 1) * sizeof(entries[0])); + + for (int i = 0; i < beam->exports.count; i++) { + entries[i] = beam->exports.entries[i]; + } + + for (int i = 0; i < beam->locals.count; i++) { + entries[i + beam->exports.count] = beam->locals.entries[i]; + } + + /* Place a sentinel entry with an invalid label number. */ + entries[named_count].label = 0; + + std::qsort(entries, + named_count, + sizeof(entries[0]), + [](const void *lhs__, const void *rhs__) { + auto lhs = (const BeamFile_ExportEntry *)lhs__; + auto rhs = (const BeamFile_ExportEntry *)rhs__; + + if (lhs->label < rhs->label) { + return -1; + } else if (lhs->label == rhs->label) { + return 0; + } else { + return 1; + } + }); + + BeamFile_ExportEntry *e = &entries[0]; + + for (int i = 1; i < num_labels; i++) { + /* Large enough to hold most realistic function names. We will + * truncate too long names, but as the label name is not important + * for the functioning of the JIT and this functionality is + * probably only used by developers, we don't bother with dynamic + * allocation. */ + char tmp[MAX_ATOM_SZ_LIMIT]; + + /* The named_labels are sorted, so no need for a search. */ + if (e->label == i) { + erts_snprintf(tmp, sizeof(tmp), "%T/%d", e->function, e->arity); + rawLabels.emplace(i, a.newNamedLabel(tmp)); + e++; + } else { + std::string lblName = "label_" + std::to_string(i); + rawLabels.emplace(i, a.newNamedLabel(lblName.data())); + } + } + + erts_free(ERTS_ALC_T_PREPARED_CODE, entries); + } else if (logger.file()) { + /* There is no naming info, but dumping of the assembly code + * has been requested, so do the best we can and number the + * labels. */ + for (int i = 1; i < num_labels; i++) { + std::string lblName = "label_" + std::to_string(i); + rawLabels.emplace(i, a.newNamedLabel(lblName.data())); + } + } else { + /* No output is requested, go with unnamed labels */ + for (int i = 1; i < num_labels; i++) { + rawLabels.emplace(i, a.newLabel()); + } + } + + if (beam) { + /* Create labels for the trampolines that unpack fun environments. + * + * Note that `num_free == 0` short-circuits directly to the target. */ + for (int i = 0; i < beam->lambdas.count; i++) { + const auto &lambda = beam->lambdas.entries[i]; + lambdas[i].trampoline = (lambda.num_free > 0) + ? a.newLabel() + : rawLabels.at(lambda.label); + } + } +} + +void BeamModuleAssembler::register_metadata(const BeamCodeHeader *header) { +#ifndef WIN32 + const BeamCodeLineTab *line_table = header->line_table; + + char name_buffer[MAX_ATOM_SZ_LIMIT]; + std::string module_name = getAtom(mod); + std::vector ranges; + ERTS_DECL_AM(erts_beamasm); + + ranges.reserve(functions.size() + 2); + + ASSERT((ErtsCodePtr)getBaseAddress() == (ErtsCodePtr)header); + ASSERT(functions.size() == header->num_functions); + + /* Push info about the header */ + ranges.push_back({.start = (ErtsCodePtr)getBaseAddress(), + .stop = (ErtsCodePtr)&header->functions[functions.size()], + .name = module_name + "::codeHeader"}); + + for (unsigned i = 0; i < functions.size(); i++) { + std::vector lines; + ErtsCodePtr start, stop; + const ErtsCodeInfo *ci; + Sint n; + + start = getCode(functions[i]); + ci = (const ErtsCodeInfo *)start; + + stop = ((const char *)erts_codeinfo_to_code(ci)); + + if (ci->mfa.module != AM_erts_beamasm) { + /* All modules (except erts_beamasm, which is a JIT internal module) + have a prologue that should be counted as part of the CodeInfo */ + stop = ((const char *)stop) + BEAM_ASM_FUNC_PROLOGUE_SIZE; + } + + n = erts_snprintf(name_buffer, + 1024, + "%T:%T/%d", + ci->mfa.module, + ci->mfa.function, + ci->mfa.arity); + + /* We use a different symbol for CodeInfo and the Prologue + * in order for the perf disassembly to be better. */ + std::string function_name(name_buffer, n); + ranges.push_back({.start = start, + .stop = stop, + .name = function_name + "-CodeInfoPrologue"}); + + /* The actual code */ + start = stop; + if (i + 1 < functions.size()) { + stop = getCode(functions[i + 1]); + } else { + stop = getCode(code_end); + } + + if (line_table) { + const void **line_cursor = line_table->func_tab[i]; + const int loc_size = line_table->loc_size; + + /* Register all lines belonging to this function. */ + while ((intptr_t)line_cursor[0] < (intptr_t)stop) { + ptrdiff_t line_index; + Uint32 loc; + + line_index = line_cursor - line_table->func_tab[0]; + + if (loc_size == 2) { + loc = line_table->loc_tab.p2[line_index]; + } else { + ASSERT(loc_size == 4); + loc = line_table->loc_tab.p4[line_index]; + } + + if (loc != LINE_INVALID_LOCATION) { + Uint32 file; + Eterm fname; + int res; + + file = LOC_FILE(loc); + fname = line_table->fname_ptr[file]; + + ERTS_ASSERT(is_nil(fname) || is_list(fname)); + + res = erts_unicode_list_to_buf(fname, + (byte *)name_buffer, + sizeof(name_buffer), + sizeof(name_buffer) / 4, + &n); + + ERTS_ASSERT(res != -1); + + lines.push_back({.start = line_cursor[0], + .file = std::string(name_buffer, n), + .line = LOC_LINE(loc)}); + } + + line_cursor++; + } + } + + ranges.push_back({.start = start, + .stop = stop, + .name = function_name, + .lines = lines}); + } + + /* Push info about the footer */ + ranges.push_back( + {.start = ranges.back().stop, + .stop = (ErtsCodePtr)(code.baseAddress() + code.codeSize()), + .name = module_name + "::codeFooter"}); + + beamasm_metadata_update(module_name, + (ErtsCodePtr)code.baseAddress(), + code.codeSize(), + ranges); +#endif +} + +BeamCodeHeader *BeamModuleAssembler::getCodeHeader() { + return (BeamCodeHeader *)getCode(code_header); +} + +const ErtsCodeInfo *BeamModuleAssembler::getOnLoad() { + if (on_load.isValid()) { + return erts_code_to_codeinfo((ErtsCodePtr)getCode(on_load)); + } else { + return 0; + } +} + +unsigned BeamModuleAssembler::patchCatches(char *rw_base) { + unsigned catch_no = BEAM_CATCHES_NIL; + + for (const auto &c : catches) { + const auto &patch = c.patch; + ErtsCodePtr handler; + + handler = (ErtsCodePtr)getCode(c.handler); + catch_no = beam_catches_cons(handler, catch_no, nullptr); + + /* Patch the `mov` instruction with the catch tag */ + auto offset = code.labelOffsetFromBase(patch.where); + auto where = (int32_t *)&rw_base[offset + patch.ptr_offs]; + + ASSERT(INT_MAX == *where); + Eterm catch_term = make_catch(catch_no); + + /* With the current tag scheme, more than 33 million + * catches can exist at once. */ + ERTS_ASSERT(catch_term >> 31 == 0); + + *where = catch_term; + } + + return catch_no; +} + +void BeamModuleAssembler::patchImport(char *rw_base, + unsigned index, + const Export *import) { + for (const auto &patch : imports[index].patches) { + auto offset = code.labelOffsetFromBase(patch.where); + auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; + + ASSERT(LLONG_MAX == *where); + *where = reinterpret_cast(import) + patch.val_offs; + } +} + +void BeamModuleAssembler::patchLambda(char *rw_base, + unsigned index, + const ErlFunEntry *fe) { + for (const auto &patch : lambdas[index].patches) { + auto offset = code.labelOffsetFromBase(patch.where); + auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; + + ASSERT(LLONG_MAX == *where); + *where = reinterpret_cast(fe) + patch.val_offs; + } +} + +void BeamModuleAssembler::patchLiteral(char *rw_base, + unsigned index, + Eterm lit) { + for (const auto &patch : literals[index].patches) { + auto offset = code.labelOffsetFromBase(patch.where); + auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; + + ASSERT(LLONG_MAX == *where); + *where = lit + patch.val_offs; + } +} + +void BeamModuleAssembler::patchStrings(char *rw_base, + const byte *string_table) { + for (const auto &patch : strings) { + auto offset = code.labelOffsetFromBase(patch.where); + auto where = (const byte **)&rw_base[offset + patch.ptr_offs]; + + ASSERT(LLONG_MAX == (Eterm)*where); + *where = string_table + patch.val_offs; + } +} + +/* ** */ + +#if defined(DEBUG) && defined(JIT_HARD_DEBUG) +void beam_jit_validate_term(Eterm term) { + if (is_boxed(term)) { + Eterm header = *boxed_val(term); + + if (header_is_bin_matchstate(header)) { + return; + } + } + + size_object_x(term, NULL); +} +#endif + +Eterm beam_jit_call_bif(Process *c_p, + Eterm *reg, + ErtsCodePtr I, + ErtsBifFunc vbf, + Uint arity) { + ErlHeapFragment *live_hf_end; + Eterm result; + + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + { + live_hf_end = c_p->mbuf; + + ERTS_CHK_MBUF_SZ(c_p); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + result = vbf(c_p, reg, I); + ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result)); + ERTS_CHK_MBUF_SZ(c_p); + + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + ERTS_HOLE_CHECK(c_p); + } + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + + if (ERTS_IS_GC_AFTER_BIF_DESIRED(c_p)) { + result = erts_gc_after_bif_call_lhf(c_p, + live_hf_end, + result, + reg, + arity); + } + + return result; +} + +Eterm beam_jit_call_nif(Process *c_p, + ErtsCodePtr I, + Eterm *reg, + BeamJitNifF *fp, + struct erl_module_nif *NifMod) { + Eterm nif_bif_result; + Eterm bif_nif_arity; + ErlHeapFragment *live_hf_end; + const ErtsCodeMFA *codemfa; + + codemfa = erts_code_to_codemfa(I); + + c_p->current = codemfa; /* current and vbf set to please handle_error */ + + bif_nif_arity = codemfa->arity; + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + + { + struct enif_environment_t env; + ASSERT(c_p->scheduler_data); + live_hf_end = c_p->mbuf; + ERTS_CHK_MBUF_SZ(c_p); + erts_pre_nif(&env, c_p, NifMod, NULL); + + ASSERT((c_p->scheduler_data)->current_nif == NULL); + (c_p->scheduler_data)->current_nif = &env; + + nif_bif_result = (*fp)(&env, bif_nif_arity, reg); + if (env.exception_thrown) + nif_bif_result = THE_NON_VALUE; + + ASSERT((c_p->scheduler_data)->current_nif == &env); + (c_p->scheduler_data)->current_nif = NULL; + + erts_post_nif(&env); + ERTS_CHK_MBUF_SZ(c_p); + + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + ASSERT(!env.exiting); + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + } + ERTS_REQ_PROC_MAIN_LOCK(c_p); + ERTS_HOLE_CHECK(c_p); + + if (ERTS_IS_GC_AFTER_BIF_DESIRED(c_p)) { + nif_bif_result = erts_gc_after_bif_call_lhf(c_p, + live_hf_end, + nif_bif_result, + reg, + bif_nif_arity); + } + + return nif_bif_result; +} + +enum beam_jit_nif_load_ret beam_jit_load_nif(Process *c_p, + ErtsCodePtr I, + Eterm *reg) { + if (erts_try_seize_code_mod_permission(c_p)) { + Eterm result; + + PROCESS_MAIN_CHK_LOCKS((c_p)); + ERTS_UNREQ_PROC_MAIN_LOCK((c_p)); + result = erts_load_nif(c_p, I, reg[0], reg[1]); + erts_release_code_mod_permission(); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + + if (ERTS_LIKELY(is_value(result))) { + reg[0] = result; + return RET_NIF_success; + } else { + c_p->freason = BADARG; + return RET_NIF_error; + } + } else { + /* Yield and try again. */ + c_p->current = NULL; + c_p->arity = 2; + return RET_NIF_yield; + } +} + +Uint beam_jit_get_map_elements(Eterm map, + Eterm *reg, + Eterm *E, + Uint n, + Eterm *fs) { + Uint sz; + + /* This instruction assumes Arg1 is a map, i.e. that it follows a test + * is_map if needed. */ + + if (is_flatmap(map)) { + flatmap_t *mp; + Eterm *ks; + Eterm *vs; + + mp = (flatmap_t *)flatmap_val(map); + sz = flatmap_get_size(mp); + + if (sz == 0) { + return 0; + } + + ks = flatmap_get_keys(mp); + vs = flatmap_get_values(mp); + + while (sz) { + if (EQ(fs[0], *ks)) { + PUT_TERM_REG(*vs, fs[1]); + + n--; + fs += 3; + + /* no more values to fetch, we are done */ + if (n == 0) { + return 1; + } + } + + ks++, sz--, vs++; + } + return 0; + } else { + ASSERT(is_hashmap(map)); + + while (n--) { + const Eterm *v; + Uint32 hx; + + hx = fs[2]; + ASSERT(hx == hashmap_make_hash(fs[0])); + + if ((v = erts_hashmap_get(hx, fs[0], map)) == NULL) { + return 0; + } + + PUT_TERM_REG(*v, fs[1]); + fs += 3; + } + + return 1; + } +} + +static void test_bin_vheap(Process *c_p, + Eterm *reg, + Uint VNh, + Uint Nh, + Uint Live) { + int need = Nh; + + if (c_p->stop - c_p->htop < (need + S_RESERVED) || + MSO(c_p).overhead + VNh >= c_p->bin_vheap_sz) { + c_p->fcalls -= + erts_garbage_collect_nobump(c_p, need, reg, Live, c_p->fcalls); + } +} + +static void gc_test(Process *c_p, Eterm *reg, Uint Ns, Uint Nh, Uint Live) { + int need = Nh + Ns; + + if (ERTS_UNLIKELY(c_p->stop - c_p->htop < (need + S_RESERVED))) { + c_p->fcalls -= + erts_garbage_collect_nobump(c_p, need, reg, Live, c_p->fcalls); + } +} + +void beam_jit_bs_field_size_argument_error(Process *c_p, Eterm size) { + if (((is_small(size) && signed_val(size) >= 0) || + (is_big(size) && !big_sign(size)))) { + /* If the argument is a positive integer, we must've had a system_limit + * error. */ + c_p->freason = SYSTEM_LIMIT; + } else { + c_p->freason = BADARG; + } +} + +/* Set the exception code for bs_add argument errors after the fact, which is + * much easier and more compact than discriminating within module code. */ +void beam_jit_bs_add_argument_error(Process *c_p, Eterm A, Eterm B) { + if (((is_small(A) && signed_val(A) >= 0) || (is_big(A) && !big_sign(A))) && + ((is_small(B) && signed_val(B) >= 0) || (is_big(B) && !big_sign(B)))) { + /* If all arguments are positive integers, we must've had a system_limit + * error. */ + c_p->freason = SYSTEM_LIMIT; + } else { + c_p->freason = BADARG; + } +} + +Eterm beam_jit_bs_init(Process *c_p, + Eterm *reg, + ERL_BITS_DECLARE_STATEP, + Eterm num_bytes, + Uint alloc, + unsigned Live) { + erts_bin_offset = 0; + if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { + ErlHeapBin *hb; + Uint bin_need; + + bin_need = heap_bin_size(num_bytes); + gc_test(c_p, reg, 0, bin_need + alloc + ERL_SUB_BIN_SIZE, Live); + hb = (ErlHeapBin *)c_p->htop; + c_p->htop += bin_need; + hb->thing_word = header_heap_bin(num_bytes); + hb->size = num_bytes; + erts_current_bin = (byte *)hb->data; + return make_binary(hb); + } else { + Binary *bptr; + ProcBin *pb; + + test_bin_vheap(c_p, + reg, + num_bytes / sizeof(Eterm), + alloc + PROC_BIN_SIZE, + Live); + + /* + * Allocate the binary struct itself. + */ + bptr = erts_bin_nrml_alloc(num_bytes); + erts_current_bin = (byte *)bptr->orig_bytes; + + /* + * Now allocate the ProcBin on the heap. + */ + pb = (ProcBin *)c_p->htop; + c_p->htop += PROC_BIN_SIZE; + pb->thing_word = HEADER_PROC_BIN; + pb->size = num_bytes; + pb->next = MSO(c_p).first; + MSO(c_p).first = (struct erl_off_heap_header *)pb; + pb->val = bptr; + pb->bytes = (byte *)bptr->orig_bytes; + pb->flags = 0; + + OH_OVERHEAD(&(MSO(c_p)), num_bytes / sizeof(Eterm)); + + return make_binary(pb); + } +} + +Eterm beam_jit_bs_init_bits(Process *c_p, + Eterm *reg, + ERL_BITS_DECLARE_STATEP, + Uint num_bits, + Uint alloc, + unsigned Live) { + Eterm new_binary; + Uint num_bytes = ((Uint64)num_bits + (Uint64)7) >> 3; + + if (num_bits & 7) { + alloc += ERL_SUB_BIN_SIZE; + } + if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { + alloc += heap_bin_size(num_bytes); + } else { + alloc += PROC_BIN_SIZE; + } + + erts_bin_offset = 0; + + /* num_bits = Number of bits to build + * num_bytes = Number of bytes to allocate in the binary + * alloc = Total number of words to allocate on heap + * Operands: NotUsed NotUsed Dst + */ + if (num_bytes <= ERL_ONHEAP_BIN_LIMIT) { + ErlHeapBin *hb; + + gc_test(c_p, reg, 0, alloc, Live); + hb = (ErlHeapBin *)c_p->htop; + c_p->htop += heap_bin_size(num_bytes); + hb->thing_word = header_heap_bin(num_bytes); + hb->size = num_bytes; + erts_current_bin = (byte *)hb->data; + new_binary = make_binary(hb); + } else { + Binary *bptr; + ProcBin *pb; + + test_bin_vheap(c_p, reg, num_bytes / sizeof(Eterm), alloc, Live); + + /* + * Allocate the binary struct itself. + */ + bptr = erts_bin_nrml_alloc(num_bytes); + erts_current_bin = (byte *)bptr->orig_bytes; + + /* + * Now allocate the ProcBin on the heap. + */ + pb = (ProcBin *)c_p->htop; + c_p->htop += PROC_BIN_SIZE; + pb->thing_word = HEADER_PROC_BIN; + pb->size = num_bytes; + pb->next = MSO(c_p).first; + MSO(c_p).first = (struct erl_off_heap_header *)pb; + pb->val = bptr; + pb->bytes = (byte *)bptr->orig_bytes; + pb->flags = 0; + OH_OVERHEAD(&(MSO(c_p)), pb->size / sizeof(Eterm)); + new_binary = make_binary(pb); + } + + if (num_bits & 7) { + ErlSubBin *sb; + + sb = (ErlSubBin *)c_p->htop; + c_p->htop += ERL_SUB_BIN_SIZE; + sb->thing_word = HEADER_SUB_BIN; + sb->size = num_bytes - 1; + sb->bitsize = num_bits & 7; + sb->offs = 0; + sb->bitoffs = 0; + sb->is_writable = 0; + sb->orig = new_binary; + new_binary = make_binary(sb); + } + + return new_binary; +} + +Eterm beam_jit_bs_get_integer(Process *c_p, + Eterm *reg, + Eterm context, + Uint flags, + Uint size, + Uint Live) { + ErlBinMatchBuffer *mb; + + if (size >= SMALL_BITS) { + Uint wordsneeded; + + /* Check bits size before potential gc. + * We do not want a gc and then realize we don't need + * the allocated space (i.e. if the op fails). + * + * Remember to re-acquire the matchbuffer after gc. + */ + mb = ms_matchbuffer(context); + if (mb->size - mb->offset < size) { + return THE_NON_VALUE; + } + + wordsneeded = 1 + WSIZE(NBYTES((Uint)size)); + reg[Live] = context; + gc_test(c_p, reg, 0, wordsneeded, Live + 1); + context = reg[Live]; + } + + mb = ms_matchbuffer(context); + return erts_bs_get_integer_2(c_p, size, flags, mb); +} + +void beam_jit_bs_construct_fail_info(Process *c_p, + Uint packed_error_info, + Eterm arg3, + Eterm arg1) { + Eterm *hp; + Eterm cause_tuple; + Eterm error_info; + Uint segment = beam_jit_get_bsc_segment(packed_error_info); + JitBSCOp op = beam_jit_get_bsc_op(packed_error_info); + JitBSCInfo info = beam_jit_get_bsc_info(packed_error_info); + JitBSCReason reason = beam_jit_get_bsc_reason(packed_error_info); + JitBSCValue value_location = beam_jit_get_bsc_value(packed_error_info); + Eterm Op = am_none; + Uint Reason = BADARG; + Eterm Info = am_none; + Eterm value = am_undefined; + + switch (op) { + case BSC_OP_BINARY: + Op = am_binary; + break; + case BSC_OP_FLOAT: + Op = am_float; + break; + case BSC_OP_INTEGER: + Op = am_integer; + break; + case BSC_OP_UTF8: + Op = am_utf8; + break; + case BSC_OP_UTF16: + Op = am_utf16; + break; + case BSC_OP_UTF32: + Op = am_utf32; + break; + } + + switch (value_location) { + case BSC_VALUE_ARG1: + value = arg1; + break; + case BSC_VALUE_ARG3: + value = arg3; + break; + case BSC_VALUE_FVALUE: + value = c_p->fvalue; + break; + } + + switch (reason) { + case BSC_REASON_BADARG: + Reason = BADARG; + break; + case BSC_REASON_SYSTEM_LIMIT: + Reason = SYSTEM_LIMIT; + break; + case BSC_REASON_DEPENDS: + if ((is_small(value) && signed_val(value) >= 0) || + (is_big(value) && !big_sign(value))) { + Reason = SYSTEM_LIMIT; + } else { + Reason = BADARG; + } + break; + } + + switch (info) { + case BSC_INFO_FVALUE: + Info = c_p->fvalue; + break; + case BSC_INFO_TYPE: + Info = am_type; + break; + case BSC_INFO_SIZE: + Info = am_size; + break; + case BSC_INFO_UNIT: + Info = am_unit; + break; + case BSC_INFO_DEPENDS: + ASSERT(op == BSC_OP_BINARY); + Info = is_binary(value) ? am_short : am_type; + break; + } + + hp = HAlloc(c_p, Sint(MAP3_SZ + 5)); + cause_tuple = TUPLE4(hp, make_small(segment), Op, Info, value); + hp += 5; + error_info = MAP3(hp, + am_cause, + cause_tuple, + am_function, + am_format_bs_fail, + am_module, + am_erl_erts_errors); + c_p->fvalue = error_info; + c_p->freason = Reason | EXF_HAS_EXT_INFO; +} + +Sint beam_jit_bs_bit_size(Eterm term) { + if (is_binary(term)) { + ASSERT(sizeof(Uint) == 8); /* Only support 64-bit machines. */ + Uint byte_size = binary_size(term); + return (Sint)((byte_size << 3) + binary_bitsize(term)); + } + + /* Signal error */ + return (Sint)-1; +} + +ErtsMessage *beam_jit_decode_dist(Process *c_p, ErtsMessage *msgp) { + if (!erts_proc_sig_decode_dist(c_p, ERTS_PROC_LOCK_MAIN, msgp, 0)) { + /* + * A corrupt distribution message that we weren't able to decode; + * remove it... + */ + + /* TODO: Add DTrace probe for this bad message situation? */ + erts_msgq_unlink_msg(c_p, msgp); + msgp->next = NULL; + erts_cleanup_messages(msgp); + + return NULL; + } + + return msgp; +} + +/* Remove a (matched) message from the message queue. */ +Sint beam_jit_remove_message(Process *c_p, + Sint FCALLS, + Eterm *HTOP, + Eterm *E, + Uint32 active_code_ix) { + ErtsMessage *msgp; + + ERTS_CHK_MBUF_SZ(c_p); + + if (active_code_ix == ERTS_SAVE_CALLS_CODE_IX) { + save_calls(c_p, &exp_receive); + } + + msgp = erts_msgq_peek_msg(c_p); + + if (ERL_MESSAGE_TOKEN(msgp) == NIL) { +#ifdef USE_VM_PROBES + if (DT_UTAG(c_p) != NIL) { + if (DT_UTAG_FLAGS(c_p) & DT_UTAG_PERMANENT) { + SEQ_TRACE_TOKEN(c_p) = am_have_dt_utag; + } else { + DT_UTAG(c_p) = NIL; + SEQ_TRACE_TOKEN(c_p) = NIL; + } + } else { +#endif + SEQ_TRACE_TOKEN(c_p) = NIL; +#ifdef USE_VM_PROBES + } + DT_UTAG_FLAGS(c_p) &= ~DT_UTAG_SPREADING; +#endif + } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) { + Eterm msg; + SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp); +#ifdef USE_VM_PROBES + if (ERL_MESSAGE_TOKEN(msgp) == am_have_dt_utag) { + if (DT_UTAG(c_p) == NIL) { + DT_UTAG(c_p) = ERL_MESSAGE_DT_UTAG(msgp); + } + DT_UTAG_FLAGS(c_p) |= DT_UTAG_SPREADING; + } else { +#endif + ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p))); + ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); + ASSERT(is_small(SEQ_TRACE_TOKEN_SERIAL(c_p))); + ASSERT(is_small(SEQ_TRACE_TOKEN_LASTCNT(c_p))); + ASSERT(is_small(SEQ_TRACE_TOKEN_FLAGS(c_p))); + ASSERT(is_pid(SEQ_TRACE_TOKEN_SENDER(c_p)) || + is_atom(SEQ_TRACE_TOKEN_SENDER(c_p))); + c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); + if (c_p->seq_trace_clock < + unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) { + c_p->seq_trace_clock = + unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); + } + msg = ERL_MESSAGE_TERM(msgp); + seq_trace_output(SEQ_TRACE_TOKEN(c_p), + msg, + SEQ_TRACE_RECEIVE, + c_p->common.id, + c_p); +#ifdef USE_VM_PROBES + } +#endif + } +#ifdef USE_VM_PROBES + if (DTRACE_ENABLED(message_receive)) { + Eterm token2 = NIL; + DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; + Sint len = erts_proc_sig_privqs_len(c_p); + + dtrace_proc_str(c_p, receiver_name); + token2 = SEQ_TRACE_TOKEN(c_p); + if (have_seqtrace(token2)) { + tok_label = SEQ_TRACE_T_DTRACE_LABEL(token2); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); + } + DTRACE6(message_receive, + receiver_name, + size_object(ERL_MESSAGE_TERM(msgp)), + len, /* This is NOT message queue len, but its something... */ + tok_label, + tok_lastcnt, + tok_serial); + } +#endif + erts_msgq_unlink_msg_set_save_first(c_p, msgp); + CANCEL_TIMER(c_p); + + erts_save_message_in_proc(c_p, msgp); + c_p->flags &= ~F_DELAY_GC; + + if (ERTS_IS_GC_DESIRED_INTERNAL(c_p, HTOP, E, 0)) { + /* + * We want to GC soon but we leave a few + * reductions giving the message some time + * to turn into garbage. + */ + ERTS_VBUMP_LEAVE_REDS_INTERNAL(c_p, 5, FCALLS); + } + + ERTS_CHK_MBUF_SZ(c_p); + + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + return FCALLS; +} + +void beam_jit_take_receive_lock(Process *c_p) { + erts_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); +} + +void beam_jit_wait_locked(Process *c_p, ErtsCodePtr cp) { + c_p->arity = 0; + if (!ERTS_PTMR_IS_TIMED_OUT(c_p)) { + erts_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); + } + ASSERT(!ERTS_PROC_IS_EXITING(c_p)); + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); + c_p->current = NULL; + c_p->i = cp; +} + +void beam_jit_wait_unlocked(Process *c_p, ErtsCodePtr cp) { + beam_jit_take_receive_lock(c_p); + beam_jit_wait_locked(c_p, cp); +} + +enum beam_jit_tmo_ret beam_jit_wait_timeout(Process *c_p, + Eterm timeout_value, + ErtsCodePtr next) { + /* + * If we have already set the timer, we must NOT set it again. Therefore, + * we must test the F_INSLPQUEUE flag as well as the F_TIMO flag. + */ + if ((c_p->flags & (F_INSLPQUEUE | F_TIMO)) == 0) { + if (timeout_value == make_small(0)) { + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); + return RET_next; + } else if (timeout_value == am_infinity) { + c_p->flags |= F_TIMO; + } else { + int tres = erts_set_proc_timer_term(c_p, timeout_value); + if (tres == 0) { + /* + * The timer routiner will set c_p->i to the value in + * c_p->def_arg_reg[0]. Note that it is safe to use this + * location because there are no living x registers in + * a receive statement. + */ + c_p->def_arg_reg[0] = (Eterm)next; + } else { /* Wrong time */ + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); + c_p->freason = EXC_TIMEOUT_VALUE; + erts_msgq_set_save_first(c_p); + return RET_badarg; + } + } + } + return RET_wait; +} + +void beam_jit_timeout(Process *c_p) { + if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) { + trace_receive(c_p, am_clock_service, am_timeout, NULL); + } + if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { + save_calls(c_p, &exp_timeout); + } + c_p->flags &= ~F_TIMO; + erts_msgq_set_save_first(c_p); +} + +void beam_jit_timeout_locked(Process *c_p) { + erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); + beam_jit_timeout(c_p); +} + +void beam_jit_return_to_trace(Process *c_p) { + if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO)) { + ErtsCodePtr return_to_address; + Uint *cpp; + + cpp = (Uint *)c_p->stop; + ASSERT(is_CP(cpp[0])); + + for (;;) { + erts_inspect_frame(cpp, &return_to_address); + + if (BeamIsReturnTrace(return_to_address)) { + cpp += CP_SIZE + BEAM_RETURN_TRACE_FRAME_SZ; + } else if (BeamIsReturnCallAccTrace(return_to_address)) { + cpp += CP_SIZE + BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ; + } else if (BeamIsReturnToTrace(return_to_address)) { + cpp += CP_SIZE + BEAM_RETURN_TO_TRACE_FRAME_SZ; + } else { + break; + } + } + + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + erts_trace_return_to(c_p, return_to_address); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + } +} + +Eterm beam_jit_build_argument_list(Process *c_p, const Eterm *regs, int arity) { + Eterm *hp; + Eterm res; + + hp = HAlloc(c_p, arity * 2); + res = NIL; + + for (int i = arity - 1; i >= 0; i--) { + res = CONS(hp, regs[i], res); + hp += 2; + } + + return res; +} + +Export *beam_jit_handle_unloaded_fun(Process *c_p, + Eterm *reg, + int arity, + Eterm fun_thing) { + ErtsCodeIndex code_ix = erts_active_code_ix(); + Eterm module, args; + ErlFunThing *funp; + ErlFunEntry *fe; + Module *modp; + Export *ep; + + funp = (ErlFunThing *)fun_val(fun_thing); + ASSERT(is_local_fun(funp)); + + fe = funp->entry.fun; + module = fe->module; + + ERTS_THR_READ_MEMORY_BARRIER; + + if (fe->pend_purge_address) { + /* The system is currently trying to purge the module containing this + * fun. Suspend the process and let it try again when the purge + * operation is done (may succeed or not). */ + ep = erts_suspend_process_on_pending_purge_lambda(c_p, fe); + } else { + if ((modp = erts_get_module(module, code_ix)) != NULL && + modp->curr.code_hdr != NULL) { + /* There is a module loaded, but obviously the fun is not defined + * in it. We must not call the error_handler (or we will get into + * an infinite loop). */ + c_p->current = NULL; + c_p->freason = EXC_BADFUN; + c_p->fvalue = fun_thing; + return NULL; + } + + /* No current code for this module. Call the error_handler module to + * attempt loading the module. */ + ep = erts_find_function(erts_proc_get_error_handler(c_p), + am_undefined_lambda, + 3, + code_ix); + if (ERTS_UNLIKELY(ep == NULL)) { + /* No error handler, crash out. */ + c_p->current = NULL; + c_p->freason = EXC_UNDEF; + return NULL; + } + } + + args = beam_jit_build_argument_list(c_p, reg, arity); + + reg[0] = module; + reg[1] = fun_thing; + reg[2] = args; + reg[3] = NIL; + + return ep; +} diff --git a/erts/emulator/beam/jit/beam_jit_common.h b/erts/emulator/beam/jit/beam_jit_common.h deleted file mode 100644 index b2da85d0b860..000000000000 --- a/erts/emulator/beam/jit/beam_jit_common.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2021. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "erl_vm.h" -#include "global.h" - -#if defined(DEBUG) && defined(JIT_HARD_DEBUG) -void beam_jit_validate_term(Eterm term); -#endif - -typedef Eterm BeamJitNifF(struct enif_environment_t *, int argc, Eterm argv[]); -enum beam_jit_nif_load_ret { RET_NIF_success, RET_NIF_error, RET_NIF_yield }; - -Eterm beam_jit_call_bif(Process *c_p, - Eterm *reg, - ErtsCodePtr I, - ErtsBifFunc vbf, - Uint arity); -Eterm beam_jit_call_nif(Process *c_p, - ErtsCodePtr I, - Eterm *reg, - BeamJitNifF *fp, - struct erl_module_nif *NifMod); -enum beam_jit_nif_load_ret beam_jit_load_nif(Process *c_p, - ErtsCodePtr I, - Eterm *reg); - -Uint beam_jit_get_map_elements(Eterm map, - Eterm *reg, - Eterm *E, - Uint n, - Eterm *fs); - -void beam_jit_bs_field_size_argument_error(Process *c_p, Eterm size); -void beam_jit_bs_add_argument_error(Process *c_p, Eterm A, Eterm B); -Eterm beam_jit_bs_start_match2(Eterm context, - Uint live, - Uint slots, - Process *c_p, - Eterm *reg); -Eterm beam_jit_bs_init(Process *c_p, - Eterm *reg, - ERL_BITS_DECLARE_STATEP, - Eterm BsOp1, - Eterm BsOp2, - unsigned Live); -Eterm beam_jit_bs_init_bits(Process *c_p, - Eterm *reg, - ERL_BITS_DECLARE_STATEP, - Uint num_bits, - Uint alloc, - unsigned Live); -Eterm beam_jit_bs_get_integer(Process *c_p, - Eterm *reg, - Eterm context, - Uint flags, - Uint size, - Uint Live); - -ErtsMessage *beam_jit_decode_dist(Process *c_p, ErtsMessage *msgp); -Sint beam_jit_remove_message(Process *c_p, - Sint FCALLS, - Eterm *HTOP, - Eterm *E, - Uint32 active_code_ix); -void beam_jit_bs_context_to_binary(Eterm context); - -void beam_jit_take_receive_lock(Process *c_p); -void beam_jit_wait_locked(Process *c_p, ErtsCodePtr cp); -void beam_jit_wait_unlocked(Process *c_p, ErtsCodePtr cp); - -enum beam_jit_tmo_ret { RET_next = 0, RET_wait = 1, RET_badarg = 2 }; - -enum beam_jit_tmo_ret beam_jit_wait_timeout(Process *c_p, - Eterm timeout_value, - ErtsCodePtr next); - -void beam_jit_timeout(Process *c_p); -void beam_jit_timeout_locked(Process *c_p); diff --git a/erts/emulator/beam/jit/beam_jit_common.hpp b/erts/emulator/beam/jit/beam_jit_common.hpp index f8f894c676f0..fb1e166d87e8 100644 --- a/erts/emulator/beam/jit/beam_jit_common.hpp +++ b/erts/emulator/beam/jit/beam_jit_common.hpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2021. All Rights Reserved. + * Copyright Ericsson AB 2021-2023. 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. @@ -18,6 +18,13 @@ * %CopyrightEnd% */ +#ifndef __BEAM_JIT_COMMON_HPP__ +#define __BEAM_JIT_COMMON_HPP__ + +#ifndef ASMJIT_ASMJIT_H_INCLUDED +# include +#endif + #include #include #include @@ -30,108 +37,618 @@ extern "C" #endif #include "sys.h" +#include "bif.h" #include "erl_vm.h" #include "global.h" - -#include "beam_jit_common.h" +#include "big.h" +#include "beam_file.h" +#include "beam_types.h" } -class ArgVal { - BeamOpArg gen_op; +/* On Windows, the min and max macros may be defined. */ +#undef min +#undef max + +#include "beam_jit_args.hpp" +#include "beam_jit_types.hpp" + +using namespace asmjit; + +struct AsmRange { + ErtsCodePtr start; + ErtsCodePtr stop; + const std::string name; + + struct LineData { + ErtsCodePtr start; + const std::string file; + unsigned line; + }; + + const std::vector lines; +}; + +/* This is a partial class for `BeamAssembler`, containing various fields and + * helper functions that are common to all architectures so that we won't have + * to redefine them all the time. */ +class BeamAssemblerCommon : public ErrorHandler { + BaseAssembler &assembler; + +protected: + CodeHolder code; + FileLogger logger; + Section *rodata; + + static bool hasCpuFeature(uint32_t featureId); + + BeamAssemblerCommon(BaseAssembler &assembler); + ~BeamAssemblerCommon(); + + void codegen(JitAllocator *allocator, + const void **executable_ptr, + void **writable_ptr); + + void comment(const char *format) { + if (logger.file()) { + assembler.commentf("# %s", format); + } + } + + template + void comment(const char *format, Ts... args) { + if (logger.file()) { + char buff[1024]; + erts_snprintf(buff, sizeof(buff), format, args...); + assembler.commentf("# %s", buff); + } + } + + void *getCode(Label label); + byte *getCode(char *labelName); + + void embed(void *data, uint32_t size) { + assembler.embed((char *)data, size); + } + + void handleError(Error err, const char *message, BaseEmitter *origin); + + void setLogger(const std::string &log); + void setLogger(FILE *log); public: - enum TYPE { - u = TAG_u, - i = TAG_i, - x = TAG_x, - y = TAG_y, - f = TAG_f, - q = TAG_q, - e = TAG_r, - l = TAG_l /* float register */ + void embed_rodata(const char *labelName, const char *buff, size_t size); + void embed_bss(const char *labelName, size_t size); + void embed_zeros(size_t size); + + void *getBaseAddress(); + size_t getOffset(); +}; + +struct BeamModuleAssemblerCommon { + typedef unsigned BeamLabel; + + /* The BEAM file we've been loaded from, if any. */ + const BeamFile *beam; + Eterm mod; + + /* Map of label number to asmjit Label */ + typedef std::unordered_map LabelMap; + LabelMap rawLabels; + + struct patch { + Label where; + size_t ptr_offs; + size_t val_offs; + }; + + struct patch_catch { + struct patch patch; + Label handler; + }; + std::vector catches; + + /* Map of import entry to patch labels and mfa */ + struct patch_import { + std::vector patches; + ErtsCodeMFA mfa; + }; + typedef std::unordered_map ImportMap; + ImportMap imports; + + /* Map of fun entry to trampoline labels and patches */ + struct patch_lambda { + std::vector patches; + Label trampoline; + }; + typedef std::unordered_map LambdaMap; + LambdaMap lambdas; + + /* Map of literals to patch labels */ + struct patch_literal { + std::vector patches; }; + typedef std::unordered_map LiteralMap; + LiteralMap literals; + + /* All string patches */ + std::vector strings; + + /* All functions that have been seen so far */ + std::vector functions; - ArgVal(const BeamOpArg &arg) { - gen_op = arg; + /* Used by emit to populate the labelToMFA map */ + Label current_label; + + /* The offset of our BeamCodeHeader, if any. */ + Label code_header; + + /* The module's on_load function, if any. */ + Label on_load; + + /* The end of the last function. Note that the dispatch table, constants, + * and veneers may follow. */ + Label code_end; + + BeamModuleAssemblerCommon(const BeamFile *beam_, Eterm mod_) + : beam(beam_), mod(mod_) { } - ArgVal(enum TYPE t, BeamInstr val) { - gen_op.type = t; - gen_op.val = val; + /* Helpers */ + const auto &getTypeEntry(const ArgSource &arg) const { + auto typeIndex = + arg.isRegister() ? arg.as().typeIndex() : 0; + ASSERT(typeIndex < beam->types.count); + return static_cast(beam->types.entries[typeIndex]); } - ArgVal(unsigned t, BeamInstr val) { -#ifdef DEBUG - switch (t) { - case TAG_u: - break; - case TAG_i: - break; - case TAG_x: - break; - case TAG_y: - break; - case TAG_f: - break; - case TAG_q: - break; - case TAG_r: - break; - case TAG_l: - break; + auto getTypeUnion(const ArgSource &arg) const { + if (arg.isRegister()) { + return getTypeEntry(arg).type(); + } + + Eterm constant = + arg.isImmed() + ? arg.as().get() + : beamfile_get_literal(beam, + arg.as().get()); + + switch (tag_val_def(constant)) { + case ATOM_DEF: + return BeamTypeId::Atom; + case BINARY_DEF: + return BeamTypeId::Bitstring; + case FLOAT_DEF: + return BeamTypeId::Float; + case FUN_DEF: + return BeamTypeId::Fun; + case BIG_DEF: + case SMALL_DEF: + return BeamTypeId::Integer; + case LIST_DEF: + return BeamTypeId::Cons; + case MAP_DEF: + return BeamTypeId::Map; + case NIL_DEF: + return BeamTypeId::Nil; + case EXTERNAL_PID_DEF: + case PID_DEF: + return BeamTypeId::Pid; + case EXTERNAL_PORT_DEF: + case PORT_DEF: + return BeamTypeId::Port; + case EXTERNAL_REF_DEF: + case REF_DEF: + return BeamTypeId::Reference; + case TUPLE_DEF: + return BeamTypeId::Tuple; default: - ASSERT(0); + ERTS_ASSERT(!"tag_val_def error"); + return BeamTypeId::None; /* Avoid warning */ } -#endif + } + + auto getClampedRange(const ArgSource &arg) const { + if (arg.isSmall()) { + Sint value = arg.as().getSigned(); + return std::make_pair(value, value); + } else { + const auto &entry = getTypeEntry(arg); + + auto min = entry.hasLowerBound() ? entry.min() : MIN_SMALL; + auto max = entry.hasUpperBound() ? entry.max() : MAX_SMALL; + + return std::make_pair(min, max); + } + } + + bool always_small(const ArgSource &arg) const { + if (arg.isSmall()) { + return true; + } else if (!exact_type(arg)) { + return false; + } + + const auto &entry = getTypeEntry(arg); - gen_op.type = t; - gen_op.val = val; + if (entry.hasLowerBound() && entry.hasUpperBound()) { + return IS_SSMALL(entry.min()) && IS_SSMALL(entry.max()); + } + + return false; } - constexpr enum TYPE getType() const { - return (enum TYPE)gen_op.type; + bool always_immediate(const ArgSource &arg) const { + return always_one_of(arg) || + always_small(arg); } - constexpr uint64_t getValue() const { - return gen_op.val; + bool always_same_types(const ArgSource &lhs, const ArgSource &rhs) const { + using integral = std::underlying_type_t; + auto lhs_types = static_cast(getTypeUnion(lhs)); + auto rhs_types = static_cast(getTypeUnion(rhs)); + + /* We can only be certain that the types are the same when there's + * one possible type. For example, if one is a number and the other + * is an integer, they could differ if the former is a float. */ + if ((lhs_types & (lhs_types - 1)) == 0) { + return lhs_types == rhs_types; + } + + return false; } - constexpr bool isMem() const { - return gen_op.type == x || gen_op.type == y; + template + bool never_one_of(const ArgSource &arg) const { + using integral = std::underlying_type_t; + auto types = static_cast(BeamTypeIdUnion::value()); + auto type_union = static_cast(getTypeUnion(arg)); + return static_cast(type_union & types) == BeamTypeId::None; } - constexpr bool isLiteral() const { - return gen_op.type == q; + template + bool maybe_one_of(const ArgSource &arg) const { + return !never_one_of(arg); } - constexpr bool isImmed() const { - return gen_op.type == i; + template + bool always_one_of(const ArgSource &arg) const { + /* Providing a single type to this function is not an error per se, but + * `exact_type` provides a bit more error checking for that use-case, + * so we want to encourage its use. */ + static_assert(!BeamTypeIdUnion::is_single_typed(), + "always_one_of expects a union of several primitive " + "types, use exact_type instead"); + + using integral = std::underlying_type_t; + auto types = static_cast(BeamTypeIdUnion::value()); + auto type_union = static_cast(getTypeUnion(arg)); + return type_union == (type_union & types); } - template - ArgVal operator+(T val) const { - return ArgVal(gen_op.type, val + gen_op.val); + template + bool exact_type(const ArgSource &arg) const { + /* Rejects `exact_type(...)` and similar, as it's + * almost always an error to exactly match a union of several types. + * + * On the off chance that you _do_ need to match a union exactly, use + * `masked_types(arg) == T` instead. */ + static_assert(BeamTypeIdUnion::is_single_typed(), + "exact_type expects exactly one primitive type, use " + "always_one_of instead"); + + using integral = std::underlying_type_t; + auto type_union = static_cast(getTypeUnion(arg)); + return type_union == (type_union & static_cast(Type)); + } + + template + BeamTypeId masked_types(const ArgSource &arg) const { + static_assert((Mask != BeamTypeId::AlwaysBoxed && + Mask != BeamTypeId::AlwaysImmediate), + "using masked_types with AlwaysBoxed or AlwaysImmediate " + "is almost always an error, use exact_type, " + "maybe_one_of, or never_one_of instead"); + static_assert((Mask == BeamTypeId::MaybeBoxed || + Mask == BeamTypeId::MaybeImmediate || + Mask == BeamTypeId::AlwaysBoxed || + Mask == BeamTypeId::AlwaysImmediate), + "masked_types expects a mask type like MaybeBoxed or " + "MaybeImmediate, use exact_type, maybe_one_of, or" + "never_one_of instead"); + + using integral = std::underlying_type_t; + auto mask = static_cast(Mask); + auto type_union = static_cast(getTypeUnion(arg)); + return static_cast(type_union & mask); } - template - ArgVal operator*(T val) const { - return ArgVal(gen_op.type, val * gen_op.val); + bool is_sum_small_if_args_are_small(const ArgSource &LHS, + const ArgSource &RHS) const { + Sint min, max; + auto [min1, max1] = getClampedRange(LHS); + auto [min2, max2] = getClampedRange(RHS); + min = min1 + min2; + max = max1 + max2; + return IS_SSMALL(min) && IS_SSMALL(max); } - enum Relation { none, consecutive, reverse_consecutive }; + bool is_diff_small_if_args_are_small(const ArgSource &LHS, + const ArgSource &RHS) const { + Sint min, max; + auto [min1, max1] = getClampedRange(LHS); + auto [min2, max2] = getClampedRange(RHS); + min = min1 - max2; + max = max1 - min2; + return IS_SSMALL(min) && IS_SSMALL(max); + } + + bool is_product_small_if_args_are_small(const ArgSource &LHS, + const ArgSource &RHS) const { + auto [min1, max1] = getClampedRange(LHS); + auto [min2, max2] = getClampedRange(RHS); + auto mag1 = std::max(std::abs(min1), std::abs(max1)); + auto mag2 = std::max(std::abs(min2), std::abs(max2)); + + /* + * mag1 * mag2 <= MAX_SMALL + * mag1 <= MAX_SMALL / mag2 (when mag2 != 0) + */ + ERTS_CT_ASSERT(MAX_SMALL < -MIN_SMALL); + return mag2 == 0 || mag1 <= MAX_SMALL / mag2; + } - static Relation register_relation(const ArgVal &arg1, const ArgVal &arg2) { - TYPE type = arg1.getType(); - bool same_reg_types = - type == arg2.getType() && (type == TYPE::x || type == TYPE::y); - if (!same_reg_types) { - return none; - } else if (arg1.getValue() + 1 == arg2.getValue()) { - return consecutive; - } else if (arg1.getValue() == arg2.getValue() + 1) { - return reverse_consecutive; + bool is_bsl_small(const ArgSource &LHS, const ArgSource &RHS) const { + if (!(always_small(LHS) && always_small(RHS))) { + return false; } else { - return none; + auto [min1, max1] = getClampedRange(LHS); + auto [min2, max2] = getClampedRange(RHS); + + if (min1 < 0 || max1 == 0 || min2 < 0) { + return false; + } + + return max2 < asmjit::Support::clz(max1) - _TAG_IMMED1_SIZE; } - }; + } + + int getSizeUnit(const ArgSource &arg) const { + auto entry = getTypeEntry(arg); + return entry.hasUnit() ? entry.unit() : 1; + } + + bool hasLowerBound(const ArgSource &arg) const { + return getTypeEntry(arg).hasLowerBound(); + } + + bool hasUpperBound(const ArgSource &arg) const { + return getTypeEntry(arg).hasUpperBound(); + } +}; + +/* This is a view into a contiguous container (like an array or `std::vector`), + * letting us reuse the existing argument array in `beamasm_emit` while keeping + * our interfaces convenient. + * + * Needless to say, spans must not live longer than the container they wrap, so + * you must be careful not to return a span of an rvalue or stack-allocated + * container. + * + * We can replace this with std::span once we require C++20. */ +template +class Span { + const T *_data; + size_t _size; + +public: + template + Span(const Container &other) : Span(other.data(), other.size()) { + } + + template + Span(Container &other) : Span(other.data(), other.size()) { + } + + Span(const T *begin, const T *end) : Span(begin, end - begin) { + } + + Span(const T *data, size_t size) : _data(data), _size(size) { + } + + Span subspan(size_t index, size_t count) const { + ASSERT(index <= size() && count <= (size() - index)); + return Span(begin() + index, count); + } + + const auto size() const { + return _size; + } + + const auto begin() const { + return &_data[0]; + } + + const auto end() const { + return &_data[size()]; + } + + const T &operator[](size_t index) const { +#ifdef DEBUG + ASSERT(index < _size); +#endif + return _data[index]; + } + + const T &front() const { + return operator[](0); + } + + const T &back() const { + return operator[](size() - 1); + } }; + +static const Uint BSC_SEGMENT_OFFSET = 10; + +typedef enum : Uint { + BSC_OP_BINARY = 0, + BSC_OP_FLOAT = 1, + BSC_OP_INTEGER = 2, + BSC_OP_UTF8 = 3, + BSC_OP_UTF16 = 4, + BSC_OP_UTF32 = 5, + BSC_OP_LAST = 5 +} JitBSCOp; +static const Uint BSC_OP_MASK = 0x07; +static const Uint BSC_OP_OFFSET = 7; + +typedef enum : Uint { + BSC_INFO_FVALUE = 0, + BSC_INFO_TYPE = 1, + BSC_INFO_SIZE = 2, + BSC_INFO_UNIT = 3, + BSC_INFO_DEPENDS = 4, + BSC_INFO_LAST = 4, +} JitBSCInfo; +static const Uint BSC_INFO_MASK = 0x07; +static const Uint BSC_INFO_OFFSET = 4; + +typedef enum : Uint { + BSC_REASON_BADARG = 0, + BSC_REASON_SYSTEM_LIMIT = 1, + BSC_REASON_DEPENDS = 2, + BSC_REASON_LAST = 2, +} JitBSCReason; +static const Uint BSC_REASON_MASK = 0x03; + +typedef enum : Uint { + BSC_VALUE_ARG1 = 0, + BSC_VALUE_ARG3 = 1, + BSC_VALUE_FVALUE = 2, + BSC_VALUE_LAST = 2 +} JitBSCValue; +static const Uint BSC_VALUE_MASK = 0x03; +static const Uint BSC_VALUE_OFFSET = 2; + +static constexpr Uint beam_jit_set_bsc_segment_op(Uint segment, JitBSCOp op) { + return (segment << BSC_SEGMENT_OFFSET) | (op << BSC_OP_OFFSET); +} + +static constexpr Uint beam_jit_update_bsc_reason_info(Uint packed_info, + JitBSCReason reason, + JitBSCInfo info, + JitBSCValue value) { + return packed_info | (value << BSC_VALUE_OFFSET) | + (info << BSC_INFO_OFFSET) | reason; +} + +static constexpr Uint beam_jit_get_bsc_segment(Uint packed_info) { + return packed_info >> BSC_SEGMENT_OFFSET; +} + +static constexpr JitBSCOp beam_jit_get_bsc_op(Uint packed_info) { + ERTS_CT_ASSERT((BSC_OP_LAST & ~BSC_OP_MASK) == 0); + return (JitBSCOp)((packed_info >> BSC_OP_OFFSET) & BSC_OP_MASK); +} + +static constexpr JitBSCInfo beam_jit_get_bsc_info(Uint packed_info) { + ERTS_CT_ASSERT((BSC_INFO_LAST & ~BSC_INFO_MASK) == 0); + return (JitBSCInfo)((packed_info >> BSC_INFO_OFFSET) & BSC_INFO_MASK); +} + +static constexpr JitBSCReason beam_jit_get_bsc_reason(Uint packed_info) { + ERTS_CT_ASSERT((BSC_REASON_LAST & ~BSC_REASON_MASK) == 0); + return (JitBSCReason)(packed_info & BSC_REASON_MASK); +} + +static constexpr JitBSCValue beam_jit_get_bsc_value(Uint packed_info) { + ERTS_CT_ASSERT((BSC_VALUE_LAST & ~BSC_VALUE_MASK) == 0); + return (JitBSCValue)((packed_info >> BSC_VALUE_OFFSET) & BSC_VALUE_MASK); +} + +/* ** */ + +#if defined(DEBUG) && defined(JIT_HARD_DEBUG) +void beam_jit_validate_term(Eterm term); +#endif + +typedef Eterm BeamJitNifF(struct enif_environment_t *, int argc, Eterm argv[]); +enum beam_jit_nif_load_ret { RET_NIF_success, RET_NIF_error, RET_NIF_yield }; + +Eterm beam_jit_call_bif(Process *c_p, + Eterm *reg, + ErtsCodePtr I, + ErtsBifFunc vbf, + Uint arity); +Eterm beam_jit_call_nif(Process *c_p, + ErtsCodePtr I, + Eterm *reg, + BeamJitNifF *fp, + struct erl_module_nif *NifMod); +enum beam_jit_nif_load_ret beam_jit_load_nif(Process *c_p, + ErtsCodePtr I, + Eterm *reg); + +Uint beam_jit_get_map_elements(Eterm map, + Eterm *reg, + Eterm *E, + Uint n, + Eterm *fs); + +void beam_jit_bs_field_size_argument_error(Process *c_p, Eterm size); +void beam_jit_bs_add_argument_error(Process *c_p, Eterm A, Eterm B); +Eterm beam_jit_bs_init(Process *c_p, + Eterm *reg, + ERL_BITS_DECLARE_STATEP, + Eterm num_bytes, + Uint alloc, + unsigned Live); +Eterm beam_jit_bs_init_bits(Process *c_p, + Eterm *reg, + ERL_BITS_DECLARE_STATEP, + Uint num_bits, + Uint alloc, + unsigned Live); +Eterm beam_jit_bs_get_integer(Process *c_p, + Eterm *reg, + Eterm context, + Uint flags, + Uint size, + Uint Live); + +ErtsMessage *beam_jit_decode_dist(Process *c_p, ErtsMessage *msgp); +Sint beam_jit_remove_message(Process *c_p, + Sint FCALLS, + Eterm *HTOP, + Eterm *E, + Uint32 active_code_ix); + +void beam_jit_bs_construct_fail_info(Process *c_p, + Uint packed_error_info, + Eterm arg3, + Eterm arg1); +Sint beam_jit_bs_bit_size(Eterm term); + +void beam_jit_take_receive_lock(Process *c_p); +void beam_jit_wait_locked(Process *c_p, ErtsCodePtr cp); +void beam_jit_wait_unlocked(Process *c_p, ErtsCodePtr cp); + +enum beam_jit_tmo_ret { RET_next = 0, RET_wait = 1, RET_badarg = 2 }; + +enum beam_jit_tmo_ret beam_jit_wait_timeout(Process *c_p, + Eterm timeout_value, + ErtsCodePtr next); + +void beam_jit_timeout(Process *c_p); +void beam_jit_timeout_locked(Process *c_p); + +void beam_jit_return_to_trace(Process *c_p); + +Eterm beam_jit_build_argument_list(Process *c_p, const Eterm *regs, int arity); + +Export *beam_jit_handle_unloaded_fun(Process *c_p, + Eterm *reg, + int arity, + Eterm fun_thing); + +#endif diff --git a/erts/emulator/beam/jit/beam_jit_main.cpp b/erts/emulator/beam/jit/beam_jit_main.cpp new file mode 100644 index 000000000000..0cd732039f5c --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_main.cpp @@ -0,0 +1,638 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "bif.h" +#include "beam_common.h" +#include "code_ix.h" +#include "export.h" +#include "erl_threads.h" + +#if defined(__APPLE__) +# include +#elif defined(WIN32) +# include +#endif +} + +#ifdef ERLANG_FRAME_POINTERS +ErtsFrameLayout ERTS_WRITE_UNLIKELY(erts_frame_layout); +#endif + +/* Global configuration variables (under the `+J` prefix) */ +#ifdef HAVE_LINUX_PERF_SUPPORT +enum beamasm_perf_flags erts_jit_perf_support; +#endif +/* Force use of single-mapped RWX memory for JIT code */ +int erts_jit_single_map = 0; + +/* + * Special Beam instructions. + */ + +ErtsCodePtr beam_run_process; +ErtsCodePtr beam_normal_exit; +ErtsCodePtr beam_exit; +ErtsCodePtr beam_export_trampoline; +ErtsCodePtr beam_bif_export_trap; +ErtsCodePtr beam_continue_exit; +ErtsCodePtr beam_save_calls_export; +ErtsCodePtr beam_save_calls_fun; +ErtsCodePtr beam_unloaded_fun; + +/* NOTE These should be the only variables containing trace instructions. +** Sometimes tests are for the instruction value, and sometimes +** for the variable reference (one of these), and rogue references +** will most likely cause chaos. +*/ +ErtsCodePtr beam_return_to_trace; /* OpCode(i_return_to_trace) */ +ErtsCodePtr beam_return_trace; /* OpCode(i_return_trace) */ +ErtsCodePtr beam_exception_trace; /* UGLY also OpCode(i_return_trace) */ +ErtsCodePtr beam_call_trace_return; /* OpCode(i_call_trace_return) */ + +static JitAllocator *jit_allocator; + +static BeamGlobalAssembler *bga; +static BeamModuleAssembler *bma; +static CpuInfo cpuinfo; + +/* + * Enter all BIFs into the export table. + * + * Note that they will all call the error_handler until their modules have been + * loaded, which may prevent the system from booting if BIFs from non-preloaded + * modules are apply/3'd while loading code. Ordinary BIF calls will work fine + * however since they won't go through export entries. + */ +static void install_bifs(void) { + typedef Eterm (*bif_func_type)(Process *, Eterm *, ErtsCodePtr); + int i; + + ASSERT(beam_export_trampoline != NULL); + ASSERT(beam_save_calls_export != NULL); + + for (i = 0; i < BIF_SIZE; i++) { + BifEntry *entry; + Export *ep; + int j; + + entry = &bif_table[i]; + + ep = erts_export_put(entry->module, entry->name, entry->arity); + + sys_memset(&ep->info.u, 0, sizeof(ep->info.u)); + ep->info.mfa.module = entry->module; + ep->info.mfa.function = entry->name; + ep->info.mfa.arity = entry->arity; + ep->bif_number = i; + + for (j = 0; j < ERTS_NUM_CODE_IX; j++) { + erts_activate_export_trampoline(ep, j); + } + + /* Set up a hidden export entry so we can trap to this BIF without + * it being seen when tracing. */ + erts_init_trap_export(BIF_TRAP_EXPORT(i), + entry->module, + entry->name, + entry->arity, + (bif_func_type)entry->f); + } +} + +static auto create_allocator(const JitAllocator::CreateParams ¶ms) { + void *test_ro, *test_rw; + bool single_mapped; + Error err; + + auto *allocator = new JitAllocator(¶ms); + + err = allocator->alloc(&test_ro, &test_rw, 1); + + if (err == ErrorCode::kErrorOk) { + /* We can get dual-mapped memory when asking for single-mapped memory + * if the latter is not possible: return whether that happened. */ + single_mapped = (test_ro == test_rw); + } + + allocator->release(test_ro); + + if (err == ErrorCode::kErrorOk) { + return std::make_pair(allocator, single_mapped); + } + + delete allocator; + return std::make_pair((JitAllocator *)nullptr, false); +} + +static JitAllocator *pick_allocator() { + JitAllocator::CreateParams params; + JitAllocator *allocator; + bool single_mapped; + +#if defined(VALGRIND) + erts_jit_single_map = 1; +#elif defined(__APPLE__) && defined(__aarch64__) + /* Allocating dual-mapped executable memory on this platform is horribly + * slow, and provides little security benefits over the MAP_JIT per-thread + * permission scheme. Force single-mapped memory. + * + * 64-bit x86 still uses dual-mapped memory as it lacks support for per- + * thread permissions and thus gets unprotected RWX pages with MAP_JIT. */ + erts_jit_single_map = 1; +#endif + +#if defined(HAVE_LINUX_PERF_SUPPORT) + /* `perf` has a hard time showing symbols for dual-mapped memory, so we'll + * use single-mapped memory when enabled. */ + if (erts_jit_perf_support & BEAMASM_PERF_ENABLED) { + erts_jit_single_map = 1; + } +#endif + + /* Default to dual-mapped memory with separate executable and writable + * regions of the same code. This is required for platforms that enforce + * W^X, and we prefer it when available to catch errors sooner. + * + * `blockSize` is analogous to "carrier size," and we pick something + * much larger than the default since dual-mapping implies having one + * file descriptor per block on most platforms. The block sizes do grow + * over time, but we don't want to waste half a dozen fds just to get to + * the shell on platforms that are very fd-constrained. */ + params.reset(); + params.blockSize = 32 << 20; + + allocator = nullptr; + single_mapped = false; + + if (!erts_jit_single_map) { + params.options = JitAllocatorOptions::kUseDualMapping; + std::tie(allocator, single_mapped) = create_allocator(params); + } + + if (allocator == nullptr) { + params.options &= ~JitAllocatorOptions::kUseDualMapping; + std::tie(allocator, single_mapped) = create_allocator(params); + } + + if (erts_jit_single_map && !single_mapped) { + ERTS_INTERNAL_ERROR("jit: Failed to allocate executable+writable " + "memory. Either allow this or disable both the " + "'+JPperf' and '+JMsingle' options."); + } + + if (allocator == nullptr) { + ERTS_INTERNAL_ERROR("jit: Cannot allocate executable memory. Use the " + "interpreter instead."); + } + + return allocator; +} + +void beamasm_init() { + unsigned label = 1; + + ASSERT(bga == nullptr && bma == nullptr); + + struct operands { + Eterm name; + int arity; + BeamInstr operand; + ErtsCodePtr *target; + }; + + std::vector operands = { + {am_run_process, 3, op_i_apply_only, &beam_run_process}, + {am_normal_exit, 0, op_normal_exit, &beam_normal_exit}, + {am_continue_exit, 0, op_continue_exit, &beam_continue_exit}, + {am_exception_trace, 0, op_return_trace, &beam_exception_trace}, + {am_return_trace, 0, op_return_trace, &beam_return_trace}, + {am_return_to_trace, + 0, + op_i_return_to_trace, + &beam_return_to_trace}, + {am_call_trace_return, + 0, + op_i_call_trace_return, + &beam_call_trace_return}}; + + Eterm mod_name; + ERTS_DECL_AM(erts_beamasm); + mod_name = AM_erts_beamasm; + + /* erts_frame_layout is hardcoded to ERTS_FRAME_LAYOUT_RA when Erlang + * frame pointers are disabled or unsupported. */ +#if defined(ERLANG_FRAME_POINTERS) +# ifdef HAVE_LINUX_PERF_SUPPORT + if (erts_jit_perf_support & BEAMASM_PERF_FP) { + erts_frame_layout = ERTS_FRAME_LAYOUT_FP_RA; + } else { + erts_frame_layout = ERTS_FRAME_LAYOUT_RA; + } +# else + erts_frame_layout = ERTS_FRAME_LAYOUT_RA; +# endif +#else + ERTS_CT_ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); +#endif + + beamasm_metadata_early_init(); + + /* + * Ensure that commonly used fields in the PCB can be accessed with + * short instructions. Before removing any of these assertions, please + * consider the effect it will have on code size and/or performance. + */ + ERTS_CT_ASSERT(offsetof(Process, htop) < 128); + ERTS_CT_ASSERT(offsetof(Process, stop) < 128); + ERTS_CT_ASSERT(offsetof(Process, fcalls) < 128); + ERTS_CT_ASSERT(offsetof(Process, freason) < 128); + ERTS_CT_ASSERT(offsetof(Process, fvalue) < 128); + +#ifdef ERLANG_FRAME_POINTERS + ERTS_CT_ASSERT(offsetof(Process, frame_pointer) < 128); +#endif + + cpuinfo = CpuInfo::host(); + + jit_allocator = pick_allocator(); + + bga = new BeamGlobalAssembler(jit_allocator); + + bma = new BeamModuleAssembler(bga, + mod_name, + 1 + operands.size() * 2, + operands.size()); + + std::vector args; + + for (auto &op : operands) { + unsigned func_label, entry_label; + + func_label = label++; + entry_label = label++; + + args = {ArgVal(ArgVal::Label, func_label), + ArgVal(ArgVal::Word, sizeof(UWord))}; + bma->emit(op_aligned_label_Lt, args); + + args = {ArgVal(ArgVal::Word, func_label), + ArgVal(ArgVal::Immediate, mod_name), + ArgVal(ArgVal::Immediate, op.name), + ArgVal(ArgVal::Word, op.arity)}; + bma->emit(op_i_func_info_IaaI, args); + + args = {ArgVal(ArgVal::Label, entry_label), + ArgVal(ArgVal::Word, sizeof(UWord))}; + bma->emit(op_aligned_label_Lt, args); + + args = {}; + bma->emit(op.operand, args); + + op.operand = entry_label; + } + + args = {}; + bma->emit(op_int_code_end, args); + + { + /* We have no need of the module pointers as we use `getCode(...)` + * for everything, and the code will live as long as the emulator + * itself. */ + const void *_ignored_exec; + void *_ignored_rw; + + /* Register our global code with gdb/perf so it shows up nicely in + * stack traces. */ + BeamCodeHeader *_ignored_code_hdr_rw = NULL; + const BeamCodeHeader *code_hdr_ro = NULL; + BeamCodeHeader load_header = {}; + + load_header.num_functions = operands.size(); + + bma->codegen(jit_allocator, + &_ignored_exec, + &_ignored_rw, + &load_header, + &code_hdr_ro, + &_ignored_code_hdr_rw); + bma->register_metadata(code_hdr_ro); + } + + for (auto op : operands) { + if (op.target) { + *op.target = bma->getCode(op.operand); + } + } + + /* These instructions rely on register contents, and can only be reached + * from a `call_ext_*`-instruction or trapping from the emulator, hence the + * lack of wrapper functions. */ + beam_save_calls_export = (ErtsCodePtr)bga->get_dispatch_save_calls_export(); + beam_save_calls_fun = (ErtsCodePtr)bga->get_dispatch_save_calls_fun(); + beam_export_trampoline = (ErtsCodePtr)bga->get_export_trampoline(); + + /* Used when trappping to Erlang code from the emulator, setting up + * registers in the same way as call_ext so that save_calls and tracing + * works when trapping. */ + beam_bif_export_trap = (ErtsCodePtr)bga->get_bif_export_trap(); + + beam_exit = (ErtsCodePtr)bga->get_process_exit(); + + beam_unloaded_fun = (ErtsCodePtr)bga->get_unloaded_fun(); + + beamasm_metadata_late_init(); +} + +bool BeamAssemblerCommon::hasCpuFeature(uint32_t featureId) { + return cpuinfo.hasFeature(featureId); +} + +void init_emulator(void) { + install_bifs(); +} + +void process_main(ErtsSchedulerData *esdp) { + typedef void (*pmain_type)(ErtsSchedulerData *); + + pmain_type pmain = (pmain_type)bga->get_process_main(); + pmain(esdp); +} + +extern "C" +{ + int erts_beam_jump_table(void) { +#if defined(NO_JUMP_TABLE) + return 0; +#else + return 1; +#endif + } + + void beamasm_unseal_module(const void *executable_region, + void *writable_region, + size_t size) { + (void)executable_region; + (void)writable_region; + (void)size; + + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite); + } + + void beamasm_seal_module(const void *executable_region, + void *writable_region, + size_t size) { + (void)executable_region; + (void)writable_region; + (void)size; + + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute); + } + + void beamasm_flush_icache(const void *address, size_t size) { +#ifdef DEBUG + erts_debug_require_code_barrier(); +#endif + +#if defined(__aarch64__) && defined(WIN32) + /* Issues full memory/instruction barriers on all threads for us. */ + FlushInstructionCache(GetCurrentProcess(), address, size); +#elif defined(__aarch64__) && defined(__APPLE__) + /* Issues full memory/instruction barriers on all threads for us. */ + sys_icache_invalidate((char *)address, size); +#elif defined(__aarch64__) && defined(__GNUC__) && \ + defined(ERTS_THR_INSTRUCTION_BARRIER) && \ + ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION && \ + ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION + /* Note that we do not issue any barriers here, whether instruction or + * memory. This is on purpose as we must issue those on all schedulers + * and not just the calling thread, and the chances of us forgetting to + * do that is much higher if we issue them here. */ + UWord start = reinterpret_cast(address); + UWord end = start + size; + + ETHR_COMPILER_BARRIER; + + for (UWord i = start & ~ERTS_CACHE_LINE_MASK; i < end; + i += ERTS_CACHE_LINE_SIZE) { + __asm__ __volatile__("dc cvau, %0\n" + "ic ivau, %0\n" ::"r"(i) + :); + } +#elif (defined(__x86_64__) || defined(_M_X64)) && \ + defined(ERTS_THR_INSTRUCTION_BARRIER) + /* We don't need to invalidate cache on this platform, but since we + * might be modifying code with a different linear address than the one + * we execute from (dual-mapped memory), we still need to issue an + * instruction barrier on all schedulers to ensure that the change is + * visible. */ + (void)address; + (void)size; +#else +# error "Platform lacks implementation for clearing instruction cache." \ + "Please report this bug." +#endif + } + + void *beamasm_new_assembler(Eterm mod, + int num_labels, + int num_functions, + BeamFile *file) { + return new BeamModuleAssembler(bga, + mod, + num_labels, + num_functions, + file); + } + + int beamasm_emit(void *instance, unsigned specific_op, BeamOp *op) { + /* The argument array must be safely convertible from `BeamOpArg*` to + * `ArgVal*` for us to reuse it directly. + * + * The exact traits we need weren't introduced until C++20, but the + * assertions below will catch just about everything that would break + * this conversion. */ + static_assert(std::is_base_of::value); + static_assert(std::is_standard_layout::value); + + BeamModuleAssembler *ba = static_cast(instance); + const Span args(static_cast(op->a), op->arity); + return ba->emit(specific_op, args); + } + + void beamasm_emit_call_nif(const ErtsCodeInfo *info, + void *normal_fptr, + void *lib, + void *dirty_fptr, + char *buff, + unsigned buff_len) { + BeamModuleAssembler ba(bga, info->mfa.module, 3); + std::vector args; + + args = {ArgVal(ArgVal::Label, 1), ArgVal(ArgVal::Word, sizeof(UWord))}; + ba.emit(op_aligned_label_Lt, args); + + args = {ArgVal(ArgVal::Word, 1), + ArgVal(ArgVal::Immediate, info->mfa.module), + ArgVal(ArgVal::Immediate, info->mfa.function), + ArgVal(ArgVal::Word, info->mfa.arity)}; + ba.emit(op_i_func_info_IaaI, args); + + args = {ArgVal(ArgVal::Label, 2), ArgVal(ArgVal::Word, sizeof(UWord))}; + ba.emit(op_aligned_label_Lt, args); + + args = {}; + ba.emit(op_i_breakpoint_trampoline, args); + + args = {ArgVal(ArgVal::Word, (BeamInstr)normal_fptr), + ArgVal(ArgVal::Word, (BeamInstr)lib), + ArgVal(ArgVal::Word, (BeamInstr)dirty_fptr)}; + ba.emit(op_call_nif_WWW, args); + + ba.codegen(buff, buff_len); + } + + void beamasm_delete_assembler(void *instance) { + BeamModuleAssembler *ba = static_cast(instance); + delete ba; + } + + void beamasm_purge_module(const void *executable_region, + void *writable_region, + size_t size) { + (void)size; + jit_allocator->release(const_cast(executable_region)); + } + + ErtsCodePtr beamasm_get_code(void *instance, int label) { + BeamModuleAssembler *ba = static_cast(instance); + return reinterpret_cast(ba->getCode(label)); + } + + ErtsCodePtr beamasm_get_lambda(void *instance, int index) { + BeamModuleAssembler *ba = static_cast(instance); + return reinterpret_cast(ba->getLambda(index)); + } + + const byte *beamasm_get_rodata(void *instance, char *label) { + BeamModuleAssembler *ba = static_cast(instance); + return reinterpret_cast(ba->getCode(label)); + } + + void beamasm_embed_rodata(void *instance, + const char *labelName, + const char *buff, + size_t size) { + BeamModuleAssembler *ba = static_cast(instance); + if (size) { + ba->embed_rodata(labelName, buff, size); + } + } + + void beamasm_embed_bss(void *instance, char *labelName, size_t size) { + BeamModuleAssembler *ba = static_cast(instance); + if (size) { + ba->embed_bss(labelName, size); + } + } + + void beamasm_codegen(void *instance, + const void **executable_region, + void **writable_region, + const BeamCodeHeader *in_hdr, + const BeamCodeHeader **out_exec_hdr, + BeamCodeHeader **out_rw_hdr) { + BeamModuleAssembler *ba = static_cast(instance); + + ba->codegen(jit_allocator, + executable_region, + writable_region, + in_hdr, + out_exec_hdr, + out_rw_hdr); + } + + void beamasm_register_metadata(void *instance, const BeamCodeHeader *hdr) { + BeamModuleAssembler *ba = static_cast(instance); + ba->register_metadata(hdr); + } + + Uint beamasm_get_header(void *instance, const BeamCodeHeader **hdr) { + BeamModuleAssembler *ba = static_cast(instance); + + *hdr = ba->getCodeHeader(); + + return ba->getCodeSize(); + } + + char *beamasm_get_base(void *instance) { + BeamModuleAssembler *ba = static_cast(instance); + return (char *)ba->getBaseAddress(); + } + + size_t beamasm_get_offset(void *instance) { + BeamModuleAssembler *ba = static_cast(instance); + return ba->getOffset(); + } + + const ErtsCodeInfo *beamasm_get_on_load(void *instance) { + BeamModuleAssembler *ba = static_cast(instance); + return ba->getOnLoad(); + } + + unsigned int beamasm_patch_catches(void *instance, char *rw_base) { + BeamModuleAssembler *ba = static_cast(instance); + return ba->patchCatches(rw_base); + } + + void beamasm_patch_import(void *instance, + char *rw_base, + int index, + const Export *import) { + BeamModuleAssembler *ba = static_cast(instance); + ba->patchImport(rw_base, index, import); + } + + void beamasm_patch_literal(void *instance, + char *rw_base, + int index, + Eterm lit) { + BeamModuleAssembler *ba = static_cast(instance); + ba->patchLiteral(rw_base, index, lit); + } + + void beamasm_patch_lambda(void *instance, + char *rw_base, + int index, + const ErlFunEntry *fe) { + BeamModuleAssembler *ba = static_cast(instance); + ba->patchLambda(rw_base, index, fe); + } + + void beamasm_patch_strings(void *instance, + char *rw_base, + const byte *string_table) { + BeamModuleAssembler *ba = static_cast(instance); + ba->patchStrings(rw_base, string_table); + } +} diff --git a/erts/emulator/beam/jit/beam_jit_metadata.cpp b/erts/emulator/beam/jit/beam_jit_metadata.cpp new file mode 100644 index 000000000000..10e82fdf373f --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_metadata.cpp @@ -0,0 +1,539 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2023. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "beam_common.h" +} + +#if !(defined(WIN32) || defined(__APPLE__) || defined(__MACH__) || \ + defined(__DARWIN__)) +# define HAVE_GDB_SUPPORT +#endif + +#ifdef HAVE_GDB_SUPPORT + +enum jit_actions : uint32_t { + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN, +}; + +struct jit_code_entry { + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; +}; + +struct jit_descriptor { + uint32_t version; + jit_actions action_flag; + struct jit_code_entry *relevant_entry; + struct jit_code_entry *first_entry; + erts_mtx_t mutex; +}; + +extern "C" +{ + extern void ERTS_NOINLINE __jit_debug_register_code(void); + + /* Make sure to specify the version statically, because the + * debugger may check the version before we can set it. */ + struct jit_descriptor __jit_debug_descriptor = {1, + JIT_NOACTION, + NULL, + NULL}; +} /* extern "C" */ + +struct emulator_info { + /* 0 = regular, 1 = frame pointers */ + int frame_layout; + const void *normal_exit; +}; + +struct module_info { + uint64_t base_address; + uint32_t range_count; + uint32_t code_size; + /* Module name, including null terminator. */ + uint16_t name_length; + char name[]; +}; + +struct range_info { + uint32_t start_offset; + uint32_t end_offset; + uint32_t line_count; + /* Range name, including null terminator. */ + uint16_t name_length; + char name[]; +}; + +struct line_info { + uint32_t start_offset; + uint32_t line_number; + /* File name, including null terminator. */ + uint16_t file_length; + char file[]; +}; + +enum debug_info_header { + DEBUG_INFO_HEADER_EMULATOR = 0, + DEBUG_INFO_HEADER_MODULE = 1, +}; + +struct debug_info { + enum debug_info_header header; + union { + struct emulator_info emu; + struct module_info mod; + } payload; +}; + +static void beamasm_init_early_gdb() { + erts_mtx_init(&__jit_debug_descriptor.mutex, + "jit_debug_descriptor", + NIL, + (ERTS_LOCK_FLAGS_PROPERTY_STATIC | + ERTS_LOCK_FLAGS_CATEGORY_GENERIC)); +} + +static void beamasm_init_late_gdb() { + auto debug_info = (struct debug_info *)malloc(sizeof(struct debug_info)); + jit_code_entry *entry; + + debug_info->header = DEBUG_INFO_HEADER_EMULATOR; + debug_info->payload.emu.frame_layout = erts_frame_layout; + debug_info->payload.emu.normal_exit = beam_normal_exit; + + entry = (jit_code_entry *)malloc(sizeof(jit_code_entry)); + entry->symfile_addr = (char *)debug_info; + entry->symfile_size = sizeof(struct debug_info); + + /* Insert into linked list */ + entry->next_entry = __jit_debug_descriptor.first_entry; + if (entry->next_entry) { + entry->next_entry->prev_entry = entry; + } else { + entry->prev_entry = nullptr; + } + + /* Insert into linked list */ + erts_mtx_lock(&__jit_debug_descriptor.mutex); + entry->next_entry = __jit_debug_descriptor.first_entry; + if (entry->next_entry) { + entry->next_entry->prev_entry = entry; + } else { + entry->prev_entry = nullptr; + } + + /* Register with gdb */ + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + __jit_debug_descriptor.first_entry = entry; + __jit_debug_descriptor.relevant_entry = entry; + __jit_debug_register_code(); + erts_mtx_unlock(&__jit_debug_descriptor.mutex); +} + +static void beamasm_update_gdb_info(std::string module_name, + ErtsCodePtr base_address, + size_t code_size, + const std::vector &ranges) { + Sint symfile_size = sizeof(struct debug_info) + module_name.size() + 1; + + for (const auto &range : ranges) { + symfile_size += sizeof(struct range_info) + range.name.size() + 1; + + for (const auto &line : range.lines) { + symfile_size += sizeof(struct line_info) + line.file.size() + 1; + } + } + + char *symfile = (char *)malloc(symfile_size); + jit_code_entry *entry; + + entry = (jit_code_entry *)malloc(sizeof(jit_code_entry)); + entry->symfile_addr = symfile; + entry->symfile_size = symfile_size; + + auto debug_info = (struct debug_info *)symfile; + debug_info->header = DEBUG_INFO_HEADER_MODULE; + + auto module_info = &debug_info->payload.mod; + module_info->base_address = (uint64_t)base_address; + module_info->code_size = (uint32_t)code_size; + module_info->range_count = ranges.size(); + module_info->name_length = module_name.size() + 1; + sys_memcpy(module_info->name, + module_name.c_str(), + module_info->name_length); + + symfile += sizeof(*debug_info) + module_info->name_length; + + for (const auto &range : ranges) { + ASSERT(range.start >= base_address && range.start <= range.stop); + + auto range_info = (struct range_info *)symfile; + range_info->start_offset = (char *)range.start - (char *)base_address; + range_info->end_offset = (char *)range.stop - (char *)base_address; + range_info->line_count = (uint32_t)range.lines.size(); + range_info->name_length = (uint16_t)range.name.size() + 1; + sys_memcpy(range_info->name, + range.name.c_str(), + range_info->name_length); + + symfile += sizeof(*range_info) + range_info->name_length; + + for (const auto &line : range.lines) { + auto line_info = (struct line_info *)symfile; + line_info->start_offset = (char *)line.start - (char *)base_address; + line_info->line_number = (uint32_t)line.line; + line_info->file_length = (uint16_t)line.file.size() + 1; + sys_memcpy(line_info->file, + line.file.c_str(), + line_info->file_length); + + symfile += sizeof(*line_info) + line_info->file_length; + } + } + + ASSERT(symfile_size == (symfile - entry->symfile_addr)); + + /* Insert into linked list */ + erts_mtx_lock(&__jit_debug_descriptor.mutex); + entry->next_entry = __jit_debug_descriptor.first_entry; + if (entry->next_entry) { + entry->next_entry->prev_entry = entry; + } else { + entry->prev_entry = nullptr; + } + + /* register with gdb */ + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + __jit_debug_descriptor.first_entry = entry; + __jit_debug_descriptor.relevant_entry = entry; + __jit_debug_register_code(); + erts_mtx_unlock(&__jit_debug_descriptor.mutex); +} + +#endif /* HAVE_GDB_SUPPORT */ + +#ifdef HAVE_LINUX_PERF_SUPPORT + +# ifdef HAVE_ELF_H +# include +# define HAVE_LINUX_PERF_DUMP_SUPPORT 1 + +class JitPerfDump { + FILE *file = nullptr; + Uint64 code_index = 0; + + enum PerfDumpId { + JIT_CODE_LOAD = 0, /* record describing a jitted function */ + JIT_CODE_MOVE = 1, /* record describing an already jitted function which + is moved */ + JIT_CODE_DEBUG_INFO = 2, /* record describing the debug information for + a jitted function */ + JIT_CODE_CLOSE = + 3, /* record marking the end of the jit runtime (optional) */ + JIT_CODE_UNWINDING_INFO = + 4 /* record describing a function unwinding information */ + }; + + struct FileHeader { + Uint32 magic; + Uint32 version; + Uint32 total_size; + Uint32 elf_mach; + Uint32 pad1; + Uint32 pid; + Uint64 timestamp; + Uint64 flags; + + FileHeader() { + magic = 0x4A695444; /* "JiTD" as numbers */ + version = 1; + total_size = sizeof(FileHeader); + elf_mach = EM_X86_64; + pad1 = 0; + pid = getpid(); + timestamp = erts_os_monotonic_time(); + flags = 0; + ERTS_CT_ASSERT(sizeof(FileHeader) == 4 * 10); + } + }; + + struct RecordHeader { + Uint32 id; + Uint32 total_size; + Uint64 timestamp; + }; + +public: + bool init() { + char name[MAXPATHLEN]; + FileHeader header; + + /* LLVM places this file in ~/.debug/jit/ maybe we should do that to? */ + + erts_snprintf(name, sizeof(name), "/tmp/jit-%d.dump", getpid()); + + file = fopen(name, "w+"); + + if (file) { + fwrite(&header, sizeof(header), 1, file); + /* inform perf of the location of the dump file */ + void *addr = mmap(NULL, + sizeof(header), + PROT_READ | PROT_EXEC, + MAP_PRIVATE, + fileno(file), + 0); + if (addr == MAP_FAILED) { + int saved_errno = errno; + erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); + erts_dsprintf(dsbuf, + "perf: mmap of %s(%d) failed: %d\r\n", + name, + fileno(file), + saved_errno); + erts_send_error_to_logger_nogl(dsbuf); + fclose(file); + file = nullptr; + return false; + } + } else { + int saved_errno = errno; + erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); + erts_dsprintf(dsbuf, + "perf: Failed to open %s (%d)", + name, + saved_errno); + erts_send_error_to_logger_nogl(dsbuf); + return false; + } + return true; + } + + void update(const std::vector &ranges) { + struct JitCodeLoadRecord { + RecordHeader header; + Uint32 pid; + Uint32 tid; + Uint64 vma; + Uint64 code_addr; + Uint64 code_size; + Uint64 code_index; + /* Null terminated M:F/A */ + /* Native code */ + } record; + + record.header.id = JIT_CODE_LOAD; + record.pid = getpid(); + record.tid = erts_thr_self(); + + for (const AsmRange &range : ranges) { + /* Line entries must be written first, if present. */ + if (!range.lines.empty()) { + struct JitCodeDebugEntry { + Uint64 line_addr; + Uint32 line; + Uint32 column; + char name[]; + } debug_entry; + + struct JitCodeDebugInfoRecord { + RecordHeader header; + Uint64 code_addr; + Uint64 nr_entry; + struct JitCodeDebugEntry entries[]; + } debug_info; + + debug_info.header.id = JIT_CODE_DEBUG_INFO; + debug_info.header.total_size = sizeof(debug_info); + debug_info.header.timestamp = erts_os_monotonic_time(); + debug_info.code_addr = (Uint64)range.start; + debug_info.nr_entry = range.lines.size() + 1; + + for (const auto &line : range.lines) { + debug_info.header.total_size += sizeof(debug_entry); + debug_info.header.total_size += line.file.size() + 1; + } + + /* Add a dummy line to terminate the function. Otherwise, the + * line section will stop right before the final line. */ + debug_info.header.total_size += sizeof(debug_entry); + debug_info.header.total_size += 1; + + fwrite(&debug_info, sizeof(debug_info), 1, file); + + for (const auto &line : range.lines) { + debug_entry.line_addr = (Uint64)line.start; + debug_entry.line = line.line; + debug_entry.column = 0; + + fwrite(&debug_entry, sizeof(debug_entry), 1, file); + fwrite(line.file.c_str(), line.file.size() + 1, 1, file); + } + + debug_entry.line_addr = (Uint64)range.stop; + debug_entry.line = 0; + debug_entry.column = 0; + + fwrite(&debug_entry, sizeof(debug_entry), 1, file); + fwrite("", 1, 1, file); + } + + ptrdiff_t codeSize = (byte *)range.stop - (byte *)range.start; + size_t nameLen = range.name.size(); + + ASSERT(codeSize >= 0); + + record.header.total_size = sizeof(record) + nameLen + 1 + codeSize; + record.vma = (Uint64)range.start; + record.code_addr = (Uint64)range.start; + record.code_size = (Uint64)codeSize; + record.code_index = ++code_index; + record.header.timestamp = erts_os_monotonic_time(); + + fwrite(&record, sizeof(record), 1, file); + fwrite(range.name.c_str(), nameLen + 1, 1, file); + fwrite(range.start, codeSize, 1, file); + } + + fflush(file); + } +}; + +# endif /* HAVE_LINUX_PERF_SUPPORT */ + +class JitPerfMap { + FILE *file = nullptr; + +public: + bool init() { + char name[MAXPATHLEN]; + snprintf(name, sizeof(name), "/tmp/perf-%i.map", getpid()); + file = fopen(name, "w"); + if (!file) { + int saved_errno = errno; + erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); + erts_dsprintf(dsbuf, + "perf: Failed to open %s (%d)", + name, + saved_errno); + erts_send_error_to_logger_nogl(dsbuf); + return false; + } + return true; + } + + void update(const std::vector &ranges) { + for (const auto &range : ranges) { + char *start = (char *)range.start, *stop = (char *)range.stop; + ptrdiff_t size = stop - start; + fprintf(file, "%p %tx $%s\n", start, size, range.name.c_str()); + } + fflush(file); + } +}; + +class JitPerfSupport { + enum PerfModes { NONE = 0, MAP = (1 << 0), DUMP = (1 << 1) }; + + int modes; + + erts_mtx_t mutex; +# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT + JitPerfDump perf_dump; +# endif + JitPerfMap perf_map; + +public: + JitPerfSupport() : modes(NONE) { + } + void init() { + modes = JitPerfSupport::NONE; +# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT + if ((erts_jit_perf_support & BEAMASM_PERF_DUMP) && perf_dump.init()) { + modes |= JitPerfSupport::DUMP; + } +# endif + if ((erts_jit_perf_support & BEAMASM_PERF_MAP) && perf_map.init()) { + modes |= JitPerfSupport::MAP; + } + + erts_mtx_init(&mutex, + "perf", + NIL, + ERTS_LOCK_FLAGS_PROPERTY_STATIC | + ERTS_LOCK_FLAGS_CATEGORY_GENERIC); + } + + void update(const std::vector &ranges) { + if (modes) { + erts_mtx_lock(&mutex); +# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT + if (modes & DUMP) { + perf_dump.update(ranges); + } +# endif + if (modes & MAP) { + perf_map.update(ranges); + } + erts_mtx_unlock(&mutex); + } + } +}; + +static JitPerfSupport perf; +#endif /* HAVE_LINUX_PERF_SUPPORT */ + +void beamasm_metadata_early_init() { +#ifdef HAVE_GDB_SUPPORT + beamasm_init_early_gdb(); +#endif + +#ifdef HAVE_LINUX_PERF_SUPPORT + perf.init(); +#endif +} + +void beamasm_metadata_late_init() { +#ifdef HAVE_GDB_SUPPORT + beamasm_init_late_gdb(); +#endif +} + +void beamasm_metadata_update(std::string module_name, + ErtsCodePtr base_address, + size_t code_size, + const std::vector &ranges) { +#ifdef HAVE_LINUX_PERF_SUPPORT + perf.update(ranges); +#endif + +#ifdef HAVE_GDB_SUPPORT + beamasm_update_gdb_info(module_name, base_address, code_size, ranges); +#endif +} diff --git a/erts/emulator/beam/jit/beam_jit_types.hpp b/erts/emulator/beam/jit/beam_jit_types.hpp new file mode 100644 index 000000000000..74edc6649629 --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_types.hpp @@ -0,0 +1,150 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2023. 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% + */ + +#ifndef __BEAM_JIT_TYPES_HPP__ +#define __BEAM_JIT_TYPES_HPP__ + +/* Type-safe wrapper around the definitions in beam_types.h. We've redefined it + * as an `enum class` to force the usage of our helpers, which lets us check + * for common usage errors at compile time. */ +enum class BeamTypeId : int { + None = BEAM_TYPE_NONE, + + Atom = BEAM_TYPE_ATOM, + Bitstring = BEAM_TYPE_BITSTRING, + BsMatchState = BEAM_TYPE_BS_MATCHSTATE, + Cons = BEAM_TYPE_CONS, + Float = BEAM_TYPE_FLOAT, + Fun = BEAM_TYPE_FUN, + Integer = BEAM_TYPE_INTEGER, + Map = BEAM_TYPE_MAP, + Nil = BEAM_TYPE_NIL, + Pid = BEAM_TYPE_PID, + Port = BEAM_TYPE_PORT, + Reference = BEAM_TYPE_REFERENCE, + Tuple = BEAM_TYPE_TUPLE, + + Any = BEAM_TYPE_ANY, + + Identifier = Pid | Port | Reference, + List = Cons | Nil, + Number = Float | Integer, + + /** @brief Types that can be boxed, including those that may also be + * immediates (e.g. pids, integers). */ + MaybeBoxed = Bitstring | BsMatchState | Float | Fun | Integer | Map | Pid | + Port | Reference | Tuple, + /** @brief Types that can be immediates, including those that may also be + * boxed (e.g. pids, integers). */ + MaybeImmediate = Atom | Integer | Nil | Pid | Port, + + /** @brief Types that are _always_ boxed. */ + AlwaysBoxed = MaybeBoxed & ~(Cons | MaybeImmediate), + /** @brief Types that are _always_ immediates. */ + AlwaysImmediate = MaybeImmediate & ~(Cons | MaybeBoxed), +}; + +template +struct BeamTypeIdUnion; + +template<> +struct BeamTypeIdUnion<> { + static constexpr BeamTypeId value() { + return BeamTypeId::None; + } +}; + +template +struct BeamTypeIdUnion : BeamTypeIdUnion { + using integral = std::underlying_type_t; + using super = BeamTypeIdUnion; + + /* Overlapping type specifications are redundant at best and a subtle error + * at worst. We've had several bugs where `Integer | MaybeBoxed` was used + * instead of `Integer | AlwaysBoxed` or similar, and erroneously drew the + * conclusion that the value is always an integer when not boxed, when it + * could also be a pid or port. */ + static constexpr bool no_overlap = + (static_cast(super::value()) & + static_cast(T)) == BEAM_TYPE_NONE; + static constexpr bool no_boxed_overlap = + no_overlap || (super::value() != BeamTypeId::MaybeBoxed && + T != BeamTypeId::MaybeBoxed); + static constexpr bool no_immed_overlap = + no_overlap || (super::value() != BeamTypeId::MaybeImmediate && + T != BeamTypeId::MaybeImmediate); + + static_assert(no_boxed_overlap, + "types must not overlap, did you mean to use " + "BeamTypeId::AlwaysBoxed here?"); + static_assert(no_immed_overlap, + "types must not overlap, did you mean to use " + "BeamTypeId::AlwaysImmediate here?"); + static_assert(no_overlap || no_boxed_overlap || no_immed_overlap, + "types must not overlap"); + + static constexpr bool is_single_typed() { + constexpr auto V = static_cast(value()); + return (static_cast(V) & (static_cast(V) - 1)) == + BEAM_TYPE_NONE; + } + + static constexpr BeamTypeId value() { + return static_cast(static_cast(super::value()) | + static_cast(T)); + } +}; + +struct BeamArgType : public BeamType { + BeamTypeId type() const { + return static_cast(BeamType::type_union); + } + + bool hasLowerBound() const { + return metadata_flags & BEAM_TYPE_HAS_LOWER_BOUND; + } + + bool hasUpperBound() const { + return metadata_flags & BEAM_TYPE_HAS_UPPER_BOUND; + } + + bool hasUnit() const { + return metadata_flags & BEAM_TYPE_HAS_UNIT; + } + + auto max() const { + ASSERT(hasUpperBound()); + return BeamType::max; + } + + auto min() const { + ASSERT(hasLowerBound()); + return BeamType::min; + } + + auto unit() const { + ASSERT(hasUnit()); + return BeamType::size_unit; + } +}; + +static_assert(std::is_standard_layout::value); + +#endif diff --git a/erts/emulator/beam/jit/load.h b/erts/emulator/beam/jit/load.h index a3d099bb042c..3f259cfe7e7c 100644 --- a/erts/emulator/beam/jit/load.h +++ b/erts/emulator/beam/jit/load.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2020. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -25,9 +25,11 @@ * Type for a label. */ typedef struct { - Uint value; /* Value of label (0 if not known yet). */ - Uint looprec_targeted; /* Non-zero if this label is the target of a - * loop_rec instruction. */ + Uint value; /* Value of label (0 if not known yet). */ + int looprec_targeted; /* Non-zero if this label is the target of a + * loop_rec instruction. */ + int lambda_index; /* The lambda index of this label, or -1 if not + * a target of a lambda. */ } Label; /* @@ -41,8 +43,6 @@ typedef struct { /* This structure contains all information about the module being loaded. */ struct LoaderState_ { - ErlDrvBinary *bin; /* Binary holding BEAM file (or NULL) */ - /* * The following are used mainly for diagnostics. */ @@ -82,16 +82,19 @@ struct LoaderState_ { unsigned int current_li; /* Current line instruction */ unsigned int *func_line; /* Mapping from function to first line instr */ + /* Translates lambda indexes to their literals, if any. Lambdas that lack + * a literal (for example if they have an environment) are represented by + * ERTS_SWORD_MAX. */ + SWord *lambda_literals; + void *ba; /* Assembler used to create x86 assembly */ - const void *native_module_exec; /* Native module after codegen */ - void *native_module_rw; /* Native module after codegen, writable mapping */ + const void *executable_region; /* Native module after codegen */ + void *writable_region; /* Native module after codegen, writable mapping */ int function_number; int last_label; - int otp_20_or_higher; - BeamOpAllocator op_allocator; BeamFile beam; }; diff --git a/erts/emulator/beam/jit/x86/beam_asm.cpp b/erts/emulator/beam/jit/x86/beam_asm.cpp deleted file mode 100644 index 51d3a7db07dd..000000000000 --- a/erts/emulator/beam/jit/x86/beam_asm.cpp +++ /dev/null @@ -1,921 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2020-2022. 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% - */ - -#include "beam_asm.hpp" - -extern "C" -{ -#include "bif.h" -#include "beam_common.h" -#include "code_ix.h" -#include "export.h" -} - -/* Global configuration variables (under the `+J` prefix) */ -#ifdef HAVE_LINUX_PERF_SUPPORT -int erts_jit_perf_support; -#endif - -/* - * Special Beam instructions. - */ - -ErtsCodePtr beam_apply; -ErtsCodePtr beam_normal_exit; -ErtsCodePtr beam_exit; -ErtsCodePtr beam_export_trampoline; -ErtsCodePtr beam_bif_export_trap; -ErtsCodePtr beam_continue_exit; -ErtsCodePtr beam_save_calls; - -/* NOTE These should be the only variables containing trace instructions. -** Sometimes tests are for the instruction value, and sometimes -** for the variable reference (one of these), and rogue references -** will most likely cause chaos. -*/ -ErtsCodePtr beam_return_to_trace; /* OpCode(i_return_to_trace) */ -ErtsCodePtr beam_return_trace; /* OpCode(i_return_trace) */ -ErtsCodePtr beam_exception_trace; /* UGLY also OpCode(i_return_trace) */ -ErtsCodePtr beam_return_time_trace; /* OpCode(i_return_time_trace) */ - -static JitAllocator *jit_allocator; - -static BeamGlobalAssembler *bga; -static BeamModuleAssembler *bma; -static CpuInfo cpuinfo; - -static void beamasm_init_gdb_jit_info(void); - -/* - * Enter all BIFs into the export table. - * - * Note that they will all call the error_handler until their modules have been - * loaded, which may prevent the system from booting if BIFs from non-preloaded - * modules are apply/3'd while loading code. Ordinary BIF calls will work fine - * however since they won't go through export entries. - */ -static void install_bifs(void) { - typedef Eterm (*bif_func_type)(Process *, Eterm *, ErtsCodePtr); - int i; - - ASSERT(beam_export_trampoline != NULL); - ASSERT(beam_save_calls != NULL); - - for (i = 0; i < BIF_SIZE; i++) { - BifEntry *entry; - Export *ep; - int j; - - entry = &bif_table[i]; - - ep = erts_export_put(entry->module, entry->name, entry->arity); - - ep->info.op = op_i_func_info_IaaI; - ep->info.mfa.module = entry->module; - ep->info.mfa.function = entry->name; - ep->info.mfa.arity = entry->arity; - ep->bif_number = i; - - for (j = 0; j < ERTS_NUM_CODE_IX; j++) { - erts_activate_export_trampoline(ep, j); - } - - /* Set up a hidden export entry so we can trap to this BIF without - * it being seen when tracing. */ - erts_init_trap_export(BIF_TRAP_EXPORT(i), - entry->module, - entry->name, - entry->arity, - (bif_func_type)entry->f); - } -} - -static JitAllocator *create_allocator(JitAllocator::CreateParams *params) { - void *test_ro, *test_rw; - Error err; - - auto *allocator = new JitAllocator(params); - - err = allocator->alloc(&test_ro, &test_rw, 1); - allocator->release(test_ro); - - if (err == ErrorCode::kErrorOk) { - return allocator; - } - - delete allocator; - return nullptr; -} - -static JitAllocator *pick_allocator() { - JitAllocator::CreateParams single_params; - single_params.reset(); - -#if defined(HAVE_LINUX_PERF_SUPPORT) - /* `perf` has a hard time showing symbols for dual-mapped memory, so we'll - * use single-mapped memory when enabled. */ - if (erts_jit_perf_support & (BEAMASM_PERF_DUMP | BEAMASM_PERF_MAP)) { - if (auto *alloc = create_allocator(&single_params)) { - return alloc; - } - - ERTS_INTERNAL_ERROR("jit: Failed to allocate executable+writable " - "memory. Either allow this or disable the " - "'+JPperf' option."); - } -#endif - -#if !defined(VALGRIND) - /* Default to dual-mapped memory with separate executable and writable - * regions of the same code. This is required for platforms that enforce - * W^X, and we prefer it when available to catch errors sooner. - * - * `blockSize` is analogous to "carrier size," and we pick something - * much larger than the default since dual-mapping implies having one - * file descriptor per block on most platforms. The block sizes do grow - * over time, but we don't want to waste half a dozen fds just to get to - * the shell on platforms that are very fd-constrained. */ - JitAllocator::CreateParams dual_params; - - dual_params.reset(); - dual_params.options = JitAllocatorOptions::kUseDualMapping, - dual_params.blockSize = 4 << 20; - - if (auto *alloc = create_allocator(&dual_params)) { - return alloc; - } else if (auto *alloc = create_allocator(&single_params)) { - return alloc; - } - - ERTS_INTERNAL_ERROR("jit: Cannot allocate executable memory. Use the " - "interpreter instead."); -#elif defined(VALGRIND) - if (auto *alloc = create_allocator(&single_params)) { - return alloc; - } - - ERTS_INTERNAL_ERROR("jit: the valgrind emulator requires the ability to " - "allocate executable+writable memory."); -#endif -} - -void beamasm_init() { - unsigned label = 1; - - ASSERT(bga == nullptr && bma == nullptr); - - struct operands { - Eterm name; - BeamInstr operand; - ErtsCodePtr *target; - }; - - std::vector operands = { - {am_exit, op_error_action_code, &beam_exit}, - {am_continue_exit, op_continue_exit, &beam_continue_exit}, - {am_return_trace, op_return_trace, &beam_return_trace}, - {am_return_to_trace, op_i_return_to_trace, &beam_return_to_trace}, - {am_return_time_trace, - op_i_return_time_trace, - &beam_return_time_trace}, - {am_exception_trace, op_return_trace, &beam_exception_trace}}; - - Eterm mod_name; - ERTS_DECL_AM(erts_beamasm); - mod_name = AM_erts_beamasm; - - beamasm_init_perf(); - beamasm_init_gdb_jit_info(); - - /* - * Ensure that commonly used fields in the PCB can be accessed with - * short instructions. Before removing any of these assertions, please - * consider the effect it will have on code size and/or performance. - */ - - ERTS_CT_ASSERT(offsetof(Process, htop) < 128); - ERTS_CT_ASSERT(offsetof(Process, stop) < 128); - ERTS_CT_ASSERT(offsetof(Process, fcalls) < 128); - ERTS_CT_ASSERT(offsetof(Process, freason) < 128); - ERTS_CT_ASSERT(offsetof(Process, fvalue) < 128); - - cpuinfo = CpuInfo::host(); - - jit_allocator = pick_allocator(); - - bga = new BeamGlobalAssembler(jit_allocator); - - bma = new BeamModuleAssembler(bga, mod_name, 4 + operands.size() * 2); - - for (auto &op : operands) { - unsigned func_label, entry_label; - - func_label = label++; - entry_label = label++; - - bma->emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, func_label), - ArgVal(ArgVal::u, sizeof(UWord))}); - bma->emit(op_i_func_info_IaaI, - {ArgVal(ArgVal::i, func_label), - ArgVal(ArgVal::i, am_erts_internal), - ArgVal(ArgVal::i, op.name), - ArgVal(ArgVal::i, 0)}); - bma->emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, entry_label), - ArgVal(ArgVal::u, sizeof(UWord))}); - bma->emit(op.operand, {}); - - op.operand = entry_label; - } - - { - unsigned func_label, apply_label, normal_exit_label; - - func_label = label++; - apply_label = label++; - normal_exit_label = label++; - - bma->emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, func_label), - ArgVal(ArgVal::u, sizeof(UWord))}); - bma->emit(op_i_func_info_IaaI, - {ArgVal(ArgVal::i, func_label), - ArgVal(ArgVal::i, am_erts_internal), - ArgVal(ArgVal::i, am_apply), - ArgVal(ArgVal::i, 3)}); - bma->emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, apply_label), - ArgVal(ArgVal::u, sizeof(UWord))}); - bma->emit(op_i_apply, {}); - bma->emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, normal_exit_label), - ArgVal(ArgVal::u, sizeof(UWord))}); - bma->emit(op_normal_exit, {}); - - bma->emit(op_int_code_end, {}); - - { - /* We have no need of the module pointers as we use `getCode(...)` - * for everything, and the code will live as long as the emulator - * itself. */ - const void *_ignored_exec; - void *_ignored_rw; - bma->codegen(jit_allocator, &_ignored_exec, &_ignored_rw); - } - - beam_apply = bma->getCode(apply_label); - beam_normal_exit = bma->getCode(normal_exit_label); - } - - for (auto op : operands) { - if (op.target) { - *op.target = bma->getCode(op.operand); - } - } - - /* This instruction relies on register contents, and can only be reached - * from a `call_ext_*`-instruction, hence the lack of a wrapper function. */ - beam_save_calls = (ErtsCodePtr)bga->get_dispatch_save_calls(); - beam_export_trampoline = (ErtsCodePtr)bga->get_export_trampoline(); - beam_bif_export_trap = (ErtsCodePtr)bga->get_bif_export_trap(); -} - -bool BeamAssembler::hasCpuFeature(uint32_t featureId) { - return cpuinfo.hasFeature(featureId); -} - -void init_emulator(void) { - install_bifs(); -} - -void process_main(ErtsSchedulerData *esdp) { - typedef void (*pmain_type)(ErtsSchedulerData *); - - pmain_type pmain = (pmain_type)bga->get_process_main(); - pmain(esdp); -} - -#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) -static Process *erts_debug_schedule(ErtsSchedulerData *esdp, - Process *c_p, - int calls) { - PROCESS_MAIN_CHK_LOCKS(c_p); - ERTS_UNREQ_PROC_MAIN_LOCK(c_p); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - c_p = erts_schedule(esdp, c_p, calls); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - ERTS_REQ_PROC_MAIN_LOCK(c_p); - PROCESS_MAIN_CHK_LOCKS(c_p); - return c_p; -} -#endif - -/* void process_main(ErtsSchedulerData *esdp); */ -void BeamGlobalAssembler::emit_process_main() { - Label context_switch_local = a.newLabel(), - context_switch_simplified_local = a.newLabel(), - do_schedule_local = a.newLabel(), schedule_next = a.newLabel(); - - const x86::Mem start_time_i = - getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time_i)); - const x86::Mem start_time = - getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time)); - - /* Allocate the register structure on the stack to allow computing the - * runtime stack address from it, greatly reducing the cost of stack - * swapping. */ - a.sub(x86::rsp, imm(sizeof(ErtsSchedulerRegisters) + ERTS_CACHE_LINE_SIZE)); - a.and_(x86::rsp, imm(~ERTS_CACHE_LINE_MASK)); - - a.mov(x86::qword_ptr(ARG1, offsetof(ErtsSchedulerData, registers)), - x86::rsp); - - /* Center `registers` at the base of x_reg_array so we can use negative - * 8-bit displacement to address the commonly used aux_regs, located at the - * start of the ErtsSchedulerRegisters struct. */ - a.lea(registers, - x86::qword_ptr(x86::rsp, - offsetof(ErtsSchedulerRegisters, x_reg_array.d))); - -#if defined(DEBUG) && defined(NATIVE_ERLANG_STACK) - /* Save stack bounds so they can be tested without clobbering anything. */ - a.call(erts_get_stacklimit); - - a.mov(getSchedulerRegRef( - offsetof(ErtsSchedulerRegisters, runtime_stack_end)), - RET); - a.mov(getSchedulerRegRef( - offsetof(ErtsSchedulerRegisters, runtime_stack_start)), - x86::rsp); -#elif !defined(NATIVE_ERLANG_STACK) - /* Save the initial SP of the thread so that we can verify that it - * doesn't grow. */ -# ifdef JIT_HARD_DEBUG - a.mov(getInitialSPRef(), x86::rsp); -# endif - - /* Manually do an `emit_enter_runtime` to match the `emit_leave_runtime` - * below. We avoid `emit_enter_runtime` because it may do additional - * assertions that may currently fail. - * - * IMPORTANT: We must ensure that this sequence leaves the stack - * aligned on a 16-byte boundary. */ - a.mov(getRuntimeStackRef(), x86::rsp); - a.sub(x86::rsp, imm(15)); - a.and_(x86::rsp, imm(-16)); -#endif - - load_erl_bits_state(ARG1); - runtime_call<1>(erts_bits_init_state); - - a.mov(start_time_i, imm(0)); - a.mov(start_time, imm(0)); - - mov_imm(c_p, 0); - mov_imm(FCALLS, 0); - mov_imm(ARG3, 0); /* Set reds_used for erts_schedule call */ - - a.jmp(schedule_next); - - a.bind(do_schedule_local); - { - /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ - a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5]))); - a.sub(ARG3, FCALLS); - - a.jmp(schedule_next); - } - - a.bind(context_switch_local); - comment("Context switch, unknown arity/MFA"); - { - Sint arity_offset = offsetof(ErtsCodeMFA, arity) - sizeof(ErtsCodeMFA); - - a.mov(ARG1, x86::qword_ptr(ARG3, arity_offset)); - a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), ARG1); - - a.lea(ARG1, x86::qword_ptr(ARG3, -(Sint)sizeof(ErtsCodeMFA))); - a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG1); - - /* !! Fall through !! */ - } - - a.bind(context_switch_simplified_local); - comment("Context switch, known arity and MFA"); - { - Label not_exiting = a.newLabel(); - -#ifdef DEBUG - Label check_i = a.newLabel(); - /* Check that ARG3 is set to a valid CP. */ - a.test(ARG3, imm(_CPMASK)); - a.je(check_i); - a.ud2(); - a.bind(check_i); -#endif - - a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), ARG3); - -#ifdef WIN32 - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.value))); -#else - a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.counter))); -#endif - - a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); - a.short_().je(not_exiting); - { - comment("Process exiting"); - - /* We load the beam_exit from memory because it has not yet been set - * when the global assembler is created. */ - a.mov(ARG1, imm(&beam_exit)); - a.mov(ARG1, x86::qword_ptr(ARG1)); - a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), ARG1); - a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), imm(0)); - a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), imm(0)); - a.jmp(do_schedule_local); - } - a.bind(not_exiting); - - /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ - a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5]))); - a.sub(ARG3, FCALLS); - - /* Spill reds_used to FCALLS as we no longer need that value */ - a.mov(FCALLS, ARG3); - - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<2>(copy_out_registers); - - /* Restore reds_used from FCALLS */ - a.mov(ARG3, FCALLS); - - /* !! Fall through !! */ - } - - a.bind(schedule_next); - comment("schedule_next"); - { - Label schedule = a.newLabel(), skip_long_schedule = a.newLabel(); - - /* ARG3 contains reds_used at this point */ - - a.cmp(start_time, imm(0)); - a.short_().je(schedule); - { - a.mov(ARG1, c_p); - a.mov(ARG2, start_time); - - /* Spill reds_used in start_time slot */ - a.mov(start_time, ARG3); - - a.mov(ARG3, start_time_i); - runtime_call<3>(check_monitor_long_schedule); - - /* Restore reds_used */ - a.mov(ARG3, start_time); - } - a.bind(schedule); - - mov_imm(ARG1, 0); - a.mov(ARG2, c_p); -#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) - runtime_call<3>(erts_debug_schedule); -#else - runtime_call<3>(erts_schedule); -#endif - a.mov(c_p, RET); - -#ifdef ERTS_MSACC_EXTENDED_STATES - a.lea(ARG1, - x86::qword_ptr(registers, - offsetof(ErtsSchedulerRegisters, - aux_regs.d.erts_msacc_cache))); - runtime_call<1>(erts_msacc_update_cache); -#endif - - a.mov(ARG1, imm((UWord)&erts_system_monitor_long_schedule)); - a.cmp(x86::qword_ptr(ARG1), imm(0)); - a.mov(start_time, imm(0)); - a.short_().je(skip_long_schedule); - { - /* Enable long schedule test */ - runtime_call<0>(erts_timestamp_millis); - a.mov(start_time, RET); - a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, i))); - a.mov(start_time_i, RET); - } - a.bind(skip_long_schedule); - - /* Copy arguments */ - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<2>(copy_in_registers); - - /* Setup reduction counting */ - a.mov(FCALLS, x86::qword_ptr(c_p, offsetof(Process, fcalls))); - a.mov(x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5])), FCALLS); - -#ifdef DEBUG - a.mov(x86::qword_ptr(c_p, offsetof(Process, debug_reds_in)), FCALLS); -#endif - - /* Check whether save calls is on */ - a.mov(ARG1, c_p); - a.mov(ARG2, imm(ERTS_PSD_SAVED_CALLS_BUF)); - runtime_call<2>(erts_psd_get); - - /* Read the active code index, overriding it with - * ERTS_SAVE_CALLS_CODE_IX when save_calls is enabled (RET != 0). */ - a.test(RET, RET); - a.mov(ARG1, imm(&the_active_code_index)); - a.mov(ARG2, imm(ERTS_SAVE_CALLS_CODE_IX)); - a.mov(active_code_ix.r32(), x86::dword_ptr(ARG1)); - a.cmovnz(active_code_ix, ARG2); - - /* Start executing the Erlang process. Note that reductions have - * already been set up above. */ - emit_leave_runtime(); - - /* Check if we are just returning from a dirty nif/bif call and if so we - * need to do a bit of cleaning up before continuing. */ - a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, i))); - a.cmp(x86::qword_ptr(RET), imm(op_call_nif_WWW)); - a.je(labels[dispatch_nif]); - a.cmp(x86::qword_ptr(RET), imm(op_call_bif_W)); - a.je(labels[dispatch_bif]); - a.jmp(RET); - } - - /* Processes may jump to the exported entry points below, executing on the - * Erlang stack when entering. These are separate from the `_local` labels - * above as we don't want to worry about which stack we're on when the - * cases overlap. */ - - /* `ga->get_context_switch()` - * - * The *next* instruction pointer is provided in ARG3, and must be preceded - * by an ErtsCodeMFA. */ - a.bind(labels[context_switch]); - { - emit_enter_runtime(); - - a.jmp(context_switch_local); - } - - /* `ga->get_context_switch_simplified()` - * - * The next instruction pointer is provided in ARG3, which does not need to - * point past an ErtsCodeMFA as the process structure has already been - * updated. */ - a.bind(labels[context_switch_simplified]); - { - emit_enter_runtime(); - - a.jmp(context_switch_simplified_local); - } - - /* `ga->get_do_schedule()` - * - * `c_p->i` must be set prior to jumping here. */ - a.bind(labels[do_schedule]); - { - emit_enter_runtime(); - - a.jmp(do_schedule_local); - } -} - -enum jit_actions : uint32_t { - JIT_NOACTION = 0, - JIT_REGISTER_FN, - JIT_UNREGISTER_FN, -}; - -struct jit_code_entry { - struct jit_code_entry *next_entry; - struct jit_code_entry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; -}; - -struct jit_descriptor { - uint32_t version; - jit_actions action_flag; - struct jit_code_entry *relevant_entry; - struct jit_code_entry *first_entry; - erts_mtx_t mutex; -}; - -extern "C" -{ - extern void ERTS_NOINLINE __jit_debug_register_code(void); - - /* Make sure to specify the version statically, because the - * debugger may check the version before we can set it. */ - struct jit_descriptor __jit_debug_descriptor = {1, - JIT_NOACTION, - NULL, - NULL}; -} /* extern "C" */ - -static void beamasm_init_gdb_jit_info(void) { - Sint symfile_size = sizeof(uint64_t) * 2; - uint64_t *symfile = (uint64_t *)malloc(symfile_size); - jit_code_entry *entry; - - symfile[0] = 0; - symfile[1] = (uint64_t)beam_normal_exit; - - entry = (jit_code_entry *)malloc(sizeof(jit_code_entry)); - - /* Add address description */ - entry->symfile_addr = (char *)symfile; - entry->symfile_size = symfile_size; - - /* Insert into linked list */ - entry->next_entry = __jit_debug_descriptor.first_entry; - if (entry->next_entry) { - entry->next_entry->prev_entry = entry; - } else { - entry->prev_entry = nullptr; - } - - /* register with dbg */ - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - __jit_debug_descriptor.first_entry = entry; - __jit_debug_descriptor.relevant_entry = entry; - __jit_debug_register_code(); - - erts_mtx_init(&__jit_debug_descriptor.mutex, - "jit_debug_descriptor", - NIL, - (ERTS_LOCK_FLAGS_PROPERTY_STATIC | - ERTS_LOCK_FLAGS_CATEGORY_GENERIC)); -} - -void BeamAssembler::update_gdb_jit_info(std::string modulename, - std::vector &functions) { - Sint symfile_size = sizeof(uint64_t) * 3 + modulename.size() + 1; - - for (auto fun : functions) { - symfile_size += sizeof(uint64_t) * 2; - symfile_size += fun.name.size() + 1; - } - - char *symfile = (char *)malloc(symfile_size); - jit_code_entry *entry; - - entry = (jit_code_entry *)malloc(sizeof(jit_code_entry)); - - /* Add address description */ - entry->symfile_addr = symfile; - entry->symfile_size = symfile_size; - - ((uint64_t *)symfile)[0] = functions.size(); - ((uint64_t *)symfile)[1] = code.baseAddress(); - ((uint64_t *)symfile)[2] = (uint64_t)code.codeSize(); - - symfile += sizeof(uint64_t) * 3; - - sys_memcpy(symfile, modulename.c_str(), modulename.size() + 1); - symfile += modulename.size() + 1; - - for (unsigned i = 0; i < functions.size(); i++) { - ((uint64_t *)symfile)[0] = (uint64_t)functions[i].start; - ((uint64_t *)symfile)[1] = (uint64_t)functions[i].stop; - - ASSERT(functions[i].start <= functions[i].stop); - - symfile += sizeof(uint64_t) * 2; - - sys_memcpy(symfile, - functions[i].name.c_str(), - functions[i].name.size() + 1); - symfile += functions[i].name.size() + 1; - } - - ASSERT(symfile_size == (symfile - entry->symfile_addr)); - - /* Insert into linked list */ - erts_mtx_lock(&__jit_debug_descriptor.mutex); - entry->next_entry = __jit_debug_descriptor.first_entry; - if (entry->next_entry) { - entry->next_entry->prev_entry = entry; - } else { - entry->prev_entry = nullptr; - } - - /* register with dbg */ - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - __jit_debug_descriptor.first_entry = entry; - __jit_debug_descriptor.relevant_entry = entry; - __jit_debug_register_code(); - erts_mtx_unlock(&__jit_debug_descriptor.mutex); -} - -extern "C" -{ - int erts_beam_jump_table(void) { -#if defined(NO_JUMP_TABLE) - return 0; -#else - return 1; -#endif - } - - void *beamasm_new_assembler(Eterm mod, int num_labels, int num_functions) { - return new BeamModuleAssembler(bga, mod, num_labels, num_functions); - } - - int beamasm_emit(void *instance, unsigned specific_op, BeamOp *op) { - BeamModuleAssembler *ba = static_cast(instance); - const std::vector args(&op->a[0], &op->a[op->arity]); - - return ba->emit(specific_op, args); - } - - void beamasm_emit_call_nif(const ErtsCodeInfo *info, - void *normal_fptr, - void *lib, - void *dirty_fptr, - char *buff, - unsigned buff_len) { - BeamModuleAssembler ba(bga, info->mfa.module, 3); - - ba.emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, 1), ArgVal(ArgVal::u, sizeof(UWord))}); - ba.emit(op_i_func_info_IaaI, - {ArgVal(ArgVal::i, 1), - ArgVal(ArgVal::i, info->mfa.module), - ArgVal(ArgVal::i, info->mfa.function), - ArgVal(ArgVal::i, info->mfa.arity)}); - ba.emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, 2), ArgVal(ArgVal::u, sizeof(UWord))}); - ba.emit(op_i_breakpoint_trampoline, {}); - ba.emit(op_call_nif_WWW, - {ArgVal(ArgVal::i, (BeamInstr)normal_fptr), - ArgVal(ArgVal::i, (BeamInstr)lib), - ArgVal(ArgVal::i, (BeamInstr)dirty_fptr)}); - - ba.codegen(buff, buff_len); - } - - void beamasm_emit_call_bif(const ErtsCodeInfo *info, - Eterm (*bif)(BIF_ALIST), - char *buff, - unsigned buff_len) { - BeamModuleAssembler ba(bga, info->mfa.module, 3); - - ba.emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, 1), ArgVal(ArgVal::u, sizeof(UWord))}); - ba.emit(op_i_func_info_IaaI, - {ArgVal(ArgVal::i, 1), - ArgVal(ArgVal::i, info->mfa.module), - ArgVal(ArgVal::i, info->mfa.function), - ArgVal(ArgVal::i, info->mfa.arity)}); - ba.emit(op_aligned_label_Lt, - {ArgVal(ArgVal::i, 2), ArgVal(ArgVal::u, sizeof(UWord))}); - ba.emit(op_i_breakpoint_trampoline, {}); - ba.emit(op_call_bif_W, {ArgVal(ArgVal::i, (BeamInstr)bif)}); - - ba.codegen(buff, buff_len); - } - - void beamasm_delete_assembler(void *instance) { - BeamModuleAssembler *ba = static_cast(instance); - delete ba; - } - - void beamasm_purge_module(const void *native_module_exec, - void *native_module_rw) { - jit_allocator->release(const_cast(native_module_exec)); - } - - ErtsCodePtr beamasm_get_code(void *instance, int label) { - BeamModuleAssembler *ba = static_cast(instance); - return reinterpret_cast(ba->getCode(label)); - } - - const byte *beamasm_get_rodata(void *instance, char *label) { - BeamModuleAssembler *ba = static_cast(instance); - return reinterpret_cast(ba->getCode(label)); - } - - void beamasm_embed_rodata(void *instance, - const char *labelName, - const char *buff, - size_t size) { - BeamModuleAssembler *ba = static_cast(instance); - if (size) { - ba->embed_rodata(labelName, buff, size); - } - } - - void beamasm_embed_bss(void *instance, char *labelName, size_t size) { - BeamModuleAssembler *ba = static_cast(instance); - if (size) { - ba->embed_bss(labelName, size); - } - } - - void beamasm_codegen(void *instance, - const void **native_module_exec, - void **native_module_rw, - const BeamCodeHeader *in_hdr, - const BeamCodeHeader **out_exec_hdr, - BeamCodeHeader **out_rw_hdr) { - BeamModuleAssembler *ba = static_cast(instance); - - ba->codegen(jit_allocator, - native_module_exec, - native_module_rw, - in_hdr, - out_exec_hdr, - out_rw_hdr); - } - - Uint beamasm_get_header(void *instance, const BeamCodeHeader **hdr) { - BeamModuleAssembler *ba = static_cast(instance); - - *hdr = ba->getCodeHeader(); - - return ba->getCodeSize(); - } - - char *beamasm_get_base(void *instance) { - BeamModuleAssembler *ba = static_cast(instance); - return (char *)ba->getBaseAddress(); - } - - size_t beamasm_get_offset(void *instance) { - BeamModuleAssembler *ba = static_cast(instance); - return ba->getOffset(); - } - - const ErtsCodeInfo *beamasm_get_on_load(void *instance) { - BeamModuleAssembler *ba = static_cast(instance); - return ba->getOnLoad(); - } - - unsigned int beamasm_patch_catches(void *instance, char *rw_base) { - BeamModuleAssembler *ba = static_cast(instance); - return ba->patchCatches(rw_base); - } - - void beamasm_patch_import(void *instance, - char *rw_base, - int index, - BeamInstr import) { - BeamModuleAssembler *ba = static_cast(instance); - ba->patchImport(rw_base, index, import); - } - - void beamasm_patch_literal(void *instance, - char *rw_base, - int index, - Eterm lit) { - BeamModuleAssembler *ba = static_cast(instance); - ba->patchLiteral(rw_base, index, lit); - } - - void beamasm_patch_lambda(void *instance, - char *rw_base, - int index, - BeamInstr fe) { - BeamModuleAssembler *ba = static_cast(instance); - ba->patchLambda(rw_base, index, fe); - } - - void beamasm_patch_strings(void *instance, - char *rw_base, - const byte *string_table) { - BeamModuleAssembler *ba = static_cast(instance); - ba->patchStrings(rw_base, string_table); - } -} - -const uint8_t *BeamAssembler::nops[3] = {nop1, nop2, nop3}; -const uint8_t BeamAssembler::nop1[1] = {0x90}; -const uint8_t BeamAssembler::nop2[2] = {0x66, 0x90}; -const uint8_t BeamAssembler::nop3[3] = {0x0F, 0x1F, 0x00}; diff --git a/erts/emulator/beam/jit/x86/beam_asm.hpp b/erts/emulator/beam/jit/x86/beam_asm.hpp index 813305c96974..c7f085ee622e 100644 --- a/erts/emulator/beam/jit/x86/beam_asm.hpp +++ b/erts/emulator/beam/jit/x86/beam_asm.hpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -22,6 +22,8 @@ #include #include #include +#include +#include #ifndef ASMJIT_ASMJIT_H_INCLUDED # include @@ -37,26 +39,33 @@ extern "C" #include "erl_vm.h" #include "global.h" #include "beam_catches.h" +#include "big.h" #include "beam_asm.h" } #include "beam_jit_common.hpp" -using namespace asmjit; +/* On Windows, the min and max macros may be defined. */ +#undef min +#undef max -class BeamAssembler : public ErrorHandler { -protected: - /* Holds code and relocation information. */ - CodeHolder code; +using namespace asmjit; - /* TODO: Want to change this to x86::Builder in order to be able to patch - * the correct I into the code after code generation */ - x86::Assembler a; +struct BeamAssembler : public BeamAssemblerCommon { + BeamAssembler() : BeamAssemblerCommon(a) { + Error err = code.attach(&a); + ERTS_ASSERT(!err && "Failed to attach codeHolder"); + } - FileLogger logger; + BeamAssembler(const std::string &log) : BeamAssembler() { + if (erts_jit_asm_dump) { + setLogger(log + ".asm"); + } + } - Section *rodata = nullptr; +protected: + x86::Assembler a; /* * * * * * * * * */ @@ -69,16 +78,18 @@ class BeamAssembler : public ErrorHandler { * when running on the runtime stack. */ const x86::Gp E = x86::rsp; - /* Cached copy of Erlang stack pointer used to speed up stack switches when - * we know that the runtime doesn't read or modify the Erlang stack. - * - * If we find ourselves pressed for registers in the future, we could save - * this in the same slot as `registers` as that can be trivially recomputed - * from the top of the runtime stack. */ - const x86::Gp E_saved = x86::r12; +# ifdef ERLANG_FRAME_POINTERS + /* Current frame pointer, used when we emit native stack frames (e.g. to + * better support `perf`). */ + const x86::Gp frame_pointer = x86::rbp; +# endif + /* When we're not using frame pointers, we can keep the Erlang stack in + * RBP when running on the runtime stack, which is slightly faster than + * reading and writing from c_p->stop. */ + const x86::Gp E_saved = x86::rbp; #else - const x86::Gp E = x86::r12; + const x86::Gp E = x86::rbp; #endif const x86::Gp c_p = x86::r13; @@ -90,7 +101,7 @@ class BeamAssembler : public ErrorHandler { * This is set to ERTS_SAVE_CALLS_CODE_IX when save_calls is active, which * routes us to a common handler routine that calls save_calls before * jumping to the actual code. */ - const x86::Gp active_code_ix = x86::rbp; + const x86::Gp active_code_ix = x86::r12; #ifdef ERTS_MSACC_EXTENDED_STATES const x86::Mem erts_msacc_cache = getSchedulerRegRef( @@ -161,106 +172,6 @@ class BeamAssembler : public ErrorHandler { enum Distance { dShort, dLong }; -public: - static bool hasCpuFeature(uint32_t featureId); - - BeamAssembler() : code() { - /* Setup with default code info */ - Error err = code.init(Environment::host()); - ERTS_ASSERT(!err && "Failed to init codeHolder"); - - err = code.newSection(&rodata, - ".rodata", - SIZE_MAX, - SectionFlags::kReadOnly, - 8); - ERTS_ASSERT(!err && "Failed to create .rodata section"); - - err = code.attach(&a); - - ERTS_ASSERT(!err && "Failed to attach codeHolder"); -#ifdef DEBUG - a.addDiagnosticOptions(DiagnosticOptions::kValidateAssembler); -#endif - a.addEncodingOptions(EncodingOptions::kOptimizeForSize); - code.setErrorHandler(this); - } - - BeamAssembler(const std::string &log) : BeamAssembler() { - if (erts_jit_asm_dump) { - setLogger(log + ".asm"); - } - } - - ~BeamAssembler() { - if (logger.file()) - fclose(logger.file()); - } - - void *getBaseAddress() { - ASSERT(code.hasBaseAddress()); - return (void *)code.baseAddress(); - } - - size_t getOffset() { - return a.offset(); - } - -protected: - void _codegen(JitAllocator *allocator, - const void **executable_ptr, - void **writable_ptr) { - Error err = code.flatten(); - ERTS_ASSERT(!err && "Could not flatten code"); - err = code.resolveUnresolvedLinks(); - ERTS_ASSERT(!err && "Could not resolve all links"); - - /* Verify that all labels are bound */ -#ifdef DEBUG - for (auto e : code.labelEntries()) { - if (!e->isBound()) { - erts_exit(ERTS_ABORT_EXIT, "Label %s is not bound", e->name()); - } - } -#endif - - err = allocator->alloc(const_cast(executable_ptr), - writable_ptr, - code.codeSize() + 16); - - if (err == ErrorCode::kErrorTooManyHandles) { - ERTS_ASSERT(!"Failed to allocate module code: " - "out of file descriptors"); - } else if (err) { - ERTS_ASSERT("Failed to allocate module code"); - } - - code.relocateToBase((uint64_t)*executable_ptr); - code.copyFlattenedData(*writable_ptr, - code.codeSize(), - CopySectionFlags::kPadSectionBuffer); -#ifdef DEBUG - if (FileLogger *l = dynamic_cast(code.logger())) - if (FILE *f = l->file()) - fprintf(f, "; CODE_SIZE: %zd\n", code.codeSize()); -#endif - } - - void *getCode(Label label) { - ASSERT(label.isValid()); - return (char *)getBaseAddress() + code.labelOffsetFromBase(label); - } - - byte *getCode(char *labelName) { - return (byte *)getCode(code.labelByName(labelName, strlen(labelName))); - } - - void handleError(Error err, const char *message, BaseEmitter *origin) { - comment(message); - fflush(logger.file()); - ASSERT(0 && "Fault instruction encode"); - } - constexpr x86::Mem getRuntimeStackRef() const { int base = offsetof(ErtsSchedulerRegisters, aux_regs.d.runtime_stack); @@ -365,6 +276,7 @@ class BeamAssembler : public ErrorHandler { a.short_().jle(ok); a.bind(crash); + comment("Redzone touched"); a.ud2(); a.bind(ok); @@ -412,6 +324,7 @@ class BeamAssembler : public ErrorHandler { Label next = a.newLabel(); a.cmp(x86::rsp, getInitialSPRef()); a.short_().je(next); + comment("The stack has grown"); a.ud2(); a.bind(next); #endif @@ -553,52 +466,47 @@ class BeamAssembler : public ErrorHandler { } /* Explicitly position-independent absolute jump, for use in fragments that - * need to be memcpy'd for performance reasons (e.g. export entries) */ + * need to be memcpy'd for performance reasons (e.g. NIF stubs) */ template void pic_jmp(T(*addr)) { a.mov(ARG6, imm(addr)); a.jmp(ARG6); } - constexpr x86::Mem getArgRef(const ArgVal &val, + constexpr x86::Mem getArgRef(const ArgRegister &arg, size_t size = sizeof(UWord)) const { - switch (val.getType()) { - case ArgVal::TYPE::l: - return getFRef(val.getValue(), size); - case ArgVal::TYPE::x: - return getXRef(val.getValue(), size); - case ArgVal::TYPE::y: - return getYRef(val.getValue(), size); - default: - ERTS_ASSERT(!"NYI"); - return x86::Mem(); + if (arg.isXRegister()) { + return getXRef(arg.as().get(), size); + } else if (arg.isYRegister()) { + return getYRef(arg.as().get(), size); } + + return getFRef(arg.as().get(), size); } - /* Returns the current code address for the export entry in `Src` + /* Returns the current code address for the `Export` or `ErlFunEntry` in + * `Src`. * - * Export tracing, save_calls, etc is implemented by shared fragments that - * assume that the export entry is in RET, so we have to copy it over if it - * isn't already. */ - x86::Mem emit_setup_export_call(const x86::Gp &Src) { - return emit_setup_export_call(Src, active_code_ix); + * Export tracing, save_calls, etc are implemented by shared fragments that + * assume that the respective entry is in RET, so we have to copy it over + * if it isn't already. */ + x86::Mem emit_setup_dispatchable_call(const x86::Gp &Src) { + return emit_setup_dispatchable_call(Src, active_code_ix); } - x86::Mem emit_setup_export_call(const x86::Gp &Src, - const x86::Gp &CodeIndex) { + x86::Mem emit_setup_dispatchable_call(const x86::Gp &Src, + const x86::Gp &CodeIndex) { if (RET != Src) { a.mov(RET, Src); } - return x86::qword_ptr(RET, CodeIndex, 3, offsetof(Export, addresses)); - } - - /* Discards a continuation pointer, including the frame pointer if - * applicable. */ - void emit_discard_cp() { - emit_assert_erlang_stack(); + ERTS_CT_ASSERT(offsetof(ErlFunEntry, dispatch) == 0); + ERTS_CT_ASSERT(offsetof(Export, dispatch) == 0); - a.add(x86::rsp, imm(CP_SIZE * sizeof(Eterm))); + return x86::qword_ptr(RET, + CodeIndex, + 3, + offsetof(ErtsDispatchable, addresses)); } void emit_assert_runtime_stack() { @@ -623,6 +531,7 @@ class BeamAssembler : public ErrorHandler { a.short_().je(next); a.bind(crash); + comment("Runtime stack is corrupt"); a.ud2(); a.bind(next); @@ -643,18 +552,65 @@ class BeamAssembler : public ErrorHandler { a.short_().jle(next); a.bind(crash); + comment("Erlang stack is corrupt"); a.ud2(); a.bind(next); #endif } + /* Prefer `eHeapAlloc` over `eStack | eHeap` when calling + * functions in the runtime system that allocate heap + * memory (`HAlloc`, heap factories, etc). + * + * Prefer `eHeapOnlyAlloc` over `eHeapAlloc` for functions + * that assume there's already a certain amount of free + * space on the heap, such as those using `HeapOnlyAlloc` + * or similar. It's slightly cheaper in release builds, + * and in debug builds it updates `eStack` to ensure that + * we can make heap size assertions. */ enum Update : int { eStack = (1 << 0), eHeap = (1 << 1), eReductions = (1 << 2), - eCodeIndex = (1 << 3) + eCodeIndex = (1 << 3), + eHeapAlloc = Update::eHeap | Update::eStack, +#ifndef DEBUG + eHeapOnlyAlloc = Update::eHeap, +#else + eHeapOnlyAlloc = Update::eHeapAlloc +#endif }; + void emit_enter_frame() { +#ifdef NATIVE_ERLANG_STACK + if (ERTS_UNLIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA)) { +# ifdef ERLANG_FRAME_POINTERS + a.push(frame_pointer); + a.mov(frame_pointer, E); +# endif + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); + } +#endif + } + + void emit_leave_frame() { +#ifdef NATIVE_ERLANG_STACK + if (ERTS_UNLIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA)) { + a.leave(); + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); + } +#endif + } + + void emit_unwind_frame() { + emit_assert_erlang_stack(); + + emit_leave_frame(); + a.add(x86::rsp, imm(sizeof(UWord))); + } + template void emit_enter_runtime() { emit_assert_erlang_stack(); @@ -662,46 +618,79 @@ class BeamAssembler : public ErrorHandler { ERTS_CT_ASSERT((Spec & (Update::eReductions | Update::eStack | Update::eHeap)) == Spec); -#ifdef NATIVE_ERLANG_STACK - if (!(Spec & Update::eStack)) { - a.mov(E_saved, E); - } -#endif + if (ERTS_LIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_RA)) { + if ((Spec & (Update::eHeap | Update::eStack)) == + (Update::eHeap | Update::eStack)) { + /* To update both heap and stack we use SSE/AVX + * instructions like gcc -O3 does. Basically it is + * this function run through gcc -O3: + * + * struct a { long a; long b; long c; }; + * void test(long a, long b, long c, struct a *s) { + * s->a = a; + * s->b = b; + * s->c = c; + * } */ + ERTS_CT_ASSERT((offsetof(Process, stop) - + offsetof(Process, htop)) == sizeof(Eterm *)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vmovq(x86::xmm1, HTOP); + a.vpinsrq(x86::xmm0, x86::xmm1, E, 1); + a.vmovdqu(x86::xmmword_ptr(c_p, offsetof(Process, htop)), + x86::xmm0); + } else { + a.movq(x86::xmm0, HTOP); + a.movq(x86::xmm1, E); + a.punpcklqdq(x86::xmm0, x86::xmm1); + a.movups(x86::xmmword_ptr(c_p, offsetof(Process, htop)), + x86::xmm0); + } + } else if (Spec & Update::eHeap) { + a.mov(x86::qword_ptr(c_p, offsetof(Process, htop)), HTOP); + } else if (Spec & Update::eStack) { + a.mov(x86::qword_ptr(c_p, offsetof(Process, stop)), E); + } - if ((Spec & (Update::eHeap | Update::eStack)) == - (Update::eHeap | Update::eStack)) { - /* To update both heap and stack we use sse instructions like gcc - -O3 does. Basically it is this function run through gcc -O3: - - struct a { long a; long b; long c; }; - - void test(long a, long b, long c, struct a *s) { - s->a = a; - s->b = b; - s->c = c; - } - */ - ERTS_CT_ASSERT(offsetof(Process, stop) - offsetof(Process, htop) == - 8); - a.movq(x86::xmm0, HTOP); - a.movq(x86::xmm1, E); - if (Spec & Update::eReductions) { - a.mov(x86::qword_ptr(c_p, offsetof(Process, fcalls)), FCALLS); +#ifdef NATIVE_ERLANG_STACK + if (!(Spec & Update::eStack)) { + a.mov(E_saved, E); } - a.punpcklqdq(x86::xmm0, x86::xmm1); - a.movups(x86::xmmword_ptr(c_p, offsetof(Process, htop)), x86::xmm0); +#endif } else { - if ((Spec & Update::eStack)) { +#ifdef ERLANG_FRAME_POINTERS + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + + if (Spec & Update::eStack) { + ERTS_CT_ASSERT((offsetof(Process, frame_pointer) - + offsetof(Process, stop)) == sizeof(Eterm *)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vmovq(x86::xmm1, E); + a.vpinsrq(x86::xmm0, x86::xmm1, frame_pointer, 1); + a.vmovdqu(x86::xmmword_ptr(c_p, offsetof(Process, stop)), + x86::xmm0); + } else { + a.movq(x86::xmm0, E); + a.movq(x86::xmm1, frame_pointer); + a.punpcklqdq(x86::xmm0, x86::xmm1); + a.movups(x86::xmmword_ptr(c_p, offsetof(Process, stop)), + x86::xmm0); + } + } else { + /* We can skip updating the frame pointer whenever the process + * doesn't have to inspect the stack. We still need to update + * the stack pointer to switch stacks, though, since we don't + * have enough spare callee-save registers. */ a.mov(x86::qword_ptr(c_p, offsetof(Process, stop)), E); } if (Spec & Update::eHeap) { a.mov(x86::qword_ptr(c_p, offsetof(Process, htop)), HTOP); } +#endif + } - if (Spec & Update::eReductions) { - a.mov(x86::qword_ptr(c_p, offsetof(Process, fcalls)), FCALLS); - } + if (Spec & Update::eReductions) { + a.mov(x86::qword_ptr(c_p, offsetof(Process, fcalls)), FCALLS); } #ifdef NATIVE_ERLANG_STACK @@ -714,6 +703,14 @@ class BeamAssembler : public ErrorHandler { a.sub(x86::rsp, imm(15)); a.and_(x86::rsp, imm(-16)); +#endif + /* If the emulator has not been compiled with AVX support (which stops + * it from using legacy SSE instructions), we'll need to clear the upper + * bits of all AVX registers to avoid AVX/SSE transition penalties. */ +#if !defined(__AVX__) + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vzeroupper(); + } #endif } @@ -724,13 +721,25 @@ class BeamAssembler : public ErrorHandler { ERTS_CT_ASSERT((Spec & (Update::eReductions | Update::eStack | Update::eHeap | Update::eCodeIndex)) == Spec); + if (ERTS_LIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_RA)) { + if (Spec & Update::eStack) { + a.mov(E, x86::qword_ptr(c_p, offsetof(Process, stop))); + } else { #ifdef NATIVE_ERLANG_STACK - if (!(Spec & Update::eStack)) { - a.mov(E, E_saved); - } + a.mov(E, E_saved); #endif - if ((Spec & Update::eStack)) { + } + } else { +#ifdef ERLANG_FRAME_POINTERS + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + a.mov(E, x86::qword_ptr(c_p, offsetof(Process, stop))); + + if (Spec & Update::eStack) { + a.mov(frame_pointer, + x86::qword_ptr(c_p, offsetof(Process, frame_pointer))); + } +#endif } if (Spec & Update::eHeap) { @@ -757,7 +766,7 @@ class BeamAssembler : public ErrorHandler { #endif } - void emit_is_boxed(Label Fail, x86::Gp Src, Distance dist = dLong) { + void emit_test_boxed(x86::Gp Src) { /* Use the shortest possible instruction depending on the source * register. */ if (Src == x86::rax || Src == x86::rdi || Src == x86::rsi || @@ -766,6 +775,10 @@ class BeamAssembler : public ErrorHandler { } else { a.test(Src.r32(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); } + } + + void emit_is_boxed(Label Fail, x86::Gp Src, Distance dist = dLong) { + emit_test_boxed(Src); if (dist == dShort) { a.short_().jne(Fail); } else { @@ -773,6 +786,15 @@ class BeamAssembler : public ErrorHandler { } } + void emit_is_not_boxed(Label Fail, x86::Gp Src, Distance dist = dLong) { + emit_test_boxed(Src); + if (dist == dShort) { + a.short_().je(Fail); + } else { + a.je(Fail); + } + } + x86::Gp emit_ptr_val(x86::Gp Dst, x86::Gp Src) { #if !defined(TAG_LITERAL_PTR) return Src; @@ -807,12 +829,53 @@ class BeamAssembler : public ErrorHandler { } } + /* Set the Z flag if Reg1 and Reg2 are definitely not equal based on their + * tags alone. (They may still be equal if both are immediates and all other + * bits are equal too.) */ + void emit_is_unequal_based_on_tags(x86::Gp Reg1, x86::Gp Reg2) { + ASSERT(Reg1 != RET && Reg2 != RET); + emit_is_unequal_based_on_tags(Reg1, Reg2, RET); + } + + void emit_is_unequal_based_on_tags(x86::Gp Reg1, + x86::Gp Reg2, + const x86::Gp &spill) { + ERTS_CT_ASSERT(TAG_PRIMARY_IMMED1 == _TAG_PRIMARY_MASK); + ERTS_CT_ASSERT((TAG_PRIMARY_LIST | TAG_PRIMARY_BOXED) == + TAG_PRIMARY_IMMED1); + a.mov(RETd, Reg1.r32()); + a.or_(RETd, Reg2.r32()); + a.and_(RETb, imm(_TAG_PRIMARY_MASK)); + + /* RET will be now be TAG_PRIMARY_IMMED1 if either one or both + * registers are immediates, or if one register is a list and the other + * a boxed. */ + a.cmp(RETb, imm(TAG_PRIMARY_IMMED1)); + } + /* * Generate the shortest instruction for setting a register to an immediate * value. May clear flags. */ - void mov_imm(x86::Gp to, Uint value) { - if (value == 0) { + template + void mov_imm(x86::Gp to, T value) { + static_assert(std::is_integral::value || std::is_pointer::value); + if (value) { + /* Generate the shortest instruction to set the register to an + * immediate. + * + * 48 c7 c0 2a 00 00 00 mov rax, 42 + * b8 2a 00 00 00 mov eax, 42 + * + * 49 c7 c0 2a 00 00 00 mov r8, 42 + * 41 b8 2a 00 00 00 mov r8d, 42 + */ + if (Support::isUInt32((Uint)value)) { + a.mov(to.r32(), imm(value)); + } else { + a.mov(to, imm(value)); + } + } else { /* * Generate the shortest instruction to set the register to zero. * @@ -825,263 +888,258 @@ class BeamAssembler : public ErrorHandler { * Note: xor clears ZF and CF; mov does not change any flags. */ a.xor_(to.r32(), to.r32()); - } else { - a.mov(to, imm(value)); } } -public: - void embed_rodata(const char *labelName, const char *buff, size_t size); - void embed_bss(const char *labelName, size_t size); - - void embed_zeros(size_t size); - - void setLogger(std::string log) { - FILE *f = fopen(log.data(), "w+"); - - /* FIXME: Don't crash when loading multiple modules with the same name. - * - * setLogger(nullptr) disables logging. */ - if (f) { - setvbuf(f, NULL, _IONBF, 0); - } - - setLogger(f); + void mov_imm(x86::Gp to, std::nullptr_t value) { + (void)value; + mov_imm(to, 0); } - void setLogger(FILE *log) { - logger.setFile(log); - logger.setIndentation(FormatIndentationGroup::kCode, 4); - code.setLogger(&logger); + template + void vmovups(Dst dst, Src src) { + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vmovups(dst, src); + } else { + a.movups(dst, src); + } } - template - void comment(const char *format, Ts... args) { - if (logger.file()) { - char buff[1024]; - erts_snprintf(buff, sizeof(buff), format, args...); - a.commentf("# %s", buff); + template + void vmovsd(Dst dst, Src src) { + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vmovsd(dst, src); + } else { + a.movsd(dst, src); } } - struct AsmRange { - ErtsCodePtr start; - ErtsCodePtr stop; - std::string name; - - /* Not used yet */ - std::string file; - unsigned line; - }; - - void update_gdb_jit_info(std::string modulename, - std::vector &functions); - - void embed(void *data, uint32_t size) { - a.embed((char *)data, size); + template + void vucomisd(Dst dst, Src src) { + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vucomisd(dst, src); + } else { + a.ucomisd(dst, src); + } } -}; -class BeamGlobalAssembler : public BeamAssembler { - typedef void (BeamGlobalAssembler::*emitFptr)(void); - typedef void (*fptr)(void); - - /* Please keep this in alphabetical order. */ -#define BEAM_GLOBAL_FUNCS(_) \ - _(arith_compare_shared) \ - _(arith_eq_shared) \ - _(bif_nif_epilogue) \ - _(bif_element_shared) \ - _(bif_export_trap) \ - _(bs_add_shared) \ - _(bs_size_check_shared) \ - _(bs_fixed_integer_shared) \ - _(bs_get_tail_shared) \ - _(call_bif_shared) \ - _(call_light_bif_shared) \ - _(call_nif_early) \ - _(call_nif_shared) \ - _(catch_end_shared) \ - _(dispatch_bif) \ - _(dispatch_nif) \ - _(dispatch_return) \ - _(dispatch_save_calls) \ - _(error_action_code) \ - _(export_trampoline) \ - _(garbage_collect) \ - _(generic_bp_global) \ - _(generic_bp_local) \ - _(debug_bp) \ - _(handle_error_shared_prologue) \ - _(handle_error_shared) \ - _(handle_element_error) \ - _(handle_hd_error) \ - _(i_band_body_shared) \ - _(i_band_guard_shared) \ - _(i_bif_body_shared) \ - _(i_bif_guard_shared) \ - _(i_bor_body_shared) \ - _(i_bor_guard_shared) \ - _(i_bnot_body_shared) \ - _(i_bnot_guard_shared) \ - _(i_bsl_guard_shared) \ - _(i_bsl_body_shared) \ - _(i_bsr_guard_shared) \ - _(i_bsr_body_shared) \ - _(i_bxor_body_shared) \ - _(i_bxor_guard_shared) \ - _(i_func_info_shared) \ - _(i_load_nif_shared) \ - _(i_length_guard_shared) \ - _(i_length_body_shared) \ - _(i_loop_rec_shared) \ - _(i_new_small_map_lit_shared) \ - _(i_test_yield_shared) \ - _(increment_body_shared) \ - _(int_div_rem_body_shared) \ - _(int_div_rem_guard_shared) \ - _(minus_body_shared) \ - _(minus_guard_shared) \ - _(new_map_shared) \ - _(plus_body_shared) \ - _(plus_guard_shared) \ - _(process_main) \ - _(times_body_shared) \ - _(times_guard_shared) \ - _(unary_minus_body_shared) \ - _(unary_minus_guard_shared) \ - _(update_map_assoc_shared) \ - _(update_map_exact_guard_shared) \ - _(update_map_exact_body_shared) - -/* Labels exported from within process_main */ -#define PROCESS_MAIN_LABELS(_) \ - _(context_switch) \ - _(context_switch_simplified) \ - _(do_schedule) - -#define DECL_ENUM(NAME) NAME, - - enum GlobalLabels : uint32_t { - BEAM_GLOBAL_FUNCS(DECL_ENUM) PROCESS_MAIN_LABELS(DECL_ENUM) - }; -#undef DECL_ENUM + /* Copies `count` words from `from` to `to`. + * + * Clobbers `spill` and the first vector register (xmm0, ymm0 etc). */ + void emit_copy_words(x86::Mem from, + x86::Mem to, + Sint32 count, + x86::Gp spill) { + ASSERT(!from.hasIndex() && !to.hasIndex()); + ASSERT(count >= 0 && count < (ERTS_SINT32_MAX / (Sint32)sizeof(UWord))); + ASSERT(from.offset() < ERTS_SINT32_MAX - count * (Sint32)sizeof(UWord)); + ASSERT(to.offset() < ERTS_SINT32_MAX - count * (Sint32)sizeof(UWord)); + + /* We're going to mix sizes pretty wildly below, so it's easiest to + * turn off size validation. */ + from.setSize(0); + to.setSize(0); + + using vectors = std::initializer_list>; + for (const auto &spec : vectors{{x86::zmm0, + 8, + x86::Inst::kIdVmovups, + CpuFeatures::X86::kAVX512_VL}, + {x86::zmm0, + 8, + x86::Inst::kIdVmovups, + CpuFeatures::X86::kAVX512_F}, + {x86::ymm0, + 4, + x86::Inst::kIdVmovups, + CpuFeatures::X86::kAVX}, + {x86::xmm0, + 2, + x86::Inst::kIdVmovups, + CpuFeatures::X86::kAVX}, + {x86::xmm0, + 2, + x86::Inst::kIdMovups, + CpuFeatures::X86::kSSE}}) { + const auto &[vector_reg, vector_size, vector_inst, feature] = spec; + + if (!hasCpuFeature(feature)) { + continue; + } - static const std::map emitPtrs; - static const std::map labelNames; - std::unordered_map labels; - std::unordered_map ptrs; + /* Copy the words inline if we can, otherwise use a loop with the + * largest vector size we're capable of. */ + if (count <= vector_size * 4) { + while (count >= vector_size) { + a.emit(vector_inst, vector_reg, from); + a.emit(vector_inst, to, vector_reg); + + from.addOffset(sizeof(UWord) * vector_size); + to.addOffset(sizeof(UWord) * vector_size); + count -= vector_size; + } + } else { + Sint32 loop_iterations, loop_size; + Label copy_next = a.newLabel(); -#define DECL_FUNC(NAME) void emit_##NAME(void); + loop_iterations = count / vector_size; + loop_size = loop_iterations * vector_size * sizeof(UWord); - BEAM_GLOBAL_FUNCS(DECL_FUNC); -#undef DECL_FUNC + from.addOffset(loop_size); + to.addOffset(loop_size); + from.setIndex(spill); + to.setIndex(spill); - template - void emit_bitwise_fallback_body(T(*func_ptr), const ErtsCodeMFA *mfa); + mov_imm(spill, -loop_size); + a.bind(copy_next); + { + a.emit(vector_inst, vector_reg, from); + a.emit(vector_inst, to, vector_reg); - template - void emit_bitwise_fallback_guard(T(*func_ptr)); + a.add(spill, imm(vector_size * sizeof(UWord))); + a.short_().jne(copy_next); + } - x86::Mem emit_i_length_common(Label fail, int state_size); + from.resetIndex(); + to.resetIndex(); - void emit_handle_error(); + count %= vector_size; + } + } -public: - BeamGlobalAssembler(JitAllocator *allocator); + if (count == 1) { + a.mov(spill, from); + a.mov(to, spill); - void (*get(GlobalLabels lbl))(void) { - ASSERT(ptrs[lbl]); - return ptrs[lbl]; - } + count -= 1; + } -#define GET_CODE(NAME) \ - void (*get_##NAME(void))() { \ - return get(NAME); \ + ASSERT(count == 0); + (void)count; } - - BEAM_GLOBAL_FUNCS(GET_CODE) - PROCESS_MAIN_LABELS(GET_CODE) -#undef GET_CODE }; -class BeamModuleAssembler : public BeamAssembler { - typedef unsigned BeamLabel; +#include "beam_asm_global.hpp" - /* Map of label number to asmjit Label */ - typedef std::unordered_map LabelMap; - LabelMap labels; +class BeamModuleAssembler : public BeamAssembler, + public BeamModuleAssemblerCommon { + BeamGlobalAssembler *ga; - struct patch { - Label where; - int64_t ptr_offs; - int64_t val_offs; - }; + /* Save the last PC for an error. */ + size_t last_error_offset = 0; - struct patch_catch { - struct patch patch; - Label handler; - }; - std::vector catches; + /* Skip unnecessary moves in mov_arg() and cmp_arg(). */ + size_t last_movarg_offset = 0; + x86::Gp last_movarg_from1, last_movarg_from2; + x86::Mem last_movarg_to1, last_movarg_to2; - /* Map of import entry to patch labels and mfa */ - struct patch_import { - std::vector patches; - ErtsCodeMFA mfa; - }; - typedef std::unordered_map ImportMap; - ImportMap imports; + /* Private helper. */ + void preserve__cache(x86::Gp dst) { + last_movarg_offset = a.offset(); + invalidate_cache(dst); + } - /* Map of fun entry to patch labels */ - struct patch_lambda { - std::vector patches; - ErlFunEntry fe; - }; - typedef std::unordered_map LambdaMap; - LambdaMap lambdas; + bool is_cache_valid() { + return a.offset() == last_movarg_offset; + } - /* Map of literals to patch labels */ - struct patch_literal { - std::vector patches; - }; - typedef std::unordered_map LiteralMap; - LiteralMap literals; + void preserve_cache(x86::Gp dst, bool cache_valid) { + if (cache_valid) { + preserve__cache(dst); + } + } - /* All string patches */ - std::vector strings; + /* Store CPU register into memory and update the cache. */ + void store_cache(x86::Gp src, x86::Mem dst) { + if (is_cache_valid() && dst != last_movarg_to1) { + /* Something is already cached in the first slot. Use the + * second slot. */ + a.mov(dst, src); - /* All functions that have been seen so far */ - std::vector functions; + last_movarg_offset = a.offset(); + last_movarg_to2 = dst; + last_movarg_from2 = src; + } else { + /* Nothing cached yet, or the first slot has the same + * memory address as we will store into. Use the first + * slot and invalidate the second slot. */ + a.mov(dst, src); - BeamGlobalAssembler *ga; + last_movarg_offset = a.offset(); + last_movarg_to1 = dst; + last_movarg_from1 = src; - /* Used by emit to populate the labelToMFA map */ - Label currLabel; - unsigned prev_op = 0; - Label codeHeader; - Label funcInfo; - Label funcYield; - Label genericBPTramp; - Label on_load; + last_movarg_to2 = x86::Mem(); + } + } - Label floatMax; - Label floatSignMask; + void invalidate_cache(x86::Gp dst) { + if (dst == last_movarg_from1) { + last_movarg_to1 = x86::Mem(); + last_movarg_from1 = x86::Gp(); + } + if (dst == last_movarg_from2) { + last_movarg_to2 = x86::Mem(); + last_movarg_from2 = x86::Gp(); + } + } - Eterm mod; + x86::Gp cached_reg(x86::Mem mem) { + if (is_cache_valid()) { + if (mem == last_movarg_to1) { + return last_movarg_from1; + } + if (mem == last_movarg_to2) { + return last_movarg_from2; + } + } + return x86::Gp(); + } + + void load_cached(x86::Gp dst, x86::Mem mem) { + if (a.offset() == last_movarg_offset) { + x86::Gp reg = cached_reg(mem); + + if (reg.isValid()) { + /* This memory location is cached. */ + if (reg != dst) { + comment("simplified fetching of BEAM register"); + a.mov(dst, reg); + preserve__cache(dst); + } else { + comment("skipped fetching of BEAM register"); + invalidate_cache(dst); + } + } else { + /* Not cached. Load and preserve the cache. */ + a.mov(dst, mem); + preserve__cache(dst); + } + } else { + /* The cache is invalid. */ + a.mov(dst, mem); + } + } - /* Save the last PC for an error. */ - size_t last_error_offset = 0; + /* Maps code pointers to thunks that jump to them, letting us treat global + * fragments as if they were local. */ + std::unordered_map _dispatchTable; public: BeamModuleAssembler(BeamGlobalAssembler *ga, Eterm mod, - unsigned num_labels); + int num_labels, + const BeamFile *file = NULL); BeamModuleAssembler(BeamGlobalAssembler *ga, Eterm mod, - unsigned num_labels, - unsigned num_functions); + int num_labels, + int num_functions, + const BeamFile *file = NULL); - bool emit(unsigned op, const std::vector &args); + bool emit(unsigned op, const Span &args); void codegen(JitAllocator *allocator, const void **executable_ptr, @@ -1096,7 +1154,11 @@ class BeamModuleAssembler : public BeamAssembler { void codegen(char *buff, size_t len); + void register_metadata(const BeamCodeHeader *header); + ErtsCodePtr getCode(unsigned label); + ErtsCodePtr getLambda(unsigned index); + void *getCode(Label label) { return BeamAssembler::getCode(label); } @@ -1104,7 +1166,7 @@ class BeamModuleAssembler : public BeamAssembler { return BeamAssembler::getCode(labelName); } - Label embed_vararg_rodata(const std::vector &args, int y_offset); + Label embed_vararg_rodata(const Span &args, int y_offset); unsigned getCodeSize() { ASSERT(code.hasBaseAddress()); @@ -1116,81 +1178,153 @@ class BeamModuleAssembler : public BeamAssembler { const ErtsCodeInfo *getOnLoad(void); unsigned patchCatches(char *rw_base); - void patchLambda(char *rw_base, unsigned index, BeamInstr I); + void patchLambda(char *rw_base, unsigned index, const ErlFunEntry *fe); void patchLiteral(char *rw_base, unsigned index, Eterm lit); - void patchImport(char *rw_base, unsigned index, BeamInstr I); + void patchImport(char *rw_base, unsigned index, const Export *import); void patchStrings(char *rw_base, const byte *string); protected: - /* Helpers */ - void emit_gc_test(const ArgVal &Stack, - const ArgVal &Heap, - const ArgVal &Live); - void emit_gc_test_preserve(const ArgVal &Need, - const ArgVal &Live, - x86::Gp term); + void emit_gc_test(const ArgWord &Stack, + const ArgWord &Heap, + const ArgWord &Live); + void emit_gc_test_preserve(const ArgWord &Need, + const ArgWord &Live, + const ArgSource &Preserve, + x86::Gp preserve_reg); x86::Mem emit_variable_apply(bool includeI); - x86::Mem emit_fixed_apply(const ArgVal &arity, bool includeI); + x86::Mem emit_fixed_apply(const ArgWord &arity, bool includeI); - x86::Gp emit_call_fun(const ArgVal &Fun); - x86::Gp emit_apply_fun(void); + x86::Gp emit_call_fun(bool skip_box_test = false, + bool skip_fun_test = false, + bool skip_arity_test = false); - void emit_is_binary(Label Fail, x86::Gp Src, Label next, Label subbin); + void emit_is_boxed(Label Fail, x86::Gp Src, Distance dist = dLong) { + BeamAssembler::emit_is_boxed(Fail, Src, dist); + } + + void emit_is_boxed(Label Fail, + const ArgVal &Arg, + x86::Gp Src, + Distance dist = dLong) { + if (always_one_of(Arg)) { + comment("skipped box test since argument is always boxed"); + return; + } + + BeamAssembler::emit_is_boxed(Fail, Src, dist); + } void emit_get_list(const x86::Gp boxed_ptr, - const ArgVal &Hd, - const ArgVal &Tl); + const ArgRegister &Hd, + const ArgRegister &Tl); - void emit_div_rem(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ErtsCodeMFA *error_mfa); + void emit_div_rem(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ErtsCodeMFA *error_mfa, + bool need_div = true, + bool need_rem = true); void emit_setup_guard_bif(const std::vector &args, - const ArgVal &bif); + const ArgWord &bif); - void emit_bif_arg_error(std::vector args, const ErtsCodeMFA *mfa); void emit_error(int code); - x86::Mem emit_bs_get_integer_prologue(Label next, - Label fail, - int flags, - int size); + void emit_bs_get_integer(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgWord Flags, + int bits, + const ArgRegister &Dst); - int emit_bs_get_field_size(const ArgVal &Size, + int emit_bs_get_field_size(const ArgSource &Size, int unit, Label Fail, const x86::Gp &out, unsigned max_size = 0); - void emit_bs_get_utf8(const ArgVal &Ctx, const ArgVal &Fail); - void emit_bs_get_utf16(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Flags); - - void emit_handle_error(); - void emit_handle_error(const ErtsCodeMFA *exp); - void emit_handle_error(Label I, const ErtsCodeMFA *exp); - void emit_validate(const ArgVal &arity); - void emit_bs_skip_bits(const ArgVal &Fail, const ArgVal &Ctx); + void emit_bs_get_utf8(const ArgRegister &Ctx, const ArgLabel &Fail); + void emit_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags); + void update_bin_state(x86::Gp bin_offset, + x86::Gp current_byte, + Sint bit_offset, + Sint size, + x86::Gp size_reg); + bool need_mask(const ArgVal Val, Sint size); + void set_zero(Sint effectiveSize); + bool bs_maybe_enter_runtime(bool entered); + void bs_maybe_leave_runtime(bool entered); + void emit_construct_utf8_shared(); + void emit_construct_utf8(const ArgVal &Src, + Sint bit_offset, + bool is_byte_aligned); + + void emit_read_bits(Uint bits, + const x86::Gp bin_base, + const x86::Gp bin_offset, + const x86::Gp bitdata); + void emit_extract_integer(const x86::Gp bitdata, + const x86::Gp tmp, + Uint flags, + Uint bits, + const ArgRegister &Dst); + void emit_extract_binary(const x86::Gp bitdata, + Uint bits, + const ArgRegister &Dst); + void emit_read_integer(const x86::Gp bin_base, + const x86::Gp bin_position, + const x86::Gp tmp, + Uint flags, + Uint bits, + const ArgRegister &Dst); + + UWord bs_get_flags(const ArgVal &val); + + void emit_raise_exception(); + void emit_raise_exception(const ErtsCodeMFA *exp); + void emit_raise_exception(Label I, const ErtsCodeMFA *exp); + void emit_raise_exception(x86::Gp I, const ErtsCodeMFA *exp); + + void emit_validate(const ArgWord &arity); + void emit_bs_skip_bits(const ArgLabel &Fail, const ArgRegister &Ctx); void emit_linear_search(x86::Gp val, const ArgVal &Fail, - const std::vector &args); + const Span &args); - void emit_check_float(Label next, x86::Xmm value); + void emit_float_instr(uint32_t instIdSSE, + uint32_t instIdAVX, + const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst); - void emit_is_small(Label fail, x86::Gp Reg); - void emit_is_both_small(Label fail, x86::Gp A, x86::Gp B); + void emit_is_small(Label fail, const ArgSource &Arg, x86::Gp Reg); + void emit_are_both_small(Label fail, + const ArgSource &LHS, + x86::Gp A, + const ArgSource &RHS, + x86::Gp B); void emit_validate_unicode(Label next, Label fail, x86::Gp value); - void emit_bif_is_eq_ne_exact_immed(const ArgVal &Src, - const ArgVal &Immed, - const ArgVal &Dst, - Eterm fail_value, - Eterm succ_value); + void emit_bif_is_eq_ne_exact(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst, + Eterm fail_value, + Eterm succ_value); + + void emit_cond_to_bool(uint32_t instId, const ArgRegister &Dst); + void emit_bif_is_ge_lt(uint32_t instId, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst); + void emit_bif_min_max(uint32_t instId, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst); void emit_proc_lc_unrequire(void); void emit_proc_lc_require(void); @@ -1201,20 +1335,42 @@ class BeamModuleAssembler : public BeamAssembler { void emit_binsearch_nodes(size_t Left, size_t Right, const ArgVal &Fail, - const std::vector &args); + const Span &args); bool emit_optimized_three_way_select(const ArgVal &Fail, - const std::vector &args); + const Span &args); #ifdef DEBUG - void emit_tuple_assertion(const ArgVal &Src, x86::Gp tuple_reg); + void emit_tuple_assertion(const ArgSource &Src, x86::Gp tuple_reg); #endif #include "beamasm_protos.h" + const Label &resolve_beam_label(const ArgLabel &Lbl) const { + return rawLabels.at(Lbl.get()); + } + + /* Resolves a shared fragment, creating a trampoline that loads the + * appropriate address before jumping there. */ + const Label &resolve_fragment(void (*fragment)()); + + void safe_fragment_call(void (*fragment)()) { + emit_assert_redzone_unused(); + a.call(resolve_fragment(fragment)); + } + + template + void aligned_call(FuncPtr(*target)) { + BeamAssembler::aligned_call(resolve_fragment(target)); + } + + void aligned_call(Label target) { + BeamAssembler::aligned_call(target); + } + void make_move_patch(x86::Gp to, std::vector &patches, - int64_t offset = 0) { + size_t offset = 0) { const int MOV_IMM64_PAYLOAD_OFFSET = 2; Label lbl = a.newLabel(); @@ -1250,42 +1406,115 @@ class BeamModuleAssembler : public BeamAssembler { } void cmp_arg(x86::Mem mem, const ArgVal &val, const x86::Gp &spill) { - /* Note that the cast to Sint is necessary to handle negative numbers - * such as NIL. */ - if (val.isImmed() && Support::isInt32((Sint)val.getValue())) { - a.cmp(mem, imm(val.getValue())); + x86::Gp reg = cached_reg(mem); + + if (reg.isValid()) { + /* Note that the cast to Sint is necessary to handle + * negative numbers such as NIL. */ + if (val.isImmed() && + Support::isInt32((Sint)val.as().get())) { + comment("simplified compare of BEAM register"); + a.cmp(reg, imm(val.as().get())); + } else if (reg != spill) { + comment("simplified compare of BEAM register"); + mov_arg(spill, val); + a.cmp(reg, spill); + } else { + mov_arg(spill, val); + a.cmp(mem, spill); + } } else { - mov_arg(spill, val); - a.cmp(mem, spill); + /* Note that the cast to Sint is necessary to handle + * negative numbers such as NIL. */ + if (val.isImmed() && + Support::isInt32((Sint)val.as().get())) { + a.cmp(mem, imm(val.as().get())); + } else { + mov_arg(spill, val); + a.cmp(mem, spill); + } } } void cmp_arg(x86::Gp gp, const ArgVal &val, const x86::Gp &spill) { - if (val.isImmed() && Support::isInt32((Sint)val.getValue())) { - a.cmp(gp, imm(val.getValue())); + if (val.isImmed() && Support::isInt32((Sint)val.as().get())) { + a.cmp(gp, imm(val.as().get())); } else { mov_arg(spill, val); a.cmp(gp, spill); } } + void cmp(x86::Gp gp, int64_t val, const x86::Gp &spill) { + if (Support::isInt32(val)) { + a.cmp(gp, imm(val)); + } else if (gp.isGpd()) { + mov_imm(spill, val); + a.cmp(gp, spill.r32()); + } else { + mov_imm(spill, val); + a.cmp(gp, spill); + } + } + + void sub(x86::Gp gp, int64_t val, const x86::Gp &spill) { + if (Support::isInt32(val)) { + a.sub(gp, imm(val)); + } else { + mov_imm(spill, val); + a.sub(gp, spill); + } + } + /* Note: May clear flags. */ void mov_arg(x86::Gp to, const ArgVal &from, const x86::Gp &spill) { - if (from.isMem()) { - a.mov(to, getArgRef(from)); + bool valid_cache = is_cache_valid(); + + if (from.isBytePtr()) { + make_move_patch(to, strings, from.as().get()); + } else if (from.isExport()) { + make_move_patch(to, imports[from.as().get()].patches); + } else if (from.isImmed()) { + mov_imm(to, from.as().get()); + } else if (from.isLambda()) { + make_move_patch(to, lambdas[from.as().get()].patches); } else if (from.isLiteral()) { - make_move_patch(to, literals[from.getValue()].patches); + make_move_patch(to, literals[from.as().get()].patches); + } else if (from.isRegister()) { + auto mem = getArgRef(from.as()); + load_cached(to, mem); + } else if (from.isWord()) { + mov_imm(to, from.as().get()); } else { - mov_imm(to, from.getValue()); + ASSERT(!"mov_arg with incompatible type"); } + + preserve_cache(to, valid_cache); +#ifdef DEBUG + /* Explicitly clear flags to catch bugs quicker, it may be very rare + * for a certain instruction to load values that would otherwise cause + * flags to be cleared. */ + a.test(to, to); +#endif } void mov_arg(x86::Mem to, const ArgVal &from, const x86::Gp &spill) { if (from.isImmed()) { - if (Support::isInt32((Sint)from.getValue())) { - a.mov(to, imm(from.getValue())); + auto val = from.as().get(); + + if (Support::isInt32((Sint)val)) { + a.mov(to, imm(val)); } else { - a.mov(spill, imm(from.getValue())); + a.mov(spill, imm(val)); + a.mov(to, spill); + } + } else if (from.isWord()) { + auto val = from.as().get(); + + if (Support::isInt32((Sint)val)) { + a.mov(to, imm(val)); + } else { + a.mov(spill, imm(val)); a.mov(to, spill); } } else { @@ -1297,7 +1526,13 @@ class BeamModuleAssembler : public BeamAssembler { void mov_arg(const ArgVal &to, x86::Gp from, const x86::Gp &spill) { (void)spill; - a.mov(getArgRef(to), from); + auto mem = getArgRef(to); + store_cache(from, mem); + } + + void mov_arg(const ArgVal &to, x86::Mem from, const x86::Gp &spill) { + a.mov(spill, from); + a.mov(getArgRef(to), spill); } void mov_arg(const ArgVal &to, BeamInstr from, const x86::Gp &spill) { @@ -1310,7 +1545,7 @@ class BeamModuleAssembler : public BeamAssembler { } void mov_arg(const ArgVal &to, const ArgVal &from, const x86::Gp &spill) { - if (from.isMem()) { + if (from.isRegister()) { mov_arg(spill, from); mov_arg(to, spill); } else { @@ -1319,5 +1554,9 @@ class BeamModuleAssembler : public BeamAssembler { } }; -void beamasm_update_perf_info(std::string modulename, - std::vector &ranges); +void beamasm_metadata_update(std::string module_name, + ErtsCodePtr base_address, + size_t code_size, + const std::vector &ranges); +void beamasm_metadata_early_init(); +void beamasm_metadata_late_init(); diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.cpp b/erts/emulator/beam/jit/x86/beam_asm_global.cpp index f66d83e5df5d..7fdfddf27621 100644 --- a/erts/emulator/beam/jit/x86/beam_asm_global.cpp +++ b/erts/emulator/beam/jit/x86/beam_asm_global.cpp @@ -18,7 +18,9 @@ * %CopyrightEnd% */ +#define ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS #include "beam_asm.hpp" +#undef ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS using namespace asmjit; @@ -28,21 +30,6 @@ extern "C" #include "beam_common.h" } -#define STRINGIFY_(X) #X -#define STRINGIFY(X) STRINGIFY_(X) - -#define DECL_EMIT(NAME) {NAME, &BeamGlobalAssembler::emit_##NAME}, -const std::map - BeamGlobalAssembler::emitPtrs = {BEAM_GLOBAL_FUNCS(DECL_EMIT)}; -#undef DECL_EMIT - -#define DECL_LABEL_NAME(NAME) {NAME, STRINGIFY(NAME)}, - -const std::map - BeamGlobalAssembler::labelNames = {BEAM_GLOBAL_FUNCS( - DECL_LABEL_NAME) PROCESS_MAIN_LABELS(DECL_LABEL_NAME)}; -#undef DECL_LABEL_NAME - BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) : BeamAssembler("beam_asm_global") { labels.reserve(emitPtrs.size()); @@ -64,11 +51,13 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) } { - /* We have no need of the module pointers as we use `getCode(...)` for - * everything. */ - const void *_ignored_exec; - void *_ignored_rw; - _codegen(allocator, &_ignored_exec, &_ignored_rw); + const void *executable_region; + void *writable_region; + + BeamAssembler::codegen(allocator, &executable_region, &writable_region); + VirtMem::flushInstructionCache((void *)executable_region, + code.codeSize()); + VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute); } #ifndef WIN32 @@ -91,8 +80,10 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) .name = code.labelEntry(labels[val.first])->name()}); } - update_gdb_jit_info("global", ranges); - beamasm_update_perf_info("global", ranges); + beamasm_metadata_update("global", + (ErtsCodePtr)getBaseAddress(), + code.codeSize(), + ranges); #endif /* `this->get_xxx` are populated last to ensure that we crash if we use them @@ -103,33 +94,31 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) } } -void BeamGlobalAssembler::emit_handle_error() { - /* Move return address into ARG2 so we know where we crashed. - * - * This bluntly assumes that we haven't pushed anything to the (Erlang) - * stack in the fragments that jump here. */ - -#ifdef NATIVE_ERLANG_STACK - a.mov(ARG2, x86::qword_ptr(E)); -#else - a.pop(ARG2); -#endif - a.jmp(labels[handle_error_shared]); -} - -/* ARG3 = (HTOP + bytes needed) !! +/* ARG3 = (HTOP + S_RESERVED + bytes needed) !! * ARG4 = Live registers */ void BeamGlobalAssembler::emit_garbage_collect() { Label exiting = a.newLabel(); - /* Convert ARG3 to words needed and move it to the correct argument slot */ + emit_enter_frame(); + + /* Convert ARG3 to words needed and move it to the correct argument slot. + * + * Note that we cancel out the S_RESERVED that we added in the GC check, as + * the GC routines handle that separately and we don't want it to be added + * twice. */ a.sub(ARG3, HTOP); a.shr(ARG3, imm(3)); - a.mov(ARG2, ARG3); + a.lea(ARG2, x86::qword_ptr(ARG3, -S_RESERVED)); /* Save our return address in c_p->i so we can tell where we crashed if we * do so during GC. */ - a.mov(RET, x86::qword_ptr(x86::rsp)); + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + a.mov(RET, x86::qword_ptr(x86::rsp)); + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + a.mov(RET, x86::qword_ptr(x86::rsp, 8)); + } + a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), RET); emit_enter_runtime(); @@ -150,10 +139,11 @@ void BeamGlobalAssembler::emit_garbage_collect() { a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); a.short_().jne(exiting); + emit_leave_frame(); a.ret(); a.bind(exiting); - emit_discard_cp(); + emit_unwind_frame(); a.jmp(labels[do_schedule]); } @@ -163,12 +153,11 @@ void BeamGlobalAssembler::emit_garbage_collect() { * * Assumes that c_p->current points into the MFA of an export entry. */ void BeamGlobalAssembler::emit_bif_export_trap() { - int export_offset = offsetof(Export, info.mfa); - a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, current))); - a.sub(RET, export_offset); + a.sub(RET, imm(offsetof(Export, info.mfa))); - a.jmp(emit_setup_export_call(RET)); + emit_leave_frame(); + a.jmp(emit_setup_dispatchable_call(RET)); } /* Handles export breakpoints, error handler, jump tracing, and so on. @@ -196,6 +185,7 @@ void BeamGlobalAssembler::emit_export_trampoline() { a.je(jump_trace); /* Must never happen. */ + comment("Unexpected export trampoline op"); a.ud2(); a.bind(call_bif); @@ -211,6 +201,7 @@ void BeamGlobalAssembler::emit_export_trampoline() { a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, i))); a.mov(ARG4, x86::qword_ptr(RET, func_offset)); + emit_enter_frame(); a.jmp(labels[call_bif_shared]); } @@ -219,8 +210,8 @@ void BeamGlobalAssembler::emit_export_trampoline() { a.bind(error_handler); { - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); a.lea(ARG2, x86::qword_ptr(RET, offsetof(Export, info.mfa))); @@ -228,12 +219,13 @@ void BeamGlobalAssembler::emit_export_trampoline() { mov_imm(ARG4, am_undefined_function); runtime_call<4>(call_error_handler); - emit_leave_runtime(); + emit_leave_runtime(); a.test(RET, RET); - a.je(labels[error_action_code]); - a.jmp(emit_setup_export_call(RET)); + a.je(labels[process_exit]); + + emit_leave_frame(); + a.jmp(emit_setup_dispatchable_call(RET)); } } @@ -241,64 +233,97 @@ void BeamGlobalAssembler::emit_export_trampoline() { * Get the error address implicitly by calling the shared fragment and using * the return address as the error address. */ -void BeamModuleAssembler::emit_handle_error() { - emit_handle_error(nullptr); +void BeamModuleAssembler::emit_raise_exception() { + emit_raise_exception(nullptr); } -void BeamModuleAssembler::emit_handle_error(const ErtsCodeMFA *exp) { - mov_imm(ARG4, (Uint)exp); - safe_fragment_call(ga->get_handle_error_shared_prologue()); - - /* - * It is important that error address is not equal to a line - * instruction that may follow this BEAM instruction. To avoid - * that, BeamModuleAssembler::emit() will emit a nop instruction - * if necessary. - */ - last_error_offset = getOffset() & -8; +void BeamModuleAssembler::emit_raise_exception(const ErtsCodeMFA *exp) { + mov_imm(ARG4, exp); + safe_fragment_call(ga->get_raise_exception()); + + /* `line` instructions need to know the latest offset that may throw an + * exception. See the `line` instruction for details. */ + last_error_offset = a.offset(); } -void BeamModuleAssembler::emit_handle_error(Label I, const ErtsCodeMFA *exp) { +void BeamModuleAssembler::emit_raise_exception(Label I, + const ErtsCodeMFA *exp) { a.lea(ARG2, x86::qword_ptr(I)); - mov_imm(ARG4, (Uint)exp); + emit_raise_exception(ARG2, exp); +} + +void BeamModuleAssembler::emit_raise_exception(x86::Gp I, + const ErtsCodeMFA *exp) { + if (I != ARG2) { + a.mov(ARG2, I); + } + + mov_imm(ARG4, exp); #ifdef NATIVE_ERLANG_STACK /* The CP must be reserved for try/catch to work, so we'll fake a call with * the return address set to the error address. */ a.push(ARG2); + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { +# ifdef ERLANG_FRAME_POINTERS + a.push(frame_pointer); +# endif + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); + } #endif - abs_jmp(ga->get_handle_error_shared()); + a.jmp(resolve_fragment(ga->get_raise_exception_shared())); } -/* This is an alias for handle_error */ -void BeamGlobalAssembler::emit_error_action_code() { +void BeamGlobalAssembler::emit_process_exit() { + emit_enter_runtime(); + + a.mov(ARG1, c_p); mov_imm(ARG2, 0); mov_imm(ARG4, 0); + load_x_reg_array(ARG3); + runtime_call<4>(handle_error); - a.jmp(labels[handle_error_shared]); + emit_leave_runtime(); + + a.test(RET, RET); + a.je(labels[do_schedule]); + comment("End of process"); + a.ud2(); } -void BeamGlobalAssembler::emit_handle_error_shared_prologue() { - /* - * We must align the return address to make it a proper tagged CP. - * This is safe because we will never actually return to the - * return address. - */ +/* Helper function for throwing exceptions from global fragments. + * + * Assumes that the next item on the _machine stack_ is a return address: we + * must not jump here while in a frame. */ +void BeamGlobalAssembler::emit_raise_exception() { + /* We must align the return address to make it a proper tagged CP, in case + * we were called with `safe_fragment_call`. This is safe because we will + * never actually return to the return address. */ a.pop(ARG2); - a.and_(ARG2, imm(-8)); + a.and_(ARG2, imm(~_CPMASK)); #ifdef NATIVE_ERLANG_STACK a.push(ARG2); + + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { +# ifdef ERLANG_FRAME_POINTERS + a.push(frame_pointer); +# endif + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); + } #endif - a.jmp(labels[handle_error_shared]); + a.jmp(labels[raise_exception_shared]); } -void BeamGlobalAssembler::emit_handle_error_shared() { +void BeamGlobalAssembler::emit_raise_exception_shared() { Label crash = a.newLabel(); - emit_enter_runtime(); + emit_enter_runtime(); /* The error address must be a valid CP or NULL. */ a.test(ARG2d, imm(_CPMASK)); @@ -309,7 +334,7 @@ void BeamGlobalAssembler::emit_handle_error_shared() { load_x_reg_array(ARG3); runtime_call<4>(handle_error); - emit_leave_runtime(); + emit_leave_runtime(); a.test(RET, RET); a.je(labels[do_schedule]); @@ -317,6 +342,7 @@ void BeamGlobalAssembler::emit_handle_error_shared() { a.jmp(RET); a.bind(crash); + comment("Error address is not a CP or NULL or ARG2 and ARG4 are unset"); a.ud2(); } diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl new file mode 100755 index 000000000000..af16da1eeede --- /dev/null +++ b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl @@ -0,0 +1,216 @@ +#!/usr/bin/env perl -W +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2022-2023. 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% +# +use strict; + +# Please keep the names in the list in alphabetical order. +my @beam_global_funcs = qw( + apply_fun_shared + arith_compare_shared + arith_eq_shared + bif_nif_epilogue + bif_element_shared + bif_export_trap + bs_add_shared + bs_create_bin_error_shared + bs_size_check_shared + bs_get_tail_shared + bs_get_utf8_shared + bs_get_utf8_short_shared + call_bif_shared + call_light_bif_shared + call_nif_early + call_nif_shared + call_nif_yield_helper + catch_end_shared + check_float_error + construct_utf8_shared + dispatch_bif + dispatch_nif + dispatch_return + dispatch_save_calls_export + dispatch_save_calls_fun + export_trampoline + garbage_collect + generic_bp_global + generic_bp_local + get_sint64_shared + debug_bp + fconv_shared + handle_call_fun_error + handle_element_error + handle_hd_error + handle_map_get_badkey + handle_map_get_badmap + handle_map_size_error + handle_node_error + i_band_body_shared + i_band_guard_shared + i_bif_body_shared + i_bif_guard_shared + i_bor_body_shared + i_bor_guard_shared + i_bnot_body_shared + i_bnot_guard_shared + i_breakpoint_trampoline_shared + i_bsl_guard_shared + i_bsl_body_shared + i_bsr_guard_shared + i_bsr_body_shared + i_bxor_body_shared + i_bxor_guard_shared + i_func_info_shared + i_get_map_element_shared + i_get_map_element_hash_shared + i_load_nif_shared + i_length_guard_shared + i_length_body_shared + i_loop_rec_shared + i_test_yield_shared + int_div_rem_body_shared + int_div_rem_guard_shared + is_in_range_shared + is_ge_lt_shared + internal_hash_helper + minus_body_shared + minus_guard_shared + new_map_shared + plus_body_shared + plus_guard_shared + process_exit + process_main + raise_exception + raise_exception_shared + store_unaligned + times_body_shared + times_guard_shared + unary_minus_body_shared + unary_minus_guard_shared + unloaded_fun + update_map_assoc_shared + update_map_exact_guard_shared + update_map_exact_body_shared + ); + +# Labels exported from within process_main +my @process_main_labels = qw( + context_switch + context_switch_simplified + do_schedule + ); + +my $decl_enums = + gen_list(' %s,', @beam_global_funcs, '', @process_main_labels); + +my $decl_emit_funcs = + gen_list(' void emit_%s(void);', @beam_global_funcs); + +my $decl_get_funcs = + gen_list(' void (*get_%s(void))() { return get(%s); }', + @beam_global_funcs, '', @process_main_labels); + +my $decl_emitPtrs = + gen_list(' {%s, &BeamGlobalAssembler::emit_%s},', @beam_global_funcs); + +my $decl_label_names = + gen_list(' {%s, "%s"},', @beam_global_funcs, '', @process_main_labels); + +sub gen_list { + my ($format, @strings) = @_; + my $out = ''; + foreach my $str (@strings) { + if ($str eq '') { + $out .= "\n"; + } + else { + my $subst = $format; + $subst =~ s/%s/$str/g; + $out .= "$subst\n"; + } + } + $out; +} + + +my $this_source_file = __FILE__; + +print < labelNames; + static const std::map emitPtrs; + std::unordered_map labels; + std::unordered_map ptrs; + +$decl_emit_funcs + + template + void emit_bitwise_fallback_body(T(*func_ptr), const ErtsCodeMFA *mfa); + + template + void emit_bitwise_fallback_guard(T(*func_ptr)); + + x86::Mem emit_i_length_common(Label fail, int state_size); + + void emit_flatmap_get_element(); + void emit_hashmap_get_element(); + +public: + BeamGlobalAssembler(JitAllocator *allocator); + + void (*get(GlobalLabels lbl))(void) { + ASSERT(ptrs[lbl]); + return ptrs[lbl]; + } + +$decl_get_funcs +}; + +#ifdef ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS + +const std::map +BeamGlobalAssembler::emitPtrs = { +$decl_emitPtrs +}; + +const std::map +BeamGlobalAssembler::labelNames = { +$decl_label_names +}; + +#endif /* ERTS_BEAM_ASM_GLOBAL_WANT_STATIC_DEFS */ + +#endif /* !_BEAM_ASM_GLOBAL_HPP */ +END_OF_FILE diff --git a/erts/emulator/beam/jit/x86/beam_asm_module.cpp b/erts/emulator/beam/jit/x86/beam_asm_module.cpp index bada1c8395aa..bc8a11e15ebc 100644 --- a/erts/emulator/beam/jit/x86/beam_asm_module.cpp +++ b/erts/emulator/beam/jit/x86/beam_asm_module.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -24,11 +24,6 @@ #include "beam_asm.hpp" using namespace asmjit; -static std::string getAtom(Eterm atom) { - Atom *ap = atom_tab(atom_val(atom)); - return std::string((char *)ap->name, ap->len); -} - #ifdef BEAMASM_DUMP_SIZES # include @@ -67,127 +62,31 @@ extern "C" void beamasm_dump_sizes() { } #endif -BeamModuleAssembler::BeamModuleAssembler(BeamGlobalAssembler *ga, - Eterm mod, - unsigned num_labels) - : BeamAssembler(getAtom(mod)) { - this->ga = ga; - this->mod = mod; - - labels.reserve(num_labels + 1); - for (unsigned i = 1; i < num_labels; i++) { - Label lbl; - -#ifdef DEBUG - std::string lblName = "label_" + std::to_string(i); - lbl = a.newNamedLabel(lblName.data()); -#else - lbl = a.newLabel(); -#endif +ErtsCodePtr BeamModuleAssembler::getCode(BeamLabel label) { + ASSERT(label < rawLabels.size() + 1); + return (ErtsCodePtr)getCode(rawLabels[label]); +} - labels[i] = lbl; - } +ErtsCodePtr BeamModuleAssembler::getLambda(unsigned index) { + const auto &lambda = lambdas[index]; + return (ErtsCodePtr)getCode(lambda.trampoline); } BeamModuleAssembler::BeamModuleAssembler(BeamGlobalAssembler *ga, Eterm mod, - unsigned num_labels, - unsigned num_functions) - : BeamModuleAssembler(ga, mod, num_labels) { - codeHeader = a.newLabel(); + int num_labels, + int num_functions, + const BeamFile *file) + : BeamModuleAssembler(ga, mod, num_labels, file) { + code_header = a.newLabel(); a.align(AlignMode::kCode, 8); - a.bind(codeHeader); + a.bind(code_header); embed_zeros(sizeof(BeamCodeHeader) + sizeof(ErtsCodeInfo *) * num_functions); - - floatMax = a.newLabel(); - a.align(AlignMode::kCode, 8); - a.bind(floatMax); - double max = DBL_MAX; - a.embed((char *)&max, sizeof(double)); - - floatSignMask = a.newLabel(); - a.align(AlignMode::kCode, 16); /* 128-bit aligned */ - a.bind(floatSignMask); - uint64_t signMask = 0x7FFFFFFFFFFFFFFFul; - a.embed((char *)&signMask, sizeof(double)); - - /* Shared trampoline for function_clause errors, which can't jump straight - * to `i_func_info_shared` due to size restrictions. */ - funcInfo = a.newLabel(); - a.align(AlignMode::kCode, 8); - a.bind(funcInfo); - abs_jmp(ga->get_i_func_info_shared()); - - /* Shared trampoline for yielding on function ingress. */ - funcYield = a.newLabel(); - a.align(AlignMode::kCode, 8); - a.bind(funcYield); - abs_jmp(ga->get_i_test_yield_shared()); - - /* Setup the early_nif/breakpoint trampoline. */ - genericBPTramp = a.newLabel(); - a.align(AlignMode::kCode, 16); - a.bind(genericBPTramp); - { - a.ret(); - - a.align(AlignMode::kCode, 16); - abs_jmp(ga->get_call_nif_early()); - - a.align(AlignMode::kCode, 16); - aligned_call(ga->get_generic_bp_local()); - a.ret(); - - a.align(AlignMode::kCode, 16); - ASSERT(a.offset() - code.labelOffsetFromBase(genericBPTramp) == 16 * 3); - aligned_call(ga->get_generic_bp_local()); - abs_jmp(ga->get_call_nif_early()); - } -} - -ErtsCodePtr BeamModuleAssembler::getCode(unsigned label) { - ASSERT(label < labels.size() + 1); - return (ErtsCodePtr)getCode(labels[label]); -} - -void BeamAssembler::embed_rodata(const char *labelName, - const char *buff, - size_t size) { - Label label = a.newNamedLabel(labelName); - - a.section(rodata); - a.bind(label); - a.embed(buff, size); - a.section(code.textSection()); -} - -void BeamAssembler::embed_bss(const char *labelName, size_t size) { - Label label = a.newNamedLabel(labelName); - - /* Reuse rodata section for now */ - a.section(rodata); - a.bind(label); - embed_zeros(size); - a.section(code.textSection()); } -void BeamAssembler::embed_zeros(size_t size) { - static constexpr size_t buf_size = 16384; - static const char zeros[buf_size] = {}; - - while (size >= buf_size) { - a.embed(zeros, buf_size); - size -= buf_size; - } - - if (size > 0) { - a.embed(zeros, size); - } -} - -Label BeamModuleAssembler::embed_vararg_rodata(const std::vector &args, +Label BeamModuleAssembler::embed_vararg_rodata(const Span &args, int y_offset) { Label label = a.newLabel(); @@ -206,27 +105,33 @@ Label BeamModuleAssembler::embed_vararg_rodata(const std::vector &args, a.align(AlignMode::kData, 8); switch (arg.getType()) { - case TAG_x: - data.as_beam = make_loader_x_reg(arg.getValue()); + case ArgVal::XReg: { + auto index = arg.as().get(); + data.as_beam = make_loader_x_reg(index); a.embed(&data.as_char, sizeof(data.as_beam)); - break; - case TAG_y: - data.as_beam = make_loader_y_reg(arg.getValue() + y_offset); + } break; + case ArgVal::YReg: { + auto index = arg.as().get(); + data.as_beam = make_loader_y_reg(index + y_offset); a.embed(&data.as_char, sizeof(data.as_beam)); + } break; + case ArgVal::Literal: { + auto index = arg.as().get(); + make_word_patch(literals[index].patches); + } break; + case ArgVal::Label: + a.embedLabel(resolve_beam_label(arg)); break; - case TAG_q: - make_word_patch(literals[arg.getValue()].patches); - break; - case TAG_f: - a.embedLabel(labels[arg.getValue()]); + case ArgVal::Immediate: + data.as_beam = arg.as().get(); + a.embed(&data.as_char, sizeof(data.as_beam)); break; - case TAG_i: - case TAG_u: - /* Tagged immediate or untagged word. */ - data.as_beam = arg.getValue(); + case ArgVal::Word: + data.as_beam = arg.as().get(); a.embed(&data.as_char, sizeof(data.as_beam)); break; default: + erts_fprintf(stderr, "tag: %li\n", arg.getType()); ERTS_ASSERT(!"error"); } } @@ -236,15 +141,11 @@ Label BeamModuleAssembler::embed_vararg_rodata(const std::vector &args, return label; } -static void i_emit_nyi(char *msg) { - erts_exit(ERTS_ERROR_EXIT, "NYI: %s\n", msg); -} - void BeamModuleAssembler::emit_i_nif_padding() { const size_t minimum_size = sizeof(UWord[BEAM_NATIVE_MIN_FUNC_SZ]); size_t prev_func_start, diff; - prev_func_start = code.labelOffsetFromBase(labels[functions.back() + 1]); + prev_func_start = code.labelOffsetFromBase(rawLabels[functions.back() + 1]); diff = a.offset() - prev_func_start; if (diff < minimum_size) { @@ -252,34 +153,86 @@ void BeamModuleAssembler::emit_i_nif_padding() { } } +void BeamGlobalAssembler::emit_i_breakpoint_trampoline_shared() { + constexpr ssize_t flag_offset = + sizeof(ErtsCodeInfo) + BEAM_ASM_FUNC_PROLOGUE_SIZE - + offsetof(ErtsCodeInfo, u.metadata.breakpoint_flag); + + Label bp_and_nif = a.newLabel(), bp_only = a.newLabel(), + nif_only = a.newLabel(); + + a.mov(RET, x86::qword_ptr(x86::rsp)); + a.movzx(RETd, x86::byte_ptr(RET, -flag_offset)); + + a.cmp(RETd, imm(ERTS_ASM_BP_FLAG_BP_NIF_CALL_NIF_EARLY)); + a.short_().je(bp_and_nif); + a.cmp(RETd, imm(ERTS_ASM_BP_FLAG_CALL_NIF_EARLY)); + a.short_().je(nif_only); + a.cmp(RETd, imm(ERTS_ASM_BP_FLAG_BP)); + a.short_().je(bp_only); + +#ifndef DEBUG + a.ret(); +#else + Label error = a.newLabel(); + + /* RET must be a valid breakpoint flag. */ + a.test(RETd, RETd); + a.short_().jnz(error); + a.ret(); + + a.bind(error); + a.ud2(); +#endif + + a.bind(bp_and_nif); + { + aligned_call(labels[generic_bp_local]); + /* FALL THROUGH */ + } + + a.bind(nif_only); + { + /* call_nif_early returns on its own, unlike generic_bp_local. */ + a.jmp(labels[call_nif_early]); + } + + a.bind(bp_only); + { + aligned_call(labels[generic_bp_local]); + a.ret(); + } +} + void BeamModuleAssembler::emit_i_breakpoint_trampoline() { /* This little prologue is used by nif loading and tracing to insert * alternative instructions. The call is filled with a relative call to a * trampoline in the module header and then the jmp target is zeroed so that * it effectively becomes a nop */ - byte flag = ERTS_ASM_BP_FLAG_NONE; Label next = a.newLabel(); a.short_().jmp(next); - /* We embed a zero byte here, which is used to flag whether to make an early - * nif call, call a breakpoint handler, or both. */ - a.embed(&flag, sizeof(flag)); - - if (genericBPTramp.isValid()) { - a.call(genericBPTramp); + if (code_header.isValid()) { + auto fragment = ga->get_i_breakpoint_trampoline_shared(); + aligned_call(resolve_fragment(fragment)); } else { /* NIF or BIF stub; we're not going to use this trampoline as-is, but * we need to reserve space for it. */ a.ud2(); + a.align(AlignMode::kCode, sizeof(UWord)); } - a.align(AlignMode::kCode, 8); + ASSERT(a.offset() % sizeof(UWord) == 0); a.bind(next); - ASSERT((a.offset() - code.labelOffsetFromBase(currLabel)) == + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == BEAM_ASM_FUNC_PROLOGUE_SIZE); } +static void i_emit_nyi(char *msg) { + erts_exit(ERTS_ERROR_EXIT, "NYI: %s\n", msg); +} + void BeamModuleAssembler::emit_nyi(const char *msg) { emit_enter_runtime(); @@ -293,8 +246,7 @@ void BeamModuleAssembler::emit_nyi() { emit_nyi(""); } -bool BeamModuleAssembler::emit(unsigned specific_op, - const std::vector &args) { +bool BeamModuleAssembler::emit(unsigned specific_op, const Span &args) { comment(opc[specific_op].name); #ifdef BEAMASM_DUMP_SIZES @@ -309,18 +261,6 @@ bool BeamModuleAssembler::emit(unsigned specific_op, break; } - if (getOffset() == last_error_offset) { - /* - * The previous PC where an exception may occur is equal to the - * current offset, which is also the offset of the next - * instruction. If the next instruction happens to be a - * line instruction, the location for the exception will - * be that line instruction, which is probably wrong. - * To avoid that, bump the instruction offset. - */ - a.nop(); - } - #ifdef BEAMASM_DUMP_SIZES { std::lock_guard lock(size_lock); @@ -341,81 +281,102 @@ void BeamGlobalAssembler::emit_i_func_info_shared() { /* Pop the ErtsCodeInfo address into ARG1 and mask out the offset added by * the call instruction. */ a.pop(ARG1); - a.and_(ARG1, ~0x7); + a.and_(ARG1, imm(~0x7)); - a.lea(ARG1, x86::qword_ptr(ARG1, offsetof(ErtsCodeInfo, mfa))); + a.add(ARG1, imm(offsetof(ErtsCodeInfo, mfa))); a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), EXC_FUNCTION_CLAUSE); a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG1); - a.jmp(labels[error_action_code]); + + mov_imm(ARG2, 0); + mov_imm(ARG4, 0); + a.jmp(labels[raise_exception_shared]); } -void BeamModuleAssembler::emit_i_func_info(const ArgVal &Label, - const ArgVal &Module, - const ArgVal &Function, - const ArgVal &Arity) { +void BeamModuleAssembler::emit_i_func_info(const ArgWord &Label, + const ArgAtom &Module, + const ArgAtom &Function, + const ArgWord &Arity) { ErtsCodeInfo info; - functions.push_back(Label.getValue()); + /* `op_i_func_info_IaaI` is used in various places in the emulator, so this + * label is always encoded as a word, even though the signature ought to + * be `op_i_func_info_LaaI`. */ + functions.push_back(Label.get()); - info.mfa.module = Module.getValue(); - info.mfa.function = Function.getValue(); - info.mfa.arity = Arity.getValue(); - info.u.gen_bp = NULL; + info.mfa.module = Module.get(); + info.mfa.function = Function.get(); + info.mfa.arity = Arity.get(); + info.gen_bp = NULL; comment("%T:%T/%d", info.mfa.module, info.mfa.function, info.mfa.arity); /* This is an ErtsCodeInfo structure that has a valid x86 opcode as its `op` - * field, which *calls* the funcInfo trampoline so we can trace it back to - * this particular function. + * field, which *calls* the `_i_func_info_shared` fragment so we can trace + * it back to this particular function. * - * We make a relative call to a trampoline in the module header because this - * needs to fit into a word, and an directy call to `i_func_info_shared` - * would be too large. */ - if (funcInfo.isValid()) { - a.call(funcInfo); - } else { - a.nop(); - } - - a.align(AlignMode::kCode, sizeof(UWord)); - a.embed(&info.u.gen_bp, sizeof(info.u.gen_bp)); + * We also use this field to store the current breakpoint flag so that we + * only have to modify a single branch target when changing breakpoints. */ + a.call(resolve_fragment(ga->get_i_func_info_shared())); + a.nop(); + a.nop(); + a.embedUInt8(ERTS_ASM_BP_FLAG_NONE); + + ASSERT(a.offset() % sizeof(UWord) == 0); + a.embed(&info.gen_bp, sizeof(info.gen_bp)); a.embed(&info.mfa, sizeof(info.mfa)); } -void BeamModuleAssembler::emit_label(const ArgVal &Label) { - currLabel = labels[Label.getValue()]; - a.bind(currLabel); +void BeamModuleAssembler::emit_label(const ArgLabel &Label) { + ASSERT(Label.isLabel()); + + current_label = rawLabels[Label.get()]; + a.bind(current_label); + + last_movarg_offset = ~0; } -void BeamModuleAssembler::emit_aligned_label(const ArgVal &Label, - const ArgVal &Alignment) { - ASSERT(Alignment.getType() == ArgVal::u); - a.align(AlignMode::kCode, Alignment.getValue()); +void BeamModuleAssembler::emit_aligned_label(const ArgLabel &Label, + const ArgWord &Alignment) { + a.align(AlignMode::kCode, Alignment.get()); emit_label(Label); } void BeamModuleAssembler::emit_on_load() { - on_load = currLabel; + on_load = current_label; } void BeamModuleAssembler::emit_int_code_end() { /* This label is used to figure out the end of the last function */ - labels[labels.size() + 1] = a.newLabel(); - a.bind(labels[labels.size()]); + code_end = a.newLabel(); + a.bind(code_end); emit_nyi("int_code_end"); + + for (auto pair : _dispatchTable) { + a.bind(pair.second); + a.jmp(imm(pair.first)); + } } -void BeamModuleAssembler::emit_line(const ArgVal &) { - /* - * There is no need to align the line instruction. In the loaded - * code, the type of the pointer will be void* and that pointer - * will only be used in comparisons. - */ +void BeamModuleAssembler::emit_line(const ArgWord &Loc) { + /* There is no need to align the line instruction. In the loaded code, the + * type of the pointer will be void* and that pointer will only be used in + * comparisons. + * + * We only need to do something when there's a possibility of raising an + * exception at the very end of the preceding instruction (and thus + * pointing at the start of this one). If we were to do nothing, the error + * would erroneously refer to this instead of the preceding line. + * + * Since line addresses are taken _after_ line instructions we can avoid + * this by adding a nop when we detect this condition. */ + if (a.offset() == last_error_offset) { + a.nop(); + } } -void BeamModuleAssembler::emit_func_line(const ArgVal &Loc) { +void BeamModuleAssembler::emit_func_line(const ArgWord &Loc) { emit_line(Loc); } @@ -434,7 +395,7 @@ void BeamModuleAssembler::emit_i_generic_breakpoint() { emit_nyi("i_generic_breakpoint should never be called"); } -void BeamModuleAssembler::emit_trace_jump(const ArgVal &) { +void BeamModuleAssembler::emit_trace_jump(const ArgWord &) { emit_nyi("trace_jump should never be called"); } @@ -442,198 +403,12 @@ void BeamModuleAssembler::emit_call_error_handler() { emit_nyi("call_error_handler should never be called"); } -void BeamModuleAssembler::codegen(JitAllocator *allocator, - const void **executable_ptr, - void **writable_ptr, - const BeamCodeHeader *in_hdr, - const BeamCodeHeader **out_exec_hdr, - BeamCodeHeader **out_rw_hdr) { - const BeamCodeHeader *code_hdr_exec; - BeamCodeHeader *code_hdr_rw; +const Label &BeamModuleAssembler::resolve_fragment(void (*fragment)()) { + auto it = _dispatchTable.find(fragment); - codegen(allocator, executable_ptr, writable_ptr); - - { - auto offset = code.labelOffsetFromBase(codeHeader); - - auto base_exec = (const char *)(*executable_ptr); - code_hdr_exec = (const BeamCodeHeader *)&base_exec[offset]; - - auto base_rw = (const char *)(*writable_ptr); - code_hdr_rw = (BeamCodeHeader *)&base_rw[offset]; + if (it == _dispatchTable.end()) { + it = _dispatchTable.emplace(fragment, a.newLabel()).first; } - sys_memcpy(code_hdr_rw, in_hdr, sizeof(BeamCodeHeader)); - code_hdr_rw->on_load = getOnLoad(); - - for (unsigned i = 0; i < functions.size(); i++) { - ErtsCodeInfo *ci = (ErtsCodeInfo *)getCode(functions[i]); - code_hdr_rw->functions[i] = ci; - } - - char *module_end = (char *)code.baseAddress() + a.offset(); - code_hdr_rw->functions[functions.size()] = (ErtsCodeInfo *)module_end; - - *out_exec_hdr = code_hdr_exec; - *out_rw_hdr = code_hdr_rw; -} - -void BeamModuleAssembler::codegen(JitAllocator *allocator, - const void **executable_ptr, - void **writable_ptr) { - _codegen(allocator, executable_ptr, writable_ptr); - -#ifndef WIN32 - if (functions.size()) { - char *buff = (char *)erts_alloc(ERTS_ALC_T_TMP, 1024); - std::vector ranges; - std::string name = getAtom(mod); - ranges.reserve(functions.size() + 2); - - /* Push info about the header */ - ranges.push_back({.start = (ErtsCodePtr)getBaseAddress(), - .stop = getCode(functions[0]), - .name = name + "::codeHeader"}); - - for (unsigned i = 0; i < functions.size(); i++) { - ErtsCodePtr start, stop; - const ErtsCodeInfo *ci; - int n; - - start = getCode(functions[i]); - ci = (const ErtsCodeInfo *)start; - - n = erts_snprintf(buff, - 1024, - "%T:%T/%d", - ci->mfa.module, - ci->mfa.function, - ci->mfa.arity); - stop = ((const char *)erts_codeinfo_to_code(ci)) + - BEAM_ASM_FUNC_PROLOGUE_SIZE; - - /* We use a different symbol for CodeInfo and the Prologue - in order for the perf disassembly to be better. */ - std::string name(buff, n); - ranges.push_back({.start = start, - .stop = stop, - .name = name + "-CodeInfoPrologue"}); - - /* The actual code */ - start = stop; - if (i + 1 < functions.size()) { - stop = getCode(functions[i + 1]); - } else { - stop = getCode(labels.size()); - } - - ranges.push_back({.start = start, .stop = stop, .name = name}); - } - - /* Push info about the footer */ - ranges.push_back( - {.start = ranges.back().stop, - .stop = (ErtsCodePtr)(code.baseAddress() + code.codeSize()), - .name = name + "::codeFooter"}); - - update_gdb_jit_info(name, ranges); - beamasm_update_perf_info(name, ranges); - erts_free(ERTS_ALC_T_TMP, buff); - } -#endif -} - -void BeamModuleAssembler::codegen(char *buff, size_t len) { - code.flatten(); - code.resolveUnresolvedLinks(); - ERTS_ASSERT(code.codeSize() <= len); - code.relocateToBase((uint64_t)buff); - code.copyFlattenedData(buff, - code.codeSize(), - CopySectionFlags::kPadSectionBuffer); -} - -BeamCodeHeader *BeamModuleAssembler::getCodeHeader() { - return (BeamCodeHeader *)getCode(codeHeader); -} - -const ErtsCodeInfo *BeamModuleAssembler::getOnLoad() { - if (on_load.isValid()) { - return erts_code_to_codeinfo((ErtsCodePtr)getCode(on_load)); - } else { - return 0; - } -} - -unsigned BeamModuleAssembler::patchCatches(char *rw_base) { - unsigned catch_no = BEAM_CATCHES_NIL; - - for (const auto &c : catches) { - const auto &patch = c.patch; - ErtsCodePtr handler; - - handler = (ErtsCodePtr)getCode(c.handler); - catch_no = beam_catches_cons(handler, catch_no, nullptr); - - /* Patch the `mov` instruction with the catch tag */ - auto offset = code.labelOffsetFromBase(patch.where); - auto where = (unsigned *)&rw_base[offset + patch.ptr_offs]; - - ASSERT(0x7fffffff == *where); - Eterm catch_term = make_catch(catch_no); - - /* With the current tag scheme, more than 33 million - * catches can exist at once. */ - ERTS_ASSERT(catch_term >> 31 == 0); - *where = (unsigned)catch_term; - } - - return catch_no; -} - -void BeamModuleAssembler::patchImport(char *rw_base, - unsigned index, - BeamInstr I) { - for (const auto &patch : imports[index].patches) { - auto offset = code.labelOffsetFromBase(patch.where); - auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; - - ASSERT(LLONG_MAX == *where); - *where = I + patch.val_offs; - } -} - -void BeamModuleAssembler::patchLambda(char *rw_base, - unsigned index, - BeamInstr I) { - for (const auto &patch : lambdas[index].patches) { - auto offset = code.labelOffsetFromBase(patch.where); - auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; - - ASSERT(LLONG_MAX == *where); - *where = I + patch.val_offs; - } -} - -void BeamModuleAssembler::patchLiteral(char *rw_base, - unsigned index, - Eterm lit) { - for (const auto &patch : literals[index].patches) { - auto offset = code.labelOffsetFromBase(patch.where); - auto where = (Eterm *)&rw_base[offset + patch.ptr_offs]; - - ASSERT(LLONG_MAX == *where); - *where = lit + patch.val_offs; - } -} - -void BeamModuleAssembler::patchStrings(char *rw_base, - const byte *string_table) { - for (const auto &patch : strings) { - auto offset = code.labelOffsetFromBase(patch.where); - auto where = (const byte **)&rw_base[offset + 2]; - - ASSERT(LLONG_MAX == (Eterm)*where); - *where = string_table + patch.val_offs; - } + return it->second; } diff --git a/erts/emulator/beam/jit/x86/beam_asm_perf.cpp b/erts/emulator/beam/jit/x86/beam_asm_perf.cpp deleted file mode 100644 index cbc61f4059a0..000000000000 --- a/erts/emulator/beam/jit/x86/beam_asm_perf.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2020-2021. 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% - */ - -#include "beam_asm.hpp" - -#ifdef HAVE_LINUX_PERF_SUPPORT - -# ifdef HAVE_ELF_H -# include -# define HAVE_LINUX_PERF_DUMP_SUPPORT 1 - -class JitPerfDump { - FILE *file = nullptr; - Uint64 code_index = 0; - - enum PerfDumpId { - JIT_CODE_LOAD = 0, /* record describing a jitted function */ - JIT_CODE_MOVE = 1, /* record describing an already jitted function which - is moved */ - JIT_CODE_DEBUG_INFO = 2, /* record describing the debug information for - a jitted function */ - JIT_CODE_CLOSE = - 3, /* record marking the end of the jit runtime (optional) */ - JIT_CODE_UNWINDING_INFO = - 4 /* record describing a function unwinding information */ - }; - - struct FileHeader { - Uint32 magic; - Uint32 version; - Uint32 total_size; - Uint32 elf_mach; - Uint32 pad1; - Uint32 pid; - Uint64 timestamp; - Uint64 flags; - - FileHeader() { - magic = 0x4A695444; /* "JiTD" as numbers */ - version = 1; - total_size = sizeof(FileHeader); - elf_mach = EM_X86_64; - pad1 = 0; - pid = getpid(); - timestamp = erts_os_monotonic_time(); - flags = 0; - ERTS_CT_ASSERT(sizeof(FileHeader) == 4 * 10); - } - }; - - struct RecordHeader { - Uint32 id; - Uint32 total_size; - Uint64 timestamp; - }; - -public: - bool init() { - char name[MAXPATHLEN]; - FileHeader header; - - /* LLVM places this file in ~/.debug/jit/ maybe we should do that to? */ - - erts_snprintf(name, sizeof(name), "/tmp/jit-%d.dump", getpid()); - - file = fopen(name, "w+"); - - if (file) { - fwrite(&header, sizeof(header), 1, file); - /* inform perf of the location of the dump file */ - void *addr = mmap(NULL, - sizeof(header), - PROT_READ | PROT_EXEC, - MAP_PRIVATE, - fileno(file), - 0); - if (addr == MAP_FAILED) { - int saved_errno = errno; - erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); - erts_dsprintf(dsbuf, - "perf: mmap of %s(%d) failed: %d\r\n", - name, - fileno(file), - saved_errno); - erts_send_error_to_logger_nogl(dsbuf); - fclose(file); - file = nullptr; - return false; - } - } else { - int saved_errno = errno; - erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); - erts_dsprintf(dsbuf, - "perf: Failed to open %s (%d)", - name, - saved_errno); - erts_send_error_to_logger_nogl(dsbuf); - return false; - } - return true; - } - - void update_perf_info(std::string modulename, - std::vector &ranges) { - struct JitCodeLoadRecord { - RecordHeader header; - Uint32 pid; - Uint32 tid; - Uint64 vma; - Uint64 code_addr; - Uint64 code_size; - Uint64 code_index; - /* Null terminated M:F/A */ - /* Native code */ - }; - JitCodeLoadRecord record; - record.header.id = JIT_CODE_LOAD; - record.pid = getpid(); - record.tid = erts_thr_self(); - for (BeamAssembler::AsmRange &r : ranges) { - size_t nameLen = r.name.size(); - ptrdiff_t codeSize = (char *)r.stop - (char *)r.start; - ASSERT(codeSize >= 0); - record.header.total_size = sizeof(record) + nameLen + 1 + codeSize; - record.vma = (Uint64)r.start; - record.code_addr = (Uint64)r.start; - record.code_size = (Uint64)codeSize; - record.code_index = ++code_index; - record.header.timestamp = erts_os_monotonic_time(); - - fwrite(&record, sizeof(record), 1, file); - fwrite(r.name.c_str(), nameLen + 1, 1, file); - fwrite(r.start, codeSize, 1, file); - } - } -}; - -# endif - -class JitPerfMap { - FILE *file = nullptr; - -public: - bool init() { - char name[MAXPATHLEN]; - snprintf(name, sizeof(name), "/tmp/perf-%i.map", getpid()); - file = fopen(name, "w"); - if (!file) { - int saved_errno = errno; - erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf(); - erts_dsprintf(dsbuf, - "perf: Failed to open %s (%d)", - name, - saved_errno); - erts_send_error_to_logger_nogl(dsbuf); - return false; - } - return true; - } - void update_perf_info(std::string modulename, - std::vector &ranges) { - for (BeamAssembler::AsmRange &r : ranges) { - char *start = (char *)r.start, *stop = (char *)r.stop; - ptrdiff_t size = stop - start; - fprintf(file, "%p %tx $%s\n", start, size, r.name.c_str()); - } - fflush(file); - } -}; - -class JitPerfSupport { - enum PerfModes { NONE = 0, MAP = (1 << 0), DUMP = (1 << 1) }; - - int modes; - - erts_mtx_t mutex; -# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT - JitPerfDump perf_dump; -# endif - JitPerfMap perf_map; - -public: - JitPerfSupport() : modes(NONE) { - } - void init() { - modes = JitPerfSupport::NONE; -# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT - if ((erts_jit_perf_support & BEAMASM_PERF_DUMP) && perf_dump.init()) { - modes |= JitPerfSupport::DUMP; - } -# endif - if ((erts_jit_perf_support & BEAMASM_PERF_MAP) && perf_map.init()) { - modes |= JitPerfSupport::MAP; - } - - erts_mtx_init(&mutex, - "perf", - NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | - ERTS_LOCK_FLAGS_CATEGORY_GENERIC); - } - - void update_perf_info(std::string modulename, - std::vector &ranges) { - if (modes) { - erts_mtx_lock(&mutex); -# ifdef HAVE_LINUX_PERF_DUMP_SUPPORT - if (modes & DUMP) { - perf_dump.update_perf_info(modulename, ranges); - } -# endif - if (modes & MAP) { - perf_map.update_perf_info(modulename, ranges); - } - erts_mtx_unlock(&mutex); - } - } -}; - -static JitPerfSupport perf; - -void beamasm_init_perf() { - perf.init(); -} - -void beamasm_update_perf_info(std::string modulename, - std::vector &ranges) { - perf.update_perf_info(modulename, ranges); -} -#else -void beamasm_init_perf() { -} - -void beamasm_update_perf_info(std::string modulename, - std::vector &ranges) { -} -#endif diff --git a/erts/emulator/beam/jit/x86/generators.tab b/erts/emulator/beam/jit/x86/generators.tab index 57424149604e..007344d17d1c 100644 --- a/erts/emulator/beam/jit/x86/generators.tab +++ b/erts/emulator/beam/jit/x86/generators.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020-2021. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. 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. @@ -19,60 +19,6 @@ // %CopyrightEnd% // -// Generate the fastest instruction to fetch an integer from a binary. -gen.get_integer2(Fail, Ms, Live, Size, Unit, Flags, Dst) { - BeamOp* op; - UWord bits; - - $NewBeamOp(S, op); - $NativeEndian(Flags); - if (Size.type == TAG_i) { - if (!beam_load_safe_mul(Size.val, Unit.val, &bits)) { - $BeamOpNameArity(op, jump, 1); - op->a[0] = Fail; - } else if (bits == 8) { - $BeamOpNameArity(op, i_bs_get_integer_8, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 16) { - $BeamOpNameArity(op, i_bs_get_integer_16, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 32) { - $BeamOpNameArity(op, i_bs_get_integer_32, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 64) { - $BeamOpNameArity(op, i_bs_get_integer_64, 5); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Live; - op->a[4] = Dst; - } else { - goto generic; - } - } else { - generic: - $BeamOpNameArity(op, i_bs_get_integer, 6); - op->a[0] = Ms; - op->a[1] = Fail; - op->a[2] = Live; - op->a[3].type = TAG_u; - op->a[3].val = (Unit.val << 3) | Flags.val; - op->a[4] = Size; - op->a[5] = Dst; - return op; - } - return op; -} - gen.select_tuple_arity(Src, Fail, Size, Rest) { BeamOp* op; BeamOpArg *tmp; @@ -114,7 +60,7 @@ gen.select_tuple_arity(Src, Fail, Size, Rest) { for (i = 3; i < arity; i += 2) { tmp[i - 2] = Rest[i - 2]; tmp[i - 3].type = TAG_v; - tmp[i - 3].val = make_arityval(Rest[i - 3].val); + tmp[i - 3].val = make_arityval_unchecked(Rest[i - 3].val); } /* Sort the values to make them useful for a binary or sentinel search. */ @@ -384,9 +330,13 @@ gen.new_small_map_lit(Dst, Live, Size, Rest) { $BeamOpArity(op, 4 + size/2); op->next = NULL; - tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, (1 + size/2) * sizeof(*tmp)); - keys = make_tuple(thp); - *thp++ = make_arityval(size/2); + tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, ((size == 0 ? 0 : 1) + size/2) * sizeof(*tmp)); + if (size == 0) { + keys = erts_get_global_literal(ERTS_LIT_EMPTY_TUPLE); + } else { + keys = make_tuple(thp); + *thp++ = make_arityval(size/2); + } dst = op->a+4; @@ -409,7 +359,7 @@ gen.new_small_map_lit(Dst, Live, Size, Rest) { *dst++ = Rest[i + 1]; } - lit = beamfile_add_literal(&S->beam, keys); + lit = beamfile_add_literal(&S->beam, keys, 1); erts_free(ERTS_ALC_T_LOADER_TMP, tmp); op->a[0] = Dst; @@ -483,27 +433,6 @@ gen.combine_conses(Len, Dst, Hd) { return cons; } -gen.is_eq_exact_literal(Fail, R, C) { - BeamOp* op; - Eterm literal; - Uint tag_test; - - ASSERT(C.type == TAG_q); - literal = beamfile_get_literal(&S->beam, C.val); - ASSERT(is_boxed(literal) || is_list(literal)); - tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); - - $NewBeamOp(S, op); - $BeamOpNameArity(op, i_is_eq_exact_literal, 4); - op->a[0] = Fail; - op->a[1] = R; - op->a[2] = C; - op->a[3].type = TAG_u; - op->a[3].val = tag_test; - - return op; -} - gen.allocate_heap_zero(Ns, Nh, Live) { BeamOp* alloc; BeamOp* init; @@ -528,3 +457,219 @@ gen.allocate_heap_zero(Ns, Nh, Live) { return alloc; } + +gen.func_end(Func_Label, Entry_Label) { + BeamOp *op = NULL; + + if (S->labels[Entry_Label.val].lambda_index != -1) { + int index = S->labels[Entry_Label.val].lambda_index; + BeamFile_LambdaEntry *lambda_entry; + + lambda_entry = &S->beam.lambdas.entries[index]; + + if (lambda_entry->num_free > 0) { + BeamOp *lambda; + + $NewBeamOp(S, lambda); + $BeamOpNameArity(lambda, i_lambda_trampoline, 4); + + lambda->a[0].type = TAG_u; + lambda->a[0].val = index; + lambda->a[1] = Entry_Label; + lambda->a[2].type = TAG_u; + lambda->a[2].val = lambda_entry->arity; + lambda->a[3].type = TAG_u; + lambda->a[3].val = lambda_entry->num_free; + + lambda->next = op; + op = lambda; + } + } + + if (S->may_load_nif && (S->load_hdr->are_nifs == NULL || + S->load_hdr->are_nifs[S->function_number-1])) { + BeamOp *padding; + + $NewBeamOp(S, padding); + $BeamOpNameArity(padding, i_nif_padding, 0); + + padding->next = op; + op = padding; + } + + if (op == NULL) { + /* Workaround for the fact that we have to return an instruction from + * generators. The loader will remove this dummy instruction. */ + $NewBeamOp(S, op); + $BeamOpNameArity(op, delete_me, 0); + + op->next = NULL; + } + + return op; +} + +gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { + BeamOp* op; + int fixed_args; + int i; + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_create_bin, 4); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Alloc; + op->a[2] = Live; + op->a[3] = Dst; + + for (i = 0; i < N.val; i += 6) { + BeamOpArg Flags; + Uint flags = 0; + + /* Copy all but flags. */ + op->a[i+fixed_args+0] = Segments[i+0]; + op->a[i+fixed_args+1] = Segments[i+1]; + op->a[i+fixed_args+2] = Segments[i+2]; + op->a[i+fixed_args+4] = Segments[i+4]; + op->a[i+fixed_args+5] = Segments[i+5]; + + /* Translate flags. */ + Flags = Segments[i+3]; /* Flags */ + if (Flags.type != TAG_n) { + if (Flags.type == TAG_q) { + Eterm term = beamfile_get_literal(&S->beam, Flags.val); + while (is_list(term)) { + Eterm* consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + flags |= BSF_LITTLE; + break; + case am_native: + flags |= BSF_NATIVE; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + } + } + Flags.type = TAG_u; + Flags.val = flags; + $NativeEndian(Flags); + op->a[i+fixed_args+3] = Flags; + + /* + * Replace short string segments with integer segments. + * Integer segments can be combined with adjacent integer + * segments for better performance. + */ + if (op->a[i+fixed_args+0].val == am_string) { + Sint num_chars = op->a[i+fixed_args+5].val; + if (num_chars <= 4) { + Sint index = op->a[i+fixed_args+4].val; + const byte* s = S->beam.strings.data + index; + Uint num = 0; + op->a[i+fixed_args+0].val = am_integer; + op->a[i+fixed_args+2].val = 8; + op->a[i+fixed_args+5].val = num_chars; + while (num_chars-- > 0) { + num = num << 8 | *s++; + } + op->a[i+fixed_args+4].type = TAG_i; + op->a[i+fixed_args+4].val = num; + } + } + } + + if (op->a[4].val == am_private_append && Alloc.val != 0) { + BeamOp* th; + $NewBeamOp(S, th); + $BeamOpNameArity(th, test_heap, 2); + th->a[0] = Alloc; + th->a[1] = Live; + th->next = op; + + op->a[1].val = 0; + + op = th; + } + + return op; +} + +gen.bs_match(Fail, Ctx, N, List) { + BeamOp* op; + int fixed_args; + int i; + + /* + * If a BEAM file produced by a later version of Erlang/OTP + * is accidentally loaded into an earlier version, ensure + * that the loading fails (as opposed to crashing the runtime) + * if there are any unknown sub commands. + */ + i = 0; + while (i < N.val) { + BeamOpArg current = List[i++]; + + if (current.type != TAG_a) { + goto error; + } + + switch (current.val) { + case am_ensure_exactly: + case am_skip: + i += 1; + break; + case am_ensure_at_least: + i += 2; + break; + case am_get_tail: + case am_Eq: + i += 3; + break; + case am_binary: + case am_integer: + i += 5; + break; + default: { + error: + $NewBeamOp(S, op); + $BeamOpNameArity(op, bad_bs_match, 1); + op->a[0] = current; + return op; + } + } + } + + /* + * Make sure that we don't attempt to pass any overflow tags to the JIT. + */ + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_match, 2); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Ctx; + + for (i = 0; i < N.val; i++) { + BeamOpArg current; + + current = List[i]; + if (current.type == TAG_o) { + /* An overflow tag (in ensure_at_least or ensure_exactly) + * means that the match will always fail. */ + $BeamOpNameArity(op, jump, 1); + op->a[0] = Fail; + return op; + } + op->a[i+fixed_args] = current; + } + + return op; +} diff --git a/erts/emulator/beam/jit/x86/instr_arith.cpp b/erts/emulator/beam/jit/x86/instr_arith.cpp index 43cb6137c122..888f3109f165 100644 --- a/erts/emulator/beam/jit/x86/instr_arith.cpp +++ b/erts/emulator/beam/jit/x86/instr_arith.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -27,99 +27,104 @@ extern "C" { +#include "big.h" #include "erl_bif_table.h" } -void BeamModuleAssembler::emit_bif_arg_error(std::vector args, - const ErtsCodeMFA *mfa) { - comment("handle_error"); - for (unsigned i = 0; i < args.size(); i++) - mov_arg(ArgVal(ArgVal::x, i), args[i]); - emit_handle_error(mfa); -} - -void BeamModuleAssembler::emit_is_small(Label fail, x86::Gp Reg) { +/* + * Clobbers ARG1. + */ +void BeamModuleAssembler::emit_is_small(Label fail, + const ArgSource &Arg, + x86::Gp Reg) { ASSERT(ARG1 != Reg); - comment("is_small(X)"); - a.mov(ARG1d, Reg.r32()); - a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(fail); -} - -void BeamModuleAssembler::emit_is_both_small(Label fail, x86::Gp A, x86::Gp B) { - ASSERT(ARG1 != A && ARG1 != B); - - comment("is_both_small(X, Y)"); - if (A != RET && B != RET) { - a.mov(RETd, A.r32()); - a.and_(RETd, B.r32()); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + if (always_small(Arg)) { + comment("skipped test for small operand since it is always small"); + } else if (always_one_of(Arg)) { + comment("simplified test for small operand since it is a number"); + a.test(Reg.r8(), imm(TAG_PRIMARY_LIST)); + a.short_().je(fail); } else { - a.mov(ARG1d, A.r32()); - a.and_(ARG1d, B.r32()); + comment("is the operand small?"); + a.mov(ARG1d, Reg.r32()); a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(fail); } - a.short_().jne(fail); } -void BeamGlobalAssembler::emit_increment_body_shared() { - Label error = a.newLabel(); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - a.or_(ARG3, imm(_TAG_IMMED1_SMALL)); - runtime_call<3>(erts_mixed_plus); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - a.short_().je(error); - - a.ret(); - - a.bind(error); - { - mov_imm(ARG4, 0); - emit_handle_error_shared_prologue(); +/* + * Clobbers RET, ARG1. + */ +void BeamModuleAssembler::emit_are_both_small(Label fail, + const ArgSource &LHS, + x86::Gp A, + const ArgSource &RHS, + x86::Gp B) { + ASSERT(ARG1 != A && ARG1 != B); + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + } else if (always_one_of(LHS) && + always_one_of(RHS)) { + comment("simplified test for small operands since both are numbers"); + if (always_small(RHS)) { + a.test(A.r8(), imm(TAG_PRIMARY_LIST)); + } else if (always_small(LHS)) { + a.test(B.r8(), imm(TAG_PRIMARY_LIST)); + } else if (A != RET && B != RET) { + a.mov(RETd, A.r32()); + a.and_(RETd, B.r32()); + a.test(RETb, imm(TAG_PRIMARY_LIST)); + } else { + a.mov(ARG1d, A.r32()); + a.and_(ARG1d, B.r32()); + a.test(ARG1.r8(), imm(TAG_PRIMARY_LIST)); + } + a.short_().je(fail); + } else if (always_small(LHS)) { + if (A == RET || B == RET) { + emit_is_small(fail, RHS, B); + } else { + comment("is the operand small?"); + a.mov(RETd, B.r32()); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(fail); + } + } else if (always_small(RHS)) { + if (A == RET || B == RET) { + emit_is_small(fail, LHS, A); + } else { + comment("is the operand small?"); + a.mov(RETd, A.r32()); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(fail); + } + } else { + comment("are both operands small?"); + if (A != RET && B != RET) { + a.mov(RETd, A.r32()); + a.and_(RETd, B.r32()); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + } else { + a.mov(ARG1d, A.r32()); + a.and_(ARG1d, B.r32()); + a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); + } + a.short_().jne(fail); } } -void BeamModuleAssembler::emit_i_increment(const ArgVal &Src, - const ArgVal &Val, - const ArgVal &Dst) { - Label mixed = a.newLabel(), next = a.newLabel(); - - /* Place the values in ARG2 and ARG3 to prepare for the mixed call. Note - * that ARG3 is untagged at this point */ - mov_arg(ARG2, Src); - mov_imm(ARG3, Val.getValue() << _TAG_IMMED1_SIZE); - a.mov(RETd, ARG2d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(mixed); - - a.mov(RET, ARG2); - a.add(RET, ARG3); - a.short_().jno(next); - - a.bind(mixed); - safe_fragment_call(ga->get_increment_body_shared()); - - /* all went well, store result in dst */ - a.bind(next); - mov_arg(Dst, RET); -} - void BeamGlobalAssembler::emit_plus_body_shared() { static const ErtsCodeMFA bif_mfa = {am_erlang, am_Plus, 2}; Label error = a.newLabel(); + emit_enter_frame(); emit_enter_runtime(); /* Save original arguments for the error path. */ @@ -130,10 +135,10 @@ void BeamGlobalAssembler::emit_plus_body_shared() { runtime_call<3>(erts_mixed_plus); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); - a.ret(); a.bind(error); @@ -145,11 +150,12 @@ void BeamGlobalAssembler::emit_plus_body_shared() { a.mov(getXRef(1), ARG2); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } void BeamGlobalAssembler::emit_plus_guard_shared() { + emit_enter_frame(); emit_enter_runtime(); a.mov(ARG1, c_p); @@ -157,35 +163,71 @@ void BeamGlobalAssembler::emit_plus_guard_shared() { runtime_call<3>(erts_mixed_plus); emit_leave_runtime(); + emit_leave_frame(); /* Set ZF if the addition failed. */ emit_test_the_non_value(RET); a.ret(); } -void BeamModuleAssembler::emit_i_plus(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_plus(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Dst) { + bool small_result = is_sum_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && small_result) { + /* Since we don't need the order on this path (no exceptions), we'll + * simplify the code below by shuffling constants to the right-hand + * side. */ + const ArgSource A = LHS.isSmall() ? RHS : LHS, + B = LHS.isSmall() ? LHS : RHS; + + comment("add without overflow check"); + mov_arg(RET, A); + + if (B.isSmall()) { + /* Must be signed for the template magic in isInt32 to work for + * negative numbers. */ + Sint untagged = B.as().getSigned() << _TAG_IMMED1_SIZE; + + if (Support::isInt32(untagged)) { + a.add(RET, imm(untagged)); + } else { + mov_imm(ARG2, B.as().get() & ~_TAG_IMMED1_MASK); + a.add(RET, ARG2); + } + } else { + mov_arg(ARG2, B); + a.lea(RET, x86::qword_ptr(RET, ARG2, 0, -_TAG_IMMED1_SMALL)); + } + + mov_arg(Dst, RET); + return; + } + Label next = a.newLabel(), mixed = a.newLabel(); mov_arg(ARG2, LHS); /* Used by erts_mixed_plus in this slot */ mov_arg(ARG3, RHS); /* Used by erts_mixed_plus in this slot */ - emit_is_both_small(mixed, ARG2, ARG3); + emit_are_both_small(mixed, LHS, ARG2, RHS, ARG3); - comment("add with overflow check"); a.mov(RET, ARG2); - a.mov(ARG4, ARG3); - a.and_(ARG4, imm(~_TAG_IMMED1_MASK)); - a.add(RET, ARG4); - a.short_().jno(next); + a.and_(RET, imm(~_TAG_IMMED1_MASK)); + a.add(RET, ARG3); + if (small_result) { + comment("skipped overflow test because the result is always small"); + a.short_().jmp(next); + } else { + a.short_().jno(next); + } /* Call mixed addition. */ a.bind(mixed); { - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_plus_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_plus_body_shared()); } @@ -200,6 +242,7 @@ void BeamGlobalAssembler::emit_minus_body_shared() { Label error = a.newLabel(); + emit_enter_frame(); emit_enter_runtime(); /* Save original arguments for the error path. */ @@ -210,10 +253,10 @@ void BeamGlobalAssembler::emit_minus_body_shared() { runtime_call<3>(erts_mixed_minus); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); - a.ret(); a.bind(error); @@ -225,11 +268,12 @@ void BeamGlobalAssembler::emit_minus_body_shared() { a.mov(getXRef(1), ARG2); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } void BeamGlobalAssembler::emit_minus_guard_shared() { + emit_enter_frame(); emit_enter_runtime(); a.mov(ARG1, c_p); @@ -237,44 +281,69 @@ void BeamGlobalAssembler::emit_minus_guard_shared() { runtime_call<3>(erts_mixed_minus); emit_leave_runtime(); + emit_leave_frame(); /* Set ZF if the addition failed. */ emit_test_the_non_value(RET); a.ret(); } -void BeamModuleAssembler::emit_i_minus(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_minus(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Dst) { + bool small_result = is_diff_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && small_result) { + comment("subtract without overflow check"); + mov_arg(RET, LHS); + + if (RHS.isSmall()) { + /* Must be signed for the template magic in isInt32 to work for + * negative numbers. */ + Sint untagged = RHS.as().getSigned() << _TAG_IMMED1_SIZE; + + if (Support::isInt32(untagged)) { + a.sub(RET, imm(untagged)); + } else { + mov_imm(ARG2, RHS.as().get() & ~_TAG_IMMED1_MASK); + a.sub(RET, ARG2); + } + } else { + mov_arg(ARG2, RHS); + a.and_(ARG2, imm(~_TAG_IMMED1_MASK)); + a.sub(RET, ARG2); + } + + mov_arg(Dst, RET); + return; + } + Label next = a.newLabel(), mixed = a.newLabel(); mov_arg(ARG2, LHS); /* Used by erts_mixed_plus in this slot */ mov_arg(ARG3, RHS); /* Used by erts_mixed_plus in this slot */ - if (RHS.isImmed() && is_small(RHS.getValue())) { - a.mov(RETd, ARG2d); - } else if (LHS.isImmed() && is_small(LHS.getValue())) { - a.mov(RETd, ARG3d); + emit_are_both_small(mixed, LHS, ARG2, RHS, ARG3); + + if (small_result) { + comment("skipped overflow test because the result is always small"); + a.mov(RET, ARG2); + a.and_(ARG3, imm(~_TAG_IMMED1_MASK)); + a.sub(RET, ARG3); + a.short_().jmp(next); } else { - a.mov(RETd, ARG2d); - a.and_(RETd, ARG3d); + a.mov(RET, ARG2); + a.mov(ARG4, ARG3); + a.and_(ARG4, imm(~_TAG_IMMED1_MASK)); + a.sub(RET, ARG4); + a.short_().jno(next); } - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(mixed); - - comment("sub with overflow check"); - a.mov(RET, ARG2); - a.mov(ARG4, ARG3); - a.and_(ARG4, imm(~_TAG_IMMED1_MASK)); - a.sub(RET, ARG4); - a.short_().jno(next); a.bind(mixed); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_minus_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_minus_body_shared()); } @@ -288,6 +357,7 @@ void BeamGlobalAssembler::emit_unary_minus_body_shared() { Label error = a.newLabel(); + emit_enter_frame(); emit_enter_runtime(); /* Save original arguments for the error path. */ @@ -297,10 +367,10 @@ void BeamGlobalAssembler::emit_unary_minus_body_shared() { runtime_call<2>(erts_unary_minus); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); - a.ret(); a.bind(error); @@ -310,11 +380,12 @@ void BeamGlobalAssembler::emit_unary_minus_body_shared() { a.mov(getXRef(0), ARG1); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } void BeamGlobalAssembler::emit_unary_minus_guard_shared() { + emit_enter_frame(); emit_enter_runtime(); a.mov(ARG1, c_p); @@ -322,15 +393,30 @@ void BeamGlobalAssembler::emit_unary_minus_guard_shared() { runtime_call<2>(erts_unary_minus); emit_leave_runtime(); + emit_leave_frame(); /* Set ZF if the negation failed. */ emit_test_the_non_value(RET); a.ret(); } -void BeamModuleAssembler::emit_i_unary_minus(const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_unary_minus(const ArgSource &Src, + const ArgLabel &Fail, + const ArgRegister &Dst) { + ArgVal zero = ArgVal(ArgVal::Immediate, make_small(0)); + bool small_result = is_diff_small_if_args_are_small(zero, Src); + + if (always_small(Src) && small_result) { + comment("negation without overflow test"); + mov_arg(ARG2, Src); + a.mov(RETd, imm(_TAG_IMMED1_SMALL)); + a.and_(ARG2, imm(~_TAG_IMMED1_MASK)); + a.sub(RET, ARG2); + mov_arg(Dst, RET); + + return; + } + Label next = a.newLabel(), mixed = a.newLabel(); mov_arg(ARG2, Src); @@ -339,18 +425,23 @@ void BeamModuleAssembler::emit_i_unary_minus(const ArgVal &Src, a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); a.short_().jne(mixed); - comment("negation with overflow test"); /* RETb is now equal to _TAG_IMMED1_SMALL. */ a.movzx(RET, RETb); /* Set RET to make_small(0). */ a.mov(ARG3, ARG2); a.and_(ARG3, imm(~_TAG_IMMED1_MASK)); a.sub(RET, ARG3); - a.short_().jno(next); + + if (small_result) { + comment("skipped overflow test because the result is always small"); + a.short_().jmp(next); + } else { + a.short_().jno(next); + } a.bind(mixed); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_unary_minus_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_unary_minus_body_shared()); } @@ -368,6 +459,8 @@ void BeamModuleAssembler::emit_i_unary_minus(const ArgVal &Src, void BeamGlobalAssembler::emit_int_div_rem_guard_shared() { Label exit = a.newLabel(), generic = a.newLabel(); + emit_enter_frame(); + a.cmp(ARG4, imm(SMALL_ZERO)); a.je(exit); @@ -430,7 +523,10 @@ void BeamGlobalAssembler::emit_int_div_rem_guard_shared() { /* Return with a potential error in ZF. It will be set if we came here from * the guard against SMALL_ZERO or if we're returning THE_NON_VALUE. */ a.bind(exit); - a.ret(); + { + emit_leave_frame(); + a.ret(); + } } /* ARG1 = LHS, ARG4 (!) = RHS, ARG5 = error MFA @@ -441,7 +537,9 @@ void BeamGlobalAssembler::emit_int_div_rem_guard_shared() { * Quotient is returned in RAX, remainder in RDX. */ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { Label div_zero = a.newLabel(), generic_div = a.newLabel(), - generic_error = a.newLabel(), error = a.newLabel(); + generic_error = a.newLabel(); + + emit_enter_frame(); a.cmp(ARG4, imm(SMALL_ZERO)); a.je(div_zero); @@ -477,6 +575,7 @@ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { a.cmp(ARG6, imm(1)); a.short_().jge(generic_div); + emit_leave_frame(); a.ret(); a.bind(generic_div); @@ -496,6 +595,7 @@ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { runtime_call<5>(erts_int_div_rem); emit_leave_runtime(); + emit_leave_frame(); /* erts_int_div returns 0 on failure and 1 on success. */ a.test(RETd, RETd); @@ -510,6 +610,8 @@ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { a.bind(div_zero); { + emit_leave_frame(); + /* Set up a badarith exception and place the original arguments in * x-registers. */ a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), @@ -519,7 +621,7 @@ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { a.mov(getXRef(1), ARG4); a.mov(ARG4, ARG5); - a.short_().jmp(error); + a.jmp(labels[raise_exception]); } a.bind(generic_error); @@ -532,37 +634,114 @@ void BeamGlobalAssembler::emit_int_div_rem_body_shared() { /* Read saved MFA. */ a.mov(ARG4, TMP_MEM3q); + a.jmp(labels[raise_exception]); + } +} - /* Fall through to `error` */ +void BeamModuleAssembler::emit_div_rem(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ErtsCodeMFA *error_mfa, + bool need_div, + bool need_rem) { + Label generic_div = a.newLabel(), next = a.newLabel(); + bool need_generic = true; + Sint divisor = 0; + + if (RHS.isSmall()) { + divisor = RHS.as().getSigned(); } - a.bind(error); - emit_handle_error_shared_prologue(); -} + if (divisor != (Sint)0 && divisor != (Sint)-1) { + /* There is no possibility of overflow. */ + a.mov(ARG6, imm(divisor)); + mov_arg(x86::rax, LHS); + if (always_small(LHS)) { + comment("skipped test for small dividend since it is always small"); + need_generic = false; + } else if (always_one_of(LHS)) { + comment("simplified test for small dividend since it is an " + "integer"); + a.test(x86::al, imm(TAG_PRIMARY_LIST)); + a.short_().je(generic_div); + } else { + comment("testing for a small dividend"); + a.mov(ARG2d, x86::eax); + a.and_(ARG2d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG2d, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic_div); + } -void BeamModuleAssembler::emit_div_rem(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ErtsCodeMFA *error_mfa) { - mov_arg(ARG4, RHS); /* Done first as mov_arg may clobber ARG1 */ - mov_arg(ARG1, LHS); - - /* TODO: Specialize division with immediates, either here or in the - * compiler. */ - if (Fail.getValue() != 0) { - safe_fragment_call(ga->get_int_div_rem_guard_shared()); - a.je(labels[Fail.getValue()]); - } else { - a.mov(ARG5, imm(error_mfa)); - safe_fragment_call(ga->get_int_div_rem_body_shared()); + /* Sign-extend and divide. The result is implicitly placed in + * RAX and the remainder in RDX (ARG3). */ + if (Support::isPowerOf2(divisor) && + std::get<0>(getClampedRange(LHS)) >= 0) { + int trailing_bits = Support::ctz(divisor); + + if (need_rem) { + Uint mask = Support::lsbMask(trailing_bits + + _TAG_IMMED1_SIZE); + mask = (1ULL << (trailing_bits + _TAG_IMMED1_SIZE)) - 1; + comment("optimized rem by replacing with masking"); + mov_imm(x86::rdx, mask); + a.and_(x86::rdx, x86::rax); + } + if (need_div) { + comment("optimized div by replacing with right shift"); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.shr(x86::rax, imm(trailing_bits)); + a.or_(x86::rax, imm(_TAG_IMMED1_SMALL)); + } + } else { + comment("divide with inlined code"); + a.sar(x86::rax, imm(_TAG_IMMED1_SIZE)); + a.cqo(); + a.idiv(ARG6); + + if (need_div) { + a.sal(x86::rax, imm(_TAG_IMMED1_SIZE)); + } + + if (need_rem) { + a.sal(x86::rdx, imm(_TAG_IMMED1_SIZE)); + } + + if (need_div) { + a.or_(x86::rax, imm(_TAG_IMMED1_SMALL)); + } + + if (need_rem) { + a.or_(x86::rdx, imm(_TAG_IMMED1_SMALL)); + } + } + + if (need_generic) { + a.short_().jmp(next); + } + } + + a.bind(generic_div); + if (need_generic) { + mov_arg(ARG4, RHS); /* Done first as mov_arg may clobber ARG1 */ + mov_arg(ARG1, LHS); + + if (Fail.get() != 0) { + safe_fragment_call(ga->get_int_div_rem_guard_shared()); + a.je(resolve_beam_label(Fail)); + } else { + a.mov(ARG5, imm(error_mfa)); + safe_fragment_call(ga->get_int_div_rem_body_shared()); + } } + + a.bind(next); } -void BeamModuleAssembler::emit_i_rem_div(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Remainder, - const ArgVal &Quotient) { +void BeamModuleAssembler::emit_i_rem_div(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Remainder, + const ArgRegister &Quotient) { static const ErtsCodeMFA bif_mfa = {am_erlang, am_rem, 2}; emit_div_rem(Fail, LHS, RHS, &bif_mfa); @@ -571,11 +750,11 @@ void BeamModuleAssembler::emit_i_rem_div(const ArgVal &LHS, mov_arg(Quotient, x86::rax); } -void BeamModuleAssembler::emit_i_div_rem(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Quotient, - const ArgVal &Remainder) { +void BeamModuleAssembler::emit_i_div_rem(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Quotient, + const ArgRegister &Remainder) { static const ErtsCodeMFA bif_mfa = {am_erlang, am_div, 2}; emit_div_rem(Fail, LHS, RHS, &bif_mfa); @@ -584,32 +763,32 @@ void BeamModuleAssembler::emit_i_div_rem(const ArgVal &LHS, mov_arg(Remainder, x86::rdx); } -void BeamModuleAssembler::emit_i_int_div(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Quotient) { +void BeamModuleAssembler::emit_i_int_div(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Quotient) { static const ErtsCodeMFA bif_mfa = {am_erlang, am_div, 2}; - emit_div_rem(Fail, LHS, RHS, &bif_mfa); + emit_div_rem(Fail, LHS, RHS, &bif_mfa, true, false); mov_arg(Quotient, x86::rax); } -void BeamModuleAssembler::emit_i_rem(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Remainder) { +void BeamModuleAssembler::emit_i_rem(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Remainder) { static const ErtsCodeMFA bif_mfa = {am_erlang, am_rem, 2}; - emit_div_rem(Fail, LHS, RHS, &bif_mfa); + emit_div_rem(Fail, LHS, RHS, &bif_mfa, false, true); mov_arg(Remainder, x86::rdx); } -void BeamModuleAssembler::emit_i_m_div(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_m_div(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { static const ErtsCodeMFA bif_mfa = {am_erlang, am_Div, 2}; Label next = a.newLabel(); @@ -627,110 +806,65 @@ void BeamModuleAssembler::emit_i_m_div(const ArgVal &Fail, emit_test_the_non_value(RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); - emit_bif_arg_error({LHS, RHS}, &bif_mfa); + + mov_arg(ARG2, LHS); + mov_arg(ARG3, RHS); + mov_arg(ArgXRegister(0), ARG2); + mov_arg(ArgXRegister(1), ARG3); + + emit_raise_exception(&bif_mfa); } a.bind(next); mov_arg(Dst, RET); } -/* ARG1 = LHS, ARG4 (!) = RHS - * - * We avoid using ARG2 and ARG3 because multiplication clobbers RDX, which is - * ARG2 on Windows and ARG3 on SystemV. +/* ARG2 = LHS, ARG3 (!) = RHS * * Result is returned in RET, error is indicated by ZF. */ void BeamGlobalAssembler::emit_times_guard_shared() { - Label generic = a.newLabel(); + emit_enter_frame(); + emit_enter_runtime(); - /* Are both smalls? */ - a.mov(ARG2d, ARG1d); - a.and_(ARG2d, ARG4d); - a.and_(ARG2d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG2d, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(generic); + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_times); - a.mov(RET, ARG1); - a.mov(ARG2, ARG4); - a.and_(RET, imm(~_TAG_IMMED1_MASK)); - a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); - a.imul(RET, ARG2); /* Clobbers RDX */ - a.short_().jo(generic); + emit_leave_runtime(); + emit_leave_frame(); - a.or_(RET, imm(_TAG_IMMED1_SMALL)); /* Always sets ZF to false */ + emit_test_the_non_value(RET); /* Sets ZF for use in caller */ a.ret(); - - a.bind(generic); - { - emit_enter_runtime(); - - a.mov(ARG2, ARG1); - a.mov(ARG3, ARG4); - a.mov(ARG1, c_p); - runtime_call<3>(erts_mixed_times); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); /* Sets ZF for use in caller */ - - a.ret(); - } } -/* ARG1 = LHS, ARG4 (!) = RHS - * - * We avoid using ARG2 and ARG3 because multiplication clobbers RDX, which is - * ARG2 on Windows and ARG3 on SystemV. +/* ARG2 = LHS, ARG3 (!) = RHS * * Result is returned in RET. */ void BeamGlobalAssembler::emit_times_body_shared() { static const ErtsCodeMFA bif_mfa = {am_erlang, am_Times, 2}; - Label generic = a.newLabel(), error = a.newLabel(); - - /* Are both smalls? */ - a.mov(ARG2d, ARG1d); - a.and_(ARG2d, ARG4d); - a.and_(ARG2d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG2, imm(_TAG_IMMED1_SMALL)); - a.jne(generic); - - a.mov(RET, ARG1); - a.mov(ARG2, ARG4); - a.and_(RET, imm(~_TAG_IMMED1_MASK)); - a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); - a.imul(RET, ARG2); /* Clobbers RDX */ - a.short_().jo(generic); - - a.or_(RET, imm(_TAG_IMMED1_SMALL)); - - a.ret(); - - a.bind(generic); - { - emit_enter_runtime(); + Label error = a.newLabel(); - /* Save original arguments for the error path. */ - a.mov(TMP_MEM1q, ARG1); - a.mov(TMP_MEM2q, ARG4); + emit_enter_frame(); + emit_enter_runtime(); - a.mov(ARG2, ARG1); - a.mov(ARG3, ARG4); - a.mov(ARG1, c_p); - runtime_call<3>(erts_mixed_times); + /* Save original arguments for the error path. */ + a.mov(TMP_MEM1q, ARG2); + a.mov(TMP_MEM2q, ARG3); - emit_leave_runtime(); + a.mov(ARG1, c_p); + runtime_call<3>(erts_mixed_times); - emit_test_the_non_value(RET); - a.short_().je(error); + emit_leave_runtime(); + emit_leave_frame(); - a.ret(); - } + emit_test_the_non_value(RET); + a.short_().je(error); + a.ret(); a.bind(error); { @@ -741,26 +875,85 @@ void BeamGlobalAssembler::emit_times_body_shared() { a.mov(getXRef(1), ARG2); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } -void BeamModuleAssembler::emit_i_times(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - mov_arg(ARG4, RHS); /* Done first as mov_arg may clobber ARG1 */ - mov_arg(ARG1, LHS); - - /* TODO: Specialize multiplication with immediates, either here or in the - * compiler. */ - if (Fail.getValue() != 0) { - safe_fragment_call(ga->get_times_guard_shared()); - a.je(labels[Fail.getValue()]); +void BeamModuleAssembler::emit_i_times(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + bool small_result = is_product_small_if_args_are_small(LHS, RHS); + + if (always_small(LHS) && always_small(RHS) && small_result) { + comment("multiplication without overflow check"); + if (RHS.isSmall()) { + Sint factor = RHS.as().getSigned(); + + mov_arg(RET, LHS); + a.and_(RET, imm(~_TAG_IMMED1_MASK)); + if (Support::isPowerOf2(factor)) { + int trailing_bits = Support::ctz(factor); + comment("optimized multiplication by replacing with left " + "shift"); + a.shl(RET, imm(trailing_bits)); + } else { + mov_imm(ARG2, factor); + a.imul(RET, ARG2); + } + } else { + mov_arg(RET, LHS); + mov_arg(ARG2, RHS); + a.and_(RET, imm(~_TAG_IMMED1_MASK)); + a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); + a.imul(RET, ARG2); + } + + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, RET); + + return; + } + + Label next = a.newLabel(), mixed = a.newLabel(); + + mov_arg(ARG2, LHS); /* Used by erts_mixed_times in this slot */ + mov_arg(ARG3, RHS); /* Used by erts_mixed_times in this slot */ + + if (RHS.isSmall()) { + Sint val = RHS.as().getSigned(); + emit_is_small(mixed, LHS, ARG2); + a.mov(RET, ARG2); + a.mov(ARG4, imm(val)); } else { - safe_fragment_call(ga->get_times_body_shared()); + emit_are_both_small(mixed, LHS, ARG2, RHS, ARG3); + a.mov(RET, ARG2); + a.mov(ARG4, ARG3); + a.sar(ARG4, imm(_TAG_IMMED1_SIZE)); } + a.and_(RET, imm(~_TAG_IMMED1_MASK)); + a.imul(RET, ARG4); + if (small_result) { + comment("skipped overflow check because the result is always small"); + } else { + a.short_().jo(mixed); + } + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + a.short_().jmp(next); + + /* Call mixed multiplication. */ + a.bind(mixed); + { + if (Fail.get() != 0) { + safe_fragment_call(ga->get_times_guard_shared()); + a.je(resolve_beam_label(Fail)); + } else { + safe_fragment_call(ga->get_times_body_shared()); + } + } + + a.bind(next); mov_arg(Dst, RET); } @@ -769,6 +962,7 @@ void BeamModuleAssembler::emit_i_times(const ArgVal &Fail, * Result is returned in RET. Error is indicated by ZF. */ template void BeamGlobalAssembler::emit_bitwise_fallback_guard(T(*func_ptr)) { + emit_enter_frame(); emit_enter_runtime(); a.mov(ARG1, c_p); @@ -777,6 +971,7 @@ void BeamGlobalAssembler::emit_bitwise_fallback_guard(T(*func_ptr)) { runtime_call<3>(func_ptr); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.ret(); @@ -790,6 +985,7 @@ void BeamGlobalAssembler::emit_bitwise_fallback_body(T(*func_ptr), const ErtsCodeMFA *mfa) { Label error = a.newLabel(); + emit_enter_frame(); emit_enter_runtime(); /* Save original arguments for the error path. */ @@ -802,10 +998,10 @@ void BeamGlobalAssembler::emit_bitwise_fallback_body(T(*func_ptr), runtime_call<3>(func_ptr); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); - a.ret(); a.bind(error); @@ -817,7 +1013,7 @@ void BeamGlobalAssembler::emit_bitwise_fallback_body(T(*func_ptr), a.mov(getXRef(1), ARG2); a.mov(ARG4, imm(mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } @@ -830,20 +1026,32 @@ void BeamGlobalAssembler::emit_i_band_body_shared() { emit_bitwise_fallback_body(erts_band, &bif_mfa); } -void BeamModuleAssembler::emit_i_band(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Dst) { - Label generic = a.newLabel(), next = a.newLabel(); +void BeamModuleAssembler::emit_i_band(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Dst) { + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + mov_arg(RET, LHS); + if (RHS.isSmall() && Support::isInt32(RHS.as().get())) { + a.and_(RETd, imm(RHS.as().get())); + } else if (RHS.isSmall() && + Support::isInt32((Sint)RHS.as().get())) { + a.and_(RET, imm(RHS.as().get())); + } else { + mov_arg(ARG2, RHS); + a.and_(RET, ARG2); + } + mov_arg(Dst, RET); + return; + } mov_arg(ARG2, LHS); mov_arg(RET, RHS); - if (RHS.isImmed() && is_small(RHS.getValue())) { - emit_is_small(generic, ARG2); - } else { - emit_is_both_small(generic, RET, ARG2); - } + Label generic = a.newLabel(), next = a.newLabel(); + + emit_are_both_small(generic, LHS, ARG2, RHS, RET); /* TAG & TAG = TAG, so we don't need to tag it again. */ a.and_(RET, ARG2); @@ -851,9 +1059,9 @@ void BeamModuleAssembler::emit_i_band(const ArgVal &LHS, a.bind(generic); { - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_band_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_band_body_shared()); } @@ -878,20 +1086,29 @@ void BeamGlobalAssembler::emit_i_bor_body_shared() { emit_bitwise_fallback_body(erts_bor, &bif_mfa); } -void BeamModuleAssembler::emit_i_bor(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label generic = a.newLabel(), next = a.newLabel(); +void BeamModuleAssembler::emit_i_bor(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + mov_arg(RET, LHS); + if (RHS.isImmed() && Support::isInt32((Sint)RHS.as().get())) { + a.or_(RET, imm(RHS.as().get())); + } else { + mov_arg(ARG2, RHS); + a.or_(RET, ARG2); + } + mov_arg(Dst, RET); + return; + } mov_arg(ARG2, LHS); mov_arg(RET, RHS); - if (RHS.isImmed() && is_small(RHS.getValue())) { - emit_is_small(generic, ARG2); - } else { - emit_is_both_small(generic, RET, ARG2); - } + Label generic = a.newLabel(), next = a.newLabel(); + + emit_are_both_small(generic, LHS, ARG2, RHS, RET); /* TAG | TAG = TAG, so we don't need to tag it again. */ a.or_(RET, ARG2); @@ -899,9 +1116,9 @@ void BeamModuleAssembler::emit_i_bor(const ArgVal &Fail, a.bind(generic); { - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bor_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bor_body_shared()); } @@ -926,20 +1143,31 @@ void BeamGlobalAssembler::emit_i_bxor_body_shared() { emit_bitwise_fallback_body(erts_bxor, &bif_mfa); } -void BeamModuleAssembler::emit_i_bxor(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label generic = a.newLabel(), next = a.newLabel(); +void BeamModuleAssembler::emit_i_bxor(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + if (always_small(LHS) && always_small(RHS)) { + comment("skipped test for small operands since they are always small"); + mov_arg(RET, LHS); + if (RHS.isImmed() && Support::isInt32((Sint)RHS.as().get())) { + a.xor_(RET, imm(RHS.as().get() & ~_TAG_IMMED1_SMALL)); + } else { + /* TAG ^ TAG = 0, so we need to tag it again. */ + mov_arg(ARG2, RHS); + a.xor_(RET, ARG2); + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + } + mov_arg(Dst, RET); + return; + } mov_arg(ARG2, LHS); mov_arg(RET, RHS); - if (RHS.isImmed() && is_small(RHS.getValue())) { - emit_is_small(generic, ARG2); - } else { - emit_is_both_small(generic, RET, ARG2); - } + Label generic = a.newLabel(), next = a.newLabel(); + + emit_are_both_small(generic, LHS, ARG2, RHS, RET); /* TAG ^ TAG = 0, so we need to tag it again. */ a.xor_(RET, ARG2); @@ -948,9 +1176,9 @@ void BeamModuleAssembler::emit_i_bxor(const ArgVal &Fail, a.bind(generic); { - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bxor_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bxor_body_shared()); } @@ -964,6 +1192,8 @@ void BeamModuleAssembler::emit_i_bxor(const ArgVal &Fail, * * Result is returned in RET. Error is indicated by ZF. */ void BeamGlobalAssembler::emit_i_bnot_guard_shared() { + emit_enter_frame(); + /* Undo the speculative inversion in module code */ a.xor_(RET, imm(~_TAG_IMMED1_MASK)); @@ -974,6 +1204,7 @@ void BeamGlobalAssembler::emit_i_bnot_guard_shared() { runtime_call<2>(erts_bnot); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.ret(); @@ -987,6 +1218,8 @@ void BeamGlobalAssembler::emit_i_bnot_body_shared() { Label error = a.newLabel(); + emit_enter_frame(); + /* Undo the speculative inversion in module code */ a.xor_(RET, imm(~_TAG_IMMED1_MASK)); @@ -1000,10 +1233,10 @@ void BeamGlobalAssembler::emit_i_bnot_body_shared() { runtime_call<2>(erts_bnot); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); - a.ret(); a.bind(error); @@ -1013,13 +1246,13 @@ void BeamGlobalAssembler::emit_i_bnot_body_shared() { a.mov(getXRef(0), ARG1); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error_shared_prologue(); + a.jmp(labels[raise_exception]); } } -void BeamModuleAssembler::emit_i_bnot(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bnot(const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { Label next = a.newLabel(); mov_arg(RET, Src); @@ -1029,14 +1262,20 @@ void BeamModuleAssembler::emit_i_bnot(const ArgVal &Fail, /* Fall through to the generic path if the result is not a small, where the * above operation will be reverted. */ - a.mov(ARG1d, RETd); - a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); - a.short_().je(next); + if (always_one_of(Src)) { + comment("simplified test for small operand since it is a number"); + a.test(RETb, imm(TAG_PRIMARY_LIST)); + a.short_().jne(next); + } else { + a.mov(ARG1d, RETd); + a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); + a.short_().je(next); + } - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bnot_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bnot_body_shared()); } @@ -1060,19 +1299,26 @@ void BeamGlobalAssembler::emit_i_bsr_body_shared() { emit_bitwise_fallback_body(erts_bsr, &bif_mfa); } -void BeamModuleAssembler::emit_i_bsr(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bsr(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Dst) { Label generic = a.newLabel(), next = a.newLabel(); + bool need_generic = true; mov_arg(ARG2, LHS); - if (RHS.isImmed() && is_small(RHS.getValue())) { - Sint shift = signed_val(RHS.getValue()); + if (RHS.isSmall()) { + Sint shift = RHS.as().getSigned(); if (shift >= 0 && shift < SMALL_BITS - 1) { - emit_is_small(generic, ARG2); + if (always_small(LHS)) { + comment("skipped test for small left operand because it is " + "always small"); + need_generic = false; + } else { + emit_is_small(generic, LHS, ARG2); + } a.mov(RET, ARG2); @@ -1082,7 +1328,9 @@ void BeamModuleAssembler::emit_i_bsr(const ArgVal &LHS, a.sar(RET, imm(shift)); a.or_(RET, imm(_TAG_IMMED1_SMALL)); - a.short_().jmp(next); + if (need_generic) { + a.short_().jmp(next); + } } else { /* Constant shift is negative or too big to fit the `sar` * instruction, fall back to the generic path. */ @@ -1090,12 +1338,12 @@ void BeamModuleAssembler::emit_i_bsr(const ArgVal &LHS, } a.bind(generic); - { + if (need_generic) { mov_arg(RET, RHS); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bsr_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bsr_body_shared()); } @@ -1127,21 +1375,30 @@ static int count_leading_zeroes(UWord value) { return word_bits; } - UWord mask = UWORD_CONSTANT(1) << (word_bits - 1); - int count = 0; + return Support::clz(value); +} - while ((value & mask) == 0) { - mask >>= 1; - count++; +void BeamModuleAssembler::emit_i_bsl(const ArgSource &LHS, + const ArgSource &RHS, + const ArgLabel &Fail, + const ArgRegister &Dst) { + if (is_bsl_small(LHS, RHS)) { + comment("skipped tests because operands and result are always small"); + mov_arg(RET, LHS); + ERTS_CT_ASSERT(_TAG_IMMED1_MASK == _TAG_IMMED1_SMALL); + a.xor_(RET, imm(_TAG_IMMED1_MASK)); + if (RHS.isSmall()) { + a.shl(RET, imm(RHS.as().getSigned())); + } else { + mov_arg(x86::rcx, RHS); + a.shr(x86::rcx, imm(_TAG_IMMED1_SIZE)); + a.shl(RET, x86::cl); + } + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, RET); + return; } - return count; -} - -void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Fail, - const ArgVal &Dst) { bool inline_shift = hasCpuFeature(CpuFeatures::X86::kLZCNT); Label generic = a.newLabel(), next = a.newLabel(); @@ -1155,12 +1412,12 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, } else if (LHS.isLiteral() || RHS.isLiteral()) { /* At least one argument is not a small. */ inline_shift = false; - } else if (LHS.isImmed() && !is_small(LHS.getValue())) { + } else if (LHS.isImmed() && !LHS.isSmall()) { /* Invalid constant. */ inline_shift = false; } else if (RHS.isImmed() && - (!is_small(RHS.getValue()) || signed_val(RHS.getValue()) < 0 || - signed_val(RHS.getValue()) >= SMALL_BITS - 1)) { + (!RHS.isSmall() || RHS.as().getSigned() < 0 || + RHS.as().getSigned() >= SMALL_BITS - 1)) { /* Constant shift is invalid or always produces a bignum. */ inline_shift = false; } @@ -1170,7 +1427,7 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, ASSERT(!(LHS.isImmed() && RHS.isImmed())); - if (LHS.isMem()) { + if (LHS.isRegister()) { a.mov(ARG1, ARG2); a.mov(ARG3, ARG2); @@ -1184,13 +1441,18 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, * flag on shifts greater than 1. */ a.lzcnt(ARG3, ARG1); - a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(generic); + if (always_small(LHS)) { + comment("skipped test for small operand since it is always " + "small"); + } else { + a.and_(ARG1d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG1d, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); + } shiftLimit = ARG3; } else { - UWord value = LHS.getValue(); + UWord value = LHS.as().get(); if (signed_val(value) < 0) { value ^= ~(UWord)_TAG_IMMED1_MASK; @@ -1199,7 +1461,7 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, shiftLimit = imm(count_leading_zeroes(value)); } - if (RHS.isMem()) { + if (RHS.isRegister()) { /* Move RHS to the counter register, as it's the only one that can * be used for variable shifts. */ a.mov(x86::rcx, RET); @@ -1223,7 +1485,7 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, } else { ASSERT(!shiftLimit.isImm()); - shiftCount = imm(signed_val(RHS.getValue())); + shiftCount = imm(RHS.as().getSigned()); a.emit(x86::Inst::kIdCmp, shiftLimit, shiftCount); a.short_().jbe(generic); @@ -1238,9 +1500,9 @@ void BeamModuleAssembler::emit_i_bsl(const ArgVal &LHS, a.bind(generic); { - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bsl_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bsl_body_shared()); } diff --git a/erts/emulator/beam/jit/x86/instr_bif.cpp b/erts/emulator/beam/jit/x86/instr_bif.cpp index bc390b0fa89e..46a514fd348d 100644 --- a/erts/emulator/beam/jit/x86/instr_bif.cpp +++ b/erts/emulator/beam/jit/x86/instr_bif.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -34,6 +34,7 @@ extern "C" * * Result is returned in RET, error is indicated by ZF. */ void BeamGlobalAssembler::emit_i_bif_guard_shared() { + emit_enter_frame(); emit_enter_runtime(); a.mov(ARG1, c_p); @@ -42,6 +43,7 @@ void BeamGlobalAssembler::emit_i_bif_guard_shared() { runtime_call(ARG4, 3); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.ret(); @@ -53,6 +55,7 @@ void BeamGlobalAssembler::emit_i_bif_guard_shared() { void BeamGlobalAssembler::emit_i_bif_body_shared() { Label error = a.newLabel(); + emit_enter_frame(); emit_enter_runtime(); /* Save current BIF and argument vector for the error path. */ @@ -68,6 +71,7 @@ void BeamGlobalAssembler::emit_i_bif_body_shared() { a.short_().je(error); emit_leave_runtime(); + emit_leave_frame(); a.ret(); @@ -87,14 +91,15 @@ void BeamGlobalAssembler::emit_i_bif_body_shared() { runtime_call<1>(ubif2mfa); emit_leave_runtime(); + emit_leave_frame(); a.mov(ARG4, RET); - a.jmp(labels[handle_error_shared_prologue]); + a.jmp(labels[raise_exception]); } } void BeamModuleAssembler::emit_setup_guard_bif(const std::vector &args, - const ArgVal &bif) { + const ArgWord &Bif) { bool is_contiguous_mem = false; ASSERT(args.size() > 0 && args.size() <= 3); @@ -102,12 +107,12 @@ void BeamModuleAssembler::emit_setup_guard_bif(const std::vector &args, /* If the guard BIF's arguments are in memory and continuous, for example * `map_get(x0, x1)`, then we can pass the address of the first argument * instead of filling in the argument vector. */ - is_contiguous_mem = args.size() && args[0].isMem(); + is_contiguous_mem = args.size() && args[0].isRegister(); for (size_t i = 1; i < args.size() && is_contiguous_mem; i++) { - const ArgVal &curr = args[i], &prev = args[i - 1]; + const ArgSource &curr = args[i], &prev = args[i - 1]; - is_contiguous_mem = curr.getType() == prev.getType() && - curr.getValue() == prev.getValue() + 1; + is_contiguous_mem = + ArgVal::memory_relation(prev, curr) == ArgVal::consecutive; } if (is_contiguous_mem) { @@ -120,18 +125,24 @@ void BeamModuleAssembler::emit_setup_guard_bif(const std::vector &args, } } - mov_arg(ARG4, bif); + if (logger.file()) { + ErtsCodeMFA *mfa = ubif2mfa((void *)Bif.get()); + if (mfa) { + comment("UBIF: %T/%d", mfa->function, mfa->arity); + } + } + mov_arg(ARG4, Bif); } -void BeamModuleAssembler::emit_i_bif1(const ArgVal &Src1, - const ArgVal &Fail, - const ArgVal &Bif, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bif1(const ArgSource &Src1, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { emit_setup_guard_bif({Src1}, Bif); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bif_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bif_body_shared()); } @@ -139,16 +150,16 @@ void BeamModuleAssembler::emit_i_bif1(const ArgVal &Src1, mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bif2(const ArgVal &Src1, - const ArgVal &Src2, - const ArgVal &Fail, - const ArgVal &Bif, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bif2(const ArgSource &Src1, + const ArgSource &Src2, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { emit_setup_guard_bif({Src1, Src2}, Bif); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bif_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bif_body_shared()); } @@ -156,17 +167,17 @@ void BeamModuleAssembler::emit_i_bif2(const ArgVal &Src1, mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bif3(const ArgVal &Src1, - const ArgVal &Src2, - const ArgVal &Src3, - const ArgVal &Fail, - const ArgVal &Bif, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bif3(const ArgSource &Src1, + const ArgSource &Src2, + const ArgSource &Src3, + const ArgLabel &Fail, + const ArgWord &Bif, + const ArgRegister &Dst) { emit_setup_guard_bif({Src1, Src2, Src3}, Bif); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { safe_fragment_call(ga->get_i_bif_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { safe_fragment_call(ga->get_i_bif_body_shared()); } @@ -180,34 +191,34 @@ void BeamModuleAssembler::emit_i_bif3(const ArgVal &Src1, * to align the call targeting the shared fragment. */ -void BeamModuleAssembler::emit_nofail_bif1(const ArgVal &Src1, - const ArgVal &Bif, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_nofail_bif1(const ArgSource &Src1, + const ArgWord &Bif, + const ArgRegister &Dst) { emit_setup_guard_bif({Src1}, Bif); safe_fragment_call(ga->get_i_bif_guard_shared()); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_nofail_bif2(const ArgVal &Src1, - const ArgVal &Src2, - const ArgVal &Bif, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_nofail_bif2(const ArgSource &Src1, + const ArgSource &Src2, + const ArgWord &Bif, + const ArgRegister &Dst) { emit_setup_guard_bif({Src1, Src2}, Bif); safe_fragment_call(ga->get_i_bif_guard_shared()); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_length_setup(const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_length_setup(const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Src) { x86::Mem trap_state; /* Store trap state after the currently live registers. There's an extra 3 * registers beyond the ordinary ones that we're free to use for whatever * purpose. */ ERTS_CT_ASSERT(ERTS_X_REGS_ALLOCATED - MAX_REG >= 3); - ASSERT(Live.getValue() <= MAX_REG); - trap_state = getXRef(Live.getValue()); + ASSERT(Live.get() <= MAX_REG); + trap_state = getXRef(Live.get()); /* Remainder of the list. */ mov_arg(trap_state, Src); @@ -217,7 +228,7 @@ void BeamModuleAssembler::emit_i_length_setup(const ArgVal &Fail, /* Original argument. This is only needed for exceptions and can be safely * skipped in guards. */ - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { x86::Mem original_argument; original_argument = trap_state.cloneAdjusted(2 * sizeof(Eterm)); @@ -238,6 +249,8 @@ x86::Mem BeamGlobalAssembler::emit_i_length_common(Label fail, int state_size) { trap_state = getXRef(0); trap_state.setIndex(ARG2, 3); + emit_enter_frame(); + /* Save arguments for error/trapping path. */ a.mov(TMP_MEM1q, ARG2); a.mov(TMP_MEM2q, ARG3); @@ -249,6 +262,7 @@ x86::Mem BeamGlobalAssembler::emit_i_length_common(Label fail, int state_size) { runtime_call<2>(erts_trapping_length_1); emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(trap); @@ -268,7 +282,7 @@ x86::Mem BeamGlobalAssembler::emit_i_length_common(Label fail, int state_size) { a.add(ARG2, imm(state_size)); /* We'll find our way back through the entry address (ARG3). */ - emit_discard_cp(); + a.add(x86::rsp, imm(sizeof(UWord))); a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), imm(0)); a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), ARG2); @@ -298,7 +312,7 @@ void BeamGlobalAssembler::emit_i_length_body_shared() { a.mov(getXRef(0), ARG1); a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error(); + a.jmp(labels[raise_exception]); } } @@ -312,14 +326,14 @@ void BeamGlobalAssembler::emit_i_length_guard_shared() { a.bind(error); { - mov_imm(RET, 0); + a.sub(RET, RET); a.ret(); } } -void BeamModuleAssembler::emit_i_length(const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_length(const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { Label entry = a.newLabel(); align_erlang_cp(); @@ -328,13 +342,13 @@ void BeamModuleAssembler::emit_i_length(const ArgVal &Fail, mov_arg(ARG2, Live); a.lea(ARG3, x86::qword_ptr(entry)); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { /* The return address is discarded when yielding, so it doesn't need to * be aligned. */ safe_fragment_call(ga->get_i_length_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { - fragment_call(ga->get_i_length_body_shared()); + safe_fragment_call(ga->get_i_length_body_shared()); } mov_arg(Dst, RET); @@ -375,31 +389,35 @@ static Eterm debug_call_light_bif(Process *c_p, * RET = BIF pointer */ void BeamGlobalAssembler::emit_call_light_bif_shared() { - /* We use the HTOP and FCALLS registers as they are - not used on the runtime-stack and are caller save. */ + x86::Mem entry_mem = TMP_MEM1q, export_mem = TMP_MEM2q, + mbuf_mem = TMP_MEM3q; + + Label trace = a.newLabel(), yield = a.newLabel(); - x86::Gp I = HTOP, exp = FCALLS; + emit_enter_frame(); - Label error = a.newLabel(), trace = a.newLabel(), trap = a.newLabel(), - yield = a.newLabel(), call_save_calls = a.newLabel(), - call_bif = a.newLabel(), gc_after_bif_call = a.newLabel(), - check_bif_return = a.newLabel(); + /* Spill everything we may need on the error and GC paths. */ + a.mov(ARG1, x86::qword_ptr(c_p, offsetof(Process, mbuf))); + a.mov(entry_mem, ARG3); + a.mov(export_mem, ARG4); + a.mov(mbuf_mem, ARG1); - /* Check if we should trace this bif call */ + /* Check if we should trace this bif call or handle save_calls. Both + * variants dispatch through the export entry. */ a.cmp(x86::dword_ptr(ARG4, offsetof(Export, is_bif_traced)), imm(0)); a.jne(trace); + a.cmp(active_code_ix, imm(ERTS_SAVE_CALLS_CODE_IX)); + a.je(trace); a.dec(FCALLS); a.jle(yield); { + Label check_bif_return = a.newLabel(), gc_after_bif_call = a.newLabel(); + emit_enter_runtime(); - /* Spill the arguments we may need on the error path. */ - a.mov(I, ARG3); - a.mov(exp, ARG4); - #ifdef ERTS_MSACC_EXTENDED_STATES { Label skip_msacc = a.newLabel(); @@ -407,7 +425,7 @@ void BeamGlobalAssembler::emit_call_light_bif_shared() { a.cmp(erts_msacc_cache, imm(0)); a.short_().je(skip_msacc); - a.mov(TMP_MEM1q, RET); + a.mov(TMP_MEM4q, ARG3); a.mov(ARG1, erts_msacc_cache); a.mov(ARG2, @@ -415,29 +433,23 @@ void BeamGlobalAssembler::emit_call_light_bif_shared() { a.mov(ARG3, RET); runtime_call<3>(erts_msacc_set_bif_state); - a.mov(ARG3, I); - a.mov(RET, TMP_MEM1q); + a.mov(ARG3, TMP_MEM4q); a.bind(skip_msacc); } #endif - /* Check if we need to call save_calls */ - a.cmp(active_code_ix, imm(ERTS_SAVE_CALLS_CODE_IX)); - a.je(call_save_calls); - a.bind(call_bif); - a.mov(ARG1, x86::qword_ptr(c_p, offsetof(Process, mbuf))); - a.mov(TMP_MEM1q, ARG1); - - /* ARG3 and RET have been set earlier. */ - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); + { + /* Call the BIF proper. ARG3 and RET have been set earlier. */ + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); #if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) - a.mov(ARG4, RET); - runtime_call<4>(debug_call_light_bif); + a.mov(ARG4, RET); + runtime_call<4>(debug_call_light_bif); #else - runtime_call(RET, 3); + runtime_call(RET, 3); #endif + } #ifdef ERTS_MSACC_EXTENDED_STATES { @@ -445,180 +457,153 @@ void BeamGlobalAssembler::emit_call_light_bif_shared() { a.cmp(erts_msacc_cache, imm(0)); a.short_().je(skip_msacc); - - /* update cache if it was changed in the bif. - TMP_MEM1q is already taken to save ARG1 above */ - a.mov(TMP_MEM2q, RET); - a.lea(ARG1, erts_msacc_cache); - runtime_call<1>(erts_msacc_update_cache); - a.mov(RET, TMP_MEM2q); - - /* set state to emulator if msacc has been enabled */ - a.cmp(erts_msacc_cache, imm(0)); - a.short_().je(skip_msacc); - a.mov(ARG1, erts_msacc_cache); - a.mov(ARG2, imm(ERTS_MSACC_STATE_EMULATOR)); - a.mov(ARG3, imm(1)); - runtime_call<3>(erts_msacc_set_state_m__); - a.mov(RET, TMP_MEM2q); - + { + /* Update cache if it was changed in the BIF, stashing the + * return value in TMP_MEM4q. */ + a.mov(TMP_MEM4q, RET); + a.lea(ARG1, erts_msacc_cache); + runtime_call<1>(erts_msacc_update_cache); + a.mov(RET, TMP_MEM4q); + + /* set state to emulator if msacc has been enabled */ + a.cmp(erts_msacc_cache, imm(0)); + a.short_().je(skip_msacc); + + a.mov(ARG1, erts_msacc_cache); + a.mov(ARG2, imm(ERTS_MSACC_STATE_EMULATOR)); + a.mov(ARG3, imm(1)); + runtime_call<3>(erts_msacc_set_state_m__); + a.mov(RET, TMP_MEM4q); + } a.bind(skip_msacc); } #endif + /* We must update the active code index in case another process has + * loaded new code, as the result of this BIF may be observable on + * both ends. + * + * It doesn't matter whether the BIF modifies anything; if process + * A loads new code and calls erlang:monotonic_time/0 soon after, + * we'd break the illusion of atomic upgrades if process B still + * ran old code after seeing a later timestamp from its own call to + * erlang:monotonic_time/0. */ + emit_leave_runtime(); + /* ERTS_IS_GC_DESIRED_INTERNAL */ { - a.mov(ARG2, x86::qword_ptr(c_p, offsetof(Process, stop))); - a.mov(ARG3, RET); - a.mov(ARG5, x86::qword_ptr(c_p, offsetof(Process, htop))); + /* Test whether GC is forced. */ + a.test(x86::dword_ptr(c_p, offsetof(Process, flags)), + imm(F_FORCE_GC | F_DISABLE_GC)); + a.jne(gc_after_bif_call); - /* Test if binary heap size should trigger gc */ - a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, bin_vheap_sz))); + /* Test if binary heap size should trigger GC. */ + a.mov(ARG1, x86::qword_ptr(c_p, offsetof(Process, bin_vheap_sz))); a.cmp(x86::qword_ptr(c_p, offsetof(Process, off_heap.overhead)), - RET); - a.mov(RETd, x86::dword_ptr(c_p, offsetof(Process, flags))); - a.seta(x86::cl); /* Clobber ARG1 on windows and ARG4 on Linux */ - a.and_(RETd, imm(F_FORCE_GC | F_DISABLE_GC)); - a.or_(x86::cl, RETb); - a.jne(gc_after_bif_call); + ARG1); + a.ja(gc_after_bif_call); /* Test if heap fragment size is larger than remaining heap size. */ - a.mov(RET, ARG2); - a.sub(RET, ARG5); - a.sar(RET, imm(3)); - a.cmp(RET, x86::qword_ptr(c_p, offsetof(Process, mbuf_sz))); + a.mov(ARG2, x86::qword_ptr(c_p, offsetof(Process, mbuf_sz))); + a.lea(ARG1, x86::qword_ptr(HTOP, ARG2, 0, 3)); + a.cmp(E, ARG1); a.jl(gc_after_bif_call); } - /* - ARG2 is set to E - ARG3 is set to bif return - ARG5 is set to HTOP - - HTOP is exp - E_saved|E is I - */ + /* ! FALL THROUGH ! */ a.bind(check_bif_return); - emit_test_the_non_value(ARG3); - - /* NOTE: Short won't reach if JIT_HARD_DEBUG is defined. */ - a.je(trap); - - a.mov(HTOP, ARG5); -#ifdef NATIVE_ERLANG_STACK - a.mov(E_saved, ARG2); -#else - a.mov(E, ARG2); -#endif - - /* We must update the active code index in case another process has - * loaded new code, as the result of this BIF may be observable on both - * ends. - * - * It doesn't matter whether the BIF modifies anything; if process A - * loads new code and calls erlang:monotonic_time/0 soon after, we'd - * break the illusion of atomic upgrades if process B still ran old code - * after seeing a later timestamp from its own call to - * erlang:monotonic_time/0. */ - - emit_leave_runtime(); - - a.mov(getXRef(0), ARG3); - a.ret(); - - a.bind(call_save_calls); { - /* Stash the bif function pointer */ - a.mov(TMP_MEM1q, RET); + Label trap = a.newLabel(), error = a.newLabel(); - /* Setup the arguments to call */ - a.mov(ARG1, c_p); - a.mov(ARG2, exp); - runtime_call<2>(save_calls); - - /* Restore RET and ARG3 to the values expected - by the bif call */ - a.mov(RET, TMP_MEM1q); - a.mov(ARG3, I); - a.jmp(call_bif); - } + emit_test_the_non_value(RET); + a.short_().je(trap); - a.bind(trap); - { - a.cmp(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(TRAP)); - a.short_().jne(error); + a.mov(getXRef(0), RET); - emit_leave_runtime(); + emit_leave_frame(); + a.ret(); + + a.bind(trap); + { + a.cmp(x86::qword_ptr(c_p, offsetof(Process, freason)), + imm(TRAP)); + a.short_().jne(error); #if !defined(NATIVE_ERLANG_STACK) - a.pop(getCPRef()); + a.pop(getCPRef()); #endif - /* Trap out, our return address is on the Erlang stack. - * - * The BIF_TRAP macros all set up c_p->arity and c_p->current, so - * we can use a simplified context switch. */ - a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, i))); - a.jmp(labels[context_switch_simplified]); - } - - a.bind(error); - { - a.mov(ARG4, exp); - a.mov(RET, I); - - /* Update::eCodeIndex clobbers ARG1 + ARG2 */ - emit_leave_runtime(); + /* Trap out, our return address is on the Erlang stack. + * + * The BIF_TRAP macros all set up c_p->arity and c_p->current, + * so we can use a simplified context switch. */ + a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, i))); + a.jmp(labels[context_switch_simplified]); + } - /* handle_error_shared needs the entry address in ARG2 */ - a.mov(ARG2, RET); + a.bind(error); + { + a.mov(ARG2, entry_mem); + a.mov(ARG4, export_mem); + a.add(ARG4, imm(offsetof(Export, info.mfa))); #if !defined(NATIVE_ERLANG_STACK) - /* Discard the continuation pointer as it will never be used. */ - emit_discard_cp(); + /* Discard the continuation pointer as it will never be + * used. */ + emit_unwind_frame(); #endif - /* get_handle_error expects current PC in ARG2 and MFA in ARG4. */ - a.lea(ARG4, x86::qword_ptr(ARG4, offsetof(Export, info.mfa))); - - /* Overwrite the return address with the entry address to ensure - * that only the entry address ends up in the stack trace. */ - a.mov(x86::qword_ptr(E), ARG2); - - a.jmp(labels[handle_error_shared]); + /* Overwrite the return address with the entry address to + * ensure that only the entry address ends up in the stack + * trace. */ + if (erts_frame_layout == ERTS_FRAME_LAYOUT_RA) { + a.mov(x86::qword_ptr(E), ARG2); + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); + a.mov(x86::qword_ptr(E, 8), ARG2); + } + + a.jmp(labels[raise_exception_shared]); + } } a.bind(gc_after_bif_call); { + a.mov(ARG2, mbuf_mem); + a.mov(ARG5, export_mem); + a.mov(ARG5, x86::qword_ptr(ARG5, offsetof(Export, info.mfa.arity))); + + emit_enter_runtime(); + a.mov(ARG1, c_p); - a.mov(ARG2, TMP_MEM1q); - /* ARG3 already contains result */ + a.mov(ARG3, RET); load_x_reg_array(ARG4); - a.mov(ARG5, x86::qword_ptr(exp, offsetof(Export, info.mfa.arity))); runtime_call<5>(erts_gc_after_bif_call_lhf); - a.mov(ARG3, RET); - a.mov(ARG5, x86::qword_ptr(c_p, offsetof(Process, htop))); - a.mov(ARG2, x86::qword_ptr(c_p, offsetof(Process, stop))); + + emit_leave_runtime(); + a.jmp(check_bif_return); } } a.bind(trace); { - /* Call the export entry instead of the BIF. If we use the - * native stack as the Erlang stack our return address is - * already on the Erlang stack. Otherwise we will have to move - * the return address from the native stack to the Erlang - * stack. */ + /* Tail call the export entry instead of the BIF. If we use the native + * stack as the Erlang stack our return address is already on the + * Erlang stack. Otherwise we will have to move the return address from + * the native stack to the Erlang stack. */ + + emit_leave_frame(); #if !defined(NATIVE_ERLANG_STACK) /* The return address must be on the Erlang stack. */ a.pop(getCPRef()); #endif - x86::Mem destination = emit_setup_export_call(ARG4); + x86::Mem destination = emit_setup_dispatchable_call(ARG4); a.jmp(destination); } @@ -630,23 +615,27 @@ void BeamGlobalAssembler::emit_call_light_bif_shared() { a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG4); /* We'll find our way back through ARG3 (entry address). */ - emit_discard_cp(); + emit_unwind_frame(); a.jmp(labels[context_switch_simplified]); } } -void BeamModuleAssembler::emit_call_light_bif(const ArgVal &Bif, - const ArgVal &Exp) { +void BeamModuleAssembler::emit_call_light_bif(const ArgWord &Bif, + const ArgExport &Exp) { Label entry = a.newLabel(); align_erlang_cp(); a.bind(entry); - make_move_patch(ARG4, imports[Exp.getValue()].patches); - a.mov(RET, imm(Bif.getValue())); + mov_arg(ARG4, Exp); + a.mov(RET, imm(Bif.get())); a.lea(ARG3, x86::qword_ptr(entry)); + if (logger.file()) { + BeamFile_ImportEntry *e = &beam->imports.entries[Exp.get()]; + comment("BIF: %T:%T/%d", e->module, e->function, e->arity); + } fragment_call(ga->get_call_light_bif_shared()); } @@ -654,9 +643,8 @@ void BeamModuleAssembler::emit_send() { Label entry = a.newLabel(); /* This is essentially a mirror of call_light_bif, there's no point to - * specializing send/2 anymore. - * - * FIXME: Rewrite this to an ordinary BIF in the loader instead. */ + * specializing send/2 anymore. We do it here because it's far more work to + * do it in the loader. */ align_erlang_cp(); a.bind(entry); @@ -667,6 +655,10 @@ void BeamModuleAssembler::emit_send() { fragment_call(ga->get_call_light_bif_shared()); } +void BeamModuleAssembler::emit_nif_start() { + /* load time only instruction */ +} + void BeamGlobalAssembler::emit_bif_nif_epilogue(void) { Label check_trap = a.newLabel(), trap = a.newLabel(), error = a.newLabel(); @@ -696,6 +688,9 @@ void BeamGlobalAssembler::emit_bif_nif_epilogue(void) { comment("Do return and dispatch to it"); a.mov(getXRef(0), RET); + + emit_leave_frame(); + #ifdef NATIVE_ERLANG_STACK a.ret(); #else @@ -745,7 +740,7 @@ void BeamGlobalAssembler::emit_bif_nif_epilogue(void) { a.mov(ARG2, RET); a.mov(ARG4, x86::qword_ptr(c_p, offsetof(Process, current))); - a.jmp(labels[handle_error_shared]); + a.jmp(labels[raise_exception_shared]); } } @@ -779,17 +774,16 @@ void BeamGlobalAssembler::emit_call_bif_shared(void) { a.short_().je(skip_msacc); a.mov(TMP_MEM1q, ARG3); - a.mov(TMP_MEM2q, ARG4); - a.mov(TMP_MEM3q, ARG5); + a.mov(TMP_MEM2q, ARG5); a.mov(ARG1, erts_msacc_cache); a.mov(ARG2, x86::qword_ptr(ARG2, offsetof(ErtsCodeMFA, module))); a.mov(ARG3, ARG4); runtime_call<3>(erts_msacc_set_bif_state); + a.mov(ARG4, RET); a.mov(ARG3, TMP_MEM1q); - a.mov(ARG4, TMP_MEM2q); - a.mov(ARG5, TMP_MEM3q); + a.mov(ARG5, TMP_MEM2q); a.bind(skip_msacc); } #endif @@ -814,41 +808,56 @@ void BeamGlobalAssembler::emit_dispatch_bif(void) { * `info` structure. */ a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, i))); - ERTS_CT_ASSERT(offsetof(ErtsNativeFunc, trampoline.trace) == + ERTS_CT_ASSERT(offsetof(ErtsNativeFunc, trampoline.call_bif_nif) == sizeof(ErtsCodeInfo)); ssize_t mfa_offset = offsetof(ErtsNativeFunc, trampoline.info.mfa) - - offsetof(ErtsNativeFunc, trampoline.trace); + offsetof(ErtsNativeFunc, trampoline.call_bif_nif); a.lea(ARG2, x86::qword_ptr(ARG3, mfa_offset)); ssize_t dfunc_offset = offsetof(ErtsNativeFunc, trampoline.dfunc) - - offsetof(ErtsNativeFunc, trampoline.trace); + offsetof(ErtsNativeFunc, trampoline.call_bif_nif); a.mov(ARG4, x86::qword_ptr(ARG3, dfunc_offset)); a.jmp(labels[call_bif_shared]); } -void BeamModuleAssembler::emit_call_bif(const ArgVal &Func) { +void BeamModuleAssembler::emit_call_bif(const ArgWord &Func) { int mfa_offset = -(int)sizeof(ErtsCodeMFA); - a.lea(ARG2, x86::qword_ptr(currLabel, mfa_offset)); - a.lea(ARG3, x86::qword_ptr(currLabel)); - mov_arg(ARG4, Func); + Label entry = a.newLabel(); + + /* This is _always_ the first instruction in a function and replaces the + * yield test that would otherwise add a frame, so we must add a frame + * here. */ + emit_enter_frame(); - abs_jmp(ga->get_call_bif_shared()); + /* Yield entry point; must be after entering frame. */ + a.bind(entry); + { + a.lea(ARG2, x86::qword_ptr(current_label, mfa_offset)); + a.lea(ARG3, x86::qword_ptr(entry)); + mov_arg(ARG4, Func); + + a.jmp(resolve_fragment(ga->get_call_bif_shared())); + } } -void BeamModuleAssembler::emit_call_bif_mfa(const ArgVal &M, - const ArgVal &F, - const ArgVal &A) { +void BeamModuleAssembler::emit_call_bif_mfa(const ArgAtom &M, + const ArgAtom &F, + const ArgWord &A) { BeamInstr func; Export *e; - e = erts_active_export_entry(M.getValue(), F.getValue(), A.getValue()); + e = erts_active_export_entry(M.get(), F.get(), A.get()); ASSERT(e != NULL && e->bif_number != -1); + comment("HBIF: %T:%T/%d", + e->info.mfa.module, + e->info.mfa.function, + A.get()); func = (BeamInstr)bif_table[e->bif_number].f; - emit_call_bif(ArgVal(ArgVal::i, func)); + emit_call_bif(ArgWord(func)); } void BeamGlobalAssembler::emit_call_nif_early() { @@ -866,6 +875,7 @@ void BeamGlobalAssembler::emit_call_nif_early() { a.test(ARG2, imm(sizeof(UWord) - 1)); a.short_().je(next); + comment("# Return address isn't word-aligned"); a.ud2(); a.bind(next); @@ -879,11 +889,14 @@ void BeamGlobalAssembler::emit_call_nif_early() { emit_leave_runtime(); - /* We won't return to the original code. */ - emit_discard_cp(); + /* We won't return to the original code. We KNOW that the stack points at + * a return address. */ + a.add(x86::rsp, imm(8)); /* Emulate `emit_call_nif`, loading the current (phony) instruction - * pointer into ARG2. */ + * pointer into ARG2. We push a (redundant) frame pointer to match the + * corresponding `emit_leave_frame` in `call_nif_shared`. */ + emit_enter_frame(); a.mov(ARG3, RET); a.jmp(labels[call_nif_shared]); } @@ -932,48 +945,71 @@ void BeamGlobalAssembler::emit_dispatch_nif(void) { * * ErtsNativeFunc already follows the NIF call layout, so we don't need to * do anything beyond loading the address. */ - ERTS_CT_ASSERT(offsetof(ErtsNativeFunc, trampoline.trace) == + ERTS_CT_ASSERT(offsetof(ErtsNativeFunc, trampoline.call_bif_nif) == sizeof(ErtsCodeInfo)); a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, i))); a.jmp(labels[call_nif_shared]); } -/* WARNING: This stub is memcpy'd, so all code herein must be explicitly - * position-independent. */ -void BeamModuleAssembler::emit_call_nif(const ArgVal &Func, - const ArgVal &NifMod, - const ArgVal &DirtyFunc) { - Label dispatch = a.newLabel(); - uint64_t val; - - /* The start of this function has to mimic the layout of ErtsNativeFunc. */ - a.jmp(dispatch); /* call_op */ - - a.align(AlignMode::kCode, 8); - /* ErtsNativeFunc.dfunc */ - val = Func.getValue(); - a.embed(&val, sizeof(val)); - /* ErtsNativeFunc.m */ - val = NifMod.getValue(); - a.embed(&val, sizeof(val)); - /* ErtsNativeFunc.func */ - val = DirtyFunc.getValue(); - a.embed(&val, sizeof(val)); - - /* The real code starts here */ - a.bind(dispatch); +void BeamGlobalAssembler::emit_call_nif_yield_helper() { + Label yield = a.newLabel(); + + a.dec(FCALLS); + a.short_().jl(yield); + a.jmp(labels[call_nif_shared]); + + a.bind(yield); { - Label yield = a.newLabel(); + int mfa_offset = -(int)sizeof(ErtsCodeMFA); + int arity_offset = mfa_offset + (int)offsetof(ErtsCodeMFA, arity); - a.lea(ARG3, x86::qword_ptr(currLabel)); + a.mov(ARG1, x86::qword_ptr(ARG3, arity_offset)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), ARG1); - a.dec(FCALLS); - a.jl(yield); + a.lea(ARG1, x86::qword_ptr(ARG3, mfa_offset)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG1); - pic_jmp(ga->get_call_nif_shared()); + /* Yield to `dispatch` rather than `entry` to avoid pushing too many + * frames to the stack. See `emit_call_nif` for details. */ + a.add(ARG3, imm(BEAM_ASM_NFUNC_SIZE + sizeof(UWord[3]))); + a.jmp(labels[context_switch_simplified]); + } +} - a.bind(yield); - pic_jmp(ga->get_context_switch()); +/* WARNING: This stub is memcpy'd, so all code herein must be explicitly + * position-independent. */ +void BeamModuleAssembler::emit_call_nif(const ArgWord &Func, + const ArgWord &NifMod, + const ArgWord &DirtyFunc) { + Label entry = a.newLabel(), dispatch = a.newLabel(); + + /* The start of this function must mimic the layout of ErtsNativeFunc. + * + * We jump here on the very first entry, pushing a stack frame if + * applicable. */ + a.bind(entry); + { + emit_enter_frame(); + a.short_().jmp(dispatch); /* call_op */ + + a.align(AlignMode::kCode, 8); + /* ErtsNativeFunc.dfunc */ + a.embedUInt64(Func.get()); + /* ErtsNativeFunc.m */ + a.embedUInt64(NifMod.get()); + /* ErtsNativeFunc.func */ + a.embedUInt64(DirtyFunc.get()); + } + + /* `emit_call_nif_yield_helper` relies on this to compute the address of + * `dispatch` */ + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + BEAM_ASM_NFUNC_SIZE + sizeof(UWord[3])); + + a.bind(dispatch); + { + a.lea(ARG3, x86::qword_ptr(current_label)); + pic_jmp(ga->get_call_nif_yield_helper()); } } @@ -985,26 +1021,29 @@ void BeamGlobalAssembler::emit_i_load_nif_shared() { a.mov(TMP_MEM1q, ARG2); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); /* ARG2 has already been set by caller */ load_x_reg_array(ARG3); runtime_call<3>(beam_jit_load_nif); - emit_leave_runtime(); + emit_leave_runtime(); a.cmp(RET, RET_NIF_yield); a.short_().je(yield); + + /* We entered the frame in module code. */ + emit_leave_frame(); + a.cmp(RET, RET_NIF_success); a.short_().jne(error); - a.ret(); a.bind(error); { a.mov(ARG4, imm(&bif_mfa)); - emit_handle_error(); + a.jmp(labels[raise_exception]); } a.bind(yield); @@ -1014,10 +1053,49 @@ void BeamGlobalAssembler::emit_i_load_nif_shared() { } } +static ErtsCodePtr get_on_load_address(Process *c_p, Eterm module) { + const Module *modp = erts_get_module(module, erts_active_code_ix()); + + if (modp && modp->on_load) { + const BeamCodeHeader *hdr = (modp->on_load)->code_hdr; + + if (hdr) { + return erts_codeinfo_to_code(hdr->on_load); + } + } + + c_p->freason = BADARG; + + return NULL; +} + +/* Implements the internal and undocumented erlang:call_on_load_function/1, + * which is tricky to implement in the face of frame pointers. */ +void BeamModuleAssembler::emit_i_call_on_load_function() { + static ErtsCodeMFA mfa = {am_erlang, am_call_on_load_function, 1}; + Label next = a.newLabel(); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + a.mov(ARG2, getXRef(0)); + runtime_call<2>(get_on_load_address); + + emit_leave_runtime(); + + a.test(RET, RET); + a.jne(next); + + emit_raise_exception(&mfa); + + a.bind(next); + erlang_call(RET, ARG1); +} + #ifdef NATIVE_ERLANG_STACK void BeamModuleAssembler::emit_i_load_nif() { - Label entry = a.newLabel(), next = a.newLabel(); + Label entry = a.newLabel(), yield = a.newLabel(), next = a.newLabel(); /* i_load_nif is a rewrite of a call_ext instruction, so we'll body-call * ourselves to ensure the stack is consistent with that. This greatly @@ -1028,8 +1106,13 @@ void BeamModuleAssembler::emit_i_load_nif() { align_erlang_cp(); a.bind(entry); { - a.lea(ARG2, x86::qword_ptr(entry)); - abs_jmp(ga->get_i_load_nif_shared()); + emit_enter_frame(); + + a.bind(yield); + { + a.lea(ARG2, x86::qword_ptr(yield)); + a.jmp(resolve_fragment(ga->get_i_load_nif_shared())); + } } a.bind(next); @@ -1045,26 +1128,26 @@ void BeamModuleAssembler::emit_i_load_nif() { align_erlang_cp(); a.bind(entry); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); - a.lea(ARG2, x86::qword_ptr(currLabel)); + a.lea(ARG2, x86::qword_ptr(current_label)); load_x_reg_array(ARG3); runtime_call<3>(beam_jit_load_nif); - emit_leave_runtime(); + emit_leave_runtime(); a.cmp(RET, imm(RET_NIF_yield)); a.je(schedule); a.cmp(RET, imm(RET_NIF_success)); a.je(next); - emit_handle_error(currLabel, &mfa); + emit_raise_exception(current_label, &mfa); a.bind(schedule); { a.lea(ARG3, x86::qword_ptr(entry)); - abs_jmp(ga->get_context_switch_simplified()); + a.jmp(resolve_fragment(ga->get_context_switch_simplified())); } a.bind(next); diff --git a/erts/emulator/beam/jit/x86/instr_bs.cpp b/erts/emulator/beam/jit/x86/instr_bs.cpp index e21ee18ba707..a4c801d43d7b 100644 --- a/erts/emulator/beam/jit/x86/instr_bs.cpp +++ b/erts/emulator/beam/jit/x86/instr_bs.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -19,6 +19,7 @@ */ #include "beam_asm.hpp" +#include extern "C" { @@ -33,14 +34,14 @@ extern "C" * * Returns -1 when the field check always fails, 1 if it may fail, and 0 if it * never fails. */ -int BeamModuleAssembler::emit_bs_get_field_size(const ArgVal &Size, +int BeamModuleAssembler::emit_bs_get_field_size(const ArgSource &Size, int unit, Label fail, const x86::Gp &out, unsigned max_size) { if (Size.isImmed()) { - if (is_small(Size.getValue())) { - Sint sval = signed_val(Size.getValue()); + if (Size.isSmall()) { + Sint sval = Size.as().getSigned(); if (sval < 0) { /* badarg */ @@ -57,12 +58,22 @@ int BeamModuleAssembler::emit_bs_get_field_size(const ArgVal &Size, a.jmp(fail); return -1; } else { + bool can_fail = true; + mov_arg(RET, Size); - a.mov(ARG3d, RETd); - a.and_(ARG3d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG3d, imm(_TAG_IMMED1_SMALL)); - a.jne(fail); + if (always_small(Size)) { + auto [min, max] = getClampedRange(Size); + can_fail = + !(0 <= min && (max >> (SMALL_BITS - ERL_UNIT_BITS)) == 0); + comment("simplified segment size checks because " + "the types are known"); + } else { + a.mov(ARG3d, RETd); + a.and_(ARG3d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG3d, imm(_TAG_IMMED1_SMALL)); + a.jne(fail); + } if (max_size) { ASSERT(Support::isInt32((Sint)make_small(max_size))); @@ -70,19 +81,35 @@ int BeamModuleAssembler::emit_bs_get_field_size(const ArgVal &Size, a.ja(fail); } - if (unit == 1) { + if (unit == 0) { + mov_imm(RET, 0); + } else if (unit == 1) { a.sar(RET, imm(_TAG_IMMED1_SIZE)); - a.js(fail); + if (can_fail) { + a.js(fail); + } + } else if (!can_fail && Support::isPowerOf2(unit)) { + int trailing_bits = Support::ctz(unit); + a.and_(RET, imm(~_TAG_IMMED1_MASK)); + if (trailing_bits < _TAG_IMMED1_SIZE) { + a.sar(RET, imm(_TAG_IMMED1_SIZE - trailing_bits)); + } else if (trailing_bits > _TAG_IMMED1_SIZE) { + a.shl(RET, imm(trailing_bits - _TAG_IMMED1_SIZE)); + } } else { /* Untag the size but don't shift it just yet, we want to fail on * overflow if the final result doesn't fit into a small. */ a.and_(RET, imm(~_TAG_IMMED1_MASK)); - a.js(fail); + if (can_fail) { + a.js(fail); + } /* Size = (Size) * (Unit) */ mov_imm(ARG3, unit); a.mul(ARG3); /* CLOBBERS ARG3! */ - a.jo(fail); + if (can_fail) { + a.jo(fail); + } a.sar(RET, imm(_TAG_IMMED1_SIZE)); } @@ -95,15 +122,15 @@ int BeamModuleAssembler::emit_bs_get_field_size(const ArgVal &Size, } } -void BeamModuleAssembler::emit_i_bs_init_heap(const ArgVal &Size, - const ArgVal &Heap, - const ArgVal &Live, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_init_heap(const ArgWord &Size, + const ArgWord &Heap, + const ArgWord &Live, + const ArgRegister &Dst) { mov_arg(ARG4, Size); mov_arg(ARG5, Heap); mov_arg(ARG6, Live); - emit_enter_runtime(); + emit_enter_runtime(); /* Must be last since mov_arg() may clobber ARG1 */ a.mov(ARG1, c_p); @@ -111,7 +138,7 @@ void BeamModuleAssembler::emit_i_bs_init_heap(const ArgVal &Size, load_erl_bits_state(ARG3); runtime_call<6>(beam_jit_bs_init); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } @@ -125,15 +152,15 @@ void BeamGlobalAssembler::emit_bs_size_check_shared() { a.ret(); } -void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgVal &Size, - const ArgVal &Heap, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgSource &Size, + const ArgWord &Heap, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { Label fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); } @@ -143,21 +170,19 @@ void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgVal &Size, mov_arg(ARG5, Heap); mov_arg(ARG6, Live); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); load_erl_bits_state(ARG3); runtime_call<6>(beam_jit_bs_init); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { Label next = a.newLabel(); a.short_().jmp(next); @@ -165,46 +190,46 @@ void BeamModuleAssembler::emit_i_bs_init_fail_heap(const ArgVal &Size, { mov_arg(ARG2, Size); safe_fragment_call(ga->get_bs_size_check_shared()); - emit_handle_error(); + emit_raise_exception(); } a.bind(next); } } -void BeamModuleAssembler::emit_i_bs_init(const ArgVal &Size, - const ArgVal &Live, - const ArgVal &Dst) { - const ArgVal Heap(ArgVal::TYPE::u, 0); +void BeamModuleAssembler::emit_i_bs_init(const ArgWord &Size, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); emit_i_bs_init_heap(Size, Heap, Live, Dst); } -void BeamModuleAssembler::emit_i_bs_init_fail(const ArgVal &Size, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { - const ArgVal Heap(ArgVal::TYPE::u, 0); +void BeamModuleAssembler::emit_i_bs_init_fail(const ArgRegister &Size, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); emit_i_bs_init_fail_heap(Size, Heap, Fail, Live, Dst); } -void BeamModuleAssembler::emit_i_bs_init_bits(const ArgVal &NumBits, - const ArgVal &Live, - const ArgVal &Dst) { - const ArgVal heap(ArgVal::TYPE::u, 0); +void BeamModuleAssembler::emit_i_bs_init_bits(const ArgWord &NumBits, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal heap(ArgVal::Word, 0); emit_i_bs_init_bits_heap(NumBits, heap, Live, Dst); } -void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgVal &NumBits, - const ArgVal &Alloc, - const ArgVal &Live, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgWord &NumBits, + const ArgWord &Alloc, + const ArgWord &Live, + const ArgRegister &Dst) { mov_arg(ARG4, NumBits); mov_arg(ARG5, Alloc); mov_arg(ARG6, Live); - emit_enter_runtime(); + emit_enter_runtime(); /* Must be last since mov_arg() may clobber ARG1 */ a.mov(ARG1, c_p); @@ -212,29 +237,30 @@ void BeamModuleAssembler::emit_i_bs_init_bits_heap(const ArgVal &NumBits, load_erl_bits_state(ARG3); runtime_call<6>(beam_jit_bs_init_bits); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_init_bits_fail(const ArgVal &NumBits, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { - const ArgVal Heap(ArgVal::TYPE::u, 0); +void BeamModuleAssembler::emit_i_bs_init_bits_fail(const ArgRegister &NumBits, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { + const ArgVal Heap(ArgVal::Word, 0); emit_i_bs_init_bits_fail_heap(NumBits, Heap, Fail, Live, Dst); } -void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap(const ArgVal &NumBits, - const ArgVal &Alloc, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap( + const ArgSource &NumBits, + const ArgWord &Alloc, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgRegister &Dst) { Label fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); } @@ -244,8 +270,7 @@ void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap(const ArgVal &NumBits, mov_arg(ARG5, Alloc); mov_arg(ARG6, Live); - emit_enter_runtime(); + emit_enter_runtime(); /* Must be last since mov_arg() may clobber ARG1 */ a.mov(ARG1, c_p); @@ -253,13 +278,12 @@ void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap(const ArgVal &NumBits, load_erl_bits_state(ARG3); runtime_call<6>(beam_jit_bs_init_bits); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { Label next = a.newLabel(); a.short_().jmp(next); @@ -267,33 +291,33 @@ void BeamModuleAssembler::emit_i_bs_init_bits_fail_heap(const ArgVal &NumBits, { mov_arg(ARG2, NumBits); safe_fragment_call(ga->get_bs_size_check_shared()); - emit_handle_error(); + emit_raise_exception(); } a.bind(next); } } -void BeamModuleAssembler::emit_bs_put_string(const ArgVal &Size, - const ArgVal &Ptr) { +void BeamModuleAssembler::emit_bs_put_string(const ArgWord &Size, + const ArgBytePtr &Ptr) { mov_arg(ARG3, Size); emit_enter_runtime(); - make_move_patch(ARG2, strings, Ptr.getValue()); + mov_arg(ARG2, Ptr); load_erl_bits_state(ARG1); runtime_call<3>(erts_new_bs_put_string); emit_leave_runtime(); } -void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Flags) { +void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgSource &Src, + const ArgLabel &Fail, + const ArgWord &Sz, + const ArgWord &Flags) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -310,8 +334,8 @@ void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgVal &Src, a.test(RET, RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); emit_error(BADARG); @@ -319,15 +343,15 @@ void BeamModuleAssembler::emit_i_new_bs_put_integer_imm(const ArgVal &Src, } } -void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Flags, - const ArgVal &Src) { - int unit = Flags.getValue() >> 3; +void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgLabel &Fail, + const ArgRegister &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; Label next, fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); next = a.newLabel(); @@ -347,29 +371,29 @@ void BeamModuleAssembler::emit_i_new_bs_put_integer(const ArgVal &Fail, a.test(RET, RET); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { a.je(fail); } else { a.short_().jne(next); } } - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.bind(fail); emit_error(BADARG); a.bind(next); } } -void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Flags, - const ArgVal &Src) { - int unit = Flags.getValue() >> 3; +void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgLabel &Fail, + const ArgSource &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; Label next, fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); next = a.newLabel(); @@ -388,26 +412,26 @@ void BeamModuleAssembler::emit_i_new_bs_put_binary(const ArgVal &Fail, a.test(RET, RET); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { a.je(fail); } else { a.short_().jne(next); } } - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.bind(fail); emit_error(BADARG); a.bind(next); } } -void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Unit) { +void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgSource &Src, + const ArgLabel &Fail, + const ArgWord &Unit) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -423,21 +447,21 @@ void BeamModuleAssembler::emit_i_new_bs_put_binary_all(const ArgVal &Src, a.test(RET, RET); - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.jne(next); emit_error(BADARG); a.bind(next); } else { - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } } -void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgLabel &Fail, + const ArgWord &Sz, + const ArgSource &Src) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -453,24 +477,24 @@ void BeamModuleAssembler::emit_i_new_bs_put_binary_imm(const ArgVal &Fail, a.test(RET, RET); - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.short_().jne(next); emit_error(BADARG); a.bind(next); } else { - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } } -void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Flags, - const ArgVal &Src) { - int unit = Flags.getValue() >> 3; +void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgLabel &Fail, + const ArgRegister &Sz, + const ArgWord &Flags, + const ArgSource &Src) { + int unit = Flags.get() >> 3; Label next, fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); next = a.newLabel(); @@ -488,29 +512,29 @@ void BeamModuleAssembler::emit_i_new_bs_put_float(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); + emit_test_the_non_value(RET); - if (Fail.getValue() != 0) { - a.je(fail); + if (Fail.get() != 0) { + a.jne(fail); } else { - a.short_().jne(next); + a.short_().je(next); } } - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.bind(fail); emit_error(BADARG); a.bind(next); } } -void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgVal &Fail, - const ArgVal &Sz, - const ArgVal &Flags, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgLabel &Fail, + const ArgWord &Sz, + const ArgWord &Flags, + const ArgSource &Src) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -525,27 +549,27 @@ void BeamModuleAssembler::emit_i_new_bs_put_float_imm(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); + emit_test_the_non_value(RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.jne(resolve_beam_label(Fail)); } else { - a.short_().jne(next); + a.short_().je(next); emit_error(BADARG); a.bind(next); } } -void BeamModuleAssembler::emit_i_bs_start_match3(const ArgVal &Src, - const ArgVal &Live, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_start_match3(const ArgRegister &Src, + const ArgWord &Live, + const ArgLabel &Fail, + const ArgRegister &Dst) { Label is_binary = a.newLabel(), next = a.newLabel(); mov_arg(ARG2, Src); - if (Fail.getValue() != 0) { - emit_is_boxed(labels[Fail.getValue()], ARG2); + if (Fail.get() != 0) { + emit_is_boxed(resolve_beam_label(Fail), Src, ARG2); } else { /* bs_start_match3 may not throw, and the compiler will only emit {f,0} * when it knows that the source is a match state or binary, so we're @@ -563,31 +587,30 @@ void BeamModuleAssembler::emit_i_bs_start_match3(const ArgVal &Src, a.short_().je(next); #endif - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { comment("is_binary_header"); a.cmp(RETb, _TAG_HEADER_SUB_BIN); a.short_().je(is_binary); ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); a.and_(RETb, imm(~4)); a.cmp(RETb, imm(_TAG_HEADER_REFC_BIN)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } a.bind(is_binary); { - /* Src is not guaranteed to be inside the live range, so we need to - * stash it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, ERL_BIN_MATCHSTATE_SIZE(0)), + emit_gc_test_preserve(ArgWord(ERL_BIN_MATCHSTATE_SIZE(0)), Live, + Src, ARG2); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); /* ARG2 was set above */ runtime_call<2>(erts_bs_start_match_3); - emit_leave_runtime(); + emit_leave_runtime(); a.lea(ARG2, x86::qword_ptr(RET, TAG_PRIMARY_BOXED)); } @@ -596,12 +619,12 @@ void BeamModuleAssembler::emit_i_bs_start_match3(const ArgVal &Src, mov_arg(Dst, ARG2); } -void BeamModuleAssembler::emit_i_bs_match_string(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Bits, - const ArgVal &Ptr) { - const UWord size = Bits.getValue(); - Label fail = labels[Fail.getValue()]; +void BeamModuleAssembler::emit_i_bs_match_string(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Bits, + const ArgBytePtr &Ptr) { + const UWord size = Bits.get(); + Label fail = resolve_beam_label(Fail); mov_arg(ARG1, Ctx); @@ -623,7 +646,7 @@ void BeamModuleAssembler::emit_i_bs_match_string(const ArgVal &Ctx, emit_enter_runtime(); - make_move_patch(ARG1, strings, Ptr.getValue()); + mov_arg(ARG1, Ptr); mov_imm(ARG2, 0); mov_imm(ARG5, size); runtime_call<5>(erts_cmp_bits); @@ -638,8 +661,8 @@ void BeamModuleAssembler::emit_i_bs_match_string(const ArgVal &Ctx, imm(size)); } -void BeamModuleAssembler::emit_i_bs_get_position(const ArgVal &Ctx, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_get_position(const ArgRegister &Ctx, + const ArgRegister &Dst) { mov_arg(ARG1, Ctx); /* Match contexts can never be literals, so we can skip clearing literal @@ -651,299 +674,116 @@ void BeamModuleAssembler::emit_i_bs_get_position(const ArgVal &Ctx, mov_arg(Dst, ARG1); } -/* ARG3 = flags | (size << 3), - * ARG4 = tagged match context */ -void BeamGlobalAssembler::emit_bs_fixed_integer_shared() { - emit_enter_runtime(); - - a.mov(ARG1, c_p); - /* Unpack size ... */ - a.mov(ARG2, ARG3); - a.shr(ARG2, imm(3)); - /* ... flags. */ - a.and_(ARG3, imm(BSF_ALIGNED | BSF_LITTLE | BSF_SIGNED)); - a.lea(ARG4, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb))); - runtime_call<4>(erts_bs_get_integer_2); - - emit_leave_runtime(); - - a.ret(); -} - -x86::Mem BeamModuleAssembler::emit_bs_get_integer_prologue(Label next, - Label fail, - int flags, - int size) { - Label aligned = a.newLabel(); - - a.mov(ARG2, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb.offset))); - a.lea(ARG3, x86::qword_ptr(ARG2, size)); - a.cmp(ARG3, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb.size))); - a.ja(fail); - - a.test(ARG2.r8(), imm(CHAR_BIT - 1)); - a.short_().je(aligned); - - /* Actually unaligned reads are quite rare, so we handle everything in a - * shared fragment. */ - mov_imm(ARG3, flags | (size << 3)); - safe_fragment_call(ga->get_bs_fixed_integer_shared()); - - /* The above call can't fail since we work on small numbers and - * bounds-tested above. */ -#ifdef JIT_HARD_DEBUG - a.jmp(next); -#else - a.short_().jmp(next); -#endif - - a.bind(aligned); - { - /* Read base address and convert offset to bytes. */ - a.mov(ARG1, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb.base))); - a.shr(ARG2, imm(3)); - - /* We cannot fail from here on; bump the match context's position. */ - a.mov(emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb.offset)), - ARG3); - - return x86::Mem(ARG1, ARG2, 0, 0, size / 8); - } -} - -void BeamModuleAssembler::emit_i_bs_get_integer_8(const ArgVal &Ctx, - const ArgVal &Flags, - const ArgVal &Fail, - const ArgVal &Dst) { - int flags = Flags.getValue(); - Label next = a.newLabel(); - x86::Mem address; - - mov_arg(ARG4, Ctx); - - address = emit_bs_get_integer_prologue(next, - labels[Fail.getValue()], - flags, - 8); - - if (flags & BSF_SIGNED) { - a.movsx(RET, address); - } else { - a.movzx(RET, address); - } - - a.shl(RET, imm(_TAG_IMMED1_SIZE)); - a.or_(RET, imm(_TAG_IMMED1_SMALL)); - - a.bind(next); - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_get_integer_16(const ArgVal &Ctx, - const ArgVal &Flags, - const ArgVal &Fail, - const ArgVal &Dst) { - int flags = Flags.getValue(); - Label next = a.newLabel(); - x86::Mem address; - - mov_arg(ARG4, Ctx); - - address = emit_bs_get_integer_prologue(next, - labels[Fail.getValue()], - flags, - 16); - - if (flags & BSF_LITTLE) { - if (flags & BSF_SIGNED) { - a.movsx(RET, address); - } else { - a.movzx(RET, address); - } - } else { - if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { - a.movbe(x86::ax, address); - } else { - a.mov(x86::ax, address); - a.xchg(x86::al, x86::ah); - } - - if (flags & BSF_SIGNED) { - a.movsx(RET, x86::ax); - } else { - a.movzx(RET, x86::ax); - } +void BeamModuleAssembler::emit_bs_get_integer2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Live, + const ArgSource &Sz, + const ArgWord &Unit, + const ArgWord &Flags, + const ArgRegister &Dst) { + Uint size; + Uint flags = Flags.get(); + + if (flags & BSF_NATIVE) { + flags &= ~BSF_NATIVE; + flags |= BSF_LITTLE; } - a.shl(RET, imm(_TAG_IMMED1_SIZE)); - a.or_(RET, imm(_TAG_IMMED1_SMALL)); - - a.bind(next); - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_get_integer_32(const ArgVal &Ctx, - const ArgVal &Flags, - const ArgVal &Fail, - const ArgVal &Dst) { - int flags = Flags.getValue(); - Label next = a.newLabel(); - x86::Mem address; - - mov_arg(ARG4, Ctx); - - address = emit_bs_get_integer_prologue(next, - labels[Fail.getValue()], - flags, - 32); - - if (flags & BSF_LITTLE) { - if (flags & BSF_SIGNED) { - a.movsxd(RET, address); - } else { - /* Implicitly zero-extends to 64 bits */ - a.mov(RETd, address); - } + if (Sz.isSmall() && Sz.as().getUnsigned() < 8 * sizeof(Uint) && + (size = Sz.as().getUnsigned() * Unit.get()) < + 8 * sizeof(Uint)) { + /* Segment of a fixed size supported by bs_match. */ + const ArgVal match[] = {ArgAtom(am_ensure_at_least), + ArgWord(size), + ArgWord(1), + ArgAtom(am_integer), + Live, + ArgWord(flags), + ArgWord(size), + ArgWord(1), + Dst}; + + const Span args(match, sizeof(match) / sizeof(match[0])); + emit_i_bs_match(Fail, Ctx, args); } else { - if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { - a.movbe(RETd, address); - } else { - a.mov(RETd, address); - a.bswap(RETd); - } - - if (flags & BSF_SIGNED) { - a.movsxd(RET, RETd); - } - } - - a.shl(RET, imm(_TAG_IMMED1_SIZE)); - a.or_(RET, imm(_TAG_IMMED1_SMALL)); - - a.bind(next); - mov_arg(Dst, RET); -} + Label fail = resolve_beam_label(Fail); + int unit = Unit.get(); + + /* Clobbers RET + ARG3, returns a negative result if we always + * fail and further work is redundant. */ + if (emit_bs_get_field_size(Sz, unit, fail, ARG5) >= 0) { + /* This operation can be expensive if a bignum can be + * created because there can be a garbage collection. */ + auto max = std::get<1>(getClampedRange(Sz)); + bool potentially_expensive = + max >= SMALL_BITS || (max * Unit.get()) >= SMALL_BITS; + + mov_arg(ARG3, Ctx); + mov_imm(ARG4, flags); + if (potentially_expensive) { + mov_arg(ARG6, Live); + } else { +#ifdef DEBUG + /* Never actually used. */ + mov_imm(ARG6, 1023); +#endif + } -void BeamModuleAssembler::emit_i_bs_get_integer_64(const ArgVal &Ctx, - const ArgVal &Flags, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Dst) { - int flags = Flags.getValue(); - Label next = a.newLabel(); - x86::Mem address; + if (potentially_expensive) { + emit_enter_runtime(); + } else { + comment("simplified entering runtime because result is always " + "small"); + emit_enter_runtime(); + } - mov_arg(ARG4, Ctx); + a.mov(ARG1, c_p); + if (potentially_expensive) { + load_x_reg_array(ARG2); + } else { +#ifdef DEBUG + /* Never actually used. */ + mov_imm(ARG2, 0); +#endif + } + runtime_call<6>(beam_jit_bs_get_integer); - /* Ctx is not guaranteed to be inside the live range, so we need to stash - * it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, BIG_UINT_HEAP_SIZE), Live, ARG4); + if (potentially_expensive) { + emit_leave_runtime(); + } else { + emit_leave_runtime(); + } - address = emit_bs_get_integer_prologue(next, - labels[Fail.getValue()], - flags, - 64); + emit_test_the_non_value(RET); + a.je(fail); - if (flags & BSF_LITTLE) { - a.mov(RET, address); - } else { - if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { - a.movbe(RET, address); - } else { - a.mov(RET, address); - a.bswap(RET); + mov_arg(Dst, RET); } } - - a.mov(ARG1, RET); - a.mov(ARG2, RET); - - /* Speculatively make a small out of the result even though it might not - * be one, and jump to the next instruction if it is. */ - a.shl(RET, imm(_TAG_IMMED1_SIZE)); - a.or_(RET, imm(_TAG_IMMED1_SMALL)); - - if (flags & BSF_SIGNED) { - a.sar(ARG2, imm(SMALL_BITS - 1)); - a.add(ARG2, imm(1)); - a.cmp(ARG2, imm(1)); - a.jbe(next); - } else { - a.shr(ARG2, imm(SMALL_BITS - 1)); - a.jz(next); - } - - emit_enter_runtime(); - - a.mov(ARG2, HTOP); - if (flags & BSF_SIGNED) { - runtime_call<2>(small_to_big); - } else { - runtime_call<2>(uword_to_big); - } - a.add(HTOP, imm(sizeof(Eterm) * BIG_UINT_HEAP_SIZE)); - - emit_leave_runtime(); - - a.bind(next); - mov_arg(Dst, RET); -} - -void BeamModuleAssembler::emit_i_bs_get_integer(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &FlagsAndUnit, - const ArgVal &Sz, - const ArgVal &Dst) { - Label fail; - int unit; - - fail = labels[Fail.getValue()]; - unit = FlagsAndUnit.getValue() >> 3; - - /* Clobbers RET + ARG3, returns a negative result if we always fail and - * further work is redundant. */ - if (emit_bs_get_field_size(Sz, unit, fail, ARG5) >= 0) { - mov_arg(ARG3, Ctx); - mov_arg(ARG4, FlagsAndUnit); - mov_arg(ARG6, Live); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<6>(beam_jit_bs_get_integer); - - emit_leave_runtime(); - - emit_test_the_non_value(RET); - a.je(fail); - - mov_arg(Dst, RET); - } } -void BeamModuleAssembler::emit_bs_test_tail2(const ArgVal &Fail, - const ArgVal &Ctx, - const ArgVal &Offset) { - ASSERT(Offset.getType() == ArgVal::TYPE::u); - +void BeamModuleAssembler::emit_bs_test_tail2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Offset) { mov_arg(ARG1, Ctx); a.mov(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.size))); a.sub(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset))); - if (Offset.getValue() != 0) { - a.cmp(ARG2, imm(Offset.getValue())); + if (Offset.get() != 0) { + if (Support::isInt32(Offset.get())) { + a.cmp(ARG2, imm(Offset.get())); + } else { + mov_imm(RET, Offset.get()); + a.cmp(ARG2, RET); + } } - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_bs_set_position(const ArgVal &Ctx, - const ArgVal &Pos) { +void BeamModuleAssembler::emit_bs_set_position(const ArgRegister &Ctx, + const ArgRegister &Pos) { mov_arg(ARG1, Ctx); mov_arg(ARG2, Pos); @@ -951,20 +791,16 @@ void BeamModuleAssembler::emit_bs_set_position(const ArgVal &Ctx, a.mov(emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset)), ARG2); } -void BeamModuleAssembler::emit_i_bs_get_binary_all2(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Unit, - const ArgVal &Dst) { - unsigned unit = Unit.getValue(); +void BeamModuleAssembler::emit_i_bs_get_binary_all2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgWord &Unit, + const ArgRegister &Dst) { + unsigned unit = Unit.get(); mov_arg(ARG1, Ctx); - /* Ctx is not guaranteed to be inside the live range, so we need to stash - * it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, EXTRACT_SUB_BIN_HEAP_NEED), - Live, - ARG1); + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), Live, Ctx, ARG1); a.mov(RET, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.size))); a.sub(RET, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset))); @@ -979,21 +815,21 @@ void BeamModuleAssembler::emit_i_bs_get_binary_all2(const ArgVal &Ctx, a.test(RETb, imm(unit - 1)); } - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); - emit_enter_runtime(); + emit_enter_runtime(); a.lea(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); a.mov(ARG1, c_p); runtime_call<2>(erts_bs_get_binary_all_2); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } void BeamGlobalAssembler::emit_bs_get_tail_shared() { - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.orig))); a.mov(ARG3, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.base))); @@ -1006,21 +842,17 @@ void BeamGlobalAssembler::emit_bs_get_tail_shared() { a.lea(ARG1, x86::qword_ptr(c_p, offsetof(Process, htop))); runtime_call<5>(erts_extract_sub_binary); - emit_leave_runtime(); + emit_leave_runtime(); a.ret(); } -void BeamModuleAssembler::emit_bs_get_tail(const ArgVal &Ctx, - const ArgVal &Dst, - const ArgVal &Live) { +void BeamModuleAssembler::emit_bs_get_tail(const ArgRegister &Ctx, + const ArgRegister &Dst, + const ArgWord &Live) { mov_arg(ARG1, Ctx); - /* Ctx is not guaranteed to be inside the live range, so we need to stash - * it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, EXTRACT_SUB_BIN_HEAP_NEED), - Live, - ARG1); + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), Live, Ctx, ARG1); safe_fragment_call(ga->get_bs_get_tail_shared()); @@ -1028,49 +860,48 @@ void BeamModuleAssembler::emit_bs_get_tail(const ArgVal &Ctx, } /* Bits to skip are passed in RET */ -void BeamModuleAssembler::emit_bs_skip_bits(const ArgVal &Fail, - const ArgVal &Ctx) { +void BeamModuleAssembler::emit_bs_skip_bits(const ArgLabel &Fail, + const ArgRegister &Ctx) { mov_arg(ARG1, Ctx); a.add(RET, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset))); a.cmp(RET, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.size))); - a.ja(labels[Fail.getValue()]); + a.ja(resolve_beam_label(Fail)); a.mov(emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset)), RET); } -void BeamModuleAssembler::emit_i_bs_skip_bits2(const ArgVal &Ctx, - const ArgVal &Bits, - const ArgVal &Fail, - const ArgVal &Unit) { +void BeamModuleAssembler::emit_i_bs_skip_bits2(const ArgRegister &Ctx, + const ArgRegister &Bits, + const ArgLabel &Fail, + const ArgWord &Unit) { Label fail; - fail = labels[Fail.getValue()]; - - if (emit_bs_get_field_size(Bits, Unit.getValue(), fail, RET) >= 0) { + fail = resolve_beam_label(Fail); + if (emit_bs_get_field_size(Bits, Unit.get(), fail, RET) >= 0) { emit_bs_skip_bits(Fail, Ctx); } } -void BeamModuleAssembler::emit_i_bs_skip_bits_imm2(const ArgVal &Fail, - const ArgVal &Ctx, - const ArgVal &Bits) { +void BeamModuleAssembler::emit_i_bs_skip_bits_imm2(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Bits) { mov_arg(RET, Bits); emit_bs_skip_bits(Fail, Ctx); } -void BeamModuleAssembler::emit_i_bs_get_binary2(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Size, - const ArgVal &Flags, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_get_binary2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Size, + const ArgWord &Flags, + const ArgRegister &Dst) { Label fail; int unit; - fail = labels[Fail.getValue()]; - unit = Flags.getValue() >> 3; + fail = resolve_beam_label(Fail); + unit = Flags.get() >> 3; /* Clobbers RET + ARG3 */ if (emit_bs_get_field_size(Size, unit, fail, ARG2) >= 0) { @@ -1078,21 +909,20 @@ void BeamModuleAssembler::emit_i_bs_get_binary2(const ArgVal &Ctx, mov_arg(ARG4, Ctx); - /* Ctx is not guaranteed to be inside the live range, so we need to - * stash it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, EXTRACT_SUB_BIN_HEAP_NEED), + emit_gc_test_preserve(ArgWord(EXTRACT_SUB_BIN_HEAP_NEED), Live, + Ctx, ARG4); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); a.mov(ARG2, TMP_MEM1q); - mov_imm(ARG3, Flags.getValue()); + mov_imm(ARG3, Flags.get()); a.lea(ARG4, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb))); runtime_call<4>(erts_bs_get_binary_2); - emit_leave_runtime(); + emit_leave_runtime(); emit_test_the_non_value(RET); a.je(fail); @@ -1101,33 +931,31 @@ void BeamModuleAssembler::emit_i_bs_get_binary2(const ArgVal &Ctx, } } -void BeamModuleAssembler::emit_i_bs_get_float2(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Sz, - const ArgVal &Flags, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_get_float2(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Live, + const ArgSource &Sz, + const ArgWord &Flags, + const ArgRegister &Dst) { Label fail; Sint unit; - fail = labels[Fail.getValue()]; - unit = Flags.getValue() >> 3; + fail = resolve_beam_label(Fail); + unit = Flags.get() >> 3; mov_arg(ARG4, Ctx); - /* Ctx is not guaranteed to be inside the live range, so we need to stash - * it during GC. */ - emit_gc_test_preserve(ArgVal(ArgVal::i, FLOAT_SIZE_OBJECT), Live, ARG4); + emit_gc_test_preserve(ArgWord(FLOAT_SIZE_OBJECT), Live, Ctx, ARG4); if (emit_bs_get_field_size(Sz, unit, fail, ARG2, 64) >= 0) { - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); - mov_imm(ARG3, Flags.getValue()); + mov_imm(ARG3, Flags.get()); a.lea(ARG4, emit_boxed_val(ARG4, offsetof(ErlBinMatchState, mb))); runtime_call<4>(erts_bs_get_float_2); - emit_leave_runtime(); + emit_leave_runtime(); emit_test_the_non_value(RET); a.je(fail); @@ -1136,8 +964,8 @@ void BeamModuleAssembler::emit_i_bs_get_float2(const ArgVal &Ctx, } } -void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgVal &Src, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgSource &Src, + const ArgXRegister &Dst) { Label next = a.newLabel(); mov_arg(ARG1, Src); @@ -1157,11 +985,11 @@ void BeamModuleAssembler::emit_i_bs_utf8_size(const ArgVal &Src, mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgLabel &Fail, + const ArgSource &Src) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -1176,8 +1004,8 @@ void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgVal &Fail, a.test(RET, RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); emit_error(BADARG); @@ -1185,35 +1013,401 @@ void BeamModuleAssembler::emit_i_bs_put_utf8(const ArgVal &Fail, } } -void BeamModuleAssembler::emit_bs_get_utf8(const ArgVal &Ctx, - const ArgVal &Fail) { - mov_arg(ARG1, Ctx); +/* + * ARG1 = pointer to match state + * ARG2 = position in binary in bits + * ARG3 = base pointer to binary data + * RET = number of bits left in binary + * + * This fragment is called if the binary is unaligned and/or the number + * of remaining bits is less than 32. + * + * See the comment for emit_bs_get_utf8_shared() for details about the + * return value. + */ +void BeamGlobalAssembler::emit_bs_get_utf8_short_shared() { + const int position_offset = offsetof(ErlBinMatchBuffer, offset); + + const x86::Gp ctx = ARG1; + const x86::Gp bin_position = ARG2; + const x86::Gp bin_base = ARG3; + + Label at_least_one = a.newLabel(); + Label two = a.newLabel(); + Label three_or_more = a.newLabel(); + Label four = a.newLabel(); + Label five = a.newLabel(); + Label read_done = a.newLabel(); + Label no_masking = a.newLabel(); + Label ascii = a.newLabel(); + + /* Calculate the number of bytes remaining in the binary and error + * out if less than one. */ + a.shr(RET, imm(3)); + a.test(RET, RET); + a.short_().jne(at_least_one); - emit_enter_runtime(); + /* ZF is is already set. */ + a.ret(); - a.lea(ARG1, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); - runtime_call<1>(erts_bs_get_utf8); + a.bind(at_least_one); + + /* Save number of bytes remaining in binary. */ + a.mov(ARG5, RET); + + /* If the position in the binary is not byte-aligned, we'll need + * to read one more byte. */ + a.test(bin_position, imm(7)); + a.setne(ARG4.r8()); + a.movzx(ARG4d, ARG4.r8()); + a.add(RET, ARG4); + + /* Save original position in bits and set up byte offset for + * reading. */ + a.push(bin_position); + a.shr(bin_position, imm(3)); + + a.cmp(RET, imm(2)); + a.short_().je(two); + a.short_().ja(three_or_more); + + /* Read one byte (always byte-aligned). */ + a.mov(RETb, x86::byte_ptr(bin_base, bin_position)); + a.movzx(RETd, RETb); + a.short_().jmp(read_done); + + /* Read two bytes. */ + a.bind(two); + a.mov(RET.r16(), x86::word_ptr(bin_base, bin_position)); + a.movzx(RETd, RET.r16()); + a.short_().jmp(read_done); + + a.bind(three_or_more); + a.cmp(RET, imm(4)); + a.short_().je(four); + a.short_().ja(five); + + /* Read three bytes. */ + a.mov(RET.r8(), x86::byte_ptr(bin_base, bin_position, 0, 2)); + a.movzx(RETd, RETb); + a.shl(RETd, imm(16)); + a.mov(RET.r16(), x86::word_ptr(bin_base, bin_position)); + a.short_().jmp(read_done); + + /* Read four bytes (always unaligned). */ + a.bind(four); + a.mov(RETd, x86::dword_ptr(bin_base, bin_position)); + a.short_().jmp(read_done); + + /* Read five bytes (always unaligned). */ + a.bind(five); + a.mov(RETd, x86::dword_ptr(bin_base, bin_position)); + a.mov(ARG4.r8(), x86::byte_ptr(bin_base, bin_position, 0, 4)); + a.movzx(ARG4d, ARG4.r8()); + a.shl(ARG4, imm(32)); + a.or_(RET, ARG4); + + /* Handle the bytes read. */ + a.bind(read_done); + a.pop(bin_position); + a.bswap(RET); + + if (x86::rcx == ctx) { + a.push(x86::rcx); + } + a.mov(x86::ecx, bin_position.r32()); + a.and_(x86::cl, imm(7)); + a.shl(RET, x86::cl); + + /* Check whether we will need to clear out trailing + * garbage not part of the binary. */ + a.mov(x86::cl, 64); + a.cmp(ARG5, imm(3)); + a.short_().ja(no_masking); + + /* Calculate a byte mask and zero out trailing garbage. */ + a.shl(ARG5d, imm(3)); + a.sub(x86::cl, ARG5.r8()); + mov_imm(ARG5, -1); + a.shl(ARG5, x86::cl); + a.and_(RET, ARG5); + + a.bind(no_masking); + if (x86::rcx == ctx) { + a.pop(x86::rcx); + } - emit_leave_runtime(); + /* `test rax, rax` is a shorter instruction but can cause a warning + * in valgrind if there are any uninitialized bits in rax. */ + a.bt(RET, imm(63)); + a.short_().jnc(ascii); - emit_test_the_non_value(RET); - a.je(labels[Fail.getValue()]); + /* The bs_get_utf8_shared fragment expects the contents in RETd. */ + a.shr(RET, imm(32)); + a.jmp(labels[bs_get_utf8_shared]); + + /* Handle plain old ASCII (code point < 128). */ + a.bind(ascii); + a.add(x86::qword_ptr(ctx, position_offset), imm(8)); + a.shr(RET, imm(56 - _TAG_IMMED1_SIZE)); + a.or_(RET, imm(_TAG_IMMED1_SMALL)); /* Always clears ZF. */ + a.ret(); +} + +/* + * ARG1 = pointer to match state + * ARG2 = position in binary in bits + * RETd = 4 bytes read from the binary in big-endian order + * + * On successful return, the extracted code point is in RET, the + * position in the match state has been updated, and the ZF is clear. + * On failure, the ZF is set. + */ +void BeamGlobalAssembler::emit_bs_get_utf8_shared() { + Label error = a.newLabel(); + + x86::Gp shift_q = ARG4, shift_d = ARG4d, shift_b = ARG4.r8(); + x86::Gp original_value_d = RETd; + + x86::Gp byte_count_q = ARG2, byte_count_d = ARG2d; + x86::Gp extracted_value_d = ARG3d, extracted_value_b = ARG3.r8(); + x86::Gp control_mask_d = ARG5d; + x86::Gp error_mask_d = ARG6d; + + ASSERT(extracted_value_d != shift_d); + ASSERT(control_mask_d != shift_d); + ASSERT(error_mask_d != shift_d); + ASSERT(byte_count_d != shift_d); + + /* UTF-8 has the following layout, where 'x' are data bits: + * + * 1 byte: 0xxxxxxx (not handled by this path) + * 2 bytes: 110xxxxx, 10xxxxxx + * 3 bytes: 1110xxxx, 10xxxxxx 10xxxxxx + * 4 bytes: 11110xxx, 10xxxxxx 10xxxxxx 10xxxxxx + * + * Note that the number of leading bits is equal to the number of bytes, + * which makes it very easy to create masks for extraction and error + * checking. */ + + /* The PEXT instruction has poor latency on some processors, so we try to + * hide that by extracting early on. Should this be a problem, it's not + * much slower to hand-roll it with shifts or BEXTR. + * + * The mask covers data bits from all variants. This includes the 23rd bit + * to support the 2-byte case, which is set on all well-formed 4-byte + * codepoints, so it must be cleared before range testing .*/ + a.mov(extracted_value_d, imm(0x1F3F3F3F)); + a.pext(extracted_value_d, original_value_d, extracted_value_d); + + /* Preserve current match buffer and bit offset. */ + a.push(ARG1); + a.push(ARG2); + + /* Byte count = leading bit count. */ + a.mov(byte_count_d, original_value_d); + a.not_(byte_count_d); + a.lzcnt(byte_count_d, byte_count_d); + + /* Mask shift = (4 - byte count) * 8 */ + a.mov(shift_d, imm(4)); + a.sub(shift_d, byte_count_d); + a.lea(shift_d, x86::qword_ptr(0, shift_q, 3)); + + /* Shift the original value and masks into place. */ + a.shrx(original_value_d, original_value_d, shift_d); + + /* Matches the '10xxxxxx' components, leaving the header byte alone. */ + a.mov(control_mask_d, imm(0x00C0C0C0)); + a.shrx(control_mask_d, control_mask_d, shift_d); + a.mov(error_mask_d, imm(0x00808080)); + a.shrx(error_mask_d, error_mask_d, shift_d); + + /* Extracted value shift = (4 - byte count) * 6, as the leading '10' on + * every byte has been removed through PEXT. + * + * We calculate the shift here to avoid depending on byte_count_d later on + * when it may have changed. */ + a.mov(shift_d, imm(4)); + a.sub(shift_d, byte_count_d); + a.add(shift_d, shift_d); + a.lea(shift_d, x86::qword_ptr(shift_q, shift_q, 1)); + + /* Assert that the header bits of each '10xxxxxx' component is correct, + * signalling errors by trashing the byte count with a guaranteed-illegal + * value. */ + a.and_(original_value_d, control_mask_d); + a.cmp(original_value_d, error_mask_d); + a.cmovne(byte_count_d, error_mask_d); + + /* Shift the extracted value into place. */ + a.shrx(RETd, extracted_value_d, shift_d); + + /* The extraction mask is a bit too wide, see above for details. */ + a.and_(RETd, imm(~(1 << 22))); + + /* Check for too large code point. */ + a.cmp(RETd, imm(0x10FFFF)); + a.cmova(byte_count_d, error_mask_d); + + /* Check for the illegal range 16#D800 - 16#DFFF. */ + a.mov(shift_d, RETd); + a.and_(shift_d, imm(-0x800)); + a.cmp(shift_d, imm(0xD800)); + a.cmove(byte_count_d, error_mask_d); + + /* Test for overlong UTF-8 sequence. That can be done by testing + * that the bits marked y below are all zero. + * + * 1 byte: 0xxxxxxx (not handled by this path) + * 2 bytes: 110yyyyx, 10xxxxxx + * 3 bytes: 1110yyyy, 10yxxxxx 10xxxxxx + * 4 bytes: 11110yyy, 10yyxxxx 10xxxxxx 10xxxxxx + * + * 1 byte: xx'xxxxx + * 2 bytes: y'yyyxx'xxxxx + * 3 bytes: y'yyyyx'xxxxx'xxxxx + * 4 bytes: y'yyyyx'xxxxx'xxxxx'xxxxx + * + * The y bits can be isolated by shifting down by the number of bits + * shown in this table: + * + * 2: 7 (byte_count * 4 - 1) + * 3: 11 (byte_count * 4 - 1) + * 4: 16 (byte_count * 4) + */ + + /* Calculate number of bits to shift. */ + a.lea(shift_d, x86::qword_ptr(0, byte_count_q, 2)); + a.cmp(byte_count_d, imm(4)); + a.setne(extracted_value_b); + a.sub(shift_b, extracted_value_b); + a.movzx(shift_q, shift_b); + + /* Now isolate the y bits and compare to zero. */ + a.shrx(extracted_value_d, RETd, shift_d); + a.test(extracted_value_d, extracted_value_d); + a.cmove(byte_count_d, error_mask_d); + + /* Restore current bit offset and match buffer. */ + ASSERT(ARG1 != byte_count_q && ARG3 != byte_count_q); + a.pop(ARG3); + a.pop(ARG1); + + /* Advance our current position. */ + a.lea(ARG3, x86::qword_ptr(ARG3, byte_count_q, 3)); + + /* Byte count must be 2, 3, or 4. */ + a.sub(byte_count_d, imm(2)); + a.cmp(byte_count_d, imm(2)); + a.ja(error); + + a.mov(x86::qword_ptr(ARG1, offsetof(ErlBinMatchBuffer, offset)), ARG3); + + a.shl(RETd, imm(_TAG_IMMED1_SIZE)); + a.or_(RETd, imm(_TAG_IMMED1_SMALL)); /* Always clears ZF. */ + + a.ret(); + + a.bind(error); + { + /* Signal error by setting ZF. */ + a.xor_(RET, RET); + a.ret(); + } +} + +void BeamModuleAssembler::emit_bs_get_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail) { + const int base_offset = offsetof(ErlBinMatchBuffer, base); + const int position_offset = offsetof(ErlBinMatchBuffer, offset); + const int size_offset = offsetof(ErlBinMatchBuffer, size); + + const x86::Gp ctx = ARG1; + const x86::Gp bin_position = ARG2; + const x86::Gp bin_base = ARG3; + + Label multi_byte = a.newLabel(), fallback = a.newLabel(), + check = a.newLabel(), done = a.newLabel(); + + mov_arg(ctx, Ctx); + a.lea(ctx, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); + + a.mov(bin_position, x86::qword_ptr(ctx, position_offset)); + a.mov(RET, x86::qword_ptr(ctx, size_offset)); + a.mov(bin_base, x86::qword_ptr(ctx, base_offset)); + a.sub(RET, bin_position); + a.cmp(RET, imm(32)); + a.short_().jb(fallback); + + a.test(bin_position, imm(7)); + a.short_().jnz(fallback); + + /* We're byte-aligned and can read at least 32 bits. */ + a.mov(RET, bin_position); + a.shr(RET, 3); + + /* The most significant bits come first, so we'll read the the next four + * bytes as big-endian so we won't have to reorder them later. */ + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RETd, x86::dword_ptr(bin_base, RET)); + } else { + a.mov(RETd, x86::dword_ptr(bin_base, RET)); + a.bswap(RETd); + } + a.test(RETd, RETd); + a.short_().js(multi_byte); + + /* Handle plain old ASCII (code point < 128). */ + a.add(x86::qword_ptr(ctx, position_offset), imm(8)); + a.shr(RETd, imm(24 - _TAG_IMMED1_SIZE)); + a.or_(RETd, imm(_TAG_IMMED1_SMALL)); + a.short_().jmp(done); + + a.bind(multi_byte); + + if (hasCpuFeature(CpuFeatures::X86::kBMI2)) { + /* This CPU supports the PEXT and SHRX instructions. */ + safe_fragment_call(ga->get_bs_get_utf8_shared()); + a.short_().jmp(check); + } + + /* Take care of unaligned binaries and binaries with less than 32 + * bits left. */ + a.bind(fallback); + if (hasCpuFeature(CpuFeatures::X86::kBMI2)) { + /* This CPU supports the PEXT and SHRX instructions. */ + safe_fragment_call(ga->get_bs_get_utf8_short_shared()); + } else { + emit_enter_runtime(); + + runtime_call<1>(erts_bs_get_utf8); + + emit_leave_runtime(); + + emit_test_the_non_value(RET); + } + + a.bind(check); + a.je(resolve_beam_label(Fail)); + + a.bind(done); } -void BeamModuleAssembler::emit_i_bs_get_utf8(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_get_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgRegister &Dst) { emit_bs_get_utf8(Ctx, Fail); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_skip_utf8(const ArgVal &Ctx, - const ArgVal &Fail) { +void BeamModuleAssembler::emit_i_bs_skip_utf8(const ArgRegister &Ctx, + const ArgLabel &Fail) { emit_bs_get_utf8(Ctx, Fail); } -void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgVal &Src, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgSource &Src, + const ArgXRegister &Dst) { mov_arg(ARG1, Src); mov_imm(RET, make_small(2)); @@ -1224,12 +1418,12 @@ void BeamModuleAssembler::emit_i_bs_utf16_size(const ArgVal &Src, mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgVal &Fail, - const ArgVal &Flags, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgLabel &Fail, + const ArgWord &Flags, + const ArgSource &Src) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -1246,8 +1440,8 @@ void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgVal &Fail, a.test(RET, RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); emit_error(BADARG); @@ -1255,34 +1449,34 @@ void BeamModuleAssembler::emit_i_bs_put_utf16(const ArgVal &Fail, } } -void BeamModuleAssembler::emit_bs_get_utf16(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Flags) { +void BeamModuleAssembler::emit_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags) { mov_arg(ARG1, Ctx); emit_enter_runtime(); a.lea(ARG1, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb))); - mov_imm(ARG2, Flags.getValue()); + mov_imm(ARG2, Flags.get()); runtime_call<2>(erts_bs_get_utf16); emit_leave_runtime(); emit_test_the_non_value(RET); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_i_bs_get_utf16(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Flags, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_get_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags, + const ArgRegister &Dst) { emit_bs_get_utf16(Ctx, Fail, Flags); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_skip_utf16(const ArgVal &Ctx, - const ArgVal &Fail, - const ArgVal &Flags) { +void BeamModuleAssembler::emit_i_bs_skip_utf16(const ArgRegister &Ctx, + const ArgLabel &Fail, + const ArgWord &Flags) { emit_bs_get_utf16(Ctx, Fail, Flags); } @@ -1290,8 +1484,8 @@ void BeamModuleAssembler::emit_validate_unicode(Label next, Label fail, x86::Gp value) { a.mov(ARG3d, value.r32()); - a.and_(ARG3d, imm(_TAG_IMMED1_MASK)); - a.cmp(ARG3d, imm(_TAG_IMMED1_SMALL)); + a.and_(ARG3d.r8(), imm(_TAG_IMMED1_MASK)); + a.cmp(ARG3d.r8(), imm(_TAG_IMMED1_SMALL)); a.jne(fail); a.cmp(value, imm(make_small(0xD800UL))); @@ -1304,12 +1498,12 @@ void BeamModuleAssembler::emit_validate_unicode(Label next, a.jmp(next); } -void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgLabel &Fail, + const ArgSource &Src) { Label fail, next = a.newLabel(); - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); } @@ -1317,7 +1511,7 @@ void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgVal &Fail, mov_arg(ARG1, Src); emit_validate_unicode(next, fail, ARG1); - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { a.bind(fail); emit_error(BADARG); } @@ -1325,9 +1519,10 @@ void BeamModuleAssembler::emit_i_bs_validate_unicode(const ArgVal &Fail, a.bind(next); } -void BeamModuleAssembler::emit_i_bs_validate_unicode_retract(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Ms) { +void BeamModuleAssembler::emit_i_bs_validate_unicode_retract( + const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Ms) { Label fail = a.newLabel(), next = a.newLabel(); mov_arg(ARG1, Src); @@ -1341,8 +1536,8 @@ void BeamModuleAssembler::emit_i_bs_validate_unicode_retract(const ArgVal &Fail, a.sub(emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset)), imm(32)); - if (Fail.getValue() != 0) { - a.jmp(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.jmp(resolve_beam_label(Fail)); } else { emit_error(BADARG); } @@ -1351,10 +1546,10 @@ void BeamModuleAssembler::emit_i_bs_validate_unicode_retract(const ArgVal &Fail, a.bind(next); } -void BeamModuleAssembler::emit_bs_test_unit(const ArgVal &Fail, - const ArgVal &Ctx, - const ArgVal &Unit) { - unsigned int unit = Unit.getValue(); +void BeamModuleAssembler::emit_bs_test_unit(const ArgLabel &Fail, + const ArgRegister &Ctx, + const ArgWord &Unit) { + unsigned int unit = Unit.get(); mov_arg(ARG1, Ctx); @@ -1371,7 +1566,7 @@ void BeamModuleAssembler::emit_bs_test_unit(const ArgVal &Fail, a.test(RETb, imm(unit - 1)); } - a.jnz(labels[Fail.getValue()]); + a.jnz(resolve_beam_label(Fail)); } /* Set the error reason when bs_add has failed. */ @@ -1383,54 +1578,57 @@ void BeamGlobalAssembler::emit_bs_add_shared() { a.ret(); } -void BeamModuleAssembler::emit_bs_add(const ArgVal &Fail, - const ArgVal &Src1, - const ArgVal &Src2, - const ArgVal &Unit, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_bs_add(const ArgLabel &Fail, + const ArgSource &Src1, + const ArgSource &Src2, + const ArgWord &Unit, + const ArgXRegister &Dst) { Label fail; - if (Fail.getValue() != 0) { - fail = labels[Fail.getValue()]; + if (Fail.get() != 0) { + fail = resolve_beam_label(Fail); } else { fail = a.newLabel(); } /* Both arguments must be immediates on x64. */ mov_arg(ARG1, Src1); - if (Src2.getType() == ArgVal::i) { + + if (Src2.isImmed()) { a.mov(RETd, ARG1d); } else { mov_arg(ARG2, Src2); a.mov(RETd, ARG2d); - if (Src1.getType() != ArgVal::i) { + if (Src1.isImmed()) { a.and_(RETd, ARG1d); } } + a.and_(RETb, imm(_TAG_IMMED1_MASK)); a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); a.jne(fail); /* Verify that ARG2 >= 0 and multiply ARG2 by the unit. The * result will be untagged but not shifted and stored in RET. */ - if (Src2.getType() == ArgVal::i) { - Uint val = unsigned_val(Src2.getValue()); + if (Src2.isSmall()) { + Uint val = Src2.as().getUnsigned(); + if ((val >> (sizeof(Eterm) - 1) * 8) != 0) { /* Protect against negative or huge literal size. */ a.jmp(fail); return; } else { - val = (Unit.getValue() * val) << _TAG_IMMED1_SIZE; + val = (Unit.get() * val) << _TAG_IMMED1_SIZE; mov_imm(RET, val); } } else { a.and_(ARG2, imm(~_TAG_IMMED1_MASK)); a.js(fail); /* Multiply ARG2 by unit. */ - if (Unit.getValue() == 1) { + if (Unit.get() == 1) { a.mov(RET, ARG2); } else { - mov_imm(RET, Unit.getValue()); + mov_imm(RET, Unit.get()); a.mul(ARG2); /* CLOBBERS RDX = ARG3! */ a.jo(fail); } @@ -1444,7 +1642,7 @@ void BeamModuleAssembler::emit_bs_add(const ArgVal &Fail, * flag when the result won't fit an immediate. */ a.add(RET, ARG1); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { a.jo(fail); } else { Label next = a.newLabel(); @@ -1456,7 +1654,7 @@ void BeamModuleAssembler::emit_bs_add(const ArgVal &Fail, mov_arg(ARG2, Src1); mov_arg(ARG3, Src2); safe_fragment_call(ga->get_bs_add_shared()); - emit_handle_error(); + emit_raise_exception(); } a.bind(next); @@ -1465,16 +1663,16 @@ void BeamModuleAssembler::emit_bs_add(const ArgVal &Fail, mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_append(const ArgVal &Fail, - const ArgVal &ExtraHeap, - const ArgVal &Live, - const ArgVal &Unit, - const ArgVal &Size, - const ArgVal &Bin, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_append(const ArgLabel &Fail, + const ArgWord &ExtraHeap, + const ArgWord &Live, + const ArgWord &Unit, + const ArgSource &Size, + const ArgSource &Bin, + const ArgRegister &Dst) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -1483,38 +1681,38 @@ void BeamModuleAssembler::emit_i_bs_append(const ArgVal &Fail, mov_arg(ARG5, ExtraHeap); mov_arg(ARG6, Unit); - mov_arg(ArgVal(ArgVal::TYPE::x, Live.getValue()), Bin); + mov_arg(ArgXRegister(Live.get()), Bin); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<6>(erts_bs_append); - emit_leave_runtime(); + emit_leave_runtime(); emit_test_the_non_value(RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); /* The error has been prepared in `erts_bs_append` */ - emit_handle_error(); + emit_raise_exception(); a.bind(next); } mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_bs_private_append(const ArgVal &Fail, - const ArgVal &Unit, - const ArgVal &Size, - const ArgVal &Src, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_bs_private_append(const ArgLabel &Fail, + const ArgWord &Unit, + const ArgSource &Size, + const ArgRegister &Src, + const ArgXRegister &Dst) { Label next; - if (Fail.getValue() == 0) { + if (Fail.get() == 0) { next = a.newLabel(); } @@ -1531,12 +1729,12 @@ void BeamModuleAssembler::emit_i_bs_private_append(const ArgVal &Fail, emit_test_the_non_value(RET); - if (Fail.getValue() != 0) { - a.je(labels[Fail.getValue()]); + if (Fail.get() != 0) { + a.je(resolve_beam_label(Fail)); } else { a.short_().jne(next); /* The error has been prepared in `erts_bs_private_append` */ - emit_handle_error(); + emit_raise_exception(); a.bind(next); } @@ -1544,70 +1742,2662 @@ void BeamModuleAssembler::emit_i_bs_private_append(const ArgVal &Fail, } void BeamModuleAssembler::emit_bs_init_writable() { - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); a.mov(ARG2, getXRef(0)); runtime_call<2>(erts_bs_init_writable); a.mov(getXRef(0), RET); - emit_leave_runtime(); + emit_leave_runtime(); } -/* Old compatibility instructions for <= OTP-21. Kept in order to be able to - * load old code. While technically we could remove these in OTP-24, we've - * decided to keep them until at least OTP-25 to make things easier for - * users. */ -void BeamModuleAssembler::emit_i_bs_start_match2(const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Live, - const ArgVal &Slots, - const ArgVal &Dst) { - mov_arg(ARG1, Src); - mov_arg(ARG2, Live); - mov_arg(ARG3, Slots); - - emit_enter_runtime(); +void BeamGlobalAssembler::emit_bs_create_bin_error_shared() { + emit_enter_runtime(); - a.mov(ARG4, c_p); - load_x_reg_array(ARG5); - runtime_call<5>(beam_jit_bs_start_match2); + /* ARG3 is already set by the caller */ + a.mov(ARG2, ARG4); + a.mov(ARG4, ARG1); + a.mov(ARG1, c_p); + runtime_call<4>(beam_jit_bs_construct_fail_info); - emit_leave_runtime(); + emit_leave_runtime(); - emit_test_the_non_value(RET); - a.je(labels[Fail.getValue()]); - mov_arg(Dst, RET); -} + /* We must align the return address to make it a proper tagged CP, in case + * we were called with `safe_fragment_call`. This is safe because we will + * never actually return to the return address. */ + a.pop(ARG2); + a.and_(ARG2, imm(-8)); -void BeamModuleAssembler::emit_i_bs_save2(const ArgVal &Ctx, - const ArgVal &Slot) { - int slot_offset = offsetof(ErlBinMatchState, save_offset) + - (sizeof(Eterm) * Slot.getValue()); +#ifdef NATIVE_ERLANG_STACK + a.push(ARG2); - mov_arg(ARG1, Ctx); + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { +# ifdef ERLANG_FRAME_POINTERS + a.push(frame_pointer); +# endif + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_RA); + } +#endif - a.mov(ARG2, emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset))); - a.mov(emit_boxed_val(ARG1, slot_offset), ARG2); + mov_imm(ARG4, nullptr); + a.jmp(labels[raise_exception_shared]); } -void BeamModuleAssembler::emit_i_bs_restore2(const ArgVal &Ctx, - const ArgVal &Slot) { - int slot_offset = offsetof(ErlBinMatchState, save_offset) + - (sizeof(Eterm) * Slot.getValue()); +/* + * ARG1 = tagged bignum term + * + * On return, Z is set if ARG1 is not a bignum. Otherwise, Z is clear and + * ARG1 is the 64 least significant bits of the bignum. + */ +void BeamGlobalAssembler::emit_get_sint64_shared() { + Label success = a.newLabel(); + Label fail = a.newLabel(); + + emit_is_boxed(fail, ARG1); + x86::Gp boxed_ptr = emit_ptr_val(ARG4, ARG1); + a.mov(ARG2, emit_boxed_val(boxed_ptr)); + a.mov(ARG3, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.and_(ARG2, imm(_TAG_HEADER_MASK)); + a.cmp(ARG2, imm(POS_BIG_SUBTAG)); + a.je(success); + + a.cmp(ARG2, imm(NEG_BIG_SUBTAG)); + a.jne(fail); + + a.neg(ARG3); - mov_arg(ARG1, Ctx); + a.bind(success); + { + a.mov(ARG1, ARG3); + /* Clear Z flag. + * + * ARG2 is known to be POS_BIG_SUBTAG or NEG_BIG_SUBTAG at this point. + */ + ERTS_CT_ASSERT(POS_BIG_SUBTAG != 0 && NEG_BIG_SUBTAG != 0); + a.test(ARG2, ARG2); + a.ret(); + } - a.mov(ARG2, emit_boxed_val(ARG1, slot_offset)); - a.mov(emit_boxed_val(ARG1, offsetof(ErlBinMatchState, mb.offset)), ARG2); + a.bind(fail); + { + a.xor_(ARG2, ARG2); /* Set Z flag */ + a.ret(); + } } -void BeamModuleAssembler::emit_bs_context_to_binary(const ArgVal &Src) { - mov_arg(ARG1, Src); +struct BscSegment { + BscSegment() + : type(am_false), unit(1), flags(0), src(ArgNil()), size(ArgNil()), + error_info(0), effectiveSize(-1), action(action::DIRECT) { + } - emit_enter_runtime(); + Eterm type; + Uint unit; + Uint flags; + ArgVal src; + ArgVal size; + + Uint error_info; + Sint effectiveSize; + + /* Here are sub actions for storing integer segments. + * + * We use the ACCUMULATE_FIRST and ACCUMULATE actions to shift the + * values of segments with known, small sizes (no more than 64 bits) + * into an accumulator register. + * + * When no more segments can be accumulated, the STORE action is + * used to store the value of the accumulator into the binary. + * + * The DIRECT action is used when it is not possible to use the + * accumulator (for unknown or too large sizes). + */ + enum class action { DIRECT, ACCUMULATE_FIRST, ACCUMULATE, STORE } action; +}; + +static std::vector bs_combine_segments( + const std::vector segments) { + std::vector segs; + + for (auto seg : segments) { + switch (seg.type) { + case am_integer: { + if (!(0 < seg.effectiveSize && seg.effectiveSize <= 64)) { + /* Unknown or too large size. Handle using the default + * DIRECT action. */ + segs.push_back(seg); + continue; + } + + if (seg.flags & BSF_LITTLE || segs.size() == 0 || + segs.back().action == BscSegment::action::DIRECT) { + /* There are no previous compatible ACCUMULATE / STORE + * actions. Create the first ones. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + continue; + } - runtime_call<1>(beam_jit_bs_context_to_binary); + auto prev = segs.back(); + if (prev.flags & BSF_LITTLE) { + /* Little-endian segments cannot be combined with other + * segments. Create new ACCUMULATE_FIRST / STORE actions. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + continue; + } - emit_leave_runtime(); + /* The current segment is compatible with the previous + * segment. Try combining them. */ + if (prev.effectiveSize + seg.effectiveSize <= 64) { + /* The combined values of the segments fits in the + * accumulator. Insert an ACCUMULATE action for the + * current segment before the pre-existing STORE + * action. */ + segs.pop_back(); + prev.effectiveSize += seg.effectiveSize; + seg.action = BscSegment::action::ACCUMULATE; + segs.push_back(seg); + segs.push_back(prev); + } else { + /* The size exceeds 64 bits. Can't combine. */ + seg.action = BscSegment::action::ACCUMULATE_FIRST; + segs.push_back(seg); + seg.action = BscSegment::action::STORE; + segs.push_back(seg); + } + break; + } + default: + segs.push_back(seg); + break; + } + } + return segs; +} + +/* + * In: + * bin_offset = if valid, register to store the lower 32 bits + * of the bit offset into the binary + * bin_ptr = register to store pointer to current byte in + * bit_offset = current bit offset into binary, or -1 if unknown + * size = size of segment to be constructed + * (ignored if size_reg is valid register) + * size_reg = if a valid register, it contains the size of + * the segment to be constructed + * + * Out: + * bin_offset register = the lower 32 bits of the bit offset + * into the binary + * bin_ptr register = pointer to current byte + * + * Preserves all other registers except RET. + */ +void BeamModuleAssembler::update_bin_state(x86::Gp bin_offset, + x86::Gp current_byte, + Sint bit_offset, + Sint size, + x86::Gp size_reg) { + const int x_reg_offset = offsetof(ErtsSchedulerRegisters, x_reg_array.d); + const int cur_bin_base = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state) + + offsetof(struct erl_bits_state, erts_current_bin_); + const int cur_bin_offset = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state) + + offsetof(struct erl_bits_state, erts_bin_offset_); + + x86::Mem mem_bin_base = + x86::Mem(registers, cur_bin_base - x_reg_offset, sizeof(UWord)); + x86::Mem mem_bin_offset = + x86::Mem(registers, cur_bin_offset - x_reg_offset, sizeof(UWord)); + + if (bit_offset % 8 != 0 || !Support::isInt32(bit_offset + size)) { + /* The bit offset is unknown or not byte-aligned. Alternatively, + * the sum of bit_offset and size does not fit in an immediate. */ + a.mov(current_byte, mem_bin_offset); + a.mov(RET, mem_bin_base); + + if (bin_offset.isValid()) { + a.mov(bin_offset.r32(), current_byte.r32()); + } + if (size_reg.isValid()) { + a.add(mem_bin_offset, size_reg); + } else { + a.add(mem_bin_offset, imm(size)); + } + a.shr(current_byte, imm(3)); + a.add(current_byte, RET); + } else { + ASSERT(size >= 0 || size_reg.isValid()); + ASSERT(bit_offset % 8 == 0); + + comment("optimized updating of binary construction state"); + a.mov(current_byte, mem_bin_base); + if (bit_offset) { + a.add(current_byte, imm(bit_offset >> 3)); + } + if (size_reg.isValid()) { + a.add(mem_bin_offset, size_reg); + } else { + a.mov(mem_bin_offset, imm(bit_offset + size)); + } + } +} + +bool BeamModuleAssembler::need_mask(const ArgVal Val, Sint size) { + if (size == 64) { + return false; + } else { + auto [min, max] = getClampedRange(Val); + return !(0 <= min && max >> size == 0); + } +} + +/* + * The size of the segment is assumed to be in ARG3. + */ +void BeamModuleAssembler::set_zero(Sint effectiveSize) { + update_bin_state(ARG2, ARG1, -1, -1, ARG3); + + mov_imm(RET, 0); + + if (effectiveSize < 0 || effectiveSize > 128) { + /* Size is unknown or greater than 128. Modern CPUs have an + * enhanced "rep stosb" instruction that in most circumstances + * is the fastest way to clear blocks of more than 128 + * bytes. */ + Label done = a.newLabel(); + + if (effectiveSize < 0) { + a.test(ARG3, ARG3); + a.short_().jz(done); + } + + if (ARG1 != x86::rdi) { + a.mov(x86::rdi, ARG1); + } + a.mov(x86::rcx, ARG3); + a.add(x86::rcx, imm(7)); + a.shr(x86::rcx, imm(3)); + a.rep().stosb(); + + a.bind(done); + } else { + /* The size is known and it is at most 128 bits. */ + Uint offset = 0; + + ASSERT(0 <= effectiveSize && effectiveSize <= 128); + + if (effectiveSize == 128) { + a.mov(x86::Mem(ARG1, offset, 8), RET); + offset += 8; + } + + if (effectiveSize >= 64) { + a.mov(x86::Mem(ARG1, offset, 8), RET); + offset += 8; + } + + if ((effectiveSize & 63) >= 32) { + a.mov(x86::Mem(ARG1, offset, 4), RETd); + offset += 4; + } + + if ((effectiveSize & 31) >= 16) { + a.mov(x86::Mem(ARG1, offset, 2), RET.r16()); + offset += 2; + } + + if ((effectiveSize & 15) >= 8) { + a.mov(x86::Mem(ARG1, offset, 1), RET.r8()); + offset += 1; + } + + if ((effectiveSize & 7) > 0) { + a.mov(x86::Mem(ARG1, offset, 1), RET.r8()); + } + } +} + +/* + * In: + * + * ARG3 = valid unicode code point (=> 0x80) to encode + * + * Out: + * + * ARG3d = the code point encoded in UTF-8. + * ARG2 = number of bits of result (16, 24, or 32) + * + * Clobbers RET and the other ARG* registers. + */ +void BeamGlobalAssembler::emit_construct_utf8_shared() { + Label more_than_two_bytes = a.newLabel(); + Label four_bytes = a.newLabel(); + const x86::Gp tmp1 = ARG1; + const x86::Gp tmp2 = ARG2; + const x86::Gp value = ARG3; + const x86::Gp num_bits = ARG2; + + a.mov(RETd, value.r32()); + a.and_(RETd, imm(0x3f)); + + a.cmp(value.r32(), imm(0x800)); + a.jae(more_than_two_bytes); + + a.shl(RETd, imm(8)); + + a.shr(value, imm(6)); + + a.or_(value.r32(), RETd); + a.or_(value.r32(), imm(0x80c0)); + + mov_imm(num_bits, 16); + a.ret(); + + /* Test whether the value should be encoded in four bytes. */ + a.bind(more_than_two_bytes); + a.cmp(value.r32(), imm(0x10000)); + a.jae(four_bytes); + + /* Encode Unicode code point in three bytes. */ + a.shl(RETd, imm(16)); + + a.lea(tmp1.r32(), x86::Mem(0ULL, ARG3, 2, 0)); + a.and_(tmp1.r32(), imm(0x3f00)); + + a.shr(value.r32(), imm(12)); + a.or_(value.r32(), tmp1.r32()); + a.or_(value.r32(), RETd); + a.or_(value.r32(), imm(0x8080e0)); + + mov_imm(num_bits, 24); + a.ret(); + + /* Encode Unicode code point in four bytes. */ + a.bind(four_bytes); + a.shl(RETd, imm(24)); + + a.mov(tmp1.r32(), value.r32()); + a.shl(tmp1.r32(), imm(10)); + a.and_(tmp1.r32(), imm(0x3f0000)); + + a.mov(tmp2.r32(), value.r32()); + a.shr(tmp2.r32(), imm(4)); + a.and_(tmp2.r32(), imm(0x3f00)); + + a.shr(value.r32(), imm(18)); + + a.or_(value.r32(), RETd); + a.or_(value.r32(), tmp1.r32()); + a.or_(value.r32(), tmp2.r32()); + a.or_(value.r32(), imm(0xffffffff808080f0)); + + mov_imm(num_bits, 32); + a.ret(); +} + +void BeamModuleAssembler::emit_construct_utf8(const ArgVal &Src, + Sint bit_offset, + bool is_byte_aligned) { + Label prepare_store = a.newLabel(); + Label store = a.newLabel(); + Label next = a.newLabel(); + +#ifdef WIN32 + const x86::Gp bin_ptr = ARG4; + const x86::Gp bin_offset = is_byte_aligned ? x86::Gp() : ARG1; +#else + const x86::Gp bin_ptr = ARG1; + const x86::Gp bin_offset = is_byte_aligned ? x86::Gp() : ARG4; +#endif + ASSERT(!bin_offset.isValid() || bin_offset == x86::rcx); + + /* The following two registers must be the same as + * emit_construct_utf8_shared() expects. */ + const x86::Gp code_point = ARG3; + const x86::Gp size_reg = ARG2; + + comment("construct utf8 segment"); + + mov_arg(code_point, Src); + a.shr(code_point.r32(), imm(_TAG_IMMED1_SIZE)); + mov_imm(size_reg, 8); + a.cmp(code_point, imm(0x80)); + a.jb(prepare_store); + + safe_fragment_call(ga->get_construct_utf8_shared()); + + a.bind(prepare_store); + + update_bin_state(bin_offset, bin_ptr, bit_offset, -1, size_reg); + + if (!is_byte_aligned) { + /* Bit offset is unknown and is not known to be + * byte aligned. Must test alignment. */ + a.and_(bin_offset.r32(), imm(7)); + a.je(store); + + /* We must combine the last partial byte with the UTF-8 + * encoded code point. */ + + a.movzx(RETd, x86::byte_ptr(bin_ptr)); + + a.bswap(code_point); + a.shr(code_point, bin_offset.r8()); + a.bswap(code_point); + + a.shl(RETd, bin_offset.r8()); + a.and_(RETd, imm(~0xff)); + a.shr(RETd, bin_offset.r8()); + + a.or_(code_point, RET); + + a.add(size_reg.r32(), imm(8)); + } + + a.bind(store); + if (bit_offset % (4 * 8) == 0) { + /* This segment is aligned on a 4-byte boundary. This implies + * that a 4-byte write will be inside the allocated binary. */ + a.mov(x86::dword_ptr(bin_ptr), code_point.r32()); + } else { + Label do_store_1 = a.newLabel(); + Label do_store_2 = a.newLabel(); + + /* Unsuitable or unknown alignment. We must be careful not + * to write beyound the allocated end of the binary. */ + a.cmp(size_reg.r8(), imm(8)); + a.short_().jne(do_store_1); + + a.mov(x86::byte_ptr(bin_ptr), code_point.r8()); + a.short_().jmp(next); + + a.bind(do_store_1); + a.cmp(size_reg.r8(), imm(24)); + a.ja(do_store_2); + + a.mov(x86::word_ptr(bin_ptr), code_point.r16()); + a.cmp(size_reg.r8(), imm(16)); + a.short_().je(next); + + a.shr(code_point.r32(), imm(16)); + a.mov(x86::byte_ptr(bin_ptr, 2), code_point.r8()); + a.short_().jmp(next); + + a.bind(do_store_2); + a.mov(x86::dword_ptr(bin_ptr), code_point.r32()); + + if (!is_byte_aligned) { + a.cmp(size_reg.r8(), imm(32)); + a.je(next); + + a.shr(code_point, imm(32)); + a.mov(x86::byte_ptr(bin_ptr, 4), code_point.r8()); + } + } + + a.bind(next); +} +/* + * In: + * ARG1 = pointer to current byte + * ARG3 = bit offset + * ARG4 = number of bits to write + * ARG5 = data to write + */ +void BeamGlobalAssembler::emit_store_unaligned() { + Label loop = a.newLabel(); + Label done = a.newLabel(); + const x86::Gp bin_ptr = ARG1; + const x86::Gp left_bit_offset = ARG3; + const x86::Gp right_bit_offset = ARG2; + const x86::Gp num_bits = ARG4; + const x86::Gp bitdata = ARG5; + + a.movzx(RETd, x86::byte_ptr(bin_ptr)); + + a.xchg(left_bit_offset, x86::rcx); + + a.mov(right_bit_offset, bitdata); + a.and_(right_bit_offset, imm(0xff)); + a.shr(right_bit_offset, x86::cl); + + a.shl(RETd, x86::cl); + a.and_(RETd, imm(~0xff)); + a.shr(RETd, x86::cl); + + a.xchg(left_bit_offset, x86::rcx); + + a.or_(RETd, ARG2d); + a.mov(byte_ptr(ARG1), RETb); + a.add(ARG1, imm(1)); + + mov_imm(right_bit_offset, 8); + a.sub(right_bit_offset, left_bit_offset); + + a.xchg(right_bit_offset, x86::rcx); + a.bswap(bitdata); + a.shl(bitdata, x86::cl); + a.xchg(right_bit_offset, x86::rcx); + + a.sub(ARG4, right_bit_offset); + a.jle(done); + + a.bind(loop); + a.rol(bitdata, imm(8)); + a.mov(byte_ptr(ARG1), bitdata.r8()); + a.add(ARG1, imm(1)); + a.sub(num_bits, imm(8)); + a.jg(loop); + + a.bind(done); + a.ret(); +} + +bool BeamModuleAssembler::bs_maybe_enter_runtime(bool entered) { + if (!entered) { + comment("enter runtime"); + emit_enter_runtime(); + } + return true; +} + +void BeamModuleAssembler::bs_maybe_leave_runtime(bool entered) { + if (entered) { + comment("leave runtime"); + emit_leave_runtime(); + } +} + +void BeamModuleAssembler::emit_i_bs_create_bin(const ArgLabel &Fail, + const ArgWord &Alloc, + const ArgWord &Live0, + const ArgRegister &Dst, + const Span &args) { + Uint num_bits = 0; + std::size_t n = args.size(); + std::vector segments; + Label error; /* Intentionally uninitialized */ + ArgWord Live = Live0; + x86::Gp sizeReg; + Sint allocated_size = -1; + bool need_error_handler = false; + bool runtime_entered = false; + + /* + * Collect information about each segment and calculate sizes of + * fixed segments. + */ + for (std::size_t i = 0; i < n; i += 6) { + BscSegment seg; + JitBSCOp bsc_op; + Uint bsc_segment; + + seg.type = args[i].as().get(); + bsc_segment = args[i + 1].as().get(); + seg.unit = args[i + 2].as().get(); + seg.flags = args[i + 3].as().get(); + seg.src = args[i + 4]; + seg.size = args[i + 5]; + + switch (seg.type) { + case am_float: + bsc_op = BSC_OP_FLOAT; + break; + case am_integer: + bsc_op = BSC_OP_INTEGER; + break; + case am_utf8: + bsc_op = BSC_OP_UTF8; + break; + case am_utf16: + bsc_op = BSC_OP_UTF16; + break; + case am_utf32: + bsc_op = BSC_OP_UTF32; + break; + default: + bsc_op = BSC_OP_BINARY; + break; + } + + /* + * Save segment number and operation for use in extended + * error information. + */ + seg.error_info = beam_jit_set_bsc_segment_op(bsc_segment, bsc_op); + + /* + * Test whether we can omit the code for the error handler. + */ + switch (seg.type) { + case am_append: + if (!(exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit)) { + need_error_handler = true; + } + break; + case am_binary: + if (!(seg.size.isAtom() && seg.size.as().get() == am_all && + exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit)) { + need_error_handler = true; + } + break; + case am_integer: + if (!exact_type(seg.src)) { + need_error_handler = true; + } + break; + case am_private_append: + case am_string: + break; + default: + need_error_handler = true; + break; + } + + /* + * As soon as we have entered runtime mode, Y registers can no + * longer be accessed in the usual way. Therefore, if the source + * and/or size are in Y registers, copy them to X registers. Be + * careful to preserve any associated type information. + */ + if (seg.src.isYRegister()) { + auto reg = + seg.src.as().copy(Live.get()); + ASSERT(reg.typeIndex() == seg.src.as().typeIndex()); + mov_arg(reg, seg.src); + + Live = Live + 1; + seg.src = reg; + } + + if (seg.size.isYRegister()) { + auto reg = + seg.size.as().copy(Live.get()); + ASSERT(reg.typeIndex() == seg.size.as().typeIndex()); + mov_arg(reg, seg.size); + + Live = Live + 1; + seg.size = reg; + } + + if (seg.size.isSmall() && seg.unit != 0) { + Uint unsigned_size = seg.size.as().getUnsigned(); + + if ((unsigned_size >> (sizeof(Eterm) - 1) * 8) == 0) { + /* This multiplication cannot overflow. */ + Uint seg_size = seg.unit * unsigned_size; + seg.effectiveSize = seg_size; + num_bits += seg_size; + } + } + + if (seg.effectiveSize < 0 && seg.type != am_append && + seg.type != am_private_append) { + /* We need a callee-save register for the size. We'll pick the + * active code index register because it's not used in any capacity + * here. Note that we have to spill it since `save_calls` may be + * enabled and we'll lose that information if we blindly re-read + * the index. */ + sizeReg = active_code_ix; + need_error_handler = true; + } + + segments.insert(segments.end(), seg); + } + + /* + * Test whether a heap binary of fixed size will result from the + * construction. If so, allocate and construct the binary now + * before entering the runtime mode. + */ + if (!sizeReg.isValid() && num_bits % 8 == 0 && + num_bits / 8 <= ERL_ONHEAP_BIN_LIMIT && segments[0].type != am_append && + segments[0].type != am_private_append) { + const int x_reg_offset = + offsetof(ErtsSchedulerRegisters, x_reg_array.d); + const int cur_bin_base = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state) + + offsetof(struct erl_bits_state, erts_current_bin_); + const int cur_bin_offset = + offsetof(ErtsSchedulerRegisters, aux_regs.d.erl_bits_state) + + offsetof(struct erl_bits_state, erts_bin_offset_); + x86::Mem mem_bin_base = + x86::qword_ptr(registers, cur_bin_base - x_reg_offset); + x86::Mem mem_bin_offset = + x86::qword_ptr(registers, cur_bin_offset - x_reg_offset); + Uint num_bytes = num_bits / 8; + + comment("allocate heap binary"); + allocated_size = (num_bytes + 7) & (-8); + + /* Ensure that there is enough room on the heap. */ + Uint need = heap_bin_size(num_bytes) + Alloc.get(); + emit_gc_test(ArgWord(0), ArgWord(need), Live); + + /* Create the heap binary. */ + a.lea(RET, x86::qword_ptr(HTOP, TAG_PRIMARY_BOXED)); + a.mov(TMP_MEM1q, RET); + a.mov(x86::qword_ptr(HTOP, 0), imm(header_heap_bin(num_bytes))); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), imm(num_bytes)); + + /* Initialize the erl_bin_state struct. */ + a.add(HTOP, imm(sizeof(Eterm[2]))); + a.mov(mem_bin_base, HTOP); + a.mov(mem_bin_offset, imm(0)); + + /* Update HTOP. */ + a.add(HTOP, imm(allocated_size)); + } + + if (!need_error_handler) { + comment("(cannot fail)"); + } else { + Label past_error = a.newLabel(); + + runtime_entered = bs_maybe_enter_runtime(false); + a.short_().jmp(past_error); + + /* + * ARG1 = optional bad size value; valid if BSC_VALUE_ARG1 is set in + * ARG4 + * + * ARG3 = optional bad size value; valid if BSC_VALUE_ARG3 is set + * in ARG4 + * + * ARG4 = packed error information + */ + error = a.newLabel(); + a.bind(error); + bs_maybe_leave_runtime(runtime_entered); + + if (sizeReg.isValid()) { + a.mov(sizeReg, TMP_MEM5q); + } + + comment("handle error"); + if (Fail.get() != 0) { + a.jmp(resolve_beam_label(Fail)); + } else { + safe_fragment_call(ga->get_bs_create_bin_error_shared()); + } + + a.bind(past_error); + } + + /* We count the total number of bits in an unsigned integer. To + * avoid having to check for overflow when adding to the counter, + * we ensure that the signed size of each segment fits in a + * word. */ + if (sizeReg.isValid()) { + comment("calculate sizes"); + a.mov(TMP_MEM5q, sizeReg); + mov_imm(sizeReg, num_bits); + } + + /* Generate code for calculating the size of the binary to be + * created. */ + for (auto seg : segments) { + if (seg.effectiveSize >= 0) { + continue; + } + + if (seg.type == am_append || seg.type == am_private_append) { + continue; + } + + if (seg.size.isAtom() && seg.size.as().get() == am_all && + seg.type == am_binary) { + comment("size of an entire binary"); + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + mov_arg(ARG1, seg.src); + + if (exact_type(seg.src)) { + auto unit = getSizeUnit(seg.src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + + if (is_bitstring) { + comment("inlined size code because the value is always " + "a bitstring"); + } else { + comment("inlined size code because the value is always " + "a binary"); + } + + a.mov(ARG2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + + if (is_bitstring) { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + } + + a.lea(sizeReg, x86::Mem(sizeReg, ARG2, 3, 0, 1)); + + if (is_bitstring) { + Label not_sub_bin = a.newLabel(); + const auto diff_mask = + _TAG_HEADER_SUB_BIN - _TAG_HEADER_REFC_BIN; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & diff_mask) != 0 && + (_TAG_HEADER_REFC_BIN & diff_mask) == 0 && + (_TAG_HEADER_HEAP_BIN & diff_mask) == 0); + a.test(RETb, imm(diff_mask)); + a.short_().jz(not_sub_bin); + + a.movzx(RETd, + emit_boxed_val(boxed_ptr, + offsetof(ErlSubBin, bitsize), + 1)); + a.add(sizeReg, RET); + + a.bind(not_sub_bin); + } + } else { + runtime_call<1>(beam_jit_bs_bit_size); + if (Fail.get() == 0) { + mov_arg(ARG1, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.test(RET, RET); + a.js(error); + a.add(sizeReg, RET); + } + } else if (seg.unit != 0) { + bool can_fail = true; + comment("size binary/integer/float/string"); + + if (always_small(seg.size)) { + auto min = std::get<0>(getClampedRange(seg.size)); + if (min >= 0) { + can_fail = false; + } + } + + if (can_fail && Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_DEPENDS, + BSC_INFO_SIZE, + BSC_VALUE_ARG1)); + } + + mov_arg(ARG1, seg.size); + + if (always_small(seg.size)) { + comment("skipped test for small size since it is always small"); + } else if (always_one_of(seg.size)) { + comment("simplified test for small size since it is a number"); + a.test(ARG1.r8(), imm(TAG_PRIMARY_LIST)); + a.je(error); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.jne(error); + } + + a.mov(RET, ARG1); + a.sar(RET, imm(_TAG_IMMED1_SIZE)); + if (can_fail) { + a.js(error); + } + if (seg.unit != 1) { + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_SYSTEM_LIMIT, + BSC_INFO_SIZE, + BSC_VALUE_ARG1)); + } + a.imul(RET, RET, imm(seg.unit)); + a.jo(error); + } + a.add(sizeReg, RET); + } else { + switch (seg.type) { + case am_utf8: { + Label next = a.newLabel(); + + comment("size utf8"); + mov_arg(ARG1, seg.src); + + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + + if (always_small(seg.src)) { + comment("skipped test for small value since it is always " + "small"); + } else if (always_one_of(seg.src)) { + comment("simplified test for small operand since other " + "types are boxed"); + emit_is_not_boxed(error, ARG1); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.jne(error); + } + + mov_imm(RET, 0); + a.mov(RETb, imm(1)); + a.cmp(ARG1, imm(make_small(0x80UL))); + a.short_().jb(next); + + a.mov(RETb, imm(2)); + a.cmp(ARG1, imm(make_small(0x800UL))); + a.short_().jb(next); + + /* Ensure that the value is not in the invalid range + * 0xD800 through 0xDFFF. */ + a.mov(ARG2, ARG1); + a.sar(ARG2, imm(11 + _TAG_IMMED1_SIZE)); + a.cmp(ARG2, imm(0x1b)); + a.je(error); + + a.cmp(ARG1, imm(make_small(0x10000UL))); + a.setae(RETb); + a.add(RETb, imm(3)); + + auto [min, max] = getClampedRange(seg.src); + if (0 <= min && max < 0x110000) { + comment("skipped range check for unicode code point"); + } else { + a.cmp(ARG1, imm(make_small(0x110000))); + a.jae(error); + } + + a.bind(next); + a.lea(sizeReg, x86::Mem(sizeReg, RET, 3, 0, 1)); + break; + } + case am_utf16: { + mov_arg(ARG1, seg.src); + mov_imm(RET, 2 * 8); + mov_imm(ARG2, 4 * 8); + a.cmp(ARG1, imm(make_small(0x10000UL))); + a.cmovae(RET, ARG2); + a.add(sizeReg, RET); + break; + } + case am_utf32: { + Label next = a.newLabel(); + + mov_arg(ARG1, seg.src); + + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + + a.add(sizeReg, imm(4 * 8)); + + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.jne(error); + + a.cmp(ARG1, imm(make_small(0xD800UL))); + a.short_().jb(next); + a.cmp(ARG1, imm(make_small(0xDFFFUL))); + a.jbe(error); + a.cmp(ARG1, imm(make_small(0x10FFFFUL))); + a.ja(error); + + a.bind(next); + break; + } + default: + ASSERT(0); + } + } + } + + segments = bs_combine_segments(segments); + + /* Allocate the binary. */ + if (segments[0].type == am_append) { + BscSegment seg = segments[0]; + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + comment("append to binary"); + mov_arg(ARG3, Live); + if (sizeReg.isValid()) { + a.mov(ARG4, sizeReg); + } else { + mov_imm(ARG4, num_bits); + } + mov_arg(ARG5, Alloc); + mov_imm(ARG6, seg.unit); + mov_arg(ArgXRegister(Live.get()), seg.src); + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<6>(erts_bs_append_checked); + + if (exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit) { + /* There is no way the call can fail with a system_limit + * exception on a 64-bit architecture. */ + comment("skipped test for success because units are compatible"); + } else { + if (Fail.get() == 0) { + mov_arg(ARG1, ArgXRegister(Live.get())); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_FVALUE, + BSC_VALUE_ARG1)); + } + emit_test_the_non_value(RET); + a.je(error); + } + a.mov(TMP_MEM1q, RET); + } else if (segments[0].type == am_private_append) { + BscSegment seg = segments[0]; + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + comment("private append to binary"); + ASSERT(Alloc.get() == 0); + mov_arg(ARG2, seg.src); + if (sizeReg.isValid()) { + a.mov(ARG3, sizeReg); + } else { + mov_imm(ARG3, num_bits); + } + a.mov(ARG4, seg.unit); + a.mov(ARG1, c_p); + runtime_call<4>(erts_bs_private_append_checked); + /* There is no way the call can fail on a 64-bit architecture. */ + a.mov(TMP_MEM1q, RET); + } else if (allocated_size >= 0) { + /* The binary has already been allocated. */ + } else { + comment("allocate binary"); + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + mov_arg(ARG5, Alloc); + mov_arg(ARG6, Live); + load_erl_bits_state(ARG3); + load_x_reg_array(ARG2); + a.mov(ARG1, c_p); + if (sizeReg.isValid()) { + a.mov(ARG4, sizeReg); + runtime_call<6>(beam_jit_bs_init_bits); + } else { + allocated_size = (num_bits + 7) / 8; + if (allocated_size <= ERL_ONHEAP_BIN_LIMIT) { + allocated_size = (allocated_size + 7) & (-8); + } + mov_imm(ARG4, num_bits); + runtime_call<6>(beam_jit_bs_init_bits); + } + a.mov(TMP_MEM1q, RET); + } + + /* Keep track of the bit offset from the being of the binary. + * Set to -1 if offset is not known (when a segment of unknown + * size has been seen). */ + Sint bit_offset = 0; + + /* Keep track of whether the current segment is byte-aligned. (A + * segment can be known to be byte-aligned even if the bit offset + * is unknown.) */ + bool is_byte_aligned = true; + + /* Build each segment of the binary. */ + for (auto seg : segments) { + switch (seg.type) { + case am_append: + case am_private_append: + bit_offset = -1; + break; + case am_binary: { + Uint error_info; + bool can_fail = true; + + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + comment("construct a binary segment"); + if (seg.effectiveSize >= 0) { + /* The segment has a literal size. */ + mov_imm(ARG3, seg.effectiveSize); + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary); + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); + } else if (seg.size.isAtom() && + seg.size.as().get() == am_all) { + /* Include the entire binary/bitstring in the + * resulting binary. */ + a.mov(ARG3, seg.unit); + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary_all); + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_UNIT, + BSC_VALUE_FVALUE); + if (exact_type(seg.src) && + std::gcd(seg.unit, getSizeUnit(seg.src)) == seg.unit) { + comment("skipped test for success because units are " + "compatible"); + can_fail = false; + } + } else { + /* The size is a variable. We have verified that + * the value is a non-negative small in the + * appropriate range. Multiply the size with the + * unit. */ + mov_arg(ARG3, seg.size); + a.sar(ARG3, imm(_TAG_IMMED1_SIZE)); + if (seg.unit != 1) { + mov_imm(RET, seg.unit); + a.mul(ARG3); /* CLOBBERS RDX = ARG3! */ + a.mov(ARG3, RET); + } + mov_arg(ARG2, seg.src); + a.mov(ARG1, c_p); + runtime_call<3>(erts_new_bs_put_binary); + error_info = beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_DEPENDS, + BSC_VALUE_FVALUE); + } + + if (can_fail) { + if (Fail.get() == 0) { + mov_imm(ARG4, error_info); + } + a.test(RETd, RETd); + a.je(error); + } + break; + } + case am_float: + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + comment("construct float segment"); + if (seg.effectiveSize >= 0) { + mov_imm(ARG3, seg.effectiveSize); + } else { + mov_arg(ARG3, seg.size); + a.sar(ARG3, imm(_TAG_IMMED1_SIZE)); + if (seg.unit != 1) { + mov_imm(RET, seg.unit); + a.mul(ARG3); /* CLOBBERS RDX = ARG3! */ + a.mov(ARG3, RET); + } + } + mov_arg(ARG2, seg.src); + mov_imm(ARG4, seg.flags); + a.mov(ARG1, c_p); + runtime_call<4>(erts_new_bs_put_float); + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_FVALUE, + BSC_VALUE_ARG1)); + } + a.mov(ARG1, RET); + emit_test_the_non_value(RET); + a.jne(error); + break; + case am_integer: + switch (seg.action) { + case BscSegment::action::ACCUMULATE_FIRST: + case BscSegment::action::ACCUMULATE: { + /* Shift an integer of known size (no more than 64 bits) + * into a word-size accumulator. */ + Label accumulate = a.newLabel(); + Label value_is_small = a.newLabel(); + x86::Gp tmp = ARG4; + x86::Gp bin_data = ARG5; + + comment("accumulate value for integer segment"); + if (seg.action == BscSegment::action::ACCUMULATE_FIRST) { + mov_imm(bin_data, 0); + } else if (seg.effectiveSize < 64) { + a.shl(bin_data, imm(seg.effectiveSize)); + } + mov_arg(ARG1, seg.src); + + if (!always_small(seg.src)) { + if (always_one_of(seg.src)) { + comment("simplified small test since all other types " + "are boxed"); + emit_is_boxed(value_is_small, seg.src, ARG1); + } else { + a.mov(ARG2d, ARG1d); + a.and_(ARG2d, imm(_TAG_IMMED1_MASK)); + a.cmp(ARG2d, imm(_TAG_IMMED1_SMALL)); + a.short_().je(value_is_small); + } + + /* The value is boxed. If it is a bignum, extract the + * least significant 64 bits. */ + safe_fragment_call(ga->get_get_sint64_shared()); + if (exact_type(seg.src)) { + a.short_().jmp(accumulate); + } else { + a.short_().jne(accumulate); + + /* Not a bignum. Signal error. */ + if (Fail.get() == 0) { + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.jmp(error); + } + } + + a.bind(value_is_small); + a.sar(ARG1, imm(_TAG_IMMED1_SIZE)); + + /* Mask (if needed) and accumulate. */ + a.bind(accumulate); + if (seg.effectiveSize == 64) { + a.mov(bin_data, ARG1); + } else if (!need_mask(seg.src, seg.effectiveSize)) { + comment("skipped masking because the value always fits"); + a.or_(bin_data, ARG1); + } else if (seg.effectiveSize == 32) { + a.mov(ARG1d, ARG1d); + a.or_(bin_data, ARG1); + } else if (seg.effectiveSize < 32) { + a.and_(ARG1, (1ULL << seg.effectiveSize) - 1); + a.or_(bin_data, ARG1); + } else { + mov_imm(tmp, (1ULL << seg.effectiveSize) - 1); + a.and_(ARG1, tmp); + a.or_(bin_data, ARG1); + } + break; + } + case BscSegment::action::STORE: { + /* The accumulator is now full or the next segment is + * not possible to accumulate, so it's time to store + * the accumulator to the current position in the + * binary. */ + Label store = a.newLabel(); + Label done = a.newLabel(); + x86::Gp bin_ptr = ARG1; + x86::Gp bin_offset = ARG3; + x86::Gp tmp = ARG4; + x86::Gp bin_data = ARG5; + + comment("construct integer segment from accumulator"); + + /* First we'll need to ensure that the value in the + * accumulator is in little endian format. */ + if (seg.effectiveSize % 8 != 0) { + Uint complete_bytes = 8 * (seg.effectiveSize / 8); + Uint num_partial = seg.effectiveSize % 8; + if ((seg.flags & BSF_LITTLE) == 0) { + a.shl(bin_data, imm(64 - seg.effectiveSize)); + a.bswap(bin_data); + } else { + Sint mask = (1ll << complete_bytes) - 1; + a.mov(RET, bin_data); + a.shr(RET, imm(complete_bytes)); + a.and_(RETd, imm((1ull << num_partial) - 1)); + a.shl(RET, imm(complete_bytes + 8 - num_partial)); + if (Support::isInt32(mask)) { + a.and_(bin_data, imm(mask)); + } else { + mov_imm(tmp, mask); + a.and_(bin_data, tmp); + } + a.or_(bin_data, RET); + } + } else if ((seg.flags & BSF_LITTLE) == 0) { + switch (seg.effectiveSize) { + case 8: + break; + case 32: + a.bswap(bin_data.r32()); + break; + case 64: + a.bswap(bin_data); + break; + default: + a.bswap(bin_data); + a.shr(bin_data, imm(64 - seg.effectiveSize)); + break; + } + } + + update_bin_state(bin_offset, + bin_ptr, + bit_offset, + seg.effectiveSize, + x86::Gp()); + + if (!is_byte_aligned) { + if (bit_offset < 0) { + /* Bit offset is unknown. Must test alignment. */ + a.and_(bin_offset, imm(7)); + a.short_().je(store); + } else if (bit_offset >= 0) { + /* Alignment is known to be unaligned. */ + mov_imm(bin_offset, bit_offset & 7); + } + + /* Bit offset is tested or known to be unaligned. */ + mov_imm(ARG4, seg.effectiveSize); + safe_fragment_call(ga->get_store_unaligned()); + + if (bit_offset < 0) { + /* The bit offset is unknown, which implies + * that there exists store code that we will + * need to branch past. */ + a.short_().jmp(done); + } + } + + a.bind(store); + + if (bit_offset <= 0 || is_byte_aligned) { + /* Bit offset is tested or known to be + * byte-aligned. Emit inline code to store the + * value of the accumulator into the binary. */ + int num_bytes = (seg.effectiveSize + 7) / 8; + + /* If more than one instruction is required for + * doing the store, test whether it would be safe + * to do a single 32 or 64 bit store. */ + switch (num_bytes) { + case 3: + if (bit_offset >= 0 && + allocated_size * 8 - bit_offset >= 32) { + comment("simplified complicated store"); + num_bytes = 4; + } + break; + case 5: + case 6: + case 7: + if (bit_offset >= 0 && + allocated_size * 8 - bit_offset >= 64) { + comment("simplified complicated store"); + num_bytes = 8; + } + break; + } + + do { + switch (num_bytes) { + case 1: + a.mov(x86::Mem(bin_ptr, 0, 1), bin_data.r8()); + break; + case 2: + a.mov(x86::Mem(bin_ptr, 0, 2), bin_data.r16()); + break; + case 3: + a.mov(x86::Mem(bin_ptr, 0, 2), bin_data.r16()); + a.shr(bin_data, imm(16)); + a.mov(x86::Mem(bin_ptr, 2, 1), bin_data.r8()); + break; + case 4: + a.mov(x86::Mem(bin_ptr, 0, 4), bin_data.r32()); + break; + case 5: + case 6: + case 7: + a.mov(x86::Mem(bin_ptr, 0, 4), bin_data.r32()); + a.add(bin_ptr, imm(4)); + a.shr(bin_data, imm(32)); + break; + case 8: + a.mov(x86::Mem(bin_ptr, 0, 8), bin_data); + num_bytes = 0; + break; + default: + ASSERT(0); + } + num_bytes -= 4; + } while (num_bytes > 0); + } + + a.bind(done); + break; + } + case BscSegment::action::DIRECT: + /* This segment either has a size exceeding the maximum + * accumulator size of 64 bits or has a variable size. + * + * First load the effective size (size * unit) into ARG3. + */ + comment("construct integer segment"); + if (seg.effectiveSize >= 0) { + mov_imm(ARG3, seg.effectiveSize); + } else { + mov_arg(ARG3, seg.size); + a.sar(ARG3, imm(_TAG_IMMED1_SIZE)); + if (Support::isPowerOf2(seg.unit)) { + Uint trailing_bits = Support::ctz(seg.unit); + if (trailing_bits) { + a.shl(ARG3, imm(trailing_bits)); + } + } else { + mov_imm(RET, seg.unit); + a.mul(ARG3); /* CLOBBERS RDX = ARG3! */ + a.mov(ARG3, RET); + } + } + + if (is_byte_aligned && seg.src.isSmall() && + seg.src.as().getSigned() == 0) { + /* Optimize the special case of setting a known + * byte-aligned segment to zero. */ + comment("optimized setting segment to 0"); + set_zero(seg.effectiveSize); + } else { + /* Call the helper function to fetch and store the + * integer into the binary. */ + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + mov_arg(ARG2, seg.src); + mov_imm(ARG4, seg.flags); + load_erl_bits_state(ARG1); + runtime_call<4>(erts_new_bs_put_integer); + if (exact_type(seg.src)) { + comment("skipped test for success because construction " + "can't fail"); + } else { + if (Fail.get() == 0) { + mov_arg(ARG1, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info( + seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.test(RETd, RETd); + a.je(error); + } + } + break; + } + break; + case am_string: { + ArgBytePtr string_ptr( + ArgVal(ArgVal::BytePtr, seg.src.as().get())); + + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + comment("insert string"); + ASSERT(seg.effectiveSize >= 0); + mov_imm(ARG3, seg.effectiveSize / 8); + mov_arg(ARG2, string_ptr); + load_erl_bits_state(ARG1); + runtime_call<3>(erts_new_bs_put_string); + } break; + case am_utf8: { + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + emit_construct_utf8(seg.src, bit_offset, is_byte_aligned); + break; + } + case am_utf16: + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + mov_arg(ARG2, seg.src); + a.mov(ARG3, seg.flags); + load_erl_bits_state(ARG1); + runtime_call<3>(erts_bs_put_utf16); + if (Fail.get() == 0) { + mov_arg(ARG1, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.test(RETd, RETd); + a.je(error); + break; + case am_utf32: + runtime_entered = bs_maybe_enter_runtime(runtime_entered); + mov_arg(ARG2, seg.src); + mov_imm(ARG3, 4 * 8); + a.mov(ARG4, seg.flags); + load_erl_bits_state(ARG1); + runtime_call<4>(erts_new_bs_put_integer); + if (Fail.get() == 0) { + mov_arg(ARG1, seg.src); + mov_imm(ARG4, + beam_jit_update_bsc_reason_info(seg.error_info, + BSC_REASON_BADARG, + BSC_INFO_TYPE, + BSC_VALUE_ARG1)); + } + a.test(RETd, RETd); + a.je(error); + break; + default: + ASSERT(0); + break; + } + + /* Try to keep track of the bit offset. */ + if (bit_offset >= 0 && (seg.action == BscSegment::action::DIRECT || + seg.action == BscSegment::action::STORE)) { + if (seg.effectiveSize >= 0) { + bit_offset += seg.effectiveSize; + } else { + bit_offset = -1; + } + } + + /* Try to keep track whether the next segment is byte + * aligned. */ + if (seg.type == am_append || seg.type == am_private_append) { + if (!exact_type(seg.src) || + std::gcd(getSizeUnit(seg.src), 8) != 8) { + is_byte_aligned = false; + } + } else if (bit_offset % 8 == 0) { + is_byte_aligned = true; + } else if (seg.effectiveSize >= 0) { + if (seg.effectiveSize % 8 != 0) { + is_byte_aligned = false; + } + } else if (std::gcd(seg.unit, 8) != 8) { + is_byte_aligned = false; + } + } + + bs_maybe_leave_runtime(runtime_entered); + + if (sizeReg.isValid()) { + a.mov(sizeReg, TMP_MEM5q); + } + + comment("done"); + a.mov(RET, TMP_MEM1q); + mov_arg(Dst, RET); +} + +/* + * Here follows the bs_match instruction and friends. + */ + +struct BsmSegment { + BsmSegment() + : action(action::TEST_HEAP), live(ArgNil()), size(0), unit(1), + flags(0), dst(ArgXRegister(0)){}; + + enum class action { + TEST_HEAP, + ENSURE_AT_LEAST, + ENSURE_EXACTLY, + READ, + EXTRACT_BINARY, + EXTRACT_INTEGER, + READ_INTEGER, + GET_INTEGER, + GET_BINARY, + SKIP, + DROP, + GET_TAIL, + EQ + } action; + ArgVal live; + Uint size; + Uint unit; + Uint flags; + ArgRegister dst; +}; + +void BeamModuleAssembler::emit_read_bits(Uint bits, + const x86::Gp bin_base, + const x86::Gp bin_offset, + const x86::Gp bitdata) { + Label read_done = a.newLabel(); + auto num_partial = bits % 8; + auto num_bytes_to_read = (bits + 7) / 8; + + ASSERT(bin_offset == x86::rcx); + + a.mov(RET, bin_offset); + a.shr(RET, imm(3)); + if (num_bytes_to_read != 1) { + a.add(bin_base, RET); + } + a.and_(bin_offset.r32(), imm(7)); + + /* + * Special-case handling of reading 8 or 9 bytes. + */ + if (num_bytes_to_read == 8) { + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(bitdata, x86::qword_ptr(bin_base, num_bytes_to_read - 8)); + } else { + a.mov(bitdata, x86::qword_ptr(bin_base, num_bytes_to_read - 8)); + a.bswap(bitdata); + } + + a.shl(bitdata, bin_offset.r8()); + + a.test(x86::cl, imm(7)); + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, this + * segment always needs an additional byte. */ + a.jz(read_done); + } else if (num_partial > 1) { + /* Non-byte-sized segment. Test whether we will need an + * additional byte. */ + a.cmp(bin_offset.r32(), imm(8 - num_partial)); + a.jle(read_done); + } + + if (num_partial != 1) { + /* Read an extra byte. */ + a.movzx(RETd, x86::byte_ptr(bin_base, 8)); + a.shl(RETd, bin_offset.r8()); + a.shr(RETd, imm(8)); + a.or_(bitdata, RET); + } + + a.bind(read_done); + + return; + } + + /* + * Handle reading of up to 7 bytes. + */ + Label handle_partial = a.newLabel(); + Label swap = a.newLabel(); + Label shift = a.newLabel(); + + if (num_partial == 0) { + /* Byte-sized segment. If bit_offset is not byte-aligned, this + * segment always needs an additional byte. */ + a.jnz(handle_partial); + } else if (num_partial > 1) { + /* Non-byte-sized segment. Test whether we will need an + * additional byte. */ + a.cmp(bin_offset.r32(), imm(8 - num_partial)); + a.jg(handle_partial); + } + + /* We don't need an extra byte. */ + if (num_bytes_to_read == 1) { + a.movzx(bitdata.r32(), x86::byte_ptr(bin_base, RET)); + if (num_partial == 0) { + a.bswap(bitdata); + a.short_().jmp(read_done); + } else if (num_partial > 1) { + a.short_().jmp(swap); + } + } else if (num_bytes_to_read <= 4) { + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(bitdata.r32(), + x86::dword_ptr(bin_base, num_bytes_to_read - 4)); + } else { + a.mov(bitdata.r32(), + x86::dword_ptr(bin_base, num_bytes_to_read - 4)); + a.bswap(bitdata.r32()); + } + a.add(bin_offset.r32(), imm(64 - 8 * num_bytes_to_read)); + a.short_().jmp(shift); + } else { + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(bitdata, x86::qword_ptr(bin_base, num_bytes_to_read - 8)); + } else { + a.mov(bitdata, x86::qword_ptr(bin_base, num_bytes_to_read - 8)); + a.bswap(bitdata); + } + ASSERT(num_bytes_to_read < 8); + a.add(bin_offset.r32(), imm(64 - 8 * num_bytes_to_read)); + a.short_().jmp(shift); + } + + /* We'll need an extra byte and we will need to shift. */ + a.bind(handle_partial); + if (num_partial != 1) { + if (num_bytes_to_read == 1) { + a.mov(bitdata.r16(), x86::word_ptr(bin_base, RET)); + } else { + ASSERT(num_bytes_to_read < 8); + a.mov(bitdata, x86::qword_ptr(bin_base, num_bytes_to_read - 7)); + a.shr(bitdata, imm(64 - 8 * (num_bytes_to_read + 1))); + } + } + + a.bind(swap); + a.bswap(bitdata); + + /* Shift the read data into the most significant bits of the + * word. */ + a.bind(shift); + a.shl(bitdata, bin_offset.r8()); + + a.bind(read_done); +} + +/* + * Read an integer and store as a term. This function only handles + * integers of certain common sizes. This is a special optimization + * when only one integer is to be extracted from a binary. + * + * Input: bin_base, bin_offset + * + * Clobbers: bin_base, bin_offset, tmp, RET + */ +void BeamModuleAssembler::emit_read_integer(const x86::Gp bin_base, + const x86::Gp bin_offset, + const x86::Gp tmp, + Uint flags, + Uint bits, + const ArgRegister &Dst) { + Label handle_unaligned = a.newLabel(); + Label store = a.newLabel(); + x86::Mem address; + + a.mov(tmp, bin_offset); + a.shr(tmp, imm(3)); + a.and_(bin_offset.r32(), imm(7)); + + switch (bits) { + case 8: + address = x86::Mem(bin_base, tmp, 0, 0, 1); + if ((flags & BSF_SIGNED) == 0) { + a.movzx(RETd, address); + } else { + a.movsx(RET, address); + } + + a.short_().jz(store); + + a.bind(handle_unaligned); + address = x86::Mem(bin_base, tmp, 0, 0, 2); + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RET.r16(), address); + } else { + a.mov(RET.r16(), address); + a.xchg(x86::al, x86::ah); + } + ASSERT(bin_offset == x86::rcx); + a.shl(RETd, bin_offset.r8()); + a.mov(x86::al, x86::ah); + if ((flags & BSF_SIGNED) == 0) { + a.movzx(RETd, RETb); + } else { + a.movsx(RET, RETb); + } + break; + case 16: + address = x86::Mem(bin_base, tmp, 0, 0, 2); + if ((flags & BSF_LITTLE) != 0) { + if ((flags & BSF_SIGNED) == 0) { + a.movzx(RETd, address); + } else { + a.movsx(RET, address); + } + } else { + /* Big-endian segment. */ + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RET.r16(), address); + } else { + a.mov(RET.r16(), address); + a.xchg(x86::al, x86::ah); + } + + if ((flags & BSF_SIGNED) != 0) { + a.movsx(RET, RET.r16()); + } else { + a.movzx(RET, RET.r16()); + } + } + + a.short_().jz(store); + + a.bind(handle_unaligned); + a.add(bin_base, tmp); + address = x86::Mem(bin_base, -1, 4); + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RETd, address); + } else { + a.mov(RETd, address); + a.bswap(RETd); + } + ASSERT(bin_offset == x86::rcx); + a.shl(RETd, bin_offset.r8()); + a.shr(RETd, imm(8)); + + if ((flags & BSF_LITTLE) != 0) { + a.xchg(x86::al, x86::ah); + } + + if ((flags & BSF_SIGNED) == 0) { + a.movzx(RETd, RET.r16()); + } else { + a.movsx(RET, RET.r16()); + } + break; + case 32: + address = x86::Mem(bin_base, tmp, 0, 0, 4); + if ((flags & BSF_LITTLE) != 0) { + /* Little-endian segment. */ + if ((flags & BSF_SIGNED) == 0) { + a.mov(RETd, address); + } else { + a.movsxd(RET, address); + } + } else { + /* Big-endian segment. */ + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RETd, address); + } else { + a.mov(RETd, address); + a.bswap(RETd); + } + + if ((flags & BSF_SIGNED) != 0) { + a.movsxd(RET, RETd); + } + } + + a.short_().jz(store); + + a.bind(handle_unaligned); + a.add(bin_base, tmp); + address = x86::Mem(bin_base, -3, 8); + if (hasCpuFeature(CpuFeatures::X86::kMOVBE)) { + a.movbe(RET, address); + } else { + a.mov(RET, address); + a.bswap(RET); + } + ASSERT(bin_offset == x86::rcx); + a.shl(RET, bin_offset.r8()); + a.shr(RET, imm(8)); + + if ((flags & BSF_LITTLE) != 0) { + a.bswap(RETd); + } + + if ((flags & BSF_SIGNED) == 0) { + a.mov(RETd, RETd); + } else { + a.movsxd(RET, RETd); + } + break; + default: + ASSERT(0); + break; + } + + a.bind(store); + a.shl(RET, imm(_TAG_IMMED1_SIZE)); + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, RET); +} + +void BeamModuleAssembler::emit_extract_integer(const x86::Gp bitdata, + const x86::Gp tmp, + Uint flags, + Uint bits, + const ArgRegister &Dst) { + if (bits == 0) { + /* Necessary for correctness when matching a zero-size + * signed segment. + */ + mov_arg(Dst, make_small(0)); + return; + } + + Label big = a.newLabel(); + Label done = a.newLabel(); + Uint num_partial = bits % 8; + Uint num_complete = 8 * (bits / 8); + + if (bits <= 8) { + /* Endian does not matter for values that fit in a byte. */ + flags &= ~BSF_LITTLE; + } + + if ((flags & BSF_LITTLE) == 0) { + /* Big-endian segment. */ + a.mov(RET, bitdata); + } else if ((flags & BSF_LITTLE) != 0) { + /* Reverse endianness for this little-endian segment. */ + if (num_partial == 0) { + a.mov(RET, bitdata); + a.bswap(RET); + if (bits < 64) { + a.shl(RET, imm(64 - num_complete)); + } + } else { + Uint shifted_mask = ((1 << num_partial) - 1) << (8 - num_partial); + a.mov(tmp, bitdata); + a.shr(tmp, imm(64 - num_complete)); + a.bswap(tmp); + a.shr(tmp, imm(num_partial)); + + a.mov(RET, bitdata); + a.rol(RET, imm(num_complete + 8)); + a.and_(RETd, imm(shifted_mask)); + a.ror(RET, imm(8)); + a.or_(RET, tmp); + } + } + + /* Now the extracted data is in RET. */ + if (bits >= SMALL_BITS) { + /* Handle segments whose values might not fit in a small + * integer. */ + Label small = a.newLabel(); + comment("test whether this integer is a small"); + if (bits < 64) { + if ((flags & BSF_SIGNED) == 0) { + /* Unsigned segment. */ + a.shr(RET, imm(64 - bits)); + } else { + /* Signed segment. */ + a.sar(RET, imm(64 - bits)); + } + } + a.mov(tmp, RET); + a.shr(tmp, imm(SMALL_BITS - 1)); + if ((flags & BSF_SIGNED) == 0) { + /* Unsigned segment. */ + a.jnz(big); + } else { + /* Signed segment. */ + a.jz(small); + a.cmp(tmp.r32(), imm(_TAG_IMMED1_MASK << 1 | 1)); + a.jnz(big); + } + + comment("store extracted integer as a small"); + a.bind(small); + a.shl(RET, imm(_TAG_IMMED1_SIZE)); + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + a.short_().jmp(done); + } else { + /* This segment always fits in a small. */ + comment("store extracted integer as a small"); + if ((flags & BSF_SIGNED) == 0) { + /* Unsigned segment. */ + a.shr(RET, imm(64 - bits - _TAG_IMMED1_SIZE)); + } else { + /* Signed segment. */ + a.sar(RET, imm(64 - bits - _TAG_IMMED1_SIZE)); + } + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == (1 << _TAG_IMMED1_SIZE) - 1); + a.or_(RET, imm(_TAG_IMMED1_SMALL)); + } + + a.bind(big); + if (bits >= SMALL_BITS) { + comment("store extracted integer as a bignum"); + if ((flags & BSF_SIGNED) == 0) { + /* Unsigned segment. */ + a.mov(x86::qword_ptr(HTOP), make_pos_bignum_header(1)); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), RET); + } else { + Label negative = a.newLabel(); + Label sign_done = a.newLabel(); + + /* Signed segment. */ + a.test(RET, RET); + a.short_().jl(negative); + + a.mov(x86::qword_ptr(HTOP), make_pos_bignum_header(1)); + a.short_().jmp(sign_done); + + a.bind(negative); + a.mov(x86::qword_ptr(HTOP), make_neg_bignum_header(1)); + a.neg(RET); + + a.bind(sign_done); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), RET); + } + a.lea(RET, x86::qword_ptr(HTOP, TAG_PRIMARY_BOXED)); + a.add(HTOP, imm(sizeof(Eterm[2]))); + } + + a.bind(done); + mov_arg(Dst, RET); +} + +/* + * Clobbers: RET + */ +void BeamModuleAssembler::emit_extract_binary(const x86::Gp bitdata, + Uint bits, + const ArgRegister &Dst) { + Uint num_bytes = bits / 8; + + a.lea(RET, x86::qword_ptr(HTOP, TAG_PRIMARY_BOXED)); + mov_arg(Dst, RET); + a.mov(x86::qword_ptr(HTOP), header_heap_bin(num_bytes)); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), imm(num_bytes)); + a.mov(RET, bitdata); + a.bswap(RET); + if (num_bytes == 0) { + a.add(HTOP, imm(sizeof(Eterm[2]))); + } else { + a.mov(x86::qword_ptr(HTOP, 2 * sizeof(Eterm)), RET); + a.add(HTOP, imm(sizeof(Eterm[3]))); + } +} + +static std::vector opt_bsm_segments( + const std::vector segments, + const ArgWord &Need, + const ArgWord &Live) { + std::vector segs; + + Uint heap_need = Need.get(); + + /* + * First calculate the total number of heap words needed for + * bignums and binaries. + */ + for (auto seg : segments) { + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + if (seg.size >= SMALL_BITS) { + heap_need += BIG_NEED_FOR_BITS(seg.size); + } + break; + case BsmSegment::action::GET_BINARY: + heap_need += erts_extracted_binary_size(seg.size); + break; + case BsmSegment::action::GET_TAIL: + heap_need += EXTRACT_SUB_BIN_HEAP_NEED; + break; + default: + break; + } + } + + int read_action_pos = -1; + int seg_index = 0; + int count = segments.size(); + + for (int i = 0; i < count; i++) { + auto seg = segments[i]; + if (heap_need != 0 && seg.live.isWord()) { + BsmSegment s = seg; + + read_action_pos = -1; + s.action = BsmSegment::action::TEST_HEAP; + s.size = heap_need; + segs.push_back(s); + heap_need = 0; + seg_index++; + } + + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + case BsmSegment::action::GET_BINARY: { + bool is_common_size; + switch (seg.size) { + case 8: + case 16: + case 32: + is_common_size = true; + break; + default: + is_common_size = false; + break; + } + + if (seg.size > 64) { + read_action_pos = -1; + } else if (seg.action == BsmSegment::action::GET_BINARY && + seg.size % 8 != 0) { + read_action_pos = -1; + } else if ((seg.flags & BSF_LITTLE) != 0 && is_common_size) { + seg.action = BsmSegment::action::READ_INTEGER; + read_action_pos = -1; + } else if (read_action_pos < 0 && + seg.action == BsmSegment::action::GET_INTEGER && + is_common_size && i + 1 == count) { + seg.action = BsmSegment::action::READ_INTEGER; + read_action_pos = -1; + } else { + if ((seg.flags & BSF_LITTLE) != 0 || read_action_pos < 0 || + seg.size + segs.at(read_action_pos).size > 64) { + BsmSegment s; + + /* Create a new READ action. */ + read_action_pos = seg_index; + s.action = BsmSegment::action::READ; + s.size = seg.size; + segs.push_back(s); + seg_index++; + } else { + /* Reuse previous READ action. */ + segs.at(read_action_pos).size += seg.size; + } + switch (seg.action) { + case BsmSegment::action::GET_INTEGER: + seg.action = BsmSegment::action::EXTRACT_INTEGER; + break; + case BsmSegment::action::GET_BINARY: + seg.action = BsmSegment::action::EXTRACT_BINARY; + break; + default: + break; + } + } + segs.push_back(seg); + break; + } + case BsmSegment::action::EQ: { + if (read_action_pos < 0 || + seg.size + segs.at(read_action_pos).size > 64) { + BsmSegment s; + + /* Create a new READ action. */ + read_action_pos = seg_index; + s.action = BsmSegment::action::READ; + s.size = seg.size; + segs.push_back(s); + seg_index++; + } else { + /* Reuse previous READ action. */ + segs.at(read_action_pos).size += seg.size; + } + auto &prev = segs.back(); + if (prev.action == BsmSegment::action::EQ && + prev.size + seg.size <= 64) { + /* Coalesce with the previous EQ instruction. */ + prev.size += seg.size; + prev.unit = prev.unit << seg.size | seg.unit; + seg_index--; + } else { + segs.push_back(seg); + } + break; + } + case BsmSegment::action::SKIP: + if (read_action_pos >= 0 && + seg.size + segs.at(read_action_pos).size <= 64) { + segs.at(read_action_pos).size += seg.size; + seg.action = BsmSegment::action::DROP; + } else { + read_action_pos = -1; + } + segs.push_back(seg); + break; + default: + read_action_pos = -1; + segs.push_back(seg); + break; + } + seg_index++; + } + + /* Handle a trailing test_heap instruction (for the + * i_bs_match_test_heap instruction). */ + if (heap_need) { + BsmSegment seg; + + seg.action = BsmSegment::action::TEST_HEAP; + seg.size = heap_need; + seg.live = Live; + segs.push_back(seg); + } + return segs; +} + +UWord BeamModuleAssembler::bs_get_flags(const ArgVal &val) { + if (val.isNil()) { + return 0; + } else if (val.isLiteral()) { + Eterm term = beamfile_get_literal(beam, val.as().get()); + UWord flags = 0; + + while (is_list(term)) { + Eterm *consp = list_val(term); + Eterm elem = CAR(consp); + switch (elem) { + case am_little: + case am_native: + flags |= BSF_LITTLE; + break; + case am_signed: + flags |= BSF_SIGNED; + break; + } + term = CDR(consp); + } + ASSERT(is_nil(term)); + return flags; + } else if (val.isWord()) { + /* Originates from bs_get_integer2 instruction. */ + return val.as().get(); + } else { + ASSERT(0); /* Should not happen. */ + return 0; + } +} + +void BeamModuleAssembler::emit_i_bs_match(ArgLabel const &Fail, + ArgRegister const &Ctx, + Span const &List) { + emit_i_bs_match_test_heap(Fail, Ctx, ArgWord(0), ArgWord(0), List); +} + +void BeamModuleAssembler::emit_i_bs_match_test_heap(ArgLabel const &Fail, + ArgRegister const &Ctx, + ArgWord const &Need, + ArgWord const &Live, + Span const &List) { + const int orig_offset = offsetof(ErlBinMatchState, mb.orig); + const int base_offset = offsetof(ErlBinMatchState, mb.base); + const int position_offset = offsetof(ErlBinMatchState, mb.offset); + const int size_offset = offsetof(ErlBinMatchState, mb.size); + + std::vector segments; + + auto current = List.begin(); + auto end = List.begin() + List.size(); + + while (current < end) { + auto cmd = current++->as().get(); + BsmSegment seg; + + switch (cmd) { + case am_ensure_at_least: { + seg.action = BsmSegment::action::ENSURE_AT_LEAST; + seg.size = current[0].as().get(); + seg.unit = current[1].as().get(); + current += 2; + break; + } + case am_ensure_exactly: { + seg.action = BsmSegment::action::ENSURE_EXACTLY; + seg.size = current[0].as().get(); + current += 1; + break; + } + case am_binary: + case am_integer: { + auto size = current[2].as().get(); + auto unit = current[3].as().get(); + + switch (cmd) { + case am_integer: + seg.action = BsmSegment::action::GET_INTEGER; + break; + case am_binary: + seg.action = BsmSegment::action::GET_BINARY; + break; + } + + seg.live = current[0]; + seg.size = size * unit; + seg.unit = unit; + seg.flags = bs_get_flags(current[1]); + seg.dst = current[4].as(); + current += 5; + break; + } + case am_get_tail: { + seg.action = BsmSegment::action::GET_TAIL; + seg.live = current[0].as(); + seg.dst = current[2].as(); + current += 3; + break; + } + case am_skip: { + seg.action = BsmSegment::action::SKIP; + seg.size = current[0].as().get(); + seg.flags = 0; + current += 1; + break; + } + case am_Eq: { + seg.action = BsmSegment::action::EQ; + seg.live = current[0]; + seg.size = current[1].as().get(); + seg.unit = current[2].as().get(); + current += 3; + break; + } + default: + abort(); + break; + } + segments.push_back(seg); + } + + segments = opt_bsm_segments(segments, Need, Live); + + /* Constraints: + * + * bin_position must be RCX because only CL can be used for + * a variable shift without using the SHLX instruction from BMI2. + */ +#ifdef WIN32 + const x86::Gp bin_position = ARG1; + const x86::Gp bitdata = ARG2; + const x86::Gp bin_base = ARG3; + const x86::Gp ctx = ARG4; +#else + const x86::Gp bin_position = ARG4; + const x86::Gp bitdata = ARG3; + const x86::Gp bin_base = ARG1; + const x86::Gp ctx = ARG2; +#endif + ASSERT(bin_position == x86::rcx); + const x86::Gp tmp = ARG5; + + bool is_ctx_valid = false; + bool is_position_valid = false; + bool next_instr_clobbers = false; + int count = segments.size(); + + for (int i = 0; i < count; i++) { + auto seg = segments[i]; + + /* Find out whether the next sub instruction clobbers + * registers or is the last. */ + next_instr_clobbers = + i == count - 1 || + (i < count - 1 && + segments[i + 1].action == BsmSegment::action::TEST_HEAP); + + switch (seg.action) { + case BsmSegment::action::ENSURE_AT_LEAST: { + auto size = seg.size; + auto unit = seg.unit; + comment("ensure_at_least %ld %ld", size, seg.unit); + mov_arg(ctx, Ctx); + if (unit == 1) { + a.mov(bin_position, emit_boxed_val(ctx, position_offset)); + a.lea(RET, qword_ptr(bin_position, size)); + a.cmp(RET, emit_boxed_val(ctx, size_offset)); + a.ja(resolve_beam_label(Fail)); + } else if (size == 0 && next_instr_clobbers) { + a.mov(RET, emit_boxed_val(ctx, size_offset)); + a.sub(RET, emit_boxed_val(ctx, position_offset)); + is_ctx_valid = is_position_valid = false; + } else { + a.mov(RET, emit_boxed_val(ctx, size_offset)); + a.mov(bin_position, emit_boxed_val(ctx, position_offset)); + a.sub(RET, bin_position); + cmp(RET, size, tmp); + a.jl(resolve_beam_label(Fail)); + } + + is_ctx_valid = is_position_valid = true; + + if (unit != 1) { + if (size % unit != 0) { + sub(RET, size, tmp); + } + + if ((unit & (unit - 1))) { + /* Clobbers ARG3 */ + a.cqo(); + mov_imm(tmp, unit); + a.div(tmp); + a.test(x86::rdx, x86::rdx); + is_ctx_valid = is_position_valid = false; + } else { + a.test(RETb, imm(unit - 1)); + } + a.jnz(resolve_beam_label(Fail)); + } + break; + } + case BsmSegment::action::ENSURE_EXACTLY: { + auto size = seg.size; + comment("ensure_exactly %ld", size); + + mov_arg(ctx, Ctx); + a.mov(RET, emit_boxed_val(ctx, size_offset)); + if (next_instr_clobbers) { + a.sub(RET, emit_boxed_val(ctx, position_offset)); + is_ctx_valid = is_position_valid = false; + } else { + a.mov(bin_position, emit_boxed_val(ctx, position_offset)); + a.sub(RET, bin_position); + is_ctx_valid = is_position_valid = true; + } + if (size != 0) { + cmp(RET, size, tmp); + } + a.jne(resolve_beam_label(Fail)); + break; + } + case BsmSegment::action::EQ: { + comment("=:= %ld %ld", seg.size, seg.unit); + auto bits = seg.size; + x86::Gp extract_reg; + + if (next_instr_clobbers) { + extract_reg = bitdata; + } else { + extract_reg = RET; + a.mov(extract_reg, bitdata); + } + if (bits != 0 && bits != 64) { + a.shr(extract_reg, imm(64 - bits)); + } + + if (seg.size <= 32) { + cmp(extract_reg.r32(), seg.unit, tmp); + } else { + cmp(extract_reg, seg.unit, tmp); + } + + a.jne(resolve_beam_label(Fail)); + + if (!next_instr_clobbers && bits != 0 && bits != 64) { + a.shl(bitdata, imm(bits)); + } + + /* bin_position is clobbered. */ + is_position_valid = false; + break; + } + case BsmSegment::action::TEST_HEAP: { + comment("test_heap %ld", seg.size); + emit_gc_test(ArgWord(0), ArgWord(seg.size), seg.live); + is_ctx_valid = is_position_valid = false; + break; + } + case BsmSegment::action::READ: { + comment("read %ld", seg.size); + if (seg.size == 0) { + comment("(nothing to do)"); + } else { + if (!is_ctx_valid) { + mov_arg(ctx, Ctx); + is_ctx_valid = true; + } + if (!is_position_valid) { + a.mov(bin_position, emit_boxed_val(ctx, position_offset)); + is_position_valid = true; + } + a.mov(bin_base, emit_boxed_val(ctx, base_offset)); + a.add(emit_boxed_val(ctx, position_offset), imm(seg.size)); + + emit_read_bits(seg.size, bin_base, bin_position, bitdata); + } + + is_position_valid = false; + break; + } + case BsmSegment::action::EXTRACT_BINARY: { + auto bits = seg.size; + auto Dst = seg.dst; + + comment("extract binary %ld", bits); + emit_extract_binary(bitdata, bits, Dst); + if (!next_instr_clobbers && bits != 0 && bits != 64) { + a.shl(bitdata, imm(bits)); + } + break; + } + case BsmSegment::action::EXTRACT_INTEGER: { + auto bits = seg.size; + auto flags = seg.flags; + auto Dst = seg.dst; + + comment("extract integer %ld", bits); + if (next_instr_clobbers && flags == 0 && bits < SMALL_BITS) { + a.shr(bitdata, imm(64 - bits - _TAG_IMMED1_SIZE)); + a.or_(bitdata, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, bitdata); + } else { + emit_extract_integer(bitdata, tmp, flags, bits, Dst); + if (!next_instr_clobbers && bits != 0 && bits != 64) { + a.shl(bitdata, imm(bits)); + } + } + + /* bin_position is clobbered. */ + is_position_valid = false; + break; + } + case BsmSegment::action::READ_INTEGER: { + auto bits = seg.size; + auto flags = seg.flags; + auto Dst = seg.dst; + + comment("read integer %ld", bits); + if (!is_ctx_valid) { + mov_arg(ctx, Ctx); + is_ctx_valid = true; + } + if (!is_position_valid) { + a.mov(bin_position, emit_boxed_val(ctx, position_offset)); + is_position_valid = true; + } + + a.mov(bin_base, emit_boxed_val(ctx, base_offset)); + a.add(emit_boxed_val(ctx, position_offset), imm(seg.size)); + emit_read_integer(bin_base, bin_position, tmp, flags, bits, Dst); + + is_position_valid = false; + break; + } + case BsmSegment::action::GET_INTEGER: { + Uint flags = seg.flags; + auto bits = seg.size; + auto Dst = seg.dst; + + comment("get integer %ld", bits); + if (!is_ctx_valid) { + mov_arg(ctx, Ctx); + } + + a.lea(ARG4, emit_boxed_val(ctx, offsetof(ErlBinMatchState, mb))); + + if (bits >= SMALL_BITS) { + emit_enter_runtime(); + } else { + emit_enter_runtime(); + } + + a.mov(ARG1, c_p); + a.mov(ARG2, bits); + a.mov(ARG3, flags); + /* ARG4 set above */ + runtime_call<4>(erts_bs_get_integer_2); + + if (bits >= SMALL_BITS) { + emit_leave_runtime(); + } else { + emit_leave_runtime(); + } + + mov_arg(Dst, RET); + + is_ctx_valid = is_position_valid = false; + break; + } + case BsmSegment::action::GET_BINARY: { + comment("get binary %ld", seg.size); + if (is_ctx_valid) { + a.mov(RET, ctx); + } else { + mov_arg(RET, Ctx); + } + emit_enter_runtime(); + a.lea(ARG1, x86::qword_ptr(c_p, offsetof(Process, htop))); + a.mov(ARG2, emit_boxed_val(RET, orig_offset)); + a.mov(ARG3, emit_boxed_val(RET, base_offset)); + a.mov(ARG4, emit_boxed_val(RET, position_offset)); + mov_imm(ARG5, seg.size); + a.add(emit_boxed_val(RET, position_offset), ARG5); + + runtime_call<5>(erts_extract_sub_binary); + + emit_leave_runtime(); + mov_arg(seg.dst, RET); + + is_ctx_valid = is_position_valid = false; + break; + } + case BsmSegment::action::GET_TAIL: { + comment("get_tail"); + if (is_ctx_valid) { + a.mov(ARG1, ctx); + } else { + mov_arg(ARG1, Ctx); + } + safe_fragment_call(ga->get_bs_get_tail_shared()); + mov_arg(seg.dst, RET); + is_ctx_valid = is_position_valid = false; + break; + } + case BsmSegment::action::SKIP: { + comment("skip %ld", seg.size); + if (!is_ctx_valid) { + mov_arg(ctx, Ctx); + is_ctx_valid = true; + } + /* The compiler limits the size of any segment in a bs_match + * instruction to 24 bits. */ + ASSERT((seg.size >> 24) == 0); + a.add(emit_boxed_val(ctx, position_offset), imm(seg.size)); + is_position_valid = false; + break; + } + case BsmSegment::action::DROP: + auto bits = seg.size; + comment("drop %ld", bits); + if (bits != 0 && bits != 64) { + a.shl(bitdata, imm(bits)); + } + break; + } + } } diff --git a/erts/emulator/beam/jit/x86/instr_call.cpp b/erts/emulator/beam/jit/x86/instr_call.cpp index de6b537393c7..367e10e29451 100644 --- a/erts/emulator/beam/jit/x86/instr_call.cpp +++ b/erts/emulator/beam/jit/x86/instr_call.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -39,13 +39,13 @@ void BeamGlobalAssembler::emit_dispatch_return() { } void BeamModuleAssembler::emit_return() { - Label dispatch_return = a.newLabel(); - #ifdef JIT_HARD_DEBUG /* Validate return address and {x,0} */ - emit_validate(ArgVal(ArgVal::u, 1)); + emit_validate(ArgWord(1)); #endif + emit_leave_frame(); + #if !defined(NATIVE_ERLANG_STACK) a.mov(ARG3, getCPRef()); a.mov(getCPRef(), imm(NIL)); @@ -54,40 +54,36 @@ void BeamModuleAssembler::emit_return() { /* The reduction test is kept in module code because moving it to a shared * fragment caused major performance regressions in dialyzer. */ a.dec(FCALLS); - a.short_().jl(dispatch_return); + a.jl(resolve_fragment(ga->get_dispatch_return())); #ifdef NATIVE_ERLANG_STACK a.ret(); #else a.jmp(ARG3); #endif - - a.bind(dispatch_return); - abs_jmp(ga->get_dispatch_return()); } -void BeamModuleAssembler::emit_i_call(const ArgVal &CallDest) { - Label dest = labels[CallDest.getValue()]; - - erlang_call(dest, RET); +void BeamModuleAssembler::emit_i_call(const ArgLabel &CallDest) { + erlang_call(resolve_beam_label(CallDest), RET); } -void BeamModuleAssembler::emit_i_call_last(const ArgVal &CallDest, - const ArgVal &Deallocate) { +void BeamModuleAssembler::emit_i_call_last(const ArgLabel &CallDest, + const ArgWord &Deallocate) { emit_deallocate(Deallocate); - - a.jmp(labels[CallDest.getValue()]); + emit_i_call_only(CallDest); } -void BeamModuleAssembler::emit_i_call_only(const ArgVal &CallDest) { - a.jmp(labels[CallDest.getValue()]); +void BeamModuleAssembler::emit_i_call_only(const ArgLabel &CallDest) { + emit_leave_frame(); + + a.jmp(resolve_beam_label(CallDest)); } -/* Handles save_calls. Export entry is in RET. +/* Handles save_calls for export entries. Export entry is in RET. * * When the active code index is ERTS_SAVE_CALLS_CODE_IX, all remote calls will * land here. */ -void BeamGlobalAssembler::emit_dispatch_save_calls() { +void BeamGlobalAssembler::emit_dispatch_save_calls_export() { a.mov(TMP_MEM1q, RET); emit_enter_runtime(); @@ -104,27 +100,31 @@ void BeamGlobalAssembler::emit_dispatch_save_calls() { a.mov(ARG1, imm(&the_active_code_index)); a.mov(ARG1d, x86::dword_ptr(ARG1)); - a.jmp(emit_setup_export_call(RET, ARG1)); + a.jmp(emit_setup_dispatchable_call(RET, ARG1)); } -void BeamModuleAssembler::emit_i_call_ext(const ArgVal &Exp) { - make_move_patch(RET, imports[Exp.getValue()].patches); - x86::Mem destination = emit_setup_export_call(RET); +void BeamModuleAssembler::emit_i_call_ext(const ArgExport &Exp) { + mov_arg(RET, Exp); + x86::Mem destination = emit_setup_dispatchable_call(RET); erlang_call(destination, ARG1); } -void BeamModuleAssembler::emit_i_call_ext_only(const ArgVal &Exp) { - make_move_patch(RET, imports[Exp.getValue()].patches); - x86::Mem destination = emit_setup_export_call(RET); +void BeamModuleAssembler::emit_i_call_ext_only(const ArgExport &Exp) { + mov_arg(RET, Exp); + x86::Mem destination = emit_setup_dispatchable_call(RET); + + emit_leave_frame(); a.jmp(destination); } -void BeamModuleAssembler::emit_i_call_ext_last(const ArgVal &Exp, - const ArgVal &Deallocate) { +void BeamModuleAssembler::emit_i_call_ext_last(const ArgExport &Exp, + const ArgWord &Deallocate) { emit_deallocate(Deallocate); - make_move_patch(RET, imports[Exp.getValue()].patches); - x86::Mem destination = emit_setup_export_call(RET); + mov_arg(RET, Exp); + x86::Mem destination = emit_setup_dispatchable_call(RET); + + emit_leave_frame(); a.jmp(destination); } @@ -136,7 +136,7 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) { align_erlang_cp(); a.bind(entry); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); @@ -151,14 +151,14 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) { runtime_call<4>(apply); - emit_leave_runtime(); + emit_leave_runtime(); a.test(RET, RET); a.short_().jne(dispatch); - emit_handle_error(entry, &apply3_mfa); + emit_raise_exception(entry, &apply3_mfa); a.bind(dispatch); - return emit_setup_export_call(RET); + return emit_setup_dispatchable_call(RET); } void BeamModuleAssembler::emit_i_apply() { @@ -166,17 +166,19 @@ void BeamModuleAssembler::emit_i_apply() { erlang_call(dest, ARG1); } -void BeamModuleAssembler::emit_i_apply_last(const ArgVal &Deallocate) { +void BeamModuleAssembler::emit_i_apply_last(const ArgWord &Deallocate) { emit_deallocate(Deallocate); emit_i_apply_only(); } void BeamModuleAssembler::emit_i_apply_only() { x86::Mem dest = emit_variable_apply(true); + + emit_leave_frame(); a.jmp(dest); } -x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity, +x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgWord &Arity, bool includeI) { Label dispatch = a.newLabel(), entry = a.newLabel(); @@ -185,7 +187,7 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity, mov_arg(ARG3, Arity); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); @@ -200,118 +202,28 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity, runtime_call<5>(fixed_apply); - emit_leave_runtime(); + emit_leave_runtime(); a.test(RET, RET); a.short_().jne(dispatch); - emit_handle_error(entry, &apply3_mfa); + emit_raise_exception(entry, &apply3_mfa); a.bind(dispatch); - return emit_setup_export_call(RET); + return emit_setup_dispatchable_call(RET); } -void BeamModuleAssembler::emit_apply(const ArgVal &Arity) { +void BeamModuleAssembler::emit_apply(const ArgWord &Arity) { x86::Mem dest = emit_fixed_apply(Arity, false); erlang_call(dest, ARG1); } -void BeamModuleAssembler::emit_apply_last(const ArgVal &Arity, - const ArgVal &Deallocate) { +void BeamModuleAssembler::emit_apply_last(const ArgWord &Arity, + const ArgWord &Deallocate) { emit_deallocate(Deallocate); x86::Mem dest = emit_fixed_apply(Arity, true); - a.jmp(dest); -} - -x86::Gp BeamModuleAssembler::emit_apply_fun() { - Label dispatch = a.newLabel(); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - a.mov(ARG2, getXRef(0)); - a.mov(ARG3, getXRef(1)); - load_x_reg_array(ARG4); - a.lea(ARG5, TMP_MEM1q); - runtime_call<5>(apply_fun); - - emit_leave_runtime(); - - a.mov(ARG2, RET); - a.test(RET, RET); - - /* Put the export entry, if any, into RET to follow the export calling - * convention in case we applied an external fun. See - * `emit_setup_export_call` for details. */ - a.mov(RET, TMP_MEM1q); - - a.short_().jne(dispatch); - emit_handle_error(); - a.bind(dispatch); - - return ARG2; -} - -void BeamModuleAssembler::emit_i_apply_fun() { - x86::Gp dest = emit_apply_fun(); - - ASSERT(dest != ARG1); - erlang_call(dest, ARG1); -} - -void BeamModuleAssembler::emit_i_apply_fun_last(const ArgVal &Deallocate) { - emit_deallocate(Deallocate); - emit_i_apply_fun_only(); -} - -void BeamModuleAssembler::emit_i_apply_fun_only() { - x86::Gp dest = emit_apply_fun(); - - a.jmp(dest); -} - -x86::Gp BeamModuleAssembler::emit_call_fun(const ArgVal &Fun) { - Label dispatch = a.newLabel(); - - mov_arg(ARG2, Fun); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - load_x_reg_array(ARG3); - mov_imm(ARG4, THE_NON_VALUE); - a.lea(ARG5, TMP_MEM1q); - runtime_call<5>(call_fun); - - emit_leave_runtime(); - - a.mov(ARG2, RET); - a.test(RET, RET); - - /* Put the export entry, if any, into RET to follow the export calling - * convention in case we called an external fun. See - * `emit_setup_export_call` for details. */ - a.mov(RET, TMP_MEM1q); - - a.short_().jne(dispatch); - emit_handle_error(); - a.bind(dispatch); - - return ARG2; -} - -void BeamModuleAssembler::emit_i_call_fun(const ArgVal &Fun) { - x86::Gp dest = emit_call_fun(Fun); - - ASSERT(dest != ARG1); - erlang_call(dest, ARG1); -} - -void BeamModuleAssembler::emit_i_call_fun_last(const ArgVal &Fun, - const ArgVal &Deallocate) { - emit_deallocate(Deallocate); - x86::Gp dest = emit_call_fun(Fun); + emit_leave_frame(); a.jmp(dest); } diff --git a/erts/emulator/beam/jit/x86/instr_common.cpp b/erts/emulator/beam/jit/x86/instr_common.cpp index 09135aa25ff5..99e67c40b2fc 100644 --- a/erts/emulator/beam/jit/x86/instr_common.cpp +++ b/erts/emulator/beam/jit/x86/instr_common.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2022. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -23,12 +23,17 @@ * * Instructions that use 32-bit registers (e.g. eax) are generally * one byte shorter than instructions that use 64-bits registers - * (e.g. rax). This does not apply to registers r8-r15 beacuse they'll + * (e.g. rax). This does not apply to registers r8-r15 because they'll * always need a rex prefix. The `and`, `or`, and `cmp` instructions - * are even shorter than operating on the RETb (al) register. The + * are even shorter when operating on the RETb (al) register. The * `test` instruction with an immediate second operand is shorter * when operating on an 8-bit register. * + * When loading an immediate value to a register, storing to the + * 32-bit register in one or two bytes shorter than storing to + * the corresponding 64-bit register. The mov_imm() helper + * will automatically choose the shortest instruction. + * * On both Unix and Windows, instructions can be shortened by using * RETd, ARG1d, or ARG2d instead of RET, ARG1, or ARG2, respectively. * On Unix, but not on Windows, ARG3d and ARG4d will also result in @@ -76,6 +81,7 @@ */ #include +#include #include "beam_asm.hpp" extern "C" @@ -85,6 +91,7 @@ extern "C" #include "beam_catches.h" #include "beam_common.h" #include "code_ix.h" +#include "erl_binary.h" } using namespace asmjit; @@ -93,47 +100,78 @@ using namespace asmjit; void BeamModuleAssembler::emit_error(int reason) { a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(reason)); - emit_handle_error(); + emit_raise_exception(); } -void BeamModuleAssembler::emit_gc_test_preserve(const ArgVal &Need, - const ArgVal &Live, - x86::Gp term) { - const int32_t bytes_needed = (Need.getValue() + S_RESERVED) * sizeof(Eterm); +void BeamModuleAssembler::emit_gc_test_preserve(const ArgWord &Need, + const ArgWord &Live, + const ArgSource &Preserve, + x86::Gp preserve_reg) { + const int32_t bytes_needed = (Need.get() + S_RESERVED) * sizeof(Eterm); Label after_gc_check = a.newLabel(); - ASSERT(term != ARG3); + ASSERT(preserve_reg != ARG3); + +#ifdef DEBUG + comment("(debug: fill dead X registers with garbage)"); + const x86::Gp garbage_reg = ARG3; + mov_imm(garbage_reg, ERTS_HOLE_MARKER); + if (!(Preserve.isXRegister() && + Preserve.as().get() >= Live.get())) { + mov_arg(ArgXRegister(Live.get()), garbage_reg); + mov_arg(ArgXRegister(Live.get() + 1), garbage_reg); + } else { + mov_arg(ArgXRegister(Live.get() + 1), garbage_reg); + mov_arg(ArgXRegister(Live.get() + 2), garbage_reg); + } +#endif a.lea(ARG3, x86::qword_ptr(HTOP, bytes_needed)); a.cmp(ARG3, E); a.short_().jbe(after_gc_check); - a.mov(getXRef(Live.getValue()), term); - mov_imm(ARG4, Live.getValue() + 1); - fragment_call(ga->get_garbage_collect()); - a.mov(term, getXRef(Live.getValue())); + /* We don't need to stash the preserved term if it's currently live, making + * the code slightly shorter. */ + if (!(Preserve.isXRegister() && + Preserve.as().get() >= Live.get())) { + mov_imm(ARG4, Live.get()); + fragment_call(ga->get_garbage_collect()); + mov_arg(preserve_reg, Preserve); + } else { + a.mov(getXRef(Live.get()), preserve_reg); + mov_imm(ARG4, Live.get() + 1); + fragment_call(ga->get_garbage_collect()); + a.mov(preserve_reg, getXRef(Live.get())); + } a.bind(after_gc_check); } -void BeamModuleAssembler::emit_gc_test(const ArgVal &Ns, - const ArgVal &Nh, - const ArgVal &Live) { +void BeamModuleAssembler::emit_gc_test(const ArgWord &Ns, + const ArgWord &Nh, + const ArgWord &Live) { const int32_t bytes_needed = - (Ns.getValue() + Nh.getValue() + S_RESERVED) * sizeof(Eterm); + (Ns.get() + Nh.get() + S_RESERVED) * sizeof(Eterm); Label after_gc_check = a.newLabel(); +#ifdef DEBUG + comment("(debug: fill dead X registers with garbage)"); + mov_imm(ARG4, ERTS_HOLE_MARKER); + mov_arg(ArgXRegister(Live.get()), ARG4); + mov_arg(ArgXRegister(Live.get() + 1), ARG4); +#endif + a.lea(ARG3, x86::qword_ptr(HTOP, bytes_needed)); a.cmp(ARG3, E); a.short_().jbe(after_gc_check); - mov_imm(ARG4, Live.getValue()); + mov_imm(ARG4, Live.get()); fragment_call(ga->get_garbage_collect()); a.bind(after_gc_check); } -void BeamModuleAssembler::emit_validate(const ArgVal &arity) { +void BeamModuleAssembler::emit_validate(const ArgWord &Arity) { #ifdef DEBUG Label next = a.newLabel(), crash = a.newLabel(); @@ -158,7 +196,7 @@ void BeamModuleAssembler::emit_validate(const ArgVal &arity) { # ifdef JIT_HARD_DEBUG emit_enter_runtime(); - for (unsigned i = 0; i < arity.getValue(); i++) { + for (unsigned i = 0; i < Arity.get(); i++) { a.mov(ARG1, getXRef(i)); runtime_call<1>(beam_jit_validate_term); } @@ -171,16 +209,15 @@ void BeamModuleAssembler::emit_validate(const ArgVal &arity) { /* Instrs */ -void BeamModuleAssembler::emit_i_validate(const ArgVal &Arity) { +void BeamModuleAssembler::emit_i_validate(const ArgWord &Arity) { emit_validate(Arity); } -void BeamModuleAssembler::emit_allocate_heap(const ArgVal &NeedStack, - const ArgVal &NeedHeap, - const ArgVal &Live) { - ASSERT(NeedStack.getType() == ArgVal::TYPE::u); - ASSERT(NeedStack.getValue() <= MAX_REG); - ArgVal needed = NeedStack; +void BeamModuleAssembler::emit_allocate_heap(const ArgWord &NeedStack, + const ArgWord &NeedHeap, + const ArgWord &Live) { + ASSERT(NeedStack.get() <= MAX_REG); + ArgWord needed = NeedStack; #if !defined(NATIVE_ERLANG_STACK) needed = needed + CP_SIZE; @@ -188,42 +225,48 @@ void BeamModuleAssembler::emit_allocate_heap(const ArgVal &NeedStack, emit_gc_test(needed, NeedHeap, Live); - if (needed.getValue() > 0) { - a.sub(E, imm(needed.getValue() * sizeof(Eterm))); + if (needed.get() > 0) { + a.sub(E, imm(needed.get() * sizeof(Eterm))); } + #if !defined(NATIVE_ERLANG_STACK) a.mov(getCPRef(), imm(NIL)); #endif } -void BeamModuleAssembler::emit_allocate(const ArgVal &NeedStack, - const ArgVal &Live) { - emit_allocate_heap(NeedStack, ArgVal(ArgVal::TYPE::u, 0), Live); +void BeamModuleAssembler::emit_allocate(const ArgWord &NeedStack, + const ArgWord &Live) { + emit_allocate_heap(NeedStack, ArgWord(0), Live); } -void BeamModuleAssembler::emit_deallocate(const ArgVal &Deallocate) { - ASSERT(Deallocate.getType() == ArgVal::TYPE::u); - ASSERT(Deallocate.getValue() <= 1023); - ArgVal dealloc = Deallocate; +void BeamModuleAssembler::emit_deallocate(const ArgWord &Deallocate) { + ASSERT(Deallocate.get() <= 1023); + + if (ERTS_LIKELY(erts_frame_layout == ERTS_FRAME_LAYOUT_RA)) { + ArgWord dealloc = Deallocate; #if !defined(NATIVE_ERLANG_STACK) - dealloc = dealloc + CP_SIZE; + dealloc = dealloc + CP_SIZE; #endif - if (dealloc.getValue() > 0) { - a.add(E, imm(dealloc.getValue() * sizeof(Eterm))); + if (dealloc.get() > 0) { + a.add(E, imm(dealloc.get() * sizeof(Eterm))); + } + } else { + ASSERT(erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA); } } -void BeamModuleAssembler::emit_test_heap(const ArgVal &Nh, const ArgVal &Live) { - emit_gc_test(ArgVal(ArgVal::u, 0), Nh, Live); +void BeamModuleAssembler::emit_test_heap(const ArgWord &Nh, + const ArgWord &Live) { + emit_gc_test(ArgWord(0), Nh, Live); } void BeamModuleAssembler::emit_normal_exit() { - /* This is implictly global; it does not normally appear in modules and + /* This is implicitly global; it does not normally appear in modules and * doesn't require size optimization. */ - emit_enter_runtime(); + emit_enter_runtime(); emit_proc_lc_unrequire(); a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(EXC_NORMAL)); @@ -233,78 +276,39 @@ void BeamModuleAssembler::emit_normal_exit() { runtime_call<2>(erts_do_exit_process); emit_proc_lc_require(); - emit_leave_runtime(); + emit_leave_runtime(); - abs_jmp(ga->get_do_schedule()); + a.jmp(resolve_fragment(ga->get_do_schedule())); } void BeamModuleAssembler::emit_continue_exit() { - /* This is implictly global; it does not normally appear in modules and + /* This is implicitly global; it does not normally appear in modules and * doesn't require size optimization. */ - emit_enter_runtime(); + emit_enter_runtime(); emit_proc_lc_unrequire(); a.mov(ARG1, c_p); runtime_call<1>(erts_continue_exit_process); emit_proc_lc_require(); - emit_leave_runtime(); - - abs_jmp(ga->get_do_schedule()); -} + emit_leave_runtime(); -/* This is an alias for handle_error */ -void BeamModuleAssembler::emit_error_action_code() { - abs_jmp(ga->get_error_action_code()); -} - -/* Psuedo-instruction for signalling lambda load errors. Never actually runs. */ -void BeamModuleAssembler::emit_i_lambda_error(const ArgVal &Dummy) { - a.hlt(); -} - -void BeamModuleAssembler::emit_i_make_fun3(const ArgVal &Fun, - const ArgVal &Dst, - const ArgVal &NumFree, - const std::vector &env) { - size_t num_free = env.size(); - ASSERT(NumFree.getValue() == num_free); - - mov_arg(ARG3, NumFree); - - emit_enter_runtime(); - - a.mov(ARG1, c_p); - make_move_patch(ARG2, lambdas[Fun.getValue()].patches); - runtime_call<3>(new_fun_thing); - - emit_leave_runtime(); - - comment("Move fun environment"); - for (unsigned i = 0; i < num_free; i++) { - mov_arg(x86::qword_ptr(RET, - offsetof(ErlFunThing, env) + i * sizeof(Eterm)), - env[i]); - } - - comment("Create boxed ptr"); - a.or_(RETb, TAG_PRIMARY_BOXED); - mov_arg(Dst, RET); + a.jmp(resolve_fragment(ga->get_do_schedule())); } void BeamModuleAssembler::emit_get_list(const x86::Gp src, - const ArgVal &Hd, - const ArgVal &Tl) { + const ArgRegister &Hd, + const ArgRegister &Tl) { x86::Gp boxed_ptr = emit_ptr_val(src, src); - switch (ArgVal::register_relation(Hd, Tl)) { + switch (ArgVal::memory_relation(Hd, Tl)) { case ArgVal::Relation::consecutive: { comment("(moving head and tail together)"); x86::Mem dst_ptr = getArgRef(Hd, 16); x86::Mem src_ptr = getCARRef(boxed_ptr, 16); - a.movups(x86::xmm0, src_ptr); - a.movups(dst_ptr, x86::xmm0); + vmovups(x86::xmm0, src_ptr); + vmovups(dst_ptr, x86::xmm0); break; } case ArgVal::Relation::reverse_consecutive: { @@ -329,14 +333,15 @@ void BeamModuleAssembler::emit_get_list(const x86::Gp src, } } -void BeamModuleAssembler::emit_get_list(const ArgVal &Src, - const ArgVal &Hd, - const ArgVal &Tl) { +void BeamModuleAssembler::emit_get_list(const ArgRegister &Src, + const ArgRegister &Hd, + const ArgRegister &Tl) { mov_arg(ARG1, Src); emit_get_list(ARG1, Hd, Tl); } -void BeamModuleAssembler::emit_get_hd(const ArgVal &Src, const ArgVal &Hd) { +void BeamModuleAssembler::emit_get_hd(const ArgRegister &Src, + const ArgRegister &Hd) { mov_arg(ARG1, Src); x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); @@ -346,7 +351,8 @@ void BeamModuleAssembler::emit_get_hd(const ArgVal &Src, const ArgVal &Hd) { mov_arg(Hd, ARG2); } -void BeamModuleAssembler::emit_get_tl(const ArgVal &Src, const ArgVal &Tl) { +void BeamModuleAssembler::emit_get_tl(const ArgRegister &Src, + const ArgRegister &Tl) { mov_arg(ARG1, Src); x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); @@ -356,22 +362,23 @@ void BeamModuleAssembler::emit_get_tl(const ArgVal &Src, const ArgVal &Tl) { mov_arg(Tl, ARG2); } -void BeamModuleAssembler::emit_is_nonempty_list_get_list(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Hd, - const ArgVal &Tl) { +void BeamModuleAssembler::emit_is_nonempty_list_get_list( + const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Hd, + const ArgRegister &Tl) { mov_arg(RET, Src); a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); emit_get_list(RET, Hd, Tl); } -void BeamModuleAssembler::emit_is_nonempty_list_get_hd(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Hd) { +void BeamModuleAssembler::emit_is_nonempty_list_get_hd(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Hd) { mov_arg(RET, Src); a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); x86::Gp boxed_ptr = emit_ptr_val(RET, RET); @@ -380,12 +387,12 @@ void BeamModuleAssembler::emit_is_nonempty_list_get_hd(const ArgVal &Fail, mov_arg(Hd, ARG2); } -void BeamModuleAssembler::emit_is_nonempty_list_get_tl(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Tl) { +void BeamModuleAssembler::emit_is_nonempty_list_get_tl(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Tl) { mov_arg(RET, Src); a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); x86::Gp boxed_ptr = emit_ptr_val(RET, RET); @@ -394,7 +401,8 @@ void BeamModuleAssembler::emit_is_nonempty_list_get_tl(const ArgVal &Fail, mov_arg(Tl, ARG2); } -void BeamModuleAssembler::emit_i_get(const ArgVal &Src, const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_get(const ArgSource &Src, + const ArgRegister &Dst) { mov_arg(ARG2, Src); emit_enter_runtime(); @@ -407,9 +415,9 @@ void BeamModuleAssembler::emit_i_get(const ArgVal &Src, const ArgVal &Dst) { mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_i_get_hash(const ArgVal &Src, - const ArgVal &Hash, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_get_hash(const ArgConstant &Src, + const ArgWord &Hash, + const ArgRegister &Dst) { mov_arg(ARG2, Hash); mov_arg(ARG3, Src); @@ -424,7 +432,7 @@ void BeamModuleAssembler::emit_i_get_hash(const ArgVal &Src, } /* Store the pointer to a tuple in ARG2. Remove any LITERAL_PTR tag. */ -void BeamModuleAssembler::emit_load_tuple_ptr(const ArgVal &Term) { +void BeamModuleAssembler::emit_load_tuple_ptr(const ArgSource &Term) { mov_arg(ARG2, Term); (void)emit_ptr_val(ARG2, ARG2); } @@ -432,7 +440,7 @@ void BeamModuleAssembler::emit_load_tuple_ptr(const ArgVal &Term) { #ifdef DEBUG /* Emit an assertion to ensure that tuple_reg points into the same * tuple as Src. */ -void BeamModuleAssembler::emit_tuple_assertion(const ArgVal &Src, +void BeamModuleAssembler::emit_tuple_assertion(const ArgSource &Src, x86::Gp tuple_reg) { Label ok = a.newLabel(), fatal = a.newLabel(); ASSERT(tuple_reg != RET); @@ -443,42 +451,60 @@ void BeamModuleAssembler::emit_tuple_assertion(const ArgVal &Src, a.short_().je(ok); a.bind(fatal); - { a.ud2(); } + { + comment("tuple assertion failure"); + a.ud2(); + } a.bind(ok); } #endif /* Fetch an element from the tuple pointed to by the boxed pointer * in ARG2. */ -void BeamModuleAssembler::emit_i_get_tuple_element(const ArgVal &Src, - const ArgVal &Element, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_get_tuple_element(const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst) { +#ifdef DEBUG + emit_tuple_assertion(Src, ARG2); +#endif + + a.mov(ARG1, emit_boxed_val(ARG2, Element.get())); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_get_tuple_element_swap( + const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst, + const ArgRegister &OtherDst) { #ifdef DEBUG emit_tuple_assertion(Src, ARG2); #endif - a.mov(ARG1, emit_boxed_val(ARG2, Element.getValue())); + mov_arg(ARG1, OtherDst); + a.mov(ARG3, emit_boxed_val(ARG2, Element.get())); mov_arg(Dst, ARG1); + mov_arg(OtherDst, ARG3); } /* Fetch two consecutive tuple elements from the tuple pointed to by * the boxed pointer in ARG2. */ -void BeamModuleAssembler::emit_get_two_tuple_elements(const ArgVal &Src, - const ArgVal &Element, - const ArgVal &Dst1, - const ArgVal &Dst2) { +void BeamModuleAssembler::emit_get_two_tuple_elements(const ArgSource &Src, + const ArgWord &Element, + const ArgRegister &Dst1, + const ArgRegister &Dst2) { #ifdef DEBUG emit_tuple_assertion(Src, ARG2); #endif x86::Mem element_ptr = - emit_boxed_val(ARG2, Element.getValue(), 2 * sizeof(Eterm)); + emit_boxed_val(ARG2, Element.get(), 2 * sizeof(Eterm)); - switch (ArgVal::register_relation(Dst1, Dst2)) { + switch (ArgVal::memory_relation(Dst1, Dst2)) { case ArgVal::Relation::consecutive: { x86::Mem dst_ptr = getArgRef(Dst1, 16); - a.movups(x86::xmm0, element_ptr); - a.movups(dst_ptr, x86::xmm0); + vmovups(x86::xmm0, element_ptr); + vmovups(dst_ptr, x86::xmm0); break; } case ArgVal::Relation::reverse_consecutive: { @@ -493,21 +519,21 @@ void BeamModuleAssembler::emit_get_two_tuple_elements(const ArgVal &Src, } case ArgVal::Relation::none: fallback: - a.mov(ARG1, emit_boxed_val(ARG2, Element.getValue())); - a.mov(ARG3, emit_boxed_val(ARG2, (Element + sizeof(Eterm)).getValue())); + a.mov(ARG1, emit_boxed_val(ARG2, Element.get())); + a.mov(ARG3, emit_boxed_val(ARG2, Element.get() + sizeof(Eterm))); mov_arg(Dst1, ARG1); mov_arg(Dst2, ARG3); break; } } -void BeamModuleAssembler::emit_init(const ArgVal &Y) { - mov_arg(Y, NIL); +void BeamModuleAssembler::emit_init(const ArgYRegister &Dst) { + mov_arg(Dst, NIL); } -void BeamModuleAssembler::emit_init_yregs(const ArgVal &Size, - const std::vector &args) { - unsigned count = Size.getValue(); +void BeamModuleAssembler::emit_init_yregs(const ArgWord &Size, + const Span &args) { + unsigned count = Size.get(); ASSERT(count == args.size()); if (count == 1) { @@ -522,14 +548,16 @@ void BeamModuleAssembler::emit_init_yregs(const ArgVal &Size, mov_imm(x86::rax, NIL); while (i < count) { + unsigned first_y = args[i].as().get(); unsigned slots = 1; - unsigned first_y = args.at(i).getValue(); while (i + slots < count) { - ArgVal current_y = args.at(i + slots); - if (first_y + slots != current_y.getValue()) { + const ArgYRegister ¤t_y = args[i + slots]; + + if (first_y + slots != current_y.get()) { break; } + slots++; } @@ -584,35 +612,34 @@ void BeamModuleAssembler::emit_init_yregs(const ArgVal &Size, } } -void BeamModuleAssembler::emit_i_trim(const ArgVal &Words) { - ASSERT(Words.getType() == ArgVal::TYPE::u); - ASSERT(Words.getValue() <= 1023); - - if (Words.getValue() > 0) { - a.add(E, imm(Words.getValue() * sizeof(Eterm))); +void BeamModuleAssembler::emit_i_trim(const ArgWord &Words) { + if (Words.get() > 0) { + ASSERT(Words.get() <= 1023); + a.add(E, imm(Words.get() * sizeof(Eterm))); } } -void BeamModuleAssembler::emit_i_move(const ArgVal &Src, const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_move(const ArgSource &Src, + const ArgRegister &Dst) { mov_arg(Dst, Src); } /* Move two words at consecutive addresses to consecutive or reverse * consecutive destinations. */ -void BeamModuleAssembler::emit_move_two_words(const ArgVal &Src1, - const ArgVal &Dst1, - const ArgVal &Src2, - const ArgVal &Dst2) { +void BeamModuleAssembler::emit_move_two_words(const ArgSource &Src1, + const ArgRegister &Dst1, + const ArgSource &Src2, + const ArgRegister &Dst2) { x86::Mem src_ptr = getArgRef(Src1, 16); - ASSERT(ArgVal::register_relation(Src1, Src2) == + ASSERT(ArgVal::memory_relation(Src1, Src2) == ArgVal::Relation::consecutive); - switch (ArgVal::register_relation(Dst1, Dst2)) { + switch (ArgVal::memory_relation(Dst1, Dst2)) { case ArgVal::Relation::consecutive: { x86::Mem dst_ptr = getArgRef(Dst1, 16); - a.movups(x86::xmm0, src_ptr); - a.movups(dst_ptr, x86::xmm0); + vmovups(x86::xmm0, src_ptr); + vmovups(dst_ptr, x86::xmm0); break; } case ArgVal::Relation::reverse_consecutive: { @@ -635,12 +662,13 @@ void BeamModuleAssembler::emit_move_two_words(const ArgVal &Src1, } } -void BeamModuleAssembler::emit_swap(const ArgVal &R1, const ArgVal &R2) { +void BeamModuleAssembler::emit_swap(const ArgRegister &R1, + const ArgRegister &R2) { if (!hasCpuFeature(CpuFeatures::X86::kAVX)) { goto fallback; } - switch (ArgVal::register_relation(R1, R2)) { + switch (ArgVal::memory_relation(R1, R2)) { case ArgVal::Relation::consecutive: { x86::Mem ptr = getArgRef(R1, 16); comment("(swapping using AVX)"); @@ -665,21 +693,22 @@ void BeamModuleAssembler::emit_swap(const ArgVal &R1, const ArgVal &R2) { } } -void BeamModuleAssembler::emit_node(const ArgVal &Dst) { +void BeamModuleAssembler::emit_node(const ArgRegister &Dst) { a.mov(ARG1, imm(&erts_this_node)); a.mov(ARG1, x86::qword_ptr(ARG1)); a.mov(ARG1, x86::qword_ptr(ARG1, offsetof(ErlNode, sysname))); mov_arg(Dst, ARG1); } -void BeamModuleAssembler::emit_put_cons(const ArgVal &Hd, const ArgVal &Tl) { - switch (ArgVal::register_relation(Hd, Tl)) { +void BeamModuleAssembler::emit_put_cons(const ArgSource &Hd, + const ArgSource &Tl) { + switch (ArgVal::memory_relation(Hd, Tl)) { case ArgVal::Relation::consecutive: { x86::Mem src_ptr = getArgRef(Hd, 16); x86::Mem dst_ptr = x86::xmmword_ptr(HTOP, 0); comment("(put head and tail together)"); - a.movups(x86::xmm0, src_ptr); - a.movups(dst_ptr, x86::xmm0); + vmovups(x86::xmm0, src_ptr); + vmovups(dst_ptr, x86::xmm0); break; } case ArgVal::Relation::reverse_consecutive: { @@ -703,25 +732,26 @@ void BeamModuleAssembler::emit_put_cons(const ArgVal &Hd, const ArgVal &Tl) { a.lea(ARG2, x86::qword_ptr(HTOP, TAG_PRIMARY_LIST)); } -void BeamModuleAssembler::emit_append_cons(const ArgVal &index, - const ArgVal &Hd) { - size_t offset = 2 * index.getValue() * sizeof(Eterm); +void BeamModuleAssembler::emit_append_cons(const ArgWord &Index, + const ArgSource &Hd) { + size_t offset = Index.get() * sizeof(Eterm[2]); mov_arg(x86::qword_ptr(HTOP, offset), Hd); a.mov(x86::qword_ptr(HTOP, offset + sizeof(Eterm)), ARG2); a.lea(ARG2, x86::qword_ptr(HTOP, offset + TAG_PRIMARY_LIST)); } -void BeamModuleAssembler::emit_store_cons(const ArgVal &len, - const ArgVal &Dst) { - a.add(HTOP, imm(len.getValue() * 2 * sizeof(Eterm))); +void BeamModuleAssembler::emit_store_cons(const ArgWord &Len, + const ArgRegister &Dst) { + a.add(HTOP, imm(Len.get() * sizeof(Eterm[2]))); mov_arg(Dst, ARG2); } -void BeamModuleAssembler::emit_put_tuple2(const ArgVal &Dst, - const ArgVal &Arity, - const std::vector &args) { +void BeamModuleAssembler::emit_put_tuple2(const ArgRegister &Dst, + const ArgWord &Arity, + const Span &args) { size_t size = args.size(); - ASSERT(arityval(Arity.getValue()) == size); + + ASSERT(arityval(Arity.get()) == size); comment("Move arity word"); mov_arg(x86::qword_ptr(HTOP, 0), Arity); @@ -733,14 +763,14 @@ void BeamModuleAssembler::emit_put_tuple2(const ArgVal &Dst, if (i + 1 == size) { mov_arg(dst_ptr, args[i]); } else { - switch (ArgVal::register_relation(args[i], args[i + 1])) { + switch (ArgVal::memory_relation(args[i], args[i + 1])) { case ArgVal::consecutive: { x86::Mem src_ptr = getArgRef(args[i], 16); comment("(moving two elements at once)"); dst_ptr.setSize(16); - a.movups(x86::xmm0, src_ptr); - a.movups(dst_ptr, x86::xmm0); + vmovups(x86::xmm0, src_ptr); + vmovups(dst_ptr, x86::xmm0); i++; break; } @@ -772,43 +802,115 @@ void BeamModuleAssembler::emit_put_tuple2(const ArgVal &Dst, mov_arg(Dst, ARG1); } -void BeamModuleAssembler::emit_self(const ArgVal &Dst) { +void BeamModuleAssembler::emit_self(const ArgRegister &Dst) { a.mov(ARG1, x86::qword_ptr(c_p, offsetof(Process, common.id))); mov_arg(Dst, ARG1); } -void BeamModuleAssembler::emit_set_tuple_element(const ArgVal &Element, - const ArgVal &Tuple, - const ArgVal &Offset) { +void BeamModuleAssembler::emit_update_record(const ArgAtom &Hint, + const ArgWord &TupleSize, + const ArgSource &Src, + const ArgRegister &Dst, + const ArgWord &UpdateCount, + const Span &updates) { + size_t copy_index = 0, size_on_heap = TupleSize.get() + 1; + Label next = a.newLabel(); + + x86::Gp ptr_val; + + ASSERT(UpdateCount.get() == updates.size()); + ASSERT((UpdateCount.get() % 2) == 0); + + ASSERT(size_on_heap > 2); + + mov_arg(RET, Src); + + /* Setting a field to the same value is pretty common, so we'll check for + * that since it's vastly cheaper than copying if we're right, and doesn't + * cost much if we're wrong. */ + if (Hint.get() == am_reuse && updates.size() == 2) { + const auto next_index = updates[0].as().get(); + const auto &next_value = updates[1].as(); + + a.mov(ARG1, RET); + ptr_val = emit_ptr_val(ARG1, ARG1); + cmp_arg(emit_boxed_val(ptr_val, next_index * sizeof(Eterm)), + next_value, + ARG2); + a.je(next); + } + + ptr_val = emit_ptr_val(RET, RET); + + for (size_t i = 0; i < updates.size(); i += 2) { + const auto next_index = updates[i].as().get(); + const auto &next_value = updates[i + 1].as(); + + ASSERT(next_index > 0 && next_index >= copy_index); + + emit_copy_words(emit_boxed_val(ptr_val, copy_index * sizeof(Eterm)), + x86::qword_ptr(HTOP, copy_index * sizeof(Eterm)), + next_index - copy_index, + ARG1); + + mov_arg(x86::qword_ptr(HTOP, next_index * sizeof(Eterm)), + next_value, + ARG1); + copy_index = next_index + 1; + } + + emit_copy_words(emit_boxed_val(ptr_val, copy_index * sizeof(Eterm)), + x86::qword_ptr(HTOP, copy_index * sizeof(Eterm)), + size_on_heap - copy_index, + ARG1); + + a.lea(RET, x86::qword_ptr(HTOP, TAG_PRIMARY_BOXED)); + a.add(HTOP, imm(size_on_heap * sizeof(Eterm))); + + a.bind(next); + mov_arg(Dst, RET); +} + +void BeamModuleAssembler::emit_set_tuple_element(const ArgSource &Element, + const ArgRegister &Tuple, + const ArgWord &Offset) { mov_arg(ARG1, Tuple); x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - mov_arg(emit_boxed_val(boxed_ptr, Offset.getValue()), Element, ARG2); + mov_arg(emit_boxed_val(boxed_ptr, Offset.get()), Element, ARG2); } -void BeamModuleAssembler::emit_is_nonempty_list(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_is_nonempty_list(const ArgLabel &Fail, + const ArgRegister &Src) { x86::Mem list_ptr = getArgRef(Src, 1); a.test(list_ptr, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_jump(const ArgVal &Fail) { - a.jmp(labels[Fail.getValue()]); +void BeamModuleAssembler::emit_jump(const ArgLabel &Fail) { + a.jmp(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_is_atom(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_atom(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(RET, Src); - ERTS_CT_ASSERT(_TAG_IMMED2_MASK < 256); - a.and_(RETb, imm(_TAG_IMMED2_MASK)); - a.cmp(RETb, imm(_TAG_IMMED2_ATOM)); - a.jne(labels[Fail.getValue()]); + + if (always_one_of(Src)) { + comment("simplified atom test since all other types are boxed"); + a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + a.je(resolve_beam_label(Fail)); + } else { + ERTS_CT_ASSERT(_TAG_IMMED2_MASK < 256); + a.and_(RETb, imm(_TAG_IMMED2_MASK)); + a.cmp(RETb, imm(_TAG_IMMED2_ATOM)); + a.jne(resolve_beam_label(Fail)); + } } -void BeamModuleAssembler::emit_is_boolean(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_is_boolean(const ArgLabel &Fail, + const ArgSource &Src) { /* Since am_true and am_false differ by a single bit, we can simplify the * check by clearing said bit and comparing against the lesser one. */ ERTS_CT_ASSERT(am_false == make_atom(0)); @@ -816,99 +918,108 @@ void BeamModuleAssembler::emit_is_boolean(const ArgVal &Fail, mov_arg(ARG1, Src); - a.and_(ARG1, imm(~(am_true & ~_TAG_IMMED1_MASK))); + a.and_(ARG1, imm(~(am_true & ~_TAG_IMMED2_MASK))); a.cmp(ARG1, imm(am_false)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_is_binary(Label fail, - x86::Gp src, - Label next, - Label subbin) { - ASSERT(src != RET && src != ARG2); - - emit_is_boxed(fail, src); +void BeamModuleAssembler::emit_is_binary(const ArgLabel &Fail, + const ArgSource &Src) { + Label is_binary = a.newLabel(), next = a.newLabel(); - x86::Gp boxed_ptr = emit_ptr_val(src, src); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - - a.and_(RETb, imm(_TAG_HEADER_MASK)); - a.cmp(RETb, imm(_TAG_HEADER_SUB_BIN)); - a.short_().je(subbin); - ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); - a.and_(RETb, imm(~4)); - a.cmp(RETb, imm(_TAG_HEADER_REFC_BIN)); - a.short_().je(next); - a.jmp(fail); -} + mov_arg(ARG1, Src); -void BeamModuleAssembler::emit_is_binary(const ArgVal &Fail, - const ArgVal &Src) { - Label next = a.newLabel(), subbin = a.newLabel(); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG1); - mov_arg(ARG1, Src); + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + if (masked_types(Src) == BeamTypeId::Bitstring) { + const auto diff_mask = _TAG_HEADER_SUB_BIN - _TAG_HEADER_REFC_BIN; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & diff_mask) != 0 && + (_TAG_HEADER_REFC_BIN & diff_mask) == 0 && + (_TAG_HEADER_HEAP_BIN & diff_mask) == 0); + comment("simplified binary test since source is always a bitstring " + "when boxed"); + a.test(emit_boxed_val(boxed_ptr, 0, 1), diff_mask); + a.short_().je(next); + } else { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_SUB_BIN)); + a.short_().jne(is_binary); + } - emit_is_binary(labels[Fail.getValue()], ARG1, next, subbin); + /* This is a sub binary. */ + a.cmp(emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize), sizeof(byte)), + imm(0)); + a.jne(resolve_beam_label(Fail)); + if (masked_types(Src) != BeamTypeId::Bitstring) { + a.short_().jmp(next); + } - a.bind(subbin); - { - /* emit_is_binary has already removed the literal tag from Src, if - * applicable. */ - a.cmp(emit_boxed_val(ARG1, offsetof(ErlSubBin, bitsize), sizeof(byte)), - imm(0)); - a.jne(labels[Fail.getValue()]); + a.bind(is_binary); + if (masked_types(Src) != BeamTypeId::Bitstring) { + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN + 4 == _TAG_HEADER_HEAP_BIN); + a.and_(RETb, imm(~4)); + a.cmp(RETb, imm(_TAG_HEADER_REFC_BIN)); + a.jne(resolve_beam_label(Fail)); } a.bind(next); } -void BeamModuleAssembler::emit_is_bitstring(const ArgVal &Fail, - const ArgVal &Src) { - Label next = a.newLabel(); - +void BeamModuleAssembler::emit_is_bitstring(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(ARG1, Src); - emit_is_binary(labels[Fail.getValue()], ARG1, next, next); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG1); - a.bind(next); + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + + const auto mask = _HEADER_SUBTAG_MASK - _BINARY_XXX_MASK; + ERTS_CT_ASSERT(TAG_PRIMARY_HEADER == 0); + ERTS_CT_ASSERT(_TAG_HEADER_REFC_BIN == (_TAG_HEADER_REFC_BIN & mask)); + a.and_(RETb, imm(mask)); + a.cmp(RETb, imm(_TAG_HEADER_REFC_BIN)); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_is_float(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_float(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(ARG1, Src); - emit_is_boxed(labels[Fail.getValue()], ARG1); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG1); - x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.cmp(emit_boxed_val(boxed_ptr), imm(HEADER_FLONUM)); - a.jne(labels[Fail.getValue()]); + if (masked_types(Src) == BeamTypeId::Float) { + comment("skipped header test since we know it's a float when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.cmp(emit_boxed_val(boxed_ptr), imm(HEADER_FLONUM)); + a.jne(resolve_beam_label(Fail)); + } } -void BeamModuleAssembler::emit_is_function(const ArgVal &Fail, - const ArgVal &Src) { - Label next = a.newLabel(); - +void BeamModuleAssembler::emit_is_function(const ArgLabel &Fail, + const ArgRegister &Src) { mov_arg(RET, Src); - emit_is_boxed(labels[Fail.getValue()], RET); - - x86::Gp boxed_ptr = emit_ptr_val(RET, RET); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.cmp(RET, imm(HEADER_FUN)); - a.short_().je(next); - ERTS_CT_ASSERT(HEADER_EXPORT < 256); - a.cmp(RETb, imm(HEADER_EXPORT)); - a.jne(labels[Fail.getValue()]); + emit_is_boxed(resolve_beam_label(Fail), Src, RET); - a.bind(next); + if (masked_types(Src) == BeamTypeId::Fun) { + comment("skipped header test since we know it's a fun when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.cmp(RET, imm(HEADER_FUN)); + a.jne(resolve_beam_label(Fail)); + } } -void BeamModuleAssembler::emit_is_function2(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Arity) { - if (Arity.getType() != ArgVal::i) { - /* - * Non-literal arity - extremely uncommon. Generate simple code. - */ +void BeamModuleAssembler::emit_is_function2(const ArgLabel &Fail, + const ArgSource &Src, + const ArgSource &Arity) { + if (!Arity.isSmall()) { + /* Non-small arity - extremely uncommon. Generate simple code. */ mov_arg(ARG2, Src); mov_arg(ARG3, Arity); @@ -920,73 +1031,81 @@ void BeamModuleAssembler::emit_is_function2(const ArgVal &Fail, emit_leave_runtime(); a.cmp(RET, imm(am_true)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); return; } - unsigned arity = unsigned_val(Arity.getValue()); + unsigned arity = Arity.as().getUnsigned(); if (arity > MAX_ARG) { /* Arity is negative or too large. */ - a.jmp(labels[Fail.getValue()]); + a.jmp(resolve_beam_label(Fail)); return; } - Label next = a.newLabel(), fun = a.newLabel(); - mov_arg(ARG1, Src); - emit_is_boxed(labels[Fail.getValue()], ARG1); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG1); x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.cmp(RETd, imm(HEADER_FUN)); - a.short_().je(fun); - ERTS_CT_ASSERT(HEADER_EXPORT < 256); - a.cmp(RETb, imm(HEADER_EXPORT)); - a.jne(labels[Fail.getValue()]); - - comment("Check arity of export fun"); - a.mov(ARG2, emit_boxed_val(boxed_ptr, sizeof(Eterm))); - a.cmp(x86::qword_ptr(ARG2, offsetof(Export, info.mfa.arity)), imm(arity)); - a.jne(labels[Fail.getValue()]); - a.short_().jmp(next); - comment("Check arity of fun"); - a.bind(fun); - { - a.cmp(emit_boxed_val(boxed_ptr, offsetof(ErlFunThing, arity)), - imm(arity)); - a.jne(labels[Fail.getValue()]); + if (masked_types(Src) == BeamTypeId::Fun) { + comment("skipped header test since we know it's a fun when boxed"); + } else { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.cmp(RETd, imm(HEADER_FUN)); + a.jne(resolve_beam_label(Fail)); } - a.bind(next); + a.cmp(emit_boxed_val(boxed_ptr, offsetof(ErlFunThing, arity), sizeof(byte)), + imm(arity)); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_is_integer(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_is_integer(const ArgLabel &Fail, + const ArgSource &Src) { + if (always_immediate(Src)) { + comment("skipped test for boxed since the value is always immediate"); + mov_arg(RET, Src); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.jne(resolve_beam_label(Fail)); + + return; + } + Label next = a.newLabel(); - Label fail = labels[Fail.getValue()]; mov_arg(ARG1, Src); - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.short_().je(next); + if (always_one_of(Src)) { + comment("simplified small test since all other types are boxed"); + emit_is_boxed(next, Src, ARG1); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().je(next); - emit_is_boxed(fail, RET); + emit_is_boxed(resolve_beam_label(Fail), Src, RET); + } - x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + if (masked_types(Src) == BeamTypeId::Integer) { + comment("skipped header test since we know it's a bignum when " + "boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.and_(RETb, imm(_TAG_HEADER_MASK - _BIG_SIGN_BIT)); - a.cmp(RETb, imm(_TAG_HEADER_POS_BIG)); - a.jne(fail); + a.and_(RETb, imm(_TAG_HEADER_MASK - _BIG_SIGN_BIT)); + a.cmp(RETb, imm(_TAG_HEADER_POS_BIG)); + a.jne(resolve_beam_label(Fail)); + } a.bind(next); } -void BeamModuleAssembler::emit_is_list(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_list(const ArgLabel &Fail, + const ArgSource &Src) { Label next = a.newLabel(); mov_arg(RET, Src); @@ -994,213 +1113,288 @@ void BeamModuleAssembler::emit_is_list(const ArgVal &Fail, const ArgVal &Src) { a.cmp(RET, imm(NIL)); a.short_().je(next); a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); a.bind(next); } -void BeamModuleAssembler::emit_is_map(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_map(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(RET, Src); - emit_is_boxed(labels[Fail.getValue()], RET); + emit_is_boxed(resolve_beam_label(Fail), Src, RET); - x86::Gp boxed_ptr = emit_ptr_val(RET, RET); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.and_(RETb, imm(_TAG_HEADER_MASK)); - a.cmp(RETb, imm(_TAG_HEADER_MAP)); - a.jne(labels[Fail.getValue()]); + /* As an optimization for the `error | #{}` case, skip checking the header + * word when we know that the only possible boxed type is a map. */ + if (masked_types(Src) == BeamTypeId::Map) { + comment("skipped header test since we know it's a map when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_MAP)); + a.jne(resolve_beam_label(Fail)); + } } -void BeamModuleAssembler::emit_is_nil(const ArgVal &Fail, const ArgVal &Src) { - a.cmp(getArgRef(Src), imm(NIL)); - a.jne(labels[Fail.getValue()]); +void BeamModuleAssembler::emit_is_nil(const ArgLabel &Fail, + const ArgRegister &Src) { + a.cmp(getArgRef(Src, 1), imm(NIL)); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_is_number(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_is_number(const ArgLabel &Fail, + const ArgSource &Src) { + Label fail = resolve_beam_label(Fail); Label next = a.newLabel(); - Label fail = labels[Fail.getValue()]; mov_arg(ARG1, Src); - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.short_().je(next); + if (always_one_of(Src)) { + comment("simplified small test test since all other types are boxed"); + emit_is_boxed(next, Src, ARG1); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().je(next); - emit_is_boxed(fail, RET); + /* Reuse RET as the important bits are still available. */ + emit_is_boxed(fail, Src, RET); + } - x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(ARG1, emit_boxed_val(boxed_ptr)); + if (masked_types(Src) == BeamTypeId::Number) { + comment("skipped header test since we know it's a number when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.mov(ARG1, emit_boxed_val(boxed_ptr)); - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_HEADER_MASK - _BIG_SIGN_BIT)); - a.cmp(RETb, imm(_TAG_HEADER_POS_BIG)); - a.short_().je(next); + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_HEADER_MASK - _BIG_SIGN_BIT)); + a.cmp(RETb, imm(_TAG_HEADER_POS_BIG)); + a.short_().je(next); - a.cmp(ARG1d, imm(HEADER_FLONUM)); - a.jne(fail); + a.cmp(ARG1d, imm(HEADER_FLONUM)); + a.jne(fail); + } a.bind(next); } -void BeamModuleAssembler::emit_is_pid(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_pid(const ArgLabel &Fail, + const ArgSource &Src) { Label next = a.newLabel(); mov_arg(ARG1, Src); - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_PID)); - a.short_().je(next); + if (always_one_of(Src)) { + comment("simplified local pid test since all other types are boxed"); + emit_is_boxed(next, Src, ARG1); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_PID)); + a.short_().je(next); + + /* Reuse RET as the important bits are still available. */ + emit_is_boxed(resolve_beam_label(Fail), Src, RET); + } - /* Reuse RET as the important bits are still available. */ - emit_is_boxed(labels[Fail.getValue()], RET); + if (masked_types(Src) == BeamTypeId::Pid) { + comment("skipped header test since we know it's a pid when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_PID)); + a.jne(resolve_beam_label(Fail)); + } - x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.and_(RETb, _TAG_HEADER_MASK); - a.cmp(RETb, _TAG_HEADER_EXTERNAL_PID); - a.jne(labels[Fail.getValue()]); a.bind(next); } -void BeamModuleAssembler::emit_is_port(const ArgVal &Fail, const ArgVal &Src) { +void BeamModuleAssembler::emit_is_port(const ArgLabel &Fail, + const ArgSource &Src) { Label next = a.newLabel(); + mov_arg(ARG1, Src); - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_PORT)); - a.short_().je(next); + if (always_one_of(Src)) { + comment("simplified local port test since all other types are boxed"); + emit_is_boxed(next, Src, ARG1); + } else { + a.mov(RETd, ARG1d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_PORT)); + a.short_().je(next); - /* Reuse RET as the important bits are still available. */ - emit_is_boxed(labels[Fail.getValue()], RET); + /* Reuse RET as the important bits are still available. */ + emit_is_boxed(resolve_beam_label(Fail), Src, RET); + } + + if (masked_types(Src) == BeamTypeId::Port) { + comment("skipped header test since we know it's a port when boxed"); + } else { + x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_PORT)); + a.jne(resolve_beam_label(Fail)); + } - x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.and_(RETb, imm(_TAG_HEADER_MASK)); - a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_PORT)); - a.jne(labels[Fail.getValue()]); a.bind(next); } -void BeamModuleAssembler::emit_is_reference(const ArgVal &Fail, - const ArgVal &Src) { - Label next = a.newLabel(); - +void BeamModuleAssembler::emit_is_reference(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(RET, Src); - emit_is_boxed(labels[Fail.getValue()], RET); + emit_is_boxed(resolve_beam_label(Fail), Src, RET); - x86::Gp boxed_ptr = emit_ptr_val(RET, RET); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - a.and_(RETb, imm(_TAG_HEADER_MASK)); - a.cmp(RETb, imm(_TAG_HEADER_REF)); - a.short_().je(next); - a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_REF)); - a.jne(labels[Fail.getValue()]); + if (masked_types(Src) == BeamTypeId::Reference) { + comment("skipped header test since we know it's a ref when boxed"); + } else { + Label next = a.newLabel(); - a.bind(next); + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_REF)); + a.short_().je(next); + a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_REF)); + a.jne(resolve_beam_label(Fail)); + + a.bind(next); + } } /* Note: This instruction leaves the pointer to the tuple in ARG2. */ -void BeamModuleAssembler::emit_i_is_tagged_tuple(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Arity, - const ArgVal &Tag) { +void BeamModuleAssembler::emit_i_is_tagged_tuple(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity, + const ArgAtom &Tag) { mov_arg(ARG2, Src); - emit_is_boxed(labels[Fail.getValue()], ARG2); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG2); x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG2); ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); - a.cmp(emit_boxed_val(boxed_ptr, 0, sizeof(Uint32)), imm(Arity.getValue())); - a.jne(labels[Fail.getValue()]); + a.cmp(emit_boxed_val(boxed_ptr, 0, sizeof(Uint32)), imm(Arity.get())); + a.jne(resolve_beam_label(Fail)); - a.cmp(emit_boxed_val(boxed_ptr, sizeof(Eterm)), imm(Tag.getValue())); - a.jne(labels[Fail.getValue()]); + a.cmp(emit_boxed_val(boxed_ptr, sizeof(Eterm)), imm(Tag.get())); + a.jne(resolve_beam_label(Fail)); } /* Note: This instruction leaves the pointer to the tuple in ARG2. */ -void BeamModuleAssembler::emit_i_is_tagged_tuple_ff(const ArgVal &NotTuple, - const ArgVal &NotRecord, - const ArgVal &Src, - const ArgVal &Arity, - const ArgVal &Tag) { +void BeamModuleAssembler::emit_i_is_tagged_tuple_ff(const ArgLabel &NotTuple, + const ArgLabel &NotRecord, + const ArgSource &Src, + const ArgWord &Arity, + const ArgAtom &Tag) { mov_arg(ARG2, Src); - emit_is_boxed(labels[NotTuple.getValue()], ARG2); + + emit_is_boxed(resolve_beam_label(NotTuple), Src, ARG2); + (void)emit_ptr_val(ARG2, ARG2); a.mov(ARG1, emit_boxed_val(ARG2)); ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); a.test(ARG1.r8(), imm(_TAG_HEADER_MASK)); - a.jne(labels[NotTuple.getValue()]); + a.jne(resolve_beam_label(NotTuple)); ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); - a.cmp(ARG1d, imm(Arity.getValue())); - a.jne(labels[NotRecord.getValue()]); + a.cmp(ARG1d, imm(Arity.get())); + a.jne(resolve_beam_label(NotRecord)); - a.cmp(emit_boxed_val(ARG2, sizeof(Eterm)), imm(Tag.getValue())); - a.jne(labels[NotRecord.getValue()]); + a.cmp(emit_boxed_val(ARG2, sizeof(Eterm)), imm(Tag.get())); + a.jne(resolve_beam_label(NotRecord)); } /* Note: This instruction leaves the pointer to the tuple in ARG2. */ -void BeamModuleAssembler::emit_i_is_tuple(const ArgVal &Fail, - const ArgVal &Src) { +void BeamModuleAssembler::emit_i_is_tuple(const ArgLabel &Fail, + const ArgSource &Src) { mov_arg(ARG2, Src); + if (masked_types(Src) == BeamTypeId::Tuple) { + /* Fast path for the `error | {ok, Value}` case. */ + comment("simplified tuple test since the source is always a tuple " + "when boxed"); + /* We must be careful to still leave the pointer to the tuple + * in ARG2. */ + (void)emit_ptr_val(ARG2, ARG2); + a.test(ARG2.r8(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + } else { + emit_is_boxed(resolve_beam_label(Fail), Src, ARG2); - emit_is_boxed(labels[Fail.getValue()], ARG2); - - (void)emit_ptr_val(ARG2, ARG2); - ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); - a.test(emit_boxed_val(ARG2, 0, sizeof(byte)), imm(_TAG_HEADER_MASK)); + (void)emit_ptr_val(ARG2, ARG2); + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.test(emit_boxed_val(ARG2, 0, sizeof(byte)), imm(_TAG_HEADER_MASK)); + } - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } /* Note: This instruction leaves the pointer to the tuple in ARG2. */ -void BeamModuleAssembler::emit_i_is_tuple_of_arity(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Arity) { +void BeamModuleAssembler::emit_i_is_tuple_of_arity(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity) { mov_arg(ARG2, Src); - emit_is_boxed(labels[Fail.getValue()], ARG2); + emit_is_boxed(resolve_beam_label(Fail), Src, ARG2); (void)emit_ptr_val(ARG2, ARG2); ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); - a.cmp(emit_boxed_val(ARG2, 0, sizeof(Uint32)), imm(Arity.getValue())); - a.jne(labels[Fail.getValue()]); + a.cmp(emit_boxed_val(ARG2, 0, sizeof(Uint32)), imm(Arity.get())); + a.jne(resolve_beam_label(Fail)); } /* Note: This instruction leaves the pointer to the tuple in ARG2. */ -void BeamModuleAssembler::emit_i_test_arity(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Arity) { +void BeamModuleAssembler::emit_i_test_arity(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Arity) { mov_arg(ARG2, Src); (void)emit_ptr_val(ARG2, ARG2); ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); - a.cmp(emit_boxed_val(ARG2, 0, sizeof(Uint32)), imm(Arity.getValue())); - a.jne(labels[Fail.getValue()]); -} + a.cmp(emit_boxed_val(ARG2, 0, sizeof(Uint32)), imm(Arity.get())); + a.jne(resolve_beam_label(Fail)); +} + +void BeamModuleAssembler::emit_is_eq_exact(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + bool is_empty_binary = false; + if (exact_type(X) && Y.isLiteral()) { + auto unit = getSizeUnit(X); + if (unit != 0 && std::gcd(unit, 8) == 8) { + Eterm literal = + beamfile_get_literal(beam, Y.as().get()); + is_empty_binary = is_binary(literal) && binary_size(literal) == 0; + } + } -void BeamModuleAssembler::emit_i_is_eq_exact_immed(const ArgVal &Fail, - const ArgVal &X, - const ArgVal &Y) { - cmp_arg(getArgRef(X), Y); - a.jne(labels[Fail.getValue()]); -} + if (is_empty_binary) { + mov_arg(RET, X); -void BeamModuleAssembler::emit_i_is_ne_exact_immed(const ArgVal &Fail, - const ArgVal &X, - const ArgVal &Y) { - cmp_arg(getArgRef(X), Y); - a.je(labels[Fail.getValue()]); -} + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + + comment("simplified equality test with empty binary"); + a.cmp(emit_boxed_val(boxed_ptr, sizeof(Eterm)), 0); + a.jne(resolve_beam_label(Fail)); + + return; + } + + /* If one argument is known to be an immediate, we can fail + * immediately if they're not equal. */ + if (X.isRegister() && always_immediate(Y)) { + comment("simplified check since one argument is an immediate"); + + cmp_arg(getArgRef(X), Y); + a.jne(resolve_beam_label(Fail)); + + return; + } -void BeamModuleAssembler::emit_is_eq_exact(const ArgVal &Fail, - const ArgVal &X, - const ArgVal &Y) { Label next = a.newLabel(); mov_arg(ARG2, Y); /* May clobber ARG1 */ @@ -1213,12 +1407,24 @@ void BeamModuleAssembler::emit_is_eq_exact(const ArgVal &Fail, a.short_().je(next); #endif - /* Fancy way of checking if both are immediates. */ - a.mov(RETd, ARG1d); - a.and_(RETd, ARG2d); - a.and_(RETb, imm(_TAG_PRIMARY_MASK)); - a.cmp(RETb, imm(TAG_PRIMARY_IMMED1)); - a.je(labels[Fail.getValue()]); + if (always_same_types(X, Y)) { + comment("skipped tag test since they are always equal"); + } else if (Y.isLiteral()) { + /* Fail immediately unless X is the same type of pointer as + * the literal Y. + */ + Eterm literal = beamfile_get_literal(beam, Y.as().get()); + Uint tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); + a.test(ARG1.r8(), imm(tag_test)); + a.jne(resolve_beam_label(Fail)); + } else { + /* Fail immediately if the pointer tags are not equal. */ + emit_is_unequal_based_on_tags(ARG1, ARG2); + a.je(resolve_beam_label(Fail)); + } + + /* Both operands are pointers having the same tag. Must do a + * deeper comparison. */ emit_enter_runtime(); @@ -1226,80 +1432,81 @@ void BeamModuleAssembler::emit_is_eq_exact(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); - a.je(labels[Fail.getValue()]); + a.test(RETd, RETd); + a.je(resolve_beam_label(Fail)); a.bind(next); } -void BeamModuleAssembler::emit_i_is_eq_exact_literal(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Literal, - const ArgVal &tag_test) { - mov_arg(ARG2, Literal); /* May clobber ARG1 */ - mov_arg(ARG1, Src); +void BeamModuleAssembler::emit_is_ne_exact(const ArgLabel &Fail, + const ArgSource &X, + const ArgSource &Y) { + bool is_empty_binary = false; + if (exact_type(X) && Y.isLiteral()) { + auto unit = getSizeUnit(X); + if (unit != 0 && std::gcd(unit, 8) == 8) { + Eterm literal = + beamfile_get_literal(beam, Y.as().get()); + is_empty_binary = is_binary(literal) && binary_size(literal) == 0; + } + } - /* Fail immediately unless Src is the same type of pointer as the literal. - */ - a.test(ARG1.r8(), imm(tag_test.getValue())); - a.jne(labels[Fail.getValue()]); + if (is_empty_binary) { + mov_arg(RET, X); - emit_enter_runtime(); + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); - runtime_call<2>(eq); + comment("simplified non-equality test with empty binary"); + a.cmp(emit_boxed_val(boxed_ptr, sizeof(Eterm)), 0); + a.je(resolve_beam_label(Fail)); - emit_leave_runtime(); + return; + } - a.test(RET, RET); - a.jz(labels[Fail.getValue()]); -} + /* If one argument is known to be an immediate, we can fail + * immediately if they're equal. */ + if (X.isRegister() && always_immediate(Y)) { + comment("simplified check since one argument is an immediate"); + + cmp_arg(getArgRef(X), Y); + a.je(resolve_beam_label(Fail)); + + return; + } -void BeamModuleAssembler::emit_is_ne_exact(const ArgVal &Fail, - const ArgVal &X, - const ArgVal &Y) { Label next = a.newLabel(); mov_arg(ARG2, Y); /* May clobber ARG1 */ mov_arg(ARG1, X); a.cmp(ARG1, ARG2); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); - /* Fancy way of checking if both are immediates. */ - a.mov(RETd, ARG1d); - a.and_(RETd, ARG2d); - a.and_(RETb, imm(_TAG_PRIMARY_MASK)); - a.cmp(RETb, imm(TAG_PRIMARY_IMMED1)); + if (always_same_types(X, Y)) { + comment("skipped tag test since they are always equal"); + } else if (Y.isLiteral()) { + /* Succeed immediately if X is not the same type of pointer as + * the literal Y. + */ + Eterm literal = beamfile_get_literal(beam, Y.as().get()); + Uint tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); + a.test(ARG1.r8(), imm(tag_test)); #ifdef JIT_HARD_DEBUG - a.je(next); + a.jne(next); #else - a.short_().je(next); + a.short_().jne(next); #endif + } else { + /* Test whether the terms are definitely unequal based on the tags + * alone. */ + emit_is_unequal_based_on_tags(ARG1, ARG2); - emit_enter_runtime(); - - runtime_call<2>(eq); - - emit_leave_runtime(); - - a.test(RET, RET); - a.jnz(labels[Fail.getValue()]); - - a.bind(next); -} - -void BeamModuleAssembler::emit_i_is_ne_exact_literal(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Literal) { - Label next = a.newLabel(); - - mov_arg(ARG2, Literal); /* May clobber ARG1 */ - mov_arg(ARG1, Src); - - a.mov(RETd, ARG1d); - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(TAG_PRIMARY_IMMED1)); - a.short_().je(next); +#ifdef JIT_HARD_DEBUG + a.je(next); +#else + a.short_().je(next); +#endif + } emit_enter_runtime(); @@ -1307,8 +1514,8 @@ void BeamModuleAssembler::emit_i_is_ne_exact_literal(const ArgVal &Fail, emit_leave_runtime(); - a.test(RET, RET); - a.jnz(labels[Fail.getValue()]); + a.test(RETd, RETd); + a.jnz(resolve_beam_label(Fail)); a.bind(next); } @@ -1334,13 +1541,13 @@ void BeamGlobalAssembler::emit_arith_eq_shared() { a.short_().jne(generic_compare); boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.movsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + vmovsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); boxed_ptr = emit_ptr_val(ARG2, ARG2); - a.movsd(x86::xmm1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + vmovsd(x86::xmm1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); /* All float terms are finite so our caller only needs to check ZF. We don't * need to check for errors (PF). */ - a.comisd(x86::xmm0, x86::xmm1); + vucomisd(x86::xmm0, x86::xmm1); a.ret(); @@ -1362,10 +1569,10 @@ void BeamGlobalAssembler::emit_arith_eq_shared() { } } -void BeamModuleAssembler::emit_is_eq(const ArgVal &Fail, - const ArgVal &A, - const ArgVal &B) { - Label fail = labels[Fail.getValue()], next = a.newLabel(); +void BeamModuleAssembler::emit_is_eq(const ArgLabel &Fail, + const ArgSource &A, + const ArgSource &B) { + Label fail = resolve_beam_label(Fail), next = a.newLabel(); mov_arg(ARG2, B); /* May clobber ARG1 */ mov_arg(ARG1, A); @@ -1385,10 +1592,10 @@ void BeamModuleAssembler::emit_is_eq(const ArgVal &Fail, a.bind(next); } -void BeamModuleAssembler::emit_is_ne(const ArgVal &Fail, - const ArgVal &A, - const ArgVal &B) { - Label fail = labels[Fail.getValue()], next = a.newLabel(); +void BeamModuleAssembler::emit_is_ne(const ArgLabel &Fail, + const ArgSource &A, + const ArgSource &B) { + Label fail = resolve_beam_label(Fail), next = a.newLabel(); mov_arg(ARG2, B); /* May clobber ARG1 */ mov_arg(ARG1, A); @@ -1414,6 +1621,8 @@ void BeamGlobalAssembler::emit_arith_compare_shared() { atom_compare = a.newLabel(); generic_compare = a.newLabel(); + emit_enter_frame(); + /* Are both floats? * * This is done first as relative comparisons on atoms doesn't make much @@ -1437,16 +1646,20 @@ void BeamGlobalAssembler::emit_arith_compare_shared() { a.jne(generic_compare); boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.movsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + vmovsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); boxed_ptr = emit_ptr_val(ARG2, ARG2); - a.movsd(x86::xmm1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); - a.comisd(x86::xmm0, x86::xmm1); + vmovsd(x86::xmm1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + vucomisd(x86::xmm0, x86::xmm1); - /* `comisd` doesn't set the flags the same way `test` and friends do, so - * they need to be converted for jl/jge to work. */ - a.setae(x86::al); - a.dec(x86::al); + /* `vucomisd` doesn't set the flags the same way `test` and + * friends do, so they need to be converted for jl/jge/jg to work. + * NOTE: jg is needed for min/2 to work. + */ + a.seta(x86::al); + a.setb(x86::ah); + a.sub(x86::al, x86::ah); + emit_leave_frame(); a.ret(); a.bind(atom_compare); @@ -1470,6 +1683,7 @@ void BeamGlobalAssembler::emit_arith_compare_shared() { /* !! erts_cmp_atoms returns int, not Sint !! */ a.test(RETd, RETd); + emit_leave_frame(); a.ret(); } @@ -1486,122 +1700,579 @@ void BeamGlobalAssembler::emit_arith_compare_shared() { a.test(RET, RET); + emit_leave_frame(); a.ret(); } } -void BeamModuleAssembler::emit_is_lt(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS) { - Label fail = labels[Fail.getValue()]; - Label generic = a.newLabel(), next = a.newLabel(); +void BeamModuleAssembler::emit_is_lt(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS) { + Label generic = a.newLabel(), do_jge = a.newLabel(), next = a.newLabel(); + bool both_small = always_small(LHS) && always_small(RHS); + bool need_generic = !both_small; mov_arg(ARG2, RHS); /* May clobber ARG1 */ mov_arg(ARG1, LHS); - a.cmp(ARG1, ARG2); - a.je(fail); + if (both_small) { + comment("skipped test for small operands since they are always small"); + } else if (always_small(LHS) && exact_type(RHS) && + hasLowerBound(RHS)) { + comment("simplified test because it always succeeds when RHS is a " + "bignum"); + need_generic = false; + emit_is_not_boxed(next, ARG2, dShort); + } else if (always_small(LHS) && exact_type(RHS) && + hasUpperBound(RHS)) { + comment("simplified test because it always fails when RHS is a bignum"); + need_generic = false; + emit_is_not_boxed(resolve_beam_label(Fail), ARG2); + } else if (exact_type(LHS) && hasLowerBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always fails when LHS is a bignum"); + need_generic = false; + emit_is_not_boxed(resolve_beam_label(Fail), ARG1); + } else if (exact_type(LHS) && hasUpperBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always succeeds when LHS is a " + "bignum"); + emit_is_not_boxed(next, ARG1, dShort); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + /* The only possible kind of immediate is a small and all other + * values are boxed, so we can test for smalls by testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_not_boxed(generic, ARG2, dShort); + } else if (always_small(RHS)) { + emit_is_not_boxed(generic, ARG1, dShort); + } else { + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + emit_is_not_boxed(generic, RET, dShort); + } + } else { + /* Relative comparisons are overwhelmingly likely to be used on + * smalls, so we'll specialize those and keep the rest in a shared + * fragment. */ + if (always_small(RHS)) { + a.mov(RETd, ARG1d); + } else if (always_small(LHS)) { + a.mov(RETd, ARG2d); + } else { + /* Avoid the expensive generic comparison for equal terms. */ + a.cmp(ARG1, ARG2); + a.short_().je(do_jge); - /* Relative comparisons are overwhelmingly likely to be used on smalls, so - * we'll specialize those and keep the rest in a shared fragment. */ + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + } - if (RHS.isImmed() && is_small(RHS.getValue())) { - a.mov(RETd, ARG1d); - } else if (LHS.isImmed() && is_small(LHS.getValue())) { - a.mov(RETd, ARG2d); - } else { - a.mov(RETd, ARG1d); - a.and_(RETd, ARG2d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); } - a.and_(RETb, imm(_TAG_IMMED1_MASK)); - a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - a.short_().jne(generic); - + /* Both arguments are smalls. */ a.cmp(ARG1, ARG2); - a.short_().jl(next); - a.jmp(fail); + if (need_generic) { + a.short_().jmp(do_jge); + } a.bind(generic); { - safe_fragment_call(ga->get_arith_compare_shared()); - a.jge(fail); + if (need_generic) { + safe_fragment_call(ga->get_arith_compare_shared()); + } } + a.bind(do_jge); + a.jge(resolve_beam_label(Fail)); + a.bind(next); } -void BeamModuleAssembler::emit_is_ge(const ArgVal &Fail, - const ArgVal &LHS, - const ArgVal &RHS) { - Label fail = labels[Fail.getValue()]; - Label generic = a.newLabel(), next = a.newLabel(); +void BeamModuleAssembler::emit_is_ge(const ArgLabel &Fail, + const ArgSource &LHS, + const ArgSource &RHS) { + bool both_small = always_small(LHS) && always_small(RHS); + + if (both_small && LHS.isRegister() && RHS.isImmed() && + Support::isInt32(RHS.as().get())) { + comment("simplified compare because one operand is an immediate small"); + a.cmp(getArgRef(LHS.as()), imm(RHS.as().get())); + a.jl(resolve_beam_label(Fail)); + return; + } else if (both_small && RHS.isRegister() && LHS.isImmed() && + Support::isInt32(LHS.as().get())) { + comment("simplified compare because one operand is an immediate small"); + a.cmp(getArgRef(RHS.as()), imm(LHS.as().get())); + a.jg(resolve_beam_label(Fail)); + return; + } + + Label generic = a.newLabel(), do_jl = a.newLabel(), next = a.newLabel(); + bool need_generic = !both_small; mov_arg(ARG2, RHS); /* May clobber ARG1 */ mov_arg(ARG1, LHS); + if (both_small) { + comment("skipped test for small operands since they are always small"); + } else if (always_small(LHS) && exact_type(RHS) && + hasLowerBound(RHS)) { + comment("simplified test because it always fails when RHS is a bignum"); + need_generic = false; + emit_is_not_boxed(resolve_beam_label(Fail), ARG2); + } else if (always_small(LHS) && exact_type(RHS) && + hasUpperBound(RHS)) { + comment("simplified test because it always succeeds when RHS is a " + "bignum"); + need_generic = false; + emit_is_not_boxed(next, ARG2, dShort); + } else if (exact_type(LHS) && hasUpperBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always fails when LHS is a bignum"); + need_generic = false; + emit_is_not_boxed(resolve_beam_label(Fail), ARG1); + } else if (exact_type(LHS) && hasLowerBound(LHS) && + always_small(RHS)) { + comment("simplified test because it always succeeds when LHS is a " + "bignum"); + need_generic = false; + emit_is_not_boxed(next, ARG1, dShort); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + /* The only possible kind of immediate is a small and all other + * values are boxed, so we can test for smalls by testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_not_boxed(generic, ARG2, dShort); + } else if (always_small(RHS)) { + emit_is_not_boxed(generic, ARG1, dShort); + } else { + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + emit_is_not_boxed(generic, RET, dShort); + } + } else { + /* Relative comparisons are overwhelmingly likely to be used on + * smalls, so we'll specialize those and keep the rest in a shared + * fragment. */ + if (always_small(RHS)) { + a.mov(RETd, ARG1d); + } else if (always_small(LHS)) { + a.mov(RETd, ARG2d); + } else { + /* Avoid the expensive generic comparison for equal terms. */ + a.cmp(ARG1, ARG2); + a.short_().je(do_jl); + + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + } + + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); + } + + /* Both arguments are smalls. */ a.cmp(ARG1, ARG2); - a.short_().je(next); + if (need_generic) { + a.short_().jmp(do_jl); + } - /* Relative comparisons are overwhelmingly likely to be used on smalls, so - * we'll specialize those and keep the rest in a shared fragment. */ + a.bind(generic); + { + if (need_generic) { + safe_fragment_call(ga->get_arith_compare_shared()); + } + } - if (RHS.isImmed() && is_small(RHS.getValue())) { - a.mov(RETd, ARG1d); - } else if (LHS.isImmed() && is_small(LHS.getValue())) { - a.mov(RETd, ARG2d); + a.bind(do_jl); + a.jl(resolve_beam_label(Fail)); + + a.bind(next); +} + +/* + * ARG1 = Src + * ARG2 = Min + * ARG3 = Max + * + * Result is returned in the flags. + */ +void BeamGlobalAssembler::emit_is_in_range_shared() { + Label immediate = a.newLabel(); + Label generic_compare = a.newLabel(); + Label done = a.newLabel(); + + /* Is the source a float? */ + emit_is_boxed(immediate, ARG1); + + x86::Gp boxed_ptr = emit_ptr_val(ARG4, ARG1); + a.cmp(emit_boxed_val(boxed_ptr), imm(HEADER_FLONUM)); + a.short_().jne(generic_compare); + + /* Compare the float to the limits. */ + vmovsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); + a.sar(ARG3, imm(_TAG_IMMED1_SIZE)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vcvtsi2sd(x86::xmm1, x86::xmm1, ARG2); + a.vcvtsi2sd(x86::xmm2, x86::xmm2, ARG3); } else { + a.cvtsi2sd(x86::xmm1, ARG2); + a.cvtsi2sd(x86::xmm2, ARG3); + } + + mov_imm(RET, -1); + mov_imm(x86::rcx, 0); + vucomisd(x86::xmm0, x86::xmm2); + a.seta(x86::cl); + vucomisd(x86::xmm1, x86::xmm0); + + a.cmovbe(RET, x86::rcx); + a.cmp(RET, imm(0)); + + a.ret(); + + a.bind(immediate); + { + /* + * Src is an immediate (such as ATOM) but not SMALL. + * That means that Src must be greater than the upper + * limit. + */ + mov_imm(RET, 1); + a.cmp(RET, imm(0)); + a.ret(); + } + + a.bind(generic_compare); + { + emit_enter_runtime(); + + a.mov(TMP_MEM1q, ARG1); + a.mov(TMP_MEM2q, ARG3); + + comment("erts_cmp_compound(X, Y, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.test(RET, RET); + a.js(done); + + a.mov(ARG1, TMP_MEM1q); + a.mov(ARG2, TMP_MEM2q); + + comment("erts_cmp_compound(X, Y, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.test(RET, RET); + + a.bind(done); + emit_leave_runtime(); + + a.ret(); + } +} + +void BeamModuleAssembler::emit_is_in_range(ArgLabel const &Small, + ArgLabel const &Large, + ArgRegister const &Src, + ArgConstant const &Min, + ArgConstant const &Max) { + Label next = a.newLabel(), generic = a.newLabel(); + bool need_generic = true; + + mov_arg(ARG1, Src); + + if (always_small(Src)) { + need_generic = false; + comment("skipped test for small operand since it always small"); + } else if (always_one_of( + Src)) { + /* The only possible kind of immediate is a small and all + * other values are boxed, so we can test for smalls by + * testing boxed. */ + comment("simplified small test since all other types are boxed"); + ERTS_CT_ASSERT(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED == (1 << 0)); + if (Small == Large && never_one_of(Src)) { + /* Src is never a float and the failure labels are + * equal. Therefore, since a bignum will never be within + * the range, we can fail immediately if Src is not a + * small. */ + need_generic = false; + a.test(ARG1.r8(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + a.je(resolve_beam_label(Small)); + } else { + /* Src can be a float or the failures labels are distinct. + * We need to call the generic routine if Src is not a small. */ + a.test(ARG1.r8(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + a.short_().je(generic); + } + } else if (Small == Large) { + /* We can save one instruction if we incorporate the test for + * small into the range check. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + comment("simplified small & range tests since failure labels are " + "equal"); + a.mov(RET, ARG1); + sub(RET, Min.as().get(), ARG4); + + /* Since we have subtracted the (tagged) lower bound, the + * tag bits of the difference is 0 if and only if Src is + * a small. Testing for a tag of 0 can be done in two + * instructions. */ + a.test(RETb, imm(_TAG_IMMED1_MASK)); + a.jne(generic); + + /* Now do the range check. */ + cmp(RET, Max.as().get() - Min.as().get(), ARG4); + a.ja(resolve_beam_label(Small)); + + /* Bypass the test code. */ + goto test_done; + } else { + /* We have no applicable type information and the failure + * labels are distinct. Emit the standard test for small + * and call the generic routine if Src is not a small. */ a.mov(RETd, ARG1d); - a.and_(RETd, ARG2d); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); + } + + /* We have now established that the operand is small. */ + if (Small == Large) { + comment("simplified range test since failure labels are equal"); + sub(ARG1, Min.as().get(), RET); + cmp(ARG1, Max.as().get() - Min.as().get(), RET); + a.ja(resolve_beam_label(Small)); + } else { + cmp(ARG1, Min.as().get(), RET); + a.jl(resolve_beam_label(Small)); + cmp(ARG1, Max.as().get(), RET); + a.jg(resolve_beam_label(Large)); + } + +test_done: + if (need_generic) { + a.short_().jmp(next); } + a.bind(generic); + if (!need_generic) { + comment("skipped generic comparison because it is not needed"); + } else { + mov_arg(ARG2, Min); + mov_arg(ARG3, Max); + safe_fragment_call(ga->get_is_in_range_shared()); + if (Small == Large) { + a.jne(resolve_beam_label(Small)); + } else { + a.jl(resolve_beam_label(Small)); + a.jg(resolve_beam_label(Large)); + } + } + + a.bind(next); +} + +/* + * ARG1 = Src + * ARG2 = A + * ARG3 = B + * + * Result is returned in the flags. + */ +void BeamGlobalAssembler::emit_is_ge_lt_shared() { + Label done = a.newLabel(); + + emit_enter_runtime(); + + a.mov(TMP_MEM1q, ARG1); + a.mov(TMP_MEM2q, ARG3); + + comment("erts_cmp_compound(Src, A, 0, 0);"); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + a.test(RET, RET); + a.short_().js(done); + + comment("erts_cmp_compound(B, Src, 0, 0);"); + a.mov(ARG1, TMP_MEM2q); + a.mov(ARG2, TMP_MEM1q); + mov_imm(ARG3, 0); + mov_imm(ARG4, 0); + runtime_call<4>(erts_cmp_compound); + + /* The following instructions implements the signum function. */ + mov_imm(ARG1, -1); + mov_imm(ARG4, 1); + a.test(RET, RET); + a.cmovs(RET, ARG1); + a.cmovg(RET, ARG4); + + /* RET is now -1, 0, or 1. */ + a.add(RET, imm(1)); + + /* We now have: + * RET == 0 if B < SRC + * RET > 0 if B => SRC + * and flags set accordingly. */ + + a.bind(done); + emit_leave_runtime(); + + a.ret(); +} + +/* + * is_ge + is_lt is 20 instructions. + * + * is_ge_lt is 15 instructions. + */ +void BeamModuleAssembler::emit_is_ge_lt(ArgLabel const &Fail1, + ArgLabel const &Fail2, + ArgRegister const &Src, + ArgConstant const &A, + ArgConstant const &B) { + Label generic = a.newLabel(), next = a.newLabel(); + + mov_arg(ARG2, A); + mov_arg(ARG3, B); + mov_arg(ARG1, Src); + + a.mov(RETd, ARG1d); a.and_(RETb, imm(_TAG_IMMED1_MASK)); a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); a.short_().jne(generic); a.cmp(ARG1, ARG2); - a.short_().jge(next); - a.jmp(fail); + a.jl(resolve_beam_label(Fail1)); + a.cmp(ARG3, ARG1); + a.jge(resolve_beam_label(Fail2)); + a.short_().jmp(next); a.bind(generic); - { - safe_fragment_call(ga->get_arith_compare_shared()); - a.jl(fail); - } + safe_fragment_call(ga->get_is_ge_lt_shared()); + a.jl(resolve_beam_label(Fail1)); + a.jg(resolve_beam_label(Fail2)); a.bind(next); } -void BeamModuleAssembler::emit_bif_is_eq_ne_exact_immed(const ArgVal &Src, - const ArgVal &Immed, - const ArgVal &Dst, - Eterm fail_value, - Eterm succ_value) { - cmp_arg(getArgRef(Src), Immed); - mov_imm(RET, fail_value); - mov_imm(ARG1, succ_value); - a.cmove(RET, ARG1); - mov_arg(Dst, RET); +/* + * The optimized instruction sequence is not always shorter, + * but it ensures that Src is only read from memory once. + */ +void BeamModuleAssembler::emit_is_ge_ge(ArgLabel const &Fail1, + ArgLabel const &Fail2, + ArgRegister const &Src, + ArgConstant const &A, + ArgConstant const &B) { + if (!always_small(Src)) { + /* In practice, it is uncommon that Src is not a known small + * integer, so we will not bother optimizing that case. */ + emit_is_ge(Fail1, Src, A); + emit_is_ge(Fail2, Src, B); + return; + } + + mov_arg(RET, Src); + sub(RET, A.as().get(), ARG1); + a.jl(resolve_beam_label(Fail1)); + cmp(RET, B.as().get() - A.as().get(), ARG1); + a.jb(resolve_beam_label(Fail2)); } -void BeamModuleAssembler::emit_bif_is_eq_exact_immed(const ArgVal &Src, - const ArgVal &Immed, - const ArgVal &Dst) { - emit_bif_is_eq_ne_exact_immed(Src, Immed, Dst, am_false, am_true); +/* + * Combine is_integer with range check. + * + * is_integer + is_ge + is_ge is 31 instructions. + * + * is_int_in_range is 6 instructions. + */ +void BeamModuleAssembler::emit_is_int_in_range(ArgLabel const &Fail, + ArgRegister const &Src, + ArgConstant const &Min, + ArgConstant const &Max) { + mov_arg(RET, Src); + + sub(RET, Min.as().get(), ARG1); + + /* Since we have subtracted the (tagged) lower bound, the + * tag bits of the difference is 0 if and only if Src is + * a small. */ + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.test(RETb, imm(_TAG_IMMED1_MASK)); + a.jne(resolve_beam_label(Fail)); + cmp(RET, Max.as().get() - Min.as().get(), ARG1); + a.ja(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_bif_is_ne_exact_immed(const ArgVal &Src, - const ArgVal &Immed, - const ArgVal &Dst) { - emit_bif_is_eq_ne_exact_immed(Src, Immed, Dst, am_true, am_false); +/* + * is_integer + is_ge is 21 instructions. + * + * is_int_ge is 14 instructions. + */ +void BeamModuleAssembler::emit_is_int_ge(ArgLabel const &Fail, + ArgRegister const &Src, + ArgConstant const &Min) { + Label small = a.newLabel(); + Label fail = a.newLabel(); + Label next = a.newLabel(); + /* On Unix, using rcx instead of ARG1 makes the `test` instruction + * in the boxed test one byte shorter. */ + const x86::Gp src_reg = x86::rcx; + + mov_arg(src_reg, Src); + + if (always_one_of(Src)) { + comment("simplified small test since all other types are boxed"); + emit_is_boxed(small, Src, src_reg); + } else { + a.mov(RETd, src_reg.r32()); + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().je(small); + + emit_is_boxed(resolve_beam_label(Fail), Src, src_reg); + } + + /* Src is boxed. Jump to failure unless Src is a positive bignum. */ + x86::Gp boxed_ptr = emit_ptr_val(src_reg, src_reg); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_POS_BIG)); + a.short_().je(next); + + a.bind(fail); + a.jmp(resolve_beam_label(Fail)); + + a.bind(small); + cmp(src_reg, Min.as().get(), RET); + a.short_().jl(fail); + + a.bind(next); } -void BeamModuleAssembler::emit_badmatch(const ArgVal &Src) { +void BeamModuleAssembler::emit_badmatch(const ArgSource &Src) { mov_arg(x86::qword_ptr(c_p, offsetof(Process, fvalue)), Src); emit_error(BADMATCH); } -void BeamModuleAssembler::emit_case_end(const ArgVal &Src) { +void BeamModuleAssembler::emit_case_end(const ArgSource &Src) { mov_arg(x86::qword_ptr(c_p, offsetof(Process, fvalue)), Src); emit_error(EXC_CASE_CLAUSE); } @@ -1614,7 +2285,13 @@ void BeamModuleAssembler::emit_if_end() { emit_error(EXC_IF_CLAUSE); } -void BeamModuleAssembler::emit_catch(const ArgVal &Y, const ArgVal &Fail) { +void BeamModuleAssembler::emit_badrecord(const ArgSource &Src) { + mov_arg(x86::qword_ptr(c_p, offsetof(Process, fvalue)), Src); + emit_error(EXC_BADRECORD); +} + +void BeamModuleAssembler::emit_catch(const ArgYRegister &CatchTag, + const ArgLabel &Handler) { a.inc(x86::qword_ptr(c_p, offsetof(Process, catches))); Label patch_addr = a.newLabel(); @@ -1630,44 +2307,54 @@ void BeamModuleAssembler::emit_catch(const ArgVal &Y, const ArgVal &Fail) { * with the tagged catch */ a.bind(patch_addr); - a.mov(RETd, imm(0x7fffffff)); - - mov_arg(Y, RET); + a.mov(RETd, imm(INT_MAX)); + mov_arg(CatchTag, RET); /* Offset = 1 for `mov` payload */ - catches.push_back({{patch_addr, 0x1, 0}, labels[Fail.getValue()]}); + catches.push_back({{patch_addr, 0x1, 0}, resolve_beam_label(Handler)}); } +/* + * At entry: + * + * x0 = THE_NON_VALUE + * x1 = Term + * x2 = Stacktrace + * x3 = Exception class + */ void BeamGlobalAssembler::emit_catch_end_shared() { Label not_throw = a.newLabel(), not_error = a.newLabel(), after_gc = a.newLabel(); + emit_enter_frame(); + /* Load thrown value / reason into ARG2 for add_stacktrace */ - a.mov(ARG2, getXRef(2)); + a.mov(ARG2, getXRef(1)); - a.cmp(getXRef(1), imm(am_throw)); + a.cmp(getXRef(3), imm(am_throw)); a.short_().jne(not_throw); /* Thrown value, return it in x0 */ a.mov(getXRef(0), ARG2); + emit_leave_frame(); a.ret(); a.bind(not_throw); { - a.cmp(getXRef(1), imm(am_error)); + a.cmp(getXRef(3), imm(am_error)); /* NOTE: Short won't reach if JIT_HARD_DEBUG is defined. */ a.jne(not_error); /* This is an error, attach a stacktrace to the reason. */ - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); /* ARG2 set above. */ - a.mov(ARG3, getXRef(3)); + a.mov(ARG3, getXRef(2)); runtime_call<3>(add_stacktrace); - emit_leave_runtime(); + emit_leave_runtime(); /* not_error assumes stacktrace/reason is in ARG2 */ a.mov(ARG2, RET); @@ -1699,13 +2386,14 @@ void BeamGlobalAssembler::emit_catch_end_shared() { a.mov(getXRef(0), RET); } + emit_leave_frame(); a.ret(); } -void BeamModuleAssembler::emit_catch_end(const ArgVal &Y) { +void BeamModuleAssembler::emit_catch_end(const ArgYRegister &CatchTag) { Label next = a.newLabel(); - emit_try_end(Y); + emit_try_end(CatchTag); a.cmp(getXRef(0), imm(THE_NON_VALUE)); a.short_().jne(next); @@ -1713,18 +2401,17 @@ void BeamModuleAssembler::emit_catch_end(const ArgVal &Y) { a.bind(next); } -void BeamModuleAssembler::emit_try_end(const ArgVal &Y) { +void BeamModuleAssembler::emit_try_end(const ArgYRegister &CatchTag) { a.dec(x86::qword_ptr(c_p, offsetof(Process, catches))); - emit_init(Y); + emit_init(CatchTag); } -void BeamModuleAssembler::emit_try_case(const ArgVal &Y) { +void BeamModuleAssembler::emit_try_case(const ArgYRegister &CatchTag) { + /* The try_tag in the Y slot in the stack frame has already been + * cleared. */ a.dec(x86::qword_ptr(c_p, offsetof(Process, catches))); - mov_arg(Y, NIL); - a.movups(x86::xmm0, x86::xmmword_ptr(registers, 1 * sizeof(Eterm))); a.mov(RET, getXRef(3)); - a.movups(x86::xmmword_ptr(registers, 0 * sizeof(Eterm)), x86::xmm0); - a.mov(getXRef(2), RET); + a.mov(getXRef(0), RET); #ifdef DEBUG Label fvalue_ok = a.newLabel(), assertion_failed = a.newLabel(); @@ -1742,12 +2429,13 @@ void BeamModuleAssembler::emit_try_case(const ArgVal &Y) { #endif } -void BeamModuleAssembler::emit_try_case_end(const ArgVal &Src) { +void BeamModuleAssembler::emit_try_case_end(const ArgSource &Src) { mov_arg(x86::qword_ptr(c_p, offsetof(Process, fvalue)), Src); emit_error(EXC_TRY_CLAUSE); } -void BeamModuleAssembler::emit_raise(const ArgVal &Trace, const ArgVal &Value) { +void BeamModuleAssembler::emit_raise(const ArgSource &Trace, + const ArgSource &Value) { mov_arg(ARG3, Value); mov_arg(ARG2, Trace); @@ -1762,17 +2450,17 @@ void BeamModuleAssembler::emit_raise(const ArgVal &Trace, const ArgVal &Value) { emit_leave_runtime(); - emit_handle_error(); + emit_raise_exception(); } void BeamModuleAssembler::emit_build_stacktrace() { - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); a.mov(ARG2, getXRef(0)); runtime_call<2>(build_stacktrace); - emit_leave_runtime(); + emit_leave_runtime(); a.mov(getXRef(0), RET); } @@ -1792,49 +2480,62 @@ void BeamModuleAssembler::emit_raw_raise() { a.test(RET, RET); a.short_().jne(next); - emit_handle_error(); + emit_raise_exception(); a.bind(next); a.mov(getXRef(0), imm(am_badarg)); } +#define TEST_YIELD_RETURN_OFFSET \ + (BEAM_ASM_FUNC_PROLOGUE_SIZE + 16 + \ + (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA ? 4 : 0)) + +/* ARG3 = return address, current_label + TEST_YIELD_RETURN_OFFSET */ void BeamGlobalAssembler::emit_i_test_yield_shared() { - int mfa_offset = -(int)sizeof(ErtsCodeMFA) - BEAM_ASM_FUNC_PROLOGUE_SIZE; + int mfa_offset = -TEST_YIELD_RETURN_OFFSET - (int)sizeof(ErtsCodeMFA); - /* Yield address is in ARG3. */ a.lea(ARG2, x86::qword_ptr(ARG3, mfa_offset)); a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG2); a.mov(ARG2, x86::qword_ptr(ARG2, offsetof(ErtsCodeMFA, arity))); a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), ARG2); - emit_discard_cp(); - a.jmp(labels[context_switch_simplified]); } void BeamModuleAssembler::emit_i_test_yield() { - Label next = a.newLabel(), entry = a.newLabel(); - /* When present, this is guaranteed to be the first instruction after the * breakpoint trampoline. */ + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + BEAM_ASM_FUNC_PROLOGUE_SIZE); - ASSERT(a.offset() % 8 == 0); - a.bind(entry); + emit_enter_frame(); + + a.lea(ARG3, x86::qword_ptr(current_label, TEST_YIELD_RETURN_OFFSET)); a.dec(FCALLS); - a.short_().jg(next); - a.lea(ARG3, x86::qword_ptr(entry)); - a.call(funcYield); - a.bind(next); + a.long_().jle(resolve_fragment(ga->get_i_test_yield_shared())); + + ASSERT((a.offset() - code.labelOffsetFromBase(current_label)) == + TEST_YIELD_RETURN_OFFSET); + +#if defined(JIT_HARD_DEBUG) && defined(ERLANG_FRAME_POINTERS) + a.mov(ARG1, c_p); + a.mov(ARG2, x86::rbp); + a.mov(ARG3, x86::rsp); + + emit_enter_runtime(); + runtime_call<3>(erts_validate_stack); + emit_leave_runtime(); +#endif } void BeamModuleAssembler::emit_i_yield() { a.mov(getXRef(0), imm(am_true)); #ifdef NATIVE_ERLANG_STACK - fragment_call(ga->get_dispatch_return()); + fragment_call(resolve_fragment(ga->get_dispatch_return())); #else Label next = a.newLabel(); a.lea(ARG3, x86::qword_ptr(next)); - abs_jmp(ga->get_dispatch_return()); + a.jmp(resolve_fragment(ga->get_dispatch_return())); a.align(AlignMode::kCode, 8); a.bind(next); @@ -1864,9 +2565,9 @@ void BeamModuleAssembler::emit_i_perf_counter() { { a.mov(TMP_MEM1q, RET); - emit_gc_test(ArgVal(ArgVal::i, 0), - ArgVal(ArgVal::i, ERTS_MAX_UINT64_HEAP_SIZE), - ArgVal(ArgVal::i, 0)); + emit_gc_test(ArgWord(0), + ArgWord(ERTS_MAX_UINT64_HEAP_SIZE), + ArgWord(0)); a.mov(ARG1, TMP_MEM1q); diff --git a/erts/emulator/beam/jit/x86/instr_float.cpp b/erts/emulator/beam/jit/x86/instr_float.cpp index 24b5d3908ebe..97ea29f940f8 100644 --- a/erts/emulator/beam/jit/x86/instr_float.cpp +++ b/erts/emulator/beam/jit/x86/instr_float.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -25,21 +25,77 @@ extern "C" #include "big.h" } -void BeamModuleAssembler::emit_fload(const ArgVal &Src, const ArgVal &Dst) { +/* Fixes a silly compilation error on Windows, where the following macro + * prevents us from using `std::numeric_limits::max()` */ +#ifdef max +# undef max +#endif + +void BeamGlobalAssembler::emit_check_float_error() { + Label error = a.newLabel(), floatMax = a.newLabel(), + floatSignMask = a.newLabel(); + + vmovsd(x86::xmm1, x86::qword_ptr(floatMax)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vandpd(x86::xmm2, x86::xmm0, x86::xmmword_ptr(floatSignMask)); + } else { + a.movq(x86::xmm2, x86::xmm0); + a.andpd(x86::xmm2, x86::xmmword_ptr(floatSignMask)); + } + vucomisd(x86::xmm1, x86::xmm2); + a.short_().jb(error); + a.ret(); + + a.bind(error); + { + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), + imm(EXC_BADARITH)); + a.sub(ARG4, ARG4); + a.jmp(labels[raise_exception]); + } + + a.align(AlignMode::kCode, 16); + a.bind(floatSignMask); + a.embedUInt64(0x7FFFFFFFFFFFFFFFul); + a.bind(floatMax); + a.embedDouble(std::numeric_limits::max()); +} + +void BeamModuleAssembler::emit_float_instr(uint32_t instIdSSE, + uint32_t instIdAVX, + const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + vmovsd(x86::xmm0, getArgRef(LHS)); + vmovsd(x86::xmm1, getArgRef(RHS)); + + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.emit(instIdAVX, x86::xmm0, x86::xmm0, x86::xmm1); + } else { + a.emit(instIdSSE, x86::xmm0, x86::xmm1); + } + safe_fragment_call(ga->get_check_float_error()); + vmovsd(getArgRef(Dst), x86::xmm0); +} + +void BeamModuleAssembler::emit_fload(const ArgSource &Src, + const ArgFRegister &Dst) { /* {thing_word,double} */ mov_arg(ARG1, Src); x86::Gp boxed_ptr = emit_ptr_val(ARG1, ARG1); - a.mov(ARG1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); - a.mov(getArgRef(Dst), ARG1); + + vmovsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + vmovsd(getArgRef(Dst), x86::xmm0); } -void BeamModuleAssembler::emit_fstore(const ArgVal &Src, const ArgVal &Dst) { - a.mov(ARG1, getArgRef(Src)); +void BeamModuleAssembler::emit_fstore(const ArgFRegister &Src, + const ArgRegister &Dst) { + vmovsd(x86::xmm0, getArgRef(Src)); /* {thing_word,double} */ a.mov(x86::qword_ptr(HTOP), imm(HEADER_FLONUM)); - a.mov(x86::qword_ptr(HTOP, sizeof(Eterm)), ARG1); + vmovsd(x86::qword_ptr(HTOP, sizeof(Eterm)), x86::xmm0); a.lea(ARG1, x86::qword_ptr(HTOP, make_float(0))); mov_arg(Dst, ARG1); @@ -47,122 +103,140 @@ void BeamModuleAssembler::emit_fstore(const ArgVal &Src, const ArgVal &Dst) { a.add(HTOP, imm(FLOAT_SIZE_OBJECT * sizeof(Eterm))); } -static int handle_fconv(Eterm src, double *dst) { - if (is_small(src)) { - *dst = (double)signed_val(src); - } else if (is_float(src)) { - GET_DOUBLE(src, *(FloatDef *)dst); - } else if (is_big(src)) { - if (big_to_double(src, dst) < 0) { - return 1; - } - } else { - return 1; - } +/* ARG2 = source term */ +void BeamGlobalAssembler::emit_fconv_shared() { + Label error = a.newLabel(); - return 0; -} + /* big_to_double expects source in ARG1 */ + a.mov(ARG1, ARG2); -void BeamModuleAssembler::emit_fconv(const ArgVal &Src, const ArgVal &Dst) { - Label next = a.newLabel(); + emit_is_boxed(error, ARG2, dShort); - mov_arg(ARG1, Src); - a.lea(ARG2, getArgRef(Dst)); + auto boxed_ptr = emit_ptr_val(ARG2, ARG2); + a.mov(ARG2, emit_boxed_val(boxed_ptr)); + a.and_(ARG2, imm(_TAG_HEADER_MASK - _BIG_SIGN_BIT)); + a.cmp(ARG2, imm(_TAG_HEADER_POS_BIG)); + a.short_().jne(error); + emit_enter_frame(); emit_enter_runtime(); - runtime_call<2>(handle_fconv); + /* ARG1 already contains the source term. */ + a.lea(ARG2, TMP_MEM1q); + runtime_call<2>(big_to_double); emit_leave_runtime(); + emit_leave_frame(); - a.test(RET, RET); - a.short_().je(next); - - emit_error(EXC_BADARITH); - - a.bind(next); -} + a.test(RETd, RETd); + a.short_().js(error); -void BeamModuleAssembler::emit_check_float(Label next, x86::Xmm value) { - a.movsd(x86::xmm2, value); - a.movsd(x86::xmm1, x86::qword_ptr(floatMax)); - a.andpd(x86::xmm2, x86::xmmword_ptr(floatSignMask)); - a.ucomisd(x86::xmm1, x86::xmm2); - a.short_().jnb(next); + vmovsd(x86::xmm0, TMP_MEM1q); + a.ret(); - emit_error(EXC_BADARITH); + a.bind(error); + { + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), + imm(EXC_BADARITH)); + a.sub(ARG4, ARG4); + a.jmp(labels[raise_exception]); + } } -void BeamModuleAssembler::emit_i_fadd(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label next = a.newLabel(); - - a.movsd(x86::xmm0, getArgRef(LHS)); - a.movsd(x86::xmm1, getArgRef(RHS)); - a.addpd(x86::xmm0, x86::xmm1); +void BeamModuleAssembler::emit_fconv(const ArgSource &Src, + const ArgFRegister &Dst) { + if (always_small(Src)) { + comment("simplified fconv since source is always small"); + mov_arg(ARG2, Src); + a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vcvtsi2sd(x86::xmm0, x86::xmm0, ARG2); + } else { + a.cvtsi2sd(x86::xmm0, ARG2); + } + vmovsd(getArgRef(Dst), x86::xmm0); + return; + } - emit_check_float(next, x86::xmm0); + Label next = a.newLabel(), not_small = a.newLabel(), + fallback = a.newLabel(); - a.bind(next); - a.movsd(getArgRef(Dst), x86::xmm0); -} + mov_arg(ARG2, Src); -void BeamModuleAssembler::emit_i_fsub(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label next = a.newLabel(); + emit_is_small(not_small, Src, ARG2); - a.movsd(x86::xmm0, getArgRef(LHS)); - a.movsd(x86::xmm1, getArgRef(RHS)); - a.subpd(x86::xmm0, x86::xmm1); + a.sar(ARG2, imm(_TAG_IMMED1_SIZE)); + if (hasCpuFeature(CpuFeatures::X86::kAVX)) { + a.vcvtsi2sd(x86::xmm0, x86::xmm0, ARG2); + } else { + a.cvtsi2sd(x86::xmm0, ARG2); + } + a.short_().jmp(next); + + a.bind(not_small); + { + if (never_one_of(Src)) { + comment("skipped float path since source cannot be a float"); + } else { + /* If the source is always a number, we can skip the box test when + * it's not a small. */ + if (always_one_of(Src)) { + comment("skipped box test since source is always a number"); + } else { + emit_is_boxed(fallback, Src, ARG2, dShort); + } + + /* Speculatively load the float value, this is safe since all boxed + * terms are at least two words long. */ + auto boxed_ptr = emit_ptr_val(ARG1, ARG2); + vmovsd(x86::xmm0, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + + a.cmp(emit_boxed_val(boxed_ptr), imm(HEADER_FLONUM)); + a.short_().je(next); + } - emit_check_float(next, x86::xmm0); + /* Bignum or invalid input, handle it in a shared fragment. */ + a.bind(fallback); + safe_fragment_call(ga->get_fconv_shared()); + } a.bind(next); - a.movsd(getArgRef(Dst), x86::xmm0); + vmovsd(getArgRef(Dst), x86::xmm0); } -void BeamModuleAssembler::emit_i_fmul(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label next = a.newLabel(); - - a.movsd(x86::xmm0, getArgRef(LHS)); - a.movsd(x86::xmm1, getArgRef(RHS)); - a.mulpd(x86::xmm0, x86::xmm1); - - emit_check_float(next, x86::xmm0); - - a.bind(next); - a.movsd(getArgRef(Dst), x86::xmm0); +void BeamModuleAssembler::emit_i_fadd(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(x86::Inst::kIdAddpd, x86::Inst::kIdVaddpd, LHS, RHS, Dst); } -void BeamModuleAssembler::emit_i_fdiv(const ArgVal &LHS, - const ArgVal &RHS, - const ArgVal &Dst) { - Label next = a.newLabel(); - - a.movsd(x86::xmm0, getArgRef(LHS)); - a.movsd(x86::xmm1, getArgRef(RHS)); - a.divpd(x86::xmm0, x86::xmm1); - - emit_check_float(next, x86::xmm0); - - a.bind(next); - a.movsd(getArgRef(Dst), x86::xmm0); +void BeamModuleAssembler::emit_i_fsub(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(x86::Inst::kIdSubpd, x86::Inst::kIdVsubpd, LHS, RHS, Dst); } -void BeamModuleAssembler::emit_i_fnegate(const ArgVal &Src, const ArgVal &Dst) { - Label next = a.newLabel(); - - /* xmm0 = 0.0 */ - a.pxor(x86::xmm0, x86::xmm0); - a.movsd(x86::xmm1, getArgRef(Src)); - a.subpd(x86::xmm0, x86::xmm1); +void BeamModuleAssembler::emit_i_fmul(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(x86::Inst::kIdMulpd, x86::Inst::kIdVmulpd, LHS, RHS, Dst); +} - emit_check_float(next, x86::xmm0); +void BeamModuleAssembler::emit_i_fdiv(const ArgFRegister &LHS, + const ArgFRegister &RHS, + const ArgFRegister &Dst) { + emit_float_instr(x86::Inst::kIdDivpd, x86::Inst::kIdVdivpd, LHS, RHS, Dst); +} - a.bind(next); - a.movsd(getArgRef(Dst), x86::xmm0); +void BeamModuleAssembler::emit_i_fnegate(const ArgFRegister &Src, + const ArgFRegister &Dst) { + /* Note that there is no need to check for errors since flipping the sign + * of a finite float is guaranteed to produce a finite float. */ + if (Src != Dst) { + mov_arg(RET, Src); + a.btc(RET, imm(63)); + mov_arg(Dst, RET); + } else { + a.btc(getArgRef(Dst), 63); + } } diff --git a/erts/emulator/beam/jit/x86/instr_fun.cpp b/erts/emulator/beam/jit/x86/instr_fun.cpp new file mode 100644 index 000000000000..903ecef49b8d --- /dev/null +++ b/erts/emulator/beam/jit/x86/instr_fun.cpp @@ -0,0 +1,441 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021-2023. 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% + */ + +#include "beam_asm.hpp" + +/* Calls to functions that are being purged (but haven't finished) land here. + * + * ARG3 = arity + * ARG4 = fun thing + * ARG5 = current PC */ +void BeamGlobalAssembler::emit_unloaded_fun() { + Label error = a.newLabel(); + + emit_enter_frame(); + + a.mov(TMP_MEM1q, ARG5); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + /* ARG3 and ARG4 have already been set. */ + runtime_call<4>(beam_jit_handle_unloaded_fun); + + emit_leave_runtime(); + + a.test(RET, RET); + a.jz(error); + + emit_leave_frame(); + a.jmp(emit_setup_dispatchable_call(RET)); + + a.bind(error); + { + /* The `raise_exception` fragment expects that the PC is on the + * stack. */ + a.push(TMP_MEM1q); + mov_imm(ARG4, nullptr); + a.jmp(labels[raise_exception]); + } +} + +/* Handles errors for `call_fun`. + * + * ARG3 = arity + * ARG4 = fun thing + * ARG5 = current PC */ +void BeamGlobalAssembler::emit_handle_call_fun_error() { + Label bad_arity = a.newLabel(), bad_fun = a.newLabel(); + + emit_enter_frame(); + + emit_is_boxed(bad_fun, ARG4); + + x86::Gp fun_thing = emit_ptr_val(RET, ARG4); + a.cmp(emit_boxed_val(fun_thing), imm(HEADER_FUN)); + a.short_().je(bad_arity); + + a.bind(bad_fun); + { + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(EXC_BADFUN)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), ARG4); + + /* The `raise_exception` fragment expects that the PC is on the + * stack. */ + a.push(ARG5); + mov_imm(ARG4, nullptr); + a.jmp(labels[raise_exception]); + } + + a.bind(bad_arity); + { + /* Stash our fun and current PC. Note that we don't move the fun to + * {x,0} straight away as that would clobber the first argument. */ + a.mov(TMP_MEM1q, ARG4); + a.mov(TMP_MEM2q, ARG5); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + /* ARG3 is already set. */ + runtime_call<3>(beam_jit_build_argument_list); + + emit_leave_runtime(); + + a.mov(ARG1, TMP_MEM1q); + a.mov(getXRef(0), ARG1); + a.mov(getXRef(1), RET); + + /* Create the {Fun, Args} tuple. */ + { + const int32_t bytes_needed = (3 + S_RESERVED) * sizeof(Eterm); + Label after_gc = a.newLabel(); + + a.lea(ARG3, x86::qword_ptr(HTOP, bytes_needed)); + a.cmp(ARG3, E); + a.short_().jbe(after_gc); + { + mov_imm(ARG4, 2); + aligned_call(labels[garbage_collect]); + } + a.bind(after_gc); + + a.mov(ARG1, getXRef(0)); + a.mov(ARG2, getXRef(1)); + + a.mov(x86::qword_ptr(HTOP), imm(make_arityval(2))); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm[1])), ARG1); + a.mov(x86::qword_ptr(HTOP, sizeof(Eterm[2])), ARG2); + + a.lea(ARG1, x86::qword_ptr(HTOP, TAG_PRIMARY_BOXED)); + a.add(HTOP, imm(sizeof(Eterm[3]))); + } + + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), + imm(EXC_BADARITY)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), ARG1); + + /* The `raise_exception` fragment expects that the PC is on the + * stack. */ + a.push(TMP_MEM2q); + mov_imm(ARG4, nullptr); + a.jmp(labels[raise_exception]); + } +} + +/* Handles save_calls for local funs, which is a side-effect of our calling + * convention. Fun entry is in RET. + * + * When the active code index is ERTS_SAVE_CALLS_CODE_IX, all local fun calls + * will land here. */ +void BeamGlobalAssembler::emit_dispatch_save_calls_fun() { + /* Keep going with the actual code index. */ + a.mov(ARG1, imm(&the_active_code_index)); + a.mov(ARG1d, x86::dword_ptr(ARG1)); + + a.jmp(emit_setup_dispatchable_call(RET, ARG1)); +} + +/* `call_fun` instructions land here to set up their environment before jumping + * to the actual implementation. + * + * Keep in mind that this runs in the limbo between caller and callee, so we + * must not enter a frame here. + * + * ARG4 = fun thing */ +void BeamModuleAssembler::emit_i_lambda_trampoline(const ArgLambda &Lambda, + const ArgLabel &Lbl, + const ArgWord &Arity, + const ArgWord &NumFree) { + const ssize_t effective_arity = Arity.get() - NumFree.get(); + const ssize_t num_free = NumFree.get(); + + const auto &lambda = lambdas[Lambda.get()]; + a.bind(lambda.trampoline); + + emit_ptr_val(ARG4, ARG4); + + ASSERT(num_free > 0); + emit_copy_words(emit_boxed_val(ARG4, offsetof(ErlFunThing, env)), + getXRef(effective_arity), + num_free, + RET); + + a.jmp(resolve_beam_label(Lbl)); +} + +void BeamModuleAssembler::emit_i_make_fun3(const ArgLambda &Lambda, + const ArgRegister &Dst, + const ArgWord &Arity, + const ArgWord &NumFree, + const Span &env) { + size_t num_free = env.size(); + + ASSERT(NumFree.get() == num_free); + + mov_arg(ARG2, Lambda); + mov_arg(ARG3, Arity); + mov_arg(ARG4, NumFree); + + emit_enter_runtime(); + + a.mov(ARG1, c_p); + runtime_call<4>(erts_new_local_fun_thing); + + emit_leave_runtime(); + + comment("Move fun environment"); + for (unsigned i = 0; i < num_free; i++) { + mov_arg(x86::qword_ptr(RET, + offsetof(ErlFunThing, env) + i * sizeof(Eterm)), + env[i]); + } + + comment("Create boxed ptr"); + a.or_(RETb, TAG_PRIMARY_BOXED); + mov_arg(Dst, RET); +} + +/* Unwraps `apply_fun` so we can share the rest of the implementation with + * `call_fun`. */ +void BeamGlobalAssembler::emit_apply_fun_shared() { + Label finished = a.newLabel(); + + emit_enter_frame(); + + /* Put the arity and fun into the right registers for `call_fun`, and stash + * the argument list in ARG5 for the error path. We'll bump the arity as + * we go through the argument list. */ + mov_imm(ARG3, 0); + a.mov(ARG4, getXRef(0)); + a.mov(ARG5, getXRef(1)); + + { + Label unpack_next = a.newLabel(), malformed_list = a.newLabel(), + raise_error = a.newLabel(); + + auto x_register = getXRef(0); + + ASSERT(x_register.shift() == 0); + x_register.setIndex(ARG3); + x_register.setShift(3); + + a.mov(ARG1, ARG5); + a.bind(unpack_next); + { + a.cmp(ARG1d, imm(NIL)); + a.short_().je(finished); + + a.test(ARG1.r8(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); + a.short_().jne(malformed_list); + + emit_ptr_val(ARG1, ARG1); + a.mov(RET, getCARRef(ARG1)); + a.mov(ARG1, getCDRRef(ARG1)); + a.mov(x_register, RET); + + a.inc(ARG3); + + /* We bail at MAX_REG-1 rather than MAX_REG as the highest register + * is reserved for the loader. */ + a.cmp(ARG3, imm(MAX_REG - 1)); + a.jb(unpack_next); + } + + a.mov(RET, imm(SYSTEM_LIMIT)); + a.jmp(raise_error); + + a.bind(malformed_list); + a.mov(RET, imm(BADARG)); + + a.bind(raise_error); + { + static const ErtsCodeMFA apply_mfa = {am_erlang, am_apply, 2}; + + a.mov(getXRef(0), ARG4); + a.mov(getXRef(1), ARG5); + + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), RET); + mov_imm(ARG4, &apply_mfa); + + emit_leave_frame(); + a.jmp(labels[raise_exception]); + } + } + + a.bind(finished); + + emit_leave_frame(); + a.ret(); +} + +void BeamModuleAssembler::emit_i_apply_fun() { + safe_fragment_call(ga->get_apply_fun_shared()); + + x86::Gp target = emit_call_fun(); + ASSERT(target != ARG6); + erlang_call(target, ARG6); +} + +void BeamModuleAssembler::emit_i_apply_fun_last(const ArgWord &Deallocate) { + emit_deallocate(Deallocate); + emit_i_apply_fun_only(); +} + +void BeamModuleAssembler::emit_i_apply_fun_only() { + safe_fragment_call(ga->get_apply_fun_shared()); + + x86::Gp target = emit_call_fun(); + emit_leave_frame(); + a.jmp(target); +} + +/* Assumes that: + * ARG3 = arity + * ARG4 = fun thing */ +x86::Gp BeamModuleAssembler::emit_call_fun(bool skip_box_test, + bool skip_fun_test, + bool skip_arity_test) { + const bool never_fails = skip_box_test && skip_fun_test && skip_arity_test; + Label next = a.newLabel(); + + /* Speculatively strip the literal tag when needed. */ + x86::Gp fun_thing = emit_ptr_val(RET, ARG4); + + if (!never_fails) { + /* Load the error fragment into ARG2 so we can CMOV ourselves there on + * error. */ + a.mov(ARG2, ga->get_handle_call_fun_error()); + } + + /* The `handle_call_fun_error` and `unloaded_fun` fragments expect current + * PC in ARG5. */ + a.lea(ARG5, x86::qword_ptr(next)); + + if (!skip_box_test) { + /* As emit_is_boxed(), but explicitly sets ZF so we can rely on that + * for error checking in `next`. */ + a.test(ARG4d, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_BOXED)); + a.short_().jne(next); + } else { + comment("skipped box test since source is always boxed"); + } + + if (skip_fun_test) { + comment("skipped fun test since source is always a fun when boxed"); + } else { + a.cmp(emit_boxed_val(fun_thing), imm(HEADER_FUN)); + a.short_().jne(next); + } + + if (skip_arity_test) { + comment("skipped arity test since source always has right arity"); + } else { + a.cmp(emit_boxed_val(fun_thing, + offsetof(ErlFunThing, arity), + sizeof(byte)), + ARG3.r8()); + } + + a.mov(RET, emit_boxed_val(fun_thing, offsetof(ErlFunThing, entry))); + a.mov(ARG1, emit_setup_dispatchable_call(RET)); + + a.bind(next); + + if (!never_fails) { + /* Assumes that ZF is set on success and clear on error, overwriting + * our destination with the error fragment's address. */ + a.cmovne(ARG1, ARG2); + } + + return ARG1; +} + +void BeamModuleAssembler::emit_i_call_fun2(const ArgVal &Tag, + const ArgWord &Arity, + const ArgRegister &Func) { + mov_arg(ARG4, Func); + + if (Tag.isImmed()) { + mov_imm(ARG3, Arity.get()); + + auto target = emit_call_fun( + always_one_of(Func), + masked_types(Func) == BeamTypeId::Fun, + Tag.as().get() == am_safe); + + erlang_call(target, ARG6); + } else { + const auto &trampoline = lambdas[Tag.as().get()].trampoline; + erlang_call(trampoline, RET); + } +} + +void BeamModuleAssembler::emit_i_call_fun2_last(const ArgVal &Tag, + const ArgWord &Arity, + const ArgRegister &Func, + const ArgWord &Deallocate) { + mov_arg(ARG4, Func); + + if (Tag.isImmed()) { + mov_imm(ARG3, Arity.get()); + + auto target = emit_call_fun( + always_one_of(Func), + masked_types(Func) == BeamTypeId::Fun, + Tag.as().get() == am_safe); + + emit_deallocate(Deallocate); + emit_leave_frame(); + + a.jmp(target); + } else { + const auto &trampoline = lambdas[Tag.as().get()].trampoline; + + emit_deallocate(Deallocate); + emit_leave_frame(); + + a.jmp(trampoline); + } +} + +void BeamModuleAssembler::emit_i_call_fun(const ArgWord &Arity) { + const ArgXRegister Func(Arity.get()); + const ArgAtom Tag(am_unsafe); + + emit_i_call_fun2(Tag, Arity, Func); +} + +void BeamModuleAssembler::emit_i_call_fun_last(const ArgWord &Arity, + const ArgWord &Deallocate) { + const ArgXRegister Func(Arity.get()); + const ArgAtom Tag(am_unsafe); + + emit_i_call_fun2_last(Tag, Arity, Func, Deallocate); +} + +/* Psuedo-instruction for signalling lambda load errors. Never actually runs. */ +void BeamModuleAssembler::emit_i_lambda_error(const ArgWord &Dummy) { + comment("lambda error"); + a.ud2(); +} diff --git a/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp b/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp index f952898c0e22..de243a45e6b6 100644 --- a/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp +++ b/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -19,6 +19,7 @@ */ #include +#include #include "beam_asm.hpp" extern "C" @@ -28,59 +29,285 @@ extern "C" #include "beam_catches.h" #include "beam_common.h" #include "code_ix.h" +#include "erl_map.h" } using namespace asmjit; -/* - * We considered specializing tuple_size/1, but ultimately didn't - * consider it worth doing. - * - * At the time of writing, there were 294 uses of tuple_size/1 - * in the OTP source code. (11 of them were in dialyzer.) - * - * The code size for the specialization was 34 bytes, - * while the code size for the bif1 instruction was 24 bytes. +/* ================================================================ + * '=:='/2 + * '=/='/2 + * '>='/2 + * '<'/2 + * ================================================================ */ -void BeamGlobalAssembler::emit_handle_hd_error() { - static ErtsCodeMFA mfa = {am_erlang, am_hd, 1}; +void BeamModuleAssembler::emit_bif_is_eq_ne_exact(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst, + Eterm fail_value, + Eterm succ_value) { + /* `mov_imm` may clobber the flags if either value is zero. */ + ASSERT(fail_value && succ_value); - a.mov(getXRef(0), RET); - a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADARG)); - a.mov(ARG4, imm(&mfa)); - a.jmp(labels[handle_error_shared_prologue]); + cmp_arg(getArgRef(LHS), RHS); + mov_imm(RET, succ_value); + + if (always_immediate(LHS) || always_immediate(RHS)) { + if (!LHS.isImmed() && !RHS.isImmed()) { + comment("simplified check since one argument is an immediate"); + } + mov_imm(ARG1, fail_value); + a.cmovne(RET, ARG1); + } else { + Label next = a.newLabel(); + + a.je(next); + + mov_arg(ARG1, LHS); + mov_arg(ARG2, RHS); + + emit_enter_runtime(); + runtime_call<2>(eq); + emit_leave_runtime(); + + a.test(RET, RET); + + mov_imm(RET, succ_value); + mov_imm(ARG1, fail_value); + a.cmove(RET, ARG1); + + a.bind(next); + } + + mov_arg(Dst, RET); } -/* - * At the time of implementation, there were 3285 uses of hd/1 in - * the OTP source code. Most of them were in code generated by - * yecc. - * - * The code size for this specialization of hd/1 is 21 bytes, - * while the code size for the bif1 instruction is 24 bytes. +void BeamModuleAssembler::emit_bif_is_eq_exact(const ArgRegister &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_is_eq_ne_exact(LHS, RHS, Dst, am_false, am_true); +} + +void BeamModuleAssembler::emit_bif_is_ne_exact(const ArgRegister &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_is_eq_ne_exact(LHS, RHS, Dst, am_true, am_false); +} + +void BeamModuleAssembler::emit_cond_to_bool(uint32_t instId, + const ArgRegister &Dst) { + mov_imm(RET, am_true); + mov_imm(ARG1, am_false); + a.emit(instId, RET, ARG1); + mov_arg(Dst, RET); +} + +void BeamModuleAssembler::emit_bif_is_ge_lt(uint32_t instId, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + Label generic = a.newLabel(), make_boolean = a.newLabel(); + + mov_arg(ARG2, RHS); /* May clobber ARG1 */ + mov_arg(ARG1, LHS); + + if (always_one_of(LHS) && + always_one_of(RHS)) { + /* The only possible kind of immediate is a small and all other + * values are boxed, so we can test for smalls by testing boxed. */ + comment("simplified small test since all other types are boxed"); + if (always_small(LHS)) { + emit_is_not_boxed(generic, ARG2, dShort); + } else if (always_small(RHS)) { + emit_is_not_boxed(generic, ARG1, dShort); + } else { + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + emit_is_not_boxed(generic, RET, dShort); + } + } else { + /* Relative comparisons are overwhelmingly likely to be used on + * smalls, so we'll specialize those and keep the rest in a shared + * fragment. */ + if (always_small(RHS)) { + a.mov(RETd, ARG1d); + } else if (always_small(LHS)) { + a.mov(RETd, ARG2d); + } else { + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + } + + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); + } + + /* Both arguments are smalls. */ + a.cmp(ARG1, ARG2); + a.short_().jmp(make_boolean); + + a.bind(generic); + { + a.cmp(ARG1, ARG2); + a.short_().je(make_boolean); + safe_fragment_call(ga->get_arith_compare_shared()); + } + + a.bind(make_boolean); + emit_cond_to_bool(instId, Dst); +} + +void BeamModuleAssembler::emit_bif_is_ge(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + bool both_small = always_small(LHS) && always_small(RHS); + + if (both_small && LHS.isRegister() && RHS.isImmed() && + Support::isInt32(RHS.as().get())) { + comment("simplified compare because one operand is an immediate small"); + a.cmp(getArgRef(LHS.as()), imm(RHS.as().get())); + emit_cond_to_bool(x86::Inst::kIdCmovl, Dst); + + return; + } else if (both_small && RHS.isRegister() && LHS.isImmed() && + Support::isInt32(LHS.as().get())) { + comment("simplified compare because one operand is an immediate small"); + a.cmp(getArgRef(RHS.as()), imm(LHS.as().get())); + emit_cond_to_bool(x86::Inst::kIdCmovg, Dst); + + return; + } + + emit_bif_is_ge_lt(x86::Inst::kIdCmovl, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_bif_is_lt(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_is_ge_lt(x86::Inst::kIdCmovge, LHS, RHS, Dst); +} + +/* ================================================================ + * bit_size/1 + * ================================================================ */ -void BeamModuleAssembler::emit_bif_hd(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Hd) { - mov_arg(RET, Src); - a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - Uint fail = Fail.getValue(); - if (fail) { - a.jne(labels[fail]); +void BeamModuleAssembler::emit_bif_bit_size(const ArgWord &Bif, + const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + if (!exact_type(Src)) { + /* Unknown type. Use the standard BIF instruction. */ + emit_i_bif1(Src, Fail, Bif, Dst); + return; + } + + mov_arg(ARG2, Src); + + auto unit = getSizeUnit(Src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG2); + + if (is_bitstring) { + comment("inlined bit_size/1 because " + "its argument is a bitstring"); } else { - Label next = a.newLabel(); - a.short_().je(next); - safe_fragment_call(ga->get_handle_hd_error()); - a.bind(next); + comment("inlined and simplified bit_size/1 because " + "its argument is a binary"); + } + + if (is_bitstring) { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + } + + a.mov(ARG1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.shl(ARG1, imm(3 + _TAG_IMMED1_SIZE)); + + if (is_bitstring) { + Label not_sub_bin = a.newLabel(); + const auto diff_mask = _TAG_HEADER_SUB_BIN - _TAG_HEADER_REFC_BIN; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & diff_mask) != 0 && + (_TAG_HEADER_REFC_BIN & diff_mask) == 0 && + (_TAG_HEADER_HEAP_BIN & diff_mask) == 0); + a.test(RETb, imm(diff_mask)); + a.short_().jz(not_sub_bin); + + a.mov(RETb, emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize), 1)); + a.shl(RETb, imm(_TAG_IMMED1_SIZE)); + a.add(ARG1.r8(), RETb); + + a.bind(not_sub_bin); + } + + a.or_(ARG1, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, ARG1); +} + +/* ================================================================ + * byte_size/1 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_byte_size(const ArgWord &Bif, + const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + if (!exact_type(Src)) { + /* Unknown type. Use the standard BIF instruction. */ + emit_i_bif1(Src, Fail, Bif, Dst); + return; + } + + mov_arg(ARG2, Src); + + auto unit = getSizeUnit(Src); + bool is_bitstring = unit == 0 || std::gcd(unit, 8) != 8; + x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG2); + + if (is_bitstring) { + comment("inlined byte_size/1 because " + "its argument is a bitstring"); + } else { + comment("inlined and simplified byte_size/1 because " + "its argument is a binary"); } - x86::Gp boxed_ptr = emit_ptr_val(RET, RET); - a.mov(ARG2, getCARRef(boxed_ptr)); - mov_arg(Hd, ARG2); + if (is_bitstring) { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + } + + a.mov(ARG1, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + + if (is_bitstring) { + Label not_sub_bin = a.newLabel(); + const auto diff_mask = _TAG_HEADER_SUB_BIN - _TAG_HEADER_REFC_BIN; + ERTS_CT_ASSERT((_TAG_HEADER_SUB_BIN & diff_mask) != 0 && + (_TAG_HEADER_REFC_BIN & diff_mask) == 0 && + (_TAG_HEADER_HEAP_BIN & diff_mask) == 0); + a.test(RETb, imm(diff_mask)); + a.short_().jz(not_sub_bin); + + a.mov(RETb, emit_boxed_val(boxed_ptr, offsetof(ErlSubBin, bitsize), 1)); + a.test(RETb, RETb); + a.setne(RETb); + a.movzx(RETd, RETb); + a.add(ARG1, RET); + + a.bind(not_sub_bin); + } + + a.shl(ARG1, imm(_TAG_IMMED1_SIZE)); + a.or_(ARG1, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, ARG1); } +/* ================================================================ + * element/2 + * ================================================================ + */ + void BeamGlobalAssembler::emit_handle_element_error() { static ErtsCodeMFA mfa = {am_erlang, am_element, 2}; @@ -88,19 +315,20 @@ void BeamGlobalAssembler::emit_handle_element_error() { a.mov(getXRef(1), ARG2); a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADARG)); a.mov(ARG4, imm(&mfa)); - a.jmp(labels[handle_error_shared_prologue]); + + a.jmp(labels[raise_exception]); } -/* - * ARG1 = Position (1-based) +/* ARG1 = Position (1-based) * ARG2 = Tuple * ARG3 = 0 if if in body, otherwise address of failure label. * - * Will return with a value in RET only if the element operation succeeds. - */ + * Will return with a value in RET only if the element operation succeeds. */ void BeamGlobalAssembler::emit_bif_element_shared() { Label error = a.newLabel(); + emit_enter_frame(); + a.mov(RETd, ARG1d); a.and_(RETb, imm(_TAG_IMMED1_MASK)); a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); @@ -116,7 +344,7 @@ void BeamGlobalAssembler::emit_bif_element_shared() { a.lea(ARG5, emit_boxed_val(ARG5)); a.mov(ARG6, x86::qword_ptr(ARG5)); a.mov(RETd, ARG6d); - ERTS_CT_ASSERT(make_arityval(0) == 0); + ERTS_CT_ASSERT(make_arityval_zero() == 0); a.and_(RETb, imm(_TAG_HEADER_MASK)); a.short_().jne(error); @@ -127,87 +355,175 @@ void BeamGlobalAssembler::emit_bif_element_shared() { a.inc(ARG4); a.mov(RET, x86::qword_ptr(ARG5, ARG4, 3)); - a.test(RETd, RETd); + + emit_leave_frame(); a.ret(); a.bind(error); { - Label exception = a.newLabel(); + emit_leave_frame(); a.test(ARG3, ARG3); - a.short_().je(exception); - emit_discard_cp(); - a.jmp(ARG3); + a.je(labels[handle_element_error]); - a.bind(exception); - a.jmp(labels[handle_element_error]); + /* Discard return address and jump to fail label. */ + a.add(x86::rsp, imm(8)); + a.jmp(ARG3); } } /* * At the time of implementation, there were 3678 uses of element/2 in * the OTP source code. 3137 of those uses had a literal first argument - * (the position in the tuple), while 540 uses had a varible first + * (the position in the tuple), while 540 uses had a variable first * argument. Calls to element/2 (with a literal first argument) is * especially common in code generated by yecc. */ -void BeamModuleAssembler::emit_bif_element(const ArgVal &Fail, - const ArgVal &Pos, - const ArgVal &Tuple, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_bif_element(const ArgLabel &Fail, + const ArgSource &Pos, + const ArgSource &Tuple, + const ArgRegister &Dst) { bool const_position; - const_position = Pos.getType() == ArgVal::i && is_small(Pos.getValue()) && - signed_val(Pos.getValue()) > 0 && - signed_val(Pos.getValue()) <= (Sint)MAX_ARITYVAL; + const_position = Pos.isSmall() && Pos.as().getSigned() > 0 && + Pos.as().getSigned() <= (Sint)MAX_ARITYVAL; + + /* + * Try to optimize the use of a tuple as a lookup table. + */ + if (exact_type(Pos) && Tuple.isLiteral()) { + Eterm tuple = beamfile_get_literal(beam, Tuple.as().get()); + + if (is_tuple(tuple)) { + Label error = a.newLabel(), next = a.newLabel(); + Sint size = Sint(arityval(*tuple_val(tuple))); + auto [min, max] = getClampedRange(Pos); + bool can_fail = min < 1 || size < max; + + comment("skipped tuple test since source is always a literal " + "tuple"); + mov_arg(ARG2, Tuple); + mov_arg(ARG1, Pos); + x86::Gp boxed_ptr = emit_ptr_val(ARG3, ARG2); + a.lea(ARG4, emit_boxed_val(boxed_ptr)); + if (always_small(Pos)) { + comment("skipped test for small position since it is always " + "small"); + } else { + comment("simplified test for small position since it is an " + "integer"); + a.test(ARG1.r8(), imm(TAG_PRIMARY_LIST)); + a.short_().je(error); + } + + a.mov(RET, ARG1); + a.sar(RET, imm(_TAG_IMMED1_SIZE)); + if (min >= 1) { + comment("skipped check for position =:= 0 since it is always " + ">= 1"); + } else { + a.short_().jz(error); + } + if (min >= 0 && size >= max) { + comment("skipped check for negative position and position " + "beyond tuple"); + } else { + /* Note: Also checks for negative size. */ + a.cmp(RET, imm(size)); + a.short_().ja(error); + } + + a.mov(RET, x86::qword_ptr(ARG4, RET, 3)); + if (can_fail) { + a.short_().jmp(next); + } + + a.bind(error); + if (can_fail) { + if (Fail.get() == 0) { + safe_fragment_call(ga->get_handle_element_error()); + } else { + a.jmp(resolve_beam_label(Fail)); + } + } + + a.bind(next); + mov_arg(Dst, RET); + + return; + } + } if (const_position) { /* The position is a valid small integer. Inline the code. * * The size of the code is 40 bytes, while the size of the bif2 * instruction is 36 bytes. */ - Uint position = signed_val(Pos.getValue()); - Label error; + Uint position = Pos.as().getSigned(); mov_arg(ARG2, Tuple); - if (Fail.getValue() == 0) { - error = a.newLabel(); + x86::Gp boxed_ptr = emit_ptr_val(ARG3, ARG2); - emit_is_boxed(error, ARG2, dShort); - } else { - emit_is_boxed(labels[Fail.getValue()], ARG2); - } + if (exact_type(Tuple)) { + comment("skipped tuple test since source is always a tuple"); + ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); + a.cmp(emit_boxed_val(boxed_ptr, 0, sizeof(Uint32)), + imm(make_arityval_unchecked(position))); - x86::Gp boxed_ptr = emit_ptr_val(ARG3, ARG2); - a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + if (Fail.get() == 0) { + Label next = a.newLabel(); - ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); - a.cmp(RETd, imm(make_arityval(position))); + a.short_().jae(next); - if (Fail.getValue() == 0) { - a.short_().jb(error); - } else { - a.jb(labels[Fail.getValue()]); - } + mov_imm(ARG1, make_small(position)); + safe_fragment_call(ga->get_handle_element_error()); - ERTS_CT_ASSERT(make_arityval(0) == 0); - a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.bind(next); + } else { + a.jb(resolve_beam_label(Fail)); + } + } else { + Distance dist; + Label error; + + if (Fail.get() == 0) { + error = a.newLabel(); + dist = dShort; + } else { + error = resolve_beam_label(Fail); + dist = dLong; + } - if (Fail.getValue() == 0) { - Label next = a.newLabel(); + emit_is_boxed(error, Tuple, ARG2, dist); - a.short_().je(next); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.cmp(RETd, imm(make_arityval_unchecked(position))); - a.bind(error); - { - mov_imm(ARG1, make_small(position)); - safe_fragment_call(ga->get_handle_element_error()); + if (Fail.get() == 0) { + a.short_().jb(error); + } else { + a.jb(error); } - a.bind(next); - } else { - a.jne(labels[Fail.getValue()]); + ERTS_CT_ASSERT(make_arityval_zero() == 0); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + + if (Fail.get() == 0) { + Label next = a.newLabel(); + + a.short_().je(next); + + a.bind(error); + { + mov_imm(ARG1, make_small(position)); + safe_fragment_call(ga->get_handle_element_error()); + } + + a.bind(next); + } else { + a.jne(error); + } } a.mov(RET, emit_boxed_val(boxed_ptr, position * sizeof(Eterm))); @@ -219,8 +535,8 @@ void BeamModuleAssembler::emit_bif_element(const ArgVal &Fail, mov_arg(ARG2, Tuple); mov_arg(ARG1, Pos); - if (Fail.getValue() != 0) { - a.lea(ARG3, x86::qword_ptr(labels[Fail.getValue()])); + if (Fail.get() != 0) { + a.lea(ARG3, x86::qword_ptr(resolve_beam_label(Fail))); } else { mov_imm(ARG3, 0); } @@ -230,3 +546,451 @@ void BeamModuleAssembler::emit_bif_element(const ArgVal &Fail, mov_arg(Dst, RET); } + +/* ================================================================ + * hd/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_hd_error() { + static ErtsCodeMFA mfa = {am_erlang, am_hd, 1}; + + a.mov(getXRef(0), RET); + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADARG)); + a.mov(ARG4, imm(&mfa)); + a.jmp(labels[raise_exception]); +} + +/* + * At the time of implementation, there were 3285 uses of hd/1 in + * the OTP source code. Most of them were in code generated by + * yecc. + * + * The code size for this specialization of hd/1 is 21 bytes, + * while the code size for the bif1 instruction is 24 bytes. + */ + +void BeamModuleAssembler::emit_bif_hd(const ArgSource &Src, + const ArgRegister &Hd) { + Label good_cons = a.newLabel(); + + mov_arg(RET, Src); + a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); + + a.short_().je(good_cons); + safe_fragment_call(ga->get_handle_hd_error()); + + a.bind(good_cons); + { + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + a.mov(ARG2, getCARRef(boxed_ptr)); + mov_arg(Hd, ARG2); + } +} + +/* ================================================================ + * is_map_key/2 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_is_map_key(const ArgWord &Bif, + const ArgLabel &Fail, + const ArgSource &Key, + const ArgSource &Src, + const ArgRegister &Dst) { + if (!exact_type(Src)) { + emit_i_bif2(Key, Src, Fail, Bif, Dst); + return; + } + + comment("inlined BIF is_map_key/2"); + + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + + if (maybe_one_of(Key) && + hasCpuFeature(CpuFeatures::X86::kBMI2)) { + safe_fragment_call(ga->get_i_get_map_element_shared()); + emit_cond_to_bool(x86::Inst::kIdCmovne, Dst); + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + emit_test_the_non_value(RET); + emit_cond_to_bool(x86::Inst::kIdCmove, Dst); + } +} + +/* ================================================================ + * map_get/2 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_map_get_badmap() { + static ErtsCodeMFA mfa = {am_erlang, am_map_get, 2}; + a.mov(getXRef(0), ARG2); + a.mov(getXRef(1), ARG1); + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADMAP)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), ARG1); + a.mov(ARG4, imm(&mfa)); + a.jmp(labels[raise_exception]); +} + +void BeamGlobalAssembler::emit_handle_map_get_badkey() { + static ErtsCodeMFA mfa = {am_erlang, am_map_get, 2}; + a.mov(getXRef(0), ARG2); + a.mov(getXRef(1), ARG1); + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADKEY)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), ARG2); + a.mov(ARG4, imm(&mfa)); + a.jmp(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_bif_map_get(const ArgLabel &Fail, + const ArgSource &Key, + const ArgSource &Src, + const ArgRegister &Dst) { + Label good_key = a.newLabel(); + + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + + if (exact_type(Src)) { + comment("skipped test for map for known map argument"); + } else { + Label bad_map = a.newLabel(); + Label good_map = a.newLabel(); + + if (Fail.get() == 0) { + emit_is_boxed(bad_map, Src, ARG1); + } else { + emit_is_boxed(resolve_beam_label(Fail), Src, ARG1); + } + + /* As an optimization for the `error | #{}` case, skip checking the + * header word when we know that the only possible boxed type + * is a map. */ + if (masked_types(Src) == BeamTypeId::Map) { + comment("skipped header test since we know it's a map when boxed"); + if (Fail.get() == 0) { + a.short_().jmp(good_map); + } + } else { + x86::Gp boxed_ptr = emit_ptr_val(RET, ARG1); + a.mov(RET, emit_boxed_val(boxed_ptr)); + a.and_(RETb, imm(_TAG_HEADER_MASK)); + a.cmp(RETb, imm(_TAG_HEADER_MAP)); + if (Fail.get() == 0) { + a.short_().je(good_map); + } else { + a.jne(resolve_beam_label(Fail)); + } + } + + a.bind(bad_map); + if (Fail.get() == 0) { + fragment_call(ga->get_handle_map_get_badmap()); + } + + a.bind(good_map); + } + + if (maybe_one_of(Key) && + hasCpuFeature(CpuFeatures::X86::kBMI2)) { + safe_fragment_call(ga->get_i_get_map_element_shared()); + if (Fail.get() == 0) { + a.je(good_key); + } else { + a.jne(resolve_beam_label(Fail)); + } + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + emit_test_the_non_value(RET); + if (Fail.get() == 0) { + a.short_().jne(good_key); + } else { + a.je(resolve_beam_label(Fail)); + } + } + + if (Fail.get() == 0) { + mov_arg(ARG1, Src); + mov_arg(ARG2, Key); + fragment_call(ga->get_handle_map_get_badkey()); + } + + a.bind(good_key); + mov_arg(Dst, RET); +} + +/* ================================================================ + * map_size/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_map_size_error() { + static ErtsCodeMFA mfa = {am_erlang, am_map_size, 1}; + + a.mov(getXRef(0), RET); + a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), RET); + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADMAP)); + a.mov(ARG4, imm(&mfa)); + a.jmp(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_bif_map_size(const ArgLabel &Fail, + const ArgSource &Src, + const ArgRegister &Dst) { + Label error = a.newLabel(), good_map = a.newLabel(); + + mov_arg(RET, Src); + + if (Fail.get() == 0) { + emit_is_boxed(error, Src, RET); + } else { + emit_is_boxed(resolve_beam_label(Fail), Src, RET); + } + + x86::Gp boxed_ptr = emit_ptr_val(x86::rdx, RET); + + if (exact_type(Src)) { + comment("skipped type check because the argument is always a map"); + a.bind(error); /* Never referenced. */ + } else { + a.mov(x86::ecx, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(x86::cl, imm(_TAG_HEADER_MASK)); + a.cmp(x86::cl, imm(_TAG_HEADER_MAP)); + if (Fail.get() == 0) { + a.short_().je(good_map); + + a.bind(error); + safe_fragment_call(ga->get_handle_map_size_error()); + } else { + a.jne(resolve_beam_label(Fail)); + a.bind(error); /* Never referenced. */ + } + } + + a.bind(good_map); + { + ERTS_CT_ASSERT(offsetof(flatmap_t, size) == sizeof(Eterm)); + a.mov(RET, emit_boxed_val(boxed_ptr, sizeof(Eterm))); + a.shl(RET, imm(4)); + a.or_(RETb, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, RET); + } +} + +/* ================================================================ + * min/2 + * max/2 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_min_max(uint32_t instId, + const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + Label generic = a.newLabel(), do_cmov = a.newLabel(); + bool both_small = always_small(LHS) && always_small(RHS); + bool need_generic = !both_small; + + mov_arg(ARG2, RHS); /* May clobber ARG1 */ + mov_arg(ARG1, LHS); + + if (both_small) { + comment("skipped test for small operands since they are always small"); + } else if (always_one_of( + LHS) && + always_small(RHS)) { + emit_is_not_boxed(generic, ARG1, dShort); + } else if (always_small(LHS) && + always_one_of( + RHS)) { + emit_is_not_boxed(generic, ARG2, dShort); + } else if (always_one_of( + LHS) && + always_one_of( + RHS)) { + comment("simplified small test since all other types are boxed"); + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + emit_is_not_boxed(generic, RETb, dShort); + } else { + /* Relative comparisons are overwhelmingly likely to be used on + * smalls, so we'll specialize those and keep the rest in a shared + * fragment. */ + if (RHS.isSmall()) { + a.mov(RETd, ARG1d); + } else if (LHS.isSmall()) { + a.mov(RETd, ARG2d); + } else { + a.mov(RETd, ARG1d); + a.and_(RETd, ARG2d); + } + + a.and_(RETb, imm(_TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); + a.short_().jne(generic); + } + + /* Both arguments are smalls. */ + a.cmp(ARG1, ARG2); + if (need_generic) { + a.short_().jmp(do_cmov); + } + + a.bind(generic); + if (need_generic) { + a.cmp(ARG1, ARG2); + a.short_().je(do_cmov); + a.push(ARG1); + a.push(ARG2); + safe_fragment_call(ga->get_arith_compare_shared()); + a.pop(ARG2); + a.pop(ARG1); + } + + a.bind(do_cmov); + a.emit(instId, ARG1, ARG2); + mov_arg(Dst, ARG1); +} + +void BeamModuleAssembler::emit_bif_max(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_min_max(x86::Inst::kIdCmovl, LHS, RHS, Dst); +} + +void BeamModuleAssembler::emit_bif_min(const ArgSource &LHS, + const ArgSource &RHS, + const ArgRegister &Dst) { + emit_bif_min_max(x86::Inst::kIdCmovg, LHS, RHS, Dst); +} + +/* ================================================================ + * node/1 + * ================================================================ + */ + +void BeamGlobalAssembler::emit_handle_node_error() { + static ErtsCodeMFA mfa = {am_erlang, am_node, 1}; + a.mov(getXRef(0), ARG1); + a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADARG)); + a.mov(ARG4, imm(&mfa)); + + a.jmp(labels[raise_exception]); +} + +void BeamModuleAssembler::emit_bif_node(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Dst) { + bool always_identifier = always_one_of(Src); + Label test_internal = a.newLabel(); + Label internal = a.newLabel(); + Label next = a.newLabel(); + Label fail; + + if (Fail.get() == 0 && !always_identifier) { + fail = a.newLabel(); + } + + mov_arg(ARG1, Src); + emit_is_boxed(test_internal, Src, ARG1); + + x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG1); + + if (!always_one_of(Src)) { + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + a.and_(RETd, imm(_TAG_HEADER_MASK)); + } + + if (maybe_one_of(Src)) { + a.cmp(RETb, imm(_TAG_HEADER_REF)); + a.short_().je(internal); + } + + if (!always_identifier) { + Label external = a.newLabel(); + + ERTS_CT_ASSERT((_TAG_HEADER_EXTERNAL_PORT - _TAG_HEADER_EXTERNAL_PID) >> + _TAG_PRIMARY_SIZE == + 1); + ERTS_CT_ASSERT((_TAG_HEADER_EXTERNAL_REF - _TAG_HEADER_EXTERNAL_PORT) >> + _TAG_PRIMARY_SIZE == + 1); + a.sub(RETb, imm(_TAG_HEADER_EXTERNAL_PID)); + a.cmp(RETb, imm(_TAG_HEADER_EXTERNAL_REF - _TAG_HEADER_EXTERNAL_PID)); + if (Fail.get() == 0) { + a.short_().jbe(external); + + a.bind(fail); + fragment_call(ga->get_handle_node_error()); + } else { + a.ja(resolve_beam_label(Fail)); + } + + a.bind(external); + } + + a.mov(ARG1, emit_boxed_val(boxed_ptr, offsetof(ExternalThing, node))); + a.short_().jmp(next); + + a.bind(test_internal); + if (!always_identifier) { + /* Since pids and ports differ by a single bit, we can + * simplify the check by clearing said bit and comparing + * against the lesser one. */ + ERTS_CT_ASSERT(_TAG_IMMED1_PORT - _TAG_IMMED1_PID == 0x4); + a.mov(RETd, ARG1d); + a.and_(RETb, + imm(~(_TAG_IMMED1_PORT - _TAG_IMMED1_PID) & _TAG_IMMED1_MASK)); + a.cmp(RETb, imm(_TAG_IMMED1_PID)); + if (Fail.get() == 0) { + a.short_().jne(fail); + } else { + a.jne(resolve_beam_label(Fail)); + } + } + + a.bind(internal); + a.mov(ARG1, imm(&erts_this_node)); + a.mov(ARG1, x86::qword_ptr(ARG1)); + + a.bind(next); + a.mov(ARG1, x86::qword_ptr(ARG1, offsetof(ErlNode, sysname))); + mov_arg(Dst, ARG1); +} + +/* ================================================================ + * tuple_size/1 + * ================================================================ + */ + +void BeamModuleAssembler::emit_bif_tuple_size(const ArgWord &Bif, + const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Dst) { + if (exact_type(Src)) { + comment("inlined tuple_size/1 because the argument is always a tuple"); + mov_arg(RET, Src); + + /* Instructions operating on dwords are shorter. */ + ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); + x86::Gp boxed_ptr = emit_ptr_val(RET, RET); + a.mov(RETd, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); + + ERTS_CT_ASSERT(_HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE > 0); + ERTS_CT_ASSERT(_TAG_IMMED1_SMALL == _TAG_IMMED1_MASK); + a.shr(RETd, imm(_HEADER_ARITY_OFFS - _TAG_IMMED1_SIZE)); + a.or_(RETb, imm(_TAG_IMMED1_SMALL)); + mov_arg(Dst, RET); + } else { + /* Unknown type. Use the standard BIF instruction. */ + emit_i_bif1(Src, Fail, Bif, Dst); + } +} diff --git a/erts/emulator/beam/jit/x86/instr_map.cpp b/erts/emulator/beam/jit/x86/instr_map.cpp index b3e5287db61e..5f89077ba655 100644 --- a/erts/emulator/beam/jit/x86/instr_map.cpp +++ b/erts/emulator/beam/jit/x86/instr_map.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -25,51 +25,248 @@ using namespace asmjit; extern "C" { #include "erl_map.h" +#include "erl_term_hashing.h" #include "beam_common.h" } -void BeamModuleAssembler::emit_ensure_map(const ArgVal &map) { - Label next = a.newLabel(), badmap = a.newLabel(); +static const Uint32 INTERNAL_HASH_SALT = 3432918353; +static const Uint32 HCONST = 0x9E3779B9; - mov_arg(ARG1, map); - emit_is_boxed(badmap, ARG1, dShort); - /* We use ARG1 in the badmap branch, so use ARG2 below */ - x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG1); - a.mov(ARG2, emit_boxed_val(boxed_ptr)); - a.and_(ARG2d, imm(_TAG_HEADER_MASK)); - a.cmp(ARG2d, imm(_TAG_HEADER_MAP)); - a.short_().je(next); +/* + * ARG4 = lower 32 + * ARG5 = upper 32 + * + * Helper function for calculating the internal hash of keys before looking + * them up in a map. + * + * This is essentially just a manual expansion of the `UINT32_HASH_2` macro. + * Whenever the internal hash algorithm is updated, this and all of its users + * must follow suit. + * + * Result is returned in ARG3. */ +void BeamGlobalAssembler::emit_internal_hash_helper() { + x86::Gp hash = ARG3d, lower = ARG4d, upper = ARG5d; + + a.mov(hash, imm(INTERNAL_HASH_SALT)); + a.add(lower, imm(HCONST)); + a.add(upper, imm(HCONST)); + +#if defined(ERL_INTERNAL_HASH_CRC32C) + a.mov(ARG6d, hash); + a.crc32(hash, lower); + a.add(hash, ARG6d); + a.crc32(hash, upper); +#else + using rounds = + std::initializer_list>; + for (const auto &round : rounds{{lower, upper, hash, 13}, + {upper, hash, lower, -8}, + {hash, lower, upper, 13}, + {lower, upper, hash, 12}, + {upper, hash, lower, -16}, + {hash, lower, upper, 5}, + {lower, upper, hash, 3}, + {upper, hash, lower, -10}, + {hash, lower, upper, 15}}) { + const auto &[r_a, r_b, r_c, shift] = round; + + a.sub(r_a, r_b); + a.sub(r_a, r_c); + + /* We have no use for the type constant anymore, reuse its register for + * the `a ^= r_c << shift` expression. */ + a.mov(ARG6d, r_c); + + if (shift > 0) { + a.shr(ARG6d, imm(shift)); + } else { + a.shl(ARG6d, imm(-shift)); + } + + a.xor_(r_a, ARG6d); + } +#endif + +#ifdef DBG_HASHMAP_COLLISION_BONANZA + a.mov(TMP_MEM1q, ARG1); + a.mov(TMP_MEM2q, ARG2); + a.mov(TMP_MEM3q, RET); - a.bind(badmap); + a.mov(ARG1, ARG3); + emit_enter_runtime(); + runtime_call<2>(erts_dbg_hashmap_collision_bonanza); + emit_leave_runtime(); + + a.mov(ARG3d, RETd); + + a.mov(ARG1, TMP_MEM1q); + a.mov(ARG2, TMP_MEM2q); + a.mov(RET, TMP_MEM3q); +#endif + + a.ret(); +} + +/* ARG1 = hash map root, ARG2 = key, ARG3 = key hash, RETd = node header + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_hashmap_get_element() { + Label node_loop = a.newLabel(); + + x86::Gp node = ARG1, key = ARG2, key_hash = ARG3d, header_val = RETd, + index = ARG4d, depth = ARG5d; + + const int header_shift = + (_HEADER_ARITY_OFFS + MAP_HEADER_TAG_SZ + MAP_HEADER_ARITY_SZ); + + /* Skip the root header. This is not required for child nodes. */ + a.add(node, imm(sizeof(Eterm))); + mov_imm(depth, 0); + + a.bind(node_loop); { - a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), ARG1); - emit_error(BADMAP); + Label done = a.newLabel(), leaf_node = a.newLabel(), + skip_index_adjustment = a.newLabel(), + collision_node = a.newLabel(); + + /* Find out which child we should follow, and shift the hash for the + * next round. */ + a.mov(index, key_hash); + a.and_(index, imm(0xF)); + a.shr(key_hash, imm(4)); + a.inc(depth); + + /* The entry offset is always equal to the index on fully populated + * nodes, so we'll skip adjusting them. */ + ERTS_CT_ASSERT(header_shift == 16); + a.sar(header_val, imm(header_shift)); + a.cmp(header_val, imm(-1)); + a.short_().je(skip_index_adjustment); + { + /* If our bit isn't set on this node, the key can't be found. + * + * Note that we jump directly to a `RET` instruction, as `BT` only + * affects CF, and ZF ("not found") is clear at this point. */ + a.bt(header_val, index); + a.short_().jnc(done); + + /* The actual offset of our entry is the number of bits set (in + * essence "entries present") before our index in the bitmap. */ + a.bzhi(header_val, header_val, index); + a.popcnt(index, header_val); + } + a.bind(skip_index_adjustment); + + a.mov(node, + x86::qword_ptr(node, + index.r64(), + 3, + sizeof(Eterm) - TAG_PRIMARY_BOXED)); + emit_ptr_val(node, node); + + /* Have we found our leaf? */ + a.test(node.r8(), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); + a.short_().je(leaf_node); + + /* Nope, we have to search another node. */ + a.mov(header_val, emit_boxed_val(node, 0, sizeof(Uint32))); + + /* After 8 nodes we've run out of the 32 bits we started with + * and we end up in a collision node. */ + a.test(depth, imm(HAMT_MAX_LEVEL - 1)); + a.short_().jnz(node_loop); + a.short_().jmp(collision_node); + + a.bind(leaf_node); + { + /* We've arrived at a leaf, set ZF according to whether its key + * matches ours and speculatively place the element in RET. */ + a.cmp(getCARRef(node), key); + a.mov(RET, getCDRRef(node)); + + /* See comment at the jump. */ + a.bind(done); + a.ret(); + } + + /* A collision node is a tuple of leafs where we do linear search.*/ + a.bind(collision_node); + { + Label linear_loop = a.newLabel(); + + a.shr(header_val, imm(_HEADER_ARITY_OFFS)); + a.lea(ARG6d, x86::qword_ptr(header_val, -1)); + + a.bind(linear_loop); + { + a.mov(ARG3, + x86::qword_ptr(node, ARG6, 3, 8 - TAG_PRIMARY_BOXED)); + + emit_ptr_val(ARG3, ARG3); + a.cmp(key, getCARRef(ARG3)); + a.mov(RET, getCDRRef(ARG3)); + a.short_().jz(done); + + a.dec(ARG6d); + a.short_().jns(linear_loop); + } + + a.ret(); + } } +} - a.bind(next); +/* ARG1 = flat map, ARG2 = key + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_flatmap_get_element() { + Label fail = a.newLabel(), loop = a.newLabel(); + + a.mov(RETd, emit_boxed_val(ARG1, offsetof(flatmap_t, size), 4)); + a.mov(ARG4, emit_boxed_val(ARG1, offsetof(flatmap_t, keys))); + + emit_ptr_val(ARG4, ARG4); + + a.bind(loop); + { + a.dec(RETd); + a.short_().jl(fail); + + a.cmp(ARG2, + x86::qword_ptr(ARG4, RET, 3, sizeof(Eterm) - TAG_PRIMARY_BOXED)); + a.short_().jne(loop); + } + + int value_offset = sizeof(flatmap_t) - TAG_PRIMARY_BOXED; + a.mov(RET, x86::qword_ptr(ARG1, RET, 3, value_offset)); + + a.bind(fail); + a.ret(); } void BeamGlobalAssembler::emit_new_map_shared() { - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<5>(erts_gc_new_map); - emit_leave_runtime(); + emit_leave_runtime(); + emit_leave_frame(); a.ret(); } -void BeamModuleAssembler::emit_new_map(const ArgVal &Dst, - const ArgVal &Live, - const ArgVal &Size, - const std::vector &args) { +void BeamModuleAssembler::emit_new_map(const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { Label data = embed_vararg_rodata(args, CP_SIZE); - ASSERT(Size.getValue() == args.size()); + ASSERT(Size.get() == args.size()); - mov_imm(ARG3, Live.getValue()); + mov_imm(ARG3, Live.get()); mov_imm(ARG4, args.size()); a.lea(ARG5, x86::qword_ptr(data)); fragment_call(ga->get_new_map_shared()); @@ -77,141 +274,330 @@ void BeamModuleAssembler::emit_new_map(const ArgVal &Dst, mov_arg(Dst, RET); } -void BeamGlobalAssembler::emit_i_new_small_map_lit_shared() { - emit_enter_runtime(); +void BeamModuleAssembler::emit_i_new_small_map_lit(const ArgRegister &Dst, + const ArgWord &Live, + const ArgLiteral &Keys, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + + emit_gc_test(ArgWord(0), + ArgWord(args.size() + MAP_HEADER_FLATMAP_SZ + 1), + Live); + + std::vector data; + data.reserve(args.size() + MAP_HEADER_FLATMAP_SZ + 1); + data.push_back(ArgWord(MAP_HEADER_FLATMAP)); + data.push_back(Size); + data.push_back(Keys); + + for (auto arg : args) { + data.push_back(arg); + } - a.mov(ARG1, c_p); - load_x_reg_array(ARG2); - runtime_call<5>(erts_gc_new_small_map_lit); + size_t size = data.size(); + unsigned i; + + mov_arg(x86::qword_ptr(HTOP), data[0]); + + /* Starting from 1 instead of 0 gives more opportunities for + * applying the MMX optimizations. */ + for (i = 1; i < size - 1; i += 2) { + x86::Mem dst_ptr0 = x86::qword_ptr(HTOP, i * sizeof(Eterm)); + x86::Mem dst_ptr1 = x86::qword_ptr(HTOP, (i + 1) * sizeof(Eterm)); + auto first = data[i]; + auto second = data[i + 1]; + + switch (ArgVal::memory_relation(first, second)) { + case ArgVal::consecutive: { + x86::Mem src_ptr = getArgRef(first, 16); + + comment("(initializing two elements at once)"); + dst_ptr0.setSize(16); + vmovups(x86::xmm0, src_ptr); + vmovups(dst_ptr0, x86::xmm0); + break; + } + case ArgVal::reverse_consecutive: { + if (!hasCpuFeature(CpuFeatures::X86::kAVX)) { + mov_arg(dst_ptr0, first); + mov_arg(dst_ptr1, second); + } else { + x86::Mem src_ptr = getArgRef(second, 16); + + comment("(initializing with two swapped elements at once)"); + dst_ptr0.setSize(16); + a.vpermilpd(x86::xmm0, src_ptr, 1); /* Load and swap */ + a.vmovups(dst_ptr0, x86::xmm0); + } + break; + } + case ArgVal::none: + mov_arg(dst_ptr0, first); + mov_arg(dst_ptr1, second); + break; + } + } - emit_leave_runtime(); + if (i < size) { + x86::Mem dst_ptr = x86::qword_ptr(HTOP, i * sizeof(Eterm)); + mov_arg(dst_ptr, data[i]); + } - a.ret(); + a.lea(ARG1, x86::byte_ptr(HTOP, TAG_PRIMARY_BOXED)); + a.add(HTOP, imm(size * sizeof(Eterm))); + + mov_arg(Dst, ARG1); } -void BeamModuleAssembler::emit_i_new_small_map_lit( - const ArgVal &Dst, - const ArgVal &Live, - const ArgVal &Keys, - const ArgVal &Size, - const std::vector &args) { - Label data = embed_vararg_rodata(args, CP_SIZE); +/* ARG1 = map, ARG2 = key + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_i_get_map_element_shared() { + Label generic = a.newLabel(), hashmap = a.newLabel(); - ASSERT(Size.getValue() == args.size()); + a.mov(RETd, ARG2d); - ASSERT(Keys.isLiteral()); - mov_arg(ARG3, Keys); - mov_imm(ARG4, Live.getValue()); - a.lea(ARG5, x86::qword_ptr(data)); + a.and_(RETb, imm(_TAG_PRIMARY_MASK)); + a.cmp(RETb, imm(TAG_PRIMARY_IMMED1)); + a.short_().jne(generic); - fragment_call(ga->get_i_new_small_map_lit_shared()); + emit_ptr_val(ARG1, ARG1); - mov_arg(Dst, RET); + a.mov(RETd, emit_boxed_val(ARG1, 0, sizeof(Uint32))); + a.mov(ARG4d, RETd); + + a.and_(ARG4d, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(ARG4d, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.short_().jne(hashmap); + + emit_flatmap_get_element(); + + a.bind(generic); + { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); + + emit_test_the_non_value(RET); + + /* Invert ZF, we want it to be set when RET is a value. */ + a.setnz(ARG1.r8()); + a.dec(ARG1.r8()); + + a.ret(); + } + + a.bind(hashmap); + { + /* Calculate the internal hash of ARG2 before diving into the HAMT. */ + a.mov(ARG5, ARG2); + a.shr(ARG5, imm(32)); + a.mov(ARG4d, ARG2d); + + a.call(labels[internal_hash_helper]); + + emit_hashmap_get_element(); + } } -void BeamModuleAssembler::emit_i_get_map_element(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Key, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_get_map_element(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgRegister &Key, + const ArgRegister &Dst) { mov_arg(ARG1, Src); mov_arg(ARG2, Key); - emit_enter_runtime(); - - runtime_call<2>(get_map_element); - - emit_leave_runtime(); + if (maybe_one_of(Key) && + hasCpuFeature(CpuFeatures::X86::kBMI2)) { + safe_fragment_call(ga->get_i_get_map_element_shared()); + a.jne(resolve_beam_label(Fail)); + } else { + emit_enter_runtime(); + runtime_call<2>(get_map_element); + emit_leave_runtime(); - emit_test_the_non_value(RET); - a.je(labels[Fail.getValue()]); + emit_test_the_non_value(RET); + a.je(resolve_beam_label(Fail)); + } - /* - * Don't store the result if the destination is the scratch X register. - * (This instruction was originally a has_map_fields instruction.) - */ - if (!(Dst.getType() == ArgVal::x && Dst.getValue() == SCRATCH_X_REG)) { + /* Don't store the result if the destination is the scratch X register. + * (This instruction was originally a has_map_fields instruction.) */ + if (!(Dst.isXRegister() && Dst.as().get() == SCRATCH_X_REG)) { mov_arg(Dst, RET); } } -void BeamModuleAssembler::emit_i_get_map_elements( - const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Size, - const std::vector &args) { +void BeamModuleAssembler::emit_i_get_map_elements(const ArgLabel &Fail, + const ArgSource &Src, + const ArgWord &Size, + const Span &args) { + Label generic = a.newLabel(), next = a.newLabel(); Label data = embed_vararg_rodata(args, 0); - ASSERT(Size.getValue() == args.size()); + /* We're not likely to gain much from inlining huge extractions, and the + * resulting code is quite large, so we'll cut it off after a handful + * elements. + * + * Note that the arguments come in flattened triplets of + * `{Key, Dst, KeyHash}` */ + bool can_inline = args.size() < (8 * 3); + + ASSERT(Size.get() == args.size()); + ASSERT((Size.get() % 3) == 0); + + for (size_t i = 0; i < args.size(); i += 3) { + can_inline &= args[i].isImmed(); + } mov_arg(ARG1, Src); - a.mov(ARG3, E); - emit_enter_runtime(); + if (can_inline) { + comment("simplified multi-element lookup"); + + emit_ptr_val(ARG1, ARG1); + + a.mov(RETd, emit_boxed_val(ARG1, 0, sizeof(Uint32))); + a.and_(RETb, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(RETb, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.jne(generic); + + ERTS_CT_ASSERT(MAP_SMALL_MAP_LIMIT <= ERTS_UINT32_MAX); + a.mov(RETd, + emit_boxed_val(ARG1, offsetof(flatmap_t, size), sizeof(Uint32))); + a.mov(ARG2, emit_boxed_val(ARG1, offsetof(flatmap_t, keys))); + + emit_ptr_val(ARG2, ARG2); + + for (ssize_t i = args.size() - 3; i >= 0; i -= 3) { + Label loop = a.newLabel(); + + a.bind(loop); + { + x86::Mem candidate = + x86::qword_ptr(ARG2, + RET, + 3, + sizeof(Eterm) - TAG_PRIMARY_BOXED); + + a.dec(RETd); + a.jl(resolve_beam_label(Fail)); + + const auto &Comparand = args[i]; + cmp_arg(candidate, Comparand, ARG3); + a.short_().jne(loop); + } + + /* Don't store the result if the destination is the scratch X + * register. (This instruction was originally a has_map_fields + * instruction.) */ + const auto &Dst = args[i + 1]; + if (!(Dst.isXRegister() && + Dst.as().get() == SCRATCH_X_REG)) { + const int value_offset = sizeof(flatmap_t) - TAG_PRIMARY_BOXED; + mov_arg(Dst, x86::qword_ptr(ARG1, RET, 3, value_offset), ARG3); + } + } + + a.short_().jmp(next); + } - mov_imm(ARG4, args.size() / 3); - a.lea(ARG5, x86::qword_ptr(data)); - load_x_reg_array(ARG2); - runtime_call<5>(beam_jit_get_map_elements); + a.bind(generic); + { + mov_imm(ARG4, args.size() / 3); + a.lea(ARG5, x86::qword_ptr(data)); + a.mov(ARG3, E); - emit_leave_runtime(); + emit_enter_runtime(); + + load_x_reg_array(ARG2); + runtime_call<5>(beam_jit_get_map_elements); + + emit_leave_runtime(); + + a.test(RET, RET); + a.je(resolve_beam_label(Fail)); + } + + a.bind(next); +} + +/* ARG1 = map, ARG2 = key, ARG3 = key hash + * + * Result is returned in RET. ZF is set on success. */ +void BeamGlobalAssembler::emit_i_get_map_element_hash_shared() { + Label hashmap = a.newLabel(); - a.test(RET, RET); - a.je(labels[Fail.getValue()]); + emit_ptr_val(ARG1, ARG1); + + a.mov(RETd, emit_boxed_val(ARG1, 0, sizeof(Uint32))); + a.mov(ARG4d, RETd); + + a.and_(ARG4d, imm(_HEADER_MAP_SUBTAG_MASK)); + a.cmp(ARG4d, imm(HAMT_SUBTAG_HEAD_FLATMAP)); + a.short_().jne(hashmap); + + emit_flatmap_get_element(); + + a.bind(hashmap); + emit_hashmap_get_element(); } -void BeamModuleAssembler::emit_i_get_map_element_hash(const ArgVal &Fail, - const ArgVal &Src, - const ArgVal &Key, - const ArgVal &Hx, - const ArgVal &Dst) { +void BeamModuleAssembler::emit_i_get_map_element_hash(const ArgLabel &Fail, + const ArgRegister &Src, + const ArgConstant &Key, + const ArgWord &Hx, + const ArgRegister &Dst) { mov_arg(ARG1, Src); mov_arg(ARG2, Key); mov_arg(ARG3, Hx); - emit_enter_runtime(); - - runtime_call<3>(get_map_element_hash); - - emit_leave_runtime(); + if (Key.isImmed() && hasCpuFeature(CpuFeatures::X86::kBMI2)) { + safe_fragment_call(ga->get_i_get_map_element_hash_shared()); + a.jne(resolve_beam_label(Fail)); + } else { + emit_enter_runtime(); + runtime_call<3>(get_map_element_hash); + emit_leave_runtime(); - emit_test_the_non_value(RET); - a.je(labels[Fail.getValue()]); + emit_test_the_non_value(RET); + a.je(resolve_beam_label(Fail)); + } - /* - * Don't store the result if the destination is the scratch X register. - * (This instruction was originally a has_map_fields instruction.) - */ - if (!(Dst.getType() == ArgVal::x && Dst.getValue() == SCRATCH_X_REG)) { + /* Don't store the result if the destination is the scratch X register. + * (This instruction was originally a has_map_fields instruction.) */ + if (!(Dst.isXRegister() && Dst.as().get() == SCRATCH_X_REG)) { mov_arg(Dst, RET); } } /* ARG3 = live registers, ARG4 = update vector size, ARG5 = update vector. */ void BeamGlobalAssembler::emit_update_map_assoc_shared() { - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<5>(erts_gc_update_map_assoc); - emit_leave_runtime(); + emit_leave_runtime(); + emit_leave_frame(); a.ret(); } -void BeamModuleAssembler::emit_update_map_assoc( - const ArgVal &Src, - const ArgVal &Dst, - const ArgVal &Live, - const ArgVal &Size, - const std::vector &args) { +void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src, + const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { Label data = embed_vararg_rodata(args, CP_SIZE); - ASSERT(Size.getValue() == args.size()); + ASSERT(Size.get() == args.size()); - mov_arg(getXRef(Live.getValue()), Src); + mov_arg(getXRef(Live.get()), Src); - mov_imm(ARG3, Live.getValue()); + mov_imm(ARG3, Live.get()); mov_imm(ARG4, args.size()); a.lea(ARG5, x86::qword_ptr(data)); fragment_call(ga->get_update_map_assoc_shared()); @@ -223,13 +609,15 @@ void BeamModuleAssembler::emit_update_map_assoc( * * Result is returned in RET, error is indicated by ZF. */ void BeamGlobalAssembler::emit_update_map_exact_guard_shared() { - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<5>(erts_gc_update_map_exact); - emit_leave_runtime(); + emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.ret(); @@ -241,13 +629,15 @@ void BeamGlobalAssembler::emit_update_map_exact_guard_shared() { void BeamGlobalAssembler::emit_update_map_exact_body_shared() { Label error = a.newLabel(); - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<5>(erts_gc_update_map_exact); - emit_leave_runtime(); + emit_leave_runtime(); + emit_leave_frame(); emit_test_the_non_value(RET); a.short_().je(error); @@ -257,31 +647,30 @@ void BeamGlobalAssembler::emit_update_map_exact_body_shared() { a.bind(error); { mov_imm(ARG4, 0); - emit_handle_error(); + a.jmp(labels[raise_exception]); } } -void BeamModuleAssembler::emit_update_map_exact( - const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Dst, - const ArgVal &Live, - const ArgVal &Size, - const std::vector &args) { +void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src, + const ArgLabel &Fail, + const ArgRegister &Dst, + const ArgWord &Live, + const ArgWord &Size, + const Span &args) { Label data = embed_vararg_rodata(args, CP_SIZE); - ASSERT(Size.getValue() == args.size()); + ASSERT(Size.get() == args.size()); /* We _KNOW_ Src is a map */ - mov_arg(getXRef(Live.getValue()), Src); + mov_arg(getXRef(Live.get()), Src); - mov_imm(ARG3, Live.getValue()); + mov_imm(ARG3, Live.get()); mov_imm(ARG4, args.size()); a.lea(ARG5, x86::qword_ptr(data)); - if (Fail.getValue() != 0) { + if (Fail.get() != 0) { fragment_call(ga->get_update_map_exact_guard_shared()); - a.je(labels[Fail.getValue()]); + a.je(resolve_beam_label(Fail)); } else { fragment_call(ga->get_update_map_exact_body_shared()); } diff --git a/erts/emulator/beam/jit/x86/instr_msg.cpp b/erts/emulator/beam/jit/x86/instr_msg.cpp index 925c98f633fe..d015d3b71baf 100644 --- a/erts/emulator/beam/jit/x86/instr_msg.cpp +++ b/erts/emulator/beam/jit/x86/instr_msg.cpp @@ -74,19 +74,19 @@ void BeamModuleAssembler::emit_i_recv_set() { #endif /* ERTS_SUPPORT_OLD_RECV_MARK_INSTRS */ -void BeamModuleAssembler::emit_recv_marker_reserve(const ArgVal &Dst) { - emit_enter_runtime(); +void BeamModuleAssembler::emit_recv_marker_reserve(const ArgRegister &Dst) { + emit_enter_runtime(); a.mov(ARG1, c_p); runtime_call<1>(erts_msgq_recv_marker_insert); - emit_leave_runtime(); + emit_leave_runtime(); mov_arg(Dst, RET); } -void BeamModuleAssembler::emit_recv_marker_bind(const ArgVal &Marker, - const ArgVal &Reference) { +void BeamModuleAssembler::emit_recv_marker_bind(const ArgRegister &Marker, + const ArgRegister &Reference) { mov_arg(ARG2, Marker); mov_arg(ARG3, Reference); @@ -98,7 +98,7 @@ void BeamModuleAssembler::emit_recv_marker_bind(const ArgVal &Marker, emit_leave_runtime(); } -void BeamModuleAssembler::emit_recv_marker_clear(const ArgVal &Reference) { +void BeamModuleAssembler::emit_recv_marker_clear(const ArgRegister &Reference) { mov_arg(ARG2, Reference); emit_enter_runtime(); @@ -109,7 +109,7 @@ void BeamModuleAssembler::emit_recv_marker_clear(const ArgVal &Reference) { emit_leave_runtime(); } -void BeamModuleAssembler::emit_recv_marker_use(const ArgVal &Reference) { +void BeamModuleAssembler::emit_recv_marker_use(const ArgRegister &Reference) { mov_arg(ARG2, Reference); emit_enter_runtime(); @@ -150,6 +150,8 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { x86::Mem await_addr = TMP_MEM1q, message_ptr = TMP_MEM2q, get_out = TMP_MEM3d; + emit_enter_frame(); + a.or_(x86::dword_ptr(c_p, offsetof(Process, flags)), imm(F_DELAY_GC)); a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), ARG1); a.mov(await_addr, ARG2); @@ -181,8 +183,7 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { comment("Inner queue empty, fetch more from outer/middle queues"); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(message_ptr, imm(0)); a.mov(ARG1, c_p); @@ -202,8 +203,7 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { * Also note that another process may have loaded new code and sent us * a message to notify us about it, so we must update the active code * index. */ - emit_leave_runtime(); + emit_leave_runtime(); a.sub(FCALLS, RET); @@ -223,7 +223,7 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { * Note that the message queue lock is still held in this case. */ a.and_(x86::dword_ptr(c_p, offsetof(Process, flags)), imm(~F_DELAY_GC)); - emit_discard_cp(); + emit_unwind_frame(); a.jmp(await_addr); } @@ -235,7 +235,7 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), imm(0)); a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), imm(0)); - emit_discard_cp(); + emit_unwind_frame(); a.jmp(labels[do_schedule]); } @@ -269,18 +269,19 @@ void BeamGlobalAssembler::emit_i_loop_rec_shared() { a.mov(ARG1, x86::qword_ptr(ARG1, offsetof(ErtsMessage, m[0]))); a.mov(getXRef(0), ARG1); + emit_leave_frame(); a.ret(); } } -void BeamModuleAssembler::emit_i_loop_rec(const ArgVal &Wait) { +void BeamModuleAssembler::emit_i_loop_rec(const ArgLabel &Wait) { Label entry = a.newLabel(); align_erlang_cp(); a.bind(entry); a.lea(ARG1, x86::qword_ptr(entry)); - a.lea(ARG2, x86::qword_ptr(labels[Wait.getValue()])); + a.lea(ARG2, x86::qword_ptr(resolve_beam_label(Wait))); fragment_call(ga->get_i_loop_rec_shared()); } @@ -301,7 +302,7 @@ void BeamModuleAssembler::emit_remove_message() { emit_leave_runtime(); } -void BeamModuleAssembler::emit_loop_rec_end(const ArgVal &Dest) { +void BeamModuleAssembler::emit_loop_rec_end(const ArgLabel &Dest) { emit_enter_runtime(); a.mov(ARG1, c_p); @@ -310,35 +311,35 @@ void BeamModuleAssembler::emit_loop_rec_end(const ArgVal &Dest) { emit_leave_runtime(); a.dec(FCALLS); - a.jmp(labels[Dest.getValue()]); + a.jmp(resolve_beam_label(Dest)); } -void BeamModuleAssembler::emit_wait_unlocked(const ArgVal &Dest) { +void BeamModuleAssembler::emit_wait_unlocked(const ArgLabel &Dest) { emit_enter_runtime(); a.mov(ARG1, c_p); - a.lea(ARG2, x86::qword_ptr(labels[Dest.getValue()])); + a.lea(ARG2, x86::qword_ptr(resolve_beam_label(Dest))); runtime_call<2>(beam_jit_wait_unlocked); emit_leave_runtime(); - abs_jmp(ga->get_do_schedule()); + a.jmp(resolve_fragment(ga->get_do_schedule())); } -void BeamModuleAssembler::emit_wait_locked(const ArgVal &Dest) { +void BeamModuleAssembler::emit_wait_locked(const ArgLabel &Dest) { emit_enter_runtime(); a.mov(ARG1, c_p); - a.lea(ARG2, x86::qword_ptr(labels[Dest.getValue()])); + a.lea(ARG2, x86::qword_ptr(resolve_beam_label(Dest))); runtime_call<2>(beam_jit_wait_locked); emit_leave_runtime(); - abs_jmp(ga->get_do_schedule()); + a.jmp(resolve_fragment(ga->get_do_schedule())); } -void BeamModuleAssembler::emit_wait_timeout_unlocked(const ArgVal &Src, - const ArgVal &Dest) { +void BeamModuleAssembler::emit_wait_timeout_unlocked(const ArgSource &Src, + const ArgLabel &Dest) { emit_enter_runtime(); a.mov(ARG1, c_p); @@ -349,8 +350,8 @@ void BeamModuleAssembler::emit_wait_timeout_unlocked(const ArgVal &Src, emit_wait_timeout_locked(Src, Dest); } -void BeamModuleAssembler::emit_wait_timeout_locked(const ArgVal &Src, - const ArgVal &Dest) { +void BeamModuleAssembler::emit_wait_timeout_locked(const ArgSource &Src, + const ArgLabel &Dest) { Label wait = a.newLabel(), next = a.newLabel(); mov_arg(ARG2, Src); @@ -372,7 +373,7 @@ void BeamModuleAssembler::emit_wait_timeout_locked(const ArgVal &Src, a.short_().jl(next); #endif - emit_handle_error(currLabel, (ErtsCodeMFA *)nullptr); + emit_raise_exception(current_label, (ErtsCodeMFA *)nullptr); a.bind(wait); emit_wait_locked(Dest); diff --git a/erts/emulator/beam/jit/x86/instr_select.cpp b/erts/emulator/beam/jit/x86/instr_select.cpp index 0784eb5bd2e1..529e1f4f01c7 100644 --- a/erts/emulator/beam/jit/x86/instr_select.cpp +++ b/erts/emulator/beam/jit/x86/instr_select.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -24,79 +24,89 @@ using namespace asmjit; void BeamModuleAssembler::emit_linear_search(x86::Gp comparand, const ArgVal &Fail, - const std::vector &args) { + const Span &args) { int count = args.size() / 2; for (int i = 0; i < count; i++) { - const ArgVal &value = args[i]; - const ArgVal &label = args[i + count]; + const ArgImmed &value = args[i]; + const ArgLabel &label = args[i + count]; cmp_arg(comparand, value, ARG1); - a.je(labels[label.getValue()]); + a.je(resolve_beam_label(label)); } - if (Fail.getType() == ArgVal::f) { - a.jmp(labels[Fail.getValue()]); + if (Fail.isLabel()) { + a.jmp(resolve_beam_label(Fail)); } else { /* NIL means fallthrough to the next instruction. */ - ASSERT(Fail.getType() == ArgVal::i && Fail.getValue() == NIL); + ASSERT(Fail.isNil()); } } -void BeamModuleAssembler::emit_i_select_tuple_arity( - const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Size, - const std::vector &args) { +void BeamModuleAssembler::emit_i_select_tuple_arity(const ArgRegister &Src, + const ArgLabel &Fail, + const ArgWord &Size, + const Span &args) { mov_arg(ARG2, Src); - emit_is_boxed(labels[Fail.getValue()], ARG2); + + emit_is_boxed(resolve_beam_label(Fail), Src, ARG2); + x86::Gp boxed_ptr = emit_ptr_val(ARG2, ARG2); ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); a.mov(ARG2d, emit_boxed_val(boxed_ptr, 0, sizeof(Uint32))); - ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); - a.test(ARG2.r8(), imm(_TAG_HEADER_MASK)); - a.jne(labels[Fail.getValue()]); + + if (masked_types(Src) == BeamTypeId::Tuple) { + comment("simplified tuple test since the source is always a tuple " + "when boxed"); + } else { + ERTS_CT_ASSERT(_TAG_HEADER_ARITYVAL == 0); + a.test(ARG2.r8(), imm(_TAG_HEADER_MASK)); + a.jne(resolve_beam_label(Fail)); + } ERTS_CT_ASSERT(Support::isInt32(make_arityval(MAX_ARITYVAL))); int count = args.size() / 2; for (int i = 0; i < count; i++) { - const ArgVal &value = args[i]; - const ArgVal &label = args[i + count]; + const ArgImmed &value = args[i]; + const ArgLabel &label = args[i + count]; - a.cmp(ARG2d, imm(value.getValue())); - a.je(labels[label.getValue()]); + a.cmp(ARG2d, imm(value.get())); + a.je(resolve_beam_label(label)); } - a.jne(labels[Fail.getValue()]); + a.jne(resolve_beam_label(Fail)); } -void BeamModuleAssembler::emit_i_select_val_lins( - const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Size, - const std::vector &args) { - ASSERT(Size.getValue() == args.size()); +void BeamModuleAssembler::emit_i_select_val_lins(const ArgSource &Src, + const ArgVal &Fail, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + mov_arg(ARG2, Src); - if (emit_optimized_three_way_select(Fail, args)) + + if (emit_optimized_three_way_select(Fail, args)) { return; + } + emit_linear_search(ARG2, Fail, args); } -void BeamModuleAssembler::emit_i_select_val_bins( - const ArgVal &Src, - const ArgVal &Fail, - const ArgVal &Size, - const std::vector &args) { - ASSERT(Size.getValue() == args.size()); +void BeamModuleAssembler::emit_i_select_val_bins(const ArgSource &Src, + const ArgVal &Fail, + const ArgWord &Size, + const Span &args) { + ASSERT(Size.get() == args.size()); + int count = args.size() / 2; Label fail; - if (Fail.getType() == ArgVal::f) { - fail = labels[Fail.getValue()]; + if (Fail.isLabel()) { + fail = resolve_beam_label(Fail); } else { /* NIL means fallthrough to the next instruction. */ - ASSERT(Fail.getType() == ArgVal::i && Fail.getValue() == NIL); + ASSERT(Fail.isNil()); fail = a.newLabel(); } @@ -104,7 +114,7 @@ void BeamModuleAssembler::emit_i_select_val_bins( comment("Binary search in table of %lu elements", count); emit_binsearch_nodes(0, count - 1, Fail, args); - if (Fail.getType() == ArgVal::i) { + if (Fail.isNil()) { a.bind(fail); } } @@ -115,15 +125,15 @@ void BeamModuleAssembler::emit_i_select_val_bins( * * ARG2 is the value being looked up. */ -void BeamModuleAssembler::emit_binsearch_nodes( - size_t Left, - size_t Right, - const ArgVal &Fail, - const std::vector &args) { +void BeamModuleAssembler::emit_binsearch_nodes(size_t Left, + size_t Right, + const ArgVal &Fail, + const Span &args) { ASSERT(Left <= Right); ASSERT(Right < args.size() / 2); size_t mid = (Left + Right) >> 1; - ArgVal midval(ArgVal::i, args[mid].getValue()); + const ArgImmed midval = args[mid]; + int count = args.size() / 2; size_t remaining = (Right - Left + 1); @@ -147,8 +157,10 @@ void BeamModuleAssembler::emit_binsearch_nodes( args.begin() + Left + count, args.begin() + count + Left + remaining); - if (!emit_optimized_three_way_select(Fail, shrunk)) + if (!emit_optimized_three_way_select(Fail, shrunk)) { emit_linear_search(ARG2, Fail, shrunk); + } + return; } @@ -156,15 +168,15 @@ void BeamModuleAssembler::emit_binsearch_nodes( cmp_arg(ARG2, midval, ARG1); if (Left == Right) { - a.je(labels[args[mid + count].getValue()]); - a.jmp(labels[Fail.getValue()]); + a.je(resolve_beam_label(args[mid + count])); + a.jmp(resolve_beam_label(Fail)); return; } - a.je(labels[args[mid + count].getValue()]); + a.je(resolve_beam_label(args[mid + count])); if (Left == mid) { - a.jb(labels[Fail.getValue()]); + a.jb(resolve_beam_label(Fail)); } else { Label right_tree = a.newLabel(); a.ja(right_tree); @@ -175,15 +187,15 @@ void BeamModuleAssembler::emit_binsearch_nodes( emit_binsearch_nodes(mid + 1, Right, Fail, args); } -void BeamModuleAssembler::emit_i_jump_on_val(const ArgVal &Src, +void BeamModuleAssembler::emit_i_jump_on_val(const ArgSource &Src, const ArgVal &Fail, - const ArgVal &Base, - const ArgVal &Size, - const std::vector &args) { + const ArgWord &Base, + const ArgWord &Size, + const Span &args) { Label data = embed_vararg_rodata(args, 0); Label fail; - ASSERT(Size.getValue() == args.size()); + ASSERT(Size.get() == args.size()); mov_arg(ARG1, Src); @@ -191,29 +203,30 @@ void BeamModuleAssembler::emit_i_jump_on_val(const ArgVal &Src, a.and_(RETb, imm(_TAG_IMMED1_MASK)); a.cmp(RETb, imm(_TAG_IMMED1_SMALL)); - if (Fail.getType() == ArgVal::f) { - a.jne(labels[Fail.getValue()]); + if (Fail.isLabel()) { + a.jne(resolve_beam_label(Fail)); } else { /* NIL means fallthrough to the next instruction. */ - ASSERT(Fail.getType() == ArgVal::i && Fail.getValue() == NIL); + ASSERT(Fail.isNil()); + fail = a.newLabel(); a.short_().jne(fail); } a.sar(ARG1, imm(_TAG_IMMED1_SIZE)); - if (Base.getValue() != 0) { - if (Support::isInt32((Sint)Base.getValue())) { - a.sub(ARG1, imm(Base.getValue())); + if (Base.get() != 0) { + if (Support::isInt32((Sint)Base.get())) { + a.sub(ARG1, imm(Base.get())); } else { - a.mov(ARG2, imm(Base.getValue())); + a.mov(ARG2, imm(Base.get())); a.sub(ARG1, ARG2); } } a.cmp(ARG1, imm(args.size())); - if (Fail.getType() == ArgVal::f) { - a.jae(labels[Fail.getValue()]); + if (Fail.isLabel()) { + a.jae(resolve_beam_label(Fail)); } else { a.short_().jae(fail); } @@ -221,7 +234,7 @@ void BeamModuleAssembler::emit_i_jump_on_val(const ArgVal &Src, a.lea(RET, x86::qword_ptr(data)); a.jmp(x86::qword_ptr(RET, ARG1, 3)); - if (Fail.getType() == ArgVal::i) { + if (Fail.isNil()) { a.bind(fail); } } @@ -241,15 +254,16 @@ void BeamModuleAssembler::emit_i_jump_on_val(const ArgVal &Src, */ bool BeamModuleAssembler::emit_optimized_three_way_select( const ArgVal &Fail, - const std::vector &args) { - if (args.size() != 4 || (args[2].getValue() != args[3].getValue())) + const Span &args) { + if (args.size() != 4 || (args[2] != args[3])) { return false; + } - uint64_t x = args[0].getValue(); - uint64_t y = args[1].getValue(); + uint64_t x = args[0].as().get(); + uint64_t y = args[1].as().get(); uint64_t combined = x | y; uint64_t diff = x ^ y; - ArgVal val(ArgVal::i, combined); + ArgVal val(ArgVal::Immediate, combined); if ((diff & (diff - 1)) != 0) return false; @@ -265,13 +279,16 @@ bool BeamModuleAssembler::emit_optimized_three_way_select( a.mov(ARG1, imm(diff)); a.or_(ARG2, ARG1); } + cmp_arg(ARG2, val, ARG1); - a.je(labels[args[2].getValue()]); - if (Fail.getType() == ArgVal::f) { - a.jmp(labels[Fail.getValue()]); + a.je(resolve_beam_label(args[2])); + + if (Fail.isLabel()) { + a.jmp(resolve_beam_label(Fail)); } else { /* NIL means fallthrough to the next instruction. */ - ASSERT(Fail.getType() == ArgVal::i && Fail.getValue() == NIL); + ASSERT(Fail.isNil()); } + return true; } diff --git a/erts/emulator/beam/jit/x86/instr_trace.cpp b/erts/emulator/beam/jit/x86/instr_trace.cpp index 02f76300f0f7..f6d7937f4e95 100644 --- a/erts/emulator/beam/jit/x86/instr_trace.cpp +++ b/erts/emulator/beam/jit/x86/instr_trace.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2020-2021. All Rights Reserved. + * Copyright Ericsson AB 2020-2023. 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. @@ -31,15 +31,20 @@ extern "C" * * RET = export entry */ void BeamGlobalAssembler::emit_generic_bp_global() { - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); a.lea(ARG2, x86::qword_ptr(RET, offsetof(Export, info))); load_x_reg_array(ARG3); runtime_call<3>(erts_generic_breakpoint); - emit_leave_runtime(); + emit_leave_runtime(); + /* This is technically a tail call so we must leave the current frame + * before jumping. Note that we might not leave the frame we entered + * earlier this function, but one added by `erts_generic_breakpoint`. */ + emit_leave_frame(); a.jmp(RET); } @@ -52,8 +57,14 @@ void BeamGlobalAssembler::emit_generic_bp_local() { emit_assert_erlang_stack(); #ifdef NATIVE_ERLANG_STACK - /* Since we've entered here on the Erlang stack, we need to stash our return - * addresses in case `erts_generic_breakpoint` pushes any trace frames. */ + /* Since we've entered here on the Erlang stack, we need to stash our + * return addresses in case `erts_generic_breakpoint` pushes any trace + * frames. + * + * Note that both of these are return addresses even when frame pointers + * are enabled due to the way the breakpoint trampoline works. They must + * not be restored until we're ready to return to module code, lest we + * leave the stack in an inconsistent state. */ a.pop(TMP_MEM2q); a.pop(ARG2); #else @@ -81,23 +92,31 @@ void BeamGlobalAssembler::emit_generic_bp_local() { } #endif - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); a.mov(ARG1, c_p); /* ARG2 is already set above */ load_x_reg_array(ARG3); runtime_call<3>(erts_generic_breakpoint); - emit_leave_runtime(); + emit_leave_runtime(); + + /* This doesn't necessarily leave the frame entered above: see the + * corresponding comment in `generic_bp_global` */ + emit_leave_frame(); + + a.cmp(RET, imm(BeamOpCodeAddr(op_i_debug_breakpoint))); + a.je(labels[debug_bp]); #ifdef NATIVE_ERLANG_STACK + /* Note that we don't restore our return addresses in the `debug_bp` case + * above, since it tail calls the error handler and thus never returns to + * module code or `call_nif_early`. */ a.push(TMP_MEM1q); a.push(TMP_MEM2q); #endif - a.cmp(RET, imm(BeamOpCodeAddr(op_i_debug_breakpoint))); - a.je(labels[debug_bp]); - a.ret(); } @@ -108,9 +127,16 @@ void BeamGlobalAssembler::emit_generic_bp_local() { void BeamGlobalAssembler::emit_debug_bp() { Label error = a.newLabel(); +#ifndef NATIVE_ERLANG_STACK + /* We're never going to return to module code, so we have to discard the + * return addresses added by the breakpoint trampoline. */ + a.add(x86::rsp, imm(sizeof(ErtsCodePtr[2]))); +#endif + emit_assert_erlang_stack(); - emit_enter_runtime(); + emit_enter_frame(); + emit_enter_runtime(); /* Read and adjust the return address we saved in generic_bp_local. */ a.mov(ARG2, TMP_MEM1q); @@ -122,24 +148,18 @@ void BeamGlobalAssembler::emit_debug_bp() { a.mov(ARG4, imm(am_breakpoint)); runtime_call<4>(call_error_handler); - emit_leave_runtime(); - - /* Skip two frames so we can make a direct jump to the error handler. This - * makes it so that if we are to do a call_nif_early, we skip that and call - * the error handler's code instead, mirroring the way the interpreter - * works. */ - emit_discard_cp(); - emit_discard_cp(); + emit_leave_runtime(); + emit_leave_frame(); a.test(RET, RET); a.je(error); - a.jmp(emit_setup_export_call(RET)); + a.jmp(emit_setup_dispatchable_call(RET)); a.bind(error); { a.mov(ARG2, TMP_MEM1q); - a.jmp(labels[handle_error_shared]); + a.jmp(labels[raise_exception]); } } @@ -157,75 +177,51 @@ void BeamModuleAssembler::emit_return_trace() { a.mov(ARG3, getXRef(0)); a.lea(ARG4, getYRef(1)); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); runtime_call<4>(return_trace); - emit_leave_runtime(); + emit_leave_runtime(); - emit_deallocate(ArgVal(ArgVal::u, 2)); + emit_deallocate(ArgWord(BEAM_RETURN_TRACE_FRAME_SZ)); emit_return(); } -void BeamModuleAssembler::emit_i_return_time_trace() { +void BeamModuleAssembler::emit_i_call_trace_return() { /* Pass prev_info if present (is a CP), otherwise null. */ a.mov(ARG2, getYRef(0)); - mov_imm(ARG3, 0); + mov_imm(ARG4, 0); a.test(ARG2, imm(_CPMASK)); a.lea(ARG2, x86::qword_ptr(ARG2, -(Sint)sizeof(ErtsCodeInfo))); - a.cmovnz(ARG2, ARG3); + a.cmovnz(ARG2, ARG4); + a.mov(ARG3, getYRef(1)); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); - runtime_call<2>(erts_trace_time_return); + runtime_call<3>(erts_call_trace_return); - emit_leave_runtime(); + emit_leave_runtime(); - emit_deallocate(ArgVal(ArgVal::u, 1)); + emit_deallocate(ArgWord(BEAM_RETURN_CALL_ACC_TRACE_FRAME_SZ)); emit_return(); } -static void i_return_to_trace(Process *c_p) { - if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO)) { - Uint *cpp = (Uint *)c_p->stop; - while (is_not_CP(*cpp)) { - cpp++; - } - for (;;) { - ErtsCodePtr w = cp_val(*cpp); - if (BeamIsReturnTrace(w)) { - do - ++cpp; - while (is_not_CP(*cpp)); - cpp += 2; - } else if (BeamIsReturnToTrace(w)) { - do - ++cpp; - while (is_not_CP(*cpp)); - } else { - break; - } - } - ERTS_UNREQ_PROC_MAIN_LOCK(c_p); - erts_trace_return_to(c_p, cp_val(*cpp)); - ERTS_REQ_PROC_MAIN_LOCK(c_p); - } -} - void BeamModuleAssembler::emit_i_return_to_trace() { - emit_enter_runtime(); + /* Remove our stack frame so that `beam_jit_return_to_trace` can inspect + * the next one. + * + * (This doesn't do anything if the native stack is used.) */ + emit_deallocate(ArgWord(BEAM_RETURN_TO_TRACE_FRAME_SZ)); - a.mov(ARG1, c_p); - runtime_call<1>(i_return_to_trace); + emit_enter_runtime(); - emit_leave_runtime(); + a.mov(ARG1, c_p); + runtime_call<1>(beam_jit_return_to_trace); - /* Remove the zero-sized stack frame. (Will actually do nothing if - * the native stack is used.) */ - emit_deallocate(ArgVal(ArgVal::u, 0)); + emit_leave_runtime(); emit_return(); } @@ -233,13 +229,13 @@ void BeamModuleAssembler::emit_i_return_to_trace() { void BeamModuleAssembler::emit_i_hibernate() { Label error = a.newLabel(); - emit_enter_runtime(); + emit_enter_runtime(); a.mov(ARG1, c_p); load_x_reg_array(ARG2); runtime_call<2>(erts_hibernate); - emit_leave_runtime(); + emit_leave_runtime(); a.test(RET, RET); a.je(error); @@ -247,8 +243,8 @@ void BeamModuleAssembler::emit_i_hibernate() { a.mov(ARG1, x86::qword_ptr(c_p, offsetof(Process, flags))); a.and_(ARG1, imm(~F_HIBERNATE_SCHED)); a.mov(x86::qword_ptr(c_p, offsetof(Process, flags)), ARG1); - abs_jmp(ga->get_do_schedule()); + a.jmp(resolve_fragment(ga->get_do_schedule())); a.bind(error); - emit_handle_error(&BIF_TRAP_EXPORT(BIF_hibernate_3)->info.mfa); + emit_raise_exception(&BIF_TRAP_EXPORT(BIF_hibernate_3)->info.mfa); } diff --git a/erts/emulator/beam/jit/x86/ops.tab b/erts/emulator/beam/jit/x86/ops.tab index 8f944220b69f..ef57021d837b 100644 --- a/erts/emulator/beam/jit/x86/ops.tab +++ b/erts/emulator/beam/jit/x86/ops.tab @@ -37,7 +37,7 @@ FORBIDDEN_TYPES=hQ # needs to be re-compiled with a modern compiler. too_old_compiler/0 -too_old_compiler | never() => +too_old_compiler | never() => _ # In R9C and earlier, the loader used to insert special instructions inside # the module_info/0,1 functions. (In R10B and later, the compiler inserts @@ -45,8 +45,10 @@ too_old_compiler | never() => # necessary.) Since the instructions don't work correctly in R12B, simply # refuse to load the module. -func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler -func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler +func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => + too_old_compiler +func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => + too_old_compiler # The undocumented and unsupported guard BIF is_constant/1 was removed # in R13. The is_constant/2 operation is marked as obsolete in genop.tab, @@ -55,12 +57,6 @@ func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compil bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler -# Since the constant pool was introduced in R12B, empty tuples ({}) -# are literals. Therefore we no longer need to allow put_tuple/2 -# with a tuple size of zero. - -put_tuple u==0 d => too_old_compiler - # # All the other instructions. # @@ -81,10 +77,11 @@ aligned_label L t i_func_info I a a I int_code_end +nif_start i_generic_breakpoint i_debug_breakpoint -i_return_time_trace +i_call_trace_return i_return_to_trace trace_jump W i_yield @@ -97,14 +94,14 @@ return # BIF, so we can omit the line instruction for non-BIFs. # -move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ +move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => move S X0 | call_ext_last Ar Func D -move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \ +move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => move S X0 | call_ext_only Ar Func -move S X0=x==0 | line Loc | call_last Ar Func D => \ +move S X0=x==0 | line Loc | call_last Ar Func D => move S X0 | call_last Ar Func D -move S X0=x==0 | line Loc | call_only Ar Func => \ +move S X0=x==0 | line Loc | call_only Ar Func => move S X0 | call_only Ar Func # The line number in int_func_start/5 can be NIL. @@ -113,11 +110,11 @@ func_line n => empty_func_line empty_func_line func_line I -line n => +line n => _ line I -allocate t t? -allocate_heap t I t? +allocate t t +allocate_heap t I t deallocate t @@ -127,7 +124,7 @@ trim N Remaining => i_trim N i_trim t -test_heap I t? +test_heap I t # Translate instructions generated by a compiler before OTP 24. allocate_zero Ns Live => allocate_heap_zero Ns u Live @@ -141,59 +138,74 @@ init_yregs I * # bytes. Therefore we shouldn't use a jump table if there are too few # values. -select_val S Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \ - jump_tab(S, Fail, Size, Rest) -is_integer Fail=f S | select_val S=s Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \ - jump_tab(S, Fail, Size, Rest) +select_val S Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => + jump_tab(S, Fail, Size, Rest) + +is_integer Fail=f S | select_val S2=s Fail2=fn Size=u Rest=* | + equal(S, S2) | equal(Fail, Fail2) | + use_jump_tab(Size, Rest, 6) => + jump_tab(S, Fail, Size, Rest) -is_integer TypeFail=f S | select_val S=s Fail=fn Size=u Rest=* | \ - mixed_types(Size, Rest) => \ - split_values(S, TypeFail, Fail, Size, Rest) +is_integer TypeFail=f S | select_val S2=s Fail=fn Size=u Rest=* | + equal(S, S2) | + mixed_types(Size, Rest) => + split_values(S, TypeFail, Fail, Size, Rest) -select_val S Fail=fn Size=u Rest=* | mixed_types(Size, Rest) => \ - split_values(S, Fail, Fail, Size, Rest) +select_val S Fail=fn Size=u Rest=* | mixed_types(Size, Rest) => + split_values(S, Fail, Fail, Size, Rest) -is_integer Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \ - fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) +is_integer Fail=f S | select_val S2=d Fail2=fn Size=u Rest=* | + equal(S, S2) | equal(Fail, Fail2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -is_atom Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \ - fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) +is_atom Fail=f S | select_val S2=d Fail2=fn Size=u Rest=* | + equal(S, S2) | equal(Fail, Fail2) | + fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -select_val S Fail=fn Size=u Rest=* | floats_or_bignums(Size, Rest) => \ - select_literals(S, Fail, Size, Rest) +select_val S Fail=fn Size=u Rest=* | floats_or_bignums(Size, Rest) => + select_literals(S, Fail, Size, Rest) -select_val S Fail=fn Size=u Rest=* | fixed_size_values(Size, Rest) => \ - select_val(S, Fail, Size, Rest) +select_val S Fail=fn Size=u Rest=* | fixed_size_values(Size, Rest) => + select_val(S, Fail, Size, Rest) -is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \ - select_tuple_arity(S, Fail, Size, Rest) +is_tuple Fail=f S | select_tuple_arity S2=d Fail2=f Size=u Rest=* | + equal(S, S2) | equal(Fail, Fail2) => + select_tuple_arity(S, Fail, Size, Rest) -select_tuple_arity S=d Fail=f Size=u Rest=* => \ - select_tuple_arity(S, Fail, Size, Rest) +select_tuple_arity S=d Fail=f Size=u Rest=* => + select_tuple_arity(S, Fail, Size, Rest) i_select_val_bins s fn I * i_select_val_lins s fn I * -i_select_tuple_arity S f? I * +i_select_tuple_arity S f I * i_jump_on_val s fn W I * -is_number f? s +is_number f s jump f # -# List matching instructions. The combination of test for a nonempty list followed -# by get_{list/hd/tl} are common, so we will optimize that. +# List matching instructions. The combination of test for a nonempty list +# followed by get_{list/hd/tl} are common, so we will optimize that. # is_nonempty_list Fail nqia => jump Fail -is_nonempty_list Fail Src | get_list Src Hd Tl => is_nonempty_list_get_list Fail Src Hd Tl -is_nonempty_list Fail Src | get_hd Src Hd => is_nonempty_list_get_hd Fail Src Hd -is_nonempty_list Fail Src | get_tl Src Tl => is_nonempty_list_get_tl Fail Src Tl -is_nonempty_list f? S +is_nonempty_list Fail Src | get_list Src2 Hd Tl | equal(Src, Src2) => + is_nonempty_list_get_list Fail Src Hd Tl + +is_nonempty_list Fail Src | get_hd Src2 Hd | equal(Src, Src2) => + is_nonempty_list_get_hd Fail Src Hd + +is_nonempty_list Fail Src | get_tl Src2 Tl | equal(Src, Src2) => + is_nonempty_list_get_tl Fail Src Tl + +is_nonempty_list f S get_list S d d get_hd S d @@ -221,63 +233,79 @@ set_tuple_element s S P # # Get tuple element. Since this instruction is frequently used, we will try -# to only fetch the pointer to the tuple once for a sequence of BEAM instructions -# that fetch multiple elements from the same tuple. +# to only fetch the pointer to the tuple once for a sequence of BEAM +# instructions that fetch multiple elements from the same tuple. # current_tuple/1 current_tuple/2 -is_tuple Fail=f Src | test_arity Fail Src Arity => \ - i_is_tuple_of_arity Fail Src Arity | current_tuple Src +is_tuple Fail=f Src | test_arity Fail2 Src2 Arity | + equal(Fail, Fail2) | equal(Src, Src2) => + i_is_tuple_of_arity Fail Src Arity | current_tuple Src test_arity Fail Src Arity => i_test_arity Fail Src Arity | current_tuple Src -is_tuple NotTupleFail Tuple | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \ - i_is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom | current_tuple Tuple +is_tuple NotTupleFail Src | + is_tagged_tuple WrongRecordFail Tuple Arity Atom | + equal(Src, Tuple) => + i_is_tagged_tuple_ff NotTupleFail WrongRecordFail Src Arity Atom | + current_tuple Src -is_tagged_tuple Fail Tuple Arity Atom => \ - i_is_tagged_tuple Fail Tuple Arity Atom | current_tuple Tuple +is_tagged_tuple Fail Tuple Arity Atom => + i_is_tagged_tuple Fail Tuple Arity Atom | current_tuple Tuple is_tuple Fail=f Src => i_is_tuple Fail Src | current_tuple Src -i_is_tuple_of_arity f? s A -i_test_arity f? s A +i_is_tuple_of_arity f s A +i_test_arity f s A -i_is_tagged_tuple f? s A a -i_is_tagged_tuple_ff f? f? s A a +i_is_tagged_tuple f s A a +i_is_tagged_tuple_ff f f s A a -i_is_tuple f? s +i_is_tuple f s # Generate instruction sequence for fetching the tuple element and remember # that we have a current tuple pointer. -get_tuple_element Tuple Pos Dst => \ - load_tuple_ptr Tuple | i_get_tuple_element Tuple Pos Dst | current_tuple Tuple -current_tuple Tuple | get_tuple_element Tuple Pos Dst => \ - i_get_tuple_element Tuple Pos Dst | current_tuple Tuple +get_tuple_element Tuple Pos Dst => + load_tuple_ptr Tuple | + i_get_tuple_element Tuple Pos Dst | + current_tuple Tuple + +current_tuple Tuple | get_tuple_element Tuple2 Pos Dst | + equal(Tuple, Tuple2) => + i_get_tuple_element Tuple Pos Dst | current_tuple Tuple # Drop the current_tuple instruction if the tuple is overwritten. -i_get_tuple_element Tuple Pos Tuple | current_tuple Tuple => i_get_tuple_element Tuple Pos Tuple +i_get_tuple_element Tuple Pos Tuple2 | current_tuple Tuple3 | + equal(Tuple, Tuple2) | equal(Tuple, Tuple3) => + i_get_tuple_element Tuple Pos Tuple -# This is a current_tuple instruction instruction not followed by get_tuple_element. -# Invalidate the current tuple pointer. +# This is a current_tuple instruction instruction not followed by +# get_tuple_element. Invalidate the current tuple pointer. -current_tuple Tuple => +current_tuple Tuple => _ load_tuple_ptr s # If both positions and destinations are in consecutive memory, fetch and store # two words at once. -i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \ - get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst1, Pos2, Dst2) => \ - get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 -i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \ - get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst2, Pos2, Dst1) => \ - get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 +i_get_tuple_element Tuple Pos1 Dst1 | + current_tuple Tuple2 | + get_tuple_element Tuple3 Pos2 Dst2 | + equal(Tuple, Tuple2) | equal(Tuple, Tuple3) | + consecutive_words(Pos1, Dst1, Pos2, Dst2) => + get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 + +i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple2 | + get_tuple_element Tuple3 Pos2 Dst2 | + equal(Tuple, Tuple2) | equal(Tuple, Tuple3) | + consecutive_words(Pos1, Dst2, Pos2, Dst1) => + get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 # Drop the current_tuple instruction if the tuple is overwritten. -current_tuple Tuple Tuple => +current_tuple Tuple Tuple2 | equal(Tuple, Tuple2) => _ current_tuple Tuple Dst => current_tuple Tuple # The first operand will only be used in the debug-compiled runtime @@ -286,8 +314,16 @@ current_tuple Tuple Dst => current_tuple Tuple i_get_tuple_element s P S get_two_tuple_elements s P S S +i_get_tuple_element Tuple Pos Dst | swap Reg1 Reg2 | equal(Dst, Reg1) => + get_tuple_element_swap Tuple Pos Dst Reg2 + +i_get_tuple_element Tuple Pos Dst | swap Reg2 Reg1 | equal(Dst, Reg1) => + get_tuple_element_swap Tuple Pos Dst Reg2 + +get_tuple_element_swap s P d d + # -# Expection rasing instructions. Infrequently executed. +# Exception raising instructions. Infrequently executed. # %cold @@ -297,11 +333,14 @@ badmatch s if_end +badrecord s + raise s s -# Workaround the limitation that generators must always return at least one instruction. +# Workaround the limitation that generators must always return at least one +# instruction. delete_me/0 -delete_me => +delete_me => _ system_limit/1 system_limit p => system_limit_body @@ -317,16 +356,21 @@ system_limit_body move Src=c Dst => i_move Src Dst -move Src SrcDst | move SrcDst Dst => i_move Src SrcDst | move SrcDst Dst +move Src SrcDst | move SrcDst2 Dst | equal(SrcDst, SrcDst2) => + i_move Src SrcDst | move SrcDst Dst # Try to move two words at once. Always arrange the source operands in # consecutive order; the destination operands may be in consecutive or # reverse consecutive order. -move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D1, S2, D2) => move_two_words S1 D1 S2 D2 -move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D2, S2, D1) => move_two_words S1 D1 S2 D2 -move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D1, S1, D2) => move_two_words S2 D2 S1 D1 -move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D2, S1, D1) => move_two_words S2 D2 S1 D1 +move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D1, S2, D2) => + move_two_words S1 D1 S2 D2 +move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D2, S2, D1) => + move_two_words S1 D1 S2 D2 +move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D1, S1, D2) => + move_two_words S2 D2 S1 D1 +move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D2, S1, D1) => + move_two_words S2 D2 S1 D1 move Src Dst => i_move Src Dst @@ -347,26 +391,26 @@ move_two_words s d s d # pointers. # -label L | loop_rec Fail Reg => \ +label L | loop_rec Fail Reg => aligned_label L u=4 | loop_rec Fail Reg -label L | wait_timeout Fail Src => \ +label L | wait_timeout Fail Src => aligned_label L u=4 | wait_timeout Fail Src -label L | wait Fail => \ +label L | wait Fail => aligned_label L u=4 | wait Fail -label L | timeout => \ +label L | timeout => aligned_label L u=4 | timeout loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail -aligned_label L A | wait_timeout Fail Src | smp_already_locked(L) => \ +aligned_label L A | wait_timeout Fail Src | smp_already_locked(L) => aligned_label L A | wait_timeout_locked Src Fail wait_timeout Fail Src => wait_timeout_unlocked Src Fail -aligned_label L A | wait Fail | smp_already_locked(L) => \ +aligned_label L A | wait Fail | smp_already_locked(L) => aligned_label L A | wait_locked Fail wait Fail => wait_unlocked Fail -aligned_label L A | timeout | smp_already_locked(L) => \ +aligned_label L A | timeout | smp_already_locked(L) => aligned_label L A | timeout_locked remove_message @@ -387,40 +431,61 @@ send # Optimized comparisons with one immediate/literal operand. # -is_eq_exact Lbl S S => +is_eq_exact Lbl LHS RHS | equal(LHS, RHS) => _ is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C is_eq_exact Lbl R=xy n => is_nil Lbl R -is_eq_exact Lbl R=xy C=ia => i_is_eq_exact_immed Lbl R C -is_eq_exact Lbl R=xy C=q => is_eq_exact_literal(Lbl, R, C) -is_ne_exact Lbl S S => jump Lbl +is_ne_exact Lbl LHS RHS | equal(LHS, RHS) => jump Lbl is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C -is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C -is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C +is_eq_exact f s s + +is_ne_exact f s s -i_is_eq_exact_immed f? s c +is_integer NotInt N0 | is_ge Small N1=xy Min=i | is_ge Large Max=i N2=xy | + equal(N0, N1) | equal(N1, N2) | + equal(NotInt, Small) | equal(Small, Large) => + is_int_in_range NotInt N0 Min Max -i_is_eq_exact_literal/4 -i_is_eq_exact_literal f? s c I +is_integer NotInt N0 | is_ge Large Max=i N2=xy | is_ge Small N1=xy Min=i | + equal(N0, N1) | equal(N1, N2) | + equal(NotInt, Small) | equal(Small, Large) => + is_int_in_range NotInt N0 Min Max -i_is_ne_exact_immed f? s c +is_integer NotInt N0 | is_ge Fail N1=xy Min=i | + equal(N0, N1) | equal(NotInt, Fail) => + is_int_ge NotInt N0 Min -i_is_ne_exact_literal f? s c +is_int_in_range f S c c +is_int_ge f S c -is_eq_exact f? s s +is_ge Small N1=xy Min=i | is_ge Large Max=i N2=xy | equal(N1, N2) => + is_in_range Small Large N1 Min Max -is_ne_exact f? s s +is_ge Large Max=i N2=xy | is_ge Small N1=xy Min=i | equal(N1, N2) => + is_in_range Small Large N2 Min Max -is_lt f? s s -is_ge f? s s +is_in_range f f S c c + +is_ge Small N1=xy A=i | is_lt Large B=i N2=xy | equal(N1, N2) => + is_ge_lt Small Large N1 A B + +is_ge_lt f f S c c + +is_ge Fail1 N1=xy A=i | is_ge Fail2 N2=xy B=i | equal(N1, N2) => + is_ge_ge Fail1 Fail2 N1 A B + +is_ge_ge f f S c c + +is_lt f s s +is_ge f s s is_eq Fail=f Const=c Reg=xy => is_eq Fail Reg Const -is_eq f? s s +is_eq f s s is_ne Fail=f Const=c Reg=xy => is_ne Fail Reg Const -is_ne f? s s +is_ne f s s # # Putting tuples. @@ -428,21 +493,6 @@ is_ne f? s s # Code compiled with OTP 22 and later uses put_tuple2 to # to construct a tuple. # -# Code compiled before OTP 22 uses put_tuple + one put instruction -# per element. Translate to put_tuple2. -# - -i_put_tuple/2 -put_tuple Arity Dst => i_put_tuple Dst u - -i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \ - put S3 | put S4 | put S5 => \ - tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5) - -i_put_tuple Dst Arity Puts=* | put S => \ - tuple_append_put(Arity, Dst, Puts, S) - -i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts put_tuple2 S A * @@ -452,8 +502,13 @@ put_tuple2 S A * store_cons/2 put_list Hd Tl Dst => put_cons Hd Tl | store_cons u=1 Dst -store_cons Len Dst | put_list Hd Dst Dst | distinct(Dst, Hd) => combine_conses(Len, Dst, Hd) -store_cons Len Dst | put_list Hd Dst OtherDst => store_cons Len Dst | append_cons u Hd | store_cons u=1 OtherDst + +store_cons Len Dst | put_list Hd Tl Dst2 | + equal(Dst, Tl) | equal(Dst, Dst2) | distinct(Dst, Hd) => + combine_conses(Len, Dst, Hd) + +store_cons Len Dst | put_list Hd Tl OtherDst | equal(Dst, Tl) => + store_cons Len Dst | append_cons u Hd | store_cons u=1 OtherDst put_cons s s append_cons I s @@ -470,7 +525,6 @@ call_bif W call_bif_mfa a a I call_nif W W W call_error_handler -error_action_code return_trace %hot @@ -482,28 +536,28 @@ return_trace # older releases and code generated by alternative code generators. # -is_integer f? s -is_list f? s -is_atom f? s -is_float f? s +is_integer f s +is_list f s +is_atom f s +is_float f s -is_nil Fail=f n => +is_nil Fail=f n => _ is_nil Fail=f qia => jump Fail -is_nil f? S +is_nil f S # XXX Deprecated. is_bitstr Fail Term => is_bitstring Fail Term -is_binary f? s -is_bitstring f? s +is_binary f s +is_bitstring f s -is_reference f? s -is_pid f? s -is_port f? s +is_reference f s +is_pid f s +is_port f s -is_boolean f? s +is_boolean f s -is_function2 f? s s +is_function2 f s s ################################################################# # External function and bif calls. @@ -516,17 +570,32 @@ call_light_bif/1 # The load_nif/2 BIF is an instruction. # -call_ext u==2 u$func:erlang:load_nif/2 => \ +call_ext u==2 u$func:erlang:load_nif/2 => i_load_nif -call_ext_last u==2 u$func:erlang:load_nif/2 D => \ +call_ext_last u==2 u$func:erlang:load_nif/2 D => i_load_nif | deallocate D | return -call_ext_only u==2 u$func:erlang:load_nif/2 => \ +call_ext_only u==2 u$func:erlang:load_nif/2 => i_load_nif | return %cold i_load_nif %hot +# +# The call_on_load_function/1 BIF is an instruction. +# + +call_ext u==1 u$func:erlang:call_on_load_function/1 => + i_call_on_load_function +call_ext_last u==1 u$func:erlang:call_on_load_function/1 D => + i_call_on_load_function | deallocate D | return +call_ext_only u==1 u$func:erlang:call_on_load_function/1 => + i_call_on_load_function | return + +%cold +i_call_on_load_function +%hot + # # apply/2 is an instruction, not a BIF. # @@ -558,11 +627,11 @@ call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate -call_ext u==0 u$func:os:perf_counter/0 => \ +call_ext u==0 u$func:os:perf_counter/0 => i_perf_counter -call_ext_last u==0 u$func:os:perf_counter/0 D => \ +call_ext_last u==0 u$func:os:perf_counter/0 D => i_perf_counter | deallocate D | return -call_ext_only u==0 u$func:os:perf_counter/0 => \ +call_ext_only u==0 u$func:os:perf_counter/0 => i_perf_counter | return # @@ -570,22 +639,22 @@ call_ext_only u==0 u$func:os:perf_counter/0 => \ # emulator state, which the ordinary call_light_bif instruction doesn't save. # -call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => \ +call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => i_call_ext Bif -call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => \ +call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => i_call_ext Bif | deallocate D | return -call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => \ +call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => allocate u Ar | i_call_ext Bif | deallocate u | return # # The general case for BIFs that have no special requirements. # -call_ext u Bif=u$is_bif => \ +call_ext u Bif=u$is_bif => call_light_bif Bif -call_ext_last u Bif=u$is_bif D => \ +call_ext_last u Bif=u$is_bif D => call_light_bif Bif | deallocate D | return -call_ext_only Ar=u Bif=u$is_bif => \ +call_ext_only Ar=u Bif=u$is_bif => allocate u Ar | call_light_bif Bif | deallocate u | return # @@ -626,25 +695,50 @@ i_perf_counter bif0 u$bif:erlang:self/0 Dst=d => self Dst bif0 u$bif:erlang:node/0 Dst=d => node Dst -bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=n Dst => \ - jump Fail -bif1 Fail=f Bif=u$bif:erlang:hd/1 Src Dst => \ +bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=xy Dst => is_nonempty_list Fail Src | get_hd Src Dst -bif1 Fail Bif=u$bif:erlang:hd/1 Src Dst => \ - bif_hd Fail Src Dst +bif1 Fail=p Bif=u$bif:erlang:hd/1 Src Dst => + bif_hd Src Dst -bif_hd j? s d +bif_hd s d -bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=n Dst => \ - jump Fail -bif1 Fail=f Bif=u$bif:erlang:tl/1 Src Dst => \ +bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=xy Dst => is_nonempty_list Fail Src | get_tl Src Dst bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst) bif2 Fail u$bif:erlang:element/2 S1=ixy S2 Dst => bif_element Fail S1 S2 Dst +bif_element j s s d + +bif1 Fail Bif=u$bif:erlang:node/1 Src=d Dst=d => bif_node Fail Src Dst +bif_node j S d + +gc_bif1 Fail Live Bif=u$bif:erlang:bit_size/1 Src Dst=d => + bif_bit_size Bif Fail Src Dst +bif_bit_size b j s d + +gc_bif1 Fail Live Bif=u$bif:erlang:byte_size/1 Src Dst=d => + bif_byte_size Bif Fail Src Dst +bif_byte_size b j s d + +bif1 Fail Bif=u$bif:erlang:tuple_size/1 Src=d Dst=d => + bif_tuple_size Bif Fail Src Dst +bif_tuple_size b j S d -bif_element j? s s d +bif2 Fail Bif=u$bif:erlang:map_get/2 Src1 Src2=xy Dst=d => + bif_map_get Fail Src1 Src2 Dst +bif_map_get j s s d + +bif2 Fail Bif=u$bif:erlang:is_map_key/2 Key Map=xy Dst=d => + bif_is_map_key Bif Fail Key Map Dst +bif_is_map_key b j s s d + +bif2 Fail Bif=u$bif:erlang:max/2 Src1 Src2 Dst => + bif_max Src1 Src2 Dst +bif2 Fail Bif=u$bif:erlang:min/2 Src1 Src2 Dst => + bif_min Src1 Src2 Dst +bif_max s s d +bif_min s s d bif1 Fail Bif S1 Dst | never_fails(Bif) => nofail_bif1 S1 Bif Dst bif2 Fail Bif S1 S2 Dst | never_fails(Bif) => nofail_bif2 S1 S2 Bif Dst @@ -652,8 +746,10 @@ bif2 Fail Bif S1 S2 Dst | never_fails(Bif) => nofail_bif2 S1 S2 Bif Dst bif1 Fail Bif S1 Dst => i_bif1 S1 Fail Bif Dst bif2 Fail Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst -nofail_bif2 S1=d S2=ian Bif Dst | is_eq_exact_bif(Bif) => bif_is_eq_exact_immed S1 S2 Dst -nofail_bif2 S1=d S2=ian Bif Dst | is_ne_exact_bif(Bif) => bif_is_ne_exact_immed S1 S2 Dst +nofail_bif2 S1=d S2 Bif Dst | is_eq_exact_bif(Bif) => bif_is_eq_exact S1 S2 Dst +nofail_bif2 S1=d S2 Bif Dst | is_ne_exact_bif(Bif) => bif_is_ne_exact S1 S2 Dst +nofail_bif2 S1 S2 Bif Dst | is_ge_bif(Bif) => bif_is_ge S1 S2 Dst +nofail_bif2 S1 S2 Bif Dst | is_lt_bif(Bif) => bif_is_lt S1 S2 Dst i_get_hash c I d i_get s d @@ -665,12 +761,14 @@ node d nofail_bif1 s b d nofail_bif2 s s b d -i_bif1 s j? b d -i_bif2 s s j? b d -i_bif3 s s s j? b d +i_bif1 s j b d +i_bif2 s s j b d +i_bif3 s s s j b d -bif_is_eq_exact_immed S c d -bif_is_ne_exact_immed S c d +bif_is_eq_exact S s d +bif_is_ne_exact S s d +bif_is_ge s s d +bif_is_lt s s d # # Internal calls. @@ -696,66 +794,77 @@ call_fun Arity => i_call_fun Arity i_call_fun t i_call_fun_last t t +call_fun2 Tag Arity Func | deallocate D | return => + i_call_fun2_last Tag Arity Func D +call_fun2 Tag Arity Func => + i_call_fun2 Tag Arity Func + +i_call_fun2 aF t S +i_call_fun2_last aF t S t + # # A fun with an empty environment can be converted to a literal. # As a further optimization, the we try to move the fun to its # final destination directly. +# + +make_fun2 OldIndex=u => + make_fun2(OldIndex) -make_fun2 OldIndex=u => make_fun2(OldIndex) -make_fun3 OldIndex=u Dst=d NumFree=u Env=* => make_fun3(OldIndex, Dst, NumFree, Env) +make_fun3 OldIndex=u Dst=d NumFree=u Env=* => + make_fun3(OldIndex, Dst, NumFree, Env) %cold -i_make_fun3 F S t * +i_make_fun3 F S t t * # Psuedo-instruction for signalling lambda load errors. Never actually runs. i_lambda_error t %hot -is_function f? S +is_function f S is_function Fail=f c => jump Fail # The start and end of a function. int_func_start/5 -int_func_end/0 +int_func_end/2 func_prologue/2 -int_func_start Func_Label Func_Line M F A | \ - label Entry_Label | line Entry_Line => \ - int_func_start Func_Label Func_Line M F A | \ +int_func_start Func_Label Func_Line M F A | + label Entry_Label | line Entry_Line => + int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label Entry_Line -int_func_start Func_Label Func_Line M F A | \ - label Entry_Label => \ - int_func_start Func_Label Func_Line M F A | \ +int_func_start Func_Label Func_Line M F A | + label Entry_Label => + int_func_start Func_Label Func_Line M F A | func_prologue Entry_Label n -int_func_start Func_Label Func_Line M F A | \ - func_prologue Entry_Label Entry_Line | \ - is_mfa_bif(M, F, A) => \ - aligned_label Func_Label u=8 | \ - func_line Func_Line | \ - i_func_info Func_Label M F A | \ - aligned_label Entry_Label u=8 | \ - line Entry_Line | \ - i_breakpoint_trampoline | \ +int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label Entry_Line | + is_mfa_bif(M, F, A) => + func_line Func_Line | + aligned_label Func_Label u=8 | + i_func_info Func_Label M F A | + aligned_label Entry_Label u=8 | + i_breakpoint_trampoline | + line Entry_Line | call_bif_mfa M F A -int_func_start Func_Label Func_Line M F A | \ - func_prologue Entry_Label Entry_Line => \ - aligned_label Func_Label u=8 | \ - func_line Func_Line | \ - i_func_info Func_Label M F A | \ - aligned_label Entry_Label u=8 | \ - line Entry_Line | \ - i_breakpoint_trampoline | \ +int_func_start Func_Label Func_Line M F A | + func_prologue Entry_Label Entry_Line => + func_line Func_Line | + aligned_label Func_Label u=8 | + i_func_info Func_Label M F A | + aligned_label Entry_Label u=8 | + i_breakpoint_trampoline | + line Entry_Line | i_test_yield - -int_func_end | needs_nif_padding() => i_nif_padding -int_func_end => +int_func_end Func_Label Entry_Label => + func_end(Func_Label, Entry_Label) # Handles yielding on function ingress (rather than on each call). i_test_yield @@ -763,75 +872,74 @@ i_test_yield # Ensures that the prior function is large enough to allow NIF patching. i_nif_padding +# Landing pad for fun calls/apply where we set up arguments and check errors +i_lambda_trampoline F f W W + # Handles tracing, early NIF calls, and so on. i_breakpoint_trampoline # ================================================================ -# Bit syntax matching obsoleted in OTP 22. +# New bit syntax matching for fixed sizes (from OTP 26). # ================================================================ -%cold -bs_start_match2 Fail=f ica X Y D => jump Fail -bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D -i_bs_start_match2 S f t t d +bs_match Fail Ctx Size Rest=* => bs_match(Fail, Ctx, Size, Rest) -bs_save2 Reg Index => bs_save(Reg, Index) -i_bs_save2 x t +i_bs_match Fail Ctx Rest=* | test_heap Need Live => + i_bs_match_test_heap Fail Ctx Need Live Rest -bs_restore2 Reg Index => bs_restore(Reg, Index) -i_bs_restore2 S t +i_bs_match f S * +i_bs_match_test_heap f S I t * -bs_context_to_binary S -%warm +# +# The following instruction is specially handled in beam_load.c +# to produce a user-friendly message if a bad bs_match instruction +# is encountered. +# +bad_bs_match/1 +bad_bs_match A | never() => _ # ================================================================ -# New bit syntax matching (R11B). +# Bit syntax matching (from R11B). # ================================================================ %warm -# Matching integers +# Matching integers. bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val -i_bs_match_string S f W W +i_bs_match_string S f W M # Fetching integers from binaries. -bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ - get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) - -i_bs_get_integer S f? t t s d - -i_bs_get_integer_8 S t f? d -i_bs_get_integer_16 S t f? d -i_bs_get_integer_32 S t f? d -i_bs_get_integer_64 S t f? t d +bs_get_integer2 f S t s t t d # Fetching binaries from binaries. -bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ - get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) +bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => + get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) -i_bs_get_binary2 S f t? s t d -i_bs_get_binary_all2 S f? t t d +i_bs_get_binary2 S f t s t d +i_bs_get_binary_all2 S f t t d # Fetching float from binaries. -bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \ - get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) +bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => + get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail -i_bs_get_float2 S f? t s t d +i_bs_get_float2 S f t s t d + +# Miscellaneous -# Miscellanous +bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => + skip_bits2(Fail, Ms, Sz, Unit, Flags) -bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => \ - skip_bits2(Fail, Ms, Sz, Unit, Flags) +i_bs_skip_bits_imm2 f S W +i_bs_skip_bits2 S S f t -i_bs_skip_bits_imm2 f? S W -i_bs_skip_bits2 S S f? t +bs_test_tail2 Fail=f Ms=xy o => jump Fail -bs_test_tail2 f? S t +bs_test_tail2 f S W -bs_test_unit f? S t +bs_test_unit f S t # Gets a bitstring from the tail of a context. bs_get_tail S d t @@ -842,20 +950,20 @@ bs_get_tail S d t # "slots" in the context itself, which lets us continue matching even after # we've passed it off to another function. -bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => \ +bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => bs_start_match3 p Src Live Ctx -bs_start_match4 Fail=f Live=u Src=xy Ctx=d => \ +bs_start_match4 Fail=f Live=u Src=xy Ctx=d => bs_start_match3 Fail Src Live Ctx %if ARCH_64 # This instruction nops on 64-bit platforms -bs_start_match4 a==am_resume Live Same Same => +bs_start_match4 a==am_resume Live Ctx Dst | equal(Ctx, Dst) => _ bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst %else -bs_start_match4 a==am_resume Live Ctx Dst => \ +bs_start_match4 a==am_resume Live Ctx Dst => bs_start_match4 a=am_no_fail Live Ctx Dst %endif @@ -873,7 +981,7 @@ i_bs_start_match3 S t j d i_bs_get_position S S bs_set_position S S %else - bs_get_position S d t? + bs_get_position S d t bs_set_position S S %endif @@ -881,103 +989,115 @@ i_bs_start_match3 S t j d # Utf8/utf16/utf32 support. (R12B-5) # bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst -i_bs_get_utf8 S f? d +i_bs_get_utf8 S f d bs_skip_utf8 Fail=f Ms=xy u u => i_bs_skip_utf8 Ms Fail -i_bs_skip_utf8 S f? +i_bs_skip_utf8 S f bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => get_utf16(Fail, Ms, Flags, Dst) bs_skip_utf16 Fail=f Ms=xy u Flags=u => skip_utf16(Fail, Ms, Flags) -i_bs_get_utf16 S f? t d -i_bs_skip_utf16 S f? t +i_bs_get_utf16 S f t d +i_bs_skip_utf16 S f t + +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst | equal(Ms, Dst) => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms | + move x Dst -bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Ms=d => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ - i_bs_validate_unicode_retract Fail x Ms | \ - move x Ms -bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \ - i_bs_validate_unicode_retract Fail Dst Ms -bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \ - bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ - i_bs_validate_unicode_retract Fail x Ms +bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | + i_bs_validate_unicode_retract Fail Dst Ms + +bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => + bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | + i_bs_validate_unicode_retract Fail x Ms i_bs_validate_unicode_retract j s S %hot -# -# Constructing binaries -# +# ================================================================ +# New binary construction (OTP 25). +# ================================================================ + +bs_create_bin Fail=j Alloc=u Live=u Unit=u Dst=xy N=u Segments=* => + create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) + +i_bs_create_bin j I t d * + +# ================================================================ +# Old instruction for constructing binaries (up to OTP 24). +# ================================================================ + %warm bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst -bs_init2 Fail Sz=u Words Regs Flags Dst => \ - i_bs_init_heap Sz Words Regs Dst +bs_init2 Fail Sz=u Words Regs Flags Dst => + i_bs_init_heap Sz Words Regs Dst -bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \ - i_bs_init_fail Sz Fail Regs Dst -bs_init2 Fail Sz Words Regs Flags Dst => \ - i_bs_init_fail_heap Sz Words Fail Regs Dst +bs_init2 Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_fail Sz Fail Regs Dst +bs_init2 Fail Sz Words Regs Flags Dst => + i_bs_init_fail_heap Sz Words Fail Regs Dst -i_bs_init_fail S j? t? S +i_bs_init_fail S j t S -i_bs_init_fail_heap s I j? t? S +i_bs_init_fail_heap s I j t S -i_bs_init W t? S +i_bs_init W t S -i_bs_init_heap W I t? S +i_bs_init_heap W I t S bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail -bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => \ +bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init_bits Sz Regs Dst -bs_init_bits Fail Sz=u Words Regs Flags Dst => \ +bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Regs Dst -bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \ - i_bs_init_bits_fail Sz Fail Regs Dst -bs_init_bits Fail Sz Words Regs Flags Dst => \ - i_bs_init_bits_fail_heap Sz Words Fail Regs Dst +bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => + i_bs_init_bits_fail Sz Fail Regs Dst +bs_init_bits Fail Sz Words Regs Flags Dst => + i_bs_init_bits_fail_heap Sz Words Fail Regs Dst -i_bs_init_bits_fail S j? t? S +i_bs_init_bits_fail S j t S -i_bs_init_bits_fail_heap s I j? t? S +i_bs_init_bits_fail_heap s I j t S -i_bs_init_bits W t? S -i_bs_init_bits_heap W I t? S +i_bs_init_bits W t S +i_bs_init_bits_heap W I t S bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D -bs_add j? s s t? x +bs_add j s s t x -bs_append Fail Size Extra Live Unit Bin Flags Dst => \ - i_bs_append Fail Extra Live Unit Size Bin Dst +bs_append Fail Size Extra Live Unit Bin Flags Dst => + i_bs_append Fail Extra Live Unit Size Bin Dst -bs_private_append Fail Size Unit Bin Flags Dst => \ - i_bs_private_append Fail Unit Size Bin Dst +bs_private_append Fail Size Unit Bin Flags Dst => + i_bs_private_append Fail Unit Size Bin Dst -i_bs_private_append Fail Unit Size Bin Dst=y => \ - i_bs_private_append Fail Unit Size Bin x | move x Dst +i_bs_private_append Fail Unit Size Bin Dst=y => + i_bs_private_append Fail Unit Size Bin x | move x Dst bs_init_writable -i_bs_append j? I t? t s s S -i_bs_private_append j? t s S x +i_bs_append j I t t s s S +i_bs_private_append j t s S x # # Storing integers into binaries. # -bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \ - put_integer(Fail, Sz, Unit, Flags, Src) +bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => + put_integer(Fail, Sz, Unit, Flags, Src) -i_new_bs_put_integer j? S t s -i_new_bs_put_integer_imm s j? W t +i_new_bs_put_integer j S t s +i_new_bs_put_integer_imm s j W t # # Utf8/utf16/utf32 support. (R12B-5) @@ -989,16 +1109,16 @@ bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src bs_put_utf16 Fail Flags Src => put_utf16(Fail, Flags, Src) -bs_put_utf32 Fail=j Flags=u Src=s => \ - i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src +bs_put_utf32 Fail=j Flags=u Src=s => + i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src i_bs_utf8_size s x i_bs_utf16_size s x -i_bs_put_utf8 j? s -i_bs_put_utf16 j? t s +i_bs_put_utf8 j s +i_bs_put_utf16 j t s -i_bs_validate_unicode j? s +i_bs_validate_unicode j s # # Storing floats into binaries. @@ -1006,24 +1126,24 @@ i_bs_validate_unicode j? s # Will fail. No need to keep the instruction, because bs_add or # bs_init* would already have raised an exception. -bs_put_float Fail Sz=q Unit Flags Val => +bs_put_float Fail Sz=q Unit Flags Val => _ -bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \ - put_float(Fail, Sz, Unit, Flags, Src) +bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => + put_float(Fail, Sz, Unit, Flags, Src) -i_new_bs_put_float j? S t s -i_new_bs_put_float_imm j? W t s +i_new_bs_put_float j S t s +i_new_bs_put_float_imm j W t s # # Storing binaries into binaries. # -bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \ - put_binary(Fail, Sz, Unit, Flags, Src) +bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => + put_binary(Fail, Sz, Unit, Flags, Src) -i_new_bs_put_binary j? s t s -i_new_bs_put_binary_imm j? W s -i_new_bs_put_binary_all s j? t +i_new_bs_put_binary j s t s +i_new_bs_put_binary_imm j W s +i_new_bs_put_binary_all s j t # # Warning: The i_bs_put_string and i_new_bs_put_string instructions @@ -1031,7 +1151,7 @@ i_new_bs_put_binary_all s j? t # Don't change the instruction format unless you change the loader too. # -bs_put_string W W +bs_put_string W M # # New floating point instructions (R8). @@ -1057,8 +1177,8 @@ i_fmul l l l i_fdiv l l l i_fnegate l l -fclearerror => -fcheckerror p => +fclearerror => _ +fcheckerror p => _ %hot @@ -1070,84 +1190,65 @@ apply t apply_last t t # -# Handle compatibility with OTP 17 here. +# Map instructions. First introduced in R17. # -i_put_map_assoc/4 - -# We KNOW that in OTP 20 (actually OTP 18 and higher), a put_map_assoc instruction -# is always preceded by an is_map test. That means that put_map_assoc can never -# fail and does not need any failure label. - -put_map_assoc Fail Map Dst Live Size Rest=* | compiled_with_otp_20_or_higher() => \ - i_put_map_assoc Map Dst Live Size Rest - -# Translate the put_map_assoc instruction if the module was compiled by a compiler -# before 20. This is only necessary if the OTP 17 compiler was used, but we -# have no safe and relatively easy way to know whether OTP 18/19 was used. - -put_map_assoc Fail=p Map Dst Live Size Rest=* => \ - ensure_map Map | i_put_map_assoc Map Dst Live Size Rest -put_map_assoc Fail=f Map Dst Live Size Rest=* => \ - is_map Fail Map | i_put_map_assoc Map Dst Live Size Rest +# We KNOW that in OTP 18 and higher, a put_map_assoc instruction is +# always preceded by an is_map test. That means that put_map_assoc can +# never fail and does not need any failure label. -ensure_map Lit=q | literal_is_map(Lit) => +put_map_assoc Fail Map Dst Live Size Rest=* => + i_put_map_assoc Map Dst Live Size Rest -%cold -ensure_map s -%hot - -# -# Map instructions. First introduced in R17. -# +i_put_map_assoc/4 sorted_put_map_assoc/4 -i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ - sorted_put_map_assoc Map Dst Live Size Rest +i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_assoc Map Dst Live Size Rest sorted_put_map_exact/5 -put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ - sorted_put_map_exact F Map Dst Live Size Rest +put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => + sorted_put_map_exact F Map Dst Live Size Rest -sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \ - new_map Dst Live Size Rest -sorted_put_map_assoc Src=s Dst Live Size Rest=* => \ - update_map_assoc Src Dst Live Size Rest +sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => + new_map Dst Live Size Rest +sorted_put_map_assoc Src=s Dst Live Size Rest=* => + update_map_assoc Src Dst Live Size Rest -sorted_put_map_exact Fail Src Dst Live Size Rest=* => \ - update_map_exact Src Fail Dst Live Size Rest +sorted_put_map_exact Fail Src Dst Live Size Rest=* => + update_map_exact Src Fail Dst Live Size Rest -new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \ - new_small_map_lit(Dst, Live, Size, Rest) +new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => + new_small_map_lit(Dst, Live, Size, Rest) new_map d t I * i_new_small_map_lit d t q I * update_map_assoc s d t I * -update_map_exact s j? d t I * +update_map_exact s j d t I * -is_map f? s +is_map f s ## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements -has_map_fields Fail Src Size Rest=* => \ - has_map_fields(Fail, Src, Size, Rest) +has_map_fields Fail Src Size Rest=* => + has_map_fields(Fail, Src, Size, Rest) ## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } -get_map_elements Fail Src Size=u==2 Rest=* => \ +get_map_elements Fail Src Size=u==2 Rest=* => get_map_element(Fail, Src, Size, Rest) -get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \ - get_map_elements(Fail, Src, Size, Rest) +get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => + get_map_elements(Fail, Src, Size, Rest) -i_get_map_elements f? s I * +i_get_map_elements f s I * -i_get_map_element_hash Fail Src=c Key Hash Dst => \ +i_get_map_element_hash Fail Src=c Key Hash Dst => move Src x | i_get_map_element_hash Fail x Key Hash Dst -i_get_map_element_hash f? S c I S +i_get_map_element_hash f S c I S -i_get_map_element Fail Src=c Key Dst => \ +i_get_map_element Fail Src=c Key Dst => move Src x | i_get_map_element Fail x Key Dst -i_get_map_element f? S S S +i_get_map_element f S S S # # Convert the plus operations to a generic plus instruction. @@ -1155,125 +1256,112 @@ i_get_map_element f? S S S gen_plus/5 gen_minus/5 -gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \ - gen_plus Fail Live Src i Dst -gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ - gen_plus Fail Live S1 S2 Dst - -gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \ - i_unary_minus Src Fail Dst -gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \ - gen_minus Fail Live S1 S2 Dst - -# -# Optimize addition and subtraction of small literals using -# the i_increment/3 instruction (in bodies, not in guards). -# - -gen_plus p Live Int=i Reg=d Dst => \ - increment(Reg, Int, Dst) -gen_plus p Live Reg=d Int=i Dst => \ - increment(Reg, Int, Dst) +gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => + gen_plus Fail Live Src i Dst +gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => + gen_plus Fail Live S1 S2 Dst -gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ - increment_from_minus(Reg, Int, Dst) +gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => + i_unary_minus Src Fail Dst +gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => + gen_minus Fail Live S1 S2 Dst # # Arithmetic instructions. # -# It is OK to swap arguments for '+' in a guard. It is also -# OK to turn minus into plus in a guard. -gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst -gen_minus Fail=f Live S1 S2=i Dst | negation_is_small(S2) => \ - plus_from_minus(Fail, Live, S1, S2, Dst) - gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \ - i_times Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => + i_times Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \ - i_m_div Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => + i_m_div Fail S1 S2 Dst # Fused 'rem'/'div' pair. -gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \ - gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \ - distinct(LHS, Remainder) | \ - distinct(RHS, Remainder) => \ - i_rem_div LHS RHS Fail Remainder Quotient +gc_bif2 Fail Live u$bif:erlang:rem/2 LHS1 RHS1 Remainder | + gc_bif2 A B u$bif:erlang:intdiv/2 LHS2 RHS2 Quotient | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Remainder) | + distinct(RHS1, Remainder) => + i_rem_div LHS1 RHS1 Fail Remainder Quotient # As above but with a `line` in between -gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \ - line Loc | \ - gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \ - distinct(LHS, Remainder) | \ - distinct(RHS, Remainder) => \ - i_rem_div LHS RHS Fail Remainder Quotient +gc_bif2 Fail Live u$bif:erlang:rem/2 LHS1 RHS1 Remainder | + line Loc | + gc_bif2 A B u$bif:erlang:intdiv/2 LHS2 RHS2 Quotient | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Remainder) | + distinct(RHS1, Remainder) => + i_rem_div LHS1 RHS1 Fail Remainder Quotient # Fused 'div'/'rem' pair -gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \ - gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \ - distinct(LHS, Quotient) | \ - distinct(RHS, Quotient) => \ - i_div_rem LHS RHS Fail Quotient Remainder +gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS1 RHS1 Quotient | + gc_bif2 A B u$bif:erlang:rem/2 LHS2 RHS2 Remainder | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Quotient) | + distinct(RHS1, Quotient) => + i_div_rem LHS1 RHS1 Fail Quotient Remainder # As above but with a `line` in between -gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \ - line Loc | \ - gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \ - distinct(LHS, Quotient) | \ - distinct(RHS, Quotient) => \ - i_div_rem LHS RHS Fail Quotient Remainder - -gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \ - i_int_div Fail S1 S2 Dst -gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \ - i_rem S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS1 RHS1 Quotient | + line Loc | + gc_bif2 A B u$bif:erlang:rem/2 LHS2 RHS2 Remainder | + equal(LHS1, LHS2) | + equal(RHS1, RHS2) | + distinct(LHS1, Quotient) | + distinct(RHS1, Quotient) => + i_div_rem LHS1 RHS1 Fail Quotient Remainder -gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \ - i_bsl S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \ - i_bsr S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => + i_int_div Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => + i_rem S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \ - i_band S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => + i_bsl S1 S2 Fail Dst +gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => + i_bsr S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \ - i_bor Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => + i_band S1 S2 Fail Dst -gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \ - i_bxor Fail S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => + i_bor Fail S1 S2 Dst -gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst => \ - i_bnot Fail Src Dst +gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => + i_bxor Fail S1 S2 Dst -i_increment S W d +gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst => + i_bnot Fail Src Dst -i_plus s s j? d -i_minus s s j? d +i_plus s s j d +i_minus s s j d -i_unary_minus s j? d +i_unary_minus s j d -i_times j? s s d +i_times j s s d -i_m_div j? s s d +i_m_div j s s d -i_rem_div s s j? d d -i_div_rem s s j? d d -i_int_div j? s s d -i_rem s s j? d +i_rem_div s s j d d +i_div_rem s s j d d +i_int_div j s s d +i_rem s s j d -i_bsl s s j? d -i_bsr s s j? d +i_bsl s s j d +i_bsr s s j d -i_band s s j? d -i_bor j? s s d -i_bxor j? s s d +i_band s s j d +i_bor j s s d +i_bxor j s s d -i_bnot j? s d +i_bnot j s d # # Old guard BIFs that creates heap fragments are no longer allowed. @@ -1289,11 +1377,18 @@ bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler # Handle the length/1 guard BIF specially to make it trappable. # -gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \ - i_length_setup Fail Live Src | i_length Fail Live Dst +gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => + i_length_setup Fail Live Src | i_length Fail Live Dst -i_length_setup j? t s -i_length j? t d +i_length_setup j t s +i_length j t d + +# +# Specialized guard BIFs. +# + +gc_bif1 Fail Live Bif=u$bif:erlang:map_size/1 Src Dst=d => bif_map_size Fail Src Dst +bif_map_size j s d # # Guard BIFs. @@ -1308,7 +1403,7 @@ gc_bif3 Fail Live Bif S1 S2 S3 Dst => i_bif3 S1 S2 S3 Fail Bif Dst # encountered. # unsupported_guard_bif/3 -unsupported_guard_bif A B C | never() => +unsupported_guard_bif A B C | never() => _ # # R13B03 @@ -1324,8 +1419,8 @@ on_load recv_mark f => i_recv_mark i_recv_mark -recv_set Fail | label Lbl | loop_rec Lf Reg => \ - i_recv_set | label Lbl | loop_rec Lf Reg +recv_set Fail | label Lbl | loop_rec Lf Reg => + i_recv_set | label Lbl | loop_rec Lf Reg i_recv_set # @@ -1352,3 +1447,9 @@ recv_marker_reserve S recv_marker_bind S S recv_marker_clear S recv_marker_use S + +# +# OTP 26 +# + +update_record a I s d I * diff --git a/erts/emulator/beam/jit/x86/predicates.tab b/erts/emulator/beam/jit/x86/predicates.tab index d9d3801c8f32..c274aba59831 100644 --- a/erts/emulator/beam/jit/x86/predicates.tab +++ b/erts/emulator/beam/jit/x86/predicates.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020-2021. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. 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. @@ -32,16 +32,10 @@ pred.is_mfa_bif(M, F, A) { return 0; } -pred.needs_nif_padding() { - /* If the module may load a NIF all functions must be able to hold a NIF - * stub, so we'll pad to that size at the end of every function. */ - return S->may_load_nif; -} - pred.never_fails(Bif) { static Eterm nofail_bifs[] = {am_Neqeq, - am_Le, + am_Lt, am_Neq, am_Eq, am_Le, @@ -113,3 +107,25 @@ pred.consecutive_words(S1, D1, S2, D2) { return S1.type == S2.type && S1.val + 1 == S2.val && D1.type == D2.type && D1.val + 1 == D2.val; } + +pred.is_ge_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Ge && entry->arity == 2; + } + return 0; +} + +pred.is_lt_bif(Bif) { + Uint index = Bif.val; + + if (Bif.type == TAG_u && index < S->beam.imports.count) { + BeamFile_ImportEntry *entry = &S->beam.imports.entries[index]; + + return entry->module == am_erlang && entry->function == am_Lt && entry->arity == 2; + } + return 0; +} diff --git a/erts/emulator/beam/jit/x86/process_main.cpp b/erts/emulator/beam/jit/x86/process_main.cpp new file mode 100644 index 000000000000..210aecb0c2f9 --- /dev/null +++ b/erts/emulator/beam/jit/x86/process_main.cpp @@ -0,0 +1,348 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020-2021. 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% + */ + +#include "beam_asm.hpp" + +extern "C" +{ +#include "bif.h" +#include "beam_common.h" +#include "code_ix.h" +#include "export.h" +} + +const uint8_t *BeamAssembler::nops[3] = {nop1, nop2, nop3}; +const uint8_t BeamAssembler::nop1[1] = {0x90}; +const uint8_t BeamAssembler::nop2[2] = {0x66, 0x90}; +const uint8_t BeamAssembler::nop3[3] = {0x0F, 0x1F, 0x00}; + +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) +static Process *erts_debug_schedule(ErtsSchedulerData *esdp, + Process *c_p, + int calls) { + PROCESS_MAIN_CHK_LOCKS(c_p); + ERTS_UNREQ_PROC_MAIN_LOCK(c_p); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + c_p = erts_schedule(esdp, c_p, calls); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + ERTS_REQ_PROC_MAIN_LOCK(c_p); + PROCESS_MAIN_CHK_LOCKS(c_p); + return c_p; +} +#endif + +/* void process_main(ErtsSchedulerData *esdp); */ +void BeamGlobalAssembler::emit_process_main() { + Label context_switch_local = a.newLabel(), + context_switch_simplified_local = a.newLabel(), + do_schedule_local = a.newLabel(), schedule_next = a.newLabel(); + + const x86::Mem start_time_i = + getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time_i)); + const x86::Mem start_time = + getSchedulerRegRef(offsetof(ErtsSchedulerRegisters, start_time)); + + /* Allocate the register structure on the stack to allow computing the + * runtime stack address from it, greatly reducing the cost of stack + * swapping. */ + a.sub(x86::rsp, imm(sizeof(ErtsSchedulerRegisters) + ERTS_CACHE_LINE_SIZE)); + a.and_(x86::rsp, imm(~ERTS_CACHE_LINE_MASK)); + + a.mov(x86::qword_ptr(ARG1, offsetof(ErtsSchedulerData, registers)), + x86::rsp); + + /* Center `registers` at the base of x_reg_array so we can use negative + * 8-bit displacement to address the commonly used aux_regs, located at the + * start of the ErtsSchedulerRegisters struct. */ + a.lea(registers, + x86::qword_ptr(x86::rsp, + offsetof(ErtsSchedulerRegisters, x_reg_array.d))); + + load_erl_bits_state(ARG1); + runtime_call<1>(erts_bits_init_state); + +#if defined(DEBUG) && defined(NATIVE_ERLANG_STACK) + /* Save stack bounds so they can be tested without clobbering anything. */ + runtime_call<0>(erts_get_stacklimit); + + a.mov(getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, runtime_stack_end)), + RET); + a.mov(getSchedulerRegRef( + offsetof(ErtsSchedulerRegisters, runtime_stack_start)), + x86::rsp); +#elif !defined(NATIVE_ERLANG_STACK) + /* Save the initial SP of the thread so that we can verify that it + * doesn't grow. */ +# ifdef JIT_HARD_DEBUG + a.mov(getInitialSPRef(), x86::rsp); +# endif + + /* Manually do an `emit_enter_runtime` to match the `emit_leave_runtime` + * below. We avoid `emit_enter_runtime` because it may do additional + * assertions that may currently fail. + * + * IMPORTANT: We must ensure that this sequence leaves the stack + * aligned on a 16-byte boundary. */ + a.mov(getRuntimeStackRef(), x86::rsp); + a.sub(x86::rsp, imm(15)); + a.and_(x86::rsp, imm(-16)); +#endif + + a.mov(start_time_i, imm(0)); + a.mov(start_time, imm(0)); + + mov_imm(c_p, 0); + mov_imm(FCALLS, 0); + mov_imm(ARG3, 0); /* Set reds_used for erts_schedule call */ + + a.jmp(schedule_next); + + a.bind(do_schedule_local); + { + /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ + a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5]))); + a.sub(ARG3, FCALLS); + + a.jmp(schedule_next); + } + + a.bind(context_switch_local); + comment("Context switch, unknown arity/MFA"); + { + Sint arity_offset = offsetof(ErtsCodeMFA, arity) - sizeof(ErtsCodeMFA); + + a.mov(ARG1, x86::qword_ptr(ARG3, arity_offset)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), ARG1); + + a.lea(ARG1, x86::qword_ptr(ARG3, -(Sint)sizeof(ErtsCodeMFA))); + a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), ARG1); + + /* !! Fall through !! */ + } + + a.bind(context_switch_simplified_local); + comment("Context switch, known arity and MFA"); + { + Label not_exiting = a.newLabel(); + +#ifdef ERLANG_FRAME_POINTERS + /* Kill the current frame pointer to avoid confusing `perf` and similar + * tools. */ + a.sub(frame_pointer, frame_pointer); +#endif + +#ifdef DEBUG + Label check_i = a.newLabel(); + /* Check that ARG3 is set to a valid CP. */ + a.test(ARG3, imm(_CPMASK)); + a.je(check_i); + comment("# ARG3 is not a valid CP"); + a.ud2(); + a.bind(check_i); +#endif + + a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), ARG3); + +#if defined(JIT_HARD_DEBUG) && defined(ERLANG_FRAME_POINTERS) + a.mov(ARG1, c_p); + a.mov(ARG2, x86::qword_ptr(c_p, offsetof(Process, frame_pointer))); + a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, stop))); + + runtime_call<3>(erts_validate_stack); +#endif + +#ifdef WIN32 + a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.value))); +#else + a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.counter))); +#endif + + a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); + a.short_().je(not_exiting); + { + comment("Process exiting"); + + a.lea(ARG1, x86::qword_ptr(labels[process_exit])); + a.mov(x86::qword_ptr(c_p, offsetof(Process, i)), ARG1); + a.mov(x86::qword_ptr(c_p, offsetof(Process, arity)), imm(0)); + a.mov(x86::qword_ptr(c_p, offsetof(Process, current)), imm(0)); + a.jmp(do_schedule_local); + } + a.bind(not_exiting); + + /* Figure out reds_used. def_arg_reg[5] = REDS_IN */ + a.mov(ARG3, x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5]))); + a.sub(ARG3, FCALLS); + + /* Spill reds_used to FCALLS as we no longer need that value */ + a.mov(FCALLS, ARG3); + + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<2>(copy_out_registers); + + /* Restore reds_used from FCALLS */ + a.mov(ARG3, FCALLS); + + /* !! Fall through !! */ + } + + a.bind(schedule_next); + comment("schedule_next"); + { + Label schedule = a.newLabel(), skip_long_schedule = a.newLabel(); + + /* ARG3 contains reds_used at this point */ + + a.cmp(start_time, imm(0)); + a.short_().je(schedule); + { + a.mov(ARG1, c_p); + a.mov(ARG2, start_time); + + /* Spill reds_used in start_time slot */ + a.mov(start_time, ARG3); + + a.mov(ARG3, start_time_i); + runtime_call<3>(check_monitor_long_schedule); + + /* Restore reds_used */ + a.mov(ARG3, start_time); + } + a.bind(schedule); + +#ifdef ERLANG_FRAME_POINTERS + if (erts_frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + /* Kill the current frame pointer so that misc jobs that execute + * during `erts_schedule` aren't attributed to the function we + * were scheduled out of. */ + a.sub(frame_pointer, frame_pointer); + } +#endif + + mov_imm(ARG1, 0); + a.mov(ARG2, c_p); +#if defined(DEBUG) || defined(ERTS_ENABLE_LOCK_CHECK) + runtime_call<3>(erts_debug_schedule); +#else + runtime_call<3>(erts_schedule); +#endif + a.mov(c_p, RET); + +#ifdef ERTS_MSACC_EXTENDED_STATES + a.lea(ARG1, + x86::qword_ptr(registers, + offsetof(ErtsSchedulerRegisters, + aux_regs.d.erts_msacc_cache))); + runtime_call<1>(erts_msacc_update_cache); +#endif + + a.mov(ARG1, imm((UWord)&erts_system_monitor_long_schedule)); + a.cmp(x86::qword_ptr(ARG1), imm(0)); + a.mov(start_time, imm(0)); + a.short_().je(skip_long_schedule); + { + /* Enable long schedule test */ + runtime_call<0>(erts_timestamp_millis); + a.mov(start_time, RET); + a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, i))); + a.mov(start_time_i, RET); + } + a.bind(skip_long_schedule); + + /* Copy arguments */ + a.mov(ARG1, c_p); + load_x_reg_array(ARG2); + runtime_call<2>(copy_in_registers); + + /* Setup reduction counting */ + a.mov(FCALLS, x86::qword_ptr(c_p, offsetof(Process, fcalls))); + a.mov(x86::qword_ptr(c_p, offsetof(Process, def_arg_reg[5])), FCALLS); + +#ifdef DEBUG + a.mov(x86::qword_ptr(c_p, offsetof(Process, debug_reds_in)), FCALLS); +#endif + + /* Check whether save calls is on */ + a.mov(ARG1, c_p); + a.mov(ARG2, imm(ERTS_PSD_SAVED_CALLS_BUF)); + runtime_call<2>(erts_psd_get); + + /* Read the active code index, overriding it with + * ERTS_SAVE_CALLS_CODE_IX when save_calls is enabled (RET != 0). */ + a.test(RET, RET); + a.mov(ARG1, imm(&the_active_code_index)); + a.mov(ARG2, imm(ERTS_SAVE_CALLS_CODE_IX)); + a.mov(active_code_ix.r32(), x86::dword_ptr(ARG1)); + a.cmovnz(active_code_ix, ARG2); + + /* Start executing the Erlang process. Note that reductions have + * already been set up above. */ + emit_leave_runtime(); + + /* Check if we are just returning from a dirty nif/bif call and if so we + * need to do a bit of cleaning up before continuing. */ + a.mov(RET, x86::qword_ptr(c_p, offsetof(Process, i))); + a.cmp(x86::qword_ptr(RET), imm(op_call_nif_WWW)); + a.je(labels[dispatch_nif]); + a.cmp(x86::qword_ptr(RET), imm(op_call_bif_W)); + a.je(labels[dispatch_bif]); + a.jmp(RET); + } + + /* Processes may jump to the exported entry points below, executing on the + * Erlang stack when entering. These are separate from the `_local` labels + * above as we don't want to worry about which stack we're on when the + * cases overlap. */ + + /* `ga->get_context_switch()` + * + * The *next* instruction pointer is provided in ARG3, and must be preceded + * by an ErtsCodeMFA. */ + a.bind(labels[context_switch]); + { + emit_enter_runtime(); + + a.jmp(context_switch_local); + } + + /* `ga->get_context_switch_simplified()` + * + * The next instruction pointer is provided in ARG3, which does not need to + * point past an ErtsCodeMFA as the process structure has already been + * updated. */ + a.bind(labels[context_switch_simplified]); + { + emit_enter_runtime(); + + a.jmp(context_switch_simplified_local); + } + + /* `ga->get_do_schedule()` + * + * `c_p->i` must be set prior to jumping here. */ + a.bind(labels[do_schedule]); + { + emit_enter_runtime(); + + a.jmp(do_schedule_local); + } +} diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index ef16a6cf549d..8776a1bf5214 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -28,6 +28,10 @@ #include "module.h" #include "beam_catches.h" +#ifdef BEAMASM +# include "beam_asm.h" +#endif + #ifdef DEBUG # define IF_DEBUG(x) x #else @@ -74,6 +78,7 @@ void erts_module_instance_init(struct erl_module_instance* modi) modi->nif = NULL; modi->num_breakpoints = 0; modi->num_traced_exports = 0; + modi->unsealed = 0; } static Module* module_alloc(Module* tmpl) @@ -162,16 +167,18 @@ static Module* put_module(Eterm mod, IndexTable* mod_tab) Module* erts_put_module(Eterm mod) { - ERTS_LC_ASSERT(erts_initialized == 0 - || erts_has_code_write_permission()); + ERTS_LC_ASSERT(erts_initialized == 0 || erts_has_code_load_permission()); return put_module(mod, &module_tables[erts_staging_code_ix()]); } -int erts_is_code_ptr_writable(struct erl_module_instance* modi, - const void *ptr) { +void *erts_writable_code_ptr(struct erl_module_instance *modi, + const void *ptr) +{ const char *code_start, *code_end, *ptr_raw; + ASSERT(modi->unsealed); + code_start = (char*)modi->code_hdr; code_end = code_start + modi->code_length; ptr_raw = (const char*)ptr; @@ -179,59 +186,62 @@ int erts_is_code_ptr_writable(struct erl_module_instance* modi, (void)code_end; (void)ptr_raw; -#ifdef BEAMASM - { - const char *exec_mod_start, *rw_mod_start, *rw_mod_end; + ASSERT(ptr_raw >= code_start && ptr_raw < code_end); - exec_mod_start = (const char*)modi->native_module_exec; - rw_mod_start = (const char*)modi->native_module_rw; + { + const char *exec_mod_start; + char *rw_mod_start; - rw_mod_end = rw_mod_start + modi->code_length + - (exec_mod_start - code_start); + exec_mod_start = (const char*)modi->executable_region; + rw_mod_start = (char*)modi->writable_region; - if (ptr_raw >= rw_mod_start && ptr_raw <= rw_mod_end) { - return 1; - } + ASSERT(code_start >= exec_mod_start); - ASSERT(ptr_raw >= code_start && ptr_raw < code_end); - return 0; + return (void*)(rw_mod_start + (ptr_raw - exec_mod_start)); } -#else - ASSERT(ptr_raw >= code_start && ptr_raw < code_end); - return 1; -#endif } -void *erts_writable_code_ptr(struct erl_module_instance* modi, - const void *ptr) { - const char *code_start, *code_end, *ptr_raw; +#ifdef DEBUG +/* Protected by code mod permission. */ +static struct erl_module_instance *unsealed_module = NULL; +#endif - ERTS_LC_ASSERT(erts_has_code_write_permission()); +void erts_unseal_module(struct erl_module_instance *modi) { + ERTS_LC_ASSERT(erts_initialized == 0 || + erts_thr_progress_is_blocking() || + erts_has_code_mod_permission()); + ASSERT(unsealed_module == NULL && !modi->unsealed); - code_start = (char*)modi->code_hdr; - code_end = code_start + modi->code_length; - ptr_raw = (const char*)ptr; +#ifdef BEAMASM + beamasm_unseal_module(modi->executable_region, + modi->writable_region, + modi->code_length); +#endif - (void)code_end; - (void)ptr_raw; +#ifdef DEBUG + unsealed_module = modi; +#endif + modi->unsealed = 1; +} - ASSERT(ptr_raw >= code_start && ptr_raw < code_end); +void erts_seal_module(struct erl_module_instance *modi) +{ + ERTS_LC_ASSERT(erts_initialized == 0 || + erts_thr_progress_is_blocking() || + erts_has_code_mod_permission()); + ASSERT(unsealed_module == modi && modi->unsealed == 1); #ifdef BEAMASM - { - const char *exec_mod_start; - char *rw_mod_start; - - exec_mod_start = (const char*)modi->native_module_exec; - rw_mod_start = (char*)modi->native_module_rw; - - ASSERT(code_start >= exec_mod_start); + beamasm_flush_icache(modi->executable_region, modi->code_length); + beamasm_seal_module(modi->executable_region, + modi->writable_region, + modi->code_length); +#endif - return (void*)(rw_mod_start + (ptr_raw - exec_mod_start)); - } -#else - return (void*)ptr; +#ifdef DEBUG + unsealed_module = NULL; #endif + modi->unsealed = 0; } Module *module_code(int i, ErtsCodeIndex code_ix) diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 2b087e644d3f..6bbadbd505d6 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -32,10 +32,11 @@ struct erl_module_instance { int num_breakpoints; int num_traced_exports; -#if defined(BEAMASM) - const void *native_module_exec; - void *native_module_rw; -#endif + const void *executable_region; + void *writable_region; + + /* Protected by code modification permission. */ + int unsealed; }; typedef struct erl_module { @@ -52,17 +53,24 @@ void erts_module_instance_init(struct erl_module_instance* modi); Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); Module* erts_put_module(Eterm mod); -/* Converts the given code pointer into a writable one. +/** @brief Converts the given code pointer into a writable one. The module must + * have been made writable through \ref erts_unseal_module. * - * `ptr` must point within the given module. */ + * @param[in] ptr Pointer to convert. Must point within the given module. */ void *erts_writable_code_ptr(struct erl_module_instance* modi, const void *ptr); -/* Debug function for asserting whether `ptr` is writable or not. +/** @brief Opens a module for modification. * - * `ptr` must point within the given module. */ -int erts_is_code_ptr_writable(struct erl_module_instance* modi, - const void *ptr); + * This may only be used for one module at a time. Remember to call + * \ref erts_seal_module before returning to Erlang code or unsealing another + * module. */ +void erts_unseal_module(struct erl_module_instance *modi); + +/** @brief Seals a previously unsealed module, changing page permissions, + * flushing code cache, et cetera as needed. The caller is responsible for + * setting up a code barrier. */ +void erts_seal_module(struct erl_module_instance *modi); void init_module_table(void); void module_start_staging(void); diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index 8ef009ca8d69..a349c3ff8446 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -230,7 +230,7 @@ struct tpkt_head { unsigned char packet_length[2]; /* size incl header, big-endian (?) */ }; -void packet_parser_init() +void packet_parser_init(void) { static int done = 0; if (!done) { @@ -293,7 +293,7 @@ int packet_get_length(enum PacketParseType htype, case TCP_PB_LINE_LF: { /* TCP_PB_LINE_LF: [Data ... Delimiter] */ const char* ptr2; - if ((ptr2 = memchr(ptr, delimiter, n)) == NULL) { + if ((ptr2 = sys_memchr(ptr, delimiter, n)) == NULL) { if (n > max_plen && max_plen != 0) { /* packet full */ DEBUGF((" => packet full (no NL)=%d\r\n", n)); goto error; @@ -407,7 +407,7 @@ int packet_get_length(enum PacketParseType htype, } while (1) { - const char* ptr2 = memchr(ptr1, '\n', len); + const char* ptr2 = sys_memchr(ptr1, '\n', len); if (ptr2 == NULL) { if (max_plen != 0) { @@ -518,8 +518,9 @@ static void http_parse_absoluteURI(PacketHttpURI* uri, const char* uri_ptr, int uri_len) { const char* p; + const char* v; - if ((p = memchr(uri_ptr, '/', uri_len)) == NULL) { + if ((p = sys_memchr(uri_ptr, '/', uri_len)) == NULL) { /* host [":" port] */ uri->s2_ptr = "/"; uri->s2_len = 1; @@ -533,15 +534,39 @@ http_parse_absoluteURI(PacketHttpURI* uri, const char* uri_ptr, int uri_len) uri->s1_ptr = uri_ptr; uri->port = 0; /* undefined */ - /* host[:port] */ - if ((p = memchr(uri_ptr, ':', uri_len)) == NULL) { + if ((p = sys_memchr(uri_ptr, ':', uri_len)) == NULL) { uri->s1_len = uri_len; } + /* ipv6 + * eg [::1]:4000 + * eg [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80 + */ + else if (sys_memchr(uri_ptr, '[', uri_len) == uri_ptr && + (v = sys_memchr(uri_ptr, ']', uri_len)) != NULL) { + int n = (v - uri_ptr) + 1; + int port = 0; + uri->s1_len = n; + n = uri_len - (n+1); + // parse port if the next char is `:` + if (sys_memrchr(uri_ptr, ':', uri_len) == v + 1) { + // Skip over `]:` + v = v + 2; + while(n && isdigit((int) *v)) { + port = port*10 + (*v - '0'); + n--; + v++; + } + if (n==0 && port!=0) + uri->port = port; + } + } + /* host[:port] */ else { int n = (p - uri_ptr); int port = 0; uri->s1_len = n; n = uri_len - (n+1); + // Skip over port delimiter `:` p++; while(n && isdigit((int) *p)) { port = port*10 + (*p - '0'); @@ -607,7 +632,7 @@ static void http_parse_uri(PacketHttpURI* uri, const char* uri_ptr, int uri_len) } else { char* ptr; - if ((ptr = memchr(uri_ptr, ':', uri_len)) == NULL) { + if ((ptr = sys_memchr(uri_ptr, ':', uri_len)) == NULL) { uri->type = URI_STRING; uri->s1_ptr = uri_ptr; uri->s1_len = uri_len; diff --git a/erts/emulator/beam/predicates.tab b/erts/emulator/beam/predicates.tab index 833542112b8d..4bccce577ffb 100644 --- a/erts/emulator/beam/predicates.tab +++ b/erts/emulator/beam/predicates.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020. All Rights Reserved. +// Copyright Ericsson AB 2020-2022. 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. @@ -23,10 +23,6 @@ pred.never() { return 0; } -pred.compiled_with_otp_20_or_higher() { - return S->otp_20_or_higher; -} - // Test whether a jump table can be used. pred.use_jump_tab(Size, Rest, MinSize) { Sint min, max; @@ -144,25 +140,18 @@ pred.is_heavy_bif(Bif) { return 0; } -// Test whether the given literal is a map. -pred.literal_is_map(Lit) { - Eterm term; - - ASSERT(Lit.type == TAG_q); - term = beamfile_get_literal(&S->beam, Lit.val); - return is_map(term); -} - // Predicate to test whether all of the given new small map keys are literals pred.is_small_map_literal_keys(Size, Rest) { - if (Size.val > MAP_SMALL_MAP_LIMIT) { + Uint pair_count = Size.val / 2; + + if (pair_count > MAP_SMALL_MAP_LIMIT) { return 0; } /* * Operations with non-literals have always only one key. */ - if (Size.val != 2) { + if (pair_count != 1) { return 1; } @@ -195,18 +184,6 @@ pred.binary_too_big(Size) { (Size.type == TAG_u && ((Size.val >> (8*sizeof(Uint)-3)) != 0)); } - -// Test whether the negation of the given number is small. -pred.negation_is_small(Int) { - /* - * Check for the rare case of overflow in BeamInstr (UWord) -> Sint. - * Cast to the correct type before using IS_SSMALL (Sint). - */ - return Int.type == TAG_i && - !(Int.val & ~((((BeamInstr)1) << ((sizeof(Sint)*8)-1))-1)) && - IS_SSMALL(-((Sint)Int.val)); -} - // Mark this label. Always succeeds. pred.smp_mark_target_label(L) { ASSERT(L.type == TAG_f); @@ -226,7 +203,33 @@ pred.map_key_sort(Size, Rest) { return beam_load_map_key_sort(S, Size, Rest); } -// Test that the two registers are distinct. -pred.distinct(Reg1, Reg2) { - return Reg1.type != Reg2.type || Reg1.val != Reg2.val; +// Test that two operands are distinct. +pred.distinct(Val1, Val2) { + if (Val1.type != Val2.type) { + return 1; + } else if (Val1.type == TAG_x || Val1.type == TAG_y) { + /* We must not compare the type indices (if any). */ + return (Val1.val & REG_MASK) != (Val2.val & REG_MASK); + } else if (Val1.type == TAG_n) { + /* NIL has no associated value. */ + return 0; + } else { + return Val1.val != Val2.val; + } +} + +// Test that two operands are equal when disregarding types. Opposite of the +// `distinct` predicate. +pred.equal(Val1, Val2) { + if (Val1.type != Val2.type) { + return 0; + } else if (Val1.type == TAG_x || Val1.type == TAG_y) { + /* We must not compare the type indices (if any). */ + return (Val1.val & REG_MASK) == (Val2.val & REG_MASK); + } else if (Val1.type == TAG_n) { + /* NIL has no associated value. */ + return 1; + } else { + return Val1.val == Val2.val; + } } diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 1ffc7f502895..f4a0e5ab63d6 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -105,6 +105,9 @@ #define ErtsInArea(ptr,start,nbytes) \ ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) +#define ErtsInBetween(ptr,start,end) \ + ErtsInArea(ptr, start, (char*)(end) - (char*)(start)) + #define ErtsContainerStruct(ptr, type, member) \ ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member))) @@ -242,6 +245,7 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType; __decl_noreturn void __noreturn erl_assert_error(const char* expr, const char *func, const char* file, int line); +#undef ASSERT #ifdef DEBUG # define ASSERT(e) ERTS_ASSERT(e) #else @@ -267,7 +271,7 @@ __decl_noreturn void __noreturn erl_assert_error(const char* expr, const char *f * static int test(){ return 0;} * GCC_DIAG_ON(unused-function) * - * These macros were orginally authored by Jonathan Wakely and has + * These macros were originally authored by Jonathan Wakely and has * been modified by Patrick Horgan. * * Source: http://dbp-consulting.com/tutorials/SuppressingGCCWarnings.html @@ -346,7 +350,7 @@ __decl_noreturn void __noreturn erl_assert_error(const char* expr, const char *f ** Eterm: A tagged erlang term (possibly 64 bits) ** BeamInstr: A beam code instruction unit, possibly larger than Eterm, not smaller. ** Uint: An unsigned integer exactly as large as an Eterm. -** Sint: A signed integer exactly as large as an eterm and therefor large +** Sint: A signed integer exactly as large as an eterm and therefore large ** enough to hold the return value of the signed_val() macro. ** UWord: An unsigned integer at least as large as a void * and also as large ** or larger than an Eterm @@ -605,7 +609,7 @@ extern erts_tsd_key_t erts_is_crash_dumping_key; static unsigned long zero_value = 0, one_value = 1; # define SET_BLOCKING(fd) { if (ioctlsocket((fd), FIONBIO, &zero_value) != 0) fprintf(stderr, "Error setting socket to non-blocking: %d\n", WSAGetLastError()); } # define SET_NONBLOCKING(fd) ioctlsocket((fd), FIONBIO, &one_value) - +# define ERRNO_BLOCK EAGAIN /* We use the posix way for windows */ # else # ifdef NB_FIONBIO /* Old BSD */ # include @@ -767,6 +771,8 @@ extern void *erts_sys_ddll_call_init(void *function); extern void *erts_sys_ddll_call_nif_init(void *function); extern int erts_sys_ddll_sym2(void *handle, const char *name, void **function, ErtsSysDdllError*); #define erts_sys_ddll_sym(H,N,F) erts_sys_ddll_sym2(H,N,F,NULL) +extern int erts_sys_ddll_vsym2(void *handle, const char *name, const char *vers, void **function, ErtsSysDdllError*); +#define erts_sys_ddll_vsym(H,N,V,F) erts_sys_ddll_vsym2(H,N,V,F,NULL) extern char *erts_sys_ddll_error(int code); @@ -842,6 +848,7 @@ int sys_double_to_chars(double, char*, size_t); int sys_double_to_chars_ext(double, char*, size_t, size_t); int sys_double_to_chars_fast(double, char*, int, int, int); void sys_get_pid(char *, size_t); +int sys_get_hostname(char *buf, size_t size); /* erl_drv_get/putenv have been implicitly 8-bit for so long that we can't * change them without breaking things on Windows. Their return values are @@ -1074,6 +1081,8 @@ ERTS_GLB_INLINE void *sys_memmove(void *dest, const void *src, size_t n); ERTS_GLB_INLINE int sys_memcmp(const void *s1, const void *s2, size_t n); ERTS_GLB_INLINE void *sys_memset(void *s, int c, size_t n); ERTS_GLB_INLINE void *sys_memzero(void *s, size_t n); +ERTS_GLB_INLINE void *sys_memchr(const void *s, int c, size_t n); +ERTS_GLB_INLINE void *sys_memrchr(const void *s, int c, size_t n); ERTS_GLB_INLINE int sys_strcmp(const char *s1, const char *s2); ERTS_GLB_INLINE int sys_strncmp(const char *s1, const char *s2, size_t n); ERTS_GLB_INLINE char *sys_strcpy(char *dest, const char *src); @@ -1107,6 +1116,26 @@ ERTS_GLB_INLINE void *sys_memzero(void *s, size_t n) ASSERT(s != NULL); return memset(s,'\0',n); } +ERTS_GLB_INLINE void *sys_memchr(const void *s, int c, size_t n) +{ + ASSERT(s != NULL); + return (void*)memchr(s, c, n); +} +ERTS_GLB_INLINE void *sys_memrchr(const void *s, int c, size_t n) +{ + ASSERT(s != NULL); +#ifdef HAVE_MEMRCHR + return (void*)memrchr(s, c, n); +#else + { + const unsigned char* ptr = (const unsigned char*)s + n; + while (ptr != s) + if (*(--ptr) == (unsigned char)c) + return (void*)ptr; + return NULL; + } +#endif +} ERTS_GLB_INLINE int sys_strcmp(const char *s1, const char *s2) { ASSERT(s1 != NULL && s2 != NULL); @@ -1368,4 +1397,60 @@ erts_raw_env_next_char(byte *p, int encoding) #define ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER 0x04c76a00U #define ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER 0x050a7800U +#define ERTS_ATTR_WUR +#define ERTS_ATTR_ALLOC_SIZE(SZPOS) +#define ERTS_ATTR_MALLOC_U +#define ERTS_ATTR_MALLOC_US(SZPOS) +#define ERTS_ATTR_MALLOC_UD(DTOR, PTRPOS) +#define ERTS_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) +#define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) + +/* ERTS_ATTR_MALLOC_xxx: + * U: Returns pointer to Undefined data. ((malloc)) + * S: Has Size argument with nr of bytes of returned data. ((alloc_size(SZPOS))) + * D: Has 1-to-1 Deallocator function with ptr argument. ((malloc(DTOR,PTRPOS))) + * (D does not work on INLINE functions) + */ + +#ifdef __has_attribute +# if __has_attribute(warn_unused_result) +# undef ERTS_ATTR_WUR +# define ERTS_ATTR_WUR __attribute__((warn_unused_result)) +# endif +# if __has_attribute(alloc_size) +# undef ERTS_ATTR_ALLOC_SIZE +# define ERTS_ATTR_ALLOC_SIZE(SZPOS) __attribute__((alloc_size(SZPOS))) +# endif +# if __has_attribute(malloc) +# undef ERTS_ATTR_MALLOC_U +# define ERTS_ATTR_MALLOC_U __attribute__((malloc)) ERTS_ATTR_WUR + +# undef ERTS_ATTR_MALLOC_US +# define ERTS_ATTR_MALLOC_US(SZPOS) \ + __attribute__((malloc)) \ + ERTS_ATTR_ALLOC_SIZE(SZPOS) \ + ERTS_ATTR_WUR + +# undef ERTS_ATTR_MALLOC_D +# if defined(__GNUC__) && __GNUC__ >= 11 +# define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) \ + __attribute__((malloc(DTOR,PTRPOS))) \ + ERTS_ATTR_WUR +# else +# define ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) \ + ERTS_ATTR_WUR +# endif + +# undef ERTS_ATTR_MALLOC_UD +# define ERTS_ATTR_MALLOC_UD(DTOR, PTRPOS) \ + ERTS_ATTR_MALLOC_U \ + ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) + +# undef ERTS_ATTR_MALLOC_USD +# define ERTS_ATTR_MALLOC_USD(SZPOS, DTOR, PTRPOS) \ + ERTS_ATTR_MALLOC_US(SZPOS) \ + ERTS_ATTR_MALLOC_D(DTOR, PTRPOS) +# endif #endif + +#endif /* __SYS_H__ */ diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index ce57b041d6d7..851b3d6109dc 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -134,7 +134,7 @@ * will be triggered at once. The circular list of the slot will * be moved to the 'sentinel' field while bumping these timers * as when bumping an ordinary wheel slot. A yielding bump - * operation and cancelation of timers is handled the same way + * operation and cancellation of timers is handled the same way * as if the timer was in a wheel slot. * * -- Searching for Next Timeout -- diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 460b723231d1..8e2b13136b4c 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -60,6 +60,8 @@ #include "erl_nfunc_sched.h" #include "erl_proc_sig_queue.h" #include "erl_unicode.h" +#include "beam_common.h" +#include "erl_global_literals.h" /* ******************************* * ** Yielding C Fun (YCF) Note ** @@ -106,9 +108,11 @@ void *ycf_debug_get_stack_start(void) { #endif #if defined(DEBUG) +# define IF_DEBUG(X) X # define DBG_RANDOM_REDS(REDS, SEED) \ ((REDS) * 0.01 * erts_sched_local_random_float(SEED)) #else +# define IF_DEBUG(X) # define DBG_RANDOM_REDS(REDS, SEED) (REDS) #endif @@ -566,8 +570,16 @@ erts_bld_tuple(Uint **hpp, Uint *szp, Uint arity, ...) ASSERT(arity < (((Uint)1) << (sizeof(Uint)*8 - _HEADER_ARITY_OFFS))); - if (szp) - *szp += arity + 1; + if (szp) { + if (arity == 0) { + *szp = 0; + } else { + *szp += arity + 1; + } + } + if (arity == 0) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } if (hpp) { res = make_tuple(*hpp); *((*hpp)++) = make_arityval(arity); @@ -596,8 +608,16 @@ Eterm erts_bld_tuplev(Uint **hpp, Uint *szp, Uint arity, Eterm terms[]) ASSERT(arity < (((Uint)1) << (sizeof(Uint)*8 - _HEADER_ARITY_OFFS))); - if (szp) - *szp += arity + 1; + if (szp) { + if (arity == 0) { + *szp = 0; + } else { + *szp += arity + 1; + } + } + if (arity == 0) { + return ERTS_GLOBAL_LIT_EMPTY_TUPLE; + } if (hpp) { res = make_tuple(*hpp); @@ -746,1723 +766,13 @@ erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length, return res; } -/* *\ - * * -\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* make a hash index from an erlang term */ - -/* -** There are two hash functions. -** -** make_hash: A hash function that will give the same values for the same -** terms regardless of the internal representation. Small integers are -** hashed using the same algorithm as bignums and bignums are hashed -** independent of the CPU endianess. -** Make_hash also hashes pids, ports and references like 32 bit numbers -** (but with different constants). -** make_hash() is called from the bif erlang:phash/2 -** -** The idea behind the hash algorithm is to produce values suitable for -** linear dynamic hashing. We cannot choose the range at all while hashing -** (it's not even supplied to the hashing functions). The good old algorithm -** [H = H*C+X mod M, where H is the hash value, C is a "random" constant(or M), -** M is the range, preferably a prime, and X is each byte value] is therefore -** modified to: -** H = H*C+X mod 2^32, where C is a large prime. This gives acceptable -** "spreading" of the hashes, so that later modulo calculations also will give -** acceptable "spreading" in the range. -** We really need to hash on bytes, otherwise the -** upper bytes of a word will be less significant than the lower ones. That's -** not acceptable at all. For internal use one could maybe optimize by using -** another hash function, that is less strict but faster. That is, however, not -** implemented. -** -** Short semi-formal description of make_hash: -** -** In make_hash, the number N is treated like this: -** Abs(N) is hashed bytewise with the least significant byte, B(0), first. -** The number of bytes (J) to calculate hash on in N is -** (the number of _32_ bit words needed to store the unsigned -** value of abs(N)) * 4. -** X = FUNNY_NUMBER2 -** If N < 0, Y = FUNNY_NUMBER4 else Y = FUNNY_NUMBER3. -** The hash value is Y*h(J) mod 2^32 where h(J) is calculated like -** h(0) = -** h(i) = h(i-1)*X + B(i-1) -** The above should hold regardless of internal representation. -** Pids are hashed like small numbers but with differrent constants, as are -** ports. -** References are hashed like ports but only on the least significant byte. -** Binaries are hashed on all bytes (not on the 15 first as in -** make_broken_hash()). -** Bytes in lists (possibly text strings) use a simpler multiplication inlined -** in the handling of lists, that is an optimization. -** Everything else is like in the old hash (make_broken_hash()). -** -** make_hash2() is faster than make_hash, in particular for bignums -** and binaries, and produces better hash values. -*/ - -/* some prime numbers just above 2 ^ 28 */ - -#define FUNNY_NUMBER1 268440163 -#define FUNNY_NUMBER2 268439161 -#define FUNNY_NUMBER3 268435459 -#define FUNNY_NUMBER4 268436141 -#define FUNNY_NUMBER5 268438633 -#define FUNNY_NUMBER6 268437017 -#define FUNNY_NUMBER7 268438039 -#define FUNNY_NUMBER8 268437511 -#define FUNNY_NUMBER9 268439627 -#define FUNNY_NUMBER10 268440479 -#define FUNNY_NUMBER11 268440577 -#define FUNNY_NUMBER12 268440581 -#define FUNNY_NUMBER13 268440593 -#define FUNNY_NUMBER14 268440611 - -static Uint32 -hash_binary_bytes(Eterm bin, Uint sz, Uint32 hash) -{ - byte* ptr; - Uint bitoffs; - Uint bitsize; - - ERTS_GET_BINARY_BYTES(bin, ptr, bitoffs, bitsize); - if (bitoffs == 0) { - while (sz--) { - hash = hash*FUNNY_NUMBER1 + *ptr++; - } - if (bitsize > 0) { - byte b = *ptr; - - b >>= 8 - bitsize; - hash = (hash*FUNNY_NUMBER1 + b) * FUNNY_NUMBER12 + bitsize; - } - } else { - Uint previous = *ptr++; - Uint b; - Uint lshift = bitoffs; - Uint rshift = 8 - lshift; - - while (sz--) { - b = (previous << lshift) & 0xFF; - previous = *ptr++; - b |= previous >> rshift; - hash = hash*FUNNY_NUMBER1 + b; - } - if (bitsize > 0) { - b = (previous << lshift) & 0xFF; - previous = *ptr++; - b |= previous >> rshift; - - b >>= 8 - bitsize; - hash = (hash*FUNNY_NUMBER1 + b) * FUNNY_NUMBER12 + bitsize; - } - } - return hash; -} - -Uint32 make_hash(Eterm term_arg) -{ - DECLARE_WSTACK(stack); - Eterm term = term_arg; - Eterm hash = 0; - unsigned op; - -#define MAKE_HASH_TUPLE_OP (FIRST_VACANT_TAG_DEF) -#define MAKE_HASH_TERM_ARRAY_OP (FIRST_VACANT_TAG_DEF+1) -#define MAKE_HASH_CDR_PRE_OP (FIRST_VACANT_TAG_DEF+2) -#define MAKE_HASH_CDR_POST_OP (FIRST_VACANT_TAG_DEF+3) - - /* - ** Convenience macro for calculating a bytewise hash on an unsigned 32 bit - ** integer. - ** If the endianess is known, we could be smarter here, - ** but that gives no significant speedup (on a sparc at least) - */ -#define UINT32_HASH_STEP(Expr, Prime1) \ - do { \ - Uint32 x = (Uint32) (Expr); \ - hash = \ - (((((hash)*(Prime1) + (x & 0xFF)) * (Prime1) + \ - ((x >> 8) & 0xFF)) * (Prime1) + \ - ((x >> 16) & 0xFF)) * (Prime1) + \ - (x >> 24)); \ - } while(0) - -#define UINT32_HASH_RET(Expr, Prime1, Prime2) \ - UINT32_HASH_STEP(Expr, Prime1); \ - hash = hash * (Prime2); \ - break - - - /* - * Significant additions needed for real 64 bit port with larger fixnums. - */ - - /* - * Note, for the simple 64bit port, not utilizing the - * larger word size this function will work without modification. - */ -tail_recur: - op = tag_val_def(term); - - for (;;) { - switch (op) { - case NIL_DEF: - hash = hash*FUNNY_NUMBER3 + 1; - break; - case ATOM_DEF: - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(term))->slot.bucket.hvalue); - break; - case SMALL_DEF: - { - Sint y1 = signed_val(term); - Uint y2 = y1 < 0 ? -(Uint)y1 : y1; - - UINT32_HASH_STEP(y2, FUNNY_NUMBER2); -#if defined(ARCH_64) - if (y2 >> 32) - UINT32_HASH_STEP(y2 >> 32, FUNNY_NUMBER2); -#endif - hash *= (y1 < 0 ? FUNNY_NUMBER4 : FUNNY_NUMBER3); - break; - } - case BINARY_DEF: - { - Uint sz = binary_size(term); - - hash = hash_binary_bytes(term, sz, hash); - hash = hash*FUNNY_NUMBER4 + sz; - break; - } - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(term) + 1)); - - hash = hash * FUNNY_NUMBER11 + ep->info.mfa.arity; - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(ep->info.mfa.module))->slot.bucket.hvalue); - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(ep->info.mfa.function))->slot.bucket.hvalue); - break; - } - - case FUN_DEF: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(term); - Uint num_free = funp->num_free; - - hash = hash * FUNNY_NUMBER10 + num_free; - hash = hash*FUNNY_NUMBER1 + - (atom_tab(atom_val(funp->fe->module))->slot.bucket.hvalue); - hash = hash*FUNNY_NUMBER2 + funp->fe->index; - hash = hash*FUNNY_NUMBER2 + funp->fe->old_uniq; - if (num_free > 0) { - if (num_free > 1) { - WSTACK_PUSH3(stack, (UWord) &funp->env[1], (num_free-1), MAKE_HASH_TERM_ARRAY_OP); - } - term = funp->env[0]; - goto tail_recur; - } - break; - } - case PID_DEF: - /* only 15 bits... */ - UINT32_HASH_RET(internal_pid_number(term),FUNNY_NUMBER5,FUNNY_NUMBER6); - case EXTERNAL_PID_DEF: - /* only 15 bits... */ - UINT32_HASH_RET(external_pid_number(term),FUNNY_NUMBER5,FUNNY_NUMBER6); - case PORT_DEF: - case EXTERNAL_PORT_DEF: { - Uint64 number = port_number(term); - Uint32 low = (Uint32) (number & 0xffffffff); - Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); - if (high) - UINT32_HASH_STEP(high, FUNNY_NUMBER11); - UINT32_HASH_RET(low,FUNNY_NUMBER9,FUNNY_NUMBER10); - } - case REF_DEF: - UINT32_HASH_RET(internal_ref_numbers(term)[0],FUNNY_NUMBER9,FUNNY_NUMBER10); - case EXTERNAL_REF_DEF: - UINT32_HASH_RET(external_ref_numbers(term)[0],FUNNY_NUMBER9,FUNNY_NUMBER10); - case FLOAT_DEF: - { - FloatDef ff; - GET_DOUBLE(term, ff); - if (ff.fd == 0.0f) { - /* ensure positive 0.0 */ - ff.fd = erts_get_positive_zero_float(); - } - hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]); - break; - } - case MAKE_HASH_CDR_PRE_OP: - term = (Eterm) WSTACK_POP(stack); - if (is_not_list(term)) { - WSTACK_PUSH(stack, (UWord) MAKE_HASH_CDR_POST_OP); - goto tail_recur; - } - /* fall through */ - case LIST_DEF: - { - Eterm* list = list_val(term); - while(is_byte(*list)) { - /* Optimization for strings. - ** Note that this hash is different from a 'small' hash, - ** as multiplications on a Sparc is so slow. - */ - hash = hash*FUNNY_NUMBER2 + unsigned_val(*list); - - if (is_not_list(CDR(list))) { - WSTACK_PUSH(stack, MAKE_HASH_CDR_POST_OP); - term = CDR(list); - goto tail_recur; - } - list = list_val(CDR(list)); - } - WSTACK_PUSH2(stack, CDR(list), MAKE_HASH_CDR_PRE_OP); - term = CAR(list); - goto tail_recur; - } - case MAKE_HASH_CDR_POST_OP: - hash *= FUNNY_NUMBER8; - break; - - case BIG_DEF: - /* Note that this is the exact same thing as the hashing of smalls.*/ - { - Eterm* ptr = big_val(term); - Uint n = BIG_SIZE(ptr); - Uint k = n-1; - ErtsDigit d; - int is_neg = BIG_SIGN(ptr); - Uint i; - int j; - - for (i = 0; i < k; i++) { - d = BIG_DIGIT(ptr, i); - for(j = 0; j < sizeof(ErtsDigit); ++j) { - hash = (hash*FUNNY_NUMBER2) + (d & 0xff); - d >>= 8; - } - } - d = BIG_DIGIT(ptr, k); - k = sizeof(ErtsDigit); -#if defined(ARCH_64) - if (!(d >> 32)) - k /= 2; -#endif - for(j = 0; j < (int)k; ++j) { - hash = (hash*FUNNY_NUMBER2) + (d & 0xff); - d >>= 8; - } - hash *= is_neg ? FUNNY_NUMBER4 : FUNNY_NUMBER3; - break; - } - case MAP_DEF: - hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); - break; - case TUPLE_DEF: - { - Eterm* ptr = tuple_val(term); - Uint arity = arityval(*ptr); - - WSTACK_PUSH3(stack, (UWord) arity, (UWord)(ptr+1), (UWord) arity); - op = MAKE_HASH_TUPLE_OP; - }/*fall through*/ - case MAKE_HASH_TUPLE_OP: - case MAKE_HASH_TERM_ARRAY_OP: - { - Uint i = (Uint) WSTACK_POP(stack); - Eterm* ptr = (Eterm*) WSTACK_POP(stack); - if (i != 0) { - term = *ptr; - WSTACK_PUSH3(stack, (UWord)(ptr+1), (UWord) i-1, (UWord) op); - goto tail_recur; - } - if (op == MAKE_HASH_TUPLE_OP) { - Uint32 arity = (Uint32) WSTACK_POP(stack); - hash = hash*FUNNY_NUMBER9 + arity; - } - break; - } - - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); - return 0; - } - if (WSTACK_ISEMPTY(stack)) break; - op = WSTACK_POP(stack); - } - DESTROY_WSTACK(stack); - return hash; - -#undef MAKE_HASH_TUPLE_OP -#undef MAKE_HASH_TERM_ARRAY_OP -#undef MAKE_HASH_CDR_PRE_OP -#undef MAKE_HASH_CDR_POST_OP -#undef UINT32_HASH_STEP -#undef UINT32_HASH_RET -} - - - -/* Hash function suggested by Bob Jenkins. */ - -#define MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} while(0) - -#define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */ - -typedef struct { - Uint32 a,b,c; -} ErtsBlockHashHelperCtx; - -#define BLOCK_HASH_BYTES_PER_ITER 12 - -/* The three functions below are separated into different functions even - though they are always used together to make trapping and handling - of unaligned binaries easier. Examples of how they are used can be - found in block_hash and make_hash2_helper.*/ -static ERTS_INLINE -void block_hash_setup(Uint32 initval, - ErtsBlockHashHelperCtx* ctx /* out parameter */) -{ - ctx->a = ctx->b = HCONST; - ctx->c = initval; /* the previous hash value */ -} - -static ERTS_INLINE -void block_hash_buffer(byte *buf, - Uint buf_length, - ErtsBlockHashHelperCtx* ctx /* out parameter */) -{ - Uint len = buf_length; - byte *k = buf; - ASSERT(buf_length % BLOCK_HASH_BYTES_PER_ITER == 0); - while (len >= BLOCK_HASH_BYTES_PER_ITER) { - ctx->a += (k[0] +((Uint32)k[1]<<8) +((Uint32)k[2]<<16) +((Uint32)k[3]<<24)); - ctx->b += (k[4] +((Uint32)k[5]<<8) +((Uint32)k[6]<<16) +((Uint32)k[7]<<24)); - ctx->c += (k[8] +((Uint32)k[9]<<8) +((Uint32)k[10]<<16)+((Uint32)k[11]<<24)); - MIX(ctx->a,ctx->b,ctx->c); - k += BLOCK_HASH_BYTES_PER_ITER; len -= BLOCK_HASH_BYTES_PER_ITER; - } -} - -static ERTS_INLINE -Uint32 block_hash_final_bytes(byte *buf, - Uint buf_length, - Uint full_length, - ErtsBlockHashHelperCtx* ctx) -{ - Uint len = buf_length; - byte *k = buf; - ctx->c += full_length; - switch(len) - { /* all the case statements fall through */ - case 11: ctx->c+=((Uint32)k[10]<<24); - case 10: ctx->c+=((Uint32)k[9]<<16); - case 9 : ctx->c+=((Uint32)k[8]<<8); - /* the first byte of c is reserved for the length */ - case 8 : ctx->b+=((Uint32)k[7]<<24); - case 7 : ctx->b+=((Uint32)k[6]<<16); - case 6 : ctx->b+=((Uint32)k[5]<<8); - case 5 : ctx->b+=k[4]; - case 4 : ctx->a+=((Uint32)k[3]<<24); - case 3 : ctx->a+=((Uint32)k[2]<<16); - case 2 : ctx->a+=((Uint32)k[1]<<8); - case 1 : ctx->a+=k[0]; - /* case 0: nothing left to add */ - } - MIX(ctx->a,ctx->b,ctx->c); - return ctx->c; -} - -static -Uint32 -block_hash(byte *block, Uint block_length, Uint32 initval) -{ - ErtsBlockHashHelperCtx ctx; - Uint no_bytes_not_in_loop = - (block_length % BLOCK_HASH_BYTES_PER_ITER); - Uint no_bytes_to_process_in_loop = - block_length - no_bytes_not_in_loop; - byte *final_bytes = block + no_bytes_to_process_in_loop; - block_hash_setup(initval, &ctx); - block_hash_buffer(block, - no_bytes_to_process_in_loop, - &ctx); - return block_hash_final_bytes(final_bytes, - no_bytes_not_in_loop, - block_length, - &ctx); -} - -typedef enum { - tag_primary_list, - arityval_subtag, - hamt_subtag_head_flatmap, - map_subtag, - fun_subtag, - neg_big_subtag, - sub_binary_subtag_1, - sub_binary_subtag_2, - hash2_common_1, - hash2_common_2, - hash2_common_3, -} ErtsMakeHash2TrapLocation; - -typedef struct { - int c; - Uint32 sh; - Eterm* ptr; -} ErtsMakeHash2Context_TAG_PRIMARY_LIST; - -typedef struct { - int i; - int arity; - Eterm* elem; -} ErtsMakeHash2Context_ARITYVAL_SUBTAG; - -typedef struct { - Eterm *ks; - Eterm *vs; - int i; - Uint size; -} ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP; - -typedef struct { - Eterm* ptr; - int i; -} ErtsMakeHash2Context_MAP_SUBTAG; - -typedef struct { - Uint num_free; - Eterm* bptr; -} ErtsMakeHash2Context_FUN_SUBTAG; - -typedef struct { - Eterm* ptr; - Uint i; - Uint n; - Uint32 con; -} ErtsMakeHash2Context_NEG_BIG_SUBTAG; - -typedef struct { - byte* bptr; - Uint sz; - Uint bitsize; - Uint bitoffs; - Uint no_bytes_processed; - ErtsBlockHashHelperCtx block_hash_ctx; - /* The following fields are only used when bitoffs != 0 */ - byte* buf; - int done; - -} ErtsMakeHash2Context_SUB_BINARY_SUBTAG; - -typedef struct { - int dummy__; /* Empty structs are not supported on all platforms */ -} ErtsMakeHash2Context_EMPTY; - -typedef struct { - ErtsMakeHash2TrapLocation trap_location; - /* specific to the trap location: */ - union { - ErtsMakeHash2Context_TAG_PRIMARY_LIST tag_primary_list; - ErtsMakeHash2Context_ARITYVAL_SUBTAG arityval_subtag; - ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP hamt_subtag_head_flatmap; - ErtsMakeHash2Context_MAP_SUBTAG map_subtag; - ErtsMakeHash2Context_FUN_SUBTAG fun_subtag; - ErtsMakeHash2Context_NEG_BIG_SUBTAG neg_big_subtag; - ErtsMakeHash2Context_SUB_BINARY_SUBTAG sub_binary_subtag_1; - ErtsMakeHash2Context_SUB_BINARY_SUBTAG sub_binary_subtag_2; - ErtsMakeHash2Context_EMPTY hash2_common_1; - ErtsMakeHash2Context_EMPTY hash2_common_2; - ErtsMakeHash2Context_EMPTY hash2_common_3; - } trap_location_state; - /* same for all trap locations: */ - Eterm term; - Uint32 hash; - Uint32 hash_xor_pairs; - ErtsEStack stack; -} ErtsMakeHash2Context; - -static int make_hash2_ctx_bin_dtor(Binary *context_bin) { - ErtsMakeHash2Context* context = ERTS_MAGIC_BIN_DATA(context_bin); - DESTROY_SAVED_ESTACK(&context->stack); - if (context->trap_location == sub_binary_subtag_2 && - context->trap_location_state.sub_binary_subtag_2.buf != NULL) { - erts_free(ERTS_ALC_T_PHASH2_TRAP, context->trap_location_state.sub_binary_subtag_2.buf); - } - return 1; -} - -/* hash2_save_trap_state is called seldom so we want to avoid inlining */ -static ERTS_NOINLINE -Eterm hash2_save_trap_state(Eterm state_mref, - Uint32 hash_xor_pairs, - Uint32 hash, - Process* p, - Eterm term, - Eterm* ESTK_DEF_STACK(s), - ErtsEStack s, - ErtsMakeHash2TrapLocation trap_location, - void* trap_location_state_ptr, - size_t trap_location_state_size) { - Binary* state_bin; - ErtsMakeHash2Context* context; - if (state_mref == THE_NON_VALUE) { - Eterm* hp; - state_bin = erts_create_magic_binary(sizeof(ErtsMakeHash2Context), - make_hash2_ctx_bin_dtor); - hp = HAlloc(p, ERTS_MAGIC_REF_THING_SIZE); - state_mref = erts_mk_magic_ref(&hp, &MSO(p), state_bin); - } else { - state_bin = erts_magic_ref2bin(state_mref); - } - context = ERTS_MAGIC_BIN_DATA(state_bin); - context->term = term; - context->hash = hash; - context->hash_xor_pairs = hash_xor_pairs; - ESTACK_SAVE(s, &context->stack); - context->trap_location = trap_location; - sys_memcpy(&context->trap_location_state, - trap_location_state_ptr, - trap_location_state_size); - erts_set_gc_state(p, 0); - BUMP_ALL_REDS(p); - return state_mref; -} -#undef NOINLINE_HASH2_SAVE_TRAP_STATE - -/* Writes back a magic reference to *state_mref_write_back when the - function traps */ -static ERTS_INLINE Uint32 -make_hash2_helper(Eterm term_param, const int can_trap, Eterm* state_mref_write_back, Process* p) -{ - static const Uint ITERATIONS_PER_RED = 64; - Uint32 hash; - Uint32 hash_xor_pairs; - Eterm term = term_param; - ERTS_UNDEF(hash_xor_pairs, 0); - -/* (HCONST * {2, ..., 22}) mod 2^32 */ -#define HCONST_2 0x3c6ef372UL -#define HCONST_3 0xdaa66d2bUL -#define HCONST_4 0x78dde6e4UL -#define HCONST_5 0x1715609dUL -#define HCONST_6 0xb54cda56UL -#define HCONST_7 0x5384540fUL -#define HCONST_8 0xf1bbcdc8UL -#define HCONST_9 0x8ff34781UL -#define HCONST_10 0x2e2ac13aUL -#define HCONST_11 0xcc623af3UL -#define HCONST_12 0x6a99b4acUL -#define HCONST_13 0x08d12e65UL -#define HCONST_14 0xa708a81eUL -#define HCONST_15 0x454021d7UL -#define HCONST_16 0xe3779b90UL -#define HCONST_17 0x81af1549UL -#define HCONST_18 0x1fe68f02UL -#define HCONST_19 0xbe1e08bbUL -#define HCONST_20 0x5c558274UL -#define HCONST_21 0xfa8cfc2dUL -#define HCONST_22 0x98c475e6UL - -#define HASH_MAP_TAIL (_make_header(1,_TAG_HEADER_REF)) -#define HASH_MAP_PAIR (_make_header(2,_TAG_HEADER_REF)) -#define HASH_CDR (_make_header(3,_TAG_HEADER_REF)) - -#define UINT32_HASH_2(Expr1, Expr2, AConst) \ - do { \ - Uint32 a,b; \ - a = AConst + (Uint32) (Expr1); \ - b = AConst + (Uint32) (Expr2); \ - MIX(a,b,hash); \ - } while(0) - -#define UINT32_HASH(Expr, AConst) UINT32_HASH_2(Expr, 0, AConst) - -#define SINT32_HASH(Expr, AConst) \ - do { \ - Sint32 y = (Sint32) (Expr); \ - if (y < 0) { \ - UINT32_HASH(-y, AConst); \ - /* Negative numbers are unnecessarily mixed twice. */ \ - } \ - UINT32_HASH(y, AConst); \ - } while(0) - -#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2) - -#define NOT_SSMALL28_HASH(SMALL) \ - do { \ - Uint64 t; \ - Uint32 x, y; \ - Uint32 con; \ - if (SMALL < 0) { \ - con = HCONST_10; \ - t = (Uint64)(SMALL * (-1)); \ - } else { \ - con = HCONST_11; \ - t = SMALL; \ - } \ - x = t & 0xffffffff; \ - y = t >> 32; \ - UINT32_HASH_2(x, y, con); \ - } while(0) - -#ifdef ARCH_64 -# define POINTER_HASH(Ptr, AConst) UINT32_HASH_2((Uint32)(UWord)(Ptr), (((UWord)(Ptr)) >> 32), AConst) -#else -# define POINTER_HASH(Ptr, AConst) UINT32_HASH(Ptr, AConst) -#endif - -#define TRAP_LOCATION_NO_RED(location_name) \ - do { \ - if(can_trap && iterations_until_trap <= 0) { \ - *state_mref_write_back = \ - hash2_save_trap_state(state_mref, \ - hash_xor_pairs, \ - hash, \ - p, \ - term, \ - ESTK_DEF_STACK(s), \ - s, \ - location_name, \ - &ctx, \ - sizeof(ctx)); \ - return 0; \ - L_##location_name: \ - ctx = context->trap_location_state. location_name; \ - } \ - } while(0) - -#define TRAP_LOCATION(location_name) \ - do { \ - if (can_trap) { \ - iterations_until_trap--; \ - TRAP_LOCATION_NO_RED(location_name); \ - } \ - } while(0) - -#define TRAP_LOCATION_NO_CTX(location_name) \ - do { \ - ErtsMakeHash2Context_EMPTY ctx; \ - TRAP_LOCATION(location_name); \ - } while(0) - - /* Optimization. Simple cases before declaration of estack. */ - if (primary_tag(term) == TAG_PRIMARY_IMMED1) { - switch (term & _TAG_IMMED1_MASK) { - case _TAG_IMMED1_IMMED2: - switch (term & _TAG_IMMED2_MASK) { - case _TAG_IMMED2_ATOM: - /* Fast, but the poor hash value should be mixed. */ - return atom_tab(atom_val(term))->slot.bucket.hvalue; - } - break; - case _TAG_IMMED1_SMALL: - { - Sint small = signed_val(term); - if (SMALL_BITS > 28 && !IS_SSMALL28(small)) { - hash = 0; - NOT_SSMALL28_HASH(small); - return hash; - } - hash = 0; - SINT32_HASH(small, HCONST); - return hash; - } - } - }; - { - Eterm tmp; - long max_iterations = 0; - long iterations_until_trap = 0; - Eterm state_mref = THE_NON_VALUE; - ErtsMakeHash2Context* context = NULL; - DECLARE_ESTACK(s); - ESTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK); - if(can_trap){ -#ifdef DEBUG - (void)ITERATIONS_PER_RED; - iterations_until_trap = max_iterations = - (1103515245 * (ERTS_BIF_REDS_LEFT(p)) + 12345) % 227; -#else - iterations_until_trap = max_iterations = - ITERATIONS_PER_RED * ERTS_BIF_REDS_LEFT(p); -#endif - } - if (can_trap && is_internal_magic_ref(term)) { - Binary* state_bin; - state_mref = term; - state_bin = erts_magic_ref2bin(state_mref); - if (ERTS_MAGIC_BIN_DESTRUCTOR(state_bin) == make_hash2_ctx_bin_dtor) { - /* Restore state after a trap */ - context = ERTS_MAGIC_BIN_DATA(state_bin); - term = context->term; - hash = context->hash; - hash_xor_pairs = context->hash_xor_pairs; - ESTACK_RESTORE(s, &context->stack); - ASSERT(p->flags & F_DISABLE_GC); - erts_set_gc_state(p, 1); - switch (context->trap_location) { - case hash2_common_3: goto L_hash2_common_3; - case tag_primary_list: goto L_tag_primary_list; - case arityval_subtag: goto L_arityval_subtag; - case hamt_subtag_head_flatmap: goto L_hamt_subtag_head_flatmap; - case map_subtag: goto L_map_subtag; - case fun_subtag: goto L_fun_subtag; - case neg_big_subtag: goto L_neg_big_subtag; - case sub_binary_subtag_1: goto L_sub_binary_subtag_1; - case sub_binary_subtag_2: goto L_sub_binary_subtag_2; - case hash2_common_1: goto L_hash2_common_1; - case hash2_common_2: goto L_hash2_common_2; - } - } - } - hash = 0; - for (;;) { - switch (primary_tag(term)) { - case TAG_PRIMARY_LIST: - { - ErtsMakeHash2Context_TAG_PRIMARY_LIST ctx = { - .c = 0, - .sh = 0, - .ptr = list_val(term)}; - while (is_byte(*ctx.ptr)) { - /* Optimization for strings. */ - ctx.sh = (ctx.sh << 8) + unsigned_val(*ctx.ptr); - if (ctx.c == 3) { - UINT32_HASH(ctx.sh, HCONST_4); - ctx.c = ctx.sh = 0; - } else { - ctx.c++; - } - term = CDR(ctx.ptr); - if (is_not_list(term)) - break; - ctx.ptr = list_val(term); - TRAP_LOCATION(tag_primary_list); - } - if (ctx.c > 0) - UINT32_HASH(ctx.sh, HCONST_4); - if (is_list(term)) { - tmp = CDR(ctx.ptr); - ESTACK_PUSH(s, tmp); - term = CAR(ctx.ptr); - } - } - break; - case TAG_PRIMARY_BOXED: - { - Eterm hdr = *boxed_val(term); - ASSERT(is_header(hdr)); - switch (hdr & _TAG_HEADER_MASK) { - case ARITYVAL_SUBTAG: - { - ErtsMakeHash2Context_ARITYVAL_SUBTAG ctx = { - .i = 0, - .arity = header_arity(hdr), - .elem = tuple_val(term)}; - UINT32_HASH(ctx.arity, HCONST_9); - if (ctx.arity == 0) /* Empty tuple */ - goto hash2_common; - for (ctx.i = ctx.arity; ; ctx.i--) { - term = ctx.elem[ctx.i]; - if (ctx.i == 1) - break; - ESTACK_PUSH(s, term); - TRAP_LOCATION(arityval_subtag); - } - } - break; - case MAP_SUBTAG: - { - Uint size; - ErtsMakeHash2Context_MAP_SUBTAG ctx = { - .ptr = boxed_val(term) + 1, - .i = 0}; - switch (hdr & _HEADER_MAP_SUBTAG_MASK) { - case HAMT_SUBTAG_HEAD_FLATMAP: - { - flatmap_t *mp = (flatmap_t *)flatmap_val(term); - ErtsMakeHash2Context_HAMT_SUBTAG_HEAD_FLATMAP ctx = { - .ks = flatmap_get_keys(mp), - .vs = flatmap_get_values(mp), - .i = 0, - .size = flatmap_get_size(mp)}; - UINT32_HASH(ctx.size, HCONST_16); - if (ctx.size == 0) - goto hash2_common; - - /* We want a portable hash function that is *independent* of - * the order in which keys and values are encountered. - * We therefore calculate context independent hashes for all . - * key-value pairs and then xor them together. - */ - ESTACK_PUSH3(s, hash_xor_pairs, hash, HASH_MAP_TAIL); - hash = 0; - hash_xor_pairs = 0; - for (ctx.i = ctx.size - 1; ctx.i >= 0; ctx.i--) { - ESTACK_PUSH3(s, HASH_MAP_PAIR, - ctx.vs[ctx.i], ctx.ks[ctx.i]); - TRAP_LOCATION(hamt_subtag_head_flatmap); - } - goto hash2_common; - } - - case HAMT_SUBTAG_HEAD_ARRAY: - case HAMT_SUBTAG_HEAD_BITMAP: - size = *ctx.ptr++; - UINT32_HASH(size, HCONST_16); - if (size == 0) - goto hash2_common; - ESTACK_PUSH3(s, hash_xor_pairs, hash, HASH_MAP_TAIL); - hash = 0; - hash_xor_pairs = 0; - } - switch (hdr & _HEADER_MAP_SUBTAG_MASK) { - case HAMT_SUBTAG_HEAD_ARRAY: - ctx.i = 16; - break; - case HAMT_SUBTAG_HEAD_BITMAP: - case HAMT_SUBTAG_NODE_BITMAP: - ctx.i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); - break; - default: - erts_exit(ERTS_ERROR_EXIT, "bad header"); - } - while (ctx.i) { - if (is_list(*ctx.ptr)) { - Eterm* cons = list_val(*ctx.ptr); - ESTACK_PUSH3(s, HASH_MAP_PAIR, CDR(cons), CAR(cons)); - } - else { - ASSERT(is_boxed(*ctx.ptr)); - if (is_tuple(*ctx.ptr)) { /* collision node */ - Eterm *coll_ptr = tuple_val(*ctx.ptr); - Uint n = arityval(*coll_ptr); - ASSERT(n >= 2); - coll_ptr++; - for (; n; n--, coll_ptr++) { - Eterm* cons = list_val(*coll_ptr); - ESTACK_PUSH3(s, HASH_MAP_PAIR, CDR(cons), CAR(cons)); - } - } - else - ESTACK_PUSH(s, *ctx.ptr); - } - ctx.i--; ctx.ptr++; - TRAP_LOCATION(map_subtag); - } - goto hash2_common; - } - break; - case EXPORT_SUBTAG: - { - Export* ep = *((Export **) (export_val(term) + 1)); - UINT32_HASH_2 - (ep->info.mfa.arity, - atom_tab(atom_val(ep->info.mfa.module))->slot.bucket.hvalue, - HCONST); - UINT32_HASH - (atom_tab(atom_val(ep->info.mfa.function))->slot.bucket.hvalue, - HCONST_14); - goto hash2_common; - } - - case FUN_SUBTAG: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(term); - ErtsMakeHash2Context_FUN_SUBTAG ctx = { - .num_free = funp->num_free, - .bptr = NULL}; - UINT32_HASH_2 - (ctx.num_free, - atom_tab(atom_val(funp->fe->module))->slot.bucket.hvalue, - HCONST); - UINT32_HASH_2 - (funp->fe->index, funp->fe->old_uniq, HCONST); - if (ctx.num_free == 0) { - goto hash2_common; - } else { - ctx.bptr = funp->env + ctx.num_free - 1; - while (ctx.num_free-- > 1) { - term = *ctx.bptr--; - ESTACK_PUSH(s, term); - TRAP_LOCATION(fun_subtag); - } - term = *ctx.bptr; - } - } - break; - case REFC_BINARY_SUBTAG: - case HEAP_BINARY_SUBTAG: - case SUB_BINARY_SUBTAG: - { -#define BYTE_BITS 8 - ErtsMakeHash2Context_SUB_BINARY_SUBTAG ctx = { - .bptr = 0, - /* !!!!!!!!!!!!!!!!!!!! OBS !!!!!!!!!!!!!!!!!!!! - * - * The size is truncated to 32 bits on the line - * below so that the code is compatible with old - * versions of the code. This means that hash - * values for binaries with a size greater than - * 4GB do not take all bytes in consideration. - * - * !!!!!!!!!!!!!!!!!!!! OBS !!!!!!!!!!!!!!!!!!!! - */ - .sz = (0xFFFFFFFF & binary_size(term)), - .bitsize = 0, - .bitoffs = 0, - .no_bytes_processed = 0 - }; - Uint32 con = HCONST_13 + hash; - Uint iters_for_bin = MAX(1, ctx.sz / BLOCK_HASH_BYTES_PER_ITER); - ERTS_GET_BINARY_BYTES(term, ctx.bptr, ctx.bitoffs, ctx.bitsize); - if (ctx.sz == 0 && ctx.bitsize == 0) { - hash = con; - } else if (ctx.bitoffs == 0 && - (!can_trap || - (iterations_until_trap - iters_for_bin) > 0)) { - /* No need to trap while hashing binary */ - if (can_trap) iterations_until_trap -= iters_for_bin; - hash = block_hash(ctx.bptr, ctx.sz, con); - if (ctx.bitsize > 0) { - UINT32_HASH_2(ctx.bitsize, - (ctx.bptr[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), - HCONST_15); - } - } else if (ctx.bitoffs == 0) { - /* Need to trap while hashing binary */ - ErtsBlockHashHelperCtx* block_hash_ctx = &ctx.block_hash_ctx; - block_hash_setup(con, block_hash_ctx); - do { - Uint max_bytes_to_process = - iterations_until_trap <= 0 ? BLOCK_HASH_BYTES_PER_ITER : - iterations_until_trap * BLOCK_HASH_BYTES_PER_ITER; - Uint bytes_left = ctx.sz - ctx.no_bytes_processed; - Uint even_bytes_left = - bytes_left - (bytes_left % BLOCK_HASH_BYTES_PER_ITER); - Uint bytes_to_process = - MIN(max_bytes_to_process, even_bytes_left); - block_hash_buffer(&ctx.bptr[ctx.no_bytes_processed], - bytes_to_process, - block_hash_ctx); - ctx.no_bytes_processed += bytes_to_process; - iterations_until_trap -= - MAX(1, bytes_to_process / BLOCK_HASH_BYTES_PER_ITER); - TRAP_LOCATION_NO_RED(sub_binary_subtag_1); - block_hash_ctx = &ctx.block_hash_ctx; /* Restore after trap */ - } while ((ctx.sz - ctx.no_bytes_processed) >= - BLOCK_HASH_BYTES_PER_ITER); - hash = block_hash_final_bytes(ctx.bptr + - ctx.no_bytes_processed, - ctx.sz - ctx.no_bytes_processed, - ctx.sz, - block_hash_ctx); - if (ctx.bitsize > 0) { - UINT32_HASH_2(ctx.bitsize, - (ctx.bptr[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), - HCONST_15); - } - } else if (/* ctx.bitoffs != 0 && */ - (!can_trap || - (iterations_until_trap - iters_for_bin) > 0)) { - /* No need to trap while hashing binary */ - Uint nr_of_bytes = ctx.sz + (ctx.bitsize != 0); - byte *buf = erts_alloc(ERTS_ALC_T_TMP, nr_of_bytes); - Uint nr_of_bits_to_copy = ctx.sz*BYTE_BITS+ctx.bitsize; - if (can_trap) iterations_until_trap -= iters_for_bin; - erts_copy_bits(ctx.bptr, - ctx.bitoffs, 1, buf, 0, 1, nr_of_bits_to_copy); - hash = block_hash(buf, ctx.sz, con); - if (ctx.bitsize > 0) { - UINT32_HASH_2(ctx.bitsize, - (buf[ctx.sz] >> (BYTE_BITS - ctx.bitsize)), - HCONST_15); - } - erts_free(ERTS_ALC_T_TMP, buf); - } else /* ctx.bitoffs != 0 && */ { -#ifdef DEBUG -#define BINARY_BUF_SIZE (BLOCK_HASH_BYTES_PER_ITER * 3) -#else -#define BINARY_BUF_SIZE (BLOCK_HASH_BYTES_PER_ITER * 256) -#endif -#define BINARY_BUF_SIZE_BITS (BINARY_BUF_SIZE*BYTE_BITS) - /* Need to trap while hashing binary */ - ErtsBlockHashHelperCtx* block_hash_ctx = &ctx.block_hash_ctx; - Uint nr_of_bytes = ctx.sz + (ctx.bitsize != 0); - ERTS_CT_ASSERT(BINARY_BUF_SIZE % BLOCK_HASH_BYTES_PER_ITER == 0); - ctx.buf = erts_alloc(ERTS_ALC_T_PHASH2_TRAP, - MIN(nr_of_bytes, BINARY_BUF_SIZE)); - block_hash_setup(con, block_hash_ctx); - do { - Uint bytes_left = - ctx.sz - ctx.no_bytes_processed; - Uint even_bytes_left = - bytes_left - (bytes_left % BLOCK_HASH_BYTES_PER_ITER); - Uint bytes_to_process = - MIN(BINARY_BUF_SIZE, even_bytes_left); - Uint nr_of_bits_left = - (ctx.sz*BYTE_BITS+ctx.bitsize) - - ctx.no_bytes_processed*BYTE_BITS; - Uint nr_of_bits_to_copy = - MIN(nr_of_bits_left, BINARY_BUF_SIZE_BITS); - ctx.done = nr_of_bits_left == nr_of_bits_to_copy; - erts_copy_bits(ctx.bptr + ctx.no_bytes_processed, - ctx.bitoffs, 1, ctx.buf, 0, 1, - nr_of_bits_to_copy); - block_hash_buffer(ctx.buf, - bytes_to_process, - block_hash_ctx); - ctx.no_bytes_processed += bytes_to_process; - iterations_until_trap -= - MAX(1, bytes_to_process / BLOCK_HASH_BYTES_PER_ITER); - TRAP_LOCATION_NO_RED(sub_binary_subtag_2); - block_hash_ctx = &ctx.block_hash_ctx; /* Restore after trap */ - } while (!ctx.done); - nr_of_bytes = ctx.sz + (ctx.bitsize != 0); - hash = block_hash_final_bytes(ctx.buf + - (ctx.no_bytes_processed - - ((nr_of_bytes-1) / BINARY_BUF_SIZE) * BINARY_BUF_SIZE), - ctx.sz - ctx.no_bytes_processed, - ctx.sz, - block_hash_ctx); - if (ctx.bitsize > 0) { - Uint last_byte_index = - nr_of_bytes - (((nr_of_bytes-1) / BINARY_BUF_SIZE) * BINARY_BUF_SIZE) -1; - UINT32_HASH_2(ctx.bitsize, - (ctx.buf[last_byte_index] >> (BYTE_BITS - ctx.bitsize)), - HCONST_15); - } - erts_free(ERTS_ALC_T_PHASH2_TRAP, ctx.buf); - context->trap_location_state.sub_binary_subtag_2.buf = NULL; - } - goto hash2_common; -#undef BYTE_BITS -#undef BINARY_BUF_SIZE -#undef BINARY_BUF_SIZE_BITS - } - break; - case POS_BIG_SUBTAG: - case NEG_BIG_SUBTAG: - { - Eterm* big_val_ptr = big_val(term); - ErtsMakeHash2Context_NEG_BIG_SUBTAG ctx = { - .ptr = big_val_ptr, - .i = 0, - .n = BIG_SIZE(big_val_ptr), - .con = BIG_SIGN(big_val_ptr) ? HCONST_10 : HCONST_11}; -#if D_EXP == 16 - do { - Uint32 x, y; - x = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; - x += (Uint32)(ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0) << 16; - y = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; - y += (Uint32)(ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0) << 16; - UINT32_HASH_2(x, y, ctx.con); - TRAP_LOCATION(neg_big_subtag); - } while (ctx.i < ctx.n); -#elif D_EXP == 32 - do { - Uint32 x, y; - x = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; - y = ctx.i < ctx.n ? BIG_DIGIT(ctx.ptr, ctx.i++) : 0; - UINT32_HASH_2(x, y, ctx.con); - TRAP_LOCATION(neg_big_subtag); - } while (ctx.i < ctx.n); -#elif D_EXP == 64 - do { - Uint t; - Uint32 x, y; - ASSERT(ctx.i < ctx.n); - t = BIG_DIGIT(ctx.ptr, ctx.i++); - x = t & 0xffffffff; - y = t >> 32; - UINT32_HASH_2(x, y, ctx.con); - TRAP_LOCATION(neg_big_subtag); - } while (ctx.i < ctx.n); -#else -#error "unsupported D_EXP size" -#endif - goto hash2_common; - } - break; - case REF_SUBTAG: - /* All parts of the ref should be hashed. */ - UINT32_HASH(internal_ref_numbers(term)[0], HCONST_7); - goto hash2_common; - break; - case EXTERNAL_REF_SUBTAG: - /* All parts of the ref should be hashed. */ - UINT32_HASH(external_ref_numbers(term)[0], HCONST_7); - goto hash2_common; - break; - case EXTERNAL_PID_SUBTAG: - /* Only 15 bits are hashed. */ - UINT32_HASH(external_pid_number(term), HCONST_5); - goto hash2_common; - case EXTERNAL_PORT_SUBTAG: { - Uint64 number = external_port_number(term); - Uint32 low = (Uint32) (number & 0xffffffff); - Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); - UINT32_HASH_2(low, high, HCONST_6); - goto hash2_common; - } - case FLOAT_SUBTAG: - { - FloatDef ff; - GET_DOUBLE(term, ff); - if (ff.fd == 0.0f) { - /* ensure positive 0.0 */ - ff.fd = erts_get_positive_zero_float(); - } -#if defined(WORDS_BIGENDIAN) || defined(DOUBLE_MIDDLE_ENDIAN) - UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12); -#else - UINT32_HASH_2(ff.fw[1], ff.fw[0], HCONST_12); -#endif - goto hash2_common; - } - break; - - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); - } - } - break; - case TAG_PRIMARY_IMMED1: - switch (term & _TAG_IMMED1_MASK) { - case _TAG_IMMED1_PID: - /* Only 15 bits are hashed. */ - UINT32_HASH(internal_pid_number(term), HCONST_5); - goto hash2_common; - case _TAG_IMMED1_PORT: { - Uint64 number = internal_port_number(term); - Uint32 low = (Uint32) (number & 0xffffffff); - Uint32 high = (Uint32) ((number >> 32) & 0xffffffff); - UINT32_HASH_2(low, high, HCONST_6); - goto hash2_common; - } - case _TAG_IMMED1_IMMED2: - switch (term & _TAG_IMMED2_MASK) { - case _TAG_IMMED2_ATOM: - if (hash == 0) - /* Fast, but the poor hash value should be mixed. */ - hash = atom_tab(atom_val(term))->slot.bucket.hvalue; - else - UINT32_HASH(atom_tab(atom_val(term))->slot.bucket.hvalue, - HCONST_3); - goto hash2_common; - case _TAG_IMMED2_NIL: - if (hash == 0) - hash = 3468870702UL; - else - UINT32_HASH(NIL_DEF, HCONST_2); - goto hash2_common; - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); - } - case _TAG_IMMED1_SMALL: - { - Sint small = signed_val(term); - if (SMALL_BITS > 28 && !IS_SSMALL28(small)) { - NOT_SSMALL28_HASH(small); - } else { - SINT32_HASH(small, HCONST); - } - - goto hash2_common; - } - } - break; - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); - hash2_common: - - /* Uint32 hash always has the hash value of the previous term, - * compounded or otherwise. - */ - - if (ESTACK_ISEMPTY(s)) { - DESTROY_ESTACK(s); - if (can_trap) { - BUMP_REDS(p, (max_iterations - iterations_until_trap) / ITERATIONS_PER_RED); - ASSERT(!(p->flags & F_DISABLE_GC)); - } - return hash; - } - - term = ESTACK_POP(s); - - switch (term) { - case HASH_MAP_TAIL: { - hash = (Uint32) ESTACK_POP(s); - UINT32_HASH(hash_xor_pairs, HCONST_19); - hash_xor_pairs = (Uint32) ESTACK_POP(s); - TRAP_LOCATION_NO_CTX(hash2_common_1); - goto hash2_common; - } - case HASH_MAP_PAIR: - hash_xor_pairs ^= hash; - hash = 0; - TRAP_LOCATION_NO_CTX(hash2_common_2); - goto hash2_common; - default: - break; - } - - } - TRAP_LOCATION_NO_CTX(hash2_common_3); - } - } -#undef TRAP_LOCATION_NO_RED -#undef TRAP_LOCATION -#undef TRAP_LOCATION_NO_CTX -} - -Uint32 -make_hash2(Eterm term) -{ - return make_hash2_helper(term, 0, NULL, NULL); -} - -Uint32 -trapping_make_hash2(Eterm term, Eterm* state_mref_write_back, Process* p) -{ - return make_hash2_helper(term, 1, state_mref_write_back, p); -} - -#ifdef DBG_HASHMAP_COLLISION_BONANZA -Uint32 erts_dbg_hashmap_collision_bonanza(Uint32 hash, Eterm key) -{ -/*{ - static Uint32 hashvec[7] = { - 0x02345678, - 0x12345678, - 0xe2345678, - 0xf2345678, - 0x12abcdef, - 0x13abcdef, - 0xcafebabe - }; - hash = hashvec[hash % (sizeof(hashvec) / sizeof(hashvec[0]))]; - }*/ - const Uint32 bad_hash = (hash & 0x12482481) * 1442968193; - const Uint32 bad_bits = hash % 67; - if (bad_bits < 32) { - /* Mix in a number of high good bits to get "randomly" close - to the collision nodes */ - const Uint32 bad_mask = (1 << bad_bits) - 1; - return (hash & ~bad_mask) | (bad_hash & bad_mask); - } - return bad_hash; -} -#endif - -/* Term hash function for maps, with a separate depth parameter */ -Uint32 make_map_hash(Eterm key) { - Uint32 hash = 0; - - hash = make_internal_hash(key, hash); - -#ifdef DBG_HASHMAP_COLLISION_BONANZA - hash = erts_dbg_hashmap_collision_bonanza(hash, key); -#endif - return hash; -} - -/* Term hash function for internal use. - * - * Limitation #1: Is not "portable" in any way between different VM instances. - * - * Limitation #2: The hash value is only valid as long as the term exists - * somewhere in the VM. Why? Because external pids, ports and refs are hashed - * by mixing the node *pointer* value. If a node disappears and later reappears - * with a new ErlNode struct, externals from that node will hash different than - * before. - * - * The property "EVERY BIT of the term that is significant for equality - * MUST BE USED AS INPUT FOR THE HASH" is nice but no longer crucial for the - * hashmap implementation that now uses collision nodes at the bottom of - * the HAMT when all hash bits are exhausted. - * - */ - -#define CONST_HASH(AConst) \ -do { /* Lightweight mixing of constant (type info) */ \ - hash ^= AConst; \ - hash = (hash << 17) ^ (hash >> (32-17)); \ -} while (0) - -/* - * Start with salt, 32-bit prime number, to avoid getting same hash as phash2 - * which can cause bad hashing in distributed ETS tables for example. - */ -#define INTERNAL_HASH_SALT 3432918353U - -Uint32 -make_internal_hash(Eterm term, Uint32 salt) -{ - Uint32 hash = salt ^ INTERNAL_HASH_SALT; - - /* Optimization. Simple cases before declaration of estack. */ - if (primary_tag(term) == TAG_PRIMARY_IMMED1) { - #if ERTS_SIZEOF_ETERM == 8 - UINT32_HASH_2((Uint32)term, (Uint32)(term >> 32), HCONST); - #elif ERTS_SIZEOF_ETERM == 4 - UINT32_HASH(term, HCONST); - #else - # error "No you don't" - #endif - return hash; - } - { - Eterm tmp; - DECLARE_ESTACK(s); - - for (;;) { - switch (primary_tag(term)) { - case TAG_PRIMARY_LIST: - { - int c = 0; - Uint32 sh = 0; - Eterm* ptr = list_val(term); - while (is_byte(*ptr)) { - /* Optimization for strings. */ - sh = (sh << 8) + unsigned_val(*ptr); - if (c == 3) { - UINT32_HASH(sh, HCONST_4); - c = sh = 0; - } else { - c++; - } - term = CDR(ptr); - if (is_not_list(term)) - break; - ptr = list_val(term); - } - if (c > 0) - UINT32_HASH_2(sh, (Uint32)c, HCONST_22); - - if (is_list(term)) { - tmp = CDR(ptr); - CONST_HASH(HCONST_17); /* Hash CAR in cons cell */ - ESTACK_PUSH(s, tmp); - if (is_not_list(tmp)) { - ESTACK_PUSH(s, HASH_CDR); - } - term = CAR(ptr); - } - } - break; - case TAG_PRIMARY_BOXED: - { - Eterm hdr = *boxed_val(term); - ASSERT(is_header(hdr)); - switch (hdr & _TAG_HEADER_MASK) { - case ARITYVAL_SUBTAG: - { - int i; - int arity = header_arity(hdr); - Eterm* elem = tuple_val(term); - UINT32_HASH(arity, HCONST_9); - if (arity == 0) /* Empty tuple */ - goto pop_next; - for (i = arity; ; i--) { - term = elem[i]; - if (i == 1) - break; - ESTACK_PUSH(s, term); - } - } - break; - - case MAP_SUBTAG: - { - Eterm* ptr = boxed_val(term) + 1; - Uint size; - int i; - - /* - * We rely on key-value iteration order being constant - * for identical maps (in this VM instance). - */ - switch (hdr & _HEADER_MAP_SUBTAG_MASK) { - case HAMT_SUBTAG_HEAD_FLATMAP: - { - flatmap_t *mp = (flatmap_t *)flatmap_val(term); - Eterm *ks = flatmap_get_keys(mp); - Eterm *vs = flatmap_get_values(mp); - size = flatmap_get_size(mp); - UINT32_HASH(size, HCONST_16); - if (size == 0) - goto pop_next; - - for (i = size - 1; i >= 0; i--) { - ESTACK_PUSH(s, vs[i]); - ESTACK_PUSH(s, ks[i]); - } - goto pop_next; - } - case HAMT_SUBTAG_HEAD_ARRAY: - case HAMT_SUBTAG_HEAD_BITMAP: - size = *ptr++; - UINT32_HASH(size, HCONST_16); - if (size == 0) - goto pop_next; - } - switch (hdr & _HEADER_MAP_SUBTAG_MASK) { - case HAMT_SUBTAG_HEAD_ARRAY: - i = 16; - break; - case HAMT_SUBTAG_HEAD_BITMAP: - case HAMT_SUBTAG_NODE_BITMAP: - i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); - break; - default: - erts_exit(ERTS_ERROR_EXIT, "bad header"); - } - while (i) { - if (is_list(*ptr)) { - Eterm* cons = list_val(*ptr); - ESTACK_PUSH(s, CDR(cons)); - ESTACK_PUSH(s, CAR(cons)); - } - else { - ASSERT(is_boxed(*ptr)); - /* no special treatment of collision nodes needed, - hash them as the tuples they are */ - ESTACK_PUSH(s, *ptr); - } - i--; ptr++; - } - goto pop_next; - } - break; - case EXPORT_SUBTAG: - { - Export* ep = *((Export **) (export_val(term) + 1)); - /* Assumes Export entries never move */ - POINTER_HASH(ep, HCONST_14); - goto pop_next; - } - - case FUN_SUBTAG: - { - ErlFunThing* funp = (ErlFunThing *) fun_val(term); - Uint num_free = funp->num_free; - UINT32_HASH_2(num_free, funp->fe->module, HCONST_20); - UINT32_HASH_2(funp->fe->index, funp->fe->old_uniq, HCONST_21); - if (num_free == 0) { - goto pop_next; - } else { - Eterm* bptr = funp->env + num_free - 1; - while (num_free-- > 1) { - term = *bptr--; - ESTACK_PUSH(s, term); - } - term = *bptr; - } - } - break; - case REFC_BINARY_SUBTAG: - case HEAP_BINARY_SUBTAG: - case SUB_BINARY_SUBTAG: - { - byte* bptr; - Uint sz = binary_size(term); - Uint32 con = HCONST_13 + hash; - Uint bitoffs; - Uint bitsize; - - ERTS_GET_BINARY_BYTES(term, bptr, bitoffs, bitsize); - if (sz == 0 && bitsize == 0) { - hash = con; - } else { - if (bitoffs == 0) { - hash = block_hash(bptr, sz, con); - if (bitsize > 0) { - UINT32_HASH_2(bitsize, (bptr[sz] >> (8 - bitsize)), - HCONST_15); - } - } else { - byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, - sz + (bitsize != 0)); - erts_copy_bits(bptr, bitoffs, 1, buf, 0, 1, sz*8+bitsize); - hash = block_hash(buf, sz, con); - if (bitsize > 0) { - UINT32_HASH_2(bitsize, (buf[sz] >> (8 - bitsize)), - HCONST_15); - } - erts_free(ERTS_ALC_T_TMP, (void *) buf); - } - } - goto pop_next; - } - break; - case POS_BIG_SUBTAG: - case NEG_BIG_SUBTAG: - { - Eterm* ptr = big_val(term); - Uint i = 0; - Uint n = BIG_SIZE(ptr); - Uint32 con = BIG_SIGN(ptr) ? HCONST_10 : HCONST_11; -#if D_EXP == 16 - do { - Uint32 x, y; - x = i < n ? BIG_DIGIT(ptr, i++) : 0; - x += (Uint32)(i < n ? BIG_DIGIT(ptr, i++) : 0) << 16; - y = i < n ? BIG_DIGIT(ptr, i++) : 0; - y += (Uint32)(i < n ? BIG_DIGIT(ptr, i++) : 0) << 16; - UINT32_HASH_2(x, y, con); - } while (i < n); -#elif D_EXP == 32 - do { - Uint32 x, y; - x = i < n ? BIG_DIGIT(ptr, i++) : 0; - y = i < n ? BIG_DIGIT(ptr, i++) : 0; - UINT32_HASH_2(x, y, con); - } while (i < n); -#elif D_EXP == 64 - do { - Uint t; - Uint32 x, y; - ASSERT(i < n); - t = BIG_DIGIT(ptr, i++); - x = t & 0xffffffff; - y = t >> 32; - UINT32_HASH_2(x, y, con); - } while (i < n); -#else -#error "unsupported D_EXP size" -#endif - goto pop_next; - } - break; - case REF_SUBTAG: - UINT32_HASH(internal_ref_numbers(term)[0], HCONST_7); - ASSERT(internal_ref_no_numbers(term) == 3); - UINT32_HASH_2(internal_ref_numbers(term)[1], - internal_ref_numbers(term)[2], HCONST_8); - goto pop_next; - - case EXTERNAL_REF_SUBTAG: - { - ExternalThing* thing = external_thing_ptr(term); - - ASSERT(external_thing_ref_no_numbers(thing) == 3); - /* See limitation #2 */ - #ifdef ARCH_64 - POINTER_HASH(thing->node, HCONST_7); - UINT32_HASH(external_thing_ref_numbers(thing)[0], HCONST_7); - #else - UINT32_HASH_2(thing->node, - external_thing_ref_numbers(thing)[0], HCONST_7); - #endif - UINT32_HASH_2(external_thing_ref_numbers(thing)[1], - external_thing_ref_numbers(thing)[2], HCONST_8); - goto pop_next; - } - case EXTERNAL_PID_SUBTAG: { - ExternalThing* thing = external_thing_ptr(term); - /* See limitation #2 */ - POINTER_HASH(thing->node, HCONST_5); - UINT32_HASH_2(thing->data.pid.num, thing->data.pid.ser, HCONST_5); - goto pop_next; - } - case EXTERNAL_PORT_SUBTAG: { - ExternalThing* thing = external_thing_ptr(term); - /* See limitation #2 */ - POINTER_HASH(thing->node, HCONST_6); - UINT32_HASH_2(thing->data.ui32[0], thing->data.ui32[1], HCONST_6); - goto pop_next; - } - case FLOAT_SUBTAG: - { - FloatDef ff; - GET_DOUBLE(term, ff); - if (ff.fd == 0.0f) { - /* ensure positive 0.0 */ - ff.fd = erts_get_positive_zero_float(); - } - UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12); - goto pop_next; - } - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_internal_hash(0x%X, %lu)\n", term, salt); - } - } - break; - case TAG_PRIMARY_IMMED1: - #if ERTS_SIZEOF_ETERM == 8 - UINT32_HASH_2((Uint32)term, (Uint32)(term >> 32), HCONST); - #else - UINT32_HASH(term, HCONST); - #endif - goto pop_next; - - default: - erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_internal_hash(0x%X, %lu)\n", term, salt); - - pop_next: - if (ESTACK_ISEMPTY(s)) { - DESTROY_ESTACK(s); - - return hash; - } - - term = ESTACK_POP(s); - - switch (term) { - case HASH_CDR: - CONST_HASH(HCONST_18); /* Hash CDR i cons cell */ - goto pop_next; - default: - break; - } - } - } - } - -#undef CONST_HASH -#undef HASH_MAP_TAIL -#undef HASH_MAP_PAIR -#undef HASH_CDR - -#undef UINT32_HASH_2 -#undef UINT32_HASH -#undef SINT32_HASH -} - -#undef HCONST -#undef MIX - /* error_logger ! {log, Level, format, [args], #{ gl, pid, time, error_logger => #{tag, emulator => true} }} */ static Eterm -do_allocate_logger_message(Eterm gleader, ErtsMonotonicTime *ts, Eterm *pid, - Eterm **hp, ErlOffHeap **ohp, - ErlHeapFragment **bp, Uint sz) +do_allocate_logger_message(ErtsHeapFactory *factory, + Eterm gleader, ErtsMonotonicTime *ts, + Eterm *pid, Uint sz) { Uint gl_sz; gl_sz = IS_CONST(gleader) ? 0 : size_object(gleader); @@ -2481,19 +791,25 @@ do_allocate_logger_message(Eterm gleader, ErtsMonotonicTime *ts, Eterm *pid, *ts = ERTS_MONOTONIC_TO_USEC(erts_os_system_time()); erts_bld_sint64(NULL, &sz, *ts); - *bp = new_message_buffer(sz); - *ohp = &(*bp)->off_heap; - *hp = (*bp)->mem; - - return copy_struct(gleader,gl_sz,hp,*ohp); + erts_factory_heap_frag_init(factory, new_message_buffer(sz)); + { + Eterm *hp = erts_produce_heap(factory, gl_sz, 0); + return copy_struct(gleader,gl_sz,&hp,factory->off_heap); + } } -static void do_send_logger_message(Eterm gl, Eterm tag, Eterm format, Eterm args, - ErtsMonotonicTime ts, Eterm pid, - Eterm *hp, ErlHeapFragment *bp) +static void do_send_logger_message(ErtsHeapFactory *factory, + Eterm gl, Eterm tag, Eterm format, Eterm args, + ErtsMonotonicTime ts, Eterm pid) { + Eterm *hp; Eterm message, md, el_tag = tag; - Eterm time = erts_bld_sint64(&hp, NULL, ts); + Uint sz = 0; + Eterm time; + + erts_bld_sint64(NULL, &sz, ts); + hp = erts_produce_heap(factory, sz, 0); + time = erts_bld_sint64(&hp, NULL, ts); /* This mapping is needed for the backwards compatible error_logger */ switch (tag) { @@ -2504,42 +820,40 @@ static void do_send_logger_message(Eterm gl, Eterm tag, Eterm format, Eterm args break; } + hp = erts_produce_heap(factory, MAP2_SZ, 0); md = MAP2(hp, am_emulator, am_true, ERTS_MAKE_AM("tag"), el_tag); - hp += MAP2_SZ; if (is_nil(gl) && is_non_value(pid)) { /* no gl and no pid, probably from a port */ + hp = erts_produce_heap(factory, MAP2_SZ, 0); md = MAP2(hp, am_error_logger, md, am_time, time); - hp += MAP2_SZ; pid = NIL; } else if (is_nil(gl)) { /* no gl */ + hp = erts_produce_heap(factory, MAP3_SZ, 0); md = MAP3(hp, am_error_logger, md, am_pid, pid, am_time, time); - hp += MAP3_SZ; } else if (is_non_value(pid)) { /* no gl */ + hp = erts_produce_heap(factory, MAP3_SZ, 0); md = MAP3(hp, am_error_logger, md, ERTS_MAKE_AM("gl"), gl, am_time, time); - hp += MAP3_SZ; pid = NIL; } else { - md = MAP4(hp, - am_error_logger, md, - ERTS_MAKE_AM("gl"), gl, - am_pid, pid, - am_time, time); - hp += MAP4_SZ; + Eterm keys[] = { am_error_logger, ERTS_MAKE_AM("gl"), am_pid, am_time }; + Eterm values[] = { md, gl, pid, time }; + md = erts_map_from_ks_and_vs(factory, keys, values, 4); } - + hp = erts_produce_heap(factory, 6, 0); message = TUPLE5(hp, am_log, tag, format, args, md); - erts_queue_error_logger_message(pid, message, bp); + erts_factory_close(factory); + erts_queue_error_logger_message(pid, message, factory->heap_frags); } static int do_send_to_logger(Eterm tag, Eterm gl, char *buf, size_t len) @@ -2547,23 +861,23 @@ static int do_send_to_logger(Eterm tag, Eterm gl, char *buf, size_t len) Uint sz; Eterm list, args, format, pid; ErtsMonotonicTime ts; + ErtsHeapFactory factory; Eterm *hp = NULL; - ErlOffHeap *ohp = NULL; - ErlHeapFragment *bp = NULL; sz = len * 2 /* message list */ + 2 /* cons surrounding message list */ + 8 /* "~s~n" */; /* gleader size is accounted and allocated next */ - gl = do_allocate_logger_message(gl, &ts, &pid, &hp, &ohp, &bp, sz); + gl = do_allocate_logger_message(&factory, gl, &ts, &pid, sz); + hp = erts_produce_heap(&factory, sz, 0); list = buf_to_intlist(&hp, buf, len, NIL); args = CONS(hp,list,NIL); hp += 2; format = buf_to_intlist(&hp, "~s~n", 4, NIL); - do_send_logger_message(gl, tag, format, args, ts, pid, hp, bp); + do_send_logger_message(&factory, gl, tag, format, args, ts, pid); return 0; } @@ -2576,8 +890,7 @@ static int do_send_term_to_logger(Eterm tag, Eterm gl, ErtsMonotonicTime ts; Eterm *hp = NULL; - ErlOffHeap *ohp = NULL; - ErlHeapFragment *bp = NULL; + ErtsHeapFactory factory; ASSERT(len > 0); @@ -2585,12 +898,13 @@ static int do_send_term_to_logger(Eterm tag, Eterm gl, sz = len * 2 /* format */ + args_sz; /* gleader size is accounted and allocated next */ - gl = do_allocate_logger_message(gl, &ts, &pid, &hp, &ohp, &bp, sz); + gl = do_allocate_logger_message(&factory, gl, &ts, &pid, sz); + hp = erts_produce_heap(&factory, sz, 0); format = buf_to_intlist(&hp, buf, len, NIL); - args = copy_struct(args, args_sz, &hp, ohp); + args = copy_struct(args, args_sz, &hp, factory.off_heap); - do_send_logger_message(gl, tag, format, args, ts, pid, hp, bp); + do_send_logger_message(&factory, gl, tag, format, args, ts, pid); return 0; } @@ -2894,35 +1208,46 @@ int eq(Eterm a, Eterm b) } break; /* not equal */ } - case EXPORT_SUBTAG: - { - if (is_export(b)) { - Export* a_exp = *((Export **) (export_val(a) + 1)); - Export* b_exp = *((Export **) (export_val(b) + 1)); - if (a_exp == b_exp) goto pop_next; - } - break; /* not equal */ - } - case FUN_SUBTAG: - { - ErlFunThing* f1; - ErlFunThing* f2; + case FUN_SUBTAG: + { + ErlFunThing* f1; + ErlFunThing* f2; - if (!is_fun(b)) - goto not_equal; - f1 = (ErlFunThing *) fun_val(a); - f2 = (ErlFunThing *) fun_val(b); - if (f1->fe->module != f2->fe->module || - f1->fe->index != f2->fe->index || - f1->fe->old_uniq != f2->fe->old_uniq || - f1->num_free != f2->num_free) { - goto not_equal; - } - if ((sz = f1->num_free) == 0) goto pop_next; - aa = f1->env; - bb = f2->env; - goto term_array; - } + if (is_not_any_fun(b)) { + goto not_equal; + } + + f1 = (ErlFunThing *) fun_val(a); + f2 = (ErlFunThing *) fun_val(b); + + if (is_local_fun(f1) && is_local_fun(f2)) { + ErlFunEntry *fe1, *fe2; + + fe1 = f1->entry.fun; + fe2 = f2->entry.fun; + + if (fe1->module != fe2->module || + fe1->index != fe2->index || + fe1->old_uniq != fe2->old_uniq || + f1->num_free != f2->num_free) { + goto not_equal; + } + + if ((sz = f1->num_free) == 0) { + goto pop_next; + } + + aa = f1->env; + bb = f2->env; + goto term_array; + } else if (is_external_fun(f1) && is_external_fun(f2)) { + if (f1->entry.exp == f2->entry.exp) { + goto pop_next; + } + } + + goto not_equal; + } case EXTERNAL_PID_SUBTAG: { ExternalThing *ap; @@ -3177,6 +1502,110 @@ int eq(Eterm a, Eterm b) return 0; } +static +Sint compare_flatmap_atom_keys(const Eterm* a_keys, + const Eterm* b_keys, + int n_atoms) +{ + Eterm min_key = THE_NON_VALUE; + Eterm a, b; + int ai, bi; + Sint res; + + ASSERT(n_atoms > 0); + ASSERT(is_atom(a_keys[0]) && is_atom(b_keys[0])); + ASSERT(is_atom(a_keys[n_atoms-1]) || is_atom(b_keys[n_atoms-1])); + + ai = n_atoms; + while (*a_keys == *b_keys) { + ASSERT(is_atom(*a_keys)); + a_keys++; + b_keys++; + if (--ai == 0) + return 0; + } + + /* + * Found atom key diff. Find the smallest unique atom. + * The atoms are sorted by atom index (not term order). + * + * Continue iterate atom key arrays by always advancing the one lagging + * behind atom index-wise. Identical atoms are skipped. An atom can only be + * candidate as minimal if we have passed that atom index in the other array + * (which means the atom did not exist in the other array). + * + * There can be different number of atom keys in the arrays (n_atoms is the + * larger count). We stop when either reaching the end or finding a non-atom. + * ERTS_UINT_MAX is used as an end marker while advancing the other one. + */ + bi = ai; + a = *a_keys; + b = *b_keys; + IF_DEBUG(res = 0); + if (!is_atom(a)) { + ASSERT(is_atom(b)); + return +1; + } + else if (!is_atom(b)) { + return -1; + } + do { + ASSERT(is_atom(a) || a == ERTS_UINT_MAX); + ASSERT(is_atom(b) || b == ERTS_UINT_MAX); + ASSERT(is_atom(a) || is_atom(b)); + + if (a < b) { + ASSERT(ai && is_atom(a)); + if (is_non_value(min_key) || erts_cmp_atoms(a, min_key) < 0) { + min_key = a; + res = -1; + } + if (--ai) { + a = *(++a_keys); + if (is_not_atom(a)) + a = ERTS_UINT_MAX; + } + else + a = ERTS_UINT_MAX; + } + else if (a > b) { + ASSERT(bi && is_atom(b)); + if (is_non_value(min_key) || erts_cmp_atoms(b, min_key) < 0) { + min_key = b; + res = +1; + } + if (--bi) { + b = *(++b_keys); + if (is_not_atom(b)) + b = ERTS_UINT_MAX; + } + else + b = ERTS_UINT_MAX; + } + else { + ASSERT(ai && bi && is_atom(a) && is_atom(b)); + if (--ai) { + a = *(++a_keys); + if (is_not_atom(a)) + a = ERTS_UINT_MAX; + } + else + a = ERTS_UINT_MAX; + if (--bi) { + b = *(++b_keys); + if (is_not_atom(b)) + b = ERTS_UINT_MAX; + } + else + b = ERTS_UINT_MAX; + } + } while (~(a&b)); + + ASSERT(a == ERTS_UINT_MAX && b == ERTS_UINT_MAX); + ASSERT(is_atom(min_key)); + ASSERT(res != 0); + return res; +} /* @@ -3197,16 +1626,19 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only); */ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) { -#define PSTACK_TYPE struct erts_cmp_hashmap_state - struct erts_cmp_hashmap_state { +#define PSTACK_TYPE struct cmp_map_state + struct cmp_map_state { Sint wstack_rollback; - int was_exact; - Eterm *ap; - Eterm *bp; + int was_exact; /* hashmap only */ + Eterm *atom_keys; /* flatmap only */ + Eterm *ap, *bp; /* hashmap: kv-cons, flatmap: values */ Eterm min_key; Sint cmp_res; /* result so far -1,0,+1 */ +#ifdef DEBUG + int is_hashmap; +#endif }; - PSTACK_DECLARE(hmap_stack, 1); + PSTACK_DECLARE(map_stack, 1); WSTACK_DECLARE(stack); WSTACK_DECLARE(b_stack); /* only used by hashmaps */ Eterm* aa; @@ -3233,10 +1665,12 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) #define HASHMAP_PHASE2_ARE_KEYS_EQUAL 5 #define HASHMAP_PHASE2_IS_MIN_KEY_A 6 #define HASHMAP_PHASE2_IS_MIN_KEY_B 7 +#define FLATMAP_ATOM_KEYS 8 +#define FLATMAP_ATOM_VALUES 9 +#define FLATMAP_ATOM_CMP_VALUES 10 - -#define OP_WORD(OP) (((OP) << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) -#define TERM_ARRAY_OP_WORD(SZ) OP_WORD(((SZ) << OP_BITS) | TERM_ARRAY_OP) +#define OP_WORD(OP) (((OP) << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER) +#define OP_ARG_WORD(OP, SZ) OP_WORD(((SZ) << OP_BITS) | OP) #define GET_OP(WORD) (ASSERT(is_header(WORD)), ((WORD) >> _TAG_PRIMARY_SIZE) & OP_MASK) #define GET_OP_ARG(WORD) (ASSERT(is_header(WORD)), ((WORD) >> (OP_BITS + _TAG_PRIMARY_SIZE))) @@ -3410,52 +1844,121 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto term_array; case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE) : { - struct erts_cmp_hashmap_state* sp; + struct cmp_map_state* sp; if (is_flatmap_header(ahdr)) { + flatmap_t* afm = (flatmap_t*)flatmap_val(a); + flatmap_t* bfm; if (!is_flatmap(b)) { if (is_hashmap(b)) { - aa = (Eterm *)flatmap_val(a); - i = flatmap_get_size((flatmap_t*)aa) - hashmap_size(b); - ASSERT(i != 0); - RETURN_NEQ(i); + ASSERT(flatmap_get_size(afm) < hashmap_size(b)); + RETURN_NEQ(-1); } a_tag = MAP_DEF; goto mixed_types; } - aa = (Eterm *)flatmap_val(a); - bb = (Eterm *)flatmap_val(b); - - i = flatmap_get_size((flatmap_t*)aa); - if (i != flatmap_get_size((flatmap_t*)bb)) { - RETURN_NEQ((int)(i - flatmap_get_size((flatmap_t*)bb))); + bfm = (flatmap_t*)flatmap_val(b); + i = flatmap_get_size(afm); + if (i != flatmap_get_size(bfm)) { + RETURN_NEQ((int)(i - flatmap_get_size(bfm))); } if (i == 0) { goto pop_next; } - aa += 2; - bb += 2; if (exact) { + /* + * We only care about equality so we can compare + * the maps as two term arrays where the first + * element pair are the key tuples. + */ + aa = &afm->keys; + bb = &bfm->keys; i += 1; /* increment for tuple-keys */ goto term_array; } else { - /* Value array */ - WSTACK_PUSH3(stack,(UWord)(bb+1),(UWord)(aa+1),TERM_ARRAY_OP_WORD(i)); - /* Switch back from 'exact' key compare */ - WSTACK_PUSH(stack,OP_WORD(SWITCH_EXACT_OFF_OP)); - /* Now do 'exact' compare of key tuples */ - a = *aa; - b = *bb; - exact = 1; - goto bodyrecur; + Eterm* a_keys = flatmap_get_keys(afm); + Eterm* b_keys = flatmap_get_keys(bfm); + Eterm* a_vals = flatmap_get_values(afm); + Eterm* b_vals = flatmap_get_values(bfm); + int n_numbers; /* sorted before atoms */ + int n_atoms; + int n_rest; /* sorted after atoms */ + int n = 0; + + /* + * All keys are sorted in term order except atoms + * which are sorted by atom index. The compare + * algorithm is optimized to only have to treat + * atoms specially and use the term order for other + * keys. + * The key arrays are divided into three possible + * partitions containing: + * #1. all numbers (< atoms) + * #2. atoms + * #3. only the rest (> atoms) + * + * The tree partions are compared separately in two + * phases, first only keys and then values. + */ + while (n < i && !(is_atom(a_keys[n]) && + is_atom(b_keys[n]))) { + ++n; + } + n_numbers = n; + while (n < i && (is_atom(a_keys[n]) || + is_atom(b_keys[n]))) { + ++n; + } + n_atoms = n - n_numbers; + n_rest = i - n; + + ASSERT(n_numbers + n_atoms + n_rest == i); + ASSERT(n_atoms || !n_rest); + + if (n_rest) { + WSTACK_PUSH3(stack, + (UWord)&b_vals[n_numbers+n_atoms], + (UWord)&a_vals[n_numbers+n_atoms], + OP_ARG_WORD(TERM_ARRAY_OP,n_rest)); + } + if (n_atoms) { + WSTACK_PUSH4(stack, + (UWord)&b_vals[n_numbers], + (UWord)&a_vals[n_numbers], + (UWord)&a_keys[n_numbers], + OP_ARG_WORD(FLATMAP_ATOM_VALUES,n_atoms)); + } + if (n_numbers) { + WSTACK_PUSH3(stack, (UWord)b_vals, (UWord)a_vals, + OP_ARG_WORD(TERM_ARRAY_OP,n_numbers)); + } + if (!exact) { + WSTACK_PUSH(stack, OP_WORD(SWITCH_EXACT_OFF_OP)); + exact = 1; + } + if (n_rest) { + WSTACK_PUSH3(stack, + (UWord)&b_keys[n_numbers+n_atoms], + (UWord)&a_keys[n_numbers+n_atoms], + OP_ARG_WORD(TERM_ARRAY_OP,n_rest)); + } + if (n_atoms) { + WSTACK_PUSH3(stack, + (UWord)&b_keys[n_numbers], + (UWord)&a_keys[n_numbers], + OP_ARG_WORD(FLATMAP_ATOM_KEYS,n_atoms)); + } + if (n_numbers) { + WSTACK_PUSH3(stack, (UWord)b_keys, (UWord)a_keys, + OP_ARG_WORD(TERM_ARRAY_OP,n_numbers)); + } } + goto pop_next; } if (!is_hashmap(b)) { if (is_flatmap(b)) { - bb = (Eterm *)flatmap_val(b); - i = hashmap_size(a) - flatmap_get_size((flatmap_t*)bb); - ASSERT(i != 0); - RETURN_NEQ(i); + ASSERT(hashmap_size(a) > flatmap_get_size(flatmap_val(b))); + RETURN_NEQ(1); } a_tag = MAP_DEF; goto mixed_types; @@ -3487,7 +1990,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) one lagging behind key-wise. */ - sp = PSTACK_PUSH(hmap_stack); + sp = PSTACK_PUSH(map_stack); + IF_DEBUG(sp->is_hashmap = 1); hashmap_iterator_init(&stack, a, 0); hashmap_iterator_init(&b_stack, b, 0); sp->ap = hashmap_iterator_next(&stack); @@ -3522,58 +2026,69 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto mixed_types; } ON_CMP_GOTO(big_comp(a, b)); - case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE): - if (!is_export(b)) { - a_tag = EXPORT_DEF; - goto mixed_types; - } else { - Export* a_exp = *((Export **) (export_val(a) + 1)); - Export* b_exp = *((Export **) (export_val(b) + 1)); - if ((j = erts_cmp_atoms(a_exp->info.mfa.module, - b_exp->info.mfa.module)) != 0) { - RETURN_NEQ(j); - } - if ((j = erts_cmp_atoms(a_exp->info.mfa.function, - b_exp->info.mfa.function)) != 0) { - RETURN_NEQ(j); - } - ON_CMP_GOTO((Sint) a_exp->info.mfa.arity - (Sint) b_exp->info.mfa.arity); - } - break; - case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): - if (!is_fun(b)) { - a_tag = FUN_DEF; - goto mixed_types; - } else { - ErlFunThing* f1 = (ErlFunThing *) fun_val(a); - ErlFunThing* f2 = (ErlFunThing *) fun_val(b); - Sint diff; + case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): + if (is_not_any_fun(b)) { + a_tag = FUN_DEF; + goto mixed_types; + } else { + ErlFunThing* f1 = (ErlFunThing *) fun_val(a); + ErlFunThing* f2 = (ErlFunThing *) fun_val(b); - diff = erts_cmp_atoms((f1->fe)->module, (f2->fe)->module); - if (diff != 0) { - RETURN_NEQ(diff); - } - diff = f1->fe->index - f2->fe->index; - if (diff != 0) { - RETURN_NEQ(diff); - } - diff = f1->fe->old_uniq - f2->fe->old_uniq; - if (diff != 0) { - RETURN_NEQ(diff); - } - diff = f1->num_free - f2->num_free; - if (diff != 0) { - RETURN_NEQ(diff); - } - i = f1->num_free; - if (i == 0) goto pop_next; - aa = f1->env; - bb = f2->env; - goto term_array; - } - case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE): - if (!is_pid(b)) { + if (is_local_fun(f1) && is_local_fun(f2)) { + ErlFunEntry* fe1 = f1->entry.fun; + ErlFunEntry* fe2 = f2->entry.fun; + + Sint diff; + + diff = erts_cmp_atoms(fe1->module, (fe2)->module); + + if (diff != 0) { + RETURN_NEQ(diff); + } + + diff = fe1->index - fe2->index; + if (diff != 0) { + RETURN_NEQ(diff); + } + + diff = fe1->old_uniq - fe2->old_uniq; + if (diff != 0) { + RETURN_NEQ(diff); + } + + diff = f1->num_free - f2->num_free; + if (diff != 0) { + RETURN_NEQ(diff); + } + + i = f1->num_free; + if (i == 0) goto pop_next; + aa = f1->env; + bb = f2->env; + goto term_array; + } else if (is_external_fun(f1) && is_external_fun(f2)) { + Export* a_exp = f1->entry.exp; + Export* b_exp = f2->entry.exp; + + if ((j = erts_cmp_atoms(a_exp->info.mfa.module, + b_exp->info.mfa.module)) != 0) { + RETURN_NEQ(j); + } + if ((j = erts_cmp_atoms(a_exp->info.mfa.function, + b_exp->info.mfa.function)) != 0) { + RETURN_NEQ(j); + } + + ON_CMP_GOTO((Sint) a_exp->info.mfa.arity - + (Sint) b_exp->info.mfa.arity); + } else { + /* External funs compare greater than local ones. */ + RETURN_NEQ(is_external_fun(f1) - is_external_fun(f2)); + } + } + case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE): + if (!is_pid(b)) { a_tag = EXTERNAL_PID_DEF; goto mixed_types; } @@ -3852,7 +2367,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto not_equal; } } else { - WSTACK_PUSH3(stack, (UWord)bb, (UWord)aa, TERM_ARRAY_OP_WORD(i)); + WSTACK_PUSH3(stack, (UWord)bb, (UWord)aa, + OP_ARG_WORD(TERM_ARRAY_OP,i)); goto tailrecur_ne; } } @@ -3864,7 +2380,7 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) pop_next: if (!WSTACK_ISEMPTY(stack)) { UWord something = WSTACK_POP(stack); - struct erts_cmp_hashmap_state* sp; + struct cmp_map_state* sp; if (primary_tag((Eterm) something) == TAG_PRIMARY_HEADER) { /* an operation */ switch (GET_OP(something)) { case TERM_ARRAY_OP: @@ -3880,7 +2396,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto pop_next; case HASHMAP_PHASE1_ARE_KEYS_EQUAL: { - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j) { /* Key diff found, enter phase 2 */ int hash_cmp = hashmap_key_hash_cmp(sp->ap, sp->bp); @@ -3923,7 +2440,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto bodyrecur; } case HASHMAP_PHASE1_IS_MIN_KEY: - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j < 0) { a = CDR(sp->ap); b = CDR(sp->bp); @@ -3935,7 +2453,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto case_HASHMAP_PHASE1_LOOP; case HASHMAP_PHASE1_CMP_VALUES: - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j) { sp->cmp_res = j; sp->min_key = CAR(sp->ap); @@ -3948,7 +2467,7 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) ASSERT(!sp->bp); /* as we assume indentical map sizes */ j = sp->cmp_res; exact = sp->was_exact; - (void) PSTACK_POP(hmap_stack); + (void) PSTACK_POP(map_stack); ON_CMP_GOTO(j); } a = CAR(sp->ap); @@ -3970,7 +2489,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto case_HASHMAP_PHASE2_NEXT_STEP; case HASHMAP_PHASE2_ARE_KEYS_EQUAL: - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j == 0) { /* keys are equal, skip them */ sp->ap = hashmap_iterator_next(&stack); @@ -4007,11 +2527,12 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) /* End of both maps */ j = sp->cmp_res; exact = sp->was_exact; - (void) PSTACK_POP(hmap_stack); + (void) PSTACK_POP(map_stack); ON_CMP_GOTO(j); case HASHMAP_PHASE2_IS_MIN_KEY_A: - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j < 0) { sp->min_key = CAR(sp->ap); sp->cmp_res = -1; @@ -4020,7 +2541,8 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto case_HASHMAP_PHASE2_LOOP; case HASHMAP_PHASE2_IS_MIN_KEY_B: - sp = PSTACK_TOP(hmap_stack); + sp = PSTACK_TOP(map_stack); + ASSERT(sp->is_hashmap); if (j < 0) { sp->min_key = CAR(sp->bp); sp->cmp_res = 1; @@ -4028,6 +2550,58 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) sp->bp = hashmap_iterator_next(&b_stack); goto case_HASHMAP_PHASE2_LOOP; + case FLATMAP_ATOM_KEYS: + i = GET_OP_ARG(something); + aa = (Eterm*) WSTACK_POP(stack); + bb = (Eterm*) WSTACK_POP(stack); + ON_CMP_GOTO(compare_flatmap_atom_keys(aa, bb, i)); + + case FLATMAP_ATOM_VALUES: { + /* + * Compare values of equal atom keys. + * Find the smallest atom key where the values differ + */ + sp = PSTACK_PUSH(map_stack); + IF_DEBUG(sp->is_hashmap = 0); + sp->atom_keys = (Eterm*) WSTACK_POP(stack); + sp->ap = (Eterm*) WSTACK_POP(stack); + sp->bp = (Eterm*) WSTACK_POP(stack); + sp->min_key = THE_NON_VALUE; + sp->cmp_res = 0; + + case_FLATMAP_ATOM_VALUES_LOOP: + i = GET_OP_ARG(something); + + while (i--) { + ASSERT(is_atom(*sp->atom_keys)); + + if (is_non_value(sp->min_key) + || erts_cmp_atoms(*sp->atom_keys, sp->min_key) < 0) { + a = *sp->ap++; + b = *sp->bp++; + WSTACK_PUSH(stack, OP_ARG_WORD(FLATMAP_ATOM_CMP_VALUES,i)); + sp->wstack_rollback = WSTACK_COUNT(stack); + goto bodyrecur; + } + sp->atom_keys++; + sp->ap++; + sp->bp++; + } + j = sp->cmp_res; + (void) PSTACK_POP(map_stack); + ON_CMP_GOTO(j); + + case FLATMAP_ATOM_CMP_VALUES: + sp = PSTACK_TOP(map_stack); + ASSERT(!sp->is_hashmap); + if (j) { + sp->min_key = *sp->atom_keys; + sp->cmp_res = j; + } + sp->atom_keys++; + goto case_FLATMAP_ATOM_VALUES_LOOP; + } + default: ASSERT(!"Invalid cmp op"); } /* switch */ @@ -4037,18 +2611,18 @@ Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) goto tailrecur; } - ASSERT(PSTACK_IS_EMPTY(hmap_stack)); - PSTACK_DESTROY(hmap_stack); + ASSERT(PSTACK_IS_EMPTY(map_stack)); + PSTACK_DESTROY(map_stack); WSTACK_DESTROY(stack); WSTACK_DESTROY(b_stack); return 0; not_equal: - if (!PSTACK_IS_EMPTY(hmap_stack) && !eq_only) { - WSTACK_ROLLBACK(stack, PSTACK_TOP(hmap_stack)->wstack_rollback); + if (!PSTACK_IS_EMPTY(map_stack) && !eq_only) { + WSTACK_ROLLBACK(stack, PSTACK_TOP(map_stack)->wstack_rollback); goto pop_next; } - PSTACK_DESTROY(hmap_stack); + PSTACK_DESTROY(map_stack); WSTACK_DESTROY(stack); WSTACK_DESTROY(b_stack); return j; @@ -4158,14 +2732,16 @@ intlist_to_buf(Eterm list, char *buf, Sint len) } /** @brief Fill buf with the UTF8 contents of the unicode list - * @param len Max number of characters to write. - * @param written NULL or bytes written. + * (no terminating NULL character written) + * @param capacity Max number of bytes to write. + * @param len Max number of characters to write. + * @param written NULL or bytes written. * @return 0 ok, * -1 type error, - * -2 list too long, only \c len characters written + * -2 list too long, not all characters written */ int -erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written) +erts_unicode_list_to_buf(Eterm list, byte *buf, Sint capacity, Sint len, Sint* written) { Eterm* listptr; Sint sz = 0; @@ -4194,9 +2770,19 @@ erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written) } val = (Uint) signed_val(CAR(listptr)); if (val < 0x80) { + capacity -= 1; + if (capacity < 0) { + res = -2; + break; + } buf[sz] = val; sz++; } else if (val < 0x800) { + capacity -= 2; + if (capacity < 0) { + res = -2; + break; + } buf[sz+0] = 0xC0 | (val >> 6); buf[sz+1] = 0x80 | (val & 0x3F); sz += 2; @@ -4205,11 +2791,21 @@ erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written) res = -1; break; } + capacity -= 3; + if (capacity < 0) { + res = -2; + break; + } buf[sz+0] = 0xE0 | (val >> 12); buf[sz+1] = 0x80 | ((val >> 6) & 0x3F); buf[sz+2] = 0x80 | (val & 0x3F); sz += 3; } else if (val < 0x110000) { + capacity -= 4; + if (capacity < 0) { + res = -2; + break; + } buf[sz+0] = 0xF0 | (val >> 18); buf[sz+1] = 0x80 | ((val >> 12) & 0x3F); buf[sz+2] = 0x80 | ((val >> 6) & 0x3F); @@ -5172,7 +3768,7 @@ erts_ptr_id(void *ptr) return ptr; } -const void *erts_get_stacklimit() { +const void *erts_get_stacklimit(void) { return ethr_get_stacklimit(); } @@ -5197,15 +3793,7 @@ erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, Eterm args, Eterm* mfa_p, Eterm Eterm tuple; int line = LOC_LINE(fi->loc); int file = LOC_FILE(fi->loc); - Eterm file_term = NIL; - - if (file == 0) { - Atom* ap = atom_tab(atom_val(fi->mfa->module)); - file_term = buf_to_intlist(&hp, ".erl", 4, NIL); - file_term = buf_to_intlist(&hp, (char*)ap->name, ap->len, file_term); - } else { - file_term = erts_atom_to_string(&hp, (fi->fname_ptr)[file-1]); - } + Eterm file_term = fi->fname_ptr[file]; tuple = TUPLE2(hp, am_line, make_small(line)); hp += 3; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index cf3c5fa3f69d..73cee97aa005 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2022. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -111,6 +111,52 @@ #include "erl_driver.h" + +#if !defined(TRUE) +#define TRUE 1 +#endif +#if !defined(FALSE) +#define FALSE 0 +#endif + +/* Descriptor debug */ +/* #define INET_DRV_DEBUG 1 */ +#ifdef INET_DRV_DEBUG +#define DDBG_DEFAULT TRUE +#else +#define DDBG_DEFAULT FALSE +#endif +#define DDBG(__D__, __ARG__) \ + do if ( (__D__)->debug ) { erts_printf __ARG__ ; } while (0) + +#define B2S(__B__) ((__B__) ? "true" : "false") +#define SH2S(__H__) (((__H__) == TCP_SHUT_WR) ? "write" : \ + (((__H__) == TCP_SHUT_RD) ? "read" : \ + (((__H__) == TCP_SHUT_RDWR) ? "read-write" : \ + "undefined"))) +#define A2S(__A__) (((__A__) == INET_PASSIVE) ? "passive" : \ + (((__A__) == INET_ACTIVE) ? "active" : \ + (((__A__) == INET_ONCE) ? "once" : \ + (((__A__) == INET_MULTI) ? "multi" : \ + "undefined")))) +#define M2S(__M__) (((__M__) == INET_MODE_LIST) ? "list" : \ + (((__M__) == INET_MODE_BINARY) ? "binary" : \ + "undefined")) +#define D2S(__D__) (((__D__) == INET_DELIVER_PORT) ? "port" : \ + (((__D__) == INET_DELIVER_TERM) ? "term" : \ + "undefined")) +#define DOM2S(__D__) (((__D__) == INET_AF_INET) ? "inet" : \ + (((__D__) == INET_AF_INET6) ? "inet6" : \ + (((__D__) == INET_AF_LOCAL) ? "local" : \ + "undefined"))) + +#if defined(__WIN32__) && defined(ARCH_64) +#define SOCKET_FSTR "%lld" +#else +#define SOCKET_FSTR "%d" +#endif + + /* The IS_SOCKET_ERROR macro below is used for portability reasons. While POSIX specifies that errors from socket-related system calls should be indicated with a -1 return value, some users have experienced non-Windows @@ -517,6 +563,13 @@ static typeof(sctp_freepaddrs) *p_sctp_freepaddrs = NULL; static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #endif +#if defined(__GNUC__) && defined(HAVE_SCTP_CONNECTX) +static typeof(sctp_connectx) *p_sctp_connectx = NULL; +#else +static int (*p_sctp_connectx) + (int sd, struct sockaddr * addrs, int addrcnt, sctp_assoc_t * assoc_id) = NULL; +#endif + #endif /* #if defined(HAVE_SCTP_H) */ #ifndef WANT_NONBLOCKING @@ -524,13 +577,13 @@ static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #endif #include "sys.h" -/* #define INET_DRV_DEBUG 1 */ #ifdef INET_DRV_DEBUG #define DEBUG 1 -#undef DEBUGF -#define DEBUGF(X) printf X +#undef DEBUGF +#define DEBUGF(__X__) erts_printf __X__ #endif + #if !defined(HAVE_STRNCASECMP) #define STRNCASECMP my_strncasecmp @@ -690,6 +743,7 @@ static size_t my_strnlen(const char *s, size_t maxlen) #define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */ #define INET_AF_LOCAL 5 #define INET_AF_UNDEFINED 6 /* Unknown */ +#define INET_AF_LIST 7 /* List of addresses for sctp connectx */ /* open and INET_REQ_GETTYPE enumeration */ #define INET_TYPE_STREAM 1 @@ -809,6 +863,9 @@ static size_t my_strnlen(const char *s, size_t maxlen) #define UDP_OPT_ADD_MEMBERSHIP 14 /* add an IP group membership */ #define UDP_OPT_DROP_MEMBERSHIP 15 /* drop an IP group membership */ #define INET_OPT_IPV6_V6ONLY 16 /* IPv6 only socket, no mapped v4 addrs */ +#define INET_OPT_REUSEPORT 17 /* enable/disable local port reuse */ +#define INET_OPT_REUSEPORT_LB 18 /* enable/disable local port reuse */ +#define INET_OPT_EXCLUSIVEADDRUSE 19 /* windows specific exclusive addr */ /* LOPT is local options */ #define INET_LOPT_BUFFER 20 /* min buffer size hint */ #define INET_LOPT_HEADER 21 /* list header size */ @@ -839,6 +896,8 @@ static size_t my_strnlen(const char *s, size_t maxlen) #define INET_OPT_TTL 46 /* IP_TTL */ #define INET_OPT_RECVTTL 47 /* IP_RECVTTL ancillary data */ #define TCP_OPT_NOPUSH 48 /* super-Nagle, aka TCP_CORK */ +#define INET_LOPT_DEBUG 99 /* Enable/disable DEBUG for a socket */ + /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1014,6 +1073,26 @@ typedef union { } inet_address; +/* On some platforms, for instance FreeBSD, this option is instead + * called IPV6_JOIN_GROUP and IPV6_JOIN_GROUP. */ + +#if defined(HAVE_IN6) + +#if defined(IPV6_ADD_MEMBERSHIP) +#define INET_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP +#elif defined(IPV6_JOIN_GROUP) +#define INET_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + +#if defined(IPV6_DROP_MEMBERSHIP) +#define INET_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP +#elif defined(IPV6_LEAVE_GROUP) +#define INET_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + +#endif + + #define inet_address_port(x) \ ((((x)->sai.sin_family == AF_INET) || \ ((x)->sai.sin_family == AF_INET6)) ? \ @@ -1039,6 +1118,11 @@ typedef union { (1 + 2 + 4) : localaddrlen(data)) #endif +typedef struct { + ErlDrvSizeT tag_len; + char *tag_buf; +} CallerRef; + typedef int (MultiTimerFunction)(ErlDrvData drv_data, ErlDrvTermData caller); typedef struct _multi_timer_data { @@ -1109,10 +1193,13 @@ typedef struct { (affect how to interpret hsz) */ int exitf; /* exit port on close or not */ int deliver; /* Delivery mode, TERM or PORT */ +#ifdef __WIN32__ + /* placed here in order to not consume more memory in 64-bit case... */ + int bsd_compat; /* State for Windows compatibility with BSD */ +#endif - ErlDrvTermData caller; /* recipient of sync reply */ - ErlDrvTermData busy_caller; /* recipient of sync reply when caller busy. - * Only valid while INET_F_BUSY. */ + ErlDrvTermData caller; /* recipient of sync reply */ + CallerRef caller_ref; inet_async_op* oph; /* queue head or NULL */ inet_async_op* opt; /* queue tail or NULL */ @@ -1148,7 +1235,7 @@ typedef struct { unsigned long recv_cnt; /* number of packets received */ unsigned long recv_max; /* maximum packet size received */ double recv_avg; /* average packet size received */ - double recv_dvi; /* avarage deviation from avg_size */ + double recv_dvi; /* average deviation from avg_size */ #ifdef ARCH_64 Uint64 send_oct; /* number of octets sent, 64 bits */ #else @@ -1166,6 +1253,7 @@ typedef struct { as full file path */ #endif int recv_cmsgflags; /* Which ancillary data to expect */ + int debug; /* debug enabled or not */ } inet_descriptor; @@ -1460,6 +1548,9 @@ static ErlDrvTermData am_linger; static ErlDrvTermData am_recbuf; static ErlDrvTermData am_sndbuf; static ErlDrvTermData am_reuseaddr; +static ErlDrvTermData am_reuseport; +static ErlDrvTermData am_reuseport_lb; +static ErlDrvTermData am_exclusiveaddruse; static ErlDrvTermData am_dontroute; static ErlDrvTermData am_priority; static ErlDrvTermData am_recvtos; @@ -1558,12 +1649,12 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ return ret; } #define REALLOC(X,Y) realloc_wrapper(X,Y) -#define FREE(P) driver_free((P)) +#define FREE(P) driver_free((P)) #else /* FATAL_MALLOC */ -#define ALLOC(X) driver_alloc((X)) +#define ALLOC(X) driver_alloc((X)) #define REALLOC(X,Y) driver_realloc((X), (Y)) -#define FREE(P) driver_free((P)) +#define FREE(P) driver_free((P)) #endif /* FATAL_MALLOC */ @@ -1645,6 +1736,100 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ ((vec)[(i)+1] = (size)), \ ((i)+LOAD_LIST_CNT)) +#define LOAD_EXT_CNT 3 +#define LOAD_EXT(vec, i, buf, len) \ + (((vec)[(i)] = ERL_DRV_EXT2TERM), \ + ((vec)[(i)+1] = (ErlDrvTermData)(buf)), \ + ((vec)[(i)+2] = (len)), \ + ((i)+LOAD_EXT_CNT)) + + +static void iov_memmove(char *buf, SysIOVec **iov_pp, ErlDrvSizeT size) { + int i; + for (i = 0; size != 0; i++) { + if ((*iov_pp)[i].iov_len < size) { + if ((*iov_pp)[i].iov_len == 0) continue; + sys_memcpy(buf, (*iov_pp)[i].iov_base, (*iov_pp)[i].iov_len); + buf += (*iov_pp)[i].iov_len; + size -= (*iov_pp)[i].iov_len; + (*iov_pp)[i].iov_base = + (char*)((*iov_pp)[i].iov_base) + (*iov_pp)[i].iov_len; + (*iov_pp)[i].iov_len = 0; + } + else { + sys_memcpy(buf, (*iov_pp)[i].iov_base, size); + (*iov_pp)[i].iov_base = (char*)((*iov_pp)[i].iov_base) + size; + (*iov_pp)[i].iov_len -= size; + break; + } + } +} + +/* Returns TRUE on success, FALSE on failure */ +static int init_caller_iov(ErlDrvTermData *caller_p, + CallerRef *cref_p, + ErlDrvPort port, + SysIOVec **iov_pp, + ErlDrvSizeT *size_p) { + ErlDrvTermData caller; + char buf[2]; + ErlDrvUInt n; + /**/ + caller = driver_caller(port); + if (is_not_internal_pid(caller)) { + return TRUE; + } + *caller_p = caller; + if (*size_p < 2) return FALSE; + iov_memmove(buf, iov_pp, 2); + *size_p -= 2; + n = get_int16(buf); + if (*size_p < n) return FALSE; + cref_p->tag_buf = ALLOC(n); + iov_memmove(cref_p->tag_buf, iov_pp, n); + *size_p -= n; + cref_p->tag_len = n; + return TRUE; +} + +/* Returns TRUE on success, FALSE on failure */ +static int init_caller(ErlDrvTermData *caller_p, + CallerRef *cref_p, + ErlDrvPort port, + char **buf_p, + ErlDrvSizeT *size_p) { + ErlDrvTermData caller; + ErlDrvUInt n; + /**/ + caller = driver_caller(port); + if (is_not_internal_pid(caller)) { + return TRUE; + } + *caller_p = caller; + if (*size_p < 2) return FALSE; + n = get_int16(*buf_p); + *buf_p += 2; + *size_p -= 2; + if (*size_p < n) return FALSE; + cref_p->tag_buf = ALLOC(n); + sys_memcpy(cref_p->tag_buf, *buf_p, n); + *buf_p += n; + *size_p -= n; + cref_p->tag_len = n; + return TRUE; +} + +static CallerRef no_caller_ref(void) { + CallerRef ret = {0, NULL}; + return ret; +} + +static void end_caller_ref(CallerRef *cref_p) { + if (cref_p->tag_buf != NULL) FREE(cref_p->tag_buf); + *cref_p = no_caller_ref(); +} + + #ifdef HAVE_SCTP /* "IS_SCTP": tells the difference between a UDP and an SCTP socket: */ @@ -1775,7 +1960,7 @@ static int load_inet_get_address #define INET_DRV_CACHE_LINE_MASK (INET_DRV_CACHE_LINE_SIZE - 1) /* -** Binary Buffer Managment +** Binary Buffer Management ** We keep a stack of usable buffers */ #define BUFFER_STACK_SIZE 14 @@ -2302,6 +2487,43 @@ static int async_ok(inet_descriptor* desc) return send_async_ok(desc->dport, aid, caller); } +#ifdef HAVE_SCTP +static int async_ok_assoc_id(inet_descriptor* desc, sctp_assoc_t assoc_id) +{ + int req; + int aid; + int i = 0; + ErlDrvTermData caller; + ErlDrvTermData spec[2*LOAD_ATOM_CNT + LOAD_PORT_CNT + LOAD_INT_CNT + + LOAD_ASSOC_ID_CNT + 2*LOAD_TUPLE_CNT]; + + if (deq_async(desc, &aid, &caller, &req) < 0) + return -1; + + i = LOAD_ATOM(spec, i, am_inet_async); + i = LOAD_PORT(spec, i, desc->dport); + i = LOAD_INT(spec, i, aid); + { + i = LOAD_ATOM(spec, i, am_ok); + i = LOAD_ASSOC_ID(spec, i, assoc_id); + i = LOAD_TUPLE(spec, i, 2); + } + i = LOAD_TUPLE(spec, i, 4); + + ASSERT(i == sizeof(spec)/sizeof(*spec)); + + return erl_drv_send_term(desc->dport, caller, spec, i); +} + +static int async_ok_maybe_assoc_id(inet_descriptor* desc, sctp_assoc_t *p_assoc_id) +{ + if (p_assoc_id) + return async_ok_assoc_id(desc, *p_assoc_id); + else + return async_ok(desc); +} +#endif + static int async_ok_port(inet_descriptor* desc, ErlDrvTermData Port2) { int req; @@ -2343,73 +2565,101 @@ static int async_error(inet_descriptor* desc, int err) return async_error_am(desc, error_atom(err)); } + +/* Maybe append the caller tag then send to caller */ +static int +inet_reply_finish(inet_descriptor *desc, ErlDrvTermData *spec, int i) { + int ret; + ErlDrvSizeT tuple_size; + CallerRef *cref_p; + /**/ + ret = 0; + cref_p = &desc->caller_ref; + if (i == 0) goto done; + if (cref_p->tag_buf != NULL) { + tuple_size = spec[i - 1]; + i = LOAD_EXT(spec, i - LOAD_TUPLE_CNT, + cref_p->tag_buf, cref_p->tag_len); + i = LOAD_TUPLE(spec, i, tuple_size + 1); + } + ret = erl_drv_send_term(desc->dport, desc->caller, spec, i); + done: + desc->caller = am_undefined; + end_caller_ref(cref_p); + return ret; +} + /* send: -** {inet_reply, S, ok} +** {inet_reply, S, ok[, CallerTag]} */ - static int inet_reply_ok(inet_descriptor* desc) { - ErlDrvTermData spec[2*LOAD_ATOM_CNT + LOAD_PORT_CNT + LOAD_TUPLE_CNT]; - ErlDrvTermData caller = desc->caller; + ErlDrvTermData + spec[2*LOAD_ATOM_CNT + LOAD_PORT_CNT + LOAD_TUPLE_CNT + + LOAD_EXT_CNT]; int i = 0; - - desc->caller = 0; - if (is_not_internal_pid(caller)) - return 0; + + if (is_not_internal_pid(desc->caller)) goto done; i = LOAD_ATOM(spec, i, am_inet_reply); i = LOAD_PORT(spec, i, desc->dport); i = LOAD_ATOM(spec, i, am_ok); i = LOAD_TUPLE(spec, i, 3); - ASSERT(i == sizeof(spec)/sizeof(*spec)); - - return erl_drv_send_term(desc->dport, caller, spec, i); + ASSERT(i == sizeof(spec)/sizeof(*spec) - LOAD_EXT_CNT); + done: + return inet_reply_finish(desc, spec, i); } #ifdef HAVE_SCTP static int inet_reply_ok_port(inet_descriptor* desc, ErlDrvTermData dport) { - ErlDrvTermData spec[2*LOAD_ATOM_CNT + 2*LOAD_PORT_CNT + 2*LOAD_TUPLE_CNT]; - ErlDrvTermData caller = desc->caller; + ErlDrvTermData + spec[2*LOAD_ATOM_CNT + 2*LOAD_PORT_CNT + 2*LOAD_TUPLE_CNT + + LOAD_EXT_CNT]; int i = 0; + if (is_not_internal_pid(desc->caller)) goto done; + i = LOAD_ATOM(spec, i, am_inet_reply); i = LOAD_PORT(spec, i, desc->dport); i = LOAD_ATOM(spec, i, am_ok); i = LOAD_PORT(spec, i, dport); i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 3); - ASSERT(i == sizeof(spec)/sizeof(*spec)); - - desc->caller = 0; - return erl_drv_send_term(desc->dport, caller, spec, i); + ASSERT(i == sizeof(spec)/sizeof(*spec) - LOAD_EXT_CNT); + done: + return inet_reply_finish(desc, spec, i); } #endif /* send: -** {inet_reply, S, {error, Reason}} +** {inet_reply, S, {error, Reason}[, CallerTag]} */ static int inet_reply_error_am(inet_descriptor* desc, ErlDrvTermData reason) { - ErlDrvTermData spec[3*LOAD_ATOM_CNT + LOAD_PORT_CNT + 2*LOAD_TUPLE_CNT]; - ErlDrvTermData caller = desc->caller; + ErlDrvTermData + spec[3*LOAD_ATOM_CNT + LOAD_PORT_CNT + 2*LOAD_TUPLE_CNT + + LOAD_EXT_CNT]; int i = 0; - + + if (is_not_internal_pid(desc->caller)) goto done; + i = LOAD_ATOM(spec, i, am_inet_reply); i = LOAD_PORT(spec, i, desc->dport); i = LOAD_ATOM(spec, i, am_error); i = LOAD_ATOM(spec, i, reason); i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 3); - ASSERT(i == sizeof(spec)/sizeof(*spec)); - desc->caller = 0; - - DEBUGF(("inet_reply_error_am %ld %ld\r\n", caller, reason)); - return erl_drv_send_term(desc->dport, caller, spec, i); + ASSERT(i == sizeof(spec)/sizeof(*spec) - LOAD_EXT_CNT); + + DEBUGF(("inet_reply_error_am %ld %ld\r\n", + desc->caller, reason)); + done: + return inet_reply_finish(desc, spec, i); } /* send: -** {inet_reply, S, {error, Reason}} +** {inet_reply, S, {error, Reason}[, CallerTag]} */ static int inet_reply_error(inet_descriptor* desc, int err) { @@ -2483,7 +2733,7 @@ static int http_response_inetdrv(void *arg, int major, int minor, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[27]; - ErlDrvTermData caller = ERL_DRV_NIL; + ErlDrvTermData caller = am_undefined; if (desc->inet.active == INET_PASSIVE) { /* {inet_async,S,Ref,{ok,{http_response,Version,Status,Phrase}}} */ @@ -2576,7 +2826,7 @@ http_request_inetdrv(void* arg, const http_atom_t* meth, const char* meth_ptr, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[43]; - ErlDrvTermData caller = ERL_DRV_NIL; + ErlDrvTermData caller = am_undefined; if (desc->inet.active == INET_PASSIVE) { /* {inet_async, S, Ref, {ok,{http_request,Meth,Uri,Version}}} */ @@ -2629,7 +2879,7 @@ http_header_inetdrv(void* arg, const http_atom_t* name, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[27]; - ErlDrvTermData caller = ERL_DRV_NIL; + ErlDrvTermData caller = am_undefined; if (desc->inet.active == INET_PASSIVE) { /* {inet_async,S,Ref,{ok,{http_header,Bit,Name,Oname,Value}} */ @@ -2758,7 +3008,7 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[30]; - ErlDrvTermData caller = ERL_DRV_NIL; + ErlDrvTermData caller = am_undefined; ErlDrvBinary* bin; int ret; @@ -2853,7 +3103,7 @@ static int inet_async_data(inet_descriptor* desc, const char* buf, int len) i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 4); ASSERT(i == 15); - desc->caller = 0; + /* desc->caller = am_undefined; XXX */ return erl_drv_send_term(desc->dport, caller, spec, i); } else { @@ -2867,7 +3117,7 @@ static int inet_async_data(inet_descriptor* desc, const char* buf, int len) i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 4); ASSERT(i <= 20); - desc->caller = 0; + /* desc->caller = am_undefined; XXX */ code = erl_drv_send_term(desc->dport, caller, spec, i); return code; } @@ -3491,7 +3741,7 @@ static int compile_ancillary_data(struct msghdr *mhdr, break; } default: - /* Unknow socket option */ + /* Unknown socket option */ return 1; } #undef COMPILE_ANCILLARY_DATA_ITEM @@ -3525,7 +3775,7 @@ inet_async_binary_data { unsigned int hsz = desc->hsz + phsz; ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN]; - ErlDrvTermData caller = desc->caller; + ErlDrvTermData caller; int aid; int req; int i = 0; @@ -3626,8 +3876,9 @@ inet_async_binary_data /* Close up the outer {inet_async, S, Ref, {ok|error, ...}} tuple: */ i = LOAD_TUPLE(spec, i, 4); - ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN); - desc->caller = 0; + ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN); + desc->caller = am_undefined; + end_caller_ref(&desc->caller_ref); return erl_drv_send_term(desc->dport, caller, spec, i); } @@ -4058,6 +4309,9 @@ static void inet_init_sctp(void) { INIT_ATOM(recbuf); INIT_ATOM(sndbuf); INIT_ATOM(reuseaddr); + INIT_ATOM(reuseport); + INIT_ATOM(reuseport_lb); + INIT_ATOM(exclusiveaddruse); INIT_ATOM(dontroute); INIT_ATOM(priority); INIT_ATOM(recvtos); @@ -4167,7 +4421,7 @@ static void inet_init_sctp(void) { } #endif /* HAVE_SCTP */ -static int inet_init() +static int inet_init(void) { if (!sock_init()) goto error; @@ -4269,6 +4523,11 @@ static int inet_init() # else p_sctp_getpaddrs = NULL; p_sctp_freepaddrs = NULL; +# endif +# if defined(HAVE_SCTP_CONNECTX) + p_sctp_connectx = sctp_connectx; +# else + p_sctp_connectx = NULL; # endif inet_init_sctp(); add_driver_entry(&sctp_inet_driver_entry); @@ -4310,6 +4569,10 @@ static int inet_init() p_sctp_freepaddrs = NULL; p_sctp_getpaddrs = NULL; } + if (erts_sys_ddll_vsym(h_libsctp, "sctp_connectx", "VERS_3", &ptr) == 0) { + p_sctp_connectx = ptr; + } + else p_sctp_connectx = NULL; inet_init_sctp(); add_driver_entry(&sctp_inet_driver_entry); } @@ -4343,10 +4606,6 @@ static char* inet_set_address(int family, inet_address* dst, { short port; - // printf("inet_set_address -> entry with" - // "\r\n family: %d" - // "\r\n", family); - switch (family) { case AF_INET: { if (*len < 2+4) return str_einval; @@ -4376,12 +4635,8 @@ static char* inet_set_address(int family, inet_address* dst, sys_memcpy(&dst->sai6.sin6_addr, *src, 16); *src += 16; dst->sai6.sin6_flowinfo = get_int32(*src); - // printf("inet_set_address -> flowinfo: %u" - // "\r\n", dst->sai6.sin6_flowinfo); *src += 4; dst->sai6.sin6_scope_id = get_int32(*src); - // printf("inet_set_address -> scope_id: %u" - // "\r\n", dst->sai6.sin6_scope_id); *src += 4; *len = sizeof(struct sockaddr_in6); return NULL; @@ -4857,6 +5112,7 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, desc->state = INET_STATE_OPEN; desc->stype = type; desc->sfamily = domain; + return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } @@ -4869,6 +5125,18 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, inet_address name; SOCKLEN_T sz; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_ctl_fdopen -> entry with" + "\r\n socket: %d" + "\r\n bound: %s" + "\r\n domain: %d" + "\r\n type: %d" + "\r\n", + __LINE__, + desc->s, driver_caller(desc->port), + s, B2S(bound), domain, type) ); + if (bound) { /* check that it is a socket and that the socket is bound */ sz = sizeof(name); @@ -4902,6 +5170,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, * not certain that we can open it again */ desc->stype = type; desc->sfamily = domain; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_ctl_fdopen -> done\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } @@ -5586,7 +5860,7 @@ static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc, else { struct sockadd_in* ap; /* emulate netmask, - * (wasted stuff since noone uses classes) + * (wasted stuff since no one uses classes) */ buf_check(sptr, s_end, 1); *sptr++ = INET_IFOPT_NETMASK; @@ -5840,9 +6114,10 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, { int i; DWORD ret, n; - IP_INTERFACE_INFO *info_p; - MIB_IPADDRTABLE *ip_addrs_p; - IP_ADAPTER_ADDRESSES *ip_adaddrs_p, *ia_p; + IP_INTERFACE_INFO *info_p = NULL; + MIB_IPADDRTABLE *ip_addrs_p = NULL; + IP_ADAPTER_ADDRESSES *ip_adaddrs_p = NULL; + IP_ADAPTER_ADDRESSES *ia_p = NULL; char *buf_p; char *buf_alloc_p; @@ -5901,10 +6176,11 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, if (ret == NO_ERROR) break; if (ret == ERROR_BUFFER_OVERFLOW) continue; i = 0; + break; } if (! i) { FREE(ip_adaddrs_p); - ip_adaddrs_p = NULL; + ip_adaddrs_p = NULL; } } else ip_adaddrs_p = NULL; } @@ -5921,11 +6197,12 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, if (ret == NO_ERROR) break; if (ret == ERROR_INSUFFICIENT_BUFFER) continue; i = 0; + break; } if (! i) { - FREE(info_p); - info_p = NULL; - } + FREE(info_p); + info_p = NULL; + } } if (! ip_adaddrs_p) { @@ -5940,6 +6217,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, if (ret == NO_ERROR) break; if (ret == ERROR_INSUFFICIENT_BUFFER) continue; i = 0; + break; } if (! i) { if (info_p) FREE(info_p); @@ -5982,13 +6260,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, } else { /* Then try IP_ADAPTER_INDEX_MAP.Name (only IPv4 adapters) */ int j; - for (j = 0; j < info_p->NumAdapters; j++) { - if (info_p->Adapter[j].Index == (ULONG) ifrow.dwIndex) { - if (info_p->Adapter[j].Name[0] != 0) { - wname_p = info_p->Adapter[j].Name; + if (info_p) { + for (j = 0; j < info_p->NumAdapters; j++) { + if (info_p->Adapter[j].Index == (ULONG) ifrow.dwIndex) { + if (info_p->Adapter[j].Name[0] != 0) { + wname_p = info_p->Adapter[j].Name; + } + break; } - break; - } + } } } if (wname_p) { @@ -6345,6 +6625,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, #endif + /* Per H @ Tail-f: The original code here had problems that possibly only occur if you abuse it for non-INET sockets, but anyway: a) If the getsockopt for SO_PRIORITY or IP_TOS failed, the actual @@ -6412,6 +6693,38 @@ static int setopt_prio_tos_trick } #endif + +static +int inet_setopt(int fd, + int proto, int type, + char* arg_ptr, int arg_sz, + int propagate) +{ + int res; + +#if defined(IP_TOS) && defined(IPPROTO_IP) \ + && defined(SO_PRIORITY) && !defined(__WIN32__) + DEBUGF(("inet_setopt -> try trick setopt with" + "\r\n fd: %d" + "\r\n proto: %d" + "\r\n type: %d" + "\r\n sz: %d" + "\r\n propagate: %d" + "\r\n", fd, proto, type, arg_sz, propagate)); + res = setopt_prio_tos_trick (fd, proto, type, arg_ptr, arg_sz, propagate); +#else + DEBUGF(("inet_setopt -> try std setopt with" + "\r\n fd: %d" + "\r\n proto: %d" + "\r\n type: %d" + "\r\n sz: %d" + "\r\n", fd, proto, type, arg_sz)); + res = sock_setopt (fd, proto, type, arg_ptr, arg_sz); +#endif + + return res; +} + /* set socket options: ** return -1 on error ** 0 if ok @@ -6427,12 +6740,22 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) int proto; int opt; struct linger li_val; -#if defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP) - struct ip_mreq mreq_val; +#if defined(HAVE_MULTICAST_SUPPORT) +#if defined(IPPROTO_IP) +#if defined(HAVE_STRUCT_IP_MREQN) + struct ip_mreqn mreq4; +#else + struct ip_mreq mreq4; #endif - int ival; +#endif +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(IPPROTO_IPV6) + struct ipv6_mreq mreq6; +#endif + unsigned int mreqSz = 0; +#endif + int ival; char* arg_ptr; - int arg_sz; + int arg_sz; #ifdef SO_BINDTODEVICE char ifname[IFNAMSIZ]; #endif @@ -6447,10 +6770,13 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) if (IS_SCTP(desc)) return sctp_set_opts(desc, ptr, len); #endif - /* XXX { int i; for(i=0;i= 5) { int recv_cmsgflags; +#ifdef __WIN32__ + int bsd_compat_set = 0; + int bsd_compat_unset = 0; +#endif opt = *ptr++; ival = get_int32(ptr); @@ -6462,47 +6788,74 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) propagate = 0; recv_cmsgflags = desc->recv_cmsgflags; - switch(opt) { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts -> opt: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), opt) ); + + switch(opt) { case INET_LOPT_HEADER: - DEBUGF(("inet_set_opts(%p): s=%d, HEADER=%d\r\n", - desc->port, desc->s,ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(header) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); desc->hsz = ival; continue; case INET_LOPT_MODE: /* List or Binary: */ - DEBUGF(("inet_set_opts(%p): s=%d, MODE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(mode) -> %s (%d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + M2S(ival), ival) ); desc->mode = ival; continue; case INET_LOPT_DELIVER: - DEBUGF(("inet_set_opts(%p): s=%d, DELIVER=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(deliver) -> %s (%d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + D2S(ival), ival) ); desc->deliver = ival; continue; case INET_LOPT_BUFFER: - DEBUGF(("inet_set_opts(%p): s=%d, BUFFER=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(buffer) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (ival < INET_MIN_BUFFER) ival = INET_MIN_BUFFER; desc->bufsz = ival; desc->flags |= INET_FLG_BUFFER_SET; continue; case INET_LOPT_ACTIVE: - DEBUGF(("inet_set_opts(%p): s=%d, ACTIVE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(active) -> active (ival): %s (%d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + A2S(ival), ival) ); desc->active = ival; if (desc->active == INET_MULTI) { - long ac = desc->active_count; + long ac = desc->active_count; Sint16 nval = get_int16(ptr); ptr += 2; len -= 2; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(active) -> nval: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), nval) ); ac += nval; if (ac > INT16_MAX || ac < INT16_MIN) return -1; desc->active_count += nval; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(active) -> count => %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), + desc->active_count) ); if (desc->active_count < 0) desc->active_count = 0; if (desc->active_count == 0) { @@ -6529,24 +6882,35 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) continue; case INET_LOPT_PACKET: - DEBUGF(("inet_set_opts(%p): s=%d, PACKET=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(packet) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); desc->htype = ival; continue; case INET_LOPT_PACKET_SIZE: - DEBUGF(("inet_set_opts(%p): s=%d, PACKET_SIZE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(packet-size) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); desc->psize = (unsigned int)ival; continue; case INET_LOPT_EXITONCLOSE: - DEBUGF(("inet_set_opts(%p): s=%d, EXITONCLOSE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(exit-on-close) -> %d (%s)\r\n", + __LINE__, + desc->s, driver_caller(desc->port), ival, B2S(ival)) ); desc->exitf = ival; continue; case INET_LOPT_TCP_HIWTRMRK: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(hiwtrmrk) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; if (ival < 0) ival = 0; @@ -6557,6 +6921,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) continue; case INET_LOPT_TCP_LOWTRMRK: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(lowtrmrk) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; if (ival < 0) ival = 0; @@ -6568,6 +6936,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_LOPT_MSGQ_HIWTRMRK: { ErlDrvSizeT high; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(msgq-hiwtrmrk) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival) return -1; @@ -6578,6 +6950,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_LOPT_MSGQ_LOWTRMRK: { ErlDrvSizeT low; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(msgq-lowtrmrk) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival) return -1; @@ -6587,6 +6963,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } case INET_LOPT_TCP_SEND_TIMEOUT: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(send-timeout) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; tdesc->send_timeout = ival; @@ -6594,6 +6974,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) continue; case INET_LOPT_TCP_SEND_TIMEOUT_CLOSE: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(send-timeout-close) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; tdesc->send_timeout_close = ival; @@ -6602,6 +6986,11 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_LOPT_TCP_DELAY_SEND: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(delay-send) -> %d (%s)\r\n", + __LINE__, + desc->s, driver_caller(desc->port), ival, B2S(ival)) ); if (desc->stype == SOCK_STREAM) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; if (ival) @@ -6613,6 +7002,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #ifdef HAVE_UDP case INET_LOPT_UDP_READ_PACKETS: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(read-packets) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (desc->stype == SOCK_DGRAM) { udp_descriptor* udesc = (udp_descriptor*) desc; if (ival <= 0) return -1; @@ -6623,6 +7016,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #ifdef HAVE_SETNS case INET_LOPT_NETNS: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(netns) -> %d, %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival, len) ); /* It is annoying that ival and len are both (signed) int */ if (ival < 0) return -1; if (len < ival) return -1; @@ -6636,6 +7033,11 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #endif case INET_LOPT_TCP_SHOW_ECONNRESET: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(show-econnreset) -> %d (%s)\r\n", + __LINE__, + desc->s, driver_caller(desc->port), ival, B2S(ival)) ); if (desc->sprotocol == IPPROTO_TCP) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; if (ival) @@ -6646,43 +7048,132 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) continue; case INET_LOPT_LINE_DELIM: - DEBUGF(("inet_set_opts(%p): s=%d, LINE_DELIM=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(line-delimiter) -> %c (%d)\r\n", + __LINE__, + desc->s, driver_caller(desc->port), (char) ival, ival) ); desc->delimiter = (char)ival; continue; - case INET_OPT_REUSEADDR: + case INET_OPT_EXCLUSIVEADDRUSE: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(exclusiveaddruse) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); #ifdef __WIN32__ - continue; /* Bjorn says */ + type = SO_EXCLUSIVEADDRUSE; #else - type = SO_REUSEADDR; - DEBUGF(("inet_set_opts(%p): s=%d, SO_REUSEADDR=%d\r\n", - desc->port, desc->s,ival)); - break; + continue; +#endif + break; + + case INET_OPT_REUSEPORT_LB: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(reuseport_lb) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); +#if defined(__WIN32__) + continue; +#elif defined(__linux__) && defined(SO_REUSEPORT) + /* SO_REUSEPORT is load balancing on linux */ + type = SO_REUSEPORT; + break; +#elif defined(SO_REUSEPORT_LB) + type = SO_REUSEPORT_LB; + break; +#else + continue; +#endif + + case INET_OPT_REUSEPORT: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(reuseport) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); +#if defined(__WIN32__) + /* fall through to INET_OPT_REUSEADDR */ +#elif defined(SO_REUSEPORT) + type = SO_REUSEPORT; + break; +#else + continue; #endif + + case INET_OPT_REUSEADDR: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(reuseaddr) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); +#ifdef __WIN32__ + { + int old_ra, new_ra, compat, ra_bits, opt_bit; + /* + * We only set SO_REUSEADDR on Windows if both 'reuseaddr' and + * 'reuseport' has been passed as options, since SO_REUSEADDR + * on Windows behaves like SO_REUSEADDR|SO_REUSEPORT does on BSD. + */ + ra_bits = (1<bsd_compat; + old_ra = (compat & ra_bits) == ra_bits; + if (ival) { + bsd_compat_set = opt_bit; + compat |= opt_bit; + } + else { + bsd_compat_unset = opt_bit; + compat &= ~opt_bit; + } + new_ra = (compat & ra_bits) == ra_bits; + desc->bsd_compat = compat; + if (old_ra == new_ra) + continue; + } +#endif + type = SO_REUSEADDR; + break; + case INET_OPT_KEEPALIVE: type = SO_KEEPALIVE; - DEBUGF(("inet_set_opts(%p): s=%d, SO_KEEPALIVE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(keepalive) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); break; + case INET_OPT_DONTROUTE: type = SO_DONTROUTE; - DEBUGF(("inet_set_opts(%p): s=%d, SO_DONTROUTE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(dontroute) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); break; + case INET_OPT_BROADCAST: type = SO_BROADCAST; - DEBUGF(("inet_set_opts(%p): s=%d, SO_BROADCAST=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(broadcast) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); break; + case INET_OPT_OOBINLINE: type = SO_OOBINLINE; - DEBUGF(("inet_set_opts(%p): s=%d, SO_OOBINLINE=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(oobinline) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); break; - case INET_OPT_SNDBUF: type = SO_SNDBUF; - DEBUGF(("inet_set_opts(%p): s=%d, SO_SNDBUF=%d\r\n", - desc->port, desc->s, ival)); + + case INET_OPT_SNDBUF: type = SO_SNDBUF; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(sndbuf) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); break; + case INET_OPT_RCVBUF: type = SO_RCVBUF; - DEBUGF(("inet_set_opts(%p): s=%d, SO_RCVBUF=%d\r\n", - desc->port, desc->s, ival)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(rcvbuf) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (!(desc->flags & INET_FLG_BUFFER_SET)) { /* make sure we have desc->bufsz >= SO_RCVBUF */ if (ival > (1 << 16) && desc->stype == SOCK_DGRAM && !IS_SCTP(desc)) @@ -6694,6 +7185,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) desc->bufsz = ival; } break; + case INET_OPT_LINGER: type = SO_LINGER; if (len < 4) return -1; @@ -6703,9 +7195,14 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) len -= 4; arg_ptr = (char*) &li_val; arg_sz = sizeof(li_val); - DEBUGF(("inet_set_opts(%p): s=%d, SO_LINGER=%d,%d", - desc->port, desc->s, - li_val.l_onoff,li_val.l_linger)); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(linger) -> %d, %d\r\n", + __LINE__, + desc->s, driver_caller(desc->port), + li_val.l_onoff, li_val.l_linger) ); + if (desc->sprotocol == IPPROTO_TCP) { tcp_descriptor* tdesc = (tcp_descriptor*) desc; if (li_val.l_onoff && li_val.l_linger == 0) @@ -6717,49 +7214,72 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_OPT_PRIORITY: #ifdef SO_PRIORITY + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(prio) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); type = SO_PRIORITY; propagate = 1; /* We do want to know if this fails */ - DEBUGF(("inet_set_opts(%p): s=%d, SO_PRIORITY=%d\r\n", - desc->port, desc->s, ival)); break; #else /* inet_fill_opts always returns a value for this option, * so we need to ignore it if not implemented */ + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(prio) -> SKIP\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); continue; #endif + case INET_OPT_TOS: #if defined(IP_TOS) && defined(IPPROTO_IP) + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(tos) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IP; type = IP_TOS; propagate = 1; - DEBUGF(("inet_set_opts(%p): s=%d, IP_TOS=%d\r\n", - desc->port, desc->s, ival)); break; #else /* inet_fill_opts always returns a value for this option, * so we need to ignore it if not implemented. */ + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(tos) -> SKIP\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); continue; #endif + #if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6) case INET_OPT_TCLASS: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(tclass) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IPV6; type = IPV6_TCLASS; propagate = 1; - DEBUGF(("inet_set_opts(%p): s=%d, IPV6_TCLASS=%d\r\n", - desc->port, desc->s, ival)); break; #endif + #if defined(IP_TTL) && defined(IPPROTO_IP) case INET_OPT_TTL: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(ttl) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IP; type = IP_TTL; propagate = 1; - DEBUGF(("inet_set_opts(%p): s=%d, IP_TTL=%d\r\n", - desc->port, desc->s, ival)); break; #endif #if defined(IP_RECVTOS) && defined(IPPROTO_IP) case INET_OPT_RECVTOS: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(recvtos) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IP; type = IP_RECVTOS; propagate = 1; @@ -6767,12 +7287,14 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTOS) : (desc->recv_cmsgflags & ~INET_CMSG_RECVTOS); - DEBUGF(("inet_set_opts(%p): s=%d, IP_RECVTOS=%d\r\n", - desc->port, desc->s, ival)); break; #endif #if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6) case INET_OPT_RECVTCLASS: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(recvtclass) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IPV6; type = IPV6_RECVTCLASS; propagate = 1; @@ -6780,12 +7302,14 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTCLASS) : (desc->recv_cmsgflags & ~INET_CMSG_RECVTCLASS); - DEBUGF(("inet_set_opts(%p): s=%d, IPV6_RECVTCLASS=%d\r\n", - desc->port, desc->s, ival)); break; #endif #if defined(IP_RECVTTL) && defined(IPPROTO_IP) case INET_OPT_RECVTTL: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(recvttl) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IP; type = IP_RECVTTL; propagate = 1; @@ -6793,87 +7317,283 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTTL) : (desc->recv_cmsgflags & ~INET_CMSG_RECVTTL); - DEBUGF(("inet_set_opts(%p): s=%d, IP_RECVTTL=%d\r\n", - desc->port, desc->s, ival)); break; #endif case TCP_OPT_NODELAY: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(nodelay) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); proto = IPPROTO_TCP; type = TCP_NODELAY; - DEBUGF(("inet_set_opts(%p): s=%d, TCP_NODELAY=%d\r\n", - desc->port, desc->s, ival)); break; case TCP_OPT_NOPUSH: #if defined(INET_TCP_NOPUSH) + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(nopush) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_TCP; type = INET_TCP_NOPUSH; - DEBUGF(("inet_set_opts(%p): s=%d, t=%d TCP_NOPUSH=%d\r\n", - desc->port, desc->s, type, ival)); break; #else /* inet_fill_opts always returns a value for this option, * so we need to ignore it if not implemented, just in case */ + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(nopush) -> SKIP\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); continue; #endif #if defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP) case UDP_OPT_MULTICAST_TTL: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(multicast-ttl) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); proto = IPPROTO_IP; type = IP_MULTICAST_TTL; - DEBUGF(("inet_set_opts(%p): s=%d, IP_MULTICAST_TTL=%d\r\n", - desc->port, desc->s,ival)); break; case UDP_OPT_MULTICAST_LOOP: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(multicast-loop) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); proto = IPPROTO_IP; type = IP_MULTICAST_LOOP; - DEBUGF(("inet_set_opts(%p): s=%d, IP_MULTICAST_LOOP=%d\r\n", - desc->port, desc->s,ival)); break; case UDP_OPT_MULTICAST_IF: - proto = IPPROTO_IP; - type = IP_MULTICAST_IF; - DEBUGF(("inet_set_opts(%p): s=%d, IP_MULTICAST_IF=%x\r\n", - desc->port, desc->s, ival)); - ival = sock_htonl(ival); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(multicast-if) -> %d (%d)\r\n", + __LINE__, + desc->s, driver_caller(desc->port), ival, sock_htonl(ival)) ); + if (desc->sfamily == AF_INET) { + proto = IPPROTO_IP; + type = IP_MULTICAST_IF; + DEBUGF(("inet_set_opts(%p): s=%d, IP_MULTICAST_IF = %x\r\n", + desc->port, desc->s, ival)); + ival = sock_htonl(ival); + } +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(IPPROTO_IPV6) + else if (desc->sfamily == AF_INET6) { + proto = IPPROTO_IPV6; + type = IPV6_MULTICAST_IF; + DEBUGF(("inet_set_opts(%p): s=%d, IPV6_MULTICAST_IF = %x\r\n", + desc->port, desc->s, ival)); + ival = sock_htonl(ival); + } else { + return -1; + } +#else + else { + return -1; + } +#endif break; case UDP_OPT_ADD_MEMBERSHIP: - proto = IPPROTO_IP; - type = IP_ADD_MEMBERSHIP; - DEBUGF(("inet_set_opts(%p): s=%d, IP_ADD_MEMBERSHIP=%d\r\n", - desc->port, desc->s,ival)); - goto L_set_mreq; - + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(add-membership) -> domain: %d (%s)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + ival, DOM2S(ival)) ); + if (ival == INET_AF_INET) { + proto = IPPROTO_IP; + type = IP_ADD_MEMBERSHIP; + } +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(IPPROTO_IPV6) + else if (ival == INET_AF_INET6) { + proto = IPPROTO_IPV6; +#if defined(INET_ADD_MEMBERSHIP) + type = INET_DROP_MEMBERSHIP; +#else + return -1; +#endif + } +#endif + else { + return -1; + } + goto L_init_mreq; + case UDP_OPT_DROP_MEMBERSHIP: - proto = IPPROTO_IP; - type = IP_DROP_MEMBERSHIP; - DEBUGF(("inet_set_opts(%p): s=%d, " - "IP_DROP_MEMBERSHIP=%x\r\n", - desc->port, desc->s, ival)); - L_set_mreq: - mreq_val.imr_multiaddr.s_addr = sock_htonl(ival); - ival = get_int32(ptr); - mreq_val.imr_interface.s_addr = sock_htonl(ival); - ptr += 4; - len -= 4; - arg_ptr = (char*)&mreq_val; - arg_sz = sizeof(mreq_val); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(drop-membership) -> %d (%s)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + ival, DOM2S(ival)) ); + if (ival == INET_AF_INET) { + proto = IPPROTO_IP; + type = IP_DROP_MEMBERSHIP; + } +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(IPPROTO_IPV6) + else if (ival == INET_AF_INET6) { + proto = IPPROTO_IPV6; +#if defined(INET_DROP_MEMBERSHIP) + type = INET_DROP_MEMBERSHIP; +#else + return -1; +#endif + } +#endif + else { + return -1; + } + + L_init_mreq: + { + int domain = ival; + + ival = get_int32(ptr); // Interface | Ifindex + ptr += 4; + len -= 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq) -> " + "\r\n proto: %d" + "\r\n type: %d" + "\r\n domain: %d (%s)" + "\r\n if: %d" + "\r\n", + __LINE__, desc->s, driver_caller(desc->port), + proto, type, domain, DOM2S(domain), ival)); + + if ((domain == INET_AF_INET) && (desc->sfamily == AF_INET)) { + + mreqSz = sizeof(mreq4); + + /* 0) Read out the ifindex (see above) + * 1) Read out the multiaddr + * 2) Read out the local address + */ + +#if defined(HAVE_STRUCT_IP_MREQN) + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq,inet) -> mreqn\r\n", + __LINE__, desc->s, driver_caller(desc->port))); + + mreq4.imr_ifindex = sock_htonl(ival); + ival = get_int32(ptr); + ptr += 4; + len -= 4; + mreq4.imr_multiaddr.s_addr = sock_htonl(ival); + ival = get_int32(ptr); + ptr += 4; + len -= 4; + mreq4.imr_address.s_addr = sock_htonl(ival); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq,inet) -> " + "try setopt: " + "\r\n maddr: %x" + "\r\n addr: %x" + "\r\n if: %d" + "\r\n sz: %d" + "\r\n", + __LINE__, desc->s, driver_caller(desc->port), + mreq4.imr_multiaddr.s_addr, + mreq4.imr_address.s_addr, + mreq4.imr_ifindex, + mreqSz)); + +#else + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq,inet) -> mreq\r\n", + __LINE__, desc->s, driver_caller(desc->port))); + + ival = get_int32(ptr); + ptr += 4; + len -= 4; + mreq4.imr_multiaddr.s_addr = sock_htonl(ival); + ival = get_int32(ptr); + ptr += 4; + len -= 4; + mreq4.imr_interface.s_addr = sock_htonl(ival); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq,inet) -> " + "try setopt: " + "\r\n maddr: %x" + "\r\n if: %x" + "\r\n sz: %d" + "\r\n", + __LINE__, desc->s, driver_caller(desc->port), + mreq4.imr_multiaddr.s_addr, + mreq4.imr_interface.s_addr, + mreqSz)); + +#endif + + arg_ptr = (char*)&mreq4; + arg_sz = mreqSz; + + } +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(IPPROTO_IPV6) + else if ((domain == INET_AF_INET6) && + (desc->sfamily == AF_INET6)) { + + mreqSz = sizeof(mreq6); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq,inet6) -> mreq\r\n", + __LINE__, desc->s, driver_caller(desc->port))); + + /* 0) Read out the ifindex + * 1) Read out the multiaddr + */ + + sys_memcpy(&mreq6.ipv6mr_multiaddr, ptr, 16); + ptr += 16; + len -= len; + mreq6.ipv6mr_interface = ival; + + arg_ptr = (char*)&mreq6; + arg_sz = mreqSz; + + } +#endif + else { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(L_init_mreq) -> " + "invalid domain: " + "\r\n domain: %d (%d, %d)" + "\r\n sfmaily: %d (%d, %d)" + "\r\n", + __LINE__, desc->s, driver_caller(desc->port), + domain, INET_AF_INET, INET_AF_INET6, + desc->sfamily, AF_INET, AF_INET6)); + return -1; + } + } break; #endif /* defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP) */ case INET_OPT_IPV6_V6ONLY: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(ipv6-v6only) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); #if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6) proto = IPPROTO_IPV6; type = IPV6_V6ONLY; propagate = 1; - DEBUGF(("inet_set_opts(%p): s=%d, IPV6_V6ONLY=%d\r\n", - desc->port, desc->s, ival)); break; #elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6) /* Fake a'la OpenBSD; set to 'true' is fine but 'false' invalid. */ @@ -6885,6 +7605,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #endif case INET_OPT_RAW: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(raw) -> %d, %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival, len) ); if (len < 8) { return -1; } @@ -6904,6 +7628,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #ifdef SO_BINDTODEVICE case INET_OPT_BIND_TO_DEVICE: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(bindtodevice) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); if (ival < 0) return -1; if (len < ival) return -1; if (ival > sizeof(ifname)) { @@ -6919,27 +7647,50 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) arg_ptr = (char*)&ifname; arg_sz = sizeof(ifname); propagate = 1; /* We do want to know if this fails */ - - DEBUGF(("inet_set_opts(%p): s=%d, SO_BINDTODEVICE=%s\r\n", - desc->port, desc->s, ifname)); break; #endif - default: + case INET_LOPT_DEBUG: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts(debug) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + if (ival) { + desc->debug = TRUE; + } else { + desc->debug = FALSE; + } + continue; /* take care of next option */ + + default: return -1; } -#if defined(IP_TOS) && defined(IPPROTO_IP) \ - && defined(SO_PRIORITY) && !defined(__WIN32__) - res = setopt_prio_tos_trick (desc->s, proto, type, arg_ptr, arg_sz, propagate); -#else - res = sock_setopt (desc->s, proto, type, arg_ptr, arg_sz); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts -> try set opt (%d) %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), proto, type) ); + + res = inet_setopt(desc->s, proto, type, arg_ptr, arg_sz, propagate); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_set_opts -> set opt result: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), res) ); + + if (res == 0) { + desc->recv_cmsgflags = recv_cmsgflags; + } + else { +#ifdef __WIN32__ + if (bsd_compat_set) + desc->bsd_compat &= ~bsd_compat_set; + if (bsd_compat_unset) + desc->bsd_compat |= bsd_compat_unset; #endif - if (res == 0) desc->recv_cmsgflags = recv_cmsgflags; - if (propagate && res != 0) { - return -1; + if (propagate) + return -1; } - DEBUGF(("inet_set_opts(%p): s=%d returned %d\r\n", - desc->port, desc->s, res)); } if ( ((desc->stype == SOCK_STREAM) && IS_CONNECTED(desc)) || @@ -6958,7 +7709,8 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } if (desc->active != old_active) { - /* Need to cancel the read_packet timer if we go from active to passive. */ + /* Need to cancel the read_packet timer * + * if we go from active to passive. */ if (desc->active == INET_PASSIVE && desc->stype == SOCK_DGRAM) driver_cancel_timer(desc->port); @@ -6995,7 +7747,7 @@ static char* sctp_get_initmsg(struct sctp_initmsg* ini, char* curr) } /* "sctp_get_sendparams": -** Parses (from the command buffer) the 6 user-sprcified parms of +** Parses (from the command buffer) the 6 user-specified params of ** "sctp_sndrcvinfo": ** stream(u16), flags(u16), ppid(u32), context(u32), ** timetoleave(u32), assoc_id @@ -7081,10 +7833,19 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) int recv_cmsgflags; /* Get the Erlang-encoded option type -- always 1 byte: */ int eopt; +#ifdef __WIN32__ + int bsd_compat_set = 0; + int bsd_compat_unset = 0; +#endif eopt = *curr; curr++; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> eopt: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), eopt) ); + recv_cmsgflags = desc->recv_cmsgflags; /* Get the option value. XXX: The condition (curr < ptr + len) does not preclude us from reading from beyond the buffer end, @@ -7096,43 +7857,82 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) /* Local INET options: */ case INET_LOPT_BUFFER: - desc->bufsz = get_int32(curr); curr += 4; + { + int ival = get_int32(curr); curr += 4; - if (desc->bufsz < INET_MIN_BUFFER) - desc->bufsz = INET_MIN_BUFFER; - desc->flags |= INET_FLG_BUFFER_SET; - res = 0; /* This does not affect the kernel buffer size */ - continue; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(buffer) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + desc->bufsz = ival; + + if (desc->bufsz < INET_MIN_BUFFER) + desc->bufsz = INET_MIN_BUFFER; + desc->flags |= INET_FLG_BUFFER_SET; + res = 0; /* This does not affect the kernel buffer size */ + } + continue; case INET_LOPT_MODE: - desc->mode = get_int32(curr); curr += 4; - res = 0; + { + int ival = get_int32(curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(mode) -> %s (%d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + M2S(ival), ival) ); + + desc->mode = ival; + res = 0; + } continue; case INET_LOPT_ACTIVE: - desc->active = get_int32(curr); curr += 4; - if (desc->active == INET_MULTI) { - long ac = desc->active_count; - Sint16 nval = get_int16(curr); curr += 2; - ac += nval; - if (ac > INT16_MAX || ac < INT16_MIN) - return -1; - desc->active_count += nval; - if (desc->active_count < 0) + { + int ival = get_int32(curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(active) -> %s (%d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), + A2S(ival), ival) ); + + desc->active = ival; + if (desc->active == INET_MULTI) { + long ac = desc->active_count; + Sint16 nval = get_int16(curr); curr += 2; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(active) -> nval: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), nval) ); + ac += nval; + if (ac > INT16_MAX || ac < INT16_MIN) + return -1; + desc->active_count += nval; + if (desc->active_count < 0) + desc->active_count = 0; + if (desc->active_count == 0) { + desc->active = INET_PASSIVE; + packet_passive_message(desc); + } + } else desc->active_count = 0; - if (desc->active_count == 0) { - desc->active = INET_PASSIVE; - packet_passive_message(desc); - } - } else - desc->active_count = 0; - res = 0; + res = 0; + } continue; #ifdef HAVE_SETNS case INET_LOPT_NETNS: { size_t ns_len; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> NETNS\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + ns_len = get_int32(curr); curr += 4; CHKLEN(curr, ns_len); if (desc->netns != NULL) FREE(desc->netns); @@ -7148,6 +7948,11 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case SCTP_OPT_RTOINFO: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> RTOINFO\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, ASSOC_ID_LEN + 3*4); arg.rtoi.srto_assoc_id = GET_ASSOC_ID(curr); curr += ASSOC_ID_LEN; arg.rtoi.srto_initial = get_int32 (curr); curr += 4; @@ -7160,8 +7965,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.rtoi); break; } + case SCTP_OPT_ASSOCINFO: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> ASSOCINFO\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, ASSOC_ID_LEN + 2*2 + 3*4); arg.ap.sasoc_assoc_id = GET_ASSOC_ID(curr); curr += ASSOC_ID_LEN; @@ -7178,8 +7989,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.ap); break; } + case SCTP_OPT_INITMSG: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> INITMSG\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, SCTP_GET_INITMSG_LEN); curr = sctp_get_initmsg (&arg.im, curr); @@ -7189,8 +8006,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.im); break; } + case INET_OPT_LINGER: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> LINGER\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, 2*4); arg.lin.l_onoff = get_int32 (curr); curr += 4; arg.lin.l_linger = get_int32 (curr); curr += 4; @@ -7201,8 +8024,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.lin); break; } + case SCTP_OPT_NODELAY: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> NODELAY\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + arg.ival= get_int32 (curr); curr += 4; proto = IPPROTO_SCTP; type = SCTP_NODELAY; @@ -7210,9 +8039,17 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.ival); break; } + case INET_OPT_RCVBUF: { - arg.ival= get_int32 (curr); curr += 4; + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(rcvbuf) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival= ival; proto = SOL_SOCKET; type = SO_RCVBUF; arg_ptr = (char*) (&arg.ival); @@ -7225,9 +8062,17 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) desc->flags |= INET_FLG_BUFFER_SET; break; } + case INET_OPT_SNDBUF: { - arg.ival= get_int32 (curr); curr += 4; + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(sndbuf) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival= ival; proto = SOL_SOCKET; type = SO_SNDBUF; arg_ptr = (char*) (&arg.ival); @@ -7235,34 +8080,140 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) break; } - case INET_OPT_REUSEADDR: + + case INET_OPT_EXCLUSIVEADDRUSE: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> EXCLUSIVEADDRUSE\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); +#ifdef __WIN32__ + arg.ival= get_int32 (curr); curr += 4; + proto = SOL_SOCKET; + type = SO_EXCLUSIVEADDRUSE; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); + break; +#else + continue; +#endif + + case INET_OPT_REUSEPORT_LB: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> REUSEPORT_LB\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); +#if defined(__WIN32__) + continue; +#elif defined(SO_REUSEPORT_LB) || (defined(__linux__) && defined(SO_REUSEPORT)) arg.ival= get_int32 (curr); curr += 4; proto = SOL_SOCKET; - type = SO_REUSEADDR; +#if defined(__linux__) + /* SO_REUSEPORT is load balancing on linux */ + type = SO_REUSEPORT; +#else + type = SO_REUSEPORT_LB; +#endif arg_ptr = (char*) (&arg.ival); arg_sz = sizeof ( arg.ival); break; +#else + continue; +#endif } - case INET_OPT_DONTROUTE: + + case INET_OPT_REUSEPORT: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> REUSEPORT\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); +#if defined(__WIN32__) + /* fall through to INET_OPT_REUSEADDR */ +#elif defined(SO_REUSEPORT) arg.ival= get_int32 (curr); curr += 4; proto = SOL_SOCKET; - type = SO_DONTROUTE; + type = SO_REUSEPORT; arg_ptr = (char*) (&arg.ival); arg_sz = sizeof ( arg.ival); break; +#else + continue; +#endif } - case INET_OPT_PRIORITY: -# ifdef SO_PRIORITY + case INET_OPT_REUSEADDR: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> REUSEADDR\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); +#ifdef __WIN32__ + { + int old_ra, new_ra, compat, ra_bits, opt_bit; + /* + * We only set SO_REUSEADDR on Windows if both 'reuseaddr' and + * 'reuseport' has been passed as options, since SO_REUSEADDR + * on Windows behaves like SO_REUSEADDR|SO_REUSEPORT does on BSD. + */ + ra_bits = (1<bsd_compat; + old_ra = (compat & ra_bits) == ra_bits; + if (ival) { + bsd_compat_set = opt_bit; + compat |= opt_bit; + } + else { + bsd_compat_unset = opt_bit; + compat &= ~opt_bit; + } + new_ra = (compat & ra_bits) == ra_bits; + desc->bsd_compat = compat; + if (old_ra == new_ra) + continue; + } +#endif arg.ival= get_int32 (curr); curr += 4; proto = SOL_SOCKET; - type = SO_PRIORITY; + type = SO_REUSEADDR; arg_ptr = (char*) (&arg.ival); arg_sz = sizeof ( arg.ival); break; } + case INET_OPT_DONTROUTE: + { + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(dontroute) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = SOL_SOCKET; + type = SO_DONTROUTE; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); + break; + } + + case INET_OPT_PRIORITY: +# ifdef SO_PRIORITY + { + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(prio) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = SOL_SOCKET; + type = SO_PRIORITY; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); + break; + } # else /* inet_fill_opts always returns a value for this option, * so we need to ignore it if not implemented, just in case */ @@ -7272,11 +8223,17 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_OPT_TOS: # if defined(IP_TOS) && defined(IPPROTO_IP) { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IP; - type = IP_TOS; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(tos) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = IPPROTO_IP; + type = IP_TOS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } # else @@ -7288,11 +8245,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6) case INET_OPT_TCLASS: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IPV6; - type = IPV6_TCLASS; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(tclass) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = IPPROTO_IPV6; + type = IPV6_TCLASS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } # endif @@ -7300,11 +8264,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # if defined(IP_TTL) && defined(IPPROTO_IP) case INET_OPT_TTL: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IP; - type = IP_TTL; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(ttl) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = IPPROTO_IP; + type = IP_TTL; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } # endif @@ -7312,11 +8283,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # if defined(IP_RECVTOS) && defined(IPPROTO_IP) case INET_OPT_RECVTOS: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IP; - type = IP_RECVTOS; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(recvtos) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_IP; + type = IP_RECVTOS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); recv_cmsgflags = arg.ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTOS) : @@ -7328,11 +8306,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6) case INET_OPT_RECVTCLASS: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IPV6; - type = IPV6_RECVTCLASS; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(recvtclass) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_IPV6; + type = IPV6_RECVTCLASS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); recv_cmsgflags = arg.ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTCLASS) : @@ -7344,11 +8329,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # if defined(IP_RECVTTL) && defined(IPPROTO_IP) case INET_OPT_RECVTTL: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IP; - type = IP_RECVTTL; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(recvttl) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_IP; + type = IP_RECVTTL; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); recv_cmsgflags = arg.ival ? (desc->recv_cmsgflags | INET_CMSG_RECVTTL) : @@ -7361,11 +8353,18 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_OPT_IPV6_V6ONLY: # if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6) { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_IPV6; - type = IPV6_V6ONLY; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(ipv6_v6only) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_IPV6; + type = IPV6_V6ONLY; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } # elif defined(__WIN32__) && defined(HAVE_IN6) && defined(AF_INET6) @@ -7376,6 +8375,11 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) #ifdef SO_BINDTODEVICE case INET_OPT_BIND_TO_DEVICE: + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> BIND_TO_DEVICE\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + arg_sz = get_int32(curr); curr += 4; CHKLEN(curr, arg_sz); if (arg_sz >= sizeof(arg.ifname)) @@ -7393,45 +8397,82 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case SCTP_OPT_AUTOCLOSE: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_SCTP; - type = SCTP_AUTOCLOSE; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(autoclose) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = IPPROTO_SCTP; + type = SCTP_AUTOCLOSE; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } + case SCTP_OPT_DISABLE_FRAGMENTS: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_SCTP; - type = SCTP_DISABLE_FRAGMENTS; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(disable_fragments) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_SCTP; + type = SCTP_DISABLE_FRAGMENTS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } + case SCTP_OPT_I_WANT_MAPPED_V4_ADDR: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_SCTP; - type = SCTP_I_WANT_MAPPED_V4_ADDR; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(i_want_mapped_v4_addr) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(ival)) ); + + arg.ival = ival; + proto = IPPROTO_SCTP; + type = SCTP_I_WANT_MAPPED_V4_ADDR; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } + case SCTP_OPT_MAXSEG: { - arg.ival= get_int32 (curr); curr += 4; - proto = IPPROTO_SCTP; - type = SCTP_MAXSEG; - arg_ptr = (char*) (&arg.ival); - arg_sz = sizeof ( arg.ival); + int ival = get_int32 (curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(maxseg) -> %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), ival) ); + + arg.ival = ival; + proto = IPPROTO_SCTP; + type = SCTP_MAXSEG; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); break; } + case SCTP_OPT_PRIMARY_ADDR: case SCTP_OPT_SET_PEER_PRIMARY_ADDR: { ErlDrvSizeT alen; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> PRIMARY_ADDR | SET_PEER_PRIMARY_ADDR\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, ASSOC_ID_LEN); /* XXX: These 2 opts have isomorphic value data structures, "sctp_setpeerprim" and "sctp_prim" (in Solaris 10, the latter @@ -7455,8 +8496,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.prim); break; } + case SCTP_OPT_ADAPTATION_LAYER: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> ADAPTATION_LAYER\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + /* XXX: do we need to convert the Ind into network byte order??? */ arg.ad.ssb_adaptation_ind = sock_htonl (get_int32(curr)); curr += 4; @@ -7466,6 +8513,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.ad); break; } + case SCTP_OPT_PEER_ADDR_PARAMS: { ErlDrvSizeT alen; @@ -7478,6 +8526,11 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) # endif # endif + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> PEER_ADDR_PARAMS\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, ASSOC_ID_LEN); arg.pap.spp_assoc_id = GET_ASSOC_ID(curr); curr += ASSOC_ID_LEN; @@ -7523,7 +8576,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) if (pmtud_disable) cflags |= SPP_PMTUD_DISABLE; # ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_SACKDELAY - /* The followings are missing in FreeBSD 7.1 */ + /* The following are missing in FreeBSD 7.1 */ sackdelay_enable =eflags& SCTP_FLAG_SACDELAY_ENABLE; sackdelay_disable=eflags& SCTP_FLAG_SACDELAY_DISABLE; if (sackdelay_enable && sackdelay_disable) @@ -7542,8 +8595,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.pap); break; } + case SCTP_OPT_DEFAULT_SEND_PARAM: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> DEFAULT_SEND_PARAM\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, SCTP_GET_SENDPARAMS_LEN); curr = sctp_get_sendparams (&arg.sri, curr); @@ -7554,8 +8613,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) VALGRIND_MAKE_MEM_DEFINED(arg_ptr, arg_sz); /*suppress "uninitialised bytes"*/ break; } + case SCTP_OPT_EVENTS: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> EVENTS\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, 9); /* We do not support "sctp_authentication_event" -- it is not implemented in Linux Kernel SCTP anyway. Just in case if @@ -7589,6 +8654,11 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) #if defined(HAVE_DECL_SCTP_DELAYED_ACK_TIME) && defined(SCTP_ASSOC_VALUE_ASSOC_ID) case SCTP_OPT_DELAYED_ACK_TIME: { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts -> DELAYED_ACK_TIME\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + CHKLEN(curr, ASSOC_ID_LEN + 4); arg.av.assoc_id = GET_ASSOC_ID(curr); curr += ASSOC_ID_LEN; arg.av.assoc_value = get_int32(curr); curr += 4; @@ -7600,6 +8670,26 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) break; } #endif + + case INET_LOPT_DEBUG: + { + int ival = get_int32(curr); curr += 4; + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "sctp_set_opts(debug) -> %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), + B2S(ival)) ); + if (ival) { + desc->debug = TRUE; + } else { + desc->debug = FALSE; + } + + res = 0; + } + continue; /* take care of next option */ + default: /* XXX: No more supported SCTP options. In particular, authentica- tion options (SCTP_AUTH_CHUNK, SCTP_AUTH_KEY, SCTP_PEER_AUTH_ @@ -7610,15 +8700,22 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) */ return -1; } -#if defined(IP_TOS) && defined(IPPROTO_IP) \ - && defined(SO_PRIORITY) && !defined(__WIN32__) - res = setopt_prio_tos_trick (desc->s, proto, type, arg_ptr, arg_sz, 1); -#else - res = sock_setopt (desc->s, proto, type, arg_ptr, arg_sz); -#endif + + res = inet_setopt(desc->s, proto, type, arg_ptr, arg_sz, 1); + /* The return values of "sock_setopt" can only be 0 or -1: */ ASSERT(res == 0 || res == -1); - if (res == 0) desc->recv_cmsgflags = recv_cmsgflags; + if (res == 0) { + desc->recv_cmsgflags = recv_cmsgflags; + } +#ifdef __WIN32__ + else { + if (bsd_compat_set) + desc->bsd_compat &= ~bsd_compat_set; + if (bsd_compat_unset) + desc->bsd_compat |= bsd_compat_unset; + } +#endif if (res == -1) { /* Got an error, DO NOT continue with other options. However, on Solaris 10, we DO allow SO_SNDBUF and SO_RCVBUF to fail, assu- @@ -7733,7 +8830,13 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, dest_used = new_need; \ } while(0) - + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_fill_opts -> entry\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + + PLACE_FOR(1,ptr); *ptr = INET_REP_OK; @@ -7746,6 +8849,11 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, PLACE_FOR(5,ptr); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_fill_opts -> opt %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), opt) ); + switch(opt) { case INET_LOPT_BUFFER: *ptr++ = opt; @@ -7956,9 +9064,55 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, TRUNCATE_TO(0,ptr); continue; #endif - case INET_OPT_REUSEADDR: - type = SO_REUSEADDR; + case INET_OPT_REUSEADDR: { +#if defined(__WIN32__) + int res = !!(desc->bsd_compat & (1<bsd_compat & (1<sfamily == AF_INET) { + put_int32(INET_AF_INET, ptr); + ptr += 4; + proto = IPPROTO_IP; + type = IP_MULTICAST_IF; + } else if (desc->sfamily == AF_INET6) { + put_int32(INET_AF_INET6, ptr); + ptr += 4; + proto = IPPROTO_IPV6; + type = IPV6_MULTICAST_IF; + } else { + RETURN_ERROR(); + } + if (IS_SOCKET_ERROR(sock_getopt(desc->s, + proto, type, + (void *) &mif, + (void *) &mifSz))) { + TRUNCATE_TO(0,ptr); + continue; + } + put_int32(mif, ptr); + } + continue; + case INET_OPT_LINGER: arg_sz = sizeof(li_val); sys_memzero((void *) &li_val, sizeof(li_val)); @@ -8179,14 +9364,36 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, } #endif /* #ifdef __WIN32__ */ + case INET_LOPT_DEBUG: + *ptr++ = opt; + ival = desc->debug; + put_int32(ival, ptr); + continue; + default: RETURN_ERROR(); } + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_fill_opts -> try get opt (proto %d, type %d)\r\n", + __LINE__, desc->s, driver_caller(desc->port), proto, type) ); + /* We have 5 bytes allocated to ptr */ if (IS_SOCKET_ERROR(sock_getopt(desc->s,proto,type,arg_ptr,&arg_sz))) { + int save_errno = sock_errno(); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_fill_opts -> failed get option (%d) %d: " + "\r\n errno: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), + proto, type, save_errno) ); + TRUNCATE_TO(0,ptr); continue; } + *ptr++ = opt; if (arg_ptr == (char*)&ival) { put_int32(ival, ptr); @@ -8264,7 +9471,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, return (Errno); \ } while(0) - /* Spec is a name parmeter */ + /* Spec is a name parameter */ # define PLACE_FOR(Spec, Index, N) \ do { \ int need; \ @@ -8485,7 +9692,6 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, /* The following options just return an integer value: */ case INET_OPT_RCVBUF : case INET_OPT_SNDBUF : - case INET_OPT_REUSEADDR: case INET_OPT_DONTROUTE: case INET_OPT_PRIORITY : case INET_OPT_TOS : @@ -8495,6 +9701,10 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, case SCTP_OPT_AUTOCLOSE: case SCTP_OPT_MAXSEG : /* The following options return true or false: */ + case INET_OPT_REUSEADDR: + case INET_OPT_REUSEPORT: + case INET_OPT_REUSEPORT_LB: + case INET_OPT_EXCLUSIVEADDRUSE: case SCTP_OPT_NODELAY : case SCTP_OPT_DISABLE_FRAGMENTS: case SCTP_OPT_I_WANT_MAPPED_V4_ADDR: @@ -8525,13 +9735,66 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, tag = am_sndbuf; break; } + case INET_OPT_EXCLUSIVEADDRUSE: + { +#if defined(__WIN32__) + proto = SOL_SOCKET; + type = SO_EXCLUSIVEADDRUSE; + is_int = 0; + tag = am_exclusiveaddruse; + break; +#else + continue; +#endif + } + case INET_OPT_REUSEPORT_LB: + { +#if defined(SO_REUSEPORT_LB) || (defined(__linux__) && defined(SO_REUSEPORT)) + proto = SOL_SOCKET; +#if defined(__linux__) + /* SO_REUSEPORT is load balancing on linux */ + type = SO_REUSEPORT; +#else + type = SO_REUSEPORT_LB; +#endif + is_int = 0; + tag = am_reuseport_lb; + break; +#else + continue; +#endif + } + case INET_OPT_REUSEPORT: + { +#if defined(__WIN32__) + res = !!(desc->bsd_compat & (1<bsd_compat & (1<s, proto, type, &res, &sz) < 0) continue; /* Form the result: */ +#ifdef __WIN32__ +form_result: +#endif PLACE_FOR(spec, i, LOAD_ATOM_CNT + (is_int ? LOAD_INT_CNT : LOAD_BOOL_CNT) + LOAD_TUPLE_CNT); @@ -8802,7 +10068,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, i = LOAD_INT (spec, i, ap.spp_hbinterval); i = LOAD_INT (spec, i, ap.spp_pathmaxrxt); - /* The following fields are not suported in SOLARIS10, + /* The following fields are not supported in SOLARIS10, ** so put 0s for "spp_pathmtu", "spp_sackdelay", ** and empty list for "spp_flags": */ @@ -9199,6 +10465,11 @@ static ErlDrvSSizeT inet_subscribe(inet_descriptor* desc, /* Terminate socket */ static void inet_stop(inet_descriptor* desc) { + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR "] " + "inet_stop -> entry\r\n", + __LINE__, desc->s) ); + erl_inet_close(desc); #ifdef HAVE_SETNS if (desc->netns != NULL) @@ -9273,6 +10544,9 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->opt = NULL; desc->op_ref = 0; + desc->caller = am_undefined; + desc->caller_ref = no_caller_ref(); + desc->peer_ptr = NULL; desc->name_ptr = NULL; @@ -9306,6 +10580,8 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->recv_cmsgflags = 0; + desc->debug = DDBG_DEFAULT; + return (ErlDrvData)desc; } @@ -9327,6 +10603,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, ErlDrvSizeT i; int dstlen = 1; /* Reply code */ + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_ctl -> GETSTAT\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + for (i = 0; i < len; i++) { switch(buf[i]) { case INET_STAT_SEND_OCT: dstlen += 9; break; @@ -9334,7 +10615,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, default: dstlen += 5; break; } } - DEBUGF(("inet_ctl(%p): GETSTAT\r\n", (long) desc->port)); + if (dstlen > INET_MAX_OPT_BUFFER) /* sanity check */ return 0; if (dstlen > rsize) { @@ -9350,8 +10631,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_SUBSCRIBE: { char* dst; int dstlen = 1 /* Reply code */ + len*5; - DEBUGF(("inet_ctl(%p): INET_REQ_SUBSCRIBE\r\n", - desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_ctl -> SUBSCRIBE\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + if (dstlen > INET_MAX_OPT_BUFFER) /* sanity check */ return 0; if (dstlen > rsize) { @@ -9366,7 +10651,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_GETOPTS: { /* get options */ ErlDrvSSizeT replen; - DEBUGF(("inet_ctl(%p): GETOPTS\r\n", desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "inet_ctl -> GETOPTS\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + #ifdef HAVE_SCTP if (IS_SCTP(desc)) { @@ -9374,44 +10664,73 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_error(-replen, rbuf, rsize); } else #endif - if ((replen = inet_fill_opts(desc, buf, len, rbuf, rsize)) < 0) { - return ctl_error(EINVAL, rbuf, rsize); - } + if ((replen = inet_fill_opts(desc, buf, len, rbuf, rsize)) < 0) { + return ctl_error(EINVAL, rbuf, rsize); + } return replen; } case INET_REQ_GETIFLIST: { - DEBUGF(("inet_ctl(%p): GETIFLIST\r\n", desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETIFLIST\r\n", + __LINE__, driver_caller(desc->port)) ); + if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); return inet_ctl_getiflist(desc, rbuf, rsize); } case INET_REQ_GETIFADDRS: { - DEBUGF(("inet_ctl(%p): GETIFADDRS\r\n", desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETIFADDRS\r\n", + __LINE__, driver_caller(desc->port)) ); + if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); return inet_ctl_getifaddrs(desc, rbuf, rsize); } case INET_REQ_IFGET: { - DEBUGF(("inet_ctl(%p): IFGET\r\n", desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> IFGET\r\n", + __LINE__, driver_caller(desc->port)) ); + if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); return inet_ctl_ifget(desc, buf, len, rbuf, rsize); } case INET_REQ_IFSET: { - DEBUGF(("inet_ctl(%p): IFSET\r\n", desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> IFSET\r\n", + __LINE__, driver_caller(desc->port)) ); + if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); return inet_ctl_ifset(desc, buf, len, rbuf, rsize); } case INET_REQ_SETOPTS: { /* set options */ - DEBUGF(("inet_ctl(%p): SETOPTS\r\n", desc->port)); - /* XXX fprintf(stderr,"inet_ctl(%p): SETOPTS (len = %d)\r\n", desc->port,(int) len); */ - switch(inet_set_opts(desc, buf, len)) { + int sres; + + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl -> SETOPTS\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + + sres = inet_set_opts(desc, buf, len); + + /* We cannot debug-print if sres == 0 since we have then actually * + * completed a driver_exit => we have no longer a descriptor! */ + if (sres != 0) + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl(setopts) -> sres: %d\r\n", + __LINE__, desc->s, driver_caller(desc->port), sres) ); + + switch(sres) { case -1: return ctl_error(EINVAL, rbuf, rsize); case 0: @@ -9436,18 +10755,26 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } } + case INET_REQ_GETSTATUS: { char tbuf[4]; - DEBUGF(("inet_ctl(%p): GETSTATUS\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETSTATUS\r\n", + __LINE__, driver_caller(desc->port)) ); + put_int32(desc->state, tbuf); return ctl_reply(INET_REP_OK, tbuf, 4, rbuf, rsize); } + case INET_REQ_GETTYPE: { char tbuf[8]; - DEBUGF(("inet_ctl(%p): GETTYPE\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETTYPE\r\n", + __LINE__, driver_caller(desc->port)) ); + if (desc->sfamily == AF_INET) { put_int32(INET_AF_INET, &tbuf[0]); } @@ -9484,18 +10811,24 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_GETFD: { char tbuf[4]; - DEBUGF(("inet_ctl(%p): GETFD\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl -> GETFD\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + if (!IS_OPEN(desc)) return ctl_error(EINVAL, rbuf, rsize); put_int32((long)desc->s, tbuf); return ctl_reply(INET_REP_OK, tbuf, 4, rbuf, rsize); } + case INET_REQ_GETHOSTNAME: { /* get host name */ char tbuf[INET_MAXHOSTNAMELEN + 1]; - DEBUGF(("inet_ctl(%p): GETHOSTNAME\r\n", - desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETHOSTNAME\r\n", + __LINE__, driver_caller(desc->port)) ); + if (len != 0) return ctl_error(EINVAL, rbuf, rsize); @@ -9505,9 +10838,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_reply(INET_REP_OK, tbuf, strlen(tbuf), rbuf, rsize); } + case INET_REQ_GETPADDRS: { - DEBUGF(("inet_ctl(%p): INET_GETPADDRS\r\n", - desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETPADDRS\r\n", + __LINE__, driver_caller(desc->port)) ); if (len != 4) return ctl_error(EINVAL, rbuf, rsize); @@ -9538,13 +10874,16 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } } + case INET_REQ_PEER: { /* get peername */ char tbuf[sizeof(inet_address)]; inet_address peer; inet_address* ptr; unsigned int sz; - DEBUGF(("inet_ctl(%p): PEER\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> PEER\r\n", + __LINE__, driver_caller(desc->port)) ); if (!(desc->state & INET_F_ACTIVE)) return ctl_error(ENOTCONN, rbuf, rsize); @@ -9567,6 +10906,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_SETPEER: { /* set fake peername Port Address */ char *xerror; + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> SETPEER\r\n", + __LINE__, driver_caller(desc->port)) ); + if (len == 0) { desc->peer_ptr = NULL; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); @@ -9584,8 +10928,10 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } case INET_REQ_GETLADDRS: { - DEBUGF(("inet_ctl(%p): INET_GETLADDRS\r\n", - desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETLADDRS\r\n", + __LINE__, driver_caller(desc->port)) ); if (len != 4) return ctl_error(EINVAL, rbuf, rsize); @@ -9623,7 +10969,9 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, inet_address* ptr; unsigned int sz; - DEBUGF(("inet_ctl(%p): NAME\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl -> NAME\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); if ((ptr = desc->name_ptr) != NULL) { sz = desc->name_addr_len; @@ -9643,6 +10991,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_SETNAME: { /* set fake sockname Port Address */ char *xerror; + + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> SETNAME\r\n", + __LINE__, driver_caller(desc->port)) ); + if (len == 0) { desc->name_ptr = NULL; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); @@ -9664,7 +11017,9 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, inet_address local; int port; - DEBUGF(("inet_ctl(%p): BIND\r\n", desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl -> BIND\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); if (len < 2) return ctl_error(EINVAL, rbuf, rsize); @@ -9675,12 +11030,9 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, (desc->sfamily, &local, &buf, &len)) != NULL) return ctl_xerror(xerror, rbuf, rsize); - // printf("inet_ctl(INET_REQ_BIND) -> try bind\r\n"); if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len))) { - // printf("inet_ctl(INET_REQ_BIND) -> bind failed\r\n"); return ctl_error(sock_errno(), rbuf, rsize); } - // printf("inet_ctl(INET_REQ_BIND) -> bound\r\n"); desc->state = INET_STATE_OPEN; @@ -9697,8 +11049,10 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } case INET_REQ_IGNOREFD: { - DEBUGF(("inet_ctl(%p): IGNOREFD, IGNORED = %d\r\n", - desc->port,(int)*buf)); + + DDBG(desc, + ("INET-DRV-DBG[%d][%d,%T] inet_ctl -> IGNOREFD: %s\r\n", + __LINE__, desc->s, driver_caller(desc->port), B2S(*buf)) ); /* * FD can only be ignored for connected TCP connections for now, @@ -9739,6 +11093,10 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, short port; int n; + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETSERVBYNAME\r\n", + __LINE__, driver_caller(desc->port)) ); + if (len < 2) return ctl_error(EINVAL, rbuf, rsize); n = get_int8(buf); buf++; len--; @@ -9765,6 +11123,10 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, int n; struct servent* srv; + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> GETSERVBYPORT\r\n", + __LINE__, driver_caller(desc->port)) ); + if (len < 3) return ctl_error(EINVAL, rbuf, rsize); port = get_int16(buf); @@ -9782,6 +11144,9 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } default: + DDBG(desc, + ("INET-DRV-DBG[%d][%T] inet_ctl -> unknown command\r\n", + __LINE__, driver_caller(desc->port)) ); return ctl_xerror(EXBADPORT, rbuf, rsize); } } @@ -10111,8 +11476,10 @@ static void tcp_close_check(tcp_descriptor* desc) static void tcp_inet_stop(ErlDrvData e) { tcp_descriptor* desc = (tcp_descriptor*)e; - DEBUGF(("tcp_inet_stop(%p) {s=%d\r\n", - desc->inet.port, desc->inet.s)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR "] tcp_inet_stop -> entry\r\n", + __LINE__, desc->inet.s) ); tcp_close_check(desc); tcp_clear_input(desc); @@ -10121,12 +11488,15 @@ static void tcp_inet_stop(ErlDrvData e) if(desc->tcp_add_flags & TCP_ADDF_SENDFILE) { desc->tcp_add_flags &= ~TCP_ADDF_SENDFILE; close(desc->sendfile.dup_file_fd); - DEBUGF(("tcp_inet_stop(%p): SENDFILE dup closed %d\r\n", - desc->inet.port, desc->sendfile.dup_file_fd)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR "] " + "tcp_inet_stop -> SENDFILE dup closed %d\r\n", + __LINE__, desc->inet.s, desc->sendfile.dup_file_fd) ); + } #endif - DEBUGF(("tcp_inet_stop(%p) }\r\n", desc->inet.port)); inet_stop(INETP(desc)); } @@ -10167,10 +11537,14 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, cmd -= ERTS_INET_DRV_CONTROL_MAGIC_NUMBER; switch(cmd) { + case INET_REQ_OPEN: { /* open socket and return internal index */ int domain; - DEBUGF(("tcp_inet_ctl(%p): OPEN\r\n", - desc->inet.port)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][%T] tcp_inet_ctl -> OPEN\r\n", + __LINE__, driver_caller(desc->inet.port)) ); + if (len != 2) return ctl_error(EINVAL, rbuf, rsize); switch(buf[0]) { case INET_AF_INET: @@ -10194,11 +11568,16 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, break; } + case INET_REQ_FDOPEN: { /* pass in an open (and optionally bound) socket */ int domain; int bound; - DEBUGF(("tcp_inet_ctl(%p): FDOPEN\r\n", - desc->inet.port)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> FDOPEN\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + if (len != 6 && len != 10) return ctl_error(EINVAL, rbuf, rsize); switch(buf[0]) { case INET_AF_INET: @@ -10228,11 +11607,15 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, break; } - case INET_REQ_LISTEN: { /* argument backlog */ + case INET_REQ_LISTEN: { /* argument backlog */ int backlog; - DEBUGF(("tcp_inet_ctl(%p): LISTEN\r\n", - desc->inet.port)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> LISTEN\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + if (desc->inet.state == INET_STATE_CLOSED) return ctl_xerror(EXBADPORT, rbuf, rsize); if (!IS_OPEN(INETP(desc))) @@ -10252,8 +11635,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char tbuf[2], *xerror; unsigned timeout; - DEBUGF(("tcp_inet_ctl(%p): CONNECT\r\n", - desc->inet.port)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> CONNECT\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + /* INPUT: Timeout(4), Port(2), Address(N) */ if (!IS_OPEN(INETP(desc))) @@ -10273,16 +11659,35 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, code = sock_connect(desc->inet.s, (struct sockaddr*) &desc->inet.remote, len); + + /* We *cannot* have debug printouts here since it resets the + * 'errno' value (printf). + */ + if (IS_SOCKET_ERROR(code) && ((sock_errno() == ERRNO_BLOCK) || /* Winsock2 */ (sock_errno() == EINPROGRESS))) { /* Unix & OSE!! */ - sock_select(INETP(desc), FD_CONNECT, 1); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(connect) -> would block => select\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port)) ); + + sock_select(INETP(desc), FD_CONNECT, 1); desc->inet.state = INET_STATE_CONNECTING; if (timeout != INET_INFINITY) driver_set_timer(desc->inet.port, timeout); enq_async(INETP(desc), tbuf, INET_REQ_CONNECT); } else if (code == 0) { /* ok we are connected */ + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(connect) -> connected\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port)) ); + desc->inet.state = INET_STATE_CONNECTED; if (desc->inet.active) sock_select(INETP(desc), (FD_READ|FD_CLOSE), 1); @@ -10290,11 +11695,21 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, async_ok(INETP(desc)); } else { - return ctl_error(sock_errno(), rbuf, rsize); + int save_errno = sock_errno(); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(connect) -> error: %s (%d)\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port), + errno_str(save_errno), save_errno) ); + + return ctl_error(save_errno, rbuf, rsize); } return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } + case INET_REQ_ACCEPT: { /* do async accept */ char tbuf[2]; unsigned timeout; @@ -10302,8 +11717,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, unsigned int n; SOCKET s; - DEBUGF(("tcp_inet_ctl(%p): ACCEPT\r\n", - desc->inet.port)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> ACCEPT\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + /* INPUT: Timeout(4) */ if ((desc->inet.state != INET_STATE_LISTENING && desc->inet.state != INET_STATE_ACCEPTING && @@ -10316,7 +11734,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, if (desc->inet.state == INET_STATE_ACCEPTING) { unsigned long time_left = 0; int oid = 0; - ErlDrvTermData ocaller = ERL_DRV_NIL; + ErlDrvTermData ocaller = am_undefined; int oreq = 0; unsigned otimeout = 0; ErlDrvTermData caller = driver_caller(desc->inet.port); @@ -10380,17 +11798,17 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_error(sock_errno(), rbuf, rsize); } } else { - ErlDrvTermData caller = driver_caller(desc->inet.port); + ErlDrvTermData owner = driver_caller(desc->inet.port); tcp_descriptor* accept_desc; int err; - if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) { + if ((accept_desc = tcp_inet_copy(desc,s,owner,&err)) == NULL) { sock_close(s); return ctl_error(err, rbuf, rsize); } /* FIXME: may MUST lock access_port * 1 - Port is accessible via the erlang:ports() - * 2 - Port is accessible via callers process_info(links) + * 2 - Port is accessible via owners process_info(links) */ accept_desc->inet.remote = remote; SET_NONBLOCKING(accept_desc->inet.s); @@ -10405,9 +11823,12 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } } + + case INET_REQ_CLOSE: - DEBUGF(("tcp_inet_ctl(%p): CLOSE\r\n", - desc->inet.port)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] tcp_inet_ctl -> CLOSE\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); tcp_close_check(desc); tcp_desc_close(desc); return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); @@ -10418,8 +11839,10 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char tbuf[2]; int n; - DEBUGF(("tcp_inet_ctl(%p): RECV (s=%d)\r\n", - desc->inet.port, desc->inet.s)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] tcp_inet_ctl -> RECV\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + /* INPUT: Timeout(4), Length(4) */ if (!IS_CONNECTED(INETP(desc))) { if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) { @@ -10438,8 +11861,13 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, timeout = get_int32(buf); buf += 4; n = get_int32(buf); - DEBUGF(("tcp_inet_ctl(%p) timeout = %d, n = %d\r\n", - desc->inet.port,timeout,n)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(recv) -> timeout: %d, n: %d\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port), timeout, n) ); + if ((desc->inet.htype != TCP_PB_RAW) && (n != 0)) return ctl_error(EINVAL, rbuf, rsize); if (n > TCP_MAX_PACKET_SIZE) @@ -10452,7 +11880,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, async_error_am(INETP(desc), am_timeout); else { if (timeout != INET_INFINITY) - add_multi_timer(desc, INETP(desc)->port, 0, + add_multi_timer(desc, INETP(desc)->port, am_undefined, timeout, &tcp_inet_recv_timeout); if (!INET_IGNORED(INETP(desc))) sock_select(INETP(desc),(FD_READ|FD_CLOSE),1); @@ -10463,9 +11891,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } + case TCP_REQ_UNRECV: { - DEBUGF(("tcp_inet_ctl(%p): UNRECV\r\n", - desc->inet.port)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] tcp_inet_ctl -> UNRECV\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); if (!IS_CONNECTED(INETP(desc))) return ctl_error(ENOTCONN, rbuf, rsize); tcp_push_buffer(desc, buf, len); @@ -10473,17 +11903,31 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, tcp_deliver(desc, 0); return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } + + case TCP_REQ_SHUTDOWN: { int how; - DEBUGF(("tcp_inet_ctl(%p): FDOPEN\r\n", - desc->inet.port)); + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> SHUTDOWN\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); + if (!IS_CONNECTED(INETP(desc))) { return ctl_error(ENOTCONN, rbuf, rsize); } if (len != 1) { return ctl_error(EINVAL, rbuf, rsize); } + how = buf[0]; + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(shutdown) -> how: %s (%d)\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port), SH2S(how), how) ); + if (how != TCP_SHUT_RD && driver_sizeq(desc->inet.port) > 0) { if (how == TCP_SHUT_WR) { desc->tcp_add_flags |= TCP_ADDF_PENDING_SHUT_WR; @@ -10501,6 +11945,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, } } + case TCP_REQ_SENDFILE: { #ifdef HAVE_SENDFILE const ErlDrvSizeT required_len = @@ -10509,8 +11954,10 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, int raw_file_fd; - DEBUGF(("tcp_inet_ctl(%p): SENDFILE\r\n", - desc->inet.port)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> SENDFILE\r\n", + __LINE__, desc->inet.s, driver_caller(desc->inet.port)) ); if (len != required_len) { return ctl_error(EINVAL, rbuf, rsize); @@ -10530,8 +11977,12 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, desc->sendfile.dup_file_fd = dup(raw_file_fd); - DEBUGF(("tcp_inet_ctl(%p): SENDFILE dup %d\r\n", - desc->inet.port, desc->sendfile.dup_file_fd)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl(sendfile) -> dup: %d\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port), + desc->sendfile.dup_file_fd) ); if(desc->sendfile.dup_file_fd == -1) { return ctl_error(errno, rbuf, rsize); @@ -10548,8 +11999,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, desc->sendfile.ioq_skip = driver_sizeq(desc->inet.port); desc->sendfile.bytes_sent = 0; - - desc->inet.caller = driver_caller(desc->inet.port); desc->tcp_add_flags |= TCP_ADDF_SENDFILE; /* See if we can finish sending without selecting & rescheduling. */ @@ -10565,8 +12014,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, } default: - DEBUGF(("tcp_inet_ctl(%p): %u\r\n", - desc->inet.port, cmd)); + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_ctl -> (maybe) general command %u\r\n", + __LINE__, + desc->inet.s, driver_caller(desc->inet.port), cmd) ); return inet_ctl(INETP(desc), cmd, buf, len, rbuf, rsize); } @@ -10577,7 +12029,6 @@ static int tcp_inet_send_timeout(ErlDrvData e, ErlDrvTermData dummy) tcp_descriptor* desc = (tcp_descriptor*)e; ASSERT(IS_BUSY(INETP(desc))); ASSERT(desc->busy_on_send); - desc->inet.caller = desc->inet.busy_caller; desc->inet.state &= ~INET_F_BUSY; desc->busy_on_send = 0; set_busy_port(desc->inet.port, 0); @@ -10660,31 +12111,62 @@ static int tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller) ** output on a socket only ! ** a reply code will be sent to connected (caller later) ** {inet_reply, S, Status} -** NOTE! normal sockets use the the tcp_inet_commandv +** NOTE! normal sockets use the tcp_inet_commandv ** but distribution still uses the tcp_inet_command!! */ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) { - tcp_descriptor* desc = (tcp_descriptor*)e; - desc->inet.caller = driver_caller(desc->inet.port); + tcp_descriptor *desc = (tcp_descriptor*)e; + inet_descriptor *inetp = INETP(desc); - DEBUGF(("tcp_inet_command(%p) {s=%d\r\n", - desc->inet.port, desc->inet.s)); - if (!IS_CONNECTED(INETP(desc))) - inet_reply_error(INETP(desc), ENOTCONN); + if (! init_caller(&inetp->caller, &inetp->caller_ref, + inetp->port, &buf, &len)) { + driver_failure_posix(inetp->port, EINVAL); + return; + } + + DDBG(inetp, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_command -> entry\r\n", + __LINE__, inetp->s, inetp->caller) ); + + if (!IS_CONNECTED(inetp)) + inet_reply_error(inetp, ENOTCONN); else if (tcp_send(desc, buf, len) == 0) - inet_reply_ok(INETP(desc)); - DEBUGF(("tcp_inet_command(%p) }\r\n", desc->inet.port)); + inet_reply_ok(inetp); + + DDBG(inetp, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_command -> done\r\n", + __LINE__, inetp->s, inetp->caller) ); + } -static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) +static void tcp_inet_commandv(ErlDrvData e, ErlIOVec *ev) { - tcp_descriptor* desc = (tcp_descriptor*)e; - desc->inet.caller = driver_caller(desc->inet.port); + tcp_descriptor *desc = (tcp_descriptor*)e; + inet_descriptor *inetp = INETP(desc); +#ifdef INET_DRV_DEBUG + ErlDrvTermData caller; +#endif + + if (! init_caller_iov(&inetp->caller, &inetp->caller_ref, + inetp->port, &ev->iov, &ev->size)) { + driver_failure_posix(inetp->port, EINVAL); + return; + } + +#ifdef INET_DRV_DEBUG + caller = inetp->caller; + /* This function is just called to much to be part of this * + * by default. Atleast as long as there are no 'debug levels'. */ + DDBG(inetp, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "tcp_inet_commandv -> entry\r\n", + __LINE__, inetp->s, caller) ); +#endif - DEBUGF(("tcp_inet_commandv(%p) {s=%d\r\n", - desc->inet.port, desc->inet.s)); if (!IS_CONNECTED(INETP(desc))) { if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_SEND) { desc->tcp_add_flags &= ~TCP_ADDF_DELAYED_CLOSE_SEND; @@ -10692,18 +12174,24 @@ static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) /* Don't clear flag. Leave it enabled for the next receive * operation. */ - inet_reply_error(INETP(desc), ECONNRESET); + inet_reply_error(inetp, ECONNRESET); } else - inet_reply_error_am(INETP(desc), am_closed); + inet_reply_error_am(inetp, am_closed); } else - inet_reply_error(INETP(desc), ENOTCONN); + inet_reply_error(inetp, ENOTCONN); } else if (desc->tcp_add_flags & TCP_ADDF_PENDING_SHUTDOWN) tcp_shutdown_error(desc, EPIPE); else if (tcp_sendv(desc, ev) == 0) - inet_reply_ok(INETP(desc)); - DEBUGF(("tcp_inet_commandv(%p) }\r\n", desc->inet.port)); + inet_reply_ok(inetp); + +#ifdef INET_DRV_DEBUG + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] tcp_inet_commandv -> done\r\n", + __LINE__, inetp->s, caller) ); +#endif + } static void tcp_inet_flush(ErlDrvData e) @@ -10734,7 +12222,13 @@ static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp) { tcp_descriptor* desc = (tcp_descriptor*)e; ErlDrvTermData who = driver_get_monitored_process(desc->inet.port,monitorp); - int state = desc->inet.state; + int state = desc->inet.state; + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%p] " + "tcp_inet_process_exit -> entry with" + "\r\n who: %T\r\n", + __LINE__, desc->inet.s, desc->inet.port, who) ); if ((state & INET_STATE_MULTI_ACCEPTING) == INET_STATE_MULTI_ACCEPTING) { int id,req; @@ -10757,6 +12251,12 @@ static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp) sock_select(INETP(desc),FD_ACCEPT,0); desc->inet.state = INET_STATE_LISTENING; /* restore state */ } + + DDBG(INETP(desc), + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%p] " + "tcp_inet_process_exit -> done\r\n", + __LINE__, desc->inet.s, desc->inet.port) ); + } static void inet_stop_select(ErlDrvEvent event, void* _) @@ -10776,10 +12276,9 @@ static int tcp_recv_closed(tcp_descriptor* desc) #endif int blocking_send = 0; DEBUGF(("tcp_recv_closed(%p): s=%d, in %s, line %d\r\n", - port, desc->inet.s, __FILE__, __LINE__)); + port, desc->inet.s, __LINE__)); if (IS_BUSY(INETP(desc))) { /* A send is blocked */ - desc->inet.caller = desc->inet.busy_caller; tcp_clear_output(desc); if (desc->busy_on_send) { cancel_multi_timer(desc, INETP(desc)->port, &tcp_inet_send_timeout); @@ -10841,7 +12340,6 @@ static int tcp_recv_error(tcp_descriptor* desc, int err) if (err != ERRNO_BLOCK) { if (IS_BUSY(INETP(desc))) { /* A send is blocked */ - desc->inet.caller = desc->inet.busy_caller; tcp_clear_output(desc); if (desc->busy_on_send) { cancel_multi_timer(desc, INETP(desc)->port, &tcp_inet_send_timeout); @@ -11182,7 +12680,7 @@ static int winsock_event_select(inet_descriptor *desc, int flags, int on) return -1; } - /* Now, WSAEventSelect() is trigged only when the queue goes from + /* Now, WSAEventSelect() is triggered only when the queue goes from full to empty or from empty to full; therefore we need an extra test to see whether it is writeable, readable or closed... */ if ((desc->event_mask & FD_WRITE)) { @@ -11324,7 +12822,7 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) } if (netEv.lNetworkEvents & FD_CLOSE) { /* error in err = netEv.iErrorCode[FD_CLOSE_BIT] */ - DEBUGF(("Detected close in %s, line %d\r\n", __FILE__, __LINE__)); + DEBUGF(("Detected close in %s, line %d\r\n", __LINE__)); if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) { err = netEv.iErrorCode[FD_CLOSE_BIT]; if (err == ECONNRESET) @@ -11358,12 +12856,8 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) { int ret = 0; -#ifdef DEBUG - long port = (long) desc->inet.port; /* Used after driver_exit() */ -#endif ASSERT(!INET_IGNORED(INETP(desc))); - DEBUGF(("tcp_inet_input(%p) {s=%d\r\n", port, desc->inet.s)); - /* XXX fprintf(stderr,"tcp_inet_input(%p) {s=%d}\r\n",(long) desc->inet.port, desc->inet.s); */ + DEBUGF(("tcp_inet_input(%p) {s=%d\r\n", desc->inet.port, desc->inet.s)); if (desc->inet.state == INET_STATE_ACCEPTING) { SOCKET s; unsigned int len; @@ -11501,10 +12995,10 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) /* maybe a close op from connection attempt?? */ sock_select(INETP(desc),FD_ACCEPT,0); DEBUGF(("tcp_inet_input(%p): s=%d bad state: %04x\r\n", - port, desc->inet.s, desc->inet.state)); + desc->inet.port, desc->inet.s, desc->inet.state)); } done: - DEBUGF(("tcp_inet_input(%p) }\r\n", port)); + DEBUGF(("tcp_inet_input(%p) }\r\n", desc->inet.port)); return ret; } @@ -11517,7 +13011,6 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) * If the port is busy, we must do some clean-up before proceeding. */ if (IS_BUSY(INETP(desc))) { - desc->inet.caller = desc->inet.busy_caller; if (desc->busy_on_send) { cancel_multi_timer(desc, INETP(desc)->port, &tcp_inet_send_timeout); desc->busy_on_send = 0; @@ -11533,7 +13026,7 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) * and active sockets. */ DEBUGF(("driver_failure_eof(%p) in %s, line %d\r\n", - desc->inet.port, __FILE__, __LINE__)); + desc->inet.port, __LINE__)); if (desc->inet.active) { ErlDrvTermData err_atom; if (show_econnreset) { @@ -11543,7 +13036,7 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) err_atom = am_closed; } tcp_closed_message(desc); - if (!(desc->tcp_add_flags & TCP_ADDF_SENDFILE)) + if (! (desc->tcp_add_flags & TCP_ADDF_SENDFILE)) inet_reply_error_am(INETP(desc), err_atom); if (desc->inet.exitf) @@ -11553,21 +13046,19 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) } else { tcp_close_check(desc); - if (desc->inet.caller) { - if (!(desc->tcp_add_flags & TCP_ADDF_SENDFILE)) { - if (show_econnreset) - inet_reply_error(INETP(desc), err); - else - inet_reply_error_am(INETP(desc), am_closed); - } - } - else { + if (is_not_internal_pid(desc->inet.caller)) { /* No blocking send op to reply to right now. * If next op is a send, make sure it returns {error,closed} * rather than {error,enotconn}. */ desc->tcp_add_flags |= TCP_ADDF_DELAYED_CLOSE_SEND; - } + } + else if (! (desc->tcp_add_flags & TCP_ADDF_SENDFILE)) { + if (show_econnreset) + inet_reply_error(INETP(desc), err); + else + inet_reply_error_am(INETP(desc), am_closed); + } tcp_desc_close(desc); /* @@ -11682,12 +13173,12 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) DEBUGF(("tcp_sendv(%p): s=%d, sender forced busy\r\n", desc->inet.port, desc->inet.s)); desc->inet.state |= INET_F_BUSY; /* mark for low-watermark */ - desc->inet.busy_caller = desc->inet.caller; set_busy_port(desc->inet.port, 1); if (desc->send_timeout != INET_INFINITY) { desc->busy_on_send = 1; add_multi_timer(desc, INETP(desc)->port, - 0 /* arg */, desc->send_timeout /* timeout */, + am_undefined, /* caller */ + desc->send_timeout /* timeout */, &tcp_inet_send_timeout); } return 1; @@ -11710,7 +13201,7 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) n = 0; } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { driver_enqv(ix, ev, 0); - add_multi_timer(desc, INETP(desc)->port, 0, + add_multi_timer(desc, INETP(desc)->port, am_undefined, 0, &tcp_inet_delay_send); return 0; } else if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, ev->iov, @@ -11794,12 +13285,12 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) DEBUGF(("tcp_send(%p): s=%d, sender forced busy\r\n", desc->inet.port, desc->inet.s)); desc->inet.state |= INET_F_BUSY; /* mark for low-watermark */ - desc->inet.busy_caller = desc->inet.caller; set_busy_port(desc->inet.port, 1); if (desc->send_timeout != INET_INFINITY) { desc->busy_on_send = 1; add_multi_timer(desc, INETP(desc)->port, - 0 /* arg */, desc->send_timeout /* timeout */, + am_undefined /* caller */, + desc->send_timeout /* timeout */, &tcp_inet_send_timeout); } return 1; @@ -11906,7 +13397,6 @@ static int tcp_sendfile_completed(tcp_descriptor* desc) { if (driver_sizeq(desc->inet.port) <= desc->low) { if (IS_BUSY(INETP(desc))) { - desc->inet.caller = desc->inet.busy_caller; desc->inet.state &= ~INET_F_BUSY; set_busy_port(desc->inet.port, 0); @@ -12129,7 +13619,7 @@ socket_error: { } #endif /* HAVE_SENDFILE */ -/* socket ready for ouput: +/* socket ready for output: ** 1. INET_STATE_CONNECTING => non block connect ? ** 2. INET_STATE_CONNECTED => write output */ @@ -12251,7 +13741,6 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) } if (driver_deq(ix, n) <= desc->low) { if (IS_BUSY(INETP(desc))) { - desc->inet.caller = desc->inet.busy_caller; desc->inet.state &= ~INET_F_BUSY; set_busy_port(desc->inet.port, 0); /* if we have a timer then cancel and send ok to client */ @@ -12327,7 +13816,8 @@ static int should_use_so_bsdcompat(void) */ static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol); -static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) +static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, + ErlDrvTermData owner, int* err) { ErlDrvSizeT q_low, q_high; ErlDrvPort port = desc->inet.port; @@ -12356,8 +13846,8 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) copy_desc->inet.hsz = desc->inet.hsz; copy_desc->inet.bufsz = desc->inet.bufsz; - /* The new port will be linked and connected to the caller */ - port = driver_create_port(port, desc->inet.caller, "sctp_inet", + /* The new port will be linked and connected to the owner */ + port = driver_create_port(port, owner, "sctp_inet", (ErlDrvData) copy_desc); if ((long)port == -1) { *err = ENFILE; @@ -12382,7 +13872,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) #ifdef HAVE_UDP -static int packet_inet_init() +static int packet_inet_init(void) { sys_memzero((char *)&disassoc_sa, sizeof(disassoc_sa)); #ifdef AF_UNSPEC @@ -12471,13 +13961,16 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int af = AF_INET; cmd -= ERTS_INET_DRV_CONTROL_MAGIC_NUMBER; + switch(cmd) { case INET_REQ_OPEN: /* open socket and return internal index */ - DEBUGF(("packet_inet_ctl(%p): OPEN\r\n", - desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][%T] packet_inet_ctl -> OPEN\r\n", + __LINE__, driver_caller(desc->port)) ); if (len != 2) { return ctl_error(EINVAL, rbuf, rsize); } + switch (buf[0]) { case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) @@ -12489,6 +13982,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, default: return ctl_xerror(str_eafnosupport, rbuf, rsize); } + switch (buf[1]) { case INET_TYPE_STREAM: type = SOCK_STREAM; break; case INET_TYPE_DGRAM: type = SOCK_DGRAM; break; @@ -12498,6 +13992,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, default: return ctl_error(EINVAL, rbuf, rsize); } + replen = inet_ctl_open(desc, af, type, rbuf, rsize); if ((*rbuf)[0] != INET_REP_ERROR) { @@ -12523,11 +14018,16 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_REQ_FDOPEN: { /* pass in an open (and optionally bound) socket */ SOCKET s; int bound; - DEBUGF(("packet inet_ctl(%p): FDOPEN\r\n", - desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> FDOPEN\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + if (len != 6 && len != 10) { return ctl_error(EINVAL, rbuf, rsize); } + switch (buf[0]) { case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) @@ -12539,6 +14039,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, default: return ctl_xerror(str_eafnosupport, rbuf, rsize); } + switch (buf[1]) { case INET_TYPE_STREAM: type = SOCK_STREAM; break; case INET_TYPE_DGRAM: type = SOCK_DGRAM; break; @@ -12577,8 +14078,10 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_REQ_CLOSE: - DEBUGF(("packet_inet_ctl(%p): CLOSE\r\n", - desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> CLOSE\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); erl_inet_close(desc); return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); @@ -12595,9 +14098,15 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, char tbuf[2]; #ifdef HAVE_SCTP unsigned timeout; + sctp_assoc_t assoc_id = 0; + sctp_assoc_t *p_assoc_id = NULL; #endif - DEBUGF(("packet_inet_ctl(%p): CONNECT\r\n", - desc->port)); + + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> CONNECT\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); /* INPUT: [ Timeout(4), Port(2), Address(N) ] */ @@ -12619,22 +14128,55 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, /* For SCTP, we do not set the peer's addr in desc->remote, as multiple peers are possible: */ - if ((xerror = inet_set_faddress - (desc->sfamily, &remote, &buf, &len)) != NULL) + if ((*buf) == INET_AF_LIST) { + /* called as gen_sctp:connectx... */ + int addrcnt = 0; + buf++; len--; + addrcnt = get_int8(buf), + buf++; len--; + if (! p_sctp_connectx) + return ctl_error(ENOTSUP, rbuf, rsize); + if (addrcnt > 0) { + char *rabuf = ALLOC(sizeof(inet_address) * addrcnt); + struct sockaddr *addrs = (struct sockaddr *) rabuf; + ErlDrvSizeT remote_size; + char *ep = buf + len; + + for(int ai=0; ai < addrcnt; ai++) { + remote_size = ep - buf; + if ((xerror = inet_set_faddress + (desc->sfamily, &remote, &buf, &remote_size)) != NULL) { + FREE((char *)addrs); + return ctl_xerror(xerror, rbuf, rsize); + } + memcpy(rabuf, &remote, remote_size); + rabuf += remote_size; + } + p_assoc_id = &assoc_id; + code = p_sctp_connectx(desc->s, addrs, addrcnt, p_assoc_id); + FREE((char *)addrs); + } else { + return ctl_error(EINVAL, rbuf, rsize); + } + } else { + /* called as gen_sctp:connect... */ + if ((xerror = inet_set_faddress + (desc->sfamily, &remote, &buf, &len)) != NULL) return ctl_xerror(xerror, rbuf, rsize); - - code = sock_connect(desc->s, &remote.sa, len); + + code = sock_connect(desc->s, &remote.sa, len); + } if (IS_SOCKET_ERROR(code) && (sock_errno() == EINPROGRESS)) { /* XXX: Unix only -- WinSock would have a different cond! */ if (timeout != INET_INFINITY) driver_set_timer(desc->port, timeout); enq_async(desc, tbuf, INET_REQ_CONNECT); - async_ok(desc); + async_ok_maybe_assoc_id(desc, p_assoc_id); } else if (code == 0) { /* OK we are connected */ enq_async(desc, tbuf, INET_REQ_CONNECT); - async_ok(desc); + async_ok_maybe_assoc_id(desc, p_assoc_id); } else { return ctl_error(sock_errno(), rbuf, rsize); @@ -12694,9 +14236,12 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, from the TCP section. Returns: {ok,[]} on success. */ int backlog; - - DEBUGF(("packet_inet_ctl(%p): LISTEN\r\n", - desc->port)); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> LISTEN\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + if (!IS_SCTP(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); if (!IS_OPEN(desc)) @@ -12723,6 +14268,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, char* curr; int add_flag, rflag; + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> BINDX\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + if (!IS_SCTP(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); @@ -12760,9 +14310,15 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, udp_descriptor* new_udesc; int err; SOCKET new_socket; + ErlDrvTermData caller; + + caller = driver_caller(desc->port); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> PEELOFF\r\n", + __LINE__, desc->s, caller) ); - DEBUGF(("packet_inet_ctl(%p): PEELOFF\r\n", - desc->port)); if (!IS_SCTP(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); if (!IS_OPEN(desc)) @@ -12779,12 +14335,14 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, return ctl_error(sock_errno(), rbuf, rsize); } - desc->caller = driver_caller(desc->port); - if ((new_udesc = sctp_inet_copy(udesc, new_socket, &err)) == NULL) { + if ((new_udesc = + sctp_inet_copy(udesc, new_socket, caller, &err)) == NULL) { sock_close(new_socket); - desc->caller = 0; return ctl_error(err, rbuf, rsize); } + else { + desc->caller = caller; + } new_udesc->inet.state = INET_STATE_CONNECTED; new_udesc->inet.stype = SOCK_STREAM; SET_NONBLOCKING(new_udesc->inet.s); @@ -12803,8 +14361,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, unsigned timeout; char tbuf[2]; - DEBUGF(("packet_inet_ctl(%p): RECV\r\n", - desc->port)); + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%T] " + "packet_inet_ctl -> RECV\r\n", + __LINE__, desc->s, driver_caller(desc->port)) ); + /* INPUT: Timeout(4), Length(4) */ if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); @@ -12829,6 +14390,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, INET_REQ_BIND goes here. If the req is not recognised there either, an error is returned: */ + return inet_ctl(desc, cmd, buf, len, rbuf, rsize); } } @@ -12837,6 +14399,12 @@ static void packet_inet_timeout(ErlDrvData e) { udp_descriptor * udesc = (udp_descriptor*) e; inet_descriptor * desc = INETP(udesc); + + DDBG(desc, + ("INET-DRV-DBG[%d][" SOCKET_FSTR ",%p] " + "packet_inet_timeout -> entry\r\n", + __LINE__, desc->s, desc->port) ); + if (!(desc->active)) { sock_select(desc, FD_READ, 0); async_error_am (desc, am_timeout); @@ -12850,7 +14418,7 @@ static void packet_inet_timeout(ErlDrvData e) ** input should be: Family Address buffer . ** For UDP, buffer (after Address) is just data to be sent. ** For SCTP, buffer contains a list representing 2 items: -** (1) 6 parms for sctp_sndrcvinfo, as in sctp_get_sendparams(); +** (1) 6 params for sctp_sndrcvinfo, as in sctp_get_sendparams(); ** (2) 0+ real data bytes. ** There is no destination address -- SCTP send is performed over ** an existing association, using "sctp_sndrcvinfo" specified. @@ -12859,14 +14427,19 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) { udp_descriptor * udesc= (udp_descriptor*) e; inet_descriptor* desc = INETP(udesc); - char* ptr = buf; + char* ptr; char* qtr; char* xerror; ErlDrvSizeT sz; int code; inet_address other; - desc->caller = driver_caller(desc->port); + if (! init_caller(&desc->caller, &desc->caller_ref, + desc->port, &buf, &len)) { + driver_failure_posix(desc->port, EINVAL); + return; + } + ptr = buf; if (!IS_OPEN(desc)) { inet_reply_error(desc, EINVAL); @@ -13484,8 +15057,7 @@ static MultiTimerData *add_multi_timer(tcp_descriptor *desc, ErlDrvPort port, -----------------------------------------------------------------------------*/ static int -save_subscriber(subs, subs_pid) -subs_list *subs; ErlDrvTermData subs_pid; +save_subscriber(subs_list *subs, ErlDrvTermData subs_pid) { subs_list *tmp; @@ -13507,8 +15079,7 @@ subs_list *subs; ErlDrvTermData subs_pid; } static void -free_subscribers(subs) -subs_list *subs; +free_subscribers(subs_list *subs) { subs_list *this; subs_list *next; @@ -13516,7 +15087,7 @@ subs_list *subs; this = subs->next; while(this) { next = this->next; - FREE((void *) this); + FREE(this); this = next; } @@ -13547,7 +15118,7 @@ static void send_to_subscribers if(free_subs && !first) { next = this->next; - FREE((void *) this); + FREE(this); this = next; } else @@ -13561,76 +15132,3 @@ static void send_to_subscribers } } - -/* - * A *very* limited socket interface. Used by the memory tracer - * (erl_mtrace.c). - */ -#include "erl_sock.h" - -erts_sock_t erts_sock_open(void) -{ - SOCKET s; - - if(!sock_init()) - return ERTS_SOCK_INVALID_SOCKET; - - s = sock_open(AF_INET, SOCK_STREAM, 0); - - if (s == INVALID_SOCKET) - return ERTS_SOCK_INVALID_SOCKET; - - return (erts_sock_t) s; -} - -void erts_sock_close(erts_sock_t socket) -{ - if (socket != ERTS_SOCK_INVALID_SOCKET) - sock_close((SOCKET) socket); -} - - -int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port) -{ - SOCKET s = (SOCKET) socket; - char buf[2 + 4], *p; - ErlDrvSizeT blen = 6; - inet_address addr; - - if (socket == ERTS_SOCK_INVALID_SOCKET || len != 4) - return 0; - - put_int16(port, buf); - memcpy((void *) (buf + 2), (void *) ip_addr, 4); - - p = buf; - if (inet_set_address(AF_INET, &addr, &p, &blen) != NULL) - return 0; - - if (IS_SOCKET_ERROR - (sock_connect(s, (struct sockaddr *) &addr, blen))) - return 0; - return 1; -} - -Sint erts_sock_send(erts_sock_t socket, const void *buf, Sint len) -{ - Sint result = (Sint) sock_send((SOCKET) socket, buf, (size_t) len, 0); - if (IS_SOCKET_ERROR(result)) - return SOCKET_ERROR; - return result; -} - - -int erts_sock_gethostname(char *buf, int bufsz) -{ - if (IS_SOCKET_ERROR(sock_hostname(buf, bufsz))) - return SOCKET_ERROR; - return 0; -} - - -int erts_sock_errno() -{ - return sock_errno(); -} diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c index 8112f824761e..fb2ac31ca703 100644 --- a/erts/emulator/drivers/common/ram_file_drv.c +++ b/erts/emulator/drivers/common/ram_file_drv.c @@ -129,11 +129,11 @@ struct erl_drv_entry ram_file_driver_entry = { /* A File is represented as a array of bytes, this array is reallocated when needed. A possibly better implementation - whould be to have a vector of blocks. This may be implemented + would be to have a vector of blocks. This may be implemented when we have the commandv/driver_outputv */ typedef struct ram_file { - ErlDrvPort port; /* the associcated port */ + ErlDrvPort port; /* the associated port */ int flags; /* flags read/write */ ErlDrvBinary* bin; /* binary to hold binary file */ char* buf; /* buffer start (in binary) */ diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c deleted file mode 100644 index 58a56e8cf0c4..000000000000 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ /dev/null @@ -1,1591 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2021. 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% - */ -/* - * Tty driver that reads one character at the time and provides a - * smart line for output. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "erl_driver.h" - -static int ttysl_init(void); -static ErlDrvData ttysl_start(ErlDrvPort, char*); - -#ifdef HAVE_TERMCAP /* else make an empty driver that cannot be opened */ - -#ifndef WANT_NONBLOCKING -#define WANT_NONBLOCKING -#endif - -#include "sys.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_WCWIDTH -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#if !defined(HAVE_SETLOCALE) || !defined(HAVE_NL_LANGINFO) || !defined(HAVE_LANGINFO_H) -#define PRIMITIVE_UTF8_CHECK 1 -#else -#include -#endif - -#if defined IOV_MAX -#define MAXIOV IOV_MAX -#elif defined UIO_MAXIOV -#define MAXIOV UIO_MAXIOV -#else -#define MAXIOV 16 -#endif - -#define TRUE 1 -#define FALSE 0 - -/* Termcap functions. */ -int tgetent(char* bp, char *name); -int tgetnum(char* cap); -int tgetflag(char* cap); -char *tgetstr(char* cap, char** buf); -char *tgoto(char* cm, int col, int line); -int tputs(char* cp, int affcnt, int (*outc)(int c)); - -/* Terminal capabilites in which we are interested. */ -static char *capbuf; -static char *up, *down, *left, *right; -static int cols, xn; -static volatile int cols_needs_update = FALSE; - -/* The various opcodes. */ -#define OP_PUTC 0 -#define OP_MOVE 1 -#define OP_INSC 2 -#define OP_DELC 3 -#define OP_BEEP 4 -#define OP_PUTC_SYNC 5 -/* Control op */ -#define CTRL_OP_GET_WINSIZE 100 -#define CTRL_OP_GET_UNICODE_STATE 101 -#define CTRL_OP_SET_UNICODE_STATE 102 - -/* We use 1024 as the buf size as that was the default buf size of FILE streams - on all platforms that I checked. */ -#define TTY_BUFFSIZE 1024 - -static int lbuf_size = BUFSIZ; -static Uint32 *lbuf; /* The current line buffer */ -static int llen; /* The current line length */ -static int lpos; /* The current "cursor position" in the line buffer */ - /* NOTE: not the same as column position a char may not take a" - * column to display or it might take many columns - */ -/* - * Tags used in line buffer to show that these bytes represent special characters, - * Max unicode is 0x0010ffff, so we have lots of place for meta tags... - */ -#define CONTROL_TAG 0x10000000U /* Control character, value in first position */ -#define ESCAPED_TAG 0x01000000U /* Escaped character, value in first position */ -#define TAG_MASK 0xFF000000U - -#define MAXSIZE (1 << 16) - -#define COL(_l) ((_l) % cols) -#define LINE(_l) ((_l) / cols) - -#define NL '\n' - -/* Main interface functions. */ -static void ttysl_stop(ErlDrvData); -static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT); -static void ttysl_to_tty(ErlDrvData, ErlDrvEvent); -static void ttysl_flush_tty(ErlDrvData); -static void ttysl_from_tty(ErlDrvData, ErlDrvEvent); -static void ttysl_stop_select(ErlDrvEvent, void*); -static Sint16 get_sint16(char*); - -static ErlDrvPort ttysl_port; -static int ttysl_fd; -static int ttysl_terminate = 0; -static int ttysl_send_ok = 0; -static ErlDrvBinary *putcbuf; -static int putcpos; -static int putclen; - -/* Functions that work on the line buffer. */ -static int start_lbuf(void); -static int stop_lbuf(void); -static int put_chars(byte*,int); -static int move_rel(int); -static int ins_chars(byte *,int); -static int del_chars(int); -static int step_over_chars(int); -static int insert_buf(byte*,int); -static int write_buf(Uint32 *,int); -static int outc(int c); -static int move_cursor(int,int); -static int cp_pos_to_col(int cp_pos); - - -/* Termcap functions. */ -static int start_termcap(void); -static int stop_termcap(void); -static int move_left(int); -static int move_right(int); -static int move_up(int); -static int move_down(int); -static void update_cols(void); - -/* Terminal setting functions. */ -static int tty_init(int,int,int,int); -static int tty_set(int); -static int tty_reset(int); -static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int, - char *, ErlDrvSizeT, char **, ErlDrvSizeT); -#ifdef ERTS_NOT_USED -static RETSIGTYPE suspend(int); -#endif -static RETSIGTYPE cont(int); -static RETSIGTYPE winch(int); - -/*#define LOG_DEBUG*/ - -#ifdef LOG_DEBUG -FILE *debuglog = NULL; - -#define DEBUGLOG(X) \ -do { \ - if (debuglog != NULL) { \ - my_debug_printf X; \ - } \ -} while (0) - -static void my_debug_printf(char *fmt, ...) -{ - char buffer[1024]; - va_list args; - - va_start(args, fmt); - erts_vsnprintf(buffer,1024,fmt,args); - va_end(args); - erts_fprintf(debuglog,"%s\n",buffer); - /*erts_printf("Debuglog = %s\n",buffer);*/ -} - -#else - -#define DEBUGLOG(X) - -#endif - -static int utf8_mode = 0; -static byte utf8buf[4]; /* for incomplete input */ -static int utf8buf_size; /* size of incomplete input */ - -# define IF_IMPL(x) x -#else -# define IF_IMPL(x) NULL -#endif /* HAVE_TERMCAP */ - -/* Define the driver table entry. */ -struct erl_drv_entry ttsl_driver_entry = { - ttysl_init, - ttysl_start, - IF_IMPL(ttysl_stop), - IF_IMPL(ttysl_from_erlang), - IF_IMPL(ttysl_from_tty), - IF_IMPL(ttysl_to_tty), - "tty_sl", /* driver_name */ - NULL, /* finish */ - NULL, /* handle */ - IF_IMPL(ttysl_control), - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - IF_IMPL(ttysl_flush_tty), - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, /* handle2 */ - NULL, /* process_exit */ - IF_IMPL(ttysl_stop_select) -}; - - -static int ttysl_init(void) -{ -#ifdef HAVE_TERMCAP - ttysl_port = (ErlDrvPort)-1; - ttysl_fd = -1; - lbuf = NULL; /* For line buffer handling */ - capbuf = NULL; /* For termcap handling */ -#endif -#ifdef LOG_DEBUG - { - char *dl; - if ((dl = getenv("TTYSL_DEBUG_LOG")) != NULL && *dl) { - debuglog = fopen(dl,"w+"); - if (debuglog != NULL) - setbuf(debuglog,NULL); - } - DEBUGLOG(("ttysl_init: Debuglog = %s(0x%ld)\n",dl,(long) debuglog)); - } -#endif - return 0; -} - -static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) -{ -#ifndef HAVE_TERMCAP - return ERL_DRV_ERROR_GENERAL; -#else - char *s, *t, *l; - int canon, echo, sig; /* Terminal characteristics */ - int flag; - extern int using_oldshell; /* set this to let the rest of erts know */ - - DEBUGLOG(("ttysl_start: driver input \"%s\", ttysl_port = %d (-1 expected)", buf, ttysl_port)); - utf8buf_size = 0; - if (ttysl_port != (ErlDrvPort)-1) { - DEBUGLOG(("ttysl_start: failure with ttysl_port = %d, not initialized properly?\n", ttysl_port)); - return ERL_DRV_ERROR_GENERAL; - } - - DEBUGLOG(("ttysl_start: isatty(0) = %d (1 expected), isatty(1) = %d (1 expected)", isatty(0), isatty(1))); - if (!isatty(0) || !isatty(1)) { - DEBUGLOG(("ttysl_start: failure in isatty, isatty(0) = %d, isatty(1) = %d", isatty(0), isatty(1))); - return ERL_DRV_ERROR_GENERAL; - } - - /* Set the terminal modes to default leave as is. */ - canon = echo = sig = 0; - - /* Parse the input parameters. */ - for (s = strchr(buf, ' '); s; s = t) { - s++; - /* Find end of this argument (start of next) and insert NUL. */ - if ((t = strchr(s, ' '))) { - *t = '\0'; - } - if ((flag = ((*s == '+') ? 1 : ((*s == '-') ? -1 : 0)))) { - if (s[1] == 'c') canon = flag; - if (s[1] == 'e') echo = flag; - if (s[1] == 's') sig = flag; - } - else if ((ttysl_fd = open(s, O_RDWR, 0)) < 0) { - DEBUGLOG(("ttysl_start: failed to open ttysl_fd, open(%s, O_RDWR, 0)) = %d\n", s, ttysl_fd)); - return ERL_DRV_ERROR_GENERAL; - } - } - - if (ttysl_fd < 0) - ttysl_fd = 0; - - if (tty_init(ttysl_fd, canon, echo, sig) < 0 || - tty_set(ttysl_fd) < 0) { - DEBUGLOG(("ttysl_start: failed init tty or set tty\n")); - ttysl_port = (ErlDrvPort)-1; - tty_reset(ttysl_fd); - return ERL_DRV_ERROR_GENERAL; - } - - /* Set up smart line and termcap stuff. */ - if (!start_lbuf() || !start_termcap()) { - DEBUGLOG(("ttysl_start: failed to start_lbuf or start_termcap\n")); - stop_lbuf(); /* Must free this */ - tty_reset(ttysl_fd); - return ERL_DRV_ERROR_GENERAL; - } - - SET_NONBLOCKING(ttysl_fd); - -#ifdef PRIMITIVE_UTF8_CHECK - setlocale(LC_CTYPE, ""); /* Set international environment, - ignore result */ - if (((l = getenv("LC_ALL")) && *l) || - ((l = getenv("LC_CTYPE")) && *l) || - ((l = getenv("LANG")) && *l)) { - if (strstr(l, "UTF-8")) - utf8_mode = 1; - } - -#else - l = setlocale(LC_CTYPE, ""); /* Set international environment */ - if (l != NULL) { - utf8_mode = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); - DEBUGLOG(("ttysl_start: setlocale: %s",l)); - } -#endif - DEBUGLOG(("ttysl_start: utf8_mode is %s",(utf8_mode) ? "on" : "off")); - sys_signal(SIGCONT, cont); - sys_signal(SIGWINCH, winch); - - driver_select(port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_READ|ERL_DRV_USE, 1); - ttysl_port = port; - - /* we need to know this when we enter the break handler */ - using_oldshell = 0; - - DEBUGLOG(("ttysl_start: successful start\n")); - return (ErlDrvData)ttysl_port; /* Nothing important to return */ -#endif /* HAVE_TERMCAP */ -} - -#ifdef HAVE_TERMCAP - -#define DEF_HEIGHT 24 -#define DEF_WIDTH 80 -static void ttysl_get_window_size(Uint32 *width, Uint32 *height) -{ -#ifdef TIOCGWINSZ - struct winsize ws; - if (ioctl(ttysl_fd,TIOCGWINSZ,&ws) == 0) { - *width = (Uint32) ws.ws_col; - *height = (Uint32) ws.ws_row; - if (*width <= 0) - *width = DEF_WIDTH; - if (*height <= 0) - *height = DEF_HEIGHT; - return; - } -#endif - *width = DEF_WIDTH; - *height = DEF_HEIGHT; -} - -static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, - unsigned int command, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - char resbuff[2*sizeof(Uint32)]; - ErlDrvSizeT res_size; - - command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER; - switch (command) { - case CTRL_OP_GET_WINSIZE: - { - Uint32 w,h; - ttysl_get_window_size(&w,&h); - memcpy(resbuff,&w,sizeof(Uint32)); - memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32)); - res_size = 2*sizeof(Uint32); - } - break; - case CTRL_OP_GET_UNICODE_STATE: - *resbuff = (utf8_mode) ? 1 : 0; - res_size = 1; - break; - case CTRL_OP_SET_UNICODE_STATE: - if (len > 0) { - int m = (int) *buf; - *resbuff = (utf8_mode) ? 1 : 0; - res_size = 1; - utf8_mode = (m) ? 1 : 0; - } else { - return 0; - } - break; - default: - return -1; - } - if (rlen < res_size) { - *rbuf = driver_alloc(res_size); - } - memcpy(*rbuf,resbuff,res_size); - return res_size; -} - - -static void ttysl_stop(ErlDrvData ttysl_data) -{ - DEBUGLOG(("ttysl_stop: ttysl_port = %d\n",ttysl_port)); - if (ttysl_port != (ErlDrvPort)-1) { - stop_lbuf(); - stop_termcap(); - tty_reset(ttysl_fd); - driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd, - ERL_DRV_WRITE|ERL_DRV_READ|ERL_DRV_USE, 0); - sys_signal(SIGCONT, SIG_DFL); - sys_signal(SIGWINCH, SIG_DFL); - } - ttysl_port = (ErlDrvPort)-1; - ttysl_fd = -1; - ttysl_terminate = 0; - /* return TRUE; */ -} - -static int put_utf8(int ch, byte *target, int sz, int *pos) -{ - Uint x = (Uint) ch; - if (x < 0x80) { - if (*pos >= sz) { - return -1; - } - target[(*pos)++] = (byte) x; - } - else if (x < 0x800) { - if (((*pos) + 1) >= sz) { - return -1; - } - target[(*pos)++] = (((byte) (x >> 6)) | - ((byte) 0xC0)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else if (x < 0x10000) { - if ((x >= 0xD800 && x <= 0xDFFF) || - (x == 0xFFFE) || - (x == 0xFFFF)) { /* Invalid unicode range */ - return -1; - } - if (((*pos) + 2) >= sz) { - return -1; - } - - target[(*pos)++] = (((byte) (x >> 12)) | - ((byte) 0xE0)); - target[(*pos)++] = ((((byte) (x >> 6)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else if (x < 0x110000) { /* Standard imposed max */ - if (((*pos) + 3) >= sz) { - return -1; - } - target[(*pos)++] = (((byte) (x >> 18)) | - ((byte) 0xF0)); - target[(*pos)++] = ((((byte) (x >> 12)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = ((((byte) (x >> 6)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else { - return -1; - } - return 0; -} - - -static int pick_utf8(byte *s, int sz, int *pos) -{ - int size = sz - (*pos); - byte *source; - Uint unipoint; - - if (size > 0) { - source = s + (*pos); - if (((*source) & ((byte) 0x80)) == 0) { - unipoint = (int) *source; - ++(*pos); - return (int) unipoint; - } else if (((*source) & ((byte) 0xE0)) == 0xC0) { - if (size < 2) { - return -2; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((*source) < 0xC2) /* overlong */) { - return -1; - } - (*pos) += 2; - unipoint = - (((Uint) ((*source) & ((byte) 0x1F))) << 6) | - ((Uint) (source[1] & ((byte) 0x3F))); - return (int) unipoint; - } else if (((*source) & ((byte) 0xF0)) == 0xE0) { - if (size < 3) { - return -2; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((source[2] & ((byte) 0xC0)) != 0x80) || - (((*source) == 0xE0) && (source[1] < 0xA0)) /* overlong */ ) { - return -1; - } - if ((((*source) & ((byte) 0xF)) == 0xD) && - ((source[1] & 0x20) != 0)) { - return -1; - } - if (((*source) == 0xEF) && (source[1] == 0xBF) && - ((source[2] == 0xBE) || (source[2] == 0xBF))) { - return -1; - } - (*pos) += 3; - unipoint = - (((Uint) ((*source) & ((byte) 0xF))) << 12) | - (((Uint) (source[1] & ((byte) 0x3F))) << 6) | - ((Uint) (source[2] & ((byte) 0x3F))); - return (int) unipoint; - } else if (((*source) & ((byte) 0xF8)) == 0xF0) { - if (size < 4) { - return -2 ; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((source[2] & ((byte) 0xC0)) != 0x80) || - ((source[3] & ((byte) 0xC0)) != 0x80) || - (((*source) == 0xF0) && (source[1] < 0x90)) /* overlong */) { - return -1; - } - if ((((*source) & ((byte)0x7)) > 0x4U) || - ((((*source) & ((byte)0x7)) == 0x4U) && - ((source[1] & ((byte)0x3F)) > 0xFU))) { - return -1; - } - (*pos) += 4; - unipoint = - (((Uint) ((*source) & ((byte) 0x7))) << 18) | - (((Uint) (source[1] & ((byte) 0x3F))) << 12) | - (((Uint) (source[2] & ((byte) 0x3F))) << 6) | - ((Uint) (source[3] & ((byte) 0x3F))); - return (int) unipoint; - } else { - return -1; - } - } else { - return -1; - } -} - -static int octal_or_hex_positions(Uint c) -{ - int x = 0; - Uint ch = c; - if (!ch) { - return 1; - } - while(ch) { - ++x; - ch >>= 3; - } - if (x <= 3) { - return 3; - } - /* \x{H ...} format when larger than \777 */ - x = 0; - ch = c; - while(ch) { - ++x; - ch >>= 4; - } - return x+3; -} - -static void octal_or_hex_format(Uint ch, byte *buf, int *pos) -{ - static byte hex_chars[] = { '0','1','2','3','4','5','6','7','8','9', - 'A','B','C','D','E','F'}; - int num = octal_or_hex_positions(ch); - if (num != 3) { - ASSERT(num > 3); - buf[(*pos)++] = 'x'; - buf[(*pos)++] = '{'; - num -= 3; - while(num--) { - buf[(*pos)++] = hex_chars[((ch >> (4*num)) & 0xFU)]; - } - buf[(*pos)++] = '}'; - } else { - while(num--) { - buf[(*pos)++] = ((byte) ((ch >> (3*num)) & 0x7U) + '0'); - } - } -} - -/* - * Check that there is enough room in all buffers to copy all pad chars - * and stiff we need If not, realloc lbuf. - */ -static int check_buf_size(byte *s, int n) -{ - int pos = 0; - int ch; - int size = 10; - - DEBUGLOG(("check_buf_size: n = %d",n)); - while(pos < n) { - /* Indata is always UTF-8 */ - if ((ch = pick_utf8(s,n,&pos)) < 0) { - /* XXX temporary allow invalid chars */ - ch = (int) s[pos]; - DEBUGLOG(("check_buf_size: Invalid UTF8:%d",ch)); - ++pos; - } - if (utf8_mode) { /* That is, terminal is UTF8 compliant */ - if (ch >= 128 || isprint(ch)) { -#ifdef HAVE_WCWIDTH - int width; -#endif - DEBUGLOG(("check_buf_size: Printable(UTF-8:%d):%d",pos,ch)); - size++; -#ifdef HAVE_WCWIDTH - if ((width = wcwidth(ch)) > 1) { - size += width - 1; - } -#endif - } else if (ch == '\t') { - size += 8; - } else { - DEBUGLOG(("check_buf_size: Magic(UTF-8:%d):%d",pos,ch)); - size += 2; - } - } else { - if (ch <= 255 && isprint(ch)) { - DEBUGLOG(("check_buf_size: Printable:%d",ch)); - size++; - } else if (ch == '\t') - size += 8; - else if (ch >= 128) { - DEBUGLOG(("check_buf_size: Non printable:%d",ch)); - size += (octal_or_hex_positions(ch) + 1); - } - else { - DEBUGLOG(("check_buf_size: Magic:%d",ch)); - size += 2; - } - } - } - - if (size + lpos >= lbuf_size) { - - lbuf_size = size + lpos + BUFSIZ; - if ((lbuf = driver_realloc(lbuf, lbuf_size * sizeof(Uint32))) == NULL) { - DEBUGLOG(("check_buf_size: alloc failure of %d bytes", lbuf_size * sizeof(Uint32))); - driver_failure(ttysl_port, -1); - return(0); - } - } - DEBUGLOG(("check_buf_size: success\n")); - return(1); -} - - -static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count) -{ - ErlDrvSizeT sz; - - sz = driver_sizeq(ttysl_port); - - putclen = count > TTY_BUFFSIZE ? TTY_BUFFSIZE : count; - putcbuf = driver_alloc_binary(putclen); - putcpos = 0; - - if (lpos > MAXSIZE) - put_chars((byte*)"\n", 1); - - DEBUGLOG(("ttysl_from_erlang: OP = %d", buf[0])); - - switch (buf[0]) { - case OP_PUTC_SYNC: - /* Using sync means that we have to send an ok to the - controlling process for each command call. We delay - sending ok if the driver queue exceeds a certain size. - We do not set ourselves as a busy port, as this - could be very bad for user_drv, if it gets blocked on - the port_command. */ - /* fall through */ - case OP_PUTC: - DEBUGLOG(("ttysl_from_erlang: OP: Putc(%lu)",(unsigned long) count-1)); - if (check_buf_size((byte*)buf+1, count-1) == 0) - return; - put_chars((byte*)buf+1, count-1); - break; - case OP_MOVE: - move_rel(get_sint16(buf+1)); - break; - case OP_INSC: - if (check_buf_size((byte*)buf+1, count-1) == 0) - return; - ins_chars((byte*)buf+1, count-1); - break; - case OP_DELC: - del_chars(get_sint16(buf+1)); - break; - case OP_BEEP: - outc('\007'); - break; - default: - /* Unknown op, just ignore. */ - break; - } - - driver_enq_bin(ttysl_port,putcbuf,0,putcpos); - driver_free_binary(putcbuf); - - if (sz == 0) { - for (;;) { - int written, qlen; - SysIOVec *iov; - - iov = driver_peekq(ttysl_port,&qlen); - if (iov) - written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen); - else - written = 0; - if (written < 0) { - if (errno == ERRNO_BLOCK || errno == EINTR) { - driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, - ERL_DRV_USE|ERL_DRV_WRITE,1); - break; - } else { - DEBUGLOG(("ttysl_from_erlang: driver failure in writev(%d,..) = %d (errno = %d)\n", ttysl_fd, written, errno)); - driver_failure_posix(ttysl_port, errno); - return; - } - } else { - if (driver_deq(ttysl_port, written) == 0) - break; - } - } - } - - if (buf[0] == OP_PUTC_SYNC) { - if (driver_sizeq(ttysl_port) > TTY_BUFFSIZE && !ttysl_terminate) { - /* We delay sending the ack until the buffer has been consumed */ - ttysl_send_ok = 1; - } else { - ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(ttysl_port), - ERL_DRV_ATOM, driver_mk_atom("ok"), - ERL_DRV_TUPLE, 2 - }; - ASSERT(ttysl_send_ok == 0); - erl_drv_output_term(driver_mk_port(ttysl_port), spec, - sizeof(spec) / sizeof(spec[0])); - } - } - - return; /* TRUE; */ -} - -static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { - for (;;) { - int written, qlen; - SysIOVec *iov; - ErlDrvSizeT sz; - - iov = driver_peekq(ttysl_port,&qlen); - - DEBUGLOG(("ttysl_to_tty: qlen = %d", qlen)); - - if (iov) - written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen); - else - written = 0; - if (written < 0) { - if (errno == EINTR) { - continue; - } else if (errno != ERRNO_BLOCK){ - DEBUGLOG(("ttysl_to_tty: driver failure in writev(%d,..) = %d (errno = %d)\n", ttysl_fd, written, errno)); - driver_failure_posix(ttysl_port, errno); - } - break; - } else { - sz = driver_deq(ttysl_port, written); - if (sz < TTY_BUFFSIZE && ttysl_send_ok) { - ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(ttysl_port), - ERL_DRV_ATOM, driver_mk_atom("ok"), - ERL_DRV_TUPLE, 2 - }; - ttysl_send_ok = 0; - erl_drv_output_term(driver_mk_port(ttysl_port), spec, - sizeof(spec) / sizeof(spec[0])); - } - if (sz == 0) { - driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, - ERL_DRV_WRITE,0); - if (ttysl_terminate) { - /* flush has been called, which means we should terminate - when queue is empty. This will not send any exit - message */ - DEBUGLOG(("ttysl_to_tty: ttysl_terminate normal\n")); - driver_failure_atom(ttysl_port, "normal"); - } - break; - } - } - } - - return; -} - -static void ttysl_flush_tty(ErlDrvData ttysl_data) { - DEBUGLOG(("ttysl_flush_tty: ..")); - ttysl_terminate = 1; - return; -} - -static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) -{ - byte b[1024]; - ssize_t i; - int ch = 0, pos = 0; - int left = 1024; - byte *p = b; - byte t[1024]; - int tpos; - - if (utf8buf_size > 0) { - memcpy(b,utf8buf,utf8buf_size); - left -= utf8buf_size; - p += utf8buf_size; - utf8buf_size = 0; - } - - DEBUGLOG(("ttysl_from_tty: remainder = %d", left)); - - if ((i = read((int)(SWord)fd, (char *) p, left)) >= 0) { - if (p != b) { - i += (p - b); - } - if (utf8_mode) { /* Hopefully an UTF8 terminal */ - while(pos < i && (ch = pick_utf8(b,i,&pos)) >= 0) - ; - if (ch == -2 && i - pos <= 4) { - /* bytes left to care for */ - utf8buf_size = i -pos; - memcpy(utf8buf,b+pos,utf8buf_size); - } else if (ch == -1) { - DEBUGLOG(("ttysl_from_tty: Giving up on UTF8 mode, invalid character")); - utf8_mode = 0; - goto latin_terminal; - } - driver_output(ttysl_port, (char *) b, pos); - } else { - latin_terminal: - tpos = 0; - while (pos < i) { - while (tpos < 1020 && pos < i) { /* Max 4 bytes for UTF8 */ - put_utf8((int) b[pos++], t, 1024, &tpos); - } - driver_output(ttysl_port, (char *) t, tpos); - tpos = 0; - } - } - } else if (errno != EAGAIN && errno != EWOULDBLOCK) { - DEBUGLOG(("ttysl_from_tty: driver failure in read(%d,..) = %d (errno = %d)\n", (int)(SWord)fd, i, errno)); - driver_failure(ttysl_port, -1); - } -} - -static void ttysl_stop_select(ErlDrvEvent e, void* _) -{ - int fd = (int)(long)e; - if (fd != 0) { - close(fd); - } -} - -/* Procedures for putting and getting integers to/from strings. */ -static Sint16 get_sint16(char *s) -{ - return ((*s << 8) | ((byte*)s)[1]); -} - -static int start_lbuf(void) -{ - if (!lbuf && !(lbuf = ( Uint32*) driver_alloc(lbuf_size * sizeof(Uint32)))) - return FALSE; - llen = 0; - lpos = 0; - return TRUE; -} - -static int stop_lbuf(void) -{ - if (lbuf) { - driver_free(lbuf); - lbuf = NULL; - } - return TRUE; -} - -/* Put l bytes (in UTF8) from s into the buffer and output them. */ -static int put_chars(byte *s, int l) -{ - int n; - - n = insert_buf(s, l); - if (lpos > llen) - llen = lpos; - if (n > 0) - write_buf(lbuf + lpos - n, n); - return TRUE; -} - -/* - * Move the current postition forwards or backwards within the current - * line. We know about padding. - */ -static int move_rel(int n) -{ - int npos; /* The new position */ - - /* Step forwards or backwards over the buffer. */ - npos = step_over_chars(n); - - /* Calculate move, updates pointers and move the cursor. */ - move_cursor(lpos, npos); - lpos = npos; - return TRUE; -} - -/* Insert characters into the buffer at the current position. */ -static int ins_chars(byte *s, int l) -{ - int n, tl; - Uint32 *tbuf = NULL; /* Suppress warning about use-before-set */ - - /* Move tail of buffer to make space. */ - if ((tl = llen - lpos) > 0) { - if ((tbuf = driver_alloc(tl * sizeof(Uint32))) == NULL) - return FALSE; - memcpy(tbuf, lbuf + lpos, tl * sizeof(Uint32)); - } - n = insert_buf(s, l); - if (tl > 0) { - memcpy(lbuf + lpos, tbuf, tl * sizeof(Uint32)); - driver_free(tbuf); - } - llen += n; - write_buf(lbuf + (lpos - n), llen - (lpos - n)); - move_cursor(llen, lpos); - return TRUE; -} - -/* - * Delete characters in the buffer. Can delete characters before (n < 0) - * and after (n > 0) the current position. Cursor left at beginning of - * deleted block. - */ -static int del_chars(int n) -{ - int i, l, r; - int pos; - int gcs; /* deleted grapheme characters */ - - update_cols(); - - /* Step forward or backwards over n logical characters. */ - pos = step_over_chars(n); - DEBUGLOG(("del_chars: %d from %d %d %d\n", n, lpos, pos, llen)); - if (pos > lpos) { - l = pos - lpos; /* Buffer characters to delete */ - r = llen - lpos - l; /* Characters after deleted */ - gcs = cp_pos_to_col(pos) - cp_pos_to_col(lpos); - /* Fix up buffer and buffer pointers. */ - if (r > 0) - memmove(lbuf + lpos, lbuf + pos, r * sizeof(Uint32)); - llen -= l; - /* Write out characters after, blank the tail and jump back to lpos. */ - write_buf(lbuf + lpos, r); - for (i = gcs ; i > 0; --i) - outc(' '); - if (xn && COL(cp_pos_to_col(llen)+gcs) == 0) - { - outc(' '); - move_left(1); - } - move_cursor(llen + gcs, lpos); - } - else if (pos < lpos) { - l = lpos - pos; /* Buffer characters */ - r = llen - lpos; /* Characters after deleted */ - gcs = -move_cursor(lpos, lpos-l); /* Move back */ - /* Fix up buffer and buffer pointers. */ - if (r > 0) - memmove(lbuf + pos, lbuf + lpos, r * sizeof(Uint32)); - lpos -= l; - llen -= l; - /* Write out characters after, blank the tail and jump back to lpos. */ - write_buf(lbuf + lpos, r); - for (i = gcs ; i > 0; --i) - outc(' '); - if (xn && COL(cp_pos_to_col(llen)+gcs) == 0) - { - outc(' '); - move_left(1); - } - move_cursor(llen + gcs, lpos); - } - return TRUE; -} - -/* Step over n logical characters, check for overflow. */ -static int step_over_chars(int n) -{ - Uint32 *c, *beg, *end; - - beg = lbuf; - end = lbuf + llen; - c = lbuf + lpos; - for ( ; n > 0 && c < end; --n) { - c++; - while (c < end && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0)) - c++; - } - for ( ; n < 0 && c > beg; n++) { - --c; - while (c > beg && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0)) - --c; - } - return c - lbuf; -} - -/* - * Insert n characters into the buffer at lpos. - * Know about pad characters and treat \n specially. - */ - -static int insert_buf(byte *s, int n) -{ - int pos = 0; - int buffpos = lpos; - int ch; - - while (pos < n) { - if ((ch = pick_utf8(s,n,&pos)) < 0) { - /* XXX temporary allow invalid chars */ - ch = (int) s[pos]; - DEBUGLOG(("insert_buf: Invalid UTF8:%d",ch)); - ++pos; - } - if ((utf8_mode && (ch >= 128 || isprint(ch))) || (ch <= 255 && isprint(ch))) { - DEBUGLOG(("insert_buf: Printable(UTF-8):%d",ch)); - lbuf[lpos++] = (Uint32) ch; - } else if (ch >= 128) { /* not utf8 mode */ - int nc = octal_or_hex_positions(ch); - lbuf[lpos++] = ((Uint32) ch) | ESCAPED_TAG; - while (nc--) { - lbuf[lpos++] = ESCAPED_TAG; - } - } else if (ch == '\t') { - do { - lbuf[lpos++] = (CONTROL_TAG | ((Uint32) ch)); - ch = 0; - } while (lpos % 8); - } else if (ch == '\e') { - DEBUGLOG(("insert_buf: ANSI Escape: \\e")); - lbuf[lpos++] = (CONTROL_TAG | ((Uint32) ch)); - } else if (ch == '\n' || ch == '\r') { - write_buf(lbuf + buffpos, lpos - buffpos); - outc('\r'); - if (ch == '\n') - outc('\n'); - if (llen > lpos) { - memmove(lbuf, lbuf + lpos, llen - lpos); - } - llen -= lpos; - lpos = buffpos = 0; - } else { - DEBUGLOG(("insert_buf: Magic(UTF-8):%d",ch)); - lbuf[lpos++] = ch | CONTROL_TAG; - lbuf[lpos++] = CONTROL_TAG; - } - } - return lpos - buffpos; /* characters "written" into - current buffer (may be less due to newline) */ -} - - - -/* - * Write n characters in line buffer starting at s. Be smart about - * non-printables. Know about pad characters and that \n can never - * occur normally. - */ - -static int write_buf(Uint32 *s, int n) -{ - byte ubuf[4]; - int ubytes = 0, i; - byte lastput = ' '; - - update_cols(); - - while (n > 0) { - if (!(*s & TAG_MASK) ) { - if (utf8_mode) { - ubytes = 0; - if (put_utf8((int) *s, ubuf, 4, &ubytes) == 0) { - for (i = 0; i < ubytes; ++i) { - outc(ubuf[i]); - } - lastput = 0; /* Means the last written character was multibyte UTF8 */ - } - } else { - outc((byte) *s); - lastput = (byte) *s; - } - --n; - ++s; - } else if (*s == (CONTROL_TAG | ((Uint32) '\t'))) { - outc(lastput = ' '); - --n; s++; - while (n > 0 && *s == CONTROL_TAG) { - outc(lastput = ' '); - --n; s++; - } - } else if (*s == (CONTROL_TAG | ((Uint32) '\e'))) { - outc(lastput = '\e'); - --n; - ++s; - } else if (*s & CONTROL_TAG) { - outc('^'); - outc(lastput = ((byte) ((*s == 0177) ? '?' : *s | 0x40))); - n -= 2; - s += 2; - } else if (*s & ESCAPED_TAG) { - Uint32 ch = *s & ~(TAG_MASK); - byte *octbuff; - byte octtmp[256]; - int octbytes; - DEBUGLOG(("write_buf: Escaped: %d", ch)); - octbytes = octal_or_hex_positions(ch); - if (octbytes > 256) { - octbuff = driver_alloc(octbytes); - } else { - octbuff = octtmp; - } - octbytes = 0; - octal_or_hex_format(ch, octbuff, &octbytes); - DEBUGLOG(("write_buf: octbytes: %d", octbytes)); - outc('\\'); - for (i = 0; i < octbytes; ++i) { - outc(lastput = octbuff[i]); - DEBUGLOG(("write_buf: outc: %d", (int) lastput)); - } - n -= octbytes+1; - s += octbytes+1; - if (octbuff != octtmp) { - driver_free(octbuff); - } - } else { - DEBUGLOG(("write_buf: Very unexpected character %d",(int) *s)); - ++n; - --s; - } - } - /* Check landed in first column of new line and have 'xn' bug. */ - n = s - lbuf; - if (xn && n != 0 && COL(cp_pos_to_col(n)) == 0) { - if (n >= llen) { - outc(' '); - } else if (lastput == 0) { /* A multibyte UTF8 character */ - for (i = 0; i < ubytes; ++i) { - outc(ubuf[i]); - } - } else { - outc(lastput); - } - move_left(1); - } - return TRUE; -} - - -/* The basic procedure for outputting one character. */ -static int outc(int c) -{ - putcbuf->orig_bytes[putcpos++] = c; - if (putcpos == putclen) { - driver_enq_bin(ttysl_port,putcbuf,0,putclen); - driver_free_binary(putcbuf); - putcpos = 0; - putclen = TTY_BUFFSIZE; - putcbuf = driver_alloc_binary(BUFSIZ); - } - return 1; -} - -static int move_cursor(int from_pos, int to_pos) -{ - int from_col, to_col; - int dc, dl; - update_cols(); - - from_col = cp_pos_to_col(from_pos); - to_col = cp_pos_to_col(to_pos); - - dc = COL(to_col) - COL(from_col); - dl = LINE(to_col) - LINE(from_col); - DEBUGLOG(("move_cursor: from %d %d to %d %d => %d %d\n", - from_pos, from_col, to_pos, to_col, dl, dc)); - if (dl > 0) - move_down(dl); - else if (dl < 0) - move_up(-dl); - if (dc > 0) - move_right(dc); - else if (dc < 0) - move_left(-dc); - return to_col-from_col; -} - -/* - * Returns the length of an ANSI escape code in a buffer, this function only consider - * color escape sequences like `\e[33m` or `\e[21;33m`. If a sequence has no valid - * terminator, the length is equal the number of characters between `\e` and the first - * invalid character, inclusive. - */ - -static int ansi_escape_width(Uint32 *s, int max_length) -{ - int i; - - if (*s != (CONTROL_TAG | ((Uint32) '\e'))) { - return 0; - } else if (max_length <= 1) { - return 1; - } else if (s[1] != '[') { - return 2; - } - - for (i = 2; i < max_length && (s[i] == ';' || (s[i] >= '0' && s[i] <= '9')); i++); - - return i + 1; -} - -static int cp_pos_to_col(int cp_pos) -{ - /* - * If we don't have any character width information. Assume that - * code points are one column wide - */ - int w = 1; - int col = 0; - int i = 0; - int j; - - if (cp_pos > llen) { - col += cp_pos - llen; - cp_pos = llen; - } - - while (i < cp_pos) { - j = ansi_escape_width(lbuf + i, llen - i); - - if (j > 0) { - i += j; - } else { -#ifdef HAVE_WCWIDTH - w = wcwidth(lbuf[i]); -#endif - if (w > 0) { - col += w; - } - i++; - } - } - - return col; -} - -static int start_termcap(void) -{ - int eres; - size_t envsz = 1024; - char *env = NULL; - char *c; - int tres; - - DEBUGLOG(("start_termcap: ..")); - - capbuf = driver_alloc(1024); - if (!capbuf) - goto termcap_false; - eres = erl_drv_getenv("TERM", capbuf, &envsz); - if (eres == 0) - env = capbuf; - else if (eres < 0) { - DEBUGLOG(("start_termcap: failure in erl_drv_getenv(\"TERM\", ..) = %d\n", eres)); - goto termcap_false; - } else /* if (eres > 1) */ { - char *envbuf = driver_alloc(envsz); - if (!envbuf) - goto termcap_false; - while (1) { - char *newenvbuf; - eres = erl_drv_getenv("TERM", envbuf, &envsz); - if (eres == 0) - break; - newenvbuf = driver_realloc(envbuf, envsz); - if (eres < 0 || !newenvbuf) { - DEBUGLOG(("start_termcap: failure in erl_drv_getenv(\"TERM\", ..) = %d or realloc buf == %p\n", eres, newenvbuf)); - env = newenvbuf ? newenvbuf : envbuf; - goto termcap_false; - } - envbuf = newenvbuf; - } - env = envbuf; - } - if ((tres = tgetent((char*)lbuf, env)) <= 0) { - DEBUGLOG(("start_termcap: failure in tgetent(..) = %d\n", tres)); - goto termcap_false; - } - if (env != capbuf) { - env = NULL; - driver_free(env); - } - c = capbuf; - cols = tgetnum("co"); - if (cols <= 0) - cols = DEF_WIDTH; - xn = tgetflag("xn"); - up = tgetstr("up", &c); - if (!(down = tgetstr("do", &c))) - down = "\n"; - if (!(left = tgetflag("bs") ? "\b" : tgetstr("bc", &c))) - left = "\b"; /* Can't happen - but does on Solaris 2 */ - right = tgetstr("nd", &c); - if (up && down && left && right) { - DEBUGLOG(("start_termcap: successful start\n")); - return TRUE; - } - DEBUGLOG(("start_termcap: failed start\n")); - termcap_false: - if (env && env != capbuf) - driver_free(env); - if (capbuf) - driver_free(capbuf); - capbuf = NULL; - return FALSE; -} - -static int stop_termcap(void) -{ - if (capbuf) driver_free(capbuf); - capbuf = NULL; - return TRUE; -} - -static int move_left(int n) -{ - while (n-- > 0) - tputs(left, 1, outc); - return TRUE; -} - -static int move_right(int n) -{ - while (n-- > 0) - tputs(right, 1, outc); - return TRUE; -} - -static int move_up(int n) -{ - while (n-- > 0) - tputs(up, 1, outc); - return TRUE; -} - -static int move_down(int n) -{ - while (n-- > 0) - tputs(down, 1, outc); - return TRUE; -} - - -/* - * Updates cols if terminal has resized (SIGWINCH). Should be called - * at the start of any function that uses the COL or LINE macros. If - * the terminal is resized after calling this function but before use - * of the macros, then we may write to the wrong screen location. - * - * We cannot call this from the SIGWINCH handler because it uses - * ioctl() which is not a safe function as listed in the signal(7) - * man page. - */ -static void update_cols(void) -{ - Uint32 width, height; - - if (cols_needs_update) { - cols_needs_update = FALSE; - ttysl_get_window_size(&width, &height); - cols = width; - } -} - - -/* - * Put a terminal device into non-canonical mode with ECHO off. - * Before doing so we first save the terminal's current mode, - * assuming the caller will call the tty_reset() function - * (also in this file) when it's done with raw mode. - */ - -static struct termios tty_smode, tty_rmode; - -static int tty_init(int fd, int canon, int echo, int sig) { - int tres; - DEBUGLOG(("tty_init: fd = %d, canon = %d, echo = %d, sig = %d", fd, canon, echo, sig)); - if ((tres = tcgetattr(fd, &tty_rmode)) < 0) { - DEBUGLOG(("tty_init: failure in tcgetattr(%d,..) = %d\n", fd, tres)); - return -1; - } - tty_smode = tty_rmode; - - /* Default characteristics for all usage including termcap output. */ - tty_smode.c_iflag &= ~ISTRIP; - - /* Turn canonical (line mode) on off. */ - if (canon > 0) { - tty_smode.c_iflag |= ICRNL; - tty_smode.c_lflag |= ICANON; - tty_smode.c_oflag |= OPOST; - tty_smode.c_cc[VEOF] = tty_rmode.c_cc[VEOF]; -#ifdef VDSUSP - tty_smode.c_cc[VDSUSP] = tty_rmode.c_cc[VDSUSP]; -#endif - } - if (canon < 0) { - tty_smode.c_iflag &= ~ICRNL; - tty_smode.c_lflag &= ~ICANON; - tty_smode.c_oflag &= ~OPOST; - /* Must get these really right or funny effects can occur. */ - tty_smode.c_cc[VMIN] = 1; - tty_smode.c_cc[VTIME] = 0; -#ifdef VDSUSP - tty_smode.c_cc[VDSUSP] = 0; -#endif - } - - /* Turn echo on or off. */ - if (echo > 0) - tty_smode.c_lflag |= ECHO; - if (echo < 0) - tty_smode.c_lflag &= ~ECHO; - - /* Set extra characteristics for "RAW" mode, no signals. */ - if (sig > 0) { - /* Ignore IMAXBEL as not POSIX. */ -#ifndef QNX - tty_smode.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON|IXANY); -#else - tty_smode.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON); -#endif - tty_smode.c_lflag |= (ISIG|IEXTEN); - } - if (sig < 0) { - /* Ignore IMAXBEL as not POSIX. */ -#ifndef QNX - tty_smode.c_iflag &= ~(BRKINT|IGNPAR|ICRNL|IXON|IXANY); -#else - tty_smode.c_iflag &= ~(BRKINT|IGNPAR|ICRNL|IXON); -#endif - tty_smode.c_lflag &= ~(ISIG|IEXTEN); - } - DEBUGLOG(("tty_init: successful init\n")); - return 0; -} - -/* - * Set/restore a terminal's mode to whatever it was on the most - * recent call to the tty_init() function above. - */ - -static int tty_set(int fd) -{ - int tres; - DEBUGF(("tty_set: Setting tty...\n")); - - if ((tres = tcsetattr(fd, TCSANOW, &tty_smode)) < 0) { - DEBUGLOG(("tty_set: failure in tcgetattr(%d,..) = %d\n", fd, tres)); - return(-1); - } - return(0); -} - -static int tty_reset(int fd) /* of terminal device */ -{ - int tres; - DEBUGF(("tty_reset: Resetting tty...\n")); - - if ((tres = tcsetattr(fd, TCSANOW, &tty_rmode)) < 0) { - DEBUGLOG(("tty_reset: failure in tcsetattr(%d,..) = %d\n", fd, tres)); - return(-1); - } - return(0); -} - -/* - * Signal handler to cope with signals so that we can reset the tty - * to the orignal settings - */ - -#ifdef ERTS_NOT_USED -/* XXX: A mistake that it isn't used, or should it be removed? */ - -static RETSIGTYPE suspend(int sig) -{ - if (tty_reset(ttysl_fd) < 0) { - DEBUGLOG(("signal: failure in suspend(%d), can't reset tty %d\n", sig, ttysl_fd)); - fprintf(stderr,"Can't reset tty \n"); - exit(1); - } - - sys_signal(sig, SIG_DFL); /* Set signal handler to default */ - sys_sigrelease(sig); /* Allow 'sig' to come through */ - kill(getpid(), sig); /* Send ourselves the signal */ - sys_sigblock(sig); /* Reset to old mask */ - sys_signal(sig, suspend); /* Reset signal handler */ - - if (tty_set(ttysl_fd) < 0) { - DEBUGLOG(("signal: failure in suspend(%d), can't set tty %d\n", sig, ttysl_fd)); - fprintf(stderr,"Can't set tty raw \n"); - exit(1); - } -} - -#endif - -static RETSIGTYPE cont(int sig) -{ - if (tty_set(ttysl_fd) < 0) { - DEBUGLOG(("signal: failure in cont(%d), can't set tty raw %d\n", sig, ttysl_fd)); - fprintf(stderr,"Can't set tty raw\n"); - exit(1); - } -} - -static RETSIGTYPE winch(int sig) -{ - cols_needs_update = TRUE; -} -#endif /* HAVE_TERMCAP */ diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c deleted file mode 100644 index 8d5968276694..000000000000 --- a/erts/emulator/drivers/win32/ttsl_drv.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2020. 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% - */ -/* - * Tty driver that reads one character at the time and provides a - * smart line for output. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys.h" -#include -#include -#include -#include -#include - -#include "erl_driver.h" -#include "win_con.h" - -#define TRUE 1 -#define FALSE 0 - -static int cols; /* Number of columns available. */ -static int rows; /* Number of rows available. */ - -/* The various opcodes. */ -#define OP_PUTC 0 -#define OP_MOVE 1 -#define OP_INSC 2 -#define OP_DELC 3 -#define OP_BEEP 4 -#define OP_PUTC_SYNC 5 - -/* Control op */ -#define CTRL_OP_GET_WINSIZE 100 -#define CTRL_OP_GET_UNICODE_STATE 101 -#define CTRL_OP_SET_UNICODE_STATE 102 - -static int lbuf_size = BUFSIZ; -Uint32 *lbuf; /* The current line buffer */ -int llen; /* The current line length */ -int lpos; /* The current "cursor position" in the line buffer */ - -/* - * Tags used in line buffer to show that these bytes represent special characters, - * Max unicode is 0x0010ffff, so we have lots of place for meta tags... - */ -#define CONTROL_TAG 0x10000000U /* Control character, value in first position */ -#define ESCAPED_TAG 0x01000000U /* Escaped character, value in first position */ -#define TAG_MASK 0xFF000000U - -#define MAXSIZE (1 << 16) - -#define ISPRINT(c) (isprint(c) || (128+32 <= (c) && (c) < 256)) - -#define DEBUGLOG(X) /* nothing */ - -/* - * XXX These are used by win_con.c (for command history). - * Should be cleaned up. - */ - - -#define NL '\n' - -/* Main interface functions. */ -static int ttysl_init(void); -static ErlDrvData ttysl_start(ErlDrvPort, char*); -static void ttysl_stop(ErlDrvData); -static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int, - char *, ErlDrvSizeT, char **, ErlDrvSizeT); -static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT); -static void ttysl_from_tty(ErlDrvData, ErlDrvEvent); -static Sint16 get_sint16(char *s); - -static ErlDrvPort ttysl_port; - -extern ErlDrvEvent console_input_event; -extern HANDLE console_thread; - -static HANDLE ttysl_in = INVALID_HANDLE_VALUE; /* Handle for console input. */ -static HANDLE ttysl_out = INVALID_HANDLE_VALUE; /* Handle for console output */ - -/* Functions that work on the line buffer. */ -static int start_lbuf(); -static int stop_lbuf(); -static int put_chars(); -static int move_rel(); -static int ins_chars(); -static int del_chars(); -static int step_over_chars(int n); -static int insert_buf(); -static int write_buf(); -static void move_cursor(int, int); - -/* Define the driver table entry. */ -struct erl_drv_entry ttsl_driver_entry = { - ttysl_init, - ttysl_start, - ttysl_stop, - ttysl_from_erlang, - ttysl_from_tty, - NULL, - "tty_sl", - NULL, - NULL, - ttysl_control, - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, - NULL, - NULL, - NULL, -}; - -static int utf8_mode = 0; - -static int ttysl_init() -{ - lbuf = NULL; /* For line buffer handling */ - ttysl_port = (ErlDrvPort)-1; - return 0; -} - -static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) -{ - if ((SWord)ttysl_port != -1 || console_thread == NULL) { - return ERL_DRV_ERROR_GENERAL; - } - start_lbuf(); - utf8_mode = 1; - driver_select(port, console_input_event, ERL_DRV_READ, 1); - ttysl_port = port; - return (ErlDrvData)ttysl_port;/* Nothing important to return */ -} - -#define DEF_HEIGHT 24 -#define DEF_WIDTH 80 - -static void ttysl_get_window_size(Uint32 *width, Uint32 *height) -{ - *width = ConGetColumns(); - *height = ConGetRows(); -} - - -static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, - unsigned int command, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - char resbuff[2*sizeof(Uint32)]; - ErlDrvSizeT res_size; - - command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER; - switch (command) { - case CTRL_OP_GET_WINSIZE: - { - Uint32 w,h; - ttysl_get_window_size(&w,&h); - memcpy(resbuff,&w,sizeof(Uint32)); - memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32)); - res_size = 2*sizeof(Uint32); - } - break; - case CTRL_OP_GET_UNICODE_STATE: - *resbuff = (utf8_mode) ? 1 : 0; - res_size = 1; - break; - case CTRL_OP_SET_UNICODE_STATE: - if (len != 0) { - int m = (int) *buf; - *resbuff = (utf8_mode) ? 1 : 0; - res_size = 1; - utf8_mode = (m) ? 1 : 0; - } else { - return 0; - } - break; - default: - return -1; - } - if (rlen < res_size) { - *rbuf = driver_alloc(res_size); - } - memcpy(*rbuf,resbuff,res_size); - return res_size; -} - - -static void ttysl_stop(ErlDrvData ttysl_data) -{ - if ((SWord)ttysl_port != -1) { - driver_select(ttysl_port, console_input_event, ERL_DRV_READ, 0); - } - - ttysl_in = ttysl_out = INVALID_HANDLE_VALUE; - stop_lbuf(); - ttysl_port = (ErlDrvPort)-1; -} - -static int put_utf8(int ch, byte *target, int sz, int *pos) -{ - Uint x = (Uint) ch; - if (x < 0x80) { - if (*pos >= sz) { - return -1; - } - target[(*pos)++] = (byte) x; - } - else if (x < 0x800) { - if (((*pos) + 1) >= sz) { - return -1; - } - target[(*pos)++] = (((byte) (x >> 6)) | - ((byte) 0xC0)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else if (x < 0x10000) { - if ((x >= 0xD800 && x <= 0xDFFF) || - (x == 0xFFFE) || - (x == 0xFFFF)) { /* Invalid unicode range */ - return -1; - } - if (((*pos) + 2) >= sz) { - return -1; - } - - target[(*pos)++] = (((byte) (x >> 12)) | - ((byte) 0xE0)); - target[(*pos)++] = ((((byte) (x >> 6)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else if (x < 0x110000) { /* Standard imposed max */ - if (((*pos) + 3) >= sz) { - return -1; - } - target[(*pos)++] = (((byte) (x >> 18)) | - ((byte) 0xF0)); - target[(*pos)++] = ((((byte) (x >> 12)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = ((((byte) (x >> 6)) & 0x3F) | - ((byte) 0x80)); - target[(*pos)++] = (((byte) (x & 0x3F)) | - ((byte) 0x80)); - } else { - return -1; - } - return 0; -} - - -static int pick_utf8(byte *s, int sz, int *pos) -{ - int size = sz - (*pos); - byte *source; - Uint unipoint; - - if (size > 0) { - source = s + (*pos); - if (((*source) & ((byte) 0x80)) == 0) { - unipoint = (int) *source; - ++(*pos); - return (int) unipoint; - } else if (((*source) & ((byte) 0xE0)) == 0xC0) { - if (size < 2) { - return -2; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((*source) < 0xC2) /* overlong */) { - return -1; - } - (*pos) += 2; - unipoint = - (((Uint) ((*source) & ((byte) 0x1F))) << 6) | - ((Uint) (source[1] & ((byte) 0x3F))); - return (int) unipoint; - } else if (((*source) & ((byte) 0xF0)) == 0xE0) { - if (size < 3) { - return -2; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((source[2] & ((byte) 0xC0)) != 0x80) || - (((*source) == 0xE0) && (source[1] < 0xA0)) /* overlong */ ) { - return -1; - } - if ((((*source) & ((byte) 0xF)) == 0xD) && - ((source[1] & 0x20) != 0)) { - return -1; - } - if (((*source) == 0xEF) && (source[1] == 0xBF) && - ((source[2] == 0xBE) || (source[2] == 0xBF))) { - return -1; - } - (*pos) += 3; - unipoint = - (((Uint) ((*source) & ((byte) 0xF))) << 12) | - (((Uint) (source[1] & ((byte) 0x3F))) << 6) | - ((Uint) (source[2] & ((byte) 0x3F))); - return (int) unipoint; - } else if (((*source) & ((byte) 0xF8)) == 0xF0) { - if (size < 4) { - return -2 ; - } - if (((source[1] & ((byte) 0xC0)) != 0x80) || - ((source[2] & ((byte) 0xC0)) != 0x80) || - ((source[3] & ((byte) 0xC0)) != 0x80) || - (((*source) == 0xF0) && (source[1] < 0x90)) /* overlong */) { - return -1; - } - if ((((*source) & ((byte)0x7)) > 0x4U) || - ((((*source) & ((byte)0x7)) == 0x4U) && - ((source[1] & ((byte)0x3F)) > 0xFU))) { - return -1; - } - (*pos) += 4; - unipoint = - (((Uint) ((*source) & ((byte) 0x7))) << 18) | - (((Uint) (source[1] & ((byte) 0x3F))) << 12) | - (((Uint) (source[2] & ((byte) 0x3F))) << 6) | - ((Uint) (source[3] & ((byte) 0x3F))); - return (int) unipoint; - } else { - return -1; - } - } else { - return -1; - } -} - -static int octal_or_hex_positions(Uint c) -{ - int x = 0; - Uint ch = c; - if (!ch) { - return 1; - } - while(ch) { - ++x; - ch >>= 3; - } - if (x <= 3) { - return 3; - } - /* \x{H ...} format when larger than \777 */ - x = 0; - ch = c; - while(ch) { - ++x; - ch >>= 4; - } - return x+3; -} - -static void octal_or_hex_format(Uint ch, byte *buf, int *pos) -{ - static byte hex_chars[] = { '0','1','2','3','4','5','6','7','8','9', - 'A','B','C','D','E','F'}; - int num = octal_or_hex_positions(ch); - if (num != 3) { - buf[(*pos)++] = 'x'; - buf[(*pos)++] = '{'; - num -= 3; - while(num--) { - buf[(*pos)++] = hex_chars[((ch >> (4*num)) & 0xFU)]; - } - buf[(*pos)++] = '}'; - } else { - while(num--) { - buf[(*pos)++] = ((byte) ((ch >> (3*num)) & 0x7U) + '0'); - } - } -} - -/* - * Check that there is enough room in all buffers to copy all pad chars - * and stiff we need If not, realloc lbuf. - */ -static int check_buf_size(byte *s, int n) -{ - int pos = 0; - int ch; - int size = 10; - - while(pos < n) { - /* Indata is always UTF-8 */ - if ((ch = pick_utf8(s,n,&pos)) < 0) { - /* XXX temporary allow invalid chars */ - ch = (int) s[pos]; - DEBUGLOG(("Invalid UTF8:%d",ch)); - ++pos; - } - if (utf8_mode) { /* That is, terminal is UTF8 compliant */ - if (ch >= 128 || isprint(ch)) { - DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch)); - size++; /* Buffer contains wide characters... */ - } else if (ch == '\t') { - size += 8; - } else { - DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch)); - size += 2; - } - } else { - if (ch <= 255 && isprint(ch)) { - DEBUGLOG(("Printable:%d",ch)); - size++; - } else if (ch == '\t') - size += 8; - else if (ch >= 128) { - DEBUGLOG(("Non printable:%d",ch)); - size += (octal_or_hex_positions(ch) + 1); - } - else { - DEBUGLOG(("Magic:%d",ch)); - size += 2; - } - } - } - - if (size + lpos >= lbuf_size) { - - lbuf_size = size + lpos + BUFSIZ; - if ((lbuf = driver_realloc(lbuf, lbuf_size * sizeof(Uint32))) == NULL) { - driver_failure(ttysl_port, -1); - return(0); - } - } - return(1); -} - - -static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count) -{ - if (lpos > MAXSIZE) - put_chars((byte*)"\n", 1); - - switch (buf[0]) { - case OP_PUTC: - case OP_PUTC_SYNC: - DEBUGLOG(("OP: Putc(%I64u)",(unsigned long long)count-1)); - if (check_buf_size((byte*)buf+1, count-1) == 0) - return; - put_chars((byte*)buf+1, count-1); - break; - case OP_MOVE: - move_rel(get_sint16(buf+1)); - break; - case OP_INSC: - if (check_buf_size((byte*)buf+1, count-1) == 0) - return; - ins_chars((byte*)buf+1, count-1); - break; - case OP_DELC: - del_chars(get_sint16(buf+1)); - break; - case OP_BEEP: - ConBeep(); - break; - default: - /* Unknown op, just ignore. */ - break; - } - - if (buf[0] == OP_PUTC_SYNC) { - /* On windows we do a blocking write to the tty so we just - send the ack immidiately. If at some point in the future - someone has a problem with tty output being blocking - this has to be changed. */ - ErlDrvTermData spec[] = { - ERL_DRV_PORT, driver_mk_port(ttysl_port), - ERL_DRV_ATOM, driver_mk_atom("ok"), - ERL_DRV_TUPLE, 2 - }; - erl_drv_output_term(driver_mk_port(ttysl_port), spec, - sizeof(spec) / sizeof(spec[0])); - } - return; -} - -extern int read_inbuf(char *data, int n); - -static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) -{ - Uint32 inbuf[64]; - byte t[1024]; - int i,pos,tpos; - - i = ConReadInput(inbuf,1); - - pos = 0; - tpos = 0; - - while (pos < i) { - while (tpos < 1020 && pos < i) { /* Max 4 bytes for UTF8 */ - put_utf8((int) inbuf[pos++], t, 1024, &tpos); - } - driver_output(ttysl_port, (char *) t, tpos); - tpos = 0; - } -} - -/* - * Gets signed 16 bit integer from binary buffer. - */ -static Sint16 -get_sint16(char *s) -{ - return ((*s << 8) | ((byte*)s)[1]); -} - - -static int start_lbuf(void) -{ - if (!lbuf && !(lbuf = ( Uint32*) driver_alloc(lbuf_size * sizeof(Uint32)))) - return FALSE; - llen = 0; - lpos = 0; - return TRUE; -} - -static int stop_lbuf(void) -{ - if (lbuf) { - driver_free(lbuf); - lbuf = NULL; - } - llen = 0; /* To avoid access error in win_con:AddToCmdHistory during exit*/ - return TRUE; -} - -/* Put l bytes (in UTF8) from s into the buffer and output them. */ -static int put_chars(byte *s, int l) -{ - int n; - - n = insert_buf(s, l); - if (n > 0) - write_buf(lbuf + lpos - n, n); - if (lpos > llen) - llen = lpos; - return TRUE; -} - -/* - * Move the current postition forwards or backwards within the current - * line. We know about padding. - */ -static int move_rel(int n) -{ - int npos; /* The new position */ - - /* Step forwards or backwards over the buffer. */ - npos = step_over_chars(n); - - /* Calculate move, updates pointers and move the cursor. */ - move_cursor(lpos, npos); - lpos = npos; - return TRUE; -} - -/* Insert characters into the buffer at the current position. */ -static int ins_chars(byte *s, int l) -{ - int n, tl; - Uint32 *tbuf = NULL; /* Suppress warning about use-before-set */ - - /* Move tail of buffer to make space. */ - if ((tl = llen - lpos) > 0) { - if ((tbuf = driver_alloc(tl * sizeof(Uint32))) == NULL) - return FALSE; - memcpy(tbuf, lbuf + lpos, tl * sizeof(Uint32)); - } - n = insert_buf(s, l); - if (tl > 0) { - memcpy(lbuf + lpos, tbuf, tl * sizeof(Uint32)); - driver_free(tbuf); - } - llen += n; - write_buf(lbuf + (lpos - n), llen - (lpos - n)); - move_cursor(llen, lpos); - return TRUE; -} - -/* - * Delete characters in the buffer. Can delete characters before (n < 0) - * and after (n > 0) the current position. Cursor left at beginning of - * deleted block. - */ -static int del_chars(int n) -{ - int i, l, r; - int pos; - - /*update_cols();*/ - - /* Step forward or backwards over n logical characters. */ - pos = step_over_chars(n); - - if (pos > lpos) { - l = pos - lpos; /* Buffer characters to delete */ - r = llen - lpos - l; /* Characters after deleted */ - /* Fix up buffer and buffer pointers. */ - if (r > 0) - memcpy(lbuf + lpos, lbuf + pos, r * sizeof(Uint32)); - llen -= l; - /* Write out characters after, blank the tail and jump back to lpos. */ - write_buf(lbuf + lpos, r); - for (i = l ; i > 0; --i) - ConPutChar(' '); - move_cursor(llen + l, lpos); - } - else if (pos < lpos) { - l = lpos - pos; /* Buffer characters */ - r = llen - lpos; /* Characters after deleted */ - move_cursor(lpos, lpos-l); /* Move back */ - /* Fix up buffer and buffer pointers. */ - if (r > 0) - memcpy(lbuf + pos, lbuf + lpos, r * sizeof(Uint32)); - lpos -= l; - llen -= l; - /* Write out characters after, blank the tail and jump back to lpos. */ - write_buf(lbuf + lpos, r); - for (i = l ; i > 0; --i) - ConPutChar(' '); - move_cursor(llen + l, lpos); - } - return TRUE; -} - - -/* Step over n logical characters, check for overflow. */ -static int step_over_chars(int n) -{ - Uint32 *c, *beg, *end; - - beg = lbuf; - end = lbuf + llen; - c = lbuf + lpos; - for ( ; n > 0 && c < end; --n) { - c++; - while (c < end && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0)) - c++; - } - for ( ; n < 0 && c > beg; n++) { - --c; - while (c > beg && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0)) - --c; - } - return c - lbuf; -} - -static int insert_buf(byte *s, int n) -{ - int pos = 0; - int buffpos = lpos; - int ch; - - while (pos < n) { - if ((ch = pick_utf8(s,n,&pos)) < 0) { - /* XXX temporary allow invalid chars */ - ch = (int) s[pos]; - DEBUGLOG(("insert_buf: Invalid UTF8:%d",ch)); - ++pos; - } - if ((utf8_mode && (ch >= 128 || isprint(ch))) || (ch <= 255 && isprint(ch))) { - DEBUGLOG(("insert_buf: Printable(UTF-8):%d",ch)); - lbuf[lpos++] = (Uint32) ch; - } else if (ch >= 128) { /* not utf8 mode */ - int nc = octal_or_hex_positions(ch); - lbuf[lpos++] = ((Uint32) ch) | ESCAPED_TAG; - while (nc--) { - lbuf[lpos++] = ESCAPED_TAG; - } - } else if (ch == '\t') { - do { - lbuf[lpos++] = (CONTROL_TAG | ((Uint32) ch)); - ch = 0; - } while (lpos % 8); - } else if (ch == '\n' || ch == '\r') { - write_buf(lbuf + buffpos, lpos - buffpos); - ConPutChar('\r'); - if (ch == '\n') - ConPutChar('\n'); - if (llen > lpos) { - memcpy(lbuf, lbuf + lpos, llen - lpos); - } - llen -= lpos; - lpos = buffpos = 0; - } else { - DEBUGLOG(("insert_buf: Magic(UTF-8):%d",ch)); - lbuf[lpos++] = ch | CONTROL_TAG; - lbuf[lpos++] = CONTROL_TAG; - } - } - return lpos - buffpos; /* characters "written" into - current buffer (may be less due to newline) */ -} -static int write_buf(Uint32 *s, int n) -{ - int i; - - /*update_cols();*/ - - while (n > 0) { - if (!(*s & TAG_MASK) ) { - ConPutChar(*s); - --n; - ++s; - } - else if (*s == (CONTROL_TAG | ((Uint32) '\t'))) { - ConPutChar(' '); - --n; s++; - while (n > 0 && *s == CONTROL_TAG) { - ConPutChar(' '); - --n; s++; - } - } else if (*s & CONTROL_TAG) { - ConPutChar('^'); - ConPutChar((*s == 0177) ? '?' : *s | 0x40); - n -= 2; - s += 2; - } else if (*s & ESCAPED_TAG) { - Uint32 ch = *s & ~(TAG_MASK); - byte *octbuff; - byte octtmp[256]; - int octbytes; - DEBUGLOG(("Escaped: %d", ch)); - octbytes = octal_or_hex_positions(ch); - if (octbytes > 256) { - octbuff = driver_alloc(octbytes); - } else { - octbuff = octtmp; - } - octbytes = 0; - octal_or_hex_format(ch, octbuff, &octbytes); - DEBUGLOG(("octbytes: %d", octbytes)); - ConPutChar('\\'); - for (i = 0; i < octbytes; ++i) { - ConPutChar(octbuff[i]); - } - n -= octbytes+1; - s += octbytes+1; - if (octbuff != octtmp) { - driver_free(octbuff); - } - } else { - DEBUGLOG(("Very unexpected character %d",(int) *s)); - ++n; - --s; - } - } - return TRUE; -} - - -static void -move_cursor(int from, int to) -{ - ConSetCursor(from,to); -} diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c deleted file mode 100644 index e0bc1fde05dd..000000000000 --- a/erts/emulator/drivers/win32/win_con.c +++ /dev/null @@ -1,2355 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2021. 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% - */ - -#define UNICODE 1 -#define _UNICODE 1 -#include -#include -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys.h" -#include -#include "resource.h" -#include "erl_version.h" -#include -#include -#include "erl_driver.h" -#include "win_con.h" - -#define ALLOC(X) malloc(X) -#define REALLOC(X,Y) realloc(X,Y) -#define FREE(X) free(X) - -#if SIZEOF_VOID_P == 8 -#define WIN64 1 -#ifndef GCL_HBRBACKGROUND -#define GCL_HBRBACKGROUND GCLP_HBRBACKGROUND -#endif -#define DIALOG_PROC_RET INT_PTR -#define CF_HOOK_RET INT_PTR -#define CC_HOOK_RET INT_PTR -#define OFN_HOOK_RET INT_PTR -#else -#define DIALOG_PROC_RET BOOL -#define CF_HOOK_RET UINT -#define CC_HOOK_RET UINT -#define OFN_HOOK_RET UINT -#endif - - -#ifndef STATE_SYSTEM_INVISIBLE -/* Mingw problem with oleacc.h and WIN32_LEAN_AND_MEAN */ -#define STATE_SYSTEM_INVISIBLE 0x00008000 -#endif - -#define WM_CONTEXT (0x0401) -#define WM_CONBEEP (0x0402) -#define WM_SAVE_PREFS (0x0403) - -#define USER_KEY TEXT("Software\\Ericsson\\Erlang\\") TEXT(ERLANG_VERSION) - -#define FRAME_HEIGHT ((2*GetSystemMetrics(SM_CYEDGE))+(2*GetSystemMetrics(SM_CYFRAME))+GetSystemMetrics(SM_CYCAPTION)) -#define FRAME_WIDTH (2*GetSystemMetrics(SM_CXFRAME)+(2*GetSystemMetrics(SM_CXFRAME))+GetSystemMetrics(SM_CXVSCROLL)) - -#define LINE_LENGTH canvasColumns -#define COL(_l) ((_l) % LINE_LENGTH) -#define LINE(_l) ((_l) / LINE_LENGTH) - -#ifdef UNICODE -/* - * We use a character in the invalid unicode range - */ -#define SET_CURSOR (0xD8FF) -#else -/* - * XXX There is no escape to send a character 0x80. Fortunately, - * the ttsl driver currently replaces 0x80 with an octal sequence. - */ -#define SET_CURSOR (0x80) -#endif - -#define SCAN_CODE_BREAK 0x46 /* scan code for Ctrl-Break */ - - -typedef struct ScreenLine_s { - struct ScreenLine_s* next; - struct ScreenLine_s* prev; - int width; -#ifdef HARDDEBUG - int allocated; -#endif - int newline; /* Ends with hard newline: 1, wrapped at end: 0 */ - TCHAR *text; -} ScreenLine_t; - -extern Uint32 *lbuf; /* The current line buffer */ -extern int llen; /* The current line length */ -extern int lpos; - -HANDLE console_input_event; -HANDLE console_thread = NULL; - -#define DEF_CANVAS_COLUMNS 80 -#define DEF_CANVAS_ROWS 26 - -#define BUFSIZE 4096 -#define MAXBUFSIZE 32768 -typedef struct { - TCHAR *data; - int size; - int wrPos; - int rdPos; -} buffer_t; - -static buffer_t inbuf; -static buffer_t outbuf; - -static CHOOSEFONT cf; - -static TCHAR szFrameClass[] = TEXT("FrameClass"); -static TCHAR szClientClass[] = TEXT("ClientClass"); -static HWND hFrameWnd; -static HWND hClientWnd; -static HWND hTBWnd; -static HWND hComboWnd; -static HANDLE console_input; -static HANDLE console_output; -static int cxChar,cyChar, cxCharMax; -static int cxClient,cyClient; -static int cyToolBar; -static int iVscrollPos,iHscrollPos; -static int iVscrollMax,iHscrollMax; -static int nBufLines; -static int cur_x; -static int cur_y; -static int canvasColumns = DEF_CANVAS_COLUMNS; -static int canvasRows = DEF_CANVAS_ROWS; -static ScreenLine_t *buffer_top,*buffer_bottom; -static ScreenLine_t* cur_line; -static POINT editBeg,editEnd; -static BOOL fSelecting = FALSE; -static BOOL fTextSelected = FALSE; -static HKEY key; -static BOOL has_key = FALSE; -static LOGFONT logfont; -static DWORD fgColor; -static DWORD bkgColor; -static FILE *logfile = NULL; -static RECT winPos; -static BOOL toolbarVisible; -static BOOL destroyed = FALSE; - -static int lines_to_save = 10000; /* Maximum number of screen lines to save. */ - -#define TITLE_BUF_SZ 256 - -struct title_buf { - TCHAR *name; - TCHAR buf[TITLE_BUF_SZ]; -}; - -static TCHAR *erlang_window_title = TEXT("Erlang"); - -static unsigned __stdcall ConThreadInit(LPVOID param); -static LRESULT CALLBACK ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); -static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); -static DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); -static ScreenLine_t *ConNewLine(void); -static void DeleteTopLine(void); -static void ensure_line_below(void); -static ScreenLine_t *GetLineFromY(int y); -static void LoadUserPreferences(void); -static void SaveUserPreferences(void); -static void set_scroll_info(HWND hwnd); -static void ConCarriageFeed(int); -static void ConScrollScreen(void); -static BOOL ConChooseFont(HWND hwnd); -static void ConFontInitialize(HWND hwnd); -static void ConSetFont(HWND hwnd); -static void ConChooseColor(HWND hwnd); -static void DrawSelection(HWND hwnd, POINT pt1, POINT pt2); -static void InvertSelectionArea(HWND hwnd); -static void OnEditCopy(HWND hwnd); -static void OnEditPaste(HWND hwnd); -static void OnEditSelAll(HWND hwnd); -static void GetFileName(HWND hwnd, TCHAR *pFile); -static void OpenLogFile(HWND hwnd); -static void CloseLogFile(HWND hwnd); -static void LogFileWrite(TCHAR *buf, int n); -static int write_inbuf(TCHAR *data, int n); -static void init_buffers(void); -static void AddToCmdHistory(void); -static int write_outbuf(TCHAR *data, int num_chars); -static void ConDrawText(HWND hwnd); -static BOOL (WINAPI *ctrl_handler)(DWORD); -static HWND InitToolBar(HWND hwndParent); -static void window_title(struct title_buf *); -static void free_window_title(struct title_buf *); -static void Client_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags); - -#ifdef HARDDEBUG -/* For really hard GUI startup debugging, place DEBUGBOX() macros in code - and get modal message boxes with the line number. */ -static void debug_box(int line) { - TCHAR buff[1024]; - swprintf(buff,1024,TEXT("DBG:%d"),line); - MessageBox(NULL,buff,TEXT("DBG"),MB_OK|MB_APPLMODAL); -} - -#define DEBUGBOX() debug_box(__LINE__) -#endif - -#define CON_VPRINTF_BUF_INC_SIZE 1024 - -static erts_dsprintf_buf_t * -grow_con_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need) -{ - char *buf; - size_t size; - - ASSERT(dsbufp); - - if (!dsbufp->str) { - size = (((need + CON_VPRINTF_BUF_INC_SIZE - 1) - / CON_VPRINTF_BUF_INC_SIZE) - * CON_VPRINTF_BUF_INC_SIZE); - buf = (char *) ALLOC(size * sizeof(char)); - } - else { - size_t free_size = dsbufp->size - dsbufp->str_len; - - if (need <= free_size) - return dsbufp; - - size = need - free_size + CON_VPRINTF_BUF_INC_SIZE; - size = (((size + CON_VPRINTF_BUF_INC_SIZE - 1) - / CON_VPRINTF_BUF_INC_SIZE) - * CON_VPRINTF_BUF_INC_SIZE); - size += dsbufp->size; - buf = (char *) REALLOC((void *) dsbufp->str, - size * sizeof(char)); - } - if (!buf) - return NULL; - if (buf != dsbufp->str) - dsbufp->str = buf; - dsbufp->size = size; - return dsbufp; -} - -static int con_vprintf(char *format, va_list arg_list) -{ - int res,i; - erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_con_vprintf_buf); - res = erts_vdsprintf(&dsbuf, format, arg_list); - if (res >= 0) { - TCHAR *tmp = ALLOC(dsbuf.str_len*sizeof(TCHAR)); - for (i=0;iwidth < xpos) { - return (canvasColumns-hscroll)*cxChar; - } - /* Not needed (?): SelectObject(hdc,CreateFontIndirect(&logfont)); */ - if (GetTextExtentPoint32(hdc,pLine->text,xpos,&size)) { -#ifdef HARDDEBUG - fprintf(stderr,"size.cx:%d\n",(int)size.cx); - fflush(stderr); -#endif - if (hscrollPix >= size.cx) { - return 0; - } - return ((int) size.cx) - hscrollPix; - } else { - return (xpos-hscroll)*cxChar; - } -} - -static int GetXFromCurrentY(HDC hdc, int hscroll, int xpos) { - return GetXFromLine(hdc, hscroll, xpos, GetLineFromY(cur_y)); -} - -void ConSetCursor(int from, int to) -{ TCHAR cmd[9]; - int *p; - //DebugBreak(); - cmd[0] = SET_CURSOR; - /* - * XXX Expect trouble on CPUs which don't allow misaligned read and writes. - */ - p = (int *)&cmd[1]; - *p++ = from; - *p = to; - write_outbuf(cmd, 1 + (2*sizeof(int)/sizeof(TCHAR))); -} - -void ConPrintf(char *format, ...) -{ - va_list va; - - va_start(va, format); - (void) con_vprintf(format, va); - va_end(va); -} - -void ConBeep(void) -{ - SendMessage(hClientWnd, WM_CONBEEP, 0L, 0L); -} - -int ConReadInput(Uint32 *data, int num_chars) -{ - TCHAR *buf; - int nread; - WaitForSingleObject(console_input,INFINITE); - nread = num_chars = min(num_chars,inbuf.wrPos-inbuf.rdPos); - buf = &inbuf.data[inbuf.rdPos]; - inbuf.rdPos += nread; - while (nread--) - *data++ = *buf++; - if (inbuf.rdPos >= inbuf.wrPos) { - inbuf.rdPos = 0; - inbuf.wrPos = 0; - ResetEvent(console_input_event); - } - ReleaseSemaphore(console_input,1,NULL); - return num_chars; -} - -int ConGetKey(void) -{ - Uint32 c; - WaitForSingleObject(console_input,INFINITE); - ResetEvent(console_input_event); - inbuf.rdPos = inbuf.wrPos = 0; - ReleaseSemaphore(console_input,1,NULL); - WaitForSingleObject(console_input_event,INFINITE); - ConReadInput(&c, 1); - return (int) c; -} - -int ConGetColumns(void) -{ - return (int) canvasColumns; /* 32bit atomic on windows */ -} - -int ConGetRows(void) { - return (int) canvasRows; -} - - -static HINSTANCE hInstance; -extern HMODULE beam_module; - -static unsigned __stdcall -ConThreadInit(LPVOID param) -{ - MSG msg; - WNDCLASSEX wndclass; - int iCmdShow; - STARTUPINFO StartupInfo; - HACCEL hAccel; - int x, y, w, h; - struct title_buf title; - - /*DebugBreak();*/ -#ifdef HARDDEBUG - if(AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()) { - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - } -#endif - - hInstance = GetModuleHandle(NULL); - StartupInfo.dwFlags = 0; - GetStartupInfo(&StartupInfo); - iCmdShow = StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? - StartupInfo.wShowWindow : SW_SHOWDEFAULT; - - LoadUserPreferences(); - - /* frame window class */ - wndclass.cbSize = sizeof (wndclass); - wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT; - wndclass.lpfnWndProc = FrameWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(1)); - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); - wndclass.hbrBackground = NULL; - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szFrameClass; - wndclass.hIconSm = LoadIcon (hInstance, MAKEINTRESOURCE(1)); - RegisterClassExW (&wndclass); - - /* client window class */ - wndclass.cbSize = sizeof (wndclass); - wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wndclass.lpfnWndProc = ClientWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(1)); - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); - wndclass.hbrBackground = CreateSolidBrush(bkgColor); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szClientClass; - wndclass.hIconSm = LoadIcon (hInstance, MAKEINTRESOURCE(1)); - RegisterClassExW (&wndclass); - - InitCommonControls(); - init_buffers(); - - nBufLines = 0; - buffer_top = cur_line = ConNewLine(); - cur_line->next = buffer_bottom = ConNewLine(); - buffer_bottom->prev = cur_line; - - /* Create Frame Window */ - window_title(&title); - hFrameWnd = CreateWindowEx(0, szFrameClass, title.name, - WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, - CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, - NULL,LoadMenu(beam_module,MAKEINTRESOURCE(1)), - hInstance,NULL); - free_window_title(&title); - - /* XXX OTP-5522: - The window position is not saved correctly and if the window - is closed when minimized, it's not possible to start werl again - with the window open. Temporary fix so far is to ignore saved values - and always start with initial settings. */ - /* Original: if (winPos.left == -1) { */ - /* Temporary: if (1) { */ - if (1) { - - /* initial window position */ - x = 0; - y = 0; - w = cxChar*LINE_LENGTH+FRAME_WIDTH+GetSystemMetrics(SM_CXVSCROLL); - h = cyChar*30+FRAME_HEIGHT; - } else { - /* saved window position */ - x = winPos.left; - y = winPos.top; - w = winPos.right - x; - h = winPos.bottom - y; - } - SetWindowPos(hFrameWnd, NULL, x, y, w, h, SWP_NOZORDER); - - ShowWindow(hFrameWnd, iCmdShow); - UpdateWindow(hFrameWnd); - - hAccel = LoadAccelerators(beam_module,MAKEINTRESOURCE(1)); - - ReleaseSemaphore(console_input, 1, NULL); - ReleaseSemaphore(console_output, 1, NULL); - - - /* Main message loop */ - while (GetMessage (&msg, NULL, 0, 0)) - { - if (!TranslateAccelerator(hFrameWnd,hAccel,&msg)) - { - TranslateMessage (&msg); - DispatchMessage (&msg); - } - } - /* - PostQuitMessage() results in WM_QUIT which makes GetMessage() - return 0 (which stops the main loop). Before we return from - the console thread, the ctrl_handler is called to do erts_exit. - */ - (*ctrl_handler)(CTRL_CLOSE_EVENT); - return msg.wParam; -} - -static LRESULT CALLBACK -FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) -{ - RECT r; - int cy,i,bufsize; - TCHAR c; - unsigned long l; - TCHAR buf[128]; - struct title_buf title; - - switch (iMsg) { - case WM_CREATE: - /* client window creation */ - window_title(&title); - hClientWnd = CreateWindowEx(0, szClientClass, title.name, - WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - hwnd, (HMENU)0, hInstance, NULL); - free_window_title(&title); - hTBWnd = InitToolBar(hwnd); - UpdateWindow (hClientWnd); - return 0; - case WM_SIZE : - if (IsWindowVisible(hTBWnd)) { - SendMessage(hTBWnd,TB_AUTOSIZE,0,0L); - GetWindowRect(hTBWnd,&r); - cy = r.bottom-r.top; - } else cy = 0; - MoveWindow(hClientWnd,0,cy,LOWORD(lParam),HIWORD(lParam)-cy,TRUE); - return 0; - case WM_ERASEBKGND: - return 1; - case WM_SETFOCUS : - CreateCaret(hClientWnd, NULL, cxChar, cyChar); - SetCaretPos(GetXFromCurrentY(GetDC(hClientWnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); - ShowCaret(hClientWnd); - return 0; - case WM_KILLFOCUS: - HideCaret(hClientWnd); - DestroyCaret(); - return 0; - case WM_INITMENUPOPUP : - if (lParam == 0) /* File popup menu */ - { - EnableMenuItem((HMENU)wParam, IDMENU_STARTLOG, - logfile ? MF_GRAYED : MF_ENABLED); - EnableMenuItem((HMENU)wParam, IDMENU_STOPLOG, - logfile ? MF_ENABLED : MF_GRAYED); - return 0; - } - else if (lParam == 1) /* Edit popup menu */ - { - EnableMenuItem((HMENU)wParam, IDMENU_COPY, - fTextSelected ? MF_ENABLED : MF_GRAYED); - EnableMenuItem((HMENU)wParam, IDMENU_PASTE, - IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED); - return 0; - } - else if (lParam == 3) /* View popup menu */ - { - CheckMenuItem((HMENU)wParam,IDMENU_TOOLBAR, - IsWindowVisible(hTBWnd) ? MF_CHECKED : MF_UNCHECKED); - return 0; - } - break; - case WM_NOTIFY: - switch (((LPNMHDR) lParam)->code) { - case TTN_NEEDTEXT: - { - LPTOOLTIPTEXT lpttt; - lpttt = (LPTOOLTIPTEXT) lParam; - lpttt->hinst = hInstance; - /* check for combobox handle */ - if (lpttt->uFlags&TTF_IDISHWND) { - if ((lpttt->hdr.idFrom == (UINT_PTR) hComboWnd)) { - lstrcpy(lpttt->lpszText,TEXT("Command History")); - break; - } - } - /* check for toolbar buttons */ - switch (lpttt->hdr.idFrom) { - case IDMENU_COPY: - lstrcpy(lpttt->lpszText,TEXT("Copy (Ctrl+C)")); - break; - case IDMENU_PASTE: - lstrcpy(lpttt->lpszText,TEXT("Paste (Ctrl+V)")); - break; - case IDMENU_FONT: - lstrcpy(lpttt->lpszText,TEXT("Fonts")); - break; - case IDMENU_ABOUT: - lstrcpy(lpttt->lpszText,TEXT("Help")); - break; - } - } - } - break; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDMENU_STARTLOG: - OpenLogFile(hwnd); - return 0; - case IDMENU_STOPLOG: - CloseLogFile(hwnd); - return 0; - case IDMENU_EXIT: - SendMessage(hwnd, WM_CLOSE, 0, 0L); - return 0; - case IDMENU_COPY: - if (fTextSelected) - OnEditCopy(hClientWnd); - return 0; - case IDMENU_PASTE: - OnEditPaste(hClientWnd); - return 0; - case IDMENU_SELALL: - OnEditSelAll(hClientWnd); - return 0; - case IDMENU_FONT: - if (ConChooseFont(hClientWnd)) { - ConSetFont(hClientWnd); - } - SaveUserPreferences(); - return 0; - case IDMENU_SELECTBKG: - ConChooseColor(hClientWnd); - SaveUserPreferences(); - return 0; - case IDMENU_TOOLBAR: - if (toolbarVisible) { - ShowWindow(hTBWnd,SW_HIDE); - toolbarVisible = FALSE; - } else { - ShowWindow(hTBWnd,SW_SHOW); - toolbarVisible = TRUE; - } - GetClientRect(hwnd,&r); - PostMessage(hwnd,WM_SIZE,0,MAKELPARAM(r.right,r.bottom)); - return 0; - case IDMENU_ABOUT: - DialogBox(beam_module,TEXT("AboutBox"),hwnd,AboutDlgProc); - return 0; - case ID_COMBOBOX: - switch (HIWORD(wParam)) { - case CBN_SELENDOK: - i = SendMessage(hComboWnd,CB_GETCURSEL,0,0); - if (i != CB_ERR) { - buf[0] = 0x01; /* CTRL+A */ - buf[1] = 0x0B; /* CTRL+K */ - bufsize = SendMessage(hComboWnd,CB_GETLBTEXT,i,(LPARAM)&buf[2]); - if (bufsize != CB_ERR) - write_inbuf(buf,bufsize+2); - SetFocus(hwnd); - } - break; - case CBN_SELENDCANCEL: - break; - } - break; - case ID_BREAK: /* CTRL+BRK */ - /* pass on break char if the ctrl_handler is disabled */ - if ((*ctrl_handler)(CTRL_C_EVENT) == FALSE) { - c = 0x03; - write_inbuf(&c,1); - } - return 0; - } - break; - case WM_KEYDOWN : - switch (wParam) { - case VK_UP: c = 'P'-'@'; break; - case VK_DOWN : c = 'N'-'@'; break; - case VK_RIGHT : c = 'F'-'@'; break; - case VK_LEFT : c = 'B'-'@'; break; - case VK_DELETE : c = 'D' -'@'; break; - case VK_HOME : c = 'A'-'@'; break; - case VK_END : c = 'E'-'@'; break; - case VK_RETURN : AddToCmdHistory(); return 0; - case VK_PRIOR : /* PageUp */ - PostMessage(hClientWnd, WM_VSCROLL, SB_PAGEUP, 0); - return 0; - case VK_NEXT : /* PageDown */ - PostMessage(hClientWnd, WM_VSCROLL, SB_PAGEDOWN, 0); - return 0; - default: return 0; - } - write_inbuf(&c, 1); - return 0; - case WM_MOUSEWHEEL: - { - int delta = GET_WHEEL_DELTA_WPARAM(wParam); - if (delta < 0) { - PostMessage(hClientWnd, WM_VSCROLL, MAKELONG(SB_THUMBTRACK, - (iVscrollPos + 5)),0); - } else { - WORD pos = ((iVscrollPos - 5) < 0) ? 0 : (iVscrollPos - 5); - PostMessage(hClientWnd, WM_VSCROLL, MAKELONG(SB_THUMBTRACK,pos),0); - } - return 0; - } - case WM_CHAR: - c = (TCHAR)wParam; - write_inbuf(&c,1); - return 0; - case WM_CLOSE : - break; - case WM_DESTROY : - SaveUserPreferences(); - destroyed = TRUE; - PostQuitMessage(0); - return 0; - case WM_SAVE_PREFS : - SaveUserPreferences(); - return 0; - } - return DefWindowProc(hwnd, iMsg, wParam, lParam); -} - -static BOOL -Client_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) -{ - ConFontInitialize(hwnd); - cur_x = cur_y = 0; - iVscrollPos = 0; - iHscrollPos = 0; - return TRUE; -} - -static void -Client_OnPaint(HWND hwnd) -{ - ScreenLine_t *pLine; - int x,y,i,iTop,iBot; - PAINTSTRUCT ps; - RECT rcInvalid; - HDC hdc; - - hdc = BeginPaint(hwnd, &ps); - rcInvalid = ps.rcPaint; - hdc = ps.hdc; - iTop = max(0, iVscrollPos + rcInvalid.top/cyChar); - iBot = min(nBufLines, iVscrollPos + rcInvalid.bottom/cyChar+1); - pLine = GetLineFromY(iTop); - for (i = iTop; i < iBot && pLine != NULL; i++) { - y = cyChar*(i-iVscrollPos); - x = -cxChar*iHscrollPos; - TextOut(hdc, x, y, &pLine->text[0], pLine->width); - pLine = pLine->next; - } - if (fTextSelected || fSelecting) { - InvertSelectionArea(hwnd); - } - SetCaretPos(GetXFromCurrentY(hdc,iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); - EndPaint(hwnd, &ps); -} -#ifdef HARDDEBUG -static void dump_linebufs(void) { - char *buff; - ScreenLine_t *s = buffer_top; - fprintf(stderr,"LinebufDump------------------------\n"); - while(s) { - if (s == buffer_top) fprintf(stderr,"BT-> "); - if (s == buffer_bottom) fprintf(stderr,"BB-> "); - if (s == cur_line) fprintf(stderr,"CL-> "); - - buff = (char *) ALLOC(s->width+1); - memcpy(buff,s->text,s->width); - buff[s->width] = '\0'; - fprintf(stderr,"{\"%s\",%d,%d}\n",buff,s->newline,s->allocated); - FREE(buff); - s = s->next; - } - fprintf(stderr,"LinebufDumpEnd---------------------\n"); - fflush(stderr); -} -#endif - -static void reorganize_linebufs(HWND hwnd) { - ScreenLine_t *otop = buffer_top; - ScreenLine_t *obot = buffer_bottom; - ScreenLine_t *next; - int i,cpos; - - cpos = 0; - i = nBufLines - cur_y; - while (i > 1) { - cpos += obot->width; - obot = obot->prev; - i--; - } - cpos += (obot->width - cur_x); -#ifdef HARDDEBUG - fprintf(stderr,"nBufLines = %d, cur_x = %d, cur_y = %d, cpos = %d\n", - nBufLines,cur_x,cur_y,cpos); - fflush(stderr); -#endif - - - nBufLines = 0; - buffer_top = cur_line = ConNewLine(); - cur_line->next = buffer_bottom = ConNewLine(); - buffer_bottom->prev = cur_line; - - cur_x = cur_y = 0; - iVscrollPos = 0; - iHscrollPos = 0; - - while(otop) { - for(i=0;iwidth;++i) { - cur_line->text[cur_x] = otop->text[i]; - cur_x++; - if (cur_x > cur_line->width) - cur_line->width = cur_x; - if (GetXFromCurrentY(GetDC(hwnd),0,cur_x) + cxChar > - (LINE_LENGTH * cxChar)) { - ConCarriageFeed(0); - } - } - if (otop->newline) { - ConCarriageFeed(1); - /*ConScrollScreen();*/ - } - next = otop->next; - FREE(otop->text); - FREE(otop); - otop = next; - } - while (cpos) { - cur_x--; - if (cur_x < 0) { - cur_y--; - cur_line = cur_line->prev; - cur_x = cur_line->width-1; - } - cpos--; - } - SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); -#ifdef HARDDEBUG - fprintf(stderr,"canvasColumns = %d,nBufLines = %d, cur_x = %d, cur_y = %d\n", - canvasColumns,nBufLines,cur_x,cur_y); - fflush(stderr); -#endif -} - - -static void -Client_OnSize(HWND hwnd, UINT state, int cx, int cy) -{ - RECT r; - SCROLLBARINFO sbi; - int w,h,columns; - int scrollheight; - cxClient = cx; - cyClient = cy; - set_scroll_info(hwnd); - GetClientRect(hwnd,&r); - w = r.right - r.left; - h = r.bottom - r.top; - sbi.cbSize = sizeof(SCROLLBARINFO); - if (!GetScrollBarInfo(hwnd, OBJID_HSCROLL,&sbi) || - (sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE)) { - scrollheight = 0; - } else { - scrollheight = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top; - } - canvasRows = (h - scrollheight) / cyChar; - if (canvasRows < DEF_CANVAS_ROWS) { - canvasRows = DEF_CANVAS_ROWS; - } - columns = (w - GetSystemMetrics(SM_CXVSCROLL)) /cxChar; - if (columns < DEF_CANVAS_COLUMNS) - columns = DEF_CANVAS_COLUMNS; - if (columns != canvasColumns) { - canvasColumns = columns; - /*dump_linebufs();*/ - reorganize_linebufs(hwnd); - fSelecting = fTextSelected = FALSE; - InvalidateRect(hwnd, NULL, TRUE); -#ifdef HARDDEBUG - fprintf(stderr,"Paint: cols = %d, rows = %d\n",canvasColumns,canvasRows); - fflush(stderr); -#endif - } - - SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); -} - -static void calc_charpoint_from_point(HDC dc, int x, int y, int y_offset, POINT *pt) -{ - int r; - int hscrollPix = iHscrollPos * cxChar; - - pt->y = y/cyChar + iVscrollPos + y_offset; - - if (x > (LINE_LENGTH-iHscrollPos) * cxChar) { - x = (LINE_LENGTH-iHscrollPos) * cxChar; - } - if (pt->y - y_offset > 0 && GetLineFromY(pt->y - y_offset) == NULL) { - pt->y = nBufLines - 1 + y_offset; - pt->x = GetLineFromY(pt->y - y_offset)->width; - } else { - for (pt->x = 1; - (r = GetXFromLine(dc, 0, pt->x, GetLineFromY(pt->y - y_offset))) != 0 && - (r - hscrollPix) < x; - ++(pt->x)) - ; - if ((r - hscrollPix) > x) - --(pt->x); -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"pt->x = %d, iHscrollPos = %d\n",(int) pt->x, iHscrollPos); - fflush(stderr); -#endif - if (pt->x <= 0) { - pt->x = x/cxChar + iHscrollPos; - } - } -} - - -static void -Client_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) -{ - int r; - SetFocus(GetParent(hwnd)); /* In case combobox steals the focus */ -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"OnLButtonDown fSelecting = %d, fTextSelected = %d:\n", - fSelecting,fTextSelected); - fflush(stderr); -#endif - if (fTextSelected) { - InvertSelectionArea(hwnd); - } - fTextSelected = FALSE; - - calc_charpoint_from_point(GetDC(hwnd), x, y, 0, &editBeg); - - editEnd.x = editBeg.x; - editEnd.y = editBeg.y + 1; - fSelecting = TRUE; - SetCapture(hwnd); -} - -static void -Client_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) -{ - if (fTextSelected) { - fSelecting = TRUE; - Client_OnMouseMove(hwnd,x,y,keyFlags); - fSelecting = FALSE; - } -} - -static void -Client_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) -{ -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"OnLButtonUp fSelecting = %d, fTextSelected = %d:\n", - fSelecting,fTextSelected); - fprintf(stderr,"(Beg.x = %d, Beg.y = %d, " - "End.x = %d, End.y = %d)\n",editBeg.x,editBeg.y, - editEnd.x,editEnd.y); -#endif - if (fSelecting && - !(editBeg.x == editEnd.x && editBeg.y == (editEnd.y - 1))) { - fTextSelected = TRUE; - } -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"OnLButtonUp fTextSelected = %d:\n", - fTextSelected); - fflush(stderr); -#endif - fSelecting = FALSE; - ReleaseCapture(); -} - -#define EMPTY_RECT(R) \ -(((R).bottom - (R).top == 0) || ((R).right - (R).left == 0)) -#define ABS(X) (((X)< 0) ? -1 * (X) : X) -#define DIFF(A,B) ABS(((int)(A)) - ((int)(B))) - -static int diff_sel_area(RECT old[3], RECT new[3], RECT result[6]) -{ - int absposold = old[0].left + old[0].top * canvasColumns; - int absposnew = new[0].left + new[0].top * canvasColumns; - int absendold = absposold, absendnew = absposnew; - int i, x, ret = 0; - int abspos[2],absend[2]; - for(i = 0; i < 3; ++i) { - if (!EMPTY_RECT(old[i])) { - absendold += (old[i].right - old[i].left) * - (old[i].bottom - old[i].top); - } - if (!EMPTY_RECT(new[i])) { - absendnew += (new[i].right - new[i].left) * - (new[i].bottom - new[i].top); - } - } - abspos[0] = min(absposold, absposnew); - absend[0] = DIFF(absposold, absposnew) + abspos[0]; - abspos[1] = min(absendold, absendnew); - absend[1] = DIFF(absendold, absendnew) + abspos[1]; -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"abspos[0] = %d, absend[0] = %d, abspos[1] = %d, absend[1] = %d\n",abspos[0],absend[0],abspos[1],absend[1]); - fflush(stderr); -#endif - i = 0; - for (x = 0; x < 2; ++x) { - if (abspos[x] != absend[x]) { - int consumed = 0; - result[i].left = abspos[x] % canvasColumns; - result[i].top = abspos[x] / canvasColumns; - result[i].bottom = result[i].top + 1; - if ((absend[x] - abspos[x]) + result[i].left < canvasColumns) { -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"Nowrap, %d < canvasColumns\n", - (absend[x] - abspos[x]) + result[i].left); - fflush(stderr); -#endif - result[i].right = (absend[x] - abspos[x]) + result[i].left; - consumed += result[i].right - result[i].left; - } else { -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"Wrap, %d >= canvasColumns\n", - (absend[x] - abspos[x]) + result[i].left); - fflush(stderr); -#endif - result[i].right = canvasColumns; - consumed += result[i].right - result[i].left; - if (absend[x] - abspos[x] - consumed >= canvasColumns) { - ++i; - result[i].top = result[i-1].bottom; - result[i].left = 0; - result[i].right = canvasColumns; - result[i].bottom = (absend[x] - abspos[x] - consumed) / canvasColumns + result[i].top; - consumed += (result[i].bottom - result[i].top) * canvasColumns; - } - if (absend[x] - abspos[x] - consumed > 0) { - ++i; - result[i].top = result[i-1].bottom; - result[i].bottom = result[i].top + 1; - result[i].left = 0; - result[i].right = absend[x] - abspos[x] - consumed; - } - } - ++i; - } - } -#ifdef HARD_SEL_DEBUG - if (i > 2) { - int x; - fprintf(stderr,"i = %d\n",i); - fflush(stderr); - for (x = 0; x < i; ++x) { - fprintf(stderr, "result[%d]: top = %d, left = %d, " - "bottom = %d. right = %d\n", - x, result[x].top, result[x].left, - result[x].bottom, result[x].right); - } - } -#endif - return i; -} - - - -static void calc_sel_area(RECT rects[3], POINT beg, POINT end) -{ - /* These are not really rects and points, these are character - based positions, need to be multiplied by cxChar and cyChar to - make up canvas coordinates */ - memset(rects,0,3*sizeof(RECT)); - rects[0].left = beg.x; - rects[0].top = beg.y; - rects[0].bottom = beg.y+1; - if (end.y - beg.y == 1) { /* Only one row */ - rects[0].right = end.x; - goto out; - } - rects[0].right = canvasColumns; - if (end.y - beg.y > 2) { - rects[1].left = 0; - rects[1].top = rects[0].bottom; - rects[1].right = canvasColumns; - rects[1].bottom = end.y - 1; - } - rects[2].left = 0; - rects[2].top = end.y - 1; - rects[2].bottom = end.y; - rects[2].right = end.x; - - out: -#ifdef HARD_SEL_DEBUG - { - int i; - fprintf(stderr,"beg.x = %d, beg.y = %d, end.x = %d, end.y = %d\n", - beg.x,beg.y,end.x,end.y); - for (i = 0; i < 3; ++i) { - fprintf(stderr,"[%d] left = %d, top = %d, " - "right = %d, bottom = %d\n", - i, rects[i].left, rects[i].top, - rects[i].right, rects[i].bottom); - } - fflush(stderr); - } -#endif - return; -} - -static void calc_sel_area_turned(RECT rects[3], POINT eBeg, POINT eEnd) { - POINT from,to; - if (eBeg.y >= eEnd.y || - (eBeg.y == eEnd.y - 1 && eBeg.x > eEnd.x)) { -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"Reverting (Beg.x = %d, Beg.y = %d, " - "End.x = %d, End.y = %d)\n",eBeg.x,eBeg.y, - eEnd.x,eEnd.y); - fflush(stderr); -#endif - from.x = eEnd.x; - from.y = eEnd.y - 1; - to.x = eBeg.x; - to.y = eBeg.y + 1; - calc_sel_area(rects,from,to); - } else { - calc_sel_area(rects,eBeg,eEnd); - } -} - - -static void InvertSelectionArea(HWND hwnd) -{ - RECT rects[3]; - POINT from,to; - int i; - calc_sel_area_turned(rects,editBeg,editEnd); - for (i = 0; i < 3; ++i) { - if (!EMPTY_RECT(rects[i])) { - from.x = rects[i].left; - to.x = rects[i].right; - from.y = rects[i].top; - to.y = rects[i].bottom; - DrawSelection(hwnd,from,to); - } - } -} - -static void -Client_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) -{ - if (fSelecting) { - RECT rold[3], rnew[3], rupdate[6]; - int num_updates,i,r; - POINT from,to; - calc_sel_area_turned(rold,editBeg,editEnd); - - calc_charpoint_from_point(GetDC(hwnd), x, y, 1, &editEnd); - - calc_sel_area_turned(rnew,editBeg,editEnd); - num_updates = diff_sel_area(rold,rnew,rupdate); - for (i = 0; i < num_updates;++i) { - from.x = rupdate[i].left; - to.x = rupdate[i].right; - from.y = rupdate[i].top; - to.y = rupdate[i].bottom; -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"from: x=%d,y=%d, to: x=%d, y=%d\n", - from.x, from.y,to.x,to.y); - fflush(stderr); -#endif - DrawSelection(hwnd,from,to); - } - } -} - -static void -Client_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) -{ - int iVscroll; - - switch(code) { - case SB_LINEDOWN: - iVscroll = 1; - break; - case SB_LINEUP: - iVscroll = -1; - break; - case SB_PAGEDOWN: - iVscroll = max(1, cyClient/cyChar); - break; - case SB_PAGEUP: - iVscroll = min(-1, -cyClient/cyChar); - break; - case SB_THUMBTRACK: - iVscroll = pos - iVscrollPos; - break; - default: - iVscroll = 0; - } - iVscroll = max(-iVscrollPos, min(iVscroll, iVscrollMax-iVscrollPos)); - if (iVscroll != 0) { - iVscrollPos += iVscroll; - ScrollWindowEx(hwnd, 0, -cyChar*iVscroll, NULL, NULL, - NULL, NULL, SW_ERASE | SW_INVALIDATE); - SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE); - iVscroll = GetScrollPos(hwnd, SB_VERT); - UpdateWindow(hwnd); - } -} - -static void -Client_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) -{ - int iHscroll, curCharWidth = cxClient/cxChar; - - switch(code) { - case SB_LINEDOWN: - iHscroll = 1; - break; - case SB_LINEUP: - iHscroll = -1; - break; - case SB_PAGEDOWN: - iHscroll = max(1,curCharWidth-1); - break; - case SB_PAGEUP: - iHscroll = min(-1,-(curCharWidth-1)); - break; - case SB_THUMBTRACK: - iHscroll = pos - iHscrollPos; - break; - default: - iHscroll = 0; - } - iHscroll = max(-iHscrollPos, min(iHscroll, iHscrollMax-iHscrollPos-(curCharWidth-1))); - if (iHscroll != 0) { - iHscrollPos += iHscroll; - ScrollWindow(hwnd, -cxChar*iHscroll, 0, NULL, NULL); - SetScrollPos(hwnd, SB_HORZ, iHscrollPos, TRUE); - UpdateWindow(hwnd); - } -} - -static LRESULT CALLBACK -ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) -{ - switch (iMsg) { - HANDLE_MSG(hwnd, WM_CREATE, Client_OnCreate); - HANDLE_MSG(hwnd, WM_SIZE, Client_OnSize); - HANDLE_MSG(hwnd, WM_PAINT, Client_OnPaint); - HANDLE_MSG(hwnd, WM_LBUTTONDOWN, Client_OnLButtonDown); - HANDLE_MSG(hwnd, WM_RBUTTONDOWN, Client_OnRButtonDown); - HANDLE_MSG(hwnd, WM_LBUTTONUP, Client_OnLButtonUp); - HANDLE_MSG(hwnd, WM_MOUSEMOVE, Client_OnMouseMove); - HANDLE_MSG(hwnd, WM_VSCROLL, Client_OnVScroll); - HANDLE_MSG(hwnd, WM_HSCROLL, Client_OnHScroll); - case WM_CONBEEP: - if (0) Beep(440, 400); - return 0; - case WM_CONTEXT: - ConDrawText(hwnd); - return 0; - case WM_CLOSE: - break; - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - return DefWindowProc (hwnd, iMsg, wParam, lParam); -} - -static void -LoadUserPreferences(void) -{ - DWORD size; - DWORD res; - DWORD type; - HFONT hfont; - /* default prefs */ - hfont = CreateFont(0,0, 0,0, 0, FALSE,FALSE,FALSE, - ANSI_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, - CLEARTYPE_QUALITY, FIXED_PITCH, TEXT("Consolas")); - if(hfont) { - GetObject(hfont, sizeof(LOGFONT), (PSTR)&logfont); - DeleteObject(hfont); - } else { - GetObject(GetStockObject(SYSTEM_FIXED_FONT),sizeof(LOGFONT),(PSTR)&logfont); - } - fgColor = GetSysColor(COLOR_WINDOWTEXT); - bkgColor = GetSysColor(COLOR_WINDOW); - winPos.left = -1; - toolbarVisible = FALSE; - - if (RegCreateKeyEx(HKEY_CURRENT_USER, USER_KEY, 0, 0, - REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, - &key, &res) != ERROR_SUCCESS) - return; - has_key = TRUE; - if (res == REG_CREATED_NEW_KEY) - return; - size = sizeof(logfont); - res = RegQueryValueEx(key,TEXT("Font"),NULL,&type,(LPBYTE)&logfont,&size); - size = sizeof(fgColor); - res = RegQueryValueEx(key,TEXT("FgColor"),NULL,&type,(LPBYTE)&fgColor,&size); - size = sizeof(bkgColor); - res = RegQueryValueEx(key,TEXT("BkColor"),NULL,&type,(LPBYTE)&bkgColor,&size); - size = sizeof(winPos); - res = RegQueryValueEx(key,TEXT("Pos"),NULL,&type,(LPBYTE)&winPos,&size); - size = sizeof(toolbarVisible); - res = RegQueryValueEx(key,TEXT("Toolbar"),NULL,&type,(LPBYTE)&toolbarVisible,&size); -} - -static void -SaveUserPreferences(void) -{ - WINDOWPLACEMENT wndPlace; - - if (has_key == TRUE) { - RegSetValueEx(key,TEXT("Font"),0,REG_BINARY,(CONST BYTE *)&logfont,sizeof(LOGFONT)); - RegSetValueEx(key,TEXT("FgColor"),0,REG_DWORD,(CONST BYTE *)&fgColor,sizeof(fgColor)); - RegSetValueEx(key,TEXT("BkColor"),0,REG_DWORD,(CONST BYTE *)&bkgColor,sizeof(bkgColor)); - RegSetValueEx(key,TEXT("Toolbar"),0,REG_DWORD,(CONST BYTE *)&toolbarVisible,sizeof(toolbarVisible)); - - wndPlace.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(hFrameWnd,&wndPlace); - /* If wndPlace.showCmd == SW_MINIMIZE, then the window is minimized. - We don't care, wndPlace.rcNormalPosition always holds the last known position. */ - winPos = wndPlace.rcNormalPosition; - RegSetValueEx(key,TEXT("Pos"),0,REG_BINARY,(CONST BYTE *)&winPos,sizeof(winPos)); - } -} - - -static void -set_scroll_info(HWND hwnd) -{ - SCROLLINFO info; - int hScrollBy; - /* - * Set vertical scrolling range and scroll box position. - */ - - iVscrollMax = nBufLines-1; - iVscrollPos = min(iVscrollPos, iVscrollMax); - info.cbSize = sizeof(info); - info.fMask = SIF_PAGE|SIF_RANGE|SIF_POS; - info.nMin = 0; - info.nPos = iVscrollPos; - info.nPage = min(cyClient/cyChar, iVscrollMax); - info.nMax = iVscrollMax; - SetScrollInfo(hwnd, SB_VERT, &info, TRUE); - - /* - * Set horizontal scrolling range and scroll box position. - */ - - iHscrollMax = LINE_LENGTH-1; - hScrollBy = max(0, (iHscrollPos - (iHscrollMax-cxClient/cxChar))*cxChar); - iHscrollPos = min(iHscrollPos, iHscrollMax); - info.nPos = iHscrollPos; - info.nPage = cxClient/cxChar; - info.nMax = iHscrollMax; - SetScrollInfo(hwnd, SB_HORZ, &info, TRUE); - /*ScrollWindow(hwnd, hScrollBy, 0, NULL, NULL);*/ -} - - -static void -ensure_line_below(void) -{ - if (cur_line->next == NULL) { - if (nBufLines >= lines_to_save) { - ScreenLine_t* pLine = buffer_top->next; - FREE(buffer_top->text); - FREE(buffer_top); - buffer_top = pLine; - buffer_top->prev = NULL; - nBufLines--; - } - cur_line->next = ConNewLine(); - cur_line->next->prev = cur_line; - buffer_bottom = cur_line->next; - set_scroll_info(hClientWnd); - } -} - -static ScreenLine_t* -ConNewLine(void) -{ - ScreenLine_t *pLine; - - pLine = (ScreenLine_t *)ALLOC(sizeof(ScreenLine_t)); - if (!pLine) - return NULL; - pLine->text = (TCHAR *) ALLOC(canvasColumns * sizeof(TCHAR)); -#ifdef HARDDEBUG - pLine->allocated = canvasColumns; -#endif - pLine->width = 0; - pLine->prev = pLine->next = NULL; - pLine->newline = 0; - nBufLines++; - return pLine; -} - -static ScreenLine_t* -GetLineFromY(int y) -{ - ScreenLine_t *pLine = buffer_top; - int i; - - for (i = 0; i < nBufLines && pLine != NULL; i++) { - if (i == y) - return pLine; - pLine = pLine->next; - } - return NULL; -} - -void ConCarriageFeed(int hard_newline) -{ - cur_x = 0; - ensure_line_below(); - cur_line->newline = hard_newline; - cur_line = cur_line->next; - if (cur_y < nBufLines-1) { - cur_y++; - } else if (iVscrollPos > 0) { - iVscrollPos--; - } -} - -/* - * Scroll screen if cursor is not visible. - */ -static void -ConScrollScreen(void) -{ - if (cur_y >= iVscrollPos + cyClient/cyChar) { - int iVscroll; - - iVscroll = cur_y - iVscrollPos - cyClient/cyChar + 1; - iVscrollPos += iVscroll; - ScrollWindowEx(hClientWnd, 0, -cyChar*iVscroll, NULL, NULL, - NULL, NULL, SW_ERASE | SW_INVALIDATE); - SetScrollPos(hClientWnd, SB_VERT, iVscrollPos, TRUE); - UpdateWindow(hClientWnd); - } -} - -static void -DrawSelection(HWND hwnd, POINT pt1, POINT pt2) -{ - HDC hdc; - int width,height; -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"pt1.x = %d, pt1.y = %d, pt2.x = %d, pt2.y = %d\n", - (int) pt1.x, (int) pt1.y, (int) pt2.x, (int) pt2.y); -#endif - pt1.x = GetXFromLine(GetDC(hwnd),iHscrollPos,pt1.x,GetLineFromY(pt1.y)); - pt2.x = GetXFromLine(GetDC(hwnd),iHscrollPos,pt2.x,GetLineFromY(pt2.y-1)); - pt1.y -= iVscrollPos; - pt2.y -= iVscrollPos; - pt1.y *= cyChar; - pt2.y *= cyChar; -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"pt1.x = %d, pt1.y = %d, pt2.x = %d, pt2.y = %d\n", - (int) pt1.x, (int) pt1.y, (int) pt2.x, (int) pt2.y); - fflush(stderr); -#endif - width = pt2.x-pt1.x; - height = pt2.y - pt1.y; - hdc = GetDC(hwnd); - PatBlt(hdc,pt1.x,pt1.y,width,height,DSTINVERT); - ReleaseDC(hwnd,hdc); -} - -static void -OnEditCopy(HWND hwnd) -{ - HGLOBAL hMem; - TCHAR *pMem; - ScreenLine_t *pLine; - RECT rects[3]; - POINT from,to; - int i,j,sum,len; - if (editBeg.y >= editEnd.y || - (editBeg.y == editEnd.y - 1 && editBeg.x > editEnd.x)) { -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"CopyReverting (Beg.x = %d, Beg.y = %d, " - "End.x = %d, End.y = %d)\n",editBeg.x,editBeg.y, - editEnd.x,editEnd.y); - fflush(stderr); -#endif - from.x = editEnd.x; - from.y = editEnd.y - 1; - to.x = editBeg.x; - to.y = editBeg.y + 1; - calc_sel_area(rects,from,to); - } else { - calc_sel_area(rects,editBeg,editEnd); - } - sum = 1; - for (i = 0; i < 3; ++i) { - if (!EMPTY_RECT(rects[i])) { - pLine = GetLineFromY(rects[i].top); - for (j = rects[i].top; j < rects[i].bottom ;++j) { - if (pLine == NULL) { - sum += 2; - break; - } - if (pLine->width > rects[i].left) { - sum += (pLine->width < rects[i].right) ? - pLine->width - rects[i].left : - rects[i].right - rects[i].left; - } - if(pLine->newline && rects[i].right >= pLine->width) { - sum += 2; - } - pLine = pLine->next; - } - } - } -#ifdef HARD_SEL_DEBUG - fprintf(stderr,"sum = %d\n",sum); - fflush(stderr); -#endif - hMem = GlobalAlloc(GHND, sum * sizeof(TCHAR)); - pMem = GlobalLock(hMem); - for (i = 0; i < 3; ++i) { - if (!EMPTY_RECT(rects[i])) { - pLine = GetLineFromY(rects[i].top); - for (j = rects[i].top; j < rects[i].bottom; ++j) { - if (pLine == NULL) { - memcpy(pMem,TEXT("\r\n"),2 * sizeof(TCHAR)); - pMem += 2; - break; - } - if (pLine->width > rects[i].left) { - len = (pLine->width < rects[i].right) ? - pLine->width - rects[i].left : - rects[i].right - rects[i].left; - memcpy(pMem,pLine->text + rects[i].left,len * sizeof(TCHAR)); - pMem +=len; - } - if(pLine->newline && rects[i].right >= pLine->width) { - memcpy(pMem,TEXT("\r\n"),2 * sizeof(TCHAR)); - pMem += 2; - } - pLine = pLine->next; - } - } - } - *pMem = TEXT('\0'); - /* Flash de selection area to give user feedback about copying */ - InvertSelectionArea(hwnd); - Sleep(100); - InvertSelectionArea(hwnd); - - OpenClipboard(hwnd); - EmptyClipboard(); - GlobalUnlock(hMem); - SetClipboardData(CF_UNICODETEXT,hMem); - CloseClipboard(); -} - -/* XXX:PaN Tchar or char? */ -static void -OnEditPaste(HWND hwnd) -{ - HANDLE hClipMem; - TCHAR *pClipMem,*pMem,*pMem2; - if (!OpenClipboard(hwnd)) - return; - if ((hClipMem = GetClipboardData(CF_UNICODETEXT)) != NULL) { - pClipMem = GlobalLock(hClipMem); - pMem = (TCHAR *)ALLOC(GlobalSize(hClipMem) * sizeof(TCHAR)); - pMem2 = pMem; - while ((*pMem2 = *pClipMem) != TEXT('\0')) { - if (*pClipMem == TEXT('\r')) - *pMem2 = TEXT('\n'); - ++pMem2; - ++pClipMem; - } - GlobalUnlock(hClipMem); - write_inbuf(pMem, _tcsclen(pMem)); - } - CloseClipboard(); -} - -static void -OnEditSelAll(HWND hwnd) -{ - editBeg.x = 0; - editBeg.y = 0; - editEnd.x = LINE_LENGTH-1; - editEnd.y = cur_y; - fTextSelected = TRUE; - InvalidateRect(hwnd, NULL, TRUE); -} - -CF_HOOK_RET APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) -{ - /* Hook procedure for font dialog box */ - HWND hOwner; - RECT rc,rcOwner,rcDlg; - switch (iMsg) { - case WM_INITDIALOG: - /* center dialogbox within its owner window */ - if ((hOwner = GetParent(hDlg)) == NULL) - hOwner = GetDesktopWindow(); - GetWindowRect(hOwner, &rcOwner); - GetWindowRect(hDlg, &rcDlg); - CopyRect(&rc, &rcOwner); - OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect(&rc, -rc.left, -rc.top); - OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); - SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), - rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return (CF_HOOK_RET) 1; - default: - break; - } - return (CF_HOOK_RET) 0; /* Let the default procedure process the message */ -} - -static BOOL -ConChooseFont(HWND hwnd) -{ - HDC hdc; - hdc = GetDC(hwnd); - cf.lStructSize = sizeof(CHOOSEFONT); - cf.hwndOwner = hwnd; - cf.hDC = NULL; - cf.lpLogFont = &logfont; - cf.iPointSize = 0; - cf.Flags = CF_INITTOLOGFONTSTRUCT|CF_SCREENFONTS|CF_FIXEDPITCHONLY|CF_EFFECTS|CF_ENABLEHOOK; - cf.rgbColors = GetTextColor(hdc); - cf.lCustData = 0L; - cf.lpfnHook = CFHookProc; - cf.lpTemplateName = NULL; - cf.hInstance = NULL; - cf.lpszStyle = NULL; - cf.nFontType = 0; - cf.nSizeMin = 0; - cf.nSizeMax = 0; - ReleaseDC(hwnd,hdc); - return ChooseFont(&cf); -} - -static void -ConFontInitialize(HWND hwnd) -{ - HDC hdc; - TEXTMETRIC tm; - HFONT hFont; - - hFont = CreateFontIndirect(&logfont); - hdc = GetDC(hwnd); - SelectObject(hdc, hFont); - SetTextColor(hdc,fgColor); - SetBkColor(hdc,bkgColor); - GetTextMetrics(hdc, &tm); - cxChar = tm.tmAveCharWidth; - cxCharMax = tm.tmMaxCharWidth; - cyChar = tm.tmHeight + tm.tmExternalLeading; - ReleaseDC(hwnd, hdc); -} - -static void -ConSetFont(HWND hwnd) -{ - HDC hdc; - TEXTMETRIC tm; - HFONT hFontNew; - - hFontNew = CreateFontIndirect(&logfont); - SendMessage(hComboWnd,WM_SETFONT,(WPARAM)hFontNew, - MAKELPARAM(1,0)); - hdc = GetDC(hwnd); - DeleteObject(SelectObject(hdc, hFontNew)); - GetTextMetrics(hdc, &tm); - cxChar = tm.tmAveCharWidth; - cxCharMax = tm.tmMaxCharWidth; - cyChar = tm.tmHeight + tm.tmExternalLeading; - fgColor = cf.rgbColors; - SetTextColor(hdc,fgColor); - ReleaseDC(hwnd, hdc); - set_scroll_info(hwnd); - HideCaret(hwnd); - if (DestroyCaret()) { - CreateCaret(hwnd, NULL, cxChar, cyChar); - SetCaretPos(GetXFromCurrentY(hdc,iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); - } - ShowCaret(hwnd); - InvalidateRect(hwnd, NULL, TRUE); -} - -CC_HOOK_RET APIENTRY -CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) -{ - /* Hook procedure for choose color dialog box */ - HWND hOwner; - RECT rc,rcOwner,rcDlg; - switch (iMsg) { - case WM_INITDIALOG: - /* center dialogbox within its owner window */ - if ((hOwner = GetParent(hDlg)) == NULL) - hOwner = GetDesktopWindow(); - GetWindowRect(hOwner, &rcOwner); - GetWindowRect(hDlg, &rcDlg); - CopyRect(&rc, &rcOwner); - OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect(&rc, -rc.left, -rc.top); - OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); - SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), - rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return (CC_HOOK_RET) 1; - default: - break; - } - return (CC_HOOK_RET) 0; /* Let the default procedure process the message */ -} - -void ConChooseColor(HWND hwnd) -{ - CHOOSECOLOR cc; - static COLORREF acrCustClr[16]; - HBRUSH hbrush; - HDC hdc; - - /* Initialize CHOOSECOLOR */ - ZeroMemory(&cc, sizeof(CHOOSECOLOR)); - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = hwnd; - cc.lpCustColors = (LPDWORD) acrCustClr; - cc.rgbResult = bkgColor; - cc.lpfnHook = CCHookProc; - cc.Flags = CC_FULLOPEN|CC_RGBINIT|CC_SOLIDCOLOR|CC_ENABLEHOOK; - - if (ChooseColor(&cc)==TRUE) { - bkgColor = cc.rgbResult; - hdc = GetDC(hwnd); - SetBkColor(hdc,bkgColor); - ReleaseDC(hwnd,hdc); - hbrush = CreateSolidBrush(bkgColor); - DeleteObject((HBRUSH)SetClassLongPtr(hClientWnd,GCL_HBRBACKGROUND,(LONG_PTR)hbrush)); - InvalidateRect(hwnd,NULL,TRUE); - } -} - -OFN_HOOK_RET APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg, - WPARAM wParam,LPARAM lParam) -{ - /* Hook procedure for open file dialog box */ - HWND hOwner,hDlg; - RECT rc,rcOwner,rcDlg; - hDlg = GetParent(hwndDlg); - switch (iMsg) { - case WM_INITDIALOG: - /* center dialogbox within its owner window */ - if ((hOwner = GetParent(hDlg)) == NULL) - hOwner = GetDesktopWindow(); - GetWindowRect(hOwner, &rcOwner); - GetWindowRect(hDlg, &rcDlg); - CopyRect(&rc, &rcOwner); - OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect(&rc, -rc.left, -rc.top); - OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); - SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), - rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return (OFN_HOOK_RET) 1; - default: - break; - } - return (OFN_HOOK_RET) 0; /* the let default procedure process the message */ -} - -static void -GetFileName(HWND hwnd, TCHAR *pFile) -{ - /* Open the File Open dialog box and */ - /* retrieve the file name */ - OPENFILENAME ofn; - TCHAR szFilterSpec [128] = TEXT("logfiles (*.log)\0*.log\0All files (*.*)\0*.*\0\0"); - #define MAXFILENAME 256 - TCHAR szFileName[MAXFILENAME]; - TCHAR szFileTitle[MAXFILENAME]; - - /* these need to be filled in */ - _tcscpy(szFileName, TEXT("erlshell.log")); - _tcscpy(szFileTitle, TEXT("")); /* must be NULL */ - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = NULL; - ofn.lpstrFilter = szFilterSpec; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 0; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = MAXFILENAME; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = MAXFILENAME; - ofn.lpstrTitle = TEXT("Open logfile"); - ofn.lpstrDefExt = TEXT("log"); - ofn.Flags = OFN_CREATEPROMPT|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_ENABLEHOOK|OFN_NOCHANGEDIR; /* OFN_NOCHANGEDIR only works in Vista :( */ - ofn.lpfnHook = OFNHookProc; - - if (!GetOpenFileName ((LPOPENFILENAME)&ofn)){ - *pFile = TEXT('\0'); - } else { - _tcscpy(pFile, ofn.lpstrFile); - } -} - -void OpenLogFile(HWND hwnd) -{ - /* open a file for logging */ - TCHAR filename[_MAX_PATH]; - - GetFileName(hwnd, filename); - if (filename[0] == '\0') - return; - if (NULL == (logfile = _tfopen(filename,TEXT("w,ccs=UNICODE")))) - return; -} - -void CloseLogFile(HWND hwnd) -{ - /* close log file */ - fclose(logfile); - logfile = NULL; -} - -void LogFileWrite(TCHAR *buf, int num_chars) -{ - /* write to logfile */ - int from,to; - while (num_chars-- > 0) { - switch (*buf) { - case SET_CURSOR: - buf++; - from = *((int *)buf); - buf += sizeof(int)/sizeof(TCHAR); - to = *((int *)buf); - buf += (sizeof(int)/sizeof(TCHAR))-1; - num_chars -= 2 * (sizeof(int)/sizeof(TCHAR)); - // Wont seek in Unicode file, sorry... - // fseek(logfile,to-from *sizeof(TCHAR),SEEK_CUR); - break; - default: - _fputtc(*buf,logfile); - break; - } - buf++; - } -} - -static void -init_buffers(void) -{ - inbuf.data = (TCHAR *) ALLOC(BUFSIZE * sizeof(TCHAR)); - outbuf.data = (TCHAR *) ALLOC(BUFSIZE * sizeof(TCHAR)); - inbuf.size = BUFSIZE; - inbuf.rdPos = inbuf.wrPos = 0; - outbuf.size = BUFSIZE; - outbuf.rdPos = outbuf.wrPos = 0; -} - -static int -check_realloc(buffer_t *buf, int num_chars) -{ - if (buf->wrPos + num_chars >= buf->size) { - if (buf->size > MAXBUFSIZE) - return 0; - buf->size += num_chars + BUFSIZE; - if (!(buf->data = (TCHAR *)REALLOC(buf->data, buf->size * sizeof(TCHAR)))) { - buf->size = buf->rdPos = buf->wrPos = 0; - return 0; - } - } - return 1; -} - -static int -write_inbuf(TCHAR *data, int num_chars) -{ - TCHAR *buf; - int nwrite; - WaitForSingleObject(console_input,INFINITE); - if (!check_realloc(&inbuf,num_chars)) { - ReleaseSemaphore(console_input,1,NULL); - return -1; - } - buf = &inbuf.data[inbuf.wrPos]; - inbuf.wrPos += num_chars; - nwrite = num_chars; - while (nwrite--) - *buf++ = *data++; - SetEvent(console_input_event); - ReleaseSemaphore(console_input,1,NULL); - return num_chars; -} - -static int -write_outbuf(TCHAR *data, int num_chars) -{ - TCHAR *buf; - int nwrite; - - WaitForSingleObject(console_output,INFINITE); - if (!check_realloc(&outbuf, num_chars)) { - ReleaseSemaphore(console_output,1,NULL); - return -1; - } - if (outbuf.rdPos == outbuf.wrPos) - PostMessage(hClientWnd, WM_CONTEXT, 0L, 0L); - buf = &outbuf.data[outbuf.wrPos]; - outbuf.wrPos += num_chars; - nwrite = num_chars; - while (nwrite--) - *buf++ = *data++; - ReleaseSemaphore(console_output,1,NULL); - return num_chars; -} - -DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) -{ - HWND hOwner; - RECT rc,rcOwner,rcDlg; - - switch (iMsg) { - case WM_INITDIALOG: - /* center dialogbox within its owner window */ - if ((hOwner = GetParent(hDlg)) == NULL) - hOwner = GetDesktopWindow(); - GetWindowRect(hOwner, &rcOwner); - GetWindowRect(hDlg, &rcDlg); - CopyRect(&rc, &rcOwner); - OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); - OffsetRect(&rc, -rc.left, -rc.top); - OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); - SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), - rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - SetDlgItemText(hDlg, ID_OTP_VERSIONSTRING, - TEXT("OTP version ") TEXT(ERLANG_OTP_VERSION)); - SetDlgItemText(hDlg, ID_ERTS_VERSIONSTRING, - TEXT("Erlang emulator version ") TEXT(ERLANG_VERSION)); - return (DIALOG_PROC_RET) TRUE; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - case IDCANCEL: - EndDialog(hDlg,0); - return (DIALOG_PROC_RET) TRUE; - } - break; - } - return (DIALOG_PROC_RET) FALSE; -} - -static void -ConDrawText(HWND hwnd) -{ - int num_chars; - int nchars; - TCHAR *buf; - int from, to; - int dl; - int dc; - RECT rc; - - WaitForSingleObject(console_output, INFINITE); - nchars = 0; - num_chars = outbuf.wrPos - outbuf.rdPos; - buf = &outbuf.data[outbuf.rdPos]; - if (logfile != NULL) - LogFileWrite(buf, num_chars); - - -#ifdef HARDDEBUG - { - TCHAR *bu = (TCHAR *) ALLOC((num_chars+1) * sizeof(TCHAR)); - memcpy(bu,buf,num_chars * sizeof(TCHAR)); - bu[num_chars]='\0'; - fprintf(stderr,"ConDrawText\"%S\"\n",bu); - FREE(bu); - fflush(stderr); - } -#endif - /* - * Don't draw any text in the window; just update the line buffers - * and invalidate the appropriate part of the window. The window - * will be updated on the next WM_PAINT message. - */ - - while (num_chars-- > 0) { - switch (*buf) { - case '\r': - break; - case '\n': - if (nchars > 0) { - rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars); - rc.right = rc.left + cxCharMax*nchars; - rc.top = cyChar * (cur_y-iVscrollPos); - rc.bottom = rc.top + cyChar; - InvalidateRect(hwnd, &rc, TRUE); - nchars = 0; - } - ConCarriageFeed(1); - ConScrollScreen(); - break; - case SET_CURSOR: - if (nchars > 0) { - rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars); - rc.right = rc.left + cxCharMax*nchars; - rc.top = cyChar * (cur_y-iVscrollPos); - rc.bottom = rc.top + cyChar; - InvalidateRect(hwnd, &rc, TRUE); - nchars = 0; - } - buf++; - from = *((int *)buf); - buf += sizeof(int)/sizeof(TCHAR); - to = *((int *)buf); - buf += (sizeof(int)/sizeof(TCHAR))-1; - num_chars -= 2 * (sizeof(int)/sizeof(TCHAR)); - while (to > from) { - cur_x++; - if (GetXFromCurrentY(GetDC(hwnd),0,cur_x)+cxChar > - (LINE_LENGTH * cxChar)) { - cur_x = 0; - cur_y++; - ensure_line_below(); - cur_line = cur_line->next; - } - from++; - } - while (to < from) { - cur_x--; - if (cur_x < 0) { - cur_y--; - cur_line = cur_line->prev; - cur_x = cur_line->width-1; - } - from--; - } - - break; - default: - nchars++; - cur_line->text[cur_x] = *buf; - cur_x++; - if (cur_x > cur_line->width) - cur_line->width = cur_x; - if (GetXFromCurrentY(GetDC(hwnd),0,cur_x)+cxChar > - (LINE_LENGTH * cxChar)) { - if (nchars > 0) { - rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars); - rc.right = rc.left + cxCharMax*nchars; - rc.top = cyChar * (cur_y-iVscrollPos); - rc.bottom = rc.top + cyChar; - InvalidateRect(hwnd, &rc, TRUE); - } - ConCarriageFeed(0); - nchars = 0; - } - } - buf++; - } - if (nchars > 0) { - rc.left = GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x - nchars); - rc.right = rc.left + cxCharMax*nchars; - rc.top = cyChar * (cur_y-iVscrollPos); - rc.bottom = rc.top + cyChar; - InvalidateRect(hwnd, &rc, TRUE); - } - ConScrollScreen(); - SetCaretPos(GetXFromCurrentY(GetDC(hwnd),iHscrollPos,cur_x), (cur_y-iVscrollPos)*cyChar); - outbuf.wrPos = outbuf.rdPos = 0; - ReleaseSemaphore(console_output, 1, NULL); -} - -static void -AddToCmdHistory(void) -{ - int i; - int size; - Uint32 *buf; - wchar_t cmdBuf[128]; - - if (llen != 0) { - for (i = 0, size = 0; i < llen-1; i++) { - /* - * Find end of prompt. - */ - if ((lbuf[i] == '>') && lbuf[i+1] == ' ') { - buf = &lbuf[i+2]; - size = llen-i-2; - break; - } - } - if (size > 0 && size < 128) { - for (i = 0;i < size; ++i) { - cmdBuf[i] = (wchar_t) buf[i]; - } - cmdBuf[size] = 0; - SendMessage(hComboWnd,CB_INSERTSTRING,0,(LPARAM)cmdBuf); - } - } -} - -/*static TBBUTTON tbb[] = -{ - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - 0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, - 1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, - 2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, - 3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, - 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, - };*/ -static TBBUTTON tbb[] = -{ - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, - {0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, - {1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, - {2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, - {3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, - {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP} -}; - -static TBADDBITMAP tbbitmap = -{ - HINST_COMMCTRL, IDB_STD_SMALL_COLOR, -}; - - -static HWND -InitToolBar(HWND hwndParent) -{ - int x,y,cx; - HWND hwndTB,hwndTT; - RECT r; - TOOLINFO ti; - HFONT hFontNew; - DWORD backgroundColor = GetSysColor(COLOR_BTNFACE); - COLORMAP colorMap; - colorMap.from = RGB(192, 192, 192); - colorMap.to = backgroundColor; - /* Create toolbar window with tooltips */ - hwndTB = CreateWindowEx(0,TOOLBARCLASSNAME,(TCHAR *)NULL, - WS_CHILD|CCS_TOP|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS, - 0,0,0,0,hwndParent, - (HMENU)2,hInstance,NULL); - SendMessage(hwndTB,TB_BUTTONSTRUCTSIZE, - (WPARAM) sizeof(TBBUTTON),0); - tbbitmap.hInst = NULL; - tbbitmap.nID = (UINT_PTR) CreateMappedBitmap(beam_module, 1,0, &colorMap, 1); - SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) 4, - (LPARAM) &tbbitmap); - - SendMessage(hwndTB,TB_ADDBUTTONS, (WPARAM) 30, - (LPARAM) tbb); - if (toolbarVisible) - ShowWindow(hwndTB, SW_SHOW); - - /* Create combobox window */ - SendMessage(hwndTB,TB_GETITEMRECT,0,(LPARAM)&r); - x = r.left; y = r.top; - SendMessage(hwndTB,TB_GETITEMRECT,23,(LPARAM)&r); - cx = r.right - x + 1; - hComboWnd = CreateWindow(TEXT("combobox"),NULL,WS_VSCROLL|WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST, - x,y,cx,100,hwndParent,(HMENU)ID_COMBOBOX, hInstance,NULL); - SetParent(hComboWnd,hwndTB); - hFontNew = CreateFontIndirect(&logfont); - SendMessage(hComboWnd,WM_SETFONT,(WPARAM)hFontNew, - MAKELPARAM(1,0)); - - /* Add tooltip for combo box */ - ZeroMemory(&ti,sizeof(TOOLINFO)); - ti.cbSize = sizeof(TOOLINFO); - ti.uFlags = TTF_IDISHWND|TTF_CENTERTIP|TTF_SUBCLASS; - ti.hwnd = hwndTB;; - ti.uId = (UINT_PTR)hComboWnd; - ti.lpszText = LPSTR_TEXTCALLBACK; - hwndTT = (HWND)SendMessage(hwndTB,TB_GETTOOLTIPS,0,0); - SendMessage(hwndTT,TTM_ADDTOOL,0,(LPARAM)&ti); - - return hwndTB; -} - -static void -window_title(struct title_buf *tbuf) -{ - int res, i; - size_t bufsz = TITLE_BUF_SZ; - unsigned char charbuff[TITLE_BUF_SZ]; - - res = erl_drv_getenv("ERL_WINDOW_TITLE", charbuff, &bufsz); - if (res < 0) - tbuf->name = erlang_window_title; - else if (res == 0) { - for (i = 0; i < bufsz; ++i) { - tbuf->buf[i] = charbuff[i]; - } - tbuf->buf[bufsz - 1] = 0; - tbuf->name = &tbuf->buf[0]; - } else { - char *buf = ALLOC(bufsz); - if (!buf) - tbuf->name = erlang_window_title; - else { - while (1) { - char *newbuf; - res = erl_drv_getenv("ERL_WINDOW_TITLE", buf, &bufsz); - if (res <= 0) { - if (res == 0) { - TCHAR *wbuf = ALLOC(bufsz *sizeof(TCHAR)); - for (i = 0; i < bufsz ; ++i) { - wbuf[i] = buf[i]; - } - wbuf[bufsz - 1] = 0; - FREE(buf); - tbuf->name = wbuf; - } else { - tbuf->name = erlang_window_title; - FREE(buf); - } - break; - } - newbuf = REALLOC(buf, bufsz); - if (newbuf) - buf = newbuf; - else { - tbuf->name = erlang_window_title; - FREE(buf); - break; - } - } - } - } -} - -static void -free_window_title(struct title_buf *tbuf) -{ - if (tbuf->name != erlang_window_title && tbuf->name != &tbuf->buf[0]) - FREE(tbuf->name); -} diff --git a/erts/emulator/drivers/win32/win_con.h b/erts/emulator/drivers/win32/win_con.h deleted file mode 100644 index 7a642cd7edb7..000000000000 --- a/erts/emulator/drivers/win32/win_con.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2007-2016. 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% - */ - -/* - * External API for the windows console (aka werl window) - * used by ttsl_drv.c - */ -#ifndef _WIN_CON_H_VISITED -#define _WIN_CON_H_VISITED 1 -void ConNormalExit(void); -void ConWaitForExit(void); -void ConSetCtrlHandler(BOOL (WINAPI *handler)(DWORD)); -int ConPutChar(Uint32 c); -void ConSetCursor(int from, int to); -void ConPrintf(char *format, ...); -void ConVprintf(char *format, va_list va); -void ConBeep(void); -int ConReadInput(Uint32 *data, int nbytes); -int ConGetKey(void); -int ConGetColumns(void); -int ConGetRows(void); -void ConInit(void); -#endif /* _WIN_CON_H_VISITED */ diff --git a/erts/emulator/internal_doc/AutomaticYieldingOfCCode.md b/erts/emulator/internal_doc/AutomaticYieldingOfCCode.md index 1497c9564203..9ee24595d8e8 100644 --- a/erts/emulator/internal_doc/AutomaticYieldingOfCCode.md +++ b/erts/emulator/internal_doc/AutomaticYieldingOfCCode.md @@ -50,7 +50,7 @@ The source code of YCF is included in the folder the Erlang/OTP system. The documentation of YCF can be found in `"$ERL_TOP"/erts/lib_src/yielding_c_fun/README.md`. A rendered version of YCF documentation can be found -[here](https://github.com/erlang/otp/erts/lib_src/yielding_c_fun/README.md). +[here](https://github.com/erlang/otp/blob/master/erts/lib_src/yielding_c_fun/README.md). Yielding C Fun in the Erlang Run-time System ------------------------------------------- @@ -69,7 +69,7 @@ Best Practices for YCF in the ERTS First of all, before starting to use YCF it is recommended to read through its documentation in -[erts/lib_src/yielding_c_fun/README.md](https://github.com/erlang/otp/erts/lib_src/yielding_c_fun/README.md) +[erts/lib_src/yielding_c_fun/README.md](https://github.com/erlang/otp/blob/master/erts/lib_src/yielding_c_fun/README.md) to understand what limitations and functionalities YCF has. ### Mark YCF Transformed Functions @@ -114,7 +114,7 @@ If a function `F1` that is transformed by one YCF invocation depends on a function `F2` that is transformed by another YCF invocation, one needs to tell YCF that `F2` is an YCF transformed function so that `F1` can call the transformed version (see the documentation of -`-fexternal` in [YCF's documentation](https://github.com/erlang/otp/erts/lib_src/yielding_c_fun/README.md) +`-fexternal` in [YCF's documentation](https://github.com/erlang/otp/blob/master/erts/lib_src/yielding_c_fun/README.md) for more information about how to do that). diff --git a/erts/emulator/internal_doc/BeamAsm.md b/erts/emulator/internal_doc/BeamAsm.md index 3b4ac619ce43..8417210be508 100644 --- a/erts/emulator/internal_doc/BeamAsm.md +++ b/erts/emulator/internal_doc/BeamAsm.md @@ -1,10 +1,11 @@ # BeamAsm, the Erlang JIT BeamAsm provides load-time conversion of Erlang BEAM instructions into -native code on x86-64. This allows the loader to eliminate any instruction -dispatching overhead and also specialize each instruction on their argument types. +native code on x86-64 and aarch64. This allows the loader to eliminate any +instruction dispatching overhead and also specialize each instruction on their +argument types. -BeamAsm does hardly any cross instruction optimizations and the x and y +BeamAsm does hardly any cross instruction optimizations and the `x` and `y` register arrays work the same as when interpreting BEAM instructions. This allows the Erlang run-time system to be largely unchanged except for places that need to work with loaded BEAM instructions like code loading, @@ -14,7 +15,8 @@ BeamAsm uses [asmjit](https://github.com/asmjit/asmjit) to generate native code in run-time. Only small parts of the [Assembler API](https://asmjit.com/doc/group__asmjit__assembler.html) of [asmjit](https://github.com/asmjit/asmjit) is used. At the moment -[asmjit](https://github.com/asmjit/asmjit) only supports x86 32/64 bit assembler. +[asmjit](https://github.com/asmjit/asmjit) only supports x86 32/64 bit and +aarch64 assembler. ## Loading Code @@ -25,12 +27,12 @@ used in BeamAsm are much simpler than the interpreter's, as most of the transformations for the interpreter are done only to eliminate the instruction dispatch overhead. -Then each instruction is encoded using the C++ functions in the jit/instr_*.cpp files. -Example: +Then each instruction is encoded using the C++ functions in the +`jit/$ARCH/instr_*.cpp` files. For example: void BeamModuleAssembler::emit_is_nonempty_list(const ArgVal &Fail, const ArgVal &Src) { a.test(getArgRef(Src), imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST)); - a.jne(labels[Fail.getValue()]); + a.jne(labels[Fail.getLabel()]); } [asmjit](https://github.com/asmjit/asmjit) provides a fairly straightforward @@ -44,11 +46,14 @@ common patterns. The original register allocation done by the Erlang compiler is used to manage the liveness of values and the physical registers are statically allocated to keep -the necessary process state. At the moment this is the static register allocation: +the necessary process state. At the moment this is the static register +allocation on x86-64: rbx: ErtsSchedulerRegisters struct (contains x/float registers and some metadata) - rbp: Active code index - r12: Optional Save slot for the Erlang stack pointer when executing C code + rbp: Current frame pointer when `perf` support is enabled, otherwise this + is an optional save slot for the Erlang stack pointer when executing C + code. + r12: Active code index r13: Current running process r14: Remaining reductions r15: Erlang heap pointer @@ -82,13 +87,12 @@ For instance, the return instruction looks something like this: Label yield = a.newLabel(); - a.dec(FCALLS); /* Decrement reduction counter */ - a.jl(dispatch_return); /* Check if we should yield */ + /* Decrement reduction counter */ + a.dec(FCALLS); + /* If FCALLS < 0, jump to the yield-on-return fragment */ + a.jl(resolve_fragment(ga->get_dispatch_return())); a.ret(); - a.bind(yield); - abs_jmp(ga->get_dispatch_return()); - The code above is not exactly what is emitted, but close enough. The thing to note is that the code for doing the context switch is never emitted. Instead, we jump to a global fragment that all return instructions share. This greatly reduces @@ -132,6 +136,23 @@ handlers even when we lack a stack frame. This is merely a reservation and has no effect on how the stack works, and all values stored there must be valid Erlang terms in case of a garbage collection. +## Frame pointers + +To aid debuggers and sampling profilers, we support running Erlang code with +native frame pointers. At the time of writing, this is only enabled together +with `perf` support (`+JPperf true`) to save stack space, but we may add a flag +to explicitly enable it in the future. + +When enabled, continuation pointers (CP) have both a return address _and_ a +frame pointer that points at the previous CP. CPs must form a valid chain at +all times, and it's illegal to have "half" a CP when the stack is inspected. + +Frame pointers are pushed when entering an Erlang function and popped before +leaving it, including on tail calls as the callee will immediately push the +frame pointer on entry. This has a slight overhead but saves us the headache of +having multiple entry points for each function depending on whether it's tail- +or body-called, which would get very tricky once breakpoints enter the picture. + ## Running C code As Erlang stacks can be very small, we have to switch over to a different stack @@ -163,39 +184,31 @@ All combinations of the `Update` constants are legal, but the ones given to ## Tracing and NIF Loading To make tracing and NIF loading work there needs to be a way to intercept -any function call. In the interpreter, this is done by rewriting the loaded BEAM code, -but this is more complicated in BeamAsm as we want to have a fast and compact way to -do this. This is solved by emitting the code below at the start of each function: +any function call. In the interpreter, this is done by rewriting the loaded +BEAM code, but this is more complicated in BeamAsm as we want to have a fast +and compact way to do this. This is solved by emitting the code below at the +start of each function (x86 variant below): - 0x0: jmp 6 - 0x2: ERTS_ASM_BP_FLAG_NONE - 0x3: relative near call - 0x4: &genericBPTramp - 0x8: actual code for the function + 0x0: short jmp 6 (address 0x8) + 0x2: nop + 0x3: relative near call to shared breakpoint fragment + 0x8: actual code for function -When code starts to execute it will simply see the `jmp 6` instruction +When code starts to execute it will simply see the `short jmp 6` instruction which skips the prologue and starts to execute the code directly. -When we want to enable a certain break point we set the `jmp` target to -be 1 (which means it will land on the call instruction) and will call -genericBPTramp. genericBPTramp is a label at the top of each module -that contains [trampolines][1] for all flag combinations. - -[1]: https://en.wikipedia.org/wiki/Trampoline_(computing) +When we want to enable a certain breakpoint we set the jmp target to be 1, +which means it will land on the call to the shared breakpoint fragment. This +fragment checks the current `breakpoint_flag` stored in the ErtsCodeInfo of +this function, and then calls `erts_call_nif_early` and +`erts_generic_breakpoint` accordingly. - genericBPTramp: +Note that the update of the branch and `breakpoint_flag` does not need to be +atomic: it's fine if a process only sees one of these being updated, as the +code that sets breakpoints/loads NIFs doesn't rely on the trampoline being +active until thread progress has been made. - 0x0: ret - 0x10: jmp call_nif_early - 0x20: call generic_bp_local - 0x30: call generic_bp_local - 0x35: jmp call_nif_early - -Note that each target is 16 byte aligned. This is because the call target -in the function prologue is updated to target the correct place when a flag -is updated. So if CALL\_NIF\_EARLY is set, then it is updated to be -genericBPTramp + 0x10. If BP is set, it is updated to genericBPTramp + 0x20 -and the combination makes it to be genericBPTramp + 0x30. +The solution for AArch64 is similar. ### Updating code @@ -205,25 +218,32 @@ executable page and once with a writable page. Since they're backed by the same memory, writes to the writable page appear magically in the executable one. -The `erts_writable_code_ptr` function can be used to get writable pointers, -given a module instance: +The `erts_writable_code_ptr` function can be used to get writable pointers +given a module instance, provided that it has been unsealed first: - for (i = 0; i < n; ++i) { - ErtsCodeInfo* ci; + for (i = 0; i < n; i++) { + const ErtsCodeInfo* ci_exec; + ErtsCodeInfo* ci_rw; void *w_ptr; - w_ptr = erts_writable_code_ptr(&modp->curr, - code_hdr->functions[i]); - ci = (ErtsCodeInfo*)w_ptr; + erts_unseal_module(&modp->curr); + + ci_exec = code_hdr->functions[i]; + w_ptr = erts_writable_code_ptr(&modp->curr, ci_exec); + ci_rw = (ErtsCodeInfo*)w_ptr; - uninstall_breakpoint(ci); - consolidate_bp_data(modp, ci, 1); - ASSERT(ci->u.gen_bp == NULL); + uninstall_breakpoint(ci_rw, ci_exec); + consolidate_bp_data(modp, ci_rw, 1); + ASSERT(ci_rw->gen_bp == NULL); + + erts_seal_module(&modp->curr); } Without the module instance there's no reliable way to figure out the writable address of a code page, and we rely on _address space layout randomization_ -(ASLR) to make it difficult to guess. +(ASLR) to make it difficult to guess. On some platforms, security is further +enhanced by protecting the writable area from writes until the module has been +unsealed by `erts_unseal_module`. ### Export tracing @@ -238,11 +258,11 @@ means that all remote calls _must_ place the export entry in said register, even when we don't know beforehand that the call is remote, such as when calling a fun. -This is pretty easy to do in assembler and the `emit_setup_export_call` helper -handles it nicely for us, but we can't set registers when trapping out from C -code. When trapping to an export entry from C code one must set `c_p->current` -to the `ErtsCodeMFA` inside the export entry in question, and then set `c_p->i` -to `beam_bif_export_trap`. +This is pretty easy to do in assembler and the `emit_setup_dispatchable_call` +helper handles it nicely for us, but we can't set registers when trapping out +from C code. When trapping to an export entry from C code one must set +`c_p->current` to the `ErtsCodeMFA` inside the export entry in question, and +then set `c_p->i` to `beam_bif_export_trap`. The `BIF_TRAP` macros handle this for you, so you generally don't need to think about it. @@ -254,54 +274,69 @@ think about it. The BeamAsm implementation resides in the `$ERL_TOP/erts/emulator/beam/jit` folder. The files are: -* `load.h` - * BeamAsm specific header for loading code * `asm_load.c` * BeamAsm specific functions for loading code -* `generators.tab`, `predicates.tab`, `ops.tab` - * BeamAsm specific transformations for instructions. See [beam_makeops](beam_makeops) for - more details. * `beam_asm.h` * Header file describing the C -> C++ api -* `beam_asm.hpp` +* `beam_jit_metadata.cpp` + * `gdb` and Linux `perf` support for BeamAsm +* `load.h` + * BeamAsm specific header for loading code +* `$ARCH/beam_asm.hpp` * Header file describing the structs and classes used by BeamAsm. -* `beam_asm.cpp` - * Implementation of the main process loop +* `$ARCH/beam_asm.cpp` * The BeamAsm initialization code * The C -> C++ interface functions. -* `beam_asm_module.cpp` +* `$ARCH/generators.tab`, `$ARCH/predicates.tab`, `$ARCH/ops.tab` + * BeamAsm specific transformations for instructions. See + [beam_makeops](beam_makeops) for more details. +* `$ARCH/beam_asm_module.cpp` * The code for the BeamAsm module code generator logic -* `beam_asm_global.cpp` - * Global code fragments that are used by multiple instructions, e.g. error handling code. -* `instr_*.cpp` +* `$ARCH/beam_asm_global.cpp` + * Global code fragments that are used by multiple instructions, e.g. error + handling code. +* `$ARCH/instr_*.cpp` * Implementation of individual instructions grouped into files by area -* `beam_asm_perf.cpp` - * The linux perf support for BeamAsm +* `$ARCH/process_main.cpp` + * Implementation of the main process loop ## Linux perf support -perf can also be instrumented using BeamAsm symbols to provide more information. As with -gdb, only the currently executing function will show up in the stack trace, which means -that perf provides functionality similar to that of [eprof](https://erlang.org/doc/man/eprof.html). +The JIT can provide symbols to the Linux profiler `perf`, making it possible to +profile Erlang code with it. Depending on the mode used, `perf` will provide +functionality similar to [eprof](https://erlang.org/doc/man/eprof.html) or +[fprof](https://erlang.org/doc/man/fprof.html) but with much lower (and +configurable) overhead. You can run perf on BeamAsm like this: - perf record erl +JPperf true + # Start Erlang under perf + perf record -- erl +JPperf true + # Record a running instance started with `+JPperf true` for 10s + perf record --pid $BEAM_PID -- sleep 10 + # Record a running instance started with `+JPperf true` until interrupted + perf record --pid $BEAM_PID -and then look at the results using `perf report` as you normally would with perf. +and then look at the results using `perf report` as you normally would with +perf. + +Frame pointers are enabled when the `+JPperf true` option is passed, so you can +use `perf record --call-graph=fp` to get more context, making the results +similar to that of `fprof`. This will give you accurate call graphs for pure +Erlang code, but in rare cases it fails to track transitions from Erlang to C +code and back. [`perf record --call-graph=lbr`](https://lwn.net/Articles/680985/) +may work better in those cases, but it's worse at tracking in general. -If you want to get some context to you calls you cann use the [lbr](https://lwn.net/Articles/680985/) -call-graph option to `perf record`. Using `lbr` is not perfect (for instance you -do not get any syscalls in the context), but it work well enough. For example, you can run perf to analyze dialyzer building a PLT like this: - ERL_FLAGS="+JPperf true +S 1" perf record --call-graph lbr \ + ERL_FLAGS="+JPperf true +S 1" perf record --call-graph=fp \ dialyzer --build_plt -Wunknown --apps compiler crypto erts kernel stdlib \ syntax_tools asn1 edoc et ftp inets mnesia observer public_key \ sasl runtime_tools snmp ssl tftp wx xmerl tools The above code is run using `+S 1` to make the perf output easier to understand. -If you then run `perf report -f --no-children` you may get something similar to this: +If you then run `perf report -f --no-children` you may get something similar to +this: ![Linux Perf report: dialyzer PLT build](figures/perf-beamasm.png) @@ -315,10 +350,10 @@ By expanding it and looking at its parents we can see that it is the function at it in the source code to see if you can figure out why so much time is spent there. After `eq` we see the function `erl_types:t_has_var/1` where we spend almost -6% of the entire execution in. A while further down you can see `copy_struct` which -is the function used to copy terms. If we expand it to view the parents we find that -it is mostly `ets:lookup_element/3` that contributes to this time via the Erlang -function `dialyzer_plt:ets_table_lookup/2`. +5% of the entire execution in. A while further down you can see `copy_struct_x` +which is the function used to copy terms. If we expand it to view the parents +we find that it is mostly `ets:lookup_element/3` that contributes to this time +via the Erlang function `dialyzer_plt:ets_table_lookup/2`. ### Flame Graph @@ -328,12 +363,12 @@ be more easily shared with others and manipulated to give a graph tailor-made fo your needs. For instance, if we run dialyzer with all schedulers: ## Run dialyzer with multiple schedulers - ERL_FLAGS="+JPperf true" perf record --call-graph lbr \ + ERL_FLAGS="+JPperf true" perf record --call-graph=fp \ dialyzer --build_plt -Wunknown --apps compiler crypto erts kernel stdlib \ syntax_tools asn1 edoc et ftp inets mnesia observer public_key \ sasl runtime_tools snmp ssl tftp wx xmerl tools --statistics -And then use the scripts found at Brendan Gregg's [CPU Flame Graphs](http://www.brendangregg.com/FlameGraphs/cpuflamegraphs) +And then use the scripts found at Brendan Gregg's [CPU Flame Graphs](https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html) web page as follows: ## Collect the results @@ -354,8 +389,9 @@ not need the symbols in the executable. Using the same data we can also produce a graph where the scheduler profile data has been merged by using `sed`: - ## Strip [0-9]+_ from all scheduler names - sed -e 's/^[0-9]\+_//' out.folded > out.folded_sched + ## Strip [0-9]+_ and/or _[0-9]+ from all scheduler names + ## scheduler names changed in OTP26, hence two expressions + sed -e 's/^[0-9]\+_//' -e 's/^erts_\([^_]\+\)_[0-9]\+/erts_\1/' out.folded > out.folded_sched ## Create the svg flamegraph.pl out.folded_sched > out_sched.svg @@ -367,12 +403,12 @@ you what you want. ### Annotate perf functions -If you want to be able to use the `perf annotate` functionality (and in extention +If you want to be able to use the `perf annotate` functionality (and in extension the annotate functionality in the `perf report` gui) you need to use a monotonic clock when calling `perf record`, i.e. `perf record -k mono`. So for a dialyzer run you would do this: - ERL_FLAGS="+JPperf true +S 1" perf record -k mono --call-graph lbr \ + ERL_FLAGS="+JPperf true +S 1" perf record -k mono --call-graph=fp \ dialyzer --build_plt -Wunknown --apps compiler crypto erts kernel stdlib \ syntax_tools asn1 edoc et ftp inets mnesia observer public_key \ sasl runtime_tools snmp ssl tftp wx xmerl tools @@ -390,10 +426,40 @@ or by pressing `a` in the `perf report` ui. Then you get something like this: ![Linux Perf FlameGraph: dialyzer PLT build](figures/beamasm-perf-annotate.png) +`perf annotate` will interleave the listing with the original source code +whenever possible. You can use the `+{source,Filename}` or `+absolute_paths` +compiler options to tell `perf` where to find the source code. + > *WARNING*: Calling `perf inject --jit` will create a lot of files in `/tmp/` > and in `~/.debug/tmp/`. So make sure to cleanup in those directories from time to > time or you may run out of inodes. +### Inspecting perf data on another host + +Sometimes it's not possible or desirable to inspect a recording on the target +machine, which gets a bit tricky because `perf report` relies on having all +symbols available. + +To inspect recordings on another machine, you can use the `perf archive` +command to bundle all the required symbols into an archive. This requires that +the recording is made with the `-k mono` flag and that it has been processed +with `perf inject --jit`: + + perf inject --jit -i perf.data -o perf.jitted.data + perf archive perf.jitted.data + +Once you have the archive, move it together with the processed recording to +the host you wish to inspect the recording on, and extract the archive to +`~/.debug`. You can then use `perf report -i perf.jitted.data` as usual. + +If you get an error message along the lines of: + + perf: 'archive' is not a perf-command. See 'perf --help'. + +Then your `perf` version is too old, and you should use +[this bash script](https://github.com/torvalds/linux/blob/master/tools/perf/perf-archive.sh) +instead. + ### perf tips and tricks You can do a lot of neat things with `perf`. Below is a list of some of the options @@ -403,12 +469,8 @@ we have found useful: Do not include the accumulation of all children in a call. * `perf report --call-graph callee` Show the callee rather than the caller when expanding a function call. -* `perf archive` - Create an archive with all the artifacts needed to inspect the data - on another host. In early version of perf this command does not work, - instead you can use [this bash script](https://github.com/torvalds/linux/blob/master/tools/perf/perf-archive.sh). * `perf report` gives "failed to process sample" and/or "failed to process type: 68" - This probably means that you are running a bugge version of perf. We have + This probably means that you are running a bugged version of perf. We have seen this when running Ubuntu 18.04 with kernel version 4. If you update to Ubuntu 20.04 or use Ubuntu 18.04 with kernel version 5 the problem should go away. @@ -420,11 +482,11 @@ we have found useful: You will see a banner containing `[jit]` shell when you start. You can also use `erlang:system_info(emu_flavor)` to check the flavor and it should be `jit`. -There are three major reasons why when building Erlang/OTP you would not get the JIT. +There are two major reasons why when building Erlang/OTP you would not get the +JIT. -* You are not building x86 64-bit +* You are not building a 64-bit emulator for x86 or ARM * You do not have a C++ compiler that supports C++-17 -* You do not have an OS that supports executable *and* writable memory If you run `./configure --enable-jit` configure will abort when it discovers that your system cannot build the JIT. @@ -448,29 +510,24 @@ when that happens. One such could be very short-lived small scripts. If you come any scenarios when this happens, please open a bug report at [the Erlang/OTP bug tracker](https://github.com/erlang/otp/issues). -### Would it be possible to add support for BeamAsm on ARM? +### Would it be possible to add support for BeamAsm on other CPU architectures? Any new architecture needs support in the assembler as well. Since we use [asmjit](https://github.com/asmjit/asmjit) for this, that means we need support in [asmjit](https://github.com/asmjit/asmjit). BeamAsm uses relatively few -instructions (mostly, `mov`, `jmp`, `cmp`, `sub`, `add`), so it would not need to have -full support of all ARM instructions. +instructions (mostly, `mov`, `jmp`, `cmp`, `sub`, `add`), so it would not need +to have full support of all instructions. Another approach would be to not use [asmjit](https://github.com/asmjit/asmjit) -for ARM, but instead, use something different to assemble code during load-time. +for the new architecture, but instead use something different to assemble code +during load-time. ### Would it be possible to add support for BeamAsm on another OS? -Adding a new OS that runs x86-64 should not need any large changes if -the OS supports mapping of memory as executable. If the ABI used by the +Adding a new OS that runs x86-64 or aarch64 should not need any large changes +if the OS supports mapping of memory as executable. If the ABI used by the OS is not supported changes related to calling C-functions also have to be made. -As a reference, it took us about 2-3 weeks to implement support for Windows. - -### Would it be possible to add support in perf to better crawl the Erlang stack? - -Yes, though not easily. - -Using `perf --call-graph lbr` works for Erlang, but it does not give a -perfect record as the buffer has a limited size. +As a reference, it took us about 2-3 weeks to implement support for Windows, +and about three months to finish the aarch64 port. diff --git a/erts/emulator/internal_doc/CodeLoading.md b/erts/emulator/internal_doc/CodeLoading.md index cfdc1bf30ab3..83d3d8048bba 100644 --- a/erts/emulator/internal_doc/CodeLoading.md +++ b/erts/emulator/internal_doc/CodeLoading.md @@ -41,8 +41,8 @@ only be done by one loader process at a time. A second loader process trying to enter finishing phase will be suspended until the first loader is done. This will only block the process, the scheduler is free to schedule other work while the second loader is waiting. (See -`erts_try_seize_code_write_permission` and -`erts_release_code_write_permission`). +`erts_try_seize_code_load_permission` and +`erts_release_code_load_permission`). The ability to prepare several modules in parallel is not currently used as almost all code loading is serialized by the code\_server @@ -56,7 +56,7 @@ different modules and returns a "magic binary" containing the internal state of each prepared module. Function `finish_loading` could take a list of such states and do the finishing of all of them in one go. -Currenlty we use the legacy BIF `erlang:load_module` which is now +Currently we use the legacy BIF `erlang:load_module` which is now implemented in Erlang by calling the above two functions in sequence. Function `finish_loading` is limited to only accepts a list with one module state as we do not yet use the multi module loading @@ -101,7 +101,7 @@ result of a half loaded module. The finishing phase is carried out in the following sequence by the BIF `erlang:finish_loading`: -1. Seize exclusive code write permission (suspend process if needed +1. Seize exclusive code load permission (suspend process if needed until we get it). 2. Make a full copy of all the active access structures. This copy is @@ -119,7 +119,7 @@ BIF `erlang:finish_loading`: 6. After thread progress, commit the staging area by assigning `the_staging_code_index` to `the_active_code_index`. -7. Release the code write permission allowing other processes to stage +7. Release the code load permission allowing other processes to stage new code. 8. Resume the loader process allowing it to return from diff --git a/erts/emulator/internal_doc/DelayedDealloc.md b/erts/emulator/internal_doc/DelayedDealloc.md index 4b7c7741410d..8a86a70b1073 100644 --- a/erts/emulator/internal_doc/DelayedDealloc.md +++ b/erts/emulator/internal_doc/DelayedDealloc.md @@ -89,7 +89,7 @@ same location in memory. The head contains pointers to beginning of the list (`head.first`), and to the first block which other threads may refer to -(`head.unref_end`). Blocks between these pointers are only refered to +(`head.unref_end`). Blocks between these pointers are only referred to by the head part of the data structure which is only used by the thread owning the allocator instance. When these two pointers are not equal the thread owning the allocator instance deallocate block after @@ -137,7 +137,7 @@ If no new memory blocks are inserted into the list, it should eventually be emptied. All pointers to the list however expect to always point to something. This is solved by inserting an empty "marker" element, which only has to purpose of being there in the -absense of other elements. That is when the list is empty it only +absence of other elements. That is when the list is empty it only contains this "marker" element. ### Contention ### diff --git a/erts/emulator/internal_doc/GarbageCollection.md b/erts/emulator/internal_doc/GarbageCollection.md index a1627b32338a..ae8602bd6849 100644 --- a/erts/emulator/internal_doc/GarbageCollection.md +++ b/erts/emulator/internal_doc/GarbageCollection.md @@ -35,7 +35,7 @@ Compiling this code to beam assembly (`erlc -S`) shows exactly what is happening Looking at the assembler code we can see three things: The heap requirement in this function turns out to be only six words, as seen by the `{test_heap,6,1}` instruction. All the allocations are combined to a single instruction. The bulk of the data `{text, "hello world!"}` is a *literal*. Literals, sometimes referred to as constants, are not allocated in the function since they are a part of the module and allocated at load time. -If there is not enough space available on the heap to satisfy the `test_heap` instructions request for memory, then a garbage collection is initiated. It may happen immediately in the `test_heap` instruction, or it can be delayed until a later time depending on what state the process is in. If the garbage collection is delayed, any memory needed will be allocated in heap fragments. Heap fragments are extra memory blocks that are a part of the young heap, but are not allocated in the contigious area where terms normally reside. See [The young heap](#the-young-heap) for more details. +If there is not enough space available on the heap to satisfy the `test_heap` instructions request for memory, then a garbage collection is initiated. It may happen immediately in the `test_heap` instruction, or it can be delayed until a later time depending on what state the process is in. If the garbage collection is delayed, any memory needed will be allocated in heap fragments. Heap fragments are extra memory blocks that are a part of the young heap, but are not allocated in the contiguous area where terms normally reside. See [The young heap](#the-young-heap) for more details. ### The collector @@ -171,7 +171,7 @@ There are a bunch of different tradeoffs that come into play when trying to figu Using `off_heap` may seem like a nice way to get a more scalable system as you get very little contention on the main locks, however, allocating a heap fragment is more expensive than allocating on the heap of the receiving process. So if it is very unlikely that contention will occur, it is more efficient to try to allocate the message directly on the receiving process' heap. -Using `on_heap` will force all messages to be part of on the young heap which will increase the amount of data that the garbage collector has to move. So if a garbage collection is triggered while processing a large amount of messages, they will be copied to the young heap. This in turn will lead to that the messages will quickly be promoted to the old heap and thus increase its size. This may be good or bad depending on exactly what the process does. A large old heap means that the young heap will also be larger, which in turn means that less garbage collections will be triggered while processing the message queue. This will temporarly increase the throughput of the process at the cost of more memory usage. However, if after all the messages have been consumed the process enters a state where a lot less messages are being received. Then it may be a long time before the next fullsweep garbage collection happens and the messages that are on the old heap will be there until that happens. So while `on_heap` is potentially faster than the other modes, it uses more memory for a longer time. This mode is the legacy mode which is almost how the message queue was handled before Erlang/OTP 19.0. +Using `on_heap` will force all messages to be part of on the young heap which will increase the amount of data that the garbage collector has to move. So if a garbage collection is triggered while processing a large amount of messages, they will be copied to the young heap. This in turn will lead to that the messages will quickly be promoted to the old heap and thus increase its size. This may be good or bad depending on exactly what the process does. A large old heap means that the young heap will also be larger, which in turn means that less garbage collections will be triggered while processing the message queue. This will temporarily increase the throughput of the process at the cost of more memory usage. However, if after all the messages have been consumed the process enters a state where a lot less messages are being received. Then it may be a long time before the next fullsweep garbage collection happens and the messages that are on the old heap will be there until that happens. So while `on_heap` is potentially faster than the other modes, it uses more memory for a longer time. This mode is the legacy mode which is almost how the message queue was handled before Erlang/OTP 19.0. Which one of these strategies is best depends a lot on what the process is doing and how it interacts with other processes. So, as always, profile the application and see how it behaves with the different options. diff --git a/erts/emulator/internal_doc/PTables.md b/erts/emulator/internal_doc/PTables.md index ef61963a40f8..6b316eaa7e76 100644 --- a/erts/emulator/internal_doc/PTables.md +++ b/erts/emulator/internal_doc/PTables.md @@ -113,7 +113,7 @@ the "thread progress" functionality in order to determine when it is safe to deallocate the process structure. We'll get back to this when describing deletion in the table. -Using this new lookup approach we wont modify any memory at all which +Using this new lookup approach we won't modify any memory at all which is important. A lookup conceptually only read memory, now this is true in the implementation also which is important from a scalability perspective. The previous implementation modified the cache line @@ -282,7 +282,7 @@ single cache line containing the state of the rwlock even in the case we are only read locking. Instead of using such an rwlock, we have our own implementation of reader optimized rwlocks which keeps track of reader threads in separate thread specific cache lines. This in order -to avoid contention on a singe cache line. As long as we only do read +to avoid contention on a single cache line. As long as we only do read lock operations, threads only need to read a global cache line and modify its own cache line, and by this minimize communication between involved processors. The iterating BIFs are normally very infrequently @@ -299,7 +299,7 @@ threads modify the table at the same time as we are trying to find the slot. The easy fix is to abort the operation if an empty slot could not be found in a finite number operation, and then restart the operation under a write lock. This will be implemented in next -release, but furter work should be made trying to find a better +release, but further work should be made trying to find a better solution. This and also previous implementation do not work well when the table @@ -320,7 +320,7 @@ not require exclusive access to the table while reading a sequence of slots. In principle this should be rather easy, the code can handle sequences of variable sizes, so shrinking the sequence size of slots to one would solv the problem. This will, however, need some tweeks -and modifications of not trival code, but is something that should be +and modifications of not trivial code, but is something that should be looked at in the future. By increasing the size of identifiers, at least on 64-bit machines diff --git a/erts/emulator/internal_doc/PortSignals.md b/erts/emulator/internal_doc/PortSignals.md index 8782ae4e17a1..f2490152caed 100644 --- a/erts/emulator/internal_doc/PortSignals.md +++ b/erts/emulator/internal_doc/PortSignals.md @@ -108,7 +108,7 @@ and a private, lock free, queue like, task data structure. This "semi locked" approach is similar to how the message boxes of processes are managed. The lock is port specific and only used for protection of port tasks, so the run queue lock is now needed in more or less the -same way for ports as for processes. This ensures that we wont see an +same way for ports as for processes. This ensures that we won't see an increased lock contention on run queue locks due to this rewrite of the port functionality. @@ -211,7 +211,7 @@ consuming, and did not really depend on the port. That is we would like to do this without having the port lock locked. In order to improve this, state information was re-organized in the -port structer, so that we can access it using atomic memory +port structure, so that we can access it using atomic memory operations. This together with the new port table implementation, enabled us to lookup the port and inspect the state before acquiring the port lock, which in turn made it possible to perform preparations diff --git a/erts/emulator/internal_doc/SuperCarrier.md b/erts/emulator/internal_doc/SuperCarrier.md index f52c6613d5eb..55ac5a67afc8 100644 --- a/erts/emulator/internal_doc/SuperCarrier.md +++ b/erts/emulator/internal_doc/SuperCarrier.md @@ -12,7 +12,7 @@ Problem ------- The initial motivation for this feature was customers asking for a way -to pre-allocate physcial memory at VM start for it to use. +to pre-allocate physical memory at VM start for it to use. Other problems were different experienced limitations of the OS implementation of mmap: @@ -29,7 +29,7 @@ fragmentation increased. Solution -------- -Allocate one large continious area of address space at VM start and +Allocate one large continuous area of address space at VM start and then use that area to satisfy our dynamic memory need during runtime. In other words: implement our own mmap. @@ -70,7 +70,7 @@ name suggest that it can be viewed as our own mmap implementation. A super carrier needs to satisfy two slightly different kinds of allocation requests; multi block carriers (MBC) and single block -carriers (SBC). They are both rather large blocks of continious +carriers (SBC). They are both rather large blocks of continuous memory, but MBCs and SBCs have different demands on alignment and size. @@ -79,13 +79,13 @@ alignment. MBCs are more restricted. They can only have a number of fixed sizes that are powers of 2. The start address need to have a very -large aligment (currently 256 kb, called "super alignment"). This is a +large alignment (currently 256 kb, called "super alignment"). This is a design choice that allows very low overhead per allocated block in the MBC. To reduce fragmentation within the super carrier, it is good to keep SBCs and MBCs apart. MBCs with their uniform alignment and sizes can be -packed very efficiently together. SBCs without demand for aligment can +packed very efficiently together. SBCs without demand for alignment can also be allocated quite efficiently together. But mixing them can lead to a lot of memory wasted when we need to create large holes of padding to the next alignment limit. @@ -102,9 +102,9 @@ The MBC area is called *sa* as in super aligned and the SBC area is called *sua* as in super un-aligned. Note that the "super" in super alignment and the "super" in super -carrier has nothing to do with each other. We could have choosen +carrier has nothing to do with each other. We could have chosen another naming to avoid confusion, such as "meta" carrier or "giant" -aligment. +alignment. +-------+ <---- sua.top | sua | diff --git a/erts/emulator/internal_doc/ThreadProgress.md b/erts/emulator/internal_doc/ThreadProgress.md index 03a802f9047e..a48b25010480 100644 --- a/erts/emulator/internal_doc/ThreadProgress.md +++ b/erts/emulator/internal_doc/ThreadProgress.md @@ -78,7 +78,7 @@ thread progress operation has been initiated, and at least once ordered using communication via memory which makes it possible to draw conclusion about the memory state after the thread progress operation has completed. Lets call the progress made from initiation to -comletion for "thread progress". +completion for "thread progress". Assuming that the thread progress functionality is efficient, a lot of algorithms can both be simplified and made more efficient than using @@ -120,7 +120,7 @@ communication. We also want threads to be able to determine when thread progress has been made relatively fast. That is we need to have some balance -between comunication overhead and time to complete the operation. +between communication overhead and time to complete the operation. ### API ### @@ -222,7 +222,7 @@ current global value plus one at the time when we call confirmed global value plus two at this time. The above described implementation more or less minimizes the -comunication needed before we can increment the global counter. The +communication needed before we can increment the global counter. The amount of communication in the system due to the thread progress functionality however also depend on the frequency with which managed threads call `erts_thr_progress_update()`. Today each scheduler thread diff --git a/erts/emulator/internal_doc/Tracing.md b/erts/emulator/internal_doc/Tracing.md index 196ae0dd4efa..28c973c26409 100644 --- a/erts/emulator/internal_doc/Tracing.md +++ b/erts/emulator/internal_doc/Tracing.md @@ -1,8 +1,64 @@ -Non-blocking trace setting -========================== - -Introduction ------------- +# Tracing + +## Implementation +### Call, return, and exception tracing + +Tracing is implemented by setting breakpoints in the traced functions, +and sending the appropriate trace messages when they're hit. + +* Call trace messages are sent immediately. +* Return tracing pushes a frame to the stack which _returns to_ an + instruction that sends a trace message when encountered. +* Exception tracing also pushes a frame to the stack, but will only send + a trace message if we encounter it in stack scanning while throwing an + exception. + +This means that one must be careful not to use return or exception tracing +on functions that never return, as each call pushes a frame that will +never be removed. + +Another limitation is that since the breakpoint is in the _callee_ and not +the _caller_, we're limited to the information we have on function ingress. +This means that we can't actually tell who called us: since we're limited +to inspecting the stack we can only say where we're _going to return to_, +which is not quite the same thing. + +As an illustration, when the `caller` option is enabled all trace messages +from `bar/1` will say that they were called from `foo/0`, even though it +went through a bunch of other functions on the way: + + foo() -> + lots(), + ok. + + lots() -> + 'of'(). + + 'of'() -> + indirections(). + + indirections() -> + bar(10). + + bar(0) -> + done; + bar(N) -> + bar(N - 1). + +### Export tracing + +In the interpreter, breakpoints are set inside the code trampoline for +export entries, and their address vector is updated to point to them. +This way, only remote calls will hit the breakpoint while local calls to +the same function are left alone, but it otherwise acts the same way as +local breakpoints. + +Things get a bit more involved in the JIT. See `BeamAsm.md` for more +details. + +## Setting breakpoints + +### Introduction Before OTP R16 when trace settings were changed by `erlang:trace_pattern`, all other execution in the VM were halted while the trace operation @@ -10,15 +66,13 @@ was carried out in single threaded mode. Similar to code loading, this can impose a severe problem for availability that grows with the number of cores. -In OTP R16, trace breakpoints are set in the code without blocking the -VM. Erlang processes may continue executing undisturbed in parallel -during the entire operation. The same base technique is used as for -code loading. A staging area of breakpoints is prepared and then made -active with a single atomic operation. - +In OTP R16, breakpoints are set in the code without blocking the VM. +Erlang processes may continue executing undisturbed in parallel during the +entire operation. The same base technique is used as for code loading. A +staging area of breakpoints is prepared and then made active with a single +atomic operation. -Redesign of Breakpoint Wheel ----------------------------- +### Redesign of Breakpoint Wheel To make it easier to manage breakpoints without single threaded mode a redesign of the breakpoint mechanism has been made. The old @@ -34,9 +88,7 @@ one struct (`GenericBp`) to hold the data for all types of breakpoints for each instrumented function. A bit-flag field is used to indicate what different type of break actions that are enabled. - -Same Same but Different ------------------------ +### Same Same but Different Even though `trace_pattern` use the same technique as the non-blocking code loading with replicated generations of data structures and an @@ -54,8 +106,8 @@ instantaneously without the need of external function calls. The chosen solution is instead for tracing to use the technique of replication applied on the data structures for breakpoints. Two -generations of breakpoints are kept and indentified by index of 0 and -1. The global atomic variables `erts_active_bp_index` will determine +generations of breakpoints are kept and identified by index of 0 and +1\. The global atomic variables `erts_active_bp_index` will determine which generation of breakpoints running code will use. ### Atomicity Without Atomic Operations @@ -70,21 +122,20 @@ guarantee we need is that the written instruction word is seen as atomic. Either fully written or not at all. This is true for word aligned write operation on all hardware architectures we use. - -Adding a new Breakpoint ------------------------ +### Adding a new Breakpoint This is a simplified sequence describing what `trace_pattern` goes through when adding a new breakpoint. -1. Seize exclusive code write permission (suspend process until we get it). +1. Seize exclusive code modification permission (suspend process until we get + it). 2. Allocate breakpoint structure `GenericBp` including both generations. Set the active part as disabled with a zeroed flagfield. Save the original instruction word in the breakpoint. -3. Write a pointer to the breakpoint at offset -4 from the first - instruction "func\_info" header. +3. Write a pointer to the breakpoint at offset `-sizeof(UWord)` from the first + instruction `ErtsFuncInfo` header. 4. Set the staging part of the breakpoint as enabled with specified breakpoint data. @@ -92,25 +143,25 @@ through when adding a new breakpoint. 5. Wait for thread progress. 6. Write a `op_i_generic_breakpoint` as the first instruction for the function. - This instruction will execute the breakpoint that it finds at offset -4. + This instruction will execute the breakpoint that it finds at offset + `-sizeof(UWord)`. 7. Wait for thread progress. -8. Commit the breadpoint by switching `erts_active_bp_index`. +8. Commit the breakpoint by switching `erts_active_bp_index`. 9. Wait for thread progress. 10. Prepare for next call to `trace_pattern` by updating the new staging part (the old active) of the breakpoint to be identic to the the new active part. -11. Release code write permission and return from `trace_pattern`. +11. Release code modification permission and return from `trace_pattern`. -The code write permission "lock" seized in step 1 is the same as used -by code loading. This will ensure that only one process at a time can -stage new trace settings but it will also prevent concurrent code -loading and make sure we see a consistent view of the beam code during -the entire sequence. +The code modification permission "lock" seized in step 1 is also taken by code +loading. This ensures that only one process at a time can stage new trace +settings, and also prevents concurrent codeloading and make sure we see a +consistent view of the beam code during the entire sequence. Between step 6 and 8, runninng processes might execute the written `op_i_generic_breakpoint` instruction. They will get the breakpoint @@ -120,9 +171,7 @@ becomes visible they will however execute the disabled part of the breakpoint structure and do nothing other than executing the saved original instruction. - -To Updating and Remove Breakpoints ----------------------------------- +### To Update and Remove Breakpoints The above sequence did only describe adding a new breakpoint. We do basically the same sequence to update the settings of an existing @@ -137,11 +186,12 @@ original beam instruction. Here is a more complete sequence that contains both adding, updating and removing breakpoints. -1. Seize exclusive code write permission (suspend process until we get it). +1. Seize exclusive code modification permission (suspend process until we get + it). 2. Allocate new breakpoint structures with a disabled active part and the original beam instruction. Write a pointer to the breakpoint in - "func\_info" header at offset -4. + `ErtsFuncInfo` header at offset `-sizeof(UWord)`. 3. Update the staging part of all affected breakpoints. Disable breakpoints that are to be removed. @@ -153,7 +203,7 @@ and removing breakpoints. 6. Wait for thread progress. -7. Commit all staged breadpoints by switching `erts_active_bp_index`. +7. Commit all staged breakpoints by switching `erts_active_bp_index`. 8. Wait for thread progress. @@ -167,8 +217,7 @@ and removing breakpoints. 12. Deallocate disabled breakpoint structures. -13. Release code write permission and return from `trace_pattern`. - +13. Release code modification permission and return from `trace_pattern`. ### All that Waiting for Thread Progress @@ -188,7 +237,7 @@ value of `erts_active_bp_index` at different times as it is read without any memory barrier. But this is the best we can do without more expensive thread synchronization. -The waiting in step 8 is to make sure we dont't restore the original +The waiting in step 8 is to make sure we don't restore the original bream instructions for disabled breakpoints until we know that no thread is still accessing the old enabled part of a disabled breakpoint. @@ -197,9 +246,7 @@ The waiting in step 10 is to make sure no lingering thread is still accessing disabled breakpoint structures to be deallocated in step 12. - -Global Tracing --------------- +### Global Tracing Call tracing with `global` option only affects external function calls. This was earlier handled by inserting a special trace @@ -212,9 +259,7 @@ tracing is that we insert the `op_i_generic_breakpoint` instruction (with its pointer at offset -4) in the export entry rather than in the code. - -Future work ------------ +### Future work We still go to single threaded mode when new code is loaded for a module that is traced, or when loading code when there is a default diff --git a/erts/emulator/internal_doc/beam_makeops.md b/erts/emulator/internal_doc/beam_makeops.md index e93aeac52d83..563ad200f746 100644 --- a/erts/emulator/internal_doc/beam_makeops.md +++ b/erts/emulator/internal_doc/beam_makeops.md @@ -77,13 +77,13 @@ following line: 64: move/2 This is a definition of an external generic BEAM instruction. Most -importantly it specifices that the opcode is 64. It also defines that +importantly it specifies that the opcode is 64. It also defines that it has two operands. The BEAM assembler will use the opcode when creating `.beam` files. The compiler does not really need the arity, but it will use it as an internal sanity check when assembling the BEAM code. -Let's have a look at `ops.tab` in `erts/emulator/beam`, where the +Let's have a look at `ops.tab` in `erts/emulator/beam/emu`, where the specific `move` instructions are defined. Here are a few of them: move x x @@ -98,8 +98,8 @@ an integer, an atom, or a literal). Now let's look at the implementation of the `move` instruction. There are multiple files containing implementations of instructions in the -`erts/emulator/beam` directory. The `move` instruction is defined in -`instrs.tab`. It looks like this: +`erts/emulator/beam/emu` directory. The `move` instruction is defined +in `instrs.tab`. It looks like this: move(Src, Dst) { $Dst = $Src; @@ -122,7 +122,7 @@ layout for the instruction `{move,{atom,id},{x,5}}`: +--------------------+--------------------+ This example and all other examples in the document assumes a 64-bit -archictecture, and furthermore that pointers to C code fit in 32 bits. +architecture, and furthermore that pointers to C code fit in 32 bits. `I` in the BEAM virtual machine is the instruction pointer. When BEAM executes an instruction, `I` points to the first word of the @@ -163,7 +163,7 @@ word. the instruction word. In this example, it will return 40 which is the byte offset for X register 5. The `xb()` macro will cast a byte pointer to an `Eterm` pointer and dereference it. The `I[1]` on -the right side of the `=` fetches an Erlang term (the atom `id` in +the right-hand side of the `=` fetches an Erlang term (the atom `id` in this case). * `I += 2` advances the instruction pointer to the next @@ -231,13 +231,13 @@ to a `move2` instruction: move X1=x Y1=y | move X2=x Y2=y => move2 X1 Y1 X2 Y2 -The left side of the arrow (`=>`) is a pattern. If the pattern +The left-hand side of the arrow (`=>`) is a pattern. If the pattern matches, the matching instructions will be replaced by the -instructions on the right side. Variables in a pattern must start +instructions on the right-hand side. Variables in a pattern must start with an uppercase letter just as in Erlang. A pattern variable may be followed `=` and one or more type letters to constrain the match to -one of those types. The variables that are bound on the left side can -be used on the right side. +one of those types. The variables that are bound on the left-hand side can +be used on the right-hand side. We will also need to define a specific instruction and an implementation: @@ -258,14 +258,15 @@ it will match the new instructions against the transformation rules. Because of that, we can define the rule for a `move3/6` instruction as follows: - move2 X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => \ + move2 X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3 -(A `\` before a newline can be used to break a long line for readability.) +(For readability, a long transformation line can be broken after `|` +and `=>` operators.) It would also be possible to define it like this: - move X1=x Y1=y | move X2=x Y2=y | move X3=x Y3=y => \ + move X1=x Y1=y | move X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3 but in that case it must be defined before the rule for `move2/4` @@ -298,7 +299,7 @@ keep multiple generic instructions in a linked list. * The loader tries to apply transformation rules against the generic instructions in the linked list. If a rule matches, the matched instructions will be removed and replaced with new -generic instructions constructed from the right side of the +generic instructions constructed from the right-hand side of the transformation. * If a transformation rule matched, the loader applies the @@ -322,7 +323,7 @@ in the code area for the module being loaded. * The loader translates each operand to a machine word and stores it in the code area. The operand type for the selected specific instruction guides the translation. For example, if the type is `e`, -the value of the operand is an index into an arry of external +the value of the operand is an index into an array of external functions and will be translated to a pointer to the export entry for the function to call. If the type is `x`, the number of the X register will be multiplied by the word size to produce a byte offset. @@ -369,7 +370,7 @@ The following files will be written to the output directory: * `beam_opcode.hrl` - Used by `beam_asm`. It contains tag definitions used for encoding instruction operands. -The input file should only contain the definition of BEAM_FORMAT_NUMBER +The input file should only contain the definition of BEAM\_FORMAT\_NUMBER and external generic instructions. (Everything else would be ignored.) ### Running beam_makeops for the emulator ### @@ -382,7 +383,7 @@ The following output files will be generated in the output directory. instructions (including how to pack their operands), and transformation rules are all part of this file. -* `beam_opcodes.h` - Miscellanous preprocessor definitions, mainly +* `beam_opcodes.h` - Miscellaneous preprocessor definitions, mainly used by `beam_load.c` but also by `beam_{hot,warm,cold}.h`. * `beam_transform.c` - Implementation of guard constraints and generators @@ -424,8 +425,10 @@ A line with `//` is also a comment. It is recommended to only use this style of comments in files that define implementations of instructions. -A long line can be broken into shorter lines by a placing a `\` before -the newline. +A long transformation line can be broken after the `=>` operator and +after `|` operators. Since OTP 25, this is the only way to break transformation +lines. When reading older source you may see that `\` was used for this +purpose, but we removed it since it was only seen together with `=>` and `|`. ### Variable definitions ### @@ -538,13 +541,14 @@ It is also possible to add an `%else` clause: The following symbols are always defined. * `ARCH_64` - is 1 for a 64-bit machine, and 0 otherwise. -* `ARCH_32` - is 1 for 32-bit machine, and 1 otherwise. +* `ARCH_32` - is 1 for 32-bit machine, and 0 otherwise. The `Makefile` for building the emulator currently defines the following symbols by using the `-D` option on the command line for **beam\_makeops**. -* `USE_VM_PROBES` - 1 if the runtime system is compiled to use VM probes (support for dtrace or systemtap), 0 otherwise. +* `USE_VM_PROBES` - 1 if the runtime system is compiled to use VM + probes (support for dtrace or systemtap), 0 otherwise. ### Defining external generic instructions ### @@ -586,8 +590,9 @@ the most common way. Whenever a specific instruction is created, **beam\_makeops** automatically creates an internal generic instruction if it does not previously exist. -* Explicitly. This is necessary only when a generic instruction does -not have any corresponding specific instruction. +* Explicitly. This is necessary only when a generic instruction is +used in transformations, but does not have any corresponding specific +instruction. The syntax for an internal generic instruction is as follows: @@ -726,18 +731,18 @@ register as a port. Therefore the literal term must not contain a port or pid.) * `S` - Tagged source register (X or Y). The tag will be tested at -runtime to retrieve the value from an X register or a Y register. Slighly +runtime to retrieve the value from an X register or a Y register. Slightly cheaper than `s`. * `d` - Tagged destination register (X or Y). The tag will be tested at runtime to set up a pointer to the destination register. If the -instruction performs a garbarge collection, it must use the +instruction performs a garbage collection, it must use the `$REFRESH_GEN_DEST()` macro to refresh the pointer before storing to it (there are more details about that in a later section). * `j` - A failure label (combination of `f` and `p`). If the branch target 0, an exception will be raised if instruction fails, otherwise control will be -transfered to the target address. +transferred to the target address. The types that follows are all applied to an operand that has the `u` type. @@ -874,31 +879,24 @@ A rule is recognized by its right-pointer arrow: `=>`. To the left of the arrow is one or more instruction patterns, separated by `|`. To the right of the arrow is zero or more instructions, separated by `|`. If the instructions from the BEAM code matches the instruction -patterns on the left side, they will be replaced with instructions on -the right side (or removed if there are no instructions on the right). +patterns on the left-hand side, they will be replaced with +instructions on the right-hand side (or removed if there are no +instructions on the right). #### Defining instruction patterns #### -We will start looking at the patterns on the left side of the arrow. +We will start looking at the patterns on the left-hand side of the arrow. A pattern for an instruction consists of its name, followed by a pattern for each of its operands. The operand patterns are separated by spaces. The simplest possible pattern is a variable. Just like in Erlang, -a variable must begin with an uppercase letter. If the same variable is -used in multiple operands, the pattern will only match if the operands -are equal. For example: - - move Same Same => +a variable must begin with an uppercase letter. In constrast to Erlang, +variables must **not** be repeated. -This pattern will match if the operands for `move` are the same. If -the pattern match, the instruction will be removed. (That used to be an -actual rule a long time ago when the compiler would occasionally produce -instructions such as `{move,{x,2},{x,2}}`.) - -Variables that have been bound on the left side can be used on the -right side. For example, this rule will rewrite all `move` instructions -to `assign` instructions with the operands swapped: +Variables that have been bound on the left-hand side can be used on +the right-hand side. For example, this rule will rewrite all `move` +instructions to `assign` instructions with the operands swapped: move Src Dst => assign Dst Src @@ -923,6 +921,18 @@ Here the `is_eq_exact` instruction is replaced with a specialized instruction that only compares literals, but only if the first operand is a register and the second operand is a literal. +#### Removing instructions #### + +The instructions of the left-hand side of the pattern can be removed +by using the `_` symbol on the right-hand side of the +transformation. For example, a `line` instruction without any actual +line-number information can be removed like this: + + line n => _ + +(Before OTP 25, this was instead achieved by leaving the right-hand side +blank.) + #### Further constraining patterns #### In addition to specifying a type letter, the actual value for the type can @@ -934,10 +944,11 @@ Here the second operand of `move` is constrained to be X register 1. When specifying an atom constraint, the atom is written as it would be in the C source code. That is, it needs an `am_` prefix, and it must -be listed in `atom.names`. For example: +be listed in `atom.names`. For example, redundant `is_boolean` instructions +can be removed like this: - is_boolean Fail=f a==am_true => - is_boolean Fail=f a==am_false => + is_boolean Fail=f a==am_true => _ + is_boolean Fail=f a==am_false => _ There are several constraints available for testing whether a call is to a BIF or a function. @@ -961,7 +972,7 @@ result. The `u$is_not_bif` constraint matches if the operand does not refer to a BIF (not listed in `bif.tab`). For example: - move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ + move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => move S X0 | call_ext_last Ar Func D The `u$bif:Module:Name/Arity` constraint tests whether the given @@ -970,7 +981,7 @@ operand refers to a specific BIF. Note that `Module:Name/Arity` be a compilation error. It is useful when a call to a specific BIF should be replaced with an instruction as in this example: - gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ + gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => gen_plus Fail Live S1 S2 Dst Here the call to the GC BIF `'+'/2` will be replaced with the instruction @@ -986,13 +997,14 @@ a specific function. Here is an example: bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler `is_constant/1` used to be a BIF a long time ago. The transformation -replaces the call with the `too_old_compiler` instruction which will produce -a nicer error message than the default error would be for a missing guard BIF. +replaces the call with the `too_old_compiler` instruction, which is +specially handled in the loader to produce a nicer error message than +the default error would be for a missing guard BIF. #### Type constraints allowed in patterns #### -Here are all type letters that are allowed on the left side of a transformation -rule. +Here are all type letters that are allowed on the left-hand side of a +transformation rule. * `u` - An untagged integer that fits in a machine word. @@ -1026,26 +1038,47 @@ instruction, it must only be used for a destination register.) * `o` - Overflow. An untagged integer that does not fit in a machine word. -#### Guard constraints (predicates) #### +#### Predicates #### If the constraints described so far is not enough, additional constraints can be implemented in C and be called as a guard function -on the left side of the transformation. If the guard function returns +on the left-hand side of the transformation. If the guard function returns a non-zero value, the matching of the rule will continue, otherwise -the match will fail. For example: +the match will fail. Such guard functions are hereafter called +*predicates*. - ensure_map Lit=q | literal_is_map(Lit) => +The most commonly used guard constraints is `equal()`. It can be used +to remove a redundant `move` instructio like this: -The guard test `literal_is_map/1` tests whether the given literal is a map. -If the literal is a map, the instruction is unnecessary and can be removed. + move R1 R2 | equal(R1, R2) => _ -Such guard tests are also called predicates. At the time of writing, all -predicates are defined in the file `predicates.tab`. +or remove a redundant `is_eq_exact` instruction like this: + + is_eq_exact Lbl Src1 Src2 | equal(Src1, Src2) => _ + +At the time of writing, all predicates are defined in files named +`predicates.tab` in several directories. In `predicates.tab` directly +in `$ERL_TOP/erts/emulator/beam`, predicates that are used by both the +traditinal emulator and the JIT implementations are contained. +Predicates only used by the emulator can be found in +`emu/predicates.tab`. + +### A very brief note on implementation of predicates #### It is outside the scope for this document to describe in detail how predicates are implemented because it requires knowledge of the -internal loader data structures, but here is the implementation of -`literal_is_map()`: +internal loader data structures, but here is quick look at the +implementation of a simple predicate called `literal_is_map()`. + +Here is first an example how it is used: + + is_map Fail Lit=q | literal_is_map(Lit) => _ + +If the `Lit` operand is a literal, then the `literal_is_map()` +predicate is called to determine wheter is is a map literal. +It it is, the instruction is not needed and can be removed. + +`literal_is_map()` is implemented like this (in `emu/predicates.tab`): pred.literal_is_map(Lit) { Eterm term; @@ -1096,23 +1129,24 @@ generic instruction: To match a variable number of arguments we need to use the special operand type `*` like this: - select_val Src=aiq Fail=f Size=u List=* => \ + select_val Src=aiq Fail=f Size=u List=* => i_const_select_val Src Fail Size List This transformation renames a `select_val/3` instruction with a constant source operand to `i_const_select_val/3`. -#### Constructing new instructions on the right side #### +#### Constructing new instructions on the right-hand side #### -The most common operand on the right side is a variable that was bound while -matching the left side. For example: +The most common operand on the right-hand side is a variable that was +bound while matching the pattern on the left-hand side. For example: trim N Remaining => i_trim N -An operand can also be a type letter to construct an operand of that type. -Each type has a default value. For example, the type `x` has the default -value 1023, which is the highest X register. That makes `x` on the right -side a convenient shortcut for a temporary X register. For example: +An operand can also be a type letter to construct an operand of that +type. Each type has a default value. For example, the type `x` has +the default value 1023, which is the highest X register. That makes +`x` on the right-hand side a convenient shortcut for a temporary X +register. For example: is_number Fail Literal=q => move Literal x | is_number Fail x @@ -1133,15 +1167,15 @@ the atom `false` is written as `am_false`. The atom must be listed in Here is an example showing how values can be specified: - bs_put_utf32 Fail=j Flags=u Src=s => \ - i_bs_validate_unicode Fail Src | \ + bs_put_utf32 Fail=j Flags=u Src=s => + i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src -#### Type letters on the right side #### +#### Type letters on the right-hand side #### Here follows all types that are allowed to be used in operands for -instructions being constructed on the right side of a transformation -rule. +instructions being constructed on the right-hand side of a +transformation rule. * `u` - Construct an untagged integer. The default value is 0. @@ -1160,16 +1194,16 @@ use as a temporary X register. * `n` - NIL (`[]`, the empty list). -#### Function call on the right side #### +#### Function call on the right-hand side #### Transformations that are not possible to describe with the rule language as described here can be implemented as a generator function -in C and called from the right side of a transformation. The left +in C and called from the right-hand side of a transformation. The left-hand side of the transformation will perform the match and bind operands to variables. The variables can then be passed to a generator function -on the right side. For example: +on the right-hand side. For example: - bif2 Fail=j u$bif:erlang:element/2 Index=s Tuple=xy Dst=d => \ + bif2 Fail=j u$bif:erlang:element/2 Index=s Tuple=xy Dst=d => element(Jump, Index, Tuple, Dst) This transformation rule matches a call to the BIF `element/2`. @@ -1191,12 +1225,13 @@ already an untagged integer. It also knows that the index is at least instruction will have to fetch the index from a register, test that it is an integer, and untag the integer. -At the time of writing, all generators functions were defined in the -file `generators.tab`. +At the time of writing, all generators functions were defined in files +named `generators.tab` in several directories (in the same directories +as the `predicates.tab` files). It is outside the scope of this document to describe in detail how -generator functions are written, but here is the -implementation of `element()`: +generator functions are written, but here is the implementation of +`element()`: gen.element(Fail, Index, Tuple, Dst) { BeamOp* op; @@ -1616,7 +1651,7 @@ of the instruction, a pointer will be initialized to point to the X or Y register in question. If there is a garbage collection before the result is stored, -the stack will move and if the `d` operand refered to a Y +the stack will move and if the `d` operand referred to a Y register, the pointer will no longer be valid. (Y registers are stored on the stack.) @@ -2047,13 +2082,13 @@ like this: select_val s f I * The `*` as the last operand will make sure that the variable operands -are passed in as a C++ vector of `ArgVal`. Here is the emitter -function: +are passed in as a `Span` of `ArgVal` (will be `std::span` in C++20 onwards). +Here is the emitter function: void BeamModuleAssembler::emit_select_val(const ArgVal &Src, const ArgVal &Fail, const ArgVal &Size, - const std::vector &args) { + const Span &args) { ASSERT(Size.getValue() == args.size()); . . diff --git a/erts/emulator/internal_doc/dec.erl b/erts/emulator/internal_doc/dec.erl index 8ce83fa40230..4d3a4d980bfd 100644 --- a/erts/emulator/internal_doc/dec.erl +++ b/erts/emulator/internal_doc/dec.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2021. 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. @@ -24,7 +24,7 @@ %% The C header is generated from a text file containing tuples in the %% following format: %% {RevList,Translation} -%% Where 'RevList' is a reversed list of the denormalized repressentation of +%% Where 'RevList' is a reversed list of the denormalized representation of %% the character 'Translation'. An example would be the swedish character %% 'ö', which would be represented in the file as: %% {[776,111],246}, as the denormalized representation of codepoint 246 diff --git a/erts/emulator/internal_doc/figures/beamasm-perf-annotate.png b/erts/emulator/internal_doc/figures/beamasm-perf-annotate.png index 6961341bddbc..0d5ed0f0f780 100644 Binary files a/erts/emulator/internal_doc/figures/beamasm-perf-annotate.png and b/erts/emulator/internal_doc/figures/beamasm-perf-annotate.png differ diff --git a/erts/emulator/internal_doc/figures/perf-beamasm.png b/erts/emulator/internal_doc/figures/perf-beamasm.png index 8524709a6828..7012861459e8 100644 Binary files a/erts/emulator/internal_doc/figures/perf-beamasm.png and b/erts/emulator/internal_doc/figures/perf-beamasm.png differ diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c index 48b532977332..4acedf169245 100644 --- a/erts/emulator/nifs/common/prim_file_nif.c +++ b/erts/emulator/nifs/common/prim_file_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson 2017-2021. All Rights Reserved. + * Copyright Ericsson 2017-2023. 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. @@ -997,9 +997,12 @@ static ERL_NIF_TERM build_file_info(ErlNifEnv *env, efile_fileinfo_t *info) { enif_make_uint64(env, info->size), efile_filetype_to_atom(info->type), efile_access_to_atom(info->access), - enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info->a_time)), - enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info->m_time)), - enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info->c_time)), + enif_make_int64(env, + MIN(EFILE_MAX_FILETIME, MAX(EFILE_MIN_FILETIME, info->a_time))), + enif_make_int64(env, + MIN(EFILE_MAX_FILETIME, MAX(EFILE_MIN_FILETIME, info->m_time))), + enif_make_int64(env, + MIN(EFILE_MAX_FILETIME, MAX(EFILE_MIN_FILETIME, info->c_time))), enif_make_uint(env, info->mode), enif_make_uint(env, info->links), enif_make_uint(env, info->major_device), diff --git a/erts/emulator/nifs/common/prim_file_nif.h b/erts/emulator/nifs/common/prim_file_nif.h index a37502122480..a9cb74ab0b4b 100644 --- a/erts/emulator/nifs/common/prim_file_nif.h +++ b/erts/emulator/nifs/common/prim_file_nif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson 2017-2021. All Rights Reserved. + * Copyright Ericsson 2017-2023. 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. @@ -28,7 +28,7 @@ enum efile_modes_t { EFILE_MODE_SYNC = (1 << 4), EFILE_MODE_SKIP_TYPE_CHECK = (1 << 5), /* Special for device files on Unix. */ - EFILE_MODE_NO_TRUNCATE = (1 << 6), /* Special for reopening on VxWorks. */ + /* EFILE_MODE_RESERVED = (1 << 6), - Reserved, previously used for reopening on VxWorks. */ EFILE_MODE_DIRECTORY = (1 << 7), @@ -94,7 +94,12 @@ typedef struct { /* The smallest value that can be converted freely between universal, local, * and POSIX time, as required by read_file_info/2. Corresponds to * {{1902,1,1},{0,0,0}} */ -#define EFILE_MIN_FILETIME -2145916800 +#define EFILE_MIN_FILETIME (-2145916800LL) + +/* The largest value that can be converted freely between universal, local, + * and POSIX time, as required by read_file_info/2. Corresponds to + * {{9999,12,31},{23,59,59}} */ +#define EFILE_MAX_FILETIME (253402300799LL) /* Initializes an efile_data_t; must be used in efile_open on success. */ #define EFILE_INIT_RESOURCE(__d, __modes) do { \ diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c index f9cd62f4e20d..299b96b60572 100644 --- a/erts/emulator/nifs/common/prim_net_nif.c +++ b/erts/emulator/nifs/common/prim_net_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2021. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. 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. @@ -31,9 +31,29 @@ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif +#ifndef ESOCK_ENABLE +# include + +static +ErlNifFunc net_funcs[] = {}; + +static +int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + (void)env; + (void)priv_data; + (void)load_info; + + return 1; +} + +ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL) + +#else + /* If we HAVE_SCTP_H and Solaris, we need to define the following in * order to get SCTP working: */ @@ -91,7 +111,7 @@ #ifdef __WIN32__ -#define STRNCASECMP strncasecmp +// #define STRNCASECMP strncasecmp #define INCL_WINSOCK_API_TYPEDEFS 1 #ifndef WINDOWS_H_INCLUDES_WINSOCK2_H @@ -101,17 +121,19 @@ #include /* NEED VC 6.0 or higher */ /* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h - * to define the right structures. It needs to be set to WINXP (or LONGHORN) - * for IPV6 to work and it's set lower by default, so we need to change it. + * to define the right structures. + * It needs to be set higher for IPV6 to work and it's set lower by default, + * so we need to change it. */ #ifdef HAVE_SDKDDKVER_H # include # ifdef NTDDI_VERSION # undef NTDDI_VERSION # endif -# define NTDDI_VERSION NTDDI_WINXP +# define NTDDI_VERSION NTDDI_WIN10_RS2 #endif #include +#include #undef WANT_NONBLOCKING #include "sys.h" @@ -218,9 +240,10 @@ /* Debug stuff... */ #define NET_NIF_DEBUG_DEFAULT FALSE -#define NDBG( proto ) ESOCK_DBG_PRINTF( data.debug , proto ) - +#define NDBG( proto ) ESOCK_DBG_PRINTF( data.debug , proto ) +#define NDBG2( dbg, proto ) ESOCK_DBG_PRINTF( (dbg || data.debug) , proto ) +/* Global 'stuff' */ typedef struct { BOOLEAN_T debug; } NetData; @@ -253,20 +276,24 @@ extern char* erl_errno_id(int error); * int argc, * const ERL_NIF_TERM argv[]); * - * So, to simplify, use some macro magic to define those. + * So, to simplify, we use some macro magic to define those. * * These are the functions making up the "official" API. */ -#define ENET_NIF_FUNCS \ - ENET_NIF_FUNC_DEF(info); \ - ENET_NIF_FUNC_DEF(command); \ - ENET_NIF_FUNC_DEF(gethostname); \ - ENET_NIF_FUNC_DEF(getnameinfo); \ - ENET_NIF_FUNC_DEF(getaddrinfo); \ - ENET_NIF_FUNC_DEF(getifaddrs); \ - ENET_NIF_FUNC_DEF(if_name2index); \ - ENET_NIF_FUNC_DEF(if_index2name); \ +#define ENET_NIF_FUNCS \ + ENET_NIF_FUNC_DEF(info); \ + ENET_NIF_FUNC_DEF(command); \ + ENET_NIF_FUNC_DEF(gethostname); \ + ENET_NIF_FUNC_DEF(getnameinfo); \ + ENET_NIF_FUNC_DEF(getaddrinfo); \ + ENET_NIF_FUNC_DEF(getifaddrs); \ + ENET_NIF_FUNC_DEF(get_adapters_addresses); \ + ENET_NIF_FUNC_DEF(get_if_entry); \ + ENET_NIF_FUNC_DEF(get_interface_info); \ + ENET_NIF_FUNC_DEF(get_ip_address_table); \ + ENET_NIF_FUNC_DEF(if_name2index); \ + ENET_NIF_FUNC_DEF(if_index2name); \ ENET_NIF_FUNC_DEF(if_names); #define ENET_NIF_FUNC_DEF(F) \ @@ -280,9 +307,8 @@ ENET_NIF_FUNCS /* And here comes the functions that does the actual work (for the most part) */ static ERL_NIF_TERM enet_command(ErlNifEnv* env, ERL_NIF_TERM cmd); -#if defined(HAVE_GETHOSTNAME) + static ERL_NIF_TERM enet_gethostname(ErlNifEnv* env); -#endif #if defined(HAVE_GETNAMEINFO) static ERL_NIF_TERM enet_getnameinfo(ErlNifEnv* env, @@ -302,6 +328,147 @@ static ERL_NIF_TERM enet_getifaddrs(ErlNifEnv* env, char* netns); #endif +#if defined(__WIN32__) + +/* *** Get Adapters Addresses functions *** */ +static BOOLEAN_T enet_get_adapters_addresses_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs); +static BOOLEAN_T enet_get_adapters_addresses_args_family(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + ULONG* fam); +static BOOLEAN_T enet_get_adapters_addresses_args_flags(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + ULONG* flags); +static ERL_NIF_TERM enet_get_adapters_addresses(ErlNifEnv* env, + BOOLEAN_T dbg, + ULONG fam, + ULONG flags); +static ERL_NIF_TERM enet_adapters_addresses_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_ADDRESSES* ipAdAddrsP); +static ERL_NIF_TERM enet_adapter_addresses_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_ADDRESSES* ipAdAddrsP); +static ERL_NIF_TERM enet_adapter_encode_name(ErlNifEnv* env, + WCHAR* name); +static ERL_NIF_TERM enet_adapter_encode_friendly_name(ErlNifEnv* env, + WCHAR* fname); +static ERL_NIF_TERM encode_if_oper_status(ErlNifEnv* env, + DWORD status); +static ERL_NIF_TERM encode_adapter_flags(ErlNifEnv* env, + IP_ADAPTER_ADDRESSES* ipAdAddrsP); +static ERL_NIF_TERM encode_adapter_unicast_addrs(ErlNifEnv* env, + IP_ADAPTER_UNICAST_ADDRESS* firstP); +static ERL_NIF_TERM encode_adapter_unicast_addr(ErlNifEnv* env, + IP_ADAPTER_UNICAST_ADDRESS* addrP); +static ERL_NIF_TERM encode_adapter_unicast_addr_flags(ErlNifEnv* env, + DWORD flags); +static ERL_NIF_TERM encode_adapter_unicast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP); +static ERL_NIF_TERM encode_adapter_unicast_addr_porig(ErlNifEnv* env, + IP_PREFIX_ORIGIN porig); +static ERL_NIF_TERM encode_adapter_unicast_addr_sorig(ErlNifEnv* env, + IP_SUFFIX_ORIGIN sorig); +static ERL_NIF_TERM encode_adapter_unicast_addr_dad_state(ErlNifEnv* env, + IP_DAD_STATE dstate); +static ERL_NIF_TERM encode_adapter_anycast_addrs(ErlNifEnv* env, + IP_ADAPTER_ANYCAST_ADDRESS* firstP); +static ERL_NIF_TERM encode_adapter_anycast_addr(ErlNifEnv* env, + IP_ADAPTER_ANYCAST_ADDRESS* addrP); +static ERL_NIF_TERM encode_adapter_anycast_addr_flags(ErlNifEnv* env, + DWORD flags); +static ERL_NIF_TERM encode_adapter_anycast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP); +static ERL_NIF_TERM encode_adapter_multicast_addrs(ErlNifEnv* env, + IP_ADAPTER_MULTICAST_ADDRESS* firstP); +static ERL_NIF_TERM encode_adapter_multicast_addr(ErlNifEnv* env, + IP_ADAPTER_MULTICAST_ADDRESS* addrP); +static ERL_NIF_TERM encode_adapter_multicast_addr_flags(ErlNifEnv* env, + DWORD flags); +static ERL_NIF_TERM encode_adapter_multicast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP); +static ERL_NIF_TERM encode_adapter_dns_server_addrs(ErlNifEnv* env, + IP_ADAPTER_DNS_SERVER_ADDRESS* firstP); +static ERL_NIF_TERM encode_adapter_dns_server_addr(ErlNifEnv* env, + IP_ADAPTER_DNS_SERVER_ADDRESS* addrP); +static ERL_NIF_TERM encode_adapter_dns_server_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP); +static ERL_NIF_TERM encode_adapter_zone_indices(ErlNifEnv* env, + DWORD* zoneIndices, + DWORD len); +static ERL_NIF_TERM encode_adapter_prefixes(ErlNifEnv* env, + IP_ADAPTER_PREFIX* firstP); +static ERL_NIF_TERM encode_adapter_prefix(ErlNifEnv* env, + IP_ADAPTER_PREFIX* prefP); +static ERL_NIF_TERM encode_adapter_prefix_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP); + + +/* *** Get If Entry (MIB_IFROW) functions *** */ +static ERL_NIF_TERM enet_get_if_entry(ErlNifEnv* env, + BOOLEAN_T dbg, + DWORD index); +static BOOLEAN_T enet_get_if_entry_args_index(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + DWORD* index); +static BOOLEAN_T enet_get_if_entry_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs); +static ERL_NIF_TERM enet_if_row_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IFROW* rowP); +static ERL_NIF_TERM encode_if_type(ErlNifEnv* env, + DWORD type); +static ERL_NIF_TERM encode_if_row_description(ErlNifEnv* env, + DWORD len, + UCHAR* buf); +static ERL_NIF_TERM encode_if_admin_status(ErlNifEnv* env, + DWORD status); +static ERL_NIF_TERM encode_internal_if_oper_status(ErlNifEnv* env, + DWORD status); +static ERL_NIF_TERM encode_if_row_phys_address(ErlNifEnv* env, + DWORD len, + UCHAR* buf); + +/* *** Get Interface Info functions *** */ +static ERL_NIF_TERM enet_get_interface_info(ErlNifEnv* env, + BOOLEAN_T dbg); +static BOOLEAN_T enet_get_interface_info_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eextra); +static ERL_NIF_TERM enet_interface_info_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_INTERFACE_INFO* infoP); +static void encode_adapter_index_map(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_INDEX_MAP* adapterP, + ERL_NIF_TERM* eadapter); +static ERL_NIF_TERM encode_adapter_index_map_name(ErlNifEnv* env, WCHAR* name); +static void make_adapter_index_map(ErlNifEnv* env, + ERL_NIF_TERM eindex, + ERL_NIF_TERM ename, + ERL_NIF_TERM* emap); +/* *** Get IP Address Table functions *** */ +static ERL_NIF_TERM enet_get_ip_address_table(ErlNifEnv* env, + BOOLEAN_T dbg); +static ERL_NIF_TERM enet_get_ip_address_table_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IPADDRTABLE* tabP); +static ERL_NIF_TERM encode_ip_address_row(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IPADDRROW* rowP); +static ERL_NIF_TERM encode_ip_address_row_addr(ErlNifEnv* env, + BOOLEAN_T dbg, + const char* descr, + DWORD addr); +static void make_ip_address_row(ErlNifEnv* env, + ERL_NIF_TERM eaddr, + ERL_NIF_TERM eindex, + ERL_NIF_TERM emask, + ERL_NIF_TERM eBCastAddr, + ERL_NIF_TERM eReasmSize, + ERL_NIF_TERM* iar); + +#endif + #if defined(HAVE_IF_NAMETOINDEX) static ERL_NIF_TERM enet_if_name2index(ErlNifEnv* env, char* ifn); @@ -359,6 +526,7 @@ static BOOLEAN_T enet_getifaddrs_netns(ErlNifEnv* env, static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err); static BOOLEAN_T restore_network_namespace(int ns, int* err); #endif +static ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, struct sockaddr* sa); static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, const ERL_NIF_TERM eflags, int* flags); @@ -379,9 +547,9 @@ static ERL_NIF_TERM encode_address_info(ErlNifEnv* env, static unsigned int address_info_length(struct addrinfo* addrInfoP); static ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, - int family); + int family); static ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, - int socktype); + int socktype); static void make_address_info(ErlNifEnv* env, ERL_NIF_TERM fam, @@ -390,9 +558,18 @@ static void make_address_info(ErlNifEnv* env, ERL_NIF_TERM addr, ERL_NIF_TERM* ai); +#if defined(__WIN32__) +static ERL_NIF_TERM encode_uchar(ErlNifEnv* env, + DWORD len, + UCHAR* buf); +static ERL_NIF_TERM encode_wchar(ErlNifEnv* env, + WCHAR* name); +#endif static BOOLEAN_T get_debug(ErlNifEnv* env, ERL_NIF_TERM map); -static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); +static int on_load(ErlNifEnv* env, + void** priv_data, + ERL_NIF_TERM load_info); #if HAVE_IN6 @@ -428,33 +605,132 @@ static const struct in6_addr in6addr_loopback = #define LOCAL_ATOMS \ LOCAL_ATOM_DECL(address_info); \ + LOCAL_ATOM_DECL(admin_status); \ + LOCAL_ATOM_DECL(anycast_addrs); \ + LOCAL_ATOM_DECL(atm); \ LOCAL_ATOM_DECL(automedia); \ + LOCAL_ATOM_DECL(bcast_addr); \ LOCAL_ATOM_DECL(broadaddr); \ LOCAL_ATOM_DECL(broadcast); \ + LOCAL_ATOM_DECL(dad_state); \ LOCAL_ATOM_DECL(debug); \ + LOCAL_ATOM_DECL(deprecated); \ + LOCAL_ATOM_DECL(description); \ + LOCAL_ATOM_DECL(dhcp); \ + LOCAL_ATOM_DECL(dhcp_v4_enabled); \ + LOCAL_ATOM_DECL(ddns_enabled); \ + LOCAL_ATOM_DECL(disconnected); \ + LOCAL_ATOM_DECL(dns_eligible); \ + LOCAL_ATOM_DECL(dns_server_addrs); \ + LOCAL_ATOM_DECL(dns_suffix); \ + LOCAL_ATOM_DECL(down); \ LOCAL_ATOM_DECL(dstaddr); \ + LOCAL_ATOM_DECL(duplicate); \ LOCAL_ATOM_DECL(dynamic); \ + LOCAL_ATOM_DECL(ethernet_csmacd); \ + LOCAL_ATOM_DECL(fddi); \ + LOCAL_ATOM_DECL(friendly_name); \ LOCAL_ATOM_DECL(host); \ LOCAL_ATOM_DECL(idn); \ + LOCAL_ATOM_DECL(ieee1394); \ + LOCAL_ATOM_DECL(ieee80211); \ + LOCAL_ATOM_DECL(ieee80216_wman); \ + LOCAL_ATOM_DECL(include_prefix); \ + LOCAL_ATOM_DECL(include_wins_info); \ + LOCAL_ATOM_DECL(include_gateways); \ + LOCAL_ATOM_DECL(include_all_interfaces); \ + LOCAL_ATOM_DECL(include_all_compartments); \ + LOCAL_ATOM_DECL(include_tunnel_bindingorder); \ + LOCAL_ATOM_DECL(index); \ + LOCAL_ATOM_DECL(internal_oper_status); \ + LOCAL_ATOM_DECL(invalid); \ + LOCAL_ATOM_DECL(in_octets); \ + LOCAL_ATOM_DECL(in_ucast_pkts); \ + LOCAL_ATOM_DECL(in_nucast_pkts); \ + LOCAL_ATOM_DECL(in_discards); \ + LOCAL_ATOM_DECL(in_errors); \ + LOCAL_ATOM_DECL(in_unknown_protos); \ + LOCAL_ATOM_DECL(ipv4_enabled); \ + LOCAL_ATOM_DECL(ipv6_enabled); \ + LOCAL_ATOM_DECL(ipv6_index); \ + LOCAL_ATOM_DECL(ipv6_managed_address_config_supported); \ + LOCAL_ATOM_DECL(ipv6_other_stateful_config); \ + LOCAL_ATOM_DECL(iso88025_tokenring); \ + LOCAL_ATOM_DECL(last_change); \ + LOCAL_ATOM_DECL(lease_lifetime); \ + LOCAL_ATOM_DECL(length); \ + LOCAL_ATOM_DECL(link_layer_address); \ + LOCAL_ATOM_DECL(lower_layer_down); \ + LOCAL_ATOM_DECL(manual); \ + LOCAL_ATOM_DECL(mask); \ LOCAL_ATOM_DECL(master); \ LOCAL_ATOM_DECL(multicast); \ + LOCAL_ATOM_DECL(multicast_addrs); \ LOCAL_ATOM_DECL(namereqd); \ LOCAL_ATOM_DECL(name_info); \ + LOCAL_ATOM_DECL(netbios_over_tcpip_enabled); \ LOCAL_ATOM_DECL(netmask); \ LOCAL_ATOM_DECL(noarp); \ LOCAL_ATOM_DECL(nofqdn); \ + LOCAL_ATOM_DECL(non_operational); \ LOCAL_ATOM_DECL(notrailers); \ + LOCAL_ATOM_DECL(not_present); \ + LOCAL_ATOM_DECL(no_multicast); \ LOCAL_ATOM_DECL(numerichost); \ LOCAL_ATOM_DECL(numericserv); \ + LOCAL_ATOM_DECL(on_link_prefix_length); \ + LOCAL_ATOM_DECL(operational); \ + LOCAL_ATOM_DECL(oper_status); \ + LOCAL_ATOM_DECL(other); \ + LOCAL_ATOM_DECL(out_octets); \ + LOCAL_ATOM_DECL(out_ucast_pkts); \ + LOCAL_ATOM_DECL(out_nucast_pkts); \ + LOCAL_ATOM_DECL(out_discards); \ + LOCAL_ATOM_DECL(out_errors); \ + LOCAL_ATOM_DECL(out_qlen); \ + LOCAL_ATOM_DECL(phys_addr); \ LOCAL_ATOM_DECL(pointopoint); \ LOCAL_ATOM_DECL(portsel); \ + LOCAL_ATOM_DECL(ppp); \ + LOCAL_ATOM_DECL(preferred); \ + LOCAL_ATOM_DECL(preferred_lifetime); \ + LOCAL_ATOM_DECL(prefixes); \ + LOCAL_ATOM_DECL(prefix_origin); \ LOCAL_ATOM_DECL(promisc); \ + LOCAL_ATOM_DECL(random); \ + LOCAL_ATOM_DECL(reasm_size); \ + LOCAL_ATOM_DECL(receive_only); \ + LOCAL_ATOM_DECL(register_adapter_suffix); \ + LOCAL_ATOM_DECL(router_advertisement); \ LOCAL_ATOM_DECL(running); \ LOCAL_ATOM_DECL(service); \ LOCAL_ATOM_DECL(slave); \ - LOCAL_ATOM_DECL(up); + LOCAL_ATOM_DECL(skip_unicast); \ + LOCAL_ATOM_DECL(skip_anycast); \ + LOCAL_ATOM_DECL(skip_multicast); \ + LOCAL_ATOM_DECL(skip_dns_server); \ + LOCAL_ATOM_DECL(skip_friendly_name); \ + LOCAL_ATOM_DECL(software_loopback); \ + LOCAL_ATOM_DECL(speed); \ + LOCAL_ATOM_DECL(suffix_origin); \ + LOCAL_ATOM_DECL(tentative); \ + LOCAL_ATOM_DECL(testing); \ + LOCAL_ATOM_DECL(transient); \ + LOCAL_ATOM_DECL(tunnel); \ + LOCAL_ATOM_DECL(unchanged); \ + LOCAL_ATOM_DECL(unknown); \ + LOCAL_ATOM_DECL(unicast_addrs); \ + LOCAL_ATOM_DECL(unreachable); \ + LOCAL_ATOM_DECL(up); \ + LOCAL_ATOM_DECL(valid_lifetime); \ + LOCAL_ATOM_DECL(well_known); \ + LOCAL_ATOM_DECL(wwanpp); \ + LOCAL_ATOM_DECL(wwanpp2); \ + LOCAL_ATOM_DECL(zone_indices); #define LOCAL_ERROR_REASON_ATOMS \ + LOCAL_ATOM_DECL(address_not_associated); \ + LOCAL_ATOM_DECL(can_not_complete); \ LOCAL_ATOM_DECL(eaddrfamily); \ LOCAL_ATOM_DECL(ebadflags); \ LOCAL_ATOM_DECL(efail); \ @@ -468,7 +744,17 @@ static const struct in6_addr in6addr_loopback = LOCAL_ATOM_DECL(eoverflow); \ LOCAL_ATOM_DECL(eservice); \ LOCAL_ATOM_DECL(esocktype); \ - LOCAL_ATOM_DECL(esystem); + LOCAL_ATOM_DECL(esystem); \ + LOCAL_ATOM_DECL(insufficient_buffer); \ + LOCAL_ATOM_DECL(invalid_data); \ + LOCAL_ATOM_DECL(invalid_flags); \ + LOCAL_ATOM_DECL(invalid_parameter); \ + LOCAL_ATOM_DECL(not_found); \ + LOCAL_ATOM_DECL(not_enough_memory); \ + LOCAL_ATOM_DECL(not_supported); \ + LOCAL_ATOM_DECL(no_data); \ + LOCAL_ATOM_DECL(no_function); \ + LOCAL_ATOM_DECL(no_uniconde_traslation); #define LOCAL_ATOM_DECL(A) static ERL_NIF_TERM atom_##A LOCAL_ATOMS @@ -501,6 +787,10 @@ static ErlNifResourceTypeInit netInit = { * nif_getnameinfo/2 * nif_getaddrinfo/3 * nif_getifaddrs/1 + * nif_get_adapters_addresses/1 + * nif_get_if_entry/1 + * nif_get_interface_info/1 + * nif_get_ip_address_table/1 * nif_if_name2index/1 * nif_if_index2name/1 * nif_if_names/0 @@ -519,9 +809,6 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM info, tmp; NDBG( ("NET", "info -> entry\r\n") ); @@ -533,7 +820,6 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, NDBG( ("NET", "info -> done: %T\r\n", info) ); return info; -#endif } @@ -555,9 +841,6 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else ERL_NIF_TERM ecmd, result; NDBG( ("NET", "command -> entry (%d)\r\n", argc) ); @@ -574,7 +857,6 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, NDBG( ("NET", "command -> result: %T\r\n", result) ); return result; -#endif } @@ -583,7 +865,6 @@ ERL_NIF_TERM nif_command(ErlNifEnv* env, * The command can, in principle, be anything, though currently we only * support a debug command. */ -#if !defined(__WIN32__) static ERL_NIF_TERM enet_command(ErlNifEnv* env, ERL_NIF_TERM cmd) @@ -610,7 +891,6 @@ ERL_NIF_TERM enet_command(ErlNifEnv* env, } } -#endif @@ -626,9 +906,6 @@ ERL_NIF_TERM nif_gethostname(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_GETHOSTNAME) ERL_NIF_TERM result; NDBG( ("NET", "nif_gethostname -> entry (%d)\r\n", argc) ); @@ -641,13 +918,9 @@ ERL_NIF_TERM nif_gethostname(ErlNifEnv* env, NDBG( ("NET", "nif_gethostname -> done when result: %T\r\n", result) ); return result; -#else - return esock_make_error(env, esock_atom_enotsup); -#endif } -#if !defined(__WIN32__) && defined(HAVE_GETHOSTNAME) static ERL_NIF_TERM enet_gethostname(ErlNifEnv* env) { @@ -683,8 +956,6 @@ ERL_NIF_TERM enet_gethostname(ErlNifEnv* env) return result; } -#endif - @@ -704,9 +975,7 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_GETNAMEINFO) +#if defined(HAVE_GETNAMEINFO) ERL_NIF_TERM result; ERL_NIF_TERM eSockAddr, eFlags; int flags = 0; // Just in case... @@ -750,10 +1019,10 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, -/* Given the provided sock(et) address (and flags), retreive the host and +/* Given the provided sock(et) address (and flags), retrieve the host and * service info. */ -#if !defined(__WIN32__) && defined(HAVE_GETNAMEINFO) +#if defined(HAVE_GETNAMEINFO) static ERL_NIF_TERM enet_getnameinfo(ErlNifEnv* env, const ESockAddress* saP, @@ -818,7 +1087,7 @@ ERL_NIF_TERM enet_getnameinfo(ErlNifEnv* env, break; #endif -#if defined(EAI_NONAME) +#if !defined(__WIN32__) && defined(EAI_NONAME) case EAI_NONAME: result = esock_make_error(env, atom_enoname); break; @@ -864,9 +1133,7 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_GETADDRINFO) +#if defined(HAVE_GETADDRINFO) ERL_NIF_TERM result, eHostName, eServName; //, eHints; char* hostName; char* servName; @@ -926,7 +1193,7 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, } -#if !defined(__WIN32__) && defined(HAVE_GETADDRINFO) +#if defined(HAVE_GETADDRINFO) static ERL_NIF_TERM enet_getaddrinfo(ErlNifEnv* env, char* host, @@ -998,7 +1265,8 @@ ERL_NIF_TERM enet_getaddrinfo(ErlNifEnv* env, break; #endif -#if defined(EAI_NONAME) + /* This value conflict with "some" other value on windows... */ +#if !defined(__WIN32__) && defined(EAI_NONAME) case EAI_NONAME: result = esock_make_error(env, atom_enoname); break; @@ -1251,7 +1519,7 @@ ERL_NIF_TERM enet_getifaddrs_process(ErlNifEnv* env, struct ifaddrs* ifap) -/* Calculate the length of the interface adress linked list +/* Calculate the length of the interface address linked list * The list is NULL-terminated, so the only way is to * iterate through the list until we find next = NULL. */ @@ -1422,19 +1690,7 @@ ERL_NIF_TERM encode_ifaddrs_flags(ErlNifEnv* env, unsigned int flags) static ERL_NIF_TERM encode_ifaddrs_addr(ErlNifEnv* env, struct sockaddr* sa) { - ERL_NIF_TERM esa; - - if (sa != NULL) { - - unsigned int sz = sizeof(ESockAddress); - - esock_encode_sockaddr(env, (ESockAddress*) sa, sz, &esa); - - } else { - esa = esock_atom_undefined; - } - - return esa; + return encode_sockaddr(env, sa); } @@ -1522,186 +1778,2342 @@ void make_ifaddrs(ErlNifEnv* env, /* ---------------------------------------------------------------------- - * nif_if_name2index + * nif_get_adapters_addresses * * Description: - * Perform a Interface Name to Interface Index translation. + * Get adapters addresses. + * This is a windows only function! * * Arguments: - * Ifn - Interface name to be translated. + * Args - A way to pass 'extra' arguments. + * #{family := unspec (default) | inet | inet6, + * flags := flags(), + * debug := boolean() (optional)} + * + * flags() :: #{skip_unicast :: boolean() (default false), + * skip_anycast :: boolean() (default true), + * skip_multicast :: boolean() (default true), + * skip_dns_server :: boolean() (default true), + * skip_friendly_name :: boolean() (default true), + * include_prefix :: boolean() (default true), + * include_wins_info :: boolean() (default false), + * include_gateways :: boolean() (default false), + * include_all_interfaces :: boolean() (default false), + * include_all_compartments :: boolean() (default false), + * include_tunnel_bindingorder :: boolean() (default false)} + * Suggested Help atoms: + * no_skips_all_includes + * all_skips_no_includes + * no_skips_no_includes + * all_skips_all_includes */ static -ERL_NIF_TERM nif_if_name2index(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM nif_get_adapters_addresses(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { -#if defined(__WIN32__) +#if !defined(__WIN32__) return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_IF_NAMETOINDEX) - ERL_NIF_TERM eifn, result; - char ifn[IF_NAMESIZE+1]; +#else + ERL_NIF_TERM result, eargs; + ULONG fam, flags; + BOOLEAN_T dbg; - NDBG( ("NET", "nif_if_name2index -> entry (%d)\r\n", argc) ); + NDBG( ("NET", "nif_get_adapters_addresses -> entry (%d)\r\n", argc) ); - if (argc != 1) { + if ((argc != 1) || + !IS_MAP(env, argv[0])) { return enif_make_badarg(env); } - eifn = argv[0]; + eargs = argv[0]; - NDBG( ("NET", - "nif_if_name2index -> " - "\r\n Ifn: %T" - "\r\n", argv[0]) ); + if (!enet_get_adapters_addresses_args_family(env, eargs, &fam)) + return enif_make_badarg(env); - if (0 >= GET_STR(env, eifn, ifn, sizeof(ifn))) - return esock_make_error(env, esock_atom_einval); + if (!enet_get_adapters_addresses_args_flags(env, eargs, &flags)) + return enif_make_badarg(env); - result = enet_if_name2index(env, ifn); + dbg = enet_get_adapters_addresses_args_debug(env, eargs); - NDBG( ("NET", "nif_if_name2index -> done when result: %T\r\n", result) ); + result = enet_get_adapters_addresses(env, dbg, fam, flags); + NDBG2( dbg, + ("NET", + "nif_get_adapters_addresses -> done when result: " + "\r\n %T\r\n", result) ); + return result; -#else - return esock_make_error(env, esock_atom_enotsup); #endif } -#if !defined(__WIN32__) && defined(HAVE_IF_NAMETOINDEX) +#if defined(__WIN32__) static -ERL_NIF_TERM enet_if_name2index(ErlNifEnv* env, - char* ifn) +BOOLEAN_T enet_get_adapters_addresses_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs) { - unsigned int idx; + return get_debug(env, eargs); +} +#endif - NDBG( ("NET", "enet_if_name2index -> entry with ifn: %s\r\n", ifn) ); - idx = if_nametoindex(ifn); - NDBG( ("NET", "enet_if_name2index -> idx: %d\r\n", idx) ); +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_adapters_addresses_args_family(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + ULONG* fam) +{ + ERL_NIF_TERM key = esock_atom_family; + ERL_NIF_TERM eval; + DWORD val; - if (idx == 0) { - int save_errno = get_errno(); - NDBG( ("NET", "nif_name2index -> failed: %d\r\n", save_errno) ); - return esock_make_error_errno(env, save_errno); + if (!GET_MAP_VAL(env, eargs, key, &eval)) { + *fam = AF_UNSPEC; // Default + return TRUE; } else { - return esock_make_ok2(env, MKI(env, idx)); - } + if (!IS_ATOM(env, eval)) + return FALSE; + + if (COMPARE(eval, esock_atom_unspec)) + val = AF_UNSPEC; + else if (COMPARE(eval, esock_atom_inet)) + val = AF_INET; + else if (COMPARE(eval, esock_atom_inet6)) + val = AF_INET6; + else + return FALSE; + *fam = val; + return TRUE; + } } -#endif +#endif // __WIN32__ +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_adapters_addresses_args_flags(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + ULONG* flags) +{ + ERL_NIF_TERM eflags; + ULONG val = 0; + + if (!GET_MAP_VAL(env, eargs, esock_atom_flags, &eflags)) { + // Default + *flags = + GAA_FLAG_INCLUDE_PREFIX | + GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_DNS_SERVER | + GAA_FLAG_SKIP_FRIENDLY_NAME | + GAA_FLAG_SKIP_MULTICAST; + return TRUE; + } else { + if (!IS_MAP(env, eflags)) + return FALSE; -/* ---------------------------------------------------------------------- - * nif_if_index2name - * - * Description: - * Perform a Interface Index to Interface Name translation. - * - * Arguments: - * Idx - Interface index to be translated. - */ + /* skip unicast */ + if (esock_get_bool_from_map(env, eflags, atom_skip_unicast, FALSE)) + val |= GAA_FLAG_SKIP_UNICAST; + + /* skip anycast */ + if (esock_get_bool_from_map(env, eflags, atom_skip_anycast, TRUE)) + val |= GAA_FLAG_SKIP_ANYCAST; + + /* skip multicast */ + if (esock_get_bool_from_map(env, eflags, atom_skip_multicast, TRUE)) + val |= GAA_FLAG_SKIP_MULTICAST; + + /* skip dns-server */ + if (esock_get_bool_from_map(env, eflags, atom_skip_dns_server, TRUE)) + val |= GAA_FLAG_SKIP_DNS_SERVER; + + /* skip fiendly-name */ + if (esock_get_bool_from_map(env, eflags, atom_skip_friendly_name, TRUE)) + val |= GAA_FLAG_SKIP_FRIENDLY_NAME; + + /* include prefix */ + if (esock_get_bool_from_map(env, eflags, atom_include_prefix, TRUE)) + val |= GAA_FLAG_INCLUDE_PREFIX; + + /* include wins-info */ + if (esock_get_bool_from_map(env, eflags, atom_include_wins_info, FALSE)) + val |= GAA_FLAG_INCLUDE_WINS_INFO; + + /* include gateways */ + if (esock_get_bool_from_map(env, eflags, atom_include_gateways, FALSE)) + val |= GAA_FLAG_INCLUDE_GATEWAYS; + + /* include all-interfaces */ + if (esock_get_bool_from_map(env, eflags, + atom_include_all_interfaces, FALSE)) + val |= GAA_FLAG_INCLUDE_ALL_INTERFACES; + + /* include all-compartments */ + if (esock_get_bool_from_map(env, eflags, + atom_include_all_compartments, FALSE)) + val |= GAA_FLAG_INCLUDE_ALL_COMPARTMENTS; + + /* include tunnel-bindingorder */ + if (esock_get_bool_from_map(env, eflags, + atom_include_tunnel_bindingorder, FALSE)) + val |= GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER; + + *flags = val; + return TRUE; + } +} +#endif // __WIN32__ + +#if defined(__WIN32__) static -ERL_NIF_TERM nif_if_index2name(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM enet_get_adapters_addresses(ErlNifEnv* env, + BOOLEAN_T dbg, + ULONG family, + ULONG flags) { -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_IF_INDEXTONAME) - ERL_NIF_TERM result; - unsigned int idx; + int i; + DWORD ret; + unsigned long ipAdAddrsSz = 16 * 1024; + IP_ADAPTER_ADDRESSES* ipAdAddrsP; + ERL_NIF_TERM eret, addrs, result; + + ipAdAddrsP = (IP_ADAPTER_ADDRESSES*) MALLOC(ipAdAddrsSz); + for (i = 17; i; i--) { + ret = GetAdaptersAddresses(family, flags, NULL, + ipAdAddrsP, &ipAdAddrsSz); + if (ret == NO_ERROR) { + /* We are done! */ + break; + } else if (ret == ERROR_BUFFER_OVERFLOW) { + /* Not large enough */ + ipAdAddrsP = REALLOC(ipAdAddrsP, ipAdAddrsSz); + continue; + } else { + /* Failure */ + i = 0; + } + if (ret == NO_ERROR) break; + if (ret == ERROR_BUFFER_OVERFLOW) continue; + i = 0; + } - NDBG( ("NET", "nif_if_index2name -> entry (%d)\r\n", argc) ); + if (! i) { + + NDBG2( dbg, + ("NET", "enet_get_adapters_addresses -> " + "try encode error (%d)\r\n", ret) ); + + FREE(ipAdAddrsP); + + switch (ret) { + case ERROR_ADDRESS_NOT_ASSOCIATED: + eret = atom_address_not_associated; + break; + case ERROR_BUFFER_OVERFLOW: + eret = atom_insufficient_buffer; + break; + case ERROR_INVALID_PARAMETER: + eret = atom_invalid_parameter; + break; + case ERROR_NO_DATA: + eret = atom_no_data; + break; + case ERROR_NOT_ENOUGH_MEMORY: + eret = atom_not_enough_memory; + break; + default: + eret = MKI(env, ret); + break; + } - if ((argc != 1) || - !GET_UINT(env, argv[0], &idx)) { - return enif_make_badarg(env); - } + result = esock_make_error(env, eret); - NDBG( ("NET", "nif_index2name -> " - "\r\n Idx: %T" - "\r\n", argv[0]) ); + } else { - result = enet_if_index2name(env, idx); + NDBG2( dbg, + ("NET", "enet_get_adapters_addresses -> " + "try encode addresses\r\n") ); - NDBG( ("NET", "nif_if_index2name -> done when result: %T\r\n", result) ); + addrs = enet_adapters_addresses_encode(env, dbg, ipAdAddrsP); + result = esock_make_ok2(env, addrs); + + } + + NDBG2( dbg, + ("NET", "enet_get_adapters_addresses -> done with:" + "\r\n result: %T" + "\r\n", result) ); return result; -#else - return esock_make_error(env, esock_atom_enotsup); -#endif } +#endif - -#if !defined(__WIN32__) && defined(HAVE_IF_INDEXTONAME) +#if defined(__WIN32__) static -ERL_NIF_TERM enet_if_index2name(ErlNifEnv* env, - unsigned int idx) +ERL_NIF_TERM enet_adapters_addresses_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_ADDRESSES* ipAdAddrsP) { - ERL_NIF_TERM result; - char* ifn = MALLOC(IF_NAMESIZE+1); + /* No idea how many we actually need, so just get some */ + SocketTArray adapterArray = TARRAY_CREATE(16); + IP_ADAPTER_ADDRESSES* addrsP = ipAdAddrsP; + ERL_NIF_TERM entry, result; - if (ifn == NULL) - return enif_make_badarg(env); // PLACEHOLDER + NDBG2( dbg, ("NET", "enet_get_adapters_addresses -> entry\r\n") ); - if (NULL != if_indextoname(idx, ifn)) { - result = esock_make_ok2(env, MKS(env, ifn)); - } else { - result = esock_make_error(env, atom_enxio); - } + while (addrsP != NULL) { + /* Process current adapter */ + entry = enet_adapter_addresses_encode(env, dbg, addrsP); - FREE(ifn); + NDBG2( dbg, ("NET", "enet_get_adapters_addresses -> entry encoded:" + "\r\n Adapter Entry: %T" + "\r\n", entry) ); - return result; -} -#endif + TARRAY_ADD(adapterArray, entry); + + addrsP = addrsP->Next; + } + TARRAY_TOLIST(adapterArray, env, &result); + NDBG2( dbg, ("NET", "enet_get_adapters_addresses -> done:" + "\r\n %T" + "\r\n", result) ); + + return result; + + } +#endif // __WIN32__ -/* ---------------------------------------------------------------------- - * nif_if_names - * - * Description: - * Get network interface names and indexes. - * - */ + +#if defined(__WIN32__) static -ERL_NIF_TERM nif_if_names(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM enet_adapter_addresses_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_ADDRESSES* ipAdAddrsP) { -#if defined(__WIN32__) || (defined(__ANDROID__) && (__ANDROID_API__ < 24)) - return enif_raise_exception(env, MKA(env, "notsup")); -#elif defined(HAVE_IF_NAMEINDEX) && defined(HAVE_IF_FREENAMEINDEX) - ERL_NIF_TERM result; + ERL_NIF_TERM ifIdx, name; + ERL_NIF_TERM unicastAddrs, anycastAddrs, multicastAddrs, dnsServerAddrs; + ERL_NIF_TERM dnsSuffix, description, flags, physAddr, fName, mtu, ifType; + ERL_NIF_TERM operStatus, zoneIndices, ipv6IfIdx, prefixes; + ERL_NIF_TERM map; + + ifIdx = MKI(env, ipAdAddrsP->IfIndex); + name = MKS(env, ipAdAddrsP->AdapterName); + unicastAddrs = encode_adapter_unicast_addrs(env, ipAdAddrsP->FirstUnicastAddress); + anycastAddrs = encode_adapter_anycast_addrs(env, ipAdAddrsP->FirstAnycastAddress); + multicastAddrs = encode_adapter_multicast_addrs(env, ipAdAddrsP->FirstMulticastAddress); + dnsServerAddrs = encode_adapter_dns_server_addrs(env, ipAdAddrsP->FirstDnsServerAddress); + dnsSuffix = encode_wchar(env, ipAdAddrsP->DnsSuffix); + description = encode_wchar(env, ipAdAddrsP->Description); + fName = encode_wchar(env, ipAdAddrsP->FriendlyName); + physAddr = encode_uchar(env, + ipAdAddrsP->PhysicalAddressLength, + ipAdAddrsP->PhysicalAddress); + flags = encode_adapter_flags(env, ipAdAddrsP); + mtu = MKUI(env, ipAdAddrsP->Mtu); + ifType = encode_if_type(env, ipAdAddrsP->IfType); + operStatus = encode_if_oper_status(env, ipAdAddrsP->OperStatus); + zoneIndices = encode_adapter_zone_indices(env, + ipAdAddrsP->ZoneIndices, + NUM(ipAdAddrsP->ZoneIndices)); + ipv6IfIdx = MKI(env, ipAdAddrsP->Ipv6IfIndex); + prefixes = encode_adapter_prefixes(env, ipAdAddrsP->FirstPrefix); + + /* *** _LH *** */ + // tLinkSpeed = MKUI64(env, ipAdAddrsP->TransmitLinkSpeed); + // rLinkSpeed = MKUI64(env, ipAdAddrsP->ReceiveLinkSpeed); + // winsServerAddr = ... + // gatewayAddr = ... + // ipv4Metric = ... + // ipv6Metric = ... + // luid = ... + // dhcpv4Server = ... + // compartmentId = ... + // networkDuid = ... + // connectionType = ... + // tunnelType = ... + // dhcpv6Server = ... + // dhcpv6ClientDuid = ... + // dhcpv6Iaid = ... + // dnsSuffix = ... + + { + ERL_NIF_TERM keys[] = {atom_index, + esock_atom_name, + atom_unicast_addrs, + atom_anycast_addrs, + atom_multicast_addrs, + atom_dns_server_addrs, + atom_dns_suffix, + atom_description, + atom_friendly_name, + atom_phys_addr, + esock_atom_flags, + esock_atom_mtu, + esock_atom_type, + atom_oper_status, + atom_zone_indices, + atom_ipv6_index, + atom_prefixes/* , */ + /* atom_transmit_link_speed, */ + /* atom_receive_link_speed */ + }; + ERL_NIF_TERM vals[] = {ifIdx, + name, + unicastAddrs, + anycastAddrs, + multicastAddrs, + dnsServerAddrs, + dnsSuffix, + description, + fName, + physAddr, + flags, + mtu, + ifType, + operStatus, + zoneIndices, + ipv6IfIdx, + prefixes + /* , */ + /* tLinkSpeed, */ + /* rLinkSpeed */ + }; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &map) ); + } + + return map; +} +#endif // __WIN32__ - NDBG( ("NET", "nif_if_names -> entry (%d)\r\n", argc) ); +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_flags(ErlNifEnv* env, + IP_ADAPTER_ADDRESSES* ipAdAddrsP) +{ + ERL_NIF_TERM ddnsEnabled, regAdSuffix, dhcpv4Enabled, recvOnly; + ERL_NIF_TERM noMulticast, ipv6OtherStatefulCfg, netbiosOverTcpipEnabled; + ERL_NIF_TERM ipv4Enabled, ipv6Enabled, ipv6ManagedAddrCfgSup; + ERL_NIF_TERM eflags; - if (argc != 0) { - return enif_make_badarg(env); +#if defined(ESOCK_WIN_XP) + /* This is just a dummy-ifdef ... there is no such flag (ESOCK_WIN_XP). + * But this is a way to keep the code... + */ + ddnsEnabled = BOOL2ATOM(ipAdAddrsP->DdnsEnabled); + regAdSuffix = BOOL2ATOM(ipAdAddrsP->RegisterAdapterSuffix); + dhcpv4Enabled = BOOL2ATOM(ipAdAddrsP->Dhcpv4Enabled); + recvOnly = BOOL2ATOM(ipAdAddrsP->ReceiveOnly); + noMulticast = BOOL2ATOM(ipAdAddrsP->NoMulticast); + ipv6OtherStatefulCfg = BOOL2ATOM(ipAdAddrsP->Ipv6OtherStatefulConfig); + netbiosOverTcpipEnabled = BOOL2ATOM(ipAdAddrsP->NetbiosOverTcpipEnabled); + ipv4Enabled = BOOL2ATOM(ipAdAddrsP->Ipv4Enabled); + ipv6Enabled = BOOL2ATOM(ipAdAddrsP->Ipv6Enabled); + ipv6ManagedAddrCfgSup = BOOL2ATOM(ipAdAddrsP->Ipv6ManagedAddressConfigurationSupported); +#else + ddnsEnabled = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_DDNS_ENABLED); + regAdSuffix = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_REGISTER_ADAPTER_SUFFIX); + dhcpv4Enabled = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_DHCP_ENABLED); + recvOnly = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_RECEIVE_ONLY); + noMulticast = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_NO_MULTICAST); + ipv6OtherStatefulCfg = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG); + netbiosOverTcpipEnabled = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_NETBIOS_OVER_TCPIP_ENABLED); + ipv4Enabled = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_IPV4_ENABLED); + ipv6Enabled = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_IPV6_ENABLED); + ipv6ManagedAddrCfgSup = BOOL2ATOM(ipAdAddrsP->Flags & IP_ADAPTER_IPV6_MANAGE_ADDRESS_CONFIG); +#endif + + { + ERL_NIF_TERM keys[] = {atom_ddns_enabled, + atom_register_adapter_suffix, + atom_dhcp_v4_enabled, + atom_receive_only, + atom_no_multicast, + atom_ipv6_other_stateful_config, + atom_netbios_over_tcpip_enabled, + atom_ipv4_enabled, + atom_ipv6_enabled, + atom_ipv6_managed_address_config_supported}; + ERL_NIF_TERM vals[] = {ddnsEnabled, + regAdSuffix, + dhcpv4Enabled, + recvOnly, + noMulticast, + ipv6OtherStatefulCfg, + netbiosOverTcpipEnabled, + ipv4Enabled, + ipv6Enabled, + ipv6ManagedAddrCfgSup}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eflags) ); } + + return eflags; +} +#endif // __WIN32__ - result = enet_if_names(env); +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addrs(ErlNifEnv* env, + IP_ADAPTER_UNICAST_ADDRESS* firstP) +{ + IP_ADAPTER_UNICAST_ADDRESS* tmp = firstP; + SocketTArray ta = TARRAY_CREATE(16); + ERL_NIF_TERM eaddrs; + - NDBG( ("NET", "nif_if_names -> done when result: %T\r\n", result) ); + while (tmp != NULL) { + TARRAY_ADD(ta, encode_adapter_unicast_addr(env, tmp)); + tmp = tmp->Next; + } - return result; -#else - return esock_make_error(env, esock_atom_enotsup); -#endif + TARRAY_TOLIST(ta, env, &eaddrs); + + return eaddrs; } +#endif // __WIN32__ +#if defined(__WIN32__) +/* + * unicast_address() :: + * #{flags := #{dns_eligible := boolean(), + * transient := boolean()}, + * addr := socket:address(), + * prefix_origin := ip_prefix_origin(), + * suffix_origin := ip_suffix_origin(), + * dad_state := ip_dad_state(), + * valid_lifetime := ulong(), + * preferred_lifetime := ulong(), + * lease_lifetime := ulong(), + * on_link_prefix_length := uint8()} + */ +static +ERL_NIF_TERM encode_adapter_unicast_addr(ErlNifEnv* env, + IP_ADAPTER_UNICAST_ADDRESS* addrP) +{ + ERL_NIF_TERM eflags, esa, eporig, esorig, edstate, evlt, eplt, ellt; + /* ERL_NIF_TERM eplen; - Not on XP */ + ERL_NIF_TERM eua; + + eflags = encode_adapter_unicast_addr_flags(env, addrP->Flags); + esa = encode_adapter_unicast_addr_sockaddr(env, + addrP->Address.lpSockaddr); + eporig = encode_adapter_unicast_addr_porig(env, addrP->PrefixOrigin); + esorig = encode_adapter_unicast_addr_sorig(env, addrP->SuffixOrigin); + edstate = encode_adapter_unicast_addr_dad_state(env, addrP->DadState); + evlt = MKUL(env, addrP->ValidLifetime); + eplt = MKUL(env, addrP->PreferredLifetime); + ellt = MKUL(env, addrP->LeaseLifetime); + /* eplen = MKUI(env, addrP->OnLinkPrefixLength); - Not on XP */ -/* if_nameindex and if_freenameindex were added in Android 7.0 Nougat. With -the Android NDK Unified Headers, check that the build is targeting at least + /* + if (addrP->Address.lpSockaddr->sa_family == AF_INET) + { + struct sockaddr* sinP = addrP->Address.lpSockaddr; + ERL_NIF_TERM keys[] = {esock_atom_flags, + esock_atom_addr, + MKA(env, "raw_addr"), + MKA(env, "raw_addr_ntohl"), + atom_prefix_origin, + atom_suffix_origin, + atom_dad_state, + atom_valid_lifetime, + atom_preferred_lifetime, + atom_lease_lifetime + }; + ERL_NIF_TERM vals[] = {eflags, + esa, + MKUI(env, (DWORD) (((struct sockaddr_in *)sinP)->sin_addr.s_addr)), + MKUI(env, ntohl((DWORD) (((struct sockaddr_in *)sinP)->sin_addr.s_addr))), + eporig, + esorig, + edstate, + evlt, + eplt, + ellt + }; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eua) ); + + } else + */ + { + ERL_NIF_TERM keys[] = {esock_atom_flags, + esock_atom_addr, + atom_prefix_origin, + atom_suffix_origin, + atom_dad_state, + atom_valid_lifetime, + atom_preferred_lifetime, + atom_lease_lifetime/* , + on_link_prefix_length + Not on XP */ + }; + ERL_NIF_TERM vals[] = {eflags, + esa, + eporig, + esorig, + edstate, + evlt, + eplt, + ellt/*, + eplen + Not pn XP */ + }; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eua) ); + + } + + return eua; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addr_flags(ErlNifEnv* env, + DWORD flags) +{ + ERL_NIF_TERM map; + ERL_NIF_TERM dnsEl = BOOL2ATOM(flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE); + ERL_NIF_TERM trans = BOOL2ATOM(flags & IP_ADAPTER_ADDRESS_TRANSIENT); + ERL_NIF_TERM keys[] = {atom_dns_eligible, atom_transient}; + ERL_NIF_TERM vals[] = {dnsEl, trans}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &map) ); + + return map; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP) +{ + return encode_sockaddr(env, addrP); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addr_porig(ErlNifEnv* env, + IP_PREFIX_ORIGIN porig) +{ + ERL_NIF_TERM eporig; + + switch (porig) { + case IpPrefixOriginOther: + eporig = atom_other; + break; + + case IpPrefixOriginManual: + eporig = atom_manual; + break; + + case IpPrefixOriginWellKnown: + eporig = atom_well_known; + break; + + case IpPrefixOriginDhcp: + eporig = atom_dhcp; + break; + + case IpPrefixOriginRouterAdvertisement: + eporig = atom_router_advertisement; + break; + + case IpPrefixOriginUnchanged: + eporig = atom_unchanged; + break; + + default: + eporig = MKI(env, (int) porig); + break; + } + + return eporig; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addr_sorig(ErlNifEnv* env, + IP_SUFFIX_ORIGIN sorig) +{ + ERL_NIF_TERM esorig; + + switch (sorig) { + case IpSuffixOriginOther: + esorig = atom_other; + break; + + case IpSuffixOriginManual: + esorig = atom_manual; + break; + + case IpSuffixOriginWellKnown: + esorig = atom_well_known; + break; + + case IpSuffixOriginDhcp: + esorig = atom_dhcp; + break; + + case IpSuffixOriginLinkLayerAddress: + esorig = atom_link_layer_address; + break; + + case IpSuffixOriginRandom: + esorig = atom_random; + break; + + case IpSuffixOriginUnchanged: + esorig = atom_unchanged; + break; + + default: + esorig = MKI(env, (int) sorig); + break; + } + + return esorig; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_unicast_addr_dad_state(ErlNifEnv* env, + IP_DAD_STATE dstate) +{ + ERL_NIF_TERM edstate; + + switch (dstate) { + case IpDadStateInvalid: + edstate = atom_invalid; + break; + + case IpDadStateTentative: + edstate = atom_tentative; + break; + + case IpDadStateDuplicate: + edstate = atom_duplicate; + break; + + case IpDadStateDeprecated: + edstate = atom_deprecated; + break; + + case IpDadStatePreferred: + edstate = atom_preferred; + break; + + default: + edstate = MKI(env, (int) dstate); + break; + } + + return edstate; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_anycast_addrs(ErlNifEnv* env, + IP_ADAPTER_ANYCAST_ADDRESS* firstP) +{ + IP_ADAPTER_ANYCAST_ADDRESS* tmp = firstP; + SocketTArray ta = TARRAY_CREATE(16); + ERL_NIF_TERM eaddrs; + + + while (tmp != NULL) { + TARRAY_ADD(ta, encode_adapter_anycast_addr(env, tmp)); + tmp = tmp->Next; + } + + TARRAY_TOLIST(ta, env, &eaddrs); + + return eaddrs; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * anycast_address() :: + * #{flags := #{dns_eligible := boolean(), + * transient := boolean()}, + * addr := socket:address()} + */ +static +ERL_NIF_TERM encode_adapter_anycast_addr(ErlNifEnv* env, + IP_ADAPTER_ANYCAST_ADDRESS* addrP) +{ + ERL_NIF_TERM eflags, esa; + ERL_NIF_TERM eaa; + + eflags = encode_adapter_anycast_addr_flags(env, addrP->Flags); + esa = encode_adapter_anycast_addr_sockaddr(env, + addrP->Address.lpSockaddr); + { + ERL_NIF_TERM keys[] = {esock_atom_flags, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {eflags, + esa}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eaa) ); + + } + + return eaa; +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_anycast_addr_flags(ErlNifEnv* env, + DWORD flags) +{ + return encode_adapter_unicast_addr_flags(env, flags); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_anycast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP) +{ + return encode_sockaddr(env, addrP); +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_multicast_addrs(ErlNifEnv* env, + IP_ADAPTER_MULTICAST_ADDRESS* firstP) +{ + IP_ADAPTER_MULTICAST_ADDRESS* tmp = firstP; + SocketTArray ta = TARRAY_CREATE(16); + ERL_NIF_TERM eaddrs; + + while (tmp != NULL) { + TARRAY_ADD(ta, encode_adapter_multicast_addr(env, tmp)); + tmp = tmp->Next; + } + + TARRAY_TOLIST(ta, env, &eaddrs); + + return eaddrs; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * multicast_address() :: + * #{flags := #{dns_eligible := boolean(), + * transient := boolean()}, + * addr := socket:address()} + */ +static +ERL_NIF_TERM encode_adapter_multicast_addr(ErlNifEnv* env, + IP_ADAPTER_MULTICAST_ADDRESS* addrP) +{ + ERL_NIF_TERM eflags, esa; + ERL_NIF_TERM ema; + + eflags = encode_adapter_multicast_addr_flags(env, addrP->Flags); + esa = encode_adapter_multicast_addr_sockaddr(env, + addrP->Address.lpSockaddr); + { + ERL_NIF_TERM keys[] = {esock_atom_flags, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {eflags, + esa}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &ema) ); + + } + + return ema; +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_multicast_addr_flags(ErlNifEnv* env, + DWORD flags) +{ + return encode_adapter_unicast_addr_flags(env, flags); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_multicast_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP) +{ + return encode_sockaddr(env, addrP); +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_dns_server_addrs(ErlNifEnv* env, + IP_ADAPTER_DNS_SERVER_ADDRESS* firstP) +{ + IP_ADAPTER_DNS_SERVER_ADDRESS* tmp = firstP; + SocketTArray ta = TARRAY_CREATE(16); + ERL_NIF_TERM eaddrs; + + while (tmp != NULL) { + TARRAY_ADD(ta, encode_adapter_dns_server_addr(env, tmp)); + tmp = tmp->Next; + } + + TARRAY_TOLIST(ta, env, &eaddrs); + + return eaddrs; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * dns_server_address() :: + * #{addr := socket:address()} + */ +static +ERL_NIF_TERM encode_adapter_dns_server_addr(ErlNifEnv* env, + IP_ADAPTER_DNS_SERVER_ADDRESS* addrP) +{ + ERL_NIF_TERM esa; + ERL_NIF_TERM edsa; + + esa = encode_adapter_dns_server_addr_sockaddr(env, + addrP->Address.lpSockaddr); + { + ERL_NIF_TERM keys[] = {esock_atom_addr}; + ERL_NIF_TERM vals[] = {esa}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &edsa) ); + + } + + return edsa; +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_dns_server_addr_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP) +{ + return encode_sockaddr(env, addrP); +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_if_oper_status(ErlNifEnv* env, + DWORD status) +{ + ERL_NIF_TERM estatus; + + switch (status) { + case IfOperStatusUp: + estatus = esock_atom_up; + break; + case IfOperStatusDown: + estatus = atom_down; + break; + case IfOperStatusTesting: + estatus = atom_testing; + break; + case IfOperStatusUnknown: + estatus = atom_unknown; + break; + case IfOperStatusDormant: + estatus = esock_atom_dormant; + break; + case IfOperStatusNotPresent: + estatus = atom_not_present; + break; + case IfOperStatusLowerLayerDown: + estatus = atom_lower_layer_down; + break; + default: + estatus = MKUI(env, status); + break; + } + + return estatus; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_zone_indices(ErlNifEnv* env, + DWORD* zoneIndices, + DWORD len) +{ + SocketTArray ta = TARRAY_CREATE(len); + DWORD i; + ERL_NIF_TERM ezi; + + for (i = 0; i < len; i++) { + TARRAY_ADD(ta, MKUI(env, zoneIndices[i])); + } + + TARRAY_TOLIST(ta, env, &ezi); + + return ezi; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_prefixes(ErlNifEnv* env, + IP_ADAPTER_PREFIX* firstP) +{ + IP_ADAPTER_PREFIX* tmp = firstP; + SocketTArray ta = TARRAY_CREATE(16); + ERL_NIF_TERM eprefs; + + while (tmp != NULL) { + TARRAY_ADD(ta, encode_adapter_prefix(env, tmp)); + tmp = tmp->Next; + } + + TARRAY_TOLIST(ta, env, &eprefs); + + return eprefs; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * prerix() :: + * #{addr := socket:address(), + * length := non_neg_integer()} + */ +static +ERL_NIF_TERM encode_adapter_prefix(ErlNifEnv* env, + IP_ADAPTER_PREFIX* prefP) +{ + ERL_NIF_TERM esa, eplen; + ERL_NIF_TERM epref; + + esa = encode_adapter_prefix_sockaddr(env, prefP->Address.lpSockaddr); + eplen = MKUI(env, prefP->PrefixLength); + /* + if (prefP->Address.lpSockaddr->sa_family == AF_INET) + { + struct sockaddr* sinP = prefP->Address.lpSockaddr; + ERL_NIF_TERM keys[] = {esock_atom_addr, + atom_length, + MKA(env, "raw_addr"), + MKA(env, "raw_addr_ntohl")}; + ERL_NIF_TERM vals[] = + {esa, eplen, + MKUI(env, (DWORD) (((struct sockaddr_in *)sinP)->sin_addr.s_addr)), + MKUI(env, ntohl((DWORD) (((struct sockaddr_in *)sinP)->sin_addr.s_addr)))}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &epref) ); + } else + */ + { + ERL_NIF_TERM keys[] = {esock_atom_addr, atom_length}; + ERL_NIF_TERM vals[] = {esa, eplen}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &epref) ); + + } + + return epref; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_prefix_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP) +{ + return encode_sockaddr(env, addrP); +} +#endif // __WIN32__ + + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM enet_adapter_encode_name(ErlNifEnv* env, WCHAR* name) +{ + return encode_wchar(env, name); +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM enet_adapter_encode_friendly_name(ErlNifEnv* env, WCHAR* fname) +{ + return encode_wchar(env, fname); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_adapter_index_map_name(ErlNifEnv* env, WCHAR* name) +{ + return encode_wchar(env, name); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +void make_adapter_index_map(ErlNifEnv* env, + ERL_NIF_TERM eindex, + ERL_NIF_TERM ename, + ERL_NIF_TERM* emap) +{ + ERL_NIF_TERM keys[2]; + ERL_NIF_TERM vals[2]; + size_t len = NUM(keys); // Just in case... + + /* Index */ + NDBG( ("NET", "make_adapter_index_map -> index: %T\r\n", eindex) ); + keys[0] = atom_index; + vals[0] = eindex; + + /* Name */ + NDBG( ("NET", "make_adapter_index_map -> name: %T\r\n", ename) ); + keys[1] = esock_atom_name; + vals[1] = ename; + + ESOCK_ASSERT( MKMA(env, keys, vals, len, emap) ); +} +#endif // __WIN32__ + + + +/* ---------------------------------------------------------------------- + * nif_get_if_entry + * + * Description: + * Get If Entry + * This is a windows only function! + * + * Arguments: + * Args - A way to pass arguments. + * Currently only used for: index and debug: + * #{index := non_neg_integer(), + * debug := boolean() (optional)} + * + * Results: + * {ok, mib_if_row()} | {error, Reason :: term()} + */ +static +ERL_NIF_TERM nif_get_if_entry(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if !defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result, eargs; + DWORD index; + BOOLEAN_T dbg; + + NDBG( ("NET", "nif_get_if_entry -> entry (%d)\r\n", argc) ); + + if ((argc != 1) || + !IS_MAP(env, argv[0])) { + return enif_make_badarg(env); + } + eargs = argv[0]; + + if (!enet_get_if_entry_args_index(env, eargs, &index)) + return enif_make_badarg(env); + + dbg = enet_get_if_entry_args_debug(env, eargs); + + result = enet_get_if_entry(env, dbg, index); + + NDBG2( dbg, + ("NET", + "nif_get_if_entry -> done when result: " + "\r\n %T\r\n", result) ); + + return result; +#endif +} + + +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_if_entry_args_index(ErlNifEnv* env, + const ERL_NIF_TERM eargs, + DWORD* index) +{ + ERL_NIF_TERM key = atom_index; + ERL_NIF_TERM eval; + DWORD val; + + if (!GET_MAP_VAL(env, eargs, key, &eval)) { + return FALSE; + } else { + if (!IS_NUM(env, eval)) + return FALSE; + + if (!GET_UINT(env, eval, &val)) + return FALSE; + + *index = val; + return TRUE; + } +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_if_entry_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs) +{ + return get_debug(env, eargs); +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM enet_get_if_entry(ErlNifEnv* env, + BOOLEAN_T dbg, + DWORD index) +{ + DWORD ret; + MIB_IFROW ifRow; + ERL_NIF_TERM eifRow, result; + + NDBG2( dbg, + ("NET", "nif_get_if_entry -> entry with" + "\r\n index: %d\r\n", index) ); + + sys_memzero(&ifRow, sizeof(ifRow)); + ifRow.dwIndex = index; + ret = GetIfEntry(&ifRow); + + NDBG2( dbg, + ("NET", "nif_get_if_entry -> get-if-entru result:" + "\r\n %d\r\n", ret) ); + + switch (ret) { + /* Success */ + case NO_ERROR: + eifRow = enet_if_row_encode(env, dbg, &ifRow); + result = esock_make_ok2(env, eifRow); + break; + + /* Known errors */ + case ERROR_CAN_NOT_COMPLETE: + result = esock_make_error(env, atom_can_not_complete); + break; + case ERROR_INVALID_DATA: + result = esock_make_error(env, atom_invalid_data); + break; + case ERROR_INVALID_PARAMETER: + result = esock_make_error(env, atom_invalid_parameter); + break; + case ERROR_NOT_FOUND: + result = esock_make_error(env, esock_atom_not_found); + break; + case ERROR_NOT_SUPPORTED: + result = esock_make_error(env, atom_not_supported); + break; + + /* Other errors */ + default: + result = esock_make_error(env, MKI(env, ret)); + break; + } + + NDBG2( dbg, + ("NET", "nif_get_if_entry -> done when:" + "\r\n result: %T\r\n", result) ); + + return result; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +// Returns: mib_if_row() +static +ERL_NIF_TERM enet_if_row_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IFROW* rowP) +{ + ERL_NIF_TERM eName, eIndex, eType, eMtu, eSpeed, ePhuysAddr, eAdminStatus; + ERL_NIF_TERM eOperStatus, eLastChange, eInOctets, eInUcastPkts; + ERL_NIF_TERM eInNUcastPkts, eInDiscards, eInError, eInUnknownProtos; + ERL_NIF_TERM eOutOcts, eOutUcastPkts, eOutNUcastPkts, eOutDiscards; + ERL_NIF_TERM eOutErrors, eOutQLen, eDescr; + ERL_NIF_TERM erow; + + NDBG2( dbg, ("NET", "enet_if_row_encode -> entry\r\n") ); + + eName = encode_wchar(env, rowP->wszName); + eIndex = MKUI(env, rowP->dwIndex); + eType = encode_if_type(env, rowP->dwType); + eMtu = MKUI(env, rowP->dwMtu); + eSpeed = MKUI(env, rowP->dwSpeed); + ePhuysAddr = encode_if_row_phys_address(env, + rowP->dwPhysAddrLen, + rowP->bPhysAddr); + eAdminStatus = encode_if_admin_status(env, rowP->dwAdminStatus); + eOperStatus = encode_internal_if_oper_status(env, rowP->dwOperStatus); + eLastChange = MKUI(env, rowP->dwLastChange); + eInOctets = MKUI(env, rowP->dwInOctets); + eInUcastPkts = MKUI(env, rowP->dwInUcastPkts); + eInNUcastPkts = MKUI(env, rowP->dwInNUcastPkts); + eInDiscards = MKUI(env, rowP->dwInDiscards); + eInError = MKUI(env, rowP->dwInErrors); + eInUnknownProtos = MKUI(env, rowP->dwInUnknownProtos); + eOutOcts = MKUI(env, rowP->dwOutOctets); + eOutUcastPkts = MKUI(env, rowP->dwOutUcastPkts); + eOutNUcastPkts = MKUI(env, rowP->dwOutNUcastPkts); + eOutDiscards = MKUI(env, rowP->dwOutDiscards); + eOutErrors = MKUI(env, rowP->dwOutErrors); + eOutQLen = MKUI(env, rowP->dwOutQLen); + eDescr = encode_if_row_description(env, + rowP->dwDescrLen, + rowP->bDescr); + { + ERL_NIF_TERM keys[] = {esock_atom_name, + atom_index, + esock_atom_type, + esock_atom_mtu, + atom_speed, + atom_phys_addr, + atom_admin_status, + atom_internal_oper_status, + atom_last_change, + atom_in_octets, + atom_in_ucast_pkts, + atom_in_nucast_pkts, + atom_in_discards, + atom_in_errors, + atom_in_unknown_protos, + atom_out_octets, + atom_out_ucast_pkts, + atom_out_nucast_pkts, + atom_out_discards, + atom_out_errors, + atom_out_qlen, + atom_description}; + ERL_NIF_TERM vals[] = {eName, + eIndex, + eType, + eMtu, + eSpeed, + ePhuysAddr, + eAdminStatus, + eOperStatus, + eLastChange, + eInOctets, + eInUcastPkts, + eInNUcastPkts, + eInDiscards, + eInError, + eInUnknownProtos, + eOutOcts, + eOutUcastPkts, + eOutNUcastPkts, + eOutDiscards, + eOutErrors, + eOutQLen, + eDescr}; + size_t numKeys = NUM(keys); + size_t numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &erow) ); + } + + NDBG2( dbg, + ("NET", "enet_if_row_encode -> done with:" + "\r\n result: %T" + "\r\n", erow) ); + + return erow; + +} +#endif + + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_if_type(ErlNifEnv* env, + DWORD type) +{ + ERL_NIF_TERM etype; + + switch (type) { + case IF_TYPE_OTHER: + etype = atom_other; + break; + case IF_TYPE_ETHERNET_CSMACD: + etype = atom_ethernet_csmacd; + break; + case IF_TYPE_ISO88025_TOKENRING: + etype = atom_iso88025_tokenring; + break; + case IF_TYPE_FDDI: + etype = atom_fddi; + break; + case IF_TYPE_PPP: + etype = atom_ppp; + break; + case IF_TYPE_SOFTWARE_LOOPBACK: + etype = atom_software_loopback; + break; + case IF_TYPE_ATM: + etype = atom_atm; + break; + case IF_TYPE_IEEE80211: + etype = atom_ieee80211; + break; + case IF_TYPE_TUNNEL: + etype = atom_tunnel; + break; + case IF_TYPE_IEEE1394: + etype = atom_ieee1394; + break; + case IF_TYPE_IEEE80216_WMAN: + etype = atom_ieee80216_wman; + break; + case IF_TYPE_WWANPP: + etype = atom_wwanpp; + break; + case IF_TYPE_WWANPP2: + etype = atom_wwanpp2; + break; + default: + etype = MKUI(env, type); + break; + } + + return etype; + +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * The description is defined as a UCHAR array with a *max* length + * of MAXLEN_IFDESCR. But the actual length is defined by the + * dwDescrLen field. + * The documentation does not specify that its a NULL terminated + * string, but in practice that is what it is. But, if the string + * *is* MAXLEN_IFDESCR there is no room for a NULL terminator... + * So, just to be on the safe side we copy the text into a buffer + * of length = len + 1 and add an extra NULL character at the last + * position. Then we can handle the it as any NULL terminated string. + */ +static +ERL_NIF_TERM encode_if_row_description(ErlNifEnv* env, + DWORD len, + UCHAR* buf) +{ + ERL_NIF_TERM edesc; + UCHAR* tmp = MALLOC(len + 1); + + ESOCK_ASSERT( tmp != NULL ); + + sys_memcpy(tmp, buf, len); + tmp[len] = 0; + + edesc = MKS(env, tmp); + + FREE(tmp); + + return edesc; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_if_admin_status(ErlNifEnv* env, + DWORD status) +{ + ERL_NIF_TERM estatus; + + switch (status) { + case IF_OPER_STATUS_NON_OPERATIONAL: + estatus = atom_non_operational; + break; + case IF_OPER_STATUS_UNREACHABLE: + estatus = atom_unreachable; + break; + case IF_OPER_STATUS_DISCONNECTED: + estatus = atom_disconnected; + break; + case IF_OPER_STATUS_CONNECTING: + estatus = esock_atom_connecting; + break; + case IF_OPER_STATUS_CONNECTED: + estatus = esock_atom_connected; + break; + case IF_OPER_STATUS_OPERATIONAL: + estatus = atom_operational; + break; + default: + estatus = MKUI(env, status); + break; + } + + return estatus; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_internal_if_oper_status(ErlNifEnv* env, + DWORD status) +{ + ERL_NIF_TERM estatus; + + switch (status) { + case IF_OPER_STATUS_NON_OPERATIONAL: + estatus = atom_non_operational; + break; + case IF_OPER_STATUS_UNREACHABLE: + estatus = atom_unreachable; + break; + case IF_OPER_STATUS_DISCONNECTED: + estatus = atom_disconnected; + break; + case IF_OPER_STATUS_CONNECTING: + estatus = esock_atom_connecting; + break; + case IF_OPER_STATUS_CONNECTED: + estatus = esock_atom_connected; + break; + case IF_OPER_STATUS_OPERATIONAL: + estatus = atom_operational; + break; + default: + estatus = MKUI(env, status); + break; + } + + return estatus; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_if_row_phys_address(ErlNifEnv* env, + DWORD len, + UCHAR* buf) +{ + return encode_uchar(env, len, buf); +} +#endif // __WIN32__ + + + +/* ---------------------------------------------------------------------- + * nif_get_interface_info + * + * Description: + * Get interface info table (only IPv4 interfaces) + * This is a windows only function! + * + * Physical Interfaces? + * + * Arguments: + * Args - A way to pass arguments. + * Currently only used for debug. + * + * Results: + * {ok, [ip_adapter_index_map()]} | {error, Reason :: term()} + */ + +static +ERL_NIF_TERM nif_get_interface_info(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if !defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result, eargs; + BOOLEAN_T dbg; + + NDBG( ("NET", "nif_get_interface_info -> entry (%d)\r\n", argc) ); + + if ((argc != 1) || + !IS_MAP(env, argv[0])) { + return enif_make_badarg(env); + } + eargs = argv[0]; + + dbg = enet_get_interface_info_args_debug(env, eargs); + + result = enet_get_interface_info(env, dbg); + + NDBG2( dbg, + ("NET", + "nif_get_interface_info -> done when result: " + "\r\n %T\r\n", result) ); + + return result; +#endif +} + + +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_interface_info_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs) +{ + return get_debug(env, eargs); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM enet_get_interface_info(ErlNifEnv* env, + BOOLEAN_T dbg) +{ + int i; + DWORD ret; + unsigned long infoSize = 4 * 1024; + IP_INTERFACE_INFO* infoP = (IP_INTERFACE_INFO*) MALLOC(infoSize); + ERL_NIF_TERM eret, einfo, result; + + for (i = 17; i; i--) { + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> try get info with: " + "\r\n infoSize: %d" + "\r\n", infoSize) ); + + ret = GetInterfaceInfo(infoP, &infoSize); + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> " + "get-info result: %d (%d)\r\n", ret, infoSize) ); + + if (ret == NO_ERROR) { + /* We are done! */ + break; + } else if (ret == ERROR_INSUFFICIENT_BUFFER) { + /* Not large enough */ + infoP = REALLOC(infoP, infoSize); + continue; + } else { + /* Failure */ + i = 0; + } + } + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> " + "done when get info counter: %d\r\n", i) ); + + if (! i) { + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> " + "try encode error (%d)\r\n", ret) ); + + FREE(infoP); + + switch (ret) { + case ERROR_INSUFFICIENT_BUFFER: + eret = atom_insufficient_buffer; + break; + case ERROR_INVALID_PARAMETER: + eret = atom_invalid_parameter; + break; + case ERROR_NO_DATA: + eret = atom_no_data; + break; + case ERROR_NOT_SUPPORTED: + eret = atom_not_supported; + break; + default: + eret = MKI(env, ret); + break; + } + + result = esock_make_error(env, eret); + + } else { + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> try encode info\r\n") ); + + einfo = enet_interface_info_encode(env, dbg, infoP); + result = esock_make_ok2(env, einfo); + + FREE(infoP); + } + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> done with:" + "\r\n result: %T" + "\r\n", result) ); + + return result; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +// Returns: [#{index := integer(), name := string()}] +static +ERL_NIF_TERM enet_interface_info_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_INTERFACE_INFO* infoP) +{ + ERL_NIF_TERM result; + LONG num = infoP->NumAdapters; + + NDBG2( dbg, + ("NET", "enet_interface_info_encode -> entry with" + "\r\n num: %d" + "\r\n", num) ); + + if (num > 0) { + ERL_NIF_TERM* array = MALLOC(num * sizeof(ERL_NIF_TERM)); + LONG i = 0; + + while (i < num) { + ERL_NIF_TERM entry; + + NDBG2( dbg, + ("NET", "enet_interface_info_encode -> " + "try encode adapter %d" + "\r\n", i) ); + + encode_adapter_index_map(env, dbg, &infoP->Adapter[i], &entry); + + array[i] = entry; + i++; + } + + result = MKLA(env, array, num); + FREE(array); + + } else { + result = MKEL(env); + } + + NDBG2( dbg, + ("NET", "enet_get_interface_info -> done with:" + "\r\n result: %T" + "\r\n", result) ); + + return result; + +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * ip_adapter_index_map() :: #{name :: string(), + * index :: non_neg_integer()} + */ +static +void encode_adapter_index_map(ErlNifEnv* env, + BOOLEAN_T dbg, + IP_ADAPTER_INDEX_MAP* adapterP, + ERL_NIF_TERM* eadapter) +{ + ERL_NIF_TERM eindex = MKI(env, adapterP->Index); + ERL_NIF_TERM ename = encode_adapter_index_map_name(env, adapterP->Name); + ERL_NIF_TERM map; + + NDBG2( dbg, + ("NET", "encode_adapter_index_map -> map fields: " + "\r\n index: %T" + "\r\n name: %T" + "\r\n", eindex, ename) ); + + make_adapter_index_map(env, eindex, ename, &map); + + NDBG2( dbg, + ("NET", "encode_adapter_index_map -> encoded map: %T\r\n", map) ); + + *eadapter = map; +} +#endif // __WIN32__ + + + +/* ---------------------------------------------------------------------- + * nif_get_ip_address_table + * + * Description: + * Get ip address table table. + * This is a windows only function! + * + * Active Interfaces? + * + * Arguments: + * Args - A way to pass arguments. + * Currently only used for debug. + * + * Returns: + * {ok, [mib_ip_address_row()]} | {error, Reason :: term()} + */ + +static +ERL_NIF_TERM nif_get_ip_address_table(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if !defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result, eargs; + BOOLEAN_T dbg; + + NDBG( ("NET", "nif_get_ip_address_table -> entry (%d)\r\n", argc) ); + + if ((argc != 1) || + !IS_MAP(env, argv[0])) { + return enif_make_badarg(env); + } + eargs = argv[0]; + + dbg = enet_get_ip_address_table_args_debug(env, eargs); + + result = enet_get_ip_address_table(env, dbg); + + NDBG2( dbg, + ("NET", + "nif_get_ip_address_table -> done when result: " + "\r\n %T\r\n", result) ); + + return result; +#endif +} + + + +#if defined(__WIN32__) +static +BOOLEAN_T enet_get_ip_address_table_args_debug(ErlNifEnv* env, + const ERL_NIF_TERM eargs) +{ + return get_debug(env, eargs); +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM enet_get_ip_address_table(ErlNifEnv* env, + BOOLEAN_T dbg) +{ + int i; + DWORD ret; + /* The table is *not* just an array of 'row', + * but that is the significant part, so... + */ + unsigned long tabSize = 16*sizeof(MIB_IPADDRROW); + MIB_IPADDRTABLE* ipAddrTabP = (MIB_IPADDRTABLE*) MALLOC(tabSize); + ERL_NIF_TERM eret, etable, result; + + for (i = 17; i; i--) { + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table -> try get table with: " + "\r\n tabSize: %d" + "\r\n", tabSize) ); + + ret = GetIpAddrTable(ipAddrTabP, &tabSize, FALSE); + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table -> " + "get-tab result: %d (%d)\r\n", ret, tabSize) ); + + ipAddrTabP = REALLOC(ipAddrTabP, tabSize); + if (ret == NO_ERROR) break; + if (ret == ERROR_INSUFFICIENT_BUFFER) continue; + i = 0; + } + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table -> " + "done when get-tab counter: %d\r\n", i) ); + + if (! i) { + + NDBG2( dbg, + ("NET", + "enet_get_ip_address_table -> try transform error\r\n") ); + + FREE(ipAddrTabP); + + switch (ret) { + case ERROR_INSUFFICIENT_BUFFER: + eret = atom_insufficient_buffer; + break; + case ERROR_INVALID_PARAMETER: + eret = atom_invalid_parameter; + break; + case ERROR_NOT_SUPPORTED: + eret = atom_not_supported; + break; + default: + eret = MKI(env, ret); + break; + } + + result = esock_make_error(env, eret); + + } else { + + NDBG2( dbg, + ("NET", + "enet_get_ip_address_table -> try transform table\r\n") ); + + etable = enet_get_ip_address_table_encode(env, dbg, ipAddrTabP); + result = esock_make_ok2(env, etable); + + FREE(ipAddrTabP); + } + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table -> done with:" + "\r\n result: %T" + "\r\n", result) ); + + return result; +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +// Returns: [row()] +static +ERL_NIF_TERM enet_get_ip_address_table_encode(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IPADDRTABLE* tabP) +{ + ERL_NIF_TERM result; + LONG num = tabP->dwNumEntries; + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table_encode -> entry with" + "\r\n num: %d" + "\r\n", num) ); + + if (num > 0) { + ERL_NIF_TERM* array = MALLOC(num * sizeof(ERL_NIF_TERM)); + LONG i = 0; + + while (i < num) { + ERL_NIF_TERM entry; + + NDBG2( dbg, + ("NET", "enet_interface_info_encode -> " + "try encode ip-address-row %d" + "\r\n", i) ); + + entry = encode_ip_address_row(env, dbg, &tabP->table[i]); + + array[i] = entry; + i++; + } + + result = MKLA(env, array, num); + FREE(array); + + } else { + result = MKEL(env); + } + + NDBG2( dbg, + ("NET", "enet_get_ip_address_table -> done with:" + "\r\n result: %T" + "\r\n", result) ); + + return result; + +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +ERL_NIF_TERM encode_ip_address_row(ErlNifEnv* env, + BOOLEAN_T dbg, + MIB_IPADDRROW* rowP) +{ + ERL_NIF_TERM eaddr = encode_ip_address_row_addr(env, + dbg, "Addr", + rowP->dwAddr); + ERL_NIF_TERM eindex = MKUL(env, rowP->dwIndex); + ERL_NIF_TERM emask = encode_ip_address_row_addr(env, + dbg, "Mask", + rowP->dwMask); + ERL_NIF_TERM eBCastAddr = encode_ip_address_row_addr(env, + dbg, "BCaseAddr", + rowP->dwBCastAddr); + ERL_NIF_TERM eReasmSize = MKUL(env, rowP->dwReasmSize); + ERL_NIF_TERM map; + + NDBG2( dbg, + ("NET", "encode_ipAddress_row_map -> map fields: " + "\r\n address: %T" + "\r\n index: %T" + "\r\n mask: %T" + "\r\n bcas-addr: %T" + "\r\n reasm-size: %T" + "\r\n", eaddr, eindex, emask, eBCastAddr, eReasmSize) ); + + make_ip_address_row(env, eaddr, eindex, emask, eBCastAddr, eReasmSize, &map); + + NDBG2( dbg, + ("NET", "encode_ip_address_row -> encoded map: %T\r\n", map) ); + + return map; +} +#endif // __WIN32__ + + + +#if defined(__WIN32__) +/* Converts an *IPv4* address to an erlang term (4-tuple) */ +static +ERL_NIF_TERM encode_ip_address_row_addr(ErlNifEnv* env, + BOOLEAN_T dbg, + const char* descr, + DWORD addr) +{ + struct in_addr a; + ERL_NIF_TERM ea; + + NDBG2( dbg, + ("NET", + "encode_ip_address_row_addr -> entry with: " + "\r\n %s: %lu\r\n", descr, addr) ); + + a.s_addr = addr; + + esock_encode_in_addr(env, &a, &ea); + + return ea; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +static +void make_ip_address_row(ErlNifEnv* env, + ERL_NIF_TERM eaddr, + ERL_NIF_TERM eindex, + ERL_NIF_TERM emask, + ERL_NIF_TERM eBCastAddr, + ERL_NIF_TERM eReasmSize, + ERL_NIF_TERM* iar) +{ + ERL_NIF_TERM keys[] = {esock_atom_addr, + atom_index, + atom_mask, + atom_bcast_addr, + atom_reasm_size}; + ERL_NIF_TERM vals[] = {eaddr, eindex, emask, eBCastAddr, eReasmSize}; + size_t numKeys = NUM(keys); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, iar) ); + +} +#endif // __WIN32__ + + + + +/* ---------------------------------------------------------------------- + * nif_if_name2index + * + * Description: + * Perform a Interface Name to Interface Index translation. + * + * Arguments: + * Ifn - Interface name to be translated. + */ + +static +ERL_NIF_TERM nif_if_name2index(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#elif defined(HAVE_IF_NAMETOINDEX) + ERL_NIF_TERM eifn, result; + char ifn[IF_NAMESIZE+1]; + + NDBG( ("NET", "nif_if_name2index -> entry (%d)\r\n", argc) ); + + if (argc != 1) { + return enif_make_badarg(env); + } + eifn = argv[0]; + + NDBG( ("NET", + "nif_if_name2index -> " + "\r\n Ifn: %T" + "\r\n", argv[0]) ); + + if (0 >= GET_STR(env, eifn, ifn, sizeof(ifn))) + return esock_make_error(env, esock_atom_einval); + + result = enet_if_name2index(env, ifn); + + NDBG( ("NET", "nif_if_name2index -> done when result: %T\r\n", result) ); + + return result; +#else + return esock_make_error(env, esock_atom_enotsup); +#endif +} + + + +#if !defined(__WIN32__) && defined(HAVE_IF_NAMETOINDEX) +static +ERL_NIF_TERM enet_if_name2index(ErlNifEnv* env, + char* ifn) +{ + unsigned int idx; + + NDBG( ("NET", "enet_if_name2index -> entry with ifn: %s\r\n", ifn) ); + + idx = if_nametoindex(ifn); + + NDBG( ("NET", "enet_if_name2index -> idx: %d\r\n", idx) ); + + if (idx == 0) { + int save_errno = get_errno(); + NDBG( ("NET", "nif_name2index -> failed: %d\r\n", save_errno) ); + return esock_make_error_errno(env, save_errno); + } else { + return esock_make_ok2(env, MKI(env, idx)); + } + +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_if_index2name + * + * Description: + * Perform a Interface Index to Interface Name translation. + * + * Arguments: + * Idx - Interface index to be translated. + */ + +static +ERL_NIF_TERM nif_if_index2name(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#elif defined(HAVE_IF_INDEXTONAME) + ERL_NIF_TERM result; + unsigned int idx; + + NDBG( ("NET", "nif_if_index2name -> entry (%d)\r\n", argc) ); + + if ((argc != 1) || + !GET_UINT(env, argv[0], &idx)) { + return enif_make_badarg(env); + } + + NDBG( ("NET", "nif_index2name -> " + "\r\n Idx: %T" + "\r\n", argv[0]) ); + + result = enet_if_index2name(env, idx); + + NDBG( ("NET", "nif_if_index2name -> done when result: %T\r\n", result) ); + + return result; +#else + return esock_make_error(env, esock_atom_enotsup); +#endif +} + + + +#if !defined(__WIN32__) && defined(HAVE_IF_INDEXTONAME) +static +ERL_NIF_TERM enet_if_index2name(ErlNifEnv* env, + unsigned int idx) +{ + ERL_NIF_TERM result; + char* ifn = MALLOC(IF_NAMESIZE+1); + + if (ifn == NULL) + return enif_make_badarg(env); // PLACEHOLDER + + if (NULL != if_indextoname(idx, ifn)) { + result = esock_make_ok2(env, MKS(env, ifn)); + } else { + result = esock_make_error(env, atom_enxio); + } + + FREE(ifn); + + return result; +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_if_names + * + * Description: + * Get network interface names and indexes. + * + */ + +static +ERL_NIF_TERM nif_if_names(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) || (defined(__ANDROID__) && (__ANDROID_API__ < 24)) + return enif_raise_exception(env, MKA(env, "notsup")); +#elif defined(HAVE_IF_NAMEINDEX) && defined(HAVE_IF_FREENAMEINDEX) + ERL_NIF_TERM result; + + NDBG( ("NET", "nif_if_names -> entry (%d)\r\n", argc) ); + + if (argc != 0) { + return enif_make_badarg(env); + } + + result = enet_if_names(env); + + NDBG( ("NET", "nif_if_names -> done when result: %T\r\n", result) ); + + return result; +#else + return esock_make_error(env, esock_atom_enotsup); +#endif +} + + + +/* if_nameindex and if_freenameindex were added in Android 7.0 Nougat. With +the Android NDK Unified Headers, check that the build is targeting at least the corresponding API level 24. */ /* Can we replace the ANDROID tests with the HAVE_... ? */ #if !defined(__WIN32__) && !(defined(__ANDROID__) && (__ANDROID_API__ < 24)) @@ -1792,7 +4204,23 @@ unsigned int enet_if_names_length(struct if_nameindex* p) * A special case is when there is no flags, which is * represented by the atom undefined. */ -#if !defined(__WIN32__) + +static +ERL_NIF_TERM encode_sockaddr(ErlNifEnv* env, struct sockaddr* sa) +{ + ERL_NIF_TERM esa; + + if (sa != NULL) { + esock_encode_sockaddr(env, (ESockAddress*) sa, -1, &esa); + } else { + esa = esock_atom_undefined; + } + + return esa; +} + + + static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, const ERL_NIF_TERM eflags, @@ -1938,24 +4366,6 @@ BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, -static -ERL_NIF_TERM decode_bool(ErlNifEnv* env, - ERL_NIF_TERM ebool, - BOOLEAN_T* ibool) -{ - if (COMPARE(ebool, esock_atom_true) == 0) { - *ibool = TRUE; - return esock_atom_ok; - } else if (COMPARE(ebool, esock_atom_false) == 0) { - *ibool = FALSE; - return esock_atom_ok; - } else { - return esock_make_error(env, esock_atom_einval); - } -} - - - /* Encode the address info * The address info is a linked list och address info, which * will result in the result being a list of zero or more length. @@ -1994,7 +4404,7 @@ ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, -/* Calculate the length of the adress info linked list +/* Calculate the length of the address info linked list * The list is NULL-terminated, so the only way is to * iterate through the list until we find next = NULL. */ @@ -2097,7 +4507,6 @@ void make_address_info(ErlNifEnv* env, ESOCK_ASSERT( numKeys == NUM(vals) ); ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, ai) ); } -#endif // if !defined(__WIN32__) @@ -2107,8 +4516,8 @@ void make_address_info(ErlNifEnv* env, /* We should really have another API, so that we can return errno... */ /* *** change network namespace *** - * Retreive the current namespace and set the new. - * Return result and previous namespace if successfull. + * Retrieve the current namespace and set the new. + * Return result and previous namespace if successful. */ #if !defined(__WIN32__) static @@ -2199,6 +4608,22 @@ BOOLEAN_T restore_network_namespace(int ns, int* err) #endif // ifdef HAVE_SETNS +static +ERL_NIF_TERM decode_bool(ErlNifEnv* env, + ERL_NIF_TERM ebool, + BOOLEAN_T* ibool) +{ + if (COMPARE(ebool, esock_atom_true) == 0) { + *ibool = TRUE; + return esock_atom_ok; + } else if (COMPARE(ebool, esock_atom_false) == 0) { + *ibool = FALSE; + return esock_atom_ok; + } else { + return esock_make_error(env, esock_atom_einval); + } +} + /* ---------------------------------------------------------------------- @@ -2261,22 +4686,97 @@ ErlNifFunc net_funcs[] = {"nif_command", 1, nif_command, 0}, // Shall we let this be dirty? /* get/set hostname */ - {"nif_gethostname", 0, nif_gethostname, 0}, + {"nif_gethostname", 0, nif_gethostname, 0}, /* address and name translation in protocol-independent manner */ - {"nif_getnameinfo", 2, nif_getnameinfo, 0}, - {"nif_getaddrinfo", 3, nif_getaddrinfo, 0}, + {"nif_getnameinfo", 2, nif_getnameinfo, 0}, + {"nif_getaddrinfo", 3, nif_getaddrinfo, 0}, - {"nif_getifaddrs", 1, nif_getifaddrs, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"nif_getifaddrs", 1, nif_getifaddrs, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"nif_get_adapters_addresses", 1, nif_get_adapters_addresses, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"nif_get_if_entry", 1, nif_get_if_entry, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"nif_get_interface_info", 1, nif_get_interface_info, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"nif_get_ip_address_table", 1, nif_get_ip_address_table, ERL_NIF_DIRTY_JOB_IO_BOUND}, /* Network interface (name and/or index) functions */ - {"nif_if_name2index", 1, nif_if_name2index, 0}, - {"nif_if_index2name", 1, nif_if_index2name, 0}, - {"nif_if_names", 0, nif_if_names, 0} + {"nif_if_name2index", 1, nif_if_name2index, 0}, + {"nif_if_index2name", 1, nif_if_index2name, 0}, + {"nif_if_names", 0, nif_if_names, 0} }; -#if !defined(__WIN32__) +#if defined(__WIN32__) +/* + * The assumption is that the 'name' string is NULL terminated + */ +static +ERL_NIF_TERM encode_wchar(ErlNifEnv* env, WCHAR* name) +{ + ERL_NIF_TERM result; + int len = WideCharToMultiByte(CP_UTF8, 0, + name, -1, + NULL, 0, NULL, NULL); + + if (!len) { + result = esock_atom_undefined; + } else { + char* buf = (char*) MALLOC(len+1); + + if (0 == WideCharToMultiByte(CP_UTF8, 0, + name, -1, + buf, len, NULL, NULL)) { + DWORD error = GetLastError(); + + switch (error) { + case ERROR_INSUFFICIENT_BUFFER: + result = atom_insufficient_buffer; + break; + case ERROR_INVALID_FLAGS: + result = atom_invalid_flags; + break; + case ERROR_INVALID_PARAMETER: + result = atom_invalid_parameter; + break; + case ERROR_NO_UNICODE_TRANSLATION: + result = atom_no_uniconde_traslation; + break; + default: + result = MKI(env, error); + break; + } + } else { + result = MKS(env, buf); + } + + FREE(buf); + } + + return result; +} +#endif // __WIN32__ + + +#if defined(__WIN32__) +/* + * This builds a binary term from an array of uchar + */ +static +ERL_NIF_TERM encode_uchar(ErlNifEnv* env, + DWORD len, + UCHAR* buf) +{ + ERL_NIF_TERM ebuf; + unsigned char* p; + + p = enif_make_new_binary(env, len, &ebuf); + ESOCK_ASSERT( p != NULL ); + sys_memcpy(p, buf, len); + + return ebuf; +} +#endif // __WIN32__ + + static BOOLEAN_T get_debug(ErlNifEnv* env, ERL_NIF_TERM map) @@ -2289,7 +4789,6 @@ BOOLEAN_T get_debug(ErlNifEnv* env, return esock_get_bool_from_map(env, map, debug, NET_NIF_DEBUG_DEFAULT); } -#endif /* ======================================================================= @@ -2330,3 +4829,4 @@ LOCAL_ERROR_REASON_ATOMS } ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL) +#endif diff --git a/erts/emulator/nifs/common/prim_socket_int.h b/erts/emulator/nifs/common/prim_socket_int.h new file mode 100644 index 000000000000..2d48874e2787 --- /dev/null +++ b/erts/emulator/nifs/common/prim_socket_int.h @@ -0,0 +1,863 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : "Global" Types and stuff for socket. + * ---------------------------------------------------------------------- + * + */ + +#ifndef PRIM_SOCKET_INT_H__ +#define PRIM_SOCKET_INT_H__ + +#include +#include + +#include "socket_int.h" +#include "socket_dbg.h" + + +/* ********************************************************************* * + * SOCKET and HANDLE * + * ********************************************************************* * + */ + +#if defined(__WIN32__) + +#define INVALID_EVENT NULL +#define SOCKET_FORMAT_STR "%lld" + +#else + +#define INVALID_HANDLE (-1) +typedef int HANDLE; +#define INVALID_SOCKET (-1) +typedef int SOCKET; /* A subset of HANDLE */ +#define INVALID_EVENT INVALID_HANDLE +#define SOCKET_FORMAT_STR "%d" + +#endif + + +/* ********************************************************************* * + * Socket state defs and macros * + * ********************************************************************* * + */ + +#define ESOCK_STATE_BOUND 0x0001 /* readState */ +#define ESOCK_STATE_LISTENING 0x0002 /* readState */ +#define ESOCK_STATE_ACCEPTING 0x0004 /* readState */ +#define ESOCK_STATE_CONNECTING 0x0010 /* writeState */ +#define ESOCK_STATE_CONNECTED 0x0020 /* writeState */ + +/* This is set in either readState or writeState + * so it has to be read from both. + * Means that the socket has been used in select, + * so select_stop is required. */ +#define ESOCK_STATE_SELECTED 0x0100 /* readState or writeState */ + +/* These are set in both readState and writeState + * so they can be read from either. */ +#define ESOCK_STATE_CLOSING 0x0200 /* readState and writeState */ + +#define ESOCK_STATE_CLOSED 0x0400 /* readState and writeState */ +// +#define ESOCK_STATE_DTOR 0x8000 + +#define IS_BOUND(st) \ + (((st) & ESOCK_STATE_BOUND) != 0) + +#define IS_CLOSED(st) \ + (((st) & ESOCK_STATE_CLOSED) != 0) + +#define IS_CLOSING(st) \ + (((st) & ESOCK_STATE_CLOSING) != 0) + +#define IS_ACCEPTING(st) \ + (((st) & ESOCK_STATE_ACCEPTING) != 0) + +#define IS_OPEN(st) \ + (((st) & (ESOCK_STATE_CLOSED | ESOCK_STATE_CLOSING)) == 0) + +#define IS_SELECTED(d) \ + ((((d)->readState | (d)->writeState) & ESOCK_STATE_SELECTED) != 0) + + +#define ESOCK_DESC_PATTERN_CREATED 0x03030303 +#define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0 + + +/* ========================================================================== + * The ESOCK_IS_ERROR macro below is used for portability reasons. + * While POSIX specifies that errors from socket-related system calls + * should be indicated with a -1 return value, some users have experienced + * non-Windows OS kernels that return negative values other than -1. + * While one can argue that such kernels are technically broken, comparing + * against values less than 0 covers their out-of-spec return values without + * imposing incorrect semantics on systems that manage to correctly return -1 + * for errors, thus increasing Erlang's portability. + */ +#ifdef __WIN32__ +#define ESOCK_IS_ERROR(val) ((val) == INVALID_SOCKET) +#else +#define ESOCK_IS_ERROR(val) ((val) < 0) +#endif + + +/* ********************************************************************* * + * Misc * + * ********************************************************************* * + */ + +#define ESOCK_GET_RESOURCE(ENV, REF, RES) \ + enif_get_resource((ENV), (REF), esocks, (RES)) + +#define ESOCK_MON2TERM(E, M) \ + esock_make_monitor_term((E), (M)) + + +/* ********************************************************************* * + * Counter type and related "things" * + * ********************************************************************* * + */ + +#if ESOCK_COUNTER_SIZE == 16 + +typedef Uint16 ESockCounter; +#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFF) +#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) +#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((CNT))) +#define ESOCK_COUNTER_FORMAT_STR "%u" + +#elif ESOCK_COUNTER_SIZE == 24 + +typedef Uint32 ESockCounter; +#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFF) +#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) +#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) +#define ESOCK_COUNTER_FORMAT_STR "%lu" + +#elif ESOCK_COUNTER_SIZE == 32 + +typedef Uint32 ESockCounter; +#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) +#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) +#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) +#define ESOCK_COUNTER_FORMAT_STR "%lu" + +#elif ESOCK_COUNTER_SIZE == 48 + +typedef Uint64 ESockCounter; +#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFFFFFFFF) +#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) +#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) +#define ESOCK_COUNTER_FORMAT_STR "%llu" + +#elif ESOCK_COUNTER_SIZE == 64 + +typedef Uint64 ESockCounter; +#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) +#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) +#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) +#define ESOCK_COUNTER_FORMAT_STR "%llu" + +#else + +#error "Invalid counter size" + +#endif + +#define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \ + do { \ + if (esock_cnt_inc((CNT), (INC))) { \ + esock_send_wrap_msg((__E__), (__D__), (SF), (ACNT)); \ + } \ + } while (0) + + + +/* ********************************************************************* * + * (Socket) Debug macros * + * ********************************************************************* * + */ + +#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto ) +#define SSDBG2( __DBG__ , proto ) ESOCK_DBG_PRINTF( (__DBG__) , proto ) + + +/* ********************************************************************* * + * Sendfile stuff * + * ********************************************************************* * + */ + +#if defined(HAVE_SENDFILE) + +typedef struct { + ESockCounter cnt; // Calls to OS sendfile() + ESockCounter byteCnt; // Bytes sent with sendfile + ESockCounter fails; // Failed sendfile operations + ESockCounter max; // Largest sendfile operation + ESockCounter maxCnt; // Counter for ="= + ESockCounter pkg; // Sendfile chunks + ESockCounter pkgMax; // Largest sendfile chunk + ESockCounter tries; // Started sendfile operations + ESockCounter waits; // Select's during sendfile +} ESockSendfileCounters; + +#endif + + +/* ********************************************************************* * + * Monitor wrapper type * + * ********************************************************************* * + */ + +typedef struct { + ErlNifMonitor mon; + BOOLEAN_T isActive; +} ESockMonitor; + + + + +/* ********************************************************************* * + * The 'request' data structure * + * Each I/O request (write, read, accept, connect, ...) that cannot be * + * completed directly, is scheduled for later or asynchronous. * + * These requests are "pushed" into a request "queue". * + * In the case of the classic (unix) implementation, this is an actual * + * queue which also takes care of the order of the requests. * + * In case of the I/O Completion Port (windows), it is only used as an * + * database (we "push" into the list but we never "pop" from the list, * + * we search and delete). * + * ********************************************************************* * + */ + +typedef struct { + ErlNifPid pid; // PID of the requesting process + ESockMonitor mon; // Monitor to the requesting process + + /* We need an environment for the copy of the ref we store here. + * We will also use this environment for any messages we send + * (with the ref in it). Such as the select message (used in the + * select call) or the abort message. + */ + ErlNifEnv* env; + ERL_NIF_TERM ref; // The (unique) reference (ID) of the request + + /* The socket for which this request is made. + * A pointer to an *optional* data structure. This is intended for + * the 'overlapped' structure used by I/O Completion Port. + * A request scheduled by the I/O Completion Port can be 'cancelled' + * using the socket and the 'overlapped' data (provided when the + * operation was scheduled). + */ + SOCKET sock; + void* dataP; + +} ESockRequestor; + +typedef struct esock_request_queue_element { + struct esock_request_queue_element* nextP; + ESockRequestor data; +} ESockRequestQueueElement; + +typedef struct { + ESockRequestQueueElement* first; + ESockRequestQueueElement* last; +} ESockRequestQueue; + + + +/* ********************************************************************* * + * Holding the socket level 'otp' option 'meta' term * + * ********************************************************************* * + */ + +typedef struct{ + ErlNifEnv* env; + ERL_NIF_TERM ref; +} ESockMeta; + + + +/* ********************************************************************* * + * Control Message spec type * + * ********************************************************************* * + */ + +typedef struct { + int type; // Message type + + // Function to encode into erlang term + BOOLEAN_T (* encode)(ErlNifEnv* env, + unsigned char* data, + size_t dataLen, + ERL_NIF_TERM* eResult); + + // Function to decode from erlang term + BOOLEAN_T (* decode)(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP); + + ERL_NIF_TERM *nameP; // Pointer to option name atom +} ESockCmsgSpec; + + +/*---------------------------------------------------------------------------- + * Interface types and constants. + * + * The set of elements should be the same as for the type + * msg_flag() in socket.erl. + */ +typedef struct { + int flag; + ERL_NIF_TERM* name; +} ESockFlag; + +extern const ESockFlag esock_msg_flags[]; +extern const int esock_msg_flags_length; +extern const ESockFlag esock_ioctl_flags[]; +extern const int esock_ioctl_flags_length; + + +/* ********************************************************************* * + * The socket nif global info * + * ********************************************************************* * + */ + +typedef struct { + /* These are for debugging, testing and the like */ + // ERL_NIF_TERM version; + // ERL_NIF_TERM buildDate; + + /* XXX Should be locked but too awkward and small gain */ + BOOLEAN_T dbg; + BOOLEAN_T useReg; + BOOLEAN_T eei; + + /* Registry stuff */ + ErlNifPid regPid; /* Constant - not locked */ + + /* IOV_MAX. Constant - not locked */ + int iov_max; + + /* XXX + * Should be locked but too awkward for no gain since it is not used yet + */ + BOOLEAN_T iow; // Where do we send this? Subscription? + + ErlNifMutex* protocolsMtx; + + ErlNifMutex* cntMtx; /* Locks the below */ + /* Its extreme overkill to have these counters be 64-bit, + * but since the other counters are, it's much simpler to + * let these be 64-bit also. + */ + ESockCounter numSockets; + ESockCounter numTypeStreams; + ESockCounter numTypeDGrams; + ESockCounter numTypeSeqPkgs; + ESockCounter numDomainInet; + ESockCounter numDomainInet6; + ESockCounter numDomainLocal; + ESockCounter numProtoIP; + ESockCounter numProtoTCP; + ESockCounter numProtoUDP; + ESockCounter numProtoSCTP; + // + BOOLEAN_T sockDbg; +} ESockData; + + + +/* ********************************************************************* * + * The socket descriptor * + * ********************************************************************* * + */ + +typedef struct { + /* + * +++ This is a way to, possibly, detect memory overrides "and stuff" +++ + * + * We have two patterns. One is set when the descriptor is created + * (allocated) and one is set when the descriptor is dtor'ed. + */ + Uint32 pattern; + + /* +++ Stuff "about" the socket +++ */ + + /* "Constant" - set when socket is created and never changed */ + int domain; + int type; + int protocol; + + /* The state is partly for debugging, decisions are made often + * based on other variables. The state is divided in + * a readState half and a writeState half that can be + * OR:ed together to create the complete state. + * The halves are locked by their corresponding lock. + */ + + /* +++ Write stuff +++ */ + ErlNifMutex* writeMtx; + /**/ + unsigned int writeState; // For debugging +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* writer. + * The queue is intended for *waiting* writers. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentWriter; + ESockRequestor* currentWriterP; // NULL or ¤tWriter +#endif + ESockRequestQueue writersQ; + ESockCounter writePkgCnt; + ESockCounter writePkgMax; + ESockCounter writePkgMaxCnt; + ESockCounter writeByteCnt; + ESockCounter writeTries; + ESockCounter writeWaits; + ESockCounter writeFails; +#ifdef HAVE_SENDFILE + HANDLE sendfileHandle; + ESockSendfileCounters* sendfileCountersP; +#endif + + /* +++ Connector +++ */ + ESockRequestor connector; + ESockRequestor* connectorP; // NULL or &connector + /* +++ Config stuff +++ */ + size_t wCtrlSz; // Write control buffer size + ESockMeta meta; // Level 'otp' option 'meta' term + + /* +++ Read stuff +++ */ + ErlNifMutex* readMtx; + /**/ + unsigned int readState; // For debugging +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* reader. + * The queue is intended for *waiting* readers. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentReader; + ESockRequestor* currentReaderP; // NULL or ¤tReader +#endif + ESockRequestQueue readersQ; + ErlNifBinary rbuffer; // DO WE NEED THIS + Uint32 readCapacity; // DO WE NEED THIS + ESockCounter readPkgCnt; + ESockCounter readPkgMax; + ESockCounter readPkgMaxCnt; + ESockCounter readByteCnt; + ESockCounter readTries; + ESockCounter readWaits; + ESockCounter readFails; + + /* +++ Accept stuff +++ */ +#ifndef __WIN32__ + /* + * On *none* Windows: + * This is intended for the *current* acceptor. + * The queue is intended for *waiting* acceptors. + * + * *On* Windows: + * We let the I/O Completion Ports handle the queue'ing + * so we do not need to keep track which request is active + * and which are waiting. + * We only use the *queue* as a database. + */ + ESockRequestor currentAcceptor; + ESockRequestor* currentAcceptorP; // NULL or ¤tAcceptor +#endif + ESockRequestQueue acceptorsQ; + ESockCounter accSuccess; + ESockCounter accTries; + ESockCounter accWaits; + ESockCounter accFails; + /* +++ Config stuff +++ */ + size_t rBufSz; // Read buffer size (when data length = 0) + /* rNum and rNumCnt are used (together with rBufSz) when calling the recv + * function with the Length argument set to 0 (zero). + * If rNum is 0 (zero), then rNumCnt is not used and only *one* read will + * be done. Also, when get'ing the value of the option (rcvbuf) with + * getopt, the value will be reported as an integer. If the rNum has a + * value greater then 0 (zero), then it will instead be reported as + * {N, BufSz}. + * On Windows, rNum and rNumCnt is *not* used! + */ +#ifndef __WIN32__ + unsigned int rNum; // recv: Number of reads using rBufSz + unsigned int rNumCnt; // recv: Current number of reads (so far) +#endif + size_t rCtrlSz; // Read control buffer size + + /* Locked by readMtx and writeMtx combined for writing, + * which means only one of them is required for reading + */ + /* +++ Close stuff +++ */ + ErlNifPid closerPid; + ESockMonitor closerMon; + ErlNifEnv* closeEnv; + ERL_NIF_TERM closeRef; + /* +++ Inform On (counter) Wrap +++ */ + BOOLEAN_T iow; + /* +++ Controller (owner) process +++ */ + ErlNifPid ctrlPid; + ESockMonitor ctrlMon; + /* +++ The actual socket +++ */ + SOCKET sock; + SOCKET origFD; // A 'socket' created from this FD + BOOLEAN_T closeOnClose; // Have we dup'ed or not + /* +++ The dbg flag for SSDBG +++ */ + BOOLEAN_T dbg; + BOOLEAN_T useReg; + + /* Lock order: readMtx, writeMtx, cntMtx + */ + +#if defined(ESOCK_DESCRIPTOR_FILLER) + char filler[1024]; +#endif + +} ESockDescriptor; + + + +/* ======================================================================== * + * What to do about this? * + * ======================================================================== * + */ + +extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ + + +/* ======================================================================== * + * Functions * + * ======================================================================== * + */ + +extern ESockDescriptor* esock_alloc_descriptor(SOCKET sock); +extern void esock_dealloc_descriptor(ErlNifEnv* env, + ESockDescriptor* descP); + +extern BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def); +extern BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def); +extern BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto); + +extern BOOLEAN_T esock_getopt_int(SOCKET sock, + int level, + int opt, + int* valP); + + +/* ** Socket Registry functions *** */ +extern void esock_send_reg_add_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +extern void esock_send_reg_del_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); + + +/* *** Message sending functions *** */ +extern void esock_send_simple_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +extern void esock_send_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestor* reqP, + ERL_NIF_TERM reason); +extern void esock_send_close_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid); +extern void esock_send_wrap_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); + + +/* ** Monitor functions *** */ +extern int esock_monitor(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pid, + ESockMonitor* mon); +extern int esock_demonitor(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockMonitor* monP); +extern void esock_monitor_init(ESockMonitor* mon); +extern ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, + const ESockMonitor* monP); +extern BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, + const ErlNifMonitor* mon); + + +/* *** Counter functions *** */ +extern BOOLEAN_T esock_cnt_inc(ESockCounter* cnt, ESockCounter inc); +extern void esock_cnt_dec(ESockCounter* cnt, ESockCounter dec); +extern void esock_inc_socket(int domain, int type, int protocol); +extern void esock_dec_socket(int domain, int type, int protocol); + + +/* *** Select functions *** */ +extern int esock_select_read(ErlNifEnv* env, + ErlNifEvent event, + void* obj, + const ErlNifPid* pidP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); +extern int esock_select_write(ErlNifEnv* env, + ErlNifEvent event, + void* obj, + const ErlNifPid* pidP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); +extern int esock_select_stop(ErlNifEnv* env, + ErlNifEvent event, + void* obj); +extern int esock_select_cancel(ErlNifEnv* env, + ErlNifEvent event, + enum ErlNifSelectFlags mode, + void* obj); +extern ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + int smode, + int rmode); + + +/* *** Request queue functions *** */ +extern void esock_free_request_queue(ESockRequestQueue* q); +extern BOOLEAN_T esock_requestor_pop(ESockRequestQueue* q, + ESockRequestor* reqP); + +extern void esock_requestor_init(ESockRequestor* reqP); +extern void esock_requestor_release(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockRequestor* reqP); + + +/* *** esock_activate_next_acceptor *** + * *** esock_activate_next_writer *** + * *** esock_activate_next_reader *** + * + * All the activate-next functions for acceptor, writer and reader + * have exactly the same API, so we apply some macro magic to simplify. + * They simply operates on dufferent data structures. + * + */ + +#define ACTIVATE_NEXT_FUNCS_DEFS \ + ACTIVATE_NEXT_FUNC_DEF(acceptor) \ + ACTIVATE_NEXT_FUNC_DEF(writer) \ + ACTIVATE_NEXT_FUNC_DEF(reader) + +#define ACTIVATE_NEXT_FUNC_DEF(F) \ + extern BOOLEAN_T esock_activate_next_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM sockRef); +ACTIVATE_NEXT_FUNCS_DEFS +#undef ACTIVATE_NEXT_FUNC_DEF + +/* esock_acceptor_search4pid | esock_writer_search4pid | esock_reader_search4pid + * esock_acceptor_push | esock_writer_push | esock_reader_push + * esock_acceptor_pop | esock_writer_pop | esock_reader_pop + * esock_acceptor_unqueue | esock_writer_unqueue | esock_reader_unqueue + * + * All the queue operator functions (search4pid, push, pop + * and unqueue) for acceptor, writer and reader has exactly + * the same API, so we apply some macro magic to simplify. + */ + +#define ESOCK_OPERATOR_FUNCS_DEFS \ + ESOCK_OPERATOR_FUNCS_DEF(acceptor) \ + ESOCK_OPERATOR_FUNCS_DEF(writer) \ + ESOCK_OPERATOR_FUNCS_DEF(reader) + +#define ESOCK_OPERATOR_FUNCS_DEF(O) \ + extern BOOLEAN_T esock_##O##_search4pid(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid* pid); \ + extern void esock_##O##_push(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid pid, \ + ERL_NIF_TERM ref, \ + void* dataP); \ + extern BOOLEAN_T esock_##O##_pop(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ESockRequestor* reqP); \ + extern BOOLEAN_T esock_##O##_unqueue(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP); +ESOCK_OPERATOR_FUNCS_DEFS +#undef ESOCK_OPERATOR_FUNCS_DEF + + +/* *** Environment wrapper functions *** + * These hould really be inline, but for now... + */ +extern void esock_clear_env(const char* slogan, ErlNifEnv* env); +extern void esock_free_env(const char* slogan, ErlNifEnv* env); +extern ErlNifEnv* esock_alloc_env(const char* slogan); + + +/* *** Control Message utility functions *** + */ +#ifndef __WIN32__ +extern void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, + size_t size, + size_t* usedP); +#if defined(IP_TTL) || \ + defined(IPV6_HOPLIMIT) || \ + defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS) +extern BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP); +#endif +extern BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP); +extern ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num); +extern ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType); + +extern BOOLEAN_T esock_encode_cmsg(ErlNifEnv* env, + int level, + int type, + unsigned char* dataP, + size_t dataLen, + ERL_NIF_TERM* eType, + ERL_NIF_TERM* eData); +extern void esock_encode_msg_flags(ErlNifEnv* env, + ESockDescriptor* descP, + int msgFlags, + ERL_NIF_TERM* flags); +#endif + + +extern void esock_stop_handle_current(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestor* reqP); +extern void esock_inform_waiting_procs(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestQueue* q, + ERL_NIF_TERM reason); + + +/* *** Control Message 'stuff' *** + */ +extern void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, // Remaining space + size_t size, // Size of data + size_t* usedP); +extern ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num); +extern ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType); + +/* *** Sendfile 'stuff' *** + */ +#ifdef HAVE_SENDFILE + +extern ESockSendfileCounters initESockSendfileCounters; + +#endif + +/* *** message functions **** + */ +extern void esock_send_wrap_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); +extern BOOLEAN_T esock_send_msg(ErlNifEnv* env, + ErlNifPid* pid, + ERL_NIF_TERM msg, + ErlNifEnv* msgEnv); +extern ERL_NIF_TERM esock_mk_socket_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM tag, + ERL_NIF_TERM info); +extern ERL_NIF_TERM esock_mk_socket(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +#ifdef HAVE_SENDFILE +extern void esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, + ESockDescriptor* descP); +#endif + + +/* *** 'close' functions *** + */ +extern int esock_close_socket(ErlNifEnv* env, + ESockDescriptor* descP, + BOOLEAN_T unlock); + + +/* *** 'ioctl' functions *** + */ +extern ERL_NIF_TERM esock_encode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + int ivalue); +extern ERL_NIF_TERM esock_encode_ioctl_bvalue(ErlNifEnv* env, + ESockDescriptor* descP, + int bvalue); + +#endif // PRIM_SOCKET_INT_H__ diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index 438387b9c460..b80f7bea5f6f 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2022. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. 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. @@ -24,25 +24,47 @@ * The first function is called 'nif_', e.g. nif_open. * This does the initial validation and argument processing and then * calls the function that does the actual work. This is called - * 'esock_'. + * '_', e.g. essio_open (actually + * essio_open_with_fd or essio_open_plain). * ---------------------------------------------------------------------- * * - * This is just a code snippet in case there is need of extra debugging + * This is just a code snippet example in case there is need of + * extra debugging: * * esock_dbg_printf("DEMONP", "[%d] %s: %T\r\n", * descP->sock, slogan, * esock_make_monitor_term(env, &mon)); - * + * ESOCK_PRINTF("foobar: %d\r\n", foo); + * ESOCK_EPRINTF("foobar: %d\r\n", foo); */ #define STATIC_ERLANG_NIF 1 - #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif +#ifndef ESOCK_ENABLE +# include + +static +ErlNifFunc esock_funcs[] = {}; + +static +int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + (void)env; + (void)priv_data; + (void)load_info; + + return 1; +} + +ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL) + +#else + /* If we HAVE_SCTP_H and Solaris, we need to define the following in * order to get SCTP working: */ @@ -104,6 +126,10 @@ * * * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +#define ESOCK_CMSG_SPACE(l) WSA_CMSG_SPACE((l)) +#define ESOCK_CMSG_LEN(l) WSA_CMSG_LEN((l)) +#define ESOCK_CMSG_DATA(p) WSA_CMSG_DATA((p)) + #define STRNCASECMP strncasecmp #define INCL_WINSOCK_API_TYPEDEFS 1 @@ -115,17 +141,19 @@ #include /* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h - * to define the right structures. It needs to be set to WINXP (or LONGHORN) - * for IPV6 to work and it's set lower by default, so we need to change it. + * to define the right structures. + * It needs to be set higher for IPV6 to work and it's set lower by default, + * so we need to change it. */ #ifdef HAVE_SDKDDKVER_H # include # ifdef NTDDI_VERSION # undef NTDDI_VERSION # endif -# define NTDDI_VERSION NTDDI_WINXP +# define NTDDI_VERSION NTDDI_WIN10_RS2 #endif #include +#include #undef WANT_NONBLOCKING #include "sys.h" @@ -146,6 +174,10 @@ * * * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +#define ESOCK_CMSG_SPACE(l) CMSG_SPACE((l)) +#define ESOCK_CMSG_LEN(l) CMSG_LEN((l)) +#define ESOCK_CMSG_DATA(p) CMSG_DATA((p)) + #include #ifdef NETDB_H_NEEDS_IN_H @@ -343,12 +375,12 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #endif /* #if defined(HAVE_SCTP_H) */ - #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING #endif #include "sys.h" + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * * * End of non-__WIN32__ section a.k.a UNIX section * @@ -364,6 +396,10 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #include "socket_tarray.h" #include "socket_int.h" #include "socket_util.h" +#include "prim_socket_int.h" +#include "socket_io.h" +#include "socket_asyncio.h" +#include "socket_syncio.h" #include "prim_file_nif_dyncall.h" #if defined(ERTS_INLINE) @@ -391,41 +427,6 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #define ESOCK_NIF_IOW_DEFAULT FALSE -#ifdef __WIN32__ - -//#define INVALID_HANDLE from Windows header file -//typedef void *HANDLE from Windows header file -//#define INVALID_SOCKET from Windows header file -//typedef void *SOCKET from Windows header file -#define INVALID_EVENT NULL - -#else - -#define INVALID_HANDLE (-1) -typedef int HANDLE; -#define INVALID_SOCKET (-1) -typedef int SOCKET; /* A subset of HANDLE */ -#define INVALID_EVENT INVALID_HANDLE - -#endif - - -/* ============================================================================== - * The ESOCK_IS_ERROR macro below is used for portability reasons. - * While POSIX specifies that errors from socket-related system calls - * should be indicated with a -1 return value, some users have experienced - * non-Windows OS kernels that return negative values other than -1. - * While one can argue that such kernels are technically broken, comparing - * against values less than 0 covers their out-of-spec return values without - * imposing incorrect semantics on systems that manage to correctly return -1 - * for errors, thus increasing Erlang's portability. - */ -#ifdef __WIN32__ -#define ESOCK_IS_ERROR(val) ((val) == INVALID_SOCKET) -#else -#define ESOCK_IS_ERROR(val) ((val) < 0) -#endif - /* *** Misc macros and defines *** */ @@ -453,70 +454,15 @@ typedef int SOCKET; /* A subset of HANDLE */ -/* *** Socket state defs *** */ - -#define ESOCK_STATE_BOUND 0x0001 /* readState */ -#define ESOCK_STATE_LISTENING 0x0002 /* readState */ -#define ESOCK_STATE_ACCEPTING 0x0004 /* readState */ -#define ESOCK_STATE_CONNECTING 0x0010 /* writeState */ -#define ESOCK_STATE_CONNECTED 0x0020 /* writeState */ - -/* This is set in either readState or writeState - * so it has to be read from both. - * Means that the socket has been used in select, - * so select_stop is required. */ -#define ESOCK_STATE_SELECTED 0x0100 /* readState or writeState */ - -/* These are set in both readState and writeState - * so they can be read from either. */ -#define ESOCK_STATE_CLOSING 0x0200 /* readState and writeState */ - -#define ESOCK_STATE_CLOSED 0x0400 /* readState and writeState */ -// -#define ESOCK_STATE_DTOR 0x8000 - -#define IS_CLOSED(st) \ - (((st) & ESOCK_STATE_CLOSED) != 0) - -#define IS_CLOSING(st) \ - (((st) & ESOCK_STATE_CLOSING) != 0) - -#define IS_OPEN(st) \ - (((st) & (ESOCK_STATE_CLOSED | ESOCK_STATE_CLOSING)) == 0) - -#define IS_SELECTED(d) \ - ((((d)->readState | (d)->writeState) & ESOCK_STATE_SELECTED) != 0) - - -#define ESOCK_GET_RESOURCE(ENV, REF, RES) \ - enif_get_resource((ENV), (REF), esocks, (RES)) - #define ESOCK_RECV_BUFFER_COUNT_DEFAULT 0 -#define ESOCK_RECV_BUFFER_SIZE_DEFAULT 8192 +#if defined(__WIN32__) +#define ESOCK_RECV_BUFFER_SIZE_DEFAULT (32*1024) +#else +#define ESOCK_RECV_BUFFER_SIZE_DEFAULT (8*1024) +#endif #define ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024 #define ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024 -#define ESOCK_DESC_PATTERN_CREATED 0x03030303 -#define ESOCK_DESC_PATTERN_DTOR 0xC0C0C0C0 - -/* -typedef union { - struct { - // 0 = not open, 1 = open - unsigned int open:1; - // 0 = not conn, 1 = connecting, 2 = connected - unsigned int connect:2; - // unsigned int connecting:1; - // unsigned int connected:1; - // 0 = not listen, 1 = listening, 2 = accepting - unsigned int listen:2; - // unsigned int listening:1; - // unsigned int accepting:1; - / * Room for more... * / - } flags; - unsigned int field; // Make it easy to reset all flags... -} SocketState; -*/ /*---------------------------------------------------------------------------- * Interface constants. @@ -525,11 +471,7 @@ typedef union { * msg_flag() in socket.erl. */ -static const struct msg_flag { - int flag; - ERL_NIF_TERM *name; -} msg_flags[] = { - +const ESockFlag esock_msg_flags[] = { { #ifdef MSG_CMSG_CLOEXEC MSG_CMSG_CLOEXEC, @@ -618,13 +560,9 @@ static const struct msg_flag { #endif &esock_atom_trunc} }; +const int esock_msg_flags_length = NUM(esock_msg_flags); - -static const struct ioctl_flag { - int flag; - ERL_NIF_TERM *name; -} ioctl_flags[] = { - +const ESockFlag esock_ioctl_flags[] = { { #ifdef IFF_UP IFF_UP, @@ -894,6 +832,7 @@ static const struct ioctl_flag { #endif &esock_atom_nogroup} }; +const int esock_ioctl_flags_length = NUM(esock_ioctl_flags); @@ -932,16 +871,6 @@ static const struct ioctl_flag { /* Global socket debug */ #define SGDBG( proto ) ESOCK_DBG_PRINTF( data.dbg , proto ) -/* Socket specific debug */ -#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto ) -#define SSDBG2( __DBG__ , proto ) ESOCK_DBG_PRINTF( (__DBG__) , proto ) - -#define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \ - do { \ - if (cnt_inc((CNT), (INC))) { \ - esock_send_wrap_msg((__E__), (__D__), (SF), (ACNT)); \ - } \ - } while (0) /* =================================================================== * @@ -959,29 +888,29 @@ static const struct ioctl_flag { /* *** Windows macros *** */ -#define sock_accept(s, addr, len) \ - make_noninheritable_handle(accept((s), (addr), (len))) -#define sock_bind(s, addr, len) bind((s), (addr), (len)) +/* #define sock_accept(s, addr, len) \ + make_noninheritable_handle(accept((s), (addr), (len))) */ +// #define sock_bind(s, addr, len) bind((s), (addr), (len)) #define sock_close(s) closesocket((s)) -#define sock_close_event(e) WSACloseEvent(e) -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_create_event(s) WSACreateEvent() +// #define sock_close_event(e) WSACloseEvent(e) +// #define sock_connect(s, addr, len) connect((s), (addr), (len)) +// #define sock_create_event(s) WSACreateEvent() #define sock_errno() WSAGetLastError() #define sock_getopt(s,l,o,v,ln) getsockopt((s),(l),(o),(v),(ln)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) +// #define sock_htons(x) htons((x)) +// #define sock_htonl(x) htonl((x)) #define sock_listen(s, b) listen((s), (b)) #define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_open(domain, type, proto) \ - make_noninheritable_handle(socket((domain), (type), (proto))) +// #define sock_ntohs(x) ntohs((x)) +/* #define sock_open(domain, type, proto) \ + make_noninheritable_handle(socket((domain), (type), (proto))) */ #define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +// #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) +/* #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) */ +/* #define sock_sendto(s,buf,blen,flag,addr,alen) \ + sendto((s),(buf),(blen),(flag),(addr),(alen)) */ #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln)) #define sock_shutdown(s, how) shutdown((s), (how)) @@ -1005,34 +934,34 @@ static unsigned long one_value = 1; * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ -#ifdef HAS_ACCEPT4 +// #ifdef HAS_ACCEPT4 // We have to figure out what the flags are... -#define sock_accept(s, addr, len) accept4((s), (addr), (len), (SOCK_CLOEXEC)) -#else -#define sock_accept(s, addr, len) accept((s), (addr), (len)) -#endif -#define sock_bind(s, addr, len) bind((s), (addr), (len)) +// #define sock_accept(s, addr, len) accept4((s), (addr), (len), (SOCK_CLOEXEC)) +// #else +// #define sock_accept(s, addr, len) accept((s), (addr), (len)) +// #endif +// #define sock_bind(s, addr, len) bind((s), (addr), (len)) #define sock_close(s) close((s)) -#define sock_close_event(e) /* do nothing */ -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_create_event(s) (s) /* return file descriptor */ +// #define sock_close_event(e) /* do nothing */ +// #define sock_connect(s, addr, len) connect((s), (addr), (len)) +// #define sock_create_event(s) (s) /* return file descriptor */ #define sock_errno() errno #define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) +// #define sock_htons(x) htons((x)) +// #define sock_htonl(x) htonl((x)) #define sock_listen(s, b) listen((s), (b)) #define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_open(domain, type, proto) socket((domain), (type), (proto)) +// #define sock_ntohs(x) ntohs((x)) +// #define sock_open(domain, type, proto) socket((domain), (type), (proto)) #define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) -#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ - recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) -#define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag)) -#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) +// #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +/* #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ */ +/* recvfrom((s),(buf),(blen),(flag),(addr),(alen)) */ +// #define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) +// #define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag)) +// #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) +/* #define sock_sendto(s,buf,blen,flag,addr,alen) \ */ +/* sendto((s),(buf),(blen),(flag),(addr),(alen)) */ #define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln)) #define sock_shutdown(s, how) shutdown((s), (how)) @@ -1045,284 +974,20 @@ static unsigned long one_value = 1; #endif /* #ifdef __WIN32__ #else */ -/* We can use the IPv4 def for this since the beginning - * is the same for INET and INET6 */ -#define which_address_port(sap) \ - ((((sap)->in4.sin_family == AF_INET) || \ - ((sap)->in4.sin_family == AF_INET6)) ? \ - ((sap)->in4.sin_port) : -1) - - -typedef struct { - ErlNifMonitor mon; - BOOLEAN_T isActive; -} ESockMonitor; - -typedef struct { - ErlNifPid pid; // PID of the requesting process - ESockMonitor mon; // Monitor to the requesting process - - /* We need an environment for the copy of the ref we store here. - * We will also use this environment for any messages we send - * (with the ref in it). Such as the select message (used in the - * select call) or the abort message. - */ - ErlNifEnv* env; - ERL_NIF_TERM ref; // The (unique) reference (ID) of the request -} ESockRequestor; - -typedef struct{ - // Holding the socket level 'otp' option 'meta' term - ErlNifEnv* env; - ERL_NIF_TERM ref; -} ESockMeta; - -typedef struct esock_request_queue_element { - struct esock_request_queue_element* nextP; - ESockRequestor data; -} ESockRequestQueueElement; - -typedef struct { - ESockRequestQueueElement* first; - ESockRequestQueueElement* last; -} ESockRequestQueue; - - -/*** The point of this is primarily testing ***/ -/* -#if defined(ESOCK_COUNTER_SIZE) -#undef ESOCK_COUNTER_SIZE -// #define ESOCK_COUNTER_SIZE 16 -// #define ESOCK_COUNTER_SIZE 24 -// #define ESOCK_COUNTER_SIZE 32 -// #define ESOCK_COUNTER_SIZE 48 -// #define ESOCK_COUNTER_SIZE 64 - -#endif -*/ - -#if ESOCK_COUNTER_SIZE == 16 - -typedef Uint16 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFF) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%u" - -#elif ESOCK_COUNTER_SIZE == 24 - -typedef Uint32 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFF) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%lu" - -#elif ESOCK_COUNTER_SIZE == 32 - -typedef Uint32 ESockCounter; -#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) -#define MKCNT(ENV, CNT) MKUI((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%lu" - -#elif ESOCK_COUNTER_SIZE == 48 - -typedef Uint64 ESockCounter; -#define ESOCK_COUNTER_MAX ((ESockCounter) 0xFFFFFFFFFFFF) -#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%llu" - -#elif ESOCK_COUNTER_SIZE == 64 - -typedef Uint64 ESockCounter; -#define ESOCK_COUNTER_MAX (~((ESockCounter) 0)) -#define MKCNT(ENV, CNT) MKUI64((ENV), (CNT)) -#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKCNT((ENV), (CNT))) -#define ESOCK_COUNTER_FORMAT_STR "%llu" - -#else - -#error "Invalid counter size" - -#endif - -// static const ESockCounter esock_counter_max = ESOCK_COUNTER_MAX; - #ifdef HAVE_SENDFILE -typedef struct { - ESockCounter cnt; // Calls to OS sendfile() - ESockCounter byteCnt; // Bytes sent with sendfile - ESockCounter fails; // Failed sendfile operations - ESockCounter max; // Largest sendfile operation - ESockCounter maxCnt; // Counter for ="= - ESockCounter pkg; // Sendfile chunks - ESockCounter pkgMax; // Largest sendfile chunk - ESockCounter tries; // Started sendfile operations - ESockCounter waits; // Select's during sendfile -} ESockSendfileCounters; -static ESockSendfileCounters initESockSendfileCounters = +ESockSendfileCounters initESockSendfileCounters = {0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif -typedef struct { - /* - * +++ This is a way to, possibly, detect memory overrides "and stuff" +++ - * - * We have two patterns. One is set when the descriptor is created - * (allocated) and one is set when the descriptor is dtor'ed. - */ - Uint32 pattern; - - /* +++ Stuff "about" the socket +++ */ - - /* "Constant" - set when socket is created and never changed */ - int domain; - int type; - int protocol; - - /* The state is partly for debugging, decisions are made often - * based on other variables. The state is divided in - * a readState half and a writeState half that can be - * OR:ed together to create the complete state. - * The halves are locked by their corresponding lock. - */ - - /* +++ Write stuff +++ */ - ErlNifMutex* writeMtx; - /**/ - unsigned int writeState; // For debugging - ESockRequestor currentWriter; - ESockRequestor* currentWriterP; // NULL or ¤tWriter - ESockRequestQueue writersQ; - ESockCounter writePkgCnt; - ESockCounter writePkgMax; - ESockCounter writePkgMaxCnt; - ESockCounter writeByteCnt; - ESockCounter writeTries; - ESockCounter writeWaits; - ESockCounter writeFails; -#ifdef HAVE_SENDFILE - HANDLE sendfileHandle; - ESockSendfileCounters* sendfileCountersP; -#endif - /* +++ Connector +++ */ - ESockRequestor connector; - ESockRequestor* connectorP; // NULL or &connector - /* +++ Config stuff +++ */ - size_t wCtrlSz; // Write control buffer size - ESockMeta meta; // Level 'otp' option 'meta' term - - /* +++ Read stuff +++ */ - ErlNifMutex* readMtx; - /**/ - unsigned int readState; // For debugging - ESockRequestor currentReader; - ESockRequestor* currentReaderP; // NULL or ¤tReader - ESockRequestQueue readersQ; - ErlNifBinary rbuffer; // DO WE NEED THIS - Uint32 readCapacity; // DO WE NEED THIS - ESockCounter readPkgCnt; - ESockCounter readPkgMax; - ESockCounter readPkgMaxCnt; - ESockCounter readByteCnt; - ESockCounter readTries; - ESockCounter readWaits; - ESockCounter readFails; - /* +++ Accept stuff +++ */ - ESockRequestor currentAcceptor; - ESockRequestor* currentAcceptorP; // NULL or ¤tAcceptor - ESockRequestQueue acceptorsQ; - ESockCounter accSuccess; - ESockCounter accTries; - ESockCounter accWaits; - ESockCounter accFails; - /* +++ Config stuff +++ */ - size_t rBufSz; // Read buffer size (when data length = 0) - /* rNum and rNumCnt are used (together with rBufSz) when calling the recv - * function with the Length argument set to 0 (zero). - * If rNum is 0 (zero), then rNumCnt is not used and only *one* read will - * be done. Also, when get'ing the value of the option (rcvbuf) with - * getopt, the value will be reported as an integer. If the rNum has a - * value greater then 0 (zero), then it will instead be reported as {N, BufSz}. - */ - unsigned int rNum; // recv: Number of reads using rBufSz - unsigned int rNumCnt; // recv: Current number of reads (so far) - size_t rCtrlSz; // Read control buffer size - - /* Locked by readMtx and writeMtx combined for writing, - * which means only one of them is required for reading - */ - /* +++ Close stuff +++ */ - ErlNifPid closerPid; - ESockMonitor closerMon; - ErlNifEnv* closeEnv; - ERL_NIF_TERM closeRef; - /* +++ Inform On (counter) Wrap +++ */ - BOOLEAN_T iow; - /* +++ Controller (owner) process +++ */ - ErlNifPid ctrlPid; - ESockMonitor ctrlMon; - /* +++ The actual socket +++ */ - SOCKET sock; - ErlNifEvent event; - SOCKET origFD; // A 'socket' created from this FD - BOOLEAN_T closeOnClose; // Have we dup'ed or not - /* +++ The dbg flag for SSDBG +++ */ - BOOLEAN_T dbg; - BOOLEAN_T useReg; - - /* Lock order: readMtx, writeMtx, cntMtx - */ -} ESockDescriptor; - - -/* Global stuff. - */ -typedef struct { - /* These are for debugging, testing and the like */ - // ERL_NIF_TERM version; - // ERL_NIF_TERM buildDate; - - /* XXX Should be locked but too awkward and small gain */ - BOOLEAN_T dbg; - BOOLEAN_T useReg; - - /* Registry stuff */ - ErlNifPid regPid; /* Constant - not locked */ - - /* IOV_MAX. Constant - not locked */ - int iov_max; - - /* XXX - * Should be locked but too awkward for no gain since it is not used yet - */ - BOOLEAN_T iow; // Where do we send this? Subscription? - - ErlNifMutex* protocolsMtx; - - ErlNifMutex* cntMtx; /* Locks the below */ - /* Its extreme overkill to have these counters be 64-bit, - * but since the other counters are, it's much simpler to - * let these be 64-bit also. - */ - ESockCounter numSockets; - ESockCounter numTypeStreams; - ESockCounter numTypeDGrams; - ESockCounter numTypeSeqPkgs; - ESockCounter numDomainInet; - ESockCounter numDomainInet6; - ESockCounter numDomainLocal; - ESockCounter numProtoIP; - ESockCounter numProtoTCP; - ESockCounter numProtoUDP; - ESockCounter numProtoSCTP; - // - BOOLEAN_T sockDbg; -} ESockData; +/* We can use the IPv4 def for this since the beginning + * is the same for INET and INET6 */ +#define which_address_port(sap) \ + ((((sap)->in4.sin_family == AF_INET) || \ + ((sap)->in4.sin_family == AF_INET6)) ? \ + ((sap)->in4.sin_port) : -1) /* ---------------------------------------------------------------------- @@ -1331,7 +996,6 @@ typedef struct { */ -extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ /* All the nif "callback" functions for the socket API has @@ -1407,247 +1071,133 @@ ESOCK_NIF_FUNCS #undef ESOCK_NIF_FUNC_DEF -#ifndef __WIN32__ -/* ---------------------------------------------------------------------- * - * * - * * - * Start of non-__WIN32__ section a.k.a UNIX section * - * * - * * - * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ +/* ======================================================================= + * Socket specific backend 'synchronicity' functions. + * This type is used to create 'sync' function table. + * This table is initiated when the nif is loaded. + * Initially, its content will be hardcoded to: + * * Windows: async (esaio) + * * Other (unix): sync (essio) + * When we introduce async I/O for unix (io_uring or something similar) + * we may make it possible to choose (set a flag when the VM is started; + * --esock-io=). + */ -/* And here comes the functions that does the actual work (for the most part) */ +typedef struct { + ESockIOInit init; + ESockIOFinish finish; + + ESockIOInfo info; + ESockIOCommand cmd; + ESockIOSupports0 supports_0; + ESockIOSupports1 supports_1; + + ESockIOOpenWithFd open_with_fd; + ESockIOOpenPlain open_plain; + ESockIOBind bind; + + ESockIOConnect connect; + ESockIOListen listen; + ESockIOAccept accept; + + ESockIOSend send; + ESockIOSendTo sendto; + ESockIOSendMsg sendmsg; + ESockIOSendFileStart sendfile_start; + ESockIOSendFileContinue sendfile_cont; + ESockIOSendFileDeferredClose sendfile_dc; + + ESockIORecv recv; + ESockIORecvFrom recvfrom; + ESockIORecvMsg recvmsg; + + ESockIOClose close; + ESockIOFinClose fin_close; + ESockIOShutdown shutdown; + + ESockIOSockName sockname; + ESockIOPeerName peername; + + /* The various cancel operations */ + ESockIOCancelConnect cancel_connect; + ESockIOCancelAccept cancel_accept; + ESockIOCancelSend cancel_send; + ESockIOCancelRecv cancel_recv; + + /* Socket option callback functions */ + ESockIOSetopt setopt; + ESockIOSetoptNative setopt_native; + ESockIOSetoptOtp setopt_otp; + ESockIOGetopt getopt; + ESockIOGetoptNative getopt_native; + ESockIOGetoptOtp getopt_otp; + + /* Socket ioctl callback functions */ + ESockIOIoctl_2 ioctl_2; + ESockIOIoctl_3 ioctl_3; + ESockIOIoctl_4 ioctl_4; + + /* (socket) NIF resource callback functions */ + ESockIODTor dtor; + ESockIOStop stop; + ESockIODown down; + +} ESockIoBackend; -static ERL_NIF_TERM esock_command(ErlNifEnv* env, - ERL_NIF_TERM command, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, - ERL_NIF_TERM cdata); -static ERL_NIF_TERM esock_global_info(ErlNifEnv* env); -static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, - unsigned int state); -#define ESOCK_SOCKET_INFO_REQ_FUNCS \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \ - ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors); +/* ------------------------------------------------------------------------ + * Socket option(s) and table(s) + */ -#define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ - ESockDescriptor* descP); -ESOCK_SOCKET_INFO_REQ_FUNCS -#undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF +struct ESockOpt +{ + int opt; // Option number -static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* currentRequestorP, - ESockRequestQueue* q); + // Function to set option + ERL_NIF_TERM (*setopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); -static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key); + // Function to get option + ERL_NIF_TERM (*getopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); -static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env); -static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env); + ERL_NIF_TERM *nameP; // Pointer to option name atom +}; -static ERL_NIF_TERM esock_open2(ErlNifEnv* env, - int fd, - ERL_NIF_TERM eextra); -static BOOLEAN_T esock_open2_todup(ErlNifEnv* env, - ERL_NIF_TERM eextra); -static BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env, - ERL_NIF_TERM eopts, - int* domain); -static BOOLEAN_T esock_open2_get_type(ErlNifEnv* env, - ERL_NIF_TERM eopt, - int* type); -static ERL_NIF_TERM esock_open4(ErlNifEnv* env, - int domain, - int type, - int protocol, - ERL_NIF_TERM eopts); -static BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, - ERL_NIF_TERM eextra, - BOOLEAN_T dflt); -static BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, - ERL_NIF_TERM eextra, - BOOLEAN_T dflt); -static BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain); -static BOOLEAN_T esock_open_which_type(SOCKET sock, int* type); -static BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto); - -static ERL_NIF_TERM esock_bind(ErlNifEnv* env, - ESockDescriptor* descP, - ESockAddress* sockAddrP, - SOCKLEN_T addrLen); -static ERL_NIF_TERM esock_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM connRef, - ESockAddress* addrP, - SOCKLEN_T addrLen); -static ERL_NIF_TERM esock_listen(ErlNifEnv* env, - ESockDescriptor* descP, - int backlog); -static ERL_NIF_TERM esock_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref); -static ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid caller, - int save_errno); -static ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid caller); -static ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref); -static ERL_NIF_TERM -esock_accept_accepting_current_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock); -static ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - int save_errno); -static ERL_NIF_TERM esock_accept_accepting_other(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ErlNifPid caller); -static ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid* pidP); -static BOOLEAN_T esock_accept_accepted(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid pid, - ERL_NIF_TERM* result); -static ERL_NIF_TERM esock_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags); -static ERL_NIF_TERM esock_sendto(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags, - ESockAddress* toAddrP, - SOCKLEN_T toAddrLen); -static ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsg, - int flags, - ERL_NIF_TERM eIOV); -#ifdef HAVE_SENDFILE -static ERL_NIF_TERM -esock_sendfile_start(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count, - ERL_NIF_TERM fRef); -static ERL_NIF_TERM -esock_sendfile_cont(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count); -static ERL_NIF_TERM -esock_sendfile_deferred_close(ErlNifEnv *env, - ESockDescriptor *descP); -static int -esock_sendfile(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - off_t offset, - size_t *count, - int *errP); -static ERL_NIF_TERM -esock_sendfile_error(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM -esock_sendfile_errno(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - int err); -static ERL_NIF_TERM -esock_sendfile_ok(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - size_t count); -static ERL_NIF_TERM -esock_sendfile_select(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - size_t count); -#endif // #ifdef HAVE_SENDFILE +/* Option levels table*/ + +struct ESockOptLevel +{ + int level; // Level number + + size_t num; // Number of options + + struct ESockOpt *opts; // Options table + + ERL_NIF_TERM *nameP; // Pointer to level name atom +}; -static ERL_NIF_TERM esock_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags); -static ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufSz, - int flags); -static ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufLen, - ssize_t ctrlLen, - int flags); -static ERL_NIF_TERM esock_close(ErlNifEnv* env, - ESockDescriptor* descP); -static BOOLEAN_T esock_do_stop(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, - ESockDescriptor* descP, - int how); +/* First chunk of forwards...some of these are used in the options tables... */ + +/* Set native options */ +static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM valueSpec); /* Set OTP level options */ static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, ESockDescriptor* descP, @@ -1662,28 +1212,186 @@ static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, * *** esock_setopt_otp_meta *** * *** esock_setopt_otp_use_registry *** */ -#define ESOCK_SETOPT_OTP_FUNCS \ - ESOCK_SETOPT_OTP_FUNC_DEF(debug); \ - ESOCK_SETOPT_OTP_FUNC_DEF(iow); \ - ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \ - ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf); \ - ESOCK_SETOPT_OTP_FUNC_DEF(meta); \ +#define ESOCK_SETOPT_OTP_FUNCS \ + ESOCK_SETOPT_OTP_FUNC_DEF(debug); \ + ESOCK_SETOPT_OTP_FUNC_DEF(iow); \ + ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \ + ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(sndctrlbuf); \ + ESOCK_SETOPT_OTP_FUNC_DEF(meta); \ ESOCK_SETOPT_OTP_FUNC_DEF(use_registry); -#define ESOCK_SETOPT_OTP_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ +#define ESOCK_SETOPT_OTP_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_setopt_otp_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ ERL_NIF_TERM eVal) ESOCK_SETOPT_OTP_FUNCS #undef ESOCK_SETOPT_OTP_FUNC_DEF -/* Set native options */ -static ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal); +static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt); +/* *** esock_getopt_otp_debug *** + * *** esock_getopt_otp_iow *** + * *** esock_getopt_otp_ctrl_proc *** + * *** esock_getopt_otp_rcvbuf *** + * *** esock_getopt_otp_rcvctrlbuf *** + * *** esock_getopt_otp_sndctrlbuf *** + * *** esock_getopt_otp_fd *** + * *** esock_getopt_otp_meta *** + * *** esock_getopt_otp_use_registry *** + * *** esock_getopt_otp_domain *** + * *** //esock_getopt_otp_type *** + * *** //esock_getopt_otp_protocol *** + * *** //esock_getopt_otp_dtp *** + */ +#define ESOCK_GETOPT_OTP_FUNCS \ + ESOCK_GETOPT_OTP_FUNC_DEF(debug); \ + ESOCK_GETOPT_OTP_FUNC_DEF(iow); \ + ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \ + ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \ + ESOCK_GETOPT_OTP_FUNC_DEF(fd); \ + ESOCK_GETOPT_OTP_FUNC_DEF(meta); \ + ESOCK_GETOPT_OTP_FUNC_DEF(use_registry); \ + ESOCK_GETOPT_OTP_FUNC_DEF(domain); +#if 0 +ESOCK_GETOPT_OTP_FUNC_DEF(type); \ +ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \ +ESOCK_GETOPT_OTP_FUNC_DEF(dtp); +#endif +#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) +ESOCK_GETOPT_OTP_FUNCS +#undef ESOCK_GETOPT_OTP_FUNC_DEF + +static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + void* optVal, + socklen_t optLen); +static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + SOCKOPTLEN_T valueSz); +static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ErlNifBinary* binP); + +static int socket_setopt(int sock, + int level, + int opt, + const void* optVal, + const socklen_t optLen); + +static int cmpESockOpt(const void *vpa, const void *vpb); +static int cmpESockOptLevel(const void *vpa, const void *vpb); +static struct ESockOpt *lookupOpt(int level, int opt); + + +static ERL_NIF_TERM esock_supports_0(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key); + +static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env); +static ERL_NIF_TERM esock_supports_options(ErlNifEnv* env); + +#ifndef __WIN32__ +/* ---------------------------------------------------------------------- * + * * + * * + * Start of non-__WIN32__ section a.k.a UNIX section * + * * + * * + * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ + +/* *** esock_activate_next_acceptor *** + * *** esock_activate_next_writer *** + * *** esock_activate_next_reader *** + * + * All the activate-next functions for acceptor, writer and reader + * have exactly the same API, so we apply some macro magic to simplify. + * They simply operates on dufferent data structures. + * + */ + +#define ACTIVATE_NEXT_FUNCS_DEFS \ + ACTIVATE_NEXT_FUNC_DEF(acceptor) \ + ACTIVATE_NEXT_FUNC_DEF(writer) \ + ACTIVATE_NEXT_FUNC_DEF(reader) + +#define ACTIVATE_NEXT_FUNC_DEF(F) \ + extern BOOLEAN_T esock_activate_next_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM sockRef); +ACTIVATE_NEXT_FUNCS_DEFS +#undef ACTIVATE_NEXT_FUNC_DEF + +/* esock_acceptor_search4pid | esock_writer_search4pid | esock_reader_search4pid + * esock_acceptor_push | esock_writer_push | esock_reader_push + * esock_acceptor_pop | esock_writer_pop | esock_reader_pop + * esock_acceptor_unqueue | esock_writer_unqueue | esock_reader_unqueue + * + * All the queue operator functions (search4pid, push, pop + * and unqueue) for acceptor, writer and reader has exactly + * the same API, so we apply some macro magic to simplify. + */ + +#define ESOCK_OPERATOR_FUNCS_DEFS \ + ESOCK_OPERATOR_FUNCS_DEF(acceptor) \ + ESOCK_OPERATOR_FUNCS_DEF(writer) \ + ESOCK_OPERATOR_FUNCS_DEF(reader) + +#define ESOCK_OPERATOR_FUNCS_DEF(O) \ + extern BOOLEAN_T esock_##O##_search4pid(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid* pid); \ + extern void esock_##O##_push(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid pid, \ + ERL_NIF_TERM ref, \ + void* dataP); \ + extern BOOLEAN_T esock_##O##_pop(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ESockRequestor* reqP); \ + extern BOOLEAN_T esock_##O##_unqueue(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP); +ESOCK_OPERATOR_FUNCS_DEFS +#undef ESOCK_OPERATOR_FUNCS_DEF + +static ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM selectRef); + + +/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * + * * + * * + * End of non-__WIN32__ section a.k.a UNIX section * + * * + * * + * ---------------------------------------------------------------------- */ +#endif // #ifndef __WIN32__ + + static ERL_NIF_TERM esock_setopt(ErlNifEnv* env, ESockDescriptor* descP, int level, @@ -1700,6 +1408,17 @@ static ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env, ERL_NIF_TERM eVal); #endif +#if defined(SO_BSP_STATE) +static ERL_NIF_TERM esock_getopt_bsp_state(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +static ERL_NIF_TERM esock_encode_bsp_state_socket_address(ErlNifEnv* env, + SOCKET_ADDRESS* addr); +static ERL_NIF_TERM esock_encode_bsp_state_type(ErlNifEnv* env, int type); +static ERL_NIF_TERM esock_encode_bsp_state_protocol(ErlNifEnv* env, int proto); +#endif + #if defined(SO_LINGER) static ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, @@ -1849,50 +1568,6 @@ static ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, #endif // defined(HAVE_SCTP) -static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, - ESockDescriptor* descP, - int eOpt); -/* *** esock_getopt_otp_debug *** - * *** esock_getopt_otp_iow *** - * *** esock_getopt_otp_ctrl_proc *** - * *** esock_getopt_otp_rcvbuf *** - * *** esock_getopt_otp_rcvctrlbuf *** - * *** esock_getopt_otp_sndctrlbuf *** - * *** esock_getopt_otp_fd *** - * *** esock_getopt_otp_meta *** - * *** esock_getopt_otp_use_registry *** - * *** esock_getopt_otp_domain *** - * *** //esock_getopt_otp_type *** - * *** //esock_getopt_otp_protocol *** - * *** //esock_getopt_otp_dtp *** - */ -#define ESOCK_GETOPT_OTP_FUNCS \ - ESOCK_GETOPT_OTP_FUNC_DEF(debug); \ - ESOCK_GETOPT_OTP_FUNC_DEF(iow); \ - ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \ - ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(rcvctrlbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(sndctrlbuf); \ - ESOCK_GETOPT_OTP_FUNC_DEF(fd); \ - ESOCK_GETOPT_OTP_FUNC_DEF(meta); \ - ESOCK_GETOPT_OTP_FUNC_DEF(use_registry); \ - ESOCK_GETOPT_OTP_FUNC_DEF(domain); -#if 0 - ESOCK_GETOPT_OTP_FUNC_DEF(type); \ - ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \ - ESOCK_GETOPT_OTP_FUNC_DEF(dtp); -#endif -#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \ - ESockDescriptor* descP) -ESOCK_GETOPT_OTP_FUNCS -#undef ESOCK_GETOPT_OTP_FUNC_DEF - -static ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM valueSpec); static ERL_NIF_TERM esock_getopt(ErlNifEnv* env, ESockDescriptor* descP, int level, @@ -1929,9 +1604,9 @@ ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, #if defined(IP_MTU_DISCOVER) static ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); + ESockDescriptor* descP, + int level, + int opt); #endif #if defined(IP_MULTICAST_IF) static ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, @@ -1997,15126 +1672,9148 @@ static ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env, #endif // defined(HAVE_SCTP) -static ERL_NIF_TERM esock_sockname(ErlNifEnv* env, - ESockDescriptor* descP); -static ERL_NIF_TERM esock_peername(ErlNifEnv* env, - ESockDescriptor* descP); - -static ERL_NIF_TERM esock_ioctl1(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req); -static ERL_NIF_TERM esock_ioctl2(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM arg); -static ERL_NIF_TERM esock_ioctl3(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM ename, - ERL_NIF_TERM eval); -static ERL_NIF_TERM esock_ioctl_gifconf(ErlNifEnv* env, - ESockDescriptor* descP); -#if defined(SIOCGIFNAME) -static ERL_NIF_TERM esock_ioctl_gifname(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eidx); +#if defined(USE_SETOPT_STR_OPT) +static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + int max, + ERL_NIF_TERM eVal); #endif - -/* esock_ioctl_gifindex */ -#if defined(SIOCGIFINDEX) -#define IOCTL_GIFINDEX_FUNC_DEF IOCTL_GET_FUNC_DEF(gifindex) -#else -#define IOCTL_GIFINDEX_FUNC_DEF +static ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ + && defined(ESOCK_USE_RCVSNDTIMEO) +static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); #endif - -/* esock_ioctl_gifflags */ -#if defined(SIOCGIFFLAGS) -#define IOCTL_GIFFLAGS_FUNC_DEF IOCTL_GET_FUNC_DEF(gifflags) -#else -#define IOCTL_GIFFLAGS_FUNC_DEF +#if defined(USE_GETOPT_STR_OPT) +static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + int max, + BOOLEAN_T stripNUL); #endif - -/* esock_ioctl_gifaddr */ -#if defined(SIOCGIFADDR) -#define IOCTL_GIFADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifaddr) -#else -#define IOCTL_GIFADDR_FUNC_DEF +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ + && defined(ESOCK_USE_RCVSNDTIMEO) +static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); #endif -/* esock_ioctl_gifdstaddr */ -#if defined(SIOCGIFDSTADDR) -#define IOCTL_GIFDSTADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifdstaddr) -#else -#define IOCTL_GIFDSTADDR_FUNC_DEF -#endif -/* esock_ioctl_gifbrdaddr */ -#if defined(SIOCGIFBRDADDR) -#define IOCTL_GIFBRDADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifbrdaddr) -#else -#define IOCTL_GIFBRDADDR_FUNC_DEF -#endif -/* esock_ioctl_gifnetmask */ -#if defined(SIOCGIFNETMASK) -#define IOCTL_GIFNETMASK_FUNC_DEF IOCTL_GET_FUNC_DEF(gifnetmask) -#else -#define IOCTL_GIFNETMASK_FUNC_DEF -#endif -/* esock_ioctl_gifmtu */ -#if defined(SIOCGIFMTU) -#define IOCTL_GIFMTU_FUNC_DEF IOCTL_GET_FUNC_DEF(gifmtu) -#else -#define IOCTL_GIFMTU_FUNC_DEF -#endif -/* esock_ioctl_gifhwaddr */ -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -#define IOCTL_GIFHWADDR_FUNC_DEF IOCTL_GET_FUNC_DEF(gifhwaddr) -#else -#define IOCTL_GIFHWADDR_FUNC_DEF -#endif -/* esock_ioctl_gifmap */ -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -#define IOCTL_GIFMAP_FUNC_DEF IOCTL_GET_FUNC_DEF(gifmap) -#else -#define IOCTL_GIFMAP_FUNC_DEF -#endif -/* esock_ioctl_giftxqlen */ -#if defined(SIOCGIFTXQLEN) -#define IOCTL_GIFTXQLEN_FUNC_DEF IOCTL_GET_FUNC_DEF(giftxqlen) -#else -#define IOCTL_GIFTXQLEN_FUNC_DEF -#endif - -#define IOCTL_GET_FUNCS_DEF \ - IOCTL_GIFINDEX_FUNC_DEF; \ - IOCTL_GIFFLAGS_FUNC_DEF; \ - IOCTL_GIFADDR_FUNC_DEF; \ - IOCTL_GIFDSTADDR_FUNC_DEF; \ - IOCTL_GIFBRDADDR_FUNC_DEF; \ - IOCTL_GIFNETMASK_FUNC_DEF; \ - IOCTL_GIFMTU_FUNC_DEF; \ - IOCTL_GIFHWADDR_FUNC_DEF; \ - IOCTL_GIFMAP_FUNC_DEF; \ - IOCTL_GIFTXQLEN_FUNC_DEF; -#define IOCTL_GET_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_ioctl_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename) -IOCTL_GET_FUNCS_DEF -#undef IOCTL_GET_FUNC_DEF - -/* esock_ioctl_sifflags */ -#if defined(SIOCSIFFLAGS) -#define IOCTL_SIFFLAGS_FUNC_DEF IOCTL_SET_FUNC_DEF(sifflags) -#else -#define IOCTL_SIFFLAGS_FUNC_DEF -#endif +static ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, + ESockDescriptor* descP, + int how); +static ERL_NIF_TERM esock_sockname(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_peername(ErlNifEnv* env, + ESockDescriptor* descP); -/* esock_ioctl_sifaddr */ -#if defined(SIOCSIFADDR) -#define IOCTL_SIFADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifaddr) -#else -#define IOCTL_SIFADDR_FUNC_DEF -#endif +static ERL_NIF_TERM esock_command(ErlNifEnv* env, + ERL_NIF_TERM command, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, + ERL_NIF_TERM cdata); +static ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, + ERL_NIF_TERM cdata); -/* esock_ioctl_sifdstaddr */ -#if defined(SIOCSIFDSTADDR) -#define IOCTL_SIFDSTADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifdstaddr) -#else -#define IOCTL_SIFDSTADDR_FUNC_DEF -#endif +#define ESOCK_SOCKET_INFO_REQ_FUNCS \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(readers); \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(writers); \ + ESOCK_SOCKET_INFO_REQ_FUNC_DEF(acceptors); -/* esock_ioctl_sifbrdaddr */ -#if defined(SIOCSIFBRDADDR) -#define IOCTL_SIFBRDADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifbrdaddr) -#else -#define IOCTL_SIFBRDADDR_FUNC_DEF -#endif - -/* esock_ioctl_sifnetmask */ -#if defined(SIOCSIFNETMASK) -#define IOCTL_SIFNETMASK_FUNC_DEF IOCTL_SET_FUNC_DEF(sifnetmask) -#else -#define IOCTL_SIFNETMASK_FUNC_DEF -#endif - -/* esock_ioctl_sifmtu */ -#if defined(SIOCSIFMTU) -#define IOCTL_SIFMTU_FUNC_DEF IOCTL_SET_FUNC_DEF(sifmtu) -#else -#define IOCTL_SIFMTU_FUNC_DEF -#endif - -/* esock_ioctl_siftxqlen */ -#if defined(SIOCSIFTXQLEN) -#define IOCTL_SIFTXQLEN_FUNC_DEF IOCTL_SET_FUNC_DEF(siftxqlen) -#else -#define IOCTL_SIFTXQLEN_FUNC_DEF -#endif - -#define IOCTL_SET_FUNCS_DEF \ - IOCTL_SIFFLAGS_FUNC_DEF; \ - IOCTL_SIFADDR_FUNC_DEF; \ - IOCTL_SIFDSTADDR_FUNC_DEF; \ - IOCTL_SIFBRDADDR_FUNC_DEF; \ - IOCTL_SIFNETMASK_FUNC_DEF; \ - IOCTL_SIFMTU_FUNC_DEF; \ - IOCTL_SIFTXQLEN_FUNC_DEF; -#define IOCTL_SET_FUNC_DEF(F) \ - static ERL_NIF_TERM esock_ioctl_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename, \ - ERL_NIF_TERM evalue) -IOCTL_SET_FUNCS_DEF -#undef IOCTL_SET_FUNC_DEF - - -static ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifconf* ifcP); -static ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifreq* ifrP); -static ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, - char* name); -static ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, - struct sockaddr* sa); -static ERL_NIF_TERM make_ifreq(ErlNifEnv* env, - ERL_NIF_TERM name, - ERL_NIF_TERM key2, - ERL_NIF_TERM val2); -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -static ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifmap* mapP); -#endif -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP); -#endif -static ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP); -static ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - short flags); -#if defined(SIOCSIFFLAGS) -static BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eflags, - short* flags); -#endif -static BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eaddr, - ESockAddress* addr); -#if defined(SIOCSIFMTU) -static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM emtu, - int* mtu); -#endif -#if defined(SIOCSIFTXQLEN) -static BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM etxqlen, - int* txqlen); -#endif -#if defined(SIOCSIFTXQLEN) -static BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eivalue, - int* ivalue); -#endif -static ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - int ivalue); +#define ESOCK_SOCKET_INFO_REQ_FUNC_DEF(F) \ + static ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ + ESockDescriptor* descP); +ESOCK_SOCKET_INFO_REQ_FUNCS +#undef ESOCK_SOCKET_INFO_REQ_FUNC_DEF static ERL_NIF_TERM esock_cancel(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM op, ERL_NIF_TERM sockRef, ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); -static ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); +/* static ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP); -static ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef); -static ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - int smode, - int rmode); +*/ +static ERL_NIF_TERM esock_listen(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog); -#if defined(USE_SETOPT_STR_OPT) -static ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - int max, - ERL_NIF_TERM eVal); -#endif -static ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal); -static ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal); -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ - && defined(ESOCK_USE_RCVSNDTIMEO) -static ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal); +static ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, + ESockDescriptor* descP, +#ifndef __WIN32__ + ESockRequestor* currentRequestorP, #endif -static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - void* optVal, - socklen_t optLen); + ESockRequestQueue* q); -#if defined(USE_GETOPT_STR_OPT) -static ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - int max, - BOOLEAN_T stripNUL); -#endif -static ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); -static ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); -static BOOLEAN_T esock_getopt_int(SOCKET sock, - int level, - int opt, - int* valP); -static ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - SOCKOPTLEN_T valueSz); -static ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ErlNifBinary* binP); -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ - && defined(ESOCK_USE_RCVSNDTIMEO) -static ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt); -#endif +static ERL_NIF_TERM esock_global_info(ErlNifEnv* env); +static ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, + unsigned int state); +static ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, + ESockDescriptor* descP); +static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM closeRef); +static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, + ERL_NIF_TERM tag, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM mk_simple_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM cnt); +static BOOLEAN_T qsearch4pid(ErlNifEnv* env, + ESockRequestQueue* q, + ErlNifPid* pid); +static unsigned int qlength(ESockRequestQueue* q); +static void qpush(ESockRequestQueue* q, + ESockRequestQueueElement* e); +static ESockRequestQueueElement* qpop(ESockRequestQueue* q); +static BOOLEAN_T qunqueue(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP); +static ESockRequestQueueElement* qget(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP); +static char* extract_debug_filename(ErlNifEnv* env, + ERL_NIF_TERM map); -/* ------------------------------------------------------------------------ - * Socket option tables and handling - */ -struct ESockOpt -{ - int opt; // Option number +/* --------------------------------------------------------------------- */ - // Function to set option - ERL_NIF_TERM (*setopt) - (ErlNifEnv *env, ESockDescriptor *descP, - int level, int opt, ERL_NIF_TERM eVal); +#if defined(IP_TOS) +static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IP_MTU_DISCOVER) +static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IP_MTU_DISCOVER) +static void encode_ip_pmtudisc(ErlNifEnv* env, + int val, + ERL_NIF_TERM* eVal); +#endif +#if defined(IPV6_MTU_DISCOVER) +static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, + ERL_NIF_TERM eVal, + int* val); +#endif +#if defined(IPV6_MTU_DISCOVER) +static void encode_ipv6_pmtudisc(ErlNifEnv* env, + int val, + ERL_NIF_TERM* eVal); +#endif - // Function to get option - ERL_NIF_TERM (*getopt) - (ErlNifEnv *env, ESockDescriptor *descP, - int level, int opt); +static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val); - ERL_NIF_TERM *nameP; // Pointer to option name atom -}; +#if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) +static +BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val); +#endif -// qsort and bsearch helper -static int cmpESockOpt(const void *vpa, const void *vpb) { - struct ESockOpt *a, *b; - a = (struct ESockOpt *) vpa; - b = (struct ESockOpt *) vpb; - return a->opt < b->opt ? -1 : (a->opt > b->opt ? 1 : 0); -} +#if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) +static BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env, + ERL_NIF_TERM eVal, + sctp_assoc_t* val); +static ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, + sctp_assoc_t val); +#endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) -/* SO_* options -------------------------------------------------------- */ +static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how); -static struct ESockOpt optLevelSocket[] = - { - { -#ifdef SO_ACCEPTCONN - SO_ACCEPTCONN, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, + +/* +#if defined(HAS_AF_LOCAL) || defined(SO_BINDTODEVICE) +static size_t my_strnlen(const char *s, size_t maxlen); #endif - &esock_atom_acceptconn}, +*/ - {0, NULL, NULL, &esock_atom_acceptfilter}, +static void esock_dtor(ErlNifEnv* env, void* obj); +static void esock_stop(ErlNifEnv* env, + void* obj, + ErlNifEvent fd, + int is_direct_call); +static void esock_down(ErlNifEnv* env, + void* obj, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); - { -#ifdef SO_BINDTODEVICE - SO_BINDTODEVICE, - esock_setopt_so_bindtodevice, esock_getopt_so_bindtodevice, -#else - 0, NULL, NULL, -#endif - &esock_atom_bindtodevice}, +static void esock_on_halt(void* priv_data); - { -#ifdef SO_BROADCAST - SO_BROADCAST, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_broadcast}, +static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); - {0, NULL, NULL, &esock_atom_busy_poll}, - { -#ifdef SO_DEBUG - SO_DEBUG, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_debug}, - - { -#ifdef SO_DOMAIN - SO_DOMAIN, - NULL, esock_getopt_sock_domain, -#else - 0, NULL, NULL, -#endif - &esock_atom_domain}, - - { -#ifdef SO_DONTROUTE - SO_DONTROUTE, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_dontroute}, - - {0, NULL, NULL, &esock_atom_error}, - - { -#ifdef SO_KEEPALIVE - SO_KEEPALIVE, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_keepalive}, - - { -#ifdef SO_LINGER - SO_LINGER, - esock_setopt_linger, esock_getopt_linger, -#else - 0, NULL, NULL, -#endif - &esock_atom_linger}, - - {0, NULL, NULL, &esock_atom_mark}, - - { -#ifdef SO_OOBINLINE - SO_OOBINLINE, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_oobinline}, - - { -#ifdef SO_PASSCRED - SO_PASSCRED, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_passcred}, - - { -#ifdef SO_PEEK_OFF - SO_PEEK_OFF, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_peek_off}, - - {0, NULL, NULL, &esock_atom_peercred}, - - { -#ifdef SO_PRIORITY - SO_PRIORITY, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_priority}, - - { -#ifdef SO_PROTOCOL - SO_PROTOCOL, - NULL, esock_getopt_sock_protocol, -#else - 0, NULL, NULL, -#endif - &esock_atom_protocol}, - - { -#ifdef SO_RCVBUF - SO_RCVBUF, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_rcvbuf}, - - {0, NULL, NULL, &esock_atom_rcvbufforce}, - - { -#ifdef SO_RCVLOWAT - SO_RCVLOWAT, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_rcvlowat}, - - { -#if defined(SO_RCVTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO) - SO_RCVTIMEO, - esock_setopt_timeval_opt, esock_getopt_timeval_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_rcvtimeo}, - - { -#ifdef SO_REUSEADDR - SO_REUSEADDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_reuseaddr}, - - { -#ifdef SO_REUSEPORT - SO_REUSEPORT, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_reuseport}, - - {0, NULL, NULL, &esock_atom_rxq_ovfl}, - {0, NULL, NULL, &esock_atom_setfib}, - - { -#ifdef SO_SNDBUF - SO_SNDBUF, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_sndbuf}, - - {0, NULL, NULL, &esock_atom_sndbufforce}, - - { -#ifdef SO_SNDLOWAT - SO_SNDLOWAT, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_sndlowat}, - - { -#if defined(SO_SNDTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO) - SO_SNDTIMEO, - esock_setopt_timeval_opt, esock_getopt_timeval_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_sndtimeo}, - - { -#ifdef SO_TIMESTAMP - SO_TIMESTAMP, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_timestamp}, - - { -#ifdef SO_TYPE - SO_TYPE, - NULL, esock_getopt_sock_type, -#else - 0, NULL, NULL, -#endif - &esock_atom_type} - }; - - -/* IP_* options -------------------------------------------------------- */ - -static struct ESockOpt optLevelIP[] = - { - { -#ifdef IP_ADD_MEMBERSHIP - IP_ADD_MEMBERSHIP, - esock_setopt_in_update_membership, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_add_membership}, - - { -#ifdef IP_ADD_SOURCE_MEMBERSHIP - IP_ADD_SOURCE_MEMBERSHIP, - esock_setopt_in_update_source, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_add_source_membership}, - - { -#ifdef IP_BLOCK_SOURCE - IP_BLOCK_SOURCE, - esock_setopt_in_update_source, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_block_source}, - - {0, NULL, NULL, &esock_atom_dontfrag}, - - { -#ifdef IP_DROP_MEMBERSHIP - IP_DROP_MEMBERSHIP, - esock_setopt_in_update_membership, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_drop_membership}, - - { -#ifdef IP_DROP_SOURCE_MEMBERSHIP - IP_DROP_SOURCE_MEMBERSHIP, - esock_setopt_in_update_source, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_drop_source_membership}, - - { -#ifdef IP_FREEBIND - IP_FREEBIND, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_freebind}, - - { -#ifdef IP_HDRINCL - IP_HDRINCL, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_hdrincl}, - - { -#ifdef IP_MINTTL - IP_MINTTL, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_minttl}, - - { -#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) - IP_MSFILTER, - esock_setopt_msfilter, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_msfilter}, - - { -#ifdef IP_MTU - IP_MTU, - NULL, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_mtu}, - - { -#ifdef IP_MTU_DISCOVER - IP_MTU_DISCOVER, - esock_setopt_ip_mtu_discover, esock_getopt_ip_mtu_discover, -#else - 0, NULL, NULL, -#endif - &esock_atom_mtu_discover}, - - { -#ifdef IP_MULTICAST_ALL - IP_MULTICAST_ALL, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_all}, - - { -#ifdef IP_MULTICAST_IF - IP_MULTICAST_IF, - esock_setopt_multicast_if, esock_getopt_multicast_if, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_if}, - - { -#ifdef IP_MULTICAST_LOOP - IP_MULTICAST_LOOP, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_loop}, - - { -#ifdef IP_MULTICAST_TTL - IP_MULTICAST_TTL, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_ttl}, - - { -#ifdef IP_NODEFRAG - IP_NODEFRAG, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_nodefrag}, - - {0, NULL, NULL, &esock_atom_options}, - - { -#ifdef IP_PKTINFO - IP_PKTINFO, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_pktinfo}, - - { -#ifdef IP_PKTOPTIONS - IP_PKTOPTIONS, - NULL, esock_getopt_pktoptions, -#else - 0, NULL, NULL, -#endif - &esock_atom_pktoptions}, - - { -#ifdef IP_RECVDSTADDR - IP_RECVDSTADDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvdstaddr}, - - { -#ifdef IP_RECVERR - IP_RECVERR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recverr}, - - { -#ifdef IP_RECVIF - IP_RECVIF, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvif}, - - { -#ifdef IP_RECVOPTS - IP_RECVOPTS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvopts}, - - { -#ifdef IP_RECVORIGDSTADDR - IP_RECVORIGDSTADDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvorigdstaddr}, - - { -#ifdef IP_RECVTOS - IP_RECVTOS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvtos}, - - { -#ifdef IP_RECVTTL - IP_RECVTTL, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvttl}, - - { -#ifdef IP_RETOPTS - IP_RETOPTS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_retopts}, - - { -#ifdef IP_ROUTER_ALERT - IP_ROUTER_ALERT, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_router_alert}, - - { -#ifdef IP_SENDSRCADDR - IP_SENDSRCADDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_sendsrcaddr}, - - { -#ifdef IP_TOS - IP_TOS, - esock_setopt_tos, esock_getopt_tos, -#else - 0, NULL, NULL, -#endif - &esock_atom_tos}, - - { -#ifdef IP_TRANSPARENT - IP_TRANSPARENT, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_transparent}, - - { -#ifdef IP_TTL - IP_TTL, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_ttl}, - - { -#ifdef IP_UNBLOCK_SOURCE - IP_UNBLOCK_SOURCE, - esock_setopt_in_update_source, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_unblock_source} - - }; - -/* IPV6_* options ------------------------------------------------------ */ - -#ifdef HAVE_IPV6 -static struct ESockOpt optLevelIPV6[] = - { - - { -#ifdef IPV6_ADDRFORM - IPV6_ADDRFORM, - esock_setopt_addrform, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_addrform}, - - { -#ifdef IPV6_ADD_MEMBERSHIP - IPV6_ADD_MEMBERSHIP, - esock_setopt_in6_update_membership, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_add_membership}, - - { -#ifdef IPV6_AUTHHDR - IPV6_AUTHHDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_authhdr}, - - {0, NULL, NULL, &esock_atom_auth_level}, - {0, NULL, NULL, &esock_atom_checksum}, - - { -#ifdef IPV6_DROP_MEMBERSHIP - IPV6_DROP_MEMBERSHIP, - esock_setopt_in6_update_membership, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_drop_membership}, - - { -#if defined(IPV6_DSTOPTS) - IPV6_DSTOPTS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_dstopts}, - - {0, NULL, NULL, &esock_atom_esp_network_level}, - {0, NULL, NULL, &esock_atom_esp_trans_level}, - {0, NULL, NULL, &esock_atom_faith}, - - { -#ifdef IPV6_FLOWINFO - IPV6_FLOWINFO, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_flowinfo}, - - { -#ifdef IPV6_HOPLIMIT - IPV6_HOPLIMIT, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_hoplimit}, - - { -#ifdef IPV6_HOPOPTS - IPV6_HOPOPTS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_hopopts}, - - {0, NULL, NULL, &esock_atom_ipcomp_level}, - {0, NULL, NULL, &esock_atom_join_group}, - {0, NULL, NULL, &esock_atom_leave_group}, - - { -#ifdef IPV6_MTU - IPV6_MTU, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_mtu}, - - { -#ifdef IPV6_MTU_DISCOVER - IPV6_MTU_DISCOVER, - esock_setopt_ipv6_mtu_discover, esock_getopt_ipv6_mtu_discover, -#else - 0, NULL, NULL, -#endif - &esock_atom_mtu_discover}, - - { -#ifdef IPV6_MULTICAST_HOPS - IPV6_MULTICAST_HOPS, - esock_setopt_hops, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_hops}, - - { -#ifdef IPV6_MULTICAST_IF - IPV6_MULTICAST_IF, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_if}, - - { -#ifdef IPV6_MULTICAST_LOOP - IPV6_MULTICAST_LOOP, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_multicast_loop}, - - {0, NULL, NULL, &esock_atom_portrange}, - - { -#ifdef IPV6_PKTOPTIONS - IPV6_PKTOPTIONS, - NULL, esock_getopt_pktoptions, -#else - 0, NULL, NULL, -#endif - &esock_atom_pktoptions}, - - { -#ifdef IPV6_RECVERR - IPV6_RECVERR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recverr}, - - { -#ifdef IPV6_RECVHOPLIMIT - IPV6_RECVHOPLIMIT, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvhoplimit}, - - { -#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) -#if defined(IPV6_RECVPKTINFO) - IPV6_RECVPKTINFO, -#else - IPV6_PKTINFO, -#endif - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvpktinfo}, - - { -#ifdef IPV6_RECVTCLASS - IPV6_RECVTCLASS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_recvtclass}, - - { -#ifdef IPV6_ROUTER_ALERT - IPV6_ROUTER_ALERT, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_router_alert}, - - { -#ifdef IPV6_RTHDR - IPV6_RTHDR, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_rthdr}, - - { -#ifdef IPV6_TCLASS - IPV6_TCLASS, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_tclass}, - - { -#ifdef IPV6_UNICAST_HOPS - IPV6_UNICAST_HOPS, - esock_setopt_hops, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_unicast_hops}, - - {0, NULL, NULL, &esock_atom_use_min_mtu}, - - { -#ifdef IPV6_V6ONLY - IPV6_V6ONLY, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_v6only} - - }; -#endif // #ifdef HAVE_IPV6 - - -/* SCTP_* options ------------------------------------------------------ */ - -#ifdef HAVE_SCTP -static struct ESockOpt optLevelSCTP[] = - { - - {0, NULL, NULL, &esock_atom_adaption_layer}, - - { -#ifdef SCTP_ASSOCINFO - SCTP_ASSOCINFO, - esock_setopt_sctp_associnfo, esock_getopt_sctp_associnfo, -#else - 0, NULL, NULL, -#endif - &esock_atom_associnfo}, - - {0, NULL, NULL, &esock_atom_auth_active_key}, - {0, NULL, NULL, &esock_atom_auth_chunk}, - {0, NULL, NULL, &esock_atom_auth_delete_key}, - {0, NULL, NULL, &esock_atom_auth_key}, - - { -#ifdef SCTP_AUTOCLOSE - SCTP_AUTOCLOSE, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_autoclose}, - - {0, NULL, NULL, &esock_atom_context}, - {0, NULL, NULL, &esock_atom_default_send_params}, - {0, NULL, NULL, &esock_atom_delayed_ack_time}, - - { -#ifdef SCTP_DISABLE_FRAGMENTS - SCTP_DISABLE_FRAGMENTS, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_disable_fragments}, - - {0, NULL, NULL, &esock_atom_hmac_ident}, - - { -#ifdef SCTP_EVENTS - SCTP_EVENTS, - esock_setopt_sctp_events, NULL, -#else - 0, NULL, NULL, -#endif - &esock_atom_events}, - - {0, NULL, NULL, &esock_atom_explicit_eor}, - {0, NULL, NULL, &esock_atom_fragment_interleave}, - {0, NULL, NULL, &esock_atom_get_peer_addr_info}, - - { -#ifdef SCTP_INITMSG - SCTP_INITMSG, - esock_setopt_sctp_initmsg, esock_getopt_sctp_initmsg, -#else - 0, NULL, NULL, -#endif - &esock_atom_initmsg}, - - {0, NULL, NULL, &esock_atom_i_want_mapped_v4_addr}, - {0, NULL, NULL, &esock_atom_local_auth_chunks}, - - { -#ifdef SCTP_MAXSEG - SCTP_MAXSEG, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_maxseg}, - - {0, NULL, NULL, &esock_atom_maxburst}, - - { -#ifdef SCTP_NODELAY - SCTP_NODELAY, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_nodelay}, - - {0, NULL, NULL, &esock_atom_partial_delivery_point}, - {0, NULL, NULL, &esock_atom_peer_addr_params}, - {0, NULL, NULL, &esock_atom_peer_auth_chunks}, - {0, NULL, NULL, &esock_atom_primary_addr}, - {0, NULL, NULL, &esock_atom_reset_streams}, - - { -#ifdef SCTP_RTOINFO - SCTP_RTOINFO, - esock_setopt_sctp_rtoinfo, esock_getopt_sctp_rtoinfo, -#else - 0, NULL, NULL, -#endif - &esock_atom_rtoinfo}, - - {0, NULL, NULL, &esock_atom_set_peer_primary_addr}, - {0, NULL, NULL, &esock_atom_status}, - {0, NULL, NULL, &esock_atom_use_ext_recvinfo} - - }; -#endif // #ifdef HAVE_SCTP - -/* TCP_* options ------------------------------------------------------- */ - -static struct ESockOpt optLevelTCP[] = - { - - { -#ifdef TCP_CONGESTION - TCP_CONGESTION, - esock_setopt_tcp_congestion, esock_getopt_tcp_congestion, -#else - 0, NULL, NULL, -#endif - &esock_atom_congestion}, - - { -#ifdef TCP_CORK - TCP_CORK, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_cork}, - - {0, NULL, NULL, &esock_atom_info}, - {0, NULL, NULL, &esock_atom_keepcnt}, - {0, NULL, NULL, &esock_atom_keepidle}, - {0, NULL, NULL, &esock_atom_keepintvl}, - - { -#ifdef TCP_MAXSEG - TCP_MAXSEG, - esock_setopt_int_opt, esock_getopt_int_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_maxseg}, - - {0, NULL, NULL, &esock_atom_md5sig}, - - { -#ifdef TCP_NODELAY - TCP_NODELAY, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_nodelay}, - - {0, NULL, NULL, &esock_atom_noopt}, - {0, NULL, NULL, &esock_atom_nopush}, - {0, NULL, NULL, &esock_atom_syncnt}, - {0, NULL, NULL, &esock_atom_user_timeout} - - }; - - -/* UDP_* options ------------------------------------------------------- */ - -static struct ESockOpt optLevelUDP[] = - { - - { -#ifdef UDP_CORK - UDP_CORK, - esock_setopt_bool_opt, esock_getopt_bool_opt, -#else - 0, NULL, NULL, -#endif - &esock_atom_cork} - - }; - -/* Option levels table ------------------------------------------------- */ - -struct ESockOptLevel -{ - int level; // Level number - - size_t num; // Number of options - - struct ESockOpt *opts; // Options table -}; - -// qsort and bsearch helper -static int cmpESockOptLevel(const void *vpa, const void *vpb) { - struct ESockOptLevel *a, *b; - a = (struct ESockOptLevel*) vpa; - b = (struct ESockOptLevel*) vpb; - return a->level < b->level ? -1 : (a->level > b->level ? 1 : 0); -} - -#define OPT_LEVEL(Level, Opts) {(Level), NUM(Opts), (Opts)} - -/* Table --------------------------------------------------------------- */ - -static struct ESockOptLevel optLevels[] = - { - OPT_LEVEL(SOL_SOCKET, optLevelSocket), - -#ifdef SOL_IP - OPT_LEVEL(SOL_IP, optLevelIP), -#else - OPT_LEVEL(IPPROTO_IP, optLevelIP), -#endif - -#ifdef HAVE_IPV6 -#ifdef SOL_IPV6 - OPT_LEVEL(SOL_IPV6, optLevelIPV6), -#else - OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6), -#endif -#endif // #ifdef HAVE_IPV6 - -#ifdef HAVE_SCTP - OPT_LEVEL(IPPROTO_SCTP, optLevelSCTP), -#endif // #ifdef HAVE_SCTP - - OPT_LEVEL(IPPROTO_UDP, optLevelUDP), - OPT_LEVEL(IPPROTO_TCP, optLevelTCP) - }; - -#undef OPT_LEVEL - -/* Tables init (sorting) ----------------------------------------------- */ - -#define ESOCK_SORT_TABLE(Array, Cmp) \ - qsort((Array), NUM(Array), sizeof(*(Array)), (Cmp)) - -static void initOpts(void) { - ESOCK_SORT_TABLE(optLevelSocket, cmpESockOpt); - ESOCK_SORT_TABLE(optLevelIP, cmpESockOpt); -#ifdef HAVE_IPV6 - ESOCK_SORT_TABLE(optLevelIPV6, cmpESockOpt); -#endif -#ifdef HAVE_SCTP - ESOCK_SORT_TABLE(optLevelSCTP, cmpESockOpt); -#endif - ESOCK_SORT_TABLE(optLevelTCP, cmpESockOpt); - ESOCK_SORT_TABLE(optLevelUDP, cmpESockOpt); - ESOCK_SORT_TABLE(optLevels, cmpESockOptLevel); -} - -/* Option lookup in tables --------------------------------------------- */ - -static struct ESockOpt *lookupOpt(int level, int opt) { - struct ESockOptLevel levelKey, *levelP; - struct ESockOpt optKey; - - sys_memzero((char *) &levelKey, sizeof(levelKey)); - levelKey.level = level; - levelP = - bsearch(&levelKey, optLevels, NUM(optLevels), sizeof(*optLevels), - cmpESockOptLevel); - if (levelP == NULL) - return NULL; - - sys_memzero((char *) &optKey, sizeof(optKey)); - optKey.opt = opt; - return - bsearch(&optKey, levelP->opts, levelP->num, sizeof(*levelP->opts), - cmpESockOpt); -} - -/* --------------------------------------------------------------------- */ - - - -static BOOLEAN_T send_check_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult); -static ERL_NIF_TERM send_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t send_result, - ssize_t dataSize, - BOOLEAN_T dataInTail, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef); -static ERL_NIF_TERM send_check_ok(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM send_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef); -static void send_error_waiting_writers(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM send_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef); -static BOOLEAN_T recv_check_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult); -static void recv_init_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref); -static void recv_update_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static void recv_error_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM recv_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - int saveErrno, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ErlNifBinary* buf1P, - ErlNifBinary* buf2P, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - ErlNifBinary* bufP, - ESockAddress* fromAddrP, - SOCKLEN_T fromAddrLen, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef); -static ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef); - -static ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env, - ESockDescriptor* descP); -static int esock_close_socket(ErlNifEnv* env, - ESockDescriptor* descP, - BOOLEAN_T unlock); - -static void encode_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM* eSockAddr); -static void encode_cmsgs(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifBinary* cmsgBinP, - struct msghdr* msgHdrP, - ERL_NIF_TERM* eCMsg); -static BOOLEAN_T encode_cmsg(ErlNifEnv* env, - int level, - int type, - unsigned char* dataP, - size_t dataLen, - ERL_NIF_TERM* eType, - ERL_NIF_TERM* eData); -static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* cmsgHdrBufP, - size_t cmsgHdrBufLen, - size_t* cmsgHdrBufUsed); -static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* bufP, - size_t rem, - size_t* used); -static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eValue, - char* dataP, - size_t dataLen, - size_t* dataUsedP); -static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eData, - char* dataP, - size_t dataLen, - size_t* dataUsedP); -static void *init_cmsghdr(struct cmsghdr* cmsgP, - size_t rem, - size_t size, - size_t* usedP); -static void encode_msg_flags(ErlNifEnv* env, - ESockDescriptor* descP, - int msgFlags, - ERL_NIF_TERM* flags); -#if defined(IP_TOS) -static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IP_MTU_DISCOVER) -static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IP_MTU_DISCOVER) -static void encode_ip_pmtudisc(ErlNifEnv* env, - int val, - ERL_NIF_TERM* eVal); -#endif -#if defined(IPV6_MTU_DISCOVER) -static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, - ERL_NIF_TERM eVal, - int* val); -#endif -#if defined(IPV6_MTU_DISCOVER) -static void encode_ipv6_pmtudisc(ErlNifEnv* env, - int val, - ERL_NIF_TERM* eVal); -#endif -#if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) -static -BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val); -#endif - -/* -static BOOLEAN_T decode_bool(ErlNifEnv* env, - ERL_NIF_TERM eVal, - BOOLEAN_T* val); -*/ -// static void encode_bool(BOOLEAN_T val, ERL_NIF_TERM* eVal); -static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val); - -#if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) -static BOOLEAN_T decode_sctp_assoc_t(ErlNifEnv* env, - ERL_NIF_TERM eVal, - sctp_assoc_t* val); -static ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, - sctp_assoc_t val); -#endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) - -static void esock_stop_handle_current(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestor* reqP); -static void inform_waiting_procs(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestQueue* q, - ERL_NIF_TERM reason); - -static int socket_setopt(int sock, - int level, - int opt, - const void* optVal, - const socklen_t optLen); - -static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err); - -static ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event); - - -static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how); -#ifdef HAVE_SETNS -static BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env, - ERL_NIF_TERM opts, - char** netns); -static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err); -static BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err); -#endif - -static BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc); -static void cnt_dec(ESockCounter* cnt, ESockCounter dec); - -static void inc_socket(int domain, int type, int protocol); -static void dec_socket(int domain, int type, int protocol); - - - -/* *** activate_next_acceptor *** - * *** activate_next_writer *** - * *** activate_next_reader *** - * - * All the activate-next functions for acceptor, writer and reader - * have exactly the same API, so we apply some macro magic to simplify. - * They simply operates on dufferent data structures. - * - */ - -#define ACTIVATE_NEXT_FUNCS_DEFS \ - ACTIVATE_NEXT_FUNC_DEF(acceptor) \ - ACTIVATE_NEXT_FUNC_DEF(writer) \ - ACTIVATE_NEXT_FUNC_DEF(reader) - -#define ACTIVATE_NEXT_FUNC_DEF(F) \ - static BOOLEAN_T activate_next_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM sockRef); -ACTIVATE_NEXT_FUNCS_DEFS -#undef ACTIVATE_NEXT_FUNC_DEF - -/* *** acceptor_search4pid | writer_search4pid | reader_search4pid *** - * *** acceptor_push | writer_push | reader_push *** - * *** acceptor_pop | writer_pop | reader_pop *** - * *** acceptor_unqueue | writer_unqueue | reader_unqueue *** - * - * All the queue operator functions (search4pid, push, pop - * and unqueue) for acceptor, writer and reader has exactly - * the same API, so we apply some macro magic to simplify. - */ - -#define ESOCK_OPERATOR_FUNCS_DEFS \ - ESOCK_OPERATOR_FUNCS_DEF(acceptor) \ - ESOCK_OPERATOR_FUNCS_DEF(writer) \ - ESOCK_OPERATOR_FUNCS_DEF(reader) - -#define ESOCK_OPERATOR_FUNCS_DEF(O) \ - static BOOLEAN_T O##_search4pid(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid* pid); \ - static void O##_push(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid pid, \ - ERL_NIF_TERM ref); \ - static BOOLEAN_T O##_pop(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ESockRequestor* reqP); \ - static BOOLEAN_T O##_unqueue(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM* refP, \ - const ErlNifPid* pidP); -ESOCK_OPERATOR_FUNCS_DEFS -#undef ESOCK_OPERATOR_FUNCS_DEF - -static BOOLEAN_T requestor_pop(ESockRequestQueue* q, - ESockRequestor* reqP); - -static void requestor_init(ESockRequestor* reqP); -static void requestor_release(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* reqP); - -static BOOLEAN_T qsearch4pid(ErlNifEnv* env, - ESockRequestQueue* q, - ErlNifPid* pid); -static void qpush(ESockRequestQueue* q, - ESockRequestQueueElement* e); -static ESockRequestQueueElement* qpop(ESockRequestQueue* q); -static BOOLEAN_T qunqueue(ErlNifEnv* env, - ESockDescriptor* descP, - const char* slogan, - ESockRequestQueue* q, - ERL_NIF_TERM* refP, - const ErlNifPid* pidP); - -static int esock_monitor(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pid, - ESockMonitor* mon); -static int esock_demonitor(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockMonitor* monP); -static void esock_monitor_init(ESockMonitor* mon); -static ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, - const ESockMonitor* monP); -static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, - const ErlNifMonitor* mon); - - - -static void esock_down_ctrl(ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pidP); -static void esock_down_acceptor(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); -static void esock_down_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); -static void esock_down_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); - -static void esock_send_reg_add_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); -static void esock_send_reg_del_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef); - -static void esock_send_wrap_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM cnt); -static void esock_send_close_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifPid* pid); -#ifdef HAVE_SENDFILE -static void -esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, - ESockDescriptor* descP); -#endif -static void esock_send_abort_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestor* reqP, - ERL_NIF_TERM reason); -static BOOLEAN_T esock_send_msg(ErlNifEnv* env, - ErlNifPid* pid, - ERL_NIF_TERM msg, - ErlNifEnv* msgEnv); - -static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, - ERL_NIF_TERM tag, - ERL_NIF_TERM sockRef); -static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - ERL_NIF_TERM reason); -static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM cnt); -static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM closeRef); -static ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM tag, - ERL_NIF_TERM info); -static ERL_NIF_TERM mk_socket(ErlNifEnv* env, - ERL_NIF_TERM sockRef); - -static int esock_select_read(ErlNifEnv* env, - ErlNifEvent event, - void* obj, - const ErlNifPid* pidP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static int esock_select_write(ErlNifEnv* env, - ErlNifEvent event, - void* obj, - const ErlNifPid* pidP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM selectRef); -static int esock_select_stop(ErlNifEnv* env, - ErlNifEvent event, - void* obj); -static int esock_select_cancel(ErlNifEnv* env, - ErlNifEvent event, - enum ErlNifSelectFlags mode, - void* obj); - -static char* extract_debug_filename(ErlNifEnv* env, - ERL_NIF_TERM map); - - -/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * * - * * - * End of non-__WIN32__ section a.k.a UNIX section * - * * - * * - * ---------------------------------------------------------------------- */ -#endif // #ifndef __WIN32__ - - -/* -#if defined(HAS_AF_LOCAL) || defined(SO_BINDTODEVICE) -static size_t my_strnlen(const char *s, size_t maxlen); -#endif -*/ - -static void esock_dtor(ErlNifEnv* env, void* obj); -static void esock_stop(ErlNifEnv* env, - void* obj, - ErlNifEvent fd, - int is_direct_call); -static void esock_down(ErlNifEnv* env, - void* obj, - const ErlNifPid* pidP, - const ErlNifMonitor* monP); - -static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); - - - -#if HAVE_IN6 -# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY -# if HAVE_DECL_IN6ADDR_ANY_INIT -static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; -# else -static const struct in6_addr in6addr_any = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; -# endif /* HAVE_IN6ADDR_ANY_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_ANY */ - -# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK -# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT -static const struct in6_addr in6addr_loopback = - { { IN6ADDR_LOOPBACK_INIT } }; -# else -static const struct in6_addr in6addr_loopback = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; -# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ -#endif /* HAVE_IN6 */ - - - -/* *** Global atoms *** - * Note that when an (global) atom is added here, it must also be added - * in the socket_int.h file! - */ -#define GLOBAL_ATOMS \ - GLOBAL_ATOM_DECL(abort); \ - GLOBAL_ATOM_DECL(accept); \ - GLOBAL_ATOM_DECL(acceptconn); \ - GLOBAL_ATOM_DECL(acceptfilter); \ - GLOBAL_ATOM_DECL(adaption_layer); \ - GLOBAL_ATOM_DECL(addr); \ - GLOBAL_ATOM_DECL(addrform); \ - GLOBAL_ATOM_DECL(add_membership); \ - GLOBAL_ATOM_DECL(add_source_membership); \ - GLOBAL_ATOM_DECL(allmulti); \ - GLOBAL_ATOM_DECL(any); \ - GLOBAL_ATOM_DECL(arphrd_dlci); \ - GLOBAL_ATOM_DECL(arphrd_ether); \ - GLOBAL_ATOM_DECL(arphrd_frelay); \ - GLOBAL_ATOM_DECL(arphrd_ieee802); \ - GLOBAL_ATOM_DECL(arphrd_ieee1394); \ - GLOBAL_ATOM_DECL(arphrd_loopback); \ - GLOBAL_ATOM_DECL(arphrd_netrom); \ - GLOBAL_ATOM_DECL(arphrd_none); \ - GLOBAL_ATOM_DECL(associnfo); \ - GLOBAL_ATOM_DECL(authhdr); \ - GLOBAL_ATOM_DECL(auth_active_key); \ - GLOBAL_ATOM_DECL(auth_asconf); \ - GLOBAL_ATOM_DECL(auth_chunk); \ - GLOBAL_ATOM_DECL(auth_delete_key); \ - GLOBAL_ATOM_DECL(auth_key); \ - GLOBAL_ATOM_DECL(auth_level); \ - GLOBAL_ATOM_DECL(autoclose); \ - GLOBAL_ATOM_DECL(automedia); \ - GLOBAL_ATOM_DECL(bad_data); \ - GLOBAL_ATOM_DECL(bindtodevice); \ - GLOBAL_ATOM_DECL(block_source); \ - GLOBAL_ATOM_DECL(broadcast); \ - GLOBAL_ATOM_DECL(busy_poll); \ - GLOBAL_ATOM_DECL(cantconfig); \ - GLOBAL_ATOM_DECL(chaos); \ - GLOBAL_ATOM_DECL(checksum); \ - GLOBAL_ATOM_DECL(close); \ - GLOBAL_ATOM_DECL(cmsg_cloexec); \ - GLOBAL_ATOM_DECL(command); \ - GLOBAL_ATOM_DECL(confirm); \ - GLOBAL_ATOM_DECL(congestion); \ - GLOBAL_ATOM_DECL(connect); \ - GLOBAL_ATOM_DECL(context); \ - GLOBAL_ATOM_DECL(cork); \ - GLOBAL_ATOM_DECL(credentials); \ - GLOBAL_ATOM_DECL(ctrl); \ - GLOBAL_ATOM_DECL(ctrunc); \ - GLOBAL_ATOM_DECL(data); \ - GLOBAL_ATOM_DECL(debug); \ - GLOBAL_ATOM_DECL(default); \ - GLOBAL_ATOM_DECL(default_send_params); \ - GLOBAL_ATOM_DECL(delayed_ack_time); \ - GLOBAL_ATOM_DECL(dgram); \ - GLOBAL_ATOM_DECL(disable_fragments); \ - GLOBAL_ATOM_DECL(domain); \ - GLOBAL_ATOM_DECL(dontfrag); \ - GLOBAL_ATOM_DECL(dontroute); \ - GLOBAL_ATOM_DECL(dormant); \ - GLOBAL_ATOM_DECL(drop_membership); \ - GLOBAL_ATOM_DECL(drop_source_membership); \ - GLOBAL_ATOM_DECL(dstopts); \ - GLOBAL_ATOM_DECL(dying); \ - GLOBAL_ATOM_DECL(dynamic); \ - GLOBAL_ATOM_DECL(echo); \ - GLOBAL_ATOM_DECL(egp); \ - GLOBAL_ATOM_DECL(enotsup); \ - GLOBAL_ATOM_DECL(eor); \ - GLOBAL_ATOM_DECL(error); \ - GLOBAL_ATOM_DECL(errqueue); \ - GLOBAL_ATOM_DECL(esp_network_level); \ - GLOBAL_ATOM_DECL(esp_trans_level); \ - GLOBAL_ATOM_DECL(events); \ - GLOBAL_ATOM_DECL(explicit_eor); \ - GLOBAL_ATOM_DECL(faith); \ - GLOBAL_ATOM_DECL(false); \ - GLOBAL_ATOM_DECL(family); \ - GLOBAL_ATOM_DECL(fastroute); \ - GLOBAL_ATOM_DECL(flags); \ - GLOBAL_ATOM_DECL(flowinfo); \ - GLOBAL_ATOM_DECL(fragment_interleave); \ - GLOBAL_ATOM_DECL(freebind); \ - GLOBAL_ATOM_DECL(get_peer_addr_info); \ - GLOBAL_ATOM_DECL(hatype); \ - GLOBAL_ATOM_DECL(hdrincl); \ - GLOBAL_ATOM_DECL(hmac_ident); \ - GLOBAL_ATOM_DECL(hoplimit); \ - GLOBAL_ATOM_DECL(hopopts); \ - GLOBAL_ATOM_DECL(host); \ - GLOBAL_ATOM_DECL(icmp); \ - GLOBAL_ATOM_DECL(icmp6); \ - GLOBAL_ATOM_DECL(ifindex); \ - GLOBAL_ATOM_DECL(igmp); \ - GLOBAL_ATOM_DECL(implink); \ - GLOBAL_ATOM_DECL(inet); \ - GLOBAL_ATOM_DECL(inet6); \ - GLOBAL_ATOM_DECL(info); \ - GLOBAL_ATOM_DECL(initmsg); \ - GLOBAL_ATOM_DECL(invalid); \ - GLOBAL_ATOM_DECL(integer_range); \ - GLOBAL_ATOM_DECL(iov); \ - GLOBAL_ATOM_DECL(ip); \ - GLOBAL_ATOM_DECL(ipcomp_level); \ - GLOBAL_ATOM_DECL(ipip); \ - GLOBAL_ATOM_DECL(ipv6); \ - GLOBAL_ATOM_DECL(i_want_mapped_v4_addr); \ - GLOBAL_ATOM_DECL(join_group); \ - GLOBAL_ATOM_DECL(keepalive); \ - GLOBAL_ATOM_DECL(keepcnt); \ - GLOBAL_ATOM_DECL(keepidle); \ - GLOBAL_ATOM_DECL(keepintvl); \ - GLOBAL_ATOM_DECL(kernel); \ - GLOBAL_ATOM_DECL(knowsepoch); \ - GLOBAL_ATOM_DECL(leave_group); \ - GLOBAL_ATOM_DECL(level); \ - GLOBAL_ATOM_DECL(linger); \ - GLOBAL_ATOM_DECL(link); \ - GLOBAL_ATOM_DECL(link0); \ - GLOBAL_ATOM_DECL(link1); \ - GLOBAL_ATOM_DECL(link2); \ - GLOBAL_ATOM_DECL(local); \ - GLOBAL_ATOM_DECL(local_auth_chunks); \ - GLOBAL_ATOM_DECL(loopback); \ - GLOBAL_ATOM_DECL(lowdelay); \ - GLOBAL_ATOM_DECL(lower_up); \ - GLOBAL_ATOM_DECL(mark); \ - GLOBAL_ATOM_DECL(master); \ - GLOBAL_ATOM_DECL(maxburst); \ - GLOBAL_ATOM_DECL(maxseg); \ - GLOBAL_ATOM_DECL(md5sig); \ - GLOBAL_ATOM_DECL(mincost); \ - GLOBAL_ATOM_DECL(minttl); \ - GLOBAL_ATOM_DECL(monitor); \ - GLOBAL_ATOM_DECL(more); \ - GLOBAL_ATOM_DECL(msfilter); \ - GLOBAL_ATOM_DECL(mtu); \ - GLOBAL_ATOM_DECL(mtu_discover); \ - GLOBAL_ATOM_DECL(multicast); \ - GLOBAL_ATOM_DECL(multicast_all); \ - GLOBAL_ATOM_DECL(multicast_hops); \ - GLOBAL_ATOM_DECL(multicast_if); \ - GLOBAL_ATOM_DECL(multicast_loop); \ - GLOBAL_ATOM_DECL(multicast_ttl); \ - GLOBAL_ATOM_DECL(name); \ - GLOBAL_ATOM_DECL(noarp); \ - GLOBAL_ATOM_DECL(nodelay); \ - GLOBAL_ATOM_DECL(nodefrag); \ - GLOBAL_ATOM_DECL(nogroup); \ - GLOBAL_ATOM_DECL(none); \ - GLOBAL_ATOM_DECL(noopt); \ - GLOBAL_ATOM_DECL(nopush); \ - GLOBAL_ATOM_DECL(nosignal); \ - GLOBAL_ATOM_DECL(notrailers); \ - GLOBAL_ATOM_DECL(not_found); \ - GLOBAL_ATOM_DECL(not_owner); \ - GLOBAL_ATOM_DECL(oactive); \ - GLOBAL_ATOM_DECL(ok); \ - GLOBAL_ATOM_DECL(oob); \ - GLOBAL_ATOM_DECL(oobinline); \ - GLOBAL_ATOM_DECL(options); \ - GLOBAL_ATOM_DECL(origdstaddr); \ - GLOBAL_ATOM_DECL(otherhost); \ - GLOBAL_ATOM_DECL(outgoing); \ - GLOBAL_ATOM_DECL(packet); \ - GLOBAL_ATOM_DECL(partial_delivery_point); \ - GLOBAL_ATOM_DECL(passcred); \ - GLOBAL_ATOM_DECL(path); \ - GLOBAL_ATOM_DECL(peek); \ - GLOBAL_ATOM_DECL(peek_off); \ - GLOBAL_ATOM_DECL(peer_addr_params); \ - GLOBAL_ATOM_DECL(peer_auth_chunks); \ - GLOBAL_ATOM_DECL(peercred); \ - GLOBAL_ATOM_DECL(pktinfo); \ - GLOBAL_ATOM_DECL(pktoptions); \ - GLOBAL_ATOM_DECL(pkttype); \ - GLOBAL_ATOM_DECL(pointopoint); \ - GLOBAL_ATOM_DECL(port); \ - GLOBAL_ATOM_DECL(portrange); \ - GLOBAL_ATOM_DECL(portsel); \ - GLOBAL_ATOM_DECL(ppromisc); \ - GLOBAL_ATOM_DECL(primary_addr); \ - GLOBAL_ATOM_DECL(priority); \ - GLOBAL_ATOM_DECL(promisc); \ - GLOBAL_ATOM_DECL(protocol); \ - GLOBAL_ATOM_DECL(pup); \ - GLOBAL_ATOM_DECL(raw); \ - GLOBAL_ATOM_DECL(rcvbuf); \ - GLOBAL_ATOM_DECL(rcvbufforce); \ - GLOBAL_ATOM_DECL(rcvlowat); \ - GLOBAL_ATOM_DECL(rcvtimeo); \ - GLOBAL_ATOM_DECL(rdm); \ - GLOBAL_ATOM_DECL(recv); \ - GLOBAL_ATOM_DECL(recvdstaddr); \ - GLOBAL_ATOM_DECL(recverr); \ - GLOBAL_ATOM_DECL(recvfrom); \ - GLOBAL_ATOM_DECL(recvhoplimit); \ - GLOBAL_ATOM_DECL(recvif); \ - GLOBAL_ATOM_DECL(recvmsg); \ - GLOBAL_ATOM_DECL(recvopts); \ - GLOBAL_ATOM_DECL(recvorigdstaddr); \ - GLOBAL_ATOM_DECL(recvpktinfo); \ - GLOBAL_ATOM_DECL(recvtclass); \ - GLOBAL_ATOM_DECL(recvtos); \ - GLOBAL_ATOM_DECL(recvttl); \ - GLOBAL_ATOM_DECL(reliability); \ - GLOBAL_ATOM_DECL(renaming); \ - GLOBAL_ATOM_DECL(reset_streams); \ - GLOBAL_ATOM_DECL(retopts); \ - GLOBAL_ATOM_DECL(reuseaddr); \ - GLOBAL_ATOM_DECL(reuseport); \ - GLOBAL_ATOM_DECL(rights); \ - GLOBAL_ATOM_DECL(router_alert); \ - GLOBAL_ATOM_DECL(rthdr); \ - GLOBAL_ATOM_DECL(rtoinfo); \ - GLOBAL_ATOM_DECL(running); \ - GLOBAL_ATOM_DECL(rxq_ovfl); \ - GLOBAL_ATOM_DECL(scope_id); \ - GLOBAL_ATOM_DECL(sctp); \ - GLOBAL_ATOM_DECL(sec); \ - GLOBAL_ATOM_DECL(select_failed); \ - GLOBAL_ATOM_DECL(select_sent); \ - GLOBAL_ATOM_DECL(send); \ - GLOBAL_ATOM_DECL(sendmsg); \ - GLOBAL_ATOM_DECL(sendsrcaddr); \ - GLOBAL_ATOM_DECL(sendto); \ - GLOBAL_ATOM_DECL(seqpacket); \ - GLOBAL_ATOM_DECL(setfib); \ - GLOBAL_ATOM_DECL(set_peer_primary_addr); \ - GLOBAL_ATOM_DECL(simplex); \ - GLOBAL_ATOM_DECL(slave); \ - GLOBAL_ATOM_DECL(sndbuf); \ - GLOBAL_ATOM_DECL(sndbufforce); \ - GLOBAL_ATOM_DECL(sndlowat); \ - GLOBAL_ATOM_DECL(sndtimeo); \ - GLOBAL_ATOM_DECL(socket); \ - GLOBAL_ATOM_DECL(spec_dst); \ - GLOBAL_ATOM_DECL(staticarp); \ - GLOBAL_ATOM_DECL(status); \ - GLOBAL_ATOM_DECL(stream); \ - GLOBAL_ATOM_DECL(syncnt); \ - GLOBAL_ATOM_DECL(tclass); \ - GLOBAL_ATOM_DECL(tcp); \ - GLOBAL_ATOM_DECL(throughput); \ - GLOBAL_ATOM_DECL(timestamp); \ - GLOBAL_ATOM_DECL(tos); \ - GLOBAL_ATOM_DECL(transparent); \ - GLOBAL_ATOM_DECL(true); \ - GLOBAL_ATOM_DECL(trunc); \ - GLOBAL_ATOM_DECL(ttl); \ - GLOBAL_ATOM_DECL(type); \ - GLOBAL_ATOM_DECL(udp); \ - GLOBAL_ATOM_DECL(unblock_source); \ - GLOBAL_ATOM_DECL(undefined); \ - GLOBAL_ATOM_DECL(unicast_hops); \ - GLOBAL_ATOM_DECL(unspec); \ - GLOBAL_ATOM_DECL(up); \ - GLOBAL_ATOM_DECL(usec); \ - GLOBAL_ATOM_DECL(user); \ - GLOBAL_ATOM_DECL(user_timeout); \ - GLOBAL_ATOM_DECL(use_ext_recvinfo); \ - GLOBAL_ATOM_DECL(use_min_mtu); \ - GLOBAL_ATOM_DECL(v6only) - - -/* *** Global error reason atoms *** */ -#define GLOBAL_ERROR_REASON_ATOMS \ - GLOBAL_ATOM_DECL(eagain); \ - GLOBAL_ATOM_DECL(einval) - - -#define GLOBAL_ATOM_DECL(A) ERL_NIF_TERM esock_atom_##A -GLOBAL_ATOMS; -GLOBAL_ERROR_REASON_ATOMS; -#undef GLOBAL_ATOM_DECL -ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket') - -/* *** Local atoms *** */ -#define LOCAL_ATOMS \ - LOCAL_ATOM_DECL(accepting); \ - LOCAL_ATOM_DECL(acc_success); \ - LOCAL_ATOM_DECL(acc_fails); \ - LOCAL_ATOM_DECL(acc_tries); \ - LOCAL_ATOM_DECL(acc_waits); \ - LOCAL_ATOM_DECL(adaptation_layer); \ - LOCAL_ATOM_DECL(add); \ - LOCAL_ATOM_DECL(addr_unreach); \ - LOCAL_ATOM_DECL(address); \ - LOCAL_ATOM_DECL(adm_prohibited); \ - LOCAL_ATOM_DECL(already); \ - LOCAL_ATOM_DECL(association); \ - LOCAL_ATOM_DECL(assoc_id); \ - LOCAL_ATOM_DECL(authentication); \ - LOCAL_ATOM_DECL(base_addr); \ - LOCAL_ATOM_DECL(boolean); \ - LOCAL_ATOM_DECL(bound); \ - LOCAL_ATOM_DECL(bufsz); \ - LOCAL_ATOM_DECL(close); \ - LOCAL_ATOM_DECL(closed); \ - LOCAL_ATOM_DECL(closing); \ - LOCAL_ATOM_DECL(code); \ - LOCAL_ATOM_DECL(connected); \ - LOCAL_ATOM_DECL(connecting); \ - LOCAL_ATOM_DECL(cookie_life); \ - LOCAL_ATOM_DECL(counter_wrap); \ - LOCAL_ATOM_DECL(counters); \ - LOCAL_ATOM_DECL(ctype); \ - LOCAL_ATOM_DECL(data_io); \ - LOCAL_ATOM_DECL(data_size); \ - LOCAL_ATOM_DECL(debug_filename); \ - LOCAL_ATOM_DECL(del); \ - LOCAL_ATOM_DECL(dest_unreach); \ - LOCAL_ATOM_DECL(dma); \ - LOCAL_ATOM_DECL(do); \ - LOCAL_ATOM_DECL(dont); \ - LOCAL_ATOM_DECL(dtor); \ - LOCAL_ATOM_DECL(dup); \ - LOCAL_ATOM_DECL(efile); \ - LOCAL_ATOM_DECL(exclude); \ - LOCAL_ATOM_DECL(false); \ - LOCAL_ATOM_DECL(frag_needed); \ - LOCAL_ATOM_DECL(gifaddr); \ - LOCAL_ATOM_DECL(gifbrdaddr); \ - LOCAL_ATOM_DECL(gifconf); \ - LOCAL_ATOM_DECL(gifdstaddr); \ - LOCAL_ATOM_DECL(gifflags); \ - LOCAL_ATOM_DECL(gifhwaddr); \ - LOCAL_ATOM_DECL(gifindex); \ - LOCAL_ATOM_DECL(gifmap); \ - LOCAL_ATOM_DECL(gifmtu); \ - LOCAL_ATOM_DECL(gifname); \ - LOCAL_ATOM_DECL(gifnetmask); \ - LOCAL_ATOM_DECL(giftxqlen); \ - LOCAL_ATOM_DECL(host_unknown); \ - LOCAL_ATOM_DECL(host_unreach); \ - LOCAL_ATOM_DECL(how); \ - LOCAL_ATOM_DECL(in4_sockaddr); \ - LOCAL_ATOM_DECL(in6_sockaddr); \ - LOCAL_ATOM_DECL(include); \ - LOCAL_ATOM_DECL(initial); \ - LOCAL_ATOM_DECL(interface); \ - LOCAL_ATOM_DECL(integer); \ - LOCAL_ATOM_DECL(ioctl_flags); \ - LOCAL_ATOM_DECL(ioctl_requests); \ - LOCAL_ATOM_DECL(iov_max); \ - LOCAL_ATOM_DECL(iow); \ - LOCAL_ATOM_DECL(irq); \ - LOCAL_ATOM_DECL(listening); \ - LOCAL_ATOM_DECL(local_rwnd); \ - LOCAL_ATOM_DECL(map); \ - LOCAL_ATOM_DECL(max); \ - LOCAL_ATOM_DECL(max_attempts); \ - LOCAL_ATOM_DECL(max_init_timeo); \ - LOCAL_ATOM_DECL(max_instreams); \ - LOCAL_ATOM_DECL(asocmaxrxt); \ - LOCAL_ATOM_DECL(mem_end); \ - LOCAL_ATOM_DECL(mem_start); \ - LOCAL_ATOM_DECL(min); \ - LOCAL_ATOM_DECL(missing); \ - LOCAL_ATOM_DECL(mode); \ - LOCAL_ATOM_DECL(msg); \ - LOCAL_ATOM_DECL(msg_flags); \ - LOCAL_ATOM_DECL(mtu); \ - LOCAL_ATOM_DECL(multiaddr); \ - LOCAL_ATOM_DECL(net_unknown); \ - LOCAL_ATOM_DECL(net_unreach); \ - LOCAL_ATOM_DECL(netns); \ - LOCAL_ATOM_DECL(nogroup); \ - LOCAL_ATOM_DECL(none); \ - LOCAL_ATOM_DECL(noroute); \ - LOCAL_ATOM_DECL(not_neighbour); \ - LOCAL_ATOM_DECL(null); \ - LOCAL_ATOM_DECL(num_acceptors); \ - LOCAL_ATOM_DECL(num_cnt_bits); \ - LOCAL_ATOM_DECL(num_dinet); \ - LOCAL_ATOM_DECL(num_dinet6); \ - LOCAL_ATOM_DECL(num_dlocal); \ - LOCAL_ATOM_DECL(num_outstreams); \ - LOCAL_ATOM_DECL(number_peer_destinations); \ - LOCAL_ATOM_DECL(num_pip); \ - LOCAL_ATOM_DECL(num_psctp); \ - LOCAL_ATOM_DECL(num_ptcp); \ - LOCAL_ATOM_DECL(num_pudp); \ - LOCAL_ATOM_DECL(num_readers); \ - LOCAL_ATOM_DECL(num_sockets); \ - LOCAL_ATOM_DECL(num_tdgrams); \ - LOCAL_ATOM_DECL(num_tseqpkgs); \ - LOCAL_ATOM_DECL(num_tstreams); \ - LOCAL_ATOM_DECL(num_writers); \ - LOCAL_ATOM_DECL(offender); \ - LOCAL_ATOM_DECL(onoff); \ - LOCAL_ATOM_DECL(options); \ - LOCAL_ATOM_DECL(origin); \ - LOCAL_ATOM_DECL(otp); \ - LOCAL_ATOM_DECL(otp_socket_option);\ - LOCAL_ATOM_DECL(owner); \ - LOCAL_ATOM_DECL(partial_delivery); \ - LOCAL_ATOM_DECL(peer_error); \ - LOCAL_ATOM_DECL(peer_rwnd); \ - LOCAL_ATOM_DECL(pkt_toobig); \ - LOCAL_ATOM_DECL(policy_fail); \ - LOCAL_ATOM_DECL(port); \ - LOCAL_ATOM_DECL(port_unreach); \ - LOCAL_ATOM_DECL(prim_file); \ - LOCAL_ATOM_DECL(probe); \ - LOCAL_ATOM_DECL(protocols); \ - LOCAL_ATOM_DECL(rcvctrlbuf); \ - LOCAL_ATOM_DECL(read); \ - LOCAL_ATOM_DECL(read_byte); \ - LOCAL_ATOM_DECL(read_fails); \ - LOCAL_ATOM_DECL(read_pkg); \ - LOCAL_ATOM_DECL(read_pkg_max); \ - LOCAL_ATOM_DECL(read_tries); \ - LOCAL_ATOM_DECL(read_waits); \ - LOCAL_ATOM_DECL(read_write); \ - LOCAL_ATOM_DECL(registry); \ - LOCAL_ATOM_DECL(reject_route); \ - LOCAL_ATOM_DECL(remote); \ - LOCAL_ATOM_DECL(rstates); \ - LOCAL_ATOM_DECL(select); \ - LOCAL_ATOM_DECL(selected); \ - LOCAL_ATOM_DECL(sender_dry); \ - LOCAL_ATOM_DECL(send_failure); \ - LOCAL_ATOM_DECL(sendfile); \ - LOCAL_ATOM_DECL(sendfile_byte); \ - LOCAL_ATOM_DECL(sendfile_deferred_close); \ - LOCAL_ATOM_DECL(sendfile_fails); \ - LOCAL_ATOM_DECL(sendfile_max); \ - LOCAL_ATOM_DECL(sendfile_pkg); \ - LOCAL_ATOM_DECL(sendfile_pkg_max); \ - LOCAL_ATOM_DECL(sendfile_tries); \ - LOCAL_ATOM_DECL(sendfile_waits); \ - LOCAL_ATOM_DECL(shutdown); \ - LOCAL_ATOM_DECL(sifaddr); \ - LOCAL_ATOM_DECL(sifbrdaddr); \ - LOCAL_ATOM_DECL(sifdstaddr); \ - LOCAL_ATOM_DECL(sifflags); \ - LOCAL_ATOM_DECL(sifmtu); \ - LOCAL_ATOM_DECL(sifnetmask); \ - LOCAL_ATOM_DECL(siftxqlen); \ - LOCAL_ATOM_DECL(slist); \ - LOCAL_ATOM_DECL(sndctrlbuf); \ - LOCAL_ATOM_DECL(sockaddr); \ - LOCAL_ATOM_DECL(socket_debug); \ - LOCAL_ATOM_DECL(socket_level); \ - LOCAL_ATOM_DECL(socket_option); \ - LOCAL_ATOM_DECL(sourceaddr); \ - LOCAL_ATOM_DECL(state); \ - LOCAL_ATOM_DECL(time_exceeded); \ - LOCAL_ATOM_DECL(timeout); \ - LOCAL_ATOM_DECL(true); \ - LOCAL_ATOM_DECL(txqlen); \ - LOCAL_ATOM_DECL(txstatus); \ - LOCAL_ATOM_DECL(txtime); \ - LOCAL_ATOM_DECL(use_registry); \ - LOCAL_ATOM_DECL(value); \ - LOCAL_ATOM_DECL(want); \ - LOCAL_ATOM_DECL(write); \ - LOCAL_ATOM_DECL(write_byte); \ - LOCAL_ATOM_DECL(write_fails); \ - LOCAL_ATOM_DECL(write_pkg); \ - LOCAL_ATOM_DECL(write_pkg_max); \ - LOCAL_ATOM_DECL(write_tries); \ - LOCAL_ATOM_DECL(write_waits); \ - LOCAL_ATOM_DECL(wstates); \ - LOCAL_ATOM_DECL(zero); \ - LOCAL_ATOM_DECL(zerocopy) - -/* Local error reason atoms */ -#define LOCAL_ERROR_REASON_ATOMS \ - LOCAL_ATOM_DECL(select_read); \ - LOCAL_ATOM_DECL(select_write) - -#define LOCAL_ATOM_DECL(LA) static ERL_NIF_TERM atom_##LA -LOCAL_ATOMS; -LOCAL_ERROR_REASON_ATOMS; -#undef LOCAL_ATOM_DECL - - -/* *** Sockets *** */ -static ErlNifResourceType* esocks; -static ErlNifResourceTypeInit esockInit = { - esock_dtor, - esock_stop, - (ErlNifResourceDown*) esock_down -}; - -// Initiated when the nif is loaded -static ESockData data; - - -/* These two (inline) functions are primarily intended for debugging, - * that is, to make it easy to add debug printouts. - */ -static ESOCK_INLINE void esock_free_env(const char* slogan, ErlNifEnv* env) -{ - SGDBG( ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) ); - // esock_dbg_printf("SOCK ENV", "free - %s: 0x%lX\r\n", slogan, env); - - if (env != NULL) enif_free_env(env); -} - - -static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan) -{ - ErlNifEnv* env; - - ESOCK_ASSERT( (env = enif_alloc_env()) != NULL); - - SGDBG( ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) ); - // esock_dbg_printf("SOCK ENV", "alloc - %s: 0x%lX\r\n", slogan, env); - - return env; -} - - -/* ---------------------------------------------------------------------- - * N I F F u n c t i o n s - * ---------------------------------------------------------------------- - * - * Utility and admin functions: - * ---------------------------- - * nif_info/0 - * nif_command/1 - * nif_supports/1 - * - * The "proper" socket functions: - * ------------------------------ - * nif_open(FD, Extra) - * nif_open(Domain, Type, Protocol, Extra) - * nif_bind(Sock, LocalAddr) - * nif_connect(Sock, SockAddr) - * nif_listen(Sock, Backlog) - * nif_accept(LSock, Ref) - * nif_send(Sock, SendRef, Data, Flags) - * nif_sendto(Sock, SendRef, Data, Dest, Flags) - * nif_sendmsg(Sock, SendRef, Msg, Flags) - * nif_sendfile(Sock, SendRef, Offset, Count, InFileRef) - * nif_sendfile(Sock, SendRef, Offset, Count) - * nif_sendfile(Sock) - * nif_recv(Sock, Length, Flags, RecvRef) - * nif_recvfrom(Sock, RecvRef, BufSz, Flags) - * nif_recvmsg(Sock, RecvRef, BufSz, CtrlSz, Flags) - * nif_close(Sock) - * nif_shutdown(Sock, How) - * nif_sockname(Sock) - * nif_peername(Sock) - * - * And some functions to manipulate and retrieve socket options: - * ------------------------------------------------------------- - * nif_setopt/5 - * nif_getopt/3,4 - * - * And some utility functions: - * ------------------------------------------------------------- - * - * And some socket admin functions: - * ------------------------------------------------------------- - * nif_cancel(Sock, Ref) - */ - - -/* ---------------------------------------------------------------------- - * nif_info - * - * Description: - * This is currently just a placeholder... - */ - -static -ERL_NIF_TERM nif_info(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM info; - ESockDescriptor* descP; - - SGDBG( ("SOCKET", "nif_info -> entry with %d args\r\n", argc) ); - - if (argc == 0) - return esock_global_info(env); - - ESOCK_ASSERT( argc == 1 ); - - if (!ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } - - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - - SSDBG( descP, ("SOCKET", "nif_info(%T) {%d,0x%X} -> get socket info\r\n", - argv[0], descP->sock, - descP->readState | descP->writeState) ); - - info = esock_socket_info(env, descP); - - SSDBG( descP, ("SOCKET", "nif_info(%T) -> get socket info done with" - "\r\n info: %T" - "\r\n", argv[0], info) ); - - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); - - return info; -#endif -} - - -/* - * This function return a property list containing "global" info. - * - * Note that we also include something in the counter list that is not - * actually a counter, the num_cnt_bits. This is the "size" of each counter, - * in number of bits: 16 | 24 | 32 | 48 | 64. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_global_info(ErlNifEnv* env) -{ - ERL_NIF_TERM - numBits, numSockets, numTypeDGrams, numTypeStreams, - numTypeSeqPkgs, numDomLocal, numDomInet, numDomInet6, - numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP, - sockDbg, iovMax, dbg, useReg, iow; - - MLOCK(data.cntMtx); - numBits = MKUI(env, ESOCK_COUNTER_SIZE); - numSockets = MKUI(env, data.numSockets); - numTypeDGrams = MKUI(env, data.numTypeDGrams); - numTypeStreams = MKUI(env, data.numTypeStreams); - numTypeSeqPkgs = MKUI(env, data.numTypeSeqPkgs); - numDomLocal = MKUI(env, data.numDomainLocal); - numDomInet = MKUI(env, data.numDomainInet); - numDomInet6 = MKUI(env, data.numDomainInet6); - numProtoIP = MKUI(env, data.numProtoIP); - numProtoTCP = MKUI(env, data.numProtoTCP); - numProtoUDP = MKUI(env, data.numProtoUDP); - numProtoSCTP = MKUI(env, data.numProtoSCTP); - sockDbg = BOOL2ATOM(data.sockDbg); - MUNLOCK(data.cntMtx); - - iovMax = MKI(env, data.iov_max); - dbg = BOOL2ATOM(data.dbg); - useReg = BOOL2ATOM(data.useReg); - iow = BOOL2ATOM(data.iow); - - { - ERL_NIF_TERM gcntVals[] = - {numBits, - numSockets, - numTypeDGrams, numTypeStreams, numTypeSeqPkgs, - numDomLocal, numDomInet, numDomInet6, - numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP}; - ERL_NIF_TERM gcntKeys[] = - {atom_num_cnt_bits, - atom_num_sockets, - atom_num_tdgrams, atom_num_tstreams, atom_num_tseqpkgs, - atom_num_dlocal, atom_num_dinet, atom_num_dinet6, - atom_num_pip, atom_num_ptcp, atom_num_pudp, atom_num_psctp}; - unsigned int numGCntVals = NUM(gcntVals); - unsigned int numGCntKeys = NUM(gcntKeys); - ERL_NIF_TERM gcnt; - - ESOCK_ASSERT( numGCntKeys == numGCntVals ); - ESOCK_ASSERT( MKMA(env, gcntKeys, gcntVals, numGCntKeys, &gcnt) ); - - { - ERL_NIF_TERM - keys[] = {esock_atom_debug, - atom_socket_debug, - atom_use_registry, - atom_iow, - atom_counters, - atom_iov_max}, - vals[] = {dbg, - sockDbg, - useReg, - iow, - gcnt, - iovMax}, - info; - unsigned int - numKeys = NUM(keys), - numVals = NUM(vals); - - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); - - return info; - } - } -} -#endif // #ifndef __WIN32__ - - -/* - * This function return a property *map*. The properties are: - * domain: The domain of the socket - * type: The type of the socket - * protocol: The protocol of the socket - * owner: Controlling process (owner) of the socket) - * rstates: Socket read state(s) - * wstates: Socket write state(s) - * counters: A list of each socket counter and there current values - * readers: The number of current and waiting readers - * writers: The number of current and waiting writers - * acceptors: The number of current and waiting acceptors - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM domain = esock_socket_info_domain(env, descP); - ERL_NIF_TERM type = esock_socket_info_type(env, descP); - ERL_NIF_TERM protocol = MKI(env, descP->protocol); - ERL_NIF_TERM ctrlPid = MKPID(env, &descP->ctrlPid); - ERL_NIF_TERM rstates = esock_socket_info_state(env, descP->readState); - ERL_NIF_TERM wstates = esock_socket_info_state(env, descP->writeState); - ERL_NIF_TERM ctype = esock_socket_info_ctype(env, descP); - ERL_NIF_TERM counters = esock_socket_info_counters(env, descP); - ERL_NIF_TERM readers = esock_socket_info_readers(env, descP); - ERL_NIF_TERM writers = esock_socket_info_writers(env, descP); - ERL_NIF_TERM acceptors = esock_socket_info_acceptors(env, descP); - - { - ERL_NIF_TERM keys[] - = {esock_atom_domain, - esock_atom_type, - esock_atom_protocol, - atom_owner, - atom_rstates, - atom_wstates, - atom_ctype, - atom_counters, - atom_num_readers, - atom_num_writers, - atom_num_acceptors}; - ERL_NIF_TERM vals[] - = {domain, - type, - protocol, - ctrlPid, - rstates, - wstates, - ctype, - counters, - readers, - writers, - acceptors}; - ERL_NIF_TERM info; - unsigned int numKeys = NUM(keys); - unsigned int numVals = NUM(vals); - - SSDBG( descP, ("SOCKET", "esock_socket_info -> " - "\r\n numKeys: %d" - "\r\n numVals: %d" - "\r\n", numKeys, numVals) ); - - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); - - return info; - } -} -#endif // #ifndef __WIN32__ - - -/* - * Encode the socket domain - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, - ESockDescriptor* descP) -{ - int domain = descP->domain; - ERL_NIF_TERM edomain; - - esock_encode_domain(env, domain, &edomain); - return edomain; -} -#endif // #ifndef __WIN32__ - - -/* - * Encode the socket type - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, - ESockDescriptor* descP) -{ - int type = descP->type; - ERL_NIF_TERM etype; - - esock_encode_type(env, type, &etype); - - return etype; -} -#endif // #ifndef __WIN32__ - - -/* - * Encode the socket "create type" - * That is "show" how this socket was created: - * - * normal | fromfd | {fromfd, integer()} - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM ctype; - - SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> entry with" - "\r\n origFD: %d" - "\r\n closeOnClose: %s" - "\r\n", descP->sock, - descP->origFD, B2S(descP->closeOnClose)) ); - - if (descP->origFD > 0) { - /* Created from other FD */ - if (descP->closeOnClose) { - /* We *have* dup'ed: {fromfd, integer()} */ - ctype = MKT2(env, MKA(env, "fromfd"), MKI(env, descP->origFD)); - } else { - /* We have *not* dup'ed: fromfd */ - ctype = MKA(env, "fromfd"); - } - } else { - /* Normal socket */ - ctype = MKA(env, "normal"); - } - - SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> done:" - "\r\n ctype: %T" - "\r\n", descP->sock, ctype) ); - - return ctype; -} -#endif // #ifndef __WIN32__ - - -/* - * Encode the socket "state" - * That is "show" how this socket was created: - * - * normal | fromfd | {fromfd, integer()} - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, - unsigned int state) -{ - SocketTArray estate = TARRAY_CREATE(10); - ERL_NIF_TERM estateList; - - - if ((state & ESOCK_STATE_BOUND) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> bound" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_bound); - } - - if ((state & ESOCK_STATE_LISTENING) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> listening" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_listening); - } - - if ((state & ESOCK_STATE_ACCEPTING) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> accepting" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_accepting); - } - - if ((state & ESOCK_STATE_CONNECTING) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connecting" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_connecting); - } - - if ((state & ESOCK_STATE_CONNECTED) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connected" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_connected); - } - - if ((state & ESOCK_STATE_SELECTED) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> selected" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_selected); - } - - if ((state & ESOCK_STATE_CLOSING) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closing" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_closing); - } - - if ((state & ESOCK_STATE_CLOSED) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closed" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_closed); - } - - if ((state & ESOCK_STATE_DTOR) != 0) { - /* - SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> dror" - "\r\n", descP->sock) ); - */ - TARRAY_ADD(estate, atom_dtor); - } - - TARRAY_TOLIST(estate, env, &estateList); - - return estateList; -} -#endif // #ifndef __WIN32__ - - -/* - * Collect all counters for a socket. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM keys[] = {atom_read_byte, - atom_read_fails, - atom_read_pkg, - atom_read_pkg_max, - atom_read_tries, - atom_read_waits, - atom_write_byte, - atom_write_fails, - atom_write_pkg, - atom_write_pkg_max, - atom_write_tries, - atom_write_waits, - atom_acc_success, - atom_acc_fails, - atom_acc_tries, - atom_acc_waits}; - unsigned int numKeys = NUM(keys); - ERL_NIF_TERM vals[] = {MKCNT(env, descP->readByteCnt), - MKCNT(env, descP->readFails), - MKCNT(env, descP->readPkgCnt), - MKCNT(env, descP->readPkgMax), - MKCNT(env, descP->readTries), - MKCNT(env, descP->readWaits), - MKCNT(env, descP->writeByteCnt), - MKCNT(env, descP->writeFails), - MKCNT(env, descP->writePkgCnt), - MKCNT(env, descP->writePkgMax), - MKCNT(env, descP->writeTries), - MKCNT(env, descP->writeWaits), - MKCNT(env, descP->accSuccess), - MKCNT(env, descP->accFails), - MKCNT(env, descP->accTries), - MKCNT(env, descP->accWaits)}; - unsigned int numVals = NUM(vals); - ERL_NIF_TERM cnts; - - SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> " - "\r\n numKeys: %d" - "\r\n numVals: %d" - "\r\n", numKeys, numVals) ); - - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &cnts) ); - -#ifdef HAVE_SENDFILE - if (descP->sendfileCountersP != NULL) { - ESockSendfileCounters *cP = descP->sendfileCountersP; - ERL_NIF_TERM m, - sfKeys[] = - {atom_sendfile, - atom_sendfile_byte, - atom_sendfile_fails, - atom_sendfile_max, - atom_sendfile_pkg, - atom_sendfile_pkg_max, - atom_sendfile_tries, - atom_sendfile_waits}, - sfVals[] = - {MKUI(env, cP->cnt), - MKUI(env, cP->byteCnt), - MKUI(env, cP->fails), - MKUI(env, cP->max), - MKUI(env, cP->pkg), - MKUI(env, cP->pkgMax), - MKUI(env, cP->tries), - MKUI(env, cP->waits)}; - size_t n, numSfKeys = NUM(sfKeys); - - ESOCK_ASSERT( numSfKeys == NUM(sfVals) ); - for (n = 0; n < numSfKeys; n++) { - ESOCK_ASSERT( enif_make_map_put(env, cnts, - sfKeys[n], sfVals[n], - &m) ); - cnts = m; - } - } -#endif - - SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> done with" - "\r\n cnts: %T" - "\r\n", cnts) ); - - return cnts; -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_command - * - * Description: - * This function is intended to handle "various" commands. That is, - * commands and operations that are not part of the socket API proper. - * It's a map with two attributes command and (command) data: - * #{command :: atom(), data :: term()} - * - * Currently it handles setting: - * - * Command Data - * ------- ---- - * (global) debug boolean() - * socket_debug boolean() - * use_registry boolean() - * - */ - -static -ERL_NIF_TERM nif_command(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM command, cdata, result; - - ESOCK_ASSERT( argc == 1 ); - - SGDBG( ("SOCKET", "nif_command -> entry with %d args\r\n", argc) ); - - if (! GET_MAP_VAL(env, argv[0], esock_atom_command, &command)) { - SGDBG( ("SOCKET", - "nif_command -> field not found: command\r\n") ); - return enif_make_badarg(env); - } - if (! GET_MAP_VAL(env, argv[0], esock_atom_data, &cdata)) { - SGDBG( ("SOCKET", - "nif_command -> field not found: data\r\n") ); - return enif_make_badarg(env); - } - - SGDBG( ("SOCKET", "nif_command -> " - "\r\n command: %T" - "\r\n cdata: %T" - "\r\n", command, cdata) ); - - result = esock_command(env, command, cdata); - - SGDBG( ("SOCKET", "nif_command -> done with result: " - "\r\n %T" - "\r\n", result) ); - - return result; - -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM -esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) -{ - int cmp; - - SGDBG( ("SOCKET", "esock_command -> entry with %T\r\n", command) ); - - cmp = COMPARE(command, atom_socket_debug); - if (cmp == 0) { - return esock_command_socket_debug(env, cdata); - } else if (cmp < 0) { - if (COMPARE(command, esock_atom_debug) == 0) - return esock_command_debug(env, cdata); - } else { // 0 < cmp - if (COMPARE(command, atom_use_registry) == 0) - return esock_command_use_socket_registry(env, cdata); - } - - SGDBG( ("SOCKET", "esock_command -> invalid command: %T\r\n", - command) ); - - return esock_raise_invalid(env, MKT2(env, esock_atom_command, command)); -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) -{ - ERL_NIF_TERM result; - - /* The data *should* be a boolean() */ - if (esock_decode_bool(cdata, &data.dbg)) - result = esock_atom_ok; - else - result = - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - - return result; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) -{ - BOOLEAN_T dbg; - - /* The data *should* be a boolean() */ - if (! esock_decode_bool(cdata, &dbg)) - return - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - - MLOCK(data.cntMtx); - data.sockDbg = dbg; - MUNLOCK(data.cntMtx); - - return esock_atom_ok;; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, - ERL_NIF_TERM cdata) -{ - BOOLEAN_T useReg = FALSE; - - /* The data *should* be a boolean() */ - if (! esock_decode_bool(cdata, &useReg)) - return - esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - - MLOCK(data.cntMtx); - data.useReg = useReg; - MUNLOCK(data.cntMtx); - - return esock_atom_ok;; -} -#endif - - - - -/* *** esock_socket_info_readers *** - * *** esock_socket_info_writers *** - * *** esock_socket_info_acceptors *** - * - * Calculate how many readers | writers | acceptors we have for this socket. - * Current requestor + any waiting requestors (of the type). - * - */ - -#ifndef __WIN32__ - -#define ESOCK_INFO_REQ_FUNCS \ - ESOCK_INFO_REQ_FUNC_DECL(readers, currentReaderP, readersQ) \ - ESOCK_INFO_REQ_FUNC_DECL(writers, currentWriterP, writersQ) \ - ESOCK_INFO_REQ_FUNC_DECL(acceptors, currentAcceptorP, acceptorsQ) - -#define ESOCK_INFO_REQ_FUNC_DECL(F, CRP, Q) \ - static \ - ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ - ESockDescriptor* descP) \ - { \ - return socket_info_reqs(env, descP, descP->CRP, &descP->Q); \ - } -ESOCK_INFO_REQ_FUNCS -#undef ESOCK_INFO_REQ_FUNC_DECL - -static -ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* currentRequestorP, - ESockRequestQueue* q) -{ - ESockRequestQueueElement* tmp; - ERL_NIF_TERM info; - unsigned int cnt = 0; - - if (currentRequestorP != NULL) { - // We have an active requestor! - cnt++; - - // And add all the waiting requestors - tmp = q->first; - while (tmp != NULL) { - cnt++; - tmp = tmp->nextP; - } - } - - info = MKUI(env, cnt); - - SSDBG( descP, ("SOCKET", "socket_info_reqs -> done with" - "\r\n info: %T" - "\r\n", info) ); - - return info; -} - -#endif // #ifndef __WIN32__ - - -/* ---------------------------------------------------------------------- - * nif_supports - * - * Description: - * This function is intended to answer the question: "Is X supported?" - * Currently three keys are "supported": options | sctp | ipv6 - * That results in a list of all *known options* (known by us) and if - * the platform supports (OS) it or not. - * - * Key - * --- - * (arity 0) [{sctp, boolean()}, - * {ipv6, boolean()}, - * {local, boolean()}, - * {netns, boolean()}, - * {sendfile, boolean()}] - * - * msg_flags [{MsgFlag, boolean()}] - * protocols [{[Protocol | Aliases], integer()}], - * options [{socket, [{Opt, boolean()} | Opt]} | - * {ProtoNum::integer(), [{Opt, boolean()} | Opt]}] - */ - -static -ERL_NIF_TERM nif_supports(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - - SGDBG( ("SOCKET", "nif_supports -> entry with %d args\r\n", argc) ); - - /* Extract arguments and perform preliminary validation */ - - if (argc == 0) - return esock_supports_0(env); - - ESOCK_ASSERT( argc == 1 ); - - return esock_supports_1(env, argv[0]); -#endif -} - -/* esock_supports - what features do we support? - * - * This gives information about what features actually - * work on the current platform. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_supports_0(ErlNifEnv* env) -{ - SocketTArray opts = TARRAY_CREATE(8); - ERL_NIF_TERM is_supported, opts_list; - - SGDBG( ("SOCKET", "esock_supports_0 -> entry\r\n") ); - -#if defined(HAVE_SCTP) - is_supported = esock_atom_true; -#else - is_supported = esock_atom_false; -#endif - TARRAY_ADD(opts, MKT2(env, esock_atom_sctp, is_supported)); - - /* Is this (test) really sufficient for testing if we support IPv6? */ -#if defined(HAVE_IPV6) - is_supported = esock_atom_true; -#else - is_supported = esock_atom_false; -#endif - TARRAY_ADD(opts, MKT2(env, esock_atom_ipv6, is_supported)); - -#if defined(AF_LOCAL) - is_supported = esock_atom_true; -#else - is_supported = esock_atom_false; -#endif - TARRAY_ADD(opts, MKT2(env, esock_atom_local, is_supported)); - -#if defined(HAVE_SETNS) - is_supported = esock_atom_true; -#else - is_supported = esock_atom_false; -#endif - TARRAY_ADD(opts, MKT2(env, atom_netns, is_supported)); - -#if defined(HAVE_SENDFILE) - is_supported = esock_atom_true; -#else - is_supported = esock_atom_false; -#endif - TARRAY_ADD(opts, MKT2(env, atom_sendfile, is_supported)); - - TARRAY_TOLIST(opts, env, &opts_list); - return opts_list; -} -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key) -{ - ERL_NIF_TERM result; - - SGDBG( ("SOCKET", - "esock_supports_1 -> entry" - "\r\n key: %T" - "\r\n", key) ); - - if (COMPARE(key, atom_msg_flags) == 0) - result = esock_supports_msg_flags(env); - else if (COMPARE(key, atom_protocols) == 0) - result = esock_supports_protocols(env); - else if (COMPARE(key, atom_ioctl_requests) == 0) - result = esock_supports_ioctl_requests(env); - else if (COMPARE(key, atom_ioctl_flags) == 0) - result = esock_supports_ioctl_flags(env); - else if (COMPARE(key, atom_options) == 0) - result = esock_supports_options(env); - else - result = MKEL(env); - - return result; -} -#endif // #ifndef __WIN32__ - - - -#ifndef __WIN32__ - -static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env) { - size_t n; - ERL_NIF_TERM result; - - result = MKEL(env); - for (n = 0; n < NUM(msg_flags); n++) { - result = - MKC(env, - MKT2(env, - *(msg_flags[n].name), - MKI(env, msg_flags[n].flag)), - result); - } - - return result; -} - -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env) -{ - ERL_NIF_TERM protocols; - - protocols = MKEL(env); - -#if defined(HAVE_GETPROTOENT) && \ - defined(HAVE_SETPROTOENT) && \ - defined(HAVE_ENDPROTOENT) - - { - struct protoent *pe; - int stayopen; - - MLOCK(data.protocolsMtx); - stayopen = TRUE; - setprotoent(stayopen); - while ((pe = getprotoent()) != NULL) { - ERL_NIF_TERM names; - char **aliases; - - names = MKEL(env); - for (aliases = pe->p_aliases; *aliases != NULL; aliases++) - names = MKC(env, MKA(env, *aliases), names); - names = MKC(env, MKA(env, pe->p_name), names); - - protocols = - MKC(env, MKT2(env, names, MKI(env, pe->p_proto)), protocols); - } - endprotoent(); - MUNLOCK(data.protocolsMtx); - } -#endif - - /* Defaults for known protocols in case getprotoent() - * does not work or does not exist. Prepended to the list - * so a subsequent maps:from_list/2 will take the default - * only when there is nothing from getprotoent(). - */ - - protocols = - MKC(env, - MKT2(env, - MKL1(env, esock_atom_ip), - MKI(env, -#ifdef SOL_IP - SOL_IP -#else - IPPROTO_IP -#endif - )), - protocols); - -#ifdef HAVE_IPV6 - protocols = - MKC(env, - MKT2(env, - MKL1(env, esock_atom_ipv6), - MKI(env, -#ifdef SOL_IPV6 - SOL_IPV6 -#else - IPPROTO_IPV6 -#endif - )), - protocols); -#endif - - protocols = - MKC(env, - MKT2(env, MKL1(env, esock_atom_tcp), MKI(env, IPPROTO_TCP)), - protocols); - - protocols = - MKC(env, - MKT2(env, MKL1(env, esock_atom_udp), MKI(env, IPPROTO_UDP)), - protocols); - -#ifdef HAVE_SCTP - protocols = - MKC(env, - MKT2(env, MKL1(env, esock_atom_sctp), MKI(env, IPPROTO_SCTP)), - protocols); -#endif - - return protocols; -} -#endif // #ifndef __WIN32__ - - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env) -{ - ERL_NIF_TERM requests; - - requests = MKEL(env); - - /* --- GET REQUESTS --- */ -#if defined(SIOCGIFNAME) - requests = MKC(env, MKT2(env, atom_gifname, MKUL(env, SIOCGIFNAME)), requests); -#endif - -#if defined(SIOCGIFINDEX) - requests = MKC(env, MKT2(env, atom_gifindex, MKUL(env, SIOCGIFINDEX)), requests); -#endif - -#if defined(SIOCGIFFLAGS) - requests = MKC(env, MKT2(env, atom_gifflags, MKUL(env, SIOCGIFFLAGS)), requests); -#endif - -#if defined(SIOCGIFADDR) - requests = MKC(env, MKT2(env, atom_gifaddr, MKUL(env, SIOCGIFADDR)), requests); -#endif - -#if defined(SIOCGIFDSTADDR) - requests = MKC(env, MKT2(env, atom_gifdstaddr, MKUL(env, SIOCGIFDSTADDR)), requests); -#endif - -#if defined(SIOCGIFBRDADDR) - requests = MKC(env, MKT2(env, atom_gifbrdaddr, MKUL(env, SIOCGIFBRDADDR)), requests); -#endif - -#if defined(SIOCGIFNETMASK) - requests = MKC(env, MKT2(env, atom_gifnetmask, MKUL(env, SIOCGIFNETMASK)), requests); -#endif - -#if defined(SIOCGIFMTU) - requests = MKC(env, MKT2(env, atom_gifmtu, MKUL(env, SIOCGIFMTU)), requests); -#endif - -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) - requests = MKC(env, MKT2(env, atom_gifhwaddr, MKUL(env, SIOCGIFHWADDR)), requests); -#endif - -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) - requests = MKC(env, MKT2(env, atom_gifmap, MKUL(env, SIOCGIFMAP)), requests); -#endif - -#if defined(SIOCGIFTXQLEN) - requests = MKC(env, MKT2(env, atom_giftxqlen, MKUL(env, SIOCGIFTXQLEN)), requests); -#endif - -#if defined(SIOCGIFCONF) - requests = MKC(env, MKT2(env, atom_gifconf, MKUL(env, SIOCGIFCONF)), requests); -#endif - - /* --- SET REQUESTS --- */ -#if defined(SIOCSIFFLAGS) - requests = MKC(env, MKT2(env, atom_sifflags, MKUL(env, SIOCSIFFLAGS)), requests); -#endif - -#if defined(SIOCSIFADDR) - requests = MKC(env, MKT2(env, atom_sifaddr, MKUL(env, SIOCSIFADDR)), requests); -#endif - -#if defined(SIOCSIFDSTADDR) - requests = MKC(env, MKT2(env, atom_sifdstaddr, MKUL(env, SIOCSIFDSTADDR)), requests); -#endif - -#if defined(SIOCSIFBRDADDR) - requests = MKC(env, MKT2(env, atom_sifbrdaddr, MKUL(env, SIOCSIFBRDADDR)), requests); -#endif - -#if defined(SIOCSIFMTU) - requests = MKC(env, MKT2(env, atom_sifmtu, MKUL(env, SIOCSIFMTU)), requests); -#endif - -#if defined(SIOCSIFTXQLEN) - requests = MKC(env, MKT2(env, atom_siftxqlen, MKUL(env, SIOCSIFTXQLEN)), requests); -#endif - - return requests; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ - -static ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env) -{ - size_t n; - ERL_NIF_TERM result; - - result = MKEL(env); - for (n = 0; n < NUM(ioctl_flags); n++) { - result = - MKC(env, - MKT2(env, - *(ioctl_flags[n].name), - MKI(env, ioctl_flags[n].flag)), - result); - } - - return result; -} - -#endif // #ifndef __WIN32__ - - - - -#ifndef __WIN32__ - -static -ERL_NIF_TERM esock_supports_options(ErlNifEnv* env) -{ - ERL_NIF_TERM levels; - size_t n; - - levels = MKEL(env); - - for (n = 0; n < NUM(optLevels); n++) { - ERL_NIF_TERM options; - size_t m; - struct ESockOptLevel *levelP; - - options = MKEL(env); - levelP = optLevels + n; - for (m = 0; m < levelP->num; m++) { - struct ESockOpt *optP; - - optP = levelP->opts + m; - if (optP->setopt == NULL && optP->getopt == NULL) { - options = MKC(env, *optP->nameP, options); - } else { - options = - MKC(env, - MKT2(env, *optP->nameP, MKI(env, optP->opt)), - options); - } - } - levels = - MKC(env, - MKT2(env, - esock_encode_level(env, levelP->level), options), - levels); - } - - return levels; -} - -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_open - * - * Description: - * Create an endpoint for communication. - * This function "exist" in two variants. - * One with two args and onewith four. - * - * Arguments (2): - * FD - File Descriptor (of an already open socket). - * Extra - A map with extra options. - * The options are: - * [M] dup - boolean() - Shall the fd be dup'ed or not. - * [O] bound - boolean() - Is the fd already bound. - * [O] domain - domain() - We may not be able to retrieve - * this on all platforms, and in - * *those* cases this *must* be - * provided. - * [O] type - type() - We may not be able to retrieve - * this on all platforms, and in - * *those* cases this *must* be - * provided. - * [O] proto - protocol() - We may not be able to retrieve - * this on all platforms, and in - * *those* cases this *must* be - * provided. - * [O] use_registry - boolean() - Shall we use the socket - * registry for this socket. - * Arguments (4): - * Domain - The domain, for example 'inet' - * Type - Type of socket, for example 'stream' - * Protocol - The protocol, for example 'tcp' - * Extra - A map with "obscure" options. - * Currently the only allowed option are: - * netns - string() - Network namespace. *Only* - * allowed on linux! - * use_registry - boolean() - Shall we use the socket - * registry for this socket. - * - */ -static -ERL_NIF_TERM nif_open(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result; - - SGDBG( ("SOCKET", "nif_open -> " - "\r\n argc: %d" - "\r\n", argc) ); - - if (argc == 2) { - int fd; - ERL_NIF_TERM eopts; - - if (! GET_INT(env, argv[0], &fd)) { - if (IS_INTEGER(env, argv[0])) - return esock_make_error_integer_range(env, argv[0]); - else - return enif_make_badarg(env); - } - if (! IS_MAP(env, argv[1])) { - return enif_make_badarg(env); - } - eopts = argv[1]; - - SGDBG( ("SOCKET", "nif_open -> " - "\r\n FD: %d" - "\r\n eopts: %T" - "\r\n", fd, eopts) ); - - MLOCK(data.cntMtx); - result = esock_open2(env, fd, eopts); - MUNLOCK(data.cntMtx); - - } else { - ERL_NIF_TERM edomain, etype, eopts; - int domain, type, proto; - - ESOCK_ASSERT( argc == 4 ); - - /* Extract arguments and perform preliminary validation */ - - if (! GET_INT(env, argv[2], &proto)) { - if (IS_INTEGER(env, argv[2])) - return esock_make_error_integer_range(env, argv[2]); - else - return enif_make_badarg(env); - } - if (! IS_MAP(env, argv[3])) { - return enif_make_badarg(env); - } - edomain = argv[0]; - etype = argv[1]; - eopts = argv[3]; - - SGDBG( ("SOCKET", "nif_open -> " - "\r\n edomain: %T" - "\r\n etype: %T" - "\r\n proto: %T" - "\r\n eopts: %T" - "\r\n", argv[0], argv[1], argv[2], eopts) ); - - if (esock_decode_domain(env, edomain, &domain) == 0) { - SGDBG( ("SOCKET", - "nif_open -> invalid domain: %d\r\n", edomain) ); - return esock_make_invalid(env, esock_atom_domain); - } - - if (! esock_decode_type(env, etype, &type)) { - SGDBG( ("SOCKET", - "nif_open -> invalid type: %d\r\n", etype) ); - return esock_make_invalid(env, esock_atom_type); - } - - MLOCK(data.cntMtx); - result = esock_open4(env, domain, type, proto, eopts); - MUNLOCK(data.cntMtx); - } - - SGDBG( ("SOCKET", "nif_open -> done with result: " - "\r\n %T" - "\r\n", result) ); - - return result; - -#endif // #ifdef __WIN32__ #else -} - - -/* esock_open - create an endpoint (from an existing fd) for communication - * - * Assumes the input has been validated. - * - * Normally we want debugging on (individual) sockets to be controlled - * by the sockets own debug flag. But since we don't even have a socket - * yet, we must use the global debug flag. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_open2(ErlNifEnv* env, - int fd, - ERL_NIF_TERM eopts) -{ - BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg); - BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg); - ESockDescriptor* descP; - ERL_NIF_TERM sockRef; - int domain, type, protocol; - int save_errno = 0; - BOOLEAN_T closeOnClose; - SOCKET sock; - ErlNifEvent event; - ErlNifPid self; - - /* Keep track of the creator - * This should not be a problem, but just in case - * the *open* function is used with the wrong kind - * of environment... - */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> entry with" - "\r\n fd: %d" - "\r\n eopts: %T" - "\r\n", fd, eopts) ); - - /* - * Before we do anything else, we try to retrieve domain, type and protocol - * This information is either present in the eopts map or if not we need - * to "get" it from the system (getsockopt). - * Note that its not possible to get all of these on all platoforms, - * and in those cases the user *must* provide us with them (eopts). - * - * We try the system first (since its more reliable) and if that fails - * we check the eopts map. If neither one works, we *give up*! - */ - - if (! esock_open_which_domain(fd, &domain)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> failed get domain from system\r\n") ); - - if (! esock_open2_get_domain(env, eopts, &domain)) { - return esock_make_invalid(env, esock_atom_domain); - } - } - - if (! esock_open_which_type(fd, &type)) { - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> failed get type from system\r\n") ); - - if (! esock_open2_get_type(env, eopts, &type)) - return esock_make_invalid(env, esock_atom_type); - } - - if (! esock_open_which_protocol(fd, &protocol)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> failed get protocol from system\r\n") ); - - if (! esock_extract_int_from_map(env, eopts, - esock_atom_protocol, &protocol)) { - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> trying protocol 0\r\n") ); - protocol = 0; - } - } - - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> " - "\r\n domain: %d" - "\r\n type: %d" - "\r\n protocol: %d" - "\r\n", domain, type, protocol) ); - - - if (esock_open2_todup(env, eopts)) { - /* We shall dup the socket */ - if (ESOCK_IS_ERROR(sock = dup(fd))) { - save_errno = sock_errno(); - - SSDBG2( dbg, - ("SOCKET", - "esock_open2 -> dup failed: %d\r\n", - save_errno) ); - - return esock_make_error_errno(env, save_errno); - } - closeOnClose = TRUE; - } else { - sock = fd; - closeOnClose = FALSE; - } - - event = sock; - - SET_NONBLOCKING(sock); - - /* Create and initiate the socket "descriptor" */ - descP = alloc_descriptor(sock, event); - descP->ctrlPid = self; - descP->domain = domain; - descP->type = type; - descP->protocol = protocol; - descP->closeOnClose = closeOnClose; - descP->origFD = fd; - - /* Check if we are already connected, if so change state */ - { - ESockAddress remote; - SOCKLEN_T addrLen = sizeof(remote); - sys_memzero((char *) &remote, addrLen); - if (sock_peer(descP->sock, - (struct sockaddr*) &remote, - &addrLen) == 0) { - SSDBG2( dbg, ("SOCKET", "esock_open2 -> connected\r\n") ); - descP->writeState |= ESOCK_STATE_CONNECTED; - } else { - SSDBG2( dbg, ("SOCKET", "esock_open2 -> not connected\r\n") ); - } - } - - /* And create the 'socket' resource */ - sockRef = enif_make_resource(env, descP); - enif_release_resource(descP); - - ESOCK_ASSERT( MONP("esock_open2 -> ctrl", - env, descP, - &descP->ctrlPid, - &descP->ctrlMon) == 0 ); - - descP->dbg = dbg; - descP->useReg = useReg; - inc_socket(domain, type, protocol); - - /* And finally (maybe) update the registry. - * Shall we keep track of the fact that this socket is created elsewhere? - */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); - - SSDBG2( dbg, - ("SOCKET", "esock_open2 -> done: %T\r\n", sockRef) ); - - return esock_make_ok2(env, sockRef); -} -#endif // #ifndef __WIN32__ - - -/* The eextra contains a boolean 'dup' key. Defaults to TRUE. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_todup(ErlNifEnv* env, ERL_NIF_TERM eextra) -{ - return esock_get_bool_from_map(env, eextra, atom_dup, TRUE); -} -#endif // #ifndef __WIN32__ - -/* The eextra contains an integer 'domain' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env, - ERL_NIF_TERM eopts, int* domain) -{ - ERL_NIF_TERM edomain; - - SGDBG( ("SOCKET", "esock_open2_get_domain -> entry with" - "\r\n eopts: %T" - "\r\n", eopts) ); - - if (!GET_MAP_VAL(env, eopts, - esock_atom_domain, &edomain)) - return FALSE; - - if (esock_decode_domain(env, edomain, domain) == 0) - return FALSE; - - return TRUE; -} -#endif // #ifndef __WIN32__ - -/* The eextra contains an integer 'type' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open2_get_type(ErlNifEnv* env, - ERL_NIF_TERM eopts, int* type) -{ - ERL_NIF_TERM etype; - - SGDBG( ("SOCKET", "esock_open2_get_type -> entry with" - "\r\n eopts: %T" - "\r\n", eopts) ); - - if (! GET_MAP_VAL(env, eopts, esock_atom_type, &etype)) - return FALSE; - - if (! esock_decode_type(env, etype, type)) - return FALSE; - - return TRUE; -} -#endif // #ifndef __WIN32__ - - -/* esock_open4 - create an endpoint for communication - * - * Assumes the input has been validated. - * - * Normally we want debugging on (individual) sockets to be controlled - * by the sockets own debug flag. But since we don't even have a socket - * yet, we must use the global debug flag. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_open4(ErlNifEnv* env, - int domain, - int type, - int protocol, - ERL_NIF_TERM eopts) -{ - BOOLEAN_T dbg = esock_open_is_debug(env, eopts, data.sockDbg); - BOOLEAN_T useReg = esock_open_use_registry(env, eopts, data.useReg); - ESockDescriptor* descP; - ERL_NIF_TERM sockRef; - int proto = protocol, save_errno; - SOCKET sock; - ErlNifEvent event; - char* netns; -#ifdef HAVE_SETNS - int current_ns = 0; -#endif - ErlNifPid self; - - /* Keep track of the creator - * This should not be a problem, but just in case - * the *open* function is used with the wrong kind - * of environment... - */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - SSDBG2( dbg, - ("SOCKET", "esock_open4 -> entry with" - "\r\n domain: %d" - "\r\n type: %d" - "\r\n protocol: %d" - "\r\n eopts: %T" - "\r\n", domain, type, protocol, eopts) ); - - -#ifdef HAVE_SETNS - if (esock_open4_get_netns(env, eopts, &netns)) { - SGDBG( ("SOCKET", "nif_open -> namespace: %s\r\n", netns) ); - } -#else - netns = NULL; -#endif - - -#ifdef HAVE_SETNS - if ((netns != NULL) && - (! change_network_namespace(netns, ¤t_ns, &save_errno))) { - FREE(netns); - return esock_make_error_errno(env, save_errno); - } -#endif - - if (ESOCK_IS_ERROR(sock = sock_open(domain, type, proto))) { - if (netns != NULL) FREE(netns); - return esock_make_error_errno(env, sock_errno()); - } - - SSDBG2( dbg, ("SOCKET", "esock_open -> open success: %d\r\n", sock) ); - - - /* NOTE that if the protocol = 0 (default) and the domain is not - * local (AF_LOCAL) we need to explicitly get the protocol here! - */ - - if (proto == 0) - (void) esock_open_which_protocol(sock, &proto); - -#ifdef HAVE_SETNS - if (netns != NULL) { - FREE(netns); - if (! restore_network_namespace(current_ns, sock, &save_errno)) - return esock_make_error_errno(env, save_errno); - } -#endif - - - if ((event = sock_create_event(sock)) == INVALID_EVENT) { - save_errno = sock_errno(); - (void) sock_close(sock); - return esock_make_error_errno(env, save_errno); - } - - SSDBG2( dbg, ("SOCKET", "esock_open4 -> event success: %d\r\n", event) ); - - SET_NONBLOCKING(sock); - - - /* Create and initiate the socket "descriptor" */ - descP = alloc_descriptor(sock, event); - descP->ctrlPid = self; - descP->domain = domain; - descP->type = type; - descP->protocol = proto; - - sockRef = enif_make_resource(env, descP); - enif_release_resource(descP); - - ESOCK_ASSERT( MONP("esock_open -> ctrl", - env, descP, - &descP->ctrlPid, - &descP->ctrlMon) == 0 ); - - descP->dbg = dbg; - descP->useReg = useReg; - inc_socket(domain, type, protocol); - - /* And finally (maybe) update the registry */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); - - return esock_make_ok2(env, sockRef); -} -#endif // #ifndef __WIN32__ - -/* The eextra map "may" contain a boolean 'debug' key. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, ERL_NIF_TERM eextra, - BOOLEAN_T dflt) -{ - return esock_get_bool_from_map(env, eextra, esock_atom_debug, dflt); -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, ERL_NIF_TERM eextra, - BOOLEAN_T dflt) -{ - return esock_get_bool_from_map(env, eextra, atom_use_registry, dflt); -} -#endif - - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_which_domain(SOCKET sock, int* domain) -{ -#if defined(SO_DOMAIN) - if (esock_getopt_int(sock, SOL_SOCKET, SO_DOMAIN, domain)) - return TRUE; -#endif - return FALSE; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_which_type(SOCKET sock, int* type) -{ -#if defined(SO_TYPE) - if (esock_getopt_int(sock, SOL_SOCKET, SO_TYPE, type)) - return TRUE; -#endif - return FALSE; -} -#endif // #ifndef __WIN32__ - - -#ifndef __WIN32__ -static -BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto) -{ -#if defined(SO_PROTOCOL) - if (esock_getopt_int(sock, SOL_SOCKET, SO_PROTOCOL, proto)) - return TRUE; -#endif - return FALSE; -} -#endif // #ifndef __WIN32__ - - - -#ifdef HAVE_SETNS - - -/* We should really have another API, so that we can return errno... */ - -/* *** change network namespace *** - * Retreive the current namespace and set the new. - * Return result and previous namespace if successfull. - */ -#ifndef __WIN32__ -static -BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err) -{ - int save_errno; - int current_ns = 0; - int new_ns = 0; - - SGDBG( ("SOCKET", "change_network_namespace -> entry with" - "\r\n new ns: %s" - "\r\n", netns) ); - - current_ns = open("/proc/self/ns/net", O_RDONLY); - if (ESOCK_IS_ERROR(current_ns)) { - *err = sock_errno(); - return FALSE; - } - new_ns = open(netns, O_RDONLY); - if (ESOCK_IS_ERROR(new_ns)) { - save_errno = sock_errno(); - (void) close(current_ns); - *err = save_errno; - return FALSE; - } - if (setns(new_ns, CLONE_NEWNET) != 0) { - save_errno = sock_errno(); - (void) close(new_ns); - (void) close(current_ns); - *err = save_errno; - return FALSE; - } else { - (void) close(new_ns); - *cns = current_ns; - return TRUE; - } -} -#endif // #ifndef __WIN32__ - - -/* *** restore network namespace *** - * Restore the previous namespace (see above). - */ -#ifndef __WIN32__ -static -BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err) -{ - SGDBG( ("SOCKET", "restore_network_namespace -> entry with" - "\r\n ns: %d" - "\r\n", ns) ); - - if (setns(ns, CLONE_NEWNET) != 0) { - /* XXX Failed to restore network namespace. - * What to do? Tidy up and return an error... - * Note that the thread now might still be in the namespace. - * Can this even happen? Should the emulator be aborted? - */ - int save_errno = sock_errno(); - (void) close(sock); - (void) close(ns); - *err = save_errno; - return FALSE; - } else { - (void) close(ns); - return TRUE; - } -} -#endif // #ifndef __WIN32__ - - -#endif // ifdef HAVE_SETNS - - - -/* ---------------------------------------------------------------------- - * nif_bind - * - * Description: - * Bind a name to a socket. - * - * Arguments: - * [0] Socket (ref) - Points to the socket descriptor. - * [1] LocalAddr - Local address is a sockaddr map ( socket:sockaddr() ). - */ -static -ERL_NIF_TERM nif_bind(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM eSockAddr, ret; - ESockAddress sockAddr; - SOCKLEN_T addrLen; - - ESOCK_ASSERT( argc == 2 ); - - SGDBG( ("SOCKET", "nif_bind -> entry with argc: %d\r\n", argc) ); - - /* Extract arguments and perform preliminary validation */ - - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } - eSockAddr = argv[1]; - - if (! esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) - return esock_make_invalid(env, atom_sockaddr); - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", "nif_bind(%T) {%d,0x%X} ->" - "\r\n SockAddr: %T" - "\r\n", - argv[0], descP->sock, descP->readState, - eSockAddr) ); - - ret = esock_bind(env, descP, &sockAddr, addrLen); - - SSDBG( descP, ("SOCKET", "nif_bind(%T) -> done with" - "\r\n ret: %T" - "\r\n", argv[0], ret) ); - - MUNLOCK(descP->readMtx); - - return ret; -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_bind(ErlNifEnv* env, - ESockDescriptor* descP, - ESockAddress* sockAddrP, - SOCKLEN_T addrLen) -{ - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - if (sock_bind(descP->sock, &sockAddrP->sa, addrLen) < 0) { - return esock_make_error_errno(env, sock_errno()); - } - - descP->readState |= ESOCK_STATE_BOUND; - - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_connect - * - * Description: - * Initiate a connection on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Optional arguments: - * ConnectRef - Ref for the connection - * SockAddr - Socket Address of "remote" host. - * This is sockaddr(), which is either - * sockaddr_in4 or sockaddr_in6. - */ -static -ERL_NIF_TERM nif_connect(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM res, sockRef, connRef; - ESockAddress addr, *addrP; - SOCKLEN_T addrLen; - - ESOCK_ASSERT( argc >= 1 ); - - SGDBG( ("SOCKET", "nif_connect -> entry with argc: %d\r\n", argc) ); - - /* Extract arguments and perform preliminary validation */ - - sockRef = argv[0]; - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) - return enif_make_badarg(env); - - if (argc == 3) { - ERL_NIF_TERM eSockAddr = argv[2]; - - connRef = argv[1]; - if (! enif_is_ref(env, connRef)) - return enif_make_badarg(env); - - if (! esock_decode_sockaddr(env, eSockAddr, &addr, &addrLen)) - return esock_make_invalid(env, atom_sockaddr); - addrP = &addr; - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_connect(%T), {%d0x%X} ->" - "\r\n ConnRef: %T" - "\r\n SockAddr: %T" - "\r\n", - sockRef, descP->sock, descP->writeState, - connRef, eSockAddr) ); - } else { - - ESOCK_ASSERT( argc == 1 ); - - connRef = esock_atom_undefined; - addrP = NULL; - addrLen = 0; - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_connect(%T), {%d,0x%X} ->" - "\r\n", - sockRef, descP->sock, descP->writeState - ) ); - } - - res = esock_connect(env, descP, sockRef, connRef, addrP, addrLen); - - SSDBG( descP, ("SOCKET", "nif_connect(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->writeMtx); - - return res; - -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM connRef, - ESockAddress* addrP, - SOCKLEN_T addrLen) -{ - int save_errno; - ErlNifPid self; - - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - /* - * Verify that we are in the proper state - */ - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentWriterP != NULL) - return esock_make_error_invalid(env, atom_state); - - if (descP->connectorP != NULL) { - /* Connect in progress */ - - if (COMPARE_PIDS(&self, &descP->connector.pid) != 0) { - /* Other process has connect in progress */ - if (addrP != NULL) { - return esock_make_error(env, atom_already); - } else { - /* This is a bad call sequence - * - connect without an address is only allowed - * for the connecting process - */ - return esock_raise_invalid(env, atom_state); - } - } - - /* Finalize after received select message */ - - requestor_release("esock_connect finalize -> connected", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; - - if (! verify_is_connected(descP, &save_errno)) { - return esock_make_error_errno(env, save_errno); - } - - descP->writeState |= ESOCK_STATE_CONNECTED; - - return esock_atom_ok; - } - - /* No connect in progress */ - - if (addrP == NULL) - /* This is a bad call sequence - * - connect without an address is only allowed when - * a connect is in progress, after getting the select message - */ - return esock_raise_invalid(env, atom_state); - - /* Initial connect call, with address */ - - if (sock_connect(descP->sock, (struct sockaddr*) addrP, addrLen) == 0) { - /* Success already! */ - SSDBG( descP, ("SOCKET", "esock_connect {%d} -> connected\r\n", - descP->sock) ); - - descP->writeState |= ESOCK_STATE_CONNECTED; - - return esock_atom_ok; - } - - /* Connect returned error */ - save_errno = sock_errno(); - - switch (save_errno) { - - case ERRNO_BLOCK: /* Winsock2 */ - case EINPROGRESS: /* Unix & OSE!! */ - SSDBG( descP, - ("SOCKET", "esock_connect {%d} -> would block => select\r\n", - descP->sock) ); - { - int sres; - - if ((sres = - esock_select_write(env, descP->sock, descP, NULL, - sockRef, connRef)) < 0) - return - enif_raise_exception(env, - MKT2(env, atom_select_write, - MKI(env, sres))); - /* Initiate connector */ - descP->connector.pid = self; - ESOCK_ASSERT( MONP("esock_connect -> conn", - env, descP, - &self, &descP->connector.mon) == 0 ); - descP->connector.env = esock_alloc_env("connector"); - descP->connector.ref = CP_TERM(descP->connector.env, connRef); - descP->connectorP = &descP->connector; - descP->writeState |= - (ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); - - return atom_select; - } - break; - - default: - SSDBG( descP, - ("SOCKET", "esock_connect {%d} -> error: %d\r\n", - descP->sock, save_errno) ); - - return esock_make_error_errno(env, save_errno); - - } // switch(save_errno) -} -#endif // #ifndef __WIN32__ - - - -/* *** verify_is_connected *** - * Check if a connection has been established. - */ -#ifndef __WIN32__ -static -BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err) -{ - /* - * *** This is strange *** - * - * This *should* work on Windows NT too, but doesn't. - * An bug in Winsock 2.0 for Windows NT? - * - * See "Unix Netwok Programming", "The Sockets Networking API", - * W.R.Stevens, Volume 1, third edition, 16.4 Nonblocking 'connect', - * before Interrupted 'connect' (p 412) for a discussion about - * Unix portability and non blocking connect. - */ - - int error = 0; - -#ifdef SO_ERROR - if (! esock_getopt_int(descP->sock, SOL_SOCKET, SO_ERROR, &error)) { - // Solaris does it this way according to W.R.Stevens - error = sock_errno(); - } -#elif 1 - char buf[0]; - if (ESOCK_IS_ERROR(read(descP->sock, buf, sizeof(buf)))) { - error = sock_errno(); - } -#else - /* This variant probably returns wrong error value - * ENOTCONN instead of the actual connect error - */ - ESockAddress remote; - SOCKLEN_T addrLen = sizeof(remote); - sys_memzero((char *) &remote, addrLen); - if (sock_peer(descP->sock, - (struct sockaddr*) &remote, &addrLen)) < 0) { - error = sock_errno(); - } -#endif - - if (error != 0) { - *err = error; - return FALSE; - } - return TRUE; -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_listen - * - * Description: - * Listen for connections on a socket. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Backlog - The maximum length to which the queue of pending - * connections for socket may grow. - */ -static -ERL_NIF_TERM nif_listen(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - int backlog; - ERL_NIF_TERM ret; - - ESOCK_ASSERT( argc == 2 ); - - SGDBG( ("SOCKET", "nif_listen -> entry with argc: %d\r\n", argc) ); - - /* Extract arguments and perform preliminary validation */ - - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } - if (! GET_INT(env, argv[1], &backlog)) { - if (IS_INTEGER(env, argv[1])) - return esock_make_error_integer_range(env, argv[1]); - else - return enif_make_badarg(env); - } - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", "nif_listen(%T), {%d,0x%X} ->" - "\r\n backlog: %d" - "\r\n", - argv[0], descP->sock, descP->readState, - backlog) ); - - ret = esock_listen(env, descP, backlog); - - SSDBG( descP, ("SOCKET", "nif_listen(%T) -> done with" - "\r\n ret: %T" - "\r\n", argv[0], ret) ); - - MUNLOCK(descP->readMtx); - - return ret; -#endif // #ifdef __WIN32__ #else -} - - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_listen(ErlNifEnv* env, - ESockDescriptor* descP, - int backlog) -{ - - /* - * Verify that we are in the proper state - */ - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* - * And attempt to make socket listening - */ - - if ((sock_listen(descP->sock, backlog)) < 0) - return esock_make_error_errno(env, sock_errno()); - - descP->readState |= ESOCK_STATE_LISTENING; - - return esock_atom_ok; - -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_accept - * - * Description: - * Accept a connection on a socket. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Request ref - Unique "id" of this request - * (used for the select, if none is in queue). - */ -static -ERL_NIF_TERM nif_accept(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, ref, res; - - ESOCK_ASSERT( argc == 2 ); - - SGDBG( ("SOCKET", "nif_accept -> entry with argc: %d\r\n", argc) ); - - /* Extract arguments and perform preliminary validation */ - - sockRef = argv[0]; - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - return enif_make_badarg(env); - } - ref = argv[1]; - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", "nif_accept%T), {%d,0x%X} ->" - "\r\n ReqRef: %T" - "\r\n Current Acceptor addr: %p" - "\r\n Current Acceptor pid: %T" - "\r\n Current Acceptor mon: %T" - "\r\n Current Acceptor env: 0x%lX" - "\r\n Current Acceptor ref: %T" - "\r\n", - sockRef, descP->sock, descP->readState, - ref, - descP->currentAcceptorP, - descP->currentAcceptor.pid, - esock_make_monitor_term(env, &descP->currentAcceptor.mon), - descP->currentAcceptor.env, - descP->currentAcceptor.ref) ); - - res = esock_accept(env, descP, sockRef, ref); - - SSDBG( descP, ("SOCKET", "nif_accept(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->readMtx); - - return res; - -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef) -{ - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentReaderP != NULL) - return esock_make_error_invalid(env, atom_state); - - if (descP->currentAcceptorP == NULL) { - SOCKET accSock; - - /* We have no active acceptor (and therefore no acceptors in queue) - */ - - SSDBG( descP, ("SOCKET", "esock_accept {%d} -> try accept\r\n", - descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1); - - accSock = sock_accept(descP->sock, NULL, NULL); - - if (ESOCK_IS_ERROR(accSock)) { - int save_errno; - - save_errno = sock_errno(); - - return esock_accept_listening_error(env, descP, sockRef, - accRef, caller, save_errno); - } else { - /* We got an incoming connection */ - return - esock_accept_listening_accept(env, descP, sockRef, - accSock, caller); - } - } else { - - /* We have an active acceptor and possibly acceptors waiting in queue. - * If the pid of the calling process is not the pid of the - * "current process", push the requester onto the (acceptor) queue. - */ - - SSDBG( descP, ("SOCKET", "esock_accept_accepting -> check: " - "is caller current acceptor:" - "\r\n Caller: %T" - "\r\n Current: %T" - "\r\n", caller, descP->currentAcceptor.pid) ); - - if (COMPARE_PIDS(&descP->currentAcceptor.pid, &caller) == 0) { - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting {%d} -> current acceptor\r\n", - descP->sock) ); - - return esock_accept_accepting_current(env, descP, sockRef, accRef); - - } else { - - /* Not the "current acceptor", so (maybe) push onto queue */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting {%d} -> *not* current acceptor\r\n", - descP->sock) ); - - return esock_accept_accepting_other(env, descP, accRef, caller); - } - } -} -#endif // #ifndef __WIN32__ - -/* *** esock_accept_listening_error *** - * - * The accept call resultet in an error - handle it. - * There are only two cases: - * 1) BLOCK => Attempt a "retry" - * 2) Other => Return the value (converted to an atom) - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid caller, - int save_errno) -{ - ERL_NIF_TERM res; - - if (save_errno == ERRNO_BLOCK || - save_errno == EAGAIN) { - - /* *** Try again later *** */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_listening_error {%d} -> would block\r\n", - descP->sock) ); - - descP->currentAcceptor.pid = caller; - ESOCK_ASSERT( MONP("esock_accept_listening -> current acceptor", - env, descP, - &descP->currentAcceptor.pid, - &descP->currentAcceptor.mon) == 0 ); - ESOCK_ASSERT( descP->currentAcceptor.env == NULL ); - descP->currentAcceptor.env = esock_alloc_env("current acceptor"); - descP->currentAcceptor.ref = - CP_TERM(descP->currentAcceptor.env, accRef); - descP->currentAcceptorP = &descP->currentAcceptor; - res = esock_accept_busy_retry(env, descP, sockRef, accRef, NULL); - } else { - SSDBG( descP, - ("SOCKET", - "esock_accept_listening {%d} -> errno: %d\r\n", - descP->sock, save_errno) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1); - - res = esock_make_error_errno(env, save_errno); - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_listening_accept *** - * - * The accept call was successful (accepted) - handle the new connection. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid caller) -{ - ERL_NIF_TERM res; - - esock_accept_accepted(env, descP, sockRef, accSock, caller, &res); - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current *** - * Handles when the current acceptor makes another attempt. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef) -{ - SOCKET accSock; - int save_errno; - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current {%d} -> try accept\r\n", - descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1); - - accSock = sock_accept(descP->sock, NULL, NULL); - - if (ESOCK_IS_ERROR(accSock)) { - - save_errno = sock_errno(); - - res = esock_accept_accepting_current_error(env, descP, sockRef, - accRef, save_errno); - } else { - - res = esock_accept_accepting_current_accept(env, descP, sockRef, - accSock); - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current_accept *** - * Handles when the current acceptor succeeded in its accept call - - * handle the new connection. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock) -{ - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_accept {%d}" - "\r\n", descP->sock) ); - - if (esock_accept_accepted(env, descP, sockRef, accSock, - descP->currentAcceptor.pid, &res)) { - - if (!activate_next_acceptor(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_accept {%d} ->" - " no more acceptors" - "\r\n", descP->sock) ); - - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_current_error *** - * The accept call of current acceptor resultet in an error - handle it. - * There are only two cases: - * 1) BLOCK => Attempt a "retry" - * 2) Other => Return the value (converted to an atom) - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef, - int save_errno) -{ - ERL_NIF_TERM res, reason; - - if (save_errno == ERRNO_BLOCK || - save_errno == EAGAIN) { - - /* - * Just try again, no real error, just a ghost trigger from poll, - */ - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> " - "would block: try again\r\n", descP->sock) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_waits, &descP->accWaits, 1); - - res = esock_accept_busy_retry(env, descP, sockRef, opRef, - &descP->currentAcceptor.pid); - - } else { - ESockRequestor req; - - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> " - "error: %d\r\n", descP->sock, save_errno) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1); - - requestor_release("esock_accept_accepting_current_error", - env, descP, &descP->currentAcceptor); - - reason = MKA(env, erl_errno_id(save_errno)); - res = esock_make_error(env, reason); - - req.env = NULL; - while (acceptor_pop(env, descP, &req)) { - SSDBG( descP, - ("SOCKET", - "esock_accept_accepting_current_error {%d} -> abort %T\r\n", - descP->sock, req.pid) ); - - esock_send_abort_msg(env, descP, sockRef, &req, reason); - - (void) DEMONP("esock_accept_accepting_current_error -> " - "pop'ed writer", - env, descP, &req.mon); - } - descP->currentAcceptorP = NULL; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepting_other *** - * Handles when the another acceptor makes an attempt, which - * results (maybe) in the request beeing pushed onto the - * acceptor queue. - */ -#ifndef __WIN32__ -ERL_NIF_TERM -esock_accept_accepting_other(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ErlNifPid caller) -{ - if (! acceptor_search4pid(env, descP, &caller)) { - acceptor_push(env, descP, caller, ref); - return atom_select; - } else { - /* Acceptor already in queue */ - return esock_raise_invalid(env, atom_state); - } -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_busy_retry *** - * - * Perform a retry select. If successful, set nextState. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM accRef, - ErlNifPid* pidP) -{ - int sres; - ERL_NIF_TERM res; - - if ((sres = esock_select_read(env, descP->sock, descP, pidP, - sockRef, accRef)) < 0) { - - ESOCK_ASSERT( DEMONP("esock_accept_busy_retry - select failed", - env, descP, &descP->currentAcceptor.mon) == 0); - /* It is very unlikely that a next acceptor will be able - * to do anything succesful, but we will clean the queue - */ - if (!activate_next_acceptor(env, descP, sockRef)) { - SSDBG( descP, - ("SOCKET", - "esock_accept_busy_retry {%d} -> no more acceptors\r\n", - descP->sock) ); - - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); - } else { - descP->readState |= - (ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); - res = atom_select; - } - - return res; -} -#endif // #ifndef __WIN32__ - - -/* *** esock_accept_accepted *** - * - * Generic function handling a successful accept. - */ -#ifndef __WIN32__ -static -BOOLEAN_T esock_accept_accepted(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - SOCKET accSock, - ErlNifPid pid, - ERL_NIF_TERM* result) -{ - ESockDescriptor* accDescP; - ErlNifEvent accEvent; - ERL_NIF_TERM accRef; - int save_errno; - - /* - * We got one - */ - - ESOCK_CNT_INC(env, descP, sockRef, atom_acc_success, &descP->accSuccess, 1); - - if ((accEvent = sock_create_event(accSock)) == INVALID_EVENT) { - save_errno = sock_errno(); - (void) sock_close(accSock); - *result = esock_make_error_errno(env, save_errno); - return FALSE; - } - - accDescP = alloc_descriptor(accSock, accEvent); - accDescP->domain = descP->domain; - accDescP->type = descP->type; - accDescP->protocol = descP->protocol; - - MLOCK(descP->writeMtx); - - accDescP->rBufSz = descP->rBufSz; // Inherit buffer size - accDescP->rNum = descP->rNum; // Inherit buffer uses - accDescP->rNumCnt = 0; - accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size - accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size - accDescP->iow = descP->iow; // Inherit iow - accDescP->dbg = descP->dbg; // Inherit debug flag - accDescP->useReg = descP->useReg; // Inherit useReg flag - inc_socket(accDescP->domain, accDescP->type, accDescP->protocol); - - accRef = enif_make_resource(env, accDescP); - enif_release_resource(accDescP); - - accDescP->ctrlPid = pid; - /* pid has actually been compared equal to self() - * in this code path just a little while ago - */ - ESOCK_ASSERT( MONP("esock_accept_accepted -> ctrl", - env, accDescP, - &accDescP->ctrlPid, - &accDescP->ctrlMon) == 0 ); - - SET_NONBLOCKING(accDescP->sock); - - descP->writeState |= ESOCK_STATE_CONNECTED; - - MUNLOCK(descP->writeMtx); - - /* And finally (maybe) update the registry */ - if (descP->useReg) esock_send_reg_add_msg(env, descP, accRef); - - *result = esock_make_ok2(env, accRef); - - return TRUE; -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_send - * - * Description: - * Send a message on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Bin - The data to send as a binary() - * Flags - Send flags as an integer() - * SendRef - A unique id reference() for this (send) request. - */ - -static -ERL_NIF_TERM nif_send(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, sendRef; - ErlNifBinary sndData; - int flags; - ERL_NIF_TERM res; - - ESOCK_ASSERT( argc == 4 ); - - SGDBG( ("SOCKET", "nif_send -> entry with argc: %d\r\n", argc) ); - - sockRef = argv[0]; // We need this in case we send in case we send abort - sendRef = argv[3]; - - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - SGDBG( ("SOCKET", "nif_send -> get resource failed\r\n") ); - return enif_make_badarg(env); - } - - /* Extract arguments and perform preliminary validation */ - - if ((! enif_is_ref(env, sendRef)) || - (! GET_BIN(env, argv[1], &sndData))) { - SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") ); - return enif_make_badarg(env); - } - if (! GET_INT(env, argv[2], &flags)) { - SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") ); - if (IS_INTEGER(env, argv[2])) - return esock_make_error_integer_range(env, argv[2]); - else - return enif_make_badarg(env); - } - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_send(%T), {%d,0x%X} ->" - "\r\n SendRef: %T" - "\r\n Data size: %u" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->writeState, - sendRef, sndData.size, flags) ); - - /* We need to handle the case when another process tries - * to write at the same time. - * If the current write could not write its entire package - * this time (resulting in an select). The write of the - * other process must be made to wait until current - * is done! - */ - - res = esock_send(env, descP, sockRef, sendRef, &sndData, flags); - - SSDBG( descP, ("SOCKET", "nif_send(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->writeMtx); - - SGDBG( ("SOCKET", "nif_send -> done with result: " - "\r\n %T" - "\r\n", res) ); - return res; - -#endif // #ifdef __WIN32__ #else -} - - - -/* *** esock_send *** - * - * Do the actual send. - * Do some initial writer checks, do the actual send and then - * analyze the result. If we are done, another writer may be - * scheduled (if there is one in the writer queue). - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* sndDataP, - int flags) -{ - ssize_t send_result; - ERL_NIF_TERM writerCheck; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - send_result = (ssize_t) sndDataP->size; - if ((size_t) send_result != sndDataP->size) - return esock_make_error_invalid(env, atom_data_size); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", "esock_send {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - - send_result = - sock_send(descP->sock, sndDataP->data, sndDataP->size, flags); - - return send_check_result(env, descP, - send_result, sndDataP->size, FALSE, - sockRef, sendRef); - -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_sendto - * - * Description: - * Send a message on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Bin - The data to send as a binary() - * Dest - Destination (socket) address. - * Flags - Send flags as an integer(). - * SendRef - A unique id reference() for this (send) request. - */ - -static -ERL_NIF_TERM nif_sendto(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, sendRef; - ErlNifBinary sndData; - int flags; - ERL_NIF_TERM eSockAddr; - ESockAddress remoteAddr; - SOCKLEN_T remoteAddrLen; - ERL_NIF_TERM res; - - ESOCK_ASSERT( argc == 5 ); - - SGDBG( ("SOCKET", "nif_sendto -> entry with argc: %d\r\n", argc) ); - - sockRef = argv[0]; // We need this in case we send abort (to the caller) - sendRef = argv[4]; - - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - SGDBG( ("SOCKET", "nif_sendto -> get resource failed\r\n") ); - return enif_make_badarg(env); - } - - /* Extract arguments and perform preliminary validation */ - - if ((! enif_is_ref(env, sendRef)) || - (! GET_BIN(env, argv[1], &sndData))) { - SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") ); - return enif_make_badarg(env); - } - if (! GET_INT(env, argv[3], &flags)) { - SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") ); - if (IS_INTEGER(env, argv[3])) - return esock_make_error_integer_range(env, argv[3]); - else - return enif_make_badarg(env); - } - eSockAddr = argv[2]; - if (! esock_decode_sockaddr(env, eSockAddr, - &remoteAddr, - &remoteAddrLen)) { - SSDBG( descP, - ("SOCKET", - "nif_sendto(%T), {%d} -> sockaddr decode failed \r\n", - sockRef, descP->sock) ); - - return esock_make_invalid(env, atom_sockaddr); - } - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_sendto(%T), {%d,0x%X} ->" - "\r\n sendRef: %T" - "\r\n Data size: %u" - "\r\n eSockAddr: %T" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->readState, - sendRef, sndData.size, eSockAddr, flags) ); - - res = esock_sendto(env, descP, sockRef, sendRef, &sndData, flags, - &remoteAddr, remoteAddrLen); - - SSDBG( descP, ("SOCKET", "nif_sendto(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->writeMtx); - - return res; - -#endif // if defined(__WIN32__) -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_sendto(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ErlNifBinary* dataP, - int flags, - ESockAddress* toAddrP, - SOCKLEN_T toAddrLen) -{ - ssize_t sendto_result; - ERL_NIF_TERM writerCheck; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - sendto_result = (ssize_t) dataP->size; - if ((size_t) sendto_result != dataP->size) - return esock_make_error_invalid(env, atom_data_size); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", "esock_sendto {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - - if (toAddrP != NULL) { - sendto_result = - sock_sendto(descP->sock, - dataP->data, dataP->size, flags, - &toAddrP->sa, toAddrLen); - } else { - sendto_result = - sock_sendto(descP->sock, - dataP->data, dataP->size, flags, - NULL, 0); - } - - return send_check_result(env, descP, sendto_result, dataP->size, FALSE, - sockRef, sendRef); -} -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_sendmsg - * - * Description: - * Send a message on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Msg - Message - map() with data and (maybe) control and dest - * Flags - Send flags as an integer(). - * SendRef - A unique id reference() for this (send) request. - */ - -static -ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM res, sockRef, sendRef, eMsg, eIOV; - ESockDescriptor* descP; - int flags; - - ESOCK_ASSERT( argc == 5 ); - - SGDBG( ("SOCKET", "nif_sendmsg -> entry with argc: %d\r\n", argc) ); - - sockRef = argv[0]; // We need this in case we send abort (to the caller) - eMsg = argv[1]; - sendRef = argv[3]; - eIOV = argv[4]; - - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - SGDBG( ("SOCKET", "nif_sendmsg -> get resource failed\r\n") ); - return enif_make_badarg(env); - } - - /* Extract arguments and perform preliminary validation */ - - if ((! enif_is_ref(env, sendRef)) || - (! IS_MAP(env, eMsg))) { - SSDBG( descP, ("SOCKET", "nif_sendmsg -> argv decode failed\r\n") ); - return enif_make_badarg(env); - } - if (! GET_INT(env, argv[2], &flags)) { - if (IS_INTEGER(env, argv[2])) - return esock_make_error_integer_range(env, argv[2]); - else - return enif_make_badarg(env); - } - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_sendmsg(%T), {%d,0x%X} ->" - "\r\n SendRef: %T" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->writeState, - sendRef, flags) ); - - res = esock_sendmsg(env, descP, sockRef, sendRef, eMsg, flags, eIOV); - - MUNLOCK(descP->writeMtx); - - SSDBG( descP, ("SOCKET", "nif_sendmsg(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - return res; - -#endif // #ifdef __WIN32__ #else -} - - -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsg, - int flags, - ERL_NIF_TERM eIOV) -{ - ERL_NIF_TERM res, eAddr, eCtrl; - ESockAddress addr; - struct msghdr msgHdr; - ErlNifIOVec *iovec = NULL; - char* ctrlBuf; - size_t ctrlBufLen, ctrlBufUsed; - ssize_t dataSize, sendmsg_result; - ERL_NIF_TERM writerCheck, tail; - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_sendmsg {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - return writerCheck; - } - - /* Initiate the .name and .namelen fields depending on if - * we have an address or not - */ - if (! GET_MAP_VAL(env, eMsg, esock_atom_addr, &eAddr)) { - - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> no address\r\n", descP->sock) ); - - msgHdr.msg_name = NULL; - msgHdr.msg_namelen = 0; - } else { - msgHdr.msg_name = (void*) &addr; - msgHdr.msg_namelen = sizeof(addr); - sys_memzero((char *) msgHdr.msg_name, msgHdr.msg_namelen); - - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n address: %T" - "\r\n", descP->sock, eAddr) ); - - if (! esock_decode_sockaddr(env, eAddr, - msgHdr.msg_name, - &msgHdr.msg_namelen)) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid address\r\n", - descP->sock) ); - return esock_make_invalid(env, esock_atom_addr); - } - } - - /* Extract the *mandatory* 'iov', which must be an erlang:iovec(), - * from which we take at most IOV_MAX binaries - */ - if ((! enif_inspect_iovec(NULL, data.iov_max, eIOV, &tail, &iovec))) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> not an iov\r\n", - descP->sock) ); - - return esock_make_invalid(env, esock_atom_iov); - } - - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n iovcnt: %lu" - "\r\n tail: %s" - "\r\n", descP->sock, - (unsigned long) iovec->iovcnt, - B2S(! enif_is_empty_list(env, tail))) ); - - /* We now have an allocated iovec */ - - eCtrl = esock_atom_undefined; - ctrlBufLen = 0; - ctrlBuf = NULL; - - if (iovec->iovcnt > data.iov_max) { - if (descP->type == SOCK_STREAM) { - iovec->iovcnt = data.iov_max; - } else { - /* We can not send the whole packet in one sendmsg() call */ - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> iovcnt > iov_max\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - } - - dataSize = 0; - { - ERL_NIF_TERM h, t; - ErlNifBinary bin; - size_t i; - - /* Find out if there is remaining data in the tail. - * Skip empty binaries otherwise break. - * If 'tail' after loop exit is the empty list - * there was no more data. Otherwise there is more - * data or the 'iov' is invalid. - */ - for (;;) { - if (enif_get_list_cell(env, tail, &h, &t) && - enif_inspect_binary(env, h, &bin) && - (bin.size == 0)) { - tail = t; - continue; - } else - break; - } - - if ((! enif_is_empty_list(env, tail)) && - (descP->type != SOCK_STREAM)) { - /* We can not send the whole packet in one sendmsg() call */ - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid tail\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - - /* Calculate the data size */ - - for (i = 0; i < iovec->iovcnt; i++) { - size_t len = iovec->iov[i].iov_len; - dataSize += len; - if (dataSize < len) { - /* Overflow */ - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> Overflow" - "\r\n i: %lu" - "\r\n len: %lu" - "\r\n dataSize: %ld" - "\r\n", descP->sock, (unsigned long) i, - (unsigned long) len, (long) dataSize) ); - res = esock_make_invalid(env, esock_atom_iov); - goto done_free_iovec; - } - } - } - SSDBG( descP, - ("SOCKET", - "esock_sendmsg {%d} ->" - "\r\n iov length: %lu" - "\r\n data size: %u" - "\r\n", - descP->sock, - (unsigned long) iovec->iovcnt, (long) dataSize) ); - - msgHdr.msg_iovlen = iovec->iovcnt; - msgHdr.msg_iov = iovec->iov; - - /* Extract the *optional* 'ctrl' */ - if (GET_MAP_VAL(env, eMsg, esock_atom_ctrl, &eCtrl)) { - ctrlBufLen = descP->wCtrlSz; - ctrlBuf = (char*) MALLOC(ctrlBufLen); - ESOCK_ASSERT( ctrlBuf != NULL ); - } - SSDBG( descP, ("SOCKET", "esock_sendmsg {%d} -> optional ctrl: " - "\r\n ctrlBuf: %p" - "\r\n ctrlBufLen: %lu" - "\r\n eCtrl: %T" - "\r\n", descP->sock, - ctrlBuf, (unsigned long) ctrlBufLen, eCtrl) ); - - /* Decode the ctrl and initiate that part of the msghdr. - */ - if (ctrlBuf != NULL) { - if (! decode_cmsghdrs(env, descP, - eCtrl, - ctrlBuf, ctrlBufLen, &ctrlBufUsed)) { - SSDBG( descP, ("SOCKET", - "esock_sendmsg {%d} -> invalid ctrl\r\n", - descP->sock) ); - res = esock_make_invalid(env, esock_atom_ctrl); - goto done_free_iovec; - } - } else { - ctrlBufUsed = 0; - } - msgHdr.msg_control = ctrlBuf; - msgHdr.msg_controllen = ctrlBufUsed; - - /* The msg_flags field is not used when sending, - * but zero it just in case */ - msgHdr.msg_flags = 0; - - ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1); - - /* And now, try to send the message */ - sendmsg_result = sock_sendmsg(descP->sock, &msgHdr, flags); - - res = send_check_result(env, descP, sendmsg_result, dataSize, - (! enif_is_empty_list(env, tail)), - sockRef, sendRef); - - done_free_iovec: - enif_free_iovec(iovec); - if (ctrlBuf != NULL) FREE(ctrlBuf); - - SSDBG( descP, - ("SOCKET", "esock_sendmsg {%d} ->" - "\r\n %T\r\n", descP->sock, res) ); - return res; -} -#endif // #ifndef __WIN32__ - - - -#ifdef FOOBAR - -/* ---------------------------------------------------------------------- - * nif_writev / nif_sendv - * - * Description: - * Send a message (vector) on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * SendRef - A unique id for this (send) request. - * Data - A vector of binaries - * Flags - Send flags. - */ - -static -ERL_NIF_TERM nwritev(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM data) -{ - ERL_NIF_TERM tail; - ErlNifIOVec vec; - ErlNifIOVec* iovec = &vec; - SysIOVec* sysiovec; - int save_errno; - int iovcnt, n; - - if (! enif_inspect_iovec(env, MAX_VSZ, data, &tail, &iovec)) - return enif_make_badarg(env); - - if (enif_ioq_size(descP->outQ) > 0) { - /* If the I/O queue contains data we enqueue the iovec - * and then peek the data to write out of the queue. - */ - if (!enif_ioq_enqv(q, iovec, 0)) - return -3; - - sysiovec = enif_ioq_peek(descP->outQ, &iovcnt); - - } else { - /* If the I/O queue is empty we skip the trip through it. */ - iovcnt = iovec->iovcnt; - sysiovec = iovec->iov; - } - - /* Attempt to write the data */ - n = writev(fd, sysiovec, iovcnt); - saved_errno = errno; - - if (enif_ioq_size(descP->outQ) == 0) { - /* If the I/O queue was initially empty we enqueue any - remaining data into the queue for writing later. */ - if (n >= 0 && !enif_ioq_enqv(descP->outQ, iovec, n)) - return -3; - } else { - /* Dequeue any data that was written from the queue. */ - if (n > 0 && !enif_ioq_deq(descP->outQ, n, NULL)) - return -4; - } - /* return n, which is either number of bytes written or -1 if - some error happened */ - errno = saved_errno; - return n; -} - -#endif // #ifdef FOOBAR - - - -/* ---------------------------------------------------------------------- - * nif_sendfile/1,4,5 - * - * Description: - * Send a file on a socket - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * - * SendRef - A unique id reference() for this (send) request. - * - * Offset - File offset to start from. - * Count - The number of bytes to send. - * - * InFileRef - A file NIF resource. - */ - -static ERL_NIF_TERM -nif_sendfile(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) || !defined(HAVE_SENDFILE) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor *descP; - ERL_NIF_TERM sockRef, res; - - SGDBG( ("SOCKET", "nif_sendfile -> entry with argc: %d\r\n", argc) ); - - if (argc < 1) { - SGDBG( ("SOCKET", "nif_sendfile -> argc < 1\r\n") ); - return enif_make_badarg(env); - } - sockRef = argv[0]; - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) (&descP))) { - SGDBG( ("SOCKET", "nif_sendfile -> get resource failed\r\n") ); - return enif_make_badarg(env); - } - - if (argc < 2) { // argc == 1 - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_sendfile(%T), {%d,%d,0x%X} ->" - "\r\n", - sockRef, - descP->sock, descP->sendfileHandle, descP->writeState) ); - - res = esock_sendfile_deferred_close(env, descP); - - } else { - ERL_NIF_TERM sendRef; - ErlNifSInt64 offset64; - ErlNifUInt64 count64u; - off_t offset; - size_t count; - BOOLEAN_T a2ok; - - ESOCK_ASSERT( argc >= 4 ); - - sendRef = argv[1]; - if ((! enif_is_ref(env, sendRef))) { - SSDBG( descP, - ("SOCKET", "nif_sendfile -> argv[1] decode failed\r\n") ); - return enif_make_badarg(env); - } - - if ((! (a2ok = GET_INT64(env, argv[2], &offset64))) || - (! GET_UINT64(env, argv[3], &count64u))) { - if ((! IS_INTEGER(env, argv[3])) || - (! IS_INTEGER(env, argv[3]))) - return enif_make_badarg(env); - if (! a2ok) - return esock_make_error_integer_range(env, argv[2]); - else - return esock_make_error_integer_range(env, argv[3]); - } - offset = (off_t) offset64; - if (offset64 != (ErlNifSInt64) offset) - return esock_make_error_integer_range(env, argv[2]); - count = (size_t) count64u; - if (count64u != (ErlNifUInt64) count) - return esock_make_error_integer_range(env, argv[3]); - - if (argc == 4) { - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->" - "\r\n sendRef: %T" - "\r\n offset: %ld" - "\r\n count: %ld" - "\r\n", - sockRef, descP->sock, descP->readState, - sendRef, (long) offset, (long) count) ); - - res = - esock_sendfile_cont(env, descP, sockRef, sendRef, - offset, count); - } else { - ERL_NIF_TERM fRef; - - ESOCK_ASSERT( argc == 5 ); - - fRef = argv[4]; - if ((! enif_is_ref(env, fRef))) - return enif_make_badarg(env); - - MLOCK(descP->writeMtx); - - SSDBG( descP, - ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->" - "\r\n sendRef: %T" - "\r\n offset: %ld" - "\r\n count: %ld" - "\r\n fRef: %T" - "\r\n", - sockRef, descP->sock, descP->readState, - sendRef, (long) offset, (long) count, fRef) ); - - res = - esock_sendfile_start(env, descP, sockRef, sendRef, - offset, count, fRef); - } - } - - SSDBG( descP, ("SOCKET", "nif_sendfile(%T) -> done with" - "\r\n res: %T" - "\r\n", sockRef, res) ); - - MUNLOCK(descP->writeMtx); - - return res; - -#endif // #if defined(__WIN32__) || !defined(HAVE_SENDFILE) -} - -#ifndef __WIN32__ -#ifdef HAVE_SENDFILE - -/* Start a sendfile() operation - */ -static ERL_NIF_TERM -esock_sendfile_start(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count, - ERL_NIF_TERM fRef) { - ERL_NIF_TERM writerCheck; - ssize_t res; - int err; - - SSDBG( descP, ("SOCKET", - "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n" - " fRef: %T\r\n" - " offset: %lu\r\n" - " count: %lu\r\n", - sockRef, descP->sock, sendRef, - fRef, (unsigned long) offset, (unsigned long) count) ); - - if (! IS_OPEN(descP->writeState)) { - return esock_make_error(env, atom_closed); - } - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) { - return esock_make_error_invalid(env, atom_state); - } - - /* Ensure that we either have no current writer or we are it, - * or enqueue this process if there is a current writer - */ - if (! send_check_writer(env, descP, sendRef, &writerCheck)) { - SSDBG( descP, ("SOCKET", - "esock_sendfile_start {%d} -> writer check failed: " - "\r\n %T\r\n", descP->sock, writerCheck) ); - - /* Returns 'select' if current process got enqueued, - * or exception invalid state if current process already - * was enqueued - */ - return writerCheck; - } - - if (descP->sendfileHandle != INVALID_HANDLE) - return esock_make_error_invalid(env, atom_state); - - /* Get a dup:ed file handle from prim_file_nif - * through a NIF dyncall - */ - { - struct prim_file_nif_dyncall_dup dc_dup; - - dc_dup.op = prim_file_nif_dyncall_dup; - dc_dup.result = EINVAL; // should not be needed - - /* Request the handle */ - if (enif_dynamic_resource_call(env, - atom_prim_file, atom_efile, fRef, - &dc_dup) - != 0) { - return - esock_sendfile_error(env, descP, sockRef, - MKT2(env, esock_atom_invalid, - atom_efile)); - } - if (dc_dup.result != 0) { - return - esock_sendfile_errno(env, descP, sockRef, dc_dup.result); - } - descP->sendfileHandle = dc_dup.handle; - } - - SSDBG( descP, ("SOCKET", - "esock_sendfile_start(%T) {%d} -> sendRef: %T\r\n" - " sendfileHandle: %d\r\n", - sockRef, descP->sock, sendRef, - descP->sendfileHandle) ); - - if (descP->sendfileCountersP == NULL) { - descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); - *descP->sendfileCountersP = initESockSendfileCounters; - } - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_tries, &descP->sendfileCountersP->tries, 1); - descP->sendfileCountersP->maxCnt = 0; - - res = esock_sendfile(env, descP, sockRef, offset, &count, &err); - - if (res < 0) { // Terminal error - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_sendfile_errno(env, descP, sockRef, err); - - } else if (res > 0) { // Retry by select - - if (descP->currentWriterP == NULL) { - int mon_res; - - /* Register writer as current */ - ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); - mon_res = - MONP("sendfile -> current writer", - env, descP, - &descP->currentWriter.pid, - &descP->currentWriter.mon); - ESOCK_ASSERT( mon_res >= 0 ); - - if (mon_res > 0) { - /* Caller died already, can happen for dirty NIFs */ - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return - esock_sendfile_error(env, descP, sockRef, - MKT2(env, - esock_atom_invalid, - esock_atom_not_owner)); - } - ESOCK_ASSERT( descP->currentWriter.env == NULL ); - descP->currentWriter.env = esock_alloc_env("current-writer"); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - descP->currentWriterP = &descP->currentWriter; - } - // else current writer is already registered by requestor_pop() - - return esock_sendfile_select(env, descP, sockRef, sendRef, count); - - } else { // res == 0: Done - return esock_sendfile_ok(env, descP, sockRef, count); - } -} - -/* Continue an ongoing sendfile operation - */ -static ERL_NIF_TERM -esock_sendfile_cont(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - off_t offset, - size_t count) { - ErlNifPid caller; - ssize_t res; - int err; - - SSDBG( descP, ("SOCKET", - "esock_sendfile_cont(%T) {%d} -> sendRef: %T\r\n", - sockRef, descP->sock, sendRef) ); - - if (! IS_OPEN(descP->writeState)) - return esock_make_error(env, atom_closed); - - /* Connect and Write uses the same select flag - * so they can not be simultaneous - */ - if (descP->connectorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Verify that this process has a sendfile operation in progress */ - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - if ((descP->currentWriterP == NULL) || - (descP->sendfileHandle == INVALID_HANDLE) || - (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0)) { - // - return esock_raise_invalid(env, atom_state); - } - - res = esock_sendfile(env, descP, sockRef, offset, &count, &err); - - if (res < 0) { // Terminal error - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_sendfile_errno(env, descP, sockRef, err); - - } else if (res > 0) { // Retry by select - - /* Overwrite current writer registration */ - enif_clear_env(descP->currentWriter.env); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - - return esock_sendfile_select(env, descP, sockRef, sendRef, count); - - } else { // res == 0: Done - return esock_sendfile_ok(env, descP, sockRef, count); - } -} - -/* Deferred close of the dup:ed file descriptor - */ -static ERL_NIF_TERM -esock_sendfile_deferred_close(ErlNifEnv *env, - ESockDescriptor *descP) { - if (descP->sendfileHandle == INVALID_HANDLE) - return esock_make_error_invalid(env, atom_state); - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_atom_ok; -} - -/* Platform independent sendfile() function - * - * Return < 0 for terminal error - * 0 for done - * > 0 for retry with select - */ -static int -esock_sendfile(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - off_t offset, - size_t *countP, - int *errP) { - - size_t pkgSize = 0; // Total sent in this call - - SSDBG( descP, ("SOCKET", - "esock_sendfile(%T) {%d,%d}\r\n", - sockRef, descP->sock, descP->sendfileHandle) ); - - for (;;) { - size_t chunk_size = (size_t) 0x20000000UL; // 0.5 GB - size_t bytes_sent; - ssize_t res; - int error; - - /* *countP == 0 means send the whole file - use chunk size */ - if ((*countP > 0) && (*countP < chunk_size)) - chunk_size = *countP; - - { - /* Platform dependent code: - * update and check offset, set and check bytes_sent, and - * set res to >= 0 and error to 0, or - * set res to < 0 and error to sock_errno() - */ -#if defined (__linux__) - - off_t prev_offset; - - prev_offset = offset; - res = - sendfile(descP->sock, descP->sendfileHandle, - &offset, chunk_size); - error = (res < 0) ? sock_errno() : 0; - - ESOCK_ASSERT( offset >= prev_offset ); - ESOCK_ASSERT( (off_t) chunk_size >= (offset - prev_offset) ); - bytes_sent = (size_t) (offset - prev_offset); - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - -#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__DARWIN__) - - off_t sbytes; - -#if defined(__DARWIN__) - sbytes = (off_t) chunk_size; - res = (ssize_t) - sendfile(descP->sendfileHandle, descP->sock, offset, - &sbytes, NULL, 0); -#else - sbytes = 0; - res = (ssize_t) - sendfile(descP->sendfileHandle, descP->sock, offset, - chunk_size, NULL, &sbytes, 0); -#endif - error = (res < 0) ? sock_errno() : 0; - - /* For an error return, we do not dare trust that sbytes is set - * unless the error is ERRNO_BLOCK or EINTR - * - the man page is to vague - */ - if ((res < 0) && (error != ERRNO_BLOCK) && (error != EINTR)) { - sbytes = 0; - } else { - ESOCK_ASSERT( sbytes >= 0 ); - ESOCK_ASSERT( (off_t) chunk_size >= sbytes ); - ESOCK_ASSERT( offset + sbytes >= offset ); - offset += sbytes; - } - bytes_sent = (size_t) sbytes; - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - -#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) - - sendfilevec_t sfvec[1]; - - sfvec[0].sfv_fd = descP->sendfileHandle; - sfvec[0].sfv_flag = 0; - sfvec[0].sfv_off = offset; - sfvec[0].sfv_len = chunk_size; - - res = sendfilev(descP->sock, sfvec, NUM(sfvec), &bytes_sent); - error = (res < 0) ? sock_errno() : 0; - - SSDBG( descP, - ("SOCKET", - "esock_sendfile(%T) {%d,%d}" - "\r\n res: %d" - "\r\n bytes_sent: %lu" - "\r\n error: %d" - "\r\n", - sockRef, descP->sock, descP->sendfileHandle, - res, (unsigned long) bytes_sent, error) ); - - if ((res < 0) && (error == EINVAL)) { - /* On e.b SunOS 5.10 using sfv_len > file size - * lands here - we regard this as a succesful send. - * All other causes for EINVAL are avoided, - * except for .sfv_fd not seekable, which would - * give bytes_sent == 0 that we would interpret - * as end of file, which is kind of true. - */ - res = 0; - } - ESOCK_ASSERT( chunk_size >= bytes_sent ); - ESOCK_ASSERT( offset + bytes_sent >= offset ); - offset += bytes_sent; - -#else -#error "Unsupported sendfile syscall; update configure test." -#endif - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile, &descP->sendfileCountersP->cnt, 1); - - if (bytes_sent != 0) { - - pkgSize += bytes_sent; - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_pkg, - &descP->sendfileCountersP->pkg, - 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_byte, - &descP->sendfileCountersP->byteCnt, - bytes_sent); - - if (pkgSize > descP->sendfileCountersP->pkgMax) - descP->sendfileCountersP->pkgMax = pkgSize; - if ((descP->sendfileCountersP->maxCnt += bytes_sent) - > descP->sendfileCountersP->max) - descP->sendfileCountersP->max = - descP->sendfileCountersP->maxCnt; - } - - /* *countP == 0 means send whole file */ - if (*countP > 0) { - - *countP -= bytes_sent; - - if (*countP == 0) { // All sent - *countP = pkgSize; - return 0; - } - } - - if (res < 0) { - if (error == ERRNO_BLOCK) { - *countP = pkgSize; - return 1; - } - if (error == EINTR) - continue; - *errP = error; - return -1; - } - - if (bytes_sent == 0) { // End of input file - *countP = pkgSize; - return 0; - } - } - } // for (;;) -} - -static ERL_NIF_TERM -esock_sendfile_errno(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - int err) { - ERL_NIF_TERM reason; - - reason = MKA(env, erl_errno_id(err)); - return esock_sendfile_error(env, descP, sockRef, reason); -} - -static ERL_NIF_TERM -esock_sendfile_error(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) { - - if (descP->sendfileCountersP == NULL) { - descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); - *descP->sendfileCountersP = initESockSendfileCounters; - } - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_fails, - &descP->sendfileCountersP->fails, 1); - - SSDBG( descP, ("SOCKET", - "esock_sendfile_error(%T) {%d} -> error: %T\r\n", - sockRef, descP->sock, reason) ); - - /* XXX Should we have special treatment for EINVAL, - * such as to only fail current operation and activate - * the next from the queue? - */ - - if (descP->currentWriterP != NULL) { - - (void) DEMONP("esock_sendfile_error", - env, descP, &descP->currentWriter.mon); - - /* Fail all queued writers */ - requestor_release("esock_sendfile_error", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; - - } - - return esock_make_error(env, reason); -} - -static ERL_NIF_TERM -esock_sendfile_select(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - size_t count) { - int sres; - - /* Select write for this process */ - sres = - esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); - if (sres < 0) { - ERL_NIF_TERM reason; - - /* Internal select error */ - (void) DEMONP("esock_sendfile_select - failed", - env, descP, &descP->currentWriter.mon); - - /* Fail all queued writers */ - reason = MKT2(env, atom_select_write, MKI(env, sres)); - requestor_release("esock_sendfile_select_fail", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; - - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return enif_raise_exception(env, reason); - - } else { - ErlNifUInt64 bytes_sent; - - SSDBG( descP, - ("SOCKET", "esock_sendfile_select(%T) {%d} -> " - "sendRef (%T)\r\n" - "count: %lu\r\n", - sockRef, descP->sock, sendRef, (unsigned long) count) ); - - ESOCK_CNT_INC(env, descP, sockRef, - atom_sendfile_waits, - &descP->sendfileCountersP->waits, - 1); - descP->writeState |= ESOCK_STATE_SELECTED; - bytes_sent = (ErlNifUInt64) count; - - return MKT2(env, atom_select, MKUI64(env, bytes_sent)); - } -} - -static ERL_NIF_TERM -esock_sendfile_ok(ErlNifEnv *env, - ESockDescriptor *descP, - ERL_NIF_TERM sockRef, - size_t count) { - ErlNifUInt64 bytes_sent64u; - - SSDBG( descP, - ("SOCKET", "esock_sendfile_ok(%T) {%d} -> " - "everything written (%lu) - done\r\n", - sockRef, descP->sock, (unsigned long) count) ); - - if (descP->currentWriterP != NULL) { - - (void) DEMONP("esock_sendfile_ok -> current writer", - env, descP, &descP->currentWriter.mon); - - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (! activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_sendfile_ok(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - } - - descP->writePkgMaxCnt = 0; - bytes_sent64u = (ErlNifUInt64) count; - (void) close(descP->sendfileHandle); - descP->sendfileHandle = INVALID_HANDLE; - - return esock_make_ok2(env, MKUI64(env, bytes_sent64u)); -} - -#endif // #ifdef HAVE_SENDFILE -#endif // #ifndef __WIN32__ - - - -/* ---------------------------------------------------------------------- - * nif_recv - * - * Description: - * Receive a message on a socket. - * Normally used only on a connected socket! - * If we are trying to read > 0 bytes, then that is what we do. - * But if we have specified 0 bytes, then we want to read - * whatever is in the buffers (everything it got). - * - * Arguments: - * Socket (ref) - NIF resource reference() to the socket descriptor. - * Length - The number of bytes to receive; integer(). - * Flags - Receive flags; integer(). - * RecvRef - A unique reference() id for this (send) request | 'poll' - */ - -static -ERL_NIF_TERM nif_recv(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, recvRef; - ErlNifUInt64 elen; - ssize_t len; /* ssize_t due to the return type of recv() */ - int flags; - ERL_NIF_TERM res; - BOOLEAN_T a1ok; - - ESOCK_ASSERT( argc == 4 ); - - sockRef = argv[0]; // We need this in case we send abort (to the caller) - recvRef = argv[3]; - - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - return enif_make_badarg(env); - } - - if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { - return enif_make_badarg(env); - } - if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) || - (! GET_INT(env, argv[2], &flags))) { - if ((! IS_INTEGER(env, argv[1])) || - (! IS_INTEGER(env, argv[2]))) - return enif_make_badarg(env); - - if (! a1ok) - return esock_make_error_integer_range(env, argv[1]); - return - esock_make_error_integer_range(env, argv[2]); - } - len = (ssize_t) elen; - if (elen != (ErlNifUInt64) len) - return esock_make_error_integer_range(env, elen); - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", "nif_recv(%T), {%d,0x%X} ->" - "\r\n recvRef: %T" - "\r\n len: %ld" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->readState, - recvRef, (long) len, flags) ); - - /* We need to handle the case when another process tries - * to receive at the same time. - * If the current recv could not read its entire package - * this time (resulting in an select). The read of the - * other process must be made to wait until current - * is done! - */ - - res = esock_recv(env, descP, sockRef, recvRef, len, flags); - - SSDBG( descP, ("SOCKET", "nif_recv(%T) -> done" - "\r\n", sockRef) ); - - MUNLOCK(descP->readMtx); +#if HAVE_IN6 +# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY +# if HAVE_DECL_IN6ADDR_ANY_INIT +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; +# else +static const struct in6_addr in6addr_any = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +# endif /* HAVE_IN6ADDR_ANY_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_ANY */ - return res; +# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK +# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT +static const struct in6_addr in6addr_loopback = + { { IN6ADDR_LOOPBACK_INIT } }; +# else +static const struct in6_addr in6addr_loopback = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ +#endif /* HAVE_IN6 */ -#endif // #ifdef __WIN32__ #else -} -/* The (read) buffer handling should be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... +/* *** Global atoms *** + * Note that when an (global) atom is added here, it must also be added + * in the socket_int.h file! */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags) -{ - ssize_t read; - ErlNifBinary buf; - ERL_NIF_TERM readerCheck; - int save_errno; - size_t bufSz = (len != 0 ? len : descP->rBufSz); - - SSDBG( descP, ("SOCKET", "esock_recv {%d} -> entry with" - "\r\n count,size: (%ld:%u:%lu)" - "\r\n", descP->sock, - (long) len, descP->rNumCnt, (unsigned long) bufSz) ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } - - /* Allocate a buffer: - * Either as much as we want to read or (if zero (0)) use the "default" - * size (what has been configured). - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); - - // If it fails (read = -1), we need errno... - SSDBG( descP, ("SOCKET", "esock_recv {%d} -> try read (%lu)\r\n", - descP->sock, (unsigned long) buf.size) ); +#define GLOBAL_ATOMS \ + GLOBAL_ATOM_DECL(abort); \ + GLOBAL_ATOM_DECL(accept); \ + GLOBAL_ATOM_DECL(acceptconn); \ + GLOBAL_ATOM_DECL(acceptfilter); \ + GLOBAL_ATOM_DECL(acc_success); \ + GLOBAL_ATOM_DECL(acc_fails); \ + GLOBAL_ATOM_DECL(acc_tries); \ + GLOBAL_ATOM_DECL(acc_waits); \ + GLOBAL_ATOM_DECL(adaption_layer); \ + GLOBAL_ATOM_DECL(addr); \ + GLOBAL_ATOM_DECL(addrform); \ + GLOBAL_ATOM_DECL(add_membership); \ + GLOBAL_ATOM_DECL(add_socket); \ + GLOBAL_ATOM_DECL(add_source_membership); \ + GLOBAL_ATOM_DECL(alen); \ + GLOBAL_ATOM_DECL(allmulti); \ + GLOBAL_ATOM_DECL(already); \ + GLOBAL_ATOM_DECL(any); \ + GLOBAL_ATOM_DECL(appletlk); \ + GLOBAL_ATOM_DECL(arcnet); \ + GLOBAL_ATOM_DECL(associnfo); \ + GLOBAL_ATOM_DECL(atm); \ + GLOBAL_ATOM_DECL(authhdr); \ + GLOBAL_ATOM_DECL(auth_active_key); \ + GLOBAL_ATOM_DECL(auth_asconf); \ + GLOBAL_ATOM_DECL(auth_chunk); \ + GLOBAL_ATOM_DECL(auth_delete_key); \ + GLOBAL_ATOM_DECL(auth_key); \ + GLOBAL_ATOM_DECL(auth_level); \ + GLOBAL_ATOM_DECL(autoclose); \ + GLOBAL_ATOM_DECL(automedia); \ + GLOBAL_ATOM_DECL(ax25); \ + GLOBAL_ATOM_DECL(bad_data); \ + GLOBAL_ATOM_DECL(base_addr); \ + GLOBAL_ATOM_DECL(bindtodevice); \ + GLOBAL_ATOM_DECL(block_source); \ + GLOBAL_ATOM_DECL(broadcast); \ + GLOBAL_ATOM_DECL(bsp_state); \ + GLOBAL_ATOM_DECL(busy_poll); \ + GLOBAL_ATOM_DECL(bytes_in); \ + GLOBAL_ATOM_DECL(bytes_in_flight); \ + GLOBAL_ATOM_DECL(bytes_out); \ + GLOBAL_ATOM_DECL(bytes_reordered); \ + GLOBAL_ATOM_DECL(bytes_retrans); \ + GLOBAL_ATOM_DECL(cancel); \ + GLOBAL_ATOM_DECL(cancelled); \ + GLOBAL_ATOM_DECL(cantconfig); \ + GLOBAL_ATOM_DECL(chaos); \ + GLOBAL_ATOM_DECL(checksum); \ + GLOBAL_ATOM_DECL(close); \ + GLOBAL_ATOM_DECL(closed); \ + GLOBAL_ATOM_DECL(close_wait); \ + GLOBAL_ATOM_DECL(closing); \ + GLOBAL_ATOM_DECL(cmsg_cloexec); \ + GLOBAL_ATOM_DECL(command); \ + GLOBAL_ATOM_DECL(completion); \ + GLOBAL_ATOM_DECL(completion_status); \ + GLOBAL_ATOM_DECL(confirm); \ + GLOBAL_ATOM_DECL(congestion); \ + GLOBAL_ATOM_DECL(connect); \ + GLOBAL_ATOM_DECL(connected); \ + GLOBAL_ATOM_DECL(connecting); \ + GLOBAL_ATOM_DECL(connection_time); \ + GLOBAL_ATOM_DECL(context); \ + GLOBAL_ATOM_DECL(cork); \ + GLOBAL_ATOM_DECL(counters); \ + GLOBAL_ATOM_DECL(credentials); \ + GLOBAL_ATOM_DECL(ctrl); \ + GLOBAL_ATOM_DECL(ctrunc); \ + GLOBAL_ATOM_DECL(cwnd); \ + GLOBAL_ATOM_DECL(data); \ + GLOBAL_ATOM_DECL(data_size); \ + GLOBAL_ATOM_DECL(debug); \ + GLOBAL_ATOM_DECL(default); \ + GLOBAL_ATOM_DECL(default_send_params); \ + GLOBAL_ATOM_DECL(delayed_ack_time); \ + GLOBAL_ATOM_DECL(dgram); \ + GLOBAL_ATOM_DECL(disable_fragments); \ + GLOBAL_ATOM_DECL(dlci); \ + GLOBAL_ATOM_DECL(dma); \ + GLOBAL_ATOM_DECL(domain); \ + GLOBAL_ATOM_DECL(dontfrag); \ + GLOBAL_ATOM_DECL(dontroute); \ + GLOBAL_ATOM_DECL(dormant); \ + GLOBAL_ATOM_DECL(drop_membership); \ + GLOBAL_ATOM_DECL(drop_source_membership); \ + GLOBAL_ATOM_DECL(dstopts); \ + GLOBAL_ATOM_DECL(dup); \ + GLOBAL_ATOM_DECL(dup_acks_in); \ + GLOBAL_ATOM_DECL(dying); \ + GLOBAL_ATOM_DECL(dynamic); \ + GLOBAL_ATOM_DECL(echo); \ + GLOBAL_ATOM_DECL(eether); \ + GLOBAL_ATOM_DECL(efile); \ + GLOBAL_ATOM_DECL(egp); \ + GLOBAL_ATOM_DECL(enotsup); \ + GLOBAL_ATOM_DECL(eor); \ + GLOBAL_ATOM_DECL(error); \ + GLOBAL_ATOM_DECL(errqueue); \ + GLOBAL_ATOM_DECL(esp_network_level); \ + GLOBAL_ATOM_DECL(esp_trans_level); \ + GLOBAL_ATOM_DECL(established); \ + GLOBAL_ATOM_DECL(ether); \ + GLOBAL_ATOM_DECL(eui64); \ + GLOBAL_ATOM_DECL(events); \ + GLOBAL_ATOM_DECL(exclusiveaddruse); \ + GLOBAL_ATOM_DECL(explicit_eor); \ + GLOBAL_ATOM_DECL(faith); \ + GLOBAL_ATOM_DECL(false); \ + GLOBAL_ATOM_DECL(family); \ + GLOBAL_ATOM_DECL(fastroute); \ + GLOBAL_ATOM_DECL(fast_retrans); \ + GLOBAL_ATOM_DECL(fin_wait_1); \ + GLOBAL_ATOM_DECL(fin_wait_2); \ + GLOBAL_ATOM_DECL(flags); \ + GLOBAL_ATOM_DECL(flowinfo); \ + GLOBAL_ATOM_DECL(fragment_interleave); \ + GLOBAL_ATOM_DECL(freebind); \ + GLOBAL_ATOM_DECL(frelay); \ + GLOBAL_ATOM_DECL(get_overlapped_result); \ + GLOBAL_ATOM_DECL(get_peer_addr_info); \ + GLOBAL_ATOM_DECL(hatype); \ + GLOBAL_ATOM_DECL(hdrincl); \ + GLOBAL_ATOM_DECL(hmac_ident); \ + GLOBAL_ATOM_DECL(hoplimit); \ + GLOBAL_ATOM_DECL(hopopts); \ + GLOBAL_ATOM_DECL(host); \ + GLOBAL_ATOM_DECL(icmp); \ + GLOBAL_ATOM_DECL(icmp6); \ + GLOBAL_ATOM_DECL(ieee802); \ + GLOBAL_ATOM_DECL(ieee1394); \ + GLOBAL_ATOM_DECL(ifindex); \ + GLOBAL_ATOM_DECL(igmp); \ + GLOBAL_ATOM_DECL(implink); \ + GLOBAL_ATOM_DECL(index); \ + GLOBAL_ATOM_DECL(inet); \ + GLOBAL_ATOM_DECL(inet6); \ + GLOBAL_ATOM_DECL(infiniband); \ + GLOBAL_ATOM_DECL(info); \ + GLOBAL_ATOM_DECL(initmsg); \ + GLOBAL_ATOM_DECL(invalid); \ + GLOBAL_ATOM_DECL(integer_range); \ + GLOBAL_ATOM_DECL(iov); \ + GLOBAL_ATOM_DECL(ip); \ + GLOBAL_ATOM_DECL(ipcomp_level); \ + GLOBAL_ATOM_DECL(ipip); \ + GLOBAL_ATOM_DECL(iplevel); \ + GLOBAL_ATOM_DECL(ipv6); \ + GLOBAL_ATOM_DECL(irq); \ + GLOBAL_ATOM_DECL(i_want_mapped_v4_addr); \ + GLOBAL_ATOM_DECL(join_group); \ + GLOBAL_ATOM_DECL(keepalive); \ + GLOBAL_ATOM_DECL(keepcnt); \ + GLOBAL_ATOM_DECL(keepidle); \ + GLOBAL_ATOM_DECL(keepintvl); \ + GLOBAL_ATOM_DECL(kernel); \ + GLOBAL_ATOM_DECL(knowsepoch); \ + GLOBAL_ATOM_DECL(last_ack); \ + GLOBAL_ATOM_DECL(leave_group); \ + GLOBAL_ATOM_DECL(level); \ + GLOBAL_ATOM_DECL(linger); \ + GLOBAL_ATOM_DECL(link); \ + GLOBAL_ATOM_DECL(link0); \ + GLOBAL_ATOM_DECL(link1); \ + GLOBAL_ATOM_DECL(link2); \ + GLOBAL_ATOM_DECL(listen); \ + GLOBAL_ATOM_DECL(local); \ + GLOBAL_ATOM_DECL(localtlk); \ + GLOBAL_ATOM_DECL(local_auth_chunks); \ + GLOBAL_ATOM_DECL(loopback); \ + GLOBAL_ATOM_DECL(lowdelay); \ + GLOBAL_ATOM_DECL(lower_up); \ + GLOBAL_ATOM_DECL(mark); \ + GLOBAL_ATOM_DECL(master); \ + GLOBAL_ATOM_DECL(max); \ + GLOBAL_ATOM_DECL(maxburst); \ + GLOBAL_ATOM_DECL(maxdg); \ + GLOBAL_ATOM_DECL(maxseg); \ + GLOBAL_ATOM_DECL(max_msg_size); \ + GLOBAL_ATOM_DECL(md5sig); \ + GLOBAL_ATOM_DECL(mem_end); \ + GLOBAL_ATOM_DECL(mem_start); \ + GLOBAL_ATOM_DECL(metricom); \ + GLOBAL_ATOM_DECL(mincost); \ + GLOBAL_ATOM_DECL(minttl); \ + GLOBAL_ATOM_DECL(min_rtt); \ + GLOBAL_ATOM_DECL(monitor); \ + GLOBAL_ATOM_DECL(more); \ + GLOBAL_ATOM_DECL(msfilter); \ + GLOBAL_ATOM_DECL(mss); \ + GLOBAL_ATOM_DECL(mtu); \ + GLOBAL_ATOM_DECL(mtu_discover); \ + GLOBAL_ATOM_DECL(multicast); \ + GLOBAL_ATOM_DECL(multicast_all); \ + GLOBAL_ATOM_DECL(multicast_hops); \ + GLOBAL_ATOM_DECL(multicast_if); \ + GLOBAL_ATOM_DECL(multicast_loop); \ + GLOBAL_ATOM_DECL(multicast_ttl); \ + GLOBAL_ATOM_DECL(name); \ + GLOBAL_ATOM_DECL(netns); \ + GLOBAL_ATOM_DECL(netrom); \ + GLOBAL_ATOM_DECL(nlen); \ + GLOBAL_ATOM_DECL(noarp); \ + GLOBAL_ATOM_DECL(nodelay); \ + GLOBAL_ATOM_DECL(nodefrag); \ + GLOBAL_ATOM_DECL(nogroup); \ + GLOBAL_ATOM_DECL(none); \ + GLOBAL_ATOM_DECL(noopt); \ + GLOBAL_ATOM_DECL(nopush); \ + GLOBAL_ATOM_DECL(nosignal); \ + GLOBAL_ATOM_DECL(notrailers); \ + GLOBAL_ATOM_DECL(not_bound); \ + GLOBAL_ATOM_DECL(not_found); \ + GLOBAL_ATOM_DECL(num_general_errors); \ + GLOBAL_ATOM_DECL(not_owner); \ + GLOBAL_ATOM_DECL(num_threads); \ + GLOBAL_ATOM_DECL(num_unexpected_accepts); \ + GLOBAL_ATOM_DECL(num_unexpected_connects); \ + GLOBAL_ATOM_DECL(num_unexpected_reads); \ + GLOBAL_ATOM_DECL(num_unexpected_writes); \ + GLOBAL_ATOM_DECL(num_unknown_cmds); \ + GLOBAL_ATOM_DECL(oactive); \ + GLOBAL_ATOM_DECL(off); \ + GLOBAL_ATOM_DECL(ok); \ + GLOBAL_ATOM_DECL(on); \ + GLOBAL_ATOM_DECL(oob); \ + GLOBAL_ATOM_DECL(oobinline); \ + GLOBAL_ATOM_DECL(options); \ + GLOBAL_ATOM_DECL(origdstaddr); \ + GLOBAL_ATOM_DECL(otherhost); \ + GLOBAL_ATOM_DECL(outgoing); \ + GLOBAL_ATOM_DECL(packet); \ + GLOBAL_ATOM_DECL(partial_delivery_point); \ + GLOBAL_ATOM_DECL(passcred); \ + GLOBAL_ATOM_DECL(path); \ + GLOBAL_ATOM_DECL(peek); \ + GLOBAL_ATOM_DECL(peek_off); \ + GLOBAL_ATOM_DECL(peer_addr_params); \ + GLOBAL_ATOM_DECL(peer_auth_chunks); \ + GLOBAL_ATOM_DECL(peercred); \ + GLOBAL_ATOM_DECL(pktinfo); \ + GLOBAL_ATOM_DECL(pktoptions); \ + GLOBAL_ATOM_DECL(pkttype); \ + GLOBAL_ATOM_DECL(pointopoint); \ + GLOBAL_ATOM_DECL(port); \ + GLOBAL_ATOM_DECL(portrange); \ + GLOBAL_ATOM_DECL(portsel); \ + GLOBAL_ATOM_DECL(ppromisc); \ + GLOBAL_ATOM_DECL(primary_addr); \ + GLOBAL_ATOM_DECL(prim_file); \ + GLOBAL_ATOM_DECL(priority); \ + GLOBAL_ATOM_DECL(promisc); \ + GLOBAL_ATOM_DECL(pronet); \ + GLOBAL_ATOM_DECL(protocol); \ + GLOBAL_ATOM_DECL(pup); \ + GLOBAL_ATOM_DECL(raw); \ + GLOBAL_ATOM_DECL(rcvbuf); \ + GLOBAL_ATOM_DECL(rcvbufforce); \ + GLOBAL_ATOM_DECL(rcvlowat); \ + GLOBAL_ATOM_DECL(rcvtimeo); \ + GLOBAL_ATOM_DECL(rcv_buf); \ + GLOBAL_ATOM_DECL(rcv_wnd); \ + GLOBAL_ATOM_DECL(rdm); \ + GLOBAL_ATOM_DECL(read_byte); \ + GLOBAL_ATOM_DECL(read_fails); \ + GLOBAL_ATOM_DECL(read_pkg); \ + GLOBAL_ATOM_DECL(read_tries); \ + GLOBAL_ATOM_DECL(read_waits); \ + GLOBAL_ATOM_DECL(recv); \ + GLOBAL_ATOM_DECL(recvdstaddr); \ + GLOBAL_ATOM_DECL(recverr); \ + GLOBAL_ATOM_DECL(recvfrom); \ + GLOBAL_ATOM_DECL(recvhoplimit); \ + GLOBAL_ATOM_DECL(recvif); \ + GLOBAL_ATOM_DECL(recvmsg); \ + GLOBAL_ATOM_DECL(recvopts); \ + GLOBAL_ATOM_DECL(recvorigdstaddr); \ + GLOBAL_ATOM_DECL(recvpktinfo); \ + GLOBAL_ATOM_DECL(recvtclass); \ + GLOBAL_ATOM_DECL(recvtos); \ + GLOBAL_ATOM_DECL(recvttl); \ + GLOBAL_ATOM_DECL(reliability); \ + GLOBAL_ATOM_DECL(renaming); \ + GLOBAL_ATOM_DECL(reset_streams); \ + GLOBAL_ATOM_DECL(retopts); \ + GLOBAL_ATOM_DECL(reuseaddr); \ + GLOBAL_ATOM_DECL(reuseport); \ + GLOBAL_ATOM_DECL(rights); \ + GLOBAL_ATOM_DECL(rm); \ + GLOBAL_ATOM_DECL(router_alert); \ + GLOBAL_ATOM_DECL(rthdr); \ + GLOBAL_ATOM_DECL(rtoinfo); \ + GLOBAL_ATOM_DECL(rtt); \ + GLOBAL_ATOM_DECL(running); \ + GLOBAL_ATOM_DECL(rxq_ovfl); \ + GLOBAL_ATOM_DECL(scope_id); \ + GLOBAL_ATOM_DECL(sctp); \ + GLOBAL_ATOM_DECL(sec); \ + GLOBAL_ATOM_DECL(select); \ + GLOBAL_ATOM_DECL(select_failed); \ + GLOBAL_ATOM_DECL(select_sent); \ + GLOBAL_ATOM_DECL(send); \ + GLOBAL_ATOM_DECL(sendfile); \ + GLOBAL_ATOM_DECL(sendfile_byte); \ + GLOBAL_ATOM_DECL(sendfile_deferred_close); \ + GLOBAL_ATOM_DECL(sendfile_fails); \ + GLOBAL_ATOM_DECL(sendfile_max); \ + GLOBAL_ATOM_DECL(sendfile_pkg); \ + GLOBAL_ATOM_DECL(sendfile_pkg_max); \ + GLOBAL_ATOM_DECL(sendfile_tries); \ + GLOBAL_ATOM_DECL(sendfile_waits); \ + GLOBAL_ATOM_DECL(sendmsg); \ + GLOBAL_ATOM_DECL(sendsrcaddr); \ + GLOBAL_ATOM_DECL(sendto); \ + GLOBAL_ATOM_DECL(seqpacket); \ + GLOBAL_ATOM_DECL(setfib); \ + GLOBAL_ATOM_DECL(set_peer_primary_addr); \ + GLOBAL_ATOM_DECL(simplex); \ + GLOBAL_ATOM_DECL(slave); \ + GLOBAL_ATOM_DECL(slen); \ + GLOBAL_ATOM_DECL(sndbuf); \ + GLOBAL_ATOM_DECL(sndbufforce); \ + GLOBAL_ATOM_DECL(sndlowat); \ + GLOBAL_ATOM_DECL(sndtimeo); \ + GLOBAL_ATOM_DECL(snd_wnd); \ + GLOBAL_ATOM_DECL(sockaddr); \ + GLOBAL_ATOM_DECL(socket); \ + GLOBAL_ATOM_DECL(spec_dst); \ + GLOBAL_ATOM_DECL(staticarp); \ + GLOBAL_ATOM_DECL(state); \ + GLOBAL_ATOM_DECL(status); \ + GLOBAL_ATOM_DECL(stream); \ + GLOBAL_ATOM_DECL(syncnt); \ + GLOBAL_ATOM_DECL(syn_rcvd); \ + GLOBAL_ATOM_DECL(syn_retrans); \ + GLOBAL_ATOM_DECL(syn_sent); \ + GLOBAL_ATOM_DECL(tclass); \ + GLOBAL_ATOM_DECL(tcp); \ + GLOBAL_ATOM_DECL(throughput); \ + GLOBAL_ATOM_DECL(timestamp); \ + GLOBAL_ATOM_DECL(tos); \ + GLOBAL_ATOM_DECL(transparent); \ + GLOBAL_ATOM_DECL(timeout); \ + GLOBAL_ATOM_DECL(timeout_episodes); \ + GLOBAL_ATOM_DECL(timestamp_enabled); \ + GLOBAL_ATOM_DECL(time_wait); \ + GLOBAL_ATOM_DECL(true); \ + GLOBAL_ATOM_DECL(trunc); \ + GLOBAL_ATOM_DECL(ttl); \ + GLOBAL_ATOM_DECL(tunnel); \ + GLOBAL_ATOM_DECL(tunnel6); \ + GLOBAL_ATOM_DECL(txqlen); \ + GLOBAL_ATOM_DECL(type); \ + GLOBAL_ATOM_DECL(udp); \ + GLOBAL_ATOM_DECL(unblock_source); \ + GLOBAL_ATOM_DECL(undefined); \ + GLOBAL_ATOM_DECL(unicast_hops); \ + GLOBAL_ATOM_DECL(unknown); \ + GLOBAL_ATOM_DECL(unspec); \ + GLOBAL_ATOM_DECL(up); \ + GLOBAL_ATOM_DECL(update_accept_context); \ + GLOBAL_ATOM_DECL(update_connect_context); \ + GLOBAL_ATOM_DECL(usec); \ + GLOBAL_ATOM_DECL(user); \ + GLOBAL_ATOM_DECL(user_timeout); \ + GLOBAL_ATOM_DECL(use_ext_recvinfo); \ + GLOBAL_ATOM_DECL(use_min_mtu); \ + GLOBAL_ATOM_DECL(use_registry); \ + GLOBAL_ATOM_DECL(value); \ + GLOBAL_ATOM_DECL(void); \ + GLOBAL_ATOM_DECL(v6only); \ + GLOBAL_ATOM_DECL(write_byte); \ + GLOBAL_ATOM_DECL(write_fails); \ + GLOBAL_ATOM_DECL(write_pkg); \ + GLOBAL_ATOM_DECL(write_tries); \ + GLOBAL_ATOM_DECL(write_waits); \ + GLOBAL_ATOM_DECL(zero) - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); - read = sock_recv(descP->sock, buf.data, buf.size, flags); - if (ESOCK_IS_ERROR(read)) { - save_errno = sock_errno(); - } else { - save_errno = 0; // The value does not actually matter in this case - } - SSDBG( descP, ("SOCKET", - "esock_recv {%d} -> read: %ld (%d)\r\n", - descP->sock, (long) read, save_errno) ); +/* *** Global error reason atoms *** */ +#define GLOBAL_ERROR_REASON_ATOMS \ + GLOBAL_ATOM_DECL(create_accept_socket); \ + GLOBAL_ATOM_DECL(eagain); \ + GLOBAL_ATOM_DECL(einval); \ + GLOBAL_ATOM_DECL(select_read); \ + GLOBAL_ATOM_DECL(select_write) - return recv_check_result(env, descP, read, len, save_errno, - &buf, sockRef, recvRef); -} -#endif // #ifndef __WIN32__ +#define GLOBAL_ATOM_DECL(A) ERL_NIF_TERM esock_atom_##A +GLOBAL_ATOMS; +GLOBAL_ERROR_REASON_ATOMS; +#undef GLOBAL_ATOM_DECL +ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket') +/* *** Local atoms *** */ +#define LOCAL_ATOMS \ + LOCAL_ATOM_DECL(accepting); \ + LOCAL_ATOM_DECL(adaptation_layer); \ + LOCAL_ATOM_DECL(add); \ + LOCAL_ATOM_DECL(addr_unreach); \ + LOCAL_ATOM_DECL(address); \ + LOCAL_ATOM_DECL(adm_prohibited); \ + LOCAL_ATOM_DECL(association); \ + LOCAL_ATOM_DECL(assoc_id); \ + LOCAL_ATOM_DECL(atmark); \ + LOCAL_ATOM_DECL(authentication); \ + LOCAL_ATOM_DECL(boolean); \ + LOCAL_ATOM_DECL(bound); \ + LOCAL_ATOM_DECL(bufsz); \ + LOCAL_ATOM_DECL(close); \ + LOCAL_ATOM_DECL(closing); \ + LOCAL_ATOM_DECL(code); \ + LOCAL_ATOM_DECL(cookie_life); \ + LOCAL_ATOM_DECL(counter_wrap); \ + LOCAL_ATOM_DECL(ctype); \ + LOCAL_ATOM_DECL(data_io); \ + LOCAL_ATOM_DECL(debug_filename); \ + LOCAL_ATOM_DECL(del); \ + LOCAL_ATOM_DECL(dest_unreach); \ + LOCAL_ATOM_DECL(do); \ + LOCAL_ATOM_DECL(dont); \ + LOCAL_ATOM_DECL(dtor); \ + LOCAL_ATOM_DECL(eei); \ + LOCAL_ATOM_DECL(exclude); \ + LOCAL_ATOM_DECL(false); \ + LOCAL_ATOM_DECL(frag_needed); \ + LOCAL_ATOM_DECL(gifaddr); \ + LOCAL_ATOM_DECL(gifbrdaddr); \ + LOCAL_ATOM_DECL(gifconf); \ + LOCAL_ATOM_DECL(gifdstaddr); \ + LOCAL_ATOM_DECL(gifflags); \ + LOCAL_ATOM_DECL(gifhwaddr); \ + LOCAL_ATOM_DECL(gifindex); \ + LOCAL_ATOM_DECL(gifmap); \ + LOCAL_ATOM_DECL(gifmtu); \ + LOCAL_ATOM_DECL(gifname); \ + LOCAL_ATOM_DECL(gifnetmask); \ + LOCAL_ATOM_DECL(giftxqlen); \ + LOCAL_ATOM_DECL(host_unknown); \ + LOCAL_ATOM_DECL(host_unreach); \ + LOCAL_ATOM_DECL(how); \ + LOCAL_ATOM_DECL(in4_sockaddr); \ + LOCAL_ATOM_DECL(in6_sockaddr); \ + LOCAL_ATOM_DECL(include); \ + LOCAL_ATOM_DECL(initial); \ + LOCAL_ATOM_DECL(interface); \ + LOCAL_ATOM_DECL(integer); \ + LOCAL_ATOM_DECL(ioctl_flags); \ + LOCAL_ATOM_DECL(ioctl_requests); \ + LOCAL_ATOM_DECL(iov_max); \ + LOCAL_ATOM_DECL(iow); \ + LOCAL_ATOM_DECL(io_backend); \ + LOCAL_ATOM_DECL(io_num_threads); \ + LOCAL_ATOM_DECL(listening); \ + LOCAL_ATOM_DECL(local_addr); \ + LOCAL_ATOM_DECL(local_rwnd); \ + LOCAL_ATOM_DECL(map); \ + LOCAL_ATOM_DECL(max); \ + LOCAL_ATOM_DECL(max_attempts); \ + LOCAL_ATOM_DECL(max_init_timeo); \ + LOCAL_ATOM_DECL(max_instreams); \ + LOCAL_ATOM_DECL(asocmaxrxt); \ + LOCAL_ATOM_DECL(min); \ + LOCAL_ATOM_DECL(missing); \ + LOCAL_ATOM_DECL(mode); \ + LOCAL_ATOM_DECL(msg); \ + LOCAL_ATOM_DECL(msg_flags); \ + LOCAL_ATOM_DECL(mtu); \ + LOCAL_ATOM_DECL(multiaddr); \ + LOCAL_ATOM_DECL(net_unknown); \ + LOCAL_ATOM_DECL(net_unreach); \ + LOCAL_ATOM_DECL(nogroup); \ + LOCAL_ATOM_DECL(none); \ + LOCAL_ATOM_DECL(noroute); \ + LOCAL_ATOM_DECL(not_neighbour); \ + LOCAL_ATOM_DECL(nread); \ + LOCAL_ATOM_DECL(nspace); \ + LOCAL_ATOM_DECL(nwrite); \ + LOCAL_ATOM_DECL(null); \ + LOCAL_ATOM_DECL(num_acceptors); \ + LOCAL_ATOM_DECL(num_cnt_bits); \ + LOCAL_ATOM_DECL(num_dinet); \ + LOCAL_ATOM_DECL(num_dinet6); \ + LOCAL_ATOM_DECL(num_dlocal); \ + LOCAL_ATOM_DECL(num_outstreams); \ + LOCAL_ATOM_DECL(number_peer_destinations); \ + LOCAL_ATOM_DECL(num_pip); \ + LOCAL_ATOM_DECL(num_psctp); \ + LOCAL_ATOM_DECL(num_ptcp); \ + LOCAL_ATOM_DECL(num_pudp); \ + LOCAL_ATOM_DECL(num_readers); \ + LOCAL_ATOM_DECL(num_sockets); \ + LOCAL_ATOM_DECL(num_tdgrams); \ + LOCAL_ATOM_DECL(num_tseqpkgs); \ + LOCAL_ATOM_DECL(num_tstreams); \ + LOCAL_ATOM_DECL(num_writers); \ + LOCAL_ATOM_DECL(offender); \ + LOCAL_ATOM_DECL(onoff); \ + LOCAL_ATOM_DECL(options); \ + LOCAL_ATOM_DECL(origin); \ + LOCAL_ATOM_DECL(otp); \ + LOCAL_ATOM_DECL(otp_socket_option);\ + LOCAL_ATOM_DECL(owner); \ + LOCAL_ATOM_DECL(partial_delivery); \ + LOCAL_ATOM_DECL(peer_error); \ + LOCAL_ATOM_DECL(peer_rwnd); \ + LOCAL_ATOM_DECL(pkt_toobig); \ + LOCAL_ATOM_DECL(policy_fail); \ + LOCAL_ATOM_DECL(port); \ + LOCAL_ATOM_DECL(port_unreach); \ + LOCAL_ATOM_DECL(probe); \ + LOCAL_ATOM_DECL(protocols); \ + LOCAL_ATOM_DECL(rcvall); \ + LOCAL_ATOM_DECL(rcvall_igmpmcast); \ + LOCAL_ATOM_DECL(rcvall_mcast); \ + LOCAL_ATOM_DECL(rcvctrlbuf); \ + LOCAL_ATOM_DECL(read); \ + LOCAL_ATOM_DECL(read_pkg_max); \ + LOCAL_ATOM_DECL(read_waits); \ + LOCAL_ATOM_DECL(read_write); \ + LOCAL_ATOM_DECL(registry); \ + LOCAL_ATOM_DECL(reject_route); \ + LOCAL_ATOM_DECL(remote); \ + LOCAL_ATOM_DECL(remote_addr); \ + LOCAL_ATOM_DECL(rstates); \ + LOCAL_ATOM_DECL(selected); \ + LOCAL_ATOM_DECL(sender_dry); \ + LOCAL_ATOM_DECL(send_failure); \ + LOCAL_ATOM_DECL(shutdown); \ + LOCAL_ATOM_DECL(sifaddr); \ + LOCAL_ATOM_DECL(sifbrdaddr); \ + LOCAL_ATOM_DECL(sifdstaddr); \ + LOCAL_ATOM_DECL(sifflags); \ + LOCAL_ATOM_DECL(sifmtu); \ + LOCAL_ATOM_DECL(sifnetmask); \ + LOCAL_ATOM_DECL(siftxqlen); \ + LOCAL_ATOM_DECL(slist); \ + LOCAL_ATOM_DECL(sndctrlbuf); \ + LOCAL_ATOM_DECL(socket_debug); \ + LOCAL_ATOM_DECL(socket_level); \ + LOCAL_ATOM_DECL(socket_option); \ + LOCAL_ATOM_DECL(sourceaddr); \ + LOCAL_ATOM_DECL(tcp_info); \ + LOCAL_ATOM_DECL(time_exceeded); \ + LOCAL_ATOM_DECL(true); \ + LOCAL_ATOM_DECL(txstatus); \ + LOCAL_ATOM_DECL(txtime); \ + LOCAL_ATOM_DECL(want); \ + LOCAL_ATOM_DECL(write); \ + LOCAL_ATOM_DECL(write_pkg_max); \ + LOCAL_ATOM_DECL(wstates); \ + LOCAL_ATOM_DECL(zerocopy) -/* ---------------------------------------------------------------------- - * nif_recvfrom - * - * Description: - * Receive a message on a socket. - * Normally used only on a (un-) connected socket! - * If a buffer size = 0 is specified, then the we will use the default - * buffer size for this socket (whatever has been configured). - * - * Arguments: - * Socket (ref) - NIF resource reference() to the socket descriptor. - * BufSz - integer() ize of the buffer - * into which we put the received message. - * Flags - Receive flags; integer(). - * RecvRef - A unique reference() id for this recv request. - * - * - * - * How do we handle if the peek flag is set? We need to basically keep - * track of if we expect any data from the read. Regardless of the - * number of bytes we try to read. - * - * +/* Local error reason atoms + * Keep this (commented) for future use... */ +/* +#define LOCAL_ERROR_REASON_ATOMS \ + LOCAL_ATOM_DECL(select_read); \ + LOCAL_ATOM_DECL(select_write) +*/ +#define LOCAL_ATOM_DECL(LA) static ERL_NIF_TERM atom_##LA +LOCAL_ATOMS; +// LOCAL_ERROR_REASON_ATOMS; +#undef LOCAL_ATOM_DECL -static -ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, recvRef; - ErlNifUInt64 elen; - ssize_t len; /* ssize_t due to the return type of recvfrom() */ - int flags; - ERL_NIF_TERM res; - BOOLEAN_T a1ok; - - ESOCK_ASSERT( argc == 4 ); - - SGDBG( ("SOCKET", "nif_recvfrom -> entry with argc: %d\r\n", argc) ); - - sockRef = argv[0]; // We need this in case we send abort (to the caller) - recvRef = argv[3]; - - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - return enif_make_badarg(env); - } - - /* Extract arguments and perform preliminary validation */ - - if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { - return enif_make_badarg(env); - } - - if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) || - (! GET_INT(env, argv[2], &flags))) { - if ((! IS_INTEGER(env, argv[1])) || - (! IS_INTEGER(env, argv[2]))) - return enif_make_badarg(env); - - if (! a1ok) - return esock_make_error_integer_range(env, argv[1]); - return - esock_make_error_integer_range(env, argv[2]); - } - len = (ssize_t) elen; - if (elen != (ErlNifUInt64) len) - return esock_make_error_integer_range(env, elen); - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", "nif_recvfrom(%T), {%d,0x%X} ->" - "\r\n recvRef: %T" - "\r\n len: %ld" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->readState, - recvRef, (long) len, flags) ); - - /* - * We need to handle the case when another process tries - * to receive at the same time. - * If the current recv could not read its entire package - * this time (resulting in an select). The read of the - * other process must be made to wait until current - * is done! - * Basically, we need a read queue! - * - * A 'reading' field (boolean), which is set if we did - * not manage to read the entire message and reset every - * time we do. - * - */ - - res = esock_recvfrom(env, descP, sockRef, recvRef, len, flags); +/* *** Sockets *** */ +static ErlNifResourceType* esocks; +static ErlNifResourceTypeInit esockInit = { + esock_dtor, + esock_stop, + (ErlNifResourceDown*) esock_down +}; - SSDBG( descP, ("SOCKET", "nif_recvfrom(%T) -> done" - "\r\n", sockRef) ); +// Initiated when the nif is loaded +static ESockData data; - MUNLOCK(descP->readMtx); +/* Jump table for the I/O backend (async or sync) */ +static ESockIoBackend io_backend = {0}; + + +/* This, the test for NULL), is temporary until we have a win stub */ +#define ESOCK_IO_INIT(NUMT) \ + ((io_backend.init != NULL) ? \ + io_backend.init((NUMT), &data) : ESOCK_IO_ERR_UNSUPPORTED) +#define ESOCK_IO_FIN() \ + ((io_backend.finish != NULL) ? \ + io_backend.finish() : ESOCK_IO_ERR_UNSUPPORTED) + +#define ESOCK_IO_INFO(ENV) \ + ((io_backend.info != NULL) ? \ + io_backend.info((ENV)) : MKEMA((ENV))) +#define ESOCK_IO_CMD(ENV, CMD, CDATA) \ + ((io_backend.cmd != NULL) ? \ + io_backend.cmd((ENV), (CMD), (CDATA)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SUPPORTS_0(ENV) \ + ((io_backend.supports_0 != NULL) ? \ + io_backend.supports_0((ENV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SUPPORTS_1(ENV, KEY) \ + ((io_backend.supports_1 != NULL) ? \ + io_backend.supports_1((ENV), (KEY)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) + +#define ESOCK_IO_OPEN_WITH_FD(ENV, FD, EOPTS) \ + ((io_backend.open_with_fd != NULL) ? \ + io_backend.open_with_fd((ENV), (FD), (EOPTS), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_OPEN_PLAIN(ENV, D, T, P, EOPTS) \ + ((io_backend.open_plain != NULL) ? \ + io_backend.open_plain((ENV), (D), \ + (T), (P), (EOPTS), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_BIND(ENV, D, SAP, AL) \ + ((io_backend.bind != NULL) ? \ + io_backend.bind((ENV), (D), (SAP), (AL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CONNECT(ENV, D, SR, CR, AP, AL) \ + ((io_backend.connect != NULL) ? \ + io_backend.connect((ENV), (D), \ + (SR), (CR), (AP), (AL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_LISTEN(ENV, D, BL) \ + ((io_backend.listen != NULL) ? \ + io_backend.listen((ENV), (D), (BL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_ACCEPT(ENV, D, SR, AR) \ + ((io_backend.accept != NULL) ? \ + io_backend.accept((ENV), (D), (SR), (AR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SEND(ENV, D, SR, RF, L, F) \ + ((io_backend.send != NULL) ? \ + io_backend.send((ENV), (D), \ + (SR), (RF), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDTO(ENV, D, \ + SOCKR, SENDR, \ + DP, F, TAP, TAL) \ + ((io_backend.sendto != NULL) ? \ + io_backend.sendto((ENV), (D), \ + (SOCKR), (SENDR), \ + (DP), (F), (TAP), (TAL)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDMSG(ENV, D, \ + SOCKR, SENDR, EM, F, EIOV) \ + ((io_backend.sendmsg != NULL) ? \ + io_backend.sendmsg((ENV), (D), \ + (SOCKR), (SENDR), \ + (EM), (F), (EIOV), &data) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_START(ENV, D, \ + SOR, SNR, \ + O, CN, FR) \ + ((io_backend.sendfile_start != NULL) ? \ + io_backend.sendfile_start((ENV), (D), \ + (SOR), (SNR), \ + (O), (CN), (FR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_CONT(ENV, D, \ + SOR, SNR, \ + O, CP) \ + ((io_backend.sendfile_cont != NULL) ? \ + io_backend.sendfile_cont((ENV), (D), \ + (SOR), (SNR), \ + (O), (CP)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SENDFILE_DC(ENV, D) \ + ((io_backend.sendfile_dc != NULL) ? \ + io_backend.sendfile_dc((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECV(ENV, D, \ + SR, RR, L, F) \ + ((io_backend.recv != NULL) ? \ + io_backend.recv((ENV), (D), \ + (SR), (RR), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECVFROM(ENV, D, \ + SR, RR, L, F) \ + ((io_backend.recvfrom != NULL) ? \ + io_backend.recvfrom((ENV), (D), \ + (SR), (RR), (L), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_RECVMSG(ENV, D, \ + SR, RR, BL, CL, F) \ + ((io_backend.recvmsg != NULL) ? \ + io_backend.recvmsg((ENV), (D), \ + (SR), (RR), \ + (BL), (CL), (F)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CLOSE(ENV, D) \ + ((io_backend.close != NULL) ? \ + io_backend.close((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_FIN_CLOSE(ENV, D) \ + ((io_backend.fin_close != NULL) ? \ + io_backend.fin_close((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SHUTDOWN(ENV, D, H) \ + ((io_backend.shutdown != NULL) ? \ + io_backend.shutdown((ENV), (D), (H)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SOCKNAME(ENV, D) \ + ((io_backend.sockname != NULL) ? \ + io_backend.sockname((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_PEERNAME(ENV, D) \ + ((io_backend.peername != NULL) ? \ + io_backend.peername((ENV), (D)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_CONNECT(ENV, D, OR) \ + ((io_backend.cancel_connect != NULL) ? \ + io_backend.cancel_connect((ENV), (D), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_ACCEPT(ENV, D, SR, OR) \ + ((io_backend.cancel_accept != NULL) ? \ + io_backend.cancel_accept((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_SEND(ENV, D, SR, OR) \ + ((io_backend.cancel_send != NULL) ? \ + io_backend.cancel_send((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_CANCEL_RECV(ENV, D, SR, OR) \ + ((io_backend.cancel_recv != NULL) ? \ + io_backend.cancel_recv((ENV), (D), (SR), (OR)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT(ENV, D, L, O, EV) \ + ((io_backend.setopt != NULL) ? \ + io_backend.setopt((ENV), (D), (L), (O), (EV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT_NATIVE(ENV, D, L, O, EV) \ + ((io_backend.setopt_native != NULL) ? \ + io_backend.setopt_native((ENV), (D), (L), (O), (EV)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_SETOPT_OTP(ENV, D, L, O) \ + ((io_backend.setopt_otp != NULL) ? \ + io_backend.setopt_otp((ENV), (D), (L), (O)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT(ENV, D, L, O) \ + ((io_backend.getopt != NULL) ? \ + io_backend.getopt((ENV), (D), (L), (O)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT_NATIVE(ENV, D, L, O, VS) \ + ((io_backend.getopt_native != NULL) ? \ + io_backend.getopt_native((ENV), (D), (L), (O), (VS)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_GETOPT_OTP(ENV, D, EO) \ + ((io_backend.getopt_otp != NULL) ? \ + io_backend.getopt_otp((ENV), (D), (EO)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_2(ENV, D, R) \ + ((io_backend.ioctl_2 != NULL) ? \ + io_backend.ioctl_2((ENV), (D), (R)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_3(ENV, D, R, A) \ + ((io_backend.ioctl_3 != NULL) ? \ + io_backend.ioctl_3((ENV), (D), (R), (A)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) +#define ESOCK_IO_IOCTL_4(ENV, D, R, A1, A2) \ + ((io_backend.ioctl_4 != NULL) ? \ + io_backend.ioctl_4((ENV), (D), (R), (A1), (A2)) : \ + enif_raise_exception((ENV), MKA((ENV), "notsup"))) + +#define ESOCK_IO_DTOR(ENV, D) \ + ((io_backend.dtor != NULL) ? \ + io_backend.dtor((ENV), (D)) : ((void) (D))) +#define ESOCK_IO_STOP(ENV, D) \ + ((io_backend.stop != NULL) ? \ + io_backend.stop((ENV), (D)) : ((void) (D))) +#define ESOCK_IO_DOWN(ENV, D, PP, MP) \ + ((io_backend.down != NULL) ? \ + io_backend.down((ENV), (D), (PP), (MP)) : ((void) (D))) - return res; -#endif // #ifdef __WIN32__ #else -} -/* The (read) buffer handling *must* be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... +/* ------------------------------------------------------------------------ + * Socket option tables and handling */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t len, - int flags) -{ - ESockAddress fromAddr; - SOCKLEN_T addrLen; - ssize_t read; - int save_errno; - ErlNifBinary buf; - ERL_NIF_TERM readerCheck; - size_t bufSz = (len != 0 ? len : descP->rBufSz); - - SSDBG( descP, ("SOCKET", "esock_recvfrom {%d} -> entry with" - "\r\n bufSz: %d" - "\r\n", descP->sock, bufSz) ); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); - - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } - - /* Allocate a buffer: - * Either as much as we want to read or (if zero (0)) use the "default" - * size (what has been configured). - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); - - addrLen = sizeof(fromAddr); - sys_memzero((char*) &fromAddr, addrLen); - - read = sock_recvfrom(descP->sock, buf.data, buf.size, flags, - &fromAddr.sa, &addrLen); - if (ESOCK_IS_ERROR(read)) - save_errno = sock_errno(); - else - save_errno = 0; // The value does not actually matter in this case - - return recvfrom_check_result(env, descP, read, save_errno, - &buf, &fromAddr, addrLen, - sockRef, recvRef); -} -#endif // #ifndef __WIN32__ +/* SO_* options -------------------------------------------------------- */ - -/* ---------------------------------------------------------------------- - * nif_recvmsg - * - * Description: - * Receive a message on a socket. - * Normally used only on a (un-) connected socket! - * If a buffer size = 0 is specified, then we will use the default - * buffer size for this socket (whatever has been configured). - * If ctrl (buffer) size = 0 is specified, then the default ctrl - * (buffer) size is used (1024). - * - * Arguments: - * Socket (ref) - NIF resource reference() to the socket descriptor. - * BufSz - Size of the buffer into which we put the received message; - * integer(). - * CtrlSz - Size of the ctrl (buffer) into which we put the received - * ancillary data; integer(). - * Flags - Receive flags; integer(). - * RecvRef - A unique reference() id for this (send) request. - * - * - * - * How do we handle if the peek flag is set? We need to basically keep - * track of if we expect any data from the read. Regardless of the - * number of bytes we try to read. - * - * - */ - -static -ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); +static struct ESockOpt optLevelSocket[] = + { + { +#ifdef SO_ACCEPTCONN + SO_ACCEPTCONN, + esock_setopt_bool_opt, esock_getopt_bool_opt, #else - ESockDescriptor* descP; - ERL_NIF_TERM sockRef, recvRef; - ErlNifUInt64 eBufSz, eCtrlSz; - ssize_t bufSz, ctrlSz; - int flags; - ERL_NIF_TERM res; - BOOLEAN_T a1ok, a2ok; - - ESOCK_ASSERT( argc == 5 ); + 0, NULL, NULL, +#endif + &esock_atom_acceptconn}, - SGDBG( ("SOCKET", "nif_recvmsg -> entry with argc: %d\r\n", argc) ); + {0, NULL, NULL, &esock_atom_acceptfilter}, - sockRef = argv[0]; // We need this in case we send abort (to the caller) - recvRef = argv[4]; + { +#ifdef SO_BINDTODEVICE + SO_BINDTODEVICE, + esock_setopt_so_bindtodevice, esock_getopt_so_bindtodevice, +#else + 0, NULL, NULL, +#endif + &esock_atom_bindtodevice}, - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { - return enif_make_badarg(env); - } + { +#ifdef SO_BROADCAST + SO_BROADCAST, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_broadcast}, - /* Extract arguments and perform preliminary validation */ + {0, NULL, NULL, &esock_atom_busy_poll}, - if ((! enif_is_ref(env, recvRef)) && - (COMPARE(recvRef, atom_zero) != 0)) { - return enif_make_badarg(env); - } + { +#ifdef SO_BSP_STATE + SO_BSP_STATE, + NULL, esock_getopt_bsp_state, +#else + 0, NULL, NULL, +#endif + &esock_atom_bsp_state}, - if ((! (a1ok = GET_UINT64(env, argv[1], &eBufSz))) || - (! (a2ok = GET_UINT64(env, argv[2], &eCtrlSz))) || - (! GET_INT(env, argv[3], &flags))) { - if ((! IS_INTEGER(env, argv[1])) || - (! IS_INTEGER(env, argv[2])) || - (! IS_INTEGER(env, argv[3]))) - return enif_make_badarg(env); + {0, NULL, NULL, &esock_atom_busy_poll}, - if (! a1ok) - return esock_make_error_integer_range(env, argv[1]); - if (! a2ok) - return esock_make_error_integer_range(env, argv[2]); - return - esock_make_error_integer_range(env, argv[3]); - } + { +#ifdef SO_DEBUG + SO_DEBUG, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_debug}, - bufSz = (ssize_t) eBufSz; - if (eBufSz != (ErlNifUInt64) bufSz) - return esock_make_error_integer_range(env, eBufSz); + { +#ifdef SO_DOMAIN + SO_DOMAIN, + NULL, esock_getopt_sock_domain, +#else + 0, NULL, NULL, +#endif + &esock_atom_domain}, - ctrlSz = (ssize_t) eCtrlSz; - if (eCtrlSz != (ErlNifUInt64) ctrlSz) - return esock_make_error_integer_range(env, eCtrlSz); + { +#ifdef SO_DONTROUTE + SO_DONTROUTE, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_dontroute}, - MLOCK(descP->readMtx); + {0, NULL, NULL, &esock_atom_error}, - SSDBG( descP, - ("SOCKET", "nif_recvmsg(%T), {%d,0x%X} ->" - "\r\n recvRef: %T" - "\r\n bufSz: %ld" - "\r\n ctrlSz: %ld" - "\r\n flags: 0x%X" - "\r\n", - sockRef, descP->sock, descP->readState, - recvRef, (long) bufSz, (long) ctrlSz, flags) ); + { +#ifdef SO_EXCLUSIVEADDRUSE + SO_EXCLUSIVEADDRUSE, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_exclusiveaddruse}, - /* - * - * We need to handle the case when another process tries - * to receive at the same time. - * If the current recv could not read its entire package - * this time (resulting in an select). The read of the - * other process must be made to wait until current - * is done! - * Basically, we need a read queue! - * - * A 'reading' field (boolean), which is set if we did - * not manage to read the entire message and reset every - * time we do. - * - * - */ + { +#ifdef SO_KEEPALIVE + SO_KEEPALIVE, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_keepalive}, - res = esock_recvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); + { +#ifdef SO_LINGER + SO_LINGER, + esock_setopt_linger, esock_getopt_linger, +#else + 0, NULL, NULL, +#endif + &esock_atom_linger}, - SSDBG( descP, ("SOCKET", "nif_recvmsg(%T) -> done" - "\r\n", sockRef) ); + {0, NULL, NULL, &esock_atom_mark}, - MUNLOCK(descP->readMtx); + { +#ifdef SO_MAXDG + SO_MAXDG, + NULL, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_maxdg}, - return res; -#endif // #ifdef __WIN32__ #else -} + { +#ifdef SO_MAX_MSG_SIZE + SO_MAX_MSG_SIZE, + NULL, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_max_msg_size}, + { +#ifdef SO_OOBINLINE + SO_OOBINLINE, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_oobinline}, -/* The (read) buffer handling *must* be optimized! - * But for now we make it easy for ourselves by - * allocating a binary (of the specified or default - * size) and then throwing it away... - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - ssize_t bufLen, - ssize_t ctrlLen, - int flags) -{ - SOCKLEN_T addrLen; - ssize_t read; - int save_errno; - size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz); - size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz); - struct msghdr msgHdr; - struct iovec iov[1]; // Shall we always use 1? - ErlNifBinary data[1]; // Shall we always use 1? - ErlNifBinary ctrl; - ERL_NIF_TERM readerCheck; - ESockAddress addr; - - SSDBG( descP, ("SOCKET", "esock_recvmsg {%d} -> entry with" - "\r\n bufSz: %lu (%ld)" - "\r\n ctrlSz: %ld (%ld)" - "\r\n", descP->sock, - (unsigned long) bufSz, (long) bufLen, - (unsigned long) ctrlSz, (long) ctrlLen) ); + { +#ifdef SO_PASSCRED + SO_PASSCRED, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_passcred}, - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + { +#ifdef SO_PEEK_OFF + SO_PEEK_OFF, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_peek_off}, - /* Accept and Read uses the same select flag - * so they can not be simultaneous - */ - if (descP->currentAcceptorP != NULL) - return esock_make_error_invalid(env, atom_state); + {0, NULL, NULL, &esock_atom_peercred}, - /* Ensure that we either have no current reader or that we are it, - * or enqueue this process if there is a current reader */ - if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { - SSDBG( descP, - ("SOCKET", "esock_recv {%d} -> reader check failed: " - "\r\n %T\r\n", descP->sock, readerCheck) ); - return readerCheck; - } + { +#ifdef SO_PRIORITY + SO_PRIORITY, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_priority}, - /* - for (i = 0; i < sizeof(buf); i++) { - ESOCK_ASSERT( ALLOC_BIN(bifSz, &buf[i]) ); - iov[i].iov_base = buf[i].data; - iov[i].iov_len = buf[i].size; - } - */ + { +#ifdef SO_PROTOCOL + SO_PROTOCOL, + NULL, esock_getopt_sock_protocol, +#else + 0, NULL, NULL, +#endif + &esock_atom_protocol}, - /* Allocate the (msg) data buffer: - */ - ESOCK_ASSERT( ALLOC_BIN(bufSz, &data[0]) ); + { +#ifdef SO_RCVBUF + SO_RCVBUF, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_rcvbuf}, - /* Allocate the ctrl (buffer): - */ - ESOCK_ASSERT( ALLOC_BIN(ctrlSz, &ctrl) ); + {0, NULL, NULL, &esock_atom_rcvbufforce}, - ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1); + { +#ifdef SO_RCVLOWAT + SO_RCVLOWAT, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_rcvlowat}, - addrLen = sizeof(addr); - sys_memzero((char*) &addr, addrLen); - sys_memzero((char*) &msgHdr, sizeof(msgHdr)); + { +#if defined(SO_RCVTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO) + SO_RCVTIMEO, + esock_setopt_timeval_opt, esock_getopt_timeval_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_rcvtimeo}, - iov[0].iov_base = data[0].data; - iov[0].iov_len = data[0].size; + { +#ifdef SO_REUSEADDR + SO_REUSEADDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_reuseaddr}, - msgHdr.msg_name = &addr; - msgHdr.msg_namelen = addrLen; - msgHdr.msg_iov = iov; - msgHdr.msg_iovlen = 1; // Should use a constant or calculate... - msgHdr.msg_control = ctrl.data; - msgHdr.msg_controllen = ctrl.size; + { +#ifdef SO_REUSEPORT + SO_REUSEPORT, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_reuseport}, - read = sock_recvmsg(descP->sock, &msgHdr, flags); - if (ESOCK_IS_ERROR(read)) - save_errno = sock_errno(); - else - save_errno = 0; // The value does not actually matter in this case + {0, NULL, NULL, &esock_atom_rxq_ovfl}, + {0, NULL, NULL, &esock_atom_setfib}, - return recvmsg_check_result(env, descP, read, save_errno, - &msgHdr, - data, // Needed for iov encode - &ctrl, // Needed for ctrl header encode - sockRef, recvRef); -} -#endif // #ifndef __WIN32__ + { +#ifdef SO_SNDBUF + SO_SNDBUF, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_sndbuf}, + {0, NULL, NULL, &esock_atom_sndbufforce}, + { +#ifdef SO_SNDLOWAT + SO_SNDLOWAT, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_sndlowat}, -/* ---------------------------------------------------------------------- - * nif_close - * - * Description: - * Close a (socket) file descriptor. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - */ + { +#if defined(SO_SNDTIMEO) && defined(ESOCK_USE_RCVSNDTIMEO) + SO_SNDTIMEO, + esock_setopt_timeval_opt, esock_getopt_timeval_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_sndtimeo}, -static -ERL_NIF_TERM nif_close(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); + { +#ifdef SO_TIMESTAMP + SO_TIMESTAMP, + esock_setopt_bool_opt, esock_getopt_bool_opt, #else - ESockDescriptor* descP; - ERL_NIF_TERM res; + 0, NULL, NULL, +#endif + &esock_atom_timestamp}, - ESOCK_ASSERT( argc == 1 ); + { +#ifdef SO_TYPE + SO_TYPE, + NULL, esock_getopt_sock_type, +#else + 0, NULL, NULL, +#endif + &esock_atom_type} + }; - SGDBG( ("SOCKET", "nif_close -> entry with argc: %d\r\n", argc) ); - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } +/* IP_* options -------------------------------------------------------- */ - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); +static struct ESockOpt optLevelIP[] = + { + { +#ifdef IP_ADD_MEMBERSHIP + IP_ADD_MEMBERSHIP, + esock_setopt_in_update_membership, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_add_membership}, - SSDBG( descP, - ("SOCKET", "nif_close(%T) ->" - "\r\n Socket: %d" - "\r\n Read State: 0x%X" - "\r\n Write State: 0x%X" - "\r\n Caller: %T" - "\r\n", - argv[0], - descP->sock, - descP->readState, descP->writeState, - esock_self(env)) ); + { +#ifdef IP_ADD_SOURCE_MEMBERSHIP + IP_ADD_SOURCE_MEMBERSHIP, + esock_setopt_in_update_source, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_add_source_membership}, - res = esock_close(env, descP); + { +#ifdef IP_BLOCK_SOURCE + IP_BLOCK_SOURCE, + esock_setopt_in_update_source, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_block_source}, - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); + {0, NULL, NULL, &esock_atom_dontfrag}, - SSDBG( descP, ("SOCKET", "nif_close(%T) -> done" - "\r\n res: %T" - "\r\n", argv[0], res) ); + { +#ifdef IP_DROP_MEMBERSHIP + IP_DROP_MEMBERSHIP, + esock_setopt_in_update_membership, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_drop_membership}, - return res; -#endif // #ifdef __WIN32__ #else -} + { +#ifdef IP_DROP_SOURCE_MEMBERSHIP + IP_DROP_SOURCE_MEMBERSHIP, + esock_setopt_in_update_source, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_drop_source_membership}, + { +#ifdef IP_FREEBIND + IP_FREEBIND, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_freebind}, -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_close(ErlNifEnv* env, - ESockDescriptor* descP) -{ - if (! IS_OPEN(descP->readState)) { - /* A bit of cheeting; maybe not closed yet - do we need a queue? */ - return esock_make_error(env, atom_closed); - } + { +#ifdef IP_HDRINCL + IP_HDRINCL, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_hdrincl}, - /* Store the PID of the caller, - * since we need to inform it when we - * (that is, the stop callback function) - * completes. - */ - ESOCK_ASSERT( enif_self(env, &descP->closerPid) != NULL ); + { +#ifdef IP_MINTTL + IP_MINTTL, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_minttl}, - /* If the caller is not the owner; monitor the caller, - * since we should complete this operation even if the caller dies - * (for whatever reason). - */ - if (COMPARE_PIDS(&descP->closerPid, &descP->ctrlPid) != 0) { + { +#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) + IP_MSFILTER, + esock_setopt_msfilter, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_msfilter}, - ESOCK_ASSERT( MONP("esock_close_check -> closer", - env, descP, - &descP->closerPid, - &descP->closerMon) == 0 ); - } + { +#ifdef IP_MTU + IP_MTU, + NULL, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_mtu}, - /* Prepare for closing the socket */ - descP->readState |= ESOCK_STATE_CLOSING; - descP->writeState |= ESOCK_STATE_CLOSING; - if (esock_do_stop(env, descP)) { - // esock_stop() has been scheduled - wait for it - SSDBG( descP, - ("SOCKET", "esock_close {%d} -> stop was scheduled\r\n", - descP->sock) ); + { +#ifdef IP_MTU_DISCOVER + IP_MTU_DISCOVER, + esock_setopt_ip_mtu_discover, esock_getopt_ip_mtu_discover, +#else + 0, NULL, NULL, +#endif + &esock_atom_mtu_discover}, - // Create closeRef for the close msg that esock_stop() will send - descP->closeEnv = esock_alloc_env("esock_close_do - close-env"); - descP->closeRef = MKREF(descP->closeEnv); + { +#ifdef IP_MULTICAST_ALL + IP_MULTICAST_ALL, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_all}, - return esock_make_ok2(env, CP_TERM(env, descP->closeRef)); - } else { - // The socket may be closed - tell caller to finalize - SSDBG( descP, - ("SOCKET", - "esock_close {%d} -> stop was called\r\n", - descP->sock) ); + { +#ifdef IP_MULTICAST_IF + IP_MULTICAST_IF, + esock_setopt_multicast_if, esock_getopt_multicast_if, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_if}, - return esock_atom_ok; - } -} -#endif // #ifndef __WIN32__ + { +#ifdef IP_MULTICAST_LOOP + IP_MULTICAST_LOOP, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_loop}, + { +#ifdef IP_MULTICAST_TTL + IP_MULTICAST_TTL, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_ttl}, -#ifndef __WIN32__ -/* Prepare for close - return whether stop is scheduled - */ -static -BOOLEAN_T esock_do_stop(ErlNifEnv* env, - ESockDescriptor* descP) { - BOOLEAN_T ret; - int sres; - ERL_NIF_TERM sockRef; + { +#ifdef IP_NODEFRAG + IP_NODEFRAG, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_nodefrag}, - sockRef = enif_make_resource(env, descP); + {0, NULL, NULL, &esock_atom_options}, - if (IS_SELECTED(descP)) { - ESOCK_ASSERT( (sres = esock_select_stop(env, descP->sock, descP)) - >= 0 ); - if ((sres & ERL_NIF_SELECT_STOP_CALLED) != 0) { - /* The socket is no longer known by the select machinery - * - it may be closed - */ - ret = FALSE; - } else { - ESOCK_ASSERT( (sres & ERL_NIF_SELECT_STOP_SCHEDULED) != 0 ); - /* esock_stop() is scheduled - * - socket may be removed by esock_stop() or later - */ - ret = TRUE; - } - } else { - sres = 0; - /* The socket has never been used in the select machinery - * - it may be closed - */ - ret = FALSE; - } + { +#ifdef IP_PKTINFO + IP_PKTINFO, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_pktinfo}, - /* +++++++ Current and waiting Writers +++++++ */ + { +#ifdef IP_PKTOPTIONS + IP_PKTOPTIONS, + NULL, esock_getopt_pktoptions, +#else + 0, NULL, NULL, +#endif + &esock_atom_pktoptions}, - if (descP->currentWriterP != NULL) { + { +#ifdef IP_RECVDSTADDR + IP_RECVDSTADDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvdstaddr}, - /* We have a current Writer; was it deselected? - */ + { +#ifdef IP_RECVERR + IP_RECVERR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recverr}, - if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { + { +#ifdef IP_RECVIF + IP_RECVIF, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvif}, - /* The current Writer will not get a select message - * - send it an abort message - */ + { +#ifdef IP_RECVOPTS + IP_RECVOPTS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvopts}, - esock_stop_handle_current(env, - "writer", - descP, sockRef, &descP->currentWriter); - } + { +#ifdef IP_RECVORIGDSTADDR + IP_RECVORIGDSTADDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvorigdstaddr}, - /* Inform the waiting Writers (in the same way) */ + { +#ifdef IP_RECVTOS + IP_RECVTOS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvtos}, - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting writer(s)\r\n", - descP->sock) ); + { +#ifdef IP_RECVTTL + IP_RECVTTL, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvttl}, - inform_waiting_procs(env, "writer", - descP, sockRef, &descP->writersQ, atom_closed); + { +#ifdef IP_RETOPTS + IP_RETOPTS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_retopts}, - descP->currentWriterP = NULL; - } + { +#ifdef IP_ROUTER_ALERT + IP_ROUTER_ALERT, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_router_alert}, - /* +++++++ Connector +++++++ - * Note that there should not be Writers and a Connector - * at the same time so the check for if the - * current Writer/Connecter was deselected is only correct - * under that assumption - */ + { +#ifdef IP_SENDSRCADDR + IP_SENDSRCADDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_sendsrcaddr}, - if (descP->connectorP != NULL) { + { +#ifdef IP_TOS + IP_TOS, + esock_setopt_tos, esock_getopt_tos, +#else + 0, NULL, NULL, +#endif + &esock_atom_tos}, - /* We have a Connector; was it deselected? - */ + { +#ifdef IP_TRANSPARENT + IP_TRANSPARENT, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_transparent}, - if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { + { +#ifdef IP_TTL + IP_TTL, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_ttl}, - /* The Connector will not get a select message - * - send it an abort message - */ + { +#ifdef IP_UNBLOCK_SOURCE + IP_UNBLOCK_SOURCE, + esock_setopt_in_update_source, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_unblock_source} - esock_stop_handle_current(env, - "connector", - descP, sockRef, &descP->connector); - } + }; - descP->connectorP = NULL; - } +/* IPV6_* options ------------------------------------------------------ */ - /* +++++++ Current and waiting Readers +++++++ */ +#ifdef HAVE_IPV6 +static struct ESockOpt optLevelIPV6[] = + { - if (descP->currentReaderP != NULL) { + { +#ifdef IPV6_ADDRFORM + IPV6_ADDRFORM, + esock_setopt_addrform, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_addrform}, - /* We have a current Reader; was it deselected? - */ + { +#ifdef IPV6_ADD_MEMBERSHIP + IPV6_ADD_MEMBERSHIP, + esock_setopt_in6_update_membership, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_add_membership}, - if (sres & ERL_NIF_SELECT_READ_CANCELLED) { + { +#ifdef IPV6_AUTHHDR + IPV6_AUTHHDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_authhdr}, - /* The current Reader will not get a select message - * - send it an abort message - */ + {0, NULL, NULL, &esock_atom_auth_level}, + {0, NULL, NULL, &esock_atom_checksum}, - esock_stop_handle_current(env, - "reader", - descP, sockRef, &descP->currentReader); - } + { +#ifdef IPV6_DROP_MEMBERSHIP + IPV6_DROP_MEMBERSHIP, + esock_setopt_in6_update_membership, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_drop_membership}, - /* Inform the Readers (in the same way) */ + { +#if defined(IPV6_DSTOPTS) + IPV6_DSTOPTS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_dstopts}, - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting reader(s)\r\n", - descP->sock) ); + {0, NULL, NULL, &esock_atom_esp_network_level}, + {0, NULL, NULL, &esock_atom_esp_trans_level}, + {0, NULL, NULL, &esock_atom_faith}, - inform_waiting_procs(env, "writer", - descP, sockRef, &descP->readersQ, atom_closed); + { +#ifdef IPV6_FLOWINFO + IPV6_FLOWINFO, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_flowinfo}, - descP->currentReaderP = NULL; - } + { +#ifdef IPV6_HOPLIMIT + IPV6_HOPLIMIT, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_hoplimit}, - /* +++++++ Current and waiting Acceptors +++++++ - * - * Note that there should not be Readers and Acceptors - * at the same time so the check for if the - * current Reader/Acceptor was deselected is only correct - * under that assumption - */ + { +#ifdef IPV6_HOPOPTS + IPV6_HOPOPTS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_hopopts}, - if (descP->currentAcceptorP != NULL) { + {0, NULL, NULL, &esock_atom_ipcomp_level}, + {0, NULL, NULL, &esock_atom_join_group}, + {0, NULL, NULL, &esock_atom_leave_group}, - /* We have a current Acceptor; was it deselected? - */ + { +#ifdef IPV6_MTU + IPV6_MTU, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_mtu}, - if (sres & ERL_NIF_SELECT_READ_CANCELLED) { + { +#ifdef IPV6_MTU_DISCOVER + IPV6_MTU_DISCOVER, + esock_setopt_ipv6_mtu_discover, esock_getopt_ipv6_mtu_discover, +#else + 0, NULL, NULL, +#endif + &esock_atom_mtu_discover}, - /* The current Acceptor will not get a select message - * - send it an abort message - */ + { +#ifdef IPV6_MULTICAST_HOPS + IPV6_MULTICAST_HOPS, + esock_setopt_hops, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_hops}, - esock_stop_handle_current(env, - "acceptor", - descP, sockRef, &descP->currentAcceptor); - } + { +#ifdef IPV6_MULTICAST_IF + IPV6_MULTICAST_IF, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_if}, - /* Inform the waiting Acceptor (in the same way) */ + { +#ifdef IPV6_MULTICAST_LOOP + IPV6_MULTICAST_LOOP, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_multicast_loop}, - SSDBG( descP, - ("SOCKET", - "esock_do_stop {%d} -> handle waiting acceptors(s)\r\n", - descP->sock) ); + {0, NULL, NULL, &esock_atom_portrange}, - inform_waiting_procs(env, "acceptor", - descP, sockRef, &descP->acceptorsQ, atom_closed); + { +#ifdef IPV6_PKTOPTIONS + IPV6_PKTOPTIONS, + NULL, esock_getopt_pktoptions, +#else + 0, NULL, NULL, +#endif + &esock_atom_pktoptions}, - descP->currentAcceptorP = NULL; - } + { +#ifdef IPV6_RECVERR + IPV6_RECVERR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recverr}, - return ret; -} -#endif // #ifndef __WIN32__ + { +#ifdef IPV6_RECVHOPLIMIT + IPV6_RECVHOPLIMIT, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvhoplimit}, + { +#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) +#if defined(IPV6_RECVPKTINFO) + IPV6_RECVPKTINFO, +#else + IPV6_PKTINFO, +#endif + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvpktinfo}, + { +#ifdef IPV6_RECVTCLASS + IPV6_RECVTCLASS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_recvtclass}, -/* ---------------------------------------------------------------------- - * nif_finalize_close - * - * Description: - * Perform the actual socket close! - * Note that this function is executed in a dirty scheduler. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - */ -static -ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ - ESockDescriptor* descP; - ERL_NIF_TERM result; -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); + { +#ifdef IPV6_ROUTER_ALERT + IPV6_ROUTER_ALERT, + esock_setopt_int_opt, esock_getopt_int_opt, #else + 0, NULL, NULL, +#endif + &esock_atom_router_alert}, - /* Extract arguments and perform preliminary validation */ + { +#ifdef IPV6_RTHDR + IPV6_RTHDR, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_rthdr}, - ESOCK_ASSERT( argc == 1 ); + { +#ifdef IPV6_TCLASS + IPV6_TCLASS, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_tclass}, - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } + { +#ifdef IPV6_UNICAST_HOPS + IPV6_UNICAST_HOPS, + esock_setopt_hops, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_unicast_hops}, - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); + {0, NULL, NULL, &esock_atom_use_min_mtu}, - SSDBG( descP, - ("SOCKET", "nif_finalize_close(%T), {%d,0x%X}\r\n", - argv[0], descP->sock, descP->readState) ); + { +#ifdef IPV6_V6ONLY + IPV6_V6ONLY, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_v6only} - result = esock_finalize_close(env, descP); + }; +#endif // #ifdef HAVE_IPV6 - SSDBG( descP, ("SOCKET", "nif_finalize_close(%T) -> done with" - "\r\n result: %T" - "\r\n", argv[0], result) ); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); +/* SCTP_* options ------------------------------------------------------ */ - return result; -#endif // #ifdef __WIN32__ #else -} +#ifdef HAVE_SCTP +static struct ESockOpt optLevelSCTP[] = + { + {0, NULL, NULL, &esock_atom_adaption_layer}, -/* *** esock_finalize_close *** - * Perform the final step in the socket close. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_finalize_close(ErlNifEnv* env, - ESockDescriptor* descP) -{ - int err; - ErlNifPid self; -#ifdef HAVE_SENDFILE - HANDLE sendfileHandle; + { +#ifdef SCTP_ASSOCINFO + SCTP_ASSOCINFO, + esock_setopt_sctp_associnfo, esock_getopt_sctp_associnfo, +#else + 0, NULL, NULL, #endif + &esock_atom_associnfo}, - ESOCK_ASSERT( enif_self(env, &self) != NULL ); - - if (IS_CLOSED(descP->readState)) - return esock_make_error(env, atom_closed); + {0, NULL, NULL, &esock_atom_auth_active_key}, + {0, NULL, NULL, &esock_atom_auth_chunk}, + {0, NULL, NULL, &esock_atom_auth_delete_key}, + {0, NULL, NULL, &esock_atom_auth_key}, - if (! IS_CLOSING(descP->readState)) { - // esock_close() has not been called - return esock_raise_invalid(env, atom_state); - } + { +#ifdef SCTP_AUTOCLOSE + SCTP_AUTOCLOSE, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_autoclose}, - if (IS_SELECTED(descP) && (descP->closeEnv != NULL)) { - // esock_stop() is scheduled but has not been called - return esock_raise_invalid(env, atom_state); - } + {0, NULL, NULL, &esock_atom_context}, + {0, NULL, NULL, &esock_atom_default_send_params}, + {0, NULL, NULL, &esock_atom_delayed_ack_time}, - if (COMPARE_PIDS(&descP->closerPid, &self) != 0) { - // This process is not the closer - return esock_raise_invalid(env, atom_state); - } + { +#ifdef SCTP_DISABLE_FRAGMENTS + SCTP_DISABLE_FRAGMENTS, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_disable_fragments}, - // Close the socket + {0, NULL, NULL, &esock_atom_hmac_ident}, - /* Stop monitoring the closer. - * Demonitoring may fail since this is a dirty NIF - * - the caller may have died already. - */ - enif_set_pid_undefined(&descP->closerPid); - if (descP->closerMon.isActive) { - (void) DEMONP("esock_finalize_close -> closer", - env, descP, &descP->closerMon); - } + { +#ifdef SCTP_EVENTS + SCTP_EVENTS, + esock_setopt_sctp_events, NULL, +#else + 0, NULL, NULL, +#endif + &esock_atom_events}, - /* Stop monitoring the owner */ - enif_set_pid_undefined(&descP->ctrlPid); - (void) DEMONP("esock_finalize_close -> ctrl", - env, descP, &descP->ctrlMon); - /* Not impossible to still get a esock_down() call from a - * just triggered owner monitor down - */ + {0, NULL, NULL, &esock_atom_explicit_eor}, + {0, NULL, NULL, &esock_atom_fragment_interleave}, + {0, NULL, NULL, &esock_atom_get_peer_addr_info}, -#ifdef HAVE_SENDFILE - sendfileHandle = descP->sendfileHandle; - descP->sendfileHandle = INVALID_HANDLE; + { +#ifdef SCTP_INITMSG + SCTP_INITMSG, + esock_setopt_sctp_initmsg, esock_getopt_sctp_initmsg, +#else + 0, NULL, NULL, #endif + &esock_atom_initmsg}, - /* This nif is executed in a dirty scheduler just so that - * it can "hang" (whith minumum effect on the VM) while the - * kernel writes our buffers. IF we have set the linger option - * for this ({true, integer() > 0}). For this to work we must - * be blocking... - */ - SET_BLOCKING(descP->sock); - err = esock_close_socket(env, descP, TRUE); + {0, NULL, NULL, &esock_atom_i_want_mapped_v4_addr}, + {0, NULL, NULL, &esock_atom_local_auth_chunks}, -#ifdef HAVE_SENDFILE - if (sendfileHandle != INVALID_HANDLE) { - (void) close(descP->sendfileHandle); - } + { +#ifdef SCTP_MAXSEG + SCTP_MAXSEG, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, #endif + &esock_atom_maxseg}, - if (err != 0) { - if (err == ERRNO_BLOCK) { - /* Not all data in the buffers where sent, - * make sure the caller gets this. - */ - return esock_make_error(env, atom_timeout); - } else { - return esock_make_error_errno(env, err); - } - } + {0, NULL, NULL, &esock_atom_maxburst}, - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ + { +#ifdef SCTP_NODELAY + SCTP_NODELAY, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_nodelay}, + {0, NULL, NULL, &esock_atom_partial_delivery_point}, + {0, NULL, NULL, &esock_atom_peer_addr_params}, + {0, NULL, NULL, &esock_atom_peer_auth_chunks}, + {0, NULL, NULL, &esock_atom_primary_addr}, + {0, NULL, NULL, &esock_atom_reset_streams}, -#ifndef __WIN32__ -static int esock_close_socket(ErlNifEnv* env, - ESockDescriptor* descP, - BOOLEAN_T unlock) { - int err = 0; - SOCKET sock = descP->sock; - ERL_NIF_TERM sockRef; + { +#ifdef SCTP_RTOINFO + SCTP_RTOINFO, + esock_setopt_sctp_rtoinfo, esock_getopt_sctp_rtoinfo, +#else + 0, NULL, NULL, +#endif + &esock_atom_rtoinfo}, - /* This code follows Linux's advice to assume that after calling - * close(2), the file descriptor may be reused, so assuming - * that it can be used for anything such as retrying - * to close is bad behaviour, although odd platforms - * such as HP-UX requires a retry after EINTR - */ + {0, NULL, NULL, &esock_atom_set_peer_primary_addr}, + {0, NULL, NULL, &esock_atom_status}, + {0, NULL, NULL, &esock_atom_use_ext_recvinfo} - /* First update the state so no other thread will try - * to close the socket, then we will close it, - * possibly when being scheduled in during - * finalize_close - */ - descP->sock = INVALID_SOCKET; - descP->event = INVALID_EVENT; - descP->readState |= ESOCK_STATE_CLOSED; - descP->writeState |= ESOCK_STATE_CLOSED; - dec_socket(descP->domain, descP->type, descP->protocol); + }; +#endif // #ifdef HAVE_SCTP - /* +++++++ Clear the meta option +++++++ */ - enif_clear_env(descP->meta.env); - descP->meta.ref = esock_atom_undefined; +/* TCP_* options ------------------------------------------------------- */ - sock_close_event(descP->event); - if (descP->closeOnClose) { - if (unlock) { - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); - } - if (sock_close(sock) != 0) - err = sock_errno(); - if (unlock) { - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - } - } +static struct ESockOpt optLevelTCP[] = + { - if (err != 0) { - SSDBG( descP, - ("SOCKET", "esock_close_socket {%d} -> %d\r\n", - sock, err) ); - } + { +#ifdef TCP_CONGESTION + TCP_CONGESTION, + esock_setopt_tcp_congestion, esock_getopt_tcp_congestion, +#else + 0, NULL, NULL, +#endif + &esock_atom_congestion}, - /* (maybe) Update the registry */ - if (descP->useReg) { - sockRef = enif_make_resource(env, descP); - esock_send_reg_del_msg(env, descP, sockRef); - } + { +#ifdef TCP_CORK + TCP_CORK, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_cork}, - return err; -} -#endif // #ifndef __WIN32__ + {0, NULL, NULL, &esock_atom_info}, + { +#ifdef TCP_KEEPCNT + TCP_KEEPCNT, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_keepcnt}, -/* ---------------------------------------------------------------------- - * nif_shutdown - * - * Description: - * Disable sends and/or receives on a socket. - * - * Arguments: - * [0] Socket (ref) - Points to the socket descriptor. - * [1] How - What will be shutdown. - */ + { +#ifdef TCP_KEEPIDLE + TCP_KEEPIDLE, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_keepidle}, -static -ERL_NIF_TERM nif_shutdown(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); + { +#ifdef TCP_KEEPINTVL + TCP_KEEPINTVL, + esock_setopt_int_opt, esock_getopt_int_opt, #else - ESockDescriptor* descP; - ERL_NIF_TERM ehow, res; - int how; + 0, NULL, NULL, +#endif + &esock_atom_keepintvl}, - ESOCK_ASSERT( argc == 2 ); + { +#ifdef TCP_MAXSEG + TCP_MAXSEG, + esock_setopt_int_opt, esock_getopt_int_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_maxseg}, - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } - ehow = argv[1]; + {0, NULL, NULL, &esock_atom_md5sig}, - if (! ehow2how(ehow, &how)) - return esock_raise_invalid(env, - MKT2(env, atom_how, ehow)); + { +#ifdef TCP_NODELAY + TCP_NODELAY, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_nodelay}, - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); + {0, NULL, NULL, &esock_atom_noopt}, + { +#ifdef TCP_NOPUSH + TCP_NOPUSH, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_nopush}, + {0, NULL, NULL, &esock_atom_syncnt}, + {0, NULL, NULL, &esock_atom_user_timeout} - SSDBG( descP, - ("SOCKET", "nif_shutdown(%T), {%d,0x%X} ->" - "\r\n how: %d" - "\r\n", - argv[0], descP->sock, descP->readState | descP->writeState, - how) ); + }; - res = esock_shutdown(env, descP, how); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); +/* UDP_* options ------------------------------------------------------- */ - SSDBG( descP, ("SOCKET", "nif_shutdown(%T) -> done with" - "\r\n res: %T" - "\r\n", argv[0], res) ); +static struct ESockOpt optLevelUDP[] = + { - return res; -#endif // #ifdef __WIN32__ #else -} + { +#ifdef UDP_CORK + UDP_CORK, + esock_setopt_bool_opt, esock_getopt_bool_opt, +#else + 0, NULL, NULL, +#endif + &esock_atom_cork} + }; -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, - ESockDescriptor* descP, - int how) -{ - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); +/* Option levels utility macro */ - if (sock_shutdown(descP->sock, how) == 0) - return esock_atom_ok; - else - return esock_make_error_errno(env, sock_errno()); -} -#endif // #ifndef __WIN32__ +#define OPT_LEVEL(Level, Opts, Name) {(Level), NUM(Opts), (Opts), (Name)} +/* Table --------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - * nif_setopt - * - * Description: - * Set socket option. - * It is possible to use a native mode value where we do not use - * any assumption about how to encode the value but instead - * use the value's type to select encoding. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Level - Level of the socket option. - * Opt - The socket option. - * Value - Value of the socket option. - * NativeValue - If 0 Value type has to match our encoding function, - * if not 0 type selects encoding. - */ +static struct ESockOptLevel optLevels[] = + { + OPT_LEVEL(SOL_SOCKET, optLevelSocket, &esock_atom_socket), -static -ERL_NIF_TERM nif_setopt(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); +#ifndef __WIN32__ +#ifdef SOL_IP + OPT_LEVEL(SOL_IP, optLevelIP, &esock_atom_ip), #else - ESockDescriptor* descP = NULL; - int level, opt, nativeValue; - ERL_NIF_TERM eVal; - - ESOCK_ASSERT( argc == 5 ); + OPT_LEVEL(IPPROTO_IP, optLevelIP, &esock_atom_ip), +#endif +#else + OPT_LEVEL(IPPROTO_IP, optLevelIP, &esock_atom_ip), +#endif - SGDBG( ("SOCKET", "nif_setopt -> entry with argc: %d\r\n", argc) ); +#ifdef HAVE_IPV6 +#ifndef __WIN32__ +#ifdef SOL_IPV6 + OPT_LEVEL(SOL_IPV6, optLevelIPV6, &esock_atom_ipv6), +#else + OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6, &esock_atom_ipv6), +#endif +#else + OPT_LEVEL(IPPROTO_IPV6, optLevelIPV6, &esock_atom_ipv6), +#endif +#endif // #ifdef HAVE_IPV6 - /* Extract arguments and perform preliminary validation */ +#ifdef HAVE_SCTP + OPT_LEVEL(IPPROTO_SCTP, optLevelSCTP, &esock_atom_sctp), +#endif // #ifdef HAVE_SCTP - if ((! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) || - (! GET_INT(env, argv[4], &nativeValue))) { - // - SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); - return enif_make_badarg(env); - } - if (! GET_INT(env, argv[2], &opt)) { - SSDBG( descP, - ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); - if (! IS_INTEGER(env, argv[2])) - return enif_make_badarg(env); - else - return esock_make_error_integer_range(env, argv[2]); - } - eVal = argv[3]; + OPT_LEVEL(IPPROTO_UDP, optLevelUDP, &esock_atom_udp), + OPT_LEVEL(IPPROTO_TCP, optLevelTCP, &esock_atom_tcp) + }; - if (esock_decode_level(env, argv[1], &level)) { - if (nativeValue == 0) - return esock_setopt(env, descP, level, opt, eVal); - else - return esock_setopt_native(env, descP, level, opt, eVal); - } +#undef OPT_LEVEL - if (COMPARE(argv[1], atom_otp) == 0) { - if (nativeValue == 0) { - return esock_setopt_otp(env, descP, opt, eVal); - } else { - SSDBG( descP, ("SOCKET", "nif_setopt -> failed arg check\r\n") ); - return enif_make_badarg(env); - } - } +/* Tables init (sorting) ----------------------------------------------- */ - SGDBG( ("SOCKET", "nif_setopt -> failed arg check\r\n") ); +#define ESOCK_SORT_TABLE(Array, Cmp) \ + qsort((Array), NUM(Array), sizeof(*(Array)), (Cmp)) - if (IS_INTEGER(env, argv[1])) - return esock_make_error_integer_range(env, argv[1]); - else - return enif_make_badarg(env); -#endif // #ifdef __WIN32__ #else +static void initOpts(void) { + ESOCK_SORT_TABLE(optLevelSocket, cmpESockOpt); + ESOCK_SORT_TABLE(optLevelIP, cmpESockOpt); +#ifdef HAVE_IPV6 + ESOCK_SORT_TABLE(optLevelIPV6, cmpESockOpt); +#endif +#ifdef HAVE_SCTP + ESOCK_SORT_TABLE(optLevelSCTP, cmpESockOpt); +#endif + ESOCK_SORT_TABLE(optLevelTCP, cmpESockOpt); + ESOCK_SORT_TABLE(optLevelUDP, cmpESockOpt); + ESOCK_SORT_TABLE(optLevels, cmpESockOptLevel); } -/* esock_setopt_otp - Handle OTP (level) options +/* ------------------------------------------------------------------------ + * Socket option tables and handling */ -#ifndef __WIN32__ + +// qsort and bsearch helper(s) static -ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, - ESockDescriptor* descP, - int eOpt, - ERL_NIF_TERM eVal) +int cmpESockOpt(const void *vpa, const void *vpb) { - ERL_NIF_TERM result; - - switch (eOpt) { - case ESOCK_OPT_OTP_DEBUG: - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - result = esock_setopt_otp_debug(env, descP, eVal); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_IOW: - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - result = esock_setopt_otp_iow(env, descP, eVal); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_CTRL_PROC: - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - result = esock_setopt_otp_ctrl_proc(env, descP, eVal); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_RCVBUF: - MLOCK(descP->readMtx); - result = esock_setopt_otp_rcvbuf(env, descP, eVal); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_RCVCTRLBUF: - MLOCK(descP->readMtx); - result = esock_setopt_otp_rcvctrlbuf(env, descP, eVal); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_SNDCTRLBUF: - MLOCK(descP->writeMtx); - result = esock_setopt_otp_sndctrlbuf(env, descP, eVal); - MUNLOCK(descP->writeMtx); - break; + struct ESockOpt *a, *b; + a = (struct ESockOpt *) vpa; + b = (struct ESockOpt *) vpb; + return a->opt < b->opt ? -1 : (a->opt > b->opt ? 1 : 0); +} - case ESOCK_OPT_OTP_META: - MLOCK(descP->writeMtx); - result = esock_setopt_otp_meta(env, descP, eVal); - MUNLOCK(descP->writeMtx); - break; +static +int cmpESockOptLevel(const void *vpa, const void *vpb) +{ + struct ESockOptLevel *a, *b; + a = (struct ESockOptLevel*) vpa; + b = (struct ESockOptLevel*) vpb; + return a->level < b->level ? -1 : (a->level > b->level ? 1 : 0); +} - case ESOCK_OPT_OTP_USE_REGISTRY: - MLOCK(descP->writeMtx); - result = esock_setopt_otp_use_registry(env, descP, eVal); - MUNLOCK(descP->writeMtx); - break; +/* Option lookup in tables --------------------------------------------- */ - default: - MLOCK(descP->writeMtx); - SSDBG( descP, - ("SOCKET", "esock_setopt_otp {%d} -> invalid with" - "\r\n eOpt: %d" - "\r\n eVal: %T" - "\r\n", descP->sock, eOpt, eVal) ); - MUNLOCK(descP->writeMtx); +static +struct ESockOpt *lookupOpt(int level, int opt) +{ + struct ESockOptLevel levelKey, *levelP; + struct ESockOpt optKey; - /* This is an internal error - prim_inet gave us junk */ - result = - esock_raise_invalid(env, - MKT2(env, - atom_otp_socket_option, - MKI(env, eOpt))); - break; - } + sys_memzero((char *) &levelKey, sizeof(levelKey)); + levelKey.level = level; + levelP = bsearch(&levelKey, optLevels, NUM(optLevels), sizeof(*optLevels), + cmpESockOptLevel); + if (levelP == NULL) + return NULL; - return result; + sys_memzero((char *) &optKey, sizeof(optKey)); + optKey.opt = opt; + return bsearch(&optKey, levelP->opts, levelP->num, sizeof(*levelP->opts), + cmpESockOpt); } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_debug - Handle the OTP (level) debug options +/* These three (inline) functions are primarily intended for debugging, + * that is, to make it easy to add debug printouts. */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) + +// static ESOCK_INLINE void esock_clear_env(const char* slogan, ErlNifEnv* env) +extern void esock_clear_env(const char* slogan, ErlNifEnv* env) { - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_debug {%d} -> closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env clear - %s: 0x%lX\r\n", slogan, env) ); - if (! esock_decode_bool(eVal, &descP->dbg)) - return esock_make_invalid(env, atom_value); + SGDBG( ("SOCKET", "env clear - %s: 0x%lX\r\n", slogan, env) ); - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_debug {%d} -> ok" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + if (env != NULL) enif_clear_env(env); +} - return esock_atom_ok; + +// static ESOCK_INLINE void esock_free_env(const char* slogan, ErlNifEnv* env) +extern void esock_free_env(const char* slogan, ErlNifEnv* env) +{ + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) ); + + SGDBG( ("SOCKET", "env free - %s: 0x%lX\r\n", slogan, env) ); + + if (env != NULL) enif_free_env(env); } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_iow - Handle the OTP (level) iow options - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +// static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan) +extern ErlNifEnv* esock_alloc_env(const char* slogan) { - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_iow {%d} -> closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + ErlNifEnv* env = enif_alloc_env(); - if (! esock_decode_bool(eVal, &descP->iow)) - return esock_make_invalid(env, atom_value); + // ESOCK_DBG_PRINTF( TRUE, ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) ); - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_iow {%d} -> ok" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + SGDBG( ("SOCKET", "env alloc - %s: 0x%lX\r\n", slogan, env) ); - return esock_atom_ok; + ESOCK_ASSERT( env != NULL ); + + return env; } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_ctrl_proc - Handle the OTP (level) - * controlling_process options +/* ---------------------------------------------------------------------- + * N I F F u n c t i o n s + * ---------------------------------------------------------------------- + * + * Utility and admin functions: + * ---------------------------- + * nif_info/0 + * nif_command/1 + * nif_supports/1 + * + * The "proper" socket functions: + * ------------------------------ + * nif_open(FD, Extra) + * nif_open(Domain, Type, Protocol, Extra) + * nif_bind(Sock, LocalAddr) + * nif_connect(Sock, SockAddr) + * nif_listen(Sock, Backlog) + * nif_accept(LSock, Ref) + * nif_send(Sock, SendRef, Data, Flags) + * nif_sendto(Sock, SendRef, Data, Dest, Flags) + * nif_sendmsg(Sock, SendRef, Msg, Flags) + * nif_sendfile(Sock, SendRef, Offset, Count, InFileRef) + * nif_sendfile(Sock, SendRef, Offset, Count) + * nif_sendfile(Sock) + * nif_recv(Sock, Length, Flags, RecvRef) + * nif_recvfrom(Sock, RecvRef, BufSz, Flags) + * nif_recvmsg(Sock, RecvRef, BufSz, CtrlSz, Flags) + * nif_close(Sock) + * nif_shutdown(Sock, How) + * nif_sockname(Sock) + * nif_peername(Sock) + * + * And some functions to manipulate and retrieve socket options: + * ------------------------------------------------------------- + * nif_setopt/5 + * nif_getopt/3,4 + * + * And some utility functions: + * ------------------------------------------------------------- + * + * And some socket admin functions: + * ------------------------------------------------------------- + * nif_cancel(Sock, Ref) */ -#ifndef __WIN32__ + + +/* ---------------------------------------------------------------------- + * nif_info + * + * Description: + * This is currently just a placeholder... + */ + static -ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_info(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ErlNifPid caller, newCtrlPid; - int xres; + ERL_NIF_TERM info; + ESockDescriptor* descP; - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> entry" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + SGDBG( ("SOCKET", "nif_info -> entry with %d args\r\n", argc) ); - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + if (argc == 0) + return esock_global_info(env); - /* Ensure that caller is (current) controlling process */ - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) { - SSDBG( descP, ("SOCKET", - "esock_setopt_otp_ctrl_proc -> not owner (%T)\r\n", - descP->ctrlPid) ); - return esock_make_error_invalid(env, esock_atom_not_owner); - } + ESOCK_ASSERT( argc == 1 ); - /* Ensure that the new controller is a local process */ - if (!GET_LPID(env, eVal, &newCtrlPid)) { - esock_warning_msg("Failed get pid of new controlling process\r\n"); - return esock_make_invalid(env, atom_value); + if (!ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); } - if ((xres = DEMONP("esock_setopt_otp_ctrl_proc -> (old) ctrl", - env, descP, &descP->ctrlMon)) != 0) { - /* There is a legitimate reason for this is; the current - * process was just killed from a different thread - */ - esock_warning_msg("Failed demonitor (%d) " - "old controlling process %T (%T)\r\n", - xres, descP->ctrlPid, descP->ctrlMon); - } + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); - descP->ctrlPid = newCtrlPid; + SSDBG( descP, ("SOCKET", "nif_info(%T) {%d,0x%X} -> get socket info\r\n", + argv[0], descP->sock, + descP->readState | descP->writeState) ); - if ((xres = - MONP("esock_setopt_otp_ctrl_proc -> (new) ctrl", - env, descP, &descP->ctrlPid, &descP->ctrlMon)) != 0) { + info = esock_socket_info(env, descP); - ESOCK_ASSERT( 0 < xres ); - /* Indicates that we do not have a DOWN callback, - * which is preposterous - */ + SSDBG( descP, ("SOCKET", "nif_info(%T) -> get socket info done with" + "\r\n info: %T" + "\r\n", argv[0], info) ); - /* We know newCtrlPid is not 'undefined' so - * it must be dead already - * - pretend the controlling process change went well - * and then the monitor went down - */ - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> DOWN" - "\r\n xres: %d" - "\r\n", descP->sock, xres) ); + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + + return info; +} + + +/* + * This function return a property list containing "global" info. + * + * Note that we also include something in the counter list that is not + * actually a counter, the num_cnt_bits. This is the "size" of each counter, + * in number of bits: 16 | 24 | 32 | 48 | 64. + */ +static +ERL_NIF_TERM esock_global_info(ErlNifEnv* env) +{ + ERL_NIF_TERM + numBits, numSockets, numTypeDGrams, numTypeStreams, + numTypeSeqPkgs, numDomLocal, numDomInet, numDomInet6, + numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP, + sockDbg, iovMax, dbg, useReg, iow, eei; + + MLOCK(data.cntMtx); + numBits = MKUI(env, ESOCK_COUNTER_SIZE); + numSockets = MKUI(env, data.numSockets); + numTypeDGrams = MKUI(env, data.numTypeDGrams); + numTypeStreams = MKUI(env, data.numTypeStreams); + numTypeSeqPkgs = MKUI(env, data.numTypeSeqPkgs); + numDomLocal = MKUI(env, data.numDomainLocal); + numDomInet = MKUI(env, data.numDomainInet); + numDomInet6 = MKUI(env, data.numDomainInet6); + numProtoIP = MKUI(env, data.numProtoIP); + numProtoTCP = MKUI(env, data.numProtoTCP); + numProtoUDP = MKUI(env, data.numProtoUDP); + numProtoSCTP = MKUI(env, data.numProtoSCTP); + sockDbg = BOOL2ATOM(data.sockDbg); + eei = BOOL2ATOM(data.eei); + MUNLOCK(data.cntMtx); - enif_set_pid_undefined(&descP->ctrlPid); + iovMax = MKI(env, data.iov_max); + dbg = BOOL2ATOM(data.dbg); + useReg = BOOL2ATOM(data.useReg); + iow = BOOL2ATOM(data.iow); - esock_down_ctrl(env, descP, &newCtrlPid); + { + ERL_NIF_TERM gcntVals[] = + {numBits, + numSockets, + numTypeDGrams, numTypeStreams, numTypeSeqPkgs, + numDomLocal, numDomInet, numDomInet6, + numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP}; + ERL_NIF_TERM gcntKeys[] = + {atom_num_cnt_bits, + atom_num_sockets, + atom_num_tdgrams, atom_num_tstreams, atom_num_tseqpkgs, + atom_num_dlocal, atom_num_dinet, atom_num_dinet6, + atom_num_pip, atom_num_ptcp, atom_num_pudp, atom_num_psctp}; + unsigned int numGCntVals = NUM(gcntVals); + unsigned int numGCntKeys = NUM(gcntKeys); + ERL_NIF_TERM gcnt; - descP->readState |= ESOCK_STATE_CLOSING; - descP->writeState |= ESOCK_STATE_CLOSING; + ESOCK_ASSERT( numGCntKeys == numGCntVals ); + ESOCK_ASSERT( MKMA(env, gcntKeys, gcntVals, numGCntKeys, &gcnt) ); - } else { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> ok" - "\r\n", descP->sock) ); - } + { + ERL_NIF_TERM + keys[] = {esock_atom_debug, + atom_socket_debug, + atom_eei, + esock_atom_use_registry, + atom_iow, + esock_atom_counters, + atom_iov_max, + atom_io_backend}, + vals[] = {dbg, + sockDbg, + eei, + useReg, + iow, + gcnt, + iovMax, + ESOCK_IO_INFO(env) + /* This mess is just a temporary hack + * and shall be replaced by a callback + * function (eventually). + * That function should return a 'term' (a map). + */ + /* +#ifdef __WIN32__ + MKA(env, "win_esaio") +#else + MKA(env, "unix_essio") +#endif + */ + }, + info; + unsigned int + numKeys = NUM(keys), + numVals = NUM(vals); - return esock_atom_ok; + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); + + return info; + } + } } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option - * The (otp) rcvbuf option is provided as: - * - * BufSz :: default | pos_integer() | - * {N :: pos_integer(), Sz :: default | pos_integer()} - * - * Where N is the max number of reads. +/* + * This function return a property *map*. The properties are: + * domain: The domain of the socket + * type: The type of the socket + * protocol: The protocol of the socket + * owner: Controlling process (owner) of the socket) + * rstates: Socket read state(s) + * wstates: Socket write state(s) + * counters: A list of each socket counter and there current values + * readers: The number of current and waiting readers + * writers: The number of current and waiting writers + * acceptors: The number of current and waiting acceptors */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_socket_info(ErlNifEnv* env, + ESockDescriptor* descP) { - const ERL_NIF_TERM* t; // The array of the elements of the tuple - int tsz; // The size of the tuple - should be 2 - unsigned int n; - size_t bufSz; - ssize_t z; - - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> entry" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); - - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + ERL_NIF_TERM domain = esock_socket_info_domain(env, descP); + ERL_NIF_TERM type = esock_socket_info_type(env, descP); + ERL_NIF_TERM protocol = MKI(env, descP->protocol); + ERL_NIF_TERM ctrlPid = MKPID(env, &descP->ctrlPid); + ERL_NIF_TERM rstates = esock_socket_info_state(env, descP->readState); + ERL_NIF_TERM wstates = esock_socket_info_state(env, descP->writeState); + ERL_NIF_TERM ctype = esock_socket_info_ctype(env, descP); + ERL_NIF_TERM counters = esock_socket_info_counters(env, descP); + ERL_NIF_TERM readers = esock_socket_info_readers(env, descP); + ERL_NIF_TERM writers = esock_socket_info_writers(env, descP); + ERL_NIF_TERM acceptors = esock_socket_info_acceptors(env, descP); - if (esock_decode_bufsz(env, - eVal, - ESOCK_RECV_BUFFER_SIZE_DEFAULT, - &bufSz)) { - n = 0; // Reported as an integer buffer size by getopt - } else { - if ((! GET_TUPLE(env, eVal, &tsz, &t)) || - (tsz != 2) || - (! GET_UINT(env, t[0], &n)) || - (n == 0) || - (! esock_decode_bufsz(env, t[1], - ESOCK_RECV_BUFFER_SIZE_DEFAULT, - &bufSz))) { - SSDBG( descP, - ("SOCKET", - "esock_setopt_otp_rcvbuf {%d} -> done invalid\r\n", - descP->sock) ); - return esock_make_invalid(env, atom_value); - } - } - // We do not want a buffer size that does not fit in ssize_t - z = bufSz; - if (bufSz != (size_t) z) - return esock_make_invalid(env, atom_value); + { + ERL_NIF_TERM keys[] + = {esock_atom_domain, + esock_atom_type, + esock_atom_protocol, + atom_owner, + atom_rstates, + atom_wstates, + atom_ctype, + esock_atom_counters, + atom_num_readers, + atom_num_writers, + atom_num_acceptors}; + ERL_NIF_TERM vals[] + = {domain, + type, + protocol, + ctrlPid, + rstates, + wstates, + ctype, + counters, + readers, + writers, + acceptors}; + ERL_NIF_TERM info; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); - descP->rNum = n; - descP->rBufSz = bufSz; + SSDBG( descP, ("SOCKET", "esock_socket_info -> " + "\r\n numKeys: %d" + "\r\n numVals: %d" + "\r\n", numKeys, numVals) ); - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> ok" - "\r\n", descP->sock) ); + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); - return esock_atom_ok; + return info; + } } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option +/* + * Encode the socket domain */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_socket_info_domain(ErlNifEnv* env, + ESockDescriptor* descP) { - size_t val; - - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_recvctrlbuf {%d} -> entry" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + int domain = descP->domain; + ERL_NIF_TERM edomain; - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + esock_encode_domain(env, domain, &edomain); + return edomain; +} - if (! esock_decode_bufsz(env, - eVal, - ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT, - &val)) { - SSDBG( descP, - ("SOCKET", - "esock_setopt_otp_rcvctrlbuf {%d} -> done invalid\r\n", - descP->sock) ); - return esock_make_invalid(env, atom_value); - } - descP->rCtrlSz = val; +/* + * Encode the socket type + */ +static +ERL_NIF_TERM esock_socket_info_type(ErlNifEnv* env, + ESockDescriptor* descP) +{ + int type = descP->type; + ERL_NIF_TERM etype; - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> ok" - "\r\n", descP->sock) ); + esock_encode_type(env, type, &etype); - return esock_atom_ok; + return etype; } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option +/* + * Encode the socket "create type" + * That is; "show" how this socket was created: + * + * normal | fromfd | {fromfd, integer()} */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_socket_info_ctype(ErlNifEnv* env, + ESockDescriptor* descP) { - size_t val; - - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_sndvctrlbuf {%d} -> entry" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); - - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + ERL_NIF_TERM ctype; - if (! esock_decode_bufsz(env, - eVal, - ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT, - &val)) { - SSDBG( descP, - ("SOCKET", - "esock_setopt_otp_sndctrlbuf {%d} -> done invalid\r\n", - descP->sock) ); - return esock_make_invalid(env, atom_value); - } + SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> entry with" + "\r\n origFD: %d" + "\r\n closeOnClose: %s" + "\r\n", descP->sock, + descP->origFD, B2S(descP->closeOnClose)) ); - descP->wCtrlSz = val; + if (descP->origFD != INVALID_SOCKET) { + /* Created from other FD */ + if (descP->closeOnClose) { + /* We *have* dup'ed: {fromfd, integer()} */ + ctype = MKT2(env, MKA(env, "fromfd"), MKI(env, descP->origFD)); + } else { + /* We have *not* dup'ed: fromfd */ + ctype = MKA(env, "fromfd"); + } + } else { + /* Normal socket */ + ctype = MKA(env, "normal"); + } - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> ok" - "\r\n", descP->sock) ); + SSDBG( descP, ("SOCKET", "esock_socket_info_ctype {%d} -> done:" + "\r\n ctype: %T" + "\r\n", descP->sock, ctype) ); - return esock_atom_ok; + return ctype; } -#endif // #ifndef __WIN32__ -/* esock_setopt_otp_meta - Handle the OTP (level) meta options +/* + * Encode the socket "state" + * This is a list of atoms, one for each valid 'state' value. */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_socket_info_state(ErlNifEnv* env, + unsigned int state) { - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + SocketTArray estate = TARRAY_CREATE(10); + ERL_NIF_TERM estateList; - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_meta {%d} -> entry" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_meta {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + if ((state & ESOCK_STATE_BOUND) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> bound" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_bound); } - if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) { - SSDBG( descP, ("SOCKET", - "esock_setopt_otp_meta -> not owner (%T)\r\n", - descP->ctrlPid) ); - return esock_make_error_invalid(env, esock_atom_not_owner); + if ((state & ESOCK_STATE_LISTENING) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> listening" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_listening); } - enif_clear_env(descP->meta.env); - descP->meta.ref = CP_TERM(descP->meta.env, eVal); - - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_meta {%d} -> ok" - "\r\n", descP->sock) ); - - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ - + if ((state & ESOCK_STATE_ACCEPTING) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> accepting" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_accepting); + } -/* esock_setopt_otp_use_registry - Handle the OTP (level) use_registry option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eVal) -{ - BOOLEAN_T useReg = FALSE; + if ((state & ESOCK_STATE_CONNECTING) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connecting" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, esock_atom_connecting); + } - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_use_registry {%d} -> closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + if ((state & ESOCK_STATE_CONNECTED) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> connected" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, esock_atom_connected); } - if (! esock_decode_bool(eVal, &useReg)) - return esock_make_invalid(env, atom_value); + if ((state & ESOCK_STATE_SELECTED) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> selected" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_selected); + } - /* We only allow turning this on! */ - if (! useReg) - return esock_make_invalid(env, atom_value); + if ((state & ESOCK_STATE_CLOSING) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closing" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_closing); + } - if (!descP->useReg) { - ERL_NIF_TERM sockRef = enif_make_resource(env, descP); + if ((state & ESOCK_STATE_CLOSED) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> closed" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, esock_atom_closed); + } - descP->useReg = useReg; - esock_send_reg_add_msg(env, descP, sockRef); + if ((state & ESOCK_STATE_DTOR) != 0) { + /* + SSDBG( descP, ("SOCKET", "esock_socket_info_state {%d} -> dtor" + "\r\n", descP->sock) ); + */ + TARRAY_ADD(estate, atom_dtor); } - SSDBG( descP, - ("SOCKET", "esock_setopt_otp_use_registry {%d} -> ok" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + TARRAY_TOLIST(estate, env, &estateList); - return esock_atom_ok; + return estateList; } -#endif // #ifndef __WIN32__ -/* The option has *not* been encoded. Instead it has been provided - * in "native mode" (value is a binary, an integer or a boolean). +/* + * Collect all counters for a socket. */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env, + ESockDescriptor* descP) { - ErlNifBinary binary; - int integer; - BOOLEAN_T boolean; - ERL_NIF_TERM result; - - MLOCK(descP->writeMtx); + ERL_NIF_TERM keys[] = {esock_atom_read_byte, + esock_atom_read_fails, + esock_atom_read_pkg, + atom_read_pkg_max, + esock_atom_read_tries, + atom_read_waits, + esock_atom_write_byte, + esock_atom_write_fails, + esock_atom_write_pkg, + atom_write_pkg_max, + esock_atom_write_tries, + esock_atom_write_waits, + esock_atom_acc_success, + esock_atom_acc_fails, + esock_atom_acc_tries, + esock_atom_acc_waits}; + unsigned int numKeys = NUM(keys); + ERL_NIF_TERM vals[] = {MKCNT(env, descP->readByteCnt), + MKCNT(env, descP->readFails), + MKCNT(env, descP->readPkgCnt), + MKCNT(env, descP->readPkgMax), + MKCNT(env, descP->readTries), + MKCNT(env, descP->readWaits), + MKCNT(env, descP->writeByteCnt), + MKCNT(env, descP->writeFails), + MKCNT(env, descP->writePkgCnt), + MKCNT(env, descP->writePkgMax), + MKCNT(env, descP->writeTries), + MKCNT(env, descP->writeWaits), + MKCNT(env, descP->accSuccess), + MKCNT(env, descP->accFails), + MKCNT(env, descP->accTries), + MKCNT(env, descP->accWaits)}; + unsigned int numVals = NUM(vals); + ERL_NIF_TERM cnts; - SSDBG( descP, - ("SOCKET", "esock_setopt_native {%d} -> entry" - "\r\n level: %d" - "\r\n opt: %d" - "\r\n eVal: %T" - "\r\n", descP->sock, - level, opt, eVal) ); + SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> " + "\r\n numKeys: %d" + "\r\n numVals: %d" + "\r\n", numKeys, numVals) ); - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_native {%d} -> done closed\r\n", - descP->sock) ); + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &cnts) ); - MUNLOCK(descP->writeMtx); - return esock_make_error(env, atom_closed); - } +#ifdef HAVE_SENDFILE + if (descP->sendfileCountersP != NULL) { + ESockSendfileCounters *cP = descP->sendfileCountersP; + ERL_NIF_TERM m, + sfKeys[] = + {esock_atom_sendfile, + esock_atom_sendfile_byte, + esock_atom_sendfile_fails, + esock_atom_sendfile_max, + esock_atom_sendfile_pkg, + esock_atom_sendfile_pkg_max, + esock_atom_sendfile_tries, + esock_atom_sendfile_waits}, + sfVals[] = + {MKUI(env, cP->cnt), + MKUI(env, cP->byteCnt), + MKUI(env, cP->fails), + MKUI(env, cP->max), + MKUI(env, cP->pkg), + MKUI(env, cP->pkgMax), + MKUI(env, cP->tries), + MKUI(env, cP->waits)}; + size_t n, numSfKeys = NUM(sfKeys); - if (GET_BIN(env, eVal, &binary)) { - result = esock_setopt_level_opt(env, descP, level, opt, - binary.data, binary.size); - } else if (GET_INT(env, eVal, &integer)) { - result = esock_setopt_level_opt(env, descP, level, opt, - &integer, sizeof(integer)); - } else if (esock_decode_bool(eVal, &boolean)) { - integer = boolean ? 1 : 0; - result = esock_setopt_level_opt(env, descP, level, opt, - &integer, sizeof(integer)); - } else { - result = esock_make_error_invalid(env, atom_value); + ESOCK_ASSERT( numSfKeys == NUM(sfVals) ); + for (n = 0; n < numSfKeys; n++) { + ESOCK_ASSERT( enif_make_map_put(env, cnts, + sfKeys[n], sfVals[n], + &m) ); + cnts = m; + } } +#endif - SSDBG( descP, - ("SOCKET", "esock_setopt_native {%d} -> done when" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> done with" + "\r\n cnts: %T" + "\r\n", cnts) ); - MUNLOCK(descP->writeMtx); - return result; + return cnts; } -#endif // #ifndef __WIN32__ -/* esock_setopt - A "proper" level (option) has been specified, - * and we have an value of known encoding + +/* ---------------------------------------------------------------------- + * nif_command + * + * Description: + * This function is intended to handle "various" commands. That is, + * commands and operations that are not part of the socket API proper. + * It's a map with two attributes command and (command) data: + * #{command :: atom(), data :: term()} + * + * Currently it handles setting: + * + * Command Data + * ------- ---- + * (global) debug boolean() + * socket_debug boolean() + * use_registry boolean() + * */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_setopt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_command(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM result; - const struct ESockOpt *optP; - - MLOCK(descP->writeMtx); + ERL_NIF_TERM command, cdata, result; - SSDBG( descP, - ("SOCKET", "esock_setopt {%d} -> entry with" - "\r\n level: %d" - "\r\n opt: %d" - "\r\n eVal: %T" - "\r\n", descP->sock, level, opt, eVal) ); + ESOCK_ASSERT( argc == 1 ); - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_setopt {%d} -> done closed\r\n", - descP->sock) ); + SGDBG( ("SOCKET", "nif_command -> entry with %d args\r\n", argc) ); - MUNLOCK(descP->writeMtx); - return esock_make_error(env, atom_closed); + if (! GET_MAP_VAL(env, argv[0], esock_atom_command, &command)) { + SGDBG( ("SOCKET", + "nif_command -> field not found: command\r\n") ); + return enif_make_badarg(env); + } + if (! GET_MAP_VAL(env, argv[0], esock_atom_data, &cdata)) { + SGDBG( ("SOCKET", + "nif_command -> field not found: data\r\n") ); + return enif_make_badarg(env); } - optP = lookupOpt(level, opt); - - if (optP == NULL) { + SGDBG( ("SOCKET", "nif_command -> " + "\r\n command: %T" + "\r\n cdata: %T" + "\r\n", command, cdata) ); - result = esock_make_invalid(env, atom_socket_option); + result = ESOCK_IO_CMD(env, command, cdata); - SSDBG( descP, - ("SOCKET", - "esock_setopt {%d} -> unknown option\r\n", - descP->sock) ); + SGDBG( ("SOCKET", "nif_command -> done with result: " + "\r\n %T" + "\r\n", result) ); - } else if (optP->setopt == NULL) { + return result; - result = esock_make_invalid(env, atom_socket_option); +} - SSDBG( descP, - ("SOCKET", - "esock_setopt {%d} -> opt not settable\r\n", - descP->sock) ); - } else { +static +ERL_NIF_TERM esock_command(ErlNifEnv* env, ERL_NIF_TERM command, ERL_NIF_TERM cdata) +{ + int cmp; - result = (optP->setopt)(env, descP, level, opt, eVal); + SGDBG( ("SOCKET", "esock_command -> entry with %T\r\n", command) ); - SSDBG( descP, - ("SOCKET", "esock_setopt {%d} -> done when" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + cmp = COMPARE(command, atom_socket_debug); + if (cmp == 0) { + return esock_command_socket_debug(env, cdata); + } else if (cmp < 0) { + if (COMPARE(command, esock_atom_debug) == 0) + return esock_command_debug(env, cdata); + } else { // 0 < cmp + if (COMPARE(command, esock_atom_use_registry) == 0) + return esock_command_use_socket_registry(env, cdata); } - MUNLOCK(descP->writeMtx); - return result; + SGDBG( ("SOCKET", "esock_command -> invalid command: %T\r\n", + command) ); + + return esock_raise_invalid(env, MKT2(env, esock_atom_command, command)); } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#if defined(SO_BINDTODEVICE) static -ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_command_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) { - return esock_setopt_str_opt(env, descP, level, opt, IFNAMSIZ, eVal); + ERL_NIF_TERM result; + + /* The data *should* be a boolean() */ + if (esock_decode_bool(cdata, &data.dbg)) + result = esock_atom_ok; + else + result = esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); + + return result; } -#endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#if defined(SO_LINGER) static -ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_command_socket_debug(ErlNifEnv* env, ERL_NIF_TERM cdata) { - ERL_NIF_TERM eOnOff, eLinger; - BOOLEAN_T onOff; - struct linger val; - - sys_memzero(&val, sizeof(val)); - - if ((! GET_MAP_VAL(env, eVal, atom_onoff, &eOnOff)) || - (! GET_MAP_VAL(env, eVal, esock_atom_linger, &eLinger))) { + BOOLEAN_T dbg; - if (COMPARE(eVal, esock_atom_abort) == 0) { - val.l_onoff = 1; - val.l_linger = 0; - return esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); - } else - return esock_make_invalid(env, atom_value); - } + /* The data *should* be a boolean() */ + if (! esock_decode_bool(cdata, &dbg)) + return esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - if ((! esock_decode_bool(eOnOff, &onOff)) || - (! GET_INT(env, eLinger, &val.l_linger)) || - (val.l_linger < 0)) { - return esock_make_invalid(env, atom_value); - } - val.l_onoff = onOff ? 1 : 0; + MLOCK(data.cntMtx); + data.sockDbg = dbg; + MUNLOCK(data.cntMtx); - return esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); + return esock_atom_ok;; } -#endif -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ -#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) - -/* esock_setopt_msfilter - Level IP MSFILTER option - * - * The value can be *either* the atom 'null' or a map of type ip_msfilter(). - */ static -ERL_NIF_TERM esock_setopt_msfilter(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_command_use_socket_registry(ErlNifEnv* env, + ERL_NIF_TERM cdata) { - ERL_NIF_TERM result; + BOOLEAN_T useReg = FALSE; - if (COMPARE(eVal, atom_null) == 0) { - return - esock_setopt_level_opt(env, descP, level, opt, NULL, 0); - } else { - struct ip_msfilter* msfP; - Uint32 msfSz; - ERL_NIF_TERM eMultiAddr, eInterface, eFMode, eSList, elem, tail; - unsigned int slistLen, idx; + /* The data *should* be a boolean() */ + if (! esock_decode_bool(cdata, &useReg)) + return esock_raise_invalid(env, MKT2(env, esock_atom_data, cdata)); - if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) || - (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) || - (! GET_MAP_VAL(env, eVal, atom_mode, &eFMode)) || - (! GET_MAP_VAL(env, eVal, atom_slist, &eSList))) - goto invalid; + MLOCK(data.cntMtx); + data.useReg = useReg; + MUNLOCK(data.cntMtx); - /* We start (decoding) with the slist, since without it we don't - * really know how much (memory) to allocate. - */ - if (! GET_LIST_LEN(env, eSList, &slistLen)) - goto invalid; + return esock_atom_ok; +} - msfSz = IP_MSFILTER_SIZE(slistLen); - msfP = MALLOC(msfSz); - ESOCK_ASSERT( msfP != NULL ); - if ((! esock_decode_in_addr(env, eMultiAddr, - &msfP->imsf_multiaddr)) || - (! esock_decode_in_addr(env, eInterface, - &msfP->imsf_interface)) || - (! decode_msfilter_mode(env, eFMode, - (Uint32*) &msfP->imsf_fmode))) - goto free_invalid; - /* And finally, extract the source addresses */ - msfP->imsf_numsrc = slistLen; - for (idx = 0; idx < slistLen; idx++) { - ESOCK_ASSERT( GET_LIST_ELEM(env, eSList, &elem, &tail) ); - if (! esock_decode_in_addr(env, elem, - &msfP->imsf_slist[idx])) - goto free_invalid; - eSList = tail; - } +/* *** esock_socket_info_readers *** + * *** esock_socket_info_writers *** + * *** esock_socket_info_acceptors *** + * + * Calculate how many readers | writers | acceptors we have for this socket. + * Current requestor + any waiting requestors (of the type). + * Note that "Current requestor" is *not* used on Windows. + */ - /* And now, finally, set the option */ - result = esock_setopt_level_opt(env, descP, level, opt, - msfP, msfSz); +#ifndef __WIN32__ - FREE(msfP); - return result; +#define ESOCK_INFO_REQ_FUNCS \ + ESOCK_INFO_REQ_FUNC_DECL(readers, currentReaderP, readersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(writers, currentWriterP, writersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(acceptors, currentAcceptorP, acceptorsQ) - free_invalid: - FREE(msfP); - invalid: - return esock_make_invalid(env, atom_value); +#define ESOCK_INFO_REQ_FUNC_DECL(F, CRP, Q) \ + static \ + ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) \ + { \ + return socket_info_reqs(env, descP, descP->CRP, &descP->Q); \ } +#else -} +#define ESOCK_INFO_REQ_FUNCS \ + ESOCK_INFO_REQ_FUNC_DECL(readers, readersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(writers, writersQ) \ + ESOCK_INFO_REQ_FUNC_DECL(acceptors, acceptorsQ) + +#define ESOCK_INFO_REQ_FUNC_DECL(F, Q) \ + static \ + ERL_NIF_TERM esock_socket_info_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) \ + { \ + return socket_info_reqs(env, descP, &descP->Q); \ + } + +#endif + +ESOCK_INFO_REQ_FUNCS +#undef ESOCK_INFO_REQ_FUNC_DECL static -BOOLEAN_T decode_msfilter_mode(ErlNifEnv* env, - ERL_NIF_TERM eVal, - Uint32* mode) +ERL_NIF_TERM socket_info_reqs(ErlNifEnv* env, + ESockDescriptor* descP, +#ifndef __WIN32__ + ESockRequestor* currentRequestorP, +#endif + ESockRequestQueue* q) { - BOOLEAN_T result; + ERL_NIF_TERM info; + unsigned int cnt; - if (COMPARE(eVal, atom_include) == 0) { - *mode = MCAST_INCLUDE; - result = TRUE; - } else if (COMPARE(eVal, atom_exclude) == 0) { - *mode = MCAST_EXCLUDE; - result = TRUE; +#ifdef __WIN32__ + cnt = 0; +#else + if (currentRequestorP != NULL) { + // We have an active requestor! + cnt = 1; } else { - result = FALSE; + cnt = 0; } +#endif - return result; -} + info = MKUI(env, cnt + qlength(q)); -#endif // #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) -#endif // #ifndef __WIN32__ + SSDBG( descP, ("SOCKET", "socket_info_reqs -> done with" + "\r\n info: %T" + "\r\n", info) ); + return info; +} -/* esock_setopt_ip_mtu_discover - Level IP MTU_DISCOVER option + +/* ---------------------------------------------------------------------- + * nif_supports * - * The value is an atom of the type ip_pmtudisc(). + * Description: + * This function is intended to answer the question: "Is X supported?" + * Currently three keys are "supported": options | sctp | ipv6 + * That results in a list of all *known options* (known by us) and if + * the platform supports (OS) it or not. + * + * Key + * --- + * (arity 0) [{sctp, boolean()}, + * {ipv6, boolean()}, + * {local, boolean()}, + * {netns, boolean()}, + * {sendfile, boolean()}] + * + * msg_flags [{MsgFlag, boolean()}] + * protocols [{[Protocol | Aliases], integer()}], + * options [{socket, [{Opt, boolean()} | Opt]} | + * {ProtoNum::integer(), [{Opt, boolean()} | Opt]}] */ -#ifndef __WIN32__ -#if defined(IP_MTU_DISCOVER) + static -ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_supports(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - int val; - if (! decode_ip_pmtudisc(env, eVal, &val)) - return esock_make_invalid(env, atom_value); - else - return esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); -} -#endif // #if defined(IP_MTU_DISCOVER) -#endif // #ifndef __WIN32__ + SGDBG( ("SOCKET", "nif_supports -> entry with %d args\r\n", argc) ); + + /* Extract arguments and perform preliminary validation */ + if (argc == 0) + return ESOCK_IO_SUPPORTS_0(env); + if (argc == 1) + return ESOCK_IO_SUPPORTS_1(env, argv[0]); -/* esock_setopt_multicast_if - Level IP MULTICAST_IF option + return esock_make_error(env, esock_atom_einval); + +} + + +/* esock_supports - what features do we support? * - * The value is either the atom 'any' or a 4-tuple. + * This gives information about what features actually + * work on the current platform. */ -#ifndef __WIN32__ -#if defined(IP_MULTICAST_IF) + static -ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_supports_0(ErlNifEnv* env) { - ERL_NIF_TERM result; - struct in_addr ifAddr; + SocketTArray opts = TARRAY_CREATE(8); + ERL_NIF_TERM is_supported, opts_list; - if (! esock_decode_in_addr(env, eVal, &ifAddr)) { - result = esock_make_invalid(env, atom_value); - } else { - result = - esock_setopt_level_opt(env, descP, level, opt, - &ifAddr, sizeof(ifAddr)); - } + SGDBG( ("SOCKET", "esock_supports_0 -> entry\r\n") ); - return result; -} +#if defined(HAVE_SCTP) + is_supported = esock_atom_true; +#else + is_supported = esock_atom_false; #endif -#endif // #ifndef __WIN32__ + TARRAY_ADD(opts, MKT2(env, esock_atom_sctp, is_supported)); -/* esock_setopt_tos - Level IP TOS option - */ -#ifndef __WIN32__ -#if defined(IP_TOS) -static -ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM result; - int val; + /* Is this (test) really sufficient for testing if we support IPv6? */ +#if defined(HAVE_IPV6) + is_supported = esock_atom_true; +#else + is_supported = esock_atom_false; +#endif + TARRAY_ADD(opts, MKT2(env, esock_atom_ipv6, is_supported)); - if (decode_ip_tos(env, eVal, &val)) { - result = - esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); - } else { - result = esock_make_invalid(env, atom_value); - } +#if defined(AF_LOCAL) + is_supported = esock_atom_true; +#else + is_supported = esock_atom_false; +#endif + TARRAY_ADD(opts, MKT2(env, esock_atom_local, is_supported)); - return result; -} +#if defined(HAVE_SETNS) + is_supported = esock_atom_true; +#else + is_supported = esock_atom_false; #endif -#endif // #ifndef __WIN32__ + TARRAY_ADD(opts, MKT2(env, esock_atom_netns, is_supported)); +#if defined(HAVE_SENDFILE) + is_supported = esock_atom_true; +#else + is_supported = esock_atom_false; +#endif + TARRAY_ADD(opts, MKT2(env, esock_atom_sendfile, is_supported)); + + TARRAY_TOLIST(opts, env, &opts_list); + return opts_list; +} -/* The value is a map with two attributes: multiaddr and interface. - * The attribute 'multiaddr' is always a 4-tuple (IPv4 address). - * The attribute 'interface' is either the atom 'any' or a 4-tuple - * (IPv4 address). - */ -#ifndef __WIN32__ -#if defined(IP_ADD_MEMBERSHIP) || defined(IP_DROP_MEMBERSHIP) static -ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_supports_1(ErlNifEnv* env, ERL_NIF_TERM key) { - ERL_NIF_TERM eMultiAddr, eInterface; - struct ip_mreq mreq; + ERL_NIF_TERM result; - if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in_update_membership -> " - "failed get multiaddr (map) attribute\r\n") ); - goto invalid; - } + SGDBG( ("SOCKET", + "esock_supports_1 -> entry" + "\r\n key: %T" + "\r\n", key) ); - if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in_update_membership -> " - "failed get interface (map) attribute\r\n") ); - goto invalid; - } + if (COMPARE(key, atom_msg_flags) == 0) + result = esock_supports_msg_flags(env); + else if (COMPARE(key, atom_protocols) == 0) + result = esock_supports_protocols(env); + else if (COMPARE(key, atom_ioctl_requests) == 0) + result = esock_supports_ioctl_requests(env); + else if (COMPARE(key, atom_ioctl_flags) == 0) + result = esock_supports_ioctl_flags(env); + else if (COMPARE(key, atom_options) == 0) + result = esock_supports_options(env); + else + result = MKEL(env); - if (! esock_decode_in_addr(env, - eMultiAddr, - &mreq.imr_multiaddr)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in_update_membership -> " - "failed decode multiaddr %T\r\n", eMultiAddr) ); - goto invalid; - } + return result; +} - if (! esock_decode_in_addr(env, - eInterface, - &mreq.imr_interface)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in_update_membership -> " - "failed decode interface %T\r\n", eInterface) ); - goto invalid; - } - return esock_setopt_level_opt(env, descP, level, opt, - &mreq, sizeof(mreq)); - invalid: - return esock_make_invalid(env, atom_value); +static ERL_NIF_TERM esock_supports_msg_flags(ErlNifEnv* env) { + size_t n; + ERL_NIF_TERM result; + + result = MKEL(env); + for (n = 0; n < esock_msg_flags_length; n++) { + result = + MKC(env, + MKT2(env, + *(esock_msg_flags[n].name), + MKI(env, esock_msg_flags[n].flag)), + result); + } + + return result; } + + + +static +ERL_NIF_TERM esock_supports_protocols(ErlNifEnv* env) +{ + ERL_NIF_TERM protocols; +#ifndef __WIN32__ +#if defined(SOL_IP) + int protoIP = SOL_IP; +#else + int protoIP = IPPROTO_IP; #endif -#endif // #ifndef __WIN32__ +#else + int protoIP = IPPROTO_IP; +#endif +#if defined(HAVE_IPV6) +#ifndef __WIN32__ +#if defined(SOL_IPV6) + int protoIPV6 = SOL_IPV6; +#else + int protoIPV6 = IPPROTO_IPV6; +#endif +#else + int protoIPV6 = IPPROTO_IPV6; +#endif +#endif + + protocols = MKEL(env); + +#if defined(HAVE_GETPROTOENT) && \ + defined(HAVE_SETPROTOENT) && \ + defined(HAVE_ENDPROTOENT) + { + struct protoent *pe; + int stayopen; -/* The value is a map with three attributes: multiaddr, interface and - * sourceaddr. - * The attribute 'multiaddr' is always a 4-tuple (IPv4 address). - * The attribute 'interface' is always a 4-tuple (IPv4 address). - * The attribute 'sourceaddr' is always a 4-tuple (IPv4 address). - * (IPv4 address). - */ -#ifndef __WIN32__ -#if defined(IP_ADD_SOURCE_MEMBERSHIP) || \ - defined(IP_DROP_SOURCE_MEMBERSHIP) || \ - defined(IP_BLOCK_SOURCE) || \ - defined(IP_UNBLOCK_SOURCE) -static -ERL_NIF_TERM esock_setopt_in_update_source(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM eMultiAddr, eInterface, eSourceAddr; - struct ip_mreq_source mreq; + MLOCK(data.protocolsMtx); + stayopen = TRUE; + setprotoent(stayopen); + while ((pe = getprotoent()) != NULL) { + ERL_NIF_TERM names; + char **aliases; - if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) || - (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) || - (! GET_MAP_VAL(env, eVal, atom_sourceaddr, &eSourceAddr)) || - (! esock_decode_in_addr(env, - eMultiAddr, - &mreq.imr_multiaddr)) || - (! esock_decode_in_addr(env, - eInterface, - &mreq.imr_interface)) || - (! esock_decode_in_addr(env, - eSourceAddr, - &mreq.imr_sourceaddr))) - goto invalid; + names = MKEL(env); + for (aliases = pe->p_aliases; *aliases != NULL; aliases++) + names = MKC(env, MKA(env, *aliases), names); + names = MKC(env, MKA(env, pe->p_name), names); - return esock_setopt_level_opt(env, descP, level, opt, - &mreq, sizeof(mreq)); - invalid: - return esock_make_invalid(env, atom_value); -} + protocols = + MKC(env, MKT2(env, names, MKI(env, pe->p_proto)), protocols); + } + endprotoent(); + MUNLOCK(data.protocolsMtx); + } #endif -#endif // #ifndef __WIN32__ + /* Defaults for known protocols in case getprotoent() + * does not work or does not exist. Prepended to the list + * so a subsequent maps:from_list/2 will take the default + * only when there is nothing from getprotoent(). + */ + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_ip), MKI(env, protoIP)), + protocols); -#if defined(HAVE_IPV6) +#ifdef HAVE_IPV6 + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_ipv6), MKI(env, protoIPV6)), + protocols); +#endif + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_tcp), MKI(env, IPPROTO_TCP)), + protocols); + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_udp), MKI(env, IPPROTO_UDP)), + protocols); -#ifndef __WIN32__ -#if defined(IPV6_ADDRFORM) -static -ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - int domain; +#ifdef IPPROTO_RM + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_rm), MKI(env, IPPROTO_RM)), + protocols); +#endif - SSDBG( descP, - ("SOCKET", "esock_setopt_addrform -> entry with" - "\r\n eVal: %T" - "\r\n", eVal) ); +#ifdef HAVE_SCTP + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_sctp), MKI(env, IPPROTO_SCTP)), + protocols); +#endif - if (esock_decode_domain(env, eVal, &domain) == 0) - return esock_make_invalid(env, atom_value); + protocols = + MKC(env, + MKT2(env, MKL1(env, esock_atom_igmp), MKI(env, IPPROTO_IGMP)), + protocols); - SSDBG( descP, ("SOCKET", - "esock_setopt_addrform -> try set opt to %d\r\n", - domain) ); - - return esock_setopt_level_opt(env, descP, level, opt, - &domain, sizeof(domain)); + return protocols; } -#endif -#endif // #ifndef __WIN32__ - -/* esock_setopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option - * - * The value is an atom of the type ipv6_pmtudisc(). - */ -#ifndef __WIN32__ -#if defined(IPV6_MTU_DISCOVER) static -ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM esock_supports_ioctl_requests(ErlNifEnv* env) { - int val; + ERL_NIF_TERM requests; - if (! decode_ipv6_pmtudisc(env, eVal, &val)) - return esock_make_invalid(env, atom_value); + requests = MKEL(env); - return esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); -} + /* --- GET REQUESTS --- */ +#if defined(SIOCGIFCONF) + requests = MKC(env, MKT2(env, atom_gifconf, MKUL(env, SIOCGIFCONF)), requests); #endif -#endif // #ifndef __WIN32__ +#if defined(FIONREAD) + requests = MKC(env, MKT2(env, atom_nread, MKUL(env, FIONREAD)), requests); +#endif -#ifndef __WIN32__ -#if defined(IPV6_MULTICAST_HOPS) -static -ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - int hops; +#if defined(FIONWRITE) + requests = MKC(env, MKT2(env, atom_nwrite, MKUL(env, FIONWRITE)), requests); +#endif - if (! decode_hops(env, eVal, &hops)) - return esock_make_invalid(env, atom_value); +#if defined(FIONSPACE) + requests = MKC(env, MKT2(env, atom_nspace, MKUL(env, FIONSPACE)), requests); +#endif - return esock_setopt_level_opt(env, descP, level, opt, - &hops, sizeof(hops)); -} +#if defined(SIOCATMARK) + requests = MKC(env, MKT2(env, atom_atmark, MKUL(env, SIOCATMARK)), requests); #endif -#endif // #ifndef __WIN32__ +#if defined(SIOCGIFNAME) + requests = MKC(env, MKT2(env, atom_gifname, MKUL(env, SIOCGIFNAME)), requests); +#endif -#ifndef __WIN32__ -#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP) -static -ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM eMultiAddr, eInterface; - struct ipv6_mreq mreq; +#if defined(SIOCGIFINDEX) + requests = MKC(env, MKT2(env, atom_gifindex, MKUL(env, SIOCGIFINDEX)), requests); +#endif - if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in6_update_membership -> " - "failed get multiaddr (map) attribute\r\n") ); - goto invalid; - } +#if defined(SIOCGIFFLAGS) + requests = MKC(env, MKT2(env, atom_gifflags, MKUL(env, SIOCGIFFLAGS)), requests); +#endif - if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in6_update_membership -> " - "failed get interface (map) attribute\r\n") ); - goto invalid; - } +#if defined(SIOCGIFADDR) + requests = MKC(env, MKT2(env, atom_gifaddr, MKUL(env, SIOCGIFADDR)), requests); +#endif - if (! esock_decode_in6_addr(env, - eMultiAddr, - &mreq.ipv6mr_multiaddr)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in6_update_membership -> " - "failed decode multiaddr %T\r\n", eMultiAddr) ); - goto invalid; - } +#if defined(SIOCGIFDSTADDR) + requests = MKC(env, MKT2(env, atom_gifdstaddr, MKUL(env, SIOCGIFDSTADDR)), requests); +#endif - if (! GET_UINT(env, eInterface, &mreq.ipv6mr_interface)) { - SSDBG( descP, - ("SOCKET", "esock_setopt_in6_update_membership -> " - "failed decode interface %T\r\n", eInterface) ); - goto invalid; - } +#if defined(SIOCGIFBRDADDR) + requests = MKC(env, MKT2(env, atom_gifbrdaddr, MKUL(env, SIOCGIFBRDADDR)), requests); +#endif - return esock_setopt_level_opt(env, descP, level, opt, - &mreq, sizeof(mreq)); +#if defined(SIOCGIFNETMASK) + requests = MKC(env, MKT2(env, atom_gifnetmask, MKUL(env, SIOCGIFNETMASK)), requests); +#endif - invalid: - return esock_make_invalid(env, atom_value); -} +#if defined(SIOCGIFMTU) + requests = MKC(env, MKT2(env, atom_gifmtu, MKUL(env, SIOCGIFMTU)), requests); #endif -#endif // #ifndef __WIN32__ +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) + requests = MKC(env, MKT2(env, atom_gifhwaddr, MKUL(env, SIOCGIFHWADDR)), requests); +#endif -#endif // defined(HAVE_IPV6) +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) + requests = MKC(env, MKT2(env, atom_gifmap, MKUL(env, SIOCGIFMAP)), requests); +#endif +#if defined(SIOCGIFTXQLEN) + requests = MKC(env, MKT2(env, atom_giftxqlen, MKUL(env, SIOCGIFTXQLEN)), requests); +#endif +#if defined(SIO_TCP_INFO) + requests = MKC(env, MKT2(env, atom_tcp_info, MKUL(env, SIO_TCP_INFO)), requests); +#endif + /* --- SET REQUESTS --- */ +#if defined(SIOCSIFFLAGS) + requests = MKC(env, MKT2(env, atom_sifflags, MKUL(env, SIOCSIFFLAGS)), requests); +#endif -/* esock_setopt_tcp_congestion - Level TCP CONGESTION option - */ -#ifndef __WIN32__ -#if defined(TCP_CONGESTION) -static -ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1; +#if defined(SIOCSIFADDR) + requests = MKC(env, MKT2(env, atom_sifaddr, MKUL(env, SIOCSIFADDR)), requests); +#endif + +#if defined(SIOCSIFDSTADDR) + requests = MKC(env, MKT2(env, atom_sifdstaddr, MKUL(env, SIOCSIFDSTADDR)), requests); +#endif + +#if defined(SIOCSIFBRDADDR) + requests = MKC(env, MKT2(env, atom_sifbrdaddr, MKUL(env, SIOCSIFBRDADDR)), requests); +#endif - return esock_setopt_str_opt(env, descP, level, opt, max, eVal); -} +#if defined(SIOCSIFMTU) + requests = MKC(env, MKT2(env, atom_sifmtu, MKUL(env, SIOCSIFMTU)), requests); #endif -#endif // #ifndef __WIN32__ +#if defined(SIOCSIFTXQLEN) + requests = MKC(env, MKT2(env, atom_siftxqlen, MKUL(env, SIOCSIFTXQLEN)), requests); +#endif +#if defined(SIO_RCVALL) + requests = MKC(env, MKT2(env, atom_rcvall, MKUL(env, SIO_RCVALL)), requests); +#endif -#if defined(HAVE_SCTP) +#if defined(SIO_RCVALL_IGMPMCAST) + requests = MKC(env, MKT2(env, atom_rcvall_igmpmcast, MKUL(env, SIO_RCVALL_IGMPMCAST)), requests); +#endif +#if defined(SIO_RCVALL_MCAST) + requests = MKC(env, MKT2(env, atom_rcvall_mcast, MKUL(env, SIO_RCVALL_MCAST)), requests); +#endif + return requests; +} -/* esock_setopt_sctp_associnfo - Level SCTP ASSOCINFO option - */ -#ifndef __WIN32__ -#if defined(SCTP_ASSOCINFO) -static -ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM eAssocId, eMaxRxt, eNumPeerDests; - ERL_NIF_TERM ePeerRWND, eLocalRWND, eCookieLife; - struct sctp_assocparams assocParams; - unsigned int ui; - SSDBG( descP, - ("SOCKET", "esock_setopt_sctp_associnfo -> entry with" - "\r\n eVal: %T" - "\r\n", eVal) ); - // It must be a map - if (! IS_MAP(env, eVal)) - goto invalid; +static +ERL_NIF_TERM esock_supports_ioctl_flags(ErlNifEnv* env) +{ + size_t n; + ERL_NIF_TERM result; - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_associnfo -> extract attributes\r\n") ); + result = MKEL(env); + for (n = 0; n < esock_ioctl_flags_length; n++) { + result = + MKC(env, + MKT2(env, + *(esock_ioctl_flags[n].name), + MKI(env, esock_ioctl_flags[n].flag)), + result); + } - if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) || - (! GET_MAP_VAL(env, eVal, atom_asocmaxrxt, &eMaxRxt)) || - (! GET_MAP_VAL(env, eVal, atom_number_peer_destinations, - &eNumPeerDests)) || - (! GET_MAP_VAL(env, eVal, atom_peer_rwnd, &ePeerRWND)) || - (! GET_MAP_VAL(env, eVal, atom_local_rwnd, &eLocalRWND)) || - (! GET_MAP_VAL(env, eVal, atom_cookie_life, &eCookieLife))) - goto invalid; + return result; +} - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_associnfo -> decode attributes\r\n") ); - if (! decode_sctp_assoc_t(env, eAssocId, &assocParams.sasoc_assoc_id)) - goto invalid; - /* - * We should really make sure this is ok in erlang (to ensure that - * the values (max-rxt and num-peer-dests) fits in 16-bits). - * The value should be a 16-bit unsigned int... - * Both sasoc_asocmaxrxt and sasoc_number_peer_destinations. - */ - if (! GET_UINT(env, eMaxRxt, &ui)) - goto invalid; - assocParams.sasoc_asocmaxrxt = (Uint16) ui; +static +ERL_NIF_TERM esock_supports_options(ErlNifEnv* env) +{ + ERL_NIF_TERM levels; + size_t n; - if (! GET_UINT(env, eNumPeerDests, &ui)) - goto invalid; - assocParams.sasoc_number_peer_destinations = (Uint16) ui; + levels = MKEL(env); - if (! GET_UINT(env, ePeerRWND, &ui)) - goto invalid; - assocParams.sasoc_peer_rwnd = (Uint32) ui; + for (n = 0; n < NUM(optLevels); n++) { + ERL_NIF_TERM options; + size_t m; + struct ESockOptLevel *levelP; - if (! GET_UINT(env, eLocalRWND, &ui)) - goto invalid; - assocParams.sasoc_local_rwnd = (Uint32) ui; + options = MKEL(env); + levelP = optLevels + n; + for (m = 0; m < levelP->num; m++) { + struct ESockOpt *optP; - if (! GET_UINT(env, eCookieLife, &ui)) - goto invalid; - assocParams.sasoc_cookie_life = (Uint32) ui; + optP = levelP->opts + m; + if (optP->setopt == NULL && optP->getopt == NULL) { + options = MKC(env, *optP->nameP, options); + } else { + options = + MKC(env, + MKT2(env, *optP->nameP, MKI(env, optP->opt)), + options); + } + } + levels = + MKC(env, + MKT2(env, + esock_encode_level(env, levelP->level), options), + levels); + } - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_associnfo -> set associnfo option\r\n") ); + return levels; +} - return esock_setopt_level_opt(env, descP, level, opt, - &assocParams, sizeof(assocParams)); - invalid: - return esock_make_invalid(env, atom_value); -} -#endif -#endif // #ifndef __WIN32__ -/* esock_setopt_sctp_events - Level SCTP EVENTS option +/* ---------------------------------------------------------------------- + * nif_open + * + * Description: + * Create an endpoint for communication. + * This function "exist" in two variants. + * One with two args and onewith four. + * + * Arguments (2): + * FD - File Descriptor (of an already open socket). + * Extra - A map with extra options. + * The options are: + * [M] dup - boolean() - Shall the fd be dup'ed or not. + * [O] bound - boolean() - Is the fd already bound. + * [O] domain - domain() - We may not be able to retrieve + * this on all platforms, and in + * *those* cases this *must* be + * provided. + * [O] type - type() - We may not be able to retrieve + * this on all platforms, and in + * *those* cases this *must* be + * provided. + * [O] proto - protocol() - We may not be able to retrieve + * this on all platforms, and in + * *those* cases this *must* be + * provided. + * [O] use_registry - boolean() - Shall we use the socket + * registry for this socket. + * Arguments (4): + * Domain - The domain, for example 'inet' + * Type - Type of socket, for example 'stream' + * Protocol - The protocol, for example 'tcp' + * Extra - A map with "obscure" options. + * Currently the only allowed option are: + * netns - string() - Network namespace. *Only* + * allowed on linux! + * use_registry - boolean() - Shall we use the socket + * registry for this socket. + * */ -#ifndef __WIN32__ -#if defined(SCTP_EVENTS) static -ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_open(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - struct sctp_event_subscribe events; - BOOLEAN_T error; + ERL_NIF_TERM result; - SSDBG( descP, - ("SOCKET", "esock_setopt_sctp_events {%d} -> entry with" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + SGDBG( ("SOCKET", "nif_open -> " + "\r\n argc: %d" + "\r\n", argc) ); - // It must be a map - if (! IS_MAP(env, eVal)) - goto invalid; + if (argc == 2) { + int fd; + ERL_NIF_TERM eopts; - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_events {%d} -> decode attributes\r\n", - descP->sock) ); + if (! GET_INT(env, argv[0], &fd)) { + if (IS_INTEGER(env, argv[0])) + return esock_make_error_integer_range(env, argv[0]); + else + return enif_make_badarg(env); + } + if (! IS_MAP(env, argv[1])) { + return enif_make_badarg(env); + } + eopts = argv[1]; - error = FALSE; + SGDBG( ("SOCKET", "nif_open -> " + "\r\n FD: %d" + "\r\n eopts: %T" + "\r\n", fd, eopts) ); - events.sctp_data_io_event = - esock_setopt_sctp_event(env, eVal, atom_data_io, &error); - events.sctp_association_event = - esock_setopt_sctp_event(env, eVal, atom_association, &error); - events.sctp_address_event = - esock_setopt_sctp_event(env, eVal, atom_address, &error); - events.sctp_send_failure_event = - esock_setopt_sctp_event(env, eVal, atom_send_failure, &error); - events.sctp_peer_error_event = - esock_setopt_sctp_event(env, eVal, atom_peer_error, &error); - events.sctp_shutdown_event = - esock_setopt_sctp_event(env, eVal, atom_shutdown, &error); - events.sctp_partial_delivery_event = - esock_setopt_sctp_event(env, eVal, atom_partial_delivery, &error); - events.sctp_adaptation_layer_event = - esock_setopt_sctp_event(env, eVal, atom_adaptation_layer, &error); + MLOCK(data.cntMtx); + result = ESOCK_IO_OPEN_WITH_FD(env, fd, eopts); + MUNLOCK(data.cntMtx); -#if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_AUTHENTICATION_EVENT) - events.sctp_authentication_event = - esock_setopt_sctp_event(env, eVal, atom_authentication, &error); -#endif + } else { + ERL_NIF_TERM edomain, etype, eproto, eopts; + int domain, type, proto; -#if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SENDER_DRY_EVENT) - events.sctp_sender_dry_event = - esock_setopt_sctp_event(env, eVal, atom_sender_dry, &error); -#endif + ESOCK_ASSERT( argc == 4 ); + + /* Extract arguments and perform preliminary validation */ + + edomain = argv[0]; + etype = argv[1]; + eproto = argv[2]; + eopts = argv[3]; + + SGDBG( ("SOCKET", "nif_open -> " + "\r\n edomain: %T" + "\r\n etype: %T" + "\r\n eproto: %T" + "\r\n eopts: %T" + "\r\n", edomain, etype, eproto, eopts) ); + + if (! GET_INT(env, eproto, &proto)) { + if (IS_INTEGER(env, eproto)) + return esock_make_error_integer_range(env, eproto); + else + return enif_make_badarg(env); + } + if (! IS_MAP(env, argv[3])) { + return enif_make_badarg(env); + } - if (error) { - goto invalid; - } else { - ERL_NIF_TERM result; + if (esock_decode_domain(env, edomain, &domain) == 0) { + SGDBG( ("SOCKET", + "nif_open -> invalid domain: %d\r\n", edomain) ); + return esock_make_invalid(env, esock_atom_domain); + } - result = esock_setopt_level_opt(env, descP, level, opt, - &events, sizeof(events)); - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_events {%d} -> set events -> %T\r\n", - descP->sock, result) ); + if (! esock_decode_type(env, etype, &type)) { + SGDBG( ("SOCKET", + "nif_open -> invalid type: %d\r\n", etype) ); + return esock_make_invalid(env, esock_atom_type); + } - return result; + MLOCK(data.cntMtx); + result = ESOCK_IO_OPEN_PLAIN(env, domain, type, proto, eopts); + MUNLOCK(data.cntMtx); } - invalid: - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_events {%d} -> invalid\r\n", - descP->sock) ); + SGDBG( ("SOCKET", "nif_open -> done with result: " + "\r\n %T" + "\r\n", result) ); + + return result; - return esock_make_invalid(env, atom_value); } -/* Return the value to make use of automatic type casting. - * Set *error if something goes wrong. - */ -static int esock_setopt_sctp_event(ErlNifEnv *env, - ERL_NIF_TERM eMap, - ERL_NIF_TERM eKey, - BOOLEAN_T *error) -{ - ERL_NIF_TERM eVal; - BOOLEAN_T val; - if (GET_MAP_VAL(env, eMap, eKey, &eVal)) - if (esock_decode_bool(eVal, &val)) - return (int) val; +extern +BOOLEAN_T esock_open_is_debug(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def) +{ + return esock_get_bool_from_map(env, eopts, esock_atom_debug, def); +} - *error = TRUE; - return 0; +extern +BOOLEAN_T esock_open_use_registry(ErlNifEnv* env, + ERL_NIF_TERM eopts, + BOOLEAN_T def) +{ + return esock_get_bool_from_map(env, eopts, esock_atom_use_registry, def); } + +extern +BOOLEAN_T esock_open_which_protocol(SOCKET sock, int* proto) +{ +#if defined(SO_PROTOCOL) + if (esock_getopt_int(sock, SOL_SOCKET, SO_PROTOCOL, proto)) + return TRUE; #endif -#endif // #ifndef __WIN32__ + return FALSE; +} -/* esock_setopt_sctp_initmsg - Level SCTP INITMSG option + + +/* ---------------------------------------------------------------------- + * nif_bind + * + * Description: + * Bind a name to a socket. + * + * Arguments: + * [0] Socket (ref) - Points to the socket descriptor. + * [1] LocalAddr - Local address is a sockaddr map ( socket:sockaddr() ). */ -#ifndef __WIN32__ -#if defined(SCTP_INITMSG) static -ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_bind(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eNumOut, eMaxIn, eMaxAttempts, eMaxInitTO; - struct sctp_initmsg initMsg; - unsigned int tmp; - - SSDBG( descP, - ("SOCKET", "esock_setopt_sctp_initmsg -> entry with" - "\r\n eVal: %T" - "\r\n", eVal) ); + ESockDescriptor* descP; + ERL_NIF_TERM eSockAddr, ret; + ESockAddress sockAddr; + SOCKLEN_T addrLen; - // It must be a map - if (! IS_MAP(env, eVal)) - goto invalid; + ESOCK_ASSERT( argc == 2 ); - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_initmsg -> extract attributes\r\n") ); + SGDBG( ("SOCKET", "nif_bind -> entry with argc: %d\r\n", argc) ); - if ((! GET_MAP_VAL(env, eVal, atom_num_outstreams, &eNumOut)) || - (! GET_MAP_VAL(env, eVal, atom_max_instreams, &eMaxIn)) || - (! GET_MAP_VAL(env, eVal, atom_max_attempts, &eMaxAttempts)) || - (! GET_MAP_VAL(env, eVal, atom_max_init_timeo, &eMaxInitTO))) - goto invalid; + /* Extract arguments and perform preliminary validation */ - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_initmsg -> decode attributes\r\n") ); + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); + } + eSockAddr = argv[1]; - if (! GET_UINT(env, eNumOut, &tmp)) - goto invalid; - initMsg.sinit_num_ostreams = (Uint16) tmp; + if (! esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) + return esock_make_invalid(env, esock_atom_sockaddr); - if (! GET_UINT(env, eMaxIn, &tmp)) - goto invalid; - initMsg.sinit_max_instreams = (Uint16) tmp; + MLOCK(descP->readMtx); - if (! GET_UINT(env, eMaxAttempts, &tmp)) - goto invalid; - initMsg.sinit_max_attempts = (Uint16) tmp; + SSDBG( descP, + ("SOCKET", "nif_bind(%T) {%d,0x%X} ->" + "\r\n SockAddr: %T" + "\r\n", + argv[0], descP->sock, descP->readState, + eSockAddr) ); - if (! GET_UINT(env, eMaxInitTO, &tmp)) - goto invalid; - initMsg.sinit_max_init_timeo = (Uint16) tmp; + ret = ESOCK_IO_BIND(env, descP, &sockAddr, addrLen); - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_initmsg -> set initmsg option\r\n") ); + SSDBG( descP, ("SOCKET", "nif_bind(%T) -> done with" + "\r\n ret: %T" + "\r\n", argv[0], ret) ); - return esock_setopt_level_opt(env, descP, level, opt, - &initMsg, sizeof(initMsg)); + MUNLOCK(descP->readMtx); - invalid: - return esock_make_invalid(env, atom_value); + return ret; } -#endif -#endif // #ifndef __WIN32__ -/* esock_setopt_sctp_rtoinfo - Level SCTP RTOINFO option +/* ---------------------------------------------------------------------- + * nif_connect + * + * Description: + * Initiate a connection on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Optional arguments: + * ConnectRef - Ref for the connection + * SockAddr - Socket Address of "remote" host. + * This is sockaddr(), which is either + * sockaddr_in4 or sockaddr_in6. */ -#ifndef __WIN32__ -#if defined(SCTP_RTOINFO) static -ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_connect(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eAssocId, eInitial, eMax, eMin; - struct sctp_rtoinfo rtoInfo; - - SSDBG( descP, - ("SOCKET", "esock_setopt_sctp_rtoinfo -> entry with" - "\r\n eVal: %T" - "\r\n", eVal) ); - - // It must be a map - if (! IS_MAP(env, eVal)) - goto invalid; - - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_rtoinfo -> extract attributes\r\n") ); - - if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) || - (! GET_MAP_VAL(env, eVal, atom_initial, &eInitial)) || - (! GET_MAP_VAL(env, eVal, atom_max, &eMax)) || - (! GET_MAP_VAL(env, eVal, atom_min, &eMin))) - goto invalid; - - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_rtoinfo -> decode attributes\r\n") ); - - if (! decode_sctp_assoc_t(env, eAssocId, &rtoInfo.srto_assoc_id)) - goto invalid; - - if ((! GET_UINT(env, eInitial, &rtoInfo.srto_initial)) || - (! GET_UINT(env, eMax, &rtoInfo.srto_max)) || - (! GET_UINT(env, eMin, &rtoInfo.srto_min))) - goto invalid; - - SSDBG( descP, - ("SOCKET", - "esock_setopt_sctp_rtoinfo -> set associnfo option\r\n") ); - - return esock_setopt_level_opt(env, descP, level, opt, - &rtoInfo, sizeof(rtoInfo)); + ESockDescriptor* descP; + ERL_NIF_TERM res, sockRef, connRef; + ESockAddress addr, *addrP; + SOCKLEN_T addrLen; - invalid: - return esock_make_invalid(env, atom_value); -} -#endif -#endif // #ifndef __WIN32__ + ESOCK_ASSERT( argc >= 1 ); + SGDBG( ("SOCKET", "nif_connect -> entry with argc: %d\r\n", argc) ); + /* Extract arguments and perform preliminary validation */ -#endif // defined(HAVE_SCTP) + sockRef = argv[0]; + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) + return enif_make_badarg(env); + if (argc == 3) { + ERL_NIF_TERM eSockAddr = argv[2]; + connRef = argv[1]; + if (! enif_is_ref(env, connRef)) + return enif_make_badarg(env); + if (! esock_decode_sockaddr(env, eSockAddr, &addr, &addrLen)) + return esock_make_invalid(env, esock_atom_sockaddr); + addrP = &addr; -/* esock_setopt_bool_opt - set an option that has an (integer) bool value - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - BOOLEAN_T val; - int ival; + MLOCK(descP->writeMtx); - if (! esock_decode_bool(eVal, &val)) - return esock_make_invalid(env, atom_value); + SSDBG( descP, + ("SOCKET", "nif_connect(%T), {%d0x%X} ->" + "\r\n ConnRef: %T" + "\r\n SockAddr: %T" + "\r\n", + sockRef, descP->sock, descP->writeState, + connRef, eSockAddr) ); + } else { - ival = (val) ? 1 : 0; - return esock_setopt_level_opt(env, descP, level, opt, - &ival, sizeof(ival)); -} -#endif // #ifndef __WIN32__ + ESOCK_ASSERT( argc == 1 ); + connRef = esock_atom_undefined; + addrP = NULL; + addrLen = 0; -/* esock_setopt_int_opt - set an option that has an integer value - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM result; - int val; + MLOCK(descP->writeMtx); - if (GET_INT(env, eVal, &val)) { - result = - esock_setopt_level_opt(env, descP, level, opt, - &val, sizeof(val)); - } else { - result = esock_make_invalid(env, atom_value); + SSDBG( descP, + ("SOCKET", "nif_connect(%T), {%d,0x%X} ->" + "\r\n", + sockRef, descP->sock, descP->writeState + ) ); } - return result; -} -#endif // #ifndef __WIN32__ - - -/* esock_setopt_str_opt - set an option that has an string value - */ -#ifndef __WIN32__ -#if defined(USE_SETOPT_STR_OPT) -static -ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - int max, - ERL_NIF_TERM eVal) -{ - ERL_NIF_TERM result; - int optLen; - char* val = MALLOC(max); - ESOCK_ASSERT( val != NULL ); + res = ESOCK_IO_CONNECT(env, descP, sockRef, connRef, addrP, addrLen); - if ((optLen = GET_STR(env, eVal, val, max)) > 0) { - optLen--; + SSDBG( descP, ("SOCKET", "nif_connect(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); - result = - esock_setopt_level_opt(env, descP, level, opt, - val, optLen); - } else { - result = esock_make_invalid(env, atom_value); - } + MUNLOCK(descP->writeMtx); - FREE(val); + return res; - return result; } -#endif -#endif // #ifndef __WIN32__ -/* esock_setopt_timeval_opt - set an option that has an (timeval) bool value + +/* ---------------------------------------------------------------------- + * nif_listen + * + * Description: + * Listen for connections on a socket. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Backlog - The maximum length to which the queue of pending + * connections for socket may grow. */ -#ifndef __WIN32__ -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ - && defined(ESOCK_USE_RCVSNDTIMEO) static -ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM eVal) +ERL_NIF_TERM nif_listen(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM result; - struct timeval timeVal; + ESockDescriptor* descP; + int backlog; + ERL_NIF_TERM ret; - SSDBG( descP, - ("SOCKET", "esock_setopt_timeval_opt -> entry with" - "\r\n eVal: %T" - "\r\n", eVal) ); + ESOCK_ASSERT( argc == 2 ); - if (! esock_decode_timeval(env, eVal, &timeVal)) - return esock_make_invalid(env, atom_value); + SGDBG( ("SOCKET", "nif_listen -> entry with argc: %d\r\n", argc) ); - SSDBG( descP, - ("SOCKET", "esock_setopt_timeval_opt -> set timeval option\r\n") ); + /* Extract arguments and perform preliminary validation */ - result = - esock_setopt_level_opt(env, descP, level, opt, - &timeVal, sizeof(timeVal)); + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); + } + if (! GET_INT(env, argv[1], &backlog)) { + if (IS_INTEGER(env, argv[1])) + return esock_make_error_integer_range(env, argv[1]); + else + return enif_make_badarg(env); + } + + MLOCK(descP->readMtx); SSDBG( descP, - ("SOCKET", "esock_setopt_timeval_opt -> done with" - "\r\n result: %T" - "\r\n", result) ); + ("SOCKET", "nif_listen(%T), {%d,0x%X} ->" + "\r\n backlog: %d" + "\r\n", + argv[0], descP->sock, descP->readState, + backlog) ); - return result; + ret = ESOCK_IO_LISTEN(env, descP, backlog); -} -#endif -#endif // #ifndef __WIN32__ + SSDBG( descP, ("SOCKET", "nif_listen(%T) -> done with" + "\r\n ret: %T" + "\r\n", argv[0], ret) ); + MUNLOCK(descP->readMtx); -#ifndef __WIN32__ -static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - void* optVal, - socklen_t optLen) -{ - if (socket_setopt(descP->sock, level, opt, optVal, optLen)) - return esock_make_error_errno(env, sock_errno()); - else - return esock_atom_ok; + return ret; } -#endif // #ifndef __WIN32__ -/* +++ socket_setopt +++ - * - * - * The original code here had problems that possibly - * only occur if you abuse it for non-INET sockets, but anyway: - * a) If the getsockopt for SO_PRIORITY or IP_TOS failed, the actual - * requested setsockopt was never even attempted. - * b) If {get,set}sockopt for one of IP_TOS and SO_PRIORITY failed, - * but ditto for the other worked and that was actually the requested - * option, failure was still reported to erlang. - * - * - * - * The relations between SO_PRIORITY, TOS and other options - * is not what you (or at least I) would expect...: - * If TOS is set after priority, priority is zeroed. - * If any other option is set after tos, tos might be zeroed. - * Therefore, save tos and priority. If something else is set, - * restore both after setting, if tos is set, restore only - * prio and if prio is set restore none... All to keep the - * user feeling socket options are independent. - * + +/* ======================================================================== */ -#ifndef __WIN32__ static -int socket_setopt(int sock, int level, int opt, - const void* optVal, const socklen_t optLen) +ERL_NIF_TERM esock_listen(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog) { - int res; - -#if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY) - int tmpIValPRIO = 0; - int tmpIValTOS = 0; - int resPRIO; - int resTOS; - SOCKOPTLEN_T tmpArgSzPRIO = sizeof(tmpIValPRIO); - SOCKOPTLEN_T tmpArgSzTOS = sizeof(tmpIValTOS); - - resPRIO = sock_getopt(sock, SOL_SOCKET, SO_PRIORITY, - &tmpIValPRIO, &tmpArgSzPRIO); - resTOS = sock_getopt(sock, SOL_IP, IP_TOS, - &tmpIValTOS, &tmpArgSzTOS); - - res = sock_setopt(sock, level, opt, optVal, optLen); - if (res == 0) { - - /* Ok, now we *maybe* need to "maybe" restore PRIO and TOS... - * maybe, possibly, ... - */ + + /* + * Verify that we are in the proper state + */ - if (opt != SO_PRIORITY) { - if ((opt != IP_TOS) && (resTOS == 0)) { - resTOS = sock_setopt(sock, SOL_IP, IP_TOS, - (void *) &tmpIValTOS, - tmpArgSzTOS); - res = resTOS; - } - if ((res == 0) && (resPRIO == 0)) { - resPRIO = sock_setopt(sock, SOL_SOCKET, SO_PRIORITY, - &tmpIValPRIO, - tmpArgSzPRIO); + SSDBG( descP, + ("SOCKET", "esock_listen(%d) -> verify open\r\n", descP->sock) ); + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); - /* Some kernels set a SO_PRIORITY by default - * that you are not permitted to reset, - * silently ignore this error condition. - */ +#if defined(__WIN32__) + SSDBG( descP, + ("SOCKET", "esock_listen(%d) -> verify bound\r\n", descP->sock) ); + if (! IS_BOUND(descP->writeState)) + return esock_make_error(env, esock_atom_not_bound); +#endif - if ((resPRIO != 0) && (sock_errno() == EPERM)) { - res = 0; - } else { - res = resPRIO; - } - } - } - } + /* + * And attempt to make socket listening + */ + + SSDBG( descP, ("SOCKET", "esock_listen(%d) -> try listen with" + "\r\n backlog: %d" + "\r\n", descP->sock, backlog) ); -#else + if ((sock_listen(descP->sock, backlog)) < 0) + return esock_make_error_errno(env, sock_errno()); - res = sock_setopt(sock, level, opt, optVal, optLen); + descP->readState |= ESOCK_STATE_LISTENING; -#endif + return esock_atom_ok; - return res; } -#endif // #ifndef __WIN32__ /* ---------------------------------------------------------------------- - * nif_getopt + * nif_accept * * Description: - * Get socket option. - * Its possible to use a ValueSpec to select - * how the value should be decoded. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Level (int) - Protocol level, encoded or native - * Opt (int) - Option, encoded or native - * ValueSpec (term) - How to decode the value [optional] + * Accept a connection on a socket. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Request ref - Unique "id" of this request + * (used for the select, if none is in queue). */ - static -ERL_NIF_TERM nif_getopt(ErlNifEnv* env, +ERL_NIF_TERM nif_accept(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; - int level, opt; - - ESOCK_ASSERT( (argc == 3) || (argc == 4) ); - - SGDBG( ("SOCKET", "nif_getopt -> entry with argc: %d\r\n", argc) ); - - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - SGDBG( ("SOCKET", "nif_getopt -> failed initial args check\r\n") ); - return enif_make_badarg(env); - } + ERL_NIF_TERM sockRef, ref, res; - if (! GET_INT(env, argv[2], &opt)) { - SSDBG( descP, - ("SOCKET", "nif_getopt -> failed initial args check\r\n") ); - if (! IS_INTEGER(env, argv[2])) - return enif_make_badarg(env); - else - return esock_make_error_integer_range(env, argv[2]); - } + ESOCK_ASSERT( argc == 2 ); - if (esock_decode_level(env, argv[1], &level)) { - if (argc == 4) { - ERL_NIF_TERM valueSpec = argv[3]; - return esock_getopt_native(env, descP, level, opt, valueSpec); - } else { - return esock_getopt(env, descP, level, opt); - } - } + SGDBG( ("SOCKET", "nif_accept -> entry with argc: %d\r\n", argc) ); - if ((COMPARE(argv[1], atom_otp) == 0) && - (argc == 3)) { - return esock_getopt_otp(env, descP, opt) ; - } + /* Extract arguments and perform preliminary validation */ - SGDBG( ("SOCKET", "nif_getopt -> failed args check\r\n") ); - if (IS_INTEGER(env, argv[1])) - return esock_make_error_integer_range(env, argv[1]); - else + sockRef = argv[0]; + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { return enif_make_badarg(env); + } + ref = argv[1]; -#endif // #ifdef __WIN32__ #else -} - - + MLOCK(descP->readMtx); -/* esock_getopt_otp - Handle OTP (level) options - */ #ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, - ESockDescriptor* descP, - int eOpt) -{ - ERL_NIF_TERM result; - SSDBG( descP, - ("SOCKET", "esock_getopt_otp -> entry with" - "\r\n eOpt: %d" - "\r\n", eOpt) ); - - switch (eOpt) { - case ESOCK_OPT_OTP_DEBUG: - MLOCK(descP->readMtx); - result = esock_getopt_otp_debug(env, descP); - MUNLOCK(descP->readMtx); - break; - - case ESOCK_OPT_OTP_IOW: - MLOCK(descP->readMtx); - result = esock_getopt_otp_iow(env, descP); - MUNLOCK(descP->readMtx); - break; + ("SOCKET", "nif_accept%T), {%d,0x%X} ->" + "\r\n ReqRef: %T" + "\r\n Current Acceptor addr: %p" + "\r\n Current Acceptor pid: %T" + "\r\n Current Acceptor mon: %T" + "\r\n Current Acceptor env: 0x%lX" + "\r\n Current Acceptor ref: %T" + "\r\n", + sockRef, descP->sock, descP->readState, + ref, + descP->currentAcceptorP, + descP->currentAcceptor.pid, + ESOCK_MON2TERM(env, &descP->currentAcceptor.mon), + descP->currentAcceptor.env, + descP->currentAcceptor.ref) ); +#else + SSDBG( descP, + ("SOCKET", "nif_accept%T), {%d,0x%X} ->" + "\r\n ReqRef: %T" + "\r\n First Acceptor addr: %p" + "\r\n", + sockRef, descP->sock, descP->readState, + ref, + descP->acceptorsQ.first) ); +#endif - case ESOCK_OPT_OTP_CTRL_PROC: - MLOCK(descP->readMtx); - result = esock_getopt_otp_ctrl_proc(env, descP); - MUNLOCK(descP->readMtx); - break; + res = ESOCK_IO_ACCEPT(env, descP, sockRef, ref); - case ESOCK_OPT_OTP_RCVBUF: - MLOCK(descP->readMtx); - result = esock_getopt_otp_rcvbuf(env, descP); - MUNLOCK(descP->readMtx); - break; + SSDBG( descP, ("SOCKET", "nif_accept(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); - case ESOCK_OPT_OTP_RCVCTRLBUF: - MLOCK(descP->readMtx); - result = esock_getopt_otp_rcvctrlbuf(env, descP); - MUNLOCK(descP->readMtx); - break; + MUNLOCK(descP->readMtx); - case ESOCK_OPT_OTP_SNDCTRLBUF: - MLOCK(descP->writeMtx); - result = esock_getopt_otp_sndctrlbuf(env, descP); - MUNLOCK(descP->writeMtx); - break; + return res; - case ESOCK_OPT_OTP_FD: - MLOCK(descP->readMtx); - result = esock_getopt_otp_fd(env, descP); - MUNLOCK(descP->readMtx); - break; +} - case ESOCK_OPT_OTP_META: - MLOCK(descP->writeMtx); - result = esock_getopt_otp_meta(env, descP); - MUNLOCK(descP->writeMtx); - break; - case ESOCK_OPT_OTP_USE_REGISTRY: - MLOCK(descP->readMtx); - result = esock_getopt_otp_use_registry(env, descP); - MUNLOCK(descP->readMtx); - break; - /* *** INTERNAL *** */ - case ESOCK_OPT_OTP_DOMAIN: - MLOCK(descP->readMtx); - result = esock_getopt_otp_domain(env, descP); - MUNLOCK(descP->readMtx); - break; +/* ---------------------------------------------------------------------- + * nif_send + * + * Description: + * Send a message on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Bin - The data to send as a binary() + * Flags - Send flags as an integer() + * SendRef - A unique id reference() for this (send) request. + */ -#if 0 - case ESOCK_OPT_OTP_TYPE: - MLOCK(descP->readMtx); - result = esock_getopt_otp_type(env, descP); - MUNLOCK(descP->readMtx); - break; +static +ERL_NIF_TERM nif_send(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ + ESockDescriptor* descP; + ERL_NIF_TERM sockRef, sendRef; + ErlNifBinary sndData; + int flags; + ERL_NIF_TERM res; - case ESOCK_OPT_OTP_PROTOCOL: - MLOCK(descP->readMtx); - result = esock_getopt_otp_protocol(env, descP); - MUNLOCK(descP->readMtx); - break; + ESOCK_ASSERT( argc == 4 ); - case ESOCK_OPT_OTP_DTP: - MLOCK(descP->readMtx); - result = esock_getopt_otp_dtp(env, descP); - MUNLOCK(descP->readMtx); - break; -#endif + SGDBG( ("SOCKET", "nif_send -> entry with argc: %d\r\n", argc) ); - default: - MLOCK(descP->readMtx); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp {%d} -> invalid with" - "\r\n eOpt: %d" - "\r\n", descP->sock, eOpt) ); - MUNLOCK(descP->readMtx); + sockRef = argv[0]; // We need this in case we send in case we send abort + sendRef = argv[3]; - /* This is an internal error - prim_inet gave us junk */ - result = - esock_raise_invalid(env, - MKT2(env, - atom_otp_socket_option, - MKI(env, eOpt))); - break; + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + SGDBG( ("SOCKET", "nif_send -> get resource failed\r\n") ); + return enif_make_badarg(env); } - return result; -} -#endif // #ifndef __WIN32__ - -/* esock_getopt_otp_debug - Handle the OTP (level) debug option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal; + /* Extract arguments and perform preliminary validation */ - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + if ((! enif_is_ref(env, sendRef)) || + (! GET_BIN(env, argv[1], &sndData))) { + SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") ); + return enif_make_badarg(env); + } + if (! GET_INT(env, argv[2], &flags)) { + SSDBG( descP, ("SOCKET", "nif_send -> argv decode failed\r\n") ); + if (IS_INTEGER(env, argv[2])) + return esock_make_error_integer_range(env, argv[2]); + else + return enif_make_badarg(env); } + MLOCK(descP->writeMtx); - eVal = esock_encode_bool(descP->dbg); + SSDBG( descP, + ("SOCKET", "nif_send(%T), {%d,0x%X} ->" + "\r\n SendRef: %T" + "\r\n Data size: %u" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->writeState, + sendRef, sndData.size, flags) ); - return esock_make_ok2(env, eVal); -} -#endif // #ifndef __WIN32__ + /* We need to handle the case when another process tries + * to write at the same time. + * If the current write could not write its entire package + * this time (resulting in an select). The write of the + * other process must be made to wait until current + * is done! + */ -/* esock_getopt_otp_iow - Handle the OTP (level) iow option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal; + res = ESOCK_IO_SEND(env, descP, sockRef, sendRef, &sndData, flags); + + SSDBG( descP, ("SOCKET", "nif_send(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_iow {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + MUNLOCK(descP->writeMtx); - eVal = esock_encode_bool(descP->iow); + SGDBG( ("SOCKET", "nif_send -> done with result: " + "\r\n %T" + "\r\n", res) ); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_iow {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + return res; - return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* esock_getopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option +/* ---------------------------------------------------------------------- + * nif_sendto + * + * Description: + * Send a message on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Bin - The data to send as a binary() + * Dest - Destination (socket) address. + * Flags - Send flags as an integer(). + * SendRef - A unique id reference() for this (send) request. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM nif_sendto(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eVal; + ESockDescriptor* descP; + ERL_NIF_TERM sockRef, sendRef; + ErlNifBinary sndData; + int flags; + ERL_NIF_TERM eSockAddr; + ESockAddress remoteAddr; + SOCKLEN_T remoteAddrLen; + ERL_NIF_TERM res; - if (! IS_OPEN(descP->readState)) { + ESOCK_ASSERT( argc == 5 ); + + SGDBG( ("SOCKET", "nif_sendto -> entry with argc: %d\r\n", argc) ); + + sockRef = argv[0]; // We need this in case we send abort (to the caller) + sendRef = argv[4]; + + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + SGDBG( ("SOCKET", "nif_sendto -> get resource failed\r\n") ); + return enif_make_badarg(env); + } + + /* Extract arguments and perform preliminary validation */ + + if ((! enif_is_ref(env, sendRef)) || + (! GET_BIN(env, argv[1], &sndData))) { + SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") ); + return enif_make_badarg(env); + } + if (! GET_INT(env, argv[3], &flags)) { + SSDBG( descP, ("SOCKET", "nif_sendto -> argv decode failed\r\n") ); + if (IS_INTEGER(env, argv[3])) + return esock_make_error_integer_range(env, argv[3]); + else + return enif_make_badarg(env); + } + eSockAddr = argv[2]; + if (! esock_decode_sockaddr(env, eSockAddr, + &remoteAddr, + &remoteAddrLen)) { SSDBG( descP, ("SOCKET", - "esock_getopt_otp_ctrl_proc {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + "nif_sendto(%T), {%d} -> sockaddr decode failed \r\n", + sockRef, descP->sock) ); + + return esock_make_invalid(env, esock_atom_sockaddr); } - eVal = MKPID(env, &descP->ctrlPid); + MLOCK(descP->writeMtx); SSDBG( descP, - ("SOCKET", "esock_getopt_otp_ctrlProc {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + ("SOCKET", "nif_sendto(%T), {%d,0x%X} ->" + "\r\n sendRef: %T" + "\r\n Data size: %u" + "\r\n eSockAddr: %T" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->readState, + sendRef, sndData.size, eSockAddr, flags) ); + + res = ESOCK_IO_SENDTO(env, descP, sockRef, sendRef, &sndData, flags, + &remoteAddr, remoteAddrLen); + + SSDBG( descP, ("SOCKET", "nif_sendto(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); + + MUNLOCK(descP->writeMtx); + + return res; - return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* esock_getopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option +/* ---------------------------------------------------------------------- + * nif_sendmsg + * + * Description: + * Send a message on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Msg - Message - map() with data and (maybe) control and dest + * Flags - Send flags as an integer(). + * SendRef - A unique id reference() for this (send) request. + * IOV - List of binaries */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eVal; + ERL_NIF_TERM res, sockRef, sendRef, eMsg, eIOV; + ESockDescriptor* descP; + int flags; - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_rcvbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + ESOCK_ASSERT( argc == 5 ); + + SGDBG( ("SOCKET", "nif_sendmsg -> entry with argc: %d\r\n", argc) ); + + sockRef = argv[0]; // We need this in case we send abort (to the caller) + eMsg = argv[1]; + sendRef = argv[3]; + eIOV = argv[4]; + + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + SGDBG( ("SOCKET", "nif_sendmsg -> get resource failed\r\n") ); + return enif_make_badarg(env); } - if (descP->rNum == 0) { - eVal = MKUL(env, (unsigned long) descP->rBufSz); - } else { - eVal = MKT2(env, - MKI(env, descP->rNum), - MKUL(env, (unsigned long) descP->rBufSz)); + /* Extract arguments and perform preliminary validation */ + + if ((! enif_is_ref(env, sendRef)) || + (! IS_MAP(env, eMsg))) { + SSDBG( descP, ("SOCKET", "nif_sendmsg -> argv decode failed\r\n") ); + return enif_make_badarg(env); + } + if (! GET_INT(env, argv[2], &flags)) { + if (IS_INTEGER(env, argv[2])) + return esock_make_error_integer_range(env, argv[2]); + else + return enif_make_badarg(env); } + MLOCK(descP->writeMtx); + SSDBG( descP, - ("SOCKET", "esock_getopt_otp_rcvbuf {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + ("SOCKET", "nif_sendmsg(%T), {%d,0x%X} ->" + "\r\n SendRef: %T" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->writeState, + sendRef, flags) ); + + res = ESOCK_IO_SENDMSG(env, descP, sockRef, sendRef, eMsg, flags, eIOV); + + MUNLOCK(descP->writeMtx); + + SSDBG( descP, ("SOCKET", "nif_sendmsg(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); + + return res; - return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* esock_getopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option + +#ifdef FOOBAR + +/* ---------------------------------------------------------------------- + * nif_writev / nif_sendv + * + * Description: + * Send a message (vector) on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * SendRef - A unique id for this (send) request. + * Data - A vector of binaries + * Flags - Send flags. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM nwritev(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM data) { - ERL_NIF_TERM eVal; + ERL_NIF_TERM tail; + ErlNifIOVec vec; + ErlNifIOVec* iovec = &vec; + SysIOVec* sysiovec; + int save_errno; + int iovcnt, n; - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", - "esock_getopt_otp_rcvctrlbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + if (! enif_inspect_iovec(env, MAX_VSZ, data, &tail, &iovec)) + return enif_make_badarg(env); + + if (enif_ioq_size(descP->outQ) > 0) { + /* If the I/O queue contains data we enqueue the iovec + * and then peek the data to write out of the queue. + */ + if (!enif_ioq_enqv(q, iovec, 0)) + return -3; + + sysiovec = enif_ioq_peek(descP->outQ, &iovcnt); + + } else { + /* If the I/O queue is empty we skip the trip through it. */ + iovcnt = iovec->iovcnt; + sysiovec = iovec->iov; } - eVal = MKUL(env, (unsigned long) descP->rCtrlSz); + /* Attempt to write the data */ + n = writev(fd, sysiovec, iovcnt); + saved_errno = errno; + + if (enif_ioq_size(descP->outQ) == 0) { + /* If the I/O queue was initially empty we enqueue any + remaining data into the queue for writing later. */ + if (n >= 0 && !enif_ioq_enqv(descP->outQ, iovec, n)) + return -3; + } else { + /* Dequeue any data that was written from the queue. */ + if (n > 0 && !enif_ioq_deq(descP->outQ, n, NULL)) + return -4; + } + /* return n, which is either number of bytes written or -1 if + some error happened */ + errno = saved_errno; + return n; +} - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_rcvctrlbuf {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); +#endif // #ifdef FOOBAR - return esock_make_ok2(env, eVal); -} -#endif // #ifndef __WIN32__ -/* esock_getopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option +/* ---------------------------------------------------------------------- + * nif_sendfile/1,4,5 + * + * Description: + * Send a file on a socket + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * + * SendRef - A unique id reference() for this (send) request. + * + * Offset - File offset to start from. + * Count - The number of bytes to send. + * + * InFileRef - A file NIF resource. */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal; - - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", - "esock_getopt_otp_sndctrlbuf {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } - eVal = MKUL(env, (unsigned long) descP->wCtrlSz); +static ERL_NIF_TERM +nif_sendfile(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if !defined(HAVE_SENDFILE) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ESockDescriptor *descP; + ERL_NIF_TERM sockRef, res; - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_sndctrlbuf {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + SGDBG( ("SOCKET", "nif_sendfile -> entry with argc: %d\r\n", argc) ); - return esock_make_ok2(env, eVal); -} -#endif // #ifndef __WIN32__ + if (argc < 1) { + SGDBG( ("SOCKET", "nif_sendfile -> argc < 1\r\n") ); + return enif_make_badarg(env); + } + sockRef = argv[0]; + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) (&descP))) { + SGDBG( ("SOCKET", "nif_sendfile -> get resource failed\r\n") ); + return enif_make_badarg(env); + } + if (argc < 2) { // argc == 1 -/* esock_getopt_otp_fd - Handle the OTP (level) fd option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal; + MLOCK(descP->writeMtx); - if (! IS_OPEN(descP->readState)) { SSDBG( descP, - ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } - - eVal = MKI(env, descP->sock); + ("SOCKET", "nif_sendfile(%T), {%d,%d,0x%X} ->" + "\r\n", + sockRef, + descP->sock, descP->sendfileHandle, descP->writeState) ); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_fd {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + res = ESOCK_IO_SENDFILE_DC(env, descP); - return esock_make_ok2(env, eVal); -} -#endif // #ifndef __WIN32__ + } else { + ERL_NIF_TERM sendRef; + ErlNifSInt64 offset64; + ErlNifUInt64 count64u; + off_t offset; + size_t count; + BOOLEAN_T a2ok; + ESOCK_ASSERT( argc >= 4 ); -/* esock_getopt_otp_meta - Handle the OTP (level) meta option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal; + sendRef = argv[1]; + if ((! enif_is_ref(env, sendRef))) { + SSDBG( descP, + ("SOCKET", "nif_sendfile -> argv[1] decode failed\r\n") ); + return enif_make_badarg(env); + } - if (! IS_OPEN(descP->writeState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_meta {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + if ((! (a2ok = GET_INT64(env, argv[2], &offset64))) || + (! GET_UINT64(env, argv[3], &count64u))) { + if ((! IS_INTEGER(env, argv[3])) || + (! IS_INTEGER(env, argv[3]))) + return enif_make_badarg(env); + if (! a2ok) + return esock_make_error_integer_range(env, argv[2]); + else + return esock_make_error_integer_range(env, argv[3]); + } + offset = (off_t) offset64; + if (offset64 != (ErlNifSInt64) offset) + return esock_make_error_integer_range(env, argv[2]); + count = (size_t) count64u; + if (count64u != (ErlNifUInt64) count) + return esock_make_error_integer_range(env, argv[3]); - eVal = CP_TERM(env, descP->meta.ref); + if (argc == 4) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_meta {%d} ->" - "\r\n eVal: %T" - "\r\n", descP->sock, eVal) ); + MLOCK(descP->writeMtx); - return esock_make_ok2(env, eVal); -} -#endif // #ifndef __WIN32__ + SSDBG( descP, + ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->" + "\r\n sendRef: %T" + "\r\n offset: %ld" + "\r\n count: %ld" + "\r\n", + sockRef, descP->sock, descP->readState, + sendRef, (long) offset, (long) count) ); + res = ESOCK_IO_SENDFILE_CONT(env, descP, + sockRef, sendRef, + offset, count); + } else { + ERL_NIF_TERM fRef; -/* esock_getopt_otp_use_registry - Handle the OTP (level) use_registry option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_use_registry(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM eVal = esock_encode_bool(descP->useReg); + ESOCK_ASSERT( argc == 5 ); - return esock_make_ok2(env, eVal); -} -#endif + fRef = argv[4]; + if ((! enif_is_ref(env, fRef))) + return enif_make_badarg(env); + MLOCK(descP->writeMtx); -/* - * esock_getopt_otp_domain - Handle the OTP (level) domain option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM domain, result; + SSDBG( descP, + ("SOCKET", "nif_sendfile(%T), {%d,0x%X} ->" + "\r\n sendRef: %T" + "\r\n offset: %ld" + "\r\n count: %ld" + "\r\n fRef: %T" + "\r\n", + sockRef, descP->sock, descP->readState, + sendRef, (long) offset, (long) count, fRef) ); - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_domain {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + res = ESOCK_IO_SENDFILE_START(env, descP, + sockRef, sendRef, + offset, count, fRef); + } } - esock_encode_domain(env, descP->domain, &domain); - result = esock_make_ok2(env, domain); + SSDBG( descP, ("SOCKET", "nif_sendfile(%T) -> done with" + "\r\n res: %T" + "\r\n", sockRef, res) ); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_domain {%d} ->" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + MUNLOCK(descP->writeMtx); - return result; -} -#endif // #ifndef __WIN32__ + return res; +#endif // !defined(HAVE_SENDFILE) +} -#if 0 -/* - * esock_getopt_otp_type - Handle the OTP (level) type options. +/* ---------------------------------------------------------------------- + * nif_recv + * + * Description: + * Receive a message on a socket. + * Normally used only on a connected socket! + * If we are trying to read > 0 bytes, then that is what we do. + * But if we have specified 0 bytes, then we want to read + * whatever is in the buffers (everything it got). + * + * Arguments: + * Socket (ref) - NIF resource reference() to the socket descriptor. + * Length - The number of bytes to receive; integer(). + * Flags - Receive flags; integer(). + * RecvRef - A unique reference() id for this (send) request | 'poll' */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM nif_recv(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM type, result; + ESockDescriptor* descP; + ERL_NIF_TERM sockRef, recvRef; + ErlNifUInt64 elen; + ssize_t len; /* ssize_t due to the return type of recv() */ + int flags; + ERL_NIF_TERM res; + BOOLEAN_T a1ok; + + ESOCK_ASSERT( argc == 4 ); + + sockRef = argv[0]; // We need this in case we send abort (to the caller) + recvRef = argv[3]; + + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + return enif_make_badarg(env); + } + + if ((! enif_is_ref(env, recvRef)) && + (COMPARE(recvRef, esock_atom_zero) != 0)) { + return enif_make_badarg(env); + } + if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) || + (! GET_INT(env, argv[2], &flags))) { + if ((! IS_INTEGER(env, argv[1])) || + (! IS_INTEGER(env, argv[2]))) + return enif_make_badarg(env); - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_type {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); + if (! a1ok) + return esock_make_error_integer_range(env, argv[1]); + return + esock_make_error_integer_range(env, argv[2]); } + len = (ssize_t) elen; + if (elen != (ErlNifUInt64) len) + return esock_make_error_integer_range(env, elen); - esock_encode_type(env, descP->type, &type); - result = esock_make_ok2(env, type); + MLOCK(descP->readMtx); SSDBG( descP, - ("SOCKET", "esock_getopt_otp_type {%d} ->" - "\r\n result: %T" - "\r\n", descP->sock, result) ); - - return result; -} -#endif // #ifndef __WIN32__ + ("SOCKET", "nif_recv(%T), {%d,0x%X} ->" + "\r\n recvRef: %T" + "\r\n len: %ld" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->readState, + recvRef, (long) len, flags) ); + /* We need to handle the case when another process tries + * to receive at the same time. + * If the current recv could not read its entire package + * this time (resulting in an select). The read of the + * other process must be made to wait until current + * is done! + */ -/* - * esock_getopt_otp_protocol - Handle the OTP (level) protocol options. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env, - ESockDescriptor* descP) -{ - ERL_NIF_TERM protocol, result; + res = ESOCK_IO_RECV(env, descP, sockRef, recvRef, len, flags); - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_protocol {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + SSDBG( descP, ("SOCKET", "nif_recv(%T) -> done" + "\r\n", sockRef) ); - protocol = MKI(env, descP->protocol); - result = esock_make_ok2(env, protocol); + MUNLOCK(descP->readMtx); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_protocol {%d} ->" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + return res; - return result; } -#endif // #ifndef __WIN32__ -/* - * esock_getopt_otp_dtp - Handle the OTP (level) type options. +/* ---------------------------------------------------------------------- + * nif_recvfrom + * + * Description: + * Receive a message on a socket. + * Normally used only on a (un-) connected socket! + * If a buffer size = 0 is specified, then the we will use the default + * buffer size for this socket (whatever has been configured). + * + * Arguments: + * Socket (ref) - NIF resource reference() to the socket descriptor. + * BufSz - integer() ize of the buffer + * into which we put the received message. + * Flags - Receive flags; integer(). + * RecvRef - A unique reference() id for this recv request. + * + * + * + * How do we handle if the peek flag is set? We need to basically keep + * track of if we expect any data from the read. Regardless of the + * number of bytes we try to read. + * + * */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM domain, type, protocol, dtp, result; + ESockDescriptor* descP; + ERL_NIF_TERM sockRef, recvRef; + ErlNifUInt64 elen; + ssize_t len; /* ssize_t due to the return type of recvfrom() */ + int flags; + ERL_NIF_TERM res; + BOOLEAN_T a1ok; - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_dtp {%d} -> done closed\r\n", - descP->sock) ); - return esock_make_error(env, atom_closed); - } + ESOCK_ASSERT( argc == 4 ); - esock_encode_domain(env, descP->domain, &domain); - esock_encode_type(env, descP->type, &type); - protocol = MKI(env, descP->protocol); - dtp = MKT3(env, domain, type, protocol); - result = esock_make_ok2(env, dtp); + SGDBG( ("SOCKET", "nif_recvfrom -> entry with argc: %d\r\n", argc) ); - SSDBG( descP, - ("SOCKET", "esock_getopt_otp_dtp {%d} ->" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + sockRef = argv[0]; // We need this in case we send abort (to the caller) + recvRef = argv[3]; - return result; -} -#endif // #ifndef __WIN32__ + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + return enif_make_badarg(env); + } + /* Extract arguments and perform preliminary validation */ -#endif // #if 0 + if ((! enif_is_ref(env, recvRef)) && + (COMPARE(recvRef, esock_atom_zero) != 0)) { + return enif_make_badarg(env); + } + if ((! (a1ok = GET_UINT64(env, argv[1], &elen))) || + (! GET_INT(env, argv[2], &flags))) { + if ((! IS_INTEGER(env, argv[1])) || + (! IS_INTEGER(env, argv[2]))) + return enif_make_badarg(env); -/* How to decode the value is specified with valueSpec - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ERL_NIF_TERM valueSpec) -{ - ERL_NIF_TERM result; - SOCKOPTLEN_T valueSz; - int sz; - ErlNifBinary bin; + if (! a1ok) + return esock_make_error_integer_range(env, argv[1]); + return esock_make_error_integer_range(env, argv[2]); + } + len = (ssize_t) elen; + if (elen != (ErlNifUInt64) len) + return esock_make_error_integer_range(env, elen); MLOCK(descP->readMtx); SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> entry" - "\r\n level: %d" - "\r\n opt: %d" - "\r\n valueSpec: %T" - "\r\n", descP->sock, - level, opt, valueSpec) ); - - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> done closed\r\n", - descP->sock) ); - MUNLOCK(descP->readMtx); - return esock_make_error(env, atom_closed); - } + ("SOCKET", "nif_recvfrom(%T), {%d,0x%X} ->" + "\r\n recvRef: %T" + "\r\n len: %ld" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->readState, + recvRef, (long) len, flags) ); /* - * We could make it possible to specify more types, - * such as string, NUL terminated or not, etc... + * We need to handle the case when another process tries + * to receive at the same time. + * If the current recv could not read its entire package + * this time (resulting in an select). The read of the + * other process must be made to wait until current + * is done! + * Basically, we need a read queue! + * + * A 'reading' field (boolean), which is set if we did + * not manage to read the entire message and reset every + * time we do. * */ - if (GET_INT(env, valueSpec, &sz)) { - valueSz = (SOCKOPTLEN_T) sz; - if ((int) valueSz == sz) { - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> binary size" - "\r\n valueSz: %d" - "\r\n", descP->sock, sz) ); - result = - esock_getopt_size_opt(env, descP, level, opt, valueSz); - } else { - result = esock_make_invalid(env, atom_value); - } - } else if (COMPARE(valueSpec, atom_integer) == 0) { - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> integer" - "\r\n", descP->sock) ); - result = esock_getopt_int_opt(env, descP, level, opt); - } else if (COMPARE(valueSpec, atom_boolean) == 0) { - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> boolean" - "\r\n", descP->sock) ); - result = esock_getopt_bool_opt(env, descP, level, opt); - } else if (enif_inspect_binary(env, valueSpec, &bin)) { - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> binary" - "\r\n size: %lu" - "\r\n", descP->sock, (unsigned long) bin.size) ); - result = esock_getopt_bin_opt(env, descP, level, opt, &bin); - } else { - result = esock_make_invalid(env, atom_value); - } + res = ESOCK_IO_RECVFROM(env, descP, sockRef, recvRef, len, flags); - SSDBG( descP, - ("SOCKET", "esock_getopt_native {%d} -> done when" - "\r\n result: %T" - "\r\n", descP->sock, result) ); + SSDBG( descP, ("SOCKET", "nif_recvfrom(%T) -> done" + "\r\n", sockRef) ); MUNLOCK(descP->readMtx); - return result; + + return res; } -#endif // #ifndef __WIN32__ -/* esock_getopt - An option that we know how to decode + +/* ---------------------------------------------------------------------- + * nif_recvmsg + * + * Description: + * Receive a message on a socket. + * Normally used only on a (un-) connected socket! + * If a buffer size = 0 is specified, then we will use the default + * buffer size for this socket (whatever has been configured). + * If ctrl (buffer) size = 0 is specified, then the default ctrl + * (buffer) size is used (1024). + * + * Arguments: + * Socket (ref) - NIF resource reference() to the socket descriptor. + * BufSz - Size of the buffer into which we put the received message; + * integer(). + * CtrlSz - Size of the ctrl (buffer) into which we put the received + * ancillary data; integer(). + * Flags - Receive flags; integer(). + * RecvRef - A unique reference() id for this (send) request. + * + * + * + * How do we handle if the peek flag is set? We need to basically keep + * track of if we expect any data from the read. Regardless of the + * number of bytes we try to read. + * + * */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM result; - const struct ESockOpt *optP; + ESockDescriptor* descP; + ERL_NIF_TERM sockRef, recvRef; + ErlNifUInt64 eBufSz, eCtrlSz; + ssize_t bufSz, ctrlSz; + int flags; + ERL_NIF_TERM res; + BOOLEAN_T a1ok, a2ok; - MLOCK(descP->readMtx); + ESOCK_ASSERT( argc == 5 ); - SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> entry with" - "\r\n level: %d" - "\r\n opt: %d" - "\r\n", descP->sock, level, opt) ); + SGDBG( ("SOCKET", "nif_recvmsg -> entry with argc: %d\r\n", argc) ); - if (! IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> done closed\r\n", - descP->sock) ); - MUNLOCK(descP->readMtx); - return esock_make_error(env, atom_closed); + sockRef = argv[0]; // We need this in case we send abort (to the caller) + recvRef = argv[4]; + + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + return enif_make_badarg(env); } - optP = lookupOpt(level, opt); + /* Extract arguments and perform preliminary validation */ - if (optP == NULL) { + if ((! enif_is_ref(env, recvRef)) && + (COMPARE(recvRef, esock_atom_zero) != 0)) { + return enif_make_badarg(env); + } - result = esock_make_invalid(env, atom_socket_option); + if ((! (a1ok = GET_UINT64(env, argv[1], &eBufSz))) || + (! (a2ok = GET_UINT64(env, argv[2], &eCtrlSz))) || + (! GET_INT(env, argv[3], &flags))) { + if ((! IS_INTEGER(env, argv[1])) || + (! IS_INTEGER(env, argv[2])) || + (! IS_INTEGER(env, argv[3]))) + return enif_make_badarg(env); - SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> unknown option\r\n", - descP->sock) ); + if (! a1ok) + return esock_make_error_integer_range(env, argv[1]); + if (! a2ok) + return esock_make_error_integer_range(env, argv[2]); + return + esock_make_error_integer_range(env, argv[3]); + } - } else if (optP->getopt == NULL) { + bufSz = (ssize_t) eBufSz; + if (eBufSz != (ErlNifUInt64) bufSz) + return esock_make_error_integer_range(env, eBufSz); - result = esock_make_invalid(env, atom_socket_option); + ctrlSz = (ssize_t) eCtrlSz; + if (eCtrlSz != (ErlNifUInt64) ctrlSz) + return esock_make_error_integer_range(env, eCtrlSz); - SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> opt not gettable\r\n", - descP->sock) ); + MLOCK(descP->readMtx); - } else { + SSDBG( descP, + ("SOCKET", "nif_recvmsg(%T), {%d,0x%X} ->" + "\r\n recvRef: %T" + "\r\n bufSz: %ld" + "\r\n ctrlSz: %ld" + "\r\n flags: 0x%X" + "\r\n", + sockRef, descP->sock, descP->readState, + recvRef, (long) bufSz, (long) ctrlSz, flags) ); - result = (optP->getopt)(env, descP, level, opt); + /* + * + * We need to handle the case when another process tries + * to receive at the same time. + * If the current recv could not read its entire package + * this time (resulting in an select). The read of the + * other process must be made to wait until current + * is done! + * Basically, we need a read queue! + * + * A 'reading' field (boolean), which is set if we did + * not manage to read the entire message and reset every + * time we do. + * + * + */ - SSDBG( descP, - ("SOCKET", "esock_getopt {%d} -> done when" - "\r\n result: %T" - "\r\n", descP->sock, result) ); - } + res = ESOCK_IO_RECVMSG(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); - MUNLOCK(descP->readMtx); - return result; -} -#endif // #ifndef __WIN32__ + SSDBG( descP, ("SOCKET", "nif_recvmsg(%T) -> done" + "\r\n", sockRef) ); + MUNLOCK(descP->readMtx); -#ifndef __WIN32__ -#if defined(SO_BINDTODEVICE) -static -ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) -{ - return esock_getopt_str_opt(env, descP, level, opt, IFNAMSIZ+1, FALSE); + return res; } -#endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#if defined(SO_DOMAIN) +/* ---------------------------------------------------------------------- + * nif_close + * + * Description: + * Close a (socket) file descriptor. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + */ + static -ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM nif_close(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - int val; - ERL_NIF_TERM result; - - if (! esock_getopt_int(descP->sock, level, opt, &val)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM domain; - esock_encode_domain(env, val, &domain); - result = esock_make_ok2(env, domain); - } + ESockDescriptor* descP; + ERL_NIF_TERM res; - return result; -} -#endif -#endif // #ifndef __WIN32__ + ESOCK_ASSERT( argc == 1 ); + SGDBG( ("SOCKET", "nif_close -> entry with argc: %d\r\n", argc) ); -#ifndef __WIN32__ -#if defined(SO_LINGER) -static -ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) -{ - ERL_NIF_TERM result; - struct linger val; - SOCKOPTLEN_T valSz = sizeof(val); - int res; + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); + } - sys_memzero((void *) &val, sizeof(val)); + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); - res = sock_getopt(descP->sock, level, opt, &val, &valSz); + SSDBG( descP, + ("SOCKET", "nif_close(%T) ->" + "\r\n Socket: %d" + "\r\n Read State: 0x%X" + "\r\n Write State: 0x%X" + "\r\n Caller: %T" + "\r\n", + argv[0], + descP->sock, + descP->readState, descP->writeState, + esock_self(env)) ); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM - lOnOff = ((val.l_onoff != 0) ? atom_true : atom_false), - lSecs = MKI(env, val.l_linger), - keys[] = {atom_onoff, esock_atom_linger}, - vals[] = {lOnOff, lSecs}, - linger; - size_t numKeys = NUM(keys); + res = ESOCK_IO_CLOSE(env, descP); - ESOCK_ASSERT( numKeys == NUM(vals) ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &linger) ); + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); - result = esock_make_ok2(env, linger); - } + SSDBG( descP, ("SOCKET", "nif_close(%T) -> done" + "\r\n res: %T" + "\r\n", argv[0], res) ); - return result; + return res; } -#endif -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ -#if defined(SO_TYPE) +/* ---------------------------------------------------------------------- + * nif_finalize_close + * + * Description: + * Perform the actual socket close! + * Note that this function is executed in a dirty scheduler. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + */ static -ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { + ESockDescriptor* descP; ERL_NIF_TERM result; - int val; - if (! esock_getopt_int(descP->sock, level, opt, &val)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM type; - esock_encode_type(env, val, &type); - result = esock_make_ok2(env, type); + /* Extract arguments and perform preliminary validation */ + + ESOCK_ASSERT( argc == 1 ); + + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); } + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + SSDBG( descP, + ("SOCKET", "nif_finalize_close(%T, %d) -> " + "\r\n ReadState: 0x%X" + "\r\n WriteState: 0x%X" + "\r\n", + argv[0], descP->sock, descP->readState, descP->writeState) ); + + result = ESOCK_IO_FIN_CLOSE(env, descP); + + SSDBG( descP, ("SOCKET", "nif_finalize_close(%T) -> done with" + "\r\n result: %T" + "\r\n", argv[0], result) ); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + return result; } -#endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#if defined(SO_PROTOCOL) -static -ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +extern +int esock_close_socket(ErlNifEnv* env, + ESockDescriptor* descP, + BOOLEAN_T unlock) { - ERL_NIF_TERM result; - int val; + int err = 0; + SOCKET sock = descP->sock; + ERL_NIF_TERM sockRef; - if (! esock_getopt_int(descP->sock, level, opt, &val)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM protocol; + /* This code follows Linux's advice to assume that after calling + * close(2), the file descriptor may be reused, so assuming + * that it can be used for anything such as retrying + * to close is bad behaviour, although odd platforms + * such as HP-UX requires a retry after EINTR + */ - protocol = -#ifdef AF_LOCAL - /* For AF_LOCAL, the protocols table value for 0 is wrong */ - (val == 0) && (descP->domain == AF_LOCAL) ? - esock_atom_default : - /* It is correct for AF_INET and hopefully for AF_INET6, - * but for future additions it is an open question - */ -#endif - MKI(env, val); + /* First update the state so no other thread will try + * to close the socket, then we will close it, + * possibly when being scheduled in during + * finalize_close + */ + descP->sock = INVALID_SOCKET; + descP->readState |= ESOCK_STATE_CLOSED; + descP->writeState |= ESOCK_STATE_CLOSED; + esock_dec_socket(descP->domain, descP->type, descP->protocol); - result = esock_make_ok2(env, protocol); + /* +++++++ Clear the meta option +++++++ */ + enif_clear_env(descP->meta.env); + descP->meta.ref = esock_atom_undefined; + + if (descP->closeOnClose) { + if (unlock) { + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + } + SSDBG( descP, + ("SOCKET", "esock_close_socket(%d) -> " + "try socket close\r\n", sock) ); + if (sock_close(sock) != 0) + err = sock_errno(); + if (unlock) { + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + } } - return result; + if (err != 0) { + SSDBG( descP, + ("SOCKET", "esock_close_socket(%d) -> %s (%d)\r\n", + sock, erl_errno_id(err), err) ); + } + + /* (maybe) Update the registry */ + if (descP->useReg) { + sockRef = enif_make_resource(env, descP); + esock_send_reg_del_msg(env, descP, sockRef); + } + + return err; } -#endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -/* esock_getopt_ip_mtu_discover - Level IP MTU_DISCOVER option + +/* ---------------------------------------------------------------------- + * nif_shutdown + * + * Description: + * Disable sends and/or receives on a socket. + * + * Arguments: + * [0] Socket (ref) - Points to the socket descriptor. + * [1] How - What will be shutdown. */ -#if defined(IP_MTU_DISCOVER) + static -ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM nif_shutdown(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM result; - int mtuDisc; - - if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eMtuDisc; - encode_ip_pmtudisc(env, mtuDisc, &eMtuDisc); - result = esock_make_ok2(env, eMtuDisc); - } + ESockDescriptor* descP; + ERL_NIF_TERM ehow, res; + int how; - return result; + ESOCK_ASSERT( argc == 2 ); -} -#endif -#endif // #ifndef __WIN32__ + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); + } + ehow = argv[1]; + if (! ehow2how(ehow, &how)) + return esock_raise_invalid(env, + MKT2(env, atom_how, ehow)); -/* esock_getopt_multicast_if - Level IP MULTICAST_IF option - */ -#ifndef __WIN32__ -#if defined(IP_MULTICAST_IF) -static -ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) -{ - ERL_NIF_TERM result; - ERL_NIF_TERM eAddr; - struct in_addr ifAddr; - SOCKOPTLEN_T ifAddrSz = sizeof(ifAddr); - int res; + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); - sys_memzero((void *) &ifAddr, ifAddrSz); + SSDBG( descP, + ("SOCKET", "nif_shutdown(%T), {%d,0x%X} ->" + "\r\n how: %d" + "\r\n", + argv[0], descP->sock, descP->readState | descP->writeState, + how) ); - res = sock_getopt(descP->sock, level, opt, &ifAddr, &ifAddrSz); + res = ESOCK_IO_SHUTDOWN(env, descP, how); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - esock_encode_in_addr(env, &ifAddr, &eAddr); - result = esock_make_ok2(env, eAddr); - } + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); - return result; + SSDBG( descP, ("SOCKET", "nif_shutdown(%T) -> done with" + "\r\n res: %T" + "\r\n", argv[0], res) ); + return res; } -#endif -#endif // #ifndef __WIN32__ -/* esock_getopt_tos - Level IP TOS option + +/* ======================================================================== */ -#ifndef __WIN32__ -#if defined(IP_TOS) static -ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_shutdown(ErlNifEnv* env, + ESockDescriptor* descP, + int how) { - ERL_NIF_TERM result; - int val = 0; - - if (! esock_getopt_int(descP->sock, level, opt, &val)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - result = esock_make_ok2(env, encode_ip_tos(env, val)); - } + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); - return result; + if (sock_shutdown(descP->sock, how) == 0) + return esock_atom_ok; + else + return esock_make_error_errno(env, sock_errno()); } -#endif -#endif // #ifndef __WIN32__ - -#if defined(HAVE_IPV6) -/* esock_getopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option +/* ---------------------------------------------------------------------- + * nif_setopt + * + * Description: + * Set socket option. + * It is possible to use a native mode value where we do not use + * any assumption about how to encode the value but instead + * use the value's type to select encoding. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Level - Level of the socket option. + * Opt - The socket option. + * Value - Value of the socket option. + * NativeValue - If 0 Value type has to match our encoding function, + * if not 0 type selects encoding. */ -#ifndef __WIN32__ -#if defined(IPV6_MTU_DISCOVER) + static -ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM nif_setopt(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM result; - int mtuDisc; + ESockDescriptor* descP = NULL; + ERL_NIF_TERM esock, elevel, eopt, eval, enval; + int level, opt, nativeValue; - if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eMtuDisc; - encode_ipv6_pmtudisc(env, mtuDisc, &eMtuDisc); - result = esock_make_ok2(env, eMtuDisc); + ESOCK_ASSERT( argc == 5 ); + + esock = argv[0]; + elevel = argv[1]; + eopt = argv[2]; + eval = argv[3]; + enval = argv[4]; + + SGDBG( ("SOCKET", + "nif_setopt -> entry with argc: %d" + "\r\n esock: %T" + "\r\n elevel: %T" + "\r\n eopt: %T" + "\r\n eval: %T" + "\r\n enval: %T" + "\r\n", argc, esock, elevel, eopt, eval, enval) ); + + /* Extract arguments and perform preliminary validation */ + + if ((! ESOCK_GET_RESOURCE(env, esock, (void**) &descP)) || + (! GET_INT(env, enval, &nativeValue))) { + SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); + return enif_make_badarg(env); } - return result; + if (! GET_INT(env, eopt, &opt)) { + SSDBG( descP, + ("SOCKET", "nif_setopt -> failed initial arg check\r\n") ); + if (! IS_INTEGER(env, eopt)) + return enif_make_badarg(env); + else + return esock_make_error_integer_range(env, eopt); + } -} -#endif -#endif // #ifndef __WIN32__ + if (COMPARE(elevel, atom_otp) == 0) { + if (nativeValue == 0) { + return ESOCK_IO_SETOPT_OTP(env, descP, opt, eval); + } else { + SSDBG( descP, ("SOCKET", "nif_setopt -> failed arg check\r\n") ); + return enif_make_badarg(env); + } + } + if (esock_decode_level(env, elevel, &level)) { + if (nativeValue == 0) + return ESOCK_IO_SETOPT(env, descP, level, opt, eval); + else + return ESOCK_IO_SETOPT_NATIVE(env, descP, level, opt, eval); + } -#endif // defined(HAVE_IPV6) + SGDBG( ("SOCKET", "nif_setopt -> failed arg check\r\n") ); + + if (IS_INTEGER(env, elevel)) + return esock_make_error_integer_range(env, elevel); + else + return enif_make_badarg(env); +} -/* esock_getopt_tcp_congestion - Level TCP CONGESTION option +/* esock_setopt_otp - Handle OTP (level) options */ -#ifndef __WIN32__ -#if defined(TCP_CONGESTION) + static -ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt, + ERL_NIF_TERM eVal) { - int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1; + ERL_NIF_TERM result; - return esock_getopt_str_opt(env, descP, level, opt, max, TRUE); -} -#endif -#endif // #ifndef __WIN32__ + switch (eOpt) { + case ESOCK_OPT_OTP_DEBUG: + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + result = esock_setopt_otp_debug(env, descP, eVal); + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_IOW: + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + result = esock_setopt_otp_iow(env, descP, eVal); + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_CTRL_PROC: + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + result = esock_setopt_otp_ctrl_proc(env, descP, eVal); + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; -#if defined(HAVE_SCTP) + case ESOCK_OPT_OTP_RCVBUF: + MLOCK(descP->readMtx); + result = esock_setopt_otp_rcvbuf(env, descP, eVal); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_RCVCTRLBUF: + MLOCK(descP->readMtx); + result = esock_setopt_otp_rcvctrlbuf(env, descP, eVal); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_SNDCTRLBUF: + MLOCK(descP->writeMtx); + result = esock_setopt_otp_sndctrlbuf(env, descP, eVal); + MUNLOCK(descP->writeMtx); + break; -/* esock_getopt_sctp_associnfo - Level SCTP ASSOCINFO option - * - * - * - * We should really specify which association this relates to, - * as it is now we get assoc-id = 0. If this socket is an - * association (and not an endpoint) then it will have an - * assoc id. But since the sctp support at present is "limited", - * we leave it for now. - * What do we do if this is an endpoint? Invalid op? Or just leave - * it for the OS? - * - * - */ -#ifndef __WIN32__ -#if defined(SCTP_ASSOCINFO) -static -ERL_NIF_TERM esock_getopt_sctp_associnfo(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) -{ - ERL_NIF_TERM result; - struct sctp_assocparams val; - SOCKOPTLEN_T valSz = sizeof(val); - int res; + case ESOCK_OPT_OTP_META: + MLOCK(descP->writeMtx); + result = esock_setopt_otp_meta(env, descP, eVal); + MUNLOCK(descP->writeMtx); + break; - sys_memzero((char*) &val, valSz); - res = sock_getopt(descP->sock, level, opt, &val, &valSz); + case ESOCK_OPT_OTP_USE_REGISTRY: + MLOCK(descP->writeMtx); + result = esock_setopt_otp_use_registry(env, descP, eVal); + MUNLOCK(descP->writeMtx); + break; - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eAssocParams; - ERL_NIF_TERM keys[] = {atom_assoc_id, - atom_asocmaxrxt, - atom_number_peer_destinations, - atom_peer_rwnd, - atom_local_rwnd, - atom_cookie_life}; - ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.sasoc_assoc_id), - MKUI(env, val.sasoc_asocmaxrxt), - MKUI(env, val.sasoc_number_peer_destinations), - MKUI(env, val.sasoc_peer_rwnd), - MKUI(env, val.sasoc_local_rwnd), - MKUI(env, val.sasoc_cookie_life)}; - size_t numKeys = NUM(keys); + default: + MLOCK(descP->writeMtx); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp {%d} -> invalid with" + "\r\n eOpt: %d" + "\r\n eVal: %T" + "\r\n", descP->sock, eOpt, eVal) ); + MUNLOCK(descP->writeMtx); - ESOCK_ASSERT( numKeys == NUM(vals) ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eAssocParams) ); - result = esock_make_ok2(env, eAssocParams); + /* This is an internal error - prim_inet gave us junk */ + result = + esock_raise_invalid(env, + MKT2(env, + atom_otp_socket_option, + MKI(env, eOpt))); + break; } return result; } -#endif -#endif // #ifndef __WIN32__ - -/* esock_getopt_sctp_initmsg - Level SCTP INITMSG option - * +/* esock_setopt_otp_debug - Handle the OTP (level) debug options */ -#ifndef __WIN32__ -#if defined(SCTP_INITMSG) + static -ERL_NIF_TERM esock_getopt_sctp_initmsg(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp_debug(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - struct sctp_initmsg val; - SOCKOPTLEN_T valSz = sizeof(val); - int res; - - sys_memzero((char*) &val, valSz); - res = sock_getopt(descP->sock, level, opt, &val, &valSz); + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_debug {%d} -> closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eInitMsg; - ERL_NIF_TERM keys[] = {atom_num_outstreams, atom_max_instreams, - atom_max_attempts, atom_max_init_timeo}; - ERL_NIF_TERM vals[] = {MKUI(env, val.sinit_num_ostreams), - MKUI(env, val.sinit_max_instreams), - MKUI(env, val.sinit_max_attempts), - MKUI(env, val.sinit_max_init_timeo)}; - unsigned int numKeys = NUM(keys); - unsigned int numVals = NUM(vals); + if (! esock_decode_bool(eVal, &descP->dbg)) + return esock_make_invalid(env, esock_atom_value); - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eInitMsg) ); - result = esock_make_ok2(env, eInitMsg); - } + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_debug {%d} -> ok" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - return result; + return esock_atom_ok; } -#endif -#endif // #ifndef __WIN32__ -/* esock_getopt_sctp_rtoinfo - Level SCTP ASSOCINFO option - * - * - * - * We should really specify which association this relates to, - * as it is now we get assoc-id = 0. If this socket is an - * association (and not an endpoint) then it will have an - * assoc id (we can assume). But since the sctp support at - * present is "limited", we leave it for now. - * What do we do if this is an endpoint? Invalid op? - * - * + +/* esock_setopt_otp_iow - Handle the OTP (level) iow options */ -#ifndef __WIN32__ -#if defined(SCTP_RTOINFO) + static -ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp_iow(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - struct sctp_rtoinfo val; - SOCKOPTLEN_T valSz = sizeof(val); - int res; - - sys_memzero((char*) &val, valSz); - res = sock_getopt(descP->sock, level, opt, &val, &valSz); - - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eRTOInfo; - ERL_NIF_TERM keys[] = {atom_assoc_id, atom_initial, atom_max, atom_min}; - ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.srto_assoc_id), - MKUI(env, val.srto_initial), - MKUI(env, val.srto_max), - MKUI(env, val.srto_min)}; - unsigned int numKeys = NUM(keys); - unsigned int numVals = NUM(vals); - - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eRTOInfo) ); - result = esock_make_ok2(env, eRTOInfo); + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_iow {%d} -> closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - return result; -} -#endif -#endif // #ifndef __WIN32__ - + if (! esock_decode_bool(eVal, &descP->iow)) + return esock_make_invalid(env, esock_atom_value); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_iow {%d} -> ok" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); -#endif // defined(HAVE_SCTP) + return esock_atom_ok; +} -/* esock_getopt_bool_opt - get an (integer) bool option +/* esock_setopt_otp_ctrl_proc - Handle the OTP (level) + * controlling_process options */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp_ctrl_proc(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - int val = 0; + ErlNifPid caller, newCtrlPid; + int xres; - if (! esock_getopt_int(descP->sock, level, opt, &val)) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM bval = ((val) ? atom_true : atom_false); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> entry" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - result = esock_make_ok2(env, bval); + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - return result; -} -#endif // #ifndef __WIN32__ + /* Ensure that caller is (current) controlling process */ + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) { + SSDBG( descP, ("SOCKET", + "esock_setopt_otp_ctrl_proc -> not owner (%T)\r\n", + descP->ctrlPid) ); + return esock_make_error_invalid(env, esock_atom_not_owner); + } -/* esock_getopt_int_opt - get an integer option - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) -{ - int val; + /* Ensure that the new controller is a local process */ + if (!GET_LPID(env, eVal, &newCtrlPid)) { + esock_warning_msg("Failed get pid of new controlling process\r\n"); + return esock_make_invalid(env, esock_atom_value); + } - if (! esock_getopt_int(descP->sock, level, opt, &val)) - return esock_make_error_errno(env, sock_errno()); + if ((xres = DEMONP("esock_setopt_otp_ctrl_proc -> (old) ctrl", + env, descP, &descP->ctrlMon)) != 0) { + /* There is a legitimate reason for this is; the current + * process was just killed from a different thread + */ + esock_warning_msg("Failed demonitor (%d) " + "old controlling process %T (%T)\r\n", + xres, descP->ctrlPid, descP->ctrlMon); + } - return esock_make_ok2(env, MKI(env, val)); -} -#endif // #ifndef __WIN32__ + descP->ctrlPid = newCtrlPid; + if ((xres = + MONP("esock_setopt_otp_ctrl_proc -> (new) ctrl", + env, descP, &descP->ctrlPid, &descP->ctrlMon)) != 0) { + ESOCK_ASSERT( 0 < xres ); + /* Indicates that we do not have a DOWN callback, + * which is preposterous + */ -/* esock_getopt_int - get an integer option - */ + /* We know newCtrlPid is not 'undefined' so + * it must be dead already + * - pretend the controlling process change went well + * and then the monitor went down + */ + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> DOWN" + "\r\n xres: %d" + "\r\n", descP->sock, xres) ); + + enif_set_pid_undefined(&descP->ctrlPid); + + /* Shall we use an function pointer argument instead? */ #ifndef __WIN32__ -static -BOOLEAN_T esock_getopt_int(SOCKET sock, - int level, - int opt, - int* valP) -{ - int val = 0; - SOCKOPTLEN_T valSz = sizeof(val); + essio_down_ctrl(env, descP, &newCtrlPid); +#else + esaio_down_ctrl(env, descP, &newCtrlPid); +#endif - if (sock_getopt(sock, level, opt, &val, &valSz) != 0) - return FALSE; + descP->readState |= ESOCK_STATE_CLOSING; + descP->writeState |= ESOCK_STATE_CLOSING; - *valP = val; - return TRUE; + } else { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_ctrl_proc {%d} -> ok" + "\r\n", descP->sock) ); + } + + return esock_atom_ok; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ +/* esock_setopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option + * The (otp) rcvbuf option is provided as: + * + * BufSz :: default | pos_integer() | + * {N :: pos_integer(), Sz :: default | pos_integer()} + * + * Where N is the max number of reads. + * Note that on Windows the tuple variant is not allowed! + */ + static -ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - SOCKOPTLEN_T valueSz) +ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - int res; - - if (valueSz == 0) { - res = sock_getopt(descP->sock, level, opt, NULL, NULL); - if (res != 0) - result = esock_make_error_errno(env, sock_errno()); - else - result = esock_atom_ok; - } else { - SOCKOPTLEN_T vsz = valueSz; - ErlNifBinary val; + const ERL_NIF_TERM* t; // The array of the elements of the tuple + int tsz; // The size of the tuple - should be 2 +#ifndef __WIN32__ + unsigned int n; +#endif + size_t bufSz; + ssize_t z; - ESOCK_ASSERT( ALLOC_BIN(vsz, &val) ); - sys_memzero(val.data, val.size); - res = sock_getopt(descP->sock, level, opt, val.data, &vsz); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - FREE_BIN(&val); - } else { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> entry" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - /* Did we use all of the buffer? */ - if (vsz == val.size) { - result = esock_make_ok2(env, MKBIN(env, &val)); + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - } else { - ERL_NIF_TERM tmp; +#ifdef __WIN32__ - tmp = MKBIN(env, &val); - tmp = MKSBIN(env, tmp, 0, vsz); + if (!esock_decode_bufsz(env, + eVal, + ESOCK_RECV_BUFFER_SIZE_DEFAULT, + &bufSz)) { + SSDBG( descP, + ("SOCKET", + "esock_setopt_otp_rcvbuf(%d) -> done invalid\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); + } - result = esock_make_ok2(env, tmp); - } +#else + + if (esock_decode_bufsz(env, + eVal, + ESOCK_RECV_BUFFER_SIZE_DEFAULT, + &bufSz)) { + n = 0; // Reported as an integer buffer size by getopt + } else { + if ((! GET_TUPLE(env, eVal, &tsz, &t)) || + (tsz != 2) || + (! GET_UINT(env, t[0], &n)) || + (n == 0) || + (! esock_decode_bufsz(env, t[1], + ESOCK_RECV_BUFFER_SIZE_DEFAULT, + &bufSz))) { + SSDBG( descP, + ("SOCKET", + "esock_setopt_otp_rcvbuf {%d} -> done invalid\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); } } +#endif - return result; + // We do not want a buffer size that does not fit in ssize_t + z = bufSz; + if (bufSz != (size_t) z) + return esock_make_invalid(env, esock_atom_value); + +#ifndef __WIN32__ + descP->rNum = n; +#endif + descP->rBufSz = bufSz; + + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_rcvbuf {%d} -> ok" + "\r\n", descP->sock) ); + + return esock_atom_ok; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + +/* esock_setopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option + */ + static -ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - ErlNifBinary* binP) +ERL_NIF_TERM esock_setopt_otp_rcvctrlbuf(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - int res; - SOCKOPTLEN_T vsz; - ErlNifBinary val; - - vsz = (SOCKOPTLEN_T) binP->size; - if (SZT(vsz) != binP->size) { - result = esock_make_error_invalid(env, atom_data_size); - } else { - ESOCK_ASSERT( ALLOC_BIN(vsz, &val) ); - sys_memcpy(val.data, binP->data, vsz); - res = sock_getopt(descP->sock, level, opt, val.data, &vsz); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - FREE_BIN(&val); - } else { + size_t val; - /* Did we use all of the buffer? */ - if (vsz == val.size) { - result = esock_make_ok2(env, MKBIN(env, &val)); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_recvctrlbuf {%d} -> entry" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - } else { + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - ERL_NIF_TERM tmp; + if (! esock_decode_bufsz(env, + eVal, + ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT, + &val)) { + SSDBG( descP, + ("SOCKET", + "esock_setopt_otp_rcvctrlbuf {%d} -> done invalid\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); + } - tmp = MKBIN(env, &val); - tmp = MKSBIN(env, tmp, 0, vsz); + descP->rCtrlSz = val; - result = esock_make_ok2(env, tmp); - } - } - } + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_rcvctrlbuf {%d} -> ok" + "\r\n", descP->sock) ); - return result; + return esock_atom_ok; } -#endif // #ifndef __WIN32__ -/* esock_getopt_timeval_opt - get an timeval option + +/* esock_setopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option */ -#ifndef __WIN32__ -#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ - && defined(ESOCK_USE_RCVSNDTIMEO) + static -ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - struct timeval val; - SOCKOPTLEN_T valSz = sizeof(val); - int res; + size_t val; - sys_memzero((char*) &val, valSz); - res = sock_getopt(descP->sock, level, opt, &val, &valSz); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_sndvctrlbuf {%d} -> entry" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM eTimeVal; + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - esock_encode_timeval(env, &val, &eTimeVal); - result = esock_make_ok2(env, eTimeVal); + if (! esock_decode_bufsz(env, + eVal, + ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT, + &val)) { + SSDBG( descP, + ("SOCKET", + "esock_setopt_otp_sndctrlbuf {%d} -> done invalid\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_value); } - return result; + descP->wCtrlSz = val; + + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_sndctrlbuf {%d} -> ok" + "\r\n", descP->sock) ); + + return esock_atom_ok; } -#endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#if defined(IP_PKTOPTIONS) || defined(IPV6_PKTOPTIONS) -/* Calculate CMSG_NXTHDR without having a struct msghdr*. - * CMSG_LEN only caters for alignment for start of data. - * To get how much to advance we need to use CMSG_SPACE - * on the payload length. To get the payload length we - * take the calculated cmsg->cmsg_len and subtract the - * header length. To get the header length we use - * the pointer difference from the cmsg start pointer - * to the CMSG_DATA(cmsg) pointer. - * - * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3) - * may return 0 as the cmsg_len if the cmsg is to be ignored. +/* esock_setopt_otp_meta - Handle the OTP (level) meta options */ -#define LEN_CMSG_DATA(__CMSG__) \ - ((__CMSG__)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \ - (__CMSG__)->cmsg_len - ((char*)CMSG_DATA(__CMSG__) - (char*)(__CMSG__))) -#define NEXT_CMSG_HDR(__CMSG__) \ - ((struct cmsghdr*)(((char*)(__CMSG__)) + CMSG_SPACE(LEN_CMSG_DATA(__CMSG__)))) static -ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt) +ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result, ePktOpts; - int res; - ErlNifBinary cmsgs; - SOCKOPTLEN_T sz = (SOCKOPTLEN_T) descP->rCtrlSz; - SocketTArray cmsghdrs = TARRAY_CREATE(16); - ERL_NIF_TERM ctrlBuf; - - ESOCK_ASSERT( ALLOC_BIN(sz, &cmsgs) ); - - sys_memzero(cmsgs.data, cmsgs.size); - sz = cmsgs.size; // Make no assumption about the size - res = sock_getopt(descP->sock, level, opt, cmsgs.data, &sz); + ErlNifPid caller; - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - struct cmsghdr* currentP; - struct cmsghdr* endOfBuf; + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); - ctrlBuf = MKBIN(env, &cmsgs); // The *entire* binary + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_meta {%d} -> entry" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - for (endOfBuf = (struct cmsghdr*)(cmsgs.data + cmsgs.size), - currentP = (struct cmsghdr*)(cmsgs.data); - (currentP != NULL) && (currentP < endOfBuf); - currentP = NEXT_CMSG_HDR(currentP)) { - unsigned char* dataP = UCHARP(CMSG_DATA(currentP)); - size_t dataPos = dataP - cmsgs.data; - size_t dataLen = (UCHARP(currentP) + currentP->cmsg_len) - dataP; + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_meta {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - SSDBG( descP, - ("SOCKET", "esock_getopt_pktoptions {%d} -> cmsg header data: " - "\r\n currentP: 0x%lX" - "\r\n level: %d" - "\r\n data: %d" - "\r\n len: %d [0x%lX]" - "\r\n dataP: 0x%lX" - "\r\n dataPos: %d" - "\r\n dataLen: %d [0x%lX]" - "\r\n", descP->sock, - currentP, - currentP->cmsg_level, - currentP->cmsg_type, - currentP->cmsg_len, currentP->cmsg_len, - dataP, - dataPos, - dataLen, dataLen) ); + if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) { + SSDBG( descP, ("SOCKET", + "esock_setopt_otp_meta -> not owner (%T)\r\n", + descP->ctrlPid) ); + return esock_make_error_invalid(env, esock_atom_not_owner); + } - /* - * Check that this is within the allocated buffer... - * The 'next control message header' is a bit adhoc, - * so this check is a bit... - */ - if ((dataPos > cmsgs.size) || - (dataLen > cmsgs.size) || - ((dataPos + dataLen) > ((size_t)endOfBuf))) { - break; - } else { - ERL_NIF_TERM cmsgHdr; - ERL_NIF_TERM keys[] = {esock_atom_level, - esock_atom_type, - esock_atom_data, - atom_value}; - ERL_NIF_TERM vals[NUM(keys)]; - size_t numKeys = NUM(keys); - BOOLEAN_T haveValue; - - vals[0] = esock_encode_level(env, currentP->cmsg_level); - vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); + enif_clear_env(descP->meta.env); + descP->meta.ref = CP_TERM(descP->meta.env, eVal); - haveValue = encode_cmsg(env, - currentP->cmsg_level, - currentP->cmsg_type, - dataP, dataLen, &vals[1], &vals[3]); + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_meta {%d} -> ok" + "\r\n", descP->sock) ); - SSDBG( descP, - ("SOCKET", "esock_getopt_pktoptions {%d} -> " - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n", descP->sock, - keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); + return esock_atom_ok; +} - if (haveValue) { - SSDBG( descP, - ("SOCKET", "esock_getopt_pktoptions {%d} -> " - "\r\n %T: %T" - "\r\n", descP->sock, keys[3], vals[3]) ); - } - /* Guard agains cut-and-paste errors */ - ESOCK_ASSERT( numKeys == NUM(vals) ); - /* Make control message header map */ - ESOCK_ASSERT( MKMA(env, keys, vals, - numKeys - (haveValue ? 0 : 1), &cmsgHdr) ); +/* esock_setopt_otp_use_registry - Handle the OTP (level) use_registry option + */ - SSDBG( descP, - ("SOCKET", "esock_getopt_pktoptions {%d} -> header processed: " - "\r\n %T" - "\r\n", descP->sock, cmsgHdr) ); +static +ERL_NIF_TERM esock_setopt_otp_use_registry(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eVal) +{ + BOOLEAN_T useReg = FALSE; - /* And finally add it to the list... */ - TARRAY_ADD(cmsghdrs, cmsgHdr); - } + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_use_registry {%d} -> closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - SSDBG( descP, - ("SOCKET", "esock_getopt_pktoptions {%d} -> " - "cmsg headers processed when" - "\r\n TArray Size: %d" - "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); - - /* The tarray is populated - convert it to a list */ - TARRAY_TOLIST(cmsghdrs, env, &ePktOpts); - - result = esock_make_ok2(env, ePktOpts); - } - - FREE_BIN(&cmsgs); + if (! esock_decode_bool(eVal, &useReg)) + return esock_make_invalid(env, esock_atom_value); - return result; -} -#endif -#endif // #ifndef __WIN32__ + /* We only allow turning this on! */ + if (! useReg) + return esock_make_invalid(env, esock_atom_value); + if (!descP->useReg) { + ERL_NIF_TERM sockRef = enif_make_resource(env, descP); + descP->useReg = useReg; + esock_send_reg_add_msg(env, descP, sockRef); + } + SSDBG( descP, + ("SOCKET", "esock_setopt_otp_use_registry {%d} -> ok" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); -/* esock_getopt_str_opt - get a string option - * - * We provide the max size of the string. This is the - * size of the buffer we allocate for the value. - * The actual size of the (read) value will be communicated - * in the valSz variable. + return esock_atom_ok; +} + + + +/* The option has *not* been encoded. Instead it has been provided + * in "native mode" (value is a binary, an integer or a boolean). */ -#ifndef __WIN32__ -#if defined(USE_GETOPT_STR_OPT) + static -ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - int opt, - int max, - BOOLEAN_T stripNUL) +ERL_NIF_TERM esock_setopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { + ErlNifBinary binary; + int integer; + BOOLEAN_T boolean; ERL_NIF_TERM result; - char* val = MALLOC(max); - SOCKOPTLEN_T valSz = max; - int res; - ESOCK_ASSERT( val != NULL ); + MLOCK(descP->writeMtx); - sys_memzero(val, max); - res = sock_getopt(descP->sock, level, opt, val, &valSz); + SSDBG( descP, + ("SOCKET", "esock_setopt_native {%d} -> entry" + "\r\n level: %d" + "\r\n opt: %d" + "\r\n eVal: %T" + "\r\n", descP->sock, + level, opt, eVal) ); - if (res != 0) { - result = esock_make_error_errno(env, sock_errno()); - } else { - if (stripNUL && - valSz > 0 && - val[valSz - 1] == '\0') valSz--; + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_native {%d} -> done closed\r\n", + descP->sock) ); - result = esock_make_ok2(env, MKSL(env, val, valSz)); + MUNLOCK(descP->writeMtx); + return esock_make_error_closed(env); } - FREE(val); + if (GET_BIN(env, eVal, &binary)) { + result = esock_setopt_level_opt(env, descP, level, opt, + binary.data, binary.size); + } else if (GET_INT(env, eVal, &integer)) { + result = esock_setopt_level_opt(env, descP, level, opt, + &integer, sizeof(integer)); + } else if (esock_decode_bool(eVal, &boolean)) { + integer = boolean ? 1 : 0; + result = esock_setopt_level_opt(env, descP, level, opt, + &integer, sizeof(integer)); + } else { + result = esock_make_error_invalid(env, esock_atom_value); + } + + SSDBG( descP, + ("SOCKET", "esock_setopt_native {%d} -> done when" + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + MUNLOCK(descP->writeMtx); return result; } -#endif // if defined(USE_GETOPT_STR_OPT) -#endif // #ifndef __WIN32__ -/* ---------------------------------------------------------------------- - * nif_sockname - get socket name - * - * Description: - * Returns the current address to which the socket is bound. - * - * Arguments: - * Socket (ref) - Points to the socket descriptor. +/* esock_setopt - A "proper" level (option) has been specified, + * and we have an value of known encoding */ static -ERL_NIF_TERM nif_sockname(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM esock_setopt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM res; + ERL_NIF_TERM result; + const struct ESockOpt *optP; - ESOCK_ASSERT( argc == 1 ); + MLOCK(descP->writeMtx); - SGDBG( ("SOCKET", "nif_sockname -> entry with argc: %d\r\n", argc) ); + SSDBG( descP, + ("SOCKET", "esock_setopt(%d) -> entry with" + "\r\n level: %d" + "\r\n opt: %d" + "\r\n eVal: %T" + "\r\n", descP->sock, level, opt, eVal) ); - /* Extract arguments and perform preliminary validation */ + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_setopt(%d) -> done closed\r\n", + descP->sock) ); - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); + MUNLOCK(descP->writeMtx); + return esock_make_error_closed(env); } - MLOCK(descP->readMtx); + optP = lookupOpt(level, opt); - SSDBG( descP, - ("SOCKET", "nif_sockname(%T) {%d}" - "\r\n", argv[0], descP->sock) ); + if (optP == NULL) { - res = esock_sockname(env, descP); + result = esock_make_invalid(env, atom_socket_option); - SSDBG( descP, - ("SOCKET", "nif_sockname(%T) {%d} -> done with res = %T\r\n", - argv[0], descP->sock, res) ); + SSDBG( descP, + ("SOCKET", + "esock_setopt(%d) -> unknown option\r\n", + descP->sock) ); - MUNLOCK(descP->readMtx); + } else if (optP->setopt == NULL) { - return res; -#endif // #ifdef __WIN32__ #else + result = esock_make_invalid(env, atom_socket_option); + + SSDBG( descP, + ("SOCKET", + "esock_setopt(%d) -> opt not settable\r\n", + descP->sock) ); + + } else { + + result = (optP->setopt)(env, descP, level, opt, eVal); + + SSDBG( descP, + ("SOCKET", "esock_setopt(%d) -> done when" + "\r\n result: %T" + "\r\n", descP->sock, result) ); + } + + MUNLOCK(descP->writeMtx); + return result; } +#if defined(SO_BINDTODEVICE) +static +ERL_NIF_TERM esock_setopt_so_bindtodevice(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + return esock_setopt_str_opt(env, descP, level, opt, IFNAMSIZ, eVal); +} +#endif + -#ifndef __WIN32__ +#if defined(SO_LINGER) static -ERL_NIF_TERM esock_sockname(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM esock_setopt_linger(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - ESockAddress sa; - ESockAddress* saP = &sa; - SOCKLEN_T sz = sizeof(ESockAddress); + ERL_NIF_TERM eOnOff, eLinger; + BOOLEAN_T onOff; + struct linger val; - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); + SSDBG( descP, + ("SOCKET", "esock_setopt_linger(%d) -> entry with" + "\r\n level: %d" + "\r\n opt: %d" + "\r\n eVal: %T" + "\r\n", descP->sock, level, opt, eVal) ); - sys_memzero((char*) saP, sz); - if (sock_name(descP->sock, (struct sockaddr*) saP, &sz) < 0) { - return esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM esa; + sys_memzero(&val, sizeof(val)); - esock_encode_sockaddr(env, saP, sz, &esa); - return esock_make_ok2(env, esa); + if ((! GET_MAP_VAL(env, eVal, atom_onoff, &eOnOff)) || + (! GET_MAP_VAL(env, eVal, esock_atom_linger, &eLinger))) { + + if (COMPARE(eVal, esock_atom_abort) == 0) { + val.l_onoff = 1; + val.l_linger = 0; + return esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); + } else + return esock_make_invalid(env, esock_atom_value); + } + + if ((! esock_decode_bool(eOnOff, &onOff)) || + (! GET_INT(env, eLinger, (int*) &val.l_linger)) || + (val.l_linger < 0)) { + return esock_make_invalid(env, esock_atom_value); } + val.l_onoff = onOff ? 1 : 0; + + SSDBG( descP, + ("SOCKET", "esock_setopt_linger(%d) -> entry with" + "\r\n val.l_onoff: %d" + "\r\n val.l_linger: %d" + "\r\n", descP->sock, val.l_onoff, val.l_linger) ); + + return esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); } -#endif // #ifndef __WIN32__ +#endif +#if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) -/* ---------------------------------------------------------------------- - * nif_peername - get name of the connected peer socket - * - * Description: - * Returns the address of the peer connected to the socket. +/* esock_setopt_msfilter - Level IP MSFILTER option * - * Arguments: - * Socket (ref) - Points to the socket descriptor. + * The value can be *either* the atom 'null' or a map of type ip_msfilter(). */ - static -ERL_NIF_TERM nif_peername(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM esock_setopt_msfilter(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM res; + ERL_NIF_TERM result; - ESOCK_ASSERT( argc == 1 ); + if (COMPARE(eVal, atom_null) == 0) { + return + esock_setopt_level_opt(env, descP, level, opt, NULL, 0); + } else { + struct ip_msfilter* msfP; + Uint32 msfSz; + ERL_NIF_TERM eMultiAddr, eInterface, eFMode, eSList, elem, tail; + unsigned int slistLen, idx; - SGDBG( ("SOCKET", "nif_peername -> entry with argc: %d\r\n", argc) ); + if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) || + (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) || + (! GET_MAP_VAL(env, eVal, atom_mode, &eFMode)) || + (! GET_MAP_VAL(env, eVal, atom_slist, &eSList))) + goto invalid; + + /* We start (decoding) with the slist, since without it we don't + * really know how much (memory) to allocate. + */ + if (! GET_LIST_LEN(env, eSList, &slistLen)) + goto invalid; + + msfSz = IP_MSFILTER_SIZE(slistLen); + msfP = MALLOC(msfSz); + ESOCK_ASSERT( msfP != NULL ); + + if ((! esock_decode_in_addr(env, eMultiAddr, + &msfP->imsf_multiaddr)) || + (! esock_decode_in_addr(env, eInterface, + &msfP->imsf_interface)) || + (! decode_msfilter_mode(env, eFMode, + (Uint32*) &msfP->imsf_fmode))) + goto free_invalid; - /* Extract arguments and perform preliminary validation */ + /* And finally, extract the source addresses */ + msfP->imsf_numsrc = slistLen; + for (idx = 0; idx < slistLen; idx++) { + ESOCK_ASSERT( GET_LIST_ELEM(env, eSList, &elem, &tail) ); + if (! esock_decode_in_addr(env, elem, + &msfP->imsf_slist[idx])) + goto free_invalid; + eSList = tail; + } - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - return enif_make_badarg(env); - } + /* And now, finally, set the option */ + result = esock_setopt_level_opt(env, descP, level, opt, + msfP, msfSz); - MLOCK(descP->readMtx); + FREE(msfP); + return result; - SSDBG( descP, - ("SOCKET", "nif_peername(%T) {%d}" - "\r\n", argv[0], descP->sock) ); + free_invalid: + FREE(msfP); + invalid: + return esock_make_invalid(env, esock_atom_value); + } - res = esock_peername(env, descP); +} - SSDBG( descP, - ("SOCKET", "nif_peername(%T) {%d} -> done with res = %T\r\n", - argv[0], descP->sock, res) ); +static +BOOLEAN_T decode_msfilter_mode(ErlNifEnv* env, + ERL_NIF_TERM eVal, + Uint32* mode) +{ + BOOLEAN_T result; - MUNLOCK(descP->readMtx); + if (COMPARE(eVal, atom_include) == 0) { + *mode = MCAST_INCLUDE; + result = TRUE; + } else if (COMPARE(eVal, atom_exclude) == 0) { + *mode = MCAST_EXCLUDE; + result = TRUE; + } else { + result = FALSE; + } - return res; -#endif // #ifdef __WIN32__ #else + return result; } +#endif // #if defined(IP_MSFILTER) && defined(IP_MSFILTER_SIZE) -#ifndef __WIN32__ +/* esock_setopt_ip_mtu_discover - Level IP MTU_DISCOVER option + * + * The value is an atom of the type ip_pmtudisc(). + */ +#if defined(IP_MTU_DISCOVER) static -ERL_NIF_TERM esock_peername(ErlNifEnv* env, - ESockDescriptor* descP) +ERL_NIF_TERM esock_setopt_ip_mtu_discover(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - ESockAddress sa; - ESockAddress* saP = &sa; - SOCKLEN_T sz = sizeof(ESockAddress); - - if (! IS_OPEN(descP->readState)) - return esock_make_error(env, atom_closed); - - sys_memzero((char*) saP, sz); - if (sock_peer(descP->sock, (struct sockaddr*) saP, &sz) < 0) { - return esock_make_error_errno(env, sock_errno()); - } else { - ERL_NIF_TERM esa; + int val; - esock_encode_sockaddr(env, saP, sz, &esa); - return esock_make_ok2(env, esa); - } + if (! decode_ip_pmtudisc(env, eVal, &val)) + return esock_make_invalid(env, esock_atom_value); + else + return esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); } -#endif // #ifndef __WIN32__ +#endif // #if defined(IP_MTU_DISCOVER) -/* ---------------------------------------------------------------------- - * nif_ioctl - control device - get - * - * Description: - * Returns whatever info the ioctl returns for the specific (get) request. - * WHEN SET IS IMPLEMENTED, WE NED ANOTHER ARGUMENT!! +/* esock_setopt_multicast_if - Level IP MULTICAST_IF option * - * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Request - The ioctl get/set request - * NameOrIdx - Name or Index of the interface - only for some requests - * Currently only one (get) request does not provide this - * (and the value) argument; gifconf - * Currently, only one (get) request use index; gifname - * All other requests (get and set) use Name as "key". - * Val - Value to *set* - * This argument is *only* provided for set requests. + * The value is either the atom 'any' or a 4-tuple. */ - +#if defined(IP_MULTICAST_IF) static -ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) +ERL_NIF_TERM esock_setopt_multicast_if(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ESockDescriptor* descP; - ERL_NIF_TERM res; - unsigned long req; - - SGDBG( ("SOCKET", "nif_ioctl -> entry with argc: %d\r\n", argc) ); - - ESOCK_ASSERT( (argc == 2) || (argc == 3) || (argc == 4) ); + ERL_NIF_TERM result; + struct in_addr ifAddr; - if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { - SGDBG( ("SOCKET", "nif_ioctl -> no resource\r\n") ); - return enif_make_badarg(env); - } + if (! esock_decode_in_addr(env, eVal, &ifAddr)) { + result = esock_make_invalid(env, esock_atom_value); + } else { + result = + esock_setopt_level_opt(env, descP, level, opt, + &ifAddr, sizeof(ifAddr)); + } - if (! GET_ULONG(env, argv[1], &req)) { - SGDBG( ("SOCKET", "nif_ioctl -> 'request' not 'unsigned long'\r\n") ); - return enif_make_badarg(env); - } + return result; +} +#endif - SSDBG( descP, - ("SOCKET", "nif_ioctl(%T) {%d} -> ioctl request %d" - "\r\n", argv[0], descP->sock, req) ); - MLOCK(descP->readMtx); +/* esock_setopt_tos - Level IP TOS option + */ - if (! IS_OPEN(descP->readState)) { - res = esock_make_error(env, atom_closed); - } else { +#if defined(IP_TOS) +static +ERL_NIF_TERM esock_setopt_tos(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + ERL_NIF_TERM result; + int val; - if (argc == 2) { + if (decode_ip_tos(env, eVal, &val)) { + result = + esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); + } else { + result = esock_make_invalid(env, esock_atom_value); + } - /* Only one request with this number of arguments: gifconf - * Socket and request (=gifconf) - */ + return result; +} +#endif - /* Two arguments: Socket and get request */ - res = esock_ioctl1(env, descP, req); - } else if (argc == 3) { - /* (Currently) All *other* get requests has 3 arguments - * Socket, request and name/index - */ +/* The value is a map with two attributes: multiaddr and interface. + * The attribute 'multiaddr' is always a 4-tuple (IPv4 address). + * The attribute 'interface' is either the atom 'any' or a 4-tuple + * (IPv4 address). + */ - ERL_NIF_TERM earg = argv[2]; +#if defined(IP_ADD_MEMBERSHIP) || defined(IP_DROP_MEMBERSHIP) +static +ERL_NIF_TERM esock_setopt_in_update_membership(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + ERL_NIF_TERM eMultiAddr, eInterface; + struct ip_mreq mreq; - /* Two arguments: request and arg */ - res = esock_ioctl2(env, descP, req, earg); + if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in_update_membership -> " + "failed get multiaddr (map) attribute\r\n") ); + goto invalid; + } - } else if (argc == 4) { + if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in_update_membership -> " + "failed get interface (map) attribute\r\n") ); + goto invalid; + } - /* (Currently) Set requests has 4 arguments - * Socket, request, name and value - */ + if (! esock_decode_in_addr(env, + eMultiAddr, + &mreq.imr_multiaddr)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in_update_membership -> " + "failed decode multiaddr %T\r\n", eMultiAddr) ); + goto invalid; + } - ERL_NIF_TERM earg1 = argv[2]; // (currently) Name - ERL_NIF_TERM earg2 = argv[3]; // Value + if (! esock_decode_in_addr(env, + eInterface, + &mreq.imr_interface)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in_update_membership -> " + "failed decode interface %T\r\n", eInterface) ); + goto invalid; + } - /* Three arguments: request, arg1 (name) and arg2 (value) */ - res = esock_ioctl3(env, descP, req, earg1, earg2); + return esock_setopt_level_opt(env, descP, level, opt, + &mreq, sizeof(mreq)); - } else { + invalid: + return esock_make_invalid(env, esock_atom_value); +} +#endif - res = esock_make_error(env, esock_atom_einval); - } - } +/* The value is a map with three attributes: multiaddr, interface and + * sourceaddr. + * The attribute 'multiaddr' is always a 4-tuple (IPv4 address). + * The attribute 'interface' is always a 4-tuple (IPv4 address). + * The attribute 'sourceaddr' is always a 4-tuple (IPv4 address). + * (IPv4 address). + */ - MUNLOCK(descP->readMtx); +#if defined(IP_ADD_SOURCE_MEMBERSHIP) || \ + defined(IP_DROP_SOURCE_MEMBERSHIP) || \ + defined(IP_BLOCK_SOURCE) || \ + defined(IP_UNBLOCK_SOURCE) +static +ERL_NIF_TERM esock_setopt_in_update_source(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + ERL_NIF_TERM eMultiAddr, eInterface, eSourceAddr; + struct ip_mreq_source mreq; - SSDBG( descP, - ("SOCKET", "nif_ioctl(%T) {%d} -> done with res = %T\r\n", - argv[0], descP->sock, res) ); + if ((! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) || + (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) || + (! GET_MAP_VAL(env, eVal, atom_sourceaddr, &eSourceAddr)) || + (! esock_decode_in_addr(env, + eMultiAddr, + &mreq.imr_multiaddr)) || + (! esock_decode_in_addr(env, + eInterface, + &mreq.imr_interface)) || + (! esock_decode_in_addr(env, + eSourceAddr, + &mreq.imr_sourceaddr))) + goto invalid; - return res; -#endif // #ifdef __WIN32__ #else + return esock_setopt_level_opt(env, descP, level, opt, + &mreq, sizeof(mreq)); + invalid: + return esock_make_invalid(env, esock_atom_value); } +#endif -#ifndef __WIN32__ +#if defined(HAVE_IPV6) +#if defined(IPV6_ADDRFORM) static -ERL_NIF_TERM esock_ioctl1(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req) +ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - switch (req) { + int domain; -#if defined(SIOCGIFCONF) - case SIOCGIFCONF: - return esock_ioctl_gifconf(env, descP); - break; -#endif + SSDBG( descP, + ("SOCKET", "esock_setopt_addrform -> entry with" + "\r\n eVal: %T" + "\r\n", eVal) ); - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } + if (esock_decode_domain(env, eVal, &domain) == 0) + return esock_make_invalid(env, esock_atom_value); + SSDBG( descP, ("SOCKET", + "esock_setopt_addrform -> try set opt to %d\r\n", + domain) ); + + return esock_setopt_level_opt(env, descP, level, opt, + &domain, sizeof(domain)); } +#endif -/* The type and value of 'arg' depend on the request, - * which we have not yet "analyzed". + +/* esock_setopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option * - * Request arg arg type - * ------- ------- -------- - * gifname ifindex integer - * gifindex name string - * gifflags name string - * gifaddr name string - * gifdstaddr name string - * gifbdraddr name string - * gifnetmask name string - * gifmtu name string - * gifhwaddr name string - * gifmap name string - * giftxqlen name string + * The value is an atom of the type ipv6_pmtudisc(). */ + +#if defined(IPV6_MTU_DISCOVER) static -ERL_NIF_TERM esock_ioctl2(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM arg) +ERL_NIF_TERM esock_setopt_ipv6_mtu_discover(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - /* This for *get* requests */ - - switch (req) { - -#if defined(SIOCGIFNAME) - case SIOCGIFNAME: - return esock_ioctl_gifname(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFINDEX) - case SIOCGIFINDEX: - return esock_ioctl_gifindex(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFFLAGS) - case SIOCGIFFLAGS: - return esock_ioctl_gifflags(env, descP, arg); - break; -#endif - -#if defined(SIOCGIFADDR) - case SIOCGIFADDR: - return esock_ioctl_gifaddr(env, descP, arg); - break; -#endif + int val; -#if defined(SIOCGIFDSTADDR) - case SIOCGIFDSTADDR: - return esock_ioctl_gifdstaddr(env, descP, arg); - break; -#endif + if (! decode_ipv6_pmtudisc(env, eVal, &val)) + return esock_make_invalid(env, esock_atom_value); -#if defined(SIOCGIFBRDADDR) - case SIOCGIFBRDADDR: - return esock_ioctl_gifbrdaddr(env, descP, arg); - break; + return esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); +} #endif -#if defined(SIOCGIFNETMASK) - case SIOCGIFNETMASK: - return esock_ioctl_gifnetmask(env, descP, arg); - break; -#endif -#if defined(SIOCGIFMTU) - case SIOCGIFMTU: - return esock_ioctl_gifmtu(env, descP, arg); - break; -#endif -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) - case SIOCGIFHWADDR: - return esock_ioctl_gifhwaddr(env, descP, arg); - break; -#endif +#if defined(IPV6_MULTICAST_HOPS) +static +ERL_NIF_TERM esock_setopt_hops(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + int hops; -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) - case SIOCGIFMAP: - return esock_ioctl_gifmap(env, descP, arg); - break; -#endif + if (! decode_hops(env, eVal, &hops)) + return esock_make_invalid(env, esock_atom_value); -#if defined(SIOCGIFTXQLEN) - case SIOCGIFTXQLEN: - return esock_ioctl_giftxqlen(env, descP, arg); - break; + return esock_setopt_level_opt(env, descP, level, opt, + &hops, sizeof(hops)); +} #endif - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } - -} -/* The type and value of arg(s) depend on the request, - * which we have not yet "analyzed". - * - * Request arg1 arg1 type arg2 arg2 type - * ------- ------- --------- ------ --------- - * sifflags name string Flags #{IntFlag := boolean()} - * IntFlag is the native flag - * sifaddr name string Addr sockaddr() - * sifdstaddr name string DstAddr sockaddr() - * sifbrdaddr name string BrdAddr sockaddr() - * sifnetmask name string NetMask sockaddr() - * gifmtu name string MTU integer() - * sifhwaddr name string HwAddr sockaddr() - * giftxqlen name string Len integer() - */ +#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP) static -ERL_NIF_TERM esock_ioctl3(ErlNifEnv* env, - ESockDescriptor* descP, - unsigned long req, - ERL_NIF_TERM ename, - ERL_NIF_TERM eval) +ERL_NIF_TERM esock_setopt_in6_update_membership(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { + ERL_NIF_TERM eMultiAddr, eInterface; + struct ipv6_mreq mreq; - switch (req) { + if (! GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in6_update_membership -> " + "failed get multiaddr (map) attribute\r\n") ); + goto invalid; + } -#if defined(SIOCSIFFLAGS) - case SIOCSIFFLAGS: - return esock_ioctl_sifflags(env, descP, ename, eval); - break; -#endif + if (! GET_MAP_VAL(env, eVal, atom_interface, &eInterface)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in6_update_membership -> " + "failed get interface (map) attribute\r\n") ); + goto invalid; + } -#if defined(SIOCSIFADDR) - case SIOCSIFADDR: - return esock_ioctl_sifaddr(env, descP, ename, eval); - break; -#endif + if (! esock_decode_in6_addr(env, + eMultiAddr, + &mreq.ipv6mr_multiaddr)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in6_update_membership -> " + "failed decode multiaddr %T\r\n", eMultiAddr) ); + goto invalid; + } -#if defined(SIOCSIFDSTADDR) - case SIOCSIFDSTADDR: - return esock_ioctl_sifdstaddr(env, descP, ename, eval); - break; -#endif + if (! GET_UINT(env, eInterface, &mreq.ipv6mr_interface)) { + SSDBG( descP, + ("SOCKET", "esock_setopt_in6_update_membership -> " + "failed decode interface %T\r\n", eInterface) ); + goto invalid; + } -#if defined(SIOCSIFBRDADDR) - case SIOCSIFBRDADDR: - return esock_ioctl_sifbrdaddr(env, descP, ename, eval); - break; -#endif + return esock_setopt_level_opt(env, descP, level, opt, + &mreq, sizeof(mreq)); -#if defined(SIOCSIFNETMASK) - case SIOCSIFNETMASK: - return esock_ioctl_sifnetmask(env, descP, ename, eval); - break; + invalid: + return esock_make_invalid(env, esock_atom_value); +} #endif -#if defined(SIOCSIFMTU) - case SIOCSIFMTU: - return esock_ioctl_sifmtu(env, descP, ename, eval); - break; -#endif -#if defined(SIOCSIFTXQLEN) - case SIOCSIFTXQLEN: - return esock_ioctl_siftxqlen(env, descP, ename, eval); - break; -#endif +#endif // defined(HAVE_IPV6) - default: - return esock_make_error(env, esock_atom_enotsup); - break; - } -} -/* =========================================================================== - * The implemented (ioctl) get requests falls into three grops: - * - * 1) gifconf - Takes no argument other then the request - * 2) gifname - Takes the interface index (integer) as an argument - * 3) other - All other (get) requests takes the interface name (string) - * as the argument. - * - * The functions defined using the macros below are all in the third (3) - * group. - * +/* esock_setopt_tcp_congestion - Level TCP CONGESTION option */ +#if defined(TCP_CONGESTION) +static +ERL_NIF_TERM esock_setopt_tcp_congestion(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1; -/* *** esock_ioctl_gifindex *** */ -#if defined(SIOCGIFINDEX) -#if defined(ESOCK_USE_IFINDEX) -#define IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_ifindex) -#elif defined(ESOCK_USE_INDEX) -#define IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_index) -#else -#define IOCTL_GIFINDEX_FUNC_DECL -#endif -#else -#define IOCTL_GIFINDEX_FUNC_DECL + return esock_setopt_str_opt(env, descP, level, opt, max, eVal); +} #endif -/* *** esock_ioctl_gifflags *** */ -#if defined(SIOCGIFFLAGS) -#define IOCTL_GIFFLAGS_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifflags, SIOCGIFFLAGS, flags, ifreq.ifr_flags) -#else -#define IOCTL_GIFFLAGS_FUNC_DECL -#endif -/* *** esock_ioctl_gifaddr *** */ -#if defined(SIOCGIFADDR) -#define IOCTL_GIFADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifaddr, SIOCGIFADDR, ifraddr, &ifreq.ifr_addr) -#else -#define IOCTL_GIFADDR_FUNC_DECL -#endif +#if defined(HAVE_SCTP) -/* *** esock_ioctl_gifdstaddr *** */ -#if defined(SIOCGIFDSTADDR) -#define IOCTL_GIFDSTADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifdstaddr, SIOCGIFDSTADDR, ifraddr, &ifreq.ifr_dstaddr) -#else -#define IOCTL_GIFDSTADDR_FUNC_DECL -#endif +/* esock_setopt_sctp_associnfo - Level SCTP ASSOCINFO option + */ -/* *** esock_ioctl_gifbrdaddr *** */ -#if defined(SIOCGIFBRDADDR) -#define IOCTL_GIFBRDADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifbrdaddr, SIOCGIFBRDADDR, ifraddr, &ifreq.ifr_broadaddr) -#else -#define IOCTL_GIFBRDADDR_FUNC_DECL -#endif +#if defined(SCTP_ASSOCINFO) +static +ERL_NIF_TERM esock_setopt_sctp_associnfo(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + ERL_NIF_TERM eAssocId, eMaxRxt, eNumPeerDests; + ERL_NIF_TERM ePeerRWND, eLocalRWND, eCookieLife; + struct sctp_assocparams assocParams; + unsigned int ui; -/* *** esock_ioctl_gifnetmask *** */ -#if defined(SIOCGIFNETMASK) -#ifdef __linux__ -#define IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_netmask) -#else -#define IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_addr) -#endif -#else -#define IOCTL_GIFNETMASK_FUNC_DECL -#endif + SSDBG( descP, + ("SOCKET", "esock_setopt_sctp_associnfo -> entry with" + "\r\n eVal: %T" + "\r\n", eVal) ); -/* *** esock_ioctl_gifmtu *** */ -#if defined(SIOCGIFMTU) -#define IOCTL_GIFMTU_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifmtu, SIOCGIFMTU, ivalue, ifreq.ifr_mtu) -#else -#define IOCTL_GIFMTU_FUNC_DECL -#endif + // It must be a map + if (! IS_MAP(env, eVal)) + goto invalid; -/* *** esock_ioctl_gifhwaddr *** */ -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -#define IOCTL_GIFHWADDR_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) -#else -#define IOCTL_GIFHWADDR_FUNC_DECL -#endif + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_associnfo -> extract attributes\r\n") ); -/* *** esock_ioctl_gifmap *** */ -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -#define IOCTL_GIFMAP_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(gifmap, SIOCGIFMAP, ifrmap, &ifreq.ifr_map) -#else -#define IOCTL_GIFMAP_FUNC_DECL -#endif + if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) || + (! GET_MAP_VAL(env, eVal, atom_asocmaxrxt, &eMaxRxt)) || + (! GET_MAP_VAL(env, eVal, atom_number_peer_destinations, + &eNumPeerDests)) || + (! GET_MAP_VAL(env, eVal, atom_peer_rwnd, &ePeerRWND)) || + (! GET_MAP_VAL(env, eVal, atom_local_rwnd, &eLocalRWND)) || + (! GET_MAP_VAL(env, eVal, atom_cookie_life, &eCookieLife))) + goto invalid; -/* *** esock_ioctl_giftxqlen *** */ -#if defined(SIOCGIFTXQLEN) -#define IOCTL_GIFTXQLEN_FUNC_DECL \ - IOCTL_GET_REQUEST_DECL(giftxqlen, SIOCGIFTXQLEN, ivalue, ifreq.ifr_qlen) -#else -#define IOCTL_GIFTXQLEN_FUNC_DECL -#endif - -#define IOCTL_GET_FUNCS \ - IOCTL_GIFINDEX_FUNC_DECL \ - IOCTL_GIFFLAGS_FUNC_DECL \ - IOCTL_GIFADDR_FUNC_DECL \ - IOCTL_GIFDSTADDR_FUNC_DECL \ - IOCTL_GIFBRDADDR_FUNC_DECL \ - IOCTL_GIFNETMASK_FUNC_DECL \ - IOCTL_GIFMTU_FUNC_DECL \ - IOCTL_GIFHWADDR_FUNC_DECL \ - IOCTL_GIFMAP_FUNC_DECL \ - IOCTL_GIFTXQLEN_FUNC_DECL - -#define IOCTL_GET_REQUEST_DECL(OR, R, EF, UV) \ - static \ - ERL_NIF_TERM esock_ioctl_##OR(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename) \ - { \ - ERL_NIF_TERM result; \ - struct ifreq ifreq; \ - char* ifn = NULL; \ - int nlen; \ - \ - SSDBG( descP, ("SOCKET", "esock_ioctl_" #OR " {%d} -> entry with" \ - "\r\n (e)Name: %T" \ - "\r\n", descP->sock, ename) ); \ - \ - if (!esock_decode_string(env, ename, &ifn)) \ - return enif_make_badarg(env); \ - \ - nlen = esock_strnlen(ifn, IFNAMSIZ); \ - \ - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ - sys_memcpy(ifreq.ifr_name, ifn, \ - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ - \ - SSDBG( descP, \ - ("SOCKET", \ - "esock_ioctl_" #OR " {%d} -> try ioctl\r\n", \ - descP->sock) ); \ - \ - if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ - int saveErrno = sock_errno(); \ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failure: " \ - "\r\n reason: %T (%d)" \ - "\r\n", descP->sock, reason, saveErrno) ); \ - \ - result = esock_make_error(env, reason); \ - \ - } else { \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> encode value\r\n", \ - descP->sock) ); \ - result = encode_ioctl_##EF(env, descP, UV); \ - } \ - \ - FREE(ifn); \ - \ - return result; \ - \ - } -IOCTL_GET_FUNCS -#undef IOCTL_GET_FUNCS + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_associnfo -> decode attributes\r\n") ); + if (! decode_sctp_assoc_t(env, eAssocId, &assocParams.sasoc_assoc_id)) + goto invalid; -/* =========================================================================== - * The "rest" of the implemented (ioctl) get requests - * - * These (get) requests could not be 'generated' by the macros above. - */ + /* + * We should really make sure this is ok in erlang (to ensure that + * the values (max-rxt and num-peer-dests) fits in 16-bits). + * The value should be a 16-bit unsigned int... + * Both sasoc_asocmaxrxt and sasoc_number_peer_destinations. + */ -static -ERL_NIF_TERM esock_ioctl_gifconf(ErlNifEnv* env, - ESockDescriptor* descP) -{ - struct ifconf ifc; - int ifc_len = 0; - int buflen = 100 * sizeof(struct ifreq); - char *buf = MALLOC(buflen); - ERL_NIF_TERM result; + if (! GET_UINT(env, eMaxRxt, &ui)) + goto invalid; + assocParams.sasoc_asocmaxrxt = (Uint16) ui; - SSDBG( descP, ("SOCKET", "esock_ioctl_gifconf {%d} -> entry\r\n", descP->sock) ); + if (! GET_UINT(env, eNumPeerDests, &ui)) + goto invalid; + assocParams.sasoc_number_peer_destinations = (Uint16) ui; - for (;;) { - ifc.ifc_len = buflen; - ifc.ifc_buf = buf; - if (ioctl(descP->sock, SIOCGIFCONF, (char *) &ifc) < 0) { - int saveErrno = sock_errno(); + if (! GET_UINT(env, ePeerRWND, &ui)) + goto invalid; + assocParams.sasoc_peer_rwnd = (Uint32) ui; - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifconf {%d} -> failure: " - "\r\n errno: %d (%s)" - "\r\n", descP->sock, saveErrno, erl_errno_id(saveErrno)) ); - - if (saveErrno != EINVAL || ifc_len) { - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - FREE(buf); - return esock_make_error(env, reason); - } - } else { - if (ifc.ifc_len == ifc_len) break; /* buf large enough */ - ifc_len = ifc.ifc_len; - } - buflen += 10 * sizeof(struct ifreq); - buf = (char *) REALLOC(buf, buflen); - } + if (! GET_UINT(env, eLocalRWND, &ui)) + goto invalid; + assocParams.sasoc_local_rwnd = (Uint32) ui; - result = encode_ioctl_ifconf(env, descP, &ifc); + if (! GET_UINT(env, eCookieLife, &ui)) + goto invalid; + assocParams.sasoc_cookie_life = (Uint32) ui; - FREE(ifc.ifc_buf); + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_associnfo -> set associnfo option\r\n") ); - return result; -} + return esock_setopt_level_opt(env, descP, level, opt, + &assocParams, sizeof(assocParams)); + invalid: + return esock_make_invalid(env, esock_atom_value); +} +#endif -#if defined(SIOCGIFNAME) -static -ERL_NIF_TERM esock_ioctl_gifname(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eidx) -{ - ERL_NIF_TERM result; - struct ifreq ifreq; - int index; - - SSDBG( descP, ("SOCKET", "esock_ioctl_gifname {%d} -> entry with" - "\r\n (e)Index: %T" - "\r\n", descP->sock, eidx) ); - - if (!GET_INT(env, eidx, &index)) - return enif_make_badarg(env); - ifreq.ifr_ifindex = index; - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> try ioctl\r\n", descP->sock) ); +/* esock_setopt_sctp_events - Level SCTP EVENTS option + */ - if (ioctl(descP->sock, SIOCGIFNAME, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); +#if defined(SCTP_EVENTS) +static +ERL_NIF_TERM esock_setopt_sctp_events(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) +{ + struct sctp_event_subscribe events; + BOOLEAN_T error; SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> failure: " - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); + ("SOCKET", "esock_setopt_sctp_events {%d} -> entry with" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - result = esock_make_error(env, reason); + // It must be a map + if (! IS_MAP(env, eVal)) + goto invalid; - } else { SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> encode name\r\n", - descP->sock) ); - - result = esock_make_ok2(env, encode_ioctl_ifreq_name(env, ifreq.ifr_name)); - } + ("SOCKET", + "esock_setopt_sctp_events {%d} -> decode attributes\r\n", + descP->sock) ); - SSDBG( descP, - ("SOCKET", "esock_ioctl_gifname {%d} -> done with" - "\r\n result: %T" - "\r\n", - descP->sock, result) ); - - return result; + error = FALSE; -} + events.sctp_data_io_event = + esock_setopt_sctp_event(env, eVal, atom_data_io, &error); + events.sctp_association_event = + esock_setopt_sctp_event(env, eVal, atom_association, &error); + events.sctp_address_event = + esock_setopt_sctp_event(env, eVal, atom_address, &error); + events.sctp_send_failure_event = + esock_setopt_sctp_event(env, eVal, atom_send_failure, &error); + events.sctp_peer_error_event = + esock_setopt_sctp_event(env, eVal, atom_peer_error, &error); + events.sctp_shutdown_event = + esock_setopt_sctp_event(env, eVal, atom_shutdown, &error); + events.sctp_partial_delivery_event = + esock_setopt_sctp_event(env, eVal, atom_partial_delivery, &error); + events.sctp_adaptation_layer_event = + esock_setopt_sctp_event(env, eVal, atom_adaptation_layer, &error); + +#if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_AUTHENTICATION_EVENT) + events.sctp_authentication_event = + esock_setopt_sctp_event(env, eVal, atom_authentication, &error); #endif +#if defined(HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SENDER_DRY_EVENT) + events.sctp_sender_dry_event = + esock_setopt_sctp_event(env, eVal, atom_sender_dry, &error); +#endif + if (error) { + goto invalid; + } else { + ERL_NIF_TERM result; + result = esock_setopt_level_opt(env, descP, level, opt, + &events, sizeof(events)); + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_events {%d} -> set events -> %T\r\n", + descP->sock, result) ); -/* =========================================================================== - * The implemented (ioctl) set requests: - * - */ + return result; + } -/* *** esock_ioctl_sifaddr *** */ -#if defined(SIOCSIFADDR) -#define IOCTL_SIFADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifaddr, SIOCSIFADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_addr)) -#else -#define IOCTL_SIFADDR_FUNC_DECL -#endif + invalid: + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_events {%d} -> invalid\r\n", + descP->sock) ); -/* *** esock_ioctl_sifdstaddr *** */ -#if defined(SIOCSIFDSTADDR) -#define IOCTL_SIFDSTADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifdstaddr, SIOCSIFDSTADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_dstaddr)) -#else -#define IOCTL_SIFDSTADDR_FUNC_DECL -#endif + return esock_make_invalid(env, esock_atom_value); +} -/* *** esock_ioctl_sifbrdaddr *** */ -#if defined(SIOCSIFBRDADDR) -#define IOCTL_SIFBRDADDR_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifbrdaddr, SIOCSIFBRDADDR, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_broadaddr)) -#else -#define IOCTL_SIFBRDADDR_FUNC_DECL -#endif +/* Return the value to make use of automatic type casting. + * Set *error if something goes wrong. + */ +static int esock_setopt_sctp_event(ErlNifEnv *env, + ERL_NIF_TERM eMap, + ERL_NIF_TERM eKey, + BOOLEAN_T *error) +{ + ERL_NIF_TERM eVal; + BOOLEAN_T val; -/* *** esock_ioctl_sifnetmask *** */ -#if defined(SIOCSIFNETMASK) -#ifdef __linux__ -#define IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_netmask)) -#else -#define IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ - ((ESockAddress*) &ifreq.ifr_addr)) -#endif -#else -#define IOCTL_SIFNETMASK_FUNC_DECL -#endif + if (GET_MAP_VAL(env, eMap, eKey, &eVal)) + if (esock_decode_bool(eVal, &val)) + return (int) val; -/* *** esock_ioctl_sifmtu *** - * On some platforms, MTU is an unsigned int - */ -#if defined(SIOCSIFMTU) -#define IOCTL_SIFMTU_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(sifmtu, SIOCSIFMTU, mtu, (int*) &ifreq.ifr_mtu) -#else -#define IOCTL_SIFMTU_FUNC_DECL + *error = TRUE; + return 0; +} #endif -/* *** esock_ioctl_siftxqlen *** */ -#if defined(SIOCSIFTXQLEN) -#define IOCTL_SIFTXQLEN_FUNC_DECL \ - IOCTL_SET_REQUEST_DECL(siftxqlen, SIOCSIFTXQLEN, txqlen, &ifreq.ifr_qlen) -#else -#define IOCTL_SIFTXQLEN_FUNC_DECL -#endif - -#define IOCTL_SET_FUNCS \ - IOCTL_SIFADDR_FUNC_DECL \ - IOCTL_SIFDSTADDR_FUNC_DECL \ - IOCTL_SIFBRDADDR_FUNC_DECL \ - IOCTL_SIFNETMASK_FUNC_DECL \ - IOCTL_SIFMTU_FUNC_DECL \ - IOCTL_SIFTXQLEN_FUNC_DECL - -#define IOCTL_SET_REQUEST_DECL(OR, R, DF, UVP) \ - static \ - ERL_NIF_TERM esock_ioctl_##OR(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM ename, \ - ERL_NIF_TERM evalue) \ - { \ - ERL_NIF_TERM result; \ - struct ifreq ifreq; \ - char* ifn = NULL; \ - int nlen; \ - \ - SSDBG( descP, ("SOCKET", "esock_ioctl_" #OR " {%d} -> entry with" \ - "\r\n (e)Name: %T" \ - "\r\n (e)Value: %T" \ - "\r\n", descP->sock, ename, evalue) ); \ - \ - if (!esock_decode_string(env, ename, &ifn)) { \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failed decode name" \ - "\r\n", descP->sock) ); \ - \ - return enif_make_badarg(env); \ - } \ - \ - if (! decode_ioctl_##DF(env, descP, evalue, UVP)) { \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failed decode addr" \ - "\r\n", descP->sock) ); \ - \ - return esock_make_invalid(env, atom_##DF); \ - } \ - \ - nlen = esock_strnlen(ifn, IFNAMSIZ); \ - \ - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ - sys_memcpy(ifreq.ifr_name, ifn, \ - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> try ioctl\r\n", \ - descP->sock) ); \ - \ - if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ - int saveErrno = sock_errno(); \ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ - \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> failure: " \ - "\r\n reason: %T (%d)" \ - "\r\n", descP->sock, reason, saveErrno) ); \ - \ - result = esock_make_error(env, reason); \ - \ - } else { \ - SSDBG( descP, \ - ("SOCKET", "esock_ioctl_" #OR " {%d} -> " \ - "addr successfully set\r\n", \ - descP->sock) ); \ - result = esock_atom_ok; \ - } \ - \ - FREE(ifn); \ - \ - return result; \ - \ - } - -IOCTL_SET_FUNCS -#undef IOCTL_SET_FUNCS -/* =========================================================================== - * The "rest" of the implemented (ioctl) set requests - * - * These (set) requests could not be 'generated' by the macros above. +/* esock_setopt_sctp_initmsg - Level SCTP INITMSG option */ -#if defined(SIOCSIFFLAGS) +#if defined(SCTP_INITMSG) static -ERL_NIF_TERM esock_ioctl_sifflags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ename, - ERL_NIF_TERM eflags) +ERL_NIF_TERM esock_setopt_sctp_initmsg(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - struct ifreq ifreq; - char* ifn = NULL; - int nlen; - - SSDBG( descP, ("SOCKET", "esock_ioctl_sifflags {%d} -> entry with" - "\r\n (e)Name: %T" - "\r\n (e)Flags: %T" - "\r\n", descP->sock, ename, eflags) ); - - if (!esock_decode_string(env, ename, &ifn)) { + ERL_NIF_TERM eNumOut, eMaxIn, eMaxAttempts, eMaxInitTO; + struct sctp_initmsg initMsg; + unsigned int tmp; SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> failed decode name" - "\r\n", descP->sock) ); - - return enif_make_badarg(env); - } - - // Make sure the length of the string is valid! - nlen = esock_strnlen(ifn, IFNAMSIZ); - - sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); // Just in case - sys_memcpy(ifreq.ifr_name, ifn, - (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> try (get) ioctl\r\n", - descP->sock) ); + ("SOCKET", "esock_setopt_sctp_initmsg -> entry with" + "\r\n eVal: %T" + "\r\n", eVal) ); - if (ioctl(descP->sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + // It must be a map + if (! IS_MAP(env, eVal)) + goto invalid; SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> " - "failure: failed reading *current* flags" - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); - - result = esock_make_error(env, reason); + ("SOCKET", + "esock_setopt_sctp_initmsg -> extract attributes\r\n") ); - } else { + if ((! GET_MAP_VAL(env, eVal, atom_num_outstreams, &eNumOut)) || + (! GET_MAP_VAL(env, eVal, atom_max_instreams, &eMaxIn)) || + (! GET_MAP_VAL(env, eVal, atom_max_attempts, &eMaxAttempts)) || + (! GET_MAP_VAL(env, eVal, atom_max_init_timeo, &eMaxInitTO))) + goto invalid; SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> (local) update flags\r\n", - descP->sock) ); - - if (decode_ioctl_flags(env, descP, eflags, &ifreq.ifr_flags)) { - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> try (set) ioctl\r\n", - descP->sock) ); - - if (ioctl(descP->sock, SIOCSIFFLAGS, (char *) &ifreq) < 0) { - int saveErrno = sock_errno(); - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> failure: " - "\r\n reason: %T (%d)" - "\r\n", descP->sock, reason, saveErrno) ); + ("SOCKET", + "esock_setopt_sctp_initmsg -> decode attributes\r\n") ); - result = esock_make_error(env, reason); + if (! GET_UINT(env, eNumOut, &tmp)) + goto invalid; + initMsg.sinit_num_ostreams = (Uint16) tmp; - } else { - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> " - "updated flags successfully set\r\n", - descP->sock) ); - result = esock_atom_ok; - } + if (! GET_UINT(env, eMaxIn, &tmp)) + goto invalid; + initMsg.sinit_max_instreams = (Uint16) tmp; - /* We know that if esock_decode_string is successful, - * we have "some" form of string, and therefor memory - * has been allocated (and need to be freed)... */ - FREE(ifn); + if (! GET_UINT(env, eMaxAttempts, &tmp)) + goto invalid; + initMsg.sinit_max_attempts = (Uint16) tmp; - } else { - result = enif_make_badarg(env); - } - } + if (! GET_UINT(env, eMaxInitTO, &tmp)) + goto invalid; + initMsg.sinit_max_init_timeo = (Uint16) tmp; - SSDBG( descP, - ("SOCKET", "esock_ioctl_sifflags {%d} -> done with result: " - "\r\n %T" - "\r\n", - descP->sock, result) ); + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_initmsg -> set initmsg option\r\n") ); - return result; + return esock_setopt_level_opt(env, descP, level, opt, + &initMsg, sizeof(initMsg)); + invalid: + return esock_make_invalid(env, esock_atom_value); } #endif -/* =========================================================================== - * ioctl utility functions - * +/* esock_setopt_sctp_rtoinfo - Level SCTP RTOINFO option */ +#if defined(SCTP_RTOINFO) static -ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifconf* ifcP) +ERL_NIF_TERM esock_setopt_sctp_rtoinfo(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM result; - unsigned int len = ((ifcP == NULL) ? 0 : - (ifcP->ifc_len / sizeof(struct ifreq))); - - SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> entry (when len = %d)\r\n", len) ); - - if (len > 0) { - ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); - unsigned int i = 0; - struct ifreq* p = ifcP->ifc_req; - - for (i = 0 ; i < len ; i++) { - SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> encode ifreq entry %d\r\n", i) ); - array[i] = encode_ioctl_ifconf_ifreq(env, descP, &p[i]); - } + ERL_NIF_TERM eAssocId, eInitial, eMax, eMin; + struct sctp_rtoinfo rtoInfo; SSDBG( descP, - ("SOCKET", "encode_ioctl_ifconf -> all entries encoded\r\n", i) ); - - result = esock_make_ok2(env, MKLA(env, array, len)); - FREE(array); - - } else { - - result = esock_make_ok2(env, MKEL(env)); - - } + ("SOCKET", "esock_setopt_sctp_rtoinfo -> entry with" + "\r\n eVal: %T" + "\r\n", eVal) ); - return result; -} + // It must be a map + if (! IS_MAP(env, eVal)) + goto invalid; + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_rtoinfo -> extract attributes\r\n") ); -#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) -static -ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifmap* mapP) -{ - ERL_NIF_TERM mapKeys[] = {atom_mem_start, - atom_mem_end, - atom_base_addr, - atom_irq, - atom_dma, - atom_port}; - ERL_NIF_TERM mapVals[] = {MKUL(env, mapP->mem_start), - MKUL(env, mapP->mem_end), - MKUI(env, mapP->base_addr), - MKUI(env, mapP->irq), - MKUI(env, mapP->dma), - MKUI(env, mapP->port)}; - unsigned int numMapKeys = NUM(mapKeys); - unsigned int numMapVals = NUM(mapVals); - ERL_NIF_TERM emap; - - ESOCK_ASSERT( numMapVals == numMapKeys ); - ESOCK_ASSERT( MKMA(env, mapKeys, mapVals, numMapKeys, &emap) ); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifrmap -> done with" - "\r\n Map: %T" - "\r\n", emap) ); - - return esock_make_ok2(env, emap);; -} -#endif + if ((! GET_MAP_VAL(env, eVal, atom_assoc_id, &eAssocId)) || + (! GET_MAP_VAL(env, eVal, atom_initial, &eInitial)) || + (! GET_MAP_VAL(env, eVal, atom_max, &eMax)) || + (! GET_MAP_VAL(env, eVal, atom_min, &eMin))) + goto invalid; + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_rtoinfo -> decode attributes\r\n") ); -#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) -static -ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP) -{ - ERL_NIF_TERM eaddr; - SOCKLEN_T sz = sizeof(struct sockaddr); + if (! decode_sctp_assoc_t(env, eAssocId, &rtoInfo.srto_assoc_id)) + goto invalid; - esock_encode_hwsockaddr(env, addrP, sz, &eaddr); + if ((! GET_UINT(env, eInitial, &rtoInfo.srto_initial)) || + (! GET_UINT(env, eMax, &rtoInfo.srto_max)) || + (! GET_UINT(env, eMin, &rtoInfo.srto_min))) + goto invalid; + + SSDBG( descP, + ("SOCKET", + "esock_setopt_sctp_rtoinfo -> set associnfo option\r\n") ); - SSDBG( descP, ("SOCKET", "encode_ioctl_ifraddr -> done with" - "\r\n Sock Addr: %T" - "\r\n", eaddr) ); + return esock_setopt_level_opt(env, descP, level, opt, + &rtoInfo, sizeof(rtoInfo)); - return esock_make_ok2(env, eaddr);; + invalid: + return esock_make_invalid(env, esock_atom_value); } #endif +#endif // defined(HAVE_SCTP) -static -ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, - ESockDescriptor* descP, - struct sockaddr* addrP) -{ - ERL_NIF_TERM eaddr; - unsigned int sz = sizeof(ESockAddress); - - esock_encode_sockaddr(env, (ESockAddress*) addrP, sz, &eaddr); - SSDBG( descP, ("SOCKET", "encode_ioctl_ifraddr -> done with" - "\r\n Sock Addr: %T" - "\r\n", eaddr) ); - return esock_make_ok2(env, eaddr);; -} +/* esock_setopt_bool_opt - set an option that has an (integer) bool value + */ static -ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - short flags) +ERL_NIF_TERM esock_setopt_bool_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - int i, flag, num = NUM(ioctl_flags); - ERL_NIF_TERM eflags, eflag; - SocketTArray ta = TARRAY_CREATE(20); // Just to be on the safe side - - if (flags == 0) { - eflags = MKEL(env); - } else { - for (i = 0; (i < num) && (flags != 0); i++) { - flag = ioctl_flags[i].flag; - if ((flag != 0) && ((flags & flag) == flag)) { - eflag = *(ioctl_flags[i].name); - flags &= ~flag; - - SSDBG( descP, ("SOCKET", "encode_ioctl_flags {%d} -> " - "\r\n i: %d" - "\r\n found flag: %T (%d)" - "\r\n remaining flags: %d" - "\r\n", descP->sock, i, eflag, flag, flags) ); - - TARRAY_ADD(ta, eflag); - } - } - if (flags != 0) { - - SSDBG( descP, ("SOCKET", "encode_ioctl_flags {%d} -> unknown flag(s): %d" - "\r\n", descP->sock, flags) ); + BOOLEAN_T val; + int ival; - TARRAY_ADD(ta, MKI(env, flags)); - } + if (! esock_decode_bool(eVal, &val)) + return esock_make_invalid(env, esock_atom_value); - TARRAY_TOLIST(ta, env, &eflags); - } - + ival = (val) ? 1 : 0; + return esock_setopt_level_opt(env, descP, level, opt, + &ival, sizeof(ival)); +} - SSDBG( descP, ("SOCKET", "encode_ioctl_flags -> done with" - "\r\n Flags: %T (%d)" - "\r\n", eflags, flags) ); - return esock_make_ok2(env, eflags);; -} +/* esock_setopt_int_opt - set an option that has an integer value + */ static -BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eaddr, - ESockAddress* addr) +ERL_NIF_TERM esock_setopt_int_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - SOCKLEN_T addrLen; - BOOLEAN_T result; + ERL_NIF_TERM result; + int val; - result = esock_decode_sockaddr(env, eaddr, (ESockAddress*) addr, &addrLen); + if (GET_INT(env, eVal, &val)) { + result = + esock_setopt_level_opt(env, descP, level, opt, + &val, sizeof(val)); + } else { + result = esock_make_invalid(env, esock_atom_value); + } + return result; +} - VOID(addrLen); - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_sockaddr {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); - return result; -} - +/* esock_setopt_str_opt - set an option that has an string value + */ +#if defined(USE_SETOPT_STR_OPT) static -BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM emtu, - int* mtu) +ERL_NIF_TERM esock_setopt_str_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + int max, + ERL_NIF_TERM eVal) { - BOOLEAN_T result; + ERL_NIF_TERM result; + int optLen; + char* val = MALLOC(max); - if (! GET_INT(env, emtu, mtu)) { - result = FALSE; - } else { - result = TRUE; - } + ESOCK_ASSERT( val != NULL ); - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_mtu {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); + if ((optLen = GET_STR(env, eVal, val, max)) > 0) { + optLen--; - return result; -} - + result = + esock_setopt_level_opt(env, descP, level, opt, + val, optLen); + } else { + result = esock_make_invalid(env, esock_atom_value); + } -#if defined(SIOCSIFTXQLEN) -static -BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM etxqlen, - int* txqlen) -{ - return decode_ioctl_ivalue(env, descP, etxqlen, txqlen); + FREE(val); + + return result; } #endif -/* All uses of the function should be added. For instance: - * #if defined(SIOCGIFTXQLEN) || defined(FOOBAR) || defined(YXA) - */ -#if defined(SIOCGIFTXQLEN) -static -BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eivalue, - int* ivalue) -{ - BOOLEAN_T result; - - if (! GET_INT(env, eivalue, ivalue)) { - result = FALSE; - } else { - result = TRUE; - } - SSDBG( descP, - ("SOCKET", "esock_decode_ioctl_ivalue {%d} -> decode result: %s" - "\r\n", descP->sock, B2S(result)) ); - return result; -} -#endif - +/* esock_setopt_timeval_opt - set an option that has an (timeval) bool value + */ +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ + && defined(ESOCK_USE_RCVSNDTIMEO) static -BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eflags, - short* flags) +ERL_NIF_TERM esock_setopt_timeval_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal) { - ERL_NIF_TERM key, value; - ErlNifMapIterator iter; - int tmpFlags = (int) *flags; // Current value - int flag; - - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> entry with" - "\r\n flags: %d" - "\r\n", - descP->sock, tmpFlags) ); - - enif_map_iterator_create(env, eflags, &iter, ERL_NIF_MAP_ITERATOR_FIRST); - - while (enif_map_iterator_get_pair(env, &iter, &key, &value)) { + ERL_NIF_TERM result; + struct timeval timeVal; - /* Convert key (eflag) to int */ - if (! GET_INT(env, key, &flag)) { - enif_map_iterator_destroy(env, &iter); - return FALSE; - } + SSDBG( descP, + ("SOCKET", "esock_setopt_timeval_opt -> entry with" + "\r\n eVal: %T" + "\r\n", eVal) ); - // Update flag - if (COMPARE(value, esock_atom_true) == 0) { - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> set %d\r\n", - descP->sock, flag) ); - tmpFlags |= flag; - } else { - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> reset %d\r\n", - descP->sock, flag) ); - tmpFlags &= ~flag; - } + if (! esock_decode_timeval(env, eVal, &timeVal)) + return esock_make_invalid(env, esock_atom_value); - enif_map_iterator_next(env, &iter); - } + SSDBG( descP, + ("SOCKET", "esock_setopt_timeval_opt -> set timeval option\r\n") ); - enif_map_iterator_destroy(env, &iter); + result = + esock_setopt_level_opt(env, descP, level, opt, + &timeVal, sizeof(timeVal)); - SSDBG( descP, - ("SOCKET", "decode_ioctl_flags {%d} -> done with" - "\r\n (new) flags: %d" - "\r\n", - descP->sock, tmpFlags) ); + SSDBG( descP, + ("SOCKET", "esock_setopt_timeval_opt -> done with" + "\r\n result: %T" + "\r\n", result) ); - *flags = (short) tmpFlags; + return result; - return TRUE; } +#endif -static -ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, - ESockDescriptor* descP, - int ivalue) +static ERL_NIF_TERM esock_setopt_level_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + void* optVal, + socklen_t optLen) { - ERL_NIF_TERM eivalue = MKI(env, ivalue); + if (socket_setopt(descP->sock, level, opt, optVal, optLen)) + return esock_make_error_errno(env, sock_errno()); + else + return esock_atom_ok; +} - SSDBG( descP, ("SOCKET", "encode_ioctl_ivalue -> done with" - "\r\n iValue: %T (%d)" - "\r\n", eivalue, ivalue) ); - return esock_make_ok2(env, eivalue);; -} +/* +++ socket_setopt +++ + * + * + * The original code here had problems that possibly + * only occur if you abuse it for non-INET sockets, but anyway: + * a) If the getsockopt for SO_PRIORITY or IP_TOS failed, the actual + * requested setsockopt was never even attempted. + * b) If {get,set}sockopt for one of IP_TOS and SO_PRIORITY failed, + * but ditto for the other worked and that was actually the requested + * option, failure was still reported to erlang. + * + * + * + * The relations between SO_PRIORITY, TOS and other options + * is not what you (or at least I) would expect...: + * If TOS is set after priority, priority is zeroed. + * If any other option is set after tos, tos might be zeroed. + * Therefore, save tos and priority. If something else is set, + * restore both after setting, if tos is set, restore only + * prio and if prio is set restore none... All to keep the + * user feeling socket options are independent. + * + */ static -ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, - ESockDescriptor* descP, - struct ifreq* ifrP) +int socket_setopt(int sock, int level, int opt, + const void* optVal, const socklen_t optLen) { - ERL_NIF_TERM ename, eaddr; - - ESOCK_ASSERT( ifrP != NULL ); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> encode name\r\n") ); - ename = encode_ioctl_ifreq_name(env, ifrP->ifr_name); - - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> encode sockaddr\r\n") ); - eaddr = encode_ioctl_ifreq_sockaddr(env, &ifrP->ifr_addr); + int res; - SSDBG( descP, ("SOCKET", "encode_ioctl_ifconf_ifreq -> make ifreq map with" - "\r\n Name: %T" - "\r\n Sock Addr: %T" - "\r\n", ename, eaddr) ); - return make_ifreq(env, ename, esock_atom_addr, eaddr); -} +#if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY) + int tmpIValPRIO = 0; + int tmpIValTOS = 0; + int resPRIO; + int resTOS; + SOCKOPTLEN_T tmpArgSzPRIO = sizeof(tmpIValPRIO); + SOCKOPTLEN_T tmpArgSzTOS = sizeof(tmpIValTOS); -static -ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, - char* name) -{ - return ((name == NULL) ? esock_atom_undefined : MKS(env, name)); -} + resPRIO = sock_getopt(sock, SOL_SOCKET, SO_PRIORITY, + &tmpIValPRIO, &tmpArgSzPRIO); + resTOS = sock_getopt(sock, SOL_IP, IP_TOS, + &tmpIValTOS, &tmpArgSzTOS); -static -ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, struct sockaddr* sa) -{ - ERL_NIF_TERM esa; + res = sock_setopt(sock, level, opt, optVal, optLen); + if (res == 0) { - if (sa != NULL) { - unsigned int sz = sizeof(ESockAddress); + /* Ok, now we *maybe* need to "maybe" restore PRIO and TOS... + * maybe, possibly, ... + */ - esock_encode_sockaddr(env, (ESockAddress*) sa, sz, &esa); - - } else { - esa = esock_atom_undefined; - } + if (opt != SO_PRIORITY) { + if ((opt != IP_TOS) && (resTOS == 0)) { + resTOS = sock_setopt(sock, SOL_IP, IP_TOS, + (void *) &tmpIValTOS, + tmpArgSzTOS); + res = resTOS; + } + if ((res == 0) && (resPRIO == 0)) { + resPRIO = sock_setopt(sock, SOL_SOCKET, SO_PRIORITY, + &tmpIValPRIO, + tmpArgSzPRIO); - return esa; -} + /* Some kernels set a SO_PRIORITY by default + * that you are not permitted to reset, + * silently ignore this error condition. + */ -/* The ifreq structure *always* contain a name - * and *one* other element. The second element - * depend on the ioctl request. - */ -static -ERL_NIF_TERM make_ifreq(ErlNifEnv* env, - ERL_NIF_TERM name, - ERL_NIF_TERM key2, - ERL_NIF_TERM val2) -{ - ERL_NIF_TERM keys[2]; - ERL_NIF_TERM vals[2]; - ERL_NIF_TERM res; + if ((resPRIO != 0) && (sock_errno() == EPERM)) { + res = 0; + } else { + res = resPRIO; + } + } + } + } - keys[0] = esock_atom_name; - vals[0] = name; +#else - keys[1] = key2; - vals[1] = val2; + res = sock_setopt(sock, level, opt, optVal, optLen); - ESOCK_ASSERT( MKMA(env, keys, vals, NUM(keys), &res) ); +#endif - return res; + return res; } - -#endif // #ifndef __WIN32__ /* ---------------------------------------------------------------------- - * nif_cancel + * nif_getopt * * Description: - * Cancel a previous select! + * Get socket option. + * Its possible to use a ValueSpec to select + * how the value should be decoded. * * Arguments: - * Socket (ref) - Points to the socket descriptor. - * Operation (atom) - What kind of operation (accept, send, ...) is to be cancelled - * Ref (ref) - Unique id for the operation + * Socket (ref) - Points to the socket descriptor. + * Level (int) - Protocol level, encoded or native + * Opt (int) - Option, encoded or native + * ValueSpec (term) - How to decode the value [optional] */ + static -ERL_NIF_TERM nif_cancel(ErlNifEnv* env, +ERL_NIF_TERM nif_getopt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { -#ifdef __WIN32__ - return enif_raise_exception(env, MKA(env, "notsup")); -#else ESockDescriptor* descP; - ERL_NIF_TERM op, sockRef, opRef; - - ESOCK_ASSERT( argc == 3 ); + ERL_NIF_TERM esock, elevel, eopt, evspec; + int level, opt; - SGDBG( ("SOCKET", "nif_cancel -> entry with argc: %d\r\n", argc) ); + ESOCK_ASSERT( (argc == 3) || (argc == 4) ); - /* Extract arguments and perform preliminary validation */ + esock = argv[0]; + elevel = argv[1]; + eopt = argv[2]; + evspec = ((argc == 4) ? argv[3] : esock_atom_undefined); - sockRef = argv[0]; - if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + SGDBG( ("SOCKET", + "nif_getopt -> entry with argc: %d" + "\r\n esock: %T" + "\r\n elevel: %T" + "\r\n eopt: %T" + "\r\n evspec: %T" + "\r\n", argc, esock, elevel, eopt, evspec) ); + + if (! ESOCK_GET_RESOURCE(env, esock, (void**) &descP)) { + SGDBG( ("SOCKET", + "nif_getopt -> failed initial args check - sock\r\n") ); return enif_make_badarg(env); } - op = argv[1]; - opRef = argv[2]; - if ((! IS_ATOM(env, op)) || - (! enif_is_ref(env, opRef))) { - return enif_make_badarg(env); + + if (! GET_INT(env, eopt, &opt)) { + SSDBG( descP, + ("SOCKET", + "nif_getopt -> failed initial args check - opt\r\n") ); + if (! IS_INTEGER(env, eopt)) + return enif_make_badarg(env); + else + return esock_make_error_integer_range(env, eopt); } - return esock_cancel(env, descP, op, sockRef, opRef); + if ((COMPARE(elevel, atom_otp) == 0) && + (argc == 3)) { + return ESOCK_IO_GETOPT_OTP(env, descP, opt) ; + } + + if (esock_decode_level(env, elevel, &level)) { + if (argc == 4) { + return ESOCK_IO_GETOPT_NATIVE(env, descP, level, opt, evspec); + } else { + return ESOCK_IO_GETOPT(env, descP, level, opt); + } + } + + SGDBG( ("SOCKET", "nif_getopt -> failed args check\r\n") ); + if (IS_INTEGER(env, elevel)) + return esock_make_error_integer_range(env, elevel); + else + return enif_make_badarg(env); -#endif // #ifdef __WIN32__ #else } -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM op, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) -{ - int cmp; - /* - * - * Do we really need all these variants? Should it not be enough with: - * - * connect | accept | send | recv - * - * - */ +/* esock_getopt_otp - Handle OTP (level) options + */ - /* Hand crafted binary search */ - if ((cmp = COMPARE(op, esock_atom_recvmsg)) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); - if (cmp < 0) { - if ((cmp = COMPARE(op, esock_atom_recv)) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); - if (cmp < 0) { - if (COMPARE(op, esock_atom_connect) == 0) - return esock_cancel_connect(env, descP, opRef); - if (COMPARE(op, esock_atom_accept) == 0) - return esock_cancel_accept(env, descP, sockRef, opRef); - } else { - if (COMPARE(op, esock_atom_recvfrom) == 0) - return esock_cancel_recv(env, descP, sockRef, opRef); - } - } else { - if ((cmp = COMPARE(op, esock_atom_sendmsg)) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); - if (cmp < 0) { - if (COMPARE(op, esock_atom_send) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); - if (COMPARE(op, atom_sendfile) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); - } else { - if (COMPARE(op, esock_atom_sendto) == 0) - return esock_cancel_send(env, descP, sockRef, opRef); - } - } +static +ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt) +{ + ERL_NIF_TERM result; - { - ERL_NIF_TERM result; - const char *reason; + SSDBG( descP, + ("SOCKET", "esock_getopt_otp -> entry with" + "\r\n eOpt: %d" + "\r\n", eOpt) ); + switch (eOpt) { + case ESOCK_OPT_OTP_DEBUG: MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - - if (! IS_OPEN(descP->readState)) { - result = esock_make_error(env, atom_closed); - reason = "closed"; - } else { - result = enif_make_badarg(env); - reason = "badarg"; - } + result = esock_getopt_otp_debug(env, descP); + MUNLOCK(descP->readMtx); + break; - SSDBG( descP, - ("SOCKET", "esock_cancel(%T), {%d,0x%X} -> %s" - "\r\n", - sockRef, descP->sock, - descP->readState | descP->writeState, reason) ); + case ESOCK_OPT_OTP_IOW: + MLOCK(descP->readMtx); + result = esock_getopt_otp_iow(env, descP); + MUNLOCK(descP->readMtx); + break; - MUNLOCK(descP->writeMtx); + case ESOCK_OPT_OTP_CTRL_PROC: + MLOCK(descP->readMtx); + result = esock_getopt_otp_ctrl_proc(env, descP); MUNLOCK(descP->readMtx); + break; - return result; - } -} -#endif // #ifndef __WIN32__ + case ESOCK_OPT_OTP_RCVBUF: + MLOCK(descP->readMtx); + result = esock_getopt_otp_rcvbuf(env, descP); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_RCVCTRLBUF: + MLOCK(descP->readMtx); + result = esock_getopt_otp_rcvctrlbuf(env, descP); + MUNLOCK(descP->readMtx); + break; + case ESOCK_OPT_OTP_SNDCTRLBUF: + MLOCK(descP->writeMtx); + result = esock_getopt_otp_sndctrlbuf(env, descP); + MUNLOCK(descP->writeMtx); + break; -/* *** esock_cancel_connect *** - * - * - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_connect(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef) -{ - ERL_NIF_TERM res; - ErlNifPid self; + case ESOCK_OPT_OTP_FD: + MLOCK(descP->readMtx); + result = esock_getopt_otp_fd(env, descP); + MUNLOCK(descP->readMtx); + break; - ESOCK_ASSERT( enif_self(env, &self) != NULL ); + case ESOCK_OPT_OTP_META: + MLOCK(descP->writeMtx); + result = esock_getopt_otp_meta(env, descP); + MUNLOCK(descP->writeMtx); + break; - MLOCK(descP->writeMtx); + case ESOCK_OPT_OTP_USE_REGISTRY: + MLOCK(descP->readMtx); + result = esock_getopt_otp_use_registry(env, descP); + MUNLOCK(descP->readMtx); + break; - if (! IS_OPEN(descP->writeState)) { + /* *** INTERNAL *** */ + case ESOCK_OPT_OTP_DOMAIN: + MLOCK(descP->readMtx); + result = esock_getopt_otp_domain(env, descP); + MUNLOCK(descP->readMtx); + break; - res = esock_make_error(env, atom_closed); +#if 0 + case ESOCK_OPT_OTP_TYPE: + MLOCK(descP->readMtx); + result = esock_getopt_otp_type(env, descP); + MUNLOCK(descP->readMtx); + break; - } else if ((descP->connectorP == NULL) || - (COMPARE_PIDS(&self, &descP->connector.pid) != 0) || - (COMPARE(opRef, descP->connector.ref) != 0)) { + case ESOCK_OPT_OTP_PROTOCOL: + MLOCK(descP->readMtx); + result = esock_getopt_otp_protocol(env, descP); + MUNLOCK(descP->readMtx); + break; - res = esock_atom_not_found; + case ESOCK_OPT_OTP_DTP: + MLOCK(descP->readMtx); + result = esock_getopt_otp_dtp(env, descP); + MUNLOCK(descP->readMtx); + break; +#endif - } else { + default: + MLOCK(descP->readMtx); + SSDBG( descP, + ("SOCKET", "esock_getopt_otp {%d} -> invalid with" + "\r\n eOpt: %d" + "\r\n", descP->sock, eOpt) ); + MUNLOCK(descP->readMtx); - res = esock_cancel_write_select(env, descP, opRef); - requestor_release("esock_cancel_connect", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; + /* This is an internal error - prim_inet gave us junk */ + result = + esock_raise_invalid(env, + MKT2(env, + atom_otp_socket_option, + MKI(env, eOpt))); + break; } - SSDBG( descP, - ("SOCKET", - "esock_cancel_connect {%d,0x%X} ->" - "\r\n opRef: %T" - "\r\n res: %T" - "\r\n", - descP->sock, descP->writeState, - opRef, res) ); - - MUNLOCK(descP->writeMtx); - - return res; + return result; } -#endif // #ifndef __WIN32__ -/* *** esock_cancel_accept *** - * - * We have two different cases: - * *) Its the current acceptor - * Cancel the select! - * We need to activate one of the waiting acceptors. - * *) Its one of the acceptors ("waiting") in the queue - * Simply remove the acceptor from the queue. - * +/* esock_getopt_otp_debug - Handle the OTP (level) debug option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_accept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) +ERL_NIF_TERM esock_getopt_otp_debug(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_accept(%T), {%d,0x%X} ->" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->readState, - opRef, - ((descP->currentAcceptorP == NULL) - ? "without acceptor" : "with acceptor")) ); + ERL_NIF_TERM eVal; if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - res = esock_make_error(env, atom_closed); + eVal = esock_encode_bool(descP->dbg); - } else if (descP->currentAcceptorP == NULL) { + return esock_make_ok2(env, eVal); +} - res = esock_atom_not_found; - } else { - ErlNifPid self; +/* esock_getopt_otp_iow - Handle the OTP (level) iow option + */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); +static +ERL_NIF_TERM esock_getopt_otp_iow(ErlNifEnv* env, + ESockDescriptor* descP) +{ + ERL_NIF_TERM eVal; - if (COMPARE_PIDS(&self, &descP->currentAcceptor.pid) == 0) { - if (COMPARE(opRef, descP->currentAcceptor.ref) == 0) - res = esock_cancel_accept_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_accept_waiting(env, descP, opRef, &self); - } + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_iow {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - SSDBG( descP, - ("SOCKET", "esock_cancel_accept(%T) -> done with result:" - "\r\n %T" - "\r\n", sockRef, res) ); + eVal = esock_encode_bool(descP->iow); - MUNLOCK(descP->readMtx); + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_iow {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - return res; + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* The current acceptor process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the acceptor queue). + +/* esock_getopt_otp_ctrl_proc - Handle the OTP (level) controlling_process option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM esock_getopt_otp_ctrl_proc(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_accept_current -> current acceptor", - env, descP, &descP->currentAcceptor.mon) == 0); - res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_accept_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); - - if (!activate_next_acceptor(env, descP, sockRef)) { + ERL_NIF_TERM eVal; + if (! IS_OPEN(descP->readState)) { SSDBG( descP, ("SOCKET", - "esock_cancel_accept_current(%T) {%d} -> " - "no more acceptors\r\n", - sockRef, descP->sock) ); + "esock_getopt_otp_ctrl_proc {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - descP->readState &= ~ESOCK_STATE_ACCEPTING; + eVal = MKPID(env, &descP->ctrlPid); - descP->currentAcceptorP = NULL; - } + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_ctrlProc {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - return res; + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* These processes have not performed a select, so we can simply - * remove them from the acceptor queue. +/* esock_getopt_otp_rcvbuf - Handle the OTP (level) rcvbuf option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_accept_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) +ERL_NIF_TERM esock_getopt_otp_rcvbuf(ErlNifEnv* env, + ESockDescriptor* descP) { - /* unqueue request from (acceptor) queue */ + ERL_NIF_TERM eVal; - if (acceptor_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_rcvbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } + +#ifdef __WIN32__ + eVal = MKUL(env, (unsigned long) descP->rBufSz); +#else + if (descP->rNum == 0) { + eVal = MKUL(env, (unsigned long) descP->rBufSz); } else { - return esock_atom_not_found; + eVal = MKT2(env, + MKI(env, descP->rNum), + MKUL(env, (unsigned long) descP->rBufSz)); } +#endif + + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_rcvbuf {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); + + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* *** esock_cancel_send *** - * - * Cancel a send operation. - * Its either the current writer or one of the waiting writers. +/* esock_getopt_otp_rcvctrlbuf - Handle the OTP (level) rcvctrlbuf option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_send(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) +ERL_NIF_TERM esock_getopt_otp_rcvctrlbuf(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; + ERL_NIF_TERM eVal; - MLOCK(descP->writeMtx); + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", + "esock_getopt_otp_rcvctrlbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); + } - SSDBG( descP, - ("SOCKET", - "esock_cancel_send(%T), {%d,0x%X} -> entry with" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->writeState, - opRef, - ((descP->currentWriterP == NULL) - ? "without writer" : "with writer")) ); + eVal = MKUL(env, (unsigned long) descP->rCtrlSz); - if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_rcvctrlbuf {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - res = esock_make_error(env, atom_closed); + return esock_make_ok2(env, eVal); +} - } else if (descP->currentWriterP == NULL) { - res = esock_atom_not_found; - } else { - ErlNifPid self; +/* esock_getopt_otp_sndctrlbuf - Handle the OTP (level) sndctrlbuf option + */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); +static +ERL_NIF_TERM esock_getopt_otp_sndctrlbuf(ErlNifEnv* env, + ESockDescriptor* descP) +{ + ERL_NIF_TERM eVal; - if (COMPARE_PIDS(&self, &descP->currentWriter.pid) == 0) { - if (COMPARE(opRef, descP->currentWriter.ref) == 0) - res = esock_cancel_send_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_send_waiting(env, descP, opRef, &self); - } + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", + "esock_getopt_otp_sndctrlbuf {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - SSDBG( descP, - ("SOCKET", "esock_cancel_send(%T) {%d} -> done with result:" - "\r\n %T" - "\r\n", sockRef, descP->sock, res) ); + eVal = MKUL(env, (unsigned long) descP->wCtrlSz); - MUNLOCK(descP->writeMtx); + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_sndctrlbuf {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); - return res; + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* The current writer process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the writer queue). +/* esock_getopt_otp_fd - Handle the OTP (level) fd option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_send_current -> current writer", - env, descP, &descP->currentWriter.mon) == 0); - res = esock_cancel_write_select(env, descP, descP->currentWriter.ref); - - SSDBG( descP, - ("SOCKET", "esock_cancel_send_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); + ERL_NIF_TERM eVal; - if (!activate_next_writer(env, descP, sockRef)) { + if (! IS_OPEN(descP->readState)) { SSDBG( descP, - ("SOCKET", - "esock_cancel_send_current(%T) {%d} -> no more writers" - "\r\n", sockRef, descP->sock) ); - - descP->currentWriterP = NULL; + ("SOCKET", "esock_getopt_otp_debug {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - return res; + eVal = MKI(env, descP->sock); + + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_fd {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); + + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* These processes have not performed a select, so we can simply - * remove them from the writer queue. + +/* esock_getopt_otp_meta - Handle the OTP (level) meta option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_send_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) +ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env, + ESockDescriptor* descP) { - /* unqueue request from (writer) queue */ + ERL_NIF_TERM eVal; - if (writer_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; - } else { - return esock_atom_not_found; + if (! IS_OPEN(descP->writeState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_meta {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } + + eVal = CP_TERM(env, descP->meta.ref); + + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_meta {%d} ->" + "\r\n eVal: %T" + "\r\n", descP->sock, eVal) ); + + return esock_make_ok2(env, eVal); } -#endif // #ifndef __WIN32__ -/* *** esock_cancel_recv *** - * - * Cancel a read operation. - * Its either the current reader or one of the waiting readers. +/* esock_getopt_otp_use_registry - Handle the OTP (level) use_registry option */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_recv(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM opRef) +ERL_NIF_TERM esock_getopt_otp_use_registry(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; - - MLOCK(descP->readMtx); - - SSDBG( descP, - ("SOCKET", - "esock_cancel_recv(%T), {%d,0x%X} -> entry with" - "\r\n opRef: %T" - "\r\n %s" - "\r\n", - sockRef, descP->sock, descP->readState, - opRef, - ((descP->currentReaderP == NULL) - ? "without reader" : "with reader")) ); - - if (! IS_OPEN(descP->readState)) { + ERL_NIF_TERM eVal = esock_encode_bool(descP->useReg); - res = esock_make_error(env, atom_closed); + return esock_make_ok2(env, eVal); +} - } else if (descP->currentReaderP == NULL) { - res = esock_atom_not_found; - } else { - ErlNifPid self; +/* + * esock_getopt_otp_domain - Handle the OTP (level) domain option + */ - ESOCK_ASSERT( enif_self(env, &self) != NULL ); +static +ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env, + ESockDescriptor* descP) +{ + ERL_NIF_TERM domain, result; - if (COMPARE_PIDS(&self, &descP->currentReader.pid) == 0) { - if (COMPARE(opRef, descP->currentReader.ref) == 0) - res = esock_cancel_recv_current(env, descP, sockRef); - else - res = esock_atom_not_found; - } else { - res = esock_cancel_recv_waiting(env, descP, opRef, &self); - } + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_domain {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - SSDBG( descP, - ("SOCKET", "esock_cancel_recv(%T) {%d} -> done with result:" - "\r\n %T" - "\r\n", sockRef, descP->sock, res) ); + esock_encode_domain(env, descP->domain, &domain); + result = esock_make_ok2(env, domain); - MUNLOCK(descP->readMtx); + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_domain {%d} ->" + "\r\n result: %T" + "\r\n", descP->sock, result) ); - return res; + return result; } -#endif // #ifndef __WIN32__ -/* The current reader process has an ongoing select we first must - * cancel. Then we must re-activate the "first" (the first - * in the reader queue). + +#if 0 + +/* + * esock_getopt_otp_type - Handle the OTP (level) type options. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; - - ESOCK_ASSERT( DEMONP("esock_cancel_recv_current -> current reader", - env, descP, &descP->currentReader.mon) == 0); - res = esock_cancel_read_select(env, descP, descP->currentReader.ref); - - SSDBG( descP, - ("SOCKET", "esock_cancel_recv_current(%T) {%d} -> cancel res: %T" - "\r\n", sockRef, descP->sock, res) ); + ERL_NIF_TERM type, result; - if (! activate_next_reader(env, descP, sockRef)) { + if (! IS_OPEN(descP->readState)) { SSDBG( descP, - ("SOCKET", - "esock_cancel_recv_current(%T) {%d} -> no more readers" - "\r\n", sockRef, descP->sock) ); - - descP->currentReaderP = NULL; + ("SOCKET", "esock_getopt_otp_type {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } - return res; + esock_encode_type(env, descP->type, &type); + result = esock_make_ok2(env, type); + + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_type {%d} ->" + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + return result; } -#endif // #ifndef __WIN32__ -/* These processes have not performed a select, so we can simply - * remove them from the reader queue. + +/* + * esock_getopt_otp_protocol - Handle the OTP (level) protocol options. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM esock_cancel_recv_waiting(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - const ErlNifPid* selfP) +ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env, + ESockDescriptor* descP) { - /* unqueue request from (reader) queue */ + ERL_NIF_TERM protocol, result; - if (reader_unqueue(env, descP, &opRef, selfP)) { - return esock_atom_ok; - } else { - return esock_atom_not_found; + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_protocol {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } -} -#endif // #ifndef __WIN32__ + protocol = MKI(env, descP->protocol); + result = esock_make_ok2(env, protocol); + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_protocol {%d} ->" + "\r\n result: %T" + "\r\n", descP->sock, result) ); -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef) -{ - return esock_cancel_mode_select(env, descP, opRef, - ERL_NIF_SELECT_READ, - ERL_NIF_SELECT_READ_CANCELLED); + return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -static -ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef) -{ - return esock_cancel_mode_select(env, descP, opRef, - ERL_NIF_SELECT_WRITE, - ERL_NIF_SELECT_WRITE_CANCELLED); -} -#endif // #ifndef __WIN32__ +/* + * esock_getopt_otp_dtp - Handle the OTP (level) type options. + */ -#ifndef __WIN32__ static -ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM opRef, - int smode, - int rmode) +ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env, + ESockDescriptor* descP) { - /* Assumes cancelling only one mode */ - - int selectRes = esock_select_cancel(env, descP->sock, smode, descP); + ERL_NIF_TERM domain, type, protocol, dtp, result; - if (selectRes >= 0) { - /* Success */ - if ((selectRes & rmode) != 0) { - /* Was cancelled */ - return esock_atom_ok; - } else { - /* Has already sent the message */ - return esock_atom_select_sent; - } - } else { - /* Stopped? */ + if (! IS_OPEN(descP->readState)) { SSDBG( descP, - ("SOCKET", - "esock_cancel_mode_select {%d} -> failed: %d (0x%lX)" - "\r\n", descP->sock, selectRes, selectRes) ); - - return esock_atom_not_found; + ("SOCKET", "esock_getopt_otp_dtp {%d} -> done closed\r\n", + descP->sock) ); + return esock_make_error_closed(env); } + + esock_encode_domain(env, descP->domain, &domain); + esock_encode_type(env, descP->type, &type); + protocol = MKI(env, descP->protocol); + dtp = MKT3(env, domain, type, protocol); + result = esock_make_ok2(env, dtp); + + SSDBG( descP, + ("SOCKET", "esock_getopt_otp_dtp {%d} ->" + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + return result; } -#endif // #ifndef __WIN32__ +#endif // #if 0 -/* ---------------------------------------------------------------------- - * U t i l i t y F u n c t i o n s - * ---------------------------------------------------------------------- - */ -/* *** send_check_writer *** - * - * Checks if we have a current writer and if that is us. - * If not (current writer), then we must be made to wait - * for our turn. This is done by pushing us unto the writer queue. +/* How to decode the value is specified with valueSpec */ -#ifndef __WIN32__ + static -BOOLEAN_T send_check_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult) +ERL_NIF_TERM esock_getopt_native(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM valueSpec) { - if (descP->currentWriterP != NULL) { - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + ERL_NIF_TERM result; + SOCKOPTLEN_T valueSz; + int sz; + ErlNifBinary bin; - if (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0) { - /* Not the "current writer", so (maybe) push onto queue */ + MLOCK(descP->readMtx); - SSDBG( descP, - ("SOCKET", - "send_check_writer {%d} -> not (current) writer" - "\r\n ref: %T" - "\r\n", descP->sock, ref) ); + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> entry" + "\r\n level: %d" + "\r\n opt: %d" + "\r\n valueSpec: %T" + "\r\n", descP->sock, + level, opt, valueSpec) ); - if (! writer_search4pid(env, descP, &caller)) { - writer_push(env, descP, caller, ref); - *checkResult = atom_select; - } else { - /* Writer already in queue */ - *checkResult = esock_raise_invalid(env, atom_state); - } - + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> done closed\r\n", + descP->sock) ); + MUNLOCK(descP->readMtx); + return esock_make_error_closed(env); + } + + /* + * We could make it possible to specify more types, + * such as string, NUL terminated or not, etc... + * + */ + + if (GET_INT(env, valueSpec, &sz)) { + valueSz = (SOCKOPTLEN_T) sz; + if ((int) valueSz == sz) { SSDBG( descP, - ("SOCKET", - "send_check_writer {%d} -> queue (push) result: %T\r\n" - "\r\n ref: %T" - "\r\n", descP->sock, *checkResult, ref) ); - - return FALSE; + ("SOCKET", "esock_getopt_native {%d} -> binary size" + "\r\n valueSz: %d" + "\r\n", descP->sock, sz) ); + result = + esock_getopt_size_opt(env, descP, level, opt, valueSz); + } else { + result = esock_make_invalid(env, esock_atom_value); } + } else if (COMPARE(valueSpec, atom_integer) == 0) { + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> integer" + "\r\n", descP->sock) ); + result = esock_getopt_int_opt(env, descP, level, opt); + } else if (COMPARE(valueSpec, atom_boolean) == 0) { + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> boolean" + "\r\n", descP->sock) ); + result = esock_getopt_bool_opt(env, descP, level, opt); + } else if (enif_inspect_binary(env, valueSpec, &bin)) { + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> binary" + "\r\n size: %lu" + "\r\n", descP->sock, (unsigned long) bin.size) ); + result = esock_getopt_bin_opt(env, descP, level, opt, &bin); + } else { + result = esock_make_invalid(env, esock_atom_value); } - // Does not actually matter in this case, but ... - *checkResult = esock_atom_ok; + SSDBG( descP, + ("SOCKET", "esock_getopt_native {%d} -> done when" + "\r\n result: %T" + "\r\n", descP->sock, result) ); - return TRUE; + MUNLOCK(descP->readMtx); + return result; } -#endif // #ifndef __WIN32__ -/* *** send_check_result *** - * - * Check the result of a socket send (send, sendto and sendmsg) call. - * If a "complete" send has been made, the next (waiting) writer will be - * scheduled (if there is one). - * If we did not manage to send the entire package, make another select, - * so that we can be informed when we can make another try (to send the rest), - * and return with the amount we actually managed to send (its up to the caller - * (that is the erlang code) to figure out hust much is left to send). - * If the write fail, we give up and return with the appropriate error code. - * - * What about the remaining writers!! - * + +/* esock_getopt - An option that we know how to decode */ -#ifndef __WIN32__ static -ERL_NIF_TERM send_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t send_result, - ssize_t dataSize, - BOOLEAN_T dataInTail, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef) +ERL_NIF_TERM esock_getopt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ERL_NIF_TERM res; - BOOLEAN_T send_error; - int err; + ERL_NIF_TERM result; + const struct ESockOpt *optP; - send_error = ESOCK_IS_ERROR(send_result); - err = send_error ? sock_errno() : 0; + MLOCK(descP->readMtx); SSDBG( descP, - ("SOCKET", "send_check_result(%T) {%d} -> entry with" - "\r\n send_result: %ld" - "\r\n dataSize: %ld" - "\r\n err: %d" - "\r\n sendRef: %T" - "\r\n", sockRef, descP->sock, - (long) send_result, (long) dataSize, err, sendRef) ); - - if (send_error) { - /* Some kind of send failure - check what kind */ - if ((err != EAGAIN) && (err != EINTR)) { - res = send_check_fail(env, descP, err, sockRef); - } else { - /* Ok, try again later */ + ("SOCKET", "esock_getopt {%d} -> entry with" + "\r\n level: %d" + "\r\n opt: %d" + "\r\n", descP->sock, level, opt) ); - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> try again" - "\r\n", sockRef, descP->sock) ); + if (! IS_OPEN(descP->readState)) { + SSDBG( descP, + ("SOCKET", "esock_getopt {%d} -> done when closed\r\n", + descP->sock) ); + MUNLOCK(descP->readMtx); + return esock_make_error_closed(env); + } + + optP = lookupOpt(level, opt); + + if (optP == NULL) { + + result = esock_make_invalid(env, atom_socket_option); + + SSDBG( descP, + ("SOCKET", "esock_getopt {%d} -> unknown option\r\n", + descP->sock) ); + + } else if (optP->getopt == NULL) { + + result = esock_make_invalid(env, atom_socket_option); + + SSDBG( descP, + ("SOCKET", "esock_getopt {%d} -> opt not gettable\r\n", + descP->sock) ); - res = send_check_retry(env, descP, -1, sockRef, sendRef); - } } else { - ssize_t written = send_result; - ESOCK_ASSERT( dataSize >= written ); - if (written < dataSize) { - /* Not the entire package */ - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> " - "not entire package written (%d of %d)" - "\r\n", sockRef, descP->sock, - written, dataSize) ); - - res = send_check_retry(env, descP, written, sockRef, sendRef); - } else if (dataInTail) { - /* Not the entire package */ - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> " - "not entire package written (%d but data in tail)" - "\r\n", sockRef, descP->sock, - written) ); - - res = - send_check_retry(env, descP, written, sockRef, - esock_atom_iov); - } else { - res = send_check_ok(env, descP, written, sockRef); - } + result = (optP->getopt)(env, descP, level, opt); + + SSDBG( descP, + ("SOCKET", "esock_getopt {%d} -> done when" + "\r\n result: %T" + "\r\n", descP->sock, result) ); } - SSDBG( descP, - ("SOCKET", - "send_check_result(%T) {%d} -> done:" - "\r\n res: %T" - "\r\n", sockRef, descP->sock, - res) ); + MUNLOCK(descP->readMtx); + return result; +} - return res; + +#if defined(SO_BINDTODEVICE) +static +ERL_NIF_TERM esock_getopt_so_bindtodevice(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + return esock_getopt_str_opt(env, descP, level, opt, IFNAMSIZ+1, FALSE); } -#endif // #ifndef __WIN32__ +#endif -/* *** send_check_ok *** - * - * Processing done upon successful send. +#if defined(SO_BSP_STATE) +/* We need to allocate *all* of the memory used by the CSADDR_INFO + * structure. *Including* the 'sockaddr' structures pointed to by + * LocalAddr and RemoteAddr (lpSockaddr in SOCKET_ADDRESS). + * The '2*' is just to "dead sure" that we have enough... */ -#ifndef __WIN32__ static -ERL_NIF_TERM send_check_ok(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM esock_getopt_bsp_state(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_pkg, &descP->writePkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_byte, &descP->writeByteCnt, written); - descP->writePkgMaxCnt += written; - if (descP->writePkgMaxCnt > descP->writePkgMax) - descP->writePkgMax = descP->writePkgMaxCnt; - descP->writePkgMaxCnt = 0; + ERL_NIF_TERM result; + SOCKOPTLEN_T valSz = 2*(sizeof(CSADDR_INFO) + 2*sizeof(SOCKADDR)); + CSADDR_INFO* valP = MALLOC(valSz); + int res; SSDBG( descP, - ("SOCKET", "send_check_ok(%T) {%d} -> " - "everything written (%ld) - done\r\n", - sockRef, descP->sock, written) ); + ("SOCKET", "esock_getopt_bsp_state(%d) -> entry\r\n", descP->sock) ); - if (descP->currentWriterP != NULL) { - ESOCK_ASSERT( DEMONP("send_check_ok -> current writer", - env, descP, &descP->currentWriter.mon) == 0); - } - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (!activate_next_writer(env, descP, sockRef)) { + sys_memzero((void *) valP, valSz); + +#ifdef __WIN32__ + res = sock_getopt(descP->sock, level, opt, (char*) valP, &valSz); +#else + res = sock_getopt(descP->sock, level, opt, valP, &valSz); +#endif + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); SSDBG( descP, - ("SOCKET", "send_check_ok(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); + ("SOCKET", "esock_getopt_bsp_state(%d) -> error: " + "\r\n %T" + "\r\n", descP->sock, reason) ); - descP->currentWriterP = NULL; - } + result = esock_make_error(env, reason); - return esock_atom_ok; -} -#endif // #ifndef __WIN32__ + } else if (valSz > 0) { + ERL_NIF_TERM + la = esock_encode_bsp_state_socket_address(env, &valP->LocalAddr), + ra = esock_encode_bsp_state_socket_address(env, &valP->RemoteAddr), + type = esock_encode_bsp_state_type(env, valP->iSocketType), + proto = esock_encode_bsp_state_protocol(env, valP->iProtocol), + keys[] = {atom_local_addr, atom_remote_addr, esock_atom_type, esock_atom_protocol}, + vals[] = {la, ra, type, proto}, + bspState; + size_t numKeys = NUM(keys); + SSDBG( descP, + ("SOCKET", "esock_getopt_bsp_state(%d) -> values encoded:" + "\r\n la: %T" + "\r\n ra: %T" + "\r\n type: %T" + "\r\n proto: %T" + "\r\n", descP->sock, + la, ra, type, proto) ); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &bspState) ); -/* *** send_check_failure *** - * - * Processing done upon failed send. - * An actual failure - we (and everyone waiting) give up. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM send_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM reason; + SSDBG( descP, + ("SOCKET", "esock_getopt_bsp_state(%d) -> " + "\r\n BSP State: %T" + "\r\n", descP->sock, bspState) ); + + result = esock_make_ok2(env, bspState); + } else { + result = esock_make_ok2(env, esock_atom_undefined); + } - ESOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1); + FREE( valP ); - SSDBG( descP, ("SOCKET", "send_check_fail(%T) {%d} -> error: %d\r\n", - sockRef, descP->sock, saveErrno) ); + SSDBG( descP, + ("SOCKET", "esock_getopt_bsp_state(%d) -> done when" + "\r\n result: %T" + "\r\n", descP->sock, result) ); - reason = MKA(env, erl_errno_id(saveErrno)); + return result; +} - if (saveErrno != EINVAL) { - /* - * We assume that anything other then einval (invalid input) - * is basically fatal (=> all waiting sends are aborted) - */ +static +ERL_NIF_TERM esock_encode_bsp_state_socket_address(ErlNifEnv* env, + SOCKET_ADDRESS* addr) +{ + ERL_NIF_TERM eaddr; - if (descP->currentWriterP != NULL) { + if (addr == NULL) + return esock_atom_undefined; - requestor_release("send_check_fail", - env, descP, &descP->currentWriter); + if ((addr->lpSockaddr == NULL) || + (addr->iSockaddrLength == 0)) + return esock_atom_undefined; - send_error_waiting_writers(env, descP, sockRef, reason); + esock_encode_sockaddr(env, + (ESockAddress*) addr->lpSockaddr, + addr->iSockaddrLength, + &eaddr); - descP->currentWriterP = NULL; - } - } - return esock_make_error(env, reason); + return eaddr; } -#endif // #ifndef __WIN32__ -/* *** send_error_waiting_writers *** - * - * Process all waiting writers when a fatal error has occured. - * All waiting writers will be "aborted", that is a - * nif_abort message will be sent (with ref and reason). - */ -#ifndef __WIN32__ static -void send_error_waiting_writers(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) +ERL_NIF_TERM esock_encode_bsp_state_type(ErlNifEnv* env, int type) { - ESockRequestor req; + ERL_NIF_TERM etype; - req.env = NULL; /* read by writer_pop before free */ - while (writer_pop(env, descP, &req)) { - SSDBG( descP, - ("SOCKET", - "send_error_waiting_writers(%T) {%d} -> abort" - "\r\n pid: %T" - "\r\n reason: %T" - "\r\n", - sockRef, descP->sock, &req.pid, reason) ); + switch (type) { + case SOCK_STREAM: + etype = esock_atom_stream; + break; + + case SOCK_DGRAM: + etype = esock_atom_dgram; + break; - esock_send_abort_msg(env, descP, sockRef, &req, reason); + case SOCK_RDM: + etype = esock_atom_rdm; + break; + + case SOCK_SEQPACKET: + etype = esock_atom_seqpacket; + break; - (void) DEMONP("send_error_waiting_writers -> pop'ed writer", - env, descP, &req.mon); + default: + etype = MKI(env, type); + break; } + + return etype; } -#endif // #ifndef __WIN32__ -/* *** send_check_retry *** - * - * Processing done upon uncomplete or blocked send. - * - * We failed to write the *entire* packet (anything less - * then size of the packet, which is 0 <= written < sizeof - * packet, so schedule the rest for later. - */ -#ifndef __WIN32__ static -ERL_NIF_TERM send_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t written, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef) +ERL_NIF_TERM esock_encode_bsp_state_protocol(ErlNifEnv* env, int proto) { - int sres; - ERL_NIF_TERM res; + ERL_NIF_TERM eproto; - SSDBG( descP, - ("SOCKET", - "send_check_retry(%T) {%d} -> %ld" - "\r\n", sockRef, descP->sock, (long) written) ); + switch (proto) { + case IPPROTO_TCP: + eproto = esock_atom_tcp; + break; - if (written >= 0) { - descP->writePkgMaxCnt += written; + case IPPROTO_UDP: + eproto = esock_atom_udp; + break; - if (descP->type != SOCK_STREAM) { - /* Partial write for packet oriented socket - * - done with packet - */ - if (descP->writePkgMaxCnt > descP->writePkgMax) - descP->writePkgMax = descP->writePkgMaxCnt; - descP->writePkgMaxCnt = 0; - - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_pkg, &descP->writePkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, - atom_write_byte, &descP->writeByteCnt, written); - - if (descP->currentWriterP != NULL) { - ESOCK_ASSERT( DEMONP("send_check_retry -> current writer", - env, descP, - &descP->currentWriter.mon) == 0); - } - /* - * Ok, this write is done maybe activate the next (if any) - */ - if (!activate_next_writer(env, descP, sockRef)) { + /* + * In Wista and later the IPPROTO_PGM constant is defined in the + * Ws2def.h header file to the same value as the IPPROTO_RM constant + * defined in the Wsrm.h header file. + * => So we use IPPROTO_PGM also but translate to rm... + * + */ +#if defined(IPPROTO_RM) || defined(IPPROTO_PGM) +#if defined(IPPROTO_RM) + case IPPROTO_RM: +#else if defined(IPPROTO_PGM) + case IPPROTO_PGM: +#endif + eproto = esock_atom_rm; + break; +#endif - SSDBG( descP, - ("SOCKET", - "send_check_retry(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); + default: + eproto = MKI(env, proto); + break; + } - descP->currentWriterP = NULL; - } + return eproto; +} - return esock_make_ok2(env, MKI64(env, written)); - } /* else partial write for stream socket */ - } /* else send would have blocked */ +#endif - /* Register this process as current writer */ - if (descP->currentWriterP == NULL) { - /* Register writer as current */ - ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); - ESOCK_ASSERT( MONP("send_check_retry -> current writer", - env, descP, - &descP->currentWriter.pid, - &descP->currentWriter.mon) == 0 ); - ESOCK_ASSERT( descP->currentWriter.env == NULL ); +#if defined(SO_DOMAIN) +static +ERL_NIF_TERM esock_getopt_sock_domain(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + int val; + ERL_NIF_TERM result; - descP->currentWriter.env = esock_alloc_env("current-writer"); - descP->currentWriter.ref = - CP_TERM(descP->currentWriter.env, sendRef); - descP->currentWriterP = &descP->currentWriter; + if (! esock_getopt_int(descP->sock, level, opt, &val)) { + result = esock_make_error_errno(env, sock_errno()); } else { - /* Overwrite current writer registration */ - enif_clear_env(descP->currentWriter.env); - descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef); + ERL_NIF_TERM domain; + esock_encode_domain(env, val, &domain); + result = esock_make_ok2(env, domain); } - if (COMPARE(sendRef, esock_atom_iov) == 0) { - ESOCK_ASSERT( written >= 0 ); - /* IOV iteration - do not select */ - return MKT2(env, esock_atom_iov, MKI64(env, written)); - } + return result; +} +#endif + + +#if defined(SO_LINGER) +static +ERL_NIF_TERM esock_getopt_linger(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + ERL_NIF_TERM result; + struct linger val; + SOCKOPTLEN_T valSz = sizeof(val); + int res; + + sys_memzero((void *) &val, sizeof(val)); - /* Select write for this process */ +#ifdef __WIN32__ + res = sock_getopt(descP->sock, level, opt, (char*) &val, &valSz); +#else + res = sock_getopt(descP->sock, level, opt, &val, &valSz); +#endif - sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM + lOnOff = ((val.l_onoff != 0) ? atom_true : atom_false), + lSecs = MKI(env, val.l_linger), + keys[] = {atom_onoff, esock_atom_linger}, + vals[] = {lOnOff, lSecs}, + linger; + size_t numKeys = NUM(keys); - if (sres < 0) { - ERL_NIF_TERM reason; + SSDBG( descP, + ("SOCKET", "esock_getopt_linger(%d) -> " + "\r\n val.l_onoff: %d" + "\r\n lOnOff: %T" + "\r\n val.l_linger: %d" + "\r\n lSecs: %T" + "\r\n", descP->sock, + val.l_onoff, lOnOff, + val.l_linger, lSecs) ); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &linger) ); - /* Internal select error */ - ESOCK_ASSERT( DEMONP("send_check_retry - select error", - env, descP, &descP->currentWriter.mon) == 0); + SSDBG( descP, + ("SOCKET", "esock_getopt_linger(%d) -> " + "\r\n linger: %T" + "\r\n", descP->sock, linger) ); + + result = esock_make_ok2(env, linger); + } - /* Fail all queued writers */ - reason = MKT2(env, atom_select_write, MKI(env, sres)); - requestor_release("send_check_retry - select error", - env, descP, &descP->currentWriter); - send_error_waiting_writers(env, descP, sockRef, reason); - descP->currentWriterP = NULL; + return result; +} +#endif - res = - enif_raise_exception(env, - MKT2(env, atom_select_write, - MKI(env, sres))); - } else { - ESOCK_CNT_INC(env, descP, sockRef, atom_write_waits, - &descP->writeWaits, 1); - descP->writeState |= ESOCK_STATE_SELECTED; +#if defined(SO_TYPE) +static +ERL_NIF_TERM esock_getopt_sock_type(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + ERL_NIF_TERM result; + int val; - if (written >= 0) { - /* Partial write success */ - res = MKT2(env, atom_select, MKI64(env, written)); - } else { - /* No write - try again */ - res = atom_select; - } + if (! esock_getopt_int(descP->sock, level, opt, &val)) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM type; + esock_encode_type(env, val, &type); + result = esock_make_ok2(env, type); } - return res; + return result; } -#endif // #ifndef __WIN32__ +#endif -/* *** recv_check_reader *** - * - * Checks if we have a current reader and if that is us. If not, - * then we must be made to wait for our turn. This is done by pushing - * us unto the reader queue. - * Note that we do *not* actually initiate the currentReader structure - * here, since we do not actually know yet if we need to! We do that in - * the [recv|recvfrom|recvmsg]_check_result function. - */ -#ifndef __WIN32__ +#if defined(SO_PROTOCOL) static -BOOLEAN_T recv_check_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM ref, - ERL_NIF_TERM* checkResult) +ERL_NIF_TERM esock_getopt_sock_protocol(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - if (descP->currentReaderP != NULL) { - ErlNifPid caller; - - ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + ERL_NIF_TERM result; + int val; - if (COMPARE_PIDS(&descP->currentReader.pid, &caller) != 0) { - /* Not the "current reader", so (maybe) push onto queue */ + if (! esock_getopt_int(descP->sock, level, opt, &val)) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM protocol; - SSDBG( descP, - ("SOCKET", - "recv_check_reader {%d} -> not (current) reader" - "\r\n ref: %T" - "\r\n", descP->sock, ref) ); - - if (! reader_search4pid(env, descP, &caller)) { - if (COMPARE(ref, atom_zero) == 0) - goto done_ok; - reader_push(env, descP, caller, ref); - *checkResult = atom_select; - } else { - /* Reader already in queue */ - *checkResult = esock_raise_invalid(env, atom_state); - } - - SSDBG( descP, - ("SOCKET", - "recv_check_reader {%d} -> queue (push) result: %T\r\n", - descP->sock, *checkResult) ); + protocol = +#ifdef AF_LOCAL + /* For AF_LOCAL, the protocols table value for 0 is wrong */ + (val == 0) && (descP->domain == AF_LOCAL) ? + esock_atom_default : + /* It is correct for AF_INET and hopefully for AF_INET6, + * but for future additions it is an open question + */ +#endif + MKI(env, val); - return FALSE; - } + result = esock_make_ok2(env, protocol); } - done_ok: - // Does not actually matter in this case, but ... - *checkResult = esock_atom_ok; - return TRUE; + return result; } -#endif // #ifndef __WIN32__ +#endif -/* *** recv_init_current_reader *** - * - * Initiate (maybe) the currentReader structure of the descriptor. - * Including monitoring the calling process. +/* esock_getopt_ip_mtu_discover - Level IP MTU_DISCOVER option */ -#ifndef __WIN32__ +#if defined(IP_MTU_DISCOVER) static -void recv_init_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_ip_mtu_discover(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - if (descP->currentReaderP == NULL) { - - ESOCK_ASSERT( enif_self(env, &descP->currentReader.pid) != NULL ); - - ESOCK_ASSERT( MONP("recv_init_current_reader -> current reader", - env, descP, - &descP->currentReader.pid, - &descP->currentReader.mon) == 0); - ESOCK_ASSERT(!descP->currentReader.env); + ERL_NIF_TERM result; + int mtuDisc; - descP->currentReader.env = esock_alloc_env("current-reader"); - descP->currentReader.ref = - CP_TERM(descP->currentReader.env, recvRef); - descP->currentReaderP = &descP->currentReader; + if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) { + result = esock_make_error_errno(env, sock_errno()); } else { + ERL_NIF_TERM eMtuDisc; + encode_ip_pmtudisc(env, mtuDisc, &eMtuDisc); + result = esock_make_ok2(env, eMtuDisc); + } - /* - * This is a retry: - * We have done, for instance, recv(Sock, X), but only received Y < X. - * We then call recv again with size = X-Y. So, we then get a new ref. - * - * Make use of the existing environment - */ + return result; - enif_clear_env(descP->currentReader.env); - descP->currentReader.ref = CP_TERM(descP->currentReader.env, recvRef); - } } -#endif // #ifndef __WIN32__ +#endif -/* *** recv_update_current_reader *** - * - * Demonitors the current reader process and pop's the reader queue. - * If there is a waiting (reader) process, then it will be assigned - * as the new current reader and a new (read) select will be done. +/* esock_getopt_multicast_if - Level IP MULTICAST_IF option */ -#ifndef __WIN32__ -static void -recv_update_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef) + +#if defined(IP_MULTICAST_IF) +static +ERL_NIF_TERM esock_getopt_multicast_if(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - if (descP->currentReaderP != NULL) { - - ESOCK_ASSERT( DEMONP("recv_update_current_reader", - env, descP, &descP->currentReader.mon) == 0); + ERL_NIF_TERM result; + ERL_NIF_TERM eAddr; + struct in_addr ifAddr; + SOCKOPTLEN_T ifAddrSz = sizeof(ifAddr); + int res; - if (! activate_next_reader(env, descP, sockRef)) { + sys_memzero((void *) &ifAddr, ifAddrSz); - SSDBG( descP, - ("SOCKET", - "recv_update_current_reader(%T) {%d} -> no more readers\r\n", - sockRef, descP->sock) ); +#ifdef __WIN32__ + res = sock_getopt(descP->sock, level, opt, (char*) &ifAddr, &ifAddrSz); +#else + res = sock_getopt(descP->sock, level, opt, &ifAddr, &ifAddrSz); +#endif - descP->currentReaderP = NULL; - } + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + esock_encode_in_addr(env, &ifAddr, &eAddr); + result = esock_make_ok2(env, eAddr); } + + return result; + } -#endif // #ifndef __WIN32__ +#endif -/* *** recv_error_current_reader *** - * - * Process the current reader and any waiting readers - * when a read (fatal) error has occured. - * All waiting readers will be "aborted", that is a - * nif_abort message will be sent (with ref and reason). + +/* esock_getopt_tos - Level IP TOS option */ -#ifndef __WIN32__ + +#if defined(IP_TOS) static -void recv_error_current_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM reason) +ERL_NIF_TERM esock_getopt_tos(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - if (descP->currentReaderP != NULL) { - ESockRequestor req; - - requestor_release("recv_error_current_reader", - env, descP, &descP->currentReader); - - req.env = NULL; /* read by reader_pop before free */ - while (reader_pop(env, descP, &req)) { + ERL_NIF_TERM result; + int val = 0; - SSDBG( descP, - ("SOCKET", "recv_error_current_reader(%T) {%d} -> abort" - "\r\n pid: %T" - "\r\n reason %T" - "\r\n", sockRef, descP->sock, - req.pid, reason) ); + if (! esock_getopt_int(descP->sock, level, opt, &val)) { + result = esock_make_error_errno(env, sock_errno()); + } else { + result = esock_make_ok2(env, encode_ip_tos(env, val)); + } - esock_send_abort_msg(env, descP, sockRef, &req, reason); + return result; +} +#endif - ESOCK_ASSERT( DEMONP("recv_error_current_reader -> pop'ed reader", - env, descP, &req.mon) == 0); - } - descP->currentReaderP = NULL; - } -} -#endif // #ifndef __WIN32__ +#if defined(HAVE_IPV6) -/* *** recv_check_result *** - * - * Process the result of a call to recv. +/* esock_getopt_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option */ -#ifndef __WIN32__ + +#if defined(IPV6_MTU_DISCOVER) static -ERL_NIF_TERM recv_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - int saveErrno, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_ipv6_mtu_discover(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ERL_NIF_TERM res; - - SSDBG( descP, - ("SOCKET", "recv_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n toRead: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, (long) toRead, saveErrno, recvRef) ); - - - /* - * - * We need to handle read = 0 for other type(s) (DGRAM) when - * its actually valid to read 0 bytes. - * - * - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { - ERL_NIF_TERM reason = atom_closed; - res = esock_make_error(env, reason); - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); + ERL_NIF_TERM result; + int mtuDisc; - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - * - * We must also notify any waiting readers! - */ + if (! esock_getopt_int(descP->sock, level, opt, &mtuDisc)) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM eMtuDisc; + encode_ipv6_pmtudisc(env, mtuDisc, &eMtuDisc); + result = esock_make_ok2(env, eMtuDisc); + } - recv_error_current_reader(env, descP, sockRef, reason); + return result; - FREE_BIN(bufP); +} +#endif - } else { - - /* There is a special case: If the provided 'to read' value is - * zero (0) (only for type =/= stream). - * That means that we read as much as we can, using the default - * read buffer size. - */ +#endif // defined(HAVE_IPV6) - if (bufP->size == read) { - /* +++ We filled the buffer +++ */ +/* esock_getopt_tcp_congestion - Level TCP CONGESTION option + */ - SSDBG( descP, - ("SOCKET", - "recv_check_result(%T) {%d} -> [%lu] filled the buffer\r\n", - sockRef, descP->sock, (unsigned long) bufP->size) ); +#if defined(TCP_CONGESTION) +static +ERL_NIF_TERM esock_getopt_tcp_congestion(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + int max = ESOCK_OPT_TCP_CONGESTION_NAME_MAX+1; - res = recv_check_full(env, descP, read, toRead, bufP, - sockRef, recvRef); + return esock_getopt_str_opt(env, descP, level, opt, max, TRUE); +} +#endif - } else if (read < 0) { - /* +++ Error handling +++ */ - res = recv_check_fail(env, descP, saveErrno, bufP, NULL, - sockRef, recvRef); +#if defined(HAVE_SCTP) - } else { +/* esock_getopt_sctp_associnfo - Level SCTP ASSOCINFO option + * + * + * + * We should really specify which association this relates to, + * as it is now we get assoc-id = 0. If this socket is an + * association (and not an endpoint) then it will have an + * assoc id. But since the sctp support at present is "limited", + * we leave it for now. + * What do we do if this is an endpoint? Invalid op? Or just leave + * it for the OS? + * + * + */ +#ifndef __WIN32__ +#if defined(SCTP_ASSOCINFO) +static +ERL_NIF_TERM esock_getopt_sctp_associnfo(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + ERL_NIF_TERM result; + struct sctp_assocparams val; + SOCKOPTLEN_T valSz = sizeof(val); + int res; - /* +++ We did not fill the buffer +++ */ + sys_memzero((char*) &val, valSz); + res = sock_getopt(descP->sock, level, opt, &val, &valSz); - SSDBG( descP, - ("SOCKET", - "recv_check_result(%T) {%d} -> [%lu] " - "did not fill the buffer (%ld)\r\n", - sockRef, descP->sock, (unsigned long) bufP->size, - (long) read) ); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM eAssocParams; + ERL_NIF_TERM keys[] = {atom_assoc_id, + atom_asocmaxrxt, + atom_number_peer_destinations, + atom_peer_rwnd, + atom_local_rwnd, + atom_cookie_life}; + ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.sasoc_assoc_id), + MKUI(env, val.sasoc_asocmaxrxt), + MKUI(env, val.sasoc_number_peer_destinations), + MKUI(env, val.sasoc_peer_rwnd), + MKUI(env, val.sasoc_local_rwnd), + MKUI(env, val.sasoc_cookie_life)}; + size_t numKeys = NUM(keys); - res = recv_check_partial(env, descP, read, toRead, bufP, - sockRef, recvRef); - } + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eAssocParams) ); + result = esock_make_ok2(env, eAssocParams); } - return res; + return result; } +#endif #endif // #ifndef __WIN32__ -/* *** recv_check_full *** - * - * This function is called if we filled the allocated buffer. - * But are we done yet? + + +/* esock_getopt_sctp_initmsg - Level SCTP INITMSG option * - * toRead = 0 means: Give me everything you have => maybe - * toRead > 0 means: Yes */ #ifndef __WIN32__ +#if defined(SCTP_INITMSG) static -ERL_NIF_TERM recv_check_full(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_sctp_initmsg(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ERL_NIF_TERM res; - - if ((toRead == 0) && - (descP->type == SOCK_STREAM)) { - - /* +++ Give us everything you have got => * - * (maybe) needs to continue +++ */ - - /* Send up each chunk of data for each of the read - * and let the erlang code assemble it: {more, Bin} - * (when complete it should return {ok, Bin}). - * We need to read atleast one more time to be sure if its - * done... - * - * Also, we need to check if the rNumCnt has reached its max (rNum), - * in which case we will assume the read to be done! - */ - - SSDBG( descP, - ("SOCKET", "recv_check_full(%T) {%d} -> shall we continue reading?" - "\r\n read: %ld" - "\r\n rNum: %u" - "\r\n rNumCnt: %u" - "\r\n", sockRef, descP->sock, - (unsigned long) read, descP->rNum, descP->rNumCnt) ); + ERL_NIF_TERM result; + struct sctp_initmsg val; + SOCKOPTLEN_T valSz = sizeof(val); + int res; - res = recv_check_full_maybe_done(env, descP, read, bufP, - sockRef, recvRef); + sys_memzero((char*) &val, valSz); + res = sock_getopt(descP->sock, level, opt, &val, &valSz); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); } else { + ERL_NIF_TERM eInitMsg; + ERL_NIF_TERM keys[] = {atom_num_outstreams, atom_max_instreams, + atom_max_attempts, atom_max_init_timeo}; + ERL_NIF_TERM vals[] = {MKUI(env, val.sinit_num_ostreams), + MKUI(env, val.sinit_max_instreams), + MKUI(env, val.sinit_max_attempts), + MKUI(env, val.sinit_max_init_timeo)}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); - /* +++ We got exactly as much as we requested => We are done +++ */ - - SSDBG( descP, - ("SOCKET", - "recv_check_full(%T) {%d} -> [%ld] " - "we got exactly what we could fit\r\n", - sockRef, descP->sock, (long) toRead) ); - - res = recv_check_full_done(env, descP, read, bufP, sockRef); - + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eInitMsg) ); + result = esock_make_ok2(env, eInitMsg); } - return res; - + return result; } +#endif #endif // #ifndef __WIN32__ -/* *** recv_check_full_maybe_done *** +/* esock_getopt_sctp_rtoinfo - Level SCTP ASSOCINFO option + * + * * - * Send up each chunk of data for each of the read - * and let the erlang code assemble it: {more, Bin} - * (when complete it should return {ok, Bin}). - * We need to read at least one more time to be sure if its - * done... + * We should really specify which association this relates to, + * as it is now we get assoc-id = 0. If this socket is an + * association (and not an endpoint) then it will have an + * assoc id (we can assume). But since the sctp support at + * present is "limited", we leave it for now. + * What do we do if this is an endpoint? Invalid op? * - * Also, we need to check if the rNumCnt has reached its max (rNum), - * in which case we will assume the read to be done! + * */ #ifndef __WIN32__ +#if defined(SCTP_RTOINFO) static -ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_sctp_rtoinfo(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_byte, &descP->readByteCnt, read); - descP->readPkgMaxCnt += read; + ERL_NIF_TERM result; + struct sctp_rtoinfo val; + SOCKOPTLEN_T valSz = sizeof(val); + int res; - descP->rNumCnt++; - if (descP->rNumCnt >= descP->rNum) { + sys_memzero((char*) &val, valSz); + res = sock_getopt(descP->sock, level, opt, &val, &valSz); - descP->rNumCnt = 0; + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM eRTOInfo; + ERL_NIF_TERM keys[] = {atom_assoc_id, atom_initial, atom_max, atom_min}; + ERL_NIF_TERM vals[] = {encode_sctp_assoc_t(env, val.srto_assoc_id), + MKUI(env, val.srto_initial), + MKUI(env, val.srto_max), + MKUI(env, val.srto_min)}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_pkg, &descP->readPkgCnt, 1); - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &eRTOInfo) ); + result = esock_make_ok2(env, eRTOInfo); + } - recv_update_current_reader(env, descP, sockRef); + return result; +} +#endif +#endif // #ifndef __WIN32__ - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - return esock_make_ok2(env, MKBIN(env, bufP)); - } +#endif // defined(HAVE_SCTP) - /* Yes, we *do* need to continue reading */ - recv_init_current_reader(env, descP, recvRef); - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ +/* esock_getopt_bool_opt - get an (integer) bool option + */ +static +ERL_NIF_TERM esock_getopt_bool_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) +{ + ERL_NIF_TERM result; + int val = 0; - SSDBG( descP, - ("SOCKET", - "recv_check_full_maybe_done(%T) {%d} -> [%lu] " - "we are done for now - read more\r\n", - sockRef, descP->sock, (unsigned long)bufP->size) ); + if (! esock_getopt_int(descP->sock, level, opt, &val)) { + result = esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM bval = ((val) ? atom_true : atom_false); - return MKT2(env, esock_atom_more, MKBIN(env, bufP)); + result = esock_make_ok2(env, bval); + } + return result; } -#endif // #ifndef __WIN32__ -/* *** recv_check_full_done *** - * - * A successful recv and we filled the buffer. +/* esock_getopt_int_opt - get an integer option */ -#ifndef __WIN32__ static -ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, +ERL_NIF_TERM esock_getopt_int_opt(ErlNifEnv* env, ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef) + int level, + int opt) { - ERL_NIF_TERM data; + int val; + + if (! esock_getopt_int(descP->sock, level, opt, &val)) + return esock_make_error_errno(env, sock_errno()); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); + return esock_make_ok2(env, MKI(env, val)); +} - descP->readPkgMaxCnt += read; - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; - recv_update_current_reader(env, descP, sockRef); - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - data = MKBIN(env, bufP); +/* esock_getopt_int - get an integer option + */ +extern +BOOLEAN_T esock_getopt_int(SOCKET sock, + int level, + int opt, + int* valP) +{ + int val = 0; + SOCKOPTLEN_T valSz = sizeof(val); + +#ifdef __WIN32__ + if (sock_getopt(sock, level, opt, (char*) &val, &valSz) != 0) +#else + if (sock_getopt(sock, level, opt, &val, &valSz) != 0) +#endif + return FALSE; - return esock_make_ok2(env, data); + *valP = val; + return TRUE; } -#endif // #ifndef __WIN32__ -/* *** recv_check_fail *** - * - * Handle recv failure. - */ -#ifndef __WIN32__ + static -ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ErlNifBinary* buf1P, - ErlNifBinary* buf2P, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_size_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + SOCKOPTLEN_T valueSz) { - ERL_NIF_TERM res; - - FREE_BIN(buf1P); - if (buf2P != NULL) FREE_BIN(buf2P); + ERL_NIF_TERM result; + int res; - if (saveErrno == ECONNRESET) { + if (valueSz == 0) { + res = sock_getopt(descP->sock, level, opt, NULL, NULL); + if (res != 0) + result = esock_make_error_errno(env, sock_errno()); + else + result = esock_atom_ok; + } else { + SOCKOPTLEN_T vsz = valueSz; + ErlNifBinary val; - /* +++ Oops - closed +++ */ + ESOCK_ASSERT( ALLOC_BIN(vsz, &val) ); + sys_memzero(val.data, val.size); + res = sock_getopt(descP->sock, level, opt, val.data, &vsz); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + FREE_BIN(&val); + } else { - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> econnreset: closed" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); + /* Did we use all of the buffer? */ + if (vsz == val.size) { + result = esock_make_ok2(env, MKBIN(env, &val)); - // This is a bit overkill (to count here), but just in case... - ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, - &descP->readFails, 1); + } else { - res = recv_check_fail_econnreset(env, descP, sockRef, recvRef); + ERL_NIF_TERM tmp; - } else if ((saveErrno == ERRNO_BLOCK) || - (saveErrno == EAGAIN)) { + tmp = MKBIN(env, &val); + tmp = MKSBIN(env, tmp, 0, vsz); - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> eagain" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); + result = esock_make_ok2(env, tmp); + } + } + } - if (COMPARE(recvRef, atom_zero) == 0) - res = esock_atom_ok; - else - res = recv_check_retry(env, descP, sockRef, recvRef); + return result; +} - } else { - SSDBG( descP, - ("SOCKET", - "recv_check_fail(%T) {%d} -> errno: %d\r\n" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, saveErrno, recvRef) ); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, - &descP->readFails, 1); +static +ERL_NIF_TERM esock_getopt_bin_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ErlNifBinary* binP) +{ + ERL_NIF_TERM result; + int res; + SOCKOPTLEN_T vsz; + ErlNifBinary val; - res = recv_check_fail_gen(env, descP, saveErrno, sockRef); - } + vsz = (SOCKOPTLEN_T) binP->size; + if (SZT(vsz) != binP->size) { + result = esock_make_error_invalid(env, esock_atom_data_size); + } else { + ESOCK_ASSERT( ALLOC_BIN(vsz, &val) ); + sys_memcpy(val.data, binP->data, vsz); + res = sock_getopt(descP->sock, level, opt, val.data, &vsz); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + FREE_BIN(&val); + } else { - return res; -} -#endif // #ifndef __WIN32__ + /* Did we use all of the buffer? */ + if (vsz == val.size) { + result = esock_make_ok2(env, MKBIN(env, &val)); + } else { -/* *** recv_check_fail_econnreset *** - * - * We detected that the socket was closed wile reading. - * Inform current and waiting readers. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM reason = MKA(env, erl_errno_id(ECONNRESET)); - ERL_NIF_TERM res = esock_make_error(env, reason); + ERL_NIF_TERM tmp; - /* - * - * IF THE CURRENT PROCESS IS *NOT* THE CONTROLLING - * PROCESS, WE NEED TO INFORM IT!!! - * - * ALL WAITING PROCESSES MUST ALSO GET THE ERROR!! - * HANDLED BY THE STOP (CALLBACK) FUNCTION? - * - * SINCE THIS IS A REMOTE CLOSE, WE DON'T NEED TO WAIT - * FOR OUTPUT TO BE WRITTEN (NO ONE WILL READ), JUST - * ABORT THE SOCKET REGARDLESS OF LINGER??? - * - * - */ + tmp = MKBIN(env, &val); + tmp = MKSBIN(env, tmp, 0, vsz); - recv_error_current_reader(env, descP, sockRef, reason); + result = esock_make_ok2(env, tmp); + } + } + } - return res; + return result; } -#endif // #ifndef __WIN32__ -/* *** recv_check_retry *** - * - * The recv call would have blocked, so retry. + +/* esock_getopt_timeval_opt - get an timeval option */ #ifndef __WIN32__ +#if (defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)) \ + && defined(ESOCK_USE_RCVSNDTIMEO) static -ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_timeval_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - int sres; - ERL_NIF_TERM res; - - descP->rNumCnt = 0; - recv_init_current_reader(env, descP, recvRef); - - SSDBG( descP, - ("SOCKET", - "recv_check_retry(%T) {%d} -> SELECT for more" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, recvRef) ); + ERL_NIF_TERM result; + struct timeval val; + SOCKOPTLEN_T valSz = sizeof(val); + int res; - if ((sres = esock_select_read(env, descP->sock, descP, NULL, - sockRef, recvRef)) < 0) { - /* Unlikely that any next reader will have better luck, - * but why not give them a shot - the queue will be cleared - */ - recv_update_current_reader(env, descP, sockRef); + sys_memzero((char*) &val, valSz); + res = sock_getopt(descP->sock, level, opt, &val, &valSz); - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); } else { - descP->readState |= ESOCK_STATE_SELECTED; - res = atom_select; + ERL_NIF_TERM eTimeVal; + + esock_encode_timeval(env, &val, &eTimeVal); + result = esock_make_ok2(env, eTimeVal); } - return res; + return result; } +#endif #endif // #ifndef __WIN32__ -/* *** recv_check_fail_gen *** +#ifndef __WIN32__ +#if defined(IP_PKTOPTIONS) || defined(IPV6_PKTOPTIONS) + +/* Calculate CMSG_NXTHDR without having a struct msghdr*. + * CMSG_LEN only caters for alignment for start of data. + * To get how much to advance we need to use CMSG_SPACE + * on the payload length. To get the payload length we + * take the calculated cmsg->cmsg_len and subtract the + * header length. To get the header length we use + * the pointer difference from the cmsg start pointer + * to the CMSG_DATA(cmsg) pointer. * - * The recv call had a "general" failure. + * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3) + * may return 0 as the cmsg_len if the cmsg is to be ignored. */ -#ifndef __WIN32__ +#define ESOCK_LEN_CMSG_DATA(__CMSG__) \ + ((__CMSG__)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \ + (__CMSG__)->cmsg_len - ((char*)ESOCK_CMSG_DATA(__CMSG__) - (char*)(__CMSG__))) +#define ESOCK_NEXT_CMSG_HDR(__CMSG__) \ + ((struct cmsghdr*)(((char*)(__CMSG__)) + ESOCK_CMSG_SPACE(ESOCK_LEN_CMSG_DATA(__CMSG__)))) + static -ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, - ESockDescriptor* descP, - int saveErrno, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM esock_getopt_pktoptions(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt) { - ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); - - recv_error_current_reader(env, descP, sockRef, reason); + ERL_NIF_TERM result, ePktOpts; + int res; + ErlNifBinary cmsgs; + SOCKOPTLEN_T sz = (SOCKOPTLEN_T) descP->rCtrlSz; + SocketTArray cmsghdrs = TARRAY_CREATE(16); + ERL_NIF_TERM ctrlBuf; - return esock_make_error(env, reason); -} -#endif // #ifndef __WIN32__ + ESOCK_ASSERT( ALLOC_BIN(sz, &cmsgs) ); + sys_memzero(cmsgs.data, cmsgs.size); + sz = cmsgs.size; // Make no assumption about the size + res = sock_getopt(descP->sock, level, opt, cmsgs.data, &sz); -/* *** recv_check_partial *** - * - * Handle a sucessful recv which only partly filled the specified buffer. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ssize_t toRead, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) -{ - ERL_NIF_TERM res; + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); + } else { + struct cmsghdr* currentP; + struct cmsghdr* endOfBuf; - if ((toRead == 0) || - (descP->type != SOCK_STREAM) || - (COMPARE(recvRef, atom_zero) == 0)) { + ctrlBuf = MKBIN(env, &cmsgs); // The *entire* binary - /* +++ We got it all, but since we +++ - * +++ did not fill the buffer, we +++ - * +++ must split it into a sub-binary. +++ - */ + for (endOfBuf = (struct cmsghdr*)(cmsgs.data + cmsgs.size), + currentP = (struct cmsghdr*)(cmsgs.data); + (currentP != NULL) && (currentP < endOfBuf); + currentP = ESOCK_NEXT_CMSG_HDR(currentP)) { + unsigned char* dataP = UCHARP(ESOCK_CMSG_DATA(currentP)); + size_t dataPos = dataP - cmsgs.data; + size_t dataLen = (UCHARP(currentP) + currentP->cmsg_len) - dataP; - SSDBG( descP, - ("SOCKET", - "recv_check_partial(%T) {%d} -> [%ld] split buffer" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, (long) toRead, - recvRef) ); + SSDBG( descP, + ("SOCKET", "esock_getopt_pktoptions {%d} -> cmsg header data: " + "\r\n currentP: 0x%lX" + "\r\n level: %d" + "\r\n data: %d" + "\r\n len: %d [0x%lX]" + "\r\n dataP: 0x%lX" + "\r\n dataPos: %d" + "\r\n dataLen: %d [0x%lX]" + "\r\n", descP->sock, + currentP, + currentP->cmsg_level, + currentP->cmsg_type, + currentP->cmsg_len, currentP->cmsg_len, + dataP, + dataPos, + dataLen, dataLen) ); - res = recv_check_partial_done(env, descP, read, bufP, sockRef); + /* + * Check that this is within the allocated buffer... + * The 'next control message header' is a bit adhoc, + * so this check is a bit... + */ + if ((dataPos > cmsgs.size) || + (dataLen > cmsgs.size) || + ((dataPos + dataLen) > ((size_t)endOfBuf))) { + break; + } else { + ERL_NIF_TERM cmsgHdr; + ERL_NIF_TERM keys[] = {esock_atom_level, + esock_atom_type, + esock_atom_data, + esock_atom_value}; + ERL_NIF_TERM vals[NUM(keys)]; + size_t numKeys = NUM(keys); + BOOLEAN_T haveValue; + + vals[0] = esock_encode_level(env, currentP->cmsg_level); + vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); - } else { - /* A stream socket with specified read size - * and not a polling read, we got a partial read - * - return a select result to initiate a retry - */ + haveValue = esock_encode_cmsg(env, + currentP->cmsg_level, + currentP->cmsg_type, + dataP, dataLen, &vals[1], &vals[3]); - SSDBG( descP, - ("SOCKET", - "recv_check_partial(%T) {%d} -> [%ld]" - " only part of message - expect more" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, (long) toRead, - recvRef) ); - - res = - recv_check_partial_part(env, descP, read, - bufP, sockRef, recvRef); - } + SSDBG( descP, + ("SOCKET", "esock_getopt_pktoptions {%d} -> " + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n", descP->sock, + keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); - return res; -} -#endif // #ifndef __WIN32__ + if (haveValue) { + SSDBG( descP, + ("SOCKET", "esock_getopt_pktoptions {%d} -> " + "\r\n %T: %T" + "\r\n", descP->sock, keys[3], vals[3]) ); + } + /* Guard against cut-and-paste errors */ + ESOCK_ASSERT( numKeys == NUM(vals) ); -/* *** recv_check_partial_done *** - * - * A successful but only partial recv, which fulfilled the required read. - */ -#ifndef __WIN32__ -static -ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef) -{ - ERL_NIF_TERM data; + /* Make control message header map */ + ESOCK_ASSERT( MKMA(env, keys, vals, + numKeys - (haveValue ? 0 : 1), &cmsgHdr) ); - descP->rNumCnt = 0; - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); + SSDBG( descP, + ("SOCKET", "esock_getopt_pktoptions {%d} -> header processed: " + "\r\n %T" + "\r\n", descP->sock, cmsgHdr) ); - descP->readPkgMaxCnt += read; - if (descP->readPkgMaxCnt > descP->readPkgMax) - descP->readPkgMax = descP->readPkgMaxCnt; - descP->readPkgMaxCnt = 0; + /* And finally add it to the list... */ + TARRAY_ADD(cmsghdrs, cmsgHdr); + } + } - recv_update_current_reader(env, descP, sockRef); + SSDBG( descP, + ("SOCKET", "esock_getopt_pktoptions {%d} -> " + "cmsg headers processed when" + "\r\n TArray Size: %d" + "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); + /* The tarray is populated - convert it to a list */ + TARRAY_TOLIST(cmsghdrs, env, &ePktOpts); - SSDBG( descP, - ("SOCKET", "recv_check_partial_done(%T) {%d} -> [%ld] done\r\n", - sockRef, descP->sock, (long) read) ); + result = esock_make_ok2(env, ePktOpts); + } + + FREE_BIN(&cmsgs); - return esock_make_ok2(env, data); + return result; } +#endif #endif // #ifndef __WIN32__ -/* *** recv_check_partial_part *** + + +/* esock_getopt_str_opt - get a string option * - * A successful but only partial recv, which only partly fulfilled - * the required read. + * We provide the max size of the string. This is the + * size of the buffer we allocate for the value. + * The actual size of the (read) value will be communicated + * in the valSz variable. */ #ifndef __WIN32__ +#if defined(USE_GETOPT_STR_OPT) static -ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - ErlNifBinary* bufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_getopt_str_opt(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + int max, + BOOLEAN_T stripNUL) { - ERL_NIF_TERM res; - int sres; - - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); - - recv_init_current_reader(env, descP, recvRef); + ERL_NIF_TERM result; + char* val = MALLOC(max); + SOCKOPTLEN_T valSz = max; + int res; - /* SELECT for more data */ + ESOCK_ASSERT( val != NULL ); - sres = esock_select_read(env, descP->sock, descP, NULL, - sockRef, recvRef); - if (sres < 0) { - /* Unlikely that any next reader will have better luck, - * but why not give them a shot - the queue will be cleared - */ - recv_update_current_reader(env, descP, sockRef); + sys_memzero(val, max); + res = sock_getopt(descP->sock, level, opt, val, &valSz); - res = - enif_raise_exception(env, - MKT2(env, atom_select_read, - MKI(env, sres))); + if (res != 0) { + result = esock_make_error_errno(env, sock_errno()); } else { - ERL_NIF_TERM data; + if (stripNUL && + valSz > 0 && + val[valSz - 1] == '\0') valSz--; - descP->readState |= ESOCK_STATE_SELECTED; - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); - res = MKT2(env, atom_select, data); + result = esock_make_ok2(env, MKSL(env, val, valSz)); } + FREE(val); - /* This transfers "ownership" of the *allocated* binary to an - * erlang term (no need for an explicit free). - */ - return res; + return result; } +#endif // if defined(USE_GETOPT_STR_OPT) #endif // #ifndef __WIN32__ - -/* The recvfrom function delivers one (1) message. If our buffer - * is too small, the message will be truncated. So, regardless - * if we filled the buffer or not, we have got what we are going - * to get regarding this message. +/* ---------------------------------------------------------------------- + * nif_sockname - get socket name + * + * Description: + * Returns the current address to which the socket is bound. + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - ErlNifBinary* bufP, - ESockAddress* fromAddrP, - SOCKLEN_T fromAddrLen, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM nif_sockname(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM data, res; - - SSDBG( descP, - ("SOCKET", "recvfrom_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, saveErrno, recvRef) ); - - /* - * - * We need to handle read = 0 for non_stream socket type(s) when - * its actually valid to read 0 bytes. - * - * - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { + ESockDescriptor* descP; + ERL_NIF_TERM res; - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - */ + ESOCK_ASSERT( argc == 1 ); - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); + SGDBG( ("SOCKET", "nif_sockname -> entry with argc: %d\r\n", argc) ); - FREE_BIN(bufP); + /* Extract arguments and perform preliminary validation */ - return esock_make_error(env, atom_closed); + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); } - if (read < 0) { - - /* +++ Error handling +++ */ - - res = recv_check_fail(env, descP, saveErrno, bufP, NULL, - sockRef, recvRef); - - } else { - - /* +++ We sucessfully got a message - time to encode the address +++ */ - - ERL_NIF_TERM eSockAddr; - - esock_encode_sockaddr(env, - fromAddrP, fromAddrLen, - &eSockAddr); - - if (read == bufP->size) { - - data = MKBIN(env, bufP); - - } else { - - /* +++ We got a chunk of data but +++ - * +++ since we did not fill the +++ - * +++ buffer, we must split it +++ - * +++ into a sub-binary. +++ - */ + MLOCK(descP->readMtx); - data = MKBIN(env, bufP); - data = MKSBIN(env, data, 0, read); - } + SSDBG( descP, + ("SOCKET", "nif_sockname(%T) {%d}" + "\r\n", argv[0], descP->sock) ); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, - &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); + res = ESOCK_IO_SOCKNAME(env, descP); - recv_update_current_reader(env, descP, sockRef); - - res = esock_make_ok2(env, MKT2(env, eSockAddr, data)); + SSDBG( descP, + ("SOCKET", "nif_sockname(%T) {%d} -> done with res = %T\r\n", + argv[0], descP->sock, res) ); - } + MUNLOCK(descP->readMtx); return res; - } -#endif // #ifndef __WIN32__ -/* *** recvmsg_check_result *** - * - * The recvmsg function delivers one (1) message. If our buffer - * is to small, the message will be truncated. So, regardless - * if we filled the buffer or not, we have got what we are going - * to get regarding this message. +/* ======================================================================== */ -#ifndef __WIN32__ + static -ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - int saveErrno, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef) +ERL_NIF_TERM esock_sockname(ErlNifEnv* env, + ESockDescriptor* descP) { - ERL_NIF_TERM res; + ESockAddress sa; + ESockAddress* saP = &sa; +#ifdef __WIN32__ + int sz = sizeof(ESockAddress); +#else + SOCKLEN_T sz = sizeof(ESockAddress); +#endif + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + SSDBG( descP, - ("SOCKET", "recvmsg_check_result(%T) {%d} -> entry with" - "\r\n read: %ld" - "\r\n saveErrno: %d" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, - (long) read, saveErrno, recvRef) ); - - - /* - * - * We need to handle read = 0 for non_stream socket type(s) when - * its actually valid to read 0 bytes. - * - * - */ - - if ((read == 0) && (descP->type == SOCK_STREAM)) { - - /* - * When a stream socket peer has performed an orderly shutdown, - * the return value will be 0 (the traditional "end-of-file" return). - * - * *We* do never actually try to read 0 bytes! - */ - - ESOCK_CNT_INC(env, descP, sockRef, - atom_read_fails, &descP->readFails, 1); - - FREE_BIN(dataBufP); FREE_BIN(ctrlBufP); - - return esock_make_error(env, atom_closed); - } - - - if (read < 0) { - - /* +++ Error handling +++ */ - - res = recv_check_fail(env, descP, saveErrno, dataBufP, ctrlBufP, - sockRef, recvRef); + ("SOCKET", "esock_sockname {%d} -> open - try get sockname\r\n", + descP->sock) ); + sys_memzero((char*) saP, sz); + if (sock_name(descP->sock, (struct sockaddr*) saP, &sz) < 0) { + return esock_make_error_errno(env, sock_errno()); } else { + ERL_NIF_TERM esa; - /* +++ We sucessfully got a message - time to encode it +++ */ - - res = recvmsg_check_msg(env, descP, read, msgHdrP, - dataBufP, ctrlBufP, sockRef); + SSDBG( descP, + ("SOCKET", "esock_sockname {%d} -> " + "got sockname - try decode\r\n", + descP->sock) ); - } + esock_encode_sockaddr(env, saP, (SOCKLEN_T) sz, &esa); - return res; + SSDBG( descP, + ("SOCKET", "esock_sockname {%d} -> decoded: " + "\r\n %T\r\n", + descP->sock, esa) ); + return esock_make_ok2(env, esa); + } } -#endif // #ifndef __WIN32__ -/* *** recvmsg_check_msg *** + +/* ---------------------------------------------------------------------- + * nif_peername - get name of the connected peer socket + * + * Description: + * Returns the address of the peer connected to the socket. * - * We successfully read one message. Time to process. + * Arguments: + * Socket (ref) - Points to the socket descriptor. */ -#ifndef __WIN32__ + static -ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM sockRef) +ERL_NIF_TERM nif_peername(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eMsg; + ESockDescriptor* descP; + ERL_NIF_TERM res; - /* - * - * - * The return value of recvmsg is the *total* number of bytes - * that where successfully read. This data has been put into - * the *IO vector*. - * - * - */ + ESOCK_ASSERT( argc == 1 ); - encode_msg(env, descP, - read, msgHdrP, dataBufP, ctrlBufP, - &eMsg); + SGDBG( ("SOCKET", "nif_peername -> entry with argc: %d\r\n", argc) ); - SSDBG( descP, - ("SOCKET", "recvmsg_check_result(%T) {%d} -> ok\r\n", - sockRef, descP->sock) ); + /* Extract arguments and perform preliminary validation */ - ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1); - ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, - &descP->readByteCnt, read); + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + return enif_make_badarg(env); + } - recv_update_current_reader(env, descP, sockRef); + MLOCK(descP->readMtx); - return esock_make_ok2(env, eMsg); -} -#endif // #ifndef __WIN32__ + SSDBG( descP, + ("SOCKET", "nif_peername(%T) {%d}" + "\r\n", argv[0], descP->sock) ); + res = ESOCK_IO_PEERNAME(env, descP); -/* +++ encode_msg +++ - * - * Encode a msg() (recvmsg). In erlang its represented as - * a map, which has a specific set of attributes: - * - * addr (source address) - sockaddr() - * iov - [binary()] - * ctrl - [cmsg()] - * flags - msg_flags() - */ -#ifndef __WIN32__ -static -void encode_msg(ErlNifEnv* env, - ESockDescriptor* descP, - ssize_t read, - struct msghdr* msgHdrP, - ErlNifBinary* dataBufP, - ErlNifBinary* ctrlBufP, - ERL_NIF_TERM* eSockAddr) -{ - ERL_NIF_TERM addr, iov, ctrl, flags; + SSDBG( descP, + ("SOCKET", "nif_peername(%T) {%d} -> done with res = %T\r\n", + argv[0], descP->sock, res) ); - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> entry with" - "\r\n read: %ld" - "\r\n", descP->sock, (long) read) ); + MUNLOCK(descP->readMtx); - /* The address is not used if we are connected (unless, maybe, - * family is 'local'), so check (length = 0) before we try to encodel - */ - if (msgHdrP->msg_namelen != 0) { - esock_encode_sockaddr(env, - (ESockAddress*) msgHdrP->msg_name, - msgHdrP->msg_namelen, - &addr); - } else { - addr = esock_atom_undefined; - } + return res; +} - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> encode iov" - "\r\n msg_iovlen: %lu" - "\r\n", - descP->sock, - (unsigned long) msgHdrP->msg_iovlen) ); - esock_encode_iov(env, read, - msgHdrP->msg_iov, msgHdrP->msg_iovlen, dataBufP, - &iov); - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> try encode cmsgs\r\n", - descP->sock) ); +/* ======================================================================== + */ - encode_cmsgs(env, descP, ctrlBufP, msgHdrP, &ctrl); +static +ERL_NIF_TERM esock_peername(ErlNifEnv* env, + ESockDescriptor* descP) +{ + ESockAddress sa; + ESockAddress* saP = &sa; +#ifdef __WIN32__ + int sz = sizeof(ESockAddress); +#else + SOCKLEN_T sz = sizeof(ESockAddress); +#endif - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> try encode flags\r\n", - descP->sock) ); + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); - encode_msg_flags(env, descP, msgHdrP->msg_flags, &flags); + SSDBG( descP, + ("SOCKET", "esock_peername {%d} -> open - try get peername (%d)\r\n", + descP->sock, sz) ); - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> components encoded:" - "\r\n addr: %T" - "\r\n ctrl: %T" - "\r\n flags: %T" - "\r\n", descP->sock, addr, ctrl, flags) ); + sys_memzero((char*) saP, sz); + if (sock_peer(descP->sock, (struct sockaddr*) saP, &sz) < 0) { + return esock_make_error_errno(env, sock_errno()); + } else { + ERL_NIF_TERM esa; - { - ERL_NIF_TERM keys[] = {esock_atom_iov, - esock_atom_ctrl, - esock_atom_flags, - esock_atom_addr}; - ERL_NIF_TERM vals[] = {iov, ctrl, flags, addr}; - size_t numKeys = NUM(keys); - - ESOCK_ASSERT( numKeys == NUM(vals) ); - - SSDBG( descP, - ("SOCKET", - "encode_msg {%d} -> create map\r\n", - descP->sock) ); + SSDBG( descP, + ("SOCKET", "esock_peername {%d} -> " + "got peername (%d) - try decode\r\n", + descP->sock, sz) ); - if (msgHdrP->msg_namelen == 0) - numKeys--; // No addr - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eSockAddr) ); + esock_encode_sockaddr(env, saP, (SOCKLEN_T) sz, &esa); - SSDBG( descP, - ("SOCKET", - "encode_msg {%d}-> map encoded\r\n", - descP->sock) ); - } + SSDBG( descP, + ("SOCKET", "esock_peername {%d} -> decoded: " + "\r\n %T\r\n", + descP->sock, esa) ); - SSDBG( descP, - ("SOCKET", "encode_msg {%d} -> done\r\n", descP->sock) ); + return esock_make_ok2(env, esa); + } } -#endif // #ifndef __WIN32__ -/* +++ encode_cmsgs +++ - * - * Encode a list of cmsg(). There can be 0 or more cmsghdr "blocks". - * - * Our "problem" is that we have no idea how many control messages - * we have. - * - * The cmsgHdrP arguments points to the start of the control data buffer, - * an actual binary. Its the only way to create sub-binaries. So, what we - * need to continue processing this is to turn that into an binary erlang - * term (which can then in turn be turned into sub-binaries). +/* ---------------------------------------------------------------------- + * nif_ioctl - control device - get * - * We need the cmsgBufP (even though cmsgHdrP points to it) to be able - * to create sub-binaries (one for each cmsg hdr). + * Description: + * Returns whatever info the ioctl returns for the specific (get) request. + * WHEN SET IS IMPLEMENTED, WE NED ANOTHER ARGUMENT!! * - * The TArray (term array) is created with the size of 128, which should - * be enough. But if its not, then it will be automatically realloc'ed during - * add. Once we are done adding hdr's to it, we convert the tarray to a list. + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Request - The ioctl get/set request + * NameOrIdx - Name or Index of the interface - only for some requests + * Currently only one (get) request does not provide this + * (and the value) argument; gifconf + * Currently, only one (get) request use index; gifname + * All other requests (get and set) use Name as "key". + * Val - Value to *set* + * This argument is *only* provided for set requests. */ -#ifndef __WIN32__ + static -void encode_cmsgs(ErlNifEnv* env, - ESockDescriptor* descP, - ErlNifBinary* cmsgBinP, - struct msghdr* msgHdrP, - ERL_NIF_TERM* eCMsg) +ERL_NIF_TERM nif_ioctl(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM ctrlBuf = MKBIN(env, cmsgBinP); // The *entire* binary - SocketTArray cmsghdrs = TARRAY_CREATE(128); - struct cmsghdr* firstP = CMSG_FIRSTHDR(msgHdrP); - struct cmsghdr* currentP; - - SSDBG( descP, ("SOCKET", "encode_cmsgs {%d} -> entry when" - "\r\n msg ctrl len: %d" - "\r\n (ctrl) firstP: 0x%lX" - "\r\n", descP->sock, - msgHdrP->msg_controllen, firstP) ); - - for (currentP = firstP; - /* - * In *old* versions of darwin, the CMSG_FIRSTHDR does not - * check the msg_controllen, so we do it here. - * We should really test this stuff during configure, - * but for now, this will have to do. - */ -#if defined(__DARWIN__) - (msgHdrP->msg_controllen >= sizeof(struct cmsghdr)) && - (currentP != NULL); -#else - (currentP != NULL); -#endif - currentP = CMSG_NXTHDR(msgHdrP, currentP)) { + ESockDescriptor* descP; + ERL_NIF_TERM res; + unsigned long req; - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> process cmsg header when" - "\r\n TArray Size: %d" - "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + SGDBG( ("SOCKET", "nif_ioctl -> entry with argc: %d\r\n", argc) ); - /* MUST check this since on Linux the returned "cmsg" may actually - * go too far! - */ - if (((CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP)) > - msgHdrP->msg_controllen) { + ESOCK_ASSERT( (argc == 2) || (argc == 3) || (argc == 4) ); - /* Ouch, fatal error - give up - * We assume we cannot trust any data if this is wrong. - */ + if (! ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) { + SGDBG( ("SOCKET", "nif_ioctl -> no resource\r\n") ); + return enif_make_badarg(env); + } - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> check failed when: " - "\r\n currentP: 0x%lX" - "\r\n (current) cmsg_len: %d" - "\r\n firstP: 0x%lX" - "\r\n => %d" - "\r\n msg ctrl len: %d" - "\r\n", descP->sock, - CHARP(currentP), currentP->cmsg_len, CHARP(firstP), - (CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP), - msgHdrP->msg_controllen) ); - - TARRAY_ADD(cmsghdrs, esock_atom_bad_data); - break; - - } else { - unsigned char* dataP = UCHARP(CMSG_DATA(currentP)); - size_t dataPos = dataP - cmsgBinP->data; - size_t dataLen = - (UCHARP(currentP) + currentP->cmsg_len) - dataP; - ERL_NIF_TERM - cmsgHdr, - keys[] = - {esock_atom_level, - esock_atom_type, - esock_atom_data, - atom_value}, - vals[NUM(keys)]; - size_t numKeys = NUM(keys); - BOOLEAN_T have_value; + if (! GET_ULONG(env, argv[1], &req)) { + SGDBG( ("SOCKET", "nif_ioctl -> 'request' not 'unsigned long'\r\n") ); + return enif_make_badarg(env); + } - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> cmsg header data: " - "\r\n dataPos: %d" - "\r\n dataLen: %d" - "\r\n", descP->sock, dataPos, dataLen) ); - - vals[0] = esock_encode_level(env, currentP->cmsg_level); - vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); - have_value = - encode_cmsg(env, - currentP->cmsg_level, - currentP->cmsg_type, - dataP, dataLen, &vals[1], &vals[3]); + SSDBG( descP, + ("SOCKET", "nif_ioctl(%T) {%d} -> ioctl request %d" + "\r\n", argv[0], descP->sock, req) ); - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> " - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n %T: %T" - "\r\n", descP->sock, - keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); - if (have_value) - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> " - "\r\n %T: %T" - "\r\n", descP->sock, keys[3], vals[3]) ); - - /* Guard agains cut-and-paste errors */ - ESOCK_ASSERT( numKeys == NUM(vals) ); - ESOCK_ASSERT( MKMA(env, keys, vals, - numKeys - (have_value ? 0 : 1), &cmsgHdr) ); - - /* And finally add it to the list... */ - TARRAY_ADD(cmsghdrs, cmsgHdr); - } - } + /* Is this really enough? Why not the write mutex also? */ + MLOCK(descP->readMtx); - SSDBG( descP, - ("SOCKET", "encode_cmsgs {%d} -> cmsg headers processed when" - "\r\n TArray Size: %d" - "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + if (! IS_OPEN(descP->readState)) { + res = esock_make_error_closed(env); + } else { - /* The tarray is populated - convert it to a list */ - TARRAY_TOLIST(cmsghdrs, env, eCMsg); + switch (argc) { + case 2: + /* Only one request with this number of arguments: gifconf + * Socket and request (=gifconf) + */ + + /* Two arguments: socket and request */ + res = ESOCK_IO_IOCTL_2(env, descP, req); + break; + + case 3: + /* (Currently) All *other* get requests has 3 arguments + * Socket, request and name/index + */ + { + ERL_NIF_TERM earg = argv[2]; + + /* Three arguments: socket, request and arg */ + res = ESOCK_IO_IOCTL_3(env, descP, req, earg); + } + break; + + case 4: + /* (Currently) Set requests has 4 arguments + * Socket, request, name and value + */ + { + ERL_NIF_TERM earg1 = argv[2]; // (currently) Name + ERL_NIF_TERM earg2 = argv[3]; // Value + + res = ESOCK_IO_IOCTL_4(env, descP, req, earg1, earg2); + } + break; + + default: + /* This is just to protect against programming errors, + * since we have an assert above! + */ + res = esock_make_error(env, esock_atom_einval); + break; + } + } + + MUNLOCK(descP->readMtx); + + SSDBG( descP, + ("SOCKET", "nif_ioctl(%T) {%d} -> done with res = %T\r\n", + argv[0], descP->sock, res) ); + + return res; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#ifdef SCM_TIMESTAMP + +/* ---------------------------------------------------------------------- + * nif_cancel + * + * Description: + * Cancel a previous select! + * + * Arguments: + * Socket (ref) - Points to the socket descriptor. + * Operation (atom) - What kind of operation (accept, send, ...) + * is to be cancelled + * Ref (ref) - Unique id for the operation + */ static -BOOLEAN_T esock_cmsg_encode_timeval(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - struct timeval* timeP = (struct timeval *) data; +ERL_NIF_TERM nif_cancel(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ + ESockDescriptor* descP; + ERL_NIF_TERM op, sockRef, opRef; - if (dataLen < sizeof(*timeP)) - return FALSE; + ESOCK_ASSERT( argc == 3 ); - esock_encode_timeval(env, timeP, eResult); - return TRUE; -} + SGDBG( ("SOCKET", "nif_cancel -> entry with argc: %d\r\n", argc) ); -static BOOLEAN_T esock_cmsg_decode_timeval(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) -{ - struct timeval time, *timeP; + /* Extract arguments and perform preliminary validation */ - if (! esock_decode_timeval(env, eValue, &time)) - return FALSE; + sockRef = argv[0]; + if (! ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) { + return enif_make_badarg(env); + } + op = argv[1]; + opRef = argv[2]; + if ((! IS_ATOM(env, op)) || + (! enif_is_ref(env, opRef))) { + return enif_make_badarg(env); + } - if ((timeP = init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL) - return FALSE; + return esock_cancel(env, descP, op, sockRef, opRef); - *timeP = time; - return TRUE; } -#endif -#endif -#ifndef __WIN32__ -#if defined(IP_TOS) || defined(IP_RECVTOS) static -BOOLEAN_T esock_cmsg_encode_ip_tos(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) +ERL_NIF_TERM esock_cancel(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM op, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) { - unsigned char tos; - - if (dataLen < sizeof(tos)) - return FALSE; - - tos = *data; + ERL_NIF_TERM result; + int cmp; - *eResult = encode_ip_tos(env, tos); - return TRUE; -} + /* + * + * Do we really need all these variants? Should it not be enough with: + * + * connect | accept | send | recv + * + * + */ -static BOOLEAN_T esock_cmsg_decode_ip_tos(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) -{ - int tos, *tosP; + /* Hand crafted binary search */ + if ((cmp = COMPARE(op, esock_atom_recvmsg)) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } + if (cmp < 0) { + if ((cmp = COMPARE(op, esock_atom_recv)) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } + if (cmp < 0) { + if (COMPARE(op, esock_atom_connect) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_CONNECT(env, descP, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + if (COMPARE(op, esock_atom_accept) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_ACCEPT(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } + } else { + if (COMPARE(op, esock_atom_recvfrom) == 0) { + MLOCK(descP->readMtx); + result = ESOCK_IO_CANCEL_RECV(env, descP, sockRef, opRef); + MUNLOCK(descP->readMtx); + return result; + } + } + } else { + if ((cmp = COMPARE(op, esock_atom_sendmsg)) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + if (cmp < 0) { + if (COMPARE(op, esock_atom_send) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + if (COMPARE(op, esock_atom_sendfile) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + } else { + if (COMPARE(op, esock_atom_sendto) == 0) { + MLOCK(descP->writeMtx); + result = ESOCK_IO_CANCEL_SEND(env, descP, sockRef, opRef); + MUNLOCK(descP->writeMtx); + return result; + } + } + } - if (! decode_ip_tos(env, eValue, &tos)) - return FALSE; + { + const char *reason; - if ((tosP = init_cmsghdr(cmsgP, rem, sizeof(*tosP), usedP)) == NULL) - return FALSE; + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); - *tosP = tos; - return TRUE; -} -#endif // #ifdef IP_TOS -#endif // #ifdef __WIN32__ + if (! IS_OPEN(descP->readState)) { + result = esock_make_error_closed(env); + reason = "closed"; + } else { + result = enif_make_badarg(env); + reason = "badarg"; + } -#ifndef __WIN32__ -#if defined(IP_TTL) || \ - defined(IPV6_HOPLIMIT) || \ - defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS) -static -BOOLEAN_T esock_cmsg_encode_int(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - int value; + SSDBG( descP, + ("SOCKET", "esock_cancel(%T), {%d,0x%X} -> %s" + "\r\n", + sockRef, descP->sock, + descP->readState | descP->writeState, reason) ); - if (dataLen < sizeof(value)) - return FALSE; + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); - value = *((int *) data); - *eResult = MKI(env, value); - return TRUE; + return result; + } } -static BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) -{ - int value, *valueP; - if (! GET_INT(env, eValue, &value)) - return FALSE; +#ifndef __WIN32__ +extern +ERL_NIF_TERM esock_cancel_read_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef) +{ + return esock_cancel_mode_select(env, descP, opRef, + ERL_NIF_SELECT_READ, + ERL_NIF_SELECT_READ_CANCELLED); +} +#endif // #ifndef __WIN32__ - if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL) - return FALSE; - *valueP = value; - return TRUE; +#ifndef __WIN32__ +extern +ERL_NIF_TERM esock_cancel_write_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef) +{ + return esock_cancel_mode_select(env, descP, opRef, + ERL_NIF_SELECT_WRITE, + ERL_NIF_SELECT_WRITE_CANCELLED); } -#endif -#endif +#endif // #ifndef __WIN32__ #ifndef __WIN32__ -static BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv *env, - ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, - size_t rem, - size_t *usedP) +extern +ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + int smode, + int rmode) { - BOOLEAN_T v; - int *valueP; + /* Assumes cancelling only one mode */ - if (! esock_decode_bool(eValue, &v)) - return FALSE; + int selectRes = esock_select_cancel(env, descP->sock, smode, descP); - if ((valueP = init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP)) == NULL) - return FALSE; + if (selectRes >= 0) { + /* Success */ + if ((selectRes & rmode) != 0) { + /* Was cancelled */ + return esock_atom_ok; + } else { + /* Has already sent the message */ + return esock_make_error(env, esock_atom_select_sent); + } + } else { + /* Stopped? */ + SSDBG( descP, + ("SOCKET", + "esock_cancel_mode_select {%d} -> failed: %d (0x%lX)" + "\r\n", descP->sock, selectRes, selectRes) ); - *valueP = v? 1 : 0; - return TRUE; + return esock_make_error(env, esock_atom_not_found); + } } -#endif - +#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -#ifdef IP_RECVTTL -static -BOOLEAN_T esock_cmsg_encode_uchar(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - unsigned char value; - if (dataLen < sizeof(value)) - return FALSE; - value = *data; - *eResult = MKUI(env, value); - return TRUE; -} -#endif -#endif +/* ---------------------------------------------------------------------- + * U t i l i t y F u n c t i o n s + * ---------------------------------------------------------------------- + */ -#ifndef __WIN32__ -#ifdef IP_PKTINFO -static -BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - struct in_pktinfo* pktInfoP = (struct in_pktinfo*) data; - ERL_NIF_TERM ifIndex; - ERL_NIF_TERM specDst, addr; +extern +BOOLEAN_T esock_encode_cmsg(ErlNifEnv* env, + int level, + int type, + unsigned char* dataP, + size_t dataLen, + ERL_NIF_TERM* eType, + ERL_NIF_TERM* eData) +{ + const ESockCmsgSpec *cmsgTable; + size_t num; - if (dataLen < sizeof(*pktInfoP)) - return FALSE; + if ((cmsgTable = esock_lookup_cmsg_table(level, &num)) != NULL) { + size_t n; - ifIndex = MKUI(env, pktInfoP->ipi_ifindex); - esock_encode_in_addr(env, &pktInfoP->ipi_spec_dst, &specDst); - esock_encode_in_addr(env, &pktInfoP->ipi_addr, &addr); + /* Linear search for type number in level table + */ + for (n = 0; n < num; n++) { + if (cmsgTable[n].type == type) { + /* Found the type number in the level table; + * return the symbolic type (atom) + * and try to encode the data + */ - { - ERL_NIF_TERM keys[] = {esock_atom_ifindex, - esock_atom_spec_dst, - esock_atom_addr}; - ERL_NIF_TERM vals[] = {ifIndex, specDst, addr}; - unsigned int numKeys = NUM(keys); - unsigned int numVals = NUM(vals); + *eType = *cmsgTable[n].nameP; - ESOCK_ASSERT( numKeys == numVals ); - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eResult) ); + if (cmsgTable[n].encode != NULL) + return cmsgTable[n].encode(env, dataP, dataLen, eData); + else + return FALSE; + } + } } - return TRUE; -} -#endif -#endif - -#ifndef __WIN32__ -#ifdef IP_ORIGDSTADDR -static -BOOLEAN_T esock_cmsg_encode_sockaddr(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - SOCKLEN_T addrLen = (SOCKLEN_T) dataLen; + /* No level table, or unknown type number in the table; + * just return the type number as an erlang integer + */ - if (addrLen != dataLen) - return FALSE; + *eType = MKI(env, type); - esock_encode_sockaddr(env, - (ESockAddress*) data, - addrLen, - eResult); - return TRUE; + return FALSE; } -#endif -#endif -#ifndef __WIN32__ -#ifdef HAVE_LINUX_ERRQUEUE_H -#if defined(IP_RECVERR) || defined(IPV6_RECVERR) -/* +++ encode_cmsg_encode_recverr +++ + +/* +++ esock_encode_msg_flags +++ * - * Encode the extended socker error in the data part of the cmsg(). + * Encode a list of msg_flag(). * */ -static -BOOLEAN_T esock_cmsg_encode_recverr(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eCMsgData) + +extern +void esock_encode_msg_flags(ErlNifEnv* env, + ESockDescriptor* descP, + int msgFlags, + ERL_NIF_TERM* flags) { - struct sock_extended_err *sock_err = (struct sock_extended_err *) data; - struct sockaddr *offender; - BOOLEAN_T have_offender = FALSE; - ERL_NIF_TERM - ee_errno, ee_origin, ee_type, ee_code, ee_info, ee_data, - eSockAddr; + SSDBG( descP, + ("SOCKET", "encode_msg_flags {%d} -> entry with" + "\r\n msgFlags: %d (0x%lX)" + "\r\n", descP->sock, msgFlags, msgFlags) ); - if (dataLen < sizeof(*sock_err)) - return FALSE; + if (msgFlags == 0) { + *flags = MKEL(env); + } else { + size_t n; + SocketTArray ta = TARRAY_CREATE(10); // Just to be on the safe side - offender = SO_EE_OFFENDER(sock_err); - ee_errno = MKA(env, erl_errno_id(sock_err->ee_errno)); - ee_info = MKI(env, sock_err->ee_info); - ee_data = MKI(env, sock_err->ee_data); + for (n = 0; n < esock_msg_flags_length; n++) { + int f = esock_msg_flags[n].flag; + if ((f != 0) && ((msgFlags & f) == f)) { + msgFlags &= ~f; + TARRAY_ADD(ta, *(esock_msg_flags[n].name)); + } + if (msgFlags == 0) goto done; + } + /* Append remaining flags as an integer */ + if (msgFlags != 0) + TARRAY_ADD(ta, MKI(env, msgFlags)); - switch (sock_err->ee_origin) { -#if defined(SO_EE_ORIGIN_NONE) - case SO_EE_ORIGIN_NONE: - ee_origin = atom_none; - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; -#endif + done: + SSDBG( descP, + ("SOCKET", "encode_msg_flags {%d} -> flags processed when" + "\r\n TArray size: %d" + "\r\n", descP->sock, TARRAY_SZ(ta)) ); -#if defined(SO_EE_ORIGIN_LOCAL) - case SO_EE_ORIGIN_LOCAL: - ee_origin = esock_atom_local; - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; -#endif + TARRAY_TOLIST(ta, env, flags); + } +} -#if defined(SO_EE_ORIGIN_ICMP) - case SO_EE_ORIGIN_ICMP: - ee_origin = esock_atom_icmp; - switch (sock_err->ee_type) { -#if defined(ICMP_DEST_UNREACH) - case ICMP_DEST_UNREACH: - ee_type = atom_dest_unreach; - switch (sock_err->ee_code) { +#ifdef SCM_TIMESTAMP +static +BOOLEAN_T esock_cmsg_encode_timeval(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) { + struct timeval* timeP = (struct timeval *) data; -#if defined(ICMP_NET_UNREACH) - case ICMP_NET_UNREACH: - ee_code = atom_net_unreach; - break; -#endif + if (dataLen < sizeof(*timeP)) + return FALSE; -#if defined(ICMP_HOST_UNREACH) - case ICMP_HOST_UNREACH: - ee_code = atom_host_unreach; - break; -#endif + esock_encode_timeval(env, timeP, eResult); + return TRUE; +} -#if defined(ICMP_PORT_UNREACH) - case ICMP_PORT_UNREACH: - ee_code = atom_port_unreach; - break; -#endif +static BOOLEAN_T esock_cmsg_decode_timeval(ErlNifEnv *env, + ERL_NIF_TERM eValue, + struct cmsghdr *cmsgP, + size_t rem, + size_t *usedP) +{ + struct timeval time, *timeP; -#if defined(ICMP_FRAG_NEEDED) - case ICMP_FRAG_NEEDED: - ee_code = atom_frag_needed; - break; -#endif + if (! esock_decode_timeval(env, eValue, &time)) + return FALSE; -#if defined(ICMP_NET_UNKNOWN) - case ICMP_NET_UNKNOWN: - ee_code = atom_net_unknown; - break; + if ((timeP = esock_init_cmsghdr(cmsgP, rem, sizeof(*timeP), usedP)) == NULL) + return FALSE; + + *timeP = time; + return TRUE; +} #endif -#if defined(ICMP_HOST_UNKNOWN) - case ICMP_HOST_UNKNOWN: - ee_code = atom_host_unknown; - break; -#endif - default: - ee_code = MKI(env, sock_err->ee_code); - break; - } - break; -#endif // ICMP_DEST_UNREACH +#if defined(IP_TOS) || defined(IP_RECVTOS) +static +BOOLEAN_T esock_cmsg_encode_ip_tos(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) +{ + unsigned char tos; -#if defined(ICMP_TIME_EXCEEDED) - case ICMP_TIME_EXCEEDED: - ee_type = atom_time_exceeded; - ee_code = MKI(env, sock_err->ee_code); - break; -#endif + if (dataLen < sizeof(tos)) + return FALSE; - default: - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; - } - break; -#endif // SO_EE_ORIGIN_ICMP + tos = *data; -#if defined(SO_EE_ORIGIN_ICMP6) - case SO_EE_ORIGIN_ICMP6: - ee_origin = esock_atom_icmp6; - switch (sock_err->ee_type) { + *eResult = encode_ip_tos(env, tos); + return TRUE; +} -#if defined(ICMPV6_DEST_UNREACH) - case ICMPV6_DEST_UNREACH: - ee_type = atom_dest_unreach; - switch (sock_err->ee_code) { +static BOOLEAN_T esock_cmsg_decode_ip_tos(ErlNifEnv *env, + ERL_NIF_TERM eValue, + struct cmsghdr *cmsgP, + size_t rem, + size_t *usedP) +{ + int tos, *tosP; -#if defined(ICMPV6_NOROUTE) - case ICMPV6_NOROUTE: - ee_code = atom_noroute; - break; -#endif -#if defined(ICMPV6_ADM_PROHIBITED) - case ICMPV6_ADM_PROHIBITED: - ee_code = atom_adm_prohibited; - break; -#endif + if (! decode_ip_tos(env, eValue, &tos)) + return FALSE; -#if defined(ICMPV6_NOT_NEIGHBOUR) - case ICMPV6_NOT_NEIGHBOUR: - ee_code = atom_not_neighbour; - break; -#endif + if ((tosP = esock_init_cmsghdr(cmsgP, rem, sizeof(*tosP), usedP)) == NULL) + return FALSE; -#if defined(ICMPV6_ADDR_UNREACH) - case ICMPV6_ADDR_UNREACH: - ee_code = atom_addr_unreach; - break; -#endif + *tosP = tos; + return TRUE; +} +#endif // #ifdef IP_TOS -#if defined(ICMPV6_PORT_UNREACH) - case ICMPV6_PORT_UNREACH: - ee_code = atom_port_unreach; - break; -#endif -#if defined(ICMPV6_POLICY_FAIL) - case ICMPV6_POLICY_FAIL: - ee_code = atom_policy_fail; - break; -#endif +#if defined(IP_TTL) || \ + defined(IPV6_HOPLIMIT) || \ + defined(IPV6_TCLASS) || defined(IPV6_RECVTCLASS) +static +BOOLEAN_T esock_cmsg_encode_int(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) { + int value; -#if defined(ICMPV6_REJECT_ROUTE) - case ICMPV6_REJECT_ROUTE: - ee_code = atom_reject_route; - break; -#endif + if (dataLen < sizeof(value)) + return FALSE; - default: - ee_code = MKI(env, sock_err->ee_code); - break; - } - break; -#endif // ICMPV6_DEST_UNREACH + value = *((int *) data); + *eResult = MKI(env, value); + return TRUE; +} -#if defined(ICMPV6_PKT_TOOBIG) - case ICMPV6_PKT_TOOBIG: - ee_type = atom_pkt_toobig; - ee_code = MKI(env, sock_err->ee_code); - break; -#endif +extern +BOOLEAN_T esock_cmsg_decode_int(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP) +{ + int value, *valueP; -#if defined(ICMPV6_TIME_EXCEED) - case ICMPV6_TIME_EXCEED: - ee_type = atom_time_exceeded; - ee_code = MKI(env, sock_err->ee_code); - break; -#endif + if (! GET_INT(env, eValue, &value)) + return FALSE; - default: - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; - } - break; -#endif // SO_EE_ORIGIN_ICMP6 + valueP = esock_init_cmsghdr(cmsgP, rem, sizeof(*valueP), usedP); + if (valueP == NULL) + return FALSE; -#if defined(SO_EE_ORIGIN_TXSTATUS) - case SO_EE_ORIGIN_TXSTATUS: - ee_origin = atom_txstatus; - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; + *valueP = value; + return TRUE; +} #endif -#if defined(SO_EE_ORIGIN_ZEROCOPY) - case SO_EE_ORIGIN_ZEROCOPY: - ee_origin = atom_zerocopy; - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; -#endif -#if defined(SO_EE_ORIGIN_TXTIME) - case SO_EE_ORIGIN_TXTIME: - ee_origin = atom_txtime; - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; -#endif +extern +BOOLEAN_T esock_cmsg_decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eValue, + struct cmsghdr* cmsgP, + size_t rem, + size_t* usedP) +{ + BOOLEAN_T v; + int* valueP; - default: - ee_origin = MKI(env, sock_err->ee_origin); - ee_type = MKI(env, sock_err->ee_type); - ee_code = MKI(env, sock_err->ee_code); - break; - } + if (! esock_decode_bool(eValue, &v)) + return FALSE; - have_offender = CHARP(sock_err) + dataLen > CHARP(offender); - if (have_offender) { - esock_encode_sockaddr(env, - (ESockAddress *)offender, - (CHARP(sock_err) + dataLen ) - CHARP(offender), - &eSockAddr); - } else { - eSockAddr = esock_atom_undefined; - } + if ((valueP = esock_init_cmsghdr(cmsgP, rem, + sizeof(*valueP), usedP)) == NULL) + return FALSE; - { - ERL_NIF_TERM keys[] = {esock_atom_error, - atom_origin, - esock_atom_type, - atom_code, - esock_atom_info, - esock_atom_data, - atom_offender}; - ERL_NIF_TERM vals[] = {ee_errno, - ee_origin, - ee_type, - ee_code, - ee_info, - ee_data, - eSockAddr}; - unsigned int numKeys = NUM(keys); - unsigned int numVals = NUM(vals); + *valueP = v? 1 : 0; + return TRUE; +} - ESOCK_ASSERT( numKeys == numVals ); - if (! have_offender) numKeys--; - ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eCMsgData) ); - } + +#ifdef IP_RECVTTL +static +BOOLEAN_T esock_cmsg_encode_uchar(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) { + unsigned char value; + + if (dataLen < sizeof(value)) + return FALSE; + + value = *data; + *eResult = MKUI(env, value); return TRUE; } -#endif // #if defined(IP_RECVERR) || defined(IPV6_RECVERR) -#endif // #ifdef HAVE_LINUX_ERRQUEUE_H -#endif // #ifndef __WIN32__ +#endif -#ifndef __WIN32__ -#ifdef IPV6_PKTINFO + +#ifdef IP_PKTINFO static -BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env, - unsigned char *data, - size_t dataLen, - ERL_NIF_TERM *eResult) { - struct in6_pktinfo* pktInfoP = (struct in6_pktinfo*) data; - ERL_NIF_TERM ifIndex, addr; +BOOLEAN_T esock_cmsg_encode_in_pktinfo(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) +{ + struct in_pktinfo* pktInfoP = (struct in_pktinfo*) data; + ERL_NIF_TERM ifIndex; + ERL_NIF_TERM specDst, addr; if (dataLen < sizeof(*pktInfoP)) return FALSE; - ifIndex = MKI(env, pktInfoP->ipi6_ifindex); - esock_encode_in6_addr(env, &pktInfoP->ipi6_addr, &addr); + + ifIndex = MKUI(env, pktInfoP->ipi_ifindex); +#ifndef __WIN32__ + /* On Windows, the field ipi_spec_dst does not exist */ + esock_encode_in_addr(env, &pktInfoP->ipi_spec_dst, &specDst); +#endif + esock_encode_in_addr(env, &pktInfoP->ipi_addr, &addr); + { - ERL_NIF_TERM keys[] = {esock_atom_addr, esock_atom_ifindex}; - ERL_NIF_TERM vals[] = {addr, ifIndex}; + ERL_NIF_TERM keys[] = {esock_atom_ifindex, + esock_atom_spec_dst, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {ifIndex, +#ifndef __WIN32__ + specDst, +#else + esock_atom_undefined, +#endif + addr}; unsigned int numKeys = NUM(keys); unsigned int numVals = NUM(vals); @@ -17126,647 +10823,531 @@ BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env, return TRUE; } #endif -#endif - #ifndef __WIN32__ +#ifdef IP_ORIGDSTADDR +static +BOOLEAN_T esock_cmsg_encode_sockaddr(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) { + SOCKLEN_T addrLen = (SOCKLEN_T) dataLen; -struct ESockCmsgSpec { - int type; // Message type - - // Function to encode into erlang term - BOOLEAN_T (* encode) - (ErlNifEnv *env, unsigned char *data, size_t dataLen, - ERL_NIF_TERM *eResult); - - // Function to decode from erlang term - BOOLEAN_T (* decode) - (ErlNifEnv *env, ERL_NIF_TERM eValue, - struct cmsghdr *cmsgP, size_t rem, size_t *usedP); - - ERL_NIF_TERM *nameP; // Pointer to option name atom -}; + if (addrLen != dataLen) + return FALSE; -static int cmpESockCmsgSpec(const void *vpa, const void *vpb) { - struct ESockCmsgSpec *a, *b; - a = (struct ESockCmsgSpec *) vpa; - b = (struct ESockCmsgSpec *) vpb; - return COMPARE(*(a->nameP), *(b->nameP)); + esock_encode_sockaddr(env, + (ESockAddress*) data, + addrLen, + eResult); + return TRUE; } - -static struct ESockCmsgSpec - cmsgLevelSocket[] = - { -#if defined(SCM_CREDENTIALS) - {SCM_CREDENTIALS, NULL, NULL, - &esock_atom_credentials}, -#elif defined(SCM_CREDS) - {SCM_CREDS, NULL, NULL, - &esock_atom_credentials}, #endif - -#if defined(SCM_RIGHTS) - {SCM_RIGHTS, NULL, NULL, - &esock_atom_rights}, #endif -#if defined(SCM_TIMESTAMP) - {SCM_TIMESTAMP, - &esock_cmsg_encode_timeval, esock_cmsg_decode_timeval, - &esock_atom_timestamp}, -#endif - }, - cmsgLevelIP[] = - { -#if defined(IP_TOS) - {IP_TOS, esock_cmsg_encode_ip_tos, esock_cmsg_decode_ip_tos, - &esock_atom_tos}, -#endif +#ifndef __WIN32__ +#ifdef HAVE_LINUX_ERRQUEUE_H +#if defined(IP_RECVERR) || defined(IPV6_RECVERR) +/* +++ encode_cmsg_encode_recverr +++ + * + * Encode the extended socker error in the data part of the cmsg(). + * + */ +static +BOOLEAN_T esock_cmsg_encode_recverr(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eCMsgData) +{ + struct sock_extended_err *sock_err = (struct sock_extended_err *) data; + struct sockaddr *offender; + BOOLEAN_T have_offender = FALSE; + ERL_NIF_TERM + ee_errno, ee_origin, ee_type, ee_code, ee_info, ee_data, + eSockAddr; -#if defined(IP_TTL) - {IP_TTL, esock_cmsg_encode_int, esock_cmsg_decode_int, - &esock_atom_ttl}, -#endif + if (dataLen < sizeof(*sock_err)) + return FALSE; -#if defined(IP_RECVTTL) - {IP_RECVTTL, esock_cmsg_encode_uchar, NULL, - &esock_atom_recvttl}, -#endif + offender = SO_EE_OFFENDER(sock_err); + ee_errno = MKA(env, erl_errno_id(sock_err->ee_errno)); + ee_info = MKI(env, sock_err->ee_info); + ee_data = MKI(env, sock_err->ee_data); -#if defined(IP_PKTINFO) - {IP_PKTINFO, esock_cmsg_encode_in_pktinfo, NULL, - &esock_atom_pktinfo}, + switch (sock_err->ee_origin) { +#if defined(SO_EE_ORIGIN_NONE) + case SO_EE_ORIGIN_NONE: + ee_origin = atom_none; + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; #endif -#if defined(IP_ORIGDSTADDR) - {IP_ORIGDSTADDR, esock_cmsg_encode_sockaddr, NULL, - &esock_atom_origdstaddr}, +#if defined(SO_EE_ORIGIN_LOCAL) + case SO_EE_ORIGIN_LOCAL: + ee_origin = esock_atom_local; + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; #endif -#if defined(IP_RECVTOS) - {IP_RECVTOS, esock_cmsg_encode_ip_tos, NULL, - &esock_atom_recvtos}, -#endif +#if defined(SO_EE_ORIGIN_ICMP) + case SO_EE_ORIGIN_ICMP: + ee_origin = esock_atom_icmp; + switch (sock_err->ee_type) { -#if defined(IP_RECVERR) - {IP_RECVERR, -#if defined(HAVE_LINUX_ERRQUEUE_H) - esock_cmsg_encode_recverr, -#else - NULL, -#endif - NULL, - &esock_atom_recverr}, -#endif - }; +#if defined(ICMP_DEST_UNREACH) + case ICMP_DEST_UNREACH: + ee_type = atom_dest_unreach; + switch (sock_err->ee_code) { -#ifdef HAVE_IPV6 -static struct ESockCmsgSpec cmsgLevelIPv6[] = - { -#if defined(IPV6_PKTINFO) - {IPV6_PKTINFO, esock_cmsg_encode_in6_pktinfo, NULL, - &esock_atom_pktinfo}, +#if defined(ICMP_NET_UNREACH) + case ICMP_NET_UNREACH: + ee_code = atom_net_unreach; + break; #endif -#if defined(IPV6_HOPLIMIT) - {IPV6_HOPLIMIT, esock_cmsg_encode_int, esock_cmsg_decode_int, - &esock_atom_hoplimit}, +#if defined(ICMP_HOST_UNREACH) + case ICMP_HOST_UNREACH: + ee_code = atom_host_unreach; + break; #endif -#if defined(IPV6_TCLASS) - {IPV6_TCLASS, esock_cmsg_encode_int, esock_cmsg_decode_int, - &esock_atom_tclass}, +#if defined(ICMP_PORT_UNREACH) + case ICMP_PORT_UNREACH: + ee_code = atom_port_unreach; + break; #endif -#if defined(IPV6_RECVTCLASS) - {IPV6_RECVTCLASS, esock_cmsg_encode_int, NULL, - &esock_atom_recvtclass}, +#if defined(ICMP_FRAG_NEEDED) + case ICMP_FRAG_NEEDED: + ee_code = atom_frag_needed; + break; #endif -#if defined(IPV6_RECVERR) - {IPV6_RECVERR, -#if defined(HAVE_LINUX_ERRQUEUE_H) - esock_cmsg_encode_recverr, -#else - NULL, -#endif - NULL, - &esock_atom_recverr}, +#if defined(ICMP_NET_UNKNOWN) + case ICMP_NET_UNKNOWN: + ee_code = atom_net_unknown; + break; #endif - }; -#endif // #ifdef HAVE_IPV6 -static void initCmsgTables(void) { - ESOCK_SORT_TABLE(cmsgLevelSocket, cmpESockCmsgSpec); - ESOCK_SORT_TABLE(cmsgLevelIP, cmpESockCmsgSpec); -#ifdef HAVE_IPV6 - ESOCK_SORT_TABLE(cmsgLevelIPv6, cmpESockCmsgSpec); +#if defined(ICMP_HOST_UNKNOWN) + case ICMP_HOST_UNKNOWN: + ee_code = atom_host_unknown; + break; #endif -} - -static struct ESockCmsgSpec *lookupCmsgTable(int level, size_t *num) { - switch (level) { - - case SOL_SOCKET: - *num = NUM(cmsgLevelSocket); - return cmsgLevelSocket; -#ifdef SOL_IP - case SOL_IP: -#else - case IPPROTO_IP: -#endif - *num = NUM(cmsgLevelIP); - return cmsgLevelIP; + default: + ee_code = MKI(env, sock_err->ee_code); + break; + } + break; +#endif // ICMP_DEST_UNREACH -#ifdef HAVE_IPV6 -#ifdef SOL_IPV6 - case SOL_IPV6: -#else - case IPPROTO_IPV6: -#endif - *num = NUM(cmsgLevelIPv6); - return cmsgLevelIPv6; +#if defined(ICMP_TIME_EXCEEDED) + case ICMP_TIME_EXCEEDED: + ee_type = atom_time_exceeded; + ee_code = MKI(env, sock_err->ee_code); + break; #endif - default: - return NULL; - } -} - -static struct ESockCmsgSpec *lookupCmsgSpec(struct ESockCmsgSpec *table, - size_t num, - ERL_NIF_TERM eType) { - struct ESockCmsgSpec key; + default: + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; + } + break; +#endif // SO_EE_ORIGIN_ICMP - sys_memzero(CHARP(&key), sizeof(key)); - key.nameP = &eType; - return bsearch(&key, table, num, sizeof(*table), cmpESockCmsgSpec); -} +#if defined(SO_EE_ORIGIN_ICMP6) + case SO_EE_ORIGIN_ICMP6: + ee_origin = esock_atom_icmp6; + switch (sock_err->ee_type) { -#endif // #ifdef __WIN32__ +#if defined(ICMPV6_DEST_UNREACH) + case ICMPV6_DEST_UNREACH: + ee_type = atom_dest_unreach; + switch (sock_err->ee_code) { +#if defined(ICMPV6_NOROUTE) + case ICMPV6_NOROUTE: + ee_code = atom_noroute; + break; +#endif +#if defined(ICMPV6_ADM_PROHIBITED) + case ICMPV6_ADM_PROHIBITED: + ee_code = atom_adm_prohibited; + break; +#endif +#if defined(ICMPV6_NOT_NEIGHBOUR) + case ICMPV6_NOT_NEIGHBOUR: + ee_code = atom_not_neighbour; + break; +#endif -#ifndef __WIN32__ -static -BOOLEAN_T encode_cmsg(ErlNifEnv* env, - int level, - int type, - unsigned char* dataP, - size_t dataLen, - ERL_NIF_TERM* eType, - ERL_NIF_TERM* eData) { - const struct ESockCmsgSpec *cmsgTable; - size_t num; +#if defined(ICMPV6_ADDR_UNREACH) + case ICMPV6_ADDR_UNREACH: + ee_code = atom_addr_unreach; + break; +#endif - if ((cmsgTable = lookupCmsgTable(level, &num)) != NULL) { - size_t n; +#if defined(ICMPV6_PORT_UNREACH) + case ICMPV6_PORT_UNREACH: + ee_code = atom_port_unreach; + break; +#endif - /* Linear search for type number in level table - */ - for (n = 0; n < num; n++) { - if (cmsgTable[n].type == type) { - /* Found the type number in the level table; - * return the symbolic type (atom) - * and try to encode the data - */ +#if defined(ICMPV6_POLICY_FAIL) + case ICMPV6_POLICY_FAIL: + ee_code = atom_policy_fail; + break; +#endif - *eType = *cmsgTable[n].nameP; +#if defined(ICMPV6_REJECT_ROUTE) + case ICMPV6_REJECT_ROUTE: + ee_code = atom_reject_route; + break; +#endif - if (cmsgTable[n].encode != NULL) - return cmsgTable[n].encode(env, dataP, dataLen, eData); - else - return FALSE; + default: + ee_code = MKI(env, sock_err->ee_code); + break; } - } - } - /* No level table, or unknown type number in the table; - * just return the type number as an erlang integer - */ - + break; +#endif // ICMPV6_DEST_UNREACH - *eType = MKI(env, type); - return FALSE; -} +#if defined(ICMPV6_PKT_TOOBIG) + case ICMPV6_PKT_TOOBIG: + ee_type = atom_pkt_toobig; + ee_code = MKI(env, sock_err->ee_code); + break; #endif +#if defined(ICMPV6_TIME_EXCEED) + case ICMPV6_TIME_EXCEED: + ee_type = atom_time_exceeded; + ee_code = MKI(env, sock_err->ee_code); + break; +#endif -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eValue, - char* bufP, - size_t rem, - size_t* usedP) -{ - int type; - struct cmsghdr *cmsgP = (struct cmsghdr *) bufP; - struct ESockCmsgSpec *cmsgTable; - struct ESockCmsgSpec *cmsgSpecP = NULL; - size_t num = 0; + default: + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; + } + break; +#endif // SO_EE_ORIGIN_ICMP6 - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> entry \r\n" - " eType: %T\r\n" - " eValue: %T\r\n", - descP->sock, eType, eValue) ); +#if defined(SO_EE_ORIGIN_TXSTATUS) + case SO_EE_ORIGIN_TXSTATUS: + ee_origin = atom_txstatus; + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; +#endif - // We have decode functions only for symbolic (atom) types - if (! IS_ATOM(env, eType)) { - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " eType not an atom\r\n", - descP->sock) ); - return FALSE; - } +#if defined(SO_EE_ORIGIN_ZEROCOPY) + case SO_EE_ORIGIN_ZEROCOPY: + ee_origin = atom_zerocopy; + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; +#endif - /* Try to look up the symbolic type - */ - if (((cmsgTable = lookupCmsgTable(level, &num)) == NULL) || - ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL) || - (cmsgSpecP->decode == NULL)) { - /* We found no table for this level, - * we found no symbolic type in the level table, - * or no decode function for this type - */ +#if defined(SO_EE_ORIGIN_TXTIME) + case SO_EE_ORIGIN_TXTIME: + ee_origin = atom_txtime; + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; +#endif - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " cmsgTable: %p\r\n" - " cmsgSpecP: %p\r\n", - descP->sock, cmsgTable, cmsgSpecP) ); - return FALSE; + default: + ee_origin = MKI(env, sock_err->ee_origin); + ee_type = MKI(env, sock_err->ee_type); + ee_code = MKI(env, sock_err->ee_code); + break; } - if (! cmsgSpecP->decode(env, eValue, cmsgP, rem, usedP)) { - // Decode function failed - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> FALSE:\r\n" - " decode function failed\r\n", - descP->sock) ); - return FALSE; + have_offender = CHARP(sock_err) + dataLen > CHARP(offender); + if (have_offender) { + esock_encode_sockaddr(env, + (ESockAddress *)offender, + (CHARP(sock_err) + dataLen) - CHARP(offender), + &eSockAddr); + } else { + eSockAddr = esock_atom_undefined; } - // Succesful decode - - type = cmsgSpecP->type; + { + ERL_NIF_TERM keys[] = {esock_atom_error, + atom_origin, + esock_atom_type, + atom_code, + esock_atom_info, + esock_atom_data, + atom_offender}; + ERL_NIF_TERM vals[] = {ee_errno, + ee_origin, + ee_type, + ee_code, + ee_info, + ee_data, + eSockAddr}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_value {%d} -> TRUE:\r\n" - " level: %d\r\n" - " type: %d\r\n", - " *usedP: %lu\r\n", - descP->sock, level, type, (unsigned long) *usedP) ); - - cmsgP->cmsg_level = level; - cmsgP->cmsg_type = type; + ESOCK_ASSERT( numKeys == numVals ); + if (! have_offender) numKeys--; + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eCMsgData) ); + } return TRUE; } -#endif +#endif // #if defined(IP_RECVERR) || defined(IPV6_RECVERR) +#endif // #ifdef HAVE_LINUX_ERRQUEUE_H +#endif // #ifndef __WIN32__ -#ifndef __WIN32__ +#ifdef IPV6_PKTINFO static -BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, - ESockDescriptor* descP, - int level, - ERL_NIF_TERM eType, - ERL_NIF_TERM eData, - char* bufP, - size_t rem, - size_t* usedP) -{ - int type; - ErlNifBinary bin; - struct cmsghdr *cmsgP = (struct cmsghdr *) bufP; - struct ESockCmsgSpec *cmsgSpecP = NULL; - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> entry \r\n" - " eType: %T\r\n" - " eData: %T\r\n", - descP->sock, eType, eData) ); - - // Decode Type - if (! GET_INT(env, eType, &type)) { - struct ESockCmsgSpec *cmsgTable = NULL; - size_t num = 0; - - /* Try to look up the symbolic (atom) type - */ - if ((! IS_ATOM(env, eType)) || - ((cmsgTable = lookupCmsgTable(level, &num)) == NULL) || - ((cmsgSpecP = lookupCmsgSpec(cmsgTable, num, eType)) == NULL)) { - /* Type was not an atom, - * we found no table for this level, - * or we found no symbolic type in the level table - */ - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE:\r\n" - " cmsgTable: %p\r\n" - " cmsgSpecP: %p\r\n", - descP->sock, cmsgTable, cmsgSpecP) ); - return FALSE; - } - - type = cmsgSpecP->type; - } - - // Decode Data - if (GET_BIN(env, eData, &bin)) { - void *p; - - p = init_cmsghdr(cmsgP, rem, bin.size, usedP); - if (p == NULL) { - /* No room for the data - */ - - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE:\r\n" - " rem: %lu\r\n" - " bin.size: %lu\r\n", - descP->sock, - (unsigned long) rem, - (unsigned long) bin.size) ); - return FALSE; - } - - // Copy the binary data - sys_memcpy(p, bin.data, bin.size); +BOOLEAN_T esock_cmsg_encode_in6_pktinfo(ErlNifEnv *env, + unsigned char *data, + size_t dataLen, + ERL_NIF_TERM *eResult) { + struct in6_pktinfo* pktInfoP = (struct in6_pktinfo*) data; + ERL_NIF_TERM ifIndex, addr; - } else if ((! esock_cmsg_decode_int(env, eData, cmsgP, rem, usedP)) && - (! esock_cmsg_decode_bool(env, eData, cmsgP, rem, usedP))) { - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> FALSE\r\n", - descP->sock) ); + if (dataLen < sizeof(*pktInfoP)) return FALSE; - } - - // Succesful decode + ifIndex = MKI(env, pktInfoP->ipi6_ifindex); + esock_encode_in6_addr(env, &pktInfoP->ipi6_addr, &addr); + { + ERL_NIF_TERM keys[] = {esock_atom_addr, esock_atom_ifindex}; + ERL_NIF_TERM vals[] = {addr, ifIndex}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); - SSDBG( descP, - ("SOCKET", - "decode_cmsghdr_data {%d} -> TRUE:\r\n" - " level: %d\r\n" - " type: %d\r\n" - " *usedP: %lu\r\n", - descP->sock, level, type, (unsigned long) *usedP) ); - - cmsgP->cmsg_level = level; - cmsgP->cmsg_type = type; + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eResult) ); + } return TRUE; } #endif -/* Clear the CMSG space and init the ->cmsg_len member, - * return the position for the data, and the total used space - */ -#ifndef __WIN32__ -static void *init_cmsghdr(struct cmsghdr *cmsgP, - size_t rem, // Remaining space - size_t size, // Size of data - size_t *usedP) -{ - size_t space = CMSG_SPACE(size); - - if (rem < space) - return NULL; // Not enough space - sys_memzero(cmsgP, space); - cmsgP->cmsg_len = CMSG_LEN(size); - *usedP = space; - return CMSG_DATA(cmsgP); +static int cmpESockCmsgSpec(const void *vpa, const void *vpb) { + ESockCmsgSpec *a, *b; + a = (ESockCmsgSpec *) vpa; + b = (ESockCmsgSpec *) vpb; + return COMPARE(*(a->nameP), *(b->nameP)); } + + +#if defined(SCM_CREDENTIALS) || defined(SCM_RIGHTS) || defined(SCM_TIMESTAMP) +#define HAVE_ESOCK_CMSG_SOCKET #endif -/* +++ decode_cmsghdrs +++ - * - * Decode a list of cmsg(). There can be 0 or more "blocks". - * - * Each element can either be a (erlang) map that needs to be decoded, - * or a (erlang) binary that just needs to be appended to the control - * buffer. - * - * Our "problem" is that we have no idea much memory we actually need. - * - */ -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* cmsgHdrBufP, - size_t cmsgHdrBufLen, - size_t* cmsgHdrBufUsed) -{ - ERL_NIF_TERM elem, tail, list; - char* bufP; - size_t rem, used, totUsed = 0; - unsigned int len; - int i; - - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> entry with" - "\r\n eCMsg: %T" - "\r\n cmsgHdrBufP: 0x%lX" - "\r\n cmsgHdrBufLen: %d" - "\r\n", descP->sock, - eCMsg, cmsgHdrBufP, cmsgHdrBufLen) ); +#if defined(HAVE_ESOCK_CMSG_SOCKET) +static ESockCmsgSpec cmsgLevelSocket[] = + { +#if defined(SCM_CREDENTIALS) + {SCM_CREDENTIALS, NULL, NULL, + &esock_atom_credentials}, +#elif defined(SCM_CREDS) + {SCM_CREDS, NULL, NULL, + &esock_atom_credentials}, +#endif - if (! GET_LIST_LEN(env, eCMsg, &len)) - return FALSE; +#if defined(SCM_RIGHTS) + {SCM_RIGHTS, NULL, NULL, + &esock_atom_rights}, +#endif - SSDBG( descP, - ("SOCKET", - "decode_cmsghdrs {%d} -> list length: %d\r\n", - descP->sock, len) ); +#if defined(SCM_TIMESTAMP) + {SCM_TIMESTAMP, + &esock_cmsg_encode_timeval, esock_cmsg_decode_timeval, + &esock_atom_timestamp}, +#endif + }; +#endif - for (i = 0, list = eCMsg, rem = cmsgHdrBufLen, bufP = cmsgHdrBufP; - i < len; i++) { - - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> process elem %d:" - "\r\n (buffer) rem: %u" - "\r\n (buffer) totUsed: %u" - "\r\n", descP->sock, i, rem, totUsed) ); +static ESockCmsgSpec cmsgLevelIP[] = + { +#if defined(IP_TOS) + {IP_TOS, esock_cmsg_encode_ip_tos, esock_cmsg_decode_ip_tos, + &esock_atom_tos}, +#endif - /* Extract the (current) head of the (cmsg hdr) list */ - if (! GET_LIST_ELEM(env, list, &elem, &tail)) - return FALSE; - - used = 0; // Just in case... - if (! decode_cmsghdr(env, descP, elem, bufP, rem, &used)) - return FALSE; +#if defined(IP_TTL) + {IP_TTL, esock_cmsg_encode_int, esock_cmsg_decode_int, + &esock_atom_ttl}, +#endif - bufP = CHARP( ULONG(bufP) + used ); - rem = SZT( rem - used ); - list = tail; - totUsed += used; +#if defined(IP_RECVTTL) + {IP_RECVTTL, esock_cmsg_encode_uchar, NULL, + &esock_atom_recvttl}, +#endif - } +#if defined(IP_PKTINFO) + {IP_PKTINFO, esock_cmsg_encode_in_pktinfo, NULL, + &esock_atom_pktinfo}, +#endif - *cmsgHdrBufUsed = totUsed; +#if defined(IP_ORIGDSTADDR) + {IP_ORIGDSTADDR, esock_cmsg_encode_sockaddr, NULL, + &esock_atom_origdstaddr}, +#endif - SSDBG( descP, ("SOCKET", "decode_cmsghdrs {%d} -> done" - "\r\n all %u ctrl headers processed" - "\r\n totUsed = %lu\r\n", - descP->sock, len, (unsigned long) totUsed) ); +#if defined(IP_RECVTOS) + {IP_RECVTOS, esock_cmsg_encode_ip_tos, NULL, + &esock_atom_recvtos}, +#endif - return TRUE; -} -#endif // #ifndef __WIN32__ +#if defined(IP_RECVERR) + {IP_RECVERR, +#if defined(HAVE_LINUX_ERRQUEUE_H) + esock_cmsg_encode_recverr, +#else + NULL, +#endif + NULL, + &esock_atom_recverr}, +#endif + }; +#ifdef HAVE_IPV6 +static ESockCmsgSpec cmsgLevelIPv6[] = + { +#if defined(IPV6_PKTINFO) + {IPV6_PKTINFO, esock_cmsg_encode_in6_pktinfo, NULL, + &esock_atom_pktinfo}, +#endif -/* +++ decode_cmsghdr +++ - * - * Decode one cmsg(). Put the "result" into the buffer and advance the - * pointer (of the buffer) afterwards. Also update 'rem' accordingly. - * But before the actual decode, make sure that there is enough room in - * the buffer for the cmsg header (sizeof(*hdr) < rem). - * - * The eCMsg should be a map with three fields: - * - * level :: socket | protocol() | integer() - * type :: atom() | integer() - * What values are valid depend on the level - * data :: binary() | integer() | boolean() - * The type of the data depends on - * or level and type, but can be a binary, - * which means that the data is already coded. - * value :: term() Which is a term matching the decode function - */ -#ifndef __WIN32__ -static -BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM eCMsg, - char* bufP, - size_t rem, - size_t* used) -{ - ERL_NIF_TERM eLevel, eType, eData, eValue; - int level; +#if defined(IPV6_HOPLIMIT) + {IPV6_HOPLIMIT, esock_cmsg_encode_int, esock_cmsg_decode_int, + &esock_atom_hoplimit}, +#endif - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> entry with" - "\r\n eCMsg: %T" - "\r\n", descP->sock, eCMsg) ); +#if defined(IPV6_TCLASS) + {IPV6_TCLASS, esock_cmsg_encode_int, esock_cmsg_decode_int, + &esock_atom_tclass}, +#endif - // Get 'level' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_level, &eLevel)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eLevel: %T" - "\r\n", descP->sock, eLevel) ); +#if defined(IPV6_RECVTCLASS) + {IPV6_RECVTCLASS, esock_cmsg_encode_int, NULL, + &esock_atom_recvtclass}, +#endif - // Get 'type' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_type, &eType)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eType: %T" - "\r\n", descP->sock, eType) ); +#if defined(IPV6_RECVERR) + {IPV6_RECVERR, +#if defined(HAVE_LINUX_ERRQUEUE_H) + esock_cmsg_encode_recverr, +#else + NULL, +#endif + NULL, + &esock_atom_recverr}, +#endif + }; +#endif // #ifdef HAVE_IPV6 - // Decode Level - if (! esock_decode_level(env, eLevel, &level)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> level: %d\r\n", - descP->sock, level) ); +static void initCmsgTables(void) +{ +#if defined(HAVE_ESOCK_CMSG_SOCKET) + ESOCK_SORT_TABLE(cmsgLevelSocket, cmpESockCmsgSpec); +#endif - // Get 'data' field - if (! GET_MAP_VAL(env, eCMsg, esock_atom_data, &eData)) { + ESOCK_SORT_TABLE(cmsgLevelIP, cmpESockCmsgSpec); - // Get 'value' field - if (! GET_MAP_VAL(env, eCMsg, atom_value, &eValue)) - return FALSE; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eValue: %T" - "\r\n", descP->sock, eValue) ); +#ifdef HAVE_IPV6 + ESOCK_SORT_TABLE(cmsgLevelIPv6, cmpESockCmsgSpec); +#endif +} - // Decode Value - if (! decode_cmsghdr_value(env, descP, level, eType, eValue, - bufP, rem, used)) - return FALSE; +extern +ESockCmsgSpec* esock_lookup_cmsg_table(int level, size_t *num) +{ + switch (level) { - } else { +#if defined(HAVE_ESOCK_CMSG_SOCKET) + case SOL_SOCKET: + *num = NUM(cmsgLevelSocket); + return cmsgLevelSocket; +#endif - // Verify no 'value' field - if (GET_MAP_VAL(env, eCMsg, atom_value, &eValue)) - return FALSE; +#ifndef __WIN32__ +#ifdef SOL_IP + case SOL_IP: +#else + case IPPROTO_IP: +#endif +#else + case IPPROTO_IP: +#endif + *num = NUM(cmsgLevelIP); + return cmsgLevelIP; - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d} -> eData: %T" - "\r\n", descP->sock, eData) ); +#ifdef HAVE_IPV6 +#ifndef __WIN32__ +#ifdef SOL_IPV6 + case SOL_IPV6: +#else + case IPPROTO_IPV6: +#endif +#else + case IPPROTO_IPV6: +#endif + *num = NUM(cmsgLevelIPv6); + return cmsgLevelIPv6; +#endif - // Decode Data - if (! decode_cmsghdr_data(env, descP, level, eType, eData, - bufP, rem, used)) - return FALSE; + default: + return NULL; } +} - SSDBG( descP, ("SOCKET", "decode_cmsghdr {%d}-> used: %lu\r\n", - descP->sock, (unsigned long) *used) ); +extern +ESockCmsgSpec* esock_lookup_cmsg_spec(ESockCmsgSpec* table, + size_t num, + ERL_NIF_TERM eType) +{ + ESockCmsgSpec key; - return TRUE; + sys_memzero(CHARP(&key), sizeof(key)); + key.nameP = &eType; + return bsearch(&key, table, num, sizeof(*table), cmpESockCmsgSpec); } -#endif // #ifndef __WIN32__ -/* +++ encode_msg_flags +++ - * - * Encode a list of msg_flag(). - * + +/* Clear the CMSG space and init the ->cmsg_len member, + * return the position for the data, and the total used space */ -#ifndef __WIN32__ -static -void encode_msg_flags(ErlNifEnv* env, - ESockDescriptor* descP, - int msgFlags, - ERL_NIF_TERM* flags) +extern +void* esock_init_cmsghdr(struct cmsghdr* cmsgP, + size_t rem, // Remaining space + size_t size, // Size of data + size_t* usedP) { - SSDBG( descP, - ("SOCKET", "encode_msg_flags {%d} -> entry with" - "\r\n msgFlags: %d (0x%lX)" - "\r\n", descP->sock, msgFlags, msgFlags) ); + size_t space = ESOCK_CMSG_SPACE(size); + void* dataP; - if (msgFlags == 0) { - *flags = MKEL(env); - } else { - size_t n; - SocketTArray ta = TARRAY_CREATE(10); // Just to be on the safe side + if (rem < space) + return NULL; // Not enough space - for (n = 0; n < NUM(msg_flags); n++) { - int f = msg_flags[n].flag; - if ((f != 0) && ((msgFlags & f) == f)) { - msgFlags &= ~f; - TARRAY_ADD(ta, *(msg_flags[n].name)); - } - if (msgFlags == 0) goto done; - } - /* Append remaining flags as an integer */ - if (msgFlags != 0) - TARRAY_ADD(ta, MKI(env, msgFlags)); + sys_memzero(cmsgP, space); + cmsgP->cmsg_len = ESOCK_CMSG_LEN(size); - done: - SSDBG( descP, - ("SOCKET", "encode_msg_flags {%d} -> flags processed when" - "\r\n TArray size: %d" - "\r\n", descP->sock, TARRAY_SZ(ta)) ); + *usedP = space; + dataP = ESOCK_CMSG_DATA(cmsgP); - TARRAY_TOLIST(ta, env, flags); - } + return dataP; } -#endif // #ifndef __WIN32__ /* +++ decode the ip socket option TOS +++ @@ -17778,8 +11359,10 @@ void encode_msg_flags(ErlNifEnv* env, * * lowdelay | throughput | reliability | mincost * + * + * For Windows, the Microsoft recommendation is: *Do not use* */ -#ifndef __WIN32__ + #if defined(IP_TOS) static BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) @@ -17788,6 +11371,14 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) if (IS_ATOM(env, eVal)) { +#ifdef __WIN32__ + + /* See above */ + *val = -1; + result = FALSE; + +#else + if (COMPARE(eVal, esock_atom_lowdelay) == 0) { *val = IPTOS_LOWDELAY; result = TRUE; @@ -17802,11 +11393,14 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) *val = IPTOS_MINCOST; result = TRUE; #endif + } else { *val = -1; result = FALSE; } +#endif // ifdef __WIN32__ + } else if (IS_NUM(env, eVal)) { if (GET_INT(env, eVal, val)) { @@ -17824,7 +11418,7 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return result; } #endif -#endif // #ifndef __WIN32__ + /* +++ decode the ip socket option MTU_DISCOVER +++ @@ -17836,20 +11430,23 @@ BOOLEAN_T decode_ip_tos(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) * * want | dont | do | probe * + * Note that on Windows, the 'want' value seems to not exist! */ -#ifndef __WIN32__ + #if defined(IP_MTU_DISCOVER) static BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) { if (IS_ATOM(env, eVal)) { - if (COMPARE(eVal, atom_want) == 0) { - *val = IP_PMTUDISC_WANT; - } else if (COMPARE(eVal, atom_dont) == 0) { + if (COMPARE(eVal, atom_dont) == 0) { *val = IP_PMTUDISC_DONT; } else if (COMPARE(eVal, atom_do) == 0) { *val = IP_PMTUDISC_DO; +#if defined(IP_PMTUDISC_WANT) + } else if (COMPARE(eVal, atom_want) == 0) { + *val = IP_PMTUDISC_WANT; +#endif #if defined(IP_PMTUDISC_PROBE) } else if (COMPARE(eVal, atom_probe) == 0) { *val = IP_PMTUDISC_PROBE; @@ -17865,10 +11462,8 @@ BOOLEAN_T decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return TRUE; } #endif -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ #if defined(IPV6_MULTICAST_HOPS) || defined(IPV6_UNICAST_HOPS) static BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { @@ -17888,7 +11483,6 @@ BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { return TRUE; } #endif -#endif // #ifndef __WIN32__ /* +++ decode the ipv6 socket option MTU_DISCOVER +++ @@ -17900,20 +11494,33 @@ BOOLEAN_T decode_hops(ErlNifEnv *env, ERL_NIF_TERM eVal, int *val) { * * want | dont | do | probe * + * Use same as IP on Windows!! */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) { if (IS_ATOM(env, eVal)) { - if (COMPARE(eVal, atom_want) == 0) { - *val = IPV6_PMTUDISC_WANT; - } else if (COMPARE(eVal, atom_dont) == 0) { +#ifdef __WIN32__ + /* On Windows, the IP-flags are used */ + if (COMPARE(eVal, atom_dont) == 0) { + *val = IP_PMTUDISC_DONT; + } else if (COMPARE(eVal, atom_do) == 0) { + *val = IP_PMTUDISC_DO; + } else if (COMPARE(eVal, atom_probe) == 0) { + *val = IP_PMTUDISC_PROBE; + } else { + return FALSE; + } +#else + if (COMPARE(eVal, atom_dont) == 0) { *val = IPV6_PMTUDISC_DONT; } else if (COMPARE(eVal, atom_do) == 0) { *val = IPV6_PMTUDISC_DO; + } else if (COMPARE(eVal, atom_want) == 0) { + *val = IPV6_PMTUDISC_WANT; #if defined(IPV6_PMTUDISC_PROBE) } else if (COMPARE(eVal, atom_probe) == 0) { *val = IPV6_PMTUDISC_PROBE; @@ -17921,6 +11528,7 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) } else { return FALSE; } +#endif } else if (! GET_INT(env, eVal, val)) { return FALSE; @@ -17929,7 +11537,6 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) return TRUE; } #endif -#endif // #ifndef __WIN32__ /* +++ encode the ip socket option MTU_DISCOVER +++ @@ -17942,15 +11549,17 @@ BOOLEAN_T decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val) * want | dont | do | probe * */ -#ifndef __WIN32__ + #if defined(IP_MTU_DISCOVER) static void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) { switch (val) { +#if defined(IP_PMTUDISC_WANT) case IP_PMTUDISC_WANT: *eVal = atom_want; break; +#endif case IP_PMTUDISC_DONT: *eVal = atom_dont; @@ -17974,7 +11583,6 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) return; } #endif -#endif // #ifndef __WIN32__ /* +++ encode the ipv6 socket option MTU_DISCOVER +++ @@ -17986,29 +11594,46 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) * * want | dont | do | probe * + * Windows uses the IP-flags. */ -#ifndef __WIN32__ + #if defined(IPV6_MTU_DISCOVER) static void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) { switch (val) { +#if defined(IPV6_PMTUDISC_WANT) case IPV6_PMTUDISC_WANT: *eVal = atom_want; break; +#endif +#if defined(__WIN32__) + case IP_PMTUDISC_DONT: +#else case IPV6_PMTUDISC_DONT: +#endif *eVal = atom_dont; break; +#if defined(__WIN32__) + case IP_PMTUDISC_DO: +#else case IPV6_PMTUDISC_DO: +#endif *eVal = atom_do; break; +#if defined(__WIN32__) + case IP_PMTUDISC_PROBE: + *eVal = atom_probe; + break; +#else #if defined(IPV6_PMTUDISC_PROBE) case IPV6_PMTUDISC_PROBE: *eVal = atom_probe; break; +#endif #endif default: @@ -18019,7 +11644,7 @@ void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) return; } #endif -#endif // #ifndef __WIN32__ + /* +++ encode the ip socket option tos +++ @@ -18028,24 +11653,30 @@ void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal) * lowdelay | throughput | reliability | mincost | integer() * */ -#ifndef __WIN32__ + static ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val) { ERL_NIF_TERM result; switch (IPTOS_TOS(val)) { +#if defined(IPTOS_LOWDELAY) case IPTOS_LOWDELAY: result = esock_atom_lowdelay; break; +#endif +#if defined(IPTOS_THROUGHPUT) case IPTOS_THROUGHPUT: result = esock_atom_throughput; break; +#endif +#if defined(IPTOS_RELIABILITY) case IPTOS_RELIABILITY: result = esock_atom_reliability; break; +#endif #if defined(IPTOS_MINCOST) case IPTOS_MINCOST: @@ -18060,10 +11691,9 @@ ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val) return result; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ + #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) static @@ -18107,20 +11737,19 @@ ERL_NIF_TERM encode_sctp_assoc_t(ErlNifEnv* env, sctp_assoc_t val) } #endif // #if defined(SCTP_ASSOCINFO) || defined(SCTP_RTOINOFO) -#endif // #ifdef __WIN32__ -/* *** alloc_descriptor *** + +/* *** esock_alloc_descriptor *** * * Allocate and perform basic initialization of a socket descriptor. * */ -#ifndef __WIN32__ -static -ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) +extern +ESockDescriptor* esock_alloc_descriptor(SOCKET sock) { ESockDescriptor* descP; - char buf[64]; /* Buffer used for building the mutex name */ + char buf[64]; /* Buffer used for building the mutex name(s) */ ESOCK_ASSERT( (descP = enif_alloc_resource(esocks, sizeof(ESockDescriptor))) @@ -18128,14 +11757,17 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->pattern = ESOCK_DESC_PATTERN_CREATED; - requestor_init(&descP->connector); + esock_requestor_init(&descP->connector); descP->connectorP = NULL; - sprintf(buf, "esock.w[%d]", sock); + sprintf(buf, "esock.w[" SOCKET_FORMAT_STR "]", sock); descP->writeMtx = MCREATE(buf); descP->writeState = 0; - requestor_init(&descP->currentWriter); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentWriter); descP->currentWriterP = NULL; // currentWriter not used +#endif descP->writersQ.first = NULL; descP->writersQ.last = NULL; @@ -18152,11 +11784,14 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->sendfileCountersP = NULL; #endif - sprintf(buf, "esock.r[%d]", sock); + sprintf(buf, "esock.r[" SOCKET_FORMAT_STR "]", sock); descP->readMtx = MCREATE(buf); descP->readState = 0; - requestor_init(&descP->currentReader); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentReader); descP->currentReaderP = NULL; // currentReader not used +#endif descP->readersQ.first = NULL; descP->readersQ.last = NULL; @@ -18168,9 +11803,12 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->readWaits = 0; descP->readFails = 0; - sprintf(buf, "esock.acc[%d]", sock); - requestor_init(&descP->currentAcceptor); + sprintf(buf, "esock.acc[" SOCKET_FORMAT_STR "]", sock); +#ifndef __WIN32__ + /* Not used on Windows - see header for more info */ + esock_requestor_init(&descP->currentAcceptor); descP->currentAcceptorP = NULL; // currentAcceptor not used +#endif descP->acceptorsQ.first = NULL; descP->acceptorsQ.last = NULL; descP->accSuccess = 0; @@ -18178,130 +11816,162 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, ErlNifEvent event) descP->accTries = 0; descP->accWaits = 0; - sprintf(buf, "esock.close[%d]", sock); + sprintf(buf, "esock.close[" SOCKET_FORMAT_STR "]", sock); descP->closeEnv = NULL; descP->closeRef = esock_atom_undefined; enif_set_pid_undefined(&descP->closerPid); MON_INIT(&descP->closerMon); - sprintf(buf, "esock.cfg[%d]", sock); + sprintf(buf, "esock.cfg[" SOCKET_FORMAT_STR "]", sock); descP->rBufSz = ESOCK_RECV_BUFFER_SIZE_DEFAULT; +#ifndef __WIN32__ descP->rNum = ESOCK_RECV_BUFFER_COUNT_DEFAULT; descP->rNumCnt = 0; +#endif descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT; descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT; descP->iow = FALSE; - descP->dbg = ESOCK_DEBUG_DEFAULT; // Overwritten by caller - descP->useReg = ESOCK_USE_SOCKET_REGISTRY; // Overwritten by caller - descP->meta.env = esock_alloc_env("alloc_descriptor - " + descP->dbg = ESOCK_DEBUG_DEFAULT; // Overwritten by caller + descP->useReg = ESOCK_USE_SOCKET_REGISTRY;// Overwritten by caller + descP->meta.env = esock_alloc_env("esock_alloc_descriptor - " "meta-env"); descP->meta.ref = esock_atom_undefined; descP->sock = sock; - descP->event = event; descP->origFD = INVALID_SOCKET; descP->closeOnClose = TRUE; enif_set_pid_undefined(&descP->ctrlPid); MON_INIT(&descP->ctrlMon); +#if defined(ESOCK_DESCRIPTOR_FILLER) + sys_memzero(descP->filler, sizeof(descP->filler)); +#endif + return descP; } -#endif // #ifndef __WIN32__ + + +/* This function is *only* called during 'open' after an + * descriptor has been allocated but before it has been used. + */ +extern +void esock_dealloc_descriptor(ErlNifEnv* env, + ESockDescriptor* descP) +{ + if (descP->writeMtx != NULL) { + MDESTROY(descP->writeMtx); + descP->writeMtx = NULL; + } + + if (descP->readMtx != NULL) { + MDESTROY(descP->readMtx); + descP->readMtx = NULL; + } + + if (descP->closeEnv != NULL) { + esock_free_env("dealloc descriptor", descP->closeEnv); + descP->closeEnv = NULL; + } + + if (descP->meta.env != NULL) { + esock_free_env("dealloc descriptor", descP->meta.env); + descP->meta.env = NULL; + } + +} + + /* Decrement counters for when a socket is closed */ -#ifndef __WIN32__ -static -void dec_socket(int domain, int type, int protocol) +extern +void esock_dec_socket(int domain, int type, int protocol) { MLOCK(data.cntMtx); - cnt_dec(&data.numSockets, 1); + esock_cnt_dec(&data.numSockets, 1); /* *** Domain counter *** */ if (domain == AF_INET) - cnt_dec(&data.numDomainInet, 1); + esock_cnt_dec(&data.numDomainInet, 1); #if defined(HAVE_IN6) && defined(AF_INET6) else if (domain == AF_INET6) - cnt_dec(&data.numDomainInet6, 1); + esock_cnt_dec(&data.numDomainInet6, 1); #endif -#ifdef HAS_AF_LOCAL +#if defined(HAS_AF_LOCAL) else if (domain == AF_LOCAL) - cnt_dec(&data.numDomainInet6, 1); + esock_cnt_dec(&data.numDomainInet6, 1); #endif /* *** Type counter *** */ if (type == SOCK_STREAM) - cnt_dec(&data.numTypeStreams, 1); + esock_cnt_dec(&data.numTypeStreams, 1); else if (type == SOCK_DGRAM) - cnt_dec(&data.numTypeDGrams, 1); -#ifdef SOCK_SEQPACKET + esock_cnt_dec(&data.numTypeDGrams, 1); +#if defined(SOCK_SEQPACKET) else if (type == SOCK_SEQPACKET) - cnt_dec(&data.numTypeSeqPkgs, 1); + esock_cnt_dec(&data.numTypeSeqPkgs, 1); #endif /* *** Protocol counter *** */ if (protocol == IPPROTO_IP) - cnt_dec(&data.numProtoIP, 1); + esock_cnt_dec(&data.numProtoIP, 1); else if (protocol == IPPROTO_TCP) - cnt_dec(&data.numProtoTCP, 1); + esock_cnt_dec(&data.numProtoTCP, 1); else if (protocol == IPPROTO_UDP) - cnt_dec(&data.numProtoUDP, 1); + esock_cnt_dec(&data.numProtoUDP, 1); #if defined(HAVE_SCTP) else if (protocol == IPPROTO_SCTP) - cnt_dec(&data.numProtoSCTP, 1); + esock_cnt_dec(&data.numProtoSCTP, 1); #endif MUNLOCK(data.cntMtx); } -#endif // #ifndef __WIN32__ /* Increment counters for when a socket is opened */ -#ifndef __WIN32__ -static -void inc_socket(int domain, int type, int protocol) +extern +void esock_inc_socket(int domain, int type, int protocol) { - cnt_inc(&data.numSockets, 1); + esock_cnt_inc(&data.numSockets, 1); /* *** Domain counter *** */ if (domain == AF_INET) - cnt_inc(&data.numDomainInet, 1); + esock_cnt_inc(&data.numDomainInet, 1); #if defined(HAVE_IN6) && defined(AF_INET6) else if (domain == AF_INET6) - cnt_inc(&data.numDomainInet6, 1); + esock_cnt_inc(&data.numDomainInet6, 1); #endif -#ifdef HAS_AF_LOCAL +#if defined(HAS_AF_LOCAL) else if (domain == AF_LOCAL) - cnt_inc(&data.numDomainInet6, 1); + esock_cnt_inc(&data.numDomainInet6, 1); #endif /* *** Type counter *** */ if (type == SOCK_STREAM) - cnt_inc(&data.numTypeStreams, 1); + esock_cnt_inc(&data.numTypeStreams, 1); else if (type == SOCK_DGRAM) - cnt_inc(&data.numTypeDGrams, 1); -#ifdef SOCK_SEQPACKET + esock_cnt_inc(&data.numTypeDGrams, 1); +#if defined(SOCK_SEQPACKET) else if (type == SOCK_SEQPACKET) - cnt_inc(&data.numTypeSeqPkgs, 1); + esock_cnt_inc(&data.numTypeSeqPkgs, 1); #endif /* *** Protocol counter *** */ if (protocol == IPPROTO_IP) - cnt_inc(&data.numProtoIP, 1); + esock_cnt_inc(&data.numProtoIP, 1); else if (protocol == IPPROTO_TCP) - cnt_inc(&data.numProtoTCP, 1); + esock_cnt_inc(&data.numProtoTCP, 1); else if (protocol == IPPROTO_UDP) - cnt_inc(&data.numProtoUDP, 1); + esock_cnt_inc(&data.numProtoUDP, 1); #if defined(HAVE_SCTP) else if (protocol == IPPROTO_SCTP) - cnt_inc(&data.numProtoSCTP, 1); + esock_cnt_inc(&data.numProtoSCTP, 1); #endif } -#endif // #ifndef __WIN32__ @@ -18310,44 +11980,10 @@ void inc_socket(int domain, int type, int protocol) * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ -#ifdef HAVE_SETNS -/* esock_open4_get_netns - extract the netns field from the opts map - */ -static -BOOLEAN_T esock_open4_get_netns(ErlNifEnv* env, ERL_NIF_TERM opts, char** netns) -{ - ERL_NIF_TERM val; - ErlNifBinary bin; - char* buf; - - /* The currently only supported extra option is: netns */ - if (!GET_MAP_VAL(env, opts, atom_netns, &val)) { - *netns = NULL; // Just in case... - return FALSE; - } - - /* The value should be a binary file name */ - if (! enif_inspect_binary(env, val, &bin)) { - *netns = NULL; // Just in case... - return FALSE; - } - - ESOCK_ASSERT( (buf = MALLOC(bin.size+1)) != NULL ); - - sys_memcpy(buf, bin.data, bin.size); - buf[bin.size] = '\0'; - *netns = buf; - return TRUE; -} -#endif -#endif // #ifndef __WIN32__ - /* ehow2how - convert internal (erlang) "shutdown how" to * (proper) "shutdown how" */ -#ifndef __WIN32__ static BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how) { @@ -18355,22 +11991,33 @@ BOOLEAN_T ehow2how(ERL_NIF_TERM ehow, int* how) cmp = COMPARE(ehow, atom_read_write); if (cmp == 0) +#ifdef __WIN32__ + *how = SD_BOTH; +#else *how = SHUT_RDWR; +#endif else if (cmp < 0) { if (COMPARE(ehow, atom_read) == 0) +#ifdef __WIN32__ + *how = SD_RECEIVE; +#else *how = SHUT_RD; +#endif else return FALSE; } else { if (COMPARE(ehow, atom_write) == 0) +#ifdef __WIN32__ + *how = SD_SEND; +#else *how = SHUT_WR; +#endif else return FALSE; } return TRUE; } -#endif // #ifndef __WIN32__ @@ -18405,8 +12052,7 @@ size_t my_strnlen(const char *s, size_t maxlen) * terminate otherwise, so there is no need to test if * the sending fails. */ -#ifndef __WIN32__ -static +extern void esock_send_reg_add_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef) @@ -18422,7 +12068,6 @@ void esock_send_reg_add_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &data.regPid)) ); } } -#endif // #ifndef __WIN32__ @@ -18431,8 +12076,7 @@ void esock_send_reg_add_msg(ErlNifEnv* env, * terminate otherwise, so there is no need to test if * the sending fails. */ -#ifndef __WIN32__ -static +extern void esock_send_reg_del_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef) @@ -18448,9 +12092,6 @@ void esock_send_reg_del_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &data.regPid)) ); } } -#endif // #ifndef __WIN32__ - - /* =========================================================================== @@ -18467,8 +12108,7 @@ void esock_send_reg_del_msg(ErlNifEnv* env, * * This message will only be sent if the iow (Inform On Wrap) is TRUE. */ -#ifndef __WIN32__ -static +extern void esock_send_wrap_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, @@ -18486,7 +12126,6 @@ void esock_send_wrap_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, &descP->ctrlPid), cnt) ); } } -#endif // #ifndef __WIN32__ /* Send an close message to the specified process: @@ -18498,8 +12137,7 @@ void esock_send_wrap_msg(ErlNifEnv* env, * erlang API (close-) function for the socket to be "closed" * (actually that the 'stop' callback function has been called). */ -#ifndef __WIN32__ -static +extern void esock_send_close_msg(ErlNifEnv* env, ESockDescriptor* descP, ErlNifPid* pid) @@ -18519,17 +12157,20 @@ void esock_send_close_msg(ErlNifEnv* env, sockRef, descP->sock, MKPID(env, pid), descP->closeRef) ); } } + + + #ifdef HAVE_SENDFILE -static void -esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, - ESockDescriptor* descP) +extern +void esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, + ESockDescriptor* descP) { ERL_NIF_TERM sockRef, msg; ErlNifPid *pid; pid = &data.regPid; sockRef = enif_make_resource(env, descP); - msg = mk_reg_msg(env, atom_sendfile_deferred_close, sockRef); + msg = mk_reg_msg(env, esock_atom_sendfile_deferred_close, sockRef); /* If this send should fail we have leaked a file descriptor * (intolerable), and if we try to close it here, on a regular @@ -18540,7 +12181,6 @@ esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, ESOCK_ASSERT( esock_send_msg(env, pid, msg, NULL) ); } #endif // #ifdef HAVE_SENDFILE -#endif // #ifndef __WIN32__ /* Send an abort message to the specified process: @@ -18551,8 +12191,7 @@ esock_send_sendfile_deferred_close_msg(ErlNifEnv* env, * This message is for processes that is waiting in the * erlang API functions for a select message. */ -#ifndef __WIN32__ -static +extern void esock_send_abort_msg(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, @@ -18565,10 +12204,11 @@ void esock_send_abort_msg(ErlNifEnv* env, { ERL_NIF_TERM msg; - msg = - mk_abort_msg(reqP->env, - /* sockRef not in env so copy */ - CP_TERM(reqP->env, sockRef), reqP->ref, reason); + msg = mk_abort_msg(reqP->env, + /* sockRef not in env so copy */ + CP_TERM(reqP->env, sockRef), + reqP->ref, + CP_TERM(reqP->env, reason)); if (! esock_send_msg(env, &reqP->pid, msg, reqP->env)) { SSDBG( descP, @@ -18580,13 +12220,38 @@ void esock_send_abort_msg(ErlNifEnv* env, } reqP->env = NULL; } -#endif // #ifndef __WIN32__ + + +/* Send an *simple* abort message to the specified process: + * A message in the form: + * + * {'$socket', Socket, abort, Info} + * + */ +extern +void esock_send_simple_abort_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* pid, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + ERL_NIF_TERM msg = mk_simple_abort_msg(env, sockRef, reason); + + if (! esock_send_msg(env, pid, msg, NULL)) { + + SSDBG( descP, + ("SOCKET", + "esock_send_simple_abort_msg(%T) {%d} failed ->" + "\r\n pid: %T" + "\r\n", + sockRef, descP->sock, MKPID(env, pid)) ); + } +} /* Send a message to the specified process. */ -#ifndef __WIN32__ -static +extern BOOLEAN_T esock_send_msg(ErlNifEnv* env, ErlNifPid* pid, ERL_NIF_TERM msg, @@ -18597,7 +12262,6 @@ BOOLEAN_T esock_send_msg(ErlNifEnv* env, return !!res; } -#endif // #ifndef __WIN32__ @@ -18608,14 +12272,12 @@ BOOLEAN_T esock_send_msg(ErlNifEnv* env, * {'$socket', add, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef) { return mk_reg_msg(env, atom_add, sockRef); } -#endif // #ifndef __WIN32__ /* *** mk_reg_del_msg *** @@ -18625,14 +12287,12 @@ ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env, * {'$socket', del, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef) { return mk_reg_msg(env, atom_del, sockRef); } -#endif // #ifndef __WIN32__ /* *** mk_reg_msg *** @@ -18643,17 +12303,31 @@ ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env, * {'$socket', Tag, Socket} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, ERL_NIF_TERM tag, ERL_NIF_TERM sockRef) { - ERL_NIF_TERM socket = mk_socket(env, sockRef); + ERL_NIF_TERM socket = esock_mk_socket(env, sockRef); return MKT3(env, esock_atom_socket_tag, tag, socket); } -#endif // #ifndef __WIN32__ + + +/* *** mk_simple_abort_msg *** + * + * Create the simple abort message, which has the following form: + * + * {'$socket', Socket, abort, Info} + * + */ +static +ERL_NIF_TERM mk_simple_abort_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + return esock_mk_socket_msg(env, sockRef, esock_atom_abort, reason); +} /* *** mk_abort_msg *** @@ -18665,7 +12339,6 @@ ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env, * This message is for processes that are waiting in the * erlang API functions for a select (or this) message. */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, @@ -18674,9 +12347,8 @@ ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, { ERL_NIF_TERM info = MKT2(env, opRef, reason); - return mk_socket_msg(env, sockRef, esock_atom_abort, info); + return esock_mk_socket_msg(env, sockRef, esock_atom_abort, info); } -#endif // #ifndef __WIN32__ /* *** mk_wrap_msg *** @@ -18686,15 +12358,13 @@ ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env, * {'$socket', Socket, counter_wrap, Counter} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM cnt) { - return mk_socket_msg(env, sockRef, atom_counter_wrap, cnt); + return esock_mk_socket_msg(env, sockRef, atom_counter_wrap, cnt); } -#endif // #ifndef __WIN32__ /* *** mk_close_msg *** @@ -18704,15 +12374,14 @@ ERL_NIF_TERM mk_wrap_msg(ErlNifEnv* env, * {'$socket', Socket, close, closeRef} * */ -#ifndef __WIN32__ static ERL_NIF_TERM mk_close_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM closeRef) { - return mk_socket_msg(env, sockRef, esock_atom_close, closeRef); + return esock_mk_socket_msg(env, sockRef, esock_atom_close, closeRef); } -#endif // #ifndef __WIN32__ + /* *** mk_select_msg *** @@ -18728,12 +12397,12 @@ ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, ERL_NIF_TERM sockRef, ERL_NIF_TERM selectRef) { - return mk_socket_msg(env, sockRef, atom_select, selectRef); + return esock_mk_socket_msg(env, sockRef, esock_atom_select, selectRef); } #endif // #ifndef __WIN32__ -/* *** mk_socket_msg *** +/* *** esock_mk_socket_msg *** * * Construct the socket message: * @@ -18744,18 +12413,16 @@ ERL_NIF_TERM mk_select_msg(ErlNifEnv* env, * Info :: term() * */ -#ifndef __WIN32__ -static -ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM tag, - ERL_NIF_TERM info) +extern +ERL_NIF_TERM esock_mk_socket_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM tag, + ERL_NIF_TERM info) { - ERL_NIF_TERM socket = mk_socket(env, sockRef); + ERL_NIF_TERM socket = esock_mk_socket(env, sockRef); return MKT4(env, esock_atom_socket_tag, socket, tag, info); } -#endif // #ifndef __WIN32__ /* *** mk_socket *** @@ -18764,14 +12431,12 @@ ERL_NIF_TERM mk_socket_msg(ErlNifEnv* env, * * socket:socket() :: {'$socket', SockRef :: reference()} */ -#ifndef __WIN32__ -static -ERL_NIF_TERM mk_socket(ErlNifEnv* env, - ERL_NIF_TERM sockRef) +extern +ERL_NIF_TERM esock_mk_socket(ErlNifEnv* env, + ERL_NIF_TERM sockRef) { return MKT2(env, esock_atom_socket_tag, sockRef); } -#endif // #ifndef __WIN32__ /* ---------------------------------------------------------------------- @@ -18794,7 +12459,7 @@ ERL_NIF_TERM mk_socket(ErlNifEnv* env, * We choose the second alternative. */ #ifndef __WIN32__ -static +extern int esock_select_read(ErlNifEnv* env, ErlNifEvent event, // The file descriptor void* obj, // The socket descriptor object @@ -18818,7 +12483,7 @@ int esock_select_read(ErlNifEnv* env, * so no need to do that here, but the selectRef needs to be copied. */ #ifndef __WIN32__ -static +extern int esock_select_write(ErlNifEnv* env, ErlNifEvent event, // The file descriptor void* obj, // The socket descriptor @@ -18842,8 +12507,7 @@ int esock_select_write(ErlNifEnv* env, * So readMtx and writeMtx are supposed to be locked * when this function is called. */ -#ifndef __WIN32__ -static +extern int esock_select_stop(ErlNifEnv* env, ErlNifEvent event, void* obj) @@ -18851,10 +12515,8 @@ int esock_select_stop(ErlNifEnv* env, return enif_select(env, event, (ERL_NIF_SELECT_STOP), obj, NULL, esock_atom_undefined); } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ -static +extern int esock_select_cancel(ErlNifEnv* env, ErlNifEvent event, enum ErlNifSelectFlags mode, @@ -18863,7 +12525,7 @@ int esock_select_cancel(ErlNifEnv* env, return enif_select(env, event, (ERL_NIF_SELECT_CANCEL | mode), obj, NULL, esock_atom_undefined); } -#endif // #ifndef __WIN32__ + /* ---------------------------------------------------------------------- @@ -18871,9 +12533,9 @@ int esock_select_cancel(ErlNifEnv* env, * ---------------------------------------------------------------------- */ -/* *** activate_next_acceptor *** - * *** activate_next_writer *** - * *** activate_next_reader *** +/* *** esock_activate_next_acceptor *** + * *** esock_activate_next_writer *** + * *** esock_activate_next_reader *** * * This functions pops the requestors queue and then selects until it * manages to successfully activate a requestor or the queue is empty. @@ -18887,11 +12549,11 @@ int esock_select_cancel(ErlNifEnv* env, ACTIVATE_NEXT_FUNC_DECL(writer, write, currentWriter, writersQ) \ ACTIVATE_NEXT_FUNC_DECL(reader, read, currentReader, readersQ) -#define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \ - static \ - BOOLEAN_T activate_next_##F(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM sockRef) \ +#define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \ + extern \ + BOOLEAN_T esock_activate_next_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM sockRef) \ { \ BOOLEAN_T popped, activated; \ int sres; \ @@ -18902,13 +12564,13 @@ int esock_select_cancel(ErlNifEnv* env, popped = FALSE; \ do { \ \ - if (requestor_pop(q, reqP)) { \ + if (esock_requestor_pop(q, reqP)) { \ \ /* There was another one */ \ \ SSDBG( descP, \ ("SOCKET", \ - "activate_next_" #F "(%T) {%d} ->" \ + "esock_activate_next_" #F "(%T) {%d} ->" \ " new (active) requestor: " \ "\r\n pid: %T" \ "\r\n ref: %T" \ @@ -18946,7 +12608,7 @@ int esock_select_cancel(ErlNifEnv* env, \ SSDBG( descP, \ ("SOCKET", \ - "activate_next_" #F "(%T) {%d} ->" \ + "esock_activate_next_" #F "(%T) {%d} ->" \ " no more requestors\r\n", \ sockRef, descP->sock) ); \ \ @@ -18957,7 +12619,7 @@ int esock_select_cancel(ErlNifEnv* env, } while (!popped); \ \ SSDBG( descP, \ - ("SOCKET", "activate_next_" #F "(%T) {%d} -> " \ + ("SOCKET", "esock_activate_next_" #F "(%T) {%d} -> " \ "done with %s\r\n", \ sockRef, descP->sock, B2S(activated)) ); \ \ @@ -18978,11 +12640,22 @@ ACTIVATE_NEXT_FUNCS * we make use of set of declaration macros. */ -#ifndef __WIN32__ -/* *** acceptor_search4pid *** - * *** writer_search4pid *** - * *** reader_search4pid *** +extern +void esock_free_request_queue(ESockRequestQueue* q) +{ + while (q->first) { + ESockRequestQueueElement* free_me = q->first; + q->first = free_me->nextP; + esock_free_env("dtor", free_me->data.env); + FREE(free_me); + } +} + + +/* *** esock_acceptor_search4pid *** + * *** esock_writer_search4pid *** + * *** esock_reader_search4pid *** * * Search for a pid in the requestor (acceptor, writer, or reader) queue. * @@ -18993,43 +12666,41 @@ ACTIVATE_NEXT_FUNCS REQ_SEARCH4PID_FUNC_DECL(writer, writersQ) \ REQ_SEARCH4PID_FUNC_DECL(reader, readersQ) -#define REQ_SEARCH4PID_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_search4pid(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid* pid) \ - { \ - return qsearch4pid(env, &descP->Q, pid); \ +#define REQ_SEARCH4PID_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_search4pid(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid* pid) \ + { \ + return qsearch4pid(env, &descP->Q, pid); \ } REQ_SEARCH4PID_FUNCS #undef REQ_SEARCH4PID_FUNC_DECL -#endif // #ifndef __WIN32__ -/* *** acceptor_push *** - * *** writer_push *** - * *** reader_push *** +/* *** esock_acceptor_push *** + * *** esock_writer_push *** + * *** esock_reader_push *** * * Push a requestor (acceptor, writer, or reader) onto its queue. * This happens when we already have a current request (of its type). * */ -#ifndef __WIN32__ - #define REQ_PUSH_FUNCS \ REQ_PUSH_FUNC_DECL(acceptor, acceptorsQ) \ REQ_PUSH_FUNC_DECL(writer, writersQ) \ REQ_PUSH_FUNC_DECL(reader, readersQ) #define REQ_PUSH_FUNC_DECL(F, Q) \ - static \ - void F##_push(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ErlNifPid pid, /* self() */ \ - ERL_NIF_TERM ref) \ + extern \ + void esock_##F##_push(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ErlNifPid pid, /* self() */ \ + ERL_NIF_TERM ref, \ + void* dataP) \ { \ ESockRequestQueueElement *e; \ ESockRequestor *reqP; \ @@ -19037,24 +12708,22 @@ REQ_SEARCH4PID_FUNCS ESOCK_ASSERT( (e = MALLOC(sizeof(ESockRequestQueueElement))) \ != NULL ); \ reqP = &e->data; \ - reqP->pid = pid; \ - ESOCK_ASSERT( MONP(#F "_push -> " #F " request", \ + reqP->dataP = dataP; \ + reqP->pid = pid; \ + ESOCK_ASSERT( MONP("esock_" #F "_push -> " #F " request", \ env, descP, &pid, &reqP->mon) == 0 ); \ - reqP->env = esock_alloc_env(#F "_push"); \ - reqP->ref = CP_TERM(reqP->env, ref); \ + reqP->env = esock_alloc_env("esock_" #F "_push"); \ + reqP->ref = CP_TERM(reqP->env, ref); \ \ qpush(&descP->Q, e); \ } REQ_PUSH_FUNCS #undef REQ_PUSH_FUNC_DECL -#endif // #ifndef __WIN32__ - - -/* *** acceptor_pop *** - * *** writer_pop *** - * *** reader_pop *** +/* *** esock_acceptor_pop *** + * *** esock_writer_pop *** + * *** esock_reader_pop *** * * Pop a requestor (acceptor, writer, or reader) from its queue. * @@ -19067,13 +12736,13 @@ REQ_PUSH_FUNCS REQ_POP_FUNC_DECL(writer, writersQ) \ REQ_POP_FUNC_DECL(reader, readersQ) -#define REQ_POP_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_pop(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ESockRequestor* reqP) \ - { \ - return requestor_pop(&descP->Q, reqP); \ +#define REQ_POP_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_pop(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ESockRequestor* reqP) \ + { \ + return esock_requestor_pop(&descP->Q, reqP); \ } REQ_POP_FUNCS #undef REQ_POP_FUNC_DECL @@ -19082,15 +12751,57 @@ REQ_POP_FUNCS -/* *** acceptor_unqueue *** - * *** writer_unqueue *** - * *** reader_unqueue *** +/* *** esock_acceptor_get *** + * *** esock_writer_get *** + * *** esock_reader_get *** * * Remove a requestor (acceptor, writer, or reader) from its queue. * */ -#ifndef __WIN32__ +#ifdef __WIN32__ + +#define REQ_GET_FUNCS \ + REQ_GET_FUNC_DECL(acceptor, acceptorsQ) \ + REQ_GET_FUNC_DECL(writer, writersQ) \ + REQ_GET_FUNC_DECL(reader, readersQ) + +#define REQ_GET_FUNC_DECL(F, Q) \ + extern \ + BOOLEAN_T esock_##F##_get(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP, \ + ESockRequestor* reqP) \ + { \ + ESockRequestQueueElement* elemP; \ + \ + elemP = qget(env, descP, "esock_" #F "_get ", \ + &descP->Q, refP, pidP); \ + if (elemP != NULL) { \ + reqP->pid = elemP->data.pid; \ + reqP->mon = elemP->data.mon; \ + reqP->env = elemP->data.env; \ + reqP->ref = elemP->data.ref; \ + reqP->dataP = elemP->data.dataP; \ + return TRUE; \ + } \ + return FALSE; \ + } +REQ_GET_FUNCS +#undef REQ_GET_FUNC_DECL + +#endif // #ifndef __WIN32__ + + + +/* *** esock_acceptor_unqueue *** + * *** esock_writer_unqueue *** + * *** esock_reader_unqueue *** + * + * Remove a requestor (acceptor, writer, or reader) from its queue. + * + */ #define REQ_UNQUEUE_FUNCS \ REQ_UNQUEUE_FUNC_DECL(acceptor, acceptorsQ) \ @@ -19098,11 +12809,11 @@ REQ_POP_FUNCS REQ_UNQUEUE_FUNC_DECL(reader, readersQ) #define REQ_UNQUEUE_FUNC_DECL(F, Q) \ - static \ - BOOLEAN_T F##_unqueue(ErlNifEnv* env, \ - ESockDescriptor* descP, \ - ERL_NIF_TERM* refP, \ - const ErlNifPid* pidP) \ + extern \ + BOOLEAN_T esock_##F##_unqueue(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM* refP, \ + const ErlNifPid* pidP) \ { \ return qunqueue(env, descP, "qunqueue -> waiting " #F, \ &descP->Q, refP, pidP); \ @@ -19110,64 +12821,63 @@ REQ_POP_FUNCS REQ_UNQUEUE_FUNCS #undef REQ_UNQUEUE_FUNC_DECL -#endif // #ifndef __WIN32__ - - /* *** requestor pop *** * * Pop an requestor from its queue. */ -#ifndef __WIN32__ - -static -BOOLEAN_T requestor_pop(ESockRequestQueue* q, - ESockRequestor* reqP) +extern +BOOLEAN_T esock_requestor_pop(ESockRequestQueue* q, + ESockRequestor* reqP) { ESockRequestQueueElement* e = qpop(q); esock_free_env("requestor_pop", reqP->env); if (e != NULL) { - reqP->pid = e->data.pid; - reqP->mon = e->data.mon; - reqP->env = e->data.env; - reqP->ref = e->data.ref; + reqP->pid = e->data.pid; + reqP->mon = e->data.mon; + reqP->env = e->data.env; + reqP->ref = e->data.ref; + reqP->dataP = e->data.dataP; FREE(e); return TRUE; } else { /* Queue was empty */ - requestor_init(reqP); + esock_requestor_init(reqP); return FALSE; } } -static void requestor_init(ESockRequestor* reqP) { +extern +void esock_requestor_init(ESockRequestor* reqP) +{ enif_set_pid_undefined(&reqP->pid); MON_INIT(&reqP->mon); - reqP->env = NULL; - reqP->ref = esock_atom_undefined; + reqP->env = NULL; + reqP->ref = esock_atom_undefined; + reqP->dataP = NULL; } -static void requestor_release(const char* slogan, - ErlNifEnv* env, - ESockDescriptor* descP, - ESockRequestor* reqP) { - +extern +void esock_requestor_release(const char* slogan, + ErlNifEnv* env, + ESockDescriptor* descP, + ESockRequestor* reqP) +{ + reqP->dataP = NULL; enif_set_pid_undefined(&reqP->pid); (void) DEMONP(slogan, env, descP, &reqP->mon); + esock_clear_env(slogan, reqP->env); esock_free_env(slogan, reqP->env); reqP->env = NULL; reqP->ref = esock_atom_undefined; } -#endif // #ifndef __WIN32__ -#ifndef __WIN32__ - static BOOLEAN_T qsearch4pid(ErlNifEnv* env, ESockRequestQueue* q, @@ -19185,6 +12895,22 @@ BOOLEAN_T qsearch4pid(ErlNifEnv* env, return FALSE; } +static +unsigned int qlength(ESockRequestQueue* q) +{ + ESockRequestQueueElement* tmp; + unsigned int cnt = 0; + + tmp = q->first; + while (tmp != NULL) { + cnt++; + tmp = tmp->nextP; + } + + return cnt; +} + + static void qpush(ESockRequestQueue* q, ESockRequestQueueElement* e) @@ -19200,13 +12926,14 @@ void qpush(ESockRequestQueue* q, } } + static ESockRequestQueueElement* qpop(ESockRequestQueue* q) { ESockRequestQueueElement* e = q->first; if (e != NULL) { - /* Atleast one element in the queue */ + /* At least one element in the queue */ if (e == q->last) { /* Only one element in the queue */ q->first = q->last = NULL; @@ -19218,11 +12945,8 @@ ESockRequestQueueElement* qpop(ESockRequestQueue* q) return e; } -#endif // #ifndef __WIN32__ - -#ifndef __WIN32__ static BOOLEAN_T qunqueue(ErlNifEnv* env, ESockDescriptor* descP, @@ -19230,20 +12954,41 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, ESockRequestQueue* q, ERL_NIF_TERM* refP, const ErlNifPid* pidP) +{ + ESockRequestQueueElement* e = qget(env, descP, slogan, q, refP, pidP); + + if (e != NULL) { + (void) DEMONP(slogan, env, descP, &e->data.mon); + esock_clear_env(slogan, e->data.env); + esock_free_env(slogan, e->data.env); + FREE(e); + + return TRUE; + } else { + return FALSE; + } +} + + +static +ESockRequestQueueElement* qget(ErlNifEnv* env, + ESockDescriptor* descP, + const char* slogan, + ESockRequestQueue* q, + ERL_NIF_TERM* refP, + const ErlNifPid* pidP) { ESockRequestQueueElement* e = q->first; ESockRequestQueueElement* p = NULL; - /* Check if it was one of the waiting acceptor processes */ + /* Check if it was one of the waiting requestor processes */ while (e != NULL) { if (COMPARE_PIDS(&e->data.pid, pidP) == 0) { if ((refP != NULL) && (COMPARE(e->data.ref, *refP) != 0)) - return FALSE; + return NULL; /* We have a match */ - (void) DEMONP(slogan, env, descP, &e->data.mon); - if (p != NULL) { /* Not the first, but could be the last */ if (q->last == e) { @@ -19263,10 +13008,7 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, } } - esock_free_env("qunqueue", e->data.env); - FREE(e); - - return TRUE; + return e; } /* Try next */ @@ -19274,9 +13016,8 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, e = e->nextP; } - return FALSE; + return NULL; } -#endif // #ifndef __WIN32__ @@ -19285,10 +13026,8 @@ BOOLEAN_T qunqueue(ErlNifEnv* env, * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ - -static -BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc) +extern +BOOLEAN_T esock_cnt_inc(ESockCounter* cnt, ESockCounter inc) { BOOLEAN_T wrap; ESockCounter max = ESOCK_COUNTER_MAX; @@ -19305,8 +13044,8 @@ BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc) return (wrap); } -static -void cnt_dec(ESockCounter* cnt, ESockCounter dec) +extern +void esock_cnt_dec(ESockCounter* cnt, ESockCounter dec) { ESockCounter current = *cnt; @@ -19318,9 +13057,6 @@ void cnt_dec(ESockCounter* cnt, ESockCounter dec) return; } -#endif // #ifndef __WIN32__ - - /* ---------------------------------------------------------------------- @@ -19328,9 +13064,7 @@ void cnt_dec(ESockCounter* cnt, ESockCounter dec) * ---------------------------------------------------------------------- */ -#ifndef __WIN32__ - -static +extern int esock_monitor(const char* slogan, ErlNifEnv* env, ESockDescriptor* descP, @@ -19359,13 +13093,13 @@ int esock_monitor(const char* slogan, ("SOCKET", "esock_monitor {%d} [%T] %s: monitor ok: %T\r\n", descP->sock, esock_self(env), slogan, - esock_make_monitor_term(env, monP)) ); + ESOCK_MON2TERM(env, monP)) ); } return res; } -static +extern int esock_demonitor(const char* slogan, ErlNifEnv* env, ESockDescriptor* descP, @@ -19379,7 +13113,7 @@ int esock_demonitor(const char* slogan, SSDBG( descP, ("SOCKET", "esock_demonitor {%d} [%T] %s: try demonitor %T\r\n", descP->sock, esock_self(env), slogan, - esock_make_monitor_term(env, monP)) ); + ESOCK_MON2TERM(env, monP)) ); res = enif_demonitor_process(env, descP, &monP->mon); esock_monitor_init(monP); @@ -19394,13 +13128,13 @@ int esock_demonitor(const char* slogan, return res; } -static +extern void esock_monitor_init(ESockMonitor* monP) { monP->isActive = FALSE; } -static +extern ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP) { if (monP->isActive) @@ -19409,17 +13143,49 @@ ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP) return esock_atom_undefined; } -static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, - const ErlNifMonitor* mon) { +extern +BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, + const ErlNifMonitor* mon) { if (monP->isActive) return enif_compare_monitors(&monP->mon, mon) == 0; else return FALSE; } -#endif // #ifndef __WIN32__ +/* + * Misc ioctl utility functions. + */ +extern +ERL_NIF_TERM esock_encode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + int ivalue) +{ + ERL_NIF_TERM eivalue = MKI(env, ivalue); + + SSDBG( descP, ("SOCKET", "esock_encode_ioctl_ivalue -> done with" + "\r\n iValue: %T (%d)" + "\r\n", eivalue, ivalue) ); + + return esock_make_ok2(env, eivalue); +} + + +extern +ERL_NIF_TERM esock_encode_ioctl_bvalue(ErlNifEnv* env, + ESockDescriptor* descP, + int bvalue) +{ + ERL_NIF_TERM ebvalue = ((bvalue) ? esock_atom_true : esock_atom_false); + + SSDBG( descP, ("SOCKET", "esock_encode_ioctl_bvalue -> done with" + "\r\n bValue: %T (%d)" + "\r\n", ebvalue, bvalue) ); + + return esock_make_ok2(env, ebvalue); +} + /* ---------------------------------------------------------------------- * C a l l b a c k F u n c t i o n s @@ -19427,18 +13193,6 @@ static BOOLEAN_T esock_monitor_eq(const ESockMonitor* monP, */ -#ifndef __WIN32__ -static void free_request_queue(ESockRequestQueue* q) -{ - while (q->first) { - ESockRequestQueueElement* free_me = q->first; - q->first = free_me->nextP; - esock_free_env("dtor", free_me->data.env); - FREE(free_me); - } -} -#endif // #ifndef __WIN32__ - /* ========================================================================= * esock_dtor - Callback function for resource destructor * @@ -19446,79 +13200,30 @@ static void free_request_queue(ESockRequestQueue* q) static void esock_dtor(ErlNifEnv* env, void* obj) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; - MLOCK(descP->readMtx); - MLOCK(descP->writeMtx); - - SGDBG( ("SOCKET", "dtor {%d,0x%X}\r\n", - descP->sock, descP->readState | descP->writeState) ); - - if (IS_SELECTED(descP)) { - /* We have used the socket in the select machinery, - * so we must have closed it properly to get here - */ - ESOCK_ASSERT( IS_CLOSED(descP->readState) ); - ESOCK_ASSERT( IS_CLOSED(descP->writeState) ); - ESOCK_ASSERT( descP->sock == INVALID_SOCKET ); - } else { - /* The socket is only opened, should be safe to close nonblocking */ - (void) sock_close(descP->sock); - descP->sock = INVALID_SOCKET; - } - - SGDBG( ("SOCKET", "dtor -> set state and pattern\r\n") ); - descP->readState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); - descP->writeState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); - descP->pattern = (ESOCK_DESC_PATTERN_DTOR | ESOCK_STATE_CLOSED); - - esock_free_env("dtor reader", descP->currentReader.env); - descP->currentReader.env = NULL; - - esock_free_env("dtor writer", descP->currentWriter.env); - descP->currentWriter.env = NULL; - - esock_free_env("dtor acceptor", descP->currentAcceptor.env); - descP->currentAcceptor.env = NULL; - - SGDBG( ("SOCKET", "dtor -> try free readers request queue\r\n") ); - free_request_queue(&descP->readersQ); - - SGDBG( ("SOCKET", "dtor -> try free writers request queue\r\n") ); - free_request_queue(&descP->writersQ); - - SGDBG( ("SOCKET", "dtor -> try free acceptors request queue\r\n") ); - free_request_queue(&descP->acceptorsQ); - -#ifdef HAVE_SENDFILE - ESOCK_ASSERT( descP->sendfileHandle == INVALID_HANDLE ); - if (descP->sendfileCountersP != NULL) { - FREE(descP->sendfileCountersP); - descP->sendfileCountersP = NULL; - } -#endif + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); - esock_free_env("dtor close env", descP->closeEnv); - descP->closeEnv = NULL; + SGDBG( ("SOCKET", "esock_dtor {%d,0x%X}\r\n", + descP->sock, descP->readState | descP->writeState) ); - esock_free_env("dtor meta env", descP->meta.env); - descP->meta.env = NULL; + ESOCK_IO_DTOR(env, descP); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); - SGDBG( ("SOCKET", "dtor -> try destroy read mutex\r\n") ); + SGDBG( ("SOCKET", "esock_dtor -> try destroy read mutex\r\n") ); MDESTROY(descP->readMtx); descP->readMtx = NULL; - SGDBG( ("SOCKET", "dtor -> try destroy write mutex\r\n") ); + SGDBG( ("SOCKET", "esock_dtor -> try destroy write mutex\r\n") ); MDESTROY(descP->writeMtx); descP->writeMtx = NULL; - SGDBG( ("SOCKET", "dtor -> done\r\n") ); -#endif // #ifndef __WIN32__ + SGDBG( ("SOCKET", "esock_dtor -> done\r\n") ); } + /* ========================================================================= * esock_stop - Callback function for resource stop * @@ -19537,7 +13242,6 @@ void esock_dtor(ErlNifEnv* env, void* obj) static void esock_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, int is_direct_call) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; if (is_direct_call) { @@ -19590,97 +13294,26 @@ void esock_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, int is_direct_call) (unsigned long) descP->accWaits, (unsigned long) descP->accFails) ); -#ifdef HAVE_SENDFILE - if (descP->sendfileCountersP != NULL) { - ESockSendfileCounters *cP = descP->sendfileCountersP; - - SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} ->" - "\r\nsendfileCounters:" - "\r\n cnt: %lu" - "\r\n byteCnt: %lu" - "\r\n fails: %lu" - "\r\n max: %lu" - "\r\n pkg: %lu" - "\r\n pkgMax %lu" - "\r\n tries: %lu" - "\r\n waits: %lu" - "\r\n", - descP->sock, fd, - (unsigned long) cP->cnt, - (unsigned long) cP->byteCnt, - (unsigned long) cP->fails, - (unsigned long) cP->max, - (unsigned long) cP->pkg, - (unsigned long) cP->pkgMax, - (unsigned long) cP->tries, - (unsigned long) cP->waits) ); - } -#endif - - /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * - * Inform waiting Closer, or close socket - * - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - if (! enif_is_pid_undefined(&descP->closerPid)) { - /* We have a waiting closer process after nif_close() - * - send message to trigger nif_finalize_close() - */ - - SSDBG( descP, - ("SOCKET", - "esock_stop {%d/%d} -> send close msg to %T\r\n", - descP->sock, fd, MKPID(env, &descP->closerPid)) ); - - esock_send_close_msg(env, descP, &descP->closerPid); - /* Message send frees closeEnv */ - descP->closeEnv = NULL; - descP->closeRef = esock_atom_undefined; - } else { - int err; - - /* We do not have a closer process - * - have to do an unclean (non blocking) close */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); + ESOCK_IO_STOP(env, descP); - if (err != 0) - esock_warning_msg("Failed closing socket without " - "closer process: " - "\r\n Controlling Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - descP->ctrlPid, descP->sock, - err, MKA(env, erl_errno_id(err))); - } + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); SSDBG( descP, ("SOCKET", "esock_stop {%d/%d} -> done\r\n", descP->sock, fd) ); - MUNLOCK(descP->writeMtx); - MUNLOCK(descP->readMtx); -#endif // #ifndef __WIN32__ } -/* *** esock_stop_handle_current *** +/* *** esock_stop_handle_currentalloc_desc *** * * Handle current requestor (reader, writer or acceptor) during * socket stop. */ -#ifndef __WIN32__ -static +extern void esock_stop_handle_current(ErlNifEnv* env, const char* role, ESockDescriptor* descP, @@ -19694,12 +13327,11 @@ void esock_stop_handle_current(ErlNifEnv* env, " send abort message to current %s %T %T\r\n", descP->sock, role, reqP->pid, reqP->ref) ); - esock_send_abort_msg(env, descP, sockRef, reqP, atom_closed); + esock_send_abort_msg(env, descP, sockRef, reqP, esock_atom_closed); enif_set_pid_undefined(&reqP->pid); reqP->ref = esock_atom_undefined; } -#endif // #ifndef __WIN32__ @@ -19707,14 +13339,13 @@ void esock_stop_handle_current(ErlNifEnv* env, * nif_abort message with the specified reason to each member, * and empty the queue. */ -#ifndef __WIN32__ -static -void inform_waiting_procs(ErlNifEnv* env, - const char* role, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ESockRequestQueue* q, - ERL_NIF_TERM reason) +extern +void esock_inform_waiting_procs(ErlNifEnv* env, + const char* role, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ESockRequestQueue* q, + ERL_NIF_TERM reason) { ESockRequestQueueElement* currentP = q->first; ESockRequestQueueElement* nextP; @@ -19754,7 +13385,6 @@ void inform_waiting_procs(ErlNifEnv* env, q->first = NULL; q->last = NULL; } -#endif // #ifndef __WIN32__ /* ========================================================================= @@ -19767,7 +13397,6 @@ void esock_down(ErlNifEnv* env, const ErlNifPid* pidP, const ErlNifMonitor* monP) { -#ifndef __WIN32__ ESockDescriptor* descP = (ESockDescriptor*) obj; MLOCK(descP->readMtx); @@ -19781,361 +13410,37 @@ void esock_down(ErlNifEnv* env, B2S(IS_CLOSED(descP->readState)), B2S(IS_CLOSING(descP->readState))) ); - if (COMPARE_PIDS(&descP->closerPid, pidP) == 0) { - - /* The closer process went down - * - it will not call nif_finalize_close - */ - - enif_set_pid_undefined(&descP->closerPid); - - if (MON_EQ(&descP->closerMon, monP)) { - MON_INIT(&descP->closerMon); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> closer process exit\r\n", - descP->sock) ); - - } else { - // The owner is the closer so we used its monitor - - ESOCK_ASSERT( MON_EQ(&descP->ctrlMon, monP) ); - MON_INIT(&descP->ctrlMon); - enif_set_pid_undefined(&descP->ctrlPid); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> closer controlling process exit\r\n", - descP->sock) ); - } - - /* Since the closer went down there was one, - * hence esock_close() must have run or scheduled esock_stop(), - * or the socket has never been selected upon - */ - - if (descP->closeEnv == NULL) { - int err; - - /* Since there is no closeEnv, - * esock_close() did not schedule esock_stop() - * and is about to call esock_finalize_close() but died, - * or esock_stop() has run, sent close_msg to the closer - * and cleared ->closeEnv but the closer died - * - we have to do an unclean (non blocking) socket close here - */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); - if (err != 0) - esock_warning_msg("Failed closing socket for terminating " - "closer process: " - "\r\n Closer Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - MKPID(env, pidP), descP->sock, - err, MKA(env, erl_errno_id(err))); - } else { - /* Since there is a closeEnv esock_stop() has not run yet - * - when it finds that there is no closer process - * it will close the socket and ignore the close_msg - */ - esock_free_env("esock_down - close-env", descP->closeEnv); - descP->closeEnv = NULL; - descP->closeRef = esock_atom_undefined; - } - - } else if (MON_EQ(&descP->ctrlMon, monP)) { - MON_INIT(&descP->ctrlMon); - /* The owner went down */ - enif_set_pid_undefined(&descP->ctrlPid); - - if (IS_OPEN(descP->readState)) { - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> controller process exit" - "\r\n initiate close\r\n", - descP->sock) ); - - esock_down_ctrl(env, descP, pidP); - - descP->readState |= ESOCK_STATE_CLOSING; - descP->writeState |= ESOCK_STATE_CLOSING; - } else { - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> controller process exit" - "\r\n already closed or closing\r\n", - descP->sock) ); - } - - } else if (descP->connectorP != NULL && - MON_EQ(&descP->connector.mon, monP)) { - MON_INIT(&descP->connector.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down {%d} -> connector process exit\r\n", - descP->sock) ); - - /* connectorP is only set during connection. - * Forget all about the ongoing connection. - * We might end up connected, but the process that initiated - * the connection has died and will never know - */ - - requestor_release("esock_down->connector", - env, descP, &descP->connector); - descP->connectorP = NULL; - descP->writeState &= ~ESOCK_STATE_CONNECTING; - - } else { - ERL_NIF_TERM sockRef; - - /* check all operation queue(s): acceptor, writer and reader. - * - * Is it really any point in doing this if the socket is closed? - * - */ - - sockRef = enif_make_resource(env, descP); - - if (IS_CLOSED(descP->readState)) { - SSDBG( descP, - ("SOCKET", - "esock_down(%T) {%d} -> stray down: %T\r\n", - sockRef, descP->sock, pidP) ); - } else { - - SSDBG( descP, - ("SOCKET", - "esock_down(%T) {%d} -> other process term\r\n", - sockRef, descP->sock) ); - - if (descP->currentReaderP != NULL) - esock_down_reader(env, descP, sockRef, pidP, monP); - if (descP->currentAcceptorP != NULL) - esock_down_acceptor(env, descP, sockRef, pidP, monP); - if (descP->currentWriterP != NULL) - esock_down_writer(env, descP, sockRef, pidP, monP); - } - } + ESOCK_IO_DOWN(env, descP, pidP, monP); MUNLOCK(descP->writeMtx); MUNLOCK(descP->readMtx); SSDBG( descP, ("SOCKET", "esock_down -> done\r\n") ); -#endif // #ifndef __WIN32__ -} - - - -/* *** esock_down_ctrl *** - * - * Stop after a downed controller - * - */ -#ifndef __WIN32__ -static -void esock_down_ctrl(ErlNifEnv* env, - ESockDescriptor* descP, - const ErlNifPid* pidP) -{ - SSDBG( descP, - ("SOCKET", "esock_down_ctrl {%d} ->" - "\r\n Pid: %T" - "\r\n", descP->sock, MKPID(env, pidP)) ); - - if (esock_do_stop(env, descP)) { - /* esock_stop() is scheduled - * - it has to close the socket - */ - SSDBG( descP, - ("SOCKET", "esock_down_ctrl {%d} -> stop was scheduled\r\n", - descP->sock) ); - } else { - int err; - - /* Socket is not in the select machinery - * so esock_stop() will not be called - * - we have to do an unclean (non blocking) socket close here - */ - -#ifdef HAVE_SENDFILE - if (descP->sendfileHandle != INVALID_HANDLE) - esock_send_sendfile_deferred_close_msg(env, descP); -#endif - - err = esock_close_socket(env, descP, FALSE); - if (err != 0) - esock_warning_msg("Failed closing socket for terminating " - "owner process: " - "\r\n Owner Process: %T" - "\r\n Descriptor: %d" - "\r\n Errno: %d (%T)" - "\r\n", - MKPID(env, pidP), descP->sock, - err, MKA(env, erl_errno_id(err))); - } } -#endif // #ifndef __WIN32__ - - - -/* *** esock_down_acceptor *** - * - * Check and then handle a downed acceptor process. - * - */ -#ifndef __WIN32__ -static -void esock_down_acceptor(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) -{ - if (MON_EQ(&descP->currentAcceptor.mon, monP)) { - MON_INIT(&descP->currentAcceptor.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> " - "current acceptor - try activate next\r\n", - sockRef, descP->sock) ); - - if (!activate_next_acceptor(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> no more writers\r\n", - sockRef, descP->sock) ); - descP->readState &= ~ESOCK_STATE_ACCEPTING; - - descP->currentAcceptorP = NULL; - } - - } else { - - /* Maybe unqueue one of the waiting acceptors */ - - SSDBG( descP, - ("SOCKET", - "esock_down_acceptor(%T) {%d} -> " - "not current acceptor - maybe a waiting acceptor\r\n", - sockRef, descP->sock) ); - - acceptor_unqueue(env, descP, NULL, pidP); - } -} -#endif // #ifndef __WIN32__ -/* *** esock_down_writer *** - * - * Check and then handle a downed writer process. - * +/* + * The idea with this function is that it should call esock_io_finish + * and release anything allocated by the I/O backend (just to be a + * nice citizen). + * On Unix this currently a void operation, but on Windows it will be + * more substantial... + * So, this is currently just a placeholder. */ -#ifndef __WIN32__ static -void esock_down_writer(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) +void esock_on_halt(void* priv_data) { - if (MON_EQ(&descP->currentWriter.mon, monP)) { - MON_INIT(&descP->currentWriter.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> " - "current writer - try activate next\r\n", - sockRef, descP->sock) ); - - if (!activate_next_writer(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> no active writer\r\n", - sockRef, descP->sock) ); - - descP->currentWriterP = NULL; - } - - } else { - - /* Maybe unqueue one of the waiting writer(s) */ - - SSDBG( descP, - ("SOCKET", - "esock_down_writer(%T) {%d} -> " - "not current writer - maybe a waiting writer\r\n", - sockRef, descP->sock) ); - - writer_unqueue(env, descP, NULL, pidP); - } -} -#endif // #ifndef __WIN32__ - - - - -/* *** esock_down_reader *** - * - * Check and then handle a downed reader process. - * - */ + // We do not *currently* use this (priv_data), so ignore #ifndef __WIN32__ -static -void esock_down_reader(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - const ErlNifPid* pidP, - const ErlNifMonitor* monP) -{ - if (MON_EQ(&descP->currentReader.mon, monP)) { - MON_INIT(&descP->currentReader.mon); - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> " - "current reader - try activate next\r\n", - sockRef, descP->sock) ); - - if (! activate_next_reader(env, descP, sockRef)) { - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> no more readers\r\n", - sockRef, descP->sock) ); - - descP->currentReaderP = NULL; - } + VOID(priv_data); +#else + VOIDP(priv_data); +#endif - } else { - - /* Maybe unqueue one of the waiting reader(s) */ - - SSDBG( descP, - ("SOCKET", - "esock_down_reader(%T) {%d} -> " - "not current reader - maybe a waiting reader\r\n", - sockRef, descP->sock) ); - - reader_unqueue(env, descP, NULL, pidP); - } + ESOCK_IO_FIN(); } -#endif // #ifndef __WIN32__ - /* ---------------------------------------------------------------------- @@ -20192,7 +13497,6 @@ ErlNifFunc esock_funcs[] = }; -#ifndef __WIN32__ static char* extract_debug_filename(ErlNifEnv* env, ERL_NIF_TERM map) @@ -20214,7 +13518,6 @@ char* extract_debug_filename(ErlNifEnv* env, filename[bin.size] = '\0'; return filename; } -#endif // #ifndef __WIN32__ @@ -20225,10 +13528,13 @@ char* extract_debug_filename(ErlNifEnv* env, static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + ErlNifSysInfo sysInfo; + unsigned int ioNumThreads, ioNumThreadsDef; + /* +++ Local atoms and error reason atoms +++ */ #define LOCAL_ATOM_DECL(A) atom_##A = MKA(env, #A) LOCAL_ATOMS; - LOCAL_ERROR_REASON_ATOMS; + // LOCAL_ERROR_REASON_ATOMS; #undef LOCAL_ATOM_DECL /* Global atom(s) and error reason atom(s) */ @@ -20239,8 +13545,6 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) esock_atom_socket_tag = MKA(env, "$socket"); -#ifndef __WIN32__ - if (! esock_extract_pid_from_map(env, load_info, atom_registry, &data.regPid)) { @@ -20248,16 +13552,26 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) return 1; // Failure - no registry pid } + /* --esock-disable-registry */ data.useReg = esock_get_bool_from_map(env, load_info, - atom_use_registry, + esock_atom_use_registry, ESOCK_USE_SOCKET_REGISTRY); + /* --esock-enable-iow */ data.iow = esock_get_bool_from_map(env, load_info, atom_iow, ESOCK_NIF_IOW_DEFAULT); + /* --enable-extended-error-info */ +#if defined(ESOCK_USE_EXTENDED_ERROR_INFO) + data.eei = TRUE; +#else + data.eei = FALSE; +#endif + + /* --esock-debug-file= */ { char *debug_filename; @@ -20296,9 +13610,37 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) data.numProtoUDP = 0; data.numProtoSCTP = 0; + initOpts(); initCmsgTables(); + + // #define ESOCK_DISPLAY_OPTION_TABLES 1 +#if defined(ESOCK_DISPLAY_OPTION_TABLES) + { + /* Display option table(s) after init */ + ESOCK_EPRINTF("\r\n[ESOCK] Option tables after init:\r\n"); + + for (int levelIdx = 0; levelIdx < NUM(optLevels); levelIdx++) { + int numOpts = optLevels[levelIdx].num; + int level = optLevels[levelIdx].level; + ERL_NIF_TERM lname = *optLevels[levelIdx].nameP; + struct ESockOpt* opts = optLevels[levelIdx].opts; + + ESOCK_EPRINTF("[ESOCK] [%d] Option table for level %T (%d) (%d options):\r\n", + levelIdx, lname, level, numOpts); + + for (int optIdx = 0; optIdx < numOpts; optIdx++) { + ESOCK_EPRINTF("[ESOCK] %T[%d]: %T -> %d\r\n", + lname, optIdx, lname, opts[optIdx].opt); + + } + ESOCK_EPRINTF("\r\n"); + } + } +#endif + + data.iov_max = #if defined(NO_SYSCONF) || (! defined(_SC_IOV_MAX)) # ifdef IOV_MAX @@ -20312,16 +13654,158 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) ; ESOCK_ASSERT( data.iov_max > 0 ); -#endif // #ifndef __WIN32__ + + /* This is (currently) intended for Windows use */ + enif_system_info(&sysInfo, sizeof(ErlNifSysInfo)); + + /* We should have a config options for this: + * --esock-num-io-threads=16 + * + * ESOCK_IO_NUM_THREADS + */ + ioNumThreadsDef = + (unsigned int) (sysInfo.scheduler_threads > 0) ? + 2*sysInfo.scheduler_threads : 2; + + ioNumThreads = esock_get_uint_from_map(env, load_info, + atom_io_num_threads, + ioNumThreadsDef); + +#ifdef __WIN32__ + + io_backend.init = esaio_init; + io_backend.finish = esaio_finish; + + io_backend.info = esaio_info; + io_backend.cmd = esock_command; + io_backend.supports_0 = esock_supports_0; + io_backend.supports_1 = esock_supports_1; + + io_backend.open_with_fd = NULL; + io_backend.open_plain = esaio_open_plain; + io_backend.bind = esaio_bind; + io_backend.connect = esaio_connect; + io_backend.listen = esock_listen; + io_backend.accept = esaio_accept; + io_backend.send = esaio_send; + io_backend.sendto = esaio_sendto; + io_backend.sendmsg = esaio_sendmsg; + io_backend.sendfile_start = NULL; + io_backend.sendfile_cont = NULL; + io_backend.sendfile_dc = NULL; + io_backend.recv = esaio_recv; + io_backend.recvfrom = esaio_recvfrom; + io_backend.recvmsg = esaio_recvmsg; + io_backend.close = esaio_close; + io_backend.fin_close = esaio_fin_close; + io_backend.shutdown = esock_shutdown; + io_backend.sockname = esock_sockname; + io_backend.peername = esock_peername; + io_backend.cancel_connect = esaio_cancel_connect; + io_backend.cancel_accept = esaio_cancel_accept; + io_backend.cancel_send = esaio_cancel_send; + io_backend.cancel_recv = esaio_cancel_recv; + + io_backend.setopt = esock_setopt; + io_backend.setopt_native = esock_setopt_native; + io_backend.setopt_otp = esock_setopt_otp; + io_backend.getopt = esock_getopt; + io_backend.getopt_native = esock_getopt_native; + io_backend.getopt_otp = esock_getopt_otp; + + io_backend.ioctl_2 = esaio_ioctl2; + io_backend.ioctl_3 = esaio_ioctl3; + io_backend.ioctl_4 = NULL; + + io_backend.dtor = esaio_dtor; + io_backend.stop = NULL; // esaio_stop; + io_backend.down = esaio_down; + +#else + + io_backend.init = essio_init; + io_backend.finish = essio_finish; + + io_backend.info = essio_info; + io_backend.cmd = esock_command; + io_backend.supports_0 = esock_supports_0; + io_backend.supports_1 = esock_supports_1; + + io_backend.open_with_fd = essio_open_with_fd; + io_backend.open_plain = essio_open_plain; + io_backend.bind = essio_bind; + io_backend.connect = essio_connect; + io_backend.listen = esock_listen; + io_backend.accept = essio_accept; + io_backend.send = essio_send; + io_backend.sendto = essio_sendto; + io_backend.sendmsg = essio_sendmsg; + io_backend.sendfile_start = essio_sendfile_start; + io_backend.sendfile_cont = essio_sendfile_cont; + io_backend.sendfile_dc = essio_sendfile_deferred_close; + io_backend.recv = essio_recv; + io_backend.recvfrom = essio_recvfrom; + io_backend.recvmsg = essio_recvmsg; + io_backend.close = essio_close; + io_backend.fin_close = essio_fin_close; + io_backend.shutdown = esock_shutdown; + io_backend.sockname = esock_sockname; + io_backend.peername = esock_peername; + io_backend.cancel_connect = essio_cancel_connect; + io_backend.cancel_accept = essio_cancel_accept; + io_backend.cancel_send = essio_cancel_send; + io_backend.cancel_recv = essio_cancel_recv; + + io_backend.setopt = esock_setopt; + io_backend.setopt_native = esock_setopt_native; + io_backend.setopt_otp = esock_setopt_otp; + io_backend.getopt = esock_getopt; + io_backend.getopt_native = esock_getopt_native; + io_backend.getopt_otp = esock_getopt_otp; + + io_backend.ioctl_2 = essio_ioctl2; + io_backend.ioctl_3 = essio_ioctl3; + io_backend.ioctl_4 = essio_ioctl4; + + io_backend.dtor = essio_dtor; + io_backend.stop = essio_stop; + io_backend.down = essio_down; + +#endif + + if (ESOCK_IO_INIT(ioNumThreads) != ESOCK_IO_OK) { + esock_error_msg("Failed initiating I/O backend"); + return 1; // Failure + } esocks = enif_open_resource_type_x(env, "sockets", &esockInit, ERL_NIF_RT_CREATE, NULL); - return esocks != NULL ? - 0: // Success - 1; // Failure + + if (esocks != NULL) { + int ores; + + // *Try* install on-halt (callback) function + if ((ores = enif_set_option(env, + ERL_NIF_OPT_ON_HALT, + esock_on_halt)) != 0) { + esock_error_msg("Failed installing 'on-halt' " + "callback function (%d)\r\n", ores); + return 1; // Failure + } + + // *Try* enable 'delay on halt' (none-fatal) + if ((ores = enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)) != 0) { + esock_error_msg("Failed enable 'on-halt' delay (%d)\r\n", ores); + } + + return 0; // Success + } else { + esock_error_msg("Failed open esock resource type\r\n"); + return 1; // Failure + } } /* @@ -20333,3 +13817,5 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) * unload: NULL (not used) */ ERL_NIF_INIT(prim_socket, esock_funcs, on_load, NULL, NULL, NULL) + +#endif diff --git a/erts/emulator/nifs/common/prim_tty_nif.c b/erts/emulator/nifs/common/prim_tty_nif.c new file mode 100644 index 000000000000..84c42f444b89 --- /dev/null +++ b/erts/emulator/nifs/common/prim_tty_nif.c @@ -0,0 +1,1168 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson 2015-2023. 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% + */ + +/* + * Purpose: NIF library for interacting with the tty + * + */ + +#define STATIC_ERLANG_NIF 1 + +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif + +#include "config.h" +#include "sys.h" +#include "erl_nif.h" +#include "erl_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TERMCAP +#include +#include +#endif +#ifndef __WIN32__ +#include +#include +#endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#if defined IOV_MAX +#define MAXIOV IOV_MAX +#elif defined UIO_MAXIOV +#define MAXIOV UIO_MAXIOV +#else +#define MAXIOV 16 +#endif + +#if !defined(HAVE_SETLOCALE) || !defined(HAVE_NL_LANGINFO) || !defined(HAVE_LANGINFO_H) +#define PRIMITIVE_UTF8_CHECK 1 +#else +#include +#endif + +#ifdef VALGRIND +# include +#endif + +#define DEF_HEIGHT 24 +#define DEF_WIDTH 80 + +typedef struct { +#ifdef __WIN32__ + HANDLE ofd; + HANDLE ifd; + HANDLE ifdOverlapped; + DWORD dwOriginalOutMode; + DWORD dwOriginalInMode; + DWORD dwOutMode; + DWORD dwInMode; + + /* Fields to handle the threaded reader */ + OVERLAPPED overlapped; + ErlNifBinary overlappedBuffer; +#else + int ofd; /* stdout */ + int ifd; /* stdin */ +#endif + ErlNifPid self; + ErlNifPid reader; + int tty; /* if the tty is initialized */ +#ifndef __WIN32__ + int signal[2]; /* Pipe used for signal (winch + cont) notifications */ +#endif +#ifdef HAVE_TERMCAP + struct termios tty_smode; + struct termios tty_rmode; +#endif +} TTYResource; + +// #define HARD_DEBUG +#ifdef HARD_DEBUG +static FILE *logFile = NULL; + +#define debug(fmt, ...) do { if (logFile) { erts_fprintf(logFile, fmt, __VA_ARGS__); fflush(logFile); } } while(0) +#else +#define debug(...) do { } while(0) +#endif + +static ErlNifResourceType *tty_rt; + +/* The NIFs: */ +static ERL_NIF_TERM isatty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_create_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_set_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM setlocale_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_encoding_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM isprint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wcwidth_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wcswidth_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sizeof_wchar_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_window_size_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_tgetent_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_tgetnum_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_tgetflag_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_tgetstr_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_tgoto_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM tty_read_signal_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"isatty", 1, isatty_nif}, + {"tty_create", 0, tty_create_nif}, + {"tty_init", 3, tty_init_nif}, + {"tty_set", 1, tty_set_nif}, + {"tty_read_signal", 2, tty_read_signal_nif}, + {"setlocale", 1, setlocale_nif}, + {"tty_select", 3, tty_select_nif}, + {"tty_window_size", 1, tty_window_size_nif}, + {"write_nif", 2, tty_write_nif, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"tty_encoding", 1, tty_encoding_nif}, + {"read_nif", 2, tty_read_nif, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"isprint", 1, isprint_nif}, + {"wcwidth", 1, wcwidth_nif}, + {"wcswidth", 1, wcswidth_nif}, + {"sizeof_wchar", 0, sizeof_wchar_nif}, + {"tgetent_nif", 1, tty_tgetent_nif}, + {"tgetnum_nif", 1, tty_tgetnum_nif}, + {"tgetflag_nif", 1, tty_tgetflag_nif}, + {"tgetstr_nif", 1, tty_tgetstr_nif}, + {"tgoto_nif", 1, tty_tgoto_nif}, + {"tgoto_nif", 2, tty_tgoto_nif}, + {"tgoto_nif", 3, tty_tgoto_nif} +}; + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info); +static void unload(ErlNifEnv* env, void* priv_data); + +ERL_NIF_INIT(prim_tty, nif_funcs, load, NULL, upgrade, unload) + +#define ATOMS \ + ATOM_DECL(canon); \ + ATOM_DECL(echo); \ + ATOM_DECL(ebadf); \ + ATOM_DECL(undefined); \ + ATOM_DECL(error); \ + ATOM_DECL(true); \ + ATOM_DECL(stdout); \ + ATOM_DECL(ok); \ + ATOM_DECL(input); \ + ATOM_DECL(false); \ + ATOM_DECL(stdin); \ + ATOM_DECL(stdout); \ + ATOM_DECL(stderr); \ + ATOM_DECL(select); \ + ATOM_DECL(sig); + + +#define ATOM_DECL(A) static ERL_NIF_TERM atom_##A +ATOMS +#undef ATOM_DECL + +static ERL_NIF_TERM make_error(ErlNifEnv *env, ERL_NIF_TERM reason) { + return enif_make_tuple2(env, atom_error, reason); +} + +static ERL_NIF_TERM make_enotsup(ErlNifEnv *env) { + return make_error(env, enif_make_atom(env, "enotsup")); +} + +static ERL_NIF_TERM make_errno(ErlNifEnv *env) { +#ifdef __WIN32__ + return enif_make_atom(env, last_error()); +#else + return enif_make_atom(env, erl_errno_id(errno)); +#endif +} + +static ERL_NIF_TERM make_errno_error(ErlNifEnv *env, const char *function) { + return make_error( + env, enif_make_tuple2( + env, enif_make_atom(env, function), make_errno(env))); +} + +static int tty_get_fd(ErlNifEnv *env, ERL_NIF_TERM atom, int *fd) { + if (enif_is_identical(atom, atom_stdout)) { + *fd = fileno(stdout); + } else if (enif_is_identical(atom, atom_stdin)) { + *fd = fileno(stdin); + } else if (enif_is_identical(atom, atom_stderr)) { + *fd = fileno(stderr); + } else { + return 0; + } + return 1; +} + +static ERL_NIF_TERM isatty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + int fd; + + if (tty_get_fd(env, argv[0], &fd)) { + if (isatty(fd)) { + return atom_true; + } else if (errno == EINVAL || errno == ENOTTY) { + return atom_false; + } else { + return atom_ebadf; + } + } + + return enif_make_badarg(env); +} + +static ERL_NIF_TERM tty_encoding_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef __WIN32__ + TTYResource *tty; + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + if (tty->tty) + return enif_make_tuple2(env, enif_make_atom(env, "utf16"), + enif_make_atom(env, "little")); +#endif + return enif_make_atom(env, "utf8"); +} + + +static ERL_NIF_TERM isprint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + int i; + if (enif_get_int(env, argv[0], &i)) { + ASSERT(i > 0 && i < 256); + return isprint((char)i) ? atom_true : atom_false; + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wcwidth_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + int i; + if (enif_get_int(env, argv[0], &i)) { +#ifndef __WIN32__ + int width; + ASSERT(i > 0 && i < (1l << 21)); + width = wcwidth((wchar_t)i); + if (width == -1) { + return make_error(env, enif_make_atom(env, "not_printable")); + } + return enif_make_int(env, width); +#else + return make_enotsup(env); +#endif + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wcswidth_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + ErlNifBinary bin; + if (enif_inspect_iolist_as_binary(env, argv[0], &bin)) { + wchar_t *chars = (wchar_t*)bin.data; + int width; +#ifdef DEBUG + for (int i = 0; i < bin.size / sizeof(wchar_t); i++) { + ASSERT(chars[i] >= 0 && chars[i] < (1l << 21)); + } +#endif +#ifndef __WIN32__ + width = wcswidth(chars, bin.size / sizeof(wchar_t)); +#else + width = bin.size / sizeof(wchar_t); +#endif + if (width == -1) { + return make_error(env, enif_make_atom(env, "not_printable")); + } + return enif_make_tuple2(env, atom_ok, enif_make_int(env, width)); + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM sizeof_wchar_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + return enif_make_int(env, sizeof(wchar_t)); +} + +static ERL_NIF_TERM tty_write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + ERL_NIF_TERM head = argv[1], tail; + ErlNifIOQueue *q = NULL; + ErlNifIOVec vec, *iovec = &vec; + SysIOVec *iov; + int iovcnt; + TTYResource *tty; + ssize_t res = 0; + size_t size; + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + + while (!enif_is_identical(head, enif_make_list(env, 0))) { + if (!enif_inspect_iovec(env, MAXIOV, head, &tail, &iovec)) + return enif_make_badarg(env); + + head = tail; + + iov = iovec->iov; + size = iovec->size; + iovcnt = iovec->iovcnt; + + do { +#ifndef __WIN32__ + do { + res = writev(tty->ofd, iov, iovcnt); + } while(res < 0 && (errno == EINTR || errno == EAGAIN)); +#else + for (int i = 0; i < iovec->iovcnt; i++) { + ssize_t written; +#ifdef HARD_DEBUG + for (int y = 0; y < iovec->iov[i].iov_len; y++) + debug("Write %u\r\n",iovec->iov[i].iov_base[y]); +#endif + BOOL r = WriteFile(tty->ofd, iovec->iov[i].iov_base, + iovec->iov[i].iov_len, &written, NULL); + if (!r) { + res = -1; + break; + } + res += written; + } +#endif + if (res < 0) { + if (q) enif_ioq_destroy(q); + return make_error(env, make_errno(env)); + } + if (res != size) { + if (!q) { + q = enif_ioq_create(ERL_NIF_IOQ_NORMAL); + enif_ioq_enqv(q, iovec, 0); + } + } + + if (q) { + enif_ioq_deq(q, res, &size); + if (size == 0) { + enif_ioq_destroy(q); + q = NULL; + } else { + iov = enif_ioq_peek(q, &iovcnt); + } + } + } while(q); + + }; + return atom_ok; +} + +static ERL_NIF_TERM tty_read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + TTYResource *tty; + ErlNifBinary bin; + ERL_NIF_TERM res_term; + ssize_t res = 0; +#ifdef __WIN32__ + HANDLE select_event; +#else + int select_event; +#endif + + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + + select_event = tty->ifd; + +#ifdef __WIN32__ + debug("tty_read_nif(%T, %T, %T)\r\n",argv[0],argv[1],argv[2]); + /** + * We have three different read scenarios we need to deal with + * using different approaches. + * + * ### New Shell + * + * Here characters need to be delivered as they are typed and we + * also need to handle terminal resize events. So we use ReadConsoleInputW + * to read. + * + * ### Input is a terminal, but there is no shell, or old shell + * + * Here we should operate in "line mode", that is characters should only + * be delivered when the user hits enter. Therefore we cannot use + * ReadConsoleInputW, and we also cannot use ReadFile in synchronous mode + * as it will block until a complete line is done. So we use the + * OVERLAPPED support of ReadFile to read data. + * + * From this mode it is important to be able to upgrade to a "New Shell" + * terminal. + * + * Unfortunately it does not seem like unicode works at all when in this + * mode. At least when I try it, all unicode characters are translated to + * "?". Maybe it could be solved by using ReadConsoleW? + * + * ### Input is an anonymous pipe + * + * Since ReadConsoleInputW and OVERLAPPED ReadFile do not work on pipes + * we use blocking ReadFile calls to read from pipes. On pipes the ReadFile + * call will not block until a full line is complete, so this is safe to do. + * + **/ + if (GetFileType(tty->ifd) == FILE_TYPE_CHAR) { + if (tty->ifdOverlapped == INVALID_HANDLE_VALUE) { + /* Input is a terminal and we are in "new shell" mode */ + + ssize_t inputs_read, num_characters = 0; + wchar_t *characters = NULL; + INPUT_RECORD inputs[128]; + + ASSERT(tty->tty); + + if (!ReadConsoleInputW(tty->ifd, inputs, sizeof(inputs)/sizeof(*inputs), + &inputs_read)) { + return make_errno_error(env, "ReadConsoleInput"); + } + + /** + * Reading keyevents using ReadConsoleInput is a bit fragile as + * different consoles and different input modes cause events to + * be triggered in different ways. I've so far identified four + * different input methods that work slightly differently and + * two classes of consoles that also work slightly differently. + * + * The input methods are: + * - Normal key presses + * - Microsoft IME + * - Pasting into console + * - Using ALT+ modifiers + * + * ### Normal key presses + * + * When typing normally both key down and up events are sent with + * the typed character. If typing a Unicode character (for instance if + * you are using a keyboard with Cyrillic layout), that character also + * is sent as both key up and key down. This behavior is the same on all + * consoles. + * + * ### Microsoft IME + * + * When typing Japanese, Chinese and many other languages it is common to + * use a "Input Method Editor". Basically what it does is that if you type + * "sushi" using the Japanese IME it convert that to "すし". All characters + * typed using IME end up as only keydown events on cmd.exe and powershell, + * while in Windows Terminal and Alacritty both keydown and keyup events + * are sent. + * + * ### Pasting into console + * + * When text pasting into the console, any ascii text pasted ends up as both + * keydown and keyup events. Any non-ascii text pasted seem to be sent using + * a keydown event with UnicodeChar set to 0 and then immediately followed by a + * keyup event with the non-ascii text. + * + * ### Using ALT+ modifiers + * + * A very old way of inputting Unicode characters on Windows is to press + * the left alt key and then some numbers on the number pad. For instance + * you can type ALT+1 to write a ☺. When doing this first a keydown + * with 0 is sent and then some events later a keyup with the character + * is sent. This behavior seems to only work on cmd.exe and powershell. + * + * + * So to summarize: + * - Normal presses -- Always keydown and keyup events + * - IME -- Always keydown, sometimes keyup + * - Pasting -- Always keydown=0 directly followed by keyup=value + * - ALT+ -- Sometimes keydown=0 followed eventually by keyup=value + * + * So in order to read characters we should always read the keydown event, + * except when it is 0, then we should read the adjacent keyup event. + * This covers all modes and consoles except ALT+. If we want ALT+ to work + * we probably have to use PeekConsoleInput to make sure the correct events + * are available and inspect the state of the key event somehow. + **/ + + for (int i = 0; i < inputs_read; i++) { + if (inputs[i].EventType == KEY_EVENT) { + if (inputs[i].Event.KeyEvent.bKeyDown) { + if (inputs[i].Event.KeyEvent.uChar.UnicodeChar != 0) { + num_characters++; + } else if (i + 1 < inputs_read && !inputs[i+1].Event.KeyEvent.bKeyDown) { + num_characters++; + } + } + } + } + enif_alloc_binary(num_characters * sizeof(wchar_t), &bin); + characters = (wchar_t*)bin.data; + for (int i = 0; i < inputs_read; i++) { + switch (inputs[i].EventType) + { + case KEY_EVENT: + if (inputs[i].Event.KeyEvent.bKeyDown) { + if (inputs[i].Event.KeyEvent.uChar.UnicodeChar != 0) { + debug("Read %u\r\n",inputs[i].Event.KeyEvent.uChar.UnicodeChar); + characters[res++] = inputs[i].Event.KeyEvent.uChar.UnicodeChar; + } else if (i + 1 < inputs_read && !inputs[i+1].Event.KeyEvent.bKeyDown) { + debug("Read %u\r\n",inputs[i+1].Event.KeyEvent.uChar.UnicodeChar); + characters[res++] = inputs[i+1].Event.KeyEvent.uChar.UnicodeChar; + } + } + break; + case WINDOW_BUFFER_SIZE_EVENT: + enif_send(env, &tty->self, NULL, + enif_make_tuple2( + env, enif_make_atom(env, "resize"), + enif_make_tuple2( + env, + enif_make_int(env, inputs[i].Event.WindowBufferSizeEvent.dwSize.Y), + enif_make_int(env, inputs[i].Event.WindowBufferSizeEvent.dwSize.X)))); + break; + case MENU_EVENT: + case FOCUS_EVENT: + /* Should be ignored according to + https://docs.microsoft.com/en-us/windows/console/input-record-str */ + break; + default: + fprintf(stderr,"Unknown event: %d\r\n", inputs[i].EventType); + break; + } + } + res *= sizeof(wchar_t); + } else { + /* Input is a terminal and we are in "noshell" or "oldshell" mode */ + DWORD bytesRead = 0; + debug("GetOverlapped on %d\r\n", tty->ifdOverlapped); + if (!GetOverlappedResult(tty->ifdOverlapped, &tty->overlapped, &bytesRead, TRUE)) { + if (GetLastError() == ERROR_OPERATION_ABORTED && tty->tty) { + /* The overlapped operation was cancels by CancelIo because + we are upgrading to "newshell". So we close the handles + involved with the overlapped io and select on the stdin + handle. From now on we use ReadConsoleInputW to get + input. */ + CloseHandle(tty->ifdOverlapped); + CloseHandle(tty->overlapped.hEvent); + tty->ifdOverlapped = INVALID_HANDLE_VALUE; + enif_select(env, tty->ifd, ERL_NIF_SELECT_READ, tty, NULL, argv[1]); + /* Return {error,aborted} to signal that the encoding has changed . */ + return make_error(env, enif_make_atom(env, "aborted")); + } + return make_errno_error(env, "GetOverlappedResult"); + } + if (bytesRead == 0) { + return make_error(env, enif_make_atom(env, "closed")); + } + debug("Read %d bytes\r\n", bytesRead); +#ifdef HARD_DEBUG + for (int i = 0; i < bytesRead; i++) + debug("Read %u\r\n", tty->overlappedBuffer.data[i]); +#endif + bin = tty->overlappedBuffer; + res = bytesRead; + enif_alloc_binary(1024, &tty->overlappedBuffer); + if (!ReadFile(tty->ifdOverlapped, tty->overlappedBuffer.data, + tty->overlappedBuffer.size, NULL, &tty->overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) + return make_errno_error(env, "ReadFile"); + } + select_event = tty->overlapped.hEvent; + } + } else { + /* Input is not a terminal */ + DWORD bytesTransferred; + enif_alloc_binary(1024, &bin); + if (ReadFile(tty->ifd, bin.data, bin.size, + &bytesTransferred, NULL)) { + res = bytesTransferred; + if (res == 0) { + enif_release_binary(&bin); + return make_error(env, enif_make_atom(env, "closed")); + } + } else { + DWORD error = GetLastError(); + enif_release_binary(&bin); + if (error == ERROR_BROKEN_PIPE) + return make_error(env, enif_make_atom(env, "closed")); + return make_errno_error(env, "ReadFile"); + } + } +#else + enif_alloc_binary(1024, &bin); + res = read(tty->ifd, bin.data, bin.size); + if (res < 0) { + if (errno != EAGAIN && errno != EINTR) { + enif_release_binary(&bin); + return make_errno_error(env, "read"); + } + res = 0; + } else if (res == 0) { + enif_release_binary(&bin); + return make_error(env, enif_make_atom(env, "closed")); + } +#endif + debug("select on %d\r\n",select_event); + enif_select(env, select_event, ERL_NIF_SELECT_READ, tty, NULL, argv[1]); + if (res == bin.size) { + res_term = enif_make_binary(env, &bin); + } else if (res < bin.size / 2) { + unsigned char *buff = enif_make_new_binary(env, res, &res_term); + if (res > 0) { + memcpy(buff, bin.data, res); + } + enif_release_binary(&bin); + } else { + enif_realloc_binary(&bin, res); + res_term = enif_make_binary(env, &bin); + } + + return enif_make_tuple2(env, atom_ok, res_term); +} + +static ERL_NIF_TERM setlocale_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef __WIN32__ + TTYResource *tty; + + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + + if (tty->dwOutMode) + { + if (!SetConsoleOutputCP(CP_UTF8)) { + return make_errno_error(env, "SetConsoleOutputCP"); + } + } + return atom_true; +#elif defined(PRIMITIVE_UTF8_CHECK) + setlocale(LC_CTYPE, ""); /* Set international environment, + ignore result */ + return enif_make_atom(env, "primitive"); +#else + char *l = setlocale(LC_CTYPE, ""); /* Set international environment */ + if (l != NULL) { + if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) + return atom_true; + } + return atom_false; +#endif +} + +static ERL_NIF_TERM tty_tgetent_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef HAVE_TERMCAP + ErlNifBinary TERM; + if (!enif_inspect_iolist_as_binary(env, argv[0], &TERM)) + return enif_make_badarg(env); + if (tgetent((char *)NULL /* ignored */, (char *)TERM.data) <= 0) { + return make_errno_error(env, "tgetent"); + } + return atom_ok; +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_tgetnum_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef HAVE_TERMCAP + ErlNifBinary TERM; + if (!enif_inspect_iolist_as_binary(env, argv[0], &TERM)) + return enif_make_badarg(env); + return enif_make_int(env, tgetnum((char*)TERM.data)); +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_tgetflag_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef HAVE_TERMCAP + ErlNifBinary TERM; + if (!enif_inspect_iolist_as_binary(env, argv[0], &TERM)) + return enif_make_badarg(env); + if (tgetflag((char*)TERM.data)) + return atom_true; + return atom_false; +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_tgetstr_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef HAVE_TERMCAP + ErlNifBinary TERM, ret; + /* tgetstr seems to use a lot of stack buffer space, + so buff needs to be relatively "small" */ + char *str = NULL; + char buff_area[BUFSIZ] = {0}; + char *buff = (char*)buff_area; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &TERM)) + return enif_make_badarg(env); + str = tgetstr((char*)TERM.data, &buff); + if (!str) return atom_false; + enif_alloc_binary(strlen(str), &ret); + memcpy(ret.data, str, strlen(str)); + return enif_make_tuple2( + env, atom_ok, enif_make_binary(env, &ret)); +#else + return make_enotsup(env); +#endif +} + +#ifdef HAVE_TERMCAP +static int tputs_buffer_index; +static unsigned char tputs_buffer[1024]; + +#if defined(__sun) && defined(__SVR4) /* Solaris */ +static int tty_puts_putc(char c) { +#else +static int tty_puts_putc(int c) { +#endif + tputs_buffer[tputs_buffer_index++] = (unsigned char)c; + return 0; +} +#endif + +static ERL_NIF_TERM tty_tgoto_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#ifdef HAVE_TERMCAP + ErlNifBinary TERM; + ERL_NIF_TERM ret; + char *ent; + int value1 = 0, value2 = 0; + unsigned char *buff; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &TERM) || + (argc > 1 && !enif_get_int(env, argv[1], &value1)) || + (argc > 2 && !enif_get_int(env, argv[2], &value2)) + ) + return enif_make_badarg(env); + ent = tgoto((char*)TERM.data, value1, value2); + if (!ent) return make_errno_error(env, "tgoto"); + + tputs_buffer_index = 0; + (void)tputs(ent, 1, tty_puts_putc); /* tputs only fails if ent is null, + which is cannot be. */ + + buff = enif_make_new_binary(env, tputs_buffer_index, &ret); + memcpy(buff, tputs_buffer, tputs_buffer_index); + return enif_make_tuple2(env, atom_ok, ret); +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_create_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + + TTYResource *tty = enif_alloc_resource(tty_rt, sizeof(TTYResource)); + ERL_NIF_TERM tty_term; + memset(tty, 0, sizeof(*tty)); +#ifndef __WIN32__ + tty->ifd = 0; + tty->ofd = 1; +#else +#ifdef HARD_DEBUG + logFile = fopen("tty.log","w+"); +#endif + tty->ifd = GetStdHandle(STD_INPUT_HANDLE); + if (tty->ifd == INVALID_HANDLE_VALUE || tty->ifd == NULL) { + tty->ifd = CreateFile("nul", GENERIC_READ, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + tty->ofd = GetStdHandle(STD_OUTPUT_HANDLE); + if (tty->ofd == INVALID_HANDLE_VALUE || tty->ofd == NULL) { + tty->ofd = CreateFile("nul", GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + if (GetConsoleMode(tty->ofd, &tty->dwOriginalOutMode)) + { + tty->dwOutMode = ENABLE_VIRTUAL_TERMINAL_PROCESSING | tty->dwOriginalOutMode; + if (!SetConsoleMode(tty->ofd, tty->dwOutMode)) { + /* Failed to set any VT mode, can't do anything here. */ + return make_errno_error(env, "SetConsoleMode"); + } + } + if (GetConsoleMode(tty->ifd, &tty->dwOriginalInMode)) + { + tty->dwInMode = ENABLE_VIRTUAL_TERMINAL_INPUT | tty->dwOriginalInMode; + if (!SetConsoleMode(tty->ifd, tty->dwInMode)) { + /* Failed to set any VT mode, can't do anything here. */ + return make_errno_error(env, "SetConsoleMode"); + } + } + tty->ifdOverlapped = INVALID_HANDLE_VALUE; +#endif + + tty_term = enif_make_resource(env, tty); + enif_release_resource(tty); + + enif_set_pid_undefined(&tty->self); + enif_set_pid_undefined(&tty->reader); + + return enif_make_tuple2(env, atom_ok, tty_term); +} + +static ERL_NIF_TERM tty_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + +#if defined(HAVE_TERMCAP) || defined(__WIN32__) + ERL_NIF_TERM canon, echo, sig; + TTYResource *tty; + int fd; + + debug("tty_init_nif(%T,%T,%T)\r\n", argv[0], argv[1], argv[2]); + + if (argc != 3 || + !tty_get_fd(env, argv[1], &fd) || + !enif_is_map(env, argv[2])) { + return enif_make_badarg(env); + } + + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + + if (!enif_get_map_value(env, argv[2], enif_make_atom(env,"canon"), &canon)) + canon = enif_make_atom(env, "undefined"); + if (!enif_get_map_value(env, argv[2], enif_make_atom(env,"echo"), &echo)) + echo = enif_make_atom(env, "undefined"); + if (!enif_get_map_value(env, argv[2], enif_make_atom(env,"sig"), &sig)) + sig = enif_make_atom(env, "undefined"); + +#ifndef __WIN32__ + if (tcgetattr(fd, &tty->tty_rmode) < 0) { + return make_errno_error(env, "tcgetattr"); + } + + tty->tty_smode = tty->tty_rmode; + + /* Default characteristics for all usage including termcap output. */ + tty->tty_smode.c_iflag &= ~ISTRIP; + + /* erts_fprintf(stderr,"canon %T\r\n", canon); */ + /* Turn canonical (line mode) on off. */ + if (enif_is_identical(canon, atom_true)) { + tty->tty_smode.c_iflag |= ICRNL; + tty->tty_smode.c_lflag |= ICANON; + tty->tty_smode.c_oflag |= OPOST; + tty->tty_smode.c_cc[VEOF] = tty->tty_rmode.c_cc[VEOF]; +#ifdef VDSUSP + tty->tty_smode.c_cc[VDSUSP] = tty->tty_rmode.c_cc[VDSUSP]; +#endif + } + if (enif_is_identical(canon, atom_false)) { + tty->tty_smode.c_iflag &= ~ICRNL; + tty->tty_smode.c_lflag &= ~ICANON; + tty->tty_smode.c_oflag &= ~OPOST; + + tty->tty_smode.c_cc[VMIN] = 1; + tty->tty_smode.c_cc[VTIME] = 0; +#ifdef VDSUSP + tty->tty_smode.c_cc[VDSUSP] = 0; +#endif + } + + /* Turn echo on or off. */ + /* erts_fprintf(stderr,"echo %T\r\n", echo); */ + if (enif_is_identical(echo, atom_true)) + tty->tty_smode.c_lflag |= ECHO; + if (enif_is_identical(echo, atom_false)) + tty->tty_smode.c_lflag &= ~ECHO; + + /* erts_fprintf(stderr,"sig %T\r\n", sig); */ + /* Set extra characteristics for "RAW" mode, no signals. */ + if (enif_is_identical(sig, atom_true)) { + /* Ignore IMAXBEL as not POSIX. */ +#ifndef QNX + tty->tty_smode.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON|IXANY); +#else + tty->tty_smode.c_iflag |= (BRKINT|IGNPAR|ICRNL|IXON); +#endif + tty->tty_smode.c_lflag |= (ISIG|IEXTEN); + } + if (enif_is_identical(sig, atom_false)) { + /* Ignore IMAXBEL as not POSIX. */ +#ifndef QNX + tty->tty_smode.c_iflag &= ~(BRKINT|IGNPAR|ICRNL|IXON|IXANY); +#else + tty->tty_smode.c_iflag &= ~(BRKINT|IGNPAR|ICRNL|IXON); +#endif + tty->tty_smode.c_lflag &= ~(ISIG|IEXTEN); + } + +#else + debug("origOutMode: %x origInMode: %x\r\n", + tty->dwOriginalOutMode, tty->dwOriginalInMode); + + /* If we cannot disable NEWLINE_AUTO_RETURN we continue anyway as things work */ + if (SetConsoleMode(tty->ofd, tty->dwOutMode | DISABLE_NEWLINE_AUTO_RETURN)) { + tty->dwOutMode |= DISABLE_NEWLINE_AUTO_RETURN; + } + + tty->dwInMode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT); + if (!SetConsoleMode(tty->ifd, tty->dwInMode)) + { + /* Failed to set disable echo or line input mode */ + return make_errno_error(env, "SetConsoleMode"); + } + + /* If we are changing from "-noshell" to a shell we + need to cancel any outstanding async io. This + will cause the enif_select to trigger which allows + us to do more cleanup in tty_read_nif. */ + if (tty->ifdOverlapped != INVALID_HANDLE_VALUE) { + debug("CancelIo on %d\r\n", tty->ifdOverlapped); + CancelIoEx(tty->ifdOverlapped, &tty->overlapped); + } + +#endif /* __WIN32__ */ + + tty->tty = 1; + + return atom_ok; +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_set_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { +#if defined(HAVE_TERMCAP) || defined(__WIN32__) + TTYResource *tty; + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); +#ifdef HAVE_TERMCAP + if (tty->tty && tcsetattr(tty->ifd, TCSANOW, &tty->tty_smode) < 0) { + return make_errno_error(env, "tcsetattr"); + } +#endif + enif_self(env, &tty->self); + enif_monitor_process(env, tty, &tty->self, NULL); + return atom_ok; +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_window_size_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + TTYResource *tty; + int width = -1, height = -1; + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + { +#ifdef TIOCGWINSZ + struct winsize ws; + if (ioctl(tty->ifd,TIOCGWINSZ,&ws) == 0) { + if (ws.ws_col > 0) + width = ws.ws_col; + if (ws.ws_row > 0) + height = ws.ws_row; + } else if (ioctl(tty->ofd,TIOCGWINSZ,&ws) == 0) { + if (ws.ws_col > 0) + width = ws.ws_col; + if (ws.ws_row > 0) + height = ws.ws_row; + } +#elif defined(__WIN32__) + CONSOLE_SCREEN_BUFFER_INFOEX buffer_info; + buffer_info.cbSize = sizeof(buffer_info); + if (GetConsoleScreenBufferInfoEx(tty->ofd, &buffer_info)) { + height = buffer_info.dwSize.Y; + width = buffer_info.dwSize.X; + } else { + return make_errno_error(env,"GetConsoleScreenBufferInfoEx"); + } +#endif + } + if (width == -1 && height == -1) { + return make_enotsup(env); + } + return enif_make_tuple2( + env, atom_ok, + enif_make_tuple2( + env, + enif_make_int(env, width), + enif_make_int(env, height) + )); +} + +#ifndef __WIN32__ + +static int tty_signal_fd = -1; + +static RETSIGTYPE tty_cont(int sig) +{ + if (tty_signal_fd != 1) { + while (write(tty_signal_fd, "c", 1) < 0 && errno == EINTR) { }; + } +} + + +static RETSIGTYPE tty_winch(int sig) +{ + if (tty_signal_fd != 1) { + while (write(tty_signal_fd, "w", 1) < 0 && errno == EINTR) { }; + } +} + +#endif + +static ERL_NIF_TERM tty_read_signal_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + TTYResource *tty; + char buff[1]; + ssize_t ret; + ERL_NIF_TERM res; + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); +#ifndef __WIN32__ + do { + ret = read(tty->signal[0], buff, 1); + } while (ret < 0 && errno == EAGAIN); + + if (ret < 0) { + return make_errno_error(env, "read"); + } else if (ret == 0) { + return make_error(env, enif_make_atom(env,"empty")); + } + + enif_select(env, tty->signal[0], ERL_NIF_SELECT_READ, tty, NULL, argv[1]); + + if (buff[0] == 'w') { + res = enif_make_atom(env, "winch"); + } else if (buff[0] == 'c') { + res = enif_make_atom(env, "cont"); + } else { + res = enif_make_string_len(env, buff, 1, ERL_NIF_LATIN1); + } + return enif_make_tuple2(env, atom_ok, res); +#else + return make_enotsup(env); +#endif +} + +static ERL_NIF_TERM tty_select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + TTYResource *tty; +#ifndef __WIN32__ + extern int using_oldshell; /* set this to let the rest of erts know */ +#else + struct tty_reader *tty_reader; +#endif + if (!enif_get_resource(env, argv[0], tty_rt, (void **)&tty)) + return enif_make_badarg(env); + +#ifndef __WIN32__ + if (pipe(tty->signal) == -1) { + return make_errno_error(env, "pipe"); + } + SET_NONBLOCKING(tty->signal[0]); + enif_select(env, tty->signal[0], ERL_NIF_SELECT_READ, tty, NULL, argv[1]); + tty_signal_fd = tty->signal[1]; + + sys_signal(SIGCONT, tty_cont); + sys_signal(SIGWINCH, tty_winch); + + using_oldshell = 0; + + enif_select(env, tty->ifd, ERL_NIF_SELECT_READ, tty, NULL, argv[2]); +#else + if (tty->tty || GetFileType(tty->ifd) != FILE_TYPE_CHAR) { + debug("Select on %d\r\n", tty->ifd); + enif_select(env, tty->ifd, ERL_NIF_SELECT_READ, tty, NULL, argv[2]); + } else { + tty->ifdOverlapped = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + enif_alloc_binary(1024, &tty->overlappedBuffer); + tty->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + debug("Calling ReadFile on %d\r\n", tty->ifdOverlapped); + if (!ReadFile(tty->ifdOverlapped, tty->overlappedBuffer.data, tty->overlappedBuffer.size, NULL, &tty->overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + return make_errno_error(env, "ReadFile"); + } + } + debug("Select on %d\r\n", tty->overlapped.hEvent); + enif_select(env, tty->overlapped.hEvent, ERL_NIF_SELECT_READ, tty, NULL, argv[2]); + } +#endif + + enif_self(env, &tty->reader); + enif_monitor_process(env, tty, &tty->reader, NULL); + + return atom_ok; +} + +static void tty_monitor_down(ErlNifEnv* caller_env, void* obj, ErlNifPid* pid, ErlNifMonitor* mon) { + TTYResource *tty = obj; +#ifdef HAVE_TERMCAP + if (enif_compare_pids(pid, &tty->self) == 0) { + tcsetattr(tty->ifd, TCSANOW, &tty->tty_rmode); + } +#endif + if (enif_compare_pids(pid, &tty->reader) == 0) { + enif_select(caller_env, tty->ifd, ERL_NIF_SELECT_STOP, tty, NULL, atom_undefined); +#ifndef __WIN32__ + enif_select(caller_env, tty->signal[0], ERL_NIF_SELECT_STOP, tty, NULL, atom_undefined); + close(tty->signal[1]); + sys_signal(SIGCONT, SIG_DFL); + sys_signal(SIGWINCH, SIG_DFL); +#endif + } +} + +static void tty_select_stop(ErlNifEnv* caller_env, void* obj, ErlNifEvent event, int is_direct_call) { +/* Only used to close the signal pipe on unix */ +#ifndef __WIN32__ + if (event != 0) + close(event); +#endif +} + +static void load_resources(ErlNifEnv* env, ErlNifResourceFlags rt_flags) { + ErlNifResourceTypeInit rt = { + NULL /* dtor */, + tty_select_stop, + tty_monitor_down}; + +#define ATOM_DECL(A) atom_##A = enif_make_atom(env, #A) + ATOMS +#undef ATOM_DECL + + tty_rt = enif_open_resource_type_x(env, "tty", &rt, rt_flags, NULL); +} + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + *priv_data = NULL; + load_resources(env, ERL_NIF_RT_CREATE); + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, + ERL_NIF_TERM load_info) +{ + if (*old_priv_data != NULL) { + return -1; /* Don't know how to do that */ + } + if (*priv_data != NULL) { + return -1; /* Don't know how to do that */ + } + *priv_data = NULL; + load_resources(env, ERL_NIF_RT_TAKEOVER); + return 0; +} diff --git a/erts/emulator/nifs/common/socket_asyncio.h b/erts/emulator/nifs/common/socket_asyncio.h new file mode 100644 index 000000000000..365e0895f050 --- /dev/null +++ b/erts/emulator/nifs/common/socket_asyncio.h @@ -0,0 +1,191 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2023-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : Asynchronous I/O functions. + * ---------------------------------------------------------------------- + * + * essio = ESock Asynchronous I/O + * + */ + +#ifndef SOCKET_ASYNCIO_H__ +#define SOCKET_ASYNCIO_H__ + +#include "socket_io.h" + +extern int esaio_init(unsigned int numThreads, + const ESockData* dataP); +extern void esaio_finish(void); +extern ERL_NIF_TERM esaio_info(ErlNifEnv* env); + +/* +extern ERL_NIF_TERM esaio_open_with_fd(ErlNifEnv* env, + int fd, + ERL_NIF_TERM eopts, + const ESockData* dataP); + */ +extern ERL_NIF_TERM esaio_open_plain(ErlNifEnv* env, + int domain, + int type, + int protocol, + ERL_NIF_TERM eopts, + const ESockData* dataP); +extern ERL_NIF_TERM esaio_bind(ErlNifEnv* env, + ESockDescriptor* descP, + ESockAddress* sockAddrP, + SOCKLEN_T addrLen); +extern ERL_NIF_TERM esaio_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen); +/* +extern ERL_NIF_TERM esaio_listen(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog); +*/ +extern ERL_NIF_TERM esaio_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef); +extern ERL_NIF_TERM esaio_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags); +extern ERL_NIF_TERM esaio_sendto(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* dataP, + int flags, + ESockAddress* toAddrP, + SOCKLEN_T toAddrLen); +extern ERL_NIF_TERM esaio_sendmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsg, + int flags, + ERL_NIF_TERM eIOV, + const ESockData* dataP); +/* +extern +ERL_NIF_TERM esaio_sendfile_start(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count, + ERL_NIF_TERM fRef); +extern +ERL_NIF_TERM esaio_sendfile_cont(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count); +extern +ERL_NIF_TERM esaio_sendfile_deferred_close(ErlNifEnv* env, + ESockDescriptor* descP); +*/ + +extern ERL_NIF_TERM esaio_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); +extern ERL_NIF_TERM esaio_recvfrom(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); +extern ERL_NIF_TERM esaio_recvmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t bufLen, + ssize_t ctrlLen, + int flags); +extern ERL_NIF_TERM esaio_close(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM esaio_fin_close(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM esaio_shutdown(ErlNifEnv* env, + ESockDescriptor* descP, + int how); +extern ERL_NIF_TERM esaio_sockname(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM esaio_peername(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM esaio_cancel_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esaio_cancel_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esaio_cancel_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM esaio_cancel_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); + +extern ERL_NIF_TERM esaio_ioctl3(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg); +extern ERL_NIF_TERM esaio_ioctl2(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req); +/* +extern ERL_NIF_TERM esaio_ioctl3(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg); +extern ERL_NIF_TERM esaio_ioctl4(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM ename, + ERL_NIF_TERM eval); +*/ + +extern void esaio_dtor(ErlNifEnv* env, + ESockDescriptor* descP); +extern void esaio_stop(ErlNifEnv* env, + ESockDescriptor* descP); +extern void esaio_down(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +/* Temporary (I hope) workaround */ +extern void esaio_down_ctrl(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP); + +#endif // SOCKET_ASYNCIO_H__ diff --git a/erts/emulator/nifs/common/socket_dbg.c b/erts/emulator/nifs/common/socket_dbg.c index deb531415f6f..3be1b21cf0d0 100644 --- a/erts/emulator/nifs/common/socket_dbg.c +++ b/erts/emulator/nifs/common/socket_dbg.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2020. All Rights Reserved. + * Copyright Ericsson AB 2018-2022. 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. @@ -23,6 +23,12 @@ * */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef ESOCK_ENABLE + #include #include #include @@ -39,6 +45,9 @@ FILE* esock_dbgout = NULL; +/* Leave at least 14 for the filename */ +#define PATH_LEN (MAX_PATH - 14) + extern BOOLEAN_T esock_dbg_init(char* filename) { @@ -58,6 +67,48 @@ BOOLEAN_T esock_dbg_init(char* filename) fp = NULL; +#if defined(__WIN32__) + { + /* char path[PATH_LEN]; */ + /* char tf[MAX_PATH]; */ + /* DWORD wres; */ + + /* wres = GetTempPathA(PATH_LEN, &path); */ + + /* if ((wres > PATH_LEN) || (wres == 0)) { */ + /* /\* */ + /* * We don't really care what is wrong. */ + /* * Just make the simplest possible solution (= use stdout) */ + /* *\/ */ + /* esock_dbgout = stdout; */ + /* return TRUE; // Successful file open */ + /* }; */ + + /* /\* If 'filename' has been constructed in the unix */ + /* * way, this may result in an odd tf... */ + /* *\/ */ + /* wres = GetTempFileNameA(path, filename, 0, &tf); */ + + /* if (wres == 0) { */ + /* /\* */ + /* * Again, we don't really care *what* is wrong. */ + /* * Just make the simplest possible solution (= use stdout) */ + /* *\/ */ + /* esock_dbgout = stdout; */ + /* return TRUE; // Successful file open */ + /* } */ + + // Should we use CreateFile instead? + // fp = fopen(tf, mode); + + + /* For simplicity, we do not (*currently*) support generating + * a 'temporary' (debug) file name, we simply use the file name + * 'as is'. + */ + fp = fopen(filename, mode); + } +#else /* If there is trailing ?????? replace it with XXXXXX * and use mkstemp() to create an unique file name */ @@ -82,10 +133,11 @@ BOOLEAN_T esock_dbg_init(char* filename) } else { fp = fopen(filename, mode); } +#endif if (fp != NULL) { esock_dbgout = fp; - return TRUE; // Succesful file open + return TRUE; // Successful file open } esock_dbgout = stdout; @@ -129,3 +181,4 @@ void esock_dbg_printf( const char* prefix, const char* format, ... ) } } +#endif diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h index cc8584ee7ecd..0d0dbc059e96 100644 --- a/erts/emulator/nifs/common/socket_int.h +++ b/erts/emulator/nifs/common/socket_int.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2021. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. 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. @@ -33,24 +33,35 @@ #ifdef __WIN32__ /* All this just to replace sys/socket.h, netinet/in.h and sys/un.h??? */ +#if !defined(INCL_WINSOCK_API_TYPEDEFS) #define INCL_WINSOCK_API_TYPEDEFS 1 +#endif #ifndef WINDOWS_H_INCLUDES_WINSOCK2_H #include #endif #include #include /* NEED VC 6.0 or higher */ + /* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h - * to define the right structures. It needs to be set to WINXP (or LONGHORN) - * for IPV6 to work and it's set lower by default, so we need to change it. + * to define the right structures. + * It needs to be set higher for IPV6 to work and it's set lower by default, + * so we need to change it. */ #ifdef HAVE_SDKDDKVER_H # include # ifdef NTDDI_VERSION # undef NTDDI_VERSION # endif -# define NTDDI_VERSION NTDDI_WINXP +# define NTDDI_VERSION NTDDI_WIN10_RS2 #endif #include +#include + +/* Since we can't get configure to work properly on Windows... */ +#if defined(AF_UNIX) +#include +#define HAVE_STRUCT_SOCKADDR_UN_SUN_PATH 1 +#endif #else /* !__WIN32__ */ @@ -60,6 +71,10 @@ #include #endif +#ifdef HAVE_NET_IF_DL_H +#include +#endif + #ifdef HAVE_NETPACKET_PACKET_H #include #endif @@ -129,6 +144,10 @@ typedef union { struct sockaddr_ll ll; #endif +#if defined(AF_LINK) + struct sockaddr_dl dl; +#endif + /* Max size sockaddr on system */ struct sockaddr_storage ss; @@ -148,6 +167,13 @@ typedef int BOOLEAN_T; #define B2S(__B__) ((__B__) ? "true" : "false") +#define TYPE2STR(T) (((T) == SOCK_STREAM) ? "stream" : \ + (((T) == SOCK_DGRAM) ? "dgram" : \ + (((T) == SOCK_RAW) ? "raw" : \ + (((T) == SOCK_RDM) ? "rdm" : \ + (((T) == SOCK_SEQPACKET) ? "seqpacket" : \ + "undefined"))))) + #define NUM(Array) (sizeof(Array) / sizeof(*(Array))) @@ -163,6 +189,13 @@ typedef int BOOLEAN_T; #define SOCKOPTLEN_T SOCKLEN_T #endif +/* + * Seems to be missing. + */ +#ifndef __GNUC__ +typedef long ssize_t; +#endif + /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * "Global" atoms (esock_atom_...) @@ -176,22 +209,24 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(accept); \ GLOBAL_ATOM_DEF(acceptconn); \ GLOBAL_ATOM_DEF(acceptfilter); \ + GLOBAL_ATOM_DEF(acc_success); \ + GLOBAL_ATOM_DEF(acc_fails); \ + GLOBAL_ATOM_DEF(acc_tries); \ + GLOBAL_ATOM_DEF(acc_waits); \ GLOBAL_ATOM_DEF(adaption_layer); \ GLOBAL_ATOM_DEF(addr); \ GLOBAL_ATOM_DEF(addrform); \ GLOBAL_ATOM_DEF(add_membership); \ GLOBAL_ATOM_DEF(add_source_membership); \ + GLOBAL_ATOM_DEF(alen); \ GLOBAL_ATOM_DEF(allmulti); \ + GLOBAL_ATOM_DEF(already); \ GLOBAL_ATOM_DEF(any); \ - GLOBAL_ATOM_DEF(arphrd_dlci); \ - GLOBAL_ATOM_DEF(arphrd_ether); \ - GLOBAL_ATOM_DEF(arphrd_frelay); \ - GLOBAL_ATOM_DEF(arphrd_ieee802); \ - GLOBAL_ATOM_DEF(arphrd_ieee1394); \ - GLOBAL_ATOM_DEF(arphrd_loopback); \ - GLOBAL_ATOM_DEF(arphrd_netrom); \ - GLOBAL_ATOM_DEF(arphrd_none); \ + GLOBAL_ATOM_DEF(appletlk); \ + GLOBAL_ATOM_DEF(arcnet); \ + GLOBAL_ATOM_DEF(ax25); \ GLOBAL_ATOM_DEF(associnfo); \ + GLOBAL_ATOM_DEF(atm); \ GLOBAL_ATOM_DEF(authhdr); \ GLOBAL_ATOM_DEF(auth_active_key); \ GLOBAL_ATOM_DEF(auth_asconf); \ @@ -202,31 +237,53 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(autoclose); \ GLOBAL_ATOM_DEF(automedia); \ GLOBAL_ATOM_DEF(bad_data); \ + GLOBAL_ATOM_DEF(base_addr); \ GLOBAL_ATOM_DEF(bindtodevice); \ GLOBAL_ATOM_DEF(block_source); \ GLOBAL_ATOM_DEF(broadcast); \ + GLOBAL_ATOM_DEF(bsp_state); \ GLOBAL_ATOM_DEF(busy_poll); \ + GLOBAL_ATOM_DEF(bytes_in); \ + GLOBAL_ATOM_DEF(bytes_in_flight); \ + GLOBAL_ATOM_DEF(bytes_out); \ + GLOBAL_ATOM_DEF(bytes_reordered); \ + GLOBAL_ATOM_DEF(bytes_retrans); \ + GLOBAL_ATOM_DEF(cancel); \ + GLOBAL_ATOM_DEF(cancelled); \ GLOBAL_ATOM_DEF(cantconfig); \ GLOBAL_ATOM_DEF(chaos); \ GLOBAL_ATOM_DEF(checksum); \ GLOBAL_ATOM_DEF(close); \ + GLOBAL_ATOM_DEF(closed); \ + GLOBAL_ATOM_DEF(close_wait); \ + GLOBAL_ATOM_DEF(closing); \ GLOBAL_ATOM_DEF(cmsg_cloexec); \ GLOBAL_ATOM_DEF(command); \ + GLOBAL_ATOM_DEF(completion); \ + GLOBAL_ATOM_DEF(completion_status); \ GLOBAL_ATOM_DEF(confirm); \ GLOBAL_ATOM_DEF(congestion); \ GLOBAL_ATOM_DEF(connect); \ + GLOBAL_ATOM_DEF(connected); \ + GLOBAL_ATOM_DEF(connecting); \ + GLOBAL_ATOM_DEF(connection_time); \ GLOBAL_ATOM_DEF(context); \ GLOBAL_ATOM_DEF(cork); \ + GLOBAL_ATOM_DEF(counters); \ GLOBAL_ATOM_DEF(credentials); \ GLOBAL_ATOM_DEF(ctrl); \ GLOBAL_ATOM_DEF(ctrunc); \ + GLOBAL_ATOM_DEF(cwnd); \ GLOBAL_ATOM_DEF(data); \ + GLOBAL_ATOM_DEF(data_size); \ GLOBAL_ATOM_DEF(debug); \ GLOBAL_ATOM_DEF(default); \ GLOBAL_ATOM_DEF(default_send_params); \ GLOBAL_ATOM_DEF(delayed_ack_time); \ GLOBAL_ATOM_DEF(dgram); \ GLOBAL_ATOM_DEF(disable_fragments); \ + GLOBAL_ATOM_DEF(dlci); \ + GLOBAL_ATOM_DEF(dma); \ GLOBAL_ATOM_DEF(domain); \ GLOBAL_ATOM_DEF(dontfrag); \ GLOBAL_ATOM_DEF(dontroute); \ @@ -234,9 +291,13 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(drop_membership); \ GLOBAL_ATOM_DEF(drop_source_membership); \ GLOBAL_ATOM_DEF(dstopts); \ + GLOBAL_ATOM_DEF(dup); \ + GLOBAL_ATOM_DEF(dup_acks_in); \ GLOBAL_ATOM_DEF(dying); \ GLOBAL_ATOM_DEF(dynamic); \ GLOBAL_ATOM_DEF(echo); \ + GLOBAL_ATOM_DEF(eether); \ + GLOBAL_ATOM_DEF(efile); \ GLOBAL_ATOM_DEF(egp); \ GLOBAL_ATOM_DEF(enotsup); \ GLOBAL_ATOM_DEF(eor); \ @@ -244,16 +305,25 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(errqueue); \ GLOBAL_ATOM_DEF(esp_network_level); \ GLOBAL_ATOM_DEF(esp_trans_level); \ + GLOBAL_ATOM_DEF(established); \ + GLOBAL_ATOM_DEF(ether); \ + GLOBAL_ATOM_DEF(eui64); \ GLOBAL_ATOM_DEF(events); \ + GLOBAL_ATOM_DEF(exclusiveaddruse); \ GLOBAL_ATOM_DEF(explicit_eor); \ GLOBAL_ATOM_DEF(faith); \ GLOBAL_ATOM_DEF(false); \ GLOBAL_ATOM_DEF(family); \ GLOBAL_ATOM_DEF(fastroute); \ + GLOBAL_ATOM_DEF(fast_retrans); \ + GLOBAL_ATOM_DEF(fin_wait_1); \ + GLOBAL_ATOM_DEF(fin_wait_2); \ GLOBAL_ATOM_DEF(flags); \ GLOBAL_ATOM_DEF(flowinfo); \ GLOBAL_ATOM_DEF(fragment_interleave); \ GLOBAL_ATOM_DEF(freebind); \ + GLOBAL_ATOM_DEF(frelay); \ + GLOBAL_ATOM_DEF(get_overlapped_result); \ GLOBAL_ATOM_DEF(get_peer_addr_info); \ GLOBAL_ATOM_DEF(hatype); \ GLOBAL_ATOM_DEF(hdrincl); \ @@ -263,11 +333,15 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(host); \ GLOBAL_ATOM_DEF(icmp); \ GLOBAL_ATOM_DEF(icmp6); \ + GLOBAL_ATOM_DEF(ieee802); \ + GLOBAL_ATOM_DEF(ieee1394); \ GLOBAL_ATOM_DEF(ifindex); \ GLOBAL_ATOM_DEF(igmp); \ GLOBAL_ATOM_DEF(implink); \ + GLOBAL_ATOM_DEF(index); \ GLOBAL_ATOM_DEF(inet); \ GLOBAL_ATOM_DEF(inet6); \ + GLOBAL_ATOM_DEF(infiniband); \ GLOBAL_ATOM_DEF(info); \ GLOBAL_ATOM_DEF(initmsg); \ GLOBAL_ATOM_DEF(invalid); \ @@ -276,7 +350,9 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(ip); \ GLOBAL_ATOM_DEF(ipcomp_level); \ GLOBAL_ATOM_DEF(ipip); \ + GLOBAL_ATOM_DEF(iplevel); \ GLOBAL_ATOM_DEF(ipv6); \ + GLOBAL_ATOM_DEF(irq); \ GLOBAL_ATOM_DEF(i_want_mapped_v4_addr); \ GLOBAL_ATOM_DEF(join_group); \ GLOBAL_ATOM_DEF(keepalive); \ @@ -285,28 +361,39 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(keepintvl); \ GLOBAL_ATOM_DEF(kernel); \ GLOBAL_ATOM_DEF(knowsepoch); \ + GLOBAL_ATOM_DEF(last_ack); \ GLOBAL_ATOM_DEF(leave_group); \ GLOBAL_ATOM_DEF(level); \ GLOBAL_ATOM_DEF(linger); \ GLOBAL_ATOM_DEF(link); \ - GLOBAL_ATOM_DEF(link0); \ - GLOBAL_ATOM_DEF(link1); \ - GLOBAL_ATOM_DEF(link2); \ + GLOBAL_ATOM_DEF(link0); \ + GLOBAL_ATOM_DEF(link1); \ + GLOBAL_ATOM_DEF(link2); \ + GLOBAL_ATOM_DEF(listen); \ GLOBAL_ATOM_DEF(local); \ + GLOBAL_ATOM_DEF(localtlk); \ GLOBAL_ATOM_DEF(local_auth_chunks); \ GLOBAL_ATOM_DEF(loopback); \ GLOBAL_ATOM_DEF(lowdelay); \ GLOBAL_ATOM_DEF(lower_up); \ GLOBAL_ATOM_DEF(mark); \ GLOBAL_ATOM_DEF(master); \ + GLOBAL_ATOM_DEF(max); \ GLOBAL_ATOM_DEF(maxburst); \ + GLOBAL_ATOM_DEF(maxdg); \ GLOBAL_ATOM_DEF(maxseg); \ + GLOBAL_ATOM_DEF(max_msg_size); \ GLOBAL_ATOM_DEF(md5sig); \ + GLOBAL_ATOM_DEF(mem_end); \ + GLOBAL_ATOM_DEF(mem_start); \ + GLOBAL_ATOM_DEF(metricom); \ GLOBAL_ATOM_DEF(mincost); \ GLOBAL_ATOM_DEF(minttl); \ + GLOBAL_ATOM_DEF(min_rtt); \ GLOBAL_ATOM_DEF(monitor); \ GLOBAL_ATOM_DEF(more); \ GLOBAL_ATOM_DEF(msfilter); \ + GLOBAL_ATOM_DEF(mss); \ GLOBAL_ATOM_DEF(mtu); \ GLOBAL_ATOM_DEF(mtu_discover); \ GLOBAL_ATOM_DEF(multicast); \ @@ -316,6 +403,9 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(multicast_loop); \ GLOBAL_ATOM_DEF(multicast_ttl); \ GLOBAL_ATOM_DEF(name); \ + GLOBAL_ATOM_DEF(netns); \ + GLOBAL_ATOM_DEF(netrom); \ + GLOBAL_ATOM_DEF(nlen); \ GLOBAL_ATOM_DEF(noarp); \ GLOBAL_ATOM_DEF(nodelay); \ GLOBAL_ATOM_DEF(nodefrag); \ @@ -325,10 +415,20 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(nopush); \ GLOBAL_ATOM_DEF(nosignal); \ GLOBAL_ATOM_DEF(notrailers); \ + GLOBAL_ATOM_DEF(not_bound); \ GLOBAL_ATOM_DEF(not_found); \ + GLOBAL_ATOM_DEF(num_general_errors); \ GLOBAL_ATOM_DEF(not_owner); \ + GLOBAL_ATOM_DEF(num_threads); \ + GLOBAL_ATOM_DEF(num_unexpected_accepts); \ + GLOBAL_ATOM_DEF(num_unexpected_connects); \ + GLOBAL_ATOM_DEF(num_unexpected_reads); \ + GLOBAL_ATOM_DEF(num_unexpected_writes); \ + GLOBAL_ATOM_DEF(num_unknown_cmds); \ GLOBAL_ATOM_DEF(oactive); \ + GLOBAL_ATOM_DEF(off); \ GLOBAL_ATOM_DEF(ok); \ + GLOBAL_ATOM_DEF(on); \ GLOBAL_ATOM_DEF(oob); \ GLOBAL_ATOM_DEF(oobinline); \ GLOBAL_ATOM_DEF(options); \ @@ -354,7 +454,9 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(portsel); \ GLOBAL_ATOM_DEF(primary_addr); \ GLOBAL_ATOM_DEF(priority); \ + GLOBAL_ATOM_DEF(prim_file); \ GLOBAL_ATOM_DEF(promisc); \ + GLOBAL_ATOM_DEF(pronet); \ GLOBAL_ATOM_DEF(protocol); \ GLOBAL_ATOM_DEF(pup); \ GLOBAL_ATOM_DEF(raw); \ @@ -362,7 +464,14 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(rcvbufforce); \ GLOBAL_ATOM_DEF(rcvlowat); \ GLOBAL_ATOM_DEF(rcvtimeo); \ + GLOBAL_ATOM_DEF(rcv_buf); \ + GLOBAL_ATOM_DEF(rcv_wnd); \ GLOBAL_ATOM_DEF(rdm); \ + GLOBAL_ATOM_DEF(read_byte); \ + GLOBAL_ATOM_DEF(read_fails); \ + GLOBAL_ATOM_DEF(read_pkg); \ + GLOBAL_ATOM_DEF(read_tries); \ + GLOBAL_ATOM_DEF(read_waits); \ GLOBAL_ATOM_DEF(recv); \ GLOBAL_ATOM_DEF(recvdstaddr); \ GLOBAL_ATOM_DEF(recverr); \ @@ -383,17 +492,29 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(reuseaddr); \ GLOBAL_ATOM_DEF(reuseport); \ GLOBAL_ATOM_DEF(rights); \ + GLOBAL_ATOM_DEF(rm); \ GLOBAL_ATOM_DEF(router_alert); \ GLOBAL_ATOM_DEF(rthdr); \ GLOBAL_ATOM_DEF(rtoinfo); \ + GLOBAL_ATOM_DEF(rtt); \ GLOBAL_ATOM_DEF(running); \ GLOBAL_ATOM_DEF(rxq_ovfl); \ GLOBAL_ATOM_DEF(scope_id); \ GLOBAL_ATOM_DEF(sctp); \ GLOBAL_ATOM_DEF(sec); \ + GLOBAL_ATOM_DEF(select); \ GLOBAL_ATOM_DEF(select_failed); \ GLOBAL_ATOM_DEF(select_sent); \ GLOBAL_ATOM_DEF(send); \ + GLOBAL_ATOM_DEF(sendfile); \ + GLOBAL_ATOM_DEF(sendfile_byte); \ + GLOBAL_ATOM_DEF(sendfile_deferred_close); \ + GLOBAL_ATOM_DEF(sendfile_fails); \ + GLOBAL_ATOM_DEF(sendfile_max); \ + GLOBAL_ATOM_DEF(sendfile_pkg); \ + GLOBAL_ATOM_DEF(sendfile_pkg_max); \ + GLOBAL_ATOM_DEF(sendfile_tries); \ + GLOBAL_ATOM_DEF(sendfile_waits); \ GLOBAL_ATOM_DEF(sendmsg); \ GLOBAL_ATOM_DEF(sendsrcaddr); \ GLOBAL_ATOM_DEF(sendto); \ @@ -402,31 +523,46 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(set_peer_primary_addr); \ GLOBAL_ATOM_DEF(simplex); \ GLOBAL_ATOM_DEF(slave); \ + GLOBAL_ATOM_DEF(slen); \ GLOBAL_ATOM_DEF(sndbuf); \ GLOBAL_ATOM_DEF(sndbufforce); \ GLOBAL_ATOM_DEF(sndlowat); \ GLOBAL_ATOM_DEF(sndtimeo); \ + GLOBAL_ATOM_DEF(snd_wnd); \ + GLOBAL_ATOM_DEF(sockaddr); \ GLOBAL_ATOM_DEF(socket); \ GLOBAL_ATOM_DEF(socket_tag); \ GLOBAL_ATOM_DEF(spec_dst); \ + GLOBAL_ATOM_DEF(state); \ GLOBAL_ATOM_DEF(status); \ GLOBAL_ATOM_DEF(staticarp); \ GLOBAL_ATOM_DEF(stream); \ GLOBAL_ATOM_DEF(syncnt); \ + GLOBAL_ATOM_DEF(syn_rcvd); \ + GLOBAL_ATOM_DEF(syn_retrans); \ + GLOBAL_ATOM_DEF(syn_sent); \ GLOBAL_ATOM_DEF(tclass); \ GLOBAL_ATOM_DEF(tcp); \ GLOBAL_ATOM_DEF(throughput); \ GLOBAL_ATOM_DEF(timestamp); \ GLOBAL_ATOM_DEF(tos); \ GLOBAL_ATOM_DEF(transparent); \ + GLOBAL_ATOM_DEF(timeout); \ + GLOBAL_ATOM_DEF(timeout_episodes); \ + GLOBAL_ATOM_DEF(timestamp_enabled); \ + GLOBAL_ATOM_DEF(time_wait); \ GLOBAL_ATOM_DEF(true); \ GLOBAL_ATOM_DEF(trunc); \ GLOBAL_ATOM_DEF(ttl); \ + GLOBAL_ATOM_DEF(tunnel); \ + GLOBAL_ATOM_DEF(tunnel6); \ + GLOBAL_ATOM_DEF(txqlen); \ GLOBAL_ATOM_DEF(type); \ GLOBAL_ATOM_DEF(udp); \ GLOBAL_ATOM_DEF(unblock_source); \ GLOBAL_ATOM_DEF(undefined); \ GLOBAL_ATOM_DEF(unicast_hops); \ + GLOBAL_ATOM_DEF(unknown); \ GLOBAL_ATOM_DEF(unspec); \ GLOBAL_ATOM_DEF(up); \ GLOBAL_ATOM_DEF(usec); \ @@ -434,21 +570,36 @@ typedef int BOOLEAN_T; GLOBAL_ATOM_DEF(user_timeout); \ GLOBAL_ATOM_DEF(use_ext_recvinfo); \ GLOBAL_ATOM_DEF(use_min_mtu); \ - GLOBAL_ATOM_DEF(v6only); + GLOBAL_ATOM_DEF(use_registry); \ + GLOBAL_ATOM_DEF(value); \ + GLOBAL_ATOM_DEF(void); \ + GLOBAL_ATOM_DEF(v6only); \ + GLOBAL_ATOM_DEF(write_byte); \ + GLOBAL_ATOM_DEF(write_fails); \ + GLOBAL_ATOM_DEF(write_pkg); \ + GLOBAL_ATOM_DEF(write_tries); \ + GLOBAL_ATOM_DEF(write_waits); \ + GLOBAL_ATOM_DEF(zero) /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Error reason atoms */ -#define GLOBAL_ERROR_REASON_ATOM_DEFS \ - GLOBAL_ATOM_DEF(eagain); \ - GLOBAL_ATOM_DEF(einval); +#define GLOBAL_ERROR_REASON_ATOM_DEFS \ + GLOBAL_ATOM_DEF(add_socket); \ + GLOBAL_ATOM_DEF(create_accept_socket); \ + GLOBAL_ATOM_DEF(eagain); \ + GLOBAL_ATOM_DEF(einval); \ + GLOBAL_ATOM_DEF(select_read); \ + GLOBAL_ATOM_DEF(select_write); \ + GLOBAL_ATOM_DEF(update_accept_context); \ + GLOBAL_ATOM_DEF(update_connect_context) #define GLOBAL_ATOM_DEF(A) extern ERL_NIF_TERM esock_atom_##A -GLOBAL_ATOM_DEFS -GLOBAL_ERROR_REASON_ATOM_DEFS +GLOBAL_ATOM_DEFS; +GLOBAL_ERROR_REASON_ATOM_DEFS; #undef GLOBAL_ATOM_DEF @@ -468,6 +619,7 @@ GLOBAL_ERROR_REASON_ATOM_DEFS #define MKL1(E,T) enif_make_list1((E), (T)) #define MKEL(E) enif_make_list((E), 0) #define MKC(E,H,T) enif_make_list_cell((E), (H), (T)) +#define MKEMA(E) enif_make_new_map((E)) #define MKMA(E,KA,VA,L,M) enif_make_map_from_arrays((E), (KA), (VA), (L), (M)) #define MKPID(E, P) enif_make_pid((E), (P)) #define MKREF(E) enif_make_ref((E)) @@ -499,6 +651,10 @@ GLOBAL_ERROR_REASON_ATOM_DEFS #define COMPARE(A, B) enif_compare((A), (B)) #define COMPARE_PIDS(P1, P2) enif_compare_pids((P1), (P2)) +#define IS_IDENTICAL(A, B) enif_is_identical((A), (B)) +#define IS_ZERO(T) (COMPARE((T), esock_atom_zero) == 0) +#define IS_UNDEFINED(T) IS_IDENTICAL((T), esock_atom_undefined) +#define IS_OK(T) IS_IDENTICAL((T), esock_atom_ok) #define IS_ATOM(E, TE) enif_is_atom((E), (TE)) #define IS_BIN(E, TE) enif_is_binary((E), (TE)) @@ -508,6 +664,9 @@ GLOBAL_ERROR_REASON_ATOM_DEFS #define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) #define IS_INTEGER(E, TE) esock_is_integer((E), (TE)) +#define IS_PID_UNDEF(P) enif_is_pid_undefined((P)) +#define SET_PID_UNDEF(P) enif_set_pid_undefined((P)) + #define GET_ATOM_LEN(E, TE, LP) \ enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) #define GET_ATOM(E, TE, BP, MAX) \ @@ -531,7 +690,22 @@ GLOBAL_ERROR_REASON_ATOM_DEFS #define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) #define FREE_BIN(BP) enif_release_binary((BP)) +#define FREE_IOVEC(IV) enif_free_iovec((IV)) + /* Copy term T into environment E */ -#define CP_TERM(E, T) enif_make_copy((E), (T)) +#define CP_TERM(E, T) enif_make_copy((E), (T)) + +#define CLEAR_ENV(E) esock_clear_env(__FUNCTION__, (E)) +#define FREE_ENV(E) esock_free_env(__FUNCTION__, (E)) + +#define TCREATE(NAME, TID, FUNC, ARGS, OPTS) \ + enif_thread_create((NAME), (TID), (FUNC), (ARGS), (OPTS)) +#define TEXIT(EVAL) enif_thread_exit((EVAL)) +#define TJOIN(TID, EV) enif_thread_join((TID), (EV)) +#define TOCREATE(NAME) enif_thread_opts_create((NAME)) +#define TODESTROY(OPTS) enif_thread_opts_destroy((OPTS)) + +#define ESOCK_PRINTF(...) enif_fprintf(stdout, __VA_ARGS__) +#define ESOCK_EPRINTF(...) enif_fprintf(stderr, __VA_ARGS__) #endif // SOCKET_INT_H__ diff --git a/erts/emulator/nifs/common/socket_io.h b/erts/emulator/nifs/common/socket_io.h new file mode 100644 index 000000000000..100ca372bef3 --- /dev/null +++ b/erts/emulator/nifs/common/socket_io.h @@ -0,0 +1,232 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : Types and stuff for the socket I/O backend + * ---------------------------------------------------------------------- + * + */ + +#ifndef SOCKET_IO_H__ +#define SOCKET_IO_H__ + +#include +#include "prim_socket_int.h" + + +#define ESOCK_IO_OK 0 +#define ESOCK_IO_ERR_UNSUPPORTED -1 + +typedef int (*ESockIOInit)(unsigned int numThreads, + const ESockData* dataP); + +typedef void (*ESockIOFinish)(void); + + +typedef ERL_NIF_TERM (*ESockIOInfo)(ErlNifEnv* env); +typedef ERL_NIF_TERM (*ESockIOCommand)(ErlNifEnv* env, + ERL_NIF_TERM command, + ERL_NIF_TERM cdata); +typedef ERL_NIF_TERM (*ESockIOSupports0)(ErlNifEnv* env); +typedef ERL_NIF_TERM (*ESockIOSupports1)(ErlNifEnv* env, + ERL_NIF_TERM key); + + +typedef ERL_NIF_TERM (*ESockIOOpenWithFd)(ErlNifEnv* env, + int fd, + ERL_NIF_TERM eopts, + const ESockData* dataP); + +typedef ERL_NIF_TERM (*ESockIOOpenPlain)(ErlNifEnv* env, + int domain, + int type, + int protocol, + ERL_NIF_TERM eopts, + const ESockData* dataP); + +typedef ERL_NIF_TERM (*ESockIOBind)(ErlNifEnv* env, + ESockDescriptor* descP, + ESockAddress* sockAddrP, + SOCKLEN_T addrLen); + +typedef ERL_NIF_TERM (*ESockIOConnect)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen); + +typedef ERL_NIF_TERM (*ESockIOListen)(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog); + +typedef ERL_NIF_TERM (*ESockIOAccept)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef); + +typedef ERL_NIF_TERM (*ESockIOSend)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags); + +typedef ERL_NIF_TERM (*ESockIOSendTo)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* dataP, + int flags, + ESockAddress* toAddrP, + SOCKLEN_T toAddrLen); + +typedef ERL_NIF_TERM (*ESockIOSendMsg)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsg, + int flags, + ERL_NIF_TERM eIOV, + const ESockData* dataP); + +typedef ERL_NIF_TERM (*ESockIOSendFileStart)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count, + ERL_NIF_TERM fRef); +typedef ERL_NIF_TERM (*ESockIOSendFileContinue)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count); +typedef ERL_NIF_TERM (*ESockIOSendFileDeferredClose)(ErlNifEnv* env, + ESockDescriptor* descP); + +typedef ERL_NIF_TERM (*ESockIORecv)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); + +typedef ERL_NIF_TERM (*ESockIORecvFrom)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); + +typedef ERL_NIF_TERM (*ESockIORecvMsg)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t bufLen, + ssize_t ctrlLen, + int flags); + +typedef ERL_NIF_TERM (*ESockIOClose)(ErlNifEnv* env, + ESockDescriptor* descP); + +typedef ERL_NIF_TERM (*ESockIOFinClose)(ErlNifEnv* env, + ESockDescriptor* descP); + +typedef ERL_NIF_TERM (*ESockIOShutdown)(ErlNifEnv* env, + ESockDescriptor* descP, + int how); + +typedef ERL_NIF_TERM (*ESockIOSockName)(ErlNifEnv* env, + ESockDescriptor* descP); + +typedef ERL_NIF_TERM (*ESockIOPeerName)(ErlNifEnv* env, + ESockDescriptor* descP); + +typedef ERL_NIF_TERM (*ESockIOCancelConnect)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); + +typedef ERL_NIF_TERM (*ESockIOCancelAccept)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); + +typedef ERL_NIF_TERM (*ESockIOCancelSend)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); + +typedef ERL_NIF_TERM (*ESockIOCancelRecv)(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); + +typedef ERL_NIF_TERM (*ESockIOSetopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +typedef ERL_NIF_TERM (*ESockIOSetoptNative)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM eVal); +typedef ERL_NIF_TERM (*ESockIOSetoptOtp)(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt, + ERL_NIF_TERM eVal); + +typedef ERL_NIF_TERM (*ESockIOGetopt)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt); +typedef ERL_NIF_TERM (*ESockIOGetoptNative)(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + int opt, + ERL_NIF_TERM valueSpec); +typedef ERL_NIF_TERM (*ESockIOGetoptOtp)(ErlNifEnv* env, + ESockDescriptor* descP, + int eOpt); + +typedef ERL_NIF_TERM (*ESockIOIoctl_2)(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req); +typedef ERL_NIF_TERM (*ESockIOIoctl_3)(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg); +typedef ERL_NIF_TERM (*ESockIOIoctl_4)(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg1, + ERL_NIF_TERM arg2); + +typedef void (*ESockIODTor)(ErlNifEnv* env, + ESockDescriptor* descP); +typedef void (*ESockIOStop)(ErlNifEnv* env, + ESockDescriptor* descP); +typedef void (*ESockIODown)(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +#endif // SOCKET_IO_H__ diff --git a/erts/emulator/nifs/common/socket_syncio.h b/erts/emulator/nifs/common/socket_syncio.h new file mode 100644 index 000000000000..2d548b864550 --- /dev/null +++ b/erts/emulator/nifs/common/socket_syncio.h @@ -0,0 +1,174 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : Synchronous I/O functions. + * ---------------------------------------------------------------------- + * + * essio = ESock Synchronous I/O + * + */ + +#ifndef SOCKET_SYNCIO_H__ +#define SOCKET_SYNCIO_H__ + +#include "socket_io.h" + +extern int essio_init(unsigned int numThreads, + const ESockData* dataP); +extern void essio_finish(void); +extern ERL_NIF_TERM essio_info(ErlNifEnv* env); + +extern ERL_NIF_TERM essio_open_with_fd(ErlNifEnv* env, + int fd, + ERL_NIF_TERM eopts, + const ESockData* dataP); +extern ERL_NIF_TERM essio_open_plain(ErlNifEnv* env, + int domain, + int type, + int protocol, + ERL_NIF_TERM eopts, + const ESockData* dataP); +extern ERL_NIF_TERM essio_bind(ErlNifEnv* env, + ESockDescriptor* descP, + ESockAddress* sockAddrP, + SOCKLEN_T addrLen); +extern ERL_NIF_TERM essio_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen); +/* +extern ERL_NIF_TERM essio_listen(ErlNifEnv* env, + ESockDescriptor* descP, + int backlog); +*/ +extern ERL_NIF_TERM essio_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef); +extern ERL_NIF_TERM essio_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags); +extern ERL_NIF_TERM essio_sendto(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* dataP, + int flags, + ESockAddress* toAddrP, + SOCKLEN_T toAddrLen); +extern ERL_NIF_TERM essio_sendmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsg, + int flags, + ERL_NIF_TERM eIOV, + const ESockData* dataP); +extern +ERL_NIF_TERM essio_sendfile_start(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count, + ERL_NIF_TERM fRef); +extern +ERL_NIF_TERM essio_sendfile_cont(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count); +extern +ERL_NIF_TERM essio_sendfile_deferred_close(ErlNifEnv* env, + ESockDescriptor* descP); + +extern ERL_NIF_TERM essio_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); +extern ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags); +extern ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t bufLen, + ssize_t ctrlLen, + int flags); +extern ERL_NIF_TERM essio_close(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM essio_fin_close(ErlNifEnv* env, + ESockDescriptor* descP); +extern ERL_NIF_TERM essio_cancel_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM essio_cancel_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM essio_cancel_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); +extern ERL_NIF_TERM essio_cancel_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef); + +extern ERL_NIF_TERM essio_ioctl2(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req); +extern ERL_NIF_TERM essio_ioctl3(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg); +extern ERL_NIF_TERM essio_ioctl4(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM ename, + ERL_NIF_TERM eval); + +extern void essio_dtor(ErlNifEnv* env, + ESockDescriptor* descP); +extern void essio_stop(ErlNifEnv* env, + ESockDescriptor* descP); +extern void essio_down(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +/* Temporary (I hope) workaround */ +extern void essio_down_ctrl(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP); + +#endif // SOCKET_SYNCIO_H__ diff --git a/erts/emulator/nifs/common/socket_tarray.c b/erts/emulator/nifs/common/socket_tarray.c index def22c491966..c35089f878a3 100644 --- a/erts/emulator/nifs/common/socket_tarray.c +++ b/erts/emulator/nifs/common/socket_tarray.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2019. All Rights Reserved. + * Copyright Ericsson AB 2018-2022. 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. @@ -24,9 +24,11 @@ * */ -/* #ifdef HAVE_CONFIG_H */ -/* #include "config.h" */ -/* #endif */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef ESOCK_ENABLE #include @@ -141,3 +143,5 @@ void esock_tarray_ensure_fits(SocketTArrayInt* taP, Uint32 needs) taP->array = (ERL_NIF_TERM*) mem; } } + +#endif diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 94a5e3e3dcf1..9f961ecff2cd 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2021. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. 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. @@ -24,9 +24,11 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif +#ifdef ESOCK_ENABLE + #include #include #include @@ -34,8 +36,13 @@ #include #include #include +#if !defined(__WIN32__) #include +#endif + +#if !defined(__IOS__) && !defined(__WIN32__) #include +#endif #include "socket_int.h" #include "sys.h" @@ -62,6 +69,10 @@ #define UDBG( proto ) ESOCK_DBG_PRINTF( UTIL_DEBUG , proto ) +#if defined(__WIN32__) +typedef u_short sa_family_t; +#endif + extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ @@ -82,6 +93,12 @@ static void esock_encode_packet_addr_tuple(ErlNifEnv* env, unsigned char* addr, ERL_NIF_TERM* eAddr); +#if defined(HAVE_NET_IF_DL_H) && defined(AF_LINK) +static void esock_encode_sockaddr_dl(ErlNifEnv* env, + struct sockaddr_dl* sockAddrP, + SOCKLEN_T addrLen, + ERL_NIF_TERM* eSockAddr); +#endif static void esock_encode_sockaddr_native(ErlNifEnv* env, struct sockaddr* sa, SOCKLEN_T len, @@ -90,7 +107,7 @@ static void esock_encode_sockaddr_native(ErlNifEnv* env, static void esock_encode_sockaddr_broken(ErlNifEnv* env, struct sockaddr* sa, - socklen_t len, + SOCKLEN_T len, ERL_NIF_TERM* eSockAddr); static void make_sockaddr_in(ErlNifEnv* env, @@ -115,14 +132,53 @@ static void make_sockaddr_ll(ErlNifEnv* env, ERL_NIF_TERM addr, ERL_NIF_TERM* sa); #endif +#if defined(HAVE_NET_IF_DL_H) && defined(AF_LINK) +static void make_sockaddr_dl(ErlNifEnv* env, + ERL_NIF_TERM index, + ERL_NIF_TERM type, + ERL_NIF_TERM nlen, + ERL_NIF_TERM alen, + ERL_NIF_TERM slen, + ERL_NIF_TERM data, + ERL_NIF_TERM* sa); +#endif +#ifdef HAS_AF_LOCAL +static SOCKLEN_T sa_local_length(int l, struct sockaddr_un* sa); +#endif +/* *** esock_get_uint_from_map *** + * + * Simple utility function used to extract a unsigned int value from a map. + * If it fails to extract the value (for whatever reason) the default + * value is used. + */ + +extern +unsigned int esock_get_uint_from_map(ErlNifEnv* env, + ERL_NIF_TERM map, + ERL_NIF_TERM key, + unsigned int def) +{ + ERL_NIF_TERM eval; + unsigned int val; + + if (!GET_MAP_VAL(env, map, key, &eval)) { + return def; + } else { + if (GET_UINT(env, eval, &val)) + return val; + else + return def; + } +} + /* *** esock_get_bool_from_map *** * * Simple utility function used to extract a boolean value from a map. * If it fails to extract the value (for whatever reason) the default - * value is returned. + * value is used. */ extern @@ -131,14 +187,14 @@ BOOLEAN_T esock_get_bool_from_map(ErlNifEnv* env, ERL_NIF_TERM key, BOOLEAN_T def) { - ERL_NIF_TERM val; + ERL_NIF_TERM eval; - if (!GET_MAP_VAL(env, map, key, &val)) { + if (!GET_MAP_VAL(env, map, key, &eval)) { return def; } else { - if (COMPARE(val, esock_atom_true) == 0) + if (COMPARE(eval, esock_atom_true) == 0) return TRUE; - else if (COMPARE(val, esock_atom_false) == 0) + else if (COMPARE(eval, esock_atom_false) == 0) return FALSE; else return def; @@ -160,14 +216,14 @@ BOOLEAN_T esock_get_bool_from_map(ErlNifEnv* env, extern void esock_encode_iov(ErlNifEnv* env, ssize_t read, - struct iovec* iov, + SysIOVec* iov, size_t len, ErlNifBinary* data, ERL_NIF_TERM* eIOV) { - ssize_t rem = read; - size_t i; - ERL_NIF_TERM a[len]; // At most this length + ssize_t rem = read; + size_t i; + ERL_NIF_TERM* a; UDBG( ("SUTIL", "esock_encode_iov -> entry with" "\r\n read: %ld" @@ -175,8 +231,11 @@ void esock_encode_iov(ErlNifEnv* env, "\r\n", (long) read, (unsigned long) len) ); if (len == 0) { + UDBG( ("SUTIL", "esock_encode_iov -> done when empty\r\n") ); *eIOV = MKEL(env); return; + } else { + a = MALLOC(len * sizeof(ERL_NIF_TERM)); // At most this length } for (i = 0; i < len; i++) { @@ -212,6 +271,8 @@ void esock_encode_iov(ErlNifEnv* env, *eIOV = MKLA(env, a, i); + FREE(a); + UDBG( ("SUTIL", "esock_encode_msghdr -> done\r\n") ); } @@ -222,7 +283,7 @@ void esock_encode_iov(ErlNifEnv* env, * Decode an IO Vector. In erlang we represented this as a list of binaries. * * We assume that we have already figured out how long the iov (actually - * eIOV) is (len), and therefor allocated an array of bins and iov to be + * eIOV) is (len), and therefore allocated an array of bins and iov to be * used. */ @@ -230,7 +291,7 @@ extern BOOLEAN_T esock_decode_iov(ErlNifEnv* env, ERL_NIF_TERM eIOV, ErlNifBinary* bufs, - struct iovec* iov, + SysIOVec* iov, size_t len, ssize_t* totSize) { @@ -255,7 +316,7 @@ BOOLEAN_T esock_decode_iov(ErlNifEnv* env, if (IS_BIN(env, elem) && GET_BIN(env, elem, &bufs[i])) { ssize_t z; - iov[i].iov_base = (caddr_t) bufs[i].data; + iov[i].iov_base = (void*) bufs[i].data; iov[i].iov_len = bufs[i].size; z = sz; @@ -366,21 +427,32 @@ BOOLEAN_T esock_decode_sockaddr(ErlNifEnv* env, * packet - sockaddr_ll: protocol, ifindex, hatype, pkttype, addr * unspec - sockaddr: addr * (int) - sockaddr: addr + * + * An address length > 0 means the caller knows the length, and we use it. + * An address length of '-1' means the caller don't know, which + * in turn mean that "we" has to calculate. + * + * sys/socket.h: + * __SOCKADDR_ALLTYPES */ +#define SALEN(L, SZ) (((L) > 0) ? (L) : (SZ)) + extern void esock_encode_sockaddr(ErlNifEnv* env, ESockAddress* sockAddrP, - SOCKLEN_T addrLen, + int addrLen, ERL_NIF_TERM* eSockAddr) { - int family; + int family; + SOCKLEN_T len; // Sanity check - if (addrLen < (char *)&sockAddrP->sa.sa_data - (char *)sockAddrP) { - // We got crap, cannot even know the address family - esock_encode_sockaddr_broken(env, &sockAddrP->sa, addrLen, eSockAddr); - return; + if ((addrLen > 0) && + (addrLen < (char *)&sockAddrP->sa.sa_data - (char *)sockAddrP)) { + // We got crap, cannot even know the address family + esock_encode_sockaddr_broken(env, &sockAddrP->sa, addrLen, eSockAddr); + return; } family = sockAddrP->ss.ss_family; @@ -391,70 +463,160 @@ void esock_encode_sockaddr(ErlNifEnv* env, switch (family) { case AF_INET: - esock_encode_sockaddr_in(env, &sockAddrP->in4, addrLen, eSockAddr); - break; + len = SALEN(addrLen, sizeof(struct sockaddr_in)); + esock_encode_sockaddr_in(env, &sockAddrP->in4, len, eSockAddr); + break; #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: - esock_encode_sockaddr_in6(env, &sockAddrP->in6, addrLen, eSockAddr); - break; + len = SALEN(addrLen, sizeof(struct sockaddr_in6)); + esock_encode_sockaddr_in6(env, &sockAddrP->in6, len, eSockAddr); + break; #endif #ifdef HAS_AF_LOCAL case AF_LOCAL: - esock_encode_sockaddr_un(env, &sockAddrP->un, addrLen, eSockAddr); - break; + len = sa_local_length(addrLen, &sockAddrP->un); + esock_encode_sockaddr_un(env, &sockAddrP->un, len, eSockAddr); + break; #endif #ifdef AF_UNSPEC case AF_UNSPEC: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, esock_atom_unspec, eSockAddr); - break; + len = SALEN(addrLen, 0); + esock_encode_sockaddr_native(env, + &sockAddrP->sa, len, + esock_atom_unspec, + eSockAddr); + break; #endif #if defined(HAVE_NETPACKET_PACKET_H) case AF_PACKET: - esock_encode_sockaddr_ll(env, &sockAddrP->ll, addrLen, eSockAddr); - break; + len = SALEN(addrLen, sizeof(struct sockaddr_ll)); + esock_encode_sockaddr_ll(env, &sockAddrP->ll, len, eSockAddr); + break; #endif #if defined(AF_IMPLINK) case AF_IMPLINK: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, esock_atom_implink, eSockAddr); + len = SALEN(addrLen, 0); + esock_encode_sockaddr_native(env, + &sockAddrP->sa, len, + esock_atom_implink, + eSockAddr); break; #endif #if defined(AF_PUP) case AF_PUP: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, esock_atom_pup, eSockAddr); - break; + len = SALEN(addrLen, 0); + esock_encode_sockaddr_native(env, + &sockAddrP->sa, len, + esock_atom_pup, + eSockAddr); + break; #endif #if defined(AF_CHAOS) case AF_CHAOS: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, esock_atom_chaos, eSockAddr); - break; + len = SALEN(addrLen, 0); + esock_encode_sockaddr_native(env, + &sockAddrP->sa, len, + esock_atom_chaos, + eSockAddr); + break; #endif -#if defined(AF_LINK) +#if defined(HAVE_NET_IF_DL_H) && defined(AF_LINK) case AF_LINK: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, esock_atom_link, eSockAddr); + /* + * macOS (Darwin Kernel Version 21.4.0): + * ------------------------------------- + * struct sockaddr_dl { + * u_char sdl_len; // Total length of sockaddr + * u_char sdl_family; // AF_LINK + * u_short sdl_index; // if != 0, system given index for interface + * u_char sdl_type; // interface type + * u_char sdl_nlen; // interface name length, no trailing 0 reqd. + * u_char sdl_alen; // link level address length + * u_char sdl_slen; // link layer selector length + * char sdl_data[12]; // minimum work area, can be larger; + * // contains both if name and ll address + * #ifndef __APPLE__ + * // For TokenRing + * u_short sdl_rcf; // source routing control + * u_short sdl_route[16]; // source routing information + * #endif + * }; + * + * FreeBSD (12.2-RELEASE-p14): + * --------------------------- + * struct sockaddr_dl { + * u_char sdl_len; // Total length of sockaddr + * u_char sdl_family; // AF_LINK + * u_short sdl_index; // if != 0, + * // system given index for interface + * u_char sdl_type; // interface type + * u_char sdl_nlen; // interface name length, no trailing 0 reqd + * u_char sdl_alen; // link level address length + * u_char sdl_slen; // link layer selector length + * char sdl_data[46]; // minimum work area, can be larger; + * // contains both if name and ll address + * }; + * + * OpenIndiana 2021.10 + * struct sockaddr_dl { + * ushort_t sdl_family; // AF_LINK + * ushort_t sdl_index; // if != 0, + * // system given index for interface + * uchar_t sdl_type; // interface type + * uchar_t sdl_nlen; // interface name length, no trailing 0 reqd + * uchar_t sdl_alen; // link level address length + * uchar_t sdl_slen; // link layer selector length + * char sdl_data[244]; // contains both if name and ll address + * }; + * + */ +#if defined(ESOCK_SDL_LEN) + len = SALEN(addrLen, sockAddrP->dl.sdl_len); +#else + // The data area is dlen = nlen + alen + len = SALEN(addrLen, + (CHARP(sockAddrP->dl.sdl_data) - CHARP(sockAddrP)) + + sockAddrP->dl.sdl_nlen + sockAddrP->dl.sdl_alen); +#endif + esock_encode_sockaddr_dl(env, &sockAddrP->dl, len, eSockAddr); break; #endif default: - esock_encode_sockaddr_native(env, &sockAddrP->sa, - addrLen, MKI(env, family), eSockAddr); - break; + len = SALEN(addrLen, 0); + esock_encode_sockaddr_native(env, + &sockAddrP->sa, len, + MKI(env, family), + eSockAddr); + break; } } +#ifdef HAS_AF_LOCAL +static +SOCKLEN_T sa_local_length(int l, struct sockaddr_un* sa) +{ + if (l > 0) { + return ((SOCKLEN_T) l); + } else { +#if defined(SUN_LEN) + return SUN_LEN(sa); +#else + return (offsetof(struct sockaddr_un, sun_path) + strlen(sa->sun_path) + 1); +#endif + } +} +#endif + extern void esock_encode_hwsockaddr(ErlNifEnv* env, @@ -481,49 +643,49 @@ void esock_encode_hwsockaddr(ErlNifEnv* env, switch (family) { #if defined(ARPHRD_NETROM) case ARPHRD_NETROM: - efamily = esock_atom_arphrd_netrom; + efamily = esock_atom_netrom; break; #endif #if defined(ARPHRD_ETHER) case ARPHRD_ETHER: - efamily = esock_atom_arphrd_ether; + efamily = esock_atom_ether; break; #endif #if defined(ARPHRD_IEEE802) case ARPHRD_IEEE802: - efamily = esock_atom_arphrd_ieee802; + efamily = esock_atom_ieee802; break; #endif #if defined(ARPHRD_DLCI) case ARPHRD_DLCI: - efamily = esock_atom_arphrd_dlci; + efamily = esock_atom_dlci; break; #endif #if defined(ARPHRD_FRELAY) case ARPHRD_FRELAY: - efamily = esock_atom_arphrd_frelay; + efamily = esock_atom_frelay; break; #endif #if defined(ARPHRD_IEEE1394) case ARPHRD_IEEE1394: - efamily = esock_atom_arphrd_ieee1394; + efamily = esock_atom_ieee1394; break; #endif #if defined(ARPHRD_LOOPBACK) case ARPHRD_LOOPBACK: - efamily = esock_atom_arphrd_loopback; + efamily = esock_atom_loopback; break; #endif #if defined(ARPHRD_NONE) case ARPHRD_NONE: - efamily = esock_atom_arphrd_none; + efamily = esock_atom_none; break; #endif @@ -643,7 +805,7 @@ void esock_encode_sockaddr_in(ErlNifEnv* env, "\r\n addr size: %d" "\r\n", addrLen, sizeof(struct sockaddr_in)) ); esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, - addrLen, MKI(env, AF_INET), eSockAddr); + addrLen, esock_atom_inet, eSockAddr); } } @@ -783,7 +945,7 @@ void esock_encode_sockaddr_in6(ErlNifEnv* env, } else { esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, - addrLen, MKI(env, AF_INET6), eSockAddr); + addrLen, esock_atom_inet6, eSockAddr); } } #endif @@ -877,7 +1039,12 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, ERL_NIF_TERM ePath; size_t n, m; + UDBG( ("SUTIL", "esock_encode_sockaddr_un -> entry with" + "\r\n addrLen: %d" + "\r\n", addrLen) ); + n = sockAddrP->sun_path - (char *)sockAddrP; // offsetof + if (addrLen >= n) { n = addrLen - n; // sun_path length if (255 < n) { @@ -889,6 +1056,7 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, unsigned char *path; m = esock_strnlen(sockAddrP->sun_path, n); + #ifdef __linux__ /* Assume that the address is a zero terminated string, * except when the first byte is \0 i.e the string length is 0, @@ -901,6 +1069,8 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, } #endif + UDBG( ("SUTIL", "esock_encode_sockaddr_un -> m: %d\r\n", m) ); + /* And finally build the 'path' attribute */ path = enif_make_new_binary(env, m, &ePath); ESOCK_ASSERT( path != NULL ); @@ -911,7 +1081,7 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, } } else { esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, - addrLen, MKI(env, AF_LOCAL), eSockAddr); + addrLen, esock_atom_local, eSockAddr); } } #endif @@ -929,7 +1099,7 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, * ifindex: integer() * hatype: integer() (should be an atom really) * pkttype: integer() (should be an atom really) - * addr: list() (should be something usefull...) + * addr: list() (should be something useful...) * */ @@ -942,6 +1112,10 @@ void esock_encode_sockaddr_ll(ErlNifEnv* env, { ERL_NIF_TERM eProto, eIfIdx, eHaType, ePktType, eAddr; + UDBG( ("SUTIL", "esock_encode_sockaddr_ll -> entry with" + "\r\n. addrLen: %d" + "\r\n", addrLen) ); + if (addrLen >= sizeof(struct sockaddr_ll)) { /* protocol - the standard ethernet protocol type */ @@ -968,7 +1142,75 @@ void esock_encode_sockaddr_ll(ErlNifEnv* env, } else { esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, - addrLen, MKI(env, AF_PACKET), eSockAddr); + addrLen, esock_atom_packet, eSockAddr); + } +} +#endif + + + +/* +++ esock_encode_sockaddr_dl +++ + * + * Encode a LINK address - sockaddr_dl (link-level layer). In erlang it's + * represented as a map, which has a specific set of attributes + * (beside the mandatory family attribute, which is "inherited" from + * the "sockaddr" type): + * + * The length field (sdl_len) has already been used, so we don't use it + * in *this* function. + * + * index: non_neg_integer() + * type: non_neg_integer() + * nlen: non_neg_integer() (name length) + * alen: non_neg_integer() (address length) + * slen: non_neg_integer() (sector length) + * data: binary() + */ + +#if defined(HAVE_NET_IF_DL_H) && defined(AF_LINK) +extern +void esock_encode_sockaddr_dl(ErlNifEnv* env, + struct sockaddr_dl* sockAddrP, + SOCKLEN_T addrLen, + ERL_NIF_TERM* eSockAddr) +{ + ERL_NIF_TERM eindex, etype, enlen, ealen, eslen, edata; + SOCKLEN_T dlen; + + UDBG( ("SUTIL", "esock_encode_sockaddr_dl -> entry with" + "\r\n. addrLen: %d" + "\r\n", addrLen) ); + + /* There is a minumum length (defined by the size of the data field) */ + if (addrLen >= sizeof(struct sockaddr_dl)) { + + /* index - if != 0, system given index for interface */ + eindex = MKUI(env, sockAddrP->sdl_index); + + /* type - interface type */ + etype = MKUI(env, sockAddrP->sdl_type); + + /* nlen - interface name length, no trailing 0 reqd. */ + enlen = MKUI(env, sockAddrP->sdl_nlen); + + /* alen - link level address length */ + ealen = MKUI(env, sockAddrP->sdl_alen); + + /* slen - ink layer selector length */ + eslen = MKUI(env, sockAddrP->sdl_slen); + + /* data - minimum work area, can be larger; * + * contains both if name and ll address */ + dlen = addrLen - (CHARP(sockAddrP->sdl_data) - CHARP(sockAddrP)); + edata = esock_make_new_binary(env, &sockAddrP->sdl_data, dlen); + + make_sockaddr_dl(env, + eindex, etype, enlen, ealen, eslen, edata, + eSockAddr); + + } else { + esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, + addrLen, esock_atom_link, eSockAddr); } } #endif @@ -1496,7 +1738,157 @@ void esock_encode_packet_hatype(ErlNifEnv* env, unsigned short hatype, ERL_NIF_TERM* eHaType) { - *eHaType = MKUI(env, hatype); + ERL_NIF_TERM tmp; + + switch (hatype) { + + /* + * ARP protocol HARDWARE identifiers. + */ + +#if defined(ARPHRD_NETROM) + case ARPHRD_NETROM: + tmp = esock_atom_netrom; + break; +#endif + +#if defined(ARPHRD_ETHER) + case ARPHRD_ETHER: + tmp = esock_atom_ether; + break; +#endif + +#if defined(ARPHRD_EETHER) + case ARPHRD_EETHER: + tmp = esock_atom_eether; + break; +#endif + +#if defined(ARPHRD_AX25) + case ARPHRD_AX25: + tmp = esock_atom_ax25; + break; +#endif + +#if defined(ARPHRD_PRONET) + case ARPHRD_PRONET: + tmp = esock_atom_pronet; + break; +#endif + +#if defined(ARPHRD_CHAOS) + case ARPHRD_CHAOS: + tmp = esock_atom_chaos; + break; +#endif + +#if defined(ARPHRD_IEEE802) + case ARPHRD_IEEE802: + tmp = esock_atom_ieee802; + break; +#endif + +#if defined(ARPHRD_ARCNET) + case ARPHRD_ARCNET: + tmp = esock_atom_arcnet; + break; +#endif + +#if defined(ARPHRD_APPLETLK) + case ARPHRD_APPLETLK: + tmp = esock_atom_appletlk; + break; +#endif + +#if defined(ARPHRD_DLCI) + case ARPHRD_DLCI: + tmp = esock_atom_dlci; + break; +#endif + +#if defined(ARPHRD_ATM) + case ARPHRD_ATM: + tmp = esock_atom_atm; + break; +#endif + +#if defined(ARPHRD_METRICOM) + case ARPHRD_METRICOM: + tmp = esock_atom_metricom; + break; +#endif + +#if defined(ARPHRD_IEEE1394) + case ARPHRD_IEEE1394: + tmp = esock_atom_ieee1394; + break; +#endif + +#if defined(ARPHRD_EUI64) + case ARPHRD_EUI64: + tmp = esock_atom_eui64; + break; +#endif + +#if defined(ARPHRD_INFINIBAND) + case ARPHRD_INFINIBAND: + tmp = esock_atom_infiniband; + break; +#endif + + + /* + * Dummy types for non ARP hardware + */ + +#if defined(ARPHRD_TUNNEL) + case ARPHRD_TUNNEL: + tmp = esock_atom_tunnel; + break; +#endif + +#if defined(ARPHRD_TUNNEL6) + case ARPHRD_TUNNEL6: + tmp = esock_atom_tunnel6; + break; +#endif + +#if defined(ARPHRD_LOOPBACK) + case ARPHRD_LOOPBACK: + tmp = esock_atom_loopback; + break; +#endif + +#if defined(ARPHRD_LOCALTLK) + case ARPHRD_LOCALTLK: + tmp = esock_atom_localtlk; + break; +#endif + + +#if defined(ARPHRD_NONE) + case ARPHRD_NONE: + tmp = esock_atom_none; + break; +#endif + +#if defined(ARPHRD_VOID) + case ARPHRD_VOID: + tmp = esock_atom_void; + break; +#endif + + + /* + * And the rest will be just integer + */ + + default: + tmp = MKUI(env, hatype); + break; + } + + *eHaType = tmp; } @@ -1623,7 +2015,7 @@ void esock_encode_packet_addr_tuple(ErlNifEnv* env, unsigned char* addr, ERL_NIF_TERM* eAddr) { - ERL_NIF_TERM array[len]; + ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); unsigned char i; for (i = 0; i < len; i++) { @@ -1631,6 +2023,9 @@ void esock_encode_packet_addr_tuple(ErlNifEnv* env, } *eAddr = MKTA(env, array, len); + + FREE(array); + } @@ -1686,7 +2081,7 @@ BOOLEAN_T esock_decode_sockaddr_native(ErlNifEnv* env, -/* Encode as #{family := integer(), addr := binary()} +/* Encode as #{family := atom() | integer(), addr := binary()} * assuming at least the ->family field can be accessed * and hence at least 0 bytes of address */ @@ -1700,8 +2095,17 @@ void esock_encode_sockaddr_native(ErlNifEnv* env, size_t size; ERL_NIF_TERM eData; - size = ((char*)addr + len) - (char*)&addr->sa_data; - eData = esock_make_new_binary(env, &addr->sa_data, size); + UDBG( ("SUTIL", "esock_encode_sockaddr_native -> entry with" + "\r\n. len: %d" + "\r\n. eFamily: %T" + "\r\n", len, eFamily) ); + + if (len > 0) { + size = ((char*)addr + len) - (char*)&addr->sa_data; + eData = esock_make_new_binary(env, &addr->sa_data, size); + } else { + eData = esock_make_new_binary(env, &addr->sa_data, 0); + } { ERL_NIF_TERM keys[] = {esock_atom_family, esock_atom_addr}; @@ -1713,6 +2117,7 @@ void esock_encode_sockaddr_native(ErlNifEnv* env, } } + /* Encode as a raw binary() regarding the whole address * structure as a blob */ @@ -1720,6 +2125,10 @@ static void esock_encode_sockaddr_broken(ErlNifEnv* env, struct sockaddr* addr, SOCKLEN_T len, ERL_NIF_TERM* eSockAddr) { + UDBG( ("SUTIL", "esock_encode_sockaddr_broken -> entry with" + "\r\n. len: %d" + "\r\n", len) ); + *eSockAddr = esock_make_new_binary(env, addr, len); } @@ -1881,15 +2290,15 @@ ERL_NIF_TERM esock_encode_bool(BOOLEAN_T val) /* *** esock_decode_level *** * - * Decode option or cmsg level - 'socket' or protocol number. + * Decode option or cmsg level - 'socket' or level number. * */ extern -BOOLEAN_T esock_decode_level(ErlNifEnv* env, ERL_NIF_TERM eVal, int *val) +BOOLEAN_T esock_decode_level(ErlNifEnv* env, ERL_NIF_TERM elevel, int *level) { - if (COMPARE(esock_atom_socket, eVal) == 0) - *val = SOL_SOCKET; - else if (! GET_INT(env, eVal, val)) + if (COMPARE(esock_atom_socket, elevel) == 0) + *level = SOL_SOCKET; + else if (! GET_INT(env, elevel, level)) return FALSE; return TRUE; @@ -1924,6 +2333,154 @@ ERL_NIF_TERM esock_make_ok2(ErlNifEnv* env, ERL_NIF_TERM any) } +/* Takes an 'errno' value and converts it to a term. + * + * If the errno can be translated using erl_errno_id, + * then we use that value otherwise we use the errno + * integer value converted to a term. + * Unless there is a specific error code that can be + * handled specially. + */ +extern +ERL_NIF_TERM esock_errno_to_term(ErlNifEnv* env, int err) +{ + switch (err) { +#if defined(NO_ERROR) + case NO_ERROR: + return MKA(env, "no_error"); + break; +#endif + +#if defined(WSA_IO_PENDING) + case WSA_IO_PENDING: + return MKA(env, "io_pending"); + break; +#endif + +#if defined(WSA_IO_INCOMPLETE) + case WSA_IO_INCOMPLETE: + return MKA(env, "io_incomplete"); + break; +#endif + +#if defined(WSA_OPERATION_ABORTED) + case WSA_OPERATION_ABORTED: + return MKA(env, "operation_aborted"); + break; +#endif + +#if defined(WSA_INVALID_PARAMETER) + case WSA_INVALID_PARAMETER: + return MKA(env, "invalid_parameter"); + break; +#endif + +#if defined(ERROR_INVALID_NETNAME) + case ERROR_INVALID_NETNAME: + return MKA(env, "invalid_netname"); + break; +#endif + +#if defined(ERROR_NETNAME_DELETED) + case ERROR_NETNAME_DELETED: + return MKA(env, "netname_deleted"); + break; +#endif + +#if defined(ERROR_TOO_MANY_CMDS) + /* The network command limit has been reached */ + case ERROR_TOO_MANY_CMDS: + return MKA(env, "too_many_cmds"); + break; +#endif + +#if defined(ERROR_DUP_NAME) + /* Not connected because a duplicate name exists on the network */ + case ERROR_DUP_NAME: + return MKA(env, "duplicate_name"); + break; +#endif + +#if defined(ERROR_MORE_DATA) + /* + * https://stackoverflow.com/questions/31883438/sockets-using-getqueuedcompletionstatus-and-error-more-data + */ + case ERROR_MORE_DATA: + return MKA(env, "more_data"); + break; +#endif + +#if defined(ERROR_NOT_FOUND) + case ERROR_NOT_FOUND: + return MKA(env, "not_found"); + break; +#endif + +#if defined(ERROR_NETWORK_UNREACHABLE) + case ERROR_NETWORK_UNREACHABLE: + return MKA(env, "network_unreachable"); + break; +#endif + +#if defined(ERROR_PORT_UNREACHABLE) + case ERROR_PORT_UNREACHABLE: + return MKA(env, "port_unreachable"); + break; +#endif + + default: + { + char* str = erl_errno_id(err); + if ( strcmp(str, "unknown") == 0 ) + return MKI(env, err); + else + return MKA(env, str); + } + break; + } + + /* This is just in case of programming error. + * We should not get this far! + */ + return MKI(env, err); +} + + + +/* *** esock_make_extra_error_info_term *** + * This is used primarily for debugging. + * Is supposed to be called via the 'MKEEI' macro. + */ +extern +ERL_NIF_TERM esock_make_extra_error_info_term(ErlNifEnv* env, + const char* file, + const char* function, + const int line, + ERL_NIF_TERM rawinfo, + ERL_NIF_TERM info) +{ + ERL_NIF_TERM keys[] = {MKA(env, "file"), + MKA(env, "function"), + MKA(env, "line"), + MKA(env, "raw_info"), + MKA(env, "info")}; + ERL_NIF_TERM vals[] = {MKS(env, file), + MKS(env, function), + MKI(env, line), + rawinfo, + info}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); + ERL_NIF_TERM map; + + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &map) ); + + return map; +} + + + /* Create an error two (2) tuple in the form: * * {error, Reason} @@ -1939,6 +2496,18 @@ ERL_NIF_TERM esock_make_error(ErlNifEnv* env, ERL_NIF_TERM reason) +/* Create an error two (2) tuple in the form: + * + * {error, closed} + */ +extern +ERL_NIF_TERM esock_make_error_closed(ErlNifEnv* env) +{ + return esock_make_error(env, esock_atom_closed); +} + + + /* Create an error two (2) tuple in the form: {error, Reason}. * * {error, Reason} @@ -1968,6 +2537,23 @@ ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err) +/* Create an error two (2) tuple in the form: + * + * {error, {Tag, Reason}} + * + * Both 'Tag' and 'Reason' are already in the form of an + * ERL_NIF_TERM so all we have to do is create "the" tuple. + */ +extern +ERL_NIF_TERM esock_make_error_t2r(ErlNifEnv* env, + ERL_NIF_TERM tag, + ERL_NIF_TERM reason) +{ + return MKT2(env, esock_atom_error, MKT2(env, tag, reason)); +} + + + /* Create an error two (2) tuple in the form: * * {error, {invalid, What}}} @@ -2079,45 +2665,53 @@ ERL_NIF_TERM esock_self(ErlNifEnv* env) -/* *** esock_warning_msg *** - * - * Temporary function for issuing warning messages. +/* + * We should really include self in the printout, + * so we can se which process are executing the code. + * But then I must change the API....something for later. * + * esock_info_msg + * esock_warning_msg + * esock_error_msg */ -extern -void esock_warning_msg( const char* format, ... ) -{ - va_list args; - char f[512 + sizeof(format)]; // This has to suffice... - char stamp[64]; // Just in case... - int res; - - /* - * We should really include self in the printout, - * so we can se which process are executing the code. - * But then I must change the API....something for later. - */ - - // 2018-06-29 12:13:21.232089 - // 29-Jun-2018::13:47:25.097097 - - if (esock_timestamp_str(stamp, sizeof(stamp))) { - res = enif_snprintf(f, sizeof(f), - "=WARNING MSG==== %s ===\r\n%s", - stamp, format); - } else { - res = enif_snprintf(f, sizeof(f), "=WARNING MSG==== %s", format); - } - if (res > 0) { - va_start (args, format); - enif_vfprintf (stdout, f, args); - va_end (args); - fflush(stdout); - } - - return; -} +#define MSG_FUNCS \ + MSG_FUNC_DECL(info, INFO) \ + MSG_FUNC_DECL(warning, WARNING) \ + MSG_FUNC_DECL(error, ERROR) + +#define MSG_FUNC_DECL(FN, MC) \ + extern \ + void esock_##FN##_msg( const char* format, ... ) \ + { \ + va_list args; \ + char f[512 + sizeof(format)]; \ + char stamp[64]; \ + int res; \ + \ + if (esock_timestamp_str(stamp, sizeof(stamp))) { \ + res = enif_snprintf(f, sizeof(f), \ + "=" #MC " MSG==== %s ===\r\n%s", \ + stamp, format); \ + } else { \ + res = enif_snprintf(f, \ + sizeof(f), \ + "=" #MC " MSG==== %s", format); \ + } \ + \ + if (res > 0) { \ + va_start (args, format); \ + enif_vfprintf (stdout, f, args); \ + va_end (args); \ + fflush(stdout); \ + } \ + \ + return; \ + } \ + +MSG_FUNCS +#undef MSG_FUNC_DECL +#undef MSG_FUNCS /* *** esock_timestamp *** @@ -2129,7 +2723,7 @@ void esock_warning_msg( const char* format, ... ) */ extern -ErlNifTime esock_timestamp() +ErlNifTime esock_timestamp(void) { ErlNifTime monTime = enif_monotonic_time(ERL_NIF_USEC); ErlNifTime offTime = enif_time_offset(ERL_NIF_USEC); @@ -2282,17 +2876,51 @@ void make_sockaddr_ll(ErlNifEnv* env, ERL_NIF_TERM* sa) { ERL_NIF_TERM keys[] = {esock_atom_family, - esock_atom_protocol, - esock_atom_ifindex, - esock_atom_hatype, - esock_atom_pkttype, - esock_atom_addr}; + esock_atom_protocol, + esock_atom_ifindex, + esock_atom_hatype, + esock_atom_pkttype, + esock_atom_addr}; ERL_NIF_TERM vals[] = {esock_atom_packet, - proto, - ifindex, - hatype, - pkttype, - addr}; + proto, + ifindex, + hatype, + pkttype, + addr}; + size_t numKeys = NUM(keys); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, sa) ); +} +#endif + + +/* Construct the Link-Level socket address */ +#if defined(HAVE_NET_IF_DL_H) && defined(AF_LINK) +static +void make_sockaddr_dl(ErlNifEnv* env, + ERL_NIF_TERM index, + ERL_NIF_TERM type, + ERL_NIF_TERM nlen, + ERL_NIF_TERM alen, + ERL_NIF_TERM slen, + ERL_NIF_TERM data, + ERL_NIF_TERM* sa) +{ + ERL_NIF_TERM keys[] = {esock_atom_family, + esock_atom_index, + esock_atom_type, + esock_atom_nlen, + esock_atom_alen, + esock_atom_slen, + esock_atom_data}; + ERL_NIF_TERM vals[] = {esock_atom_link, + index, + type, + nlen, + alen, + slen, + data}; size_t numKeys = NUM(keys); ESOCK_ASSERT( numKeys == NUM(vals) ); @@ -2338,3 +2966,5 @@ BOOLEAN_T esock_is_integer(ErlNifEnv *env, ERL_NIF_TERM term) else return FALSE; } + +#endif diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h index af58c153772d..c16803bbdc6b 100644 --- a/erts/emulator/nifs/common/socket_util.h +++ b/erts/emulator/nifs/common/socket_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2021. All Rights Reserved. + * Copyright Ericsson AB 2018-2023. 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. @@ -36,7 +36,9 @@ #define LONG(L) ((long) (L)) #define ULONG(L) ((unsigned long) (L)) #define SZT(I) ((size_t) (I)) +#ifndef VOID #define VOID(D) ((void) (D)) +#endif #define VOIDP(P) ((void*) (P)) #define CHARP(P) ((char*) (P)) #define UCHARP(P) ((unsigned char*) (P)) @@ -44,6 +46,36 @@ #define ESOCK_ABORT(E) esock_abort(E, __func__, __FILE__, __LINE__) #define ESOCK_ASSERT(e) ((void) ((e) ? 1 : (ESOCK_ABORT(#e), 0))) +#define MKEEI(E, RI, I) \ + esock_make_extra_error_info_term((E), \ + __FILE__, \ + __FUNCTION__, \ + __LINE__, \ + (RI), (I)) + +#if defined(ESOCK_USE_EXTENDED_ERROR_INFO) +#define ENO2T(E, ENO) MKEEI((E), \ + MKI((E), (ENO)), \ + esock_errno_to_term((E), (ENO))) +#else +#define ENO2T(E, ENO) esock_errno_to_term((E), (ENO)) +#endif + + +extern +ERL_NIF_TERM esock_make_extra_error_info_term(ErlNifEnv* env, + const char* file, + const char* function, + const int line, + ERL_NIF_TERM rawinfo, + ERL_NIF_TERM info); + +extern +unsigned int esock_get_uint_from_map(ErlNifEnv* env, + ERL_NIF_TERM map, + ERL_NIF_TERM key, + unsigned int def); + extern BOOLEAN_T esock_get_bool_from_map(ErlNifEnv* env, ERL_NIF_TERM map, @@ -54,13 +86,13 @@ extern BOOLEAN_T esock_decode_iov(ErlNifEnv* env, ERL_NIF_TERM eIOV, ErlNifBinary* bufs, - struct iovec* iov, + SysIOVec* iov, size_t len, ssize_t* totSize); extern void esock_encode_iov(ErlNifEnv* env, ssize_t read, - struct iovec* iov, + SysIOVec* iov, size_t len, ErlNifBinary* data, ERL_NIF_TERM* eIOV); @@ -73,7 +105,7 @@ BOOLEAN_T esock_decode_sockaddr(ErlNifEnv* env, extern void esock_encode_sockaddr(ErlNifEnv* env, ESockAddress* sockAddrP, - SOCKLEN_T addrLen, + int addrLen, ERL_NIF_TERM* eSockAddr); extern void esock_encode_hwsockaddr(ErlNifEnv* env, @@ -239,12 +271,19 @@ ERL_NIF_TERM esock_self(ErlNifEnv* env); extern ERL_NIF_TERM esock_make_ok2(ErlNifEnv* env, ERL_NIF_TERM any); extern +ERL_NIF_TERM esock_errno_to_term(ErlNifEnv* env, int err); +extern ERL_NIF_TERM esock_make_error(ErlNifEnv* env, ERL_NIF_TERM reason); extern +ERL_NIF_TERM esock_make_error_closed(ErlNifEnv* env); +extern ERL_NIF_TERM esock_make_error_str(ErlNifEnv* env, char* reason); extern ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err); extern +ERL_NIF_TERM esock_make_error_t2r(ErlNifEnv* env, + ERL_NIF_TERM tag, ERL_NIF_TERM reason); +extern ERL_NIF_TERM esock_make_error_invalid(ErlNifEnv* env, ERL_NIF_TERM what); extern ERL_NIF_TERM esock_make_error_integer_range(ErlNifEnv* env, ERL_NIF_TERM i); @@ -265,8 +304,18 @@ BOOLEAN_T esock_timestamp_str(char *buf, unsigned int len); extern BOOLEAN_T esock_format_timestamp(ErlNifTime timestamp, char *buf, unsigned int len); -extern -void esock_warning_msg(const char* format, ... ); +#define MSG_FUNCS \ + MSG_FUNC_DEF(info) \ + MSG_FUNC_DEF(warning) \ + MSG_FUNC_DEF(error) + +#define MSG_FUNC_DEF(FN) \ + extern \ + void esock_##FN##_msg(const char* format, ... ); + +MSG_FUNCS +#undef MSG_FUNC_DEF +#undef MSG_FUNCS extern BOOLEAN_T esock_is_integer(ErlNifEnv *env, ERL_NIF_TERM term); diff --git a/erts/emulator/nifs/unix/unix_prim_file.c b/erts/emulator/nifs/unix/unix_prim_file.c index c7caec44791d..2bb51651ef9e 100644 --- a/erts/emulator/nifs/unix/unix_prim_file.c +++ b/erts/emulator/nifs/unix/unix_prim_file.c @@ -141,11 +141,7 @@ static int get_flags(enum efile_modes_t modes) { if(modes & EFILE_MODE_READ && !(modes & EFILE_MODE_WRITE)) { flags |= O_RDONLY; } else if(modes & EFILE_MODE_WRITE && !(modes & EFILE_MODE_READ)) { - if(!(modes & EFILE_MODE_NO_TRUNCATE)) { - flags |= O_TRUNC; - } - - flags |= O_WRONLY | O_CREAT; + flags |= O_TRUNC | O_WRONLY | O_CREAT; } else if(modes & EFILE_MODE_READ_WRITE) { flags |= O_RDWR | O_CREAT; } else { @@ -554,7 +550,9 @@ int efile_sync(efile_data_t *d, int data_only) { } #endif -#if defined(__DARWIN__) && defined(F_FULLFSYNC) +#if defined(__DARWIN__) && defined(F_BARRIERFSYNC) + if(fcntl(u->fd, F_BARRIERFSYNC) < 0) { +#elif defined(__DARWIN__) && defined(F_FULLFSYNC) if(fcntl(u->fd, F_FULLFSYNC) < 0) { #else if(fsync(u->fd) < 0) { diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c new file mode 100644 index 000000000000..a2a92c02ad1a --- /dev/null +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -0,0 +1,7625 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : UNIX version of synchronous I/O backend. + * ---------------------------------------------------------------------- + * + * essio = ESock Synchronous I/O + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef ESOCK_ENABLE + +/* If we HAVE_SCTP_H and Solaris, we need to define the following in + * order to get SCTP working: + */ +#if (defined(HAVE_SCTP_H) && defined(__sun) && defined(__SVR4)) +#define SOLARIS10 1 +/* WARNING: This is not quite correct, it may also be Solaris 11! */ +#define _XPG4_2 +#define __EXTENSIONS__ +#endif + +#ifdef HAVE_SENDFILE +#if defined(__linux__) || (defined(__sun) && defined(__SVR4)) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + /* Need to define __BSD_VISIBLE in order to expose prototype + * of sendfile in sys/socket.h + */ + #define __BSD_VISIBLE 1 +#endif +#endif + +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif +#include "sys.h" + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include + +#include "prim_socket_int.h" +#include "socket_util.h" +#include "socket_io.h" +#include "socket_syncio.h" +#include "socket_tarray.h" +#include "prim_file_nif_dyncall.h" + + +/* ======================================================================== * + * Socket wrappers * + * ======================================================================== * + */ + +#ifdef HAS_ACCEPT4 +// We have to figure out what the flags are... +#define sock_accept(s, addr, len) \ + accept4((s), (addr), (len), (SOCK_CLOEXEC)) +#else +#define sock_accept(s, addr, len) accept((s), (addr), (len)) +#endif +#define sock_bind(s, addr, len) bind((s), (addr), (len)) +#define sock_close(s) close((s)) +// #define sock_close_event(e) /* do nothing */ +#define sock_connect(s, addr, len) connect((s), (addr), (len)) +#define sock_errno() errno +// #define sock_listen(s, b) listen((s), (b)) +// #define sock_name(s, addr, len) getsockname((s), (addr), (len)) +#define sock_open(domain, type, proto) socket((domain), (type), (proto)) +#define sock_peer(s, addr, len) getpeername((s), (addr), (len)) +#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ + recvfrom((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) +#define sock_send(s,buf,len,flag) send((s), (buf), (len), (flag)) +#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) +#define sock_sendto(s,buf,blen,flag,addr,alen) \ + sendto((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_shutdown(s, how) shutdown((s), (how)) + + +/* =================================================================== * + * * + * Various esaio macros * + * * + * =================================================================== */ + +/* Global socket debug */ +#define SGDBG( proto ) ESOCK_DBG_PRINTF( ctrl.dbg , proto ) + + +/* =================================================================== * + * * + * Local types * + * * + * =================================================================== */ + +typedef struct { + /* Misc stuff */ + BOOLEAN_T dbg; + BOOLEAN_T sockDbg; +} ESSIOControl; + + + +/* ======================================================================== * + * Function Forwards * + * ======================================================================== * + */ +static BOOLEAN_T open_todup(ErlNifEnv* env, + ERL_NIF_TERM eopts); +static BOOLEAN_T open_which_domain(SOCKET sock, int* domain); +static BOOLEAN_T open_which_type(SOCKET sock, int* type); +static BOOLEAN_T open_get_domain(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* domain); +static BOOLEAN_T open_get_type(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* type); +static BOOLEAN_T open_get_protocol(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* protocol); + +#ifdef HAVE_SETNS +static BOOLEAN_T open_get_netns(ErlNifEnv* env, + ERL_NIF_TERM opts, + char** netns); +static BOOLEAN_T change_network_namespace(BOOLEAN_T dbg, + char* netns, int* cns, int* err); +static BOOLEAN_T restore_network_namespace(BOOLEAN_T dbg, + int ns, SOCKET sock, int* err); +#endif + +static BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err); + +static ERL_NIF_TERM essio_cancel_accept_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM essio_cancel_accept_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP); +static ERL_NIF_TERM essio_cancel_send_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM essio_cancel_send_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP); +static ERL_NIF_TERM essio_cancel_recv_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM essio_cancel_recv_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP); + +static ERL_NIF_TERM essio_accept_listening_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + ErlNifPid caller, + int save_errno); +static ERL_NIF_TERM essio_accept_listening_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock, + ErlNifPid caller); +static ERL_NIF_TERM essio_accept_accepting_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM ref); +static +ERL_NIF_TERM essio_accept_accepting_current_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock); +static +ERL_NIF_TERM essio_accept_accepting_current_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef, + int save_errno); +static ERL_NIF_TERM essio_accept_accepting_other(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ErlNifPid caller); +static ERL_NIF_TERM essio_accept_busy_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + ErlNifPid* pidP); +static BOOLEAN_T essio_accept_accepted(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock, + ErlNifPid pid, + ERL_NIF_TERM* result); + +static BOOLEAN_T send_check_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ERL_NIF_TERM* checkResult); +static ERL_NIF_TERM send_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t send_result, + ssize_t dataSize, + BOOLEAN_T dataInTail, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef); +static ERL_NIF_TERM send_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t written, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM send_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef); +static void send_error_waiting_writers(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM send_check_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t written, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef); + +static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* cmsgHdrBufP, + size_t cmsgHdrBufLen, + size_t* cmsgHdrBufUsed); +static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* bufP, + size_t rem, + size_t* used); +static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eValue, + char* dataP, + size_t dataLen, + size_t* dataUsedP); +static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eData, + char* dataP, + size_t dataLen, + size_t* dataUsedP); + +static void encode_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM* eMsg); +static void encode_cmsgs(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifBinary* cmsgBinP, + struct msghdr* msgHdrP, + ERL_NIF_TERM* eCMsg); + +#if defined(HAVE_SENDFILE) +static int essio_sendfile(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + off_t offset, + size_t* countP, + int* errP); +static ERL_NIF_TERM essio_sendfile_errno(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + int err); +static ERL_NIF_TERM essio_sendfile_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); +static ERL_NIF_TERM essio_sendfile_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + size_t count); +static ERL_NIF_TERM essio_sendfile_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + size_t count); +#endif + +static ERL_NIF_TERM recv_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + int saveErrno, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + int saveErrno, + ErlNifBinary* bufP, + ESockAddress* fromAddrP, + SOCKLEN_T fromAddrLen, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static BOOLEAN_T recv_check_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ERL_NIF_TERM* checkResult); +static ERL_NIF_TERM recv_check_full(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ErlNifBinary* buf1P, + ErlNifBinary* buf2P, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static void recv_init_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM recvRef); +static void recv_update_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef); +static void recv_error_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason); + +static ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + int saveErrno, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM sockRef); + + +static ERL_NIF_TERM essio_ioctl_gifconf(ErlNifEnv* env, + ESockDescriptor* descP); +/* esock_ioctl_fionread */ +#if defined(FIONREAD) +#define IOCTL_FIONREAD_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionread) +#else +#define IOCTL_FIONREAD_FUNC2_DEF +#endif + +/* esock_ioctl_fionwrite */ +#if defined(FIONWRITE) +#define IOCTL_FIONWRITE_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionwrite) +#else +#define IOCTL_FIONWRITE_FUNC2_DEF +#endif + +/* esock_ioctl_fionspace */ +#if defined(FIONSPACE) +#define IOCTL_FIONSPACE_FUNC2_DEF IOCTL_GET_FUNC2_DEF(fionspace) +#else +#define IOCTL_FIONSPACE_FUNC2_DEF +#endif + +/* esock_ioctl_siocatmark */ +#if defined(SIOCATMARK) +#define IOCTL_SIOCATMARK_FUNC2_DEF IOCTL_GET_FUNC2_DEF(siocatmark) +#else +#define IOCTL_SIOCATMARK_FUNC2_DEF +#endif + +#define IOCTL_GET_FUNCS2_DEF \ + IOCTL_FIONREAD_FUNC2_DEF; \ + IOCTL_FIONWRITE_FUNC2_DEF; \ + IOCTL_FIONSPACE_FUNC2_DEF; \ + IOCTL_SIOCATMARK_FUNC2_DEF; +#define IOCTL_GET_FUNC2_DEF(F) \ + static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \ + ESockDescriptor* descP) +IOCTL_GET_FUNCS2_DEF +#undef IOCTL_GET_FUNC2_DEF + +#if defined(SIOCGIFNAME) +static ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eidx); +#endif + +/* esock_ioctl_gifindex */ +#if defined(SIOCGIFINDEX) +#define IOCTL_GIFINDEX_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifindex) +#else +#define IOCTL_GIFINDEX_FUNC3_DEF +#endif + +/* esock_ioctl_gifflags */ +#if defined(SIOCGIFFLAGS) +#define IOCTL_GIFFLAGS_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifflags) +#else +#define IOCTL_GIFFLAGS_FUNC3_DEF +#endif + +/* esock_ioctl_gifaddr */ +#if defined(SIOCGIFADDR) +#define IOCTL_GIFADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifaddr) +#else +#define IOCTL_GIFADDR_FUNC3_DEF +#endif + +/* esock_ioctl_gifdstaddr */ +#if defined(SIOCGIFDSTADDR) +#define IOCTL_GIFDSTADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifdstaddr) +#else +#define IOCTL_GIFDSTADDR_FUNC3_DEF +#endif + +/* esock_ioctl_gifbrdaddr */ +#if defined(SIOCGIFBRDADDR) +#define IOCTL_GIFBRDADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifbrdaddr) +#else +#define IOCTL_GIFBRDADDR_FUNC3_DEF +#endif + +/* esock_ioctl_gifnetmask */ +#if defined(SIOCGIFNETMASK) +#define IOCTL_GIFNETMASK_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifnetmask) +#else +#define IOCTL_GIFNETMASK_FUNC3_DEF +#endif + +/* esock_ioctl_gifmtu */ +#if defined(SIOCGIFMTU) +#define IOCTL_GIFMTU_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifmtu) +#else +#define IOCTL_GIFMTU_FUNC3_DEF +#endif + +/* esock_ioctl_gifhwaddr */ +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +#define IOCTL_GIFHWADDR_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifhwaddr) +#else +#define IOCTL_GIFHWADDR_FUNC3_DEF +#endif + +/* esock_ioctl_gifmap */ +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) +#define IOCTL_GIFMAP_FUNC3_DEF IOCTL_GET_FUNC3_DEF(gifmap) +#else +#define IOCTL_GIFMAP_FUNC3_DEF +#endif + +/* esock_ioctl_giftxqlen */ +#if defined(SIOCGIFTXQLEN) +#define IOCTL_GIFTXQLEN_FUNC3_DEF IOCTL_GET_FUNC3_DEF(giftxqlen) +#else +#define IOCTL_GIFTXQLEN_FUNC3_DEF +#endif + +#define IOCTL_GET_FUNCS3_DEF \ + IOCTL_GIFINDEX_FUNC3_DEF; \ + IOCTL_GIFFLAGS_FUNC3_DEF; \ + IOCTL_GIFADDR_FUNC3_DEF; \ + IOCTL_GIFDSTADDR_FUNC3_DEF; \ + IOCTL_GIFBRDADDR_FUNC3_DEF; \ + IOCTL_GIFNETMASK_FUNC3_DEF; \ + IOCTL_GIFMTU_FUNC3_DEF; \ + IOCTL_GIFHWADDR_FUNC3_DEF; \ + IOCTL_GIFMAP_FUNC3_DEF; \ + IOCTL_GIFTXQLEN_FUNC3_DEF; +#define IOCTL_GET_FUNC3_DEF(F) \ + static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM ename) +IOCTL_GET_FUNCS3_DEF +#undef IOCTL_GET_FUNC3_DEF + +/* esock_ioctl_sifflags */ +#if defined(SIOCSIFFLAGS) +#define IOCTL_SIFFLAGS_FUNC_DEF IOCTL_SET_FUNC_DEF(sifflags) +#else +#define IOCTL_SIFFLAGS_FUNC_DEF +#endif + +/* esock_ioctl_sifaddr */ +#if defined(SIOCSIFADDR) +#define IOCTL_SIFADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifaddr) +#else +#define IOCTL_SIFADDR_FUNC_DEF +#endif + +/* esock_ioctl_sifdstaddr */ +#if defined(SIOCSIFDSTADDR) +#define IOCTL_SIFDSTADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifdstaddr) +#else +#define IOCTL_SIFDSTADDR_FUNC_DEF +#endif + +/* esock_ioctl_sifbrdaddr */ +#if defined(SIOCSIFBRDADDR) +#define IOCTL_SIFBRDADDR_FUNC_DEF IOCTL_SET_FUNC_DEF(sifbrdaddr) +#else +#define IOCTL_SIFBRDADDR_FUNC_DEF +#endif + +/* esock_ioctl_sifnetmask */ +#if defined(SIOCSIFNETMASK) +#define IOCTL_SIFNETMASK_FUNC_DEF IOCTL_SET_FUNC_DEF(sifnetmask) +#else +#define IOCTL_SIFNETMASK_FUNC_DEF +#endif + +/* esock_ioctl_sifmtu */ +#if defined(SIOCSIFMTU) +#define IOCTL_SIFMTU_FUNC_DEF IOCTL_SET_FUNC_DEF(sifmtu) +#else +#define IOCTL_SIFMTU_FUNC_DEF +#endif + +/* esock_ioctl_siftxqlen */ +#if defined(SIOCSIFTXQLEN) +#define IOCTL_SIFTXQLEN_FUNC_DEF IOCTL_SET_FUNC_DEF(siftxqlen) +#else +#define IOCTL_SIFTXQLEN_FUNC_DEF +#endif + +#define IOCTL_SET_FUNCS_DEF \ + IOCTL_SIFFLAGS_FUNC_DEF; \ + IOCTL_SIFADDR_FUNC_DEF; \ + IOCTL_SIFDSTADDR_FUNC_DEF; \ + IOCTL_SIFBRDADDR_FUNC_DEF; \ + IOCTL_SIFNETMASK_FUNC_DEF; \ + IOCTL_SIFMTU_FUNC_DEF; \ + IOCTL_SIFTXQLEN_FUNC_DEF; +#define IOCTL_SET_FUNC_DEF(F) \ + static ERL_NIF_TERM essio_ioctl_##F(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM ename, \ + ERL_NIF_TERM evalue) +IOCTL_SET_FUNCS_DEF +#undef IOCTL_SET_FUNC_DEF + + +static ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifconf* ifcP); +static ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifreq* ifrP); +static ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, + char* name); +static ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, + struct sockaddr* sa); +static ERL_NIF_TERM make_ifreq(ErlNifEnv* env, + ERL_NIF_TERM name, + ERL_NIF_TERM key2, + ERL_NIF_TERM val2); +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) +static ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifmap* mapP); +#endif +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +static ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, + ESockDescriptor* descP, + struct sockaddr* addrP); +#endif +static ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, + ESockDescriptor* descP, + struct sockaddr* addrP); +static ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, + ESockDescriptor* descP, + short flags); +#if defined(SIOCSIFFLAGS) +static BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eflags, + short* flags); +#endif +static BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eaddr, + ESockAddress* addr); +#if defined(SIOCSIFMTU) +static BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM emtu, + int* mtu); +#endif +#if defined(SIOCSIFTXQLEN) +static BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM etxqlen, + int* txqlen); +#endif +#if defined(SIOCSIFTXQLEN) +static BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eivalue, + int* ivalue); +#endif +static ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + int ivalue); +static ERL_NIF_TERM encode_ioctl_bvalue(ErlNifEnv* env, + ESockDescriptor* descP, + int bvalue); + + +/* +static void essio_down_ctrl(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP); +*/ +static void essio_down_acceptor(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); +static void essio_down_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); +static void essio_down_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +static BOOLEAN_T do_stop(ErlNifEnv* env, + ESockDescriptor* descP); + + +/* =================================================================== * + * * + * Local (global) variables * + * * + * =================================================================== */ + +static ESSIOControl ctrl = {0}; + + + +/* ======================================================================== * + * ESSIO Functions * + * ======================================================================== * + */ + +/* + * For "standard" (unix) synchronous I/O, in our case + * this is just a dummy function. + */ +extern +int essio_init(unsigned int numThreads, + const ESockData* dataP) +{ + VOID(numThreads); + + ctrl.dbg = dataP->dbg; + ctrl.sockDbg = dataP->sockDbg; + + return ESOCK_IO_OK; +} + + +/* + * For "standard" (unix) synchronous I/O, this is just a dummy function. + * Also, will we ever call this? + */ +extern +void essio_finish(void) +{ + return; +} + + + +/* ******************************************************************* + * essio_info - Return info "about" this I/O backend. + */ + +extern +ERL_NIF_TERM essio_info(ErlNifEnv* env) +{ + ERL_NIF_TERM info; + ERL_NIF_TERM keys[] = {esock_atom_name}; + ERL_NIF_TERM vals[] = {MKA(env, "unix_essio")}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); + + return info; +} + + + +/* ======================================================================== + * essio_open - create an endpoint (from an existing fd) for communication + * + * Assumes the input has been validated. + * + * Normally we want debugging on (individual) sockets to be controlled + * by the sockets own debug flag. But since we don't even have a socket + * yet, we must use the global debug flag. + */ +extern +ERL_NIF_TERM essio_open_with_fd(ErlNifEnv* env, + int fd, + ERL_NIF_TERM eopts, + const ESockData* dataP) +{ + BOOLEAN_T dbg = esock_open_is_debug(env, eopts, dataP->sockDbg); + BOOLEAN_T useReg = esock_open_use_registry(env, eopts, dataP->useReg); + ESockDescriptor* descP; + ERL_NIF_TERM sockRef; + int domain, type, protocol; + int save_errno = 0; + BOOLEAN_T closeOnClose; + SOCKET sock; + ErlNifPid self; + + /* Keep track of the creator + * This should not be a problem, but just in case + * the *open* function is used with the wrong kind + * of environment... + */ + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + SSDBG2( dbg, + ("UNIX-ESSIO", "essio_open2 -> entry with" + "\r\n fd: %d" + "\r\n eopts: %T" + "\r\n", fd, eopts) ); + + /* + * Before we do anything else, we try to retrieve domain, type and protocol + * This information is either present in the eopts map or if not we need + * to "get" it from the system (getsockopt). + * Note that its not possible to get all of these on all platforms, + * and in those cases the user *must* provide us with them (eopts). + * + * We try the system first (since its more reliable) and if that fails + * we check the eopts map. If neither one works, we *give up*! + */ + + if (! open_which_domain(fd, &domain)) { + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> failed get domain from system\r\n") ); + + if (! open_get_domain(env, eopts, &domain)) { + return esock_make_invalid(env, esock_atom_domain); + } + } + + if (! open_which_type(fd, &type)) { + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> failed get type from system\r\n") ); + + if (! open_get_type(env, eopts, &type)) + return esock_make_invalid(env, esock_atom_type); + } + + if (! esock_open_which_protocol(fd, &protocol)) { + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> failed get protocol from system\r\n") ); + + if (! open_get_protocol(env, eopts, &protocol)) { + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> " + "failed get protocol => try protocol 0\r\n") ); + protocol = 0; + } + } + + + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> " + "\r\n domain: %d" + "\r\n type: %d" + "\r\n protocol: %d" + "\r\n", domain, type, protocol) ); + + + if (open_todup(env, eopts)) { + /* We shall dup the socket */ + if (ESOCK_IS_ERROR(sock = dup(fd))) { + save_errno = sock_errno(); + + SSDBG2( dbg, + ("UNIX-ESSIO", + "essio_open2 -> dup failed: %d\r\n", + save_errno) ); + + return esock_make_error_errno(env, save_errno); + } + closeOnClose = TRUE; + } else { + sock = fd; + closeOnClose = FALSE; + } + + + SET_NONBLOCKING(sock); + + /* Create and initiate the socket "descriptor" */ + descP = esock_alloc_descriptor(sock); + descP->ctrlPid = self; + descP->domain = domain; + descP->type = type; + descP->protocol = protocol; + descP->closeOnClose = closeOnClose; + descP->origFD = fd; + + /* Check if we are already connected, if so change state */ + { + ESockAddress remote; + SOCKLEN_T addrLen = sizeof(remote); + sys_memzero((char *) &remote, addrLen); + if (sock_peer(descP->sock, + (struct sockaddr*) &remote, + &addrLen) == 0) { + SSDBG2( dbg, ("UNIX-ESSIO", "essio_open2 -> connected\r\n") ); + descP->writeState |= ESOCK_STATE_CONNECTED; + } else { + SSDBG2( dbg, ("UNIX-ESSIO", "essio_open2 -> not connected\r\n") ); + } + } + + /* And create the 'socket' resource */ + sockRef = enif_make_resource(env, descP); + enif_release_resource(descP); + + ESOCK_ASSERT( MONP("essio_open2 -> ctrl", + env, descP, + &descP->ctrlPid, + &descP->ctrlMon) == 0 ); + + descP->dbg = dbg; + descP->useReg = useReg; + esock_inc_socket(domain, type, protocol); + + /* And finally (maybe) update the registry. + * Shall we keep track of the fact that this socket is created elsewhere? + */ + if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); + + SSDBG2( dbg, + ("UNIX-ESSIO", "essio_open2 -> done: %T\r\n", sockRef) ); + + return esock_make_ok2(env, sockRef); +} + + +static +BOOLEAN_T open_which_domain(SOCKET sock, int* domain) +{ +#if defined(SO_DOMAIN) + if (esock_getopt_int(sock, SOL_SOCKET, SO_DOMAIN, domain)) + return TRUE; +#endif + return FALSE; +} + +/* The eopts contains an integer 'domain' key. + */ +static +BOOLEAN_T open_get_domain(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* domain) +{ + ERL_NIF_TERM edomain; + + if (!GET_MAP_VAL(env, eopts, + esock_atom_domain, &edomain)) + return FALSE; + + if (esock_decode_domain(env, edomain, domain) == 0) + return FALSE; + + return TRUE; +} + +static +BOOLEAN_T open_which_type(SOCKET sock, int* type) +{ +#if defined(SO_TYPE) + if (esock_getopt_int(sock, SOL_SOCKET, SO_TYPE, type)) + return TRUE; +#endif + return FALSE; +} + +/* The eopts contains an integer 'type' key. + */ +static +BOOLEAN_T open_get_type(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* type) +{ + ERL_NIF_TERM etype; + + if (! GET_MAP_VAL(env, eopts, esock_atom_type, &etype)) + return FALSE; + + if (! esock_decode_type(env, etype, type)) + return FALSE; + + return TRUE; +} + +/* The eopts contains an integer 'type' key. + */ +static +BOOLEAN_T open_get_protocol(ErlNifEnv* env, + ERL_NIF_TERM eopts, + int* protocol) +{ + return esock_extract_int_from_map(env, eopts, + esock_atom_protocol, protocol); +} + + +/* The eopts contains a boolean 'dup' key. Defaults to TRUE. + */ +static +BOOLEAN_T open_todup(ErlNifEnv* env, ERL_NIF_TERM eopts) +{ + return esock_get_bool_from_map(env, eopts, esock_atom_dup, TRUE); +} + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_open_plain(ErlNifEnv* env, + int domain, + int type, + int protocol, + ERL_NIF_TERM eopts, + const ESockData* dataP) +{ + BOOLEAN_T dbg = esock_open_is_debug(env, eopts, dataP->sockDbg); + BOOLEAN_T useReg = esock_open_use_registry(env, eopts, dataP->useReg); + ESockDescriptor* descP; + ERL_NIF_TERM sockRef; + int proto = protocol; + SOCKET sock; + char* netns; +#ifdef HAVE_SETNS + int save_errno; + int current_ns = 0; +#endif + ErlNifPid self; + + /* Keep track of the creator + * This should not be a problem, but just in case + * the *open* function is used with the wrong kind + * of environment... + */ + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + SSDBG2( dbg, + ("UNIX-ESSIO", "essio_open4 -> entry with" + "\r\n domain: %d" + "\r\n type: %d" + "\r\n protocol: %d" + "\r\n eopts: %T" + "\r\n", domain, type, protocol, eopts) ); + + +#ifdef HAVE_SETNS + if (open_get_netns(env, eopts, &netns)) { + SSDBG2( dbg, + ("UNIX-ESSIO", "essio_open4 -> namespace: %s\r\n", netns) ); + } +#else + netns = NULL; +#endif + + +#ifdef HAVE_SETNS + if ((netns != NULL) && + (! change_network_namespace(dbg, + netns, ¤t_ns, &save_errno))) { + FREE(netns); + return esock_make_error_errno(env, save_errno); + } +#endif + + if (ESOCK_IS_ERROR(sock = sock_open(domain, type, proto))) { + if (netns != NULL) FREE(netns); + return esock_make_error_errno(env, sock_errno()); + } + + SSDBG2( dbg, ("UNIX-ESSIO", "essio_open4 -> open success: %d\r\n", sock) ); + + + /* NOTE that if the protocol = 0 (default) and the domain is not + * local (AF_LOCAL) we need to explicitly get the protocol here! + */ + + if (proto == 0) + (void) esock_open_which_protocol(sock, &proto); + +#ifdef HAVE_SETNS + if (netns != NULL) { + FREE(netns); + if (! restore_network_namespace(dbg, + current_ns, sock, &save_errno)) + return esock_make_error_errno(env, save_errno); + } +#endif + + SET_NONBLOCKING(sock); + + + /* Create and initiate the socket "descriptor" */ + descP = esock_alloc_descriptor(sock); + descP->ctrlPid = self; + descP->domain = domain; + descP->type = type; + descP->protocol = proto; + + sockRef = enif_make_resource(env, descP); + enif_release_resource(descP); + + ESOCK_ASSERT( MONP("esock_open -> ctrl", + env, descP, + &descP->ctrlPid, + &descP->ctrlMon) == 0 ); + + descP->dbg = dbg; + descP->useReg = useReg; + esock_inc_socket(domain, type, proto); + + /* And finally (maybe) update the registry */ + if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); + + return esock_make_ok2(env, sockRef); +} + + +#ifdef HAVE_SETNS +/* open_get_netns - extract the netns field from the opts map + */ +static +BOOLEAN_T open_get_netns(ErlNifEnv* env, ERL_NIF_TERM opts, char** netns) +{ + ERL_NIF_TERM val; + ErlNifBinary bin; + char* buf; + + /* The currently only supported extra option is: netns */ + if (!GET_MAP_VAL(env, opts, esock_atom_netns, &val)) { + *netns = NULL; // Just in case... + return FALSE; + } + + /* The value should be a binary file name */ + if (! enif_inspect_binary(env, val, &bin)) { + *netns = NULL; // Just in case... + return FALSE; + } + + ESOCK_ASSERT( (buf = MALLOC(bin.size+1)) != NULL ); + + sys_memcpy(buf, bin.data, bin.size); + buf[bin.size] = '\0'; + *netns = buf; + + return TRUE; +} + + +/* We should really have another API, so that we can return errno... */ + +/* *** change network namespace *** + * Retrieve the current namespace and set the new. + * Return result and previous namespace if successful. + */ +static +BOOLEAN_T change_network_namespace(BOOLEAN_T dbg, + char* netns, int* cns, int* err) +{ + int save_errno; + int current_ns = 0; + int new_ns = 0; + + SSDBG2( dbg, + ("UNIX-ESSIO", "change_network_namespace -> entry with" + "\r\n new ns: %s" + "\r\n", netns) ); + + current_ns = open("/proc/self/ns/net", O_RDONLY); + if (ESOCK_IS_ERROR(current_ns)) { + *err = sock_errno(); + return FALSE; + } + new_ns = open(netns, O_RDONLY); + if (ESOCK_IS_ERROR(new_ns)) { + save_errno = sock_errno(); + (void) close(current_ns); + *err = save_errno; + return FALSE; + } + if (setns(new_ns, CLONE_NEWNET) != 0) { + save_errno = sock_errno(); + (void) close(new_ns); + (void) close(current_ns); + *err = save_errno; + return FALSE; + } else { + (void) close(new_ns); + *cns = current_ns; + return TRUE; + } +} + + +/* *** restore network namespace *** + * Restore the previous namespace (see above). + */ +static +BOOLEAN_T restore_network_namespace(BOOLEAN_T dbg, + int ns, SOCKET sock, int* err) +{ + SSDBG2( dbg, + ("UNIX-ESSIO", "restore_network_namespace -> entry with" + "\r\n ns: %d" + "\r\n", ns) ); + + if (setns(ns, CLONE_NEWNET) != 0) { + /* XXX Failed to restore network namespace. + * What to do? Tidy up and return an error... + * Note that the thread now might still be in the namespace. + * Can this even happen? Should the emulator be aborted? + */ + int save_errno = sock_errno(); + (void) close(sock); + (void) close(ns); + *err = save_errno; + return FALSE; + } else { + (void) close(ns); + return TRUE; + } +} + +#endif + + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_bind(ErlNifEnv* env, + ESockDescriptor* descP, + ESockAddress* sockAddrP, + SOCKLEN_T addrLen) +{ + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + if (sock_bind(descP->sock, &sockAddrP->sa, addrLen) < 0) { + return esock_make_error_errno(env, sock_errno()); + } + + descP->readState |= ESOCK_STATE_BOUND; + + return esock_atom_ok; +} + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen) +{ + int save_errno; + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + /* + * Verify that we are in the proper state + */ + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->currentWriterP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + if (descP->connectorP != NULL) { + /* Connect in progress */ + + if (COMPARE_PIDS(&self, &descP->connector.pid) != 0) { + /* Other process has connect in progress */ + if (addrP != NULL) { + return esock_make_error(env, esock_atom_already); + } else { + /* This is a bad call sequence + * - connect without an address is only allowed + * for the connecting process + */ + return esock_raise_invalid(env, esock_atom_state); + } + } + + /* Finalize after received select message */ + + esock_requestor_release("essio_connect finalize -> connected", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~ESOCK_STATE_CONNECTING; + + if (! verify_is_connected(descP, &save_errno)) { + return esock_make_error_errno(env, save_errno); + } + + descP->writeState |= ESOCK_STATE_CONNECTED; + + return esock_atom_ok; + } + + /* No connect in progress */ + + if (addrP == NULL) + /* This is a bad call sequence + * - connect without an address is only allowed when + * a connect is in progress, after getting the select message + */ + return esock_raise_invalid(env, esock_atom_state); + + /* Initial connect call, with address */ + + if (sock_connect(descP->sock, (struct sockaddr*) addrP, addrLen) == 0) { + /* Success already! */ + SSDBG( descP, ("UNIX-ESSIO", "essio_connect {%d} -> connected\r\n", + descP->sock) ); + + descP->writeState |= ESOCK_STATE_CONNECTED; + + return esock_atom_ok; + } + + /* Connect returned error */ + save_errno = sock_errno(); + + switch (save_errno) { + + case EINPROGRESS: /* Unix & OSE!! */ + SSDBG( descP, + ("UNIX-ESSIO", "essio_connect {%d} -> would block => select\r\n", + descP->sock) ); + { + int sres; + + if ((sres = + esock_select_write(env, descP->sock, descP, NULL, + sockRef, connRef)) < 0) + return + enif_raise_exception(env, + MKT2(env, esock_atom_select_write, + MKI(env, sres))); + /* Initiate connector */ + descP->connector.pid = self; + ESOCK_ASSERT( MONP("essio_connect -> conn", + env, descP, + &self, &descP->connector.mon) == 0 ); + descP->connector.env = esock_alloc_env("connector"); + descP->connector.ref = CP_TERM(descP->connector.env, connRef); + descP->connectorP = &descP->connector; + descP->writeState |= + (ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + + return esock_atom_select; + } + break; + + default: + SSDBG( descP, + ("UNIX-ESSIO", "essio_connect {%d} -> error: %d\r\n", + descP->sock, save_errno) ); + + return esock_make_error_errno(env, save_errno); + + } // switch(save_errno) +} + + +/* *** verify_is_connected *** + * Check if a connection has been established. + */ +static +BOOLEAN_T verify_is_connected(ESockDescriptor* descP, int* err) +{ + /* + * *** This is strange *** + * + * This *should* work on Windows NT too, but doesn't. + * An bug in Winsock 2.0 for Windows NT? + * + * See "Unix Netwok Programming", "The Sockets Networking API", + * W.R.Stevens, Volume 1, third edition, 16.4 Nonblocking 'connect', + * before Interrupted 'connect' (p 412) for a discussion about + * Unix portability and non blocking connect. + */ + + int error = 0; + +#ifdef SO_ERROR + if (! esock_getopt_int(descP->sock, SOL_SOCKET, SO_ERROR, &error)) { + // Solaris does it this way according to W.R.Stevens + error = sock_errno(); + } +#elif 1 + char buf[0]; + if (ESOCK_IS_ERROR(read(descP->sock, buf, sizeof(buf)))) { + error = sock_errno(); + } +#else + /* This variant probably returns wrong error value + * ENOTCONN instead of the actual connect error + */ + ESockAddress remote; + SOCKLEN_T addrLen = sizeof(remote); + sys_memzero((char *) &remote, addrLen); + if (sock_peer(descP->sock, + (struct sockaddr*) &remote, &addrLen)) < 0) { + error = sock_errno(); + } +#endif + + if (error != 0) { + *err = error; + return FALSE; + } + return TRUE; +} + + + +/* *** essio_listen *** */ + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef) +{ + ErlNifPid caller; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read uses the same select flag + * so they can not be simultaneous + */ + if (descP->currentReaderP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + if (descP->currentAcceptorP == NULL) { + SOCKET accSock; + + /* We have no active acceptor (and therefore no acceptors in queue) + */ + + SSDBG( descP, ("UNIX-ESSIO", "essio_accept {%d} -> try accept\r\n", + descP->sock) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_tries, &descP->accTries, 1); + + accSock = sock_accept(descP->sock, NULL, NULL); + + if (ESOCK_IS_ERROR(accSock)) { + int save_errno; + + save_errno = sock_errno(); + + return essio_accept_listening_error(env, descP, sockRef, + accRef, caller, save_errno); + } else { + /* We got an incoming connection */ + return essio_accept_listening_accept(env, descP, sockRef, + accSock, caller); + } + } else { + + /* We have an active acceptor and possibly acceptors waiting in queue. + * If the pid of the calling process is not the pid of the + * "current process", push the requester onto the (acceptor) queue. + */ + + SSDBG( descP, ("UNIX-ESSIO", "essio_accept_accepting -> " + "check: is caller current acceptor:" + "\r\n Caller: %T" + "\r\n Current: %T" + "\r\n Current Mon: %T" + "\r\n", + caller, + descP->currentAcceptor.pid, + ESOCK_MON2TERM(env, &descP->currentAcceptor.mon)) ); + + if (COMPARE_PIDS(&descP->currentAcceptor.pid, &caller) == 0) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting {%d} -> " + "current acceptor - try again" + "\r\n", descP->sock) ); + + return essio_accept_accepting_current(env, descP, sockRef, accRef); + + } else { + + /* Not the "current acceptor", so (maybe) push onto queue */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting {%d} -> *not* current acceptor\r\n", + descP->sock) ); + + return essio_accept_accepting_other(env, descP, accRef, caller); + } + } +} + + +/* *** essio_accept_listening_error *** + * + * The accept call resultet in an error - handle it. + * There are only two cases: + * 1) BLOCK => Attempt a "retry" + * 2) Other => Return the value (converted to an atom) + */ +static +ERL_NIF_TERM essio_accept_listening_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + ErlNifPid caller, + int save_errno) +{ + ERL_NIF_TERM res; + + if (save_errno == ERRNO_BLOCK || + save_errno == EAGAIN) { + + /* *** Try again later *** */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_listening_error {%d} -> would block - retry\r\n", + descP->sock) ); + + descP->currentAcceptor.pid = caller; + ESOCK_ASSERT( MONP("essio_accept_listening -> current acceptor", + env, descP, + &descP->currentAcceptor.pid, + &descP->currentAcceptor.mon) == 0 ); + ESOCK_ASSERT( descP->currentAcceptor.env == NULL ); + descP->currentAcceptor.env = esock_alloc_env("current acceptor"); + descP->currentAcceptor.ref = + CP_TERM(descP->currentAcceptor.env, accRef); + descP->currentAcceptorP = &descP->currentAcceptor; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_listening_error {%d} -> retry for: " + "\r\n Current Pid: %T" + "\r\n Current Mon: %T" + "\r\n", + descP->sock, + descP->currentAcceptor.pid, + ESOCK_MON2TERM(env, &descP->currentAcceptor.mon)) ); + + res = essio_accept_busy_retry(env, descP, sockRef, accRef, NULL); + + } else { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_listening {%d} -> errno: %d\r\n", + descP->sock, save_errno) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_fails, &descP->accFails, 1); + + res = esock_make_error_errno(env, save_errno); + } + + return res; +} + + +/* *** essio_accept_listening_accept *** + * + * The accept call was successful (accepted) - handle the new connection. + */ +static +ERL_NIF_TERM essio_accept_listening_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock, + ErlNifPid caller) +{ + ERL_NIF_TERM res; + + essio_accept_accepted(env, descP, sockRef, accSock, caller, &res); + + return res; +} + + +/* *** essio_accept_accepting_current *** + * Handles when the current acceptor makes another attempt. + */ +static +ERL_NIF_TERM essio_accept_accepting_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef) +{ + SOCKET accSock; + int save_errno; + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current {%d} -> try accept\r\n", + descP->sock) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_tries, &descP->accTries, 1); + + accSock = sock_accept(descP->sock, NULL, NULL); + + if (ESOCK_IS_ERROR(accSock)) { + + save_errno = sock_errno(); + + res = essio_accept_accepting_current_error(env, descP, sockRef, + accRef, save_errno); + } else { + + res = essio_accept_accepting_current_accept(env, descP, sockRef, + accSock); + } + + return res; +} + + +/* *** essio_accept_accepting_current_accept *** + * + * Handles when the current acceptor succeeded in its accept call - + * handle the new connection. + */ +static +ERL_NIF_TERM essio_accept_accepting_current_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_accept {%d}" + "\r\n", descP->sock) ); + + if (essio_accept_accepted(env, descP, sockRef, accSock, + descP->currentAcceptor.pid, &res)) { + + ESOCK_ASSERT( DEMONP("essio_accept_accepting_current_accept -> " + "current acceptor", + env, descP, &descP->currentAcceptor.mon) == 0); + + MON_INIT(&descP->currentAcceptor.mon); + + if (!esock_activate_next_acceptor(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_accept {%d} ->" + " no more acceptors" + "\r\n", descP->sock) ); + + descP->readState &= ~ESOCK_STATE_ACCEPTING; + + descP->currentAcceptorP = NULL; + } + + } + + return res; +} + + +/* *** essio_accept_accepting_current_error *** + * The accept call of current acceptor resultet in an error - handle it. + * There are only two cases: + * 1) BLOCK => Attempt a "retry" + * 2) Other => Return the value (converted to an atom) + */ +static +ERL_NIF_TERM essio_accept_accepting_current_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + int save_errno) +{ + ERL_NIF_TERM res, reason; + + if (save_errno == ERRNO_BLOCK || + save_errno == EAGAIN) { + + /* + * Just try again, no real error, just a ghost trigger from poll, + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> " + "would block: try again\r\n", descP->sock) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_waits, &descP->accWaits, 1); + + + /* Maybe cancel "current" select */ + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> " + "cancel current select" + "\r\n", descP->sock) ); + res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref); + + if (IS_OK(res)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> " + "send abort message" + "\r\n", descP->sock) ); + esock_send_abort_msg(env, descP, sockRef, + &descP->currentAcceptor, + esock_atom_cancelled); + /* We need a new env, + * since sending the abort message uses up the old */ + descP->currentAcceptor.env = esock_alloc_env("current acceptor"); + + /* And update the currentr acceptor ref (handle) */ + descP->currentAcceptor.ref = + CP_TERM(descP->currentAcceptor.env, accRef); + + /* And finally - retry */ + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> " + "try new select" + "\r\n", descP->sock) ); + res = essio_accept_busy_retry(env, descP, sockRef, accRef, + &descP->currentAcceptor.pid); + } + + } else { + ESockRequestor req; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> " + "error: %d\r\n", descP->sock, save_errno) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_fails, &descP->accFails, 1); + + esock_requestor_release("essio_accept_accepting_current_error", + env, descP, &descP->currentAcceptor); + + reason = MKA(env, erl_errno_id(save_errno)); + res = esock_make_error(env, reason); + + req.env = NULL; + while (esock_acceptor_pop(env, descP, &req)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_accepting_current_error(%d) -> abort %T\r\n", + descP->sock, req.pid) ); + + esock_send_abort_msg(env, descP, sockRef, &req, reason); + + (void) DEMONP("essio_accept_accepting_current_error -> " + "pop'ed writer", + env, descP, &req.mon); + } + descP->currentAcceptorP = NULL; + } + + return res; +} + + +/* *** essio_accept_accepting_other *** + * Handles when the another acceptor makes an attempt, which + * results (maybe) in the request being pushed onto the + * acceptor queue. + */ +static +ERL_NIF_TERM essio_accept_accepting_other(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ErlNifPid caller) +{ + if (! esock_acceptor_search4pid(env, descP, &caller)) { + esock_acceptor_push(env, descP, caller, ref, NULL); + return esock_atom_select; + } else { + /* Acceptor already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } +} + + +/* *** essio_accept_busy_retry *** + * + * Perform a retry select. If successful, set nextState. + */ +static +ERL_NIF_TERM essio_accept_busy_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + ErlNifPid* pidP) +{ + int sres; + ERL_NIF_TERM res; + + if ((sres = esock_select_read(env, descP->sock, descP, pidP, + sockRef, accRef)) < 0) { + + ESOCK_ASSERT( DEMONP("essio_accept_busy_retry - select failed", + env, descP, &descP->currentAcceptor.mon) == 0); + + MON_INIT(&descP->currentAcceptor.mon); + + /* It is very unlikely that a next acceptor will be able + * to do anything successful, but we will clean the queue + */ + + if (!esock_activate_next_acceptor(env, descP, sockRef)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_accept_busy_retry {%d} -> no more acceptors\r\n", + descP->sock) ); + + descP->readState &= ~ESOCK_STATE_ACCEPTING; + + descP->currentAcceptorP = NULL; + } + + res = + enif_raise_exception(env, + MKT2(env, esock_atom_select_read, + MKI(env, sres))); + } else { + + descP->readState |= + (ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); + + res = esock_atom_select; + } + + return res; +} + + +/* *** essio_accept_accepted *** + * + * Generic function handling a successful accept. + */ +static +BOOLEAN_T essio_accept_accepted(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + SOCKET accSock, + ErlNifPid pid, + ERL_NIF_TERM* result) +{ + ESockDescriptor* accDescP; + ERL_NIF_TERM accRef; + + /* + * We got one + */ + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_success, &descP->accSuccess, 1); + + accDescP = esock_alloc_descriptor(accSock); + accDescP->domain = descP->domain; + accDescP->type = descP->type; + accDescP->protocol = descP->protocol; + + MLOCK(descP->writeMtx); + + accDescP->rBufSz = descP->rBufSz; // Inherit buffer size + accDescP->rNum = descP->rNum; // Inherit buffer uses + accDescP->rNumCnt = 0; + accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size + accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size + accDescP->iow = descP->iow; // Inherit iow + accDescP->dbg = descP->dbg; // Inherit debug flag + accDescP->useReg = descP->useReg; // Inherit useReg flag + esock_inc_socket(accDescP->domain, accDescP->type, accDescP->protocol); + + accRef = enif_make_resource(env, accDescP); + enif_release_resource(accDescP); + + accDescP->ctrlPid = pid; + /* pid has actually been compared equal to self() + * in this code path just a little while ago + */ + ESOCK_ASSERT( MONP("essio_accept_accepted -> ctrl", + env, accDescP, + &accDescP->ctrlPid, + &accDescP->ctrlMon) == 0 ); + + SET_NONBLOCKING(accDescP->sock); + + accDescP->writeState |= ESOCK_STATE_CONNECTED; + + MUNLOCK(descP->writeMtx); + + /* And finally (maybe) update the registry */ + if (descP->useReg) esock_send_reg_add_msg(env, descP, accRef); + + *result = esock_make_ok2(env, accRef); + + return TRUE; +} + + + +/* ======================================================================== + * Do the actual send. + * Do some initial writer checks, do the actual send and then + * analyze the result. If we are done, another writer may be + * scheduled (if there is one in the writer queue). + */ +extern +ERL_NIF_TERM essio_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags) +{ + ssize_t send_result; + ERL_NIF_TERM writerCheck; + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + send_result = (ssize_t) sndDataP->size; + if ((size_t) send_result != sndDataP->size) + return esock_make_error_invalid(env, esock_atom_data_size); + + /* Ensure that we either have no current writer or we are it, + * or enqueue this process if there is a current writer */ + if (! send_check_writer(env, descP, sendRef, &writerCheck)) { + SSDBG( descP, ("UNIX-ESSIO", "esock_send {%d} -> writer check failed: " + "\r\n %T\r\n", descP->sock, writerCheck) ); + return writerCheck; + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + send_result = sock_send(descP->sock, sndDataP->data, sndDataP->size, flags); + + return send_check_result(env, descP, + send_result, sndDataP->size, FALSE, + sockRef, sendRef); + +} + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_sendto(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* dataP, + int flags, + ESockAddress* toAddrP, + SOCKLEN_T toAddrLen) +{ + ssize_t result; + ERL_NIF_TERM writerCheck; + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + result = (ssize_t) dataP->size; + if ((size_t) result != dataP->size) + return esock_make_error_invalid(env, esock_atom_data_size); + + /* Ensure that we either have no current writer or we are it, + * or enqueue this process if there is a current writer */ + if (! send_check_writer(env, descP, sendRef, &writerCheck)) { + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendto {%d} -> writer check failed: " + "\r\n %T\r\n", descP->sock, writerCheck) ); + return writerCheck; + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + if (toAddrP != NULL) { + result = sock_sendto(descP->sock, + dataP->data, dataP->size, flags, + &toAddrP->sa, toAddrLen); + } else { + result = sock_sendto(descP->sock, + dataP->data, dataP->size, flags, + NULL, 0); + } + + return send_check_result(env, descP, result, dataP->size, FALSE, + sockRef, sendRef); +} + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_sendmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsg, + int flags, + ERL_NIF_TERM eIOV, + const ESockData* dataP) +{ + ERL_NIF_TERM res, eAddr, eCtrl; + ESockAddress addr; + struct msghdr msgHdr; + ErlNifIOVec *iovec = NULL; + char* ctrlBuf; + size_t ctrlBufLen, ctrlBufUsed; + ssize_t dataSize, sendmsg_result; + ERL_NIF_TERM writerCheck, tail; + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that we either have no current writer or we are it, + * or enqueue this process if there is a current writer */ + if (! send_check_writer(env, descP, sendRef, &writerCheck)) { + SSDBG( descP, + ("UNIX-ESSIO", "essio_sendmsg {%d} -> writer check failed: " + "\r\n %T\r\n", descP->sock, writerCheck) ); + return writerCheck; + } + + /* Initiate the .name and .namelen fields depending on if + * we have an address or not + */ + if (! GET_MAP_VAL(env, eMsg, esock_atom_addr, &eAddr)) { + + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> no address\r\n", descP->sock) ); + + msgHdr.msg_name = NULL; + msgHdr.msg_namelen = 0; + } else { + msgHdr.msg_name = (void*) &addr; + msgHdr.msg_namelen = sizeof(addr); + sys_memzero((char *) msgHdr.msg_name, msgHdr.msg_namelen); + + SSDBG( descP, ("UNIX-ESSIO", "essio_sendmsg {%d} ->" + "\r\n address: %T" + "\r\n", descP->sock, eAddr) ); + + if (! esock_decode_sockaddr(env, eAddr, + msgHdr.msg_name, + &msgHdr.msg_namelen)) { + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> invalid address\r\n", + descP->sock) ); + return esock_make_invalid(env, esock_atom_addr); + } + } + + /* Extract the *mandatory* 'iov', which must be an erlang:iovec(), + * from which we take at most IOV_MAX binaries + */ + if ((! enif_inspect_iovec(NULL, dataP->iov_max, eIOV, &tail, &iovec))) { + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> not an iov\r\n", + descP->sock) ); + + return esock_make_invalid(env, esock_atom_iov); + } + + SSDBG( descP, ("UNIX-ESSIO", "essio_sendmsg {%d} ->" + "\r\n iovcnt: %lu" + "\r\n tail: %s" + "\r\n", descP->sock, + (unsigned long) iovec->iovcnt, + B2S(! enif_is_empty_list(env, tail))) ); + + /* We now have an allocated iovec */ + + eCtrl = esock_atom_undefined; + ctrlBufLen = 0; + ctrlBuf = NULL; + + if (iovec->iovcnt > dataP->iov_max) { + if (descP->type == SOCK_STREAM) { + iovec->iovcnt = dataP->iov_max; + } else { + /* We can not send the whole packet in one sendmsg() call */ + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> iovcnt > iov_max\r\n", + descP->sock) ); + res = esock_make_invalid(env, esock_atom_iov); + goto done_free_iovec; + } + } + + dataSize = 0; + { + ERL_NIF_TERM h, t; + ErlNifBinary bin; + size_t i; + + /* Find out if there is remaining data in the tail. + * Skip empty binaries otherwise break. + * If 'tail' after loop exit is the empty list + * there was no more data. Otherwise there is more + * data or the 'iov' is invalid. + */ + for (;;) { + if (enif_get_list_cell(env, tail, &h, &t) && + enif_inspect_binary(env, h, &bin) && + (bin.size == 0)) { + tail = t; + continue; + } else + break; + } + + if ((! enif_is_empty_list(env, tail)) && + (descP->type != SOCK_STREAM)) { + /* We can not send the whole packet in one sendmsg() call */ + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> invalid tail\r\n", + descP->sock) ); + res = esock_make_invalid(env, esock_atom_iov); + goto done_free_iovec; + } + + /* Calculate the data size */ + + for (i = 0; i < iovec->iovcnt; i++) { + size_t len = iovec->iov[i].iov_len; + dataSize += len; + if (dataSize < len) { + /* Overflow */ + SSDBG( descP, ("UNIX-ESSIO", "essio_sendmsg {%d} -> Overflow" + "\r\n i: %lu" + "\r\n len: %lu" + "\r\n dataSize: %ld" + "\r\n", descP->sock, (unsigned long) i, + (unsigned long) len, (long) dataSize) ); + res = esock_make_invalid(env, esock_atom_iov); + goto done_free_iovec; + } + } + } + SSDBG( descP, + ("UNIX-ESSIO", + "essio_sendmsg {%d} -> iovec size verified" + "\r\n iov length: %lu" + "\r\n data size: %u" + "\r\n", + descP->sock, + (unsigned long) iovec->iovcnt, (long) dataSize) ); + + msgHdr.msg_iovlen = iovec->iovcnt; + msgHdr.msg_iov = iovec->iov; + + /* Extract the *optional* 'ctrl' */ + if (GET_MAP_VAL(env, eMsg, esock_atom_ctrl, &eCtrl)) { + ctrlBufLen = descP->wCtrlSz; + ctrlBuf = (char*) MALLOC(ctrlBufLen); + ESOCK_ASSERT( ctrlBuf != NULL ); + } + SSDBG( descP, ("UNIX-ESSIO", "essio_sendmsg {%d} -> optional ctrl: " + "\r\n ctrlBuf: %p" + "\r\n ctrlBufLen: %lu" + "\r\n eCtrl: %T" + "\r\n", descP->sock, + ctrlBuf, (unsigned long) ctrlBufLen, eCtrl) ); + + /* Decode the ctrl and initiate that part of the msghdr. + */ + if (ctrlBuf != NULL) { + if (! decode_cmsghdrs(env, descP, + eCtrl, + ctrlBuf, ctrlBufLen, &ctrlBufUsed)) { + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendmsg {%d} -> invalid ctrl\r\n", + descP->sock) ); + res = esock_make_invalid(env, esock_atom_ctrl); + goto done_free_iovec; + } + } else { + ctrlBufUsed = 0; + } + msgHdr.msg_control = ctrlBuf; + msgHdr.msg_controllen = ctrlBufUsed; + + /* The msg_flags field is not used when sending, + * but zero it just in case */ + msgHdr.msg_flags = 0; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + /* And now, try to send the message */ + sendmsg_result = sock_sendmsg(descP->sock, &msgHdr, flags); + + res = send_check_result(env, descP, sendmsg_result, dataSize, + (! enif_is_empty_list(env, tail)), + sockRef, sendRef); + + done_free_iovec: + FREE_IOVEC( iovec ); + if (ctrlBuf != NULL) FREE(ctrlBuf); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_sendmsg {%d} -> done" + "\r\n %T" + "\r\n", descP->sock, res) ); + + return res; + +} + + +/* ======================================================================== + * Start a sendfile() operation + */ +extern +ERL_NIF_TERM essio_sendfile_start(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count, + ERL_NIF_TERM fRef) +{ +#if defined(HAVE_SENDFILE) + ERL_NIF_TERM writerCheck; + ssize_t res; + int err; + + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile_start {%d} -> entry with" + "\r\n sockRef: %T" + "\r\n sendRef: %T" + "\r\n fRef: %T" + "\r\n offset: %lu" + "\r\n count: %lu" + "\r\n", + descP->sock, sockRef, sendRef, + fRef, (unsigned long) offset, (unsigned long) count) ); + + if (! IS_OPEN(descP->writeState)) { + return esock_make_error_closed(env); + } + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->connectorP != NULL) { + return esock_make_error_invalid(env, esock_atom_state); + } + + /* Ensure that we either have no current writer or we are it, + * or enqueue this process if there is a current writer + */ + if (! send_check_writer(env, descP, sendRef, &writerCheck)) { + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile_start {%d} -> writer check failed: " + "\r\n %T\r\n", descP->sock, writerCheck) ); + + /* Returns 'select' if current process got enqueued, + * or exception invalid state if current process already + * was enqueued + */ + return writerCheck; + } + + if (descP->sendfileHandle != INVALID_HANDLE) + return esock_make_error_invalid(env, esock_atom_state); + + /* Get a dup:ed file handle from prim_file_nif + * through a NIF dyncall + */ + { + struct prim_file_nif_dyncall_dup dc_dup; + + dc_dup.op = prim_file_nif_dyncall_dup; + dc_dup.result = EINVAL; // should not be needed + + /* Request the handle */ + if (enif_dynamic_resource_call(env, + esock_atom_prim_file, + esock_atom_efile, + fRef, + &dc_dup) + != 0) { + return + essio_sendfile_error(env, descP, sockRef, + MKT2(env, + esock_atom_invalid, + esock_atom_efile)); + } + if (dc_dup.result != 0) { + return + essio_sendfile_errno(env, descP, sockRef, dc_dup.result); + } + descP->sendfileHandle = dc_dup.handle; + } + + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile_start(%T) {%d} -> sendRef: %T" + "\r\n sendfileHandle: %d" + "\r\n", + sockRef, descP->sock, sendRef, + descP->sendfileHandle) ); + + if (descP->sendfileCountersP == NULL) { + descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); + *descP->sendfileCountersP = initESockSendfileCounters; + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile_tries, + &descP->sendfileCountersP->tries, 1); + descP->sendfileCountersP->maxCnt = 0; + + res = essio_sendfile(env, descP, sockRef, offset, &count, &err); + + if (res < 0) { // Terminal error + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return essio_sendfile_errno(env, descP, sockRef, err); + + } else if (res > 0) { // Retry by select + + if (descP->currentWriterP == NULL) { + int mon_res; + + /* Register writer as current */ + ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); + mon_res = + MONP("sendfile-start -> current writer", + env, descP, + &descP->currentWriter.pid, + &descP->currentWriter.mon); + ESOCK_ASSERT( mon_res >= 0 ); + + if (mon_res > 0) { + /* Caller died already, can happen for dirty NIFs */ + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return essio_sendfile_error(env, descP, sockRef, + MKT2(env, + esock_atom_invalid, + esock_atom_not_owner)); + } + ESOCK_ASSERT( descP->currentWriter.env == NULL ); + descP->currentWriter.env = esock_alloc_env("current-writer"); + descP->currentWriter.ref = + CP_TERM(descP->currentWriter.env, sendRef); + descP->currentWriterP = &descP->currentWriter; + } + // else current writer is already registered by esock_requestor_pop() + + return essio_sendfile_select(env, descP, sockRef, sendRef, count); + + } else { // res == 0: Done + return essio_sendfile_ok(env, descP, sockRef, count); + } +#else + VOID(env); + VOID(descP); + VOID(sockRef); + VOID(sendRef); + VOID(offset); + VOID(count); + VOID(fRef); + return enif_raise_exception(env, MKA(env, "notsup")); +#endif +} + + +/* ======================================================================== + * Continue an ongoing sendfile operation + */ + +extern +ERL_NIF_TERM essio_sendfile_cont(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + off_t offset, + size_t count) +{ +#if defined(HAVE_SENDFILE) + ErlNifPid caller; + ssize_t res; + int err; + + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile_cont {%d} -> entry" + "\r\n sockRef: %T" + "\r\n sendRef: %T" + "\r\n", descP->sock, sockRef, sendRef) ); + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write uses the same select flag + * so they can not be simultaneous + */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Verify that this process has a sendfile operation in progress */ + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + if ((descP->currentWriterP == NULL) || + (descP->sendfileHandle == INVALID_HANDLE) || + (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0)) { + // + return esock_raise_invalid(env, esock_atom_state); + } + + res = essio_sendfile(env, descP, sockRef, offset, &count, &err); + + if (res < 0) { // Terminal error + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return essio_sendfile_errno(env, descP, sockRef, err); + + } else if (res > 0) { // Retry by select + + /* Overwrite current writer registration */ + enif_clear_env(descP->currentWriter.env); + descP->currentWriter.ref = + CP_TERM(descP->currentWriter.env, sendRef); + + return essio_sendfile_select(env, descP, sockRef, sendRef, count); + + } else { // res == 0: Done + return essio_sendfile_ok(env, descP, sockRef, count); + } +#else + VOID(env); + VOID(descP); + VOID(sockRef); + VOID(sendRef); + VOID(offset); + VOID(count); + return enif_raise_exception(env, MKA(env, "notsup")); +#endif +} + + +/* ======================================================================== + * Deferred close of the dup:ed file descriptor + */ + +extern +ERL_NIF_TERM essio_sendfile_deferred_close(ErlNifEnv* env, + ESockDescriptor* descP) +{ +#if defined(HAVE_SENDFILE) + if (descP->sendfileHandle == INVALID_HANDLE) + return esock_make_error_invalid(env, esock_atom_state); + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return esock_atom_ok; +#else + VOID(env); + VOID(descP); + return enif_raise_exception(env, MKA(env, "notsup")); +#endif +} + + + +/* ======================================================================== + * The (read) buffer handling should be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throwing it away... + */ +extern +ERL_NIF_TERM essio_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags) +{ + ssize_t read; + ErlNifBinary buf; + ERL_NIF_TERM readerCheck; + int save_errno; + size_t bufSz = (len != 0 ? len : descP->rBufSz); + + SSDBG( descP, ("UNIX-ESSIO", "essio_recv {%d} -> entry with" + "\r\n count,size: (%ld:%u:%lu)" + "\r\n", descP->sock, + (long) len, descP->rNumCnt, (unsigned long) bufSz) ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read uses the same select flag + * so they can not be simultaneous + */ + if (descP->currentAcceptorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that we either have no current reader or that we are it, + * or enqueue this process if there is a current reader */ + if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { + SSDBG( descP, + ("UNIX-ESSIO", "essio_recv {%d} -> reader check failed: " + "\r\n %T" + "\r\n", descP->sock, readerCheck) ); + return readerCheck; + } + + /* Allocate a buffer: + * Either as much as we want to read or (if zero (0)) use the "default" + * size (what has been configured). + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); + + // If it fails (read = -1), we need errno... + SSDBG( descP, ("UNIX-ESSIO", "essio_recv {%d} -> try read (%lu)\r\n", + descP->sock, (unsigned long) buf.size) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + read = sock_recv(descP->sock, buf.data, buf.size, flags); + if (ESOCK_IS_ERROR(read)) { + save_errno = sock_errno(); + } else { + save_errno = 0; // The value does not actually matter in this case + } + + SSDBG( descP, ("UNIX-ESSIO", + "essio_recv {%d} -> read: %ld (%d)\r\n", + descP->sock, (long) read, save_errno) ); + + return recv_check_result(env, descP, read, len, save_errno, + &buf, sockRef, recvRef); +} + + +/* *** recv_check_result *** + * + * Process the result of a call to recv. + */ +static +ERL_NIF_TERM recv_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + int saveErrno, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", "recv_check_result(%T) {%d} -> entry with" + "\r\n read: %ld" + "\r\n toRead: %ld" + "\r\n saveErrno: %d" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, + (long) read, (long) toRead, saveErrno, recvRef) ); + + + /* + * + * We need to handle read = 0 for other type(s) (DGRAM) when + * its actually valid to read 0 bytes. + * + * + */ + + if ((read == 0) && (descP->type == SOCK_STREAM)) { + ERL_NIF_TERM reason = esock_atom_closed; + res = esock_make_error(env, reason); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + /* + * When a stream socket peer has performed an orderly shutdown, + * the return value will be 0 (the traditional "end-of-file" return). + * + * *We* do never actually try to read 0 bytes! + * + * We must also notify any waiting readers! + */ + + recv_error_current_reader(env, descP, sockRef, reason); + + FREE_BIN(bufP); + + } else { + + /* There is a special case: If the provided 'to read' value is + * zero (0) (only for type =/= stream). + * That means that we read as much as we can, using the default + * read buffer size. + */ + + if (bufP->size == read) { + + /* +++ We filled the buffer +++ */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_result(%T) {%d} -> [%lu] filled the buffer\r\n", + sockRef, descP->sock, (unsigned long) bufP->size) ); + + res = recv_check_full(env, descP, read, toRead, bufP, + sockRef, recvRef); + + } else if (read < 0) { + + /* +++ Error handling +++ */ + + res = recv_check_fail(env, descP, saveErrno, bufP, NULL, + sockRef, recvRef); + + } else { + + /* +++ We did not fill the buffer +++ */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_result(%T) {%d} -> [%lu] " + "did not fill the buffer (%ld)\r\n", + sockRef, descP->sock, (unsigned long) bufP->size, + (long) read) ); + + res = recv_check_partial(env, descP, read, toRead, bufP, + sockRef, recvRef); + } + } + + return res; +} + + + +/* ======================================================================== + * The (read) buffer handling *must* be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throwing it away... + */ +extern +ERL_NIF_TERM essio_recvfrom(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags) +{ + ESockAddress fromAddr; + SOCKLEN_T addrLen; + ssize_t read; + int save_errno; + ErlNifBinary buf; + ERL_NIF_TERM readerCheck; + size_t bufSz = (len != 0 ? len : descP->rBufSz); + + SSDBG( descP, ("UNIX-ESSIO", "essio_recvfrom {%d} -> entry with" + "\r\n bufSz: %d" + "\r\n", descP->sock, bufSz) ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read uses the same select flag + * so they can not be simultaneous + */ + if (descP->currentAcceptorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that we either have no current reader or that we are it, + * or enqueue this process if there is a current reader */ + if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { + SSDBG( descP, + ("UNIX-ESSIO", "essio_recv {%d} -> reader check failed: " + "\r\n %T\r\n", descP->sock, readerCheck) ); + return readerCheck; + } + + /* Allocate a buffer: + * Either as much as we want to read or (if zero (0)) use the "default" + * size (what has been configured). + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &buf) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + addrLen = sizeof(fromAddr); + sys_memzero((char*) &fromAddr, addrLen); + + read = sock_recvfrom(descP->sock, buf.data, buf.size, flags, + &fromAddr.sa, &addrLen); + if (ESOCK_IS_ERROR(read)) + save_errno = sock_errno(); + else + save_errno = 0; // The value does not actually matter in this case + + return recvfrom_check_result(env, descP, read, save_errno, + &buf, &fromAddr, addrLen, + sockRef, recvRef); +} + + +/* The recvfrom function delivers one (1) message. If our buffer + * is too small, the message will be truncated. So, regardless + * if we filled the buffer or not, we have got what we are going + * to get regarding this message. + */ + +static +ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + int saveErrno, + ErlNifBinary* bufP, + ESockAddress* fromAddrP, + SOCKLEN_T fromAddrLen, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM data, res; + + SSDBG( descP, + ("UNIX-ESSIO", "recvfrom_check_result(%T) {%d} -> entry with" + "\r\n read: %ld" + "\r\n saveErrno: %d" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, + (long) read, saveErrno, recvRef) ); + + /* + * + * We need to handle read = 0 for non_stream socket type(s) when + * its actually valid to read 0 bytes. + * + * + */ + + if ((read == 0) && (descP->type == SOCK_STREAM)) { + + /* + * When a stream socket peer has performed an orderly shutdown, + * the return value will be 0 (the traditional "end-of-file" return). + * + * *We* do never actually try to read 0 bytes! + */ + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + FREE_BIN(bufP); + + return esock_make_error_closed(env); + } + + if (read < 0) { + + /* +++ Error handling +++ */ + + res = recv_check_fail(env, descP, saveErrno, bufP, NULL, + sockRef, recvRef); + + } else { + + /* +++ We successfully got a message - time to encode the address +++ */ + + ERL_NIF_TERM eSockAddr; + + esock_encode_sockaddr(env, + fromAddrP, fromAddrLen, + &eSockAddr); + + if (read == bufP->size) { + + data = MKBIN(env, bufP); + + } else { + + /* +++ We got a chunk of data but +++ + * +++ since we did not fill the +++ + * +++ buffer, we must split it +++ + * +++ into a sub-binary. +++ + */ + + data = MKBIN(env, bufP); + data = MKSBIN(env, data, 0, read); + } + + ESOCK_CNT_INC(env, descP, sockRef, esock_atom_read_pkg, + &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, esock_atom_read_byte, + &descP->readByteCnt, read); + + recv_update_current_reader(env, descP, sockRef); + + res = esock_make_ok2(env, MKT2(env, eSockAddr, data)); + + } + + return res; + +} + + + +/* ======================================================================== + * The (read) buffer handling *must* be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throwing it away... + */ +extern +ERL_NIF_TERM essio_recvmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t bufLen, + ssize_t ctrlLen, + int flags) +{ + SOCKLEN_T addrLen; + ssize_t read; + int save_errno; + size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz); + size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz); + struct msghdr msgHdr; + SysIOVec iov[1]; // Shall we always use 1? + ErlNifBinary data[1]; // Shall we always use 1? + ErlNifBinary ctrl; + ERL_NIF_TERM readerCheck; + ESockAddress addr; + + SSDBG( descP, ("UNIX-ESSIO", "essio_recvmsg {%d} -> entry with" + "\r\n bufSz: %lu (%ld)" + "\r\n ctrlSz: %ld (%ld)" + "\r\n", descP->sock, + (unsigned long) bufSz, (long) bufLen, + (unsigned long) ctrlSz, (long) ctrlLen) ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read uses the same select flag + * so they can not be simultaneous + */ + if (descP->currentAcceptorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that we either have no current reader or that we are it, + * or enqueue this process if there is a current reader */ + if (! recv_check_reader(env, descP, recvRef, &readerCheck)) { + SSDBG( descP, + ("UNIX-ESSIO", "essio_recvmsg {%d} -> reader check failed: " + "\r\n %T\r\n", descP->sock, readerCheck) ); + return readerCheck; + } + + /* Allocate the (msg) data buffer: + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &data[0]) ); + + /* Allocate the ctrl (buffer): + */ + ESOCK_ASSERT( ALLOC_BIN(ctrlSz, &ctrl) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + addrLen = sizeof(addr); + sys_memzero((char*) &addr, addrLen); + sys_memzero((char*) &msgHdr, sizeof(msgHdr)); + + iov[0].iov_base = data[0].data; + iov[0].iov_len = data[0].size; + + msgHdr.msg_name = &addr; + msgHdr.msg_namelen = addrLen; + msgHdr.msg_iov = iov; + msgHdr.msg_iovlen = 1; // Should use a constant or calculate... + msgHdr.msg_control = ctrl.data; + msgHdr.msg_controllen = ctrl.size; + + read = sock_recvmsg(descP->sock, &msgHdr, flags); + if (ESOCK_IS_ERROR(read)) + save_errno = sock_errno(); + else + save_errno = 0; // The value does not actually matter in this case + + return recvmsg_check_result(env, descP, read, save_errno, + &msgHdr, + data, // Needed for iov encode + &ctrl, // Needed for ctrl header encode + sockRef, recvRef); +} + + +/* *** recvmsg_check_result *** + * + * The recvmsg function delivers one (1) message. If our buffer + * is to small, the message will be truncated. So, regardless + * if we filled the buffer or not, we have got what we are going + * to get regarding this message. + */ +static +ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + int saveErrno, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", "recvmsg_check_result(%T) {%d} -> entry with" + "\r\n read: %ld" + "\r\n saveErrno: %d" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, + (long) read, saveErrno, recvRef) ); + + + /* + * + * We need to handle read = 0 for non_stream socket type(s) when + * its actually valid to read 0 bytes. + * + * + */ + + if ((read == 0) && (descP->type == SOCK_STREAM)) { + + /* + * When a stream socket peer has performed an orderly shutdown, + * the return value will be 0 (the traditional "end-of-file" return). + * + * *We* do never actually try to read 0 bytes! + */ + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + FREE_BIN(dataBufP); FREE_BIN(ctrlBufP); + + return esock_make_error_closed(env); + } + + + if (read < 0) { + + /* +++ Error handling +++ */ + + res = recv_check_fail(env, descP, saveErrno, dataBufP, ctrlBufP, + sockRef, recvRef); + + } else { + + /* +++ We successfully got a message - time to encode it +++ */ + + res = recvmsg_check_msg(env, descP, read, msgHdrP, + dataBufP, ctrlBufP, sockRef); + + } + + return res; + +} + + +/* *** recvmsg_check_msg *** + * + * We successfully read one message. Time to process. + */ +static +ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM eMsg; + + /* + * + * + * The return value of recvmsg is the *total* number of bytes + * that where successfully read. This data has been put into + * the *IO vector*. + * + * + */ + + encode_msg(env, descP, + read, msgHdrP, dataBufP, ctrlBufP, + &eMsg); + + SSDBG( descP, + ("UNIX-ESSIO", "recvmsg_check_result(%T) {%d} -> ok\r\n", + sockRef, descP->sock) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, esock_atom_read_byte, + &descP->readByteCnt, read); + + recv_update_current_reader(env, descP, sockRef); + + return esock_make_ok2(env, eMsg); +} + + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM essio_close(ErlNifEnv* env, + ESockDescriptor* descP) +{ + if (! IS_OPEN(descP->readState)) { + /* A bit of cheeting; maybe not closed yet - do we need a queue? */ + return esock_make_error_closed(env); + } + + /* Store the PID of the caller, + * since we need to inform it when we + * (that is, the stop callback function) + * completes. + */ + ESOCK_ASSERT( enif_self(env, &descP->closerPid) != NULL ); + + /* If the caller is not the owner; monitor the caller, + * since we should complete this operation even if the caller dies + * (for whatever reason). + */ + if (COMPARE_PIDS(&descP->closerPid, &descP->ctrlPid) != 0) { + + ESOCK_ASSERT( MONP("essio_close-check -> closer", + env, descP, + &descP->closerPid, + &descP->closerMon) == 0 ); + } + + /* Prepare for closing the socket */ + descP->readState |= ESOCK_STATE_CLOSING; + descP->writeState |= ESOCK_STATE_CLOSING; + if (do_stop(env, descP)) { + // stop() has been scheduled - wait for it + SSDBG( descP, + ("UNIX-ESSIO", "essio_close {%d} -> stop was scheduled\r\n", + descP->sock) ); + + // Create closeRef for the close msg that esock_stop() will send + descP->closeEnv = esock_alloc_env("esock_close_do - close-env"); + descP->closeRef = MKREF(descP->closeEnv); + + return esock_make_ok2(env, CP_TERM(env, descP->closeRef)); + } else { + // The socket may be closed - tell caller to finalize + SSDBG( descP, + ("UNIX-ESSIO", + "essio_close {%d} -> stop was called\r\n", + descP->sock) ); + + return esock_atom_ok; + } +} + + + +/* Prepare for close - return whether stop is scheduled or not + */ +static +BOOLEAN_T do_stop(ErlNifEnv* env, + ESockDescriptor* descP) +{ + BOOLEAN_T ret; + int sres; + ERL_NIF_TERM sockRef; + + sockRef = enif_make_resource(env, descP); + + if (IS_SELECTED(descP)) { + ESOCK_ASSERT( (sres = esock_select_stop(env, + (ErlNifEvent) descP->sock, + descP)) + >= 0 ); + if ((sres & ERL_NIF_SELECT_STOP_CALLED) != 0) { + /* The socket is no longer known by the select machinery + * - it may be closed + */ + ret = FALSE; + } else { + ESOCK_ASSERT( (sres & ERL_NIF_SELECT_STOP_SCHEDULED) != 0 ); + /* esock_stop() is scheduled + * - socket may be removed by esock_stop() or later + */ + ret = TRUE; + } + } else { + sres = 0; + /* The socket has never been used in the select machinery + * - it may be closed + */ + ret = FALSE; + } + + /* +++++++ Current and waiting Writers +++++++ */ + + if (descP->currentWriterP != NULL) { + + /* We have a current Writer; was it deselected? + */ + + if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { + + /* The current Writer will not get a select message + * - send it an abort message + */ + + esock_stop_handle_current(env, + "writer", + descP, sockRef, &descP->currentWriter); + } + + /* Inform the waiting Writers (in the same way) */ + + SSDBG( descP, + ("UNIX-ESSIO", + "do_stop {%d} -> handle waiting writer(s)\r\n", + descP->sock) ); + + esock_inform_waiting_procs(env, "writer", + descP, sockRef, &descP->writersQ, + esock_atom_closed); + + descP->currentWriterP = NULL; + } + + /* +++++++ Connector +++++++ + * Note that there should not be Writers and a Connector + * at the same time so the check for if the + * current Writer/Connecter was deselected is only correct + * under that assumption + */ + + if (descP->connectorP != NULL) { + + /* We have a Connector; was it deselected? + */ + + if (sres & ERL_NIF_SELECT_WRITE_CANCELLED) { + + /* The Connector will not get a select message + * - send it an abort message + */ + + esock_stop_handle_current(env, + "connector", + descP, sockRef, &descP->connector); + } + + descP->connectorP = NULL; + } + + /* +++++++ Current and waiting Readers +++++++ */ + + if (descP->currentReaderP != NULL) { + + /* We have a current Reader; was it deselected? + */ + + if (sres & ERL_NIF_SELECT_READ_CANCELLED) { + + /* The current Reader will not get a select message + * - send it an abort message + */ + + esock_stop_handle_current(env, + "reader", + descP, sockRef, &descP->currentReader); + } + + /* Inform the Readers (in the same way) */ + + SSDBG( descP, + ("UNIX-ESSIO", + "do_stop {%d} -> handle waiting reader(s)\r\n", + descP->sock) ); + + esock_inform_waiting_procs(env, "writer", + descP, sockRef, &descP->readersQ, + esock_atom_closed); + + descP->currentReaderP = NULL; + } + + /* +++++++ Current and waiting Acceptors +++++++ + * + * Note that there should not be Readers and Acceptors + * at the same time so the check for if the + * current Reader/Acceptor was deselected is only correct + * under that assumption + */ + + if (descP->currentAcceptorP != NULL) { + + /* We have a current Acceptor; was it deselected? + */ + + if (sres & ERL_NIF_SELECT_READ_CANCELLED) { + + /* The current Acceptor will not get a select message + * - send it an abort message + */ + + esock_stop_handle_current(env, + "acceptor", + descP, sockRef, &descP->currentAcceptor); + } + + /* Inform the waiting Acceptor (in the same way) */ + + SSDBG( descP, + ("UNIX-ESSIO", + "do_stop {%d} -> handle waiting acceptors(s)\r\n", + descP->sock) ); + + esock_inform_waiting_procs(env, "acceptor", + descP, sockRef, &descP->acceptorsQ, + esock_atom_closed); + + descP->currentAcceptorP = NULL; + } + + return ret; +} + + + +/* ======================================================================== + * Perform the final step in the socket close. + */ +extern +ERL_NIF_TERM essio_fin_close(ErlNifEnv* env, + ESockDescriptor* descP) +{ + int err; + ErlNifPid self; +#ifdef HAVE_SENDFILE + HANDLE sendfileHandle; +#endif + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (IS_CLOSED(descP->readState)) + return esock_make_error_closed(env); + + if (! IS_CLOSING(descP->readState)) { + // esock_close() has not been called + return esock_raise_invalid(env, esock_atom_state); + } + + if (IS_SELECTED(descP) && (descP->closeEnv != NULL)) { + // esock_stop() is scheduled but has not been called + return esock_raise_invalid(env, esock_atom_state); + } + + if (COMPARE_PIDS(&descP->closerPid, &self) != 0) { + // This process is not the closer + return esock_raise_invalid(env, esock_atom_state); + } + + // Close the socket + + /* Stop monitoring the closer. + * Demonitoring may fail since this is a dirty NIF + * - the caller may have died already. + */ + enif_set_pid_undefined(&descP->closerPid); + if (descP->closerMon.isActive) { + (void) DEMONP("essio_fin_close -> closer", + env, descP, &descP->closerMon); + } + + /* Stop monitoring the owner */ + enif_set_pid_undefined(&descP->ctrlPid); + (void) DEMONP("essio_fin_close -> ctrl", + env, descP, &descP->ctrlMon); + /* Not impossible to still get a esock_down() call from a + * just triggered owner monitor down + */ + +#ifdef HAVE_SENDFILE + sendfileHandle = descP->sendfileHandle; + descP->sendfileHandle = INVALID_HANDLE; +#endif + + /* This nif-function is executed in a dirty scheduler just so + * that it can "hang" (with minimum effect on the VM) while the + * kernel writes our buffers. IF we have set the linger option + * for this ({true, integer() > 0}). For this to work we must + * be blocking... + */ + SET_BLOCKING(descP->sock); + err = esock_close_socket(env, descP, TRUE); + +#ifdef HAVE_SENDFILE + if (sendfileHandle != INVALID_HANDLE) { + (void) close(descP->sendfileHandle); + } +#endif + + if (err != 0) { + if (err == ERRNO_BLOCK) { + /* Not all data in the buffers where sent, + * make sure the caller gets this. + */ + return esock_make_error(env, esock_atom_timeout); + } else { + return esock_make_error_errno(env, err); + } + } + + return esock_atom_ok; +} + + +/* ======================================================================== + * *** essio_shutdown should go here - if we need one *** + */ + + +/* ======================================================================== + * *** essio_sockname should go here - if we need one *** + */ + + +/* ======================================================================== + * *** essio_peername should go here - if we need one *** + */ + + +/* ======================================================================== + * Cancel a connect request. + */ + +extern +ERL_NIF_TERM essio_cancel_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + ErlNifPid self; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_connect {%d} -> entry with" + "\r\n writeState: 0x%X" + "\r\n opRef: %T" + "\r\n", + descP->sock, descP->writeState, opRef) ); + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (! IS_OPEN(descP->writeState)) { + + res = esock_make_error_closed(env); + + } else if ((descP->connectorP == NULL) || + (COMPARE_PIDS(&self, &descP->connector.pid) != 0) || + (COMPARE(opRef, descP->connector.ref) != 0)) { + + res = esock_make_error(env, esock_atom_not_found); + + } else { + + res = esock_cancel_write_select(env, descP, opRef); + esock_requestor_release("esock_cancel_connect", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~ESOCK_STATE_CONNECTING; + } + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_connect {%d} -> done when" + "\r\n res: %T" + "\r\n", + descP->sock, descP->writeState, + opRef, res) ); + + return res; +} + + + +/* ======================================================================== + * Cancel accept request + * + * We have two different cases: + * *) Its the current acceptor + * Cancel the select! + * We need to activate one of the waiting acceptors. + * *) Its one of the acceptors ("waiting") in the queue + * Simply remove the acceptor from the queue. + * + */ +extern +ERL_NIF_TERM essio_cancel_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_accept(%T), {%d,0x%X} ->" + "\r\n opRef: %T" + "\r\n %s" + "\r\n", + sockRef, descP->sock, descP->readState, + opRef, + ((descP->currentAcceptorP == NULL) + ? "without acceptor" : "with acceptor")) ); + + if (! IS_OPEN(descP->readState)) { + + res = esock_make_error_closed(env); + + } else if (descP->currentAcceptorP == NULL) { + + res = esock_atom_not_found; + + } else { + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (COMPARE_PIDS(&self, &descP->currentAcceptor.pid) == 0) { + if (COMPARE(opRef, descP->currentAcceptor.ref) == 0) + res = essio_cancel_accept_current(env, descP, sockRef); + else + res = esock_atom_not_found; + } else { + res = essio_cancel_accept_waiting(env, descP, opRef, &self); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_cancel_accept(%T) -> done with result:" + "\r\n %T" + "\r\n", sockRef, res) ); + + return res; +} + + +/* The current acceptor process has an ongoing select we first must + * cancel. Then we must re-activate the "first" (the first + * in the acceptor queue). + */ +static +ERL_NIF_TERM essio_cancel_accept_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM res; + + ESOCK_ASSERT( DEMONP("essio_cancel_accept_current -> current acceptor", + env, descP, &descP->currentAcceptor.mon) == 0); + MON_INIT(&descP->currentAcceptor.mon); + res = esock_cancel_read_select(env, descP, descP->currentAcceptor.ref); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_accept_current(%T) {%d} -> cancel res: %T" + "\r\n", sockRef, descP->sock, res) ); + + if (!esock_activate_next_acceptor(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_accept_current(%T) {%d} -> " + "no more acceptors\r\n", + sockRef, descP->sock) ); + + descP->readState &= ~ESOCK_STATE_ACCEPTING; + + descP->currentAcceptorP = NULL; + } + + return res; +} + + +/* These processes have not performed a select, so we can simply + * remove them from the acceptor queue. + */ +static +ERL_NIF_TERM essio_cancel_accept_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP) +{ + /* unqueue request from (acceptor) queue */ + + if (esock_acceptor_unqueue(env, descP, &opRef, selfP)) { + return esock_atom_ok; + } else { + return esock_atom_not_found; + } +} + + + +/* ======================================================================== + * Cancel send request + * + * Cancel a send operation. + * Its either the current writer or one of the waiting writers. + */ + +extern +ERL_NIF_TERM essio_cancel_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_send(%T), {%d,0x%X} -> entry with" + "\r\n opRef: %T" + "\r\n %s" + "\r\n", + sockRef, descP->sock, descP->writeState, + opRef, + ((descP->currentWriterP == NULL) + ? "without writer" : "with writer")) ); + + if (! IS_OPEN(descP->writeState)) { + + res = esock_make_error_closed(env); + + } else if (descP->currentWriterP == NULL) { + + res = esock_atom_not_found; + + } else { + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (COMPARE_PIDS(&self, &descP->currentWriter.pid) == 0) { + if (COMPARE(opRef, descP->currentWriter.ref) == 0) + res = essio_cancel_send_current(env, descP, sockRef); + else + res = esock_atom_not_found; + } else { + res = essio_cancel_send_waiting(env, descP, opRef, &self); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_cancel_send(%T) {%d} -> done with result:" + "\r\n %T" + "\r\n", sockRef, descP->sock, res) ); + + return res; +} + + + +/* The current writer process has an ongoing select we first must + * cancel. Then we must re-activate the "first" (the first + * in the writer queue). + */ +static +ERL_NIF_TERM essio_cancel_send_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM res; + + ESOCK_ASSERT( DEMONP("essio_cancel_send_current -> current writer", + env, descP, &descP->currentWriter.mon) == 0); + res = esock_cancel_write_select(env, descP, descP->currentWriter.ref); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_cancel_send_current(%T) {%d} -> cancel res: %T" + "\r\n", sockRef, descP->sock, res) ); + + if (!esock_activate_next_writer(env, descP, sockRef)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_send_current(%T) {%d} -> no more writers" + "\r\n", sockRef, descP->sock) ); + + descP->currentWriterP = NULL; + } + + return res; +} + + + +/* These processes have not performed a select, so we can simply + * remove them from the writer queue. + */ +static +ERL_NIF_TERM essio_cancel_send_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP) +{ + /* unqueue request from (writer) queue */ + + if (esock_writer_unqueue(env, descP, &opRef, selfP)) { + return esock_atom_ok; + } else { + return esock_atom_not_found; + } +} + + + +/* ======================================================================== + * Cancel receive request + * + * Cancel a read operation. + * Its either the current reader or one of the waiting readers. + */ +extern +ERL_NIF_TERM essio_cancel_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_recv(%T), {%d,0x%X} -> entry with" + "\r\n opRef: %T" + "\r\n %s" + "\r\n", + sockRef, descP->sock, descP->readState, + opRef, + ((descP->currentReaderP == NULL) + ? "without reader" : "with reader")) ); + + if (! IS_OPEN(descP->readState)) { + + res = esock_make_error_closed(env); + + } else if (descP->currentReaderP == NULL) { + + res = esock_atom_not_found; + + } else { + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (COMPARE_PIDS(&self, &descP->currentReader.pid) == 0) { + if (COMPARE(opRef, descP->currentReader.ref) == 0) + res = essio_cancel_recv_current(env, descP, sockRef); + else + res = esock_atom_not_found; + } else { + res = essio_cancel_recv_waiting(env, descP, opRef, &self); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_cancel_recv(%T) {%d} -> done with result:" + "\r\n %T" + "\r\n", sockRef, descP->sock, res) ); + + + return res; + +} + + +/* The current reader process has an ongoing select we first must + * cancel. Then we must re-activate the "first" (the first + * in the reader queue). + */ +static +ERL_NIF_TERM essio_cancel_recv_current(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM res; + + ESOCK_ASSERT( DEMONP("essio_cancel_recv_current -> current reader", + env, descP, &descP->currentReader.mon) == 0); + res = esock_cancel_read_select(env, descP, descP->currentReader.ref); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_cancel_recv_current(%T) {%d} -> cancel res: %T" + "\r\n", sockRef, descP->sock, res) ); + + if (!esock_activate_next_reader(env, descP, sockRef)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_cancel_recv_current(%T) {%d} -> no more readers" + "\r\n", sockRef, descP->sock) ); + + descP->currentReaderP = NULL; + } + + return res; +} + + +/* These processes have not performed a select, so we can simply + * remove them from the reader queue. + */ +static +ERL_NIF_TERM essio_cancel_recv_waiting(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef, + const ErlNifPid* selfP) +{ + /* unqueue request from (reader) queue */ + + if (esock_reader_unqueue(env, descP, &opRef, selfP)) { + return esock_atom_ok; + } else { + return esock_atom_not_found; + } +} + + + +/* ======================================================================== + * IOCTL with two args (socket and request "key") + * + */ +extern +ERL_NIF_TERM essio_ioctl2(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req) +{ + switch (req) { + +#if defined(SIOCGIFCONF) + case SIOCGIFCONF: + return essio_ioctl_gifconf(env, descP); + break; +#endif + +#if defined(FIONREAD) + case FIONREAD: + return essio_ioctl_fionread(env, descP); + break; +#endif + +#if defined(FIONWRITE) + case FIONWRITE: + return essio_ioctl_fionwrite(env, descP); + break; +#endif + +#if defined(FIONSPACE) + case FIONSPACE: + return essio_ioctl_fionspace(env, descP); + break; +#endif + +#if defined(SIOCATMARK) + case SIOCATMARK: + return essio_ioctl_siocatmark(env, descP); + break; +#endif + + default: + return esock_make_error(env, esock_atom_enotsup); + break; + } + +} + + + +/* ======================================================================== + * IOCTL with three args (socket, request "key" and one argument) + * + * The type and value of 'arg' depend on the request, + * which we have not yet "analyzed". + * + * Request arg arg type + * ------- ------- -------- + * gifname ifindex integer + * gifindex name string + * gifflags name string + * gifaddr name string + * gifdstaddr name string + * gifbdraddr name string + * gifnetmask name string + * gifmtu name string + * gifhwaddr name string + * gifmap name string + * giftxqlen name string + */ +extern +ERL_NIF_TERM essio_ioctl3(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg) +{ + /* This for *get* requests */ + + switch (req) { + +#if defined(SIOCGIFNAME) + case SIOCGIFNAME: + return essio_ioctl_gifname(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFINDEX) + case SIOCGIFINDEX: + return essio_ioctl_gifindex(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFFLAGS) + case SIOCGIFFLAGS: + return essio_ioctl_gifflags(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFADDR) + case SIOCGIFADDR: + return essio_ioctl_gifaddr(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFDSTADDR) + case SIOCGIFDSTADDR: + return essio_ioctl_gifdstaddr(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFBRDADDR) + case SIOCGIFBRDADDR: + return essio_ioctl_gifbrdaddr(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFNETMASK) + case SIOCGIFNETMASK: + return essio_ioctl_gifnetmask(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFMTU) + case SIOCGIFMTU: + return essio_ioctl_gifmtu(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) + case SIOCGIFHWADDR: + return essio_ioctl_gifhwaddr(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) + case SIOCGIFMAP: + return essio_ioctl_gifmap(env, descP, arg); + break; +#endif + +#if defined(SIOCGIFTXQLEN) + case SIOCGIFTXQLEN: + return essio_ioctl_giftxqlen(env, descP, arg); + break; +#endif + + default: + return esock_make_error(env, esock_atom_enotsup); + break; + } + +} + + + +/* ======================================================================== + * IOCTL with four args (socket, request "key" and two arguments) + * + * The type and value of arg(s) depend on the request, + * which we have not yet "analyzed". + * + * Request arg1 arg1 type arg2 arg2 type + * ------- ------- --------- ------ --------- + * sifflags name string Flags #{IntFlag := boolean()} + * IntFlag is the native flag + * sifaddr name string Addr sockaddr() + * sifdstaddr name string DstAddr sockaddr() + * sifbrdaddr name string BrdAddr sockaddr() + * sifnetmask name string NetMask sockaddr() + * gifmtu name string MTU integer() + * sifhwaddr name string HwAddr sockaddr() + * giftxqlen name string Len integer() + */ +extern +ERL_NIF_TERM essio_ioctl4(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM ename, + ERL_NIF_TERM eval) +{ + + switch (req) { + +#if defined(SIOCSIFFLAGS) + case SIOCSIFFLAGS: + return essio_ioctl_sifflags(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFADDR) + case SIOCSIFADDR: + return essio_ioctl_sifaddr(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFDSTADDR) + case SIOCSIFDSTADDR: + return essio_ioctl_sifdstaddr(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFBRDADDR) + case SIOCSIFBRDADDR: + return essio_ioctl_sifbrdaddr(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFNETMASK) + case SIOCSIFNETMASK: + return essio_ioctl_sifnetmask(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFMTU) + case SIOCSIFMTU: + return essio_ioctl_sifmtu(env, descP, ename, eval); + break; +#endif + +#if defined(SIOCSIFTXQLEN) + case SIOCSIFTXQLEN: + return essio_ioctl_siftxqlen(env, descP, ename, eval); + break; +#endif + + default: + return esock_make_error(env, esock_atom_enotsup); + break; + } + +} + + + +/* =========================================================================== + * The implemented (ioctl) get requests falls into three grops: + * + * 1) gifconf - Takes no argument other then the request + * 2) gifname - Takes the interface index (integer) as an argument + * 3) other - All other (get) requests takes the interface name (string) + * as the argument. + * + * The functions defined using the macros below are all in the third (3) + * group. + * + */ + +static +ERL_NIF_TERM essio_ioctl_gifconf(ErlNifEnv* env, + ESockDescriptor* descP) +{ + struct ifconf ifc; + int ifc_len = 0; + int buflen = 100 * sizeof(struct ifreq); + char *buf = MALLOC(buflen); + ERL_NIF_TERM result; + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_gifconf {%d} -> entry\r\n", descP->sock) ); + + for (;;) { + ifc.ifc_len = buflen; + ifc.ifc_buf = buf; + if (ioctl(descP->sock, SIOCGIFCONF, (char *) &ifc) < 0) { + int saveErrno = sock_errno(); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_gifconf {%d} -> failure: " + "\r\n errno: %d (%s)" + "\r\n", descP->sock, saveErrno, erl_errno_id(saveErrno)) ); + + if (saveErrno != EINVAL || ifc_len) { + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + FREE(buf); + return esock_make_error(env, reason); + } + } else { + if (ifc.ifc_len == ifc_len) break; /* buf large enough */ + ifc_len = ifc.ifc_len; + } + buflen += 10 * sizeof(struct ifreq); + buf = (char *) REALLOC(buf, buflen); + } + + result = encode_ioctl_ifconf(env, descP, &ifc); + + FREE(ifc.ifc_buf); + + return result; +} + +/* + static + ERL_NIF_TERM essio_ioctl_fionread(ErlNifEnv* env, + ESockDescriptor* descP) + { + int n = 0; + ERL_NIF_TERM result; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_ioctl_fionread(%d) -> entry\r\n", descP->sock) ); + + if (ioctl(descP->sock, FIONREAD, (char *) &n) < 0) { + ERL_NIF_TERM reason; + int saveErrno = sock_errno(); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_fionread(%d) -> failure: " + "\r\n errno: %d (%s)" + "\r\n", descP->sock, saveErrno, erl_errno_id(saveErrno)) ); + + reason = MKA(env, erl_errno_id(saveErrno)); + + result = esock_make_error(env, reason); + } else { + + result = encode_ioctl_ivalue(env, descP, n); + + } + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_ioctl_fionread(%d) -> done with: " + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + return result; + } +*/ + +/* *** essio_ioctl_fionread *** */ +#if defined(FIONREAD) +#define IOCTL_FIONREAD_FUNC2_DECL \ + IOCTL_GET_REQUEST2_DECL(fionread, FIONREAD, ivalue) +#else +#define IOCTL_FIONREAD_FUNC2_DECL +#endif + +/* *** essio_ioctl_fionwrite *** */ +#if defined(FIONWRITE) +#define IOCTL_FIONWRITE_FUNC2_DECL \ + IOCTL_GET_REQUEST2_DECL(fionwrite, FIONWRITE, ivalue) +#else +#define IOCTL_FIONWRITE_FUNC2_DECL +#endif + +/* *** essio_ioctl_fionspace *** */ +#if defined(FIONSPACE) +#define IOCTL_FIONSPACE_FUNC2_DECL \ + IOCTL_GET_REQUEST2_DECL(fionspace, FIONSPACE, ivalue) +#else +#define IOCTL_FIONSPACE_FUNC2_DECL +#endif + +/* *** essio_ioctl_siocatmark *** */ +#if defined(SIOCATMARK) +#define IOCTL_SIOCATMARK_FUNC2_DECL \ + IOCTL_GET_REQUEST2_DECL(siocatmark, SIOCATMARK, bvalue) +#else +#define IOCTL_FIONSPACE_FUNC2_DECL +#endif + +#define IOCTL_GET_FUNCS2 \ + IOCTL_FIONREAD_FUNC2_DECL \ + IOCTL_FIONWRITE_FUNC2_DECL \ + IOCTL_FIONSPACE_FUNC2_DECL \ + IOCTL_SIOCATMARK_FUNC2_DECL + +#define IOCTL_GET_REQUEST2_DECL(OR, R, EF) \ + static \ + ERL_NIF_TERM essio_ioctl_##OR(ErlNifEnv* env, \ + ESockDescriptor* descP) \ + { \ + ERL_NIF_TERM result; \ + int n = 0; \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR "(%d) -> entry" \ + "\r\n", descP->sock) ); \ + \ + if (ioctl(descP->sock, R, &n) < 0) { \ + int saveErrno = sock_errno(); \ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR "(%d) -> failure: " \ + "\r\n reason: %T (%d)" \ + "\r\n", descP->sock, reason, saveErrno) ); \ + \ + result = esock_make_error(env, reason); \ + \ + } else { \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR "(%d) -> encode value\r\n", \ + descP->sock) ); \ + result = encode_ioctl_##EF(env, descP, n); \ + } \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", \ + "essio_ioctl_" #OR "(%d) -> done with: " \ + "\r\n result: %T" \ + "\r\n", descP->sock, result) ); \ + \ + return result; \ + \ + } +IOCTL_GET_FUNCS2 +#undef IOCTL_GET_FUNCS2 + + +/* *** essio_ioctl_gifindex *** */ +#if defined(SIOCGIFINDEX) +#if defined(ESOCK_USE_IFINDEX) +#define IOCTL_GIFINDEX_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_ifindex) +#elif defined(ESOCK_USE_INDEX) +#define IOCTL_GIFINDEX_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifindex, SIOCGIFINDEX, ivalue, ifreq.ifr_index) +#else +#define IOCTL_GIFINDEX_FUNC3_DECL +#endif +#else +#define IOCTL_GIFINDEX_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifflags *** */ +#if defined(SIOCGIFFLAGS) +#define IOCTL_GIFFLAGS_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifflags, SIOCGIFFLAGS, flags, ifreq.ifr_flags) +#else +#define IOCTL_GIFFLAGS_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifaddr *** */ +#if defined(SIOCGIFADDR) +#define IOCTL_GIFADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifaddr, SIOCGIFADDR, ifraddr, &ifreq.ifr_addr) +#else +#define IOCTL_GIFADDR_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifdstaddr *** */ +#if defined(SIOCGIFDSTADDR) +#define IOCTL_GIFDSTADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifdstaddr, SIOCGIFDSTADDR, ifraddr, &ifreq.ifr_dstaddr) +#else +#define IOCTL_GIFDSTADDR_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifbrdaddr *** */ +#if defined(SIOCGIFBRDADDR) +#define IOCTL_GIFBRDADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifbrdaddr, SIOCGIFBRDADDR, ifraddr, &ifreq.ifr_broadaddr) +#else +#define IOCTL_GIFBRDADDR_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifnetmask *** */ +#if defined(SIOCGIFNETMASK) +#ifdef __linux__ +#define IOCTL_GIFNETMASK_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_netmask) +#else +#define IOCTL_GIFNETMASK_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifnetmask, SIOCGIFNETMASK, ifraddr, &ifreq.ifr_addr) +#endif +#else +#define IOCTL_GIFNETMASK_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifmtu *** */ +#if defined(SIOCGIFMTU) +#define IOCTL_GIFMTU_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifmtu, SIOCGIFMTU, ivalue, ifreq.ifr_mtu) +#else +#define IOCTL_GIFMTU_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifhwaddr *** */ +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +#define IOCTL_GIFHWADDR_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifhwaddr, SIOCGIFHWADDR, hwaddr, &ifreq.ifr_hwaddr) +#else +#define IOCTL_GIFHWADDR_FUNC3_DECL +#endif + +/* *** essio_ioctl_gifmap *** */ +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) +#define IOCTL_GIFMAP_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(gifmap, SIOCGIFMAP, ifrmap, &ifreq.ifr_map) +#else +#define IOCTL_GIFMAP_FUNC3_DECL +#endif + +/* *** essio_ioctl_giftxqlen *** */ +#if defined(SIOCGIFTXQLEN) +#define IOCTL_GIFTXQLEN_FUNC3_DECL \ + IOCTL_GET_REQUEST3_DECL(giftxqlen, SIOCGIFTXQLEN, ivalue, ifreq.ifr_qlen) +#else +#define IOCTL_GIFTXQLEN_FUNC3_DECL +#endif + +#define IOCTL_GET_FUNCS3 \ + IOCTL_GIFINDEX_FUNC3_DECL \ + IOCTL_GIFFLAGS_FUNC3_DECL \ + IOCTL_GIFADDR_FUNC3_DECL \ + IOCTL_GIFDSTADDR_FUNC3_DECL \ + IOCTL_GIFBRDADDR_FUNC3_DECL \ + IOCTL_GIFNETMASK_FUNC3_DECL \ + IOCTL_GIFMTU_FUNC3_DECL \ + IOCTL_GIFHWADDR_FUNC3_DECL \ + IOCTL_GIFMAP_FUNC3_DECL \ + IOCTL_GIFTXQLEN_FUNC3_DECL + +#define IOCTL_GET_REQUEST3_DECL(OR, R, EF, UV) \ + static \ + ERL_NIF_TERM essio_ioctl_##OR(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM ename) \ + { \ + ERL_NIF_TERM result; \ + struct ifreq ifreq; \ + char* ifn = NULL; \ + int nlen; \ + \ + SSDBG( descP, ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> entry with" \ + "\r\n (e)Name: %T" \ + "\r\n", descP->sock, ename) ); \ + \ + if (!esock_decode_string(env, ename, &ifn)) \ + return enif_make_badarg(env); \ + \ + nlen = esock_strnlen(ifn, IFNAMSIZ); \ + \ + sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ + sys_memcpy(ifreq.ifr_name, ifn, \ + (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", \ + "essio_ioctl_" #OR " {%d} -> try ioctl\r\n", \ + descP->sock) ); \ + \ + if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ + int saveErrno = sock_errno(); \ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> failure: " \ + "\r\n reason: %T (%d)" \ + "\r\n", descP->sock, reason, saveErrno) ); \ + \ + result = esock_make_error(env, reason); \ + \ + } else { \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> encode value\r\n", \ + descP->sock) ); \ + result = encode_ioctl_##EF(env, descP, UV); \ + } \ + \ + FREE(ifn); \ + \ + return result; \ + \ + } +IOCTL_GET_FUNCS3 +#undef IOCTL_GET_FUNCS3 + + +/* =========================================================================== + * The "rest" of the implemented (ioctl) get requests(3) + * + * These (get) requests could not be 'generated' by the (simple) macros above. + */ + +#if defined(SIOCGIFNAME) +static +ERL_NIF_TERM essio_ioctl_gifname(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eidx) +{ + ERL_NIF_TERM result; + struct ifreq ifreq; + int index; + + SSDBG( descP, ("UNIX-ESSIO", "essio_ioctl_gifname {%d} -> entry with" + "\r\n (e)Index: %T" + "\r\n", descP->sock, eidx) ); + + if (!GET_INT(env, eidx, &index)) + return enif_make_badarg(env); + + ifreq.ifr_ifindex = index; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_ioctl_gifname {%d} -> try ioctl\r\n", descP->sock) ); + + if (ioctl(descP->sock, SIOCGIFNAME, (char *) &ifreq) < 0) { + int saveErrno = sock_errno(); + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_gifname {%d} -> failure: " + "\r\n reason: %T (%d)" + "\r\n", descP->sock, reason, saveErrno) ); + + result = esock_make_error(env, reason); + + } else { + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_gifname {%d} -> encode name\r\n", + descP->sock) ); + + result = esock_make_ok2(env, encode_ioctl_ifreq_name(env, ifreq.ifr_name)); + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_gifname {%d} -> done with" + "\r\n result: %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + + + +/* =========================================================================== + * The implemented (ioctl) set requests: + * + */ + +/* *** essio_ioctl_sifaddr *** */ +#if defined(SIOCSIFADDR) +#define IOCTL_SIFADDR_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifaddr, SIOCSIFADDR, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_addr)) +#else +#define IOCTL_SIFADDR_FUNC_DECL +#endif + +/* *** essio_ioctl_sifdstaddr *** */ +#if defined(SIOCSIFDSTADDR) +#define IOCTL_SIFDSTADDR_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifdstaddr, SIOCSIFDSTADDR, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_dstaddr)) +#else +#define IOCTL_SIFDSTADDR_FUNC_DECL +#endif + +/* *** essio_ioctl_sifbrdaddr *** */ +#if defined(SIOCSIFBRDADDR) +#define IOCTL_SIFBRDADDR_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifbrdaddr, SIOCSIFBRDADDR, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_broadaddr)) +#else +#define IOCTL_SIFBRDADDR_FUNC_DECL +#endif + +/* *** essio_ioctl_sifnetmask *** */ +#if defined(SIOCSIFNETMASK) +#ifdef __linux__ +#define IOCTL_SIFNETMASK_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_netmask)) +#else +#define IOCTL_SIFNETMASK_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifnetmask, SIOCSIFNETMASK, sockaddr, \ + ((ESockAddress*) &ifreq.ifr_addr)) +#endif +#else +#define IOCTL_SIFNETMASK_FUNC_DECL +#endif + +/* *** essio_ioctl_sifmtu *** + * On some platforms, MTU is an unsigned int + */ +#if defined(SIOCSIFMTU) +#define IOCTL_SIFMTU_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(sifmtu, SIOCSIFMTU, mtu, (int*) &ifreq.ifr_mtu) +#else +#define IOCTL_SIFMTU_FUNC_DECL +#endif + +/* *** essio_ioctl_siftxqlen *** */ +#if defined(SIOCSIFTXQLEN) +#define IOCTL_SIFTXQLEN_FUNC_DECL \ + IOCTL_SET_REQUEST_DECL(siftxqlen, SIOCSIFTXQLEN, txqlen, &ifreq.ifr_qlen) +#else +#define IOCTL_SIFTXQLEN_FUNC_DECL +#endif + +#define IOCTL_SET_FUNCS \ + IOCTL_SIFADDR_FUNC_DECL \ + IOCTL_SIFDSTADDR_FUNC_DECL \ + IOCTL_SIFBRDADDR_FUNC_DECL \ + IOCTL_SIFNETMASK_FUNC_DECL \ + IOCTL_SIFMTU_FUNC_DECL \ + IOCTL_SIFTXQLEN_FUNC_DECL + +#define IOCTL_SET_REQUEST_DECL(OR, R, DF, UVP) \ + static \ + ERL_NIF_TERM essio_ioctl_##OR(ErlNifEnv* env, \ + ESockDescriptor* descP, \ + ERL_NIF_TERM ename, \ + ERL_NIF_TERM evalue) \ + { \ + ERL_NIF_TERM result; \ + struct ifreq ifreq; \ + char* ifn = NULL; \ + int nlen; \ + \ + SSDBG( descP, ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> entry with" \ + "\r\n (e)Name: %T" \ + "\r\n (e)Value: %T" \ + "\r\n", descP->sock, ename, evalue) ); \ + \ + if (!esock_decode_string(env, ename, &ifn)) { \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> failed decode name" \ + "\r\n", descP->sock) ); \ + \ + return enif_make_badarg(env); \ + } \ + \ + if (! decode_ioctl_##DF(env, descP, evalue, UVP)) { \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> failed decode addr" \ + "\r\n", descP->sock) ); \ + \ + return esock_make_invalid(env, esock_atom_##DF); \ + } \ + \ + nlen = esock_strnlen(ifn, IFNAMSIZ); \ + \ + sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); \ + sys_memcpy(ifreq.ifr_name, ifn, \ + (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> try ioctl\r\n", \ + descP->sock) ); \ + \ + if (ioctl(descP->sock, R, (char *) &ifreq) < 0) { \ + int saveErrno = sock_errno(); \ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); \ + \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> failure: " \ + "\r\n reason: %T (%d)" \ + "\r\n", descP->sock, reason, saveErrno) ); \ + \ + result = esock_make_error(env, reason); \ + \ + } else { \ + SSDBG( descP, \ + ("UNIX-ESSIO", "essio_ioctl_" #OR " {%d} -> " \ + "addr successfully set\r\n", \ + descP->sock) ); \ + result = esock_atom_ok; \ + } \ + \ + FREE(ifn); \ + \ + return result; \ + \ + } + +IOCTL_SET_FUNCS +#undef IOCTL_SET_FUNCS + + +/* =========================================================================== + * The "rest" of the implemented (ioctl) set requests + * + * These (set) requests could not be 'generated' by the macros above. + */ + +#if defined(SIOCSIFFLAGS) +static +ERL_NIF_TERM essio_ioctl_sifflags(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ename, + ERL_NIF_TERM eflags) +{ + ERL_NIF_TERM result; + struct ifreq ifreq; + char* ifn = NULL; + int nlen; + + SSDBG( descP, ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> entry with" + "\r\n (e)Name: %T" + "\r\n (e)Flags: %T" + "\r\n", descP->sock, ename, eflags) ); + + if (!esock_decode_string(env, ename, &ifn)) { + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> failed decode name" + "\r\n", descP->sock) ); + + return enif_make_badarg(env); + } + + // Make sure the length of the string is valid! + nlen = esock_strnlen(ifn, IFNAMSIZ); + + sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); // Just in case + sys_memcpy(ifreq.ifr_name, ifn, + (nlen >= IFNAMSIZ) ? IFNAMSIZ-1 : nlen); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> try (get) ioctl\r\n", + descP->sock) ); + + if (ioctl(descP->sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { + int saveErrno = sock_errno(); + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> " + "failure: failed reading *current* flags" + "\r\n reason: %T (%d)" + "\r\n", descP->sock, reason, saveErrno) ); + + result = esock_make_error(env, reason); + + } else { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_ioctl_sifflags {%d} -> (local) update flags\r\n", + descP->sock) ); + + if (decode_ioctl_flags(env, descP, eflags, &ifreq.ifr_flags)) { + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> try (set) ioctl\r\n", + descP->sock) ); + + if (ioctl(descP->sock, SIOCSIFFLAGS, (char *) &ifreq) < 0) { + int saveErrno = sock_errno(); + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> failure: " + "\r\n reason: %T (%d)" + "\r\n", descP->sock, reason, saveErrno) ); + + result = esock_make_error(env, reason); + + } else { + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> " + "updated flags successfully set\r\n", + descP->sock) ); + result = esock_atom_ok; + } + + /* We know that if esock_decode_string is successful, + * we have "some" form of string, and therefor memory + * has been allocated (and need to be freed)... */ + FREE(ifn); + + } else { + result = enif_make_badarg(env); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_sifflags {%d} -> done with result: " + "\r\n %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + + +/* =========================================================================== + * ioctl utility functions + * + */ + +static +ERL_NIF_TERM encode_ioctl_ifconf(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifconf* ifcP) +{ + ERL_NIF_TERM result; + unsigned int len = ((ifcP == NULL) ? 0 : + (ifcP->ifc_len / sizeof(struct ifreq))); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> entry (when len = %d)\r\n", len) ); + + if (len > 0) { + ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); + unsigned int i = 0; + struct ifreq* p = ifcP->ifc_req; + + for (i = 0 ; i < len ; i++) { + SSDBG( descP, + ("UNIX-ESSIO", + "encode_ioctl_ifconf -> encode ifreq entry %d\r\n", i) ); + array[i] = encode_ioctl_ifconf_ifreq(env, descP, &p[i]); + } + + SSDBG( descP, + ("UNIX-ESSIO", "encode_ioctl_ifconf -> all entries encoded\r\n", i) ); + + result = esock_make_ok2(env, MKLA(env, array, len)); + FREE(array); + + } else { + + result = esock_make_ok2(env, MKEL(env)); + + } + + return result; +} + + +#if defined(SIOCGIFMAP) && defined(ESOCK_USE_IFMAP) +static +ERL_NIF_TERM encode_ioctl_ifrmap(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifmap* mapP) +{ + ERL_NIF_TERM mapKeys[] = {esock_atom_mem_start, + esock_atom_mem_end, + esock_atom_base_addr, + esock_atom_irq, + esock_atom_dma, + esock_atom_port}; + ERL_NIF_TERM mapVals[] = {MKUL(env, mapP->mem_start), + MKUL(env, mapP->mem_end), + MKUI(env, mapP->base_addr), + MKUI(env, mapP->irq), + MKUI(env, mapP->dma), + MKUI(env, mapP->port)}; + unsigned int numMapKeys = NUM(mapKeys); + unsigned int numMapVals = NUM(mapVals); + ERL_NIF_TERM emap; + + ESOCK_ASSERT( numMapVals == numMapKeys ); + ESOCK_ASSERT( MKMA(env, mapKeys, mapVals, numMapKeys, &emap) ); + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_ifrmap -> done with" + "\r\n Map: %T" + "\r\n", emap) ); + + return esock_make_ok2(env, emap);; +} +#endif + + +#if defined(SIOCGIFHWADDR) && defined(ESOCK_USE_HWADDR) +static +ERL_NIF_TERM encode_ioctl_hwaddr(ErlNifEnv* env, + ESockDescriptor* descP, + struct sockaddr* addrP) +{ + ERL_NIF_TERM eaddr; + SOCKLEN_T sz = sizeof(struct sockaddr); + + esock_encode_hwsockaddr(env, addrP, sz, &eaddr); + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_ifraddr -> done with" + "\r\n Sock Addr: %T" + "\r\n", eaddr) ); + + return esock_make_ok2(env, eaddr);; +} +#endif + + +static +ERL_NIF_TERM encode_ioctl_ifraddr(ErlNifEnv* env, + ESockDescriptor* descP, + struct sockaddr* addrP) +{ + ERL_NIF_TERM eaddr; + + esock_encode_sockaddr(env, (ESockAddress*) addrP, -1, &eaddr); + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_ifraddr -> done with" + "\r\n Sock Addr: %T" + "\r\n", eaddr) ); + + return esock_make_ok2(env, eaddr);; +} + + +static +ERL_NIF_TERM encode_ioctl_flags(ErlNifEnv* env, + ESockDescriptor* descP, + short flags) +{ + int i, flag, num = esock_ioctl_flags_length; // NUM(ioctl_flags); + ERL_NIF_TERM eflags, eflag; + SocketTArray ta = TARRAY_CREATE(20); // Just to be on the safe side + + if (flags == 0) { + eflags = MKEL(env); + } else { + for (i = 0; (i < num) && (flags != 0); i++) { + flag = esock_ioctl_flags[i].flag; + if ((flag != 0) && ((flags & flag) == flag)) { + eflag = *(esock_ioctl_flags[i].name); + flags &= ~flag; + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_flags {%d} -> " + "\r\n i: %d" + "\r\n found flag: %T (%d)" + "\r\n remaining flags: %d" + "\r\n", descP->sock, i, eflag, flag, flags) ); + + TARRAY_ADD(ta, eflag); + } + } + if (flags != 0) { + + SSDBG( descP, + ("UNIX-ESSIO", "encode_ioctl_flags {%d} -> unknown flag(s): %d" + "\r\n", descP->sock, flags) ); + + TARRAY_ADD(ta, MKI(env, flags)); + } + + TARRAY_TOLIST(ta, env, &eflags); + } + + + SSDBG( descP, ("UNIX-ESSIO", "encode_ioctl_flags -> done with" + "\r\n Flags: %T (%d)" + "\r\n", eflags, flags) ); + + return esock_make_ok2(env, eflags); +} + + +static +BOOLEAN_T decode_ioctl_sockaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eaddr, + ESockAddress* addr) +{ + SOCKLEN_T addrLen; + BOOLEAN_T result; + + result = esock_decode_sockaddr(env, eaddr, (ESockAddress*) addr, &addrLen); + + VOID(addrLen); + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_sockaddr {%d} -> decode result: %s" + "\r\n", descP->sock, B2S(result)) ); + + return result; +} + + +static +BOOLEAN_T decode_ioctl_mtu(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM emtu, + int* mtu) +{ + BOOLEAN_T result; + + if (! GET_INT(env, emtu, mtu)) { + result = FALSE; + } else { + result = TRUE; + } + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_mtu {%d} -> decode result: %s" + "\r\n", descP->sock, B2S(result)) ); + + return result; +} + + +#if defined(SIOCSIFTXQLEN) +static +BOOLEAN_T decode_ioctl_txqlen(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM etxqlen, + int* txqlen) +{ + return decode_ioctl_ivalue(env, descP, etxqlen, txqlen); +} +#endif + +/* All uses of the function should be added. For instance: + * #if defined(SIOCGIFTXQLEN) || defined(FOOBAR) || defined(YXA) + */ +#if defined(SIOCGIFTXQLEN) +static +BOOLEAN_T decode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eivalue, + int* ivalue) +{ + BOOLEAN_T result; + + if (! GET_INT(env, eivalue, ivalue)) { + result = FALSE; + } else { + result = TRUE; + } + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_ivalue {%d} -> decode result: %s" + "\r\n", descP->sock, B2S(result)) ); + + return result; +} +#endif + + +static +BOOLEAN_T decode_ioctl_flags(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eflags, + short* flags) +{ + ERL_NIF_TERM key, value; + ErlNifMapIterator iter; + int tmpFlags = (int) *flags; // Current value + int flag; + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_flags {%d} -> entry with" + "\r\n flags: %d" + "\r\n", + descP->sock, tmpFlags) ); + + enif_map_iterator_create(env, eflags, &iter, ERL_NIF_MAP_ITERATOR_FIRST); + + while (enif_map_iterator_get_pair(env, &iter, &key, &value)) { + + /* Convert key (eflag) to int */ + if (! GET_INT(env, key, &flag)) { + enif_map_iterator_destroy(env, &iter); + return FALSE; + } + + // Update flag + if (COMPARE(value, esock_atom_true) == 0) { + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_flags {%d} -> set %d\r\n", + descP->sock, flag) ); + tmpFlags |= flag; + } else { + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_flags {%d} -> reset %d\r\n", + descP->sock, flag) ); + tmpFlags &= ~flag; + } + + enif_map_iterator_next(env, &iter); + } + + enif_map_iterator_destroy(env, &iter); + + SSDBG( descP, + ("UNIX-ESSIO", "decode_ioctl_flags {%d} -> done with" + "\r\n (new) flags: %d" + "\r\n", + descP->sock, tmpFlags) ); + + *flags = (short) tmpFlags; + + return TRUE; +} + + +static +ERL_NIF_TERM encode_ioctl_ivalue(ErlNifEnv* env, + ESockDescriptor* descP, + int ivalue) +{ + return esock_encode_ioctl_ivalue(env, descP, ivalue); +} + +static +ERL_NIF_TERM encode_ioctl_bvalue(ErlNifEnv* env, + ESockDescriptor* descP, + int bvalue) +{ + return esock_encode_ioctl_bvalue(env, descP, bvalue); +} + +static +ERL_NIF_TERM encode_ioctl_ifconf_ifreq(ErlNifEnv* env, + ESockDescriptor* descP, + struct ifreq* ifrP) +{ + ERL_NIF_TERM ename, eaddr; + + ESOCK_ASSERT( ifrP != NULL ); + + SSDBG( descP, + ("UNIX-ESSIO", "encode_ioctl_ifconf_ifreq -> encode name\r\n") ); + ename = encode_ioctl_ifreq_name(env, ifrP->ifr_name); + + SSDBG( descP, + ("UNIX-ESSIO", "encode_ioctl_ifconf_ifreq -> encode sockaddr\r\n") ); + eaddr = encode_ioctl_ifreq_sockaddr(env, &ifrP->ifr_addr); + + SSDBG( descP, + ("UNIX-ESSIO", "encode_ioctl_ifconf_ifreq -> make ifreq map with" + "\r\n Name: %T" + "\r\n Sock Addr: %T" + "\r\n", ename, eaddr) ); + return make_ifreq(env, ename, esock_atom_addr, eaddr); +} + +static +ERL_NIF_TERM encode_ioctl_ifreq_name(ErlNifEnv* env, + char* name) +{ + return ((name == NULL) ? esock_atom_undefined : MKS(env, name)); +} + +static +ERL_NIF_TERM encode_ioctl_ifreq_sockaddr(ErlNifEnv* env, struct sockaddr* sa) +{ + ERL_NIF_TERM esa; + + if (sa != NULL) { + + esock_encode_sockaddr(env, (ESockAddress*) sa, -1, &esa); + + } else { + + esa = esock_atom_undefined; + + } + + return esa; +} + + +/* The ifreq structure *always* contain a name + * and *one* other element. The second element + * depend on the ioctl request. + */ +static +ERL_NIF_TERM make_ifreq(ErlNifEnv* env, + ERL_NIF_TERM name, + ERL_NIF_TERM key2, + ERL_NIF_TERM val2) +{ + ERL_NIF_TERM keys[2]; + ERL_NIF_TERM vals[2]; + ERL_NIF_TERM res; + + keys[0] = esock_atom_name; + vals[0] = name; + + keys[1] = key2; + vals[1] = val2; + + ESOCK_ASSERT( MKMA(env, keys, vals, NUM(keys), &res) ); + + return res; +} + + + + +/* ---------------------------------------------------------------------- + * U t i l i t y F u n c t i o n s + * ---------------------------------------------------------------------- + */ + +/* *** send_check_writer *** + * + * Checks if we have a current writer and if that is us. + * If not (current writer), then we must be made to wait + * for our turn. This is done by pushing us unto the writer queue. + */ +static +BOOLEAN_T send_check_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ERL_NIF_TERM* checkResult) +{ + if (descP->currentWriterP != NULL) { + ErlNifPid caller; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (COMPARE_PIDS(&descP->currentWriter.pid, &caller) != 0) { + /* Not the "current writer", so (maybe) push onto queue */ + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_writer {%d} -> not (current) writer" + "\r\n ref: %T" + "\r\n", descP->sock, ref) ); + + if (! esock_writer_search4pid(env, descP, &caller)) { + esock_writer_push(env, descP, caller, ref, NULL); + *checkResult = esock_atom_select; + } else { + /* Writer already in queue */ + *checkResult = esock_raise_invalid(env, esock_atom_state); + } + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_writer {%d} -> queue (push) result: %T\r\n" + "\r\n ref: %T" + "\r\n", descP->sock, *checkResult, ref) ); + + return FALSE; + } + } + + // Does not actually matter in this case, but ... + *checkResult = esock_atom_ok; + + return TRUE; +} + + +/* *** send_check_result *** + * + * Check the result of a socket send (send, sendto and sendmsg) call. + * If a "complete" send has been made, the next (waiting) writer will be + * scheduled (if there is one). + * If we did not manage to send the entire package, make another select, + * so that we can be informed when we can make another try (to send the rest), + * and return with the amount we actually managed to send (its up to the caller + * (that is the erlang code) to figure out hust much is left to send). + * If the write fail, we give up and return with the appropriate error code. + * + * What about the remaining writers!! + * + */ +static +ERL_NIF_TERM send_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t send_result, + ssize_t dataSize, + BOOLEAN_T dataInTail, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef) +{ + ERL_NIF_TERM res; + BOOLEAN_T send_error; + int err; + + send_error = ESOCK_IS_ERROR(send_result); + err = send_error ? sock_errno() : 0; + + SSDBG( descP, + ("UNIX-ESSIO", "send_check_result(%T) {%d} -> entry with" + "\r\n send_result: %ld" + "\r\n dataSize: %ld" + "\r\n err: %d" + "\r\n sendRef: %T" + "\r\n", sockRef, descP->sock, + (long) send_result, (long) dataSize, err, sendRef) ); + + if (send_error) { + /* Some kind of send failure - check what kind */ + if ((err != EAGAIN) && (err != EINTR)) { + res = send_check_fail(env, descP, err, sockRef); + } else { + /* Ok, try again later */ + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_result(%T) {%d} -> try again" + "\r\n", sockRef, descP->sock) ); + + res = send_check_retry(env, descP, -1, sockRef, sendRef); + } + } else { + ssize_t written = send_result; + ESOCK_ASSERT( dataSize >= written ); + + if (written < dataSize) { + /* Not the entire package */ + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_result(%T) {%d} -> " + "not entire package written (%d of %d)" + "\r\n", sockRef, descP->sock, + written, dataSize) ); + + res = send_check_retry(env, descP, written, sockRef, sendRef); + } else if (dataInTail) { + /* We sent all we could, but not everything (data in tail) */ + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_result(%T) {%d} -> " + "not entire package written (%d but data in tail)" + "\r\n", sockRef, descP->sock, + written) ); + + res = + send_check_retry(env, descP, written, sockRef, + esock_atom_iov); + } else { + res = send_check_ok(env, descP, written, sockRef); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_result(%T) {%d} -> done:" + "\r\n res: %T" + "\r\n", sockRef, descP->sock, + res) ); + + return res; +} + + +/* *** send_check_ok *** + * + * Processing done upon successful send. + */ +static +ERL_NIF_TERM send_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t written, + ERL_NIF_TERM sockRef) +{ + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_pkg, &descP->writePkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_byte, &descP->writeByteCnt, written); + descP->writePkgMaxCnt += written; + if (descP->writePkgMaxCnt > descP->writePkgMax) + descP->writePkgMax = descP->writePkgMaxCnt; + descP->writePkgMaxCnt = 0; + + SSDBG( descP, + ("UNIX-ESSIO", "send_check_ok(%T) {%d} -> " + "everything written (%ld) - done\r\n", + sockRef, descP->sock, written) ); + + if (descP->currentWriterP != NULL) { + ESOCK_ASSERT( DEMONP("send_check_ok -> current writer", + env, descP, &descP->currentWriter.mon) == 0); + } + /* + * Ok, this write is done maybe activate the next (if any) + */ + if (!esock_activate_next_writer(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", "send_check_ok(%T) {%d} -> no more writers\r\n", + sockRef, descP->sock) ); + + descP->currentWriterP = NULL; + } + + return esock_atom_ok; +} + + +/* *** send_check_fail *** + * + * Processing done upon failed send. + * An actual failure - we (and everyone waiting) give up. + */ +static +ERL_NIF_TERM send_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM reason; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_fails, &descP->writeFails, 1); + + reason = MKA(env, erl_errno_id(saveErrno)); + + SSDBG( descP, + ("UNIX-ESSIO", "send_check_fail(%T) {%d} -> error: %d (%T)\r\n", + sockRef, descP->sock, saveErrno, reason) ); + + if (saveErrno != EINVAL) { + + /* + * We assume that anything other then einval (invalid input) + * is basically fatal (=> all waiting sends are aborted) + */ + + if (descP->currentWriterP != NULL) { + + esock_requestor_release("send_check_fail", + env, descP, &descP->currentWriter); + + send_error_waiting_writers(env, descP, sockRef, reason); + + descP->currentWriterP = NULL; + } + } + + return esock_make_error(env, reason); +} + + +/* *** send_error_waiting_writers *** + * + * Process all waiting writers when a fatal error has occurred. + * All waiting writers will be "aborted", that is a + * nif_abort message will be sent (with ref and reason). + */ +static +void send_error_waiting_writers(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + ESockRequestor req; + + req.env = NULL; /* read by writer_pop before free */ + while (esock_writer_pop(env, descP, &req)) { + SSDBG( descP, + ("UNIX-ESSIO", + "send_error_waiting_writers(%T) {%d} -> abort" + "\r\n pid: %T" + "\r\n reason: %T" + "\r\n", + sockRef, descP->sock, &req.pid, reason) ); + + esock_send_abort_msg(env, descP, sockRef, &req, reason); + + (void) DEMONP("send_error_waiting_writers -> pop'ed writer", + env, descP, &req.mon); + } +} + + +/* *** send_check_retry *** + * + * Processing done upon incomplete or blocked send. + * + * We failed to write the *entire* packet (anything less + * then size of the packet, which is 0 <= written < sizeof + * packet, so schedule the rest for later. + */ +static +ERL_NIF_TERM send_check_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t written, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef) +{ + int sres; + ERL_NIF_TERM res; + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_retry(%T) {%d} -> %ld" + "\r\n", sockRef, descP->sock, (long) written) ); + + if (written >= 0) { + descP->writePkgMaxCnt += written; + + if (descP->type != SOCK_STREAM) { + /* Partial write for packet oriented socket + * - done with packet + */ + if (descP->writePkgMaxCnt > descP->writePkgMax) + descP->writePkgMax = descP->writePkgMaxCnt; + descP->writePkgMaxCnt = 0; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_pkg, &descP->writePkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_byte, &descP->writeByteCnt, written); + + if (descP->currentWriterP != NULL) { + ESOCK_ASSERT( DEMONP("send_check_retry -> current writer", + env, descP, + &descP->currentWriter.mon) == 0); + } + /* + * Ok, this write is done maybe activate the next (if any) + */ + if (!esock_activate_next_writer(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "send_check_retry(%T) {%d} -> no more writers\r\n", + sockRef, descP->sock) ); + + descP->currentWriterP = NULL; + } + + return esock_make_ok2(env, MKI64(env, written)); + } /* else partial write for stream socket */ + } /* else send would have blocked */ + + /* Register this process as current writer */ + + if (descP->currentWriterP == NULL) { + /* Register writer as current */ + + ESOCK_ASSERT( enif_self(env, &descP->currentWriter.pid) != NULL ); + ESOCK_ASSERT( MONP("send_check_retry -> current writer", + env, descP, + &descP->currentWriter.pid, + &descP->currentWriter.mon) == 0 ); + ESOCK_ASSERT( descP->currentWriter.env == NULL ); + + descP->currentWriter.env = esock_alloc_env("current-writer"); + descP->currentWriter.ref = + CP_TERM(descP->currentWriter.env, sendRef); + descP->currentWriterP = &descP->currentWriter; + } else { + /* Overwrite current writer registration */ + enif_clear_env(descP->currentWriter.env); + descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef); + } + + if (COMPARE(sendRef, esock_atom_iov) == 0) { + ESOCK_ASSERT( written >= 0 ); + /* IOV iteration - do not select */ + return MKT2(env, esock_atom_iov, MKI64(env, written)); + } + + /* Select write for this process */ + + sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); + + if (sres < 0) { + ERL_NIF_TERM reason; + + /* Internal select error */ + ESOCK_ASSERT( DEMONP("send_check_retry - select error", + env, descP, &descP->currentWriter.mon) == 0); + + /* Fail all queued writers */ + reason = MKT2(env, esock_atom_select_write, MKI(env, sres)); + esock_requestor_release("send_check_retry - select error", + env, descP, &descP->currentWriter); + send_error_waiting_writers(env, descP, sockRef, reason); + descP->currentWriterP = NULL; + + res = + enif_raise_exception(env, + MKT2(env, esock_atom_select_write, + MKI(env, sres))); + + } else { + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_waits, &descP->writeWaits, 1); + + descP->writeState |= ESOCK_STATE_SELECTED; + + if (written >= 0) { + /* Partial write success */ + res = MKT2(env, esock_atom_select, MKI64(env, written)); + } else { + /* No write - try again */ + res = esock_atom_select; + } + } + + return res; +} + + +/* *** Control message utility functions *** */ + +/* +++ decode_cmsghdrs +++ + * + * Decode a list of cmsg(). There can be 0 or more "blocks". + * + * Each element can either be a (erlang) map that needs to be decoded, + * or a (erlang) binary that just needs to be appended to the control + * buffer. + * + * Our "problem" is that we have no idea how much memory we actually need. + * + */ + +static +BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* cmsgHdrBufP, + size_t cmsgHdrBufLen, + size_t* cmsgHdrBufUsed) +{ + ERL_NIF_TERM elem, tail, list; + char* bufP; + size_t rem, used, totUsed = 0; + unsigned int len; + int i; + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdrs {%d} -> entry with" + "\r\n eCMsg: %T" + "\r\n cmsgHdrBufP: 0x%lX" + "\r\n cmsgHdrBufLen: %d" + "\r\n", descP->sock, + eCMsg, cmsgHdrBufP, cmsgHdrBufLen) ); + + if (! GET_LIST_LEN(env, eCMsg, &len)) + return FALSE; + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdrs {%d} -> list length: %d\r\n", + descP->sock, len) ); + + for (i = 0, list = eCMsg, rem = cmsgHdrBufLen, bufP = cmsgHdrBufP; + i < len; i++) { + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdrs {%d} -> process elem %d:" + "\r\n (buffer) rem: %u" + "\r\n (buffer) totUsed: %u" + "\r\n", descP->sock, i, rem, totUsed) ); + + /* Extract the (current) head of the (cmsg hdr) list */ + if (! GET_LIST_ELEM(env, list, &elem, &tail)) + return FALSE; + + used = 0; // Just in case... + if (! decode_cmsghdr(env, descP, elem, bufP, rem, &used)) + return FALSE; + + bufP = CHARP( ULONG(bufP) + used ); + rem = SZT( rem - used ); + list = tail; + totUsed += used; + + } + + *cmsgHdrBufUsed = totUsed; + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdrs {%d} -> done" + "\r\n all %u ctrl headers processed" + "\r\n totUsed = %lu\r\n", + descP->sock, len, (unsigned long) totUsed) ); + + return TRUE; +} + + +/* +++ decode_cmsghdr +++ + * + * Decode one cmsg(). Put the "result" into the buffer and advance the + * pointer (of the buffer) afterwards. Also update 'rem' accordingly. + * But before the actual decode, make sure that there is enough room in + * the buffer for the cmsg header (sizeof(*hdr) < rem). + * + * The eCMsg should be a map with three fields: + * + * level :: socket | protocol() | integer() + * type :: atom() | integer() + * What values are valid depend on the level + * data :: binary() | integer() | boolean() + * The type of the data depends on + * or level and type, but can be a binary, + * which means that the data is already coded. + * value :: term() Which is a term matching the decode function + */ + +static +BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* bufP, + size_t rem, + size_t* used) +{ + ERL_NIF_TERM eLevel, eType, eData, eValue; + int level; + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d} -> entry with" + "\r\n eCMsg: %T" + "\r\n", descP->sock, eCMsg) ); + + // Get 'level' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_level, &eLevel)) + return FALSE; + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d} -> eLevel: %T" + "\r\n", descP->sock, eLevel) ); + + // Get 'type' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_type, &eType)) + return FALSE; + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d} -> eType: %T" + "\r\n", descP->sock, eType) ); + + // Decode Level + if (! esock_decode_level(env, eLevel, &level)) + return FALSE; + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d}-> level: %d\r\n", + descP->sock, level) ); + + // Get 'data' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_data, &eData)) { + + // Get 'value' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_value, &eValue)) + return FALSE; + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d} -> eValue: %T" + "\r\n", descP->sock, eValue) ); + + // Decode Value + if (! decode_cmsghdr_value(env, descP, level, eType, eValue, + bufP, rem, used)) + return FALSE; + + } else { + + // Verify no 'value' field + if (GET_MAP_VAL(env, eCMsg, esock_atom_value, &eValue)) + return FALSE; + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d} -> eData: %T" + "\r\n", descP->sock, eData) ); + + // Decode Data + if (! decode_cmsghdr_data(env, descP, level, eType, eData, + bufP, rem, used)) + return FALSE; + } + + SSDBG( descP, ("UNIX-ESSIO", "decode_cmsghdr {%d}-> used: %lu\r\n", + descP->sock, (unsigned long) *used) ); + + return TRUE; +} + + +static +BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eValue, + char* bufP, + size_t rem, + size_t* usedP) +{ + int type; + struct cmsghdr* cmsgP = (struct cmsghdr *) bufP; + ESockCmsgSpec* cmsgTable; + ESockCmsgSpec* cmsgSpecP = NULL; + size_t num = 0; + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_value {%d} -> entry \r\n" + " eType: %T\r\n" + " eValue: %T\r\n", + descP->sock, eType, eValue) ); + + // We have decode functions only for symbolic (atom) types + if (! IS_ATOM(env, eType)) { + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " eType not an atom\r\n", + descP->sock) ); + return FALSE; + } + + /* Try to look up the symbolic type + */ + if (((cmsgTable = esock_lookup_cmsg_table(level, &num)) == NULL) || + ((cmsgSpecP = esock_lookup_cmsg_spec(cmsgTable, num, eType)) == NULL) || + (cmsgSpecP->decode == NULL)) { + /* We found no table for this level, + * we found no symbolic type in the level table, + * or no decode function for this type + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " cmsgTable: %p\r\n" + " cmsgSpecP: %p\r\n", + descP->sock, cmsgTable, cmsgSpecP) ); + return FALSE; + } + + if (! cmsgSpecP->decode(env, eValue, cmsgP, rem, usedP)) { + // Decode function failed + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " decode function failed\r\n", + descP->sock) ); + return FALSE; + } + + // Successful decode + + type = cmsgSpecP->type; + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_value {%d} -> TRUE:\r\n" + " level: %d\r\n" + " type: %d\r\n", + " *usedP: %lu\r\n", + descP->sock, level, type, (unsigned long) *usedP) ); + + cmsgP->cmsg_level = level; + cmsgP->cmsg_type = type; + return TRUE; +} + + +static +BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eData, + char* bufP, + size_t rem, + size_t* usedP) +{ + int type; + ErlNifBinary bin; + struct cmsghdr* cmsgP = (struct cmsghdr *) bufP; + ESockCmsgSpec* cmsgSpecP = NULL; + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_data {%d} -> entry \r\n" + " eType: %T\r\n" + " eData: %T\r\n", + descP->sock, eType, eData) ); + + // Decode Type + if (! GET_INT(env, eType, &type)) { + ESockCmsgSpec* cmsgTable = NULL; + size_t num = 0; + + /* Try to look up the symbolic (atom) type + */ + if ((! IS_ATOM(env, eType)) || + ((cmsgTable = esock_lookup_cmsg_table(level, &num)) == NULL) || + ((cmsgSpecP = esock_lookup_cmsg_spec(cmsgTable, num, eType)) == NULL)) { + /* Type was not an atom, + * we found no table for this level, + * or we found no symbolic type in the level table + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_data {%d} -> FALSE:\r\n" + " cmsgTable: %p\r\n" + " cmsgSpecP: %p\r\n", + descP->sock, cmsgTable, cmsgSpecP) ); + return FALSE; + } + + type = cmsgSpecP->type; + } + + // Decode Data + if (GET_BIN(env, eData, &bin)) { + void *p; + + p = esock_init_cmsghdr(cmsgP, rem, bin.size, usedP); + if (p == NULL) { + /* No room for the data + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_data {%d} -> FALSE:\r\n" + " rem: %lu\r\n" + " bin.size: %lu\r\n", + descP->sock, + (unsigned long) rem, + (unsigned long) bin.size) ); + return FALSE; + } + + // Copy the binary data + sys_memcpy(p, bin.data, bin.size); + + } else if ((! esock_cmsg_decode_int(env, eData, cmsgP, rem, usedP)) && + (! esock_cmsg_decode_bool(env, eData, cmsgP, rem, usedP))) { + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_data {%d} -> FALSE\r\n", + descP->sock) ); + return FALSE; + } + + // Successful decode + + SSDBG( descP, + ("UNIX-ESSIO", + "decode_cmsghdr_data {%d} -> TRUE:\r\n" + " level: %d\r\n" + " type: %d\r\n" + " *usedP: %lu\r\n", + descP->sock, level, type, (unsigned long) *usedP) ); + + cmsgP->cmsg_level = level; + cmsgP->cmsg_type = type; + return TRUE; +} + + +/* +++ encode_msg +++ + * + * Encode a msg() (recvmsg). In erlang its represented as + * a map, which has a specific set of attributes: + * + * addr (source address) - sockaddr() + * iov - [binary()] + * ctrl - [cmsg()] + * flags - msg_flags() + */ + +static +void encode_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + struct msghdr* msgHdrP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM* eMsg) +{ + ERL_NIF_TERM addr, iov, ctrl, flags; + + SSDBG( descP, + ("UNIX-ESSIO", "encode_msg {%d} -> entry with" + "\r\n read: %ld" + "\r\n", descP->sock, (long) read) ); + + /* The address is not used if we are connected (unless, maybe, + * family is 'local'), so check (length = 0) before we try to encodel + */ + if (msgHdrP->msg_namelen != 0) { + esock_encode_sockaddr(env, + (ESockAddress*) msgHdrP->msg_name, + msgHdrP->msg_namelen, + &addr); + } else { + addr = esock_atom_undefined; + } + + SSDBG( descP, + ("UNIX-ESSIO", "encode_msg {%d} -> encode iov" + "\r\n msg_iovlen: %lu" + "\r\n", + descP->sock, + (unsigned long) msgHdrP->msg_iovlen) ); + + esock_encode_iov(env, read, + msgHdrP->msg_iov, msgHdrP->msg_iovlen, dataBufP, + &iov); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_msg {%d} -> try encode cmsgs\r\n", + descP->sock) ); + + encode_cmsgs(env, descP, ctrlBufP, msgHdrP, &ctrl); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_msg {%d} -> try encode flags\r\n", + descP->sock) ); + + esock_encode_msg_flags(env, descP, msgHdrP->msg_flags, &flags); + + SSDBG( descP, + ("UNIX-ESSIO", "encode_msg {%d} -> components encoded:" + "\r\n addr: %T" + "\r\n ctrl: %T" + "\r\n flags: %T" + "\r\n", descP->sock, addr, ctrl, flags) ); + + { + ERL_NIF_TERM keys[] = {esock_atom_iov, + esock_atom_ctrl, + esock_atom_flags, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {iov, ctrl, flags, addr}; + size_t numKeys = NUM(keys); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_msg {%d} -> create map\r\n", + descP->sock) ); + + if (msgHdrP->msg_namelen == 0) + numKeys--; // No addr + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eMsg) ); + + SSDBG( descP, + ("UNIX-ESSIO", + "encode_msg {%d}-> map encoded\r\n", + descP->sock) ); + } + + SSDBG( descP, + ("UNIX-ESSIO", "encode_msg {%d} -> done\r\n", descP->sock) ); +} + + + +/* +++ encode_cmsgs +++ + * + * Encode a list of cmsg(). There can be 0 or more cmsghdr "blocks". + * + * Our "problem" is that we have no idea how many control messages + * we have. + * + * The cmsgHdrP arguments points to the start of the control data buffer, + * an actual binary. Its the only way to create sub-binaries. So, what we + * need to continue processing this is to turn that into an binary erlang + * term (which can then in turn be turned into sub-binaries). + * + * We need the cmsgBufP (even though cmsgHdrP points to it) to be able + * to create sub-binaries (one for each cmsg hdr). + * + * The TArray (term array) is created with the size of 128, which should + * be enough. But if its not, then it will be automatically realloc'ed during + * add. Once we are done adding hdr's to it, we convert the tarray to a list. + */ + +static +void encode_cmsgs(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifBinary* cmsgBinP, + struct msghdr* msgHdrP, + ERL_NIF_TERM* eCMsg) +{ + ERL_NIF_TERM ctrlBuf = MKBIN(env, cmsgBinP); // The *entire* binary + SocketTArray cmsghdrs = TARRAY_CREATE(128); + struct cmsghdr* firstP = CMSG_FIRSTHDR(msgHdrP); + struct cmsghdr* currentP; + + SSDBG( descP, ("UNIX-ESSIO", "encode_cmsgs {%d} -> entry when" + "\r\n msg ctrl len: %d" + "\r\n (ctrl) firstP: 0x%lX" + "\r\n", descP->sock, + msgHdrP->msg_controllen, firstP) ); + + for (currentP = firstP; + /* + * In *old* versions of darwin, the CMSG_FIRSTHDR does not + * check the msg_controllen, so we do it here. + * We should really test this stuff during configure, + * but for now, this will have to do. + */ +#if defined(__DARWIN__) + (msgHdrP->msg_controllen >= sizeof(struct cmsghdr)) && + (currentP != NULL); +#else + (currentP != NULL); +#endif + currentP = CMSG_NXTHDR(msgHdrP, currentP)) { + + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> process cmsg header when" + "\r\n TArray Size: %d" + "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + + /* MUST check this since on Linux the returned "cmsg" may actually + * go too far! + */ + if (((CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP)) > + msgHdrP->msg_controllen) { + + /* Ouch, fatal error - give up + * We assume we cannot trust any data if this is wrong. + */ + + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> check failed when: " + "\r\n currentP: 0x%lX" + "\r\n (current) cmsg_len: %d" + "\r\n firstP: 0x%lX" + "\r\n => %d" + "\r\n msg ctrl len: %d" + "\r\n", descP->sock, + CHARP(currentP), currentP->cmsg_len, CHARP(firstP), + (CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP), + msgHdrP->msg_controllen) ); + + TARRAY_ADD(cmsghdrs, esock_atom_bad_data); + break; + + } else { + unsigned char* dataP = UCHARP(CMSG_DATA(currentP)); + size_t dataPos = dataP - cmsgBinP->data; + size_t dataLen = + (UCHARP(currentP) + currentP->cmsg_len) - dataP; + ERL_NIF_TERM + cmsgHdr, + keys[] = + {esock_atom_level, + esock_atom_type, + esock_atom_data, + esock_atom_value}, + vals[NUM(keys)]; + size_t numKeys = NUM(keys); + BOOLEAN_T have_value; + + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> cmsg header data: " + "\r\n dataPos: %d" + "\r\n dataLen: %d" + "\r\n", descP->sock, dataPos, dataLen) ); + + vals[0] = esock_encode_level(env, currentP->cmsg_level); + vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); + have_value = esock_encode_cmsg(env, + currentP->cmsg_level, + currentP->cmsg_type, + dataP, dataLen, &vals[1], &vals[3]); + + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> " + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n", descP->sock, + keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); + if (have_value) + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> " + "\r\n %T: %T" + "\r\n", descP->sock, keys[3], vals[3]) ); + + /* Guard against cut-and-paste errors */ + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, + numKeys - (have_value ? 0 : 1), &cmsgHdr) ); + + /* And finally add it to the list... */ + TARRAY_ADD(cmsghdrs, cmsgHdr); + } + } + + SSDBG( descP, + ("UNIX-ESSIO", "encode_cmsgs {%d} -> cmsg headers processed when" + "\r\n TArray Size: %d" + "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + + /* The tarray is populated - convert it to a list */ + TARRAY_TOLIST(cmsghdrs, env, eCMsg); +} + + + +/* *** Sendfile utility functions *** */ + +/* Platform independent sendfile() function + * + * Return < 0 for terminal error + * 0 for done + * > 0 for retry with select + */ +#if defined(HAVE_SENDFILE) +static +int essio_sendfile(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + off_t offset, + size_t* countP, + int* errP) +{ + size_t pkgSize = 0; // Total sent in this call + + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile {%d,%d} -> entry" + "\r\n sockRef: %T" + "\r\n", + descP->sock, descP->sendfileHandle, sockRef) ); + + for (;;) { + size_t chunk_size = (size_t) 0x20000000UL; // 0.5 GB + size_t bytes_sent; + ssize_t res; + int error; + + /* *countP == 0 means send the whole file - use chunk size */ + if ((*countP > 0) && (*countP < chunk_size)) + chunk_size = *countP; + + { + /* Platform dependent code: + * update and check offset, set and check bytes_sent, and + * set res to >= 0 and error to 0, or + * set res to < 0 and error to sock_errno() + */ +#if defined (__linux__) + + off_t prev_offset; + + prev_offset = offset; + res = + sendfile(descP->sock, descP->sendfileHandle, + &offset, chunk_size); + error = (res < 0) ? sock_errno() : 0; + + ESOCK_ASSERT( offset >= prev_offset ); + ESOCK_ASSERT( (off_t) chunk_size >= (offset - prev_offset) ); + bytes_sent = (size_t) (offset - prev_offset); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_sendfile(%T) {%d,%d}" + "\r\n res: %d" + "\r\n bytes_sent: %lu" + "\r\n error: %d" + "\r\n", + sockRef, descP->sock, descP->sendfileHandle, + res, (unsigned long) bytes_sent, error) ); + +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__DARWIN__) + + off_t sbytes; + +#if defined(__DARWIN__) + sbytes = (off_t) chunk_size; + res = (ssize_t) + sendfile(descP->sendfileHandle, descP->sock, offset, + &sbytes, NULL, 0); +#else + sbytes = 0; + res = (ssize_t) + sendfile(descP->sendfileHandle, descP->sock, offset, + chunk_size, NULL, &sbytes, 0); +#endif + error = (res < 0) ? sock_errno() : 0; + + /* For an error return, we do not dare trust that sbytes is set + * unless the error is ERRNO_BLOCK or EINTR + * - the man page is to vague + */ + if ((res < 0) && (error != ERRNO_BLOCK) && (error != EINTR)) { + sbytes = 0; + } else { + ESOCK_ASSERT( sbytes >= 0 ); + ESOCK_ASSERT( (off_t) chunk_size >= sbytes ); + ESOCK_ASSERT( offset + sbytes >= offset ); + offset += sbytes; + } + bytes_sent = (size_t) sbytes; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_sendfile(%T) {%d,%d}" + "\r\n res: %d" + "\r\n bytes_sent: %lu" + "\r\n error: %d" + "\r\n", + sockRef, descP->sock, descP->sendfileHandle, + res, (unsigned long) bytes_sent, error) ); + +#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) + + sendfilevec_t sfvec[1]; + + sfvec[0].sfv_fd = descP->sendfileHandle; + sfvec[0].sfv_flag = 0; + sfvec[0].sfv_off = offset; + sfvec[0].sfv_len = chunk_size; + + res = sendfilev(descP->sock, sfvec, NUM(sfvec), &bytes_sent); + error = (res < 0) ? sock_errno() : 0; + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_sendfile(%T) {%d,%d}" + "\r\n res: %d" + "\r\n bytes_sent: %lu" + "\r\n error: %d" + "\r\n", + sockRef, descP->sock, descP->sendfileHandle, + res, (unsigned long) bytes_sent, error) ); + + if ((res < 0) && (error == EINVAL)) { + /* On e.b SunOS 5.10 using sfv_len > file size + * lands here - we regard this as a successful send. + * All other causes for EINVAL are avoided, + * except for .sfv_fd not seekable, which would + * give bytes_sent == 0 that we would interpret + * as end of file, which is kind of true. + */ + res = 0; + } + ESOCK_ASSERT( chunk_size >= bytes_sent ); + ESOCK_ASSERT( offset + bytes_sent >= offset ); + offset += bytes_sent; + +#else +#error "Unsupported sendfile syscall; update configure test." +#endif + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile, + &descP->sendfileCountersP->cnt, 1); + + if (bytes_sent != 0) { + + pkgSize += bytes_sent; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile_pkg, + &descP->sendfileCountersP->pkg, + 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile_byte, + &descP->sendfileCountersP->byteCnt, + bytes_sent); + + if (pkgSize > descP->sendfileCountersP->pkgMax) + descP->sendfileCountersP->pkgMax = pkgSize; + if ((descP->sendfileCountersP->maxCnt += bytes_sent) + > descP->sendfileCountersP->max) + descP->sendfileCountersP->max = + descP->sendfileCountersP->maxCnt; + } + + /* *countP == 0 means send whole file */ + if (*countP > 0) { + + *countP -= bytes_sent; + + if (*countP == 0) { // All sent + *countP = pkgSize; + return 0; + } + } + + if (res < 0) { + if (error == ERRNO_BLOCK) { + *countP = pkgSize; + return 1; + } + if (error == EINTR) + continue; + *errP = error; + return -1; + } + + if (bytes_sent == 0) { // End of input file + *countP = pkgSize; + return 0; + } + } + } // for (;;) +} + + +static +ERL_NIF_TERM essio_sendfile_errno(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + int err) +{ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(err)); + + return essio_sendfile_error(env, descP, sockRef, reason); +} + + +static +ERL_NIF_TERM essio_sendfile_error(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + SSDBG( descP, ("UNIX-ESSIO", + "essio_sendfile_error {%d} -> entry" + "\r\n sockRef: %T" + "\r\n reason: %T" + "\r\n", descP->sock, sockRef, reason) ); + + if (descP->sendfileCountersP == NULL) { + descP->sendfileCountersP = MALLOC(sizeof(ESockSendfileCounters)); + *descP->sendfileCountersP = initESockSendfileCounters; + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile_fails, + &descP->sendfileCountersP->fails, 1); + + /* XXX Should we have special treatment for EINVAL, + * such as to only fail current operation and activate + * the next from the queue? + */ + + if (descP->currentWriterP != NULL) { + + (void) DEMONP("essio_sendfile_error", + env, descP, &descP->currentWriter.mon); + + /* Fail all queued writers */ + esock_requestor_release("essio_sendfile_error", + env, descP, &descP->currentWriter); + send_error_waiting_writers(env, descP, sockRef, reason); + descP->currentWriterP = NULL; + + } + + return esock_make_error(env, reason); +} + +static +ERL_NIF_TERM essio_sendfile_select(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + size_t count) +{ + int sres; + + /* Select write for this process */ + sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef); + if (sres < 0) { + ERL_NIF_TERM reason; + + /* Internal select error */ + (void) DEMONP("essio_sendfile_select - failed", + env, descP, &descP->currentWriter.mon); + + /* Fail all queued writers */ + reason = MKT2(env, esock_atom_select_write, MKI(env, sres)); + esock_requestor_release("essio_sendfile_select - failed", + env, descP, &descP->currentWriter); + send_error_waiting_writers(env, descP, sockRef, reason); + descP->currentWriterP = NULL; + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return enif_raise_exception(env, reason); + + } else { + ErlNifUInt64 bytes_sent; + + SSDBG( descP, + ("UNIX-ESSIO", "essio_sendfile_select {%d} -> selected" + "\r\n sockRef: %T" + "\r\n sendRef: %T" + "\r\n count: %lu" + "\r\n", descP->sock, sockRef, sendRef, (unsigned long) count) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_sendfile_waits, + &descP->sendfileCountersP->waits, + 1); + + descP->writeState |= ESOCK_STATE_SELECTED; + bytes_sent = (ErlNifUInt64) count; + + return MKT2(env, esock_atom_select, MKUI64(env, bytes_sent)); + } +} + + +static +ERL_NIF_TERM essio_sendfile_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + size_t count) +{ + ErlNifUInt64 bytes_sent64u; + + SSDBG( descP, + ("UNIX-ESSIO", "essio_sendfile_ok {%d} -> entry when done" + "\r\n sockRef: %T" + "\r\n written: %lu" + "\r\n", descP->sock, sockRef, (unsigned long) count) ); + + if (descP->currentWriterP != NULL) { + + (void) DEMONP("essio_sendfile_ok -> current writer", + env, descP, &descP->currentWriter.mon); + + /* + * Ok, this write is done maybe activate the next (if any) + */ + if (! esock_activate_next_writer(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_sendfile_ok {%d} -> no more writers" + "\r\n sockRef: %T" + "\r\n", + descP->sock, sockRef) ); + + descP->currentWriterP = NULL; + } + } + + descP->writePkgMaxCnt = 0; + bytes_sent64u = (ErlNifUInt64) count; + + (void) close(descP->sendfileHandle); + descP->sendfileHandle = INVALID_HANDLE; + + return esock_make_ok2(env, MKUI64(env, bytes_sent64u)); +} + +#endif // #ifdef HAVE_SENDFILE + + +/* ==================================================================== + * + * NIF (I/O backend) Resource callback functions: dtor, stop and down + * + * ==================================================================== + */ + +extern +void essio_dtor(ErlNifEnv* env, + ESockDescriptor* descP) +{ + SGDBG( ("UNIX-ESSIO", "dtor -> entry\r\n") ); + + if (IS_SELECTED(descP)) { + /* We have used the socket in the select machinery, + * so we must have closed it properly to get here + */ + ESOCK_ASSERT( IS_CLOSED(descP->readState) ); + ESOCK_ASSERT( IS_CLOSED(descP->writeState) ); + ESOCK_ASSERT( descP->sock == INVALID_SOCKET ); + } else { + /* The socket is only opened, should be safe to close nonblocking */ + (void) sock_close(descP->sock); + descP->sock = INVALID_SOCKET; + } + + SGDBG( ("UNIX-ESSIO", "dtor -> set state and pattern\r\n") ); + descP->readState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); + descP->writeState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); + descP->pattern = (ESOCK_DESC_PATTERN_DTOR | ESOCK_STATE_CLOSED); + + esock_free_env("dtor reader", descP->currentReader.env); + descP->currentReader.env = NULL; + + esock_free_env("dtor writer", descP->currentWriter.env); + descP->currentWriter.env = NULL; + + esock_free_env("dtor acceptor", descP->currentAcceptor.env); + descP->currentAcceptor.env = NULL; + + SGDBG( ("UNIX-ESSIO", "dtor -> try free readers request queue\r\n") ); + esock_free_request_queue(&descP->readersQ); + + SGDBG( ("UNIX-ESSIO", "dtor -> try free writers request queue\r\n") ); + esock_free_request_queue(&descP->writersQ); + + SGDBG( ("UNIX-ESSIO", "dtor -> try free acceptors request queue\r\n") ); + esock_free_request_queue(&descP->acceptorsQ); + +#ifdef HAVE_SENDFILE + ESOCK_ASSERT( descP->sendfileHandle == INVALID_HANDLE ); + if (descP->sendfileCountersP != NULL) { + FREE(descP->sendfileCountersP); + descP->sendfileCountersP = NULL; + } +#endif + + esock_free_env("dtor close env", descP->closeEnv); + descP->closeEnv = NULL; + + esock_free_env("dtor meta env", descP->meta.env); + descP->meta.env = NULL; + + SGDBG( ("UNIX-ESSIO", "dtor -> done\r\n") ); +} + + +extern +void essio_stop(ErlNifEnv* env, + ESockDescriptor* descP) +{ +#ifdef HAVE_SENDFILE + if (descP->sendfileCountersP != NULL) { + ESockSendfileCounters* cntP = descP->sendfileCountersP; + + SSDBG( descP, ("UNIX-ESSIO", "esock_stop(%d) -> sendfileCounters:" + "\r\n cnt: %lu" + "\r\n byteCnt: %lu" + "\r\n fails: %lu" + "\r\n max: %lu" + "\r\n pkg: %lu" + "\r\n pkgMax %lu" + "\r\n tries: %lu" + "\r\n waits: %lu" + "\r\n", + descP->sock, + (unsigned long) cntP->cnt, + (unsigned long) cntP->byteCnt, + (unsigned long) cntP->fails, + (unsigned long) cntP->max, + (unsigned long) cntP->pkg, + (unsigned long) cntP->pkgMax, + (unsigned long) cntP->tries, + (unsigned long) cntP->waits) ); + } +#endif + + /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Inform waiting Closer, or close socket + * + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + if (! enif_is_pid_undefined(&descP->closerPid)) { + /* We have a waiting closer process after nif_close() + * - send message to trigger nif_finalize_close() + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "esock_stop(%d) -> send close msg to %T\r\n", + descP->sock, MKPID(env, &descP->closerPid)) ); + + esock_send_close_msg(env, descP, &descP->closerPid); + /* Message send frees closeEnv */ + descP->closeEnv = NULL; + descP->closeRef = esock_atom_undefined; + + } else { + int err; + + /* We do not have a closer process + * - have to do an unclean (non blocking) close */ + +#ifdef HAVE_SENDFILE + if (descP->sendfileHandle != INVALID_HANDLE) + esock_send_sendfile_deferred_close_msg(env, descP); +#endif + + err = esock_close_socket(env, descP, FALSE); + + if (err != 0) + esock_warning_msg("[UNIX-ESSIO] Failed closing socket without " + "closer process: " + "\r\n Controlling Process: %T" + "\r\n Descriptor: %d" + "\r\n Errno: %d (%T)" + "\r\n", + descP->ctrlPid, descP->sock, + err, MKA(env, erl_errno_id(err))); + } + +} + + +/* A 'down' has occured. + * Check the possible processes we monitor in turn: + * closer, controlling process (owner), connector, reader, acceptor and writer. + * + */ +extern +void essio_down(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + if (COMPARE_PIDS(&descP->closerPid, pidP) == 0) { + + /* The closer process went down + * - it will not call nif_finalize_close + */ + + enif_set_pid_undefined(&descP->closerPid); + + if (MON_EQ(&descP->closerMon, monP)) { + MON_INIT(&descP->closerMon); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down {%d} -> closer process exit\r\n", + descP->sock) ); + + } else { + // The owner is the closer so we used its monitor + + ESOCK_ASSERT( MON_EQ(&descP->ctrlMon, monP) ); + MON_INIT(&descP->ctrlMon); + enif_set_pid_undefined(&descP->ctrlPid); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down {%d} -> closer controlling process exit\r\n", + descP->sock) ); + } + + /* Since the closer went down there was one, + * hence esock_close() must have run or scheduled esock_stop(), + * or the socket has never been "selected" upon. + */ + + if (descP->closeEnv == NULL) { + int err; + + /* Since there is no closeEnv, + * esock_close() did not schedule esock_stop() + * and is about to call esock_finalize_close() but died, + * or esock_stop() has run, sent close_msg to the closer + * and cleared ->closeEnv but the closer died + * - we have to do an unclean (non blocking) socket close here + */ + +#ifdef HAVE_SENDFILE + if (descP->sendfileHandle != INVALID_HANDLE) + esock_send_sendfile_deferred_close_msg(env, descP); +#endif + + err = esock_close_socket(env, descP, FALSE); + if (err != 0) + esock_warning_msg("[UNIX-ESSIO] " + "Failed closing socket for terminating " + "closer process: " + "\r\n Closer Process: %T" + "\r\n Descriptor: %d" + "\r\n Errno: %d (%T)" + "\r\n", + MKPID(env, pidP), descP->sock, + err, MKA(env, erl_errno_id(err))); + } else { + /* Since there is a closeEnv esock_stop() has not run yet + * - when it finds that there is no closer process + * it will close the socket and ignore the close_msg + */ + esock_clear_env("essio_down - close-env", descP->closeEnv); + esock_free_env("essio_down - close-env", descP->closeEnv); + descP->closeEnv = NULL; + descP->closeRef = esock_atom_undefined; + } + + } else if (MON_EQ(&descP->ctrlMon, monP)) { + MON_INIT(&descP->ctrlMon); + /* The owner went down */ + enif_set_pid_undefined(&descP->ctrlPid); + + if (IS_OPEN(descP->readState)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down {%d} -> controller process exit" + "\r\n initiate close\r\n", + descP->sock) ); + + essio_down_ctrl(env, descP, pidP); + + descP->readState |= ESOCK_STATE_CLOSING; + descP->writeState |= ESOCK_STATE_CLOSING; + + } else { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down {%d} -> controller process exit" + "\r\n already closed or closing\r\n", + descP->sock) ); + + } + + } else if (descP->connectorP != NULL && + MON_EQ(&descP->connector.mon, monP)) { + MON_INIT(&descP->connector.mon); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down {%d} -> connector process exit\r\n", + descP->sock) ); + + /* connectorP is only set during connection. + * Forget all about the ongoing connection. + * We might end up connected, but the process that initiated + * the connection has died and will never know + */ + + esock_requestor_release("esock_down->connector", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~ESOCK_STATE_CONNECTING; + + } else { + ERL_NIF_TERM sockRef = enif_make_resource(env, descP); + + /* check all operation queue(s): acceptor, writer and reader. + * + * Is it really any point in doing this if the socket is closed? + * + */ + + if (IS_CLOSED(descP->readState)) { + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down(%T) {%d} -> stray down: %T\r\n", + sockRef, descP->sock, pidP) ); + } else { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down(%T) {%d} -> other process term\r\n", + sockRef, descP->sock) ); + + if (descP->currentReaderP != NULL) + essio_down_reader(env, descP, sockRef, pidP, monP); + if (descP->currentAcceptorP != NULL) + essio_down_acceptor(env, descP, sockRef, pidP, monP); + if (descP->currentWriterP != NULL) + essio_down_writer(env, descP, sockRef, pidP, monP); + } + } + +} + + +/* ==================================================================== */ + +/* *** Recv/recvfrom/recvmsg utility functions *** */ + +/* *** recv_check_reader *** + * + * Checks if we have a current reader and if that is us. If not, + * then we must be made to wait for our turn. This is done by pushing + * us unto the reader queue. + * Note that we do *not* actually initiate the currentReader structure + * here, since we do not actually know yet if we need to! We do that in + * the [recv|recvfrom|recvmsg]_check_result function. + */ + +static +BOOLEAN_T recv_check_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM ref, + ERL_NIF_TERM* checkResult) +{ + if (descP->currentReaderP != NULL) { + ErlNifPid caller; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (COMPARE_PIDS(&descP->currentReader.pid, &caller) != 0) { + /* Not the "current reader", so (maybe) push onto queue */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_reader {%d} -> not (current) reader" + "\r\n ref: %T" + "\r\n", descP->sock, ref) ); + + if (! esock_reader_search4pid(env, descP, &caller)) { + if (COMPARE(ref, esock_atom_zero) == 0) + goto done_ok; + esock_reader_push(env, descP, caller, ref, NULL); + *checkResult = esock_atom_select; + } else { + /* Reader already in queue */ + *checkResult = esock_raise_invalid(env, esock_atom_state); + } + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_reader {%d} -> queue (push) result: %T\r\n", + descP->sock, *checkResult) ); + + return FALSE; + } + } + + done_ok: + // Does not actually matter in this case, but ... + *checkResult = esock_atom_ok; + return TRUE; +} + + +/* *** recv_check_full *** + * + * This function is called if we filled the allocated buffer. + * But are we done yet? + * + * toRead = 0 means: Give me everything you have => maybe + * toRead > 0 means: Yes + */ + +static +ERL_NIF_TERM recv_check_full(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + + if ((toRead == 0) && + (descP->type == SOCK_STREAM)) { + + /* +++ Give us everything you have got => * + * (maybe) needs to continue +++ */ + + /* Send up each chunk of data for each of the read + * and let the erlang code assemble it: {more, Bin} + * (when complete it should return {ok, Bin}). + * We need to read at least one more time to be sure if its + * done... + * + * Also, we need to check if the rNumCnt has reached its max (rNum), + * in which case we will assume the read to be done! + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_full(%T) {%d} -> shall we continue reading?" + "\r\n read: %ld" + "\r\n rNum: %u" + "\r\n rNumCnt: %u" + "\r\n", sockRef, descP->sock, + (unsigned long) read, descP->rNum, descP->rNumCnt) ); + + res = recv_check_full_maybe_done(env, descP, read, bufP, + sockRef, recvRef); + + } else { + + /* +++ We got exactly as much as we requested => We are done +++ */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_full(%T) {%d} -> [%ld] " + "we got exactly what we could fit\r\n", + sockRef, descP->sock, (long) toRead) ); + + res = recv_check_full_done(env, descP, read, bufP, sockRef); + + } + + return res; + +} + + +/* *** recv_check_full_maybe_done *** + * + * Send up each chunk of data for each of the read + * and let the erlang code assemble it: {more, Bin} + * (when complete it should return {ok, Bin}). + * We need to read at least one more time to be sure if its + * done... + * + * Also, we need to check if the rNumCnt has reached its max (rNum), + * in which case we will assume the read to be done! + */ + +static +ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + descP->readPkgMaxCnt += read; + + descP->rNumCnt++; + if (descP->rNumCnt >= descP->rNum) { + + descP->rNumCnt = 0; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + if (descP->readPkgMaxCnt > descP->readPkgMax) + descP->readPkgMax = descP->readPkgMaxCnt; + descP->readPkgMaxCnt = 0; + + recv_update_current_reader(env, descP, sockRef); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + + return esock_make_ok2(env, MKBIN(env, bufP)); + + } + + /* Yes, we *do* need to continue reading */ + + recv_init_current_reader(env, descP, recvRef); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_full_maybe_done(%T) {%d} -> [%lu] " + "we are done for now - read more\r\n", + sockRef, descP->sock, (unsigned long)bufP->size) ); + + return MKT2(env, esock_atom_more, MKBIN(env, bufP)); +} + + + +/* *** recv_check_full_done *** + * + * A successful recv and we filled the buffer. + */ + +static +ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM data; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + descP->readPkgMaxCnt += read; + if (descP->readPkgMaxCnt > descP->readPkgMax) + descP->readPkgMax = descP->readPkgMaxCnt; + descP->readPkgMaxCnt = 0; + + recv_update_current_reader(env, descP, sockRef); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, bufP); + + return esock_make_ok2(env, data); +} + + + +/* *** recv_check_fail *** + * + * Handle recv failure. + */ + +static +ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ErlNifBinary* buf1P, + ErlNifBinary* buf2P, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + + FREE_BIN(buf1P); + if (buf2P != NULL) FREE_BIN(buf2P); + + if (saveErrno == ECONNRESET) { + + /* +++ Oops - closed +++ */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_fail(%T) {%d} -> econnreset: closed" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, recvRef) ); + + // This is a bit overkill (to count here), but just in case... + ESOCK_CNT_INC(env, descP, sockRef, esock_atom_read_fails, + &descP->readFails, 1); + + res = recv_check_fail_econnreset(env, descP, sockRef, recvRef); + + } else if ((saveErrno == ERRNO_BLOCK) || + (saveErrno == EAGAIN)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_fail(%T) {%d} -> eagain" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, recvRef) ); + + if (COMPARE(recvRef, esock_atom_zero) == 0) + res = esock_atom_ok; + else + res = recv_check_retry(env, descP, sockRef, recvRef); + + } else { + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_fail(%T) {%d} -> errno: %d\r\n" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, saveErrno, recvRef) ); + + ESOCK_CNT_INC(env, descP, sockRef, esock_atom_read_fails, + &descP->readFails, 1); + + res = recv_check_fail_gen(env, descP, saveErrno, sockRef); + } + + return res; +} + + +/* *** recv_check_fail_gen *** + * + * The recv call had a "general" failure. + */ + +static +ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + + recv_error_current_reader(env, descP, sockRef, reason); + + return esock_make_error(env, reason); +} + + +/* *** recv_check_fail_econnreset *** + * + * We detected that the socket was closed while reading. + * Inform current and waiting readers. + */ + +static +ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(ECONNRESET)); + ERL_NIF_TERM res = esock_make_error(env, reason); + + /* + * + * IF THE CURRENT PROCESS IS *NOT* THE CONTROLLING + * PROCESS, WE NEED TO INFORM IT!!! + * + * ALL WAITING PROCESSES MUST ALSO GET THE ERROR!! + * HANDLED BY THE STOP (CALLBACK) FUNCTION? + * + * SINCE THIS IS A REMOTE CLOSE, WE DON'T NEED TO WAIT + * FOR OUTPUT TO BE WRITTEN (NO ONE WILL READ), JUST + * ABORT THE SOCKET REGARDLESS OF LINGER??? + * + * + */ + + recv_error_current_reader(env, descP, sockRef, reason); + + return res; +} + + +/* *** recv_check_retry *** + * + * The recv call would have blocked, so retry. + */ + +static +ERL_NIF_TERM recv_check_retry(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + int sres; + ERL_NIF_TERM res; + + descP->rNumCnt = 0; + recv_init_current_reader(env, descP, recvRef); + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_retry(%T) {%d} -> SELECT for more" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, recvRef) ); + + if ((sres = esock_select_read(env, descP->sock, descP, NULL, + sockRef, recvRef)) < 0) { + /* Unlikely that any next reader will have better luck, + * but why not give them a shot - the queue will be cleared + */ + recv_update_current_reader(env, descP, sockRef); + + res = enif_raise_exception(env, + MKT2(env, esock_atom_select_read, + MKI(env, sres))); + } else { + descP->readState |= ESOCK_STATE_SELECTED; + res = esock_atom_select; + } + + return res; +} + + + +/* *** recv_check_partial *** + * + * Handle a successful recv which only partly filled the specified buffer. + */ + +static +ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ssize_t toRead, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + + if ((toRead == 0) || + (descP->type != SOCK_STREAM) || + (COMPARE(recvRef, esock_atom_zero) == 0)) { + + /* +++ We got it all, but since we +++ + * +++ did not fill the buffer, we +++ + * +++ must split it into a sub-binary. +++ + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_partial(%T) {%d} -> [%ld] split buffer" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, (long) toRead, + recvRef) ); + + res = recv_check_partial_done(env, descP, read, bufP, sockRef); + + } else { + /* A stream socket with specified read size + * and not a polling read, we got a partial read + * - return a select result to initiate a retry + */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_partial(%T) {%d} -> [%ld]" + " only part of message - expect more" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, (long) toRead, + recvRef) ); + + res = recv_check_partial_part(env, descP, read, + bufP, sockRef, recvRef); + } + + return res; +} + + +/* *** recv_check_partial_done *** + * + * A successful but only partial recv, which fulfilled the required read. + */ + +static +ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM data; + + descP->rNumCnt = 0; + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + descP->readPkgMaxCnt += read; + if (descP->readPkgMaxCnt > descP->readPkgMax) + descP->readPkgMax = descP->readPkgMaxCnt; + descP->readPkgMaxCnt = 0; + + recv_update_current_reader(env, descP, sockRef); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, bufP); + data = MKSBIN(env, data, 0, read); + + SSDBG( descP, + ("UNIX-ESSIO", "recv_check_partial_done(%T) {%d} -> [%ld] done\r\n", + sockRef, descP->sock, (long) read) ); + + return esock_make_ok2(env, data); +} + + +/* *** recv_check_partial_part *** + * + * A successful but only partial recv, which only partly fulfilled + * the required read. + */ + +static +ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + ErlNifBinary* bufP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM res; + int sres; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + recv_init_current_reader(env, descP, recvRef); + + /* SELECT for more data */ + + sres = esock_select_read(env, descP->sock, descP, NULL, + sockRef, recvRef); + if (sres < 0) { + /* Unlikely that any next reader will have better luck, + * but why not give them a shot - the queue will be cleared + */ + recv_update_current_reader(env, descP, sockRef); + + res = enif_raise_exception(env, + MKT2(env, esock_atom_select_read, + MKI(env, sres))); + } else { + ERL_NIF_TERM data; + + descP->readState |= ESOCK_STATE_SELECTED; + data = MKBIN(env, bufP); + data = MKSBIN(env, data, 0, read); + res = MKT2(env, esock_atom_select, data); + } + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + return res; +} + + +/* *** recv_init_current_reader *** + * + * Initiate (maybe) the currentReader structure of the descriptor. + * Including monitoring the calling process. + */ +static +void recv_init_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM recvRef) +{ + if (descP->currentReaderP == NULL) { + + ESOCK_ASSERT( enif_self(env, &descP->currentReader.pid) != NULL ); + + ESOCK_ASSERT( MONP("recv_init_current_reader -> current reader", + env, descP, + &descP->currentReader.pid, + &descP->currentReader.mon) == 0); + ESOCK_ASSERT(!descP->currentReader.env); + + descP->currentReader.env = esock_alloc_env("current-reader"); + descP->currentReader.ref = + CP_TERM(descP->currentReader.env, recvRef); + descP->currentReaderP = &descP->currentReader; + } else { + + /* + * This is a retry: + * We have done, for instance, recv(Sock, X), but only received Y < X. + * We then call recv again with size = X-Y. So, we then get a new ref. + * + * Make use of the existing environment + */ + + enif_clear_env(descP->currentReader.env); + descP->currentReader.ref = CP_TERM(descP->currentReader.env, recvRef); + } +} + + +/* *** recv_update_current_reader *** + * + * Demonitors the current reader process and pop's the reader queue. + * If there is a waiting (reader) process, then it will be assigned + * as the new current reader and a new (read) select will be done. + */ + +static +void recv_update_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef) +{ + if (descP->currentReaderP != NULL) { + + ESOCK_ASSERT( DEMONP("recv_update_current_reader", + env, descP, &descP->currentReader.mon) == 0); + + if (! esock_activate_next_reader(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_update_current_reader(%T) {%d} -> no more readers\r\n", + sockRef, descP->sock) ); + + descP->currentReaderP = NULL; + } + } +} + + +/* *** recv_error_current_reader *** + * + * Process the current reader and any waiting readers + * when a read (fatal) error has occurred. + * All waiting readers will be "aborted", that is a + * nif_abort message will be sent (with ref and reason). + */ + +static +void recv_error_current_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM reason) +{ + if (descP->currentReaderP != NULL) { + ESockRequestor req; + + esock_requestor_release("recv_error_current_reader", + env, descP, &descP->currentReader); + + req.env = NULL; /* read by reader_pop before free */ + while (esock_reader_pop(env, descP, &req)) { + + SSDBG( descP, + ("UNIX-ESSIO", "recv_error_current_reader(%T) {%d} -> abort" + "\r\n pid: %T" + "\r\n reason %T" + "\r\n", sockRef, descP->sock, + req.pid, reason) ); + + esock_send_abort_msg(env, descP, sockRef, &req, reason); + + ESOCK_ASSERT( DEMONP("recv_error_current_reader -> pop'ed reader", + env, descP, &req.mon) == 0); + } + + descP->currentReaderP = NULL; + } +} + + +/* *** essio_down_ctrl *** + * + * Stop after a downed controller (controlling process = owner process) + * + * This is 'extern' because its currently called from prim_socket_nif + * (esock_setopt_otp_ctrl_proc). + */ +extern +void essio_down_ctrl(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP) +{ + SSDBG( descP, + ("UNIX-ESSIO", "essio_down_ctrl {%d} ->" + "\r\n Pid: %T" + "\r\n", descP->sock, MKPID(env, pidP)) ); + + if (do_stop(env, descP)) { + /* esock_stop() is scheduled + * - it has to close the socket + */ + SSDBG( descP, + ("UNIX-ESSIO", "essio_down_ctrl {%d} -> stop was scheduled\r\n", + descP->sock) ); + } else { + int err; + + /* Socket is not in the select machinery + * so esock_stop() will not be called + * - we have to do an unclean (non blocking) socket close here + */ + +#ifdef HAVE_SENDFILE + if (descP->sendfileHandle != INVALID_HANDLE) + esock_send_sendfile_deferred_close_msg(env, descP); +#endif + + err = esock_close_socket(env, descP, FALSE); + if (err != 0) + esock_warning_msg("[UNIX-ESSIO] " + "Failed closing socket for terminating " + "owner process: " + "\r\n Owner Process: %T" + "\r\n Descriptor: %d" + "\r\n Errno: %d (%T)" + "\r\n", + MKPID(env, pidP), descP->sock, + err, MKA(env, erl_errno_id(err))); + } +} + + + +/* *** essio_down_acceptor *** + * + * Check and then handle a downed acceptor process. + * + */ +static +void essio_down_acceptor(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + if (MON_EQ(&descP->currentAcceptor.mon, monP)) { + MON_INIT(&descP->currentAcceptor.mon); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_acceptor(%T) {%d} -> " + "current acceptor - try activate next\r\n", + sockRef, descP->sock) ); + + if (!esock_activate_next_acceptor(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_acceptor(%T) {%d} -> no more writers\r\n", + sockRef, descP->sock) ); + + descP->readState &= ~ESOCK_STATE_ACCEPTING; + + descP->currentAcceptorP = NULL; + } + + } else { + + /* Maybe unqueue one of the waiting acceptors */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_acceptor(%T) {%d} -> " + "not current acceptor - maybe a waiting acceptor\r\n", + sockRef, descP->sock) ); + + esock_acceptor_unqueue(env, descP, NULL, pidP); + } +} + + +/* *** essio_down_writer *** + * + * Check and then handle a downed writer process. + * + */ + +static +void essio_down_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + if (MON_EQ(&descP->currentWriter.mon, monP)) { + MON_INIT(&descP->currentWriter.mon); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_writer(%T) {%d} -> " + "current writer - try activate next\r\n", + sockRef, descP->sock) ); + + if (!esock_activate_next_writer(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_writer(%T) {%d} -> no active writer\r\n", + sockRef, descP->sock) ); + + descP->currentWriterP = NULL; + } + + } else { + + /* Maybe unqueue one of the waiting writer(s) */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_writer(%T) {%d} -> " + "not current writer - maybe a waiting writer\r\n", + sockRef, descP->sock) ); + + esock_writer_unqueue(env, descP, NULL, pidP); + } +} + + +/* *** essio_down_reader *** + * + * Check and then handle a downed reader process. + * + */ + +static +void essio_down_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + if (MON_EQ(&descP->currentReader.mon, monP)) { + MON_INIT(&descP->currentReader.mon); + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_reader(%T) {%d} -> " + "current reader - try activate next\r\n", + sockRef, descP->sock) ); + + if (! esock_activate_next_reader(env, descP, sockRef)) { + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_reader(%T) {%d} -> no more readers\r\n", + sockRef, descP->sock) ); + + descP->currentReaderP = NULL; + } + + } else { + + /* Maybe unqueue one of the waiting reader(s) */ + + SSDBG( descP, + ("UNIX-ESSIO", + "essio_down_reader(%T) {%d} -> " + "not current reader - maybe a waiting reader\r\n", + sockRef, descP->sock) ); + + esock_reader_unqueue(env, descP, NULL, pidP); + } +} + + +#endif diff --git a/erts/emulator/nifs/win32/win_prim_file.c b/erts/emulator/nifs/win32/win_prim_file.c index 57797fad3936..bdbf7a19d230 100644 --- a/erts/emulator/nifs/win32/win_prim_file.c +++ b/erts/emulator/nifs/win32/win_prim_file.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson 2017-2021. All Rights Reserved. + * Copyright Ericsson 2017-2022. 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. @@ -65,11 +65,16 @@ #define TICKS_PER_SECOND (10000000ULL) #define EPOCH_DIFFERENCE (11644473600LL) +/* Note: some functions return a file time of -1 when the time is unavailable, + * rather than the documented 0, so we'll silently convert it to 0. */ \ #define FILETIME_TO_EPOCH(epoch, ft) \ do { \ ULARGE_INTEGER ull; \ ull.LowPart = (ft).dwLowDateTime; \ ull.HighPart = (ft).dwHighDateTime; \ + if (ull.QuadPart == ~0ULL) { \ + ull.QuadPart = 0; \ + } \ (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_DIFFERENCE); \ } while(0) @@ -85,7 +90,7 @@ typedef struct { efile_data_t common; HANDLE handle; /* The following field is only used when the handle has been - obtained from an already exisiting file descriptor (i.e., + obtained from an already existing file descriptor (i.e., prim_file:file_desc_to_ref/2). common.modes is set to EFILE_MODE_FROM_ALREADY_OPEN_FD when that is the case. It is needed because we can't close using handle in that case. */ @@ -428,7 +433,7 @@ static int is_path_root(const efile_path_t *path) { path_iterator++; } while(path_iterator < path_end && !IS_SLASH(*path_iterator)); - /* If we're past the end of the string and it didnt't end with a slash, + /* If we're past the end of the string and it didn't end with a slash, * then we're a root path. */ return path_iterator >= path_end && !IS_SLASH(path_start[length - 1]); } diff --git a/erts/emulator/nifs/win32/win_socket_asyncio.c b/erts/emulator/nifs/win32/win_socket_asyncio.c new file mode 100644 index 000000000000..78e93262226c --- /dev/null +++ b/erts/emulator/nifs/win32/win_socket_asyncio.c @@ -0,0 +1,11239 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2023-2023. 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% + * + * ---------------------------------------------------------------------- + * Purpose : Windows version of the asyncronous I/O backend. + * ---------------------------------------------------------------------- + * + * Misc: + * This is based of the Windows concept: I/O Completion Port. + * This feature works on "all" kinds of I/O, even file I/O. But, + * our implementation only deals with socket I/O. + * The "asynchronous" access functions (that "can" block) that we + * use are as following: + * + * * WSASend, WSASendTo, WSASendMsg, WSARecv, WSARecvFrom, WSARecvMsg + * * AccepxEx + * (this is actually a function pointer, obtained at run time by + * making a call to the WSAIoctl function with the + * SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. + * The input buffer passed to the WSAIoctl function must contain + * WSAID_ACCEPTEX). + * To get the local and remote addresses, the GetAcceptExSockaddrs + * must be called. This function is *also* a function pointer + * obtained at run time by making a call to the WSAIoctl function. + * * ConnectEx: + * (this is actually a function pointer, obtained at run time by + * The function pointer for the ConnectEx function must be + * making a call to the WSAIoctl function with the + * SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. + * The input buffer passed to the WSAIoctl function must contain + * WSAID_CONNECTEX). + * * WSASendMsg & WSARecvMsg are actually *also* function pointers!! + * + * But since we want them to "behave" the same way, we need to add + * some wrapper code to simulate the "completion behaviour". + * + * These functions (in erlang) should return simething *like* this: + * + * ok | completion | {error, Reason} + * + * And if the return value was 'completion', the caller shall expect + * the following message, when the "operation" has "completed" (success + * or failure): + * + * {'$socket', Socket, completion, {Ref, CompletionStatus}} + * + * Where 'Socket' is the socket on which the call was made (for example, + * 'socket:send(Socket, ...)), and CompletionStatus is the result of + * actual operation: ok | {error, Reason} + * + * Examples: + * * https://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancediomethod5i.html + * * https://www.codeproject.com/Articles/13382/A-simple-application-using-I-O-Completion-Ports-an + * * https://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6b.html + * + * More useful links: + * * https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex + * * https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl + * * https://learn.microsoft.com/en-us/windows/win32/winsock/socket-options-and-ioctls-2 + * + * Note: + * - + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef ESOCK_ENABLE + +// #include +// #include +// #include +#include +#include +#include + +#include + +#include "socket_int.h" +#include "socket_io.h" +#include "socket_asyncio.h" +#include "socket_util.h" +#include "socket_tarray.h" +#include "socket_dbg.h" + + +/* =================================================================== * + * * + * Local Constants * + * * + * =================================================================== */ + +#define ESAIO_OK ESOCK_IO_OK +#define ESAIO_ERR_WINSOCK_INIT 0x0001 +#define ESAIO_ERR_IOCPORT_CREATE 0x0002 +#define ESAIO_ERR_FSOCK_CREATE 0x0003 +#define ESAIO_ERR_IOCTL_ACCEPT_GET 0x0004 +#define ESAIO_ERR_IOCTL_CONNECT_GET 0x0005 +#define ESAIO_ERR_IOCTL_SENDMSG_GET 0x0006 +#define ESAIO_ERR_IOCTL_RECVMSG_GET 0x0007 +#define ESAIO_ERR_THREAD_OPTS_CREATE 0x0011 +#define ESAIO_ERR_THREAD_CREATE 0x0012 + +#define ERRNO_BLOCK WSAEWOULDBLOCK + +#define ESAIO_RECVFROM_MIN_BUFSZ 0x8000 + + +/* ======================================================================== * + * Socket wrappers * + * ======================================================================== * + */ + +#define sock_accept_O(s, as, b, al, rb, o) \ + ctrl.accept((s), (as), (b), 0, (al), (al), (rb), (o)) +#define sock_bind(s, addr, len) bind((s), (addr), (len)) +#define sock_close(s) closesocket((s)) +#define sock_connect(s, a, al) connect((s), (a), (al)) +#define sock_connect_O(s, a, al, sent, o) \ + ctrl.connect((s), (struct sockaddr*) (a), (al), NULL, 0, (sent), (o)) +#define sock_errno() WSAGetLastError() +#define sock_ioctl1(s, cc, b) \ + ioctlsocket((s), (cc), (b)) +#define sock_ioctl2(s, cc, ib, ibs, ob, obs, br) \ + WSAIoctl((s), (cc), (ib), (ibs), (ob), (obs), (br), NULL, NULL) +// #define sock_listen(s, b) listen((s), (b)) +// #define sock_name(s, addr, len) getsockname((s), (addr), (len)) +#define sock_open(domain, type, proto) socket((domain), (type), (proto)) +#define sock_open_O(domain, type, proto) \ + WSASocket((domain), (type), (proto), NULL, 0, WSA_FLAG_OVERLAPPED) +#define sock_recv_O(s,buf,flag,ol) \ + WSARecv((s), (buf), 1, NULL, (flag), (ol), NULL) +#define sock_recvfrom_O(s,buf,flag,fa,fal,ol) \ + WSARecvFrom((s), (buf), 1, NULL, (flag), (fa), (fal), (ol), NULL) +#define sock_recvmsg_O(s,msg,o) \ + ctrl.recvmsg((s), (msg), NULL, (o), NULL) +#define sock_send_O(s,buf,flag,o) \ + WSASend((s), (buf), 1, NULL, (flag), (o), NULL) +/* #define sock_sendmsg_O(s,buf,flag,ol) \ */ +/* WSASendMsg((s), (buf), (flag), NULL, (ol), NULL) */ +#define sock_sendmsg_O(s,buf,flag,ol) \ + ctrl.sendmsg((s), (buf), (flag), NULL, (ol), NULL) +#define sock_sendto_O(s,buf,flag,ta,tal,o) \ + WSASendTo((s), (buf), 1, NULL, (flag), (ta), (tal), (o), NULL) +#define sock_setopt(s,l,o,v,ln) setsockopt((s),(l),(o),(v),(ln)) + + +#define ESAIO_UPDATE_ACCEPT_CONTEXT(AS, LS) \ + sock_setopt( (AS), SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, \ + (char*) &(LS), sizeof( (LS) )) +#define ESAIO_UPDATE_CONNECT_CONTEXT(S) \ + sock_setopt((S), SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) + + +#define ESOCK_CMSG_FIRSTHDR(M) WSA_CMSG_FIRSTHDR((M)) +#define ESOCK_CMSG_NXTHDR(M,C) WSA_CMSG_NXTHDR((M), (C)) +#define ESOCK_CMSG_DATA(C) WSA_CMSG_DATA((C)) + + +/* =================================================================== * + * * + * Local types * + * * + * =================================================================== */ + +typedef struct { + Uint16 id; /* Thread id: mainly used for debugging, + * and name creation */ + + /* Thread state(s) */ +#define ESAIO_THREAD_STATE_UNDEF 0xFFFF +#define ESAIO_THREAD_STATE_INITIATING 0x0000 +#define ESAIO_THREAD_STATE_OPERATIONAL 0x0001 +#define ESAIO_THREAD_STATE_TERMINATING 0x0002 +#define ESAIO_THREAD_STATE_TERMINATED 0x0003 + + Uint16 state; /* State of the thread: + * undefined, initiating, operational, terminating */ + + /* Thread error 'state(s)'. + * If the thread is "not running", this value tells why. + */ +#define ESAIO_THREAD_ERROR_UNDEF 0xFFFF +#define ESAIO_THREAD_ERROR_OK 0x0000 +#define ESAIO_THREAD_ERROR_TOCREATE 0x0001 +#define ESAIO_THREAD_ERROR_TCREATE 0x0002 +#define ESAIO_THREAD_ERROR_GET 0x0003 +#define ESAIO_THREAD_ERROR_CMD 0x0004 + + Uint32 error; /* In case the thread exits, + * this is where the (error) reason is stored. + * Not sure i f we would ever be able to + * read this (if things are bad enough that the + * threads terminate)... + */ + + /* Do we need this? + * "The environment of the calling thread (process bound or + * callback environment) or NULL if calling from a custom + * thread not spawned by ERTS." + */ + ErlNifEnv* env; /* Used when sending messages */ + +#define ESAIO_THREAD_CNT_MAX 0xFFFFFFFF + + Uint32 cnt; /* Run-counter: mainly used for debugging */ + + unsigned int latest; /* Latest request (tag) */ +} ESAIOThreadData; + +typedef struct { + ErlNifThreadOpts* optsP; + ErlNifTid tid; + ESAIOThreadData data; +} ESAIOThread; + +typedef struct { + WSADATA wsaData; + HANDLE cport; + + SOCKET dummy; // Used for extracting AcceptEx and ConnectEx + + LPFN_ACCEPTEX accept; + LPFN_CONNECTEX connect; + LPFN_WSASENDMSG sendmsg; + LPFN_WSARECVMSG recvmsg; + + /* Thread pool stuff. + * The size of the pool is configurable. */ + DWORD numThreads; + ESAIOThread* threads; + + /* Misc stuff */ + BOOLEAN_T dbg; + BOOLEAN_T sockDbg; + + /* Counter stuff */ + ErlNifMutex* cntMtx; + ESockCounter unexpectedConnects; + ESockCounter unexpectedAccepts; + ESockCounter unexpectedWrites; + ESockCounter unexpectedReads; + ESockCounter genErrs; + ESockCounter unknownCmds; + +} ESAIOControl; + + +typedef struct __ESAIOOpDataAccept { + /* AcceptEx; ; lookup with WSAID_ACCEPTEX */ + + /* The socket, sock, is created empty and then provided as an + * argumented to AcceptEx (together with the listen socket + * and the other arguments). + * When AcceptEx has completed successfully, the socket, s, is + * usable. + * But in order for the functions sockname and peername to work, + * the SO_UPDATE_ACCEPT_CONTEXT option must be set on the + * accepted socket, sock. */ + SOCKET lsock; /* The listen socket */ + SOCKET asock; /* The "accepted" socket. + * This is created "in advance" + * and then sent to AcceptEx as an argument. + */ + char* buf; /* Size depends on domain. + * This is used for 'initial data', + * 'local address' and 'remote address'. + * We use neither of these, but the + * AcceptEx function requires this argument! + */ + ERL_NIF_TERM lSockRef; /* The listen socket */ + ERL_NIF_TERM accRef; /* The (unique) reference (ID) of the accept */ +} ESAIOOpDataAccept; + +typedef struct __ESAIOOpDataConnect { + /* ConnectEx; ; lookup with WSAID_CONNECTEX */ + + /* When ConnectEx has completed successfully, + * the socket is usable. + * *But*, in order for the functions sockname and peername to work, + * the SO_UPDATE_CONNECT_CONTEXT option must be set on the socket. + */ + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM connRef; /* The (unique) reference (ID) + * of the connect request */ +} ESAIOOpDataConnect; + +typedef struct __ESAIOOpDataSend { + /* WSASend */ + WSABUF wbuf; /* During ongoing sending, this buffer cannot + * be de-allocated. */ + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM sendRef; /* The (unique) reference (ID) + * of the send request */ +} ESAIOOpDataSend; + +typedef struct __ESAIOOpDataSendTo { + /* WSASendTo */ + WSABUF wbuf; /* During ongoing sending, this buffer cannot + * be de-allocated. */ + + /* Do we actually need these (remote address)? + * Debugging/logging? + */ + ESockAddress remoteAddr; + SOCKLEN_T remoteAddrLen; + + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM sendRef; /* The (unique) reference (ID) + * of the send request */ +} ESAIOOpDataSendTo; + +typedef struct __ESAIOOpDataSendMsg { + /* WSASendMsg; lookup with WSAID_WSASENDMSG */ + WSAMSG msg; + ErlNifIOVec* iovec; + char* ctrlBuf; + ESockAddress addr; + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM sendRef; /* The (unique) reference (ID) + * of the send request */ +} ESAIOOpDataSendMsg; + +typedef struct __ESAIOOpDataRecv { + /* WSARecv */ + DWORD toRead; /* Can be 0 (= zero) + * "just to indicate: give me what you got" + */ + ErlNifBinary buf; + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM recvRef; /* The (unique) reference (ID) + * of the recv request */ +} ESAIOOpDataRecv; + +typedef struct __ESAIOOpDataRecvFrom { + /* WSARecvFrom */ + DWORD toRead; /* Can be 0 (= zero) + * "just to indicate: give me what you got" + */ + ErlNifBinary buf; + + ESockAddress fromAddr; + INT addrLen; // SOCKLEN_T + + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM recvRef; /* The (unique) reference (ID) + * of the recv request */ +} ESAIOOpDataRecvFrom; + +typedef struct __ESAIOOpDataRecvMsg { + /* WSARecvMsg; lookup with WSAID_WSARECVMSG */ + + /* If we used I/O - vectors of different size(s), + * we would (maybe) need to malloc them, and simply + * have a pointer here. + */ + + WSAMSG msg; + WSABUF wbufs[1]; + ErlNifBinary data[1]; + ErlNifBinary ctrl; + ESockAddress addr; + + ERL_NIF_TERM sockRef; /* The socket */ + ERL_NIF_TERM recvRef; /* The (unique) reference (ID) + * of the recv request */ +} ESAIOOpDataRecvMsg; + +/* An 'operation', recv/recvfrom/recvmsg and send/sendto/sendmsg, + * accept or connect, is 'encoded' into this structure, which is + * "passed around". + */ +typedef struct __ESAIOOperation { + /* Has to be first and is *only* used by I/O Completion Port framework */ + WSAOVERLAPPED ol; + + /* *** Commands (=tags) *** */ +#define ESAIO_OP_NONE 0x0000 // None + /* "system" commands */ +#define ESAIO_OP_TERMINATE 0x0001 // Terminate +#define ESAIO_OP_DEBUG 0x0002 // Change debug level for thread(s) + /* Commands for establishing connections; connect and accept */ +#define ESAIO_OP_CONNECT 0x0011 // ConnectEx (function pointer) +#define ESAIO_OP_ACCEPT 0x0012 // AcceptEx (function pointer) + /* Commands for sending */ +#define ESAIO_OP_SEND 0x0021 // WSASend +#define ESAIO_OP_SENDTO 0x0022 // WSASendTo +#define ESAIO_OP_SENDMSG 0x0023 // WSASendMsg + /* Commands for receiving */ +#define ESAIO_OP_RECV 0x0031 // WSARecv +#define ESAIO_OP_RECVFROM 0x0032 // WSARecvFrom +#define ESAIO_OP_RECVMSG 0x0033 // WSARecvMsg + + unsigned int tag; /* The 'tag' of the operation */ + + ErlNifPid caller; /* Almost every request (not connect) + * operations require a caller */ + ErlNifEnv* env; /* Almost every request + * needs an environment */ + + /* Generic "data" field. + * This is different for each 'operation'! + * Also, not all opererations have this! + */ + + union { + /* +++ accept +++ */ + ESAIOOpDataAccept accept; + + /* +++ connect +++ */ + ESAIOOpDataConnect connect; + + /* +++ send +++ */ + ESAIOOpDataSend send; + + /* +++ sendto +++ */ + ESAIOOpDataSendTo sendto; + + /* +++ sendmsg +++ */ + ESAIOOpDataSendMsg sendmsg; + + /* +++ recv +++ */ + ESAIOOpDataRecv recv; + + /* +++ recvfrom +++ */ + ESAIOOpDataRecvFrom recvfrom; + + /* +++ recvmsg +++ */ + ESAIOOpDataRecvMsg recvmsg; + + } data; + +} ESAIOOperation; + + + +/* =================================================================== * + * * + * Function Forwards * + * * + * =================================================================== */ + +static ERL_NIF_TERM esaio_connect_stream(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen); +static ERL_NIF_TERM connect_stream_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + BOOL cres); +static ERL_NIF_TERM esaio_connect_dgram(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen); + +static ERL_NIF_TERM accept_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + BOOL ares, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + SOCKET accSock, + ErlNifPid caller); +static ERL_NIF_TERM accept_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef); +static ERL_NIF_TERM accept_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + SOCKET accSock, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM esaio_accept_accepted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid pid, + ERL_NIF_TERM sockRef, + SOCKET accSock); + +static ERL_NIF_TERM send_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int send_result, + ssize_t dataSize, + BOOLEAN_T dataInTail, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + BOOLEAN_T* cleanup); +static ERL_NIF_TERM send_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + DWORD written, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM send_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef); +static ERL_NIF_TERM send_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef); + +static BOOLEAN_T init_sendmsg_sockaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eMsg, + WSAMSG* msgP, + ESockAddress* addrP); +static BOOLEAN_T verify_sendmsg_iovec_size(const ESockData* dataP, + ESockDescriptor* descP, + ErlNifIOVec* iovec); +static BOOLEAN_T verify_sendmsg_iovec_tail(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM* tail); +static BOOLEAN_T check_sendmsg_iovec_overflow(ESockDescriptor* descP, + ErlNifIOVec* iovec, + ssize_t* dataSize); +static BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* cmsgHdrBufP, + size_t cmsgHdrBufLen, + size_t* cmsgHdrBufUsed); +static BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* bufP, + size_t rem, + size_t* used); +static BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eValue, + char* dataP, + size_t dataLen, + size_t* dataUsedP); +static BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eData, + char* dataP, + size_t dataLen, + size_t* dataUsedP); +static void encode_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + WSAMSG* msgP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM* eMsg); +static void encode_cmsgs(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifBinary* cmsgBinP, + WSAMSG* msgP, + ERL_NIF_TERM* eCMsg); +static ERL_NIF_TERM recv_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); + +static ERL_NIF_TERM recv_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recv_check_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvfrom_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvfrom_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef); +static ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvmsg_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef); +static ERL_NIF_TERM recvmsg_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef); + +#if defined(FIONREAD) +static ERL_NIF_TERM esaio_ioctl_fionread(ErlNifEnv* env, + ESockDescriptor* descP); +#endif +#if defined(SIOCATMARK) +static ERL_NIF_TERM esaio_ioctl_siocatmark(ErlNifEnv* env, + ESockDescriptor* descP); +#endif + +#if defined(SIO_TCP_INFO) +static ERL_NIF_TERM esaio_ioctl_tcp_info(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eversion); +static ERL_NIF_TERM encode_tcp_info_v0(ErlNifEnv* env, + TCP_INFO_v0* infoP); +#if defined(HAVE_TCP_INFO_V1) +static ERL_NIF_TERM encode_tcp_info_v1(ErlNifEnv* env, + TCP_INFO_v1* infoP); +#endif +static ERL_NIF_TERM encode_tcp_state(ErlNifEnv* env, + TCPSTATE state); +#endif + +#if defined(SIO_RCVALL) +static ERL_NIF_TERM esaio_ioctl_rcvall(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue); +#endif + +#if defined(SIO_RCVALL_IGMPMCAST) +static ERL_NIF_TERM esaio_ioctl_rcvall_igmpmcast(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue); +#endif + +#if defined(SIO_RCVALL_MCAST) +static ERL_NIF_TERM esaio_ioctl_rcvall_mcast(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue); +#endif + + +static void* esaio_completion_main(void* threadDataP); +static BOOLEAN_T esaio_completion_terminate(ESAIOThreadData* dataP, + OVERLAPPED* ovl); +static BOOLEAN_T esaio_completion_unknown(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + DWORD numBytes, + int error); +static void esaio_completion_fail(ErlNifEnv* env, + ESockDescriptor* descP, + const char* opStr, + int error, + BOOLEAN_T inform); + +static BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataConnect* opDataP, + int error); +static void esaio_completion_connect_success(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP); +static void esaio_completion_connect_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP); +static void esaio_completion_connect_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP, + int error); +static void esaio_completion_connect_completed(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataPP); +static void esaio_completion_connect_not_active(ESockDescriptor* descP); +static void esaio_completion_connect_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); + +static BOOLEAN_T esaio_completion_accept(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + int error); +static void esaio_completion_accept_success(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP); +static void esaio_completion_accept_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP); +static void esaio_completion_accept_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + int error); +static void esaio_completion_accept_completed(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + ESockRequestor* reqP); +static void esaio_completion_accept_not_active(ESockDescriptor* descP); +static void esaio_completion_accept_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); + +static BOOLEAN_T esaio_completion_send(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP, + int error); +static void esaio_completion_send_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP); +static void esaio_completion_send_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP); +static void esaio_completion_send_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP, + int error); +static void esaio_completion_send_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* sender, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + DWORD toWrite, + ESockRequestor* reqP); +static ERL_NIF_TERM esaio_completion_send_done(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + DWORD written); +static ERL_NIF_TERM esaio_completion_send_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + DWORD written); +static void esaio_completion_send_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); +static void esaio_completion_send_not_active(ESockDescriptor* descP); +static BOOLEAN_T esaio_completion_sendto(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP, + int error); +static void esaio_completion_sendto_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP); +static void esaio_completion_sendto_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP); +static void esaio_completion_sendto_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP, + int error); +static void esaio_completion_sendto_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); +static BOOLEAN_T esaio_completion_sendmsg(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP, + int error); +static void esaio_completion_sendmsg_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP); +static void esaio_completion_sendmsg_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP); +static void esaio_completion_sendmsg_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP, + int error); +static void esaio_completion_sendmsg_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); +static BOOLEAN_T esaio_completion_recv(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + int error); +static void esaio_completion_recv_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP); +static void esaio_completion_recv_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP); +static void esaio_completion_recv_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + int error); +static void esaio_completion_recv_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + ESockRequestor* reqP); +static ERL_NIF_TERM esaio_completion_recv_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + DWORD flags); +static ERL_NIF_TERM esaio_completion_recv_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags); +static ERL_NIF_TERM esaio_completion_recv_partial_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ssize_t read, + DWORD flags); +static ERL_NIF_TERM esaio_completion_recv_partial_part(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ssize_t read, + DWORD flags); +static void esaio_completion_recv_not_active(ESockDescriptor* descP); +static void esaio_completion_recv_closed(ESockDescriptor* descP, + int error); +static void esaio_completion_recv_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); +static BOOLEAN_T esaio_completion_recvfrom(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error); +static void esaio_completion_recvfrom_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP); +static void esaio_completion_recvfrom_more_data(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error); +static void esaio_completion_recvfrom_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP); +static void esaio_completion_recvfrom_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error); +static void esaio_completion_recvfrom_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + ESockRequestor* reqP); +static ERL_NIF_TERM esaio_completion_recvfrom_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvFrom* opDataP, + DWORD flags); +static ERL_NIF_TERM esaio_completion_recvfrom_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvFrom* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags); +static void esaio_completion_recvfrom_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); +static BOOLEAN_T esaio_completion_recvmsg(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + int error); +static void esaio_completion_recvmsg_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP); +static void esaio_completion_recvmsg_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP); +static void esaio_completion_recvmsg_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + int error); +static void esaio_completion_recvmsg_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + ESockRequestor* reqP); +static ERL_NIF_TERM esaio_completion_recvmsg_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvMsg* opDataP, + DWORD flags); +static ERL_NIF_TERM esaio_completion_recvmsg_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvMsg* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags); +static void esaio_completion_recvmsg_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform); + +static ERL_NIF_TERM esaio_completion_get_ovl_result_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error); + +static BOOL get_send_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* written); +static BOOL get_recv_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* read, + DWORD* flags); +static BOOL get_recvmsg_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* read); +static BOOL get_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* transfer, + DWORD* flags); + +static void esaio_completion_inc(ESAIOThreadData* dataP); + +static int esaio_add_socket(ESockDescriptor* descP); + +static void esaio_send_completion_msg(ErlNifEnv* sendEnv, + ESockDescriptor* descP, + ErlNifPid* pid, + ErlNifEnv* msgEnv, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef); +static ERL_NIF_TERM mk_completion_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM completionRef); + +static void esaio_down_acceptor(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); +static void esaio_down_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); +static void esaio_down_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP); + +static BOOLEAN_T do_stop(ErlNifEnv* env, + ESockDescriptor* descP); + + +/* =================================================================== * + * * + * Local (global) variables * + * * + * =================================================================== */ + +static ESAIOControl ctrl = {0}; + + + +/* =================================================================== * + * * + * Various esaio macros * + * * + * =================================================================== */ + +/* Global socket debug */ +#define SGDBG( proto ) ESOCK_DBG_PRINTF( ctrl.dbg , proto ) + +/* These are just wrapper macros for the I/O Completion Port */ +#define ESAIO_IOCP_CREATE(NT) \ + CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long) 0, (NT)) +#define ESAIO_IOCP_ADD(SOCK, DP) \ + CreateIoCompletionPort((SOCK), ctrl.cport, (ULONG*) (DP), 0) + +/* These are just wrapper macros for the I/O Completion Port queue */ +#define ESAIO_IOCQ_POP(NB, DP, OLP) \ + GetQueuedCompletionStatus(ctrl.cport, (DP), (DP), (OLP), INFINITE) +#define ESAIO_IOCQ_PUSH(OP) \ + PostQueuedCompletionStatus(ctrl.cport, 0, 0, (OVERLAPPED*) (OP)) +#define ESAIO_IOCQ_CANCEL(H, OP) \ + CancelIoEx((H), (OVERLAPPED*) (OP)) + + +/* =================================================================== * + * * + * I/O Backend exports * + * * + * =================================================================== */ + + +/* ******************************************************************* + * This function is called during (esock) nif loading + * The only argument that we actually *need* is the 'numThreads'. + * 'dataP' is just for convenience (dbg and stuff). + */ +extern +int esaio_init(unsigned int numThreads, + const ESockData* dataP) +{ + int ires, save_errno; + unsigned int i; + DWORD dummy; + GUID guidAcceptEx = WSAID_ACCEPTEX; + GUID guidConnectEx = WSAID_CONNECTEX; + GUID guidSendMsg = WSAID_WSASENDMSG; + GUID guidRecvMsg = WSAID_WSARECVMSG; + + /* Enabling this results in a core dump when calling socket:accept + * multiple times (the second call fails in env alloc).! + */ + // ctrl.dbg = TRUE; + ctrl.dbg = dataP->dbg; + ctrl.sockDbg = dataP->sockDbg; + + SGDBG( ("WIN-ESAIO", "esaio_init -> entry\r\n") ); + + ctrl.cntMtx = MCREATE("win-esaio.cnt"); + ctrl.unexpectedConnects = 0; + ctrl.unexpectedAccepts = 0; + ctrl.unexpectedWrites = 0; + ctrl.unexpectedReads = 0; + ctrl.genErrs = 0; + ctrl.unknownCmds = 0; + + /* We should actually check the value of 'numThreads' + * Since if its zero (the default), we should instead + * assign: 2 * 'number of schedulers' + * Or shall we trust the 'prim_socket' preloaded to + * select the proper value? + */ + ctrl.numThreads = (DWORD) numThreads; + + // Initialize Winsock + SGDBG( ("WIN-ESAIO", "esaio_init -> try initialize winsock\r\n") ); + ires = WSAStartup(MAKEWORD(2, 2), &ctrl.wsaData); + if (ires != NO_ERROR) { + save_errno = sock_errno(); + + esock_error_msg("Failed initialize winsock: %d" + "\r\n %s (%d)" + "\r\n", + ires, erl_errno_id(save_errno), save_errno); + + return ESAIO_ERR_WINSOCK_INIT; + } + + // Create a handle for the completion port + SGDBG( ("WIN-ESAIO", "esaio_init -> try create I/O completion port\r\n") ); + ctrl.cport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, (u_long) 0, ctrl.numThreads); + if (ctrl.cport == NULL) { + save_errno = sock_errno(); + + esock_error_msg("Failed create I/O Completion Port:" + "\r\n %s (%d)" + "\r\n", erl_errno_id(save_errno), save_errno); + + WSACleanup(); + + return ESAIO_ERR_IOCPORT_CREATE; + } + + + /* Create the "dummy" socket and then + * extract the AcceptEx and ConnectEx functions. + */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try create 'dummy' socket\r\n") ); + ctrl.dummy = sock_open(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (ctrl.dummy == INVALID_SOCKET) { + save_errno = sock_errno(); + + esock_error_msg("Failed create 'dummy' socket: " + "\r\n %s (%d)" + "\r\n", + erl_errno_id(save_errno), save_errno); + + WSACleanup(); + + return ESAIO_ERR_FSOCK_CREATE; + } + + + /* Load the AcceptEx function into memory using WSAIoctl. + * The WSAIoctl function is an extension of the ioctlsocket() + * function that can use overlapped I/O. + * The function's 3rd through 6th parameters are input and output + * buffers where we pass the pointer to our AcceptEx function. + * This is used so that we can call the AcceptEx function directly, + * rather than refer to the Mswsock.lib library. + */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try extract 'accept' function\r\n") ); + ires = WSAIoctl(ctrl.dummy, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guidAcceptEx, sizeof (guidAcceptEx), + &ctrl.accept, sizeof (ctrl.accept), + &dummy, NULL, NULL); + if (ires == SOCKET_ERROR) { + save_errno = sock_errno(); + + esock_error_msg("Failed extracting 'accept' function: %d" + "\r\n %s (%d)" + "\r\n", + ires, erl_errno_id(save_errno), save_errno); + + (void) sock_close(ctrl.dummy); + ctrl.dummy = INVALID_SOCKET; + ctrl.accept = NULL; + + WSACleanup(); + + return ESAIO_ERR_IOCTL_ACCEPT_GET; + } + + + /* Basically the same as for AcceptEx above */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try extract 'connect' function\r\n") ); + ires = WSAIoctl(ctrl.dummy, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guidConnectEx, sizeof (guidConnectEx), + &ctrl.connect, sizeof (ctrl.connect), + &dummy, NULL, NULL); + if (ires == SOCKET_ERROR) { + save_errno = sock_errno(); + + esock_error_msg("Failed extracting 'connect' function: %d" + "\r\n %s (%d)" + "\r\n", + ires, erl_errno_id(save_errno), save_errno); + + (void) sock_close(ctrl.dummy); + ctrl.dummy = INVALID_SOCKET; + ctrl.accept = NULL; + + WSACleanup(); + return ESAIO_ERR_IOCTL_CONNECT_GET; + } + + + /* Basically the same as for AcceptEx above */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try extract 'sendmsg' function\r\n") ); + ires = WSAIoctl(ctrl.dummy, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guidSendMsg, sizeof (guidSendMsg), + &ctrl.sendmsg, sizeof (ctrl.sendmsg), + &dummy, NULL, NULL); + if (ires == SOCKET_ERROR) { + save_errno = sock_errno(); + + esock_error_msg("Failed extracting 'sendmsg' function: %d" + "\r\n %s (%d)" + "\r\n", + ires, erl_errno_id(save_errno), save_errno); + + (void) sock_close(ctrl.dummy); + ctrl.dummy = INVALID_SOCKET; + ctrl.accept = NULL; + ctrl.connect = NULL; + + WSACleanup(); + return ESAIO_ERR_IOCTL_SENDMSG_GET; + } + + + /* Basically the same as for AcceptEx above */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try extract 'recvmsg' function\r\n") ); + ires = WSAIoctl(ctrl.dummy, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guidRecvMsg, sizeof (guidRecvMsg), + &ctrl.recvmsg, sizeof (ctrl.recvmsg), + &dummy, NULL, NULL); + if (ires == SOCKET_ERROR) { + save_errno = sock_errno(); + + esock_error_msg("Failed extracting 'recvmsg' function: %d" + "\r\n %s (%d)" + "\r\n", + ires, erl_errno_id(save_errno), save_errno); + + (void) sock_close(ctrl.dummy); + ctrl.dummy = INVALID_SOCKET; + ctrl.accept = NULL; + ctrl.connect = NULL; + ctrl.sendmsg = NULL; + + WSACleanup(); + return ESAIO_ERR_IOCTL_RECVMSG_GET; + } + + + /* + * Create the completion port thread pool. + */ + SGDBG( ("WIN-ESAIO", "esaio_init -> try alloc thread pool memory\r\n") ); + ctrl.threads = MALLOC(numThreads * sizeof(ESAIOThread)); + ESOCK_ASSERT( ctrl.threads != NULL ); + + SGDBG( ("WIN-ESAIO", "esaio_init -> basic init of thread data\r\n") ); + for (i = 0; i < numThreads; i++) { + ctrl.threads[i].data.id = i; + ctrl.threads[i].data.state = ESAIO_THREAD_STATE_UNDEF; + ctrl.threads[i].data.error = ESAIO_THREAD_ERROR_UNDEF; + ctrl.threads[i].data.env = NULL; + ctrl.threads[i].data.cnt = 0; + } + + SGDBG( ("WIN-ESAIO", "esaio_init -> try create thread(s)\r\n") ); + for (i = 0; i < numThreads; i++) { + char buf[64]; /* Buffer used for building the names */ + int j; + + /* We set these here to avoid raise with the thread. + * *If* we fail in the creation, then we set an error */ + + ctrl.threads[i].data.state = ESAIO_THREAD_STATE_INITIATING; + ctrl.threads[i].data.error = ESAIO_THREAD_ERROR_OK; + + SGDBG( ("WIN-ESAIO", + "esaio_init -> try create %d thread opts\r\n", i) ); + sprintf(buf, "esaio-opts[%d]", i); + ctrl.threads[i].optsP = TOCREATE(buf); + if (ctrl.threads[i].optsP == NULL) { + esock_error_msg("Failed create thread opts %d\r\n"); + + ctrl.threads[i].data.error = ESAIO_THREAD_ERROR_TOCREATE; + + for (j = 0; j < i; j++) { + SGDBG( ("WIN-ESAIO", + "esaio_init -> destroy thread opts %d\r\n", j) ); + TODESTROY(ctrl.threads[j].optsP); + } + return ESAIO_ERR_THREAD_OPTS_CREATE; + } + + SGDBG( ("WIN-ESAIO", + "esaio_init -> try create thread %d\r\n", i) ); + sprintf(buf, "esaio[%d]", i); + if (0 != TCREATE(buf, + &ctrl.threads[i].tid, + esaio_completion_main, + (void*) &ctrl.threads[i].data, + ctrl.threads[i].optsP)) { + + ctrl.threads[i].data.error = ESAIO_THREAD_ERROR_TCREATE; + + for (j = 0; j <= i; j++) { + SGDBG( ("WIN-ESAIO", + "esaio_init -> destroy thread opts %d\r\n", j) ); + TODESTROY(ctrl.threads[j].optsP); + } + return ESAIO_ERR_THREAD_CREATE; + } + + } + + + SGDBG( ("WIN-ESAIO", "esaio_init -> done\r\n") ); + + return ESAIO_OK; +} + + + +/* ******************************************************************* + * Finish, terminate, the ESock Async I/O backend. + * This means principally to terminate (threads of) the thread pool. + * Issue a "message" via PostQueuedCompletionStatus + * instructing all (completion) threads to terminate. + */ +extern +void esaio_finish() +{ + int t, lastThread; + + SGDBG( ("WIN-ESAIO", "esaio_finish -> entry\r\n") ); + + if (ctrl.dummy != INVALID_SOCKET) { + SGDBG( ("WIN-ESAIO", "esaio_finish -> close 'dummy' socket\r\n") ); + (void) sock_close(ctrl.dummy); + ctrl.dummy = INVALID_SOCKET; + } + + SGDBG( ("WIN-ESAIO", + "esaio_finish -> try terminate %d worker threads\r\n", + ctrl.numThreads) ); + for (t = 0, lastThread = -1, lastThread; t < ctrl.numThreads; t++) { + ESAIOOperation* opP; + BOOL qres; + + SGDBG( ("WIN-ESAIO", + "esaio_finish -> " + "[%d] try allocate (terminate-) operation\r\n", t) ); + + /* Where is this FREE'ed?? + * By the thread after it has been received? + */ + + opP = MALLOC( sizeof(ESAIOOperation) ); + + /* We should actually check that the alloc was successful + * and if not ... + * Note that this function is only called when we are terminating + * the VM. So, is there actuall any pointy in "doing" something? + * Or should we solve this another way? Instead of allocating + * a memory block; Send in a constant, ESAIO_OP_TERMINATE, + * *instead of* the overlapped pointer! + */ + + /* If this dows not work, there is not much we can do! + * And since this is *only* done when we terminate the VM... + */ + + if (opP != NULL) { + sys_memzero((char *) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_TERMINATE; + + SGDBG( ("WIN-ESAIO", + "esaio_finish -> " + "try post (terminate-) package %d\r\n", t) ); + + qres = PostQueuedCompletionStatus(ctrl.cport, + 0, 0, (OVERLAPPED*) opP); + + if (!qres) { + int save_errno = sock_errno(); + esock_error_msg("Failed posting 'terminate' command: " + "\r\n %s (%d)" + "\r\n", erl_errno_id(save_errno), save_errno); + break; + } else { + lastThread = t; + } + + } else { + + SGDBG( ("WIN-ESAIO", + "esaio_finish -> " + "failed allocate (terminate-) operation %d\r\n", t) ); + + } + } + + if (lastThread >= 0) { + SGDBG( ("WIN-ESAIO", + "esaio_finish -> await (worker) thread(s) termination\r\n") ); + for (t = 0; t < (lastThread+1); t++) { + + SGDBG( ("WIN-ESAIO", + "esaio_finish -> try join with thread %d\r\n", t) ); + + (void) TJOIN(ctrl.threads[t].tid, NULL); + + SGDBG( ("WIN-ESAIO", "esaio_finish -> joined with %d\r\n", t) ); + + } + } + + /* This is overkill, + * since this function, esaio_finish, is called when the VM is halt'ing... + * ...but just to be a nice citizen... + */ + SGDBG( ("WIN-ESAIO", "esaio_finish -> free the thread pool data\r\n") ); + FREE( ctrl.threads ); + + SGDBG( ("WIN-ESAIO", "esaio_finish -> invalidate functions\r\n") ); + ctrl.accept = NULL; + ctrl.connect = NULL; + + SGDBG( ("WIN-ESAIO", "esaio_finish -> done\r\n") ); + + return; +} + + + +/* ******************************************************************* + * esaio_info - Return info "about" this I/O backend. + */ + +extern +ERL_NIF_TERM esaio_info(ErlNifEnv* env) +{ + ERL_NIF_TERM info, numThreads, + numUnexpAccs, numUnexpConns, numUnexpWs, numUnexpRs, + numGenErrs, + numUnknownCmds; + + numThreads = MKUI(env, ctrl.numThreads); + + MLOCK(ctrl.cntMtx); + + numUnexpConns = MKUI(env, ctrl.unexpectedConnects); + numUnexpAccs = MKUI(env, ctrl.unexpectedAccepts); + numUnexpWs = MKUI(env, ctrl.unexpectedWrites); + numUnexpRs = MKUI(env, ctrl.unexpectedReads); + numGenErrs = MKUI(env, ctrl.genErrs); + numUnknownCmds = MKUI(env, ctrl.unknownCmds); + + MUNLOCK(ctrl.cntMtx); + + { + ERL_NIF_TERM cntKeys[] = {esock_atom_num_unexpected_connects, + esock_atom_num_unexpected_accepts, + esock_atom_num_unexpected_writes, + esock_atom_num_unexpected_reads, + esock_atom_num_general_errors, + esock_atom_num_unknown_cmds}; + ERL_NIF_TERM cntVals[] = {numUnexpConns, numUnexpAccs, + numUnexpWs, numUnexpRs, + numGenErrs, + numUnknownCmds}; + unsigned int numCntKeys = NUM(cntKeys); + unsigned int numCntVals = NUM(cntVals); + ERL_NIF_TERM counters; + + ESOCK_ASSERT( numCntKeys == numCntVals ); + ESOCK_ASSERT( MKMA(env, cntKeys, cntVals, numCntKeys, &counters) ); + + { + ERL_NIF_TERM keys[] = {esock_atom_name, + esock_atom_num_threads, + esock_atom_counters}; + ERL_NIF_TERM vals[] = {MKA(env, "win_esaio"), + numThreads, + counters}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &info) ); + } + } + + return info; +} + + + +/* ******************************************************************* + * esaio_open_plain - create an endpoint (from an existing fd) for + * communication. + * + * Create an *overlapped* socket, then add it to the I/O + * completion port. + */ + +extern +ERL_NIF_TERM esaio_open_plain(ErlNifEnv* env, + int domain, + int type, + int protocol, + ERL_NIF_TERM eopts, + const ESockData* dataP) +{ + /* We do not actually need the dataP since we already have the dbg... */ + BOOLEAN_T dbg = esock_open_is_debug(env, eopts, dataP->sockDbg); + BOOLEAN_T useReg = esock_open_use_registry(env, eopts, dataP->useReg); + ESockDescriptor* descP; + ERL_NIF_TERM sockRef; + int proto = protocol; + DWORD dwFlags = WSA_FLAG_OVERLAPPED; + SOCKET sock = INVALID_SOCKET; + ErlNifPid self; + int res, save_errno; + + /* Keep track of the creator + * This should not be a problem, but just in case + * the *open* function is used with the wrong kind + * of environment... + */ + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + SSDBG2( dbg, + ("WIN-ESAIO", "esaio_open_plain -> entry with" + "\r\n domain: %d" + "\r\n type: %d" + "\r\n protocol: %d" + "\r\n eopts: %T" + "\r\n", domain, type, protocol, eopts) ); + + sock = sock_open_O(domain, type, proto); + + if (sock == INVALID_SOCKET) { + save_errno = sock_errno(); + return esock_make_error_errno(env, save_errno); + } + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> open success: %d\r\n", sock) ); + + /* NOTE that if the protocol = 0 (default) and the domain is not + * local (AF_LOCAL) we need to explicitly get the protocol here! + */ + + if (proto == 0) + (void) esock_open_which_protocol(sock, &proto); + + /* Create and initiate the socket "descriptor" */ + descP = esock_alloc_descriptor(sock); + descP->ctrlPid = self; + descP->domain = domain; + descP->type = type; + descP->protocol = proto; + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> add to completion port\r\n") ); + + if (ESAIO_OK != (save_errno = esaio_add_socket(descP))) { + // See esock_dtor for what needs done! + ERL_NIF_TERM tag = esock_atom_add_socket; + ERL_NIF_TERM reason = MKA(env, erl_errno_id(save_errno)); + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> " + "failed adding socket to completion port: " + "%T (%d)\r\n", reason, save_errno) ); + + esock_dealloc_descriptor(env, descP); + sock_close(sock); + + /* This should really be: + * {error, {invalid, {add_to_completion_port, Reason}}} + */ + + return esock_make_error_t2r(env, tag, reason); + } + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> create socket ref\r\n") ); + + sockRef = enif_make_resource(env, descP); + enif_release_resource(descP); + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> monitor owner %T\r\n", descP->ctrlPid) ); + + ESOCK_ASSERT( MONP("esaio_open -> ctrl", + env, descP, + &descP->ctrlPid, + &descP->ctrlMon) == 0 ); + + descP->dbg = dbg; + descP->useReg = useReg; + esock_inc_socket(domain, type, proto); + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> maybe update registry\r\n") ); + + /* And finally (maybe) update the registry */ + if (descP->useReg) esock_send_reg_add_msg(env, descP, sockRef); + + SSDBG2( dbg, ("WIN-ESAIO", + "esaio_open_plain -> done\r\n") ); + + return esock_make_ok2(env, sockRef); +} + + + +/* ******************************************************************* + * esaio_bind - Bind a name to a socket. + * + */ +extern +ERL_NIF_TERM esaio_bind(ErlNifEnv* env, + ESockDescriptor* descP, + ESockAddress* sockAddrP, + SOCKLEN_T addrLen) +{ + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + if (sock_bind(descP->sock, &sockAddrP->sa, addrLen) < 0) { + return esock_make_error_errno(env, sock_errno()); + } + + descP->writeState |= ESOCK_STATE_BOUND; + + return esock_atom_ok; +} + + + +/* ******************************************************************* + * esaio_connect - Connect the socket to a specified address + * + * The function we use here, ConnectEx, is intended for STREAM/TCP. + * But (traditional) connect can be used with DGRAM/UDP. + * So, does ConnectEx work with DGRAM/UDP sockets? I think not. + * So we may need to test what kind of socket we have, and for + * DGRAM/UDP use the "old" connect: + * + * if (type == DGRAM) && (protocol == UDP) + * connect(...); + * else + * ConnectEx(...); + * + * Quote from the Microsoft documentation: + * "The ConnectEx function can only be used with connection-oriented sockets. + * The socket passed in the s parameter must be created with a socket type + * of SOCK_STREAM, SOCK_RDM, or SOCK_SEQPACKET." + * + * Quote from the Microsoft documentation: + * When the ConnectEx function successfully completes, the "connected socket" + * can be passed to only the following functions: + * + * * ReadFile (not provided by our API) + * * WriteFile (not provided by our API) + * * send or WSASend (send not used by us) + * * recv or WSARecv (recv not used by us) + * * TransmitFile (not provided by our API) + * * closesocket + * + * Socket used *must* be *bound* before calling ConnectEx! + */ + +extern +ERL_NIF_TERM esaio_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen) +{ + /* + * Verify that we are in the proper state + */ + + SSDBG( descP, + ("WIN-ESAIO", "esaio_connect(%T, %d) -> verify open\r\n", + sockRef, descP->sock) ); + + if (! IS_OPEN(descP->writeState)) + return esock_make_error(env, esock_atom_closed); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_connect(%T, %d) -> verify type: %s\r\n", + sockRef, descP->sock, TYPE2STR(descP->type)) ); + + switch (descP->type) { + case SOCK_STREAM: + return esaio_connect_stream(env, + descP, sockRef, connRef, + addrP, addrLen); + break; + + case SOCK_DGRAM: + return esaio_connect_dgram(env, + descP, sockRef, connRef, + addrP, addrLen); + break; + + default: + return enif_make_badarg(env); + } +} + + + +/* ******************************************************************* + * esaio_connect_stream - Connect the (stream) socket + */ +static +ERL_NIF_TERM esaio_connect_stream(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen) +{ + int save_errno; + BOOL cres; + ESAIOOperation* opP; + ERL_NIF_TERM eres; + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + + /* ConnectEx *requires* the socket to be bound */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_connect_stream(%T) -> verify bound\r\n", sockRef) ); + if (! IS_BOUND(descP->writeState)) + return esock_make_error(env, esock_atom_not_bound); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_connect_stream(%T) -> check if ongoing\r\n", + sockRef) ); + if (descP->connectorP != NULL) { + + /* Connect already in progress, check if its us */ + + if (COMPARE_PIDS(&self, &descP->connector.pid) != 0) { + /* *Other* process has connect in progress */ + if (addrP != NULL) { + eres = esock_make_error(env, esock_atom_already); + } else { + /* This is a bad call sequence + * - connect without an address is only allowed + * for the connecting process + */ + eres = esock_raise_invalid(env, esock_atom_state); + } + } else { + + /* TRHIS IS NOT HOW IT WORKS ON WINDOWS! + * This function should never be called *again* + * The completion message contains the full and final answer. + * No need to call again! + */ + + eres = esock_raise_invalid(env, esock_atom_state); + } + + } else if (addrP == NULL) { + + /* This is a bad call sequence + * - connect without an address is not valid on Windows. + */ + eres = esock_raise_invalid(env, esock_atom_state); + + } else { + + DWORD sentDummy = 0; + + /* No connect in progress */ + + /* Initial connect call, with address */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_connect_stream(%T) -> allocate (connect) operation\r\n", + sockRef) ); + + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_CONNECT; + + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + + /* Initiate connector */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_connect_stream(%T) -> initiate connector\r\n", + sockRef) ); + + descP->connector.pid = self; + ESOCK_ASSERT( MONP("esaio_connect_stream -> conn", + env, descP, + &self, &descP->connector.mon) == 0 ); + descP->connector.dataP = (void*) opP; + descP->connector.env = esock_alloc_env("connector"); + descP->connector.ref = CP_TERM(descP->connector.env, connRef); + descP->connectorP = &descP->connector; + descP->writeState |= + (ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + + opP->env = esock_alloc_env("esaio-connect-stream"); + opP->caller = self; + opP->data.connect.sockRef = CP_TERM(opP->env, sockRef); + opP->data.connect.connRef = CP_TERM(opP->env, connRef); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_connect_stream {%d} -> try connect\r\n", + descP->sock) ); + + /* + * BOOL LpfnConnectex( + * [in] SOCKET s, + * [in] const sockaddr *name, + * [in] int namelen, + * [in, optional] PVOID lpSendBuffer, + * [in] DWORD dwSendDataLength, + * [out] LPDWORD lpdwBytesSent, + * [in] LPOVERLAPPED lpOverlapped + * ) + */ + + cres = sock_connect_O(descP->sock, + addrP, addrLen, + &sentDummy, (OVERLAPPED*) opP); + + /* + * We need to keep using the requestor "queues"! + * That is the "only" way to handle the monitoring of + * the requestor. + * That is if the request (for instance a connect) is + * is scheduled, WSA_IO_PENDING, then we need to store + * the info about the requestor somewhere we can access it, + * in case the requestor for example dies (and we need to + * clean up). + */ + + eres = connect_stream_check_result(env, descP, opP, cres); + + } + + SSDBG( descP, ("WIN-ESAIO", "esaio_connect {%d} -> done with" + "\r\n eres: %T" + "\r\n", + descP->sock, eres) ); + + return eres; +} + + +static +ERL_NIF_TERM connect_stream_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + BOOL cres) +{ + ERL_NIF_TERM eres, tag, reason; + int save_errno; + + if (cres) { + + /* Success already! */ + + int err; + + SSDBG( descP, + ("WIN-ESAIO", + "connect_stream_check_result(%d) -> connected\r\n", + descP->sock) ); + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("connect_stream_check_result -> success", + env, descP, &descP->connector); + descP->connectorP = NULL; + + /* We need to make sure peername and sockname works! */ + + SSDBG( descP, + ("WIN-ESAIO", + "connect_stream_check_result {%d} -> " + "update connect context\r\n", + descP->sock) ); + + err = ESAIO_UPDATE_CONNECT_CONTEXT( descP->sock ); + + if (err == 0) { + + descP->writeState &= + ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + descP->writeState |= ESOCK_STATE_CONNECTED; + + eres = esock_atom_ok; + + } else { + + save_errno = sock_errno(); + tag = esock_atom_update_connect_context; + reason = ENO2T(env, save_errno); + + SSDBG( descP, ("WIN-ESAIO", + "connect_stream_check_result(%d) -> " + "connect context update failed: %T\r\n", + descP->sock, reason) ); + + sock_close(descP->sock); + descP->writeState = ESOCK_STATE_CLOSED; + + WSACleanup(); + + eres = esock_make_error_t2r(env, tag, reason); + } + + } else { + + /* Connect returned error, check which */ + + save_errno = sock_errno(); + + if (save_errno == WSA_IO_PENDING) { + + SSDBG( descP, + ("WIN-ESAIO", + "connect_stream_check_result(%d) -> connect scheduled\r\n", + descP->sock) ); + + eres = esock_atom_completion; + + } else { + ERL_NIF_TERM ereason = ENO2T(env, save_errno); + + SSDBG( descP, ("WIN-ESAIO", + "connect_stream_check_result(%d) -> " + "connect attempt failed: %T\r\n", + descP->sock, ereason) ); + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("connect_stream_check_result -> failure", + env, descP, &descP->connector); + descP->connectorP = NULL; + + /* Will an event be generetade in this case? + * Assume not => We need to clean up here! + */ + esock_clear_env("connect_stream_check_result", opP->env); + esock_free_env("connect_stream_check_result", opP->env); + FREE( opP ); + + sock_close(descP->sock); + descP->writeState = ESOCK_STATE_CLOSED; + WSACleanup(); + + eres = esock_make_error(env, ereason); + } + } + + return eres; +} + + + +/* *** esaio_connect_dgram *** + * Handle the "fake" connect of a DGRAM socket ("bind" to + * a remote address, so user can use send/recv instead of + * sendto/recvfrom). Should use sock_connect(...) + * This is corrently just a placeholder! + */ +static +ERL_NIF_TERM esaio_connect_dgram(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM connRef, + ESockAddress* addrP, + SOCKLEN_T addrLen) +{ + return enif_make_badarg(env); +} + + + +/* *** esaio_listen *** */ + + +/* ======================================================================== + */ +extern +ERL_NIF_TERM esaio_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef) +{ + ErlNifPid caller; + ERL_NIF_TERM eres; + SOCKET accSock; + ESAIOOperation* opP; + BOOLEAN_T ares; + unsigned int addrSz, bufSz; + DWORD recvBytes; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + /* Ensure that this caller does not already have a + * (accept) request waiting */ + if (esock_acceptor_search4pid(env, descP, &caller)) { + /* Acceptor already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + /* Accept and Read uses the same flag so they can not be simultaneous. + */ + SSDBG( descP, ("WIN-ESAIO", "esaio_accept {%d} -> verify not reading\r\n", + descP->sock) ); + if (descP->readersQ.first != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Should we verify domain, type and protocol? */ + + /* Allocate 'operation' */ + SSDBG( descP, ("WIN-ESAIO", + "esaio_accept {%d} -> allocate 'operation'\r\n", + descP->sock) ); + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_ACCEPT; + + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + SSDBG( descP, ("WIN-ESAIO", + "esaio_accept {%d} -> initiate 'operation'\r\n", + descP->sock) ); + opP->env = esock_alloc_env("esaio_accept - operation"); + opP->data.accept.lSockRef = CP_TERM(opP->env, sockRef); + opP->data.accept.accRef = CP_TERM(opP->env, accRef); + opP->data.accept.lsock = descP->sock; + opP->caller = caller; + + /* Create the accepting socket + * domain - should be AF_INET | AF_INET6 | AF_LOCAL (sould we make sure?) + * type - should be SOCK_STREAM | SOCK_SEQPACKET (should we make sure?) + * protocol - should be IPPROTO_TCP | IPPROTO_SCTP (should we make sure?) + * See check above! + */ + SSDBG( descP, ("WIN-ESAIO", + "esaio_accept {%d} -> try create 'accepting' socket\r\n", + descP->sock) ); + accSock = sock_open(descP->domain, descP->type, descP->protocol); + if (accSock == INVALID_SOCKET) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = MKA(env, erl_errno_id(save_errno)); + ERL_NIF_TERM tag = esock_atom_create_accept_socket; + + esock_clear_env("esaio_accept - invalid accept socket", opP->env); + esock_free_env("esaio_accept - invalid accept socket", opP->env); + FREE( opP ); + WSACleanup(); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept {%d} -> failed create 'accepting' socket:" + "\r\n %T (%d)" + "\r\n", + descP->sock, reason, save_errno) ); + + return esock_make_error_t2r(env, tag, reason); + } + + opP->data.accept.asock = accSock; + + /* According to the (Microsoft) documentation, the buffer size of the + * local and remote address must be 16 bytes *more* than the size of + * the sockaddr structure for the transport protocol in use. + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept {%d} -> " + "try calculate address and address buffer size(s)\r\n", + descP->sock) ); + switch (descP->domain) { + case AF_INET: + addrSz = sizeof(struct sockaddr_in) + 16; + break; + case AF_INET6: + addrSz = sizeof(struct sockaddr_in6) + 16; + break; + case AF_LOCAL: + addrSz = sizeof(struct sockaddr_un) + 16; + break; + default: + return esock_make_error_invalid(env, esock_atom_domain); + break; + } + bufSz = 2 * addrSz; + + opP->data.accept.buf = MALLOC( bufSz ); + ESOCK_ASSERT( opP->data.accept.buf != NULL); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_accept(%T, %d) -> try accept\r\n", + sockRef, descP->sock) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_tries, &descP->accTries, 1); + + ares = sock_accept_O(descP->sock, accSock, + opP->data.accept.buf, + addrSz, + &recvBytes, + (OVERLAPPED*) opP); + + eres = accept_check_result(env, descP, opP, ares, + sockRef, accRef, accSock, caller); + + SSDBG( descP, ("WIN-ESAIO", "esaio_accept(%T, %d) -> done when" + "\r\n eres: %T" + "\r\n", sockRef, descP->sock, eres) ); + + return eres; +} + + + +static +ERL_NIF_TERM accept_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + BOOL ares, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef, + SOCKET accSock, + ErlNifPid caller) +{ + ERL_NIF_TERM eres; + + if (ares) { + + /* Success already! + * So, no need to store the data (in the "queue"). + * And then allocate and initiate the new descriptor. + */ + + eres = esaio_accept_accepted(env, descP, caller, sockRef, accSock); + + } else { + + /* Accept returned error, check which */ + + int save_errno = sock_errno(); + + /* As pointed out above, there are basically two kinds of errors: + * 1) Pending: + * An overlapped operation was successfully initiated. + * Completion will be "indicated" at a later time. + * 2) An actual error + */ + + if (save_errno == WSA_IO_PENDING) { + + /* We need to store the data in the queue! */ + + eres = accept_check_pending(env, descP, opP, caller, + sockRef, accRef); + + } else { + + eres = accept_check_fail(env, descP, opP, save_errno, + accSock, sockRef); + + } + } + + SSDBG( descP, + ("WIN-ESAIO", + "accept_check_result(%T, %d) -> done with" + "\r\n result: %T" + "\r\n", sockRef, descP->sock, eres) ); + + return eres; +} + + + +static +ERL_NIF_TERM accept_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM accRef) +{ + SSDBG( descP, + ("WIN-ESAIO", + "accept_check_pending(%T, %d) -> entry with" + "\r\n accRef: %T" + "\r\n", sockRef, descP->sock, accRef) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_waits, &descP->accWaits, 1); + + if (descP->acceptorsQ.first == NULL) + descP->readState |= (ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); + + /* Will be picked up by the (worker) threads when the event comes */ + esock_acceptor_push(env, descP, caller, accRef, opP); + + return esock_atom_completion; + +} + + +static +ERL_NIF_TERM accept_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + SOCKET accSock, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", + "accept_check_fail(%T, %d) -> entry with" + "\r\n errno: %d" + "\r\n (acc) socket: %d" + "\r\n", sockRef, descP->sock, saveErrno, accSock) ); + + reason = MKA(env, erl_errno_id(saveErrno)); + + /* Will an event be generetade in this case? + * Assume not => We need to clean up here! + */ + esock_clear_env("esaio_accept", opP->env); + esock_free_env("esaio_accept", opP->env); + FREE( opP->data.accept.buf ); + FREE( opP ); + + sock_close(accSock); + WSACleanup(); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_fails, &descP->accFails, 1); + + return esock_make_error(env, reason); +} + + + +/* *** esaio_accept_accepted *** + * + * Generic function handling a successful accept. + */ +static +ERL_NIF_TERM esaio_accept_accepted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid pid, + ERL_NIF_TERM sockRef, + SOCKET accSock) +{ + ESockDescriptor* accDescP; + ERL_NIF_TERM accRef; + int save_errno; + + /* + * We got one + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept_accepted(%T, %d) -> entry with" + "\r\n (accept) socket: %T" + "\r\n", sockRef, descP->sock, accSock) ); + + // Allocate the descriptor + accDescP = esock_alloc_descriptor(accSock); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept_accepted(%T, %d) -> add to completion port\r\n", + sockRef, descP->sock) ); + + if (ESAIO_OK != (save_errno = esaio_add_socket(accDescP))) { + // See esock_dtor for what needs done! + ERL_NIF_TERM tag = esock_atom_add_socket; + ERL_NIF_TERM reason = MKA(env, erl_errno_id(save_errno)); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_fails, &descP->accFails, 1); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept_accepted(%T, %d) -> " + "failed adding (accepted) socket to completion port: " + "%T (%d)\r\n", sockRef, descP->sock, reason, save_errno) ); + + esock_dealloc_descriptor(env, accDescP); + sock_close(accSock); + + /* This should really be: + * {error, {invalid, {add_to_completion_port, Reason}}} + */ + + return esock_make_error_t2r(env, tag, reason); + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_acc_success, &descP->accSuccess, 1); + + accDescP->domain = descP->domain; + accDescP->type = descP->type; + accDescP->protocol = descP->protocol; + + MLOCK(descP->writeMtx); + + accDescP->rBufSz = descP->rBufSz; // Inherit buffer size + accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size + accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size + accDescP->iow = descP->iow; // Inherit iow + accDescP->dbg = descP->dbg; // Inherit debug flag + accDescP->useReg = descP->useReg; // Inherit useReg flag + esock_inc_socket(accDescP->domain, accDescP->type, accDescP->protocol); + + accRef = enif_make_resource(env, accDescP); + enif_release_resource(accDescP); + + accDescP->ctrlPid = pid; + /* pid has actually been compared equal to self() + * in this code path just a little while ago + */ + ESOCK_ASSERT( MONP("esaio_accept_accepted -> ctrl", + env, accDescP, + &accDescP->ctrlPid, + &accDescP->ctrlMon) == 0 ); + + accDescP->writeState |= ESOCK_STATE_CONNECTED; + + MUNLOCK(descP->writeMtx); + + /* And finally (maybe) update the registry */ + if (descP->useReg) esock_send_reg_add_msg(env, descP, accRef); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_accept_accepted(%T, %d) -> done\r\n", + sockRef, descP->sock) ); + + return esock_make_ok2(env, accRef); + +} + + + +/* ======================================================================== + * Do the actual send. + * Do some initial writer checks, do the actual send and then + * analyze the result. + * + * The following flags are "valid": + * + * MSG_DONTROUTE, MSG_PARTIAL, and MSG_OOB + * + */ +extern +ERL_NIF_TERM esaio_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags) +{ + ErlNifPid caller; + ERL_NIF_TERM eres; + BOOLEAN_T cleanup = FALSE; + int wres; + DWORD toWrite; + char* buf; + DWORD f = (DWORD) flags; + ESAIOOperation* opP; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->writeState)) { + ESOCK_EPRINTF("esaio_send(%T, %d) -> NOT OPEN\r\n", + sockRef, descP->sock); + return esock_make_error_closed(env); + } + + /* Connect and Write can not be simultaneous? */ + if (descP->connectorP != NULL) { + ESOCK_EPRINTF("esaio_send(%T, %d) -> CONNECTING\r\n", + sockRef, descP->sock); + return esock_make_error_invalid(env, esock_atom_state); + } + + /* Ensure that this caller does not *already* have a + * (send) request waiting */ + if (esock_writer_search4pid(env, descP, &caller)) { + /* Sender already in queue */ + ESOCK_EPRINTF("esaio_send(%T, %d) -> ALREADY SENDING\r\n", + sockRef, descP->sock); + return esock_raise_invalid(env, esock_atom_state); + } + + /* This is a size check, + * to ensure we do not try to send something *to* large */ + toWrite = (DWORD) sndDataP->size; + if ((size_t) toWrite != sndDataP->size) + return esock_make_error_invalid(env, esock_atom_data_size); + + /* Once the send function has been called, this memory + * is "owned" by the system. That is, we cannot free it + * (or do anything with it) until the *operation* has completed, + * so the free is done by the thread(s). + */ + buf = MALLOC( toWrite ); + ESOCK_ASSERT( buf != NULL ); + sys_memcpy(buf, sndDataP->data, toWrite); + + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_SEND; + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * But after the call is to late, so... + */ + opP->env = esock_alloc_env("esaio-send - operation"); + opP->data.send.sendRef = CP_TERM(opP->env, sendRef); + opP->data.send.sockRef = CP_TERM(opP->env, sockRef); + opP->data.send.wbuf.buf = buf; + opP->data.send.wbuf.len = toWrite; + opP->caller = caller; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + wres = sock_send_O(descP->sock, &opP->data.send.wbuf, f, (OVERLAPPED*) opP); + + eres = send_check_result(env, descP, opP, caller, + wres, toWrite, FALSE, + sockRef, sendRef, &cleanup); + + if (cleanup) { + + /* "Manually" allocated buffer */ + FREE( opP->data.send.wbuf.buf ); + + esock_clear_env("esaio_send - cleanup", opP->env); + esock_free_env("esaio_send - cleanup", opP->env); + + FREE( opP ); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_send {%d} -> done (%s)" + "\r\n %T" + "\r\n", descP->sock, B2S(cleanup), eres) ); + + return eres; +} + + + +/* ======================================================================== + * Do the actual send. + * Do some initial writer checks, do the actual send and then + * analyze the result. + * + * The following flags are "valid": + * + * MSG_DONTROUTE, MSG_PARTIAL, and MSG_OOB + * + * "Explicit binding is discouraged for client applications." + */ + +extern +ERL_NIF_TERM esaio_sendto(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ErlNifBinary* sndDataP, + int flags, + ESockAddress* toAddrP, + SOCKLEN_T toAddrLen) +{ + ErlNifPid caller; + ERL_NIF_TERM eres; + BOOLEAN_T cleanup = FALSE; + int wres; + DWORD toWrite; + char* buf; + DWORD f = (DWORD) flags; + ESAIOOperation* opP; + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write can not be simultaneous? */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Empty address to allowed */ + if (toAddrP == NULL) + return esock_make_invalid(env, esock_atom_sockaddr); + + /* Ensure that this caller does not *already* have a + * (send) request waiting */ + if (esock_writer_search4pid(env, descP, &caller)) { + /* Sender already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + /* This is a size check, + * to ensure we do not try to send something *to* large */ + toWrite = (DWORD) sndDataP->size; + if ((size_t) toWrite != sndDataP->size) + return esock_make_error_invalid(env, esock_atom_data_size); + + /* Once the send function has been called, this memory + * (buf) "belongs" to the "system" (so no need to free it). + */ + buf = MALLOC( toWrite ); + ESOCK_ASSERT( buf != NULL ); + sys_memcpy(buf, sndDataP->data, toWrite); + + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_SENDTO; + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * But after the call is to late, so... + */ + opP->env = esock_alloc_env("esaio-sendto - operation"); + opP->data.sendto.sendRef = CP_TERM(opP->env, sendRef); + opP->data.sendto.sockRef = CP_TERM(opP->env, sockRef); + opP->data.sendto.wbuf.buf = buf; + opP->data.sendto.wbuf.len = toWrite; + opP->data.sendto.remoteAddr = *toAddrP; // Do we need this? + opP->data.sendto.remoteAddrLen = toAddrLen;// Do we need this? + opP->caller = caller; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + wres = sock_sendto_O(descP->sock, &opP->data.sendto.wbuf, f, + (struct sockaddr*) toAddrP, toAddrLen, + (OVERLAPPED*) opP); + + eres = send_check_result(env, descP, opP, caller, + wres, toWrite, FALSE, + sockRef, sendRef, &cleanup); + + if (cleanup) { + + /* "Manually" allocated buffer */ + FREE( opP->data.sendto.wbuf.buf ); + + esock_clear_env("esaio_sendto - cleanup", opP->env); + esock_free_env("esaio_sendto - cleanup", opP->env); + + FREE( opP ); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_sendto {%d} -> done (%s)" + "\r\n %T" + "\r\n", descP->sock, B2S(cleanup), eres) ); + + return eres; +} + + + +/* ======================================================================== + * Do the actual sendmsg. + * Do some initial writer checks, do the actual send and then + * analyze the result. + * + * The following flags are "valid": + * + * MSG_DONTROUTE, MSG_PARTIAL, and MSG_OOB + * + * "Explicit binding is discouraged for client applications." + * + * Also, according to Microsoft documentation: + * + * "can only be used with datagrams and raw sockets." + * + * So, should we check, or let the user crash and burn? + * + * Note that this operation *only* works for socket + * of types SOCK_DGRAM and SOCK_RAW! Should we check + * and throw 'enotsup' otherwise? Would make testing + * easier... + */ + +extern +ERL_NIF_TERM esaio_sendmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsg, + int flags, + ERL_NIF_TERM eIOV, + const ESockData* dataP) +{ + ErlNifPid caller; + ERL_NIF_TERM eres; + BOOLEAN_T cleanup = FALSE; + int wres; + ERL_NIF_TERM tail; + ERL_NIF_TERM eAddr, eCtrl; + ssize_t dataSize; + size_t ctrlBufLen, ctrlBufUsed; + WSABUF* wbufs = NULL; + ESAIOOperation* opP = NULL; + + SSDBG( descP, ("WIN-ESAIO", "esaio_sendmsg(%T, %d) -> entry with" + "\r\n", sockRef, descP->sock) ); + + /* This *only* works on socket type(s) DGRAM or RAW. + * Other socket types results in einval, which is not very + * helpful. So, in order to, atleast, help with testing, + * we do this... + */ + if (! ((descP->type == SOCK_DGRAM) || (descP->type == SOCK_RAW))) { + return enif_raise_exception(env, MKA(env, "notsup")); + } + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->writeState)) + return esock_make_error_closed(env); + + /* Connect and Write can not be simultaneous? */ + if (descP->connectorP != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that this caller does not *already* have a + * (send) request waiting */ + if (esock_writer_search4pid(env, descP, &caller)) { + /* Sender already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_SENDMSG; + + if (! init_sendmsg_sockaddr(env, descP, eMsg, + &opP->data.sendmsg.msg, + &opP->data.sendmsg.addr)) { + + FREE( opP ); + + return esock_make_invalid(env, esock_atom_addr); + } + + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + opP->env = esock_alloc_env("esaio_sendmsg - operation"); + + /* Extract the *mandatory* 'iov', which must be an erlang:iovec(), + * from which we take at most IOV_MAX binaries. + * The env *cannot* be NULL because we don't actually know if + * the send succeeds *now*. It could be sceduled! + */ + if ((! enif_inspect_iovec(opP->env, + dataP->iov_max, eIOV, &tail, + &opP->data.sendmsg.iovec))) { + + SSDBG( descP, ("WIN-ESAIO", + "essaio_sendmsg {%d} -> not an iov\r\n", + descP->sock) ); + + esock_free_env("esaio-sendmsg - iovec failure", opP->env); + FREE( opP ); + + return esock_make_error_invalid(env, esock_atom_iov); + } + + SSDBG( descP, ("WIN-ESAIO", "esaio_sendmsg {%d} ->" + "\r\n iovcnt: %lu" + "\r\n tail: %s" + "\r\n", descP->sock, + (unsigned long) opP->data.sendmsg.iovec->iovcnt, + B2S(! enif_is_empty_list(opP->env, tail))) ); + + + /* We now have an allocated iovec - verify vector size */ + + if (! verify_sendmsg_iovec_size(dataP, descP, opP->data.sendmsg.iovec)) { + + /* We can not send the whole packet in one sendmsg() call */ + SSDBG( descP, ("WIN-ESAIO", + "esaio_sendmsg {%d} -> iovcnt > iov_max\r\n", + descP->sock) ); + + // No need - belongs to op env: FREE_IOVEC( opP->data.sendmsg.iovec ); + esock_free_env("esaio-sendmsg - iovec failure", opP->env); + FREE( opP ); + + return esock_make_error_invalid(env, esock_atom_iov); + } + + + /* Verify that we can send the entire message. + * On DGRAM the tail must be "empty" (= everything must fit in one message). + */ + if (! verify_sendmsg_iovec_tail(opP->env, descP, &tail)) { + + // No need - belongs to op env: FREE_IOVEC( opP->data.sendmsg.iovec ); + esock_free_env("esaio-sendmsg - iovec tail failure", opP->env); + FREE( opP ); + + return esock_make_error_invalid(env, esock_atom_iov); + + } + + if (! check_sendmsg_iovec_overflow(descP, + opP->data.sendmsg.iovec, &dataSize)) { + + // No need - belongs to op env: FREE_IOVEC( opP->data.sendmsg.iovec ); + esock_free_env("esaio-sendmsg - iovec size failure", opP->env); + FREE( opP ); + + return esock_make_error_invalid(env, esock_atom_iov); + + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_sendmsg {%d} -> iovec size verified" + "\r\n iov length: %lu" + "\r\n data size: %u" + "\r\n", + descP->sock, + (unsigned long) opP->data.sendmsg.iovec->iovcnt, + (long) dataSize) ); + + wbufs = MALLOC(opP->data.sendmsg.iovec->iovcnt * sizeof(WSABUF)); + ESOCK_ASSERT( wbufs != NULL ); + for (int i = 0; i < opP->data.sendmsg.iovec->iovcnt; i++) { + wbufs[i].len = opP->data.sendmsg.iovec->iov[i].iov_len; + wbufs[i].buf = opP->data.sendmsg.iovec->iov[i].iov_base; + } + + opP->data.sendmsg.msg.lpBuffers = wbufs; + opP->data.sendmsg.msg.dwBufferCount = opP->data.sendmsg.iovec->iovcnt; + + /* And now for the control headers - some default first */ + eCtrl = esock_atom_undefined; + ctrlBufLen = 0; + opP->data.sendmsg.ctrlBuf = NULL; + + /* Extract the *optional* 'ctrl' out of the eMsg map */ + if (GET_MAP_VAL(env, eMsg, esock_atom_ctrl, &eCtrl)) { + ctrlBufLen = descP->wCtrlSz; + opP->data.sendmsg.ctrlBuf = (char*) MALLOC(ctrlBufLen); + ESOCK_ASSERT( opP->data.sendmsg.ctrlBuf != NULL ); + } + + SSDBG( descP, ("WIN-ESAIO", "esaio_sendmsg {%d} -> optional ctrl: " + "\r\n ctrlBuf: %p" + "\r\n ctrlBufLen: %lu" + "\r\n eCtrl: %T" + "\r\n", descP->sock, + opP->data.sendmsg.ctrlBuf, + (unsigned long) ctrlBufLen, eCtrl) ); + + if (opP->data.sendmsg.ctrlBuf != NULL) { + if (! decode_cmsghdrs(env, descP, + eCtrl, + opP->data.sendmsg.ctrlBuf, ctrlBufLen, + &ctrlBufUsed)) { + + FREE( opP->data.sendmsg.ctrlBuf ); + FREE( opP->data.sendmsg.msg.lpBuffers ); + // No need - belongs to op env: FREE_IOVEC( opP->data.sendmsg.iovec ); + esock_free_env("esaio-sendmsg - iovec size failure", opP->env); + FREE( opP ); + + return esock_make_invalid(env, esock_atom_ctrl); + } + } else { + ctrlBufUsed = 0; + } + opP->data.sendmsg.msg.Control.len = ctrlBufUsed; + opP->data.sendmsg.msg.Control.buf = opP->data.sendmsg.ctrlBuf; + + /* We do not yet handle the flags (see function header above), + * so zero it just in case. */ + opP->data.sendmsg.msg.dwFlags = 0; + + opP->tag = ESAIO_OP_SENDMSG; + opP->caller = caller; + opP->data.sendmsg.sockRef = CP_TERM(opP->env, sockRef); + opP->data.sendmsg.sendRef = CP_TERM(opP->env, sendRef); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_tries, &descP->writeTries, 1); + + wres = sock_sendmsg_O(descP->sock, &opP->data.sendmsg.msg, flags, + (OVERLAPPED*) opP); + + eres = send_check_result(env, descP, opP, caller, + wres, dataSize, + (! enif_is_empty_list(opP->env, tail)), + sockRef, sendRef, &cleanup); + + if (cleanup) { + + /* "Manually" allocated buffers */ + FREE( opP->data.sendmsg.msg.lpBuffers ); + if (opP->data.sendmsg.ctrlBuf != NULL) + FREE( opP->data.sendmsg.ctrlBuf ); + + /* The i/o vector belongs to the op env, + * so it goes when the env goes. + */ + esock_clear_env("esaio_sendto - cleanup", opP->env); + esock_free_env("esaio_sendto - cleanup", opP->env); + + FREE( opP ); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_sendmsg {%d} -> done (%s)" + "\r\n %T" + "\r\n", descP->sock, B2S(cleanup), eres) ); + + return eres; +} + + +static +BOOLEAN_T init_sendmsg_sockaddr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eMsg, + WSAMSG* msgP, + ESockAddress* addrP) +{ + ERL_NIF_TERM eAddr; + + if (! GET_MAP_VAL(env, eMsg, esock_atom_addr, &eAddr)) { + + SSDBG( descP, ("WIN-ESAIO", + "init_sendmsg_sockaddr {%d} -> no address\r\n", + descP->sock) ); + + msgP->name = NULL; + msgP->namelen = 0; + + } else { + + SSDBG( descP, ("WIN-ESAIO", "init_sendmsg_sockaddr {%d} ->" + "\r\n address: %T" + "\r\n", descP->sock, eAddr) ); + + msgP->name = (void*) addrP; + msgP->namelen = sizeof(ESockAddress); + sys_memzero((char *) msgP->name, msgP->namelen); + + if (! esock_decode_sockaddr(env, eAddr, + (ESockAddress*) msgP->name, + (SOCKLEN_T*) &msgP->namelen)) { + + SSDBG( descP, ("WIN-ESAIO", + "init_sendmsg_sockaddr {%d} -> invalid address\r\n", + descP->sock) ); + + return FALSE; + } + } + + return TRUE; + +} + + + +static +BOOLEAN_T verify_sendmsg_iovec_size(const ESockData* dataP, + ESockDescriptor* descP, + ErlNifIOVec* iovec) +{ + if (iovec->iovcnt > dataP->iov_max) { + if (descP->type == SOCK_STREAM) { + iovec->iovcnt = dataP->iov_max; + } else { + return FALSE; + } + } + + return TRUE; +} + + + +static +BOOLEAN_T verify_sendmsg_iovec_tail(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM* tail) +{ + ERL_NIF_TERM h, t, tmp = *tail; + ErlNifBinary bin; + + /* Find out if there is remaining data in the tail. + * Skip empty binaries otherwise break. + * If 'tail' after loop exit is the empty list + * there was no more data. Otherwise there is more + * data or the 'iov' is invalid. + */ + + for (;;) { + if (enif_get_list_cell(env, tmp, &h, &t) && + enif_inspect_binary(env, h, &bin) && + (bin.size == 0)) { + tmp = t; + continue; + } else + break; + } + + *tail = tmp; + + if ((! enif_is_empty_list(env, tmp)) && + (descP->type != SOCK_STREAM)) { + + /* We can not send the whole packet in one sendmsg() call */ + SSDBG( descP, ("WIN-ESAIO", + "essio_sendmsg {%d} -> invalid tail\r\n", + descP->sock) ); + + return FALSE; + } + + return TRUE; + +} + + + +static +BOOLEAN_T check_sendmsg_iovec_overflow(ESockDescriptor* descP, + ErlNifIOVec* iovec, + ssize_t* dataSize) +{ + ssize_t dsz = 0; + size_t i; + + for (i = 0; i < iovec->iovcnt; i++) { + size_t len = iovec->iov[i].iov_len; + dsz += len; + if (dsz < len) { + + /* Overflow */ + + SSDBG( descP, ("WIN-ESAIO", + "verify_sendmsg_iovec_size {%d} -> Overflow" + "\r\n i: %lu" + "\r\n len: %lu" + "\r\n dataSize: %ld" + "\r\n", descP->sock, (unsigned long) i, + (unsigned long) len, (long) dsz) ); + + *dataSize = dsz; + + return FALSE; + + } + } + + *dataSize = dsz; + + return TRUE; + +} + + + +/* *** Control message utility functions *** */ + +/* +++ decode_cmsghdrs +++ + * + * Decode a list of cmsg(). There can be 0 or more "blocks". + * + * Each element can either be a (erlang) map that needs to be decoded, + * or a (erlang) binary that just needs to be appended to the control + * buffer. + * + * Our "problem" is that we have no idea how much memory we actually need. + * + */ + +static +BOOLEAN_T decode_cmsghdrs(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* cmsgHdrBufP, + size_t cmsgHdrBufLen, + size_t* cmsgHdrBufUsed) +{ + ERL_NIF_TERM elem, tail, list; + char* bufP; + size_t rem, used, totUsed = 0; + unsigned int len; + int i; + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdrs {%d} -> entry with" + "\r\n eCMsg: %T" + "\r\n cmsgHdrBufP: 0x%lX" + "\r\n cmsgHdrBufLen: %d" + "\r\n", descP->sock, + eCMsg, cmsgHdrBufP, cmsgHdrBufLen) ); + + if (! GET_LIST_LEN(env, eCMsg, &len)) + return FALSE; + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdrs {%d} -> list length: %d\r\n", + descP->sock, len) ); + + for (i = 0, list = eCMsg, rem = cmsgHdrBufLen, bufP = cmsgHdrBufP; + i < len; i++) { + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdrs {%d} -> process elem %d:" + "\r\n (buffer) rem: %u" + "\r\n (buffer) totUsed: %u" + "\r\n", descP->sock, i, rem, totUsed) ); + + /* Extract the (current) head of the (cmsg hdr) list */ + if (! GET_LIST_ELEM(env, list, &elem, &tail)) + return FALSE; + + used = 0; // Just in case... + if (! decode_cmsghdr(env, descP, elem, bufP, rem, &used)) + return FALSE; + +#ifdef __WIN32__ + bufP = CHARP( bufP + used ); +#else + bufP = CHARP( ULONG(bufP) + used ); +#endif + rem = SZT( rem - used ); + list = tail; + totUsed += used; + + } + + *cmsgHdrBufUsed = totUsed; + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdrs {%d} -> done" + "\r\n all %u ctrl headers processed" + "\r\n totUsed = %lu\r\n", + descP->sock, len, (unsigned long) totUsed) ); + + return TRUE; +} + + + +/* +++ decode_cmsghdr +++ + * + * Decode one cmsg(). Put the "result" into the buffer and advance the + * pointer (of the buffer) afterwards. Also update 'rem' accordingly. + * But before the actual decode, make sure that there is enough room in + * the buffer for the cmsg header (sizeof(*hdr) < rem). + * + * The eCMsg should be a map with three fields: + * + * level :: socket | protocol() | integer() + * type :: atom() | integer() + * What values are valid depend on the level + * data :: binary() | integer() | boolean() + * The type of the data depends on + * or level and type, but can be a binary, + * which means that the data is already coded. + * value :: term() Which is a term matching the decode function + */ + +static +BOOLEAN_T decode_cmsghdr(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eCMsg, + char* bufP, + size_t rem, + size_t* used) +{ + ERL_NIF_TERM eLevel, eType, eData, eValue; + int level; + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d} -> entry with" + "\r\n eCMsg: %T" + "\r\n", descP->sock, eCMsg) ); + + // Get 'level' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_level, &eLevel)) + return FALSE; + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d} -> eLevel: %T" + "\r\n", descP->sock, eLevel) ); + + // Get 'type' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_type, &eType)) + return FALSE; + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d} -> eType: %T" + "\r\n", descP->sock, eType) ); + + // Decode Level + if (! esock_decode_level(env, eLevel, &level)) + return FALSE; + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d}-> level: %d\r\n", + descP->sock, level) ); + + // Get 'data' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_data, &eData)) { + + // Get 'value' field + if (! GET_MAP_VAL(env, eCMsg, esock_atom_value, &eValue)) + return FALSE; + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d} -> eValue: %T" + "\r\n", descP->sock, eValue) ); + + // Decode Value + if (! decode_cmsghdr_value(env, descP, level, eType, eValue, + bufP, rem, used)) + return FALSE; + + } else { + + // Verify no 'value' field + if (GET_MAP_VAL(env, eCMsg, esock_atom_value, &eValue)) + return FALSE; + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d} -> eData: %T" + "\r\n", descP->sock, eData) ); + + // Decode Data + if (! decode_cmsghdr_data(env, descP, level, eType, eData, + bufP, rem, used)) + return FALSE; + } + + SSDBG( descP, ("WIN-ESAIO", "decode_cmsghdr {%d}-> used: %lu\r\n", + descP->sock, (unsigned long) *used) ); + + return TRUE; +} + + +static +BOOLEAN_T decode_cmsghdr_value(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eValue, + char* bufP, + size_t rem, + size_t* usedP) +{ + int type; + struct cmsghdr* cmsgP = (struct cmsghdr *) bufP; + ESockCmsgSpec* cmsgTable; + ESockCmsgSpec* cmsgSpecP = NULL; + size_t num = 0; + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_value {%d} -> entry \r\n" + " eType: %T\r\n" + " eValue: %T\r\n", + descP->sock, eType, eValue) ); + + // We have decode functions only for symbolic (atom) types + if (! IS_ATOM(env, eType)) { + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " eType not an atom\r\n", + descP->sock) ); + return FALSE; + } + + /* Try to look up the symbolic type + */ + if (((cmsgTable = esock_lookup_cmsg_table(level, &num)) == NULL) || + ((cmsgSpecP = esock_lookup_cmsg_spec(cmsgTable, num, eType)) == NULL) || + (cmsgSpecP->decode == NULL)) { + + /* We found no table for this level, + * we found no symbolic type in the level table, + * or no decode function for this type + */ + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " cmsgTable: %p\r\n" + " cmsgSpecP: %p\r\n", + descP->sock, cmsgTable, cmsgSpecP) ); + + return FALSE; + } + + if (! cmsgSpecP->decode(env, eValue, cmsgP, rem, usedP)) { + // Decode function failed + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_value {%d} -> FALSE:\r\n" + " decode function failed\r\n", + descP->sock) ); + return FALSE; + } + + // Successful decode + + type = cmsgSpecP->type; + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_value {%d} -> TRUE:\r\n" + " level: %d\r\n" + " type: %d\r\n", + " *usedP: %lu\r\n", + descP->sock, level, type, (unsigned long) *usedP) ); + + cmsgP->cmsg_level = level; + cmsgP->cmsg_type = type; + return TRUE; +} + + +static +BOOLEAN_T decode_cmsghdr_data(ErlNifEnv* env, + ESockDescriptor* descP, + int level, + ERL_NIF_TERM eType, + ERL_NIF_TERM eData, + char* bufP, + size_t rem, + size_t* usedP) +{ + int type; + ErlNifBinary bin; + struct cmsghdr* cmsgP = (struct cmsghdr *) bufP; + ESockCmsgSpec* cmsgSpecP = NULL; + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_data {%d} -> entry \r\n" + " eType: %T\r\n" + " eData: %T\r\n", + descP->sock, eType, eData) ); + + // Decode Type + if (! GET_INT(env, eType, &type)) { + ESockCmsgSpec* cmsgTable = NULL; + size_t num = 0; + + /* Try to look up the symbolic (atom) type + */ + if ((! IS_ATOM(env, eType)) || + ((cmsgTable = esock_lookup_cmsg_table(level, &num)) == NULL) || + ((cmsgSpecP = esock_lookup_cmsg_spec(cmsgTable, num, eType)) == NULL)) { + /* Type was not an atom, + * we found no table for this level, + * or we found no symbolic type in the level table + */ + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_data {%d} -> FALSE:\r\n" + " cmsgTable: %p\r\n" + " cmsgSpecP: %p\r\n", + descP->sock, cmsgTable, cmsgSpecP) ); + return FALSE; + } + + type = cmsgSpecP->type; + } + + // Decode Data + if (GET_BIN(env, eData, &bin)) { + void *p; + + p = esock_init_cmsghdr(cmsgP, rem, bin.size, usedP); + if (p == NULL) { + /* No room for the data + */ + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_data {%d} -> FALSE:\r\n" + " rem: %lu\r\n" + " bin.size: %lu\r\n", + descP->sock, + (unsigned long) rem, + (unsigned long) bin.size) ); + return FALSE; + } + + // Copy the binary data + sys_memcpy(p, bin.data, bin.size); + + } else if ((! esock_cmsg_decode_int(env, eData, cmsgP, rem, usedP)) && + (! esock_cmsg_decode_bool(env, eData, cmsgP, rem, usedP))) { + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_data {%d} -> FALSE\r\n", + descP->sock) ); + return FALSE; + } + + // Successful decode + + SSDBG( descP, + ("WIN-ESAIO", + "decode_cmsghdr_data {%d} -> TRUE:\r\n" + " level: %d\r\n" + " type: %d\r\n" + " *usedP: %lu\r\n", + descP->sock, level, type, (unsigned long) *usedP) ); + + cmsgP->cmsg_level = level; + cmsgP->cmsg_type = type; + return TRUE; +} + + + + +/* +++ encode_msg +++ + * + * Encode a msg() (recvmsg). In erlang its represented as + * a map, which has a specific set of attributes: + * + * addr (source address) - sockaddr() + * iov - [binary()] + * ctrl - [cmsg()] + * flags - msg_flags() + */ + +static +void encode_msg(ErlNifEnv* env, + ESockDescriptor* descP, + ssize_t read, + WSAMSG* msgP, + ErlNifBinary* dataBufP, + ErlNifBinary* ctrlBufP, + ERL_NIF_TERM* eMsg) +{ + ERL_NIF_TERM addr, iov, ctrl, flags; + + SSDBG( descP, + ("WIN-ESAIO", "encode_msg {%d} -> entry with" + "\r\n read: %ld" + "\r\n", descP->sock, (long) read) ); + + /* The address is not used if we are connected (unless, maybe, + * family is 'local'), so check (length = 0) before we try to encodel + */ + if (msgP->namelen != 0) { + esock_encode_sockaddr(env, + (ESockAddress*) msgP->name, + msgP->namelen, + &addr); + } else { + addr = esock_atom_undefined; + } + + SSDBG( descP, + ("WIN-ESAIO", "encode_msg {%d} -> encode iov" + "\r\n num vectors: %lu" + "\r\n", descP->sock, (unsigned long) msgP->dwBufferCount) ); + + esock_encode_iov(env, read, + (SysIOVec*) msgP->lpBuffers, msgP->dwBufferCount, dataBufP, + &iov); + + SSDBG( descP, + ("WIN-ESAIO", + "encode_msg {%d} -> try encode cmsgs\r\n", + descP->sock) ); + + encode_cmsgs(env, descP, ctrlBufP, msgP, &ctrl); + + SSDBG( descP, + ("WIN-ESAIO", + "encode_msg {%d} -> try encode flags\r\n", + descP->sock) ); + + esock_encode_msg_flags(env, descP, msgP->dwFlags, &flags); + + SSDBG( descP, + ("WIN-ESAIO", "encode_msg {%d} -> components encoded:" + "\r\n addr: %T" + "\r\n ctrl: %T" + "\r\n flags: %T" + "\r\n", descP->sock, addr, ctrl, flags) ); + + { + ERL_NIF_TERM keys[] = {esock_atom_iov, + esock_atom_ctrl, + esock_atom_flags, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {iov, ctrl, flags, addr}; + size_t numKeys = NUM(keys); + + ESOCK_ASSERT( numKeys == NUM(vals) ); + + SSDBG( descP, + ("WIN-ESAIO", + "encode_msg {%d} -> create map\r\n", + descP->sock) ); + + if (msgP->namelen == 0) + numKeys--; // No addr + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, eMsg) ); + + SSDBG( descP, + ("WIN-ESAIO", + "encode_msg {%d}-> map encoded\r\n", + descP->sock) ); + } + + SSDBG( descP, + ("WIN-ESAIO", "encode_msg {%d} -> done\r\n", descP->sock) ); +} + + + +/* +++ encode_cmsgs +++ + * + * Encode a list of cmsg(). There can be 0 or more cmsghdr "blocks". + * + * Our "problem" is that we have no idea how many control messages + * we have. + * + * The cmsgHdrP arguments points to the start of the control data buffer, + * an actual binary. Its the only way to create sub-binaries. So, what we + * need to continue processing this is to turn that into an binary erlang + * term (which can then in turn be turned into sub-binaries). + * + * We need the cmsgBufP (even though cmsgHdrP points to it) to be able + * to create sub-binaries (one for each cmsg hdr). + * + * The TArray (term array) is created with the size of 128, which should + * be enough. But if its not, then it will be automatically realloc'ed during + * add. Once we are done adding hdr's to it, we convert the tarray to a list. + */ + +static +void encode_cmsgs(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifBinary* cmsgBinP, + WSAMSG* msgP, + ERL_NIF_TERM* eCMsg) +{ + ERL_NIF_TERM ctrlBuf = MKBIN(env, cmsgBinP); // The *entire* binary + SocketTArray cmsghdrs = TARRAY_CREATE(128); + WSACMSGHDR* firstP = ESOCK_CMSG_FIRSTHDR(msgP); + WSACMSGHDR* currentP; + + SSDBG( descP, ("WIN-ESAIO", "encode_cmsgs {%d} -> entry when" + "\r\n msg ctrl len: %d" + "\r\n (ctrl) firstP: 0x%lX" + "\r\n", descP->sock, msgP->Control.len, firstP) ); + + for (currentP = firstP; + (currentP != NULL); + /* nifs\win32\win_socket_asyncio.c(3167): + * warning C4116: unnamed type definition in parentheses + */ + currentP = ESOCK_CMSG_NXTHDR(msgP, currentP)) { + + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> process cmsg header when" + "\r\n TArray Size: %d" + "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + + /* MUST check this since on Linux the returned "cmsg" may actually + * go too far! + */ + if (((CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP)) > + msgP->Control.len) { + + /* Ouch, fatal error - give up + * We assume we cannot trust any data if this is wrong. + */ + + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> check failed when: " + "\r\n currentP: 0x%lX" + "\r\n (current) cmsg_len: %d" + "\r\n firstP: 0x%lX" + "\r\n => %d" + "\r\n msg ctrl len: %d" + "\r\n", descP->sock, + CHARP(currentP), currentP->cmsg_len, CHARP(firstP), + (CHARP(currentP) + currentP->cmsg_len) - CHARP(firstP), + msgP->Control.len) ); + + TARRAY_ADD(cmsghdrs, esock_atom_bad_data); + break; + + } else { + unsigned char* dataP = UCHARP(ESOCK_CMSG_DATA(currentP)); + size_t dataPos = dataP - cmsgBinP->data; + size_t dataLen = + (UCHARP(currentP) + currentP->cmsg_len) - dataP; + ERL_NIF_TERM + cmsgHdr, + keys[] = + {esock_atom_level, + esock_atom_type, + esock_atom_data, + esock_atom_value}, + vals[NUM(keys)]; + size_t numKeys = NUM(keys); + BOOLEAN_T have_value; + + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> cmsg header data: " + "\r\n dataPos: %d" + "\r\n dataLen: %d" + "\r\n", descP->sock, dataPos, dataLen) ); + + vals[0] = esock_encode_level(env, currentP->cmsg_level); + vals[2] = MKSBIN(env, ctrlBuf, dataPos, dataLen); + have_value = esock_encode_cmsg(env, + currentP->cmsg_level, + currentP->cmsg_type, + dataP, dataLen, &vals[1], &vals[3]); + + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> " + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n %T: %T" + "\r\n", descP->sock, + keys[0], vals[0], keys[1], vals[1], keys[2], vals[2]) ); + if (have_value) + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> " + "\r\n %T: %T" + "\r\n", descP->sock, keys[3], vals[3]) ); + + /* Guard against cut-and-paste errors */ + ESOCK_ASSERT( numKeys == NUM(vals) ); + ESOCK_ASSERT( MKMA(env, keys, vals, + numKeys - (have_value ? 0 : 1), &cmsgHdr) ); + + /* And finally add it to the list... */ + TARRAY_ADD(cmsghdrs, cmsgHdr); + } + } + + SSDBG( descP, + ("WIN-ESAIO", "encode_cmsgs {%d} -> cmsg headers processed when" + "\r\n TArray Size: %d" + "\r\n", descP->sock, TARRAY_SZ(cmsghdrs)) ); + + /* The tarray is populated - convert it to a list */ + TARRAY_TOLIST(cmsghdrs, env, eCMsg); +} + + + +/* ====== Receive functions ====== */ + + +/* ======================================================================== + * The (read) buffer handling should be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throwing it away... + * + * The following flags are supported (with overlapped): + * MSG_OOB - Processes OOB data. + * MSG_PARTIAL - *message-oriented* sockets only. + * Both intput to *and* output from recv. + * MSG_PUSH_IMMEDIATE - *stream-oriented* sockets only. + * Hint rather than an actual guarantee. + * MSG_WAITALL - *stream-oriented* sockets only. + * The request will complete only when one of + * the following conditions apply: + * - buffer is completely full. + * - The connection has been closed. + * - The request has been canceled or an error occurred. + */ +extern +ERL_NIF_TERM esaio_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags) +{ + ErlNifPid caller; + ESAIOOperation* opP; + int rres; + WSABUF wbuf; + DWORD f = flags; + size_t bufSz = (len != 0 ? len : descP->rBufSz); + + SSDBG( descP, ("WIN-ESAIO", "esaio_recv {%d} -> entry with" + "\r\n length: %ld" + "\r\n (buffer) size: %lu" + "\r\n", descP->sock, + (long) len, (unsigned long) bufSz) ); + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read can not be simultaneous? */ + if (descP->acceptorsQ.first != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that this caller does not *already* have a + * (recv) request waiting */ + if (esock_reader_search4pid(env, descP, &caller)) { + /* Reader already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + /* Allocate the operation */ + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_RECV; + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + opP->env = esock_alloc_env("esaio-recv - operation"); + opP->data.recv.recvRef = CP_TERM(opP->env, recvRef); + opP->data.recv.sockRef = CP_TERM(opP->env, sockRef); + opP->caller = caller; + + /* Allocate a buffer: + * Either as much as we want to read or (if zero (0)) use the "default" + * size (what has been configured). + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &opP->data.recv.buf) ); + + opP->data.recv.toRead = len; + wbuf.buf = opP->data.recv.buf.data; + wbuf.len = opP->data.recv.buf.size; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + SSDBG( descP, ("WIN-ESAIO", "esaio_recv {%d} -> try read (%lu)\r\n", + descP->sock, (unsigned long) bufSz) ); + + rres = sock_recv_O(descP->sock, &wbuf, &f, (OVERLAPPED*) opP); + + return recv_check_result(env, descP, opP, caller, rres, + sockRef, recvRef); +} + + +/* *** recv_check_result *** + * + * Analyze the result of a receive attempt. + * The receive may have been completed directly or scheduled (overlapped). + */ +static +ERL_NIF_TERM recv_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM eres; + + if (recv_result == 0) { + + /* +++ Success +++ */ + + eres = recv_check_ok(env, descP, opP, caller, sockRef, recvRef); + + } else { + int err; + + /* +++ Failure or pending +++ */ + + err = sock_errno(); + + /* As pointed out above, there are basically two kinds of errors: + * 1) Pending: + * An overlapped operation was successfully initiated. + * Completion will be indicated at a later time. + * 2) An actual error + */ + + if (err == WSA_IO_PENDING) { + + if (! IS_ZERO(recvRef)) { + + eres = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + + } else { + + /* We are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_result(%T, %d) -> " + "pending - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_result(%T, %d) -> " + "failed cancel pending operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + eres = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + eres = esock_atom_ok; + + } + + } + + } else { + + eres = recv_check_fail(env, descP, opP, err, sockRef); + + } + + } + + return eres; +} + + + +/* *** recv_check_ok *** + * + * A successful recv. We *know* that in this case the buffer is filled! + */ + +static +ERL_NIF_TERM recv_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM data, result; + DWORD read = 0, flags = 0; + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok -> try get overlapped result\r\n") ); + + if (get_recv_ovl_result(descP->sock, (OVERLAPPED*) opP, &read, &flags)) { + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok -> overlapped success result: " + "\r\n read: %d" + "\r\n flags: 0x%X" + "\r\n", read, flags) ); + + (void) flags; // We should really do something with this... + + /* + * + * We need to handle read = 0 for other type(s) (DGRAM) when + * its actually valid to read 0 bytes. + * + * + */ + + if ((read == 0) && (descP->type == SOCK_STREAM)) { + + /* + * When a stream socket peer has performed an orderly + * shutdown, the return value will be 0 (the traditional + * "end-of-file" return). + * + * *We* do never actually try to read 0 bytes! + */ + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + result = esock_make_error(env, esock_atom_closed); + + } else { + + if (read == opP->data.recv.buf.size) { + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok(%T, %d) -> complete success" + "\r\n", sockRef, descP->sock) ); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, &opP->data.recv.buf); + + } else { + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok(%T, %d) -> partial (%d) success" + "\r\n", sockRef, descP->sock, read) ); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, &opP->data.recv.buf); + data = MKSBIN(env, data, 0, read); + + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + /* (maybe) Update max */ + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + result = esock_make_ok2(env, data); + + } + + } else { + + int save_errno = sock_errno(); + + switch (save_errno) { + case WSA_IO_INCOMPLETE: + /* + * WSA_IO_INCOMPLETE + * + * Even though it (the I/O Completion Port framework) told + * us it was done, it was not. So we need to postpone and let + * the (worker) threads deal with it anyway...effing framework... + */ + + if (! IS_ZERO(recvRef)) { + + result = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + } else { + + /* But we are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok(%T, %d) -> " + "incomplete - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_ok(%T, %d) -> " + "failed cancel incomplete operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + result = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + result = esock_atom_ok; // Will trigger {error, timeout} + + } + } + break; + + default: + { + ERL_NIF_TERM eerrno = ENO2T(env, save_errno); + ERL_NIF_TERM reason = MKT2(env, + esock_atom_get_overlapped_result, + eerrno); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.genErrs, 1); + + MUNLOCK(ctrl.cntMtx); + + result = esock_make_error(env, reason); + } + break; + } + } + + SSDBG( descP, + ("WIN-ESAIO", "recv_check_ok(%T) {%d} -> done" + "\r\n", + sockRef, descP->sock) ); + + return result; +} + + + +/* *** recv_check_pending *** + * + * The recv operation was scheduled, that is, its now in the hands + * of the I/O Completion Port framework. + */ +static +ERL_NIF_TERM recv_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + + SSDBG( descP, + ("WIN-ESAIO", + "recv_check_pending(%T, %d) -> entry with" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, recvRef) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_waits, &descP->readWaits, 1); + + descP->readState |= ESOCK_STATE_SELECTED; + + esock_reader_push(env, descP, caller, recvRef, opP); + + return esock_atom_completion; + +} + + + +/* *** recv_check_fail *** + * + * Processing done upon failed 'recv'. + * An actual failure. + */ +static +ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + SSDBG( descP, + ("WIN-ESAIO", "recv_check_fail(%T) {%d} -> entry with" + "\r\n errno: %d" + "\r\n", + sockRef, descP->sock, saveErrno) ); + + FREE_BIN( &opP->data.recv.buf ); + + return recv_check_failure(env, descP, opP, saveErrno, sockRef); +} + + + +/* *** recv_check_failure *** + * + * Processing done upon failed recv. + * An actual failure. + */ +static +ERL_NIF_TERM recv_check_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno)); + + SSDBG( descP, + ("WIN-ESAIO", "recv_check_failure(%T) {%d} -> error: %d (%T)\r\n", + sockRef, descP->sock, saveErrno, reason) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + esock_clear_env("recv_check_failure", opP->env); + esock_free_env("recv_check_failure", opP->env); + FREE( opP ); + + return esock_make_error(env, reason); +} + + + +/* ======================================================================== + * esaio_recvfrom - Read a "packet" from a socket + * + * The (read) buffer handling *must* be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throw'ing it away... + */ +extern +ERL_NIF_TERM esaio_recvfrom(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t len, + int flags) +{ + ErlNifPid caller; + ESAIOOperation* opP; + int rres; + WSABUF wbuf; + DWORD f = flags; + size_t bufSz = (len != 0 ? len : descP->rBufSz); + + if (bufSz < ESAIO_RECVFROM_MIN_BUFSZ) bufSz = ESAIO_RECVFROM_MIN_BUFSZ; + + SSDBG( descP, ("WIN-ESAIO", "essio_recvfrom {%d} -> entry with" + "\r\n bufSz: %d" + "\r\n", descP->sock, bufSz) ); + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read can not be simultaneous? */ + if (descP->acceptorsQ.first != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that this caller does not *already* have a + * (recv) request waiting */ + if (esock_reader_search4pid(env, descP, &caller)) { + /* Reader already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + /* Allocate the operation */ + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_RECVFROM; + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + opP->env = esock_alloc_env("esaio-recvfrom - operation"); + opP->data.recvfrom.recvRef = CP_TERM(opP->env, recvRef); + opP->data.recvfrom.sockRef = CP_TERM(opP->env, sockRef); + opP->caller = caller; + + /* Allocate a buffer: + * Either as much as we want to read or (if zero (0)) use the "default" + * size (what has been configured). + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &opP->data.recv.buf) ); + + opP->data.recvfrom.toRead = len; + wbuf.buf = opP->data.recvfrom.buf.data; + wbuf.len = opP->data.recvfrom.buf.size; + + opP->data.recvfrom.addrLen = sizeof(ESockAddress); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + SSDBG( descP, ("WIN-ESAIO", "esaio_recvfrom {%d} -> try read (%lu)\r\n", + descP->sock, (unsigned long) bufSz) ); + + rres = sock_recvfrom_O(descP->sock, &wbuf, &f, + (struct sockaddr*) &opP->data.recvfrom.fromAddr, + &opP->data.recvfrom.addrLen, (OVERLAPPED*) opP); + + return recvfrom_check_result(env, descP, opP, caller, rres, + sockRef, recvRef); +} + + + +/* *** recvfrom_check_result *** + * + * Analyze the result of a receive attempt. + * The receive may have been completed directly or scheduled (overlapped). + */ +static +ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM eres; + + if (recv_result == 0) { + + /* +++ Success +++ */ + + eres = recvfrom_check_ok(env, descP, opP, caller, sockRef, recvRef); + + } else { + int err; + + /* +++ Failure +++ */ + + err = sock_errno(); + + /* As pointed out above, there are basically two kinds of errors: + * 1) Pending: + * An overlapped operation was successfully initiated. + * Completion will be indicated at a later time. + * 2) An actual error + */ + + if (err == WSA_IO_PENDING) { + + if (! IS_ZERO(recvRef)) { + + eres = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + } else { + + /* We are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_result(%T, %d) -> " + "pending - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_result(%T, %d) -> " + "failed cancel pending operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + eres = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + eres = esock_atom_ok; // Will trigger {error, timeout} + + } + + } + + } else { + + eres = recvfrom_check_fail(env, descP, opP, err, sockRef); + + } + + } + + return eres; +} + + + +/* *** recvfrom_check_ok *** + * + * A successful recvfrom. We *know* that in this case the buffer is filled! + */ + +static +ERL_NIF_TERM recvfrom_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM data, result; + DWORD read = 0, flags = 0; + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_ok -> try get overlapped result\r\n") ); + + if (get_recv_ovl_result(descP->sock, (OVERLAPPED*) opP, &read, &flags)) { + + ERL_NIF_TERM eSockAddr; + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_ok -> overlapped result: " + "\r\n read: %d" + "\r\n flags: 0x%X" + "\r\n", read, flags) ); + + (void) flags; // We should really do something with this... + + esock_encode_sockaddr(env, + &opP->data.recvfrom.fromAddr, + opP->data.recvfrom.addrLen, + &eSockAddr); + + if (read == opP->data.recvfrom.buf.size) { + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, &opP->data.recvfrom.buf); + } else { + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(env, &opP->data.recvfrom.buf); + data = MKSBIN(env, data, 0, read); + } + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + /* (maybe) Update max */ + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + /* + * This is: {ok, {Source, Data}} + * But it should really be: {ok, {Source, Flags, Data}} + */ + result = esock_make_ok2(env, MKT2(env, eSockAddr, data)); + + } else { + + int save_errno = sock_errno(); + + switch (save_errno) { + case WSA_IO_INCOMPLETE: + /* + * WSA_IO_INCOMPLETE + * + * Even though it (the I/O Completion Port framework) told + * us it was done, it was not. So we need to postpone and let + * the (worker) threads deal with it anyway...effing framework... + */ + + if (! IS_ZERO(recvRef)) { + + result = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + + } else { + + /* But we are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_ok(%T, %d) -> " + "incomplete - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recvfrom_check_ok(%T, %d) -> " + "failed cancel incomplete operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + result = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + result = esock_atom_ok; // Will trigger {error, timeout} + + } + } + break; + + default: + { + ERL_NIF_TERM eerrno = ENO2T(env, save_errno); + ERL_NIF_TERM reason = MKT2(env, + esock_atom_get_overlapped_result, + eerrno); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.genErrs, 1); + + MUNLOCK(ctrl.cntMtx); + + result = esock_make_error(env, reason); + } + break; + } + } + + SSDBG( descP, + ("WIN-ESAIO", "recvfrom_check_ok(%T) {%d} -> done with" + "\r\n result: %T" + "\r\n", + sockRef, descP->sock, result) ); + + return result; +} + + + +/* *** recvfrom_check_fail *** + * + * Processing done upon failed 'recvfrom'. + * An actual failure. + */ +static +ERL_NIF_TERM recvfrom_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + SSDBG( descP, + ("WIN-ESAIO", "recfrom_check_fail(%T) {%d} -> entry with" + "\r\n errno: %d" + "\r\n", + sockRef, descP->sock, saveErrno) ); + + FREE_BIN( &opP->data.recvfrom.buf ); + + return recv_check_failure(env, descP, opP, saveErrno, sockRef); +} + + + + +/* ======================================================================== + * esaio_recvmsg - Read a "message" from a socket + * The (read) buffer handling *must* be optimized! + * But for now we make it easy for ourselves by + * allocating a binary (of the specified or default + * size) and then throwing it away... + * + * Note that this operation *only* works for socket + * of types SOCK_DGRAM and SOCK_RAW! Should we check + * and throw 'enotsup' otherwise? Would make testing + * easier... + */ +extern +ERL_NIF_TERM esaio_recvmsg(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + ssize_t bufLen, + ssize_t ctrlLen, + int flags) +{ + ErlNifPid caller; + ESAIOOperation* opP; + SOCKLEN_T addrLen; + size_t bufSz = (bufLen != 0 ? bufLen : descP->rBufSz); + size_t ctrlSz = (ctrlLen != 0 ? ctrlLen : descP->rCtrlSz); + int rres; + ERL_NIF_TERM eres; + + (void) flags; + + SSDBG( descP, ("WIN-ESAIO", "esaio_recvmsg(%T) {%d} -> entry with" + "\r\n bufSz: %lu (%ld)" + "\r\n ctrlSz: %ld (%ld)" + "\r\n", sockRef, descP->sock, + (unsigned long) bufSz, (long) bufLen, + (unsigned long) ctrlSz, (long) ctrlLen) ); + + /* This *only* works on socket type(s) DGRAM or RAW. + * Other socket types results in einval, which is not very + * helpful. So, in order to, atleast, help with testing, + * we do this... + */ + if (! ((descP->type == SOCK_DGRAM) || (descP->type == SOCK_RAW))) { + return enif_raise_exception(env, MKA(env, "notsup")); + } + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) + return esock_make_error_closed(env); + + /* Accept and Read can not be simultaneous? */ + if (descP->acceptorsQ.first != NULL) + return esock_make_error_invalid(env, esock_atom_state); + + /* Ensure that this caller does not *already* have a + * (recv) request waiting */ + if (esock_reader_search4pid(env, descP, &caller)) { + /* Reader already in queue */ + return esock_raise_invalid(env, esock_atom_state); + } + + /* Allocate the operation */ + opP = MALLOC( sizeof(ESAIOOperation) ); + ESOCK_ASSERT( opP != NULL); + sys_memzero((char*) opP, sizeof(ESAIOOperation)); + + opP->tag = ESAIO_OP_RECVMSG; + /* Its a bit annoying that we have to alloc an env and then + * copy the ref *before* we know that we actually need it. + * How much does this cost? + */ + opP->env = esock_alloc_env("esaio-recvmsg - operation"); + opP->data.recvmsg.recvRef = CP_TERM(opP->env, recvRef); + opP->data.recvmsg.sockRef = CP_TERM(opP->env, sockRef); + opP->caller = caller; + + /* Allocate the (msg) data buffer: + */ + ESOCK_ASSERT( ALLOC_BIN(bufSz, &opP->data.recvmsg.data[0]) ); + + /* Allocate the ctrl (buffer): + */ + ESOCK_ASSERT( ALLOC_BIN(ctrlSz, &opP->data.recvmsg.ctrl) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_tries, &descP->readTries, 1); + + addrLen = sizeof(opP->data.recvmsg.addr); + sys_memzero((char*) &opP->data.recvmsg.addr, addrLen); + sys_memzero((char*) &opP->data.recvmsg.msg, sizeof(opP->data.recvmsg.msg)); + + opP->data.recvmsg.wbufs[0].buf = opP->data.recvmsg.data[0].data; + opP->data.recvmsg.wbufs[0].len = opP->data.recvmsg.data[0].size; + + opP->data.recvmsg.msg.name = (SOCKADDR*) &opP->data.recvmsg.addr; + opP->data.recvmsg.msg.namelen = addrLen; + opP->data.recvmsg.msg.lpBuffers = opP->data.recvmsg.wbufs; + opP->data.recvmsg.msg.dwBufferCount = 1; // Should be calculated... + opP->data.recvmsg.msg.Control.buf = opP->data.recvmsg.ctrl.data; + opP->data.recvmsg.msg.Control.len = opP->data.recvmsg.ctrl.size; + opP->data.recvmsg.msg.dwFlags = 0; // TMP + + rres = sock_recvmsg_O(descP->sock, + &opP->data.recvmsg.msg, + (OVERLAPPED*) opP); + + eres = recvmsg_check_result(env, descP, opP, caller, rres, + sockRef, recvRef); + + SSDBG( descP, ("WIN-ESAIO", "esaio_recvmsg(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return eres; +} + + +static +BOOLEAN_T recv_check_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* caller, + ERL_NIF_TERM ref, + ERL_NIF_TERM* checkResult) +{ + BOOLEAN_T result; + + /* Check if already reader */ + if (! esock_reader_search4pid(env, descP, caller)) { + /* No; check if we can wait for a result */ + if (COMPARE(ref, esock_atom_zero) == 0) + return FALSE; + } else { + *checkResult = esock_raise_invalid(env, esock_atom_state); + } + + return TRUE; +} + + +/* *** recvmsg_check_result *** + * + * The recvmsg function (maybe) delivers one (1) message. If our buffer + * is to small, the message will be truncated. So, regardless of + * if we filled the buffer or not, we have got what we are going + * to get regarding this message. + */ +static +ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int recv_result, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM eres; + + SSDBG( descP, + ("WIN-ESAIO", "recvmsg_check_result(%T) {%d} -> entry with" + "\r\n recv_result: %d" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, recv_result, recvRef) ); + + if (recv_result == 0) { + + /* +++ Success +++ */ + + eres = recvmsg_check_ok(env, descP, opP, caller, sockRef, recvRef); + + } else { + int err; + + /* +++ Failure +++ */ + + err = sock_errno(); + + /* As pointed out above, there are basically two kinds of errors: + * 1) Pending: + * An overlapped operation was successfully initiated. + * Completion will be indicated at a later time. + * 2) An actual error + */ + + if (err == WSA_IO_PENDING) { + + if (! IS_ZERO(recvRef)) { + + eres = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + + } else { + + /* We are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_result(%T, %d) -> " + "pending - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_result(%T, %d) -> " + "failed cancel pending operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + eres = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + eres = esock_atom_ok; // Will trigger {error, timeout} + + } + + } + + } else { + + eres = recvmsg_check_fail(env, descP, opP, err, sockRef); + + } + + } + + SSDBG( descP, + ("WIN-ESAIO", "recvmsg_check_result(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return eres; +} + + +/* *** recvmsg_check_ok *** + * + * A successful recvmsg. We *know* that in this case the buffer is filled! + */ + +static +ERL_NIF_TERM recvmsg_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef) +{ + ERL_NIF_TERM eMsg, result; + DWORD read = 0, flags = 0; + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_ok(%T) {%d} -> try get overlapped result\r\n", + sockRef, descP->sock) ); + + if (get_recv_ovl_result(descP->sock, (OVERLAPPED*) opP, &read, &flags)) { + + ERL_NIF_TERM eSockAddr; + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_ok(%T, %d) -> overlapped success result: " + "\r\n read: %d" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, read, flags) ); + + (void) flags; // We should really do something with this... + + encode_msg(env, descP, read, + &opP->data.recvmsg.msg, + opP->data.recvmsg.data, + &opP->data.recvmsg.ctrl, + &eMsg); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + /* (maybe) Update max */ + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + result = esock_make_ok2(env, eMsg); + + } else { + + int save_errno = sock_errno(); + + switch (save_errno) { + case WSA_IO_INCOMPLETE: + /* + * WSA_IO_INCOMPLETE + * + * Even though it (the I/O Completion Port framework) told + * us it was done, it was not. So we need to postpone and let + * the (worker) threads deal with it anyway...effing framework... + */ + + if (! IS_ZERO(recvRef)) { + + result = recv_check_pending(env, descP, opP, caller, + sockRef, recvRef); + + } else { + + /* But we are not allowed to wait! => cancel */ + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_ok(%T, %d) -> " + "incomplete - but we are not allowed to wait => cancel" + "\r\n", sockRef, descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) opP)) { + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_cancel; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "recvmsg_check_ok(%T, %d) -> " + "failed cancel incomplete operation" + "\r\n %T" + "\r\n", sockRef, descP->sock, reason) ); + + result = esock_make_error(env, MKT2(env, tag, reason)); + + } else { + + result = esock_atom_ok; // Will trigger {error, timeout} + + } + } + break; + + default: + { + ERL_NIF_TERM eerrno = ENO2T(env, save_errno); + ERL_NIF_TERM reason = MKT2(env, + esock_atom_get_overlapped_result, + eerrno); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.genErrs, 1); + + MUNLOCK(ctrl.cntMtx); + + result = esock_make_error(env, reason); + } + break; + } + } + + SSDBG( descP, + ("WIN-ESAIO", "recvmsg_check_ok(%T) {%d} -> done with" + "\r\n result: %T" + "\r\n", + sockRef, descP->sock, result) ); + + return result; +} + + + +/* *** recvmsg_check_fail *** + * + * Processing done upon failed 'recvmsg'. + * An actual failure. + */ +static +ERL_NIF_TERM recvmsg_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + SSDBG( descP, + ("WIN-ESAIO", "recvmsg_check_fail(%T) {%d} -> entry with" + "\r\n errno: %d" + "\r\n", + sockRef, descP->sock, saveErrno) ); + + FREE_BIN( &opP->data.recvmsg.data[0] ); + FREE_BIN( &opP->data.recvmsg.ctrl ); + + return recv_check_failure(env, descP, opP, saveErrno, sockRef); +} + + + + + +/* ******************************************************************* + * esaio_close - Close a socket + * + * Stage 1 of the socket close + */ + +extern +ERL_NIF_TERM esaio_close(ErlNifEnv* env, + ESockDescriptor* descP) +{ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_close(%d) -> begin closing\r\n", + descP->sock) ); + + if (! IS_OPEN(descP->readState)) { + /* A bit of cheeting; maybe not closed yet - do we need a queue? */ + return esock_make_error_closed(env); + } + + /* Store the PID of the caller, + * since we need to inform it when we + * (that is, the stop callback function) + * completes. + */ + ESOCK_ASSERT( enif_self(env, &descP->closerPid) != NULL ); + + /* If the caller is not the owner; monitor the caller, + * since we should complete this operation even if the caller dies + * (for whatever reason). + */ + if (COMPARE_PIDS(&descP->closerPid, &descP->ctrlPid) != 0) { + + ESOCK_ASSERT( MONP("esaio_close-check -> closer", + env, descP, + &descP->closerPid, + &descP->closerMon) == 0 ); + } + + /* Prepare for closing the socket */ + descP->readState |= ESOCK_STATE_CLOSING; + descP->writeState |= ESOCK_STATE_CLOSING; + if (do_stop(env, descP)) { + + // stop() has been scheduled - wait for it + SSDBG( descP, + ("WIN-ESAIO", "esaio_close {%d} -> stop was scheduled\r\n", + descP->sock) ); + + // Create closeRef for the close msg that esock_stop() will send + descP->closeEnv = esock_alloc_env("esock_close_do - close-env"); + descP->closeRef = MKREF(descP->closeEnv); + + return esock_make_ok2(env, CP_TERM(env, descP->closeRef)); + + } else { + // The socket may be closed - tell caller to finalize + SSDBG( descP, + ("WIN-ESAIO", + "esaio_close {%d} -> stop was called\r\n", + descP->sock) ); + + return esock_atom_ok; + } +} + + + +static +BOOLEAN_T do_stop(ErlNifEnv* env, + ESockDescriptor* descP) +{ + BOOLEAN_T ret; + ERL_NIF_TERM sockRef; + + sockRef = enif_make_resource(env, descP); + + if (IS_SELECTED(descP)) { + + SSDBG( descP, + ("WIN-ESAIO", + "do_stop {%d} -> cancel outstanding I/O operations\r\n", + descP->sock) ); + + /* Cancel *all* outstanding I/O operations on the socket. + * We have to wait for the worker threads to process these ops! + * (will result in OPERATION_ABORTED for the threads). + */ + if (! CancelIoEx((HANDLE) descP->sock, NULL) ) { + int save_errno = sock_errno(); + ERL_NIF_TERM ereason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", + "do_stop {%d} -> cancel I/O failed: " + "\r\n %T\r\n", + descP->sock, ereason) ); + + /* Only issue an error message for errors *other* than + * 'not found' (since 'not found' means there is no active + * requests = already completed => race). + */ + + if (save_errno != ERROR_NOT_FOUND) + esock_error_msg("Failed cancel outstanding I/O operations:" + "\r\n Socket: " SOCKET_FORMAT_STR + "\r\n Reason: %T" + "\r\n", + descP->sock, ereason); + + ret = FALSE; + + } else { + + /* Cancel of all active requests (to the I/O completion port + * machinery) has been successfully requested. + * The requests will be aborted and handled by the worker threads. + */ + + SSDBG( descP, + ("WIN-ESAIO", + "do_stop {%d} -> successfully canceled\r\n", descP->sock) ); + + ret = TRUE; + } + + } else { + + /* No active requests in the I/O completion port machinery */ + + SSDBG( descP, + ("WIN-ESAIO", + "do_stop {%d} -> no active I/O requests\r\n", descP->sock) ); + + ret = FALSE; + } + + /* We do nothing here with the requests in the various queues + * They are handled by the working threads, when the abort is triggered + * (one for each request)! + */ + + /* +++++++ Connector +++++++ + * Note that there should not be Writers and a Connector + * at the same time so the check for if the + * current Writer/Connecter was deselected is only correct + * under that assumption + */ + + if (descP->connectorP != NULL) { + + /* We have a Connector; + * + * The Connector will not get a select message + * - send it an abort message + */ + + esock_stop_handle_current(env, + "connector", + descP, sockRef, &descP->connector); + + descP->connectorP = NULL; + } + + return ret; +} + + + +/* ======================================================================== + * Perform the final step in the socket close. + */ +extern +ERL_NIF_TERM esaio_fin_close(ErlNifEnv* env, + ESockDescriptor* descP) +{ + int err; + ErlNifPid self; + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (IS_CLOSED(descP->readState)) + return esock_make_error_closed(env); + + if (! IS_CLOSING(descP->readState)) { + // esock_close() has not been called + return esock_raise_invalid(env, esock_atom_state); + } + + if (IS_SELECTED(descP) && (descP->closeEnv != NULL)) { + // esock_stop() is scheduled but has not been called + return esock_raise_invalid(env, esock_atom_state); + } + + if (COMPARE_PIDS(&descP->closerPid, &self) != 0) { + // This process is not the closer + return esock_raise_invalid(env, esock_atom_state); + } + + // Close the socket + + /* Stop monitoring the closer. + * Demonitoring may fail since this is a dirty NIF + * - the caller may have died already. + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_fin_close {%d} -> demonitor closer process %T\r\n", + descP->sock, descP->closerPid) ); + enif_set_pid_undefined(&descP->closerPid); + if (descP->closerMon.isActive) { + (void) DEMONP("esaio_fin_close -> closer", + env, descP, &descP->closerMon); + } + + /* Stop monitoring the owner */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_fin_close {%d} -> demonitor owner process %T\r\n", + descP->sock, descP->ctrlPid) ); + enif_set_pid_undefined(&descP->ctrlPid); + (void) DEMONP("esaio_fin_close -> ctrl", + env, descP, &descP->ctrlMon); + /* Not impossible to still get a esock_down() call from a + * just triggered owner monitor down + */ + + /* This nif-function is executed in a dirty scheduler just so + * that it can "hang" (with minimum effect on the VM) while the + * kernel writes our buffers. IF we have set the linger option + * for this ({true, integer() > 0}). + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_fin_close {%d} -> (try) close the socket\r\n", + descP->sock, descP->ctrlPid) ); + err = esock_close_socket(env, descP, TRUE); + + if (err != 0) { + if (err == ERRNO_BLOCK) { + /* Not all data in the buffers where sent, + * make sure the caller gets this. + */ + return esock_make_error(env, esock_atom_timeout); + } else { + return esock_make_error_errno(env, err); + } + } + + SSDBG( descP, ("WIN-ESAIO", "esaio_fin_close -> done\r\n") ); + + return esock_atom_ok; +} + + + +/* ======================================================================== + * Cancel a connect request. + */ +extern +ERL_NIF_TERM esaio_cancel_connect(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + ErlNifPid self; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_connect {%d} -> entry with" + "\r\n writeState: 0x%X" + "\r\n opRef: %T" + "\r\n", + descP->sock, descP->writeState, opRef) ); + + ESOCK_ASSERT( enif_self(env, &self) != NULL ); + + if (! IS_OPEN(descP->writeState)) { + + res = esock_make_error_closed(env); + + } else if ((descP->connectorP == NULL) || + (COMPARE_PIDS(&self, &descP->connector.pid) != 0) || + (COMPARE(opRef, descP->connector.ref) != 0)) { + + res = esock_make_error(env, esock_atom_not_found); + + } else { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_connect {%d} -> " + "try cancel connect I/O request\r\n", + descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, + (OVERLAPPED*) descP->connector.dataP)) { + /* What does this mean? + * One of the possible reasons is that the connect succeeded. + * In which case, one of the threads in the thread-pool will + * be triggered (eventually). + * Then we have to deal with a connected socket that no one wants... + */ + int save_errno = sock_errno(); + res = esock_make_error_errno(env, save_errno); + } else { + res = esock_atom_ok; + } + + esock_requestor_release("esock_cancel_connect", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~ESOCK_STATE_CONNECTING; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_connect {%d} -> done when" + "\r\n res: %T" + "\r\n", + descP->sock, descP->writeState, + opRef, res) ); + + return res; +} + + + +/* *** esock_cancel_accept *** + * + * We have three different cases: + * *) Socket is closed: + * return error: closed + * *) Active accept (found in the request store): + * Cancel the completion request! + * Success will trigger an event (delivered) to the + * (completion) worker threads. + * *) Not found (in the request store): + * This request has already completed (race): + * return: not_found + * + */ +extern +ERL_NIF_TERM esaio_cancel_accept(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + ESockRequestor req; + ErlNifPid caller; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_accept(%T), {%d,0x%X} ->" + "\r\n opRef: %T" + "\r\n", sockRef, descP->sock, descP->readState, opRef) ); + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) { + + res = esock_make_error_closed(env); + + } else if (esock_acceptor_get(env, descP, &opRef, &caller, &req)) { + + ESOCK_ASSERT( DEMONP("esaio_cancel_accept -> acceptor", + env, descP, &req.mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_accept {%d} -> try cancel accept I/O request\r\n", + descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) req.dataP)) { + + /* What does this mean? + * One of the possible reasons is that the accept succeeded. + * In which case, one of the threads in the thread-pool will + * be triggered (eventually). + * Then we have to deal with a connected socket that no one wants... + */ + + int save_errno = sock_errno(); + res = esock_make_error_errno(env, save_errno); + + } else { + + res = esock_atom_ok; + + } + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_cancel_accept -> req cleanup", req.env); + esock_free_env("esaio_cancel_accept -> req cleanup", req.env); + + /* *Maybe* update listen socket (read) state + * (depends on if the queue is now empty) + */ + if (descP->acceptorsQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_ACCEPTING; + } + + } else { + + res = esock_make_error(env, esock_atom_not_found); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_cancel_accept(%T) -> done with result:" + "\r\n %T" + "\r\n", sockRef, res) ); + + return res; +} + + + + +/* *** esock_cancel_send *** + * + * We have three different cases: + * *) Socket is closed: + * return error: closed + * *) Active send (found in the request store): + * Cancel the completion request! + * Success will trigger an event (delivered) to the + * (completion) worker threads. + * *) Not found (in the request store): + * This request has already completed (race): + * return: not_found + * + */ +extern +ERL_NIF_TERM esaio_cancel_send(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + ESockRequestor req; + ErlNifPid caller; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_send(%T), {%d,0x%X} ->" + "\r\n opRef: %T" + "\r\n", sockRef, descP->sock, descP->readState, opRef) ); + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->writeState)) { + + res = esock_make_error_closed(env); + + } else if (esock_writer_get(env, descP, &opRef, &caller, &req)) { + + ESOCK_ASSERT( DEMONP("esaio_cancel_send -> sender", + env, descP, &req.mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_send {%d} -> try cancel send I/O request\r\n", + descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) req.dataP)) { + + /* What does this mean? + * One of the possible reasons is that the send succeeded. + * In which case, one of the threads in the thread-pool will + * be triggered (eventually). + */ + + int save_errno = sock_errno(); + res = esock_make_error_errno(env, save_errno); + + } else { + + res = esock_atom_ok; + + } + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_cancel_send -> req cleanup", req.env); + esock_free_env("esaio_cancel_send -> req cleanup", req.env); + + } else { + + res = esock_make_error(env, esock_atom_not_found); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_cancel_send(%T) -> done with result:" + "\r\n %T" + "\r\n", sockRef, res) ); + + return res; +} + + + + +/* *** esock_cancel_recv *** + * + * We have three different cases: + * *) Socket is closed: + * return error: closed + * *) Active receive (found in the request store): + * Cancel the completion request! + * Success will trigger an event (delivered) to the + * (completion) worker threads. + * *) Not found (in the request store): + * This request has already completed (race): + * return: not_found + * + */ +extern +ERL_NIF_TERM esaio_cancel_recv(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM opRef) +{ + ERL_NIF_TERM res; + ESockRequestor req; + ErlNifPid caller; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_recv(%T), {%d,0x%X} ->" + "\r\n opRef: %T" + "\r\n", sockRef, descP->sock, descP->readState, opRef) ); + + ESOCK_ASSERT( enif_self(env, &caller) != NULL ); + + if (! IS_OPEN(descP->readState)) { + + res = esock_make_error_closed(env); + + } else if (esock_reader_get(env, descP, &opRef, &caller, &req)) { + + ESOCK_ASSERT( DEMONP("esaio_cancel_recv -> reader", + env, descP, &req.mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_cancel_recv {%d} -> try cancel send I/O request\r\n", + descP->sock) ); + + if (! CancelIoEx((HANDLE) descP->sock, (OVERLAPPED*) req.dataP)) { + + /* What does this mean? + * One of the possible reasons is that the recv succeeded. + * In which case, one of the threads in the thread-pool will + * be triggered (eventually). + */ + + int save_errno = sock_errno(); + res = esock_make_error_errno(env, save_errno); + + } else { + + res = esock_atom_ok; + + } + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_cancel_recv -> req cleanup", req.env); + esock_free_env("esaio_cancel_recv -> req cleanup", req.env); + + } else { + + res = esock_make_error(env, esock_atom_not_found); + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_cancel_recv(%T) -> done with result:" + "\r\n %T" + "\r\n", sockRef, res) ); + + return res; +} + + + + +/* ======================================================================== + * IOCTL with three args (socket, request "key" and one argument) + * + * The type and value of 'arg' depend on the request, + * which we have not yet "analyzed". + * + * Request arg arg type + * ------- ------- -------- + * tcp_info version integer() + * rcvall command atom() (off | on | iplevel) + */ +extern +ERL_NIF_TERM esaio_ioctl3(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req, + ERL_NIF_TERM arg) +{ + switch (req) { + + /* These are *get* requests */ + +#if defined(SIO_TCP_INFO) + case SIO_TCP_INFO: + return esaio_ioctl_tcp_info(env, descP, arg); + break; +#endif + + /* These are *set* requests */ + +#if defined(SIO_RCVALL) + case SIO_RCVALL: + return esaio_ioctl_rcvall(env, descP, arg); + break; +#endif + +#if defined(SIO_RCVALL_IGMPMCAST) + case SIO_RCVALL_IGMPMCAST: + return esaio_ioctl_rcvall_igmpmcast(env, descP, arg); + break; +#endif + +#if defined(SIO_RCVALL_MCAST) + case SIO_RCVALL_MCAST: + return esaio_ioctl_rcvall_mcast(env, descP, arg); + break; +#endif + + + default: + return esock_make_error(env, esock_atom_enotsup); + break; + } + +} + + + +#if defined(SIO_TCP_INFO) +static +ERL_NIF_TERM esaio_ioctl_tcp_info(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM eversion) +{ + DWORD ndata = 0; // We do not actually use this + ERL_NIF_TERM result; + int res; + int version; + + SSDBG( descP, ("WIN-ESAIO", "esaio_ioctl_tcp_info(%d) -> entry with" + "\r\n (e)version: %T" + "\r\n", descP->sock, eversion) ); + + if (!GET_INT(env, eversion, &version)) + return enif_make_badarg(env); + + switch (version) { + case 0: + { + TCP_INFO_v0 info; + + sys_memzero((char *) &info, sizeof(info)); + res = sock_ioctl2(descP->sock, SIO_TCP_INFO, + &version, sizeof(version), + &info, sizeof(info), &ndata); + (void) ndata; + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_tcp_info(%d,v0) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + ERL_NIF_TERM einfo = encode_tcp_info_v0(env, &info); + + result = esock_make_ok2(env, einfo); + } + } + break; + +#if defined(HAVE_TCP_INFO_V1) + case 1: + { + TCP_INFO_v1 info; + + sys_memzero((char *) &info, sizeof(info)); + res = sock_ioctl2(descP->sock, SIO_TCP_INFO, + &version, sizeof(version), + &info, sizeof(info), &ndata); + (void) ndata; + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_tcp_info(%d,v1) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + ERL_NIF_TERM einfo = encode_tcp_info_v1(env, &info); + + result = esock_make_ok2(env, einfo); + } + } + break; +#endif + + default: + return enif_make_badarg(env); + } + + SSDBG( descP, + ("UNIX-ESSIO", "essio_ioctl_tcp_info(%d) -> done with" + "\r\n result: %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + +/* + typedef struct _TCP_INFO_v0 { + TCPSTATE State; + ULONG Mss; + ULONG64 ConnectionTimeMs; + BOOLEAN TimestampsEnabled; + ULONG RttUs; + ULONG MinRttUs; + ULONG BytesInFlight; + ULONG Cwnd; + ULONG SndWnd; + ULONG RcvWnd; + ULONG RcvBuf; + ULONG64 BytesOut; + ULONG64 BytesIn; + ULONG BytesReordered; + ULONG BytesRetrans; + ULONG FastRetrans; + ULONG DupAcksIn; + ULONG TimeoutEpisodes; + UCHAR SynRetrans; + } TCP_INFO_v0, *PTCP_INFO_v0; + * + typedef enum _TCPSTATE { + TCPSTATE_CLOSED, + TCPSTATE_LISTEN, + TCPSTATE_SYN_SENT, + TCPSTATE_SYN_RCVD, + TCPSTATE_ESTABLISHED, + TCPSTATE_FIN_WAIT_1, + TCPSTATE_FIN_WAIT_2, + TCPSTATE_CLOSE_WAIT, + TCPSTATE_CLOSING, + TCPSTATE_LAST_ACK, + TCPSTATE_TIME_WAIT, + TCPSTATE_MAX + } TCPSTATE; + */ +#if defined(SIO_TCP_INFO) +static +ERL_NIF_TERM encode_tcp_info_v0(ErlNifEnv* env, TCP_INFO_v0* infoP) +{ + ERL_NIF_TERM einfo; + ERL_NIF_TERM keys[] = {esock_atom_state, + esock_atom_mss, + esock_atom_connection_time, + esock_atom_timestamp_enabled, + esock_atom_rtt, + esock_atom_min_rtt, + esock_atom_bytes_in_flight, + esock_atom_cwnd, + esock_atom_snd_wnd, + esock_atom_rcv_wnd, + esock_atom_rcv_buf, + esock_atom_bytes_out, + esock_atom_bytes_in, + esock_atom_bytes_reordered, + esock_atom_bytes_retrans, + esock_atom_fast_retrans, + esock_atom_dup_acks_in, + esock_atom_timeout_episodes, + esock_atom_syn_retrans}; + ERL_NIF_TERM vals[] = {encode_tcp_state(env, infoP->State), + MKUL(env, infoP->Mss), + MKUI64(env, infoP->ConnectionTimeMs), + infoP->TimestampsEnabled ? esock_atom_true : esock_atom_false, + MKUL(env, infoP->RttUs), + MKUL(env, infoP->MinRttUs), + MKUL(env, infoP->BytesInFlight), + MKUL(env, infoP->Cwnd), + MKUL(env, infoP->SndWnd), + MKUL(env, infoP->RcvWnd), + MKUL(env, infoP->RcvBuf), + MKUI64(env, infoP->BytesOut), + MKUI64(env, infoP->BytesIn), + MKUL(env, infoP->BytesReordered), + MKUL(env, infoP->BytesRetrans), + MKUL(env, infoP->FastRetrans), + MKUL(env, infoP->DupAcksIn), + MKUL(env, infoP->TimeoutEpisodes), + MKUI(env, infoP->SynRetrans)}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &einfo) ); + + return einfo; +} +#endif + + +/* + typedef struct _TCP_INFO_v1 { + TCPSTATE State; + ULONG Mss; + ULONG64 ConnectionTimeMs; + BOOLEAN TimestampsEnabled; + ULONG RttUs; + ULONG MinRttUs; + ULONG BytesInFlight; + ULONG Cwnd; + ULONG SndWnd; + ULONG RcvWnd; + ULONG RcvBuf; + ULONG64 BytesOut; + ULONG64 BytesIn; + ULONG BytesReordered; + ULONG BytesRetrans; + ULONG FastRetrans; + ULONG DupAcksIn; + ULONG TimeoutEpisodes; + UCHAR SynRetrans; + ULONG SndLimTransRwin; + ULONG SndLimTimeRwin; + ULONG64 SndLimBytesRwin; + ULONG SndLimTransCwnd; + ULONG SndLimTimeCwnd; + ULONG64 SndLimBytesCwnd; + ULONG SndLimTransSnd; + ULONG SndLimTimeSnd; + ULONG64 SndLimBytesSnd; + } TCP_INFO_v1, *PTCP_INFO_v1; + */ +#if defined(SIO_TCP_INFO) && defined(HAVE_TCP_INFO_V1) +static +ERL_NIF_TERM encode_tcp_info_v1(ErlNifEnv* env, TCP_INFO_v1* infoP) +{ + ERL_NIF_TERM einfo; + ERL_NIF_TERM keys[] = {esock_atom_state, + esock_atom_mss, + esock_atom_connection_time, + esock_atom_timestamp_enabled, + esock_atom_rtt, + esock_atom_min_rtt, + esock_atom_bytes_in_flight, + esock_atom_cwnd, + esock_atom_snd_wnd, + esock_atom_rcv_wnd, + esock_atom_rcv_buf, + esock_atom_bytes_out, + esock_atom_bytes_in, + esock_atom_bytes_reordered, + esock_atom_bytes_retrans, + esock_atom_fast_retrans, + esock_atom_dup_acks_in, + esock_atom_timeout_episodes, + esock_atom_syn_retrans, + esock_atom_syn_lim_trans_rwin, + esock_atom_syn_lim_time_rwin, + esock_atom_syn_lim_bytes_rwin, + esock_atom_syn_lim_trans_cwnd, + esock_atom_syn_lim_time_cwnd, + esock_atom_syn_lim_bytes_cwnd, + esock_atom_syn_lim_trans_snd, + esock_atom_syn_lim_time_snd, + esock_atom_syn_lim_bytes_snd}; + ERL_NIF_TERM vals[] = {encode_tcp_state(env, infoP->State), + MKUL(env, infoP->Mss), + MKUI64(end, infoP->ConnectionTimeMs), + infoP->TimestampsEnabled ? esock_atom_true : esock_atom_false, + MKUL(env, infoP->RttUs), + MKUL(env, infoP->MinRttUs), + MKUL(env, infoP->BytesInFlight), + MKUL(env, infoP->Cwnd), + MKUL(env, infoP->SndWnd), + MKUL(env, infoP->RcvWnd), + MKUL(env, infoP->RcvBuf), + MKUI64(env, infoP->BytesOut), + MKUI64(env, infoP->BytesIn), + MKUL(env, infoP->BytesReordered), + MKUL(env, infoP->BytesRetrans), + MKUL(env, infoP->FastRetrans), + MKUL(env, infoP->DupAcksIn), + MKUL(env, infoP->TimeoutEpisodes), + MKUI(env, infoP->SynRetrans), + MKUL(env, infoP->SndLimTransRwin), + MKUL(env, infoP->SndLimTimeRwin), + MKUI64(env, infoP->SndLimBytesRwin), + MKUL(env, infoP->SndLimTransCwnd), + MKUL(env, infoP->SndLimTimeCwnd), + MKUI64(env, infoP->SndLimBytesCwnd), + MKUL(env, infoP->SndLimTransSnd), + MKUL(env, infoP->SndLimTimeSnd), + MKUI64(env, infoP->SndLimBytesSnd)}; + unsigned int numKeys = NUM(keys); + unsigned int numVals = NUM(vals); + + ESOCK_ASSERT( numKeys == numVals ); + ESOCK_ASSERT( MKMA(env, keys, vals, numKeys, &einfo) ); + + return einfo; +} +#endif + + + +#if defined(SIO_TCP_INFO) +static +ERL_NIF_TERM encode_tcp_state(ErlNifEnv* env, TCPSTATE state) +{ + ERL_NIF_TERM estate; + + switch (state) { + case TCPSTATE_CLOSED: + estate = esock_atom_closed; + break; + case TCPSTATE_LISTEN: + estate = esock_atom_listen; + break; + case TCPSTATE_SYN_SENT: + estate = esock_atom_syn_sent; + break; + case TCPSTATE_SYN_RCVD: + estate = esock_atom_syn_rcvd; + break; + case TCPSTATE_ESTABLISHED: + estate = esock_atom_established; + break; + case TCPSTATE_FIN_WAIT_1: + estate = esock_atom_fin_wait_1; + break; + case TCPSTATE_FIN_WAIT_2: + estate = esock_atom_fin_wait_2; + break; + case TCPSTATE_CLOSE_WAIT: + estate = esock_atom_close_wait; + break; + case TCPSTATE_CLOSING: + estate = esock_atom_closing; + break; + case TCPSTATE_LAST_ACK: + estate = esock_atom_last_ack; + break; + case TCPSTATE_TIME_WAIT: + estate = esock_atom_time_wait; + break; + case TCPSTATE_MAX: + estate = esock_atom_max; + break; + default: + estate = MKI(env, state); + break; + } + + return estate; +} +#endif + + +#if defined(SIO_RCVALL) +static +ERL_NIF_TERM esaio_ioctl_rcvall(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue) +{ + DWORD ndata = 0; // We do not actually use this + ERL_NIF_TERM result; + int value, res; + + SSDBG( descP, ("WIN-ESAIO", "esaio_ioctl_rcvall(%d) -> entry with" + "\r\n (e)value: %T" + "\r\n", descP->sock, evalue) ); + + if (! IS_ATOM(env, evalue)) + return enif_make_badarg(env); + + if (COMPARE(evalue, esock_atom_off) == 0) { + value = RCVALL_OFF; + } else if (COMPARE(evalue, esock_atom_on) == 0) { + value = RCVALL_ON; + } else if (COMPARE(evalue, esock_atom_iplevel) == 0) { + value = RCVALL_IPLEVEL; + } else { + return enif_make_badarg(env); + } + + res = sock_ioctl2(descP->sock, SIO_RCVALL, + &value, sizeof(value), + NULL, 0, &ndata); + (void) ndata; + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall(%d) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + + result = esock_atom_ok; + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall(%d) -> done with" + "\r\n result: %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + + +#if defined(SIO_RCVALL_IGMPMCAST) +static +ERL_NIF_TERM esaio_ioctl_rcvall_igmpmcast(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue) +{ + DWORD ndata = 0; // We do not actually use this + ERL_NIF_TERM result; + int value, res; + + SSDBG( descP, ("WIN-ESAIO", "esaio_ioctl_rcvall_igmpmcast(%d) -> entry with" + "\r\n (e)value: %T" + "\r\n", descP->sock, evalue) ); + + if (! IS_ATOM(env, evalue)) + return enif_make_badarg(env); + + if (COMPARE(evalue, esock_atom_off) == 0) { + value = RCVALL_OFF; + } else if (COMPARE(evalue, esock_atom_on) == 0) { + value = RCVALL_ON; + } else { + return enif_make_badarg(env); + } + + res = sock_ioctl2(descP->sock, SIO_RCVALL_IGMPMCAST, + &value, sizeof(value), + NULL, 0, &ndata); + (void) ndata; + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall_igmpmcast(%d) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + + result = esock_atom_ok; + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall_igmpmcast(%d) -> done with" + "\r\n result: %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + + +#if defined(SIO_RCVALL_MCAST) +/* + * We should really have a common function for this, + * since igmpmcast and mcast is basically identical. + */ +static +ERL_NIF_TERM esaio_ioctl_rcvall_mcast(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM evalue) +{ + DWORD ndata = 0; // We do not actually use this + ERL_NIF_TERM result; + int value, res; + + SSDBG( descP, ("WIN-ESAIO", "esaio_ioctl_rcvall_mcast(%d) -> entry with" + "\r\n (e)value: %T" + "\r\n", descP->sock, evalue) ); + + if (! IS_ATOM(env, evalue)) + return enif_make_badarg(env); + + if (COMPARE(evalue, esock_atom_off) == 0) { + value = RCVALL_OFF; + } else if (COMPARE(evalue, esock_atom_on) == 0) { + value = RCVALL_ON; + } else { + return enif_make_badarg(env); + } + + res = sock_ioctl2(descP->sock, SIO_RCVALL_MCAST, + &value, sizeof(value), + NULL, 0, &ndata); + (void) ndata; + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall_mcast(%d) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + + result = esock_atom_ok; + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_rcvall_mcast(%d) -> done with" + "\r\n result: %T" + "\r\n", + descP->sock, result) ); + + return result; + +} +#endif + + + +/* ======================================================================== + * IOCTL with two args (socket and request "key") + * + */ +extern +ERL_NIF_TERM esaio_ioctl2(ErlNifEnv* env, + ESockDescriptor* descP, + unsigned long req) +{ + switch (req) { + +#if defined(FIONREAD) + case FIONREAD: + return esaio_ioctl_fionread(env, descP); + break; +#endif + +#if defined(SIOCATMARK) + case SIOCATMARK: + return esaio_ioctl_siocatmark(env, descP); + break; +#endif + + default: + return esock_make_error(env, esock_atom_enotsup); + break; + } + +} + + +#if defined(FIONREAD) +static +ERL_NIF_TERM esaio_ioctl_fionread(ErlNifEnv* env, + ESockDescriptor* descP) +{ + u_long n = 0; + DWORD ndata = 0; // We do not actually use this + int res; + ERL_NIF_TERM result; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_fionread(%d) -> entry\r\n", descP->sock) ); + + res = sock_ioctl2(descP->sock, FIONREAD, NULL, 0, &n, sizeof(n), &ndata); + (void) ndata; + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_fionread(%d) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + + result = esock_encode_ioctl_ivalue(env, descP, n); + + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_ioctl_fionread(%d) -> done with: " + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + return result; +} +#endif + + +/* For a stream socket that has been configured for inline reception of any + * OOB data (SO_OOBINLINE), tests if there is any OOB data waiting to be read. + * Returns TRUE if there data waiting to be read, FALSE otherwise. + */ +#if defined(SIOCATMARK) +static +ERL_NIF_TERM esaio_ioctl_siocatmark(ErlNifEnv* env, + ESockDescriptor* descP) +{ + int b = 0; + DWORD ndata = 0; // We do not actually use this + int res; + ERL_NIF_TERM result; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_siocatmark(%d) -> entry\r\n", + descP->sock) ); + + res = sock_ioctl2(descP->sock, SIOCATMARK, NULL, 0, &b, sizeof(b), &ndata); + (void) ndata; + + if (res != 0) { + int save_errno = sock_errno(); + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_ioctl_siocatmark(%d) -> failure: " + "\r\n reason: %T" + "\r\n", descP->sock, reason) ); + + result = esock_make_error(env, reason); + + } else { + + result = esock_encode_ioctl_bvalue(env, descP, b); + + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_ioctl_siocatmark(%d) -> done with: " + "\r\n result: %T" + "\r\n", descP->sock, result) ); + + return result; +} +#endif + + + + +/* ==================================================================== + * + * The "worker" thread of the I/O Completion Port thread pool. + * Shall each thread have its own environment? + * + * ==================================================================== + */ + +static +void* esaio_completion_main(void* threadDataP) +{ + char envName[64]; /* Used for building the (env-) name */ + BOOLEAN_T done = FALSE; + ESAIOThreadData* dataP = (ESAIOThreadData*) threadDataP; + ESockDescriptor* descP = NULL; + ESAIOOperation* opP; + OVERLAPPED* olP; + BOOL res; + DWORD numBytes, flags = 0; + int save_errno; + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> entry\r\n") ); + + dataP->state = ESAIO_THREAD_STATE_INITIATING; + + sprintf(envName, "esaio-completion-main[%d]", dataP->id); + dataP->env = esock_alloc_env(envName); + + dataP->state = ESAIO_THREAD_STATE_OPERATIONAL; + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> initiated\r\n") ); + + while (!done) { + /* + * If this function *fails*, return value FALSE, the (out-) arguments: + * - lpNumberOfBytes (numBytes) + * - lpCompletionKey (descP) + * - lpOverlapped (olP) + * *can* contain particular value combinations as follows: + * + * * If *lpOverlapped is NULL, the function did not dequeue a + * completion packet from the completion port. + * In this case, the function does not store information in the + * variables pointed to by the lpNumberOfBytes and lpCompletionKey + * parameters, and their values are indeterminate. + * + * * If *lpOverlapped is not NULL and the function dequeues a + * completion packet for a failed I/O operation from the + * completion port, the function stores information about the + * failed operation in the variables pointed to by lpNumberOfBytes, + * lpCompletionKey, and lpOverlapped. + * To get extended error information, call GetLastError. + * + */ + + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> [%d] try dequeue packet\r\n", + dataP->cnt) ); + + res = GetQueuedCompletionStatus(ctrl.cport, + &numBytes, + (PULONG_PTR) &descP, + &olP, + INFINITE); + save_errno = NO_ERROR; + + if (!res) { + + save_errno = sock_errno(); // Details + + if (olP == NULL) { + + /* First alt. + * What shall we do here? Quit? Try again? + */ + + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> [failure 1]" + "\r\n %s (%d)" + "\r\n", erl_errno_id(save_errno), save_errno) ); + + dataP->state = ESAIO_THREAD_STATE_TERMINATING; + dataP->error = ESAIO_THREAD_ERROR_GET; + opP = NULL; + done = TRUE; + break; + + } else { + + /* Second alt. + * Dequeued a complete packet for a *failed* I/O operation. + */ + + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> [failure 2] " + "\r\n %s (%d)" + "\r\n", erl_errno_id(save_errno), save_errno) ); + + opP = CONTAINING_RECORD(olP, ESAIOOperation, ol); + esaio_completion_inc(dataP); + + } + } else { + opP = CONTAINING_RECORD(olP, ESAIOOperation, ol); + esaio_completion_inc(dataP); + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> success\r\n") ); + + } /* if (!res) */ + + dataP->latest = opP->tag; + + switch (opP->tag) { + case ESAIO_OP_TERMINATE: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received terminate cmd\r\n") ); + done = esaio_completion_terminate(dataP, (OVERLAPPED*) opP); + break; + + case ESAIO_OP_CONNECT: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received connect cmd\r\n") ); + done = esaio_completion_connect(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.connect, + save_errno); + break; + + case ESAIO_OP_ACCEPT: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received accept cmd\r\n") ); + done = esaio_completion_accept(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.accept, + save_errno); + break; + + case ESAIO_OP_SEND: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received send cmd\r\n") ); + done = esaio_completion_send(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.send, + save_errno); + break; + + case ESAIO_OP_SENDTO: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received sendto cmd\r\n") ); + done = esaio_completion_sendto(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.sendto, + save_errno); + break; + + case ESAIO_OP_SENDMSG: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received sendmsg cmd\r\n") ); + done = esaio_completion_sendmsg(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.sendmsg, + save_errno); + break; + + case ESAIO_OP_RECV: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received recv cmd\r\n") ); + done = esaio_completion_recv(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.recv, + save_errno); + break; + + case ESAIO_OP_RECVFROM: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received recvfrom cmd\r\n") ); + done = esaio_completion_recvfrom(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.recvfrom, + save_errno); + break; + + case ESAIO_OP_RECVMSG: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received recvmsg cmd\r\n") ); + done = esaio_completion_recvmsg(dataP, descP, (OVERLAPPED*) opP, + opP->env, &opP->caller, + &opP->data.recvmsg, + save_errno); + break; + + default: + SGDBG( ("WIN-ESAIO", + "esaio_completion_main -> received unknown cmd: " + "\r\n %d" + "\r\n", + opP->tag) ); + done = esaio_completion_unknown(dataP, descP, (OVERLAPPED*) opP, + numBytes, save_errno); + break; + + } + + FREE(opP); + + } /* while (!done) */ + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> terminating\r\n") ); + + TEXIT(threadDataP); + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> terminated\r\n") ); + + dataP->state = ESAIO_THREAD_STATE_TERMINATED; + + SGDBG( ("WIN-ESAIO", "esaio_completion_main -> done\r\n") ); + + return threadDataP; +} + + +/* *** esaio_completion_terminate *** + * + * We are done + * + */ +static +BOOLEAN_T esaio_completion_terminate(ESAIOThreadData* dataP, + OVERLAPPED* ovl) +{ + (void) ovl; + + dataP->state = ESAIO_THREAD_STATE_TERMINATING; + dataP->error = ESAIO_THREAD_ERROR_CMD; + + return TRUE; +} + + +/* *** esaio_completion_connect *** + * + * Handle a completed 'connect' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:connect(Socket, ..., nowait), the connect is + * scheduled, and then just as it has completed, but before this + * thread has been activated to handle the 'connect completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + */ +static +BOOLEAN_T esaio_completion_connect(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataConnect* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_connect(%d) -> entry\r\n", + descP->sock, error) ); + + (void) opCaller; + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_connect(%d) -> success" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_connect_success(env, descP, opDataP); + + MUNLOCK(descP->writeMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_connect_aborted(env, descP, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect(%d) -> unknown failure:" + "\r\n %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + MLOCK(descP->writeMtx); + + esaio_completion_connect_failure(env, descP, opDataP, error); + + MUNLOCK(descP->writeMtx); + break; + } + + SGDBG( ("WIN-ESAIO", + "esaio_completion_connect -> clear and delete op env\r\n") ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_connect", opEnv); + esock_free_env("esaio_completion_connect", opEnv); + + SGDBG( ("WIN-ESAIO", "esaio_completion_connect -> done\r\n") ); + + return FALSE; +} + + + +/* *** esaio_completion_connect_success *** + * The 'connect' operation was successful. + */ +static +void esaio_completion_connect_success(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP) +{ + if (descP->connectorP != NULL) { + if (IS_OPEN(descP->writeState)) { + esaio_completion_connect_completed(env, descP, opDataP); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("esaio_completion_connect_success -> " + "not active", + env, descP, &descP->connector); + descP->connectorP = NULL; + + descP->writeState &= + ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + + esaio_completion_connect_not_active(descP); + } + } else { + /* Connect was actually completed directly + * (and 'connector' was therefor not initiated) + * => Nothing to do here, other than cleanup. + */ + descP->writeState &= ~ESOCK_STATE_SELECTED; + } +} + + + +/* *** esaio_completion_connect_aborted *** + * The 'connect' operation was aborted. + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_connect_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP) +{ + if (descP->connectorP != NULL) { + + ERL_NIF_TERM reason = esock_atom_closed; + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + descP->connectorP, reason); + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("connect_stream_check_result -> abort", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + if (! IS_OPEN(descP->writeState)) { + + esaio_stop(env, descP); + + } + } else { + descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + } +} + + +/* *** esaio_completion_connect_failure * + * A "general" failure happened while performing the 'connect' operation. + */ +static +void esaio_completion_connect_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP, + int error) +{ + if (descP->connectorP != NULL) { + /* Figure out the reason */ + ERL_NIF_TERM reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + descP->connectorP, reason); + esaio_completion_connect_fail(env, descP, error, FALSE); + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("connect_stream_check_result -> failure", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + + } else { + esaio_completion_connect_fail(env, descP, error, TRUE); + } +} + + +/* *** esaio_completion_connect_completed *** + * The connect request has completed. + */ +static +void esaio_completion_connect_completed(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOpDataConnect* opDataP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + int ucres; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect_completed(%d) -> " + "success - try update context\r\n", descP->sock) ); + + ucres = ESAIO_UPDATE_CONNECT_CONTEXT( descP->sock ); + + if (ucres == 0) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect_completed({%d) -> success\r\n", + descP->sock) ); + + descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + descP->writeState |= ESOCK_STATE_CONNECTED; + + completionStatus = esock_atom_ok; + + } else { + + /* It is actually possible that this is an error "we do not know" + * which will result in the atom 'unknown', which is not very useful... + * So, we should really test if is 'unknown' and if so use the actual + * value (the integer) instead. + */ + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_update_connect_context; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, ("WIN-ESAIO", + "esaio_completion_connect_completed(%d) -> " + "failed update connect context: %T\r\n", + descP->sock, reason) ); + + descP->writeState = ESOCK_STATE_CLOSED; + + sock_close(descP->sock); + + WSACleanup(); + + completionStatus = esock_make_error_t2r(descP->connector.env, + tag, reason); + + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect_completed {%d} -> " + "completion status: %T\r\n", + descP->sock, completionStatus) ); + + completionInfo = MKT2(descP->connector.env, + descP->connector.ref, + completionStatus); + + /* Send a 'connect' completion message */ + esaio_send_completion_msg(env, + descP, + &descP->connector.pid, + descP->connector.env, + CP_TERM(descP->connector.env, opDataP->sockRef), + completionInfo); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect_completed {%d} -> cleanup\r\n", + descP->sock) ); + + /* Clean up the connector stuff, no need for that anymore */ + esock_requestor_release("esaio_completion_connect_completed", + env, descP, &descP->connector); + descP->connectorP = NULL; + +} + + + +/* *** esaio_completion_connect_not_active *** + * A connect has completed but the operation is no longer valid. + */ +static +void esaio_completion_connect_not_active(ESockDescriptor* descP) +{ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_connect_not_active -> " + "success for cancelled connect\r\n") ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unexpectedConnects, 1); + + MUNLOCK(ctrl.cntMtx); + +} + + + +/* *** esaio_completion_connect_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_connect_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + descP->writeState &= ~(ESOCK_STATE_CONNECTING | ESOCK_STATE_SELECTED); + esaio_completion_fail(env, descP, "connect", error, inform); +} + + + + +/* === accept 'stuff' === */ + +/* *** esaio_completion_accept *** + * + * Handle a completed 'accept' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:accept(Socket, ..., nowait), the accept is + * scheduled, and then just as it has completed, but before this + * thread has been activated to handle the 'accept completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + */ +static +BOOLEAN_T esaio_completion_accept(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_accept(%d) -> entry with" + "\r\n error: %s (%d)" + "\r\n", descP->sock, erl_errno_id(error), error) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_accept(%d) -> success" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_accept_success(env, descP, opEnv, opCaller, opDataP); + + MUNLOCK(descP->readMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_accept_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept(%d) -> unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_accept_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->readMtx); + break; + } + + SGDBG( ("WIN-ESAIO", + "esaio_completion_accept -> clear and delete op env\r\n") ); + + /* "Manually" allocated buffer */ + FREE( opDataP->buf ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_accept - op cleanup", opEnv); + esock_free_env("esaio_completion_accept - op cleanup", opEnv); + + SGDBG( ("WIN-ESAIO", "esaio_completion_accept -> done\r\n") ); + + return FALSE; + +} + + +/* *** esaio_completion_accept_success *** + * The 'accept' operation was successful. + */ +static +void esaio_completion_accept_success(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP) +{ + ESockRequestor req; + + if (esock_acceptor_get(env, descP, + &opDataP->accRef, + opCaller, + &req)) { + if (IS_OPEN(descP->readState)) { + esaio_completion_accept_completed(env, descP, + opEnv, opCaller, opDataP, + &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_accept_not_active(descP); + } + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + * => But we do not free the "buffer" since it was "used up" + * when we (as assumed) got the result (directly)... + */ + } + + /* *Maybe* update socket (read) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_success(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->acceptorsQ.first == NULL)), descP->readState) ); + if (descP->acceptorsQ.first == NULL) { + descP->readState &= ~(ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); + } +} + + +/* *** esaio_completion_accept_aborted *** + * The 'accept' operation was aborted. + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_accept_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_acceptor_get(env, descP, + &opDataP->accRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->lSockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (read) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->readState)))) ); + + if (! IS_OPEN(descP->readState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->acceptorsQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->readersQ.first == NULL) && + (descP->writersQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + /* *Maybe* update socket (read) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_aborted(%d) -> " + "maybe (%s) update (read) state (0x%X)\r\n", + descP->sock, + B2S((descP->acceptorsQ.first == NULL)), descP->readState) ); + if (descP->acceptorsQ.first == NULL) { + descP->readState &= ~(ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); + } + +} + + +/* *** esaio_completion_accept_failure * + * A "general" failure happened while performing the 'accept' operation. + */ +static +void esaio_completion_accept_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + if (esock_acceptor_get(env, descP, + &opDataP->accRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->lSockRef, + &req, reason); + esaio_completion_accept_fail(env, descP, error, FALSE); + } else { + esaio_completion_accept_fail(env, descP, error, TRUE); + } + + /* *Maybe* update socket (read) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_failure(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->acceptorsQ.first == NULL)), descP->readState) ); + if (descP->acceptorsQ.first == NULL) { + descP->readState &= ~(ESOCK_STATE_ACCEPTING | ESOCK_STATE_SELECTED); + } + +} + + +/* *** esaio_completion_accept_completed *** + * The accept request has completed. + */ +static +void esaio_completion_accept_completed(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataAccept* opDataP, + ESockRequestor* reqP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + int ucres; + ESockDescriptor* accDescP; + ERL_NIF_TERM accRef, accSocket; + + ESOCK_ASSERT( DEMONP("esaio_completion_accept_completed - acceptor", + env, descP, &reqP->mon) == 0); + + /* We need to make sure peername and sockname works! */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_completed -> " + "success - try update context\r\n") ); + + ucres = ESAIO_UPDATE_ACCEPT_CONTEXT( opDataP->asock, opDataP->lsock ); + + if (ucres == 0) { + + int save_errno; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_completed -> " + "create (accepted) descriptor\r\n") ); + + accDescP = esock_alloc_descriptor(opDataP->asock); + + if (ESAIO_OK != (save_errno = esaio_add_socket(accDescP))) { + // See esock_dtor for what needs done! + ERL_NIF_TERM tag = esock_atom_add_socket; + ERL_NIF_TERM reason = ENO2T(opEnv, save_errno); + + ESOCK_CNT_INC(env, descP, CP_TERM(env, opDataP->lSockRef), + esock_atom_acc_fails, &descP->accFails, 1); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_completed -> " + "failed adding (accepted) socket to completion port: " + "%T\r\n", reason) ); + + esock_dealloc_descriptor(env, accDescP); + sock_close(opDataP->asock); + + /* This should really be: + * {error, {invalid, {add_to_completion_port, Reason}}} + */ + + completionStatus = esock_make_error_t2r(opEnv, tag, reason); + + } else { + + ESOCK_CNT_INC(env, descP, CP_TERM(env, opDataP->lSockRef), + esock_atom_acc_success, &descP->accSuccess, 1); + + accDescP->domain = descP->domain; + accDescP->type = descP->type; + accDescP->protocol = descP->protocol; + + MLOCK(descP->writeMtx); + + accDescP->rBufSz = descP->rBufSz; // Inherit buffer size + accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size + accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size + accDescP->iow = descP->iow; // Inherit iow + accDescP->dbg = descP->dbg; // Inherit debug flag + accDescP->useReg = descP->useReg; // Inherit useReg flag + esock_inc_socket(accDescP->domain, accDescP->type, + accDescP->protocol); + + accRef = enif_make_resource(env, accDescP); + enif_release_resource(accDescP); + accSocket = esock_mk_socket(opEnv, CP_TERM(opEnv, accRef)); + + accDescP->ctrlPid = *opCaller; + + ESOCK_ASSERT( MONP("esaio_completion_accept_completed -> ctrl", + env, accDescP, + &accDescP->ctrlPid, + &accDescP->ctrlMon) == 0 ); + + accDescP->writeState |= ESOCK_STATE_CONNECTED; + + MUNLOCK(descP->writeMtx); + + /* And finally (maybe) update the registry */ + if (descP->useReg) + esock_send_reg_add_msg(env, descP, accRef); + + completionStatus = esock_make_ok2(opEnv, accSocket); + + } + + } else { + + /* It is actually possible that this is an error "we do not know" + * which will result in the atom 'unknown', which is not very useful... + * So, we should really test if is 'unknown' and if so use the actual + * value (the integer) instead. + */ + int save_errno = sock_errno(); + ERL_NIF_TERM tag = esock_atom_update_accept_context; + ERL_NIF_TERM reason = ENO2T(env, save_errno); + + SSDBG( descP, ("WIN-ESAIO", + "esaio_completion_accept_completed(%d) -> " + "accept context update failed: %T (%d)\r\n", + descP->sock, reason, save_errno) ); + + sock_close(descP->sock); + descP->writeState = ESOCK_STATE_CLOSED; + + WSACleanup(); + + completionStatus = esock_make_error_t2r(opEnv, tag, reason); + + } + + completionInfo = MKT2(opEnv, opDataP->accRef, completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_completed -> " + "send completion message to %T with" + "\r\n CompletionInfo: %T" + "\r\n", MKPID(env, opCaller), completionInfo) ); + + /* Send a 'accept' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + opCaller, // Msg destination + opEnv, // Msg env + opDataP->lSockRef, // Dest socket + completionInfo); // Info + + /* *** Finalize *** */ + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_accept_completed -> finalize\r\n") ); + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_completion_accept_completed -> req cleanup", + reqP->env); + esock_free_env("esaio_completion_accept_completed -> req cleanup", + reqP->env); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_accept_completed -> done\r\n") ); +} + + + +/* *** esaio_completion_accept_not_active *** + * A accept request has completed but the request is no longer valid. + */ +static +void esaio_completion_accept_not_active(ESockDescriptor* descP) +{ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_not_active(%d) -> " + "success for not active accept request\r\n", descP->sock) ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unexpectedAccepts, 1); + + MUNLOCK(ctrl.cntMtx); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_accept_not_active(%d) -> done\r\n", + descP->sock) ); + +} + + +/* *** esaio_completion_accept_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_accept_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "accept", error, inform); +} + + + + +/* === send 'stuff' === */ + +/* *** esaio_completion_send *** + * + * Handle a completed 'send' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:send(Socket, ..., nowait), the send is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'send completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + * + * We need to use 'WSAGetOverlappedResult' to actually figure out the + * "transfer result" (how much was sent). + */ +static +BOOLEAN_T esaio_completion_send(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_send(%d) -> entry with" + "\r\n error: %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_send(%d) -> no error" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_send_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_send_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send(%d) -> operation unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_send_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->writeMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send(%d) -> cleanup\r\n", descP->sock) ); + + FREE( opDataP->wbuf.buf ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_send - op cleanup", opEnv); + esock_free_env("esaio_completion_send - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_send(%d) -> done\r\n", + descP->sock) ); + + return FALSE; + +} + + + +/* *** esaio_completion_send_success *** + * The 'send' operation was successful. + */ +static +void esaio_completion_send_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP) +{ + ESockRequestor req; + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + if (IS_OPEN(descP->writeState)) { + esaio_completion_send_completed(env, descP, ovl, opEnv, + opCaller, + opDataP->sockRef, + opDataP->sendRef, + opDataP->wbuf.len, + &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_send_not_active(descP); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_success(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + + +/* *** esaio_completion_send_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_send_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (write) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->writeState)))) ); + + if (! IS_OPEN(descP->writeState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->writersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->readersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_aborted(%d) -> " + "maybe (%s) update (write) state (0x%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + + +/* *** esaio_completion_send_failure * + * A "general" failure happened while performing the 'send' operation. + */ +static +void esaio_completion_send_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSend* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_send_fail(env, descP, error, FALSE); + + } else { + esaio_completion_send_fail(env, descP, error, TRUE); + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_failure(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_send_completed *** + * The send request has completed. + */ +static +void esaio_completion_send_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* sender, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + DWORD toWrite, + ESockRequestor* reqP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + DWORD written; + + ESOCK_ASSERT( DEMONP("esaio_completion_send_completed - sender", + env, descP, &reqP->mon) == 0); + + /* Success, but we need to check how much we actually got. + * Also the 'flags' (which we currenty ignore) + * + * CompletionStatus = ok | {ok, RestData} + * CompletionInfo = {ConnRef, CompletionStatus} + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_completed ->" + "success - try get overlapped result\r\n") ); + + if (get_send_ovl_result(descP->sock, ovl, &written)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_completed -> overlapped result: " + "\r\n written: %d" + "\r\n buffer size: %d" + "\r\n", written, toWrite) ); + + if (written == toWrite) { + + /* Sent it all => done */ + + completionStatus = esaio_completion_send_done(env, + descP, sockRef, + written); + + } else { + + /* Only send part of the data => + * needs splitting and (maybe) retry (its up to the caller)! + */ + + completionStatus = esaio_completion_send_partial(env, + descP, + sockRef, + written); + } + + } else { + + int save_errno = sock_errno(); + + /* Now what? + * We know we wrote "something" but we cannot figure out + * how much... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_completed -> " + "overlapped result failure: %d\r\n", save_errno) ); + + completionStatus = + esaio_completion_get_ovl_result_fail(env, descP, save_errno); + } + + completionInfo = MKT2(env, CP_TERM(env, sendRef), completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_completed -> " + "send completion message to %T with" + "\r\n CompletionInfo: %T" + "\r\n", MKPID(env, sender), completionInfo) ); + + /* Send a 'send' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + sender, // Msg destination + opEnv, // Msg env + sockRef, // Dest socket + completionInfo); // Info + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_send_completed -> done\r\n") ); +} + + + +/* *** esaio_completion_send_done *** + * + * A complete write (the entire buffer was sent). + * + */ +static +ERL_NIF_TERM esaio_completion_send_done(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + DWORD written) +{ + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_pkg, &descP->writePkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_byte, &descP->writeByteCnt, written); + + if (written > descP->writePkgMax) + descP->writePkgMax = written; + + return esock_atom_ok; +} + + + +/* *** esaio_completion_send_partial *** + * + * A partial send, that is only part of the buffer was used. + * + */ +static +ERL_NIF_TERM esaio_completion_send_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + DWORD written) +{ + if (written > 0) { + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_pkg, &descP->writePkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_byte, &descP->writeByteCnt, written); + + if (written > descP->writePkgMax) + descP->writePkgMax = written; + + } + + return esock_make_ok2(env, MKI64(env, written)); + +} + + + +/* *** esaio_completion_send_not_active *** + * A send request has completed but the request is no longer valid. + */ +static +void esaio_completion_send_not_active(ESockDescriptor* descP) +{ + /* This send request is *not* "active"! + * The send (send, sendto, sendmsg) operation + * has been (most likely) cancelled => cleanup. + * If the op failed, its safe to assume that the error is + * the result of the cancellation, and we do not actually + * need to do anything here. + * If however, the send succeeded, we need to do "some + * cleanup". + * But what can we do here? + * Send an abort message to the sender or/and owner? + * Increment a counter (unexpected acceptssends)? + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_not_active(%d) -> " + "success for not active send request\r\n", + descP->sock) ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unexpectedWrites, 1); + + MUNLOCK(ctrl.cntMtx); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_send_not_active(%d) -> done\r\n", + descP->sock) ); + +} + + + +/* *** esaio_completion_send_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_send_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "send", error, inform); +} + + + +/* *** esaio_completion_sendto *** + * + * Handle a completed 'sendto' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:sendto(Socket, ..., nowait), the send is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'send completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + * + * We need to use 'WSAGetOverlappedResult' to actually figure out the + * "transfer result" (how much was sent). + */ +static +BOOLEAN_T esaio_completion_sendto(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendto(%d) -> entry" + "\r\n error: %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendto(%d) -> no error" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_sendto_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_sendto_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto(%d) -> operation unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_sendto_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->writeMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto(%d) -> cleanup\r\n", + descP->sock) ); + + FREE( opDataP->wbuf.buf ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_sendto - op cleanup", opEnv); + esock_free_env("esaio_completion_sendto - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendto(%d) -> done\r\n", + descP->sock) ); + + return FALSE; +} + + + +/* *** esaio_completion_sendto_suuccess *** */ +static +void esaio_completion_sendto_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP) +{ + ESockRequestor req; + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + if (IS_OPEN(descP->writeState)) { + esaio_completion_send_completed(env, descP, ovl, opEnv, + opCaller, + opDataP->sockRef, + opDataP->sendRef, + opDataP->wbuf.len, + &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_send_not_active(descP); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_success(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + + +/* *** esaio_completion_sendto_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_sendto_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (write) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->writeState)))) ); + + if (! IS_OPEN(descP->writeState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->writersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->readersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_aborted(%d) -> " + "maybe (%s) update (write) state (0x%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } +} + + +/* *** esaio_completion_sendto_failure * + * A "general" failure happened while performing the 'sendto' operation. + */ +static +void esaio_completion_sendto_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendTo* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_sendto_fail(env, descP, error, FALSE); + + } else { + esaio_completion_sendto_fail(env, descP, error, TRUE); + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendto_failure(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + + +/* *** esaio_completion_sendto_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_sendto_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "sendto", error, inform); +} + + + +/* *** esaio_completion_sendmsg *** + * + * Handle a completed 'sendmsg' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:sendto(Socket, ..., nowait), the send is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'send completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + * + * We need to use 'WSAGetOverlappedResult' to actually figure out the + * "transfer result" (how much was sent). + */ +static +BOOLEAN_T esaio_completion_sendmsg(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendmsg(%d) -> entry with" + "\r\n error: %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendmsg(%d) -> no error" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_sendmsg_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_sendmsg_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg(%d) -> operation unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->writeMtx); + + esaio_completion_sendmsg_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->writeMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg(%d) -> cleanup\r\n", descP->sock) ); + + /* "Manually" allocated buffers */ + FREE( opDataP->msg.lpBuffers ); + if (opDataP->ctrlBuf != NULL) + FREE( opDataP->ctrlBuf ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_sendmsg - op cleanup", opEnv); + esock_free_env("esaio_completion_sendmsg - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_sendmsg(%d) -> done\r\n", + descP->sock) ); + + return FALSE; + +} + + +/* *** esaio_completion_sendmsg_suuccess *** */ +static +void esaio_completion_sendmsg_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP) +{ + ESockRequestor req; + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + if (IS_OPEN(descP->writeState)) { + + DWORD toWrite = 0; + + /* Calculate how much data *in total* + * we was supposed to write */ + for (int i = 0; i < opDataP->iovec->iovcnt; i++) { + toWrite += opDataP->iovec->iov[i].iov_len; + } + + esaio_completion_send_completed(env, descP, ovl, opEnv, + opCaller, + opDataP->sockRef, + opDataP->sendRef, + toWrite, + &req); + + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_send_not_active(descP); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_success(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_sendmsg_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_sendmsg_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (write) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->writeState)))) ); + + if (! IS_OPEN(descP->writeState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->writersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->readersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_aborted(%d) -> " + "maybe (%s) update (write) state (0x%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_sendmsg_failure * + * A "general" failure happened while performing the 'sendmsg' operation. + */ +static +void esaio_completion_sendmsg_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataSendMsg* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_writer_get(env, descP, + &opDataP->sendRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_sendmsg_fail(env, descP, error, FALSE); + + } else { + esaio_completion_sendmsg_fail(env, descP, error, TRUE); + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_sendmsg_success(%d) -> " + "maybe (%s) update (write) state (ox%X)\r\n", + descP->sock, + B2S((descP->writersQ.first == NULL)), descP->writeState) ); + if (descP->writersQ.first == NULL) { + descP->writeState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_sendmsg_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_sendmsg_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "sendmsg", error, inform); +} + + + +/* === receive 'stuff' === */ + +/* *** esaio_completion_recv *** + * + * Handle a completed 'recv' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:recv(Socket, ..., nowait), the recv is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'recv completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + */ +static +BOOLEAN_T esaio_completion_recv(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recv(%d) -> entry with" + "\r\n error: %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recv(%d) -> no error" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recv_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->readMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_recv_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv(%d) -> operation unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recv_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->readMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv {%d} -> clear and delete op env\r\n", + descP->sock) ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_recv - op cleanup", opEnv); + esock_free_env("esaio_completion_recv - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recv(%d) -> done\r\n", + descP->sock) ); + + return FALSE; +} + + +static +void esaio_completion_recv_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP) +{ + ESockRequestor req; + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + if (IS_OPEN(descP->readState)) { + esaio_completion_recv_completed(env, descP, ovl, opEnv, + opCaller, opDataP, + &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_recv_not_active(descP); + FREE_BIN( &opDataP->buf ); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + * => But we do not free the "buffer" since it was "used up" + * when we (as assumed) got the result (directly)... + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_success(%d) -> " + "maybe (%s) update (read) state (0x%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recv_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_recv_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (read) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->readState)))) ); + + if (! IS_OPEN(descP->readState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->readersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->writersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + FREE_BIN( &opDataP->buf ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_aborted(%d) -> " + "maybe (%s) update (read) state (0x%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recv_failure * + * A "general" failure happened while performing the 'recv' operation. + */ +static +void esaio_completion_recv_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + /* Figure out the reason */ + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_recv_fail(env, descP, error, FALSE); + + } else { + esaio_completion_recv_fail(env, descP, error, TRUE); + } + + FREE_BIN( &opDataP->buf ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_failure(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recv_completed *** + * The recv request has completed. + */ +static +void esaio_completion_recv_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecv* opDataP, + ESockRequestor* reqP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + DWORD read, flags; + + ESOCK_ASSERT( DEMONP("esaio_completion_recv_completed - sender", + env, descP, &reqP->mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_completed ->" + "success - try get overlapped result\r\n") ); + + if (get_recv_ovl_result(descP->sock, ovl, &read, &flags)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_completed -> overlapped result: " + "\r\n read: %d" + "\r\n buffer size: %d" + "\r\n flags: %d" + "\r\n", read, opDataP->buf.size, flags) ); + + /* *** Success! *** + * CompletionStatus = {ok, {Flags, Bin}} (should be) + * CompletionInfo = {ConnRef, CompletionStatus} + */ + + if ((read == 0) && (descP->type == SOCK_STREAM)) { + + /* + * When a stream socket peer has performed an orderly + * shutdown, the return value will be 0 (the traditional + * "end-of-file" return). + * + * *We* do never actually try to read 0 bytes! + */ + + ESOCK_CNT_INC(env, descP, opDataP->sockRef, + esock_atom_read_fails, &descP->readFails, 1); + + completionStatus = esock_make_error(opEnv, esock_atom_closed); + + } else { + + if (read == opDataP->buf.size) { + /* We filled the buffer => done */ + + completionStatus = + esaio_completion_recv_done(env, descP, + opEnv, opDataP, + flags); + + } else { + + /* Only used a part of the buffer => + * needs splitting and (maybe) retry (its up to the caller)! + */ + + completionStatus = + esaio_completion_recv_partial(env, descP, + opEnv, opDataP, + reqP, read, flags); + } + + } + + } else { + + int save_errno = sock_errno(); + + /* Now what? + * We know we read "something" but we cannot figure out + * how much... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_completed -> " + "overlapped result failure: %d\r\n", save_errno) ); + + completionStatus = + esaio_completion_get_ovl_result_fail(opEnv, descP, save_errno); + } + + completionInfo = MKT2(opEnv, opDataP->recvRef, completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_completed -> " + "send completion message to %T with" + "\r\n CompletionInfo: %T" + "\r\n", MKPID(env, opCaller), completionInfo) ); + + /* Send a 'send' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + opCaller, // Msg destination + opEnv, // Msg env + opDataP->sockRef, // Socket + completionInfo); // Info + + /* *** Finalize *** */ + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recv_completed -> finalize\r\n") ); + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_completion_recv_completed -> req cleanup", + reqP->env); + esock_free_env("esaio_completion_recv_completed -> req cleanup", + reqP->env); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recv_completed -> done\r\n") ); +} + + + +/* *** esaio_completion_recv_done *** + * + * A complete read (filled the provided buffer). + * + */ +static +ERL_NIF_TERM esaio_completion_recv_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + DWORD flags) +{ + ERL_NIF_TERM data; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + DWORD read = opDataP->buf.size; + + (void) flags; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_done(%T) {%d} -> entry with" + "\r\n recvRef: %T" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, recvRef, flags) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(opEnv, &opDataP->buf); + + /* We ignore the flags *for now*. + * Needs to be passed up eventually! + * + * This should eventually be something like: + * + * {ok, {Flags, Bin}} + * + * But for now we skip the 'flags' part: + * + * {ok, Bin} + */ + return esock_make_ok2(opEnv, data); +} + + +/* *** esaio_completion_recv_partial *** + * + * A partial read, that is only part of the buffer was used. + * + */ +static +ERL_NIF_TERM esaio_completion_recv_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags) +{ + ERL_NIF_TERM res; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + DWORD toRead = opDataP->toRead; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_partial(%T) {%d} -> entry with" + "\r\n toRead: %ld" + "\r\n recvRef: %T" + "\r\n read: %ld" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, + (long) toRead, recvRef, (long) read, flags) ); + + /* We only got part of what we wanted, but since we let the user + * (or possibly the read loop in socket) decide what to do, + * do we actually need this check? Why not just call a + * 'esaio_completion_recv_partial' function (that splits the + * binary and deliver what we got) and let the user sort it out? + */ + + if ((toRead == 0) || + (descP->type != SOCK_STREAM)) { + + /* +++ We only got a partial, *** + * *** but we should not wait for more. +++ + * +++ Must split it into a sub-binary. +++ + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_partial(%T) {%d} -> done reading\r\n", + sockRef, descP->sock) ); + + res = esaio_completion_recv_partial_done(env, descP, + opEnv, opDataP, + read, flags); + + } else { + + /* A stream socket with specified read size + * and not a polling read, we got a partial read + * - return a result to initiate a retry + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_partial(%T) {%d} ->" + " only part of data - expected more" + "\r\n", sockRef, descP->sock) ); + + res = esaio_completion_recv_partial_part(env, descP, + opEnv, opDataP, + read, flags); + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_partial(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return res; +} + + + +/* *** esaio_completion_recv_partial_done *** + * + * A successful but only partial recv, which fulfilled the required read. + */ + +static +ERL_NIF_TERM esaio_completion_recv_partial_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ssize_t read, + DWORD flags) +{ + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM data; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(opEnv, &opDataP->buf); + data = MKSBIN(opEnv, data, 0, read); + + (void) flags; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_partial_done(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return esock_make_ok2(opEnv, data); +} + + + +/* *** esaio_completion_recv_partial_part *** + * + * A successful but only partial recv, which only partly fulfilled + * the required read. + * We do *not* want to risk ending up in a "never ending" read loop + * here (by trying to read more data (and yet again getting partial)). + * [worst case, we could up with all our worker threads busy trying + * to read more data, and no one ready to respond to new requests]. + * So we simply return what we got to the user and let the user + * decide what to do. + * + * What shall we send? {ok, Bin} | {more, Bin} + * Presumably the user knows how much to expect, so is therefor + * able to check: + * + * "Expected > byte_size(Bin)" -> read again + * "Expected =:= byte_size(Bin)" -> done + */ + +static +ERL_NIF_TERM esaio_completion_recv_partial_part(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecv* opDataP, + ssize_t read, + DWORD flags) +{ + /* This is just a "placeholder". Is this really all we need to do? */ + return esaio_completion_recv_partial_done(env, descP, + opEnv, opDataP, + read, flags); +} + + + +/* *** esaio_completion_recv_not_active *** + * A recv request has completed but the request is no longer valid. + */ +static +void esaio_completion_recv_not_active(ESockDescriptor* descP) +{ + /* This receive request is *not* "active"! + * The receive (recv,recvfrom,recvmsg) operation + * has been (most likely) cancelled => cleanup. + * If the op failed, its safe to assume that the error is + * the result of the cancellation, and we do not actually + * need to do anything here. + * If however, the recv succeeded, we need to do "some + * cleanup". + * But what can we do here? + * Send an abort message to the reader or/and owner? + * Increment a counter (unexpected readsa)? + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_not_active {%d} -> " + "success for not active read request\r\n", descP->sock) ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unexpectedReads, 1); + + MUNLOCK(ctrl.cntMtx); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_not_active {%d} -> done\r\n", + descP->sock) ); + +} + + + +/* *** esaio_completion_recv_closed *** + * A recv request has completed but the socket is closed. + * When the socket is closed, all outstanding requests + * are "flushed", so we do not actually need to "do" anything + * here (other then maybe count unexpected writes), maybe read bytes?. + */ +static +void esaio_completion_recv_closed(ESockDescriptor* descP, + int error) +{ + if (error == NO_ERROR) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recv_closed -> " + "success for closed socket (%d)\r\n", + descP->sock) ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unexpectedReads, 1); + + MUNLOCK(ctrl.cntMtx); + + } +} + + + +/* *** esaio_completion_recv_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_recv_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "recv", error, inform); +} + + + +/* *** esaio_completion_recvfrom *** + * + * Handle a completed 'recvfrom' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:recvfrom(Socket, ..., nowait), the receive is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'recv completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + */ +static +BOOLEAN_T esaio_completion_recvfrom(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvfrom(%d) -> entry with" + "\r\n error: %T, %s (%d)" + "\r\n", + descP->sock, ENO2T(env, error), + erl_errno_id(error), error) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvfrom(%d) -> no error" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recvfrom_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->readMtx); + break; + + case ERROR_MORE_DATA: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom(%d) -> more data" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recvfrom_more_data(env, descP, + opEnv, opCaller, opDataP, + error); + + MUNLOCK(descP->readMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_recvfrom_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom(%d) -> operation unknown failure" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recvfrom_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->readMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom {%d} -> clear and delete op env\r\n") ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_recvfrom - op cleanup", opEnv); + esock_free_env("esaio_completion_recvfrom - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvfrom {%d} -> done\r\n") ); + + return FALSE; +} + + +static +void esaio_completion_recvfrom_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP) +{ + ESockRequestor req; + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + if (IS_OPEN(descP->readState)) { + esaio_completion_recvfrom_completed(env, descP, + ovl, opEnv, opCaller, + opDataP, &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_recv_not_active(descP); + FREE_BIN( &opDataP->buf ); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + * => But we do not free the "buffer" since it was "used up" + * when we (as assumed) got the result (directly)... + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_success(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +static +void esaio_completion_recvfrom_more_data(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error) +{ + ESockRequestor req; + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + if (IS_OPEN(descP->readState)) { + /* We do not actually need to call this function + * since we already know its 'more_data', but just + * to get the same format... + */ + ERL_NIF_TERM reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + ERL_NIF_TERM completionStatus = esock_make_error(env, reason); + ERL_NIF_TERM completionInfo = MKT2(opEnv, + opDataP->recvRef, + completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_more_data(%d) -> " + "send completion message: " + "\r\n Completion Status: %T" + "\r\n", descP->sock, completionStatus) ); + + /* Send a 'recvfrom' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + opCaller, // Msg destination + opEnv, // Msg env + opDataP->sockRef, // Dest socket + completionInfo); // Info + + } + + FREE_BIN( &opDataP->buf ); + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + * => But we do not free the "buffer" since it was "used up" + * when we (as assumed) got the result (directly)... + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_more_data(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvfrom_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ +static +void esaio_completion_recvfrom_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (read) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->readState)))) ); + + if (! IS_OPEN(descP->readState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->readersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->writersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + FREE_BIN( &opDataP->buf ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_aborted(%d) -> " + "maybe (%s) update (read) state (0x%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvfrom_failure * + * A "general" failure happened while performing the 'recvfrom' operation. + */ +static +void esaio_completion_recvfrom_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_recvfrom_fail(env, descP, error, FALSE); + + } else { + esaio_completion_recvfrom_fail(env, descP, error, TRUE); + } + + FREE_BIN( &opDataP->buf ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_failure(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvfrom_completed *** + * The recvfrom request has completed. + */ +static +void esaio_completion_recvfrom_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvFrom* opDataP, + ESockRequestor* reqP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + DWORD read, flags; + + ESOCK_ASSERT( DEMONP("esaio_completion_recvfrom_completed - sender", + env, descP, &reqP->mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_completed ->" + "success - try get overlapped result\r\n") ); + + if (get_recv_ovl_result(descP->sock, ovl, &read, &flags)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_completed -> overlapped result: " + "\r\n read: %d" + "\r\n buffer size: %d" + "\r\n flags: %d" + "\r\n", read, opDataP->buf.size, flags) ); + + /* *** Success! *** + * CompletionStatus = {ok, {Flags, Bin}} (should be) + * CompletionInfo = {ConnRef, CompletionStatus} + */ + + if (read == opDataP->buf.size) { + /* We filled the buffer => done */ + + completionStatus = + esaio_completion_recvfrom_done(env, descP, + opEnv, opDataP, + flags); + + } else { + + /* Only used a part of the buffer => + * needs splitting and (maybe) retry (its up to the caller)! + */ + + completionStatus = + esaio_completion_recvfrom_partial(env, descP, + opEnv, opDataP, + reqP, read, flags); + } + + } else { + + int save_errno = sock_errno(); + + /* Now what? + * We know we read "something" but we cannot figure out + * how much... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_completed -> " + "overlapped result failure: %d\r\n", save_errno) ); + + completionStatus = + esaio_completion_get_ovl_result_fail(opEnv, descP, save_errno); + + FREE_BIN( &opDataP->buf ); + } + + completionInfo = MKT2(opEnv, opDataP->recvRef, completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_completed -> " + "send completion message to %T with" + "\r\n CompletionInfo: %T" + "\r\n", MKPID(env, opCaller), completionInfo) ); + + /* Send a 'recvfrom' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + opCaller, // Msg destination + opEnv, // Msg env + opDataP->sockRef, // Dest socket + completionInfo); // Info + + /* *** Finalize *** */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_completed -> finalize\r\n") ); + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_completion_recvfrom_completed -> req cleanup", + reqP->env); + esock_free_env("esaio_completion_recvfrom_completed -> req cleanup", + reqP->env); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvfrom_completed -> done\r\n") ); +} + + + +/* *** esaio_completion_recvfrom_done *** + * + * A complete read (filled the provided buffer). + * + */ +static +ERL_NIF_TERM esaio_completion_recvfrom_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvFrom* opDataP, + DWORD flags) +{ + ERL_NIF_TERM res, data, eSockAddr; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + DWORD read = opDataP->buf.size; + + (void) flags; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_done(%T) {%d} -> entry with" + "\r\n recvRef: %T" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, recvRef, flags) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + esock_encode_sockaddr(opEnv, + &opDataP->fromAddr, + opDataP->addrLen, + &eSockAddr); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(opEnv, &opDataP->buf); + + /* We ignore the flags *for now*. + * Needs to be passed up eventually! + * + * This should eventually be something like: + * + * {ok, {Source, Flags, Data}} + * + * But for now we skip the 'flags' part: + * + * {ok, {Source, Data}} + */ + res = esock_make_ok2(opEnv, MKT2(opEnv, eSockAddr, data)); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_done(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return res; +} + + + +/* *** esaio_completion_recvfrom_partial *** + * + * A partial read, that is only part of the buffer was used. + * + */ +static +ERL_NIF_TERM esaio_completion_recvfrom_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvFrom* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags) +{ + ERL_NIF_TERM res, data, eSockAddr; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + + (void) flags; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_partial(%T) {%d} -> entry with" + "\r\n recvRef: %T" + "\r\n read: %ld" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, recvRef, (long) read, flags) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + esock_encode_sockaddr(opEnv, + &opDataP->fromAddr, + opDataP->addrLen, + &eSockAddr); + + /* This transfers "ownership" of the *allocated* binary to an + * erlang term (no need for an explicit free). + */ + data = MKBIN(opEnv, &opDataP->buf); + data = MKSBIN(opEnv, data, 0, read); + + /* We ignore the flags *for now*. + * Needs to be passed up eventually! + * + * This should eventually be something like: + * + * {ok, {Source, Flags, Data}} + * + * But for now we skip the 'flags' part: + * + * {ok, {Source, Data}} + */ + + res = esock_make_ok2(opEnv, MKT2(opEnv, eSockAddr, data)); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvfrom_partial(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return res; +} + + + +/* *** esaio_completion_recvfrom_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_recvfrom_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "recvfrom", error, inform); +} + + + +/* *** esaio_completion_recvmsg *** + * + * Handle a completed 'recvmsg' (completion) request. + * Send a 'completion' message (to requestor) with the request status. + * + * Completion message: + * {'socket tag', socket(), completion, CompletionInfo} + * + * CompletionInfo: {CompletionHandle, CompletionStatus} + * CompletionHandle: reference() + * Result: ok | {error, Reason} + * + * + * There is a possibillity of a race here. That is, if the user + * calls socket:recvmsg(Socket, ..., nowait), the receive is scheduled, + * and then just as it has completed, but before this + * thread has been activated to handle the 'recv completed' + * the user calls socket:close(Socket) (or exits). + * Then when this function is called, the socket is closed. + * What to do? + */ +static +BOOLEAN_T esaio_completion_recvmsg(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + int error) +{ + ErlNifEnv* env = dataP->env; + ESockRequestor req; + ERL_NIF_TERM reason; + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvmsg(%d) -> entry with" + "\r\n error: %T" + "\r\n", descP->sock, ENO2T(env, error)) ); + + switch (error) { + case NO_ERROR: + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvmsg(%d) -> no error:" + "\r\n try get request %T from %T" + "\r\n", + descP->sock, + opDataP->recvRef, MKPID(env, opCaller)) ); + MLOCK(descP->readMtx); + + esaio_completion_recvmsg_success(env, descP, ovl, opEnv, + opCaller, opDataP); + + MUNLOCK(descP->readMtx); + break; + + case WSA_OPERATION_ABORTED: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg(%d) -> operation aborted" + "\r\n", descP->sock) ); + /* *** SAME MTX LOCK ORDER FOR ALL OPs *** */ + MLOCK(descP->readMtx); + MLOCK(descP->writeMtx); + + esaio_completion_recvmsg_aborted(env, descP, opCaller, opDataP); + + MUNLOCK(descP->writeMtx); + MUNLOCK(descP->readMtx); + break; + + default: + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg(%d) -> unknown operation failure" + "\r\n", descP->sock) ); + MLOCK(descP->readMtx); + + esaio_completion_recvmsg_failure(env, descP, opCaller, opDataP, error); + + MUNLOCK(descP->readMtx); + break; + } + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg {%d} -> clear and delete op env\r\n", + descP->sock) ); + + /* No need for this "stuff" anymore */ + esock_clear_env("esaio_completion_recvmsg - op cleanup", opEnv); + esock_free_env("esaio_completion_recvmsg - op cleanup", opEnv); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvmsg {%d} -> done\r\n", + descP->sock) ); + + return FALSE; +} + + +static +void esaio_completion_recvmsg_success(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP) +{ + ESockRequestor req; + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + if (IS_OPEN(descP->readState)) { + esaio_completion_recvmsg_completed(env, descP, ovl, opEnv, + opCaller, opDataP, + &req); + } else { + /* A completed (active) request for a socket that is not open. + * Is this even possible? + * A race (completed just as the socket was closed). + */ + esaio_completion_recv_not_active(descP); + FREE_BIN( &opDataP->data[0] ); + FREE_BIN( &opDataP->ctrl ); + } + + } else { + /* Request was actually completed directly + * (and was therefor not put into the "queue") + * => Nothing to do here, other than cleanup (see below). + * => But we do not free the "buffer" since it was "used up" + * when we (as assumed) got the result (directly)... + */ + } + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_success(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvmsg_aborted *** + * The only thing *we* do that could cause an abort is the + * 'CancelIoEx' call, which we do when closing the socket + * (or cancel a request). + * But if we have done that; + * - Socket state will not be 'open' and + * - we have also set closer (pid and ref). + */ + +static +void esaio_completion_recvmsg_aborted(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP) +{ + ESockRequestor req; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_aborted(%d) -> " + "try get request" + "\r\n", descP->sock) ); + + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + + ERL_NIF_TERM reason = esock_atom_closed; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_aborted(%d) -> " + "send abort message to %T" + "\r\n", descP->sock, req.pid) ); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + + } + + /* The socket not being open (assumed closing), + * means we are in the closing phase... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_aborted(%d) -> " + "maybe send close message => " + "\r\n is socket (read) open: %s" + "\r\n", + descP->sock, B2S((IS_OPEN(descP->readState)))) ); + + if (! IS_OPEN(descP->readState)) { + + /* We can only send the 'close' message to the closer + * when all requests has been processed! + */ + + /* Check "our" queue */ + if (descP->readersQ.first == NULL) { + + /* Check "other" queue(s) and if there is a closer pid */ + if ((descP->writersQ.first == NULL) && + (descP->acceptorsQ.first == NULL)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_aborted(%d) -> " + "all queues are empty => " + "\r\n send close message" + "\r\n", + descP->sock) ); + + esaio_stop(env, descP); + + } + } + } + + FREE_BIN( &opDataP->data[0] ); + FREE_BIN( &opDataP->ctrl ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_aborted(%d) -> " + "maybe (%s) update (read) state (0x%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvmsg_failure * + * A "general" failure happened while performing the 'recvmsg' operation. + */ +static +void esaio_completion_recvmsg_failure(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + int error) +{ + ESockRequestor req; + ERL_NIF_TERM reason; + + /* We do not know what this is + * but we can "assume" that the request failed so we need to + * remove it from the "queue" if its still there... + * And cleanup... + */ + if (esock_reader_get(env, descP, + &opDataP->recvRef, + opCaller, + &req)) { + + reason = MKT2(env, + esock_atom_completion_status, + ENO2T(env, error)); + + /* Inform the user waiting for a reply */ + esock_send_abort_msg(env, descP, opDataP->sockRef, + &req, reason); + esaio_completion_recvmsg_fail(env, descP, error, FALSE); + + } else { + esaio_completion_recvmsg_fail(env, descP, error, TRUE); + } + + FREE_BIN( &opDataP->data[0] ); + FREE_BIN( &opDataP->ctrl ); + + /* *Maybe* update socket (write) state + * (depends on if the queue is now empty) + */ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_failure(%d) -> " + "maybe (%s) update (read) state (ox%X)\r\n", + descP->sock, + B2S((descP->readersQ.first == NULL)), descP->readState) ); + if (descP->readersQ.first == NULL) { + descP->readState &= ~ESOCK_STATE_SELECTED; + } + +} + + +/* *** esaio_completion_recvmsg_completed *** + * The recvmsg request has completed. + */ +static +void esaio_completion_recvmsg_completed(ErlNifEnv* env, + ESockDescriptor* descP, + OVERLAPPED* ovl, + ErlNifEnv* opEnv, + ErlNifPid* opCaller, + ESAIOOpDataRecvMsg* opDataP, + ESockRequestor* reqP) +{ + ERL_NIF_TERM completionStatus, completionInfo; + DWORD read, flags; + + ESOCK_ASSERT( DEMONP("esaio_completion_recvmsg_completed - sender", + env, descP, &reqP->mon) == 0); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_completed ->" + "success - try get overlapped result\r\n") ); + + if (get_recv_ovl_result(descP->sock, ovl, &read, &flags)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_completed -> overlapped result: " + "\r\n read: %d" + "\r\n buffer size: %d" + "\r\n flags: %d" + "\r\n", read, opDataP->data[0].size, flags) ); + + /* *** Success! *** + * CompletionStatus = {ok, Msg} (should be) + * CompletionInfo = {ConnRef, CompletionStatus} + */ + + /* We should have "calculated" the entire size before, + * but since we have a vector of size one... + */ + if (read == opDataP->data[0].size) { + /* We filled the buffer => done */ + + completionStatus = + esaio_completion_recvmsg_done(env, descP, + opEnv, opDataP, + flags); + + } else { + + /* Only used a part of the buffer => + * needs splitting and (maybe) retry (its up to the caller)! + */ + + completionStatus = + esaio_completion_recvmsg_partial(env, descP, + opEnv, opDataP, + reqP, read, flags); + } + + } else { + + int save_errno = sock_errno(); + + /* Now what? + * We know we read "something" but we cannot figure out + * how much... + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_completed -> " + "overlapped result failure: %d\r\n", save_errno) ); + + completionStatus = + esaio_completion_get_ovl_result_fail(opEnv, descP, save_errno); + + } + + completionInfo = MKT2(opEnv, opDataP->recvRef, completionStatus); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_completed -> " + "send completion message to %T with" + "\r\n CompletionInfo: %T" + "\r\n", MKPID(env, opCaller), completionInfo) ); + + /* Send a 'send' completion message */ + esaio_send_completion_msg(env, // Send env + descP, // Descriptor + opCaller, // Msg destination + opEnv, // Msg env + opDataP->sockRef, // Dest socket + completionInfo); // Info + + /* *** Finalize *** */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_completed -> finalize\r\n") ); + + /* Request cleanup (demonitor already done above) */ + esock_clear_env("esaio_completion_recvmsg_completed -> req cleanup", + reqP->env); + esock_free_env("esaio_completion_recvmsg_completed -> req cleanup", + reqP->env); + + SSDBG( descP, + ("WIN-ESAIO", "esaio_completion_recvmsg_completed -> done\r\n") ); +} + + + +/* *** esaio_completion_recvmsg_done *** + * + * A complete read (filled the provided buffer). + * + */ +static +ERL_NIF_TERM esaio_completion_recvmsg_done(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvMsg* opDataP, + DWORD flags) +{ + ERL_NIF_TERM res, eMsg; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + DWORD read = opDataP->data[0].size; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_done(%T) {%d} -> entry with" + "\r\n recvRef: %T" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, recvRef, flags) ); + + (void) flags; + + encode_msg(opEnv, descP, read, + &opDataP->msg, + opDataP->data, + &opDataP->ctrl, + &eMsg); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + res = esock_make_ok2(opEnv, eMsg); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_done(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return res; +} + + + +/* *** esaio_completion_recvmsg_partial *** + * + * A partial read, that is only part of the buffer was used. + * + */ +static +ERL_NIF_TERM esaio_completion_recvmsg_partial(ErlNifEnv* env, + ESockDescriptor* descP, + ErlNifEnv* opEnv, + ESAIOOpDataRecvMsg* opDataP, + ESockRequestor* reqP, + DWORD read, + DWORD flags) +{ + ERL_NIF_TERM res, eMsg; + ERL_NIF_TERM sockRef = opDataP->sockRef; + ERL_NIF_TERM recvRef = opDataP->recvRef; + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_partial(%T) {%d} -> entry with" + "\r\n recvRef: %T" + "\r\n read: %ld" + "\r\n flags: 0x%X" + "\r\n", sockRef, descP->sock, recvRef, (long) read, flags) ); + + (void) flags; + + /* This function hansles splitting the binaries */ + encode_msg(opEnv, descP, read, + &opDataP->msg, + opDataP->data, + &opDataP->ctrl, + &eMsg); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_pkg, &descP->readPkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_read_byte, &descP->readByteCnt, read); + + if (read > descP->readPkgMax) + descP->readPkgMax = read; + + res = esock_make_ok2(opEnv, eMsg); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_recvmsg_partial(%T) {%d} -> done\r\n", + sockRef, descP->sock) ); + + return res; +} + + + +/* *** esaio_completion_recvmsg_fail *** + * Unknown operation failure. + */ +static +void esaio_completion_recvmsg_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error, + BOOLEAN_T inform) +{ + esaio_completion_fail(env, descP, "recvmsg", error, inform); +} + + + +/* *** esaio_completion_get_ovl_result_fail *** + * This function is called when the function 'WSAGetOverlappedResult' fails. + * It generates a result (returns) in the form of: + * + * {error, {get_overlapped_result, atom()}} + */ +static +ERL_NIF_TERM esaio_completion_get_ovl_result_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int error) +{ + ERL_NIF_TERM eerrno = ENO2T(env, error); + ERL_NIF_TERM reason = MKT2(env, esock_atom_get_overlapped_result, eerrno); + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_completion_get_ovl_result_fail{%d} -> entry with" + "\r\n Errno: %d (%T)" + "\r\n", descP->sock, error, eerrno) ); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.genErrs, 1); + + MUNLOCK(ctrl.cntMtx); + + return esock_make_error(env, reason); +} + + + + +/* === Unknown command 'stuff' === */ + +/* *** esaio_completion_unknown *** + * What shall we actually do here? + * Increment counters (bytes, number of unknown packages)? + * Send a messge with this info to "someone"? + * Write a (error) message to stdout/stderr? + */ +static +BOOLEAN_T esaio_completion_unknown(ESAIOThreadData* dataP, + ESockDescriptor* descP, + OVERLAPPED* ovl, + DWORD numBytes, + int error) +{ + (void) dataP; + (void) descP; + (void) ovl; + (void) numBytes; + (void) error; + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.unknownCmds, 1); + + MUNLOCK(ctrl.cntMtx); + + return FALSE; +} + + + +/* *** esaio_completion_fail *** + * Unknown operation failure (not 'unknown operation' failure, + * but an unknown 'operation failure'). + */ +static +void esaio_completion_fail(ErlNifEnv* env, + ESockDescriptor* descP, + const char* opStr, + int error, + BOOLEAN_T inform) +{ + if (inform) + esock_warning_msg("[WIN-ESAIO] Unknown (%s) operation failure: " + "\r\n Descriptor: %d" + "\r\n Error: %T" + "\r\n", + opStr, descP->sock, ENO2T(env, error)); + + MLOCK(ctrl.cntMtx); + + esock_cnt_inc(&ctrl.genErrs, 1); + + MUNLOCK(ctrl.cntMtx); + +} + + + +static +void esaio_completion_inc(ESAIOThreadData* dataP) +{ + if (dataP->cnt == ESAIO_THREAD_CNT_MAX) { + dataP->cnt = 0; + } else { + dataP->cnt++; + } +} + + + +/* ==================================================================== + * + * NIF (I/O backend) Resource callback functions: dtor, stop and down + * + * ==================================================================== + */ + +extern +void esaio_dtor(ErlNifEnv* env, + ESockDescriptor* descP) +{ + ERL_NIF_TERM sockRef; + + SGDBG( ("WIN-ESAIO", "esaio_dtor -> entry\r\n") ); + + /* + ESOCK_PRINTF("esaio_dtor -> entry when" + "\r\n is selected: %s" + "\r\n read state: 0x%X" + "\r\n is read-closed: %s" + "\r\n write state: 0x%X" + "\r\n is write-closed: %s" + "\r\n sock: %d" + "\r\n", + B2S(IS_SELECTED(descP)), + descP->readState, + B2S(IS_CLOSED(descP->readState)), + descP->writeState, + B2S(IS_CLOSED(descP->writeState)), + descP->sock); + */ + + if (IS_SELECTED(descP)) { + /* We have used the socket in the "I/O Completion Port" machinery, + * so we must have closed it properly to get here + */ + if (! IS_CLOSED(descP->readState) ) + esock_warning_msg("Socket Read State not CLOSED (0x%X) " + "at dtor\r\n", descP->readState); + + if (! IS_CLOSED(descP->writeState) ) + esock_warning_msg("Socket Write State not CLOSED (0x%X) " + "at dtor\r\n", descP->writeState); + + if ( descP->sock != INVALID_SOCKET ) + esock_warning_msg("Socket %d still valid\r\n", descP->sock); + + ESOCK_ASSERT( IS_CLOSED(descP->readState) ); + ESOCK_ASSERT( IS_CLOSED(descP->writeState) ); + ESOCK_ASSERT( descP->sock == INVALID_SOCKET ); + + } else { + /* The socket is only opened, should be safe to close nonblocking */ + (void) sock_close(descP->sock); + descP->sock = INVALID_SOCKET; + } + + SGDBG( ("WIN-ESAIO", "esaio_dtor -> set state and pattern\r\n") ); + descP->readState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); + descP->writeState |= (ESOCK_STATE_DTOR | ESOCK_STATE_CLOSED); + descP->pattern = (ESOCK_DESC_PATTERN_DTOR | ESOCK_STATE_CLOSED); + + SGDBG( ("WIN-ESAIO", + "esaio_dtor -> try free readers request queue\r\n") ); + esock_free_request_queue(&descP->readersQ); + + SGDBG( ("WIN-ESAIO", + "esaio_dtor -> try free writers request queue\r\n") ); + esock_free_request_queue(&descP->writersQ); + + SGDBG( ("WIN-ESAIO", + "esaio_dtor -> try free acceptors request queue\r\n") ); + esock_free_request_queue(&descP->acceptorsQ); + + esock_free_env("esaio_dtor close env", descP->closeEnv); + descP->closeEnv = NULL; + + esock_free_env("esaio_dtor meta env", descP->meta.env); + descP->meta.env = NULL; + + SGDBG( ("WIN-ESAIO", "esaio_dtor -> done\r\n") ); +} + + + +extern +void esaio_stop(ErlNifEnv* env, + ESockDescriptor* descP) +{ + + SSDBG( descP, + ("WIN-ESAIO", "esaio_stop(%d) -> entry\r\n", descP->sock) ); + + /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * + * Inform waiting Closer, or close socket + * + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + if ( !IS_PID_UNDEF(&descP->closerPid) && + (descP->closeEnv != NULL) ) { + + /* We will only send this message if the user was made to + * wait (async close). In that case we have en env! + * We have a waiting closer process after nif_close() + * - send message to trigger nif_finalize_close() + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_stop(%d) -> send close msg to %T\r\n", + descP->sock, MKPID(env, &descP->closerPid)) ); + + esock_send_close_msg(env, descP, &descP->closerPid); + /* Message send frees closeEnv */ + descP->closeEnv = NULL; + descP->closeRef = esock_atom_undefined; + + } else { + int err; + + /* We do not have a closer process + * - have to do an unclean (non blocking) close */ + + err = esock_close_socket(env, descP, FALSE); + + switch (err) { + case NO_ERROR: + break; + case WSAENOTSOCK: + if (descP->sock != INVALID_SOCKET) + esock_warning_msg("[WIN-ESAIO] Attempt to close an " + "already closed socket" + "\r\n(without a closer process): " + "\r\n Controlling Process: %T" + "\r\n socket fd: %d" + "\r\n", + descP->ctrlPid, descP->sock); + break; + + default: + esock_warning_msg("[WIN-ESAIO] Failed closing socket without " + "closer process: " + "\r\n Controlling Process: %T" + "\r\n socket fd: %d" + "\r\n Errno: %T" + "\r\n", + descP->ctrlPid, descP->sock, ENO2T(env, err)); + break; + } + + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_stop(%d) -> done\r\n", descP->sock) ); + +} + + + + +/* A 'down' has occured. + * Check the possible processes we monitor in turn: + * closer, controlling process (owner), connector, reader, acceptor and writer. + * + */ +extern +void esaio_down(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> entry with:" + "\r\n Pid: %T" + "\r\n Mon: %T" + "\r\n", descP->sock, MKPID(env, pidP), MON2T(env, monP)) ); + + if (COMPARE_PIDS(&descP->closerPid, pidP) == 0) { + + /* The closer process went down + * - it will not call nif_finalize_close + */ + + enif_set_pid_undefined(&descP->closerPid); + + if (MON_EQ(&descP->closerMon, monP)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> closer process exit\r\n", + descP->sock) ); + + MON_INIT(&descP->closerMon); + + } else { + // The owner is the closer so we used its monitor + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> closer controlling process exit\r\n", + descP->sock) ); + + ESOCK_ASSERT( MON_EQ(&descP->ctrlMon, monP) ); + MON_INIT(&descP->ctrlMon); + enif_set_pid_undefined(&descP->ctrlPid); + + } + + /* Since the closer went down there was one, + * hence esock_close() must have run or scheduled esock_stop(), + * or the socket has never been "selected" upon. + */ + + if (descP->closeEnv == NULL) { + int err; + + /* Since there is no closeEnv, + * esock_close() did not schedule esock_stop() + * and is about to call esock_finalize_close() but died, + * or esock_stop() has run, sent close_msg to the closer + * and cleared ->closeEnv but the closer died + * - we have to do an unclean (non blocking) socket close here + */ + + err = esock_close_socket(env, descP, FALSE); + if (err != 0) + esock_warning_msg("[WIN-ESAIO] " + "Failed closing socket for terminating " + "closer process: " + "\r\n Closer Process: %T" + "\r\n Descriptor: %d" + "\r\n Errno: %d (%T)" + "\r\n", + MKPID(env, pidP), descP->sock, + err, ENO2T(env, err)); + } else { + /* Since there is a closeEnv esock_stop() has not run yet + * - when it finds that there is no closer process + * it will close the socket and ignore the close_msg + * + * The 'stop' callback function will never be triggered on + * Windows...It may be explicitly called... + */ + esock_clear_env("esaio_down - close-env", descP->closeEnv); + esock_free_env("esaio_down - close-env", descP->closeEnv); + descP->closeEnv = NULL; + descP->closeRef = esock_atom_undefined; + } + + } else if (MON_EQ(&descP->ctrlMon, monP)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> controller process exit\r\n", + descP->sock) ); + + MON_INIT(&descP->ctrlMon); + /* The owner went down */ + enif_set_pid_undefined(&descP->ctrlPid); + + if (IS_OPEN(descP->readState)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> OPEN => initiate close\r\n", + descP->sock) ); + + esaio_down_ctrl(env, descP, pidP); + + descP->readState |= ESOCK_STATE_CLOSING; + descP->writeState |= ESOCK_STATE_CLOSING; + + } else { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> already closed or closing\r\n", + descP->sock) ); + + } + + } else if (descP->connectorP != NULL && + MON_EQ(&descP->connector.mon, monP)) { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down {%d} -> connector process exit\r\n", + descP->sock) ); + + MON_INIT(&descP->connector.mon); + + /* connectorP is only set during connection. + * Forget all about the ongoing connection. + * We might end up connected, but the process that initiated + * the connection has died and will never know + */ + + esock_requestor_release("esaio_down->connector", + env, descP, &descP->connector); + descP->connectorP = NULL; + descP->writeState &= ~ESOCK_STATE_CONNECTING; + + } else { + ERL_NIF_TERM sockRef = enif_make_resource(env, descP); + + /* check all operation queue(s): acceptor, writer and reader. + * + * Is it really any point in doing this if the socket is closed? + * + */ + + if (IS_CLOSED(descP->readState)) { + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down(%T) {%d} -> stray down: %T\r\n", + sockRef, descP->sock, pidP) ); + } else { + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down(%T) {%d} -> " + "other process - check readers, writers and acceptors\r\n", + sockRef, descP->sock) ); + + if (descP->readersQ.first != NULL) + esaio_down_reader(env, descP, sockRef, pidP, monP); + if (descP->acceptorsQ.first != NULL) + esaio_down_acceptor(env, descP, sockRef, pidP, monP); + if (descP->writersQ.first != NULL) + esaio_down_writer(env, descP, sockRef, pidP, monP); + } + } + + SSDBG( descP, ("WIN-ESAIO", "esaio_down {%d} -> done\r\n", descP->sock) ); + +} + + + +/* *** esaio_down_ctrl *** + * + * Stop after a downed controller (controlling process = owner process) + * + * This is 'extern' because its currently called from prim_socket_nif + * (esock_setopt_otp_ctrl_proc). + */ +extern +void esaio_down_ctrl(ErlNifEnv* env, + ESockDescriptor* descP, + const ErlNifPid* pidP) +{ + SSDBG( descP, + ("WIN-ESAIO", "esaio_down_ctrl {%d} -> entry with" + "\r\n Pid: %T" + "\r\n", descP->sock, MKPID(env, pidP)) ); + + if (do_stop(env, descP)) { + /* esock_stop() is scheduled + * - it has to close the socket + */ + SSDBG( descP, + ("WIN-ESAIO", "esaio_down_ctrl {%d} -> stop was scheduled\r\n", + descP->sock) ); + } else { + int err; + + /* Socket has no *active* requests in the I/O Completion Ports machinery + * so esock_stop() will not be called + * - we have to do an unclean (non blocking) socket close here + */ + + err = esock_close_socket(env, descP, FALSE); + if (err != 0) + esock_warning_msg("[WIN-ESAIO] " + "Failed closing socket for terminating " + "owner process: " + "\r\n Owner Process: %T" + "\r\n Descriptor: %d" + "\r\n Errno: %d (%T)" + "\r\n", + MKPID(env, pidP), descP->sock, + err, ENO2T(env, err)); + } + + SSDBG( descP, + ("WIN-ESAIO", "esaio_down_ctrl {%d} -> done\r\n", descP->sock) ); + +} + + + +/* *** esaio_down_acceptor *** + * + * Check and then handle a downed acceptor process. + * + */ +static +void esaio_down_acceptor(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + + /* Maybe unqueue one of the waiting acceptors */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down_acceptor(%T) {%d} -> " + "maybe unqueue a waiting acceptor\r\n", + sockRef, descP->sock) ); + + esock_acceptor_unqueue(env, descP, NULL, pidP); + +} + + +/* *** esaio_down_writer *** + * + * Check and then handle a downed writer process. + * + */ + +static +void esaio_down_writer(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + + /* Maybe unqueue one of the waiting writer(s) */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down_writer(%T) {%d} -> maybe unqueue a waiting writer\r\n", + sockRef, descP->sock) ); + + esock_writer_unqueue(env, descP, NULL, pidP); + +} + + +/* *** esaio_down_reader *** + * + * Check and then handle a downed reader process. + * + */ + +static +void esaio_down_reader(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + const ErlNifPid* pidP, + const ErlNifMonitor* monP) +{ + /* Maybe unqueue one of the waiting reader(s) */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_down_reader(%T) {%d} -> maybe unqueue a waiting reader\r\n", + sockRef, descP->sock) ); + + esock_reader_unqueue(env, descP, NULL, pidP); + +} + + +/* ==================================================================== * + * * + * Send Utility functions * + * * + * ==================================================================== * + */ + +/* *** send_check_result *** + * + * Check the result of a socket send (WSASend, WSASendTo and WSASendMsg) call. + * + */ +static +ERL_NIF_TERM send_check_result(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + int send_result, + ssize_t dataSize, + BOOLEAN_T dataInTail, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + BOOLEAN_T* cleanup) +{ + ERL_NIF_TERM res; + BOOLEAN_T send_error; + int err; + + if (send_result == 0) { + + /* Send success already! + * So, no need to store the data (request, in the "queue"). + * Note that the completion threads will use the + * precense or absence of this request 'record' to inform + * its actions. + */ + + *cleanup = FALSE; + + res = send_check_ok(env, descP, dataSize, sockRef); + + } else { + + /* send returned error, check which */ + + int save_errno = sock_errno(); + + /* There are basically two kinds of errors: + * 1) Pending: + * An overlapped operation was successfully initiated. + * Completion will be "indicated" at a later time. + * 2) An actual error + */ + + if (save_errno == WSA_IO_PENDING) { + + /* We need to store the data in the queue! */ + + *cleanup = FALSE; + + res = send_check_pending(env, descP, opP, caller, sockRef, sendRef); + + } else { + + *cleanup = TRUE; + + res = send_check_fail(env, descP, save_errno, sockRef); + + } + } + + SSDBG( descP, + ("WIN-ESAIO", + "send_check_result(%T) {%d} -> done:" + "\r\n res: %T" + "\r\n", sockRef, descP->sock, res) ); + + return res; +} + + + +/* *** send_check_ok *** + * + * Processing done upon successful send. + */ +static +ERL_NIF_TERM send_check_ok(ErlNifEnv* env, + ESockDescriptor* descP, + DWORD written, + ERL_NIF_TERM sockRef) +{ + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_pkg, &descP->writePkgCnt, 1); + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_byte, &descP->writeByteCnt, written); + + /* We can *never* have a partial successs: + * Either the entire buffer is sent, or the op is scheduled or we fail. + * But since we have a field (writePkgMaxCnt) in the descriptor + * we might as well use it. + */ + + descP->writePkgMaxCnt = written; + if (descP->writePkgMaxCnt > descP->writePkgMax) + descP->writePkgMax = descP->writePkgMaxCnt; + descP->writePkgMaxCnt = 0; + + SSDBG( descP, + ("WIN-ESAIO", "send_check_ok(%T) {%d} -> %ld written - done\r\n", + sockRef, descP->sock, written) ); + + return esock_atom_ok; +} + + +/* *** send_check_pending *** + * + * The send operation was scheduled, that is, its now in the handls + * of the I/O Completion Port framework. + */ +static +ERL_NIF_TERM send_check_pending(ErlNifEnv* env, + ESockDescriptor* descP, + ESAIOOperation* opP, + ErlNifPid caller, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef) +{ + SSDBG( descP, + ("WIN-ESAIO", + "send_check_pending(%T, %d) -> entry with" + "\r\n sendRef: %T" + "\r\n", sockRef, descP->sock, sendRef) ); + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_waits, &descP->writeWaits, 1); + + descP->writeState |= ESOCK_STATE_SELECTED; + + esock_writer_push(env, descP, caller, sendRef, opP); + + return esock_atom_completion; + +} + + + +/* *** send_check_fail *** + * + * Processing done upon failed send. + * An actual failure. + */ +static +ERL_NIF_TERM send_check_fail(ErlNifEnv* env, + ESockDescriptor* descP, + int saveErrno, + ERL_NIF_TERM sockRef) +{ + ERL_NIF_TERM reason; + + ESOCK_CNT_INC(env, descP, sockRef, + esock_atom_write_fails, &descP->writeFails, 1); + + reason = ENO2T(env, saveErrno); + + SSDBG( descP, + ("WIN-ESAIO", + "send_check_fail(%T, %d) -> error: " + "\r\n %d (%T)\r\n", + sockRef, descP->sock, saveErrno, reason) ); + + return esock_make_error(env, reason); +} + + + +/* ==================================================================== * + * * + * Utility functions * + * * + * ==================================================================== * + */ + +/* *** get_send_ovl_result *** + * + * Used for all send 'overlapped' operations; send, sendto and sendmsg. + */ +static +BOOL get_send_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* written) +{ + DWORD flags = 0; + BOOL result = get_ovl_result(sock, ovl, written, &flags); + + (void) flags; + + return result; +} + + +/* *** get_recv_ovl_result *** + * + * Used for recv *and* recvfrom 'overlapped' operations. + */ +static +BOOL get_recv_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* read, + DWORD* flags) +{ + return get_ovl_result(sock, ovl, read, flags); +} + + +/* *** get_recvmsg_ovl_result *** + * + * Used for all recvmsg 'overlapped' operations. + */ +static +BOOL get_recvmsg_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* read) +{ + DWORD flags = 0; + BOOL result = get_ovl_result(sock, ovl, read, &flags); + + (void) flags; + + return result; +} + + +/* *** get_ovl_result *** + * + * Simple wrapper function for WSAGetOverlappedResult. + */ +static +BOOL get_ovl_result(SOCKET sock, + OVERLAPPED* ovl, + DWORD* transfer, + DWORD* flags) +{ + return WSAGetOverlappedResult(sock, ovl, transfer, FALSE, flags); +} + + + +/* *** esaio_add_socket *** + * + * Add socket to I/O completion port. + */ +static +int esaio_add_socket(ESockDescriptor* descP) +{ + int res; + HANDLE tmp = CreateIoCompletionPort((HANDLE) descP->sock, ctrl.cport, + (ULONG_PTR) descP, 0); + + if (tmp != NULL) { + res = ESAIO_OK; + } else { + res = sock_errno(); + } + + return res; +} + + +static +void esaio_send_completion_msg(ErlNifEnv* sendEnv, + ESockDescriptor* descP, + ErlNifPid* pid, + ErlNifEnv* msgEnv, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM completionInfo) +{ + ERL_NIF_TERM msg = mk_completion_msg(msgEnv, sockRef, completionInfo); + + /* This can only fail if: + * - The recipient is dead. + * Our monitor should clear this up ... eventually. + * Possible race? + * - We (the sender) are "dead" (which we are clearly not) + */ + if (! esock_send_msg(sendEnv, pid, msg, NULL)) { + + /* + ESOCK_DBG_PRINTF( TRUE, ("IN-ESAIO", + "esaio_send_completion_msg(%T) {%d} failed ->" + "\r\n pid: %T" + "\r\n", + sockRef, descP->sock, MKPID(sendEnv, pid)) ); + */ + + SSDBG( descP, + ("WIN-ESAIO", + "esaio_send_completion_msg(%T) {%d} failed ->" + "\r\n pid: %T" + "\r\n", + sockRef, descP->sock, MKPID(sendEnv, pid)) ); + } +} + + +/* *** mk_completion_msg *** + * + * Construct a completion (socket) message. It has the form: + * + * {'$socket', Socket, completion, CompletionInfo} + * + */ + +static +ERL_NIF_TERM mk_completion_msg(ErlNifEnv* env, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM info) +{ + return esock_mk_socket_msg(env, sockRef, + esock_atom_completion, info); +} + + +#endif diff --git a/erts/emulator/pcre/local_config.h b/erts/emulator/pcre/local_config.h index 178c4d42817f..6f4f3a18680e 100644 --- a/erts/emulator/pcre/local_config.h +++ b/erts/emulator/pcre/local_config.h @@ -73,9 +73,6 @@ "configure" can be used to override this default. */ #define POSIX_MALLOC_THRESHOLD 10 -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - /* Define to enable support for Unicode properties */ #define SUPPORT_UCP diff --git a/erts/emulator/pcre/pcre_compile.c b/erts/emulator/pcre/pcre_compile.c index 80b966869a1a..94a7222e4db3 100644 --- a/erts/emulator/pcre/pcre_compile.c +++ b/erts/emulator/pcre/pcre_compile.c @@ -4834,7 +4834,7 @@ for (;; ptr++) If the class contains characters outside the 0-255 range, a different opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells + but those above are explicitly listed afterwards. A flag byte tells whether the bitmap is present, and whether this is a negated class or not. In JavaScript compatibility mode, an isolated ']' causes an error. In @@ -5855,7 +5855,7 @@ for (;; ptr++) /* If previous was a character type match (\d or similar), abolish it and create a suitable repeat item. The code is shared with single-character repeats by setting op_type to add a suitable offset into repeat_type. Note - the the Unicode property types will be present only when SUPPORT_UCP is + the Unicode property types will be present only when SUPPORT_UCP is defined, but we don't wrap the little bits of code here because it just makes it horribly messy. */ @@ -7070,7 +7070,7 @@ for (;; ptr++) /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird thing to do, but Perl allows all assertions to be quantified, and when they contain capturing parentheses there may be a potential use for - this feature. Not that that applies to a quantified (?!) but we allow + this feature. Not that applies to a quantified (?!) but we allow it for uniformity. */ /* ------------------------------------------------------------ */ diff --git a/erts/emulator/pcre/pcre_exec.c b/erts/emulator/pcre/pcre_exec.c index 99c37f065736..bf7a9044ee98 100644 --- a/erts/emulator/pcre/pcre_exec.c +++ b/erts/emulator/pcre/pcre_exec.c @@ -301,7 +301,7 @@ been known for decades.) So.... There is a fudge, triggered by defining NO_RECURSE, which avoids recursive calls by keeping local variables that need to be preserved in blocks of memory -obtained from malloc() instead instead of on the stack. Macros are used to +obtained from malloc() instead of on the stack. Macros are used to achieve this so that the actual code doesn't look very different to what it always used to. @@ -626,7 +626,7 @@ frame->Xoffset_top = offset_top; frame->Xeptrb = eptrb; frame->Xrdepth = rdepth; -/* This is where control jumps back to to effect "recursion" */ +/* This is where control jumps back to effect "recursion" */ HEAP_RECURSE: @@ -3213,7 +3213,7 @@ for (;;) /* Match an extended character class. In the 8-bit library, this opcode is - encountered only when UTF-8 mode mode is supported. In the 16-bit and + encountered only when UTF-8 mode is supported. In the 16-bit and 32-bit libraries, codepoints greater than 255 may be encountered even when UTF is not supported. */ @@ -7023,7 +7023,7 @@ if (extra_data != NULL) { md->loop_limit = extra_data->loop_limit; if (extra_data->restart_data) - md->loop_limit -= extra_data->loop_limit - exec_context->valid_utf_ystate.cnt; + md->loop_limit -= exec_context->valid_utf_ystate.cnt; if (md->loop_limit < 10) md->loop_limit = 10; /* At least do something if we've come this far... */ } @@ -7371,7 +7371,7 @@ for(;;) break; } - /* If req_char is set, we know that that character must appear in the + /* If req_char is set, we know that character must appear in the subject for the match to succeed. If the first character is set, req_char must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of backtracking in patterns with diff --git a/erts/emulator/pcre/pcre_maketables.c b/erts/emulator/pcre/pcre_maketables.c index 89204d115229..7877a577e99d 100644 --- a/erts/emulator/pcre/pcre_maketables.c +++ b/erts/emulator/pcre/pcre_maketables.c @@ -108,7 +108,7 @@ exclusive ones - in some locales things may be different. Note that the table for "space" includes everything "isspace" gives, including VT in the default locale. This makes it work for the POSIX class [:space:]. -From release 8.34 is is also correct for Perl space, because Perl added VT at +From release 8.34 is also correct for Perl space, because Perl added VT at release 5.18. Note also that it is possible for a character to be alnum or alpha without diff --git a/erts/emulator/pcre/pcre_valid_utf8.c b/erts/emulator/pcre/pcre_valid_utf8.c index 1dc1f9ba0c0b..95a60c3fdbfd 100644 --- a/erts/emulator/pcre/pcre_valid_utf8.c +++ b/erts/emulator/pcre/pcre_valid_utf8.c @@ -219,7 +219,7 @@ for (p = string; length-- > 0; p++) switch (ab) { /* 2-byte character. No further bytes to check for 0x80. Check first byte - for for xx00 000x (overlong sequence). */ + for xx00 000x (overlong sequence). */ case 1: if ((c & 0x3e) == 0) { @@ -251,7 +251,7 @@ for (p = string; length-- > 0; p++) break; /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2 - bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a + bytes for 1111 0000, xx00 xxxx (overlong sequence), then check for a character greater than 0x0010ffff (f4 8f bf bf) */ case 3: diff --git a/erts/emulator/ryu/README.ryu_update.md b/erts/emulator/ryu/README.ryu_update.md new file mode 100644 index 000000000000..cc60ea169003 --- /dev/null +++ b/erts/emulator/ryu/README.ryu_update.md @@ -0,0 +1,20 @@ +# How to update the Ryu version used by Erlang + +Last commit taken : 844864ac213bdbf1fb57e6f51c653b3d90af0937 + +## The basic changes to the Ryu library + +To work with the Erlang VM, Ryu has been changed in three important ways. These +changes have been marked with a `//CHANGE_FOR_ERLANG` comment explaining them in +the code. + +1. We only kept the bare minimum files needed to generate a double to string with the shortest algorithm, with the widest lookup table +2. We deleted the code producing the final string, this is handled using a modified version of to_chars from the MS STL. +3. All other unneeded code has been deleted + +This is build with our own makefile. + +Some of the more minor difference: + +- the Zero case in common.h is changed to correspond to erlang fixed point version +- the MS STL pointer check are not here. Erlang generate a 256 bytes buffer, we only need 30 maximum. Beware what this mean when refactoring. diff --git a/erts/emulator/ryu/common.h b/erts/emulator/ryu/common.h new file mode 100644 index 000000000000..7048e909749c --- /dev/null +++ b/erts/emulator/ryu/common.h @@ -0,0 +1,115 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +#ifndef RYU_COMMON_H +#define RYU_COMMON_H + +#include +#include +#include + +#if defined(_M_IX86) || defined(_M_ARM) +#define RYU_32_BIT_PLATFORM +#endif + +// Returns the number of decimal digits in v, which must not contain more than 9 digits. +static inline uint32_t decimalLength9(const uint32_t v) { + // Function precondition: v is not a 10-digit number. + // (f2s: 9 digits are sufficient for round-tripping.) + // (d2fixed: We print 9-digit blocks.) + assert(v < 1000000000); + if (v >= 100000000) { return 9; } + if (v >= 10000000) { return 8; } + if (v >= 1000000) { return 7; } + if (v >= 100000) { return 6; } + if (v >= 10000) { return 5; } + if (v >= 1000) { return 4; } + if (v >= 100) { return 3; } + if (v >= 10) { return 2; } + return 1; +} + +// Returns e == 0 ? 1 : [log_2(5^e)]; requires 0 <= e <= 3528. +static inline int32_t log2pow5(const int32_t e) { + // This approximation works up to the point that the multiplication overflows at e = 3529. + // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater + // than 2^9297. + assert(e >= 0); + assert(e <= 3528); + return (int32_t) ((((uint32_t) e) * 1217359) >> 19); +} + +// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528. +static inline int32_t pow5bits(const int32_t e) { + // This approximation works up to the point that the multiplication overflows at e = 3529. + // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater + // than 2^9297. + assert(e >= 0); + assert(e <= 3528); + return (int32_t) (((((uint32_t) e) * 1217359) >> 19) + 1); +} + +// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528. +static inline int32_t ceil_log2pow5(const int32_t e) { + return log2pow5(e) + 1; +} + +// Returns floor(log_10(2^e)); requires 0 <= e <= 1650. +static inline uint32_t log10Pow2(const int32_t e) { + // The first value this approximation fails for is 2^1651 which is just greater than 10^297. + assert(e >= 0); + assert(e <= 1650); + return (((uint32_t) e) * 78913) >> 18; +} + +// Returns floor(log_10(5^e)); requires 0 <= e <= 2620. +static inline uint32_t log10Pow5(const int32_t e) { + // The first value this approximation fails for is 5^2621 which is just greater than 10^1832. + assert(e >= 0); + assert(e <= 2620); + return (((uint32_t) e) * 732923) >> 20; +} + +static inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) { + if (mantissa) { + memcpy(result, "NaN", 3); + return 3; + } + if (sign) { + result[0] = '-'; + } + if (exponent) { + memcpy(result + sign, "Infinity", 8); + return sign + 8; + } + // CHANGE_FOR_ERLANG we use "0.0" as the 0 and not "0E0" + memcpy(result + sign, "0.0", 3); + return sign + 3; +} + +static inline uint32_t float_to_bits(const float f) { + uint32_t bits = 0; + memcpy(&bits, &f, sizeof(float)); + return bits; +} + +static inline uint64_t double_to_bits(const double d) { + uint64_t bits = 0; + memcpy(&bits, &d, sizeof(double)); + return bits; +} + +#endif // RYU_COMMON_H diff --git a/erts/emulator/ryu/d2s.c b/erts/emulator/ryu/d2s.c new file mode 100644 index 000000000000..643e41ce0250 --- /dev/null +++ b/erts/emulator/ryu/d2s.c @@ -0,0 +1,712 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +// Runtime compiler options: +// -DRYU_DEBUG Generate verbose debugging output to stdout. +// +// -DRYU_ONLY_64_BIT_OPS Avoid using uint128_t or 64-bit intrinsics. Slower, +// depending on your compiler. +// + +// CHANGE_FOR_ERLANG: "ryu/ryu.h" -> "ryu.h" +#include "ryu.h" +// END CHANGE_FOR_ERLANG + +#include +#include +#include +#include +#include + +#ifdef RYU_DEBUG +#include +#include +#endif + +// CHANGE_FOR_ERLANG: "ryu/*.h" -> "*.h" +#include "common.h" +#include "digit_table.h" +#include "d2s_intrinsics.h" +// END CHANGE_FOR_ERLANG + +// CHANGE_FOR_ERLANG we got rid of the small_table. Also namespace as above +#include "d2s_full_table.h" +// END CHANGE_FOR_ERLANG + +#define DOUBLE_MANTISSA_BITS 52 +#define DOUBLE_EXPONENT_BITS 11 +#define DOUBLE_BIAS 1023 + +static inline uint32_t decimalLength17(const uint64_t v) { + // This is slightly faster than a loop. + // The average output length is 16.38 digits, so we check high-to-low. + // Function precondition: v is not an 18, 19, or 20-digit number. + // (17 digits are sufficient for round-tripping.) + assert(v < 100000000000000000L); + if (v >= 10000000000000000L) { return 17; } + if (v >= 1000000000000000L) { return 16; } + if (v >= 100000000000000L) { return 15; } + if (v >= 10000000000000L) { return 14; } + if (v >= 1000000000000L) { return 13; } + if (v >= 100000000000L) { return 12; } + if (v >= 10000000000L) { return 11; } + if (v >= 1000000000L) { return 10; } + if (v >= 100000000L) { return 9; } + if (v >= 10000000L) { return 8; } + if (v >= 1000000L) { return 7; } + if (v >= 100000L) { return 6; } + if (v >= 10000L) { return 5; } + if (v >= 1000L) { return 4; } + if (v >= 100L) { return 3; } + if (v >= 10L) { return 2; } + return 1; +} + +// A floating decimal representing m * 10^e. +typedef struct floating_decimal_64 { + uint64_t mantissa; + // Decimal exponent's range is -324 to 308 + // inclusive, and can fit in a short if needed. + int32_t exponent; +} floating_decimal_64; + +static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent) { + int32_t e2; + uint64_t m2; + if (ieeeExponent == 0) { + // We subtract 2 so that the bounds computation has 2 additional bits. + e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2; + m2 = ieeeMantissa; + } else { + e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2; + m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa; + } + const bool even = (m2 & 1) == 0; + const bool acceptBounds = even; + +#ifdef RYU_DEBUG + printf("-> %" PRIu64 " * 2^%d\n", m2, e2 + 2); +#endif + + // Step 2: Determine the interval of valid decimal representations. + const uint64_t mv = 4 * m2; + // Implicit bool -> int conversion. True is 1, false is 0. + const uint32_t mmShift = ieeeMantissa != 0 || ieeeExponent <= 1; + // We would compute mp and mm like this: + // uint64_t mp = 4 * m2 + 2; + // uint64_t mm = mv - 1 - mmShift; + + // Step 3: Convert to a decimal power base using 128-bit arithmetic. + uint64_t vr, vp, vm; + int32_t e10; + bool vmIsTrailingZeros = false; + bool vrIsTrailingZeros = false; + if (e2 >= 0) { + // I tried special-casing q == 0, but there was no effect on performance. + // This expression is slightly faster than max(0, log10Pow2(e2) - 1). + const uint32_t q = log10Pow2(e2) - (e2 > 3); + e10 = (int32_t) q; + const int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t) q) - 1; + const int32_t i = -e2 + (int32_t) q + k; + vr = mulShiftAll64(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift); +#ifdef RYU_DEBUG + printf("%" PRIu64 " * 2^%d / 10^%u\n", mv, e2, q); + printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm); +#endif + if (q <= 21) { + // This should use q <= 22, but I think 21 is also safe. Smaller values + // may still be safe, but it's more difficult to reason about them. + // Only one of mp, mv, and mm can be a multiple of 5, if any. + const uint32_t mvMod5 = ((uint32_t) mv) - 5 * ((uint32_t) div5(mv)); + if (mvMod5 == 0) { + vrIsTrailingZeros = multipleOfPowerOf5(mv, q); + } else if (acceptBounds) { + // Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q + // <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q + // <=> true && pow5Factor(mm) >= q, since e2 >= q. + vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q); + } else { + // Same as min(e2 + 1, pow5Factor(mp)) >= q. + vp -= multipleOfPowerOf5(mv + 2, q); + } + } + } else { + // This expression is slightly faster than max(0, log10Pow5(-e2) - 1). + const uint32_t q = log10Pow5(-e2) - (-e2 > 1); + e10 = (int32_t) q + e2; + const int32_t i = -e2 - (int32_t) q; + const int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT; + const int32_t j = (int32_t) q - k; + vr = mulShiftAll64(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift); +#ifdef RYU_DEBUG + printf("%" PRIu64 " * 5^%d / 10^%u\n", mv, -e2, q); + printf("%u %d %d %d\n", q, i, k, j); + printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm); +#endif + if (q <= 1) { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 * m2, so it always has at least two trailing 0 bits. + vrIsTrailingZeros = true; + if (acceptBounds) { + // mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1. + vmIsTrailingZeros = mmShift == 1; + } else { + // mp = mv + 2, so it always has at least one trailing 0 bit. + --vp; + } + } else if (q < 63) { // TODO(ulfjack): Use a tighter bound here. + // We want to know if the full product has at least q trailing zeros. + // We need to compute min(p2(mv), p5(mv) - e2) >= q + // <=> p2(mv) >= q && p5(mv) - e2 >= q + // <=> p2(mv) >= q (because -e2 >= q) + vrIsTrailingZeros = multipleOfPowerOf2(mv, q); +#ifdef RYU_DEBUG + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); +#endif + } + } +#ifdef RYU_DEBUG + printf("e10=%d\n", e10); + printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm); + printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false"); + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); +#endif + + // Step 4: Find the shortest decimal representation in the interval of valid representations. + int32_t removed = 0; + uint8_t lastRemovedDigit = 0; + uint64_t output; + // On average, we remove ~2 digits. + if (vmIsTrailingZeros || vrIsTrailingZeros) { + // General case, which happens rarely (~0.7%). + for (;;) { + const uint64_t vpDiv10 = div10(vp); + const uint64_t vmDiv10 = div10(vm); + if (vpDiv10 <= vmDiv10) { + break; + } + const uint32_t vmMod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmDiv10); + const uint64_t vrDiv10 = div10(vr); + const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10); + vmIsTrailingZeros &= vmMod10 == 0; + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8_t) vrMod10; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } +#ifdef RYU_DEBUG + printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm); + printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false"); +#endif + if (vmIsTrailingZeros) { + for (;;) { + const uint64_t vmDiv10 = div10(vm); + const uint32_t vmMod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmDiv10); + if (vmMod10 != 0) { + break; + } + const uint64_t vpDiv10 = div10(vp); + const uint64_t vrDiv10 = div10(vr); + const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10); + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8_t) vrMod10; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } + } +#ifdef RYU_DEBUG + printf("%" PRIu64 " %d\n", vr, lastRemovedDigit); + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); +#endif + if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0) { + // Round even if the exact number is .....50..0. + lastRemovedDigit = 4; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5); + } else { + // Specialized for the common case (~99.3%). Percentages below are relative to this. + bool roundUp = false; + const uint64_t vpDiv100 = div100(vp); + const uint64_t vmDiv100 = div100(vm); + if (vpDiv100 > vmDiv100) { // Optimization: remove two digits at a time (~86.2%). + const uint64_t vrDiv100 = div100(vr); + const uint32_t vrMod100 = ((uint32_t) vr) - 100 * ((uint32_t) vrDiv100); + roundUp = vrMod100 >= 50; + vr = vrDiv100; + vp = vpDiv100; + vm = vmDiv100; + removed += 2; + } + // Loop iterations below (approximately), without optimization above: + // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02% + // Loop iterations below (approximately), with optimization above: + // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% + for (;;) { + const uint64_t vpDiv10 = div10(vp); + const uint64_t vmDiv10 = div10(vm); + if (vpDiv10 <= vmDiv10) { + break; + } + const uint64_t vrDiv10 = div10(vr); + const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10); + roundUp = vrMod10 >= 5; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } +#ifdef RYU_DEBUG + printf("%" PRIu64 " roundUp=%s\n", vr, roundUp ? "true" : "false"); + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); +#endif + // We need to take vr + 1 if vr is outside bounds or we need to round up. + output = vr + (vr == vm || roundUp); + } + const int32_t exp = e10 + removed; + +#ifdef RYU_DEBUG + printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm); + printf("O=%" PRIu64 "\n", output); + printf("EXP=%d\n", exp); +#endif + + floating_decimal_64 fd; + fd.exponent = exp; + fd.mantissa = output; + return fd; +} + +//CHANGE_FOR_ERLANG: This format is new, it is here to handle the different format switch used in the STL code +enum chars_format { + FMT_SCIENTIFIC, + FMT_FIXED, + FMT_GENERAL +}; + +// This is inspired from the MS STL Charconv, under Apache with LLVM exception licence +// see https://github.com/microsoft/STL/blob/main/LICENSE.txt +// The inspiration is at https://github.com/microsoft/STL/blob/e745bad3b1d05b5b19ec652d68abb37865ffa454/stl/inc/xcharconv_ryu.h#L1926 +// CHANGE_FOR_ERLANG all the types and typecast have been adapted to C types from Cpp. +// I have also kept the Ryu original function head as it allows to not impact the rest of the code +// __v and __mantissa and __exponent have lost their double underscore over the whole function +// all the test on the lenght of the buffer have been dropped too. This could need change, but +// we always pass a 256 bytes buffer when we only need 26 bytes maximum. +static inline int to_chars(const floating_decimal_64 v, const bool sign, char* const result) { + // Step 5: Print the decimal representation. + uint64_t __output = v.mantissa; + int32_t _Ryu_exponent = v.exponent; + const uint32_t __olength = decimalLength17(__output); + int32_t _Scientific_exponent = _Ryu_exponent + ((int32_t) __olength) - 1; + + // CHANGE_FOR_ERLANG: we use our chars_format instead of the STL one + enum chars_format _Fmt; + + int32_t _Lower; + int32_t _Upper; + + if (__olength == 1) { + // CHANGE_FOR_ERLANG the format and examples have been adapted to the erlang format + // as the original would have not shown a change in format + // (erlang always add ".0" to scientific format) and omit the + in the exponent + // Value | Fixed | Scientific + // 1e-4 | "0.0001" | "1.0e-4" + // 1e2 | "100.0" | "1.0e2" + // CHANGE_FOR_ERLANG the values for a switch, as seen in the example above, for erlang + // are different than for STL format. + _Lower = -4; + _Upper = 2; + } else if (_Scientific_exponent >= 10) { + // CHANGE_FOR_ERLANG This case does not exist for the STL and is due to the + // negative sign in the exponent. + // Value | Fixed | Scientific + // 123456789e1 | "1234567890.0" | "1.23456789e9" + // 123456789e2 | "12345678900.0" | "1.23456789e10" + + _Lower = - (int32_t) (__olength + 2); + _Upper = 2; + } else { + // CHANGE_FOR_ERLANG the format and examples have been adapted to the erlang format + // as the original would have not shown a change in format + // (erlang always add ".0" to scientific format) and omit the + in the exponent + // Value | Fixed | Scientific + // 1234e-6 | "0.001234" | "1.234e-4" + // 1234e1 | "12340.0" | "1.234e4" + // CHANGE_FOR_ERLANG the values for a switch, as seen in the example above, for erlang + // are different than for STL format. + _Lower = - (int32_t) (__olength + 2); + _Upper = 1; + } + + if (_Lower <= _Ryu_exponent && _Ryu_exponent <= _Upper) { + // CHANGE_FOR_ERLANG this is added to handle the -2**53, 2**53 range special case + // These are edge cases not captured above, all the other are naturally handled + // by _Lower nad _Upper + if ((__output >= (1ull << 53) && _Ryu_exponent == 0) + || (__output > ((1ull << 52) / 5) && _Ryu_exponent == 1) + || (__output > ((1ull << 51) / 25) && _Ryu_exponent == 2)) { + _Fmt = FMT_SCIENTIFIC; + } else { + _Fmt = FMT_FIXED; + } + } else { + // CHANGE_FOR_ERLANG we do not need to handle the %g case here. + _Fmt = FMT_SCIENTIFIC; + } + + // CHANGE_FOR_ERLANG we handle the sign here as it is handled outside of this in the STL case + // and we need it to compute the start of the buffer for the characters after + if (sign) { + result[0] = '-'; + } + + // CHANGE_FOR_ERLANG we compute the start of the usable buffer. It is done here + // in order to be fixed for both branches of formatting. + char* const __result = result + sign; + + if (_Fmt == FMT_FIXED) { + // CHANGE_FOR_ERLANG this whole table has been adapted to erlang examples to help + // debug and evolve the edge cases + // Example: __output == 1729, __olength == 4 + + // _Ryu_exponent | Printed | _Whole_digits | _Total_fixed_length | Notes + // --------------|----------|---------------|----------------------|--------------------------------------- + // 1 | 17290.0 | 5 | _Whole_digits + 2 | Unified length cases. + // 0 | 1729.0 | 4 | | + // --------------|----------|---------------|----------------------|--------------------------------------- + // -1 | 172.9 | 3 | __olength + 1 | This case can't happen for + // -2 | 17.29 | 2 | | __olength == 1, but no additional + // -3 | 1.729 | 1 | | code is needed to avoid it. + // --------------|----------|---------------|----------------------|--------------------------------------- + // -4 | 0.1729 | 0 | 2 - _Ryu_exponent | If the decimal point appears, we need + // -5 | 0.01729 | -1 | | to put the "0" in front + // -6 | 0.001729 | -2 | | + + const int32_t _Whole_digits = (int32_t) (__olength) + _Ryu_exponent; + + uint32_t _Total_fixed_length; + if (_Ryu_exponent >= 0) { + // CHANGE_FOR_ERLANG the examples and values have been adapted to erlang format one + // CHANGE_FOR_ERLANG we also dropped the whole adjustement, as it is only of value + // for %f which we do not handle + // cases "17290.0" and "1729.0" + _Total_fixed_length = (uint32_t) (_Whole_digits) + 2; + } else if (_Whole_digits > 0) { // case "17.29" + _Total_fixed_length = __olength + 1; + } else { // case "0.001729" + _Total_fixed_length = (uint32_t) (2 - _Ryu_exponent); + } + + char* _Mid; + if (_Ryu_exponent >= 0) { // case "172900.0" + // CHANGE_FOR_ERLANG we do not need the can_use_ryu, as we are not doing %f + // but always shortest round_trip. The whole complexity here is dropped + // Print the decimal digits, left-aligned within [result, result + _Total_fixed_length). + _Mid = __result + __olength; + } else { // cases "1729.0", "17.29", and "0.001729" + // Print the decimal digits, right-aligned within [result, result + _Total_fixed_length). + _Mid = __result + _Total_fixed_length; + } + + // We prefer 32-bit operations, even on 64-bit platforms. + // We have at most 17 digits, and uint32_t can store 9 digits. + // If __output doesn't fit into uint32_t, we cut off 8 digits, + // so the rest will fit into uint32_t. + // CHANGE_FOR_ERLANG we consider in this whole thing that memcopy use the same + // char has defined in the DIGIT_TABLE + // CHANGE_FOR_ERLANG __DIGIT_TABLE became DIGIT_TABLE + if ((__output >> 32) != 0) { + // Expensive 64-bit division. + const uint64_t __q = div1e8(__output); + uint32_t __output2 = (uint32_t) (__output - 100000000 * __q); + __output = __q; + + const uint32_t __c = __output2 % 10000; + __output2 /= 10000; + const uint32_t __d = __output2 % 10000; + const uint32_t __c0 = (__c % 100) << 1; + const uint32_t __c1 = (__c / 100) << 1; + const uint32_t __d0 = (__d % 100) << 1; + const uint32_t __d1 = (__d / 100) << 1; + + memcpy(_Mid -= 2, DIGIT_TABLE + __c0, 2); + memcpy(_Mid -= 2, DIGIT_TABLE + __c1, 2); + memcpy(_Mid -= 2, DIGIT_TABLE + __d0, 2); + memcpy(_Mid -= 2, DIGIT_TABLE + __d1, 2); + } + uint32_t __output2 = (uint32_t) __output; + while (__output2 >= 10000) { +#ifdef __clang__ // TRANSITION, LLVM-38217 + const uint32_t __c = __output2 - 10000 * (__output2 / 10000); +#else + const uint32_t __c = __output2 % 10000; +#endif + __output2 /= 10000; + const uint32_t __c0 = (__c % 100) << 1; + const uint32_t __c1 = (__c / 100) << 1; + memcpy(_Mid -= 2, DIGIT_TABLE + __c0, 2); + memcpy(_Mid -= 2, DIGIT_TABLE + __c1, 2); + } + if (__output2 >= 100) { + const uint32_t __c = (__output2 % 100) << 1; + __output2 /= 100; + memcpy(_Mid -= 2, DIGIT_TABLE + __c, 2); + } + if (__output2 >= 10) { + const uint32_t __c = __output2 << 1; + memcpy(_Mid -= 2, DIGIT_TABLE + __c, 2); + } else { + *--_Mid = (char) ('0' + __output2); + } + + if (_Ryu_exponent > 0) { // case "172900.0" + // Performance note: it might be more efficient to do this immediately after setting _Mid. + // CHANGE_FOR_ERLANG we have different case here, so we have to add the ".0" here + // we use memset as we do not have access to fill_n + memset(__result + __olength, '0', (size_t) _Ryu_exponent); + __result[__olength + (size_t) _Ryu_exponent] = '.'; + __result[__olength + (size_t) _Ryu_exponent + 1] = '0'; + } else if (_Ryu_exponent == 0) { // case "1729.0" + // CHANGE_FOR_ERLANG we have different case here, so we have to add the ".0" here + __result[__olength] = '.'; + __result[__olength + 1] = '0'; + } else if (_Whole_digits > 0) { // case "17.29" + // Performance note: moving digits might not be optimal. + memmove(__result, __result + 1, (size_t) _Whole_digits); + __result[_Whole_digits] = '.'; + } else { // case "0.001729" + // CHANGE_FOR_ERLANG we use the memset here as we do not have access to fill_n + // Performance note: a larger memset() followed by overwriting '.' might be more efficient. + __result[0] = '0'; + __result[1] = '.'; + memset(__result + 2, '0', (size_t) (-_Whole_digits)); + } + + // CHANGE_FOR_ERLANG we do not need the errc and we are only interested in + // returning the length, as it is what Ryu and erlang expect. We do add the + // sign as we did it here instead of adding it by default as in the STL + return _Total_fixed_length + sign; + } + + uint32_t _Scientific_exponent_length; + // CHANGE_FOR_ERLANG we have to do a little bit more complex logic here because we do not always + // print the exponent sign, only if it is negative + if (_Scientific_exponent <= -100) { // "e-100" + _Scientific_exponent_length = 5; + } else if (_Scientific_exponent <= -10 || _Scientific_exponent >= 100) { // "e-10" or "e100" + _Scientific_exponent_length = 4; + } else if ((_Scientific_exponent > -10 && _Scientific_exponent < 0) || _Scientific_exponent >= 10) { // "e-9" or "e10" + _Scientific_exponent_length = 3; + } else { // "e1" + _Scientific_exponent_length = 2; + } + + // CHANGE_FOR_ERLANG we do not need the ternary as we did all the logic above + const uint32_t _Total_scientific_length = __olength + 1 +(__olength == 1) // digits + decimal point + possible 0 after decimal point + + _Scientific_exponent_length; // + scientific exponent + + // Print the decimal digits. + uint32_t __i = 0; + // We prefer 32-bit operations, even on 64-bit platforms. + // We have at most 17 digits, and uint32_t can store 9 digits. + // If __output doesn't fit into uint32_t, we cut off 8 digits, + // so the rest will fit into uint32_t. + // CHANGE_FOR_ERLANG we consider in this whole thing that memcopy use the same + // char has defined in the DIGIT_TABLE + // CHANGE_FOR_ERLANG __DIGIT_TABLE became DIGIT_TABLE + if ((__output >> 32) != 0) { + // Expensive 64-bit division. + const uint64_t __q = div1e8(__output); + uint32_t __output2 = (uint32_t) (__output) - 100000000 * (uint32_t) (__q); + __output = __q; + + const uint32_t __c = __output2 % 10000; + __output2 /= 10000; + const uint32_t __d = __output2 % 10000; + const uint32_t __c0 = (__c % 100) << 1; + const uint32_t __c1 = (__c / 100) << 1; + const uint32_t __d0 = (__d % 100) << 1; + const uint32_t __d1 = (__d / 100) << 1; + memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c0, 2); + memcpy(__result + __olength - __i - 3, DIGIT_TABLE + __c1, 2); + memcpy(__result + __olength - __i - 5, DIGIT_TABLE + __d0, 2); + memcpy(__result + __olength - __i - 7, DIGIT_TABLE + __d1, 2); + __i += 8; + } + uint32_t __output2 = (uint32_t) (__output); + while (__output2 >= 10000) { +#ifdef __clang__ // TRANSITION, LLVM-38217 + const uint32_t __c = __output2 - 10000 * (__output2 / 10000); +#else + const uint32_t __c = __output2 % 10000; +#endif + __output2 /= 10000; + const uint32_t __c0 = (__c % 100) << 1; + const uint32_t __c1 = (__c / 100) << 1; + memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c0, 2); + memcpy(__result + __olength - __i - 3, DIGIT_TABLE + __c1, 2); + __i += 4; + } + if (__output2 >= 100) { + const uint32_t __c = (__output2 % 100) << 1; + __output2 /= 100; + memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c, 2); + __i += 2; + } + if (__output2 >= 10) { + const uint32_t __c = __output2 << 1; + // We can't use memcpy here: the decimal dot goes between these two digits. + __result[2] = DIGIT_TABLE[__c + 1]; + __result[0] = DIGIT_TABLE[__c]; + } else { + __result[0] = (char) ('0' + __output2); + } + + // Print decimal point if needed. + uint32_t __index; + if (__olength > 1) { + __result[1] = '.'; + __index = __olength + 1; + } else { + // In erlang we _have_ to print the ".0" in the case this is an integer + __result[1] = '.'; + __result[2] = '0'; + __index = __olength + 2; + } + + // Print the exponent. + __result[__index++] = 'e'; + if (_Scientific_exponent < 0) { + __result[__index++] = '-'; + _Scientific_exponent = -_Scientific_exponent; + } + // CHANGE_FOR_ERLANG no else, as we do not print the positive sign on the exponent + + if (_Scientific_exponent >= 100) { + const int32_t __c = _Scientific_exponent % 10; + memcpy(__result + __index, DIGIT_TABLE + 2 * (_Scientific_exponent / 10), 2); + __result[__index + 2] = (char) ('0' + __c); + __index += 3; + } else if (_Scientific_exponent >= 10) { + // CHANGE_FOR_ERLANG we have to do this only if the exponent is larger than 10 + memcpy(__result + __index, DIGIT_TABLE + 2 * _Scientific_exponent, 2); + __index += 2; + } else { + // CHANGE_FOR_ERLANG we can have an exponent under 10, which is not handled by the table + // so we handle it here + __result[__index++] = (char) ('0' + _Scientific_exponent); + } + + // CHANGE_FOR_ERLANG we do not need the errc and we are only interested in + // returning the length, as it is what Ryu and erlang expect. We do add the + // sign as we did it here instead of adding it by default as in the STL + return _Total_scientific_length + sign; +} +// end of STL code, back to ryu + +static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent, + floating_decimal_64* const v) { + const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa; + const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS; + + if (e2 > 0) { + // f = m2 * 2^e2 >= 2^53 is an integer. + // Ignore this case for now. + return false; + } + + if (e2 < -52) { + // f < 1. + return false; + } + + // Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52: 1 <= f = m2 / 2^-e2 < 2^53. + // Test if the lower -e2 bits of the significand are 0, i.e. whether the fraction is 0. + const uint64_t mask = (1ull << -e2) - 1; + const uint64_t fraction = m2 & mask; + if (fraction != 0) { + return false; + } + + // f is an integer in the range [1, 2^53). + // Note: mantissa might contain trailing (decimal) 0's. + // Note: since 2^53 < 10^16, there is no need to adjust decimalLength17(). + v->mantissa = m2 >> -e2; + v->exponent = 0; + return true; +} + +int d2s_buffered_n(double f, char* result) { + // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. + const uint64_t bits = double_to_bits(f); + +#ifdef RYU_DEBUG + printf("IN="); + for (int32_t bit = 63; bit >= 0; --bit) { + printf("%d", (int) ((bits >> bit) & 1)); + } + printf("\n"); +#endif + + // Decode bits into sign, mantissa, and exponent. + const bool ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; + const uint64_t ieeeMantissa = bits & ((1ull << DOUBLE_MANTISSA_BITS) - 1); + const uint32_t ieeeExponent = (uint32_t) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1)); + // Case distinction; exit early for the easy cases. + if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) { + return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa); + } + + floating_decimal_64 v; + const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v); + if (isSmallInt) { + // For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros. + // For scientific notation we need to move these zeros into the exponent. + // (This is not needed for fixed-point notation, so it might be beneficial to trim + // trailing zeros in to_chars only if needed - once fixed-point notation output is implemented.) + for (;;) { + const uint64_t q = div10(v.mantissa); + const uint32_t r = ((uint32_t) v.mantissa) - 10 * ((uint32_t) q); + if (r != 0) { + break; + } + v.mantissa = q; + ++v.exponent; + } + } else { + v = d2d(ieeeMantissa, ieeeExponent); + } + + return to_chars(v, ieeeSign, result); +} + +void d2s_buffered(double f, char* result) { + const int index = d2s_buffered_n(f, result); + + // Terminate the string. + result[index] = '\0'; +} + +char* d2s(double f) { + char* const result = (char*) malloc(25); + d2s_buffered(f, result); + return result; +} diff --git a/erts/emulator/ryu/d2s_full_table.h b/erts/emulator/ryu/d2s_full_table.h new file mode 100644 index 000000000000..c8629eef1b2e --- /dev/null +++ b/erts/emulator/ryu/d2s_full_table.h @@ -0,0 +1,367 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +#ifndef RYU_D2S_FULL_TABLE_H +#define RYU_D2S_FULL_TABLE_H + +// These tables are generated by PrintDoubleLookupTable. +#define DOUBLE_POW5_INV_BITCOUNT 125 +#define DOUBLE_POW5_BITCOUNT 125 + +#define DOUBLE_POW5_INV_TABLE_SIZE 342 +#define DOUBLE_POW5_TABLE_SIZE 326 + +static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = { + { 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u }, + { 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u }, + { 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u }, + { 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u }, + { 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u }, + { 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u }, + { 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u }, + { 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u }, + { 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u }, + { 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u }, + { 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u }, + { 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u }, + { 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u }, + { 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u }, + { 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u }, + { 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u }, + { 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u }, + { 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u }, + { 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u }, + { 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u }, + { 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u }, + { 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u }, + { 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u }, + { 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u }, + { 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u }, + { 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u }, + { 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u }, + { 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u }, + { 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u }, + { 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u }, + { 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u }, + { 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u }, + { 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u }, + { 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u }, + { 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u }, + { 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u }, + { 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u }, + { 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u }, + { 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u }, + { 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u }, + { 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u }, + { 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u }, + { 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u }, + { 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u }, + { 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u }, + { 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u }, + { 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u }, + { 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u }, + { 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u }, + { 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u }, + { 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u }, + { 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u }, + { 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u }, + { 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u }, + { 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u }, + { 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u }, + { 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u }, + { 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u }, + { 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u }, + { 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u }, + { 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u }, + { 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u }, + { 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u }, + { 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u }, + { 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u }, + { 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u }, + { 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u }, + { 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u }, + { 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u }, + { 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u }, + { 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u }, + { 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u }, + { 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u }, + { 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u }, + { 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u }, + { 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u }, + { 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u }, + { 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u }, + { 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u }, + { 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u }, + { 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u }, + { 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u }, + { 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u }, + { 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u }, + { 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u }, + { 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u }, + { 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u }, + { 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u }, + { 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u }, + { 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u }, + { 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u }, + { 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u }, + { 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u }, + { 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u }, + { 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u }, + { 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u }, + { 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u }, + { 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u }, + { 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u }, + { 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u }, + { 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u }, + { 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u }, + { 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u }, + { 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u }, + { 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u }, + { 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u }, + { 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u }, + { 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u }, + { 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u }, + { 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u }, + { 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u }, + { 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u }, + { 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u }, + { 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u }, + { 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u }, + { 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u }, + { 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u }, + { 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u }, + { 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u }, + { 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u }, + { 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u }, + { 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u }, + { 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u }, + { 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u }, + { 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u }, + { 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u }, + { 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u }, + { 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u }, + { 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u }, + { 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u }, + { 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u }, + { 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u }, + { 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u }, + { 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u }, + { 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u }, + { 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u }, + { 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u }, + { 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u }, + { 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u }, + { 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u }, + { 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u }, + { 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u }, + { 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u }, + { 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u }, + { 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u }, + { 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u }, + { 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u }, + { 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u }, + { 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u }, + { 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u }, + { 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u }, + { 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u }, + { 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u }, + { 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u }, + { 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u }, + { 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u }, + { 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u }, + { 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u }, + { 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u }, + { 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u }, + { 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u }, + { 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u }, + { 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u }, + { 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u }, + { 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u }, + { 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u }, + { 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u }, + { 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u }, + { 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u }, + { 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u }, + { 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u } +}; + +static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = { + { 0u, 1152921504606846976u }, { 0u, 1441151880758558720u }, + { 0u, 1801439850948198400u }, { 0u, 2251799813685248000u }, + { 0u, 1407374883553280000u }, { 0u, 1759218604441600000u }, + { 0u, 2199023255552000000u }, { 0u, 1374389534720000000u }, + { 0u, 1717986918400000000u }, { 0u, 2147483648000000000u }, + { 0u, 1342177280000000000u }, { 0u, 1677721600000000000u }, + { 0u, 2097152000000000000u }, { 0u, 1310720000000000000u }, + { 0u, 1638400000000000000u }, { 0u, 2048000000000000000u }, + { 0u, 1280000000000000000u }, { 0u, 1600000000000000000u }, + { 0u, 2000000000000000000u }, { 0u, 1250000000000000000u }, + { 0u, 1562500000000000000u }, { 0u, 1953125000000000000u }, + { 0u, 1220703125000000000u }, { 0u, 1525878906250000000u }, + { 0u, 1907348632812500000u }, { 0u, 1192092895507812500u }, + { 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u }, + { 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u }, + { 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u }, + { 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u }, + { 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u }, + { 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u }, + { 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u }, + { 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u }, + { 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u }, + { 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u }, + { 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u }, + { 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u }, + { 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u }, + { 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u }, + { 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u }, + { 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u }, + { 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u }, + { 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u }, + { 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u }, + { 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u }, + { 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u }, + { 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u }, + { 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u }, + { 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u }, + { 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u }, + { 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u }, + { 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u }, + { 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u }, + { 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u }, + { 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u }, + { 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u }, + { 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u }, + { 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u }, + { 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u }, + { 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u }, + { 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u }, + { 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u }, + { 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u }, + { 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u }, + { 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u }, + { 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u }, + { 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u }, + { 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u }, + { 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u }, + { 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u }, + { 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u }, + { 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u }, + { 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u }, + { 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u }, + { 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u }, + { 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u }, + { 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u }, + { 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u }, + { 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u }, + { 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u }, + { 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u }, + { 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u }, + { 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u }, + { 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u }, + { 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u }, + { 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u }, + { 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u }, + { 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u }, + { 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u }, + { 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u }, + { 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u }, + { 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u }, + { 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u }, + { 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u }, + { 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u }, + { 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u }, + { 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u }, + { 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u }, + { 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u }, + { 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u }, + { 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u }, + { 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u }, + { 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u }, + { 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u }, + { 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u }, + { 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u }, + { 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u }, + { 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u }, + { 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u }, + { 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u }, + { 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u }, + { 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u }, + { 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u }, + { 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u }, + { 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u }, + { 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u }, + { 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u }, + { 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u }, + { 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u }, + { 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u }, + { 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u }, + { 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u }, + { 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u }, + { 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u }, + { 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u }, + { 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u }, + { 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u }, + { 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u }, + { 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u }, + { 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u }, + { 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u }, + { 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u }, + { 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u }, + { 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u }, + { 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u }, + { 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u }, + { 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u }, + { 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u }, + { 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u }, + { 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u }, + { 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u }, + { 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u }, + { 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u }, + { 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u }, + { 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u }, + { 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u }, + { 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u }, + { 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u }, + { 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u }, + { 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u }, + { 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u }, + { 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u }, + { 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u }, + { 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u }, + { 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u }, + { 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u }, + { 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u }, + { 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u }, + { 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u }, + { 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u }, + { 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u }, + { 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u }, + { 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u }, + { 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u }, + { 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u }, + { 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u }, + { 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u }, + { 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u }, + { 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u }, + { 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u }, + { 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u }, + { 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u }, + { 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u }, + { 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u }, + { 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u } +}; + +#endif // RYU_D2S_FULL_TABLE_H diff --git a/erts/emulator/ryu/d2s_intrinsics.h b/erts/emulator/ryu/d2s_intrinsics.h new file mode 100644 index 000000000000..77388b308821 --- /dev/null +++ b/erts/emulator/ryu/d2s_intrinsics.h @@ -0,0 +1,358 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +#ifndef RYU_D2S_INTRINSICS_H +#define RYU_D2S_INTRINSICS_H + +#include +#include + +// Defines RYU_32_BIT_PLATFORM if applicable. +#include "common.h" + +// ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined. +// Let's do the same for now. +#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) +#define HAS_UINT128 +#elif defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64) +#define HAS_64_BIT_INTRINSICS +#endif + +#if defined(HAS_UINT128) +typedef __uint128_t uint128_t; +#endif + +#if defined(HAS_64_BIT_INTRINSICS) + +#include + +static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) { + return _umul128(a, b, productHi); +} + +// Returns the lower 64 bits of (hi*2^64 + lo) >> dist, with 0 < dist < 64. +static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) { + // For the __shiftright128 intrinsic, the shift value is always + // modulo 64. + // In the current implementation of the double-precision version + // of Ryu, the shift value is always < 64. (In the case + // RYU_OPTIMIZE_SIZE == 0, the shift value is in the range [49, 58]. + // Otherwise in the range [2, 59].) + // However, this function is now also called by s2d, which requires supporting + // the larger shift range (TODO: what is the actual range?). + // Check this here in case a future change requires larger shift + // values. In this case this function needs to be adjusted. + assert(dist < 64); + return __shiftright128(lo, hi, (unsigned char) dist); +} + +#else // defined(HAS_64_BIT_INTRINSICS) + +static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) { + // The casts here help MSVC to avoid calls to the __allmul library function. + const uint32_t aLo = (uint32_t)a; + const uint32_t aHi = (uint32_t)(a >> 32); + const uint32_t bLo = (uint32_t)b; + const uint32_t bHi = (uint32_t)(b >> 32); + + const uint64_t b00 = (uint64_t)aLo * bLo; + const uint64_t b01 = (uint64_t)aLo * bHi; + const uint64_t b10 = (uint64_t)aHi * bLo; + const uint64_t b11 = (uint64_t)aHi * bHi; + + const uint32_t b00Lo = (uint32_t)b00; + const uint32_t b00Hi = (uint32_t)(b00 >> 32); + + const uint64_t mid1 = b10 + b00Hi; + const uint32_t mid1Lo = (uint32_t)(mid1); + const uint32_t mid1Hi = (uint32_t)(mid1 >> 32); + + const uint64_t mid2 = b01 + mid1Lo; + const uint32_t mid2Lo = (uint32_t)(mid2); + const uint32_t mid2Hi = (uint32_t)(mid2 >> 32); + + const uint64_t pHi = b11 + mid1Hi + mid2Hi; + const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo; + + *productHi = pHi; + return pLo; +} + +static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) { + // We don't need to handle the case dist >= 64 here (see above). + assert(dist < 64); + assert(dist > 0); + return (hi << (64 - dist)) | (lo >> dist); +} + +#endif // defined(HAS_64_BIT_INTRINSICS) + +#if defined(RYU_32_BIT_PLATFORM) + +// Returns the high 64 bits of the 128-bit product of a and b. +static inline uint64_t umulh(const uint64_t a, const uint64_t b) { + // Reuse the umul128 implementation. + // Optimizers will likely eliminate the instructions used to compute the + // low part of the product. + uint64_t hi; + umul128(a, b, &hi); + return hi; +} + +// On 32-bit platforms, compilers typically generate calls to library +// functions for 64-bit divisions, even if the divisor is a constant. +// +// E.g.: +// https://bugs.llvm.org/show_bug.cgi?id=37932 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17958 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37443 +// +// The functions here perform division-by-constant using multiplications +// in the same way as 64-bit compilers would do. +// +// NB: +// The multipliers and shift values are the ones generated by clang x64 +// for expressions like x/5, x/10, etc. + +static inline uint64_t div5(const uint64_t x) { + return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2; +} + +static inline uint64_t div10(const uint64_t x) { + return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3; +} + +static inline uint64_t div100(const uint64_t x) { + return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2; +} + +static inline uint64_t div1e8(const uint64_t x) { + return umulh(x, 0xABCC77118461CEFDu) >> 26; +} + +static inline uint64_t div1e9(const uint64_t x) { + return umulh(x >> 9, 0x44B82FA09B5A53u) >> 11; +} + +static inline uint32_t mod1e9(const uint64_t x) { + // Avoid 64-bit math as much as possible. + // Returning (uint32_t) (x - 1000000000 * div1e9(x)) would + // perform 32x64-bit multiplication and 64-bit subtraction. + // x and 1000000000 * div1e9(x) are guaranteed to differ by + // less than 10^9, so their highest 32 bits must be identical, + // so we can truncate both sides to uint32_t before subtracting. + // We can also simplify (uint32_t) (1000000000 * div1e9(x)). + // We can truncate before multiplying instead of after, as multiplying + // the highest 32 bits of div1e9(x) can't affect the lowest 32 bits. + return ((uint32_t) x) - 1000000000 * ((uint32_t) div1e9(x)); +} + +#else // defined(RYU_32_BIT_PLATFORM) + +static inline uint64_t div5(const uint64_t x) { + return x / 5; +} + +static inline uint64_t div10(const uint64_t x) { + return x / 10; +} + +static inline uint64_t div100(const uint64_t x) { + return x / 100; +} + +static inline uint64_t div1e8(const uint64_t x) { + return x / 100000000; +} + +static inline uint64_t div1e9(const uint64_t x) { + return x / 1000000000; +} + +static inline uint32_t mod1e9(const uint64_t x) { + return (uint32_t) (x - 1000000000 * div1e9(x)); +} + +#endif // defined(RYU_32_BIT_PLATFORM) + +static inline uint32_t pow5Factor(uint64_t value) { + uint32_t count = 0; + for (;;) { + assert(value != 0); + const uint64_t q = div5(value); + const uint32_t r = ((uint32_t) value) - 5 * ((uint32_t) q); + if (r != 0) { + break; + } + value = q; + ++count; + } + return count; +} + +// Returns true if value is divisible by 5^p. +static inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) { + // I tried a case distinction on p, but there was no performance difference. + return pow5Factor(value) >= p; +} + +// Returns true if value is divisible by 2^p. +static inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) { + assert(value != 0); + assert(p < 64); + // __builtin_ctzll doesn't appear to be faster here. + return (value & ((1ull << p) - 1)) == 0; +} + +// We need a 64x128-bit multiplication and a subsequent 128-bit shift. +// Multiplication: +// The 64-bit factor is variable and passed in, the 128-bit factor comes +// from a lookup table. We know that the 64-bit factor only has 55 +// significant bits (i.e., the 9 topmost bits are zeros). The 128-bit +// factor only has 124 significant bits (i.e., the 4 topmost bits are +// zeros). +// Shift: +// In principle, the multiplication result requires 55 + 124 = 179 bits to +// represent. However, we then shift this value to the right by j, which is +// at least j >= 115, so the result is guaranteed to fit into 179 - 115 = 64 +// bits. This means that we only need the topmost 64 significant bits of +// the 64x128-bit multiplication. +// +// There are several ways to do this: +// 1. Best case: the compiler exposes a 128-bit type. +// We perform two 64x64-bit multiplications, add the higher 64 bits of the +// lower result to the higher result, and shift by j - 64 bits. +// +// We explicitly cast from 64-bit to 128-bit, so the compiler can tell +// that these are only 64-bit inputs, and can map these to the best +// possible sequence of assembly instructions. +// x64 machines happen to have matching assembly instructions for +// 64x64-bit multiplications and 128-bit shifts. +// +// 2. Second best case: the compiler exposes intrinsics for the x64 assembly +// instructions mentioned in 1. +// +// 3. We only have 64x64 bit instructions that return the lower 64 bits of +// the result, i.e., we have to use plain C. +// Our inputs are less than the full width, so we have three options: +// a. Ignore this fact and just implement the intrinsics manually. +// b. Split both into 31-bit pieces, which guarantees no internal overflow, +// but requires extra work upfront (unless we change the lookup table). +// c. Split only the first factor into 31-bit pieces, which also guarantees +// no internal overflow, but requires extra work since the intermediate +// results are not perfectly aligned. +#if defined(HAS_UINT128) + +// Best case: use 128-bit type. +static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) { + const uint128_t b0 = ((uint128_t) m) * mul[0]; + const uint128_t b2 = ((uint128_t) m) * mul[1]; + return (uint64_t) (((b0 >> 64) + b2) >> (j - 64)); +} + +static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j, + uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) { +// m <<= 2; +// uint128_t b0 = ((uint128_t) m) * mul[0]; // 0 +// uint128_t b2 = ((uint128_t) m) * mul[1]; // 64 +// +// uint128_t hi = (b0 >> 64) + b2; +// uint128_t lo = b0 & 0xffffffffffffffffull; +// uint128_t factor = (((uint128_t) mul[1]) << 64) + mul[0]; +// uint128_t vpLo = lo + (factor << 1); +// *vp = (uint64_t) ((hi + (vpLo >> 64)) >> (j - 64)); +// uint128_t vmLo = lo - (factor << mmShift); +// *vm = (uint64_t) ((hi + (vmLo >> 64) - (((uint128_t) 1ull) << 64)) >> (j - 64)); +// return (uint64_t) (hi >> (j - 64)); + *vp = mulShift64(4 * m + 2, mul, j); + *vm = mulShift64(4 * m - 1 - mmShift, mul, j); + return mulShift64(4 * m, mul, j); +} + +#elif defined(HAS_64_BIT_INTRINSICS) + +static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) { + // m is maximum 55 bits + uint64_t high1; // 128 + const uint64_t low1 = umul128(m, mul[1], &high1); // 64 + uint64_t high0; // 64 + umul128(m, mul[0], &high0); // 0 + const uint64_t sum = high0 + low1; + if (sum < high0) { + ++high1; // overflow into high1 + } + return shiftright128(sum, high1, j - 64); +} + +static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j, + uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) { + *vp = mulShift64(4 * m + 2, mul, j); + *vm = mulShift64(4 * m - 1 - mmShift, mul, j); + return mulShift64(4 * m, mul, j); +} + +#else // !defined(HAS_UINT128) && !defined(HAS_64_BIT_INTRINSICS) + +static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) { + // m is maximum 55 bits + uint64_t high1; // 128 + const uint64_t low1 = umul128(m, mul[1], &high1); // 64 + uint64_t high0; // 64 + umul128(m, mul[0], &high0); // 0 + const uint64_t sum = high0 + low1; + if (sum < high0) { + ++high1; // overflow into high1 + } + return shiftright128(sum, high1, j - 64); +} + +// This is faster if we don't have a 64x64->128-bit multiplication. +static inline uint64_t mulShiftAll64(uint64_t m, const uint64_t* const mul, const int32_t j, + uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) { + m <<= 1; + // m is maximum 55 bits + uint64_t tmp; + const uint64_t lo = umul128(m, mul[0], &tmp); + uint64_t hi; + const uint64_t mid = tmp + umul128(m, mul[1], &hi); + hi += mid < tmp; // overflow into hi + + const uint64_t lo2 = lo + mul[0]; + const uint64_t mid2 = mid + mul[1] + (lo2 < lo); + const uint64_t hi2 = hi + (mid2 < mid); + *vp = shiftright128(mid2, hi2, (uint32_t) (j - 64 - 1)); + + if (mmShift == 1) { + const uint64_t lo3 = lo - mul[0]; + const uint64_t mid3 = mid - mul[1] - (lo3 > lo); + const uint64_t hi3 = hi - (mid3 > mid); + *vm = shiftright128(mid3, hi3, (uint32_t) (j - 64 - 1)); + } else { + const uint64_t lo3 = lo + lo; + const uint64_t mid3 = mid + mid + (lo3 < lo); + const uint64_t hi3 = hi + hi + (mid3 < mid); + const uint64_t lo4 = lo3 - mul[0]; + const uint64_t mid4 = mid3 - mul[1] - (lo4 > lo3); + const uint64_t hi4 = hi3 - (mid4 > mid3); + *vm = shiftright128(mid4, hi4, (uint32_t) (j - 64)); + } + + return shiftright128(mid, hi, (uint32_t) (j - 64 - 1)); +} + +#endif // HAS_64_BIT_INTRINSICS + +#endif // RYU_D2S_INTRINSICS_H diff --git a/erts/emulator/ryu/digit_table.h b/erts/emulator/ryu/digit_table.h new file mode 100644 index 000000000000..02219bc6d53b --- /dev/null +++ b/erts/emulator/ryu/digit_table.h @@ -0,0 +1,35 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +#ifndef RYU_DIGIT_TABLE_H +#define RYU_DIGIT_TABLE_H + +// A table of all two-digit numbers. This is used to speed up decimal digit +// generation by copying pairs of digits into the final output. +static const char DIGIT_TABLE[200] = { + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' +}; + +#endif // RYU_DIGIT_TABLE_H diff --git a/erts/emulator/ryu/ryu.h b/erts/emulator/ryu/ryu.h new file mode 100644 index 000000000000..9439ada7cc77 --- /dev/null +++ b/erts/emulator/ryu/ryu.h @@ -0,0 +1,36 @@ +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +#ifndef RYU_H +#define RYU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int d2s_buffered_n(double f, char* result); +void d2s_buffered(double f, char* result); +char* d2s(double f); + +//CHANGE_FOR_ERLANG we dropped all the other functions as not used by us + +#ifdef __cplusplus +} +#endif + +#endif // RYU_H diff --git a/erts/emulator/ryu/ryu.mk b/erts/emulator/ryu/ryu.mk new file mode 100644 index 000000000000..524618f446ca --- /dev/null +++ b/erts/emulator/ryu/ryu.mk @@ -0,0 +1,57 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode +# ---------------------------------------------------- +# Make include file for Ryu +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2011-2021. 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% +# +# ---------------------------------------------------- + +RYU_FILES = d2s + +RYU_OBJDIR = $(ERL_TOP)/erts/emulator/ryu/obj/$(TARGET)/$(TYPE) +RYU_OBJS = $(RYU_FILES:%=$(RYU_OBJDIR)/%.o) +RYU_DIR = $(ERL_TOP)/erts/emulator/ryu + +RYU_SRC = $(RYU_FILES:%=ryu/%.c) + +ifeq ($(TARGET), win32) +RYU_LIBRARY = $(RYU_OBJDIR)/ryu.lib +else +RYU_LIBRARY = $(RYU_OBJDIR)/libryu.a +endif + +ifeq ($(TARGET), win32) +RYU_CFLAGS = $(CFLAGS) +else +RYU_CFLAGS = $(filter-out -Wdeclaration-after-statement,$(CFLAGS)) +endif + +ifeq ($(TARGET), win32) +$(RYU_LIBRARY): $(RYU_OBJS) + $(V_AR) -out:$@ $(RYU_OBJS) +else +$(RYU_LIBRARY): $(RYU_OBJS) + $(V_AR) $(ARFLAGS) $@ $(RYU_OBJS) + -@ ($(RANLIB) $@ || true) 2>/dev/null +endif + + + +$(RYU_OBJDIR)/%.o: ryu/%.c + $(V_CC) -c $(RYU_CFLAGS) -o $@ $< diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index 5c1f755c4580..f821cca9c854 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2021. All Rights Reserved. + * Copyright Ericsson AB 2006-2023. 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. @@ -93,7 +93,7 @@ typedef enum { #endif ERTS_EV_FLAG_WANT_ERROR = 0x10, /* ERL_NIF_SELECT_ERROR turned on */ - /* Combinations */ + /* Combinations, defined only to be displayed by debugger (gdb) */ ERTS_EV_FLAG_USED_FALLBACK = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_FALLBACK, ERTS_EV_FLAG_USED_SCHEDULER = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_SCHEDULER, ERTS_EV_FLAG_USED_IN_SCHEDULER = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER, @@ -101,16 +101,25 @@ typedef enum { ERTS_EV_FLAG_UNUSED_IN_SCHEDULER = ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER } EventStateFlags; -#define flag2str(flags) \ - ((flags) == ERTS_EV_FLAG_CLEAR ? "CLEAR" : \ - ((flags) == ERTS_EV_FLAG_USED ? "USED" : \ - ((flags) == ERTS_EV_FLAG_FALLBACK ? "FLBK" : \ - ((flags) == ERTS_EV_FLAG_USED_FALLBACK ? "USED|FLBK" : \ - ((flags) == ERTS_EV_FLAG_USED_SCHEDULER ? "USED|SCHD" : \ - ((flags) == ERTS_EV_FLAG_UNUSED_SCHEDULER ? "SCHD" : \ - ((flags) == ERTS_EV_FLAG_USED_IN_SCHEDULER ? "USED|IN_SCHD" : \ - ((flags) == ERTS_EV_FLAG_UNUSED_IN_SCHEDULER ? "IN_SCHD" : \ - "ERROR")))))))) + +static const char* event_state_flag_to_str(EventStateFlags f) +{ + switch ((int)f) { + case ERTS_EV_FLAG_CLEAR: return "CLEAR"; + case ERTS_EV_FLAG_USED: return "USED"; + case ERTS_EV_FLAG_FALLBACK: return "FLBK"; + case ERTS_EV_FLAG_FALLBACK | ERTS_EV_FLAG_USED: return "USED|FLBK"; + +#if ERTS_POLL_USE_SCHEDULER_POLLING + case ERTS_EV_FLAG_SCHEDULER: return "SCHD"; + case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_USED: return "USED|SCHD"; + case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER: return "IN_SCHD"; + case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER + | ERTS_EV_FLAG_USED: return "USED|IN_SCHD"; +#endif + default: return "ERROR"; + } +} /* How many events that can be handled at once by one erts_poll_wait call */ #define ERTS_CHECK_IO_POLL_RES_LEN 512 @@ -137,7 +146,7 @@ static ErtsPollThread *psiv; static ErtsPollSet *flbk_pollset; #endif #if ERTS_POLL_USE_SCHEDULER_POLLING -static ErtsPollSet *sched_pollset; +ErtsPollSet *sched_pollset; #endif typedef struct { @@ -409,7 +418,7 @@ static ERTS_INLINE ErtsPollSet * get_scheduler_pollset(ErtsSysFdType fd) { #if ERTS_POLL_USE_SCHEDULER_POLLING - return sched_pollset; + return sched_pollset ? sched_pollset : get_pollset(fd); #else return get_pollset(fd); #endif @@ -488,16 +497,18 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type, active_events = state->active_events; - if (!(state->flags & ERTS_EV_FLAG_IN_SCHEDULER) || type == ERTS_PORT_TASK_OUTPUT) { + if (state->type == ERTS_EV_TYPE_DRV_SEL) { switch (type) { case ERTS_PORT_TASK_INPUT: DEBUG_PRINT_FD("executed ready_input", state); - ASSERT(!(state->active_events & ERTS_POLL_EV_IN)); - if (state->events & ERTS_POLL_EV_IN) { + if (!(state->flags & ERTS_EV_FLAG_IN_SCHEDULER) + && !(active_events & ERTS_POLL_EV_IN) + && (state->events & ERTS_POLL_EV_IN)) { + active_events |= ERTS_POLL_EV_IN; - if (state->count > 10 && ERTS_POLL_USE_SCHEDULER_POLLING) { + if (state->count > 10 && erts_sched_poll_enabled()) { if (!(state->flags & ERTS_EV_FLAG_SCHEDULER)) op = ERTS_POLL_OP_ADD; state->flags |= ERTS_EV_FLAG_IN_SCHEDULER|ERTS_EV_FLAG_SCHEDULER; @@ -505,7 +516,7 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type, DEBUG_PRINT_FD("moving to scheduler ps", state); } else new_events = active_events; - if (!(state->flags & ERTS_EV_FLAG_FALLBACK) && ERTS_POLL_USE_SCHEDULER_POLLING) + if (!(state->flags & ERTS_EV_FLAG_FALLBACK) && erts_sched_poll_enabled()) state->count++; } break; @@ -513,8 +524,9 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type, DEBUG_PRINT_FD("executed ready_output", state); - ASSERT(!(state->active_events & ERTS_POLL_EV_OUT)); - if (state->events & ERTS_POLL_EV_OUT) { + if (!(active_events & ERTS_POLL_EV_OUT) + && (state->events & ERTS_POLL_EV_OUT)) { + active_events |= ERTS_POLL_EV_OUT; if (state->flags & ERTS_EV_FLAG_IN_SCHEDULER && active_events & ERTS_POLL_EV_IN) new_events = ERTS_POLL_EV_OUT; @@ -527,7 +539,8 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type, break; } - if (state->active_events != active_events && new_events) { + if (state->active_events != active_events) { + ASSERT(new_events); state->active_events = active_events; new_events = erts_io_control(state, op, new_events); } @@ -1791,7 +1804,7 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time, int poll_only select/deselect in rapid succession. */ revents &= state->active_events | ERTS_POLL_EV_NVAL; - if (psi->ps != get_scheduler_pollset(fd) || !ERTS_POLL_USE_SCHEDULER_POLLING) { + if (psi->ps != get_scheduler_pollset(fd) || !erts_sched_poll_enabled()) { ErtsPollEvents reactive_events; state->active_events &= ~revents; @@ -1909,6 +1922,7 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time, int poll_only /* fallthrough */ case ERTS_EV_TYPE_NONE: /* Deselected ... */ case_ERTS_EV_TYPE_NONE: + state->flags &= ~ERTS_EV_FLAG_FALLBACK; ASSERT(!state->events && !state->active_events && !state->flags); check_fd_cleanup(state, &free_select, &free_nif); break; @@ -2109,7 +2123,7 @@ get_arg(char* rest, char** argv, int* ip) } static void -parse_args(int *argc, char **argv, int concurrent_waiters) +parse_args(int *argc, char **argv, int concurrent_waiters, int* use_sched_poll) { int i = 0, j; int no_pollsets = 0, no_poll_threads = 0, @@ -2151,8 +2165,16 @@ parse_args(int *argc, char **argv, int concurrent_waiters) erts_fprintf(stderr,"bad I/O pollset percentage number: %s\n", arg); erts_usage(); } - } else { - break; + } else if (sys_strcmp(argv[i]+2, "Os") == 0) { + const char *arg = get_arg(argv[i]+4, argv, &i); + if (sys_strcmp(arg, "true") == 0) { + *use_sched_poll = 1; + } else if (sys_strcmp(arg, "false") == 0) { + *use_sched_poll = 0; + } else { + erts_fprintf(stderr,"bad +IOs boolean argument: %s\n", arg); + erts_usage(); + } } break; } @@ -2220,6 +2242,8 @@ void erts_init_check_io(int *argc, char **argv) { int j, concurrent_waiters, no_poll_threads; + int use_sched_poll = ERTS_POLL_USE_SCHEDULER_POLLING; + ERTS_CT_ASSERT((INT_MIN & (ERL_NIF_SELECT_STOP_CALLED | ERL_NIF_SELECT_STOP_SCHEDULED | ERL_NIF_SELECT_INVALID_EVENT | @@ -2231,7 +2255,7 @@ erts_init_check_io(int *argc, char **argv) erts_poll_init_flbk(NULL); #endif - parse_args(argc, argv, concurrent_waiters); + parse_args(argc, argv, concurrent_waiters, &use_sched_poll); /* Create the actual pollsets */ pollsetv = erts_alloc(ERTS_ALC_T_POLLSET,sizeof(ErtsPollSet *) * erts_no_pollsets); @@ -2243,10 +2267,16 @@ erts_init_check_io(int *argc, char **argv) j = -1; + if (use_sched_poll) { #if ERTS_POLL_USE_SCHEDULER_POLLING - sched_pollset = erts_poll_create_pollset(j--); - no_poll_threads++; + sched_pollset = erts_poll_create_pollset(j--); + ASSERT(erts_sched_poll_enabled()); + no_poll_threads++; +#else + erts_fprintf(stderr,"+IOs true: not supported by this emulator\n"); + erts_usage(); #endif + } #if ERTS_POLL_USE_FALLBACK flbk_pollset = erts_poll_create_pollset_flbk(j--); @@ -2263,13 +2293,13 @@ erts_init_check_io(int *argc, char **argv) psiv++; #endif -#if ERTS_POLL_USE_SCHEDULER_POLLING - psiv[0].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN; - psiv[0].pollres = erts_alloc(ERTS_ALC_T_POLLSET, - sizeof(ErtsPollResFd) * ERTS_CHECK_IO_POLL_RES_LEN); - psiv[0].ps = get_scheduler_pollset(0); - psiv++; -#endif + if (erts_sched_poll_enabled()) { + psiv[0].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN; + psiv[0].pollres = erts_alloc(ERTS_ALC_T_POLLSET, + sizeof(ErtsPollResFd) * ERTS_CHECK_IO_POLL_RES_LEN); + psiv[0].ps = get_scheduler_pollset(0); + psiv++; + } for (j = 0; j < erts_no_poll_threads; j++) { psiv[j].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN; @@ -2327,12 +2357,12 @@ erts_check_io_size(void) erts_poll_info(get_fallback_pollset(), &pi); res += pi.memory_size; #endif - #if ERTS_POLL_USE_SCHEDULER_POLLING - erts_poll_info(get_scheduler_pollset(0), &pi); - res += pi.memory_size; + if (erts_sched_poll_enabled()) { + erts_poll_info(sched_pollset, &pi); + res += pi.memory_size; + } #endif - for (i = 0; i < erts_no_pollsets; i++) { erts_poll_info(pollsetv[i], &pi); res += pi.memory_size; @@ -2361,9 +2391,9 @@ erts_check_io_info(void *proc) Uint sz, *szp, *hp, **hpp; ErtsPollInfo *piv; Sint i, j = 0, len; - int no_pollsets = erts_no_pollsets + ERTS_POLL_USE_FALLBACK + ERTS_POLL_USE_SCHEDULER_POLLING; + int no_pollsets = erts_no_pollsets + ERTS_POLL_USE_FALLBACK + erts_sched_poll_enabled(); ERTS_CT_ASSERT(ERTS_POLL_USE_FALLBACK == 0 || ERTS_POLL_USE_FALLBACK == 1); - ERTS_CT_ASSERT(ERTS_POLL_USE_SCHEDULER_POLLING == 0 || ERTS_POLL_USE_SCHEDULER_POLLING == 1); + ERTS_ASSERT(erts_sched_poll_enabled() == 0 || erts_sched_poll_enabled() == 1); piv = erts_alloc(ERTS_ALC_T_TMP, sizeof(ErtsPollInfo) * no_pollsets); @@ -2373,14 +2403,14 @@ erts_check_io_info(void *proc) piv[0].active_fds = 0; piv++; #endif - #if ERTS_POLL_USE_SCHEDULER_POLLING - erts_poll_info(get_scheduler_pollset(0), &piv[0]); - piv[0].poll_threads = 0; - piv[0].active_fds = 0; - piv++; + if (erts_sched_poll_enabled()) { + erts_poll_info(sched_pollset, &piv[0]); + piv[0].poll_threads = 0; + piv[0].active_fds = 0; + piv++; + } #endif - for (j = 0; j < erts_no_pollsets; j++) { erts_poll_info(pollsetv[j], &piv[j]); piv[j].active_fds = 0; @@ -2429,7 +2459,7 @@ erts_check_io_info(void *proc) sz = 0; piv -= ERTS_POLL_USE_FALLBACK; - piv -= ERTS_POLL_USE_SCHEDULER_POLLING; + piv -= erts_sched_poll_enabled(); bld_it: @@ -2534,7 +2564,11 @@ print_events(erts_dsprintf_buf_t *dsbufp, ErtsPollEvents ev) static ERTS_INLINE void print_flags(erts_dsprintf_buf_t *dsbufp, EventStateFlags f) { - erts_dsprintf(dsbufp, "%s", flag2str(f)); + if (f & ERTS_EV_FLAG_WANT_ERROR) { + erts_dsprintf(dsbufp, "WANTERR|"); + f &= ~ERTS_EV_FLAG_WANT_ERROR; + } + erts_dsprintf(dsbufp, "%s", event_state_flag_to_str(f)); } #ifdef DEBUG_PRINT_MODE @@ -2680,9 +2714,17 @@ static int erts_debug_print_checkio_state(erts_dsprintf_buf_t *dsbufp, err = 1; } else { - ErtsPollEvents ev = cio_events; - if (ev != ep_events && ep_events != ERTS_POLL_EV_NONE) - err = 1; + if (ep_events != ERTS_POLL_EV_NONE) { + if (!ERTS_POLL_USE_KERNEL_POLL + || (!(state->flags & (ERTS_EV_FLAG_SCHEDULER|ERTS_EV_FLAG_FALLBACK)) + && ((cio_events ^ ep_events) & ep_events) != 0)) { + err = 1; + } + /* else: Kernel poll with oneshot (used by poller threads) + * may cause a race where an event just triggered and + * thereby was cleared in the pollset (ep_events). + */ + } erts_dsprintf(dsbufp, "cio_ev="); print_events(dsbufp, cio_events); erts_dsprintf(dsbufp, " ep_ev="); @@ -2898,18 +2940,19 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip) } #endif #if ERTS_POLL_USE_SCHEDULER_POLLING - erts_dsprintf(dsbufp, "--- fds in scheduler pollset ----------------------------\n"); - erts_poll_get_selected_events(get_scheduler_pollset(0), counters.epep, - drv_ev_state.max_fds); - for (fd = 0; fd < len; fd++) { - if (drv_ev_state.v[fd].flags & ERTS_EV_FLAG_SCHEDULER) { - if (drv_ev_state.v[fd].events && drv_ev_state.v[fd].events != ERTS_POLL_EV_NONE) - counters.epep[fd] &= ~ERTS_POLL_EV_OUT; - doit_erts_check_io_debug(&drv_ev_state.v[fd], &counters, dsbufp); + if (erts_sched_poll_enabled()) { + erts_dsprintf(dsbufp, "--- fds in scheduler pollset ----------------------------\n"); + erts_poll_get_selected_events(sched_pollset, counters.epep, + drv_ev_state.max_fds); + for (fd = 0; fd < len; fd++) { + if (drv_ev_state.v[fd].flags & ERTS_EV_FLAG_SCHEDULER) { + if (drv_ev_state.v[fd].events && drv_ev_state.v[fd].events != ERTS_POLL_EV_NONE) + counters.epep[fd] &= ~ERTS_POLL_EV_OUT; + doit_erts_check_io_debug(&drv_ev_state.v[fd], &counters, dsbufp); + } } } #endif - erts_dsprintf(dsbufp, "--- fds in pollset --------------------------------------\n"); for (i = 0; i < erts_no_pollsets; i++) { @@ -2921,6 +2964,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip) && get_pollset_id(fd) == i) { if (counters.epep[fd] != ERTS_POLL_EV_NONE && drv_ev_state.v[fd].flags & ERTS_EV_FLAG_IN_SCHEDULER) { + ERTS_ASSERT(erts_sched_poll_enabled()); /* We add the in flag if it is enabled in the scheduler pollset and get_selected_events works on the platform */ counters.epep[fd] |= ERTS_POLL_EV_IN; @@ -2929,6 +2973,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip) } } } + for (fd = len ; fd < drv_ev_state.max_fds; fd++) { null_des.fd = fd; doit_erts_check_io_debug(&null_des, &counters, dsbufp); @@ -2955,6 +3000,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip) erts_dsprintf(dsbufp, "internal fds=%d\n", counters.internal_fds); #endif erts_dsprintf(dsbufp, "---------------------------------------------------------\n"); + erts_send_error_to_logger_nogl(dsbufp); #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS erts_free(ERTS_ALC_T_TMP, (void *) counters.epep); diff --git a/erts/emulator/sys/common/erl_check_io.h b/erts/emulator/sys/common/erl_check_io.h index b96f4f960981..d44b494223f3 100644 --- a/erts/emulator/sys/common/erl_check_io.h +++ b/erts/emulator/sys/common/erl_check_io.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2020. All Rights Reserved. + * Copyright Ericsson AB 2006-2022. 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. @@ -112,6 +112,22 @@ typedef struct { } ErtsIoTask; +ERTS_GLB_INLINE int erts_sched_poll_enabled(void); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE int erts_sched_poll_enabled(void) +{ +#if ERTS_POLL_USE_SCHEDULER_POLLING + extern ErtsPollSet *sched_pollset; + return (sched_pollset != NULL); +#else + return 0; +#endif +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + #endif /* ERL_CHECK_IO_H__ */ #if !defined(ERL_CHECK_IO_C__) && !defined(ERTS_ALLOC_C__) @@ -133,6 +149,7 @@ extern int erts_no_poll_threads; #include "erl_poll.h" #include "erl_port_task.h" + typedef struct { Eterm inport; Eterm outport; @@ -152,3 +169,4 @@ typedef struct { } ErtsNifSelectDataState; #endif /* #ifndef ERL_CHECK_IO_INTERNAL__ */ + diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c index edcdd12d2cd9..e3300e3c433f 100644 --- a/erts/emulator/sys/common/erl_mmap.c +++ b/erts/emulator/sys/common/erl_mmap.c @@ -327,7 +327,7 @@ struct ErtsMemMapper_ { * Super unaligned area is located above super aligned * area. That is, `sa.bot` is beginning of the super * carrier, `sua.top` is the end of the super carrier, - * and sa.top and sua.bot moves towards eachother. + * and sa.top and sua.bot moves towards each other. */ struct { char *top; @@ -2587,10 +2587,10 @@ static void print_tree(enum SortOrder order, RBTNode*); /* * Checks that the order between parent and children are correct, - * and that the Red-Black Tree properies are satisfied. if size > 0, + * and that the Red-Black Tree properties are satisfied. if size > 0, * check_tree() returns the node that satisfies "address order first fit" * - * The Red-Black Tree properies are: + * The Red-Black Tree properties are: * 1. Every node is either red or black. * 2. Every leaf (NIL) is black. * 3. If a node is red, then both its children are black. diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h index e4e9dfb7aec4..ecb1ef6a13b0 100644 --- a/erts/emulator/sys/common/erl_mmap.h +++ b/erts/emulator/sys/common/erl_mmap.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2013-2021. All Rights Reserved. + * Copyright Ericsson AB 2013-2022. 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. diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index 42c4879a0eff..1b6b3aa0f7a8 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2021. All Rights Reserved. + * Copyright Ericsson AB 2002-2022. 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. @@ -36,7 +36,6 @@ #include "erl_mseg.h" #include "global.h" #include "erl_threads.h" -#include "erl_mtrace.h" #include "erl_time.h" #include "erl_alloc.h" #include "big.h" @@ -45,8 +44,6 @@ #if HAVE_ERTS_MSEG -#define SEGTYPE ERTS_MTRACE_SEGMENT_ID - #ifndef HAVE_GETPAGESIZE #define HAVE_GETPAGESIZE 0 #endif @@ -570,9 +567,6 @@ static ERTS_INLINE Uint mseg_drop_one_cache_size(ErtsMsegAllctr_t *ma, Uint flag c = erts_circleq_tail(head); erts_circleq_remove(c); - if (erts_mtrace_enabled) - erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg); - mseg_destroy(ma, flags, c->seg, c->size); mseg_cache_clear_node(c); erts_circleq_push_head(&(ma->cache_free), c); @@ -593,9 +587,6 @@ static ERTS_INLINE Uint mseg_drop_cache_size(ErtsMsegAllctr_t *ma, Uint flags, c c = erts_circleq_tail(head); erts_circleq_remove(c); - if (erts_mtrace_enabled) - erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg); - mseg_destroy(ma, flags, c->seg, c->size); mseg_cache_clear_node(c); @@ -732,9 +723,6 @@ mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, UWord *size_p, else { done: *size_p = size; - if (erts_mtrace_enabled) - erts_mtrace_crr_alloc(seg, atype, ERTS_MTRACE_SEGMENT_ID, size); - ERTS_MSEG_ALLOC_STAT(ma,size); } @@ -753,9 +741,6 @@ mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, UWord size, goto done; } - if (erts_mtrace_enabled) - erts_mtrace_crr_free(atype, SEGTYPE, seg); - mseg_destroy(ma, flags, seg, size); done: @@ -825,9 +810,6 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, } } - if (erts_mtrace_enabled) - erts_mtrace_crr_realloc(new_seg, atype, SEGTYPE, seg, new_size); - INC_CC(ma, realloc); ASSERT(!MSEG_FLG_IS_2POW(flags) || IS_2POW(new_size)); diff --git a/erts/emulator/sys/common/erl_mtrace_sys_wrap.c b/erts/emulator/sys/common/erl_mtrace_sys_wrap.c deleted file mode 100644 index fc871f94f188..000000000000 --- a/erts/emulator/sys/common/erl_mtrace_sys_wrap.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2016. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys.h" -#include "erl_mtrace.h" - -#ifdef ERTS_CAN_TRACK_MALLOC -#if defined(HAVE_END_SYMBOL) -extern char end; -#elif defined(HAVE__END_SYMBOL) -extern char _end; -#endif - -static int inited = 0; -static int init(void); - -static volatile char *heap_start = NULL; -static volatile char *heap_end = NULL; - -#if defined(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC) /* ----------------- */ - -#ifdef HAVE_MALLOC_H -# include -#endif - -#undef SBRK_0 -#define SBRK_0 sbrk(0) - -static void -init_hook(void) -{ - __after_morecore_hook = erts_mtrace_update_heap_size; - if (inited) - return; - heap_end = NULL; -#if defined(HAVE_END_SYMBOL) - heap_start = &end; -#elif defined(HAVE__END_SYMBOL) - heap_start = &_end; -#else - heap_start = SBRK_0; - if (heap_start == (SBRK_RET_TYPE) -1) { - heap_start = NULL; - return; - } -#endif - inited = 1; -} - -static int -init(void) -{ - init_hook(); - return inited; -} - -void (*__malloc_initialize_hook)(void) = init_hook; - -#elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) /* ------------------------ */ -#ifdef HAVE_DLFCN_H -# include -#endif - -#undef SBRK_0 -#define SBRK_0 (*real_sbrk)(0) - -#ifndef HAVE_SBRK -# error no sbrk() -#endif -#if !defined(HAVE_END_SYMBOL) && !defined(HAVE__END_SYMBOL) -# error no 'end' nor '_end' -#endif - -static void update_heap_size(char *new_end); - -#define SBRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \ -RET_TYPE FUNC (ARG_TYPE); \ -static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \ -RET_TYPE FUNC (ARG_TYPE arg) \ -{ \ - RET_TYPE res; \ - if (!inited && !init()) \ - return (RET_TYPE) -1; \ - res = (*real_ ## FUNC)(arg); \ - if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \ - update_heap_size((char *) (*real_ ## FUNC)(0)); \ - return res; \ -} - -#define BRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \ -RET_TYPE FUNC (ARG_TYPE); \ -static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \ -RET_TYPE FUNC (ARG_TYPE arg) \ -{ \ - RET_TYPE res; \ - if (!inited && !init()) \ - return (RET_TYPE) -1; \ - res = (*real_ ## FUNC)(arg); \ - if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \ - update_heap_size((char *) arg); \ - return res; \ -} - -SBRK_IMPL(SBRK_RET_TYPE, sbrk, SBRK_ARG_TYPE) -#ifdef HAVE_BRK - BRK_IMPL(BRK_RET_TYPE, brk, BRK_ARG_TYPE) -#endif - -#ifdef HAVE__SBRK - SBRK_IMPL(SBRK_RET_TYPE, _sbrk, SBRK_ARG_TYPE) -#endif -#ifdef HAVE__BRK - BRK_IMPL(BRK_RET_TYPE, _brk, BRK_ARG_TYPE) -#endif - -#ifdef HAVE___SBRK - SBRK_IMPL(SBRK_RET_TYPE, __sbrk, SBRK_ARG_TYPE) -#endif -#ifdef HAVE___BRK - BRK_IMPL(BRK_RET_TYPE, __brk, BRK_ARG_TYPE) -#endif - -static int -init(void) -{ - if (inited) - return 1; - -#define INIT_XBRK_SYM(SYM) \ -do { \ - if (!real_ ## SYM) { \ - real_ ## SYM = dlsym(RTLD_NEXT, #SYM); \ - if (!real_ ## SYM) { \ - errno = ENOMEM; \ - return 0; \ - } \ - } \ -} while (0) - - heap_end = NULL; -#if defined(HAVE_END_SYMBOL) - heap_start = &end; -#elif defined(HAVE__END_SYMBOL) - heap_start = &_end; -#endif - - INIT_XBRK_SYM(sbrk); -#ifdef HAVE_BRK - INIT_XBRK_SYM(brk); -#endif -#ifdef HAVE__SBRK - INIT_XBRK_SYM(_sbrk); -#endif -#ifdef HAVE__BRK - INIT_XBRK_SYM(_brk); -#endif -#ifdef HAVE___SBRK - INIT_XBRK_SYM(__sbrk); -#endif -#ifdef HAVE___BRK - INIT_XBRK_SYM(__brk); -#endif - - return inited = 1; -#undef INIT_XBRK_SYM -} - -#endif /* #elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) */ /* ----------- */ - -static void -update_heap_size(char *new_end) -{ - volatile char *new_start, *old_start, *old_end; - Uint size; - - if (new_end == ((char *) -1)) - return; - - new_start = (old_start = heap_start); - old_end = heap_end; - heap_end = new_end; - if (new_end < old_start || !old_start) - heap_start = (new_start = new_end); - - size = (Uint) (new_end - new_start); - - if (!old_end) { - if (size) - erts_mtrace_crr_alloc((void *) new_start, - ERTS_ALC_A_SYSTEM, - ERTS_MTRACE_SEGMENT_ID, - size); - else - heap_end = NULL; - } - else { - if (old_end != new_end || old_start != new_start) { - - if (size) - erts_mtrace_crr_realloc((void *) new_start, - ERTS_ALC_A_SYSTEM, - ERTS_MTRACE_SEGMENT_ID, - (void *) old_start, - size); - else { - if (old_start) - erts_mtrace_crr_free(ERTS_ALC_A_SYSTEM, - ERTS_MTRACE_SEGMENT_ID, - (void *) old_start); - heap_end = NULL; - } - } - } -} - -#endif /* #ifdef ERTS_CAN_TRACK_MALLOC */ - -void -erts_mtrace_update_heap_size(void) -{ -#ifdef ERTS_CAN_TRACK_MALLOC - if (erts_mtrace_enabled && (inited || init())) - update_heap_size((char *) SBRK_0); -#endif -} - diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index ecf0d684c235..6aa001210feb 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2021. All Rights Reserved. + * Copyright Ericsson AB 2006-2023. 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. @@ -1965,7 +1965,7 @@ ERTS_POLL_EXPORT(erts_poll_wait)(ErtsPollSet *ps, /* * This may have happened because another thread deselected * a fd in our poll set and then closed it, i.e. the driver - * behaved correctly. We wan't to avoid looking for a bad + * behaved correctly. We want to avoid looking for a bad * fd, that may even not exist anymore. Therefore, handle * update requests and try again. This behaviour should only * happen when using SELECT as the polling mechanism. @@ -2466,7 +2466,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, char fname[30]; char s[256]; FILE *f; - unsigned int pos, flags, mnt_id; + unsigned int pos, flags, mnt_id, ino; int hdr_lines, line = 1; sprintf(fname,"/proc/%d/fdinfo/%d",getpid(), ps->kp_fd); for (fd = 0; fd < len; fd++) @@ -2476,14 +2476,16 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, fprintf(stderr,"failed to open file %s, errno = %d\n", fname, errno); return; } - hdr_lines = fscanf(f,"pos:\t%x\nflags:\t%x\nmnt_id:\t%x\n", - &pos, &flags, &mnt_id); + + hdr_lines = fscanf(f,"pos:\t%x\nflags:\t%x\nmnt_id:\t%x\nino:\t%x\n", + &pos, &flags, &mnt_id, &ino); if (hdr_lines < 2) { fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno); ASSERT(0); fclose(f); return; } + line += hdr_lines; while (fgets(s, sizeof(s) / sizeof(*s), f)) { /* tfd: 10 events: 40000019 data: 180000000a */ diff --git a/erts/emulator/sys/unix/driver_int.h b/erts/emulator/sys/unix/driver_int.h index 840b8328788a..5eb9ce54b8c9 100644 --- a/erts/emulator/sys/unix/driver_int.h +++ b/erts/emulator/sys/unix/driver_int.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2016. All Rights Reserved. + * Copyright Ericsson AB 1997-2021. 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. @@ -18,7 +18,7 @@ * %CopyrightEnd% */ /* - * System dependant driver declarations + * System dependent driver declarations */ #ifndef __DRIVER_INT_H__ diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c index 652715f5f9cf..ae269292e5c5 100644 --- a/erts/emulator/sys/unix/erl_child_setup.c +++ b/erts/emulator/sys/unix/erl_child_setup.c @@ -58,6 +58,7 @@ #include #include #include +#include #define WANT_NONBLOCKING @@ -136,6 +137,43 @@ void sys_sigrelease(int sig) sigprocmask(SIG_UNBLOCK, &mask, (sigset_t *)NULL); } + +/* This version of read/write makes sure to read/write the entire size before + returning. Normal read/write can handle partial results which we do not want. */ +static ssize_t read_all(int fd, char *buff, size_t size) { + ssize_t res, pos = 0; + do { + if ((res = read(fd, buff + pos, size - pos)) < 0) { + if (errno == ERRNO_BLOCK || errno == EINTR) + continue; + return res; + } + if (res == 0) { + errno = EPIPE; + return -1; + } + pos += res; + } while(size - pos != 0); + return pos; +} + +static ssize_t write_all(int fd, const char *buff, size_t size) { + ssize_t res, pos = 0; + do { + if ((res = write(fd, buff + pos, size - pos)) < 0) { + if (errno == ERRNO_BLOCK || errno == EINTR) + continue; + return res; + } + if (res == 0) { + errno = EPIPE; + return -1; + } + pos += res; + } while (size - pos != 0); + return pos; +} + static void add_os_pid_to_port_id_mapping(Eterm, pid_t); static Eterm get_port_id(pid_t); static int forker_hash_init(void); @@ -148,7 +186,7 @@ start_new_child(int pipes[]) { struct sigaction sa; int errln = -1; - int size, res, i, pos = 0; + int size, i; char *buff, *o_buff; char *cmd, *cwd, *wd, **new_environ, **args = NULL; @@ -166,12 +204,8 @@ start_new_child(int pipes[]) perror(NULL); exit(1); } - - do { - res = read(pipes[0], (char*)&size, sizeof(size)); - } while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK)); - if (res <= 0) { + if (read_all(pipes[0], (char*)&size, sizeof(size)) <= 0) { errln = __LINE__; goto child_error; } @@ -180,20 +214,10 @@ start_new_child(int pipes[]) DEBUG_PRINT("size = %d", size); - do { - if ((res = read(pipes[0], buff + pos, size - pos)) < 0) { - if (errno == ERRNO_BLOCK || errno == EINTR) - continue; - errln = __LINE__; - goto child_error; - } - if (res == 0) { - errno = EPIPE; - errln = __LINE__; - goto child_error; - } - pos += res; - } while(size - pos != 0); + if (read_all(pipes[0], buff, size) <= 0) { + errln = __LINE__; + goto child_error; + } o_buff = buff; @@ -252,18 +276,13 @@ start_new_child(int pipes[]) } DEBUG_PRINT("read ack"); - do { + { ErtsSysForkerProto proto; - res = read(pipes[0], &proto, sizeof(proto)); - if (res > 0) { - ASSERT(proto.action == ErtsSysForkerProtoAction_Ack); + if (read_all(pipes[0], (char*)&proto, sizeof(proto)) <= 0) { + errln = __LINE__; + goto child_error; } - } while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK)); - - if (res < 1) { - errno = EPIPE; - errln = __LINE__; - goto child_error; + ASSERT(proto.action == ErtsSysForkerProtoAction_Ack); } DEBUG_PRINT("Set cwd to: '%s'",cwd); @@ -373,15 +392,13 @@ start_new_child(int pipes[]) * for posterity. */ static void handle_sigchld(int sig) { - int buff[2], res, __preverrno = errno; + int buff[2], __preverrno = errno; + ssize_t res; sys_sigblock(SIGCHLD); while ((buff[0] = waitpid((pid_t)(-1), buff+1, WNOHANG)) > 0) { - do { - res = write(sigchld_pipe[1], buff, sizeof(buff)); - } while (res < 0 && errno == EINTR); - if (res <= 0) + if ((res = write_all(sigchld_pipe[1], (char*)buff, sizeof(buff))) <= 0) ABORT("Failed to write to sigchld_pipe (%d): %d (%d)", sigchld_pipe[1], res, errno); DEBUG_PRINT("Reap child %d (%d)", buff[0], buff[1]); } @@ -416,6 +433,17 @@ static int system_properties_fd(void) } #endif /* __ANDROID__ */ +/* + If beam is terminated using kill -9 or Ctrl-C when +B is set it may not + cleanup the terminal properly. So to clean it up we save the initial state in + erl_child_setup and then reset the terminal if we detect that beam terminated. + + Not all shells and OSs have this issue, but we do it on all unixes anyway as + it is hard for us to know where the bug exists or not and there is no hard in + doing it. + */ +static struct termios initial_tty_mode; + int main(int argc, char *argv[]) { @@ -431,6 +459,10 @@ main(int argc, char *argv[]) ABORT("Invalid arguments to child_setup"); } + if (isatty(0)) { + tcgetattr(0,&initial_tty_mode); + } + /* We close all fds except the uds from beam. All other fds from now on will have the CLOEXEC flags set on them. This means that we @@ -525,12 +557,18 @@ main(int argc, char *argv[]) pipes, 3, MSG_DONTWAIT)) < 0) { if (errno == EINTR) continue; + if (isatty(0)) { + tcsetattr(0,TCSANOW,&initial_tty_mode); + } DEBUG_PRINT("erl_child_setup failed to read from uds: %d, %d", res, errno); _exit(0); } if (res == 0) { DEBUG_PRINT("uds was closed!"); + if (isatty(0)) { + tcsetattr(0,TCSANOW,&initial_tty_mode); + } _exit(0); } /* Since we use unix domain sockets and send the entire data in @@ -553,13 +591,11 @@ main(int argc, char *argv[]) proto.action = ErtsSysForkerProtoAction_Go; proto.u.go.os_pid = os_pid; proto.u.go.error_number = errno; - while (write(pipes[1], &proto, sizeof(proto)) < 0 && errno == EINTR) - ; /* remove gcc warning */ + write_all(pipes[1], (char *)&proto, sizeof(proto)); #ifdef FORKER_PROTO_START_ACK proto.action = ErtsSysForkerProtoAction_StartAck; - while (write(uds_fd, &proto, sizeof(proto)) < 0 && errno == EINTR) - ; /* remove gcc warning */ + write_all(uds_fd, (char *)&proto, sizeof(proto)); #endif sys_sigrelease(SIGCHLD); @@ -571,10 +607,8 @@ main(int argc, char *argv[]) if (FD_ISSET(sigchld_pipe[0], &read_fds)) { int ibuff[2]; ErtsSysForkerProto proto; - res = read(sigchld_pipe[0], ibuff, sizeof(ibuff)); + res = read_all(sigchld_pipe[0], (char *)ibuff, sizeof(ibuff)); if (res <= 0) { - if (errno == EINTR) - continue; ABORT("Failed to read from sigchld pipe: %d (%d)", res, errno); } @@ -586,9 +620,7 @@ main(int argc, char *argv[]) proto.action = ErtsSysForkerProtoAction_SigChld; proto.u.sigchld.error_number = ibuff[1]; DEBUG_PRINT("send sigchld to %d (errno = %d)", uds_fd, ibuff[1]); - if (write(uds_fd, &proto, sizeof(proto)) < 0) { - if (errno == EINTR) - continue; + if (write_all(uds_fd, (char *)&proto, sizeof(proto)) < 0) { /* The uds was close, which most likely means that the VM has exited. This will be detected when we try to read from the uds_fd. */ diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index ab0de4ad9deb..9b926f9aeb33 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2022. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -73,15 +73,9 @@ # include #endif -#if TIME_WITH_SYS_TIME +#include +#if HAVE_SYS_TIME_H # include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif #endif #include @@ -113,6 +107,10 @@ # define ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC 1 #endif +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + /* * Make sure that MAXPATHLEN is defined. */ @@ -283,7 +281,7 @@ ERTS_GLB_INLINE ErtsSysPerfCounter erts_sys_perf_counter(void); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_FORCE_INLINE ErtsSysPerfCounter -erts_sys_perf_counter() +erts_sys_perf_counter(void) { return (*erts_sys_time_data__.r.o.perf_counter)(); } diff --git a/erts/emulator/sys/unix/erl_unix_sys_ddll.c b/erts/emulator/sys/unix/erl_unix_sys_ddll.c index 71a26fc7efd9..d8d8fc13a8c6 100644 --- a/erts/emulator/sys/unix/erl_unix_sys_ddll.c +++ b/erts/emulator/sys/unix/erl_unix_sys_ddll.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2021. All Rights Reserved. + * Copyright Ericsson AB 2006-2022. 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. @@ -180,6 +180,31 @@ int erts_sys_ddll_sym2(void *handle, const char *func_name, void **function, #endif } +/* + * Find a symbol in the shared object + */ +int erts_sys_ddll_vsym2(void *handle, const char *func_name, const char *vers, + void **function, ErtsSysDdllError* err) +{ +#if defined(HAVE_DLVSYM) + void *sym; + char *e; + int ret; + dlerror(); + sym = dlvsym(handle, func_name, vers); + if ((e = dlerror()) != NULL) { + ret = ERL_DE_DYNAMIC_ERROR_OFFSET - find_errcode(e, err); + ASSERT(ret != ERL_DE_NO_ERROR); + } else { + *function = sym; + ret = ERL_DE_NO_ERROR; + } + return ret; +#else + return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; +#endif +} + /* XXX:PaN These two will be changed with new driver interface! */ /* diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 7ff8425d5229..210d7a55432f 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -814,6 +814,10 @@ void sys_get_pid(char *buffer, size_t buffer_size){ erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p); } +int sys_get_hostname(char *buf, size_t size) +{ + return gethostname(buf, size); +} void sys_init_io(void) { } void erts_sys_alloc_init(void) { } @@ -1057,7 +1061,7 @@ init_smp_sig_notify(void) { erts_thr_opts_t thr_opts = ERTS_THR_OPTS_DEFAULT_INITER; thr_opts.detached = 1; - thr_opts.name = "sys_sig_dispatcher"; + thr_opts.name = "erts_ssig_disp"; if (pipe(sig_notify_fds) < 0) { erts_exit(ERTS_ABORT_EXIT, @@ -1107,7 +1111,7 @@ erts_sys_main_thread(void) #else /* Become signal receiver thread... */ #ifdef ERTS_ENABLE_LOCK_CHECK - erts_lc_set_thread_name("signal_receiver"); + erts_lc_set_thread_name("main"); #endif #endif smp_sig_notify(0); /* Notify initialized */ diff --git a/erts/emulator/sys/unix/sys_env.c b/erts/emulator/sys/unix/sys_env.c index 4d8301f98542..eb98e7b63529 100644 --- a/erts/emulator/sys/unix/sys_env.c +++ b/erts/emulator/sys/unix/sys_env.c @@ -16,7 +16,7 @@ extern char **environ; static void import_initial_env(void); -void erts_sys_env_init() { +void erts_sys_env_init(void) { erts_rwmtx_init(&sysenv_rwmtx, "environ", NIL, ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC); @@ -24,21 +24,21 @@ void erts_sys_env_init() { import_initial_env(); } -const erts_osenv_t *erts_sys_rlock_global_osenv() { +const erts_osenv_t *erts_sys_rlock_global_osenv(void) { erts_rwmtx_rlock(&sysenv_rwmtx); return &sysenv_global_env; } -erts_osenv_t *erts_sys_rwlock_global_osenv() { +erts_osenv_t *erts_sys_rwlock_global_osenv(void) { erts_rwmtx_rwlock(&sysenv_rwmtx); return &sysenv_global_env; } -void erts_sys_rwunlock_global_osenv() { +void erts_sys_rwunlock_global_osenv(void) { erts_rwmtx_rwunlock(&sysenv_rwmtx); } -void erts_sys_runlock_global_osenv() { +void erts_sys_runlock_global_osenv(void) { erts_rwmtx_runlock(&sysenv_rwmtx); } diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index 91e8a087ed8b..f7a043d68bbd 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -56,7 +56,7 @@ sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t deci if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size) return -1; - /* Search upto decimal point */ + /* Search up to decimal point */ if (*s == '+' || *s == '-') s++; while (ISDIGIT(*s)) s++; if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */ diff --git a/erts/emulator/sys/unix/sys_signal_stack.c b/erts/emulator/sys/unix/sys_signal_stack.c index f4731a503467..3bd7d98a8937 100644 --- a/erts/emulator/sys/unix/sys_signal_stack.c +++ b/erts/emulator/sys/unix/sys_signal_stack.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2020. All Rights Reserved. + * Copyright Ericsson AB 2001-2022. 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. @@ -97,7 +97,7 @@ * Assumes Mac OS X >= 10.3 (dlsym operations not available in 10.2 and * earlier). * - * The code below assumes that is is part of the main image (earlier + * The code below assumes that is part of the main image (earlier * in the load order than libSystem and certainly before any dylib * that might use sigaction) -- a standard RTLD_NEXT caveat. * diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 5fd48b793ca7..eb2c47bb207d 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2020. All Rights Reserved. + * Copyright Ericsson AB 2005-2022. 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. @@ -89,7 +89,7 @@ get_tick_count(void) /* * init timers, chose a tick length, and return it. - * Unix is priviliged when it comes to time, as erl_time_sup.c + * Unix is privileged when it comes to time, as erl_time_sup.c * does almost everything. Other platforms have to * emulate Unix in this sense. */ @@ -219,7 +219,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) #endif init_resp->os_monotonic_time_info.resolution = (Uint64) 1000*1000*1000; -#if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) +#if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) init_resp->os_monotonic_time_info.resolution = mach_clock_getres(&internal_state.r.o.mach.clock.monotonic); #elif defined(HAVE_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) @@ -379,7 +379,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) init_resp->os_system_time_info.locked_use = 0; init_resp->os_system_time_info.resolution = (Uint64) 1000*1000*1000; -#if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(WALL_CLOCK_ID) +#if defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) init_resp->os_system_time_info.resolution = mach_clock_getres(&internal_state.r.o.mach.clock.wall); #elif defined(HAVE_CLOCK_GETRES) && defined(WALL_CLOCK_ID) diff --git a/erts/emulator/sys/win32/driver_int.h b/erts/emulator/sys/win32/driver_int.h index 50097d3fd2bf..a337058f99ed 100644 --- a/erts/emulator/sys/win32/driver_int.h +++ b/erts/emulator/sys/win32/driver_int.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2016. All Rights Reserved. + * Copyright Ericsson AB 1997-2021. 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. @@ -18,7 +18,7 @@ * %CopyrightEnd% */ /*---------------------------------------------------------------------- -** Purpose : System dependant driver declarations +** Purpose : System dependent driver declarations **---------------------------------------------------------------------- */ #ifndef __DRIVER_INT_H__ diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c index 3843a27a6e96..36b4ebd5521f 100644 --- a/erts/emulator/sys/win32/erl_poll.c +++ b/erts/emulator/sys/win32/erl_poll.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2018. All Rights Reserved. + * Copyright Ericsson AB 2007-2021. 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. @@ -320,7 +320,7 @@ static void *threaded_waiter(void *param); static void *break_waiter(void *param); /* - * Sychronization macros and functions + * Synchronization macros and functions */ #define START_WAITER(PS, w) \ SetEvent((w)->go_ahead) @@ -435,7 +435,7 @@ wake_poller(ErtsPollSet *ps, int io_ready) /* * Since we don't know the internals of SetEvent() we issue * a memory barrier as a safety precaution ensuring that - * the store we just made to wakeup_state wont be reordered + * the store we just made to wakeup_state won't be reordered * with loads in SetEvent(). */ ERTS_THR_MEMORY_BARRIER; @@ -769,7 +769,7 @@ static void *threaded_waiter(void *param) notify_io_ready(ps); /* - * The main thread wont start working on our arrays until we're + * The main thread won't start working on our arrays until we're * stopped, so we can work in peace although the main thread runs */ ASSERT(i >= WAIT_OBJECT_0+1); @@ -1044,7 +1044,7 @@ int erts_poll_wait(ErtsPollSet *ps, /* * Since we don't know the internals of ResetEvent() we issue * a memory barrier as a safety precaution ensuring that - * the load of wakeup_state wont be reordered with stores made + * the load of wakeup_state won't be reordered with stores made * by ResetEvent(). */ ERTS_THR_MEMORY_BARRIER; @@ -1287,7 +1287,7 @@ void erts_poll_late_init(void) } /* - * Non windows friendly interface, not used when fd's are not continous + * Non windows friendly interface, not used when fd's are not continuous */ void erts_poll_get_selected_events(ErtsPollSet *ps, ErtsPollEvents ev[], diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c index 7fe1f5cc78bb..c0714762b0fa 100644 --- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c +++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2018. All Rights Reserved. + * Copyright Ericsson AB 2006-2022. 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. @@ -91,7 +91,7 @@ int erts_sys_ddll_open(const char *full_name, void **handle, ErtsSysDdllError* e /* LOAD_WITH_ALTERED_SEARCH_PATH adds the specified DLL's directory to the * dependency search path. This also removes the directory we started in, - * but we've explicitly added that in in erl_sys_ddll_init. */ + * but we've explicitly added that in erl_sys_ddll_init. */ if ((hinstance = LoadLibraryExW(wcp, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) { code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError(); if (err != NULL) { diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h index c683e8cf49b1..8105128f8710 100644 --- a/erts/emulator/sys/win32/erl_win_dyn_driver.h +++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2018. All Rights Reserved. + * Copyright Ericsson AB 2003-2021. 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. @@ -262,7 +262,7 @@ typedef struct { /* Add new calls here */ } TWinDynDriverCallbacks; -/* This header is included explicitly by the ddll static driver, it musn't define things then */ +/* This header is included explicitly by the ddll static driver, it mustn't define things then */ #ifndef STATIC_ERLANG_DRIVER extern TWinDynDriverCallbacks WinDynDriverCallbacks; diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 513adbed63ea..a7b1f7ac9583 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -95,7 +95,7 @@ #define ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC 1 /* - * Practial Windows specific macros. + * Practical Windows specific macros. */ #define CreateAutoEvent(state) CreateEvent(NULL, FALSE, state, NULL) @@ -271,7 +271,7 @@ extern volatile int erl_fp_exception; #include /* I suspect this test isn't right, it might depend on the version of GCC - rather than if it's a MINGW gcc, but I havent been able to pinpoint the + rather than if it's a MINGW gcc, but I haven't been able to pinpoint the exact point where _finite was added to the headers in cygwin... */ #if defined (__GNUC__) && !defined(__MINGW32__) int _finite(double x); diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index fd3cb3413049..4d4b2b7fb8b1 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2022. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -32,10 +32,13 @@ #include "erl_sys_driver.h" #include "global.h" #include "erl_threads.h" -#include "../../drivers/win32/win_con.h" #include "erl_cpu_topology.h" #include +#if defined(__WIN32__) && !defined(WINDOWS_H_INCLUDES_WINSOCK2_H) +#include +#endif + void erts_sys_init_float(void); void erl_start(int, char**); @@ -77,7 +80,7 @@ static BOOL create_child_process(wchar_t *, HANDLE, HANDLE, static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL); static int application_type(const wchar_t* originalName, wchar_t fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, - int *error_return, BOOL *requote); + int *error_return); static void *build_env_block(const erts_osenv_t *env); HANDLE erts_service_event; @@ -125,8 +128,6 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType); static int max_files = 1024; static BOOL use_named_pipes; -static BOOL win_console = FALSE; - static OSVERSIONINFO int_os_version; /* Version information for Win32. */ @@ -205,10 +206,6 @@ erts_sys_misc_mem_sz(void) */ void sys_tty_reset(int exit_code) { - if (exit_code == ERTS_ERROR_EXIT) - ConWaitForExit(); - else - ConNormalExit(); } void erl_sys_args(int* argc, char** argv) @@ -304,25 +301,16 @@ int erts_set_signal(Eterm signal, Eterm type) { return 0; } +static DWORD dwOriginalOutMode = 0; +static DWORD dwOriginalInMode = 0; + static void init_console(void) { - char* mode = erts_read_env("ERL_CONSOLE_MODE"); - - if (!mode || strcmp(mode, "window") == 0) { - win_console = TRUE; - ConInit(); - /*nohup = 0;*/ - } else if (strncmp(mode, "tty:", 4) == 0) { - if (mode[5] == 'c') { - setvbuf(stdout, NULL, _IONBF, 0); - } - if (mode[6] == 'c') { - setvbuf(stderr, NULL, _IONBF, 0); - } - } - - erts_free_read_env(mode); + GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dwOriginalOutMode); + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwOriginalInMode); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); } int sys_max_files(void) @@ -704,11 +692,11 @@ release_driver_data(DriverData* dp) else #endif { - /* This is a workaround for the fact that CancelIo cant cancel - requests issued by another thread and that we cant use + /* This is a workaround for the fact that CancelIo can't cancel + requests issued by another thread and that we can't use CancelIoEx as that's only available in Vista etc. R14: Avoid scheduler deadlock by only wait for 10ms, and then spawn - a thread that will keep waiting in in order to close handles. */ + a thread that will keep waiting in order to close handles. */ HANDLE handles[2]; int i = 0; int timeout = 10; @@ -1020,7 +1008,7 @@ async_read_file(AsyncIo* aio, LPVOID buf, DWORD numToRead) aio->async_io_active = 1; /* Will get 0 when the event actually happened */ if (ReadFile(aio->fd, buf, numToRead, &aio->bytesTransferred, &aio->ov)) { - DEBUGF(("async_read_file: ReadFile() suceeded: %d bytes\n", + DEBUGF(("async_read_file: ReadFile() succeeded: %d bytes\n", aio->bytesTransferred)); #ifdef HARD_POLL_DEBUG poll_debug_async_immediate(aio->ov.hEvent, aio->bytesTransferred); @@ -1068,7 +1056,7 @@ async_write_file(AsyncIo* aio, /* Pointer to async control block. */ aio->async_io_active = 1; /* Will get 0 when the event actually happened */ if (WriteFile(aio->fd, buf, numToWrite, &aio->bytesTransferred, &aio->ov)) { - DEBUGF(("async_write_file: WriteFile() suceeded: %d bytes\n", + DEBUGF(("async_write_file: WriteFile() succeeded: %d bytes\n", aio->bytesTransferred)); aio->async_io_active = 0; /* The event will not be signalled */ ResetEvent(aio->ov.hEvent); @@ -1137,7 +1125,7 @@ get_overlapped_result(AsyncIo* aio, /* Pointer to async control block. */ DEBUGF(("get_overlapped_result: pending error: %s\n", win32_errorstr(error))); return error; - } else if (aio->flags & DF_OVR_READY) { /* Operation succeded. */ + } else if (aio->flags & DF_OVR_READY) { /* Operation succeeded. */ aio->flags &= ~DF_OVR_READY; *pBytesRead = aio->bytesTransferred; ResetEvent(aio->ov.hEvent); @@ -1526,7 +1514,7 @@ create_child_process wchar_t *wd, /* Working dir for the child */ unsigned st, /* Flags for spawn, tells us how to interpret origcmd */ wchar_t **argv, /* Argument vector if given. */ - int *errno_return /* Place to put an errno in in case of failure */ + int *errno_return /* Place to put an errno in case of failure */ ) { PROCESS_INFORMATION piProcInfo = {0}; @@ -1542,7 +1530,9 @@ create_child_process HANDLE hProcess = GetCurrentProcess(); STARTUPINFOW siStartInfo = {0}; wchar_t execPath[MAX_PATH]; - BOOL requote = FALSE; + BOOL need_quote; + int quotedLen; + wchar_t *ptr; *errno_return = -1; siStartInfo.cb = sizeof(STARTUPINFOW); @@ -1557,22 +1547,25 @@ create_child_process * contain spaces). */ cmdlength = parse_command(origcmd); - newcmdline = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, (MAX_PATH+wcslen(origcmd)-cmdlength)*sizeof(wchar_t)); thecommand = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, (cmdlength+1)*sizeof(wchar_t)); wcsncpy(thecommand, origcmd, cmdlength); thecommand[cmdlength] = L'\0'; DEBUGF(("spawn command: %S\n", thecommand)); applType = - application_type(thecommand, execPath, TRUE, TRUE, errno_return, &requote); + application_type(thecommand, execPath, TRUE, TRUE, errno_return); DEBUGF(("application_type returned for (%S) is %d\n", thecommand, applType)); erts_free(ERTS_ALC_T_TMP, (void *) thecommand); - if (applType == APPL_NONE) { - erts_free(ERTS_ALC_T_TMP,newcmdline); + if (applType == APPL_NONE) { return FALSE; } - newcmdline[0] = L'\0'; + quotedLen = escape_and_quote(execPath, NULL, &need_quote); + newcmdline = (wchar_t *) + erts_alloc(ERTS_ALC_T_TMP, + (11+quotedLen+wcslen(origcmd)-cmdlength)*sizeof(wchar_t)); + + ptr = newcmdline; if (applType == APPL_DOS) { /* * Under NT, 16-bit DOS applications will not run unless they @@ -1584,7 +1577,8 @@ create_child_process siStartInfo.wShowWindow = SW_HIDE; siStartInfo.dwFlags |= STARTF_USESHOWWINDOW; createFlags = CREATE_NEW_CONSOLE; - wcscat(newcmdline, L"cmd.exe /c "); + wcscpy(newcmdline, L"cmd.exe /c "); + ptr += 11; } else if (hide) { DEBUGF(("hiding window\n")); siStartInfo.wShowWindow = SW_HIDE; @@ -1592,14 +1586,9 @@ create_child_process createFlags = 0; } - if (requote) { - wcscat(newcmdline, L"\""); - } - wcscat(newcmdline, execPath); - if (requote) { - wcscat(newcmdline, L"\""); - } - wcscat(newcmdline, origcmd+cmdlength); + ptr += escape_and_quote(execPath, ptr, &need_quote); + + wcscpy(ptr, origcmd+cmdlength); DEBUGF(("Creating child process: %S, createFlags = %d\n", newcmdline, createFlags)); ok = CreateProcessW((applType == APPL_DOS) ? appname : execPath, newcmdline, @@ -1617,7 +1606,7 @@ create_child_process int run_cmd = 0; applType = - application_type(origcmd, execPath, FALSE, FALSE, errno_return, &requote); + application_type(origcmd, execPath, FALSE, FALSE, errno_return); if (applType == APPL_NONE) { return FALSE; } @@ -1640,7 +1629,7 @@ create_child_process wchar_t cmdPath[MAX_PATH]; int cmdType; cmdType = - application_type(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return, &requote); + application_type(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return); if (cmdType == APPL_NONE || cmdType == APPL_DOS) { return FALSE; } @@ -1759,7 +1748,7 @@ static int create_pipe(HANDLE *phRead, HANDLE *phWrite, BOOL inheritRead, BOOL o Uint calls; /* - * If we should't use named pipes, create anonmous pipes. + * If we shouldn't use named pipes, create anonmous pipes. */ if (!use_named_pipes) { @@ -1832,8 +1821,7 @@ static int application_type (const wchar_t *originalName, /* Name of the applica * application. */ BOOL search_in_path, /* If we should search the system wide path */ BOOL handle_quotes, /* If we should handle quotes around executable */ - int *error_return, /* A place to put an error code */ - BOOL *requote) /* The path needs requoting */ + int *error_return) /* A place to put an error code */ { int applType, i; HANDLE hFile; @@ -1844,15 +1832,17 @@ static int application_type (const wchar_t *originalName, /* Name of the applica static wchar_t extensions[][5] = {L"", L".com", L".exe", L".bat"}; int len; wchar_t xfullpath[MAX_PATH]; + BOOL is_quoted; len = wcslen(originalName); - *requote = handle_quotes && len > 0 && originalName[0] == L'"' && - originalName[len-1] == L'"'; + is_quoted = (handle_quotes && len > 0 + && originalName[0] == L'"' + && originalName[len-1] == L'"'); applType = APPL_NONE; *error_return = ENOENT; for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { - if(*requote) { + if(is_quoted) { lstrcpynW(xfullpath, originalName+1, MAX_PATH - 7); /* Cannot start using StringCchCopy yet, we support older platforms */ len = wcslen(xfullpath); @@ -2054,7 +2044,7 @@ threaded_writer(LPVOID param) aio->pendingError = 0; aio->bytesTransferred = numToWrite; } else if (aio->pendingError == ERROR_NOT_ENOUGH_MEMORY) { - /* This could be a console, which limits utput to 64kbytes, + /* This could be a console, which limits output to 64kbytes, which might translate to less on a unicode system. Try 16k chunks and see if it works before giving up. */ int done = 0; @@ -2194,7 +2184,6 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) return ERL_DRV_ERROR_GENERAL; } - fd_driver_input = &(dp->in); dp->in.flags = DF_XLAT_CR; if (is_std_error) { dp->out.flags |= DF_DROP_IF_INVH; /* Just drop messages if stderror @@ -2202,6 +2191,7 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) } if ( in == 0 && out == 1) { + fd_driver_input = &(dp->in); save_01_port = dp; } else if (in == 2 && out == 2) { save_22_port = dp; @@ -2217,7 +2207,7 @@ static void fd_stop(ErlDrvData data) /* * There's no way we can terminate an fd port in a consistent way. * Instead we let it live until it's opened again (which it is, - * as the only FD-drivers are for 0,1 and 2 adn the only time they + * as the only FD-drivers are for 0,1 and 2 and the only time they * get closed is by init:reboot). * So - just deselect them and let everything be as is. * They get woken up in fd_start again, where the DriverData is @@ -2781,6 +2771,11 @@ void sys_get_pid(char *buffer, size_t buffer_size){ erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p); } +int sys_get_hostname(char *buf, size_t size) +{ + return gethostname(buf, size); +} + void sys_init_io(void) { @@ -2945,10 +2940,6 @@ sys_get_key(int fd) { ASSERT(fd == 0); - if (win_console) { - return ConGetKey(); - } - /* * Black magic follows. (Code stolen from get_overlapped_result()) */ @@ -2974,6 +2965,32 @@ sys_get_key(int fd) } } } + else { + char c[64]; + DWORD dwBytesRead, dwCurrentOutMode = 0, dwCurrentInMode = 0; + + /* Get current console information */ + GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dwCurrentOutMode); + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwCurrentInMode); + + /* Set the a "oldstyle" terminal with line input that we can use ReadFile on */ + SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), dwOriginalOutMode); + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), + ENABLE_PROCESSED_INPUT | + ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | + ENABLE_INSERT_MODE | + ENABLE_QUICK_EDIT_MODE | + ENABLE_AUTO_POSITION + ); + + if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), &c, sizeof(c), &dwBytesRead, NULL) && dwBytesRead > 0) { + /* Restore original console information */ + SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), dwCurrentOutMode); + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwCurrentInMode); + return c[0]; + } + } return '*'; /* Error! */ } diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c index 22457a4be4a4..0c8d961508cb 100644 --- a/erts/emulator/sys/win32/sys_float.c +++ b/erts/emulator/sys/win32/sys_float.c @@ -113,7 +113,7 @@ sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t deci if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size) return -1; - /* Search upto decimal point */ + /* Search up to decimal point */ if (*s == '+' || *s == '-') s++; while (isdigit(*s)) s++; if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */ diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c index cee269eed4b1..fc4f63d4bf05 100644 --- a/erts/emulator/sys/win32/sys_interrupt.c +++ b/erts/emulator/sys/win32/sys_interrupt.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2018. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -23,11 +23,13 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#define ERTS_WANT_BREAK_HANDLING + #include "sys.h" #include "erl_alloc.h" #include "erl_thr_progress.h" #include "erl_driver.h" -#include "../../drivers/win32/win_con.h" #if defined(__GNUC__) # define WIN_SYS_INLINE __inline__ @@ -82,7 +84,6 @@ BOOL WINAPI ctrl_handler_ignore_break(DWORD dwCtrlType) } void erts_set_ignore_break(void) { - ConSetCtrlHandler(ctrl_handler_ignore_break); SetConsoleCtrlHandler(ctrl_handler_ignore_break, TRUE); } @@ -92,6 +93,9 @@ BOOL WINAPI ctrl_handler_replace_intr(DWORD dwCtrlType) case CTRL_C_EVENT: return FALSE; case CTRL_BREAK_EVENT: + if (ERTS_BREAK_REQUESTED) { + erts_exit(ERTS_INTR_EXIT, ""); + } SetEvent(erts_sys_break_event); break; case CTRL_LOGOFF_EVENT: @@ -110,7 +114,11 @@ BOOL WINAPI ctrl_handler_replace_intr(DWORD dwCtrlType) /* Don't use ctrl-c for break handler but let it be used by the shell instead (see user_drv.erl) */ void erts_replace_intr(void) { - ConSetCtrlHandler(ctrl_handler_replace_intr); + HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); + DWORD dwOriginalInMode = 0; + if (GetConsoleMode(hIn, &dwOriginalInMode)) { + SetConsoleMode(hIn, dwOriginalInMode & ~ENABLE_PROCESSED_INPUT); + } SetConsoleCtrlHandler(ctrl_handler_replace_intr, TRUE); } @@ -119,6 +127,9 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType) switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: + if (ERTS_BREAK_REQUESTED) { + erts_exit(ERTS_INTR_EXIT, ""); + } SetEvent(erts_sys_break_event); break; case CTRL_LOGOFF_EVENT: @@ -135,7 +146,6 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType) void init_break_handler() { - ConSetCtrlHandler(ctrl_handler); SetConsoleCtrlHandler(ctrl_handler, TRUE); } diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index e7849c7dd2c2..1d3cdf3b97fd 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -76,6 +76,7 @@ MODULES= \ hello_SUITE \ hibernate_SUITE \ iovec_SUITE \ + jit_SUITE \ list_bif_SUITE \ lttng_SUITE \ lcnt_SUITE \ @@ -92,7 +93,6 @@ MODULES= \ message_queue_data_SUITE \ op_SUITE \ os_signal_SUITE \ - perf_SUITE \ port_SUITE \ port_bif_SUITE \ prim_eval_SUITE \ @@ -123,6 +123,7 @@ MODULES= \ trace_meta_SUITE \ trace_call_count_SUITE \ trace_call_time_SUITE \ + trace_call_memory_SUITE \ tracer_SUITE \ tracer_test \ scheduler_SUITE \ @@ -149,6 +150,24 @@ NO_OPT= bs_bincomp \ guard \ map +R25= \ + bs_bincomp \ + bs_construct \ + bs_match_bin \ + bs_match_int \ + bs_match_tail \ + bs_match_misc \ + bs_utf + +STRIPPED_TYPES= \ + bs_bincomp \ + bs_construct \ + bs_match_bin \ + bs_match_int \ + bs_match_tail \ + bs_match_misc \ + bs_utf + NATIVE= hibernate NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE) @@ -157,6 +176,12 @@ NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl) NATIVE_MODULES= $(NATIVE:%=%_native_SUITE) NATIVE_ERL_FILES= $(NATIVE_MODULES:%=%.erl) +R25_MODULES= $(R25:%=%_r25_SUITE) +R25_ERL_FILES= $(R25_MODULES:%=%.erl) + +STRIPPED_TYPES_MODULES= $(STRIPPED_TYPES:%=%_stripped_types_SUITE) +STRIPPED_TYPES_ERL_FILES= $(STRIPPED_TYPES_MODULES:%=%.erl) + ERL_FILES= $(MODULES:%=%.erl) TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) @@ -169,6 +194,7 @@ EMAKEFILE=Emakefile TEST_SPEC_FILES= emulator.spec \ emulator.spec.win \ emulator_bench.spec \ + emulator_gh.spec \ emulator_smoke.spec \ emulator_node_container_SUITE.spec @@ -181,19 +207,25 @@ RELSYSDIR = $(RELEASE_PATH)/emulator_test # FLAGS # ---------------------------------------------------- ERL_MAKE_FLAGS += -ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$($(ERL_COMPILE_FLAGS))) # ---------------------------------------------------- # Targets # ---------------------------------------------------- -make_emakefile: $(NO_OPT_ERL_FILES) $(NATIVE_ERL_FILES) $(KERNEL_ERL_FILES) +make_emakefile: $(NO_OPT_ERL_FILES) $(NATIVE_ERL_FILES) \ + $(KERNEL_ERL_FILES) $(R25_ERL_FILES) $(STRIPPED_TYPES_ERL_FILES) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) +compressed -o$(EBIN) \ $(MODULES) $(KERNEL_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt +no_ssa_opt +no_bsm_opt \ $(ERL_COMPILE_FLAGS) -o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE) $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) \ -o$(EBIN) $(NATIVE_MODULES) >> $(EMAKEFILE) + $(ERL_TOP)/make/make_emakefile +r25 \ + $(ERL_COMPILE_FLAGS) -o$(EBIN) $(R25_MODULES) >> $(EMAKEFILE) + $(ERL_TOP)/make/make_emakefile +strip_types \ + $(ERL_COMPILE_FLAGS) -o$(EBIN) $(STRIPPED_TYPES_MODULES) >> $(EMAKEFILE) + tests debug opt: make_emakefile erl $(ERL_MAKE_FLAGS) -make @@ -217,6 +249,12 @@ targets: $(TARGET_FILES) %_native_SUITE.erl: %_SUITE.erl sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ +%_r25_SUITE.erl: %_SUITE.erl + sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ + +%_stripped_types_SUITE.erl: %_SUITE.erl + sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@ + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- @@ -231,6 +269,8 @@ release_tests_spec: make_emakefile $(INSTALL_DATA) $(NO_OPT_ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(NATIVE_ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(KERNEL_ERL_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) $(R25_ERL_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) $(STRIPPED_TYPES_ERL_FILES) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -) diff --git a/erts/emulator/test/a_SUITE.erl b/erts/emulator/test/a_SUITE.erl index 59b7839a8787..0f749f629e5d 100644 --- a/erts/emulator/test/a_SUITE.erl +++ b/erts/emulator/test/a_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2023. 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. @@ -47,6 +47,18 @@ init_per_suite(Config) when is_list(Config) -> %% allow other suites to use it... inet_gethost_native:gethostbyname("localhost"), + %% Trigger usage of large pids and ports in 64-bit case... + case erlang:system_info(wordsize) of + 4 -> + ok; + 8 -> + erts_debug:set_internal_state(available_internal_state,true), + erts_debug:set_internal_state(next_pid, 1 bsl 32), + erts_debug:set_internal_state(next_port, 1 bsl 32), + erts_debug:set_internal_state(available_internal_state,false), + ok + end, + %% Start the timer server. timer:start(), diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index e96f0fa07508..cea3d610a020 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -35,6 +35,9 @@ migration/1, cpool_opt/1]). +%% Internal export +-export([run_drv_case/2]). + -include_lib("common_test/include/ct.hrl"). suite() -> @@ -60,10 +63,10 @@ end_per_suite(_Config) -> ok. init_per_testcase(Case, Config) when is_list(Config) -> - [{testcase, Case},{debug,false}|Config]. + [{testcase, Case}|Config]. end_per_testcase(_Case, Config) when is_list(Config) -> - ok. + erts_test_utils:ept_check_leaked_nodes(Config). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% @@ -84,47 +87,41 @@ migration(Cfg) -> %% Enable test_alloc. %% Disable driver_alloc to avoid recursive alloc_util calls %% through enif_mutex_create() in my_creating_mbc(). - drv_case(Cfg, concurrent, "+MZe true +MRe false"), - drv_case(Cfg, concurrent, "+MZe true +MRe false +MZas ageffcbf"), - drv_case(Cfg, concurrent, "+MZe true +MRe false +MZas chaosff"). + drv_case(Cfg, concurrent, ["+MZe", "true", "+MRe", "false"]), + drv_case(Cfg, concurrent, ["+MZe", "true", "+MRe", "false", "+MZas", "ageffcbf"]), + drv_case(Cfg, concurrent, ["+MZe", "true", "+MRe", "false", "+MZas", "chaosff"]). cpool_opt(Config) when is_list(Config) -> - OldEnv = clear_env(), - try - {ok, NodeA} = start_node(Config, "+Mue true +Mut true +Muacul de +Mucp @", []), - {cp, '@'} = get_cp_opt(NodeA, binary_alloc), - {cp, '@'} = get_cp_opt(NodeA, std_alloc), - {cp, '@'} = get_cp_opt(NodeA, ets_alloc), - {cp, '@'} = get_cp_opt(NodeA, fix_alloc), - {cp, '@'} = get_cp_opt(NodeA, eheap_alloc), - {cp, '@'} = get_cp_opt(NodeA, ll_alloc), - {cp, '@'} = get_cp_opt(NodeA, driver_alloc), - {cp, '@'} = get_cp_opt(NodeA, sl_alloc), - stop_node(NodeA), - {ok, NodeB} = start_node(Config, "+Mue true +Mut true +Muacul de +Mucp :", []), - {cp, 'B'} = get_cp_opt(NodeB, binary_alloc), - {cp, 'D'} = get_cp_opt(NodeB, std_alloc), - {cp, 'E'} = get_cp_opt(NodeB, ets_alloc), - {cp, 'F'} = get_cp_opt(NodeB, fix_alloc), - {cp, 'H'} = get_cp_opt(NodeB, eheap_alloc), - {cp, 'L'} = get_cp_opt(NodeB, ll_alloc), - {cp, 'R'} = get_cp_opt(NodeB, driver_alloc), - {cp, 'S'} = get_cp_opt(NodeB, sl_alloc), - stop_node(NodeB), - {ok, NodeC} = start_node(Config, "+Mue true +Mut true +Muacul de +Mucp : +MEcp H", []), - {cp, 'B'} = get_cp_opt(NodeC, binary_alloc), - {cp, 'D'} = get_cp_opt(NodeC, std_alloc), - {cp, 'H'} = get_cp_opt(NodeC, ets_alloc), - {cp, 'F'} = get_cp_opt(NodeC, fix_alloc), - {cp, 'H'} = get_cp_opt(NodeC, eheap_alloc), - {cp, 'L'} = get_cp_opt(NodeC, ll_alloc), - {cp, 'R'} = get_cp_opt(NodeC, driver_alloc), - {cp, 'S'} = get_cp_opt(NodeC, sl_alloc), - stop_node(NodeC) - after - restore_env(OldEnv) - end, - ok. + {ok, PeerA, NodeA} = ?CT_PEER(["+Mue", "true", "+Mut", "true", "+Muacul", "de", "+Mucp", "@"]), + {cp, '@'} = get_cp_opt(NodeA, binary_alloc), + {cp, '@'} = get_cp_opt(NodeA, std_alloc), + {cp, '@'} = get_cp_opt(NodeA, ets_alloc), + {cp, '@'} = get_cp_opt(NodeA, fix_alloc), + {cp, '@'} = get_cp_opt(NodeA, eheap_alloc), + {cp, '@'} = get_cp_opt(NodeA, ll_alloc), + {cp, '@'} = get_cp_opt(NodeA, driver_alloc), + {cp, '@'} = get_cp_opt(NodeA, sl_alloc), + peer:stop(PeerA), + {ok, PeerB, NodeB} = ?CT_PEER(["+Mue", "true", "+Mut", "true", "+Muacul", "de", "+Mucp", ":"]), + {cp, 'B'} = get_cp_opt(NodeB, binary_alloc), + {cp, 'D'} = get_cp_opt(NodeB, std_alloc), + {cp, 'E'} = get_cp_opt(NodeB, ets_alloc), + {cp, 'F'} = get_cp_opt(NodeB, fix_alloc), + {cp, 'H'} = get_cp_opt(NodeB, eheap_alloc), + {cp, 'L'} = get_cp_opt(NodeB, ll_alloc), + {cp, 'R'} = get_cp_opt(NodeB, driver_alloc), + {cp, 'S'} = get_cp_opt(NodeB, sl_alloc), + peer:stop(PeerB), + {ok, PeerC, NodeC} = ?CT_PEER(["+Mue", "true", "+Mut", "true", "+Muacul", "de", "+Mucp", ":", "+MEcp", "H"]), + {cp, 'B'} = get_cp_opt(NodeC, binary_alloc), + {cp, 'D'} = get_cp_opt(NodeC, std_alloc), + {cp, 'H'} = get_cp_opt(NodeC, ets_alloc), + {cp, 'F'} = get_cp_opt(NodeC, fix_alloc), + {cp, 'H'} = get_cp_opt(NodeC, eheap_alloc), + {cp, 'L'} = get_cp_opt(NodeC, ll_alloc), + {cp, 'R'} = get_cp_opt(NodeC, driver_alloc), + {cp, 'S'} = get_cp_opt(NodeC, sl_alloc), + peer:stop(PeerC). get_cp_opt(Node, Alloc) -> AInfo = rpc:call(Node, erlang, system_info, [{allocator,Alloc}]), @@ -136,7 +133,7 @@ get_cp_opt(Node, Alloc) -> erts_mmap(Config) when is_list(Config) -> case {os:type(), mmsc_flags()} of {{unix,_}, false} -> - [erts_mmap_do(Config, SCO, SCRPM, SCRFSD) + [erts_mmap_do(SCO, SCRPM, SCRFSD) || SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]]; {{unix,_}, Flags} -> {skipped, Flags}; @@ -162,23 +159,21 @@ mmsc_flags(Env) -> end end. -erts_mmap_do(Config, SCO, SCRPM, SCRFSD) -> +erts_mmap_do(SCO, SCRPM, SCRFSD) -> %% We use the number of schedulers + 1 * approx main carriers size %% to calculate how large the super carrier has to be %% and then use a minimum of 100 for systems with a low amount of %% schedulers Schldr = erlang:system_info(schedulers_online)+1, SCS = max(round((262144 * 6 + 3 * 1048576) * Schldr / 1024 / 1024),100), - O1 = "+MMscs" ++ integer_to_list(SCS) - ++ " +MMsco" ++ atom_to_list(SCO) - ++ " +MMscrpm" ++ atom_to_list(SCRPM), + O1 = ["+MMscs" ++ integer_to_list(SCS), + "+MMsco" ++ atom_to_list(SCO), + "+MMscrpm" ++ atom_to_list(SCRPM)], Opts = case SCRFSD of 0 -> O1; - _ -> O1 ++ " +MMscrfsd"++integer_to_list(SCRFSD) + _ -> O1 ++ ["+MMscrfsd"++integer_to_list(SCRFSD)] end, - {ok, Node} = start_node(Config, Opts, []), - Self = self(), - Ref = make_ref(), + {ok, Peer, Node} = ?CT_PEER(Opts), F = fun() -> SI = erlang:system_info({allocator,erts_mmap}), {default_mmap,EM} = lists:keyfind(default_mmap, 1, SI), @@ -197,12 +192,12 @@ erts_mmap_do(Config, SCO, SCRPM, SCRFSD) -> {false, {os,_}} -> ok end, - Self ! {Ref, ok} + exit(ok) end, - spawn_link(Node, F), - Result = receive {Ref, Rslt} -> Rslt end, - stop_node(Node), + {Pid, MRef} = spawn_monitor(Node, F), + Result = receive {'DOWN', MRef, process, Pid, Rslt} -> Rslt end, + peer:stop(Peer), Result. @@ -293,18 +288,11 @@ drv_case(Config) -> drv_case(Config, Mode, NodeOpts) when is_list(Config) -> case os:type() of {Family, _} when Family == unix; Family == win32 -> - %%Prog = {prog,"/my/own/otp/bin/cerl -debug"}, - Prog = [], - {ok, Node} = start_node(Config, NodeOpts, Prog), - Self = self(), - Ref = make_ref(), - spawn_link(Node, - fun () -> - Res = run_drv_case(Config, Mode), - Self ! {Ref, Res} - end), - Result = receive {Ref, Rslt} -> Rslt end, - stop_node(Node), + %% ?CT_PEER(#{exec => {"/usr/local/bin/erl", ["-emu_type", "debug"]}}) + TC = proplists:get_value(testcase, Config), + {ok, Peer, Node} = ?CT_PEER(#{name => ?CT_PEER_NAME(TC), args => NodeOpts}), + Result = erpc:call(Node, ?MODULE, run_drv_case, [Config, Mode]), + peer:stop(Peer), Result; SkipOs -> {skipped, @@ -493,84 +481,21 @@ handle_result(_State, Result0) -> continue end. -start_node(Config, Opts, Prog) when is_list(Config), is_list(Opts) -> - case proplists:get_value(debug,Config) of - true -> {ok, node()}; - _ -> start_node_1(Config, Opts, Prog) - end. - -start_node_1(Config, Opts, Prog) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - ErlArg = case Prog of - [] -> []; - _ -> [{erl,[Prog]}] - end, - test_server:start_node(Name, slave, [{args, Opts++" -pa "++Pa} | ErlArg]). - -stop_node(Node) when Node =:= node() -> ok; -stop_node(Node) -> - test_server:stop_node(Node). - free_memory() -> %% Free memory in MB. try SMD = memsup:get_system_memory_data(), - {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD), - TotFree = (Free + - case lists:keysearch(cached_memory, 1, SMD) of - {value, {cached_memory, Cached}} -> Cached; - false -> 0 - end + - case lists:keysearch(buffered_memory, 1, SMD) of - {value, {buffered_memory, Buffed}} -> Buffed; - false -> 0 - end), + TotFree = proplists:get_value( + available_memory, SMD, + proplists:get_value(free_memory, SMD) + + proplists:get_value(cached_memory, SMD, 0) + + proplists:get_value(buffered_memory, SMD, 0) + ), TotFree div (1024*1024) catch error : undef -> ct:fail({"os_mon not built"}) end. -clear_env() -> - ErlRelFlagsName = - "ERL_OTP" - ++ erlang:system_info(otp_release) - ++ "_FLAGS", - ErlFlags = os:getenv("ERL_FLAGS"), - os:unsetenv("ERL_FLAGS"), - ErlAFlags = os:getenv("ERL_AFLAGS"), - os:unsetenv("ERL_AFLAGS"), - ErlZFlags = os:getenv("ERL_ZFLAGS"), - os:unsetenv("ERL_ZFLAGS"), - ErlRelFlags = os:getenv(ErlRelFlagsName), - os:unsetenv(ErlRelFlagsName), - {ErlFlags, ErlAFlags, ErlZFlags, ErlRelFlags}. - -restore_env({ErlFlags, ErlAFlags, ErlZFlags, ErlRelFlags}) -> - if ErlFlags == false -> ok; - true -> os:putenv("ERL_FLAGS", ErlFlags) - end, - if ErlAFlags == false -> ok; - true -> os:putenv("ERL_AFLAGS", ErlAFlags) - end, - if ErlZFlags == false -> ok; - true -> os:putenv("ERL_ZFLAGS", ErlZFlags) - end, - if ErlRelFlags == false -> ok; - true -> - ErlRelFlagsName = - "ERL_OTP" - ++ erlang:system_info(otp_release) - ++ "_FLAGS", - os:putenv(ErlRelFlagsName, ErlRelFlags) - end, - ok. diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c index c94c265f4e0f..36dbce9f20de 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -24,7 +24,7 @@ #include #if defined(__WIN32__) && SIZEOF_VOID_P == 8 -/* Use larger threashold for win64 as block alignment +/* Use larger threshold for win64 as block alignment is 16 bytes and not 8 */ #define SBCT ((1024*1024)) #else diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c index 7791409a3468..cbab000db721 100644 --- a/erts/emulator/test/alloc_SUITE_data/coalesce.c +++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c @@ -126,7 +126,7 @@ test_free(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) FREE(a, p[0]); FREE(a, p[6]); - testcase_printf(tcs," --- free() with block size %lu succeded ---\n",bsz); + testcase_printf(tcs," --- free() with block size %lu succeeded ---\n",bsz); } static void @@ -195,7 +195,7 @@ test_realloc(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) ASSERT(tcs, IS_FREE_BLK(blk)); ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2])); - /* Grow upto next alloced block by allocating just enough so that no + /* Grow up to next allocated block by allocating just enough so that no free block fits between them */ nbsz = BLK_SZ(blk) + UMEM_SZ(UMEM2BLK(p[0])); nbsz -= MIN_BLK_SZ(a) - 1; @@ -227,7 +227,7 @@ test_realloc(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) ASSERT(tcs, blk == UMEM2BLK(p[2])); /* Shrink just as much so that a free block can fit between - the alloced blocks */ + the allocated blocks */ nbsz -= 1; ptr = REALLOC(a, p[0], nbsz); ASSERT(tcs, p[0] == ptr); @@ -253,7 +253,7 @@ test_realloc(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz) FREE(a, p[0]); FREE(a, p[2]); - testcase_printf(tcs, " --- realloc() with block size %lu succeded ---\n", + testcase_printf(tcs, " --- realloc() with block size %lu succeeded ---\n", bsz); } diff --git a/erts/emulator/test/beam_SUITE.erl b/erts/emulator/test/beam_SUITE.erl index 584bec967bcd..d44e038d1b9a 100644 --- a/erts/emulator/test/beam_SUITE.erl +++ b/erts/emulator/test/beam_SUITE.erl @@ -239,7 +239,7 @@ heap_sizes(Config) when is_list(Config) -> %% Verify that the largest heap size consists of %% - 31 bits of bytes on 32 bits arch - %% - atleast 52 bits of bytes (48 is the maximum virtual address) + %% - at least 52 bits of bytes (48 is the maximum virtual address) %% and at the most 63 bits on 64 bit archs %% heap sizes are in words case erlang:system_info(wordsize) of diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 27d8210c7653..5f66122ee760 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2022. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -37,12 +37,14 @@ error_stacktrace_during_call_trace/1, group_leader_prio/1, group_leader_prio_dirty/1, is_process_alive/1, + is_process_alive_signal_from/1, process_info_blast/1, os_env_case_sensitivity/1, verify_middle_queue_save/1, test_length/1, fixed_apply_badarg/1, - external_fun_apply3/1]). + external_fun_apply3/1, + node_1/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -57,9 +59,10 @@ all() -> erl_crash_dump_bytes, min_max, erlang_halt, is_builtin, error_stacktrace, error_stacktrace_during_call_trace, group_leader_prio, group_leader_prio_dirty, - is_process_alive, process_info_blast, os_env_case_sensitivity, + is_process_alive, is_process_alive_signal_from, + process_info_blast, os_env_case_sensitivity, verify_middle_queue_save, test_length,fixed_apply_badarg, - external_fun_apply3]. + external_fun_apply3, node_1]. init_per_testcase(guard_bifs_in_erl_bif_types, Config) when is_list(Config) -> skip_missing_erl_bif_types(Config); @@ -70,8 +73,8 @@ init_per_testcase(shadow_comments, Config) when is_list(Config) -> init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> Config. -end_per_testcase(_Func, _Config) -> - ok. +end_per_testcase(_Func, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). %% erl_bif_types comes from dialyzer which some test runs skip building, so %% we'll skip the tests that use it as the result shouldn't vary based on @@ -85,11 +88,9 @@ skip_missing_erl_bif_types(Config) -> %% Uses erlang:display to test that erts_printf does not do deep recursion display(Config) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - {ok, Node} = test_server:start_node(display_huge_term,peer, - [{args, "-pa \""++Pa++"\""}]), + {ok, Peer, Node} = ?CT_PEER(), true = rpc:call(Node,?MODULE,display_huge,[]), - test_server:stop_node(Node), + peer:stop(Peer), ok. display_huge() -> @@ -356,6 +357,11 @@ auto_imports([], Errors) -> extract_functions(M, Abstr) -> [{{M,F,A},Body} || {function,_,F,A,Body} <- Abstr]. +check_stub({_,F,2}, _B) when F =:= min; F =:= max -> + %% In Erlang/OTP 26, min/2 and max/2 are guard BIFs. For backward + %% compatibility with code compiled with an earlier version, the + %% Erlang implementation of them is kept. + ok; check_stub({_,F,A}, B) -> try [{clause,_,Args,[],Body}] = B, @@ -724,33 +730,147 @@ fail_atom_to_binary(Term) -> end. -min_max(Config) when is_list(Config) -> - a = erlang:min(id(a), a), - a = erlang:min(id(a), b), - a = erlang:min(id(b), a), - b = erlang:min(id(b), b), - a = erlang:max(id(a), a), - b = erlang:max(id(a), b), - b = erlang:max(id(b), a), - b = erlang:max(id(b), b), - - 42.0 = erlang:min(42.0, 42), - 42.0 = erlang:max(42.0, 42), - %% And now (R14) they are also autoimported! +min_max(Config) when is_list(Config) -> + Self = self(), + Port = hd(erlang:ports()), + Ref = make_ref(), a = min(id(a), a), a = min(id(a), b), a = min(id(b), a), b = min(id(b), b), + Ref = min(id(Self), id(Ref)), + + -3 = min(id(5), -3), + -3 = min(-3, id(5)), + -3 = min(0, id(-3)), + -3 = min(id(-3), 0), + 0 = min(0, id(17)), + a = max(id(a), a), b = max(id(a), b), b = max(id(b), a), b = max(id(b), b), + Self = max(id(Self), id(Ref)), + + 5 = max(id(5), -3), + 5 = max(-3, id(5)), + 0 = max(0, id(-3)), + 0 = max(id(-3), 0), + 17 = max(0, id(17)), + + %% Return the first argument when arguments are equal. + 42.0 = min(id(42.0), 42), + 42.0 = max(id(42.0), 42), + + Min = id(min), + Max = id(max), + + "abc" = erlang:Min("abc", "def"), + <<"def">> = erlang:Max(<<"abc">>, <<"def">>), + + %% Make sure that the JIT doesn't do any unsafe optimizations. + {0, 0} = min_max_zero(0), + {-7, 0} = min_max_zero(-7), + {0, 555} = min_max_zero(555), + {0, 1 bsl 64} = min_max_zero(1 bsl 64), + {-1 bsl 64, 0} = min_max_zero(-1 bsl 64), + + {-99, 23} = do_min_max(-99, 23), + {-10, 0} = do_min_max(0, -10), + {0, 77} = do_min_max(77, 0), + {1, 2} = do_min_max(1, 2), + {42, 99} = do_min_max(99, 42), + {100, 1 bsl 64} = do_min_max(100, 1 bsl 64), + {-1 bsl 64, 77} = do_min_max(77, -1 bsl 64), + {-1 bsl 64, 1 bsl 64} = do_min_max(1 bsl 64, -1 bsl 64), + {42.0, 43} = do_min_max(42.0, 43), + {42.0, 50.0} = do_min_max(42.0, 50.0), + {42.0, 42.0} = do_min_max(42.0, id(40.0 + 2.0)), + {{1,2}, {a,b}} = do_min_max({id(a), id(b)}, {id(1), id(2)}), + {{a,b}, [a,b]} = do_min_max({a,id(b)}, [a,id(b)]), + {{1.0,b}, {1.0,b}} = do_min_max({id(1.0), id(b)}, {id(1), id(b)}), + {{7,b}, {7,b}} = do_min_max({id(7), id(b)}, {id(7.0), id(b)}), + + {42,Self} = do_min_max(42, Self), + {42,Self} = do_min_max(Self, 42), + {42,Port} = do_min_max(42, Port), + {42,Port} = do_min_max(Port, 42), - 42.0 = min(42.0, 42), - 42.0 = max(42.0, 42), ok. +min_max_zero(A0) -> + Result = {min(A0, 0), max(A0, 0)}, + Result = {min(0, A0), max(0, A0)}, + A = id(A0), + Result = {min(A, 0), max(A, 0)}, + Result = {min(0, A), max(0, A)}. + +do_min_max(A0, B0) -> + Result = {min(A0, B0), max(A0, B0)}, + + A0 = min(id(A0), A0), + A0 = max(id(A0), A0), + B0 = min(id(B0), B0), + B0 = max(id(B0), B0), + + A = id(A0), + B = id(B0), + Result = {min(A, B), max(A, B)}, + + if + is_integer(A), is_atom(node(B)) orelse is_integer(B) -> + _ = id(0), + Result = {min(A, B),max(A, B)}; + is_atom(node(A)) orelse is_integer(A), is_integer(B) -> + _ = id(0), + Result = {min(A, B),max(A, B)}; + true -> + ok + end, + + if + is_integer(A), 0 =< A, A =< 1000, is_atom(node(B)) orelse is_integer(B) -> + _ = id(0), + Result = {min(A, B),max(A, B)}; + is_atom(node(A)) orelse is_integer(A), is_integer(B), 0 =< B, B =< 1000 -> + _ = id(0), + Result = {min(A, B),max(A, B)}; + true -> + ok + end, + Result = do_min_max_1(1, 2, 3, 4, 5, A, B). + +do_min_max_1(_, _, _, _, _, A, B) -> + if + is_integer(A), 0 =< A, A < 16#1_0000, + is_integer(B), 0 =< B, B < 16#1_0000 -> + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}, + _ = id(0), + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}; + is_integer(A), is_integer(B) -> + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}, + _ = id(0), + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}; + is_float(A), is_float(B) -> + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}, + _ = id(0), + Result = {min(A, B),max(A, B)}, + Result = {min(B, A),max(B, A)}; + is_number(A), is_number(B) -> + Result = {min(A, B),max(A, B)}, + _ = id(0), + Result = {min(A, B),max(A, B)}; + true -> + Result = {min(A, B),max(A, B)}, + _ = id(0), + Result = {min(A, B),max(A, B)} + end. erlang_halt(Config) when is_list(Config) -> try erlang:halt(undefined) of @@ -780,33 +900,32 @@ erlang_halt(Config) when is_list(Config) -> try halt(0, [{flush,true,undefined}]) of _-> ct:fail({halt,{0,[{flush,true,undefined}]}}) catch error:badarg -> ok end, - H = hostname(), - {ok,N1} = slave:start(H, halt_node1), + {ok, _, N1} = ?CT_PEER(), {badrpc,nodedown} = rpc:call(N1, erlang, halt, []), - {ok,N2} = slave:start(H, halt_node2), + {ok, _, N2} = ?CT_PEER(), {badrpc,nodedown} = rpc:call(N2, erlang, halt, [0]), - {ok,N3} = slave:start(H, halt_node3), + {ok, _, N3} = ?CT_PEER(), {badrpc,nodedown} = rpc:call(N3, erlang, halt, [0,[]]), - {ok,N4} = slave:start(H, halt_node4), + {ok, _, N4} = ?CT_PEER(), {badrpc,nodedown} = rpc:call(N4, erlang, halt, [lists:duplicate(300,$x)]), %% Test unicode slogan - {ok,N4} = slave:start(H, halt_node4), - {badrpc,nodedown} = rpc:call(N4, erlang, halt, [[339,338,254,230,198,295,167,223,32,12507,12531,12480]]), + {ok, _, N5} = ?CT_PEER(), + {badrpc,nodedown} = rpc:call(N5, erlang, halt, [[339,338,254,230,198,295,167,223,32,12507,12531,12480]]), % This test triggers a segfault when dumping a crash dump % to make sure that we can handle it properly. %% Prevent address sanitizer from catching SEGV in slave node AsanOpts = add_asan_opt("handle_segv=0"), - {ok,N4} = slave:start(H, halt_node4), + {ok, _, N6} = ?CT_PEER(), reset_asan_opts(AsanOpts), CrashDump = filename:join(proplists:get_value(priv_dir,Config), "segfault_erl_crash.dump"), - true = rpc:call(N4, os, putenv, ["ERL_CRASH_DUMP",CrashDump]), - false = rpc:call(N4, erts_debug, set_internal_state, + true = rpc:call(N6, os, putenv, ["ERL_CRASH_DUMP",CrashDump]), + false = rpc:call(N6, erts_debug, set_internal_state, [available_internal_state, true]), - {badrpc,nodedown} = rpc:call(N4, erts_debug, set_internal_state, + {badrpc,nodedown} = rpc:call(N6, erts_debug, set_internal_state, [broken_halt, "Validate correct crash dump"]), {ok,_} = wait_until_stable_size(CrashDump,-1), {ok, Bin} = file:read_file(CrashDump), @@ -863,8 +982,7 @@ erl_crash_dump_bytes(Config) when is_list(Config) -> ok. do_limited_crash_dump(Config, Bytes) -> - H = hostname(), - {ok,N} = slave:start(H, halt_node), + {ok, _, N} = ?CT_PEER(), BytesStr = integer_to_list(Bytes), CrashDump = filename:join(proplists:get_value(priv_dir,Config), "erl_crash." ++ BytesStr ++ ".dump"), @@ -1113,7 +1231,7 @@ group_leader_prio_test(Dirty) -> end, 100}; true -> - %% These processes wont handle incoming signals by + %% These processes won't handle incoming signals by %% them selves since they are stuck on dirty schedulers %% when we try to change group leader. A dirty process %% signal handler process (system process) will be notified @@ -1212,6 +1330,51 @@ is_process_alive(Config) when is_list(Config) -> Ps), ok. +is_process_alive_signal_from(Config) when is_list(Config) -> + process_flag(priority, high), + process_flag(scheduler, 1), + Schdlr = case erlang:system_info(schedulers_online) of + 1 -> 1; + _ -> 2 + end, + X = is_process_alive_signal_from_test(100000, 0, Schdlr), + erlang:display({exits_detected, X}), + {comment, integer_to_list(X) ++ " exited processes detected"}. + +is_process_alive_signal_from_test(0, X, _Schdlr) -> + X; +is_process_alive_signal_from_test(N, X, Schdlr) -> + Tester = self(), + {Testee, TMon} = spawn_opt(fun () -> + Mon = erlang:monitor(process, Tester), + Tester ! {self(), ready}, + busy_wait_go(), + _ = erlang:demonitor(Mon), + exit(normal) + end, + [link, + monitor, + {priority, high}, + {scheduler, Schdlr}]), + receive {Testee, ready} -> ok end, + {monitored_by, MBList1} = process_info(self(), monitored_by), + true = lists:member(Testee, MBList1), + erlang:yield(), + Testee ! {go, ok}, + erlang:yield(), + NewX = case erlang:is_process_alive(Testee) of + true -> + X; + false -> + %% Demonitor signal should have reached us before the + %% is-process-alive reply... + {monitored_by, MBList2} = process_info(self(), monitored_by), + false = lists:member(Testee, MBList2), + X+1 + end, + receive {'DOWN', TMon, process, Testee, normal} -> ok end, + is_process_alive_signal_from_test(N-1, NewX, Schdlr). + process_info_blast(Config) when is_list(Config) -> Tester = self(), NoAttackers = 1000, @@ -1402,8 +1565,84 @@ external_fun_apply3(_Config) -> ok. +node_1(_Config) -> + {ok, Peer, Node} = ?CT_PEER(), + + local_node(self()), + LocalPort = lists:last(erlang:ports()), + local_node(LocalPort), + local_node(make_ref()), + + external_node(erpc:call(Node, erlang, self, []), Node), + ExtPort = hd(erpc:call(Node, erlang, ports, [])), + external_node(ExtPort, Node), + external_node(erpc:call(Node, erlang, make_ref, []), Node), + + node_error(a), + node_error(42), + node_error({a,b,c}), + node_error({tag,self()}), + node_error([self()]), + node_error(1 bsl 133), + node_error(#{}), + node_error(#{id(a) => b}), + node_error(<<"binary">>), + + peer:stop(Peer), + ok. + +local_node(E) -> + test_node(E, node()). + +external_node(E, Node) -> + test_node(E, Node). + +test_node(E0, Node) -> + true = node(id(E0)) =:= Node, + E = id(E0), + if + node(E) =:= Node -> + ok + end, + test_node_2(id(E), Node). + +test_node_2(E, Node) when is_pid(E); is_port(E); is_reference(E) -> + true = node(E) =:= Node, + if + node(E) =:= Node -> + ok + end, + test_node_3(id(E), Node), + ok. + +test_node_3(E, Node) when is_pid(E) -> + true = node(E) =:= Node; +test_node_3(E, Node) when is_port(E) -> + true = node(E) =:= Node; +test_node_3(E, Node) when is_reference(E) -> + true = node(E) =:= Node. + +node_error(E0) -> + E = id(E0), + {'EXIT',{badarg,[{erlang,node,[E],_}|_]}} = catch node(E), + if + node(E) -> + ct:fail(should_fail); + true -> + ok + end. + %% helpers - + +busy_wait_go() -> + receive + {go, Info} -> + Info + after + 0 -> + busy_wait_go() + end. + id(I) -> I. %% Get code path, including the path for the erts application. @@ -1435,14 +1674,6 @@ extract_abstract(Mod, Path) -> {Mod,Abstr}. -hostname() -> - hostname(atom_to_list(node())). - -hostname([$@ | Hostname]) -> - list_to_atom(Hostname); -hostname([_C | Cs]) -> - hostname(Cs). - tok_loop() -> tok_loop(hej). diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index d69027c14b5d..9d69741b8ba8 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -50,6 +50,7 @@ t_split_binary/1, bad_split/1, terms/1, terms_float/1, float_middle_endian/1, b2t_used_big/1, t2b_deterministic/1, + t2b_minor_version/1, external_size/1, t_iolist_size/1, t_iolist_size_huge_list/1, t_iolist_size_huge_bad_arg_list/1, @@ -71,12 +72,13 @@ ordering/1,unaligned_order/1,gc_test/1, bit_sized_binary_sizes/1, otp_6817/1,deep/1, - term2bin_tuple_fallbacks/1, robustness/1,otp_8117/1, otp_8180/1, trapping/1, large/1, error_after_yield/1, cmp_old_impl/1, t2b_system_limit/1, - term_to_iovec/1]). + term_to_iovec/1, + is_binary_test/1, + local_ext/1]). %% Internal exports. -export([sleeper/0,trapping_loop/4]). @@ -93,6 +95,7 @@ all() -> t_iolist_size_huge_bad_arg_list, {group, iolist_size_benchmarks}, b2t_used_big, t2b_deterministic, + t2b_minor_version, bad_binary_to_term_2, safe_binary_to_term2, bad_binary_to_term, bad_terms, t_hash, bad_size, big_binary_to_term, @@ -102,9 +105,10 @@ all() -> otp_5484, otp_5933, ordering, unaligned_order, gc_test, bit_sized_binary_sizes, otp_6817, otp_8117, deep, - term2bin_tuple_fallbacks, robustness, otp_8180, trapping, large, - error_after_yield, cmp_old_impl]. + error_after_yield, cmp_old_impl, + is_binary_test, + local_ext]. groups() -> [ @@ -152,6 +156,15 @@ end_per_testcase(_Func, _Config) -> -define(heap_binary_size, 64). +-define(MAP_EXT, 116). +-define(SMALL_INTEGER_EXT, 97). +-define(SMALL_ATOM_UTF8_EXT, 119). +-define(ATOM_EXT, 100). +-define(NIL, 106). +-define(MAP_SMALL_MAP_LIMIT, 32). +-define(FLOAT_EXT, 99). +-define(NEW_FLOAT_EXT, 70). + copy_terms(Config) when is_list(Config) -> Self = self(), Pid = spawn_link(fun() -> copy_server(Self) end), @@ -475,10 +488,8 @@ bad_term_to_binary(Config) when is_list(Config) -> t2b_system_limit(Config) when is_list(Config) -> case erlang:system_info(wordsize) of 8 -> - case proplists:get_value(system_total_memory, - memsup:get_system_memory_data()) of - Memory when is_integer(Memory), - Memory > 6*1024*1024*1024 -> + case total_memory() of + Memory when is_integer(Memory), Memory > 6 -> do_t2b_system_limit(); _ -> {skipped, "Not enough memory on this machine"} @@ -501,9 +512,9 @@ do_t2b_system_limit() -> garbage_collect(), ok end, - Opts = [{args, "-pa " ++ filename:dirname(code:which(?MODULE))}], - {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, Opts), - erpc:call(Node, F). + {ok, Peer, Node} = ?CT_PEER(), + erpc:call(Node, F), + peer:stop(Peer). test_t2b_system_limit(HugeBin, Name, F1, F2) -> io:format("Testing ~p(HugeBin)~n", [Name]), @@ -690,6 +701,53 @@ float_middle_endian(Config) when is_list(Config) -> <<131,70,63,240,0,0,0,0,0,0>> = term_to_binary(1.0, [{minor_version,1}]), 1.0 = binary_to_term_stress(<<131,70,63,240,0,0,0,0,0,0>>). +t2b_minor_version(_Config) -> + Umlaut = "ätöm", + UmlautLatin1 = unicode:characters_to_binary(Umlaut, latin1, latin1), + UmlautUtf8 = unicode:characters_to_binary(Umlaut, latin1, utf8), + UmlautAtom = binary_to_atom(UmlautLatin1, latin1), + UmlautAtom = binary_to_atom(UmlautUtf8, utf8), + ExoticBin = <<"こんにちは"/utf8>>, + ExoticAtom = binary_to_atom(ExoticBin, utf8), + + <<131, ?SMALL_ATOM_UTF8_EXT, 4, "atom">> = term_to_binary(atom), + <<131, ?SMALL_ATOM_UTF8_EXT, 6, UmlautUtf8/binary>> = + term_to_binary(UmlautAtom), + <<131, ?SMALL_ATOM_UTF8_EXT, 15, ExoticBin/binary>> = + term_to_binary(ExoticAtom), + + <<131, ?SMALL_ATOM_UTF8_EXT, 4, "atom">> = + term_to_binary(atom, [{minor_version,2}]), + <<131, ?SMALL_ATOM_UTF8_EXT, 6, UmlautUtf8/binary>> = + term_to_binary(UmlautAtom, [{minor_version,2}]), + <<131, ?SMALL_ATOM_UTF8_EXT, 15, ExoticBin/binary>> = + term_to_binary(ExoticAtom, [{minor_version,2}]), + + <<131, ?ATOM_EXT, 4:16, "atom">> = + term_to_binary(atom, [{minor_version,1}]), + <<131, ?ATOM_EXT, 4:16, UmlautLatin1/binary>> = + term_to_binary(UmlautAtom, [{minor_version,1}]), + <<131, ?SMALL_ATOM_UTF8_EXT, 15, ExoticBin/binary>> = + term_to_binary(ExoticAtom, [{minor_version,1}]), + + <<131, ?ATOM_EXT, 4:16, "atom">> = + term_to_binary(atom, [{minor_version,0}]), + <<131, ?ATOM_EXT, 4:16, UmlautLatin1/binary>> = + term_to_binary(UmlautAtom, [{minor_version,0}]), + <<131, ?SMALL_ATOM_UTF8_EXT, 15, ExoticBin/binary>> = + term_to_binary(ExoticAtom, [{minor_version,0}]), + + <<131,?NEW_FLOAT_EXT,64,9,30,184,81,235,133,31>> = + term_to_binary(3.14), + <<131,?NEW_FLOAT_EXT,64,9,30,184,81,235,133,31>> = + term_to_binary(3.14, [{minor_version, 2}]), + <<131,?NEW_FLOAT_EXT,64,9,30,184,81,235,133,31>> = + term_to_binary(3.14, [{minor_version, 1}]), + <<131,?FLOAT_EXT,FloatStr:31/binary>> = + term_to_binary(3.14, [{minor_version, 0}]), + 3.14 = binary_to_float(FloatStr), + ok. + %% Test term_to_binary(Term, [deterministic]). t2b_deterministic(_Config) -> _ = rand:uniform(), %Seed generator @@ -925,10 +983,8 @@ build_iolist(N0, Base) -> [47,L,L|Seq] end. -approx_4GB_bin() -> - Bin = lists:duplicate(4194304, 255), - BinRet = erlang:iolist_to_binary(lists:duplicate(1124, Bin)), - BinRet. +approx_1GB_bin() -> + iolist_to_binary(lists:duplicate(281, <<-1:4194304/unit:8>>)). duplicate_iolist(IOList, 0) -> IOList; @@ -938,9 +994,15 @@ duplicate_iolist(IOList, NrOfTimes) -> t_iolist_size_huge_list(Config) when is_list(Config) -> run_when_enough_resources( fun() -> - {TimeToCreateIOList, IOList} = timer:tc(fun()->duplicate_iolist(approx_4GB_bin(), 32) end), - {IOListSizeTime, CalculatedSize} = timer:tc(fun()->erlang:iolist_size(IOList) end), - 20248183924657750016 = CalculatedSize, + {TimeToCreateIOList, IOList} = + timer:tc(fun() -> + duplicate_iolist(approx_1GB_bin(), 32) + end), + {IOListSizeTime, CalculatedSize} = + timer:tc(fun() -> + iolist_size(IOList) + end), + 5062045981164437504 = CalculatedSize, {comment, io_lib:format("Time to create iolist: ~f s. Time to calculate size: ~f s.", [TimeToCreateIOList / 1000000, IOListSizeTime / 1000000])} end). @@ -949,9 +1011,10 @@ t_iolist_size_huge_bad_arg_list(Config) when is_list(Config) -> run_when_enough_resources( fun() -> P = self(), - spawn_link(fun()-> IOListTmp = duplicate_iolist(approx_4GB_bin(), 32), + spawn_link(fun() -> + IOListTmp = duplicate_iolist(approx_1GB_bin(), 32), IOList = [IOListTmp, [badarg]], - {'EXIT',{badarg,_}} = (catch erlang:iolist_size(IOList)), + {'EXIT',{badarg,_}} = catch iolist_size(IOList), P ! ok end), receive ok -> ok end @@ -1038,15 +1101,14 @@ report_throughput(Fun, NrOfItems) -> total_memory() -> %% Total memory in GB. try - MemoryData = memsup:get_system_memory_data(), - case lists:keysearch(total_memory, 1, MemoryData) of - {value, {total_memory, TM}} -> - TM div (1024*1024*1024); - false -> - {value, {system_total_memory, STM}} = - lists:keysearch(system_total_memory, 1, MemoryData), - STM div (1024*1024*1024) - end + SMD = memsup:get_system_memory_data(), + TM = proplists:get_value( + available_memory, SMD, + proplists:get_value( + total_memory, SMD, + proplists:get_value( + system_total_memory, SMD))), + TM div (1024*1024*1024) catch _ : _ -> undefined @@ -1071,7 +1133,7 @@ run_when_enough_resources(Fun) -> %% OTP-4053 bad_binary_to_term_2(Config) when is_list(Config) -> - {ok, N} = test_server:start_node(plopp, slave, []), + {ok, Peer, N} = ?CT_PEER(), R = rpc:call(N, erlang, binary_to_term, [<<131,111,255,255,255,0>>]), case R of {badrpc, {'EXIT', _}} -> @@ -1079,7 +1141,7 @@ bad_binary_to_term_2(Config) when is_list(Config) -> _Other -> ct:fail({rpcresult, R}) end, - test_server:stop_node(N), + peer:stop(Peer), ok. %% Try bad input to binary_to_term/1. @@ -1106,10 +1168,6 @@ bad_bin_to_term(BadBin) -> bad_bin_to_term(BadBin,Opts) -> {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin,Opts)). --define(MAP_EXT, 116). --define(SMALL_INTEGER_EXT, 97). --define(NIL, 106). --define(MAP_SMALL_MAP_LIMIT, 32). %% OTP-18343: Decode unsorted flatmap as key in hashmap unsorted_map_in_map(Config) when is_list(Config) -> @@ -1598,11 +1656,14 @@ test_terms(Test_Func) -> Test_Func("abcdef"), Test_Func([a, b, 1, 2]), Test_Func([a|b]), + Test_Func([make_port(), make_ref(), make_pid(), fun() -> ok end, + Very_Big | lists:seq(1, 75)]), Test_Func({}), Test_Func({1}), Test_Func({a, b}), Test_Func({a, b, c}), + Test_Func({make_port(), make_ref(), make_pid(), fun() -> ok end}), Test_Func(list_to_tuple(lists:seq(0, 255))), Test_Func(list_to_tuple(lists:seq(0, 256))), @@ -1653,9 +1714,11 @@ test_terms(Test_Func) -> Test_Func(<<42:10>>), Test_Func(list_to_bitstring([<<5:6>>|lists:seq(0, 255)])), + %% Funs in a list. Test_Func(F = fun(A) -> 42*A end), Test_Func(lists:duplicate(32, F)), + %% External funs in a list. Test_Func(FF = fun binary_SUITE:all/0), Test_Func(lists:duplicate(32, FF)), @@ -1796,29 +1859,6 @@ deep_roundtrip(T) -> B = term_to_binary(T), T = binary_to_term(B). -term2bin_tuple_fallbacks(Config) when is_list(Config) -> - erts_debug:set_internal_state(available_internal_state, true), - - term2bin_tf(fun ?MODULE:all/1), - term2bin_tf(<<1:1>>), - term2bin_tf(<<90,80:7>>), - - erts_debug:set_internal_state(available_internal_state, false), - ok. - -term2bin_tf(Term) -> - Tuple = case Term of - Fun when is_function(Fun) -> - {type, external} = erlang:fun_info(Fun, type), - {module,M} = erlang:fun_info(Fun, module), - {name,F} = erlang:fun_info(Fun, name), - {M,F}; - BS when bit_size(BS) rem 8 =/= 0 -> - Bits = bit_size(BS) rem 8, - {<>, Bits} - end, - Tuple = binary_to_term_stress(erts_debug:get_internal_state({term_to_binary_tuple_fallbacks,Term})). - %% Test non-standard encodings never generated by term_to_binary/1 %% but recognized by binary_to_term/1. @@ -2027,18 +2067,11 @@ cmp_old_impl(Config) when is_list(Config) -> %% implementation in R16B. Since OTP 22 we can't talk distribution with such %% old nodes (< 19). The test case it kept but compares with previous major %% version for semantic regression test. - Cookie = atom_to_list(erlang:get_cookie()), - Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1) - ++ "_latest"), - case test_server:is_release_available(Rel) of - false -> + Rel = integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1), + case ?CT_PEER_REL([], Rel, proplists:get_value(priv_dir, Config)) of + not_available -> {skipped, "No OTP "++Rel++" available"}; - true -> - {ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel), - peer, - [{args, " -setcookie "++Cookie}, - {erl, [{release, Rel}]}]), - + {ok, Peer, Node} -> cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(1))]}), cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(10))]}), cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(100))]}), @@ -2076,7 +2109,7 @@ cmp_old_impl(Config) when is_list(Config) -> cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(1000000)))]}), cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(10000000)))]}), - test_server:stop_node(Node), + peer:stop(Peer), ok end. @@ -2116,6 +2149,28 @@ echo(Papa) -> receive M -> Papa ! M end, echo(Papa). +%% GH-6239. +is_binary_test(_Config) -> + <<"foo42">> = concat_stuff(foo, 42), + <<"foo2749963626218098647">> = concat_stuff(foo, 2749963626218098647), %Bignum. + <<"foobar">> = concat_stuff(foo, <<"bar">>), + <<"bar100">> = concat_stuff(<<"bar">>, 100), + <<"bar2749963626218098647">> = concat_stuff(<<"bar">>, 2749963626218098647), %Bignum. + <<"barfood">> = concat_stuff(<<"bar">>, <<"food">>), + + ok. + +concat_stuff(A, B) when is_integer(B); is_binary(B) -> + <<(case A of + X when is_binary(X) -> X; + _ -> atom_to_binary(A) + end)/binary, + (case B of + %% The JIT would do an unsafe simplification of the is_binary/1 test, + %% accepting any boxed term (such as a bignum) as a binary. + Y when is_binary(Y) -> Y; + _ -> integer_to_binary(B) + end)/binary>>. %% Utilities. @@ -2295,3 +2350,177 @@ list2bitstrlist([X0, X1, X2, X3, X4, X5 | Xs], Acc) when is_integer(X0), 0 =< X0 list2bitstrlist(Xs, NewAcc); list2bitstrlist([X | Xs], Acc) -> list2bitstrlist(Xs, [Acc,X]). + +local_ext(Config) when is_list(Config) -> + SDrv = send_term_local_drv, + CDrv = call_local_drv, + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + FileName = filename:join(PrivDir, "local_ext.data"), + Args = ["-setcookie", atom_to_list(erlang:get_cookie()), + "-pa", filename:dirname(code:which(?MODULE))], + {ok, Peer1, _} = peer:start_link(#{connection => 0, args => Args}), + {ok, Peer2, _} = peer:start_link(#{connection => 0, args => Args}), + LongNames = net_kernel:longnames(), + DynStartOpts = #{name_domain => if LongNames -> longnames; + true -> shortnames + end}, + ExternalPid = self(), + ExternalRef = make_ref(), + ExternalPort = hd(erlang:ports()), + EncDecLocal = fun () -> + erl_ddll:start(), + ok = erl_ddll:load_driver(DataDir, SDrv), + SPort = open_port({spawn, SDrv}, []), + ok = erl_ddll:load_driver(DataDir, CDrv), + CPort = open_port({spawn, CDrv}, []), + false = erlang:is_alive(), + nonode@nohost = node(), + LocalPid = self(), + LocalRef = make_ref(), + LocalPort = hd(erlang:ports()), + Bin1 = <<4711:800>>, + Bin2 = <<4711:703>>, + Bin3 = <<4711:600>>, + Terms = [ + LocalPid, + ExternalPid, + LocalRef, + ExternalRef, + LocalPort, + ExternalPort, + [LocalPid, Bin1, ExternalPid, LocalRef, Bin2, + ExternalRef, Bin3, Bin2, LocalPort, + ExternalPort], + "hej", + [], + {processes(), Bin3, erlang:ports(), Bin3}, + #{pid => LocalPid, ref => LocalRef, port => LocalPort} + ], + {ok, FD} = file:open(FileName, [write]), + ETs = lists:map(fun (Term) -> + {enc_local(FD, Term), Term} + end, Terms), + ok = file:close(FD), + CheckET = fun ({LExt, Term}) -> + Term = binary_to_term(LExt), + SPort ! {self(), {command, LExt}}, + receive + {SPort, Reply} -> + Term = Reply + end + end, + lists:foreach(CheckET, ETs), + call_local_success(CPort, ETs), + NodeName = peer:random_name(), + {ok, _} = net_kernel:start(list_to_atom(NodeName), + DynStartOpts), + true = erlang:is_alive(), + true = nonode@nohost /= node(), + lists:foreach(CheckET, ETs), + call_local_success(CPort, ETs), + ok = net_kernel:stop(), + false = erlang:is_alive(), + nonode@nohost = node(), + lists:foreach(CheckET, ETs), + call_local_success(CPort, ETs), + {ok, ExtList} = file:consult(FileName), + lists:foreach(fun (Ext) when is_binary(Ext) -> + _ = binary_to_term(Ext), + SPort ! {self(), {command, Ext}}, + receive + {SPort, "bad_term_error"} -> + error(bad_term_error); + {SPort, _} -> + ok + end + end, + ExtList), + true = port_close(SPort), + true = port_close(CPort), + ok + end, + ok = peer:call(Peer1, erlang, apply, [EncDecLocal, []]), + DecOthersLocal = fun () -> + %% Verify that decoding of the terms encoded + %% on local external format by the other runtime + %% system instance fails on this runtime system + %% instance... + erl_ddll:start(), + ok = erl_ddll:load_driver(DataDir, SDrv), + SPort = open_port({spawn, SDrv}, []), + ok = erl_ddll:load_driver(DataDir, CDrv), + CPort = open_port({spawn, CDrv}, []), + false = erlang:is_alive(), + nonode@nohost = node(), + {ok, ExtList} = file:consult(FileName), + lists:foreach(fun (Ext) when is_binary(Ext) -> + try + Term = binary_to_term(Ext), + error({successful_decode, Term}) + catch + error:badarg -> + ok + end, + SPort ! {self(), {command, Ext}}, + receive + {SPort, Reply} -> + "bad_term_error" = Reply + end + end, + ExtList), + call_local_fail(CPort, ExtList), + true = port_close(SPort), + true = port_close(CPort), + ok + end, + ok = peer:call(Peer2, erlang, apply, [DecOthersLocal, []]), + peer:stop(Peer1), + peer:stop(Peer2), + ok. + +enc_local(FD, Term) -> + Ext = term_to_binary(Term, [local]), + Ext = iolist_to_binary(term_to_iovec(Term, [local])), + Term = binary_to_term(Ext), + io:format(FD, "~p.~n", [Ext]), + Ext. + +call_local_success(Port, []) -> + ok; +call_local_success(Port, [{Lext1, T1}]) -> + Me = self(), + Ref = make_ref(), + Term = {term_to_binary(Me), Lext1, term_to_binary(Ref)}, + {call_result, Me, 4711, T1, 17, Ref, "end_of_data"} = erlang:port_call(Port, 0, Term), + ok; +call_local_success(Port, [{Lext1, T1}, {Lext3, T3} | Rest]) -> + Me = self(), + Term = {Lext1, term_to_binary(Me), Lext3}, + {call_result, T1, 4711, Me, 17, T3, "end_of_data"} = erlang:port_call(Port, 0, Term), + call_local_success(Port, Rest). + +call_local_fail(Port, []) -> + ok; +call_local_fail(Port, [Lext1]) -> + Me = self(), + Ref = make_ref(), + Term = {term_to_binary(Me), Lext1, term_to_binary(Ref)}, + try + erlang:port_call(Port, 0, Term), + error(unexpected_port_call_success) + catch + error:badarg -> + ok + end; +call_local_fail(Port, [Lext1, Lext3 | Rest]) -> + Me = self(), + Term = {Lext1, term_to_binary(Me), Lext3}, + try + erlang:port_call(Port, 0, Term), + error(unexpected_port_call_success) + catch + error:badarg -> + ok + end, + call_local_fail(Port, Rest). diff --git a/erts/emulator/test/binary_SUITE_data/Makefile.src b/erts/emulator/test/binary_SUITE_data/Makefile.src new file mode 100644 index 000000000000..eb74303caf52 --- /dev/null +++ b/erts/emulator/test/binary_SUITE_data/Makefile.src @@ -0,0 +1,33 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2023. 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% +# + +include @erl_interface_mk_include@ + +CC = @CC@ +LD = @LD@ +CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@ +CROSSLDFLAGS = @CROSSLDFLAGS@ + +SHLIB_EXTRA_CFLAGS = @EI_CFLAGS@ -I@erl_interface_include@ +SHLIB_EXTRA_LDLIBS = @erl_interface_eilib@ @erl_interface_sock_libs@ + +all: send_term_local_drv@dll@ call_local_drv@dll@ + +@SHLIB_RULES@ diff --git a/erts/emulator/test/binary_SUITE_data/call_local_drv.c b/erts/emulator/test/binary_SUITE_data/call_local_drv.c new file mode 100644 index 000000000000..8db6c1c7724c --- /dev/null +++ b/erts/emulator/test/binary_SUITE_data/call_local_drv.c @@ -0,0 +1,204 @@ +/* ``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. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include +#include +#include "erl_driver.h" +#include "ei.h" + +static ErlDrvSSizeT call(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags); + +static ErlDrvEntry call_local_drv_entry = { + NULL /* init */, + NULL /* start */, + NULL /* stop */, + NULL /* output */, + NULL /* ready_input */, + NULL /* ready_output */, + "call_local_drv", + NULL /* finish */, + NULL /* handle */, + NULL /* control */, + NULL /* timeout */, + NULL /* outputv */, + NULL /* ready_async */, + NULL /* flush */, + call, + NULL /* event */, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL /* handle2 */, + NULL /* handle_monitor */ +}; + +DRIVER_INIT(call_local_drv) +{ + return &call_local_drv_entry; +} + + +static ErlDrvSSizeT call(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags) +{ + ei_x_buff xbuf; + void *bin1 = NULL, *bin2 = NULL, *bin3 = NULL; + char *lext1, *lext2, *lext3; + int vsn, arity, type, ix, lix, res, err, size; + long size1, size2, size3; + ErlDrvSSizeT ret_size = (ErlDrvSSizeT) ERL_DRV_ERROR_GENERAL; + + xbuf.buff = NULL; + + ei_init(); + + ix = 0; + res = ei_decode_version(buf, &ix, &vsn); + if (res != 0 || vsn != 131) + goto error; + + res = ei_decode_tuple_header(buf, &ix, &arity); + if (res != 0) + goto error; + + /* External term 1 */ + res = ei_get_type(buf, &ix, &type, &size); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + size1 = size; + bin1 = driver_alloc(size1); + + res = ei_decode_binary(buf, &ix, bin1, &size1); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + lext1 = bin1; + lix = 0; + res = ei_decode_version(lext1, &lix, &vsn); + if (res != 0 || vsn != 131) + goto error; + lext1 += lix; + size1 -= lix; + + /* External term 2 */ + res = ei_get_type(buf, &ix, &type, &size); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + size2 = size; + bin2 = driver_alloc(size2); + + res = ei_decode_binary(buf, &ix, bin2, &size2); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + lext2 = bin2; + lix = 0; + res = ei_decode_version(lext2, &lix, &vsn); + if (res != 0 || vsn != 131) + goto error; + lext2 += lix; + size2 -= lix; + + /* External term 3 */ + res = ei_get_type(buf, &ix, &type, &size); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + size3 = size; + bin3 = driver_alloc(size3); + + res = ei_decode_binary(buf, &ix, bin3, &size3); + if (res != 0 && type != ERL_BINARY_EXT) + goto error; + + lext3 = bin3; + lix = 0; + res = ei_decode_version(lext3, &lix, &vsn); + if (res != 0 || vsn != 131) + goto error; + lext3 += lix; + size3 -= lix; + + /* encode result */ + + res = ei_x_new_with_version(&xbuf); + if (res != 0) + goto error; + + res = ei_x_encode_tuple_header(&xbuf, 7); + if (res != 0) + goto error; + + res = ei_x_encode_atom(&xbuf, "call_result"); + if (res != 0) + goto error; + + res = ei_x_append_buf(&xbuf, lext1, size1); + if (res != 0) + goto error; + + res = ei_x_encode_long(&xbuf, 4711); + if (res != 0) + goto error; + + res = ei_x_append_buf(&xbuf, lext2, size2); + if (res != 0) + goto error; + + res = ei_x_encode_long(&xbuf, 17); + if (res != 0) + goto error; + + res = ei_x_append_buf(&xbuf, lext3, size3); + if (res != 0) + goto error; + + res = ei_x_encode_string(&xbuf, "end_of_data"); + if (res != 0) + goto error; + + /* success */ + ret_size = xbuf.index; + *rbuf = driver_alloc(ret_size); + memcpy((void *) *rbuf, (void *) xbuf.buff, ret_size); + +error: + + if (bin1) + driver_free(bin1); + if (bin2) + driver_free(bin2); + if (bin3) + driver_free(bin3); + + if (xbuf.buff) + ei_x_free(&xbuf); + + return ret_size; +} diff --git a/erts/emulator/test/binary_SUITE_data/send_term_local_drv.c b/erts/emulator/test/binary_SUITE_data/send_term_local_drv.c new file mode 100644 index 000000000000..a5335d4a0923 --- /dev/null +++ b/erts/emulator/test/binary_SUITE_data/send_term_local_drv.c @@ -0,0 +1,96 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2023. 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% + */ + +#include "erl_driver.h" +#include + +static void stop(ErlDrvData drv_data); +static ErlDrvData start(ErlDrvPort port, + char *command); +static void output(ErlDrvData drv_data, + char *buf, ErlDrvSizeT len); + +static ErlDrvEntry send_term_local_drv_entry = { + NULL /* init */, + start, + stop, + output, + NULL /* ready_input */, + NULL /* ready_output */, + "send_term_local_drv", + NULL /* finish */, + NULL /* handle */, + NULL /* control */, + NULL /* timeout */, + NULL /* outputv */, + NULL /* ready_async */, + NULL /* flush */, + NULL /* call */, + NULL /* event */, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL /* handle2 */, + NULL /* handle_monitor */ +}; + +DRIVER_INIT(send_term_local_drv) +{ + return &send_term_local_drv_entry; +} + +static void stop(ErlDrvData drv_data) +{ +} + +static ErlDrvData start(ErlDrvPort port, + char *command) +{ + + return (ErlDrvData) port; +} + +static void output(ErlDrvData drv_data, + char *buf, ErlDrvSizeT len) +{ + ErlDrvPort port = (ErlDrvPort) drv_data; + ErlDrvTermData term_port = driver_mk_port(port); + ErlDrvTermData caller = driver_caller(port); + int res; + ErlDrvTermData spec[] = { + ERL_DRV_PORT, term_port, + ERL_DRV_EXT2TERM, (ErlDrvTermData) buf, len, + ERL_DRV_TUPLE, 2 + }; + if (0 >= erl_drv_send_term(term_port, caller, + spec, sizeof(spec)/sizeof(spec[0]))) { + char *bad_term = "bad_term_error"; + ErlDrvTermData spec[] = { + ERL_DRV_PORT, term_port, + ERL_DRV_STRING, (ErlDrvTermData) bad_term, strlen(bad_term), + ERL_DRV_TUPLE, 2 + }; + if (0 >= erl_drv_send_term(term_port, caller, spec, + sizeof(spec)/sizeof(spec[0]))) { + driver_failure_atom(port, "failed_to_bad_term_error"); + } + } +} diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index 77716f85b54b..adf893d9993a 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -28,7 +28,9 @@ huge_float_field/1, system_limit/1, badarg/1, copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, otp_7422/1, zero_width/1, bad_append/1, bs_append_overflow/1, - reductions/1, fp16/1]). + bs_append_offheap/1, + reductions/1, fp16/1, zero_init/1, error_info/1, little/1, + heap_binary_unit/1]). -include_lib("common_test/include/ct.hrl"). @@ -41,7 +43,9 @@ all() -> in_guard, mem_leak, coerce_to_float, bjorn, append_empty_is_same, huge_float_field, system_limit, badarg, copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, - bad_append, bs_append_overflow, reductions, fp16]. + bad_append, bs_append_overflow, bs_append_offheap, + reductions, fp16, zero_init, + error_info, little, heap_binary_unit]. init_per_suite(Config) -> Config. @@ -49,14 +53,6 @@ init_per_suite(Config) -> end_per_suite(_Config) -> application:stop(os_mon). -big(1) -> - 57285702734876389752897683. - -i(X) -> X. - -r(L) -> - lists:reverse(L). - -define(T(B, L), {B, ??B, L}). -define(N(B), {B, ??B, unknown}). @@ -89,7 +85,7 @@ l(I_13, I_big1) -> ?T(<<57285702734876389752897684:32>>, [138, 99, 0, 148]), ?T(<>, - r([138, 99, 0, 147])), + lists:reverse([138, 99, 0, 147])), ?T(<<-1:17/unit:8>>, lists:duplicate(17, 255)), @@ -111,6 +107,9 @@ l(I_13, I_big1) -> ?T(<<4,3,<<1,2>>:1/binary>>, [4,3,1]), + ?T(<< <<153,27:5>>:I_13/bits, 1:3 >>, + [153,217]), + ?T(<<(256*45+47)>>, [47]), @@ -142,9 +141,74 @@ l(I_13, I_big1) -> ?T(<<<<5:3>>/bitstring>>, <<5:3>>), ?T(<<42,<<7:4>>/binary-unit:4>>, <<42,7:4>>), ?T(<<<<344:17>>/binary-unit:17>>, <<344:17>>), - ?T(<<<<42,3,7656:16>>/binary-unit:16>>, <<42,3,7656:16>>) - - ]. + ?T(<<<<42,3,7656:16>>/binary-unit:16>>, <<42,3,7656:16>>), + + %% Different sizes and types. First without types. + ?T(<>, [147]), + ?T(<>, [0, 147]), + ?T(<>, [99, 0, 147]), + ?T(<>, [138, 99, 0, 147]), + ?T(<>, [5, 138, 99, 0, 147]), + ?T(<>, [229, 5, 138, 99, 0, 147]), + ?T(<>, [249, 229, 5, 138, 99, 0, 147]), + ?T(<>, [42, 249, 229, 5, 138, 99, 0, 147]), + + %% Known integer with range. + ?T(<<(I_big1 band ((1 bsl 56) - 1)):8>>, [147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):16>>, [0, 147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):24>>, [99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):32>>, [138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):40>>, [5, 138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):48>>, [229, 5, 138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 56) - 1)):56>>, [249, 229, 5, 138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 64) - 1)):64>>, [42, 249, 229, 5, 138, 99, 0, 147]), + + %% Known integer with exact range. + ?T(<<(I_big1 band ((1 bsl 8) - 1)):8>>, [147]), + ?T(<<(I_big1 band ((1 bsl 16) - 1)):16>>, [0, 147]), + ?T(<<(I_big1 band ((1 bsl 24) - 1)):24>>, [99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 32) - 1)):32>>, [138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 40) - 1)):40>>, [5, 138, 99, 0, 147]), + ?T(<<(I_big1 band ((1 bsl 48) - 1)):48>>, [229, 5, 138, 99, 0, 147]), + + %% Known integer without range. + ?T(<<(I_big1 + 0):8>>, [147]), + ?T(<<(I_big1 + 0):16>>, [0, 147]), + ?T(<<(I_big1 + 0):24>>, [99, 0, 147]), + ?T(<<(I_big1 + 0):32>>, [138, 99, 0, 147]), + ?T(<<(I_big1 + 0):40>>, [5, 138, 99, 0, 147]), + ?T(<<(I_big1 + 0):48>>, [229, 5, 138, 99, 0, 147]), + ?T(<<(I_big1 + 0):56>>, [249, 229, 5, 138, 99, 0, 147]), + ?T(<<(I_big1 + 0):64>>, [42, 249, 229, 5, 138, 99, 0, 147]), + + %% Known integer. Verify that the value does not bleed into the + %% previous segment. + ?T(<<1, (I_big1 + 0):8>>, [1, 147]), + ?T(<<2, (I_big1 + 0):16>>, [2, 0, 147]), + ?T(<<3, (I_big1 + 0):24>>, [3, 99, 0, 147]), + ?T(<<4, (I_big1 + 0):32>>, [4, 138, 99, 0, 147]), + ?T(<<5, (I_big1 + 0):40>>, [5, 5, 138, 99, 0, 147]), + ?T(<<6, (I_big1 + 0):48>>, [6, 229, 5, 138, 99, 0, 147]), + ?T(<<7, (I_big1 + 0):56>>, [7, 249, 229, 5, 138, 99, 0, 147]), + ?T(<<8, (I_big1 + 0):64>>, [8, 42, 249, 229, 5, 138, 99, 0, 147]), + + %% Test non-byte sizes. + ?T(<>, <<197,49,128,73,1:1>>), + ?T(<>, <<11,20,198,1,19:7>>), + + ?T(<>, <<124,242,130,197,49,128,73,1:1>>), + ?T(<>, <<190,121,65,98,152,192,36,3:2>>), + ?T(<>, <<95,60,160,177,76,96,18,3:3>>), + ?T(<>, <<175,158,80,88,166,48,9,3:4>>), + ?T(<>, <<87,207,40,44,83,24,4,19:5>>), + ?T(<>, <<171,231,148,22,41,140,2,19:6>>), + ?T(<>, <<85,243,202,11,20,198,1,19:7>>), + + %% Test non-byte sizes and also that the value does not bleed + %% into the previous segment. + ?T(<<17, I_big1:33>>, <<17, 197,49,128,73,1:1>>), + ?T(<<19, I_big1:39>>, <<19, 11,20,198,1,19:7>>) + ]. native_3798() -> case <<1:16/native>> of @@ -274,10 +338,10 @@ fail_check(Res, _, _) -> %%% Simple working cases test1(Config) when is_list(Config) -> - I_13 = i(13), - I_big1 = big(1), + I_13 = id(13), + I_big1 = id(57285702734876389752897683), Vars = [{'I_13', I_13}, - {'I_big1', I_big1}], + {'I_big1', I_big1}], lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1), Vars)). %%% Misc @@ -409,6 +473,20 @@ testf(Config) when is_list(Config) -> ?FAIL(<<<<7,8,9,3:7>>/binary-unit:16>>), ?FAIL(<<<<7,8,9,3:7>>/binary-unit:17>>), + %% Failures not deteced by v3_core. Those must be detected at + %% runtime. + Atom = id(ok), + Float = id(2.71), + List = id([-1,0,1]), + NonBinaries = [{'Atom',Atom}, {'Float',Float}, {'List',List}], + ?FAIL_VARS(<>, NonBinaries), + ?FAIL_VARS(<>, NonBinaries), + ?FAIL_VARS(<<0,Atom/bits>>, NonBinaries), + ?FAIL_VARS(<>, NonBinaries), + ?FAIL_VARS(<>, NonBinaries), + ?FAIL_VARS(<>, NonBinaries), + ?FAIL_VARS(<>, NonBinaries), + ok. testf_1(W, B) -> @@ -717,6 +795,21 @@ dynamic_big(Bef, N, Int, Lpad, Rpad) -> Bin = id(<>), Bin = <>, + %% Units are seldom used with integer segments even in our test + %% suites, and I have never seen non-power-of-two units in + %% production code. + if + Bef rem 8 =:= 0 -> + Bin = <>; + Bef rem 7 =:= 0 -> + Bin = <>; + (128-Bef-N) rem 5 =:= 0 -> + Aft = (128 - Bef - N) div 5, + Bin = <>; + true -> + ok + end, + %% Further verify the result by matching. LpadMasked = Lpad band ((1 bsl Bef) - 1), RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), @@ -733,6 +826,20 @@ dynamic_little(Bef, N, Int, Lpad, Rpad) -> Bin = id(<>), Bin = <>, + if + Bef rem 8 =:= 0 -> + Bin = <>; + Bef rem 9 =:= 0 -> + Bin = <>; + (128-Bef-N) rem 17 =:= 0 -> + Aft = (128 - Bef - N) div 17, + Bin = <>; + true -> + ok + end, + %% Further verify the result by matching. LpadMasked = Lpad band ((1 bsl Bef) - 1), RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), @@ -742,7 +849,8 @@ dynamic_little(Bef, N, Int, Lpad, Rpad) -> %% Test that the bs_add/5 instruction handles big numbers correctly. bs_add(Config) when is_list(Config) -> - Mod = bs_construct_bs_add, + Mod = list_to_atom(atom_to_list(?MODULE) ++ "_" ++ + atom_to_list(?FUNCTION_NAME)), N = 2000, Code = [{module, Mod}, {exports, [{bs_add,2}]}, @@ -793,9 +901,12 @@ bs_add(Config) when is_list(Config) -> %% Clean up. ok = file:delete(AsmFile), ok = file:delete(code:which(Mod)), + _ = code:delete(Mod), + _ = code:purge(Mod), + ok. - + smallest_big() -> smallest_big_1(1 bsl 24). @@ -927,6 +1038,29 @@ bs_append_overflow_unsigned() -> C = <>, true = byte_size(B) < byte_size(C). +bs_append_offheap(Config) when is_list(Config) -> + %% test that erts_bs_private_append is reflected correctly in + %% process_info(Pid, binary()) report for off-heap binaries. + {Pid, MRef} = erlang:spawn_monitor(fun bs_append_offheap_proc/0), + receive + {'DOWN', MRef, process, Pid, normal} -> + ok; + {'DOWN', MRef, process, Pid, {{badmatch,[{binary,[]}]}, _}} -> + {fail, "missing binary in erts_bs_private_append"} + end. + +bs_append_offheap_proc() -> + Self = self(), + Len = 128, + OffHeapBin = list_to_binary(lists:duplicate(Len, $b)), + erlang:garbage_collect(Self), + [{binary, [{_, Len, 1}]}] = erlang:process_info(Self, [binary]), + Bin = <>, + erlang:garbage_collect(Self), + %% expect a single binary (2 bytes longer than the original) + [{binary, [{_, _, 1}]}] = erlang:process_info(Self, [binary]), + Bin. + reductions(_Config) -> TwoMeg = <<0:(2_000*1024)/unit:8>>, reds_at_least(2000, fun() -> <<0:8,TwoMeg/binary>> end), @@ -953,13 +1087,15 @@ reds_at_least(N, Fun) -> Diff -> ct:fail({expected,N,got,Diff}) end. - -id(I) -> I. - memsize() -> application:ensure_all_started(os_mon), - {Tot,_Used,_} = memsup:get_memory_data(), - Tot. + case proplists:get_value(available_memory, memsup:get_system_memory_data()) of + undefined -> + {Tot,_Used,_} = memsup:get_memory_data(), + Tot; + Available -> + Available + end. -define(FP16(EncodedInt, Float), (fun(NlInt, NlFloat) -> @@ -1002,3 +1138,566 @@ fp16(_Config) -> ?FP16(16#4000, 2), ?FP16(16#4000, 2.0), ok. + +zero_init(_Config) -> + <> = id(erlang:md5([42])), + Sizes = [511,512,513, 767,768,769, 1023,1024,1025, + 16#7fff,16#ffff,16#10000] ++ lists:seq(0, 257), + _ = [do_zero_init(Size, LPad, RPad) || Size <- Sizes], + ok. + +do_zero_init(Size, LPad, RPad) -> + try + do_zero_init_1(Size, LPad, RPad) + catch + C:R:Stk -> + io:format("Size = ~p, LPad = ~p, RPad = ~p\n", [Size, LPad, RPad]), + erlang:raise(C, R, Stk) + end. + +do_zero_init_1(Size, LPad, RPad) -> + Zeroes = id(<<0:Size>>), + <<0:Size>> = Zeroes, + Bin = id(<>), + Bin = id(<>), + Bin = id(<>), + + if + Size rem 11 =:= 0 -> + Bin = id(<>); + true -> + ok + end, + + case Size of + 0 -> + Bin = id(<>); + 1 -> + Bin = id(<>); + 2 -> + Bin = id(<>); + 3 -> + Bin = id(<>); + 4 -> + Bin = id(<>); + 5 -> + Bin = id(<>); + 6 -> + Bin = id(<>); + 7 -> + Bin = id(<>); + 8 -> + Bin = id(<>); + 9 -> + Bin = id(<>); + 10 -> + Bin = id(<>); + 11 -> + Bin = id(<>); + 12 -> + Bin = id(<>); + 13 -> + Bin = id(<>); + 14 -> + Bin = id(<>); + 15 -> + Bin = id(<>); + 16 -> + Bin = id(<>); + + 31 -> + Bin = id(<>); + 32 -> + Bin = id(<>); + 33 -> + Bin = id(<>); + + 47 -> + Bin = id(<>); + 48 -> + Bin = id(<>); + 49 -> + Bin = id(<>); + + 63 -> + Bin = id(<>); + 64 -> + Bin = id(<>); + 65 -> + Bin = id(<>); + + 79 -> + Bin = id(<>); + 80 -> + Bin = id(<>); + 81 -> + Bin = id(<>); + + 90 -> + Bin = id(<>); + 91 -> + Bin = id(<>); + 92 -> + Bin = id(<>); + 93 -> + Bin = id(<>); + 94 -> + Bin = id(<>); + 95 -> + Bin = id(<>); + 96 -> + Bin = id(<>); + 97 -> + Bin = id(<>); + 98 -> + Bin = id(<>); + 99 -> + Bin = id(<>); + 100 -> + Bin = id(<>); + 101 -> + Bin = id(<>); + 102 -> + Bin = id(<>); + 103 -> + Bin = id(<>); + 104 -> + Bin = id(<>); + 105 -> + Bin = id(<>); + 106 -> + Bin = id(<>); + 107 -> + Bin = id(<>); + 108 -> + Bin = id(<>); + 109 -> + Bin = id(<>); + + 127 -> + Bin = id(<>); + 128 -> + Bin = id(<>); + 129 -> + Bin = id(<>); + 130 -> + Bin = id(<>); + 131 -> + Bin = id(<>); + 132 -> + Bin = id(<>); + 133 -> + Bin = id(<>); + 134 -> + Bin = id(<>); + 135 -> + Bin = id(<>); + 136 -> + Bin = id(<>); + 137 -> + Bin = id(<>); + 138 -> + Bin = id(<>); + 139 -> + Bin = id(<>); + 140 -> + Bin = id(<>); + 141 -> + Bin = id(<>); + 142 -> + Bin = id(<>); + 143 -> + Bin = id(<>); + 144 -> + Bin = id(<>); + 145 -> + Bin = id(<>); + + 159 -> + Bin = id(<>); + 160 -> + Bin = id(<>); + 161 -> + Bin = id(<>); + + 191 -> + Bin = id(<>); + 192 -> + Bin = id(<>); + 193 -> + Bin = id(<>); + + 255 -> + Bin = id(<>); + 256 -> + Bin = id(<>); + 257 -> + Bin = id(<>); + + 511 -> + Bin = id(<>); + 512 -> + Bin = id(<>); + 513 -> + Bin = id(<>); + + 767 -> + Bin = id(<>); + 768 -> + Bin = id(<>); + 769 -> + Bin = id(<>); + + 1023 -> + Bin = id(<>); + 1024 -> + Bin = id(<>); + 1025 -> + Bin = id(<>); + + 16#7fff -> + Bin = id(<>); + 16#ffff -> + Bin = id(<>); + 16#10000 -> + Bin = id(<>); + _ -> + ok + end. + + +-define(ERROR_INFO(Expr), + fun() -> + try Expr of + _ -> + error(should_fail) + catch + error:Reason:Stk -> + error_info_verify(Reason, Stk, ??Expr, #{}) + end + end()). + +-define(ERROR_INFO(Expr, Overrides), + fun() -> + try Expr of + _ -> + error(should_fail) + catch + error:Reason:Stk -> + error_info_verify(Reason, Stk, ??Expr, Overrides) + end + end()). + +error_info(_Config) -> + Atom = id(some_atom), + NegSize = id(-1), + HugeNegSize = id(-1 bsl 64), + Binary = id(<<"abc">>), + HugeBig = id(1 bsl 1500), + LongList = lists:seq(1, 100), + BadBinary = id(ok), + BadSize = case Atom of + a -> 0; + _ -> bad_size + end, + + {badarg, {1,binary,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {2,binary,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {3,binary,type,Atom}, _} = ?ERROR_INFO(<<1:32, Binary/binary, Atom/binary>>), + {badarg, {4,binary,type,Atom}, _} = ?ERROR_INFO(<<1:32, "xyz", Binary/binary, Atom/binary>>), + + {badarg, {1,integer,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,integer,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,integer,type,LongList}, _} = ?ERROR_INFO(<>), + {badarg, {1,integer,size,Atom}, _} = ?ERROR_INFO(<<42:Atom>>), + {badarg, {1,integer,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,integer,size,NegSize}, _} = ?ERROR_INFO(<<42:NegSize>>), + {badarg, {1,integer,size,HugeNegSize}, _} = ?ERROR_INFO(<<42:HugeNegSize>>), + {system_limit, {1,integer,size,1 bsl 58}, _} = ?ERROR_INFO(<<42:(1 bsl 58)/unit:255>>), + {system_limit, {1,integer,size,1 bsl 60}, _} = ?ERROR_INFO(<<42:(1 bsl 60)/unit:8>>), + {system_limit, {1,integer,size,1 bsl 64}, _} = ?ERROR_INFO(<<42:(1 bsl 64)>>), + + {badarg, {1,binary,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,size,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,size,NegSize}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,size,HugeNegSize}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,size,BadSize}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,size,BadSize}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,short,Binary}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,short,Binary}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,binary,unit,<<1:1>>}, _} = ?ERROR_INFO(<<(id(<<1:1>>))/binary>>), + {badarg, {1,binary,unit,<<0:1111>>}, _} = ?ERROR_INFO(<<(id(<<0:1111>>))/binary>>), + {badarg, {2,binary,unit,<<1:1>>}, _} = ?ERROR_INFO(<<0, (id(<<1:1>>))/binary>>), + {badarg, {2,binary,unit,<<0:1111>>}, _} = ?ERROR_INFO(<<0, (id(<<0:1111>>))/binary>>), + {system_limit, {1,binary,size,1 bsl 64}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,1 bsl 64}, _} = ?ERROR_INFO(<>), + + {badarg, {1,float,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,float,size,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,float,size,NegSize}, _} = ?ERROR_INFO(<<42.0:NegSize/float>>), + {badarg, {1,float,size,HugeNegSize}, _} = ?ERROR_INFO(<<42.0:HugeNegSize/float>>), + {badarg, {1,float,invalid,1}, _} = ?ERROR_INFO(<<42.0:(id(1))/float>>), + {badarg, {1,float,no_float,HugeBig}, _} = ?ERROR_INFO(<>), + {badarg, {1,float,no_float,HugeBig}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,1 bsl 64}, _} = ?ERROR_INFO(<<42.0:(id(1 bsl 64))/float>>), + + {badarg, {1,utf8,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,utf16,type,Atom}, _} = ?ERROR_INFO(<>), + {badarg, {1,utf32,type,Atom}, _} = ?ERROR_INFO(<>), + + Bin = id(<<>>), + Float = id(42.0), + MaxSmall = (1 bsl 59) - 1, %Max small for 64-bit architectures. + + %% Attempt constructing a binary with total size 1^64 + 32. + + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(MaxSmall)/unit:32,0:64>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(MaxSmall)/unit:32,(id(0)):64>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:32,0:64>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:32,(id(0)):64>>), + + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + + %% Test a size exceeding 1^64, where the sign bit (bit 63) is not set. + 0 = (((MaxSmall) * 33) bsr 63) band 1, %Assertion: The sign bit is not set. + + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(MaxSmall)/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(MaxSmall)/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:33>>), + {system_limit, {1,integer,size,MaxSmall}, _} = ?ERROR_INFO(<<0:(id(MaxSmall))/unit:33>>), + + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,binary,size,MaxSmall}, _} = ?ERROR_INFO(<>), + + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + {system_limit, {1,float,size,MaxSmall}, _} = ?ERROR_INFO(<>), + + %% error messages with options + PP = fun(Term) -> <<"'", (erlang:atom_to_binary(Term))/binary, "'">> end, + + {_, _, <<"segment 1 of type 'float': expected a float or an integer but got: some_atom">>} = + ?ERROR_INFO(<>, #{}), + + {_, _, <<"segment 2 of type 'float': expected a float or an integer but got: some_atom">>} = + ?ERROR_INFO(<>, #{override_segment_position => 2}), + + {_, _, <<"segment 1 of type 'float': expected a float or an integer but got: 'some_atom'">>} = + ?ERROR_INFO(<>, #{pretty_printer => PP}), + + ok. + +error_info_verify(Reason, Stk0, Expr, Overrides) -> + [{?MODULE, Fun, Arity, Info0}|Rest] = Stk0, + {value, {error_info, ErrorInfo}, Info1} = lists:keytake(error_info, 1, Info0), + #{cause := Cause, module := Module, function := Function} = ErrorInfo, + Info2 = maps:merge(ErrorInfo, Overrides), + Stk1 = [{?MODULE, Fun, Arity, Info1 ++ [{error_info, Info2}]} | Rest], + Result = Module:Function(Reason, Stk1), + #{general := String} = Result, + true = is_binary(String), + io:format("~ts: ~ts\n", [Expr,String]), + {Reason, Cause, String}. + +little(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + + RandBytes = rand:bytes(10), + _ = [do_little(RandBytes, N) || N <- lists:seq(0, 10*8)], + + ok. + +do_little(Bin0, N) -> + <> = Bin0, + Bin2Size = bit_size(Bin2), + + <> = Bin1, + <> = Bin2, + + Bin1 = <>, + Bin1 = do_little_1(N, id(I1)), + + Bin2 = <>, + Bin2 = do_little_1(Bin2Size, id(I2)), + + ok. + +do_little_1(0, I) -> <>; +do_little_1(1, I) -> <>; +do_little_1(2, I) -> <>; +do_little_1(3, I) -> <>; +do_little_1(4, I) -> <>; +do_little_1(5, I) -> <>; +do_little_1(6, I) -> <>; +do_little_1(7, I) -> <>; +do_little_1(8, I) -> <>; +do_little_1(9, I) -> <>; +do_little_1(10, I) -> <>; +do_little_1(11, I) -> <>; +do_little_1(12, I) -> <>; +do_little_1(13, I) -> <>; +do_little_1(14, I) -> <>; +do_little_1(15, I) -> <>; +do_little_1(16, I) -> <>; +do_little_1(17, I) -> <>; +do_little_1(18, I) -> <>; +do_little_1(19, I) -> <>; +do_little_1(20, I) -> <>; +do_little_1(21, I) -> <>; +do_little_1(22, I) -> <>; +do_little_1(23, I) -> <>; +do_little_1(24, I) -> <>; +do_little_1(25, I) -> <>; +do_little_1(26, I) -> <>; +do_little_1(27, I) -> <>; +do_little_1(28, I) -> <>; +do_little_1(29, I) -> <>; +do_little_1(30, I) -> <>; +do_little_1(31, I) -> <>; +do_little_1(32, I) -> <>; +do_little_1(33, I) -> <>; +do_little_1(34, I) -> <>; +do_little_1(35, I) -> <>; +do_little_1(36, I) -> <>; +do_little_1(37, I) -> <>; +do_little_1(38, I) -> <>; +do_little_1(39, I) -> <>; +do_little_1(40, I) -> <>; +do_little_1(41, I) -> <>; +do_little_1(42, I) -> <>; +do_little_1(43, I) -> <>; +do_little_1(44, I) -> <>; +do_little_1(45, I) -> <>; +do_little_1(46, I) -> <>; +do_little_1(47, I) -> <>; +do_little_1(48, I) -> <>; +do_little_1(49, I) -> <>; +do_little_1(50, I) -> <>; +do_little_1(51, I) -> <>; +do_little_1(52, I) -> <>; +do_little_1(53, I) -> <>; +do_little_1(54, I) -> <>; +do_little_1(55, I) -> <>; +do_little_1(56, I) -> <>; +do_little_1(57, I) -> <>; +do_little_1(58, I) -> <>; +do_little_1(59, I) -> <>; +do_little_1(60, I) -> <>; +do_little_1(61, I) -> <>; +do_little_1(62, I) -> <>; +do_little_1(63, I) -> <>; +do_little_1(64, I) -> <>; +do_little_1(65, I) -> <>; +do_little_1(66, I) -> <>; +do_little_1(67, I) -> <>; +do_little_1(68, I) -> <>; +do_little_1(69, I) -> <>; +do_little_1(70, I) -> <>; +do_little_1(71, I) -> <>; +do_little_1(72, I) -> <>; +do_little_1(73, I) -> <>; +do_little_1(74, I) -> <>; +do_little_1(75, I) -> <>; +do_little_1(76, I) -> <>; +do_little_1(77, I) -> <>; +do_little_1(78, I) -> <>; +do_little_1(79, I) -> <>; +do_little_1(80, I) -> <>; +do_little_1(81, I) -> <>; +do_little_1(82, I) -> <>; +do_little_1(83, I) -> <>; +do_little_1(84, I) -> <>; +do_little_1(85, I) -> <>; +do_little_1(86, I) -> <>; +do_little_1(87, I) -> <>; +do_little_1(88, I) -> <>; +do_little_1(89, I) -> <>; +do_little_1(90, I) -> <>; +do_little_1(91, I) -> <>; +do_little_1(92, I) -> <>; +do_little_1(93, I) -> <>; +do_little_1(94, I) -> <>; +do_little_1(95, I) -> <>; +do_little_1(96, I) -> <>; +do_little_1(97, I) -> <>; +do_little_1(98, I) -> <>; +do_little_1(99, I) -> <>; +do_little_1(100, I) -> <>; +do_little_1(101, I) -> <>; +do_little_1(102, I) -> <>; +do_little_1(103, I) -> <>; +do_little_1(104, I) -> <>; +do_little_1(105, I) -> <>; +do_little_1(106, I) -> <>; +do_little_1(107, I) -> <>; +do_little_1(108, I) -> <>; +do_little_1(109, I) -> <>; +do_little_1(110, I) -> <>; +do_little_1(111, I) -> <>; +do_little_1(112, I) -> <>; +do_little_1(113, I) -> <>; +do_little_1(114, I) -> <>; +do_little_1(115, I) -> <>; +do_little_1(116, I) -> <>; +do_little_1(117, I) -> <>; +do_little_1(118, I) -> <>; +do_little_1(119, I) -> <>; +do_little_1(120, I) -> <>; +do_little_1(121, I) -> <>; +do_little_1(122, I) -> <>; +do_little_1(123, I) -> <>; +do_little_1(124, I) -> <>; +do_little_1(125, I) -> <>; +do_little_1(126, I) -> <>; +do_little_1(127, I) -> <>; +do_little_1(128, I) -> <>. + +%% GH-7469: The unit of variable-sized segments wasn't checked properly, +%% resulting in the creation of heap binaries for non-binary bitstrings. +heap_binary_unit(_Config) -> + {ok, 14524} = heap_binary_unit_1(id(<<184,188,2,66,172,19,0,3>>)), + ok. + +heap_binary_unit_1(<<2:2/integer,Rest:62/bitstring>>) -> + heap_binary_unit_2(<<2:2/integer>>, Rest). + +heap_binary_unit_2(Variant, Rest) -> + VariantSize = bit_size(Variant), + ClockHiSize = 8 - VariantSize, + ClockSize = 8 + ClockHiSize, + case Rest of + <> -> + case + <> + of + <> -> + {ok, Clock}; + Bin1 -> + {error1, Bin1} + end; + Bin2 -> + {error2, Bin2} + end. + +%%% +%%% Common utilities. +%%% + +id(I) -> I. diff --git a/erts/emulator/test/bs_match_bin_SUITE.erl b/erts/emulator/test/bs_match_bin_SUITE.erl index f5c996ae9e38..0ea354b01ee1 100644 --- a/erts/emulator/test/bs_match_bin_SUITE.erl +++ b/erts/emulator/test/bs_match_bin_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -21,17 +21,21 @@ -module(bs_match_bin_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - byte_split_binary/1,bit_split_binary/1,match_huge_bin/1]). + init_per_group/2,end_per_group/2, + byte_split_binary/1,bit_split_binary/1,match_huge_bin/1, + bs_match_string_edge_case/1,contexts/1, + empty_binary/1,small_bitstring/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> - [byte_split_binary, bit_split_binary, match_huge_bin]. +all() -> + [byte_split_binary, bit_split_binary, match_huge_bin, + bs_match_string_edge_case, contexts, empty_binary, + small_bitstring]. -groups() -> +groups() -> []. init_per_suite(Config) -> @@ -110,14 +114,6 @@ bits_to_list([], _) -> []. mkbin(L) when is_list(L) -> list_to_binary(L). -make_unaligned_sub_binary(Bin0) -> - Bin1 = <<0:3,Bin0/binary,31:5>>, - Sz = size(Bin0), - <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), - Bin. - -id(I) -> I. - match_huge_bin(Config) when is_list(Config) -> Bin = <<0:(1 bsl 27),13:8>>, skip_huge_bin_1(1 bsl 27, Bin), @@ -214,3 +210,100 @@ overflow_huge_bin_64(<>) -> overflow_huge_bin_64(<>) -> {7,Bin}; % 1 bsl 62 overflow_huge_bin_64(<>) -> {8,Bin}; % 1 bsl 63 overflow_huge_bin_64(_) -> nomatch. + +-define(MATCH512, + " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17" + " 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32" + " 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49" + " 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64" + " 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81" + " 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96" + " 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113" + " 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128"). + +%% GH-5871: bs_match_string broke when matching more than 4095 bits (max for a +%% 12-bit immediate) on ARM. +bs_match_string_edge_case(_Config) -> + Bin = id(<>), + <> = Bin, + <> = Bin, + <<" ", Tail1/binary>> = id(Tail0), + ok. + +contexts(_Config) -> + Bytes = rand:bytes(12), + _ = [begin + <> = Bytes, + B = id(get_binary(B)) + end || N <- lists:seq(0, 12)], + ok. + +get_binary(Bin) -> + [A,B,C,D,E,F] = id([1,2,3,4,5,6]), + {Res,_} = get_binary_memory_ctx(A, B, C, D, E, F, Bin), + Res. + + +get_binary_memory_ctx(A, B, C, D, E, F, Bin) -> + %% The match context will be in {x,6}, which is not + %% a X register backed by a CPU register on any platform. + Res = case Bin of + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0; + <> -> Res0 + end, + {Res,{A,B,C,D,E,F}}. + +empty_binary(_Config) -> + _ = do_empty_binary(1_000_000), + ok. + +do_empty_binary(0) -> + ok; +do_empty_binary(N) -> + %% The new bs_match instruction would use more heap space + %% than reserved when matching out an empty binary. + <> = id(<<>>), + [0|do_empty_binary(N-1)]. + +small_bitstring(_Config) -> + %% GH-7292: The new bs_match instruction would reserve insufficient + %% heap space for small bitstrings. + rand_seed(), + Bin = rand:bytes(10_000), + ok = small_bitstring_1(id(Bin), id(Bin)). + +small_bitstring_1(<>, + <>) -> + small_bitstring_1(As0, As1); +small_bitstring_1(<<>>, <<>>) -> + ok. + +%%% +%%% Common utilities. +%%% + +rand_seed() -> + rand:seed(default), + io:format("\n*** rand:export_seed() = ~w\n\n", [rand:export_seed()]), + ok. + +make_unaligned_sub_binary(Bin0) -> + Bin1 = <<0:3,Bin0/binary,31:5>>, + Sz = size(Bin0), + <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), + Bin. + +id(I) -> I. diff --git a/erts/emulator/test/bs_match_int_SUITE.erl b/erts/emulator/test/bs_match_int_SUITE.erl index 0268ba18c80e..eab2f5ce0744 100644 --- a/erts/emulator/test/bs_match_int_SUITE.erl +++ b/erts/emulator/test/bs_match_int_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -19,10 +19,10 @@ -module(bs_match_int_SUITE). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1, - match_huge_int/1,bignum/1,unaligned_32_bit/1]). + integer/1,mixed_sizes/1,signed_integer/1,dynamic/1,more_dynamic/1, + mml/1,match_huge_int/1,bignum/1,unaligned_32_bit/1,unit/1]). -include_lib("common_test/include/ct.hrl"). @@ -30,11 +30,11 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> - [integer, signed_integer, dynamic, more_dynamic, mml, - match_huge_int, bignum, unaligned_32_bit]. +all() -> + [integer, mixed_sizes, signed_integer, dynamic, more_dynamic, mml, + match_huge_int, bignum, unaligned_32_bit, unit]. -groups() -> +groups() -> []. init_per_suite(Config) -> @@ -51,6 +51,9 @@ end_per_group(_GroupName, Config) -> integer(Config) when is_list(Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + 0 = get_int(mkbin([])), 0 = get_int(mkbin([0])), 42 = get_int(mkbin([42])), @@ -58,36 +61,628 @@ integer(Config) when is_list(Config) -> 256 = get_int(mkbin([1,0])), 257 = get_int(mkbin([1,1])), 258 = get_int(mkbin([1,2])), - 258 = get_int(mkbin([1,2])), 65534 = get_int(mkbin([255,254])), 16776455 = get_int(mkbin([255,253,7])), 4245492555 = get_int(mkbin([253,13,19,75])), 4294967294 = get_int(mkbin([255,255,255,254])), 4294967295 = get_int(mkbin([255,255,255,255])), + + 16#cafebeef = get_int(<<16#cafebeef:32>>), + 16#cafebeef42 = get_int(<<16#cafebeef42:40>>), + 16#cafebeeffeed = get_int(<<16#cafebeeffeed:48>>), + 16#cafebeeffeed42 = get_int(<<16#cafebeeffeed42:56>>), + 16#1cafebeeffeed42 = get_int(<<16#1cafebeeffeed42:57>>), + 16#2cafebeeffeed42 = get_int(<<16#2cafebeeffeed42:58>>), + 16#7cafebeeffeed42 = get_int(<<16#7cafebeeffeed42:59>>), + + 16#beefcafefeed = get_int(<<16#beefcafefeed:60>>), + 16#beefcafefeed = get_int(<<16#beefcafefeed:61>>), + 16#beefcafefeed = get_int(<<16#beefcafefeed:62>>), + 16#beefcafefeed = get_int(<<16#beefcafefeed:63>>), + + 16#cafebeeffeed42 = get_int(<<16#cafebeeffeed42:60>>), + 16#cafebeeffeed42 = get_int(<<16#cafebeeffeed42:61>>), + 16#cafebeeffeed42 = get_int(<<16#cafebeeffeed42:62>>), + 16#cafebeeffeed42 = get_int(<<16#cafebeeffeed42:63>>), + + 16#acafebeeffeed42 = get_int(<<16#acafebeeffeed42:60>>), + 16#acafebeeffeed42 = get_int(<<16#acafebeeffeed42:61>>), + 16#acafebeeffeed42 = get_int(<<16#acafebeeffeed42:62>>), + 16#acafebeeffeed42 = get_int(<<16#acafebeeffeed42:63>>), + + 16#cafebeeffeed = get_int(<<16#cafebeeffeed:64>>), + 16#cafebeeffeedface = get_int(<<16#cafebeeffeedface:64>>), + + get_int_roundtrip(rand:bytes(12), 0), + get_int_roundtrip(rand:bytes(12), 0), + Eight = [200,1,19,128,222,42,97,111], cmp128(Eight, uint(Eight)), - fun_clause(catch get_int(mkbin(seq(1,5)))), + fun_clause(catch get_int(mkbin(seq(1, 20)))), + ok. + +get_int_roundtrip(Bin0, Size) when Size =< 8*byte_size(Bin0) -> + <> = Bin0, + <> = Bin, + I = get_int(Bin), + get_int_roundtrip(Bin0, Size+1); +get_int_roundtrip(_, _) -> ok. + +get_int(Bin0) -> + %% Note that it has become impossible to create a byte-sized sub + %% binary (see erts_extract_sub_binary() in erl_bits.c) of size 64 + %% or less. Therefore, to be able to create an unaligned binary, + %% we'll need to base it on on a binary with more than 64 bytes. + Size = bit_size(Bin0), + Filler = rand:bytes(65), + UnsignedBigBin = id(<>), + I = get_unsigned_big(UnsignedBigBin), + + %% io:format("~p ~p\n", [Size,I]), + if + Size =< 10*8 -> + OversizedUnsignedBig = id(<>), + I = get_unsigned_big(OversizedUnsignedBig); + true -> + ok + end, + + test_unaligned(UnsignedBigBin, I, fun get_unsigned_big/1), + + %% Test unsigned little-endian integers. + + UnsignedLittleBin = id(<>), + I = get_unsigned_little(UnsignedLittleBin), + + test_unaligned(UnsignedLittleBin, I, fun get_unsigned_little/1), + + %% Test signed big-endian integers. + + SignedBigBin1 = id(<>), + I = -get_signed_big(SignedBigBin1), + + SignedBigBin2 = id(<>), + I = get_signed_big(SignedBigBin2), + + %% test_unaligned(SignedBigBin1, -I, fun get_signed_big/1), + test_unaligned(SignedBigBin2, I, fun get_signed_big/1), + + %% Test signed little-endian integers. + + SignedLittleBin1 = id(<>), + I = -get_signed_little(SignedLittleBin1), + + SignedLittleBin2 = id(<>), + I = get_signed_little(SignedLittleBin2), + + test_unaligned(SignedLittleBin1, -I, fun get_signed_little/1), + test_unaligned(SignedLittleBin2, I, fun get_signed_little/1), + + I. + +test_unaligned(Bin, I, Matcher) -> + <> = rand:bytes(16), + Size = bit_size(Bin), + _ = [begin + <<_:(Offset+32),UnalignedBin:Size/bits,_/bits>> = + id(<>), + I = Matcher(UnalignedBin) + end || Offset <- [1,2,3,4,5,6,7]], ok. -get_int(Bin) -> - I = get_int1(Bin), - get_int(Bin, I). -get_int(Bin0, I) when size(Bin0) < 4 -> - Bin = <<0,Bin0/binary>>, - I = get_int1(Bin), - get_int(Bin, I); -get_int(_, I) -> I. -get_int1(<>) -> I; -get_int1(<>) -> I; -get_int1(<>) -> I; -get_int1(<>) -> I; -get_int1(<>) -> I. +get_unsigned_big(Bin) -> + Res = get_unsigned_big_plain(Bin), + [A,B,C,D,E] = id([1,2,3,4,5]), + {Res,_} = get_unsigned_big_memory_ctx(A, B, C, D, E, Res, Bin), + Res. + +get_unsigned_big_memory_ctx(A, B, C, D, E, Res0, Bin) -> + %% The match context will be in {x,6}, which is not + %% a X register backed by a CPU register on any platform. + Res = case Bin of + <<_:65/unit:8,I:7>> -> I; + <<_:65/unit:8,I:8>> -> I; + <<_:65/unit:8,I:36>> -> I; + <<_:65/unit:8,I:59>> -> I; + <<_:65/unit:8,I:60>> -> I; + <<_:65/unit:8,I:61>> -> I; + <<_:65/unit:8,I:62>> -> I; + <<_:65/unit:8,I:63>> -> I; + <<_:65/unit:8,I:64>> -> I; + <<_:65/unit:8,I:65>> -> I; + <<_:65/unit:8,I:70>> -> I; + <<_:65/unit:8,I:80>> -> I; + <<_:65/unit:8,I:95>> -> I; + _ -> Res0 + end, + {Res,{A,B,C,D,E}}. + +get_unsigned_big_plain(<<_:65/unit:8,I:0>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:1>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:2>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:3>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:4>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:5>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:6>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:7>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:8>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:9>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:10>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:11>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:12>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:13>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:14>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:15>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:16>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:17>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:18>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:19>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:20>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:21>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:22>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:23>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:24>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:25>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:26>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:27>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:28>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:29>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:30>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:31>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:32>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:33>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:34>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:35>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:36>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:37>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:38>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:39>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:40>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:41>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:42>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:43>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:44>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:45>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:46>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:47>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:48>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:49>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:50>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:51>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:52>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:53>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:54>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:55>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:56>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:57>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:58>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:59>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:60>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:61>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:62>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:63>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:64>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:65>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:66>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:67>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:68>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:69>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:70>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:71>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:72>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:73>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:74>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:75>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:76>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:77>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:78>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:79>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:80>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:81>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:82>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:83>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:84>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:85>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:86>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:87>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:88>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:89>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:90>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:91>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:92>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:93>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:94>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:95>>) -> I; +get_unsigned_big_plain(<<_:65/unit:8,I:96>>) -> I. + +get_unsigned_little(<<_:65/unit:8,I:0/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:1/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:2/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:3/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:4/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:5/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:6/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:7/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:8/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:9/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:10/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:11/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:12/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:13/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:14/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:15/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:16/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:17/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:18/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:19/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:20/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:21/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:22/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:23/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:24/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:25/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:26/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:27/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:28/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:29/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:30/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:31/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:32/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:33/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:34/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:35/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:36/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:37/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:38/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:39/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:40/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:41/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:42/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:43/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:44/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:45/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:46/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:47/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:48/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:49/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:50/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:51/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:52/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:53/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:54/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:55/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:56/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:57/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:58/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:59/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:60/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:61/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:62/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:63/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:64/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:65/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:66/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:67/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:68/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:69/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:70/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:71/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:72/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:73/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:74/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:75/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:76/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:77/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:78/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:79/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:80/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:81/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:82/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:83/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:84/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:85/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:86/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:87/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:88/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:89/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:90/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:91/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:92/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:93/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:94/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:95/little>>) -> I; +get_unsigned_little(<<_:65/unit:8,I:96/little>>) -> I. + +get_signed_big(<<_:65/unit:8,I:0/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:1/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:2/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:3/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:4/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:5/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:6/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:7/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:8/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:9/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:10/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:11/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:12/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:13/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:14/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:15/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:16/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:17/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:18/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:19/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:20/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:21/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:22/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:23/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:24/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:25/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:26/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:27/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:28/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:29/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:30/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:31/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:32/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:33/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:34/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:35/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:36/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:37/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:38/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:39/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:40/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:41/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:42/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:43/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:44/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:45/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:46/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:47/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:48/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:49/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:50/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:51/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:52/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:53/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:54/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:55/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:56/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:57/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:58/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:59/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:60/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:61/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:62/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:63/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:64/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:65/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:66/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:67/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:68/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:69/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:70/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:71/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:72/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:73/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:74/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:75/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:76/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:77/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:78/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:79/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:80/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:81/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:82/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:83/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:84/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:85/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:86/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:87/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:88/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:89/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:90/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:91/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:92/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:93/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:94/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:95/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:96/signed-big>>) -> I; +get_signed_big(<<_:65/unit:8,I:97/signed-big>>) -> I. + +get_signed_little(<<_:65/unit:8,I:0/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:1/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:2/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:3/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:4/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:5/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:6/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:7/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:8/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:9/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:10/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:11/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:12/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:13/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:14/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:15/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:16/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:17/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:18/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:19/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:20/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:21/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:22/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:23/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:24/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:25/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:26/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:27/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:28/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:29/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:30/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:31/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:32/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:33/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:34/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:35/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:36/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:37/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:38/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:39/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:40/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:41/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:42/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:43/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:44/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:45/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:46/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:47/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:48/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:49/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:50/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:51/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:52/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:53/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:54/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:55/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:56/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:57/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:58/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:59/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:60/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:61/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:62/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:63/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:64/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:65/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:66/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:67/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:68/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:69/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:70/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:71/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:72/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:73/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:74/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:75/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:76/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:77/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:78/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:79/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:80/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:81/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:82/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:83/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:84/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:85/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:86/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:87/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:88/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:89/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:90/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:91/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:92/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:93/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:94/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:95/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:96/signed-little>>) -> I; +get_signed_little(<<_:65/unit:8,I:97/signed-little>>) -> I. cmp128(<>, I) -> equal; cmp128(_, _) -> not_equal. - + +mixed_sizes(_Config) -> + mixed({345,42}, + fun({A,B}) -> + <>; + (<>) -> + {A,B} + end), + + mixed({27033,59991,16#c001cafe,12345,2}, + fun({A,B,C,D,E}) -> + <>; + (<>) -> + {A,B,C,D,E} + end), + + mixed({79,153,17555,50_000,777_000,36#hugebignumber,2222}, + fun({A,B,C,D,E,F,G}) -> + <>; + (<>) -> + {A,B,C,D,E,F,G} + end), + + mixed({16#123456789ABCDEF,13,36#hugenum,979}, + fun({A,B,C,D}) -> + <>; + (<>) -> + {A,B,C,D} + end), + + mixed({16#123456789ABCDEF,13,36#hugenum,979}, + fun({A,B,C,D}) -> + <>; + (<>) -> + {A,B,C,D} + end), + + mixed({15692284513449131826, 17798, 33798}, + fun({A,B,C}) -> + <>; + (<>) -> + {A,B,C} + end), + + mixed({15692344284519131826, 1779863, 13556268}, + fun({A,B,C}) -> + <>; + (<>) -> + {A,B,C} + end), + + mixed({15519169234428431825, 194086885, 2813274043}, + fun({A,B,C}) -> + <>; + (<>) -> + {A,B,C} + end), + + mixed({5,9,38759385,93}, + fun({A,B,C,D}) -> + <<1:3,A:4,B:5,C:47,D:7>>; + (<<1:3,A:4,B:5,C:47,D:7>>) -> + {A,B,C,D} + end), + + mixed({2022,8,22}, + fun({A,B,C}) -> + <>; + (<>) -> + {A,B,C} + end), + + mixed({2022,8,22}, + fun({A,B,C}) -> + <>; + (<>) -> + _ = id(0), + {A,B,C} + end), + ok. + +mixed(Data, F) -> + Bin = F(Data), + Data = F(Bin), + true = is_bitstring(Bin). + signed_integer(Config) when is_list(Config) -> {no_match,_} = sint(mkbin([])), {no_match,_} = sint(mkbin([1,2,3])), @@ -133,7 +728,7 @@ dynamic(Bin, S1, S2, A, B) -> %% Extract integers at different alignments and of different sizes. more_dynamic(Config) when is_list(Config) -> - % Unsigned big-endian numbers. + %% Unsigned big-endian numbers. Unsigned = fun(Bin, List, SkipBef, N) -> SkipAft = 8*size(Bin) - N - SkipBef, <<_:SkipBef,Int:N,_:SkipAft>> = Bin, @@ -249,35 +844,48 @@ match_huge_int(Config) when is_list(Config) -> %% because of insufficient memory. {skip, "unoptimized code would use too much memory"}; bs_match_int_SUITE -> - Sz = 1 bsl 27, - Bin = <<0:Sz,13:8>>, - skip_huge_int_1(Sz, Bin), - 0 = match_huge_int_1(Sz, Bin), - - %% Test overflowing the size of an integer field. - nomatch = overflow_huge_int_skip_32(Bin), - case erlang:system_info(wordsize) of - 4 -> - nomatch = overflow_huge_int_32(Bin); - 8 -> - %% An attempt will be made to allocate heap space for - %% the bignum (which will probably fail); only if the - %% allocation succeeds will the matching fail because - %% the binary is too small. - ok - end, - nomatch = overflow_huge_int_skip_64(Bin), - nomatch = overflow_huge_int_64(Bin), - - %% Test overflowing the size of an integer field using - %% variables as sizes. - Sizes = case erlang:system_info(wordsize) of - 4 -> lists:seq(25, 32); - 8 -> [] - end ++ lists:seq(50, 64), - ok = overflow_huge_int_unit128(Bin, Sizes) + do_match_huge_int(); + bs_match_int_r25_SUITE -> + do_match_huge_int(); + bs_match_int_stripped_types_SUITE -> + do_match_huge_int() end. +do_match_huge_int() -> + Sz = 1 bsl 27, + Bin = <<0:Sz,13:8>>, + skip_huge_int_1(Sz, Bin), + 0 = match_huge_int_1(Sz, Bin), + + %% Test overflowing the size of an integer field. + nomatch = overflow_huge_int_skip_32(Bin), + case erlang:system_info(wordsize) of + 4 -> + nomatch = overflow_huge_int_32(Bin); + 8 -> + %% An attempt will be made to allocate heap space for + %% the bignum (which will probably fail); only if the + %% allocation succeeds will the matching fail because + %% the binary is too small. + ok + end, + nomatch = overflow_huge_int_skip_64(Bin), + nomatch = overflow_huge_int_64(Bin), + + %% Test overflowing the size of an integer field using + %% variables as sizes. + Sizes = case erlang:system_info(wordsize) of + 4 -> lists:seq(25, 32); + 8 -> [] + end ++ lists:seq(50, 64), + ok = overflow_huge_int_unit128(Bin, Sizes), + + %% GH-6701: [vm] crash with -emu_flavor emu: + %% "no next heap size found: 18446744072702918678, offset 0" + {'EXIT',{function_clause,_}} = + (catch fun(<>) -> X end(<<>>)), + ok. + overflow_huge_int_unit128(Bin, [Sz0|Sizes]) -> Sz = id(1 bsl Sz0), case Bin of @@ -375,5 +983,18 @@ unaligned_32_bit_1(_) -> unaligned_32_bit_verify([], 0) -> ok; unaligned_32_bit_verify([4294967295|T], N) when N > 0 -> unaligned_32_bit_verify(T, N-1). - + +unit(_Config) -> + %% GH-6732. Would fail to match with no_ssa_opt or r25. + <> = id(<<16#cafebeef:5/integer-unit:8>>), + 16#cafebeef = id(V1), + <> = id(<<16#cafebeef:8/integer-unit:5>>), + 16#cafebeef = id(V2), + + ok. + +%%% +%%% Common utilities. +%%% + id(I) -> I. diff --git a/erts/emulator/test/bs_match_misc_SUITE.erl b/erts/emulator/test/bs_match_misc_SUITE.erl index 65256dae35dd..83f4873dbeb2 100644 --- a/erts/emulator/test/bs_match_misc_SUITE.erl +++ b/erts/emulator/test/bs_match_misc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -24,7 +24,8 @@ kenneth/1,encode_binary/1,native/1,happi/1, size_var/1,wiger/1,x0_context/1,huge_float_field/1, writable_binary_matched/1,otp_7198/1,unordered_bindings/1, - float_middle_endian/1,unsafe_get_binary_reuse/1, fp16/1]). + float_middle_endian/1,unsafe_get_binary_reuse/1, fp16/1, + bad_bs_match/1]). -include_lib("common_test/include/ct.hrl"). @@ -37,7 +38,8 @@ all() -> kenneth, encode_binary, native, happi, size_var, wiger, x0_context, huge_float_field, writable_binary_matched, otp_7198, unordered_bindings, float_middle_endian, - unsafe_get_binary_reuse, fp16]. + unsafe_get_binary_reuse, fp16, + bad_bs_match]. %% Test matching of bound variables. @@ -579,8 +581,6 @@ unsafe_get_binary_reuse(Config) when is_list(Config) -> ubgr_1(<<_CP/utf8, Rest/binary>>) -> id(Rest); ubgr_1(_) -> false. -id(I) -> I. - -define(FP16(EncodedInt, Float), (fun(NlInt, NlFloat) -> <> = <>, @@ -638,3 +638,30 @@ fp16(_Config) -> ?FP16(16#4000, 2), ?FP16(16#4000, 2.0), ok. + +bad_bs_match(_Config) -> + Lines = ["-module(bad_bs_match).", + "-export([f/1]).", + "f(<>) -> X."], + {Forms,_} = + lists:mapfoldl(fun(Line, L0) -> + {ok,Tokens,L} = erl_scan:string(Line ++ "\n", L0), + {ok,Form} = erl_parse:parse_form(Tokens), + {Form,L} + end, 1, Lines), + {ok,Mod,Beam0} = compile:forms(Forms, [binary]), + + %% Introduce a non-existing sub command of the bs_match instruction. + Beam = binary:replace(Beam0, <<"ensure_at_least">>, <<"future_cool_cmd">>), + true = Beam0 =/= Beam, + + %% There should be an error when attempting to load this BEAM + %% file, not a runtime crash. + {error,badfile} = code:load_binary(Mod, "", Beam), + + ok. + + +%%% Common utilities. +id(I) -> I. + diff --git a/erts/emulator/test/bs_match_tail_SUITE.erl b/erts/emulator/test/bs_match_tail_SUITE.erl index cbebc554c7d3..7aa4c5efbc17 100644 --- a/erts/emulator/test/bs_match_tail_SUITE.erl +++ b/erts/emulator/test/bs_match_tail_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -22,14 +22,14 @@ -author('bjorn@erix.ericsson.se'). -export([all/0, suite/0, - aligned/1,unaligned/1,zero_tail/1]). + aligned/1,unaligned/1,zero_tail/1,huge_tail/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [aligned, unaligned, zero_tail]. + [aligned, unaligned, zero_tail, huge_tail]. %% Test aligned tails. @@ -86,4 +86,39 @@ test_zero_tail(<>) -> A. test_zero_tail2(<<_A:4,_B:4>>) -> ok. -mkbin(L) when is_list(L) -> list_to_binary(L). +huge_tail(_Config) -> + 42 = huge_tail_1(id(<<42,0:16#1001>>)), + {'EXIT',{function_clause,_}} = catch huge_tail_1(id(<<0:8,0:10>>)), + + {'EXIT',{function_clause,_}} = catch huge_tail_2(id(<<0:8,0:100>>)), + + {'EXIT',{function_clause,_}} = catch huge_tail_3(id(<<0:8,0:200>>)), + + %% The following code is commented out by default because it + %% constructs a 2Gb binary. + + %% try huge_tail_2(id(<<100, 0:16#8000_0000>>)) of + %% 100 -> + %% ok + %% catch + %% error:function_clause -> + %% ct:fail(not_supposed_to_fail) + %% end, + + ok. + +%% On AArch64, the immediate for the `cmp` instruction is 12 bits (unsigned). +huge_tail_1(<>) -> B. + +%% On x86_64, the immediate for the `cmp` instruction is 32 bits (signed). +huge_tail_2(<>) -> B. + +%% Matching will fail on all platforms. +huge_tail_3(<>) -> B. + +%%% +%%% Common utilities. +%%% +mkbin(L) when is_list(L) -> list_to_binary(id(L)). + +id(I) -> I. diff --git a/erts/emulator/test/bs_utf_SUITE.erl b/erts/emulator/test/bs_utf_SUITE.erl index 68099c6f393a..ec15c1b312bb 100644 --- a/erts/emulator/test/bs_utf_SUITE.erl +++ b/erts/emulator/test/bs_utf_SUITE.erl @@ -20,11 +20,12 @@ -module(bs_utf_SUITE). --export([all/0, suite/0, +-export([all/0, suite/0, init_per_suite/1, end_per_suite/1, utf8_roundtrip/1,utf16_roundtrip/1,utf32_roundtrip/1, utf8_illegal_sequences/1,utf16_illegal_sequences/1, utf32_illegal_sequences/1, - bad_construction/1]). + bad_construction/1, + utf8_big_file/1]). -include_lib("common_test/include/ct.hrl"). @@ -34,26 +35,93 @@ suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 6}}]. -all() -> +all() -> [utf8_roundtrip, utf16_roundtrip, utf32_roundtrip, utf8_illegal_sequences, utf16_illegal_sequences, - utf32_illegal_sequences, bad_construction]. + utf32_illegal_sequences, bad_construction, + utf8_big_file]. + +init_per_suite(Config) -> + %% Make sure that calls to id/1 will hide types. + id(Config), + Config. + +end_per_suite(Config) -> + Config. utf8_roundtrip(Config) when is_list(Config) -> utf8_roundtrip(0, 16#D7FF), utf8_roundtrip(16#E000, 16#10FFFF), ok. -utf8_roundtrip(First, Last) when First =< Last -> - Bin = int_to_utf8(First), +utf8_roundtrip(First, Last) -> + %% Hide types. + do_utf8_roundtrip(id(First), id(Last)). + +do_utf8_roundtrip(First, Last) when First =< Last -> + Bin = int_to_utf8(id(First)), Bin = id(<>), Bin = id(<<(id(<<>>))/binary,First/utf8>>), - Unaligned = id(<<3:2,First/utf8>>), - <<_:2,Bin/binary>> = Unaligned, + + <<0:7/unit:8,Bin/binary>> = id(<<0:7/unit:8,First/utf8>>), + + %% Here a heap binary and a sub binary will be allocated. If the + %% write in the utf8 segment extends beyond the end of heap binary, + %% it will will overwrite the header for the sub binary. + <<-1:(64-9)/signed,Bin/binary>> = id(<<-1:(64-9),First/utf8>>), + <<-1:63/signed,Bin/binary>> = id(<<-1:63,First/utf8>>), + + if + is_integer(First) -> + Bin = id(<>) + end, + + <<1:1,Bin/binary>> = id(<<1:1,First/utf8>>), + <<0:1,Bin/binary>> = id(<<0:1,First/utf8>>), + <<3:2,Bin/binary>> = id(<<3:2,First/utf8>>), + <<5:3,Bin/binary>> = id(<<5:3,First/utf8>>), + <<13:4,Bin/binary>> = id(<<13:4,First/utf8>>), + <<21:5,Bin/binary>> = id(<<21:5,First/utf8>>), + <<51:6,Bin/binary>> = id(<<51:6,First/utf8>>), + <<107:7,Bin/binary>> = id(<<107:7,First/utf8>>), + <> = Bin, <> = make_unaligned(Bin), - utf8_roundtrip(First+1, Last); -utf8_roundtrip(_, _) -> ok. + + %% Matching of utf8 segments use different code paths dependending + %% on the the number of bytes available in the binary. Make sure + %% we test both code paths. + <> = id(<>), + <<0:3,First/utf8,0:64>> = id(<<0:3,Bin/binary,0:64>>), + + unaligned_match(First), + + Bin = id(<>), + do_utf8_roundtrip(First+1, Last); +do_utf8_roundtrip(_, _) -> ok. + +unaligned_match(Char) -> + %% We create a REFC binary so that we can create sub binaries + %% and control the contents just beyond the end of the binary. + _ = [begin + Bin = id(<<0:64/unit:8,0:Offset,Char/utf8>>), + <<0:64/unit:8,0:Offset,Char/utf8>> = Bin, + unaligned_match(Bin, Offset, 8) + end || Offset <- lists:seq(1, 7)], + ok. + +unaligned_match(_Bin, _Offset, 0) -> + ok; +unaligned_match(Bin, Offset, N) -> + Size = bit_size(Bin), + <> = Bin, + try + <<0:64/unit:8,0:Offset,Char/utf8>> = Shorter, + ct:fail({short_binary_accepted,Shorter,Char}) + catch + error:{badmatch,_} -> + unaligned_match(Shorter, Offset, N - 1) + end. utf16_roundtrip(Config) when is_list(Config) -> Big = fun utf16_big_roundtrip/1, @@ -149,6 +217,7 @@ fail_range(Char, End) when Char =< End -> {'EXIT',_} = (catch <>), Bin = int_to_utf8(Char), fail(Bin), + fail(<>), fail_range(Char+1, End); fail_range(_, _) -> ok. @@ -201,24 +270,39 @@ overlong(Char, Last, NumBytes) when Char =< Last -> overlong(_, _, _) -> ok. overlong(Char, NumBytes) when NumBytes < 5 -> - case int_to_utf8(Char, NumBytes) of + Bin = int_to_utf8(Char, NumBytes), + case <<(int_to_utf8(Char, NumBytes))/binary>> of <>=Bin -> ct:fail({illegal_encoding_accepted,Bin,Char}); <>=Bin -> ct:fail({illegal_encoding_accepted,Bin,Char,OtherChar}); _ -> ok end, + case <<(int_to_utf8(Char, NumBytes))/binary,0:64>> of + <>=Bin2 -> + ct:fail({illegal_encoding_accepted,Bin2,Char}); + <>=Bin2 -> + ct:fail({illegal_encoding_accepted,Bin2,Char,OtherChar2}); + _ -> ok + end, overlong(Char, NumBytes+1); overlong(_, _) -> ok. fail(Bin) -> fail_1(Bin), - fail_1(make_unaligned(Bin)). + fail_1(make_unaligned(Bin)), + BinExt = <>, + fail_2(BinExt), + fail_2(make_unaligned(BinExt)). fail_1(<>=Bin) -> ct:fail({illegal_encoding_accepted,Bin,Char}); fail_1(_) -> ok. +fail_2(<>=Bin) -> + ct:fail({illegal_encoding_accepted,Bin,Char}); +fail_2(_) -> ok. + utf16_illegal_sequences(Config) when is_list(Config) -> utf16_fail_range(16#10FFFF+1, 16#10FFFF+512), %Too large. @@ -295,6 +379,9 @@ bad_construction(Config) when is_list(Config) -> ?FAIL(<<3.14/utf8>>), ?FAIL(<<3.1415/utf16>>), ?FAIL(<<3.1415/utf32>>), + {'EXIT',_} = (catch <<(id(3.14))/utf8>>), + {'EXIT',_} = (catch <<(id(3.1415))/utf16>>), + {'EXIT',_} = (catch <<(id(3.1415))/utf32>>), ?FAIL(<<(-1)/utf8>>), ?FAIL(<<(-1)/utf16>>), @@ -305,9 +392,23 @@ bad_construction(Config) when is_list(Config) -> ?FAIL(<<16#D800/utf8>>), ?FAIL(<<16#D800/utf16>>), ?FAIL(<<16#D800/utf32>>), + {'EXIT',_} = (catch <<(id(16#D800))/utf8>>), + {'EXIT',_} = (catch <<(id(16#D800))/utf16>>), + {'EXIT',_} = (catch <<(id(16#D800))/utf32>>), ok. +utf8_big_file(Config) -> + DataDir = get_data_dir(Config), + {ok, Bin} = file:read_file(filename:join(DataDir, "NormalizationTest.txt")), + List = unicode:characters_to_list(Bin), + _ = [begin + io:format("~p\n", [Offset]), + <<0:Offset, Rest/binary>> = id(<<0:Offset, Bin/binary>>), + List = [Char || <> <= Rest] + end || Offset <- lists:seq(0, 8)], + ok. + %% This function intentionally allows construction of %% UTF-8 sequence in illegal ranges. int_to_utf8(I) when I =< 16#7F -> @@ -384,4 +485,16 @@ evaluate(Str, Vars) -> Result end. +%% Retrieve the original data directory for cloned modules. +get_data_dir(Config) -> + Data = proplists:get_value(data_dir, Config), + Opts = [{return,list}], + Suffixes = ["_no_opt_SUITE", + "_r25_SUITE", + "_stripped_types_SUITE"], + lists:foldl(fun(Suffix, Acc) -> + Opts = [{return,list}], + re:replace(Acc, Suffix, "_SUITE", Opts) + end, Data, Suffixes). + id(I) -> I. diff --git a/erts/emulator/test/bs_utf_SUITE_data/NormalizationTest.txt b/erts/emulator/test/bs_utf_SUITE_data/NormalizationTest.txt new file mode 100644 index 000000000000..302c35f37c7d --- /dev/null +++ b/erts/emulator/test/bs_utf_SUITE_data/NormalizationTest.txt @@ -0,0 +1,19047 @@ +# NormalizationTest-14.0.0.txt +# Date: 2021-05-28, 21:49:12 GMT +# © 2021 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Normalization Test Suite +# Format: +# +# Columns (c1, c2,...) are separated by semicolons +# They have the following meaning: +# source; NFC; NFD; NFKC; NFKD +# Comments are indicated with hash marks +# Each of the columns may have one or more code points. +# +# CONFORMANCE: +# 1. The following invariants must be true for all conformant implementations +# +# NFC +# c2 == toNFC(c1) == toNFC(c2) == toNFC(c3) +# c4 == toNFC(c4) == toNFC(c5) +# +# NFD +# c3 == toNFD(c1) == toNFD(c2) == toNFD(c3) +# c5 == toNFD(c4) == toNFD(c5) +# +# NFKC +# c4 == toNFKC(c1) == toNFKC(c2) == toNFKC(c3) == toNFKC(c4) == toNFKC(c5) +# +# NFKD +# c5 == toNFKD(c1) == toNFKD(c2) == toNFKD(c3) == toNFKD(c4) == toNFKD(c5) +# +# 2. For every code point X assigned in this version of Unicode that is not specifically +# listed in Part 1, the following invariants must be true for all conformant +# implementations: +# +# X == toNFC(X) == toNFD(X) == toNFKC(X) == toNFKD(X) +# +@Part0 # Specific cases +# +1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +1E0A 0323;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (Ḋ◌̣; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW +1E0C 0307;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (Ḍ◌̇; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE +0044 0307 0323;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (D◌̇◌̣; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING DOT ABOVE, COMBINING DOT BELOW +0044 0323 0307;1E0C 0307;0044 0323 0307;1E0C 0307;0044 0323 0307; # (D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; Ḍ◌̇; D◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE +1E0A 031B;1E0A 031B;0044 031B 0307;1E0A 031B;0044 031B 0307; # (Ḋ◌̛; Ḋ◌̛; D◌̛◌̇; Ḋ◌̛; D◌̛◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING HORN +1E0C 031B;1E0C 031B;0044 031B 0323;1E0C 031B;0044 031B 0323; # (Ḍ◌̛; Ḍ◌̛; D◌̛◌̣; Ḍ◌̛; D◌̛◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING HORN +1E0A 031B 0323;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (Ḋ◌̛◌̣; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING HORN, COMBINING DOT BELOW +1E0C 031B 0307;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (Ḍ◌̛◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING HORN, COMBINING DOT ABOVE +0044 031B 0307 0323;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (D◌̛◌̇◌̣; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT ABOVE, COMBINING DOT BELOW +0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307;1E0C 031B 0307;0044 031B 0323 0307; # (D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; Ḍ◌̛◌̇; D◌̛◌̣◌̇; ) LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE +00C8;00C8;0045 0300;00C8;0045 0300; # (È; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E WITH GRAVE +0112;0112;0045 0304;0112;0045 0304; # (Ē; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E WITH MACRON +0045 0300;00C8;0045 0300;00C8;0045 0300; # (E◌̀; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E, COMBINING GRAVE ACCENT +0045 0304;0112;0045 0304;0112;0045 0304; # (E◌̄; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E, COMBINING MACRON +1E14;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ḕ; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +0112 0300;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ē◌̀; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT +1E14 0304;1E14 0304;0045 0304 0300 0304;1E14 0304;0045 0304 0300 0304; # (Ḕ◌̄; Ḕ◌̄; E◌̄◌̀◌̄; Ḕ◌̄; E◌̄◌̀◌̄; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON +0045 0304 0300;1E14;0045 0304 0300;1E14;0045 0304 0300; # (E◌̄◌̀; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E, COMBINING MACRON, COMBINING GRAVE ACCENT +0045 0300 0304;00C8 0304;0045 0300 0304;00C8 0304;0045 0300 0304; # (E◌̀◌̄; È◌̄; E◌̀◌̄; È◌̄; E◌̀◌̄; ) LATIN CAPITAL LETTER E, COMBINING GRAVE ACCENT, COMBINING MACRON +05B8 05B9 05B1 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F; # (◌ָ◌ֹ◌ֱ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ) HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL, HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA, HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA +0592 05B7 05BC 05A5 05B0 05C0 05C4 05AD;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4; # (◌֒◌ַ◌ּ◌֥◌ְ׀◌ׄ◌֭; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ) HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ, HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ, HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI +1100 AC00 11A8;1100 AC01;1100 1100 1161 11A8;1100 AC01;1100 1100 1161 11A8; # (ᄀ각; ᄀ각; ᄀ각; ᄀ각; ᄀ각; ) HANGUL CHOSEONG KIYEOK, HANGUL SYLLABLE GA, HANGUL JONGSEONG KIYEOK +1100 AC00 11A8 11A8;1100 AC01 11A8;1100 1100 1161 11A8 11A8;1100 AC01 11A8;1100 1100 1161 11A8 11A8; # (ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ) HANGUL CHOSEONG KIYEOK, HANGUL SYLLABLE GA, HANGUL JONGSEONG KIYEOK, HANGUL JONGSEONG KIYEOK +# +@Part1 # Character by character test +# All characters not explicitly occurring in c1 of Part 1 have identical NFC, D, KC, KD forms. +# +00A0;00A0;00A0;0020;0020; # ( ;  ;  ; ; ; ) NO-BREAK SPACE +00A8;00A8;00A8;0020 0308;0020 0308; # (¨; ¨; ¨; ◌̈; ◌̈; ) DIAERESIS +00AA;00AA;00AA;0061;0061; # (ª; ª; ª; a; a; ) FEMININE ORDINAL INDICATOR +00AF;00AF;00AF;0020 0304;0020 0304; # (¯; ¯; ¯; ◌̄; ◌̄; ) MACRON +00B2;00B2;00B2;0032;0032; # (²; ²; ²; 2; 2; ) SUPERSCRIPT TWO +00B3;00B3;00B3;0033;0033; # (³; ³; ³; 3; 3; ) SUPERSCRIPT THREE +00B4;00B4;00B4;0020 0301;0020 0301; # (´; ´; ´; ◌́; ◌́; ) ACUTE ACCENT +00B5;00B5;00B5;03BC;03BC; # (µ; µ; µ; μ; μ; ) MICRO SIGN +00B8;00B8;00B8;0020 0327;0020 0327; # (¸; ¸; ¸; ◌̧; ◌̧; ) CEDILLA +00B9;00B9;00B9;0031;0031; # (¹; ¹; ¹; 1; 1; ) SUPERSCRIPT ONE +00BA;00BA;00BA;006F;006F; # (º; º; º; o; o; ) MASCULINE ORDINAL INDICATOR +00BC;00BC;00BC;0031 2044 0034;0031 2044 0034; # (¼; ¼; ¼; 1⁄4; 1⁄4; ) VULGAR FRACTION ONE QUARTER +00BD;00BD;00BD;0031 2044 0032;0031 2044 0032; # (½; ½; ½; 1⁄2; 1⁄2; ) VULGAR FRACTION ONE HALF +00BE;00BE;00BE;0033 2044 0034;0033 2044 0034; # (¾; ¾; ¾; 3⁄4; 3⁄4; ) VULGAR FRACTION THREE QUARTERS +00C0;00C0;0041 0300;00C0;0041 0300; # (À; À; A◌̀; À; A◌̀; ) LATIN CAPITAL LETTER A WITH GRAVE +00C1;00C1;0041 0301;00C1;0041 0301; # (Á; Á; A◌́; Á; A◌́; ) LATIN CAPITAL LETTER A WITH ACUTE +00C2;00C2;0041 0302;00C2;0041 0302; # (Â; Â; A◌̂; Â; A◌̂; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3;00C3;0041 0303;00C3;0041 0303; # (Ã; Ã; A◌̃; Ã; A◌̃; ) LATIN CAPITAL LETTER A WITH TILDE +00C4;00C4;0041 0308;00C4;0041 0308; # (Ä; Ä; A◌̈; Ä; A◌̈; ) LATIN CAPITAL LETTER A WITH DIAERESIS +00C5;00C5;0041 030A;00C5;0041 030A; # (Å; Å; A◌̊; Å; A◌̊; ) LATIN CAPITAL LETTER A WITH RING ABOVE +00C7;00C7;0043 0327;00C7;0043 0327; # (Ç; Ç; C◌̧; Ç; C◌̧; ) LATIN CAPITAL LETTER C WITH CEDILLA +00C8;00C8;0045 0300;00C8;0045 0300; # (È; È; E◌̀; È; E◌̀; ) LATIN CAPITAL LETTER E WITH GRAVE +00C9;00C9;0045 0301;00C9;0045 0301; # (É; É; E◌́; É; E◌́; ) LATIN CAPITAL LETTER E WITH ACUTE +00CA;00CA;0045 0302;00CA;0045 0302; # (Ê; Ê; E◌̂; Ê; E◌̂; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB;00CB;0045 0308;00CB;0045 0308; # (Ë; Ë; E◌̈; Ë; E◌̈; ) LATIN CAPITAL LETTER E WITH DIAERESIS +00CC;00CC;0049 0300;00CC;0049 0300; # (Ì; Ì; I◌̀; Ì; I◌̀; ) LATIN CAPITAL LETTER I WITH GRAVE +00CD;00CD;0049 0301;00CD;0049 0301; # (Í; Í; I◌́; Í; I◌́; ) LATIN CAPITAL LETTER I WITH ACUTE +00CE;00CE;0049 0302;00CE;0049 0302; # (Î; Î; I◌̂; Î; I◌̂; ) LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF;00CF;0049 0308;00CF;0049 0308; # (Ï; Ï; I◌̈; Ï; I◌̈; ) LATIN CAPITAL LETTER I WITH DIAERESIS +00D1;00D1;004E 0303;00D1;004E 0303; # (Ñ; Ñ; N◌̃; Ñ; N◌̃; ) LATIN CAPITAL LETTER N WITH TILDE +00D2;00D2;004F 0300;00D2;004F 0300; # (Ò; Ò; O◌̀; Ò; O◌̀; ) LATIN CAPITAL LETTER O WITH GRAVE +00D3;00D3;004F 0301;00D3;004F 0301; # (Ó; Ó; O◌́; Ó; O◌́; ) LATIN CAPITAL LETTER O WITH ACUTE +00D4;00D4;004F 0302;00D4;004F 0302; # (Ô; Ô; O◌̂; Ô; O◌̂; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5;00D5;004F 0303;00D5;004F 0303; # (Õ; Õ; O◌̃; Õ; O◌̃; ) LATIN CAPITAL LETTER O WITH TILDE +00D6;00D6;004F 0308;00D6;004F 0308; # (Ö; Ö; O◌̈; Ö; O◌̈; ) LATIN CAPITAL LETTER O WITH DIAERESIS +00D9;00D9;0055 0300;00D9;0055 0300; # (Ù; Ù; U◌̀; Ù; U◌̀; ) LATIN CAPITAL LETTER U WITH GRAVE +00DA;00DA;0055 0301;00DA;0055 0301; # (Ú; Ú; U◌́; Ú; U◌́; ) LATIN CAPITAL LETTER U WITH ACUTE +00DB;00DB;0055 0302;00DB;0055 0302; # (Û; Û; U◌̂; Û; U◌̂; ) LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC;00DC;0055 0308;00DC;0055 0308; # (Ü; Ü; U◌̈; Ü; U◌̈; ) LATIN CAPITAL LETTER U WITH DIAERESIS +00DD;00DD;0059 0301;00DD;0059 0301; # (Ý; Ý; Y◌́; Ý; Y◌́; ) LATIN CAPITAL LETTER Y WITH ACUTE +00E0;00E0;0061 0300;00E0;0061 0300; # (à; à; a◌̀; à; a◌̀; ) LATIN SMALL LETTER A WITH GRAVE +00E1;00E1;0061 0301;00E1;0061 0301; # (á; á; a◌́; á; a◌́; ) LATIN SMALL LETTER A WITH ACUTE +00E2;00E2;0061 0302;00E2;0061 0302; # (â; â; a◌̂; â; a◌̂; ) LATIN SMALL LETTER A WITH CIRCUMFLEX +00E3;00E3;0061 0303;00E3;0061 0303; # (ã; ã; a◌̃; ã; a◌̃; ) LATIN SMALL LETTER A WITH TILDE +00E4;00E4;0061 0308;00E4;0061 0308; # (ä; ä; a◌̈; ä; a◌̈; ) LATIN SMALL LETTER A WITH DIAERESIS +00E5;00E5;0061 030A;00E5;0061 030A; # (å; å; a◌̊; å; a◌̊; ) LATIN SMALL LETTER A WITH RING ABOVE +00E7;00E7;0063 0327;00E7;0063 0327; # (ç; ç; c◌̧; ç; c◌̧; ) LATIN SMALL LETTER C WITH CEDILLA +00E8;00E8;0065 0300;00E8;0065 0300; # (è; è; e◌̀; è; e◌̀; ) LATIN SMALL LETTER E WITH GRAVE +00E9;00E9;0065 0301;00E9;0065 0301; # (é; é; e◌́; é; e◌́; ) LATIN SMALL LETTER E WITH ACUTE +00EA;00EA;0065 0302;00EA;0065 0302; # (ê; ê; e◌̂; ê; e◌̂; ) LATIN SMALL LETTER E WITH CIRCUMFLEX +00EB;00EB;0065 0308;00EB;0065 0308; # (ë; ë; e◌̈; ë; e◌̈; ) LATIN SMALL LETTER E WITH DIAERESIS +00EC;00EC;0069 0300;00EC;0069 0300; # (ì; ì; i◌̀; ì; i◌̀; ) LATIN SMALL LETTER I WITH GRAVE +00ED;00ED;0069 0301;00ED;0069 0301; # (í; í; i◌́; í; i◌́; ) LATIN SMALL LETTER I WITH ACUTE +00EE;00EE;0069 0302;00EE;0069 0302; # (î; î; i◌̂; î; i◌̂; ) LATIN SMALL LETTER I WITH CIRCUMFLEX +00EF;00EF;0069 0308;00EF;0069 0308; # (ï; ï; i◌̈; ï; i◌̈; ) LATIN SMALL LETTER I WITH DIAERESIS +00F1;00F1;006E 0303;00F1;006E 0303; # (ñ; ñ; n◌̃; ñ; n◌̃; ) LATIN SMALL LETTER N WITH TILDE +00F2;00F2;006F 0300;00F2;006F 0300; # (ò; ò; o◌̀; ò; o◌̀; ) LATIN SMALL LETTER O WITH GRAVE +00F3;00F3;006F 0301;00F3;006F 0301; # (ó; ó; o◌́; ó; o◌́; ) LATIN SMALL LETTER O WITH ACUTE +00F4;00F4;006F 0302;00F4;006F 0302; # (ô; ô; o◌̂; ô; o◌̂; ) LATIN SMALL LETTER O WITH CIRCUMFLEX +00F5;00F5;006F 0303;00F5;006F 0303; # (õ; õ; o◌̃; õ; o◌̃; ) LATIN SMALL LETTER O WITH TILDE +00F6;00F6;006F 0308;00F6;006F 0308; # (ö; ö; o◌̈; ö; o◌̈; ) LATIN SMALL LETTER O WITH DIAERESIS +00F9;00F9;0075 0300;00F9;0075 0300; # (ù; ù; u◌̀; ù; u◌̀; ) LATIN SMALL LETTER U WITH GRAVE +00FA;00FA;0075 0301;00FA;0075 0301; # (ú; ú; u◌́; ú; u◌́; ) LATIN SMALL LETTER U WITH ACUTE +00FB;00FB;0075 0302;00FB;0075 0302; # (û; û; u◌̂; û; u◌̂; ) LATIN SMALL LETTER U WITH CIRCUMFLEX +00FC;00FC;0075 0308;00FC;0075 0308; # (ü; ü; u◌̈; ü; u◌̈; ) LATIN SMALL LETTER U WITH DIAERESIS +00FD;00FD;0079 0301;00FD;0079 0301; # (ý; ý; y◌́; ý; y◌́; ) LATIN SMALL LETTER Y WITH ACUTE +00FF;00FF;0079 0308;00FF;0079 0308; # (ÿ; ÿ; y◌̈; ÿ; y◌̈; ) LATIN SMALL LETTER Y WITH DIAERESIS +0100;0100;0041 0304;0100;0041 0304; # (Ā; Ā; A◌̄; Ā; A◌̄; ) LATIN CAPITAL LETTER A WITH MACRON +0101;0101;0061 0304;0101;0061 0304; # (ā; ā; a◌̄; ā; a◌̄; ) LATIN SMALL LETTER A WITH MACRON +0102;0102;0041 0306;0102;0041 0306; # (Ă; Ă; A◌̆; Ă; A◌̆; ) LATIN CAPITAL LETTER A WITH BREVE +0103;0103;0061 0306;0103;0061 0306; # (ă; ă; a◌̆; ă; a◌̆; ) LATIN SMALL LETTER A WITH BREVE +0104;0104;0041 0328;0104;0041 0328; # (Ą; Ą; A◌̨; Ą; A◌̨; ) LATIN CAPITAL LETTER A WITH OGONEK +0105;0105;0061 0328;0105;0061 0328; # (ą; ą; a◌̨; ą; a◌̨; ) LATIN SMALL LETTER A WITH OGONEK +0106;0106;0043 0301;0106;0043 0301; # (Ć; Ć; C◌́; Ć; C◌́; ) LATIN CAPITAL LETTER C WITH ACUTE +0107;0107;0063 0301;0107;0063 0301; # (ć; ć; c◌́; ć; c◌́; ) LATIN SMALL LETTER C WITH ACUTE +0108;0108;0043 0302;0108;0043 0302; # (Ĉ; Ĉ; C◌̂; Ĉ; C◌̂; ) LATIN CAPITAL LETTER C WITH CIRCUMFLEX +0109;0109;0063 0302;0109;0063 0302; # (ĉ; ĉ; c◌̂; ĉ; c◌̂; ) LATIN SMALL LETTER C WITH CIRCUMFLEX +010A;010A;0043 0307;010A;0043 0307; # (Ċ; Ċ; C◌̇; Ċ; C◌̇; ) LATIN CAPITAL LETTER C WITH DOT ABOVE +010B;010B;0063 0307;010B;0063 0307; # (ċ; ċ; c◌̇; ċ; c◌̇; ) LATIN SMALL LETTER C WITH DOT ABOVE +010C;010C;0043 030C;010C;0043 030C; # (Č; Č; C◌̌; Č; C◌̌; ) LATIN CAPITAL LETTER C WITH CARON +010D;010D;0063 030C;010D;0063 030C; # (č; č; c◌̌; č; c◌̌; ) LATIN SMALL LETTER C WITH CARON +010E;010E;0044 030C;010E;0044 030C; # (Ď; Ď; D◌̌; Ď; D◌̌; ) LATIN CAPITAL LETTER D WITH CARON +010F;010F;0064 030C;010F;0064 030C; # (ď; ď; d◌̌; ď; d◌̌; ) LATIN SMALL LETTER D WITH CARON +0112;0112;0045 0304;0112;0045 0304; # (Ē; Ē; E◌̄; Ē; E◌̄; ) LATIN CAPITAL LETTER E WITH MACRON +0113;0113;0065 0304;0113;0065 0304; # (ē; ē; e◌̄; ē; e◌̄; ) LATIN SMALL LETTER E WITH MACRON +0114;0114;0045 0306;0114;0045 0306; # (Ĕ; Ĕ; E◌̆; Ĕ; E◌̆; ) LATIN CAPITAL LETTER E WITH BREVE +0115;0115;0065 0306;0115;0065 0306; # (ĕ; ĕ; e◌̆; ĕ; e◌̆; ) LATIN SMALL LETTER E WITH BREVE +0116;0116;0045 0307;0116;0045 0307; # (Ė; Ė; E◌̇; Ė; E◌̇; ) LATIN CAPITAL LETTER E WITH DOT ABOVE +0117;0117;0065 0307;0117;0065 0307; # (ė; ė; e◌̇; ė; e◌̇; ) LATIN SMALL LETTER E WITH DOT ABOVE +0118;0118;0045 0328;0118;0045 0328; # (Ę; Ę; E◌̨; Ę; E◌̨; ) LATIN CAPITAL LETTER E WITH OGONEK +0119;0119;0065 0328;0119;0065 0328; # (ę; ę; e◌̨; ę; e◌̨; ) LATIN SMALL LETTER E WITH OGONEK +011A;011A;0045 030C;011A;0045 030C; # (Ě; Ě; E◌̌; Ě; E◌̌; ) LATIN CAPITAL LETTER E WITH CARON +011B;011B;0065 030C;011B;0065 030C; # (ě; ě; e◌̌; ě; e◌̌; ) LATIN SMALL LETTER E WITH CARON +011C;011C;0047 0302;011C;0047 0302; # (Ĝ; Ĝ; G◌̂; Ĝ; G◌̂; ) LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011D;011D;0067 0302;011D;0067 0302; # (ĝ; ĝ; g◌̂; ĝ; g◌̂; ) LATIN SMALL LETTER G WITH CIRCUMFLEX +011E;011E;0047 0306;011E;0047 0306; # (Ğ; Ğ; G◌̆; Ğ; G◌̆; ) LATIN CAPITAL LETTER G WITH BREVE +011F;011F;0067 0306;011F;0067 0306; # (ğ; ğ; g◌̆; ğ; g◌̆; ) LATIN SMALL LETTER G WITH BREVE +0120;0120;0047 0307;0120;0047 0307; # (Ġ; Ġ; G◌̇; Ġ; G◌̇; ) LATIN CAPITAL LETTER G WITH DOT ABOVE +0121;0121;0067 0307;0121;0067 0307; # (ġ; ġ; g◌̇; ġ; g◌̇; ) LATIN SMALL LETTER G WITH DOT ABOVE +0122;0122;0047 0327;0122;0047 0327; # (Ģ; Ģ; G◌̧; Ģ; G◌̧; ) LATIN CAPITAL LETTER G WITH CEDILLA +0123;0123;0067 0327;0123;0067 0327; # (ģ; ģ; g◌̧; ģ; g◌̧; ) LATIN SMALL LETTER G WITH CEDILLA +0124;0124;0048 0302;0124;0048 0302; # (Ĥ; Ĥ; H◌̂; Ĥ; H◌̂; ) LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0125;0125;0068 0302;0125;0068 0302; # (ĥ; ĥ; h◌̂; ĥ; h◌̂; ) LATIN SMALL LETTER H WITH CIRCUMFLEX +0128;0128;0049 0303;0128;0049 0303; # (Ĩ; Ĩ; I◌̃; Ĩ; I◌̃; ) LATIN CAPITAL LETTER I WITH TILDE +0129;0129;0069 0303;0129;0069 0303; # (ĩ; ĩ; i◌̃; ĩ; i◌̃; ) LATIN SMALL LETTER I WITH TILDE +012A;012A;0049 0304;012A;0049 0304; # (Ī; Ī; I◌̄; Ī; I◌̄; ) LATIN CAPITAL LETTER I WITH MACRON +012B;012B;0069 0304;012B;0069 0304; # (ī; ī; i◌̄; ī; i◌̄; ) LATIN SMALL LETTER I WITH MACRON +012C;012C;0049 0306;012C;0049 0306; # (Ĭ; Ĭ; I◌̆; Ĭ; I◌̆; ) LATIN CAPITAL LETTER I WITH BREVE +012D;012D;0069 0306;012D;0069 0306; # (ĭ; ĭ; i◌̆; ĭ; i◌̆; ) LATIN SMALL LETTER I WITH BREVE +012E;012E;0049 0328;012E;0049 0328; # (Į; Į; I◌̨; Į; I◌̨; ) LATIN CAPITAL LETTER I WITH OGONEK +012F;012F;0069 0328;012F;0069 0328; # (į; į; i◌̨; į; i◌̨; ) LATIN SMALL LETTER I WITH OGONEK +0130;0130;0049 0307;0130;0049 0307; # (İ; İ; I◌̇; İ; I◌̇; ) LATIN CAPITAL LETTER I WITH DOT ABOVE +0132;0132;0132;0049 004A;0049 004A; # (IJ; IJ; IJ; IJ; IJ; ) LATIN CAPITAL LIGATURE IJ +0133;0133;0133;0069 006A;0069 006A; # (ij; ij; ij; ij; ij; ) LATIN SMALL LIGATURE IJ +0134;0134;004A 0302;0134;004A 0302; # (Ĵ; Ĵ; J◌̂; Ĵ; J◌̂; ) LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0135;0135;006A 0302;0135;006A 0302; # (ĵ; ĵ; j◌̂; ĵ; j◌̂; ) LATIN SMALL LETTER J WITH CIRCUMFLEX +0136;0136;004B 0327;0136;004B 0327; # (Ķ; Ķ; K◌̧; Ķ; K◌̧; ) LATIN CAPITAL LETTER K WITH CEDILLA +0137;0137;006B 0327;0137;006B 0327; # (ķ; ķ; k◌̧; ķ; k◌̧; ) LATIN SMALL LETTER K WITH CEDILLA +0139;0139;004C 0301;0139;004C 0301; # (Ĺ; Ĺ; L◌́; Ĺ; L◌́; ) LATIN CAPITAL LETTER L WITH ACUTE +013A;013A;006C 0301;013A;006C 0301; # (ĺ; ĺ; l◌́; ĺ; l◌́; ) LATIN SMALL LETTER L WITH ACUTE +013B;013B;004C 0327;013B;004C 0327; # (Ļ; Ļ; L◌̧; Ļ; L◌̧; ) LATIN CAPITAL LETTER L WITH CEDILLA +013C;013C;006C 0327;013C;006C 0327; # (ļ; ļ; l◌̧; ļ; l◌̧; ) LATIN SMALL LETTER L WITH CEDILLA +013D;013D;004C 030C;013D;004C 030C; # (Ľ; Ľ; L◌̌; Ľ; L◌̌; ) LATIN CAPITAL LETTER L WITH CARON +013E;013E;006C 030C;013E;006C 030C; # (ľ; ľ; l◌̌; ľ; l◌̌; ) LATIN SMALL LETTER L WITH CARON +013F;013F;013F;004C 00B7;004C 00B7; # (Ŀ; Ŀ; Ŀ; L·; L·; ) LATIN CAPITAL LETTER L WITH MIDDLE DOT +0140;0140;0140;006C 00B7;006C 00B7; # (ŀ; ŀ; ŀ; l·; l·; ) LATIN SMALL LETTER L WITH MIDDLE DOT +0143;0143;004E 0301;0143;004E 0301; # (Ń; Ń; N◌́; Ń; N◌́; ) LATIN CAPITAL LETTER N WITH ACUTE +0144;0144;006E 0301;0144;006E 0301; # (ń; ń; n◌́; ń; n◌́; ) LATIN SMALL LETTER N WITH ACUTE +0145;0145;004E 0327;0145;004E 0327; # (Ņ; Ņ; N◌̧; Ņ; N◌̧; ) LATIN CAPITAL LETTER N WITH CEDILLA +0146;0146;006E 0327;0146;006E 0327; # (ņ; ņ; n◌̧; ņ; n◌̧; ) LATIN SMALL LETTER N WITH CEDILLA +0147;0147;004E 030C;0147;004E 030C; # (Ň; Ň; N◌̌; Ň; N◌̌; ) LATIN CAPITAL LETTER N WITH CARON +0148;0148;006E 030C;0148;006E 030C; # (ň; ň; n◌̌; ň; n◌̌; ) LATIN SMALL LETTER N WITH CARON +0149;0149;0149;02BC 006E;02BC 006E; # (ʼn; ʼn; ʼn; ʼn; ʼn; ) LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014C;014C;004F 0304;014C;004F 0304; # (Ō; Ō; O◌̄; Ō; O◌̄; ) LATIN CAPITAL LETTER O WITH MACRON +014D;014D;006F 0304;014D;006F 0304; # (ō; ō; o◌̄; ō; o◌̄; ) LATIN SMALL LETTER O WITH MACRON +014E;014E;004F 0306;014E;004F 0306; # (Ŏ; Ŏ; O◌̆; Ŏ; O◌̆; ) LATIN CAPITAL LETTER O WITH BREVE +014F;014F;006F 0306;014F;006F 0306; # (ŏ; ŏ; o◌̆; ŏ; o◌̆; ) LATIN SMALL LETTER O WITH BREVE +0150;0150;004F 030B;0150;004F 030B; # (Ő; Ő; O◌̋; Ő; O◌̋; ) LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0151;0151;006F 030B;0151;006F 030B; # (ő; ő; o◌̋; ő; o◌̋; ) LATIN SMALL LETTER O WITH DOUBLE ACUTE +0154;0154;0052 0301;0154;0052 0301; # (Ŕ; Ŕ; R◌́; Ŕ; R◌́; ) LATIN CAPITAL LETTER R WITH ACUTE +0155;0155;0072 0301;0155;0072 0301; # (ŕ; ŕ; r◌́; ŕ; r◌́; ) LATIN SMALL LETTER R WITH ACUTE +0156;0156;0052 0327;0156;0052 0327; # (Ŗ; Ŗ; R◌̧; Ŗ; R◌̧; ) LATIN CAPITAL LETTER R WITH CEDILLA +0157;0157;0072 0327;0157;0072 0327; # (ŗ; ŗ; r◌̧; ŗ; r◌̧; ) LATIN SMALL LETTER R WITH CEDILLA +0158;0158;0052 030C;0158;0052 030C; # (Ř; Ř; R◌̌; Ř; R◌̌; ) LATIN CAPITAL LETTER R WITH CARON +0159;0159;0072 030C;0159;0072 030C; # (ř; ř; r◌̌; ř; r◌̌; ) LATIN SMALL LETTER R WITH CARON +015A;015A;0053 0301;015A;0053 0301; # (Ś; Ś; S◌́; Ś; S◌́; ) LATIN CAPITAL LETTER S WITH ACUTE +015B;015B;0073 0301;015B;0073 0301; # (ś; ś; s◌́; ś; s◌́; ) LATIN SMALL LETTER S WITH ACUTE +015C;015C;0053 0302;015C;0053 0302; # (Ŝ; Ŝ; S◌̂; Ŝ; S◌̂; ) LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015D;015D;0073 0302;015D;0073 0302; # (ŝ; ŝ; s◌̂; ŝ; s◌̂; ) LATIN SMALL LETTER S WITH CIRCUMFLEX +015E;015E;0053 0327;015E;0053 0327; # (Ş; Ş; S◌̧; Ş; S◌̧; ) LATIN CAPITAL LETTER S WITH CEDILLA +015F;015F;0073 0327;015F;0073 0327; # (ş; ş; s◌̧; ş; s◌̧; ) LATIN SMALL LETTER S WITH CEDILLA +0160;0160;0053 030C;0160;0053 030C; # (Š; Š; S◌̌; Š; S◌̌; ) LATIN CAPITAL LETTER S WITH CARON +0161;0161;0073 030C;0161;0073 030C; # (š; š; s◌̌; š; s◌̌; ) LATIN SMALL LETTER S WITH CARON +0162;0162;0054 0327;0162;0054 0327; # (Ţ; Ţ; T◌̧; Ţ; T◌̧; ) LATIN CAPITAL LETTER T WITH CEDILLA +0163;0163;0074 0327;0163;0074 0327; # (ţ; ţ; t◌̧; ţ; t◌̧; ) LATIN SMALL LETTER T WITH CEDILLA +0164;0164;0054 030C;0164;0054 030C; # (Ť; Ť; T◌̌; Ť; T◌̌; ) LATIN CAPITAL LETTER T WITH CARON +0165;0165;0074 030C;0165;0074 030C; # (ť; ť; t◌̌; ť; t◌̌; ) LATIN SMALL LETTER T WITH CARON +0168;0168;0055 0303;0168;0055 0303; # (Ũ; Ũ; U◌̃; Ũ; U◌̃; ) LATIN CAPITAL LETTER U WITH TILDE +0169;0169;0075 0303;0169;0075 0303; # (ũ; ũ; u◌̃; ũ; u◌̃; ) LATIN SMALL LETTER U WITH TILDE +016A;016A;0055 0304;016A;0055 0304; # (Ū; Ū; U◌̄; Ū; U◌̄; ) LATIN CAPITAL LETTER U WITH MACRON +016B;016B;0075 0304;016B;0075 0304; # (ū; ū; u◌̄; ū; u◌̄; ) LATIN SMALL LETTER U WITH MACRON +016C;016C;0055 0306;016C;0055 0306; # (Ŭ; Ŭ; U◌̆; Ŭ; U◌̆; ) LATIN CAPITAL LETTER U WITH BREVE +016D;016D;0075 0306;016D;0075 0306; # (ŭ; ŭ; u◌̆; ŭ; u◌̆; ) LATIN SMALL LETTER U WITH BREVE +016E;016E;0055 030A;016E;0055 030A; # (Ů; Ů; U◌̊; Ů; U◌̊; ) LATIN CAPITAL LETTER U WITH RING ABOVE +016F;016F;0075 030A;016F;0075 030A; # (ů; ů; u◌̊; ů; u◌̊; ) LATIN SMALL LETTER U WITH RING ABOVE +0170;0170;0055 030B;0170;0055 030B; # (Ű; Ű; U◌̋; Ű; U◌̋; ) LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0171;0171;0075 030B;0171;0075 030B; # (ű; ű; u◌̋; ű; u◌̋; ) LATIN SMALL LETTER U WITH DOUBLE ACUTE +0172;0172;0055 0328;0172;0055 0328; # (Ų; Ų; U◌̨; Ų; U◌̨; ) LATIN CAPITAL LETTER U WITH OGONEK +0173;0173;0075 0328;0173;0075 0328; # (ų; ų; u◌̨; ų; u◌̨; ) LATIN SMALL LETTER U WITH OGONEK +0174;0174;0057 0302;0174;0057 0302; # (Ŵ; Ŵ; W◌̂; Ŵ; W◌̂; ) LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0175;0175;0077 0302;0175;0077 0302; # (ŵ; ŵ; w◌̂; ŵ; w◌̂; ) LATIN SMALL LETTER W WITH CIRCUMFLEX +0176;0176;0059 0302;0176;0059 0302; # (Ŷ; Ŷ; Y◌̂; Ŷ; Y◌̂; ) LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0177;0177;0079 0302;0177;0079 0302; # (ŷ; ŷ; y◌̂; ŷ; y◌̂; ) LATIN SMALL LETTER Y WITH CIRCUMFLEX +0178;0178;0059 0308;0178;0059 0308; # (Ÿ; Ÿ; Y◌̈; Ÿ; Y◌̈; ) LATIN CAPITAL LETTER Y WITH DIAERESIS +0179;0179;005A 0301;0179;005A 0301; # (Ź; Ź; Z◌́; Ź; Z◌́; ) LATIN CAPITAL LETTER Z WITH ACUTE +017A;017A;007A 0301;017A;007A 0301; # (ź; ź; z◌́; ź; z◌́; ) LATIN SMALL LETTER Z WITH ACUTE +017B;017B;005A 0307;017B;005A 0307; # (Ż; Ż; Z◌̇; Ż; Z◌̇; ) LATIN CAPITAL LETTER Z WITH DOT ABOVE +017C;017C;007A 0307;017C;007A 0307; # (ż; ż; z◌̇; ż; z◌̇; ) LATIN SMALL LETTER Z WITH DOT ABOVE +017D;017D;005A 030C;017D;005A 030C; # (Ž; Ž; Z◌̌; Ž; Z◌̌; ) LATIN CAPITAL LETTER Z WITH CARON +017E;017E;007A 030C;017E;007A 030C; # (ž; ž; z◌̌; ž; z◌̌; ) LATIN SMALL LETTER Z WITH CARON +017F;017F;017F;0073;0073; # (ſ; ſ; ſ; s; s; ) LATIN SMALL LETTER LONG S +01A0;01A0;004F 031B;01A0;004F 031B; # (Ơ; Ơ; O◌̛; Ơ; O◌̛; ) LATIN CAPITAL LETTER O WITH HORN +01A1;01A1;006F 031B;01A1;006F 031B; # (ơ; ơ; o◌̛; ơ; o◌̛; ) LATIN SMALL LETTER O WITH HORN +01AF;01AF;0055 031B;01AF;0055 031B; # (Ư; Ư; U◌̛; Ư; U◌̛; ) LATIN CAPITAL LETTER U WITH HORN +01B0;01B0;0075 031B;01B0;0075 031B; # (ư; ư; u◌̛; ư; u◌̛; ) LATIN SMALL LETTER U WITH HORN +01C4;01C4;01C4;0044 017D;0044 005A 030C; # (DŽ; DŽ; DŽ; DŽ; DZ◌̌; ) LATIN CAPITAL LETTER DZ WITH CARON +01C5;01C5;01C5;0044 017E;0044 007A 030C; # (Dž; Dž; Dž; Dž; Dz◌̌; ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C6;01C6;01C6;0064 017E;0064 007A 030C; # (dž; dž; dž; dž; dz◌̌; ) LATIN SMALL LETTER DZ WITH CARON +01C7;01C7;01C7;004C 004A;004C 004A; # (LJ; LJ; LJ; LJ; LJ; ) LATIN CAPITAL LETTER LJ +01C8;01C8;01C8;004C 006A;004C 006A; # (Lj; Lj; Lj; Lj; Lj; ) LATIN CAPITAL LETTER L WITH SMALL LETTER J +01C9;01C9;01C9;006C 006A;006C 006A; # (lj; lj; lj; lj; lj; ) LATIN SMALL LETTER LJ +01CA;01CA;01CA;004E 004A;004E 004A; # (NJ; NJ; NJ; NJ; NJ; ) LATIN CAPITAL LETTER NJ +01CB;01CB;01CB;004E 006A;004E 006A; # (Nj; Nj; Nj; Nj; Nj; ) LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CC;01CC;01CC;006E 006A;006E 006A; # (nj; nj; nj; nj; nj; ) LATIN SMALL LETTER NJ +01CD;01CD;0041 030C;01CD;0041 030C; # (Ǎ; Ǎ; A◌̌; Ǎ; A◌̌; ) LATIN CAPITAL LETTER A WITH CARON +01CE;01CE;0061 030C;01CE;0061 030C; # (ǎ; ǎ; a◌̌; ǎ; a◌̌; ) LATIN SMALL LETTER A WITH CARON +01CF;01CF;0049 030C;01CF;0049 030C; # (Ǐ; Ǐ; I◌̌; Ǐ; I◌̌; ) LATIN CAPITAL LETTER I WITH CARON +01D0;01D0;0069 030C;01D0;0069 030C; # (ǐ; ǐ; i◌̌; ǐ; i◌̌; ) LATIN SMALL LETTER I WITH CARON +01D1;01D1;004F 030C;01D1;004F 030C; # (Ǒ; Ǒ; O◌̌; Ǒ; O◌̌; ) LATIN CAPITAL LETTER O WITH CARON +01D2;01D2;006F 030C;01D2;006F 030C; # (ǒ; ǒ; o◌̌; ǒ; o◌̌; ) LATIN SMALL LETTER O WITH CARON +01D3;01D3;0055 030C;01D3;0055 030C; # (Ǔ; Ǔ; U◌̌; Ǔ; U◌̌; ) LATIN CAPITAL LETTER U WITH CARON +01D4;01D4;0075 030C;01D4;0075 030C; # (ǔ; ǔ; u◌̌; ǔ; u◌̌; ) LATIN SMALL LETTER U WITH CARON +01D5;01D5;0055 0308 0304;01D5;0055 0308 0304; # (Ǖ; Ǖ; U◌̈◌̄; Ǖ; U◌̈◌̄; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D6;01D6;0075 0308 0304;01D6;0075 0308 0304; # (ǖ; ǖ; u◌̈◌̄; ǖ; u◌̈◌̄; ) LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D7;01D7;0055 0308 0301;01D7;0055 0308 0301; # (Ǘ; Ǘ; U◌̈◌́; Ǘ; U◌̈◌́; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D8;01D8;0075 0308 0301;01D8;0075 0308 0301; # (ǘ; ǘ; u◌̈◌́; ǘ; u◌̈◌́; ) LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01D9;01D9;0055 0308 030C;01D9;0055 0308 030C; # (Ǚ; Ǚ; U◌̈◌̌; Ǚ; U◌̈◌̌; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DA;01DA;0075 0308 030C;01DA;0075 0308 030C; # (ǚ; ǚ; u◌̈◌̌; ǚ; u◌̈◌̌; ) LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DB;01DB;0055 0308 0300;01DB;0055 0308 0300; # (Ǜ; Ǜ; U◌̈◌̀; Ǜ; U◌̈◌̀; ) LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DC;01DC;0075 0308 0300;01DC;0075 0308 0300; # (ǜ; ǜ; u◌̈◌̀; ǜ; u◌̈◌̀; ) LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE +01DE;01DE;0041 0308 0304;01DE;0041 0308 0304; # (Ǟ; Ǟ; A◌̈◌̄; Ǟ; A◌̈◌̄; ) LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01DF;01DF;0061 0308 0304;01DF;0061 0308 0304; # (ǟ; ǟ; a◌̈◌̄; ǟ; a◌̈◌̄; ) LATIN SMALL LETTER A WITH DIAERESIS AND MACRON +01E0;01E0;0041 0307 0304;01E0;0041 0307 0304; # (Ǡ; Ǡ; A◌̇◌̄; Ǡ; A◌̇◌̄; ) LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E1;01E1;0061 0307 0304;01E1;0061 0307 0304; # (ǡ; ǡ; a◌̇◌̄; ǡ; a◌̇◌̄; ) LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON +01E2;01E2;00C6 0304;01E2;00C6 0304; # (Ǣ; Ǣ; Æ◌̄; Ǣ; Æ◌̄; ) LATIN CAPITAL LETTER AE WITH MACRON +01E3;01E3;00E6 0304;01E3;00E6 0304; # (ǣ; ǣ; æ◌̄; ǣ; æ◌̄; ) LATIN SMALL LETTER AE WITH MACRON +01E6;01E6;0047 030C;01E6;0047 030C; # (Ǧ; Ǧ; G◌̌; Ǧ; G◌̌; ) LATIN CAPITAL LETTER G WITH CARON +01E7;01E7;0067 030C;01E7;0067 030C; # (ǧ; ǧ; g◌̌; ǧ; g◌̌; ) LATIN SMALL LETTER G WITH CARON +01E8;01E8;004B 030C;01E8;004B 030C; # (Ǩ; Ǩ; K◌̌; Ǩ; K◌̌; ) LATIN CAPITAL LETTER K WITH CARON +01E9;01E9;006B 030C;01E9;006B 030C; # (ǩ; ǩ; k◌̌; ǩ; k◌̌; ) LATIN SMALL LETTER K WITH CARON +01EA;01EA;004F 0328;01EA;004F 0328; # (Ǫ; Ǫ; O◌̨; Ǫ; O◌̨; ) LATIN CAPITAL LETTER O WITH OGONEK +01EB;01EB;006F 0328;01EB;006F 0328; # (ǫ; ǫ; o◌̨; ǫ; o◌̨; ) LATIN SMALL LETTER O WITH OGONEK +01EC;01EC;004F 0328 0304;01EC;004F 0328 0304; # (Ǭ; Ǭ; O◌̨◌̄; Ǭ; O◌̨◌̄; ) LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01ED;01ED;006F 0328 0304;01ED;006F 0328 0304; # (ǭ; ǭ; o◌̨◌̄; ǭ; o◌̨◌̄; ) LATIN SMALL LETTER O WITH OGONEK AND MACRON +01EE;01EE;01B7 030C;01EE;01B7 030C; # (Ǯ; Ǯ; Ʒ◌̌; Ǯ; Ʒ◌̌; ) LATIN CAPITAL LETTER EZH WITH CARON +01EF;01EF;0292 030C;01EF;0292 030C; # (ǯ; ǯ; ʒ◌̌; ǯ; ʒ◌̌; ) LATIN SMALL LETTER EZH WITH CARON +01F0;01F0;006A 030C;01F0;006A 030C; # (ǰ; ǰ; j◌̌; ǰ; j◌̌; ) LATIN SMALL LETTER J WITH CARON +01F1;01F1;01F1;0044 005A;0044 005A; # (DZ; DZ; DZ; DZ; DZ; ) LATIN CAPITAL LETTER DZ +01F2;01F2;01F2;0044 007A;0044 007A; # (Dz; Dz; Dz; Dz; Dz; ) LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F3;01F3;01F3;0064 007A;0064 007A; # (dz; dz; dz; dz; dz; ) LATIN SMALL LETTER DZ +01F4;01F4;0047 0301;01F4;0047 0301; # (Ǵ; Ǵ; G◌́; Ǵ; G◌́; ) LATIN CAPITAL LETTER G WITH ACUTE +01F5;01F5;0067 0301;01F5;0067 0301; # (ǵ; ǵ; g◌́; ǵ; g◌́; ) LATIN SMALL LETTER G WITH ACUTE +01F8;01F8;004E 0300;01F8;004E 0300; # (Ǹ; Ǹ; N◌̀; Ǹ; N◌̀; ) LATIN CAPITAL LETTER N WITH GRAVE +01F9;01F9;006E 0300;01F9;006E 0300; # (ǹ; ǹ; n◌̀; ǹ; n◌̀; ) LATIN SMALL LETTER N WITH GRAVE +01FA;01FA;0041 030A 0301;01FA;0041 030A 0301; # (Ǻ; Ǻ; A◌̊◌́; Ǻ; A◌̊◌́; ) LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FB;01FB;0061 030A 0301;01FB;0061 030A 0301; # (ǻ; ǻ; a◌̊◌́; ǻ; a◌̊◌́; ) LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +01FC;01FC;00C6 0301;01FC;00C6 0301; # (Ǽ; Ǽ; Æ◌́; Ǽ; Æ◌́; ) LATIN CAPITAL LETTER AE WITH ACUTE +01FD;01FD;00E6 0301;01FD;00E6 0301; # (ǽ; ǽ; æ◌́; ǽ; æ◌́; ) LATIN SMALL LETTER AE WITH ACUTE +01FE;01FE;00D8 0301;01FE;00D8 0301; # (Ǿ; Ǿ; Ø◌́; Ǿ; Ø◌́; ) LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +01FF;01FF;00F8 0301;01FF;00F8 0301; # (ǿ; ǿ; ø◌́; ǿ; ø◌́; ) LATIN SMALL LETTER O WITH STROKE AND ACUTE +0200;0200;0041 030F;0200;0041 030F; # (Ȁ; Ȁ; A◌̏; Ȁ; A◌̏; ) LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0201;0201;0061 030F;0201;0061 030F; # (ȁ; ȁ; a◌̏; ȁ; a◌̏; ) LATIN SMALL LETTER A WITH DOUBLE GRAVE +0202;0202;0041 0311;0202;0041 0311; # (Ȃ; Ȃ; A◌̑; Ȃ; A◌̑; ) LATIN CAPITAL LETTER A WITH INVERTED BREVE +0203;0203;0061 0311;0203;0061 0311; # (ȃ; ȃ; a◌̑; ȃ; a◌̑; ) LATIN SMALL LETTER A WITH INVERTED BREVE +0204;0204;0045 030F;0204;0045 030F; # (Ȅ; Ȅ; E◌̏; Ȅ; E◌̏; ) LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0205;0205;0065 030F;0205;0065 030F; # (ȅ; ȅ; e◌̏; ȅ; e◌̏; ) LATIN SMALL LETTER E WITH DOUBLE GRAVE +0206;0206;0045 0311;0206;0045 0311; # (Ȇ; Ȇ; E◌̑; Ȇ; E◌̑; ) LATIN CAPITAL LETTER E WITH INVERTED BREVE +0207;0207;0065 0311;0207;0065 0311; # (ȇ; ȇ; e◌̑; ȇ; e◌̑; ) LATIN SMALL LETTER E WITH INVERTED BREVE +0208;0208;0049 030F;0208;0049 030F; # (Ȉ; Ȉ; I◌̏; Ȉ; I◌̏; ) LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +0209;0209;0069 030F;0209;0069 030F; # (ȉ; ȉ; i◌̏; ȉ; i◌̏; ) LATIN SMALL LETTER I WITH DOUBLE GRAVE +020A;020A;0049 0311;020A;0049 0311; # (Ȋ; Ȋ; I◌̑; Ȋ; I◌̑; ) LATIN CAPITAL LETTER I WITH INVERTED BREVE +020B;020B;0069 0311;020B;0069 0311; # (ȋ; ȋ; i◌̑; ȋ; i◌̑; ) LATIN SMALL LETTER I WITH INVERTED BREVE +020C;020C;004F 030F;020C;004F 030F; # (Ȍ; Ȍ; O◌̏; Ȍ; O◌̏; ) LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020D;020D;006F 030F;020D;006F 030F; # (ȍ; ȍ; o◌̏; ȍ; o◌̏; ) LATIN SMALL LETTER O WITH DOUBLE GRAVE +020E;020E;004F 0311;020E;004F 0311; # (Ȏ; Ȏ; O◌̑; Ȏ; O◌̑; ) LATIN CAPITAL LETTER O WITH INVERTED BREVE +020F;020F;006F 0311;020F;006F 0311; # (ȏ; ȏ; o◌̑; ȏ; o◌̑; ) LATIN SMALL LETTER O WITH INVERTED BREVE +0210;0210;0052 030F;0210;0052 030F; # (Ȑ; Ȑ; R◌̏; Ȑ; R◌̏; ) LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0211;0211;0072 030F;0211;0072 030F; # (ȑ; ȑ; r◌̏; ȑ; r◌̏; ) LATIN SMALL LETTER R WITH DOUBLE GRAVE +0212;0212;0052 0311;0212;0052 0311; # (Ȓ; Ȓ; R◌̑; Ȓ; R◌̑; ) LATIN CAPITAL LETTER R WITH INVERTED BREVE +0213;0213;0072 0311;0213;0072 0311; # (ȓ; ȓ; r◌̑; ȓ; r◌̑; ) LATIN SMALL LETTER R WITH INVERTED BREVE +0214;0214;0055 030F;0214;0055 030F; # (Ȕ; Ȕ; U◌̏; Ȕ; U◌̏; ) LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0215;0215;0075 030F;0215;0075 030F; # (ȕ; ȕ; u◌̏; ȕ; u◌̏; ) LATIN SMALL LETTER U WITH DOUBLE GRAVE +0216;0216;0055 0311;0216;0055 0311; # (Ȗ; Ȗ; U◌̑; Ȗ; U◌̑; ) LATIN CAPITAL LETTER U WITH INVERTED BREVE +0217;0217;0075 0311;0217;0075 0311; # (ȗ; ȗ; u◌̑; ȗ; u◌̑; ) LATIN SMALL LETTER U WITH INVERTED BREVE +0218;0218;0053 0326;0218;0053 0326; # (Ș; Ș; S◌̦; Ș; S◌̦; ) LATIN CAPITAL LETTER S WITH COMMA BELOW +0219;0219;0073 0326;0219;0073 0326; # (ș; ș; s◌̦; ș; s◌̦; ) LATIN SMALL LETTER S WITH COMMA BELOW +021A;021A;0054 0326;021A;0054 0326; # (Ț; Ț; T◌̦; Ț; T◌̦; ) LATIN CAPITAL LETTER T WITH COMMA BELOW +021B;021B;0074 0326;021B;0074 0326; # (ț; ț; t◌̦; ț; t◌̦; ) LATIN SMALL LETTER T WITH COMMA BELOW +021E;021E;0048 030C;021E;0048 030C; # (Ȟ; Ȟ; H◌̌; Ȟ; H◌̌; ) LATIN CAPITAL LETTER H WITH CARON +021F;021F;0068 030C;021F;0068 030C; # (ȟ; ȟ; h◌̌; ȟ; h◌̌; ) LATIN SMALL LETTER H WITH CARON +0226;0226;0041 0307;0226;0041 0307; # (Ȧ; Ȧ; A◌̇; Ȧ; A◌̇; ) LATIN CAPITAL LETTER A WITH DOT ABOVE +0227;0227;0061 0307;0227;0061 0307; # (ȧ; ȧ; a◌̇; ȧ; a◌̇; ) LATIN SMALL LETTER A WITH DOT ABOVE +0228;0228;0045 0327;0228;0045 0327; # (Ȩ; Ȩ; E◌̧; Ȩ; E◌̧; ) LATIN CAPITAL LETTER E WITH CEDILLA +0229;0229;0065 0327;0229;0065 0327; # (ȩ; ȩ; e◌̧; ȩ; e◌̧; ) LATIN SMALL LETTER E WITH CEDILLA +022A;022A;004F 0308 0304;022A;004F 0308 0304; # (Ȫ; Ȫ; O◌̈◌̄; Ȫ; O◌̈◌̄; ) LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022B;022B;006F 0308 0304;022B;006F 0308 0304; # (ȫ; ȫ; o◌̈◌̄; ȫ; o◌̈◌̄; ) LATIN SMALL LETTER O WITH DIAERESIS AND MACRON +022C;022C;004F 0303 0304;022C;004F 0303 0304; # (Ȭ; Ȭ; O◌̃◌̄; Ȭ; O◌̃◌̄; ) LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022D;022D;006F 0303 0304;022D;006F 0303 0304; # (ȭ; ȭ; o◌̃◌̄; ȭ; o◌̃◌̄; ) LATIN SMALL LETTER O WITH TILDE AND MACRON +022E;022E;004F 0307;022E;004F 0307; # (Ȯ; Ȯ; O◌̇; Ȯ; O◌̇; ) LATIN CAPITAL LETTER O WITH DOT ABOVE +022F;022F;006F 0307;022F;006F 0307; # (ȯ; ȯ; o◌̇; ȯ; o◌̇; ) LATIN SMALL LETTER O WITH DOT ABOVE +0230;0230;004F 0307 0304;0230;004F 0307 0304; # (Ȱ; Ȱ; O◌̇◌̄; Ȱ; O◌̇◌̄; ) LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0231;0231;006F 0307 0304;0231;006F 0307 0304; # (ȱ; ȱ; o◌̇◌̄; ȱ; o◌̇◌̄; ) LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON +0232;0232;0059 0304;0232;0059 0304; # (Ȳ; Ȳ; Y◌̄; Ȳ; Y◌̄; ) LATIN CAPITAL LETTER Y WITH MACRON +0233;0233;0079 0304;0233;0079 0304; # (ȳ; ȳ; y◌̄; ȳ; y◌̄; ) LATIN SMALL LETTER Y WITH MACRON +02B0;02B0;02B0;0068;0068; # (ʰ; ʰ; ʰ; h; h; ) MODIFIER LETTER SMALL H +02B1;02B1;02B1;0266;0266; # (ʱ; ʱ; ʱ; ɦ; ɦ; ) MODIFIER LETTER SMALL H WITH HOOK +02B2;02B2;02B2;006A;006A; # (ʲ; ʲ; ʲ; j; j; ) MODIFIER LETTER SMALL J +02B3;02B3;02B3;0072;0072; # (ʳ; ʳ; ʳ; r; r; ) MODIFIER LETTER SMALL R +02B4;02B4;02B4;0279;0279; # (ʴ; ʴ; ʴ; ɹ; ɹ; ) MODIFIER LETTER SMALL TURNED R +02B5;02B5;02B5;027B;027B; # (ʵ; ʵ; ʵ; ɻ; ɻ; ) MODIFIER LETTER SMALL TURNED R WITH HOOK +02B6;02B6;02B6;0281;0281; # (ʶ; ʶ; ʶ; ʁ; ʁ; ) MODIFIER LETTER SMALL CAPITAL INVERTED R +02B7;02B7;02B7;0077;0077; # (ʷ; ʷ; ʷ; w; w; ) MODIFIER LETTER SMALL W +02B8;02B8;02B8;0079;0079; # (ʸ; ʸ; ʸ; y; y; ) MODIFIER LETTER SMALL Y +02D8;02D8;02D8;0020 0306;0020 0306; # (˘; ˘; ˘; ◌̆; ◌̆; ) BREVE +02D9;02D9;02D9;0020 0307;0020 0307; # (˙; ˙; ˙; ◌̇; ◌̇; ) DOT ABOVE +02DA;02DA;02DA;0020 030A;0020 030A; # (˚; ˚; ˚; ◌̊; ◌̊; ) RING ABOVE +02DB;02DB;02DB;0020 0328;0020 0328; # (˛; ˛; ˛; ◌̨; ◌̨; ) OGONEK +02DC;02DC;02DC;0020 0303;0020 0303; # (˜; ˜; ˜; ◌̃; ◌̃; ) SMALL TILDE +02DD;02DD;02DD;0020 030B;0020 030B; # (˝; ˝; ˝; ◌̋; ◌̋; ) DOUBLE ACUTE ACCENT +02E0;02E0;02E0;0263;0263; # (ˠ; ˠ; ˠ; ɣ; ɣ; ) MODIFIER LETTER SMALL GAMMA +02E1;02E1;02E1;006C;006C; # (ˡ; ˡ; ˡ; l; l; ) MODIFIER LETTER SMALL L +02E2;02E2;02E2;0073;0073; # (ˢ; ˢ; ˢ; s; s; ) MODIFIER LETTER SMALL S +02E3;02E3;02E3;0078;0078; # (ˣ; ˣ; ˣ; x; x; ) MODIFIER LETTER SMALL X +02E4;02E4;02E4;0295;0295; # (ˤ; ˤ; ˤ; ʕ; ʕ; ) MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +0340;0300;0300;0300;0300; # (◌̀; ◌̀; ◌̀; ◌̀; ◌̀; ) COMBINING GRAVE TONE MARK +0341;0301;0301;0301;0301; # (◌́; ◌́; ◌́; ◌́; ◌́; ) COMBINING ACUTE TONE MARK +0343;0313;0313;0313;0313; # (◌̓; ◌̓; ◌̓; ◌̓; ◌̓; ) COMBINING GREEK KORONIS +0344;0308 0301;0308 0301;0308 0301;0308 0301; # (◌̈́; ◌̈◌́; ◌̈◌́; ◌̈◌́; ◌̈◌́; ) COMBINING GREEK DIALYTIKA TONOS +0374;02B9;02B9;02B9;02B9; # (ʹ; ʹ; ʹ; ʹ; ʹ; ) GREEK NUMERAL SIGN +037A;037A;037A;0020 0345;0020 0345; # (ͺ; ͺ; ͺ; ◌ͅ; ◌ͅ; ) GREEK YPOGEGRAMMENI +037E;003B;003B;003B;003B; # (;; ;; ;; ;; ;; ) GREEK QUESTION MARK +0384;0384;0384;0020 0301;0020 0301; # (΄; ΄; ΄; ◌́; ◌́; ) GREEK TONOS +0385;0385;00A8 0301;0020 0308 0301;0020 0308 0301; # (΅; ΅; ¨◌́; ◌̈◌́; ◌̈◌́; ) GREEK DIALYTIKA TONOS +0386;0386;0391 0301;0386;0391 0301; # (Ά; Ά; Α◌́; Ά; Α◌́; ) GREEK CAPITAL LETTER ALPHA WITH TONOS +0387;00B7;00B7;00B7;00B7; # (·; ·; ·; ·; ·; ) GREEK ANO TELEIA +0388;0388;0395 0301;0388;0395 0301; # (Έ; Έ; Ε◌́; Έ; Ε◌́; ) GREEK CAPITAL LETTER EPSILON WITH TONOS +0389;0389;0397 0301;0389;0397 0301; # (Ή; Ή; Η◌́; Ή; Η◌́; ) GREEK CAPITAL LETTER ETA WITH TONOS +038A;038A;0399 0301;038A;0399 0301; # (Ί; Ί; Ι◌́; Ί; Ι◌́; ) GREEK CAPITAL LETTER IOTA WITH TONOS +038C;038C;039F 0301;038C;039F 0301; # (Ό; Ό; Ο◌́; Ό; Ο◌́; ) GREEK CAPITAL LETTER OMICRON WITH TONOS +038E;038E;03A5 0301;038E;03A5 0301; # (Ύ; Ύ; Υ◌́; Ύ; Υ◌́; ) GREEK CAPITAL LETTER UPSILON WITH TONOS +038F;038F;03A9 0301;038F;03A9 0301; # (Ώ; Ώ; Ω◌́; Ώ; Ω◌́; ) GREEK CAPITAL LETTER OMEGA WITH TONOS +0390;0390;03B9 0308 0301;0390;03B9 0308 0301; # (ΐ; ΐ; ι◌̈◌́; ΐ; ι◌̈◌́; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AA;03AA;0399 0308;03AA;0399 0308; # (Ϊ; Ϊ; Ι◌̈; Ϊ; Ι◌̈; ) GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB;03AB;03A5 0308;03AB;03A5 0308; # (Ϋ; Ϋ; Υ◌̈; Ϋ; Υ◌̈; ) GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03AC;03AC;03B1 0301;03AC;03B1 0301; # (ά; ά; α◌́; ά; α◌́; ) GREEK SMALL LETTER ALPHA WITH TONOS +03AD;03AD;03B5 0301;03AD;03B5 0301; # (έ; έ; ε◌́; έ; ε◌́; ) GREEK SMALL LETTER EPSILON WITH TONOS +03AE;03AE;03B7 0301;03AE;03B7 0301; # (ή; ή; η◌́; ή; η◌́; ) GREEK SMALL LETTER ETA WITH TONOS +03AF;03AF;03B9 0301;03AF;03B9 0301; # (ί; ί; ι◌́; ί; ι◌́; ) GREEK SMALL LETTER IOTA WITH TONOS +03B0;03B0;03C5 0308 0301;03B0;03C5 0308 0301; # (ΰ; ΰ; υ◌̈◌́; ΰ; υ◌̈◌́; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03CA;03CA;03B9 0308;03CA;03B9 0308; # (ϊ; ϊ; ι◌̈; ϊ; ι◌̈; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA +03CB;03CB;03C5 0308;03CB;03C5 0308; # (ϋ; ϋ; υ◌̈; ϋ; υ◌̈; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA +03CC;03CC;03BF 0301;03CC;03BF 0301; # (ό; ό; ο◌́; ό; ο◌́; ) GREEK SMALL LETTER OMICRON WITH TONOS +03CD;03CD;03C5 0301;03CD;03C5 0301; # (ύ; ύ; υ◌́; ύ; υ◌́; ) GREEK SMALL LETTER UPSILON WITH TONOS +03CE;03CE;03C9 0301;03CE;03C9 0301; # (ώ; ώ; ω◌́; ώ; ω◌́; ) GREEK SMALL LETTER OMEGA WITH TONOS +03D0;03D0;03D0;03B2;03B2; # (ϐ; ϐ; ϐ; β; β; ) GREEK BETA SYMBOL +03D1;03D1;03D1;03B8;03B8; # (ϑ; ϑ; ϑ; θ; θ; ) GREEK THETA SYMBOL +03D2;03D2;03D2;03A5;03A5; # (ϒ; ϒ; ϒ; Υ; Υ; ) GREEK UPSILON WITH HOOK SYMBOL +03D3;03D3;03D2 0301;038E;03A5 0301; # (ϓ; ϓ; ϒ◌́; Ύ; Υ◌́; ) GREEK UPSILON WITH ACUTE AND HOOK SYMBOL +03D4;03D4;03D2 0308;03AB;03A5 0308; # (ϔ; ϔ; ϒ◌̈; Ϋ; Υ◌̈; ) GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL +03D5;03D5;03D5;03C6;03C6; # (ϕ; ϕ; ϕ; φ; φ; ) GREEK PHI SYMBOL +03D6;03D6;03D6;03C0;03C0; # (ϖ; ϖ; ϖ; π; π; ) GREEK PI SYMBOL +03F0;03F0;03F0;03BA;03BA; # (ϰ; ϰ; ϰ; κ; κ; ) GREEK KAPPA SYMBOL +03F1;03F1;03F1;03C1;03C1; # (ϱ; ϱ; ϱ; ρ; ρ; ) GREEK RHO SYMBOL +03F2;03F2;03F2;03C2;03C2; # (ϲ; ϲ; ϲ; ς; ς; ) GREEK LUNATE SIGMA SYMBOL +03F4;03F4;03F4;0398;0398; # (ϴ; ϴ; ϴ; Θ; Θ; ) GREEK CAPITAL THETA SYMBOL +03F5;03F5;03F5;03B5;03B5; # (ϵ; ϵ; ϵ; ε; ε; ) GREEK LUNATE EPSILON SYMBOL +03F9;03F9;03F9;03A3;03A3; # (Ϲ; Ϲ; Ϲ; Σ; Σ; ) GREEK CAPITAL LUNATE SIGMA SYMBOL +0400;0400;0415 0300;0400;0415 0300; # (Ѐ; Ѐ; Е◌̀; Ѐ; Е◌̀; ) CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401;0401;0415 0308;0401;0415 0308; # (Ё; Ё; Е◌̈; Ё; Е◌̈; ) CYRILLIC CAPITAL LETTER IO +0403;0403;0413 0301;0403;0413 0301; # (Ѓ; Ѓ; Г◌́; Ѓ; Г◌́; ) CYRILLIC CAPITAL LETTER GJE +0407;0407;0406 0308;0407;0406 0308; # (Ї; Ї; І◌̈; Ї; І◌̈; ) CYRILLIC CAPITAL LETTER YI +040C;040C;041A 0301;040C;041A 0301; # (Ќ; Ќ; К◌́; Ќ; К◌́; ) CYRILLIC CAPITAL LETTER KJE +040D;040D;0418 0300;040D;0418 0300; # (Ѝ; Ѝ; И◌̀; Ѝ; И◌̀; ) CYRILLIC CAPITAL LETTER I WITH GRAVE +040E;040E;0423 0306;040E;0423 0306; # (Ў; Ў; У◌̆; Ў; У◌̆; ) CYRILLIC CAPITAL LETTER SHORT U +0419;0419;0418 0306;0419;0418 0306; # (Й; Й; И◌̆; Й; И◌̆; ) CYRILLIC CAPITAL LETTER SHORT I +0439;0439;0438 0306;0439;0438 0306; # (й; й; и◌̆; й; и◌̆; ) CYRILLIC SMALL LETTER SHORT I +0450;0450;0435 0300;0450;0435 0300; # (ѐ; ѐ; е◌̀; ѐ; е◌̀; ) CYRILLIC SMALL LETTER IE WITH GRAVE +0451;0451;0435 0308;0451;0435 0308; # (ё; ё; е◌̈; ё; е◌̈; ) CYRILLIC SMALL LETTER IO +0453;0453;0433 0301;0453;0433 0301; # (ѓ; ѓ; г◌́; ѓ; г◌́; ) CYRILLIC SMALL LETTER GJE +0457;0457;0456 0308;0457;0456 0308; # (ї; ї; і◌̈; ї; і◌̈; ) CYRILLIC SMALL LETTER YI +045C;045C;043A 0301;045C;043A 0301; # (ќ; ќ; к◌́; ќ; к◌́; ) CYRILLIC SMALL LETTER KJE +045D;045D;0438 0300;045D;0438 0300; # (ѝ; ѝ; и◌̀; ѝ; и◌̀; ) CYRILLIC SMALL LETTER I WITH GRAVE +045E;045E;0443 0306;045E;0443 0306; # (ў; ў; у◌̆; ў; у◌̆; ) CYRILLIC SMALL LETTER SHORT U +0476;0476;0474 030F;0476;0474 030F; # (Ѷ; Ѷ; Ѵ◌̏; Ѷ; Ѵ◌̏; ) CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0477;0477;0475 030F;0477;0475 030F; # (ѷ; ѷ; ѵ◌̏; ѷ; ѵ◌̏; ) CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +04C1;04C1;0416 0306;04C1;0416 0306; # (Ӂ; Ӂ; Ж◌̆; Ӂ; Ж◌̆; ) CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C2;04C2;0436 0306;04C2;0436 0306; # (ӂ; ӂ; ж◌̆; ӂ; ж◌̆; ) CYRILLIC SMALL LETTER ZHE WITH BREVE +04D0;04D0;0410 0306;04D0;0410 0306; # (Ӑ; Ӑ; А◌̆; Ӑ; А◌̆; ) CYRILLIC CAPITAL LETTER A WITH BREVE +04D1;04D1;0430 0306;04D1;0430 0306; # (ӑ; ӑ; а◌̆; ӑ; а◌̆; ) CYRILLIC SMALL LETTER A WITH BREVE +04D2;04D2;0410 0308;04D2;0410 0308; # (Ӓ; Ӓ; А◌̈; Ӓ; А◌̈; ) CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D3;04D3;0430 0308;04D3;0430 0308; # (ӓ; ӓ; а◌̈; ӓ; а◌̈; ) CYRILLIC SMALL LETTER A WITH DIAERESIS +04D6;04D6;0415 0306;04D6;0415 0306; # (Ӗ; Ӗ; Е◌̆; Ӗ; Е◌̆; ) CYRILLIC CAPITAL LETTER IE WITH BREVE +04D7;04D7;0435 0306;04D7;0435 0306; # (ӗ; ӗ; е◌̆; ӗ; е◌̆; ) CYRILLIC SMALL LETTER IE WITH BREVE +04DA;04DA;04D8 0308;04DA;04D8 0308; # (Ӛ; Ӛ; Ә◌̈; Ӛ; Ә◌̈; ) CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DB;04DB;04D9 0308;04DB;04D9 0308; # (ӛ; ӛ; ә◌̈; ӛ; ә◌̈; ) CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DC;04DC;0416 0308;04DC;0416 0308; # (Ӝ; Ӝ; Ж◌̈; Ӝ; Ж◌̈; ) CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DD;04DD;0436 0308;04DD;0436 0308; # (ӝ; ӝ; ж◌̈; ӝ; ж◌̈; ) CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DE;04DE;0417 0308;04DE;0417 0308; # (Ӟ; Ӟ; З◌̈; Ӟ; З◌̈; ) CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04DF;04DF;0437 0308;04DF;0437 0308; # (ӟ; ӟ; з◌̈; ӟ; з◌̈; ) CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04E2;04E2;0418 0304;04E2;0418 0304; # (Ӣ; Ӣ; И◌̄; Ӣ; И◌̄; ) CYRILLIC CAPITAL LETTER I WITH MACRON +04E3;04E3;0438 0304;04E3;0438 0304; # (ӣ; ӣ; и◌̄; ӣ; и◌̄; ) CYRILLIC SMALL LETTER I WITH MACRON +04E4;04E4;0418 0308;04E4;0418 0308; # (Ӥ; Ӥ; И◌̈; Ӥ; И◌̈; ) CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E5;04E5;0438 0308;04E5;0438 0308; # (ӥ; ӥ; и◌̈; ӥ; и◌̈; ) CYRILLIC SMALL LETTER I WITH DIAERESIS +04E6;04E6;041E 0308;04E6;041E 0308; # (Ӧ; Ӧ; О◌̈; Ӧ; О◌̈; ) CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E7;04E7;043E 0308;04E7;043E 0308; # (ӧ; ӧ; о◌̈; ӧ; о◌̈; ) CYRILLIC SMALL LETTER O WITH DIAERESIS +04EA;04EA;04E8 0308;04EA;04E8 0308; # (Ӫ; Ӫ; Ө◌̈; Ӫ; Ө◌̈; ) CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EB;04EB;04E9 0308;04EB;04E9 0308; # (ӫ; ӫ; ө◌̈; ӫ; ө◌̈; ) CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04EC;04EC;042D 0308;04EC;042D 0308; # (Ӭ; Ӭ; Э◌̈; Ӭ; Э◌̈; ) CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04ED;04ED;044D 0308;04ED;044D 0308; # (ӭ; ӭ; э◌̈; ӭ; э◌̈; ) CYRILLIC SMALL LETTER E WITH DIAERESIS +04EE;04EE;0423 0304;04EE;0423 0304; # (Ӯ; Ӯ; У◌̄; Ӯ; У◌̄; ) CYRILLIC CAPITAL LETTER U WITH MACRON +04EF;04EF;0443 0304;04EF;0443 0304; # (ӯ; ӯ; у◌̄; ӯ; у◌̄; ) CYRILLIC SMALL LETTER U WITH MACRON +04F0;04F0;0423 0308;04F0;0423 0308; # (Ӱ; Ӱ; У◌̈; Ӱ; У◌̈; ) CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F1;04F1;0443 0308;04F1;0443 0308; # (ӱ; ӱ; у◌̈; ӱ; у◌̈; ) CYRILLIC SMALL LETTER U WITH DIAERESIS +04F2;04F2;0423 030B;04F2;0423 030B; # (Ӳ; Ӳ; У◌̋; Ӳ; У◌̋; ) CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F3;04F3;0443 030B;04F3;0443 030B; # (ӳ; ӳ; у◌̋; ӳ; у◌̋; ) CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F4;04F4;0427 0308;04F4;0427 0308; # (Ӵ; Ӵ; Ч◌̈; Ӵ; Ч◌̈; ) CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F5;04F5;0447 0308;04F5;0447 0308; # (ӵ; ӵ; ч◌̈; ӵ; ч◌̈; ) CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F8;04F8;042B 0308;04F8;042B 0308; # (Ӹ; Ӹ; Ы◌̈; Ӹ; Ы◌̈; ) CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04F9;04F9;044B 0308;04F9;044B 0308; # (ӹ; ӹ; ы◌̈; ӹ; ы◌̈; ) CYRILLIC SMALL LETTER YERU WITH DIAERESIS +0587;0587;0587;0565 0582;0565 0582; # (և; և; և; եւ; եւ; ) ARMENIAN SMALL LIGATURE ECH YIWN +0622;0622;0627 0653;0622;0627 0653; # (آ; آ; ا◌ٓ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE +0623;0623;0627 0654;0623;0627 0654; # (أ; أ; ا◌ٔ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE +0624;0624;0648 0654;0624;0648 0654; # (ؤ; ؤ; و◌ٔ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE +0625;0625;0627 0655;0625;0627 0655; # (إ; إ; ا◌ٕ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW +0626;0626;064A 0654;0626;064A 0654; # (ئ; ئ; ي◌ٔ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE +0675;0675;0675;0627 0674;0627 0674; # (ٵ; ٵ; ٵ; اٴ; اٴ; ) ARABIC LETTER HIGH HAMZA ALEF +0676;0676;0676;0648 0674;0648 0674; # (ٶ; ٶ; ٶ; وٴ; وٴ; ) ARABIC LETTER HIGH HAMZA WAW +0677;0677;0677;06C7 0674;06C7 0674; # (ٷ; ٷ; ٷ; ۇٴ; ۇٴ; ) ARABIC LETTER U WITH HAMZA ABOVE +0678;0678;0678;064A 0674;064A 0674; # (ٸ; ٸ; ٸ; يٴ; يٴ; ) ARABIC LETTER HIGH HAMZA YEH +06C0;06C0;06D5 0654;06C0;06D5 0654; # (ۀ; ۀ; ە◌ٔ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE +06C2;06C2;06C1 0654;06C2;06C1 0654; # (ۂ; ۂ; ہ◌ٔ; ۂ; ہ◌ٔ; ) ARABIC LETTER HEH GOAL WITH HAMZA ABOVE +06D3;06D3;06D2 0654;06D3;06D2 0654; # (ۓ; ۓ; ے◌ٔ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +0929;0929;0928 093C;0929;0928 093C; # (ऩ; ऩ; न◌़; ऩ; न◌़; ) DEVANAGARI LETTER NNNA +0931;0931;0930 093C;0931;0930 093C; # (ऱ; ऱ; र◌़; ऱ; र◌़; ) DEVANAGARI LETTER RRA +0934;0934;0933 093C;0934;0933 093C; # (ऴ; ऴ; ळ◌़; ऴ; ळ◌़; ) DEVANAGARI LETTER LLLA +0958;0915 093C;0915 093C;0915 093C;0915 093C; # (क़; क◌़; क◌़; क◌़; क◌़; ) DEVANAGARI LETTER QA +0959;0916 093C;0916 093C;0916 093C;0916 093C; # (ख़; ख◌़; ख◌़; ख◌़; ख◌़; ) DEVANAGARI LETTER KHHA +095A;0917 093C;0917 093C;0917 093C;0917 093C; # (ग़; ग◌़; ग◌़; ग◌़; ग◌़; ) DEVANAGARI LETTER GHHA +095B;091C 093C;091C 093C;091C 093C;091C 093C; # (ज़; ज◌़; ज◌़; ज◌़; ज◌़; ) DEVANAGARI LETTER ZA +095C;0921 093C;0921 093C;0921 093C;0921 093C; # (ड़; ड◌़; ड◌़; ड◌़; ड◌़; ) DEVANAGARI LETTER DDDHA +095D;0922 093C;0922 093C;0922 093C;0922 093C; # (ढ़; ढ◌़; ढ◌़; ढ◌़; ढ◌़; ) DEVANAGARI LETTER RHA +095E;092B 093C;092B 093C;092B 093C;092B 093C; # (फ़; फ◌़; फ◌़; फ◌़; फ◌़; ) DEVANAGARI LETTER FA +095F;092F 093C;092F 093C;092F 093C;092F 093C; # (य़; य◌़; य◌़; य◌़; य◌़; ) DEVANAGARI LETTER YYA +09CB;09CB;09C7 09BE;09CB;09C7 09BE; # (ো; ো; ো; ো; ো; ) BENGALI VOWEL SIGN O +09CC;09CC;09C7 09D7;09CC;09C7 09D7; # (ৌ; ৌ; ৌ; ৌ; ৌ; ) BENGALI VOWEL SIGN AU +09DC;09A1 09BC;09A1 09BC;09A1 09BC;09A1 09BC; # (ড়; ড◌়; ড◌়; ড◌়; ড◌়; ) BENGALI LETTER RRA +09DD;09A2 09BC;09A2 09BC;09A2 09BC;09A2 09BC; # (ঢ়; ঢ◌়; ঢ◌়; ঢ◌়; ঢ◌়; ) BENGALI LETTER RHA +09DF;09AF 09BC;09AF 09BC;09AF 09BC;09AF 09BC; # (য়; য◌়; য◌়; য◌়; য◌়; ) BENGALI LETTER YYA +0A33;0A32 0A3C;0A32 0A3C;0A32 0A3C;0A32 0A3C; # (ਲ਼; ਲ◌਼; ਲ◌਼; ਲ◌਼; ਲ◌਼; ) GURMUKHI LETTER LLA +0A36;0A38 0A3C;0A38 0A3C;0A38 0A3C;0A38 0A3C; # (ਸ਼; ਸ◌਼; ਸ◌਼; ਸ◌਼; ਸ◌਼; ) GURMUKHI LETTER SHA +0A59;0A16 0A3C;0A16 0A3C;0A16 0A3C;0A16 0A3C; # (ਖ਼; ਖ◌਼; ਖ◌਼; ਖ◌਼; ਖ◌਼; ) GURMUKHI LETTER KHHA +0A5A;0A17 0A3C;0A17 0A3C;0A17 0A3C;0A17 0A3C; # (ਗ਼; ਗ◌਼; ਗ◌਼; ਗ◌਼; ਗ◌਼; ) GURMUKHI LETTER GHHA +0A5B;0A1C 0A3C;0A1C 0A3C;0A1C 0A3C;0A1C 0A3C; # (ਜ਼; ਜ◌਼; ਜ◌਼; ਜ◌਼; ਜ◌਼; ) GURMUKHI LETTER ZA +0A5E;0A2B 0A3C;0A2B 0A3C;0A2B 0A3C;0A2B 0A3C; # (ਫ਼; ਫ◌਼; ਫ◌਼; ਫ◌਼; ਫ◌਼; ) GURMUKHI LETTER FA +0B48;0B48;0B47 0B56;0B48;0B47 0B56; # (ୈ; ୈ; େ◌ୖ; ୈ; େ◌ୖ; ) ORIYA VOWEL SIGN AI +0B4B;0B4B;0B47 0B3E;0B4B;0B47 0B3E; # (ୋ; ୋ; ୋ; ୋ; ୋ; ) ORIYA VOWEL SIGN O +0B4C;0B4C;0B47 0B57;0B4C;0B47 0B57; # (ୌ; ୌ; ୌ; ୌ; ୌ; ) ORIYA VOWEL SIGN AU +0B5C;0B21 0B3C;0B21 0B3C;0B21 0B3C;0B21 0B3C; # (ଡ଼; ଡ◌଼; ଡ◌଼; ଡ◌଼; ଡ◌଼; ) ORIYA LETTER RRA +0B5D;0B22 0B3C;0B22 0B3C;0B22 0B3C;0B22 0B3C; # (ଢ଼; ଢ◌଼; ଢ◌଼; ଢ◌଼; ଢ◌଼; ) ORIYA LETTER RHA +0B94;0B94;0B92 0BD7;0B94;0B92 0BD7; # (ஔ; ஔ; ஔ; ஔ; ஔ; ) TAMIL LETTER AU +0BCA;0BCA;0BC6 0BBE;0BCA;0BC6 0BBE; # (ொ; ொ; ொ; ொ; ொ; ) TAMIL VOWEL SIGN O +0BCB;0BCB;0BC7 0BBE;0BCB;0BC7 0BBE; # (ோ; ோ; ோ; ோ; ோ; ) TAMIL VOWEL SIGN OO +0BCC;0BCC;0BC6 0BD7;0BCC;0BC6 0BD7; # (ௌ; ௌ; ௌ; ௌ; ௌ; ) TAMIL VOWEL SIGN AU +0C48;0C48;0C46 0C56;0C48;0C46 0C56; # (◌ై; ◌ై; ◌ె◌ౖ; ◌ై; ◌ె◌ౖ; ) TELUGU VOWEL SIGN AI +0CC0;0CC0;0CBF 0CD5;0CC0;0CBF 0CD5; # (ೀ; ೀ; ◌ೀ; ೀ; ◌ೀ; ) KANNADA VOWEL SIGN II +0CC7;0CC7;0CC6 0CD5;0CC7;0CC6 0CD5; # (ೇ; ೇ; ◌ೇ; ೇ; ◌ೇ; ) KANNADA VOWEL SIGN EE +0CC8;0CC8;0CC6 0CD6;0CC8;0CC6 0CD6; # (ೈ; ೈ; ◌ೈ; ೈ; ◌ೈ; ) KANNADA VOWEL SIGN AI +0CCA;0CCA;0CC6 0CC2;0CCA;0CC6 0CC2; # (ೊ; ೊ; ◌ೊ; ೊ; ◌ೊ; ) KANNADA VOWEL SIGN O +0CCB;0CCB;0CC6 0CC2 0CD5;0CCB;0CC6 0CC2 0CD5; # (ೋ; ೋ; ◌ೋ; ೋ; ◌ೋ; ) KANNADA VOWEL SIGN OO +0D4A;0D4A;0D46 0D3E;0D4A;0D46 0D3E; # (ൊ; ൊ; ൊ; ൊ; ൊ; ) MALAYALAM VOWEL SIGN O +0D4B;0D4B;0D47 0D3E;0D4B;0D47 0D3E; # (ോ; ോ; ോ; ോ; ോ; ) MALAYALAM VOWEL SIGN OO +0D4C;0D4C;0D46 0D57;0D4C;0D46 0D57; # (ൌ; ൌ; ൌ; ൌ; ൌ; ) MALAYALAM VOWEL SIGN AU +0DDA;0DDA;0DD9 0DCA;0DDA;0DD9 0DCA; # (ේ; ේ; ෙ◌්; ේ; ෙ◌්; ) SINHALA VOWEL SIGN DIGA KOMBUVA +0DDC;0DDC;0DD9 0DCF;0DDC;0DD9 0DCF; # (ො; ො; ො; ො; ො; ) SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DDD;0DDD;0DD9 0DCF 0DCA;0DDD;0DD9 0DCF 0DCA; # (ෝ; ෝ; ො◌්; ෝ; ො◌්; ) SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDE;0DDE;0DD9 0DDF;0DDE;0DD9 0DDF; # (ෞ; ෞ; ෞ; ෞ; ෞ; ) SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0E33;0E33;0E33;0E4D 0E32;0E4D 0E32; # (ำ; ำ; ำ; ◌ํา; ◌ํา; ) THAI CHARACTER SARA AM +0EB3;0EB3;0EB3;0ECD 0EB2;0ECD 0EB2; # (ຳ; ຳ; ຳ; ◌ໍາ; ◌ໍາ; ) LAO VOWEL SIGN AM +0EDC;0EDC;0EDC;0EAB 0E99;0EAB 0E99; # (ໜ; ໜ; ໜ; ຫນ; ຫນ; ) LAO HO NO +0EDD;0EDD;0EDD;0EAB 0EA1;0EAB 0EA1; # (ໝ; ໝ; ໝ; ຫມ; ຫມ; ) LAO HO MO +0F0C;0F0C;0F0C;0F0B;0F0B; # (༌; ༌; ༌; ་; ་; ) TIBETAN MARK DELIMITER TSHEG BSTAR +0F43;0F42 0FB7;0F42 0FB7;0F42 0FB7;0F42 0FB7; # (གྷ; ག◌ྷ; ག◌ྷ; ག◌ྷ; ག◌ྷ; ) TIBETAN LETTER GHA +0F4D;0F4C 0FB7;0F4C 0FB7;0F4C 0FB7;0F4C 0FB7; # (ཌྷ; ཌ◌ྷ; ཌ◌ྷ; ཌ◌ྷ; ཌ◌ྷ; ) TIBETAN LETTER DDHA +0F52;0F51 0FB7;0F51 0FB7;0F51 0FB7;0F51 0FB7; # (དྷ; ད◌ྷ; ད◌ྷ; ད◌ྷ; ད◌ྷ; ) TIBETAN LETTER DHA +0F57;0F56 0FB7;0F56 0FB7;0F56 0FB7;0F56 0FB7; # (བྷ; བ◌ྷ; བ◌ྷ; བ◌ྷ; བ◌ྷ; ) TIBETAN LETTER BHA +0F5C;0F5B 0FB7;0F5B 0FB7;0F5B 0FB7;0F5B 0FB7; # (ཛྷ; ཛ◌ྷ; ཛ◌ྷ; ཛ◌ྷ; ཛ◌ྷ; ) TIBETAN LETTER DZHA +0F69;0F40 0FB5;0F40 0FB5;0F40 0FB5;0F40 0FB5; # (ཀྵ; ཀ◌ྵ; ཀ◌ྵ; ཀ◌ྵ; ཀ◌ྵ; ) TIBETAN LETTER KSSA +0F73;0F71 0F72;0F71 0F72;0F71 0F72;0F71 0F72; # (◌ཱི; ◌ཱ◌ི; ◌ཱ◌ི; ◌ཱ◌ི; ◌ཱ◌ི; ) TIBETAN VOWEL SIGN II +0F75;0F71 0F74;0F71 0F74;0F71 0F74;0F71 0F74; # (◌ཱུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ◌ཱ◌ུ; ) TIBETAN VOWEL SIGN UU +0F76;0FB2 0F80;0FB2 0F80;0FB2 0F80;0FB2 0F80; # (◌ྲྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ◌ྲ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC R +0F77;0F77;0F77;0FB2 0F71 0F80;0FB2 0F71 0F80; # (◌ཷ; ◌ཷ; ◌ཷ; ◌ྲ◌ཱ◌ྀ; ◌ྲ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC RR +0F78;0FB3 0F80;0FB3 0F80;0FB3 0F80;0FB3 0F80; # (◌ླྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ◌ླ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC L +0F79;0F79;0F79;0FB3 0F71 0F80;0FB3 0F71 0F80; # (◌ཹ; ◌ཹ; ◌ཹ; ◌ླ◌ཱ◌ྀ; ◌ླ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN VOCALIC LL +0F81;0F71 0F80;0F71 0F80;0F71 0F80;0F71 0F80; # (◌ཱྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ◌ཱ◌ྀ; ) TIBETAN VOWEL SIGN REVERSED II +0F93;0F92 0FB7;0F92 0FB7;0F92 0FB7;0F92 0FB7; # (◌ྒྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ◌ྒ◌ྷ; ) TIBETAN SUBJOINED LETTER GHA +0F9D;0F9C 0FB7;0F9C 0FB7;0F9C 0FB7;0F9C 0FB7; # (◌ྜྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ◌ྜ◌ྷ; ) TIBETAN SUBJOINED LETTER DDHA +0FA2;0FA1 0FB7;0FA1 0FB7;0FA1 0FB7;0FA1 0FB7; # (◌ྡྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ◌ྡ◌ྷ; ) TIBETAN SUBJOINED LETTER DHA +0FA7;0FA6 0FB7;0FA6 0FB7;0FA6 0FB7;0FA6 0FB7; # (◌ྦྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ◌ྦ◌ྷ; ) TIBETAN SUBJOINED LETTER BHA +0FAC;0FAB 0FB7;0FAB 0FB7;0FAB 0FB7;0FAB 0FB7; # (◌ྫྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ◌ྫ◌ྷ; ) TIBETAN SUBJOINED LETTER DZHA +0FB9;0F90 0FB5;0F90 0FB5;0F90 0FB5;0F90 0FB5; # (◌ྐྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ◌ྐ◌ྵ; ) TIBETAN SUBJOINED LETTER KSSA +1026;1026;1025 102E;1026;1025 102E; # (ဦ; ဦ; ဥ◌ီ; ဦ; ဥ◌ီ; ) MYANMAR LETTER UU +10FC;10FC;10FC;10DC;10DC; # (ჼ; ჼ; ჼ; ნ; ნ; ) MODIFIER LETTER GEORGIAN NAR +1B06;1B06;1B05 1B35;1B06;1B05 1B35; # (ᬆ; ᬆ; ᬆ; ᬆ; ᬆ; ) BALINESE LETTER AKARA TEDUNG +1B08;1B08;1B07 1B35;1B08;1B07 1B35; # (ᬈ; ᬈ; ᬈ; ᬈ; ᬈ; ) BALINESE LETTER IKARA TEDUNG +1B0A;1B0A;1B09 1B35;1B0A;1B09 1B35; # (ᬊ; ᬊ; ᬊ; ᬊ; ᬊ; ) BALINESE LETTER UKARA TEDUNG +1B0C;1B0C;1B0B 1B35;1B0C;1B0B 1B35; # (ᬌ; ᬌ; ᬌ; ᬌ; ᬌ; ) BALINESE LETTER RA REPA TEDUNG +1B0E;1B0E;1B0D 1B35;1B0E;1B0D 1B35; # (ᬎ; ᬎ; ᬎ; ᬎ; ᬎ; ) BALINESE LETTER LA LENGA TEDUNG +1B12;1B12;1B11 1B35;1B12;1B11 1B35; # (ᬒ; ᬒ; ᬒ; ᬒ; ᬒ; ) BALINESE LETTER OKARA TEDUNG +1B3B;1B3B;1B3A 1B35;1B3B;1B3A 1B35; # (ᬻ; ᬻ; ◌ᬻ; ᬻ; ◌ᬻ; ) BALINESE VOWEL SIGN RA REPA TEDUNG +1B3D;1B3D;1B3C 1B35;1B3D;1B3C 1B35; # (ᬽ; ᬽ; ◌ᬽ; ᬽ; ◌ᬽ; ) BALINESE VOWEL SIGN LA LENGA TEDUNG +1B40;1B40;1B3E 1B35;1B40;1B3E 1B35; # (ᭀ; ᭀ; ᭀ; ᭀ; ᭀ; ) BALINESE VOWEL SIGN TALING TEDUNG +1B41;1B41;1B3F 1B35;1B41;1B3F 1B35; # (ᭁ; ᭁ; ᭁ; ᭁ; ᭁ; ) BALINESE VOWEL SIGN TALING REPA TEDUNG +1B43;1B43;1B42 1B35;1B43;1B42 1B35; # (ᭃ; ᭃ; ◌ᭃ; ᭃ; ◌ᭃ; ) BALINESE VOWEL SIGN PEPET TEDUNG +1D2C;1D2C;1D2C;0041;0041; # (ᴬ; ᴬ; ᴬ; A; A; ) MODIFIER LETTER CAPITAL A +1D2D;1D2D;1D2D;00C6;00C6; # (ᴭ; ᴭ; ᴭ; Æ; Æ; ) MODIFIER LETTER CAPITAL AE +1D2E;1D2E;1D2E;0042;0042; # (ᴮ; ᴮ; ᴮ; B; B; ) MODIFIER LETTER CAPITAL B +1D30;1D30;1D30;0044;0044; # (ᴰ; ᴰ; ᴰ; D; D; ) MODIFIER LETTER CAPITAL D +1D31;1D31;1D31;0045;0045; # (ᴱ; ᴱ; ᴱ; E; E; ) MODIFIER LETTER CAPITAL E +1D32;1D32;1D32;018E;018E; # (ᴲ; ᴲ; ᴲ; Ǝ; Ǝ; ) MODIFIER LETTER CAPITAL REVERSED E +1D33;1D33;1D33;0047;0047; # (ᴳ; ᴳ; ᴳ; G; G; ) MODIFIER LETTER CAPITAL G +1D34;1D34;1D34;0048;0048; # (ᴴ; ᴴ; ᴴ; H; H; ) MODIFIER LETTER CAPITAL H +1D35;1D35;1D35;0049;0049; # (ᴵ; ᴵ; ᴵ; I; I; ) MODIFIER LETTER CAPITAL I +1D36;1D36;1D36;004A;004A; # (ᴶ; ᴶ; ᴶ; J; J; ) MODIFIER LETTER CAPITAL J +1D37;1D37;1D37;004B;004B; # (ᴷ; ᴷ; ᴷ; K; K; ) MODIFIER LETTER CAPITAL K +1D38;1D38;1D38;004C;004C; # (ᴸ; ᴸ; ᴸ; L; L; ) MODIFIER LETTER CAPITAL L +1D39;1D39;1D39;004D;004D; # (ᴹ; ᴹ; ᴹ; M; M; ) MODIFIER LETTER CAPITAL M +1D3A;1D3A;1D3A;004E;004E; # (ᴺ; ᴺ; ᴺ; N; N; ) MODIFIER LETTER CAPITAL N +1D3C;1D3C;1D3C;004F;004F; # (ᴼ; ᴼ; ᴼ; O; O; ) MODIFIER LETTER CAPITAL O +1D3D;1D3D;1D3D;0222;0222; # (ᴽ; ᴽ; ᴽ; Ȣ; Ȣ; ) MODIFIER LETTER CAPITAL OU +1D3E;1D3E;1D3E;0050;0050; # (ᴾ; ᴾ; ᴾ; P; P; ) MODIFIER LETTER CAPITAL P +1D3F;1D3F;1D3F;0052;0052; # (ᴿ; ᴿ; ᴿ; R; R; ) MODIFIER LETTER CAPITAL R +1D40;1D40;1D40;0054;0054; # (ᵀ; ᵀ; ᵀ; T; T; ) MODIFIER LETTER CAPITAL T +1D41;1D41;1D41;0055;0055; # (ᵁ; ᵁ; ᵁ; U; U; ) MODIFIER LETTER CAPITAL U +1D42;1D42;1D42;0057;0057; # (ᵂ; ᵂ; ᵂ; W; W; ) MODIFIER LETTER CAPITAL W +1D43;1D43;1D43;0061;0061; # (ᵃ; ᵃ; ᵃ; a; a; ) MODIFIER LETTER SMALL A +1D44;1D44;1D44;0250;0250; # (ᵄ; ᵄ; ᵄ; ɐ; ɐ; ) MODIFIER LETTER SMALL TURNED A +1D45;1D45;1D45;0251;0251; # (ᵅ; ᵅ; ᵅ; ɑ; ɑ; ) MODIFIER LETTER SMALL ALPHA +1D46;1D46;1D46;1D02;1D02; # (ᵆ; ᵆ; ᵆ; ᴂ; ᴂ; ) MODIFIER LETTER SMALL TURNED AE +1D47;1D47;1D47;0062;0062; # (ᵇ; ᵇ; ᵇ; b; b; ) MODIFIER LETTER SMALL B +1D48;1D48;1D48;0064;0064; # (ᵈ; ᵈ; ᵈ; d; d; ) MODIFIER LETTER SMALL D +1D49;1D49;1D49;0065;0065; # (ᵉ; ᵉ; ᵉ; e; e; ) MODIFIER LETTER SMALL E +1D4A;1D4A;1D4A;0259;0259; # (ᵊ; ᵊ; ᵊ; ə; ə; ) MODIFIER LETTER SMALL SCHWA +1D4B;1D4B;1D4B;025B;025B; # (ᵋ; ᵋ; ᵋ; ɛ; ɛ; ) MODIFIER LETTER SMALL OPEN E +1D4C;1D4C;1D4C;025C;025C; # (ᵌ; ᵌ; ᵌ; ɜ; ɜ; ) MODIFIER LETTER SMALL TURNED OPEN E +1D4D;1D4D;1D4D;0067;0067; # (ᵍ; ᵍ; ᵍ; g; g; ) MODIFIER LETTER SMALL G +1D4F;1D4F;1D4F;006B;006B; # (ᵏ; ᵏ; ᵏ; k; k; ) MODIFIER LETTER SMALL K +1D50;1D50;1D50;006D;006D; # (ᵐ; ᵐ; ᵐ; m; m; ) MODIFIER LETTER SMALL M +1D51;1D51;1D51;014B;014B; # (ᵑ; ᵑ; ᵑ; ŋ; ŋ; ) MODIFIER LETTER SMALL ENG +1D52;1D52;1D52;006F;006F; # (ᵒ; ᵒ; ᵒ; o; o; ) MODIFIER LETTER SMALL O +1D53;1D53;1D53;0254;0254; # (ᵓ; ᵓ; ᵓ; ɔ; ɔ; ) MODIFIER LETTER SMALL OPEN O +1D54;1D54;1D54;1D16;1D16; # (ᵔ; ᵔ; ᵔ; ᴖ; ᴖ; ) MODIFIER LETTER SMALL TOP HALF O +1D55;1D55;1D55;1D17;1D17; # (ᵕ; ᵕ; ᵕ; ᴗ; ᴗ; ) MODIFIER LETTER SMALL BOTTOM HALF O +1D56;1D56;1D56;0070;0070; # (ᵖ; ᵖ; ᵖ; p; p; ) MODIFIER LETTER SMALL P +1D57;1D57;1D57;0074;0074; # (ᵗ; ᵗ; ᵗ; t; t; ) MODIFIER LETTER SMALL T +1D58;1D58;1D58;0075;0075; # (ᵘ; ᵘ; ᵘ; u; u; ) MODIFIER LETTER SMALL U +1D59;1D59;1D59;1D1D;1D1D; # (ᵙ; ᵙ; ᵙ; ᴝ; ᴝ; ) MODIFIER LETTER SMALL SIDEWAYS U +1D5A;1D5A;1D5A;026F;026F; # (ᵚ; ᵚ; ᵚ; ɯ; ɯ; ) MODIFIER LETTER SMALL TURNED M +1D5B;1D5B;1D5B;0076;0076; # (ᵛ; ᵛ; ᵛ; v; v; ) MODIFIER LETTER SMALL V +1D5C;1D5C;1D5C;1D25;1D25; # (ᵜ; ᵜ; ᵜ; ᴥ; ᴥ; ) MODIFIER LETTER SMALL AIN +1D5D;1D5D;1D5D;03B2;03B2; # (ᵝ; ᵝ; ᵝ; β; β; ) MODIFIER LETTER SMALL BETA +1D5E;1D5E;1D5E;03B3;03B3; # (ᵞ; ᵞ; ᵞ; γ; γ; ) MODIFIER LETTER SMALL GREEK GAMMA +1D5F;1D5F;1D5F;03B4;03B4; # (ᵟ; ᵟ; ᵟ; δ; δ; ) MODIFIER LETTER SMALL DELTA +1D60;1D60;1D60;03C6;03C6; # (ᵠ; ᵠ; ᵠ; φ; φ; ) MODIFIER LETTER SMALL GREEK PHI +1D61;1D61;1D61;03C7;03C7; # (ᵡ; ᵡ; ᵡ; χ; χ; ) MODIFIER LETTER SMALL CHI +1D62;1D62;1D62;0069;0069; # (ᵢ; ᵢ; ᵢ; i; i; ) LATIN SUBSCRIPT SMALL LETTER I +1D63;1D63;1D63;0072;0072; # (ᵣ; ᵣ; ᵣ; r; r; ) LATIN SUBSCRIPT SMALL LETTER R +1D64;1D64;1D64;0075;0075; # (ᵤ; ᵤ; ᵤ; u; u; ) LATIN SUBSCRIPT SMALL LETTER U +1D65;1D65;1D65;0076;0076; # (ᵥ; ᵥ; ᵥ; v; v; ) LATIN SUBSCRIPT SMALL LETTER V +1D66;1D66;1D66;03B2;03B2; # (ᵦ; ᵦ; ᵦ; β; β; ) GREEK SUBSCRIPT SMALL LETTER BETA +1D67;1D67;1D67;03B3;03B3; # (ᵧ; ᵧ; ᵧ; γ; γ; ) GREEK SUBSCRIPT SMALL LETTER GAMMA +1D68;1D68;1D68;03C1;03C1; # (ᵨ; ᵨ; ᵨ; ρ; ρ; ) GREEK SUBSCRIPT SMALL LETTER RHO +1D69;1D69;1D69;03C6;03C6; # (ᵩ; ᵩ; ᵩ; φ; φ; ) GREEK SUBSCRIPT SMALL LETTER PHI +1D6A;1D6A;1D6A;03C7;03C7; # (ᵪ; ᵪ; ᵪ; χ; χ; ) GREEK SUBSCRIPT SMALL LETTER CHI +1D78;1D78;1D78;043D;043D; # (ᵸ; ᵸ; ᵸ; н; н; ) MODIFIER LETTER CYRILLIC EN +1D9B;1D9B;1D9B;0252;0252; # (ᶛ; ᶛ; ᶛ; ɒ; ɒ; ) MODIFIER LETTER SMALL TURNED ALPHA +1D9C;1D9C;1D9C;0063;0063; # (ᶜ; ᶜ; ᶜ; c; c; ) MODIFIER LETTER SMALL C +1D9D;1D9D;1D9D;0255;0255; # (ᶝ; ᶝ; ᶝ; ɕ; ɕ; ) MODIFIER LETTER SMALL C WITH CURL +1D9E;1D9E;1D9E;00F0;00F0; # (ᶞ; ᶞ; ᶞ; ð; ð; ) MODIFIER LETTER SMALL ETH +1D9F;1D9F;1D9F;025C;025C; # (ᶟ; ᶟ; ᶟ; ɜ; ɜ; ) MODIFIER LETTER SMALL REVERSED OPEN E +1DA0;1DA0;1DA0;0066;0066; # (ᶠ; ᶠ; ᶠ; f; f; ) MODIFIER LETTER SMALL F +1DA1;1DA1;1DA1;025F;025F; # (ᶡ; ᶡ; ᶡ; ɟ; ɟ; ) MODIFIER LETTER SMALL DOTLESS J WITH STROKE +1DA2;1DA2;1DA2;0261;0261; # (ᶢ; ᶢ; ᶢ; ɡ; ɡ; ) MODIFIER LETTER SMALL SCRIPT G +1DA3;1DA3;1DA3;0265;0265; # (ᶣ; ᶣ; ᶣ; ɥ; ɥ; ) MODIFIER LETTER SMALL TURNED H +1DA4;1DA4;1DA4;0268;0268; # (ᶤ; ᶤ; ᶤ; ɨ; ɨ; ) MODIFIER LETTER SMALL I WITH STROKE +1DA5;1DA5;1DA5;0269;0269; # (ᶥ; ᶥ; ᶥ; ɩ; ɩ; ) MODIFIER LETTER SMALL IOTA +1DA6;1DA6;1DA6;026A;026A; # (ᶦ; ᶦ; ᶦ; ɪ; ɪ; ) MODIFIER LETTER SMALL CAPITAL I +1DA7;1DA7;1DA7;1D7B;1D7B; # (ᶧ; ᶧ; ᶧ; ᵻ; ᵻ; ) MODIFIER LETTER SMALL CAPITAL I WITH STROKE +1DA8;1DA8;1DA8;029D;029D; # (ᶨ; ᶨ; ᶨ; ʝ; ʝ; ) MODIFIER LETTER SMALL J WITH CROSSED-TAIL +1DA9;1DA9;1DA9;026D;026D; # (ᶩ; ᶩ; ᶩ; ɭ; ɭ; ) MODIFIER LETTER SMALL L WITH RETROFLEX HOOK +1DAA;1DAA;1DAA;1D85;1D85; # (ᶪ; ᶪ; ᶪ; ᶅ; ᶅ; ) MODIFIER LETTER SMALL L WITH PALATAL HOOK +1DAB;1DAB;1DAB;029F;029F; # (ᶫ; ᶫ; ᶫ; ʟ; ʟ; ) MODIFIER LETTER SMALL CAPITAL L +1DAC;1DAC;1DAC;0271;0271; # (ᶬ; ᶬ; ᶬ; ɱ; ɱ; ) MODIFIER LETTER SMALL M WITH HOOK +1DAD;1DAD;1DAD;0270;0270; # (ᶭ; ᶭ; ᶭ; ɰ; ɰ; ) MODIFIER LETTER SMALL TURNED M WITH LONG LEG +1DAE;1DAE;1DAE;0272;0272; # (ᶮ; ᶮ; ᶮ; ɲ; ɲ; ) MODIFIER LETTER SMALL N WITH LEFT HOOK +1DAF;1DAF;1DAF;0273;0273; # (ᶯ; ᶯ; ᶯ; ɳ; ɳ; ) MODIFIER LETTER SMALL N WITH RETROFLEX HOOK +1DB0;1DB0;1DB0;0274;0274; # (ᶰ; ᶰ; ᶰ; ɴ; ɴ; ) MODIFIER LETTER SMALL CAPITAL N +1DB1;1DB1;1DB1;0275;0275; # (ᶱ; ᶱ; ᶱ; ɵ; ɵ; ) MODIFIER LETTER SMALL BARRED O +1DB2;1DB2;1DB2;0278;0278; # (ᶲ; ᶲ; ᶲ; ɸ; ɸ; ) MODIFIER LETTER SMALL PHI +1DB3;1DB3;1DB3;0282;0282; # (ᶳ; ᶳ; ᶳ; ʂ; ʂ; ) MODIFIER LETTER SMALL S WITH HOOK +1DB4;1DB4;1DB4;0283;0283; # (ᶴ; ᶴ; ᶴ; ʃ; ʃ; ) MODIFIER LETTER SMALL ESH +1DB5;1DB5;1DB5;01AB;01AB; # (ᶵ; ᶵ; ᶵ; ƫ; ƫ; ) MODIFIER LETTER SMALL T WITH PALATAL HOOK +1DB6;1DB6;1DB6;0289;0289; # (ᶶ; ᶶ; ᶶ; ʉ; ʉ; ) MODIFIER LETTER SMALL U BAR +1DB7;1DB7;1DB7;028A;028A; # (ᶷ; ᶷ; ᶷ; ʊ; ʊ; ) MODIFIER LETTER SMALL UPSILON +1DB8;1DB8;1DB8;1D1C;1D1C; # (ᶸ; ᶸ; ᶸ; ᴜ; ᴜ; ) MODIFIER LETTER SMALL CAPITAL U +1DB9;1DB9;1DB9;028B;028B; # (ᶹ; ᶹ; ᶹ; ʋ; ʋ; ) MODIFIER LETTER SMALL V WITH HOOK +1DBA;1DBA;1DBA;028C;028C; # (ᶺ; ᶺ; ᶺ; ʌ; ʌ; ) MODIFIER LETTER SMALL TURNED V +1DBB;1DBB;1DBB;007A;007A; # (ᶻ; ᶻ; ᶻ; z; z; ) MODIFIER LETTER SMALL Z +1DBC;1DBC;1DBC;0290;0290; # (ᶼ; ᶼ; ᶼ; ʐ; ʐ; ) MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK +1DBD;1DBD;1DBD;0291;0291; # (ᶽ; ᶽ; ᶽ; ʑ; ʑ; ) MODIFIER LETTER SMALL Z WITH CURL +1DBE;1DBE;1DBE;0292;0292; # (ᶾ; ᶾ; ᶾ; ʒ; ʒ; ) MODIFIER LETTER SMALL EZH +1DBF;1DBF;1DBF;03B8;03B8; # (ᶿ; ᶿ; ᶿ; θ; θ; ) MODIFIER LETTER SMALL THETA +1E00;1E00;0041 0325;1E00;0041 0325; # (Ḁ; Ḁ; A◌̥; Ḁ; A◌̥; ) LATIN CAPITAL LETTER A WITH RING BELOW +1E01;1E01;0061 0325;1E01;0061 0325; # (ḁ; ḁ; a◌̥; ḁ; a◌̥; ) LATIN SMALL LETTER A WITH RING BELOW +1E02;1E02;0042 0307;1E02;0042 0307; # (Ḃ; Ḃ; B◌̇; Ḃ; B◌̇; ) LATIN CAPITAL LETTER B WITH DOT ABOVE +1E03;1E03;0062 0307;1E03;0062 0307; # (ḃ; ḃ; b◌̇; ḃ; b◌̇; ) LATIN SMALL LETTER B WITH DOT ABOVE +1E04;1E04;0042 0323;1E04;0042 0323; # (Ḅ; Ḅ; B◌̣; Ḅ; B◌̣; ) LATIN CAPITAL LETTER B WITH DOT BELOW +1E05;1E05;0062 0323;1E05;0062 0323; # (ḅ; ḅ; b◌̣; ḅ; b◌̣; ) LATIN SMALL LETTER B WITH DOT BELOW +1E06;1E06;0042 0331;1E06;0042 0331; # (Ḇ; Ḇ; B◌̱; Ḇ; B◌̱; ) LATIN CAPITAL LETTER B WITH LINE BELOW +1E07;1E07;0062 0331;1E07;0062 0331; # (ḇ; ḇ; b◌̱; ḇ; b◌̱; ) LATIN SMALL LETTER B WITH LINE BELOW +1E08;1E08;0043 0327 0301;1E08;0043 0327 0301; # (Ḉ; Ḉ; C◌̧◌́; Ḉ; C◌̧◌́; ) LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E09;1E09;0063 0327 0301;1E09;0063 0327 0301; # (ḉ; ḉ; c◌̧◌́; ḉ; c◌̧◌́; ) LATIN SMALL LETTER C WITH CEDILLA AND ACUTE +1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0B;1E0B;0064 0307;1E0B;0064 0307; # (ḋ; ḋ; d◌̇; ḋ; d◌̇; ) LATIN SMALL LETTER D WITH DOT ABOVE +1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +1E0D;1E0D;0064 0323;1E0D;0064 0323; # (ḍ; ḍ; d◌̣; ḍ; d◌̣; ) LATIN SMALL LETTER D WITH DOT BELOW +1E0E;1E0E;0044 0331;1E0E;0044 0331; # (Ḏ; Ḏ; D◌̱; Ḏ; D◌̱; ) LATIN CAPITAL LETTER D WITH LINE BELOW +1E0F;1E0F;0064 0331;1E0F;0064 0331; # (ḏ; ḏ; d◌̱; ḏ; d◌̱; ) LATIN SMALL LETTER D WITH LINE BELOW +1E10;1E10;0044 0327;1E10;0044 0327; # (Ḑ; Ḑ; D◌̧; Ḑ; D◌̧; ) LATIN CAPITAL LETTER D WITH CEDILLA +1E11;1E11;0064 0327;1E11;0064 0327; # (ḑ; ḑ; d◌̧; ḑ; d◌̧; ) LATIN SMALL LETTER D WITH CEDILLA +1E12;1E12;0044 032D;1E12;0044 032D; # (Ḓ; Ḓ; D◌̭; Ḓ; D◌̭; ) LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E13;1E13;0064 032D;1E13;0064 032D; # (ḓ; ḓ; d◌̭; ḓ; d◌̭; ) LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW +1E14;1E14;0045 0304 0300;1E14;0045 0304 0300; # (Ḕ; Ḕ; E◌̄◌̀; Ḕ; E◌̄◌̀; ) LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E15;1E15;0065 0304 0300;1E15;0065 0304 0300; # (ḕ; ḕ; e◌̄◌̀; ḕ; e◌̄◌̀; ) LATIN SMALL LETTER E WITH MACRON AND GRAVE +1E16;1E16;0045 0304 0301;1E16;0045 0304 0301; # (Ḗ; Ḗ; E◌̄◌́; Ḗ; E◌̄◌́; ) LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E17;1E17;0065 0304 0301;1E17;0065 0304 0301; # (ḗ; ḗ; e◌̄◌́; ḗ; e◌̄◌́; ) LATIN SMALL LETTER E WITH MACRON AND ACUTE +1E18;1E18;0045 032D;1E18;0045 032D; # (Ḙ; Ḙ; E◌̭; Ḙ; E◌̭; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E19;1E19;0065 032D;1E19;0065 032D; # (ḙ; ḙ; e◌̭; ḙ; e◌̭; ) LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW +1E1A;1E1A;0045 0330;1E1A;0045 0330; # (Ḛ; Ḛ; E◌̰; Ḛ; E◌̰; ) LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1B;1E1B;0065 0330;1E1B;0065 0330; # (ḛ; ḛ; e◌̰; ḛ; e◌̰; ) LATIN SMALL LETTER E WITH TILDE BELOW +1E1C;1E1C;0045 0327 0306;1E1C;0045 0327 0306; # (Ḝ; Ḝ; E◌̧◌̆; Ḝ; E◌̧◌̆; ) LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1D;1E1D;0065 0327 0306;1E1D;0065 0327 0306; # (ḝ; ḝ; e◌̧◌̆; ḝ; e◌̧◌̆; ) LATIN SMALL LETTER E WITH CEDILLA AND BREVE +1E1E;1E1E;0046 0307;1E1E;0046 0307; # (Ḟ; Ḟ; F◌̇; Ḟ; F◌̇; ) LATIN CAPITAL LETTER F WITH DOT ABOVE +1E1F;1E1F;0066 0307;1E1F;0066 0307; # (ḟ; ḟ; f◌̇; ḟ; f◌̇; ) LATIN SMALL LETTER F WITH DOT ABOVE +1E20;1E20;0047 0304;1E20;0047 0304; # (Ḡ; Ḡ; G◌̄; Ḡ; G◌̄; ) LATIN CAPITAL LETTER G WITH MACRON +1E21;1E21;0067 0304;1E21;0067 0304; # (ḡ; ḡ; g◌̄; ḡ; g◌̄; ) LATIN SMALL LETTER G WITH MACRON +1E22;1E22;0048 0307;1E22;0048 0307; # (Ḣ; Ḣ; H◌̇; Ḣ; H◌̇; ) LATIN CAPITAL LETTER H WITH DOT ABOVE +1E23;1E23;0068 0307;1E23;0068 0307; # (ḣ; ḣ; h◌̇; ḣ; h◌̇; ) LATIN SMALL LETTER H WITH DOT ABOVE +1E24;1E24;0048 0323;1E24;0048 0323; # (Ḥ; Ḥ; H◌̣; Ḥ; H◌̣; ) LATIN CAPITAL LETTER H WITH DOT BELOW +1E25;1E25;0068 0323;1E25;0068 0323; # (ḥ; ḥ; h◌̣; ḥ; h◌̣; ) LATIN SMALL LETTER H WITH DOT BELOW +1E26;1E26;0048 0308;1E26;0048 0308; # (Ḧ; Ḧ; H◌̈; Ḧ; H◌̈; ) LATIN CAPITAL LETTER H WITH DIAERESIS +1E27;1E27;0068 0308;1E27;0068 0308; # (ḧ; ḧ; h◌̈; ḧ; h◌̈; ) LATIN SMALL LETTER H WITH DIAERESIS +1E28;1E28;0048 0327;1E28;0048 0327; # (Ḩ; Ḩ; H◌̧; Ḩ; H◌̧; ) LATIN CAPITAL LETTER H WITH CEDILLA +1E29;1E29;0068 0327;1E29;0068 0327; # (ḩ; ḩ; h◌̧; ḩ; h◌̧; ) LATIN SMALL LETTER H WITH CEDILLA +1E2A;1E2A;0048 032E;1E2A;0048 032E; # (Ḫ; Ḫ; H◌̮; Ḫ; H◌̮; ) LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2B;1E2B;0068 032E;1E2B;0068 032E; # (ḫ; ḫ; h◌̮; ḫ; h◌̮; ) LATIN SMALL LETTER H WITH BREVE BELOW +1E2C;1E2C;0049 0330;1E2C;0049 0330; # (Ḭ; Ḭ; I◌̰; Ḭ; I◌̰; ) LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2D;1E2D;0069 0330;1E2D;0069 0330; # (ḭ; ḭ; i◌̰; ḭ; i◌̰; ) LATIN SMALL LETTER I WITH TILDE BELOW +1E2E;1E2E;0049 0308 0301;1E2E;0049 0308 0301; # (Ḯ; Ḯ; I◌̈◌́; Ḯ; I◌̈◌́; ) LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E2F;1E2F;0069 0308 0301;1E2F;0069 0308 0301; # (ḯ; ḯ; i◌̈◌́; ḯ; i◌̈◌́; ) LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE +1E30;1E30;004B 0301;1E30;004B 0301; # (Ḱ; Ḱ; K◌́; Ḱ; K◌́; ) LATIN CAPITAL LETTER K WITH ACUTE +1E31;1E31;006B 0301;1E31;006B 0301; # (ḱ; ḱ; k◌́; ḱ; k◌́; ) LATIN SMALL LETTER K WITH ACUTE +1E32;1E32;004B 0323;1E32;004B 0323; # (Ḳ; Ḳ; K◌̣; Ḳ; K◌̣; ) LATIN CAPITAL LETTER K WITH DOT BELOW +1E33;1E33;006B 0323;1E33;006B 0323; # (ḳ; ḳ; k◌̣; ḳ; k◌̣; ) LATIN SMALL LETTER K WITH DOT BELOW +1E34;1E34;004B 0331;1E34;004B 0331; # (Ḵ; Ḵ; K◌̱; Ḵ; K◌̱; ) LATIN CAPITAL LETTER K WITH LINE BELOW +1E35;1E35;006B 0331;1E35;006B 0331; # (ḵ; ḵ; k◌̱; ḵ; k◌̱; ) LATIN SMALL LETTER K WITH LINE BELOW +1E36;1E36;004C 0323;1E36;004C 0323; # (Ḷ; Ḷ; L◌̣; Ḷ; L◌̣; ) LATIN CAPITAL LETTER L WITH DOT BELOW +1E37;1E37;006C 0323;1E37;006C 0323; # (ḷ; ḷ; l◌̣; ḷ; l◌̣; ) LATIN SMALL LETTER L WITH DOT BELOW +1E38;1E38;004C 0323 0304;1E38;004C 0323 0304; # (Ḹ; Ḹ; L◌̣◌̄; Ḹ; L◌̣◌̄; ) LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E39;1E39;006C 0323 0304;1E39;006C 0323 0304; # (ḹ; ḹ; l◌̣◌̄; ḹ; l◌̣◌̄; ) LATIN SMALL LETTER L WITH DOT BELOW AND MACRON +1E3A;1E3A;004C 0331;1E3A;004C 0331; # (Ḻ; Ḻ; L◌̱; Ḻ; L◌̱; ) LATIN CAPITAL LETTER L WITH LINE BELOW +1E3B;1E3B;006C 0331;1E3B;006C 0331; # (ḻ; ḻ; l◌̱; ḻ; l◌̱; ) LATIN SMALL LETTER L WITH LINE BELOW +1E3C;1E3C;004C 032D;1E3C;004C 032D; # (Ḽ; Ḽ; L◌̭; Ḽ; L◌̭; ) LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3D;1E3D;006C 032D;1E3D;006C 032D; # (ḽ; ḽ; l◌̭; ḽ; l◌̭; ) LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW +1E3E;1E3E;004D 0301;1E3E;004D 0301; # (Ḿ; Ḿ; M◌́; Ḿ; M◌́; ) LATIN CAPITAL LETTER M WITH ACUTE +1E3F;1E3F;006D 0301;1E3F;006D 0301; # (ḿ; ḿ; m◌́; ḿ; m◌́; ) LATIN SMALL LETTER M WITH ACUTE +1E40;1E40;004D 0307;1E40;004D 0307; # (Ṁ; Ṁ; M◌̇; Ṁ; M◌̇; ) LATIN CAPITAL LETTER M WITH DOT ABOVE +1E41;1E41;006D 0307;1E41;006D 0307; # (ṁ; ṁ; m◌̇; ṁ; m◌̇; ) LATIN SMALL LETTER M WITH DOT ABOVE +1E42;1E42;004D 0323;1E42;004D 0323; # (Ṃ; Ṃ; M◌̣; Ṃ; M◌̣; ) LATIN CAPITAL LETTER M WITH DOT BELOW +1E43;1E43;006D 0323;1E43;006D 0323; # (ṃ; ṃ; m◌̣; ṃ; m◌̣; ) LATIN SMALL LETTER M WITH DOT BELOW +1E44;1E44;004E 0307;1E44;004E 0307; # (Ṅ; Ṅ; N◌̇; Ṅ; N◌̇; ) LATIN CAPITAL LETTER N WITH DOT ABOVE +1E45;1E45;006E 0307;1E45;006E 0307; # (ṅ; ṅ; n◌̇; ṅ; n◌̇; ) LATIN SMALL LETTER N WITH DOT ABOVE +1E46;1E46;004E 0323;1E46;004E 0323; # (Ṇ; Ṇ; N◌̣; Ṇ; N◌̣; ) LATIN CAPITAL LETTER N WITH DOT BELOW +1E47;1E47;006E 0323;1E47;006E 0323; # (ṇ; ṇ; n◌̣; ṇ; n◌̣; ) LATIN SMALL LETTER N WITH DOT BELOW +1E48;1E48;004E 0331;1E48;004E 0331; # (Ṉ; Ṉ; N◌̱; Ṉ; N◌̱; ) LATIN CAPITAL LETTER N WITH LINE BELOW +1E49;1E49;006E 0331;1E49;006E 0331; # (ṉ; ṉ; n◌̱; ṉ; n◌̱; ) LATIN SMALL LETTER N WITH LINE BELOW +1E4A;1E4A;004E 032D;1E4A;004E 032D; # (Ṋ; Ṋ; N◌̭; Ṋ; N◌̭; ) LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4B;1E4B;006E 032D;1E4B;006E 032D; # (ṋ; ṋ; n◌̭; ṋ; n◌̭; ) LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW +1E4C;1E4C;004F 0303 0301;1E4C;004F 0303 0301; # (Ṍ; Ṍ; O◌̃◌́; Ṍ; O◌̃◌́; ) LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4D;1E4D;006F 0303 0301;1E4D;006F 0303 0301; # (ṍ; ṍ; o◌̃◌́; ṍ; o◌̃◌́; ) LATIN SMALL LETTER O WITH TILDE AND ACUTE +1E4E;1E4E;004F 0303 0308;1E4E;004F 0303 0308; # (Ṏ; Ṏ; O◌̃◌̈; Ṏ; O◌̃◌̈; ) LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E4F;1E4F;006F 0303 0308;1E4F;006F 0303 0308; # (ṏ; ṏ; o◌̃◌̈; ṏ; o◌̃◌̈; ) LATIN SMALL LETTER O WITH TILDE AND DIAERESIS +1E50;1E50;004F 0304 0300;1E50;004F 0304 0300; # (Ṑ; Ṑ; O◌̄◌̀; Ṑ; O◌̄◌̀; ) LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E51;1E51;006F 0304 0300;1E51;006F 0304 0300; # (ṑ; ṑ; o◌̄◌̀; ṑ; o◌̄◌̀; ) LATIN SMALL LETTER O WITH MACRON AND GRAVE +1E52;1E52;004F 0304 0301;1E52;004F 0304 0301; # (Ṓ; Ṓ; O◌̄◌́; Ṓ; O◌̄◌́; ) LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E53;1E53;006F 0304 0301;1E53;006F 0304 0301; # (ṓ; ṓ; o◌̄◌́; ṓ; o◌̄◌́; ) LATIN SMALL LETTER O WITH MACRON AND ACUTE +1E54;1E54;0050 0301;1E54;0050 0301; # (Ṕ; Ṕ; P◌́; Ṕ; P◌́; ) LATIN CAPITAL LETTER P WITH ACUTE +1E55;1E55;0070 0301;1E55;0070 0301; # (ṕ; ṕ; p◌́; ṕ; p◌́; ) LATIN SMALL LETTER P WITH ACUTE +1E56;1E56;0050 0307;1E56;0050 0307; # (Ṗ; Ṗ; P◌̇; Ṗ; P◌̇; ) LATIN CAPITAL LETTER P WITH DOT ABOVE +1E57;1E57;0070 0307;1E57;0070 0307; # (ṗ; ṗ; p◌̇; ṗ; p◌̇; ) LATIN SMALL LETTER P WITH DOT ABOVE +1E58;1E58;0052 0307;1E58;0052 0307; # (Ṙ; Ṙ; R◌̇; Ṙ; R◌̇; ) LATIN CAPITAL LETTER R WITH DOT ABOVE +1E59;1E59;0072 0307;1E59;0072 0307; # (ṙ; ṙ; r◌̇; ṙ; r◌̇; ) LATIN SMALL LETTER R WITH DOT ABOVE +1E5A;1E5A;0052 0323;1E5A;0052 0323; # (Ṛ; Ṛ; R◌̣; Ṛ; R◌̣; ) LATIN CAPITAL LETTER R WITH DOT BELOW +1E5B;1E5B;0072 0323;1E5B;0072 0323; # (ṛ; ṛ; r◌̣; ṛ; r◌̣; ) LATIN SMALL LETTER R WITH DOT BELOW +1E5C;1E5C;0052 0323 0304;1E5C;0052 0323 0304; # (Ṝ; Ṝ; R◌̣◌̄; Ṝ; R◌̣◌̄; ) LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5D;1E5D;0072 0323 0304;1E5D;0072 0323 0304; # (ṝ; ṝ; r◌̣◌̄; ṝ; r◌̣◌̄; ) LATIN SMALL LETTER R WITH DOT BELOW AND MACRON +1E5E;1E5E;0052 0331;1E5E;0052 0331; # (Ṟ; Ṟ; R◌̱; Ṟ; R◌̱; ) LATIN CAPITAL LETTER R WITH LINE BELOW +1E5F;1E5F;0072 0331;1E5F;0072 0331; # (ṟ; ṟ; r◌̱; ṟ; r◌̱; ) LATIN SMALL LETTER R WITH LINE BELOW +1E60;1E60;0053 0307;1E60;0053 0307; # (Ṡ; Ṡ; S◌̇; Ṡ; S◌̇; ) LATIN CAPITAL LETTER S WITH DOT ABOVE +1E61;1E61;0073 0307;1E61;0073 0307; # (ṡ; ṡ; s◌̇; ṡ; s◌̇; ) LATIN SMALL LETTER S WITH DOT ABOVE +1E62;1E62;0053 0323;1E62;0053 0323; # (Ṣ; Ṣ; S◌̣; Ṣ; S◌̣; ) LATIN CAPITAL LETTER S WITH DOT BELOW +1E63;1E63;0073 0323;1E63;0073 0323; # (ṣ; ṣ; s◌̣; ṣ; s◌̣; ) LATIN SMALL LETTER S WITH DOT BELOW +1E64;1E64;0053 0301 0307;1E64;0053 0301 0307; # (Ṥ; Ṥ; S◌́◌̇; Ṥ; S◌́◌̇; ) LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E65;1E65;0073 0301 0307;1E65;0073 0301 0307; # (ṥ; ṥ; s◌́◌̇; ṥ; s◌́◌̇; ) LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE +1E66;1E66;0053 030C 0307;1E66;0053 030C 0307; # (Ṧ; Ṧ; S◌̌◌̇; Ṧ; S◌̌◌̇; ) LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E67;1E67;0073 030C 0307;1E67;0073 030C 0307; # (ṧ; ṧ; s◌̌◌̇; ṧ; s◌̌◌̇; ) LATIN SMALL LETTER S WITH CARON AND DOT ABOVE +1E68;1E68;0053 0323 0307;1E68;0053 0323 0307; # (Ṩ; Ṩ; S◌̣◌̇; Ṩ; S◌̣◌̇; ) LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E69;1E69;0073 0323 0307;1E69;0073 0323 0307; # (ṩ; ṩ; s◌̣◌̇; ṩ; s◌̣◌̇; ) LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A;1E6A;0054 0307;1E6A;0054 0307; # (Ṫ; Ṫ; T◌̇; Ṫ; T◌̇; ) LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6B;1E6B;0074 0307;1E6B;0074 0307; # (ṫ; ṫ; t◌̇; ṫ; t◌̇; ) LATIN SMALL LETTER T WITH DOT ABOVE +1E6C;1E6C;0054 0323;1E6C;0054 0323; # (Ṭ; Ṭ; T◌̣; Ṭ; T◌̣; ) LATIN CAPITAL LETTER T WITH DOT BELOW +1E6D;1E6D;0074 0323;1E6D;0074 0323; # (ṭ; ṭ; t◌̣; ṭ; t◌̣; ) LATIN SMALL LETTER T WITH DOT BELOW +1E6E;1E6E;0054 0331;1E6E;0054 0331; # (Ṯ; Ṯ; T◌̱; Ṯ; T◌̱; ) LATIN CAPITAL LETTER T WITH LINE BELOW +1E6F;1E6F;0074 0331;1E6F;0074 0331; # (ṯ; ṯ; t◌̱; ṯ; t◌̱; ) LATIN SMALL LETTER T WITH LINE BELOW +1E70;1E70;0054 032D;1E70;0054 032D; # (Ṱ; Ṱ; T◌̭; Ṱ; T◌̭; ) LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E71;1E71;0074 032D;1E71;0074 032D; # (ṱ; ṱ; t◌̭; ṱ; t◌̭; ) LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW +1E72;1E72;0055 0324;1E72;0055 0324; # (Ṳ; Ṳ; U◌̤; Ṳ; U◌̤; ) LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E73;1E73;0075 0324;1E73;0075 0324; # (ṳ; ṳ; u◌̤; ṳ; u◌̤; ) LATIN SMALL LETTER U WITH DIAERESIS BELOW +1E74;1E74;0055 0330;1E74;0055 0330; # (Ṵ; Ṵ; U◌̰; Ṵ; U◌̰; ) LATIN CAPITAL LETTER U WITH TILDE BELOW +1E75;1E75;0075 0330;1E75;0075 0330; # (ṵ; ṵ; u◌̰; ṵ; u◌̰; ) LATIN SMALL LETTER U WITH TILDE BELOW +1E76;1E76;0055 032D;1E76;0055 032D; # (Ṷ; Ṷ; U◌̭; Ṷ; U◌̭; ) LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E77;1E77;0075 032D;1E77;0075 032D; # (ṷ; ṷ; u◌̭; ṷ; u◌̭; ) LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW +1E78;1E78;0055 0303 0301;1E78;0055 0303 0301; # (Ṹ; Ṹ; U◌̃◌́; Ṹ; U◌̃◌́; ) LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E79;1E79;0075 0303 0301;1E79;0075 0303 0301; # (ṹ; ṹ; u◌̃◌́; ṹ; u◌̃◌́; ) LATIN SMALL LETTER U WITH TILDE AND ACUTE +1E7A;1E7A;0055 0304 0308;1E7A;0055 0304 0308; # (Ṻ; Ṻ; U◌̄◌̈; Ṻ; U◌̄◌̈; ) LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7B;1E7B;0075 0304 0308;1E7B;0075 0304 0308; # (ṻ; ṻ; u◌̄◌̈; ṻ; u◌̄◌̈; ) LATIN SMALL LETTER U WITH MACRON AND DIAERESIS +1E7C;1E7C;0056 0303;1E7C;0056 0303; # (Ṽ; Ṽ; V◌̃; Ṽ; V◌̃; ) LATIN CAPITAL LETTER V WITH TILDE +1E7D;1E7D;0076 0303;1E7D;0076 0303; # (ṽ; ṽ; v◌̃; ṽ; v◌̃; ) LATIN SMALL LETTER V WITH TILDE +1E7E;1E7E;0056 0323;1E7E;0056 0323; # (Ṿ; Ṿ; V◌̣; Ṿ; V◌̣; ) LATIN CAPITAL LETTER V WITH DOT BELOW +1E7F;1E7F;0076 0323;1E7F;0076 0323; # (ṿ; ṿ; v◌̣; ṿ; v◌̣; ) LATIN SMALL LETTER V WITH DOT BELOW +1E80;1E80;0057 0300;1E80;0057 0300; # (Ẁ; Ẁ; W◌̀; Ẁ; W◌̀; ) LATIN CAPITAL LETTER W WITH GRAVE +1E81;1E81;0077 0300;1E81;0077 0300; # (ẁ; ẁ; w◌̀; ẁ; w◌̀; ) LATIN SMALL LETTER W WITH GRAVE +1E82;1E82;0057 0301;1E82;0057 0301; # (Ẃ; Ẃ; W◌́; Ẃ; W◌́; ) LATIN CAPITAL LETTER W WITH ACUTE +1E83;1E83;0077 0301;1E83;0077 0301; # (ẃ; ẃ; w◌́; ẃ; w◌́; ) LATIN SMALL LETTER W WITH ACUTE +1E84;1E84;0057 0308;1E84;0057 0308; # (Ẅ; Ẅ; W◌̈; Ẅ; W◌̈; ) LATIN CAPITAL LETTER W WITH DIAERESIS +1E85;1E85;0077 0308;1E85;0077 0308; # (ẅ; ẅ; w◌̈; ẅ; w◌̈; ) LATIN SMALL LETTER W WITH DIAERESIS +1E86;1E86;0057 0307;1E86;0057 0307; # (Ẇ; Ẇ; W◌̇; Ẇ; W◌̇; ) LATIN CAPITAL LETTER W WITH DOT ABOVE +1E87;1E87;0077 0307;1E87;0077 0307; # (ẇ; ẇ; w◌̇; ẇ; w◌̇; ) LATIN SMALL LETTER W WITH DOT ABOVE +1E88;1E88;0057 0323;1E88;0057 0323; # (Ẉ; Ẉ; W◌̣; Ẉ; W◌̣; ) LATIN CAPITAL LETTER W WITH DOT BELOW +1E89;1E89;0077 0323;1E89;0077 0323; # (ẉ; ẉ; w◌̣; ẉ; w◌̣; ) LATIN SMALL LETTER W WITH DOT BELOW +1E8A;1E8A;0058 0307;1E8A;0058 0307; # (Ẋ; Ẋ; X◌̇; Ẋ; X◌̇; ) LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8B;1E8B;0078 0307;1E8B;0078 0307; # (ẋ; ẋ; x◌̇; ẋ; x◌̇; ) LATIN SMALL LETTER X WITH DOT ABOVE +1E8C;1E8C;0058 0308;1E8C;0058 0308; # (Ẍ; Ẍ; X◌̈; Ẍ; X◌̈; ) LATIN CAPITAL LETTER X WITH DIAERESIS +1E8D;1E8D;0078 0308;1E8D;0078 0308; # (ẍ; ẍ; x◌̈; ẍ; x◌̈; ) LATIN SMALL LETTER X WITH DIAERESIS +1E8E;1E8E;0059 0307;1E8E;0059 0307; # (Ẏ; Ẏ; Y◌̇; Ẏ; Y◌̇; ) LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E8F;1E8F;0079 0307;1E8F;0079 0307; # (ẏ; ẏ; y◌̇; ẏ; y◌̇; ) LATIN SMALL LETTER Y WITH DOT ABOVE +1E90;1E90;005A 0302;1E90;005A 0302; # (Ẑ; Ẑ; Z◌̂; Ẑ; Z◌̂; ) LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E91;1E91;007A 0302;1E91;007A 0302; # (ẑ; ẑ; z◌̂; ẑ; z◌̂; ) LATIN SMALL LETTER Z WITH CIRCUMFLEX +1E92;1E92;005A 0323;1E92;005A 0323; # (Ẓ; Ẓ; Z◌̣; Ẓ; Z◌̣; ) LATIN CAPITAL LETTER Z WITH DOT BELOW +1E93;1E93;007A 0323;1E93;007A 0323; # (ẓ; ẓ; z◌̣; ẓ; z◌̣; ) LATIN SMALL LETTER Z WITH DOT BELOW +1E94;1E94;005A 0331;1E94;005A 0331; # (Ẕ; Ẕ; Z◌̱; Ẕ; Z◌̱; ) LATIN CAPITAL LETTER Z WITH LINE BELOW +1E95;1E95;007A 0331;1E95;007A 0331; # (ẕ; ẕ; z◌̱; ẕ; z◌̱; ) LATIN SMALL LETTER Z WITH LINE BELOW +1E96;1E96;0068 0331;1E96;0068 0331; # (ẖ; ẖ; h◌̱; ẖ; h◌̱; ) LATIN SMALL LETTER H WITH LINE BELOW +1E97;1E97;0074 0308;1E97;0074 0308; # (ẗ; ẗ; t◌̈; ẗ; t◌̈; ) LATIN SMALL LETTER T WITH DIAERESIS +1E98;1E98;0077 030A;1E98;0077 030A; # (ẘ; ẘ; w◌̊; ẘ; w◌̊; ) LATIN SMALL LETTER W WITH RING ABOVE +1E99;1E99;0079 030A;1E99;0079 030A; # (ẙ; ẙ; y◌̊; ẙ; y◌̊; ) LATIN SMALL LETTER Y WITH RING ABOVE +1E9A;1E9A;1E9A;0061 02BE;0061 02BE; # (ẚ; ẚ; ẚ; aʾ; aʾ; ) LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B;1E9B;017F 0307;1E61;0073 0307; # (ẛ; ẛ; ſ◌̇; ṡ; s◌̇; ) LATIN SMALL LETTER LONG S WITH DOT ABOVE +1EA0;1EA0;0041 0323;1EA0;0041 0323; # (Ạ; Ạ; A◌̣; Ạ; A◌̣; ) LATIN CAPITAL LETTER A WITH DOT BELOW +1EA1;1EA1;0061 0323;1EA1;0061 0323; # (ạ; ạ; a◌̣; ạ; a◌̣; ) LATIN SMALL LETTER A WITH DOT BELOW +1EA2;1EA2;0041 0309;1EA2;0041 0309; # (Ả; Ả; A◌̉; Ả; A◌̉; ) LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA3;1EA3;0061 0309;1EA3;0061 0309; # (ả; ả; a◌̉; ả; a◌̉; ) LATIN SMALL LETTER A WITH HOOK ABOVE +1EA4;1EA4;0041 0302 0301;1EA4;0041 0302 0301; # (Ấ; Ấ; A◌̂◌́; Ấ; A◌̂◌́; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA5;1EA5;0061 0302 0301;1EA5;0061 0302 0301; # (ấ; ấ; a◌̂◌́; ấ; a◌̂◌́; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6;1EA6;0041 0302 0300;1EA6;0041 0302 0300; # (Ầ; Ầ; A◌̂◌̀; Ầ; A◌̂◌̀; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA7;1EA7;0061 0302 0300;1EA7;0061 0302 0300; # (ầ; ầ; a◌̂◌̀; ầ; a◌̂◌̀; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8;1EA8;0041 0302 0309;1EA8;0041 0302 0309; # (Ẩ; Ẩ; A◌̂◌̉; Ẩ; A◌̂◌̉; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EA9;1EA9;0061 0302 0309;1EA9;0061 0302 0309; # (ẩ; ẩ; a◌̂◌̉; ẩ; a◌̂◌̉; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA;1EAA;0041 0302 0303;1EAA;0041 0302 0303; # (Ẫ; Ẫ; A◌̂◌̃; Ẫ; A◌̂◌̃; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAB;1EAB;0061 0302 0303;1EAB;0061 0302 0303; # (ẫ; ẫ; a◌̂◌̃; ẫ; a◌̂◌̃; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC;1EAC;0041 0323 0302;1EAC;0041 0323 0302; # (Ậ; Ậ; A◌̣◌̂; Ậ; A◌̣◌̂; ) LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAD;1EAD;0061 0323 0302;1EAD;0061 0323 0302; # (ậ; ậ; a◌̣◌̂; ậ; a◌̣◌̂; ) LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE;1EAE;0041 0306 0301;1EAE;0041 0306 0301; # (Ắ; Ắ; A◌̆◌́; Ắ; A◌̆◌́; ) LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EAF;1EAF;0061 0306 0301;1EAF;0061 0306 0301; # (ắ; ắ; a◌̆◌́; ắ; a◌̆◌́; ) LATIN SMALL LETTER A WITH BREVE AND ACUTE +1EB0;1EB0;0041 0306 0300;1EB0;0041 0306 0300; # (Ằ; Ằ; A◌̆◌̀; Ằ; A◌̆◌̀; ) LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB1;1EB1;0061 0306 0300;1EB1;0061 0306 0300; # (ằ; ằ; a◌̆◌̀; ằ; a◌̆◌̀; ) LATIN SMALL LETTER A WITH BREVE AND GRAVE +1EB2;1EB2;0041 0306 0309;1EB2;0041 0306 0309; # (Ẳ; Ẳ; A◌̆◌̉; Ẳ; A◌̆◌̉; ) LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB3;1EB3;0061 0306 0309;1EB3;0061 0306 0309; # (ẳ; ẳ; a◌̆◌̉; ẳ; a◌̆◌̉; ) LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE +1EB4;1EB4;0041 0306 0303;1EB4;0041 0306 0303; # (Ẵ; Ẵ; A◌̆◌̃; Ẵ; A◌̆◌̃; ) LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB5;1EB5;0061 0306 0303;1EB5;0061 0306 0303; # (ẵ; ẵ; a◌̆◌̃; ẵ; a◌̆◌̃; ) LATIN SMALL LETTER A WITH BREVE AND TILDE +1EB6;1EB6;0041 0323 0306;1EB6;0041 0323 0306; # (Ặ; Ặ; A◌̣◌̆; Ặ; A◌̣◌̆; ) LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB7;1EB7;0061 0323 0306;1EB7;0061 0323 0306; # (ặ; ặ; a◌̣◌̆; ặ; a◌̣◌̆; ) LATIN SMALL LETTER A WITH BREVE AND DOT BELOW +1EB8;1EB8;0045 0323;1EB8;0045 0323; # (Ẹ; Ẹ; E◌̣; Ẹ; E◌̣; ) LATIN CAPITAL LETTER E WITH DOT BELOW +1EB9;1EB9;0065 0323;1EB9;0065 0323; # (ẹ; ẹ; e◌̣; ẹ; e◌̣; ) LATIN SMALL LETTER E WITH DOT BELOW +1EBA;1EBA;0045 0309;1EBA;0045 0309; # (Ẻ; Ẻ; E◌̉; Ẻ; E◌̉; ) LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBB;1EBB;0065 0309;1EBB;0065 0309; # (ẻ; ẻ; e◌̉; ẻ; e◌̉; ) LATIN SMALL LETTER E WITH HOOK ABOVE +1EBC;1EBC;0045 0303;1EBC;0045 0303; # (Ẽ; Ẽ; E◌̃; Ẽ; E◌̃; ) LATIN CAPITAL LETTER E WITH TILDE +1EBD;1EBD;0065 0303;1EBD;0065 0303; # (ẽ; ẽ; e◌̃; ẽ; e◌̃; ) LATIN SMALL LETTER E WITH TILDE +1EBE;1EBE;0045 0302 0301;1EBE;0045 0302 0301; # (Ế; Ế; E◌̂◌́; Ế; E◌̂◌́; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EBF;1EBF;0065 0302 0301;1EBF;0065 0302 0301; # (ế; ế; e◌̂◌́; ế; e◌̂◌́; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0;1EC0;0045 0302 0300;1EC0;0045 0302 0300; # (Ề; Ề; E◌̂◌̀; Ề; E◌̂◌̀; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC1;1EC1;0065 0302 0300;1EC1;0065 0302 0300; # (ề; ề; e◌̂◌̀; ề; e◌̂◌̀; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2;1EC2;0045 0302 0309;1EC2;0045 0302 0309; # (Ể; Ể; E◌̂◌̉; Ể; E◌̂◌̉; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC3;1EC3;0065 0302 0309;1EC3;0065 0302 0309; # (ể; ể; e◌̂◌̉; ể; e◌̂◌̉; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4;1EC4;0045 0302 0303;1EC4;0045 0302 0303; # (Ễ; Ễ; E◌̂◌̃; Ễ; E◌̂◌̃; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC5;1EC5;0065 0302 0303;1EC5;0065 0302 0303; # (ễ; ễ; e◌̂◌̃; ễ; e◌̂◌̃; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6;1EC6;0045 0323 0302;1EC6;0045 0323 0302; # (Ệ; Ệ; E◌̣◌̂; Ệ; E◌̣◌̂; ) LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC7;1EC7;0065 0323 0302;1EC7;0065 0323 0302; # (ệ; ệ; e◌̣◌̂; ệ; e◌̣◌̂; ) LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8;1EC8;0049 0309;1EC8;0049 0309; # (Ỉ; Ỉ; I◌̉; Ỉ; I◌̉; ) LATIN CAPITAL LETTER I WITH HOOK ABOVE +1EC9;1EC9;0069 0309;1EC9;0069 0309; # (ỉ; ỉ; i◌̉; ỉ; i◌̉; ) LATIN SMALL LETTER I WITH HOOK ABOVE +1ECA;1ECA;0049 0323;1ECA;0049 0323; # (Ị; Ị; I◌̣; Ị; I◌̣; ) LATIN CAPITAL LETTER I WITH DOT BELOW +1ECB;1ECB;0069 0323;1ECB;0069 0323; # (ị; ị; i◌̣; ị; i◌̣; ) LATIN SMALL LETTER I WITH DOT BELOW +1ECC;1ECC;004F 0323;1ECC;004F 0323; # (Ọ; Ọ; O◌̣; Ọ; O◌̣; ) LATIN CAPITAL LETTER O WITH DOT BELOW +1ECD;1ECD;006F 0323;1ECD;006F 0323; # (ọ; ọ; o◌̣; ọ; o◌̣; ) LATIN SMALL LETTER O WITH DOT BELOW +1ECE;1ECE;004F 0309;1ECE;004F 0309; # (Ỏ; Ỏ; O◌̉; Ỏ; O◌̉; ) LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ECF;1ECF;006F 0309;1ECF;006F 0309; # (ỏ; ỏ; o◌̉; ỏ; o◌̉; ) LATIN SMALL LETTER O WITH HOOK ABOVE +1ED0;1ED0;004F 0302 0301;1ED0;004F 0302 0301; # (Ố; Ố; O◌̂◌́; Ố; O◌̂◌́; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED1;1ED1;006F 0302 0301;1ED1;006F 0302 0301; # (ố; ố; o◌̂◌́; ố; o◌̂◌́; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2;1ED2;004F 0302 0300;1ED2;004F 0302 0300; # (Ồ; Ồ; O◌̂◌̀; Ồ; O◌̂◌̀; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED3;1ED3;006F 0302 0300;1ED3;006F 0302 0300; # (ồ; ồ; o◌̂◌̀; ồ; o◌̂◌̀; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4;1ED4;004F 0302 0309;1ED4;004F 0302 0309; # (Ổ; Ổ; O◌̂◌̉; Ổ; O◌̂◌̉; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED5;1ED5;006F 0302 0309;1ED5;006F 0302 0309; # (ổ; ổ; o◌̂◌̉; ổ; o◌̂◌̉; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6;1ED6;004F 0302 0303;1ED6;004F 0302 0303; # (Ỗ; Ỗ; O◌̂◌̃; Ỗ; O◌̂◌̃; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED7;1ED7;006F 0302 0303;1ED7;006F 0302 0303; # (ỗ; ỗ; o◌̂◌̃; ỗ; o◌̂◌̃; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8;1ED8;004F 0323 0302;1ED8;004F 0323 0302; # (Ộ; Ộ; O◌̣◌̂; Ộ; O◌̣◌̂; ) LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1ED9;1ED9;006F 0323 0302;1ED9;006F 0323 0302; # (ộ; ộ; o◌̣◌̂; ộ; o◌̣◌̂; ) LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA;1EDA;004F 031B 0301;1EDA;004F 031B 0301; # (Ớ; Ớ; O◌̛◌́; Ớ; O◌̛◌́; ) LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDB;1EDB;006F 031B 0301;1EDB;006F 031B 0301; # (ớ; ớ; o◌̛◌́; ớ; o◌̛◌́; ) LATIN SMALL LETTER O WITH HORN AND ACUTE +1EDC;1EDC;004F 031B 0300;1EDC;004F 031B 0300; # (Ờ; Ờ; O◌̛◌̀; Ờ; O◌̛◌̀; ) LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDD;1EDD;006F 031B 0300;1EDD;006F 031B 0300; # (ờ; ờ; o◌̛◌̀; ờ; o◌̛◌̀; ) LATIN SMALL LETTER O WITH HORN AND GRAVE +1EDE;1EDE;004F 031B 0309;1EDE;004F 031B 0309; # (Ở; Ở; O◌̛◌̉; Ở; O◌̛◌̉; ) LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EDF;1EDF;006F 031B 0309;1EDF;006F 031B 0309; # (ở; ở; o◌̛◌̉; ở; o◌̛◌̉; ) LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE +1EE0;1EE0;004F 031B 0303;1EE0;004F 031B 0303; # (Ỡ; Ỡ; O◌̛◌̃; Ỡ; O◌̛◌̃; ) LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE1;1EE1;006F 031B 0303;1EE1;006F 031B 0303; # (ỡ; ỡ; o◌̛◌̃; ỡ; o◌̛◌̃; ) LATIN SMALL LETTER O WITH HORN AND TILDE +1EE2;1EE2;004F 031B 0323;1EE2;004F 031B 0323; # (Ợ; Ợ; O◌̛◌̣; Ợ; O◌̛◌̣; ) LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE3;1EE3;006F 031B 0323;1EE3;006F 031B 0323; # (ợ; ợ; o◌̛◌̣; ợ; o◌̛◌̣; ) LATIN SMALL LETTER O WITH HORN AND DOT BELOW +1EE4;1EE4;0055 0323;1EE4;0055 0323; # (Ụ; Ụ; U◌̣; Ụ; U◌̣; ) LATIN CAPITAL LETTER U WITH DOT BELOW +1EE5;1EE5;0075 0323;1EE5;0075 0323; # (ụ; ụ; u◌̣; ụ; u◌̣; ) LATIN SMALL LETTER U WITH DOT BELOW +1EE6;1EE6;0055 0309;1EE6;0055 0309; # (Ủ; Ủ; U◌̉; Ủ; U◌̉; ) LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE7;1EE7;0075 0309;1EE7;0075 0309; # (ủ; ủ; u◌̉; ủ; u◌̉; ) LATIN SMALL LETTER U WITH HOOK ABOVE +1EE8;1EE8;0055 031B 0301;1EE8;0055 031B 0301; # (Ứ; Ứ; U◌̛◌́; Ứ; U◌̛◌́; ) LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EE9;1EE9;0075 031B 0301;1EE9;0075 031B 0301; # (ứ; ứ; u◌̛◌́; ứ; u◌̛◌́; ) LATIN SMALL LETTER U WITH HORN AND ACUTE +1EEA;1EEA;0055 031B 0300;1EEA;0055 031B 0300; # (Ừ; Ừ; U◌̛◌̀; Ừ; U◌̛◌̀; ) LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEB;1EEB;0075 031B 0300;1EEB;0075 031B 0300; # (ừ; ừ; u◌̛◌̀; ừ; u◌̛◌̀; ) LATIN SMALL LETTER U WITH HORN AND GRAVE +1EEC;1EEC;0055 031B 0309;1EEC;0055 031B 0309; # (Ử; Ử; U◌̛◌̉; Ử; U◌̛◌̉; ) LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EED;1EED;0075 031B 0309;1EED;0075 031B 0309; # (ử; ử; u◌̛◌̉; ử; u◌̛◌̉; ) LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE +1EEE;1EEE;0055 031B 0303;1EEE;0055 031B 0303; # (Ữ; Ữ; U◌̛◌̃; Ữ; U◌̛◌̃; ) LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EEF;1EEF;0075 031B 0303;1EEF;0075 031B 0303; # (ữ; ữ; u◌̛◌̃; ữ; u◌̛◌̃; ) LATIN SMALL LETTER U WITH HORN AND TILDE +1EF0;1EF0;0055 031B 0323;1EF0;0055 031B 0323; # (Ự; Ự; U◌̛◌̣; Ự; U◌̛◌̣; ) LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF1;1EF1;0075 031B 0323;1EF1;0075 031B 0323; # (ự; ự; u◌̛◌̣; ự; u◌̛◌̣; ) LATIN SMALL LETTER U WITH HORN AND DOT BELOW +1EF2;1EF2;0059 0300;1EF2;0059 0300; # (Ỳ; Ỳ; Y◌̀; Ỳ; Y◌̀; ) LATIN CAPITAL LETTER Y WITH GRAVE +1EF3;1EF3;0079 0300;1EF3;0079 0300; # (ỳ; ỳ; y◌̀; ỳ; y◌̀; ) LATIN SMALL LETTER Y WITH GRAVE +1EF4;1EF4;0059 0323;1EF4;0059 0323; # (Ỵ; Ỵ; Y◌̣; Ỵ; Y◌̣; ) LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF5;1EF5;0079 0323;1EF5;0079 0323; # (ỵ; ỵ; y◌̣; ỵ; y◌̣; ) LATIN SMALL LETTER Y WITH DOT BELOW +1EF6;1EF6;0059 0309;1EF6;0059 0309; # (Ỷ; Ỷ; Y◌̉; Ỷ; Y◌̉; ) LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF7;1EF7;0079 0309;1EF7;0079 0309; # (ỷ; ỷ; y◌̉; ỷ; y◌̉; ) LATIN SMALL LETTER Y WITH HOOK ABOVE +1EF8;1EF8;0059 0303;1EF8;0059 0303; # (Ỹ; Ỹ; Y◌̃; Ỹ; Y◌̃; ) LATIN CAPITAL LETTER Y WITH TILDE +1EF9;1EF9;0079 0303;1EF9;0079 0303; # (ỹ; ỹ; y◌̃; ỹ; y◌̃; ) LATIN SMALL LETTER Y WITH TILDE +1F00;1F00;03B1 0313;1F00;03B1 0313; # (ἀ; ἀ; α◌̓; ἀ; α◌̓; ) GREEK SMALL LETTER ALPHA WITH PSILI +1F01;1F01;03B1 0314;1F01;03B1 0314; # (ἁ; ἁ; α◌̔; ἁ; α◌̔; ) GREEK SMALL LETTER ALPHA WITH DASIA +1F02;1F02;03B1 0313 0300;1F02;03B1 0313 0300; # (ἂ; ἂ; α◌̓◌̀; ἂ; α◌̓◌̀; ) GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA +1F03;1F03;03B1 0314 0300;1F03;03B1 0314 0300; # (ἃ; ἃ; α◌̔◌̀; ἃ; α◌̔◌̀; ) GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA +1F04;1F04;03B1 0313 0301;1F04;03B1 0313 0301; # (ἄ; ἄ; α◌̓◌́; ἄ; α◌̓◌́; ) GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA +1F05;1F05;03B1 0314 0301;1F05;03B1 0314 0301; # (ἅ; ἅ; α◌̔◌́; ἅ; α◌̔◌́; ) GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA +1F06;1F06;03B1 0313 0342;1F06;03B1 0313 0342; # (ἆ; ἆ; α◌̓◌͂; ἆ; α◌̓◌͂; ) GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F07;1F07;03B1 0314 0342;1F07;03B1 0314 0342; # (ἇ; ἇ; α◌̔◌͂; ἇ; α◌̔◌͂; ) GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F08;1F08;0391 0313;1F08;0391 0313; # (Ἀ; Ἀ; Α◌̓; Ἀ; Α◌̓; ) GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09;1F09;0391 0314;1F09;0391 0314; # (Ἁ; Ἁ; Α◌̔; Ἁ; Α◌̔; ) GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A;1F0A;0391 0313 0300;1F0A;0391 0313 0300; # (Ἂ; Ἂ; Α◌̓◌̀; Ἂ; Α◌̓◌̀; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B;1F0B;0391 0314 0300;1F0B;0391 0314 0300; # (Ἃ; Ἃ; Α◌̔◌̀; Ἃ; Α◌̔◌̀; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C;1F0C;0391 0313 0301;1F0C;0391 0313 0301; # (Ἄ; Ἄ; Α◌̓◌́; Ἄ; Α◌̓◌́; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D;1F0D;0391 0314 0301;1F0D;0391 0314 0301; # (Ἅ; Ἅ; Α◌̔◌́; Ἅ; Α◌̔◌́; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E;1F0E;0391 0313 0342;1F0E;0391 0313 0342; # (Ἆ; Ἆ; Α◌̓◌͂; Ἆ; Α◌̓◌͂; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F;1F0F;0391 0314 0342;1F0F;0391 0314 0342; # (Ἇ; Ἇ; Α◌̔◌͂; Ἇ; Α◌̔◌͂; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F10;1F10;03B5 0313;1F10;03B5 0313; # (ἐ; ἐ; ε◌̓; ἐ; ε◌̓; ) GREEK SMALL LETTER EPSILON WITH PSILI +1F11;1F11;03B5 0314;1F11;03B5 0314; # (ἑ; ἑ; ε◌̔; ἑ; ε◌̔; ) GREEK SMALL LETTER EPSILON WITH DASIA +1F12;1F12;03B5 0313 0300;1F12;03B5 0313 0300; # (ἒ; ἒ; ε◌̓◌̀; ἒ; ε◌̓◌̀; ) GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA +1F13;1F13;03B5 0314 0300;1F13;03B5 0314 0300; # (ἓ; ἓ; ε◌̔◌̀; ἓ; ε◌̔◌̀; ) GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA +1F14;1F14;03B5 0313 0301;1F14;03B5 0313 0301; # (ἔ; ἔ; ε◌̓◌́; ἔ; ε◌̓◌́; ) GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA +1F15;1F15;03B5 0314 0301;1F15;03B5 0314 0301; # (ἕ; ἕ; ε◌̔◌́; ἕ; ε◌̔◌́; ) GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18;1F18;0395 0313;1F18;0395 0313; # (Ἐ; Ἐ; Ε◌̓; Ἐ; Ε◌̓; ) GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19;1F19;0395 0314;1F19;0395 0314; # (Ἑ; Ἑ; Ε◌̔; Ἑ; Ε◌̔; ) GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A;1F1A;0395 0313 0300;1F1A;0395 0313 0300; # (Ἒ; Ἒ; Ε◌̓◌̀; Ἒ; Ε◌̓◌̀; ) GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B;1F1B;0395 0314 0300;1F1B;0395 0314 0300; # (Ἓ; Ἓ; Ε◌̔◌̀; Ἓ; Ε◌̔◌̀; ) GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C;1F1C;0395 0313 0301;1F1C;0395 0313 0301; # (Ἔ; Ἔ; Ε◌̓◌́; Ἔ; Ε◌̓◌́; ) GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D;1F1D;0395 0314 0301;1F1D;0395 0314 0301; # (Ἕ; Ἕ; Ε◌̔◌́; Ἕ; Ε◌̔◌́; ) GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20;1F20;03B7 0313;1F20;03B7 0313; # (ἠ; ἠ; η◌̓; ἠ; η◌̓; ) GREEK SMALL LETTER ETA WITH PSILI +1F21;1F21;03B7 0314;1F21;03B7 0314; # (ἡ; ἡ; η◌̔; ἡ; η◌̔; ) GREEK SMALL LETTER ETA WITH DASIA +1F22;1F22;03B7 0313 0300;1F22;03B7 0313 0300; # (ἢ; ἢ; η◌̓◌̀; ἢ; η◌̓◌̀; ) GREEK SMALL LETTER ETA WITH PSILI AND VARIA +1F23;1F23;03B7 0314 0300;1F23;03B7 0314 0300; # (ἣ; ἣ; η◌̔◌̀; ἣ; η◌̔◌̀; ) GREEK SMALL LETTER ETA WITH DASIA AND VARIA +1F24;1F24;03B7 0313 0301;1F24;03B7 0313 0301; # (ἤ; ἤ; η◌̓◌́; ἤ; η◌̓◌́; ) GREEK SMALL LETTER ETA WITH PSILI AND OXIA +1F25;1F25;03B7 0314 0301;1F25;03B7 0314 0301; # (ἥ; ἥ; η◌̔◌́; ἥ; η◌̔◌́; ) GREEK SMALL LETTER ETA WITH DASIA AND OXIA +1F26;1F26;03B7 0313 0342;1F26;03B7 0313 0342; # (ἦ; ἦ; η◌̓◌͂; ἦ; η◌̓◌͂; ) GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI +1F27;1F27;03B7 0314 0342;1F27;03B7 0314 0342; # (ἧ; ἧ; η◌̔◌͂; ἧ; η◌̔◌͂; ) GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI +1F28;1F28;0397 0313;1F28;0397 0313; # (Ἠ; Ἠ; Η◌̓; Ἠ; Η◌̓; ) GREEK CAPITAL LETTER ETA WITH PSILI +1F29;1F29;0397 0314;1F29;0397 0314; # (Ἡ; Ἡ; Η◌̔; Ἡ; Η◌̔; ) GREEK CAPITAL LETTER ETA WITH DASIA +1F2A;1F2A;0397 0313 0300;1F2A;0397 0313 0300; # (Ἢ; Ἢ; Η◌̓◌̀; Ἢ; Η◌̓◌̀; ) GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B;1F2B;0397 0314 0300;1F2B;0397 0314 0300; # (Ἣ; Ἣ; Η◌̔◌̀; Ἣ; Η◌̔◌̀; ) GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C;1F2C;0397 0313 0301;1F2C;0397 0313 0301; # (Ἤ; Ἤ; Η◌̓◌́; Ἤ; Η◌̓◌́; ) GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D;1F2D;0397 0314 0301;1F2D;0397 0314 0301; # (Ἥ; Ἥ; Η◌̔◌́; Ἥ; Η◌̔◌́; ) GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E;1F2E;0397 0313 0342;1F2E;0397 0313 0342; # (Ἦ; Ἦ; Η◌̓◌͂; Ἦ; Η◌̓◌͂; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F;1F2F;0397 0314 0342;1F2F;0397 0314 0342; # (Ἧ; Ἧ; Η◌̔◌͂; Ἧ; Η◌̔◌͂; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F30;1F30;03B9 0313;1F30;03B9 0313; # (ἰ; ἰ; ι◌̓; ἰ; ι◌̓; ) GREEK SMALL LETTER IOTA WITH PSILI +1F31;1F31;03B9 0314;1F31;03B9 0314; # (ἱ; ἱ; ι◌̔; ἱ; ι◌̔; ) GREEK SMALL LETTER IOTA WITH DASIA +1F32;1F32;03B9 0313 0300;1F32;03B9 0313 0300; # (ἲ; ἲ; ι◌̓◌̀; ἲ; ι◌̓◌̀; ) GREEK SMALL LETTER IOTA WITH PSILI AND VARIA +1F33;1F33;03B9 0314 0300;1F33;03B9 0314 0300; # (ἳ; ἳ; ι◌̔◌̀; ἳ; ι◌̔◌̀; ) GREEK SMALL LETTER IOTA WITH DASIA AND VARIA +1F34;1F34;03B9 0313 0301;1F34;03B9 0313 0301; # (ἴ; ἴ; ι◌̓◌́; ἴ; ι◌̓◌́; ) GREEK SMALL LETTER IOTA WITH PSILI AND OXIA +1F35;1F35;03B9 0314 0301;1F35;03B9 0314 0301; # (ἵ; ἵ; ι◌̔◌́; ἵ; ι◌̔◌́; ) GREEK SMALL LETTER IOTA WITH DASIA AND OXIA +1F36;1F36;03B9 0313 0342;1F36;03B9 0313 0342; # (ἶ; ἶ; ι◌̓◌͂; ἶ; ι◌̓◌͂; ) GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI +1F37;1F37;03B9 0314 0342;1F37;03B9 0314 0342; # (ἷ; ἷ; ι◌̔◌͂; ἷ; ι◌̔◌͂; ) GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI +1F38;1F38;0399 0313;1F38;0399 0313; # (Ἰ; Ἰ; Ι◌̓; Ἰ; Ι◌̓; ) GREEK CAPITAL LETTER IOTA WITH PSILI +1F39;1F39;0399 0314;1F39;0399 0314; # (Ἱ; Ἱ; Ι◌̔; Ἱ; Ι◌̔; ) GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A;1F3A;0399 0313 0300;1F3A;0399 0313 0300; # (Ἲ; Ἲ; Ι◌̓◌̀; Ἲ; Ι◌̓◌̀; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B;1F3B;0399 0314 0300;1F3B;0399 0314 0300; # (Ἳ; Ἳ; Ι◌̔◌̀; Ἳ; Ι◌̔◌̀; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C;1F3C;0399 0313 0301;1F3C;0399 0313 0301; # (Ἴ; Ἴ; Ι◌̓◌́; Ἴ; Ι◌̓◌́; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D;1F3D;0399 0314 0301;1F3D;0399 0314 0301; # (Ἵ; Ἵ; Ι◌̔◌́; Ἵ; Ι◌̔◌́; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E;1F3E;0399 0313 0342;1F3E;0399 0313 0342; # (Ἶ; Ἶ; Ι◌̓◌͂; Ἶ; Ι◌̓◌͂; ) GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F;1F3F;0399 0314 0342;1F3F;0399 0314 0342; # (Ἷ; Ἷ; Ι◌̔◌͂; Ἷ; Ι◌̔◌͂; ) GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F40;1F40;03BF 0313;1F40;03BF 0313; # (ὀ; ὀ; ο◌̓; ὀ; ο◌̓; ) GREEK SMALL LETTER OMICRON WITH PSILI +1F41;1F41;03BF 0314;1F41;03BF 0314; # (ὁ; ὁ; ο◌̔; ὁ; ο◌̔; ) GREEK SMALL LETTER OMICRON WITH DASIA +1F42;1F42;03BF 0313 0300;1F42;03BF 0313 0300; # (ὂ; ὂ; ο◌̓◌̀; ὂ; ο◌̓◌̀; ) GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA +1F43;1F43;03BF 0314 0300;1F43;03BF 0314 0300; # (ὃ; ὃ; ο◌̔◌̀; ὃ; ο◌̔◌̀; ) GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA +1F44;1F44;03BF 0313 0301;1F44;03BF 0313 0301; # (ὄ; ὄ; ο◌̓◌́; ὄ; ο◌̓◌́; ) GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA +1F45;1F45;03BF 0314 0301;1F45;03BF 0314 0301; # (ὅ; ὅ; ο◌̔◌́; ὅ; ο◌̔◌́; ) GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48;1F48;039F 0313;1F48;039F 0313; # (Ὀ; Ὀ; Ο◌̓; Ὀ; Ο◌̓; ) GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49;1F49;039F 0314;1F49;039F 0314; # (Ὁ; Ὁ; Ο◌̔; Ὁ; Ο◌̔; ) GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A;1F4A;039F 0313 0300;1F4A;039F 0313 0300; # (Ὂ; Ὂ; Ο◌̓◌̀; Ὂ; Ο◌̓◌̀; ) GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B;1F4B;039F 0314 0300;1F4B;039F 0314 0300; # (Ὃ; Ὃ; Ο◌̔◌̀; Ὃ; Ο◌̔◌̀; ) GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C;1F4C;039F 0313 0301;1F4C;039F 0313 0301; # (Ὄ; Ὄ; Ο◌̓◌́; Ὄ; Ο◌̓◌́; ) GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D;1F4D;039F 0314 0301;1F4D;039F 0314 0301; # (Ὅ; Ὅ; Ο◌̔◌́; Ὅ; Ο◌̔◌́; ) GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50;1F50;03C5 0313;1F50;03C5 0313; # (ὐ; ὐ; υ◌̓; ὐ; υ◌̓; ) GREEK SMALL LETTER UPSILON WITH PSILI +1F51;1F51;03C5 0314;1F51;03C5 0314; # (ὑ; ὑ; υ◌̔; ὑ; υ◌̔; ) GREEK SMALL LETTER UPSILON WITH DASIA +1F52;1F52;03C5 0313 0300;1F52;03C5 0313 0300; # (ὒ; ὒ; υ◌̓◌̀; ὒ; υ◌̓◌̀; ) GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F53;1F53;03C5 0314 0300;1F53;03C5 0314 0300; # (ὓ; ὓ; υ◌̔◌̀; ὓ; υ◌̔◌̀; ) GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA +1F54;1F54;03C5 0313 0301;1F54;03C5 0313 0301; # (ὔ; ὔ; υ◌̓◌́; ὔ; υ◌̓◌́; ) GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F55;1F55;03C5 0314 0301;1F55;03C5 0314 0301; # (ὕ; ὕ; υ◌̔◌́; ὕ; υ◌̔◌́; ) GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA +1F56;1F56;03C5 0313 0342;1F56;03C5 0313 0342; # (ὖ; ὖ; υ◌̓◌͂; ὖ; υ◌̓◌͂; ) GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F57;1F57;03C5 0314 0342;1F57;03C5 0314 0342; # (ὗ; ὗ; υ◌̔◌͂; ὗ; υ◌̔◌͂; ) GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59;1F59;03A5 0314;1F59;03A5 0314; # (Ὑ; Ὑ; Υ◌̔; Ὑ; Υ◌̔; ) GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B;1F5B;03A5 0314 0300;1F5B;03A5 0314 0300; # (Ὓ; Ὓ; Υ◌̔◌̀; Ὓ; Υ◌̔◌̀; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D;1F5D;03A5 0314 0301;1F5D;03A5 0314 0301; # (Ὕ; Ὕ; Υ◌̔◌́; Ὕ; Υ◌̔◌́; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F;1F5F;03A5 0314 0342;1F5F;03A5 0314 0342; # (Ὗ; Ὗ; Υ◌̔◌͂; Ὗ; Υ◌̔◌͂; ) GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F60;1F60;03C9 0313;1F60;03C9 0313; # (ὠ; ὠ; ω◌̓; ὠ; ω◌̓; ) GREEK SMALL LETTER OMEGA WITH PSILI +1F61;1F61;03C9 0314;1F61;03C9 0314; # (ὡ; ὡ; ω◌̔; ὡ; ω◌̔; ) GREEK SMALL LETTER OMEGA WITH DASIA +1F62;1F62;03C9 0313 0300;1F62;03C9 0313 0300; # (ὢ; ὢ; ω◌̓◌̀; ὢ; ω◌̓◌̀; ) GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA +1F63;1F63;03C9 0314 0300;1F63;03C9 0314 0300; # (ὣ; ὣ; ω◌̔◌̀; ὣ; ω◌̔◌̀; ) GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA +1F64;1F64;03C9 0313 0301;1F64;03C9 0313 0301; # (ὤ; ὤ; ω◌̓◌́; ὤ; ω◌̓◌́; ) GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA +1F65;1F65;03C9 0314 0301;1F65;03C9 0314 0301; # (ὥ; ὥ; ω◌̔◌́; ὥ; ω◌̔◌́; ) GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA +1F66;1F66;03C9 0313 0342;1F66;03C9 0313 0342; # (ὦ; ὦ; ω◌̓◌͂; ὦ; ω◌̓◌͂; ) GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F67;1F67;03C9 0314 0342;1F67;03C9 0314 0342; # (ὧ; ὧ; ω◌̔◌͂; ὧ; ω◌̔◌͂; ) GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F68;1F68;03A9 0313;1F68;03A9 0313; # (Ὠ; Ὠ; Ω◌̓; Ὠ; Ω◌̓; ) GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69;1F69;03A9 0314;1F69;03A9 0314; # (Ὡ; Ὡ; Ω◌̔; Ὡ; Ω◌̔; ) GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A;1F6A;03A9 0313 0300;1F6A;03A9 0313 0300; # (Ὢ; Ὢ; Ω◌̓◌̀; Ὢ; Ω◌̓◌̀; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B;1F6B;03A9 0314 0300;1F6B;03A9 0314 0300; # (Ὣ; Ὣ; Ω◌̔◌̀; Ὣ; Ω◌̔◌̀; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C;1F6C;03A9 0313 0301;1F6C;03A9 0313 0301; # (Ὤ; Ὤ; Ω◌̓◌́; Ὤ; Ω◌̓◌́; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D;1F6D;03A9 0314 0301;1F6D;03A9 0314 0301; # (Ὥ; Ὥ; Ω◌̔◌́; Ὥ; Ω◌̔◌́; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E;1F6E;03A9 0313 0342;1F6E;03A9 0313 0342; # (Ὦ; Ὦ; Ω◌̓◌͂; Ὦ; Ω◌̓◌͂; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F;1F6F;03A9 0314 0342;1F6F;03A9 0314 0342; # (Ὧ; Ὧ; Ω◌̔◌͂; Ὧ; Ω◌̔◌͂; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F70;1F70;03B1 0300;1F70;03B1 0300; # (ὰ; ὰ; α◌̀; ὰ; α◌̀; ) GREEK SMALL LETTER ALPHA WITH VARIA +1F71;03AC;03B1 0301;03AC;03B1 0301; # (ά; ά; α◌́; ά; α◌́; ) GREEK SMALL LETTER ALPHA WITH OXIA +1F72;1F72;03B5 0300;1F72;03B5 0300; # (ὲ; ὲ; ε◌̀; ὲ; ε◌̀; ) GREEK SMALL LETTER EPSILON WITH VARIA +1F73;03AD;03B5 0301;03AD;03B5 0301; # (έ; έ; ε◌́; έ; ε◌́; ) GREEK SMALL LETTER EPSILON WITH OXIA +1F74;1F74;03B7 0300;1F74;03B7 0300; # (ὴ; ὴ; η◌̀; ὴ; η◌̀; ) GREEK SMALL LETTER ETA WITH VARIA +1F75;03AE;03B7 0301;03AE;03B7 0301; # (ή; ή; η◌́; ή; η◌́; ) GREEK SMALL LETTER ETA WITH OXIA +1F76;1F76;03B9 0300;1F76;03B9 0300; # (ὶ; ὶ; ι◌̀; ὶ; ι◌̀; ) GREEK SMALL LETTER IOTA WITH VARIA +1F77;03AF;03B9 0301;03AF;03B9 0301; # (ί; ί; ι◌́; ί; ι◌́; ) GREEK SMALL LETTER IOTA WITH OXIA +1F78;1F78;03BF 0300;1F78;03BF 0300; # (ὸ; ὸ; ο◌̀; ὸ; ο◌̀; ) GREEK SMALL LETTER OMICRON WITH VARIA +1F79;03CC;03BF 0301;03CC;03BF 0301; # (ό; ό; ο◌́; ό; ο◌́; ) GREEK SMALL LETTER OMICRON WITH OXIA +1F7A;1F7A;03C5 0300;1F7A;03C5 0300; # (ὺ; ὺ; υ◌̀; ὺ; υ◌̀; ) GREEK SMALL LETTER UPSILON WITH VARIA +1F7B;03CD;03C5 0301;03CD;03C5 0301; # (ύ; ύ; υ◌́; ύ; υ◌́; ) GREEK SMALL LETTER UPSILON WITH OXIA +1F7C;1F7C;03C9 0300;1F7C;03C9 0300; # (ὼ; ὼ; ω◌̀; ὼ; ω◌̀; ) GREEK SMALL LETTER OMEGA WITH VARIA +1F7D;03CE;03C9 0301;03CE;03C9 0301; # (ώ; ώ; ω◌́; ώ; ω◌́; ) GREEK SMALL LETTER OMEGA WITH OXIA +1F80;1F80;03B1 0313 0345;1F80;03B1 0313 0345; # (ᾀ; ᾀ; α◌̓◌ͅ; ᾀ; α◌̓◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81;1F81;03B1 0314 0345;1F81;03B1 0314 0345; # (ᾁ; ᾁ; α◌̔◌ͅ; ᾁ; α◌̔◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82;1F82;03B1 0313 0300 0345;1F82;03B1 0313 0300 0345; # (ᾂ; ᾂ; α◌̓◌̀◌ͅ; ᾂ; α◌̓◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83;1F83;03B1 0314 0300 0345;1F83;03B1 0314 0300 0345; # (ᾃ; ᾃ; α◌̔◌̀◌ͅ; ᾃ; α◌̔◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84;1F84;03B1 0313 0301 0345;1F84;03B1 0313 0301 0345; # (ᾄ; ᾄ; α◌̓◌́◌ͅ; ᾄ; α◌̓◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85;1F85;03B1 0314 0301 0345;1F85;03B1 0314 0301 0345; # (ᾅ; ᾅ; α◌̔◌́◌ͅ; ᾅ; α◌̔◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86;1F86;03B1 0313 0342 0345;1F86;03B1 0313 0342 0345; # (ᾆ; ᾆ; α◌̓◌͂◌ͅ; ᾆ; α◌̓◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87;1F87;03B1 0314 0342 0345;1F87;03B1 0314 0342 0345; # (ᾇ; ᾇ; α◌̔◌͂◌ͅ; ᾇ; α◌̔◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88;1F88;0391 0313 0345;1F88;0391 0313 0345; # (ᾈ; ᾈ; Α◌̓◌ͅ; ᾈ; Α◌̓◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89;1F89;0391 0314 0345;1F89;0391 0314 0345; # (ᾉ; ᾉ; Α◌̔◌ͅ; ᾉ; Α◌̔◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A;1F8A;0391 0313 0300 0345;1F8A;0391 0313 0300 0345; # (ᾊ; ᾊ; Α◌̓◌̀◌ͅ; ᾊ; Α◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B;1F8B;0391 0314 0300 0345;1F8B;0391 0314 0300 0345; # (ᾋ; ᾋ; Α◌̔◌̀◌ͅ; ᾋ; Α◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C;1F8C;0391 0313 0301 0345;1F8C;0391 0313 0301 0345; # (ᾌ; ᾌ; Α◌̓◌́◌ͅ; ᾌ; Α◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D;1F8D;0391 0314 0301 0345;1F8D;0391 0314 0301 0345; # (ᾍ; ᾍ; Α◌̔◌́◌ͅ; ᾍ; Α◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E;1F8E;0391 0313 0342 0345;1F8E;0391 0313 0342 0345; # (ᾎ; ᾎ; Α◌̓◌͂◌ͅ; ᾎ; Α◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F;1F8F;0391 0314 0342 0345;1F8F;0391 0314 0342 0345; # (ᾏ; ᾏ; Α◌̔◌͂◌ͅ; ᾏ; Α◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90;1F90;03B7 0313 0345;1F90;03B7 0313 0345; # (ᾐ; ᾐ; η◌̓◌ͅ; ᾐ; η◌̓◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91;1F91;03B7 0314 0345;1F91;03B7 0314 0345; # (ᾑ; ᾑ; η◌̔◌ͅ; ᾑ; η◌̔◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92;1F92;03B7 0313 0300 0345;1F92;03B7 0313 0300 0345; # (ᾒ; ᾒ; η◌̓◌̀◌ͅ; ᾒ; η◌̓◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93;1F93;03B7 0314 0300 0345;1F93;03B7 0314 0300 0345; # (ᾓ; ᾓ; η◌̔◌̀◌ͅ; ᾓ; η◌̔◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94;1F94;03B7 0313 0301 0345;1F94;03B7 0313 0301 0345; # (ᾔ; ᾔ; η◌̓◌́◌ͅ; ᾔ; η◌̓◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95;1F95;03B7 0314 0301 0345;1F95;03B7 0314 0301 0345; # (ᾕ; ᾕ; η◌̔◌́◌ͅ; ᾕ; η◌̔◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96;1F96;03B7 0313 0342 0345;1F96;03B7 0313 0342 0345; # (ᾖ; ᾖ; η◌̓◌͂◌ͅ; ᾖ; η◌̓◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97;1F97;03B7 0314 0342 0345;1F97;03B7 0314 0342 0345; # (ᾗ; ᾗ; η◌̔◌͂◌ͅ; ᾗ; η◌̔◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98;1F98;0397 0313 0345;1F98;0397 0313 0345; # (ᾘ; ᾘ; Η◌̓◌ͅ; ᾘ; Η◌̓◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99;1F99;0397 0314 0345;1F99;0397 0314 0345; # (ᾙ; ᾙ; Η◌̔◌ͅ; ᾙ; Η◌̔◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A;1F9A;0397 0313 0300 0345;1F9A;0397 0313 0300 0345; # (ᾚ; ᾚ; Η◌̓◌̀◌ͅ; ᾚ; Η◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B;1F9B;0397 0314 0300 0345;1F9B;0397 0314 0300 0345; # (ᾛ; ᾛ; Η◌̔◌̀◌ͅ; ᾛ; Η◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C;1F9C;0397 0313 0301 0345;1F9C;0397 0313 0301 0345; # (ᾜ; ᾜ; Η◌̓◌́◌ͅ; ᾜ; Η◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D;1F9D;0397 0314 0301 0345;1F9D;0397 0314 0301 0345; # (ᾝ; ᾝ; Η◌̔◌́◌ͅ; ᾝ; Η◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E;1F9E;0397 0313 0342 0345;1F9E;0397 0313 0342 0345; # (ᾞ; ᾞ; Η◌̓◌͂◌ͅ; ᾞ; Η◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F;1F9F;0397 0314 0342 0345;1F9F;0397 0314 0342 0345; # (ᾟ; ᾟ; Η◌̔◌͂◌ͅ; ᾟ; Η◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0;1FA0;03C9 0313 0345;1FA0;03C9 0313 0345; # (ᾠ; ᾠ; ω◌̓◌ͅ; ᾠ; ω◌̓◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1;1FA1;03C9 0314 0345;1FA1;03C9 0314 0345; # (ᾡ; ᾡ; ω◌̔◌ͅ; ᾡ; ω◌̔◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2;1FA2;03C9 0313 0300 0345;1FA2;03C9 0313 0300 0345; # (ᾢ; ᾢ; ω◌̓◌̀◌ͅ; ᾢ; ω◌̓◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3;1FA3;03C9 0314 0300 0345;1FA3;03C9 0314 0300 0345; # (ᾣ; ᾣ; ω◌̔◌̀◌ͅ; ᾣ; ω◌̔◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4;1FA4;03C9 0313 0301 0345;1FA4;03C9 0313 0301 0345; # (ᾤ; ᾤ; ω◌̓◌́◌ͅ; ᾤ; ω◌̓◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5;1FA5;03C9 0314 0301 0345;1FA5;03C9 0314 0301 0345; # (ᾥ; ᾥ; ω◌̔◌́◌ͅ; ᾥ; ω◌̔◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6;1FA6;03C9 0313 0342 0345;1FA6;03C9 0313 0342 0345; # (ᾦ; ᾦ; ω◌̓◌͂◌ͅ; ᾦ; ω◌̓◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7;1FA7;03C9 0314 0342 0345;1FA7;03C9 0314 0342 0345; # (ᾧ; ᾧ; ω◌̔◌͂◌ͅ; ᾧ; ω◌̔◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8;1FA8;03A9 0313 0345;1FA8;03A9 0313 0345; # (ᾨ; ᾨ; Ω◌̓◌ͅ; ᾨ; Ω◌̓◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9;1FA9;03A9 0314 0345;1FA9;03A9 0314 0345; # (ᾩ; ᾩ; Ω◌̔◌ͅ; ᾩ; Ω◌̔◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA;1FAA;03A9 0313 0300 0345;1FAA;03A9 0313 0300 0345; # (ᾪ; ᾪ; Ω◌̓◌̀◌ͅ; ᾪ; Ω◌̓◌̀◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB;1FAB;03A9 0314 0300 0345;1FAB;03A9 0314 0300 0345; # (ᾫ; ᾫ; Ω◌̔◌̀◌ͅ; ᾫ; Ω◌̔◌̀◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC;1FAC;03A9 0313 0301 0345;1FAC;03A9 0313 0301 0345; # (ᾬ; ᾬ; Ω◌̓◌́◌ͅ; ᾬ; Ω◌̓◌́◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD;1FAD;03A9 0314 0301 0345;1FAD;03A9 0314 0301 0345; # (ᾭ; ᾭ; Ω◌̔◌́◌ͅ; ᾭ; Ω◌̔◌́◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE;1FAE;03A9 0313 0342 0345;1FAE;03A9 0313 0342 0345; # (ᾮ; ᾮ; Ω◌̓◌͂◌ͅ; ᾮ; Ω◌̓◌͂◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF;1FAF;03A9 0314 0342 0345;1FAF;03A9 0314 0342 0345; # (ᾯ; ᾯ; Ω◌̔◌͂◌ͅ; ᾯ; Ω◌̔◌͂◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB0;1FB0;03B1 0306;1FB0;03B1 0306; # (ᾰ; ᾰ; α◌̆; ᾰ; α◌̆; ) GREEK SMALL LETTER ALPHA WITH VRACHY +1FB1;1FB1;03B1 0304;1FB1;03B1 0304; # (ᾱ; ᾱ; α◌̄; ᾱ; α◌̄; ) GREEK SMALL LETTER ALPHA WITH MACRON +1FB2;1FB2;03B1 0300 0345;1FB2;03B1 0300 0345; # (ᾲ; ᾲ; α◌̀◌ͅ; ᾲ; α◌̀◌ͅ; ) GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3;1FB3;03B1 0345;1FB3;03B1 0345; # (ᾳ; ᾳ; α◌ͅ; ᾳ; α◌ͅ; ) GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4;1FB4;03B1 0301 0345;1FB4;03B1 0301 0345; # (ᾴ; ᾴ; α◌́◌ͅ; ᾴ; α◌́◌ͅ; ) GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6;1FB6;03B1 0342;1FB6;03B1 0342; # (ᾶ; ᾶ; α◌͂; ᾶ; α◌͂; ) GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7;1FB7;03B1 0342 0345;1FB7;03B1 0342 0345; # (ᾷ; ᾷ; α◌͂◌ͅ; ᾷ; α◌͂◌ͅ; ) GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8;1FB8;0391 0306;1FB8;0391 0306; # (Ᾰ; Ᾰ; Α◌̆; Ᾰ; Α◌̆; ) GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9;1FB9;0391 0304;1FB9;0391 0304; # (Ᾱ; Ᾱ; Α◌̄; Ᾱ; Α◌̄; ) GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA;1FBA;0391 0300;1FBA;0391 0300; # (Ὰ; Ὰ; Α◌̀; Ὰ; Α◌̀; ) GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB;0386;0391 0301;0386;0391 0301; # (Ά; Ά; Α◌́; Ά; Α◌́; ) GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC;1FBC;0391 0345;1FBC;0391 0345; # (ᾼ; ᾼ; Α◌ͅ; ᾼ; Α◌ͅ; ) GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD;1FBD;1FBD;0020 0313;0020 0313; # (᾽; ᾽; ᾽; ◌̓; ◌̓; ) GREEK KORONIS +1FBE;03B9;03B9;03B9;03B9; # (ι; ι; ι; ι; ι; ) GREEK PROSGEGRAMMENI +1FBF;1FBF;1FBF;0020 0313;0020 0313; # (᾿; ᾿; ᾿; ◌̓; ◌̓; ) GREEK PSILI +1FC0;1FC0;1FC0;0020 0342;0020 0342; # (῀; ῀; ῀; ◌͂; ◌͂; ) GREEK PERISPOMENI +1FC1;1FC1;00A8 0342;0020 0308 0342;0020 0308 0342; # (῁; ῁; ¨◌͂; ◌̈◌͂; ◌̈◌͂; ) GREEK DIALYTIKA AND PERISPOMENI +1FC2;1FC2;03B7 0300 0345;1FC2;03B7 0300 0345; # (ῂ; ῂ; η◌̀◌ͅ; ῂ; η◌̀◌ͅ; ) GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3;1FC3;03B7 0345;1FC3;03B7 0345; # (ῃ; ῃ; η◌ͅ; ῃ; η◌ͅ; ) GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4;1FC4;03B7 0301 0345;1FC4;03B7 0301 0345; # (ῄ; ῄ; η◌́◌ͅ; ῄ; η◌́◌ͅ; ) GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6;1FC6;03B7 0342;1FC6;03B7 0342; # (ῆ; ῆ; η◌͂; ῆ; η◌͂; ) GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7;1FC7;03B7 0342 0345;1FC7;03B7 0342 0345; # (ῇ; ῇ; η◌͂◌ͅ; ῇ; η◌͂◌ͅ; ) GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8;1FC8;0395 0300;1FC8;0395 0300; # (Ὲ; Ὲ; Ε◌̀; Ὲ; Ε◌̀; ) GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9;0388;0395 0301;0388;0395 0301; # (Έ; Έ; Ε◌́; Έ; Ε◌́; ) GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA;1FCA;0397 0300;1FCA;0397 0300; # (Ὴ; Ὴ; Η◌̀; Ὴ; Η◌̀; ) GREEK CAPITAL LETTER ETA WITH VARIA +1FCB;0389;0397 0301;0389;0397 0301; # (Ή; Ή; Η◌́; Ή; Η◌́; ) GREEK CAPITAL LETTER ETA WITH OXIA +1FCC;1FCC;0397 0345;1FCC;0397 0345; # (ῌ; ῌ; Η◌ͅ; ῌ; Η◌ͅ; ) GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD;1FCD;1FBF 0300;0020 0313 0300;0020 0313 0300; # (῍; ῍; ᾿◌̀; ◌̓◌̀; ◌̓◌̀; ) GREEK PSILI AND VARIA +1FCE;1FCE;1FBF 0301;0020 0313 0301;0020 0313 0301; # (῎; ῎; ᾿◌́; ◌̓◌́; ◌̓◌́; ) GREEK PSILI AND OXIA +1FCF;1FCF;1FBF 0342;0020 0313 0342;0020 0313 0342; # (῏; ῏; ᾿◌͂; ◌̓◌͂; ◌̓◌͂; ) GREEK PSILI AND PERISPOMENI +1FD0;1FD0;03B9 0306;1FD0;03B9 0306; # (ῐ; ῐ; ι◌̆; ῐ; ι◌̆; ) GREEK SMALL LETTER IOTA WITH VRACHY +1FD1;1FD1;03B9 0304;1FD1;03B9 0304; # (ῑ; ῑ; ι◌̄; ῑ; ι◌̄; ) GREEK SMALL LETTER IOTA WITH MACRON +1FD2;1FD2;03B9 0308 0300;1FD2;03B9 0308 0300; # (ῒ; ῒ; ι◌̈◌̀; ῒ; ι◌̈◌̀; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3;0390;03B9 0308 0301;0390;03B9 0308 0301; # (ΐ; ΐ; ι◌̈◌́; ΐ; ι◌̈◌́; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6;1FD6;03B9 0342;1FD6;03B9 0342; # (ῖ; ῖ; ι◌͂; ῖ; ι◌͂; ) GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7;1FD7;03B9 0308 0342;1FD7;03B9 0308 0342; # (ῗ; ῗ; ι◌̈◌͂; ῗ; ι◌̈◌͂; ) GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8;1FD8;0399 0306;1FD8;0399 0306; # (Ῐ; Ῐ; Ι◌̆; Ῐ; Ι◌̆; ) GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9;1FD9;0399 0304;1FD9;0399 0304; # (Ῑ; Ῑ; Ι◌̄; Ῑ; Ι◌̄; ) GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA;1FDA;0399 0300;1FDA;0399 0300; # (Ὶ; Ὶ; Ι◌̀; Ὶ; Ι◌̀; ) GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB;038A;0399 0301;038A;0399 0301; # (Ί; Ί; Ι◌́; Ί; Ι◌́; ) GREEK CAPITAL LETTER IOTA WITH OXIA +1FDD;1FDD;1FFE 0300;0020 0314 0300;0020 0314 0300; # (῝; ῝; ῾◌̀; ◌̔◌̀; ◌̔◌̀; ) GREEK DASIA AND VARIA +1FDE;1FDE;1FFE 0301;0020 0314 0301;0020 0314 0301; # (῞; ῞; ῾◌́; ◌̔◌́; ◌̔◌́; ) GREEK DASIA AND OXIA +1FDF;1FDF;1FFE 0342;0020 0314 0342;0020 0314 0342; # (῟; ῟; ῾◌͂; ◌̔◌͂; ◌̔◌͂; ) GREEK DASIA AND PERISPOMENI +1FE0;1FE0;03C5 0306;1FE0;03C5 0306; # (ῠ; ῠ; υ◌̆; ῠ; υ◌̆; ) GREEK SMALL LETTER UPSILON WITH VRACHY +1FE1;1FE1;03C5 0304;1FE1;03C5 0304; # (ῡ; ῡ; υ◌̄; ῡ; υ◌̄; ) GREEK SMALL LETTER UPSILON WITH MACRON +1FE2;1FE2;03C5 0308 0300;1FE2;03C5 0308 0300; # (ῢ; ῢ; υ◌̈◌̀; ῢ; υ◌̈◌̀; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3;03B0;03C5 0308 0301;03B0;03C5 0308 0301; # (ΰ; ΰ; υ◌̈◌́; ΰ; υ◌̈◌́; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4;1FE4;03C1 0313;1FE4;03C1 0313; # (ῤ; ῤ; ρ◌̓; ῤ; ρ◌̓; ) GREEK SMALL LETTER RHO WITH PSILI +1FE5;1FE5;03C1 0314;1FE5;03C1 0314; # (ῥ; ῥ; ρ◌̔; ῥ; ρ◌̔; ) GREEK SMALL LETTER RHO WITH DASIA +1FE6;1FE6;03C5 0342;1FE6;03C5 0342; # (ῦ; ῦ; υ◌͂; ῦ; υ◌͂; ) GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7;1FE7;03C5 0308 0342;1FE7;03C5 0308 0342; # (ῧ; ῧ; υ◌̈◌͂; ῧ; υ◌̈◌͂; ) GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8;1FE8;03A5 0306;1FE8;03A5 0306; # (Ῠ; Ῠ; Υ◌̆; Ῠ; Υ◌̆; ) GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9;1FE9;03A5 0304;1FE9;03A5 0304; # (Ῡ; Ῡ; Υ◌̄; Ῡ; Υ◌̄; ) GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA;1FEA;03A5 0300;1FEA;03A5 0300; # (Ὺ; Ὺ; Υ◌̀; Ὺ; Υ◌̀; ) GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB;038E;03A5 0301;038E;03A5 0301; # (Ύ; Ύ; Υ◌́; Ύ; Υ◌́; ) GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC;1FEC;03A1 0314;1FEC;03A1 0314; # (Ῥ; Ῥ; Ρ◌̔; Ῥ; Ρ◌̔; ) GREEK CAPITAL LETTER RHO WITH DASIA +1FED;1FED;00A8 0300;0020 0308 0300;0020 0308 0300; # (῭; ῭; ¨◌̀; ◌̈◌̀; ◌̈◌̀; ) GREEK DIALYTIKA AND VARIA +1FEE;0385;00A8 0301;0020 0308 0301;0020 0308 0301; # (΅; ΅; ¨◌́; ◌̈◌́; ◌̈◌́; ) GREEK DIALYTIKA AND OXIA +1FEF;0060;0060;0060;0060; # (`; `; `; `; `; ) GREEK VARIA +1FF2;1FF2;03C9 0300 0345;1FF2;03C9 0300 0345; # (ῲ; ῲ; ω◌̀◌ͅ; ῲ; ω◌̀◌ͅ; ) GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3;1FF3;03C9 0345;1FF3;03C9 0345; # (ῳ; ῳ; ω◌ͅ; ῳ; ω◌ͅ; ) GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4;1FF4;03C9 0301 0345;1FF4;03C9 0301 0345; # (ῴ; ῴ; ω◌́◌ͅ; ῴ; ω◌́◌ͅ; ) GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6;1FF6;03C9 0342;1FF6;03C9 0342; # (ῶ; ῶ; ω◌͂; ῶ; ω◌͂; ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7;1FF7;03C9 0342 0345;1FF7;03C9 0342 0345; # (ῷ; ῷ; ω◌͂◌ͅ; ῷ; ω◌͂◌ͅ; ) GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8;1FF8;039F 0300;1FF8;039F 0300; # (Ὸ; Ὸ; Ο◌̀; Ὸ; Ο◌̀; ) GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9;038C;039F 0301;038C;039F 0301; # (Ό; Ό; Ο◌́; Ό; Ο◌́; ) GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA;1FFA;03A9 0300;1FFA;03A9 0300; # (Ὼ; Ὼ; Ω◌̀; Ὼ; Ω◌̀; ) GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB;038F;03A9 0301;038F;03A9 0301; # (Ώ; Ώ; Ω◌́; Ώ; Ω◌́; ) GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC;1FFC;03A9 0345;1FFC;03A9 0345; # (ῼ; ῼ; Ω◌ͅ; ῼ; Ω◌ͅ; ) GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD;00B4;00B4;0020 0301;0020 0301; # (´; ´; ´; ◌́; ◌́; ) GREEK OXIA +1FFE;1FFE;1FFE;0020 0314;0020 0314; # (῾; ῾; ῾; ◌̔; ◌̔; ) GREEK DASIA +2000;2002;2002;0020;0020; # ( ;  ;  ; ; ; ) EN QUAD +2001;2003;2003;0020;0020; # ( ;  ;  ; ; ; ) EM QUAD +2002;2002;2002;0020;0020; # ( ;  ;  ; ; ; ) EN SPACE +2003;2003;2003;0020;0020; # ( ;  ;  ; ; ; ) EM SPACE +2004;2004;2004;0020;0020; # ( ;  ;  ; ; ; ) THREE-PER-EM SPACE +2005;2005;2005;0020;0020; # ( ;  ;  ; ; ; ) FOUR-PER-EM SPACE +2006;2006;2006;0020;0020; # ( ;  ;  ; ; ; ) SIX-PER-EM SPACE +2007;2007;2007;0020;0020; # ( ;  ;  ; ; ; ) FIGURE SPACE +2008;2008;2008;0020;0020; # ( ;  ;  ; ; ; ) PUNCTUATION SPACE +2009;2009;2009;0020;0020; # ( ;  ;  ; ; ; ) THIN SPACE +200A;200A;200A;0020;0020; # ( ;  ;  ; ; ; ) HAIR SPACE +2011;2011;2011;2010;2010; # (‑; ‑; ‑; ‐; ‐; ) NON-BREAKING HYPHEN +2017;2017;2017;0020 0333;0020 0333; # (‗; ‗; ‗; ◌̳; ◌̳; ) DOUBLE LOW LINE +2024;2024;2024;002E;002E; # (․; ․; ․; .; .; ) ONE DOT LEADER +2025;2025;2025;002E 002E;002E 002E; # (‥; ‥; ‥; ..; ..; ) TWO DOT LEADER +2026;2026;2026;002E 002E 002E;002E 002E 002E; # (…; …; …; ...; ...; ) HORIZONTAL ELLIPSIS +202F;202F;202F;0020;0020; # ( ;  ;  ; ; ; ) NARROW NO-BREAK SPACE +2033;2033;2033;2032 2032;2032 2032; # (″; ″; ″; ′′; ′′; ) DOUBLE PRIME +2034;2034;2034;2032 2032 2032;2032 2032 2032; # (‴; ‴; ‴; ′′′; ′′′; ) TRIPLE PRIME +2036;2036;2036;2035 2035;2035 2035; # (‶; ‶; ‶; ‵‵; ‵‵; ) REVERSED DOUBLE PRIME +2037;2037;2037;2035 2035 2035;2035 2035 2035; # (‷; ‷; ‷; ‵‵‵; ‵‵‵; ) REVERSED TRIPLE PRIME +203C;203C;203C;0021 0021;0021 0021; # (‼; ‼; ‼; !!; !!; ) DOUBLE EXCLAMATION MARK +203E;203E;203E;0020 0305;0020 0305; # (‾; ‾; ‾; ◌̅; ◌̅; ) OVERLINE +2047;2047;2047;003F 003F;003F 003F; # (⁇; ⁇; ⁇; ??; ??; ) DOUBLE QUESTION MARK +2048;2048;2048;003F 0021;003F 0021; # (⁈; ⁈; ⁈; ?!; ?!; ) QUESTION EXCLAMATION MARK +2049;2049;2049;0021 003F;0021 003F; # (⁉; ⁉; ⁉; !?; !?; ) EXCLAMATION QUESTION MARK +2057;2057;2057;2032 2032 2032 2032;2032 2032 2032 2032; # (⁗; ⁗; ⁗; ′′′′; ′′′′; ) QUADRUPLE PRIME +205F;205F;205F;0020;0020; # ( ;  ;  ; ; ; ) MEDIUM MATHEMATICAL SPACE +2070;2070;2070;0030;0030; # (⁰; ⁰; ⁰; 0; 0; ) SUPERSCRIPT ZERO +2071;2071;2071;0069;0069; # (ⁱ; ⁱ; ⁱ; i; i; ) SUPERSCRIPT LATIN SMALL LETTER I +2074;2074;2074;0034;0034; # (⁴; ⁴; ⁴; 4; 4; ) SUPERSCRIPT FOUR +2075;2075;2075;0035;0035; # (⁵; ⁵; ⁵; 5; 5; ) SUPERSCRIPT FIVE +2076;2076;2076;0036;0036; # (⁶; ⁶; ⁶; 6; 6; ) SUPERSCRIPT SIX +2077;2077;2077;0037;0037; # (⁷; ⁷; ⁷; 7; 7; ) SUPERSCRIPT SEVEN +2078;2078;2078;0038;0038; # (⁸; ⁸; ⁸; 8; 8; ) SUPERSCRIPT EIGHT +2079;2079;2079;0039;0039; # (⁹; ⁹; ⁹; 9; 9; ) SUPERSCRIPT NINE +207A;207A;207A;002B;002B; # (⁺; ⁺; ⁺; +; +; ) SUPERSCRIPT PLUS SIGN +207B;207B;207B;2212;2212; # (⁻; ⁻; ⁻; −; −; ) SUPERSCRIPT MINUS +207C;207C;207C;003D;003D; # (⁼; ⁼; ⁼; =; =; ) SUPERSCRIPT EQUALS SIGN +207D;207D;207D;0028;0028; # (⁽; ⁽; ⁽; (; (; ) SUPERSCRIPT LEFT PARENTHESIS +207E;207E;207E;0029;0029; # (⁾; ⁾; ⁾; ); ); ) SUPERSCRIPT RIGHT PARENTHESIS +207F;207F;207F;006E;006E; # (ⁿ; ⁿ; ⁿ; n; n; ) SUPERSCRIPT LATIN SMALL LETTER N +2080;2080;2080;0030;0030; # (₀; ₀; ₀; 0; 0; ) SUBSCRIPT ZERO +2081;2081;2081;0031;0031; # (₁; ₁; ₁; 1; 1; ) SUBSCRIPT ONE +2082;2082;2082;0032;0032; # (₂; ₂; ₂; 2; 2; ) SUBSCRIPT TWO +2083;2083;2083;0033;0033; # (₃; ₃; ₃; 3; 3; ) SUBSCRIPT THREE +2084;2084;2084;0034;0034; # (₄; ₄; ₄; 4; 4; ) SUBSCRIPT FOUR +2085;2085;2085;0035;0035; # (₅; ₅; ₅; 5; 5; ) SUBSCRIPT FIVE +2086;2086;2086;0036;0036; # (₆; ₆; ₆; 6; 6; ) SUBSCRIPT SIX +2087;2087;2087;0037;0037; # (₇; ₇; ₇; 7; 7; ) SUBSCRIPT SEVEN +2088;2088;2088;0038;0038; # (₈; ₈; ₈; 8; 8; ) SUBSCRIPT EIGHT +2089;2089;2089;0039;0039; # (₉; ₉; ₉; 9; 9; ) SUBSCRIPT NINE +208A;208A;208A;002B;002B; # (₊; ₊; ₊; +; +; ) SUBSCRIPT PLUS SIGN +208B;208B;208B;2212;2212; # (₋; ₋; ₋; −; −; ) SUBSCRIPT MINUS +208C;208C;208C;003D;003D; # (₌; ₌; ₌; =; =; ) SUBSCRIPT EQUALS SIGN +208D;208D;208D;0028;0028; # (₍; ₍; ₍; (; (; ) SUBSCRIPT LEFT PARENTHESIS +208E;208E;208E;0029;0029; # (₎; ₎; ₎; ); ); ) SUBSCRIPT RIGHT PARENTHESIS +2090;2090;2090;0061;0061; # (ₐ; ₐ; ₐ; a; a; ) LATIN SUBSCRIPT SMALL LETTER A +2091;2091;2091;0065;0065; # (ₑ; ₑ; ₑ; e; e; ) LATIN SUBSCRIPT SMALL LETTER E +2092;2092;2092;006F;006F; # (ₒ; ₒ; ₒ; o; o; ) LATIN SUBSCRIPT SMALL LETTER O +2093;2093;2093;0078;0078; # (ₓ; ₓ; ₓ; x; x; ) LATIN SUBSCRIPT SMALL LETTER X +2094;2094;2094;0259;0259; # (ₔ; ₔ; ₔ; ə; ə; ) LATIN SUBSCRIPT SMALL LETTER SCHWA +2095;2095;2095;0068;0068; # (ₕ; ₕ; ₕ; h; h; ) LATIN SUBSCRIPT SMALL LETTER H +2096;2096;2096;006B;006B; # (ₖ; ₖ; ₖ; k; k; ) LATIN SUBSCRIPT SMALL LETTER K +2097;2097;2097;006C;006C; # (ₗ; ₗ; ₗ; l; l; ) LATIN SUBSCRIPT SMALL LETTER L +2098;2098;2098;006D;006D; # (ₘ; ₘ; ₘ; m; m; ) LATIN SUBSCRIPT SMALL LETTER M +2099;2099;2099;006E;006E; # (ₙ; ₙ; ₙ; n; n; ) LATIN SUBSCRIPT SMALL LETTER N +209A;209A;209A;0070;0070; # (ₚ; ₚ; ₚ; p; p; ) LATIN SUBSCRIPT SMALL LETTER P +209B;209B;209B;0073;0073; # (ₛ; ₛ; ₛ; s; s; ) LATIN SUBSCRIPT SMALL LETTER S +209C;209C;209C;0074;0074; # (ₜ; ₜ; ₜ; t; t; ) LATIN SUBSCRIPT SMALL LETTER T +20A8;20A8;20A8;0052 0073;0052 0073; # (₨; ₨; ₨; Rs; Rs; ) RUPEE SIGN +2100;2100;2100;0061 002F 0063;0061 002F 0063; # (℀; ℀; ℀; a/c; a/c; ) ACCOUNT OF +2101;2101;2101;0061 002F 0073;0061 002F 0073; # (℁; ℁; ℁; a/s; a/s; ) ADDRESSED TO THE SUBJECT +2102;2102;2102;0043;0043; # (ℂ; ℂ; ℂ; C; C; ) DOUBLE-STRUCK CAPITAL C +2103;2103;2103;00B0 0043;00B0 0043; # (℃; ℃; ℃; °C; °C; ) DEGREE CELSIUS +2105;2105;2105;0063 002F 006F;0063 002F 006F; # (℅; ℅; ℅; c/o; c/o; ) CARE OF +2106;2106;2106;0063 002F 0075;0063 002F 0075; # (℆; ℆; ℆; c/u; c/u; ) CADA UNA +2107;2107;2107;0190;0190; # (ℇ; ℇ; ℇ; Ɛ; Ɛ; ) EULER CONSTANT +2109;2109;2109;00B0 0046;00B0 0046; # (℉; ℉; ℉; °F; °F; ) DEGREE FAHRENHEIT +210A;210A;210A;0067;0067; # (ℊ; ℊ; ℊ; g; g; ) SCRIPT SMALL G +210B;210B;210B;0048;0048; # (ℋ; ℋ; ℋ; H; H; ) SCRIPT CAPITAL H +210C;210C;210C;0048;0048; # (ℌ; ℌ; ℌ; H; H; ) BLACK-LETTER CAPITAL H +210D;210D;210D;0048;0048; # (ℍ; ℍ; ℍ; H; H; ) DOUBLE-STRUCK CAPITAL H +210E;210E;210E;0068;0068; # (ℎ; ℎ; ℎ; h; h; ) PLANCK CONSTANT +210F;210F;210F;0127;0127; # (ℏ; ℏ; ℏ; ħ; ħ; ) PLANCK CONSTANT OVER TWO PI +2110;2110;2110;0049;0049; # (ℐ; ℐ; ℐ; I; I; ) SCRIPT CAPITAL I +2111;2111;2111;0049;0049; # (ℑ; ℑ; ℑ; I; I; ) BLACK-LETTER CAPITAL I +2112;2112;2112;004C;004C; # (ℒ; ℒ; ℒ; L; L; ) SCRIPT CAPITAL L +2113;2113;2113;006C;006C; # (ℓ; ℓ; ℓ; l; l; ) SCRIPT SMALL L +2115;2115;2115;004E;004E; # (ℕ; ℕ; ℕ; N; N; ) DOUBLE-STRUCK CAPITAL N +2116;2116;2116;004E 006F;004E 006F; # (№; №; №; No; No; ) NUMERO SIGN +2119;2119;2119;0050;0050; # (ℙ; ℙ; ℙ; P; P; ) DOUBLE-STRUCK CAPITAL P +211A;211A;211A;0051;0051; # (ℚ; ℚ; ℚ; Q; Q; ) DOUBLE-STRUCK CAPITAL Q +211B;211B;211B;0052;0052; # (ℛ; ℛ; ℛ; R; R; ) SCRIPT CAPITAL R +211C;211C;211C;0052;0052; # (ℜ; ℜ; ℜ; R; R; ) BLACK-LETTER CAPITAL R +211D;211D;211D;0052;0052; # (ℝ; ℝ; ℝ; R; R; ) DOUBLE-STRUCK CAPITAL R +2120;2120;2120;0053 004D;0053 004D; # (℠; ℠; ℠; SM; SM; ) SERVICE MARK +2121;2121;2121;0054 0045 004C;0054 0045 004C; # (℡; ℡; ℡; TEL; TEL; ) TELEPHONE SIGN +2122;2122;2122;0054 004D;0054 004D; # (™; ™; ™; TM; TM; ) TRADE MARK SIGN +2124;2124;2124;005A;005A; # (ℤ; ℤ; ℤ; Z; Z; ) DOUBLE-STRUCK CAPITAL Z +2126;03A9;03A9;03A9;03A9; # (Ω; Ω; Ω; Ω; Ω; ) OHM SIGN +2128;2128;2128;005A;005A; # (ℨ; ℨ; ℨ; Z; Z; ) BLACK-LETTER CAPITAL Z +212A;004B;004B;004B;004B; # (K; K; K; K; K; ) KELVIN SIGN +212B;00C5;0041 030A;00C5;0041 030A; # (Å; Å; A◌̊; Å; A◌̊; ) ANGSTROM SIGN +212C;212C;212C;0042;0042; # (ℬ; ℬ; ℬ; B; B; ) SCRIPT CAPITAL B +212D;212D;212D;0043;0043; # (ℭ; ℭ; ℭ; C; C; ) BLACK-LETTER CAPITAL C +212F;212F;212F;0065;0065; # (ℯ; ℯ; ℯ; e; e; ) SCRIPT SMALL E +2130;2130;2130;0045;0045; # (ℰ; ℰ; ℰ; E; E; ) SCRIPT CAPITAL E +2131;2131;2131;0046;0046; # (ℱ; ℱ; ℱ; F; F; ) SCRIPT CAPITAL F +2133;2133;2133;004D;004D; # (ℳ; ℳ; ℳ; M; M; ) SCRIPT CAPITAL M +2134;2134;2134;006F;006F; # (ℴ; ℴ; ℴ; o; o; ) SCRIPT SMALL O +2135;2135;2135;05D0;05D0; # (ℵ; ℵ; ℵ; א; א; ) ALEF SYMBOL +2136;2136;2136;05D1;05D1; # (ℶ; ℶ; ℶ; ב; ב; ) BET SYMBOL +2137;2137;2137;05D2;05D2; # (ℷ; ℷ; ℷ; ג; ג; ) GIMEL SYMBOL +2138;2138;2138;05D3;05D3; # (ℸ; ℸ; ℸ; ד; ד; ) DALET SYMBOL +2139;2139;2139;0069;0069; # (ℹ; ℹ; ℹ; i; i; ) INFORMATION SOURCE +213B;213B;213B;0046 0041 0058;0046 0041 0058; # (℻; ℻; ℻; FAX; FAX; ) FACSIMILE SIGN +213C;213C;213C;03C0;03C0; # (ℼ; ℼ; ℼ; π; π; ) DOUBLE-STRUCK SMALL PI +213D;213D;213D;03B3;03B3; # (ℽ; ℽ; ℽ; γ; γ; ) DOUBLE-STRUCK SMALL GAMMA +213E;213E;213E;0393;0393; # (ℾ; ℾ; ℾ; Γ; Γ; ) DOUBLE-STRUCK CAPITAL GAMMA +213F;213F;213F;03A0;03A0; # (ℿ; ℿ; ℿ; Π; Π; ) DOUBLE-STRUCK CAPITAL PI +2140;2140;2140;2211;2211; # (⅀; ⅀; ⅀; ∑; ∑; ) DOUBLE-STRUCK N-ARY SUMMATION +2145;2145;2145;0044;0044; # (ⅅ; ⅅ; ⅅ; D; D; ) DOUBLE-STRUCK ITALIC CAPITAL D +2146;2146;2146;0064;0064; # (ⅆ; ⅆ; ⅆ; d; d; ) DOUBLE-STRUCK ITALIC SMALL D +2147;2147;2147;0065;0065; # (ⅇ; ⅇ; ⅇ; e; e; ) DOUBLE-STRUCK ITALIC SMALL E +2148;2148;2148;0069;0069; # (ⅈ; ⅈ; ⅈ; i; i; ) DOUBLE-STRUCK ITALIC SMALL I +2149;2149;2149;006A;006A; # (ⅉ; ⅉ; ⅉ; j; j; ) DOUBLE-STRUCK ITALIC SMALL J +2150;2150;2150;0031 2044 0037;0031 2044 0037; # (⅐; ⅐; ⅐; 1⁄7; 1⁄7; ) VULGAR FRACTION ONE SEVENTH +2151;2151;2151;0031 2044 0039;0031 2044 0039; # (⅑; ⅑; ⅑; 1⁄9; 1⁄9; ) VULGAR FRACTION ONE NINTH +2152;2152;2152;0031 2044 0031 0030;0031 2044 0031 0030; # (⅒; ⅒; ⅒; 1⁄10; 1⁄10; ) VULGAR FRACTION ONE TENTH +2153;2153;2153;0031 2044 0033;0031 2044 0033; # (⅓; ⅓; ⅓; 1⁄3; 1⁄3; ) VULGAR FRACTION ONE THIRD +2154;2154;2154;0032 2044 0033;0032 2044 0033; # (⅔; ⅔; ⅔; 2⁄3; 2⁄3; ) VULGAR FRACTION TWO THIRDS +2155;2155;2155;0031 2044 0035;0031 2044 0035; # (⅕; ⅕; ⅕; 1⁄5; 1⁄5; ) VULGAR FRACTION ONE FIFTH +2156;2156;2156;0032 2044 0035;0032 2044 0035; # (⅖; ⅖; ⅖; 2⁄5; 2⁄5; ) VULGAR FRACTION TWO FIFTHS +2157;2157;2157;0033 2044 0035;0033 2044 0035; # (⅗; ⅗; ⅗; 3⁄5; 3⁄5; ) VULGAR FRACTION THREE FIFTHS +2158;2158;2158;0034 2044 0035;0034 2044 0035; # (⅘; ⅘; ⅘; 4⁄5; 4⁄5; ) VULGAR FRACTION FOUR FIFTHS +2159;2159;2159;0031 2044 0036;0031 2044 0036; # (⅙; ⅙; ⅙; 1⁄6; 1⁄6; ) VULGAR FRACTION ONE SIXTH +215A;215A;215A;0035 2044 0036;0035 2044 0036; # (⅚; ⅚; ⅚; 5⁄6; 5⁄6; ) VULGAR FRACTION FIVE SIXTHS +215B;215B;215B;0031 2044 0038;0031 2044 0038; # (⅛; ⅛; ⅛; 1⁄8; 1⁄8; ) VULGAR FRACTION ONE EIGHTH +215C;215C;215C;0033 2044 0038;0033 2044 0038; # (⅜; ⅜; ⅜; 3⁄8; 3⁄8; ) VULGAR FRACTION THREE EIGHTHS +215D;215D;215D;0035 2044 0038;0035 2044 0038; # (⅝; ⅝; ⅝; 5⁄8; 5⁄8; ) VULGAR FRACTION FIVE EIGHTHS +215E;215E;215E;0037 2044 0038;0037 2044 0038; # (⅞; ⅞; ⅞; 7⁄8; 7⁄8; ) VULGAR FRACTION SEVEN EIGHTHS +215F;215F;215F;0031 2044;0031 2044; # (⅟; ⅟; ⅟; 1⁄; 1⁄; ) FRACTION NUMERATOR ONE +2160;2160;2160;0049;0049; # (Ⅰ; Ⅰ; Ⅰ; I; I; ) ROMAN NUMERAL ONE +2161;2161;2161;0049 0049;0049 0049; # (Ⅱ; Ⅱ; Ⅱ; II; II; ) ROMAN NUMERAL TWO +2162;2162;2162;0049 0049 0049;0049 0049 0049; # (Ⅲ; Ⅲ; Ⅲ; III; III; ) ROMAN NUMERAL THREE +2163;2163;2163;0049 0056;0049 0056; # (Ⅳ; Ⅳ; Ⅳ; IV; IV; ) ROMAN NUMERAL FOUR +2164;2164;2164;0056;0056; # (Ⅴ; Ⅴ; Ⅴ; V; V; ) ROMAN NUMERAL FIVE +2165;2165;2165;0056 0049;0056 0049; # (Ⅵ; Ⅵ; Ⅵ; VI; VI; ) ROMAN NUMERAL SIX +2166;2166;2166;0056 0049 0049;0056 0049 0049; # (Ⅶ; Ⅶ; Ⅶ; VII; VII; ) ROMAN NUMERAL SEVEN +2167;2167;2167;0056 0049 0049 0049;0056 0049 0049 0049; # (Ⅷ; Ⅷ; Ⅷ; VIII; VIII; ) ROMAN NUMERAL EIGHT +2168;2168;2168;0049 0058;0049 0058; # (Ⅸ; Ⅸ; Ⅸ; IX; IX; ) ROMAN NUMERAL NINE +2169;2169;2169;0058;0058; # (Ⅹ; Ⅹ; Ⅹ; X; X; ) ROMAN NUMERAL TEN +216A;216A;216A;0058 0049;0058 0049; # (Ⅺ; Ⅺ; Ⅺ; XI; XI; ) ROMAN NUMERAL ELEVEN +216B;216B;216B;0058 0049 0049;0058 0049 0049; # (Ⅻ; Ⅻ; Ⅻ; XII; XII; ) ROMAN NUMERAL TWELVE +216C;216C;216C;004C;004C; # (Ⅼ; Ⅼ; Ⅼ; L; L; ) ROMAN NUMERAL FIFTY +216D;216D;216D;0043;0043; # (Ⅽ; Ⅽ; Ⅽ; C; C; ) ROMAN NUMERAL ONE HUNDRED +216E;216E;216E;0044;0044; # (Ⅾ; Ⅾ; Ⅾ; D; D; ) ROMAN NUMERAL FIVE HUNDRED +216F;216F;216F;004D;004D; # (Ⅿ; Ⅿ; Ⅿ; M; M; ) ROMAN NUMERAL ONE THOUSAND +2170;2170;2170;0069;0069; # (ⅰ; ⅰ; ⅰ; i; i; ) SMALL ROMAN NUMERAL ONE +2171;2171;2171;0069 0069;0069 0069; # (ⅱ; ⅱ; ⅱ; ii; ii; ) SMALL ROMAN NUMERAL TWO +2172;2172;2172;0069 0069 0069;0069 0069 0069; # (ⅲ; ⅲ; ⅲ; iii; iii; ) SMALL ROMAN NUMERAL THREE +2173;2173;2173;0069 0076;0069 0076; # (ⅳ; ⅳ; ⅳ; iv; iv; ) SMALL ROMAN NUMERAL FOUR +2174;2174;2174;0076;0076; # (ⅴ; ⅴ; ⅴ; v; v; ) SMALL ROMAN NUMERAL FIVE +2175;2175;2175;0076 0069;0076 0069; # (ⅵ; ⅵ; ⅵ; vi; vi; ) SMALL ROMAN NUMERAL SIX +2176;2176;2176;0076 0069 0069;0076 0069 0069; # (ⅶ; ⅶ; ⅶ; vii; vii; ) SMALL ROMAN NUMERAL SEVEN +2177;2177;2177;0076 0069 0069 0069;0076 0069 0069 0069; # (ⅷ; ⅷ; ⅷ; viii; viii; ) SMALL ROMAN NUMERAL EIGHT +2178;2178;2178;0069 0078;0069 0078; # (ⅸ; ⅸ; ⅸ; ix; ix; ) SMALL ROMAN NUMERAL NINE +2179;2179;2179;0078;0078; # (ⅹ; ⅹ; ⅹ; x; x; ) SMALL ROMAN NUMERAL TEN +217A;217A;217A;0078 0069;0078 0069; # (ⅺ; ⅺ; ⅺ; xi; xi; ) SMALL ROMAN NUMERAL ELEVEN +217B;217B;217B;0078 0069 0069;0078 0069 0069; # (ⅻ; ⅻ; ⅻ; xii; xii; ) SMALL ROMAN NUMERAL TWELVE +217C;217C;217C;006C;006C; # (ⅼ; ⅼ; ⅼ; l; l; ) SMALL ROMAN NUMERAL FIFTY +217D;217D;217D;0063;0063; # (ⅽ; ⅽ; ⅽ; c; c; ) SMALL ROMAN NUMERAL ONE HUNDRED +217E;217E;217E;0064;0064; # (ⅾ; ⅾ; ⅾ; d; d; ) SMALL ROMAN NUMERAL FIVE HUNDRED +217F;217F;217F;006D;006D; # (ⅿ; ⅿ; ⅿ; m; m; ) SMALL ROMAN NUMERAL ONE THOUSAND +2189;2189;2189;0030 2044 0033;0030 2044 0033; # (↉; ↉; ↉; 0⁄3; 0⁄3; ) VULGAR FRACTION ZERO THIRDS +219A;219A;2190 0338;219A;2190 0338; # (↚; ↚; ←◌̸; ↚; ←◌̸; ) LEFTWARDS ARROW WITH STROKE +219B;219B;2192 0338;219B;2192 0338; # (↛; ↛; →◌̸; ↛; →◌̸; ) RIGHTWARDS ARROW WITH STROKE +21AE;21AE;2194 0338;21AE;2194 0338; # (↮; ↮; ↔◌̸; ↮; ↔◌̸; ) LEFT RIGHT ARROW WITH STROKE +21CD;21CD;21D0 0338;21CD;21D0 0338; # (⇍; ⇍; ⇐◌̸; ⇍; ⇐◌̸; ) LEFTWARDS DOUBLE ARROW WITH STROKE +21CE;21CE;21D4 0338;21CE;21D4 0338; # (⇎; ⇎; ⇔◌̸; ⇎; ⇔◌̸; ) LEFT RIGHT DOUBLE ARROW WITH STROKE +21CF;21CF;21D2 0338;21CF;21D2 0338; # (⇏; ⇏; ⇒◌̸; ⇏; ⇒◌̸; ) RIGHTWARDS DOUBLE ARROW WITH STROKE +2204;2204;2203 0338;2204;2203 0338; # (∄; ∄; ∃◌̸; ∄; ∃◌̸; ) THERE DOES NOT EXIST +2209;2209;2208 0338;2209;2208 0338; # (∉; ∉; ∈◌̸; ∉; ∈◌̸; ) NOT AN ELEMENT OF +220C;220C;220B 0338;220C;220B 0338; # (∌; ∌; ∋◌̸; ∌; ∋◌̸; ) DOES NOT CONTAIN AS MEMBER +2224;2224;2223 0338;2224;2223 0338; # (∤; ∤; ∣◌̸; ∤; ∣◌̸; ) DOES NOT DIVIDE +2226;2226;2225 0338;2226;2225 0338; # (∦; ∦; ∥◌̸; ∦; ∥◌̸; ) NOT PARALLEL TO +222C;222C;222C;222B 222B;222B 222B; # (∬; ∬; ∬; ∫∫; ∫∫; ) DOUBLE INTEGRAL +222D;222D;222D;222B 222B 222B;222B 222B 222B; # (∭; ∭; ∭; ∫∫∫; ∫∫∫; ) TRIPLE INTEGRAL +222F;222F;222F;222E 222E;222E 222E; # (∯; ∯; ∯; ∮∮; ∮∮; ) SURFACE INTEGRAL +2230;2230;2230;222E 222E 222E;222E 222E 222E; # (∰; ∰; ∰; ∮∮∮; ∮∮∮; ) VOLUME INTEGRAL +2241;2241;223C 0338;2241;223C 0338; # (≁; ≁; ∼◌̸; ≁; ∼◌̸; ) NOT TILDE +2244;2244;2243 0338;2244;2243 0338; # (≄; ≄; ≃◌̸; ≄; ≃◌̸; ) NOT ASYMPTOTICALLY EQUAL TO +2247;2247;2245 0338;2247;2245 0338; # (≇; ≇; ≅◌̸; ≇; ≅◌̸; ) NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2249;2249;2248 0338;2249;2248 0338; # (≉; ≉; ≈◌̸; ≉; ≈◌̸; ) NOT ALMOST EQUAL TO +2260;2260;003D 0338;2260;003D 0338; # (≠; ≠; =◌̸; ≠; =◌̸; ) NOT EQUAL TO +2262;2262;2261 0338;2262;2261 0338; # (≢; ≢; ≡◌̸; ≢; ≡◌̸; ) NOT IDENTICAL TO +226D;226D;224D 0338;226D;224D 0338; # (≭; ≭; ≍◌̸; ≭; ≍◌̸; ) NOT EQUIVALENT TO +226E;226E;003C 0338;226E;003C 0338; # (≮; ≮; <◌̸; ≮; <◌̸; ) NOT LESS-THAN +226F;226F;003E 0338;226F;003E 0338; # (≯; ≯; >◌̸; ≯; >◌̸; ) NOT GREATER-THAN +2270;2270;2264 0338;2270;2264 0338; # (≰; ≰; ≤◌̸; ≰; ≤◌̸; ) NEITHER LESS-THAN NOR EQUAL TO +2271;2271;2265 0338;2271;2265 0338; # (≱; ≱; ≥◌̸; ≱; ≥◌̸; ) NEITHER GREATER-THAN NOR EQUAL TO +2274;2274;2272 0338;2274;2272 0338; # (≴; ≴; ≲◌̸; ≴; ≲◌̸; ) NEITHER LESS-THAN NOR EQUIVALENT TO +2275;2275;2273 0338;2275;2273 0338; # (≵; ≵; ≳◌̸; ≵; ≳◌̸; ) NEITHER GREATER-THAN NOR EQUIVALENT TO +2278;2278;2276 0338;2278;2276 0338; # (≸; ≸; ≶◌̸; ≸; ≶◌̸; ) NEITHER LESS-THAN NOR GREATER-THAN +2279;2279;2277 0338;2279;2277 0338; # (≹; ≹; ≷◌̸; ≹; ≷◌̸; ) NEITHER GREATER-THAN NOR LESS-THAN +2280;2280;227A 0338;2280;227A 0338; # (⊀; ⊀; ≺◌̸; ⊀; ≺◌̸; ) DOES NOT PRECEDE +2281;2281;227B 0338;2281;227B 0338; # (⊁; ⊁; ≻◌̸; ⊁; ≻◌̸; ) DOES NOT SUCCEED +2284;2284;2282 0338;2284;2282 0338; # (⊄; ⊄; ⊂◌̸; ⊄; ⊂◌̸; ) NOT A SUBSET OF +2285;2285;2283 0338;2285;2283 0338; # (⊅; ⊅; ⊃◌̸; ⊅; ⊃◌̸; ) NOT A SUPERSET OF +2288;2288;2286 0338;2288;2286 0338; # (⊈; ⊈; ⊆◌̸; ⊈; ⊆◌̸; ) NEITHER A SUBSET OF NOR EQUAL TO +2289;2289;2287 0338;2289;2287 0338; # (⊉; ⊉; ⊇◌̸; ⊉; ⊇◌̸; ) NEITHER A SUPERSET OF NOR EQUAL TO +22AC;22AC;22A2 0338;22AC;22A2 0338; # (⊬; ⊬; ⊢◌̸; ⊬; ⊢◌̸; ) DOES NOT PROVE +22AD;22AD;22A8 0338;22AD;22A8 0338; # (⊭; ⊭; ⊨◌̸; ⊭; ⊨◌̸; ) NOT TRUE +22AE;22AE;22A9 0338;22AE;22A9 0338; # (⊮; ⊮; ⊩◌̸; ⊮; ⊩◌̸; ) DOES NOT FORCE +22AF;22AF;22AB 0338;22AF;22AB 0338; # (⊯; ⊯; ⊫◌̸; ⊯; ⊫◌̸; ) NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE +22E0;22E0;227C 0338;22E0;227C 0338; # (⋠; ⋠; ≼◌̸; ⋠; ≼◌̸; ) DOES NOT PRECEDE OR EQUAL +22E1;22E1;227D 0338;22E1;227D 0338; # (⋡; ⋡; ≽◌̸; ⋡; ≽◌̸; ) DOES NOT SUCCEED OR EQUAL +22E2;22E2;2291 0338;22E2;2291 0338; # (⋢; ⋢; ⊑◌̸; ⋢; ⊑◌̸; ) NOT SQUARE IMAGE OF OR EQUAL TO +22E3;22E3;2292 0338;22E3;2292 0338; # (⋣; ⋣; ⊒◌̸; ⋣; ⊒◌̸; ) NOT SQUARE ORIGINAL OF OR EQUAL TO +22EA;22EA;22B2 0338;22EA;22B2 0338; # (⋪; ⋪; ⊲◌̸; ⋪; ⊲◌̸; ) NOT NORMAL SUBGROUP OF +22EB;22EB;22B3 0338;22EB;22B3 0338; # (⋫; ⋫; ⊳◌̸; ⋫; ⊳◌̸; ) DOES NOT CONTAIN AS NORMAL SUBGROUP +22EC;22EC;22B4 0338;22EC;22B4 0338; # (⋬; ⋬; ⊴◌̸; ⋬; ⊴◌̸; ) NOT NORMAL SUBGROUP OF OR EQUAL TO +22ED;22ED;22B5 0338;22ED;22B5 0338; # (⋭; ⋭; ⊵◌̸; ⋭; ⊵◌̸; ) DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL +2329;3008;3008;3008;3008; # (〈; 〈; 〈; 〈; 〈; ) LEFT-POINTING ANGLE BRACKET +232A;3009;3009;3009;3009; # (〉; 〉; 〉; 〉; 〉; ) RIGHT-POINTING ANGLE BRACKET +2460;2460;2460;0031;0031; # (①; ①; ①; 1; 1; ) CIRCLED DIGIT ONE +2461;2461;2461;0032;0032; # (②; ②; ②; 2; 2; ) CIRCLED DIGIT TWO +2462;2462;2462;0033;0033; # (③; ③; ③; 3; 3; ) CIRCLED DIGIT THREE +2463;2463;2463;0034;0034; # (④; ④; ④; 4; 4; ) CIRCLED DIGIT FOUR +2464;2464;2464;0035;0035; # (⑤; ⑤; ⑤; 5; 5; ) CIRCLED DIGIT FIVE +2465;2465;2465;0036;0036; # (⑥; ⑥; ⑥; 6; 6; ) CIRCLED DIGIT SIX +2466;2466;2466;0037;0037; # (⑦; ⑦; ⑦; 7; 7; ) CIRCLED DIGIT SEVEN +2467;2467;2467;0038;0038; # (⑧; ⑧; ⑧; 8; 8; ) CIRCLED DIGIT EIGHT +2468;2468;2468;0039;0039; # (⑨; ⑨; ⑨; 9; 9; ) CIRCLED DIGIT NINE +2469;2469;2469;0031 0030;0031 0030; # (⑩; ⑩; ⑩; 10; 10; ) CIRCLED NUMBER TEN +246A;246A;246A;0031 0031;0031 0031; # (⑪; ⑪; ⑪; 11; 11; ) CIRCLED NUMBER ELEVEN +246B;246B;246B;0031 0032;0031 0032; # (⑫; ⑫; ⑫; 12; 12; ) CIRCLED NUMBER TWELVE +246C;246C;246C;0031 0033;0031 0033; # (⑬; ⑬; ⑬; 13; 13; ) CIRCLED NUMBER THIRTEEN +246D;246D;246D;0031 0034;0031 0034; # (⑭; ⑭; ⑭; 14; 14; ) CIRCLED NUMBER FOURTEEN +246E;246E;246E;0031 0035;0031 0035; # (⑮; ⑮; ⑮; 15; 15; ) CIRCLED NUMBER FIFTEEN +246F;246F;246F;0031 0036;0031 0036; # (⑯; ⑯; ⑯; 16; 16; ) CIRCLED NUMBER SIXTEEN +2470;2470;2470;0031 0037;0031 0037; # (⑰; ⑰; ⑰; 17; 17; ) CIRCLED NUMBER SEVENTEEN +2471;2471;2471;0031 0038;0031 0038; # (⑱; ⑱; ⑱; 18; 18; ) CIRCLED NUMBER EIGHTEEN +2472;2472;2472;0031 0039;0031 0039; # (⑲; ⑲; ⑲; 19; 19; ) CIRCLED NUMBER NINETEEN +2473;2473;2473;0032 0030;0032 0030; # (⑳; ⑳; ⑳; 20; 20; ) CIRCLED NUMBER TWENTY +2474;2474;2474;0028 0031 0029;0028 0031 0029; # (⑴; ⑴; ⑴; (1); (1); ) PARENTHESIZED DIGIT ONE +2475;2475;2475;0028 0032 0029;0028 0032 0029; # (⑵; ⑵; ⑵; (2); (2); ) PARENTHESIZED DIGIT TWO +2476;2476;2476;0028 0033 0029;0028 0033 0029; # (⑶; ⑶; ⑶; (3); (3); ) PARENTHESIZED DIGIT THREE +2477;2477;2477;0028 0034 0029;0028 0034 0029; # (⑷; ⑷; ⑷; (4); (4); ) PARENTHESIZED DIGIT FOUR +2478;2478;2478;0028 0035 0029;0028 0035 0029; # (⑸; ⑸; ⑸; (5); (5); ) PARENTHESIZED DIGIT FIVE +2479;2479;2479;0028 0036 0029;0028 0036 0029; # (⑹; ⑹; ⑹; (6); (6); ) PARENTHESIZED DIGIT SIX +247A;247A;247A;0028 0037 0029;0028 0037 0029; # (⑺; ⑺; ⑺; (7); (7); ) PARENTHESIZED DIGIT SEVEN +247B;247B;247B;0028 0038 0029;0028 0038 0029; # (⑻; ⑻; ⑻; (8); (8); ) PARENTHESIZED DIGIT EIGHT +247C;247C;247C;0028 0039 0029;0028 0039 0029; # (⑼; ⑼; ⑼; (9); (9); ) PARENTHESIZED DIGIT NINE +247D;247D;247D;0028 0031 0030 0029;0028 0031 0030 0029; # (⑽; ⑽; ⑽; (10); (10); ) PARENTHESIZED NUMBER TEN +247E;247E;247E;0028 0031 0031 0029;0028 0031 0031 0029; # (⑾; ⑾; ⑾; (11); (11); ) PARENTHESIZED NUMBER ELEVEN +247F;247F;247F;0028 0031 0032 0029;0028 0031 0032 0029; # (⑿; ⑿; ⑿; (12); (12); ) PARENTHESIZED NUMBER TWELVE +2480;2480;2480;0028 0031 0033 0029;0028 0031 0033 0029; # (⒀; ⒀; ⒀; (13); (13); ) PARENTHESIZED NUMBER THIRTEEN +2481;2481;2481;0028 0031 0034 0029;0028 0031 0034 0029; # (⒁; ⒁; ⒁; (14); (14); ) PARENTHESIZED NUMBER FOURTEEN +2482;2482;2482;0028 0031 0035 0029;0028 0031 0035 0029; # (⒂; ⒂; ⒂; (15); (15); ) PARENTHESIZED NUMBER FIFTEEN +2483;2483;2483;0028 0031 0036 0029;0028 0031 0036 0029; # (⒃; ⒃; ⒃; (16); (16); ) PARENTHESIZED NUMBER SIXTEEN +2484;2484;2484;0028 0031 0037 0029;0028 0031 0037 0029; # (⒄; ⒄; ⒄; (17); (17); ) PARENTHESIZED NUMBER SEVENTEEN +2485;2485;2485;0028 0031 0038 0029;0028 0031 0038 0029; # (⒅; ⒅; ⒅; (18); (18); ) PARENTHESIZED NUMBER EIGHTEEN +2486;2486;2486;0028 0031 0039 0029;0028 0031 0039 0029; # (⒆; ⒆; ⒆; (19); (19); ) PARENTHESIZED NUMBER NINETEEN +2487;2487;2487;0028 0032 0030 0029;0028 0032 0030 0029; # (⒇; ⒇; ⒇; (20); (20); ) PARENTHESIZED NUMBER TWENTY +2488;2488;2488;0031 002E;0031 002E; # (⒈; ⒈; ⒈; 1.; 1.; ) DIGIT ONE FULL STOP +2489;2489;2489;0032 002E;0032 002E; # (⒉; ⒉; ⒉; 2.; 2.; ) DIGIT TWO FULL STOP +248A;248A;248A;0033 002E;0033 002E; # (⒊; ⒊; ⒊; 3.; 3.; ) DIGIT THREE FULL STOP +248B;248B;248B;0034 002E;0034 002E; # (⒋; ⒋; ⒋; 4.; 4.; ) DIGIT FOUR FULL STOP +248C;248C;248C;0035 002E;0035 002E; # (⒌; ⒌; ⒌; 5.; 5.; ) DIGIT FIVE FULL STOP +248D;248D;248D;0036 002E;0036 002E; # (⒍; ⒍; ⒍; 6.; 6.; ) DIGIT SIX FULL STOP +248E;248E;248E;0037 002E;0037 002E; # (⒎; ⒎; ⒎; 7.; 7.; ) DIGIT SEVEN FULL STOP +248F;248F;248F;0038 002E;0038 002E; # (⒏; ⒏; ⒏; 8.; 8.; ) DIGIT EIGHT FULL STOP +2490;2490;2490;0039 002E;0039 002E; # (⒐; ⒐; ⒐; 9.; 9.; ) DIGIT NINE FULL STOP +2491;2491;2491;0031 0030 002E;0031 0030 002E; # (⒑; ⒑; ⒑; 10.; 10.; ) NUMBER TEN FULL STOP +2492;2492;2492;0031 0031 002E;0031 0031 002E; # (⒒; ⒒; ⒒; 11.; 11.; ) NUMBER ELEVEN FULL STOP +2493;2493;2493;0031 0032 002E;0031 0032 002E; # (⒓; ⒓; ⒓; 12.; 12.; ) NUMBER TWELVE FULL STOP +2494;2494;2494;0031 0033 002E;0031 0033 002E; # (⒔; ⒔; ⒔; 13.; 13.; ) NUMBER THIRTEEN FULL STOP +2495;2495;2495;0031 0034 002E;0031 0034 002E; # (⒕; ⒕; ⒕; 14.; 14.; ) NUMBER FOURTEEN FULL STOP +2496;2496;2496;0031 0035 002E;0031 0035 002E; # (⒖; ⒖; ⒖; 15.; 15.; ) NUMBER FIFTEEN FULL STOP +2497;2497;2497;0031 0036 002E;0031 0036 002E; # (⒗; ⒗; ⒗; 16.; 16.; ) NUMBER SIXTEEN FULL STOP +2498;2498;2498;0031 0037 002E;0031 0037 002E; # (⒘; ⒘; ⒘; 17.; 17.; ) NUMBER SEVENTEEN FULL STOP +2499;2499;2499;0031 0038 002E;0031 0038 002E; # (⒙; ⒙; ⒙; 18.; 18.; ) NUMBER EIGHTEEN FULL STOP +249A;249A;249A;0031 0039 002E;0031 0039 002E; # (⒚; ⒚; ⒚; 19.; 19.; ) NUMBER NINETEEN FULL STOP +249B;249B;249B;0032 0030 002E;0032 0030 002E; # (⒛; ⒛; ⒛; 20.; 20.; ) NUMBER TWENTY FULL STOP +249C;249C;249C;0028 0061 0029;0028 0061 0029; # (⒜; ⒜; ⒜; (a); (a); ) PARENTHESIZED LATIN SMALL LETTER A +249D;249D;249D;0028 0062 0029;0028 0062 0029; # (⒝; ⒝; ⒝; (b); (b); ) PARENTHESIZED LATIN SMALL LETTER B +249E;249E;249E;0028 0063 0029;0028 0063 0029; # (⒞; ⒞; ⒞; (c); (c); ) PARENTHESIZED LATIN SMALL LETTER C +249F;249F;249F;0028 0064 0029;0028 0064 0029; # (⒟; ⒟; ⒟; (d); (d); ) PARENTHESIZED LATIN SMALL LETTER D +24A0;24A0;24A0;0028 0065 0029;0028 0065 0029; # (⒠; ⒠; ⒠; (e); (e); ) PARENTHESIZED LATIN SMALL LETTER E +24A1;24A1;24A1;0028 0066 0029;0028 0066 0029; # (⒡; ⒡; ⒡; (f); (f); ) PARENTHESIZED LATIN SMALL LETTER F +24A2;24A2;24A2;0028 0067 0029;0028 0067 0029; # (⒢; ⒢; ⒢; (g); (g); ) PARENTHESIZED LATIN SMALL LETTER G +24A3;24A3;24A3;0028 0068 0029;0028 0068 0029; # (⒣; ⒣; ⒣; (h); (h); ) PARENTHESIZED LATIN SMALL LETTER H +24A4;24A4;24A4;0028 0069 0029;0028 0069 0029; # (⒤; ⒤; ⒤; (i); (i); ) PARENTHESIZED LATIN SMALL LETTER I +24A5;24A5;24A5;0028 006A 0029;0028 006A 0029; # (⒥; ⒥; ⒥; (j); (j); ) PARENTHESIZED LATIN SMALL LETTER J +24A6;24A6;24A6;0028 006B 0029;0028 006B 0029; # (⒦; ⒦; ⒦; (k); (k); ) PARENTHESIZED LATIN SMALL LETTER K +24A7;24A7;24A7;0028 006C 0029;0028 006C 0029; # (⒧; ⒧; ⒧; (l); (l); ) PARENTHESIZED LATIN SMALL LETTER L +24A8;24A8;24A8;0028 006D 0029;0028 006D 0029; # (⒨; ⒨; ⒨; (m); (m); ) PARENTHESIZED LATIN SMALL LETTER M +24A9;24A9;24A9;0028 006E 0029;0028 006E 0029; # (⒩; ⒩; ⒩; (n); (n); ) PARENTHESIZED LATIN SMALL LETTER N +24AA;24AA;24AA;0028 006F 0029;0028 006F 0029; # (⒪; ⒪; ⒪; (o); (o); ) PARENTHESIZED LATIN SMALL LETTER O +24AB;24AB;24AB;0028 0070 0029;0028 0070 0029; # (⒫; ⒫; ⒫; (p); (p); ) PARENTHESIZED LATIN SMALL LETTER P +24AC;24AC;24AC;0028 0071 0029;0028 0071 0029; # (⒬; ⒬; ⒬; (q); (q); ) PARENTHESIZED LATIN SMALL LETTER Q +24AD;24AD;24AD;0028 0072 0029;0028 0072 0029; # (⒭; ⒭; ⒭; (r); (r); ) PARENTHESIZED LATIN SMALL LETTER R +24AE;24AE;24AE;0028 0073 0029;0028 0073 0029; # (⒮; ⒮; ⒮; (s); (s); ) PARENTHESIZED LATIN SMALL LETTER S +24AF;24AF;24AF;0028 0074 0029;0028 0074 0029; # (⒯; ⒯; ⒯; (t); (t); ) PARENTHESIZED LATIN SMALL LETTER T +24B0;24B0;24B0;0028 0075 0029;0028 0075 0029; # (⒰; ⒰; ⒰; (u); (u); ) PARENTHESIZED LATIN SMALL LETTER U +24B1;24B1;24B1;0028 0076 0029;0028 0076 0029; # (⒱; ⒱; ⒱; (v); (v); ) PARENTHESIZED LATIN SMALL LETTER V +24B2;24B2;24B2;0028 0077 0029;0028 0077 0029; # (⒲; ⒲; ⒲; (w); (w); ) PARENTHESIZED LATIN SMALL LETTER W +24B3;24B3;24B3;0028 0078 0029;0028 0078 0029; # (⒳; ⒳; ⒳; (x); (x); ) PARENTHESIZED LATIN SMALL LETTER X +24B4;24B4;24B4;0028 0079 0029;0028 0079 0029; # (⒴; ⒴; ⒴; (y); (y); ) PARENTHESIZED LATIN SMALL LETTER Y +24B5;24B5;24B5;0028 007A 0029;0028 007A 0029; # (⒵; ⒵; ⒵; (z); (z); ) PARENTHESIZED LATIN SMALL LETTER Z +24B6;24B6;24B6;0041;0041; # (Ⓐ; Ⓐ; Ⓐ; A; A; ) CIRCLED LATIN CAPITAL LETTER A +24B7;24B7;24B7;0042;0042; # (Ⓑ; Ⓑ; Ⓑ; B; B; ) CIRCLED LATIN CAPITAL LETTER B +24B8;24B8;24B8;0043;0043; # (Ⓒ; Ⓒ; Ⓒ; C; C; ) CIRCLED LATIN CAPITAL LETTER C +24B9;24B9;24B9;0044;0044; # (Ⓓ; Ⓓ; Ⓓ; D; D; ) CIRCLED LATIN CAPITAL LETTER D +24BA;24BA;24BA;0045;0045; # (Ⓔ; Ⓔ; Ⓔ; E; E; ) CIRCLED LATIN CAPITAL LETTER E +24BB;24BB;24BB;0046;0046; # (Ⓕ; Ⓕ; Ⓕ; F; F; ) CIRCLED LATIN CAPITAL LETTER F +24BC;24BC;24BC;0047;0047; # (Ⓖ; Ⓖ; Ⓖ; G; G; ) CIRCLED LATIN CAPITAL LETTER G +24BD;24BD;24BD;0048;0048; # (Ⓗ; Ⓗ; Ⓗ; H; H; ) CIRCLED LATIN CAPITAL LETTER H +24BE;24BE;24BE;0049;0049; # (Ⓘ; Ⓘ; Ⓘ; I; I; ) CIRCLED LATIN CAPITAL LETTER I +24BF;24BF;24BF;004A;004A; # (Ⓙ; Ⓙ; Ⓙ; J; J; ) CIRCLED LATIN CAPITAL LETTER J +24C0;24C0;24C0;004B;004B; # (Ⓚ; Ⓚ; Ⓚ; K; K; ) CIRCLED LATIN CAPITAL LETTER K +24C1;24C1;24C1;004C;004C; # (Ⓛ; Ⓛ; Ⓛ; L; L; ) CIRCLED LATIN CAPITAL LETTER L +24C2;24C2;24C2;004D;004D; # (Ⓜ; Ⓜ; Ⓜ; M; M; ) CIRCLED LATIN CAPITAL LETTER M +24C3;24C3;24C3;004E;004E; # (Ⓝ; Ⓝ; Ⓝ; N; N; ) CIRCLED LATIN CAPITAL LETTER N +24C4;24C4;24C4;004F;004F; # (Ⓞ; Ⓞ; Ⓞ; O; O; ) CIRCLED LATIN CAPITAL LETTER O +24C5;24C5;24C5;0050;0050; # (Ⓟ; Ⓟ; Ⓟ; P; P; ) CIRCLED LATIN CAPITAL LETTER P +24C6;24C6;24C6;0051;0051; # (Ⓠ; Ⓠ; Ⓠ; Q; Q; ) CIRCLED LATIN CAPITAL LETTER Q +24C7;24C7;24C7;0052;0052; # (Ⓡ; Ⓡ; Ⓡ; R; R; ) CIRCLED LATIN CAPITAL LETTER R +24C8;24C8;24C8;0053;0053; # (Ⓢ; Ⓢ; Ⓢ; S; S; ) CIRCLED LATIN CAPITAL LETTER S +24C9;24C9;24C9;0054;0054; # (Ⓣ; Ⓣ; Ⓣ; T; T; ) CIRCLED LATIN CAPITAL LETTER T +24CA;24CA;24CA;0055;0055; # (Ⓤ; Ⓤ; Ⓤ; U; U; ) CIRCLED LATIN CAPITAL LETTER U +24CB;24CB;24CB;0056;0056; # (Ⓥ; Ⓥ; Ⓥ; V; V; ) CIRCLED LATIN CAPITAL LETTER V +24CC;24CC;24CC;0057;0057; # (Ⓦ; Ⓦ; Ⓦ; W; W; ) CIRCLED LATIN CAPITAL LETTER W +24CD;24CD;24CD;0058;0058; # (Ⓧ; Ⓧ; Ⓧ; X; X; ) CIRCLED LATIN CAPITAL LETTER X +24CE;24CE;24CE;0059;0059; # (Ⓨ; Ⓨ; Ⓨ; Y; Y; ) CIRCLED LATIN CAPITAL LETTER Y +24CF;24CF;24CF;005A;005A; # (Ⓩ; Ⓩ; Ⓩ; Z; Z; ) CIRCLED LATIN CAPITAL LETTER Z +24D0;24D0;24D0;0061;0061; # (ⓐ; ⓐ; ⓐ; a; a; ) CIRCLED LATIN SMALL LETTER A +24D1;24D1;24D1;0062;0062; # (ⓑ; ⓑ; ⓑ; b; b; ) CIRCLED LATIN SMALL LETTER B +24D2;24D2;24D2;0063;0063; # (ⓒ; ⓒ; ⓒ; c; c; ) CIRCLED LATIN SMALL LETTER C +24D3;24D3;24D3;0064;0064; # (ⓓ; ⓓ; ⓓ; d; d; ) CIRCLED LATIN SMALL LETTER D +24D4;24D4;24D4;0065;0065; # (ⓔ; ⓔ; ⓔ; e; e; ) CIRCLED LATIN SMALL LETTER E +24D5;24D5;24D5;0066;0066; # (ⓕ; ⓕ; ⓕ; f; f; ) CIRCLED LATIN SMALL LETTER F +24D6;24D6;24D6;0067;0067; # (ⓖ; ⓖ; ⓖ; g; g; ) CIRCLED LATIN SMALL LETTER G +24D7;24D7;24D7;0068;0068; # (ⓗ; ⓗ; ⓗ; h; h; ) CIRCLED LATIN SMALL LETTER H +24D8;24D8;24D8;0069;0069; # (ⓘ; ⓘ; ⓘ; i; i; ) CIRCLED LATIN SMALL LETTER I +24D9;24D9;24D9;006A;006A; # (ⓙ; ⓙ; ⓙ; j; j; ) CIRCLED LATIN SMALL LETTER J +24DA;24DA;24DA;006B;006B; # (ⓚ; ⓚ; ⓚ; k; k; ) CIRCLED LATIN SMALL LETTER K +24DB;24DB;24DB;006C;006C; # (ⓛ; ⓛ; ⓛ; l; l; ) CIRCLED LATIN SMALL LETTER L +24DC;24DC;24DC;006D;006D; # (ⓜ; ⓜ; ⓜ; m; m; ) CIRCLED LATIN SMALL LETTER M +24DD;24DD;24DD;006E;006E; # (ⓝ; ⓝ; ⓝ; n; n; ) CIRCLED LATIN SMALL LETTER N +24DE;24DE;24DE;006F;006F; # (ⓞ; ⓞ; ⓞ; o; o; ) CIRCLED LATIN SMALL LETTER O +24DF;24DF;24DF;0070;0070; # (ⓟ; ⓟ; ⓟ; p; p; ) CIRCLED LATIN SMALL LETTER P +24E0;24E0;24E0;0071;0071; # (ⓠ; ⓠ; ⓠ; q; q; ) CIRCLED LATIN SMALL LETTER Q +24E1;24E1;24E1;0072;0072; # (ⓡ; ⓡ; ⓡ; r; r; ) CIRCLED LATIN SMALL LETTER R +24E2;24E2;24E2;0073;0073; # (ⓢ; ⓢ; ⓢ; s; s; ) CIRCLED LATIN SMALL LETTER S +24E3;24E3;24E3;0074;0074; # (ⓣ; ⓣ; ⓣ; t; t; ) CIRCLED LATIN SMALL LETTER T +24E4;24E4;24E4;0075;0075; # (ⓤ; ⓤ; ⓤ; u; u; ) CIRCLED LATIN SMALL LETTER U +24E5;24E5;24E5;0076;0076; # (ⓥ; ⓥ; ⓥ; v; v; ) CIRCLED LATIN SMALL LETTER V +24E6;24E6;24E6;0077;0077; # (ⓦ; ⓦ; ⓦ; w; w; ) CIRCLED LATIN SMALL LETTER W +24E7;24E7;24E7;0078;0078; # (ⓧ; ⓧ; ⓧ; x; x; ) CIRCLED LATIN SMALL LETTER X +24E8;24E8;24E8;0079;0079; # (ⓨ; ⓨ; ⓨ; y; y; ) CIRCLED LATIN SMALL LETTER Y +24E9;24E9;24E9;007A;007A; # (ⓩ; ⓩ; ⓩ; z; z; ) CIRCLED LATIN SMALL LETTER Z +24EA;24EA;24EA;0030;0030; # (⓪; ⓪; ⓪; 0; 0; ) CIRCLED DIGIT ZERO +2A0C;2A0C;2A0C;222B 222B 222B 222B;222B 222B 222B 222B; # (⨌; ⨌; ⨌; ∫∫∫∫; ∫∫∫∫; ) QUADRUPLE INTEGRAL OPERATOR +2A74;2A74;2A74;003A 003A 003D;003A 003A 003D; # (⩴; ⩴; ⩴; ::=; ::=; ) DOUBLE COLON EQUAL +2A75;2A75;2A75;003D 003D;003D 003D; # (⩵; ⩵; ⩵; ==; ==; ) TWO CONSECUTIVE EQUALS SIGNS +2A76;2A76;2A76;003D 003D 003D;003D 003D 003D; # (⩶; ⩶; ⩶; ===; ===; ) THREE CONSECUTIVE EQUALS SIGNS +2ADC;2ADD 0338;2ADD 0338;2ADD 0338;2ADD 0338; # (⫝̸; ⫝◌̸; ⫝◌̸; ⫝◌̸; ⫝◌̸; ) FORKING +2C7C;2C7C;2C7C;006A;006A; # (ⱼ; ⱼ; ⱼ; j; j; ) LATIN SUBSCRIPT SMALL LETTER J +2C7D;2C7D;2C7D;0056;0056; # (ⱽ; ⱽ; ⱽ; V; V; ) MODIFIER LETTER CAPITAL V +2D6F;2D6F;2D6F;2D61;2D61; # (ⵯ; ⵯ; ⵯ; ⵡ; ⵡ; ) TIFINAGH MODIFIER LETTER LABIALIZATION MARK +2E9F;2E9F;2E9F;6BCD;6BCD; # (⺟; ⺟; ⺟; 母; 母; ) CJK RADICAL MOTHER +2EF3;2EF3;2EF3;9F9F;9F9F; # (⻳; ⻳; ⻳; 龟; 龟; ) CJK RADICAL C-SIMPLIFIED TURTLE +2F00;2F00;2F00;4E00;4E00; # (⼀; ⼀; ⼀; 一; 一; ) KANGXI RADICAL ONE +2F01;2F01;2F01;4E28;4E28; # (⼁; ⼁; ⼁; 丨; 丨; ) KANGXI RADICAL LINE +2F02;2F02;2F02;4E36;4E36; # (⼂; ⼂; ⼂; 丶; 丶; ) KANGXI RADICAL DOT +2F03;2F03;2F03;4E3F;4E3F; # (⼃; ⼃; ⼃; 丿; 丿; ) KANGXI RADICAL SLASH +2F04;2F04;2F04;4E59;4E59; # (⼄; ⼄; ⼄; 乙; 乙; ) KANGXI RADICAL SECOND +2F05;2F05;2F05;4E85;4E85; # (⼅; ⼅; ⼅; 亅; 亅; ) KANGXI RADICAL HOOK +2F06;2F06;2F06;4E8C;4E8C; # (⼆; ⼆; ⼆; 二; 二; ) KANGXI RADICAL TWO +2F07;2F07;2F07;4EA0;4EA0; # (⼇; ⼇; ⼇; 亠; 亠; ) KANGXI RADICAL LID +2F08;2F08;2F08;4EBA;4EBA; # (⼈; ⼈; ⼈; 人; 人; ) KANGXI RADICAL MAN +2F09;2F09;2F09;513F;513F; # (⼉; ⼉; ⼉; 儿; 儿; ) KANGXI RADICAL LEGS +2F0A;2F0A;2F0A;5165;5165; # (⼊; ⼊; ⼊; 入; 入; ) KANGXI RADICAL ENTER +2F0B;2F0B;2F0B;516B;516B; # (⼋; ⼋; ⼋; 八; 八; ) KANGXI RADICAL EIGHT +2F0C;2F0C;2F0C;5182;5182; # (⼌; ⼌; ⼌; 冂; 冂; ) KANGXI RADICAL DOWN BOX +2F0D;2F0D;2F0D;5196;5196; # (⼍; ⼍; ⼍; 冖; 冖; ) KANGXI RADICAL COVER +2F0E;2F0E;2F0E;51AB;51AB; # (⼎; ⼎; ⼎; 冫; 冫; ) KANGXI RADICAL ICE +2F0F;2F0F;2F0F;51E0;51E0; # (⼏; ⼏; ⼏; 几; 几; ) KANGXI RADICAL TABLE +2F10;2F10;2F10;51F5;51F5; # (⼐; ⼐; ⼐; 凵; 凵; ) KANGXI RADICAL OPEN BOX +2F11;2F11;2F11;5200;5200; # (⼑; ⼑; ⼑; 刀; 刀; ) KANGXI RADICAL KNIFE +2F12;2F12;2F12;529B;529B; # (⼒; ⼒; ⼒; 力; 力; ) KANGXI RADICAL POWER +2F13;2F13;2F13;52F9;52F9; # (⼓; ⼓; ⼓; 勹; 勹; ) KANGXI RADICAL WRAP +2F14;2F14;2F14;5315;5315; # (⼔; ⼔; ⼔; 匕; 匕; ) KANGXI RADICAL SPOON +2F15;2F15;2F15;531A;531A; # (⼕; ⼕; ⼕; 匚; 匚; ) KANGXI RADICAL RIGHT OPEN BOX +2F16;2F16;2F16;5338;5338; # (⼖; ⼖; ⼖; 匸; 匸; ) KANGXI RADICAL HIDING ENCLOSURE +2F17;2F17;2F17;5341;5341; # (⼗; ⼗; ⼗; 十; 十; ) KANGXI RADICAL TEN +2F18;2F18;2F18;535C;535C; # (⼘; ⼘; ⼘; 卜; 卜; ) KANGXI RADICAL DIVINATION +2F19;2F19;2F19;5369;5369; # (⼙; ⼙; ⼙; 卩; 卩; ) KANGXI RADICAL SEAL +2F1A;2F1A;2F1A;5382;5382; # (⼚; ⼚; ⼚; 厂; 厂; ) KANGXI RADICAL CLIFF +2F1B;2F1B;2F1B;53B6;53B6; # (⼛; ⼛; ⼛; 厶; 厶; ) KANGXI RADICAL PRIVATE +2F1C;2F1C;2F1C;53C8;53C8; # (⼜; ⼜; ⼜; 又; 又; ) KANGXI RADICAL AGAIN +2F1D;2F1D;2F1D;53E3;53E3; # (⼝; ⼝; ⼝; 口; 口; ) KANGXI RADICAL MOUTH +2F1E;2F1E;2F1E;56D7;56D7; # (⼞; ⼞; ⼞; 囗; 囗; ) KANGXI RADICAL ENCLOSURE +2F1F;2F1F;2F1F;571F;571F; # (⼟; ⼟; ⼟; 土; 土; ) KANGXI RADICAL EARTH +2F20;2F20;2F20;58EB;58EB; # (⼠; ⼠; ⼠; 士; 士; ) KANGXI RADICAL SCHOLAR +2F21;2F21;2F21;5902;5902; # (⼡; ⼡; ⼡; 夂; 夂; ) KANGXI RADICAL GO +2F22;2F22;2F22;590A;590A; # (⼢; ⼢; ⼢; 夊; 夊; ) KANGXI RADICAL GO SLOWLY +2F23;2F23;2F23;5915;5915; # (⼣; ⼣; ⼣; 夕; 夕; ) KANGXI RADICAL EVENING +2F24;2F24;2F24;5927;5927; # (⼤; ⼤; ⼤; 大; 大; ) KANGXI RADICAL BIG +2F25;2F25;2F25;5973;5973; # (⼥; ⼥; ⼥; 女; 女; ) KANGXI RADICAL WOMAN +2F26;2F26;2F26;5B50;5B50; # (⼦; ⼦; ⼦; 子; 子; ) KANGXI RADICAL CHILD +2F27;2F27;2F27;5B80;5B80; # (⼧; ⼧; ⼧; 宀; 宀; ) KANGXI RADICAL ROOF +2F28;2F28;2F28;5BF8;5BF8; # (⼨; ⼨; ⼨; 寸; 寸; ) KANGXI RADICAL INCH +2F29;2F29;2F29;5C0F;5C0F; # (⼩; ⼩; ⼩; 小; 小; ) KANGXI RADICAL SMALL +2F2A;2F2A;2F2A;5C22;5C22; # (⼪; ⼪; ⼪; 尢; 尢; ) KANGXI RADICAL LAME +2F2B;2F2B;2F2B;5C38;5C38; # (⼫; ⼫; ⼫; 尸; 尸; ) KANGXI RADICAL CORPSE +2F2C;2F2C;2F2C;5C6E;5C6E; # (⼬; ⼬; ⼬; 屮; 屮; ) KANGXI RADICAL SPROUT +2F2D;2F2D;2F2D;5C71;5C71; # (⼭; ⼭; ⼭; 山; 山; ) KANGXI RADICAL MOUNTAIN +2F2E;2F2E;2F2E;5DDB;5DDB; # (⼮; ⼮; ⼮; 巛; 巛; ) KANGXI RADICAL RIVER +2F2F;2F2F;2F2F;5DE5;5DE5; # (⼯; ⼯; ⼯; 工; 工; ) KANGXI RADICAL WORK +2F30;2F30;2F30;5DF1;5DF1; # (⼰; ⼰; ⼰; 己; 己; ) KANGXI RADICAL ONESELF +2F31;2F31;2F31;5DFE;5DFE; # (⼱; ⼱; ⼱; 巾; 巾; ) KANGXI RADICAL TURBAN +2F32;2F32;2F32;5E72;5E72; # (⼲; ⼲; ⼲; 干; 干; ) KANGXI RADICAL DRY +2F33;2F33;2F33;5E7A;5E7A; # (⼳; ⼳; ⼳; 幺; 幺; ) KANGXI RADICAL SHORT THREAD +2F34;2F34;2F34;5E7F;5E7F; # (⼴; ⼴; ⼴; 广; 广; ) KANGXI RADICAL DOTTED CLIFF +2F35;2F35;2F35;5EF4;5EF4; # (⼵; ⼵; ⼵; 廴; 廴; ) KANGXI RADICAL LONG STRIDE +2F36;2F36;2F36;5EFE;5EFE; # (⼶; ⼶; ⼶; 廾; 廾; ) KANGXI RADICAL TWO HANDS +2F37;2F37;2F37;5F0B;5F0B; # (⼷; ⼷; ⼷; 弋; 弋; ) KANGXI RADICAL SHOOT +2F38;2F38;2F38;5F13;5F13; # (⼸; ⼸; ⼸; 弓; 弓; ) KANGXI RADICAL BOW +2F39;2F39;2F39;5F50;5F50; # (⼹; ⼹; ⼹; 彐; 彐; ) KANGXI RADICAL SNOUT +2F3A;2F3A;2F3A;5F61;5F61; # (⼺; ⼺; ⼺; 彡; 彡; ) KANGXI RADICAL BRISTLE +2F3B;2F3B;2F3B;5F73;5F73; # (⼻; ⼻; ⼻; 彳; 彳; ) KANGXI RADICAL STEP +2F3C;2F3C;2F3C;5FC3;5FC3; # (⼼; ⼼; ⼼; 心; 心; ) KANGXI RADICAL HEART +2F3D;2F3D;2F3D;6208;6208; # (⼽; ⼽; ⼽; 戈; 戈; ) KANGXI RADICAL HALBERD +2F3E;2F3E;2F3E;6236;6236; # (⼾; ⼾; ⼾; 戶; 戶; ) KANGXI RADICAL DOOR +2F3F;2F3F;2F3F;624B;624B; # (⼿; ⼿; ⼿; 手; 手; ) KANGXI RADICAL HAND +2F40;2F40;2F40;652F;652F; # (⽀; ⽀; ⽀; 支; 支; ) KANGXI RADICAL BRANCH +2F41;2F41;2F41;6534;6534; # (⽁; ⽁; ⽁; 攴; 攴; ) KANGXI RADICAL RAP +2F42;2F42;2F42;6587;6587; # (⽂; ⽂; ⽂; 文; 文; ) KANGXI RADICAL SCRIPT +2F43;2F43;2F43;6597;6597; # (⽃; ⽃; ⽃; 斗; 斗; ) KANGXI RADICAL DIPPER +2F44;2F44;2F44;65A4;65A4; # (⽄; ⽄; ⽄; 斤; 斤; ) KANGXI RADICAL AXE +2F45;2F45;2F45;65B9;65B9; # (⽅; ⽅; ⽅; 方; 方; ) KANGXI RADICAL SQUARE +2F46;2F46;2F46;65E0;65E0; # (⽆; ⽆; ⽆; 无; 无; ) KANGXI RADICAL NOT +2F47;2F47;2F47;65E5;65E5; # (⽇; ⽇; ⽇; 日; 日; ) KANGXI RADICAL SUN +2F48;2F48;2F48;66F0;66F0; # (⽈; ⽈; ⽈; 曰; 曰; ) KANGXI RADICAL SAY +2F49;2F49;2F49;6708;6708; # (⽉; ⽉; ⽉; 月; 月; ) KANGXI RADICAL MOON +2F4A;2F4A;2F4A;6728;6728; # (⽊; ⽊; ⽊; 木; 木; ) KANGXI RADICAL TREE +2F4B;2F4B;2F4B;6B20;6B20; # (⽋; ⽋; ⽋; 欠; 欠; ) KANGXI RADICAL LACK +2F4C;2F4C;2F4C;6B62;6B62; # (⽌; ⽌; ⽌; 止; 止; ) KANGXI RADICAL STOP +2F4D;2F4D;2F4D;6B79;6B79; # (⽍; ⽍; ⽍; 歹; 歹; ) KANGXI RADICAL DEATH +2F4E;2F4E;2F4E;6BB3;6BB3; # (⽎; ⽎; ⽎; 殳; 殳; ) KANGXI RADICAL WEAPON +2F4F;2F4F;2F4F;6BCB;6BCB; # (⽏; ⽏; ⽏; 毋; 毋; ) KANGXI RADICAL DO NOT +2F50;2F50;2F50;6BD4;6BD4; # (⽐; ⽐; ⽐; 比; 比; ) KANGXI RADICAL COMPARE +2F51;2F51;2F51;6BDB;6BDB; # (⽑; ⽑; ⽑; 毛; 毛; ) KANGXI RADICAL FUR +2F52;2F52;2F52;6C0F;6C0F; # (⽒; ⽒; ⽒; 氏; 氏; ) KANGXI RADICAL CLAN +2F53;2F53;2F53;6C14;6C14; # (⽓; ⽓; ⽓; 气; 气; ) KANGXI RADICAL STEAM +2F54;2F54;2F54;6C34;6C34; # (⽔; ⽔; ⽔; 水; 水; ) KANGXI RADICAL WATER +2F55;2F55;2F55;706B;706B; # (⽕; ⽕; ⽕; 火; 火; ) KANGXI RADICAL FIRE +2F56;2F56;2F56;722A;722A; # (⽖; ⽖; ⽖; 爪; 爪; ) KANGXI RADICAL CLAW +2F57;2F57;2F57;7236;7236; # (⽗; ⽗; ⽗; 父; 父; ) KANGXI RADICAL FATHER +2F58;2F58;2F58;723B;723B; # (⽘; ⽘; ⽘; 爻; 爻; ) KANGXI RADICAL DOUBLE X +2F59;2F59;2F59;723F;723F; # (⽙; ⽙; ⽙; 爿; 爿; ) KANGXI RADICAL HALF TREE TRUNK +2F5A;2F5A;2F5A;7247;7247; # (⽚; ⽚; ⽚; 片; 片; ) KANGXI RADICAL SLICE +2F5B;2F5B;2F5B;7259;7259; # (⽛; ⽛; ⽛; 牙; 牙; ) KANGXI RADICAL FANG +2F5C;2F5C;2F5C;725B;725B; # (⽜; ⽜; ⽜; 牛; 牛; ) KANGXI RADICAL COW +2F5D;2F5D;2F5D;72AC;72AC; # (⽝; ⽝; ⽝; 犬; 犬; ) KANGXI RADICAL DOG +2F5E;2F5E;2F5E;7384;7384; # (⽞; ⽞; ⽞; 玄; 玄; ) KANGXI RADICAL PROFOUND +2F5F;2F5F;2F5F;7389;7389; # (⽟; ⽟; ⽟; 玉; 玉; ) KANGXI RADICAL JADE +2F60;2F60;2F60;74DC;74DC; # (⽠; ⽠; ⽠; 瓜; 瓜; ) KANGXI RADICAL MELON +2F61;2F61;2F61;74E6;74E6; # (⽡; ⽡; ⽡; 瓦; 瓦; ) KANGXI RADICAL TILE +2F62;2F62;2F62;7518;7518; # (⽢; ⽢; ⽢; 甘; 甘; ) KANGXI RADICAL SWEET +2F63;2F63;2F63;751F;751F; # (⽣; ⽣; ⽣; 生; 生; ) KANGXI RADICAL LIFE +2F64;2F64;2F64;7528;7528; # (⽤; ⽤; ⽤; 用; 用; ) KANGXI RADICAL USE +2F65;2F65;2F65;7530;7530; # (⽥; ⽥; ⽥; 田; 田; ) KANGXI RADICAL FIELD +2F66;2F66;2F66;758B;758B; # (⽦; ⽦; ⽦; 疋; 疋; ) KANGXI RADICAL BOLT OF CLOTH +2F67;2F67;2F67;7592;7592; # (⽧; ⽧; ⽧; 疒; 疒; ) KANGXI RADICAL SICKNESS +2F68;2F68;2F68;7676;7676; # (⽨; ⽨; ⽨; 癶; 癶; ) KANGXI RADICAL DOTTED TENT +2F69;2F69;2F69;767D;767D; # (⽩; ⽩; ⽩; 白; 白; ) KANGXI RADICAL WHITE +2F6A;2F6A;2F6A;76AE;76AE; # (⽪; ⽪; ⽪; 皮; 皮; ) KANGXI RADICAL SKIN +2F6B;2F6B;2F6B;76BF;76BF; # (⽫; ⽫; ⽫; 皿; 皿; ) KANGXI RADICAL DISH +2F6C;2F6C;2F6C;76EE;76EE; # (⽬; ⽬; ⽬; 目; 目; ) KANGXI RADICAL EYE +2F6D;2F6D;2F6D;77DB;77DB; # (⽭; ⽭; ⽭; 矛; 矛; ) KANGXI RADICAL SPEAR +2F6E;2F6E;2F6E;77E2;77E2; # (⽮; ⽮; ⽮; 矢; 矢; ) KANGXI RADICAL ARROW +2F6F;2F6F;2F6F;77F3;77F3; # (⽯; ⽯; ⽯; 石; 石; ) KANGXI RADICAL STONE +2F70;2F70;2F70;793A;793A; # (⽰; ⽰; ⽰; 示; 示; ) KANGXI RADICAL SPIRIT +2F71;2F71;2F71;79B8;79B8; # (⽱; ⽱; ⽱; 禸; 禸; ) KANGXI RADICAL TRACK +2F72;2F72;2F72;79BE;79BE; # (⽲; ⽲; ⽲; 禾; 禾; ) KANGXI RADICAL GRAIN +2F73;2F73;2F73;7A74;7A74; # (⽳; ⽳; ⽳; 穴; 穴; ) KANGXI RADICAL CAVE +2F74;2F74;2F74;7ACB;7ACB; # (⽴; ⽴; ⽴; 立; 立; ) KANGXI RADICAL STAND +2F75;2F75;2F75;7AF9;7AF9; # (⽵; ⽵; ⽵; 竹; 竹; ) KANGXI RADICAL BAMBOO +2F76;2F76;2F76;7C73;7C73; # (⽶; ⽶; ⽶; 米; 米; ) KANGXI RADICAL RICE +2F77;2F77;2F77;7CF8;7CF8; # (⽷; ⽷; ⽷; 糸; 糸; ) KANGXI RADICAL SILK +2F78;2F78;2F78;7F36;7F36; # (⽸; ⽸; ⽸; 缶; 缶; ) KANGXI RADICAL JAR +2F79;2F79;2F79;7F51;7F51; # (⽹; ⽹; ⽹; 网; 网; ) KANGXI RADICAL NET +2F7A;2F7A;2F7A;7F8A;7F8A; # (⽺; ⽺; ⽺; 羊; 羊; ) KANGXI RADICAL SHEEP +2F7B;2F7B;2F7B;7FBD;7FBD; # (⽻; ⽻; ⽻; 羽; 羽; ) KANGXI RADICAL FEATHER +2F7C;2F7C;2F7C;8001;8001; # (⽼; ⽼; ⽼; 老; 老; ) KANGXI RADICAL OLD +2F7D;2F7D;2F7D;800C;800C; # (⽽; ⽽; ⽽; 而; 而; ) KANGXI RADICAL AND +2F7E;2F7E;2F7E;8012;8012; # (⽾; ⽾; ⽾; 耒; 耒; ) KANGXI RADICAL PLOW +2F7F;2F7F;2F7F;8033;8033; # (⽿; ⽿; ⽿; 耳; 耳; ) KANGXI RADICAL EAR +2F80;2F80;2F80;807F;807F; # (⾀; ⾀; ⾀; 聿; 聿; ) KANGXI RADICAL BRUSH +2F81;2F81;2F81;8089;8089; # (⾁; ⾁; ⾁; 肉; 肉; ) KANGXI RADICAL MEAT +2F82;2F82;2F82;81E3;81E3; # (⾂; ⾂; ⾂; 臣; 臣; ) KANGXI RADICAL MINISTER +2F83;2F83;2F83;81EA;81EA; # (⾃; ⾃; ⾃; 自; 自; ) KANGXI RADICAL SELF +2F84;2F84;2F84;81F3;81F3; # (⾄; ⾄; ⾄; 至; 至; ) KANGXI RADICAL ARRIVE +2F85;2F85;2F85;81FC;81FC; # (⾅; ⾅; ⾅; 臼; 臼; ) KANGXI RADICAL MORTAR +2F86;2F86;2F86;820C;820C; # (⾆; ⾆; ⾆; 舌; 舌; ) KANGXI RADICAL TONGUE +2F87;2F87;2F87;821B;821B; # (⾇; ⾇; ⾇; 舛; 舛; ) KANGXI RADICAL OPPOSE +2F88;2F88;2F88;821F;821F; # (⾈; ⾈; ⾈; 舟; 舟; ) KANGXI RADICAL BOAT +2F89;2F89;2F89;826E;826E; # (⾉; ⾉; ⾉; 艮; 艮; ) KANGXI RADICAL STOPPING +2F8A;2F8A;2F8A;8272;8272; # (⾊; ⾊; ⾊; 色; 色; ) KANGXI RADICAL COLOR +2F8B;2F8B;2F8B;8278;8278; # (⾋; ⾋; ⾋; 艸; 艸; ) KANGXI RADICAL GRASS +2F8C;2F8C;2F8C;864D;864D; # (⾌; ⾌; ⾌; 虍; 虍; ) KANGXI RADICAL TIGER +2F8D;2F8D;2F8D;866B;866B; # (⾍; ⾍; ⾍; 虫; 虫; ) KANGXI RADICAL INSECT +2F8E;2F8E;2F8E;8840;8840; # (⾎; ⾎; ⾎; 血; 血; ) KANGXI RADICAL BLOOD +2F8F;2F8F;2F8F;884C;884C; # (⾏; ⾏; ⾏; 行; 行; ) KANGXI RADICAL WALK ENCLOSURE +2F90;2F90;2F90;8863;8863; # (⾐; ⾐; ⾐; 衣; 衣; ) KANGXI RADICAL CLOTHES +2F91;2F91;2F91;897E;897E; # (⾑; ⾑; ⾑; 襾; 襾; ) KANGXI RADICAL WEST +2F92;2F92;2F92;898B;898B; # (⾒; ⾒; ⾒; 見; 見; ) KANGXI RADICAL SEE +2F93;2F93;2F93;89D2;89D2; # (⾓; ⾓; ⾓; 角; 角; ) KANGXI RADICAL HORN +2F94;2F94;2F94;8A00;8A00; # (⾔; ⾔; ⾔; 言; 言; ) KANGXI RADICAL SPEECH +2F95;2F95;2F95;8C37;8C37; # (⾕; ⾕; ⾕; 谷; 谷; ) KANGXI RADICAL VALLEY +2F96;2F96;2F96;8C46;8C46; # (⾖; ⾖; ⾖; 豆; 豆; ) KANGXI RADICAL BEAN +2F97;2F97;2F97;8C55;8C55; # (⾗; ⾗; ⾗; 豕; 豕; ) KANGXI RADICAL PIG +2F98;2F98;2F98;8C78;8C78; # (⾘; ⾘; ⾘; 豸; 豸; ) KANGXI RADICAL BADGER +2F99;2F99;2F99;8C9D;8C9D; # (⾙; ⾙; ⾙; 貝; 貝; ) KANGXI RADICAL SHELL +2F9A;2F9A;2F9A;8D64;8D64; # (⾚; ⾚; ⾚; 赤; 赤; ) KANGXI RADICAL RED +2F9B;2F9B;2F9B;8D70;8D70; # (⾛; ⾛; ⾛; 走; 走; ) KANGXI RADICAL RUN +2F9C;2F9C;2F9C;8DB3;8DB3; # (⾜; ⾜; ⾜; 足; 足; ) KANGXI RADICAL FOOT +2F9D;2F9D;2F9D;8EAB;8EAB; # (⾝; ⾝; ⾝; 身; 身; ) KANGXI RADICAL BODY +2F9E;2F9E;2F9E;8ECA;8ECA; # (⾞; ⾞; ⾞; 車; 車; ) KANGXI RADICAL CART +2F9F;2F9F;2F9F;8F9B;8F9B; # (⾟; ⾟; ⾟; 辛; 辛; ) KANGXI RADICAL BITTER +2FA0;2FA0;2FA0;8FB0;8FB0; # (⾠; ⾠; ⾠; 辰; 辰; ) KANGXI RADICAL MORNING +2FA1;2FA1;2FA1;8FB5;8FB5; # (⾡; ⾡; ⾡; 辵; 辵; ) KANGXI RADICAL WALK +2FA2;2FA2;2FA2;9091;9091; # (⾢; ⾢; ⾢; 邑; 邑; ) KANGXI RADICAL CITY +2FA3;2FA3;2FA3;9149;9149; # (⾣; ⾣; ⾣; 酉; 酉; ) KANGXI RADICAL WINE +2FA4;2FA4;2FA4;91C6;91C6; # (⾤; ⾤; ⾤; 釆; 釆; ) KANGXI RADICAL DISTINGUISH +2FA5;2FA5;2FA5;91CC;91CC; # (⾥; ⾥; ⾥; 里; 里; ) KANGXI RADICAL VILLAGE +2FA6;2FA6;2FA6;91D1;91D1; # (⾦; ⾦; ⾦; 金; 金; ) KANGXI RADICAL GOLD +2FA7;2FA7;2FA7;9577;9577; # (⾧; ⾧; ⾧; 長; 長; ) KANGXI RADICAL LONG +2FA8;2FA8;2FA8;9580;9580; # (⾨; ⾨; ⾨; 門; 門; ) KANGXI RADICAL GATE +2FA9;2FA9;2FA9;961C;961C; # (⾩; ⾩; ⾩; 阜; 阜; ) KANGXI RADICAL MOUND +2FAA;2FAA;2FAA;96B6;96B6; # (⾪; ⾪; ⾪; 隶; 隶; ) KANGXI RADICAL SLAVE +2FAB;2FAB;2FAB;96B9;96B9; # (⾫; ⾫; ⾫; 隹; 隹; ) KANGXI RADICAL SHORT TAILED BIRD +2FAC;2FAC;2FAC;96E8;96E8; # (⾬; ⾬; ⾬; 雨; 雨; ) KANGXI RADICAL RAIN +2FAD;2FAD;2FAD;9751;9751; # (⾭; ⾭; ⾭; 靑; 靑; ) KANGXI RADICAL BLUE +2FAE;2FAE;2FAE;975E;975E; # (⾮; ⾮; ⾮; 非; 非; ) KANGXI RADICAL WRONG +2FAF;2FAF;2FAF;9762;9762; # (⾯; ⾯; ⾯; 面; 面; ) KANGXI RADICAL FACE +2FB0;2FB0;2FB0;9769;9769; # (⾰; ⾰; ⾰; 革; 革; ) KANGXI RADICAL LEATHER +2FB1;2FB1;2FB1;97CB;97CB; # (⾱; ⾱; ⾱; 韋; 韋; ) KANGXI RADICAL TANNED LEATHER +2FB2;2FB2;2FB2;97ED;97ED; # (⾲; ⾲; ⾲; 韭; 韭; ) KANGXI RADICAL LEEK +2FB3;2FB3;2FB3;97F3;97F3; # (⾳; ⾳; ⾳; 音; 音; ) KANGXI RADICAL SOUND +2FB4;2FB4;2FB4;9801;9801; # (⾴; ⾴; ⾴; 頁; 頁; ) KANGXI RADICAL LEAF +2FB5;2FB5;2FB5;98A8;98A8; # (⾵; ⾵; ⾵; 風; 風; ) KANGXI RADICAL WIND +2FB6;2FB6;2FB6;98DB;98DB; # (⾶; ⾶; ⾶; 飛; 飛; ) KANGXI RADICAL FLY +2FB7;2FB7;2FB7;98DF;98DF; # (⾷; ⾷; ⾷; 食; 食; ) KANGXI RADICAL EAT +2FB8;2FB8;2FB8;9996;9996; # (⾸; ⾸; ⾸; 首; 首; ) KANGXI RADICAL HEAD +2FB9;2FB9;2FB9;9999;9999; # (⾹; ⾹; ⾹; 香; 香; ) KANGXI RADICAL FRAGRANT +2FBA;2FBA;2FBA;99AC;99AC; # (⾺; ⾺; ⾺; 馬; 馬; ) KANGXI RADICAL HORSE +2FBB;2FBB;2FBB;9AA8;9AA8; # (⾻; ⾻; ⾻; 骨; 骨; ) KANGXI RADICAL BONE +2FBC;2FBC;2FBC;9AD8;9AD8; # (⾼; ⾼; ⾼; 高; 高; ) KANGXI RADICAL TALL +2FBD;2FBD;2FBD;9ADF;9ADF; # (⾽; ⾽; ⾽; 髟; 髟; ) KANGXI RADICAL HAIR +2FBE;2FBE;2FBE;9B25;9B25; # (⾾; ⾾; ⾾; 鬥; 鬥; ) KANGXI RADICAL FIGHT +2FBF;2FBF;2FBF;9B2F;9B2F; # (⾿; ⾿; ⾿; 鬯; 鬯; ) KANGXI RADICAL SACRIFICIAL WINE +2FC0;2FC0;2FC0;9B32;9B32; # (⿀; ⿀; ⿀; 鬲; 鬲; ) KANGXI RADICAL CAULDRON +2FC1;2FC1;2FC1;9B3C;9B3C; # (⿁; ⿁; ⿁; 鬼; 鬼; ) KANGXI RADICAL GHOST +2FC2;2FC2;2FC2;9B5A;9B5A; # (⿂; ⿂; ⿂; 魚; 魚; ) KANGXI RADICAL FISH +2FC3;2FC3;2FC3;9CE5;9CE5; # (⿃; ⿃; ⿃; 鳥; 鳥; ) KANGXI RADICAL BIRD +2FC4;2FC4;2FC4;9E75;9E75; # (⿄; ⿄; ⿄; 鹵; 鹵; ) KANGXI RADICAL SALT +2FC5;2FC5;2FC5;9E7F;9E7F; # (⿅; ⿅; ⿅; 鹿; 鹿; ) KANGXI RADICAL DEER +2FC6;2FC6;2FC6;9EA5;9EA5; # (⿆; ⿆; ⿆; 麥; 麥; ) KANGXI RADICAL WHEAT +2FC7;2FC7;2FC7;9EBB;9EBB; # (⿇; ⿇; ⿇; 麻; 麻; ) KANGXI RADICAL HEMP +2FC8;2FC8;2FC8;9EC3;9EC3; # (⿈; ⿈; ⿈; 黃; 黃; ) KANGXI RADICAL YELLOW +2FC9;2FC9;2FC9;9ECD;9ECD; # (⿉; ⿉; ⿉; 黍; 黍; ) KANGXI RADICAL MILLET +2FCA;2FCA;2FCA;9ED1;9ED1; # (⿊; ⿊; ⿊; 黑; 黑; ) KANGXI RADICAL BLACK +2FCB;2FCB;2FCB;9EF9;9EF9; # (⿋; ⿋; ⿋; 黹; 黹; ) KANGXI RADICAL EMBROIDERY +2FCC;2FCC;2FCC;9EFD;9EFD; # (⿌; ⿌; ⿌; 黽; 黽; ) KANGXI RADICAL FROG +2FCD;2FCD;2FCD;9F0E;9F0E; # (⿍; ⿍; ⿍; 鼎; 鼎; ) KANGXI RADICAL TRIPOD +2FCE;2FCE;2FCE;9F13;9F13; # (⿎; ⿎; ⿎; 鼓; 鼓; ) KANGXI RADICAL DRUM +2FCF;2FCF;2FCF;9F20;9F20; # (⿏; ⿏; ⿏; 鼠; 鼠; ) KANGXI RADICAL RAT +2FD0;2FD0;2FD0;9F3B;9F3B; # (⿐; ⿐; ⿐; 鼻; 鼻; ) KANGXI RADICAL NOSE +2FD1;2FD1;2FD1;9F4A;9F4A; # (⿑; ⿑; ⿑; 齊; 齊; ) KANGXI RADICAL EVEN +2FD2;2FD2;2FD2;9F52;9F52; # (⿒; ⿒; ⿒; 齒; 齒; ) KANGXI RADICAL TOOTH +2FD3;2FD3;2FD3;9F8D;9F8D; # (⿓; ⿓; ⿓; 龍; 龍; ) KANGXI RADICAL DRAGON +2FD4;2FD4;2FD4;9F9C;9F9C; # (⿔; ⿔; ⿔; 龜; 龜; ) KANGXI RADICAL TURTLE +2FD5;2FD5;2FD5;9FA0;9FA0; # (⿕; ⿕; ⿕; 龠; 龠; ) KANGXI RADICAL FLUTE +3000;3000;3000;0020;0020; # ( ;  ;  ; ; ; ) IDEOGRAPHIC SPACE +3036;3036;3036;3012;3012; # (〶; 〶; 〶; 〒; 〒; ) CIRCLED POSTAL MARK +3038;3038;3038;5341;5341; # (〸; 〸; 〸; 十; 十; ) HANGZHOU NUMERAL TEN +3039;3039;3039;5344;5344; # (〹; 〹; 〹; 卄; 卄; ) HANGZHOU NUMERAL TWENTY +303A;303A;303A;5345;5345; # (〺; 〺; 〺; 卅; 卅; ) HANGZHOU NUMERAL THIRTY +304C;304C;304B 3099;304C;304B 3099; # (が; が; か◌゙; が; か◌゙; ) HIRAGANA LETTER GA +304E;304E;304D 3099;304E;304D 3099; # (ぎ; ぎ; き◌゙; ぎ; き◌゙; ) HIRAGANA LETTER GI +3050;3050;304F 3099;3050;304F 3099; # (ぐ; ぐ; く◌゙; ぐ; く◌゙; ) HIRAGANA LETTER GU +3052;3052;3051 3099;3052;3051 3099; # (げ; げ; け◌゙; げ; け◌゙; ) HIRAGANA LETTER GE +3054;3054;3053 3099;3054;3053 3099; # (ご; ご; こ◌゙; ご; こ◌゙; ) HIRAGANA LETTER GO +3056;3056;3055 3099;3056;3055 3099; # (ざ; ざ; さ◌゙; ざ; さ◌゙; ) HIRAGANA LETTER ZA +3058;3058;3057 3099;3058;3057 3099; # (じ; じ; し◌゙; じ; し◌゙; ) HIRAGANA LETTER ZI +305A;305A;3059 3099;305A;3059 3099; # (ず; ず; す◌゙; ず; す◌゙; ) HIRAGANA LETTER ZU +305C;305C;305B 3099;305C;305B 3099; # (ぜ; ぜ; せ◌゙; ぜ; せ◌゙; ) HIRAGANA LETTER ZE +305E;305E;305D 3099;305E;305D 3099; # (ぞ; ぞ; そ◌゙; ぞ; そ◌゙; ) HIRAGANA LETTER ZO +3060;3060;305F 3099;3060;305F 3099; # (だ; だ; た◌゙; だ; た◌゙; ) HIRAGANA LETTER DA +3062;3062;3061 3099;3062;3061 3099; # (ぢ; ぢ; ち◌゙; ぢ; ち◌゙; ) HIRAGANA LETTER DI +3065;3065;3064 3099;3065;3064 3099; # (づ; づ; つ◌゙; づ; つ◌゙; ) HIRAGANA LETTER DU +3067;3067;3066 3099;3067;3066 3099; # (で; で; て◌゙; で; て◌゙; ) HIRAGANA LETTER DE +3069;3069;3068 3099;3069;3068 3099; # (ど; ど; と◌゙; ど; と◌゙; ) HIRAGANA LETTER DO +3070;3070;306F 3099;3070;306F 3099; # (ば; ば; は◌゙; ば; は◌゙; ) HIRAGANA LETTER BA +3071;3071;306F 309A;3071;306F 309A; # (ぱ; ぱ; は◌゚; ぱ; は◌゚; ) HIRAGANA LETTER PA +3073;3073;3072 3099;3073;3072 3099; # (び; び; ひ◌゙; び; ひ◌゙; ) HIRAGANA LETTER BI +3074;3074;3072 309A;3074;3072 309A; # (ぴ; ぴ; ひ◌゚; ぴ; ひ◌゚; ) HIRAGANA LETTER PI +3076;3076;3075 3099;3076;3075 3099; # (ぶ; ぶ; ふ◌゙; ぶ; ふ◌゙; ) HIRAGANA LETTER BU +3077;3077;3075 309A;3077;3075 309A; # (ぷ; ぷ; ふ◌゚; ぷ; ふ◌゚; ) HIRAGANA LETTER PU +3079;3079;3078 3099;3079;3078 3099; # (べ; べ; へ◌゙; べ; へ◌゙; ) HIRAGANA LETTER BE +307A;307A;3078 309A;307A;3078 309A; # (ぺ; ぺ; へ◌゚; ぺ; へ◌゚; ) HIRAGANA LETTER PE +307C;307C;307B 3099;307C;307B 3099; # (ぼ; ぼ; ほ◌゙; ぼ; ほ◌゙; ) HIRAGANA LETTER BO +307D;307D;307B 309A;307D;307B 309A; # (ぽ; ぽ; ほ◌゚; ぽ; ほ◌゚; ) HIRAGANA LETTER PO +3094;3094;3046 3099;3094;3046 3099; # (ゔ; ゔ; う◌゙; ゔ; う◌゙; ) HIRAGANA LETTER VU +309B;309B;309B;0020 3099;0020 3099; # (゛; ゛; ゛; ◌゙; ◌゙; ) KATAKANA-HIRAGANA VOICED SOUND MARK +309C;309C;309C;0020 309A;0020 309A; # (゜; ゜; ゜; ◌゚; ◌゚; ) KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309E;309E;309D 3099;309E;309D 3099; # (ゞ; ゞ; ゝ◌゙; ゞ; ゝ◌゙; ) HIRAGANA VOICED ITERATION MARK +309F;309F;309F;3088 308A;3088 308A; # (ゟ; ゟ; ゟ; より; より; ) HIRAGANA DIGRAPH YORI +30AC;30AC;30AB 3099;30AC;30AB 3099; # (ガ; ガ; カ◌゙; ガ; カ◌゙; ) KATAKANA LETTER GA +30AE;30AE;30AD 3099;30AE;30AD 3099; # (ギ; ギ; キ◌゙; ギ; キ◌゙; ) KATAKANA LETTER GI +30B0;30B0;30AF 3099;30B0;30AF 3099; # (グ; グ; ク◌゙; グ; ク◌゙; ) KATAKANA LETTER GU +30B2;30B2;30B1 3099;30B2;30B1 3099; # (ゲ; ゲ; ケ◌゙; ゲ; ケ◌゙; ) KATAKANA LETTER GE +30B4;30B4;30B3 3099;30B4;30B3 3099; # (ゴ; ゴ; コ◌゙; ゴ; コ◌゙; ) KATAKANA LETTER GO +30B6;30B6;30B5 3099;30B6;30B5 3099; # (ザ; ザ; サ◌゙; ザ; サ◌゙; ) KATAKANA LETTER ZA +30B8;30B8;30B7 3099;30B8;30B7 3099; # (ジ; ジ; シ◌゙; ジ; シ◌゙; ) KATAKANA LETTER ZI +30BA;30BA;30B9 3099;30BA;30B9 3099; # (ズ; ズ; ス◌゙; ズ; ス◌゙; ) KATAKANA LETTER ZU +30BC;30BC;30BB 3099;30BC;30BB 3099; # (ゼ; ゼ; セ◌゙; ゼ; セ◌゙; ) KATAKANA LETTER ZE +30BE;30BE;30BD 3099;30BE;30BD 3099; # (ゾ; ゾ; ソ◌゙; ゾ; ソ◌゙; ) KATAKANA LETTER ZO +30C0;30C0;30BF 3099;30C0;30BF 3099; # (ダ; ダ; タ◌゙; ダ; タ◌゙; ) KATAKANA LETTER DA +30C2;30C2;30C1 3099;30C2;30C1 3099; # (ヂ; ヂ; チ◌゙; ヂ; チ◌゙; ) KATAKANA LETTER DI +30C5;30C5;30C4 3099;30C5;30C4 3099; # (ヅ; ヅ; ツ◌゙; ヅ; ツ◌゙; ) KATAKANA LETTER DU +30C7;30C7;30C6 3099;30C7;30C6 3099; # (デ; デ; テ◌゙; デ; テ◌゙; ) KATAKANA LETTER DE +30C9;30C9;30C8 3099;30C9;30C8 3099; # (ド; ド; ト◌゙; ド; ト◌゙; ) KATAKANA LETTER DO +30D0;30D0;30CF 3099;30D0;30CF 3099; # (バ; バ; ハ◌゙; バ; ハ◌゙; ) KATAKANA LETTER BA +30D1;30D1;30CF 309A;30D1;30CF 309A; # (パ; パ; ハ◌゚; パ; ハ◌゚; ) KATAKANA LETTER PA +30D3;30D3;30D2 3099;30D3;30D2 3099; # (ビ; ビ; ヒ◌゙; ビ; ヒ◌゙; ) KATAKANA LETTER BI +30D4;30D4;30D2 309A;30D4;30D2 309A; # (ピ; ピ; ヒ◌゚; ピ; ヒ◌゚; ) KATAKANA LETTER PI +30D6;30D6;30D5 3099;30D6;30D5 3099; # (ブ; ブ; フ◌゙; ブ; フ◌゙; ) KATAKANA LETTER BU +30D7;30D7;30D5 309A;30D7;30D5 309A; # (プ; プ; フ◌゚; プ; フ◌゚; ) KATAKANA LETTER PU +30D9;30D9;30D8 3099;30D9;30D8 3099; # (ベ; ベ; ヘ◌゙; ベ; ヘ◌゙; ) KATAKANA LETTER BE +30DA;30DA;30D8 309A;30DA;30D8 309A; # (ペ; ペ; ヘ◌゚; ペ; ヘ◌゚; ) KATAKANA LETTER PE +30DC;30DC;30DB 3099;30DC;30DB 3099; # (ボ; ボ; ホ◌゙; ボ; ホ◌゙; ) KATAKANA LETTER BO +30DD;30DD;30DB 309A;30DD;30DB 309A; # (ポ; ポ; ホ◌゚; ポ; ホ◌゚; ) KATAKANA LETTER PO +30F4;30F4;30A6 3099;30F4;30A6 3099; # (ヴ; ヴ; ウ◌゙; ヴ; ウ◌゙; ) KATAKANA LETTER VU +30F7;30F7;30EF 3099;30F7;30EF 3099; # (ヷ; ヷ; ワ◌゙; ヷ; ワ◌゙; ) KATAKANA LETTER VA +30F8;30F8;30F0 3099;30F8;30F0 3099; # (ヸ; ヸ; ヰ◌゙; ヸ; ヰ◌゙; ) KATAKANA LETTER VI +30F9;30F9;30F1 3099;30F9;30F1 3099; # (ヹ; ヹ; ヱ◌゙; ヹ; ヱ◌゙; ) KATAKANA LETTER VE +30FA;30FA;30F2 3099;30FA;30F2 3099; # (ヺ; ヺ; ヲ◌゙; ヺ; ヲ◌゙; ) KATAKANA LETTER VO +30FE;30FE;30FD 3099;30FE;30FD 3099; # (ヾ; ヾ; ヽ◌゙; ヾ; ヽ◌゙; ) KATAKANA VOICED ITERATION MARK +30FF;30FF;30FF;30B3 30C8;30B3 30C8; # (ヿ; ヿ; ヿ; コト; コト; ) KATAKANA DIGRAPH KOTO +3131;3131;3131;1100;1100; # (ㄱ; ㄱ; ㄱ; ᄀ; ᄀ; ) HANGUL LETTER KIYEOK +3132;3132;3132;1101;1101; # (ㄲ; ㄲ; ㄲ; ᄁ; ᄁ; ) HANGUL LETTER SSANGKIYEOK +3133;3133;3133;11AA;11AA; # (ㄳ; ㄳ; ㄳ; ᆪ; ᆪ; ) HANGUL LETTER KIYEOK-SIOS +3134;3134;3134;1102;1102; # (ㄴ; ㄴ; ㄴ; ᄂ; ᄂ; ) HANGUL LETTER NIEUN +3135;3135;3135;11AC;11AC; # (ㄵ; ㄵ; ㄵ; ᆬ; ᆬ; ) HANGUL LETTER NIEUN-CIEUC +3136;3136;3136;11AD;11AD; # (ㄶ; ㄶ; ㄶ; ᆭ; ᆭ; ) HANGUL LETTER NIEUN-HIEUH +3137;3137;3137;1103;1103; # (ㄷ; ㄷ; ㄷ; ᄃ; ᄃ; ) HANGUL LETTER TIKEUT +3138;3138;3138;1104;1104; # (ㄸ; ㄸ; ㄸ; ᄄ; ᄄ; ) HANGUL LETTER SSANGTIKEUT +3139;3139;3139;1105;1105; # (ㄹ; ㄹ; ㄹ; ᄅ; ᄅ; ) HANGUL LETTER RIEUL +313A;313A;313A;11B0;11B0; # (ㄺ; ㄺ; ㄺ; ᆰ; ᆰ; ) HANGUL LETTER RIEUL-KIYEOK +313B;313B;313B;11B1;11B1; # (ㄻ; ㄻ; ㄻ; ᆱ; ᆱ; ) HANGUL LETTER RIEUL-MIEUM +313C;313C;313C;11B2;11B2; # (ㄼ; ㄼ; ㄼ; ᆲ; ᆲ; ) HANGUL LETTER RIEUL-PIEUP +313D;313D;313D;11B3;11B3; # (ㄽ; ㄽ; ㄽ; ᆳ; ᆳ; ) HANGUL LETTER RIEUL-SIOS +313E;313E;313E;11B4;11B4; # (ㄾ; ㄾ; ㄾ; ᆴ; ᆴ; ) HANGUL LETTER RIEUL-THIEUTH +313F;313F;313F;11B5;11B5; # (ㄿ; ㄿ; ㄿ; ᆵ; ᆵ; ) HANGUL LETTER RIEUL-PHIEUPH +3140;3140;3140;111A;111A; # (ㅀ; ㅀ; ㅀ; ᄚ; ᄚ; ) HANGUL LETTER RIEUL-HIEUH +3141;3141;3141;1106;1106; # (ㅁ; ㅁ; ㅁ; ᄆ; ᄆ; ) HANGUL LETTER MIEUM +3142;3142;3142;1107;1107; # (ㅂ; ㅂ; ㅂ; ᄇ; ᄇ; ) HANGUL LETTER PIEUP +3143;3143;3143;1108;1108; # (ㅃ; ㅃ; ㅃ; ᄈ; ᄈ; ) HANGUL LETTER SSANGPIEUP +3144;3144;3144;1121;1121; # (ㅄ; ㅄ; ㅄ; ᄡ; ᄡ; ) HANGUL LETTER PIEUP-SIOS +3145;3145;3145;1109;1109; # (ㅅ; ㅅ; ㅅ; ᄉ; ᄉ; ) HANGUL LETTER SIOS +3146;3146;3146;110A;110A; # (ㅆ; ㅆ; ㅆ; ᄊ; ᄊ; ) HANGUL LETTER SSANGSIOS +3147;3147;3147;110B;110B; # (ㅇ; ㅇ; ㅇ; ᄋ; ᄋ; ) HANGUL LETTER IEUNG +3148;3148;3148;110C;110C; # (ㅈ; ㅈ; ㅈ; ᄌ; ᄌ; ) HANGUL LETTER CIEUC +3149;3149;3149;110D;110D; # (ㅉ; ㅉ; ㅉ; ᄍ; ᄍ; ) HANGUL LETTER SSANGCIEUC +314A;314A;314A;110E;110E; # (ㅊ; ㅊ; ㅊ; ᄎ; ᄎ; ) HANGUL LETTER CHIEUCH +314B;314B;314B;110F;110F; # (ㅋ; ㅋ; ㅋ; ᄏ; ᄏ; ) HANGUL LETTER KHIEUKH +314C;314C;314C;1110;1110; # (ㅌ; ㅌ; ㅌ; ᄐ; ᄐ; ) HANGUL LETTER THIEUTH +314D;314D;314D;1111;1111; # (ㅍ; ㅍ; ㅍ; ᄑ; ᄑ; ) HANGUL LETTER PHIEUPH +314E;314E;314E;1112;1112; # (ㅎ; ㅎ; ㅎ; ᄒ; ᄒ; ) HANGUL LETTER HIEUH +314F;314F;314F;1161;1161; # (ㅏ; ㅏ; ㅏ; ᅡ; ᅡ; ) HANGUL LETTER A +3150;3150;3150;1162;1162; # (ㅐ; ㅐ; ㅐ; ᅢ; ᅢ; ) HANGUL LETTER AE +3151;3151;3151;1163;1163; # (ㅑ; ㅑ; ㅑ; ᅣ; ᅣ; ) HANGUL LETTER YA +3152;3152;3152;1164;1164; # (ㅒ; ㅒ; ㅒ; ᅤ; ᅤ; ) HANGUL LETTER YAE +3153;3153;3153;1165;1165; # (ㅓ; ㅓ; ㅓ; ᅥ; ᅥ; ) HANGUL LETTER EO +3154;3154;3154;1166;1166; # (ㅔ; ㅔ; ㅔ; ᅦ; ᅦ; ) HANGUL LETTER E +3155;3155;3155;1167;1167; # (ㅕ; ㅕ; ㅕ; ᅧ; ᅧ; ) HANGUL LETTER YEO +3156;3156;3156;1168;1168; # (ㅖ; ㅖ; ㅖ; ᅨ; ᅨ; ) HANGUL LETTER YE +3157;3157;3157;1169;1169; # (ㅗ; ㅗ; ㅗ; ᅩ; ᅩ; ) HANGUL LETTER O +3158;3158;3158;116A;116A; # (ㅘ; ㅘ; ㅘ; ᅪ; ᅪ; ) HANGUL LETTER WA +3159;3159;3159;116B;116B; # (ㅙ; ㅙ; ㅙ; ᅫ; ᅫ; ) HANGUL LETTER WAE +315A;315A;315A;116C;116C; # (ㅚ; ㅚ; ㅚ; ᅬ; ᅬ; ) HANGUL LETTER OE +315B;315B;315B;116D;116D; # (ㅛ; ㅛ; ㅛ; ᅭ; ᅭ; ) HANGUL LETTER YO +315C;315C;315C;116E;116E; # (ㅜ; ㅜ; ㅜ; ᅮ; ᅮ; ) HANGUL LETTER U +315D;315D;315D;116F;116F; # (ㅝ; ㅝ; ㅝ; ᅯ; ᅯ; ) HANGUL LETTER WEO +315E;315E;315E;1170;1170; # (ㅞ; ㅞ; ㅞ; ᅰ; ᅰ; ) HANGUL LETTER WE +315F;315F;315F;1171;1171; # (ㅟ; ㅟ; ㅟ; ᅱ; ᅱ; ) HANGUL LETTER WI +3160;3160;3160;1172;1172; # (ㅠ; ㅠ; ㅠ; ᅲ; ᅲ; ) HANGUL LETTER YU +3161;3161;3161;1173;1173; # (ㅡ; ㅡ; ㅡ; ᅳ; ᅳ; ) HANGUL LETTER EU +3162;3162;3162;1174;1174; # (ㅢ; ㅢ; ㅢ; ᅴ; ᅴ; ) HANGUL LETTER YI +3163;3163;3163;1175;1175; # (ㅣ; ㅣ; ㅣ; ᅵ; ᅵ; ) HANGUL LETTER I +3164;3164;3164;1160;1160; # (ㅤ; ㅤ; ㅤ; ᅠ; ᅠ; ) HANGUL FILLER +3165;3165;3165;1114;1114; # (ㅥ; ㅥ; ㅥ; ᄔ; ᄔ; ) HANGUL LETTER SSANGNIEUN +3166;3166;3166;1115;1115; # (ㅦ; ㅦ; ㅦ; ᄕ; ᄕ; ) HANGUL LETTER NIEUN-TIKEUT +3167;3167;3167;11C7;11C7; # (ㅧ; ㅧ; ㅧ; ᇇ; ᇇ; ) HANGUL LETTER NIEUN-SIOS +3168;3168;3168;11C8;11C8; # (ㅨ; ㅨ; ㅨ; ᇈ; ᇈ; ) HANGUL LETTER NIEUN-PANSIOS +3169;3169;3169;11CC;11CC; # (ㅩ; ㅩ; ㅩ; ᇌ; ᇌ; ) HANGUL LETTER RIEUL-KIYEOK-SIOS +316A;316A;316A;11CE;11CE; # (ㅪ; ㅪ; ㅪ; ᇎ; ᇎ; ) HANGUL LETTER RIEUL-TIKEUT +316B;316B;316B;11D3;11D3; # (ㅫ; ㅫ; ㅫ; ᇓ; ᇓ; ) HANGUL LETTER RIEUL-PIEUP-SIOS +316C;316C;316C;11D7;11D7; # (ㅬ; ㅬ; ㅬ; ᇗ; ᇗ; ) HANGUL LETTER RIEUL-PANSIOS +316D;316D;316D;11D9;11D9; # (ㅭ; ㅭ; ㅭ; ᇙ; ᇙ; ) HANGUL LETTER RIEUL-YEORINHIEUH +316E;316E;316E;111C;111C; # (ㅮ; ㅮ; ㅮ; ᄜ; ᄜ; ) HANGUL LETTER MIEUM-PIEUP +316F;316F;316F;11DD;11DD; # (ㅯ; ㅯ; ㅯ; ᇝ; ᇝ; ) HANGUL LETTER MIEUM-SIOS +3170;3170;3170;11DF;11DF; # (ㅰ; ㅰ; ㅰ; ᇟ; ᇟ; ) HANGUL LETTER MIEUM-PANSIOS +3171;3171;3171;111D;111D; # (ㅱ; ㅱ; ㅱ; ᄝ; ᄝ; ) HANGUL LETTER KAPYEOUNMIEUM +3172;3172;3172;111E;111E; # (ㅲ; ㅲ; ㅲ; ᄞ; ᄞ; ) HANGUL LETTER PIEUP-KIYEOK +3173;3173;3173;1120;1120; # (ㅳ; ㅳ; ㅳ; ᄠ; ᄠ; ) HANGUL LETTER PIEUP-TIKEUT +3174;3174;3174;1122;1122; # (ㅴ; ㅴ; ㅴ; ᄢ; ᄢ; ) HANGUL LETTER PIEUP-SIOS-KIYEOK +3175;3175;3175;1123;1123; # (ㅵ; ㅵ; ㅵ; ᄣ; ᄣ; ) HANGUL LETTER PIEUP-SIOS-TIKEUT +3176;3176;3176;1127;1127; # (ㅶ; ㅶ; ㅶ; ᄧ; ᄧ; ) HANGUL LETTER PIEUP-CIEUC +3177;3177;3177;1129;1129; # (ㅷ; ㅷ; ㅷ; ᄩ; ᄩ; ) HANGUL LETTER PIEUP-THIEUTH +3178;3178;3178;112B;112B; # (ㅸ; ㅸ; ㅸ; ᄫ; ᄫ; ) HANGUL LETTER KAPYEOUNPIEUP +3179;3179;3179;112C;112C; # (ㅹ; ㅹ; ㅹ; ᄬ; ᄬ; ) HANGUL LETTER KAPYEOUNSSANGPIEUP +317A;317A;317A;112D;112D; # (ㅺ; ㅺ; ㅺ; ᄭ; ᄭ; ) HANGUL LETTER SIOS-KIYEOK +317B;317B;317B;112E;112E; # (ㅻ; ㅻ; ㅻ; ᄮ; ᄮ; ) HANGUL LETTER SIOS-NIEUN +317C;317C;317C;112F;112F; # (ㅼ; ㅼ; ㅼ; ᄯ; ᄯ; ) HANGUL LETTER SIOS-TIKEUT +317D;317D;317D;1132;1132; # (ㅽ; ㅽ; ㅽ; ᄲ; ᄲ; ) HANGUL LETTER SIOS-PIEUP +317E;317E;317E;1136;1136; # (ㅾ; ㅾ; ㅾ; ᄶ; ᄶ; ) HANGUL LETTER SIOS-CIEUC +317F;317F;317F;1140;1140; # (ㅿ; ㅿ; ㅿ; ᅀ; ᅀ; ) HANGUL LETTER PANSIOS +3180;3180;3180;1147;1147; # (ㆀ; ㆀ; ㆀ; ᅇ; ᅇ; ) HANGUL LETTER SSANGIEUNG +3181;3181;3181;114C;114C; # (ㆁ; ㆁ; ㆁ; ᅌ; ᅌ; ) HANGUL LETTER YESIEUNG +3182;3182;3182;11F1;11F1; # (ㆂ; ㆂ; ㆂ; ᇱ; ᇱ; ) HANGUL LETTER YESIEUNG-SIOS +3183;3183;3183;11F2;11F2; # (ㆃ; ㆃ; ㆃ; ᇲ; ᇲ; ) HANGUL LETTER YESIEUNG-PANSIOS +3184;3184;3184;1157;1157; # (ㆄ; ㆄ; ㆄ; ᅗ; ᅗ; ) HANGUL LETTER KAPYEOUNPHIEUPH +3185;3185;3185;1158;1158; # (ㆅ; ㆅ; ㆅ; ᅘ; ᅘ; ) HANGUL LETTER SSANGHIEUH +3186;3186;3186;1159;1159; # (ㆆ; ㆆ; ㆆ; ᅙ; ᅙ; ) HANGUL LETTER YEORINHIEUH +3187;3187;3187;1184;1184; # (ㆇ; ㆇ; ㆇ; ᆄ; ᆄ; ) HANGUL LETTER YO-YA +3188;3188;3188;1185;1185; # (ㆈ; ㆈ; ㆈ; ᆅ; ᆅ; ) HANGUL LETTER YO-YAE +3189;3189;3189;1188;1188; # (ㆉ; ㆉ; ㆉ; ᆈ; ᆈ; ) HANGUL LETTER YO-I +318A;318A;318A;1191;1191; # (ㆊ; ㆊ; ㆊ; ᆑ; ᆑ; ) HANGUL LETTER YU-YEO +318B;318B;318B;1192;1192; # (ㆋ; ㆋ; ㆋ; ᆒ; ᆒ; ) HANGUL LETTER YU-YE +318C;318C;318C;1194;1194; # (ㆌ; ㆌ; ㆌ; ᆔ; ᆔ; ) HANGUL LETTER YU-I +318D;318D;318D;119E;119E; # (ㆍ; ㆍ; ㆍ; ᆞ; ᆞ; ) HANGUL LETTER ARAEA +318E;318E;318E;11A1;11A1; # (ㆎ; ㆎ; ㆎ; ᆡ; ᆡ; ) HANGUL LETTER ARAEAE +3192;3192;3192;4E00;4E00; # (㆒; ㆒; ㆒; 一; 一; ) IDEOGRAPHIC ANNOTATION ONE MARK +3193;3193;3193;4E8C;4E8C; # (㆓; ㆓; ㆓; 二; 二; ) IDEOGRAPHIC ANNOTATION TWO MARK +3194;3194;3194;4E09;4E09; # (㆔; ㆔; ㆔; 三; 三; ) IDEOGRAPHIC ANNOTATION THREE MARK +3195;3195;3195;56DB;56DB; # (㆕; ㆕; ㆕; 四; 四; ) IDEOGRAPHIC ANNOTATION FOUR MARK +3196;3196;3196;4E0A;4E0A; # (㆖; ㆖; ㆖; 上; 上; ) IDEOGRAPHIC ANNOTATION TOP MARK +3197;3197;3197;4E2D;4E2D; # (㆗; ㆗; ㆗; 中; 中; ) IDEOGRAPHIC ANNOTATION MIDDLE MARK +3198;3198;3198;4E0B;4E0B; # (㆘; ㆘; ㆘; 下; 下; ) IDEOGRAPHIC ANNOTATION BOTTOM MARK +3199;3199;3199;7532;7532; # (㆙; ㆙; ㆙; 甲; 甲; ) IDEOGRAPHIC ANNOTATION FIRST MARK +319A;319A;319A;4E59;4E59; # (㆚; ㆚; ㆚; 乙; 乙; ) IDEOGRAPHIC ANNOTATION SECOND MARK +319B;319B;319B;4E19;4E19; # (㆛; ㆛; ㆛; 丙; 丙; ) IDEOGRAPHIC ANNOTATION THIRD MARK +319C;319C;319C;4E01;4E01; # (㆜; ㆜; ㆜; 丁; 丁; ) IDEOGRAPHIC ANNOTATION FOURTH MARK +319D;319D;319D;5929;5929; # (㆝; ㆝; ㆝; 天; 天; ) IDEOGRAPHIC ANNOTATION HEAVEN MARK +319E;319E;319E;5730;5730; # (㆞; ㆞; ㆞; 地; 地; ) IDEOGRAPHIC ANNOTATION EARTH MARK +319F;319F;319F;4EBA;4EBA; # (㆟; ㆟; ㆟; 人; 人; ) IDEOGRAPHIC ANNOTATION MAN MARK +3200;3200;3200;0028 1100 0029;0028 1100 0029; # (㈀; ㈀; ㈀; (ᄀ); (ᄀ); ) PARENTHESIZED HANGUL KIYEOK +3201;3201;3201;0028 1102 0029;0028 1102 0029; # (㈁; ㈁; ㈁; (ᄂ); (ᄂ); ) PARENTHESIZED HANGUL NIEUN +3202;3202;3202;0028 1103 0029;0028 1103 0029; # (㈂; ㈂; ㈂; (ᄃ); (ᄃ); ) PARENTHESIZED HANGUL TIKEUT +3203;3203;3203;0028 1105 0029;0028 1105 0029; # (㈃; ㈃; ㈃; (ᄅ); (ᄅ); ) PARENTHESIZED HANGUL RIEUL +3204;3204;3204;0028 1106 0029;0028 1106 0029; # (㈄; ㈄; ㈄; (ᄆ); (ᄆ); ) PARENTHESIZED HANGUL MIEUM +3205;3205;3205;0028 1107 0029;0028 1107 0029; # (㈅; ㈅; ㈅; (ᄇ); (ᄇ); ) PARENTHESIZED HANGUL PIEUP +3206;3206;3206;0028 1109 0029;0028 1109 0029; # (㈆; ㈆; ㈆; (ᄉ); (ᄉ); ) PARENTHESIZED HANGUL SIOS +3207;3207;3207;0028 110B 0029;0028 110B 0029; # (㈇; ㈇; ㈇; (ᄋ); (ᄋ); ) PARENTHESIZED HANGUL IEUNG +3208;3208;3208;0028 110C 0029;0028 110C 0029; # (㈈; ㈈; ㈈; (ᄌ); (ᄌ); ) PARENTHESIZED HANGUL CIEUC +3209;3209;3209;0028 110E 0029;0028 110E 0029; # (㈉; ㈉; ㈉; (ᄎ); (ᄎ); ) PARENTHESIZED HANGUL CHIEUCH +320A;320A;320A;0028 110F 0029;0028 110F 0029; # (㈊; ㈊; ㈊; (ᄏ); (ᄏ); ) PARENTHESIZED HANGUL KHIEUKH +320B;320B;320B;0028 1110 0029;0028 1110 0029; # (㈋; ㈋; ㈋; (ᄐ); (ᄐ); ) PARENTHESIZED HANGUL THIEUTH +320C;320C;320C;0028 1111 0029;0028 1111 0029; # (㈌; ㈌; ㈌; (ᄑ); (ᄑ); ) PARENTHESIZED HANGUL PHIEUPH +320D;320D;320D;0028 1112 0029;0028 1112 0029; # (㈍; ㈍; ㈍; (ᄒ); (ᄒ); ) PARENTHESIZED HANGUL HIEUH +320E;320E;320E;0028 AC00 0029;0028 1100 1161 0029; # (㈎; ㈎; ㈎; (가); (가); ) PARENTHESIZED HANGUL KIYEOK A +320F;320F;320F;0028 B098 0029;0028 1102 1161 0029; # (㈏; ㈏; ㈏; (나); (나); ) PARENTHESIZED HANGUL NIEUN A +3210;3210;3210;0028 B2E4 0029;0028 1103 1161 0029; # (㈐; ㈐; ㈐; (다); (다); ) PARENTHESIZED HANGUL TIKEUT A +3211;3211;3211;0028 B77C 0029;0028 1105 1161 0029; # (㈑; ㈑; ㈑; (라); (라); ) PARENTHESIZED HANGUL RIEUL A +3212;3212;3212;0028 B9C8 0029;0028 1106 1161 0029; # (㈒; ㈒; ㈒; (마); (마); ) PARENTHESIZED HANGUL MIEUM A +3213;3213;3213;0028 BC14 0029;0028 1107 1161 0029; # (㈓; ㈓; ㈓; (바); (바); ) PARENTHESIZED HANGUL PIEUP A +3214;3214;3214;0028 C0AC 0029;0028 1109 1161 0029; # (㈔; ㈔; ㈔; (사); (사); ) PARENTHESIZED HANGUL SIOS A +3215;3215;3215;0028 C544 0029;0028 110B 1161 0029; # (㈕; ㈕; ㈕; (아); (아); ) PARENTHESIZED HANGUL IEUNG A +3216;3216;3216;0028 C790 0029;0028 110C 1161 0029; # (㈖; ㈖; ㈖; (자); (자); ) PARENTHESIZED HANGUL CIEUC A +3217;3217;3217;0028 CC28 0029;0028 110E 1161 0029; # (㈗; ㈗; ㈗; (차); (차); ) PARENTHESIZED HANGUL CHIEUCH A +3218;3218;3218;0028 CE74 0029;0028 110F 1161 0029; # (㈘; ㈘; ㈘; (카); (카); ) PARENTHESIZED HANGUL KHIEUKH A +3219;3219;3219;0028 D0C0 0029;0028 1110 1161 0029; # (㈙; ㈙; ㈙; (타); (타); ) PARENTHESIZED HANGUL THIEUTH A +321A;321A;321A;0028 D30C 0029;0028 1111 1161 0029; # (㈚; ㈚; ㈚; (파); (파); ) PARENTHESIZED HANGUL PHIEUPH A +321B;321B;321B;0028 D558 0029;0028 1112 1161 0029; # (㈛; ㈛; ㈛; (하); (하); ) PARENTHESIZED HANGUL HIEUH A +321C;321C;321C;0028 C8FC 0029;0028 110C 116E 0029; # (㈜; ㈜; ㈜; (주); (주); ) PARENTHESIZED HANGUL CIEUC U +321D;321D;321D;0028 C624 C804 0029;0028 110B 1169 110C 1165 11AB 0029; # (㈝; ㈝; ㈝; (오전); (오전); ) PARENTHESIZED KOREAN CHARACTER OJEON +321E;321E;321E;0028 C624 D6C4 0029;0028 110B 1169 1112 116E 0029; # (㈞; ㈞; ㈞; (오후); (오후); ) PARENTHESIZED KOREAN CHARACTER O HU +3220;3220;3220;0028 4E00 0029;0028 4E00 0029; # (㈠; ㈠; ㈠; (一); (一); ) PARENTHESIZED IDEOGRAPH ONE +3221;3221;3221;0028 4E8C 0029;0028 4E8C 0029; # (㈡; ㈡; ㈡; (二); (二); ) PARENTHESIZED IDEOGRAPH TWO +3222;3222;3222;0028 4E09 0029;0028 4E09 0029; # (㈢; ㈢; ㈢; (三); (三); ) PARENTHESIZED IDEOGRAPH THREE +3223;3223;3223;0028 56DB 0029;0028 56DB 0029; # (㈣; ㈣; ㈣; (四); (四); ) PARENTHESIZED IDEOGRAPH FOUR +3224;3224;3224;0028 4E94 0029;0028 4E94 0029; # (㈤; ㈤; ㈤; (五); (五); ) PARENTHESIZED IDEOGRAPH FIVE +3225;3225;3225;0028 516D 0029;0028 516D 0029; # (㈥; ㈥; ㈥; (六); (六); ) PARENTHESIZED IDEOGRAPH SIX +3226;3226;3226;0028 4E03 0029;0028 4E03 0029; # (㈦; ㈦; ㈦; (七); (七); ) PARENTHESIZED IDEOGRAPH SEVEN +3227;3227;3227;0028 516B 0029;0028 516B 0029; # (㈧; ㈧; ㈧; (八); (八); ) PARENTHESIZED IDEOGRAPH EIGHT +3228;3228;3228;0028 4E5D 0029;0028 4E5D 0029; # (㈨; ㈨; ㈨; (九); (九); ) PARENTHESIZED IDEOGRAPH NINE +3229;3229;3229;0028 5341 0029;0028 5341 0029; # (㈩; ㈩; ㈩; (十); (十); ) PARENTHESIZED IDEOGRAPH TEN +322A;322A;322A;0028 6708 0029;0028 6708 0029; # (㈪; ㈪; ㈪; (月); (月); ) PARENTHESIZED IDEOGRAPH MOON +322B;322B;322B;0028 706B 0029;0028 706B 0029; # (㈫; ㈫; ㈫; (火); (火); ) PARENTHESIZED IDEOGRAPH FIRE +322C;322C;322C;0028 6C34 0029;0028 6C34 0029; # (㈬; ㈬; ㈬; (水); (水); ) PARENTHESIZED IDEOGRAPH WATER +322D;322D;322D;0028 6728 0029;0028 6728 0029; # (㈭; ㈭; ㈭; (木); (木); ) PARENTHESIZED IDEOGRAPH WOOD +322E;322E;322E;0028 91D1 0029;0028 91D1 0029; # (㈮; ㈮; ㈮; (金); (金); ) PARENTHESIZED IDEOGRAPH METAL +322F;322F;322F;0028 571F 0029;0028 571F 0029; # (㈯; ㈯; ㈯; (土); (土); ) PARENTHESIZED IDEOGRAPH EARTH +3230;3230;3230;0028 65E5 0029;0028 65E5 0029; # (㈰; ㈰; ㈰; (日); (日); ) PARENTHESIZED IDEOGRAPH SUN +3231;3231;3231;0028 682A 0029;0028 682A 0029; # (㈱; ㈱; ㈱; (株); (株); ) PARENTHESIZED IDEOGRAPH STOCK +3232;3232;3232;0028 6709 0029;0028 6709 0029; # (㈲; ㈲; ㈲; (有); (有); ) PARENTHESIZED IDEOGRAPH HAVE +3233;3233;3233;0028 793E 0029;0028 793E 0029; # (㈳; ㈳; ㈳; (社); (社); ) PARENTHESIZED IDEOGRAPH SOCIETY +3234;3234;3234;0028 540D 0029;0028 540D 0029; # (㈴; ㈴; ㈴; (名); (名); ) PARENTHESIZED IDEOGRAPH NAME +3235;3235;3235;0028 7279 0029;0028 7279 0029; # (㈵; ㈵; ㈵; (特); (特); ) PARENTHESIZED IDEOGRAPH SPECIAL +3236;3236;3236;0028 8CA1 0029;0028 8CA1 0029; # (㈶; ㈶; ㈶; (財); (財); ) PARENTHESIZED IDEOGRAPH FINANCIAL +3237;3237;3237;0028 795D 0029;0028 795D 0029; # (㈷; ㈷; ㈷; (祝); (祝); ) PARENTHESIZED IDEOGRAPH CONGRATULATION +3238;3238;3238;0028 52B4 0029;0028 52B4 0029; # (㈸; ㈸; ㈸; (労); (労); ) PARENTHESIZED IDEOGRAPH LABOR +3239;3239;3239;0028 4EE3 0029;0028 4EE3 0029; # (㈹; ㈹; ㈹; (代); (代); ) PARENTHESIZED IDEOGRAPH REPRESENT +323A;323A;323A;0028 547C 0029;0028 547C 0029; # (㈺; ㈺; ㈺; (呼); (呼); ) PARENTHESIZED IDEOGRAPH CALL +323B;323B;323B;0028 5B66 0029;0028 5B66 0029; # (㈻; ㈻; ㈻; (学); (学); ) PARENTHESIZED IDEOGRAPH STUDY +323C;323C;323C;0028 76E3 0029;0028 76E3 0029; # (㈼; ㈼; ㈼; (監); (監); ) PARENTHESIZED IDEOGRAPH SUPERVISE +323D;323D;323D;0028 4F01 0029;0028 4F01 0029; # (㈽; ㈽; ㈽; (企); (企); ) PARENTHESIZED IDEOGRAPH ENTERPRISE +323E;323E;323E;0028 8CC7 0029;0028 8CC7 0029; # (㈾; ㈾; ㈾; (資); (資); ) PARENTHESIZED IDEOGRAPH RESOURCE +323F;323F;323F;0028 5354 0029;0028 5354 0029; # (㈿; ㈿; ㈿; (協); (協); ) PARENTHESIZED IDEOGRAPH ALLIANCE +3240;3240;3240;0028 796D 0029;0028 796D 0029; # (㉀; ㉀; ㉀; (祭); (祭); ) PARENTHESIZED IDEOGRAPH FESTIVAL +3241;3241;3241;0028 4F11 0029;0028 4F11 0029; # (㉁; ㉁; ㉁; (休); (休); ) PARENTHESIZED IDEOGRAPH REST +3242;3242;3242;0028 81EA 0029;0028 81EA 0029; # (㉂; ㉂; ㉂; (自); (自); ) PARENTHESIZED IDEOGRAPH SELF +3243;3243;3243;0028 81F3 0029;0028 81F3 0029; # (㉃; ㉃; ㉃; (至); (至); ) PARENTHESIZED IDEOGRAPH REACH +3244;3244;3244;554F;554F; # (㉄; ㉄; ㉄; 問; 問; ) CIRCLED IDEOGRAPH QUESTION +3245;3245;3245;5E7C;5E7C; # (㉅; ㉅; ㉅; 幼; 幼; ) CIRCLED IDEOGRAPH KINDERGARTEN +3246;3246;3246;6587;6587; # (㉆; ㉆; ㉆; 文; 文; ) CIRCLED IDEOGRAPH SCHOOL +3247;3247;3247;7B8F;7B8F; # (㉇; ㉇; ㉇; 箏; 箏; ) CIRCLED IDEOGRAPH KOTO +3250;3250;3250;0050 0054 0045;0050 0054 0045; # (㉐; ㉐; ㉐; PTE; PTE; ) PARTNERSHIP SIGN +3251;3251;3251;0032 0031;0032 0031; # (㉑; ㉑; ㉑; 21; 21; ) CIRCLED NUMBER TWENTY ONE +3252;3252;3252;0032 0032;0032 0032; # (㉒; ㉒; ㉒; 22; 22; ) CIRCLED NUMBER TWENTY TWO +3253;3253;3253;0032 0033;0032 0033; # (㉓; ㉓; ㉓; 23; 23; ) CIRCLED NUMBER TWENTY THREE +3254;3254;3254;0032 0034;0032 0034; # (㉔; ㉔; ㉔; 24; 24; ) CIRCLED NUMBER TWENTY FOUR +3255;3255;3255;0032 0035;0032 0035; # (㉕; ㉕; ㉕; 25; 25; ) CIRCLED NUMBER TWENTY FIVE +3256;3256;3256;0032 0036;0032 0036; # (㉖; ㉖; ㉖; 26; 26; ) CIRCLED NUMBER TWENTY SIX +3257;3257;3257;0032 0037;0032 0037; # (㉗; ㉗; ㉗; 27; 27; ) CIRCLED NUMBER TWENTY SEVEN +3258;3258;3258;0032 0038;0032 0038; # (㉘; ㉘; ㉘; 28; 28; ) CIRCLED NUMBER TWENTY EIGHT +3259;3259;3259;0032 0039;0032 0039; # (㉙; ㉙; ㉙; 29; 29; ) CIRCLED NUMBER TWENTY NINE +325A;325A;325A;0033 0030;0033 0030; # (㉚; ㉚; ㉚; 30; 30; ) CIRCLED NUMBER THIRTY +325B;325B;325B;0033 0031;0033 0031; # (㉛; ㉛; ㉛; 31; 31; ) CIRCLED NUMBER THIRTY ONE +325C;325C;325C;0033 0032;0033 0032; # (㉜; ㉜; ㉜; 32; 32; ) CIRCLED NUMBER THIRTY TWO +325D;325D;325D;0033 0033;0033 0033; # (㉝; ㉝; ㉝; 33; 33; ) CIRCLED NUMBER THIRTY THREE +325E;325E;325E;0033 0034;0033 0034; # (㉞; ㉞; ㉞; 34; 34; ) CIRCLED NUMBER THIRTY FOUR +325F;325F;325F;0033 0035;0033 0035; # (㉟; ㉟; ㉟; 35; 35; ) CIRCLED NUMBER THIRTY FIVE +3260;3260;3260;1100;1100; # (㉠; ㉠; ㉠; ᄀ; ᄀ; ) CIRCLED HANGUL KIYEOK +3261;3261;3261;1102;1102; # (㉡; ㉡; ㉡; ᄂ; ᄂ; ) CIRCLED HANGUL NIEUN +3262;3262;3262;1103;1103; # (㉢; ㉢; ㉢; ᄃ; ᄃ; ) CIRCLED HANGUL TIKEUT +3263;3263;3263;1105;1105; # (㉣; ㉣; ㉣; ᄅ; ᄅ; ) CIRCLED HANGUL RIEUL +3264;3264;3264;1106;1106; # (㉤; ㉤; ㉤; ᄆ; ᄆ; ) CIRCLED HANGUL MIEUM +3265;3265;3265;1107;1107; # (㉥; ㉥; ㉥; ᄇ; ᄇ; ) CIRCLED HANGUL PIEUP +3266;3266;3266;1109;1109; # (㉦; ㉦; ㉦; ᄉ; ᄉ; ) CIRCLED HANGUL SIOS +3267;3267;3267;110B;110B; # (㉧; ㉧; ㉧; ᄋ; ᄋ; ) CIRCLED HANGUL IEUNG +3268;3268;3268;110C;110C; # (㉨; ㉨; ㉨; ᄌ; ᄌ; ) CIRCLED HANGUL CIEUC +3269;3269;3269;110E;110E; # (㉩; ㉩; ㉩; ᄎ; ᄎ; ) CIRCLED HANGUL CHIEUCH +326A;326A;326A;110F;110F; # (㉪; ㉪; ㉪; ᄏ; ᄏ; ) CIRCLED HANGUL KHIEUKH +326B;326B;326B;1110;1110; # (㉫; ㉫; ㉫; ᄐ; ᄐ; ) CIRCLED HANGUL THIEUTH +326C;326C;326C;1111;1111; # (㉬; ㉬; ㉬; ᄑ; ᄑ; ) CIRCLED HANGUL PHIEUPH +326D;326D;326D;1112;1112; # (㉭; ㉭; ㉭; ᄒ; ᄒ; ) CIRCLED HANGUL HIEUH +326E;326E;326E;AC00;1100 1161; # (㉮; ㉮; ㉮; 가; 가; ) CIRCLED HANGUL KIYEOK A +326F;326F;326F;B098;1102 1161; # (㉯; ㉯; ㉯; 나; 나; ) CIRCLED HANGUL NIEUN A +3270;3270;3270;B2E4;1103 1161; # (㉰; ㉰; ㉰; 다; 다; ) CIRCLED HANGUL TIKEUT A +3271;3271;3271;B77C;1105 1161; # (㉱; ㉱; ㉱; 라; 라; ) CIRCLED HANGUL RIEUL A +3272;3272;3272;B9C8;1106 1161; # (㉲; ㉲; ㉲; 마; 마; ) CIRCLED HANGUL MIEUM A +3273;3273;3273;BC14;1107 1161; # (㉳; ㉳; ㉳; 바; 바; ) CIRCLED HANGUL PIEUP A +3274;3274;3274;C0AC;1109 1161; # (㉴; ㉴; ㉴; 사; 사; ) CIRCLED HANGUL SIOS A +3275;3275;3275;C544;110B 1161; # (㉵; ㉵; ㉵; 아; 아; ) CIRCLED HANGUL IEUNG A +3276;3276;3276;C790;110C 1161; # (㉶; ㉶; ㉶; 자; 자; ) CIRCLED HANGUL CIEUC A +3277;3277;3277;CC28;110E 1161; # (㉷; ㉷; ㉷; 차; 차; ) CIRCLED HANGUL CHIEUCH A +3278;3278;3278;CE74;110F 1161; # (㉸; ㉸; ㉸; 카; 카; ) CIRCLED HANGUL KHIEUKH A +3279;3279;3279;D0C0;1110 1161; # (㉹; ㉹; ㉹; 타; 타; ) CIRCLED HANGUL THIEUTH A +327A;327A;327A;D30C;1111 1161; # (㉺; ㉺; ㉺; 파; 파; ) CIRCLED HANGUL PHIEUPH A +327B;327B;327B;D558;1112 1161; # (㉻; ㉻; ㉻; 하; 하; ) CIRCLED HANGUL HIEUH A +327C;327C;327C;CC38 ACE0;110E 1161 11B7 1100 1169; # (㉼; ㉼; ㉼; 참고; 참고; ) CIRCLED KOREAN CHARACTER CHAMKO +327D;327D;327D;C8FC C758;110C 116E 110B 1174; # (㉽; ㉽; ㉽; 주의; 주의; ) CIRCLED KOREAN CHARACTER JUEUI +327E;327E;327E;C6B0;110B 116E; # (㉾; ㉾; ㉾; 우; 우; ) CIRCLED HANGUL IEUNG U +3280;3280;3280;4E00;4E00; # (㊀; ㊀; ㊀; 一; 一; ) CIRCLED IDEOGRAPH ONE +3281;3281;3281;4E8C;4E8C; # (㊁; ㊁; ㊁; 二; 二; ) CIRCLED IDEOGRAPH TWO +3282;3282;3282;4E09;4E09; # (㊂; ㊂; ㊂; 三; 三; ) CIRCLED IDEOGRAPH THREE +3283;3283;3283;56DB;56DB; # (㊃; ㊃; ㊃; 四; 四; ) CIRCLED IDEOGRAPH FOUR +3284;3284;3284;4E94;4E94; # (㊄; ㊄; ㊄; 五; 五; ) CIRCLED IDEOGRAPH FIVE +3285;3285;3285;516D;516D; # (㊅; ㊅; ㊅; 六; 六; ) CIRCLED IDEOGRAPH SIX +3286;3286;3286;4E03;4E03; # (㊆; ㊆; ㊆; 七; 七; ) CIRCLED IDEOGRAPH SEVEN +3287;3287;3287;516B;516B; # (㊇; ㊇; ㊇; 八; 八; ) CIRCLED IDEOGRAPH EIGHT +3288;3288;3288;4E5D;4E5D; # (㊈; ㊈; ㊈; 九; 九; ) CIRCLED IDEOGRAPH NINE +3289;3289;3289;5341;5341; # (㊉; ㊉; ㊉; 十; 十; ) CIRCLED IDEOGRAPH TEN +328A;328A;328A;6708;6708; # (㊊; ㊊; ㊊; 月; 月; ) CIRCLED IDEOGRAPH MOON +328B;328B;328B;706B;706B; # (㊋; ㊋; ㊋; 火; 火; ) CIRCLED IDEOGRAPH FIRE +328C;328C;328C;6C34;6C34; # (㊌; ㊌; ㊌; 水; 水; ) CIRCLED IDEOGRAPH WATER +328D;328D;328D;6728;6728; # (㊍; ㊍; ㊍; 木; 木; ) CIRCLED IDEOGRAPH WOOD +328E;328E;328E;91D1;91D1; # (㊎; ㊎; ㊎; 金; 金; ) CIRCLED IDEOGRAPH METAL +328F;328F;328F;571F;571F; # (㊏; ㊏; ㊏; 土; 土; ) CIRCLED IDEOGRAPH EARTH +3290;3290;3290;65E5;65E5; # (㊐; ㊐; ㊐; 日; 日; ) CIRCLED IDEOGRAPH SUN +3291;3291;3291;682A;682A; # (㊑; ㊑; ㊑; 株; 株; ) CIRCLED IDEOGRAPH STOCK +3292;3292;3292;6709;6709; # (㊒; ㊒; ㊒; 有; 有; ) CIRCLED IDEOGRAPH HAVE +3293;3293;3293;793E;793E; # (㊓; ㊓; ㊓; 社; 社; ) CIRCLED IDEOGRAPH SOCIETY +3294;3294;3294;540D;540D; # (㊔; ㊔; ㊔; 名; 名; ) CIRCLED IDEOGRAPH NAME +3295;3295;3295;7279;7279; # (㊕; ㊕; ㊕; 特; 特; ) CIRCLED IDEOGRAPH SPECIAL +3296;3296;3296;8CA1;8CA1; # (㊖; ㊖; ㊖; 財; 財; ) CIRCLED IDEOGRAPH FINANCIAL +3297;3297;3297;795D;795D; # (㊗; ㊗; ㊗; 祝; 祝; ) CIRCLED IDEOGRAPH CONGRATULATION +3298;3298;3298;52B4;52B4; # (㊘; ㊘; ㊘; 労; 労; ) CIRCLED IDEOGRAPH LABOR +3299;3299;3299;79D8;79D8; # (㊙; ㊙; ㊙; 秘; 秘; ) CIRCLED IDEOGRAPH SECRET +329A;329A;329A;7537;7537; # (㊚; ㊚; ㊚; 男; 男; ) CIRCLED IDEOGRAPH MALE +329B;329B;329B;5973;5973; # (㊛; ㊛; ㊛; 女; 女; ) CIRCLED IDEOGRAPH FEMALE +329C;329C;329C;9069;9069; # (㊜; ㊜; ㊜; 適; 適; ) CIRCLED IDEOGRAPH SUITABLE +329D;329D;329D;512A;512A; # (㊝; ㊝; ㊝; 優; 優; ) CIRCLED IDEOGRAPH EXCELLENT +329E;329E;329E;5370;5370; # (㊞; ㊞; ㊞; 印; 印; ) CIRCLED IDEOGRAPH PRINT +329F;329F;329F;6CE8;6CE8; # (㊟; ㊟; ㊟; 注; 注; ) CIRCLED IDEOGRAPH ATTENTION +32A0;32A0;32A0;9805;9805; # (㊠; ㊠; ㊠; 項; 項; ) CIRCLED IDEOGRAPH ITEM +32A1;32A1;32A1;4F11;4F11; # (㊡; ㊡; ㊡; 休; 休; ) CIRCLED IDEOGRAPH REST +32A2;32A2;32A2;5199;5199; # (㊢; ㊢; ㊢; 写; 写; ) CIRCLED IDEOGRAPH COPY +32A3;32A3;32A3;6B63;6B63; # (㊣; ㊣; ㊣; 正; 正; ) CIRCLED IDEOGRAPH CORRECT +32A4;32A4;32A4;4E0A;4E0A; # (㊤; ㊤; ㊤; 上; 上; ) CIRCLED IDEOGRAPH HIGH +32A5;32A5;32A5;4E2D;4E2D; # (㊥; ㊥; ㊥; 中; 中; ) CIRCLED IDEOGRAPH CENTRE +32A6;32A6;32A6;4E0B;4E0B; # (㊦; ㊦; ㊦; 下; 下; ) CIRCLED IDEOGRAPH LOW +32A7;32A7;32A7;5DE6;5DE6; # (㊧; ㊧; ㊧; 左; 左; ) CIRCLED IDEOGRAPH LEFT +32A8;32A8;32A8;53F3;53F3; # (㊨; ㊨; ㊨; 右; 右; ) CIRCLED IDEOGRAPH RIGHT +32A9;32A9;32A9;533B;533B; # (㊩; ㊩; ㊩; 医; 医; ) CIRCLED IDEOGRAPH MEDICINE +32AA;32AA;32AA;5B97;5B97; # (㊪; ㊪; ㊪; 宗; 宗; ) CIRCLED IDEOGRAPH RELIGION +32AB;32AB;32AB;5B66;5B66; # (㊫; ㊫; ㊫; 学; 学; ) CIRCLED IDEOGRAPH STUDY +32AC;32AC;32AC;76E3;76E3; # (㊬; ㊬; ㊬; 監; 監; ) CIRCLED IDEOGRAPH SUPERVISE +32AD;32AD;32AD;4F01;4F01; # (㊭; ㊭; ㊭; 企; 企; ) CIRCLED IDEOGRAPH ENTERPRISE +32AE;32AE;32AE;8CC7;8CC7; # (㊮; ㊮; ㊮; 資; 資; ) CIRCLED IDEOGRAPH RESOURCE +32AF;32AF;32AF;5354;5354; # (㊯; ㊯; ㊯; 協; 協; ) CIRCLED IDEOGRAPH ALLIANCE +32B0;32B0;32B0;591C;591C; # (㊰; ㊰; ㊰; 夜; 夜; ) CIRCLED IDEOGRAPH NIGHT +32B1;32B1;32B1;0033 0036;0033 0036; # (㊱; ㊱; ㊱; 36; 36; ) CIRCLED NUMBER THIRTY SIX +32B2;32B2;32B2;0033 0037;0033 0037; # (㊲; ㊲; ㊲; 37; 37; ) CIRCLED NUMBER THIRTY SEVEN +32B3;32B3;32B3;0033 0038;0033 0038; # (㊳; ㊳; ㊳; 38; 38; ) CIRCLED NUMBER THIRTY EIGHT +32B4;32B4;32B4;0033 0039;0033 0039; # (㊴; ㊴; ㊴; 39; 39; ) CIRCLED NUMBER THIRTY NINE +32B5;32B5;32B5;0034 0030;0034 0030; # (㊵; ㊵; ㊵; 40; 40; ) CIRCLED NUMBER FORTY +32B6;32B6;32B6;0034 0031;0034 0031; # (㊶; ㊶; ㊶; 41; 41; ) CIRCLED NUMBER FORTY ONE +32B7;32B7;32B7;0034 0032;0034 0032; # (㊷; ㊷; ㊷; 42; 42; ) CIRCLED NUMBER FORTY TWO +32B8;32B8;32B8;0034 0033;0034 0033; # (㊸; ㊸; ㊸; 43; 43; ) CIRCLED NUMBER FORTY THREE +32B9;32B9;32B9;0034 0034;0034 0034; # (㊹; ㊹; ㊹; 44; 44; ) CIRCLED NUMBER FORTY FOUR +32BA;32BA;32BA;0034 0035;0034 0035; # (㊺; ㊺; ㊺; 45; 45; ) CIRCLED NUMBER FORTY FIVE +32BB;32BB;32BB;0034 0036;0034 0036; # (㊻; ㊻; ㊻; 46; 46; ) CIRCLED NUMBER FORTY SIX +32BC;32BC;32BC;0034 0037;0034 0037; # (㊼; ㊼; ㊼; 47; 47; ) CIRCLED NUMBER FORTY SEVEN +32BD;32BD;32BD;0034 0038;0034 0038; # (㊽; ㊽; ㊽; 48; 48; ) CIRCLED NUMBER FORTY EIGHT +32BE;32BE;32BE;0034 0039;0034 0039; # (㊾; ㊾; ㊾; 49; 49; ) CIRCLED NUMBER FORTY NINE +32BF;32BF;32BF;0035 0030;0035 0030; # (㊿; ㊿; ㊿; 50; 50; ) CIRCLED NUMBER FIFTY +32C0;32C0;32C0;0031 6708;0031 6708; # (㋀; ㋀; ㋀; 1月; 1月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY +32C1;32C1;32C1;0032 6708;0032 6708; # (㋁; ㋁; ㋁; 2月; 2月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY +32C2;32C2;32C2;0033 6708;0033 6708; # (㋂; ㋂; ㋂; 3月; 3月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH +32C3;32C3;32C3;0034 6708;0034 6708; # (㋃; ㋃; ㋃; 4月; 4月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL +32C4;32C4;32C4;0035 6708;0035 6708; # (㋄; ㋄; ㋄; 5月; 5月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY +32C5;32C5;32C5;0036 6708;0036 6708; # (㋅; ㋅; ㋅; 6月; 6月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE +32C6;32C6;32C6;0037 6708;0037 6708; # (㋆; ㋆; ㋆; 7月; 7月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY +32C7;32C7;32C7;0038 6708;0038 6708; # (㋇; ㋇; ㋇; 8月; 8月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST +32C8;32C8;32C8;0039 6708;0039 6708; # (㋈; ㋈; ㋈; 9月; 9月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER +32C9;32C9;32C9;0031 0030 6708;0031 0030 6708; # (㋉; ㋉; ㋉; 10月; 10月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER +32CA;32CA;32CA;0031 0031 6708;0031 0031 6708; # (㋊; ㋊; ㋊; 11月; 11月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER +32CB;32CB;32CB;0031 0032 6708;0031 0032 6708; # (㋋; ㋋; ㋋; 12月; 12月; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER +32CC;32CC;32CC;0048 0067;0048 0067; # (㋌; ㋌; ㋌; Hg; Hg; ) SQUARE HG +32CD;32CD;32CD;0065 0072 0067;0065 0072 0067; # (㋍; ㋍; ㋍; erg; erg; ) SQUARE ERG +32CE;32CE;32CE;0065 0056;0065 0056; # (㋎; ㋎; ㋎; eV; eV; ) SQUARE EV +32CF;32CF;32CF;004C 0054 0044;004C 0054 0044; # (㋏; ㋏; ㋏; LTD; LTD; ) LIMITED LIABILITY SIGN +32D0;32D0;32D0;30A2;30A2; # (㋐; ㋐; ㋐; ア; ア; ) CIRCLED KATAKANA A +32D1;32D1;32D1;30A4;30A4; # (㋑; ㋑; ㋑; イ; イ; ) CIRCLED KATAKANA I +32D2;32D2;32D2;30A6;30A6; # (㋒; ㋒; ㋒; ウ; ウ; ) CIRCLED KATAKANA U +32D3;32D3;32D3;30A8;30A8; # (㋓; ㋓; ㋓; エ; エ; ) CIRCLED KATAKANA E +32D4;32D4;32D4;30AA;30AA; # (㋔; ㋔; ㋔; オ; オ; ) CIRCLED KATAKANA O +32D5;32D5;32D5;30AB;30AB; # (㋕; ㋕; ㋕; カ; カ; ) CIRCLED KATAKANA KA +32D6;32D6;32D6;30AD;30AD; # (㋖; ㋖; ㋖; キ; キ; ) CIRCLED KATAKANA KI +32D7;32D7;32D7;30AF;30AF; # (㋗; ㋗; ㋗; ク; ク; ) CIRCLED KATAKANA KU +32D8;32D8;32D8;30B1;30B1; # (㋘; ㋘; ㋘; ケ; ケ; ) CIRCLED KATAKANA KE +32D9;32D9;32D9;30B3;30B3; # (㋙; ㋙; ㋙; コ; コ; ) CIRCLED KATAKANA KO +32DA;32DA;32DA;30B5;30B5; # (㋚; ㋚; ㋚; サ; サ; ) CIRCLED KATAKANA SA +32DB;32DB;32DB;30B7;30B7; # (㋛; ㋛; ㋛; シ; シ; ) CIRCLED KATAKANA SI +32DC;32DC;32DC;30B9;30B9; # (㋜; ㋜; ㋜; ス; ス; ) CIRCLED KATAKANA SU +32DD;32DD;32DD;30BB;30BB; # (㋝; ㋝; ㋝; セ; セ; ) CIRCLED KATAKANA SE +32DE;32DE;32DE;30BD;30BD; # (㋞; ㋞; ㋞; ソ; ソ; ) CIRCLED KATAKANA SO +32DF;32DF;32DF;30BF;30BF; # (㋟; ㋟; ㋟; タ; タ; ) CIRCLED KATAKANA TA +32E0;32E0;32E0;30C1;30C1; # (㋠; ㋠; ㋠; チ; チ; ) CIRCLED KATAKANA TI +32E1;32E1;32E1;30C4;30C4; # (㋡; ㋡; ㋡; ツ; ツ; ) CIRCLED KATAKANA TU +32E2;32E2;32E2;30C6;30C6; # (㋢; ㋢; ㋢; テ; テ; ) CIRCLED KATAKANA TE +32E3;32E3;32E3;30C8;30C8; # (㋣; ㋣; ㋣; ト; ト; ) CIRCLED KATAKANA TO +32E4;32E4;32E4;30CA;30CA; # (㋤; ㋤; ㋤; ナ; ナ; ) CIRCLED KATAKANA NA +32E5;32E5;32E5;30CB;30CB; # (㋥; ㋥; ㋥; ニ; ニ; ) CIRCLED KATAKANA NI +32E6;32E6;32E6;30CC;30CC; # (㋦; ㋦; ㋦; ヌ; ヌ; ) CIRCLED KATAKANA NU +32E7;32E7;32E7;30CD;30CD; # (㋧; ㋧; ㋧; ネ; ネ; ) CIRCLED KATAKANA NE +32E8;32E8;32E8;30CE;30CE; # (㋨; ㋨; ㋨; ノ; ノ; ) CIRCLED KATAKANA NO +32E9;32E9;32E9;30CF;30CF; # (㋩; ㋩; ㋩; ハ; ハ; ) CIRCLED KATAKANA HA +32EA;32EA;32EA;30D2;30D2; # (㋪; ㋪; ㋪; ヒ; ヒ; ) CIRCLED KATAKANA HI +32EB;32EB;32EB;30D5;30D5; # (㋫; ㋫; ㋫; フ; フ; ) CIRCLED KATAKANA HU +32EC;32EC;32EC;30D8;30D8; # (㋬; ㋬; ㋬; ヘ; ヘ; ) CIRCLED KATAKANA HE +32ED;32ED;32ED;30DB;30DB; # (㋭; ㋭; ㋭; ホ; ホ; ) CIRCLED KATAKANA HO +32EE;32EE;32EE;30DE;30DE; # (㋮; ㋮; ㋮; マ; マ; ) CIRCLED KATAKANA MA +32EF;32EF;32EF;30DF;30DF; # (㋯; ㋯; ㋯; ミ; ミ; ) CIRCLED KATAKANA MI +32F0;32F0;32F0;30E0;30E0; # (㋰; ㋰; ㋰; ム; ム; ) CIRCLED KATAKANA MU +32F1;32F1;32F1;30E1;30E1; # (㋱; ㋱; ㋱; メ; メ; ) CIRCLED KATAKANA ME +32F2;32F2;32F2;30E2;30E2; # (㋲; ㋲; ㋲; モ; モ; ) CIRCLED KATAKANA MO +32F3;32F3;32F3;30E4;30E4; # (㋳; ㋳; ㋳; ヤ; ヤ; ) CIRCLED KATAKANA YA +32F4;32F4;32F4;30E6;30E6; # (㋴; ㋴; ㋴; ユ; ユ; ) CIRCLED KATAKANA YU +32F5;32F5;32F5;30E8;30E8; # (㋵; ㋵; ㋵; ヨ; ヨ; ) CIRCLED KATAKANA YO +32F6;32F6;32F6;30E9;30E9; # (㋶; ㋶; ㋶; ラ; ラ; ) CIRCLED KATAKANA RA +32F7;32F7;32F7;30EA;30EA; # (㋷; ㋷; ㋷; リ; リ; ) CIRCLED KATAKANA RI +32F8;32F8;32F8;30EB;30EB; # (㋸; ㋸; ㋸; ル; ル; ) CIRCLED KATAKANA RU +32F9;32F9;32F9;30EC;30EC; # (㋹; ㋹; ㋹; レ; レ; ) CIRCLED KATAKANA RE +32FA;32FA;32FA;30ED;30ED; # (㋺; ㋺; ㋺; ロ; ロ; ) CIRCLED KATAKANA RO +32FB;32FB;32FB;30EF;30EF; # (㋻; ㋻; ㋻; ワ; ワ; ) CIRCLED KATAKANA WA +32FC;32FC;32FC;30F0;30F0; # (㋼; ㋼; ㋼; ヰ; ヰ; ) CIRCLED KATAKANA WI +32FD;32FD;32FD;30F1;30F1; # (㋽; ㋽; ㋽; ヱ; ヱ; ) CIRCLED KATAKANA WE +32FE;32FE;32FE;30F2;30F2; # (㋾; ㋾; ㋾; ヲ; ヲ; ) CIRCLED KATAKANA WO +32FF;32FF;32FF;4EE4 548C;4EE4 548C; # (㋿; ㋿; ㋿; 令和; 令和; ) SQUARE ERA NAME REIWA +3300;3300;3300;30A2 30D1 30FC 30C8;30A2 30CF 309A 30FC 30C8; # (㌀; ㌀; ㌀; アパート; アハ◌゚ート; ) SQUARE APAATO +3301;3301;3301;30A2 30EB 30D5 30A1;30A2 30EB 30D5 30A1; # (㌁; ㌁; ㌁; アルファ; アルファ; ) SQUARE ARUHUA +3302;3302;3302;30A2 30F3 30DA 30A2;30A2 30F3 30D8 309A 30A2; # (㌂; ㌂; ㌂; アンペア; アンヘ◌゚ア; ) SQUARE ANPEA +3303;3303;3303;30A2 30FC 30EB;30A2 30FC 30EB; # (㌃; ㌃; ㌃; アール; アール; ) SQUARE AARU +3304;3304;3304;30A4 30CB 30F3 30B0;30A4 30CB 30F3 30AF 3099; # (㌄; ㌄; ㌄; イニング; イニンク◌゙; ) SQUARE ININGU +3305;3305;3305;30A4 30F3 30C1;30A4 30F3 30C1; # (㌅; ㌅; ㌅; インチ; インチ; ) SQUARE INTI +3306;3306;3306;30A6 30A9 30F3;30A6 30A9 30F3; # (㌆; ㌆; ㌆; ウォン; ウォン; ) SQUARE UON +3307;3307;3307;30A8 30B9 30AF 30FC 30C9;30A8 30B9 30AF 30FC 30C8 3099; # (㌇; ㌇; ㌇; エスクード; エスクート◌゙; ) SQUARE ESUKUUDO +3308;3308;3308;30A8 30FC 30AB 30FC;30A8 30FC 30AB 30FC; # (㌈; ㌈; ㌈; エーカー; エーカー; ) SQUARE EEKAA +3309;3309;3309;30AA 30F3 30B9;30AA 30F3 30B9; # (㌉; ㌉; ㌉; オンス; オンス; ) SQUARE ONSU +330A;330A;330A;30AA 30FC 30E0;30AA 30FC 30E0; # (㌊; ㌊; ㌊; オーム; オーム; ) SQUARE OOMU +330B;330B;330B;30AB 30A4 30EA;30AB 30A4 30EA; # (㌋; ㌋; ㌋; カイリ; カイリ; ) SQUARE KAIRI +330C;330C;330C;30AB 30E9 30C3 30C8;30AB 30E9 30C3 30C8; # (㌌; ㌌; ㌌; カラット; カラット; ) SQUARE KARATTO +330D;330D;330D;30AB 30ED 30EA 30FC;30AB 30ED 30EA 30FC; # (㌍; ㌍; ㌍; カロリー; カロリー; ) SQUARE KARORII +330E;330E;330E;30AC 30ED 30F3;30AB 3099 30ED 30F3; # (㌎; ㌎; ㌎; ガロン; カ◌゙ロン; ) SQUARE GARON +330F;330F;330F;30AC 30F3 30DE;30AB 3099 30F3 30DE; # (㌏; ㌏; ㌏; ガンマ; カ◌゙ンマ; ) SQUARE GANMA +3310;3310;3310;30AE 30AC;30AD 3099 30AB 3099; # (㌐; ㌐; ㌐; ギガ; キ◌゙カ◌゙; ) SQUARE GIGA +3311;3311;3311;30AE 30CB 30FC;30AD 3099 30CB 30FC; # (㌑; ㌑; ㌑; ギニー; キ◌゙ニー; ) SQUARE GINII +3312;3312;3312;30AD 30E5 30EA 30FC;30AD 30E5 30EA 30FC; # (㌒; ㌒; ㌒; キュリー; キュリー; ) SQUARE KYURII +3313;3313;3313;30AE 30EB 30C0 30FC;30AD 3099 30EB 30BF 3099 30FC; # (㌓; ㌓; ㌓; ギルダー; キ◌゙ルタ◌゙ー; ) SQUARE GIRUDAA +3314;3314;3314;30AD 30ED;30AD 30ED; # (㌔; ㌔; ㌔; キロ; キロ; ) SQUARE KIRO +3315;3315;3315;30AD 30ED 30B0 30E9 30E0;30AD 30ED 30AF 3099 30E9 30E0; # (㌕; ㌕; ㌕; キログラム; キロク◌゙ラム; ) SQUARE KIROGURAMU +3316;3316;3316;30AD 30ED 30E1 30FC 30C8 30EB;30AD 30ED 30E1 30FC 30C8 30EB; # (㌖; ㌖; ㌖; キロメートル; キロメートル; ) SQUARE KIROMEETORU +3317;3317;3317;30AD 30ED 30EF 30C3 30C8;30AD 30ED 30EF 30C3 30C8; # (㌗; ㌗; ㌗; キロワット; キロワット; ) SQUARE KIROWATTO +3318;3318;3318;30B0 30E9 30E0;30AF 3099 30E9 30E0; # (㌘; ㌘; ㌘; グラム; ク◌゙ラム; ) SQUARE GURAMU +3319;3319;3319;30B0 30E9 30E0 30C8 30F3;30AF 3099 30E9 30E0 30C8 30F3; # (㌙; ㌙; ㌙; グラムトン; ク◌゙ラムトン; ) SQUARE GURAMUTON +331A;331A;331A;30AF 30EB 30BC 30A4 30ED;30AF 30EB 30BB 3099 30A4 30ED; # (㌚; ㌚; ㌚; クルゼイロ; クルセ◌゙イロ; ) SQUARE KURUZEIRO +331B;331B;331B;30AF 30ED 30FC 30CD;30AF 30ED 30FC 30CD; # (㌛; ㌛; ㌛; クローネ; クローネ; ) SQUARE KUROONE +331C;331C;331C;30B1 30FC 30B9;30B1 30FC 30B9; # (㌜; ㌜; ㌜; ケース; ケース; ) SQUARE KEESU +331D;331D;331D;30B3 30EB 30CA;30B3 30EB 30CA; # (㌝; ㌝; ㌝; コルナ; コルナ; ) SQUARE KORUNA +331E;331E;331E;30B3 30FC 30DD;30B3 30FC 30DB 309A; # (㌞; ㌞; ㌞; コーポ; コーホ◌゚; ) SQUARE KOOPO +331F;331F;331F;30B5 30A4 30AF 30EB;30B5 30A4 30AF 30EB; # (㌟; ㌟; ㌟; サイクル; サイクル; ) SQUARE SAIKURU +3320;3320;3320;30B5 30F3 30C1 30FC 30E0;30B5 30F3 30C1 30FC 30E0; # (㌠; ㌠; ㌠; サンチーム; サンチーム; ) SQUARE SANTIIMU +3321;3321;3321;30B7 30EA 30F3 30B0;30B7 30EA 30F3 30AF 3099; # (㌡; ㌡; ㌡; シリング; シリンク◌゙; ) SQUARE SIRINGU +3322;3322;3322;30BB 30F3 30C1;30BB 30F3 30C1; # (㌢; ㌢; ㌢; センチ; センチ; ) SQUARE SENTI +3323;3323;3323;30BB 30F3 30C8;30BB 30F3 30C8; # (㌣; ㌣; ㌣; セント; セント; ) SQUARE SENTO +3324;3324;3324;30C0 30FC 30B9;30BF 3099 30FC 30B9; # (㌤; ㌤; ㌤; ダース; タ◌゙ース; ) SQUARE DAASU +3325;3325;3325;30C7 30B7;30C6 3099 30B7; # (㌥; ㌥; ㌥; デシ; テ◌゙シ; ) SQUARE DESI +3326;3326;3326;30C9 30EB;30C8 3099 30EB; # (㌦; ㌦; ㌦; ドル; ト◌゙ル; ) SQUARE DORU +3327;3327;3327;30C8 30F3;30C8 30F3; # (㌧; ㌧; ㌧; トン; トン; ) SQUARE TON +3328;3328;3328;30CA 30CE;30CA 30CE; # (㌨; ㌨; ㌨; ナノ; ナノ; ) SQUARE NANO +3329;3329;3329;30CE 30C3 30C8;30CE 30C3 30C8; # (㌩; ㌩; ㌩; ノット; ノット; ) SQUARE NOTTO +332A;332A;332A;30CF 30A4 30C4;30CF 30A4 30C4; # (㌪; ㌪; ㌪; ハイツ; ハイツ; ) SQUARE HAITU +332B;332B;332B;30D1 30FC 30BB 30F3 30C8;30CF 309A 30FC 30BB 30F3 30C8; # (㌫; ㌫; ㌫; パーセント; ハ◌゚ーセント; ) SQUARE PAASENTO +332C;332C;332C;30D1 30FC 30C4;30CF 309A 30FC 30C4; # (㌬; ㌬; ㌬; パーツ; ハ◌゚ーツ; ) SQUARE PAATU +332D;332D;332D;30D0 30FC 30EC 30EB;30CF 3099 30FC 30EC 30EB; # (㌭; ㌭; ㌭; バーレル; ハ◌゙ーレル; ) SQUARE BAARERU +332E;332E;332E;30D4 30A2 30B9 30C8 30EB;30D2 309A 30A2 30B9 30C8 30EB; # (㌮; ㌮; ㌮; ピアストル; ヒ◌゚アストル; ) SQUARE PIASUTORU +332F;332F;332F;30D4 30AF 30EB;30D2 309A 30AF 30EB; # (㌯; ㌯; ㌯; ピクル; ヒ◌゚クル; ) SQUARE PIKURU +3330;3330;3330;30D4 30B3;30D2 309A 30B3; # (㌰; ㌰; ㌰; ピコ; ヒ◌゚コ; ) SQUARE PIKO +3331;3331;3331;30D3 30EB;30D2 3099 30EB; # (㌱; ㌱; ㌱; ビル; ヒ◌゙ル; ) SQUARE BIRU +3332;3332;3332;30D5 30A1 30E9 30C3 30C9;30D5 30A1 30E9 30C3 30C8 3099; # (㌲; ㌲; ㌲; ファラッド; ファラット◌゙; ) SQUARE HUARADDO +3333;3333;3333;30D5 30A3 30FC 30C8;30D5 30A3 30FC 30C8; # (㌳; ㌳; ㌳; フィート; フィート; ) SQUARE HUIITO +3334;3334;3334;30D6 30C3 30B7 30A7 30EB;30D5 3099 30C3 30B7 30A7 30EB; # (㌴; ㌴; ㌴; ブッシェル; フ◌゙ッシェル; ) SQUARE BUSSYERU +3335;3335;3335;30D5 30E9 30F3;30D5 30E9 30F3; # (㌵; ㌵; ㌵; フラン; フラン; ) SQUARE HURAN +3336;3336;3336;30D8 30AF 30BF 30FC 30EB;30D8 30AF 30BF 30FC 30EB; # (㌶; ㌶; ㌶; ヘクタール; ヘクタール; ) SQUARE HEKUTAARU +3337;3337;3337;30DA 30BD;30D8 309A 30BD; # (㌷; ㌷; ㌷; ペソ; ヘ◌゚ソ; ) SQUARE PESO +3338;3338;3338;30DA 30CB 30D2;30D8 309A 30CB 30D2; # (㌸; ㌸; ㌸; ペニヒ; ヘ◌゚ニヒ; ) SQUARE PENIHI +3339;3339;3339;30D8 30EB 30C4;30D8 30EB 30C4; # (㌹; ㌹; ㌹; ヘルツ; ヘルツ; ) SQUARE HERUTU +333A;333A;333A;30DA 30F3 30B9;30D8 309A 30F3 30B9; # (㌺; ㌺; ㌺; ペンス; ヘ◌゚ンス; ) SQUARE PENSU +333B;333B;333B;30DA 30FC 30B8;30D8 309A 30FC 30B7 3099; # (㌻; ㌻; ㌻; ページ; ヘ◌゚ーシ◌゙; ) SQUARE PEEZI +333C;333C;333C;30D9 30FC 30BF;30D8 3099 30FC 30BF; # (㌼; ㌼; ㌼; ベータ; ヘ◌゙ータ; ) SQUARE BEETA +333D;333D;333D;30DD 30A4 30F3 30C8;30DB 309A 30A4 30F3 30C8; # (㌽; ㌽; ㌽; ポイント; ホ◌゚イント; ) SQUARE POINTO +333E;333E;333E;30DC 30EB 30C8;30DB 3099 30EB 30C8; # (㌾; ㌾; ㌾; ボルト; ホ◌゙ルト; ) SQUARE BORUTO +333F;333F;333F;30DB 30F3;30DB 30F3; # (㌿; ㌿; ㌿; ホン; ホン; ) SQUARE HON +3340;3340;3340;30DD 30F3 30C9;30DB 309A 30F3 30C8 3099; # (㍀; ㍀; ㍀; ポンド; ホ◌゚ント◌゙; ) SQUARE PONDO +3341;3341;3341;30DB 30FC 30EB;30DB 30FC 30EB; # (㍁; ㍁; ㍁; ホール; ホール; ) SQUARE HOORU +3342;3342;3342;30DB 30FC 30F3;30DB 30FC 30F3; # (㍂; ㍂; ㍂; ホーン; ホーン; ) SQUARE HOON +3343;3343;3343;30DE 30A4 30AF 30ED;30DE 30A4 30AF 30ED; # (㍃; ㍃; ㍃; マイクロ; マイクロ; ) SQUARE MAIKURO +3344;3344;3344;30DE 30A4 30EB;30DE 30A4 30EB; # (㍄; ㍄; ㍄; マイル; マイル; ) SQUARE MAIRU +3345;3345;3345;30DE 30C3 30CF;30DE 30C3 30CF; # (㍅; ㍅; ㍅; マッハ; マッハ; ) SQUARE MAHHA +3346;3346;3346;30DE 30EB 30AF;30DE 30EB 30AF; # (㍆; ㍆; ㍆; マルク; マルク; ) SQUARE MARUKU +3347;3347;3347;30DE 30F3 30B7 30E7 30F3;30DE 30F3 30B7 30E7 30F3; # (㍇; ㍇; ㍇; マンション; マンション; ) SQUARE MANSYON +3348;3348;3348;30DF 30AF 30ED 30F3;30DF 30AF 30ED 30F3; # (㍈; ㍈; ㍈; ミクロン; ミクロン; ) SQUARE MIKURON +3349;3349;3349;30DF 30EA;30DF 30EA; # (㍉; ㍉; ㍉; ミリ; ミリ; ) SQUARE MIRI +334A;334A;334A;30DF 30EA 30D0 30FC 30EB;30DF 30EA 30CF 3099 30FC 30EB; # (㍊; ㍊; ㍊; ミリバール; ミリハ◌゙ール; ) SQUARE MIRIBAARU +334B;334B;334B;30E1 30AC;30E1 30AB 3099; # (㍋; ㍋; ㍋; メガ; メカ◌゙; ) SQUARE MEGA +334C;334C;334C;30E1 30AC 30C8 30F3;30E1 30AB 3099 30C8 30F3; # (㍌; ㍌; ㍌; メガトン; メカ◌゙トン; ) SQUARE MEGATON +334D;334D;334D;30E1 30FC 30C8 30EB;30E1 30FC 30C8 30EB; # (㍍; ㍍; ㍍; メートル; メートル; ) SQUARE MEETORU +334E;334E;334E;30E4 30FC 30C9;30E4 30FC 30C8 3099; # (㍎; ㍎; ㍎; ヤード; ヤート◌゙; ) SQUARE YAADO +334F;334F;334F;30E4 30FC 30EB;30E4 30FC 30EB; # (㍏; ㍏; ㍏; ヤール; ヤール; ) SQUARE YAARU +3350;3350;3350;30E6 30A2 30F3;30E6 30A2 30F3; # (㍐; ㍐; ㍐; ユアン; ユアン; ) SQUARE YUAN +3351;3351;3351;30EA 30C3 30C8 30EB;30EA 30C3 30C8 30EB; # (㍑; ㍑; ㍑; リットル; リットル; ) SQUARE RITTORU +3352;3352;3352;30EA 30E9;30EA 30E9; # (㍒; ㍒; ㍒; リラ; リラ; ) SQUARE RIRA +3353;3353;3353;30EB 30D4 30FC;30EB 30D2 309A 30FC; # (㍓; ㍓; ㍓; ルピー; ルヒ◌゚ー; ) SQUARE RUPII +3354;3354;3354;30EB 30FC 30D6 30EB;30EB 30FC 30D5 3099 30EB; # (㍔; ㍔; ㍔; ルーブル; ルーフ◌゙ル; ) SQUARE RUUBURU +3355;3355;3355;30EC 30E0;30EC 30E0; # (㍕; ㍕; ㍕; レム; レム; ) SQUARE REMU +3356;3356;3356;30EC 30F3 30C8 30B2 30F3;30EC 30F3 30C8 30B1 3099 30F3; # (㍖; ㍖; ㍖; レントゲン; レントケ◌゙ン; ) SQUARE RENTOGEN +3357;3357;3357;30EF 30C3 30C8;30EF 30C3 30C8; # (㍗; ㍗; ㍗; ワット; ワット; ) SQUARE WATTO +3358;3358;3358;0030 70B9;0030 70B9; # (㍘; ㍘; ㍘; 0点; 0点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO +3359;3359;3359;0031 70B9;0031 70B9; # (㍙; ㍙; ㍙; 1点; 1点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE +335A;335A;335A;0032 70B9;0032 70B9; # (㍚; ㍚; ㍚; 2点; 2点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO +335B;335B;335B;0033 70B9;0033 70B9; # (㍛; ㍛; ㍛; 3点; 3点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE +335C;335C;335C;0034 70B9;0034 70B9; # (㍜; ㍜; ㍜; 4点; 4点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR +335D;335D;335D;0035 70B9;0035 70B9; # (㍝; ㍝; ㍝; 5点; 5点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE +335E;335E;335E;0036 70B9;0036 70B9; # (㍞; ㍞; ㍞; 6点; 6点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX +335F;335F;335F;0037 70B9;0037 70B9; # (㍟; ㍟; ㍟; 7点; 7点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN +3360;3360;3360;0038 70B9;0038 70B9; # (㍠; ㍠; ㍠; 8点; 8点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT +3361;3361;3361;0039 70B9;0039 70B9; # (㍡; ㍡; ㍡; 9点; 9点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE +3362;3362;3362;0031 0030 70B9;0031 0030 70B9; # (㍢; ㍢; ㍢; 10点; 10点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN +3363;3363;3363;0031 0031 70B9;0031 0031 70B9; # (㍣; ㍣; ㍣; 11点; 11点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN +3364;3364;3364;0031 0032 70B9;0031 0032 70B9; # (㍤; ㍤; ㍤; 12点; 12点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE +3365;3365;3365;0031 0033 70B9;0031 0033 70B9; # (㍥; ㍥; ㍥; 13点; 13点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN +3366;3366;3366;0031 0034 70B9;0031 0034 70B9; # (㍦; ㍦; ㍦; 14点; 14点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN +3367;3367;3367;0031 0035 70B9;0031 0035 70B9; # (㍧; ㍧; ㍧; 15点; 15点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN +3368;3368;3368;0031 0036 70B9;0031 0036 70B9; # (㍨; ㍨; ㍨; 16点; 16点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN +3369;3369;3369;0031 0037 70B9;0031 0037 70B9; # (㍩; ㍩; ㍩; 17点; 17点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN +336A;336A;336A;0031 0038 70B9;0031 0038 70B9; # (㍪; ㍪; ㍪; 18点; 18点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN +336B;336B;336B;0031 0039 70B9;0031 0039 70B9; # (㍫; ㍫; ㍫; 19点; 19点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN +336C;336C;336C;0032 0030 70B9;0032 0030 70B9; # (㍬; ㍬; ㍬; 20点; 20点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY +336D;336D;336D;0032 0031 70B9;0032 0031 70B9; # (㍭; ㍭; ㍭; 21点; 21点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE +336E;336E;336E;0032 0032 70B9;0032 0032 70B9; # (㍮; ㍮; ㍮; 22点; 22点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO +336F;336F;336F;0032 0033 70B9;0032 0033 70B9; # (㍯; ㍯; ㍯; 23点; 23点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE +3370;3370;3370;0032 0034 70B9;0032 0034 70B9; # (㍰; ㍰; ㍰; 24点; 24点; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR +3371;3371;3371;0068 0050 0061;0068 0050 0061; # (㍱; ㍱; ㍱; hPa; hPa; ) SQUARE HPA +3372;3372;3372;0064 0061;0064 0061; # (㍲; ㍲; ㍲; da; da; ) SQUARE DA +3373;3373;3373;0041 0055;0041 0055; # (㍳; ㍳; ㍳; AU; AU; ) SQUARE AU +3374;3374;3374;0062 0061 0072;0062 0061 0072; # (㍴; ㍴; ㍴; bar; bar; ) SQUARE BAR +3375;3375;3375;006F 0056;006F 0056; # (㍵; ㍵; ㍵; oV; oV; ) SQUARE OV +3376;3376;3376;0070 0063;0070 0063; # (㍶; ㍶; ㍶; pc; pc; ) SQUARE PC +3377;3377;3377;0064 006D;0064 006D; # (㍷; ㍷; ㍷; dm; dm; ) SQUARE DM +3378;3378;3378;0064 006D 0032;0064 006D 0032; # (㍸; ㍸; ㍸; dm2; dm2; ) SQUARE DM SQUARED +3379;3379;3379;0064 006D 0033;0064 006D 0033; # (㍹; ㍹; ㍹; dm3; dm3; ) SQUARE DM CUBED +337A;337A;337A;0049 0055;0049 0055; # (㍺; ㍺; ㍺; IU; IU; ) SQUARE IU +337B;337B;337B;5E73 6210;5E73 6210; # (㍻; ㍻; ㍻; 平成; 平成; ) SQUARE ERA NAME HEISEI +337C;337C;337C;662D 548C;662D 548C; # (㍼; ㍼; ㍼; 昭和; 昭和; ) SQUARE ERA NAME SYOUWA +337D;337D;337D;5927 6B63;5927 6B63; # (㍽; ㍽; ㍽; 大正; 大正; ) SQUARE ERA NAME TAISYOU +337E;337E;337E;660E 6CBB;660E 6CBB; # (㍾; ㍾; ㍾; 明治; 明治; ) SQUARE ERA NAME MEIZI +337F;337F;337F;682A 5F0F 4F1A 793E;682A 5F0F 4F1A 793E; # (㍿; ㍿; ㍿; 株式会社; 株式会社; ) SQUARE CORPORATION +3380;3380;3380;0070 0041;0070 0041; # (㎀; ㎀; ㎀; pA; pA; ) SQUARE PA AMPS +3381;3381;3381;006E 0041;006E 0041; # (㎁; ㎁; ㎁; nA; nA; ) SQUARE NA +3382;3382;3382;03BC 0041;03BC 0041; # (㎂; ㎂; ㎂; μA; μA; ) SQUARE MU A +3383;3383;3383;006D 0041;006D 0041; # (㎃; ㎃; ㎃; mA; mA; ) SQUARE MA +3384;3384;3384;006B 0041;006B 0041; # (㎄; ㎄; ㎄; kA; kA; ) SQUARE KA +3385;3385;3385;004B 0042;004B 0042; # (㎅; ㎅; ㎅; KB; KB; ) SQUARE KB +3386;3386;3386;004D 0042;004D 0042; # (㎆; ㎆; ㎆; MB; MB; ) SQUARE MB +3387;3387;3387;0047 0042;0047 0042; # (㎇; ㎇; ㎇; GB; GB; ) SQUARE GB +3388;3388;3388;0063 0061 006C;0063 0061 006C; # (㎈; ㎈; ㎈; cal; cal; ) SQUARE CAL +3389;3389;3389;006B 0063 0061 006C;006B 0063 0061 006C; # (㎉; ㎉; ㎉; kcal; kcal; ) SQUARE KCAL +338A;338A;338A;0070 0046;0070 0046; # (㎊; ㎊; ㎊; pF; pF; ) SQUARE PF +338B;338B;338B;006E 0046;006E 0046; # (㎋; ㎋; ㎋; nF; nF; ) SQUARE NF +338C;338C;338C;03BC 0046;03BC 0046; # (㎌; ㎌; ㎌; μF; μF; ) SQUARE MU F +338D;338D;338D;03BC 0067;03BC 0067; # (㎍; ㎍; ㎍; μg; μg; ) SQUARE MU G +338E;338E;338E;006D 0067;006D 0067; # (㎎; ㎎; ㎎; mg; mg; ) SQUARE MG +338F;338F;338F;006B 0067;006B 0067; # (㎏; ㎏; ㎏; kg; kg; ) SQUARE KG +3390;3390;3390;0048 007A;0048 007A; # (㎐; ㎐; ㎐; Hz; Hz; ) SQUARE HZ +3391;3391;3391;006B 0048 007A;006B 0048 007A; # (㎑; ㎑; ㎑; kHz; kHz; ) SQUARE KHZ +3392;3392;3392;004D 0048 007A;004D 0048 007A; # (㎒; ㎒; ㎒; MHz; MHz; ) SQUARE MHZ +3393;3393;3393;0047 0048 007A;0047 0048 007A; # (㎓; ㎓; ㎓; GHz; GHz; ) SQUARE GHZ +3394;3394;3394;0054 0048 007A;0054 0048 007A; # (㎔; ㎔; ㎔; THz; THz; ) SQUARE THZ +3395;3395;3395;03BC 006C;03BC 006C; # (㎕; ㎕; ㎕; μl; μl; ) SQUARE MU L +3396;3396;3396;006D 006C;006D 006C; # (㎖; ㎖; ㎖; ml; ml; ) SQUARE ML +3397;3397;3397;0064 006C;0064 006C; # (㎗; ㎗; ㎗; dl; dl; ) SQUARE DL +3398;3398;3398;006B 006C;006B 006C; # (㎘; ㎘; ㎘; kl; kl; ) SQUARE KL +3399;3399;3399;0066 006D;0066 006D; # (㎙; ㎙; ㎙; fm; fm; ) SQUARE FM +339A;339A;339A;006E 006D;006E 006D; # (㎚; ㎚; ㎚; nm; nm; ) SQUARE NM +339B;339B;339B;03BC 006D;03BC 006D; # (㎛; ㎛; ㎛; μm; μm; ) SQUARE MU M +339C;339C;339C;006D 006D;006D 006D; # (㎜; ㎜; ㎜; mm; mm; ) SQUARE MM +339D;339D;339D;0063 006D;0063 006D; # (㎝; ㎝; ㎝; cm; cm; ) SQUARE CM +339E;339E;339E;006B 006D;006B 006D; # (㎞; ㎞; ㎞; km; km; ) SQUARE KM +339F;339F;339F;006D 006D 0032;006D 006D 0032; # (㎟; ㎟; ㎟; mm2; mm2; ) SQUARE MM SQUARED +33A0;33A0;33A0;0063 006D 0032;0063 006D 0032; # (㎠; ㎠; ㎠; cm2; cm2; ) SQUARE CM SQUARED +33A1;33A1;33A1;006D 0032;006D 0032; # (㎡; ㎡; ㎡; m2; m2; ) SQUARE M SQUARED +33A2;33A2;33A2;006B 006D 0032;006B 006D 0032; # (㎢; ㎢; ㎢; km2; km2; ) SQUARE KM SQUARED +33A3;33A3;33A3;006D 006D 0033;006D 006D 0033; # (㎣; ㎣; ㎣; mm3; mm3; ) SQUARE MM CUBED +33A4;33A4;33A4;0063 006D 0033;0063 006D 0033; # (㎤; ㎤; ㎤; cm3; cm3; ) SQUARE CM CUBED +33A5;33A5;33A5;006D 0033;006D 0033; # (㎥; ㎥; ㎥; m3; m3; ) SQUARE M CUBED +33A6;33A6;33A6;006B 006D 0033;006B 006D 0033; # (㎦; ㎦; ㎦; km3; km3; ) SQUARE KM CUBED +33A7;33A7;33A7;006D 2215 0073;006D 2215 0073; # (㎧; ㎧; ㎧; m∕s; m∕s; ) SQUARE M OVER S +33A8;33A8;33A8;006D 2215 0073 0032;006D 2215 0073 0032; # (㎨; ㎨; ㎨; m∕s2; m∕s2; ) SQUARE M OVER S SQUARED +33A9;33A9;33A9;0050 0061;0050 0061; # (㎩; ㎩; ㎩; Pa; Pa; ) SQUARE PA +33AA;33AA;33AA;006B 0050 0061;006B 0050 0061; # (㎪; ㎪; ㎪; kPa; kPa; ) SQUARE KPA +33AB;33AB;33AB;004D 0050 0061;004D 0050 0061; # (㎫; ㎫; ㎫; MPa; MPa; ) SQUARE MPA +33AC;33AC;33AC;0047 0050 0061;0047 0050 0061; # (㎬; ㎬; ㎬; GPa; GPa; ) SQUARE GPA +33AD;33AD;33AD;0072 0061 0064;0072 0061 0064; # (㎭; ㎭; ㎭; rad; rad; ) SQUARE RAD +33AE;33AE;33AE;0072 0061 0064 2215 0073;0072 0061 0064 2215 0073; # (㎮; ㎮; ㎮; rad∕s; rad∕s; ) SQUARE RAD OVER S +33AF;33AF;33AF;0072 0061 0064 2215 0073 0032;0072 0061 0064 2215 0073 0032; # (㎯; ㎯; ㎯; rad∕s2; rad∕s2; ) SQUARE RAD OVER S SQUARED +33B0;33B0;33B0;0070 0073;0070 0073; # (㎰; ㎰; ㎰; ps; ps; ) SQUARE PS +33B1;33B1;33B1;006E 0073;006E 0073; # (㎱; ㎱; ㎱; ns; ns; ) SQUARE NS +33B2;33B2;33B2;03BC 0073;03BC 0073; # (㎲; ㎲; ㎲; μs; μs; ) SQUARE MU S +33B3;33B3;33B3;006D 0073;006D 0073; # (㎳; ㎳; ㎳; ms; ms; ) SQUARE MS +33B4;33B4;33B4;0070 0056;0070 0056; # (㎴; ㎴; ㎴; pV; pV; ) SQUARE PV +33B5;33B5;33B5;006E 0056;006E 0056; # (㎵; ㎵; ㎵; nV; nV; ) SQUARE NV +33B6;33B6;33B6;03BC 0056;03BC 0056; # (㎶; ㎶; ㎶; μV; μV; ) SQUARE MU V +33B7;33B7;33B7;006D 0056;006D 0056; # (㎷; ㎷; ㎷; mV; mV; ) SQUARE MV +33B8;33B8;33B8;006B 0056;006B 0056; # (㎸; ㎸; ㎸; kV; kV; ) SQUARE KV +33B9;33B9;33B9;004D 0056;004D 0056; # (㎹; ㎹; ㎹; MV; MV; ) SQUARE MV MEGA +33BA;33BA;33BA;0070 0057;0070 0057; # (㎺; ㎺; ㎺; pW; pW; ) SQUARE PW +33BB;33BB;33BB;006E 0057;006E 0057; # (㎻; ㎻; ㎻; nW; nW; ) SQUARE NW +33BC;33BC;33BC;03BC 0057;03BC 0057; # (㎼; ㎼; ㎼; μW; μW; ) SQUARE MU W +33BD;33BD;33BD;006D 0057;006D 0057; # (㎽; ㎽; ㎽; mW; mW; ) SQUARE MW +33BE;33BE;33BE;006B 0057;006B 0057; # (㎾; ㎾; ㎾; kW; kW; ) SQUARE KW +33BF;33BF;33BF;004D 0057;004D 0057; # (㎿; ㎿; ㎿; MW; MW; ) SQUARE MW MEGA +33C0;33C0;33C0;006B 03A9;006B 03A9; # (㏀; ㏀; ㏀; kΩ; kΩ; ) SQUARE K OHM +33C1;33C1;33C1;004D 03A9;004D 03A9; # (㏁; ㏁; ㏁; MΩ; MΩ; ) SQUARE M OHM +33C2;33C2;33C2;0061 002E 006D 002E;0061 002E 006D 002E; # (㏂; ㏂; ㏂; a.m.; a.m.; ) SQUARE AM +33C3;33C3;33C3;0042 0071;0042 0071; # (㏃; ㏃; ㏃; Bq; Bq; ) SQUARE BQ +33C4;33C4;33C4;0063 0063;0063 0063; # (㏄; ㏄; ㏄; cc; cc; ) SQUARE CC +33C5;33C5;33C5;0063 0064;0063 0064; # (㏅; ㏅; ㏅; cd; cd; ) SQUARE CD +33C6;33C6;33C6;0043 2215 006B 0067;0043 2215 006B 0067; # (㏆; ㏆; ㏆; C∕kg; C∕kg; ) SQUARE C OVER KG +33C7;33C7;33C7;0043 006F 002E;0043 006F 002E; # (㏇; ㏇; ㏇; Co.; Co.; ) SQUARE CO +33C8;33C8;33C8;0064 0042;0064 0042; # (㏈; ㏈; ㏈; dB; dB; ) SQUARE DB +33C9;33C9;33C9;0047 0079;0047 0079; # (㏉; ㏉; ㏉; Gy; Gy; ) SQUARE GY +33CA;33CA;33CA;0068 0061;0068 0061; # (㏊; ㏊; ㏊; ha; ha; ) SQUARE HA +33CB;33CB;33CB;0048 0050;0048 0050; # (㏋; ㏋; ㏋; HP; HP; ) SQUARE HP +33CC;33CC;33CC;0069 006E;0069 006E; # (㏌; ㏌; ㏌; in; in; ) SQUARE IN +33CD;33CD;33CD;004B 004B;004B 004B; # (㏍; ㏍; ㏍; KK; KK; ) SQUARE KK +33CE;33CE;33CE;004B 004D;004B 004D; # (㏎; ㏎; ㏎; KM; KM; ) SQUARE KM CAPITAL +33CF;33CF;33CF;006B 0074;006B 0074; # (㏏; ㏏; ㏏; kt; kt; ) SQUARE KT +33D0;33D0;33D0;006C 006D;006C 006D; # (㏐; ㏐; ㏐; lm; lm; ) SQUARE LM +33D1;33D1;33D1;006C 006E;006C 006E; # (㏑; ㏑; ㏑; ln; ln; ) SQUARE LN +33D2;33D2;33D2;006C 006F 0067;006C 006F 0067; # (㏒; ㏒; ㏒; log; log; ) SQUARE LOG +33D3;33D3;33D3;006C 0078;006C 0078; # (㏓; ㏓; ㏓; lx; lx; ) SQUARE LX +33D4;33D4;33D4;006D 0062;006D 0062; # (㏔; ㏔; ㏔; mb; mb; ) SQUARE MB SMALL +33D5;33D5;33D5;006D 0069 006C;006D 0069 006C; # (㏕; ㏕; ㏕; mil; mil; ) SQUARE MIL +33D6;33D6;33D6;006D 006F 006C;006D 006F 006C; # (㏖; ㏖; ㏖; mol; mol; ) SQUARE MOL +33D7;33D7;33D7;0050 0048;0050 0048; # (㏗; ㏗; ㏗; PH; PH; ) SQUARE PH +33D8;33D8;33D8;0070 002E 006D 002E;0070 002E 006D 002E; # (㏘; ㏘; ㏘; p.m.; p.m.; ) SQUARE PM +33D9;33D9;33D9;0050 0050 004D;0050 0050 004D; # (㏙; ㏙; ㏙; PPM; PPM; ) SQUARE PPM +33DA;33DA;33DA;0050 0052;0050 0052; # (㏚; ㏚; ㏚; PR; PR; ) SQUARE PR +33DB;33DB;33DB;0073 0072;0073 0072; # (㏛; ㏛; ㏛; sr; sr; ) SQUARE SR +33DC;33DC;33DC;0053 0076;0053 0076; # (㏜; ㏜; ㏜; Sv; Sv; ) SQUARE SV +33DD;33DD;33DD;0057 0062;0057 0062; # (㏝; ㏝; ㏝; Wb; Wb; ) SQUARE WB +33DE;33DE;33DE;0056 2215 006D;0056 2215 006D; # (㏞; ㏞; ㏞; V∕m; V∕m; ) SQUARE V OVER M +33DF;33DF;33DF;0041 2215 006D;0041 2215 006D; # (㏟; ㏟; ㏟; A∕m; A∕m; ) SQUARE A OVER M +33E0;33E0;33E0;0031 65E5;0031 65E5; # (㏠; ㏠; ㏠; 1日; 1日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE +33E1;33E1;33E1;0032 65E5;0032 65E5; # (㏡; ㏡; ㏡; 2日; 2日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO +33E2;33E2;33E2;0033 65E5;0033 65E5; # (㏢; ㏢; ㏢; 3日; 3日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE +33E3;33E3;33E3;0034 65E5;0034 65E5; # (㏣; ㏣; ㏣; 4日; 4日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR +33E4;33E4;33E4;0035 65E5;0035 65E5; # (㏤; ㏤; ㏤; 5日; 5日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE +33E5;33E5;33E5;0036 65E5;0036 65E5; # (㏥; ㏥; ㏥; 6日; 6日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX +33E6;33E6;33E6;0037 65E5;0037 65E5; # (㏦; ㏦; ㏦; 7日; 7日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN +33E7;33E7;33E7;0038 65E5;0038 65E5; # (㏧; ㏧; ㏧; 8日; 8日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT +33E8;33E8;33E8;0039 65E5;0039 65E5; # (㏨; ㏨; ㏨; 9日; 9日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE +33E9;33E9;33E9;0031 0030 65E5;0031 0030 65E5; # (㏩; ㏩; ㏩; 10日; 10日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN +33EA;33EA;33EA;0031 0031 65E5;0031 0031 65E5; # (㏪; ㏪; ㏪; 11日; 11日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN +33EB;33EB;33EB;0031 0032 65E5;0031 0032 65E5; # (㏫; ㏫; ㏫; 12日; 12日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE +33EC;33EC;33EC;0031 0033 65E5;0031 0033 65E5; # (㏬; ㏬; ㏬; 13日; 13日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN +33ED;33ED;33ED;0031 0034 65E5;0031 0034 65E5; # (㏭; ㏭; ㏭; 14日; 14日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN +33EE;33EE;33EE;0031 0035 65E5;0031 0035 65E5; # (㏮; ㏮; ㏮; 15日; 15日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN +33EF;33EF;33EF;0031 0036 65E5;0031 0036 65E5; # (㏯; ㏯; ㏯; 16日; 16日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN +33F0;33F0;33F0;0031 0037 65E5;0031 0037 65E5; # (㏰; ㏰; ㏰; 17日; 17日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN +33F1;33F1;33F1;0031 0038 65E5;0031 0038 65E5; # (㏱; ㏱; ㏱; 18日; 18日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN +33F2;33F2;33F2;0031 0039 65E5;0031 0039 65E5; # (㏲; ㏲; ㏲; 19日; 19日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN +33F3;33F3;33F3;0032 0030 65E5;0032 0030 65E5; # (㏳; ㏳; ㏳; 20日; 20日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY +33F4;33F4;33F4;0032 0031 65E5;0032 0031 65E5; # (㏴; ㏴; ㏴; 21日; 21日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE +33F5;33F5;33F5;0032 0032 65E5;0032 0032 65E5; # (㏵; ㏵; ㏵; 22日; 22日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO +33F6;33F6;33F6;0032 0033 65E5;0032 0033 65E5; # (㏶; ㏶; ㏶; 23日; 23日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE +33F7;33F7;33F7;0032 0034 65E5;0032 0034 65E5; # (㏷; ㏷; ㏷; 24日; 24日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR +33F8;33F8;33F8;0032 0035 65E5;0032 0035 65E5; # (㏸; ㏸; ㏸; 25日; 25日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE +33F9;33F9;33F9;0032 0036 65E5;0032 0036 65E5; # (㏹; ㏹; ㏹; 26日; 26日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX +33FA;33FA;33FA;0032 0037 65E5;0032 0037 65E5; # (㏺; ㏺; ㏺; 27日; 27日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN +33FB;33FB;33FB;0032 0038 65E5;0032 0038 65E5; # (㏻; ㏻; ㏻; 28日; 28日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT +33FC;33FC;33FC;0032 0039 65E5;0032 0039 65E5; # (㏼; ㏼; ㏼; 29日; 29日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE +33FD;33FD;33FD;0033 0030 65E5;0033 0030 65E5; # (㏽; ㏽; ㏽; 30日; 30日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY +33FE;33FE;33FE;0033 0031 65E5;0033 0031 65E5; # (㏾; ㏾; ㏾; 31日; 31日; ) IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE +33FF;33FF;33FF;0067 0061 006C;0067 0061 006C; # (㏿; ㏿; ㏿; gal; gal; ) SQUARE GAL +A69C;A69C;A69C;044A;044A; # (ꚜ; ꚜ; ꚜ; ъ; ъ; ) MODIFIER LETTER CYRILLIC HARD SIGN +A69D;A69D;A69D;044C;044C; # (ꚝ; ꚝ; ꚝ; ь; ь; ) MODIFIER LETTER CYRILLIC SOFT SIGN +A770;A770;A770;A76F;A76F; # (ꝰ; ꝰ; ꝰ; ꝯ; ꝯ; ) MODIFIER LETTER US +A7F2;A7F2;A7F2;0043;0043; # (ꟲ; ꟲ; ꟲ; C; C; ) MODIFIER LETTER CAPITAL C +A7F3;A7F3;A7F3;0046;0046; # (ꟳ; ꟳ; ꟳ; F; F; ) MODIFIER LETTER CAPITAL F +A7F4;A7F4;A7F4;0051;0051; # (ꟴ; ꟴ; ꟴ; Q; Q; ) MODIFIER LETTER CAPITAL Q +A7F8;A7F8;A7F8;0126;0126; # (ꟸ; ꟸ; ꟸ; Ħ; Ħ; ) MODIFIER LETTER CAPITAL H WITH STROKE +A7F9;A7F9;A7F9;0153;0153; # (ꟹ; ꟹ; ꟹ; œ; œ; ) MODIFIER LETTER SMALL LIGATURE OE +AB5C;AB5C;AB5C;A727;A727; # (ꭜ; ꭜ; ꭜ; ꜧ; ꜧ; ) MODIFIER LETTER SMALL HENG +AB5D;AB5D;AB5D;AB37;AB37; # (ꭝ; ꭝ; ꭝ; ꬷ; ꬷ; ) MODIFIER LETTER SMALL L WITH INVERTED LAZY S +AB5E;AB5E;AB5E;026B;026B; # (ꭞ; ꭞ; ꭞ; ɫ; ɫ; ) MODIFIER LETTER SMALL L WITH MIDDLE TILDE +AB5F;AB5F;AB5F;AB52;AB52; # (ꭟ; ꭟ; ꭟ; ꭒ; ꭒ; ) MODIFIER LETTER SMALL U WITH LEFT HOOK +AB69;AB69;AB69;028D;028D; # (ꭩ; ꭩ; ꭩ; ʍ; ʍ; ) MODIFIER LETTER SMALL TURNED W +AC00;AC00;1100 1161;AC00;1100 1161; # (가; 가; 가; 가; 가; ) HANGUL SYLLABLE GA +AC01;AC01;1100 1161 11A8;AC01;1100 1161 11A8; # (각; 각; 각; 각; 각; ) HANGUL SYLLABLE GAG +AC02;AC02;1100 1161 11A9;AC02;1100 1161 11A9; # (갂; 갂; 갂; 갂; 갂; ) HANGUL SYLLABLE GAGG +AC03;AC03;1100 1161 11AA;AC03;1100 1161 11AA; # (갃; 갃; 갃; 갃; 갃; ) HANGUL SYLLABLE GAGS +AC04;AC04;1100 1161 11AB;AC04;1100 1161 11AB; # (간; 간; 간; 간; 간; ) HANGUL SYLLABLE GAN +AC05;AC05;1100 1161 11AC;AC05;1100 1161 11AC; # (갅; 갅; 갅; 갅; 갅; ) HANGUL SYLLABLE GANJ +AC06;AC06;1100 1161 11AD;AC06;1100 1161 11AD; # (갆; 갆; 갆; 갆; 갆; ) HANGUL SYLLABLE GANH +AC07;AC07;1100 1161 11AE;AC07;1100 1161 11AE; # (갇; 갇; 갇; 갇; 갇; ) HANGUL SYLLABLE GAD +AC08;AC08;1100 1161 11AF;AC08;1100 1161 11AF; # (갈; 갈; 갈; 갈; 갈; ) HANGUL SYLLABLE GAL +AC09;AC09;1100 1161 11B0;AC09;1100 1161 11B0; # (갉; 갉; 갉; 갉; 갉; ) HANGUL SYLLABLE GALG +AC0A;AC0A;1100 1161 11B1;AC0A;1100 1161 11B1; # (갊; 갊; 갊; 갊; 갊; ) HANGUL SYLLABLE GALM +AC0B;AC0B;1100 1161 11B2;AC0B;1100 1161 11B2; # (갋; 갋; 갋; 갋; 갋; ) HANGUL SYLLABLE GALB +AC0C;AC0C;1100 1161 11B3;AC0C;1100 1161 11B3; # (갌; 갌; 갌; 갌; 갌; ) HANGUL SYLLABLE GALS +AC0D;AC0D;1100 1161 11B4;AC0D;1100 1161 11B4; # (갍; 갍; 갍; 갍; 갍; ) HANGUL SYLLABLE GALT +AC0E;AC0E;1100 1161 11B5;AC0E;1100 1161 11B5; # (갎; 갎; 갎; 갎; 갎; ) HANGUL SYLLABLE GALP +AC0F;AC0F;1100 1161 11B6;AC0F;1100 1161 11B6; # (갏; 갏; 갏; 갏; 갏; ) HANGUL SYLLABLE GALH +AC10;AC10;1100 1161 11B7;AC10;1100 1161 11B7; # (감; 감; 감; 감; 감; ) HANGUL SYLLABLE GAM +AC11;AC11;1100 1161 11B8;AC11;1100 1161 11B8; # (갑; 갑; 갑; 갑; 갑; ) HANGUL SYLLABLE GAB +AC12;AC12;1100 1161 11B9;AC12;1100 1161 11B9; # (값; 값; 값; 값; 값; ) HANGUL SYLLABLE GABS +AC13;AC13;1100 1161 11BA;AC13;1100 1161 11BA; # (갓; 갓; 갓; 갓; 갓; ) HANGUL SYLLABLE GAS +AC14;AC14;1100 1161 11BB;AC14;1100 1161 11BB; # (갔; 갔; 갔; 갔; 갔; ) HANGUL SYLLABLE GASS +AC15;AC15;1100 1161 11BC;AC15;1100 1161 11BC; # (강; 강; 강; 강; 강; ) HANGUL SYLLABLE GANG +AC16;AC16;1100 1161 11BD;AC16;1100 1161 11BD; # (갖; 갖; 갖; 갖; 갖; ) HANGUL SYLLABLE GAJ +AC17;AC17;1100 1161 11BE;AC17;1100 1161 11BE; # (갗; 갗; 갗; 갗; 갗; ) HANGUL SYLLABLE GAC +AC18;AC18;1100 1161 11BF;AC18;1100 1161 11BF; # (갘; 갘; 갘; 갘; 갘; ) HANGUL SYLLABLE GAK +AC19;AC19;1100 1161 11C0;AC19;1100 1161 11C0; # (같; 같; 같; 같; 같; ) HANGUL SYLLABLE GAT +AC1A;AC1A;1100 1161 11C1;AC1A;1100 1161 11C1; # (갚; 갚; 갚; 갚; 갚; ) HANGUL SYLLABLE GAP +AC1B;AC1B;1100 1161 11C2;AC1B;1100 1161 11C2; # (갛; 갛; 갛; 갛; 갛; ) HANGUL SYLLABLE GAH +AC1C;AC1C;1100 1162;AC1C;1100 1162; # (개; 개; 개; 개; 개; ) HANGUL SYLLABLE GAE +AC1D;AC1D;1100 1162 11A8;AC1D;1100 1162 11A8; # (객; 객; 객; 객; 객; ) HANGUL SYLLABLE GAEG +AC1E;AC1E;1100 1162 11A9;AC1E;1100 1162 11A9; # (갞; 갞; 갞; 갞; 갞; ) HANGUL SYLLABLE GAEGG +AC1F;AC1F;1100 1162 11AA;AC1F;1100 1162 11AA; # (갟; 갟; 갟; 갟; 갟; ) HANGUL SYLLABLE GAEGS +AC20;AC20;1100 1162 11AB;AC20;1100 1162 11AB; # (갠; 갠; 갠; 갠; 갠; ) HANGUL SYLLABLE GAEN +AC21;AC21;1100 1162 11AC;AC21;1100 1162 11AC; # (갡; 갡; 갡; 갡; 갡; ) HANGUL SYLLABLE GAENJ +AC22;AC22;1100 1162 11AD;AC22;1100 1162 11AD; # (갢; 갢; 갢; 갢; 갢; ) HANGUL SYLLABLE GAENH +AC23;AC23;1100 1162 11AE;AC23;1100 1162 11AE; # (갣; 갣; 갣; 갣; 갣; ) HANGUL SYLLABLE GAED +AC24;AC24;1100 1162 11AF;AC24;1100 1162 11AF; # (갤; 갤; 갤; 갤; 갤; ) HANGUL SYLLABLE GAEL +AC25;AC25;1100 1162 11B0;AC25;1100 1162 11B0; # (갥; 갥; 갥; 갥; 갥; ) HANGUL SYLLABLE GAELG +AC26;AC26;1100 1162 11B1;AC26;1100 1162 11B1; # (갦; 갦; 갦; 갦; 갦; ) HANGUL SYLLABLE GAELM +AC27;AC27;1100 1162 11B2;AC27;1100 1162 11B2; # (갧; 갧; 갧; 갧; 갧; ) HANGUL SYLLABLE GAELB +AC28;AC28;1100 1162 11B3;AC28;1100 1162 11B3; # (갨; 갨; 갨; 갨; 갨; ) HANGUL SYLLABLE GAELS +AC29;AC29;1100 1162 11B4;AC29;1100 1162 11B4; # (갩; 갩; 갩; 갩; 갩; ) HANGUL SYLLABLE GAELT +AC2A;AC2A;1100 1162 11B5;AC2A;1100 1162 11B5; # (갪; 갪; 갪; 갪; 갪; ) HANGUL SYLLABLE GAELP +AC2B;AC2B;1100 1162 11B6;AC2B;1100 1162 11B6; # (갫; 갫; 갫; 갫; 갫; ) HANGUL SYLLABLE GAELH +AC2C;AC2C;1100 1162 11B7;AC2C;1100 1162 11B7; # (갬; 갬; 갬; 갬; 갬; ) HANGUL SYLLABLE GAEM +AC2D;AC2D;1100 1162 11B8;AC2D;1100 1162 11B8; # (갭; 갭; 갭; 갭; 갭; ) HANGUL SYLLABLE GAEB +AC2E;AC2E;1100 1162 11B9;AC2E;1100 1162 11B9; # (갮; 갮; 갮; 갮; 갮; ) HANGUL SYLLABLE GAEBS +AC2F;AC2F;1100 1162 11BA;AC2F;1100 1162 11BA; # (갯; 갯; 갯; 갯; 갯; ) HANGUL SYLLABLE GAES +AC30;AC30;1100 1162 11BB;AC30;1100 1162 11BB; # (갰; 갰; 갰; 갰; 갰; ) HANGUL SYLLABLE GAESS +AC31;AC31;1100 1162 11BC;AC31;1100 1162 11BC; # (갱; 갱; 갱; 갱; 갱; ) HANGUL SYLLABLE GAENG +AC32;AC32;1100 1162 11BD;AC32;1100 1162 11BD; # (갲; 갲; 갲; 갲; 갲; ) HANGUL SYLLABLE GAEJ +AC33;AC33;1100 1162 11BE;AC33;1100 1162 11BE; # (갳; 갳; 갳; 갳; 갳; ) HANGUL SYLLABLE GAEC +AC34;AC34;1100 1162 11BF;AC34;1100 1162 11BF; # (갴; 갴; 갴; 갴; 갴; ) HANGUL SYLLABLE GAEK +AC35;AC35;1100 1162 11C0;AC35;1100 1162 11C0; # (갵; 갵; 갵; 갵; 갵; ) HANGUL SYLLABLE GAET +AC36;AC36;1100 1162 11C1;AC36;1100 1162 11C1; # (갶; 갶; 갶; 갶; 갶; ) HANGUL SYLLABLE GAEP +AC37;AC37;1100 1162 11C2;AC37;1100 1162 11C2; # (갷; 갷; 갷; 갷; 갷; ) HANGUL SYLLABLE GAEH +AC38;AC38;1100 1163;AC38;1100 1163; # (갸; 갸; 갸; 갸; 갸; ) HANGUL SYLLABLE GYA +AC39;AC39;1100 1163 11A8;AC39;1100 1163 11A8; # (갹; 갹; 갹; 갹; 갹; ) HANGUL SYLLABLE GYAG +AC3A;AC3A;1100 1163 11A9;AC3A;1100 1163 11A9; # (갺; 갺; 갺; 갺; 갺; ) HANGUL SYLLABLE GYAGG +AC3B;AC3B;1100 1163 11AA;AC3B;1100 1163 11AA; # (갻; 갻; 갻; 갻; 갻; ) HANGUL SYLLABLE GYAGS +AC3C;AC3C;1100 1163 11AB;AC3C;1100 1163 11AB; # (갼; 갼; 갼; 갼; 갼; ) HANGUL SYLLABLE GYAN +AC3D;AC3D;1100 1163 11AC;AC3D;1100 1163 11AC; # (갽; 갽; 갽; 갽; 갽; ) HANGUL SYLLABLE GYANJ +AC3E;AC3E;1100 1163 11AD;AC3E;1100 1163 11AD; # (갾; 갾; 갾; 갾; 갾; ) HANGUL SYLLABLE GYANH +AC3F;AC3F;1100 1163 11AE;AC3F;1100 1163 11AE; # (갿; 갿; 갿; 갿; 갿; ) HANGUL SYLLABLE GYAD +AC40;AC40;1100 1163 11AF;AC40;1100 1163 11AF; # (걀; 걀; 걀; 걀; 걀; ) HANGUL SYLLABLE GYAL +AC41;AC41;1100 1163 11B0;AC41;1100 1163 11B0; # (걁; 걁; 걁; 걁; 걁; ) HANGUL SYLLABLE GYALG +AC42;AC42;1100 1163 11B1;AC42;1100 1163 11B1; # (걂; 걂; 걂; 걂; 걂; ) HANGUL SYLLABLE GYALM +AC43;AC43;1100 1163 11B2;AC43;1100 1163 11B2; # (걃; 걃; 걃; 걃; 걃; ) HANGUL SYLLABLE GYALB +AC44;AC44;1100 1163 11B3;AC44;1100 1163 11B3; # (걄; 걄; 걄; 걄; 걄; ) HANGUL SYLLABLE GYALS +AC45;AC45;1100 1163 11B4;AC45;1100 1163 11B4; # (걅; 걅; 걅; 걅; 걅; ) HANGUL SYLLABLE GYALT +AC46;AC46;1100 1163 11B5;AC46;1100 1163 11B5; # (걆; 걆; 걆; 걆; 걆; ) HANGUL SYLLABLE GYALP +AC47;AC47;1100 1163 11B6;AC47;1100 1163 11B6; # (걇; 걇; 걇; 걇; 걇; ) HANGUL SYLLABLE GYALH +AC48;AC48;1100 1163 11B7;AC48;1100 1163 11B7; # (걈; 걈; 걈; 걈; 걈; ) HANGUL SYLLABLE GYAM +AC49;AC49;1100 1163 11B8;AC49;1100 1163 11B8; # (걉; 걉; 걉; 걉; 걉; ) HANGUL SYLLABLE GYAB +AC4A;AC4A;1100 1163 11B9;AC4A;1100 1163 11B9; # (걊; 걊; 걊; 걊; 걊; ) HANGUL SYLLABLE GYABS +AC4B;AC4B;1100 1163 11BA;AC4B;1100 1163 11BA; # (걋; 걋; 걋; 걋; 걋; ) HANGUL SYLLABLE GYAS +AC4C;AC4C;1100 1163 11BB;AC4C;1100 1163 11BB; # (걌; 걌; 걌; 걌; 걌; ) HANGUL SYLLABLE GYASS +AC4D;AC4D;1100 1163 11BC;AC4D;1100 1163 11BC; # (걍; 걍; 걍; 걍; 걍; ) HANGUL SYLLABLE GYANG +AC4E;AC4E;1100 1163 11BD;AC4E;1100 1163 11BD; # (걎; 걎; 걎; 걎; 걎; ) HANGUL SYLLABLE GYAJ +AC4F;AC4F;1100 1163 11BE;AC4F;1100 1163 11BE; # (걏; 걏; 걏; 걏; 걏; ) HANGUL SYLLABLE GYAC +AC50;AC50;1100 1163 11BF;AC50;1100 1163 11BF; # (걐; 걐; 걐; 걐; 걐; ) HANGUL SYLLABLE GYAK +AC51;AC51;1100 1163 11C0;AC51;1100 1163 11C0; # (걑; 걑; 걑; 걑; 걑; ) HANGUL SYLLABLE GYAT +AC52;AC52;1100 1163 11C1;AC52;1100 1163 11C1; # (걒; 걒; 걒; 걒; 걒; ) HANGUL SYLLABLE GYAP +AC53;AC53;1100 1163 11C2;AC53;1100 1163 11C2; # (걓; 걓; 걓; 걓; 걓; ) HANGUL SYLLABLE GYAH +AC54;AC54;1100 1164;AC54;1100 1164; # (걔; 걔; 걔; 걔; 걔; ) HANGUL SYLLABLE GYAE +AC55;AC55;1100 1164 11A8;AC55;1100 1164 11A8; # (걕; 걕; 걕; 걕; 걕; ) HANGUL SYLLABLE GYAEG +AC56;AC56;1100 1164 11A9;AC56;1100 1164 11A9; # (걖; 걖; 걖; 걖; 걖; ) HANGUL SYLLABLE GYAEGG +AC57;AC57;1100 1164 11AA;AC57;1100 1164 11AA; # (걗; 걗; 걗; 걗; 걗; ) HANGUL SYLLABLE GYAEGS +AC58;AC58;1100 1164 11AB;AC58;1100 1164 11AB; # (걘; 걘; 걘; 걘; 걘; ) HANGUL SYLLABLE GYAEN +AC59;AC59;1100 1164 11AC;AC59;1100 1164 11AC; # (걙; 걙; 걙; 걙; 걙; ) HANGUL SYLLABLE GYAENJ +AC5A;AC5A;1100 1164 11AD;AC5A;1100 1164 11AD; # (걚; 걚; 걚; 걚; 걚; ) HANGUL SYLLABLE GYAENH +AC5B;AC5B;1100 1164 11AE;AC5B;1100 1164 11AE; # (걛; 걛; 걛; 걛; 걛; ) HANGUL SYLLABLE GYAED +AC5C;AC5C;1100 1164 11AF;AC5C;1100 1164 11AF; # (걜; 걜; 걜; 걜; 걜; ) HANGUL SYLLABLE GYAEL +AC5D;AC5D;1100 1164 11B0;AC5D;1100 1164 11B0; # (걝; 걝; 걝; 걝; 걝; ) HANGUL SYLLABLE GYAELG +AC5E;AC5E;1100 1164 11B1;AC5E;1100 1164 11B1; # (걞; 걞; 걞; 걞; 걞; ) HANGUL SYLLABLE GYAELM +AC5F;AC5F;1100 1164 11B2;AC5F;1100 1164 11B2; # (걟; 걟; 걟; 걟; 걟; ) HANGUL SYLLABLE GYAELB +AC60;AC60;1100 1164 11B3;AC60;1100 1164 11B3; # (걠; 걠; 걠; 걠; 걠; ) HANGUL SYLLABLE GYAELS +AC61;AC61;1100 1164 11B4;AC61;1100 1164 11B4; # (걡; 걡; 걡; 걡; 걡; ) HANGUL SYLLABLE GYAELT +AC62;AC62;1100 1164 11B5;AC62;1100 1164 11B5; # (걢; 걢; 걢; 걢; 걢; ) HANGUL SYLLABLE GYAELP +AC63;AC63;1100 1164 11B6;AC63;1100 1164 11B6; # (걣; 걣; 걣; 걣; 걣; ) HANGUL SYLLABLE GYAELH +AC64;AC64;1100 1164 11B7;AC64;1100 1164 11B7; # (걤; 걤; 걤; 걤; 걤; ) HANGUL SYLLABLE GYAEM +AC65;AC65;1100 1164 11B8;AC65;1100 1164 11B8; # (걥; 걥; 걥; 걥; 걥; ) HANGUL SYLLABLE GYAEB +AC66;AC66;1100 1164 11B9;AC66;1100 1164 11B9; # (걦; 걦; 걦; 걦; 걦; ) HANGUL SYLLABLE GYAEBS +AC67;AC67;1100 1164 11BA;AC67;1100 1164 11BA; # (걧; 걧; 걧; 걧; 걧; ) HANGUL SYLLABLE GYAES +AC68;AC68;1100 1164 11BB;AC68;1100 1164 11BB; # (걨; 걨; 걨; 걨; 걨; ) HANGUL SYLLABLE GYAESS +AC69;AC69;1100 1164 11BC;AC69;1100 1164 11BC; # (걩; 걩; 걩; 걩; 걩; ) HANGUL SYLLABLE GYAENG +AC6A;AC6A;1100 1164 11BD;AC6A;1100 1164 11BD; # (걪; 걪; 걪; 걪; 걪; ) HANGUL SYLLABLE GYAEJ +AC6B;AC6B;1100 1164 11BE;AC6B;1100 1164 11BE; # (걫; 걫; 걫; 걫; 걫; ) HANGUL SYLLABLE GYAEC +AC6C;AC6C;1100 1164 11BF;AC6C;1100 1164 11BF; # (걬; 걬; 걬; 걬; 걬; ) HANGUL SYLLABLE GYAEK +AC6D;AC6D;1100 1164 11C0;AC6D;1100 1164 11C0; # (걭; 걭; 걭; 걭; 걭; ) HANGUL SYLLABLE GYAET +AC6E;AC6E;1100 1164 11C1;AC6E;1100 1164 11C1; # (걮; 걮; 걮; 걮; 걮; ) HANGUL SYLLABLE GYAEP +AC6F;AC6F;1100 1164 11C2;AC6F;1100 1164 11C2; # (걯; 걯; 걯; 걯; 걯; ) HANGUL SYLLABLE GYAEH +AC70;AC70;1100 1165;AC70;1100 1165; # (거; 거; 거; 거; 거; ) HANGUL SYLLABLE GEO +AC71;AC71;1100 1165 11A8;AC71;1100 1165 11A8; # (걱; 걱; 걱; 걱; 걱; ) HANGUL SYLLABLE GEOG +AC72;AC72;1100 1165 11A9;AC72;1100 1165 11A9; # (걲; 걲; 걲; 걲; 걲; ) HANGUL SYLLABLE GEOGG +AC73;AC73;1100 1165 11AA;AC73;1100 1165 11AA; # (걳; 걳; 걳; 걳; 걳; ) HANGUL SYLLABLE GEOGS +AC74;AC74;1100 1165 11AB;AC74;1100 1165 11AB; # (건; 건; 건; 건; 건; ) HANGUL SYLLABLE GEON +AC75;AC75;1100 1165 11AC;AC75;1100 1165 11AC; # (걵; 걵; 걵; 걵; 걵; ) HANGUL SYLLABLE GEONJ +AC76;AC76;1100 1165 11AD;AC76;1100 1165 11AD; # (걶; 걶; 걶; 걶; 걶; ) HANGUL SYLLABLE GEONH +AC77;AC77;1100 1165 11AE;AC77;1100 1165 11AE; # (걷; 걷; 걷; 걷; 걷; ) HANGUL SYLLABLE GEOD +AC78;AC78;1100 1165 11AF;AC78;1100 1165 11AF; # (걸; 걸; 걸; 걸; 걸; ) HANGUL SYLLABLE GEOL +AC79;AC79;1100 1165 11B0;AC79;1100 1165 11B0; # (걹; 걹; 걹; 걹; 걹; ) HANGUL SYLLABLE GEOLG +AC7A;AC7A;1100 1165 11B1;AC7A;1100 1165 11B1; # (걺; 걺; 걺; 걺; 걺; ) HANGUL SYLLABLE GEOLM +AC7B;AC7B;1100 1165 11B2;AC7B;1100 1165 11B2; # (걻; 걻; 걻; 걻; 걻; ) HANGUL SYLLABLE GEOLB +AC7C;AC7C;1100 1165 11B3;AC7C;1100 1165 11B3; # (걼; 걼; 걼; 걼; 걼; ) HANGUL SYLLABLE GEOLS +AC7D;AC7D;1100 1165 11B4;AC7D;1100 1165 11B4; # (걽; 걽; 걽; 걽; 걽; ) HANGUL SYLLABLE GEOLT +AC7E;AC7E;1100 1165 11B5;AC7E;1100 1165 11B5; # (걾; 걾; 걾; 걾; 걾; ) HANGUL SYLLABLE GEOLP +AC7F;AC7F;1100 1165 11B6;AC7F;1100 1165 11B6; # (걿; 걿; 걿; 걿; 걿; ) HANGUL SYLLABLE GEOLH +AC80;AC80;1100 1165 11B7;AC80;1100 1165 11B7; # (검; 검; 검; 검; 검; ) HANGUL SYLLABLE GEOM +AC81;AC81;1100 1165 11B8;AC81;1100 1165 11B8; # (겁; 겁; 겁; 겁; 겁; ) HANGUL SYLLABLE GEOB +AC82;AC82;1100 1165 11B9;AC82;1100 1165 11B9; # (겂; 겂; 겂; 겂; 겂; ) HANGUL SYLLABLE GEOBS +AC83;AC83;1100 1165 11BA;AC83;1100 1165 11BA; # (것; 것; 것; 것; 것; ) HANGUL SYLLABLE GEOS +AC84;AC84;1100 1165 11BB;AC84;1100 1165 11BB; # (겄; 겄; 겄; 겄; 겄; ) HANGUL SYLLABLE GEOSS +AC85;AC85;1100 1165 11BC;AC85;1100 1165 11BC; # (겅; 겅; 겅; 겅; 겅; ) HANGUL SYLLABLE GEONG +AC86;AC86;1100 1165 11BD;AC86;1100 1165 11BD; # (겆; 겆; 겆; 겆; 겆; ) HANGUL SYLLABLE GEOJ +AC87;AC87;1100 1165 11BE;AC87;1100 1165 11BE; # (겇; 겇; 겇; 겇; 겇; ) HANGUL SYLLABLE GEOC +AC88;AC88;1100 1165 11BF;AC88;1100 1165 11BF; # (겈; 겈; 겈; 겈; 겈; ) HANGUL SYLLABLE GEOK +AC89;AC89;1100 1165 11C0;AC89;1100 1165 11C0; # (겉; 겉; 겉; 겉; 겉; ) HANGUL SYLLABLE GEOT +AC8A;AC8A;1100 1165 11C1;AC8A;1100 1165 11C1; # (겊; 겊; 겊; 겊; 겊; ) HANGUL SYLLABLE GEOP +AC8B;AC8B;1100 1165 11C2;AC8B;1100 1165 11C2; # (겋; 겋; 겋; 겋; 겋; ) HANGUL SYLLABLE GEOH +AC8C;AC8C;1100 1166;AC8C;1100 1166; # (게; 게; 게; 게; 게; ) HANGUL SYLLABLE GE +AC8D;AC8D;1100 1166 11A8;AC8D;1100 1166 11A8; # (겍; 겍; 겍; 겍; 겍; ) HANGUL SYLLABLE GEG +AC8E;AC8E;1100 1166 11A9;AC8E;1100 1166 11A9; # (겎; 겎; 겎; 겎; 겎; ) HANGUL SYLLABLE GEGG +AC8F;AC8F;1100 1166 11AA;AC8F;1100 1166 11AA; # (겏; 겏; 겏; 겏; 겏; ) HANGUL SYLLABLE GEGS +AC90;AC90;1100 1166 11AB;AC90;1100 1166 11AB; # (겐; 겐; 겐; 겐; 겐; ) HANGUL SYLLABLE GEN +AC91;AC91;1100 1166 11AC;AC91;1100 1166 11AC; # (겑; 겑; 겑; 겑; 겑; ) HANGUL SYLLABLE GENJ +AC92;AC92;1100 1166 11AD;AC92;1100 1166 11AD; # (겒; 겒; 겒; 겒; 겒; ) HANGUL SYLLABLE GENH +AC93;AC93;1100 1166 11AE;AC93;1100 1166 11AE; # (겓; 겓; 겓; 겓; 겓; ) HANGUL SYLLABLE GED +AC94;AC94;1100 1166 11AF;AC94;1100 1166 11AF; # (겔; 겔; 겔; 겔; 겔; ) HANGUL SYLLABLE GEL +AC95;AC95;1100 1166 11B0;AC95;1100 1166 11B0; # (겕; 겕; 겕; 겕; 겕; ) HANGUL SYLLABLE GELG +AC96;AC96;1100 1166 11B1;AC96;1100 1166 11B1; # (겖; 겖; 겖; 겖; 겖; ) HANGUL SYLLABLE GELM +AC97;AC97;1100 1166 11B2;AC97;1100 1166 11B2; # (겗; 겗; 겗; 겗; 겗; ) HANGUL SYLLABLE GELB +AC98;AC98;1100 1166 11B3;AC98;1100 1166 11B3; # (겘; 겘; 겘; 겘; 겘; ) HANGUL SYLLABLE GELS +AC99;AC99;1100 1166 11B4;AC99;1100 1166 11B4; # (겙; 겙; 겙; 겙; 겙; ) HANGUL SYLLABLE GELT +AC9A;AC9A;1100 1166 11B5;AC9A;1100 1166 11B5; # (겚; 겚; 겚; 겚; 겚; ) HANGUL SYLLABLE GELP +AC9B;AC9B;1100 1166 11B6;AC9B;1100 1166 11B6; # (겛; 겛; 겛; 겛; 겛; ) HANGUL SYLLABLE GELH +AC9C;AC9C;1100 1166 11B7;AC9C;1100 1166 11B7; # (겜; 겜; 겜; 겜; 겜; ) HANGUL SYLLABLE GEM +AC9D;AC9D;1100 1166 11B8;AC9D;1100 1166 11B8; # (겝; 겝; 겝; 겝; 겝; ) HANGUL SYLLABLE GEB +AC9E;AC9E;1100 1166 11B9;AC9E;1100 1166 11B9; # (겞; 겞; 겞; 겞; 겞; ) HANGUL SYLLABLE GEBS +AC9F;AC9F;1100 1166 11BA;AC9F;1100 1166 11BA; # (겟; 겟; 겟; 겟; 겟; ) HANGUL SYLLABLE GES +ACA0;ACA0;1100 1166 11BB;ACA0;1100 1166 11BB; # (겠; 겠; 겠; 겠; 겠; ) HANGUL SYLLABLE GESS +ACA1;ACA1;1100 1166 11BC;ACA1;1100 1166 11BC; # (겡; 겡; 겡; 겡; 겡; ) HANGUL SYLLABLE GENG +ACA2;ACA2;1100 1166 11BD;ACA2;1100 1166 11BD; # (겢; 겢; 겢; 겢; 겢; ) HANGUL SYLLABLE GEJ +ACA3;ACA3;1100 1166 11BE;ACA3;1100 1166 11BE; # (겣; 겣; 겣; 겣; 겣; ) HANGUL SYLLABLE GEC +ACA4;ACA4;1100 1166 11BF;ACA4;1100 1166 11BF; # (겤; 겤; 겤; 겤; 겤; ) HANGUL SYLLABLE GEK +ACA5;ACA5;1100 1166 11C0;ACA5;1100 1166 11C0; # (겥; 겥; 겥; 겥; 겥; ) HANGUL SYLLABLE GET +ACA6;ACA6;1100 1166 11C1;ACA6;1100 1166 11C1; # (겦; 겦; 겦; 겦; 겦; ) HANGUL SYLLABLE GEP +ACA7;ACA7;1100 1166 11C2;ACA7;1100 1166 11C2; # (겧; 겧; 겧; 겧; 겧; ) HANGUL SYLLABLE GEH +ACA8;ACA8;1100 1167;ACA8;1100 1167; # (겨; 겨; 겨; 겨; 겨; ) HANGUL SYLLABLE GYEO +ACA9;ACA9;1100 1167 11A8;ACA9;1100 1167 11A8; # (격; 격; 격; 격; 격; ) HANGUL SYLLABLE GYEOG +ACAA;ACAA;1100 1167 11A9;ACAA;1100 1167 11A9; # (겪; 겪; 겪; 겪; 겪; ) HANGUL SYLLABLE GYEOGG +ACAB;ACAB;1100 1167 11AA;ACAB;1100 1167 11AA; # (겫; 겫; 겫; 겫; 겫; ) HANGUL SYLLABLE GYEOGS +ACAC;ACAC;1100 1167 11AB;ACAC;1100 1167 11AB; # (견; 견; 견; 견; 견; ) HANGUL SYLLABLE GYEON +ACAD;ACAD;1100 1167 11AC;ACAD;1100 1167 11AC; # (겭; 겭; 겭; 겭; 겭; ) HANGUL SYLLABLE GYEONJ +ACAE;ACAE;1100 1167 11AD;ACAE;1100 1167 11AD; # (겮; 겮; 겮; 겮; 겮; ) HANGUL SYLLABLE GYEONH +ACAF;ACAF;1100 1167 11AE;ACAF;1100 1167 11AE; # (겯; 겯; 겯; 겯; 겯; ) HANGUL SYLLABLE GYEOD +ACB0;ACB0;1100 1167 11AF;ACB0;1100 1167 11AF; # (결; 결; 결; 결; 결; ) HANGUL SYLLABLE GYEOL +ACB1;ACB1;1100 1167 11B0;ACB1;1100 1167 11B0; # (겱; 겱; 겱; 겱; 겱; ) HANGUL SYLLABLE GYEOLG +ACB2;ACB2;1100 1167 11B1;ACB2;1100 1167 11B1; # (겲; 겲; 겲; 겲; 겲; ) HANGUL SYLLABLE GYEOLM +ACB3;ACB3;1100 1167 11B2;ACB3;1100 1167 11B2; # (겳; 겳; 겳; 겳; 겳; ) HANGUL SYLLABLE GYEOLB +ACB4;ACB4;1100 1167 11B3;ACB4;1100 1167 11B3; # (겴; 겴; 겴; 겴; 겴; ) HANGUL SYLLABLE GYEOLS +ACB5;ACB5;1100 1167 11B4;ACB5;1100 1167 11B4; # (겵; 겵; 겵; 겵; 겵; ) HANGUL SYLLABLE GYEOLT +ACB6;ACB6;1100 1167 11B5;ACB6;1100 1167 11B5; # (겶; 겶; 겶; 겶; 겶; ) HANGUL SYLLABLE GYEOLP +ACB7;ACB7;1100 1167 11B6;ACB7;1100 1167 11B6; # (겷; 겷; 겷; 겷; 겷; ) HANGUL SYLLABLE GYEOLH +ACB8;ACB8;1100 1167 11B7;ACB8;1100 1167 11B7; # (겸; 겸; 겸; 겸; 겸; ) HANGUL SYLLABLE GYEOM +ACB9;ACB9;1100 1167 11B8;ACB9;1100 1167 11B8; # (겹; 겹; 겹; 겹; 겹; ) HANGUL SYLLABLE GYEOB +ACBA;ACBA;1100 1167 11B9;ACBA;1100 1167 11B9; # (겺; 겺; 겺; 겺; 겺; ) HANGUL SYLLABLE GYEOBS +ACBB;ACBB;1100 1167 11BA;ACBB;1100 1167 11BA; # (겻; 겻; 겻; 겻; 겻; ) HANGUL SYLLABLE GYEOS +ACBC;ACBC;1100 1167 11BB;ACBC;1100 1167 11BB; # (겼; 겼; 겼; 겼; 겼; ) HANGUL SYLLABLE GYEOSS +ACBD;ACBD;1100 1167 11BC;ACBD;1100 1167 11BC; # (경; 경; 경; 경; 경; ) HANGUL SYLLABLE GYEONG +ACBE;ACBE;1100 1167 11BD;ACBE;1100 1167 11BD; # (겾; 겾; 겾; 겾; 겾; ) HANGUL SYLLABLE GYEOJ +ACBF;ACBF;1100 1167 11BE;ACBF;1100 1167 11BE; # (겿; 겿; 겿; 겿; 겿; ) HANGUL SYLLABLE GYEOC +ACC0;ACC0;1100 1167 11BF;ACC0;1100 1167 11BF; # (곀; 곀; 곀; 곀; 곀; ) HANGUL SYLLABLE GYEOK +ACC1;ACC1;1100 1167 11C0;ACC1;1100 1167 11C0; # (곁; 곁; 곁; 곁; 곁; ) HANGUL SYLLABLE GYEOT +ACC2;ACC2;1100 1167 11C1;ACC2;1100 1167 11C1; # (곂; 곂; 곂; 곂; 곂; ) HANGUL SYLLABLE GYEOP +ACC3;ACC3;1100 1167 11C2;ACC3;1100 1167 11C2; # (곃; 곃; 곃; 곃; 곃; ) HANGUL SYLLABLE GYEOH +ACC4;ACC4;1100 1168;ACC4;1100 1168; # (계; 계; 계; 계; 계; ) HANGUL SYLLABLE GYE +ACC5;ACC5;1100 1168 11A8;ACC5;1100 1168 11A8; # (곅; 곅; 곅; 곅; 곅; ) HANGUL SYLLABLE GYEG +ACC6;ACC6;1100 1168 11A9;ACC6;1100 1168 11A9; # (곆; 곆; 곆; 곆; 곆; ) HANGUL SYLLABLE GYEGG +ACC7;ACC7;1100 1168 11AA;ACC7;1100 1168 11AA; # (곇; 곇; 곇; 곇; 곇; ) HANGUL SYLLABLE GYEGS +ACC8;ACC8;1100 1168 11AB;ACC8;1100 1168 11AB; # (곈; 곈; 곈; 곈; 곈; ) HANGUL SYLLABLE GYEN +ACC9;ACC9;1100 1168 11AC;ACC9;1100 1168 11AC; # (곉; 곉; 곉; 곉; 곉; ) HANGUL SYLLABLE GYENJ +ACCA;ACCA;1100 1168 11AD;ACCA;1100 1168 11AD; # (곊; 곊; 곊; 곊; 곊; ) HANGUL SYLLABLE GYENH +ACCB;ACCB;1100 1168 11AE;ACCB;1100 1168 11AE; # (곋; 곋; 곋; 곋; 곋; ) HANGUL SYLLABLE GYED +ACCC;ACCC;1100 1168 11AF;ACCC;1100 1168 11AF; # (곌; 곌; 곌; 곌; 곌; ) HANGUL SYLLABLE GYEL +ACCD;ACCD;1100 1168 11B0;ACCD;1100 1168 11B0; # (곍; 곍; 곍; 곍; 곍; ) HANGUL SYLLABLE GYELG +ACCE;ACCE;1100 1168 11B1;ACCE;1100 1168 11B1; # (곎; 곎; 곎; 곎; 곎; ) HANGUL SYLLABLE GYELM +ACCF;ACCF;1100 1168 11B2;ACCF;1100 1168 11B2; # (곏; 곏; 곏; 곏; 곏; ) HANGUL SYLLABLE GYELB +ACD0;ACD0;1100 1168 11B3;ACD0;1100 1168 11B3; # (곐; 곐; 곐; 곐; 곐; ) HANGUL SYLLABLE GYELS +ACD1;ACD1;1100 1168 11B4;ACD1;1100 1168 11B4; # (곑; 곑; 곑; 곑; 곑; ) HANGUL SYLLABLE GYELT +ACD2;ACD2;1100 1168 11B5;ACD2;1100 1168 11B5; # (곒; 곒; 곒; 곒; 곒; ) HANGUL SYLLABLE GYELP +ACD3;ACD3;1100 1168 11B6;ACD3;1100 1168 11B6; # (곓; 곓; 곓; 곓; 곓; ) HANGUL SYLLABLE GYELH +ACD4;ACD4;1100 1168 11B7;ACD4;1100 1168 11B7; # (곔; 곔; 곔; 곔; 곔; ) HANGUL SYLLABLE GYEM +ACD5;ACD5;1100 1168 11B8;ACD5;1100 1168 11B8; # (곕; 곕; 곕; 곕; 곕; ) HANGUL SYLLABLE GYEB +ACD6;ACD6;1100 1168 11B9;ACD6;1100 1168 11B9; # (곖; 곖; 곖; 곖; 곖; ) HANGUL SYLLABLE GYEBS +ACD7;ACD7;1100 1168 11BA;ACD7;1100 1168 11BA; # (곗; 곗; 곗; 곗; 곗; ) HANGUL SYLLABLE GYES +ACD8;ACD8;1100 1168 11BB;ACD8;1100 1168 11BB; # (곘; 곘; 곘; 곘; 곘; ) HANGUL SYLLABLE GYESS +ACD9;ACD9;1100 1168 11BC;ACD9;1100 1168 11BC; # (곙; 곙; 곙; 곙; 곙; ) HANGUL SYLLABLE GYENG +ACDA;ACDA;1100 1168 11BD;ACDA;1100 1168 11BD; # (곚; 곚; 곚; 곚; 곚; ) HANGUL SYLLABLE GYEJ +ACDB;ACDB;1100 1168 11BE;ACDB;1100 1168 11BE; # (곛; 곛; 곛; 곛; 곛; ) HANGUL SYLLABLE GYEC +ACDC;ACDC;1100 1168 11BF;ACDC;1100 1168 11BF; # (곜; 곜; 곜; 곜; 곜; ) HANGUL SYLLABLE GYEK +ACDD;ACDD;1100 1168 11C0;ACDD;1100 1168 11C0; # (곝; 곝; 곝; 곝; 곝; ) HANGUL SYLLABLE GYET +ACDE;ACDE;1100 1168 11C1;ACDE;1100 1168 11C1; # (곞; 곞; 곞; 곞; 곞; ) HANGUL SYLLABLE GYEP +ACDF;ACDF;1100 1168 11C2;ACDF;1100 1168 11C2; # (곟; 곟; 곟; 곟; 곟; ) HANGUL SYLLABLE GYEH +ACE0;ACE0;1100 1169;ACE0;1100 1169; # (고; 고; 고; 고; 고; ) HANGUL SYLLABLE GO +ACE1;ACE1;1100 1169 11A8;ACE1;1100 1169 11A8; # (곡; 곡; 곡; 곡; 곡; ) HANGUL SYLLABLE GOG +ACE2;ACE2;1100 1169 11A9;ACE2;1100 1169 11A9; # (곢; 곢; 곢; 곢; 곢; ) HANGUL SYLLABLE GOGG +ACE3;ACE3;1100 1169 11AA;ACE3;1100 1169 11AA; # (곣; 곣; 곣; 곣; 곣; ) HANGUL SYLLABLE GOGS +ACE4;ACE4;1100 1169 11AB;ACE4;1100 1169 11AB; # (곤; 곤; 곤; 곤; 곤; ) HANGUL SYLLABLE GON +ACE5;ACE5;1100 1169 11AC;ACE5;1100 1169 11AC; # (곥; 곥; 곥; 곥; 곥; ) HANGUL SYLLABLE GONJ +ACE6;ACE6;1100 1169 11AD;ACE6;1100 1169 11AD; # (곦; 곦; 곦; 곦; 곦; ) HANGUL SYLLABLE GONH +ACE7;ACE7;1100 1169 11AE;ACE7;1100 1169 11AE; # (곧; 곧; 곧; 곧; 곧; ) HANGUL SYLLABLE GOD +ACE8;ACE8;1100 1169 11AF;ACE8;1100 1169 11AF; # (골; 골; 골; 골; 골; ) HANGUL SYLLABLE GOL +ACE9;ACE9;1100 1169 11B0;ACE9;1100 1169 11B0; # (곩; 곩; 곩; 곩; 곩; ) HANGUL SYLLABLE GOLG +ACEA;ACEA;1100 1169 11B1;ACEA;1100 1169 11B1; # (곪; 곪; 곪; 곪; 곪; ) HANGUL SYLLABLE GOLM +ACEB;ACEB;1100 1169 11B2;ACEB;1100 1169 11B2; # (곫; 곫; 곫; 곫; 곫; ) HANGUL SYLLABLE GOLB +ACEC;ACEC;1100 1169 11B3;ACEC;1100 1169 11B3; # (곬; 곬; 곬; 곬; 곬; ) HANGUL SYLLABLE GOLS +ACED;ACED;1100 1169 11B4;ACED;1100 1169 11B4; # (곭; 곭; 곭; 곭; 곭; ) HANGUL SYLLABLE GOLT +ACEE;ACEE;1100 1169 11B5;ACEE;1100 1169 11B5; # (곮; 곮; 곮; 곮; 곮; ) HANGUL SYLLABLE GOLP +ACEF;ACEF;1100 1169 11B6;ACEF;1100 1169 11B6; # (곯; 곯; 곯; 곯; 곯; ) HANGUL SYLLABLE GOLH +ACF0;ACF0;1100 1169 11B7;ACF0;1100 1169 11B7; # (곰; 곰; 곰; 곰; 곰; ) HANGUL SYLLABLE GOM +ACF1;ACF1;1100 1169 11B8;ACF1;1100 1169 11B8; # (곱; 곱; 곱; 곱; 곱; ) HANGUL SYLLABLE GOB +ACF2;ACF2;1100 1169 11B9;ACF2;1100 1169 11B9; # (곲; 곲; 곲; 곲; 곲; ) HANGUL SYLLABLE GOBS +ACF3;ACF3;1100 1169 11BA;ACF3;1100 1169 11BA; # (곳; 곳; 곳; 곳; 곳; ) HANGUL SYLLABLE GOS +ACF4;ACF4;1100 1169 11BB;ACF4;1100 1169 11BB; # (곴; 곴; 곴; 곴; 곴; ) HANGUL SYLLABLE GOSS +ACF5;ACF5;1100 1169 11BC;ACF5;1100 1169 11BC; # (공; 공; 공; 공; 공; ) HANGUL SYLLABLE GONG +ACF6;ACF6;1100 1169 11BD;ACF6;1100 1169 11BD; # (곶; 곶; 곶; 곶; 곶; ) HANGUL SYLLABLE GOJ +ACF7;ACF7;1100 1169 11BE;ACF7;1100 1169 11BE; # (곷; 곷; 곷; 곷; 곷; ) HANGUL SYLLABLE GOC +ACF8;ACF8;1100 1169 11BF;ACF8;1100 1169 11BF; # (곸; 곸; 곸; 곸; 곸; ) HANGUL SYLLABLE GOK +ACF9;ACF9;1100 1169 11C0;ACF9;1100 1169 11C0; # (곹; 곹; 곹; 곹; 곹; ) HANGUL SYLLABLE GOT +ACFA;ACFA;1100 1169 11C1;ACFA;1100 1169 11C1; # (곺; 곺; 곺; 곺; 곺; ) HANGUL SYLLABLE GOP +ACFB;ACFB;1100 1169 11C2;ACFB;1100 1169 11C2; # (곻; 곻; 곻; 곻; 곻; ) HANGUL SYLLABLE GOH +ACFC;ACFC;1100 116A;ACFC;1100 116A; # (과; 과; 과; 과; 과; ) HANGUL SYLLABLE GWA +ACFD;ACFD;1100 116A 11A8;ACFD;1100 116A 11A8; # (곽; 곽; 곽; 곽; 곽; ) HANGUL SYLLABLE GWAG +ACFE;ACFE;1100 116A 11A9;ACFE;1100 116A 11A9; # (곾; 곾; 곾; 곾; 곾; ) HANGUL SYLLABLE GWAGG +ACFF;ACFF;1100 116A 11AA;ACFF;1100 116A 11AA; # (곿; 곿; 곿; 곿; 곿; ) HANGUL SYLLABLE GWAGS +AD00;AD00;1100 116A 11AB;AD00;1100 116A 11AB; # (관; 관; 관; 관; 관; ) HANGUL SYLLABLE GWAN +AD01;AD01;1100 116A 11AC;AD01;1100 116A 11AC; # (괁; 괁; 괁; 괁; 괁; ) HANGUL SYLLABLE GWANJ +AD02;AD02;1100 116A 11AD;AD02;1100 116A 11AD; # (괂; 괂; 괂; 괂; 괂; ) HANGUL SYLLABLE GWANH +AD03;AD03;1100 116A 11AE;AD03;1100 116A 11AE; # (괃; 괃; 괃; 괃; 괃; ) HANGUL SYLLABLE GWAD +AD04;AD04;1100 116A 11AF;AD04;1100 116A 11AF; # (괄; 괄; 괄; 괄; 괄; ) HANGUL SYLLABLE GWAL +AD05;AD05;1100 116A 11B0;AD05;1100 116A 11B0; # (괅; 괅; 괅; 괅; 괅; ) HANGUL SYLLABLE GWALG +AD06;AD06;1100 116A 11B1;AD06;1100 116A 11B1; # (괆; 괆; 괆; 괆; 괆; ) HANGUL SYLLABLE GWALM +AD07;AD07;1100 116A 11B2;AD07;1100 116A 11B2; # (괇; 괇; 괇; 괇; 괇; ) HANGUL SYLLABLE GWALB +AD08;AD08;1100 116A 11B3;AD08;1100 116A 11B3; # (괈; 괈; 괈; 괈; 괈; ) HANGUL SYLLABLE GWALS +AD09;AD09;1100 116A 11B4;AD09;1100 116A 11B4; # (괉; 괉; 괉; 괉; 괉; ) HANGUL SYLLABLE GWALT +AD0A;AD0A;1100 116A 11B5;AD0A;1100 116A 11B5; # (괊; 괊; 괊; 괊; 괊; ) HANGUL SYLLABLE GWALP +AD0B;AD0B;1100 116A 11B6;AD0B;1100 116A 11B6; # (괋; 괋; 괋; 괋; 괋; ) HANGUL SYLLABLE GWALH +AD0C;AD0C;1100 116A 11B7;AD0C;1100 116A 11B7; # (괌; 괌; 괌; 괌; 괌; ) HANGUL SYLLABLE GWAM +AD0D;AD0D;1100 116A 11B8;AD0D;1100 116A 11B8; # (괍; 괍; 괍; 괍; 괍; ) HANGUL SYLLABLE GWAB +AD0E;AD0E;1100 116A 11B9;AD0E;1100 116A 11B9; # (괎; 괎; 괎; 괎; 괎; ) HANGUL SYLLABLE GWABS +AD0F;AD0F;1100 116A 11BA;AD0F;1100 116A 11BA; # (괏; 괏; 괏; 괏; 괏; ) HANGUL SYLLABLE GWAS +AD10;AD10;1100 116A 11BB;AD10;1100 116A 11BB; # (괐; 괐; 괐; 괐; 괐; ) HANGUL SYLLABLE GWASS +AD11;AD11;1100 116A 11BC;AD11;1100 116A 11BC; # (광; 광; 광; 광; 광; ) HANGUL SYLLABLE GWANG +AD12;AD12;1100 116A 11BD;AD12;1100 116A 11BD; # (괒; 괒; 괒; 괒; 괒; ) HANGUL SYLLABLE GWAJ +AD13;AD13;1100 116A 11BE;AD13;1100 116A 11BE; # (괓; 괓; 괓; 괓; 괓; ) HANGUL SYLLABLE GWAC +AD14;AD14;1100 116A 11BF;AD14;1100 116A 11BF; # (괔; 괔; 괔; 괔; 괔; ) HANGUL SYLLABLE GWAK +AD15;AD15;1100 116A 11C0;AD15;1100 116A 11C0; # (괕; 괕; 괕; 괕; 괕; ) HANGUL SYLLABLE GWAT +AD16;AD16;1100 116A 11C1;AD16;1100 116A 11C1; # (괖; 괖; 괖; 괖; 괖; ) HANGUL SYLLABLE GWAP +AD17;AD17;1100 116A 11C2;AD17;1100 116A 11C2; # (괗; 괗; 괗; 괗; 괗; ) HANGUL SYLLABLE GWAH +AD18;AD18;1100 116B;AD18;1100 116B; # (괘; 괘; 괘; 괘; 괘; ) HANGUL SYLLABLE GWAE +AD19;AD19;1100 116B 11A8;AD19;1100 116B 11A8; # (괙; 괙; 괙; 괙; 괙; ) HANGUL SYLLABLE GWAEG +AD1A;AD1A;1100 116B 11A9;AD1A;1100 116B 11A9; # (괚; 괚; 괚; 괚; 괚; ) HANGUL SYLLABLE GWAEGG +AD1B;AD1B;1100 116B 11AA;AD1B;1100 116B 11AA; # (괛; 괛; 괛; 괛; 괛; ) HANGUL SYLLABLE GWAEGS +AD1C;AD1C;1100 116B 11AB;AD1C;1100 116B 11AB; # (괜; 괜; 괜; 괜; 괜; ) HANGUL SYLLABLE GWAEN +AD1D;AD1D;1100 116B 11AC;AD1D;1100 116B 11AC; # (괝; 괝; 괝; 괝; 괝; ) HANGUL SYLLABLE GWAENJ +AD1E;AD1E;1100 116B 11AD;AD1E;1100 116B 11AD; # (괞; 괞; 괞; 괞; 괞; ) HANGUL SYLLABLE GWAENH +AD1F;AD1F;1100 116B 11AE;AD1F;1100 116B 11AE; # (괟; 괟; 괟; 괟; 괟; ) HANGUL SYLLABLE GWAED +AD20;AD20;1100 116B 11AF;AD20;1100 116B 11AF; # (괠; 괠; 괠; 괠; 괠; ) HANGUL SYLLABLE GWAEL +AD21;AD21;1100 116B 11B0;AD21;1100 116B 11B0; # (괡; 괡; 괡; 괡; 괡; ) HANGUL SYLLABLE GWAELG +AD22;AD22;1100 116B 11B1;AD22;1100 116B 11B1; # (괢; 괢; 괢; 괢; 괢; ) HANGUL SYLLABLE GWAELM +AD23;AD23;1100 116B 11B2;AD23;1100 116B 11B2; # (괣; 괣; 괣; 괣; 괣; ) HANGUL SYLLABLE GWAELB +AD24;AD24;1100 116B 11B3;AD24;1100 116B 11B3; # (괤; 괤; 괤; 괤; 괤; ) HANGUL SYLLABLE GWAELS +AD25;AD25;1100 116B 11B4;AD25;1100 116B 11B4; # (괥; 괥; 괥; 괥; 괥; ) HANGUL SYLLABLE GWAELT +AD26;AD26;1100 116B 11B5;AD26;1100 116B 11B5; # (괦; 괦; 괦; 괦; 괦; ) HANGUL SYLLABLE GWAELP +AD27;AD27;1100 116B 11B6;AD27;1100 116B 11B6; # (괧; 괧; 괧; 괧; 괧; ) HANGUL SYLLABLE GWAELH +AD28;AD28;1100 116B 11B7;AD28;1100 116B 11B7; # (괨; 괨; 괨; 괨; 괨; ) HANGUL SYLLABLE GWAEM +AD29;AD29;1100 116B 11B8;AD29;1100 116B 11B8; # (괩; 괩; 괩; 괩; 괩; ) HANGUL SYLLABLE GWAEB +AD2A;AD2A;1100 116B 11B9;AD2A;1100 116B 11B9; # (괪; 괪; 괪; 괪; 괪; ) HANGUL SYLLABLE GWAEBS +AD2B;AD2B;1100 116B 11BA;AD2B;1100 116B 11BA; # (괫; 괫; 괫; 괫; 괫; ) HANGUL SYLLABLE GWAES +AD2C;AD2C;1100 116B 11BB;AD2C;1100 116B 11BB; # (괬; 괬; 괬; 괬; 괬; ) HANGUL SYLLABLE GWAESS +AD2D;AD2D;1100 116B 11BC;AD2D;1100 116B 11BC; # (괭; 괭; 괭; 괭; 괭; ) HANGUL SYLLABLE GWAENG +AD2E;AD2E;1100 116B 11BD;AD2E;1100 116B 11BD; # (괮; 괮; 괮; 괮; 괮; ) HANGUL SYLLABLE GWAEJ +AD2F;AD2F;1100 116B 11BE;AD2F;1100 116B 11BE; # (괯; 괯; 괯; 괯; 괯; ) HANGUL SYLLABLE GWAEC +AD30;AD30;1100 116B 11BF;AD30;1100 116B 11BF; # (괰; 괰; 괰; 괰; 괰; ) HANGUL SYLLABLE GWAEK +AD31;AD31;1100 116B 11C0;AD31;1100 116B 11C0; # (괱; 괱; 괱; 괱; 괱; ) HANGUL SYLLABLE GWAET +AD32;AD32;1100 116B 11C1;AD32;1100 116B 11C1; # (괲; 괲; 괲; 괲; 괲; ) HANGUL SYLLABLE GWAEP +AD33;AD33;1100 116B 11C2;AD33;1100 116B 11C2; # (괳; 괳; 괳; 괳; 괳; ) HANGUL SYLLABLE GWAEH +AD34;AD34;1100 116C;AD34;1100 116C; # (괴; 괴; 괴; 괴; 괴; ) HANGUL SYLLABLE GOE +AD35;AD35;1100 116C 11A8;AD35;1100 116C 11A8; # (괵; 괵; 괵; 괵; 괵; ) HANGUL SYLLABLE GOEG +AD36;AD36;1100 116C 11A9;AD36;1100 116C 11A9; # (괶; 괶; 괶; 괶; 괶; ) HANGUL SYLLABLE GOEGG +AD37;AD37;1100 116C 11AA;AD37;1100 116C 11AA; # (괷; 괷; 괷; 괷; 괷; ) HANGUL SYLLABLE GOEGS +AD38;AD38;1100 116C 11AB;AD38;1100 116C 11AB; # (괸; 괸; 괸; 괸; 괸; ) HANGUL SYLLABLE GOEN +AD39;AD39;1100 116C 11AC;AD39;1100 116C 11AC; # (괹; 괹; 괹; 괹; 괹; ) HANGUL SYLLABLE GOENJ +AD3A;AD3A;1100 116C 11AD;AD3A;1100 116C 11AD; # (괺; 괺; 괺; 괺; 괺; ) HANGUL SYLLABLE GOENH +AD3B;AD3B;1100 116C 11AE;AD3B;1100 116C 11AE; # (괻; 괻; 괻; 괻; 괻; ) HANGUL SYLLABLE GOED +AD3C;AD3C;1100 116C 11AF;AD3C;1100 116C 11AF; # (괼; 괼; 괼; 괼; 괼; ) HANGUL SYLLABLE GOEL +AD3D;AD3D;1100 116C 11B0;AD3D;1100 116C 11B0; # (괽; 괽; 괽; 괽; 괽; ) HANGUL SYLLABLE GOELG +AD3E;AD3E;1100 116C 11B1;AD3E;1100 116C 11B1; # (괾; 괾; 괾; 괾; 괾; ) HANGUL SYLLABLE GOELM +AD3F;AD3F;1100 116C 11B2;AD3F;1100 116C 11B2; # (괿; 괿; 괿; 괿; 괿; ) HANGUL SYLLABLE GOELB +AD40;AD40;1100 116C 11B3;AD40;1100 116C 11B3; # (굀; 굀; 굀; 굀; 굀; ) HANGUL SYLLABLE GOELS +AD41;AD41;1100 116C 11B4;AD41;1100 116C 11B4; # (굁; 굁; 굁; 굁; 굁; ) HANGUL SYLLABLE GOELT +AD42;AD42;1100 116C 11B5;AD42;1100 116C 11B5; # (굂; 굂; 굂; 굂; 굂; ) HANGUL SYLLABLE GOELP +AD43;AD43;1100 116C 11B6;AD43;1100 116C 11B6; # (굃; 굃; 굃; 굃; 굃; ) HANGUL SYLLABLE GOELH +AD44;AD44;1100 116C 11B7;AD44;1100 116C 11B7; # (굄; 굄; 굄; 굄; 굄; ) HANGUL SYLLABLE GOEM +AD45;AD45;1100 116C 11B8;AD45;1100 116C 11B8; # (굅; 굅; 굅; 굅; 굅; ) HANGUL SYLLABLE GOEB +AD46;AD46;1100 116C 11B9;AD46;1100 116C 11B9; # (굆; 굆; 굆; 굆; 굆; ) HANGUL SYLLABLE GOEBS +AD47;AD47;1100 116C 11BA;AD47;1100 116C 11BA; # (굇; 굇; 굇; 굇; 굇; ) HANGUL SYLLABLE GOES +AD48;AD48;1100 116C 11BB;AD48;1100 116C 11BB; # (굈; 굈; 굈; 굈; 굈; ) HANGUL SYLLABLE GOESS +AD49;AD49;1100 116C 11BC;AD49;1100 116C 11BC; # (굉; 굉; 굉; 굉; 굉; ) HANGUL SYLLABLE GOENG +AD4A;AD4A;1100 116C 11BD;AD4A;1100 116C 11BD; # (굊; 굊; 굊; 굊; 굊; ) HANGUL SYLLABLE GOEJ +AD4B;AD4B;1100 116C 11BE;AD4B;1100 116C 11BE; # (굋; 굋; 굋; 굋; 굋; ) HANGUL SYLLABLE GOEC +AD4C;AD4C;1100 116C 11BF;AD4C;1100 116C 11BF; # (굌; 굌; 굌; 굌; 굌; ) HANGUL SYLLABLE GOEK +AD4D;AD4D;1100 116C 11C0;AD4D;1100 116C 11C0; # (굍; 굍; 굍; 굍; 굍; ) HANGUL SYLLABLE GOET +AD4E;AD4E;1100 116C 11C1;AD4E;1100 116C 11C1; # (굎; 굎; 굎; 굎; 굎; ) HANGUL SYLLABLE GOEP +AD4F;AD4F;1100 116C 11C2;AD4F;1100 116C 11C2; # (굏; 굏; 굏; 굏; 굏; ) HANGUL SYLLABLE GOEH +AD50;AD50;1100 116D;AD50;1100 116D; # (교; 교; 교; 교; 교; ) HANGUL SYLLABLE GYO +AD51;AD51;1100 116D 11A8;AD51;1100 116D 11A8; # (굑; 굑; 굑; 굑; 굑; ) HANGUL SYLLABLE GYOG +AD52;AD52;1100 116D 11A9;AD52;1100 116D 11A9; # (굒; 굒; 굒; 굒; 굒; ) HANGUL SYLLABLE GYOGG +AD53;AD53;1100 116D 11AA;AD53;1100 116D 11AA; # (굓; 굓; 굓; 굓; 굓; ) HANGUL SYLLABLE GYOGS +AD54;AD54;1100 116D 11AB;AD54;1100 116D 11AB; # (굔; 굔; 굔; 굔; 굔; ) HANGUL SYLLABLE GYON +AD55;AD55;1100 116D 11AC;AD55;1100 116D 11AC; # (굕; 굕; 굕; 굕; 굕; ) HANGUL SYLLABLE GYONJ +AD56;AD56;1100 116D 11AD;AD56;1100 116D 11AD; # (굖; 굖; 굖; 굖; 굖; ) HANGUL SYLLABLE GYONH +AD57;AD57;1100 116D 11AE;AD57;1100 116D 11AE; # (굗; 굗; 굗; 굗; 굗; ) HANGUL SYLLABLE GYOD +AD58;AD58;1100 116D 11AF;AD58;1100 116D 11AF; # (굘; 굘; 굘; 굘; 굘; ) HANGUL SYLLABLE GYOL +AD59;AD59;1100 116D 11B0;AD59;1100 116D 11B0; # (굙; 굙; 굙; 굙; 굙; ) HANGUL SYLLABLE GYOLG +AD5A;AD5A;1100 116D 11B1;AD5A;1100 116D 11B1; # (굚; 굚; 굚; 굚; 굚; ) HANGUL SYLLABLE GYOLM +AD5B;AD5B;1100 116D 11B2;AD5B;1100 116D 11B2; # (굛; 굛; 굛; 굛; 굛; ) HANGUL SYLLABLE GYOLB +AD5C;AD5C;1100 116D 11B3;AD5C;1100 116D 11B3; # (굜; 굜; 굜; 굜; 굜; ) HANGUL SYLLABLE GYOLS +AD5D;AD5D;1100 116D 11B4;AD5D;1100 116D 11B4; # (굝; 굝; 굝; 굝; 굝; ) HANGUL SYLLABLE GYOLT +AD5E;AD5E;1100 116D 11B5;AD5E;1100 116D 11B5; # (굞; 굞; 굞; 굞; 굞; ) HANGUL SYLLABLE GYOLP +AD5F;AD5F;1100 116D 11B6;AD5F;1100 116D 11B6; # (굟; 굟; 굟; 굟; 굟; ) HANGUL SYLLABLE GYOLH +AD60;AD60;1100 116D 11B7;AD60;1100 116D 11B7; # (굠; 굠; 굠; 굠; 굠; ) HANGUL SYLLABLE GYOM +AD61;AD61;1100 116D 11B8;AD61;1100 116D 11B8; # (굡; 굡; 굡; 굡; 굡; ) HANGUL SYLLABLE GYOB +AD62;AD62;1100 116D 11B9;AD62;1100 116D 11B9; # (굢; 굢; 굢; 굢; 굢; ) HANGUL SYLLABLE GYOBS +AD63;AD63;1100 116D 11BA;AD63;1100 116D 11BA; # (굣; 굣; 굣; 굣; 굣; ) HANGUL SYLLABLE GYOS +AD64;AD64;1100 116D 11BB;AD64;1100 116D 11BB; # (굤; 굤; 굤; 굤; 굤; ) HANGUL SYLLABLE GYOSS +AD65;AD65;1100 116D 11BC;AD65;1100 116D 11BC; # (굥; 굥; 굥; 굥; 굥; ) HANGUL SYLLABLE GYONG +AD66;AD66;1100 116D 11BD;AD66;1100 116D 11BD; # (굦; 굦; 굦; 굦; 굦; ) HANGUL SYLLABLE GYOJ +AD67;AD67;1100 116D 11BE;AD67;1100 116D 11BE; # (굧; 굧; 굧; 굧; 굧; ) HANGUL SYLLABLE GYOC +AD68;AD68;1100 116D 11BF;AD68;1100 116D 11BF; # (굨; 굨; 굨; 굨; 굨; ) HANGUL SYLLABLE GYOK +AD69;AD69;1100 116D 11C0;AD69;1100 116D 11C0; # (굩; 굩; 굩; 굩; 굩; ) HANGUL SYLLABLE GYOT +AD6A;AD6A;1100 116D 11C1;AD6A;1100 116D 11C1; # (굪; 굪; 굪; 굪; 굪; ) HANGUL SYLLABLE GYOP +AD6B;AD6B;1100 116D 11C2;AD6B;1100 116D 11C2; # (굫; 굫; 굫; 굫; 굫; ) HANGUL SYLLABLE GYOH +AD6C;AD6C;1100 116E;AD6C;1100 116E; # (구; 구; 구; 구; 구; ) HANGUL SYLLABLE GU +AD6D;AD6D;1100 116E 11A8;AD6D;1100 116E 11A8; # (국; 국; 국; 국; 국; ) HANGUL SYLLABLE GUG +AD6E;AD6E;1100 116E 11A9;AD6E;1100 116E 11A9; # (굮; 굮; 굮; 굮; 굮; ) HANGUL SYLLABLE GUGG +AD6F;AD6F;1100 116E 11AA;AD6F;1100 116E 11AA; # (굯; 굯; 굯; 굯; 굯; ) HANGUL SYLLABLE GUGS +AD70;AD70;1100 116E 11AB;AD70;1100 116E 11AB; # (군; 군; 군; 군; 군; ) HANGUL SYLLABLE GUN +AD71;AD71;1100 116E 11AC;AD71;1100 116E 11AC; # (굱; 굱; 굱; 굱; 굱; ) HANGUL SYLLABLE GUNJ +AD72;AD72;1100 116E 11AD;AD72;1100 116E 11AD; # (굲; 굲; 굲; 굲; 굲; ) HANGUL SYLLABLE GUNH +AD73;AD73;1100 116E 11AE;AD73;1100 116E 11AE; # (굳; 굳; 굳; 굳; 굳; ) HANGUL SYLLABLE GUD +AD74;AD74;1100 116E 11AF;AD74;1100 116E 11AF; # (굴; 굴; 굴; 굴; 굴; ) HANGUL SYLLABLE GUL +AD75;AD75;1100 116E 11B0;AD75;1100 116E 11B0; # (굵; 굵; 굵; 굵; 굵; ) HANGUL SYLLABLE GULG +AD76;AD76;1100 116E 11B1;AD76;1100 116E 11B1; # (굶; 굶; 굶; 굶; 굶; ) HANGUL SYLLABLE GULM +AD77;AD77;1100 116E 11B2;AD77;1100 116E 11B2; # (굷; 굷; 굷; 굷; 굷; ) HANGUL SYLLABLE GULB +AD78;AD78;1100 116E 11B3;AD78;1100 116E 11B3; # (굸; 굸; 굸; 굸; 굸; ) HANGUL SYLLABLE GULS +AD79;AD79;1100 116E 11B4;AD79;1100 116E 11B4; # (굹; 굹; 굹; 굹; 굹; ) HANGUL SYLLABLE GULT +AD7A;AD7A;1100 116E 11B5;AD7A;1100 116E 11B5; # (굺; 굺; 굺; 굺; 굺; ) HANGUL SYLLABLE GULP +AD7B;AD7B;1100 116E 11B6;AD7B;1100 116E 11B6; # (굻; 굻; 굻; 굻; 굻; ) HANGUL SYLLABLE GULH +AD7C;AD7C;1100 116E 11B7;AD7C;1100 116E 11B7; # (굼; 굼; 굼; 굼; 굼; ) HANGUL SYLLABLE GUM +AD7D;AD7D;1100 116E 11B8;AD7D;1100 116E 11B8; # (굽; 굽; 굽; 굽; 굽; ) HANGUL SYLLABLE GUB +AD7E;AD7E;1100 116E 11B9;AD7E;1100 116E 11B9; # (굾; 굾; 굾; 굾; 굾; ) HANGUL SYLLABLE GUBS +AD7F;AD7F;1100 116E 11BA;AD7F;1100 116E 11BA; # (굿; 굿; 굿; 굿; 굿; ) HANGUL SYLLABLE GUS +AD80;AD80;1100 116E 11BB;AD80;1100 116E 11BB; # (궀; 궀; 궀; 궀; 궀; ) HANGUL SYLLABLE GUSS +AD81;AD81;1100 116E 11BC;AD81;1100 116E 11BC; # (궁; 궁; 궁; 궁; 궁; ) HANGUL SYLLABLE GUNG +AD82;AD82;1100 116E 11BD;AD82;1100 116E 11BD; # (궂; 궂; 궂; 궂; 궂; ) HANGUL SYLLABLE GUJ +AD83;AD83;1100 116E 11BE;AD83;1100 116E 11BE; # (궃; 궃; 궃; 궃; 궃; ) HANGUL SYLLABLE GUC +AD84;AD84;1100 116E 11BF;AD84;1100 116E 11BF; # (궄; 궄; 궄; 궄; 궄; ) HANGUL SYLLABLE GUK +AD85;AD85;1100 116E 11C0;AD85;1100 116E 11C0; # (궅; 궅; 궅; 궅; 궅; ) HANGUL SYLLABLE GUT +AD86;AD86;1100 116E 11C1;AD86;1100 116E 11C1; # (궆; 궆; 궆; 궆; 궆; ) HANGUL SYLLABLE GUP +AD87;AD87;1100 116E 11C2;AD87;1100 116E 11C2; # (궇; 궇; 궇; 궇; 궇; ) HANGUL SYLLABLE GUH +AD88;AD88;1100 116F;AD88;1100 116F; # (궈; 궈; 궈; 궈; 궈; ) HANGUL SYLLABLE GWEO +AD89;AD89;1100 116F 11A8;AD89;1100 116F 11A8; # (궉; 궉; 궉; 궉; 궉; ) HANGUL SYLLABLE GWEOG +AD8A;AD8A;1100 116F 11A9;AD8A;1100 116F 11A9; # (궊; 궊; 궊; 궊; 궊; ) HANGUL SYLLABLE GWEOGG +AD8B;AD8B;1100 116F 11AA;AD8B;1100 116F 11AA; # (궋; 궋; 궋; 궋; 궋; ) HANGUL SYLLABLE GWEOGS +AD8C;AD8C;1100 116F 11AB;AD8C;1100 116F 11AB; # (권; 권; 권; 권; 권; ) HANGUL SYLLABLE GWEON +AD8D;AD8D;1100 116F 11AC;AD8D;1100 116F 11AC; # (궍; 궍; 궍; 궍; 궍; ) HANGUL SYLLABLE GWEONJ +AD8E;AD8E;1100 116F 11AD;AD8E;1100 116F 11AD; # (궎; 궎; 궎; 궎; 궎; ) HANGUL SYLLABLE GWEONH +AD8F;AD8F;1100 116F 11AE;AD8F;1100 116F 11AE; # (궏; 궏; 궏; 궏; 궏; ) HANGUL SYLLABLE GWEOD +AD90;AD90;1100 116F 11AF;AD90;1100 116F 11AF; # (궐; 궐; 궐; 궐; 궐; ) HANGUL SYLLABLE GWEOL +AD91;AD91;1100 116F 11B0;AD91;1100 116F 11B0; # (궑; 궑; 궑; 궑; 궑; ) HANGUL SYLLABLE GWEOLG +AD92;AD92;1100 116F 11B1;AD92;1100 116F 11B1; # (궒; 궒; 궒; 궒; 궒; ) HANGUL SYLLABLE GWEOLM +AD93;AD93;1100 116F 11B2;AD93;1100 116F 11B2; # (궓; 궓; 궓; 궓; 궓; ) HANGUL SYLLABLE GWEOLB +AD94;AD94;1100 116F 11B3;AD94;1100 116F 11B3; # (궔; 궔; 궔; 궔; 궔; ) HANGUL SYLLABLE GWEOLS +AD95;AD95;1100 116F 11B4;AD95;1100 116F 11B4; # (궕; 궕; 궕; 궕; 궕; ) HANGUL SYLLABLE GWEOLT +AD96;AD96;1100 116F 11B5;AD96;1100 116F 11B5; # (궖; 궖; 궖; 궖; 궖; ) HANGUL SYLLABLE GWEOLP +AD97;AD97;1100 116F 11B6;AD97;1100 116F 11B6; # (궗; 궗; 궗; 궗; 궗; ) HANGUL SYLLABLE GWEOLH +AD98;AD98;1100 116F 11B7;AD98;1100 116F 11B7; # (궘; 궘; 궘; 궘; 궘; ) HANGUL SYLLABLE GWEOM +AD99;AD99;1100 116F 11B8;AD99;1100 116F 11B8; # (궙; 궙; 궙; 궙; 궙; ) HANGUL SYLLABLE GWEOB +AD9A;AD9A;1100 116F 11B9;AD9A;1100 116F 11B9; # (궚; 궚; 궚; 궚; 궚; ) HANGUL SYLLABLE GWEOBS +AD9B;AD9B;1100 116F 11BA;AD9B;1100 116F 11BA; # (궛; 궛; 궛; 궛; 궛; ) HANGUL SYLLABLE GWEOS +AD9C;AD9C;1100 116F 11BB;AD9C;1100 116F 11BB; # (궜; 궜; 궜; 궜; 궜; ) HANGUL SYLLABLE GWEOSS +AD9D;AD9D;1100 116F 11BC;AD9D;1100 116F 11BC; # (궝; 궝; 궝; 궝; 궝; ) HANGUL SYLLABLE GWEONG +AD9E;AD9E;1100 116F 11BD;AD9E;1100 116F 11BD; # (궞; 궞; 궞; 궞; 궞; ) HANGUL SYLLABLE GWEOJ +AD9F;AD9F;1100 116F 11BE;AD9F;1100 116F 11BE; # (궟; 궟; 궟; 궟; 궟; ) HANGUL SYLLABLE GWEOC +ADA0;ADA0;1100 116F 11BF;ADA0;1100 116F 11BF; # (궠; 궠; 궠; 궠; 궠; ) HANGUL SYLLABLE GWEOK +ADA1;ADA1;1100 116F 11C0;ADA1;1100 116F 11C0; # (궡; 궡; 궡; 궡; 궡; ) HANGUL SYLLABLE GWEOT +ADA2;ADA2;1100 116F 11C1;ADA2;1100 116F 11C1; # (궢; 궢; 궢; 궢; 궢; ) HANGUL SYLLABLE GWEOP +ADA3;ADA3;1100 116F 11C2;ADA3;1100 116F 11C2; # (궣; 궣; 궣; 궣; 궣; ) HANGUL SYLLABLE GWEOH +ADA4;ADA4;1100 1170;ADA4;1100 1170; # (궤; 궤; 궤; 궤; 궤; ) HANGUL SYLLABLE GWE +ADA5;ADA5;1100 1170 11A8;ADA5;1100 1170 11A8; # (궥; 궥; 궥; 궥; 궥; ) HANGUL SYLLABLE GWEG +ADA6;ADA6;1100 1170 11A9;ADA6;1100 1170 11A9; # (궦; 궦; 궦; 궦; 궦; ) HANGUL SYLLABLE GWEGG +ADA7;ADA7;1100 1170 11AA;ADA7;1100 1170 11AA; # (궧; 궧; 궧; 궧; 궧; ) HANGUL SYLLABLE GWEGS +ADA8;ADA8;1100 1170 11AB;ADA8;1100 1170 11AB; # (궨; 궨; 궨; 궨; 궨; ) HANGUL SYLLABLE GWEN +ADA9;ADA9;1100 1170 11AC;ADA9;1100 1170 11AC; # (궩; 궩; 궩; 궩; 궩; ) HANGUL SYLLABLE GWENJ +ADAA;ADAA;1100 1170 11AD;ADAA;1100 1170 11AD; # (궪; 궪; 궪; 궪; 궪; ) HANGUL SYLLABLE GWENH +ADAB;ADAB;1100 1170 11AE;ADAB;1100 1170 11AE; # (궫; 궫; 궫; 궫; 궫; ) HANGUL SYLLABLE GWED +ADAC;ADAC;1100 1170 11AF;ADAC;1100 1170 11AF; # (궬; 궬; 궬; 궬; 궬; ) HANGUL SYLLABLE GWEL +ADAD;ADAD;1100 1170 11B0;ADAD;1100 1170 11B0; # (궭; 궭; 궭; 궭; 궭; ) HANGUL SYLLABLE GWELG +ADAE;ADAE;1100 1170 11B1;ADAE;1100 1170 11B1; # (궮; 궮; 궮; 궮; 궮; ) HANGUL SYLLABLE GWELM +ADAF;ADAF;1100 1170 11B2;ADAF;1100 1170 11B2; # (궯; 궯; 궯; 궯; 궯; ) HANGUL SYLLABLE GWELB +ADB0;ADB0;1100 1170 11B3;ADB0;1100 1170 11B3; # (궰; 궰; 궰; 궰; 궰; ) HANGUL SYLLABLE GWELS +ADB1;ADB1;1100 1170 11B4;ADB1;1100 1170 11B4; # (궱; 궱; 궱; 궱; 궱; ) HANGUL SYLLABLE GWELT +ADB2;ADB2;1100 1170 11B5;ADB2;1100 1170 11B5; # (궲; 궲; 궲; 궲; 궲; ) HANGUL SYLLABLE GWELP +ADB3;ADB3;1100 1170 11B6;ADB3;1100 1170 11B6; # (궳; 궳; 궳; 궳; 궳; ) HANGUL SYLLABLE GWELH +ADB4;ADB4;1100 1170 11B7;ADB4;1100 1170 11B7; # (궴; 궴; 궴; 궴; 궴; ) HANGUL SYLLABLE GWEM +ADB5;ADB5;1100 1170 11B8;ADB5;1100 1170 11B8; # (궵; 궵; 궵; 궵; 궵; ) HANGUL SYLLABLE GWEB +ADB6;ADB6;1100 1170 11B9;ADB6;1100 1170 11B9; # (궶; 궶; 궶; 궶; 궶; ) HANGUL SYLLABLE GWEBS +ADB7;ADB7;1100 1170 11BA;ADB7;1100 1170 11BA; # (궷; 궷; 궷; 궷; 궷; ) HANGUL SYLLABLE GWES +ADB8;ADB8;1100 1170 11BB;ADB8;1100 1170 11BB; # (궸; 궸; 궸; 궸; 궸; ) HANGUL SYLLABLE GWESS +ADB9;ADB9;1100 1170 11BC;ADB9;1100 1170 11BC; # (궹; 궹; 궹; 궹; 궹; ) HANGUL SYLLABLE GWENG +ADBA;ADBA;1100 1170 11BD;ADBA;1100 1170 11BD; # (궺; 궺; 궺; 궺; 궺; ) HANGUL SYLLABLE GWEJ +ADBB;ADBB;1100 1170 11BE;ADBB;1100 1170 11BE; # (궻; 궻; 궻; 궻; 궻; ) HANGUL SYLLABLE GWEC +ADBC;ADBC;1100 1170 11BF;ADBC;1100 1170 11BF; # (궼; 궼; 궼; 궼; 궼; ) HANGUL SYLLABLE GWEK +ADBD;ADBD;1100 1170 11C0;ADBD;1100 1170 11C0; # (궽; 궽; 궽; 궽; 궽; ) HANGUL SYLLABLE GWET +ADBE;ADBE;1100 1170 11C1;ADBE;1100 1170 11C1; # (궾; 궾; 궾; 궾; 궾; ) HANGUL SYLLABLE GWEP +ADBF;ADBF;1100 1170 11C2;ADBF;1100 1170 11C2; # (궿; 궿; 궿; 궿; 궿; ) HANGUL SYLLABLE GWEH +ADC0;ADC0;1100 1171;ADC0;1100 1171; # (귀; 귀; 귀; 귀; 귀; ) HANGUL SYLLABLE GWI +ADC1;ADC1;1100 1171 11A8;ADC1;1100 1171 11A8; # (귁; 귁; 귁; 귁; 귁; ) HANGUL SYLLABLE GWIG +ADC2;ADC2;1100 1171 11A9;ADC2;1100 1171 11A9; # (귂; 귂; 귂; 귂; 귂; ) HANGUL SYLLABLE GWIGG +ADC3;ADC3;1100 1171 11AA;ADC3;1100 1171 11AA; # (귃; 귃; 귃; 귃; 귃; ) HANGUL SYLLABLE GWIGS +ADC4;ADC4;1100 1171 11AB;ADC4;1100 1171 11AB; # (귄; 귄; 귄; 귄; 귄; ) HANGUL SYLLABLE GWIN +ADC5;ADC5;1100 1171 11AC;ADC5;1100 1171 11AC; # (귅; 귅; 귅; 귅; 귅; ) HANGUL SYLLABLE GWINJ +ADC6;ADC6;1100 1171 11AD;ADC6;1100 1171 11AD; # (귆; 귆; 귆; 귆; 귆; ) HANGUL SYLLABLE GWINH +ADC7;ADC7;1100 1171 11AE;ADC7;1100 1171 11AE; # (귇; 귇; 귇; 귇; 귇; ) HANGUL SYLLABLE GWID +ADC8;ADC8;1100 1171 11AF;ADC8;1100 1171 11AF; # (귈; 귈; 귈; 귈; 귈; ) HANGUL SYLLABLE GWIL +ADC9;ADC9;1100 1171 11B0;ADC9;1100 1171 11B0; # (귉; 귉; 귉; 귉; 귉; ) HANGUL SYLLABLE GWILG +ADCA;ADCA;1100 1171 11B1;ADCA;1100 1171 11B1; # (귊; 귊; 귊; 귊; 귊; ) HANGUL SYLLABLE GWILM +ADCB;ADCB;1100 1171 11B2;ADCB;1100 1171 11B2; # (귋; 귋; 귋; 귋; 귋; ) HANGUL SYLLABLE GWILB +ADCC;ADCC;1100 1171 11B3;ADCC;1100 1171 11B3; # (귌; 귌; 귌; 귌; 귌; ) HANGUL SYLLABLE GWILS +ADCD;ADCD;1100 1171 11B4;ADCD;1100 1171 11B4; # (귍; 귍; 귍; 귍; 귍; ) HANGUL SYLLABLE GWILT +ADCE;ADCE;1100 1171 11B5;ADCE;1100 1171 11B5; # (귎; 귎; 귎; 귎; 귎; ) HANGUL SYLLABLE GWILP +ADCF;ADCF;1100 1171 11B6;ADCF;1100 1171 11B6; # (귏; 귏; 귏; 귏; 귏; ) HANGUL SYLLABLE GWILH +ADD0;ADD0;1100 1171 11B7;ADD0;1100 1171 11B7; # (귐; 귐; 귐; 귐; 귐; ) HANGUL SYLLABLE GWIM +ADD1;ADD1;1100 1171 11B8;ADD1;1100 1171 11B8; # (귑; 귑; 귑; 귑; 귑; ) HANGUL SYLLABLE GWIB +ADD2;ADD2;1100 1171 11B9;ADD2;1100 1171 11B9; # (귒; 귒; 귒; 귒; 귒; ) HANGUL SYLLABLE GWIBS +ADD3;ADD3;1100 1171 11BA;ADD3;1100 1171 11BA; # (귓; 귓; 귓; 귓; 귓; ) HANGUL SYLLABLE GWIS +ADD4;ADD4;1100 1171 11BB;ADD4;1100 1171 11BB; # (귔; 귔; 귔; 귔; 귔; ) HANGUL SYLLABLE GWISS +ADD5;ADD5;1100 1171 11BC;ADD5;1100 1171 11BC; # (귕; 귕; 귕; 귕; 귕; ) HANGUL SYLLABLE GWING +ADD6;ADD6;1100 1171 11BD;ADD6;1100 1171 11BD; # (귖; 귖; 귖; 귖; 귖; ) HANGUL SYLLABLE GWIJ +ADD7;ADD7;1100 1171 11BE;ADD7;1100 1171 11BE; # (귗; 귗; 귗; 귗; 귗; ) HANGUL SYLLABLE GWIC +ADD8;ADD8;1100 1171 11BF;ADD8;1100 1171 11BF; # (귘; 귘; 귘; 귘; 귘; ) HANGUL SYLLABLE GWIK +ADD9;ADD9;1100 1171 11C0;ADD9;1100 1171 11C0; # (귙; 귙; 귙; 귙; 귙; ) HANGUL SYLLABLE GWIT +ADDA;ADDA;1100 1171 11C1;ADDA;1100 1171 11C1; # (귚; 귚; 귚; 귚; 귚; ) HANGUL SYLLABLE GWIP +ADDB;ADDB;1100 1171 11C2;ADDB;1100 1171 11C2; # (귛; 귛; 귛; 귛; 귛; ) HANGUL SYLLABLE GWIH +ADDC;ADDC;1100 1172;ADDC;1100 1172; # (규; 규; 규; 규; 규; ) HANGUL SYLLABLE GYU +ADDD;ADDD;1100 1172 11A8;ADDD;1100 1172 11A8; # (귝; 귝; 귝; 귝; 귝; ) HANGUL SYLLABLE GYUG +ADDE;ADDE;1100 1172 11A9;ADDE;1100 1172 11A9; # (귞; 귞; 귞; 귞; 귞; ) HANGUL SYLLABLE GYUGG +ADDF;ADDF;1100 1172 11AA;ADDF;1100 1172 11AA; # (귟; 귟; 귟; 귟; 귟; ) HANGUL SYLLABLE GYUGS +ADE0;ADE0;1100 1172 11AB;ADE0;1100 1172 11AB; # (균; 균; 균; 균; 균; ) HANGUL SYLLABLE GYUN +ADE1;ADE1;1100 1172 11AC;ADE1;1100 1172 11AC; # (귡; 귡; 귡; 귡; 귡; ) HANGUL SYLLABLE GYUNJ +ADE2;ADE2;1100 1172 11AD;ADE2;1100 1172 11AD; # (귢; 귢; 귢; 귢; 귢; ) HANGUL SYLLABLE GYUNH +ADE3;ADE3;1100 1172 11AE;ADE3;1100 1172 11AE; # (귣; 귣; 귣; 귣; 귣; ) HANGUL SYLLABLE GYUD +ADE4;ADE4;1100 1172 11AF;ADE4;1100 1172 11AF; # (귤; 귤; 귤; 귤; 귤; ) HANGUL SYLLABLE GYUL +ADE5;ADE5;1100 1172 11B0;ADE5;1100 1172 11B0; # (귥; 귥; 귥; 귥; 귥; ) HANGUL SYLLABLE GYULG +ADE6;ADE6;1100 1172 11B1;ADE6;1100 1172 11B1; # (귦; 귦; 귦; 귦; 귦; ) HANGUL SYLLABLE GYULM +ADE7;ADE7;1100 1172 11B2;ADE7;1100 1172 11B2; # (귧; 귧; 귧; 귧; 귧; ) HANGUL SYLLABLE GYULB +ADE8;ADE8;1100 1172 11B3;ADE8;1100 1172 11B3; # (귨; 귨; 귨; 귨; 귨; ) HANGUL SYLLABLE GYULS +ADE9;ADE9;1100 1172 11B4;ADE9;1100 1172 11B4; # (귩; 귩; 귩; 귩; 귩; ) HANGUL SYLLABLE GYULT +ADEA;ADEA;1100 1172 11B5;ADEA;1100 1172 11B5; # (귪; 귪; 귪; 귪; 귪; ) HANGUL SYLLABLE GYULP +ADEB;ADEB;1100 1172 11B6;ADEB;1100 1172 11B6; # (귫; 귫; 귫; 귫; 귫; ) HANGUL SYLLABLE GYULH +ADEC;ADEC;1100 1172 11B7;ADEC;1100 1172 11B7; # (귬; 귬; 귬; 귬; 귬; ) HANGUL SYLLABLE GYUM +ADED;ADED;1100 1172 11B8;ADED;1100 1172 11B8; # (귭; 귭; 귭; 귭; 귭; ) HANGUL SYLLABLE GYUB +ADEE;ADEE;1100 1172 11B9;ADEE;1100 1172 11B9; # (귮; 귮; 귮; 귮; 귮; ) HANGUL SYLLABLE GYUBS +ADEF;ADEF;1100 1172 11BA;ADEF;1100 1172 11BA; # (귯; 귯; 귯; 귯; 귯; ) HANGUL SYLLABLE GYUS +ADF0;ADF0;1100 1172 11BB;ADF0;1100 1172 11BB; # (귰; 귰; 귰; 귰; 귰; ) HANGUL SYLLABLE GYUSS +ADF1;ADF1;1100 1172 11BC;ADF1;1100 1172 11BC; # (귱; 귱; 귱; 귱; 귱; ) HANGUL SYLLABLE GYUNG +ADF2;ADF2;1100 1172 11BD;ADF2;1100 1172 11BD; # (귲; 귲; 귲; 귲; 귲; ) HANGUL SYLLABLE GYUJ +ADF3;ADF3;1100 1172 11BE;ADF3;1100 1172 11BE; # (귳; 귳; 귳; 귳; 귳; ) HANGUL SYLLABLE GYUC +ADF4;ADF4;1100 1172 11BF;ADF4;1100 1172 11BF; # (귴; 귴; 귴; 귴; 귴; ) HANGUL SYLLABLE GYUK +ADF5;ADF5;1100 1172 11C0;ADF5;1100 1172 11C0; # (귵; 귵; 귵; 귵; 귵; ) HANGUL SYLLABLE GYUT +ADF6;ADF6;1100 1172 11C1;ADF6;1100 1172 11C1; # (귶; 귶; 귶; 귶; 귶; ) HANGUL SYLLABLE GYUP +ADF7;ADF7;1100 1172 11C2;ADF7;1100 1172 11C2; # (귷; 귷; 귷; 귷; 귷; ) HANGUL SYLLABLE GYUH +ADF8;ADF8;1100 1173;ADF8;1100 1173; # (그; 그; 그; 그; 그; ) HANGUL SYLLABLE GEU +ADF9;ADF9;1100 1173 11A8;ADF9;1100 1173 11A8; # (극; 극; 극; 극; 극; ) HANGUL SYLLABLE GEUG +ADFA;ADFA;1100 1173 11A9;ADFA;1100 1173 11A9; # (귺; 귺; 귺; 귺; 귺; ) HANGUL SYLLABLE GEUGG +ADFB;ADFB;1100 1173 11AA;ADFB;1100 1173 11AA; # (귻; 귻; 귻; 귻; 귻; ) HANGUL SYLLABLE GEUGS +ADFC;ADFC;1100 1173 11AB;ADFC;1100 1173 11AB; # (근; 근; 근; 근; 근; ) HANGUL SYLLABLE GEUN +ADFD;ADFD;1100 1173 11AC;ADFD;1100 1173 11AC; # (귽; 귽; 귽; 귽; 귽; ) HANGUL SYLLABLE GEUNJ +ADFE;ADFE;1100 1173 11AD;ADFE;1100 1173 11AD; # (귾; 귾; 귾; 귾; 귾; ) HANGUL SYLLABLE GEUNH +ADFF;ADFF;1100 1173 11AE;ADFF;1100 1173 11AE; # (귿; 귿; 귿; 귿; 귿; ) HANGUL SYLLABLE GEUD +AE00;AE00;1100 1173 11AF;AE00;1100 1173 11AF; # (글; 글; 글; 글; 글; ) HANGUL SYLLABLE GEUL +AE01;AE01;1100 1173 11B0;AE01;1100 1173 11B0; # (긁; 긁; 긁; 긁; 긁; ) HANGUL SYLLABLE GEULG +AE02;AE02;1100 1173 11B1;AE02;1100 1173 11B1; # (긂; 긂; 긂; 긂; 긂; ) HANGUL SYLLABLE GEULM +AE03;AE03;1100 1173 11B2;AE03;1100 1173 11B2; # (긃; 긃; 긃; 긃; 긃; ) HANGUL SYLLABLE GEULB +AE04;AE04;1100 1173 11B3;AE04;1100 1173 11B3; # (긄; 긄; 긄; 긄; 긄; ) HANGUL SYLLABLE GEULS +AE05;AE05;1100 1173 11B4;AE05;1100 1173 11B4; # (긅; 긅; 긅; 긅; 긅; ) HANGUL SYLLABLE GEULT +AE06;AE06;1100 1173 11B5;AE06;1100 1173 11B5; # (긆; 긆; 긆; 긆; 긆; ) HANGUL SYLLABLE GEULP +AE07;AE07;1100 1173 11B6;AE07;1100 1173 11B6; # (긇; 긇; 긇; 긇; 긇; ) HANGUL SYLLABLE GEULH +AE08;AE08;1100 1173 11B7;AE08;1100 1173 11B7; # (금; 금; 금; 금; 금; ) HANGUL SYLLABLE GEUM +AE09;AE09;1100 1173 11B8;AE09;1100 1173 11B8; # (급; 급; 급; 급; 급; ) HANGUL SYLLABLE GEUB +AE0A;AE0A;1100 1173 11B9;AE0A;1100 1173 11B9; # (긊; 긊; 긊; 긊; 긊; ) HANGUL SYLLABLE GEUBS +AE0B;AE0B;1100 1173 11BA;AE0B;1100 1173 11BA; # (긋; 긋; 긋; 긋; 긋; ) HANGUL SYLLABLE GEUS +AE0C;AE0C;1100 1173 11BB;AE0C;1100 1173 11BB; # (긌; 긌; 긌; 긌; 긌; ) HANGUL SYLLABLE GEUSS +AE0D;AE0D;1100 1173 11BC;AE0D;1100 1173 11BC; # (긍; 긍; 긍; 긍; 긍; ) HANGUL SYLLABLE GEUNG +AE0E;AE0E;1100 1173 11BD;AE0E;1100 1173 11BD; # (긎; 긎; 긎; 긎; 긎; ) HANGUL SYLLABLE GEUJ +AE0F;AE0F;1100 1173 11BE;AE0F;1100 1173 11BE; # (긏; 긏; 긏; 긏; 긏; ) HANGUL SYLLABLE GEUC +AE10;AE10;1100 1173 11BF;AE10;1100 1173 11BF; # (긐; 긐; 긐; 긐; 긐; ) HANGUL SYLLABLE GEUK +AE11;AE11;1100 1173 11C0;AE11;1100 1173 11C0; # (긑; 긑; 긑; 긑; 긑; ) HANGUL SYLLABLE GEUT +AE12;AE12;1100 1173 11C1;AE12;1100 1173 11C1; # (긒; 긒; 긒; 긒; 긒; ) HANGUL SYLLABLE GEUP +AE13;AE13;1100 1173 11C2;AE13;1100 1173 11C2; # (긓; 긓; 긓; 긓; 긓; ) HANGUL SYLLABLE GEUH +AE14;AE14;1100 1174;AE14;1100 1174; # (긔; 긔; 긔; 긔; 긔; ) HANGUL SYLLABLE GYI +AE15;AE15;1100 1174 11A8;AE15;1100 1174 11A8; # (긕; 긕; 긕; 긕; 긕; ) HANGUL SYLLABLE GYIG +AE16;AE16;1100 1174 11A9;AE16;1100 1174 11A9; # (긖; 긖; 긖; 긖; 긖; ) HANGUL SYLLABLE GYIGG +AE17;AE17;1100 1174 11AA;AE17;1100 1174 11AA; # (긗; 긗; 긗; 긗; 긗; ) HANGUL SYLLABLE GYIGS +AE18;AE18;1100 1174 11AB;AE18;1100 1174 11AB; # (긘; 긘; 긘; 긘; 긘; ) HANGUL SYLLABLE GYIN +AE19;AE19;1100 1174 11AC;AE19;1100 1174 11AC; # (긙; 긙; 긙; 긙; 긙; ) HANGUL SYLLABLE GYINJ +AE1A;AE1A;1100 1174 11AD;AE1A;1100 1174 11AD; # (긚; 긚; 긚; 긚; 긚; ) HANGUL SYLLABLE GYINH +AE1B;AE1B;1100 1174 11AE;AE1B;1100 1174 11AE; # (긛; 긛; 긛; 긛; 긛; ) HANGUL SYLLABLE GYID +AE1C;AE1C;1100 1174 11AF;AE1C;1100 1174 11AF; # (긜; 긜; 긜; 긜; 긜; ) HANGUL SYLLABLE GYIL +AE1D;AE1D;1100 1174 11B0;AE1D;1100 1174 11B0; # (긝; 긝; 긝; 긝; 긝; ) HANGUL SYLLABLE GYILG +AE1E;AE1E;1100 1174 11B1;AE1E;1100 1174 11B1; # (긞; 긞; 긞; 긞; 긞; ) HANGUL SYLLABLE GYILM +AE1F;AE1F;1100 1174 11B2;AE1F;1100 1174 11B2; # (긟; 긟; 긟; 긟; 긟; ) HANGUL SYLLABLE GYILB +AE20;AE20;1100 1174 11B3;AE20;1100 1174 11B3; # (긠; 긠; 긠; 긠; 긠; ) HANGUL SYLLABLE GYILS +AE21;AE21;1100 1174 11B4;AE21;1100 1174 11B4; # (긡; 긡; 긡; 긡; 긡; ) HANGUL SYLLABLE GYILT +AE22;AE22;1100 1174 11B5;AE22;1100 1174 11B5; # (긢; 긢; 긢; 긢; 긢; ) HANGUL SYLLABLE GYILP +AE23;AE23;1100 1174 11B6;AE23;1100 1174 11B6; # (긣; 긣; 긣; 긣; 긣; ) HANGUL SYLLABLE GYILH +AE24;AE24;1100 1174 11B7;AE24;1100 1174 11B7; # (긤; 긤; 긤; 긤; 긤; ) HANGUL SYLLABLE GYIM +AE25;AE25;1100 1174 11B8;AE25;1100 1174 11B8; # (긥; 긥; 긥; 긥; 긥; ) HANGUL SYLLABLE GYIB +AE26;AE26;1100 1174 11B9;AE26;1100 1174 11B9; # (긦; 긦; 긦; 긦; 긦; ) HANGUL SYLLABLE GYIBS +AE27;AE27;1100 1174 11BA;AE27;1100 1174 11BA; # (긧; 긧; 긧; 긧; 긧; ) HANGUL SYLLABLE GYIS +AE28;AE28;1100 1174 11BB;AE28;1100 1174 11BB; # (긨; 긨; 긨; 긨; 긨; ) HANGUL SYLLABLE GYISS +AE29;AE29;1100 1174 11BC;AE29;1100 1174 11BC; # (긩; 긩; 긩; 긩; 긩; ) HANGUL SYLLABLE GYING +AE2A;AE2A;1100 1174 11BD;AE2A;1100 1174 11BD; # (긪; 긪; 긪; 긪; 긪; ) HANGUL SYLLABLE GYIJ +AE2B;AE2B;1100 1174 11BE;AE2B;1100 1174 11BE; # (긫; 긫; 긫; 긫; 긫; ) HANGUL SYLLABLE GYIC +AE2C;AE2C;1100 1174 11BF;AE2C;1100 1174 11BF; # (긬; 긬; 긬; 긬; 긬; ) HANGUL SYLLABLE GYIK +AE2D;AE2D;1100 1174 11C0;AE2D;1100 1174 11C0; # (긭; 긭; 긭; 긭; 긭; ) HANGUL SYLLABLE GYIT +AE2E;AE2E;1100 1174 11C1;AE2E;1100 1174 11C1; # (긮; 긮; 긮; 긮; 긮; ) HANGUL SYLLABLE GYIP +AE2F;AE2F;1100 1174 11C2;AE2F;1100 1174 11C2; # (긯; 긯; 긯; 긯; 긯; ) HANGUL SYLLABLE GYIH +AE30;AE30;1100 1175;AE30;1100 1175; # (기; 기; 기; 기; 기; ) HANGUL SYLLABLE GI +AE31;AE31;1100 1175 11A8;AE31;1100 1175 11A8; # (긱; 긱; 긱; 긱; 긱; ) HANGUL SYLLABLE GIG +AE32;AE32;1100 1175 11A9;AE32;1100 1175 11A9; # (긲; 긲; 긲; 긲; 긲; ) HANGUL SYLLABLE GIGG +AE33;AE33;1100 1175 11AA;AE33;1100 1175 11AA; # (긳; 긳; 긳; 긳; 긳; ) HANGUL SYLLABLE GIGS +AE34;AE34;1100 1175 11AB;AE34;1100 1175 11AB; # (긴; 긴; 긴; 긴; 긴; ) HANGUL SYLLABLE GIN +AE35;AE35;1100 1175 11AC;AE35;1100 1175 11AC; # (긵; 긵; 긵; 긵; 긵; ) HANGUL SYLLABLE GINJ +AE36;AE36;1100 1175 11AD;AE36;1100 1175 11AD; # (긶; 긶; 긶; 긶; 긶; ) HANGUL SYLLABLE GINH +AE37;AE37;1100 1175 11AE;AE37;1100 1175 11AE; # (긷; 긷; 긷; 긷; 긷; ) HANGUL SYLLABLE GID +AE38;AE38;1100 1175 11AF;AE38;1100 1175 11AF; # (길; 길; 길; 길; 길; ) HANGUL SYLLABLE GIL +AE39;AE39;1100 1175 11B0;AE39;1100 1175 11B0; # (긹; 긹; 긹; 긹; 긹; ) HANGUL SYLLABLE GILG +AE3A;AE3A;1100 1175 11B1;AE3A;1100 1175 11B1; # (긺; 긺; 긺; 긺; 긺; ) HANGUL SYLLABLE GILM +AE3B;AE3B;1100 1175 11B2;AE3B;1100 1175 11B2; # (긻; 긻; 긻; 긻; 긻; ) HANGUL SYLLABLE GILB +AE3C;AE3C;1100 1175 11B3;AE3C;1100 1175 11B3; # (긼; 긼; 긼; 긼; 긼; ) HANGUL SYLLABLE GILS +AE3D;AE3D;1100 1175 11B4;AE3D;1100 1175 11B4; # (긽; 긽; 긽; 긽; 긽; ) HANGUL SYLLABLE GILT +AE3E;AE3E;1100 1175 11B5;AE3E;1100 1175 11B5; # (긾; 긾; 긾; 긾; 긾; ) HANGUL SYLLABLE GILP +AE3F;AE3F;1100 1175 11B6;AE3F;1100 1175 11B6; # (긿; 긿; 긿; 긿; 긿; ) HANGUL SYLLABLE GILH +AE40;AE40;1100 1175 11B7;AE40;1100 1175 11B7; # (김; 김; 김; 김; 김; ) HANGUL SYLLABLE GIM +AE41;AE41;1100 1175 11B8;AE41;1100 1175 11B8; # (깁; 깁; 깁; 깁; 깁; ) HANGUL SYLLABLE GIB +AE42;AE42;1100 1175 11B9;AE42;1100 1175 11B9; # (깂; 깂; 깂; 깂; 깂; ) HANGUL SYLLABLE GIBS +AE43;AE43;1100 1175 11BA;AE43;1100 1175 11BA; # (깃; 깃; 깃; 깃; 깃; ) HANGUL SYLLABLE GIS +AE44;AE44;1100 1175 11BB;AE44;1100 1175 11BB; # (깄; 깄; 깄; 깄; 깄; ) HANGUL SYLLABLE GISS +AE45;AE45;1100 1175 11BC;AE45;1100 1175 11BC; # (깅; 깅; 깅; 깅; 깅; ) HANGUL SYLLABLE GING +AE46;AE46;1100 1175 11BD;AE46;1100 1175 11BD; # (깆; 깆; 깆; 깆; 깆; ) HANGUL SYLLABLE GIJ +AE47;AE47;1100 1175 11BE;AE47;1100 1175 11BE; # (깇; 깇; 깇; 깇; 깇; ) HANGUL SYLLABLE GIC +AE48;AE48;1100 1175 11BF;AE48;1100 1175 11BF; # (깈; 깈; 깈; 깈; 깈; ) HANGUL SYLLABLE GIK +AE49;AE49;1100 1175 11C0;AE49;1100 1175 11C0; # (깉; 깉; 깉; 깉; 깉; ) HANGUL SYLLABLE GIT +AE4A;AE4A;1100 1175 11C1;AE4A;1100 1175 11C1; # (깊; 깊; 깊; 깊; 깊; ) HANGUL SYLLABLE GIP +AE4B;AE4B;1100 1175 11C2;AE4B;1100 1175 11C2; # (깋; 깋; 깋; 깋; 깋; ) HANGUL SYLLABLE GIH +AE4C;AE4C;1101 1161;AE4C;1101 1161; # (까; 까; 까; 까; 까; ) HANGUL SYLLABLE GGA +AE4D;AE4D;1101 1161 11A8;AE4D;1101 1161 11A8; # (깍; 깍; 깍; 깍; 깍; ) HANGUL SYLLABLE GGAG +AE4E;AE4E;1101 1161 11A9;AE4E;1101 1161 11A9; # (깎; 깎; 깎; 깎; 깎; ) HANGUL SYLLABLE GGAGG +AE4F;AE4F;1101 1161 11AA;AE4F;1101 1161 11AA; # (깏; 깏; 깏; 깏; 깏; ) HANGUL SYLLABLE GGAGS +AE50;AE50;1101 1161 11AB;AE50;1101 1161 11AB; # (깐; 깐; 깐; 깐; 깐; ) HANGUL SYLLABLE GGAN +AE51;AE51;1101 1161 11AC;AE51;1101 1161 11AC; # (깑; 깑; 깑; 깑; 깑; ) HANGUL SYLLABLE GGANJ +AE52;AE52;1101 1161 11AD;AE52;1101 1161 11AD; # (깒; 깒; 깒; 깒; 깒; ) HANGUL SYLLABLE GGANH +AE53;AE53;1101 1161 11AE;AE53;1101 1161 11AE; # (깓; 깓; 깓; 깓; 깓; ) HANGUL SYLLABLE GGAD +AE54;AE54;1101 1161 11AF;AE54;1101 1161 11AF; # (깔; 깔; 깔; 깔; 깔; ) HANGUL SYLLABLE GGAL +AE55;AE55;1101 1161 11B0;AE55;1101 1161 11B0; # (깕; 깕; 깕; 깕; 깕; ) HANGUL SYLLABLE GGALG +AE56;AE56;1101 1161 11B1;AE56;1101 1161 11B1; # (깖; 깖; 깖; 깖; 깖; ) HANGUL SYLLABLE GGALM +AE57;AE57;1101 1161 11B2;AE57;1101 1161 11B2; # (깗; 깗; 깗; 깗; 깗; ) HANGUL SYLLABLE GGALB +AE58;AE58;1101 1161 11B3;AE58;1101 1161 11B3; # (깘; 깘; 깘; 깘; 깘; ) HANGUL SYLLABLE GGALS +AE59;AE59;1101 1161 11B4;AE59;1101 1161 11B4; # (깙; 깙; 깙; 깙; 깙; ) HANGUL SYLLABLE GGALT +AE5A;AE5A;1101 1161 11B5;AE5A;1101 1161 11B5; # (깚; 깚; 깚; 깚; 깚; ) HANGUL SYLLABLE GGALP +AE5B;AE5B;1101 1161 11B6;AE5B;1101 1161 11B6; # (깛; 깛; 깛; 깛; 깛; ) HANGUL SYLLABLE GGALH +AE5C;AE5C;1101 1161 11B7;AE5C;1101 1161 11B7; # (깜; 깜; 깜; 깜; 깜; ) HANGUL SYLLABLE GGAM +AE5D;AE5D;1101 1161 11B8;AE5D;1101 1161 11B8; # (깝; 깝; 깝; 깝; 깝; ) HANGUL SYLLABLE GGAB +AE5E;AE5E;1101 1161 11B9;AE5E;1101 1161 11B9; # (깞; 깞; 깞; 깞; 깞; ) HANGUL SYLLABLE GGABS +AE5F;AE5F;1101 1161 11BA;AE5F;1101 1161 11BA; # (깟; 깟; 깟; 깟; 깟; ) HANGUL SYLLABLE GGAS +AE60;AE60;1101 1161 11BB;AE60;1101 1161 11BB; # (깠; 깠; 깠; 깠; 깠; ) HANGUL SYLLABLE GGASS +AE61;AE61;1101 1161 11BC;AE61;1101 1161 11BC; # (깡; 깡; 깡; 깡; 깡; ) HANGUL SYLLABLE GGANG +AE62;AE62;1101 1161 11BD;AE62;1101 1161 11BD; # (깢; 깢; 깢; 깢; 깢; ) HANGUL SYLLABLE GGAJ +AE63;AE63;1101 1161 11BE;AE63;1101 1161 11BE; # (깣; 깣; 깣; 깣; 깣; ) HANGUL SYLLABLE GGAC +AE64;AE64;1101 1161 11BF;AE64;1101 1161 11BF; # (깤; 깤; 깤; 깤; 깤; ) HANGUL SYLLABLE GGAK +AE65;AE65;1101 1161 11C0;AE65;1101 1161 11C0; # (깥; 깥; 깥; 깥; 깥; ) HANGUL SYLLABLE GGAT +AE66;AE66;1101 1161 11C1;AE66;1101 1161 11C1; # (깦; 깦; 깦; 깦; 깦; ) HANGUL SYLLABLE GGAP +AE67;AE67;1101 1161 11C2;AE67;1101 1161 11C2; # (깧; 깧; 깧; 깧; 깧; ) HANGUL SYLLABLE GGAH +AE68;AE68;1101 1162;AE68;1101 1162; # (깨; 깨; 깨; 깨; 깨; ) HANGUL SYLLABLE GGAE +AE69;AE69;1101 1162 11A8;AE69;1101 1162 11A8; # (깩; 깩; 깩; 깩; 깩; ) HANGUL SYLLABLE GGAEG +AE6A;AE6A;1101 1162 11A9;AE6A;1101 1162 11A9; # (깪; 깪; 깪; 깪; 깪; ) HANGUL SYLLABLE GGAEGG +AE6B;AE6B;1101 1162 11AA;AE6B;1101 1162 11AA; # (깫; 깫; 깫; 깫; 깫; ) HANGUL SYLLABLE GGAEGS +AE6C;AE6C;1101 1162 11AB;AE6C;1101 1162 11AB; # (깬; 깬; 깬; 깬; 깬; ) HANGUL SYLLABLE GGAEN +AE6D;AE6D;1101 1162 11AC;AE6D;1101 1162 11AC; # (깭; 깭; 깭; 깭; 깭; ) HANGUL SYLLABLE GGAENJ +AE6E;AE6E;1101 1162 11AD;AE6E;1101 1162 11AD; # (깮; 깮; 깮; 깮; 깮; ) HANGUL SYLLABLE GGAENH +AE6F;AE6F;1101 1162 11AE;AE6F;1101 1162 11AE; # (깯; 깯; 깯; 깯; 깯; ) HANGUL SYLLABLE GGAED +AE70;AE70;1101 1162 11AF;AE70;1101 1162 11AF; # (깰; 깰; 깰; 깰; 깰; ) HANGUL SYLLABLE GGAEL +AE71;AE71;1101 1162 11B0;AE71;1101 1162 11B0; # (깱; 깱; 깱; 깱; 깱; ) HANGUL SYLLABLE GGAELG +AE72;AE72;1101 1162 11B1;AE72;1101 1162 11B1; # (깲; 깲; 깲; 깲; 깲; ) HANGUL SYLLABLE GGAELM +AE73;AE73;1101 1162 11B2;AE73;1101 1162 11B2; # (깳; 깳; 깳; 깳; 깳; ) HANGUL SYLLABLE GGAELB +AE74;AE74;1101 1162 11B3;AE74;1101 1162 11B3; # (깴; 깴; 깴; 깴; 깴; ) HANGUL SYLLABLE GGAELS +AE75;AE75;1101 1162 11B4;AE75;1101 1162 11B4; # (깵; 깵; 깵; 깵; 깵; ) HANGUL SYLLABLE GGAELT +AE76;AE76;1101 1162 11B5;AE76;1101 1162 11B5; # (깶; 깶; 깶; 깶; 깶; ) HANGUL SYLLABLE GGAELP +AE77;AE77;1101 1162 11B6;AE77;1101 1162 11B6; # (깷; 깷; 깷; 깷; 깷; ) HANGUL SYLLABLE GGAELH +AE78;AE78;1101 1162 11B7;AE78;1101 1162 11B7; # (깸; 깸; 깸; 깸; 깸; ) HANGUL SYLLABLE GGAEM +AE79;AE79;1101 1162 11B8;AE79;1101 1162 11B8; # (깹; 깹; 깹; 깹; 깹; ) HANGUL SYLLABLE GGAEB +AE7A;AE7A;1101 1162 11B9;AE7A;1101 1162 11B9; # (깺; 깺; 깺; 깺; 깺; ) HANGUL SYLLABLE GGAEBS +AE7B;AE7B;1101 1162 11BA;AE7B;1101 1162 11BA; # (깻; 깻; 깻; 깻; 깻; ) HANGUL SYLLABLE GGAES +AE7C;AE7C;1101 1162 11BB;AE7C;1101 1162 11BB; # (깼; 깼; 깼; 깼; 깼; ) HANGUL SYLLABLE GGAESS +AE7D;AE7D;1101 1162 11BC;AE7D;1101 1162 11BC; # (깽; 깽; 깽; 깽; 깽; ) HANGUL SYLLABLE GGAENG +AE7E;AE7E;1101 1162 11BD;AE7E;1101 1162 11BD; # (깾; 깾; 깾; 깾; 깾; ) HANGUL SYLLABLE GGAEJ +AE7F;AE7F;1101 1162 11BE;AE7F;1101 1162 11BE; # (깿; 깿; 깿; 깿; 깿; ) HANGUL SYLLABLE GGAEC +AE80;AE80;1101 1162 11BF;AE80;1101 1162 11BF; # (꺀; 꺀; 꺀; 꺀; 꺀; ) HANGUL SYLLABLE GGAEK +AE81;AE81;1101 1162 11C0;AE81;1101 1162 11C0; # (꺁; 꺁; 꺁; 꺁; 꺁; ) HANGUL SYLLABLE GGAET +AE82;AE82;1101 1162 11C1;AE82;1101 1162 11C1; # (꺂; 꺂; 꺂; 꺂; 꺂; ) HANGUL SYLLABLE GGAEP +AE83;AE83;1101 1162 11C2;AE83;1101 1162 11C2; # (꺃; 꺃; 꺃; 꺃; 꺃; ) HANGUL SYLLABLE GGAEH +AE84;AE84;1101 1163;AE84;1101 1163; # (꺄; 꺄; 꺄; 꺄; 꺄; ) HANGUL SYLLABLE GGYA +AE85;AE85;1101 1163 11A8;AE85;1101 1163 11A8; # (꺅; 꺅; 꺅; 꺅; 꺅; ) HANGUL SYLLABLE GGYAG +AE86;AE86;1101 1163 11A9;AE86;1101 1163 11A9; # (꺆; 꺆; 꺆; 꺆; 꺆; ) HANGUL SYLLABLE GGYAGG +AE87;AE87;1101 1163 11AA;AE87;1101 1163 11AA; # (꺇; 꺇; 꺇; 꺇; 꺇; ) HANGUL SYLLABLE GGYAGS +AE88;AE88;1101 1163 11AB;AE88;1101 1163 11AB; # (꺈; 꺈; 꺈; 꺈; 꺈; ) HANGUL SYLLABLE GGYAN +AE89;AE89;1101 1163 11AC;AE89;1101 1163 11AC; # (꺉; 꺉; 꺉; 꺉; 꺉; ) HANGUL SYLLABLE GGYANJ +AE8A;AE8A;1101 1163 11AD;AE8A;1101 1163 11AD; # (꺊; 꺊; 꺊; 꺊; 꺊; ) HANGUL SYLLABLE GGYANH +AE8B;AE8B;1101 1163 11AE;AE8B;1101 1163 11AE; # (꺋; 꺋; 꺋; 꺋; 꺋; ) HANGUL SYLLABLE GGYAD +AE8C;AE8C;1101 1163 11AF;AE8C;1101 1163 11AF; # (꺌; 꺌; 꺌; 꺌; 꺌; ) HANGUL SYLLABLE GGYAL +AE8D;AE8D;1101 1163 11B0;AE8D;1101 1163 11B0; # (꺍; 꺍; 꺍; 꺍; 꺍; ) HANGUL SYLLABLE GGYALG +AE8E;AE8E;1101 1163 11B1;AE8E;1101 1163 11B1; # (꺎; 꺎; 꺎; 꺎; 꺎; ) HANGUL SYLLABLE GGYALM +AE8F;AE8F;1101 1163 11B2;AE8F;1101 1163 11B2; # (꺏; 꺏; 꺏; 꺏; 꺏; ) HANGUL SYLLABLE GGYALB +AE90;AE90;1101 1163 11B3;AE90;1101 1163 11B3; # (꺐; 꺐; 꺐; 꺐; 꺐; ) HANGUL SYLLABLE GGYALS +AE91;AE91;1101 1163 11B4;AE91;1101 1163 11B4; # (꺑; 꺑; 꺑; 꺑; 꺑; ) HANGUL SYLLABLE GGYALT +AE92;AE92;1101 1163 11B5;AE92;1101 1163 11B5; # (꺒; 꺒; 꺒; 꺒; 꺒; ) HANGUL SYLLABLE GGYALP +AE93;AE93;1101 1163 11B6;AE93;1101 1163 11B6; # (꺓; 꺓; 꺓; 꺓; 꺓; ) HANGUL SYLLABLE GGYALH +AE94;AE94;1101 1163 11B7;AE94;1101 1163 11B7; # (꺔; 꺔; 꺔; 꺔; 꺔; ) HANGUL SYLLABLE GGYAM +AE95;AE95;1101 1163 11B8;AE95;1101 1163 11B8; # (꺕; 꺕; 꺕; 꺕; 꺕; ) HANGUL SYLLABLE GGYAB +AE96;AE96;1101 1163 11B9;AE96;1101 1163 11B9; # (꺖; 꺖; 꺖; 꺖; 꺖; ) HANGUL SYLLABLE GGYABS +AE97;AE97;1101 1163 11BA;AE97;1101 1163 11BA; # (꺗; 꺗; 꺗; 꺗; 꺗; ) HANGUL SYLLABLE GGYAS +AE98;AE98;1101 1163 11BB;AE98;1101 1163 11BB; # (꺘; 꺘; 꺘; 꺘; 꺘; ) HANGUL SYLLABLE GGYASS +AE99;AE99;1101 1163 11BC;AE99;1101 1163 11BC; # (꺙; 꺙; 꺙; 꺙; 꺙; ) HANGUL SYLLABLE GGYANG +AE9A;AE9A;1101 1163 11BD;AE9A;1101 1163 11BD; # (꺚; 꺚; 꺚; 꺚; 꺚; ) HANGUL SYLLABLE GGYAJ +AE9B;AE9B;1101 1163 11BE;AE9B;1101 1163 11BE; # (꺛; 꺛; 꺛; 꺛; 꺛; ) HANGUL SYLLABLE GGYAC +AE9C;AE9C;1101 1163 11BF;AE9C;1101 1163 11BF; # (꺜; 꺜; 꺜; 꺜; 꺜; ) HANGUL SYLLABLE GGYAK +AE9D;AE9D;1101 1163 11C0;AE9D;1101 1163 11C0; # (꺝; 꺝; 꺝; 꺝; 꺝; ) HANGUL SYLLABLE GGYAT +AE9E;AE9E;1101 1163 11C1;AE9E;1101 1163 11C1; # (꺞; 꺞; 꺞; 꺞; 꺞; ) HANGUL SYLLABLE GGYAP +AE9F;AE9F;1101 1163 11C2;AE9F;1101 1163 11C2; # (꺟; 꺟; 꺟; 꺟; 꺟; ) HANGUL SYLLABLE GGYAH +AEA0;AEA0;1101 1164;AEA0;1101 1164; # (꺠; 꺠; 꺠; 꺠; 꺠; ) HANGUL SYLLABLE GGYAE +AEA1;AEA1;1101 1164 11A8;AEA1;1101 1164 11A8; # (꺡; 꺡; 꺡; 꺡; 꺡; ) HANGUL SYLLABLE GGYAEG +AEA2;AEA2;1101 1164 11A9;AEA2;1101 1164 11A9; # (꺢; 꺢; 꺢; 꺢; 꺢; ) HANGUL SYLLABLE GGYAEGG +AEA3;AEA3;1101 1164 11AA;AEA3;1101 1164 11AA; # (꺣; 꺣; 꺣; 꺣; 꺣; ) HANGUL SYLLABLE GGYAEGS +AEA4;AEA4;1101 1164 11AB;AEA4;1101 1164 11AB; # (꺤; 꺤; 꺤; 꺤; 꺤; ) HANGUL SYLLABLE GGYAEN +AEA5;AEA5;1101 1164 11AC;AEA5;1101 1164 11AC; # (꺥; 꺥; 꺥; 꺥; 꺥; ) HANGUL SYLLABLE GGYAENJ +AEA6;AEA6;1101 1164 11AD;AEA6;1101 1164 11AD; # (꺦; 꺦; 꺦; 꺦; 꺦; ) HANGUL SYLLABLE GGYAENH +AEA7;AEA7;1101 1164 11AE;AEA7;1101 1164 11AE; # (꺧; 꺧; 꺧; 꺧; 꺧; ) HANGUL SYLLABLE GGYAED +AEA8;AEA8;1101 1164 11AF;AEA8;1101 1164 11AF; # (꺨; 꺨; 꺨; 꺨; 꺨; ) HANGUL SYLLABLE GGYAEL +AEA9;AEA9;1101 1164 11B0;AEA9;1101 1164 11B0; # (꺩; 꺩; 꺩; 꺩; 꺩; ) HANGUL SYLLABLE GGYAELG +AEAA;AEAA;1101 1164 11B1;AEAA;1101 1164 11B1; # (꺪; 꺪; 꺪; 꺪; 꺪; ) HANGUL SYLLABLE GGYAELM +AEAB;AEAB;1101 1164 11B2;AEAB;1101 1164 11B2; # (꺫; 꺫; 꺫; 꺫; 꺫; ) HANGUL SYLLABLE GGYAELB +AEAC;AEAC;1101 1164 11B3;AEAC;1101 1164 11B3; # (꺬; 꺬; 꺬; 꺬; 꺬; ) HANGUL SYLLABLE GGYAELS +AEAD;AEAD;1101 1164 11B4;AEAD;1101 1164 11B4; # (꺭; 꺭; 꺭; 꺭; 꺭; ) HANGUL SYLLABLE GGYAELT +AEAE;AEAE;1101 1164 11B5;AEAE;1101 1164 11B5; # (꺮; 꺮; 꺮; 꺮; 꺮; ) HANGUL SYLLABLE GGYAELP +AEAF;AEAF;1101 1164 11B6;AEAF;1101 1164 11B6; # (꺯; 꺯; 꺯; 꺯; 꺯; ) HANGUL SYLLABLE GGYAELH +AEB0;AEB0;1101 1164 11B7;AEB0;1101 1164 11B7; # (꺰; 꺰; 꺰; 꺰; 꺰; ) HANGUL SYLLABLE GGYAEM +AEB1;AEB1;1101 1164 11B8;AEB1;1101 1164 11B8; # (꺱; 꺱; 꺱; 꺱; 꺱; ) HANGUL SYLLABLE GGYAEB +AEB2;AEB2;1101 1164 11B9;AEB2;1101 1164 11B9; # (꺲; 꺲; 꺲; 꺲; 꺲; ) HANGUL SYLLABLE GGYAEBS +AEB3;AEB3;1101 1164 11BA;AEB3;1101 1164 11BA; # (꺳; 꺳; 꺳; 꺳; 꺳; ) HANGUL SYLLABLE GGYAES +AEB4;AEB4;1101 1164 11BB;AEB4;1101 1164 11BB; # (꺴; 꺴; 꺴; 꺴; 꺴; ) HANGUL SYLLABLE GGYAESS +AEB5;AEB5;1101 1164 11BC;AEB5;1101 1164 11BC; # (꺵; 꺵; 꺵; 꺵; 꺵; ) HANGUL SYLLABLE GGYAENG +AEB6;AEB6;1101 1164 11BD;AEB6;1101 1164 11BD; # (꺶; 꺶; 꺶; 꺶; 꺶; ) HANGUL SYLLABLE GGYAEJ +AEB7;AEB7;1101 1164 11BE;AEB7;1101 1164 11BE; # (꺷; 꺷; 꺷; 꺷; 꺷; ) HANGUL SYLLABLE GGYAEC +AEB8;AEB8;1101 1164 11BF;AEB8;1101 1164 11BF; # (꺸; 꺸; 꺸; 꺸; 꺸; ) HANGUL SYLLABLE GGYAEK +AEB9;AEB9;1101 1164 11C0;AEB9;1101 1164 11C0; # (꺹; 꺹; 꺹; 꺹; 꺹; ) HANGUL SYLLABLE GGYAET +AEBA;AEBA;1101 1164 11C1;AEBA;1101 1164 11C1; # (꺺; 꺺; 꺺; 꺺; 꺺; ) HANGUL SYLLABLE GGYAEP +AEBB;AEBB;1101 1164 11C2;AEBB;1101 1164 11C2; # (꺻; 꺻; 꺻; 꺻; 꺻; ) HANGUL SYLLABLE GGYAEH +AEBC;AEBC;1101 1165;AEBC;1101 1165; # (꺼; 꺼; 꺼; 꺼; 꺼; ) HANGUL SYLLABLE GGEO +AEBD;AEBD;1101 1165 11A8;AEBD;1101 1165 11A8; # (꺽; 꺽; 꺽; 꺽; 꺽; ) HANGUL SYLLABLE GGEOG +AEBE;AEBE;1101 1165 11A9;AEBE;1101 1165 11A9; # (꺾; 꺾; 꺾; 꺾; 꺾; ) HANGUL SYLLABLE GGEOGG +AEBF;AEBF;1101 1165 11AA;AEBF;1101 1165 11AA; # (꺿; 꺿; 꺿; 꺿; 꺿; ) HANGUL SYLLABLE GGEOGS +AEC0;AEC0;1101 1165 11AB;AEC0;1101 1165 11AB; # (껀; 껀; 껀; 껀; 껀; ) HANGUL SYLLABLE GGEON +AEC1;AEC1;1101 1165 11AC;AEC1;1101 1165 11AC; # (껁; 껁; 껁; 껁; 껁; ) HANGUL SYLLABLE GGEONJ +AEC2;AEC2;1101 1165 11AD;AEC2;1101 1165 11AD; # (껂; 껂; 껂; 껂; 껂; ) HANGUL SYLLABLE GGEONH +AEC3;AEC3;1101 1165 11AE;AEC3;1101 1165 11AE; # (껃; 껃; 껃; 껃; 껃; ) HANGUL SYLLABLE GGEOD +AEC4;AEC4;1101 1165 11AF;AEC4;1101 1165 11AF; # (껄; 껄; 껄; 껄; 껄; ) HANGUL SYLLABLE GGEOL +AEC5;AEC5;1101 1165 11B0;AEC5;1101 1165 11B0; # (껅; 껅; 껅; 껅; 껅; ) HANGUL SYLLABLE GGEOLG +AEC6;AEC6;1101 1165 11B1;AEC6;1101 1165 11B1; # (껆; 껆; 껆; 껆; 껆; ) HANGUL SYLLABLE GGEOLM +AEC7;AEC7;1101 1165 11B2;AEC7;1101 1165 11B2; # (껇; 껇; 껇; 껇; 껇; ) HANGUL SYLLABLE GGEOLB +AEC8;AEC8;1101 1165 11B3;AEC8;1101 1165 11B3; # (껈; 껈; 껈; 껈; 껈; ) HANGUL SYLLABLE GGEOLS +AEC9;AEC9;1101 1165 11B4;AEC9;1101 1165 11B4; # (껉; 껉; 껉; 껉; 껉; ) HANGUL SYLLABLE GGEOLT +AECA;AECA;1101 1165 11B5;AECA;1101 1165 11B5; # (껊; 껊; 껊; 껊; 껊; ) HANGUL SYLLABLE GGEOLP +AECB;AECB;1101 1165 11B6;AECB;1101 1165 11B6; # (껋; 껋; 껋; 껋; 껋; ) HANGUL SYLLABLE GGEOLH +AECC;AECC;1101 1165 11B7;AECC;1101 1165 11B7; # (껌; 껌; 껌; 껌; 껌; ) HANGUL SYLLABLE GGEOM +AECD;AECD;1101 1165 11B8;AECD;1101 1165 11B8; # (껍; 껍; 껍; 껍; 껍; ) HANGUL SYLLABLE GGEOB +AECE;AECE;1101 1165 11B9;AECE;1101 1165 11B9; # (껎; 껎; 껎; 껎; 껎; ) HANGUL SYLLABLE GGEOBS +AECF;AECF;1101 1165 11BA;AECF;1101 1165 11BA; # (껏; 껏; 껏; 껏; 껏; ) HANGUL SYLLABLE GGEOS +AED0;AED0;1101 1165 11BB;AED0;1101 1165 11BB; # (껐; 껐; 껐; 껐; 껐; ) HANGUL SYLLABLE GGEOSS +AED1;AED1;1101 1165 11BC;AED1;1101 1165 11BC; # (껑; 껑; 껑; 껑; 껑; ) HANGUL SYLLABLE GGEONG +AED2;AED2;1101 1165 11BD;AED2;1101 1165 11BD; # (껒; 껒; 껒; 껒; 껒; ) HANGUL SYLLABLE GGEOJ +AED3;AED3;1101 1165 11BE;AED3;1101 1165 11BE; # (껓; 껓; 껓; 껓; 껓; ) HANGUL SYLLABLE GGEOC +AED4;AED4;1101 1165 11BF;AED4;1101 1165 11BF; # (껔; 껔; 껔; 껔; 껔; ) HANGUL SYLLABLE GGEOK +AED5;AED5;1101 1165 11C0;AED5;1101 1165 11C0; # (껕; 껕; 껕; 껕; 껕; ) HANGUL SYLLABLE GGEOT +AED6;AED6;1101 1165 11C1;AED6;1101 1165 11C1; # (껖; 껖; 껖; 껖; 껖; ) HANGUL SYLLABLE GGEOP +AED7;AED7;1101 1165 11C2;AED7;1101 1165 11C2; # (껗; 껗; 껗; 껗; 껗; ) HANGUL SYLLABLE GGEOH +AED8;AED8;1101 1166;AED8;1101 1166; # (께; 께; 께; 께; 께; ) HANGUL SYLLABLE GGE +AED9;AED9;1101 1166 11A8;AED9;1101 1166 11A8; # (껙; 껙; 껙; 껙; 껙; ) HANGUL SYLLABLE GGEG +AEDA;AEDA;1101 1166 11A9;AEDA;1101 1166 11A9; # (껚; 껚; 껚; 껚; 껚; ) HANGUL SYLLABLE GGEGG +AEDB;AEDB;1101 1166 11AA;AEDB;1101 1166 11AA; # (껛; 껛; 껛; 껛; 껛; ) HANGUL SYLLABLE GGEGS +AEDC;AEDC;1101 1166 11AB;AEDC;1101 1166 11AB; # (껜; 껜; 껜; 껜; 껜; ) HANGUL SYLLABLE GGEN +AEDD;AEDD;1101 1166 11AC;AEDD;1101 1166 11AC; # (껝; 껝; 껝; 껝; 껝; ) HANGUL SYLLABLE GGENJ +AEDE;AEDE;1101 1166 11AD;AEDE;1101 1166 11AD; # (껞; 껞; 껞; 껞; 껞; ) HANGUL SYLLABLE GGENH +AEDF;AEDF;1101 1166 11AE;AEDF;1101 1166 11AE; # (껟; 껟; 껟; 껟; 껟; ) HANGUL SYLLABLE GGED +AEE0;AEE0;1101 1166 11AF;AEE0;1101 1166 11AF; # (껠; 껠; 껠; 껠; 껠; ) HANGUL SYLLABLE GGEL +AEE1;AEE1;1101 1166 11B0;AEE1;1101 1166 11B0; # (껡; 껡; 껡; 껡; 껡; ) HANGUL SYLLABLE GGELG +AEE2;AEE2;1101 1166 11B1;AEE2;1101 1166 11B1; # (껢; 껢; 껢; 껢; 껢; ) HANGUL SYLLABLE GGELM +AEE3;AEE3;1101 1166 11B2;AEE3;1101 1166 11B2; # (껣; 껣; 껣; 껣; 껣; ) HANGUL SYLLABLE GGELB +AEE4;AEE4;1101 1166 11B3;AEE4;1101 1166 11B3; # (껤; 껤; 껤; 껤; 껤; ) HANGUL SYLLABLE GGELS +AEE5;AEE5;1101 1166 11B4;AEE5;1101 1166 11B4; # (껥; 껥; 껥; 껥; 껥; ) HANGUL SYLLABLE GGELT +AEE6;AEE6;1101 1166 11B5;AEE6;1101 1166 11B5; # (껦; 껦; 껦; 껦; 껦; ) HANGUL SYLLABLE GGELP +AEE7;AEE7;1101 1166 11B6;AEE7;1101 1166 11B6; # (껧; 껧; 껧; 껧; 껧; ) HANGUL SYLLABLE GGELH +AEE8;AEE8;1101 1166 11B7;AEE8;1101 1166 11B7; # (껨; 껨; 껨; 껨; 껨; ) HANGUL SYLLABLE GGEM +AEE9;AEE9;1101 1166 11B8;AEE9;1101 1166 11B8; # (껩; 껩; 껩; 껩; 껩; ) HANGUL SYLLABLE GGEB +AEEA;AEEA;1101 1166 11B9;AEEA;1101 1166 11B9; # (껪; 껪; 껪; 껪; 껪; ) HANGUL SYLLABLE GGEBS +AEEB;AEEB;1101 1166 11BA;AEEB;1101 1166 11BA; # (껫; 껫; 껫; 껫; 껫; ) HANGUL SYLLABLE GGES +AEEC;AEEC;1101 1166 11BB;AEEC;1101 1166 11BB; # (껬; 껬; 껬; 껬; 껬; ) HANGUL SYLLABLE GGESS +AEED;AEED;1101 1166 11BC;AEED;1101 1166 11BC; # (껭; 껭; 껭; 껭; 껭; ) HANGUL SYLLABLE GGENG +AEEE;AEEE;1101 1166 11BD;AEEE;1101 1166 11BD; # (껮; 껮; 껮; 껮; 껮; ) HANGUL SYLLABLE GGEJ +AEEF;AEEF;1101 1166 11BE;AEEF;1101 1166 11BE; # (껯; 껯; 껯; 껯; 껯; ) HANGUL SYLLABLE GGEC +AEF0;AEF0;1101 1166 11BF;AEF0;1101 1166 11BF; # (껰; 껰; 껰; 껰; 껰; ) HANGUL SYLLABLE GGEK +AEF1;AEF1;1101 1166 11C0;AEF1;1101 1166 11C0; # (껱; 껱; 껱; 껱; 껱; ) HANGUL SYLLABLE GGET +AEF2;AEF2;1101 1166 11C1;AEF2;1101 1166 11C1; # (껲; 껲; 껲; 껲; 껲; ) HANGUL SYLLABLE GGEP +AEF3;AEF3;1101 1166 11C2;AEF3;1101 1166 11C2; # (껳; 껳; 껳; 껳; 껳; ) HANGUL SYLLABLE GGEH +AEF4;AEF4;1101 1167;AEF4;1101 1167; # (껴; 껴; 껴; 껴; 껴; ) HANGUL SYLLABLE GGYEO +AEF5;AEF5;1101 1167 11A8;AEF5;1101 1167 11A8; # (껵; 껵; 껵; 껵; 껵; ) HANGUL SYLLABLE GGYEOG +AEF6;AEF6;1101 1167 11A9;AEF6;1101 1167 11A9; # (껶; 껶; 껶; 껶; 껶; ) HANGUL SYLLABLE GGYEOGG +AEF7;AEF7;1101 1167 11AA;AEF7;1101 1167 11AA; # (껷; 껷; 껷; 껷; 껷; ) HANGUL SYLLABLE GGYEOGS +AEF8;AEF8;1101 1167 11AB;AEF8;1101 1167 11AB; # (껸; 껸; 껸; 껸; 껸; ) HANGUL SYLLABLE GGYEON +AEF9;AEF9;1101 1167 11AC;AEF9;1101 1167 11AC; # (껹; 껹; 껹; 껹; 껹; ) HANGUL SYLLABLE GGYEONJ +AEFA;AEFA;1101 1167 11AD;AEFA;1101 1167 11AD; # (껺; 껺; 껺; 껺; 껺; ) HANGUL SYLLABLE GGYEONH +AEFB;AEFB;1101 1167 11AE;AEFB;1101 1167 11AE; # (껻; 껻; 껻; 껻; 껻; ) HANGUL SYLLABLE GGYEOD +AEFC;AEFC;1101 1167 11AF;AEFC;1101 1167 11AF; # (껼; 껼; 껼; 껼; 껼; ) HANGUL SYLLABLE GGYEOL +AEFD;AEFD;1101 1167 11B0;AEFD;1101 1167 11B0; # (껽; 껽; 껽; 껽; 껽; ) HANGUL SYLLABLE GGYEOLG +AEFE;AEFE;1101 1167 11B1;AEFE;1101 1167 11B1; # (껾; 껾; 껾; 껾; 껾; ) HANGUL SYLLABLE GGYEOLM +AEFF;AEFF;1101 1167 11B2;AEFF;1101 1167 11B2; # (껿; 껿; 껿; 껿; 껿; ) HANGUL SYLLABLE GGYEOLB +AF00;AF00;1101 1167 11B3;AF00;1101 1167 11B3; # (꼀; 꼀; 꼀; 꼀; 꼀; ) HANGUL SYLLABLE GGYEOLS +AF01;AF01;1101 1167 11B4;AF01;1101 1167 11B4; # (꼁; 꼁; 꼁; 꼁; 꼁; ) HANGUL SYLLABLE GGYEOLT +AF02;AF02;1101 1167 11B5;AF02;1101 1167 11B5; # (꼂; 꼂; 꼂; 꼂; 꼂; ) HANGUL SYLLABLE GGYEOLP +AF03;AF03;1101 1167 11B6;AF03;1101 1167 11B6; # (꼃; 꼃; 꼃; 꼃; 꼃; ) HANGUL SYLLABLE GGYEOLH +AF04;AF04;1101 1167 11B7;AF04;1101 1167 11B7; # (꼄; 꼄; 꼄; 꼄; 꼄; ) HANGUL SYLLABLE GGYEOM +AF05;AF05;1101 1167 11B8;AF05;1101 1167 11B8; # (꼅; 꼅; 꼅; 꼅; 꼅; ) HANGUL SYLLABLE GGYEOB +AF06;AF06;1101 1167 11B9;AF06;1101 1167 11B9; # (꼆; 꼆; 꼆; 꼆; 꼆; ) HANGUL SYLLABLE GGYEOBS +AF07;AF07;1101 1167 11BA;AF07;1101 1167 11BA; # (꼇; 꼇; 꼇; 꼇; 꼇; ) HANGUL SYLLABLE GGYEOS +AF08;AF08;1101 1167 11BB;AF08;1101 1167 11BB; # (꼈; 꼈; 꼈; 꼈; 꼈; ) HANGUL SYLLABLE GGYEOSS +AF09;AF09;1101 1167 11BC;AF09;1101 1167 11BC; # (꼉; 꼉; 꼉; 꼉; 꼉; ) HANGUL SYLLABLE GGYEONG +AF0A;AF0A;1101 1167 11BD;AF0A;1101 1167 11BD; # (꼊; 꼊; 꼊; 꼊; 꼊; ) HANGUL SYLLABLE GGYEOJ +AF0B;AF0B;1101 1167 11BE;AF0B;1101 1167 11BE; # (꼋; 꼋; 꼋; 꼋; 꼋; ) HANGUL SYLLABLE GGYEOC +AF0C;AF0C;1101 1167 11BF;AF0C;1101 1167 11BF; # (꼌; 꼌; 꼌; 꼌; 꼌; ) HANGUL SYLLABLE GGYEOK +AF0D;AF0D;1101 1167 11C0;AF0D;1101 1167 11C0; # (꼍; 꼍; 꼍; 꼍; 꼍; ) HANGUL SYLLABLE GGYEOT +AF0E;AF0E;1101 1167 11C1;AF0E;1101 1167 11C1; # (꼎; 꼎; 꼎; 꼎; 꼎; ) HANGUL SYLLABLE GGYEOP +AF0F;AF0F;1101 1167 11C2;AF0F;1101 1167 11C2; # (꼏; 꼏; 꼏; 꼏; 꼏; ) HANGUL SYLLABLE GGYEOH +AF10;AF10;1101 1168;AF10;1101 1168; # (꼐; 꼐; 꼐; 꼐; 꼐; ) HANGUL SYLLABLE GGYE +AF11;AF11;1101 1168 11A8;AF11;1101 1168 11A8; # (꼑; 꼑; 꼑; 꼑; 꼑; ) HANGUL SYLLABLE GGYEG +AF12;AF12;1101 1168 11A9;AF12;1101 1168 11A9; # (꼒; 꼒; 꼒; 꼒; 꼒; ) HANGUL SYLLABLE GGYEGG +AF13;AF13;1101 1168 11AA;AF13;1101 1168 11AA; # (꼓; 꼓; 꼓; 꼓; 꼓; ) HANGUL SYLLABLE GGYEGS +AF14;AF14;1101 1168 11AB;AF14;1101 1168 11AB; # (꼔; 꼔; 꼔; 꼔; 꼔; ) HANGUL SYLLABLE GGYEN +AF15;AF15;1101 1168 11AC;AF15;1101 1168 11AC; # (꼕; 꼕; 꼕; 꼕; 꼕; ) HANGUL SYLLABLE GGYENJ +AF16;AF16;1101 1168 11AD;AF16;1101 1168 11AD; # (꼖; 꼖; 꼖; 꼖; 꼖; ) HANGUL SYLLABLE GGYENH +AF17;AF17;1101 1168 11AE;AF17;1101 1168 11AE; # (꼗; 꼗; 꼗; 꼗; 꼗; ) HANGUL SYLLABLE GGYED +AF18;AF18;1101 1168 11AF;AF18;1101 1168 11AF; # (꼘; 꼘; 꼘; 꼘; 꼘; ) HANGUL SYLLABLE GGYEL +AF19;AF19;1101 1168 11B0;AF19;1101 1168 11B0; # (꼙; 꼙; 꼙; 꼙; 꼙; ) HANGUL SYLLABLE GGYELG +AF1A;AF1A;1101 1168 11B1;AF1A;1101 1168 11B1; # (꼚; 꼚; 꼚; 꼚; 꼚; ) HANGUL SYLLABLE GGYELM +AF1B;AF1B;1101 1168 11B2;AF1B;1101 1168 11B2; # (꼛; 꼛; 꼛; 꼛; 꼛; ) HANGUL SYLLABLE GGYELB +AF1C;AF1C;1101 1168 11B3;AF1C;1101 1168 11B3; # (꼜; 꼜; 꼜; 꼜; 꼜; ) HANGUL SYLLABLE GGYELS +AF1D;AF1D;1101 1168 11B4;AF1D;1101 1168 11B4; # (꼝; 꼝; 꼝; 꼝; 꼝; ) HANGUL SYLLABLE GGYELT +AF1E;AF1E;1101 1168 11B5;AF1E;1101 1168 11B5; # (꼞; 꼞; 꼞; 꼞; 꼞; ) HANGUL SYLLABLE GGYELP +AF1F;AF1F;1101 1168 11B6;AF1F;1101 1168 11B6; # (꼟; 꼟; 꼟; 꼟; 꼟; ) HANGUL SYLLABLE GGYELH +AF20;AF20;1101 1168 11B7;AF20;1101 1168 11B7; # (꼠; 꼠; 꼠; 꼠; 꼠; ) HANGUL SYLLABLE GGYEM +AF21;AF21;1101 1168 11B8;AF21;1101 1168 11B8; # (꼡; 꼡; 꼡; 꼡; 꼡; ) HANGUL SYLLABLE GGYEB +AF22;AF22;1101 1168 11B9;AF22;1101 1168 11B9; # (꼢; 꼢; 꼢; 꼢; 꼢; ) HANGUL SYLLABLE GGYEBS +AF23;AF23;1101 1168 11BA;AF23;1101 1168 11BA; # (꼣; 꼣; 꼣; 꼣; 꼣; ) HANGUL SYLLABLE GGYES +AF24;AF24;1101 1168 11BB;AF24;1101 1168 11BB; # (꼤; 꼤; 꼤; 꼤; 꼤; ) HANGUL SYLLABLE GGYESS +AF25;AF25;1101 1168 11BC;AF25;1101 1168 11BC; # (꼥; 꼥; 꼥; 꼥; 꼥; ) HANGUL SYLLABLE GGYENG +AF26;AF26;1101 1168 11BD;AF26;1101 1168 11BD; # (꼦; 꼦; 꼦; 꼦; 꼦; ) HANGUL SYLLABLE GGYEJ +AF27;AF27;1101 1168 11BE;AF27;1101 1168 11BE; # (꼧; 꼧; 꼧; 꼧; 꼧; ) HANGUL SYLLABLE GGYEC +AF28;AF28;1101 1168 11BF;AF28;1101 1168 11BF; # (꼨; 꼨; 꼨; 꼨; 꼨; ) HANGUL SYLLABLE GGYEK +AF29;AF29;1101 1168 11C0;AF29;1101 1168 11C0; # (꼩; 꼩; 꼩; 꼩; 꼩; ) HANGUL SYLLABLE GGYET +AF2A;AF2A;1101 1168 11C1;AF2A;1101 1168 11C1; # (꼪; 꼪; 꼪; 꼪; 꼪; ) HANGUL SYLLABLE GGYEP +AF2B;AF2B;1101 1168 11C2;AF2B;1101 1168 11C2; # (꼫; 꼫; 꼫; 꼫; 꼫; ) HANGUL SYLLABLE GGYEH +AF2C;AF2C;1101 1169;AF2C;1101 1169; # (꼬; 꼬; 꼬; 꼬; 꼬; ) HANGUL SYLLABLE GGO +AF2D;AF2D;1101 1169 11A8;AF2D;1101 1169 11A8; # (꼭; 꼭; 꼭; 꼭; 꼭; ) HANGUL SYLLABLE GGOG +AF2E;AF2E;1101 1169 11A9;AF2E;1101 1169 11A9; # (꼮; 꼮; 꼮; 꼮; 꼮; ) HANGUL SYLLABLE GGOGG +AF2F;AF2F;1101 1169 11AA;AF2F;1101 1169 11AA; # (꼯; 꼯; 꼯; 꼯; 꼯; ) HANGUL SYLLABLE GGOGS +AF30;AF30;1101 1169 11AB;AF30;1101 1169 11AB; # (꼰; 꼰; 꼰; 꼰; 꼰; ) HANGUL SYLLABLE GGON +AF31;AF31;1101 1169 11AC;AF31;1101 1169 11AC; # (꼱; 꼱; 꼱; 꼱; 꼱; ) HANGUL SYLLABLE GGONJ +AF32;AF32;1101 1169 11AD;AF32;1101 1169 11AD; # (꼲; 꼲; 꼲; 꼲; 꼲; ) HANGUL SYLLABLE GGONH +AF33;AF33;1101 1169 11AE;AF33;1101 1169 11AE; # (꼳; 꼳; 꼳; 꼳; 꼳; ) HANGUL SYLLABLE GGOD +AF34;AF34;1101 1169 11AF;AF34;1101 1169 11AF; # (꼴; 꼴; 꼴; 꼴; 꼴; ) HANGUL SYLLABLE GGOL +AF35;AF35;1101 1169 11B0;AF35;1101 1169 11B0; # (꼵; 꼵; 꼵; 꼵; 꼵; ) HANGUL SYLLABLE GGOLG +AF36;AF36;1101 1169 11B1;AF36;1101 1169 11B1; # (꼶; 꼶; 꼶; 꼶; 꼶; ) HANGUL SYLLABLE GGOLM +AF37;AF37;1101 1169 11B2;AF37;1101 1169 11B2; # (꼷; 꼷; 꼷; 꼷; 꼷; ) HANGUL SYLLABLE GGOLB +AF38;AF38;1101 1169 11B3;AF38;1101 1169 11B3; # (꼸; 꼸; 꼸; 꼸; 꼸; ) HANGUL SYLLABLE GGOLS +AF39;AF39;1101 1169 11B4;AF39;1101 1169 11B4; # (꼹; 꼹; 꼹; 꼹; 꼹; ) HANGUL SYLLABLE GGOLT +AF3A;AF3A;1101 1169 11B5;AF3A;1101 1169 11B5; # (꼺; 꼺; 꼺; 꼺; 꼺; ) HANGUL SYLLABLE GGOLP +AF3B;AF3B;1101 1169 11B6;AF3B;1101 1169 11B6; # (꼻; 꼻; 꼻; 꼻; 꼻; ) HANGUL SYLLABLE GGOLH +AF3C;AF3C;1101 1169 11B7;AF3C;1101 1169 11B7; # (꼼; 꼼; 꼼; 꼼; 꼼; ) HANGUL SYLLABLE GGOM +AF3D;AF3D;1101 1169 11B8;AF3D;1101 1169 11B8; # (꼽; 꼽; 꼽; 꼽; 꼽; ) HANGUL SYLLABLE GGOB +AF3E;AF3E;1101 1169 11B9;AF3E;1101 1169 11B9; # (꼾; 꼾; 꼾; 꼾; 꼾; ) HANGUL SYLLABLE GGOBS +AF3F;AF3F;1101 1169 11BA;AF3F;1101 1169 11BA; # (꼿; 꼿; 꼿; 꼿; 꼿; ) HANGUL SYLLABLE GGOS +AF40;AF40;1101 1169 11BB;AF40;1101 1169 11BB; # (꽀; 꽀; 꽀; 꽀; 꽀; ) HANGUL SYLLABLE GGOSS +AF41;AF41;1101 1169 11BC;AF41;1101 1169 11BC; # (꽁; 꽁; 꽁; 꽁; 꽁; ) HANGUL SYLLABLE GGONG +AF42;AF42;1101 1169 11BD;AF42;1101 1169 11BD; # (꽂; 꽂; 꽂; 꽂; 꽂; ) HANGUL SYLLABLE GGOJ +AF43;AF43;1101 1169 11BE;AF43;1101 1169 11BE; # (꽃; 꽃; 꽃; 꽃; 꽃; ) HANGUL SYLLABLE GGOC +AF44;AF44;1101 1169 11BF;AF44;1101 1169 11BF; # (꽄; 꽄; 꽄; 꽄; 꽄; ) HANGUL SYLLABLE GGOK +AF45;AF45;1101 1169 11C0;AF45;1101 1169 11C0; # (꽅; 꽅; 꽅; 꽅; 꽅; ) HANGUL SYLLABLE GGOT +AF46;AF46;1101 1169 11C1;AF46;1101 1169 11C1; # (꽆; 꽆; 꽆; 꽆; 꽆; ) HANGUL SYLLABLE GGOP +AF47;AF47;1101 1169 11C2;AF47;1101 1169 11C2; # (꽇; 꽇; 꽇; 꽇; 꽇; ) HANGUL SYLLABLE GGOH +AF48;AF48;1101 116A;AF48;1101 116A; # (꽈; 꽈; 꽈; 꽈; 꽈; ) HANGUL SYLLABLE GGWA +AF49;AF49;1101 116A 11A8;AF49;1101 116A 11A8; # (꽉; 꽉; 꽉; 꽉; 꽉; ) HANGUL SYLLABLE GGWAG +AF4A;AF4A;1101 116A 11A9;AF4A;1101 116A 11A9; # (꽊; 꽊; 꽊; 꽊; 꽊; ) HANGUL SYLLABLE GGWAGG +AF4B;AF4B;1101 116A 11AA;AF4B;1101 116A 11AA; # (꽋; 꽋; 꽋; 꽋; 꽋; ) HANGUL SYLLABLE GGWAGS +AF4C;AF4C;1101 116A 11AB;AF4C;1101 116A 11AB; # (꽌; 꽌; 꽌; 꽌; 꽌; ) HANGUL SYLLABLE GGWAN +AF4D;AF4D;1101 116A 11AC;AF4D;1101 116A 11AC; # (꽍; 꽍; 꽍; 꽍; 꽍; ) HANGUL SYLLABLE GGWANJ +AF4E;AF4E;1101 116A 11AD;AF4E;1101 116A 11AD; # (꽎; 꽎; 꽎; 꽎; 꽎; ) HANGUL SYLLABLE GGWANH +AF4F;AF4F;1101 116A 11AE;AF4F;1101 116A 11AE; # (꽏; 꽏; 꽏; 꽏; 꽏; ) HANGUL SYLLABLE GGWAD +AF50;AF50;1101 116A 11AF;AF50;1101 116A 11AF; # (꽐; 꽐; 꽐; 꽐; 꽐; ) HANGUL SYLLABLE GGWAL +AF51;AF51;1101 116A 11B0;AF51;1101 116A 11B0; # (꽑; 꽑; 꽑; 꽑; 꽑; ) HANGUL SYLLABLE GGWALG +AF52;AF52;1101 116A 11B1;AF52;1101 116A 11B1; # (꽒; 꽒; 꽒; 꽒; 꽒; ) HANGUL SYLLABLE GGWALM +AF53;AF53;1101 116A 11B2;AF53;1101 116A 11B2; # (꽓; 꽓; 꽓; 꽓; 꽓; ) HANGUL SYLLABLE GGWALB +AF54;AF54;1101 116A 11B3;AF54;1101 116A 11B3; # (꽔; 꽔; 꽔; 꽔; 꽔; ) HANGUL SYLLABLE GGWALS +AF55;AF55;1101 116A 11B4;AF55;1101 116A 11B4; # (꽕; 꽕; 꽕; 꽕; 꽕; ) HANGUL SYLLABLE GGWALT +AF56;AF56;1101 116A 11B5;AF56;1101 116A 11B5; # (꽖; 꽖; 꽖; 꽖; 꽖; ) HANGUL SYLLABLE GGWALP +AF57;AF57;1101 116A 11B6;AF57;1101 116A 11B6; # (꽗; 꽗; 꽗; 꽗; 꽗; ) HANGUL SYLLABLE GGWALH +AF58;AF58;1101 116A 11B7;AF58;1101 116A 11B7; # (꽘; 꽘; 꽘; 꽘; 꽘; ) HANGUL SYLLABLE GGWAM +AF59;AF59;1101 116A 11B8;AF59;1101 116A 11B8; # (꽙; 꽙; 꽙; 꽙; 꽙; ) HANGUL SYLLABLE GGWAB +AF5A;AF5A;1101 116A 11B9;AF5A;1101 116A 11B9; # (꽚; 꽚; 꽚; 꽚; 꽚; ) HANGUL SYLLABLE GGWABS +AF5B;AF5B;1101 116A 11BA;AF5B;1101 116A 11BA; # (꽛; 꽛; 꽛; 꽛; 꽛; ) HANGUL SYLLABLE GGWAS +AF5C;AF5C;1101 116A 11BB;AF5C;1101 116A 11BB; # (꽜; 꽜; 꽜; 꽜; 꽜; ) HANGUL SYLLABLE GGWASS +AF5D;AF5D;1101 116A 11BC;AF5D;1101 116A 11BC; # (꽝; 꽝; 꽝; 꽝; 꽝; ) HANGUL SYLLABLE GGWANG +AF5E;AF5E;1101 116A 11BD;AF5E;1101 116A 11BD; # (꽞; 꽞; 꽞; 꽞; 꽞; ) HANGUL SYLLABLE GGWAJ +AF5F;AF5F;1101 116A 11BE;AF5F;1101 116A 11BE; # (꽟; 꽟; 꽟; 꽟; 꽟; ) HANGUL SYLLABLE GGWAC +AF60;AF60;1101 116A 11BF;AF60;1101 116A 11BF; # (꽠; 꽠; 꽠; 꽠; 꽠; ) HANGUL SYLLABLE GGWAK +AF61;AF61;1101 116A 11C0;AF61;1101 116A 11C0; # (꽡; 꽡; 꽡; 꽡; 꽡; ) HANGUL SYLLABLE GGWAT +AF62;AF62;1101 116A 11C1;AF62;1101 116A 11C1; # (꽢; 꽢; 꽢; 꽢; 꽢; ) HANGUL SYLLABLE GGWAP +AF63;AF63;1101 116A 11C2;AF63;1101 116A 11C2; # (꽣; 꽣; 꽣; 꽣; 꽣; ) HANGUL SYLLABLE GGWAH +AF64;AF64;1101 116B;AF64;1101 116B; # (꽤; 꽤; 꽤; 꽤; 꽤; ) HANGUL SYLLABLE GGWAE +AF65;AF65;1101 116B 11A8;AF65;1101 116B 11A8; # (꽥; 꽥; 꽥; 꽥; 꽥; ) HANGUL SYLLABLE GGWAEG +AF66;AF66;1101 116B 11A9;AF66;1101 116B 11A9; # (꽦; 꽦; 꽦; 꽦; 꽦; ) HANGUL SYLLABLE GGWAEGG +AF67;AF67;1101 116B 11AA;AF67;1101 116B 11AA; # (꽧; 꽧; 꽧; 꽧; 꽧; ) HANGUL SYLLABLE GGWAEGS +AF68;AF68;1101 116B 11AB;AF68;1101 116B 11AB; # (꽨; 꽨; 꽨; 꽨; 꽨; ) HANGUL SYLLABLE GGWAEN +AF69;AF69;1101 116B 11AC;AF69;1101 116B 11AC; # (꽩; 꽩; 꽩; 꽩; 꽩; ) HANGUL SYLLABLE GGWAENJ +AF6A;AF6A;1101 116B 11AD;AF6A;1101 116B 11AD; # (꽪; 꽪; 꽪; 꽪; 꽪; ) HANGUL SYLLABLE GGWAENH +AF6B;AF6B;1101 116B 11AE;AF6B;1101 116B 11AE; # (꽫; 꽫; 꽫; 꽫; 꽫; ) HANGUL SYLLABLE GGWAED +AF6C;AF6C;1101 116B 11AF;AF6C;1101 116B 11AF; # (꽬; 꽬; 꽬; 꽬; 꽬; ) HANGUL SYLLABLE GGWAEL +AF6D;AF6D;1101 116B 11B0;AF6D;1101 116B 11B0; # (꽭; 꽭; 꽭; 꽭; 꽭; ) HANGUL SYLLABLE GGWAELG +AF6E;AF6E;1101 116B 11B1;AF6E;1101 116B 11B1; # (꽮; 꽮; 꽮; 꽮; 꽮; ) HANGUL SYLLABLE GGWAELM +AF6F;AF6F;1101 116B 11B2;AF6F;1101 116B 11B2; # (꽯; 꽯; 꽯; 꽯; 꽯; ) HANGUL SYLLABLE GGWAELB +AF70;AF70;1101 116B 11B3;AF70;1101 116B 11B3; # (꽰; 꽰; 꽰; 꽰; 꽰; ) HANGUL SYLLABLE GGWAELS +AF71;AF71;1101 116B 11B4;AF71;1101 116B 11B4; # (꽱; 꽱; 꽱; 꽱; 꽱; ) HANGUL SYLLABLE GGWAELT +AF72;AF72;1101 116B 11B5;AF72;1101 116B 11B5; # (꽲; 꽲; 꽲; 꽲; 꽲; ) HANGUL SYLLABLE GGWAELP +AF73;AF73;1101 116B 11B6;AF73;1101 116B 11B6; # (꽳; 꽳; 꽳; 꽳; 꽳; ) HANGUL SYLLABLE GGWAELH +AF74;AF74;1101 116B 11B7;AF74;1101 116B 11B7; # (꽴; 꽴; 꽴; 꽴; 꽴; ) HANGUL SYLLABLE GGWAEM +AF75;AF75;1101 116B 11B8;AF75;1101 116B 11B8; # (꽵; 꽵; 꽵; 꽵; 꽵; ) HANGUL SYLLABLE GGWAEB +AF76;AF76;1101 116B 11B9;AF76;1101 116B 11B9; # (꽶; 꽶; 꽶; 꽶; 꽶; ) HANGUL SYLLABLE GGWAEBS +AF77;AF77;1101 116B 11BA;AF77;1101 116B 11BA; # (꽷; 꽷; 꽷; 꽷; 꽷; ) HANGUL SYLLABLE GGWAES +AF78;AF78;1101 116B 11BB;AF78;1101 116B 11BB; # (꽸; 꽸; 꽸; 꽸; 꽸; ) HANGUL SYLLABLE GGWAESS +AF79;AF79;1101 116B 11BC;AF79;1101 116B 11BC; # (꽹; 꽹; 꽹; 꽹; 꽹; ) HANGUL SYLLABLE GGWAENG +AF7A;AF7A;1101 116B 11BD;AF7A;1101 116B 11BD; # (꽺; 꽺; 꽺; 꽺; 꽺; ) HANGUL SYLLABLE GGWAEJ +AF7B;AF7B;1101 116B 11BE;AF7B;1101 116B 11BE; # (꽻; 꽻; 꽻; 꽻; 꽻; ) HANGUL SYLLABLE GGWAEC +AF7C;AF7C;1101 116B 11BF;AF7C;1101 116B 11BF; # (꽼; 꽼; 꽼; 꽼; 꽼; ) HANGUL SYLLABLE GGWAEK +AF7D;AF7D;1101 116B 11C0;AF7D;1101 116B 11C0; # (꽽; 꽽; 꽽; 꽽; 꽽; ) HANGUL SYLLABLE GGWAET +AF7E;AF7E;1101 116B 11C1;AF7E;1101 116B 11C1; # (꽾; 꽾; 꽾; 꽾; 꽾; ) HANGUL SYLLABLE GGWAEP +AF7F;AF7F;1101 116B 11C2;AF7F;1101 116B 11C2; # (꽿; 꽿; 꽿; 꽿; 꽿; ) HANGUL SYLLABLE GGWAEH +AF80;AF80;1101 116C;AF80;1101 116C; # (꾀; 꾀; 꾀; 꾀; 꾀; ) HANGUL SYLLABLE GGOE +AF81;AF81;1101 116C 11A8;AF81;1101 116C 11A8; # (꾁; 꾁; 꾁; 꾁; 꾁; ) HANGUL SYLLABLE GGOEG +AF82;AF82;1101 116C 11A9;AF82;1101 116C 11A9; # (꾂; 꾂; 꾂; 꾂; 꾂; ) HANGUL SYLLABLE GGOEGG +AF83;AF83;1101 116C 11AA;AF83;1101 116C 11AA; # (꾃; 꾃; 꾃; 꾃; 꾃; ) HANGUL SYLLABLE GGOEGS +AF84;AF84;1101 116C 11AB;AF84;1101 116C 11AB; # (꾄; 꾄; 꾄; 꾄; 꾄; ) HANGUL SYLLABLE GGOEN +AF85;AF85;1101 116C 11AC;AF85;1101 116C 11AC; # (꾅; 꾅; 꾅; 꾅; 꾅; ) HANGUL SYLLABLE GGOENJ +AF86;AF86;1101 116C 11AD;AF86;1101 116C 11AD; # (꾆; 꾆; 꾆; 꾆; 꾆; ) HANGUL SYLLABLE GGOENH +AF87;AF87;1101 116C 11AE;AF87;1101 116C 11AE; # (꾇; 꾇; 꾇; 꾇; 꾇; ) HANGUL SYLLABLE GGOED +AF88;AF88;1101 116C 11AF;AF88;1101 116C 11AF; # (꾈; 꾈; 꾈; 꾈; 꾈; ) HANGUL SYLLABLE GGOEL +AF89;AF89;1101 116C 11B0;AF89;1101 116C 11B0; # (꾉; 꾉; 꾉; 꾉; 꾉; ) HANGUL SYLLABLE GGOELG +AF8A;AF8A;1101 116C 11B1;AF8A;1101 116C 11B1; # (꾊; 꾊; 꾊; 꾊; 꾊; ) HANGUL SYLLABLE GGOELM +AF8B;AF8B;1101 116C 11B2;AF8B;1101 116C 11B2; # (꾋; 꾋; 꾋; 꾋; 꾋; ) HANGUL SYLLABLE GGOELB +AF8C;AF8C;1101 116C 11B3;AF8C;1101 116C 11B3; # (꾌; 꾌; 꾌; 꾌; 꾌; ) HANGUL SYLLABLE GGOELS +AF8D;AF8D;1101 116C 11B4;AF8D;1101 116C 11B4; # (꾍; 꾍; 꾍; 꾍; 꾍; ) HANGUL SYLLABLE GGOELT +AF8E;AF8E;1101 116C 11B5;AF8E;1101 116C 11B5; # (꾎; 꾎; 꾎; 꾎; 꾎; ) HANGUL SYLLABLE GGOELP +AF8F;AF8F;1101 116C 11B6;AF8F;1101 116C 11B6; # (꾏; 꾏; 꾏; 꾏; 꾏; ) HANGUL SYLLABLE GGOELH +AF90;AF90;1101 116C 11B7;AF90;1101 116C 11B7; # (꾐; 꾐; 꾐; 꾐; 꾐; ) HANGUL SYLLABLE GGOEM +AF91;AF91;1101 116C 11B8;AF91;1101 116C 11B8; # (꾑; 꾑; 꾑; 꾑; 꾑; ) HANGUL SYLLABLE GGOEB +AF92;AF92;1101 116C 11B9;AF92;1101 116C 11B9; # (꾒; 꾒; 꾒; 꾒; 꾒; ) HANGUL SYLLABLE GGOEBS +AF93;AF93;1101 116C 11BA;AF93;1101 116C 11BA; # (꾓; 꾓; 꾓; 꾓; 꾓; ) HANGUL SYLLABLE GGOES +AF94;AF94;1101 116C 11BB;AF94;1101 116C 11BB; # (꾔; 꾔; 꾔; 꾔; 꾔; ) HANGUL SYLLABLE GGOESS +AF95;AF95;1101 116C 11BC;AF95;1101 116C 11BC; # (꾕; 꾕; 꾕; 꾕; 꾕; ) HANGUL SYLLABLE GGOENG +AF96;AF96;1101 116C 11BD;AF96;1101 116C 11BD; # (꾖; 꾖; 꾖; 꾖; 꾖; ) HANGUL SYLLABLE GGOEJ +AF97;AF97;1101 116C 11BE;AF97;1101 116C 11BE; # (꾗; 꾗; 꾗; 꾗; 꾗; ) HANGUL SYLLABLE GGOEC +AF98;AF98;1101 116C 11BF;AF98;1101 116C 11BF; # (꾘; 꾘; 꾘; 꾘; 꾘; ) HANGUL SYLLABLE GGOEK +AF99;AF99;1101 116C 11C0;AF99;1101 116C 11C0; # (꾙; 꾙; 꾙; 꾙; 꾙; ) HANGUL SYLLABLE GGOET +AF9A;AF9A;1101 116C 11C1;AF9A;1101 116C 11C1; # (꾚; 꾚; 꾚; 꾚; 꾚; ) HANGUL SYLLABLE GGOEP +AF9B;AF9B;1101 116C 11C2;AF9B;1101 116C 11C2; # (꾛; 꾛; 꾛; 꾛; 꾛; ) HANGUL SYLLABLE GGOEH +AF9C;AF9C;1101 116D;AF9C;1101 116D; # (꾜; 꾜; 꾜; 꾜; 꾜; ) HANGUL SYLLABLE GGYO +AF9D;AF9D;1101 116D 11A8;AF9D;1101 116D 11A8; # (꾝; 꾝; 꾝; 꾝; 꾝; ) HANGUL SYLLABLE GGYOG +AF9E;AF9E;1101 116D 11A9;AF9E;1101 116D 11A9; # (꾞; 꾞; 꾞; 꾞; 꾞; ) HANGUL SYLLABLE GGYOGG +AF9F;AF9F;1101 116D 11AA;AF9F;1101 116D 11AA; # (꾟; 꾟; 꾟; 꾟; 꾟; ) HANGUL SYLLABLE GGYOGS +AFA0;AFA0;1101 116D 11AB;AFA0;1101 116D 11AB; # (꾠; 꾠; 꾠; 꾠; 꾠; ) HANGUL SYLLABLE GGYON +AFA1;AFA1;1101 116D 11AC;AFA1;1101 116D 11AC; # (꾡; 꾡; 꾡; 꾡; 꾡; ) HANGUL SYLLABLE GGYONJ +AFA2;AFA2;1101 116D 11AD;AFA2;1101 116D 11AD; # (꾢; 꾢; 꾢; 꾢; 꾢; ) HANGUL SYLLABLE GGYONH +AFA3;AFA3;1101 116D 11AE;AFA3;1101 116D 11AE; # (꾣; 꾣; 꾣; 꾣; 꾣; ) HANGUL SYLLABLE GGYOD +AFA4;AFA4;1101 116D 11AF;AFA4;1101 116D 11AF; # (꾤; 꾤; 꾤; 꾤; 꾤; ) HANGUL SYLLABLE GGYOL +AFA5;AFA5;1101 116D 11B0;AFA5;1101 116D 11B0; # (꾥; 꾥; 꾥; 꾥; 꾥; ) HANGUL SYLLABLE GGYOLG +AFA6;AFA6;1101 116D 11B1;AFA6;1101 116D 11B1; # (꾦; 꾦; 꾦; 꾦; 꾦; ) HANGUL SYLLABLE GGYOLM +AFA7;AFA7;1101 116D 11B2;AFA7;1101 116D 11B2; # (꾧; 꾧; 꾧; 꾧; 꾧; ) HANGUL SYLLABLE GGYOLB +AFA8;AFA8;1101 116D 11B3;AFA8;1101 116D 11B3; # (꾨; 꾨; 꾨; 꾨; 꾨; ) HANGUL SYLLABLE GGYOLS +AFA9;AFA9;1101 116D 11B4;AFA9;1101 116D 11B4; # (꾩; 꾩; 꾩; 꾩; 꾩; ) HANGUL SYLLABLE GGYOLT +AFAA;AFAA;1101 116D 11B5;AFAA;1101 116D 11B5; # (꾪; 꾪; 꾪; 꾪; 꾪; ) HANGUL SYLLABLE GGYOLP +AFAB;AFAB;1101 116D 11B6;AFAB;1101 116D 11B6; # (꾫; 꾫; 꾫; 꾫; 꾫; ) HANGUL SYLLABLE GGYOLH +AFAC;AFAC;1101 116D 11B7;AFAC;1101 116D 11B7; # (꾬; 꾬; 꾬; 꾬; 꾬; ) HANGUL SYLLABLE GGYOM +AFAD;AFAD;1101 116D 11B8;AFAD;1101 116D 11B8; # (꾭; 꾭; 꾭; 꾭; 꾭; ) HANGUL SYLLABLE GGYOB +AFAE;AFAE;1101 116D 11B9;AFAE;1101 116D 11B9; # (꾮; 꾮; 꾮; 꾮; 꾮; ) HANGUL SYLLABLE GGYOBS +AFAF;AFAF;1101 116D 11BA;AFAF;1101 116D 11BA; # (꾯; 꾯; 꾯; 꾯; 꾯; ) HANGUL SYLLABLE GGYOS +AFB0;AFB0;1101 116D 11BB;AFB0;1101 116D 11BB; # (꾰; 꾰; 꾰; 꾰; 꾰; ) HANGUL SYLLABLE GGYOSS +AFB1;AFB1;1101 116D 11BC;AFB1;1101 116D 11BC; # (꾱; 꾱; 꾱; 꾱; 꾱; ) HANGUL SYLLABLE GGYONG +AFB2;AFB2;1101 116D 11BD;AFB2;1101 116D 11BD; # (꾲; 꾲; 꾲; 꾲; 꾲; ) HANGUL SYLLABLE GGYOJ +AFB3;AFB3;1101 116D 11BE;AFB3;1101 116D 11BE; # (꾳; 꾳; 꾳; 꾳; 꾳; ) HANGUL SYLLABLE GGYOC +AFB4;AFB4;1101 116D 11BF;AFB4;1101 116D 11BF; # (꾴; 꾴; 꾴; 꾴; 꾴; ) HANGUL SYLLABLE GGYOK +AFB5;AFB5;1101 116D 11C0;AFB5;1101 116D 11C0; # (꾵; 꾵; 꾵; 꾵; 꾵; ) HANGUL SYLLABLE GGYOT +AFB6;AFB6;1101 116D 11C1;AFB6;1101 116D 11C1; # (꾶; 꾶; 꾶; 꾶; 꾶; ) HANGUL SYLLABLE GGYOP +AFB7;AFB7;1101 116D 11C2;AFB7;1101 116D 11C2; # (꾷; 꾷; 꾷; 꾷; 꾷; ) HANGUL SYLLABLE GGYOH +AFB8;AFB8;1101 116E;AFB8;1101 116E; # (꾸; 꾸; 꾸; 꾸; 꾸; ) HANGUL SYLLABLE GGU +AFB9;AFB9;1101 116E 11A8;AFB9;1101 116E 11A8; # (꾹; 꾹; 꾹; 꾹; 꾹; ) HANGUL SYLLABLE GGUG +AFBA;AFBA;1101 116E 11A9;AFBA;1101 116E 11A9; # (꾺; 꾺; 꾺; 꾺; 꾺; ) HANGUL SYLLABLE GGUGG +AFBB;AFBB;1101 116E 11AA;AFBB;1101 116E 11AA; # (꾻; 꾻; 꾻; 꾻; 꾻; ) HANGUL SYLLABLE GGUGS +AFBC;AFBC;1101 116E 11AB;AFBC;1101 116E 11AB; # (꾼; 꾼; 꾼; 꾼; 꾼; ) HANGUL SYLLABLE GGUN +AFBD;AFBD;1101 116E 11AC;AFBD;1101 116E 11AC; # (꾽; 꾽; 꾽; 꾽; 꾽; ) HANGUL SYLLABLE GGUNJ +AFBE;AFBE;1101 116E 11AD;AFBE;1101 116E 11AD; # (꾾; 꾾; 꾾; 꾾; 꾾; ) HANGUL SYLLABLE GGUNH +AFBF;AFBF;1101 116E 11AE;AFBF;1101 116E 11AE; # (꾿; 꾿; 꾿; 꾿; 꾿; ) HANGUL SYLLABLE GGUD +AFC0;AFC0;1101 116E 11AF;AFC0;1101 116E 11AF; # (꿀; 꿀; 꿀; 꿀; 꿀; ) HANGUL SYLLABLE GGUL +AFC1;AFC1;1101 116E 11B0;AFC1;1101 116E 11B0; # (꿁; 꿁; 꿁; 꿁; 꿁; ) HANGUL SYLLABLE GGULG +AFC2;AFC2;1101 116E 11B1;AFC2;1101 116E 11B1; # (꿂; 꿂; 꿂; 꿂; 꿂; ) HANGUL SYLLABLE GGULM +AFC3;AFC3;1101 116E 11B2;AFC3;1101 116E 11B2; # (꿃; 꿃; 꿃; 꿃; 꿃; ) HANGUL SYLLABLE GGULB +AFC4;AFC4;1101 116E 11B3;AFC4;1101 116E 11B3; # (꿄; 꿄; 꿄; 꿄; 꿄; ) HANGUL SYLLABLE GGULS +AFC5;AFC5;1101 116E 11B4;AFC5;1101 116E 11B4; # (꿅; 꿅; 꿅; 꿅; 꿅; ) HANGUL SYLLABLE GGULT +AFC6;AFC6;1101 116E 11B5;AFC6;1101 116E 11B5; # (꿆; 꿆; 꿆; 꿆; 꿆; ) HANGUL SYLLABLE GGULP +AFC7;AFC7;1101 116E 11B6;AFC7;1101 116E 11B6; # (꿇; 꿇; 꿇; 꿇; 꿇; ) HANGUL SYLLABLE GGULH +AFC8;AFC8;1101 116E 11B7;AFC8;1101 116E 11B7; # (꿈; 꿈; 꿈; 꿈; 꿈; ) HANGUL SYLLABLE GGUM +AFC9;AFC9;1101 116E 11B8;AFC9;1101 116E 11B8; # (꿉; 꿉; 꿉; 꿉; 꿉; ) HANGUL SYLLABLE GGUB +AFCA;AFCA;1101 116E 11B9;AFCA;1101 116E 11B9; # (꿊; 꿊; 꿊; 꿊; 꿊; ) HANGUL SYLLABLE GGUBS +AFCB;AFCB;1101 116E 11BA;AFCB;1101 116E 11BA; # (꿋; 꿋; 꿋; 꿋; 꿋; ) HANGUL SYLLABLE GGUS +AFCC;AFCC;1101 116E 11BB;AFCC;1101 116E 11BB; # (꿌; 꿌; 꿌; 꿌; 꿌; ) HANGUL SYLLABLE GGUSS +AFCD;AFCD;1101 116E 11BC;AFCD;1101 116E 11BC; # (꿍; 꿍; 꿍; 꿍; 꿍; ) HANGUL SYLLABLE GGUNG +AFCE;AFCE;1101 116E 11BD;AFCE;1101 116E 11BD; # (꿎; 꿎; 꿎; 꿎; 꿎; ) HANGUL SYLLABLE GGUJ +AFCF;AFCF;1101 116E 11BE;AFCF;1101 116E 11BE; # (꿏; 꿏; 꿏; 꿏; 꿏; ) HANGUL SYLLABLE GGUC +AFD0;AFD0;1101 116E 11BF;AFD0;1101 116E 11BF; # (꿐; 꿐; 꿐; 꿐; 꿐; ) HANGUL SYLLABLE GGUK +AFD1;AFD1;1101 116E 11C0;AFD1;1101 116E 11C0; # (꿑; 꿑; 꿑; 꿑; 꿑; ) HANGUL SYLLABLE GGUT +AFD2;AFD2;1101 116E 11C1;AFD2;1101 116E 11C1; # (꿒; 꿒; 꿒; 꿒; 꿒; ) HANGUL SYLLABLE GGUP +AFD3;AFD3;1101 116E 11C2;AFD3;1101 116E 11C2; # (꿓; 꿓; 꿓; 꿓; 꿓; ) HANGUL SYLLABLE GGUH +AFD4;AFD4;1101 116F;AFD4;1101 116F; # (꿔; 꿔; 꿔; 꿔; 꿔; ) HANGUL SYLLABLE GGWEO +AFD5;AFD5;1101 116F 11A8;AFD5;1101 116F 11A8; # (꿕; 꿕; 꿕; 꿕; 꿕; ) HANGUL SYLLABLE GGWEOG +AFD6;AFD6;1101 116F 11A9;AFD6;1101 116F 11A9; # (꿖; 꿖; 꿖; 꿖; 꿖; ) HANGUL SYLLABLE GGWEOGG +AFD7;AFD7;1101 116F 11AA;AFD7;1101 116F 11AA; # (꿗; 꿗; 꿗; 꿗; 꿗; ) HANGUL SYLLABLE GGWEOGS +AFD8;AFD8;1101 116F 11AB;AFD8;1101 116F 11AB; # (꿘; 꿘; 꿘; 꿘; 꿘; ) HANGUL SYLLABLE GGWEON +AFD9;AFD9;1101 116F 11AC;AFD9;1101 116F 11AC; # (꿙; 꿙; 꿙; 꿙; 꿙; ) HANGUL SYLLABLE GGWEONJ +AFDA;AFDA;1101 116F 11AD;AFDA;1101 116F 11AD; # (꿚; 꿚; 꿚; 꿚; 꿚; ) HANGUL SYLLABLE GGWEONH +AFDB;AFDB;1101 116F 11AE;AFDB;1101 116F 11AE; # (꿛; 꿛; 꿛; 꿛; 꿛; ) HANGUL SYLLABLE GGWEOD +AFDC;AFDC;1101 116F 11AF;AFDC;1101 116F 11AF; # (꿜; 꿜; 꿜; 꿜; 꿜; ) HANGUL SYLLABLE GGWEOL +AFDD;AFDD;1101 116F 11B0;AFDD;1101 116F 11B0; # (꿝; 꿝; 꿝; 꿝; 꿝; ) HANGUL SYLLABLE GGWEOLG +AFDE;AFDE;1101 116F 11B1;AFDE;1101 116F 11B1; # (꿞; 꿞; 꿞; 꿞; 꿞; ) HANGUL SYLLABLE GGWEOLM +AFDF;AFDF;1101 116F 11B2;AFDF;1101 116F 11B2; # (꿟; 꿟; 꿟; 꿟; 꿟; ) HANGUL SYLLABLE GGWEOLB +AFE0;AFE0;1101 116F 11B3;AFE0;1101 116F 11B3; # (꿠; 꿠; 꿠; 꿠; 꿠; ) HANGUL SYLLABLE GGWEOLS +AFE1;AFE1;1101 116F 11B4;AFE1;1101 116F 11B4; # (꿡; 꿡; 꿡; 꿡; 꿡; ) HANGUL SYLLABLE GGWEOLT +AFE2;AFE2;1101 116F 11B5;AFE2;1101 116F 11B5; # (꿢; 꿢; 꿢; 꿢; 꿢; ) HANGUL SYLLABLE GGWEOLP +AFE3;AFE3;1101 116F 11B6;AFE3;1101 116F 11B6; # (꿣; 꿣; 꿣; 꿣; 꿣; ) HANGUL SYLLABLE GGWEOLH +AFE4;AFE4;1101 116F 11B7;AFE4;1101 116F 11B7; # (꿤; 꿤; 꿤; 꿤; 꿤; ) HANGUL SYLLABLE GGWEOM +AFE5;AFE5;1101 116F 11B8;AFE5;1101 116F 11B8; # (꿥; 꿥; 꿥; 꿥; 꿥; ) HANGUL SYLLABLE GGWEOB +AFE6;AFE6;1101 116F 11B9;AFE6;1101 116F 11B9; # (꿦; 꿦; 꿦; 꿦; 꿦; ) HANGUL SYLLABLE GGWEOBS +AFE7;AFE7;1101 116F 11BA;AFE7;1101 116F 11BA; # (꿧; 꿧; 꿧; 꿧; 꿧; ) HANGUL SYLLABLE GGWEOS +AFE8;AFE8;1101 116F 11BB;AFE8;1101 116F 11BB; # (꿨; 꿨; 꿨; 꿨; 꿨; ) HANGUL SYLLABLE GGWEOSS +AFE9;AFE9;1101 116F 11BC;AFE9;1101 116F 11BC; # (꿩; 꿩; 꿩; 꿩; 꿩; ) HANGUL SYLLABLE GGWEONG +AFEA;AFEA;1101 116F 11BD;AFEA;1101 116F 11BD; # (꿪; 꿪; 꿪; 꿪; 꿪; ) HANGUL SYLLABLE GGWEOJ +AFEB;AFEB;1101 116F 11BE;AFEB;1101 116F 11BE; # (꿫; 꿫; 꿫; 꿫; 꿫; ) HANGUL SYLLABLE GGWEOC +AFEC;AFEC;1101 116F 11BF;AFEC;1101 116F 11BF; # (꿬; 꿬; 꿬; 꿬; 꿬; ) HANGUL SYLLABLE GGWEOK +AFED;AFED;1101 116F 11C0;AFED;1101 116F 11C0; # (꿭; 꿭; 꿭; 꿭; 꿭; ) HANGUL SYLLABLE GGWEOT +AFEE;AFEE;1101 116F 11C1;AFEE;1101 116F 11C1; # (꿮; 꿮; 꿮; 꿮; 꿮; ) HANGUL SYLLABLE GGWEOP +AFEF;AFEF;1101 116F 11C2;AFEF;1101 116F 11C2; # (꿯; 꿯; 꿯; 꿯; 꿯; ) HANGUL SYLLABLE GGWEOH +AFF0;AFF0;1101 1170;AFF0;1101 1170; # (꿰; 꿰; 꿰; 꿰; 꿰; ) HANGUL SYLLABLE GGWE +AFF1;AFF1;1101 1170 11A8;AFF1;1101 1170 11A8; # (꿱; 꿱; 꿱; 꿱; 꿱; ) HANGUL SYLLABLE GGWEG +AFF2;AFF2;1101 1170 11A9;AFF2;1101 1170 11A9; # (꿲; 꿲; 꿲; 꿲; 꿲; ) HANGUL SYLLABLE GGWEGG +AFF3;AFF3;1101 1170 11AA;AFF3;1101 1170 11AA; # (꿳; 꿳; 꿳; 꿳; 꿳; ) HANGUL SYLLABLE GGWEGS +AFF4;AFF4;1101 1170 11AB;AFF4;1101 1170 11AB; # (꿴; 꿴; 꿴; 꿴; 꿴; ) HANGUL SYLLABLE GGWEN +AFF5;AFF5;1101 1170 11AC;AFF5;1101 1170 11AC; # (꿵; 꿵; 꿵; 꿵; 꿵; ) HANGUL SYLLABLE GGWENJ +AFF6;AFF6;1101 1170 11AD;AFF6;1101 1170 11AD; # (꿶; 꿶; 꿶; 꿶; 꿶; ) HANGUL SYLLABLE GGWENH +AFF7;AFF7;1101 1170 11AE;AFF7;1101 1170 11AE; # (꿷; 꿷; 꿷; 꿷; 꿷; ) HANGUL SYLLABLE GGWED +AFF8;AFF8;1101 1170 11AF;AFF8;1101 1170 11AF; # (꿸; 꿸; 꿸; 꿸; 꿸; ) HANGUL SYLLABLE GGWEL +AFF9;AFF9;1101 1170 11B0;AFF9;1101 1170 11B0; # (꿹; 꿹; 꿹; 꿹; 꿹; ) HANGUL SYLLABLE GGWELG +AFFA;AFFA;1101 1170 11B1;AFFA;1101 1170 11B1; # (꿺; 꿺; 꿺; 꿺; 꿺; ) HANGUL SYLLABLE GGWELM +AFFB;AFFB;1101 1170 11B2;AFFB;1101 1170 11B2; # (꿻; 꿻; 꿻; 꿻; 꿻; ) HANGUL SYLLABLE GGWELB +AFFC;AFFC;1101 1170 11B3;AFFC;1101 1170 11B3; # (꿼; 꿼; 꿼; 꿼; 꿼; ) HANGUL SYLLABLE GGWELS +AFFD;AFFD;1101 1170 11B4;AFFD;1101 1170 11B4; # (꿽; 꿽; 꿽; 꿽; 꿽; ) HANGUL SYLLABLE GGWELT +AFFE;AFFE;1101 1170 11B5;AFFE;1101 1170 11B5; # (꿾; 꿾; 꿾; 꿾; 꿾; ) HANGUL SYLLABLE GGWELP +AFFF;AFFF;1101 1170 11B6;AFFF;1101 1170 11B6; # (꿿; 꿿; 꿿; 꿿; 꿿; ) HANGUL SYLLABLE GGWELH +B000;B000;1101 1170 11B7;B000;1101 1170 11B7; # (뀀; 뀀; 뀀; 뀀; 뀀; ) HANGUL SYLLABLE GGWEM +B001;B001;1101 1170 11B8;B001;1101 1170 11B8; # (뀁; 뀁; 뀁; 뀁; 뀁; ) HANGUL SYLLABLE GGWEB +B002;B002;1101 1170 11B9;B002;1101 1170 11B9; # (뀂; 뀂; 뀂; 뀂; 뀂; ) HANGUL SYLLABLE GGWEBS +B003;B003;1101 1170 11BA;B003;1101 1170 11BA; # (뀃; 뀃; 뀃; 뀃; 뀃; ) HANGUL SYLLABLE GGWES +B004;B004;1101 1170 11BB;B004;1101 1170 11BB; # (뀄; 뀄; 뀄; 뀄; 뀄; ) HANGUL SYLLABLE GGWESS +B005;B005;1101 1170 11BC;B005;1101 1170 11BC; # (뀅; 뀅; 뀅; 뀅; 뀅; ) HANGUL SYLLABLE GGWENG +B006;B006;1101 1170 11BD;B006;1101 1170 11BD; # (뀆; 뀆; 뀆; 뀆; 뀆; ) HANGUL SYLLABLE GGWEJ +B007;B007;1101 1170 11BE;B007;1101 1170 11BE; # (뀇; 뀇; 뀇; 뀇; 뀇; ) HANGUL SYLLABLE GGWEC +B008;B008;1101 1170 11BF;B008;1101 1170 11BF; # (뀈; 뀈; 뀈; 뀈; 뀈; ) HANGUL SYLLABLE GGWEK +B009;B009;1101 1170 11C0;B009;1101 1170 11C0; # (뀉; 뀉; 뀉; 뀉; 뀉; ) HANGUL SYLLABLE GGWET +B00A;B00A;1101 1170 11C1;B00A;1101 1170 11C1; # (뀊; 뀊; 뀊; 뀊; 뀊; ) HANGUL SYLLABLE GGWEP +B00B;B00B;1101 1170 11C2;B00B;1101 1170 11C2; # (뀋; 뀋; 뀋; 뀋; 뀋; ) HANGUL SYLLABLE GGWEH +B00C;B00C;1101 1171;B00C;1101 1171; # (뀌; 뀌; 뀌; 뀌; 뀌; ) HANGUL SYLLABLE GGWI +B00D;B00D;1101 1171 11A8;B00D;1101 1171 11A8; # (뀍; 뀍; 뀍; 뀍; 뀍; ) HANGUL SYLLABLE GGWIG +B00E;B00E;1101 1171 11A9;B00E;1101 1171 11A9; # (뀎; 뀎; 뀎; 뀎; 뀎; ) HANGUL SYLLABLE GGWIGG +B00F;B00F;1101 1171 11AA;B00F;1101 1171 11AA; # (뀏; 뀏; 뀏; 뀏; 뀏; ) HANGUL SYLLABLE GGWIGS +B010;B010;1101 1171 11AB;B010;1101 1171 11AB; # (뀐; 뀐; 뀐; 뀐; 뀐; ) HANGUL SYLLABLE GGWIN +B011;B011;1101 1171 11AC;B011;1101 1171 11AC; # (뀑; 뀑; 뀑; 뀑; 뀑; ) HANGUL SYLLABLE GGWINJ +B012;B012;1101 1171 11AD;B012;1101 1171 11AD; # (뀒; 뀒; 뀒; 뀒; 뀒; ) HANGUL SYLLABLE GGWINH +B013;B013;1101 1171 11AE;B013;1101 1171 11AE; # (뀓; 뀓; 뀓; 뀓; 뀓; ) HANGUL SYLLABLE GGWID +B014;B014;1101 1171 11AF;B014;1101 1171 11AF; # (뀔; 뀔; 뀔; 뀔; 뀔; ) HANGUL SYLLABLE GGWIL +B015;B015;1101 1171 11B0;B015;1101 1171 11B0; # (뀕; 뀕; 뀕; 뀕; 뀕; ) HANGUL SYLLABLE GGWILG +B016;B016;1101 1171 11B1;B016;1101 1171 11B1; # (뀖; 뀖; 뀖; 뀖; 뀖; ) HANGUL SYLLABLE GGWILM +B017;B017;1101 1171 11B2;B017;1101 1171 11B2; # (뀗; 뀗; 뀗; 뀗; 뀗; ) HANGUL SYLLABLE GGWILB +B018;B018;1101 1171 11B3;B018;1101 1171 11B3; # (뀘; 뀘; 뀘; 뀘; 뀘; ) HANGUL SYLLABLE GGWILS +B019;B019;1101 1171 11B4;B019;1101 1171 11B4; # (뀙; 뀙; 뀙; 뀙; 뀙; ) HANGUL SYLLABLE GGWILT +B01A;B01A;1101 1171 11B5;B01A;1101 1171 11B5; # (뀚; 뀚; 뀚; 뀚; 뀚; ) HANGUL SYLLABLE GGWILP +B01B;B01B;1101 1171 11B6;B01B;1101 1171 11B6; # (뀛; 뀛; 뀛; 뀛; 뀛; ) HANGUL SYLLABLE GGWILH +B01C;B01C;1101 1171 11B7;B01C;1101 1171 11B7; # (뀜; 뀜; 뀜; 뀜; 뀜; ) HANGUL SYLLABLE GGWIM +B01D;B01D;1101 1171 11B8;B01D;1101 1171 11B8; # (뀝; 뀝; 뀝; 뀝; 뀝; ) HANGUL SYLLABLE GGWIB +B01E;B01E;1101 1171 11B9;B01E;1101 1171 11B9; # (뀞; 뀞; 뀞; 뀞; 뀞; ) HANGUL SYLLABLE GGWIBS +B01F;B01F;1101 1171 11BA;B01F;1101 1171 11BA; # (뀟; 뀟; 뀟; 뀟; 뀟; ) HANGUL SYLLABLE GGWIS +B020;B020;1101 1171 11BB;B020;1101 1171 11BB; # (뀠; 뀠; 뀠; 뀠; 뀠; ) HANGUL SYLLABLE GGWISS +B021;B021;1101 1171 11BC;B021;1101 1171 11BC; # (뀡; 뀡; 뀡; 뀡; 뀡; ) HANGUL SYLLABLE GGWING +B022;B022;1101 1171 11BD;B022;1101 1171 11BD; # (뀢; 뀢; 뀢; 뀢; 뀢; ) HANGUL SYLLABLE GGWIJ +B023;B023;1101 1171 11BE;B023;1101 1171 11BE; # (뀣; 뀣; 뀣; 뀣; 뀣; ) HANGUL SYLLABLE GGWIC +B024;B024;1101 1171 11BF;B024;1101 1171 11BF; # (뀤; 뀤; 뀤; 뀤; 뀤; ) HANGUL SYLLABLE GGWIK +B025;B025;1101 1171 11C0;B025;1101 1171 11C0; # (뀥; 뀥; 뀥; 뀥; 뀥; ) HANGUL SYLLABLE GGWIT +B026;B026;1101 1171 11C1;B026;1101 1171 11C1; # (뀦; 뀦; 뀦; 뀦; 뀦; ) HANGUL SYLLABLE GGWIP +B027;B027;1101 1171 11C2;B027;1101 1171 11C2; # (뀧; 뀧; 뀧; 뀧; 뀧; ) HANGUL SYLLABLE GGWIH +B028;B028;1101 1172;B028;1101 1172; # (뀨; 뀨; 뀨; 뀨; 뀨; ) HANGUL SYLLABLE GGYU +B029;B029;1101 1172 11A8;B029;1101 1172 11A8; # (뀩; 뀩; 뀩; 뀩; 뀩; ) HANGUL SYLLABLE GGYUG +B02A;B02A;1101 1172 11A9;B02A;1101 1172 11A9; # (뀪; 뀪; 뀪; 뀪; 뀪; ) HANGUL SYLLABLE GGYUGG +B02B;B02B;1101 1172 11AA;B02B;1101 1172 11AA; # (뀫; 뀫; 뀫; 뀫; 뀫; ) HANGUL SYLLABLE GGYUGS +B02C;B02C;1101 1172 11AB;B02C;1101 1172 11AB; # (뀬; 뀬; 뀬; 뀬; 뀬; ) HANGUL SYLLABLE GGYUN +B02D;B02D;1101 1172 11AC;B02D;1101 1172 11AC; # (뀭; 뀭; 뀭; 뀭; 뀭; ) HANGUL SYLLABLE GGYUNJ +B02E;B02E;1101 1172 11AD;B02E;1101 1172 11AD; # (뀮; 뀮; 뀮; 뀮; 뀮; ) HANGUL SYLLABLE GGYUNH +B02F;B02F;1101 1172 11AE;B02F;1101 1172 11AE; # (뀯; 뀯; 뀯; 뀯; 뀯; ) HANGUL SYLLABLE GGYUD +B030;B030;1101 1172 11AF;B030;1101 1172 11AF; # (뀰; 뀰; 뀰; 뀰; 뀰; ) HANGUL SYLLABLE GGYUL +B031;B031;1101 1172 11B0;B031;1101 1172 11B0; # (뀱; 뀱; 뀱; 뀱; 뀱; ) HANGUL SYLLABLE GGYULG +B032;B032;1101 1172 11B1;B032;1101 1172 11B1; # (뀲; 뀲; 뀲; 뀲; 뀲; ) HANGUL SYLLABLE GGYULM +B033;B033;1101 1172 11B2;B033;1101 1172 11B2; # (뀳; 뀳; 뀳; 뀳; 뀳; ) HANGUL SYLLABLE GGYULB +B034;B034;1101 1172 11B3;B034;1101 1172 11B3; # (뀴; 뀴; 뀴; 뀴; 뀴; ) HANGUL SYLLABLE GGYULS +B035;B035;1101 1172 11B4;B035;1101 1172 11B4; # (뀵; 뀵; 뀵; 뀵; 뀵; ) HANGUL SYLLABLE GGYULT +B036;B036;1101 1172 11B5;B036;1101 1172 11B5; # (뀶; 뀶; 뀶; 뀶; 뀶; ) HANGUL SYLLABLE GGYULP +B037;B037;1101 1172 11B6;B037;1101 1172 11B6; # (뀷; 뀷; 뀷; 뀷; 뀷; ) HANGUL SYLLABLE GGYULH +B038;B038;1101 1172 11B7;B038;1101 1172 11B7; # (뀸; 뀸; 뀸; 뀸; 뀸; ) HANGUL SYLLABLE GGYUM +B039;B039;1101 1172 11B8;B039;1101 1172 11B8; # (뀹; 뀹; 뀹; 뀹; 뀹; ) HANGUL SYLLABLE GGYUB +B03A;B03A;1101 1172 11B9;B03A;1101 1172 11B9; # (뀺; 뀺; 뀺; 뀺; 뀺; ) HANGUL SYLLABLE GGYUBS +B03B;B03B;1101 1172 11BA;B03B;1101 1172 11BA; # (뀻; 뀻; 뀻; 뀻; 뀻; ) HANGUL SYLLABLE GGYUS +B03C;B03C;1101 1172 11BB;B03C;1101 1172 11BB; # (뀼; 뀼; 뀼; 뀼; 뀼; ) HANGUL SYLLABLE GGYUSS +B03D;B03D;1101 1172 11BC;B03D;1101 1172 11BC; # (뀽; 뀽; 뀽; 뀽; 뀽; ) HANGUL SYLLABLE GGYUNG +B03E;B03E;1101 1172 11BD;B03E;1101 1172 11BD; # (뀾; 뀾; 뀾; 뀾; 뀾; ) HANGUL SYLLABLE GGYUJ +B03F;B03F;1101 1172 11BE;B03F;1101 1172 11BE; # (뀿; 뀿; 뀿; 뀿; 뀿; ) HANGUL SYLLABLE GGYUC +B040;B040;1101 1172 11BF;B040;1101 1172 11BF; # (끀; 끀; 끀; 끀; 끀; ) HANGUL SYLLABLE GGYUK +B041;B041;1101 1172 11C0;B041;1101 1172 11C0; # (끁; 끁; 끁; 끁; 끁; ) HANGUL SYLLABLE GGYUT +B042;B042;1101 1172 11C1;B042;1101 1172 11C1; # (끂; 끂; 끂; 끂; 끂; ) HANGUL SYLLABLE GGYUP +B043;B043;1101 1172 11C2;B043;1101 1172 11C2; # (끃; 끃; 끃; 끃; 끃; ) HANGUL SYLLABLE GGYUH +B044;B044;1101 1173;B044;1101 1173; # (끄; 끄; 끄; 끄; 끄; ) HANGUL SYLLABLE GGEU +B045;B045;1101 1173 11A8;B045;1101 1173 11A8; # (끅; 끅; 끅; 끅; 끅; ) HANGUL SYLLABLE GGEUG +B046;B046;1101 1173 11A9;B046;1101 1173 11A9; # (끆; 끆; 끆; 끆; 끆; ) HANGUL SYLLABLE GGEUGG +B047;B047;1101 1173 11AA;B047;1101 1173 11AA; # (끇; 끇; 끇; 끇; 끇; ) HANGUL SYLLABLE GGEUGS +B048;B048;1101 1173 11AB;B048;1101 1173 11AB; # (끈; 끈; 끈; 끈; 끈; ) HANGUL SYLLABLE GGEUN +B049;B049;1101 1173 11AC;B049;1101 1173 11AC; # (끉; 끉; 끉; 끉; 끉; ) HANGUL SYLLABLE GGEUNJ +B04A;B04A;1101 1173 11AD;B04A;1101 1173 11AD; # (끊; 끊; 끊; 끊; 끊; ) HANGUL SYLLABLE GGEUNH +B04B;B04B;1101 1173 11AE;B04B;1101 1173 11AE; # (끋; 끋; 끋; 끋; 끋; ) HANGUL SYLLABLE GGEUD +B04C;B04C;1101 1173 11AF;B04C;1101 1173 11AF; # (끌; 끌; 끌; 끌; 끌; ) HANGUL SYLLABLE GGEUL +B04D;B04D;1101 1173 11B0;B04D;1101 1173 11B0; # (끍; 끍; 끍; 끍; 끍; ) HANGUL SYLLABLE GGEULG +B04E;B04E;1101 1173 11B1;B04E;1101 1173 11B1; # (끎; 끎; 끎; 끎; 끎; ) HANGUL SYLLABLE GGEULM +B04F;B04F;1101 1173 11B2;B04F;1101 1173 11B2; # (끏; 끏; 끏; 끏; 끏; ) HANGUL SYLLABLE GGEULB +B050;B050;1101 1173 11B3;B050;1101 1173 11B3; # (끐; 끐; 끐; 끐; 끐; ) HANGUL SYLLABLE GGEULS +B051;B051;1101 1173 11B4;B051;1101 1173 11B4; # (끑; 끑; 끑; 끑; 끑; ) HANGUL SYLLABLE GGEULT +B052;B052;1101 1173 11B5;B052;1101 1173 11B5; # (끒; 끒; 끒; 끒; 끒; ) HANGUL SYLLABLE GGEULP +B053;B053;1101 1173 11B6;B053;1101 1173 11B6; # (끓; 끓; 끓; 끓; 끓; ) HANGUL SYLLABLE GGEULH +B054;B054;1101 1173 11B7;B054;1101 1173 11B7; # (끔; 끔; 끔; 끔; 끔; ) HANGUL SYLLABLE GGEUM +B055;B055;1101 1173 11B8;B055;1101 1173 11B8; # (끕; 끕; 끕; 끕; 끕; ) HANGUL SYLLABLE GGEUB +B056;B056;1101 1173 11B9;B056;1101 1173 11B9; # (끖; 끖; 끖; 끖; 끖; ) HANGUL SYLLABLE GGEUBS +B057;B057;1101 1173 11BA;B057;1101 1173 11BA; # (끗; 끗; 끗; 끗; 끗; ) HANGUL SYLLABLE GGEUS +B058;B058;1101 1173 11BB;B058;1101 1173 11BB; # (끘; 끘; 끘; 끘; 끘; ) HANGUL SYLLABLE GGEUSS +B059;B059;1101 1173 11BC;B059;1101 1173 11BC; # (끙; 끙; 끙; 끙; 끙; ) HANGUL SYLLABLE GGEUNG +B05A;B05A;1101 1173 11BD;B05A;1101 1173 11BD; # (끚; 끚; 끚; 끚; 끚; ) HANGUL SYLLABLE GGEUJ +B05B;B05B;1101 1173 11BE;B05B;1101 1173 11BE; # (끛; 끛; 끛; 끛; 끛; ) HANGUL SYLLABLE GGEUC +B05C;B05C;1101 1173 11BF;B05C;1101 1173 11BF; # (끜; 끜; 끜; 끜; 끜; ) HANGUL SYLLABLE GGEUK +B05D;B05D;1101 1173 11C0;B05D;1101 1173 11C0; # (끝; 끝; 끝; 끝; 끝; ) HANGUL SYLLABLE GGEUT +B05E;B05E;1101 1173 11C1;B05E;1101 1173 11C1; # (끞; 끞; 끞; 끞; 끞; ) HANGUL SYLLABLE GGEUP +B05F;B05F;1101 1173 11C2;B05F;1101 1173 11C2; # (끟; 끟; 끟; 끟; 끟; ) HANGUL SYLLABLE GGEUH +B060;B060;1101 1174;B060;1101 1174; # (끠; 끠; 끠; 끠; 끠; ) HANGUL SYLLABLE GGYI +B061;B061;1101 1174 11A8;B061;1101 1174 11A8; # (끡; 끡; 끡; 끡; 끡; ) HANGUL SYLLABLE GGYIG +B062;B062;1101 1174 11A9;B062;1101 1174 11A9; # (끢; 끢; 끢; 끢; 끢; ) HANGUL SYLLABLE GGYIGG +B063;B063;1101 1174 11AA;B063;1101 1174 11AA; # (끣; 끣; 끣; 끣; 끣; ) HANGUL SYLLABLE GGYIGS +B064;B064;1101 1174 11AB;B064;1101 1174 11AB; # (끤; 끤; 끤; 끤; 끤; ) HANGUL SYLLABLE GGYIN +B065;B065;1101 1174 11AC;B065;1101 1174 11AC; # (끥; 끥; 끥; 끥; 끥; ) HANGUL SYLLABLE GGYINJ +B066;B066;1101 1174 11AD;B066;1101 1174 11AD; # (끦; 끦; 끦; 끦; 끦; ) HANGUL SYLLABLE GGYINH +B067;B067;1101 1174 11AE;B067;1101 1174 11AE; # (끧; 끧; 끧; 끧; 끧; ) HANGUL SYLLABLE GGYID +B068;B068;1101 1174 11AF;B068;1101 1174 11AF; # (끨; 끨; 끨; 끨; 끨; ) HANGUL SYLLABLE GGYIL +B069;B069;1101 1174 11B0;B069;1101 1174 11B0; # (끩; 끩; 끩; 끩; 끩; ) HANGUL SYLLABLE GGYILG +B06A;B06A;1101 1174 11B1;B06A;1101 1174 11B1; # (끪; 끪; 끪; 끪; 끪; ) HANGUL SYLLABLE GGYILM +B06B;B06B;1101 1174 11B2;B06B;1101 1174 11B2; # (끫; 끫; 끫; 끫; 끫; ) HANGUL SYLLABLE GGYILB +B06C;B06C;1101 1174 11B3;B06C;1101 1174 11B3; # (끬; 끬; 끬; 끬; 끬; ) HANGUL SYLLABLE GGYILS +B06D;B06D;1101 1174 11B4;B06D;1101 1174 11B4; # (끭; 끭; 끭; 끭; 끭; ) HANGUL SYLLABLE GGYILT +B06E;B06E;1101 1174 11B5;B06E;1101 1174 11B5; # (끮; 끮; 끮; 끮; 끮; ) HANGUL SYLLABLE GGYILP +B06F;B06F;1101 1174 11B6;B06F;1101 1174 11B6; # (끯; 끯; 끯; 끯; 끯; ) HANGUL SYLLABLE GGYILH +B070;B070;1101 1174 11B7;B070;1101 1174 11B7; # (끰; 끰; 끰; 끰; 끰; ) HANGUL SYLLABLE GGYIM +B071;B071;1101 1174 11B8;B071;1101 1174 11B8; # (끱; 끱; 끱; 끱; 끱; ) HANGUL SYLLABLE GGYIB +B072;B072;1101 1174 11B9;B072;1101 1174 11B9; # (끲; 끲; 끲; 끲; 끲; ) HANGUL SYLLABLE GGYIBS +B073;B073;1101 1174 11BA;B073;1101 1174 11BA; # (끳; 끳; 끳; 끳; 끳; ) HANGUL SYLLABLE GGYIS +B074;B074;1101 1174 11BB;B074;1101 1174 11BB; # (끴; 끴; 끴; 끴; 끴; ) HANGUL SYLLABLE GGYISS +B075;B075;1101 1174 11BC;B075;1101 1174 11BC; # (끵; 끵; 끵; 끵; 끵; ) HANGUL SYLLABLE GGYING +B076;B076;1101 1174 11BD;B076;1101 1174 11BD; # (끶; 끶; 끶; 끶; 끶; ) HANGUL SYLLABLE GGYIJ +B077;B077;1101 1174 11BE;B077;1101 1174 11BE; # (끷; 끷; 끷; 끷; 끷; ) HANGUL SYLLABLE GGYIC +B078;B078;1101 1174 11BF;B078;1101 1174 11BF; # (끸; 끸; 끸; 끸; 끸; ) HANGUL SYLLABLE GGYIK +B079;B079;1101 1174 11C0;B079;1101 1174 11C0; # (끹; 끹; 끹; 끹; 끹; ) HANGUL SYLLABLE GGYIT +B07A;B07A;1101 1174 11C1;B07A;1101 1174 11C1; # (끺; 끺; 끺; 끺; 끺; ) HANGUL SYLLABLE GGYIP +B07B;B07B;1101 1174 11C2;B07B;1101 1174 11C2; # (끻; 끻; 끻; 끻; 끻; ) HANGUL SYLLABLE GGYIH +B07C;B07C;1101 1175;B07C;1101 1175; # (끼; 끼; 끼; 끼; 끼; ) HANGUL SYLLABLE GGI +B07D;B07D;1101 1175 11A8;B07D;1101 1175 11A8; # (끽; 끽; 끽; 끽; 끽; ) HANGUL SYLLABLE GGIG +B07E;B07E;1101 1175 11A9;B07E;1101 1175 11A9; # (끾; 끾; 끾; 끾; 끾; ) HANGUL SYLLABLE GGIGG +B07F;B07F;1101 1175 11AA;B07F;1101 1175 11AA; # (끿; 끿; 끿; 끿; 끿; ) HANGUL SYLLABLE GGIGS +B080;B080;1101 1175 11AB;B080;1101 1175 11AB; # (낀; 낀; 낀; 낀; 낀; ) HANGUL SYLLABLE GGIN +B081;B081;1101 1175 11AC;B081;1101 1175 11AC; # (낁; 낁; 낁; 낁; 낁; ) HANGUL SYLLABLE GGINJ +B082;B082;1101 1175 11AD;B082;1101 1175 11AD; # (낂; 낂; 낂; 낂; 낂; ) HANGUL SYLLABLE GGINH +B083;B083;1101 1175 11AE;B083;1101 1175 11AE; # (낃; 낃; 낃; 낃; 낃; ) HANGUL SYLLABLE GGID +B084;B084;1101 1175 11AF;B084;1101 1175 11AF; # (낄; 낄; 낄; 낄; 낄; ) HANGUL SYLLABLE GGIL +B085;B085;1101 1175 11B0;B085;1101 1175 11B0; # (낅; 낅; 낅; 낅; 낅; ) HANGUL SYLLABLE GGILG +B086;B086;1101 1175 11B1;B086;1101 1175 11B1; # (낆; 낆; 낆; 낆; 낆; ) HANGUL SYLLABLE GGILM +B087;B087;1101 1175 11B2;B087;1101 1175 11B2; # (낇; 낇; 낇; 낇; 낇; ) HANGUL SYLLABLE GGILB +B088;B088;1101 1175 11B3;B088;1101 1175 11B3; # (낈; 낈; 낈; 낈; 낈; ) HANGUL SYLLABLE GGILS +B089;B089;1101 1175 11B4;B089;1101 1175 11B4; # (낉; 낉; 낉; 낉; 낉; ) HANGUL SYLLABLE GGILT +B08A;B08A;1101 1175 11B5;B08A;1101 1175 11B5; # (낊; 낊; 낊; 낊; 낊; ) HANGUL SYLLABLE GGILP +B08B;B08B;1101 1175 11B6;B08B;1101 1175 11B6; # (낋; 낋; 낋; 낋; 낋; ) HANGUL SYLLABLE GGILH +B08C;B08C;1101 1175 11B7;B08C;1101 1175 11B7; # (낌; 낌; 낌; 낌; 낌; ) HANGUL SYLLABLE GGIM +B08D;B08D;1101 1175 11B8;B08D;1101 1175 11B8; # (낍; 낍; 낍; 낍; 낍; ) HANGUL SYLLABLE GGIB +B08E;B08E;1101 1175 11B9;B08E;1101 1175 11B9; # (낎; 낎; 낎; 낎; 낎; ) HANGUL SYLLABLE GGIBS +B08F;B08F;1101 1175 11BA;B08F;1101 1175 11BA; # (낏; 낏; 낏; 낏; 낏; ) HANGUL SYLLABLE GGIS +B090;B090;1101 1175 11BB;B090;1101 1175 11BB; # (낐; 낐; 낐; 낐; 낐; ) HANGUL SYLLABLE GGISS +B091;B091;1101 1175 11BC;B091;1101 1175 11BC; # (낑; 낑; 낑; 낑; 낑; ) HANGUL SYLLABLE GGING +B092;B092;1101 1175 11BD;B092;1101 1175 11BD; # (낒; 낒; 낒; 낒; 낒; ) HANGUL SYLLABLE GGIJ +B093;B093;1101 1175 11BE;B093;1101 1175 11BE; # (낓; 낓; 낓; 낓; 낓; ) HANGUL SYLLABLE GGIC +B094;B094;1101 1175 11BF;B094;1101 1175 11BF; # (낔; 낔; 낔; 낔; 낔; ) HANGUL SYLLABLE GGIK +B095;B095;1101 1175 11C0;B095;1101 1175 11C0; # (낕; 낕; 낕; 낕; 낕; ) HANGUL SYLLABLE GGIT +B096;B096;1101 1175 11C1;B096;1101 1175 11C1; # (낖; 낖; 낖; 낖; 낖; ) HANGUL SYLLABLE GGIP +B097;B097;1101 1175 11C2;B097;1101 1175 11C2; # (낗; 낗; 낗; 낗; 낗; ) HANGUL SYLLABLE GGIH +B098;B098;1102 1161;B098;1102 1161; # (나; 나; 나; 나; 나; ) HANGUL SYLLABLE NA +B099;B099;1102 1161 11A8;B099;1102 1161 11A8; # (낙; 낙; 낙; 낙; 낙; ) HANGUL SYLLABLE NAG +B09A;B09A;1102 1161 11A9;B09A;1102 1161 11A9; # (낚; 낚; 낚; 낚; 낚; ) HANGUL SYLLABLE NAGG +B09B;B09B;1102 1161 11AA;B09B;1102 1161 11AA; # (낛; 낛; 낛; 낛; 낛; ) HANGUL SYLLABLE NAGS +B09C;B09C;1102 1161 11AB;B09C;1102 1161 11AB; # (난; 난; 난; 난; 난; ) HANGUL SYLLABLE NAN +B09D;B09D;1102 1161 11AC;B09D;1102 1161 11AC; # (낝; 낝; 낝; 낝; 낝; ) HANGUL SYLLABLE NANJ +B09E;B09E;1102 1161 11AD;B09E;1102 1161 11AD; # (낞; 낞; 낞; 낞; 낞; ) HANGUL SYLLABLE NANH +B09F;B09F;1102 1161 11AE;B09F;1102 1161 11AE; # (낟; 낟; 낟; 낟; 낟; ) HANGUL SYLLABLE NAD +B0A0;B0A0;1102 1161 11AF;B0A0;1102 1161 11AF; # (날; 날; 날; 날; 날; ) HANGUL SYLLABLE NAL +B0A1;B0A1;1102 1161 11B0;B0A1;1102 1161 11B0; # (낡; 낡; 낡; 낡; 낡; ) HANGUL SYLLABLE NALG +B0A2;B0A2;1102 1161 11B1;B0A2;1102 1161 11B1; # (낢; 낢; 낢; 낢; 낢; ) HANGUL SYLLABLE NALM +B0A3;B0A3;1102 1161 11B2;B0A3;1102 1161 11B2; # (낣; 낣; 낣; 낣; 낣; ) HANGUL SYLLABLE NALB +B0A4;B0A4;1102 1161 11B3;B0A4;1102 1161 11B3; # (낤; 낤; 낤; 낤; 낤; ) HANGUL SYLLABLE NALS +B0A5;B0A5;1102 1161 11B4;B0A5;1102 1161 11B4; # (낥; 낥; 낥; 낥; 낥; ) HANGUL SYLLABLE NALT +B0A6;B0A6;1102 1161 11B5;B0A6;1102 1161 11B5; # (낦; 낦; 낦; 낦; 낦; ) HANGUL SYLLABLE NALP +B0A7;B0A7;1102 1161 11B6;B0A7;1102 1161 11B6; # (낧; 낧; 낧; 낧; 낧; ) HANGUL SYLLABLE NALH +B0A8;B0A8;1102 1161 11B7;B0A8;1102 1161 11B7; # (남; 남; 남; 남; 남; ) HANGUL SYLLABLE NAM +B0A9;B0A9;1102 1161 11B8;B0A9;1102 1161 11B8; # (납; 납; 납; 납; 납; ) HANGUL SYLLABLE NAB +B0AA;B0AA;1102 1161 11B9;B0AA;1102 1161 11B9; # (낪; 낪; 낪; 낪; 낪; ) HANGUL SYLLABLE NABS +B0AB;B0AB;1102 1161 11BA;B0AB;1102 1161 11BA; # (낫; 낫; 낫; 낫; 낫; ) HANGUL SYLLABLE NAS +B0AC;B0AC;1102 1161 11BB;B0AC;1102 1161 11BB; # (났; 났; 났; 났; 났; ) HANGUL SYLLABLE NASS +B0AD;B0AD;1102 1161 11BC;B0AD;1102 1161 11BC; # (낭; 낭; 낭; 낭; 낭; ) HANGUL SYLLABLE NANG +B0AE;B0AE;1102 1161 11BD;B0AE;1102 1161 11BD; # (낮; 낮; 낮; 낮; 낮; ) HANGUL SYLLABLE NAJ +B0AF;B0AF;1102 1161 11BE;B0AF;1102 1161 11BE; # (낯; 낯; 낯; 낯; 낯; ) HANGUL SYLLABLE NAC +B0B0;B0B0;1102 1161 11BF;B0B0;1102 1161 11BF; # (낰; 낰; 낰; 낰; 낰; ) HANGUL SYLLABLE NAK +B0B1;B0B1;1102 1161 11C0;B0B1;1102 1161 11C0; # (낱; 낱; 낱; 낱; 낱; ) HANGUL SYLLABLE NAT +B0B2;B0B2;1102 1161 11C1;B0B2;1102 1161 11C1; # (낲; 낲; 낲; 낲; 낲; ) HANGUL SYLLABLE NAP +B0B3;B0B3;1102 1161 11C2;B0B3;1102 1161 11C2; # (낳; 낳; 낳; 낳; 낳; ) HANGUL SYLLABLE NAH +B0B4;B0B4;1102 1162;B0B4;1102 1162; # (내; 내; 내; 내; 내; ) HANGUL SYLLABLE NAE +B0B5;B0B5;1102 1162 11A8;B0B5;1102 1162 11A8; # (낵; 낵; 낵; 낵; 낵; ) HANGUL SYLLABLE NAEG +B0B6;B0B6;1102 1162 11A9;B0B6;1102 1162 11A9; # (낶; 낶; 낶; 낶; 낶; ) HANGUL SYLLABLE NAEGG +B0B7;B0B7;1102 1162 11AA;B0B7;1102 1162 11AA; # (낷; 낷; 낷; 낷; 낷; ) HANGUL SYLLABLE NAEGS +B0B8;B0B8;1102 1162 11AB;B0B8;1102 1162 11AB; # (낸; 낸; 낸; 낸; 낸; ) HANGUL SYLLABLE NAEN +B0B9;B0B9;1102 1162 11AC;B0B9;1102 1162 11AC; # (낹; 낹; 낹; 낹; 낹; ) HANGUL SYLLABLE NAENJ +B0BA;B0BA;1102 1162 11AD;B0BA;1102 1162 11AD; # (낺; 낺; 낺; 낺; 낺; ) HANGUL SYLLABLE NAENH +B0BB;B0BB;1102 1162 11AE;B0BB;1102 1162 11AE; # (낻; 낻; 낻; 낻; 낻; ) HANGUL SYLLABLE NAED +B0BC;B0BC;1102 1162 11AF;B0BC;1102 1162 11AF; # (낼; 낼; 낼; 낼; 낼; ) HANGUL SYLLABLE NAEL +B0BD;B0BD;1102 1162 11B0;B0BD;1102 1162 11B0; # (낽; 낽; 낽; 낽; 낽; ) HANGUL SYLLABLE NAELG +B0BE;B0BE;1102 1162 11B1;B0BE;1102 1162 11B1; # (낾; 낾; 낾; 낾; 낾; ) HANGUL SYLLABLE NAELM +B0BF;B0BF;1102 1162 11B2;B0BF;1102 1162 11B2; # (낿; 낿; 낿; 낿; 낿; ) HANGUL SYLLABLE NAELB +B0C0;B0C0;1102 1162 11B3;B0C0;1102 1162 11B3; # (냀; 냀; 냀; 냀; 냀; ) HANGUL SYLLABLE NAELS +B0C1;B0C1;1102 1162 11B4;B0C1;1102 1162 11B4; # (냁; 냁; 냁; 냁; 냁; ) HANGUL SYLLABLE NAELT +B0C2;B0C2;1102 1162 11B5;B0C2;1102 1162 11B5; # (냂; 냂; 냂; 냂; 냂; ) HANGUL SYLLABLE NAELP +B0C3;B0C3;1102 1162 11B6;B0C3;1102 1162 11B6; # (냃; 냃; 냃; 냃; 냃; ) HANGUL SYLLABLE NAELH +B0C4;B0C4;1102 1162 11B7;B0C4;1102 1162 11B7; # (냄; 냄; 냄; 냄; 냄; ) HANGUL SYLLABLE NAEM +B0C5;B0C5;1102 1162 11B8;B0C5;1102 1162 11B8; # (냅; 냅; 냅; 냅; 냅; ) HANGUL SYLLABLE NAEB +B0C6;B0C6;1102 1162 11B9;B0C6;1102 1162 11B9; # (냆; 냆; 냆; 냆; 냆; ) HANGUL SYLLABLE NAEBS +B0C7;B0C7;1102 1162 11BA;B0C7;1102 1162 11BA; # (냇; 냇; 냇; 냇; 냇; ) HANGUL SYLLABLE NAES +B0C8;B0C8;1102 1162 11BB;B0C8;1102 1162 11BB; # (냈; 냈; 냈; 냈; 냈; ) HANGUL SYLLABLE NAESS +B0C9;B0C9;1102 1162 11BC;B0C9;1102 1162 11BC; # (냉; 냉; 냉; 냉; 냉; ) HANGUL SYLLABLE NAENG +B0CA;B0CA;1102 1162 11BD;B0CA;1102 1162 11BD; # (냊; 냊; 냊; 냊; 냊; ) HANGUL SYLLABLE NAEJ +B0CB;B0CB;1102 1162 11BE;B0CB;1102 1162 11BE; # (냋; 냋; 냋; 냋; 냋; ) HANGUL SYLLABLE NAEC +B0CC;B0CC;1102 1162 11BF;B0CC;1102 1162 11BF; # (냌; 냌; 냌; 냌; 냌; ) HANGUL SYLLABLE NAEK +B0CD;B0CD;1102 1162 11C0;B0CD;1102 1162 11C0; # (냍; 냍; 냍; 냍; 냍; ) HANGUL SYLLABLE NAET +B0CE;B0CE;1102 1162 11C1;B0CE;1102 1162 11C1; # (냎; 냎; 냎; 냎; 냎; ) HANGUL SYLLABLE NAEP +B0CF;B0CF;1102 1162 11C2;B0CF;1102 1162 11C2; # (냏; 냏; 냏; 냏; 냏; ) HANGUL SYLLABLE NAEH +B0D0;B0D0;1102 1163;B0D0;1102 1163; # (냐; 냐; 냐; 냐; 냐; ) HANGUL SYLLABLE NYA +B0D1;B0D1;1102 1163 11A8;B0D1;1102 1163 11A8; # (냑; 냑; 냑; 냑; 냑; ) HANGUL SYLLABLE NYAG +B0D2;B0D2;1102 1163 11A9;B0D2;1102 1163 11A9; # (냒; 냒; 냒; 냒; 냒; ) HANGUL SYLLABLE NYAGG +B0D3;B0D3;1102 1163 11AA;B0D3;1102 1163 11AA; # (냓; 냓; 냓; 냓; 냓; ) HANGUL SYLLABLE NYAGS +B0D4;B0D4;1102 1163 11AB;B0D4;1102 1163 11AB; # (냔; 냔; 냔; 냔; 냔; ) HANGUL SYLLABLE NYAN +B0D5;B0D5;1102 1163 11AC;B0D5;1102 1163 11AC; # (냕; 냕; 냕; 냕; 냕; ) HANGUL SYLLABLE NYANJ +B0D6;B0D6;1102 1163 11AD;B0D6;1102 1163 11AD; # (냖; 냖; 냖; 냖; 냖; ) HANGUL SYLLABLE NYANH +B0D7;B0D7;1102 1163 11AE;B0D7;1102 1163 11AE; # (냗; 냗; 냗; 냗; 냗; ) HANGUL SYLLABLE NYAD +B0D8;B0D8;1102 1163 11AF;B0D8;1102 1163 11AF; # (냘; 냘; 냘; 냘; 냘; ) HANGUL SYLLABLE NYAL +B0D9;B0D9;1102 1163 11B0;B0D9;1102 1163 11B0; # (냙; 냙; 냙; 냙; 냙; ) HANGUL SYLLABLE NYALG +B0DA;B0DA;1102 1163 11B1;B0DA;1102 1163 11B1; # (냚; 냚; 냚; 냚; 냚; ) HANGUL SYLLABLE NYALM +B0DB;B0DB;1102 1163 11B2;B0DB;1102 1163 11B2; # (냛; 냛; 냛; 냛; 냛; ) HANGUL SYLLABLE NYALB +B0DC;B0DC;1102 1163 11B3;B0DC;1102 1163 11B3; # (냜; 냜; 냜; 냜; 냜; ) HANGUL SYLLABLE NYALS +B0DD;B0DD;1102 1163 11B4;B0DD;1102 1163 11B4; # (냝; 냝; 냝; 냝; 냝; ) HANGUL SYLLABLE NYALT +B0DE;B0DE;1102 1163 11B5;B0DE;1102 1163 11B5; # (냞; 냞; 냞; 냞; 냞; ) HANGUL SYLLABLE NYALP +B0DF;B0DF;1102 1163 11B6;B0DF;1102 1163 11B6; # (냟; 냟; 냟; 냟; 냟; ) HANGUL SYLLABLE NYALH +B0E0;B0E0;1102 1163 11B7;B0E0;1102 1163 11B7; # (냠; 냠; 냠; 냠; 냠; ) HANGUL SYLLABLE NYAM +B0E1;B0E1;1102 1163 11B8;B0E1;1102 1163 11B8; # (냡; 냡; 냡; 냡; 냡; ) HANGUL SYLLABLE NYAB +B0E2;B0E2;1102 1163 11B9;B0E2;1102 1163 11B9; # (냢; 냢; 냢; 냢; 냢; ) HANGUL SYLLABLE NYABS +B0E3;B0E3;1102 1163 11BA;B0E3;1102 1163 11BA; # (냣; 냣; 냣; 냣; 냣; ) HANGUL SYLLABLE NYAS +B0E4;B0E4;1102 1163 11BB;B0E4;1102 1163 11BB; # (냤; 냤; 냤; 냤; 냤; ) HANGUL SYLLABLE NYASS +B0E5;B0E5;1102 1163 11BC;B0E5;1102 1163 11BC; # (냥; 냥; 냥; 냥; 냥; ) HANGUL SYLLABLE NYANG +B0E6;B0E6;1102 1163 11BD;B0E6;1102 1163 11BD; # (냦; 냦; 냦; 냦; 냦; ) HANGUL SYLLABLE NYAJ +B0E7;B0E7;1102 1163 11BE;B0E7;1102 1163 11BE; # (냧; 냧; 냧; 냧; 냧; ) HANGUL SYLLABLE NYAC +B0E8;B0E8;1102 1163 11BF;B0E8;1102 1163 11BF; # (냨; 냨; 냨; 냨; 냨; ) HANGUL SYLLABLE NYAK +B0E9;B0E9;1102 1163 11C0;B0E9;1102 1163 11C0; # (냩; 냩; 냩; 냩; 냩; ) HANGUL SYLLABLE NYAT +B0EA;B0EA;1102 1163 11C1;B0EA;1102 1163 11C1; # (냪; 냪; 냪; 냪; 냪; ) HANGUL SYLLABLE NYAP +B0EB;B0EB;1102 1163 11C2;B0EB;1102 1163 11C2; # (냫; 냫; 냫; 냫; 냫; ) HANGUL SYLLABLE NYAH +B0EC;B0EC;1102 1164;B0EC;1102 1164; # (냬; 냬; 냬; 냬; 냬; ) HANGUL SYLLABLE NYAE +B0ED;B0ED;1102 1164 11A8;B0ED;1102 1164 11A8; # (냭; 냭; 냭; 냭; 냭; ) HANGUL SYLLABLE NYAEG +B0EE;B0EE;1102 1164 11A9;B0EE;1102 1164 11A9; # (냮; 냮; 냮; 냮; 냮; ) HANGUL SYLLABLE NYAEGG +B0EF;B0EF;1102 1164 11AA;B0EF;1102 1164 11AA; # (냯; 냯; 냯; 냯; 냯; ) HANGUL SYLLABLE NYAEGS +B0F0;B0F0;1102 1164 11AB;B0F0;1102 1164 11AB; # (냰; 냰; 냰; 냰; 냰; ) HANGUL SYLLABLE NYAEN +B0F1;B0F1;1102 1164 11AC;B0F1;1102 1164 11AC; # (냱; 냱; 냱; 냱; 냱; ) HANGUL SYLLABLE NYAENJ +B0F2;B0F2;1102 1164 11AD;B0F2;1102 1164 11AD; # (냲; 냲; 냲; 냲; 냲; ) HANGUL SYLLABLE NYAENH +B0F3;B0F3;1102 1164 11AE;B0F3;1102 1164 11AE; # (냳; 냳; 냳; 냳; 냳; ) HANGUL SYLLABLE NYAED +B0F4;B0F4;1102 1164 11AF;B0F4;1102 1164 11AF; # (냴; 냴; 냴; 냴; 냴; ) HANGUL SYLLABLE NYAEL +B0F5;B0F5;1102 1164 11B0;B0F5;1102 1164 11B0; # (냵; 냵; 냵; 냵; 냵; ) HANGUL SYLLABLE NYAELG +B0F6;B0F6;1102 1164 11B1;B0F6;1102 1164 11B1; # (냶; 냶; 냶; 냶; 냶; ) HANGUL SYLLABLE NYAELM +B0F7;B0F7;1102 1164 11B2;B0F7;1102 1164 11B2; # (냷; 냷; 냷; 냷; 냷; ) HANGUL SYLLABLE NYAELB +B0F8;B0F8;1102 1164 11B3;B0F8;1102 1164 11B3; # (냸; 냸; 냸; 냸; 냸; ) HANGUL SYLLABLE NYAELS +B0F9;B0F9;1102 1164 11B4;B0F9;1102 1164 11B4; # (냹; 냹; 냹; 냹; 냹; ) HANGUL SYLLABLE NYAELT +B0FA;B0FA;1102 1164 11B5;B0FA;1102 1164 11B5; # (냺; 냺; 냺; 냺; 냺; ) HANGUL SYLLABLE NYAELP +B0FB;B0FB;1102 1164 11B6;B0FB;1102 1164 11B6; # (냻; 냻; 냻; 냻; 냻; ) HANGUL SYLLABLE NYAELH +B0FC;B0FC;1102 1164 11B7;B0FC;1102 1164 11B7; # (냼; 냼; 냼; 냼; 냼; ) HANGUL SYLLABLE NYAEM +B0FD;B0FD;1102 1164 11B8;B0FD;1102 1164 11B8; # (냽; 냽; 냽; 냽; 냽; ) HANGUL SYLLABLE NYAEB +B0FE;B0FE;1102 1164 11B9;B0FE;1102 1164 11B9; # (냾; 냾; 냾; 냾; 냾; ) HANGUL SYLLABLE NYAEBS +B0FF;B0FF;1102 1164 11BA;B0FF;1102 1164 11BA; # (냿; 냿; 냿; 냿; 냿; ) HANGUL SYLLABLE NYAES +B100;B100;1102 1164 11BB;B100;1102 1164 11BB; # (넀; 넀; 넀; 넀; 넀; ) HANGUL SYLLABLE NYAESS +B101;B101;1102 1164 11BC;B101;1102 1164 11BC; # (넁; 넁; 넁; 넁; 넁; ) HANGUL SYLLABLE NYAENG +B102;B102;1102 1164 11BD;B102;1102 1164 11BD; # (넂; 넂; 넂; 넂; 넂; ) HANGUL SYLLABLE NYAEJ +B103;B103;1102 1164 11BE;B103;1102 1164 11BE; # (넃; 넃; 넃; 넃; 넃; ) HANGUL SYLLABLE NYAEC +B104;B104;1102 1164 11BF;B104;1102 1164 11BF; # (넄; 넄; 넄; 넄; 넄; ) HANGUL SYLLABLE NYAEK +B105;B105;1102 1164 11C0;B105;1102 1164 11C0; # (넅; 넅; 넅; 넅; 넅; ) HANGUL SYLLABLE NYAET +B106;B106;1102 1164 11C1;B106;1102 1164 11C1; # (넆; 넆; 넆; 넆; 넆; ) HANGUL SYLLABLE NYAEP +B107;B107;1102 1164 11C2;B107;1102 1164 11C2; # (넇; 넇; 넇; 넇; 넇; ) HANGUL SYLLABLE NYAEH +B108;B108;1102 1165;B108;1102 1165; # (너; 너; 너; 너; 너; ) HANGUL SYLLABLE NEO +B109;B109;1102 1165 11A8;B109;1102 1165 11A8; # (넉; 넉; 넉; 넉; 넉; ) HANGUL SYLLABLE NEOG +B10A;B10A;1102 1165 11A9;B10A;1102 1165 11A9; # (넊; 넊; 넊; 넊; 넊; ) HANGUL SYLLABLE NEOGG +B10B;B10B;1102 1165 11AA;B10B;1102 1165 11AA; # (넋; 넋; 넋; 넋; 넋; ) HANGUL SYLLABLE NEOGS +B10C;B10C;1102 1165 11AB;B10C;1102 1165 11AB; # (넌; 넌; 넌; 넌; 넌; ) HANGUL SYLLABLE NEON +B10D;B10D;1102 1165 11AC;B10D;1102 1165 11AC; # (넍; 넍; 넍; 넍; 넍; ) HANGUL SYLLABLE NEONJ +B10E;B10E;1102 1165 11AD;B10E;1102 1165 11AD; # (넎; 넎; 넎; 넎; 넎; ) HANGUL SYLLABLE NEONH +B10F;B10F;1102 1165 11AE;B10F;1102 1165 11AE; # (넏; 넏; 넏; 넏; 넏; ) HANGUL SYLLABLE NEOD +B110;B110;1102 1165 11AF;B110;1102 1165 11AF; # (널; 널; 널; 널; 널; ) HANGUL SYLLABLE NEOL +B111;B111;1102 1165 11B0;B111;1102 1165 11B0; # (넑; 넑; 넑; 넑; 넑; ) HANGUL SYLLABLE NEOLG +B112;B112;1102 1165 11B1;B112;1102 1165 11B1; # (넒; 넒; 넒; 넒; 넒; ) HANGUL SYLLABLE NEOLM +B113;B113;1102 1165 11B2;B113;1102 1165 11B2; # (넓; 넓; 넓; 넓; 넓; ) HANGUL SYLLABLE NEOLB +B114;B114;1102 1165 11B3;B114;1102 1165 11B3; # (넔; 넔; 넔; 넔; 넔; ) HANGUL SYLLABLE NEOLS +B115;B115;1102 1165 11B4;B115;1102 1165 11B4; # (넕; 넕; 넕; 넕; 넕; ) HANGUL SYLLABLE NEOLT +B116;B116;1102 1165 11B5;B116;1102 1165 11B5; # (넖; 넖; 넖; 넖; 넖; ) HANGUL SYLLABLE NEOLP +B117;B117;1102 1165 11B6;B117;1102 1165 11B6; # (넗; 넗; 넗; 넗; 넗; ) HANGUL SYLLABLE NEOLH +B118;B118;1102 1165 11B7;B118;1102 1165 11B7; # (넘; 넘; 넘; 넘; 넘; ) HANGUL SYLLABLE NEOM +B119;B119;1102 1165 11B8;B119;1102 1165 11B8; # (넙; 넙; 넙; 넙; 넙; ) HANGUL SYLLABLE NEOB +B11A;B11A;1102 1165 11B9;B11A;1102 1165 11B9; # (넚; 넚; 넚; 넚; 넚; ) HANGUL SYLLABLE NEOBS +B11B;B11B;1102 1165 11BA;B11B;1102 1165 11BA; # (넛; 넛; 넛; 넛; 넛; ) HANGUL SYLLABLE NEOS +B11C;B11C;1102 1165 11BB;B11C;1102 1165 11BB; # (넜; 넜; 넜; 넜; 넜; ) HANGUL SYLLABLE NEOSS +B11D;B11D;1102 1165 11BC;B11D;1102 1165 11BC; # (넝; 넝; 넝; 넝; 넝; ) HANGUL SYLLABLE NEONG +B11E;B11E;1102 1165 11BD;B11E;1102 1165 11BD; # (넞; 넞; 넞; 넞; 넞; ) HANGUL SYLLABLE NEOJ +B11F;B11F;1102 1165 11BE;B11F;1102 1165 11BE; # (넟; 넟; 넟; 넟; 넟; ) HANGUL SYLLABLE NEOC +B120;B120;1102 1165 11BF;B120;1102 1165 11BF; # (넠; 넠; 넠; 넠; 넠; ) HANGUL SYLLABLE NEOK +B121;B121;1102 1165 11C0;B121;1102 1165 11C0; # (넡; 넡; 넡; 넡; 넡; ) HANGUL SYLLABLE NEOT +B122;B122;1102 1165 11C1;B122;1102 1165 11C1; # (넢; 넢; 넢; 넢; 넢; ) HANGUL SYLLABLE NEOP +B123;B123;1102 1165 11C2;B123;1102 1165 11C2; # (넣; 넣; 넣; 넣; 넣; ) HANGUL SYLLABLE NEOH +B124;B124;1102 1166;B124;1102 1166; # (네; 네; 네; 네; 네; ) HANGUL SYLLABLE NE +B125;B125;1102 1166 11A8;B125;1102 1166 11A8; # (넥; 넥; 넥; 넥; 넥; ) HANGUL SYLLABLE NEG +B126;B126;1102 1166 11A9;B126;1102 1166 11A9; # (넦; 넦; 넦; 넦; 넦; ) HANGUL SYLLABLE NEGG +B127;B127;1102 1166 11AA;B127;1102 1166 11AA; # (넧; 넧; 넧; 넧; 넧; ) HANGUL SYLLABLE NEGS +B128;B128;1102 1166 11AB;B128;1102 1166 11AB; # (넨; 넨; 넨; 넨; 넨; ) HANGUL SYLLABLE NEN +B129;B129;1102 1166 11AC;B129;1102 1166 11AC; # (넩; 넩; 넩; 넩; 넩; ) HANGUL SYLLABLE NENJ +B12A;B12A;1102 1166 11AD;B12A;1102 1166 11AD; # (넪; 넪; 넪; 넪; 넪; ) HANGUL SYLLABLE NENH +B12B;B12B;1102 1166 11AE;B12B;1102 1166 11AE; # (넫; 넫; 넫; 넫; 넫; ) HANGUL SYLLABLE NED +B12C;B12C;1102 1166 11AF;B12C;1102 1166 11AF; # (넬; 넬; 넬; 넬; 넬; ) HANGUL SYLLABLE NEL +B12D;B12D;1102 1166 11B0;B12D;1102 1166 11B0; # (넭; 넭; 넭; 넭; 넭; ) HANGUL SYLLABLE NELG +B12E;B12E;1102 1166 11B1;B12E;1102 1166 11B1; # (넮; 넮; 넮; 넮; 넮; ) HANGUL SYLLABLE NELM +B12F;B12F;1102 1166 11B2;B12F;1102 1166 11B2; # (넯; 넯; 넯; 넯; 넯; ) HANGUL SYLLABLE NELB +B130;B130;1102 1166 11B3;B130;1102 1166 11B3; # (넰; 넰; 넰; 넰; 넰; ) HANGUL SYLLABLE NELS +B131;B131;1102 1166 11B4;B131;1102 1166 11B4; # (넱; 넱; 넱; 넱; 넱; ) HANGUL SYLLABLE NELT +B132;B132;1102 1166 11B5;B132;1102 1166 11B5; # (넲; 넲; 넲; 넲; 넲; ) HANGUL SYLLABLE NELP +B133;B133;1102 1166 11B6;B133;1102 1166 11B6; # (넳; 넳; 넳; 넳; 넳; ) HANGUL SYLLABLE NELH +B134;B134;1102 1166 11B7;B134;1102 1166 11B7; # (넴; 넴; 넴; 넴; 넴; ) HANGUL SYLLABLE NEM +B135;B135;1102 1166 11B8;B135;1102 1166 11B8; # (넵; 넵; 넵; 넵; 넵; ) HANGUL SYLLABLE NEB +B136;B136;1102 1166 11B9;B136;1102 1166 11B9; # (넶; 넶; 넶; 넶; 넶; ) HANGUL SYLLABLE NEBS +B137;B137;1102 1166 11BA;B137;1102 1166 11BA; # (넷; 넷; 넷; 넷; 넷; ) HANGUL SYLLABLE NES +B138;B138;1102 1166 11BB;B138;1102 1166 11BB; # (넸; 넸; 넸; 넸; 넸; ) HANGUL SYLLABLE NESS +B139;B139;1102 1166 11BC;B139;1102 1166 11BC; # (넹; 넹; 넹; 넹; 넹; ) HANGUL SYLLABLE NENG +B13A;B13A;1102 1166 11BD;B13A;1102 1166 11BD; # (넺; 넺; 넺; 넺; 넺; ) HANGUL SYLLABLE NEJ +B13B;B13B;1102 1166 11BE;B13B;1102 1166 11BE; # (넻; 넻; 넻; 넻; 넻; ) HANGUL SYLLABLE NEC +B13C;B13C;1102 1166 11BF;B13C;1102 1166 11BF; # (넼; 넼; 넼; 넼; 넼; ) HANGUL SYLLABLE NEK +B13D;B13D;1102 1166 11C0;B13D;1102 1166 11C0; # (넽; 넽; 넽; 넽; 넽; ) HANGUL SYLLABLE NET +B13E;B13E;1102 1166 11C1;B13E;1102 1166 11C1; # (넾; 넾; 넾; 넾; 넾; ) HANGUL SYLLABLE NEP +B13F;B13F;1102 1166 11C2;B13F;1102 1166 11C2; # (넿; 넿; 넿; 넿; 넿; ) HANGUL SYLLABLE NEH +B140;B140;1102 1167;B140;1102 1167; # (녀; 녀; 녀; 녀; 녀; ) HANGUL SYLLABLE NYEO +B141;B141;1102 1167 11A8;B141;1102 1167 11A8; # (녁; 녁; 녁; 녁; 녁; ) HANGUL SYLLABLE NYEOG +B142;B142;1102 1167 11A9;B142;1102 1167 11A9; # (녂; 녂; 녂; 녂; 녂; ) HANGUL SYLLABLE NYEOGG +B143;B143;1102 1167 11AA;B143;1102 1167 11AA; # (녃; 녃; 녃; 녃; 녃; ) HANGUL SYLLABLE NYEOGS +B144;B144;1102 1167 11AB;B144;1102 1167 11AB; # (년; 년; 년; 년; 년; ) HANGUL SYLLABLE NYEON +B145;B145;1102 1167 11AC;B145;1102 1167 11AC; # (녅; 녅; 녅; 녅; 녅; ) HANGUL SYLLABLE NYEONJ +B146;B146;1102 1167 11AD;B146;1102 1167 11AD; # (녆; 녆; 녆; 녆; 녆; ) HANGUL SYLLABLE NYEONH +B147;B147;1102 1167 11AE;B147;1102 1167 11AE; # (녇; 녇; 녇; 녇; 녇; ) HANGUL SYLLABLE NYEOD +B148;B148;1102 1167 11AF;B148;1102 1167 11AF; # (녈; 녈; 녈; 녈; 녈; ) HANGUL SYLLABLE NYEOL +B149;B149;1102 1167 11B0;B149;1102 1167 11B0; # (녉; 녉; 녉; 녉; 녉; ) HANGUL SYLLABLE NYEOLG +B14A;B14A;1102 1167 11B1;B14A;1102 1167 11B1; # (녊; 녊; 녊; 녊; 녊; ) HANGUL SYLLABLE NYEOLM +B14B;B14B;1102 1167 11B2;B14B;1102 1167 11B2; # (녋; 녋; 녋; 녋; 녋; ) HANGUL SYLLABLE NYEOLB +B14C;B14C;1102 1167 11B3;B14C;1102 1167 11B3; # (녌; 녌; 녌; 녌; 녌; ) HANGUL SYLLABLE NYEOLS +B14D;B14D;1102 1167 11B4;B14D;1102 1167 11B4; # (녍; 녍; 녍; 녍; 녍; ) HANGUL SYLLABLE NYEOLT +B14E;B14E;1102 1167 11B5;B14E;1102 1167 11B5; # (녎; 녎; 녎; 녎; 녎; ) HANGUL SYLLABLE NYEOLP +B14F;B14F;1102 1167 11B6;B14F;1102 1167 11B6; # (녏; 녏; 녏; 녏; 녏; ) HANGUL SYLLABLE NYEOLH +B150;B150;1102 1167 11B7;B150;1102 1167 11B7; # (념; 념; 념; 념; 념; ) HANGUL SYLLABLE NYEOM +B151;B151;1102 1167 11B8;B151;1102 1167 11B8; # (녑; 녑; 녑; 녑; 녑; ) HANGUL SYLLABLE NYEOB +B152;B152;1102 1167 11B9;B152;1102 1167 11B9; # (녒; 녒; 녒; 녒; 녒; ) HANGUL SYLLABLE NYEOBS +B153;B153;1102 1167 11BA;B153;1102 1167 11BA; # (녓; 녓; 녓; 녓; 녓; ) HANGUL SYLLABLE NYEOS +B154;B154;1102 1167 11BB;B154;1102 1167 11BB; # (녔; 녔; 녔; 녔; 녔; ) HANGUL SYLLABLE NYEOSS +B155;B155;1102 1167 11BC;B155;1102 1167 11BC; # (녕; 녕; 녕; 녕; 녕; ) HANGUL SYLLABLE NYEONG +B156;B156;1102 1167 11BD;B156;1102 1167 11BD; # (녖; 녖; 녖; 녖; 녖; ) HANGUL SYLLABLE NYEOJ +B157;B157;1102 1167 11BE;B157;1102 1167 11BE; # (녗; 녗; 녗; 녗; 녗; ) HANGUL SYLLABLE NYEOC +B158;B158;1102 1167 11BF;B158;1102 1167 11BF; # (녘; 녘; 녘; 녘; 녘; ) HANGUL SYLLABLE NYEOK +B159;B159;1102 1167 11C0;B159;1102 1167 11C0; # (녙; 녙; 녙; 녙; 녙; ) HANGUL SYLLABLE NYEOT +B15A;B15A;1102 1167 11C1;B15A;1102 1167 11C1; # (녚; 녚; 녚; 녚; 녚; ) HANGUL SYLLABLE NYEOP +B15B;B15B;1102 1167 11C2;B15B;1102 1167 11C2; # (녛; 녛; 녛; 녛; 녛; ) HANGUL SYLLABLE NYEOH +B15C;B15C;1102 1168;B15C;1102 1168; # (녜; 녜; 녜; 녜; 녜; ) HANGUL SYLLABLE NYE +B15D;B15D;1102 1168 11A8;B15D;1102 1168 11A8; # (녝; 녝; 녝; 녝; 녝; ) HANGUL SYLLABLE NYEG +B15E;B15E;1102 1168 11A9;B15E;1102 1168 11A9; # (녞; 녞; 녞; 녞; 녞; ) HANGUL SYLLABLE NYEGG +B15F;B15F;1102 1168 11AA;B15F;1102 1168 11AA; # (녟; 녟; 녟; 녟; 녟; ) HANGUL SYLLABLE NYEGS +B160;B160;1102 1168 11AB;B160;1102 1168 11AB; # (녠; 녠; 녠; 녠; 녠; ) HANGUL SYLLABLE NYEN +B161;B161;1102 1168 11AC;B161;1102 1168 11AC; # (녡; 녡; 녡; 녡; 녡; ) HANGUL SYLLABLE NYENJ +B162;B162;1102 1168 11AD;B162;1102 1168 11AD; # (녢; 녢; 녢; 녢; 녢; ) HANGUL SYLLABLE NYENH +B163;B163;1102 1168 11AE;B163;1102 1168 11AE; # (녣; 녣; 녣; 녣; 녣; ) HANGUL SYLLABLE NYED +B164;B164;1102 1168 11AF;B164;1102 1168 11AF; # (녤; 녤; 녤; 녤; 녤; ) HANGUL SYLLABLE NYEL +B165;B165;1102 1168 11B0;B165;1102 1168 11B0; # (녥; 녥; 녥; 녥; 녥; ) HANGUL SYLLABLE NYELG +B166;B166;1102 1168 11B1;B166;1102 1168 11B1; # (녦; 녦; 녦; 녦; 녦; ) HANGUL SYLLABLE NYELM +B167;B167;1102 1168 11B2;B167;1102 1168 11B2; # (녧; 녧; 녧; 녧; 녧; ) HANGUL SYLLABLE NYELB +B168;B168;1102 1168 11B3;B168;1102 1168 11B3; # (녨; 녨; 녨; 녨; 녨; ) HANGUL SYLLABLE NYELS +B169;B169;1102 1168 11B4;B169;1102 1168 11B4; # (녩; 녩; 녩; 녩; 녩; ) HANGUL SYLLABLE NYELT +B16A;B16A;1102 1168 11B5;B16A;1102 1168 11B5; # (녪; 녪; 녪; 녪; 녪; ) HANGUL SYLLABLE NYELP +B16B;B16B;1102 1168 11B6;B16B;1102 1168 11B6; # (녫; 녫; 녫; 녫; 녫; ) HANGUL SYLLABLE NYELH +B16C;B16C;1102 1168 11B7;B16C;1102 1168 11B7; # (녬; 녬; 녬; 녬; 녬; ) HANGUL SYLLABLE NYEM +B16D;B16D;1102 1168 11B8;B16D;1102 1168 11B8; # (녭; 녭; 녭; 녭; 녭; ) HANGUL SYLLABLE NYEB +B16E;B16E;1102 1168 11B9;B16E;1102 1168 11B9; # (녮; 녮; 녮; 녮; 녮; ) HANGUL SYLLABLE NYEBS +B16F;B16F;1102 1168 11BA;B16F;1102 1168 11BA; # (녯; 녯; 녯; 녯; 녯; ) HANGUL SYLLABLE NYES +B170;B170;1102 1168 11BB;B170;1102 1168 11BB; # (녰; 녰; 녰; 녰; 녰; ) HANGUL SYLLABLE NYESS +B171;B171;1102 1168 11BC;B171;1102 1168 11BC; # (녱; 녱; 녱; 녱; 녱; ) HANGUL SYLLABLE NYENG +B172;B172;1102 1168 11BD;B172;1102 1168 11BD; # (녲; 녲; 녲; 녲; 녲; ) HANGUL SYLLABLE NYEJ +B173;B173;1102 1168 11BE;B173;1102 1168 11BE; # (녳; 녳; 녳; 녳; 녳; ) HANGUL SYLLABLE NYEC +B174;B174;1102 1168 11BF;B174;1102 1168 11BF; # (녴; 녴; 녴; 녴; 녴; ) HANGUL SYLLABLE NYEK +B175;B175;1102 1168 11C0;B175;1102 1168 11C0; # (녵; 녵; 녵; 녵; 녵; ) HANGUL SYLLABLE NYET +B176;B176;1102 1168 11C1;B176;1102 1168 11C1; # (녶; 녶; 녶; 녶; 녶; ) HANGUL SYLLABLE NYEP +B177;B177;1102 1168 11C2;B177;1102 1168 11C2; # (녷; 녷; 녷; 녷; 녷; ) HANGUL SYLLABLE NYEH +B178;B178;1102 1169;B178;1102 1169; # (노; 노; 노; 노; 노; ) HANGUL SYLLABLE NO +B179;B179;1102 1169 11A8;B179;1102 1169 11A8; # (녹; 녹; 녹; 녹; 녹; ) HANGUL SYLLABLE NOG +B17A;B17A;1102 1169 11A9;B17A;1102 1169 11A9; # (녺; 녺; 녺; 녺; 녺; ) HANGUL SYLLABLE NOGG +B17B;B17B;1102 1169 11AA;B17B;1102 1169 11AA; # (녻; 녻; 녻; 녻; 녻; ) HANGUL SYLLABLE NOGS +B17C;B17C;1102 1169 11AB;B17C;1102 1169 11AB; # (논; 논; 논; 논; 논; ) HANGUL SYLLABLE NON +B17D;B17D;1102 1169 11AC;B17D;1102 1169 11AC; # (녽; 녽; 녽; 녽; 녽; ) HANGUL SYLLABLE NONJ +B17E;B17E;1102 1169 11AD;B17E;1102 1169 11AD; # (녾; 녾; 녾; 녾; 녾; ) HANGUL SYLLABLE NONH +B17F;B17F;1102 1169 11AE;B17F;1102 1169 11AE; # (녿; 녿; 녿; 녿; 녿; ) HANGUL SYLLABLE NOD +B180;B180;1102 1169 11AF;B180;1102 1169 11AF; # (놀; 놀; 놀; 놀; 놀; ) HANGUL SYLLABLE NOL +B181;B181;1102 1169 11B0;B181;1102 1169 11B0; # (놁; 놁; 놁; 놁; 놁; ) HANGUL SYLLABLE NOLG +B182;B182;1102 1169 11B1;B182;1102 1169 11B1; # (놂; 놂; 놂; 놂; 놂; ) HANGUL SYLLABLE NOLM +B183;B183;1102 1169 11B2;B183;1102 1169 11B2; # (놃; 놃; 놃; 놃; 놃; ) HANGUL SYLLABLE NOLB +B184;B184;1102 1169 11B3;B184;1102 1169 11B3; # (놄; 놄; 놄; 놄; 놄; ) HANGUL SYLLABLE NOLS +B185;B185;1102 1169 11B4;B185;1102 1169 11B4; # (놅; 놅; 놅; 놅; 놅; ) HANGUL SYLLABLE NOLT +B186;B186;1102 1169 11B5;B186;1102 1169 11B5; # (놆; 놆; 놆; 놆; 놆; ) HANGUL SYLLABLE NOLP +B187;B187;1102 1169 11B6;B187;1102 1169 11B6; # (놇; 놇; 놇; 놇; 놇; ) HANGUL SYLLABLE NOLH +B188;B188;1102 1169 11B7;B188;1102 1169 11B7; # (놈; 놈; 놈; 놈; 놈; ) HANGUL SYLLABLE NOM +B189;B189;1102 1169 11B8;B189;1102 1169 11B8; # (놉; 놉; 놉; 놉; 놉; ) HANGUL SYLLABLE NOB +B18A;B18A;1102 1169 11B9;B18A;1102 1169 11B9; # (놊; 놊; 놊; 놊; 놊; ) HANGUL SYLLABLE NOBS +B18B;B18B;1102 1169 11BA;B18B;1102 1169 11BA; # (놋; 놋; 놋; 놋; 놋; ) HANGUL SYLLABLE NOS +B18C;B18C;1102 1169 11BB;B18C;1102 1169 11BB; # (놌; 놌; 놌; 놌; 놌; ) HANGUL SYLLABLE NOSS +B18D;B18D;1102 1169 11BC;B18D;1102 1169 11BC; # (농; 농; 농; 농; 농; ) HANGUL SYLLABLE NONG +B18E;B18E;1102 1169 11BD;B18E;1102 1169 11BD; # (놎; 놎; 놎; 놎; 놎; ) HANGUL SYLLABLE NOJ +B18F;B18F;1102 1169 11BE;B18F;1102 1169 11BE; # (놏; 놏; 놏; 놏; 놏; ) HANGUL SYLLABLE NOC +B190;B190;1102 1169 11BF;B190;1102 1169 11BF; # (놐; 놐; 놐; 놐; 놐; ) HANGUL SYLLABLE NOK +B191;B191;1102 1169 11C0;B191;1102 1169 11C0; # (놑; 놑; 놑; 놑; 놑; ) HANGUL SYLLABLE NOT +B192;B192;1102 1169 11C1;B192;1102 1169 11C1; # (높; 높; 높; 높; 높; ) HANGUL SYLLABLE NOP +B193;B193;1102 1169 11C2;B193;1102 1169 11C2; # (놓; 놓; 놓; 놓; 놓; ) HANGUL SYLLABLE NOH +B194;B194;1102 116A;B194;1102 116A; # (놔; 놔; 놔; 놔; 놔; ) HANGUL SYLLABLE NWA +B195;B195;1102 116A 11A8;B195;1102 116A 11A8; # (놕; 놕; 놕; 놕; 놕; ) HANGUL SYLLABLE NWAG +B196;B196;1102 116A 11A9;B196;1102 116A 11A9; # (놖; 놖; 놖; 놖; 놖; ) HANGUL SYLLABLE NWAGG +B197;B197;1102 116A 11AA;B197;1102 116A 11AA; # (놗; 놗; 놗; 놗; 놗; ) HANGUL SYLLABLE NWAGS +B198;B198;1102 116A 11AB;B198;1102 116A 11AB; # (놘; 놘; 놘; 놘; 놘; ) HANGUL SYLLABLE NWAN +B199;B199;1102 116A 11AC;B199;1102 116A 11AC; # (놙; 놙; 놙; 놙; 놙; ) HANGUL SYLLABLE NWANJ +B19A;B19A;1102 116A 11AD;B19A;1102 116A 11AD; # (놚; 놚; 놚; 놚; 놚; ) HANGUL SYLLABLE NWANH +B19B;B19B;1102 116A 11AE;B19B;1102 116A 11AE; # (놛; 놛; 놛; 놛; 놛; ) HANGUL SYLLABLE NWAD +B19C;B19C;1102 116A 11AF;B19C;1102 116A 11AF; # (놜; 놜; 놜; 놜; 놜; ) HANGUL SYLLABLE NWAL +B19D;B19D;1102 116A 11B0;B19D;1102 116A 11B0; # (놝; 놝; 놝; 놝; 놝; ) HANGUL SYLLABLE NWALG +B19E;B19E;1102 116A 11B1;B19E;1102 116A 11B1; # (놞; 놞; 놞; 놞; 놞; ) HANGUL SYLLABLE NWALM +B19F;B19F;1102 116A 11B2;B19F;1102 116A 11B2; # (놟; 놟; 놟; 놟; 놟; ) HANGUL SYLLABLE NWALB +B1A0;B1A0;1102 116A 11B3;B1A0;1102 116A 11B3; # (놠; 놠; 놠; 놠; 놠; ) HANGUL SYLLABLE NWALS +B1A1;B1A1;1102 116A 11B4;B1A1;1102 116A 11B4; # (놡; 놡; 놡; 놡; 놡; ) HANGUL SYLLABLE NWALT +B1A2;B1A2;1102 116A 11B5;B1A2;1102 116A 11B5; # (놢; 놢; 놢; 놢; 놢; ) HANGUL SYLLABLE NWALP +B1A3;B1A3;1102 116A 11B6;B1A3;1102 116A 11B6; # (놣; 놣; 놣; 놣; 놣; ) HANGUL SYLLABLE NWALH +B1A4;B1A4;1102 116A 11B7;B1A4;1102 116A 11B7; # (놤; 놤; 놤; 놤; 놤; ) HANGUL SYLLABLE NWAM +B1A5;B1A5;1102 116A 11B8;B1A5;1102 116A 11B8; # (놥; 놥; 놥; 놥; 놥; ) HANGUL SYLLABLE NWAB +B1A6;B1A6;1102 116A 11B9;B1A6;1102 116A 11B9; # (놦; 놦; 놦; 놦; 놦; ) HANGUL SYLLABLE NWABS +B1A7;B1A7;1102 116A 11BA;B1A7;1102 116A 11BA; # (놧; 놧; 놧; 놧; 놧; ) HANGUL SYLLABLE NWAS +B1A8;B1A8;1102 116A 11BB;B1A8;1102 116A 11BB; # (놨; 놨; 놨; 놨; 놨; ) HANGUL SYLLABLE NWASS +B1A9;B1A9;1102 116A 11BC;B1A9;1102 116A 11BC; # (놩; 놩; 놩; 놩; 놩; ) HANGUL SYLLABLE NWANG +B1AA;B1AA;1102 116A 11BD;B1AA;1102 116A 11BD; # (놪; 놪; 놪; 놪; 놪; ) HANGUL SYLLABLE NWAJ +B1AB;B1AB;1102 116A 11BE;B1AB;1102 116A 11BE; # (놫; 놫; 놫; 놫; 놫; ) HANGUL SYLLABLE NWAC +B1AC;B1AC;1102 116A 11BF;B1AC;1102 116A 11BF; # (놬; 놬; 놬; 놬; 놬; ) HANGUL SYLLABLE NWAK +B1AD;B1AD;1102 116A 11C0;B1AD;1102 116A 11C0; # (놭; 놭; 놭; 놭; 놭; ) HANGUL SYLLABLE NWAT +B1AE;B1AE;1102 116A 11C1;B1AE;1102 116A 11C1; # (놮; 놮; 놮; 놮; 놮; ) HANGUL SYLLABLE NWAP +B1AF;B1AF;1102 116A 11C2;B1AF;1102 116A 11C2; # (놯; 놯; 놯; 놯; 놯; ) HANGUL SYLLABLE NWAH +B1B0;B1B0;1102 116B;B1B0;1102 116B; # (놰; 놰; 놰; 놰; 놰; ) HANGUL SYLLABLE NWAE +B1B1;B1B1;1102 116B 11A8;B1B1;1102 116B 11A8; # (놱; 놱; 놱; 놱; 놱; ) HANGUL SYLLABLE NWAEG +B1B2;B1B2;1102 116B 11A9;B1B2;1102 116B 11A9; # (놲; 놲; 놲; 놲; 놲; ) HANGUL SYLLABLE NWAEGG +B1B3;B1B3;1102 116B 11AA;B1B3;1102 116B 11AA; # (놳; 놳; 놳; 놳; 놳; ) HANGUL SYLLABLE NWAEGS +B1B4;B1B4;1102 116B 11AB;B1B4;1102 116B 11AB; # (놴; 놴; 놴; 놴; 놴; ) HANGUL SYLLABLE NWAEN +B1B5;B1B5;1102 116B 11AC;B1B5;1102 116B 11AC; # (놵; 놵; 놵; 놵; 놵; ) HANGUL SYLLABLE NWAENJ +B1B6;B1B6;1102 116B 11AD;B1B6;1102 116B 11AD; # (놶; 놶; 놶; 놶; 놶; ) HANGUL SYLLABLE NWAENH +B1B7;B1B7;1102 116B 11AE;B1B7;1102 116B 11AE; # (놷; 놷; 놷; 놷; 놷; ) HANGUL SYLLABLE NWAED +B1B8;B1B8;1102 116B 11AF;B1B8;1102 116B 11AF; # (놸; 놸; 놸; 놸; 놸; ) HANGUL SYLLABLE NWAEL +B1B9;B1B9;1102 116B 11B0;B1B9;1102 116B 11B0; # (놹; 놹; 놹; 놹; 놹; ) HANGUL SYLLABLE NWAELG +B1BA;B1BA;1102 116B 11B1;B1BA;1102 116B 11B1; # (놺; 놺; 놺; 놺; 놺; ) HANGUL SYLLABLE NWAELM +B1BB;B1BB;1102 116B 11B2;B1BB;1102 116B 11B2; # (놻; 놻; 놻; 놻; 놻; ) HANGUL SYLLABLE NWAELB +B1BC;B1BC;1102 116B 11B3;B1BC;1102 116B 11B3; # (놼; 놼; 놼; 놼; 놼; ) HANGUL SYLLABLE NWAELS +B1BD;B1BD;1102 116B 11B4;B1BD;1102 116B 11B4; # (놽; 놽; 놽; 놽; 놽; ) HANGUL SYLLABLE NWAELT +B1BE;B1BE;1102 116B 11B5;B1BE;1102 116B 11B5; # (놾; 놾; 놾; 놾; 놾; ) HANGUL SYLLABLE NWAELP +B1BF;B1BF;1102 116B 11B6;B1BF;1102 116B 11B6; # (놿; 놿; 놿; 놿; 놿; ) HANGUL SYLLABLE NWAELH +B1C0;B1C0;1102 116B 11B7;B1C0;1102 116B 11B7; # (뇀; 뇀; 뇀; 뇀; 뇀; ) HANGUL SYLLABLE NWAEM +B1C1;B1C1;1102 116B 11B8;B1C1;1102 116B 11B8; # (뇁; 뇁; 뇁; 뇁; 뇁; ) HANGUL SYLLABLE NWAEB +B1C2;B1C2;1102 116B 11B9;B1C2;1102 116B 11B9; # (뇂; 뇂; 뇂; 뇂; 뇂; ) HANGUL SYLLABLE NWAEBS +B1C3;B1C3;1102 116B 11BA;B1C3;1102 116B 11BA; # (뇃; 뇃; 뇃; 뇃; 뇃; ) HANGUL SYLLABLE NWAES +B1C4;B1C4;1102 116B 11BB;B1C4;1102 116B 11BB; # (뇄; 뇄; 뇄; 뇄; 뇄; ) HANGUL SYLLABLE NWAESS +B1C5;B1C5;1102 116B 11BC;B1C5;1102 116B 11BC; # (뇅; 뇅; 뇅; 뇅; 뇅; ) HANGUL SYLLABLE NWAENG +B1C6;B1C6;1102 116B 11BD;B1C6;1102 116B 11BD; # (뇆; 뇆; 뇆; 뇆; 뇆; ) HANGUL SYLLABLE NWAEJ +B1C7;B1C7;1102 116B 11BE;B1C7;1102 116B 11BE; # (뇇; 뇇; 뇇; 뇇; 뇇; ) HANGUL SYLLABLE NWAEC +B1C8;B1C8;1102 116B 11BF;B1C8;1102 116B 11BF; # (뇈; 뇈; 뇈; 뇈; 뇈; ) HANGUL SYLLABLE NWAEK +B1C9;B1C9;1102 116B 11C0;B1C9;1102 116B 11C0; # (뇉; 뇉; 뇉; 뇉; 뇉; ) HANGUL SYLLABLE NWAET +B1CA;B1CA;1102 116B 11C1;B1CA;1102 116B 11C1; # (뇊; 뇊; 뇊; 뇊; 뇊; ) HANGUL SYLLABLE NWAEP +B1CB;B1CB;1102 116B 11C2;B1CB;1102 116B 11C2; # (뇋; 뇋; 뇋; 뇋; 뇋; ) HANGUL SYLLABLE NWAEH +B1CC;B1CC;1102 116C;B1CC;1102 116C; # (뇌; 뇌; 뇌; 뇌; 뇌; ) HANGUL SYLLABLE NOE +B1CD;B1CD;1102 116C 11A8;B1CD;1102 116C 11A8; # (뇍; 뇍; 뇍; 뇍; 뇍; ) HANGUL SYLLABLE NOEG +B1CE;B1CE;1102 116C 11A9;B1CE;1102 116C 11A9; # (뇎; 뇎; 뇎; 뇎; 뇎; ) HANGUL SYLLABLE NOEGG +B1CF;B1CF;1102 116C 11AA;B1CF;1102 116C 11AA; # (뇏; 뇏; 뇏; 뇏; 뇏; ) HANGUL SYLLABLE NOEGS +B1D0;B1D0;1102 116C 11AB;B1D0;1102 116C 11AB; # (뇐; 뇐; 뇐; 뇐; 뇐; ) HANGUL SYLLABLE NOEN +B1D1;B1D1;1102 116C 11AC;B1D1;1102 116C 11AC; # (뇑; 뇑; 뇑; 뇑; 뇑; ) HANGUL SYLLABLE NOENJ +B1D2;B1D2;1102 116C 11AD;B1D2;1102 116C 11AD; # (뇒; 뇒; 뇒; 뇒; 뇒; ) HANGUL SYLLABLE NOENH +B1D3;B1D3;1102 116C 11AE;B1D3;1102 116C 11AE; # (뇓; 뇓; 뇓; 뇓; 뇓; ) HANGUL SYLLABLE NOED +B1D4;B1D4;1102 116C 11AF;B1D4;1102 116C 11AF; # (뇔; 뇔; 뇔; 뇔; 뇔; ) HANGUL SYLLABLE NOEL +B1D5;B1D5;1102 116C 11B0;B1D5;1102 116C 11B0; # (뇕; 뇕; 뇕; 뇕; 뇕; ) HANGUL SYLLABLE NOELG +B1D6;B1D6;1102 116C 11B1;B1D6;1102 116C 11B1; # (뇖; 뇖; 뇖; 뇖; 뇖; ) HANGUL SYLLABLE NOELM +B1D7;B1D7;1102 116C 11B2;B1D7;1102 116C 11B2; # (뇗; 뇗; 뇗; 뇗; 뇗; ) HANGUL SYLLABLE NOELB +B1D8;B1D8;1102 116C 11B3;B1D8;1102 116C 11B3; # (뇘; 뇘; 뇘; 뇘; 뇘; ) HANGUL SYLLABLE NOELS +B1D9;B1D9;1102 116C 11B4;B1D9;1102 116C 11B4; # (뇙; 뇙; 뇙; 뇙; 뇙; ) HANGUL SYLLABLE NOELT +B1DA;B1DA;1102 116C 11B5;B1DA;1102 116C 11B5; # (뇚; 뇚; 뇚; 뇚; 뇚; ) HANGUL SYLLABLE NOELP +B1DB;B1DB;1102 116C 11B6;B1DB;1102 116C 11B6; # (뇛; 뇛; 뇛; 뇛; 뇛; ) HANGUL SYLLABLE NOELH +B1DC;B1DC;1102 116C 11B7;B1DC;1102 116C 11B7; # (뇜; 뇜; 뇜; 뇜; 뇜; ) HANGUL SYLLABLE NOEM +B1DD;B1DD;1102 116C 11B8;B1DD;1102 116C 11B8; # (뇝; 뇝; 뇝; 뇝; 뇝; ) HANGUL SYLLABLE NOEB +B1DE;B1DE;1102 116C 11B9;B1DE;1102 116C 11B9; # (뇞; 뇞; 뇞; 뇞; 뇞; ) HANGUL SYLLABLE NOEBS +B1DF;B1DF;1102 116C 11BA;B1DF;1102 116C 11BA; # (뇟; 뇟; 뇟; 뇟; 뇟; ) HANGUL SYLLABLE NOES +B1E0;B1E0;1102 116C 11BB;B1E0;1102 116C 11BB; # (뇠; 뇠; 뇠; 뇠; 뇠; ) HANGUL SYLLABLE NOESS +B1E1;B1E1;1102 116C 11BC;B1E1;1102 116C 11BC; # (뇡; 뇡; 뇡; 뇡; 뇡; ) HANGUL SYLLABLE NOENG +B1E2;B1E2;1102 116C 11BD;B1E2;1102 116C 11BD; # (뇢; 뇢; 뇢; 뇢; 뇢; ) HANGUL SYLLABLE NOEJ +B1E3;B1E3;1102 116C 11BE;B1E3;1102 116C 11BE; # (뇣; 뇣; 뇣; 뇣; 뇣; ) HANGUL SYLLABLE NOEC +B1E4;B1E4;1102 116C 11BF;B1E4;1102 116C 11BF; # (뇤; 뇤; 뇤; 뇤; 뇤; ) HANGUL SYLLABLE NOEK +B1E5;B1E5;1102 116C 11C0;B1E5;1102 116C 11C0; # (뇥; 뇥; 뇥; 뇥; 뇥; ) HANGUL SYLLABLE NOET +B1E6;B1E6;1102 116C 11C1;B1E6;1102 116C 11C1; # (뇦; 뇦; 뇦; 뇦; 뇦; ) HANGUL SYLLABLE NOEP +B1E7;B1E7;1102 116C 11C2;B1E7;1102 116C 11C2; # (뇧; 뇧; 뇧; 뇧; 뇧; ) HANGUL SYLLABLE NOEH +B1E8;B1E8;1102 116D;B1E8;1102 116D; # (뇨; 뇨; 뇨; 뇨; 뇨; ) HANGUL SYLLABLE NYO +B1E9;B1E9;1102 116D 11A8;B1E9;1102 116D 11A8; # (뇩; 뇩; 뇩; 뇩; 뇩; ) HANGUL SYLLABLE NYOG +B1EA;B1EA;1102 116D 11A9;B1EA;1102 116D 11A9; # (뇪; 뇪; 뇪; 뇪; 뇪; ) HANGUL SYLLABLE NYOGG +B1EB;B1EB;1102 116D 11AA;B1EB;1102 116D 11AA; # (뇫; 뇫; 뇫; 뇫; 뇫; ) HANGUL SYLLABLE NYOGS +B1EC;B1EC;1102 116D 11AB;B1EC;1102 116D 11AB; # (뇬; 뇬; 뇬; 뇬; 뇬; ) HANGUL SYLLABLE NYON +B1ED;B1ED;1102 116D 11AC;B1ED;1102 116D 11AC; # (뇭; 뇭; 뇭; 뇭; 뇭; ) HANGUL SYLLABLE NYONJ +B1EE;B1EE;1102 116D 11AD;B1EE;1102 116D 11AD; # (뇮; 뇮; 뇮; 뇮; 뇮; ) HANGUL SYLLABLE NYONH +B1EF;B1EF;1102 116D 11AE;B1EF;1102 116D 11AE; # (뇯; 뇯; 뇯; 뇯; 뇯; ) HANGUL SYLLABLE NYOD +B1F0;B1F0;1102 116D 11AF;B1F0;1102 116D 11AF; # (뇰; 뇰; 뇰; 뇰; 뇰; ) HANGUL SYLLABLE NYOL +B1F1;B1F1;1102 116D 11B0;B1F1;1102 116D 11B0; # (뇱; 뇱; 뇱; 뇱; 뇱; ) HANGUL SYLLABLE NYOLG +B1F2;B1F2;1102 116D 11B1;B1F2;1102 116D 11B1; # (뇲; 뇲; 뇲; 뇲; 뇲; ) HANGUL SYLLABLE NYOLM +B1F3;B1F3;1102 116D 11B2;B1F3;1102 116D 11B2; # (뇳; 뇳; 뇳; 뇳; 뇳; ) HANGUL SYLLABLE NYOLB +B1F4;B1F4;1102 116D 11B3;B1F4;1102 116D 11B3; # (뇴; 뇴; 뇴; 뇴; 뇴; ) HANGUL SYLLABLE NYOLS +B1F5;B1F5;1102 116D 11B4;B1F5;1102 116D 11B4; # (뇵; 뇵; 뇵; 뇵; 뇵; ) HANGUL SYLLABLE NYOLT +B1F6;B1F6;1102 116D 11B5;B1F6;1102 116D 11B5; # (뇶; 뇶; 뇶; 뇶; 뇶; ) HANGUL SYLLABLE NYOLP +B1F7;B1F7;1102 116D 11B6;B1F7;1102 116D 11B6; # (뇷; 뇷; 뇷; 뇷; 뇷; ) HANGUL SYLLABLE NYOLH +B1F8;B1F8;1102 116D 11B7;B1F8;1102 116D 11B7; # (뇸; 뇸; 뇸; 뇸; 뇸; ) HANGUL SYLLABLE NYOM +B1F9;B1F9;1102 116D 11B8;B1F9;1102 116D 11B8; # (뇹; 뇹; 뇹; 뇹; 뇹; ) HANGUL SYLLABLE NYOB +B1FA;B1FA;1102 116D 11B9;B1FA;1102 116D 11B9; # (뇺; 뇺; 뇺; 뇺; 뇺; ) HANGUL SYLLABLE NYOBS +B1FB;B1FB;1102 116D 11BA;B1FB;1102 116D 11BA; # (뇻; 뇻; 뇻; 뇻; 뇻; ) HANGUL SYLLABLE NYOS +B1FC;B1FC;1102 116D 11BB;B1FC;1102 116D 11BB; # (뇼; 뇼; 뇼; 뇼; 뇼; ) HANGUL SYLLABLE NYOSS +B1FD;B1FD;1102 116D 11BC;B1FD;1102 116D 11BC; # (뇽; 뇽; 뇽; 뇽; 뇽; ) HANGUL SYLLABLE NYONG +B1FE;B1FE;1102 116D 11BD;B1FE;1102 116D 11BD; # (뇾; 뇾; 뇾; 뇾; 뇾; ) HANGUL SYLLABLE NYOJ +B1FF;B1FF;1102 116D 11BE;B1FF;1102 116D 11BE; # (뇿; 뇿; 뇿; 뇿; 뇿; ) HANGUL SYLLABLE NYOC +B200;B200;1102 116D 11BF;B200;1102 116D 11BF; # (눀; 눀; 눀; 눀; 눀; ) HANGUL SYLLABLE NYOK +B201;B201;1102 116D 11C0;B201;1102 116D 11C0; # (눁; 눁; 눁; 눁; 눁; ) HANGUL SYLLABLE NYOT +B202;B202;1102 116D 11C1;B202;1102 116D 11C1; # (눂; 눂; 눂; 눂; 눂; ) HANGUL SYLLABLE NYOP +B203;B203;1102 116D 11C2;B203;1102 116D 11C2; # (눃; 눃; 눃; 눃; 눃; ) HANGUL SYLLABLE NYOH +B204;B204;1102 116E;B204;1102 116E; # (누; 누; 누; 누; 누; ) HANGUL SYLLABLE NU +B205;B205;1102 116E 11A8;B205;1102 116E 11A8; # (눅; 눅; 눅; 눅; 눅; ) HANGUL SYLLABLE NUG +B206;B206;1102 116E 11A9;B206;1102 116E 11A9; # (눆; 눆; 눆; 눆; 눆; ) HANGUL SYLLABLE NUGG +B207;B207;1102 116E 11AA;B207;1102 116E 11AA; # (눇; 눇; 눇; 눇; 눇; ) HANGUL SYLLABLE NUGS +B208;B208;1102 116E 11AB;B208;1102 116E 11AB; # (눈; 눈; 눈; 눈; 눈; ) HANGUL SYLLABLE NUN +B209;B209;1102 116E 11AC;B209;1102 116E 11AC; # (눉; 눉; 눉; 눉; 눉; ) HANGUL SYLLABLE NUNJ +B20A;B20A;1102 116E 11AD;B20A;1102 116E 11AD; # (눊; 눊; 눊; 눊; 눊; ) HANGUL SYLLABLE NUNH +B20B;B20B;1102 116E 11AE;B20B;1102 116E 11AE; # (눋; 눋; 눋; 눋; 눋; ) HANGUL SYLLABLE NUD +B20C;B20C;1102 116E 11AF;B20C;1102 116E 11AF; # (눌; 눌; 눌; 눌; 눌; ) HANGUL SYLLABLE NUL +B20D;B20D;1102 116E 11B0;B20D;1102 116E 11B0; # (눍; 눍; 눍; 눍; 눍; ) HANGUL SYLLABLE NULG +B20E;B20E;1102 116E 11B1;B20E;1102 116E 11B1; # (눎; 눎; 눎; 눎; 눎; ) HANGUL SYLLABLE NULM +B20F;B20F;1102 116E 11B2;B20F;1102 116E 11B2; # (눏; 눏; 눏; 눏; 눏; ) HANGUL SYLLABLE NULB +B210;B210;1102 116E 11B3;B210;1102 116E 11B3; # (눐; 눐; 눐; 눐; 눐; ) HANGUL SYLLABLE NULS +B211;B211;1102 116E 11B4;B211;1102 116E 11B4; # (눑; 눑; 눑; 눑; 눑; ) HANGUL SYLLABLE NULT +B212;B212;1102 116E 11B5;B212;1102 116E 11B5; # (눒; 눒; 눒; 눒; 눒; ) HANGUL SYLLABLE NULP +B213;B213;1102 116E 11B6;B213;1102 116E 11B6; # (눓; 눓; 눓; 눓; 눓; ) HANGUL SYLLABLE NULH +B214;B214;1102 116E 11B7;B214;1102 116E 11B7; # (눔; 눔; 눔; 눔; 눔; ) HANGUL SYLLABLE NUM +B215;B215;1102 116E 11B8;B215;1102 116E 11B8; # (눕; 눕; 눕; 눕; 눕; ) HANGUL SYLLABLE NUB +B216;B216;1102 116E 11B9;B216;1102 116E 11B9; # (눖; 눖; 눖; 눖; 눖; ) HANGUL SYLLABLE NUBS +B217;B217;1102 116E 11BA;B217;1102 116E 11BA; # (눗; 눗; 눗; 눗; 눗; ) HANGUL SYLLABLE NUS +B218;B218;1102 116E 11BB;B218;1102 116E 11BB; # (눘; 눘; 눘; 눘; 눘; ) HANGUL SYLLABLE NUSS +B219;B219;1102 116E 11BC;B219;1102 116E 11BC; # (눙; 눙; 눙; 눙; 눙; ) HANGUL SYLLABLE NUNG +B21A;B21A;1102 116E 11BD;B21A;1102 116E 11BD; # (눚; 눚; 눚; 눚; 눚; ) HANGUL SYLLABLE NUJ +B21B;B21B;1102 116E 11BE;B21B;1102 116E 11BE; # (눛; 눛; 눛; 눛; 눛; ) HANGUL SYLLABLE NUC +B21C;B21C;1102 116E 11BF;B21C;1102 116E 11BF; # (눜; 눜; 눜; 눜; 눜; ) HANGUL SYLLABLE NUK +B21D;B21D;1102 116E 11C0;B21D;1102 116E 11C0; # (눝; 눝; 눝; 눝; 눝; ) HANGUL SYLLABLE NUT +B21E;B21E;1102 116E 11C1;B21E;1102 116E 11C1; # (눞; 눞; 눞; 눞; 눞; ) HANGUL SYLLABLE NUP +B21F;B21F;1102 116E 11C2;B21F;1102 116E 11C2; # (눟; 눟; 눟; 눟; 눟; ) HANGUL SYLLABLE NUH +B220;B220;1102 116F;B220;1102 116F; # (눠; 눠; 눠; 눠; 눠; ) HANGUL SYLLABLE NWEO +B221;B221;1102 116F 11A8;B221;1102 116F 11A8; # (눡; 눡; 눡; 눡; 눡; ) HANGUL SYLLABLE NWEOG +B222;B222;1102 116F 11A9;B222;1102 116F 11A9; # (눢; 눢; 눢; 눢; 눢; ) HANGUL SYLLABLE NWEOGG +B223;B223;1102 116F 11AA;B223;1102 116F 11AA; # (눣; 눣; 눣; 눣; 눣; ) HANGUL SYLLABLE NWEOGS +B224;B224;1102 116F 11AB;B224;1102 116F 11AB; # (눤; 눤; 눤; 눤; 눤; ) HANGUL SYLLABLE NWEON +B225;B225;1102 116F 11AC;B225;1102 116F 11AC; # (눥; 눥; 눥; 눥; 눥; ) HANGUL SYLLABLE NWEONJ +B226;B226;1102 116F 11AD;B226;1102 116F 11AD; # (눦; 눦; 눦; 눦; 눦; ) HANGUL SYLLABLE NWEONH +B227;B227;1102 116F 11AE;B227;1102 116F 11AE; # (눧; 눧; 눧; 눧; 눧; ) HANGUL SYLLABLE NWEOD +B228;B228;1102 116F 11AF;B228;1102 116F 11AF; # (눨; 눨; 눨; 눨; 눨; ) HANGUL SYLLABLE NWEOL +B229;B229;1102 116F 11B0;B229;1102 116F 11B0; # (눩; 눩; 눩; 눩; 눩; ) HANGUL SYLLABLE NWEOLG +B22A;B22A;1102 116F 11B1;B22A;1102 116F 11B1; # (눪; 눪; 눪; 눪; 눪; ) HANGUL SYLLABLE NWEOLM +B22B;B22B;1102 116F 11B2;B22B;1102 116F 11B2; # (눫; 눫; 눫; 눫; 눫; ) HANGUL SYLLABLE NWEOLB +B22C;B22C;1102 116F 11B3;B22C;1102 116F 11B3; # (눬; 눬; 눬; 눬; 눬; ) HANGUL SYLLABLE NWEOLS +B22D;B22D;1102 116F 11B4;B22D;1102 116F 11B4; # (눭; 눭; 눭; 눭; 눭; ) HANGUL SYLLABLE NWEOLT +B22E;B22E;1102 116F 11B5;B22E;1102 116F 11B5; # (눮; 눮; 눮; 눮; 눮; ) HANGUL SYLLABLE NWEOLP +B22F;B22F;1102 116F 11B6;B22F;1102 116F 11B6; # (눯; 눯; 눯; 눯; 눯; ) HANGUL SYLLABLE NWEOLH +B230;B230;1102 116F 11B7;B230;1102 116F 11B7; # (눰; 눰; 눰; 눰; 눰; ) HANGUL SYLLABLE NWEOM +B231;B231;1102 116F 11B8;B231;1102 116F 11B8; # (눱; 눱; 눱; 눱; 눱; ) HANGUL SYLLABLE NWEOB +B232;B232;1102 116F 11B9;B232;1102 116F 11B9; # (눲; 눲; 눲; 눲; 눲; ) HANGUL SYLLABLE NWEOBS +B233;B233;1102 116F 11BA;B233;1102 116F 11BA; # (눳; 눳; 눳; 눳; 눳; ) HANGUL SYLLABLE NWEOS +B234;B234;1102 116F 11BB;B234;1102 116F 11BB; # (눴; 눴; 눴; 눴; 눴; ) HANGUL SYLLABLE NWEOSS +B235;B235;1102 116F 11BC;B235;1102 116F 11BC; # (눵; 눵; 눵; 눵; 눵; ) HANGUL SYLLABLE NWEONG +B236;B236;1102 116F 11BD;B236;1102 116F 11BD; # (눶; 눶; 눶; 눶; 눶; ) HANGUL SYLLABLE NWEOJ +B237;B237;1102 116F 11BE;B237;1102 116F 11BE; # (눷; 눷; 눷; 눷; 눷; ) HANGUL SYLLABLE NWEOC +B238;B238;1102 116F 11BF;B238;1102 116F 11BF; # (눸; 눸; 눸; 눸; 눸; ) HANGUL SYLLABLE NWEOK +B239;B239;1102 116F 11C0;B239;1102 116F 11C0; # (눹; 눹; 눹; 눹; 눹; ) HANGUL SYLLABLE NWEOT +B23A;B23A;1102 116F 11C1;B23A;1102 116F 11C1; # (눺; 눺; 눺; 눺; 눺; ) HANGUL SYLLABLE NWEOP +B23B;B23B;1102 116F 11C2;B23B;1102 116F 11C2; # (눻; 눻; 눻; 눻; 눻; ) HANGUL SYLLABLE NWEOH +B23C;B23C;1102 1170;B23C;1102 1170; # (눼; 눼; 눼; 눼; 눼; ) HANGUL SYLLABLE NWE +B23D;B23D;1102 1170 11A8;B23D;1102 1170 11A8; # (눽; 눽; 눽; 눽; 눽; ) HANGUL SYLLABLE NWEG +B23E;B23E;1102 1170 11A9;B23E;1102 1170 11A9; # (눾; 눾; 눾; 눾; 눾; ) HANGUL SYLLABLE NWEGG +B23F;B23F;1102 1170 11AA;B23F;1102 1170 11AA; # (눿; 눿; 눿; 눿; 눿; ) HANGUL SYLLABLE NWEGS +B240;B240;1102 1170 11AB;B240;1102 1170 11AB; # (뉀; 뉀; 뉀; 뉀; 뉀; ) HANGUL SYLLABLE NWEN +B241;B241;1102 1170 11AC;B241;1102 1170 11AC; # (뉁; 뉁; 뉁; 뉁; 뉁; ) HANGUL SYLLABLE NWENJ +B242;B242;1102 1170 11AD;B242;1102 1170 11AD; # (뉂; 뉂; 뉂; 뉂; 뉂; ) HANGUL SYLLABLE NWENH +B243;B243;1102 1170 11AE;B243;1102 1170 11AE; # (뉃; 뉃; 뉃; 뉃; 뉃; ) HANGUL SYLLABLE NWED +B244;B244;1102 1170 11AF;B244;1102 1170 11AF; # (뉄; 뉄; 뉄; 뉄; 뉄; ) HANGUL SYLLABLE NWEL +B245;B245;1102 1170 11B0;B245;1102 1170 11B0; # (뉅; 뉅; 뉅; 뉅; 뉅; ) HANGUL SYLLABLE NWELG +B246;B246;1102 1170 11B1;B246;1102 1170 11B1; # (뉆; 뉆; 뉆; 뉆; 뉆; ) HANGUL SYLLABLE NWELM +B247;B247;1102 1170 11B2;B247;1102 1170 11B2; # (뉇; 뉇; 뉇; 뉇; 뉇; ) HANGUL SYLLABLE NWELB +B248;B248;1102 1170 11B3;B248;1102 1170 11B3; # (뉈; 뉈; 뉈; 뉈; 뉈; ) HANGUL SYLLABLE NWELS +B249;B249;1102 1170 11B4;B249;1102 1170 11B4; # (뉉; 뉉; 뉉; 뉉; 뉉; ) HANGUL SYLLABLE NWELT +B24A;B24A;1102 1170 11B5;B24A;1102 1170 11B5; # (뉊; 뉊; 뉊; 뉊; 뉊; ) HANGUL SYLLABLE NWELP +B24B;B24B;1102 1170 11B6;B24B;1102 1170 11B6; # (뉋; 뉋; 뉋; 뉋; 뉋; ) HANGUL SYLLABLE NWELH +B24C;B24C;1102 1170 11B7;B24C;1102 1170 11B7; # (뉌; 뉌; 뉌; 뉌; 뉌; ) HANGUL SYLLABLE NWEM +B24D;B24D;1102 1170 11B8;B24D;1102 1170 11B8; # (뉍; 뉍; 뉍; 뉍; 뉍; ) HANGUL SYLLABLE NWEB +B24E;B24E;1102 1170 11B9;B24E;1102 1170 11B9; # (뉎; 뉎; 뉎; 뉎; 뉎; ) HANGUL SYLLABLE NWEBS +B24F;B24F;1102 1170 11BA;B24F;1102 1170 11BA; # (뉏; 뉏; 뉏; 뉏; 뉏; ) HANGUL SYLLABLE NWES +B250;B250;1102 1170 11BB;B250;1102 1170 11BB; # (뉐; 뉐; 뉐; 뉐; 뉐; ) HANGUL SYLLABLE NWESS +B251;B251;1102 1170 11BC;B251;1102 1170 11BC; # (뉑; 뉑; 뉑; 뉑; 뉑; ) HANGUL SYLLABLE NWENG +B252;B252;1102 1170 11BD;B252;1102 1170 11BD; # (뉒; 뉒; 뉒; 뉒; 뉒; ) HANGUL SYLLABLE NWEJ +B253;B253;1102 1170 11BE;B253;1102 1170 11BE; # (뉓; 뉓; 뉓; 뉓; 뉓; ) HANGUL SYLLABLE NWEC +B254;B254;1102 1170 11BF;B254;1102 1170 11BF; # (뉔; 뉔; 뉔; 뉔; 뉔; ) HANGUL SYLLABLE NWEK +B255;B255;1102 1170 11C0;B255;1102 1170 11C0; # (뉕; 뉕; 뉕; 뉕; 뉕; ) HANGUL SYLLABLE NWET +B256;B256;1102 1170 11C1;B256;1102 1170 11C1; # (뉖; 뉖; 뉖; 뉖; 뉖; ) HANGUL SYLLABLE NWEP +B257;B257;1102 1170 11C2;B257;1102 1170 11C2; # (뉗; 뉗; 뉗; 뉗; 뉗; ) HANGUL SYLLABLE NWEH +B258;B258;1102 1171;B258;1102 1171; # (뉘; 뉘; 뉘; 뉘; 뉘; ) HANGUL SYLLABLE NWI +B259;B259;1102 1171 11A8;B259;1102 1171 11A8; # (뉙; 뉙; 뉙; 뉙; 뉙; ) HANGUL SYLLABLE NWIG +B25A;B25A;1102 1171 11A9;B25A;1102 1171 11A9; # (뉚; 뉚; 뉚; 뉚; 뉚; ) HANGUL SYLLABLE NWIGG +B25B;B25B;1102 1171 11AA;B25B;1102 1171 11AA; # (뉛; 뉛; 뉛; 뉛; 뉛; ) HANGUL SYLLABLE NWIGS +B25C;B25C;1102 1171 11AB;B25C;1102 1171 11AB; # (뉜; 뉜; 뉜; 뉜; 뉜; ) HANGUL SYLLABLE NWIN +B25D;B25D;1102 1171 11AC;B25D;1102 1171 11AC; # (뉝; 뉝; 뉝; 뉝; 뉝; ) HANGUL SYLLABLE NWINJ +B25E;B25E;1102 1171 11AD;B25E;1102 1171 11AD; # (뉞; 뉞; 뉞; 뉞; 뉞; ) HANGUL SYLLABLE NWINH +B25F;B25F;1102 1171 11AE;B25F;1102 1171 11AE; # (뉟; 뉟; 뉟; 뉟; 뉟; ) HANGUL SYLLABLE NWID +B260;B260;1102 1171 11AF;B260;1102 1171 11AF; # (뉠; 뉠; 뉠; 뉠; 뉠; ) HANGUL SYLLABLE NWIL +B261;B261;1102 1171 11B0;B261;1102 1171 11B0; # (뉡; 뉡; 뉡; 뉡; 뉡; ) HANGUL SYLLABLE NWILG +B262;B262;1102 1171 11B1;B262;1102 1171 11B1; # (뉢; 뉢; 뉢; 뉢; 뉢; ) HANGUL SYLLABLE NWILM +B263;B263;1102 1171 11B2;B263;1102 1171 11B2; # (뉣; 뉣; 뉣; 뉣; 뉣; ) HANGUL SYLLABLE NWILB +B264;B264;1102 1171 11B3;B264;1102 1171 11B3; # (뉤; 뉤; 뉤; 뉤; 뉤; ) HANGUL SYLLABLE NWILS +B265;B265;1102 1171 11B4;B265;1102 1171 11B4; # (뉥; 뉥; 뉥; 뉥; 뉥; ) HANGUL SYLLABLE NWILT +B266;B266;1102 1171 11B5;B266;1102 1171 11B5; # (뉦; 뉦; 뉦; 뉦; 뉦; ) HANGUL SYLLABLE NWILP +B267;B267;1102 1171 11B6;B267;1102 1171 11B6; # (뉧; 뉧; 뉧; 뉧; 뉧; ) HANGUL SYLLABLE NWILH +B268;B268;1102 1171 11B7;B268;1102 1171 11B7; # (뉨; 뉨; 뉨; 뉨; 뉨; ) HANGUL SYLLABLE NWIM +B269;B269;1102 1171 11B8;B269;1102 1171 11B8; # (뉩; 뉩; 뉩; 뉩; 뉩; ) HANGUL SYLLABLE NWIB +B26A;B26A;1102 1171 11B9;B26A;1102 1171 11B9; # (뉪; 뉪; 뉪; 뉪; 뉪; ) HANGUL SYLLABLE NWIBS +B26B;B26B;1102 1171 11BA;B26B;1102 1171 11BA; # (뉫; 뉫; 뉫; 뉫; 뉫; ) HANGUL SYLLABLE NWIS +B26C;B26C;1102 1171 11BB;B26C;1102 1171 11BB; # (뉬; 뉬; 뉬; 뉬; 뉬; ) HANGUL SYLLABLE NWISS +B26D;B26D;1102 1171 11BC;B26D;1102 1171 11BC; # (뉭; 뉭; 뉭; 뉭; 뉭; ) HANGUL SYLLABLE NWING +B26E;B26E;1102 1171 11BD;B26E;1102 1171 11BD; # (뉮; 뉮; 뉮; 뉮; 뉮; ) HANGUL SYLLABLE NWIJ +B26F;B26F;1102 1171 11BE;B26F;1102 1171 11BE; # (뉯; 뉯; 뉯; 뉯; 뉯; ) HANGUL SYLLABLE NWIC +B270;B270;1102 1171 11BF;B270;1102 1171 11BF; # (뉰; 뉰; 뉰; 뉰; 뉰; ) HANGUL SYLLABLE NWIK +B271;B271;1102 1171 11C0;B271;1102 1171 11C0; # (뉱; 뉱; 뉱; 뉱; 뉱; ) HANGUL SYLLABLE NWIT +B272;B272;1102 1171 11C1;B272;1102 1171 11C1; # (뉲; 뉲; 뉲; 뉲; 뉲; ) HANGUL SYLLABLE NWIP +B273;B273;1102 1171 11C2;B273;1102 1171 11C2; # (뉳; 뉳; 뉳; 뉳; 뉳; ) HANGUL SYLLABLE NWIH +B274;B274;1102 1172;B274;1102 1172; # (뉴; 뉴; 뉴; 뉴; 뉴; ) HANGUL SYLLABLE NYU +B275;B275;1102 1172 11A8;B275;1102 1172 11A8; # (뉵; 뉵; 뉵; 뉵; 뉵; ) HANGUL SYLLABLE NYUG +B276;B276;1102 1172 11A9;B276;1102 1172 11A9; # (뉶; 뉶; 뉶; 뉶; 뉶; ) HANGUL SYLLABLE NYUGG +B277;B277;1102 1172 11AA;B277;1102 1172 11AA; # (뉷; 뉷; 뉷; 뉷; 뉷; ) HANGUL SYLLABLE NYUGS +B278;B278;1102 1172 11AB;B278;1102 1172 11AB; # (뉸; 뉸; 뉸; 뉸; 뉸; ) HANGUL SYLLABLE NYUN +B279;B279;1102 1172 11AC;B279;1102 1172 11AC; # (뉹; 뉹; 뉹; 뉹; 뉹; ) HANGUL SYLLABLE NYUNJ +B27A;B27A;1102 1172 11AD;B27A;1102 1172 11AD; # (뉺; 뉺; 뉺; 뉺; 뉺; ) HANGUL SYLLABLE NYUNH +B27B;B27B;1102 1172 11AE;B27B;1102 1172 11AE; # (뉻; 뉻; 뉻; 뉻; 뉻; ) HANGUL SYLLABLE NYUD +B27C;B27C;1102 1172 11AF;B27C;1102 1172 11AF; # (뉼; 뉼; 뉼; 뉼; 뉼; ) HANGUL SYLLABLE NYUL +B27D;B27D;1102 1172 11B0;B27D;1102 1172 11B0; # (뉽; 뉽; 뉽; 뉽; 뉽; ) HANGUL SYLLABLE NYULG +B27E;B27E;1102 1172 11B1;B27E;1102 1172 11B1; # (뉾; 뉾; 뉾; 뉾; 뉾; ) HANGUL SYLLABLE NYULM +B27F;B27F;1102 1172 11B2;B27F;1102 1172 11B2; # (뉿; 뉿; 뉿; 뉿; 뉿; ) HANGUL SYLLABLE NYULB +B280;B280;1102 1172 11B3;B280;1102 1172 11B3; # (늀; 늀; 늀; 늀; 늀; ) HANGUL SYLLABLE NYULS +B281;B281;1102 1172 11B4;B281;1102 1172 11B4; # (늁; 늁; 늁; 늁; 늁; ) HANGUL SYLLABLE NYULT +B282;B282;1102 1172 11B5;B282;1102 1172 11B5; # (늂; 늂; 늂; 늂; 늂; ) HANGUL SYLLABLE NYULP +B283;B283;1102 1172 11B6;B283;1102 1172 11B6; # (늃; 늃; 늃; 늃; 늃; ) HANGUL SYLLABLE NYULH +B284;B284;1102 1172 11B7;B284;1102 1172 11B7; # (늄; 늄; 늄; 늄; 늄; ) HANGUL SYLLABLE NYUM +B285;B285;1102 1172 11B8;B285;1102 1172 11B8; # (늅; 늅; 늅; 늅; 늅; ) HANGUL SYLLABLE NYUB +B286;B286;1102 1172 11B9;B286;1102 1172 11B9; # (늆; 늆; 늆; 늆; 늆; ) HANGUL SYLLABLE NYUBS +B287;B287;1102 1172 11BA;B287;1102 1172 11BA; # (늇; 늇; 늇; 늇; 늇; ) HANGUL SYLLABLE NYUS +B288;B288;1102 1172 11BB;B288;1102 1172 11BB; # (늈; 늈; 늈; 늈; 늈; ) HANGUL SYLLABLE NYUSS +B289;B289;1102 1172 11BC;B289;1102 1172 11BC; # (늉; 늉; 늉; 늉; 늉; ) HANGUL SYLLABLE NYUNG +B28A;B28A;1102 1172 11BD;B28A;1102 1172 11BD; # (늊; 늊; 늊; 늊; 늊; ) HANGUL SYLLABLE NYUJ +B28B;B28B;1102 1172 11BE;B28B;1102 1172 11BE; # (늋; 늋; 늋; 늋; 늋; ) HANGUL SYLLABLE NYUC +B28C;B28C;1102 1172 11BF;B28C;1102 1172 11BF; # (늌; 늌; 늌; 늌; 늌; ) HANGUL SYLLABLE NYUK +B28D;B28D;1102 1172 11C0;B28D;1102 1172 11C0; # (늍; 늍; 늍; 늍; 늍; ) HANGUL SYLLABLE NYUT +B28E;B28E;1102 1172 11C1;B28E;1102 1172 11C1; # (늎; 늎; 늎; 늎; 늎; ) HANGUL SYLLABLE NYUP +B28F;B28F;1102 1172 11C2;B28F;1102 1172 11C2; # (늏; 늏; 늏; 늏; 늏; ) HANGUL SYLLABLE NYUH +B290;B290;1102 1173;B290;1102 1173; # (느; 느; 느; 느; 느; ) HANGUL SYLLABLE NEU +B291;B291;1102 1173 11A8;B291;1102 1173 11A8; # (늑; 늑; 늑; 늑; 늑; ) HANGUL SYLLABLE NEUG +B292;B292;1102 1173 11A9;B292;1102 1173 11A9; # (늒; 늒; 늒; 늒; 늒; ) HANGUL SYLLABLE NEUGG +B293;B293;1102 1173 11AA;B293;1102 1173 11AA; # (늓; 늓; 늓; 늓; 늓; ) HANGUL SYLLABLE NEUGS +B294;B294;1102 1173 11AB;B294;1102 1173 11AB; # (는; 는; 는; 는; 는; ) HANGUL SYLLABLE NEUN +B295;B295;1102 1173 11AC;B295;1102 1173 11AC; # (늕; 늕; 늕; 늕; 늕; ) HANGUL SYLLABLE NEUNJ +B296;B296;1102 1173 11AD;B296;1102 1173 11AD; # (늖; 늖; 늖; 늖; 늖; ) HANGUL SYLLABLE NEUNH +B297;B297;1102 1173 11AE;B297;1102 1173 11AE; # (늗; 늗; 늗; 늗; 늗; ) HANGUL SYLLABLE NEUD +B298;B298;1102 1173 11AF;B298;1102 1173 11AF; # (늘; 늘; 늘; 늘; 늘; ) HANGUL SYLLABLE NEUL +B299;B299;1102 1173 11B0;B299;1102 1173 11B0; # (늙; 늙; 늙; 늙; 늙; ) HANGUL SYLLABLE NEULG +B29A;B29A;1102 1173 11B1;B29A;1102 1173 11B1; # (늚; 늚; 늚; 늚; 늚; ) HANGUL SYLLABLE NEULM +B29B;B29B;1102 1173 11B2;B29B;1102 1173 11B2; # (늛; 늛; 늛; 늛; 늛; ) HANGUL SYLLABLE NEULB +B29C;B29C;1102 1173 11B3;B29C;1102 1173 11B3; # (늜; 늜; 늜; 늜; 늜; ) HANGUL SYLLABLE NEULS +B29D;B29D;1102 1173 11B4;B29D;1102 1173 11B4; # (늝; 늝; 늝; 늝; 늝; ) HANGUL SYLLABLE NEULT +B29E;B29E;1102 1173 11B5;B29E;1102 1173 11B5; # (늞; 늞; 늞; 늞; 늞; ) HANGUL SYLLABLE NEULP +B29F;B29F;1102 1173 11B6;B29F;1102 1173 11B6; # (늟; 늟; 늟; 늟; 늟; ) HANGUL SYLLABLE NEULH +B2A0;B2A0;1102 1173 11B7;B2A0;1102 1173 11B7; # (늠; 늠; 늠; 늠; 늠; ) HANGUL SYLLABLE NEUM +B2A1;B2A1;1102 1173 11B8;B2A1;1102 1173 11B8; # (늡; 늡; 늡; 늡; 늡; ) HANGUL SYLLABLE NEUB +B2A2;B2A2;1102 1173 11B9;B2A2;1102 1173 11B9; # (늢; 늢; 늢; 늢; 늢; ) HANGUL SYLLABLE NEUBS +B2A3;B2A3;1102 1173 11BA;B2A3;1102 1173 11BA; # (늣; 늣; 늣; 늣; 늣; ) HANGUL SYLLABLE NEUS +B2A4;B2A4;1102 1173 11BB;B2A4;1102 1173 11BB; # (늤; 늤; 늤; 늤; 늤; ) HANGUL SYLLABLE NEUSS +B2A5;B2A5;1102 1173 11BC;B2A5;1102 1173 11BC; # (능; 능; 능; 능; 능; ) HANGUL SYLLABLE NEUNG +B2A6;B2A6;1102 1173 11BD;B2A6;1102 1173 11BD; # (늦; 늦; 늦; 늦; 늦; ) HANGUL SYLLABLE NEUJ +B2A7;B2A7;1102 1173 11BE;B2A7;1102 1173 11BE; # (늧; 늧; 늧; 늧; 늧; ) HANGUL SYLLABLE NEUC +B2A8;B2A8;1102 1173 11BF;B2A8;1102 1173 11BF; # (늨; 늨; 늨; 늨; 늨; ) HANGUL SYLLABLE NEUK +B2A9;B2A9;1102 1173 11C0;B2A9;1102 1173 11C0; # (늩; 늩; 늩; 늩; 늩; ) HANGUL SYLLABLE NEUT +B2AA;B2AA;1102 1173 11C1;B2AA;1102 1173 11C1; # (늪; 늪; 늪; 늪; 늪; ) HANGUL SYLLABLE NEUP +B2AB;B2AB;1102 1173 11C2;B2AB;1102 1173 11C2; # (늫; 늫; 늫; 늫; 늫; ) HANGUL SYLLABLE NEUH +B2AC;B2AC;1102 1174;B2AC;1102 1174; # (늬; 늬; 늬; 늬; 늬; ) HANGUL SYLLABLE NYI +B2AD;B2AD;1102 1174 11A8;B2AD;1102 1174 11A8; # (늭; 늭; 늭; 늭; 늭; ) HANGUL SYLLABLE NYIG +B2AE;B2AE;1102 1174 11A9;B2AE;1102 1174 11A9; # (늮; 늮; 늮; 늮; 늮; ) HANGUL SYLLABLE NYIGG +B2AF;B2AF;1102 1174 11AA;B2AF;1102 1174 11AA; # (늯; 늯; 늯; 늯; 늯; ) HANGUL SYLLABLE NYIGS +B2B0;B2B0;1102 1174 11AB;B2B0;1102 1174 11AB; # (늰; 늰; 늰; 늰; 늰; ) HANGUL SYLLABLE NYIN +B2B1;B2B1;1102 1174 11AC;B2B1;1102 1174 11AC; # (늱; 늱; 늱; 늱; 늱; ) HANGUL SYLLABLE NYINJ +B2B2;B2B2;1102 1174 11AD;B2B2;1102 1174 11AD; # (늲; 늲; 늲; 늲; 늲; ) HANGUL SYLLABLE NYINH +B2B3;B2B3;1102 1174 11AE;B2B3;1102 1174 11AE; # (늳; 늳; 늳; 늳; 늳; ) HANGUL SYLLABLE NYID +B2B4;B2B4;1102 1174 11AF;B2B4;1102 1174 11AF; # (늴; 늴; 늴; 늴; 늴; ) HANGUL SYLLABLE NYIL +B2B5;B2B5;1102 1174 11B0;B2B5;1102 1174 11B0; # (늵; 늵; 늵; 늵; 늵; ) HANGUL SYLLABLE NYILG +B2B6;B2B6;1102 1174 11B1;B2B6;1102 1174 11B1; # (늶; 늶; 늶; 늶; 늶; ) HANGUL SYLLABLE NYILM +B2B7;B2B7;1102 1174 11B2;B2B7;1102 1174 11B2; # (늷; 늷; 늷; 늷; 늷; ) HANGUL SYLLABLE NYILB +B2B8;B2B8;1102 1174 11B3;B2B8;1102 1174 11B3; # (늸; 늸; 늸; 늸; 늸; ) HANGUL SYLLABLE NYILS +B2B9;B2B9;1102 1174 11B4;B2B9;1102 1174 11B4; # (늹; 늹; 늹; 늹; 늹; ) HANGUL SYLLABLE NYILT +B2BA;B2BA;1102 1174 11B5;B2BA;1102 1174 11B5; # (늺; 늺; 늺; 늺; 늺; ) HANGUL SYLLABLE NYILP +B2BB;B2BB;1102 1174 11B6;B2BB;1102 1174 11B6; # (늻; 늻; 늻; 늻; 늻; ) HANGUL SYLLABLE NYILH +B2BC;B2BC;1102 1174 11B7;B2BC;1102 1174 11B7; # (늼; 늼; 늼; 늼; 늼; ) HANGUL SYLLABLE NYIM +B2BD;B2BD;1102 1174 11B8;B2BD;1102 1174 11B8; # (늽; 늽; 늽; 늽; 늽; ) HANGUL SYLLABLE NYIB +B2BE;B2BE;1102 1174 11B9;B2BE;1102 1174 11B9; # (늾; 늾; 늾; 늾; 늾; ) HANGUL SYLLABLE NYIBS +B2BF;B2BF;1102 1174 11BA;B2BF;1102 1174 11BA; # (늿; 늿; 늿; 늿; 늿; ) HANGUL SYLLABLE NYIS +B2C0;B2C0;1102 1174 11BB;B2C0;1102 1174 11BB; # (닀; 닀; 닀; 닀; 닀; ) HANGUL SYLLABLE NYISS +B2C1;B2C1;1102 1174 11BC;B2C1;1102 1174 11BC; # (닁; 닁; 닁; 닁; 닁; ) HANGUL SYLLABLE NYING +B2C2;B2C2;1102 1174 11BD;B2C2;1102 1174 11BD; # (닂; 닂; 닂; 닂; 닂; ) HANGUL SYLLABLE NYIJ +B2C3;B2C3;1102 1174 11BE;B2C3;1102 1174 11BE; # (닃; 닃; 닃; 닃; 닃; ) HANGUL SYLLABLE NYIC +B2C4;B2C4;1102 1174 11BF;B2C4;1102 1174 11BF; # (닄; 닄; 닄; 닄; 닄; ) HANGUL SYLLABLE NYIK +B2C5;B2C5;1102 1174 11C0;B2C5;1102 1174 11C0; # (닅; 닅; 닅; 닅; 닅; ) HANGUL SYLLABLE NYIT +B2C6;B2C6;1102 1174 11C1;B2C6;1102 1174 11C1; # (닆; 닆; 닆; 닆; 닆; ) HANGUL SYLLABLE NYIP +B2C7;B2C7;1102 1174 11C2;B2C7;1102 1174 11C2; # (닇; 닇; 닇; 닇; 닇; ) HANGUL SYLLABLE NYIH +B2C8;B2C8;1102 1175;B2C8;1102 1175; # (니; 니; 니; 니; 니; ) HANGUL SYLLABLE NI +B2C9;B2C9;1102 1175 11A8;B2C9;1102 1175 11A8; # (닉; 닉; 닉; 닉; 닉; ) HANGUL SYLLABLE NIG +B2CA;B2CA;1102 1175 11A9;B2CA;1102 1175 11A9; # (닊; 닊; 닊; 닊; 닊; ) HANGUL SYLLABLE NIGG +B2CB;B2CB;1102 1175 11AA;B2CB;1102 1175 11AA; # (닋; 닋; 닋; 닋; 닋; ) HANGUL SYLLABLE NIGS +B2CC;B2CC;1102 1175 11AB;B2CC;1102 1175 11AB; # (닌; 닌; 닌; 닌; 닌; ) HANGUL SYLLABLE NIN +B2CD;B2CD;1102 1175 11AC;B2CD;1102 1175 11AC; # (닍; 닍; 닍; 닍; 닍; ) HANGUL SYLLABLE NINJ +B2CE;B2CE;1102 1175 11AD;B2CE;1102 1175 11AD; # (닎; 닎; 닎; 닎; 닎; ) HANGUL SYLLABLE NINH +B2CF;B2CF;1102 1175 11AE;B2CF;1102 1175 11AE; # (닏; 닏; 닏; 닏; 닏; ) HANGUL SYLLABLE NID +B2D0;B2D0;1102 1175 11AF;B2D0;1102 1175 11AF; # (닐; 닐; 닐; 닐; 닐; ) HANGUL SYLLABLE NIL +B2D1;B2D1;1102 1175 11B0;B2D1;1102 1175 11B0; # (닑; 닑; 닑; 닑; 닑; ) HANGUL SYLLABLE NILG +B2D2;B2D2;1102 1175 11B1;B2D2;1102 1175 11B1; # (닒; 닒; 닒; 닒; 닒; ) HANGUL SYLLABLE NILM +B2D3;B2D3;1102 1175 11B2;B2D3;1102 1175 11B2; # (닓; 닓; 닓; 닓; 닓; ) HANGUL SYLLABLE NILB +B2D4;B2D4;1102 1175 11B3;B2D4;1102 1175 11B3; # (닔; 닔; 닔; 닔; 닔; ) HANGUL SYLLABLE NILS +B2D5;B2D5;1102 1175 11B4;B2D5;1102 1175 11B4; # (닕; 닕; 닕; 닕; 닕; ) HANGUL SYLLABLE NILT +B2D6;B2D6;1102 1175 11B5;B2D6;1102 1175 11B5; # (닖; 닖; 닖; 닖; 닖; ) HANGUL SYLLABLE NILP +B2D7;B2D7;1102 1175 11B6;B2D7;1102 1175 11B6; # (닗; 닗; 닗; 닗; 닗; ) HANGUL SYLLABLE NILH +B2D8;B2D8;1102 1175 11B7;B2D8;1102 1175 11B7; # (님; 님; 님; 님; 님; ) HANGUL SYLLABLE NIM +B2D9;B2D9;1102 1175 11B8;B2D9;1102 1175 11B8; # (닙; 닙; 닙; 닙; 닙; ) HANGUL SYLLABLE NIB +B2DA;B2DA;1102 1175 11B9;B2DA;1102 1175 11B9; # (닚; 닚; 닚; 닚; 닚; ) HANGUL SYLLABLE NIBS +B2DB;B2DB;1102 1175 11BA;B2DB;1102 1175 11BA; # (닛; 닛; 닛; 닛; 닛; ) HANGUL SYLLABLE NIS +B2DC;B2DC;1102 1175 11BB;B2DC;1102 1175 11BB; # (닜; 닜; 닜; 닜; 닜; ) HANGUL SYLLABLE NISS +B2DD;B2DD;1102 1175 11BC;B2DD;1102 1175 11BC; # (닝; 닝; 닝; 닝; 닝; ) HANGUL SYLLABLE NING +B2DE;B2DE;1102 1175 11BD;B2DE;1102 1175 11BD; # (닞; 닞; 닞; 닞; 닞; ) HANGUL SYLLABLE NIJ +B2DF;B2DF;1102 1175 11BE;B2DF;1102 1175 11BE; # (닟; 닟; 닟; 닟; 닟; ) HANGUL SYLLABLE NIC +B2E0;B2E0;1102 1175 11BF;B2E0;1102 1175 11BF; # (닠; 닠; 닠; 닠; 닠; ) HANGUL SYLLABLE NIK +B2E1;B2E1;1102 1175 11C0;B2E1;1102 1175 11C0; # (닡; 닡; 닡; 닡; 닡; ) HANGUL SYLLABLE NIT +B2E2;B2E2;1102 1175 11C1;B2E2;1102 1175 11C1; # (닢; 닢; 닢; 닢; 닢; ) HANGUL SYLLABLE NIP +B2E3;B2E3;1102 1175 11C2;B2E3;1102 1175 11C2; # (닣; 닣; 닣; 닣; 닣; ) HANGUL SYLLABLE NIH +B2E4;B2E4;1103 1161;B2E4;1103 1161; # (다; 다; 다; 다; 다; ) HANGUL SYLLABLE DA +B2E5;B2E5;1103 1161 11A8;B2E5;1103 1161 11A8; # (닥; 닥; 닥; 닥; 닥; ) HANGUL SYLLABLE DAG +B2E6;B2E6;1103 1161 11A9;B2E6;1103 1161 11A9; # (닦; 닦; 닦; 닦; 닦; ) HANGUL SYLLABLE DAGG +B2E7;B2E7;1103 1161 11AA;B2E7;1103 1161 11AA; # (닧; 닧; 닧; 닧; 닧; ) HANGUL SYLLABLE DAGS +B2E8;B2E8;1103 1161 11AB;B2E8;1103 1161 11AB; # (단; 단; 단; 단; 단; ) HANGUL SYLLABLE DAN +B2E9;B2E9;1103 1161 11AC;B2E9;1103 1161 11AC; # (닩; 닩; 닩; 닩; 닩; ) HANGUL SYLLABLE DANJ +B2EA;B2EA;1103 1161 11AD;B2EA;1103 1161 11AD; # (닪; 닪; 닪; 닪; 닪; ) HANGUL SYLLABLE DANH +B2EB;B2EB;1103 1161 11AE;B2EB;1103 1161 11AE; # (닫; 닫; 닫; 닫; 닫; ) HANGUL SYLLABLE DAD +B2EC;B2EC;1103 1161 11AF;B2EC;1103 1161 11AF; # (달; 달; 달; 달; 달; ) HANGUL SYLLABLE DAL +B2ED;B2ED;1103 1161 11B0;B2ED;1103 1161 11B0; # (닭; 닭; 닭; 닭; 닭; ) HANGUL SYLLABLE DALG +B2EE;B2EE;1103 1161 11B1;B2EE;1103 1161 11B1; # (닮; 닮; 닮; 닮; 닮; ) HANGUL SYLLABLE DALM +B2EF;B2EF;1103 1161 11B2;B2EF;1103 1161 11B2; # (닯; 닯; 닯; 닯; 닯; ) HANGUL SYLLABLE DALB +B2F0;B2F0;1103 1161 11B3;B2F0;1103 1161 11B3; # (닰; 닰; 닰; 닰; 닰; ) HANGUL SYLLABLE DALS +B2F1;B2F1;1103 1161 11B4;B2F1;1103 1161 11B4; # (닱; 닱; 닱; 닱; 닱; ) HANGUL SYLLABLE DALT +B2F2;B2F2;1103 1161 11B5;B2F2;1103 1161 11B5; # (닲; 닲; 닲; 닲; 닲; ) HANGUL SYLLABLE DALP +B2F3;B2F3;1103 1161 11B6;B2F3;1103 1161 11B6; # (닳; 닳; 닳; 닳; 닳; ) HANGUL SYLLABLE DALH +B2F4;B2F4;1103 1161 11B7;B2F4;1103 1161 11B7; # (담; 담; 담; 담; 담; ) HANGUL SYLLABLE DAM +B2F5;B2F5;1103 1161 11B8;B2F5;1103 1161 11B8; # (답; 답; 답; 답; 답; ) HANGUL SYLLABLE DAB +B2F6;B2F6;1103 1161 11B9;B2F6;1103 1161 11B9; # (닶; 닶; 닶; 닶; 닶; ) HANGUL SYLLABLE DABS +B2F7;B2F7;1103 1161 11BA;B2F7;1103 1161 11BA; # (닷; 닷; 닷; 닷; 닷; ) HANGUL SYLLABLE DAS +B2F8;B2F8;1103 1161 11BB;B2F8;1103 1161 11BB; # (닸; 닸; 닸; 닸; 닸; ) HANGUL SYLLABLE DASS +B2F9;B2F9;1103 1161 11BC;B2F9;1103 1161 11BC; # (당; 당; 당; 당; 당; ) HANGUL SYLLABLE DANG +B2FA;B2FA;1103 1161 11BD;B2FA;1103 1161 11BD; # (닺; 닺; 닺; 닺; 닺; ) HANGUL SYLLABLE DAJ +B2FB;B2FB;1103 1161 11BE;B2FB;1103 1161 11BE; # (닻; 닻; 닻; 닻; 닻; ) HANGUL SYLLABLE DAC +B2FC;B2FC;1103 1161 11BF;B2FC;1103 1161 11BF; # (닼; 닼; 닼; 닼; 닼; ) HANGUL SYLLABLE DAK +B2FD;B2FD;1103 1161 11C0;B2FD;1103 1161 11C0; # (닽; 닽; 닽; 닽; 닽; ) HANGUL SYLLABLE DAT +B2FE;B2FE;1103 1161 11C1;B2FE;1103 1161 11C1; # (닾; 닾; 닾; 닾; 닾; ) HANGUL SYLLABLE DAP +B2FF;B2FF;1103 1161 11C2;B2FF;1103 1161 11C2; # (닿; 닿; 닿; 닿; 닿; ) HANGUL SYLLABLE DAH +B300;B300;1103 1162;B300;1103 1162; # (대; 대; 대; 대; 대; ) HANGUL SYLLABLE DAE +B301;B301;1103 1162 11A8;B301;1103 1162 11A8; # (댁; 댁; 댁; 댁; 댁; ) HANGUL SYLLABLE DAEG +B302;B302;1103 1162 11A9;B302;1103 1162 11A9; # (댂; 댂; 댂; 댂; 댂; ) HANGUL SYLLABLE DAEGG +B303;B303;1103 1162 11AA;B303;1103 1162 11AA; # (댃; 댃; 댃; 댃; 댃; ) HANGUL SYLLABLE DAEGS +B304;B304;1103 1162 11AB;B304;1103 1162 11AB; # (댄; 댄; 댄; 댄; 댄; ) HANGUL SYLLABLE DAEN +B305;B305;1103 1162 11AC;B305;1103 1162 11AC; # (댅; 댅; 댅; 댅; 댅; ) HANGUL SYLLABLE DAENJ +B306;B306;1103 1162 11AD;B306;1103 1162 11AD; # (댆; 댆; 댆; 댆; 댆; ) HANGUL SYLLABLE DAENH +B307;B307;1103 1162 11AE;B307;1103 1162 11AE; # (댇; 댇; 댇; 댇; 댇; ) HANGUL SYLLABLE DAED +B308;B308;1103 1162 11AF;B308;1103 1162 11AF; # (댈; 댈; 댈; 댈; 댈; ) HANGUL SYLLABLE DAEL +B309;B309;1103 1162 11B0;B309;1103 1162 11B0; # (댉; 댉; 댉; 댉; 댉; ) HANGUL SYLLABLE DAELG +B30A;B30A;1103 1162 11B1;B30A;1103 1162 11B1; # (댊; 댊; 댊; 댊; 댊; ) HANGUL SYLLABLE DAELM +B30B;B30B;1103 1162 11B2;B30B;1103 1162 11B2; # (댋; 댋; 댋; 댋; 댋; ) HANGUL SYLLABLE DAELB +B30C;B30C;1103 1162 11B3;B30C;1103 1162 11B3; # (댌; 댌; 댌; 댌; 댌; ) HANGUL SYLLABLE DAELS +B30D;B30D;1103 1162 11B4;B30D;1103 1162 11B4; # (댍; 댍; 댍; 댍; 댍; ) HANGUL SYLLABLE DAELT +B30E;B30E;1103 1162 11B5;B30E;1103 1162 11B5; # (댎; 댎; 댎; 댎; 댎; ) HANGUL SYLLABLE DAELP +B30F;B30F;1103 1162 11B6;B30F;1103 1162 11B6; # (댏; 댏; 댏; 댏; 댏; ) HANGUL SYLLABLE DAELH +B310;B310;1103 1162 11B7;B310;1103 1162 11B7; # (댐; 댐; 댐; 댐; 댐; ) HANGUL SYLLABLE DAEM +B311;B311;1103 1162 11B8;B311;1103 1162 11B8; # (댑; 댑; 댑; 댑; 댑; ) HANGUL SYLLABLE DAEB +B312;B312;1103 1162 11B9;B312;1103 1162 11B9; # (댒; 댒; 댒; 댒; 댒; ) HANGUL SYLLABLE DAEBS +B313;B313;1103 1162 11BA;B313;1103 1162 11BA; # (댓; 댓; 댓; 댓; 댓; ) HANGUL SYLLABLE DAES +B314;B314;1103 1162 11BB;B314;1103 1162 11BB; # (댔; 댔; 댔; 댔; 댔; ) HANGUL SYLLABLE DAESS +B315;B315;1103 1162 11BC;B315;1103 1162 11BC; # (댕; 댕; 댕; 댕; 댕; ) HANGUL SYLLABLE DAENG +B316;B316;1103 1162 11BD;B316;1103 1162 11BD; # (댖; 댖; 댖; 댖; 댖; ) HANGUL SYLLABLE DAEJ +B317;B317;1103 1162 11BE;B317;1103 1162 11BE; # (댗; 댗; 댗; 댗; 댗; ) HANGUL SYLLABLE DAEC +B318;B318;1103 1162 11BF;B318;1103 1162 11BF; # (댘; 댘; 댘; 댘; 댘; ) HANGUL SYLLABLE DAEK +B319;B319;1103 1162 11C0;B319;1103 1162 11C0; # (댙; 댙; 댙; 댙; 댙; ) HANGUL SYLLABLE DAET +B31A;B31A;1103 1162 11C1;B31A;1103 1162 11C1; # (댚; 댚; 댚; 댚; 댚; ) HANGUL SYLLABLE DAEP +B31B;B31B;1103 1162 11C2;B31B;1103 1162 11C2; # (댛; 댛; 댛; 댛; 댛; ) HANGUL SYLLABLE DAEH +B31C;B31C;1103 1163;B31C;1103 1163; # (댜; 댜; 댜; 댜; 댜; ) HANGUL SYLLABLE DYA +B31D;B31D;1103 1163 11A8;B31D;1103 1163 11A8; # (댝; 댝; 댝; 댝; 댝; ) HANGUL SYLLABLE DYAG +B31E;B31E;1103 1163 11A9;B31E;1103 1163 11A9; # (댞; 댞; 댞; 댞; 댞; ) HANGUL SYLLABLE DYAGG +B31F;B31F;1103 1163 11AA;B31F;1103 1163 11AA; # (댟; 댟; 댟; 댟; 댟; ) HANGUL SYLLABLE DYAGS +B320;B320;1103 1163 11AB;B320;1103 1163 11AB; # (댠; 댠; 댠; 댠; 댠; ) HANGUL SYLLABLE DYAN +B321;B321;1103 1163 11AC;B321;1103 1163 11AC; # (댡; 댡; 댡; 댡; 댡; ) HANGUL SYLLABLE DYANJ +B322;B322;1103 1163 11AD;B322;1103 1163 11AD; # (댢; 댢; 댢; 댢; 댢; ) HANGUL SYLLABLE DYANH +B323;B323;1103 1163 11AE;B323;1103 1163 11AE; # (댣; 댣; 댣; 댣; 댣; ) HANGUL SYLLABLE DYAD +B324;B324;1103 1163 11AF;B324;1103 1163 11AF; # (댤; 댤; 댤; 댤; 댤; ) HANGUL SYLLABLE DYAL +B325;B325;1103 1163 11B0;B325;1103 1163 11B0; # (댥; 댥; 댥; 댥; 댥; ) HANGUL SYLLABLE DYALG +B326;B326;1103 1163 11B1;B326;1103 1163 11B1; # (댦; 댦; 댦; 댦; 댦; ) HANGUL SYLLABLE DYALM +B327;B327;1103 1163 11B2;B327;1103 1163 11B2; # (댧; 댧; 댧; 댧; 댧; ) HANGUL SYLLABLE DYALB +B328;B328;1103 1163 11B3;B328;1103 1163 11B3; # (댨; 댨; 댨; 댨; 댨; ) HANGUL SYLLABLE DYALS +B329;B329;1103 1163 11B4;B329;1103 1163 11B4; # (댩; 댩; 댩; 댩; 댩; ) HANGUL SYLLABLE DYALT +B32A;B32A;1103 1163 11B5;B32A;1103 1163 11B5; # (댪; 댪; 댪; 댪; 댪; ) HANGUL SYLLABLE DYALP +B32B;B32B;1103 1163 11B6;B32B;1103 1163 11B6; # (댫; 댫; 댫; 댫; 댫; ) HANGUL SYLLABLE DYALH +B32C;B32C;1103 1163 11B7;B32C;1103 1163 11B7; # (댬; 댬; 댬; 댬; 댬; ) HANGUL SYLLABLE DYAM +B32D;B32D;1103 1163 11B8;B32D;1103 1163 11B8; # (댭; 댭; 댭; 댭; 댭; ) HANGUL SYLLABLE DYAB +B32E;B32E;1103 1163 11B9;B32E;1103 1163 11B9; # (댮; 댮; 댮; 댮; 댮; ) HANGUL SYLLABLE DYABS +B32F;B32F;1103 1163 11BA;B32F;1103 1163 11BA; # (댯; 댯; 댯; 댯; 댯; ) HANGUL SYLLABLE DYAS +B330;B330;1103 1163 11BB;B330;1103 1163 11BB; # (댰; 댰; 댰; 댰; 댰; ) HANGUL SYLLABLE DYASS +B331;B331;1103 1163 11BC;B331;1103 1163 11BC; # (댱; 댱; 댱; 댱; 댱; ) HANGUL SYLLABLE DYANG +B332;B332;1103 1163 11BD;B332;1103 1163 11BD; # (댲; 댲; 댲; 댲; 댲; ) HANGUL SYLLABLE DYAJ +B333;B333;1103 1163 11BE;B333;1103 1163 11BE; # (댳; 댳; 댳; 댳; 댳; ) HANGUL SYLLABLE DYAC +B334;B334;1103 1163 11BF;B334;1103 1163 11BF; # (댴; 댴; 댴; 댴; 댴; ) HANGUL SYLLABLE DYAK +B335;B335;1103 1163 11C0;B335;1103 1163 11C0; # (댵; 댵; 댵; 댵; 댵; ) HANGUL SYLLABLE DYAT +B336;B336;1103 1163 11C1;B336;1103 1163 11C1; # (댶; 댶; 댶; 댶; 댶; ) HANGUL SYLLABLE DYAP +B337;B337;1103 1163 11C2;B337;1103 1163 11C2; # (댷; 댷; 댷; 댷; 댷; ) HANGUL SYLLABLE DYAH +B338;B338;1103 1164;B338;1103 1164; # (댸; 댸; 댸; 댸; 댸; ) HANGUL SYLLABLE DYAE +B339;B339;1103 1164 11A8;B339;1103 1164 11A8; # (댹; 댹; 댹; 댹; 댹; ) HANGUL SYLLABLE DYAEG +B33A;B33A;1103 1164 11A9;B33A;1103 1164 11A9; # (댺; 댺; 댺; 댺; 댺; ) HANGUL SYLLABLE DYAEGG +B33B;B33B;1103 1164 11AA;B33B;1103 1164 11AA; # (댻; 댻; 댻; 댻; 댻; ) HANGUL SYLLABLE DYAEGS +B33C;B33C;1103 1164 11AB;B33C;1103 1164 11AB; # (댼; 댼; 댼; 댼; 댼; ) HANGUL SYLLABLE DYAEN +B33D;B33D;1103 1164 11AC;B33D;1103 1164 11AC; # (댽; 댽; 댽; 댽; 댽; ) HANGUL SYLLABLE DYAENJ +B33E;B33E;1103 1164 11AD;B33E;1103 1164 11AD; # (댾; 댾; 댾; 댾; 댾; ) HANGUL SYLLABLE DYAENH +B33F;B33F;1103 1164 11AE;B33F;1103 1164 11AE; # (댿; 댿; 댿; 댿; 댿; ) HANGUL SYLLABLE DYAED +B340;B340;1103 1164 11AF;B340;1103 1164 11AF; # (덀; 덀; 덀; 덀; 덀; ) HANGUL SYLLABLE DYAEL +B341;B341;1103 1164 11B0;B341;1103 1164 11B0; # (덁; 덁; 덁; 덁; 덁; ) HANGUL SYLLABLE DYAELG +B342;B342;1103 1164 11B1;B342;1103 1164 11B1; # (덂; 덂; 덂; 덂; 덂; ) HANGUL SYLLABLE DYAELM +B343;B343;1103 1164 11B2;B343;1103 1164 11B2; # (덃; 덃; 덃; 덃; 덃; ) HANGUL SYLLABLE DYAELB +B344;B344;1103 1164 11B3;B344;1103 1164 11B3; # (덄; 덄; 덄; 덄; 덄; ) HANGUL SYLLABLE DYAELS +B345;B345;1103 1164 11B4;B345;1103 1164 11B4; # (덅; 덅; 덅; 덅; 덅; ) HANGUL SYLLABLE DYAELT +B346;B346;1103 1164 11B5;B346;1103 1164 11B5; # (덆; 덆; 덆; 덆; 덆; ) HANGUL SYLLABLE DYAELP +B347;B347;1103 1164 11B6;B347;1103 1164 11B6; # (덇; 덇; 덇; 덇; 덇; ) HANGUL SYLLABLE DYAELH +B348;B348;1103 1164 11B7;B348;1103 1164 11B7; # (덈; 덈; 덈; 덈; 덈; ) HANGUL SYLLABLE DYAEM +B349;B349;1103 1164 11B8;B349;1103 1164 11B8; # (덉; 덉; 덉; 덉; 덉; ) HANGUL SYLLABLE DYAEB +B34A;B34A;1103 1164 11B9;B34A;1103 1164 11B9; # (덊; 덊; 덊; 덊; 덊; ) HANGUL SYLLABLE DYAEBS +B34B;B34B;1103 1164 11BA;B34B;1103 1164 11BA; # (덋; 덋; 덋; 덋; 덋; ) HANGUL SYLLABLE DYAES +B34C;B34C;1103 1164 11BB;B34C;1103 1164 11BB; # (덌; 덌; 덌; 덌; 덌; ) HANGUL SYLLABLE DYAESS +B34D;B34D;1103 1164 11BC;B34D;1103 1164 11BC; # (덍; 덍; 덍; 덍; 덍; ) HANGUL SYLLABLE DYAENG +B34E;B34E;1103 1164 11BD;B34E;1103 1164 11BD; # (덎; 덎; 덎; 덎; 덎; ) HANGUL SYLLABLE DYAEJ +B34F;B34F;1103 1164 11BE;B34F;1103 1164 11BE; # (덏; 덏; 덏; 덏; 덏; ) HANGUL SYLLABLE DYAEC +B350;B350;1103 1164 11BF;B350;1103 1164 11BF; # (덐; 덐; 덐; 덐; 덐; ) HANGUL SYLLABLE DYAEK +B351;B351;1103 1164 11C0;B351;1103 1164 11C0; # (덑; 덑; 덑; 덑; 덑; ) HANGUL SYLLABLE DYAET +B352;B352;1103 1164 11C1;B352;1103 1164 11C1; # (덒; 덒; 덒; 덒; 덒; ) HANGUL SYLLABLE DYAEP +B353;B353;1103 1164 11C2;B353;1103 1164 11C2; # (덓; 덓; 덓; 덓; 덓; ) HANGUL SYLLABLE DYAEH +B354;B354;1103 1165;B354;1103 1165; # (더; 더; 더; 더; 더; ) HANGUL SYLLABLE DEO +B355;B355;1103 1165 11A8;B355;1103 1165 11A8; # (덕; 덕; 덕; 덕; 덕; ) HANGUL SYLLABLE DEOG +B356;B356;1103 1165 11A9;B356;1103 1165 11A9; # (덖; 덖; 덖; 덖; 덖; ) HANGUL SYLLABLE DEOGG +B357;B357;1103 1165 11AA;B357;1103 1165 11AA; # (덗; 덗; 덗; 덗; 덗; ) HANGUL SYLLABLE DEOGS +B358;B358;1103 1165 11AB;B358;1103 1165 11AB; # (던; 던; 던; 던; 던; ) HANGUL SYLLABLE DEON +B359;B359;1103 1165 11AC;B359;1103 1165 11AC; # (덙; 덙; 덙; 덙; 덙; ) HANGUL SYLLABLE DEONJ +B35A;B35A;1103 1165 11AD;B35A;1103 1165 11AD; # (덚; 덚; 덚; 덚; 덚; ) HANGUL SYLLABLE DEONH +B35B;B35B;1103 1165 11AE;B35B;1103 1165 11AE; # (덛; 덛; 덛; 덛; 덛; ) HANGUL SYLLABLE DEOD +B35C;B35C;1103 1165 11AF;B35C;1103 1165 11AF; # (덜; 덜; 덜; 덜; 덜; ) HANGUL SYLLABLE DEOL +B35D;B35D;1103 1165 11B0;B35D;1103 1165 11B0; # (덝; 덝; 덝; 덝; 덝; ) HANGUL SYLLABLE DEOLG +B35E;B35E;1103 1165 11B1;B35E;1103 1165 11B1; # (덞; 덞; 덞; 덞; 덞; ) HANGUL SYLLABLE DEOLM +B35F;B35F;1103 1165 11B2;B35F;1103 1165 11B2; # (덟; 덟; 덟; 덟; 덟; ) HANGUL SYLLABLE DEOLB +B360;B360;1103 1165 11B3;B360;1103 1165 11B3; # (덠; 덠; 덠; 덠; 덠; ) HANGUL SYLLABLE DEOLS +B361;B361;1103 1165 11B4;B361;1103 1165 11B4; # (덡; 덡; 덡; 덡; 덡; ) HANGUL SYLLABLE DEOLT +B362;B362;1103 1165 11B5;B362;1103 1165 11B5; # (덢; 덢; 덢; 덢; 덢; ) HANGUL SYLLABLE DEOLP +B363;B363;1103 1165 11B6;B363;1103 1165 11B6; # (덣; 덣; 덣; 덣; 덣; ) HANGUL SYLLABLE DEOLH +B364;B364;1103 1165 11B7;B364;1103 1165 11B7; # (덤; 덤; 덤; 덤; 덤; ) HANGUL SYLLABLE DEOM +B365;B365;1103 1165 11B8;B365;1103 1165 11B8; # (덥; 덥; 덥; 덥; 덥; ) HANGUL SYLLABLE DEOB +B366;B366;1103 1165 11B9;B366;1103 1165 11B9; # (덦; 덦; 덦; 덦; 덦; ) HANGUL SYLLABLE DEOBS +B367;B367;1103 1165 11BA;B367;1103 1165 11BA; # (덧; 덧; 덧; 덧; 덧; ) HANGUL SYLLABLE DEOS +B368;B368;1103 1165 11BB;B368;1103 1165 11BB; # (덨; 덨; 덨; 덨; 덨; ) HANGUL SYLLABLE DEOSS +B369;B369;1103 1165 11BC;B369;1103 1165 11BC; # (덩; 덩; 덩; 덩; 덩; ) HANGUL SYLLABLE DEONG +B36A;B36A;1103 1165 11BD;B36A;1103 1165 11BD; # (덪; 덪; 덪; 덪; 덪; ) HANGUL SYLLABLE DEOJ +B36B;B36B;1103 1165 11BE;B36B;1103 1165 11BE; # (덫; 덫; 덫; 덫; 덫; ) HANGUL SYLLABLE DEOC +B36C;B36C;1103 1165 11BF;B36C;1103 1165 11BF; # (덬; 덬; 덬; 덬; 덬; ) HANGUL SYLLABLE DEOK +B36D;B36D;1103 1165 11C0;B36D;1103 1165 11C0; # (덭; 덭; 덭; 덭; 덭; ) HANGUL SYLLABLE DEOT +B36E;B36E;1103 1165 11C1;B36E;1103 1165 11C1; # (덮; 덮; 덮; 덮; 덮; ) HANGUL SYLLABLE DEOP +B36F;B36F;1103 1165 11C2;B36F;1103 1165 11C2; # (덯; 덯; 덯; 덯; 덯; ) HANGUL SYLLABLE DEOH +B370;B370;1103 1166;B370;1103 1166; # (데; 데; 데; 데; 데; ) HANGUL SYLLABLE DE +B371;B371;1103 1166 11A8;B371;1103 1166 11A8; # (덱; 덱; 덱; 덱; 덱; ) HANGUL SYLLABLE DEG +B372;B372;1103 1166 11A9;B372;1103 1166 11A9; # (덲; 덲; 덲; 덲; 덲; ) HANGUL SYLLABLE DEGG +B373;B373;1103 1166 11AA;B373;1103 1166 11AA; # (덳; 덳; 덳; 덳; 덳; ) HANGUL SYLLABLE DEGS +B374;B374;1103 1166 11AB;B374;1103 1166 11AB; # (덴; 덴; 덴; 덴; 덴; ) HANGUL SYLLABLE DEN +B375;B375;1103 1166 11AC;B375;1103 1166 11AC; # (덵; 덵; 덵; 덵; 덵; ) HANGUL SYLLABLE DENJ +B376;B376;1103 1166 11AD;B376;1103 1166 11AD; # (덶; 덶; 덶; 덶; 덶; ) HANGUL SYLLABLE DENH +B377;B377;1103 1166 11AE;B377;1103 1166 11AE; # (덷; 덷; 덷; 덷; 덷; ) HANGUL SYLLABLE DED +B378;B378;1103 1166 11AF;B378;1103 1166 11AF; # (델; 델; 델; 델; 델; ) HANGUL SYLLABLE DEL +B379;B379;1103 1166 11B0;B379;1103 1166 11B0; # (덹; 덹; 덹; 덹; 덹; ) HANGUL SYLLABLE DELG +B37A;B37A;1103 1166 11B1;B37A;1103 1166 11B1; # (덺; 덺; 덺; 덺; 덺; ) HANGUL SYLLABLE DELM +B37B;B37B;1103 1166 11B2;B37B;1103 1166 11B2; # (덻; 덻; 덻; 덻; 덻; ) HANGUL SYLLABLE DELB +B37C;B37C;1103 1166 11B3;B37C;1103 1166 11B3; # (덼; 덼; 덼; 덼; 덼; ) HANGUL SYLLABLE DELS +B37D;B37D;1103 1166 11B4;B37D;1103 1166 11B4; # (덽; 덽; 덽; 덽; 덽; ) HANGUL SYLLABLE DELT +B37E;B37E;1103 1166 11B5;B37E;1103 1166 11B5; # (덾; 덾; 덾; 덾; 덾; ) HANGUL SYLLABLE DELP +B37F;B37F;1103 1166 11B6;B37F;1103 1166 11B6; # (덿; 덿; 덿; 덿; 덿; ) HANGUL SYLLABLE DELH +B380;B380;1103 1166 11B7;B380;1103 1166 11B7; # (뎀; 뎀; 뎀; 뎀; 뎀; ) HANGUL SYLLABLE DEM +B381;B381;1103 1166 11B8;B381;1103 1166 11B8; # (뎁; 뎁; 뎁; 뎁; 뎁; ) HANGUL SYLLABLE DEB +B382;B382;1103 1166 11B9;B382;1103 1166 11B9; # (뎂; 뎂; 뎂; 뎂; 뎂; ) HANGUL SYLLABLE DEBS +B383;B383;1103 1166 11BA;B383;1103 1166 11BA; # (뎃; 뎃; 뎃; 뎃; 뎃; ) HANGUL SYLLABLE DES +B384;B384;1103 1166 11BB;B384;1103 1166 11BB; # (뎄; 뎄; 뎄; 뎄; 뎄; ) HANGUL SYLLABLE DESS +B385;B385;1103 1166 11BC;B385;1103 1166 11BC; # (뎅; 뎅; 뎅; 뎅; 뎅; ) HANGUL SYLLABLE DENG +B386;B386;1103 1166 11BD;B386;1103 1166 11BD; # (뎆; 뎆; 뎆; 뎆; 뎆; ) HANGUL SYLLABLE DEJ +B387;B387;1103 1166 11BE;B387;1103 1166 11BE; # (뎇; 뎇; 뎇; 뎇; 뎇; ) HANGUL SYLLABLE DEC +B388;B388;1103 1166 11BF;B388;1103 1166 11BF; # (뎈; 뎈; 뎈; 뎈; 뎈; ) HANGUL SYLLABLE DEK +B389;B389;1103 1166 11C0;B389;1103 1166 11C0; # (뎉; 뎉; 뎉; 뎉; 뎉; ) HANGUL SYLLABLE DET +B38A;B38A;1103 1166 11C1;B38A;1103 1166 11C1; # (뎊; 뎊; 뎊; 뎊; 뎊; ) HANGUL SYLLABLE DEP +B38B;B38B;1103 1166 11C2;B38B;1103 1166 11C2; # (뎋; 뎋; 뎋; 뎋; 뎋; ) HANGUL SYLLABLE DEH +B38C;B38C;1103 1167;B38C;1103 1167; # (뎌; 뎌; 뎌; 뎌; 뎌; ) HANGUL SYLLABLE DYEO +B38D;B38D;1103 1167 11A8;B38D;1103 1167 11A8; # (뎍; 뎍; 뎍; 뎍; 뎍; ) HANGUL SYLLABLE DYEOG +B38E;B38E;1103 1167 11A9;B38E;1103 1167 11A9; # (뎎; 뎎; 뎎; 뎎; 뎎; ) HANGUL SYLLABLE DYEOGG +B38F;B38F;1103 1167 11AA;B38F;1103 1167 11AA; # (뎏; 뎏; 뎏; 뎏; 뎏; ) HANGUL SYLLABLE DYEOGS +B390;B390;1103 1167 11AB;B390;1103 1167 11AB; # (뎐; 뎐; 뎐; 뎐; 뎐; ) HANGUL SYLLABLE DYEON +B391;B391;1103 1167 11AC;B391;1103 1167 11AC; # (뎑; 뎑; 뎑; 뎑; 뎑; ) HANGUL SYLLABLE DYEONJ +B392;B392;1103 1167 11AD;B392;1103 1167 11AD; # (뎒; 뎒; 뎒; 뎒; 뎒; ) HANGUL SYLLABLE DYEONH +B393;B393;1103 1167 11AE;B393;1103 1167 11AE; # (뎓; 뎓; 뎓; 뎓; 뎓; ) HANGUL SYLLABLE DYEOD +B394;B394;1103 1167 11AF;B394;1103 1167 11AF; # (뎔; 뎔; 뎔; 뎔; 뎔; ) HANGUL SYLLABLE DYEOL +B395;B395;1103 1167 11B0;B395;1103 1167 11B0; # (뎕; 뎕; 뎕; 뎕; 뎕; ) HANGUL SYLLABLE DYEOLG +B396;B396;1103 1167 11B1;B396;1103 1167 11B1; # (뎖; 뎖; 뎖; 뎖; 뎖; ) HANGUL SYLLABLE DYEOLM +B397;B397;1103 1167 11B2;B397;1103 1167 11B2; # (뎗; 뎗; 뎗; 뎗; 뎗; ) HANGUL SYLLABLE DYEOLB +B398;B398;1103 1167 11B3;B398;1103 1167 11B3; # (뎘; 뎘; 뎘; 뎘; 뎘; ) HANGUL SYLLABLE DYEOLS +B399;B399;1103 1167 11B4;B399;1103 1167 11B4; # (뎙; 뎙; 뎙; 뎙; 뎙; ) HANGUL SYLLABLE DYEOLT +B39A;B39A;1103 1167 11B5;B39A;1103 1167 11B5; # (뎚; 뎚; 뎚; 뎚; 뎚; ) HANGUL SYLLABLE DYEOLP +B39B;B39B;1103 1167 11B6;B39B;1103 1167 11B6; # (뎛; 뎛; 뎛; 뎛; 뎛; ) HANGUL SYLLABLE DYEOLH +B39C;B39C;1103 1167 11B7;B39C;1103 1167 11B7; # (뎜; 뎜; 뎜; 뎜; 뎜; ) HANGUL SYLLABLE DYEOM +B39D;B39D;1103 1167 11B8;B39D;1103 1167 11B8; # (뎝; 뎝; 뎝; 뎝; 뎝; ) HANGUL SYLLABLE DYEOB +B39E;B39E;1103 1167 11B9;B39E;1103 1167 11B9; # (뎞; 뎞; 뎞; 뎞; 뎞; ) HANGUL SYLLABLE DYEOBS +B39F;B39F;1103 1167 11BA;B39F;1103 1167 11BA; # (뎟; 뎟; 뎟; 뎟; 뎟; ) HANGUL SYLLABLE DYEOS +B3A0;B3A0;1103 1167 11BB;B3A0;1103 1167 11BB; # (뎠; 뎠; 뎠; 뎠; 뎠; ) HANGUL SYLLABLE DYEOSS +B3A1;B3A1;1103 1167 11BC;B3A1;1103 1167 11BC; # (뎡; 뎡; 뎡; 뎡; 뎡; ) HANGUL SYLLABLE DYEONG +B3A2;B3A2;1103 1167 11BD;B3A2;1103 1167 11BD; # (뎢; 뎢; 뎢; 뎢; 뎢; ) HANGUL SYLLABLE DYEOJ +B3A3;B3A3;1103 1167 11BE;B3A3;1103 1167 11BE; # (뎣; 뎣; 뎣; 뎣; 뎣; ) HANGUL SYLLABLE DYEOC +B3A4;B3A4;1103 1167 11BF;B3A4;1103 1167 11BF; # (뎤; 뎤; 뎤; 뎤; 뎤; ) HANGUL SYLLABLE DYEOK +B3A5;B3A5;1103 1167 11C0;B3A5;1103 1167 11C0; # (뎥; 뎥; 뎥; 뎥; 뎥; ) HANGUL SYLLABLE DYEOT +B3A6;B3A6;1103 1167 11C1;B3A6;1103 1167 11C1; # (뎦; 뎦; 뎦; 뎦; 뎦; ) HANGUL SYLLABLE DYEOP +B3A7;B3A7;1103 1167 11C2;B3A7;1103 1167 11C2; # (뎧; 뎧; 뎧; 뎧; 뎧; ) HANGUL SYLLABLE DYEOH +B3A8;B3A8;1103 1168;B3A8;1103 1168; # (뎨; 뎨; 뎨; 뎨; 뎨; ) HANGUL SYLLABLE DYE +B3A9;B3A9;1103 1168 11A8;B3A9;1103 1168 11A8; # (뎩; 뎩; 뎩; 뎩; 뎩; ) HANGUL SYLLABLE DYEG +B3AA;B3AA;1103 1168 11A9;B3AA;1103 1168 11A9; # (뎪; 뎪; 뎪; 뎪; 뎪; ) HANGUL SYLLABLE DYEGG +B3AB;B3AB;1103 1168 11AA;B3AB;1103 1168 11AA; # (뎫; 뎫; 뎫; 뎫; 뎫; ) HANGUL SYLLABLE DYEGS +B3AC;B3AC;1103 1168 11AB;B3AC;1103 1168 11AB; # (뎬; 뎬; 뎬; 뎬; 뎬; ) HANGUL SYLLABLE DYEN +B3AD;B3AD;1103 1168 11AC;B3AD;1103 1168 11AC; # (뎭; 뎭; 뎭; 뎭; 뎭; ) HANGUL SYLLABLE DYENJ +B3AE;B3AE;1103 1168 11AD;B3AE;1103 1168 11AD; # (뎮; 뎮; 뎮; 뎮; 뎮; ) HANGUL SYLLABLE DYENH +B3AF;B3AF;1103 1168 11AE;B3AF;1103 1168 11AE; # (뎯; 뎯; 뎯; 뎯; 뎯; ) HANGUL SYLLABLE DYED +B3B0;B3B0;1103 1168 11AF;B3B0;1103 1168 11AF; # (뎰; 뎰; 뎰; 뎰; 뎰; ) HANGUL SYLLABLE DYEL +B3B1;B3B1;1103 1168 11B0;B3B1;1103 1168 11B0; # (뎱; 뎱; 뎱; 뎱; 뎱; ) HANGUL SYLLABLE DYELG +B3B2;B3B2;1103 1168 11B1;B3B2;1103 1168 11B1; # (뎲; 뎲; 뎲; 뎲; 뎲; ) HANGUL SYLLABLE DYELM +B3B3;B3B3;1103 1168 11B2;B3B3;1103 1168 11B2; # (뎳; 뎳; 뎳; 뎳; 뎳; ) HANGUL SYLLABLE DYELB +B3B4;B3B4;1103 1168 11B3;B3B4;1103 1168 11B3; # (뎴; 뎴; 뎴; 뎴; 뎴; ) HANGUL SYLLABLE DYELS +B3B5;B3B5;1103 1168 11B4;B3B5;1103 1168 11B4; # (뎵; 뎵; 뎵; 뎵; 뎵; ) HANGUL SYLLABLE DYELT +B3B6;B3B6;1103 1168 11B5;B3B6;1103 1168 11B5; # (뎶; 뎶; 뎶; 뎶; 뎶; ) HANGUL SYLLABLE DYELP +B3B7;B3B7;1103 1168 11B6;B3B7;1103 1168 11B6; # (뎷; 뎷; 뎷; 뎷; 뎷; ) HANGUL SYLLABLE DYELH +B3B8;B3B8;1103 1168 11B7;B3B8;1103 1168 11B7; # (뎸; 뎸; 뎸; 뎸; 뎸; ) HANGUL SYLLABLE DYEM +B3B9;B3B9;1103 1168 11B8;B3B9;1103 1168 11B8; # (뎹; 뎹; 뎹; 뎹; 뎹; ) HANGUL SYLLABLE DYEB +B3BA;B3BA;1103 1168 11B9;B3BA;1103 1168 11B9; # (뎺; 뎺; 뎺; 뎺; 뎺; ) HANGUL SYLLABLE DYEBS +B3BB;B3BB;1103 1168 11BA;B3BB;1103 1168 11BA; # (뎻; 뎻; 뎻; 뎻; 뎻; ) HANGUL SYLLABLE DYES +B3BC;B3BC;1103 1168 11BB;B3BC;1103 1168 11BB; # (뎼; 뎼; 뎼; 뎼; 뎼; ) HANGUL SYLLABLE DYESS +B3BD;B3BD;1103 1168 11BC;B3BD;1103 1168 11BC; # (뎽; 뎽; 뎽; 뎽; 뎽; ) HANGUL SYLLABLE DYENG +B3BE;B3BE;1103 1168 11BD;B3BE;1103 1168 11BD; # (뎾; 뎾; 뎾; 뎾; 뎾; ) HANGUL SYLLABLE DYEJ +B3BF;B3BF;1103 1168 11BE;B3BF;1103 1168 11BE; # (뎿; 뎿; 뎿; 뎿; 뎿; ) HANGUL SYLLABLE DYEC +B3C0;B3C0;1103 1168 11BF;B3C0;1103 1168 11BF; # (돀; 돀; 돀; 돀; 돀; ) HANGUL SYLLABLE DYEK +B3C1;B3C1;1103 1168 11C0;B3C1;1103 1168 11C0; # (돁; 돁; 돁; 돁; 돁; ) HANGUL SYLLABLE DYET +B3C2;B3C2;1103 1168 11C1;B3C2;1103 1168 11C1; # (돂; 돂; 돂; 돂; 돂; ) HANGUL SYLLABLE DYEP +B3C3;B3C3;1103 1168 11C2;B3C3;1103 1168 11C2; # (돃; 돃; 돃; 돃; 돃; ) HANGUL SYLLABLE DYEH +B3C4;B3C4;1103 1169;B3C4;1103 1169; # (도; 도; 도; 도; 도; ) HANGUL SYLLABLE DO +B3C5;B3C5;1103 1169 11A8;B3C5;1103 1169 11A8; # (독; 독; 독; 독; 독; ) HANGUL SYLLABLE DOG +B3C6;B3C6;1103 1169 11A9;B3C6;1103 1169 11A9; # (돆; 돆; 돆; 돆; 돆; ) HANGUL SYLLABLE DOGG +B3C7;B3C7;1103 1169 11AA;B3C7;1103 1169 11AA; # (돇; 돇; 돇; 돇; 돇; ) HANGUL SYLLABLE DOGS +B3C8;B3C8;1103 1169 11AB;B3C8;1103 1169 11AB; # (돈; 돈; 돈; 돈; 돈; ) HANGUL SYLLABLE DON +B3C9;B3C9;1103 1169 11AC;B3C9;1103 1169 11AC; # (돉; 돉; 돉; 돉; 돉; ) HANGUL SYLLABLE DONJ +B3CA;B3CA;1103 1169 11AD;B3CA;1103 1169 11AD; # (돊; 돊; 돊; 돊; 돊; ) HANGUL SYLLABLE DONH +B3CB;B3CB;1103 1169 11AE;B3CB;1103 1169 11AE; # (돋; 돋; 돋; 돋; 돋; ) HANGUL SYLLABLE DOD +B3CC;B3CC;1103 1169 11AF;B3CC;1103 1169 11AF; # (돌; 돌; 돌; 돌; 돌; ) HANGUL SYLLABLE DOL +B3CD;B3CD;1103 1169 11B0;B3CD;1103 1169 11B0; # (돍; 돍; 돍; 돍; 돍; ) HANGUL SYLLABLE DOLG +B3CE;B3CE;1103 1169 11B1;B3CE;1103 1169 11B1; # (돎; 돎; 돎; 돎; 돎; ) HANGUL SYLLABLE DOLM +B3CF;B3CF;1103 1169 11B2;B3CF;1103 1169 11B2; # (돏; 돏; 돏; 돏; 돏; ) HANGUL SYLLABLE DOLB +B3D0;B3D0;1103 1169 11B3;B3D0;1103 1169 11B3; # (돐; 돐; 돐; 돐; 돐; ) HANGUL SYLLABLE DOLS +B3D1;B3D1;1103 1169 11B4;B3D1;1103 1169 11B4; # (돑; 돑; 돑; 돑; 돑; ) HANGUL SYLLABLE DOLT +B3D2;B3D2;1103 1169 11B5;B3D2;1103 1169 11B5; # (돒; 돒; 돒; 돒; 돒; ) HANGUL SYLLABLE DOLP +B3D3;B3D3;1103 1169 11B6;B3D3;1103 1169 11B6; # (돓; 돓; 돓; 돓; 돓; ) HANGUL SYLLABLE DOLH +B3D4;B3D4;1103 1169 11B7;B3D4;1103 1169 11B7; # (돔; 돔; 돔; 돔; 돔; ) HANGUL SYLLABLE DOM +B3D5;B3D5;1103 1169 11B8;B3D5;1103 1169 11B8; # (돕; 돕; 돕; 돕; 돕; ) HANGUL SYLLABLE DOB +B3D6;B3D6;1103 1169 11B9;B3D6;1103 1169 11B9; # (돖; 돖; 돖; 돖; 돖; ) HANGUL SYLLABLE DOBS +B3D7;B3D7;1103 1169 11BA;B3D7;1103 1169 11BA; # (돗; 돗; 돗; 돗; 돗; ) HANGUL SYLLABLE DOS +B3D8;B3D8;1103 1169 11BB;B3D8;1103 1169 11BB; # (돘; 돘; 돘; 돘; 돘; ) HANGUL SYLLABLE DOSS +B3D9;B3D9;1103 1169 11BC;B3D9;1103 1169 11BC; # (동; 동; 동; 동; 동; ) HANGUL SYLLABLE DONG +B3DA;B3DA;1103 1169 11BD;B3DA;1103 1169 11BD; # (돚; 돚; 돚; 돚; 돚; ) HANGUL SYLLABLE DOJ +B3DB;B3DB;1103 1169 11BE;B3DB;1103 1169 11BE; # (돛; 돛; 돛; 돛; 돛; ) HANGUL SYLLABLE DOC +B3DC;B3DC;1103 1169 11BF;B3DC;1103 1169 11BF; # (돜; 돜; 돜; 돜; 돜; ) HANGUL SYLLABLE DOK +B3DD;B3DD;1103 1169 11C0;B3DD;1103 1169 11C0; # (돝; 돝; 돝; 돝; 돝; ) HANGUL SYLLABLE DOT +B3DE;B3DE;1103 1169 11C1;B3DE;1103 1169 11C1; # (돞; 돞; 돞; 돞; 돞; ) HANGUL SYLLABLE DOP +B3DF;B3DF;1103 1169 11C2;B3DF;1103 1169 11C2; # (돟; 돟; 돟; 돟; 돟; ) HANGUL SYLLABLE DOH +B3E0;B3E0;1103 116A;B3E0;1103 116A; # (돠; 돠; 돠; 돠; 돠; ) HANGUL SYLLABLE DWA +B3E1;B3E1;1103 116A 11A8;B3E1;1103 116A 11A8; # (돡; 돡; 돡; 돡; 돡; ) HANGUL SYLLABLE DWAG +B3E2;B3E2;1103 116A 11A9;B3E2;1103 116A 11A9; # (돢; 돢; 돢; 돢; 돢; ) HANGUL SYLLABLE DWAGG +B3E3;B3E3;1103 116A 11AA;B3E3;1103 116A 11AA; # (돣; 돣; 돣; 돣; 돣; ) HANGUL SYLLABLE DWAGS +B3E4;B3E4;1103 116A 11AB;B3E4;1103 116A 11AB; # (돤; 돤; 돤; 돤; 돤; ) HANGUL SYLLABLE DWAN +B3E5;B3E5;1103 116A 11AC;B3E5;1103 116A 11AC; # (돥; 돥; 돥; 돥; 돥; ) HANGUL SYLLABLE DWANJ +B3E6;B3E6;1103 116A 11AD;B3E6;1103 116A 11AD; # (돦; 돦; 돦; 돦; 돦; ) HANGUL SYLLABLE DWANH +B3E7;B3E7;1103 116A 11AE;B3E7;1103 116A 11AE; # (돧; 돧; 돧; 돧; 돧; ) HANGUL SYLLABLE DWAD +B3E8;B3E8;1103 116A 11AF;B3E8;1103 116A 11AF; # (돨; 돨; 돨; 돨; 돨; ) HANGUL SYLLABLE DWAL +B3E9;B3E9;1103 116A 11B0;B3E9;1103 116A 11B0; # (돩; 돩; 돩; 돩; 돩; ) HANGUL SYLLABLE DWALG +B3EA;B3EA;1103 116A 11B1;B3EA;1103 116A 11B1; # (돪; 돪; 돪; 돪; 돪; ) HANGUL SYLLABLE DWALM +B3EB;B3EB;1103 116A 11B2;B3EB;1103 116A 11B2; # (돫; 돫; 돫; 돫; 돫; ) HANGUL SYLLABLE DWALB +B3EC;B3EC;1103 116A 11B3;B3EC;1103 116A 11B3; # (돬; 돬; 돬; 돬; 돬; ) HANGUL SYLLABLE DWALS +B3ED;B3ED;1103 116A 11B4;B3ED;1103 116A 11B4; # (돭; 돭; 돭; 돭; 돭; ) HANGUL SYLLABLE DWALT +B3EE;B3EE;1103 116A 11B5;B3EE;1103 116A 11B5; # (돮; 돮; 돮; 돮; 돮; ) HANGUL SYLLABLE DWALP +B3EF;B3EF;1103 116A 11B6;B3EF;1103 116A 11B6; # (돯; 돯; 돯; 돯; 돯; ) HANGUL SYLLABLE DWALH +B3F0;B3F0;1103 116A 11B7;B3F0;1103 116A 11B7; # (돰; 돰; 돰; 돰; 돰; ) HANGUL SYLLABLE DWAM +B3F1;B3F1;1103 116A 11B8;B3F1;1103 116A 11B8; # (돱; 돱; 돱; 돱; 돱; ) HANGUL SYLLABLE DWAB +B3F2;B3F2;1103 116A 11B9;B3F2;1103 116A 11B9; # (돲; 돲; 돲; 돲; 돲; ) HANGUL SYLLABLE DWABS +B3F3;B3F3;1103 116A 11BA;B3F3;1103 116A 11BA; # (돳; 돳; 돳; 돳; 돳; ) HANGUL SYLLABLE DWAS +B3F4;B3F4;1103 116A 11BB;B3F4;1103 116A 11BB; # (돴; 돴; 돴; 돴; 돴; ) HANGUL SYLLABLE DWASS +B3F5;B3F5;1103 116A 11BC;B3F5;1103 116A 11BC; # (돵; 돵; 돵; 돵; 돵; ) HANGUL SYLLABLE DWANG +B3F6;B3F6;1103 116A 11BD;B3F6;1103 116A 11BD; # (돶; 돶; 돶; 돶; 돶; ) HANGUL SYLLABLE DWAJ +B3F7;B3F7;1103 116A 11BE;B3F7;1103 116A 11BE; # (돷; 돷; 돷; 돷; 돷; ) HANGUL SYLLABLE DWAC +B3F8;B3F8;1103 116A 11BF;B3F8;1103 116A 11BF; # (돸; 돸; 돸; 돸; 돸; ) HANGUL SYLLABLE DWAK +B3F9;B3F9;1103 116A 11C0;B3F9;1103 116A 11C0; # (돹; 돹; 돹; 돹; 돹; ) HANGUL SYLLABLE DWAT +B3FA;B3FA;1103 116A 11C1;B3FA;1103 116A 11C1; # (돺; 돺; 돺; 돺; 돺; ) HANGUL SYLLABLE DWAP +B3FB;B3FB;1103 116A 11C2;B3FB;1103 116A 11C2; # (돻; 돻; 돻; 돻; 돻; ) HANGUL SYLLABLE DWAH +B3FC;B3FC;1103 116B;B3FC;1103 116B; # (돼; 돼; 돼; 돼; 돼; ) HANGUL SYLLABLE DWAE +B3FD;B3FD;1103 116B 11A8;B3FD;1103 116B 11A8; # (돽; 돽; 돽; 돽; 돽; ) HANGUL SYLLABLE DWAEG +B3FE;B3FE;1103 116B 11A9;B3FE;1103 116B 11A9; # (돾; 돾; 돾; 돾; 돾; ) HANGUL SYLLABLE DWAEGG +B3FF;B3FF;1103 116B 11AA;B3FF;1103 116B 11AA; # (돿; 돿; 돿; 돿; 돿; ) HANGUL SYLLABLE DWAEGS +B400;B400;1103 116B 11AB;B400;1103 116B 11AB; # (됀; 됀; 됀; 됀; 됀; ) HANGUL SYLLABLE DWAEN +B401;B401;1103 116B 11AC;B401;1103 116B 11AC; # (됁; 됁; 됁; 됁; 됁; ) HANGUL SYLLABLE DWAENJ +B402;B402;1103 116B 11AD;B402;1103 116B 11AD; # (됂; 됂; 됂; 됂; 됂; ) HANGUL SYLLABLE DWAENH +B403;B403;1103 116B 11AE;B403;1103 116B 11AE; # (됃; 됃; 됃; 됃; 됃; ) HANGUL SYLLABLE DWAED +B404;B404;1103 116B 11AF;B404;1103 116B 11AF; # (됄; 됄; 됄; 됄; 됄; ) HANGUL SYLLABLE DWAEL +B405;B405;1103 116B 11B0;B405;1103 116B 11B0; # (됅; 됅; 됅; 됅; 됅; ) HANGUL SYLLABLE DWAELG +B406;B406;1103 116B 11B1;B406;1103 116B 11B1; # (됆; 됆; 됆; 됆; 됆; ) HANGUL SYLLABLE DWAELM +B407;B407;1103 116B 11B2;B407;1103 116B 11B2; # (됇; 됇; 됇; 됇; 됇; ) HANGUL SYLLABLE DWAELB +B408;B408;1103 116B 11B3;B408;1103 116B 11B3; # (됈; 됈; 됈; 됈; 됈; ) HANGUL SYLLABLE DWAELS +B409;B409;1103 116B 11B4;B409;1103 116B 11B4; # (됉; 됉; 됉; 됉; 됉; ) HANGUL SYLLABLE DWAELT +B40A;B40A;1103 116B 11B5;B40A;1103 116B 11B5; # (됊; 됊; 됊; 됊; 됊; ) HANGUL SYLLABLE DWAELP +B40B;B40B;1103 116B 11B6;B40B;1103 116B 11B6; # (됋; 됋; 됋; 됋; 됋; ) HANGUL SYLLABLE DWAELH +B40C;B40C;1103 116B 11B7;B40C;1103 116B 11B7; # (됌; 됌; 됌; 됌; 됌; ) HANGUL SYLLABLE DWAEM +B40D;B40D;1103 116B 11B8;B40D;1103 116B 11B8; # (됍; 됍; 됍; 됍; 됍; ) HANGUL SYLLABLE DWAEB +B40E;B40E;1103 116B 11B9;B40E;1103 116B 11B9; # (됎; 됎; 됎; 됎; 됎; ) HANGUL SYLLABLE DWAEBS +B40F;B40F;1103 116B 11BA;B40F;1103 116B 11BA; # (됏; 됏; 됏; 됏; 됏; ) HANGUL SYLLABLE DWAES +B410;B410;1103 116B 11BB;B410;1103 116B 11BB; # (됐; 됐; 됐; 됐; 됐; ) HANGUL SYLLABLE DWAESS +B411;B411;1103 116B 11BC;B411;1103 116B 11BC; # (됑; 됑; 됑; 됑; 됑; ) HANGUL SYLLABLE DWAENG +B412;B412;1103 116B 11BD;B412;1103 116B 11BD; # (됒; 됒; 됒; 됒; 됒; ) HANGUL SYLLABLE DWAEJ +B413;B413;1103 116B 11BE;B413;1103 116B 11BE; # (됓; 됓; 됓; 됓; 됓; ) HANGUL SYLLABLE DWAEC +B414;B414;1103 116B 11BF;B414;1103 116B 11BF; # (됔; 됔; 됔; 됔; 됔; ) HANGUL SYLLABLE DWAEK +B415;B415;1103 116B 11C0;B415;1103 116B 11C0; # (됕; 됕; 됕; 됕; 됕; ) HANGUL SYLLABLE DWAET +B416;B416;1103 116B 11C1;B416;1103 116B 11C1; # (됖; 됖; 됖; 됖; 됖; ) HANGUL SYLLABLE DWAEP +B417;B417;1103 116B 11C2;B417;1103 116B 11C2; # (됗; 됗; 됗; 됗; 됗; ) HANGUL SYLLABLE DWAEH +B418;B418;1103 116C;B418;1103 116C; # (되; 되; 되; 되; 되; ) HANGUL SYLLABLE DOE +B419;B419;1103 116C 11A8;B419;1103 116C 11A8; # (됙; 됙; 됙; 됙; 됙; ) HANGUL SYLLABLE DOEG +B41A;B41A;1103 116C 11A9;B41A;1103 116C 11A9; # (됚; 됚; 됚; 됚; 됚; ) HANGUL SYLLABLE DOEGG +B41B;B41B;1103 116C 11AA;B41B;1103 116C 11AA; # (됛; 됛; 됛; 됛; 됛; ) HANGUL SYLLABLE DOEGS +B41C;B41C;1103 116C 11AB;B41C;1103 116C 11AB; # (된; 된; 된; 된; 된; ) HANGUL SYLLABLE DOEN +B41D;B41D;1103 116C 11AC;B41D;1103 116C 11AC; # (됝; 됝; 됝; 됝; 됝; ) HANGUL SYLLABLE DOENJ +B41E;B41E;1103 116C 11AD;B41E;1103 116C 11AD; # (됞; 됞; 됞; 됞; 됞; ) HANGUL SYLLABLE DOENH +B41F;B41F;1103 116C 11AE;B41F;1103 116C 11AE; # (됟; 됟; 됟; 됟; 됟; ) HANGUL SYLLABLE DOED +B420;B420;1103 116C 11AF;B420;1103 116C 11AF; # (될; 될; 될; 될; 될; ) HANGUL SYLLABLE DOEL +B421;B421;1103 116C 11B0;B421;1103 116C 11B0; # (됡; 됡; 됡; 됡; 됡; ) HANGUL SYLLABLE DOELG +B422;B422;1103 116C 11B1;B422;1103 116C 11B1; # (됢; 됢; 됢; 됢; 됢; ) HANGUL SYLLABLE DOELM +B423;B423;1103 116C 11B2;B423;1103 116C 11B2; # (됣; 됣; 됣; 됣; 됣; ) HANGUL SYLLABLE DOELB +B424;B424;1103 116C 11B3;B424;1103 116C 11B3; # (됤; 됤; 됤; 됤; 됤; ) HANGUL SYLLABLE DOELS +B425;B425;1103 116C 11B4;B425;1103 116C 11B4; # (됥; 됥; 됥; 됥; 됥; ) HANGUL SYLLABLE DOELT +B426;B426;1103 116C 11B5;B426;1103 116C 11B5; # (됦; 됦; 됦; 됦; 됦; ) HANGUL SYLLABLE DOELP +B427;B427;1103 116C 11B6;B427;1103 116C 11B6; # (됧; 됧; 됧; 됧; 됧; ) HANGUL SYLLABLE DOELH +B428;B428;1103 116C 11B7;B428;1103 116C 11B7; # (됨; 됨; 됨; 됨; 됨; ) HANGUL SYLLABLE DOEM +B429;B429;1103 116C 11B8;B429;1103 116C 11B8; # (됩; 됩; 됩; 됩; 됩; ) HANGUL SYLLABLE DOEB +B42A;B42A;1103 116C 11B9;B42A;1103 116C 11B9; # (됪; 됪; 됪; 됪; 됪; ) HANGUL SYLLABLE DOEBS +B42B;B42B;1103 116C 11BA;B42B;1103 116C 11BA; # (됫; 됫; 됫; 됫; 됫; ) HANGUL SYLLABLE DOES +B42C;B42C;1103 116C 11BB;B42C;1103 116C 11BB; # (됬; 됬; 됬; 됬; 됬; ) HANGUL SYLLABLE DOESS +B42D;B42D;1103 116C 11BC;B42D;1103 116C 11BC; # (됭; 됭; 됭; 됭; 됭; ) HANGUL SYLLABLE DOENG +B42E;B42E;1103 116C 11BD;B42E;1103 116C 11BD; # (됮; 됮; 됮; 됮; 됮; ) HANGUL SYLLABLE DOEJ +B42F;B42F;1103 116C 11BE;B42F;1103 116C 11BE; # (됯; 됯; 됯; 됯; 됯; ) HANGUL SYLLABLE DOEC +B430;B430;1103 116C 11BF;B430;1103 116C 11BF; # (됰; 됰; 됰; 됰; 됰; ) HANGUL SYLLABLE DOEK +B431;B431;1103 116C 11C0;B431;1103 116C 11C0; # (됱; 됱; 됱; 됱; 됱; ) HANGUL SYLLABLE DOET +B432;B432;1103 116C 11C1;B432;1103 116C 11C1; # (됲; 됲; 됲; 됲; 됲; ) HANGUL SYLLABLE DOEP +B433;B433;1103 116C 11C2;B433;1103 116C 11C2; # (됳; 됳; 됳; 됳; 됳; ) HANGUL SYLLABLE DOEH +B434;B434;1103 116D;B434;1103 116D; # (됴; 됴; 됴; 됴; 됴; ) HANGUL SYLLABLE DYO +B435;B435;1103 116D 11A8;B435;1103 116D 11A8; # (됵; 됵; 됵; 됵; 됵; ) HANGUL SYLLABLE DYOG +B436;B436;1103 116D 11A9;B436;1103 116D 11A9; # (됶; 됶; 됶; 됶; 됶; ) HANGUL SYLLABLE DYOGG +B437;B437;1103 116D 11AA;B437;1103 116D 11AA; # (됷; 됷; 됷; 됷; 됷; ) HANGUL SYLLABLE DYOGS +B438;B438;1103 116D 11AB;B438;1103 116D 11AB; # (됸; 됸; 됸; 됸; 됸; ) HANGUL SYLLABLE DYON +B439;B439;1103 116D 11AC;B439;1103 116D 11AC; # (됹; 됹; 됹; 됹; 됹; ) HANGUL SYLLABLE DYONJ +B43A;B43A;1103 116D 11AD;B43A;1103 116D 11AD; # (됺; 됺; 됺; 됺; 됺; ) HANGUL SYLLABLE DYONH +B43B;B43B;1103 116D 11AE;B43B;1103 116D 11AE; # (됻; 됻; 됻; 됻; 됻; ) HANGUL SYLLABLE DYOD +B43C;B43C;1103 116D 11AF;B43C;1103 116D 11AF; # (됼; 됼; 됼; 됼; 됼; ) HANGUL SYLLABLE DYOL +B43D;B43D;1103 116D 11B0;B43D;1103 116D 11B0; # (됽; 됽; 됽; 됽; 됽; ) HANGUL SYLLABLE DYOLG +B43E;B43E;1103 116D 11B1;B43E;1103 116D 11B1; # (됾; 됾; 됾; 됾; 됾; ) HANGUL SYLLABLE DYOLM +B43F;B43F;1103 116D 11B2;B43F;1103 116D 11B2; # (됿; 됿; 됿; 됿; 됿; ) HANGUL SYLLABLE DYOLB +B440;B440;1103 116D 11B3;B440;1103 116D 11B3; # (둀; 둀; 둀; 둀; 둀; ) HANGUL SYLLABLE DYOLS +B441;B441;1103 116D 11B4;B441;1103 116D 11B4; # (둁; 둁; 둁; 둁; 둁; ) HANGUL SYLLABLE DYOLT +B442;B442;1103 116D 11B5;B442;1103 116D 11B5; # (둂; 둂; 둂; 둂; 둂; ) HANGUL SYLLABLE DYOLP +B443;B443;1103 116D 11B6;B443;1103 116D 11B6; # (둃; 둃; 둃; 둃; 둃; ) HANGUL SYLLABLE DYOLH +B444;B444;1103 116D 11B7;B444;1103 116D 11B7; # (둄; 둄; 둄; 둄; 둄; ) HANGUL SYLLABLE DYOM +B445;B445;1103 116D 11B8;B445;1103 116D 11B8; # (둅; 둅; 둅; 둅; 둅; ) HANGUL SYLLABLE DYOB +B446;B446;1103 116D 11B9;B446;1103 116D 11B9; # (둆; 둆; 둆; 둆; 둆; ) HANGUL SYLLABLE DYOBS +B447;B447;1103 116D 11BA;B447;1103 116D 11BA; # (둇; 둇; 둇; 둇; 둇; ) HANGUL SYLLABLE DYOS +B448;B448;1103 116D 11BB;B448;1103 116D 11BB; # (둈; 둈; 둈; 둈; 둈; ) HANGUL SYLLABLE DYOSS +B449;B449;1103 116D 11BC;B449;1103 116D 11BC; # (둉; 둉; 둉; 둉; 둉; ) HANGUL SYLLABLE DYONG +B44A;B44A;1103 116D 11BD;B44A;1103 116D 11BD; # (둊; 둊; 둊; 둊; 둊; ) HANGUL SYLLABLE DYOJ +B44B;B44B;1103 116D 11BE;B44B;1103 116D 11BE; # (둋; 둋; 둋; 둋; 둋; ) HANGUL SYLLABLE DYOC +B44C;B44C;1103 116D 11BF;B44C;1103 116D 11BF; # (둌; 둌; 둌; 둌; 둌; ) HANGUL SYLLABLE DYOK +B44D;B44D;1103 116D 11C0;B44D;1103 116D 11C0; # (둍; 둍; 둍; 둍; 둍; ) HANGUL SYLLABLE DYOT +B44E;B44E;1103 116D 11C1;B44E;1103 116D 11C1; # (둎; 둎; 둎; 둎; 둎; ) HANGUL SYLLABLE DYOP +B44F;B44F;1103 116D 11C2;B44F;1103 116D 11C2; # (둏; 둏; 둏; 둏; 둏; ) HANGUL SYLLABLE DYOH +B450;B450;1103 116E;B450;1103 116E; # (두; 두; 두; 두; 두; ) HANGUL SYLLABLE DU +B451;B451;1103 116E 11A8;B451;1103 116E 11A8; # (둑; 둑; 둑; 둑; 둑; ) HANGUL SYLLABLE DUG +B452;B452;1103 116E 11A9;B452;1103 116E 11A9; # (둒; 둒; 둒; 둒; 둒; ) HANGUL SYLLABLE DUGG +B453;B453;1103 116E 11AA;B453;1103 116E 11AA; # (둓; 둓; 둓; 둓; 둓; ) HANGUL SYLLABLE DUGS +B454;B454;1103 116E 11AB;B454;1103 116E 11AB; # (둔; 둔; 둔; 둔; 둔; ) HANGUL SYLLABLE DUN +B455;B455;1103 116E 11AC;B455;1103 116E 11AC; # (둕; 둕; 둕; 둕; 둕; ) HANGUL SYLLABLE DUNJ +B456;B456;1103 116E 11AD;B456;1103 116E 11AD; # (둖; 둖; 둖; 둖; 둖; ) HANGUL SYLLABLE DUNH +B457;B457;1103 116E 11AE;B457;1103 116E 11AE; # (둗; 둗; 둗; 둗; 둗; ) HANGUL SYLLABLE DUD +B458;B458;1103 116E 11AF;B458;1103 116E 11AF; # (둘; 둘; 둘; 둘; 둘; ) HANGUL SYLLABLE DUL +B459;B459;1103 116E 11B0;B459;1103 116E 11B0; # (둙; 둙; 둙; 둙; 둙; ) HANGUL SYLLABLE DULG +B45A;B45A;1103 116E 11B1;B45A;1103 116E 11B1; # (둚; 둚; 둚; 둚; 둚; ) HANGUL SYLLABLE DULM +B45B;B45B;1103 116E 11B2;B45B;1103 116E 11B2; # (둛; 둛; 둛; 둛; 둛; ) HANGUL SYLLABLE DULB +B45C;B45C;1103 116E 11B3;B45C;1103 116E 11B3; # (둜; 둜; 둜; 둜; 둜; ) HANGUL SYLLABLE DULS +B45D;B45D;1103 116E 11B4;B45D;1103 116E 11B4; # (둝; 둝; 둝; 둝; 둝; ) HANGUL SYLLABLE DULT +B45E;B45E;1103 116E 11B5;B45E;1103 116E 11B5; # (둞; 둞; 둞; 둞; 둞; ) HANGUL SYLLABLE DULP +B45F;B45F;1103 116E 11B6;B45F;1103 116E 11B6; # (둟; 둟; 둟; 둟; 둟; ) HANGUL SYLLABLE DULH +B460;B460;1103 116E 11B7;B460;1103 116E 11B7; # (둠; 둠; 둠; 둠; 둠; ) HANGUL SYLLABLE DUM +B461;B461;1103 116E 11B8;B461;1103 116E 11B8; # (둡; 둡; 둡; 둡; 둡; ) HANGUL SYLLABLE DUB +B462;B462;1103 116E 11B9;B462;1103 116E 11B9; # (둢; 둢; 둢; 둢; 둢; ) HANGUL SYLLABLE DUBS +B463;B463;1103 116E 11BA;B463;1103 116E 11BA; # (둣; 둣; 둣; 둣; 둣; ) HANGUL SYLLABLE DUS +B464;B464;1103 116E 11BB;B464;1103 116E 11BB; # (둤; 둤; 둤; 둤; 둤; ) HANGUL SYLLABLE DUSS +B465;B465;1103 116E 11BC;B465;1103 116E 11BC; # (둥; 둥; 둥; 둥; 둥; ) HANGUL SYLLABLE DUNG +B466;B466;1103 116E 11BD;B466;1103 116E 11BD; # (둦; 둦; 둦; 둦; 둦; ) HANGUL SYLLABLE DUJ +B467;B467;1103 116E 11BE;B467;1103 116E 11BE; # (둧; 둧; 둧; 둧; 둧; ) HANGUL SYLLABLE DUC +B468;B468;1103 116E 11BF;B468;1103 116E 11BF; # (둨; 둨; 둨; 둨; 둨; ) HANGUL SYLLABLE DUK +B469;B469;1103 116E 11C0;B469;1103 116E 11C0; # (둩; 둩; 둩; 둩; 둩; ) HANGUL SYLLABLE DUT +B46A;B46A;1103 116E 11C1;B46A;1103 116E 11C1; # (둪; 둪; 둪; 둪; 둪; ) HANGUL SYLLABLE DUP +B46B;B46B;1103 116E 11C2;B46B;1103 116E 11C2; # (둫; 둫; 둫; 둫; 둫; ) HANGUL SYLLABLE DUH +B46C;B46C;1103 116F;B46C;1103 116F; # (둬; 둬; 둬; 둬; 둬; ) HANGUL SYLLABLE DWEO +B46D;B46D;1103 116F 11A8;B46D;1103 116F 11A8; # (둭; 둭; 둭; 둭; 둭; ) HANGUL SYLLABLE DWEOG +B46E;B46E;1103 116F 11A9;B46E;1103 116F 11A9; # (둮; 둮; 둮; 둮; 둮; ) HANGUL SYLLABLE DWEOGG +B46F;B46F;1103 116F 11AA;B46F;1103 116F 11AA; # (둯; 둯; 둯; 둯; 둯; ) HANGUL SYLLABLE DWEOGS +B470;B470;1103 116F 11AB;B470;1103 116F 11AB; # (둰; 둰; 둰; 둰; 둰; ) HANGUL SYLLABLE DWEON +B471;B471;1103 116F 11AC;B471;1103 116F 11AC; # (둱; 둱; 둱; 둱; 둱; ) HANGUL SYLLABLE DWEONJ +B472;B472;1103 116F 11AD;B472;1103 116F 11AD; # (둲; 둲; 둲; 둲; 둲; ) HANGUL SYLLABLE DWEONH +B473;B473;1103 116F 11AE;B473;1103 116F 11AE; # (둳; 둳; 둳; 둳; 둳; ) HANGUL SYLLABLE DWEOD +B474;B474;1103 116F 11AF;B474;1103 116F 11AF; # (둴; 둴; 둴; 둴; 둴; ) HANGUL SYLLABLE DWEOL +B475;B475;1103 116F 11B0;B475;1103 116F 11B0; # (둵; 둵; 둵; 둵; 둵; ) HANGUL SYLLABLE DWEOLG +B476;B476;1103 116F 11B1;B476;1103 116F 11B1; # (둶; 둶; 둶; 둶; 둶; ) HANGUL SYLLABLE DWEOLM +B477;B477;1103 116F 11B2;B477;1103 116F 11B2; # (둷; 둷; 둷; 둷; 둷; ) HANGUL SYLLABLE DWEOLB +B478;B478;1103 116F 11B3;B478;1103 116F 11B3; # (둸; 둸; 둸; 둸; 둸; ) HANGUL SYLLABLE DWEOLS +B479;B479;1103 116F 11B4;B479;1103 116F 11B4; # (둹; 둹; 둹; 둹; 둹; ) HANGUL SYLLABLE DWEOLT +B47A;B47A;1103 116F 11B5;B47A;1103 116F 11B5; # (둺; 둺; 둺; 둺; 둺; ) HANGUL SYLLABLE DWEOLP +B47B;B47B;1103 116F 11B6;B47B;1103 116F 11B6; # (둻; 둻; 둻; 둻; 둻; ) HANGUL SYLLABLE DWEOLH +B47C;B47C;1103 116F 11B7;B47C;1103 116F 11B7; # (둼; 둼; 둼; 둼; 둼; ) HANGUL SYLLABLE DWEOM +B47D;B47D;1103 116F 11B8;B47D;1103 116F 11B8; # (둽; 둽; 둽; 둽; 둽; ) HANGUL SYLLABLE DWEOB +B47E;B47E;1103 116F 11B9;B47E;1103 116F 11B9; # (둾; 둾; 둾; 둾; 둾; ) HANGUL SYLLABLE DWEOBS +B47F;B47F;1103 116F 11BA;B47F;1103 116F 11BA; # (둿; 둿; 둿; 둿; 둿; ) HANGUL SYLLABLE DWEOS +B480;B480;1103 116F 11BB;B480;1103 116F 11BB; # (뒀; 뒀; 뒀; 뒀; 뒀; ) HANGUL SYLLABLE DWEOSS +B481;B481;1103 116F 11BC;B481;1103 116F 11BC; # (뒁; 뒁; 뒁; 뒁; 뒁; ) HANGUL SYLLABLE DWEONG +B482;B482;1103 116F 11BD;B482;1103 116F 11BD; # (뒂; 뒂; 뒂; 뒂; 뒂; ) HANGUL SYLLABLE DWEOJ +B483;B483;1103 116F 11BE;B483;1103 116F 11BE; # (뒃; 뒃; 뒃; 뒃; 뒃; ) HANGUL SYLLABLE DWEOC +B484;B484;1103 116F 11BF;B484;1103 116F 11BF; # (뒄; 뒄; 뒄; 뒄; 뒄; ) HANGUL SYLLABLE DWEOK +B485;B485;1103 116F 11C0;B485;1103 116F 11C0; # (뒅; 뒅; 뒅; 뒅; 뒅; ) HANGUL SYLLABLE DWEOT +B486;B486;1103 116F 11C1;B486;1103 116F 11C1; # (뒆; 뒆; 뒆; 뒆; 뒆; ) HANGUL SYLLABLE DWEOP +B487;B487;1103 116F 11C2;B487;1103 116F 11C2; # (뒇; 뒇; 뒇; 뒇; 뒇; ) HANGUL SYLLABLE DWEOH +B488;B488;1103 1170;B488;1103 1170; # (뒈; 뒈; 뒈; 뒈; 뒈; ) HANGUL SYLLABLE DWE +B489;B489;1103 1170 11A8;B489;1103 1170 11A8; # (뒉; 뒉; 뒉; 뒉; 뒉; ) HANGUL SYLLABLE DWEG +B48A;B48A;1103 1170 11A9;B48A;1103 1170 11A9; # (뒊; 뒊; 뒊; 뒊; 뒊; ) HANGUL SYLLABLE DWEGG +B48B;B48B;1103 1170 11AA;B48B;1103 1170 11AA; # (뒋; 뒋; 뒋; 뒋; 뒋; ) HANGUL SYLLABLE DWEGS +B48C;B48C;1103 1170 11AB;B48C;1103 1170 11AB; # (뒌; 뒌; 뒌; 뒌; 뒌; ) HANGUL SYLLABLE DWEN +B48D;B48D;1103 1170 11AC;B48D;1103 1170 11AC; # (뒍; 뒍; 뒍; 뒍; 뒍; ) HANGUL SYLLABLE DWENJ +B48E;B48E;1103 1170 11AD;B48E;1103 1170 11AD; # (뒎; 뒎; 뒎; 뒎; 뒎; ) HANGUL SYLLABLE DWENH +B48F;B48F;1103 1170 11AE;B48F;1103 1170 11AE; # (뒏; 뒏; 뒏; 뒏; 뒏; ) HANGUL SYLLABLE DWED +B490;B490;1103 1170 11AF;B490;1103 1170 11AF; # (뒐; 뒐; 뒐; 뒐; 뒐; ) HANGUL SYLLABLE DWEL +B491;B491;1103 1170 11B0;B491;1103 1170 11B0; # (뒑; 뒑; 뒑; 뒑; 뒑; ) HANGUL SYLLABLE DWELG +B492;B492;1103 1170 11B1;B492;1103 1170 11B1; # (뒒; 뒒; 뒒; 뒒; 뒒; ) HANGUL SYLLABLE DWELM +B493;B493;1103 1170 11B2;B493;1103 1170 11B2; # (뒓; 뒓; 뒓; 뒓; 뒓; ) HANGUL SYLLABLE DWELB +B494;B494;1103 1170 11B3;B494;1103 1170 11B3; # (뒔; 뒔; 뒔; 뒔; 뒔; ) HANGUL SYLLABLE DWELS +B495;B495;1103 1170 11B4;B495;1103 1170 11B4; # (뒕; 뒕; 뒕; 뒕; 뒕; ) HANGUL SYLLABLE DWELT +B496;B496;1103 1170 11B5;B496;1103 1170 11B5; # (뒖; 뒖; 뒖; 뒖; 뒖; ) HANGUL SYLLABLE DWELP +B497;B497;1103 1170 11B6;B497;1103 1170 11B6; # (뒗; 뒗; 뒗; 뒗; 뒗; ) HANGUL SYLLABLE DWELH +B498;B498;1103 1170 11B7;B498;1103 1170 11B7; # (뒘; 뒘; 뒘; 뒘; 뒘; ) HANGUL SYLLABLE DWEM +B499;B499;1103 1170 11B8;B499;1103 1170 11B8; # (뒙; 뒙; 뒙; 뒙; 뒙; ) HANGUL SYLLABLE DWEB +B49A;B49A;1103 1170 11B9;B49A;1103 1170 11B9; # (뒚; 뒚; 뒚; 뒚; 뒚; ) HANGUL SYLLABLE DWEBS +B49B;B49B;1103 1170 11BA;B49B;1103 1170 11BA; # (뒛; 뒛; 뒛; 뒛; 뒛; ) HANGUL SYLLABLE DWES +B49C;B49C;1103 1170 11BB;B49C;1103 1170 11BB; # (뒜; 뒜; 뒜; 뒜; 뒜; ) HANGUL SYLLABLE DWESS +B49D;B49D;1103 1170 11BC;B49D;1103 1170 11BC; # (뒝; 뒝; 뒝; 뒝; 뒝; ) HANGUL SYLLABLE DWENG +B49E;B49E;1103 1170 11BD;B49E;1103 1170 11BD; # (뒞; 뒞; 뒞; 뒞; 뒞; ) HANGUL SYLLABLE DWEJ +B49F;B49F;1103 1170 11BE;B49F;1103 1170 11BE; # (뒟; 뒟; 뒟; 뒟; 뒟; ) HANGUL SYLLABLE DWEC +B4A0;B4A0;1103 1170 11BF;B4A0;1103 1170 11BF; # (뒠; 뒠; 뒠; 뒠; 뒠; ) HANGUL SYLLABLE DWEK +B4A1;B4A1;1103 1170 11C0;B4A1;1103 1170 11C0; # (뒡; 뒡; 뒡; 뒡; 뒡; ) HANGUL SYLLABLE DWET +B4A2;B4A2;1103 1170 11C1;B4A2;1103 1170 11C1; # (뒢; 뒢; 뒢; 뒢; 뒢; ) HANGUL SYLLABLE DWEP +B4A3;B4A3;1103 1170 11C2;B4A3;1103 1170 11C2; # (뒣; 뒣; 뒣; 뒣; 뒣; ) HANGUL SYLLABLE DWEH +B4A4;B4A4;1103 1171;B4A4;1103 1171; # (뒤; 뒤; 뒤; 뒤; 뒤; ) HANGUL SYLLABLE DWI +B4A5;B4A5;1103 1171 11A8;B4A5;1103 1171 11A8; # (뒥; 뒥; 뒥; 뒥; 뒥; ) HANGUL SYLLABLE DWIG +B4A6;B4A6;1103 1171 11A9;B4A6;1103 1171 11A9; # (뒦; 뒦; 뒦; 뒦; 뒦; ) HANGUL SYLLABLE DWIGG +B4A7;B4A7;1103 1171 11AA;B4A7;1103 1171 11AA; # (뒧; 뒧; 뒧; 뒧; 뒧; ) HANGUL SYLLABLE DWIGS +B4A8;B4A8;1103 1171 11AB;B4A8;1103 1171 11AB; # (뒨; 뒨; 뒨; 뒨; 뒨; ) HANGUL SYLLABLE DWIN +B4A9;B4A9;1103 1171 11AC;B4A9;1103 1171 11AC; # (뒩; 뒩; 뒩; 뒩; 뒩; ) HANGUL SYLLABLE DWINJ +B4AA;B4AA;1103 1171 11AD;B4AA;1103 1171 11AD; # (뒪; 뒪; 뒪; 뒪; 뒪; ) HANGUL SYLLABLE DWINH +B4AB;B4AB;1103 1171 11AE;B4AB;1103 1171 11AE; # (뒫; 뒫; 뒫; 뒫; 뒫; ) HANGUL SYLLABLE DWID +B4AC;B4AC;1103 1171 11AF;B4AC;1103 1171 11AF; # (뒬; 뒬; 뒬; 뒬; 뒬; ) HANGUL SYLLABLE DWIL +B4AD;B4AD;1103 1171 11B0;B4AD;1103 1171 11B0; # (뒭; 뒭; 뒭; 뒭; 뒭; ) HANGUL SYLLABLE DWILG +B4AE;B4AE;1103 1171 11B1;B4AE;1103 1171 11B1; # (뒮; 뒮; 뒮; 뒮; 뒮; ) HANGUL SYLLABLE DWILM +B4AF;B4AF;1103 1171 11B2;B4AF;1103 1171 11B2; # (뒯; 뒯; 뒯; 뒯; 뒯; ) HANGUL SYLLABLE DWILB +B4B0;B4B0;1103 1171 11B3;B4B0;1103 1171 11B3; # (뒰; 뒰; 뒰; 뒰; 뒰; ) HANGUL SYLLABLE DWILS +B4B1;B4B1;1103 1171 11B4;B4B1;1103 1171 11B4; # (뒱; 뒱; 뒱; 뒱; 뒱; ) HANGUL SYLLABLE DWILT +B4B2;B4B2;1103 1171 11B5;B4B2;1103 1171 11B5; # (뒲; 뒲; 뒲; 뒲; 뒲; ) HANGUL SYLLABLE DWILP +B4B3;B4B3;1103 1171 11B6;B4B3;1103 1171 11B6; # (뒳; 뒳; 뒳; 뒳; 뒳; ) HANGUL SYLLABLE DWILH +B4B4;B4B4;1103 1171 11B7;B4B4;1103 1171 11B7; # (뒴; 뒴; 뒴; 뒴; 뒴; ) HANGUL SYLLABLE DWIM +B4B5;B4B5;1103 1171 11B8;B4B5;1103 1171 11B8; # (뒵; 뒵; 뒵; 뒵; 뒵; ) HANGUL SYLLABLE DWIB +B4B6;B4B6;1103 1171 11B9;B4B6;1103 1171 11B9; # (뒶; 뒶; 뒶; 뒶; 뒶; ) HANGUL SYLLABLE DWIBS +B4B7;B4B7;1103 1171 11BA;B4B7;1103 1171 11BA; # (뒷; 뒷; 뒷; 뒷; 뒷; ) HANGUL SYLLABLE DWIS +B4B8;B4B8;1103 1171 11BB;B4B8;1103 1171 11BB; # (뒸; 뒸; 뒸; 뒸; 뒸; ) HANGUL SYLLABLE DWISS +B4B9;B4B9;1103 1171 11BC;B4B9;1103 1171 11BC; # (뒹; 뒹; 뒹; 뒹; 뒹; ) HANGUL SYLLABLE DWING +B4BA;B4BA;1103 1171 11BD;B4BA;1103 1171 11BD; # (뒺; 뒺; 뒺; 뒺; 뒺; ) HANGUL SYLLABLE DWIJ +B4BB;B4BB;1103 1171 11BE;B4BB;1103 1171 11BE; # (뒻; 뒻; 뒻; 뒻; 뒻; ) HANGUL SYLLABLE DWIC +B4BC;B4BC;1103 1171 11BF;B4BC;1103 1171 11BF; # (뒼; 뒼; 뒼; 뒼; 뒼; ) HANGUL SYLLABLE DWIK +B4BD;B4BD;1103 1171 11C0;B4BD;1103 1171 11C0; # (뒽; 뒽; 뒽; 뒽; 뒽; ) HANGUL SYLLABLE DWIT +B4BE;B4BE;1103 1171 11C1;B4BE;1103 1171 11C1; # (뒾; 뒾; 뒾; 뒾; 뒾; ) HANGUL SYLLABLE DWIP +B4BF;B4BF;1103 1171 11C2;B4BF;1103 1171 11C2; # (뒿; 뒿; 뒿; 뒿; 뒿; ) HANGUL SYLLABLE DWIH +B4C0;B4C0;1103 1172;B4C0;1103 1172; # (듀; 듀; 듀; 듀; 듀; ) HANGUL SYLLABLE DYU +B4C1;B4C1;1103 1172 11A8;B4C1;1103 1172 11A8; # (듁; 듁; 듁; 듁; 듁; ) HANGUL SYLLABLE DYUG +B4C2;B4C2;1103 1172 11A9;B4C2;1103 1172 11A9; # (듂; 듂; 듂; 듂; 듂; ) HANGUL SYLLABLE DYUGG +B4C3;B4C3;1103 1172 11AA;B4C3;1103 1172 11AA; # (듃; 듃; 듃; 듃; 듃; ) HANGUL SYLLABLE DYUGS +B4C4;B4C4;1103 1172 11AB;B4C4;1103 1172 11AB; # (듄; 듄; 듄; 듄; 듄; ) HANGUL SYLLABLE DYUN +B4C5;B4C5;1103 1172 11AC;B4C5;1103 1172 11AC; # (듅; 듅; 듅; 듅; 듅; ) HANGUL SYLLABLE DYUNJ +B4C6;B4C6;1103 1172 11AD;B4C6;1103 1172 11AD; # (듆; 듆; 듆; 듆; 듆; ) HANGUL SYLLABLE DYUNH +B4C7;B4C7;1103 1172 11AE;B4C7;1103 1172 11AE; # (듇; 듇; 듇; 듇; 듇; ) HANGUL SYLLABLE DYUD +B4C8;B4C8;1103 1172 11AF;B4C8;1103 1172 11AF; # (듈; 듈; 듈; 듈; 듈; ) HANGUL SYLLABLE DYUL +B4C9;B4C9;1103 1172 11B0;B4C9;1103 1172 11B0; # (듉; 듉; 듉; 듉; 듉; ) HANGUL SYLLABLE DYULG +B4CA;B4CA;1103 1172 11B1;B4CA;1103 1172 11B1; # (듊; 듊; 듊; 듊; 듊; ) HANGUL SYLLABLE DYULM +B4CB;B4CB;1103 1172 11B2;B4CB;1103 1172 11B2; # (듋; 듋; 듋; 듋; 듋; ) HANGUL SYLLABLE DYULB +B4CC;B4CC;1103 1172 11B3;B4CC;1103 1172 11B3; # (듌; 듌; 듌; 듌; 듌; ) HANGUL SYLLABLE DYULS +B4CD;B4CD;1103 1172 11B4;B4CD;1103 1172 11B4; # (듍; 듍; 듍; 듍; 듍; ) HANGUL SYLLABLE DYULT +B4CE;B4CE;1103 1172 11B5;B4CE;1103 1172 11B5; # (듎; 듎; 듎; 듎; 듎; ) HANGUL SYLLABLE DYULP +B4CF;B4CF;1103 1172 11B6;B4CF;1103 1172 11B6; # (듏; 듏; 듏; 듏; 듏; ) HANGUL SYLLABLE DYULH +B4D0;B4D0;1103 1172 11B7;B4D0;1103 1172 11B7; # (듐; 듐; 듐; 듐; 듐; ) HANGUL SYLLABLE DYUM +B4D1;B4D1;1103 1172 11B8;B4D1;1103 1172 11B8; # (듑; 듑; 듑; 듑; 듑; ) HANGUL SYLLABLE DYUB +B4D2;B4D2;1103 1172 11B9;B4D2;1103 1172 11B9; # (듒; 듒; 듒; 듒; 듒; ) HANGUL SYLLABLE DYUBS +B4D3;B4D3;1103 1172 11BA;B4D3;1103 1172 11BA; # (듓; 듓; 듓; 듓; 듓; ) HANGUL SYLLABLE DYUS +B4D4;B4D4;1103 1172 11BB;B4D4;1103 1172 11BB; # (듔; 듔; 듔; 듔; 듔; ) HANGUL SYLLABLE DYUSS +B4D5;B4D5;1103 1172 11BC;B4D5;1103 1172 11BC; # (듕; 듕; 듕; 듕; 듕; ) HANGUL SYLLABLE DYUNG +B4D6;B4D6;1103 1172 11BD;B4D6;1103 1172 11BD; # (듖; 듖; 듖; 듖; 듖; ) HANGUL SYLLABLE DYUJ +B4D7;B4D7;1103 1172 11BE;B4D7;1103 1172 11BE; # (듗; 듗; 듗; 듗; 듗; ) HANGUL SYLLABLE DYUC +B4D8;B4D8;1103 1172 11BF;B4D8;1103 1172 11BF; # (듘; 듘; 듘; 듘; 듘; ) HANGUL SYLLABLE DYUK +B4D9;B4D9;1103 1172 11C0;B4D9;1103 1172 11C0; # (듙; 듙; 듙; 듙; 듙; ) HANGUL SYLLABLE DYUT +B4DA;B4DA;1103 1172 11C1;B4DA;1103 1172 11C1; # (듚; 듚; 듚; 듚; 듚; ) HANGUL SYLLABLE DYUP +B4DB;B4DB;1103 1172 11C2;B4DB;1103 1172 11C2; # (듛; 듛; 듛; 듛; 듛; ) HANGUL SYLLABLE DYUH +B4DC;B4DC;1103 1173;B4DC;1103 1173; # (드; 드; 드; 드; 드; ) HANGUL SYLLABLE DEU +B4DD;B4DD;1103 1173 11A8;B4DD;1103 1173 11A8; # (득; 득; 득; 득; 득; ) HANGUL SYLLABLE DEUG +B4DE;B4DE;1103 1173 11A9;B4DE;1103 1173 11A9; # (듞; 듞; 듞; 듞; 듞; ) HANGUL SYLLABLE DEUGG +B4DF;B4DF;1103 1173 11AA;B4DF;1103 1173 11AA; # (듟; 듟; 듟; 듟; 듟; ) HANGUL SYLLABLE DEUGS +B4E0;B4E0;1103 1173 11AB;B4E0;1103 1173 11AB; # (든; 든; 든; 든; 든; ) HANGUL SYLLABLE DEUN +B4E1;B4E1;1103 1173 11AC;B4E1;1103 1173 11AC; # (듡; 듡; 듡; 듡; 듡; ) HANGUL SYLLABLE DEUNJ +B4E2;B4E2;1103 1173 11AD;B4E2;1103 1173 11AD; # (듢; 듢; 듢; 듢; 듢; ) HANGUL SYLLABLE DEUNH +B4E3;B4E3;1103 1173 11AE;B4E3;1103 1173 11AE; # (듣; 듣; 듣; 듣; 듣; ) HANGUL SYLLABLE DEUD +B4E4;B4E4;1103 1173 11AF;B4E4;1103 1173 11AF; # (들; 들; 들; 들; 들; ) HANGUL SYLLABLE DEUL +B4E5;B4E5;1103 1173 11B0;B4E5;1103 1173 11B0; # (듥; 듥; 듥; 듥; 듥; ) HANGUL SYLLABLE DEULG +B4E6;B4E6;1103 1173 11B1;B4E6;1103 1173 11B1; # (듦; 듦; 듦; 듦; 듦; ) HANGUL SYLLABLE DEULM +B4E7;B4E7;1103 1173 11B2;B4E7;1103 1173 11B2; # (듧; 듧; 듧; 듧; 듧; ) HANGUL SYLLABLE DEULB +B4E8;B4E8;1103 1173 11B3;B4E8;1103 1173 11B3; # (듨; 듨; 듨; 듨; 듨; ) HANGUL SYLLABLE DEULS +B4E9;B4E9;1103 1173 11B4;B4E9;1103 1173 11B4; # (듩; 듩; 듩; 듩; 듩; ) HANGUL SYLLABLE DEULT +B4EA;B4EA;1103 1173 11B5;B4EA;1103 1173 11B5; # (듪; 듪; 듪; 듪; 듪; ) HANGUL SYLLABLE DEULP +B4EB;B4EB;1103 1173 11B6;B4EB;1103 1173 11B6; # (듫; 듫; 듫; 듫; 듫; ) HANGUL SYLLABLE DEULH +B4EC;B4EC;1103 1173 11B7;B4EC;1103 1173 11B7; # (듬; 듬; 듬; 듬; 듬; ) HANGUL SYLLABLE DEUM +B4ED;B4ED;1103 1173 11B8;B4ED;1103 1173 11B8; # (듭; 듭; 듭; 듭; 듭; ) HANGUL SYLLABLE DEUB +B4EE;B4EE;1103 1173 11B9;B4EE;1103 1173 11B9; # (듮; 듮; 듮; 듮; 듮; ) HANGUL SYLLABLE DEUBS +B4EF;B4EF;1103 1173 11BA;B4EF;1103 1173 11BA; # (듯; 듯; 듯; 듯; 듯; ) HANGUL SYLLABLE DEUS +B4F0;B4F0;1103 1173 11BB;B4F0;1103 1173 11BB; # (듰; 듰; 듰; 듰; 듰; ) HANGUL SYLLABLE DEUSS +B4F1;B4F1;1103 1173 11BC;B4F1;1103 1173 11BC; # (등; 등; 등; 등; 등; ) HANGUL SYLLABLE DEUNG +B4F2;B4F2;1103 1173 11BD;B4F2;1103 1173 11BD; # (듲; 듲; 듲; 듲; 듲; ) HANGUL SYLLABLE DEUJ +B4F3;B4F3;1103 1173 11BE;B4F3;1103 1173 11BE; # (듳; 듳; 듳; 듳; 듳; ) HANGUL SYLLABLE DEUC +B4F4;B4F4;1103 1173 11BF;B4F4;1103 1173 11BF; # (듴; 듴; 듴; 듴; 듴; ) HANGUL SYLLABLE DEUK +B4F5;B4F5;1103 1173 11C0;B4F5;1103 1173 11C0; # (듵; 듵; 듵; 듵; 듵; ) HANGUL SYLLABLE DEUT +B4F6;B4F6;1103 1173 11C1;B4F6;1103 1173 11C1; # (듶; 듶; 듶; 듶; 듶; ) HANGUL SYLLABLE DEUP +B4F7;B4F7;1103 1173 11C2;B4F7;1103 1173 11C2; # (듷; 듷; 듷; 듷; 듷; ) HANGUL SYLLABLE DEUH +B4F8;B4F8;1103 1174;B4F8;1103 1174; # (듸; 듸; 듸; 듸; 듸; ) HANGUL SYLLABLE DYI +B4F9;B4F9;1103 1174 11A8;B4F9;1103 1174 11A8; # (듹; 듹; 듹; 듹; 듹; ) HANGUL SYLLABLE DYIG +B4FA;B4FA;1103 1174 11A9;B4FA;1103 1174 11A9; # (듺; 듺; 듺; 듺; 듺; ) HANGUL SYLLABLE DYIGG +B4FB;B4FB;1103 1174 11AA;B4FB;1103 1174 11AA; # (듻; 듻; 듻; 듻; 듻; ) HANGUL SYLLABLE DYIGS +B4FC;B4FC;1103 1174 11AB;B4FC;1103 1174 11AB; # (듼; 듼; 듼; 듼; 듼; ) HANGUL SYLLABLE DYIN +B4FD;B4FD;1103 1174 11AC;B4FD;1103 1174 11AC; # (듽; 듽; 듽; 듽; 듽; ) HANGUL SYLLABLE DYINJ +B4FE;B4FE;1103 1174 11AD;B4FE;1103 1174 11AD; # (듾; 듾; 듾; 듾; 듾; ) HANGUL SYLLABLE DYINH +B4FF;B4FF;1103 1174 11AE;B4FF;1103 1174 11AE; # (듿; 듿; 듿; 듿; 듿; ) HANGUL SYLLABLE DYID +B500;B500;1103 1174 11AF;B500;1103 1174 11AF; # (딀; 딀; 딀; 딀; 딀; ) HANGUL SYLLABLE DYIL +B501;B501;1103 1174 11B0;B501;1103 1174 11B0; # (딁; 딁; 딁; 딁; 딁; ) HANGUL SYLLABLE DYILG +B502;B502;1103 1174 11B1;B502;1103 1174 11B1; # (딂; 딂; 딂; 딂; 딂; ) HANGUL SYLLABLE DYILM +B503;B503;1103 1174 11B2;B503;1103 1174 11B2; # (딃; 딃; 딃; 딃; 딃; ) HANGUL SYLLABLE DYILB +B504;B504;1103 1174 11B3;B504;1103 1174 11B3; # (딄; 딄; 딄; 딄; 딄; ) HANGUL SYLLABLE DYILS +B505;B505;1103 1174 11B4;B505;1103 1174 11B4; # (딅; 딅; 딅; 딅; 딅; ) HANGUL SYLLABLE DYILT +B506;B506;1103 1174 11B5;B506;1103 1174 11B5; # (딆; 딆; 딆; 딆; 딆; ) HANGUL SYLLABLE DYILP +B507;B507;1103 1174 11B6;B507;1103 1174 11B6; # (딇; 딇; 딇; 딇; 딇; ) HANGUL SYLLABLE DYILH +B508;B508;1103 1174 11B7;B508;1103 1174 11B7; # (딈; 딈; 딈; 딈; 딈; ) HANGUL SYLLABLE DYIM +B509;B509;1103 1174 11B8;B509;1103 1174 11B8; # (딉; 딉; 딉; 딉; 딉; ) HANGUL SYLLABLE DYIB +B50A;B50A;1103 1174 11B9;B50A;1103 1174 11B9; # (딊; 딊; 딊; 딊; 딊; ) HANGUL SYLLABLE DYIBS +B50B;B50B;1103 1174 11BA;B50B;1103 1174 11BA; # (딋; 딋; 딋; 딋; 딋; ) HANGUL SYLLABLE DYIS +B50C;B50C;1103 1174 11BB;B50C;1103 1174 11BB; # (딌; 딌; 딌; 딌; 딌; ) HANGUL SYLLABLE DYISS +B50D;B50D;1103 1174 11BC;B50D;1103 1174 11BC; # (딍; 딍; 딍; 딍; 딍; ) HANGUL SYLLABLE DYING +B50E;B50E;1103 1174 11BD;B50E;1103 1174 11BD; # (딎; 딎; 딎; 딎; 딎; ) HANGUL SYLLABLE DYIJ +B50F;B50F;1103 1174 11BE;B50F;1103 1174 11BE; # (딏; 딏; 딏; 딏; 딏; ) HANGUL SYLLABLE DYIC +B510;B510;1103 1174 11BF;B510;1103 1174 11BF; # (딐; 딐; 딐; 딐; 딐; ) HANGUL SYLLABLE DYIK +B511;B511;1103 1174 11C0;B511;1103 1174 11C0; # (딑; 딑; 딑; 딑; 딑; ) HANGUL SYLLABLE DYIT +B512;B512;1103 1174 11C1;B512;1103 1174 11C1; # (딒; 딒; 딒; 딒; 딒; ) HANGUL SYLLABLE DYIP +B513;B513;1103 1174 11C2;B513;1103 1174 11C2; # (딓; 딓; 딓; 딓; 딓; ) HANGUL SYLLABLE DYIH +B514;B514;1103 1175;B514;1103 1175; # (디; 디; 디; 디; 디; ) HANGUL SYLLABLE DI +B515;B515;1103 1175 11A8;B515;1103 1175 11A8; # (딕; 딕; 딕; 딕; 딕; ) HANGUL SYLLABLE DIG +B516;B516;1103 1175 11A9;B516;1103 1175 11A9; # (딖; 딖; 딖; 딖; 딖; ) HANGUL SYLLABLE DIGG +B517;B517;1103 1175 11AA;B517;1103 1175 11AA; # (딗; 딗; 딗; 딗; 딗; ) HANGUL SYLLABLE DIGS +B518;B518;1103 1175 11AB;B518;1103 1175 11AB; # (딘; 딘; 딘; 딘; 딘; ) HANGUL SYLLABLE DIN +B519;B519;1103 1175 11AC;B519;1103 1175 11AC; # (딙; 딙; 딙; 딙; 딙; ) HANGUL SYLLABLE DINJ +B51A;B51A;1103 1175 11AD;B51A;1103 1175 11AD; # (딚; 딚; 딚; 딚; 딚; ) HANGUL SYLLABLE DINH +B51B;B51B;1103 1175 11AE;B51B;1103 1175 11AE; # (딛; 딛; 딛; 딛; 딛; ) HANGUL SYLLABLE DID +B51C;B51C;1103 1175 11AF;B51C;1103 1175 11AF; # (딜; 딜; 딜; 딜; 딜; ) HANGUL SYLLABLE DIL +B51D;B51D;1103 1175 11B0;B51D;1103 1175 11B0; # (딝; 딝; 딝; 딝; 딝; ) HANGUL SYLLABLE DILG +B51E;B51E;1103 1175 11B1;B51E;1103 1175 11B1; # (딞; 딞; 딞; 딞; 딞; ) HANGUL SYLLABLE DILM +B51F;B51F;1103 1175 11B2;B51F;1103 1175 11B2; # (딟; 딟; 딟; 딟; 딟; ) HANGUL SYLLABLE DILB +B520;B520;1103 1175 11B3;B520;1103 1175 11B3; # (딠; 딠; 딠; 딠; 딠; ) HANGUL SYLLABLE DILS +B521;B521;1103 1175 11B4;B521;1103 1175 11B4; # (딡; 딡; 딡; 딡; 딡; ) HANGUL SYLLABLE DILT +B522;B522;1103 1175 11B5;B522;1103 1175 11B5; # (딢; 딢; 딢; 딢; 딢; ) HANGUL SYLLABLE DILP +B523;B523;1103 1175 11B6;B523;1103 1175 11B6; # (딣; 딣; 딣; 딣; 딣; ) HANGUL SYLLABLE DILH +B524;B524;1103 1175 11B7;B524;1103 1175 11B7; # (딤; 딤; 딤; 딤; 딤; ) HANGUL SYLLABLE DIM +B525;B525;1103 1175 11B8;B525;1103 1175 11B8; # (딥; 딥; 딥; 딥; 딥; ) HANGUL SYLLABLE DIB +B526;B526;1103 1175 11B9;B526;1103 1175 11B9; # (딦; 딦; 딦; 딦; 딦; ) HANGUL SYLLABLE DIBS +B527;B527;1103 1175 11BA;B527;1103 1175 11BA; # (딧; 딧; 딧; 딧; 딧; ) HANGUL SYLLABLE DIS +B528;B528;1103 1175 11BB;B528;1103 1175 11BB; # (딨; 딨; 딨; 딨; 딨; ) HANGUL SYLLABLE DISS +B529;B529;1103 1175 11BC;B529;1103 1175 11BC; # (딩; 딩; 딩; 딩; 딩; ) HANGUL SYLLABLE DING +B52A;B52A;1103 1175 11BD;B52A;1103 1175 11BD; # (딪; 딪; 딪; 딪; 딪; ) HANGUL SYLLABLE DIJ +B52B;B52B;1103 1175 11BE;B52B;1103 1175 11BE; # (딫; 딫; 딫; 딫; 딫; ) HANGUL SYLLABLE DIC +B52C;B52C;1103 1175 11BF;B52C;1103 1175 11BF; # (딬; 딬; 딬; 딬; 딬; ) HANGUL SYLLABLE DIK +B52D;B52D;1103 1175 11C0;B52D;1103 1175 11C0; # (딭; 딭; 딭; 딭; 딭; ) HANGUL SYLLABLE DIT +B52E;B52E;1103 1175 11C1;B52E;1103 1175 11C1; # (딮; 딮; 딮; 딮; 딮; ) HANGUL SYLLABLE DIP +B52F;B52F;1103 1175 11C2;B52F;1103 1175 11C2; # (딯; 딯; 딯; 딯; 딯; ) HANGUL SYLLABLE DIH +B530;B530;1104 1161;B530;1104 1161; # (따; 따; 따; 따; 따; ) HANGUL SYLLABLE DDA +B531;B531;1104 1161 11A8;B531;1104 1161 11A8; # (딱; 딱; 딱; 딱; 딱; ) HANGUL SYLLABLE DDAG +B532;B532;1104 1161 11A9;B532;1104 1161 11A9; # (딲; 딲; 딲; 딲; 딲; ) HANGUL SYLLABLE DDAGG +B533;B533;1104 1161 11AA;B533;1104 1161 11AA; # (딳; 딳; 딳; 딳; 딳; ) HANGUL SYLLABLE DDAGS +B534;B534;1104 1161 11AB;B534;1104 1161 11AB; # (딴; 딴; 딴; 딴; 딴; ) HANGUL SYLLABLE DDAN +B535;B535;1104 1161 11AC;B535;1104 1161 11AC; # (딵; 딵; 딵; 딵; 딵; ) HANGUL SYLLABLE DDANJ +B536;B536;1104 1161 11AD;B536;1104 1161 11AD; # (딶; 딶; 딶; 딶; 딶; ) HANGUL SYLLABLE DDANH +B537;B537;1104 1161 11AE;B537;1104 1161 11AE; # (딷; 딷; 딷; 딷; 딷; ) HANGUL SYLLABLE DDAD +B538;B538;1104 1161 11AF;B538;1104 1161 11AF; # (딸; 딸; 딸; 딸; 딸; ) HANGUL SYLLABLE DDAL +B539;B539;1104 1161 11B0;B539;1104 1161 11B0; # (딹; 딹; 딹; 딹; 딹; ) HANGUL SYLLABLE DDALG +B53A;B53A;1104 1161 11B1;B53A;1104 1161 11B1; # (딺; 딺; 딺; 딺; 딺; ) HANGUL SYLLABLE DDALM +B53B;B53B;1104 1161 11B2;B53B;1104 1161 11B2; # (딻; 딻; 딻; 딻; 딻; ) HANGUL SYLLABLE DDALB +B53C;B53C;1104 1161 11B3;B53C;1104 1161 11B3; # (딼; 딼; 딼; 딼; 딼; ) HANGUL SYLLABLE DDALS +B53D;B53D;1104 1161 11B4;B53D;1104 1161 11B4; # (딽; 딽; 딽; 딽; 딽; ) HANGUL SYLLABLE DDALT +B53E;B53E;1104 1161 11B5;B53E;1104 1161 11B5; # (딾; 딾; 딾; 딾; 딾; ) HANGUL SYLLABLE DDALP +B53F;B53F;1104 1161 11B6;B53F;1104 1161 11B6; # (딿; 딿; 딿; 딿; 딿; ) HANGUL SYLLABLE DDALH +B540;B540;1104 1161 11B7;B540;1104 1161 11B7; # (땀; 땀; 땀; 땀; 땀; ) HANGUL SYLLABLE DDAM +B541;B541;1104 1161 11B8;B541;1104 1161 11B8; # (땁; 땁; 땁; 땁; 땁; ) HANGUL SYLLABLE DDAB +B542;B542;1104 1161 11B9;B542;1104 1161 11B9; # (땂; 땂; 땂; 땂; 땂; ) HANGUL SYLLABLE DDABS +B543;B543;1104 1161 11BA;B543;1104 1161 11BA; # (땃; 땃; 땃; 땃; 땃; ) HANGUL SYLLABLE DDAS +B544;B544;1104 1161 11BB;B544;1104 1161 11BB; # (땄; 땄; 땄; 땄; 땄; ) HANGUL SYLLABLE DDASS +B545;B545;1104 1161 11BC;B545;1104 1161 11BC; # (땅; 땅; 땅; 땅; 땅; ) HANGUL SYLLABLE DDANG +B546;B546;1104 1161 11BD;B546;1104 1161 11BD; # (땆; 땆; 땆; 땆; 땆; ) HANGUL SYLLABLE DDAJ +B547;B547;1104 1161 11BE;B547;1104 1161 11BE; # (땇; 땇; 땇; 땇; 땇; ) HANGUL SYLLABLE DDAC +B548;B548;1104 1161 11BF;B548;1104 1161 11BF; # (땈; 땈; 땈; 땈; 땈; ) HANGUL SYLLABLE DDAK +B549;B549;1104 1161 11C0;B549;1104 1161 11C0; # (땉; 땉; 땉; 땉; 땉; ) HANGUL SYLLABLE DDAT +B54A;B54A;1104 1161 11C1;B54A;1104 1161 11C1; # (땊; 땊; 땊; 땊; 땊; ) HANGUL SYLLABLE DDAP +B54B;B54B;1104 1161 11C2;B54B;1104 1161 11C2; # (땋; 땋; 땋; 땋; 땋; ) HANGUL SYLLABLE DDAH +B54C;B54C;1104 1162;B54C;1104 1162; # (때; 때; 때; 때; 때; ) HANGUL SYLLABLE DDAE +B54D;B54D;1104 1162 11A8;B54D;1104 1162 11A8; # (땍; 땍; 땍; 땍; 땍; ) HANGUL SYLLABLE DDAEG +B54E;B54E;1104 1162 11A9;B54E;1104 1162 11A9; # (땎; 땎; 땎; 땎; 땎; ) HANGUL SYLLABLE DDAEGG +B54F;B54F;1104 1162 11AA;B54F;1104 1162 11AA; # (땏; 땏; 땏; 땏; 땏; ) HANGUL SYLLABLE DDAEGS +B550;B550;1104 1162 11AB;B550;1104 1162 11AB; # (땐; 땐; 땐; 땐; 땐; ) HANGUL SYLLABLE DDAEN +B551;B551;1104 1162 11AC;B551;1104 1162 11AC; # (땑; 땑; 땑; 땑; 땑; ) HANGUL SYLLABLE DDAENJ +B552;B552;1104 1162 11AD;B552;1104 1162 11AD; # (땒; 땒; 땒; 땒; 땒; ) HANGUL SYLLABLE DDAENH +B553;B553;1104 1162 11AE;B553;1104 1162 11AE; # (땓; 땓; 땓; 땓; 땓; ) HANGUL SYLLABLE DDAED +B554;B554;1104 1162 11AF;B554;1104 1162 11AF; # (땔; 땔; 땔; 땔; 땔; ) HANGUL SYLLABLE DDAEL +B555;B555;1104 1162 11B0;B555;1104 1162 11B0; # (땕; 땕; 땕; 땕; 땕; ) HANGUL SYLLABLE DDAELG +B556;B556;1104 1162 11B1;B556;1104 1162 11B1; # (땖; 땖; 땖; 땖; 땖; ) HANGUL SYLLABLE DDAELM +B557;B557;1104 1162 11B2;B557;1104 1162 11B2; # (땗; 땗; 땗; 땗; 땗; ) HANGUL SYLLABLE DDAELB +B558;B558;1104 1162 11B3;B558;1104 1162 11B3; # (땘; 땘; 땘; 땘; 땘; ) HANGUL SYLLABLE DDAELS +B559;B559;1104 1162 11B4;B559;1104 1162 11B4; # (땙; 땙; 땙; 땙; 땙; ) HANGUL SYLLABLE DDAELT +B55A;B55A;1104 1162 11B5;B55A;1104 1162 11B5; # (땚; 땚; 땚; 땚; 땚; ) HANGUL SYLLABLE DDAELP +B55B;B55B;1104 1162 11B6;B55B;1104 1162 11B6; # (땛; 땛; 땛; 땛; 땛; ) HANGUL SYLLABLE DDAELH +B55C;B55C;1104 1162 11B7;B55C;1104 1162 11B7; # (땜; 땜; 땜; 땜; 땜; ) HANGUL SYLLABLE DDAEM +B55D;B55D;1104 1162 11B8;B55D;1104 1162 11B8; # (땝; 땝; 땝; 땝; 땝; ) HANGUL SYLLABLE DDAEB +B55E;B55E;1104 1162 11B9;B55E;1104 1162 11B9; # (땞; 땞; 땞; 땞; 땞; ) HANGUL SYLLABLE DDAEBS +B55F;B55F;1104 1162 11BA;B55F;1104 1162 11BA; # (땟; 땟; 땟; 땟; 땟; ) HANGUL SYLLABLE DDAES +B560;B560;1104 1162 11BB;B560;1104 1162 11BB; # (땠; 땠; 땠; 땠; 땠; ) HANGUL SYLLABLE DDAESS +B561;B561;1104 1162 11BC;B561;1104 1162 11BC; # (땡; 땡; 땡; 땡; 땡; ) HANGUL SYLLABLE DDAENG +B562;B562;1104 1162 11BD;B562;1104 1162 11BD; # (땢; 땢; 땢; 땢; 땢; ) HANGUL SYLLABLE DDAEJ +B563;B563;1104 1162 11BE;B563;1104 1162 11BE; # (땣; 땣; 땣; 땣; 땣; ) HANGUL SYLLABLE DDAEC +B564;B564;1104 1162 11BF;B564;1104 1162 11BF; # (땤; 땤; 땤; 땤; 땤; ) HANGUL SYLLABLE DDAEK +B565;B565;1104 1162 11C0;B565;1104 1162 11C0; # (땥; 땥; 땥; 땥; 땥; ) HANGUL SYLLABLE DDAET +B566;B566;1104 1162 11C1;B566;1104 1162 11C1; # (땦; 땦; 땦; 땦; 땦; ) HANGUL SYLLABLE DDAEP +B567;B567;1104 1162 11C2;B567;1104 1162 11C2; # (땧; 땧; 땧; 땧; 땧; ) HANGUL SYLLABLE DDAEH +B568;B568;1104 1163;B568;1104 1163; # (땨; 땨; 땨; 땨; 땨; ) HANGUL SYLLABLE DDYA +B569;B569;1104 1163 11A8;B569;1104 1163 11A8; # (땩; 땩; 땩; 땩; 땩; ) HANGUL SYLLABLE DDYAG +B56A;B56A;1104 1163 11A9;B56A;1104 1163 11A9; # (땪; 땪; 땪; 땪; 땪; ) HANGUL SYLLABLE DDYAGG +B56B;B56B;1104 1163 11AA;B56B;1104 1163 11AA; # (땫; 땫; 땫; 땫; 땫; ) HANGUL SYLLABLE DDYAGS +B56C;B56C;1104 1163 11AB;B56C;1104 1163 11AB; # (땬; 땬; 땬; 땬; 땬; ) HANGUL SYLLABLE DDYAN +B56D;B56D;1104 1163 11AC;B56D;1104 1163 11AC; # (땭; 땭; 땭; 땭; 땭; ) HANGUL SYLLABLE DDYANJ +B56E;B56E;1104 1163 11AD;B56E;1104 1163 11AD; # (땮; 땮; 땮; 땮; 땮; ) HANGUL SYLLABLE DDYANH +B56F;B56F;1104 1163 11AE;B56F;1104 1163 11AE; # (땯; 땯; 땯; 땯; 땯; ) HANGUL SYLLABLE DDYAD +B570;B570;1104 1163 11AF;B570;1104 1163 11AF; # (땰; 땰; 땰; 땰; 땰; ) HANGUL SYLLABLE DDYAL +B571;B571;1104 1163 11B0;B571;1104 1163 11B0; # (땱; 땱; 땱; 땱; 땱; ) HANGUL SYLLABLE DDYALG +B572;B572;1104 1163 11B1;B572;1104 1163 11B1; # (땲; 땲; 땲; 땲; 땲; ) HANGUL SYLLABLE DDYALM +B573;B573;1104 1163 11B2;B573;1104 1163 11B2; # (땳; 땳; 땳; 땳; 땳; ) HANGUL SYLLABLE DDYALB +B574;B574;1104 1163 11B3;B574;1104 1163 11B3; # (땴; 땴; 땴; 땴; 땴; ) HANGUL SYLLABLE DDYALS +B575;B575;1104 1163 11B4;B575;1104 1163 11B4; # (땵; 땵; 땵; 땵; 땵; ) HANGUL SYLLABLE DDYALT +B576;B576;1104 1163 11B5;B576;1104 1163 11B5; # (땶; 땶; 땶; 땶; 땶; ) HANGUL SYLLABLE DDYALP +B577;B577;1104 1163 11B6;B577;1104 1163 11B6; # (땷; 땷; 땷; 땷; 땷; ) HANGUL SYLLABLE DDYALH +B578;B578;1104 1163 11B7;B578;1104 1163 11B7; # (땸; 땸; 땸; 땸; 땸; ) HANGUL SYLLABLE DDYAM +B579;B579;1104 1163 11B8;B579;1104 1163 11B8; # (땹; 땹; 땹; 땹; 땹; ) HANGUL SYLLABLE DDYAB +B57A;B57A;1104 1163 11B9;B57A;1104 1163 11B9; # (땺; 땺; 땺; 땺; 땺; ) HANGUL SYLLABLE DDYABS +B57B;B57B;1104 1163 11BA;B57B;1104 1163 11BA; # (땻; 땻; 땻; 땻; 땻; ) HANGUL SYLLABLE DDYAS +B57C;B57C;1104 1163 11BB;B57C;1104 1163 11BB; # (땼; 땼; 땼; 땼; 땼; ) HANGUL SYLLABLE DDYASS +B57D;B57D;1104 1163 11BC;B57D;1104 1163 11BC; # (땽; 땽; 땽; 땽; 땽; ) HANGUL SYLLABLE DDYANG +B57E;B57E;1104 1163 11BD;B57E;1104 1163 11BD; # (땾; 땾; 땾; 땾; 땾; ) HANGUL SYLLABLE DDYAJ +B57F;B57F;1104 1163 11BE;B57F;1104 1163 11BE; # (땿; 땿; 땿; 땿; 땿; ) HANGUL SYLLABLE DDYAC +B580;B580;1104 1163 11BF;B580;1104 1163 11BF; # (떀; 떀; 떀; 떀; 떀; ) HANGUL SYLLABLE DDYAK +B581;B581;1104 1163 11C0;B581;1104 1163 11C0; # (떁; 떁; 떁; 떁; 떁; ) HANGUL SYLLABLE DDYAT +B582;B582;1104 1163 11C1;B582;1104 1163 11C1; # (떂; 떂; 떂; 떂; 떂; ) HANGUL SYLLABLE DDYAP +B583;B583;1104 1163 11C2;B583;1104 1163 11C2; # (떃; 떃; 떃; 떃; 떃; ) HANGUL SYLLABLE DDYAH +B584;B584;1104 1164;B584;1104 1164; # (떄; 떄; 떄; 떄; 떄; ) HANGUL SYLLABLE DDYAE +B585;B585;1104 1164 11A8;B585;1104 1164 11A8; # (떅; 떅; 떅; 떅; 떅; ) HANGUL SYLLABLE DDYAEG +B586;B586;1104 1164 11A9;B586;1104 1164 11A9; # (떆; 떆; 떆; 떆; 떆; ) HANGUL SYLLABLE DDYAEGG +B587;B587;1104 1164 11AA;B587;1104 1164 11AA; # (떇; 떇; 떇; 떇; 떇; ) HANGUL SYLLABLE DDYAEGS +B588;B588;1104 1164 11AB;B588;1104 1164 11AB; # (떈; 떈; 떈; 떈; 떈; ) HANGUL SYLLABLE DDYAEN +B589;B589;1104 1164 11AC;B589;1104 1164 11AC; # (떉; 떉; 떉; 떉; 떉; ) HANGUL SYLLABLE DDYAENJ +B58A;B58A;1104 1164 11AD;B58A;1104 1164 11AD; # (떊; 떊; 떊; 떊; 떊; ) HANGUL SYLLABLE DDYAENH +B58B;B58B;1104 1164 11AE;B58B;1104 1164 11AE; # (떋; 떋; 떋; 떋; 떋; ) HANGUL SYLLABLE DDYAED +B58C;B58C;1104 1164 11AF;B58C;1104 1164 11AF; # (떌; 떌; 떌; 떌; 떌; ) HANGUL SYLLABLE DDYAEL +B58D;B58D;1104 1164 11B0;B58D;1104 1164 11B0; # (떍; 떍; 떍; 떍; 떍; ) HANGUL SYLLABLE DDYAELG +B58E;B58E;1104 1164 11B1;B58E;1104 1164 11B1; # (떎; 떎; 떎; 떎; 떎; ) HANGUL SYLLABLE DDYAELM +B58F;B58F;1104 1164 11B2;B58F;1104 1164 11B2; # (떏; 떏; 떏; 떏; 떏; ) HANGUL SYLLABLE DDYAELB +B590;B590;1104 1164 11B3;B590;1104 1164 11B3; # (떐; 떐; 떐; 떐; 떐; ) HANGUL SYLLABLE DDYAELS +B591;B591;1104 1164 11B4;B591;1104 1164 11B4; # (떑; 떑; 떑; 떑; 떑; ) HANGUL SYLLABLE DDYAELT +B592;B592;1104 1164 11B5;B592;1104 1164 11B5; # (떒; 떒; 떒; 떒; 떒; ) HANGUL SYLLABLE DDYAELP +B593;B593;1104 1164 11B6;B593;1104 1164 11B6; # (떓; 떓; 떓; 떓; 떓; ) HANGUL SYLLABLE DDYAELH +B594;B594;1104 1164 11B7;B594;1104 1164 11B7; # (떔; 떔; 떔; 떔; 떔; ) HANGUL SYLLABLE DDYAEM +B595;B595;1104 1164 11B8;B595;1104 1164 11B8; # (떕; 떕; 떕; 떕; 떕; ) HANGUL SYLLABLE DDYAEB +B596;B596;1104 1164 11B9;B596;1104 1164 11B9; # (떖; 떖; 떖; 떖; 떖; ) HANGUL SYLLABLE DDYAEBS +B597;B597;1104 1164 11BA;B597;1104 1164 11BA; # (떗; 떗; 떗; 떗; 떗; ) HANGUL SYLLABLE DDYAES +B598;B598;1104 1164 11BB;B598;1104 1164 11BB; # (떘; 떘; 떘; 떘; 떘; ) HANGUL SYLLABLE DDYAESS +B599;B599;1104 1164 11BC;B599;1104 1164 11BC; # (떙; 떙; 떙; 떙; 떙; ) HANGUL SYLLABLE DDYAENG +B59A;B59A;1104 1164 11BD;B59A;1104 1164 11BD; # (떚; 떚; 떚; 떚; 떚; ) HANGUL SYLLABLE DDYAEJ +B59B;B59B;1104 1164 11BE;B59B;1104 1164 11BE; # (떛; 떛; 떛; 떛; 떛; ) HANGUL SYLLABLE DDYAEC +B59C;B59C;1104 1164 11BF;B59C;1104 1164 11BF; # (떜; 떜; 떜; 떜; 떜; ) HANGUL SYLLABLE DDYAEK +B59D;B59D;1104 1164 11C0;B59D;1104 1164 11C0; # (떝; 떝; 떝; 떝; 떝; ) HANGUL SYLLABLE DDYAET +B59E;B59E;1104 1164 11C1;B59E;1104 1164 11C1; # (떞; 떞; 떞; 떞; 떞; ) HANGUL SYLLABLE DDYAEP +B59F;B59F;1104 1164 11C2;B59F;1104 1164 11C2; # (떟; 떟; 떟; 떟; 떟; ) HANGUL SYLLABLE DDYAEH +B5A0;B5A0;1104 1165;B5A0;1104 1165; # (떠; 떠; 떠; 떠; 떠; ) HANGUL SYLLABLE DDEO +B5A1;B5A1;1104 1165 11A8;B5A1;1104 1165 11A8; # (떡; 떡; 떡; 떡; 떡; ) HANGUL SYLLABLE DDEOG +B5A2;B5A2;1104 1165 11A9;B5A2;1104 1165 11A9; # (떢; 떢; 떢; 떢; 떢; ) HANGUL SYLLABLE DDEOGG +B5A3;B5A3;1104 1165 11AA;B5A3;1104 1165 11AA; # (떣; 떣; 떣; 떣; 떣; ) HANGUL SYLLABLE DDEOGS +B5A4;B5A4;1104 1165 11AB;B5A4;1104 1165 11AB; # (떤; 떤; 떤; 떤; 떤; ) HANGUL SYLLABLE DDEON +B5A5;B5A5;1104 1165 11AC;B5A5;1104 1165 11AC; # (떥; 떥; 떥; 떥; 떥; ) HANGUL SYLLABLE DDEONJ +B5A6;B5A6;1104 1165 11AD;B5A6;1104 1165 11AD; # (떦; 떦; 떦; 떦; 떦; ) HANGUL SYLLABLE DDEONH +B5A7;B5A7;1104 1165 11AE;B5A7;1104 1165 11AE; # (떧; 떧; 떧; 떧; 떧; ) HANGUL SYLLABLE DDEOD +B5A8;B5A8;1104 1165 11AF;B5A8;1104 1165 11AF; # (떨; 떨; 떨; 떨; 떨; ) HANGUL SYLLABLE DDEOL +B5A9;B5A9;1104 1165 11B0;B5A9;1104 1165 11B0; # (떩; 떩; 떩; 떩; 떩; ) HANGUL SYLLABLE DDEOLG +B5AA;B5AA;1104 1165 11B1;B5AA;1104 1165 11B1; # (떪; 떪; 떪; 떪; 떪; ) HANGUL SYLLABLE DDEOLM +B5AB;B5AB;1104 1165 11B2;B5AB;1104 1165 11B2; # (떫; 떫; 떫; 떫; 떫; ) HANGUL SYLLABLE DDEOLB +B5AC;B5AC;1104 1165 11B3;B5AC;1104 1165 11B3; # (떬; 떬; 떬; 떬; 떬; ) HANGUL SYLLABLE DDEOLS +B5AD;B5AD;1104 1165 11B4;B5AD;1104 1165 11B4; # (떭; 떭; 떭; 떭; 떭; ) HANGUL SYLLABLE DDEOLT +B5AE;B5AE;1104 1165 11B5;B5AE;1104 1165 11B5; # (떮; 떮; 떮; 떮; 떮; ) HANGUL SYLLABLE DDEOLP +B5AF;B5AF;1104 1165 11B6;B5AF;1104 1165 11B6; # (떯; 떯; 떯; 떯; 떯; ) HANGUL SYLLABLE DDEOLH +B5B0;B5B0;1104 1165 11B7;B5B0;1104 1165 11B7; # (떰; 떰; 떰; 떰; 떰; ) HANGUL SYLLABLE DDEOM +B5B1;B5B1;1104 1165 11B8;B5B1;1104 1165 11B8; # (떱; 떱; 떱; 떱; 떱; ) HANGUL SYLLABLE DDEOB +B5B2;B5B2;1104 1165 11B9;B5B2;1104 1165 11B9; # (떲; 떲; 떲; 떲; 떲; ) HANGUL SYLLABLE DDEOBS +B5B3;B5B3;1104 1165 11BA;B5B3;1104 1165 11BA; # (떳; 떳; 떳; 떳; 떳; ) HANGUL SYLLABLE DDEOS +B5B4;B5B4;1104 1165 11BB;B5B4;1104 1165 11BB; # (떴; 떴; 떴; 떴; 떴; ) HANGUL SYLLABLE DDEOSS +B5B5;B5B5;1104 1165 11BC;B5B5;1104 1165 11BC; # (떵; 떵; 떵; 떵; 떵; ) HANGUL SYLLABLE DDEONG +B5B6;B5B6;1104 1165 11BD;B5B6;1104 1165 11BD; # (떶; 떶; 떶; 떶; 떶; ) HANGUL SYLLABLE DDEOJ +B5B7;B5B7;1104 1165 11BE;B5B7;1104 1165 11BE; # (떷; 떷; 떷; 떷; 떷; ) HANGUL SYLLABLE DDEOC +B5B8;B5B8;1104 1165 11BF;B5B8;1104 1165 11BF; # (떸; 떸; 떸; 떸; 떸; ) HANGUL SYLLABLE DDEOK +B5B9;B5B9;1104 1165 11C0;B5B9;1104 1165 11C0; # (떹; 떹; 떹; 떹; 떹; ) HANGUL SYLLABLE DDEOT +B5BA;B5BA;1104 1165 11C1;B5BA;1104 1165 11C1; # (떺; 떺; 떺; 떺; 떺; ) HANGUL SYLLABLE DDEOP +B5BB;B5BB;1104 1165 11C2;B5BB;1104 1165 11C2; # (떻; 떻; 떻; 떻; 떻; ) HANGUL SYLLABLE DDEOH +B5BC;B5BC;1104 1166;B5BC;1104 1166; # (떼; 떼; 떼; 떼; 떼; ) HANGUL SYLLABLE DDE +B5BD;B5BD;1104 1166 11A8;B5BD;1104 1166 11A8; # (떽; 떽; 떽; 떽; 떽; ) HANGUL SYLLABLE DDEG +B5BE;B5BE;1104 1166 11A9;B5BE;1104 1166 11A9; # (떾; 떾; 떾; 떾; 떾; ) HANGUL SYLLABLE DDEGG +B5BF;B5BF;1104 1166 11AA;B5BF;1104 1166 11AA; # (떿; 떿; 떿; 떿; 떿; ) HANGUL SYLLABLE DDEGS +B5C0;B5C0;1104 1166 11AB;B5C0;1104 1166 11AB; # (뗀; 뗀; 뗀; 뗀; 뗀; ) HANGUL SYLLABLE DDEN +B5C1;B5C1;1104 1166 11AC;B5C1;1104 1166 11AC; # (뗁; 뗁; 뗁; 뗁; 뗁; ) HANGUL SYLLABLE DDENJ +B5C2;B5C2;1104 1166 11AD;B5C2;1104 1166 11AD; # (뗂; 뗂; 뗂; 뗂; 뗂; ) HANGUL SYLLABLE DDENH +B5C3;B5C3;1104 1166 11AE;B5C3;1104 1166 11AE; # (뗃; 뗃; 뗃; 뗃; 뗃; ) HANGUL SYLLABLE DDED +B5C4;B5C4;1104 1166 11AF;B5C4;1104 1166 11AF; # (뗄; 뗄; 뗄; 뗄; 뗄; ) HANGUL SYLLABLE DDEL +B5C5;B5C5;1104 1166 11B0;B5C5;1104 1166 11B0; # (뗅; 뗅; 뗅; 뗅; 뗅; ) HANGUL SYLLABLE DDELG +B5C6;B5C6;1104 1166 11B1;B5C6;1104 1166 11B1; # (뗆; 뗆; 뗆; 뗆; 뗆; ) HANGUL SYLLABLE DDELM +B5C7;B5C7;1104 1166 11B2;B5C7;1104 1166 11B2; # (뗇; 뗇; 뗇; 뗇; 뗇; ) HANGUL SYLLABLE DDELB +B5C8;B5C8;1104 1166 11B3;B5C8;1104 1166 11B3; # (뗈; 뗈; 뗈; 뗈; 뗈; ) HANGUL SYLLABLE DDELS +B5C9;B5C9;1104 1166 11B4;B5C9;1104 1166 11B4; # (뗉; 뗉; 뗉; 뗉; 뗉; ) HANGUL SYLLABLE DDELT +B5CA;B5CA;1104 1166 11B5;B5CA;1104 1166 11B5; # (뗊; 뗊; 뗊; 뗊; 뗊; ) HANGUL SYLLABLE DDELP +B5CB;B5CB;1104 1166 11B6;B5CB;1104 1166 11B6; # (뗋; 뗋; 뗋; 뗋; 뗋; ) HANGUL SYLLABLE DDELH +B5CC;B5CC;1104 1166 11B7;B5CC;1104 1166 11B7; # (뗌; 뗌; 뗌; 뗌; 뗌; ) HANGUL SYLLABLE DDEM +B5CD;B5CD;1104 1166 11B8;B5CD;1104 1166 11B8; # (뗍; 뗍; 뗍; 뗍; 뗍; ) HANGUL SYLLABLE DDEB +B5CE;B5CE;1104 1166 11B9;B5CE;1104 1166 11B9; # (뗎; 뗎; 뗎; 뗎; 뗎; ) HANGUL SYLLABLE DDEBS +B5CF;B5CF;1104 1166 11BA;B5CF;1104 1166 11BA; # (뗏; 뗏; 뗏; 뗏; 뗏; ) HANGUL SYLLABLE DDES +B5D0;B5D0;1104 1166 11BB;B5D0;1104 1166 11BB; # (뗐; 뗐; 뗐; 뗐; 뗐; ) HANGUL SYLLABLE DDESS +B5D1;B5D1;1104 1166 11BC;B5D1;1104 1166 11BC; # (뗑; 뗑; 뗑; 뗑; 뗑; ) HANGUL SYLLABLE DDENG +B5D2;B5D2;1104 1166 11BD;B5D2;1104 1166 11BD; # (뗒; 뗒; 뗒; 뗒; 뗒; ) HANGUL SYLLABLE DDEJ +B5D3;B5D3;1104 1166 11BE;B5D3;1104 1166 11BE; # (뗓; 뗓; 뗓; 뗓; 뗓; ) HANGUL SYLLABLE DDEC +B5D4;B5D4;1104 1166 11BF;B5D4;1104 1166 11BF; # (뗔; 뗔; 뗔; 뗔; 뗔; ) HANGUL SYLLABLE DDEK +B5D5;B5D5;1104 1166 11C0;B5D5;1104 1166 11C0; # (뗕; 뗕; 뗕; 뗕; 뗕; ) HANGUL SYLLABLE DDET +B5D6;B5D6;1104 1166 11C1;B5D6;1104 1166 11C1; # (뗖; 뗖; 뗖; 뗖; 뗖; ) HANGUL SYLLABLE DDEP +B5D7;B5D7;1104 1166 11C2;B5D7;1104 1166 11C2; # (뗗; 뗗; 뗗; 뗗; 뗗; ) HANGUL SYLLABLE DDEH +B5D8;B5D8;1104 1167;B5D8;1104 1167; # (뗘; 뗘; 뗘; 뗘; 뗘; ) HANGUL SYLLABLE DDYEO +B5D9;B5D9;1104 1167 11A8;B5D9;1104 1167 11A8; # (뗙; 뗙; 뗙; 뗙; 뗙; ) HANGUL SYLLABLE DDYEOG +B5DA;B5DA;1104 1167 11A9;B5DA;1104 1167 11A9; # (뗚; 뗚; 뗚; 뗚; 뗚; ) HANGUL SYLLABLE DDYEOGG +B5DB;B5DB;1104 1167 11AA;B5DB;1104 1167 11AA; # (뗛; 뗛; 뗛; 뗛; 뗛; ) HANGUL SYLLABLE DDYEOGS +B5DC;B5DC;1104 1167 11AB;B5DC;1104 1167 11AB; # (뗜; 뗜; 뗜; 뗜; 뗜; ) HANGUL SYLLABLE DDYEON +B5DD;B5DD;1104 1167 11AC;B5DD;1104 1167 11AC; # (뗝; 뗝; 뗝; 뗝; 뗝; ) HANGUL SYLLABLE DDYEONJ +B5DE;B5DE;1104 1167 11AD;B5DE;1104 1167 11AD; # (뗞; 뗞; 뗞; 뗞; 뗞; ) HANGUL SYLLABLE DDYEONH +B5DF;B5DF;1104 1167 11AE;B5DF;1104 1167 11AE; # (뗟; 뗟; 뗟; 뗟; 뗟; ) HANGUL SYLLABLE DDYEOD +B5E0;B5E0;1104 1167 11AF;B5E0;1104 1167 11AF; # (뗠; 뗠; 뗠; 뗠; 뗠; ) HANGUL SYLLABLE DDYEOL +B5E1;B5E1;1104 1167 11B0;B5E1;1104 1167 11B0; # (뗡; 뗡; 뗡; 뗡; 뗡; ) HANGUL SYLLABLE DDYEOLG +B5E2;B5E2;1104 1167 11B1;B5E2;1104 1167 11B1; # (뗢; 뗢; 뗢; 뗢; 뗢; ) HANGUL SYLLABLE DDYEOLM +B5E3;B5E3;1104 1167 11B2;B5E3;1104 1167 11B2; # (뗣; 뗣; 뗣; 뗣; 뗣; ) HANGUL SYLLABLE DDYEOLB +B5E4;B5E4;1104 1167 11B3;B5E4;1104 1167 11B3; # (뗤; 뗤; 뗤; 뗤; 뗤; ) HANGUL SYLLABLE DDYEOLS +B5E5;B5E5;1104 1167 11B4;B5E5;1104 1167 11B4; # (뗥; 뗥; 뗥; 뗥; 뗥; ) HANGUL SYLLABLE DDYEOLT +B5E6;B5E6;1104 1167 11B5;B5E6;1104 1167 11B5; # (뗦; 뗦; 뗦; 뗦; 뗦; ) HANGUL SYLLABLE DDYEOLP +B5E7;B5E7;1104 1167 11B6;B5E7;1104 1167 11B6; # (뗧; 뗧; 뗧; 뗧; 뗧; ) HANGUL SYLLABLE DDYEOLH +B5E8;B5E8;1104 1167 11B7;B5E8;1104 1167 11B7; # (뗨; 뗨; 뗨; 뗨; 뗨; ) HANGUL SYLLABLE DDYEOM +B5E9;B5E9;1104 1167 11B8;B5E9;1104 1167 11B8; # (뗩; 뗩; 뗩; 뗩; 뗩; ) HANGUL SYLLABLE DDYEOB +B5EA;B5EA;1104 1167 11B9;B5EA;1104 1167 11B9; # (뗪; 뗪; 뗪; 뗪; 뗪; ) HANGUL SYLLABLE DDYEOBS +B5EB;B5EB;1104 1167 11BA;B5EB;1104 1167 11BA; # (뗫; 뗫; 뗫; 뗫; 뗫; ) HANGUL SYLLABLE DDYEOS +B5EC;B5EC;1104 1167 11BB;B5EC;1104 1167 11BB; # (뗬; 뗬; 뗬; 뗬; 뗬; ) HANGUL SYLLABLE DDYEOSS +B5ED;B5ED;1104 1167 11BC;B5ED;1104 1167 11BC; # (뗭; 뗭; 뗭; 뗭; 뗭; ) HANGUL SYLLABLE DDYEONG +B5EE;B5EE;1104 1167 11BD;B5EE;1104 1167 11BD; # (뗮; 뗮; 뗮; 뗮; 뗮; ) HANGUL SYLLABLE DDYEOJ +B5EF;B5EF;1104 1167 11BE;B5EF;1104 1167 11BE; # (뗯; 뗯; 뗯; 뗯; 뗯; ) HANGUL SYLLABLE DDYEOC +B5F0;B5F0;1104 1167 11BF;B5F0;1104 1167 11BF; # (뗰; 뗰; 뗰; 뗰; 뗰; ) HANGUL SYLLABLE DDYEOK +B5F1;B5F1;1104 1167 11C0;B5F1;1104 1167 11C0; # (뗱; 뗱; 뗱; 뗱; 뗱; ) HANGUL SYLLABLE DDYEOT +B5F2;B5F2;1104 1167 11C1;B5F2;1104 1167 11C1; # (뗲; 뗲; 뗲; 뗲; 뗲; ) HANGUL SYLLABLE DDYEOP +B5F3;B5F3;1104 1167 11C2;B5F3;1104 1167 11C2; # (뗳; 뗳; 뗳; 뗳; 뗳; ) HANGUL SYLLABLE DDYEOH +B5F4;B5F4;1104 1168;B5F4;1104 1168; # (뗴; 뗴; 뗴; 뗴; 뗴; ) HANGUL SYLLABLE DDYE +B5F5;B5F5;1104 1168 11A8;B5F5;1104 1168 11A8; # (뗵; 뗵; 뗵; 뗵; 뗵; ) HANGUL SYLLABLE DDYEG +B5F6;B5F6;1104 1168 11A9;B5F6;1104 1168 11A9; # (뗶; 뗶; 뗶; 뗶; 뗶; ) HANGUL SYLLABLE DDYEGG +B5F7;B5F7;1104 1168 11AA;B5F7;1104 1168 11AA; # (뗷; 뗷; 뗷; 뗷; 뗷; ) HANGUL SYLLABLE DDYEGS +B5F8;B5F8;1104 1168 11AB;B5F8;1104 1168 11AB; # (뗸; 뗸; 뗸; 뗸; 뗸; ) HANGUL SYLLABLE DDYEN +B5F9;B5F9;1104 1168 11AC;B5F9;1104 1168 11AC; # (뗹; 뗹; 뗹; 뗹; 뗹; ) HANGUL SYLLABLE DDYENJ +B5FA;B5FA;1104 1168 11AD;B5FA;1104 1168 11AD; # (뗺; 뗺; 뗺; 뗺; 뗺; ) HANGUL SYLLABLE DDYENH +B5FB;B5FB;1104 1168 11AE;B5FB;1104 1168 11AE; # (뗻; 뗻; 뗻; 뗻; 뗻; ) HANGUL SYLLABLE DDYED +B5FC;B5FC;1104 1168 11AF;B5FC;1104 1168 11AF; # (뗼; 뗼; 뗼; 뗼; 뗼; ) HANGUL SYLLABLE DDYEL +B5FD;B5FD;1104 1168 11B0;B5FD;1104 1168 11B0; # (뗽; 뗽; 뗽; 뗽; 뗽; ) HANGUL SYLLABLE DDYELG +B5FE;B5FE;1104 1168 11B1;B5FE;1104 1168 11B1; # (뗾; 뗾; 뗾; 뗾; 뗾; ) HANGUL SYLLABLE DDYELM +B5FF;B5FF;1104 1168 11B2;B5FF;1104 1168 11B2; # (뗿; 뗿; 뗿; 뗿; 뗿; ) HANGUL SYLLABLE DDYELB +B600;B600;1104 1168 11B3;B600;1104 1168 11B3; # (똀; 똀; 똀; 똀; 똀; ) HANGUL SYLLABLE DDYELS +B601;B601;1104 1168 11B4;B601;1104 1168 11B4; # (똁; 똁; 똁; 똁; 똁; ) HANGUL SYLLABLE DDYELT +B602;B602;1104 1168 11B5;B602;1104 1168 11B5; # (똂; 똂; 똂; 똂; 똂; ) HANGUL SYLLABLE DDYELP +B603;B603;1104 1168 11B6;B603;1104 1168 11B6; # (똃; 똃; 똃; 똃; 똃; ) HANGUL SYLLABLE DDYELH +B604;B604;1104 1168 11B7;B604;1104 1168 11B7; # (똄; 똄; 똄; 똄; 똄; ) HANGUL SYLLABLE DDYEM +B605;B605;1104 1168 11B8;B605;1104 1168 11B8; # (똅; 똅; 똅; 똅; 똅; ) HANGUL SYLLABLE DDYEB +B606;B606;1104 1168 11B9;B606;1104 1168 11B9; # (똆; 똆; 똆; 똆; 똆; ) HANGUL SYLLABLE DDYEBS +B607;B607;1104 1168 11BA;B607;1104 1168 11BA; # (똇; 똇; 똇; 똇; 똇; ) HANGUL SYLLABLE DDYES +B608;B608;1104 1168 11BB;B608;1104 1168 11BB; # (똈; 똈; 똈; 똈; 똈; ) HANGUL SYLLABLE DDYESS +B609;B609;1104 1168 11BC;B609;1104 1168 11BC; # (똉; 똉; 똉; 똉; 똉; ) HANGUL SYLLABLE DDYENG +B60A;B60A;1104 1168 11BD;B60A;1104 1168 11BD; # (똊; 똊; 똊; 똊; 똊; ) HANGUL SYLLABLE DDYEJ +B60B;B60B;1104 1168 11BE;B60B;1104 1168 11BE; # (똋; 똋; 똋; 똋; 똋; ) HANGUL SYLLABLE DDYEC +B60C;B60C;1104 1168 11BF;B60C;1104 1168 11BF; # (똌; 똌; 똌; 똌; 똌; ) HANGUL SYLLABLE DDYEK +B60D;B60D;1104 1168 11C0;B60D;1104 1168 11C0; # (똍; 똍; 똍; 똍; 똍; ) HANGUL SYLLABLE DDYET +B60E;B60E;1104 1168 11C1;B60E;1104 1168 11C1; # (똎; 똎; 똎; 똎; 똎; ) HANGUL SYLLABLE DDYEP +B60F;B60F;1104 1168 11C2;B60F;1104 1168 11C2; # (똏; 똏; 똏; 똏; 똏; ) HANGUL SYLLABLE DDYEH +B610;B610;1104 1169;B610;1104 1169; # (또; 또; 또; 또; 또; ) HANGUL SYLLABLE DDO +B611;B611;1104 1169 11A8;B611;1104 1169 11A8; # (똑; 똑; 똑; 똑; 똑; ) HANGUL SYLLABLE DDOG +B612;B612;1104 1169 11A9;B612;1104 1169 11A9; # (똒; 똒; 똒; 똒; 똒; ) HANGUL SYLLABLE DDOGG +B613;B613;1104 1169 11AA;B613;1104 1169 11AA; # (똓; 똓; 똓; 똓; 똓; ) HANGUL SYLLABLE DDOGS +B614;B614;1104 1169 11AB;B614;1104 1169 11AB; # (똔; 똔; 똔; 똔; 똔; ) HANGUL SYLLABLE DDON +B615;B615;1104 1169 11AC;B615;1104 1169 11AC; # (똕; 똕; 똕; 똕; 똕; ) HANGUL SYLLABLE DDONJ +B616;B616;1104 1169 11AD;B616;1104 1169 11AD; # (똖; 똖; 똖; 똖; 똖; ) HANGUL SYLLABLE DDONH +B617;B617;1104 1169 11AE;B617;1104 1169 11AE; # (똗; 똗; 똗; 똗; 똗; ) HANGUL SYLLABLE DDOD +B618;B618;1104 1169 11AF;B618;1104 1169 11AF; # (똘; 똘; 똘; 똘; 똘; ) HANGUL SYLLABLE DDOL +B619;B619;1104 1169 11B0;B619;1104 1169 11B0; # (똙; 똙; 똙; 똙; 똙; ) HANGUL SYLLABLE DDOLG +B61A;B61A;1104 1169 11B1;B61A;1104 1169 11B1; # (똚; 똚; 똚; 똚; 똚; ) HANGUL SYLLABLE DDOLM +B61B;B61B;1104 1169 11B2;B61B;1104 1169 11B2; # (똛; 똛; 똛; 똛; 똛; ) HANGUL SYLLABLE DDOLB +B61C;B61C;1104 1169 11B3;B61C;1104 1169 11B3; # (똜; 똜; 똜; 똜; 똜; ) HANGUL SYLLABLE DDOLS +B61D;B61D;1104 1169 11B4;B61D;1104 1169 11B4; # (똝; 똝; 똝; 똝; 똝; ) HANGUL SYLLABLE DDOLT +B61E;B61E;1104 1169 11B5;B61E;1104 1169 11B5; # (똞; 똞; 똞; 똞; 똞; ) HANGUL SYLLABLE DDOLP +B61F;B61F;1104 1169 11B6;B61F;1104 1169 11B6; # (똟; 똟; 똟; 똟; 똟; ) HANGUL SYLLABLE DDOLH +B620;B620;1104 1169 11B7;B620;1104 1169 11B7; # (똠; 똠; 똠; 똠; 똠; ) HANGUL SYLLABLE DDOM +B621;B621;1104 1169 11B8;B621;1104 1169 11B8; # (똡; 똡; 똡; 똡; 똡; ) HANGUL SYLLABLE DDOB +B622;B622;1104 1169 11B9;B622;1104 1169 11B9; # (똢; 똢; 똢; 똢; 똢; ) HANGUL SYLLABLE DDOBS +B623;B623;1104 1169 11BA;B623;1104 1169 11BA; # (똣; 똣; 똣; 똣; 똣; ) HANGUL SYLLABLE DDOS +B624;B624;1104 1169 11BB;B624;1104 1169 11BB; # (똤; 똤; 똤; 똤; 똤; ) HANGUL SYLLABLE DDOSS +B625;B625;1104 1169 11BC;B625;1104 1169 11BC; # (똥; 똥; 똥; 똥; 똥; ) HANGUL SYLLABLE DDONG +B626;B626;1104 1169 11BD;B626;1104 1169 11BD; # (똦; 똦; 똦; 똦; 똦; ) HANGUL SYLLABLE DDOJ +B627;B627;1104 1169 11BE;B627;1104 1169 11BE; # (똧; 똧; 똧; 똧; 똧; ) HANGUL SYLLABLE DDOC +B628;B628;1104 1169 11BF;B628;1104 1169 11BF; # (똨; 똨; 똨; 똨; 똨; ) HANGUL SYLLABLE DDOK +B629;B629;1104 1169 11C0;B629;1104 1169 11C0; # (똩; 똩; 똩; 똩; 똩; ) HANGUL SYLLABLE DDOT +B62A;B62A;1104 1169 11C1;B62A;1104 1169 11C1; # (똪; 똪; 똪; 똪; 똪; ) HANGUL SYLLABLE DDOP +B62B;B62B;1104 1169 11C2;B62B;1104 1169 11C2; # (똫; 똫; 똫; 똫; 똫; ) HANGUL SYLLABLE DDOH +B62C;B62C;1104 116A;B62C;1104 116A; # (똬; 똬; 똬; 똬; 똬; ) HANGUL SYLLABLE DDWA +B62D;B62D;1104 116A 11A8;B62D;1104 116A 11A8; # (똭; 똭; 똭; 똭; 똭; ) HANGUL SYLLABLE DDWAG +B62E;B62E;1104 116A 11A9;B62E;1104 116A 11A9; # (똮; 똮; 똮; 똮; 똮; ) HANGUL SYLLABLE DDWAGG +B62F;B62F;1104 116A 11AA;B62F;1104 116A 11AA; # (똯; 똯; 똯; 똯; 똯; ) HANGUL SYLLABLE DDWAGS +B630;B630;1104 116A 11AB;B630;1104 116A 11AB; # (똰; 똰; 똰; 똰; 똰; ) HANGUL SYLLABLE DDWAN +B631;B631;1104 116A 11AC;B631;1104 116A 11AC; # (똱; 똱; 똱; 똱; 똱; ) HANGUL SYLLABLE DDWANJ +B632;B632;1104 116A 11AD;B632;1104 116A 11AD; # (똲; 똲; 똲; 똲; 똲; ) HANGUL SYLLABLE DDWANH +B633;B633;1104 116A 11AE;B633;1104 116A 11AE; # (똳; 똳; 똳; 똳; 똳; ) HANGUL SYLLABLE DDWAD +B634;B634;1104 116A 11AF;B634;1104 116A 11AF; # (똴; 똴; 똴; 똴; 똴; ) HANGUL SYLLABLE DDWAL +B635;B635;1104 116A 11B0;B635;1104 116A 11B0; # (똵; 똵; 똵; 똵; 똵; ) HANGUL SYLLABLE DDWALG +B636;B636;1104 116A 11B1;B636;1104 116A 11B1; # (똶; 똶; 똶; 똶; 똶; ) HANGUL SYLLABLE DDWALM +B637;B637;1104 116A 11B2;B637;1104 116A 11B2; # (똷; 똷; 똷; 똷; 똷; ) HANGUL SYLLABLE DDWALB +B638;B638;1104 116A 11B3;B638;1104 116A 11B3; # (똸; 똸; 똸; 똸; 똸; ) HANGUL SYLLABLE DDWALS +B639;B639;1104 116A 11B4;B639;1104 116A 11B4; # (똹; 똹; 똹; 똹; 똹; ) HANGUL SYLLABLE DDWALT +B63A;B63A;1104 116A 11B5;B63A;1104 116A 11B5; # (똺; 똺; 똺; 똺; 똺; ) HANGUL SYLLABLE DDWALP +B63B;B63B;1104 116A 11B6;B63B;1104 116A 11B6; # (똻; 똻; 똻; 똻; 똻; ) HANGUL SYLLABLE DDWALH +B63C;B63C;1104 116A 11B7;B63C;1104 116A 11B7; # (똼; 똼; 똼; 똼; 똼; ) HANGUL SYLLABLE DDWAM +B63D;B63D;1104 116A 11B8;B63D;1104 116A 11B8; # (똽; 똽; 똽; 똽; 똽; ) HANGUL SYLLABLE DDWAB +B63E;B63E;1104 116A 11B9;B63E;1104 116A 11B9; # (똾; 똾; 똾; 똾; 똾; ) HANGUL SYLLABLE DDWABS +B63F;B63F;1104 116A 11BA;B63F;1104 116A 11BA; # (똿; 똿; 똿; 똿; 똿; ) HANGUL SYLLABLE DDWAS +B640;B640;1104 116A 11BB;B640;1104 116A 11BB; # (뙀; 뙀; 뙀; 뙀; 뙀; ) HANGUL SYLLABLE DDWASS +B641;B641;1104 116A 11BC;B641;1104 116A 11BC; # (뙁; 뙁; 뙁; 뙁; 뙁; ) HANGUL SYLLABLE DDWANG +B642;B642;1104 116A 11BD;B642;1104 116A 11BD; # (뙂; 뙂; 뙂; 뙂; 뙂; ) HANGUL SYLLABLE DDWAJ +B643;B643;1104 116A 11BE;B643;1104 116A 11BE; # (뙃; 뙃; 뙃; 뙃; 뙃; ) HANGUL SYLLABLE DDWAC +B644;B644;1104 116A 11BF;B644;1104 116A 11BF; # (뙄; 뙄; 뙄; 뙄; 뙄; ) HANGUL SYLLABLE DDWAK +B645;B645;1104 116A 11C0;B645;1104 116A 11C0; # (뙅; 뙅; 뙅; 뙅; 뙅; ) HANGUL SYLLABLE DDWAT +B646;B646;1104 116A 11C1;B646;1104 116A 11C1; # (뙆; 뙆; 뙆; 뙆; 뙆; ) HANGUL SYLLABLE DDWAP +B647;B647;1104 116A 11C2;B647;1104 116A 11C2; # (뙇; 뙇; 뙇; 뙇; 뙇; ) HANGUL SYLLABLE DDWAH +B648;B648;1104 116B;B648;1104 116B; # (뙈; 뙈; 뙈; 뙈; 뙈; ) HANGUL SYLLABLE DDWAE +B649;B649;1104 116B 11A8;B649;1104 116B 11A8; # (뙉; 뙉; 뙉; 뙉; 뙉; ) HANGUL SYLLABLE DDWAEG +B64A;B64A;1104 116B 11A9;B64A;1104 116B 11A9; # (뙊; 뙊; 뙊; 뙊; 뙊; ) HANGUL SYLLABLE DDWAEGG +B64B;B64B;1104 116B 11AA;B64B;1104 116B 11AA; # (뙋; 뙋; 뙋; 뙋; 뙋; ) HANGUL SYLLABLE DDWAEGS +B64C;B64C;1104 116B 11AB;B64C;1104 116B 11AB; # (뙌; 뙌; 뙌; 뙌; 뙌; ) HANGUL SYLLABLE DDWAEN +B64D;B64D;1104 116B 11AC;B64D;1104 116B 11AC; # (뙍; 뙍; 뙍; 뙍; 뙍; ) HANGUL SYLLABLE DDWAENJ +B64E;B64E;1104 116B 11AD;B64E;1104 116B 11AD; # (뙎; 뙎; 뙎; 뙎; 뙎; ) HANGUL SYLLABLE DDWAENH +B64F;B64F;1104 116B 11AE;B64F;1104 116B 11AE; # (뙏; 뙏; 뙏; 뙏; 뙏; ) HANGUL SYLLABLE DDWAED +B650;B650;1104 116B 11AF;B650;1104 116B 11AF; # (뙐; 뙐; 뙐; 뙐; 뙐; ) HANGUL SYLLABLE DDWAEL +B651;B651;1104 116B 11B0;B651;1104 116B 11B0; # (뙑; 뙑; 뙑; 뙑; 뙑; ) HANGUL SYLLABLE DDWAELG +B652;B652;1104 116B 11B1;B652;1104 116B 11B1; # (뙒; 뙒; 뙒; 뙒; 뙒; ) HANGUL SYLLABLE DDWAELM +B653;B653;1104 116B 11B2;B653;1104 116B 11B2; # (뙓; 뙓; 뙓; 뙓; 뙓; ) HANGUL SYLLABLE DDWAELB +B654;B654;1104 116B 11B3;B654;1104 116B 11B3; # (뙔; 뙔; 뙔; 뙔; 뙔; ) HANGUL SYLLABLE DDWAELS +B655;B655;1104 116B 11B4;B655;1104 116B 11B4; # (뙕; 뙕; 뙕; 뙕; 뙕; ) HANGUL SYLLABLE DDWAELT +B656;B656;1104 116B 11B5;B656;1104 116B 11B5; # (뙖; 뙖; 뙖; 뙖; 뙖; ) HANGUL SYLLABLE DDWAELP +B657;B657;1104 116B 11B6;B657;1104 116B 11B6; # (뙗; 뙗; 뙗; 뙗; 뙗; ) HANGUL SYLLABLE DDWAELH +B658;B658;1104 116B 11B7;B658;1104 116B 11B7; # (뙘; 뙘; 뙘; 뙘; 뙘; ) HANGUL SYLLABLE DDWAEM +B659;B659;1104 116B 11B8;B659;1104 116B 11B8; # (뙙; 뙙; 뙙; 뙙; 뙙; ) HANGUL SYLLABLE DDWAEB +B65A;B65A;1104 116B 11B9;B65A;1104 116B 11B9; # (뙚; 뙚; 뙚; 뙚; 뙚; ) HANGUL SYLLABLE DDWAEBS +B65B;B65B;1104 116B 11BA;B65B;1104 116B 11BA; # (뙛; 뙛; 뙛; 뙛; 뙛; ) HANGUL SYLLABLE DDWAES +B65C;B65C;1104 116B 11BB;B65C;1104 116B 11BB; # (뙜; 뙜; 뙜; 뙜; 뙜; ) HANGUL SYLLABLE DDWAESS +B65D;B65D;1104 116B 11BC;B65D;1104 116B 11BC; # (뙝; 뙝; 뙝; 뙝; 뙝; ) HANGUL SYLLABLE DDWAENG +B65E;B65E;1104 116B 11BD;B65E;1104 116B 11BD; # (뙞; 뙞; 뙞; 뙞; 뙞; ) HANGUL SYLLABLE DDWAEJ +B65F;B65F;1104 116B 11BE;B65F;1104 116B 11BE; # (뙟; 뙟; 뙟; 뙟; 뙟; ) HANGUL SYLLABLE DDWAEC +B660;B660;1104 116B 11BF;B660;1104 116B 11BF; # (뙠; 뙠; 뙠; 뙠; 뙠; ) HANGUL SYLLABLE DDWAEK +B661;B661;1104 116B 11C0;B661;1104 116B 11C0; # (뙡; 뙡; 뙡; 뙡; 뙡; ) HANGUL SYLLABLE DDWAET +B662;B662;1104 116B 11C1;B662;1104 116B 11C1; # (뙢; 뙢; 뙢; 뙢; 뙢; ) HANGUL SYLLABLE DDWAEP +B663;B663;1104 116B 11C2;B663;1104 116B 11C2; # (뙣; 뙣; 뙣; 뙣; 뙣; ) HANGUL SYLLABLE DDWAEH +B664;B664;1104 116C;B664;1104 116C; # (뙤; 뙤; 뙤; 뙤; 뙤; ) HANGUL SYLLABLE DDOE +B665;B665;1104 116C 11A8;B665;1104 116C 11A8; # (뙥; 뙥; 뙥; 뙥; 뙥; ) HANGUL SYLLABLE DDOEG +B666;B666;1104 116C 11A9;B666;1104 116C 11A9; # (뙦; 뙦; 뙦; 뙦; 뙦; ) HANGUL SYLLABLE DDOEGG +B667;B667;1104 116C 11AA;B667;1104 116C 11AA; # (뙧; 뙧; 뙧; 뙧; 뙧; ) HANGUL SYLLABLE DDOEGS +B668;B668;1104 116C 11AB;B668;1104 116C 11AB; # (뙨; 뙨; 뙨; 뙨; 뙨; ) HANGUL SYLLABLE DDOEN +B669;B669;1104 116C 11AC;B669;1104 116C 11AC; # (뙩; 뙩; 뙩; 뙩; 뙩; ) HANGUL SYLLABLE DDOENJ +B66A;B66A;1104 116C 11AD;B66A;1104 116C 11AD; # (뙪; 뙪; 뙪; 뙪; 뙪; ) HANGUL SYLLABLE DDOENH +B66B;B66B;1104 116C 11AE;B66B;1104 116C 11AE; # (뙫; 뙫; 뙫; 뙫; 뙫; ) HANGUL SYLLABLE DDOED +B66C;B66C;1104 116C 11AF;B66C;1104 116C 11AF; # (뙬; 뙬; 뙬; 뙬; 뙬; ) HANGUL SYLLABLE DDOEL +B66D;B66D;1104 116C 11B0;B66D;1104 116C 11B0; # (뙭; 뙭; 뙭; 뙭; 뙭; ) HANGUL SYLLABLE DDOELG +B66E;B66E;1104 116C 11B1;B66E;1104 116C 11B1; # (뙮; 뙮; 뙮; 뙮; 뙮; ) HANGUL SYLLABLE DDOELM +B66F;B66F;1104 116C 11B2;B66F;1104 116C 11B2; # (뙯; 뙯; 뙯; 뙯; 뙯; ) HANGUL SYLLABLE DDOELB +B670;B670;1104 116C 11B3;B670;1104 116C 11B3; # (뙰; 뙰; 뙰; 뙰; 뙰; ) HANGUL SYLLABLE DDOELS +B671;B671;1104 116C 11B4;B671;1104 116C 11B4; # (뙱; 뙱; 뙱; 뙱; 뙱; ) HANGUL SYLLABLE DDOELT +B672;B672;1104 116C 11B5;B672;1104 116C 11B5; # (뙲; 뙲; 뙲; 뙲; 뙲; ) HANGUL SYLLABLE DDOELP +B673;B673;1104 116C 11B6;B673;1104 116C 11B6; # (뙳; 뙳; 뙳; 뙳; 뙳; ) HANGUL SYLLABLE DDOELH +B674;B674;1104 116C 11B7;B674;1104 116C 11B7; # (뙴; 뙴; 뙴; 뙴; 뙴; ) HANGUL SYLLABLE DDOEM +B675;B675;1104 116C 11B8;B675;1104 116C 11B8; # (뙵; 뙵; 뙵; 뙵; 뙵; ) HANGUL SYLLABLE DDOEB +B676;B676;1104 116C 11B9;B676;1104 116C 11B9; # (뙶; 뙶; 뙶; 뙶; 뙶; ) HANGUL SYLLABLE DDOEBS +B677;B677;1104 116C 11BA;B677;1104 116C 11BA; # (뙷; 뙷; 뙷; 뙷; 뙷; ) HANGUL SYLLABLE DDOES +B678;B678;1104 116C 11BB;B678;1104 116C 11BB; # (뙸; 뙸; 뙸; 뙸; 뙸; ) HANGUL SYLLABLE DDOESS +B679;B679;1104 116C 11BC;B679;1104 116C 11BC; # (뙹; 뙹; 뙹; 뙹; 뙹; ) HANGUL SYLLABLE DDOENG +B67A;B67A;1104 116C 11BD;B67A;1104 116C 11BD; # (뙺; 뙺; 뙺; 뙺; 뙺; ) HANGUL SYLLABLE DDOEJ +B67B;B67B;1104 116C 11BE;B67B;1104 116C 11BE; # (뙻; 뙻; 뙻; 뙻; 뙻; ) HANGUL SYLLABLE DDOEC +B67C;B67C;1104 116C 11BF;B67C;1104 116C 11BF; # (뙼; 뙼; 뙼; 뙼; 뙼; ) HANGUL SYLLABLE DDOEK +B67D;B67D;1104 116C 11C0;B67D;1104 116C 11C0; # (뙽; 뙽; 뙽; 뙽; 뙽; ) HANGUL SYLLABLE DDOET +B67E;B67E;1104 116C 11C1;B67E;1104 116C 11C1; # (뙾; 뙾; 뙾; 뙾; 뙾; ) HANGUL SYLLABLE DDOEP +B67F;B67F;1104 116C 11C2;B67F;1104 116C 11C2; # (뙿; 뙿; 뙿; 뙿; 뙿; ) HANGUL SYLLABLE DDOEH +B680;B680;1104 116D;B680;1104 116D; # (뚀; 뚀; 뚀; 뚀; 뚀; ) HANGUL SYLLABLE DDYO +B681;B681;1104 116D 11A8;B681;1104 116D 11A8; # (뚁; 뚁; 뚁; 뚁; 뚁; ) HANGUL SYLLABLE DDYOG +B682;B682;1104 116D 11A9;B682;1104 116D 11A9; # (뚂; 뚂; 뚂; 뚂; 뚂; ) HANGUL SYLLABLE DDYOGG +B683;B683;1104 116D 11AA;B683;1104 116D 11AA; # (뚃; 뚃; 뚃; 뚃; 뚃; ) HANGUL SYLLABLE DDYOGS +B684;B684;1104 116D 11AB;B684;1104 116D 11AB; # (뚄; 뚄; 뚄; 뚄; 뚄; ) HANGUL SYLLABLE DDYON +B685;B685;1104 116D 11AC;B685;1104 116D 11AC; # (뚅; 뚅; 뚅; 뚅; 뚅; ) HANGUL SYLLABLE DDYONJ +B686;B686;1104 116D 11AD;B686;1104 116D 11AD; # (뚆; 뚆; 뚆; 뚆; 뚆; ) HANGUL SYLLABLE DDYONH +B687;B687;1104 116D 11AE;B687;1104 116D 11AE; # (뚇; 뚇; 뚇; 뚇; 뚇; ) HANGUL SYLLABLE DDYOD +B688;B688;1104 116D 11AF;B688;1104 116D 11AF; # (뚈; 뚈; 뚈; 뚈; 뚈; ) HANGUL SYLLABLE DDYOL +B689;B689;1104 116D 11B0;B689;1104 116D 11B0; # (뚉; 뚉; 뚉; 뚉; 뚉; ) HANGUL SYLLABLE DDYOLG +B68A;B68A;1104 116D 11B1;B68A;1104 116D 11B1; # (뚊; 뚊; 뚊; 뚊; 뚊; ) HANGUL SYLLABLE DDYOLM +B68B;B68B;1104 116D 11B2;B68B;1104 116D 11B2; # (뚋; 뚋; 뚋; 뚋; 뚋; ) HANGUL SYLLABLE DDYOLB +B68C;B68C;1104 116D 11B3;B68C;1104 116D 11B3; # (뚌; 뚌; 뚌; 뚌; 뚌; ) HANGUL SYLLABLE DDYOLS +B68D;B68D;1104 116D 11B4;B68D;1104 116D 11B4; # (뚍; 뚍; 뚍; 뚍; 뚍; ) HANGUL SYLLABLE DDYOLT +B68E;B68E;1104 116D 11B5;B68E;1104 116D 11B5; # (뚎; 뚎; 뚎; 뚎; 뚎; ) HANGUL SYLLABLE DDYOLP +B68F;B68F;1104 116D 11B6;B68F;1104 116D 11B6; # (뚏; 뚏; 뚏; 뚏; 뚏; ) HANGUL SYLLABLE DDYOLH +B690;B690;1104 116D 11B7;B690;1104 116D 11B7; # (뚐; 뚐; 뚐; 뚐; 뚐; ) HANGUL SYLLABLE DDYOM +B691;B691;1104 116D 11B8;B691;1104 116D 11B8; # (뚑; 뚑; 뚑; 뚑; 뚑; ) HANGUL SYLLABLE DDYOB +B692;B692;1104 116D 11B9;B692;1104 116D 11B9; # (뚒; 뚒; 뚒; 뚒; 뚒; ) HANGUL SYLLABLE DDYOBS +B693;B693;1104 116D 11BA;B693;1104 116D 11BA; # (뚓; 뚓; 뚓; 뚓; 뚓; ) HANGUL SYLLABLE DDYOS +B694;B694;1104 116D 11BB;B694;1104 116D 11BB; # (뚔; 뚔; 뚔; 뚔; 뚔; ) HANGUL SYLLABLE DDYOSS +B695;B695;1104 116D 11BC;B695;1104 116D 11BC; # (뚕; 뚕; 뚕; 뚕; 뚕; ) HANGUL SYLLABLE DDYONG +B696;B696;1104 116D 11BD;B696;1104 116D 11BD; # (뚖; 뚖; 뚖; 뚖; 뚖; ) HANGUL SYLLABLE DDYOJ +B697;B697;1104 116D 11BE;B697;1104 116D 11BE; # (뚗; 뚗; 뚗; 뚗; 뚗; ) HANGUL SYLLABLE DDYOC +B698;B698;1104 116D 11BF;B698;1104 116D 11BF; # (뚘; 뚘; 뚘; 뚘; 뚘; ) HANGUL SYLLABLE DDYOK +B699;B699;1104 116D 11C0;B699;1104 116D 11C0; # (뚙; 뚙; 뚙; 뚙; 뚙; ) HANGUL SYLLABLE DDYOT +B69A;B69A;1104 116D 11C1;B69A;1104 116D 11C1; # (뚚; 뚚; 뚚; 뚚; 뚚; ) HANGUL SYLLABLE DDYOP +B69B;B69B;1104 116D 11C2;B69B;1104 116D 11C2; # (뚛; 뚛; 뚛; 뚛; 뚛; ) HANGUL SYLLABLE DDYOH +B69C;B69C;1104 116E;B69C;1104 116E; # (뚜; 뚜; 뚜; 뚜; 뚜; ) HANGUL SYLLABLE DDU +B69D;B69D;1104 116E 11A8;B69D;1104 116E 11A8; # (뚝; 뚝; 뚝; 뚝; 뚝; ) HANGUL SYLLABLE DDUG +B69E;B69E;1104 116E 11A9;B69E;1104 116E 11A9; # (뚞; 뚞; 뚞; 뚞; 뚞; ) HANGUL SYLLABLE DDUGG +B69F;B69F;1104 116E 11AA;B69F;1104 116E 11AA; # (뚟; 뚟; 뚟; 뚟; 뚟; ) HANGUL SYLLABLE DDUGS +B6A0;B6A0;1104 116E 11AB;B6A0;1104 116E 11AB; # (뚠; 뚠; 뚠; 뚠; 뚠; ) HANGUL SYLLABLE DDUN +B6A1;B6A1;1104 116E 11AC;B6A1;1104 116E 11AC; # (뚡; 뚡; 뚡; 뚡; 뚡; ) HANGUL SYLLABLE DDUNJ +B6A2;B6A2;1104 116E 11AD;B6A2;1104 116E 11AD; # (뚢; 뚢; 뚢; 뚢; 뚢; ) HANGUL SYLLABLE DDUNH +B6A3;B6A3;1104 116E 11AE;B6A3;1104 116E 11AE; # (뚣; 뚣; 뚣; 뚣; 뚣; ) HANGUL SYLLABLE DDUD +B6A4;B6A4;1104 116E 11AF;B6A4;1104 116E 11AF; # (뚤; 뚤; 뚤; 뚤; 뚤; ) HANGUL SYLLABLE DDUL +B6A5;B6A5;1104 116E 11B0;B6A5;1104 116E 11B0; # (뚥; 뚥; 뚥; 뚥; 뚥; ) HANGUL SYLLABLE DDULG +B6A6;B6A6;1104 116E 11B1;B6A6;1104 116E 11B1; # (뚦; 뚦; 뚦; 뚦; 뚦; ) HANGUL SYLLABLE DDULM +B6A7;B6A7;1104 116E 11B2;B6A7;1104 116E 11B2; # (뚧; 뚧; 뚧; 뚧; 뚧; ) HANGUL SYLLABLE DDULB +B6A8;B6A8;1104 116E 11B3;B6A8;1104 116E 11B3; # (뚨; 뚨; 뚨; 뚨; 뚨; ) HANGUL SYLLABLE DDULS +B6A9;B6A9;1104 116E 11B4;B6A9;1104 116E 11B4; # (뚩; 뚩; 뚩; 뚩; 뚩; ) HANGUL SYLLABLE DDULT +B6AA;B6AA;1104 116E 11B5;B6AA;1104 116E 11B5; # (뚪; 뚪; 뚪; 뚪; 뚪; ) HANGUL SYLLABLE DDULP +B6AB;B6AB;1104 116E 11B6;B6AB;1104 116E 11B6; # (뚫; 뚫; 뚫; 뚫; 뚫; ) HANGUL SYLLABLE DDULH +B6AC;B6AC;1104 116E 11B7;B6AC;1104 116E 11B7; # (뚬; 뚬; 뚬; 뚬; 뚬; ) HANGUL SYLLABLE DDUM +B6AD;B6AD;1104 116E 11B8;B6AD;1104 116E 11B8; # (뚭; 뚭; 뚭; 뚭; 뚭; ) HANGUL SYLLABLE DDUB +B6AE;B6AE;1104 116E 11B9;B6AE;1104 116E 11B9; # (뚮; 뚮; 뚮; 뚮; 뚮; ) HANGUL SYLLABLE DDUBS +B6AF;B6AF;1104 116E 11BA;B6AF;1104 116E 11BA; # (뚯; 뚯; 뚯; 뚯; 뚯; ) HANGUL SYLLABLE DDUS +B6B0;B6B0;1104 116E 11BB;B6B0;1104 116E 11BB; # (뚰; 뚰; 뚰; 뚰; 뚰; ) HANGUL SYLLABLE DDUSS +B6B1;B6B1;1104 116E 11BC;B6B1;1104 116E 11BC; # (뚱; 뚱; 뚱; 뚱; 뚱; ) HANGUL SYLLABLE DDUNG +B6B2;B6B2;1104 116E 11BD;B6B2;1104 116E 11BD; # (뚲; 뚲; 뚲; 뚲; 뚲; ) HANGUL SYLLABLE DDUJ +B6B3;B6B3;1104 116E 11BE;B6B3;1104 116E 11BE; # (뚳; 뚳; 뚳; 뚳; 뚳; ) HANGUL SYLLABLE DDUC +B6B4;B6B4;1104 116E 11BF;B6B4;1104 116E 11BF; # (뚴; 뚴; 뚴; 뚴; 뚴; ) HANGUL SYLLABLE DDUK +B6B5;B6B5;1104 116E 11C0;B6B5;1104 116E 11C0; # (뚵; 뚵; 뚵; 뚵; 뚵; ) HANGUL SYLLABLE DDUT +B6B6;B6B6;1104 116E 11C1;B6B6;1104 116E 11C1; # (뚶; 뚶; 뚶; 뚶; 뚶; ) HANGUL SYLLABLE DDUP +B6B7;B6B7;1104 116E 11C2;B6B7;1104 116E 11C2; # (뚷; 뚷; 뚷; 뚷; 뚷; ) HANGUL SYLLABLE DDUH +B6B8;B6B8;1104 116F;B6B8;1104 116F; # (뚸; 뚸; 뚸; 뚸; 뚸; ) HANGUL SYLLABLE DDWEO +B6B9;B6B9;1104 116F 11A8;B6B9;1104 116F 11A8; # (뚹; 뚹; 뚹; 뚹; 뚹; ) HANGUL SYLLABLE DDWEOG +B6BA;B6BA;1104 116F 11A9;B6BA;1104 116F 11A9; # (뚺; 뚺; 뚺; 뚺; 뚺; ) HANGUL SYLLABLE DDWEOGG +B6BB;B6BB;1104 116F 11AA;B6BB;1104 116F 11AA; # (뚻; 뚻; 뚻; 뚻; 뚻; ) HANGUL SYLLABLE DDWEOGS +B6BC;B6BC;1104 116F 11AB;B6BC;1104 116F 11AB; # (뚼; 뚼; 뚼; 뚼; 뚼; ) HANGUL SYLLABLE DDWEON +B6BD;B6BD;1104 116F 11AC;B6BD;1104 116F 11AC; # (뚽; 뚽; 뚽; 뚽; 뚽; ) HANGUL SYLLABLE DDWEONJ +B6BE;B6BE;1104 116F 11AD;B6BE;1104 116F 11AD; # (뚾; 뚾; 뚾; 뚾; 뚾; ) HANGUL SYLLABLE DDWEONH +B6BF;B6BF;1104 116F 11AE;B6BF;1104 116F 11AE; # (뚿; 뚿; 뚿; 뚿; 뚿; ) HANGUL SYLLABLE DDWEOD +B6C0;B6C0;1104 116F 11AF;B6C0;1104 116F 11AF; # (뛀; 뛀; 뛀; 뛀; 뛀; ) HANGUL SYLLABLE DDWEOL +B6C1;B6C1;1104 116F 11B0;B6C1;1104 116F 11B0; # (뛁; 뛁; 뛁; 뛁; 뛁; ) HANGUL SYLLABLE DDWEOLG +B6C2;B6C2;1104 116F 11B1;B6C2;1104 116F 11B1; # (뛂; 뛂; 뛂; 뛂; 뛂; ) HANGUL SYLLABLE DDWEOLM +B6C3;B6C3;1104 116F 11B2;B6C3;1104 116F 11B2; # (뛃; 뛃; 뛃; 뛃; 뛃; ) HANGUL SYLLABLE DDWEOLB +B6C4;B6C4;1104 116F 11B3;B6C4;1104 116F 11B3; # (뛄; 뛄; 뛄; 뛄; 뛄; ) HANGUL SYLLABLE DDWEOLS +B6C5;B6C5;1104 116F 11B4;B6C5;1104 116F 11B4; # (뛅; 뛅; 뛅; 뛅; 뛅; ) HANGUL SYLLABLE DDWEOLT +B6C6;B6C6;1104 116F 11B5;B6C6;1104 116F 11B5; # (뛆; 뛆; 뛆; 뛆; 뛆; ) HANGUL SYLLABLE DDWEOLP +B6C7;B6C7;1104 116F 11B6;B6C7;1104 116F 11B6; # (뛇; 뛇; 뛇; 뛇; 뛇; ) HANGUL SYLLABLE DDWEOLH +B6C8;B6C8;1104 116F 11B7;B6C8;1104 116F 11B7; # (뛈; 뛈; 뛈; 뛈; 뛈; ) HANGUL SYLLABLE DDWEOM +B6C9;B6C9;1104 116F 11B8;B6C9;1104 116F 11B8; # (뛉; 뛉; 뛉; 뛉; 뛉; ) HANGUL SYLLABLE DDWEOB +B6CA;B6CA;1104 116F 11B9;B6CA;1104 116F 11B9; # (뛊; 뛊; 뛊; 뛊; 뛊; ) HANGUL SYLLABLE DDWEOBS +B6CB;B6CB;1104 116F 11BA;B6CB;1104 116F 11BA; # (뛋; 뛋; 뛋; 뛋; 뛋; ) HANGUL SYLLABLE DDWEOS +B6CC;B6CC;1104 116F 11BB;B6CC;1104 116F 11BB; # (뛌; 뛌; 뛌; 뛌; 뛌; ) HANGUL SYLLABLE DDWEOSS +B6CD;B6CD;1104 116F 11BC;B6CD;1104 116F 11BC; # (뛍; 뛍; 뛍; 뛍; 뛍; ) HANGUL SYLLABLE DDWEONG +B6CE;B6CE;1104 116F 11BD;B6CE;1104 116F 11BD; # (뛎; 뛎; 뛎; 뛎; 뛎; ) HANGUL SYLLABLE DDWEOJ +B6CF;B6CF;1104 116F 11BE;B6CF;1104 116F 11BE; # (뛏; 뛏; 뛏; 뛏; 뛏; ) HANGUL SYLLABLE DDWEOC +B6D0;B6D0;1104 116F 11BF;B6D0;1104 116F 11BF; # (뛐; 뛐; 뛐; 뛐; 뛐; ) HANGUL SYLLABLE DDWEOK +B6D1;B6D1;1104 116F 11C0;B6D1;1104 116F 11C0; # (뛑; 뛑; 뛑; 뛑; 뛑; ) HANGUL SYLLABLE DDWEOT +B6D2;B6D2;1104 116F 11C1;B6D2;1104 116F 11C1; # (뛒; 뛒; 뛒; 뛒; 뛒; ) HANGUL SYLLABLE DDWEOP +B6D3;B6D3;1104 116F 11C2;B6D3;1104 116F 11C2; # (뛓; 뛓; 뛓; 뛓; 뛓; ) HANGUL SYLLABLE DDWEOH +B6D4;B6D4;1104 1170;B6D4;1104 1170; # (뛔; 뛔; 뛔; 뛔; 뛔; ) HANGUL SYLLABLE DDWE +B6D5;B6D5;1104 1170 11A8;B6D5;1104 1170 11A8; # (뛕; 뛕; 뛕; 뛕; 뛕; ) HANGUL SYLLABLE DDWEG +B6D6;B6D6;1104 1170 11A9;B6D6;1104 1170 11A9; # (뛖; 뛖; 뛖; 뛖; 뛖; ) HANGUL SYLLABLE DDWEGG +B6D7;B6D7;1104 1170 11AA;B6D7;1104 1170 11AA; # (뛗; 뛗; 뛗; 뛗; 뛗; ) HANGUL SYLLABLE DDWEGS +B6D8;B6D8;1104 1170 11AB;B6D8;1104 1170 11AB; # (뛘; 뛘; 뛘; 뛘; 뛘; ) HANGUL SYLLABLE DDWEN +B6D9;B6D9;1104 1170 11AC;B6D9;1104 1170 11AC; # (뛙; 뛙; 뛙; 뛙; 뛙; ) HANGUL SYLLABLE DDWENJ +B6DA;B6DA;1104 1170 11AD;B6DA;1104 1170 11AD; # (뛚; 뛚; 뛚; 뛚; 뛚; ) HANGUL SYLLABLE DDWENH +B6DB;B6DB;1104 1170 11AE;B6DB;1104 1170 11AE; # (뛛; 뛛; 뛛; 뛛; 뛛; ) HANGUL SYLLABLE DDWED +B6DC;B6DC;1104 1170 11AF;B6DC;1104 1170 11AF; # (뛜; 뛜; 뛜; 뛜; 뛜; ) HANGUL SYLLABLE DDWEL +B6DD;B6DD;1104 1170 11B0;B6DD;1104 1170 11B0; # (뛝; 뛝; 뛝; 뛝; 뛝; ) HANGUL SYLLABLE DDWELG +B6DE;B6DE;1104 1170 11B1;B6DE;1104 1170 11B1; # (뛞; 뛞; 뛞; 뛞; 뛞; ) HANGUL SYLLABLE DDWELM +B6DF;B6DF;1104 1170 11B2;B6DF;1104 1170 11B2; # (뛟; 뛟; 뛟; 뛟; 뛟; ) HANGUL SYLLABLE DDWELB +B6E0;B6E0;1104 1170 11B3;B6E0;1104 1170 11B3; # (뛠; 뛠; 뛠; 뛠; 뛠; ) HANGUL SYLLABLE DDWELS +B6E1;B6E1;1104 1170 11B4;B6E1;1104 1170 11B4; # (뛡; 뛡; 뛡; 뛡; 뛡; ) HANGUL SYLLABLE DDWELT +B6E2;B6E2;1104 1170 11B5;B6E2;1104 1170 11B5; # (뛢; 뛢; 뛢; 뛢; 뛢; ) HANGUL SYLLABLE DDWELP +B6E3;B6E3;1104 1170 11B6;B6E3;1104 1170 11B6; # (뛣; 뛣; 뛣; 뛣; 뛣; ) HANGUL SYLLABLE DDWELH +B6E4;B6E4;1104 1170 11B7;B6E4;1104 1170 11B7; # (뛤; 뛤; 뛤; 뛤; 뛤; ) HANGUL SYLLABLE DDWEM +B6E5;B6E5;1104 1170 11B8;B6E5;1104 1170 11B8; # (뛥; 뛥; 뛥; 뛥; 뛥; ) HANGUL SYLLABLE DDWEB +B6E6;B6E6;1104 1170 11B9;B6E6;1104 1170 11B9; # (뛦; 뛦; 뛦; 뛦; 뛦; ) HANGUL SYLLABLE DDWEBS +B6E7;B6E7;1104 1170 11BA;B6E7;1104 1170 11BA; # (뛧; 뛧; 뛧; 뛧; 뛧; ) HANGUL SYLLABLE DDWES +B6E8;B6E8;1104 1170 11BB;B6E8;1104 1170 11BB; # (뛨; 뛨; 뛨; 뛨; 뛨; ) HANGUL SYLLABLE DDWESS +B6E9;B6E9;1104 1170 11BC;B6E9;1104 1170 11BC; # (뛩; 뛩; 뛩; 뛩; 뛩; ) HANGUL SYLLABLE DDWENG +B6EA;B6EA;1104 1170 11BD;B6EA;1104 1170 11BD; # (뛪; 뛪; 뛪; 뛪; 뛪; ) HANGUL SYLLABLE DDWEJ +B6EB;B6EB;1104 1170 11BE;B6EB;1104 1170 11BE; # (뛫; 뛫; 뛫; 뛫; 뛫; ) HANGUL SYLLABLE DDWEC +B6EC;B6EC;1104 1170 11BF;B6EC;1104 1170 11BF; # (뛬; 뛬; 뛬; 뛬; 뛬; ) HANGUL SYLLABLE DDWEK +B6ED;B6ED;1104 1170 11C0;B6ED;1104 1170 11C0; # (뛭; 뛭; 뛭; 뛭; 뛭; ) HANGUL SYLLABLE DDWET +B6EE;B6EE;1104 1170 11C1;B6EE;1104 1170 11C1; # (뛮; 뛮; 뛮; 뛮; 뛮; ) HANGUL SYLLABLE DDWEP +B6EF;B6EF;1104 1170 11C2;B6EF;1104 1170 11C2; # (뛯; 뛯; 뛯; 뛯; 뛯; ) HANGUL SYLLABLE DDWEH +B6F0;B6F0;1104 1171;B6F0;1104 1171; # (뛰; 뛰; 뛰; 뛰; 뛰; ) HANGUL SYLLABLE DDWI +B6F1;B6F1;1104 1171 11A8;B6F1;1104 1171 11A8; # (뛱; 뛱; 뛱; 뛱; 뛱; ) HANGUL SYLLABLE DDWIG +B6F2;B6F2;1104 1171 11A9;B6F2;1104 1171 11A9; # (뛲; 뛲; 뛲; 뛲; 뛲; ) HANGUL SYLLABLE DDWIGG +B6F3;B6F3;1104 1171 11AA;B6F3;1104 1171 11AA; # (뛳; 뛳; 뛳; 뛳; 뛳; ) HANGUL SYLLABLE DDWIGS +B6F4;B6F4;1104 1171 11AB;B6F4;1104 1171 11AB; # (뛴; 뛴; 뛴; 뛴; 뛴; ) HANGUL SYLLABLE DDWIN +B6F5;B6F5;1104 1171 11AC;B6F5;1104 1171 11AC; # (뛵; 뛵; 뛵; 뛵; 뛵; ) HANGUL SYLLABLE DDWINJ +B6F6;B6F6;1104 1171 11AD;B6F6;1104 1171 11AD; # (뛶; 뛶; 뛶; 뛶; 뛶; ) HANGUL SYLLABLE DDWINH +B6F7;B6F7;1104 1171 11AE;B6F7;1104 1171 11AE; # (뛷; 뛷; 뛷; 뛷; 뛷; ) HANGUL SYLLABLE DDWID +B6F8;B6F8;1104 1171 11AF;B6F8;1104 1171 11AF; # (뛸; 뛸; 뛸; 뛸; 뛸; ) HANGUL SYLLABLE DDWIL +B6F9;B6F9;1104 1171 11B0;B6F9;1104 1171 11B0; # (뛹; 뛹; 뛹; 뛹; 뛹; ) HANGUL SYLLABLE DDWILG +B6FA;B6FA;1104 1171 11B1;B6FA;1104 1171 11B1; # (뛺; 뛺; 뛺; 뛺; 뛺; ) HANGUL SYLLABLE DDWILM +B6FB;B6FB;1104 1171 11B2;B6FB;1104 1171 11B2; # (뛻; 뛻; 뛻; 뛻; 뛻; ) HANGUL SYLLABLE DDWILB +B6FC;B6FC;1104 1171 11B3;B6FC;1104 1171 11B3; # (뛼; 뛼; 뛼; 뛼; 뛼; ) HANGUL SYLLABLE DDWILS +B6FD;B6FD;1104 1171 11B4;B6FD;1104 1171 11B4; # (뛽; 뛽; 뛽; 뛽; 뛽; ) HANGUL SYLLABLE DDWILT +B6FE;B6FE;1104 1171 11B5;B6FE;1104 1171 11B5; # (뛾; 뛾; 뛾; 뛾; 뛾; ) HANGUL SYLLABLE DDWILP +B6FF;B6FF;1104 1171 11B6;B6FF;1104 1171 11B6; # (뛿; 뛿; 뛿; 뛿; 뛿; ) HANGUL SYLLABLE DDWILH +B700;B700;1104 1171 11B7;B700;1104 1171 11B7; # (뜀; 뜀; 뜀; 뜀; 뜀; ) HANGUL SYLLABLE DDWIM +B701;B701;1104 1171 11B8;B701;1104 1171 11B8; # (뜁; 뜁; 뜁; 뜁; 뜁; ) HANGUL SYLLABLE DDWIB +B702;B702;1104 1171 11B9;B702;1104 1171 11B9; # (뜂; 뜂; 뜂; 뜂; 뜂; ) HANGUL SYLLABLE DDWIBS +B703;B703;1104 1171 11BA;B703;1104 1171 11BA; # (뜃; 뜃; 뜃; 뜃; 뜃; ) HANGUL SYLLABLE DDWIS +B704;B704;1104 1171 11BB;B704;1104 1171 11BB; # (뜄; 뜄; 뜄; 뜄; 뜄; ) HANGUL SYLLABLE DDWISS +B705;B705;1104 1171 11BC;B705;1104 1171 11BC; # (뜅; 뜅; 뜅; 뜅; 뜅; ) HANGUL SYLLABLE DDWING +B706;B706;1104 1171 11BD;B706;1104 1171 11BD; # (뜆; 뜆; 뜆; 뜆; 뜆; ) HANGUL SYLLABLE DDWIJ +B707;B707;1104 1171 11BE;B707;1104 1171 11BE; # (뜇; 뜇; 뜇; 뜇; 뜇; ) HANGUL SYLLABLE DDWIC +B708;B708;1104 1171 11BF;B708;1104 1171 11BF; # (뜈; 뜈; 뜈; 뜈; 뜈; ) HANGUL SYLLABLE DDWIK +B709;B709;1104 1171 11C0;B709;1104 1171 11C0; # (뜉; 뜉; 뜉; 뜉; 뜉; ) HANGUL SYLLABLE DDWIT +B70A;B70A;1104 1171 11C1;B70A;1104 1171 11C1; # (뜊; 뜊; 뜊; 뜊; 뜊; ) HANGUL SYLLABLE DDWIP +B70B;B70B;1104 1171 11C2;B70B;1104 1171 11C2; # (뜋; 뜋; 뜋; 뜋; 뜋; ) HANGUL SYLLABLE DDWIH +B70C;B70C;1104 1172;B70C;1104 1172; # (뜌; 뜌; 뜌; 뜌; 뜌; ) HANGUL SYLLABLE DDYU +B70D;B70D;1104 1172 11A8;B70D;1104 1172 11A8; # (뜍; 뜍; 뜍; 뜍; 뜍; ) HANGUL SYLLABLE DDYUG +B70E;B70E;1104 1172 11A9;B70E;1104 1172 11A9; # (뜎; 뜎; 뜎; 뜎; 뜎; ) HANGUL SYLLABLE DDYUGG +B70F;B70F;1104 1172 11AA;B70F;1104 1172 11AA; # (뜏; 뜏; 뜏; 뜏; 뜏; ) HANGUL SYLLABLE DDYUGS +B710;B710;1104 1172 11AB;B710;1104 1172 11AB; # (뜐; 뜐; 뜐; 뜐; 뜐; ) HANGUL SYLLABLE DDYUN +B711;B711;1104 1172 11AC;B711;1104 1172 11AC; # (뜑; 뜑; 뜑; 뜑; 뜑; ) HANGUL SYLLABLE DDYUNJ +B712;B712;1104 1172 11AD;B712;1104 1172 11AD; # (뜒; 뜒; 뜒; 뜒; 뜒; ) HANGUL SYLLABLE DDYUNH +B713;B713;1104 1172 11AE;B713;1104 1172 11AE; # (뜓; 뜓; 뜓; 뜓; 뜓; ) HANGUL SYLLABLE DDYUD +B714;B714;1104 1172 11AF;B714;1104 1172 11AF; # (뜔; 뜔; 뜔; 뜔; 뜔; ) HANGUL SYLLABLE DDYUL +B715;B715;1104 1172 11B0;B715;1104 1172 11B0; # (뜕; 뜕; 뜕; 뜕; 뜕; ) HANGUL SYLLABLE DDYULG +B716;B716;1104 1172 11B1;B716;1104 1172 11B1; # (뜖; 뜖; 뜖; 뜖; 뜖; ) HANGUL SYLLABLE DDYULM +B717;B717;1104 1172 11B2;B717;1104 1172 11B2; # (뜗; 뜗; 뜗; 뜗; 뜗; ) HANGUL SYLLABLE DDYULB +B718;B718;1104 1172 11B3;B718;1104 1172 11B3; # (뜘; 뜘; 뜘; 뜘; 뜘; ) HANGUL SYLLABLE DDYULS +B719;B719;1104 1172 11B4;B719;1104 1172 11B4; # (뜙; 뜙; 뜙; 뜙; 뜙; ) HANGUL SYLLABLE DDYULT +B71A;B71A;1104 1172 11B5;B71A;1104 1172 11B5; # (뜚; 뜚; 뜚; 뜚; 뜚; ) HANGUL SYLLABLE DDYULP +B71B;B71B;1104 1172 11B6;B71B;1104 1172 11B6; # (뜛; 뜛; 뜛; 뜛; 뜛; ) HANGUL SYLLABLE DDYULH +B71C;B71C;1104 1172 11B7;B71C;1104 1172 11B7; # (뜜; 뜜; 뜜; 뜜; 뜜; ) HANGUL SYLLABLE DDYUM +B71D;B71D;1104 1172 11B8;B71D;1104 1172 11B8; # (뜝; 뜝; 뜝; 뜝; 뜝; ) HANGUL SYLLABLE DDYUB +B71E;B71E;1104 1172 11B9;B71E;1104 1172 11B9; # (뜞; 뜞; 뜞; 뜞; 뜞; ) HANGUL SYLLABLE DDYUBS +B71F;B71F;1104 1172 11BA;B71F;1104 1172 11BA; # (뜟; 뜟; 뜟; 뜟; 뜟; ) HANGUL SYLLABLE DDYUS +B720;B720;1104 1172 11BB;B720;1104 1172 11BB; # (뜠; 뜠; 뜠; 뜠; 뜠; ) HANGUL SYLLABLE DDYUSS +B721;B721;1104 1172 11BC;B721;1104 1172 11BC; # (뜡; 뜡; 뜡; 뜡; 뜡; ) HANGUL SYLLABLE DDYUNG +B722;B722;1104 1172 11BD;B722;1104 1172 11BD; # (뜢; 뜢; 뜢; 뜢; 뜢; ) HANGUL SYLLABLE DDYUJ +B723;B723;1104 1172 11BE;B723;1104 1172 11BE; # (뜣; 뜣; 뜣; 뜣; 뜣; ) HANGUL SYLLABLE DDYUC +B724;B724;1104 1172 11BF;B724;1104 1172 11BF; # (뜤; 뜤; 뜤; 뜤; 뜤; ) HANGUL SYLLABLE DDYUK +B725;B725;1104 1172 11C0;B725;1104 1172 11C0; # (뜥; 뜥; 뜥; 뜥; 뜥; ) HANGUL SYLLABLE DDYUT +B726;B726;1104 1172 11C1;B726;1104 1172 11C1; # (뜦; 뜦; 뜦; 뜦; 뜦; ) HANGUL SYLLABLE DDYUP +B727;B727;1104 1172 11C2;B727;1104 1172 11C2; # (뜧; 뜧; 뜧; 뜧; 뜧; ) HANGUL SYLLABLE DDYUH +B728;B728;1104 1173;B728;1104 1173; # (뜨; 뜨; 뜨; 뜨; 뜨; ) HANGUL SYLLABLE DDEU +B729;B729;1104 1173 11A8;B729;1104 1173 11A8; # (뜩; 뜩; 뜩; 뜩; 뜩; ) HANGUL SYLLABLE DDEUG +B72A;B72A;1104 1173 11A9;B72A;1104 1173 11A9; # (뜪; 뜪; 뜪; 뜪; 뜪; ) HANGUL SYLLABLE DDEUGG +B72B;B72B;1104 1173 11AA;B72B;1104 1173 11AA; # (뜫; 뜫; 뜫; 뜫; 뜫; ) HANGUL SYLLABLE DDEUGS +B72C;B72C;1104 1173 11AB;B72C;1104 1173 11AB; # (뜬; 뜬; 뜬; 뜬; 뜬; ) HANGUL SYLLABLE DDEUN +B72D;B72D;1104 1173 11AC;B72D;1104 1173 11AC; # (뜭; 뜭; 뜭; 뜭; 뜭; ) HANGUL SYLLABLE DDEUNJ +B72E;B72E;1104 1173 11AD;B72E;1104 1173 11AD; # (뜮; 뜮; 뜮; 뜮; 뜮; ) HANGUL SYLLABLE DDEUNH +B72F;B72F;1104 1173 11AE;B72F;1104 1173 11AE; # (뜯; 뜯; 뜯; 뜯; 뜯; ) HANGUL SYLLABLE DDEUD +B730;B730;1104 1173 11AF;B730;1104 1173 11AF; # (뜰; 뜰; 뜰; 뜰; 뜰; ) HANGUL SYLLABLE DDEUL +B731;B731;1104 1173 11B0;B731;1104 1173 11B0; # (뜱; 뜱; 뜱; 뜱; 뜱; ) HANGUL SYLLABLE DDEULG +B732;B732;1104 1173 11B1;B732;1104 1173 11B1; # (뜲; 뜲; 뜲; 뜲; 뜲; ) HANGUL SYLLABLE DDEULM +B733;B733;1104 1173 11B2;B733;1104 1173 11B2; # (뜳; 뜳; 뜳; 뜳; 뜳; ) HANGUL SYLLABLE DDEULB +B734;B734;1104 1173 11B3;B734;1104 1173 11B3; # (뜴; 뜴; 뜴; 뜴; 뜴; ) HANGUL SYLLABLE DDEULS +B735;B735;1104 1173 11B4;B735;1104 1173 11B4; # (뜵; 뜵; 뜵; 뜵; 뜵; ) HANGUL SYLLABLE DDEULT +B736;B736;1104 1173 11B5;B736;1104 1173 11B5; # (뜶; 뜶; 뜶; 뜶; 뜶; ) HANGUL SYLLABLE DDEULP +B737;B737;1104 1173 11B6;B737;1104 1173 11B6; # (뜷; 뜷; 뜷; 뜷; 뜷; ) HANGUL SYLLABLE DDEULH +B738;B738;1104 1173 11B7;B738;1104 1173 11B7; # (뜸; 뜸; 뜸; 뜸; 뜸; ) HANGUL SYLLABLE DDEUM +B739;B739;1104 1173 11B8;B739;1104 1173 11B8; # (뜹; 뜹; 뜹; 뜹; 뜹; ) HANGUL SYLLABLE DDEUB +B73A;B73A;1104 1173 11B9;B73A;1104 1173 11B9; # (뜺; 뜺; 뜺; 뜺; 뜺; ) HANGUL SYLLABLE DDEUBS +B73B;B73B;1104 1173 11BA;B73B;1104 1173 11BA; # (뜻; 뜻; 뜻; 뜻; 뜻; ) HANGUL SYLLABLE DDEUS +B73C;B73C;1104 1173 11BB;B73C;1104 1173 11BB; # (뜼; 뜼; 뜼; 뜼; 뜼; ) HANGUL SYLLABLE DDEUSS +B73D;B73D;1104 1173 11BC;B73D;1104 1173 11BC; # (뜽; 뜽; 뜽; 뜽; 뜽; ) HANGUL SYLLABLE DDEUNG +B73E;B73E;1104 1173 11BD;B73E;1104 1173 11BD; # (뜾; 뜾; 뜾; 뜾; 뜾; ) HANGUL SYLLABLE DDEUJ +B73F;B73F;1104 1173 11BE;B73F;1104 1173 11BE; # (뜿; 뜿; 뜿; 뜿; 뜿; ) HANGUL SYLLABLE DDEUC +B740;B740;1104 1173 11BF;B740;1104 1173 11BF; # (띀; 띀; 띀; 띀; 띀; ) HANGUL SYLLABLE DDEUK +B741;B741;1104 1173 11C0;B741;1104 1173 11C0; # (띁; 띁; 띁; 띁; 띁; ) HANGUL SYLLABLE DDEUT +B742;B742;1104 1173 11C1;B742;1104 1173 11C1; # (띂; 띂; 띂; 띂; 띂; ) HANGUL SYLLABLE DDEUP +B743;B743;1104 1173 11C2;B743;1104 1173 11C2; # (띃; 띃; 띃; 띃; 띃; ) HANGUL SYLLABLE DDEUH +B744;B744;1104 1174;B744;1104 1174; # (띄; 띄; 띄; 띄; 띄; ) HANGUL SYLLABLE DDYI +B745;B745;1104 1174 11A8;B745;1104 1174 11A8; # (띅; 띅; 띅; 띅; 띅; ) HANGUL SYLLABLE DDYIG +B746;B746;1104 1174 11A9;B746;1104 1174 11A9; # (띆; 띆; 띆; 띆; 띆; ) HANGUL SYLLABLE DDYIGG +B747;B747;1104 1174 11AA;B747;1104 1174 11AA; # (띇; 띇; 띇; 띇; 띇; ) HANGUL SYLLABLE DDYIGS +B748;B748;1104 1174 11AB;B748;1104 1174 11AB; # (띈; 띈; 띈; 띈; 띈; ) HANGUL SYLLABLE DDYIN +B749;B749;1104 1174 11AC;B749;1104 1174 11AC; # (띉; 띉; 띉; 띉; 띉; ) HANGUL SYLLABLE DDYINJ +B74A;B74A;1104 1174 11AD;B74A;1104 1174 11AD; # (띊; 띊; 띊; 띊; 띊; ) HANGUL SYLLABLE DDYINH +B74B;B74B;1104 1174 11AE;B74B;1104 1174 11AE; # (띋; 띋; 띋; 띋; 띋; ) HANGUL SYLLABLE DDYID +B74C;B74C;1104 1174 11AF;B74C;1104 1174 11AF; # (띌; 띌; 띌; 띌; 띌; ) HANGUL SYLLABLE DDYIL +B74D;B74D;1104 1174 11B0;B74D;1104 1174 11B0; # (띍; 띍; 띍; 띍; 띍; ) HANGUL SYLLABLE DDYILG +B74E;B74E;1104 1174 11B1;B74E;1104 1174 11B1; # (띎; 띎; 띎; 띎; 띎; ) HANGUL SYLLABLE DDYILM +B74F;B74F;1104 1174 11B2;B74F;1104 1174 11B2; # (띏; 띏; 띏; 띏; 띏; ) HANGUL SYLLABLE DDYILB +B750;B750;1104 1174 11B3;B750;1104 1174 11B3; # (띐; 띐; 띐; 띐; 띐; ) HANGUL SYLLABLE DDYILS +B751;B751;1104 1174 11B4;B751;1104 1174 11B4; # (띑; 띑; 띑; 띑; 띑; ) HANGUL SYLLABLE DDYILT +B752;B752;1104 1174 11B5;B752;1104 1174 11B5; # (띒; 띒; 띒; 띒; 띒; ) HANGUL SYLLABLE DDYILP +B753;B753;1104 1174 11B6;B753;1104 1174 11B6; # (띓; 띓; 띓; 띓; 띓; ) HANGUL SYLLABLE DDYILH +B754;B754;1104 1174 11B7;B754;1104 1174 11B7; # (띔; 띔; 띔; 띔; 띔; ) HANGUL SYLLABLE DDYIM +B755;B755;1104 1174 11B8;B755;1104 1174 11B8; # (띕; 띕; 띕; 띕; 띕; ) HANGUL SYLLABLE DDYIB +B756;B756;1104 1174 11B9;B756;1104 1174 11B9; # (띖; 띖; 띖; 띖; 띖; ) HANGUL SYLLABLE DDYIBS +B757;B757;1104 1174 11BA;B757;1104 1174 11BA; # (띗; 띗; 띗; 띗; 띗; ) HANGUL SYLLABLE DDYIS +B758;B758;1104 1174 11BB;B758;1104 1174 11BB; # (띘; 띘; 띘; 띘; 띘; ) HANGUL SYLLABLE DDYISS +B759;B759;1104 1174 11BC;B759;1104 1174 11BC; # (띙; 띙; 띙; 띙; 띙; ) HANGUL SYLLABLE DDYING +B75A;B75A;1104 1174 11BD;B75A;1104 1174 11BD; # (띚; 띚; 띚; 띚; 띚; ) HANGUL SYLLABLE DDYIJ +B75B;B75B;1104 1174 11BE;B75B;1104 1174 11BE; # (띛; 띛; 띛; 띛; 띛; ) HANGUL SYLLABLE DDYIC +B75C;B75C;1104 1174 11BF;B75C;1104 1174 11BF; # (띜; 띜; 띜; 띜; 띜; ) HANGUL SYLLABLE DDYIK +B75D;B75D;1104 1174 11C0;B75D;1104 1174 11C0; # (띝; 띝; 띝; 띝; 띝; ) HANGUL SYLLABLE DDYIT +B75E;B75E;1104 1174 11C1;B75E;1104 1174 11C1; # (띞; 띞; 띞; 띞; 띞; ) HANGUL SYLLABLE DDYIP +B75F;B75F;1104 1174 11C2;B75F;1104 1174 11C2; # (띟; 띟; 띟; 띟; 띟; ) HANGUL SYLLABLE DDYIH +B760;B760;1104 1175;B760;1104 1175; # (띠; 띠; 띠; 띠; 띠; ) HANGUL SYLLABLE DDI +B761;B761;1104 1175 11A8;B761;1104 1175 11A8; # (띡; 띡; 띡; 띡; 띡; ) HANGUL SYLLABLE DDIG +B762;B762;1104 1175 11A9;B762;1104 1175 11A9; # (띢; 띢; 띢; 띢; 띢; ) HANGUL SYLLABLE DDIGG +B763;B763;1104 1175 11AA;B763;1104 1175 11AA; # (띣; 띣; 띣; 띣; 띣; ) HANGUL SYLLABLE DDIGS +B764;B764;1104 1175 11AB;B764;1104 1175 11AB; # (띤; 띤; 띤; 띤; 띤; ) HANGUL SYLLABLE DDIN +B765;B765;1104 1175 11AC;B765;1104 1175 11AC; # (띥; 띥; 띥; 띥; 띥; ) HANGUL SYLLABLE DDINJ +B766;B766;1104 1175 11AD;B766;1104 1175 11AD; # (띦; 띦; 띦; 띦; 띦; ) HANGUL SYLLABLE DDINH +B767;B767;1104 1175 11AE;B767;1104 1175 11AE; # (띧; 띧; 띧; 띧; 띧; ) HANGUL SYLLABLE DDID +B768;B768;1104 1175 11AF;B768;1104 1175 11AF; # (띨; 띨; 띨; 띨; 띨; ) HANGUL SYLLABLE DDIL +B769;B769;1104 1175 11B0;B769;1104 1175 11B0; # (띩; 띩; 띩; 띩; 띩; ) HANGUL SYLLABLE DDILG +B76A;B76A;1104 1175 11B1;B76A;1104 1175 11B1; # (띪; 띪; 띪; 띪; 띪; ) HANGUL SYLLABLE DDILM +B76B;B76B;1104 1175 11B2;B76B;1104 1175 11B2; # (띫; 띫; 띫; 띫; 띫; ) HANGUL SYLLABLE DDILB +B76C;B76C;1104 1175 11B3;B76C;1104 1175 11B3; # (띬; 띬; 띬; 띬; 띬; ) HANGUL SYLLABLE DDILS +B76D;B76D;1104 1175 11B4;B76D;1104 1175 11B4; # (띭; 띭; 띭; 띭; 띭; ) HANGUL SYLLABLE DDILT +B76E;B76E;1104 1175 11B5;B76E;1104 1175 11B5; # (띮; 띮; 띮; 띮; 띮; ) HANGUL SYLLABLE DDILP +B76F;B76F;1104 1175 11B6;B76F;1104 1175 11B6; # (띯; 띯; 띯; 띯; 띯; ) HANGUL SYLLABLE DDILH +B770;B770;1104 1175 11B7;B770;1104 1175 11B7; # (띰; 띰; 띰; 띰; 띰; ) HANGUL SYLLABLE DDIM +B771;B771;1104 1175 11B8;B771;1104 1175 11B8; # (띱; 띱; 띱; 띱; 띱; ) HANGUL SYLLABLE DDIB +B772;B772;1104 1175 11B9;B772;1104 1175 11B9; # (띲; 띲; 띲; 띲; 띲; ) HANGUL SYLLABLE DDIBS +B773;B773;1104 1175 11BA;B773;1104 1175 11BA; # (띳; 띳; 띳; 띳; 띳; ) HANGUL SYLLABLE DDIS +B774;B774;1104 1175 11BB;B774;1104 1175 11BB; # (띴; 띴; 띴; 띴; 띴; ) HANGUL SYLLABLE DDISS +B775;B775;1104 1175 11BC;B775;1104 1175 11BC; # (띵; 띵; 띵; 띵; 띵; ) HANGUL SYLLABLE DDING +B776;B776;1104 1175 11BD;B776;1104 1175 11BD; # (띶; 띶; 띶; 띶; 띶; ) HANGUL SYLLABLE DDIJ +B777;B777;1104 1175 11BE;B777;1104 1175 11BE; # (띷; 띷; 띷; 띷; 띷; ) HANGUL SYLLABLE DDIC +B778;B778;1104 1175 11BF;B778;1104 1175 11BF; # (띸; 띸; 띸; 띸; 띸; ) HANGUL SYLLABLE DDIK +B779;B779;1104 1175 11C0;B779;1104 1175 11C0; # (띹; 띹; 띹; 띹; 띹; ) HANGUL SYLLABLE DDIT +B77A;B77A;1104 1175 11C1;B77A;1104 1175 11C1; # (띺; 띺; 띺; 띺; 띺; ) HANGUL SYLLABLE DDIP +B77B;B77B;1104 1175 11C2;B77B;1104 1175 11C2; # (띻; 띻; 띻; 띻; 띻; ) HANGUL SYLLABLE DDIH +B77C;B77C;1105 1161;B77C;1105 1161; # (라; 라; 라; 라; 라; ) HANGUL SYLLABLE RA +B77D;B77D;1105 1161 11A8;B77D;1105 1161 11A8; # (락; 락; 락; 락; 락; ) HANGUL SYLLABLE RAG +B77E;B77E;1105 1161 11A9;B77E;1105 1161 11A9; # (띾; 띾; 띾; 띾; 띾; ) HANGUL SYLLABLE RAGG +B77F;B77F;1105 1161 11AA;B77F;1105 1161 11AA; # (띿; 띿; 띿; 띿; 띿; ) HANGUL SYLLABLE RAGS +B780;B780;1105 1161 11AB;B780;1105 1161 11AB; # (란; 란; 란; 란; 란; ) HANGUL SYLLABLE RAN +B781;B781;1105 1161 11AC;B781;1105 1161 11AC; # (랁; 랁; 랁; 랁; 랁; ) HANGUL SYLLABLE RANJ +B782;B782;1105 1161 11AD;B782;1105 1161 11AD; # (랂; 랂; 랂; 랂; 랂; ) HANGUL SYLLABLE RANH +B783;B783;1105 1161 11AE;B783;1105 1161 11AE; # (랃; 랃; 랃; 랃; 랃; ) HANGUL SYLLABLE RAD +B784;B784;1105 1161 11AF;B784;1105 1161 11AF; # (랄; 랄; 랄; 랄; 랄; ) HANGUL SYLLABLE RAL +B785;B785;1105 1161 11B0;B785;1105 1161 11B0; # (랅; 랅; 랅; 랅; 랅; ) HANGUL SYLLABLE RALG +B786;B786;1105 1161 11B1;B786;1105 1161 11B1; # (랆; 랆; 랆; 랆; 랆; ) HANGUL SYLLABLE RALM +B787;B787;1105 1161 11B2;B787;1105 1161 11B2; # (랇; 랇; 랇; 랇; 랇; ) HANGUL SYLLABLE RALB +B788;B788;1105 1161 11B3;B788;1105 1161 11B3; # (랈; 랈; 랈; 랈; 랈; ) HANGUL SYLLABLE RALS +B789;B789;1105 1161 11B4;B789;1105 1161 11B4; # (랉; 랉; 랉; 랉; 랉; ) HANGUL SYLLABLE RALT +B78A;B78A;1105 1161 11B5;B78A;1105 1161 11B5; # (랊; 랊; 랊; 랊; 랊; ) HANGUL SYLLABLE RALP +B78B;B78B;1105 1161 11B6;B78B;1105 1161 11B6; # (랋; 랋; 랋; 랋; 랋; ) HANGUL SYLLABLE RALH +B78C;B78C;1105 1161 11B7;B78C;1105 1161 11B7; # (람; 람; 람; 람; 람; ) HANGUL SYLLABLE RAM +B78D;B78D;1105 1161 11B8;B78D;1105 1161 11B8; # (랍; 랍; 랍; 랍; 랍; ) HANGUL SYLLABLE RAB +B78E;B78E;1105 1161 11B9;B78E;1105 1161 11B9; # (랎; 랎; 랎; 랎; 랎; ) HANGUL SYLLABLE RABS +B78F;B78F;1105 1161 11BA;B78F;1105 1161 11BA; # (랏; 랏; 랏; 랏; 랏; ) HANGUL SYLLABLE RAS +B790;B790;1105 1161 11BB;B790;1105 1161 11BB; # (랐; 랐; 랐; 랐; 랐; ) HANGUL SYLLABLE RASS +B791;B791;1105 1161 11BC;B791;1105 1161 11BC; # (랑; 랑; 랑; 랑; 랑; ) HANGUL SYLLABLE RANG +B792;B792;1105 1161 11BD;B792;1105 1161 11BD; # (랒; 랒; 랒; 랒; 랒; ) HANGUL SYLLABLE RAJ +B793;B793;1105 1161 11BE;B793;1105 1161 11BE; # (랓; 랓; 랓; 랓; 랓; ) HANGUL SYLLABLE RAC +B794;B794;1105 1161 11BF;B794;1105 1161 11BF; # (랔; 랔; 랔; 랔; 랔; ) HANGUL SYLLABLE RAK +B795;B795;1105 1161 11C0;B795;1105 1161 11C0; # (랕; 랕; 랕; 랕; 랕; ) HANGUL SYLLABLE RAT +B796;B796;1105 1161 11C1;B796;1105 1161 11C1; # (랖; 랖; 랖; 랖; 랖; ) HANGUL SYLLABLE RAP +B797;B797;1105 1161 11C2;B797;1105 1161 11C2; # (랗; 랗; 랗; 랗; 랗; ) HANGUL SYLLABLE RAH +B798;B798;1105 1162;B798;1105 1162; # (래; 래; 래; 래; 래; ) HANGUL SYLLABLE RAE +B799;B799;1105 1162 11A8;B799;1105 1162 11A8; # (랙; 랙; 랙; 랙; 랙; ) HANGUL SYLLABLE RAEG +B79A;B79A;1105 1162 11A9;B79A;1105 1162 11A9; # (랚; 랚; 랚; 랚; 랚; ) HANGUL SYLLABLE RAEGG +B79B;B79B;1105 1162 11AA;B79B;1105 1162 11AA; # (랛; 랛; 랛; 랛; 랛; ) HANGUL SYLLABLE RAEGS +B79C;B79C;1105 1162 11AB;B79C;1105 1162 11AB; # (랜; 랜; 랜; 랜; 랜; ) HANGUL SYLLABLE RAEN +B79D;B79D;1105 1162 11AC;B79D;1105 1162 11AC; # (랝; 랝; 랝; 랝; 랝; ) HANGUL SYLLABLE RAENJ +B79E;B79E;1105 1162 11AD;B79E;1105 1162 11AD; # (랞; 랞; 랞; 랞; 랞; ) HANGUL SYLLABLE RAENH +B79F;B79F;1105 1162 11AE;B79F;1105 1162 11AE; # (랟; 랟; 랟; 랟; 랟; ) HANGUL SYLLABLE RAED +B7A0;B7A0;1105 1162 11AF;B7A0;1105 1162 11AF; # (랠; 랠; 랠; 랠; 랠; ) HANGUL SYLLABLE RAEL +B7A1;B7A1;1105 1162 11B0;B7A1;1105 1162 11B0; # (랡; 랡; 랡; 랡; 랡; ) HANGUL SYLLABLE RAELG +B7A2;B7A2;1105 1162 11B1;B7A2;1105 1162 11B1; # (랢; 랢; 랢; 랢; 랢; ) HANGUL SYLLABLE RAELM +B7A3;B7A3;1105 1162 11B2;B7A3;1105 1162 11B2; # (랣; 랣; 랣; 랣; 랣; ) HANGUL SYLLABLE RAELB +B7A4;B7A4;1105 1162 11B3;B7A4;1105 1162 11B3; # (랤; 랤; 랤; 랤; 랤; ) HANGUL SYLLABLE RAELS +B7A5;B7A5;1105 1162 11B4;B7A5;1105 1162 11B4; # (랥; 랥; 랥; 랥; 랥; ) HANGUL SYLLABLE RAELT +B7A6;B7A6;1105 1162 11B5;B7A6;1105 1162 11B5; # (랦; 랦; 랦; 랦; 랦; ) HANGUL SYLLABLE RAELP +B7A7;B7A7;1105 1162 11B6;B7A7;1105 1162 11B6; # (랧; 랧; 랧; 랧; 랧; ) HANGUL SYLLABLE RAELH +B7A8;B7A8;1105 1162 11B7;B7A8;1105 1162 11B7; # (램; 램; 램; 램; 램; ) HANGUL SYLLABLE RAEM +B7A9;B7A9;1105 1162 11B8;B7A9;1105 1162 11B8; # (랩; 랩; 랩; 랩; 랩; ) HANGUL SYLLABLE RAEB +B7AA;B7AA;1105 1162 11B9;B7AA;1105 1162 11B9; # (랪; 랪; 랪; 랪; 랪; ) HANGUL SYLLABLE RAEBS +B7AB;B7AB;1105 1162 11BA;B7AB;1105 1162 11BA; # (랫; 랫; 랫; 랫; 랫; ) HANGUL SYLLABLE RAES +B7AC;B7AC;1105 1162 11BB;B7AC;1105 1162 11BB; # (랬; 랬; 랬; 랬; 랬; ) HANGUL SYLLABLE RAESS +B7AD;B7AD;1105 1162 11BC;B7AD;1105 1162 11BC; # (랭; 랭; 랭; 랭; 랭; ) HANGUL SYLLABLE RAENG +B7AE;B7AE;1105 1162 11BD;B7AE;1105 1162 11BD; # (랮; 랮; 랮; 랮; 랮; ) HANGUL SYLLABLE RAEJ +B7AF;B7AF;1105 1162 11BE;B7AF;1105 1162 11BE; # (랯; 랯; 랯; 랯; 랯; ) HANGUL SYLLABLE RAEC +B7B0;B7B0;1105 1162 11BF;B7B0;1105 1162 11BF; # (랰; 랰; 랰; 랰; 랰; ) HANGUL SYLLABLE RAEK +B7B1;B7B1;1105 1162 11C0;B7B1;1105 1162 11C0; # (랱; 랱; 랱; 랱; 랱; ) HANGUL SYLLABLE RAET +B7B2;B7B2;1105 1162 11C1;B7B2;1105 1162 11C1; # (랲; 랲; 랲; 랲; 랲; ) HANGUL SYLLABLE RAEP +B7B3;B7B3;1105 1162 11C2;B7B3;1105 1162 11C2; # (랳; 랳; 랳; 랳; 랳; ) HANGUL SYLLABLE RAEH +B7B4;B7B4;1105 1163;B7B4;1105 1163; # (랴; 랴; 랴; 랴; 랴; ) HANGUL SYLLABLE RYA +B7B5;B7B5;1105 1163 11A8;B7B5;1105 1163 11A8; # (략; 략; 략; 략; 략; ) HANGUL SYLLABLE RYAG +B7B6;B7B6;1105 1163 11A9;B7B6;1105 1163 11A9; # (랶; 랶; 랶; 랶; 랶; ) HANGUL SYLLABLE RYAGG +B7B7;B7B7;1105 1163 11AA;B7B7;1105 1163 11AA; # (랷; 랷; 랷; 랷; 랷; ) HANGUL SYLLABLE RYAGS +B7B8;B7B8;1105 1163 11AB;B7B8;1105 1163 11AB; # (랸; 랸; 랸; 랸; 랸; ) HANGUL SYLLABLE RYAN +B7B9;B7B9;1105 1163 11AC;B7B9;1105 1163 11AC; # (랹; 랹; 랹; 랹; 랹; ) HANGUL SYLLABLE RYANJ +B7BA;B7BA;1105 1163 11AD;B7BA;1105 1163 11AD; # (랺; 랺; 랺; 랺; 랺; ) HANGUL SYLLABLE RYANH +B7BB;B7BB;1105 1163 11AE;B7BB;1105 1163 11AE; # (랻; 랻; 랻; 랻; 랻; ) HANGUL SYLLABLE RYAD +B7BC;B7BC;1105 1163 11AF;B7BC;1105 1163 11AF; # (랼; 랼; 랼; 랼; 랼; ) HANGUL SYLLABLE RYAL +B7BD;B7BD;1105 1163 11B0;B7BD;1105 1163 11B0; # (랽; 랽; 랽; 랽; 랽; ) HANGUL SYLLABLE RYALG +B7BE;B7BE;1105 1163 11B1;B7BE;1105 1163 11B1; # (랾; 랾; 랾; 랾; 랾; ) HANGUL SYLLABLE RYALM +B7BF;B7BF;1105 1163 11B2;B7BF;1105 1163 11B2; # (랿; 랿; 랿; 랿; 랿; ) HANGUL SYLLABLE RYALB +B7C0;B7C0;1105 1163 11B3;B7C0;1105 1163 11B3; # (럀; 럀; 럀; 럀; 럀; ) HANGUL SYLLABLE RYALS +B7C1;B7C1;1105 1163 11B4;B7C1;1105 1163 11B4; # (럁; 럁; 럁; 럁; 럁; ) HANGUL SYLLABLE RYALT +B7C2;B7C2;1105 1163 11B5;B7C2;1105 1163 11B5; # (럂; 럂; 럂; 럂; 럂; ) HANGUL SYLLABLE RYALP +B7C3;B7C3;1105 1163 11B6;B7C3;1105 1163 11B6; # (럃; 럃; 럃; 럃; 럃; ) HANGUL SYLLABLE RYALH +B7C4;B7C4;1105 1163 11B7;B7C4;1105 1163 11B7; # (럄; 럄; 럄; 럄; 럄; ) HANGUL SYLLABLE RYAM +B7C5;B7C5;1105 1163 11B8;B7C5;1105 1163 11B8; # (럅; 럅; 럅; 럅; 럅; ) HANGUL SYLLABLE RYAB +B7C6;B7C6;1105 1163 11B9;B7C6;1105 1163 11B9; # (럆; 럆; 럆; 럆; 럆; ) HANGUL SYLLABLE RYABS +B7C7;B7C7;1105 1163 11BA;B7C7;1105 1163 11BA; # (럇; 럇; 럇; 럇; 럇; ) HANGUL SYLLABLE RYAS +B7C8;B7C8;1105 1163 11BB;B7C8;1105 1163 11BB; # (럈; 럈; 럈; 럈; 럈; ) HANGUL SYLLABLE RYASS +B7C9;B7C9;1105 1163 11BC;B7C9;1105 1163 11BC; # (량; 량; 량; 량; 량; ) HANGUL SYLLABLE RYANG +B7CA;B7CA;1105 1163 11BD;B7CA;1105 1163 11BD; # (럊; 럊; 럊; 럊; 럊; ) HANGUL SYLLABLE RYAJ +B7CB;B7CB;1105 1163 11BE;B7CB;1105 1163 11BE; # (럋; 럋; 럋; 럋; 럋; ) HANGUL SYLLABLE RYAC +B7CC;B7CC;1105 1163 11BF;B7CC;1105 1163 11BF; # (럌; 럌; 럌; 럌; 럌; ) HANGUL SYLLABLE RYAK +B7CD;B7CD;1105 1163 11C0;B7CD;1105 1163 11C0; # (럍; 럍; 럍; 럍; 럍; ) HANGUL SYLLABLE RYAT +B7CE;B7CE;1105 1163 11C1;B7CE;1105 1163 11C1; # (럎; 럎; 럎; 럎; 럎; ) HANGUL SYLLABLE RYAP +B7CF;B7CF;1105 1163 11C2;B7CF;1105 1163 11C2; # (럏; 럏; 럏; 럏; 럏; ) HANGUL SYLLABLE RYAH +B7D0;B7D0;1105 1164;B7D0;1105 1164; # (럐; 럐; 럐; 럐; 럐; ) HANGUL SYLLABLE RYAE +B7D1;B7D1;1105 1164 11A8;B7D1;1105 1164 11A8; # (럑; 럑; 럑; 럑; 럑; ) HANGUL SYLLABLE RYAEG +B7D2;B7D2;1105 1164 11A9;B7D2;1105 1164 11A9; # (럒; 럒; 럒; 럒; 럒; ) HANGUL SYLLABLE RYAEGG +B7D3;B7D3;1105 1164 11AA;B7D3;1105 1164 11AA; # (럓; 럓; 럓; 럓; 럓; ) HANGUL SYLLABLE RYAEGS +B7D4;B7D4;1105 1164 11AB;B7D4;1105 1164 11AB; # (럔; 럔; 럔; 럔; 럔; ) HANGUL SYLLABLE RYAEN +B7D5;B7D5;1105 1164 11AC;B7D5;1105 1164 11AC; # (럕; 럕; 럕; 럕; 럕; ) HANGUL SYLLABLE RYAENJ +B7D6;B7D6;1105 1164 11AD;B7D6;1105 1164 11AD; # (럖; 럖; 럖; 럖; 럖; ) HANGUL SYLLABLE RYAENH +B7D7;B7D7;1105 1164 11AE;B7D7;1105 1164 11AE; # (럗; 럗; 럗; 럗; 럗; ) HANGUL SYLLABLE RYAED +B7D8;B7D8;1105 1164 11AF;B7D8;1105 1164 11AF; # (럘; 럘; 럘; 럘; 럘; ) HANGUL SYLLABLE RYAEL +B7D9;B7D9;1105 1164 11B0;B7D9;1105 1164 11B0; # (럙; 럙; 럙; 럙; 럙; ) HANGUL SYLLABLE RYAELG +B7DA;B7DA;1105 1164 11B1;B7DA;1105 1164 11B1; # (럚; 럚; 럚; 럚; 럚; ) HANGUL SYLLABLE RYAELM +B7DB;B7DB;1105 1164 11B2;B7DB;1105 1164 11B2; # (럛; 럛; 럛; 럛; 럛; ) HANGUL SYLLABLE RYAELB +B7DC;B7DC;1105 1164 11B3;B7DC;1105 1164 11B3; # (럜; 럜; 럜; 럜; 럜; ) HANGUL SYLLABLE RYAELS +B7DD;B7DD;1105 1164 11B4;B7DD;1105 1164 11B4; # (럝; 럝; 럝; 럝; 럝; ) HANGUL SYLLABLE RYAELT +B7DE;B7DE;1105 1164 11B5;B7DE;1105 1164 11B5; # (럞; 럞; 럞; 럞; 럞; ) HANGUL SYLLABLE RYAELP +B7DF;B7DF;1105 1164 11B6;B7DF;1105 1164 11B6; # (럟; 럟; 럟; 럟; 럟; ) HANGUL SYLLABLE RYAELH +B7E0;B7E0;1105 1164 11B7;B7E0;1105 1164 11B7; # (럠; 럠; 럠; 럠; 럠; ) HANGUL SYLLABLE RYAEM +B7E1;B7E1;1105 1164 11B8;B7E1;1105 1164 11B8; # (럡; 럡; 럡; 럡; 럡; ) HANGUL SYLLABLE RYAEB +B7E2;B7E2;1105 1164 11B9;B7E2;1105 1164 11B9; # (럢; 럢; 럢; 럢; 럢; ) HANGUL SYLLABLE RYAEBS +B7E3;B7E3;1105 1164 11BA;B7E3;1105 1164 11BA; # (럣; 럣; 럣; 럣; 럣; ) HANGUL SYLLABLE RYAES +B7E4;B7E4;1105 1164 11BB;B7E4;1105 1164 11BB; # (럤; 럤; 럤; 럤; 럤; ) HANGUL SYLLABLE RYAESS +B7E5;B7E5;1105 1164 11BC;B7E5;1105 1164 11BC; # (럥; 럥; 럥; 럥; 럥; ) HANGUL SYLLABLE RYAENG +B7E6;B7E6;1105 1164 11BD;B7E6;1105 1164 11BD; # (럦; 럦; 럦; 럦; 럦; ) HANGUL SYLLABLE RYAEJ +B7E7;B7E7;1105 1164 11BE;B7E7;1105 1164 11BE; # (럧; 럧; 럧; 럧; 럧; ) HANGUL SYLLABLE RYAEC +B7E8;B7E8;1105 1164 11BF;B7E8;1105 1164 11BF; # (럨; 럨; 럨; 럨; 럨; ) HANGUL SYLLABLE RYAEK +B7E9;B7E9;1105 1164 11C0;B7E9;1105 1164 11C0; # (럩; 럩; 럩; 럩; 럩; ) HANGUL SYLLABLE RYAET +B7EA;B7EA;1105 1164 11C1;B7EA;1105 1164 11C1; # (럪; 럪; 럪; 럪; 럪; ) HANGUL SYLLABLE RYAEP +B7EB;B7EB;1105 1164 11C2;B7EB;1105 1164 11C2; # (럫; 럫; 럫; 럫; 럫; ) HANGUL SYLLABLE RYAEH +B7EC;B7EC;1105 1165;B7EC;1105 1165; # (러; 러; 러; 러; 러; ) HANGUL SYLLABLE REO +B7ED;B7ED;1105 1165 11A8;B7ED;1105 1165 11A8; # (럭; 럭; 럭; 럭; 럭; ) HANGUL SYLLABLE REOG +B7EE;B7EE;1105 1165 11A9;B7EE;1105 1165 11A9; # (럮; 럮; 럮; 럮; 럮; ) HANGUL SYLLABLE REOGG +B7EF;B7EF;1105 1165 11AA;B7EF;1105 1165 11AA; # (럯; 럯; 럯; 럯; 럯; ) HANGUL SYLLABLE REOGS +B7F0;B7F0;1105 1165 11AB;B7F0;1105 1165 11AB; # (런; 런; 런; 런; 런; ) HANGUL SYLLABLE REON +B7F1;B7F1;1105 1165 11AC;B7F1;1105 1165 11AC; # (럱; 럱; 럱; 럱; 럱; ) HANGUL SYLLABLE REONJ +B7F2;B7F2;1105 1165 11AD;B7F2;1105 1165 11AD; # (럲; 럲; 럲; 럲; 럲; ) HANGUL SYLLABLE REONH +B7F3;B7F3;1105 1165 11AE;B7F3;1105 1165 11AE; # (럳; 럳; 럳; 럳; 럳; ) HANGUL SYLLABLE REOD +B7F4;B7F4;1105 1165 11AF;B7F4;1105 1165 11AF; # (럴; 럴; 럴; 럴; 럴; ) HANGUL SYLLABLE REOL +B7F5;B7F5;1105 1165 11B0;B7F5;1105 1165 11B0; # (럵; 럵; 럵; 럵; 럵; ) HANGUL SYLLABLE REOLG +B7F6;B7F6;1105 1165 11B1;B7F6;1105 1165 11B1; # (럶; 럶; 럶; 럶; 럶; ) HANGUL SYLLABLE REOLM +B7F7;B7F7;1105 1165 11B2;B7F7;1105 1165 11B2; # (럷; 럷; 럷; 럷; 럷; ) HANGUL SYLLABLE REOLB +B7F8;B7F8;1105 1165 11B3;B7F8;1105 1165 11B3; # (럸; 럸; 럸; 럸; 럸; ) HANGUL SYLLABLE REOLS +B7F9;B7F9;1105 1165 11B4;B7F9;1105 1165 11B4; # (럹; 럹; 럹; 럹; 럹; ) HANGUL SYLLABLE REOLT +B7FA;B7FA;1105 1165 11B5;B7FA;1105 1165 11B5; # (럺; 럺; 럺; 럺; 럺; ) HANGUL SYLLABLE REOLP +B7FB;B7FB;1105 1165 11B6;B7FB;1105 1165 11B6; # (럻; 럻; 럻; 럻; 럻; ) HANGUL SYLLABLE REOLH +B7FC;B7FC;1105 1165 11B7;B7FC;1105 1165 11B7; # (럼; 럼; 럼; 럼; 럼; ) HANGUL SYLLABLE REOM +B7FD;B7FD;1105 1165 11B8;B7FD;1105 1165 11B8; # (럽; 럽; 럽; 럽; 럽; ) HANGUL SYLLABLE REOB +B7FE;B7FE;1105 1165 11B9;B7FE;1105 1165 11B9; # (럾; 럾; 럾; 럾; 럾; ) HANGUL SYLLABLE REOBS +B7FF;B7FF;1105 1165 11BA;B7FF;1105 1165 11BA; # (럿; 럿; 럿; 럿; 럿; ) HANGUL SYLLABLE REOS +B800;B800;1105 1165 11BB;B800;1105 1165 11BB; # (렀; 렀; 렀; 렀; 렀; ) HANGUL SYLLABLE REOSS +B801;B801;1105 1165 11BC;B801;1105 1165 11BC; # (렁; 렁; 렁; 렁; 렁; ) HANGUL SYLLABLE REONG +B802;B802;1105 1165 11BD;B802;1105 1165 11BD; # (렂; 렂; 렂; 렂; 렂; ) HANGUL SYLLABLE REOJ +B803;B803;1105 1165 11BE;B803;1105 1165 11BE; # (렃; 렃; 렃; 렃; 렃; ) HANGUL SYLLABLE REOC +B804;B804;1105 1165 11BF;B804;1105 1165 11BF; # (렄; 렄; 렄; 렄; 렄; ) HANGUL SYLLABLE REOK +B805;B805;1105 1165 11C0;B805;1105 1165 11C0; # (렅; 렅; 렅; 렅; 렅; ) HANGUL SYLLABLE REOT +B806;B806;1105 1165 11C1;B806;1105 1165 11C1; # (렆; 렆; 렆; 렆; 렆; ) HANGUL SYLLABLE REOP +B807;B807;1105 1165 11C2;B807;1105 1165 11C2; # (렇; 렇; 렇; 렇; 렇; ) HANGUL SYLLABLE REOH +B808;B808;1105 1166;B808;1105 1166; # (레; 레; 레; 레; 레; ) HANGUL SYLLABLE RE +B809;B809;1105 1166 11A8;B809;1105 1166 11A8; # (렉; 렉; 렉; 렉; 렉; ) HANGUL SYLLABLE REG +B80A;B80A;1105 1166 11A9;B80A;1105 1166 11A9; # (렊; 렊; 렊; 렊; 렊; ) HANGUL SYLLABLE REGG +B80B;B80B;1105 1166 11AA;B80B;1105 1166 11AA; # (렋; 렋; 렋; 렋; 렋; ) HANGUL SYLLABLE REGS +B80C;B80C;1105 1166 11AB;B80C;1105 1166 11AB; # (렌; 렌; 렌; 렌; 렌; ) HANGUL SYLLABLE REN +B80D;B80D;1105 1166 11AC;B80D;1105 1166 11AC; # (렍; 렍; 렍; 렍; 렍; ) HANGUL SYLLABLE RENJ +B80E;B80E;1105 1166 11AD;B80E;1105 1166 11AD; # (렎; 렎; 렎; 렎; 렎; ) HANGUL SYLLABLE RENH +B80F;B80F;1105 1166 11AE;B80F;1105 1166 11AE; # (렏; 렏; 렏; 렏; 렏; ) HANGUL SYLLABLE RED +B810;B810;1105 1166 11AF;B810;1105 1166 11AF; # (렐; 렐; 렐; 렐; 렐; ) HANGUL SYLLABLE REL +B811;B811;1105 1166 11B0;B811;1105 1166 11B0; # (렑; 렑; 렑; 렑; 렑; ) HANGUL SYLLABLE RELG +B812;B812;1105 1166 11B1;B812;1105 1166 11B1; # (렒; 렒; 렒; 렒; 렒; ) HANGUL SYLLABLE RELM +B813;B813;1105 1166 11B2;B813;1105 1166 11B2; # (렓; 렓; 렓; 렓; 렓; ) HANGUL SYLLABLE RELB +B814;B814;1105 1166 11B3;B814;1105 1166 11B3; # (렔; 렔; 렔; 렔; 렔; ) HANGUL SYLLABLE RELS +B815;B815;1105 1166 11B4;B815;1105 1166 11B4; # (렕; 렕; 렕; 렕; 렕; ) HANGUL SYLLABLE RELT +B816;B816;1105 1166 11B5;B816;1105 1166 11B5; # (렖; 렖; 렖; 렖; 렖; ) HANGUL SYLLABLE RELP +B817;B817;1105 1166 11B6;B817;1105 1166 11B6; # (렗; 렗; 렗; 렗; 렗; ) HANGUL SYLLABLE RELH +B818;B818;1105 1166 11B7;B818;1105 1166 11B7; # (렘; 렘; 렘; 렘; 렘; ) HANGUL SYLLABLE REM +B819;B819;1105 1166 11B8;B819;1105 1166 11B8; # (렙; 렙; 렙; 렙; 렙; ) HANGUL SYLLABLE REB +B81A;B81A;1105 1166 11B9;B81A;1105 1166 11B9; # (렚; 렚; 렚; 렚; 렚; ) HANGUL SYLLABLE REBS +B81B;B81B;1105 1166 11BA;B81B;1105 1166 11BA; # (렛; 렛; 렛; 렛; 렛; ) HANGUL SYLLABLE RES +B81C;B81C;1105 1166 11BB;B81C;1105 1166 11BB; # (렜; 렜; 렜; 렜; 렜; ) HANGUL SYLLABLE RESS +B81D;B81D;1105 1166 11BC;B81D;1105 1166 11BC; # (렝; 렝; 렝; 렝; 렝; ) HANGUL SYLLABLE RENG +B81E;B81E;1105 1166 11BD;B81E;1105 1166 11BD; # (렞; 렞; 렞; 렞; 렞; ) HANGUL SYLLABLE REJ +B81F;B81F;1105 1166 11BE;B81F;1105 1166 11BE; # (렟; 렟; 렟; 렟; 렟; ) HANGUL SYLLABLE REC +B820;B820;1105 1166 11BF;B820;1105 1166 11BF; # (렠; 렠; 렠; 렠; 렠; ) HANGUL SYLLABLE REK +B821;B821;1105 1166 11C0;B821;1105 1166 11C0; # (렡; 렡; 렡; 렡; 렡; ) HANGUL SYLLABLE RET +B822;B822;1105 1166 11C1;B822;1105 1166 11C1; # (렢; 렢; 렢; 렢; 렢; ) HANGUL SYLLABLE REP +B823;B823;1105 1166 11C2;B823;1105 1166 11C2; # (렣; 렣; 렣; 렣; 렣; ) HANGUL SYLLABLE REH +B824;B824;1105 1167;B824;1105 1167; # (려; 려; 려; 려; 려; ) HANGUL SYLLABLE RYEO +B825;B825;1105 1167 11A8;B825;1105 1167 11A8; # (력; 력; 력; 력; 력; ) HANGUL SYLLABLE RYEOG +B826;B826;1105 1167 11A9;B826;1105 1167 11A9; # (렦; 렦; 렦; 렦; 렦; ) HANGUL SYLLABLE RYEOGG +B827;B827;1105 1167 11AA;B827;1105 1167 11AA; # (렧; 렧; 렧; 렧; 렧; ) HANGUL SYLLABLE RYEOGS +B828;B828;1105 1167 11AB;B828;1105 1167 11AB; # (련; 련; 련; 련; 련; ) HANGUL SYLLABLE RYEON +B829;B829;1105 1167 11AC;B829;1105 1167 11AC; # (렩; 렩; 렩; 렩; 렩; ) HANGUL SYLLABLE RYEONJ +B82A;B82A;1105 1167 11AD;B82A;1105 1167 11AD; # (렪; 렪; 렪; 렪; 렪; ) HANGUL SYLLABLE RYEONH +B82B;B82B;1105 1167 11AE;B82B;1105 1167 11AE; # (렫; 렫; 렫; 렫; 렫; ) HANGUL SYLLABLE RYEOD +B82C;B82C;1105 1167 11AF;B82C;1105 1167 11AF; # (렬; 렬; 렬; 렬; 렬; ) HANGUL SYLLABLE RYEOL +B82D;B82D;1105 1167 11B0;B82D;1105 1167 11B0; # (렭; 렭; 렭; 렭; 렭; ) HANGUL SYLLABLE RYEOLG +B82E;B82E;1105 1167 11B1;B82E;1105 1167 11B1; # (렮; 렮; 렮; 렮; 렮; ) HANGUL SYLLABLE RYEOLM +B82F;B82F;1105 1167 11B2;B82F;1105 1167 11B2; # (렯; 렯; 렯; 렯; 렯; ) HANGUL SYLLABLE RYEOLB +B830;B830;1105 1167 11B3;B830;1105 1167 11B3; # (렰; 렰; 렰; 렰; 렰; ) HANGUL SYLLABLE RYEOLS +B831;B831;1105 1167 11B4;B831;1105 1167 11B4; # (렱; 렱; 렱; 렱; 렱; ) HANGUL SYLLABLE RYEOLT +B832;B832;1105 1167 11B5;B832;1105 1167 11B5; # (렲; 렲; 렲; 렲; 렲; ) HANGUL SYLLABLE RYEOLP +B833;B833;1105 1167 11B6;B833;1105 1167 11B6; # (렳; 렳; 렳; 렳; 렳; ) HANGUL SYLLABLE RYEOLH +B834;B834;1105 1167 11B7;B834;1105 1167 11B7; # (렴; 렴; 렴; 렴; 렴; ) HANGUL SYLLABLE RYEOM +B835;B835;1105 1167 11B8;B835;1105 1167 11B8; # (렵; 렵; 렵; 렵; 렵; ) HANGUL SYLLABLE RYEOB +B836;B836;1105 1167 11B9;B836;1105 1167 11B9; # (렶; 렶; 렶; 렶; 렶; ) HANGUL SYLLABLE RYEOBS +B837;B837;1105 1167 11BA;B837;1105 1167 11BA; # (렷; 렷; 렷; 렷; 렷; ) HANGUL SYLLABLE RYEOS +B838;B838;1105 1167 11BB;B838;1105 1167 11BB; # (렸; 렸; 렸; 렸; 렸; ) HANGUL SYLLABLE RYEOSS +B839;B839;1105 1167 11BC;B839;1105 1167 11BC; # (령; 령; 령; 령; 령; ) HANGUL SYLLABLE RYEONG +B83A;B83A;1105 1167 11BD;B83A;1105 1167 11BD; # (렺; 렺; 렺; 렺; 렺; ) HANGUL SYLLABLE RYEOJ +B83B;B83B;1105 1167 11BE;B83B;1105 1167 11BE; # (렻; 렻; 렻; 렻; 렻; ) HANGUL SYLLABLE RYEOC +B83C;B83C;1105 1167 11BF;B83C;1105 1167 11BF; # (렼; 렼; 렼; 렼; 렼; ) HANGUL SYLLABLE RYEOK +B83D;B83D;1105 1167 11C0;B83D;1105 1167 11C0; # (렽; 렽; 렽; 렽; 렽; ) HANGUL SYLLABLE RYEOT +B83E;B83E;1105 1167 11C1;B83E;1105 1167 11C1; # (렾; 렾; 렾; 렾; 렾; ) HANGUL SYLLABLE RYEOP +B83F;B83F;1105 1167 11C2;B83F;1105 1167 11C2; # (렿; 렿; 렿; 렿; 렿; ) HANGUL SYLLABLE RYEOH +B840;B840;1105 1168;B840;1105 1168; # (례; 례; 례; 례; 례; ) HANGUL SYLLABLE RYE +B841;B841;1105 1168 11A8;B841;1105 1168 11A8; # (롁; 롁; 롁; 롁; 롁; ) HANGUL SYLLABLE RYEG +B842;B842;1105 1168 11A9;B842;1105 1168 11A9; # (롂; 롂; 롂; 롂; 롂; ) HANGUL SYLLABLE RYEGG +B843;B843;1105 1168 11AA;B843;1105 1168 11AA; # (롃; 롃; 롃; 롃; 롃; ) HANGUL SYLLABLE RYEGS +B844;B844;1105 1168 11AB;B844;1105 1168 11AB; # (롄; 롄; 롄; 롄; 롄; ) HANGUL SYLLABLE RYEN +B845;B845;1105 1168 11AC;B845;1105 1168 11AC; # (롅; 롅; 롅; 롅; 롅; ) HANGUL SYLLABLE RYENJ +B846;B846;1105 1168 11AD;B846;1105 1168 11AD; # (롆; 롆; 롆; 롆; 롆; ) HANGUL SYLLABLE RYENH +B847;B847;1105 1168 11AE;B847;1105 1168 11AE; # (롇; 롇; 롇; 롇; 롇; ) HANGUL SYLLABLE RYED +B848;B848;1105 1168 11AF;B848;1105 1168 11AF; # (롈; 롈; 롈; 롈; 롈; ) HANGUL SYLLABLE RYEL +B849;B849;1105 1168 11B0;B849;1105 1168 11B0; # (롉; 롉; 롉; 롉; 롉; ) HANGUL SYLLABLE RYELG +B84A;B84A;1105 1168 11B1;B84A;1105 1168 11B1; # (롊; 롊; 롊; 롊; 롊; ) HANGUL SYLLABLE RYELM +B84B;B84B;1105 1168 11B2;B84B;1105 1168 11B2; # (롋; 롋; 롋; 롋; 롋; ) HANGUL SYLLABLE RYELB +B84C;B84C;1105 1168 11B3;B84C;1105 1168 11B3; # (롌; 롌; 롌; 롌; 롌; ) HANGUL SYLLABLE RYELS +B84D;B84D;1105 1168 11B4;B84D;1105 1168 11B4; # (롍; 롍; 롍; 롍; 롍; ) HANGUL SYLLABLE RYELT +B84E;B84E;1105 1168 11B5;B84E;1105 1168 11B5; # (롎; 롎; 롎; 롎; 롎; ) HANGUL SYLLABLE RYELP +B84F;B84F;1105 1168 11B6;B84F;1105 1168 11B6; # (롏; 롏; 롏; 롏; 롏; ) HANGUL SYLLABLE RYELH +B850;B850;1105 1168 11B7;B850;1105 1168 11B7; # (롐; 롐; 롐; 롐; 롐; ) HANGUL SYLLABLE RYEM +B851;B851;1105 1168 11B8;B851;1105 1168 11B8; # (롑; 롑; 롑; 롑; 롑; ) HANGUL SYLLABLE RYEB +B852;B852;1105 1168 11B9;B852;1105 1168 11B9; # (롒; 롒; 롒; 롒; 롒; ) HANGUL SYLLABLE RYEBS +B853;B853;1105 1168 11BA;B853;1105 1168 11BA; # (롓; 롓; 롓; 롓; 롓; ) HANGUL SYLLABLE RYES +B854;B854;1105 1168 11BB;B854;1105 1168 11BB; # (롔; 롔; 롔; 롔; 롔; ) HANGUL SYLLABLE RYESS +B855;B855;1105 1168 11BC;B855;1105 1168 11BC; # (롕; 롕; 롕; 롕; 롕; ) HANGUL SYLLABLE RYENG +B856;B856;1105 1168 11BD;B856;1105 1168 11BD; # (롖; 롖; 롖; 롖; 롖; ) HANGUL SYLLABLE RYEJ +B857;B857;1105 1168 11BE;B857;1105 1168 11BE; # (롗; 롗; 롗; 롗; 롗; ) HANGUL SYLLABLE RYEC +B858;B858;1105 1168 11BF;B858;1105 1168 11BF; # (롘; 롘; 롘; 롘; 롘; ) HANGUL SYLLABLE RYEK +B859;B859;1105 1168 11C0;B859;1105 1168 11C0; # (롙; 롙; 롙; 롙; 롙; ) HANGUL SYLLABLE RYET +B85A;B85A;1105 1168 11C1;B85A;1105 1168 11C1; # (롚; 롚; 롚; 롚; 롚; ) HANGUL SYLLABLE RYEP +B85B;B85B;1105 1168 11C2;B85B;1105 1168 11C2; # (롛; 롛; 롛; 롛; 롛; ) HANGUL SYLLABLE RYEH +B85C;B85C;1105 1169;B85C;1105 1169; # (로; 로; 로; 로; 로; ) HANGUL SYLLABLE RO +B85D;B85D;1105 1169 11A8;B85D;1105 1169 11A8; # (록; 록; 록; 록; 록; ) HANGUL SYLLABLE ROG +B85E;B85E;1105 1169 11A9;B85E;1105 1169 11A9; # (롞; 롞; 롞; 롞; 롞; ) HANGUL SYLLABLE ROGG +B85F;B85F;1105 1169 11AA;B85F;1105 1169 11AA; # (롟; 롟; 롟; 롟; 롟; ) HANGUL SYLLABLE ROGS +B860;B860;1105 1169 11AB;B860;1105 1169 11AB; # (론; 론; 론; 론; 론; ) HANGUL SYLLABLE RON +B861;B861;1105 1169 11AC;B861;1105 1169 11AC; # (롡; 롡; 롡; 롡; 롡; ) HANGUL SYLLABLE RONJ +B862;B862;1105 1169 11AD;B862;1105 1169 11AD; # (롢; 롢; 롢; 롢; 롢; ) HANGUL SYLLABLE RONH +B863;B863;1105 1169 11AE;B863;1105 1169 11AE; # (롣; 롣; 롣; 롣; 롣; ) HANGUL SYLLABLE ROD +B864;B864;1105 1169 11AF;B864;1105 1169 11AF; # (롤; 롤; 롤; 롤; 롤; ) HANGUL SYLLABLE ROL +B865;B865;1105 1169 11B0;B865;1105 1169 11B0; # (롥; 롥; 롥; 롥; 롥; ) HANGUL SYLLABLE ROLG +B866;B866;1105 1169 11B1;B866;1105 1169 11B1; # (롦; 롦; 롦; 롦; 롦; ) HANGUL SYLLABLE ROLM +B867;B867;1105 1169 11B2;B867;1105 1169 11B2; # (롧; 롧; 롧; 롧; 롧; ) HANGUL SYLLABLE ROLB +B868;B868;1105 1169 11B3;B868;1105 1169 11B3; # (롨; 롨; 롨; 롨; 롨; ) HANGUL SYLLABLE ROLS +B869;B869;1105 1169 11B4;B869;1105 1169 11B4; # (롩; 롩; 롩; 롩; 롩; ) HANGUL SYLLABLE ROLT +B86A;B86A;1105 1169 11B5;B86A;1105 1169 11B5; # (롪; 롪; 롪; 롪; 롪; ) HANGUL SYLLABLE ROLP +B86B;B86B;1105 1169 11B6;B86B;1105 1169 11B6; # (롫; 롫; 롫; 롫; 롫; ) HANGUL SYLLABLE ROLH +B86C;B86C;1105 1169 11B7;B86C;1105 1169 11B7; # (롬; 롬; 롬; 롬; 롬; ) HANGUL SYLLABLE ROM +B86D;B86D;1105 1169 11B8;B86D;1105 1169 11B8; # (롭; 롭; 롭; 롭; 롭; ) HANGUL SYLLABLE ROB +B86E;B86E;1105 1169 11B9;B86E;1105 1169 11B9; # (롮; 롮; 롮; 롮; 롮; ) HANGUL SYLLABLE ROBS +B86F;B86F;1105 1169 11BA;B86F;1105 1169 11BA; # (롯; 롯; 롯; 롯; 롯; ) HANGUL SYLLABLE ROS +B870;B870;1105 1169 11BB;B870;1105 1169 11BB; # (롰; 롰; 롰; 롰; 롰; ) HANGUL SYLLABLE ROSS +B871;B871;1105 1169 11BC;B871;1105 1169 11BC; # (롱; 롱; 롱; 롱; 롱; ) HANGUL SYLLABLE RONG +B872;B872;1105 1169 11BD;B872;1105 1169 11BD; # (롲; 롲; 롲; 롲; 롲; ) HANGUL SYLLABLE ROJ +B873;B873;1105 1169 11BE;B873;1105 1169 11BE; # (롳; 롳; 롳; 롳; 롳; ) HANGUL SYLLABLE ROC +B874;B874;1105 1169 11BF;B874;1105 1169 11BF; # (롴; 롴; 롴; 롴; 롴; ) HANGUL SYLLABLE ROK +B875;B875;1105 1169 11C0;B875;1105 1169 11C0; # (롵; 롵; 롵; 롵; 롵; ) HANGUL SYLLABLE ROT +B876;B876;1105 1169 11C1;B876;1105 1169 11C1; # (롶; 롶; 롶; 롶; 롶; ) HANGUL SYLLABLE ROP +B877;B877;1105 1169 11C2;B877;1105 1169 11C2; # (롷; 롷; 롷; 롷; 롷; ) HANGUL SYLLABLE ROH +B878;B878;1105 116A;B878;1105 116A; # (롸; 롸; 롸; 롸; 롸; ) HANGUL SYLLABLE RWA +B879;B879;1105 116A 11A8;B879;1105 116A 11A8; # (롹; 롹; 롹; 롹; 롹; ) HANGUL SYLLABLE RWAG +B87A;B87A;1105 116A 11A9;B87A;1105 116A 11A9; # (롺; 롺; 롺; 롺; 롺; ) HANGUL SYLLABLE RWAGG +B87B;B87B;1105 116A 11AA;B87B;1105 116A 11AA; # (롻; 롻; 롻; 롻; 롻; ) HANGUL SYLLABLE RWAGS +B87C;B87C;1105 116A 11AB;B87C;1105 116A 11AB; # (롼; 롼; 롼; 롼; 롼; ) HANGUL SYLLABLE RWAN +B87D;B87D;1105 116A 11AC;B87D;1105 116A 11AC; # (롽; 롽; 롽; 롽; 롽; ) HANGUL SYLLABLE RWANJ +B87E;B87E;1105 116A 11AD;B87E;1105 116A 11AD; # (롾; 롾; 롾; 롾; 롾; ) HANGUL SYLLABLE RWANH +B87F;B87F;1105 116A 11AE;B87F;1105 116A 11AE; # (롿; 롿; 롿; 롿; 롿; ) HANGUL SYLLABLE RWAD +B880;B880;1105 116A 11AF;B880;1105 116A 11AF; # (뢀; 뢀; 뢀; 뢀; 뢀; ) HANGUL SYLLABLE RWAL +B881;B881;1105 116A 11B0;B881;1105 116A 11B0; # (뢁; 뢁; 뢁; 뢁; 뢁; ) HANGUL SYLLABLE RWALG +B882;B882;1105 116A 11B1;B882;1105 116A 11B1; # (뢂; 뢂; 뢂; 뢂; 뢂; ) HANGUL SYLLABLE RWALM +B883;B883;1105 116A 11B2;B883;1105 116A 11B2; # (뢃; 뢃; 뢃; 뢃; 뢃; ) HANGUL SYLLABLE RWALB +B884;B884;1105 116A 11B3;B884;1105 116A 11B3; # (뢄; 뢄; 뢄; 뢄; 뢄; ) HANGUL SYLLABLE RWALS +B885;B885;1105 116A 11B4;B885;1105 116A 11B4; # (뢅; 뢅; 뢅; 뢅; 뢅; ) HANGUL SYLLABLE RWALT +B886;B886;1105 116A 11B5;B886;1105 116A 11B5; # (뢆; 뢆; 뢆; 뢆; 뢆; ) HANGUL SYLLABLE RWALP +B887;B887;1105 116A 11B6;B887;1105 116A 11B6; # (뢇; 뢇; 뢇; 뢇; 뢇; ) HANGUL SYLLABLE RWALH +B888;B888;1105 116A 11B7;B888;1105 116A 11B7; # (뢈; 뢈; 뢈; 뢈; 뢈; ) HANGUL SYLLABLE RWAM +B889;B889;1105 116A 11B8;B889;1105 116A 11B8; # (뢉; 뢉; 뢉; 뢉; 뢉; ) HANGUL SYLLABLE RWAB +B88A;B88A;1105 116A 11B9;B88A;1105 116A 11B9; # (뢊; 뢊; 뢊; 뢊; 뢊; ) HANGUL SYLLABLE RWABS +B88B;B88B;1105 116A 11BA;B88B;1105 116A 11BA; # (뢋; 뢋; 뢋; 뢋; 뢋; ) HANGUL SYLLABLE RWAS +B88C;B88C;1105 116A 11BB;B88C;1105 116A 11BB; # (뢌; 뢌; 뢌; 뢌; 뢌; ) HANGUL SYLLABLE RWASS +B88D;B88D;1105 116A 11BC;B88D;1105 116A 11BC; # (뢍; 뢍; 뢍; 뢍; 뢍; ) HANGUL SYLLABLE RWANG +B88E;B88E;1105 116A 11BD;B88E;1105 116A 11BD; # (뢎; 뢎; 뢎; 뢎; 뢎; ) HANGUL SYLLABLE RWAJ +B88F;B88F;1105 116A 11BE;B88F;1105 116A 11BE; # (뢏; 뢏; 뢏; 뢏; 뢏; ) HANGUL SYLLABLE RWAC +B890;B890;1105 116A 11BF;B890;1105 116A 11BF; # (뢐; 뢐; 뢐; 뢐; 뢐; ) HANGUL SYLLABLE RWAK +B891;B891;1105 116A 11C0;B891;1105 116A 11C0; # (뢑; 뢑; 뢑; 뢑; 뢑; ) HANGUL SYLLABLE RWAT +B892;B892;1105 116A 11C1;B892;1105 116A 11C1; # (뢒; 뢒; 뢒; 뢒; 뢒; ) HANGUL SYLLABLE RWAP +B893;B893;1105 116A 11C2;B893;1105 116A 11C2; # (뢓; 뢓; 뢓; 뢓; 뢓; ) HANGUL SYLLABLE RWAH +B894;B894;1105 116B;B894;1105 116B; # (뢔; 뢔; 뢔; 뢔; 뢔; ) HANGUL SYLLABLE RWAE +B895;B895;1105 116B 11A8;B895;1105 116B 11A8; # (뢕; 뢕; 뢕; 뢕; 뢕; ) HANGUL SYLLABLE RWAEG +B896;B896;1105 116B 11A9;B896;1105 116B 11A9; # (뢖; 뢖; 뢖; 뢖; 뢖; ) HANGUL SYLLABLE RWAEGG +B897;B897;1105 116B 11AA;B897;1105 116B 11AA; # (뢗; 뢗; 뢗; 뢗; 뢗; ) HANGUL SYLLABLE RWAEGS +B898;B898;1105 116B 11AB;B898;1105 116B 11AB; # (뢘; 뢘; 뢘; 뢘; 뢘; ) HANGUL SYLLABLE RWAEN +B899;B899;1105 116B 11AC;B899;1105 116B 11AC; # (뢙; 뢙; 뢙; 뢙; 뢙; ) HANGUL SYLLABLE RWAENJ +B89A;B89A;1105 116B 11AD;B89A;1105 116B 11AD; # (뢚; 뢚; 뢚; 뢚; 뢚; ) HANGUL SYLLABLE RWAENH +B89B;B89B;1105 116B 11AE;B89B;1105 116B 11AE; # (뢛; 뢛; 뢛; 뢛; 뢛; ) HANGUL SYLLABLE RWAED +B89C;B89C;1105 116B 11AF;B89C;1105 116B 11AF; # (뢜; 뢜; 뢜; 뢜; 뢜; ) HANGUL SYLLABLE RWAEL +B89D;B89D;1105 116B 11B0;B89D;1105 116B 11B0; # (뢝; 뢝; 뢝; 뢝; 뢝; ) HANGUL SYLLABLE RWAELG +B89E;B89E;1105 116B 11B1;B89E;1105 116B 11B1; # (뢞; 뢞; 뢞; 뢞; 뢞; ) HANGUL SYLLABLE RWAELM +B89F;B89F;1105 116B 11B2;B89F;1105 116B 11B2; # (뢟; 뢟; 뢟; 뢟; 뢟; ) HANGUL SYLLABLE RWAELB +B8A0;B8A0;1105 116B 11B3;B8A0;1105 116B 11B3; # (뢠; 뢠; 뢠; 뢠; 뢠; ) HANGUL SYLLABLE RWAELS +B8A1;B8A1;1105 116B 11B4;B8A1;1105 116B 11B4; # (뢡; 뢡; 뢡; 뢡; 뢡; ) HANGUL SYLLABLE RWAELT +B8A2;B8A2;1105 116B 11B5;B8A2;1105 116B 11B5; # (뢢; 뢢; 뢢; 뢢; 뢢; ) HANGUL SYLLABLE RWAELP +B8A3;B8A3;1105 116B 11B6;B8A3;1105 116B 11B6; # (뢣; 뢣; 뢣; 뢣; 뢣; ) HANGUL SYLLABLE RWAELH +B8A4;B8A4;1105 116B 11B7;B8A4;1105 116B 11B7; # (뢤; 뢤; 뢤; 뢤; 뢤; ) HANGUL SYLLABLE RWAEM +B8A5;B8A5;1105 116B 11B8;B8A5;1105 116B 11B8; # (뢥; 뢥; 뢥; 뢥; 뢥; ) HANGUL SYLLABLE RWAEB +B8A6;B8A6;1105 116B 11B9;B8A6;1105 116B 11B9; # (뢦; 뢦; 뢦; 뢦; 뢦; ) HANGUL SYLLABLE RWAEBS +B8A7;B8A7;1105 116B 11BA;B8A7;1105 116B 11BA; # (뢧; 뢧; 뢧; 뢧; 뢧; ) HANGUL SYLLABLE RWAES +B8A8;B8A8;1105 116B 11BB;B8A8;1105 116B 11BB; # (뢨; 뢨; 뢨; 뢨; 뢨; ) HANGUL SYLLABLE RWAESS +B8A9;B8A9;1105 116B 11BC;B8A9;1105 116B 11BC; # (뢩; 뢩; 뢩; 뢩; 뢩; ) HANGUL SYLLABLE RWAENG +B8AA;B8AA;1105 116B 11BD;B8AA;1105 116B 11BD; # (뢪; 뢪; 뢪; 뢪; 뢪; ) HANGUL SYLLABLE RWAEJ +B8AB;B8AB;1105 116B 11BE;B8AB;1105 116B 11BE; # (뢫; 뢫; 뢫; 뢫; 뢫; ) HANGUL SYLLABLE RWAEC +B8AC;B8AC;1105 116B 11BF;B8AC;1105 116B 11BF; # (뢬; 뢬; 뢬; 뢬; 뢬; ) HANGUL SYLLABLE RWAEK +B8AD;B8AD;1105 116B 11C0;B8AD;1105 116B 11C0; # (뢭; 뢭; 뢭; 뢭; 뢭; ) HANGUL SYLLABLE RWAET +B8AE;B8AE;1105 116B 11C1;B8AE;1105 116B 11C1; # (뢮; 뢮; 뢮; 뢮; 뢮; ) HANGUL SYLLABLE RWAEP +B8AF;B8AF;1105 116B 11C2;B8AF;1105 116B 11C2; # (뢯; 뢯; 뢯; 뢯; 뢯; ) HANGUL SYLLABLE RWAEH +B8B0;B8B0;1105 116C;B8B0;1105 116C; # (뢰; 뢰; 뢰; 뢰; 뢰; ) HANGUL SYLLABLE ROE +B8B1;B8B1;1105 116C 11A8;B8B1;1105 116C 11A8; # (뢱; 뢱; 뢱; 뢱; 뢱; ) HANGUL SYLLABLE ROEG +B8B2;B8B2;1105 116C 11A9;B8B2;1105 116C 11A9; # (뢲; 뢲; 뢲; 뢲; 뢲; ) HANGUL SYLLABLE ROEGG +B8B3;B8B3;1105 116C 11AA;B8B3;1105 116C 11AA; # (뢳; 뢳; 뢳; 뢳; 뢳; ) HANGUL SYLLABLE ROEGS +B8B4;B8B4;1105 116C 11AB;B8B4;1105 116C 11AB; # (뢴; 뢴; 뢴; 뢴; 뢴; ) HANGUL SYLLABLE ROEN +B8B5;B8B5;1105 116C 11AC;B8B5;1105 116C 11AC; # (뢵; 뢵; 뢵; 뢵; 뢵; ) HANGUL SYLLABLE ROENJ +B8B6;B8B6;1105 116C 11AD;B8B6;1105 116C 11AD; # (뢶; 뢶; 뢶; 뢶; 뢶; ) HANGUL SYLLABLE ROENH +B8B7;B8B7;1105 116C 11AE;B8B7;1105 116C 11AE; # (뢷; 뢷; 뢷; 뢷; 뢷; ) HANGUL SYLLABLE ROED +B8B8;B8B8;1105 116C 11AF;B8B8;1105 116C 11AF; # (뢸; 뢸; 뢸; 뢸; 뢸; ) HANGUL SYLLABLE ROEL +B8B9;B8B9;1105 116C 11B0;B8B9;1105 116C 11B0; # (뢹; 뢹; 뢹; 뢹; 뢹; ) HANGUL SYLLABLE ROELG +B8BA;B8BA;1105 116C 11B1;B8BA;1105 116C 11B1; # (뢺; 뢺; 뢺; 뢺; 뢺; ) HANGUL SYLLABLE ROELM +B8BB;B8BB;1105 116C 11B2;B8BB;1105 116C 11B2; # (뢻; 뢻; 뢻; 뢻; 뢻; ) HANGUL SYLLABLE ROELB +B8BC;B8BC;1105 116C 11B3;B8BC;1105 116C 11B3; # (뢼; 뢼; 뢼; 뢼; 뢼; ) HANGUL SYLLABLE ROELS +B8BD;B8BD;1105 116C 11B4;B8BD;1105 116C 11B4; # (뢽; 뢽; 뢽; 뢽; 뢽; ) HANGUL SYLLABLE ROELT +B8BE;B8BE;1105 116C 11B5;B8BE;1105 116C 11B5; # (뢾; 뢾; 뢾; 뢾; 뢾; ) HANGUL SYLLABLE ROELP +B8BF;B8BF;1105 116C 11B6;B8BF;1105 116C 11B6; # (뢿; 뢿; 뢿; 뢿; 뢿; ) HANGUL SYLLABLE ROELH +B8C0;B8C0;1105 116C 11B7;B8C0;1105 116C 11B7; # (룀; 룀; 룀; 룀; 룀; ) HANGUL SYLLABLE ROEM +B8C1;B8C1;1105 116C 11B8;B8C1;1105 116C 11B8; # (룁; 룁; 룁; 룁; 룁; ) HANGUL SYLLABLE ROEB +B8C2;B8C2;1105 116C 11B9;B8C2;1105 116C 11B9; # (룂; 룂; 룂; 룂; 룂; ) HANGUL SYLLABLE ROEBS +B8C3;B8C3;1105 116C 11BA;B8C3;1105 116C 11BA; # (룃; 룃; 룃; 룃; 룃; ) HANGUL SYLLABLE ROES +B8C4;B8C4;1105 116C 11BB;B8C4;1105 116C 11BB; # (룄; 룄; 룄; 룄; 룄; ) HANGUL SYLLABLE ROESS +B8C5;B8C5;1105 116C 11BC;B8C5;1105 116C 11BC; # (룅; 룅; 룅; 룅; 룅; ) HANGUL SYLLABLE ROENG +B8C6;B8C6;1105 116C 11BD;B8C6;1105 116C 11BD; # (룆; 룆; 룆; 룆; 룆; ) HANGUL SYLLABLE ROEJ +B8C7;B8C7;1105 116C 11BE;B8C7;1105 116C 11BE; # (룇; 룇; 룇; 룇; 룇; ) HANGUL SYLLABLE ROEC +B8C8;B8C8;1105 116C 11BF;B8C8;1105 116C 11BF; # (룈; 룈; 룈; 룈; 룈; ) HANGUL SYLLABLE ROEK +B8C9;B8C9;1105 116C 11C0;B8C9;1105 116C 11C0; # (룉; 룉; 룉; 룉; 룉; ) HANGUL SYLLABLE ROET +B8CA;B8CA;1105 116C 11C1;B8CA;1105 116C 11C1; # (룊; 룊; 룊; 룊; 룊; ) HANGUL SYLLABLE ROEP +B8CB;B8CB;1105 116C 11C2;B8CB;1105 116C 11C2; # (룋; 룋; 룋; 룋; 룋; ) HANGUL SYLLABLE ROEH +B8CC;B8CC;1105 116D;B8CC;1105 116D; # (료; 료; 료; 료; 료; ) HANGUL SYLLABLE RYO +B8CD;B8CD;1105 116D 11A8;B8CD;1105 116D 11A8; # (룍; 룍; 룍; 룍; 룍; ) HANGUL SYLLABLE RYOG +B8CE;B8CE;1105 116D 11A9;B8CE;1105 116D 11A9; # (룎; 룎; 룎; 룎; 룎; ) HANGUL SYLLABLE RYOGG +B8CF;B8CF;1105 116D 11AA;B8CF;1105 116D 11AA; # (룏; 룏; 룏; 룏; 룏; ) HANGUL SYLLABLE RYOGS +B8D0;B8D0;1105 116D 11AB;B8D0;1105 116D 11AB; # (룐; 룐; 룐; 룐; 룐; ) HANGUL SYLLABLE RYON +B8D1;B8D1;1105 116D 11AC;B8D1;1105 116D 11AC; # (룑; 룑; 룑; 룑; 룑; ) HANGUL SYLLABLE RYONJ +B8D2;B8D2;1105 116D 11AD;B8D2;1105 116D 11AD; # (룒; 룒; 룒; 룒; 룒; ) HANGUL SYLLABLE RYONH +B8D3;B8D3;1105 116D 11AE;B8D3;1105 116D 11AE; # (룓; 룓; 룓; 룓; 룓; ) HANGUL SYLLABLE RYOD +B8D4;B8D4;1105 116D 11AF;B8D4;1105 116D 11AF; # (룔; 룔; 룔; 룔; 룔; ) HANGUL SYLLABLE RYOL +B8D5;B8D5;1105 116D 11B0;B8D5;1105 116D 11B0; # (룕; 룕; 룕; 룕; 룕; ) HANGUL SYLLABLE RYOLG +B8D6;B8D6;1105 116D 11B1;B8D6;1105 116D 11B1; # (룖; 룖; 룖; 룖; 룖; ) HANGUL SYLLABLE RYOLM +B8D7;B8D7;1105 116D 11B2;B8D7;1105 116D 11B2; # (룗; 룗; 룗; 룗; 룗; ) HANGUL SYLLABLE RYOLB +B8D8;B8D8;1105 116D 11B3;B8D8;1105 116D 11B3; # (룘; 룘; 룘; 룘; 룘; ) HANGUL SYLLABLE RYOLS +B8D9;B8D9;1105 116D 11B4;B8D9;1105 116D 11B4; # (룙; 룙; 룙; 룙; 룙; ) HANGUL SYLLABLE RYOLT +B8DA;B8DA;1105 116D 11B5;B8DA;1105 116D 11B5; # (룚; 룚; 룚; 룚; 룚; ) HANGUL SYLLABLE RYOLP +B8DB;B8DB;1105 116D 11B6;B8DB;1105 116D 11B6; # (룛; 룛; 룛; 룛; 룛; ) HANGUL SYLLABLE RYOLH +B8DC;B8DC;1105 116D 11B7;B8DC;1105 116D 11B7; # (룜; 룜; 룜; 룜; 룜; ) HANGUL SYLLABLE RYOM +B8DD;B8DD;1105 116D 11B8;B8DD;1105 116D 11B8; # (룝; 룝; 룝; 룝; 룝; ) HANGUL SYLLABLE RYOB +B8DE;B8DE;1105 116D 11B9;B8DE;1105 116D 11B9; # (룞; 룞; 룞; 룞; 룞; ) HANGUL SYLLABLE RYOBS +B8DF;B8DF;1105 116D 11BA;B8DF;1105 116D 11BA; # (룟; 룟; 룟; 룟; 룟; ) HANGUL SYLLABLE RYOS +B8E0;B8E0;1105 116D 11BB;B8E0;1105 116D 11BB; # (룠; 룠; 룠; 룠; 룠; ) HANGUL SYLLABLE RYOSS +B8E1;B8E1;1105 116D 11BC;B8E1;1105 116D 11BC; # (룡; 룡; 룡; 룡; 룡; ) HANGUL SYLLABLE RYONG +B8E2;B8E2;1105 116D 11BD;B8E2;1105 116D 11BD; # (룢; 룢; 룢; 룢; 룢; ) HANGUL SYLLABLE RYOJ +B8E3;B8E3;1105 116D 11BE;B8E3;1105 116D 11BE; # (룣; 룣; 룣; 룣; 룣; ) HANGUL SYLLABLE RYOC +B8E4;B8E4;1105 116D 11BF;B8E4;1105 116D 11BF; # (룤; 룤; 룤; 룤; 룤; ) HANGUL SYLLABLE RYOK +B8E5;B8E5;1105 116D 11C0;B8E5;1105 116D 11C0; # (룥; 룥; 룥; 룥; 룥; ) HANGUL SYLLABLE RYOT +B8E6;B8E6;1105 116D 11C1;B8E6;1105 116D 11C1; # (룦; 룦; 룦; 룦; 룦; ) HANGUL SYLLABLE RYOP +B8E7;B8E7;1105 116D 11C2;B8E7;1105 116D 11C2; # (룧; 룧; 룧; 룧; 룧; ) HANGUL SYLLABLE RYOH +B8E8;B8E8;1105 116E;B8E8;1105 116E; # (루; 루; 루; 루; 루; ) HANGUL SYLLABLE RU +B8E9;B8E9;1105 116E 11A8;B8E9;1105 116E 11A8; # (룩; 룩; 룩; 룩; 룩; ) HANGUL SYLLABLE RUG +B8EA;B8EA;1105 116E 11A9;B8EA;1105 116E 11A9; # (룪; 룪; 룪; 룪; 룪; ) HANGUL SYLLABLE RUGG +B8EB;B8EB;1105 116E 11AA;B8EB;1105 116E 11AA; # (룫; 룫; 룫; 룫; 룫; ) HANGUL SYLLABLE RUGS +B8EC;B8EC;1105 116E 11AB;B8EC;1105 116E 11AB; # (룬; 룬; 룬; 룬; 룬; ) HANGUL SYLLABLE RUN +B8ED;B8ED;1105 116E 11AC;B8ED;1105 116E 11AC; # (룭; 룭; 룭; 룭; 룭; ) HANGUL SYLLABLE RUNJ +B8EE;B8EE;1105 116E 11AD;B8EE;1105 116E 11AD; # (룮; 룮; 룮; 룮; 룮; ) HANGUL SYLLABLE RUNH +B8EF;B8EF;1105 116E 11AE;B8EF;1105 116E 11AE; # (룯; 룯; 룯; 룯; 룯; ) HANGUL SYLLABLE RUD +B8F0;B8F0;1105 116E 11AF;B8F0;1105 116E 11AF; # (룰; 룰; 룰; 룰; 룰; ) HANGUL SYLLABLE RUL +B8F1;B8F1;1105 116E 11B0;B8F1;1105 116E 11B0; # (룱; 룱; 룱; 룱; 룱; ) HANGUL SYLLABLE RULG +B8F2;B8F2;1105 116E 11B1;B8F2;1105 116E 11B1; # (룲; 룲; 룲; 룲; 룲; ) HANGUL SYLLABLE RULM +B8F3;B8F3;1105 116E 11B2;B8F3;1105 116E 11B2; # (룳; 룳; 룳; 룳; 룳; ) HANGUL SYLLABLE RULB +B8F4;B8F4;1105 116E 11B3;B8F4;1105 116E 11B3; # (룴; 룴; 룴; 룴; 룴; ) HANGUL SYLLABLE RULS +B8F5;B8F5;1105 116E 11B4;B8F5;1105 116E 11B4; # (룵; 룵; 룵; 룵; 룵; ) HANGUL SYLLABLE RULT +B8F6;B8F6;1105 116E 11B5;B8F6;1105 116E 11B5; # (룶; 룶; 룶; 룶; 룶; ) HANGUL SYLLABLE RULP +B8F7;B8F7;1105 116E 11B6;B8F7;1105 116E 11B6; # (룷; 룷; 룷; 룷; 룷; ) HANGUL SYLLABLE RULH +B8F8;B8F8;1105 116E 11B7;B8F8;1105 116E 11B7; # (룸; 룸; 룸; 룸; 룸; ) HANGUL SYLLABLE RUM +B8F9;B8F9;1105 116E 11B8;B8F9;1105 116E 11B8; # (룹; 룹; 룹; 룹; 룹; ) HANGUL SYLLABLE RUB +B8FA;B8FA;1105 116E 11B9;B8FA;1105 116E 11B9; # (룺; 룺; 룺; 룺; 룺; ) HANGUL SYLLABLE RUBS +B8FB;B8FB;1105 116E 11BA;B8FB;1105 116E 11BA; # (룻; 룻; 룻; 룻; 룻; ) HANGUL SYLLABLE RUS +B8FC;B8FC;1105 116E 11BB;B8FC;1105 116E 11BB; # (룼; 룼; 룼; 룼; 룼; ) HANGUL SYLLABLE RUSS +B8FD;B8FD;1105 116E 11BC;B8FD;1105 116E 11BC; # (룽; 룽; 룽; 룽; 룽; ) HANGUL SYLLABLE RUNG +B8FE;B8FE;1105 116E 11BD;B8FE;1105 116E 11BD; # (룾; 룾; 룾; 룾; 룾; ) HANGUL SYLLABLE RUJ +B8FF;B8FF;1105 116E 11BE;B8FF;1105 116E 11BE; # (룿; 룿; 룿; 룿; 룿; ) HANGUL SYLLABLE RUC +B900;B900;1105 116E 11BF;B900;1105 116E 11BF; # (뤀; 뤀; 뤀; 뤀; 뤀; ) HANGUL SYLLABLE RUK +B901;B901;1105 116E 11C0;B901;1105 116E 11C0; # (뤁; 뤁; 뤁; 뤁; 뤁; ) HANGUL SYLLABLE RUT +B902;B902;1105 116E 11C1;B902;1105 116E 11C1; # (뤂; 뤂; 뤂; 뤂; 뤂; ) HANGUL SYLLABLE RUP +B903;B903;1105 116E 11C2;B903;1105 116E 11C2; # (뤃; 뤃; 뤃; 뤃; 뤃; ) HANGUL SYLLABLE RUH +B904;B904;1105 116F;B904;1105 116F; # (뤄; 뤄; 뤄; 뤄; 뤄; ) HANGUL SYLLABLE RWEO +B905;B905;1105 116F 11A8;B905;1105 116F 11A8; # (뤅; 뤅; 뤅; 뤅; 뤅; ) HANGUL SYLLABLE RWEOG +B906;B906;1105 116F 11A9;B906;1105 116F 11A9; # (뤆; 뤆; 뤆; 뤆; 뤆; ) HANGUL SYLLABLE RWEOGG +B907;B907;1105 116F 11AA;B907;1105 116F 11AA; # (뤇; 뤇; 뤇; 뤇; 뤇; ) HANGUL SYLLABLE RWEOGS +B908;B908;1105 116F 11AB;B908;1105 116F 11AB; # (뤈; 뤈; 뤈; 뤈; 뤈; ) HANGUL SYLLABLE RWEON +B909;B909;1105 116F 11AC;B909;1105 116F 11AC; # (뤉; 뤉; 뤉; 뤉; 뤉; ) HANGUL SYLLABLE RWEONJ +B90A;B90A;1105 116F 11AD;B90A;1105 116F 11AD; # (뤊; 뤊; 뤊; 뤊; 뤊; ) HANGUL SYLLABLE RWEONH +B90B;B90B;1105 116F 11AE;B90B;1105 116F 11AE; # (뤋; 뤋; 뤋; 뤋; 뤋; ) HANGUL SYLLABLE RWEOD +B90C;B90C;1105 116F 11AF;B90C;1105 116F 11AF; # (뤌; 뤌; 뤌; 뤌; 뤌; ) HANGUL SYLLABLE RWEOL +B90D;B90D;1105 116F 11B0;B90D;1105 116F 11B0; # (뤍; 뤍; 뤍; 뤍; 뤍; ) HANGUL SYLLABLE RWEOLG +B90E;B90E;1105 116F 11B1;B90E;1105 116F 11B1; # (뤎; 뤎; 뤎; 뤎; 뤎; ) HANGUL SYLLABLE RWEOLM +B90F;B90F;1105 116F 11B2;B90F;1105 116F 11B2; # (뤏; 뤏; 뤏; 뤏; 뤏; ) HANGUL SYLLABLE RWEOLB +B910;B910;1105 116F 11B3;B910;1105 116F 11B3; # (뤐; 뤐; 뤐; 뤐; 뤐; ) HANGUL SYLLABLE RWEOLS +B911;B911;1105 116F 11B4;B911;1105 116F 11B4; # (뤑; 뤑; 뤑; 뤑; 뤑; ) HANGUL SYLLABLE RWEOLT +B912;B912;1105 116F 11B5;B912;1105 116F 11B5; # (뤒; 뤒; 뤒; 뤒; 뤒; ) HANGUL SYLLABLE RWEOLP +B913;B913;1105 116F 11B6;B913;1105 116F 11B6; # (뤓; 뤓; 뤓; 뤓; 뤓; ) HANGUL SYLLABLE RWEOLH +B914;B914;1105 116F 11B7;B914;1105 116F 11B7; # (뤔; 뤔; 뤔; 뤔; 뤔; ) HANGUL SYLLABLE RWEOM +B915;B915;1105 116F 11B8;B915;1105 116F 11B8; # (뤕; 뤕; 뤕; 뤕; 뤕; ) HANGUL SYLLABLE RWEOB +B916;B916;1105 116F 11B9;B916;1105 116F 11B9; # (뤖; 뤖; 뤖; 뤖; 뤖; ) HANGUL SYLLABLE RWEOBS +B917;B917;1105 116F 11BA;B917;1105 116F 11BA; # (뤗; 뤗; 뤗; 뤗; 뤗; ) HANGUL SYLLABLE RWEOS +B918;B918;1105 116F 11BB;B918;1105 116F 11BB; # (뤘; 뤘; 뤘; 뤘; 뤘; ) HANGUL SYLLABLE RWEOSS +B919;B919;1105 116F 11BC;B919;1105 116F 11BC; # (뤙; 뤙; 뤙; 뤙; 뤙; ) HANGUL SYLLABLE RWEONG +B91A;B91A;1105 116F 11BD;B91A;1105 116F 11BD; # (뤚; 뤚; 뤚; 뤚; 뤚; ) HANGUL SYLLABLE RWEOJ +B91B;B91B;1105 116F 11BE;B91B;1105 116F 11BE; # (뤛; 뤛; 뤛; 뤛; 뤛; ) HANGUL SYLLABLE RWEOC +B91C;B91C;1105 116F 11BF;B91C;1105 116F 11BF; # (뤜; 뤜; 뤜; 뤜; 뤜; ) HANGUL SYLLABLE RWEOK +B91D;B91D;1105 116F 11C0;B91D;1105 116F 11C0; # (뤝; 뤝; 뤝; 뤝; 뤝; ) HANGUL SYLLABLE RWEOT +B91E;B91E;1105 116F 11C1;B91E;1105 116F 11C1; # (뤞; 뤞; 뤞; 뤞; 뤞; ) HANGUL SYLLABLE RWEOP +B91F;B91F;1105 116F 11C2;B91F;1105 116F 11C2; # (뤟; 뤟; 뤟; 뤟; 뤟; ) HANGUL SYLLABLE RWEOH +B920;B920;1105 1170;B920;1105 1170; # (뤠; 뤠; 뤠; 뤠; 뤠; ) HANGUL SYLLABLE RWE +B921;B921;1105 1170 11A8;B921;1105 1170 11A8; # (뤡; 뤡; 뤡; 뤡; 뤡; ) HANGUL SYLLABLE RWEG +B922;B922;1105 1170 11A9;B922;1105 1170 11A9; # (뤢; 뤢; 뤢; 뤢; 뤢; ) HANGUL SYLLABLE RWEGG +B923;B923;1105 1170 11AA;B923;1105 1170 11AA; # (뤣; 뤣; 뤣; 뤣; 뤣; ) HANGUL SYLLABLE RWEGS +B924;B924;1105 1170 11AB;B924;1105 1170 11AB; # (뤤; 뤤; 뤤; 뤤; 뤤; ) HANGUL SYLLABLE RWEN +B925;B925;1105 1170 11AC;B925;1105 1170 11AC; # (뤥; 뤥; 뤥; 뤥; 뤥; ) HANGUL SYLLABLE RWENJ +B926;B926;1105 1170 11AD;B926;1105 1170 11AD; # (뤦; 뤦; 뤦; 뤦; 뤦; ) HANGUL SYLLABLE RWENH +B927;B927;1105 1170 11AE;B927;1105 1170 11AE; # (뤧; 뤧; 뤧; 뤧; 뤧; ) HANGUL SYLLABLE RWED +B928;B928;1105 1170 11AF;B928;1105 1170 11AF; # (뤨; 뤨; 뤨; 뤨; 뤨; ) HANGUL SYLLABLE RWEL +B929;B929;1105 1170 11B0;B929;1105 1170 11B0; # (뤩; 뤩; 뤩; 뤩; 뤩; ) HANGUL SYLLABLE RWELG +B92A;B92A;1105 1170 11B1;B92A;1105 1170 11B1; # (뤪; 뤪; 뤪; 뤪; 뤪; ) HANGUL SYLLABLE RWELM +B92B;B92B;1105 1170 11B2;B92B;1105 1170 11B2; # (뤫; 뤫; 뤫; 뤫; 뤫; ) HANGUL SYLLABLE RWELB +B92C;B92C;1105 1170 11B3;B92C;1105 1170 11B3; # (뤬; 뤬; 뤬; 뤬; 뤬; ) HANGUL SYLLABLE RWELS +B92D;B92D;1105 1170 11B4;B92D;1105 1170 11B4; # (뤭; 뤭; 뤭; 뤭; 뤭; ) HANGUL SYLLABLE RWELT +B92E;B92E;1105 1170 11B5;B92E;1105 1170 11B5; # (뤮; 뤮; 뤮; 뤮; 뤮; ) HANGUL SYLLABLE RWELP +B92F;B92F;1105 1170 11B6;B92F;1105 1170 11B6; # (뤯; 뤯; 뤯; 뤯; 뤯; ) HANGUL SYLLABLE RWELH +B930;B930;1105 1170 11B7;B930;1105 1170 11B7; # (뤰; 뤰; 뤰; 뤰; 뤰; ) HANGUL SYLLABLE RWEM +B931;B931;1105 1170 11B8;B931;1105 1170 11B8; # (뤱; 뤱; 뤱; 뤱; 뤱; ) HANGUL SYLLABLE RWEB +B932;B932;1105 1170 11B9;B932;1105 1170 11B9; # (뤲; 뤲; 뤲; 뤲; 뤲; ) HANGUL SYLLABLE RWEBS +B933;B933;1105 1170 11BA;B933;1105 1170 11BA; # (뤳; 뤳; 뤳; 뤳; 뤳; ) HANGUL SYLLABLE RWES +B934;B934;1105 1170 11BB;B934;1105 1170 11BB; # (뤴; 뤴; 뤴; 뤴; 뤴; ) HANGUL SYLLABLE RWESS +B935;B935;1105 1170 11BC;B935;1105 1170 11BC; # (뤵; 뤵; 뤵; 뤵; 뤵; ) HANGUL SYLLABLE RWENG +B936;B936;1105 1170 11BD;B936;1105 1170 11BD; # (뤶; 뤶; 뤶; 뤶; 뤶; ) HANGUL SYLLABLE RWEJ +B937;B937;1105 1170 11BE;B937;1105 1170 11BE; # (뤷; 뤷; 뤷; 뤷; 뤷; ) HANGUL SYLLABLE RWEC +B938;B938;1105 1170 11BF;B938;1105 1170 11BF; # (뤸; 뤸; 뤸; 뤸; 뤸; ) HANGUL SYLLABLE RWEK +B939;B939;1105 1170 11C0;B939;1105 1170 11C0; # (뤹; 뤹; 뤹; 뤹; 뤹; ) HANGUL SYLLABLE RWET +B93A;B93A;1105 1170 11C1;B93A;1105 1170 11C1; # (뤺; 뤺; 뤺; 뤺; 뤺; ) HANGUL SYLLABLE RWEP +B93B;B93B;1105 1170 11C2;B93B;1105 1170 11C2; # (뤻; 뤻; 뤻; 뤻; 뤻; ) HANGUL SYLLABLE RWEH +B93C;B93C;1105 1171;B93C;1105 1171; # (뤼; 뤼; 뤼; 뤼; 뤼; ) HANGUL SYLLABLE RWI +B93D;B93D;1105 1171 11A8;B93D;1105 1171 11A8; # (뤽; 뤽; 뤽; 뤽; 뤽; ) HANGUL SYLLABLE RWIG +B93E;B93E;1105 1171 11A9;B93E;1105 1171 11A9; # (뤾; 뤾; 뤾; 뤾; 뤾; ) HANGUL SYLLABLE RWIGG +B93F;B93F;1105 1171 11AA;B93F;1105 1171 11AA; # (뤿; 뤿; 뤿; 뤿; 뤿; ) HANGUL SYLLABLE RWIGS +B940;B940;1105 1171 11AB;B940;1105 1171 11AB; # (륀; 륀; 륀; 륀; 륀; ) HANGUL SYLLABLE RWIN +B941;B941;1105 1171 11AC;B941;1105 1171 11AC; # (륁; 륁; 륁; 륁; 륁; ) HANGUL SYLLABLE RWINJ +B942;B942;1105 1171 11AD;B942;1105 1171 11AD; # (륂; 륂; 륂; 륂; 륂; ) HANGUL SYLLABLE RWINH +B943;B943;1105 1171 11AE;B943;1105 1171 11AE; # (륃; 륃; 륃; 륃; 륃; ) HANGUL SYLLABLE RWID +B944;B944;1105 1171 11AF;B944;1105 1171 11AF; # (륄; 륄; 륄; 륄; 륄; ) HANGUL SYLLABLE RWIL +B945;B945;1105 1171 11B0;B945;1105 1171 11B0; # (륅; 륅; 륅; 륅; 륅; ) HANGUL SYLLABLE RWILG +B946;B946;1105 1171 11B1;B946;1105 1171 11B1; # (륆; 륆; 륆; 륆; 륆; ) HANGUL SYLLABLE RWILM +B947;B947;1105 1171 11B2;B947;1105 1171 11B2; # (륇; 륇; 륇; 륇; 륇; ) HANGUL SYLLABLE RWILB +B948;B948;1105 1171 11B3;B948;1105 1171 11B3; # (륈; 륈; 륈; 륈; 륈; ) HANGUL SYLLABLE RWILS +B949;B949;1105 1171 11B4;B949;1105 1171 11B4; # (륉; 륉; 륉; 륉; 륉; ) HANGUL SYLLABLE RWILT +B94A;B94A;1105 1171 11B5;B94A;1105 1171 11B5; # (륊; 륊; 륊; 륊; 륊; ) HANGUL SYLLABLE RWILP +B94B;B94B;1105 1171 11B6;B94B;1105 1171 11B6; # (륋; 륋; 륋; 륋; 륋; ) HANGUL SYLLABLE RWILH +B94C;B94C;1105 1171 11B7;B94C;1105 1171 11B7; # (륌; 륌; 륌; 륌; 륌; ) HANGUL SYLLABLE RWIM +B94D;B94D;1105 1171 11B8;B94D;1105 1171 11B8; # (륍; 륍; 륍; 륍; 륍; ) HANGUL SYLLABLE RWIB +B94E;B94E;1105 1171 11B9;B94E;1105 1171 11B9; # (륎; 륎; 륎; 륎; 륎; ) HANGUL SYLLABLE RWIBS +B94F;B94F;1105 1171 11BA;B94F;1105 1171 11BA; # (륏; 륏; 륏; 륏; 륏; ) HANGUL SYLLABLE RWIS +B950;B950;1105 1171 11BB;B950;1105 1171 11BB; # (륐; 륐; 륐; 륐; 륐; ) HANGUL SYLLABLE RWISS +B951;B951;1105 1171 11BC;B951;1105 1171 11BC; # (륑; 륑; 륑; 륑; 륑; ) HANGUL SYLLABLE RWING +B952;B952;1105 1171 11BD;B952;1105 1171 11BD; # (륒; 륒; 륒; 륒; 륒; ) HANGUL SYLLABLE RWIJ +B953;B953;1105 1171 11BE;B953;1105 1171 11BE; # (륓; 륓; 륓; 륓; 륓; ) HANGUL SYLLABLE RWIC +B954;B954;1105 1171 11BF;B954;1105 1171 11BF; # (륔; 륔; 륔; 륔; 륔; ) HANGUL SYLLABLE RWIK +B955;B955;1105 1171 11C0;B955;1105 1171 11C0; # (륕; 륕; 륕; 륕; 륕; ) HANGUL SYLLABLE RWIT +B956;B956;1105 1171 11C1;B956;1105 1171 11C1; # (륖; 륖; 륖; 륖; 륖; ) HANGUL SYLLABLE RWIP +B957;B957;1105 1171 11C2;B957;1105 1171 11C2; # (륗; 륗; 륗; 륗; 륗; ) HANGUL SYLLABLE RWIH +B958;B958;1105 1172;B958;1105 1172; # (류; 류; 류; 류; 류; ) HANGUL SYLLABLE RYU +B959;B959;1105 1172 11A8;B959;1105 1172 11A8; # (륙; 륙; 륙; 륙; 륙; ) HANGUL SYLLABLE RYUG +B95A;B95A;1105 1172 11A9;B95A;1105 1172 11A9; # (륚; 륚; 륚; 륚; 륚; ) HANGUL SYLLABLE RYUGG +B95B;B95B;1105 1172 11AA;B95B;1105 1172 11AA; # (륛; 륛; 륛; 륛; 륛; ) HANGUL SYLLABLE RYUGS +B95C;B95C;1105 1172 11AB;B95C;1105 1172 11AB; # (륜; 륜; 륜; 륜; 륜; ) HANGUL SYLLABLE RYUN +B95D;B95D;1105 1172 11AC;B95D;1105 1172 11AC; # (륝; 륝; 륝; 륝; 륝; ) HANGUL SYLLABLE RYUNJ +B95E;B95E;1105 1172 11AD;B95E;1105 1172 11AD; # (륞; 륞; 륞; 륞; 륞; ) HANGUL SYLLABLE RYUNH +B95F;B95F;1105 1172 11AE;B95F;1105 1172 11AE; # (륟; 륟; 륟; 륟; 륟; ) HANGUL SYLLABLE RYUD +B960;B960;1105 1172 11AF;B960;1105 1172 11AF; # (률; 률; 률; 률; 률; ) HANGUL SYLLABLE RYUL +B961;B961;1105 1172 11B0;B961;1105 1172 11B0; # (륡; 륡; 륡; 륡; 륡; ) HANGUL SYLLABLE RYULG +B962;B962;1105 1172 11B1;B962;1105 1172 11B1; # (륢; 륢; 륢; 륢; 륢; ) HANGUL SYLLABLE RYULM +B963;B963;1105 1172 11B2;B963;1105 1172 11B2; # (륣; 륣; 륣; 륣; 륣; ) HANGUL SYLLABLE RYULB +B964;B964;1105 1172 11B3;B964;1105 1172 11B3; # (륤; 륤; 륤; 륤; 륤; ) HANGUL SYLLABLE RYULS +B965;B965;1105 1172 11B4;B965;1105 1172 11B4; # (륥; 륥; 륥; 륥; 륥; ) HANGUL SYLLABLE RYULT +B966;B966;1105 1172 11B5;B966;1105 1172 11B5; # (륦; 륦; 륦; 륦; 륦; ) HANGUL SYLLABLE RYULP +B967;B967;1105 1172 11B6;B967;1105 1172 11B6; # (륧; 륧; 륧; 륧; 륧; ) HANGUL SYLLABLE RYULH +B968;B968;1105 1172 11B7;B968;1105 1172 11B7; # (륨; 륨; 륨; 륨; 륨; ) HANGUL SYLLABLE RYUM +B969;B969;1105 1172 11B8;B969;1105 1172 11B8; # (륩; 륩; 륩; 륩; 륩; ) HANGUL SYLLABLE RYUB +B96A;B96A;1105 1172 11B9;B96A;1105 1172 11B9; # (륪; 륪; 륪; 륪; 륪; ) HANGUL SYLLABLE RYUBS +B96B;B96B;1105 1172 11BA;B96B;1105 1172 11BA; # (륫; 륫; 륫; 륫; 륫; ) HANGUL SYLLABLE RYUS +B96C;B96C;1105 1172 11BB;B96C;1105 1172 11BB; # (륬; 륬; 륬; 륬; 륬; ) HANGUL SYLLABLE RYUSS +B96D;B96D;1105 1172 11BC;B96D;1105 1172 11BC; # (륭; 륭; 륭; 륭; 륭; ) HANGUL SYLLABLE RYUNG +B96E;B96E;1105 1172 11BD;B96E;1105 1172 11BD; # (륮; 륮; 륮; 륮; 륮; ) HANGUL SYLLABLE RYUJ +B96F;B96F;1105 1172 11BE;B96F;1105 1172 11BE; # (륯; 륯; 륯; 륯; 륯; ) HANGUL SYLLABLE RYUC +B970;B970;1105 1172 11BF;B970;1105 1172 11BF; # (륰; 륰; 륰; 륰; 륰; ) HANGUL SYLLABLE RYUK +B971;B971;1105 1172 11C0;B971;1105 1172 11C0; # (륱; 륱; 륱; 륱; 륱; ) HANGUL SYLLABLE RYUT +B972;B972;1105 1172 11C1;B972;1105 1172 11C1; # (륲; 륲; 륲; 륲; 륲; ) HANGUL SYLLABLE RYUP +B973;B973;1105 1172 11C2;B973;1105 1172 11C2; # (륳; 륳; 륳; 륳; 륳; ) HANGUL SYLLABLE RYUH +B974;B974;1105 1173;B974;1105 1173; # (르; 르; 르; 르; 르; ) HANGUL SYLLABLE REU +B975;B975;1105 1173 11A8;B975;1105 1173 11A8; # (륵; 륵; 륵; 륵; 륵; ) HANGUL SYLLABLE REUG +B976;B976;1105 1173 11A9;B976;1105 1173 11A9; # (륶; 륶; 륶; 륶; 륶; ) HANGUL SYLLABLE REUGG +B977;B977;1105 1173 11AA;B977;1105 1173 11AA; # (륷; 륷; 륷; 륷; 륷; ) HANGUL SYLLABLE REUGS +B978;B978;1105 1173 11AB;B978;1105 1173 11AB; # (른; 른; 른; 른; 른; ) HANGUL SYLLABLE REUN +B979;B979;1105 1173 11AC;B979;1105 1173 11AC; # (륹; 륹; 륹; 륹; 륹; ) HANGUL SYLLABLE REUNJ +B97A;B97A;1105 1173 11AD;B97A;1105 1173 11AD; # (륺; 륺; 륺; 륺; 륺; ) HANGUL SYLLABLE REUNH +B97B;B97B;1105 1173 11AE;B97B;1105 1173 11AE; # (륻; 륻; 륻; 륻; 륻; ) HANGUL SYLLABLE REUD +B97C;B97C;1105 1173 11AF;B97C;1105 1173 11AF; # (를; 를; 를; 를; 를; ) HANGUL SYLLABLE REUL +B97D;B97D;1105 1173 11B0;B97D;1105 1173 11B0; # (륽; 륽; 륽; 륽; 륽; ) HANGUL SYLLABLE REULG +B97E;B97E;1105 1173 11B1;B97E;1105 1173 11B1; # (륾; 륾; 륾; 륾; 륾; ) HANGUL SYLLABLE REULM +B97F;B97F;1105 1173 11B2;B97F;1105 1173 11B2; # (륿; 륿; 륿; 륿; 륿; ) HANGUL SYLLABLE REULB +B980;B980;1105 1173 11B3;B980;1105 1173 11B3; # (릀; 릀; 릀; 릀; 릀; ) HANGUL SYLLABLE REULS +B981;B981;1105 1173 11B4;B981;1105 1173 11B4; # (릁; 릁; 릁; 릁; 릁; ) HANGUL SYLLABLE REULT +B982;B982;1105 1173 11B5;B982;1105 1173 11B5; # (릂; 릂; 릂; 릂; 릂; ) HANGUL SYLLABLE REULP +B983;B983;1105 1173 11B6;B983;1105 1173 11B6; # (릃; 릃; 릃; 릃; 릃; ) HANGUL SYLLABLE REULH +B984;B984;1105 1173 11B7;B984;1105 1173 11B7; # (름; 름; 름; 름; 름; ) HANGUL SYLLABLE REUM +B985;B985;1105 1173 11B8;B985;1105 1173 11B8; # (릅; 릅; 릅; 릅; 릅; ) HANGUL SYLLABLE REUB +B986;B986;1105 1173 11B9;B986;1105 1173 11B9; # (릆; 릆; 릆; 릆; 릆; ) HANGUL SYLLABLE REUBS +B987;B987;1105 1173 11BA;B987;1105 1173 11BA; # (릇; 릇; 릇; 릇; 릇; ) HANGUL SYLLABLE REUS +B988;B988;1105 1173 11BB;B988;1105 1173 11BB; # (릈; 릈; 릈; 릈; 릈; ) HANGUL SYLLABLE REUSS +B989;B989;1105 1173 11BC;B989;1105 1173 11BC; # (릉; 릉; 릉; 릉; 릉; ) HANGUL SYLLABLE REUNG +B98A;B98A;1105 1173 11BD;B98A;1105 1173 11BD; # (릊; 릊; 릊; 릊; 릊; ) HANGUL SYLLABLE REUJ +B98B;B98B;1105 1173 11BE;B98B;1105 1173 11BE; # (릋; 릋; 릋; 릋; 릋; ) HANGUL SYLLABLE REUC +B98C;B98C;1105 1173 11BF;B98C;1105 1173 11BF; # (릌; 릌; 릌; 릌; 릌; ) HANGUL SYLLABLE REUK +B98D;B98D;1105 1173 11C0;B98D;1105 1173 11C0; # (릍; 릍; 릍; 릍; 릍; ) HANGUL SYLLABLE REUT +B98E;B98E;1105 1173 11C1;B98E;1105 1173 11C1; # (릎; 릎; 릎; 릎; 릎; ) HANGUL SYLLABLE REUP +B98F;B98F;1105 1173 11C2;B98F;1105 1173 11C2; # (릏; 릏; 릏; 릏; 릏; ) HANGUL SYLLABLE REUH +B990;B990;1105 1174;B990;1105 1174; # (릐; 릐; 릐; 릐; 릐; ) HANGUL SYLLABLE RYI +B991;B991;1105 1174 11A8;B991;1105 1174 11A8; # (릑; 릑; 릑; 릑; 릑; ) HANGUL SYLLABLE RYIG +B992;B992;1105 1174 11A9;B992;1105 1174 11A9; # (릒; 릒; 릒; 릒; 릒; ) HANGUL SYLLABLE RYIGG +B993;B993;1105 1174 11AA;B993;1105 1174 11AA; # (릓; 릓; 릓; 릓; 릓; ) HANGUL SYLLABLE RYIGS +B994;B994;1105 1174 11AB;B994;1105 1174 11AB; # (릔; 릔; 릔; 릔; 릔; ) HANGUL SYLLABLE RYIN +B995;B995;1105 1174 11AC;B995;1105 1174 11AC; # (릕; 릕; 릕; 릕; 릕; ) HANGUL SYLLABLE RYINJ +B996;B996;1105 1174 11AD;B996;1105 1174 11AD; # (릖; 릖; 릖; 릖; 릖; ) HANGUL SYLLABLE RYINH +B997;B997;1105 1174 11AE;B997;1105 1174 11AE; # (릗; 릗; 릗; 릗; 릗; ) HANGUL SYLLABLE RYID +B998;B998;1105 1174 11AF;B998;1105 1174 11AF; # (릘; 릘; 릘; 릘; 릘; ) HANGUL SYLLABLE RYIL +B999;B999;1105 1174 11B0;B999;1105 1174 11B0; # (릙; 릙; 릙; 릙; 릙; ) HANGUL SYLLABLE RYILG +B99A;B99A;1105 1174 11B1;B99A;1105 1174 11B1; # (릚; 릚; 릚; 릚; 릚; ) HANGUL SYLLABLE RYILM +B99B;B99B;1105 1174 11B2;B99B;1105 1174 11B2; # (릛; 릛; 릛; 릛; 릛; ) HANGUL SYLLABLE RYILB +B99C;B99C;1105 1174 11B3;B99C;1105 1174 11B3; # (릜; 릜; 릜; 릜; 릜; ) HANGUL SYLLABLE RYILS +B99D;B99D;1105 1174 11B4;B99D;1105 1174 11B4; # (릝; 릝; 릝; 릝; 릝; ) HANGUL SYLLABLE RYILT +B99E;B99E;1105 1174 11B5;B99E;1105 1174 11B5; # (릞; 릞; 릞; 릞; 릞; ) HANGUL SYLLABLE RYILP +B99F;B99F;1105 1174 11B6;B99F;1105 1174 11B6; # (릟; 릟; 릟; 릟; 릟; ) HANGUL SYLLABLE RYILH +B9A0;B9A0;1105 1174 11B7;B9A0;1105 1174 11B7; # (릠; 릠; 릠; 릠; 릠; ) HANGUL SYLLABLE RYIM +B9A1;B9A1;1105 1174 11B8;B9A1;1105 1174 11B8; # (릡; 릡; 릡; 릡; 릡; ) HANGUL SYLLABLE RYIB +B9A2;B9A2;1105 1174 11B9;B9A2;1105 1174 11B9; # (릢; 릢; 릢; 릢; 릢; ) HANGUL SYLLABLE RYIBS +B9A3;B9A3;1105 1174 11BA;B9A3;1105 1174 11BA; # (릣; 릣; 릣; 릣; 릣; ) HANGUL SYLLABLE RYIS +B9A4;B9A4;1105 1174 11BB;B9A4;1105 1174 11BB; # (릤; 릤; 릤; 릤; 릤; ) HANGUL SYLLABLE RYISS +B9A5;B9A5;1105 1174 11BC;B9A5;1105 1174 11BC; # (릥; 릥; 릥; 릥; 릥; ) HANGUL SYLLABLE RYING +B9A6;B9A6;1105 1174 11BD;B9A6;1105 1174 11BD; # (릦; 릦; 릦; 릦; 릦; ) HANGUL SYLLABLE RYIJ +B9A7;B9A7;1105 1174 11BE;B9A7;1105 1174 11BE; # (릧; 릧; 릧; 릧; 릧; ) HANGUL SYLLABLE RYIC +B9A8;B9A8;1105 1174 11BF;B9A8;1105 1174 11BF; # (릨; 릨; 릨; 릨; 릨; ) HANGUL SYLLABLE RYIK +B9A9;B9A9;1105 1174 11C0;B9A9;1105 1174 11C0; # (릩; 릩; 릩; 릩; 릩; ) HANGUL SYLLABLE RYIT +B9AA;B9AA;1105 1174 11C1;B9AA;1105 1174 11C1; # (릪; 릪; 릪; 릪; 릪; ) HANGUL SYLLABLE RYIP +B9AB;B9AB;1105 1174 11C2;B9AB;1105 1174 11C2; # (릫; 릫; 릫; 릫; 릫; ) HANGUL SYLLABLE RYIH +B9AC;B9AC;1105 1175;B9AC;1105 1175; # (리; 리; 리; 리; 리; ) HANGUL SYLLABLE RI +B9AD;B9AD;1105 1175 11A8;B9AD;1105 1175 11A8; # (릭; 릭; 릭; 릭; 릭; ) HANGUL SYLLABLE RIG +B9AE;B9AE;1105 1175 11A9;B9AE;1105 1175 11A9; # (릮; 릮; 릮; 릮; 릮; ) HANGUL SYLLABLE RIGG +B9AF;B9AF;1105 1175 11AA;B9AF;1105 1175 11AA; # (릯; 릯; 릯; 릯; 릯; ) HANGUL SYLLABLE RIGS +B9B0;B9B0;1105 1175 11AB;B9B0;1105 1175 11AB; # (린; 린; 린; 린; 린; ) HANGUL SYLLABLE RIN +B9B1;B9B1;1105 1175 11AC;B9B1;1105 1175 11AC; # (릱; 릱; 릱; 릱; 릱; ) HANGUL SYLLABLE RINJ +B9B2;B9B2;1105 1175 11AD;B9B2;1105 1175 11AD; # (릲; 릲; 릲; 릲; 릲; ) HANGUL SYLLABLE RINH +B9B3;B9B3;1105 1175 11AE;B9B3;1105 1175 11AE; # (릳; 릳; 릳; 릳; 릳; ) HANGUL SYLLABLE RID +B9B4;B9B4;1105 1175 11AF;B9B4;1105 1175 11AF; # (릴; 릴; 릴; 릴; 릴; ) HANGUL SYLLABLE RIL +B9B5;B9B5;1105 1175 11B0;B9B5;1105 1175 11B0; # (릵; 릵; 릵; 릵; 릵; ) HANGUL SYLLABLE RILG +B9B6;B9B6;1105 1175 11B1;B9B6;1105 1175 11B1; # (릶; 릶; 릶; 릶; 릶; ) HANGUL SYLLABLE RILM +B9B7;B9B7;1105 1175 11B2;B9B7;1105 1175 11B2; # (릷; 릷; 릷; 릷; 릷; ) HANGUL SYLLABLE RILB +B9B8;B9B8;1105 1175 11B3;B9B8;1105 1175 11B3; # (릸; 릸; 릸; 릸; 릸; ) HANGUL SYLLABLE RILS +B9B9;B9B9;1105 1175 11B4;B9B9;1105 1175 11B4; # (릹; 릹; 릹; 릹; 릹; ) HANGUL SYLLABLE RILT +B9BA;B9BA;1105 1175 11B5;B9BA;1105 1175 11B5; # (릺; 릺; 릺; 릺; 릺; ) HANGUL SYLLABLE RILP +B9BB;B9BB;1105 1175 11B6;B9BB;1105 1175 11B6; # (릻; 릻; 릻; 릻; 릻; ) HANGUL SYLLABLE RILH +B9BC;B9BC;1105 1175 11B7;B9BC;1105 1175 11B7; # (림; 림; 림; 림; 림; ) HANGUL SYLLABLE RIM +B9BD;B9BD;1105 1175 11B8;B9BD;1105 1175 11B8; # (립; 립; 립; 립; 립; ) HANGUL SYLLABLE RIB +B9BE;B9BE;1105 1175 11B9;B9BE;1105 1175 11B9; # (릾; 릾; 릾; 릾; 릾; ) HANGUL SYLLABLE RIBS +B9BF;B9BF;1105 1175 11BA;B9BF;1105 1175 11BA; # (릿; 릿; 릿; 릿; 릿; ) HANGUL SYLLABLE RIS +B9C0;B9C0;1105 1175 11BB;B9C0;1105 1175 11BB; # (맀; 맀; 맀; 맀; 맀; ) HANGUL SYLLABLE RISS +B9C1;B9C1;1105 1175 11BC;B9C1;1105 1175 11BC; # (링; 링; 링; 링; 링; ) HANGUL SYLLABLE RING +B9C2;B9C2;1105 1175 11BD;B9C2;1105 1175 11BD; # (맂; 맂; 맂; 맂; 맂; ) HANGUL SYLLABLE RIJ +B9C3;B9C3;1105 1175 11BE;B9C3;1105 1175 11BE; # (맃; 맃; 맃; 맃; 맃; ) HANGUL SYLLABLE RIC +B9C4;B9C4;1105 1175 11BF;B9C4;1105 1175 11BF; # (맄; 맄; 맄; 맄; 맄; ) HANGUL SYLLABLE RIK +B9C5;B9C5;1105 1175 11C0;B9C5;1105 1175 11C0; # (맅; 맅; 맅; 맅; 맅; ) HANGUL SYLLABLE RIT +B9C6;B9C6;1105 1175 11C1;B9C6;1105 1175 11C1; # (맆; 맆; 맆; 맆; 맆; ) HANGUL SYLLABLE RIP +B9C7;B9C7;1105 1175 11C2;B9C7;1105 1175 11C2; # (맇; 맇; 맇; 맇; 맇; ) HANGUL SYLLABLE RIH +B9C8;B9C8;1106 1161;B9C8;1106 1161; # (마; 마; 마; 마; 마; ) HANGUL SYLLABLE MA +B9C9;B9C9;1106 1161 11A8;B9C9;1106 1161 11A8; # (막; 막; 막; 막; 막; ) HANGUL SYLLABLE MAG +B9CA;B9CA;1106 1161 11A9;B9CA;1106 1161 11A9; # (맊; 맊; 맊; 맊; 맊; ) HANGUL SYLLABLE MAGG +B9CB;B9CB;1106 1161 11AA;B9CB;1106 1161 11AA; # (맋; 맋; 맋; 맋; 맋; ) HANGUL SYLLABLE MAGS +B9CC;B9CC;1106 1161 11AB;B9CC;1106 1161 11AB; # (만; 만; 만; 만; 만; ) HANGUL SYLLABLE MAN +B9CD;B9CD;1106 1161 11AC;B9CD;1106 1161 11AC; # (맍; 맍; 맍; 맍; 맍; ) HANGUL SYLLABLE MANJ +B9CE;B9CE;1106 1161 11AD;B9CE;1106 1161 11AD; # (많; 많; 많; 많; 많; ) HANGUL SYLLABLE MANH +B9CF;B9CF;1106 1161 11AE;B9CF;1106 1161 11AE; # (맏; 맏; 맏; 맏; 맏; ) HANGUL SYLLABLE MAD +B9D0;B9D0;1106 1161 11AF;B9D0;1106 1161 11AF; # (말; 말; 말; 말; 말; ) HANGUL SYLLABLE MAL +B9D1;B9D1;1106 1161 11B0;B9D1;1106 1161 11B0; # (맑; 맑; 맑; 맑; 맑; ) HANGUL SYLLABLE MALG +B9D2;B9D2;1106 1161 11B1;B9D2;1106 1161 11B1; # (맒; 맒; 맒; 맒; 맒; ) HANGUL SYLLABLE MALM +B9D3;B9D3;1106 1161 11B2;B9D3;1106 1161 11B2; # (맓; 맓; 맓; 맓; 맓; ) HANGUL SYLLABLE MALB +B9D4;B9D4;1106 1161 11B3;B9D4;1106 1161 11B3; # (맔; 맔; 맔; 맔; 맔; ) HANGUL SYLLABLE MALS +B9D5;B9D5;1106 1161 11B4;B9D5;1106 1161 11B4; # (맕; 맕; 맕; 맕; 맕; ) HANGUL SYLLABLE MALT +B9D6;B9D6;1106 1161 11B5;B9D6;1106 1161 11B5; # (맖; 맖; 맖; 맖; 맖; ) HANGUL SYLLABLE MALP +B9D7;B9D7;1106 1161 11B6;B9D7;1106 1161 11B6; # (맗; 맗; 맗; 맗; 맗; ) HANGUL SYLLABLE MALH +B9D8;B9D8;1106 1161 11B7;B9D8;1106 1161 11B7; # (맘; 맘; 맘; 맘; 맘; ) HANGUL SYLLABLE MAM +B9D9;B9D9;1106 1161 11B8;B9D9;1106 1161 11B8; # (맙; 맙; 맙; 맙; 맙; ) HANGUL SYLLABLE MAB +B9DA;B9DA;1106 1161 11B9;B9DA;1106 1161 11B9; # (맚; 맚; 맚; 맚; 맚; ) HANGUL SYLLABLE MABS +B9DB;B9DB;1106 1161 11BA;B9DB;1106 1161 11BA; # (맛; 맛; 맛; 맛; 맛; ) HANGUL SYLLABLE MAS +B9DC;B9DC;1106 1161 11BB;B9DC;1106 1161 11BB; # (맜; 맜; 맜; 맜; 맜; ) HANGUL SYLLABLE MASS +B9DD;B9DD;1106 1161 11BC;B9DD;1106 1161 11BC; # (망; 망; 망; 망; 망; ) HANGUL SYLLABLE MANG +B9DE;B9DE;1106 1161 11BD;B9DE;1106 1161 11BD; # (맞; 맞; 맞; 맞; 맞; ) HANGUL SYLLABLE MAJ +B9DF;B9DF;1106 1161 11BE;B9DF;1106 1161 11BE; # (맟; 맟; 맟; 맟; 맟; ) HANGUL SYLLABLE MAC +B9E0;B9E0;1106 1161 11BF;B9E0;1106 1161 11BF; # (맠; 맠; 맠; 맠; 맠; ) HANGUL SYLLABLE MAK +B9E1;B9E1;1106 1161 11C0;B9E1;1106 1161 11C0; # (맡; 맡; 맡; 맡; 맡; ) HANGUL SYLLABLE MAT +B9E2;B9E2;1106 1161 11C1;B9E2;1106 1161 11C1; # (맢; 맢; 맢; 맢; 맢; ) HANGUL SYLLABLE MAP +B9E3;B9E3;1106 1161 11C2;B9E3;1106 1161 11C2; # (맣; 맣; 맣; 맣; 맣; ) HANGUL SYLLABLE MAH +B9E4;B9E4;1106 1162;B9E4;1106 1162; # (매; 매; 매; 매; 매; ) HANGUL SYLLABLE MAE +B9E5;B9E5;1106 1162 11A8;B9E5;1106 1162 11A8; # (맥; 맥; 맥; 맥; 맥; ) HANGUL SYLLABLE MAEG +B9E6;B9E6;1106 1162 11A9;B9E6;1106 1162 11A9; # (맦; 맦; 맦; 맦; 맦; ) HANGUL SYLLABLE MAEGG +B9E7;B9E7;1106 1162 11AA;B9E7;1106 1162 11AA; # (맧; 맧; 맧; 맧; 맧; ) HANGUL SYLLABLE MAEGS +B9E8;B9E8;1106 1162 11AB;B9E8;1106 1162 11AB; # (맨; 맨; 맨; 맨; 맨; ) HANGUL SYLLABLE MAEN +B9E9;B9E9;1106 1162 11AC;B9E9;1106 1162 11AC; # (맩; 맩; 맩; 맩; 맩; ) HANGUL SYLLABLE MAENJ +B9EA;B9EA;1106 1162 11AD;B9EA;1106 1162 11AD; # (맪; 맪; 맪; 맪; 맪; ) HANGUL SYLLABLE MAENH +B9EB;B9EB;1106 1162 11AE;B9EB;1106 1162 11AE; # (맫; 맫; 맫; 맫; 맫; ) HANGUL SYLLABLE MAED +B9EC;B9EC;1106 1162 11AF;B9EC;1106 1162 11AF; # (맬; 맬; 맬; 맬; 맬; ) HANGUL SYLLABLE MAEL +B9ED;B9ED;1106 1162 11B0;B9ED;1106 1162 11B0; # (맭; 맭; 맭; 맭; 맭; ) HANGUL SYLLABLE MAELG +B9EE;B9EE;1106 1162 11B1;B9EE;1106 1162 11B1; # (맮; 맮; 맮; 맮; 맮; ) HANGUL SYLLABLE MAELM +B9EF;B9EF;1106 1162 11B2;B9EF;1106 1162 11B2; # (맯; 맯; 맯; 맯; 맯; ) HANGUL SYLLABLE MAELB +B9F0;B9F0;1106 1162 11B3;B9F0;1106 1162 11B3; # (맰; 맰; 맰; 맰; 맰; ) HANGUL SYLLABLE MAELS +B9F1;B9F1;1106 1162 11B4;B9F1;1106 1162 11B4; # (맱; 맱; 맱; 맱; 맱; ) HANGUL SYLLABLE MAELT +B9F2;B9F2;1106 1162 11B5;B9F2;1106 1162 11B5; # (맲; 맲; 맲; 맲; 맲; ) HANGUL SYLLABLE MAELP +B9F3;B9F3;1106 1162 11B6;B9F3;1106 1162 11B6; # (맳; 맳; 맳; 맳; 맳; ) HANGUL SYLLABLE MAELH +B9F4;B9F4;1106 1162 11B7;B9F4;1106 1162 11B7; # (맴; 맴; 맴; 맴; 맴; ) HANGUL SYLLABLE MAEM +B9F5;B9F5;1106 1162 11B8;B9F5;1106 1162 11B8; # (맵; 맵; 맵; 맵; 맵; ) HANGUL SYLLABLE MAEB +B9F6;B9F6;1106 1162 11B9;B9F6;1106 1162 11B9; # (맶; 맶; 맶; 맶; 맶; ) HANGUL SYLLABLE MAEBS +B9F7;B9F7;1106 1162 11BA;B9F7;1106 1162 11BA; # (맷; 맷; 맷; 맷; 맷; ) HANGUL SYLLABLE MAES +B9F8;B9F8;1106 1162 11BB;B9F8;1106 1162 11BB; # (맸; 맸; 맸; 맸; 맸; ) HANGUL SYLLABLE MAESS +B9F9;B9F9;1106 1162 11BC;B9F9;1106 1162 11BC; # (맹; 맹; 맹; 맹; 맹; ) HANGUL SYLLABLE MAENG +B9FA;B9FA;1106 1162 11BD;B9FA;1106 1162 11BD; # (맺; 맺; 맺; 맺; 맺; ) HANGUL SYLLABLE MAEJ +B9FB;B9FB;1106 1162 11BE;B9FB;1106 1162 11BE; # (맻; 맻; 맻; 맻; 맻; ) HANGUL SYLLABLE MAEC +B9FC;B9FC;1106 1162 11BF;B9FC;1106 1162 11BF; # (맼; 맼; 맼; 맼; 맼; ) HANGUL SYLLABLE MAEK +B9FD;B9FD;1106 1162 11C0;B9FD;1106 1162 11C0; # (맽; 맽; 맽; 맽; 맽; ) HANGUL SYLLABLE MAET +B9FE;B9FE;1106 1162 11C1;B9FE;1106 1162 11C1; # (맾; 맾; 맾; 맾; 맾; ) HANGUL SYLLABLE MAEP +B9FF;B9FF;1106 1162 11C2;B9FF;1106 1162 11C2; # (맿; 맿; 맿; 맿; 맿; ) HANGUL SYLLABLE MAEH +BA00;BA00;1106 1163;BA00;1106 1163; # (먀; 먀; 먀; 먀; 먀; ) HANGUL SYLLABLE MYA +BA01;BA01;1106 1163 11A8;BA01;1106 1163 11A8; # (먁; 먁; 먁; 먁; 먁; ) HANGUL SYLLABLE MYAG +BA02;BA02;1106 1163 11A9;BA02;1106 1163 11A9; # (먂; 먂; 먂; 먂; 먂; ) HANGUL SYLLABLE MYAGG +BA03;BA03;1106 1163 11AA;BA03;1106 1163 11AA; # (먃; 먃; 먃; 먃; 먃; ) HANGUL SYLLABLE MYAGS +BA04;BA04;1106 1163 11AB;BA04;1106 1163 11AB; # (먄; 먄; 먄; 먄; 먄; ) HANGUL SYLLABLE MYAN +BA05;BA05;1106 1163 11AC;BA05;1106 1163 11AC; # (먅; 먅; 먅; 먅; 먅; ) HANGUL SYLLABLE MYANJ +BA06;BA06;1106 1163 11AD;BA06;1106 1163 11AD; # (먆; 먆; 먆; 먆; 먆; ) HANGUL SYLLABLE MYANH +BA07;BA07;1106 1163 11AE;BA07;1106 1163 11AE; # (먇; 먇; 먇; 먇; 먇; ) HANGUL SYLLABLE MYAD +BA08;BA08;1106 1163 11AF;BA08;1106 1163 11AF; # (먈; 먈; 먈; 먈; 먈; ) HANGUL SYLLABLE MYAL +BA09;BA09;1106 1163 11B0;BA09;1106 1163 11B0; # (먉; 먉; 먉; 먉; 먉; ) HANGUL SYLLABLE MYALG +BA0A;BA0A;1106 1163 11B1;BA0A;1106 1163 11B1; # (먊; 먊; 먊; 먊; 먊; ) HANGUL SYLLABLE MYALM +BA0B;BA0B;1106 1163 11B2;BA0B;1106 1163 11B2; # (먋; 먋; 먋; 먋; 먋; ) HANGUL SYLLABLE MYALB +BA0C;BA0C;1106 1163 11B3;BA0C;1106 1163 11B3; # (먌; 먌; 먌; 먌; 먌; ) HANGUL SYLLABLE MYALS +BA0D;BA0D;1106 1163 11B4;BA0D;1106 1163 11B4; # (먍; 먍; 먍; 먍; 먍; ) HANGUL SYLLABLE MYALT +BA0E;BA0E;1106 1163 11B5;BA0E;1106 1163 11B5; # (먎; 먎; 먎; 먎; 먎; ) HANGUL SYLLABLE MYALP +BA0F;BA0F;1106 1163 11B6;BA0F;1106 1163 11B6; # (먏; 먏; 먏; 먏; 먏; ) HANGUL SYLLABLE MYALH +BA10;BA10;1106 1163 11B7;BA10;1106 1163 11B7; # (먐; 먐; 먐; 먐; 먐; ) HANGUL SYLLABLE MYAM +BA11;BA11;1106 1163 11B8;BA11;1106 1163 11B8; # (먑; 먑; 먑; 먑; 먑; ) HANGUL SYLLABLE MYAB +BA12;BA12;1106 1163 11B9;BA12;1106 1163 11B9; # (먒; 먒; 먒; 먒; 먒; ) HANGUL SYLLABLE MYABS +BA13;BA13;1106 1163 11BA;BA13;1106 1163 11BA; # (먓; 먓; 먓; 먓; 먓; ) HANGUL SYLLABLE MYAS +BA14;BA14;1106 1163 11BB;BA14;1106 1163 11BB; # (먔; 먔; 먔; 먔; 먔; ) HANGUL SYLLABLE MYASS +BA15;BA15;1106 1163 11BC;BA15;1106 1163 11BC; # (먕; 먕; 먕; 먕; 먕; ) HANGUL SYLLABLE MYANG +BA16;BA16;1106 1163 11BD;BA16;1106 1163 11BD; # (먖; 먖; 먖; 먖; 먖; ) HANGUL SYLLABLE MYAJ +BA17;BA17;1106 1163 11BE;BA17;1106 1163 11BE; # (먗; 먗; 먗; 먗; 먗; ) HANGUL SYLLABLE MYAC +BA18;BA18;1106 1163 11BF;BA18;1106 1163 11BF; # (먘; 먘; 먘; 먘; 먘; ) HANGUL SYLLABLE MYAK +BA19;BA19;1106 1163 11C0;BA19;1106 1163 11C0; # (먙; 먙; 먙; 먙; 먙; ) HANGUL SYLLABLE MYAT +BA1A;BA1A;1106 1163 11C1;BA1A;1106 1163 11C1; # (먚; 먚; 먚; 먚; 먚; ) HANGUL SYLLABLE MYAP +BA1B;BA1B;1106 1163 11C2;BA1B;1106 1163 11C2; # (먛; 먛; 먛; 먛; 먛; ) HANGUL SYLLABLE MYAH +BA1C;BA1C;1106 1164;BA1C;1106 1164; # (먜; 먜; 먜; 먜; 먜; ) HANGUL SYLLABLE MYAE +BA1D;BA1D;1106 1164 11A8;BA1D;1106 1164 11A8; # (먝; 먝; 먝; 먝; 먝; ) HANGUL SYLLABLE MYAEG +BA1E;BA1E;1106 1164 11A9;BA1E;1106 1164 11A9; # (먞; 먞; 먞; 먞; 먞; ) HANGUL SYLLABLE MYAEGG +BA1F;BA1F;1106 1164 11AA;BA1F;1106 1164 11AA; # (먟; 먟; 먟; 먟; 먟; ) HANGUL SYLLABLE MYAEGS +BA20;BA20;1106 1164 11AB;BA20;1106 1164 11AB; # (먠; 먠; 먠; 먠; 먠; ) HANGUL SYLLABLE MYAEN +BA21;BA21;1106 1164 11AC;BA21;1106 1164 11AC; # (먡; 먡; 먡; 먡; 먡; ) HANGUL SYLLABLE MYAENJ +BA22;BA22;1106 1164 11AD;BA22;1106 1164 11AD; # (먢; 먢; 먢; 먢; 먢; ) HANGUL SYLLABLE MYAENH +BA23;BA23;1106 1164 11AE;BA23;1106 1164 11AE; # (먣; 먣; 먣; 먣; 먣; ) HANGUL SYLLABLE MYAED +BA24;BA24;1106 1164 11AF;BA24;1106 1164 11AF; # (먤; 먤; 먤; 먤; 먤; ) HANGUL SYLLABLE MYAEL +BA25;BA25;1106 1164 11B0;BA25;1106 1164 11B0; # (먥; 먥; 먥; 먥; 먥; ) HANGUL SYLLABLE MYAELG +BA26;BA26;1106 1164 11B1;BA26;1106 1164 11B1; # (먦; 먦; 먦; 먦; 먦; ) HANGUL SYLLABLE MYAELM +BA27;BA27;1106 1164 11B2;BA27;1106 1164 11B2; # (먧; 먧; 먧; 먧; 먧; ) HANGUL SYLLABLE MYAELB +BA28;BA28;1106 1164 11B3;BA28;1106 1164 11B3; # (먨; 먨; 먨; 먨; 먨; ) HANGUL SYLLABLE MYAELS +BA29;BA29;1106 1164 11B4;BA29;1106 1164 11B4; # (먩; 먩; 먩; 먩; 먩; ) HANGUL SYLLABLE MYAELT +BA2A;BA2A;1106 1164 11B5;BA2A;1106 1164 11B5; # (먪; 먪; 먪; 먪; 먪; ) HANGUL SYLLABLE MYAELP +BA2B;BA2B;1106 1164 11B6;BA2B;1106 1164 11B6; # (먫; 먫; 먫; 먫; 먫; ) HANGUL SYLLABLE MYAELH +BA2C;BA2C;1106 1164 11B7;BA2C;1106 1164 11B7; # (먬; 먬; 먬; 먬; 먬; ) HANGUL SYLLABLE MYAEM +BA2D;BA2D;1106 1164 11B8;BA2D;1106 1164 11B8; # (먭; 먭; 먭; 먭; 먭; ) HANGUL SYLLABLE MYAEB +BA2E;BA2E;1106 1164 11B9;BA2E;1106 1164 11B9; # (먮; 먮; 먮; 먮; 먮; ) HANGUL SYLLABLE MYAEBS +BA2F;BA2F;1106 1164 11BA;BA2F;1106 1164 11BA; # (먯; 먯; 먯; 먯; 먯; ) HANGUL SYLLABLE MYAES +BA30;BA30;1106 1164 11BB;BA30;1106 1164 11BB; # (먰; 먰; 먰; 먰; 먰; ) HANGUL SYLLABLE MYAESS +BA31;BA31;1106 1164 11BC;BA31;1106 1164 11BC; # (먱; 먱; 먱; 먱; 먱; ) HANGUL SYLLABLE MYAENG +BA32;BA32;1106 1164 11BD;BA32;1106 1164 11BD; # (먲; 먲; 먲; 먲; 먲; ) HANGUL SYLLABLE MYAEJ +BA33;BA33;1106 1164 11BE;BA33;1106 1164 11BE; # (먳; 먳; 먳; 먳; 먳; ) HANGUL SYLLABLE MYAEC +BA34;BA34;1106 1164 11BF;BA34;1106 1164 11BF; # (먴; 먴; 먴; 먴; 먴; ) HANGUL SYLLABLE MYAEK +BA35;BA35;1106 1164 11C0;BA35;1106 1164 11C0; # (먵; 먵; 먵; 먵; 먵; ) HANGUL SYLLABLE MYAET +BA36;BA36;1106 1164 11C1;BA36;1106 1164 11C1; # (먶; 먶; 먶; 먶; 먶; ) HANGUL SYLLABLE MYAEP +BA37;BA37;1106 1164 11C2;BA37;1106 1164 11C2; # (먷; 먷; 먷; 먷; 먷; ) HANGUL SYLLABLE MYAEH +BA38;BA38;1106 1165;BA38;1106 1165; # (머; 머; 머; 머; 머; ) HANGUL SYLLABLE MEO +BA39;BA39;1106 1165 11A8;BA39;1106 1165 11A8; # (먹; 먹; 먹; 먹; 먹; ) HANGUL SYLLABLE MEOG +BA3A;BA3A;1106 1165 11A9;BA3A;1106 1165 11A9; # (먺; 먺; 먺; 먺; 먺; ) HANGUL SYLLABLE MEOGG +BA3B;BA3B;1106 1165 11AA;BA3B;1106 1165 11AA; # (먻; 먻; 먻; 먻; 먻; ) HANGUL SYLLABLE MEOGS +BA3C;BA3C;1106 1165 11AB;BA3C;1106 1165 11AB; # (먼; 먼; 먼; 먼; 먼; ) HANGUL SYLLABLE MEON +BA3D;BA3D;1106 1165 11AC;BA3D;1106 1165 11AC; # (먽; 먽; 먽; 먽; 먽; ) HANGUL SYLLABLE MEONJ +BA3E;BA3E;1106 1165 11AD;BA3E;1106 1165 11AD; # (먾; 먾; 먾; 먾; 먾; ) HANGUL SYLLABLE MEONH +BA3F;BA3F;1106 1165 11AE;BA3F;1106 1165 11AE; # (먿; 먿; 먿; 먿; 먿; ) HANGUL SYLLABLE MEOD +BA40;BA40;1106 1165 11AF;BA40;1106 1165 11AF; # (멀; 멀; 멀; 멀; 멀; ) HANGUL SYLLABLE MEOL +BA41;BA41;1106 1165 11B0;BA41;1106 1165 11B0; # (멁; 멁; 멁; 멁; 멁; ) HANGUL SYLLABLE MEOLG +BA42;BA42;1106 1165 11B1;BA42;1106 1165 11B1; # (멂; 멂; 멂; 멂; 멂; ) HANGUL SYLLABLE MEOLM +BA43;BA43;1106 1165 11B2;BA43;1106 1165 11B2; # (멃; 멃; 멃; 멃; 멃; ) HANGUL SYLLABLE MEOLB +BA44;BA44;1106 1165 11B3;BA44;1106 1165 11B3; # (멄; 멄; 멄; 멄; 멄; ) HANGUL SYLLABLE MEOLS +BA45;BA45;1106 1165 11B4;BA45;1106 1165 11B4; # (멅; 멅; 멅; 멅; 멅; ) HANGUL SYLLABLE MEOLT +BA46;BA46;1106 1165 11B5;BA46;1106 1165 11B5; # (멆; 멆; 멆; 멆; 멆; ) HANGUL SYLLABLE MEOLP +BA47;BA47;1106 1165 11B6;BA47;1106 1165 11B6; # (멇; 멇; 멇; 멇; 멇; ) HANGUL SYLLABLE MEOLH +BA48;BA48;1106 1165 11B7;BA48;1106 1165 11B7; # (멈; 멈; 멈; 멈; 멈; ) HANGUL SYLLABLE MEOM +BA49;BA49;1106 1165 11B8;BA49;1106 1165 11B8; # (멉; 멉; 멉; 멉; 멉; ) HANGUL SYLLABLE MEOB +BA4A;BA4A;1106 1165 11B9;BA4A;1106 1165 11B9; # (멊; 멊; 멊; 멊; 멊; ) HANGUL SYLLABLE MEOBS +BA4B;BA4B;1106 1165 11BA;BA4B;1106 1165 11BA; # (멋; 멋; 멋; 멋; 멋; ) HANGUL SYLLABLE MEOS +BA4C;BA4C;1106 1165 11BB;BA4C;1106 1165 11BB; # (멌; 멌; 멌; 멌; 멌; ) HANGUL SYLLABLE MEOSS +BA4D;BA4D;1106 1165 11BC;BA4D;1106 1165 11BC; # (멍; 멍; 멍; 멍; 멍; ) HANGUL SYLLABLE MEONG +BA4E;BA4E;1106 1165 11BD;BA4E;1106 1165 11BD; # (멎; 멎; 멎; 멎; 멎; ) HANGUL SYLLABLE MEOJ +BA4F;BA4F;1106 1165 11BE;BA4F;1106 1165 11BE; # (멏; 멏; 멏; 멏; 멏; ) HANGUL SYLLABLE MEOC +BA50;BA50;1106 1165 11BF;BA50;1106 1165 11BF; # (멐; 멐; 멐; 멐; 멐; ) HANGUL SYLLABLE MEOK +BA51;BA51;1106 1165 11C0;BA51;1106 1165 11C0; # (멑; 멑; 멑; 멑; 멑; ) HANGUL SYLLABLE MEOT +BA52;BA52;1106 1165 11C1;BA52;1106 1165 11C1; # (멒; 멒; 멒; 멒; 멒; ) HANGUL SYLLABLE MEOP +BA53;BA53;1106 1165 11C2;BA53;1106 1165 11C2; # (멓; 멓; 멓; 멓; 멓; ) HANGUL SYLLABLE MEOH +BA54;BA54;1106 1166;BA54;1106 1166; # (메; 메; 메; 메; 메; ) HANGUL SYLLABLE ME +BA55;BA55;1106 1166 11A8;BA55;1106 1166 11A8; # (멕; 멕; 멕; 멕; 멕; ) HANGUL SYLLABLE MEG +BA56;BA56;1106 1166 11A9;BA56;1106 1166 11A9; # (멖; 멖; 멖; 멖; 멖; ) HANGUL SYLLABLE MEGG +BA57;BA57;1106 1166 11AA;BA57;1106 1166 11AA; # (멗; 멗; 멗; 멗; 멗; ) HANGUL SYLLABLE MEGS +BA58;BA58;1106 1166 11AB;BA58;1106 1166 11AB; # (멘; 멘; 멘; 멘; 멘; ) HANGUL SYLLABLE MEN +BA59;BA59;1106 1166 11AC;BA59;1106 1166 11AC; # (멙; 멙; 멙; 멙; 멙; ) HANGUL SYLLABLE MENJ +BA5A;BA5A;1106 1166 11AD;BA5A;1106 1166 11AD; # (멚; 멚; 멚; 멚; 멚; ) HANGUL SYLLABLE MENH +BA5B;BA5B;1106 1166 11AE;BA5B;1106 1166 11AE; # (멛; 멛; 멛; 멛; 멛; ) HANGUL SYLLABLE MED +BA5C;BA5C;1106 1166 11AF;BA5C;1106 1166 11AF; # (멜; 멜; 멜; 멜; 멜; ) HANGUL SYLLABLE MEL +BA5D;BA5D;1106 1166 11B0;BA5D;1106 1166 11B0; # (멝; 멝; 멝; 멝; 멝; ) HANGUL SYLLABLE MELG +BA5E;BA5E;1106 1166 11B1;BA5E;1106 1166 11B1; # (멞; 멞; 멞; 멞; 멞; ) HANGUL SYLLABLE MELM +BA5F;BA5F;1106 1166 11B2;BA5F;1106 1166 11B2; # (멟; 멟; 멟; 멟; 멟; ) HANGUL SYLLABLE MELB +BA60;BA60;1106 1166 11B3;BA60;1106 1166 11B3; # (멠; 멠; 멠; 멠; 멠; ) HANGUL SYLLABLE MELS +BA61;BA61;1106 1166 11B4;BA61;1106 1166 11B4; # (멡; 멡; 멡; 멡; 멡; ) HANGUL SYLLABLE MELT +BA62;BA62;1106 1166 11B5;BA62;1106 1166 11B5; # (멢; 멢; 멢; 멢; 멢; ) HANGUL SYLLABLE MELP +BA63;BA63;1106 1166 11B6;BA63;1106 1166 11B6; # (멣; 멣; 멣; 멣; 멣; ) HANGUL SYLLABLE MELH +BA64;BA64;1106 1166 11B7;BA64;1106 1166 11B7; # (멤; 멤; 멤; 멤; 멤; ) HANGUL SYLLABLE MEM +BA65;BA65;1106 1166 11B8;BA65;1106 1166 11B8; # (멥; 멥; 멥; 멥; 멥; ) HANGUL SYLLABLE MEB +BA66;BA66;1106 1166 11B9;BA66;1106 1166 11B9; # (멦; 멦; 멦; 멦; 멦; ) HANGUL SYLLABLE MEBS +BA67;BA67;1106 1166 11BA;BA67;1106 1166 11BA; # (멧; 멧; 멧; 멧; 멧; ) HANGUL SYLLABLE MES +BA68;BA68;1106 1166 11BB;BA68;1106 1166 11BB; # (멨; 멨; 멨; 멨; 멨; ) HANGUL SYLLABLE MESS +BA69;BA69;1106 1166 11BC;BA69;1106 1166 11BC; # (멩; 멩; 멩; 멩; 멩; ) HANGUL SYLLABLE MENG +BA6A;BA6A;1106 1166 11BD;BA6A;1106 1166 11BD; # (멪; 멪; 멪; 멪; 멪; ) HANGUL SYLLABLE MEJ +BA6B;BA6B;1106 1166 11BE;BA6B;1106 1166 11BE; # (멫; 멫; 멫; 멫; 멫; ) HANGUL SYLLABLE MEC +BA6C;BA6C;1106 1166 11BF;BA6C;1106 1166 11BF; # (멬; 멬; 멬; 멬; 멬; ) HANGUL SYLLABLE MEK +BA6D;BA6D;1106 1166 11C0;BA6D;1106 1166 11C0; # (멭; 멭; 멭; 멭; 멭; ) HANGUL SYLLABLE MET +BA6E;BA6E;1106 1166 11C1;BA6E;1106 1166 11C1; # (멮; 멮; 멮; 멮; 멮; ) HANGUL SYLLABLE MEP +BA6F;BA6F;1106 1166 11C2;BA6F;1106 1166 11C2; # (멯; 멯; 멯; 멯; 멯; ) HANGUL SYLLABLE MEH +BA70;BA70;1106 1167;BA70;1106 1167; # (며; 며; 며; 며; 며; ) HANGUL SYLLABLE MYEO +BA71;BA71;1106 1167 11A8;BA71;1106 1167 11A8; # (멱; 멱; 멱; 멱; 멱; ) HANGUL SYLLABLE MYEOG +BA72;BA72;1106 1167 11A9;BA72;1106 1167 11A9; # (멲; 멲; 멲; 멲; 멲; ) HANGUL SYLLABLE MYEOGG +BA73;BA73;1106 1167 11AA;BA73;1106 1167 11AA; # (멳; 멳; 멳; 멳; 멳; ) HANGUL SYLLABLE MYEOGS +BA74;BA74;1106 1167 11AB;BA74;1106 1167 11AB; # (면; 면; 면; 면; 면; ) HANGUL SYLLABLE MYEON +BA75;BA75;1106 1167 11AC;BA75;1106 1167 11AC; # (멵; 멵; 멵; 멵; 멵; ) HANGUL SYLLABLE MYEONJ +BA76;BA76;1106 1167 11AD;BA76;1106 1167 11AD; # (멶; 멶; 멶; 멶; 멶; ) HANGUL SYLLABLE MYEONH +BA77;BA77;1106 1167 11AE;BA77;1106 1167 11AE; # (멷; 멷; 멷; 멷; 멷; ) HANGUL SYLLABLE MYEOD +BA78;BA78;1106 1167 11AF;BA78;1106 1167 11AF; # (멸; 멸; 멸; 멸; 멸; ) HANGUL SYLLABLE MYEOL +BA79;BA79;1106 1167 11B0;BA79;1106 1167 11B0; # (멹; 멹; 멹; 멹; 멹; ) HANGUL SYLLABLE MYEOLG +BA7A;BA7A;1106 1167 11B1;BA7A;1106 1167 11B1; # (멺; 멺; 멺; 멺; 멺; ) HANGUL SYLLABLE MYEOLM +BA7B;BA7B;1106 1167 11B2;BA7B;1106 1167 11B2; # (멻; 멻; 멻; 멻; 멻; ) HANGUL SYLLABLE MYEOLB +BA7C;BA7C;1106 1167 11B3;BA7C;1106 1167 11B3; # (멼; 멼; 멼; 멼; 멼; ) HANGUL SYLLABLE MYEOLS +BA7D;BA7D;1106 1167 11B4;BA7D;1106 1167 11B4; # (멽; 멽; 멽; 멽; 멽; ) HANGUL SYLLABLE MYEOLT +BA7E;BA7E;1106 1167 11B5;BA7E;1106 1167 11B5; # (멾; 멾; 멾; 멾; 멾; ) HANGUL SYLLABLE MYEOLP +BA7F;BA7F;1106 1167 11B6;BA7F;1106 1167 11B6; # (멿; 멿; 멿; 멿; 멿; ) HANGUL SYLLABLE MYEOLH +BA80;BA80;1106 1167 11B7;BA80;1106 1167 11B7; # (몀; 몀; 몀; 몀; 몀; ) HANGUL SYLLABLE MYEOM +BA81;BA81;1106 1167 11B8;BA81;1106 1167 11B8; # (몁; 몁; 몁; 몁; 몁; ) HANGUL SYLLABLE MYEOB +BA82;BA82;1106 1167 11B9;BA82;1106 1167 11B9; # (몂; 몂; 몂; 몂; 몂; ) HANGUL SYLLABLE MYEOBS +BA83;BA83;1106 1167 11BA;BA83;1106 1167 11BA; # (몃; 몃; 몃; 몃; 몃; ) HANGUL SYLLABLE MYEOS +BA84;BA84;1106 1167 11BB;BA84;1106 1167 11BB; # (몄; 몄; 몄; 몄; 몄; ) HANGUL SYLLABLE MYEOSS +BA85;BA85;1106 1167 11BC;BA85;1106 1167 11BC; # (명; 명; 명; 명; 명; ) HANGUL SYLLABLE MYEONG +BA86;BA86;1106 1167 11BD;BA86;1106 1167 11BD; # (몆; 몆; 몆; 몆; 몆; ) HANGUL SYLLABLE MYEOJ +BA87;BA87;1106 1167 11BE;BA87;1106 1167 11BE; # (몇; 몇; 몇; 몇; 몇; ) HANGUL SYLLABLE MYEOC +BA88;BA88;1106 1167 11BF;BA88;1106 1167 11BF; # (몈; 몈; 몈; 몈; 몈; ) HANGUL SYLLABLE MYEOK +BA89;BA89;1106 1167 11C0;BA89;1106 1167 11C0; # (몉; 몉; 몉; 몉; 몉; ) HANGUL SYLLABLE MYEOT +BA8A;BA8A;1106 1167 11C1;BA8A;1106 1167 11C1; # (몊; 몊; 몊; 몊; 몊; ) HANGUL SYLLABLE MYEOP +BA8B;BA8B;1106 1167 11C2;BA8B;1106 1167 11C2; # (몋; 몋; 몋; 몋; 몋; ) HANGUL SYLLABLE MYEOH +BA8C;BA8C;1106 1168;BA8C;1106 1168; # (몌; 몌; 몌; 몌; 몌; ) HANGUL SYLLABLE MYE +BA8D;BA8D;1106 1168 11A8;BA8D;1106 1168 11A8; # (몍; 몍; 몍; 몍; 몍; ) HANGUL SYLLABLE MYEG +BA8E;BA8E;1106 1168 11A9;BA8E;1106 1168 11A9; # (몎; 몎; 몎; 몎; 몎; ) HANGUL SYLLABLE MYEGG +BA8F;BA8F;1106 1168 11AA;BA8F;1106 1168 11AA; # (몏; 몏; 몏; 몏; 몏; ) HANGUL SYLLABLE MYEGS +BA90;BA90;1106 1168 11AB;BA90;1106 1168 11AB; # (몐; 몐; 몐; 몐; 몐; ) HANGUL SYLLABLE MYEN +BA91;BA91;1106 1168 11AC;BA91;1106 1168 11AC; # (몑; 몑; 몑; 몑; 몑; ) HANGUL SYLLABLE MYENJ +BA92;BA92;1106 1168 11AD;BA92;1106 1168 11AD; # (몒; 몒; 몒; 몒; 몒; ) HANGUL SYLLABLE MYENH +BA93;BA93;1106 1168 11AE;BA93;1106 1168 11AE; # (몓; 몓; 몓; 몓; 몓; ) HANGUL SYLLABLE MYED +BA94;BA94;1106 1168 11AF;BA94;1106 1168 11AF; # (몔; 몔; 몔; 몔; 몔; ) HANGUL SYLLABLE MYEL +BA95;BA95;1106 1168 11B0;BA95;1106 1168 11B0; # (몕; 몕; 몕; 몕; 몕; ) HANGUL SYLLABLE MYELG +BA96;BA96;1106 1168 11B1;BA96;1106 1168 11B1; # (몖; 몖; 몖; 몖; 몖; ) HANGUL SYLLABLE MYELM +BA97;BA97;1106 1168 11B2;BA97;1106 1168 11B2; # (몗; 몗; 몗; 몗; 몗; ) HANGUL SYLLABLE MYELB +BA98;BA98;1106 1168 11B3;BA98;1106 1168 11B3; # (몘; 몘; 몘; 몘; 몘; ) HANGUL SYLLABLE MYELS +BA99;BA99;1106 1168 11B4;BA99;1106 1168 11B4; # (몙; 몙; 몙; 몙; 몙; ) HANGUL SYLLABLE MYELT +BA9A;BA9A;1106 1168 11B5;BA9A;1106 1168 11B5; # (몚; 몚; 몚; 몚; 몚; ) HANGUL SYLLABLE MYELP +BA9B;BA9B;1106 1168 11B6;BA9B;1106 1168 11B6; # (몛; 몛; 몛; 몛; 몛; ) HANGUL SYLLABLE MYELH +BA9C;BA9C;1106 1168 11B7;BA9C;1106 1168 11B7; # (몜; 몜; 몜; 몜; 몜; ) HANGUL SYLLABLE MYEM +BA9D;BA9D;1106 1168 11B8;BA9D;1106 1168 11B8; # (몝; 몝; 몝; 몝; 몝; ) HANGUL SYLLABLE MYEB +BA9E;BA9E;1106 1168 11B9;BA9E;1106 1168 11B9; # (몞; 몞; 몞; 몞; 몞; ) HANGUL SYLLABLE MYEBS +BA9F;BA9F;1106 1168 11BA;BA9F;1106 1168 11BA; # (몟; 몟; 몟; 몟; 몟; ) HANGUL SYLLABLE MYES +BAA0;BAA0;1106 1168 11BB;BAA0;1106 1168 11BB; # (몠; 몠; 몠; 몠; 몠; ) HANGUL SYLLABLE MYESS +BAA1;BAA1;1106 1168 11BC;BAA1;1106 1168 11BC; # (몡; 몡; 몡; 몡; 몡; ) HANGUL SYLLABLE MYENG +BAA2;BAA2;1106 1168 11BD;BAA2;1106 1168 11BD; # (몢; 몢; 몢; 몢; 몢; ) HANGUL SYLLABLE MYEJ +BAA3;BAA3;1106 1168 11BE;BAA3;1106 1168 11BE; # (몣; 몣; 몣; 몣; 몣; ) HANGUL SYLLABLE MYEC +BAA4;BAA4;1106 1168 11BF;BAA4;1106 1168 11BF; # (몤; 몤; 몤; 몤; 몤; ) HANGUL SYLLABLE MYEK +BAA5;BAA5;1106 1168 11C0;BAA5;1106 1168 11C0; # (몥; 몥; 몥; 몥; 몥; ) HANGUL SYLLABLE MYET +BAA6;BAA6;1106 1168 11C1;BAA6;1106 1168 11C1; # (몦; 몦; 몦; 몦; 몦; ) HANGUL SYLLABLE MYEP +BAA7;BAA7;1106 1168 11C2;BAA7;1106 1168 11C2; # (몧; 몧; 몧; 몧; 몧; ) HANGUL SYLLABLE MYEH +BAA8;BAA8;1106 1169;BAA8;1106 1169; # (모; 모; 모; 모; 모; ) HANGUL SYLLABLE MO +BAA9;BAA9;1106 1169 11A8;BAA9;1106 1169 11A8; # (목; 목; 목; 목; 목; ) HANGUL SYLLABLE MOG +BAAA;BAAA;1106 1169 11A9;BAAA;1106 1169 11A9; # (몪; 몪; 몪; 몪; 몪; ) HANGUL SYLLABLE MOGG +BAAB;BAAB;1106 1169 11AA;BAAB;1106 1169 11AA; # (몫; 몫; 몫; 몫; 몫; ) HANGUL SYLLABLE MOGS +BAAC;BAAC;1106 1169 11AB;BAAC;1106 1169 11AB; # (몬; 몬; 몬; 몬; 몬; ) HANGUL SYLLABLE MON +BAAD;BAAD;1106 1169 11AC;BAAD;1106 1169 11AC; # (몭; 몭; 몭; 몭; 몭; ) HANGUL SYLLABLE MONJ +BAAE;BAAE;1106 1169 11AD;BAAE;1106 1169 11AD; # (몮; 몮; 몮; 몮; 몮; ) HANGUL SYLLABLE MONH +BAAF;BAAF;1106 1169 11AE;BAAF;1106 1169 11AE; # (몯; 몯; 몯; 몯; 몯; ) HANGUL SYLLABLE MOD +BAB0;BAB0;1106 1169 11AF;BAB0;1106 1169 11AF; # (몰; 몰; 몰; 몰; 몰; ) HANGUL SYLLABLE MOL +BAB1;BAB1;1106 1169 11B0;BAB1;1106 1169 11B0; # (몱; 몱; 몱; 몱; 몱; ) HANGUL SYLLABLE MOLG +BAB2;BAB2;1106 1169 11B1;BAB2;1106 1169 11B1; # (몲; 몲; 몲; 몲; 몲; ) HANGUL SYLLABLE MOLM +BAB3;BAB3;1106 1169 11B2;BAB3;1106 1169 11B2; # (몳; 몳; 몳; 몳; 몳; ) HANGUL SYLLABLE MOLB +BAB4;BAB4;1106 1169 11B3;BAB4;1106 1169 11B3; # (몴; 몴; 몴; 몴; 몴; ) HANGUL SYLLABLE MOLS +BAB5;BAB5;1106 1169 11B4;BAB5;1106 1169 11B4; # (몵; 몵; 몵; 몵; 몵; ) HANGUL SYLLABLE MOLT +BAB6;BAB6;1106 1169 11B5;BAB6;1106 1169 11B5; # (몶; 몶; 몶; 몶; 몶; ) HANGUL SYLLABLE MOLP +BAB7;BAB7;1106 1169 11B6;BAB7;1106 1169 11B6; # (몷; 몷; 몷; 몷; 몷; ) HANGUL SYLLABLE MOLH +BAB8;BAB8;1106 1169 11B7;BAB8;1106 1169 11B7; # (몸; 몸; 몸; 몸; 몸; ) HANGUL SYLLABLE MOM +BAB9;BAB9;1106 1169 11B8;BAB9;1106 1169 11B8; # (몹; 몹; 몹; 몹; 몹; ) HANGUL SYLLABLE MOB +BABA;BABA;1106 1169 11B9;BABA;1106 1169 11B9; # (몺; 몺; 몺; 몺; 몺; ) HANGUL SYLLABLE MOBS +BABB;BABB;1106 1169 11BA;BABB;1106 1169 11BA; # (못; 못; 못; 못; 못; ) HANGUL SYLLABLE MOS +BABC;BABC;1106 1169 11BB;BABC;1106 1169 11BB; # (몼; 몼; 몼; 몼; 몼; ) HANGUL SYLLABLE MOSS +BABD;BABD;1106 1169 11BC;BABD;1106 1169 11BC; # (몽; 몽; 몽; 몽; 몽; ) HANGUL SYLLABLE MONG +BABE;BABE;1106 1169 11BD;BABE;1106 1169 11BD; # (몾; 몾; 몾; 몾; 몾; ) HANGUL SYLLABLE MOJ +BABF;BABF;1106 1169 11BE;BABF;1106 1169 11BE; # (몿; 몿; 몿; 몿; 몿; ) HANGUL SYLLABLE MOC +BAC0;BAC0;1106 1169 11BF;BAC0;1106 1169 11BF; # (뫀; 뫀; 뫀; 뫀; 뫀; ) HANGUL SYLLABLE MOK +BAC1;BAC1;1106 1169 11C0;BAC1;1106 1169 11C0; # (뫁; 뫁; 뫁; 뫁; 뫁; ) HANGUL SYLLABLE MOT +BAC2;BAC2;1106 1169 11C1;BAC2;1106 1169 11C1; # (뫂; 뫂; 뫂; 뫂; 뫂; ) HANGUL SYLLABLE MOP +BAC3;BAC3;1106 1169 11C2;BAC3;1106 1169 11C2; # (뫃; 뫃; 뫃; 뫃; 뫃; ) HANGUL SYLLABLE MOH +BAC4;BAC4;1106 116A;BAC4;1106 116A; # (뫄; 뫄; 뫄; 뫄; 뫄; ) HANGUL SYLLABLE MWA +BAC5;BAC5;1106 116A 11A8;BAC5;1106 116A 11A8; # (뫅; 뫅; 뫅; 뫅; 뫅; ) HANGUL SYLLABLE MWAG +BAC6;BAC6;1106 116A 11A9;BAC6;1106 116A 11A9; # (뫆; 뫆; 뫆; 뫆; 뫆; ) HANGUL SYLLABLE MWAGG +BAC7;BAC7;1106 116A 11AA;BAC7;1106 116A 11AA; # (뫇; 뫇; 뫇; 뫇; 뫇; ) HANGUL SYLLABLE MWAGS +BAC8;BAC8;1106 116A 11AB;BAC8;1106 116A 11AB; # (뫈; 뫈; 뫈; 뫈; 뫈; ) HANGUL SYLLABLE MWAN +BAC9;BAC9;1106 116A 11AC;BAC9;1106 116A 11AC; # (뫉; 뫉; 뫉; 뫉; 뫉; ) HANGUL SYLLABLE MWANJ +BACA;BACA;1106 116A 11AD;BACA;1106 116A 11AD; # (뫊; 뫊; 뫊; 뫊; 뫊; ) HANGUL SYLLABLE MWANH +BACB;BACB;1106 116A 11AE;BACB;1106 116A 11AE; # (뫋; 뫋; 뫋; 뫋; 뫋; ) HANGUL SYLLABLE MWAD +BACC;BACC;1106 116A 11AF;BACC;1106 116A 11AF; # (뫌; 뫌; 뫌; 뫌; 뫌; ) HANGUL SYLLABLE MWAL +BACD;BACD;1106 116A 11B0;BACD;1106 116A 11B0; # (뫍; 뫍; 뫍; 뫍; 뫍; ) HANGUL SYLLABLE MWALG +BACE;BACE;1106 116A 11B1;BACE;1106 116A 11B1; # (뫎; 뫎; 뫎; 뫎; 뫎; ) HANGUL SYLLABLE MWALM +BACF;BACF;1106 116A 11B2;BACF;1106 116A 11B2; # (뫏; 뫏; 뫏; 뫏; 뫏; ) HANGUL SYLLABLE MWALB +BAD0;BAD0;1106 116A 11B3;BAD0;1106 116A 11B3; # (뫐; 뫐; 뫐; 뫐; 뫐; ) HANGUL SYLLABLE MWALS +BAD1;BAD1;1106 116A 11B4;BAD1;1106 116A 11B4; # (뫑; 뫑; 뫑; 뫑; 뫑; ) HANGUL SYLLABLE MWALT +BAD2;BAD2;1106 116A 11B5;BAD2;1106 116A 11B5; # (뫒; 뫒; 뫒; 뫒; 뫒; ) HANGUL SYLLABLE MWALP +BAD3;BAD3;1106 116A 11B6;BAD3;1106 116A 11B6; # (뫓; 뫓; 뫓; 뫓; 뫓; ) HANGUL SYLLABLE MWALH +BAD4;BAD4;1106 116A 11B7;BAD4;1106 116A 11B7; # (뫔; 뫔; 뫔; 뫔; 뫔; ) HANGUL SYLLABLE MWAM +BAD5;BAD5;1106 116A 11B8;BAD5;1106 116A 11B8; # (뫕; 뫕; 뫕; 뫕; 뫕; ) HANGUL SYLLABLE MWAB +BAD6;BAD6;1106 116A 11B9;BAD6;1106 116A 11B9; # (뫖; 뫖; 뫖; 뫖; 뫖; ) HANGUL SYLLABLE MWABS +BAD7;BAD7;1106 116A 11BA;BAD7;1106 116A 11BA; # (뫗; 뫗; 뫗; 뫗; 뫗; ) HANGUL SYLLABLE MWAS +BAD8;BAD8;1106 116A 11BB;BAD8;1106 116A 11BB; # (뫘; 뫘; 뫘; 뫘; 뫘; ) HANGUL SYLLABLE MWASS +BAD9;BAD9;1106 116A 11BC;BAD9;1106 116A 11BC; # (뫙; 뫙; 뫙; 뫙; 뫙; ) HANGUL SYLLABLE MWANG +BADA;BADA;1106 116A 11BD;BADA;1106 116A 11BD; # (뫚; 뫚; 뫚; 뫚; 뫚; ) HANGUL SYLLABLE MWAJ +BADB;BADB;1106 116A 11BE;BADB;1106 116A 11BE; # (뫛; 뫛; 뫛; 뫛; 뫛; ) HANGUL SYLLABLE MWAC +BADC;BADC;1106 116A 11BF;BADC;1106 116A 11BF; # (뫜; 뫜; 뫜; 뫜; 뫜; ) HANGUL SYLLABLE MWAK +BADD;BADD;1106 116A 11C0;BADD;1106 116A 11C0; # (뫝; 뫝; 뫝; 뫝; 뫝; ) HANGUL SYLLABLE MWAT +BADE;BADE;1106 116A 11C1;BADE;1106 116A 11C1; # (뫞; 뫞; 뫞; 뫞; 뫞; ) HANGUL SYLLABLE MWAP +BADF;BADF;1106 116A 11C2;BADF;1106 116A 11C2; # (뫟; 뫟; 뫟; 뫟; 뫟; ) HANGUL SYLLABLE MWAH +BAE0;BAE0;1106 116B;BAE0;1106 116B; # (뫠; 뫠; 뫠; 뫠; 뫠; ) HANGUL SYLLABLE MWAE +BAE1;BAE1;1106 116B 11A8;BAE1;1106 116B 11A8; # (뫡; 뫡; 뫡; 뫡; 뫡; ) HANGUL SYLLABLE MWAEG +BAE2;BAE2;1106 116B 11A9;BAE2;1106 116B 11A9; # (뫢; 뫢; 뫢; 뫢; 뫢; ) HANGUL SYLLABLE MWAEGG +BAE3;BAE3;1106 116B 11AA;BAE3;1106 116B 11AA; # (뫣; 뫣; 뫣; 뫣; 뫣; ) HANGUL SYLLABLE MWAEGS +BAE4;BAE4;1106 116B 11AB;BAE4;1106 116B 11AB; # (뫤; 뫤; 뫤; 뫤; 뫤; ) HANGUL SYLLABLE MWAEN +BAE5;BAE5;1106 116B 11AC;BAE5;1106 116B 11AC; # (뫥; 뫥; 뫥; 뫥; 뫥; ) HANGUL SYLLABLE MWAENJ +BAE6;BAE6;1106 116B 11AD;BAE6;1106 116B 11AD; # (뫦; 뫦; 뫦; 뫦; 뫦; ) HANGUL SYLLABLE MWAENH +BAE7;BAE7;1106 116B 11AE;BAE7;1106 116B 11AE; # (뫧; 뫧; 뫧; 뫧; 뫧; ) HANGUL SYLLABLE MWAED +BAE8;BAE8;1106 116B 11AF;BAE8;1106 116B 11AF; # (뫨; 뫨; 뫨; 뫨; 뫨; ) HANGUL SYLLABLE MWAEL +BAE9;BAE9;1106 116B 11B0;BAE9;1106 116B 11B0; # (뫩; 뫩; 뫩; 뫩; 뫩; ) HANGUL SYLLABLE MWAELG +BAEA;BAEA;1106 116B 11B1;BAEA;1106 116B 11B1; # (뫪; 뫪; 뫪; 뫪; 뫪; ) HANGUL SYLLABLE MWAELM +BAEB;BAEB;1106 116B 11B2;BAEB;1106 116B 11B2; # (뫫; 뫫; 뫫; 뫫; 뫫; ) HANGUL SYLLABLE MWAELB +BAEC;BAEC;1106 116B 11B3;BAEC;1106 116B 11B3; # (뫬; 뫬; 뫬; 뫬; 뫬; ) HANGUL SYLLABLE MWAELS +BAED;BAED;1106 116B 11B4;BAED;1106 116B 11B4; # (뫭; 뫭; 뫭; 뫭; 뫭; ) HANGUL SYLLABLE MWAELT +BAEE;BAEE;1106 116B 11B5;BAEE;1106 116B 11B5; # (뫮; 뫮; 뫮; 뫮; 뫮; ) HANGUL SYLLABLE MWAELP +BAEF;BAEF;1106 116B 11B6;BAEF;1106 116B 11B6; # (뫯; 뫯; 뫯; 뫯; 뫯; ) HANGUL SYLLABLE MWAELH +BAF0;BAF0;1106 116B 11B7;BAF0;1106 116B 11B7; # (뫰; 뫰; 뫰; 뫰; 뫰; ) HANGUL SYLLABLE MWAEM +BAF1;BAF1;1106 116B 11B8;BAF1;1106 116B 11B8; # (뫱; 뫱; 뫱; 뫱; 뫱; ) HANGUL SYLLABLE MWAEB +BAF2;BAF2;1106 116B 11B9;BAF2;1106 116B 11B9; # (뫲; 뫲; 뫲; 뫲; 뫲; ) HANGUL SYLLABLE MWAEBS +BAF3;BAF3;1106 116B 11BA;BAF3;1106 116B 11BA; # (뫳; 뫳; 뫳; 뫳; 뫳; ) HANGUL SYLLABLE MWAES +BAF4;BAF4;1106 116B 11BB;BAF4;1106 116B 11BB; # (뫴; 뫴; 뫴; 뫴; 뫴; ) HANGUL SYLLABLE MWAESS +BAF5;BAF5;1106 116B 11BC;BAF5;1106 116B 11BC; # (뫵; 뫵; 뫵; 뫵; 뫵; ) HANGUL SYLLABLE MWAENG +BAF6;BAF6;1106 116B 11BD;BAF6;1106 116B 11BD; # (뫶; 뫶; 뫶; 뫶; 뫶; ) HANGUL SYLLABLE MWAEJ +BAF7;BAF7;1106 116B 11BE;BAF7;1106 116B 11BE; # (뫷; 뫷; 뫷; 뫷; 뫷; ) HANGUL SYLLABLE MWAEC +BAF8;BAF8;1106 116B 11BF;BAF8;1106 116B 11BF; # (뫸; 뫸; 뫸; 뫸; 뫸; ) HANGUL SYLLABLE MWAEK +BAF9;BAF9;1106 116B 11C0;BAF9;1106 116B 11C0; # (뫹; 뫹; 뫹; 뫹; 뫹; ) HANGUL SYLLABLE MWAET +BAFA;BAFA;1106 116B 11C1;BAFA;1106 116B 11C1; # (뫺; 뫺; 뫺; 뫺; 뫺; ) HANGUL SYLLABLE MWAEP +BAFB;BAFB;1106 116B 11C2;BAFB;1106 116B 11C2; # (뫻; 뫻; 뫻; 뫻; 뫻; ) HANGUL SYLLABLE MWAEH +BAFC;BAFC;1106 116C;BAFC;1106 116C; # (뫼; 뫼; 뫼; 뫼; 뫼; ) HANGUL SYLLABLE MOE +BAFD;BAFD;1106 116C 11A8;BAFD;1106 116C 11A8; # (뫽; 뫽; 뫽; 뫽; 뫽; ) HANGUL SYLLABLE MOEG +BAFE;BAFE;1106 116C 11A9;BAFE;1106 116C 11A9; # (뫾; 뫾; 뫾; 뫾; 뫾; ) HANGUL SYLLABLE MOEGG +BAFF;BAFF;1106 116C 11AA;BAFF;1106 116C 11AA; # (뫿; 뫿; 뫿; 뫿; 뫿; ) HANGUL SYLLABLE MOEGS +BB00;BB00;1106 116C 11AB;BB00;1106 116C 11AB; # (묀; 묀; 묀; 묀; 묀; ) HANGUL SYLLABLE MOEN +BB01;BB01;1106 116C 11AC;BB01;1106 116C 11AC; # (묁; 묁; 묁; 묁; 묁; ) HANGUL SYLLABLE MOENJ +BB02;BB02;1106 116C 11AD;BB02;1106 116C 11AD; # (묂; 묂; 묂; 묂; 묂; ) HANGUL SYLLABLE MOENH +BB03;BB03;1106 116C 11AE;BB03;1106 116C 11AE; # (묃; 묃; 묃; 묃; 묃; ) HANGUL SYLLABLE MOED +BB04;BB04;1106 116C 11AF;BB04;1106 116C 11AF; # (묄; 묄; 묄; 묄; 묄; ) HANGUL SYLLABLE MOEL +BB05;BB05;1106 116C 11B0;BB05;1106 116C 11B0; # (묅; 묅; 묅; 묅; 묅; ) HANGUL SYLLABLE MOELG +BB06;BB06;1106 116C 11B1;BB06;1106 116C 11B1; # (묆; 묆; 묆; 묆; 묆; ) HANGUL SYLLABLE MOELM +BB07;BB07;1106 116C 11B2;BB07;1106 116C 11B2; # (묇; 묇; 묇; 묇; 묇; ) HANGUL SYLLABLE MOELB +BB08;BB08;1106 116C 11B3;BB08;1106 116C 11B3; # (묈; 묈; 묈; 묈; 묈; ) HANGUL SYLLABLE MOELS +BB09;BB09;1106 116C 11B4;BB09;1106 116C 11B4; # (묉; 묉; 묉; 묉; 묉; ) HANGUL SYLLABLE MOELT +BB0A;BB0A;1106 116C 11B5;BB0A;1106 116C 11B5; # (묊; 묊; 묊; 묊; 묊; ) HANGUL SYLLABLE MOELP +BB0B;BB0B;1106 116C 11B6;BB0B;1106 116C 11B6; # (묋; 묋; 묋; 묋; 묋; ) HANGUL SYLLABLE MOELH +BB0C;BB0C;1106 116C 11B7;BB0C;1106 116C 11B7; # (묌; 묌; 묌; 묌; 묌; ) HANGUL SYLLABLE MOEM +BB0D;BB0D;1106 116C 11B8;BB0D;1106 116C 11B8; # (묍; 묍; 묍; 묍; 묍; ) HANGUL SYLLABLE MOEB +BB0E;BB0E;1106 116C 11B9;BB0E;1106 116C 11B9; # (묎; 묎; 묎; 묎; 묎; ) HANGUL SYLLABLE MOEBS +BB0F;BB0F;1106 116C 11BA;BB0F;1106 116C 11BA; # (묏; 묏; 묏; 묏; 묏; ) HANGUL SYLLABLE MOES +BB10;BB10;1106 116C 11BB;BB10;1106 116C 11BB; # (묐; 묐; 묐; 묐; 묐; ) HANGUL SYLLABLE MOESS +BB11;BB11;1106 116C 11BC;BB11;1106 116C 11BC; # (묑; 묑; 묑; 묑; 묑; ) HANGUL SYLLABLE MOENG +BB12;BB12;1106 116C 11BD;BB12;1106 116C 11BD; # (묒; 묒; 묒; 묒; 묒; ) HANGUL SYLLABLE MOEJ +BB13;BB13;1106 116C 11BE;BB13;1106 116C 11BE; # (묓; 묓; 묓; 묓; 묓; ) HANGUL SYLLABLE MOEC +BB14;BB14;1106 116C 11BF;BB14;1106 116C 11BF; # (묔; 묔; 묔; 묔; 묔; ) HANGUL SYLLABLE MOEK +BB15;BB15;1106 116C 11C0;BB15;1106 116C 11C0; # (묕; 묕; 묕; 묕; 묕; ) HANGUL SYLLABLE MOET +BB16;BB16;1106 116C 11C1;BB16;1106 116C 11C1; # (묖; 묖; 묖; 묖; 묖; ) HANGUL SYLLABLE MOEP +BB17;BB17;1106 116C 11C2;BB17;1106 116C 11C2; # (묗; 묗; 묗; 묗; 묗; ) HANGUL SYLLABLE MOEH +BB18;BB18;1106 116D;BB18;1106 116D; # (묘; 묘; 묘; 묘; 묘; ) HANGUL SYLLABLE MYO +BB19;BB19;1106 116D 11A8;BB19;1106 116D 11A8; # (묙; 묙; 묙; 묙; 묙; ) HANGUL SYLLABLE MYOG +BB1A;BB1A;1106 116D 11A9;BB1A;1106 116D 11A9; # (묚; 묚; 묚; 묚; 묚; ) HANGUL SYLLABLE MYOGG +BB1B;BB1B;1106 116D 11AA;BB1B;1106 116D 11AA; # (묛; 묛; 묛; 묛; 묛; ) HANGUL SYLLABLE MYOGS +BB1C;BB1C;1106 116D 11AB;BB1C;1106 116D 11AB; # (묜; 묜; 묜; 묜; 묜; ) HANGUL SYLLABLE MYON +BB1D;BB1D;1106 116D 11AC;BB1D;1106 116D 11AC; # (묝; 묝; 묝; 묝; 묝; ) HANGUL SYLLABLE MYONJ +BB1E;BB1E;1106 116D 11AD;BB1E;1106 116D 11AD; # (묞; 묞; 묞; 묞; 묞; ) HANGUL SYLLABLE MYONH +BB1F;BB1F;1106 116D 11AE;BB1F;1106 116D 11AE; # (묟; 묟; 묟; 묟; 묟; ) HANGUL SYLLABLE MYOD +BB20;BB20;1106 116D 11AF;BB20;1106 116D 11AF; # (묠; 묠; 묠; 묠; 묠; ) HANGUL SYLLABLE MYOL +BB21;BB21;1106 116D 11B0;BB21;1106 116D 11B0; # (묡; 묡; 묡; 묡; 묡; ) HANGUL SYLLABLE MYOLG +BB22;BB22;1106 116D 11B1;BB22;1106 116D 11B1; # (묢; 묢; 묢; 묢; 묢; ) HANGUL SYLLABLE MYOLM +BB23;BB23;1106 116D 11B2;BB23;1106 116D 11B2; # (묣; 묣; 묣; 묣; 묣; ) HANGUL SYLLABLE MYOLB +BB24;BB24;1106 116D 11B3;BB24;1106 116D 11B3; # (묤; 묤; 묤; 묤; 묤; ) HANGUL SYLLABLE MYOLS +BB25;BB25;1106 116D 11B4;BB25;1106 116D 11B4; # (묥; 묥; 묥; 묥; 묥; ) HANGUL SYLLABLE MYOLT +BB26;BB26;1106 116D 11B5;BB26;1106 116D 11B5; # (묦; 묦; 묦; 묦; 묦; ) HANGUL SYLLABLE MYOLP +BB27;BB27;1106 116D 11B6;BB27;1106 116D 11B6; # (묧; 묧; 묧; 묧; 묧; ) HANGUL SYLLABLE MYOLH +BB28;BB28;1106 116D 11B7;BB28;1106 116D 11B7; # (묨; 묨; 묨; 묨; 묨; ) HANGUL SYLLABLE MYOM +BB29;BB29;1106 116D 11B8;BB29;1106 116D 11B8; # (묩; 묩; 묩; 묩; 묩; ) HANGUL SYLLABLE MYOB +BB2A;BB2A;1106 116D 11B9;BB2A;1106 116D 11B9; # (묪; 묪; 묪; 묪; 묪; ) HANGUL SYLLABLE MYOBS +BB2B;BB2B;1106 116D 11BA;BB2B;1106 116D 11BA; # (묫; 묫; 묫; 묫; 묫; ) HANGUL SYLLABLE MYOS +BB2C;BB2C;1106 116D 11BB;BB2C;1106 116D 11BB; # (묬; 묬; 묬; 묬; 묬; ) HANGUL SYLLABLE MYOSS +BB2D;BB2D;1106 116D 11BC;BB2D;1106 116D 11BC; # (묭; 묭; 묭; 묭; 묭; ) HANGUL SYLLABLE MYONG +BB2E;BB2E;1106 116D 11BD;BB2E;1106 116D 11BD; # (묮; 묮; 묮; 묮; 묮; ) HANGUL SYLLABLE MYOJ +BB2F;BB2F;1106 116D 11BE;BB2F;1106 116D 11BE; # (묯; 묯; 묯; 묯; 묯; ) HANGUL SYLLABLE MYOC +BB30;BB30;1106 116D 11BF;BB30;1106 116D 11BF; # (묰; 묰; 묰; 묰; 묰; ) HANGUL SYLLABLE MYOK +BB31;BB31;1106 116D 11C0;BB31;1106 116D 11C0; # (묱; 묱; 묱; 묱; 묱; ) HANGUL SYLLABLE MYOT +BB32;BB32;1106 116D 11C1;BB32;1106 116D 11C1; # (묲; 묲; 묲; 묲; 묲; ) HANGUL SYLLABLE MYOP +BB33;BB33;1106 116D 11C2;BB33;1106 116D 11C2; # (묳; 묳; 묳; 묳; 묳; ) HANGUL SYLLABLE MYOH +BB34;BB34;1106 116E;BB34;1106 116E; # (무; 무; 무; 무; 무; ) HANGUL SYLLABLE MU +BB35;BB35;1106 116E 11A8;BB35;1106 116E 11A8; # (묵; 묵; 묵; 묵; 묵; ) HANGUL SYLLABLE MUG +BB36;BB36;1106 116E 11A9;BB36;1106 116E 11A9; # (묶; 묶; 묶; 묶; 묶; ) HANGUL SYLLABLE MUGG +BB37;BB37;1106 116E 11AA;BB37;1106 116E 11AA; # (묷; 묷; 묷; 묷; 묷; ) HANGUL SYLLABLE MUGS +BB38;BB38;1106 116E 11AB;BB38;1106 116E 11AB; # (문; 문; 문; 문; 문; ) HANGUL SYLLABLE MUN +BB39;BB39;1106 116E 11AC;BB39;1106 116E 11AC; # (묹; 묹; 묹; 묹; 묹; ) HANGUL SYLLABLE MUNJ +BB3A;BB3A;1106 116E 11AD;BB3A;1106 116E 11AD; # (묺; 묺; 묺; 묺; 묺; ) HANGUL SYLLABLE MUNH +BB3B;BB3B;1106 116E 11AE;BB3B;1106 116E 11AE; # (묻; 묻; 묻; 묻; 묻; ) HANGUL SYLLABLE MUD +BB3C;BB3C;1106 116E 11AF;BB3C;1106 116E 11AF; # (물; 물; 물; 물; 물; ) HANGUL SYLLABLE MUL +BB3D;BB3D;1106 116E 11B0;BB3D;1106 116E 11B0; # (묽; 묽; 묽; 묽; 묽; ) HANGUL SYLLABLE MULG +BB3E;BB3E;1106 116E 11B1;BB3E;1106 116E 11B1; # (묾; 묾; 묾; 묾; 묾; ) HANGUL SYLLABLE MULM +BB3F;BB3F;1106 116E 11B2;BB3F;1106 116E 11B2; # (묿; 묿; 묿; 묿; 묿; ) HANGUL SYLLABLE MULB +BB40;BB40;1106 116E 11B3;BB40;1106 116E 11B3; # (뭀; 뭀; 뭀; 뭀; 뭀; ) HANGUL SYLLABLE MULS +BB41;BB41;1106 116E 11B4;BB41;1106 116E 11B4; # (뭁; 뭁; 뭁; 뭁; 뭁; ) HANGUL SYLLABLE MULT +BB42;BB42;1106 116E 11B5;BB42;1106 116E 11B5; # (뭂; 뭂; 뭂; 뭂; 뭂; ) HANGUL SYLLABLE MULP +BB43;BB43;1106 116E 11B6;BB43;1106 116E 11B6; # (뭃; 뭃; 뭃; 뭃; 뭃; ) HANGUL SYLLABLE MULH +BB44;BB44;1106 116E 11B7;BB44;1106 116E 11B7; # (뭄; 뭄; 뭄; 뭄; 뭄; ) HANGUL SYLLABLE MUM +BB45;BB45;1106 116E 11B8;BB45;1106 116E 11B8; # (뭅; 뭅; 뭅; 뭅; 뭅; ) HANGUL SYLLABLE MUB +BB46;BB46;1106 116E 11B9;BB46;1106 116E 11B9; # (뭆; 뭆; 뭆; 뭆; 뭆; ) HANGUL SYLLABLE MUBS +BB47;BB47;1106 116E 11BA;BB47;1106 116E 11BA; # (뭇; 뭇; 뭇; 뭇; 뭇; ) HANGUL SYLLABLE MUS +BB48;BB48;1106 116E 11BB;BB48;1106 116E 11BB; # (뭈; 뭈; 뭈; 뭈; 뭈; ) HANGUL SYLLABLE MUSS +BB49;BB49;1106 116E 11BC;BB49;1106 116E 11BC; # (뭉; 뭉; 뭉; 뭉; 뭉; ) HANGUL SYLLABLE MUNG +BB4A;BB4A;1106 116E 11BD;BB4A;1106 116E 11BD; # (뭊; 뭊; 뭊; 뭊; 뭊; ) HANGUL SYLLABLE MUJ +BB4B;BB4B;1106 116E 11BE;BB4B;1106 116E 11BE; # (뭋; 뭋; 뭋; 뭋; 뭋; ) HANGUL SYLLABLE MUC +BB4C;BB4C;1106 116E 11BF;BB4C;1106 116E 11BF; # (뭌; 뭌; 뭌; 뭌; 뭌; ) HANGUL SYLLABLE MUK +BB4D;BB4D;1106 116E 11C0;BB4D;1106 116E 11C0; # (뭍; 뭍; 뭍; 뭍; 뭍; ) HANGUL SYLLABLE MUT +BB4E;BB4E;1106 116E 11C1;BB4E;1106 116E 11C1; # (뭎; 뭎; 뭎; 뭎; 뭎; ) HANGUL SYLLABLE MUP +BB4F;BB4F;1106 116E 11C2;BB4F;1106 116E 11C2; # (뭏; 뭏; 뭏; 뭏; 뭏; ) HANGUL SYLLABLE MUH +BB50;BB50;1106 116F;BB50;1106 116F; # (뭐; 뭐; 뭐; 뭐; 뭐; ) HANGUL SYLLABLE MWEO +BB51;BB51;1106 116F 11A8;BB51;1106 116F 11A8; # (뭑; 뭑; 뭑; 뭑; 뭑; ) HANGUL SYLLABLE MWEOG +BB52;BB52;1106 116F 11A9;BB52;1106 116F 11A9; # (뭒; 뭒; 뭒; 뭒; 뭒; ) HANGUL SYLLABLE MWEOGG +BB53;BB53;1106 116F 11AA;BB53;1106 116F 11AA; # (뭓; 뭓; 뭓; 뭓; 뭓; ) HANGUL SYLLABLE MWEOGS +BB54;BB54;1106 116F 11AB;BB54;1106 116F 11AB; # (뭔; 뭔; 뭔; 뭔; 뭔; ) HANGUL SYLLABLE MWEON +BB55;BB55;1106 116F 11AC;BB55;1106 116F 11AC; # (뭕; 뭕; 뭕; 뭕; 뭕; ) HANGUL SYLLABLE MWEONJ +BB56;BB56;1106 116F 11AD;BB56;1106 116F 11AD; # (뭖; 뭖; 뭖; 뭖; 뭖; ) HANGUL SYLLABLE MWEONH +BB57;BB57;1106 116F 11AE;BB57;1106 116F 11AE; # (뭗; 뭗; 뭗; 뭗; 뭗; ) HANGUL SYLLABLE MWEOD +BB58;BB58;1106 116F 11AF;BB58;1106 116F 11AF; # (뭘; 뭘; 뭘; 뭘; 뭘; ) HANGUL SYLLABLE MWEOL +BB59;BB59;1106 116F 11B0;BB59;1106 116F 11B0; # (뭙; 뭙; 뭙; 뭙; 뭙; ) HANGUL SYLLABLE MWEOLG +BB5A;BB5A;1106 116F 11B1;BB5A;1106 116F 11B1; # (뭚; 뭚; 뭚; 뭚; 뭚; ) HANGUL SYLLABLE MWEOLM +BB5B;BB5B;1106 116F 11B2;BB5B;1106 116F 11B2; # (뭛; 뭛; 뭛; 뭛; 뭛; ) HANGUL SYLLABLE MWEOLB +BB5C;BB5C;1106 116F 11B3;BB5C;1106 116F 11B3; # (뭜; 뭜; 뭜; 뭜; 뭜; ) HANGUL SYLLABLE MWEOLS +BB5D;BB5D;1106 116F 11B4;BB5D;1106 116F 11B4; # (뭝; 뭝; 뭝; 뭝; 뭝; ) HANGUL SYLLABLE MWEOLT +BB5E;BB5E;1106 116F 11B5;BB5E;1106 116F 11B5; # (뭞; 뭞; 뭞; 뭞; 뭞; ) HANGUL SYLLABLE MWEOLP +BB5F;BB5F;1106 116F 11B6;BB5F;1106 116F 11B6; # (뭟; 뭟; 뭟; 뭟; 뭟; ) HANGUL SYLLABLE MWEOLH +BB60;BB60;1106 116F 11B7;BB60;1106 116F 11B7; # (뭠; 뭠; 뭠; 뭠; 뭠; ) HANGUL SYLLABLE MWEOM +BB61;BB61;1106 116F 11B8;BB61;1106 116F 11B8; # (뭡; 뭡; 뭡; 뭡; 뭡; ) HANGUL SYLLABLE MWEOB +BB62;BB62;1106 116F 11B9;BB62;1106 116F 11B9; # (뭢; 뭢; 뭢; 뭢; 뭢; ) HANGUL SYLLABLE MWEOBS +BB63;BB63;1106 116F 11BA;BB63;1106 116F 11BA; # (뭣; 뭣; 뭣; 뭣; 뭣; ) HANGUL SYLLABLE MWEOS +BB64;BB64;1106 116F 11BB;BB64;1106 116F 11BB; # (뭤; 뭤; 뭤; 뭤; 뭤; ) HANGUL SYLLABLE MWEOSS +BB65;BB65;1106 116F 11BC;BB65;1106 116F 11BC; # (뭥; 뭥; 뭥; 뭥; 뭥; ) HANGUL SYLLABLE MWEONG +BB66;BB66;1106 116F 11BD;BB66;1106 116F 11BD; # (뭦; 뭦; 뭦; 뭦; 뭦; ) HANGUL SYLLABLE MWEOJ +BB67;BB67;1106 116F 11BE;BB67;1106 116F 11BE; # (뭧; 뭧; 뭧; 뭧; 뭧; ) HANGUL SYLLABLE MWEOC +BB68;BB68;1106 116F 11BF;BB68;1106 116F 11BF; # (뭨; 뭨; 뭨; 뭨; 뭨; ) HANGUL SYLLABLE MWEOK +BB69;BB69;1106 116F 11C0;BB69;1106 116F 11C0; # (뭩; 뭩; 뭩; 뭩; 뭩; ) HANGUL SYLLABLE MWEOT +BB6A;BB6A;1106 116F 11C1;BB6A;1106 116F 11C1; # (뭪; 뭪; 뭪; 뭪; 뭪; ) HANGUL SYLLABLE MWEOP +BB6B;BB6B;1106 116F 11C2;BB6B;1106 116F 11C2; # (뭫; 뭫; 뭫; 뭫; 뭫; ) HANGUL SYLLABLE MWEOH +BB6C;BB6C;1106 1170;BB6C;1106 1170; # (뭬; 뭬; 뭬; 뭬; 뭬; ) HANGUL SYLLABLE MWE +BB6D;BB6D;1106 1170 11A8;BB6D;1106 1170 11A8; # (뭭; 뭭; 뭭; 뭭; 뭭; ) HANGUL SYLLABLE MWEG +BB6E;BB6E;1106 1170 11A9;BB6E;1106 1170 11A9; # (뭮; 뭮; 뭮; 뭮; 뭮; ) HANGUL SYLLABLE MWEGG +BB6F;BB6F;1106 1170 11AA;BB6F;1106 1170 11AA; # (뭯; 뭯; 뭯; 뭯; 뭯; ) HANGUL SYLLABLE MWEGS +BB70;BB70;1106 1170 11AB;BB70;1106 1170 11AB; # (뭰; 뭰; 뭰; 뭰; 뭰; ) HANGUL SYLLABLE MWEN +BB71;BB71;1106 1170 11AC;BB71;1106 1170 11AC; # (뭱; 뭱; 뭱; 뭱; 뭱; ) HANGUL SYLLABLE MWENJ +BB72;BB72;1106 1170 11AD;BB72;1106 1170 11AD; # (뭲; 뭲; 뭲; 뭲; 뭲; ) HANGUL SYLLABLE MWENH +BB73;BB73;1106 1170 11AE;BB73;1106 1170 11AE; # (뭳; 뭳; 뭳; 뭳; 뭳; ) HANGUL SYLLABLE MWED +BB74;BB74;1106 1170 11AF;BB74;1106 1170 11AF; # (뭴; 뭴; 뭴; 뭴; 뭴; ) HANGUL SYLLABLE MWEL +BB75;BB75;1106 1170 11B0;BB75;1106 1170 11B0; # (뭵; 뭵; 뭵; 뭵; 뭵; ) HANGUL SYLLABLE MWELG +BB76;BB76;1106 1170 11B1;BB76;1106 1170 11B1; # (뭶; 뭶; 뭶; 뭶; 뭶; ) HANGUL SYLLABLE MWELM +BB77;BB77;1106 1170 11B2;BB77;1106 1170 11B2; # (뭷; 뭷; 뭷; 뭷; 뭷; ) HANGUL SYLLABLE MWELB +BB78;BB78;1106 1170 11B3;BB78;1106 1170 11B3; # (뭸; 뭸; 뭸; 뭸; 뭸; ) HANGUL SYLLABLE MWELS +BB79;BB79;1106 1170 11B4;BB79;1106 1170 11B4; # (뭹; 뭹; 뭹; 뭹; 뭹; ) HANGUL SYLLABLE MWELT +BB7A;BB7A;1106 1170 11B5;BB7A;1106 1170 11B5; # (뭺; 뭺; 뭺; 뭺; 뭺; ) HANGUL SYLLABLE MWELP +BB7B;BB7B;1106 1170 11B6;BB7B;1106 1170 11B6; # (뭻; 뭻; 뭻; 뭻; 뭻; ) HANGUL SYLLABLE MWELH +BB7C;BB7C;1106 1170 11B7;BB7C;1106 1170 11B7; # (뭼; 뭼; 뭼; 뭼; 뭼; ) HANGUL SYLLABLE MWEM +BB7D;BB7D;1106 1170 11B8;BB7D;1106 1170 11B8; # (뭽; 뭽; 뭽; 뭽; 뭽; ) HANGUL SYLLABLE MWEB +BB7E;BB7E;1106 1170 11B9;BB7E;1106 1170 11B9; # (뭾; 뭾; 뭾; 뭾; 뭾; ) HANGUL SYLLABLE MWEBS +BB7F;BB7F;1106 1170 11BA;BB7F;1106 1170 11BA; # (뭿; 뭿; 뭿; 뭿; 뭿; ) HANGUL SYLLABLE MWES +BB80;BB80;1106 1170 11BB;BB80;1106 1170 11BB; # (뮀; 뮀; 뮀; 뮀; 뮀; ) HANGUL SYLLABLE MWESS +BB81;BB81;1106 1170 11BC;BB81;1106 1170 11BC; # (뮁; 뮁; 뮁; 뮁; 뮁; ) HANGUL SYLLABLE MWENG +BB82;BB82;1106 1170 11BD;BB82;1106 1170 11BD; # (뮂; 뮂; 뮂; 뮂; 뮂; ) HANGUL SYLLABLE MWEJ +BB83;BB83;1106 1170 11BE;BB83;1106 1170 11BE; # (뮃; 뮃; 뮃; 뮃; 뮃; ) HANGUL SYLLABLE MWEC +BB84;BB84;1106 1170 11BF;BB84;1106 1170 11BF; # (뮄; 뮄; 뮄; 뮄; 뮄; ) HANGUL SYLLABLE MWEK +BB85;BB85;1106 1170 11C0;BB85;1106 1170 11C0; # (뮅; 뮅; 뮅; 뮅; 뮅; ) HANGUL SYLLABLE MWET +BB86;BB86;1106 1170 11C1;BB86;1106 1170 11C1; # (뮆; 뮆; 뮆; 뮆; 뮆; ) HANGUL SYLLABLE MWEP +BB87;BB87;1106 1170 11C2;BB87;1106 1170 11C2; # (뮇; 뮇; 뮇; 뮇; 뮇; ) HANGUL SYLLABLE MWEH +BB88;BB88;1106 1171;BB88;1106 1171; # (뮈; 뮈; 뮈; 뮈; 뮈; ) HANGUL SYLLABLE MWI +BB89;BB89;1106 1171 11A8;BB89;1106 1171 11A8; # (뮉; 뮉; 뮉; 뮉; 뮉; ) HANGUL SYLLABLE MWIG +BB8A;BB8A;1106 1171 11A9;BB8A;1106 1171 11A9; # (뮊; 뮊; 뮊; 뮊; 뮊; ) HANGUL SYLLABLE MWIGG +BB8B;BB8B;1106 1171 11AA;BB8B;1106 1171 11AA; # (뮋; 뮋; 뮋; 뮋; 뮋; ) HANGUL SYLLABLE MWIGS +BB8C;BB8C;1106 1171 11AB;BB8C;1106 1171 11AB; # (뮌; 뮌; 뮌; 뮌; 뮌; ) HANGUL SYLLABLE MWIN +BB8D;BB8D;1106 1171 11AC;BB8D;1106 1171 11AC; # (뮍; 뮍; 뮍; 뮍; 뮍; ) HANGUL SYLLABLE MWINJ +BB8E;BB8E;1106 1171 11AD;BB8E;1106 1171 11AD; # (뮎; 뮎; 뮎; 뮎; 뮎; ) HANGUL SYLLABLE MWINH +BB8F;BB8F;1106 1171 11AE;BB8F;1106 1171 11AE; # (뮏; 뮏; 뮏; 뮏; 뮏; ) HANGUL SYLLABLE MWID +BB90;BB90;1106 1171 11AF;BB90;1106 1171 11AF; # (뮐; 뮐; 뮐; 뮐; 뮐; ) HANGUL SYLLABLE MWIL +BB91;BB91;1106 1171 11B0;BB91;1106 1171 11B0; # (뮑; 뮑; 뮑; 뮑; 뮑; ) HANGUL SYLLABLE MWILG +BB92;BB92;1106 1171 11B1;BB92;1106 1171 11B1; # (뮒; 뮒; 뮒; 뮒; 뮒; ) HANGUL SYLLABLE MWILM +BB93;BB93;1106 1171 11B2;BB93;1106 1171 11B2; # (뮓; 뮓; 뮓; 뮓; 뮓; ) HANGUL SYLLABLE MWILB +BB94;BB94;1106 1171 11B3;BB94;1106 1171 11B3; # (뮔; 뮔; 뮔; 뮔; 뮔; ) HANGUL SYLLABLE MWILS +BB95;BB95;1106 1171 11B4;BB95;1106 1171 11B4; # (뮕; 뮕; 뮕; 뮕; 뮕; ) HANGUL SYLLABLE MWILT +BB96;BB96;1106 1171 11B5;BB96;1106 1171 11B5; # (뮖; 뮖; 뮖; 뮖; 뮖; ) HANGUL SYLLABLE MWILP +BB97;BB97;1106 1171 11B6;BB97;1106 1171 11B6; # (뮗; 뮗; 뮗; 뮗; 뮗; ) HANGUL SYLLABLE MWILH +BB98;BB98;1106 1171 11B7;BB98;1106 1171 11B7; # (뮘; 뮘; 뮘; 뮘; 뮘; ) HANGUL SYLLABLE MWIM +BB99;BB99;1106 1171 11B8;BB99;1106 1171 11B8; # (뮙; 뮙; 뮙; 뮙; 뮙; ) HANGUL SYLLABLE MWIB +BB9A;BB9A;1106 1171 11B9;BB9A;1106 1171 11B9; # (뮚; 뮚; 뮚; 뮚; 뮚; ) HANGUL SYLLABLE MWIBS +BB9B;BB9B;1106 1171 11BA;BB9B;1106 1171 11BA; # (뮛; 뮛; 뮛; 뮛; 뮛; ) HANGUL SYLLABLE MWIS +BB9C;BB9C;1106 1171 11BB;BB9C;1106 1171 11BB; # (뮜; 뮜; 뮜; 뮜; 뮜; ) HANGUL SYLLABLE MWISS +BB9D;BB9D;1106 1171 11BC;BB9D;1106 1171 11BC; # (뮝; 뮝; 뮝; 뮝; 뮝; ) HANGUL SYLLABLE MWING +BB9E;BB9E;1106 1171 11BD;BB9E;1106 1171 11BD; # (뮞; 뮞; 뮞; 뮞; 뮞; ) HANGUL SYLLABLE MWIJ +BB9F;BB9F;1106 1171 11BE;BB9F;1106 1171 11BE; # (뮟; 뮟; 뮟; 뮟; 뮟; ) HANGUL SYLLABLE MWIC +BBA0;BBA0;1106 1171 11BF;BBA0;1106 1171 11BF; # (뮠; 뮠; 뮠; 뮠; 뮠; ) HANGUL SYLLABLE MWIK +BBA1;BBA1;1106 1171 11C0;BBA1;1106 1171 11C0; # (뮡; 뮡; 뮡; 뮡; 뮡; ) HANGUL SYLLABLE MWIT +BBA2;BBA2;1106 1171 11C1;BBA2;1106 1171 11C1; # (뮢; 뮢; 뮢; 뮢; 뮢; ) HANGUL SYLLABLE MWIP +BBA3;BBA3;1106 1171 11C2;BBA3;1106 1171 11C2; # (뮣; 뮣; 뮣; 뮣; 뮣; ) HANGUL SYLLABLE MWIH +BBA4;BBA4;1106 1172;BBA4;1106 1172; # (뮤; 뮤; 뮤; 뮤; 뮤; ) HANGUL SYLLABLE MYU +BBA5;BBA5;1106 1172 11A8;BBA5;1106 1172 11A8; # (뮥; 뮥; 뮥; 뮥; 뮥; ) HANGUL SYLLABLE MYUG +BBA6;BBA6;1106 1172 11A9;BBA6;1106 1172 11A9; # (뮦; 뮦; 뮦; 뮦; 뮦; ) HANGUL SYLLABLE MYUGG +BBA7;BBA7;1106 1172 11AA;BBA7;1106 1172 11AA; # (뮧; 뮧; 뮧; 뮧; 뮧; ) HANGUL SYLLABLE MYUGS +BBA8;BBA8;1106 1172 11AB;BBA8;1106 1172 11AB; # (뮨; 뮨; 뮨; 뮨; 뮨; ) HANGUL SYLLABLE MYUN +BBA9;BBA9;1106 1172 11AC;BBA9;1106 1172 11AC; # (뮩; 뮩; 뮩; 뮩; 뮩; ) HANGUL SYLLABLE MYUNJ +BBAA;BBAA;1106 1172 11AD;BBAA;1106 1172 11AD; # (뮪; 뮪; 뮪; 뮪; 뮪; ) HANGUL SYLLABLE MYUNH +BBAB;BBAB;1106 1172 11AE;BBAB;1106 1172 11AE; # (뮫; 뮫; 뮫; 뮫; 뮫; ) HANGUL SYLLABLE MYUD +BBAC;BBAC;1106 1172 11AF;BBAC;1106 1172 11AF; # (뮬; 뮬; 뮬; 뮬; 뮬; ) HANGUL SYLLABLE MYUL +BBAD;BBAD;1106 1172 11B0;BBAD;1106 1172 11B0; # (뮭; 뮭; 뮭; 뮭; 뮭; ) HANGUL SYLLABLE MYULG +BBAE;BBAE;1106 1172 11B1;BBAE;1106 1172 11B1; # (뮮; 뮮; 뮮; 뮮; 뮮; ) HANGUL SYLLABLE MYULM +BBAF;BBAF;1106 1172 11B2;BBAF;1106 1172 11B2; # (뮯; 뮯; 뮯; 뮯; 뮯; ) HANGUL SYLLABLE MYULB +BBB0;BBB0;1106 1172 11B3;BBB0;1106 1172 11B3; # (뮰; 뮰; 뮰; 뮰; 뮰; ) HANGUL SYLLABLE MYULS +BBB1;BBB1;1106 1172 11B4;BBB1;1106 1172 11B4; # (뮱; 뮱; 뮱; 뮱; 뮱; ) HANGUL SYLLABLE MYULT +BBB2;BBB2;1106 1172 11B5;BBB2;1106 1172 11B5; # (뮲; 뮲; 뮲; 뮲; 뮲; ) HANGUL SYLLABLE MYULP +BBB3;BBB3;1106 1172 11B6;BBB3;1106 1172 11B6; # (뮳; 뮳; 뮳; 뮳; 뮳; ) HANGUL SYLLABLE MYULH +BBB4;BBB4;1106 1172 11B7;BBB4;1106 1172 11B7; # (뮴; 뮴; 뮴; 뮴; 뮴; ) HANGUL SYLLABLE MYUM +BBB5;BBB5;1106 1172 11B8;BBB5;1106 1172 11B8; # (뮵; 뮵; 뮵; 뮵; 뮵; ) HANGUL SYLLABLE MYUB +BBB6;BBB6;1106 1172 11B9;BBB6;1106 1172 11B9; # (뮶; 뮶; 뮶; 뮶; 뮶; ) HANGUL SYLLABLE MYUBS +BBB7;BBB7;1106 1172 11BA;BBB7;1106 1172 11BA; # (뮷; 뮷; 뮷; 뮷; 뮷; ) HANGUL SYLLABLE MYUS +BBB8;BBB8;1106 1172 11BB;BBB8;1106 1172 11BB; # (뮸; 뮸; 뮸; 뮸; 뮸; ) HANGUL SYLLABLE MYUSS +BBB9;BBB9;1106 1172 11BC;BBB9;1106 1172 11BC; # (뮹; 뮹; 뮹; 뮹; 뮹; ) HANGUL SYLLABLE MYUNG +BBBA;BBBA;1106 1172 11BD;BBBA;1106 1172 11BD; # (뮺; 뮺; 뮺; 뮺; 뮺; ) HANGUL SYLLABLE MYUJ +BBBB;BBBB;1106 1172 11BE;BBBB;1106 1172 11BE; # (뮻; 뮻; 뮻; 뮻; 뮻; ) HANGUL SYLLABLE MYUC +BBBC;BBBC;1106 1172 11BF;BBBC;1106 1172 11BF; # (뮼; 뮼; 뮼; 뮼; 뮼; ) HANGUL SYLLABLE MYUK +BBBD;BBBD;1106 1172 11C0;BBBD;1106 1172 11C0; # (뮽; 뮽; 뮽; 뮽; 뮽; ) HANGUL SYLLABLE MYUT +BBBE;BBBE;1106 1172 11C1;BBBE;1106 1172 11C1; # (뮾; 뮾; 뮾; 뮾; 뮾; ) HANGUL SYLLABLE MYUP +BBBF;BBBF;1106 1172 11C2;BBBF;1106 1172 11C2; # (뮿; 뮿; 뮿; 뮿; 뮿; ) HANGUL SYLLABLE MYUH +BBC0;BBC0;1106 1173;BBC0;1106 1173; # (므; 므; 므; 므; 므; ) HANGUL SYLLABLE MEU +BBC1;BBC1;1106 1173 11A8;BBC1;1106 1173 11A8; # (믁; 믁; 믁; 믁; 믁; ) HANGUL SYLLABLE MEUG +BBC2;BBC2;1106 1173 11A9;BBC2;1106 1173 11A9; # (믂; 믂; 믂; 믂; 믂; ) HANGUL SYLLABLE MEUGG +BBC3;BBC3;1106 1173 11AA;BBC3;1106 1173 11AA; # (믃; 믃; 믃; 믃; 믃; ) HANGUL SYLLABLE MEUGS +BBC4;BBC4;1106 1173 11AB;BBC4;1106 1173 11AB; # (믄; 믄; 믄; 믄; 믄; ) HANGUL SYLLABLE MEUN +BBC5;BBC5;1106 1173 11AC;BBC5;1106 1173 11AC; # (믅; 믅; 믅; 믅; 믅; ) HANGUL SYLLABLE MEUNJ +BBC6;BBC6;1106 1173 11AD;BBC6;1106 1173 11AD; # (믆; 믆; 믆; 믆; 믆; ) HANGUL SYLLABLE MEUNH +BBC7;BBC7;1106 1173 11AE;BBC7;1106 1173 11AE; # (믇; 믇; 믇; 믇; 믇; ) HANGUL SYLLABLE MEUD +BBC8;BBC8;1106 1173 11AF;BBC8;1106 1173 11AF; # (믈; 믈; 믈; 믈; 믈; ) HANGUL SYLLABLE MEUL +BBC9;BBC9;1106 1173 11B0;BBC9;1106 1173 11B0; # (믉; 믉; 믉; 믉; 믉; ) HANGUL SYLLABLE MEULG +BBCA;BBCA;1106 1173 11B1;BBCA;1106 1173 11B1; # (믊; 믊; 믊; 믊; 믊; ) HANGUL SYLLABLE MEULM +BBCB;BBCB;1106 1173 11B2;BBCB;1106 1173 11B2; # (믋; 믋; 믋; 믋; 믋; ) HANGUL SYLLABLE MEULB +BBCC;BBCC;1106 1173 11B3;BBCC;1106 1173 11B3; # (믌; 믌; 믌; 믌; 믌; ) HANGUL SYLLABLE MEULS +BBCD;BBCD;1106 1173 11B4;BBCD;1106 1173 11B4; # (믍; 믍; 믍; 믍; 믍; ) HANGUL SYLLABLE MEULT +BBCE;BBCE;1106 1173 11B5;BBCE;1106 1173 11B5; # (믎; 믎; 믎; 믎; 믎; ) HANGUL SYLLABLE MEULP +BBCF;BBCF;1106 1173 11B6;BBCF;1106 1173 11B6; # (믏; 믏; 믏; 믏; 믏; ) HANGUL SYLLABLE MEULH +BBD0;BBD0;1106 1173 11B7;BBD0;1106 1173 11B7; # (믐; 믐; 믐; 믐; 믐; ) HANGUL SYLLABLE MEUM +BBD1;BBD1;1106 1173 11B8;BBD1;1106 1173 11B8; # (믑; 믑; 믑; 믑; 믑; ) HANGUL SYLLABLE MEUB +BBD2;BBD2;1106 1173 11B9;BBD2;1106 1173 11B9; # (믒; 믒; 믒; 믒; 믒; ) HANGUL SYLLABLE MEUBS +BBD3;BBD3;1106 1173 11BA;BBD3;1106 1173 11BA; # (믓; 믓; 믓; 믓; 믓; ) HANGUL SYLLABLE MEUS +BBD4;BBD4;1106 1173 11BB;BBD4;1106 1173 11BB; # (믔; 믔; 믔; 믔; 믔; ) HANGUL SYLLABLE MEUSS +BBD5;BBD5;1106 1173 11BC;BBD5;1106 1173 11BC; # (믕; 믕; 믕; 믕; 믕; ) HANGUL SYLLABLE MEUNG +BBD6;BBD6;1106 1173 11BD;BBD6;1106 1173 11BD; # (믖; 믖; 믖; 믖; 믖; ) HANGUL SYLLABLE MEUJ +BBD7;BBD7;1106 1173 11BE;BBD7;1106 1173 11BE; # (믗; 믗; 믗; 믗; 믗; ) HANGUL SYLLABLE MEUC +BBD8;BBD8;1106 1173 11BF;BBD8;1106 1173 11BF; # (믘; 믘; 믘; 믘; 믘; ) HANGUL SYLLABLE MEUK +BBD9;BBD9;1106 1173 11C0;BBD9;1106 1173 11C0; # (믙; 믙; 믙; 믙; 믙; ) HANGUL SYLLABLE MEUT +BBDA;BBDA;1106 1173 11C1;BBDA;1106 1173 11C1; # (믚; 믚; 믚; 믚; 믚; ) HANGUL SYLLABLE MEUP +BBDB;BBDB;1106 1173 11C2;BBDB;1106 1173 11C2; # (믛; 믛; 믛; 믛; 믛; ) HANGUL SYLLABLE MEUH +BBDC;BBDC;1106 1174;BBDC;1106 1174; # (믜; 믜; 믜; 믜; 믜; ) HANGUL SYLLABLE MYI +BBDD;BBDD;1106 1174 11A8;BBDD;1106 1174 11A8; # (믝; 믝; 믝; 믝; 믝; ) HANGUL SYLLABLE MYIG +BBDE;BBDE;1106 1174 11A9;BBDE;1106 1174 11A9; # (믞; 믞; 믞; 믞; 믞; ) HANGUL SYLLABLE MYIGG +BBDF;BBDF;1106 1174 11AA;BBDF;1106 1174 11AA; # (믟; 믟; 믟; 믟; 믟; ) HANGUL SYLLABLE MYIGS +BBE0;BBE0;1106 1174 11AB;BBE0;1106 1174 11AB; # (믠; 믠; 믠; 믠; 믠; ) HANGUL SYLLABLE MYIN +BBE1;BBE1;1106 1174 11AC;BBE1;1106 1174 11AC; # (믡; 믡; 믡; 믡; 믡; ) HANGUL SYLLABLE MYINJ +BBE2;BBE2;1106 1174 11AD;BBE2;1106 1174 11AD; # (믢; 믢; 믢; 믢; 믢; ) HANGUL SYLLABLE MYINH +BBE3;BBE3;1106 1174 11AE;BBE3;1106 1174 11AE; # (믣; 믣; 믣; 믣; 믣; ) HANGUL SYLLABLE MYID +BBE4;BBE4;1106 1174 11AF;BBE4;1106 1174 11AF; # (믤; 믤; 믤; 믤; 믤; ) HANGUL SYLLABLE MYIL +BBE5;BBE5;1106 1174 11B0;BBE5;1106 1174 11B0; # (믥; 믥; 믥; 믥; 믥; ) HANGUL SYLLABLE MYILG +BBE6;BBE6;1106 1174 11B1;BBE6;1106 1174 11B1; # (믦; 믦; 믦; 믦; 믦; ) HANGUL SYLLABLE MYILM +BBE7;BBE7;1106 1174 11B2;BBE7;1106 1174 11B2; # (믧; 믧; 믧; 믧; 믧; ) HANGUL SYLLABLE MYILB +BBE8;BBE8;1106 1174 11B3;BBE8;1106 1174 11B3; # (믨; 믨; 믨; 믨; 믨; ) HANGUL SYLLABLE MYILS +BBE9;BBE9;1106 1174 11B4;BBE9;1106 1174 11B4; # (믩; 믩; 믩; 믩; 믩; ) HANGUL SYLLABLE MYILT +BBEA;BBEA;1106 1174 11B5;BBEA;1106 1174 11B5; # (믪; 믪; 믪; 믪; 믪; ) HANGUL SYLLABLE MYILP +BBEB;BBEB;1106 1174 11B6;BBEB;1106 1174 11B6; # (믫; 믫; 믫; 믫; 믫; ) HANGUL SYLLABLE MYILH +BBEC;BBEC;1106 1174 11B7;BBEC;1106 1174 11B7; # (믬; 믬; 믬; 믬; 믬; ) HANGUL SYLLABLE MYIM +BBED;BBED;1106 1174 11B8;BBED;1106 1174 11B8; # (믭; 믭; 믭; 믭; 믭; ) HANGUL SYLLABLE MYIB +BBEE;BBEE;1106 1174 11B9;BBEE;1106 1174 11B9; # (믮; 믮; 믮; 믮; 믮; ) HANGUL SYLLABLE MYIBS +BBEF;BBEF;1106 1174 11BA;BBEF;1106 1174 11BA; # (믯; 믯; 믯; 믯; 믯; ) HANGUL SYLLABLE MYIS +BBF0;BBF0;1106 1174 11BB;BBF0;1106 1174 11BB; # (믰; 믰; 믰; 믰; 믰; ) HANGUL SYLLABLE MYISS +BBF1;BBF1;1106 1174 11BC;BBF1;1106 1174 11BC; # (믱; 믱; 믱; 믱; 믱; ) HANGUL SYLLABLE MYING +BBF2;BBF2;1106 1174 11BD;BBF2;1106 1174 11BD; # (믲; 믲; 믲; 믲; 믲; ) HANGUL SYLLABLE MYIJ +BBF3;BBF3;1106 1174 11BE;BBF3;1106 1174 11BE; # (믳; 믳; 믳; 믳; 믳; ) HANGUL SYLLABLE MYIC +BBF4;BBF4;1106 1174 11BF;BBF4;1106 1174 11BF; # (믴; 믴; 믴; 믴; 믴; ) HANGUL SYLLABLE MYIK +BBF5;BBF5;1106 1174 11C0;BBF5;1106 1174 11C0; # (믵; 믵; 믵; 믵; 믵; ) HANGUL SYLLABLE MYIT +BBF6;BBF6;1106 1174 11C1;BBF6;1106 1174 11C1; # (믶; 믶; 믶; 믶; 믶; ) HANGUL SYLLABLE MYIP +BBF7;BBF7;1106 1174 11C2;BBF7;1106 1174 11C2; # (믷; 믷; 믷; 믷; 믷; ) HANGUL SYLLABLE MYIH +BBF8;BBF8;1106 1175;BBF8;1106 1175; # (미; 미; 미; 미; 미; ) HANGUL SYLLABLE MI +BBF9;BBF9;1106 1175 11A8;BBF9;1106 1175 11A8; # (믹; 믹; 믹; 믹; 믹; ) HANGUL SYLLABLE MIG +BBFA;BBFA;1106 1175 11A9;BBFA;1106 1175 11A9; # (믺; 믺; 믺; 믺; 믺; ) HANGUL SYLLABLE MIGG +BBFB;BBFB;1106 1175 11AA;BBFB;1106 1175 11AA; # (믻; 믻; 믻; 믻; 믻; ) HANGUL SYLLABLE MIGS +BBFC;BBFC;1106 1175 11AB;BBFC;1106 1175 11AB; # (민; 민; 민; 민; 민; ) HANGUL SYLLABLE MIN +BBFD;BBFD;1106 1175 11AC;BBFD;1106 1175 11AC; # (믽; 믽; 믽; 믽; 믽; ) HANGUL SYLLABLE MINJ +BBFE;BBFE;1106 1175 11AD;BBFE;1106 1175 11AD; # (믾; 믾; 믾; 믾; 믾; ) HANGUL SYLLABLE MINH +BBFF;BBFF;1106 1175 11AE;BBFF;1106 1175 11AE; # (믿; 믿; 믿; 믿; 믿; ) HANGUL SYLLABLE MID +BC00;BC00;1106 1175 11AF;BC00;1106 1175 11AF; # (밀; 밀; 밀; 밀; 밀; ) HANGUL SYLLABLE MIL +BC01;BC01;1106 1175 11B0;BC01;1106 1175 11B0; # (밁; 밁; 밁; 밁; 밁; ) HANGUL SYLLABLE MILG +BC02;BC02;1106 1175 11B1;BC02;1106 1175 11B1; # (밂; 밂; 밂; 밂; 밂; ) HANGUL SYLLABLE MILM +BC03;BC03;1106 1175 11B2;BC03;1106 1175 11B2; # (밃; 밃; 밃; 밃; 밃; ) HANGUL SYLLABLE MILB +BC04;BC04;1106 1175 11B3;BC04;1106 1175 11B3; # (밄; 밄; 밄; 밄; 밄; ) HANGUL SYLLABLE MILS +BC05;BC05;1106 1175 11B4;BC05;1106 1175 11B4; # (밅; 밅; 밅; 밅; 밅; ) HANGUL SYLLABLE MILT +BC06;BC06;1106 1175 11B5;BC06;1106 1175 11B5; # (밆; 밆; 밆; 밆; 밆; ) HANGUL SYLLABLE MILP +BC07;BC07;1106 1175 11B6;BC07;1106 1175 11B6; # (밇; 밇; 밇; 밇; 밇; ) HANGUL SYLLABLE MILH +BC08;BC08;1106 1175 11B7;BC08;1106 1175 11B7; # (밈; 밈; 밈; 밈; 밈; ) HANGUL SYLLABLE MIM +BC09;BC09;1106 1175 11B8;BC09;1106 1175 11B8; # (밉; 밉; 밉; 밉; 밉; ) HANGUL SYLLABLE MIB +BC0A;BC0A;1106 1175 11B9;BC0A;1106 1175 11B9; # (밊; 밊; 밊; 밊; 밊; ) HANGUL SYLLABLE MIBS +BC0B;BC0B;1106 1175 11BA;BC0B;1106 1175 11BA; # (밋; 밋; 밋; 밋; 밋; ) HANGUL SYLLABLE MIS +BC0C;BC0C;1106 1175 11BB;BC0C;1106 1175 11BB; # (밌; 밌; 밌; 밌; 밌; ) HANGUL SYLLABLE MISS +BC0D;BC0D;1106 1175 11BC;BC0D;1106 1175 11BC; # (밍; 밍; 밍; 밍; 밍; ) HANGUL SYLLABLE MING +BC0E;BC0E;1106 1175 11BD;BC0E;1106 1175 11BD; # (밎; 밎; 밎; 밎; 밎; ) HANGUL SYLLABLE MIJ +BC0F;BC0F;1106 1175 11BE;BC0F;1106 1175 11BE; # (및; 및; 및; 및; 및; ) HANGUL SYLLABLE MIC +BC10;BC10;1106 1175 11BF;BC10;1106 1175 11BF; # (밐; 밐; 밐; 밐; 밐; ) HANGUL SYLLABLE MIK +BC11;BC11;1106 1175 11C0;BC11;1106 1175 11C0; # (밑; 밑; 밑; 밑; 밑; ) HANGUL SYLLABLE MIT +BC12;BC12;1106 1175 11C1;BC12;1106 1175 11C1; # (밒; 밒; 밒; 밒; 밒; ) HANGUL SYLLABLE MIP +BC13;BC13;1106 1175 11C2;BC13;1106 1175 11C2; # (밓; 밓; 밓; 밓; 밓; ) HANGUL SYLLABLE MIH +BC14;BC14;1107 1161;BC14;1107 1161; # (바; 바; 바; 바; 바; ) HANGUL SYLLABLE BA +BC15;BC15;1107 1161 11A8;BC15;1107 1161 11A8; # (박; 박; 박; 박; 박; ) HANGUL SYLLABLE BAG +BC16;BC16;1107 1161 11A9;BC16;1107 1161 11A9; # (밖; 밖; 밖; 밖; 밖; ) HANGUL SYLLABLE BAGG +BC17;BC17;1107 1161 11AA;BC17;1107 1161 11AA; # (밗; 밗; 밗; 밗; 밗; ) HANGUL SYLLABLE BAGS +BC18;BC18;1107 1161 11AB;BC18;1107 1161 11AB; # (반; 반; 반; 반; 반; ) HANGUL SYLLABLE BAN +BC19;BC19;1107 1161 11AC;BC19;1107 1161 11AC; # (밙; 밙; 밙; 밙; 밙; ) HANGUL SYLLABLE BANJ +BC1A;BC1A;1107 1161 11AD;BC1A;1107 1161 11AD; # (밚; 밚; 밚; 밚; 밚; ) HANGUL SYLLABLE BANH +BC1B;BC1B;1107 1161 11AE;BC1B;1107 1161 11AE; # (받; 받; 받; 받; 받; ) HANGUL SYLLABLE BAD +BC1C;BC1C;1107 1161 11AF;BC1C;1107 1161 11AF; # (발; 발; 발; 발; 발; ) HANGUL SYLLABLE BAL +BC1D;BC1D;1107 1161 11B0;BC1D;1107 1161 11B0; # (밝; 밝; 밝; 밝; 밝; ) HANGUL SYLLABLE BALG +BC1E;BC1E;1107 1161 11B1;BC1E;1107 1161 11B1; # (밞; 밞; 밞; 밞; 밞; ) HANGUL SYLLABLE BALM +BC1F;BC1F;1107 1161 11B2;BC1F;1107 1161 11B2; # (밟; 밟; 밟; 밟; 밟; ) HANGUL SYLLABLE BALB +BC20;BC20;1107 1161 11B3;BC20;1107 1161 11B3; # (밠; 밠; 밠; 밠; 밠; ) HANGUL SYLLABLE BALS +BC21;BC21;1107 1161 11B4;BC21;1107 1161 11B4; # (밡; 밡; 밡; 밡; 밡; ) HANGUL SYLLABLE BALT +BC22;BC22;1107 1161 11B5;BC22;1107 1161 11B5; # (밢; 밢; 밢; 밢; 밢; ) HANGUL SYLLABLE BALP +BC23;BC23;1107 1161 11B6;BC23;1107 1161 11B6; # (밣; 밣; 밣; 밣; 밣; ) HANGUL SYLLABLE BALH +BC24;BC24;1107 1161 11B7;BC24;1107 1161 11B7; # (밤; 밤; 밤; 밤; 밤; ) HANGUL SYLLABLE BAM +BC25;BC25;1107 1161 11B8;BC25;1107 1161 11B8; # (밥; 밥; 밥; 밥; 밥; ) HANGUL SYLLABLE BAB +BC26;BC26;1107 1161 11B9;BC26;1107 1161 11B9; # (밦; 밦; 밦; 밦; 밦; ) HANGUL SYLLABLE BABS +BC27;BC27;1107 1161 11BA;BC27;1107 1161 11BA; # (밧; 밧; 밧; 밧; 밧; ) HANGUL SYLLABLE BAS +BC28;BC28;1107 1161 11BB;BC28;1107 1161 11BB; # (밨; 밨; 밨; 밨; 밨; ) HANGUL SYLLABLE BASS +BC29;BC29;1107 1161 11BC;BC29;1107 1161 11BC; # (방; 방; 방; 방; 방; ) HANGUL SYLLABLE BANG +BC2A;BC2A;1107 1161 11BD;BC2A;1107 1161 11BD; # (밪; 밪; 밪; 밪; 밪; ) HANGUL SYLLABLE BAJ +BC2B;BC2B;1107 1161 11BE;BC2B;1107 1161 11BE; # (밫; 밫; 밫; 밫; 밫; ) HANGUL SYLLABLE BAC +BC2C;BC2C;1107 1161 11BF;BC2C;1107 1161 11BF; # (밬; 밬; 밬; 밬; 밬; ) HANGUL SYLLABLE BAK +BC2D;BC2D;1107 1161 11C0;BC2D;1107 1161 11C0; # (밭; 밭; 밭; 밭; 밭; ) HANGUL SYLLABLE BAT +BC2E;BC2E;1107 1161 11C1;BC2E;1107 1161 11C1; # (밮; 밮; 밮; 밮; 밮; ) HANGUL SYLLABLE BAP +BC2F;BC2F;1107 1161 11C2;BC2F;1107 1161 11C2; # (밯; 밯; 밯; 밯; 밯; ) HANGUL SYLLABLE BAH +BC30;BC30;1107 1162;BC30;1107 1162; # (배; 배; 배; 배; 배; ) HANGUL SYLLABLE BAE +BC31;BC31;1107 1162 11A8;BC31;1107 1162 11A8; # (백; 백; 백; 백; 백; ) HANGUL SYLLABLE BAEG +BC32;BC32;1107 1162 11A9;BC32;1107 1162 11A9; # (밲; 밲; 밲; 밲; 밲; ) HANGUL SYLLABLE BAEGG +BC33;BC33;1107 1162 11AA;BC33;1107 1162 11AA; # (밳; 밳; 밳; 밳; 밳; ) HANGUL SYLLABLE BAEGS +BC34;BC34;1107 1162 11AB;BC34;1107 1162 11AB; # (밴; 밴; 밴; 밴; 밴; ) HANGUL SYLLABLE BAEN +BC35;BC35;1107 1162 11AC;BC35;1107 1162 11AC; # (밵; 밵; 밵; 밵; 밵; ) HANGUL SYLLABLE BAENJ +BC36;BC36;1107 1162 11AD;BC36;1107 1162 11AD; # (밶; 밶; 밶; 밶; 밶; ) HANGUL SYLLABLE BAENH +BC37;BC37;1107 1162 11AE;BC37;1107 1162 11AE; # (밷; 밷; 밷; 밷; 밷; ) HANGUL SYLLABLE BAED +BC38;BC38;1107 1162 11AF;BC38;1107 1162 11AF; # (밸; 밸; 밸; 밸; 밸; ) HANGUL SYLLABLE BAEL +BC39;BC39;1107 1162 11B0;BC39;1107 1162 11B0; # (밹; 밹; 밹; 밹; 밹; ) HANGUL SYLLABLE BAELG +BC3A;BC3A;1107 1162 11B1;BC3A;1107 1162 11B1; # (밺; 밺; 밺; 밺; 밺; ) HANGUL SYLLABLE BAELM +BC3B;BC3B;1107 1162 11B2;BC3B;1107 1162 11B2; # (밻; 밻; 밻; 밻; 밻; ) HANGUL SYLLABLE BAELB +BC3C;BC3C;1107 1162 11B3;BC3C;1107 1162 11B3; # (밼; 밼; 밼; 밼; 밼; ) HANGUL SYLLABLE BAELS +BC3D;BC3D;1107 1162 11B4;BC3D;1107 1162 11B4; # (밽; 밽; 밽; 밽; 밽; ) HANGUL SYLLABLE BAELT +BC3E;BC3E;1107 1162 11B5;BC3E;1107 1162 11B5; # (밾; 밾; 밾; 밾; 밾; ) HANGUL SYLLABLE BAELP +BC3F;BC3F;1107 1162 11B6;BC3F;1107 1162 11B6; # (밿; 밿; 밿; 밿; 밿; ) HANGUL SYLLABLE BAELH +BC40;BC40;1107 1162 11B7;BC40;1107 1162 11B7; # (뱀; 뱀; 뱀; 뱀; 뱀; ) HANGUL SYLLABLE BAEM +BC41;BC41;1107 1162 11B8;BC41;1107 1162 11B8; # (뱁; 뱁; 뱁; 뱁; 뱁; ) HANGUL SYLLABLE BAEB +BC42;BC42;1107 1162 11B9;BC42;1107 1162 11B9; # (뱂; 뱂; 뱂; 뱂; 뱂; ) HANGUL SYLLABLE BAEBS +BC43;BC43;1107 1162 11BA;BC43;1107 1162 11BA; # (뱃; 뱃; 뱃; 뱃; 뱃; ) HANGUL SYLLABLE BAES +BC44;BC44;1107 1162 11BB;BC44;1107 1162 11BB; # (뱄; 뱄; 뱄; 뱄; 뱄; ) HANGUL SYLLABLE BAESS +BC45;BC45;1107 1162 11BC;BC45;1107 1162 11BC; # (뱅; 뱅; 뱅; 뱅; 뱅; ) HANGUL SYLLABLE BAENG +BC46;BC46;1107 1162 11BD;BC46;1107 1162 11BD; # (뱆; 뱆; 뱆; 뱆; 뱆; ) HANGUL SYLLABLE BAEJ +BC47;BC47;1107 1162 11BE;BC47;1107 1162 11BE; # (뱇; 뱇; 뱇; 뱇; 뱇; ) HANGUL SYLLABLE BAEC +BC48;BC48;1107 1162 11BF;BC48;1107 1162 11BF; # (뱈; 뱈; 뱈; 뱈; 뱈; ) HANGUL SYLLABLE BAEK +BC49;BC49;1107 1162 11C0;BC49;1107 1162 11C0; # (뱉; 뱉; 뱉; 뱉; 뱉; ) HANGUL SYLLABLE BAET +BC4A;BC4A;1107 1162 11C1;BC4A;1107 1162 11C1; # (뱊; 뱊; 뱊; 뱊; 뱊; ) HANGUL SYLLABLE BAEP +BC4B;BC4B;1107 1162 11C2;BC4B;1107 1162 11C2; # (뱋; 뱋; 뱋; 뱋; 뱋; ) HANGUL SYLLABLE BAEH +BC4C;BC4C;1107 1163;BC4C;1107 1163; # (뱌; 뱌; 뱌; 뱌; 뱌; ) HANGUL SYLLABLE BYA +BC4D;BC4D;1107 1163 11A8;BC4D;1107 1163 11A8; # (뱍; 뱍; 뱍; 뱍; 뱍; ) HANGUL SYLLABLE BYAG +BC4E;BC4E;1107 1163 11A9;BC4E;1107 1163 11A9; # (뱎; 뱎; 뱎; 뱎; 뱎; ) HANGUL SYLLABLE BYAGG +BC4F;BC4F;1107 1163 11AA;BC4F;1107 1163 11AA; # (뱏; 뱏; 뱏; 뱏; 뱏; ) HANGUL SYLLABLE BYAGS +BC50;BC50;1107 1163 11AB;BC50;1107 1163 11AB; # (뱐; 뱐; 뱐; 뱐; 뱐; ) HANGUL SYLLABLE BYAN +BC51;BC51;1107 1163 11AC;BC51;1107 1163 11AC; # (뱑; 뱑; 뱑; 뱑; 뱑; ) HANGUL SYLLABLE BYANJ +BC52;BC52;1107 1163 11AD;BC52;1107 1163 11AD; # (뱒; 뱒; 뱒; 뱒; 뱒; ) HANGUL SYLLABLE BYANH +BC53;BC53;1107 1163 11AE;BC53;1107 1163 11AE; # (뱓; 뱓; 뱓; 뱓; 뱓; ) HANGUL SYLLABLE BYAD +BC54;BC54;1107 1163 11AF;BC54;1107 1163 11AF; # (뱔; 뱔; 뱔; 뱔; 뱔; ) HANGUL SYLLABLE BYAL +BC55;BC55;1107 1163 11B0;BC55;1107 1163 11B0; # (뱕; 뱕; 뱕; 뱕; 뱕; ) HANGUL SYLLABLE BYALG +BC56;BC56;1107 1163 11B1;BC56;1107 1163 11B1; # (뱖; 뱖; 뱖; 뱖; 뱖; ) HANGUL SYLLABLE BYALM +BC57;BC57;1107 1163 11B2;BC57;1107 1163 11B2; # (뱗; 뱗; 뱗; 뱗; 뱗; ) HANGUL SYLLABLE BYALB +BC58;BC58;1107 1163 11B3;BC58;1107 1163 11B3; # (뱘; 뱘; 뱘; 뱘; 뱘; ) HANGUL SYLLABLE BYALS +BC59;BC59;1107 1163 11B4;BC59;1107 1163 11B4; # (뱙; 뱙; 뱙; 뱙; 뱙; ) HANGUL SYLLABLE BYALT +BC5A;BC5A;1107 1163 11B5;BC5A;1107 1163 11B5; # (뱚; 뱚; 뱚; 뱚; 뱚; ) HANGUL SYLLABLE BYALP +BC5B;BC5B;1107 1163 11B6;BC5B;1107 1163 11B6; # (뱛; 뱛; 뱛; 뱛; 뱛; ) HANGUL SYLLABLE BYALH +BC5C;BC5C;1107 1163 11B7;BC5C;1107 1163 11B7; # (뱜; 뱜; 뱜; 뱜; 뱜; ) HANGUL SYLLABLE BYAM +BC5D;BC5D;1107 1163 11B8;BC5D;1107 1163 11B8; # (뱝; 뱝; 뱝; 뱝; 뱝; ) HANGUL SYLLABLE BYAB +BC5E;BC5E;1107 1163 11B9;BC5E;1107 1163 11B9; # (뱞; 뱞; 뱞; 뱞; 뱞; ) HANGUL SYLLABLE BYABS +BC5F;BC5F;1107 1163 11BA;BC5F;1107 1163 11BA; # (뱟; 뱟; 뱟; 뱟; 뱟; ) HANGUL SYLLABLE BYAS +BC60;BC60;1107 1163 11BB;BC60;1107 1163 11BB; # (뱠; 뱠; 뱠; 뱠; 뱠; ) HANGUL SYLLABLE BYASS +BC61;BC61;1107 1163 11BC;BC61;1107 1163 11BC; # (뱡; 뱡; 뱡; 뱡; 뱡; ) HANGUL SYLLABLE BYANG +BC62;BC62;1107 1163 11BD;BC62;1107 1163 11BD; # (뱢; 뱢; 뱢; 뱢; 뱢; ) HANGUL SYLLABLE BYAJ +BC63;BC63;1107 1163 11BE;BC63;1107 1163 11BE; # (뱣; 뱣; 뱣; 뱣; 뱣; ) HANGUL SYLLABLE BYAC +BC64;BC64;1107 1163 11BF;BC64;1107 1163 11BF; # (뱤; 뱤; 뱤; 뱤; 뱤; ) HANGUL SYLLABLE BYAK +BC65;BC65;1107 1163 11C0;BC65;1107 1163 11C0; # (뱥; 뱥; 뱥; 뱥; 뱥; ) HANGUL SYLLABLE BYAT +BC66;BC66;1107 1163 11C1;BC66;1107 1163 11C1; # (뱦; 뱦; 뱦; 뱦; 뱦; ) HANGUL SYLLABLE BYAP +BC67;BC67;1107 1163 11C2;BC67;1107 1163 11C2; # (뱧; 뱧; 뱧; 뱧; 뱧; ) HANGUL SYLLABLE BYAH +BC68;BC68;1107 1164;BC68;1107 1164; # (뱨; 뱨; 뱨; 뱨; 뱨; ) HANGUL SYLLABLE BYAE +BC69;BC69;1107 1164 11A8;BC69;1107 1164 11A8; # (뱩; 뱩; 뱩; 뱩; 뱩; ) HANGUL SYLLABLE BYAEG +BC6A;BC6A;1107 1164 11A9;BC6A;1107 1164 11A9; # (뱪; 뱪; 뱪; 뱪; 뱪; ) HANGUL SYLLABLE BYAEGG +BC6B;BC6B;1107 1164 11AA;BC6B;1107 1164 11AA; # (뱫; 뱫; 뱫; 뱫; 뱫; ) HANGUL SYLLABLE BYAEGS +BC6C;BC6C;1107 1164 11AB;BC6C;1107 1164 11AB; # (뱬; 뱬; 뱬; 뱬; 뱬; ) HANGUL SYLLABLE BYAEN +BC6D;BC6D;1107 1164 11AC;BC6D;1107 1164 11AC; # (뱭; 뱭; 뱭; 뱭; 뱭; ) HANGUL SYLLABLE BYAENJ +BC6E;BC6E;1107 1164 11AD;BC6E;1107 1164 11AD; # (뱮; 뱮; 뱮; 뱮; 뱮; ) HANGUL SYLLABLE BYAENH +BC6F;BC6F;1107 1164 11AE;BC6F;1107 1164 11AE; # (뱯; 뱯; 뱯; 뱯; 뱯; ) HANGUL SYLLABLE BYAED +BC70;BC70;1107 1164 11AF;BC70;1107 1164 11AF; # (뱰; 뱰; 뱰; 뱰; 뱰; ) HANGUL SYLLABLE BYAEL +BC71;BC71;1107 1164 11B0;BC71;1107 1164 11B0; # (뱱; 뱱; 뱱; 뱱; 뱱; ) HANGUL SYLLABLE BYAELG +BC72;BC72;1107 1164 11B1;BC72;1107 1164 11B1; # (뱲; 뱲; 뱲; 뱲; 뱲; ) HANGUL SYLLABLE BYAELM +BC73;BC73;1107 1164 11B2;BC73;1107 1164 11B2; # (뱳; 뱳; 뱳; 뱳; 뱳; ) HANGUL SYLLABLE BYAELB +BC74;BC74;1107 1164 11B3;BC74;1107 1164 11B3; # (뱴; 뱴; 뱴; 뱴; 뱴; ) HANGUL SYLLABLE BYAELS +BC75;BC75;1107 1164 11B4;BC75;1107 1164 11B4; # (뱵; 뱵; 뱵; 뱵; 뱵; ) HANGUL SYLLABLE BYAELT +BC76;BC76;1107 1164 11B5;BC76;1107 1164 11B5; # (뱶; 뱶; 뱶; 뱶; 뱶; ) HANGUL SYLLABLE BYAELP +BC77;BC77;1107 1164 11B6;BC77;1107 1164 11B6; # (뱷; 뱷; 뱷; 뱷; 뱷; ) HANGUL SYLLABLE BYAELH +BC78;BC78;1107 1164 11B7;BC78;1107 1164 11B7; # (뱸; 뱸; 뱸; 뱸; 뱸; ) HANGUL SYLLABLE BYAEM +BC79;BC79;1107 1164 11B8;BC79;1107 1164 11B8; # (뱹; 뱹; 뱹; 뱹; 뱹; ) HANGUL SYLLABLE BYAEB +BC7A;BC7A;1107 1164 11B9;BC7A;1107 1164 11B9; # (뱺; 뱺; 뱺; 뱺; 뱺; ) HANGUL SYLLABLE BYAEBS +BC7B;BC7B;1107 1164 11BA;BC7B;1107 1164 11BA; # (뱻; 뱻; 뱻; 뱻; 뱻; ) HANGUL SYLLABLE BYAES +BC7C;BC7C;1107 1164 11BB;BC7C;1107 1164 11BB; # (뱼; 뱼; 뱼; 뱼; 뱼; ) HANGUL SYLLABLE BYAESS +BC7D;BC7D;1107 1164 11BC;BC7D;1107 1164 11BC; # (뱽; 뱽; 뱽; 뱽; 뱽; ) HANGUL SYLLABLE BYAENG +BC7E;BC7E;1107 1164 11BD;BC7E;1107 1164 11BD; # (뱾; 뱾; 뱾; 뱾; 뱾; ) HANGUL SYLLABLE BYAEJ +BC7F;BC7F;1107 1164 11BE;BC7F;1107 1164 11BE; # (뱿; 뱿; 뱿; 뱿; 뱿; ) HANGUL SYLLABLE BYAEC +BC80;BC80;1107 1164 11BF;BC80;1107 1164 11BF; # (벀; 벀; 벀; 벀; 벀; ) HANGUL SYLLABLE BYAEK +BC81;BC81;1107 1164 11C0;BC81;1107 1164 11C0; # (벁; 벁; 벁; 벁; 벁; ) HANGUL SYLLABLE BYAET +BC82;BC82;1107 1164 11C1;BC82;1107 1164 11C1; # (벂; 벂; 벂; 벂; 벂; ) HANGUL SYLLABLE BYAEP +BC83;BC83;1107 1164 11C2;BC83;1107 1164 11C2; # (벃; 벃; 벃; 벃; 벃; ) HANGUL SYLLABLE BYAEH +BC84;BC84;1107 1165;BC84;1107 1165; # (버; 버; 버; 버; 버; ) HANGUL SYLLABLE BEO +BC85;BC85;1107 1165 11A8;BC85;1107 1165 11A8; # (벅; 벅; 벅; 벅; 벅; ) HANGUL SYLLABLE BEOG +BC86;BC86;1107 1165 11A9;BC86;1107 1165 11A9; # (벆; 벆; 벆; 벆; 벆; ) HANGUL SYLLABLE BEOGG +BC87;BC87;1107 1165 11AA;BC87;1107 1165 11AA; # (벇; 벇; 벇; 벇; 벇; ) HANGUL SYLLABLE BEOGS +BC88;BC88;1107 1165 11AB;BC88;1107 1165 11AB; # (번; 번; 번; 번; 번; ) HANGUL SYLLABLE BEON +BC89;BC89;1107 1165 11AC;BC89;1107 1165 11AC; # (벉; 벉; 벉; 벉; 벉; ) HANGUL SYLLABLE BEONJ +BC8A;BC8A;1107 1165 11AD;BC8A;1107 1165 11AD; # (벊; 벊; 벊; 벊; 벊; ) HANGUL SYLLABLE BEONH +BC8B;BC8B;1107 1165 11AE;BC8B;1107 1165 11AE; # (벋; 벋; 벋; 벋; 벋; ) HANGUL SYLLABLE BEOD +BC8C;BC8C;1107 1165 11AF;BC8C;1107 1165 11AF; # (벌; 벌; 벌; 벌; 벌; ) HANGUL SYLLABLE BEOL +BC8D;BC8D;1107 1165 11B0;BC8D;1107 1165 11B0; # (벍; 벍; 벍; 벍; 벍; ) HANGUL SYLLABLE BEOLG +BC8E;BC8E;1107 1165 11B1;BC8E;1107 1165 11B1; # (벎; 벎; 벎; 벎; 벎; ) HANGUL SYLLABLE BEOLM +BC8F;BC8F;1107 1165 11B2;BC8F;1107 1165 11B2; # (벏; 벏; 벏; 벏; 벏; ) HANGUL SYLLABLE BEOLB +BC90;BC90;1107 1165 11B3;BC90;1107 1165 11B3; # (벐; 벐; 벐; 벐; 벐; ) HANGUL SYLLABLE BEOLS +BC91;BC91;1107 1165 11B4;BC91;1107 1165 11B4; # (벑; 벑; 벑; 벑; 벑; ) HANGUL SYLLABLE BEOLT +BC92;BC92;1107 1165 11B5;BC92;1107 1165 11B5; # (벒; 벒; 벒; 벒; 벒; ) HANGUL SYLLABLE BEOLP +BC93;BC93;1107 1165 11B6;BC93;1107 1165 11B6; # (벓; 벓; 벓; 벓; 벓; ) HANGUL SYLLABLE BEOLH +BC94;BC94;1107 1165 11B7;BC94;1107 1165 11B7; # (범; 범; 범; 범; 범; ) HANGUL SYLLABLE BEOM +BC95;BC95;1107 1165 11B8;BC95;1107 1165 11B8; # (법; 법; 법; 법; 법; ) HANGUL SYLLABLE BEOB +BC96;BC96;1107 1165 11B9;BC96;1107 1165 11B9; # (벖; 벖; 벖; 벖; 벖; ) HANGUL SYLLABLE BEOBS +BC97;BC97;1107 1165 11BA;BC97;1107 1165 11BA; # (벗; 벗; 벗; 벗; 벗; ) HANGUL SYLLABLE BEOS +BC98;BC98;1107 1165 11BB;BC98;1107 1165 11BB; # (벘; 벘; 벘; 벘; 벘; ) HANGUL SYLLABLE BEOSS +BC99;BC99;1107 1165 11BC;BC99;1107 1165 11BC; # (벙; 벙; 벙; 벙; 벙; ) HANGUL SYLLABLE BEONG +BC9A;BC9A;1107 1165 11BD;BC9A;1107 1165 11BD; # (벚; 벚; 벚; 벚; 벚; ) HANGUL SYLLABLE BEOJ +BC9B;BC9B;1107 1165 11BE;BC9B;1107 1165 11BE; # (벛; 벛; 벛; 벛; 벛; ) HANGUL SYLLABLE BEOC +BC9C;BC9C;1107 1165 11BF;BC9C;1107 1165 11BF; # (벜; 벜; 벜; 벜; 벜; ) HANGUL SYLLABLE BEOK +BC9D;BC9D;1107 1165 11C0;BC9D;1107 1165 11C0; # (벝; 벝; 벝; 벝; 벝; ) HANGUL SYLLABLE BEOT +BC9E;BC9E;1107 1165 11C1;BC9E;1107 1165 11C1; # (벞; 벞; 벞; 벞; 벞; ) HANGUL SYLLABLE BEOP +BC9F;BC9F;1107 1165 11C2;BC9F;1107 1165 11C2; # (벟; 벟; 벟; 벟; 벟; ) HANGUL SYLLABLE BEOH +BCA0;BCA0;1107 1166;BCA0;1107 1166; # (베; 베; 베; 베; 베; ) HANGUL SYLLABLE BE +BCA1;BCA1;1107 1166 11A8;BCA1;1107 1166 11A8; # (벡; 벡; 벡; 벡; 벡; ) HANGUL SYLLABLE BEG +BCA2;BCA2;1107 1166 11A9;BCA2;1107 1166 11A9; # (벢; 벢; 벢; 벢; 벢; ) HANGUL SYLLABLE BEGG +BCA3;BCA3;1107 1166 11AA;BCA3;1107 1166 11AA; # (벣; 벣; 벣; 벣; 벣; ) HANGUL SYLLABLE BEGS +BCA4;BCA4;1107 1166 11AB;BCA4;1107 1166 11AB; # (벤; 벤; 벤; 벤; 벤; ) HANGUL SYLLABLE BEN +BCA5;BCA5;1107 1166 11AC;BCA5;1107 1166 11AC; # (벥; 벥; 벥; 벥; 벥; ) HANGUL SYLLABLE BENJ +BCA6;BCA6;1107 1166 11AD;BCA6;1107 1166 11AD; # (벦; 벦; 벦; 벦; 벦; ) HANGUL SYLLABLE BENH +BCA7;BCA7;1107 1166 11AE;BCA7;1107 1166 11AE; # (벧; 벧; 벧; 벧; 벧; ) HANGUL SYLLABLE BED +BCA8;BCA8;1107 1166 11AF;BCA8;1107 1166 11AF; # (벨; 벨; 벨; 벨; 벨; ) HANGUL SYLLABLE BEL +BCA9;BCA9;1107 1166 11B0;BCA9;1107 1166 11B0; # (벩; 벩; 벩; 벩; 벩; ) HANGUL SYLLABLE BELG +BCAA;BCAA;1107 1166 11B1;BCAA;1107 1166 11B1; # (벪; 벪; 벪; 벪; 벪; ) HANGUL SYLLABLE BELM +BCAB;BCAB;1107 1166 11B2;BCAB;1107 1166 11B2; # (벫; 벫; 벫; 벫; 벫; ) HANGUL SYLLABLE BELB +BCAC;BCAC;1107 1166 11B3;BCAC;1107 1166 11B3; # (벬; 벬; 벬; 벬; 벬; ) HANGUL SYLLABLE BELS +BCAD;BCAD;1107 1166 11B4;BCAD;1107 1166 11B4; # (벭; 벭; 벭; 벭; 벭; ) HANGUL SYLLABLE BELT +BCAE;BCAE;1107 1166 11B5;BCAE;1107 1166 11B5; # (벮; 벮; 벮; 벮; 벮; ) HANGUL SYLLABLE BELP +BCAF;BCAF;1107 1166 11B6;BCAF;1107 1166 11B6; # (벯; 벯; 벯; 벯; 벯; ) HANGUL SYLLABLE BELH +BCB0;BCB0;1107 1166 11B7;BCB0;1107 1166 11B7; # (벰; 벰; 벰; 벰; 벰; ) HANGUL SYLLABLE BEM +BCB1;BCB1;1107 1166 11B8;BCB1;1107 1166 11B8; # (벱; 벱; 벱; 벱; 벱; ) HANGUL SYLLABLE BEB +BCB2;BCB2;1107 1166 11B9;BCB2;1107 1166 11B9; # (벲; 벲; 벲; 벲; 벲; ) HANGUL SYLLABLE BEBS +BCB3;BCB3;1107 1166 11BA;BCB3;1107 1166 11BA; # (벳; 벳; 벳; 벳; 벳; ) HANGUL SYLLABLE BES +BCB4;BCB4;1107 1166 11BB;BCB4;1107 1166 11BB; # (벴; 벴; 벴; 벴; 벴; ) HANGUL SYLLABLE BESS +BCB5;BCB5;1107 1166 11BC;BCB5;1107 1166 11BC; # (벵; 벵; 벵; 벵; 벵; ) HANGUL SYLLABLE BENG +BCB6;BCB6;1107 1166 11BD;BCB6;1107 1166 11BD; # (벶; 벶; 벶; 벶; 벶; ) HANGUL SYLLABLE BEJ +BCB7;BCB7;1107 1166 11BE;BCB7;1107 1166 11BE; # (벷; 벷; 벷; 벷; 벷; ) HANGUL SYLLABLE BEC +BCB8;BCB8;1107 1166 11BF;BCB8;1107 1166 11BF; # (벸; 벸; 벸; 벸; 벸; ) HANGUL SYLLABLE BEK +BCB9;BCB9;1107 1166 11C0;BCB9;1107 1166 11C0; # (벹; 벹; 벹; 벹; 벹; ) HANGUL SYLLABLE BET +BCBA;BCBA;1107 1166 11C1;BCBA;1107 1166 11C1; # (벺; 벺; 벺; 벺; 벺; ) HANGUL SYLLABLE BEP +BCBB;BCBB;1107 1166 11C2;BCBB;1107 1166 11C2; # (벻; 벻; 벻; 벻; 벻; ) HANGUL SYLLABLE BEH +BCBC;BCBC;1107 1167;BCBC;1107 1167; # (벼; 벼; 벼; 벼; 벼; ) HANGUL SYLLABLE BYEO +BCBD;BCBD;1107 1167 11A8;BCBD;1107 1167 11A8; # (벽; 벽; 벽; 벽; 벽; ) HANGUL SYLLABLE BYEOG +BCBE;BCBE;1107 1167 11A9;BCBE;1107 1167 11A9; # (벾; 벾; 벾; 벾; 벾; ) HANGUL SYLLABLE BYEOGG +BCBF;BCBF;1107 1167 11AA;BCBF;1107 1167 11AA; # (벿; 벿; 벿; 벿; 벿; ) HANGUL SYLLABLE BYEOGS +BCC0;BCC0;1107 1167 11AB;BCC0;1107 1167 11AB; # (변; 변; 변; 변; 변; ) HANGUL SYLLABLE BYEON +BCC1;BCC1;1107 1167 11AC;BCC1;1107 1167 11AC; # (볁; 볁; 볁; 볁; 볁; ) HANGUL SYLLABLE BYEONJ +BCC2;BCC2;1107 1167 11AD;BCC2;1107 1167 11AD; # (볂; 볂; 볂; 볂; 볂; ) HANGUL SYLLABLE BYEONH +BCC3;BCC3;1107 1167 11AE;BCC3;1107 1167 11AE; # (볃; 볃; 볃; 볃; 볃; ) HANGUL SYLLABLE BYEOD +BCC4;BCC4;1107 1167 11AF;BCC4;1107 1167 11AF; # (별; 별; 별; 별; 별; ) HANGUL SYLLABLE BYEOL +BCC5;BCC5;1107 1167 11B0;BCC5;1107 1167 11B0; # (볅; 볅; 볅; 볅; 볅; ) HANGUL SYLLABLE BYEOLG +BCC6;BCC6;1107 1167 11B1;BCC6;1107 1167 11B1; # (볆; 볆; 볆; 볆; 볆; ) HANGUL SYLLABLE BYEOLM +BCC7;BCC7;1107 1167 11B2;BCC7;1107 1167 11B2; # (볇; 볇; 볇; 볇; 볇; ) HANGUL SYLLABLE BYEOLB +BCC8;BCC8;1107 1167 11B3;BCC8;1107 1167 11B3; # (볈; 볈; 볈; 볈; 볈; ) HANGUL SYLLABLE BYEOLS +BCC9;BCC9;1107 1167 11B4;BCC9;1107 1167 11B4; # (볉; 볉; 볉; 볉; 볉; ) HANGUL SYLLABLE BYEOLT +BCCA;BCCA;1107 1167 11B5;BCCA;1107 1167 11B5; # (볊; 볊; 볊; 볊; 볊; ) HANGUL SYLLABLE BYEOLP +BCCB;BCCB;1107 1167 11B6;BCCB;1107 1167 11B6; # (볋; 볋; 볋; 볋; 볋; ) HANGUL SYLLABLE BYEOLH +BCCC;BCCC;1107 1167 11B7;BCCC;1107 1167 11B7; # (볌; 볌; 볌; 볌; 볌; ) HANGUL SYLLABLE BYEOM +BCCD;BCCD;1107 1167 11B8;BCCD;1107 1167 11B8; # (볍; 볍; 볍; 볍; 볍; ) HANGUL SYLLABLE BYEOB +BCCE;BCCE;1107 1167 11B9;BCCE;1107 1167 11B9; # (볎; 볎; 볎; 볎; 볎; ) HANGUL SYLLABLE BYEOBS +BCCF;BCCF;1107 1167 11BA;BCCF;1107 1167 11BA; # (볏; 볏; 볏; 볏; 볏; ) HANGUL SYLLABLE BYEOS +BCD0;BCD0;1107 1167 11BB;BCD0;1107 1167 11BB; # (볐; 볐; 볐; 볐; 볐; ) HANGUL SYLLABLE BYEOSS +BCD1;BCD1;1107 1167 11BC;BCD1;1107 1167 11BC; # (병; 병; 병; 병; 병; ) HANGUL SYLLABLE BYEONG +BCD2;BCD2;1107 1167 11BD;BCD2;1107 1167 11BD; # (볒; 볒; 볒; 볒; 볒; ) HANGUL SYLLABLE BYEOJ +BCD3;BCD3;1107 1167 11BE;BCD3;1107 1167 11BE; # (볓; 볓; 볓; 볓; 볓; ) HANGUL SYLLABLE BYEOC +BCD4;BCD4;1107 1167 11BF;BCD4;1107 1167 11BF; # (볔; 볔; 볔; 볔; 볔; ) HANGUL SYLLABLE BYEOK +BCD5;BCD5;1107 1167 11C0;BCD5;1107 1167 11C0; # (볕; 볕; 볕; 볕; 볕; ) HANGUL SYLLABLE BYEOT +BCD6;BCD6;1107 1167 11C1;BCD6;1107 1167 11C1; # (볖; 볖; 볖; 볖; 볖; ) HANGUL SYLLABLE BYEOP +BCD7;BCD7;1107 1167 11C2;BCD7;1107 1167 11C2; # (볗; 볗; 볗; 볗; 볗; ) HANGUL SYLLABLE BYEOH +BCD8;BCD8;1107 1168;BCD8;1107 1168; # (볘; 볘; 볘; 볘; 볘; ) HANGUL SYLLABLE BYE +BCD9;BCD9;1107 1168 11A8;BCD9;1107 1168 11A8; # (볙; 볙; 볙; 볙; 볙; ) HANGUL SYLLABLE BYEG +BCDA;BCDA;1107 1168 11A9;BCDA;1107 1168 11A9; # (볚; 볚; 볚; 볚; 볚; ) HANGUL SYLLABLE BYEGG +BCDB;BCDB;1107 1168 11AA;BCDB;1107 1168 11AA; # (볛; 볛; 볛; 볛; 볛; ) HANGUL SYLLABLE BYEGS +BCDC;BCDC;1107 1168 11AB;BCDC;1107 1168 11AB; # (볜; 볜; 볜; 볜; 볜; ) HANGUL SYLLABLE BYEN +BCDD;BCDD;1107 1168 11AC;BCDD;1107 1168 11AC; # (볝; 볝; 볝; 볝; 볝; ) HANGUL SYLLABLE BYENJ +BCDE;BCDE;1107 1168 11AD;BCDE;1107 1168 11AD; # (볞; 볞; 볞; 볞; 볞; ) HANGUL SYLLABLE BYENH +BCDF;BCDF;1107 1168 11AE;BCDF;1107 1168 11AE; # (볟; 볟; 볟; 볟; 볟; ) HANGUL SYLLABLE BYED +BCE0;BCE0;1107 1168 11AF;BCE0;1107 1168 11AF; # (볠; 볠; 볠; 볠; 볠; ) HANGUL SYLLABLE BYEL +BCE1;BCE1;1107 1168 11B0;BCE1;1107 1168 11B0; # (볡; 볡; 볡; 볡; 볡; ) HANGUL SYLLABLE BYELG +BCE2;BCE2;1107 1168 11B1;BCE2;1107 1168 11B1; # (볢; 볢; 볢; 볢; 볢; ) HANGUL SYLLABLE BYELM +BCE3;BCE3;1107 1168 11B2;BCE3;1107 1168 11B2; # (볣; 볣; 볣; 볣; 볣; ) HANGUL SYLLABLE BYELB +BCE4;BCE4;1107 1168 11B3;BCE4;1107 1168 11B3; # (볤; 볤; 볤; 볤; 볤; ) HANGUL SYLLABLE BYELS +BCE5;BCE5;1107 1168 11B4;BCE5;1107 1168 11B4; # (볥; 볥; 볥; 볥; 볥; ) HANGUL SYLLABLE BYELT +BCE6;BCE6;1107 1168 11B5;BCE6;1107 1168 11B5; # (볦; 볦; 볦; 볦; 볦; ) HANGUL SYLLABLE BYELP +BCE7;BCE7;1107 1168 11B6;BCE7;1107 1168 11B6; # (볧; 볧; 볧; 볧; 볧; ) HANGUL SYLLABLE BYELH +BCE8;BCE8;1107 1168 11B7;BCE8;1107 1168 11B7; # (볨; 볨; 볨; 볨; 볨; ) HANGUL SYLLABLE BYEM +BCE9;BCE9;1107 1168 11B8;BCE9;1107 1168 11B8; # (볩; 볩; 볩; 볩; 볩; ) HANGUL SYLLABLE BYEB +BCEA;BCEA;1107 1168 11B9;BCEA;1107 1168 11B9; # (볪; 볪; 볪; 볪; 볪; ) HANGUL SYLLABLE BYEBS +BCEB;BCEB;1107 1168 11BA;BCEB;1107 1168 11BA; # (볫; 볫; 볫; 볫; 볫; ) HANGUL SYLLABLE BYES +BCEC;BCEC;1107 1168 11BB;BCEC;1107 1168 11BB; # (볬; 볬; 볬; 볬; 볬; ) HANGUL SYLLABLE BYESS +BCED;BCED;1107 1168 11BC;BCED;1107 1168 11BC; # (볭; 볭; 볭; 볭; 볭; ) HANGUL SYLLABLE BYENG +BCEE;BCEE;1107 1168 11BD;BCEE;1107 1168 11BD; # (볮; 볮; 볮; 볮; 볮; ) HANGUL SYLLABLE BYEJ +BCEF;BCEF;1107 1168 11BE;BCEF;1107 1168 11BE; # (볯; 볯; 볯; 볯; 볯; ) HANGUL SYLLABLE BYEC +BCF0;BCF0;1107 1168 11BF;BCF0;1107 1168 11BF; # (볰; 볰; 볰; 볰; 볰; ) HANGUL SYLLABLE BYEK +BCF1;BCF1;1107 1168 11C0;BCF1;1107 1168 11C0; # (볱; 볱; 볱; 볱; 볱; ) HANGUL SYLLABLE BYET +BCF2;BCF2;1107 1168 11C1;BCF2;1107 1168 11C1; # (볲; 볲; 볲; 볲; 볲; ) HANGUL SYLLABLE BYEP +BCF3;BCF3;1107 1168 11C2;BCF3;1107 1168 11C2; # (볳; 볳; 볳; 볳; 볳; ) HANGUL SYLLABLE BYEH +BCF4;BCF4;1107 1169;BCF4;1107 1169; # (보; 보; 보; 보; 보; ) HANGUL SYLLABLE BO +BCF5;BCF5;1107 1169 11A8;BCF5;1107 1169 11A8; # (복; 복; 복; 복; 복; ) HANGUL SYLLABLE BOG +BCF6;BCF6;1107 1169 11A9;BCF6;1107 1169 11A9; # (볶; 볶; 볶; 볶; 볶; ) HANGUL SYLLABLE BOGG +BCF7;BCF7;1107 1169 11AA;BCF7;1107 1169 11AA; # (볷; 볷; 볷; 볷; 볷; ) HANGUL SYLLABLE BOGS +BCF8;BCF8;1107 1169 11AB;BCF8;1107 1169 11AB; # (본; 본; 본; 본; 본; ) HANGUL SYLLABLE BON +BCF9;BCF9;1107 1169 11AC;BCF9;1107 1169 11AC; # (볹; 볹; 볹; 볹; 볹; ) HANGUL SYLLABLE BONJ +BCFA;BCFA;1107 1169 11AD;BCFA;1107 1169 11AD; # (볺; 볺; 볺; 볺; 볺; ) HANGUL SYLLABLE BONH +BCFB;BCFB;1107 1169 11AE;BCFB;1107 1169 11AE; # (볻; 볻; 볻; 볻; 볻; ) HANGUL SYLLABLE BOD +BCFC;BCFC;1107 1169 11AF;BCFC;1107 1169 11AF; # (볼; 볼; 볼; 볼; 볼; ) HANGUL SYLLABLE BOL +BCFD;BCFD;1107 1169 11B0;BCFD;1107 1169 11B0; # (볽; 볽; 볽; 볽; 볽; ) HANGUL SYLLABLE BOLG +BCFE;BCFE;1107 1169 11B1;BCFE;1107 1169 11B1; # (볾; 볾; 볾; 볾; 볾; ) HANGUL SYLLABLE BOLM +BCFF;BCFF;1107 1169 11B2;BCFF;1107 1169 11B2; # (볿; 볿; 볿; 볿; 볿; ) HANGUL SYLLABLE BOLB +BD00;BD00;1107 1169 11B3;BD00;1107 1169 11B3; # (봀; 봀; 봀; 봀; 봀; ) HANGUL SYLLABLE BOLS +BD01;BD01;1107 1169 11B4;BD01;1107 1169 11B4; # (봁; 봁; 봁; 봁; 봁; ) HANGUL SYLLABLE BOLT +BD02;BD02;1107 1169 11B5;BD02;1107 1169 11B5; # (봂; 봂; 봂; 봂; 봂; ) HANGUL SYLLABLE BOLP +BD03;BD03;1107 1169 11B6;BD03;1107 1169 11B6; # (봃; 봃; 봃; 봃; 봃; ) HANGUL SYLLABLE BOLH +BD04;BD04;1107 1169 11B7;BD04;1107 1169 11B7; # (봄; 봄; 봄; 봄; 봄; ) HANGUL SYLLABLE BOM +BD05;BD05;1107 1169 11B8;BD05;1107 1169 11B8; # (봅; 봅; 봅; 봅; 봅; ) HANGUL SYLLABLE BOB +BD06;BD06;1107 1169 11B9;BD06;1107 1169 11B9; # (봆; 봆; 봆; 봆; 봆; ) HANGUL SYLLABLE BOBS +BD07;BD07;1107 1169 11BA;BD07;1107 1169 11BA; # (봇; 봇; 봇; 봇; 봇; ) HANGUL SYLLABLE BOS +BD08;BD08;1107 1169 11BB;BD08;1107 1169 11BB; # (봈; 봈; 봈; 봈; 봈; ) HANGUL SYLLABLE BOSS +BD09;BD09;1107 1169 11BC;BD09;1107 1169 11BC; # (봉; 봉; 봉; 봉; 봉; ) HANGUL SYLLABLE BONG +BD0A;BD0A;1107 1169 11BD;BD0A;1107 1169 11BD; # (봊; 봊; 봊; 봊; 봊; ) HANGUL SYLLABLE BOJ +BD0B;BD0B;1107 1169 11BE;BD0B;1107 1169 11BE; # (봋; 봋; 봋; 봋; 봋; ) HANGUL SYLLABLE BOC +BD0C;BD0C;1107 1169 11BF;BD0C;1107 1169 11BF; # (봌; 봌; 봌; 봌; 봌; ) HANGUL SYLLABLE BOK +BD0D;BD0D;1107 1169 11C0;BD0D;1107 1169 11C0; # (봍; 봍; 봍; 봍; 봍; ) HANGUL SYLLABLE BOT +BD0E;BD0E;1107 1169 11C1;BD0E;1107 1169 11C1; # (봎; 봎; 봎; 봎; 봎; ) HANGUL SYLLABLE BOP +BD0F;BD0F;1107 1169 11C2;BD0F;1107 1169 11C2; # (봏; 봏; 봏; 봏; 봏; ) HANGUL SYLLABLE BOH +BD10;BD10;1107 116A;BD10;1107 116A; # (봐; 봐; 봐; 봐; 봐; ) HANGUL SYLLABLE BWA +BD11;BD11;1107 116A 11A8;BD11;1107 116A 11A8; # (봑; 봑; 봑; 봑; 봑; ) HANGUL SYLLABLE BWAG +BD12;BD12;1107 116A 11A9;BD12;1107 116A 11A9; # (봒; 봒; 봒; 봒; 봒; ) HANGUL SYLLABLE BWAGG +BD13;BD13;1107 116A 11AA;BD13;1107 116A 11AA; # (봓; 봓; 봓; 봓; 봓; ) HANGUL SYLLABLE BWAGS +BD14;BD14;1107 116A 11AB;BD14;1107 116A 11AB; # (봔; 봔; 봔; 봔; 봔; ) HANGUL SYLLABLE BWAN +BD15;BD15;1107 116A 11AC;BD15;1107 116A 11AC; # (봕; 봕; 봕; 봕; 봕; ) HANGUL SYLLABLE BWANJ +BD16;BD16;1107 116A 11AD;BD16;1107 116A 11AD; # (봖; 봖; 봖; 봖; 봖; ) HANGUL SYLLABLE BWANH +BD17;BD17;1107 116A 11AE;BD17;1107 116A 11AE; # (봗; 봗; 봗; 봗; 봗; ) HANGUL SYLLABLE BWAD +BD18;BD18;1107 116A 11AF;BD18;1107 116A 11AF; # (봘; 봘; 봘; 봘; 봘; ) HANGUL SYLLABLE BWAL +BD19;BD19;1107 116A 11B0;BD19;1107 116A 11B0; # (봙; 봙; 봙; 봙; 봙; ) HANGUL SYLLABLE BWALG +BD1A;BD1A;1107 116A 11B1;BD1A;1107 116A 11B1; # (봚; 봚; 봚; 봚; 봚; ) HANGUL SYLLABLE BWALM +BD1B;BD1B;1107 116A 11B2;BD1B;1107 116A 11B2; # (봛; 봛; 봛; 봛; 봛; ) HANGUL SYLLABLE BWALB +BD1C;BD1C;1107 116A 11B3;BD1C;1107 116A 11B3; # (봜; 봜; 봜; 봜; 봜; ) HANGUL SYLLABLE BWALS +BD1D;BD1D;1107 116A 11B4;BD1D;1107 116A 11B4; # (봝; 봝; 봝; 봝; 봝; ) HANGUL SYLLABLE BWALT +BD1E;BD1E;1107 116A 11B5;BD1E;1107 116A 11B5; # (봞; 봞; 봞; 봞; 봞; ) HANGUL SYLLABLE BWALP +BD1F;BD1F;1107 116A 11B6;BD1F;1107 116A 11B6; # (봟; 봟; 봟; 봟; 봟; ) HANGUL SYLLABLE BWALH +BD20;BD20;1107 116A 11B7;BD20;1107 116A 11B7; # (봠; 봠; 봠; 봠; 봠; ) HANGUL SYLLABLE BWAM +BD21;BD21;1107 116A 11B8;BD21;1107 116A 11B8; # (봡; 봡; 봡; 봡; 봡; ) HANGUL SYLLABLE BWAB +BD22;BD22;1107 116A 11B9;BD22;1107 116A 11B9; # (봢; 봢; 봢; 봢; 봢; ) HANGUL SYLLABLE BWABS +BD23;BD23;1107 116A 11BA;BD23;1107 116A 11BA; # (봣; 봣; 봣; 봣; 봣; ) HANGUL SYLLABLE BWAS +BD24;BD24;1107 116A 11BB;BD24;1107 116A 11BB; # (봤; 봤; 봤; 봤; 봤; ) HANGUL SYLLABLE BWASS +BD25;BD25;1107 116A 11BC;BD25;1107 116A 11BC; # (봥; 봥; 봥; 봥; 봥; ) HANGUL SYLLABLE BWANG +BD26;BD26;1107 116A 11BD;BD26;1107 116A 11BD; # (봦; 봦; 봦; 봦; 봦; ) HANGUL SYLLABLE BWAJ +BD27;BD27;1107 116A 11BE;BD27;1107 116A 11BE; # (봧; 봧; 봧; 봧; 봧; ) HANGUL SYLLABLE BWAC +BD28;BD28;1107 116A 11BF;BD28;1107 116A 11BF; # (봨; 봨; 봨; 봨; 봨; ) HANGUL SYLLABLE BWAK +BD29;BD29;1107 116A 11C0;BD29;1107 116A 11C0; # (봩; 봩; 봩; 봩; 봩; ) HANGUL SYLLABLE BWAT +BD2A;BD2A;1107 116A 11C1;BD2A;1107 116A 11C1; # (봪; 봪; 봪; 봪; 봪; ) HANGUL SYLLABLE BWAP +BD2B;BD2B;1107 116A 11C2;BD2B;1107 116A 11C2; # (봫; 봫; 봫; 봫; 봫; ) HANGUL SYLLABLE BWAH +BD2C;BD2C;1107 116B;BD2C;1107 116B; # (봬; 봬; 봬; 봬; 봬; ) HANGUL SYLLABLE BWAE +BD2D;BD2D;1107 116B 11A8;BD2D;1107 116B 11A8; # (봭; 봭; 봭; 봭; 봭; ) HANGUL SYLLABLE BWAEG +BD2E;BD2E;1107 116B 11A9;BD2E;1107 116B 11A9; # (봮; 봮; 봮; 봮; 봮; ) HANGUL SYLLABLE BWAEGG +BD2F;BD2F;1107 116B 11AA;BD2F;1107 116B 11AA; # (봯; 봯; 봯; 봯; 봯; ) HANGUL SYLLABLE BWAEGS +BD30;BD30;1107 116B 11AB;BD30;1107 116B 11AB; # (봰; 봰; 봰; 봰; 봰; ) HANGUL SYLLABLE BWAEN +BD31;BD31;1107 116B 11AC;BD31;1107 116B 11AC; # (봱; 봱; 봱; 봱; 봱; ) HANGUL SYLLABLE BWAENJ +BD32;BD32;1107 116B 11AD;BD32;1107 116B 11AD; # (봲; 봲; 봲; 봲; 봲; ) HANGUL SYLLABLE BWAENH +BD33;BD33;1107 116B 11AE;BD33;1107 116B 11AE; # (봳; 봳; 봳; 봳; 봳; ) HANGUL SYLLABLE BWAED +BD34;BD34;1107 116B 11AF;BD34;1107 116B 11AF; # (봴; 봴; 봴; 봴; 봴; ) HANGUL SYLLABLE BWAEL +BD35;BD35;1107 116B 11B0;BD35;1107 116B 11B0; # (봵; 봵; 봵; 봵; 봵; ) HANGUL SYLLABLE BWAELG +BD36;BD36;1107 116B 11B1;BD36;1107 116B 11B1; # (봶; 봶; 봶; 봶; 봶; ) HANGUL SYLLABLE BWAELM +BD37;BD37;1107 116B 11B2;BD37;1107 116B 11B2; # (봷; 봷; 봷; 봷; 봷; ) HANGUL SYLLABLE BWAELB +BD38;BD38;1107 116B 11B3;BD38;1107 116B 11B3; # (봸; 봸; 봸; 봸; 봸; ) HANGUL SYLLABLE BWAELS +BD39;BD39;1107 116B 11B4;BD39;1107 116B 11B4; # (봹; 봹; 봹; 봹; 봹; ) HANGUL SYLLABLE BWAELT +BD3A;BD3A;1107 116B 11B5;BD3A;1107 116B 11B5; # (봺; 봺; 봺; 봺; 봺; ) HANGUL SYLLABLE BWAELP +BD3B;BD3B;1107 116B 11B6;BD3B;1107 116B 11B6; # (봻; 봻; 봻; 봻; 봻; ) HANGUL SYLLABLE BWAELH +BD3C;BD3C;1107 116B 11B7;BD3C;1107 116B 11B7; # (봼; 봼; 봼; 봼; 봼; ) HANGUL SYLLABLE BWAEM +BD3D;BD3D;1107 116B 11B8;BD3D;1107 116B 11B8; # (봽; 봽; 봽; 봽; 봽; ) HANGUL SYLLABLE BWAEB +BD3E;BD3E;1107 116B 11B9;BD3E;1107 116B 11B9; # (봾; 봾; 봾; 봾; 봾; ) HANGUL SYLLABLE BWAEBS +BD3F;BD3F;1107 116B 11BA;BD3F;1107 116B 11BA; # (봿; 봿; 봿; 봿; 봿; ) HANGUL SYLLABLE BWAES +BD40;BD40;1107 116B 11BB;BD40;1107 116B 11BB; # (뵀; 뵀; 뵀; 뵀; 뵀; ) HANGUL SYLLABLE BWAESS +BD41;BD41;1107 116B 11BC;BD41;1107 116B 11BC; # (뵁; 뵁; 뵁; 뵁; 뵁; ) HANGUL SYLLABLE BWAENG +BD42;BD42;1107 116B 11BD;BD42;1107 116B 11BD; # (뵂; 뵂; 뵂; 뵂; 뵂; ) HANGUL SYLLABLE BWAEJ +BD43;BD43;1107 116B 11BE;BD43;1107 116B 11BE; # (뵃; 뵃; 뵃; 뵃; 뵃; ) HANGUL SYLLABLE BWAEC +BD44;BD44;1107 116B 11BF;BD44;1107 116B 11BF; # (뵄; 뵄; 뵄; 뵄; 뵄; ) HANGUL SYLLABLE BWAEK +BD45;BD45;1107 116B 11C0;BD45;1107 116B 11C0; # (뵅; 뵅; 뵅; 뵅; 뵅; ) HANGUL SYLLABLE BWAET +BD46;BD46;1107 116B 11C1;BD46;1107 116B 11C1; # (뵆; 뵆; 뵆; 뵆; 뵆; ) HANGUL SYLLABLE BWAEP +BD47;BD47;1107 116B 11C2;BD47;1107 116B 11C2; # (뵇; 뵇; 뵇; 뵇; 뵇; ) HANGUL SYLLABLE BWAEH +BD48;BD48;1107 116C;BD48;1107 116C; # (뵈; 뵈; 뵈; 뵈; 뵈; ) HANGUL SYLLABLE BOE +BD49;BD49;1107 116C 11A8;BD49;1107 116C 11A8; # (뵉; 뵉; 뵉; 뵉; 뵉; ) HANGUL SYLLABLE BOEG +BD4A;BD4A;1107 116C 11A9;BD4A;1107 116C 11A9; # (뵊; 뵊; 뵊; 뵊; 뵊; ) HANGUL SYLLABLE BOEGG +BD4B;BD4B;1107 116C 11AA;BD4B;1107 116C 11AA; # (뵋; 뵋; 뵋; 뵋; 뵋; ) HANGUL SYLLABLE BOEGS +BD4C;BD4C;1107 116C 11AB;BD4C;1107 116C 11AB; # (뵌; 뵌; 뵌; 뵌; 뵌; ) HANGUL SYLLABLE BOEN +BD4D;BD4D;1107 116C 11AC;BD4D;1107 116C 11AC; # (뵍; 뵍; 뵍; 뵍; 뵍; ) HANGUL SYLLABLE BOENJ +BD4E;BD4E;1107 116C 11AD;BD4E;1107 116C 11AD; # (뵎; 뵎; 뵎; 뵎; 뵎; ) HANGUL SYLLABLE BOENH +BD4F;BD4F;1107 116C 11AE;BD4F;1107 116C 11AE; # (뵏; 뵏; 뵏; 뵏; 뵏; ) HANGUL SYLLABLE BOED +BD50;BD50;1107 116C 11AF;BD50;1107 116C 11AF; # (뵐; 뵐; 뵐; 뵐; 뵐; ) HANGUL SYLLABLE BOEL +BD51;BD51;1107 116C 11B0;BD51;1107 116C 11B0; # (뵑; 뵑; 뵑; 뵑; 뵑; ) HANGUL SYLLABLE BOELG +BD52;BD52;1107 116C 11B1;BD52;1107 116C 11B1; # (뵒; 뵒; 뵒; 뵒; 뵒; ) HANGUL SYLLABLE BOELM +BD53;BD53;1107 116C 11B2;BD53;1107 116C 11B2; # (뵓; 뵓; 뵓; 뵓; 뵓; ) HANGUL SYLLABLE BOELB +BD54;BD54;1107 116C 11B3;BD54;1107 116C 11B3; # (뵔; 뵔; 뵔; 뵔; 뵔; ) HANGUL SYLLABLE BOELS +BD55;BD55;1107 116C 11B4;BD55;1107 116C 11B4; # (뵕; 뵕; 뵕; 뵕; 뵕; ) HANGUL SYLLABLE BOELT +BD56;BD56;1107 116C 11B5;BD56;1107 116C 11B5; # (뵖; 뵖; 뵖; 뵖; 뵖; ) HANGUL SYLLABLE BOELP +BD57;BD57;1107 116C 11B6;BD57;1107 116C 11B6; # (뵗; 뵗; 뵗; 뵗; 뵗; ) HANGUL SYLLABLE BOELH +BD58;BD58;1107 116C 11B7;BD58;1107 116C 11B7; # (뵘; 뵘; 뵘; 뵘; 뵘; ) HANGUL SYLLABLE BOEM +BD59;BD59;1107 116C 11B8;BD59;1107 116C 11B8; # (뵙; 뵙; 뵙; 뵙; 뵙; ) HANGUL SYLLABLE BOEB +BD5A;BD5A;1107 116C 11B9;BD5A;1107 116C 11B9; # (뵚; 뵚; 뵚; 뵚; 뵚; ) HANGUL SYLLABLE BOEBS +BD5B;BD5B;1107 116C 11BA;BD5B;1107 116C 11BA; # (뵛; 뵛; 뵛; 뵛; 뵛; ) HANGUL SYLLABLE BOES +BD5C;BD5C;1107 116C 11BB;BD5C;1107 116C 11BB; # (뵜; 뵜; 뵜; 뵜; 뵜; ) HANGUL SYLLABLE BOESS +BD5D;BD5D;1107 116C 11BC;BD5D;1107 116C 11BC; # (뵝; 뵝; 뵝; 뵝; 뵝; ) HANGUL SYLLABLE BOENG +BD5E;BD5E;1107 116C 11BD;BD5E;1107 116C 11BD; # (뵞; 뵞; 뵞; 뵞; 뵞; ) HANGUL SYLLABLE BOEJ +BD5F;BD5F;1107 116C 11BE;BD5F;1107 116C 11BE; # (뵟; 뵟; 뵟; 뵟; 뵟; ) HANGUL SYLLABLE BOEC +BD60;BD60;1107 116C 11BF;BD60;1107 116C 11BF; # (뵠; 뵠; 뵠; 뵠; 뵠; ) HANGUL SYLLABLE BOEK +BD61;BD61;1107 116C 11C0;BD61;1107 116C 11C0; # (뵡; 뵡; 뵡; 뵡; 뵡; ) HANGUL SYLLABLE BOET +BD62;BD62;1107 116C 11C1;BD62;1107 116C 11C1; # (뵢; 뵢; 뵢; 뵢; 뵢; ) HANGUL SYLLABLE BOEP +BD63;BD63;1107 116C 11C2;BD63;1107 116C 11C2; # (뵣; 뵣; 뵣; 뵣; 뵣; ) HANGUL SYLLABLE BOEH +BD64;BD64;1107 116D;BD64;1107 116D; # (뵤; 뵤; 뵤; 뵤; 뵤; ) HANGUL SYLLABLE BYO +BD65;BD65;1107 116D 11A8;BD65;1107 116D 11A8; # (뵥; 뵥; 뵥; 뵥; 뵥; ) HANGUL SYLLABLE BYOG +BD66;BD66;1107 116D 11A9;BD66;1107 116D 11A9; # (뵦; 뵦; 뵦; 뵦; 뵦; ) HANGUL SYLLABLE BYOGG +BD67;BD67;1107 116D 11AA;BD67;1107 116D 11AA; # (뵧; 뵧; 뵧; 뵧; 뵧; ) HANGUL SYLLABLE BYOGS +BD68;BD68;1107 116D 11AB;BD68;1107 116D 11AB; # (뵨; 뵨; 뵨; 뵨; 뵨; ) HANGUL SYLLABLE BYON +BD69;BD69;1107 116D 11AC;BD69;1107 116D 11AC; # (뵩; 뵩; 뵩; 뵩; 뵩; ) HANGUL SYLLABLE BYONJ +BD6A;BD6A;1107 116D 11AD;BD6A;1107 116D 11AD; # (뵪; 뵪; 뵪; 뵪; 뵪; ) HANGUL SYLLABLE BYONH +BD6B;BD6B;1107 116D 11AE;BD6B;1107 116D 11AE; # (뵫; 뵫; 뵫; 뵫; 뵫; ) HANGUL SYLLABLE BYOD +BD6C;BD6C;1107 116D 11AF;BD6C;1107 116D 11AF; # (뵬; 뵬; 뵬; 뵬; 뵬; ) HANGUL SYLLABLE BYOL +BD6D;BD6D;1107 116D 11B0;BD6D;1107 116D 11B0; # (뵭; 뵭; 뵭; 뵭; 뵭; ) HANGUL SYLLABLE BYOLG +BD6E;BD6E;1107 116D 11B1;BD6E;1107 116D 11B1; # (뵮; 뵮; 뵮; 뵮; 뵮; ) HANGUL SYLLABLE BYOLM +BD6F;BD6F;1107 116D 11B2;BD6F;1107 116D 11B2; # (뵯; 뵯; 뵯; 뵯; 뵯; ) HANGUL SYLLABLE BYOLB +BD70;BD70;1107 116D 11B3;BD70;1107 116D 11B3; # (뵰; 뵰; 뵰; 뵰; 뵰; ) HANGUL SYLLABLE BYOLS +BD71;BD71;1107 116D 11B4;BD71;1107 116D 11B4; # (뵱; 뵱; 뵱; 뵱; 뵱; ) HANGUL SYLLABLE BYOLT +BD72;BD72;1107 116D 11B5;BD72;1107 116D 11B5; # (뵲; 뵲; 뵲; 뵲; 뵲; ) HANGUL SYLLABLE BYOLP +BD73;BD73;1107 116D 11B6;BD73;1107 116D 11B6; # (뵳; 뵳; 뵳; 뵳; 뵳; ) HANGUL SYLLABLE BYOLH +BD74;BD74;1107 116D 11B7;BD74;1107 116D 11B7; # (뵴; 뵴; 뵴; 뵴; 뵴; ) HANGUL SYLLABLE BYOM +BD75;BD75;1107 116D 11B8;BD75;1107 116D 11B8; # (뵵; 뵵; 뵵; 뵵; 뵵; ) HANGUL SYLLABLE BYOB +BD76;BD76;1107 116D 11B9;BD76;1107 116D 11B9; # (뵶; 뵶; 뵶; 뵶; 뵶; ) HANGUL SYLLABLE BYOBS +BD77;BD77;1107 116D 11BA;BD77;1107 116D 11BA; # (뵷; 뵷; 뵷; 뵷; 뵷; ) HANGUL SYLLABLE BYOS +BD78;BD78;1107 116D 11BB;BD78;1107 116D 11BB; # (뵸; 뵸; 뵸; 뵸; 뵸; ) HANGUL SYLLABLE BYOSS +BD79;BD79;1107 116D 11BC;BD79;1107 116D 11BC; # (뵹; 뵹; 뵹; 뵹; 뵹; ) HANGUL SYLLABLE BYONG +BD7A;BD7A;1107 116D 11BD;BD7A;1107 116D 11BD; # (뵺; 뵺; 뵺; 뵺; 뵺; ) HANGUL SYLLABLE BYOJ +BD7B;BD7B;1107 116D 11BE;BD7B;1107 116D 11BE; # (뵻; 뵻; 뵻; 뵻; 뵻; ) HANGUL SYLLABLE BYOC +BD7C;BD7C;1107 116D 11BF;BD7C;1107 116D 11BF; # (뵼; 뵼; 뵼; 뵼; 뵼; ) HANGUL SYLLABLE BYOK +BD7D;BD7D;1107 116D 11C0;BD7D;1107 116D 11C0; # (뵽; 뵽; 뵽; 뵽; 뵽; ) HANGUL SYLLABLE BYOT +BD7E;BD7E;1107 116D 11C1;BD7E;1107 116D 11C1; # (뵾; 뵾; 뵾; 뵾; 뵾; ) HANGUL SYLLABLE BYOP +BD7F;BD7F;1107 116D 11C2;BD7F;1107 116D 11C2; # (뵿; 뵿; 뵿; 뵿; 뵿; ) HANGUL SYLLABLE BYOH +BD80;BD80;1107 116E;BD80;1107 116E; # (부; 부; 부; 부; 부; ) HANGUL SYLLABLE BU +BD81;BD81;1107 116E 11A8;BD81;1107 116E 11A8; # (북; 북; 북; 북; 북; ) HANGUL SYLLABLE BUG +BD82;BD82;1107 116E 11A9;BD82;1107 116E 11A9; # (붂; 붂; 붂; 붂; 붂; ) HANGUL SYLLABLE BUGG +BD83;BD83;1107 116E 11AA;BD83;1107 116E 11AA; # (붃; 붃; 붃; 붃; 붃; ) HANGUL SYLLABLE BUGS +BD84;BD84;1107 116E 11AB;BD84;1107 116E 11AB; # (분; 분; 분; 분; 분; ) HANGUL SYLLABLE BUN +BD85;BD85;1107 116E 11AC;BD85;1107 116E 11AC; # (붅; 붅; 붅; 붅; 붅; ) HANGUL SYLLABLE BUNJ +BD86;BD86;1107 116E 11AD;BD86;1107 116E 11AD; # (붆; 붆; 붆; 붆; 붆; ) HANGUL SYLLABLE BUNH +BD87;BD87;1107 116E 11AE;BD87;1107 116E 11AE; # (붇; 붇; 붇; 붇; 붇; ) HANGUL SYLLABLE BUD +BD88;BD88;1107 116E 11AF;BD88;1107 116E 11AF; # (불; 불; 불; 불; 불; ) HANGUL SYLLABLE BUL +BD89;BD89;1107 116E 11B0;BD89;1107 116E 11B0; # (붉; 붉; 붉; 붉; 붉; ) HANGUL SYLLABLE BULG +BD8A;BD8A;1107 116E 11B1;BD8A;1107 116E 11B1; # (붊; 붊; 붊; 붊; 붊; ) HANGUL SYLLABLE BULM +BD8B;BD8B;1107 116E 11B2;BD8B;1107 116E 11B2; # (붋; 붋; 붋; 붋; 붋; ) HANGUL SYLLABLE BULB +BD8C;BD8C;1107 116E 11B3;BD8C;1107 116E 11B3; # (붌; 붌; 붌; 붌; 붌; ) HANGUL SYLLABLE BULS +BD8D;BD8D;1107 116E 11B4;BD8D;1107 116E 11B4; # (붍; 붍; 붍; 붍; 붍; ) HANGUL SYLLABLE BULT +BD8E;BD8E;1107 116E 11B5;BD8E;1107 116E 11B5; # (붎; 붎; 붎; 붎; 붎; ) HANGUL SYLLABLE BULP +BD8F;BD8F;1107 116E 11B6;BD8F;1107 116E 11B6; # (붏; 붏; 붏; 붏; 붏; ) HANGUL SYLLABLE BULH +BD90;BD90;1107 116E 11B7;BD90;1107 116E 11B7; # (붐; 붐; 붐; 붐; 붐; ) HANGUL SYLLABLE BUM +BD91;BD91;1107 116E 11B8;BD91;1107 116E 11B8; # (붑; 붑; 붑; 붑; 붑; ) HANGUL SYLLABLE BUB +BD92;BD92;1107 116E 11B9;BD92;1107 116E 11B9; # (붒; 붒; 붒; 붒; 붒; ) HANGUL SYLLABLE BUBS +BD93;BD93;1107 116E 11BA;BD93;1107 116E 11BA; # (붓; 붓; 붓; 붓; 붓; ) HANGUL SYLLABLE BUS +BD94;BD94;1107 116E 11BB;BD94;1107 116E 11BB; # (붔; 붔; 붔; 붔; 붔; ) HANGUL SYLLABLE BUSS +BD95;BD95;1107 116E 11BC;BD95;1107 116E 11BC; # (붕; 붕; 붕; 붕; 붕; ) HANGUL SYLLABLE BUNG +BD96;BD96;1107 116E 11BD;BD96;1107 116E 11BD; # (붖; 붖; 붖; 붖; 붖; ) HANGUL SYLLABLE BUJ +BD97;BD97;1107 116E 11BE;BD97;1107 116E 11BE; # (붗; 붗; 붗; 붗; 붗; ) HANGUL SYLLABLE BUC +BD98;BD98;1107 116E 11BF;BD98;1107 116E 11BF; # (붘; 붘; 붘; 붘; 붘; ) HANGUL SYLLABLE BUK +BD99;BD99;1107 116E 11C0;BD99;1107 116E 11C0; # (붙; 붙; 붙; 붙; 붙; ) HANGUL SYLLABLE BUT +BD9A;BD9A;1107 116E 11C1;BD9A;1107 116E 11C1; # (붚; 붚; 붚; 붚; 붚; ) HANGUL SYLLABLE BUP +BD9B;BD9B;1107 116E 11C2;BD9B;1107 116E 11C2; # (붛; 붛; 붛; 붛; 붛; ) HANGUL SYLLABLE BUH +BD9C;BD9C;1107 116F;BD9C;1107 116F; # (붜; 붜; 붜; 붜; 붜; ) HANGUL SYLLABLE BWEO +BD9D;BD9D;1107 116F 11A8;BD9D;1107 116F 11A8; # (붝; 붝; 붝; 붝; 붝; ) HANGUL SYLLABLE BWEOG +BD9E;BD9E;1107 116F 11A9;BD9E;1107 116F 11A9; # (붞; 붞; 붞; 붞; 붞; ) HANGUL SYLLABLE BWEOGG +BD9F;BD9F;1107 116F 11AA;BD9F;1107 116F 11AA; # (붟; 붟; 붟; 붟; 붟; ) HANGUL SYLLABLE BWEOGS +BDA0;BDA0;1107 116F 11AB;BDA0;1107 116F 11AB; # (붠; 붠; 붠; 붠; 붠; ) HANGUL SYLLABLE BWEON +BDA1;BDA1;1107 116F 11AC;BDA1;1107 116F 11AC; # (붡; 붡; 붡; 붡; 붡; ) HANGUL SYLLABLE BWEONJ +BDA2;BDA2;1107 116F 11AD;BDA2;1107 116F 11AD; # (붢; 붢; 붢; 붢; 붢; ) HANGUL SYLLABLE BWEONH +BDA3;BDA3;1107 116F 11AE;BDA3;1107 116F 11AE; # (붣; 붣; 붣; 붣; 붣; ) HANGUL SYLLABLE BWEOD +BDA4;BDA4;1107 116F 11AF;BDA4;1107 116F 11AF; # (붤; 붤; 붤; 붤; 붤; ) HANGUL SYLLABLE BWEOL +BDA5;BDA5;1107 116F 11B0;BDA5;1107 116F 11B0; # (붥; 붥; 붥; 붥; 붥; ) HANGUL SYLLABLE BWEOLG +BDA6;BDA6;1107 116F 11B1;BDA6;1107 116F 11B1; # (붦; 붦; 붦; 붦; 붦; ) HANGUL SYLLABLE BWEOLM +BDA7;BDA7;1107 116F 11B2;BDA7;1107 116F 11B2; # (붧; 붧; 붧; 붧; 붧; ) HANGUL SYLLABLE BWEOLB +BDA8;BDA8;1107 116F 11B3;BDA8;1107 116F 11B3; # (붨; 붨; 붨; 붨; 붨; ) HANGUL SYLLABLE BWEOLS +BDA9;BDA9;1107 116F 11B4;BDA9;1107 116F 11B4; # (붩; 붩; 붩; 붩; 붩; ) HANGUL SYLLABLE BWEOLT +BDAA;BDAA;1107 116F 11B5;BDAA;1107 116F 11B5; # (붪; 붪; 붪; 붪; 붪; ) HANGUL SYLLABLE BWEOLP +BDAB;BDAB;1107 116F 11B6;BDAB;1107 116F 11B6; # (붫; 붫; 붫; 붫; 붫; ) HANGUL SYLLABLE BWEOLH +BDAC;BDAC;1107 116F 11B7;BDAC;1107 116F 11B7; # (붬; 붬; 붬; 붬; 붬; ) HANGUL SYLLABLE BWEOM +BDAD;BDAD;1107 116F 11B8;BDAD;1107 116F 11B8; # (붭; 붭; 붭; 붭; 붭; ) HANGUL SYLLABLE BWEOB +BDAE;BDAE;1107 116F 11B9;BDAE;1107 116F 11B9; # (붮; 붮; 붮; 붮; 붮; ) HANGUL SYLLABLE BWEOBS +BDAF;BDAF;1107 116F 11BA;BDAF;1107 116F 11BA; # (붯; 붯; 붯; 붯; 붯; ) HANGUL SYLLABLE BWEOS +BDB0;BDB0;1107 116F 11BB;BDB0;1107 116F 11BB; # (붰; 붰; 붰; 붰; 붰; ) HANGUL SYLLABLE BWEOSS +BDB1;BDB1;1107 116F 11BC;BDB1;1107 116F 11BC; # (붱; 붱; 붱; 붱; 붱; ) HANGUL SYLLABLE BWEONG +BDB2;BDB2;1107 116F 11BD;BDB2;1107 116F 11BD; # (붲; 붲; 붲; 붲; 붲; ) HANGUL SYLLABLE BWEOJ +BDB3;BDB3;1107 116F 11BE;BDB3;1107 116F 11BE; # (붳; 붳; 붳; 붳; 붳; ) HANGUL SYLLABLE BWEOC +BDB4;BDB4;1107 116F 11BF;BDB4;1107 116F 11BF; # (붴; 붴; 붴; 붴; 붴; ) HANGUL SYLLABLE BWEOK +BDB5;BDB5;1107 116F 11C0;BDB5;1107 116F 11C0; # (붵; 붵; 붵; 붵; 붵; ) HANGUL SYLLABLE BWEOT +BDB6;BDB6;1107 116F 11C1;BDB6;1107 116F 11C1; # (붶; 붶; 붶; 붶; 붶; ) HANGUL SYLLABLE BWEOP +BDB7;BDB7;1107 116F 11C2;BDB7;1107 116F 11C2; # (붷; 붷; 붷; 붷; 붷; ) HANGUL SYLLABLE BWEOH +BDB8;BDB8;1107 1170;BDB8;1107 1170; # (붸; 붸; 붸; 붸; 붸; ) HANGUL SYLLABLE BWE +BDB9;BDB9;1107 1170 11A8;BDB9;1107 1170 11A8; # (붹; 붹; 붹; 붹; 붹; ) HANGUL SYLLABLE BWEG +BDBA;BDBA;1107 1170 11A9;BDBA;1107 1170 11A9; # (붺; 붺; 붺; 붺; 붺; ) HANGUL SYLLABLE BWEGG +BDBB;BDBB;1107 1170 11AA;BDBB;1107 1170 11AA; # (붻; 붻; 붻; 붻; 붻; ) HANGUL SYLLABLE BWEGS +BDBC;BDBC;1107 1170 11AB;BDBC;1107 1170 11AB; # (붼; 붼; 붼; 붼; 붼; ) HANGUL SYLLABLE BWEN +BDBD;BDBD;1107 1170 11AC;BDBD;1107 1170 11AC; # (붽; 붽; 붽; 붽; 붽; ) HANGUL SYLLABLE BWENJ +BDBE;BDBE;1107 1170 11AD;BDBE;1107 1170 11AD; # (붾; 붾; 붾; 붾; 붾; ) HANGUL SYLLABLE BWENH +BDBF;BDBF;1107 1170 11AE;BDBF;1107 1170 11AE; # (붿; 붿; 붿; 붿; 붿; ) HANGUL SYLLABLE BWED +BDC0;BDC0;1107 1170 11AF;BDC0;1107 1170 11AF; # (뷀; 뷀; 뷀; 뷀; 뷀; ) HANGUL SYLLABLE BWEL +BDC1;BDC1;1107 1170 11B0;BDC1;1107 1170 11B0; # (뷁; 뷁; 뷁; 뷁; 뷁; ) HANGUL SYLLABLE BWELG +BDC2;BDC2;1107 1170 11B1;BDC2;1107 1170 11B1; # (뷂; 뷂; 뷂; 뷂; 뷂; ) HANGUL SYLLABLE BWELM +BDC3;BDC3;1107 1170 11B2;BDC3;1107 1170 11B2; # (뷃; 뷃; 뷃; 뷃; 뷃; ) HANGUL SYLLABLE BWELB +BDC4;BDC4;1107 1170 11B3;BDC4;1107 1170 11B3; # (뷄; 뷄; 뷄; 뷄; 뷄; ) HANGUL SYLLABLE BWELS +BDC5;BDC5;1107 1170 11B4;BDC5;1107 1170 11B4; # (뷅; 뷅; 뷅; 뷅; 뷅; ) HANGUL SYLLABLE BWELT +BDC6;BDC6;1107 1170 11B5;BDC6;1107 1170 11B5; # (뷆; 뷆; 뷆; 뷆; 뷆; ) HANGUL SYLLABLE BWELP +BDC7;BDC7;1107 1170 11B6;BDC7;1107 1170 11B6; # (뷇; 뷇; 뷇; 뷇; 뷇; ) HANGUL SYLLABLE BWELH +BDC8;BDC8;1107 1170 11B7;BDC8;1107 1170 11B7; # (뷈; 뷈; 뷈; 뷈; 뷈; ) HANGUL SYLLABLE BWEM +BDC9;BDC9;1107 1170 11B8;BDC9;1107 1170 11B8; # (뷉; 뷉; 뷉; 뷉; 뷉; ) HANGUL SYLLABLE BWEB +BDCA;BDCA;1107 1170 11B9;BDCA;1107 1170 11B9; # (뷊; 뷊; 뷊; 뷊; 뷊; ) HANGUL SYLLABLE BWEBS +BDCB;BDCB;1107 1170 11BA;BDCB;1107 1170 11BA; # (뷋; 뷋; 뷋; 뷋; 뷋; ) HANGUL SYLLABLE BWES +BDCC;BDCC;1107 1170 11BB;BDCC;1107 1170 11BB; # (뷌; 뷌; 뷌; 뷌; 뷌; ) HANGUL SYLLABLE BWESS +BDCD;BDCD;1107 1170 11BC;BDCD;1107 1170 11BC; # (뷍; 뷍; 뷍; 뷍; 뷍; ) HANGUL SYLLABLE BWENG +BDCE;BDCE;1107 1170 11BD;BDCE;1107 1170 11BD; # (뷎; 뷎; 뷎; 뷎; 뷎; ) HANGUL SYLLABLE BWEJ +BDCF;BDCF;1107 1170 11BE;BDCF;1107 1170 11BE; # (뷏; 뷏; 뷏; 뷏; 뷏; ) HANGUL SYLLABLE BWEC +BDD0;BDD0;1107 1170 11BF;BDD0;1107 1170 11BF; # (뷐; 뷐; 뷐; 뷐; 뷐; ) HANGUL SYLLABLE BWEK +BDD1;BDD1;1107 1170 11C0;BDD1;1107 1170 11C0; # (뷑; 뷑; 뷑; 뷑; 뷑; ) HANGUL SYLLABLE BWET +BDD2;BDD2;1107 1170 11C1;BDD2;1107 1170 11C1; # (뷒; 뷒; 뷒; 뷒; 뷒; ) HANGUL SYLLABLE BWEP +BDD3;BDD3;1107 1170 11C2;BDD3;1107 1170 11C2; # (뷓; 뷓; 뷓; 뷓; 뷓; ) HANGUL SYLLABLE BWEH +BDD4;BDD4;1107 1171;BDD4;1107 1171; # (뷔; 뷔; 뷔; 뷔; 뷔; ) HANGUL SYLLABLE BWI +BDD5;BDD5;1107 1171 11A8;BDD5;1107 1171 11A8; # (뷕; 뷕; 뷕; 뷕; 뷕; ) HANGUL SYLLABLE BWIG +BDD6;BDD6;1107 1171 11A9;BDD6;1107 1171 11A9; # (뷖; 뷖; 뷖; 뷖; 뷖; ) HANGUL SYLLABLE BWIGG +BDD7;BDD7;1107 1171 11AA;BDD7;1107 1171 11AA; # (뷗; 뷗; 뷗; 뷗; 뷗; ) HANGUL SYLLABLE BWIGS +BDD8;BDD8;1107 1171 11AB;BDD8;1107 1171 11AB; # (뷘; 뷘; 뷘; 뷘; 뷘; ) HANGUL SYLLABLE BWIN +BDD9;BDD9;1107 1171 11AC;BDD9;1107 1171 11AC; # (뷙; 뷙; 뷙; 뷙; 뷙; ) HANGUL SYLLABLE BWINJ +BDDA;BDDA;1107 1171 11AD;BDDA;1107 1171 11AD; # (뷚; 뷚; 뷚; 뷚; 뷚; ) HANGUL SYLLABLE BWINH +BDDB;BDDB;1107 1171 11AE;BDDB;1107 1171 11AE; # (뷛; 뷛; 뷛; 뷛; 뷛; ) HANGUL SYLLABLE BWID +BDDC;BDDC;1107 1171 11AF;BDDC;1107 1171 11AF; # (뷜; 뷜; 뷜; 뷜; 뷜; ) HANGUL SYLLABLE BWIL +BDDD;BDDD;1107 1171 11B0;BDDD;1107 1171 11B0; # (뷝; 뷝; 뷝; 뷝; 뷝; ) HANGUL SYLLABLE BWILG +BDDE;BDDE;1107 1171 11B1;BDDE;1107 1171 11B1; # (뷞; 뷞; 뷞; 뷞; 뷞; ) HANGUL SYLLABLE BWILM +BDDF;BDDF;1107 1171 11B2;BDDF;1107 1171 11B2; # (뷟; 뷟; 뷟; 뷟; 뷟; ) HANGUL SYLLABLE BWILB +BDE0;BDE0;1107 1171 11B3;BDE0;1107 1171 11B3; # (뷠; 뷠; 뷠; 뷠; 뷠; ) HANGUL SYLLABLE BWILS +BDE1;BDE1;1107 1171 11B4;BDE1;1107 1171 11B4; # (뷡; 뷡; 뷡; 뷡; 뷡; ) HANGUL SYLLABLE BWILT +BDE2;BDE2;1107 1171 11B5;BDE2;1107 1171 11B5; # (뷢; 뷢; 뷢; 뷢; 뷢; ) HANGUL SYLLABLE BWILP +BDE3;BDE3;1107 1171 11B6;BDE3;1107 1171 11B6; # (뷣; 뷣; 뷣; 뷣; 뷣; ) HANGUL SYLLABLE BWILH +BDE4;BDE4;1107 1171 11B7;BDE4;1107 1171 11B7; # (뷤; 뷤; 뷤; 뷤; 뷤; ) HANGUL SYLLABLE BWIM +BDE5;BDE5;1107 1171 11B8;BDE5;1107 1171 11B8; # (뷥; 뷥; 뷥; 뷥; 뷥; ) HANGUL SYLLABLE BWIB +BDE6;BDE6;1107 1171 11B9;BDE6;1107 1171 11B9; # (뷦; 뷦; 뷦; 뷦; 뷦; ) HANGUL SYLLABLE BWIBS +BDE7;BDE7;1107 1171 11BA;BDE7;1107 1171 11BA; # (뷧; 뷧; 뷧; 뷧; 뷧; ) HANGUL SYLLABLE BWIS +BDE8;BDE8;1107 1171 11BB;BDE8;1107 1171 11BB; # (뷨; 뷨; 뷨; 뷨; 뷨; ) HANGUL SYLLABLE BWISS +BDE9;BDE9;1107 1171 11BC;BDE9;1107 1171 11BC; # (뷩; 뷩; 뷩; 뷩; 뷩; ) HANGUL SYLLABLE BWING +BDEA;BDEA;1107 1171 11BD;BDEA;1107 1171 11BD; # (뷪; 뷪; 뷪; 뷪; 뷪; ) HANGUL SYLLABLE BWIJ +BDEB;BDEB;1107 1171 11BE;BDEB;1107 1171 11BE; # (뷫; 뷫; 뷫; 뷫; 뷫; ) HANGUL SYLLABLE BWIC +BDEC;BDEC;1107 1171 11BF;BDEC;1107 1171 11BF; # (뷬; 뷬; 뷬; 뷬; 뷬; ) HANGUL SYLLABLE BWIK +BDED;BDED;1107 1171 11C0;BDED;1107 1171 11C0; # (뷭; 뷭; 뷭; 뷭; 뷭; ) HANGUL SYLLABLE BWIT +BDEE;BDEE;1107 1171 11C1;BDEE;1107 1171 11C1; # (뷮; 뷮; 뷮; 뷮; 뷮; ) HANGUL SYLLABLE BWIP +BDEF;BDEF;1107 1171 11C2;BDEF;1107 1171 11C2; # (뷯; 뷯; 뷯; 뷯; 뷯; ) HANGUL SYLLABLE BWIH +BDF0;BDF0;1107 1172;BDF0;1107 1172; # (뷰; 뷰; 뷰; 뷰; 뷰; ) HANGUL SYLLABLE BYU +BDF1;BDF1;1107 1172 11A8;BDF1;1107 1172 11A8; # (뷱; 뷱; 뷱; 뷱; 뷱; ) HANGUL SYLLABLE BYUG +BDF2;BDF2;1107 1172 11A9;BDF2;1107 1172 11A9; # (뷲; 뷲; 뷲; 뷲; 뷲; ) HANGUL SYLLABLE BYUGG +BDF3;BDF3;1107 1172 11AA;BDF3;1107 1172 11AA; # (뷳; 뷳; 뷳; 뷳; 뷳; ) HANGUL SYLLABLE BYUGS +BDF4;BDF4;1107 1172 11AB;BDF4;1107 1172 11AB; # (뷴; 뷴; 뷴; 뷴; 뷴; ) HANGUL SYLLABLE BYUN +BDF5;BDF5;1107 1172 11AC;BDF5;1107 1172 11AC; # (뷵; 뷵; 뷵; 뷵; 뷵; ) HANGUL SYLLABLE BYUNJ +BDF6;BDF6;1107 1172 11AD;BDF6;1107 1172 11AD; # (뷶; 뷶; 뷶; 뷶; 뷶; ) HANGUL SYLLABLE BYUNH +BDF7;BDF7;1107 1172 11AE;BDF7;1107 1172 11AE; # (뷷; 뷷; 뷷; 뷷; 뷷; ) HANGUL SYLLABLE BYUD +BDF8;BDF8;1107 1172 11AF;BDF8;1107 1172 11AF; # (뷸; 뷸; 뷸; 뷸; 뷸; ) HANGUL SYLLABLE BYUL +BDF9;BDF9;1107 1172 11B0;BDF9;1107 1172 11B0; # (뷹; 뷹; 뷹; 뷹; 뷹; ) HANGUL SYLLABLE BYULG +BDFA;BDFA;1107 1172 11B1;BDFA;1107 1172 11B1; # (뷺; 뷺; 뷺; 뷺; 뷺; ) HANGUL SYLLABLE BYULM +BDFB;BDFB;1107 1172 11B2;BDFB;1107 1172 11B2; # (뷻; 뷻; 뷻; 뷻; 뷻; ) HANGUL SYLLABLE BYULB +BDFC;BDFC;1107 1172 11B3;BDFC;1107 1172 11B3; # (뷼; 뷼; 뷼; 뷼; 뷼; ) HANGUL SYLLABLE BYULS +BDFD;BDFD;1107 1172 11B4;BDFD;1107 1172 11B4; # (뷽; 뷽; 뷽; 뷽; 뷽; ) HANGUL SYLLABLE BYULT +BDFE;BDFE;1107 1172 11B5;BDFE;1107 1172 11B5; # (뷾; 뷾; 뷾; 뷾; 뷾; ) HANGUL SYLLABLE BYULP +BDFF;BDFF;1107 1172 11B6;BDFF;1107 1172 11B6; # (뷿; 뷿; 뷿; 뷿; 뷿; ) HANGUL SYLLABLE BYULH +BE00;BE00;1107 1172 11B7;BE00;1107 1172 11B7; # (븀; 븀; 븀; 븀; 븀; ) HANGUL SYLLABLE BYUM +BE01;BE01;1107 1172 11B8;BE01;1107 1172 11B8; # (븁; 븁; 븁; 븁; 븁; ) HANGUL SYLLABLE BYUB +BE02;BE02;1107 1172 11B9;BE02;1107 1172 11B9; # (븂; 븂; 븂; 븂; 븂; ) HANGUL SYLLABLE BYUBS +BE03;BE03;1107 1172 11BA;BE03;1107 1172 11BA; # (븃; 븃; 븃; 븃; 븃; ) HANGUL SYLLABLE BYUS +BE04;BE04;1107 1172 11BB;BE04;1107 1172 11BB; # (븄; 븄; 븄; 븄; 븄; ) HANGUL SYLLABLE BYUSS +BE05;BE05;1107 1172 11BC;BE05;1107 1172 11BC; # (븅; 븅; 븅; 븅; 븅; ) HANGUL SYLLABLE BYUNG +BE06;BE06;1107 1172 11BD;BE06;1107 1172 11BD; # (븆; 븆; 븆; 븆; 븆; ) HANGUL SYLLABLE BYUJ +BE07;BE07;1107 1172 11BE;BE07;1107 1172 11BE; # (븇; 븇; 븇; 븇; 븇; ) HANGUL SYLLABLE BYUC +BE08;BE08;1107 1172 11BF;BE08;1107 1172 11BF; # (븈; 븈; 븈; 븈; 븈; ) HANGUL SYLLABLE BYUK +BE09;BE09;1107 1172 11C0;BE09;1107 1172 11C0; # (븉; 븉; 븉; 븉; 븉; ) HANGUL SYLLABLE BYUT +BE0A;BE0A;1107 1172 11C1;BE0A;1107 1172 11C1; # (븊; 븊; 븊; 븊; 븊; ) HANGUL SYLLABLE BYUP +BE0B;BE0B;1107 1172 11C2;BE0B;1107 1172 11C2; # (븋; 븋; 븋; 븋; 븋; ) HANGUL SYLLABLE BYUH +BE0C;BE0C;1107 1173;BE0C;1107 1173; # (브; 브; 브; 브; 브; ) HANGUL SYLLABLE BEU +BE0D;BE0D;1107 1173 11A8;BE0D;1107 1173 11A8; # (븍; 븍; 븍; 븍; 븍; ) HANGUL SYLLABLE BEUG +BE0E;BE0E;1107 1173 11A9;BE0E;1107 1173 11A9; # (븎; 븎; 븎; 븎; 븎; ) HANGUL SYLLABLE BEUGG +BE0F;BE0F;1107 1173 11AA;BE0F;1107 1173 11AA; # (븏; 븏; 븏; 븏; 븏; ) HANGUL SYLLABLE BEUGS +BE10;BE10;1107 1173 11AB;BE10;1107 1173 11AB; # (븐; 븐; 븐; 븐; 븐; ) HANGUL SYLLABLE BEUN +BE11;BE11;1107 1173 11AC;BE11;1107 1173 11AC; # (븑; 븑; 븑; 븑; 븑; ) HANGUL SYLLABLE BEUNJ +BE12;BE12;1107 1173 11AD;BE12;1107 1173 11AD; # (븒; 븒; 븒; 븒; 븒; ) HANGUL SYLLABLE BEUNH +BE13;BE13;1107 1173 11AE;BE13;1107 1173 11AE; # (븓; 븓; 븓; 븓; 븓; ) HANGUL SYLLABLE BEUD +BE14;BE14;1107 1173 11AF;BE14;1107 1173 11AF; # (블; 블; 블; 블; 블; ) HANGUL SYLLABLE BEUL +BE15;BE15;1107 1173 11B0;BE15;1107 1173 11B0; # (븕; 븕; 븕; 븕; 븕; ) HANGUL SYLLABLE BEULG +BE16;BE16;1107 1173 11B1;BE16;1107 1173 11B1; # (븖; 븖; 븖; 븖; 븖; ) HANGUL SYLLABLE BEULM +BE17;BE17;1107 1173 11B2;BE17;1107 1173 11B2; # (븗; 븗; 븗; 븗; 븗; ) HANGUL SYLLABLE BEULB +BE18;BE18;1107 1173 11B3;BE18;1107 1173 11B3; # (븘; 븘; 븘; 븘; 븘; ) HANGUL SYLLABLE BEULS +BE19;BE19;1107 1173 11B4;BE19;1107 1173 11B4; # (븙; 븙; 븙; 븙; 븙; ) HANGUL SYLLABLE BEULT +BE1A;BE1A;1107 1173 11B5;BE1A;1107 1173 11B5; # (븚; 븚; 븚; 븚; 븚; ) HANGUL SYLLABLE BEULP +BE1B;BE1B;1107 1173 11B6;BE1B;1107 1173 11B6; # (븛; 븛; 븛; 븛; 븛; ) HANGUL SYLLABLE BEULH +BE1C;BE1C;1107 1173 11B7;BE1C;1107 1173 11B7; # (븜; 븜; 븜; 븜; 븜; ) HANGUL SYLLABLE BEUM +BE1D;BE1D;1107 1173 11B8;BE1D;1107 1173 11B8; # (븝; 븝; 븝; 븝; 븝; ) HANGUL SYLLABLE BEUB +BE1E;BE1E;1107 1173 11B9;BE1E;1107 1173 11B9; # (븞; 븞; 븞; 븞; 븞; ) HANGUL SYLLABLE BEUBS +BE1F;BE1F;1107 1173 11BA;BE1F;1107 1173 11BA; # (븟; 븟; 븟; 븟; 븟; ) HANGUL SYLLABLE BEUS +BE20;BE20;1107 1173 11BB;BE20;1107 1173 11BB; # (븠; 븠; 븠; 븠; 븠; ) HANGUL SYLLABLE BEUSS +BE21;BE21;1107 1173 11BC;BE21;1107 1173 11BC; # (븡; 븡; 븡; 븡; 븡; ) HANGUL SYLLABLE BEUNG +BE22;BE22;1107 1173 11BD;BE22;1107 1173 11BD; # (븢; 븢; 븢; 븢; 븢; ) HANGUL SYLLABLE BEUJ +BE23;BE23;1107 1173 11BE;BE23;1107 1173 11BE; # (븣; 븣; 븣; 븣; 븣; ) HANGUL SYLLABLE BEUC +BE24;BE24;1107 1173 11BF;BE24;1107 1173 11BF; # (븤; 븤; 븤; 븤; 븤; ) HANGUL SYLLABLE BEUK +BE25;BE25;1107 1173 11C0;BE25;1107 1173 11C0; # (븥; 븥; 븥; 븥; 븥; ) HANGUL SYLLABLE BEUT +BE26;BE26;1107 1173 11C1;BE26;1107 1173 11C1; # (븦; 븦; 븦; 븦; 븦; ) HANGUL SYLLABLE BEUP +BE27;BE27;1107 1173 11C2;BE27;1107 1173 11C2; # (븧; 븧; 븧; 븧; 븧; ) HANGUL SYLLABLE BEUH +BE28;BE28;1107 1174;BE28;1107 1174; # (븨; 븨; 븨; 븨; 븨; ) HANGUL SYLLABLE BYI +BE29;BE29;1107 1174 11A8;BE29;1107 1174 11A8; # (븩; 븩; 븩; 븩; 븩; ) HANGUL SYLLABLE BYIG +BE2A;BE2A;1107 1174 11A9;BE2A;1107 1174 11A9; # (븪; 븪; 븪; 븪; 븪; ) HANGUL SYLLABLE BYIGG +BE2B;BE2B;1107 1174 11AA;BE2B;1107 1174 11AA; # (븫; 븫; 븫; 븫; 븫; ) HANGUL SYLLABLE BYIGS +BE2C;BE2C;1107 1174 11AB;BE2C;1107 1174 11AB; # (븬; 븬; 븬; 븬; 븬; ) HANGUL SYLLABLE BYIN +BE2D;BE2D;1107 1174 11AC;BE2D;1107 1174 11AC; # (븭; 븭; 븭; 븭; 븭; ) HANGUL SYLLABLE BYINJ +BE2E;BE2E;1107 1174 11AD;BE2E;1107 1174 11AD; # (븮; 븮; 븮; 븮; 븮; ) HANGUL SYLLABLE BYINH +BE2F;BE2F;1107 1174 11AE;BE2F;1107 1174 11AE; # (븯; 븯; 븯; 븯; 븯; ) HANGUL SYLLABLE BYID +BE30;BE30;1107 1174 11AF;BE30;1107 1174 11AF; # (븰; 븰; 븰; 븰; 븰; ) HANGUL SYLLABLE BYIL +BE31;BE31;1107 1174 11B0;BE31;1107 1174 11B0; # (븱; 븱; 븱; 븱; 븱; ) HANGUL SYLLABLE BYILG +BE32;BE32;1107 1174 11B1;BE32;1107 1174 11B1; # (븲; 븲; 븲; 븲; 븲; ) HANGUL SYLLABLE BYILM +BE33;BE33;1107 1174 11B2;BE33;1107 1174 11B2; # (븳; 븳; 븳; 븳; 븳; ) HANGUL SYLLABLE BYILB +BE34;BE34;1107 1174 11B3;BE34;1107 1174 11B3; # (븴; 븴; 븴; 븴; 븴; ) HANGUL SYLLABLE BYILS +BE35;BE35;1107 1174 11B4;BE35;1107 1174 11B4; # (븵; 븵; 븵; 븵; 븵; ) HANGUL SYLLABLE BYILT +BE36;BE36;1107 1174 11B5;BE36;1107 1174 11B5; # (븶; 븶; 븶; 븶; 븶; ) HANGUL SYLLABLE BYILP +BE37;BE37;1107 1174 11B6;BE37;1107 1174 11B6; # (븷; 븷; 븷; 븷; 븷; ) HANGUL SYLLABLE BYILH +BE38;BE38;1107 1174 11B7;BE38;1107 1174 11B7; # (븸; 븸; 븸; 븸; 븸; ) HANGUL SYLLABLE BYIM +BE39;BE39;1107 1174 11B8;BE39;1107 1174 11B8; # (븹; 븹; 븹; 븹; 븹; ) HANGUL SYLLABLE BYIB +BE3A;BE3A;1107 1174 11B9;BE3A;1107 1174 11B9; # (븺; 븺; 븺; 븺; 븺; ) HANGUL SYLLABLE BYIBS +BE3B;BE3B;1107 1174 11BA;BE3B;1107 1174 11BA; # (븻; 븻; 븻; 븻; 븻; ) HANGUL SYLLABLE BYIS +BE3C;BE3C;1107 1174 11BB;BE3C;1107 1174 11BB; # (븼; 븼; 븼; 븼; 븼; ) HANGUL SYLLABLE BYISS +BE3D;BE3D;1107 1174 11BC;BE3D;1107 1174 11BC; # (븽; 븽; 븽; 븽; 븽; ) HANGUL SYLLABLE BYING +BE3E;BE3E;1107 1174 11BD;BE3E;1107 1174 11BD; # (븾; 븾; 븾; 븾; 븾; ) HANGUL SYLLABLE BYIJ +BE3F;BE3F;1107 1174 11BE;BE3F;1107 1174 11BE; # (븿; 븿; 븿; 븿; 븿; ) HANGUL SYLLABLE BYIC +BE40;BE40;1107 1174 11BF;BE40;1107 1174 11BF; # (빀; 빀; 빀; 빀; 빀; ) HANGUL SYLLABLE BYIK +BE41;BE41;1107 1174 11C0;BE41;1107 1174 11C0; # (빁; 빁; 빁; 빁; 빁; ) HANGUL SYLLABLE BYIT +BE42;BE42;1107 1174 11C1;BE42;1107 1174 11C1; # (빂; 빂; 빂; 빂; 빂; ) HANGUL SYLLABLE BYIP +BE43;BE43;1107 1174 11C2;BE43;1107 1174 11C2; # (빃; 빃; 빃; 빃; 빃; ) HANGUL SYLLABLE BYIH +BE44;BE44;1107 1175;BE44;1107 1175; # (비; 비; 비; 비; 비; ) HANGUL SYLLABLE BI +BE45;BE45;1107 1175 11A8;BE45;1107 1175 11A8; # (빅; 빅; 빅; 빅; 빅; ) HANGUL SYLLABLE BIG +BE46;BE46;1107 1175 11A9;BE46;1107 1175 11A9; # (빆; 빆; 빆; 빆; 빆; ) HANGUL SYLLABLE BIGG +BE47;BE47;1107 1175 11AA;BE47;1107 1175 11AA; # (빇; 빇; 빇; 빇; 빇; ) HANGUL SYLLABLE BIGS +BE48;BE48;1107 1175 11AB;BE48;1107 1175 11AB; # (빈; 빈; 빈; 빈; 빈; ) HANGUL SYLLABLE BIN +BE49;BE49;1107 1175 11AC;BE49;1107 1175 11AC; # (빉; 빉; 빉; 빉; 빉; ) HANGUL SYLLABLE BINJ +BE4A;BE4A;1107 1175 11AD;BE4A;1107 1175 11AD; # (빊; 빊; 빊; 빊; 빊; ) HANGUL SYLLABLE BINH +BE4B;BE4B;1107 1175 11AE;BE4B;1107 1175 11AE; # (빋; 빋; 빋; 빋; 빋; ) HANGUL SYLLABLE BID +BE4C;BE4C;1107 1175 11AF;BE4C;1107 1175 11AF; # (빌; 빌; 빌; 빌; 빌; ) HANGUL SYLLABLE BIL +BE4D;BE4D;1107 1175 11B0;BE4D;1107 1175 11B0; # (빍; 빍; 빍; 빍; 빍; ) HANGUL SYLLABLE BILG +BE4E;BE4E;1107 1175 11B1;BE4E;1107 1175 11B1; # (빎; 빎; 빎; 빎; 빎; ) HANGUL SYLLABLE BILM +BE4F;BE4F;1107 1175 11B2;BE4F;1107 1175 11B2; # (빏; 빏; 빏; 빏; 빏; ) HANGUL SYLLABLE BILB +BE50;BE50;1107 1175 11B3;BE50;1107 1175 11B3; # (빐; 빐; 빐; 빐; 빐; ) HANGUL SYLLABLE BILS +BE51;BE51;1107 1175 11B4;BE51;1107 1175 11B4; # (빑; 빑; 빑; 빑; 빑; ) HANGUL SYLLABLE BILT +BE52;BE52;1107 1175 11B5;BE52;1107 1175 11B5; # (빒; 빒; 빒; 빒; 빒; ) HANGUL SYLLABLE BILP +BE53;BE53;1107 1175 11B6;BE53;1107 1175 11B6; # (빓; 빓; 빓; 빓; 빓; ) HANGUL SYLLABLE BILH +BE54;BE54;1107 1175 11B7;BE54;1107 1175 11B7; # (빔; 빔; 빔; 빔; 빔; ) HANGUL SYLLABLE BIM +BE55;BE55;1107 1175 11B8;BE55;1107 1175 11B8; # (빕; 빕; 빕; 빕; 빕; ) HANGUL SYLLABLE BIB +BE56;BE56;1107 1175 11B9;BE56;1107 1175 11B9; # (빖; 빖; 빖; 빖; 빖; ) HANGUL SYLLABLE BIBS +BE57;BE57;1107 1175 11BA;BE57;1107 1175 11BA; # (빗; 빗; 빗; 빗; 빗; ) HANGUL SYLLABLE BIS +BE58;BE58;1107 1175 11BB;BE58;1107 1175 11BB; # (빘; 빘; 빘; 빘; 빘; ) HANGUL SYLLABLE BISS +BE59;BE59;1107 1175 11BC;BE59;1107 1175 11BC; # (빙; 빙; 빙; 빙; 빙; ) HANGUL SYLLABLE BING +BE5A;BE5A;1107 1175 11BD;BE5A;1107 1175 11BD; # (빚; 빚; 빚; 빚; 빚; ) HANGUL SYLLABLE BIJ +BE5B;BE5B;1107 1175 11BE;BE5B;1107 1175 11BE; # (빛; 빛; 빛; 빛; 빛; ) HANGUL SYLLABLE BIC +BE5C;BE5C;1107 1175 11BF;BE5C;1107 1175 11BF; # (빜; 빜; 빜; 빜; 빜; ) HANGUL SYLLABLE BIK +BE5D;BE5D;1107 1175 11C0;BE5D;1107 1175 11C0; # (빝; 빝; 빝; 빝; 빝; ) HANGUL SYLLABLE BIT +BE5E;BE5E;1107 1175 11C1;BE5E;1107 1175 11C1; # (빞; 빞; 빞; 빞; 빞; ) HANGUL SYLLABLE BIP +BE5F;BE5F;1107 1175 11C2;BE5F;1107 1175 11C2; # (빟; 빟; 빟; 빟; 빟; ) HANGUL SYLLABLE BIH +BE60;BE60;1108 1161;BE60;1108 1161; # (빠; 빠; 빠; 빠; 빠; ) HANGUL SYLLABLE BBA +BE61;BE61;1108 1161 11A8;BE61;1108 1161 11A8; # (빡; 빡; 빡; 빡; 빡; ) HANGUL SYLLABLE BBAG +BE62;BE62;1108 1161 11A9;BE62;1108 1161 11A9; # (빢; 빢; 빢; 빢; 빢; ) HANGUL SYLLABLE BBAGG +BE63;BE63;1108 1161 11AA;BE63;1108 1161 11AA; # (빣; 빣; 빣; 빣; 빣; ) HANGUL SYLLABLE BBAGS +BE64;BE64;1108 1161 11AB;BE64;1108 1161 11AB; # (빤; 빤; 빤; 빤; 빤; ) HANGUL SYLLABLE BBAN +BE65;BE65;1108 1161 11AC;BE65;1108 1161 11AC; # (빥; 빥; 빥; 빥; 빥; ) HANGUL SYLLABLE BBANJ +BE66;BE66;1108 1161 11AD;BE66;1108 1161 11AD; # (빦; 빦; 빦; 빦; 빦; ) HANGUL SYLLABLE BBANH +BE67;BE67;1108 1161 11AE;BE67;1108 1161 11AE; # (빧; 빧; 빧; 빧; 빧; ) HANGUL SYLLABLE BBAD +BE68;BE68;1108 1161 11AF;BE68;1108 1161 11AF; # (빨; 빨; 빨; 빨; 빨; ) HANGUL SYLLABLE BBAL +BE69;BE69;1108 1161 11B0;BE69;1108 1161 11B0; # (빩; 빩; 빩; 빩; 빩; ) HANGUL SYLLABLE BBALG +BE6A;BE6A;1108 1161 11B1;BE6A;1108 1161 11B1; # (빪; 빪; 빪; 빪; 빪; ) HANGUL SYLLABLE BBALM +BE6B;BE6B;1108 1161 11B2;BE6B;1108 1161 11B2; # (빫; 빫; 빫; 빫; 빫; ) HANGUL SYLLABLE BBALB +BE6C;BE6C;1108 1161 11B3;BE6C;1108 1161 11B3; # (빬; 빬; 빬; 빬; 빬; ) HANGUL SYLLABLE BBALS +BE6D;BE6D;1108 1161 11B4;BE6D;1108 1161 11B4; # (빭; 빭; 빭; 빭; 빭; ) HANGUL SYLLABLE BBALT +BE6E;BE6E;1108 1161 11B5;BE6E;1108 1161 11B5; # (빮; 빮; 빮; 빮; 빮; ) HANGUL SYLLABLE BBALP +BE6F;BE6F;1108 1161 11B6;BE6F;1108 1161 11B6; # (빯; 빯; 빯; 빯; 빯; ) HANGUL SYLLABLE BBALH +BE70;BE70;1108 1161 11B7;BE70;1108 1161 11B7; # (빰; 빰; 빰; 빰; 빰; ) HANGUL SYLLABLE BBAM +BE71;BE71;1108 1161 11B8;BE71;1108 1161 11B8; # (빱; 빱; 빱; 빱; 빱; ) HANGUL SYLLABLE BBAB +BE72;BE72;1108 1161 11B9;BE72;1108 1161 11B9; # (빲; 빲; 빲; 빲; 빲; ) HANGUL SYLLABLE BBABS +BE73;BE73;1108 1161 11BA;BE73;1108 1161 11BA; # (빳; 빳; 빳; 빳; 빳; ) HANGUL SYLLABLE BBAS +BE74;BE74;1108 1161 11BB;BE74;1108 1161 11BB; # (빴; 빴; 빴; 빴; 빴; ) HANGUL SYLLABLE BBASS +BE75;BE75;1108 1161 11BC;BE75;1108 1161 11BC; # (빵; 빵; 빵; 빵; 빵; ) HANGUL SYLLABLE BBANG +BE76;BE76;1108 1161 11BD;BE76;1108 1161 11BD; # (빶; 빶; 빶; 빶; 빶; ) HANGUL SYLLABLE BBAJ +BE77;BE77;1108 1161 11BE;BE77;1108 1161 11BE; # (빷; 빷; 빷; 빷; 빷; ) HANGUL SYLLABLE BBAC +BE78;BE78;1108 1161 11BF;BE78;1108 1161 11BF; # (빸; 빸; 빸; 빸; 빸; ) HANGUL SYLLABLE BBAK +BE79;BE79;1108 1161 11C0;BE79;1108 1161 11C0; # (빹; 빹; 빹; 빹; 빹; ) HANGUL SYLLABLE BBAT +BE7A;BE7A;1108 1161 11C1;BE7A;1108 1161 11C1; # (빺; 빺; 빺; 빺; 빺; ) HANGUL SYLLABLE BBAP +BE7B;BE7B;1108 1161 11C2;BE7B;1108 1161 11C2; # (빻; 빻; 빻; 빻; 빻; ) HANGUL SYLLABLE BBAH +BE7C;BE7C;1108 1162;BE7C;1108 1162; # (빼; 빼; 빼; 빼; 빼; ) HANGUL SYLLABLE BBAE +BE7D;BE7D;1108 1162 11A8;BE7D;1108 1162 11A8; # (빽; 빽; 빽; 빽; 빽; ) HANGUL SYLLABLE BBAEG +BE7E;BE7E;1108 1162 11A9;BE7E;1108 1162 11A9; # (빾; 빾; 빾; 빾; 빾; ) HANGUL SYLLABLE BBAEGG +BE7F;BE7F;1108 1162 11AA;BE7F;1108 1162 11AA; # (빿; 빿; 빿; 빿; 빿; ) HANGUL SYLLABLE BBAEGS +BE80;BE80;1108 1162 11AB;BE80;1108 1162 11AB; # (뺀; 뺀; 뺀; 뺀; 뺀; ) HANGUL SYLLABLE BBAEN +BE81;BE81;1108 1162 11AC;BE81;1108 1162 11AC; # (뺁; 뺁; 뺁; 뺁; 뺁; ) HANGUL SYLLABLE BBAENJ +BE82;BE82;1108 1162 11AD;BE82;1108 1162 11AD; # (뺂; 뺂; 뺂; 뺂; 뺂; ) HANGUL SYLLABLE BBAENH +BE83;BE83;1108 1162 11AE;BE83;1108 1162 11AE; # (뺃; 뺃; 뺃; 뺃; 뺃; ) HANGUL SYLLABLE BBAED +BE84;BE84;1108 1162 11AF;BE84;1108 1162 11AF; # (뺄; 뺄; 뺄; 뺄; 뺄; ) HANGUL SYLLABLE BBAEL +BE85;BE85;1108 1162 11B0;BE85;1108 1162 11B0; # (뺅; 뺅; 뺅; 뺅; 뺅; ) HANGUL SYLLABLE BBAELG +BE86;BE86;1108 1162 11B1;BE86;1108 1162 11B1; # (뺆; 뺆; 뺆; 뺆; 뺆; ) HANGUL SYLLABLE BBAELM +BE87;BE87;1108 1162 11B2;BE87;1108 1162 11B2; # (뺇; 뺇; 뺇; 뺇; 뺇; ) HANGUL SYLLABLE BBAELB +BE88;BE88;1108 1162 11B3;BE88;1108 1162 11B3; # (뺈; 뺈; 뺈; 뺈; 뺈; ) HANGUL SYLLABLE BBAELS +BE89;BE89;1108 1162 11B4;BE89;1108 1162 11B4; # (뺉; 뺉; 뺉; 뺉; 뺉; ) HANGUL SYLLABLE BBAELT +BE8A;BE8A;1108 1162 11B5;BE8A;1108 1162 11B5; # (뺊; 뺊; 뺊; 뺊; 뺊; ) HANGUL SYLLABLE BBAELP +BE8B;BE8B;1108 1162 11B6;BE8B;1108 1162 11B6; # (뺋; 뺋; 뺋; 뺋; 뺋; ) HANGUL SYLLABLE BBAELH +BE8C;BE8C;1108 1162 11B7;BE8C;1108 1162 11B7; # (뺌; 뺌; 뺌; 뺌; 뺌; ) HANGUL SYLLABLE BBAEM +BE8D;BE8D;1108 1162 11B8;BE8D;1108 1162 11B8; # (뺍; 뺍; 뺍; 뺍; 뺍; ) HANGUL SYLLABLE BBAEB +BE8E;BE8E;1108 1162 11B9;BE8E;1108 1162 11B9; # (뺎; 뺎; 뺎; 뺎; 뺎; ) HANGUL SYLLABLE BBAEBS +BE8F;BE8F;1108 1162 11BA;BE8F;1108 1162 11BA; # (뺏; 뺏; 뺏; 뺏; 뺏; ) HANGUL SYLLABLE BBAES +BE90;BE90;1108 1162 11BB;BE90;1108 1162 11BB; # (뺐; 뺐; 뺐; 뺐; 뺐; ) HANGUL SYLLABLE BBAESS +BE91;BE91;1108 1162 11BC;BE91;1108 1162 11BC; # (뺑; 뺑; 뺑; 뺑; 뺑; ) HANGUL SYLLABLE BBAENG +BE92;BE92;1108 1162 11BD;BE92;1108 1162 11BD; # (뺒; 뺒; 뺒; 뺒; 뺒; ) HANGUL SYLLABLE BBAEJ +BE93;BE93;1108 1162 11BE;BE93;1108 1162 11BE; # (뺓; 뺓; 뺓; 뺓; 뺓; ) HANGUL SYLLABLE BBAEC +BE94;BE94;1108 1162 11BF;BE94;1108 1162 11BF; # (뺔; 뺔; 뺔; 뺔; 뺔; ) HANGUL SYLLABLE BBAEK +BE95;BE95;1108 1162 11C0;BE95;1108 1162 11C0; # (뺕; 뺕; 뺕; 뺕; 뺕; ) HANGUL SYLLABLE BBAET +BE96;BE96;1108 1162 11C1;BE96;1108 1162 11C1; # (뺖; 뺖; 뺖; 뺖; 뺖; ) HANGUL SYLLABLE BBAEP +BE97;BE97;1108 1162 11C2;BE97;1108 1162 11C2; # (뺗; 뺗; 뺗; 뺗; 뺗; ) HANGUL SYLLABLE BBAEH +BE98;BE98;1108 1163;BE98;1108 1163; # (뺘; 뺘; 뺘; 뺘; 뺘; ) HANGUL SYLLABLE BBYA +BE99;BE99;1108 1163 11A8;BE99;1108 1163 11A8; # (뺙; 뺙; 뺙; 뺙; 뺙; ) HANGUL SYLLABLE BBYAG +BE9A;BE9A;1108 1163 11A9;BE9A;1108 1163 11A9; # (뺚; 뺚; 뺚; 뺚; 뺚; ) HANGUL SYLLABLE BBYAGG +BE9B;BE9B;1108 1163 11AA;BE9B;1108 1163 11AA; # (뺛; 뺛; 뺛; 뺛; 뺛; ) HANGUL SYLLABLE BBYAGS +BE9C;BE9C;1108 1163 11AB;BE9C;1108 1163 11AB; # (뺜; 뺜; 뺜; 뺜; 뺜; ) HANGUL SYLLABLE BBYAN +BE9D;BE9D;1108 1163 11AC;BE9D;1108 1163 11AC; # (뺝; 뺝; 뺝; 뺝; 뺝; ) HANGUL SYLLABLE BBYANJ +BE9E;BE9E;1108 1163 11AD;BE9E;1108 1163 11AD; # (뺞; 뺞; 뺞; 뺞; 뺞; ) HANGUL SYLLABLE BBYANH +BE9F;BE9F;1108 1163 11AE;BE9F;1108 1163 11AE; # (뺟; 뺟; 뺟; 뺟; 뺟; ) HANGUL SYLLABLE BBYAD +BEA0;BEA0;1108 1163 11AF;BEA0;1108 1163 11AF; # (뺠; 뺠; 뺠; 뺠; 뺠; ) HANGUL SYLLABLE BBYAL +BEA1;BEA1;1108 1163 11B0;BEA1;1108 1163 11B0; # (뺡; 뺡; 뺡; 뺡; 뺡; ) HANGUL SYLLABLE BBYALG +BEA2;BEA2;1108 1163 11B1;BEA2;1108 1163 11B1; # (뺢; 뺢; 뺢; 뺢; 뺢; ) HANGUL SYLLABLE BBYALM +BEA3;BEA3;1108 1163 11B2;BEA3;1108 1163 11B2; # (뺣; 뺣; 뺣; 뺣; 뺣; ) HANGUL SYLLABLE BBYALB +BEA4;BEA4;1108 1163 11B3;BEA4;1108 1163 11B3; # (뺤; 뺤; 뺤; 뺤; 뺤; ) HANGUL SYLLABLE BBYALS +BEA5;BEA5;1108 1163 11B4;BEA5;1108 1163 11B4; # (뺥; 뺥; 뺥; 뺥; 뺥; ) HANGUL SYLLABLE BBYALT +BEA6;BEA6;1108 1163 11B5;BEA6;1108 1163 11B5; # (뺦; 뺦; 뺦; 뺦; 뺦; ) HANGUL SYLLABLE BBYALP +BEA7;BEA7;1108 1163 11B6;BEA7;1108 1163 11B6; # (뺧; 뺧; 뺧; 뺧; 뺧; ) HANGUL SYLLABLE BBYALH +BEA8;BEA8;1108 1163 11B7;BEA8;1108 1163 11B7; # (뺨; 뺨; 뺨; 뺨; 뺨; ) HANGUL SYLLABLE BBYAM +BEA9;BEA9;1108 1163 11B8;BEA9;1108 1163 11B8; # (뺩; 뺩; 뺩; 뺩; 뺩; ) HANGUL SYLLABLE BBYAB +BEAA;BEAA;1108 1163 11B9;BEAA;1108 1163 11B9; # (뺪; 뺪; 뺪; 뺪; 뺪; ) HANGUL SYLLABLE BBYABS +BEAB;BEAB;1108 1163 11BA;BEAB;1108 1163 11BA; # (뺫; 뺫; 뺫; 뺫; 뺫; ) HANGUL SYLLABLE BBYAS +BEAC;BEAC;1108 1163 11BB;BEAC;1108 1163 11BB; # (뺬; 뺬; 뺬; 뺬; 뺬; ) HANGUL SYLLABLE BBYASS +BEAD;BEAD;1108 1163 11BC;BEAD;1108 1163 11BC; # (뺭; 뺭; 뺭; 뺭; 뺭; ) HANGUL SYLLABLE BBYANG +BEAE;BEAE;1108 1163 11BD;BEAE;1108 1163 11BD; # (뺮; 뺮; 뺮; 뺮; 뺮; ) HANGUL SYLLABLE BBYAJ +BEAF;BEAF;1108 1163 11BE;BEAF;1108 1163 11BE; # (뺯; 뺯; 뺯; 뺯; 뺯; ) HANGUL SYLLABLE BBYAC +BEB0;BEB0;1108 1163 11BF;BEB0;1108 1163 11BF; # (뺰; 뺰; 뺰; 뺰; 뺰; ) HANGUL SYLLABLE BBYAK +BEB1;BEB1;1108 1163 11C0;BEB1;1108 1163 11C0; # (뺱; 뺱; 뺱; 뺱; 뺱; ) HANGUL SYLLABLE BBYAT +BEB2;BEB2;1108 1163 11C1;BEB2;1108 1163 11C1; # (뺲; 뺲; 뺲; 뺲; 뺲; ) HANGUL SYLLABLE BBYAP +BEB3;BEB3;1108 1163 11C2;BEB3;1108 1163 11C2; # (뺳; 뺳; 뺳; 뺳; 뺳; ) HANGUL SYLLABLE BBYAH +BEB4;BEB4;1108 1164;BEB4;1108 1164; # (뺴; 뺴; 뺴; 뺴; 뺴; ) HANGUL SYLLABLE BBYAE +BEB5;BEB5;1108 1164 11A8;BEB5;1108 1164 11A8; # (뺵; 뺵; 뺵; 뺵; 뺵; ) HANGUL SYLLABLE BBYAEG +BEB6;BEB6;1108 1164 11A9;BEB6;1108 1164 11A9; # (뺶; 뺶; 뺶; 뺶; 뺶; ) HANGUL SYLLABLE BBYAEGG +BEB7;BEB7;1108 1164 11AA;BEB7;1108 1164 11AA; # (뺷; 뺷; 뺷; 뺷; 뺷; ) HANGUL SYLLABLE BBYAEGS +BEB8;BEB8;1108 1164 11AB;BEB8;1108 1164 11AB; # (뺸; 뺸; 뺸; 뺸; 뺸; ) HANGUL SYLLABLE BBYAEN +BEB9;BEB9;1108 1164 11AC;BEB9;1108 1164 11AC; # (뺹; 뺹; 뺹; 뺹; 뺹; ) HANGUL SYLLABLE BBYAENJ +BEBA;BEBA;1108 1164 11AD;BEBA;1108 1164 11AD; # (뺺; 뺺; 뺺; 뺺; 뺺; ) HANGUL SYLLABLE BBYAENH +BEBB;BEBB;1108 1164 11AE;BEBB;1108 1164 11AE; # (뺻; 뺻; 뺻; 뺻; 뺻; ) HANGUL SYLLABLE BBYAED +BEBC;BEBC;1108 1164 11AF;BEBC;1108 1164 11AF; # (뺼; 뺼; 뺼; 뺼; 뺼; ) HANGUL SYLLABLE BBYAEL +BEBD;BEBD;1108 1164 11B0;BEBD;1108 1164 11B0; # (뺽; 뺽; 뺽; 뺽; 뺽; ) HANGUL SYLLABLE BBYAELG +BEBE;BEBE;1108 1164 11B1;BEBE;1108 1164 11B1; # (뺾; 뺾; 뺾; 뺾; 뺾; ) HANGUL SYLLABLE BBYAELM +BEBF;BEBF;1108 1164 11B2;BEBF;1108 1164 11B2; # (뺿; 뺿; 뺿; 뺿; 뺿; ) HANGUL SYLLABLE BBYAELB +BEC0;BEC0;1108 1164 11B3;BEC0;1108 1164 11B3; # (뻀; 뻀; 뻀; 뻀; 뻀; ) HANGUL SYLLABLE BBYAELS +BEC1;BEC1;1108 1164 11B4;BEC1;1108 1164 11B4; # (뻁; 뻁; 뻁; 뻁; 뻁; ) HANGUL SYLLABLE BBYAELT +BEC2;BEC2;1108 1164 11B5;BEC2;1108 1164 11B5; # (뻂; 뻂; 뻂; 뻂; 뻂; ) HANGUL SYLLABLE BBYAELP +BEC3;BEC3;1108 1164 11B6;BEC3;1108 1164 11B6; # (뻃; 뻃; 뻃; 뻃; 뻃; ) HANGUL SYLLABLE BBYAELH +BEC4;BEC4;1108 1164 11B7;BEC4;1108 1164 11B7; # (뻄; 뻄; 뻄; 뻄; 뻄; ) HANGUL SYLLABLE BBYAEM +BEC5;BEC5;1108 1164 11B8;BEC5;1108 1164 11B8; # (뻅; 뻅; 뻅; 뻅; 뻅; ) HANGUL SYLLABLE BBYAEB +BEC6;BEC6;1108 1164 11B9;BEC6;1108 1164 11B9; # (뻆; 뻆; 뻆; 뻆; 뻆; ) HANGUL SYLLABLE BBYAEBS +BEC7;BEC7;1108 1164 11BA;BEC7;1108 1164 11BA; # (뻇; 뻇; 뻇; 뻇; 뻇; ) HANGUL SYLLABLE BBYAES +BEC8;BEC8;1108 1164 11BB;BEC8;1108 1164 11BB; # (뻈; 뻈; 뻈; 뻈; 뻈; ) HANGUL SYLLABLE BBYAESS +BEC9;BEC9;1108 1164 11BC;BEC9;1108 1164 11BC; # (뻉; 뻉; 뻉; 뻉; 뻉; ) HANGUL SYLLABLE BBYAENG +BECA;BECA;1108 1164 11BD;BECA;1108 1164 11BD; # (뻊; 뻊; 뻊; 뻊; 뻊; ) HANGUL SYLLABLE BBYAEJ +BECB;BECB;1108 1164 11BE;BECB;1108 1164 11BE; # (뻋; 뻋; 뻋; 뻋; 뻋; ) HANGUL SYLLABLE BBYAEC +BECC;BECC;1108 1164 11BF;BECC;1108 1164 11BF; # (뻌; 뻌; 뻌; 뻌; 뻌; ) HANGUL SYLLABLE BBYAEK +BECD;BECD;1108 1164 11C0;BECD;1108 1164 11C0; # (뻍; 뻍; 뻍; 뻍; 뻍; ) HANGUL SYLLABLE BBYAET +BECE;BECE;1108 1164 11C1;BECE;1108 1164 11C1; # (뻎; 뻎; 뻎; 뻎; 뻎; ) HANGUL SYLLABLE BBYAEP +BECF;BECF;1108 1164 11C2;BECF;1108 1164 11C2; # (뻏; 뻏; 뻏; 뻏; 뻏; ) HANGUL SYLLABLE BBYAEH +BED0;BED0;1108 1165;BED0;1108 1165; # (뻐; 뻐; 뻐; 뻐; 뻐; ) HANGUL SYLLABLE BBEO +BED1;BED1;1108 1165 11A8;BED1;1108 1165 11A8; # (뻑; 뻑; 뻑; 뻑; 뻑; ) HANGUL SYLLABLE BBEOG +BED2;BED2;1108 1165 11A9;BED2;1108 1165 11A9; # (뻒; 뻒; 뻒; 뻒; 뻒; ) HANGUL SYLLABLE BBEOGG +BED3;BED3;1108 1165 11AA;BED3;1108 1165 11AA; # (뻓; 뻓; 뻓; 뻓; 뻓; ) HANGUL SYLLABLE BBEOGS +BED4;BED4;1108 1165 11AB;BED4;1108 1165 11AB; # (뻔; 뻔; 뻔; 뻔; 뻔; ) HANGUL SYLLABLE BBEON +BED5;BED5;1108 1165 11AC;BED5;1108 1165 11AC; # (뻕; 뻕; 뻕; 뻕; 뻕; ) HANGUL SYLLABLE BBEONJ +BED6;BED6;1108 1165 11AD;BED6;1108 1165 11AD; # (뻖; 뻖; 뻖; 뻖; 뻖; ) HANGUL SYLLABLE BBEONH +BED7;BED7;1108 1165 11AE;BED7;1108 1165 11AE; # (뻗; 뻗; 뻗; 뻗; 뻗; ) HANGUL SYLLABLE BBEOD +BED8;BED8;1108 1165 11AF;BED8;1108 1165 11AF; # (뻘; 뻘; 뻘; 뻘; 뻘; ) HANGUL SYLLABLE BBEOL +BED9;BED9;1108 1165 11B0;BED9;1108 1165 11B0; # (뻙; 뻙; 뻙; 뻙; 뻙; ) HANGUL SYLLABLE BBEOLG +BEDA;BEDA;1108 1165 11B1;BEDA;1108 1165 11B1; # (뻚; 뻚; 뻚; 뻚; 뻚; ) HANGUL SYLLABLE BBEOLM +BEDB;BEDB;1108 1165 11B2;BEDB;1108 1165 11B2; # (뻛; 뻛; 뻛; 뻛; 뻛; ) HANGUL SYLLABLE BBEOLB +BEDC;BEDC;1108 1165 11B3;BEDC;1108 1165 11B3; # (뻜; 뻜; 뻜; 뻜; 뻜; ) HANGUL SYLLABLE BBEOLS +BEDD;BEDD;1108 1165 11B4;BEDD;1108 1165 11B4; # (뻝; 뻝; 뻝; 뻝; 뻝; ) HANGUL SYLLABLE BBEOLT +BEDE;BEDE;1108 1165 11B5;BEDE;1108 1165 11B5; # (뻞; 뻞; 뻞; 뻞; 뻞; ) HANGUL SYLLABLE BBEOLP +BEDF;BEDF;1108 1165 11B6;BEDF;1108 1165 11B6; # (뻟; 뻟; 뻟; 뻟; 뻟; ) HANGUL SYLLABLE BBEOLH +BEE0;BEE0;1108 1165 11B7;BEE0;1108 1165 11B7; # (뻠; 뻠; 뻠; 뻠; 뻠; ) HANGUL SYLLABLE BBEOM +BEE1;BEE1;1108 1165 11B8;BEE1;1108 1165 11B8; # (뻡; 뻡; 뻡; 뻡; 뻡; ) HANGUL SYLLABLE BBEOB +BEE2;BEE2;1108 1165 11B9;BEE2;1108 1165 11B9; # (뻢; 뻢; 뻢; 뻢; 뻢; ) HANGUL SYLLABLE BBEOBS +BEE3;BEE3;1108 1165 11BA;BEE3;1108 1165 11BA; # (뻣; 뻣; 뻣; 뻣; 뻣; ) HANGUL SYLLABLE BBEOS +BEE4;BEE4;1108 1165 11BB;BEE4;1108 1165 11BB; # (뻤; 뻤; 뻤; 뻤; 뻤; ) HANGUL SYLLABLE BBEOSS +BEE5;BEE5;1108 1165 11BC;BEE5;1108 1165 11BC; # (뻥; 뻥; 뻥; 뻥; 뻥; ) HANGUL SYLLABLE BBEONG +BEE6;BEE6;1108 1165 11BD;BEE6;1108 1165 11BD; # (뻦; 뻦; 뻦; 뻦; 뻦; ) HANGUL SYLLABLE BBEOJ +BEE7;BEE7;1108 1165 11BE;BEE7;1108 1165 11BE; # (뻧; 뻧; 뻧; 뻧; 뻧; ) HANGUL SYLLABLE BBEOC +BEE8;BEE8;1108 1165 11BF;BEE8;1108 1165 11BF; # (뻨; 뻨; 뻨; 뻨; 뻨; ) HANGUL SYLLABLE BBEOK +BEE9;BEE9;1108 1165 11C0;BEE9;1108 1165 11C0; # (뻩; 뻩; 뻩; 뻩; 뻩; ) HANGUL SYLLABLE BBEOT +BEEA;BEEA;1108 1165 11C1;BEEA;1108 1165 11C1; # (뻪; 뻪; 뻪; 뻪; 뻪; ) HANGUL SYLLABLE BBEOP +BEEB;BEEB;1108 1165 11C2;BEEB;1108 1165 11C2; # (뻫; 뻫; 뻫; 뻫; 뻫; ) HANGUL SYLLABLE BBEOH +BEEC;BEEC;1108 1166;BEEC;1108 1166; # (뻬; 뻬; 뻬; 뻬; 뻬; ) HANGUL SYLLABLE BBE +BEED;BEED;1108 1166 11A8;BEED;1108 1166 11A8; # (뻭; 뻭; 뻭; 뻭; 뻭; ) HANGUL SYLLABLE BBEG +BEEE;BEEE;1108 1166 11A9;BEEE;1108 1166 11A9; # (뻮; 뻮; 뻮; 뻮; 뻮; ) HANGUL SYLLABLE BBEGG +BEEF;BEEF;1108 1166 11AA;BEEF;1108 1166 11AA; # (뻯; 뻯; 뻯; 뻯; 뻯; ) HANGUL SYLLABLE BBEGS +BEF0;BEF0;1108 1166 11AB;BEF0;1108 1166 11AB; # (뻰; 뻰; 뻰; 뻰; 뻰; ) HANGUL SYLLABLE BBEN +BEF1;BEF1;1108 1166 11AC;BEF1;1108 1166 11AC; # (뻱; 뻱; 뻱; 뻱; 뻱; ) HANGUL SYLLABLE BBENJ +BEF2;BEF2;1108 1166 11AD;BEF2;1108 1166 11AD; # (뻲; 뻲; 뻲; 뻲; 뻲; ) HANGUL SYLLABLE BBENH +BEF3;BEF3;1108 1166 11AE;BEF3;1108 1166 11AE; # (뻳; 뻳; 뻳; 뻳; 뻳; ) HANGUL SYLLABLE BBED +BEF4;BEF4;1108 1166 11AF;BEF4;1108 1166 11AF; # (뻴; 뻴; 뻴; 뻴; 뻴; ) HANGUL SYLLABLE BBEL +BEF5;BEF5;1108 1166 11B0;BEF5;1108 1166 11B0; # (뻵; 뻵; 뻵; 뻵; 뻵; ) HANGUL SYLLABLE BBELG +BEF6;BEF6;1108 1166 11B1;BEF6;1108 1166 11B1; # (뻶; 뻶; 뻶; 뻶; 뻶; ) HANGUL SYLLABLE BBELM +BEF7;BEF7;1108 1166 11B2;BEF7;1108 1166 11B2; # (뻷; 뻷; 뻷; 뻷; 뻷; ) HANGUL SYLLABLE BBELB +BEF8;BEF8;1108 1166 11B3;BEF8;1108 1166 11B3; # (뻸; 뻸; 뻸; 뻸; 뻸; ) HANGUL SYLLABLE BBELS +BEF9;BEF9;1108 1166 11B4;BEF9;1108 1166 11B4; # (뻹; 뻹; 뻹; 뻹; 뻹; ) HANGUL SYLLABLE BBELT +BEFA;BEFA;1108 1166 11B5;BEFA;1108 1166 11B5; # (뻺; 뻺; 뻺; 뻺; 뻺; ) HANGUL SYLLABLE BBELP +BEFB;BEFB;1108 1166 11B6;BEFB;1108 1166 11B6; # (뻻; 뻻; 뻻; 뻻; 뻻; ) HANGUL SYLLABLE BBELH +BEFC;BEFC;1108 1166 11B7;BEFC;1108 1166 11B7; # (뻼; 뻼; 뻼; 뻼; 뻼; ) HANGUL SYLLABLE BBEM +BEFD;BEFD;1108 1166 11B8;BEFD;1108 1166 11B8; # (뻽; 뻽; 뻽; 뻽; 뻽; ) HANGUL SYLLABLE BBEB +BEFE;BEFE;1108 1166 11B9;BEFE;1108 1166 11B9; # (뻾; 뻾; 뻾; 뻾; 뻾; ) HANGUL SYLLABLE BBEBS +BEFF;BEFF;1108 1166 11BA;BEFF;1108 1166 11BA; # (뻿; 뻿; 뻿; 뻿; 뻿; ) HANGUL SYLLABLE BBES +BF00;BF00;1108 1166 11BB;BF00;1108 1166 11BB; # (뼀; 뼀; 뼀; 뼀; 뼀; ) HANGUL SYLLABLE BBESS +BF01;BF01;1108 1166 11BC;BF01;1108 1166 11BC; # (뼁; 뼁; 뼁; 뼁; 뼁; ) HANGUL SYLLABLE BBENG +BF02;BF02;1108 1166 11BD;BF02;1108 1166 11BD; # (뼂; 뼂; 뼂; 뼂; 뼂; ) HANGUL SYLLABLE BBEJ +BF03;BF03;1108 1166 11BE;BF03;1108 1166 11BE; # (뼃; 뼃; 뼃; 뼃; 뼃; ) HANGUL SYLLABLE BBEC +BF04;BF04;1108 1166 11BF;BF04;1108 1166 11BF; # (뼄; 뼄; 뼄; 뼄; 뼄; ) HANGUL SYLLABLE BBEK +BF05;BF05;1108 1166 11C0;BF05;1108 1166 11C0; # (뼅; 뼅; 뼅; 뼅; 뼅; ) HANGUL SYLLABLE BBET +BF06;BF06;1108 1166 11C1;BF06;1108 1166 11C1; # (뼆; 뼆; 뼆; 뼆; 뼆; ) HANGUL SYLLABLE BBEP +BF07;BF07;1108 1166 11C2;BF07;1108 1166 11C2; # (뼇; 뼇; 뼇; 뼇; 뼇; ) HANGUL SYLLABLE BBEH +BF08;BF08;1108 1167;BF08;1108 1167; # (뼈; 뼈; 뼈; 뼈; 뼈; ) HANGUL SYLLABLE BBYEO +BF09;BF09;1108 1167 11A8;BF09;1108 1167 11A8; # (뼉; 뼉; 뼉; 뼉; 뼉; ) HANGUL SYLLABLE BBYEOG +BF0A;BF0A;1108 1167 11A9;BF0A;1108 1167 11A9; # (뼊; 뼊; 뼊; 뼊; 뼊; ) HANGUL SYLLABLE BBYEOGG +BF0B;BF0B;1108 1167 11AA;BF0B;1108 1167 11AA; # (뼋; 뼋; 뼋; 뼋; 뼋; ) HANGUL SYLLABLE BBYEOGS +BF0C;BF0C;1108 1167 11AB;BF0C;1108 1167 11AB; # (뼌; 뼌; 뼌; 뼌; 뼌; ) HANGUL SYLLABLE BBYEON +BF0D;BF0D;1108 1167 11AC;BF0D;1108 1167 11AC; # (뼍; 뼍; 뼍; 뼍; 뼍; ) HANGUL SYLLABLE BBYEONJ +BF0E;BF0E;1108 1167 11AD;BF0E;1108 1167 11AD; # (뼎; 뼎; 뼎; 뼎; 뼎; ) HANGUL SYLLABLE BBYEONH +BF0F;BF0F;1108 1167 11AE;BF0F;1108 1167 11AE; # (뼏; 뼏; 뼏; 뼏; 뼏; ) HANGUL SYLLABLE BBYEOD +BF10;BF10;1108 1167 11AF;BF10;1108 1167 11AF; # (뼐; 뼐; 뼐; 뼐; 뼐; ) HANGUL SYLLABLE BBYEOL +BF11;BF11;1108 1167 11B0;BF11;1108 1167 11B0; # (뼑; 뼑; 뼑; 뼑; 뼑; ) HANGUL SYLLABLE BBYEOLG +BF12;BF12;1108 1167 11B1;BF12;1108 1167 11B1; # (뼒; 뼒; 뼒; 뼒; 뼒; ) HANGUL SYLLABLE BBYEOLM +BF13;BF13;1108 1167 11B2;BF13;1108 1167 11B2; # (뼓; 뼓; 뼓; 뼓; 뼓; ) HANGUL SYLLABLE BBYEOLB +BF14;BF14;1108 1167 11B3;BF14;1108 1167 11B3; # (뼔; 뼔; 뼔; 뼔; 뼔; ) HANGUL SYLLABLE BBYEOLS +BF15;BF15;1108 1167 11B4;BF15;1108 1167 11B4; # (뼕; 뼕; 뼕; 뼕; 뼕; ) HANGUL SYLLABLE BBYEOLT +BF16;BF16;1108 1167 11B5;BF16;1108 1167 11B5; # (뼖; 뼖; 뼖; 뼖; 뼖; ) HANGUL SYLLABLE BBYEOLP +BF17;BF17;1108 1167 11B6;BF17;1108 1167 11B6; # (뼗; 뼗; 뼗; 뼗; 뼗; ) HANGUL SYLLABLE BBYEOLH +BF18;BF18;1108 1167 11B7;BF18;1108 1167 11B7; # (뼘; 뼘; 뼘; 뼘; 뼘; ) HANGUL SYLLABLE BBYEOM +BF19;BF19;1108 1167 11B8;BF19;1108 1167 11B8; # (뼙; 뼙; 뼙; 뼙; 뼙; ) HANGUL SYLLABLE BBYEOB +BF1A;BF1A;1108 1167 11B9;BF1A;1108 1167 11B9; # (뼚; 뼚; 뼚; 뼚; 뼚; ) HANGUL SYLLABLE BBYEOBS +BF1B;BF1B;1108 1167 11BA;BF1B;1108 1167 11BA; # (뼛; 뼛; 뼛; 뼛; 뼛; ) HANGUL SYLLABLE BBYEOS +BF1C;BF1C;1108 1167 11BB;BF1C;1108 1167 11BB; # (뼜; 뼜; 뼜; 뼜; 뼜; ) HANGUL SYLLABLE BBYEOSS +BF1D;BF1D;1108 1167 11BC;BF1D;1108 1167 11BC; # (뼝; 뼝; 뼝; 뼝; 뼝; ) HANGUL SYLLABLE BBYEONG +BF1E;BF1E;1108 1167 11BD;BF1E;1108 1167 11BD; # (뼞; 뼞; 뼞; 뼞; 뼞; ) HANGUL SYLLABLE BBYEOJ +BF1F;BF1F;1108 1167 11BE;BF1F;1108 1167 11BE; # (뼟; 뼟; 뼟; 뼟; 뼟; ) HANGUL SYLLABLE BBYEOC +BF20;BF20;1108 1167 11BF;BF20;1108 1167 11BF; # (뼠; 뼠; 뼠; 뼠; 뼠; ) HANGUL SYLLABLE BBYEOK +BF21;BF21;1108 1167 11C0;BF21;1108 1167 11C0; # (뼡; 뼡; 뼡; 뼡; 뼡; ) HANGUL SYLLABLE BBYEOT +BF22;BF22;1108 1167 11C1;BF22;1108 1167 11C1; # (뼢; 뼢; 뼢; 뼢; 뼢; ) HANGUL SYLLABLE BBYEOP +BF23;BF23;1108 1167 11C2;BF23;1108 1167 11C2; # (뼣; 뼣; 뼣; 뼣; 뼣; ) HANGUL SYLLABLE BBYEOH +BF24;BF24;1108 1168;BF24;1108 1168; # (뼤; 뼤; 뼤; 뼤; 뼤; ) HANGUL SYLLABLE BBYE +BF25;BF25;1108 1168 11A8;BF25;1108 1168 11A8; # (뼥; 뼥; 뼥; 뼥; 뼥; ) HANGUL SYLLABLE BBYEG +BF26;BF26;1108 1168 11A9;BF26;1108 1168 11A9; # (뼦; 뼦; 뼦; 뼦; 뼦; ) HANGUL SYLLABLE BBYEGG +BF27;BF27;1108 1168 11AA;BF27;1108 1168 11AA; # (뼧; 뼧; 뼧; 뼧; 뼧; ) HANGUL SYLLABLE BBYEGS +BF28;BF28;1108 1168 11AB;BF28;1108 1168 11AB; # (뼨; 뼨; 뼨; 뼨; 뼨; ) HANGUL SYLLABLE BBYEN +BF29;BF29;1108 1168 11AC;BF29;1108 1168 11AC; # (뼩; 뼩; 뼩; 뼩; 뼩; ) HANGUL SYLLABLE BBYENJ +BF2A;BF2A;1108 1168 11AD;BF2A;1108 1168 11AD; # (뼪; 뼪; 뼪; 뼪; 뼪; ) HANGUL SYLLABLE BBYENH +BF2B;BF2B;1108 1168 11AE;BF2B;1108 1168 11AE; # (뼫; 뼫; 뼫; 뼫; 뼫; ) HANGUL SYLLABLE BBYED +BF2C;BF2C;1108 1168 11AF;BF2C;1108 1168 11AF; # (뼬; 뼬; 뼬; 뼬; 뼬; ) HANGUL SYLLABLE BBYEL +BF2D;BF2D;1108 1168 11B0;BF2D;1108 1168 11B0; # (뼭; 뼭; 뼭; 뼭; 뼭; ) HANGUL SYLLABLE BBYELG +BF2E;BF2E;1108 1168 11B1;BF2E;1108 1168 11B1; # (뼮; 뼮; 뼮; 뼮; 뼮; ) HANGUL SYLLABLE BBYELM +BF2F;BF2F;1108 1168 11B2;BF2F;1108 1168 11B2; # (뼯; 뼯; 뼯; 뼯; 뼯; ) HANGUL SYLLABLE BBYELB +BF30;BF30;1108 1168 11B3;BF30;1108 1168 11B3; # (뼰; 뼰; 뼰; 뼰; 뼰; ) HANGUL SYLLABLE BBYELS +BF31;BF31;1108 1168 11B4;BF31;1108 1168 11B4; # (뼱; 뼱; 뼱; 뼱; 뼱; ) HANGUL SYLLABLE BBYELT +BF32;BF32;1108 1168 11B5;BF32;1108 1168 11B5; # (뼲; 뼲; 뼲; 뼲; 뼲; ) HANGUL SYLLABLE BBYELP +BF33;BF33;1108 1168 11B6;BF33;1108 1168 11B6; # (뼳; 뼳; 뼳; 뼳; 뼳; ) HANGUL SYLLABLE BBYELH +BF34;BF34;1108 1168 11B7;BF34;1108 1168 11B7; # (뼴; 뼴; 뼴; 뼴; 뼴; ) HANGUL SYLLABLE BBYEM +BF35;BF35;1108 1168 11B8;BF35;1108 1168 11B8; # (뼵; 뼵; 뼵; 뼵; 뼵; ) HANGUL SYLLABLE BBYEB +BF36;BF36;1108 1168 11B9;BF36;1108 1168 11B9; # (뼶; 뼶; 뼶; 뼶; 뼶; ) HANGUL SYLLABLE BBYEBS +BF37;BF37;1108 1168 11BA;BF37;1108 1168 11BA; # (뼷; 뼷; 뼷; 뼷; 뼷; ) HANGUL SYLLABLE BBYES +BF38;BF38;1108 1168 11BB;BF38;1108 1168 11BB; # (뼸; 뼸; 뼸; 뼸; 뼸; ) HANGUL SYLLABLE BBYESS +BF39;BF39;1108 1168 11BC;BF39;1108 1168 11BC; # (뼹; 뼹; 뼹; 뼹; 뼹; ) HANGUL SYLLABLE BBYENG +BF3A;BF3A;1108 1168 11BD;BF3A;1108 1168 11BD; # (뼺; 뼺; 뼺; 뼺; 뼺; ) HANGUL SYLLABLE BBYEJ +BF3B;BF3B;1108 1168 11BE;BF3B;1108 1168 11BE; # (뼻; 뼻; 뼻; 뼻; 뼻; ) HANGUL SYLLABLE BBYEC +BF3C;BF3C;1108 1168 11BF;BF3C;1108 1168 11BF; # (뼼; 뼼; 뼼; 뼼; 뼼; ) HANGUL SYLLABLE BBYEK +BF3D;BF3D;1108 1168 11C0;BF3D;1108 1168 11C0; # (뼽; 뼽; 뼽; 뼽; 뼽; ) HANGUL SYLLABLE BBYET +BF3E;BF3E;1108 1168 11C1;BF3E;1108 1168 11C1; # (뼾; 뼾; 뼾; 뼾; 뼾; ) HANGUL SYLLABLE BBYEP +BF3F;BF3F;1108 1168 11C2;BF3F;1108 1168 11C2; # (뼿; 뼿; 뼿; 뼿; 뼿; ) HANGUL SYLLABLE BBYEH +BF40;BF40;1108 1169;BF40;1108 1169; # (뽀; 뽀; 뽀; 뽀; 뽀; ) HANGUL SYLLABLE BBO +BF41;BF41;1108 1169 11A8;BF41;1108 1169 11A8; # (뽁; 뽁; 뽁; 뽁; 뽁; ) HANGUL SYLLABLE BBOG +BF42;BF42;1108 1169 11A9;BF42;1108 1169 11A9; # (뽂; 뽂; 뽂; 뽂; 뽂; ) HANGUL SYLLABLE BBOGG +BF43;BF43;1108 1169 11AA;BF43;1108 1169 11AA; # (뽃; 뽃; 뽃; 뽃; 뽃; ) HANGUL SYLLABLE BBOGS +BF44;BF44;1108 1169 11AB;BF44;1108 1169 11AB; # (뽄; 뽄; 뽄; 뽄; 뽄; ) HANGUL SYLLABLE BBON +BF45;BF45;1108 1169 11AC;BF45;1108 1169 11AC; # (뽅; 뽅; 뽅; 뽅; 뽅; ) HANGUL SYLLABLE BBONJ +BF46;BF46;1108 1169 11AD;BF46;1108 1169 11AD; # (뽆; 뽆; 뽆; 뽆; 뽆; ) HANGUL SYLLABLE BBONH +BF47;BF47;1108 1169 11AE;BF47;1108 1169 11AE; # (뽇; 뽇; 뽇; 뽇; 뽇; ) HANGUL SYLLABLE BBOD +BF48;BF48;1108 1169 11AF;BF48;1108 1169 11AF; # (뽈; 뽈; 뽈; 뽈; 뽈; ) HANGUL SYLLABLE BBOL +BF49;BF49;1108 1169 11B0;BF49;1108 1169 11B0; # (뽉; 뽉; 뽉; 뽉; 뽉; ) HANGUL SYLLABLE BBOLG +BF4A;BF4A;1108 1169 11B1;BF4A;1108 1169 11B1; # (뽊; 뽊; 뽊; 뽊; 뽊; ) HANGUL SYLLABLE BBOLM +BF4B;BF4B;1108 1169 11B2;BF4B;1108 1169 11B2; # (뽋; 뽋; 뽋; 뽋; 뽋; ) HANGUL SYLLABLE BBOLB +BF4C;BF4C;1108 1169 11B3;BF4C;1108 1169 11B3; # (뽌; 뽌; 뽌; 뽌; 뽌; ) HANGUL SYLLABLE BBOLS +BF4D;BF4D;1108 1169 11B4;BF4D;1108 1169 11B4; # (뽍; 뽍; 뽍; 뽍; 뽍; ) HANGUL SYLLABLE BBOLT +BF4E;BF4E;1108 1169 11B5;BF4E;1108 1169 11B5; # (뽎; 뽎; 뽎; 뽎; 뽎; ) HANGUL SYLLABLE BBOLP +BF4F;BF4F;1108 1169 11B6;BF4F;1108 1169 11B6; # (뽏; 뽏; 뽏; 뽏; 뽏; ) HANGUL SYLLABLE BBOLH +BF50;BF50;1108 1169 11B7;BF50;1108 1169 11B7; # (뽐; 뽐; 뽐; 뽐; 뽐; ) HANGUL SYLLABLE BBOM +BF51;BF51;1108 1169 11B8;BF51;1108 1169 11B8; # (뽑; 뽑; 뽑; 뽑; 뽑; ) HANGUL SYLLABLE BBOB +BF52;BF52;1108 1169 11B9;BF52;1108 1169 11B9; # (뽒; 뽒; 뽒; 뽒; 뽒; ) HANGUL SYLLABLE BBOBS +BF53;BF53;1108 1169 11BA;BF53;1108 1169 11BA; # (뽓; 뽓; 뽓; 뽓; 뽓; ) HANGUL SYLLABLE BBOS +BF54;BF54;1108 1169 11BB;BF54;1108 1169 11BB; # (뽔; 뽔; 뽔; 뽔; 뽔; ) HANGUL SYLLABLE BBOSS +BF55;BF55;1108 1169 11BC;BF55;1108 1169 11BC; # (뽕; 뽕; 뽕; 뽕; 뽕; ) HANGUL SYLLABLE BBONG +BF56;BF56;1108 1169 11BD;BF56;1108 1169 11BD; # (뽖; 뽖; 뽖; 뽖; 뽖; ) HANGUL SYLLABLE BBOJ +BF57;BF57;1108 1169 11BE;BF57;1108 1169 11BE; # (뽗; 뽗; 뽗; 뽗; 뽗; ) HANGUL SYLLABLE BBOC +BF58;BF58;1108 1169 11BF;BF58;1108 1169 11BF; # (뽘; 뽘; 뽘; 뽘; 뽘; ) HANGUL SYLLABLE BBOK +BF59;BF59;1108 1169 11C0;BF59;1108 1169 11C0; # (뽙; 뽙; 뽙; 뽙; 뽙; ) HANGUL SYLLABLE BBOT +BF5A;BF5A;1108 1169 11C1;BF5A;1108 1169 11C1; # (뽚; 뽚; 뽚; 뽚; 뽚; ) HANGUL SYLLABLE BBOP +BF5B;BF5B;1108 1169 11C2;BF5B;1108 1169 11C2; # (뽛; 뽛; 뽛; 뽛; 뽛; ) HANGUL SYLLABLE BBOH +BF5C;BF5C;1108 116A;BF5C;1108 116A; # (뽜; 뽜; 뽜; 뽜; 뽜; ) HANGUL SYLLABLE BBWA +BF5D;BF5D;1108 116A 11A8;BF5D;1108 116A 11A8; # (뽝; 뽝; 뽝; 뽝; 뽝; ) HANGUL SYLLABLE BBWAG +BF5E;BF5E;1108 116A 11A9;BF5E;1108 116A 11A9; # (뽞; 뽞; 뽞; 뽞; 뽞; ) HANGUL SYLLABLE BBWAGG +BF5F;BF5F;1108 116A 11AA;BF5F;1108 116A 11AA; # (뽟; 뽟; 뽟; 뽟; 뽟; ) HANGUL SYLLABLE BBWAGS +BF60;BF60;1108 116A 11AB;BF60;1108 116A 11AB; # (뽠; 뽠; 뽠; 뽠; 뽠; ) HANGUL SYLLABLE BBWAN +BF61;BF61;1108 116A 11AC;BF61;1108 116A 11AC; # (뽡; 뽡; 뽡; 뽡; 뽡; ) HANGUL SYLLABLE BBWANJ +BF62;BF62;1108 116A 11AD;BF62;1108 116A 11AD; # (뽢; 뽢; 뽢; 뽢; 뽢; ) HANGUL SYLLABLE BBWANH +BF63;BF63;1108 116A 11AE;BF63;1108 116A 11AE; # (뽣; 뽣; 뽣; 뽣; 뽣; ) HANGUL SYLLABLE BBWAD +BF64;BF64;1108 116A 11AF;BF64;1108 116A 11AF; # (뽤; 뽤; 뽤; 뽤; 뽤; ) HANGUL SYLLABLE BBWAL +BF65;BF65;1108 116A 11B0;BF65;1108 116A 11B0; # (뽥; 뽥; 뽥; 뽥; 뽥; ) HANGUL SYLLABLE BBWALG +BF66;BF66;1108 116A 11B1;BF66;1108 116A 11B1; # (뽦; 뽦; 뽦; 뽦; 뽦; ) HANGUL SYLLABLE BBWALM +BF67;BF67;1108 116A 11B2;BF67;1108 116A 11B2; # (뽧; 뽧; 뽧; 뽧; 뽧; ) HANGUL SYLLABLE BBWALB +BF68;BF68;1108 116A 11B3;BF68;1108 116A 11B3; # (뽨; 뽨; 뽨; 뽨; 뽨; ) HANGUL SYLLABLE BBWALS +BF69;BF69;1108 116A 11B4;BF69;1108 116A 11B4; # (뽩; 뽩; 뽩; 뽩; 뽩; ) HANGUL SYLLABLE BBWALT +BF6A;BF6A;1108 116A 11B5;BF6A;1108 116A 11B5; # (뽪; 뽪; 뽪; 뽪; 뽪; ) HANGUL SYLLABLE BBWALP +BF6B;BF6B;1108 116A 11B6;BF6B;1108 116A 11B6; # (뽫; 뽫; 뽫; 뽫; 뽫; ) HANGUL SYLLABLE BBWALH +BF6C;BF6C;1108 116A 11B7;BF6C;1108 116A 11B7; # (뽬; 뽬; 뽬; 뽬; 뽬; ) HANGUL SYLLABLE BBWAM +BF6D;BF6D;1108 116A 11B8;BF6D;1108 116A 11B8; # (뽭; 뽭; 뽭; 뽭; 뽭; ) HANGUL SYLLABLE BBWAB +BF6E;BF6E;1108 116A 11B9;BF6E;1108 116A 11B9; # (뽮; 뽮; 뽮; 뽮; 뽮; ) HANGUL SYLLABLE BBWABS +BF6F;BF6F;1108 116A 11BA;BF6F;1108 116A 11BA; # (뽯; 뽯; 뽯; 뽯; 뽯; ) HANGUL SYLLABLE BBWAS +BF70;BF70;1108 116A 11BB;BF70;1108 116A 11BB; # (뽰; 뽰; 뽰; 뽰; 뽰; ) HANGUL SYLLABLE BBWASS +BF71;BF71;1108 116A 11BC;BF71;1108 116A 11BC; # (뽱; 뽱; 뽱; 뽱; 뽱; ) HANGUL SYLLABLE BBWANG +BF72;BF72;1108 116A 11BD;BF72;1108 116A 11BD; # (뽲; 뽲; 뽲; 뽲; 뽲; ) HANGUL SYLLABLE BBWAJ +BF73;BF73;1108 116A 11BE;BF73;1108 116A 11BE; # (뽳; 뽳; 뽳; 뽳; 뽳; ) HANGUL SYLLABLE BBWAC +BF74;BF74;1108 116A 11BF;BF74;1108 116A 11BF; # (뽴; 뽴; 뽴; 뽴; 뽴; ) HANGUL SYLLABLE BBWAK +BF75;BF75;1108 116A 11C0;BF75;1108 116A 11C0; # (뽵; 뽵; 뽵; 뽵; 뽵; ) HANGUL SYLLABLE BBWAT +BF76;BF76;1108 116A 11C1;BF76;1108 116A 11C1; # (뽶; 뽶; 뽶; 뽶; 뽶; ) HANGUL SYLLABLE BBWAP +BF77;BF77;1108 116A 11C2;BF77;1108 116A 11C2; # (뽷; 뽷; 뽷; 뽷; 뽷; ) HANGUL SYLLABLE BBWAH +BF78;BF78;1108 116B;BF78;1108 116B; # (뽸; 뽸; 뽸; 뽸; 뽸; ) HANGUL SYLLABLE BBWAE +BF79;BF79;1108 116B 11A8;BF79;1108 116B 11A8; # (뽹; 뽹; 뽹; 뽹; 뽹; ) HANGUL SYLLABLE BBWAEG +BF7A;BF7A;1108 116B 11A9;BF7A;1108 116B 11A9; # (뽺; 뽺; 뽺; 뽺; 뽺; ) HANGUL SYLLABLE BBWAEGG +BF7B;BF7B;1108 116B 11AA;BF7B;1108 116B 11AA; # (뽻; 뽻; 뽻; 뽻; 뽻; ) HANGUL SYLLABLE BBWAEGS +BF7C;BF7C;1108 116B 11AB;BF7C;1108 116B 11AB; # (뽼; 뽼; 뽼; 뽼; 뽼; ) HANGUL SYLLABLE BBWAEN +BF7D;BF7D;1108 116B 11AC;BF7D;1108 116B 11AC; # (뽽; 뽽; 뽽; 뽽; 뽽; ) HANGUL SYLLABLE BBWAENJ +BF7E;BF7E;1108 116B 11AD;BF7E;1108 116B 11AD; # (뽾; 뽾; 뽾; 뽾; 뽾; ) HANGUL SYLLABLE BBWAENH +BF7F;BF7F;1108 116B 11AE;BF7F;1108 116B 11AE; # (뽿; 뽿; 뽿; 뽿; 뽿; ) HANGUL SYLLABLE BBWAED +BF80;BF80;1108 116B 11AF;BF80;1108 116B 11AF; # (뾀; 뾀; 뾀; 뾀; 뾀; ) HANGUL SYLLABLE BBWAEL +BF81;BF81;1108 116B 11B0;BF81;1108 116B 11B0; # (뾁; 뾁; 뾁; 뾁; 뾁; ) HANGUL SYLLABLE BBWAELG +BF82;BF82;1108 116B 11B1;BF82;1108 116B 11B1; # (뾂; 뾂; 뾂; 뾂; 뾂; ) HANGUL SYLLABLE BBWAELM +BF83;BF83;1108 116B 11B2;BF83;1108 116B 11B2; # (뾃; 뾃; 뾃; 뾃; 뾃; ) HANGUL SYLLABLE BBWAELB +BF84;BF84;1108 116B 11B3;BF84;1108 116B 11B3; # (뾄; 뾄; 뾄; 뾄; 뾄; ) HANGUL SYLLABLE BBWAELS +BF85;BF85;1108 116B 11B4;BF85;1108 116B 11B4; # (뾅; 뾅; 뾅; 뾅; 뾅; ) HANGUL SYLLABLE BBWAELT +BF86;BF86;1108 116B 11B5;BF86;1108 116B 11B5; # (뾆; 뾆; 뾆; 뾆; 뾆; ) HANGUL SYLLABLE BBWAELP +BF87;BF87;1108 116B 11B6;BF87;1108 116B 11B6; # (뾇; 뾇; 뾇; 뾇; 뾇; ) HANGUL SYLLABLE BBWAELH +BF88;BF88;1108 116B 11B7;BF88;1108 116B 11B7; # (뾈; 뾈; 뾈; 뾈; 뾈; ) HANGUL SYLLABLE BBWAEM +BF89;BF89;1108 116B 11B8;BF89;1108 116B 11B8; # (뾉; 뾉; 뾉; 뾉; 뾉; ) HANGUL SYLLABLE BBWAEB +BF8A;BF8A;1108 116B 11B9;BF8A;1108 116B 11B9; # (뾊; 뾊; 뾊; 뾊; 뾊; ) HANGUL SYLLABLE BBWAEBS +BF8B;BF8B;1108 116B 11BA;BF8B;1108 116B 11BA; # (뾋; 뾋; 뾋; 뾋; 뾋; ) HANGUL SYLLABLE BBWAES +BF8C;BF8C;1108 116B 11BB;BF8C;1108 116B 11BB; # (뾌; 뾌; 뾌; 뾌; 뾌; ) HANGUL SYLLABLE BBWAESS +BF8D;BF8D;1108 116B 11BC;BF8D;1108 116B 11BC; # (뾍; 뾍; 뾍; 뾍; 뾍; ) HANGUL SYLLABLE BBWAENG +BF8E;BF8E;1108 116B 11BD;BF8E;1108 116B 11BD; # (뾎; 뾎; 뾎; 뾎; 뾎; ) HANGUL SYLLABLE BBWAEJ +BF8F;BF8F;1108 116B 11BE;BF8F;1108 116B 11BE; # (뾏; 뾏; 뾏; 뾏; 뾏; ) HANGUL SYLLABLE BBWAEC +BF90;BF90;1108 116B 11BF;BF90;1108 116B 11BF; # (뾐; 뾐; 뾐; 뾐; 뾐; ) HANGUL SYLLABLE BBWAEK +BF91;BF91;1108 116B 11C0;BF91;1108 116B 11C0; # (뾑; 뾑; 뾑; 뾑; 뾑; ) HANGUL SYLLABLE BBWAET +BF92;BF92;1108 116B 11C1;BF92;1108 116B 11C1; # (뾒; 뾒; 뾒; 뾒; 뾒; ) HANGUL SYLLABLE BBWAEP +BF93;BF93;1108 116B 11C2;BF93;1108 116B 11C2; # (뾓; 뾓; 뾓; 뾓; 뾓; ) HANGUL SYLLABLE BBWAEH +BF94;BF94;1108 116C;BF94;1108 116C; # (뾔; 뾔; 뾔; 뾔; 뾔; ) HANGUL SYLLABLE BBOE +BF95;BF95;1108 116C 11A8;BF95;1108 116C 11A8; # (뾕; 뾕; 뾕; 뾕; 뾕; ) HANGUL SYLLABLE BBOEG +BF96;BF96;1108 116C 11A9;BF96;1108 116C 11A9; # (뾖; 뾖; 뾖; 뾖; 뾖; ) HANGUL SYLLABLE BBOEGG +BF97;BF97;1108 116C 11AA;BF97;1108 116C 11AA; # (뾗; 뾗; 뾗; 뾗; 뾗; ) HANGUL SYLLABLE BBOEGS +BF98;BF98;1108 116C 11AB;BF98;1108 116C 11AB; # (뾘; 뾘; 뾘; 뾘; 뾘; ) HANGUL SYLLABLE BBOEN +BF99;BF99;1108 116C 11AC;BF99;1108 116C 11AC; # (뾙; 뾙; 뾙; 뾙; 뾙; ) HANGUL SYLLABLE BBOENJ +BF9A;BF9A;1108 116C 11AD;BF9A;1108 116C 11AD; # (뾚; 뾚; 뾚; 뾚; 뾚; ) HANGUL SYLLABLE BBOENH +BF9B;BF9B;1108 116C 11AE;BF9B;1108 116C 11AE; # (뾛; 뾛; 뾛; 뾛; 뾛; ) HANGUL SYLLABLE BBOED +BF9C;BF9C;1108 116C 11AF;BF9C;1108 116C 11AF; # (뾜; 뾜; 뾜; 뾜; 뾜; ) HANGUL SYLLABLE BBOEL +BF9D;BF9D;1108 116C 11B0;BF9D;1108 116C 11B0; # (뾝; 뾝; 뾝; 뾝; 뾝; ) HANGUL SYLLABLE BBOELG +BF9E;BF9E;1108 116C 11B1;BF9E;1108 116C 11B1; # (뾞; 뾞; 뾞; 뾞; 뾞; ) HANGUL SYLLABLE BBOELM +BF9F;BF9F;1108 116C 11B2;BF9F;1108 116C 11B2; # (뾟; 뾟; 뾟; 뾟; 뾟; ) HANGUL SYLLABLE BBOELB +BFA0;BFA0;1108 116C 11B3;BFA0;1108 116C 11B3; # (뾠; 뾠; 뾠; 뾠; 뾠; ) HANGUL SYLLABLE BBOELS +BFA1;BFA1;1108 116C 11B4;BFA1;1108 116C 11B4; # (뾡; 뾡; 뾡; 뾡; 뾡; ) HANGUL SYLLABLE BBOELT +BFA2;BFA2;1108 116C 11B5;BFA2;1108 116C 11B5; # (뾢; 뾢; 뾢; 뾢; 뾢; ) HANGUL SYLLABLE BBOELP +BFA3;BFA3;1108 116C 11B6;BFA3;1108 116C 11B6; # (뾣; 뾣; 뾣; 뾣; 뾣; ) HANGUL SYLLABLE BBOELH +BFA4;BFA4;1108 116C 11B7;BFA4;1108 116C 11B7; # (뾤; 뾤; 뾤; 뾤; 뾤; ) HANGUL SYLLABLE BBOEM +BFA5;BFA5;1108 116C 11B8;BFA5;1108 116C 11B8; # (뾥; 뾥; 뾥; 뾥; 뾥; ) HANGUL SYLLABLE BBOEB +BFA6;BFA6;1108 116C 11B9;BFA6;1108 116C 11B9; # (뾦; 뾦; 뾦; 뾦; 뾦; ) HANGUL SYLLABLE BBOEBS +BFA7;BFA7;1108 116C 11BA;BFA7;1108 116C 11BA; # (뾧; 뾧; 뾧; 뾧; 뾧; ) HANGUL SYLLABLE BBOES +BFA8;BFA8;1108 116C 11BB;BFA8;1108 116C 11BB; # (뾨; 뾨; 뾨; 뾨; 뾨; ) HANGUL SYLLABLE BBOESS +BFA9;BFA9;1108 116C 11BC;BFA9;1108 116C 11BC; # (뾩; 뾩; 뾩; 뾩; 뾩; ) HANGUL SYLLABLE BBOENG +BFAA;BFAA;1108 116C 11BD;BFAA;1108 116C 11BD; # (뾪; 뾪; 뾪; 뾪; 뾪; ) HANGUL SYLLABLE BBOEJ +BFAB;BFAB;1108 116C 11BE;BFAB;1108 116C 11BE; # (뾫; 뾫; 뾫; 뾫; 뾫; ) HANGUL SYLLABLE BBOEC +BFAC;BFAC;1108 116C 11BF;BFAC;1108 116C 11BF; # (뾬; 뾬; 뾬; 뾬; 뾬; ) HANGUL SYLLABLE BBOEK +BFAD;BFAD;1108 116C 11C0;BFAD;1108 116C 11C0; # (뾭; 뾭; 뾭; 뾭; 뾭; ) HANGUL SYLLABLE BBOET +BFAE;BFAE;1108 116C 11C1;BFAE;1108 116C 11C1; # (뾮; 뾮; 뾮; 뾮; 뾮; ) HANGUL SYLLABLE BBOEP +BFAF;BFAF;1108 116C 11C2;BFAF;1108 116C 11C2; # (뾯; 뾯; 뾯; 뾯; 뾯; ) HANGUL SYLLABLE BBOEH +BFB0;BFB0;1108 116D;BFB0;1108 116D; # (뾰; 뾰; 뾰; 뾰; 뾰; ) HANGUL SYLLABLE BBYO +BFB1;BFB1;1108 116D 11A8;BFB1;1108 116D 11A8; # (뾱; 뾱; 뾱; 뾱; 뾱; ) HANGUL SYLLABLE BBYOG +BFB2;BFB2;1108 116D 11A9;BFB2;1108 116D 11A9; # (뾲; 뾲; 뾲; 뾲; 뾲; ) HANGUL SYLLABLE BBYOGG +BFB3;BFB3;1108 116D 11AA;BFB3;1108 116D 11AA; # (뾳; 뾳; 뾳; 뾳; 뾳; ) HANGUL SYLLABLE BBYOGS +BFB4;BFB4;1108 116D 11AB;BFB4;1108 116D 11AB; # (뾴; 뾴; 뾴; 뾴; 뾴; ) HANGUL SYLLABLE BBYON +BFB5;BFB5;1108 116D 11AC;BFB5;1108 116D 11AC; # (뾵; 뾵; 뾵; 뾵; 뾵; ) HANGUL SYLLABLE BBYONJ +BFB6;BFB6;1108 116D 11AD;BFB6;1108 116D 11AD; # (뾶; 뾶; 뾶; 뾶; 뾶; ) HANGUL SYLLABLE BBYONH +BFB7;BFB7;1108 116D 11AE;BFB7;1108 116D 11AE; # (뾷; 뾷; 뾷; 뾷; 뾷; ) HANGUL SYLLABLE BBYOD +BFB8;BFB8;1108 116D 11AF;BFB8;1108 116D 11AF; # (뾸; 뾸; 뾸; 뾸; 뾸; ) HANGUL SYLLABLE BBYOL +BFB9;BFB9;1108 116D 11B0;BFB9;1108 116D 11B0; # (뾹; 뾹; 뾹; 뾹; 뾹; ) HANGUL SYLLABLE BBYOLG +BFBA;BFBA;1108 116D 11B1;BFBA;1108 116D 11B1; # (뾺; 뾺; 뾺; 뾺; 뾺; ) HANGUL SYLLABLE BBYOLM +BFBB;BFBB;1108 116D 11B2;BFBB;1108 116D 11B2; # (뾻; 뾻; 뾻; 뾻; 뾻; ) HANGUL SYLLABLE BBYOLB +BFBC;BFBC;1108 116D 11B3;BFBC;1108 116D 11B3; # (뾼; 뾼; 뾼; 뾼; 뾼; ) HANGUL SYLLABLE BBYOLS +BFBD;BFBD;1108 116D 11B4;BFBD;1108 116D 11B4; # (뾽; 뾽; 뾽; 뾽; 뾽; ) HANGUL SYLLABLE BBYOLT +BFBE;BFBE;1108 116D 11B5;BFBE;1108 116D 11B5; # (뾾; 뾾; 뾾; 뾾; 뾾; ) HANGUL SYLLABLE BBYOLP +BFBF;BFBF;1108 116D 11B6;BFBF;1108 116D 11B6; # (뾿; 뾿; 뾿; 뾿; 뾿; ) HANGUL SYLLABLE BBYOLH +BFC0;BFC0;1108 116D 11B7;BFC0;1108 116D 11B7; # (뿀; 뿀; 뿀; 뿀; 뿀; ) HANGUL SYLLABLE BBYOM +BFC1;BFC1;1108 116D 11B8;BFC1;1108 116D 11B8; # (뿁; 뿁; 뿁; 뿁; 뿁; ) HANGUL SYLLABLE BBYOB +BFC2;BFC2;1108 116D 11B9;BFC2;1108 116D 11B9; # (뿂; 뿂; 뿂; 뿂; 뿂; ) HANGUL SYLLABLE BBYOBS +BFC3;BFC3;1108 116D 11BA;BFC3;1108 116D 11BA; # (뿃; 뿃; 뿃; 뿃; 뿃; ) HANGUL SYLLABLE BBYOS +BFC4;BFC4;1108 116D 11BB;BFC4;1108 116D 11BB; # (뿄; 뿄; 뿄; 뿄; 뿄; ) HANGUL SYLLABLE BBYOSS +BFC5;BFC5;1108 116D 11BC;BFC5;1108 116D 11BC; # (뿅; 뿅; 뿅; 뿅; 뿅; ) HANGUL SYLLABLE BBYONG +BFC6;BFC6;1108 116D 11BD;BFC6;1108 116D 11BD; # (뿆; 뿆; 뿆; 뿆; 뿆; ) HANGUL SYLLABLE BBYOJ +BFC7;BFC7;1108 116D 11BE;BFC7;1108 116D 11BE; # (뿇; 뿇; 뿇; 뿇; 뿇; ) HANGUL SYLLABLE BBYOC +BFC8;BFC8;1108 116D 11BF;BFC8;1108 116D 11BF; # (뿈; 뿈; 뿈; 뿈; 뿈; ) HANGUL SYLLABLE BBYOK +BFC9;BFC9;1108 116D 11C0;BFC9;1108 116D 11C0; # (뿉; 뿉; 뿉; 뿉; 뿉; ) HANGUL SYLLABLE BBYOT +BFCA;BFCA;1108 116D 11C1;BFCA;1108 116D 11C1; # (뿊; 뿊; 뿊; 뿊; 뿊; ) HANGUL SYLLABLE BBYOP +BFCB;BFCB;1108 116D 11C2;BFCB;1108 116D 11C2; # (뿋; 뿋; 뿋; 뿋; 뿋; ) HANGUL SYLLABLE BBYOH +BFCC;BFCC;1108 116E;BFCC;1108 116E; # (뿌; 뿌; 뿌; 뿌; 뿌; ) HANGUL SYLLABLE BBU +BFCD;BFCD;1108 116E 11A8;BFCD;1108 116E 11A8; # (뿍; 뿍; 뿍; 뿍; 뿍; ) HANGUL SYLLABLE BBUG +BFCE;BFCE;1108 116E 11A9;BFCE;1108 116E 11A9; # (뿎; 뿎; 뿎; 뿎; 뿎; ) HANGUL SYLLABLE BBUGG +BFCF;BFCF;1108 116E 11AA;BFCF;1108 116E 11AA; # (뿏; 뿏; 뿏; 뿏; 뿏; ) HANGUL SYLLABLE BBUGS +BFD0;BFD0;1108 116E 11AB;BFD0;1108 116E 11AB; # (뿐; 뿐; 뿐; 뿐; 뿐; ) HANGUL SYLLABLE BBUN +BFD1;BFD1;1108 116E 11AC;BFD1;1108 116E 11AC; # (뿑; 뿑; 뿑; 뿑; 뿑; ) HANGUL SYLLABLE BBUNJ +BFD2;BFD2;1108 116E 11AD;BFD2;1108 116E 11AD; # (뿒; 뿒; 뿒; 뿒; 뿒; ) HANGUL SYLLABLE BBUNH +BFD3;BFD3;1108 116E 11AE;BFD3;1108 116E 11AE; # (뿓; 뿓; 뿓; 뿓; 뿓; ) HANGUL SYLLABLE BBUD +BFD4;BFD4;1108 116E 11AF;BFD4;1108 116E 11AF; # (뿔; 뿔; 뿔; 뿔; 뿔; ) HANGUL SYLLABLE BBUL +BFD5;BFD5;1108 116E 11B0;BFD5;1108 116E 11B0; # (뿕; 뿕; 뿕; 뿕; 뿕; ) HANGUL SYLLABLE BBULG +BFD6;BFD6;1108 116E 11B1;BFD6;1108 116E 11B1; # (뿖; 뿖; 뿖; 뿖; 뿖; ) HANGUL SYLLABLE BBULM +BFD7;BFD7;1108 116E 11B2;BFD7;1108 116E 11B2; # (뿗; 뿗; 뿗; 뿗; 뿗; ) HANGUL SYLLABLE BBULB +BFD8;BFD8;1108 116E 11B3;BFD8;1108 116E 11B3; # (뿘; 뿘; 뿘; 뿘; 뿘; ) HANGUL SYLLABLE BBULS +BFD9;BFD9;1108 116E 11B4;BFD9;1108 116E 11B4; # (뿙; 뿙; 뿙; 뿙; 뿙; ) HANGUL SYLLABLE BBULT +BFDA;BFDA;1108 116E 11B5;BFDA;1108 116E 11B5; # (뿚; 뿚; 뿚; 뿚; 뿚; ) HANGUL SYLLABLE BBULP +BFDB;BFDB;1108 116E 11B6;BFDB;1108 116E 11B6; # (뿛; 뿛; 뿛; 뿛; 뿛; ) HANGUL SYLLABLE BBULH +BFDC;BFDC;1108 116E 11B7;BFDC;1108 116E 11B7; # (뿜; 뿜; 뿜; 뿜; 뿜; ) HANGUL SYLLABLE BBUM +BFDD;BFDD;1108 116E 11B8;BFDD;1108 116E 11B8; # (뿝; 뿝; 뿝; 뿝; 뿝; ) HANGUL SYLLABLE BBUB +BFDE;BFDE;1108 116E 11B9;BFDE;1108 116E 11B9; # (뿞; 뿞; 뿞; 뿞; 뿞; ) HANGUL SYLLABLE BBUBS +BFDF;BFDF;1108 116E 11BA;BFDF;1108 116E 11BA; # (뿟; 뿟; 뿟; 뿟; 뿟; ) HANGUL SYLLABLE BBUS +BFE0;BFE0;1108 116E 11BB;BFE0;1108 116E 11BB; # (뿠; 뿠; 뿠; 뿠; 뿠; ) HANGUL SYLLABLE BBUSS +BFE1;BFE1;1108 116E 11BC;BFE1;1108 116E 11BC; # (뿡; 뿡; 뿡; 뿡; 뿡; ) HANGUL SYLLABLE BBUNG +BFE2;BFE2;1108 116E 11BD;BFE2;1108 116E 11BD; # (뿢; 뿢; 뿢; 뿢; 뿢; ) HANGUL SYLLABLE BBUJ +BFE3;BFE3;1108 116E 11BE;BFE3;1108 116E 11BE; # (뿣; 뿣; 뿣; 뿣; 뿣; ) HANGUL SYLLABLE BBUC +BFE4;BFE4;1108 116E 11BF;BFE4;1108 116E 11BF; # (뿤; 뿤; 뿤; 뿤; 뿤; ) HANGUL SYLLABLE BBUK +BFE5;BFE5;1108 116E 11C0;BFE5;1108 116E 11C0; # (뿥; 뿥; 뿥; 뿥; 뿥; ) HANGUL SYLLABLE BBUT +BFE6;BFE6;1108 116E 11C1;BFE6;1108 116E 11C1; # (뿦; 뿦; 뿦; 뿦; 뿦; ) HANGUL SYLLABLE BBUP +BFE7;BFE7;1108 116E 11C2;BFE7;1108 116E 11C2; # (뿧; 뿧; 뿧; 뿧; 뿧; ) HANGUL SYLLABLE BBUH +BFE8;BFE8;1108 116F;BFE8;1108 116F; # (뿨; 뿨; 뿨; 뿨; 뿨; ) HANGUL SYLLABLE BBWEO +BFE9;BFE9;1108 116F 11A8;BFE9;1108 116F 11A8; # (뿩; 뿩; 뿩; 뿩; 뿩; ) HANGUL SYLLABLE BBWEOG +BFEA;BFEA;1108 116F 11A9;BFEA;1108 116F 11A9; # (뿪; 뿪; 뿪; 뿪; 뿪; ) HANGUL SYLLABLE BBWEOGG +BFEB;BFEB;1108 116F 11AA;BFEB;1108 116F 11AA; # (뿫; 뿫; 뿫; 뿫; 뿫; ) HANGUL SYLLABLE BBWEOGS +BFEC;BFEC;1108 116F 11AB;BFEC;1108 116F 11AB; # (뿬; 뿬; 뿬; 뿬; 뿬; ) HANGUL SYLLABLE BBWEON +BFED;BFED;1108 116F 11AC;BFED;1108 116F 11AC; # (뿭; 뿭; 뿭; 뿭; 뿭; ) HANGUL SYLLABLE BBWEONJ +BFEE;BFEE;1108 116F 11AD;BFEE;1108 116F 11AD; # (뿮; 뿮; 뿮; 뿮; 뿮; ) HANGUL SYLLABLE BBWEONH +BFEF;BFEF;1108 116F 11AE;BFEF;1108 116F 11AE; # (뿯; 뿯; 뿯; 뿯; 뿯; ) HANGUL SYLLABLE BBWEOD +BFF0;BFF0;1108 116F 11AF;BFF0;1108 116F 11AF; # (뿰; 뿰; 뿰; 뿰; 뿰; ) HANGUL SYLLABLE BBWEOL +BFF1;BFF1;1108 116F 11B0;BFF1;1108 116F 11B0; # (뿱; 뿱; 뿱; 뿱; 뿱; ) HANGUL SYLLABLE BBWEOLG +BFF2;BFF2;1108 116F 11B1;BFF2;1108 116F 11B1; # (뿲; 뿲; 뿲; 뿲; 뿲; ) HANGUL SYLLABLE BBWEOLM +BFF3;BFF3;1108 116F 11B2;BFF3;1108 116F 11B2; # (뿳; 뿳; 뿳; 뿳; 뿳; ) HANGUL SYLLABLE BBWEOLB +BFF4;BFF4;1108 116F 11B3;BFF4;1108 116F 11B3; # (뿴; 뿴; 뿴; 뿴; 뿴; ) HANGUL SYLLABLE BBWEOLS +BFF5;BFF5;1108 116F 11B4;BFF5;1108 116F 11B4; # (뿵; 뿵; 뿵; 뿵; 뿵; ) HANGUL SYLLABLE BBWEOLT +BFF6;BFF6;1108 116F 11B5;BFF6;1108 116F 11B5; # (뿶; 뿶; 뿶; 뿶; 뿶; ) HANGUL SYLLABLE BBWEOLP +BFF7;BFF7;1108 116F 11B6;BFF7;1108 116F 11B6; # (뿷; 뿷; 뿷; 뿷; 뿷; ) HANGUL SYLLABLE BBWEOLH +BFF8;BFF8;1108 116F 11B7;BFF8;1108 116F 11B7; # (뿸; 뿸; 뿸; 뿸; 뿸; ) HANGUL SYLLABLE BBWEOM +BFF9;BFF9;1108 116F 11B8;BFF9;1108 116F 11B8; # (뿹; 뿹; 뿹; 뿹; 뿹; ) HANGUL SYLLABLE BBWEOB +BFFA;BFFA;1108 116F 11B9;BFFA;1108 116F 11B9; # (뿺; 뿺; 뿺; 뿺; 뿺; ) HANGUL SYLLABLE BBWEOBS +BFFB;BFFB;1108 116F 11BA;BFFB;1108 116F 11BA; # (뿻; 뿻; 뿻; 뿻; 뿻; ) HANGUL SYLLABLE BBWEOS +BFFC;BFFC;1108 116F 11BB;BFFC;1108 116F 11BB; # (뿼; 뿼; 뿼; 뿼; 뿼; ) HANGUL SYLLABLE BBWEOSS +BFFD;BFFD;1108 116F 11BC;BFFD;1108 116F 11BC; # (뿽; 뿽; 뿽; 뿽; 뿽; ) HANGUL SYLLABLE BBWEONG +BFFE;BFFE;1108 116F 11BD;BFFE;1108 116F 11BD; # (뿾; 뿾; 뿾; 뿾; 뿾; ) HANGUL SYLLABLE BBWEOJ +BFFF;BFFF;1108 116F 11BE;BFFF;1108 116F 11BE; # (뿿; 뿿; 뿿; 뿿; 뿿; ) HANGUL SYLLABLE BBWEOC +C000;C000;1108 116F 11BF;C000;1108 116F 11BF; # (쀀; 쀀; 쀀; 쀀; 쀀; ) HANGUL SYLLABLE BBWEOK +C001;C001;1108 116F 11C0;C001;1108 116F 11C0; # (쀁; 쀁; 쀁; 쀁; 쀁; ) HANGUL SYLLABLE BBWEOT +C002;C002;1108 116F 11C1;C002;1108 116F 11C1; # (쀂; 쀂; 쀂; 쀂; 쀂; ) HANGUL SYLLABLE BBWEOP +C003;C003;1108 116F 11C2;C003;1108 116F 11C2; # (쀃; 쀃; 쀃; 쀃; 쀃; ) HANGUL SYLLABLE BBWEOH +C004;C004;1108 1170;C004;1108 1170; # (쀄; 쀄; 쀄; 쀄; 쀄; ) HANGUL SYLLABLE BBWE +C005;C005;1108 1170 11A8;C005;1108 1170 11A8; # (쀅; 쀅; 쀅; 쀅; 쀅; ) HANGUL SYLLABLE BBWEG +C006;C006;1108 1170 11A9;C006;1108 1170 11A9; # (쀆; 쀆; 쀆; 쀆; 쀆; ) HANGUL SYLLABLE BBWEGG +C007;C007;1108 1170 11AA;C007;1108 1170 11AA; # (쀇; 쀇; 쀇; 쀇; 쀇; ) HANGUL SYLLABLE BBWEGS +C008;C008;1108 1170 11AB;C008;1108 1170 11AB; # (쀈; 쀈; 쀈; 쀈; 쀈; ) HANGUL SYLLABLE BBWEN +C009;C009;1108 1170 11AC;C009;1108 1170 11AC; # (쀉; 쀉; 쀉; 쀉; 쀉; ) HANGUL SYLLABLE BBWENJ +C00A;C00A;1108 1170 11AD;C00A;1108 1170 11AD; # (쀊; 쀊; 쀊; 쀊; 쀊; ) HANGUL SYLLABLE BBWENH +C00B;C00B;1108 1170 11AE;C00B;1108 1170 11AE; # (쀋; 쀋; 쀋; 쀋; 쀋; ) HANGUL SYLLABLE BBWED +C00C;C00C;1108 1170 11AF;C00C;1108 1170 11AF; # (쀌; 쀌; 쀌; 쀌; 쀌; ) HANGUL SYLLABLE BBWEL +C00D;C00D;1108 1170 11B0;C00D;1108 1170 11B0; # (쀍; 쀍; 쀍; 쀍; 쀍; ) HANGUL SYLLABLE BBWELG +C00E;C00E;1108 1170 11B1;C00E;1108 1170 11B1; # (쀎; 쀎; 쀎; 쀎; 쀎; ) HANGUL SYLLABLE BBWELM +C00F;C00F;1108 1170 11B2;C00F;1108 1170 11B2; # (쀏; 쀏; 쀏; 쀏; 쀏; ) HANGUL SYLLABLE BBWELB +C010;C010;1108 1170 11B3;C010;1108 1170 11B3; # (쀐; 쀐; 쀐; 쀐; 쀐; ) HANGUL SYLLABLE BBWELS +C011;C011;1108 1170 11B4;C011;1108 1170 11B4; # (쀑; 쀑; 쀑; 쀑; 쀑; ) HANGUL SYLLABLE BBWELT +C012;C012;1108 1170 11B5;C012;1108 1170 11B5; # (쀒; 쀒; 쀒; 쀒; 쀒; ) HANGUL SYLLABLE BBWELP +C013;C013;1108 1170 11B6;C013;1108 1170 11B6; # (쀓; 쀓; 쀓; 쀓; 쀓; ) HANGUL SYLLABLE BBWELH +C014;C014;1108 1170 11B7;C014;1108 1170 11B7; # (쀔; 쀔; 쀔; 쀔; 쀔; ) HANGUL SYLLABLE BBWEM +C015;C015;1108 1170 11B8;C015;1108 1170 11B8; # (쀕; 쀕; 쀕; 쀕; 쀕; ) HANGUL SYLLABLE BBWEB +C016;C016;1108 1170 11B9;C016;1108 1170 11B9; # (쀖; 쀖; 쀖; 쀖; 쀖; ) HANGUL SYLLABLE BBWEBS +C017;C017;1108 1170 11BA;C017;1108 1170 11BA; # (쀗; 쀗; 쀗; 쀗; 쀗; ) HANGUL SYLLABLE BBWES +C018;C018;1108 1170 11BB;C018;1108 1170 11BB; # (쀘; 쀘; 쀘; 쀘; 쀘; ) HANGUL SYLLABLE BBWESS +C019;C019;1108 1170 11BC;C019;1108 1170 11BC; # (쀙; 쀙; 쀙; 쀙; 쀙; ) HANGUL SYLLABLE BBWENG +C01A;C01A;1108 1170 11BD;C01A;1108 1170 11BD; # (쀚; 쀚; 쀚; 쀚; 쀚; ) HANGUL SYLLABLE BBWEJ +C01B;C01B;1108 1170 11BE;C01B;1108 1170 11BE; # (쀛; 쀛; 쀛; 쀛; 쀛; ) HANGUL SYLLABLE BBWEC +C01C;C01C;1108 1170 11BF;C01C;1108 1170 11BF; # (쀜; 쀜; 쀜; 쀜; 쀜; ) HANGUL SYLLABLE BBWEK +C01D;C01D;1108 1170 11C0;C01D;1108 1170 11C0; # (쀝; 쀝; 쀝; 쀝; 쀝; ) HANGUL SYLLABLE BBWET +C01E;C01E;1108 1170 11C1;C01E;1108 1170 11C1; # (쀞; 쀞; 쀞; 쀞; 쀞; ) HANGUL SYLLABLE BBWEP +C01F;C01F;1108 1170 11C2;C01F;1108 1170 11C2; # (쀟; 쀟; 쀟; 쀟; 쀟; ) HANGUL SYLLABLE BBWEH +C020;C020;1108 1171;C020;1108 1171; # (쀠; 쀠; 쀠; 쀠; 쀠; ) HANGUL SYLLABLE BBWI +C021;C021;1108 1171 11A8;C021;1108 1171 11A8; # (쀡; 쀡; 쀡; 쀡; 쀡; ) HANGUL SYLLABLE BBWIG +C022;C022;1108 1171 11A9;C022;1108 1171 11A9; # (쀢; 쀢; 쀢; 쀢; 쀢; ) HANGUL SYLLABLE BBWIGG +C023;C023;1108 1171 11AA;C023;1108 1171 11AA; # (쀣; 쀣; 쀣; 쀣; 쀣; ) HANGUL SYLLABLE BBWIGS +C024;C024;1108 1171 11AB;C024;1108 1171 11AB; # (쀤; 쀤; 쀤; 쀤; 쀤; ) HANGUL SYLLABLE BBWIN +C025;C025;1108 1171 11AC;C025;1108 1171 11AC; # (쀥; 쀥; 쀥; 쀥; 쀥; ) HANGUL SYLLABLE BBWINJ +C026;C026;1108 1171 11AD;C026;1108 1171 11AD; # (쀦; 쀦; 쀦; 쀦; 쀦; ) HANGUL SYLLABLE BBWINH +C027;C027;1108 1171 11AE;C027;1108 1171 11AE; # (쀧; 쀧; 쀧; 쀧; 쀧; ) HANGUL SYLLABLE BBWID +C028;C028;1108 1171 11AF;C028;1108 1171 11AF; # (쀨; 쀨; 쀨; 쀨; 쀨; ) HANGUL SYLLABLE BBWIL +C029;C029;1108 1171 11B0;C029;1108 1171 11B0; # (쀩; 쀩; 쀩; 쀩; 쀩; ) HANGUL SYLLABLE BBWILG +C02A;C02A;1108 1171 11B1;C02A;1108 1171 11B1; # (쀪; 쀪; 쀪; 쀪; 쀪; ) HANGUL SYLLABLE BBWILM +C02B;C02B;1108 1171 11B2;C02B;1108 1171 11B2; # (쀫; 쀫; 쀫; 쀫; 쀫; ) HANGUL SYLLABLE BBWILB +C02C;C02C;1108 1171 11B3;C02C;1108 1171 11B3; # (쀬; 쀬; 쀬; 쀬; 쀬; ) HANGUL SYLLABLE BBWILS +C02D;C02D;1108 1171 11B4;C02D;1108 1171 11B4; # (쀭; 쀭; 쀭; 쀭; 쀭; ) HANGUL SYLLABLE BBWILT +C02E;C02E;1108 1171 11B5;C02E;1108 1171 11B5; # (쀮; 쀮; 쀮; 쀮; 쀮; ) HANGUL SYLLABLE BBWILP +C02F;C02F;1108 1171 11B6;C02F;1108 1171 11B6; # (쀯; 쀯; 쀯; 쀯; 쀯; ) HANGUL SYLLABLE BBWILH +C030;C030;1108 1171 11B7;C030;1108 1171 11B7; # (쀰; 쀰; 쀰; 쀰; 쀰; ) HANGUL SYLLABLE BBWIM +C031;C031;1108 1171 11B8;C031;1108 1171 11B8; # (쀱; 쀱; 쀱; 쀱; 쀱; ) HANGUL SYLLABLE BBWIB +C032;C032;1108 1171 11B9;C032;1108 1171 11B9; # (쀲; 쀲; 쀲; 쀲; 쀲; ) HANGUL SYLLABLE BBWIBS +C033;C033;1108 1171 11BA;C033;1108 1171 11BA; # (쀳; 쀳; 쀳; 쀳; 쀳; ) HANGUL SYLLABLE BBWIS +C034;C034;1108 1171 11BB;C034;1108 1171 11BB; # (쀴; 쀴; 쀴; 쀴; 쀴; ) HANGUL SYLLABLE BBWISS +C035;C035;1108 1171 11BC;C035;1108 1171 11BC; # (쀵; 쀵; 쀵; 쀵; 쀵; ) HANGUL SYLLABLE BBWING +C036;C036;1108 1171 11BD;C036;1108 1171 11BD; # (쀶; 쀶; 쀶; 쀶; 쀶; ) HANGUL SYLLABLE BBWIJ +C037;C037;1108 1171 11BE;C037;1108 1171 11BE; # (쀷; 쀷; 쀷; 쀷; 쀷; ) HANGUL SYLLABLE BBWIC +C038;C038;1108 1171 11BF;C038;1108 1171 11BF; # (쀸; 쀸; 쀸; 쀸; 쀸; ) HANGUL SYLLABLE BBWIK +C039;C039;1108 1171 11C0;C039;1108 1171 11C0; # (쀹; 쀹; 쀹; 쀹; 쀹; ) HANGUL SYLLABLE BBWIT +C03A;C03A;1108 1171 11C1;C03A;1108 1171 11C1; # (쀺; 쀺; 쀺; 쀺; 쀺; ) HANGUL SYLLABLE BBWIP +C03B;C03B;1108 1171 11C2;C03B;1108 1171 11C2; # (쀻; 쀻; 쀻; 쀻; 쀻; ) HANGUL SYLLABLE BBWIH +C03C;C03C;1108 1172;C03C;1108 1172; # (쀼; 쀼; 쀼; 쀼; 쀼; ) HANGUL SYLLABLE BBYU +C03D;C03D;1108 1172 11A8;C03D;1108 1172 11A8; # (쀽; 쀽; 쀽; 쀽; 쀽; ) HANGUL SYLLABLE BBYUG +C03E;C03E;1108 1172 11A9;C03E;1108 1172 11A9; # (쀾; 쀾; 쀾; 쀾; 쀾; ) HANGUL SYLLABLE BBYUGG +C03F;C03F;1108 1172 11AA;C03F;1108 1172 11AA; # (쀿; 쀿; 쀿; 쀿; 쀿; ) HANGUL SYLLABLE BBYUGS +C040;C040;1108 1172 11AB;C040;1108 1172 11AB; # (쁀; 쁀; 쁀; 쁀; 쁀; ) HANGUL SYLLABLE BBYUN +C041;C041;1108 1172 11AC;C041;1108 1172 11AC; # (쁁; 쁁; 쁁; 쁁; 쁁; ) HANGUL SYLLABLE BBYUNJ +C042;C042;1108 1172 11AD;C042;1108 1172 11AD; # (쁂; 쁂; 쁂; 쁂; 쁂; ) HANGUL SYLLABLE BBYUNH +C043;C043;1108 1172 11AE;C043;1108 1172 11AE; # (쁃; 쁃; 쁃; 쁃; 쁃; ) HANGUL SYLLABLE BBYUD +C044;C044;1108 1172 11AF;C044;1108 1172 11AF; # (쁄; 쁄; 쁄; 쁄; 쁄; ) HANGUL SYLLABLE BBYUL +C045;C045;1108 1172 11B0;C045;1108 1172 11B0; # (쁅; 쁅; 쁅; 쁅; 쁅; ) HANGUL SYLLABLE BBYULG +C046;C046;1108 1172 11B1;C046;1108 1172 11B1; # (쁆; 쁆; 쁆; 쁆; 쁆; ) HANGUL SYLLABLE BBYULM +C047;C047;1108 1172 11B2;C047;1108 1172 11B2; # (쁇; 쁇; 쁇; 쁇; 쁇; ) HANGUL SYLLABLE BBYULB +C048;C048;1108 1172 11B3;C048;1108 1172 11B3; # (쁈; 쁈; 쁈; 쁈; 쁈; ) HANGUL SYLLABLE BBYULS +C049;C049;1108 1172 11B4;C049;1108 1172 11B4; # (쁉; 쁉; 쁉; 쁉; 쁉; ) HANGUL SYLLABLE BBYULT +C04A;C04A;1108 1172 11B5;C04A;1108 1172 11B5; # (쁊; 쁊; 쁊; 쁊; 쁊; ) HANGUL SYLLABLE BBYULP +C04B;C04B;1108 1172 11B6;C04B;1108 1172 11B6; # (쁋; 쁋; 쁋; 쁋; 쁋; ) HANGUL SYLLABLE BBYULH +C04C;C04C;1108 1172 11B7;C04C;1108 1172 11B7; # (쁌; 쁌; 쁌; 쁌; 쁌; ) HANGUL SYLLABLE BBYUM +C04D;C04D;1108 1172 11B8;C04D;1108 1172 11B8; # (쁍; 쁍; 쁍; 쁍; 쁍; ) HANGUL SYLLABLE BBYUB +C04E;C04E;1108 1172 11B9;C04E;1108 1172 11B9; # (쁎; 쁎; 쁎; 쁎; 쁎; ) HANGUL SYLLABLE BBYUBS +C04F;C04F;1108 1172 11BA;C04F;1108 1172 11BA; # (쁏; 쁏; 쁏; 쁏; 쁏; ) HANGUL SYLLABLE BBYUS +C050;C050;1108 1172 11BB;C050;1108 1172 11BB; # (쁐; 쁐; 쁐; 쁐; 쁐; ) HANGUL SYLLABLE BBYUSS +C051;C051;1108 1172 11BC;C051;1108 1172 11BC; # (쁑; 쁑; 쁑; 쁑; 쁑; ) HANGUL SYLLABLE BBYUNG +C052;C052;1108 1172 11BD;C052;1108 1172 11BD; # (쁒; 쁒; 쁒; 쁒; 쁒; ) HANGUL SYLLABLE BBYUJ +C053;C053;1108 1172 11BE;C053;1108 1172 11BE; # (쁓; 쁓; 쁓; 쁓; 쁓; ) HANGUL SYLLABLE BBYUC +C054;C054;1108 1172 11BF;C054;1108 1172 11BF; # (쁔; 쁔; 쁔; 쁔; 쁔; ) HANGUL SYLLABLE BBYUK +C055;C055;1108 1172 11C0;C055;1108 1172 11C0; # (쁕; 쁕; 쁕; 쁕; 쁕; ) HANGUL SYLLABLE BBYUT +C056;C056;1108 1172 11C1;C056;1108 1172 11C1; # (쁖; 쁖; 쁖; 쁖; 쁖; ) HANGUL SYLLABLE BBYUP +C057;C057;1108 1172 11C2;C057;1108 1172 11C2; # (쁗; 쁗; 쁗; 쁗; 쁗; ) HANGUL SYLLABLE BBYUH +C058;C058;1108 1173;C058;1108 1173; # (쁘; 쁘; 쁘; 쁘; 쁘; ) HANGUL SYLLABLE BBEU +C059;C059;1108 1173 11A8;C059;1108 1173 11A8; # (쁙; 쁙; 쁙; 쁙; 쁙; ) HANGUL SYLLABLE BBEUG +C05A;C05A;1108 1173 11A9;C05A;1108 1173 11A9; # (쁚; 쁚; 쁚; 쁚; 쁚; ) HANGUL SYLLABLE BBEUGG +C05B;C05B;1108 1173 11AA;C05B;1108 1173 11AA; # (쁛; 쁛; 쁛; 쁛; 쁛; ) HANGUL SYLLABLE BBEUGS +C05C;C05C;1108 1173 11AB;C05C;1108 1173 11AB; # (쁜; 쁜; 쁜; 쁜; 쁜; ) HANGUL SYLLABLE BBEUN +C05D;C05D;1108 1173 11AC;C05D;1108 1173 11AC; # (쁝; 쁝; 쁝; 쁝; 쁝; ) HANGUL SYLLABLE BBEUNJ +C05E;C05E;1108 1173 11AD;C05E;1108 1173 11AD; # (쁞; 쁞; 쁞; 쁞; 쁞; ) HANGUL SYLLABLE BBEUNH +C05F;C05F;1108 1173 11AE;C05F;1108 1173 11AE; # (쁟; 쁟; 쁟; 쁟; 쁟; ) HANGUL SYLLABLE BBEUD +C060;C060;1108 1173 11AF;C060;1108 1173 11AF; # (쁠; 쁠; 쁠; 쁠; 쁠; ) HANGUL SYLLABLE BBEUL +C061;C061;1108 1173 11B0;C061;1108 1173 11B0; # (쁡; 쁡; 쁡; 쁡; 쁡; ) HANGUL SYLLABLE BBEULG +C062;C062;1108 1173 11B1;C062;1108 1173 11B1; # (쁢; 쁢; 쁢; 쁢; 쁢; ) HANGUL SYLLABLE BBEULM +C063;C063;1108 1173 11B2;C063;1108 1173 11B2; # (쁣; 쁣; 쁣; 쁣; 쁣; ) HANGUL SYLLABLE BBEULB +C064;C064;1108 1173 11B3;C064;1108 1173 11B3; # (쁤; 쁤; 쁤; 쁤; 쁤; ) HANGUL SYLLABLE BBEULS +C065;C065;1108 1173 11B4;C065;1108 1173 11B4; # (쁥; 쁥; 쁥; 쁥; 쁥; ) HANGUL SYLLABLE BBEULT +C066;C066;1108 1173 11B5;C066;1108 1173 11B5; # (쁦; 쁦; 쁦; 쁦; 쁦; ) HANGUL SYLLABLE BBEULP +C067;C067;1108 1173 11B6;C067;1108 1173 11B6; # (쁧; 쁧; 쁧; 쁧; 쁧; ) HANGUL SYLLABLE BBEULH +C068;C068;1108 1173 11B7;C068;1108 1173 11B7; # (쁨; 쁨; 쁨; 쁨; 쁨; ) HANGUL SYLLABLE BBEUM +C069;C069;1108 1173 11B8;C069;1108 1173 11B8; # (쁩; 쁩; 쁩; 쁩; 쁩; ) HANGUL SYLLABLE BBEUB +C06A;C06A;1108 1173 11B9;C06A;1108 1173 11B9; # (쁪; 쁪; 쁪; 쁪; 쁪; ) HANGUL SYLLABLE BBEUBS +C06B;C06B;1108 1173 11BA;C06B;1108 1173 11BA; # (쁫; 쁫; 쁫; 쁫; 쁫; ) HANGUL SYLLABLE BBEUS +C06C;C06C;1108 1173 11BB;C06C;1108 1173 11BB; # (쁬; 쁬; 쁬; 쁬; 쁬; ) HANGUL SYLLABLE BBEUSS +C06D;C06D;1108 1173 11BC;C06D;1108 1173 11BC; # (쁭; 쁭; 쁭; 쁭; 쁭; ) HANGUL SYLLABLE BBEUNG +C06E;C06E;1108 1173 11BD;C06E;1108 1173 11BD; # (쁮; 쁮; 쁮; 쁮; 쁮; ) HANGUL SYLLABLE BBEUJ +C06F;C06F;1108 1173 11BE;C06F;1108 1173 11BE; # (쁯; 쁯; 쁯; 쁯; 쁯; ) HANGUL SYLLABLE BBEUC +C070;C070;1108 1173 11BF;C070;1108 1173 11BF; # (쁰; 쁰; 쁰; 쁰; 쁰; ) HANGUL SYLLABLE BBEUK +C071;C071;1108 1173 11C0;C071;1108 1173 11C0; # (쁱; 쁱; 쁱; 쁱; 쁱; ) HANGUL SYLLABLE BBEUT +C072;C072;1108 1173 11C1;C072;1108 1173 11C1; # (쁲; 쁲; 쁲; 쁲; 쁲; ) HANGUL SYLLABLE BBEUP +C073;C073;1108 1173 11C2;C073;1108 1173 11C2; # (쁳; 쁳; 쁳; 쁳; 쁳; ) HANGUL SYLLABLE BBEUH +C074;C074;1108 1174;C074;1108 1174; # (쁴; 쁴; 쁴; 쁴; 쁴; ) HANGUL SYLLABLE BBYI +C075;C075;1108 1174 11A8;C075;1108 1174 11A8; # (쁵; 쁵; 쁵; 쁵; 쁵; ) HANGUL SYLLABLE BBYIG +C076;C076;1108 1174 11A9;C076;1108 1174 11A9; # (쁶; 쁶; 쁶; 쁶; 쁶; ) HANGUL SYLLABLE BBYIGG +C077;C077;1108 1174 11AA;C077;1108 1174 11AA; # (쁷; 쁷; 쁷; 쁷; 쁷; ) HANGUL SYLLABLE BBYIGS +C078;C078;1108 1174 11AB;C078;1108 1174 11AB; # (쁸; 쁸; 쁸; 쁸; 쁸; ) HANGUL SYLLABLE BBYIN +C079;C079;1108 1174 11AC;C079;1108 1174 11AC; # (쁹; 쁹; 쁹; 쁹; 쁹; ) HANGUL SYLLABLE BBYINJ +C07A;C07A;1108 1174 11AD;C07A;1108 1174 11AD; # (쁺; 쁺; 쁺; 쁺; 쁺; ) HANGUL SYLLABLE BBYINH +C07B;C07B;1108 1174 11AE;C07B;1108 1174 11AE; # (쁻; 쁻; 쁻; 쁻; 쁻; ) HANGUL SYLLABLE BBYID +C07C;C07C;1108 1174 11AF;C07C;1108 1174 11AF; # (쁼; 쁼; 쁼; 쁼; 쁼; ) HANGUL SYLLABLE BBYIL +C07D;C07D;1108 1174 11B0;C07D;1108 1174 11B0; # (쁽; 쁽; 쁽; 쁽; 쁽; ) HANGUL SYLLABLE BBYILG +C07E;C07E;1108 1174 11B1;C07E;1108 1174 11B1; # (쁾; 쁾; 쁾; 쁾; 쁾; ) HANGUL SYLLABLE BBYILM +C07F;C07F;1108 1174 11B2;C07F;1108 1174 11B2; # (쁿; 쁿; 쁿; 쁿; 쁿; ) HANGUL SYLLABLE BBYILB +C080;C080;1108 1174 11B3;C080;1108 1174 11B3; # (삀; 삀; 삀; 삀; 삀; ) HANGUL SYLLABLE BBYILS +C081;C081;1108 1174 11B4;C081;1108 1174 11B4; # (삁; 삁; 삁; 삁; 삁; ) HANGUL SYLLABLE BBYILT +C082;C082;1108 1174 11B5;C082;1108 1174 11B5; # (삂; 삂; 삂; 삂; 삂; ) HANGUL SYLLABLE BBYILP +C083;C083;1108 1174 11B6;C083;1108 1174 11B6; # (삃; 삃; 삃; 삃; 삃; ) HANGUL SYLLABLE BBYILH +C084;C084;1108 1174 11B7;C084;1108 1174 11B7; # (삄; 삄; 삄; 삄; 삄; ) HANGUL SYLLABLE BBYIM +C085;C085;1108 1174 11B8;C085;1108 1174 11B8; # (삅; 삅; 삅; 삅; 삅; ) HANGUL SYLLABLE BBYIB +C086;C086;1108 1174 11B9;C086;1108 1174 11B9; # (삆; 삆; 삆; 삆; 삆; ) HANGUL SYLLABLE BBYIBS +C087;C087;1108 1174 11BA;C087;1108 1174 11BA; # (삇; 삇; 삇; 삇; 삇; ) HANGUL SYLLABLE BBYIS +C088;C088;1108 1174 11BB;C088;1108 1174 11BB; # (삈; 삈; 삈; 삈; 삈; ) HANGUL SYLLABLE BBYISS +C089;C089;1108 1174 11BC;C089;1108 1174 11BC; # (삉; 삉; 삉; 삉; 삉; ) HANGUL SYLLABLE BBYING +C08A;C08A;1108 1174 11BD;C08A;1108 1174 11BD; # (삊; 삊; 삊; 삊; 삊; ) HANGUL SYLLABLE BBYIJ +C08B;C08B;1108 1174 11BE;C08B;1108 1174 11BE; # (삋; 삋; 삋; 삋; 삋; ) HANGUL SYLLABLE BBYIC +C08C;C08C;1108 1174 11BF;C08C;1108 1174 11BF; # (삌; 삌; 삌; 삌; 삌; ) HANGUL SYLLABLE BBYIK +C08D;C08D;1108 1174 11C0;C08D;1108 1174 11C0; # (삍; 삍; 삍; 삍; 삍; ) HANGUL SYLLABLE BBYIT +C08E;C08E;1108 1174 11C1;C08E;1108 1174 11C1; # (삎; 삎; 삎; 삎; 삎; ) HANGUL SYLLABLE BBYIP +C08F;C08F;1108 1174 11C2;C08F;1108 1174 11C2; # (삏; 삏; 삏; 삏; 삏; ) HANGUL SYLLABLE BBYIH +C090;C090;1108 1175;C090;1108 1175; # (삐; 삐; 삐; 삐; 삐; ) HANGUL SYLLABLE BBI +C091;C091;1108 1175 11A8;C091;1108 1175 11A8; # (삑; 삑; 삑; 삑; 삑; ) HANGUL SYLLABLE BBIG +C092;C092;1108 1175 11A9;C092;1108 1175 11A9; # (삒; 삒; 삒; 삒; 삒; ) HANGUL SYLLABLE BBIGG +C093;C093;1108 1175 11AA;C093;1108 1175 11AA; # (삓; 삓; 삓; 삓; 삓; ) HANGUL SYLLABLE BBIGS +C094;C094;1108 1175 11AB;C094;1108 1175 11AB; # (삔; 삔; 삔; 삔; 삔; ) HANGUL SYLLABLE BBIN +C095;C095;1108 1175 11AC;C095;1108 1175 11AC; # (삕; 삕; 삕; 삕; 삕; ) HANGUL SYLLABLE BBINJ +C096;C096;1108 1175 11AD;C096;1108 1175 11AD; # (삖; 삖; 삖; 삖; 삖; ) HANGUL SYLLABLE BBINH +C097;C097;1108 1175 11AE;C097;1108 1175 11AE; # (삗; 삗; 삗; 삗; 삗; ) HANGUL SYLLABLE BBID +C098;C098;1108 1175 11AF;C098;1108 1175 11AF; # (삘; 삘; 삘; 삘; 삘; ) HANGUL SYLLABLE BBIL +C099;C099;1108 1175 11B0;C099;1108 1175 11B0; # (삙; 삙; 삙; 삙; 삙; ) HANGUL SYLLABLE BBILG +C09A;C09A;1108 1175 11B1;C09A;1108 1175 11B1; # (삚; 삚; 삚; 삚; 삚; ) HANGUL SYLLABLE BBILM +C09B;C09B;1108 1175 11B2;C09B;1108 1175 11B2; # (삛; 삛; 삛; 삛; 삛; ) HANGUL SYLLABLE BBILB +C09C;C09C;1108 1175 11B3;C09C;1108 1175 11B3; # (삜; 삜; 삜; 삜; 삜; ) HANGUL SYLLABLE BBILS +C09D;C09D;1108 1175 11B4;C09D;1108 1175 11B4; # (삝; 삝; 삝; 삝; 삝; ) HANGUL SYLLABLE BBILT +C09E;C09E;1108 1175 11B5;C09E;1108 1175 11B5; # (삞; 삞; 삞; 삞; 삞; ) HANGUL SYLLABLE BBILP +C09F;C09F;1108 1175 11B6;C09F;1108 1175 11B6; # (삟; 삟; 삟; 삟; 삟; ) HANGUL SYLLABLE BBILH +C0A0;C0A0;1108 1175 11B7;C0A0;1108 1175 11B7; # (삠; 삠; 삠; 삠; 삠; ) HANGUL SYLLABLE BBIM +C0A1;C0A1;1108 1175 11B8;C0A1;1108 1175 11B8; # (삡; 삡; 삡; 삡; 삡; ) HANGUL SYLLABLE BBIB +C0A2;C0A2;1108 1175 11B9;C0A2;1108 1175 11B9; # (삢; 삢; 삢; 삢; 삢; ) HANGUL SYLLABLE BBIBS +C0A3;C0A3;1108 1175 11BA;C0A3;1108 1175 11BA; # (삣; 삣; 삣; 삣; 삣; ) HANGUL SYLLABLE BBIS +C0A4;C0A4;1108 1175 11BB;C0A4;1108 1175 11BB; # (삤; 삤; 삤; 삤; 삤; ) HANGUL SYLLABLE BBISS +C0A5;C0A5;1108 1175 11BC;C0A5;1108 1175 11BC; # (삥; 삥; 삥; 삥; 삥; ) HANGUL SYLLABLE BBING +C0A6;C0A6;1108 1175 11BD;C0A6;1108 1175 11BD; # (삦; 삦; 삦; 삦; 삦; ) HANGUL SYLLABLE BBIJ +C0A7;C0A7;1108 1175 11BE;C0A7;1108 1175 11BE; # (삧; 삧; 삧; 삧; 삧; ) HANGUL SYLLABLE BBIC +C0A8;C0A8;1108 1175 11BF;C0A8;1108 1175 11BF; # (삨; 삨; 삨; 삨; 삨; ) HANGUL SYLLABLE BBIK +C0A9;C0A9;1108 1175 11C0;C0A9;1108 1175 11C0; # (삩; 삩; 삩; 삩; 삩; ) HANGUL SYLLABLE BBIT +C0AA;C0AA;1108 1175 11C1;C0AA;1108 1175 11C1; # (삪; 삪; 삪; 삪; 삪; ) HANGUL SYLLABLE BBIP +C0AB;C0AB;1108 1175 11C2;C0AB;1108 1175 11C2; # (삫; 삫; 삫; 삫; 삫; ) HANGUL SYLLABLE BBIH +C0AC;C0AC;1109 1161;C0AC;1109 1161; # (사; 사; 사; 사; 사; ) HANGUL SYLLABLE SA +C0AD;C0AD;1109 1161 11A8;C0AD;1109 1161 11A8; # (삭; 삭; 삭; 삭; 삭; ) HANGUL SYLLABLE SAG +C0AE;C0AE;1109 1161 11A9;C0AE;1109 1161 11A9; # (삮; 삮; 삮; 삮; 삮; ) HANGUL SYLLABLE SAGG +C0AF;C0AF;1109 1161 11AA;C0AF;1109 1161 11AA; # (삯; 삯; 삯; 삯; 삯; ) HANGUL SYLLABLE SAGS +C0B0;C0B0;1109 1161 11AB;C0B0;1109 1161 11AB; # (산; 산; 산; 산; 산; ) HANGUL SYLLABLE SAN +C0B1;C0B1;1109 1161 11AC;C0B1;1109 1161 11AC; # (삱; 삱; 삱; 삱; 삱; ) HANGUL SYLLABLE SANJ +C0B2;C0B2;1109 1161 11AD;C0B2;1109 1161 11AD; # (삲; 삲; 삲; 삲; 삲; ) HANGUL SYLLABLE SANH +C0B3;C0B3;1109 1161 11AE;C0B3;1109 1161 11AE; # (삳; 삳; 삳; 삳; 삳; ) HANGUL SYLLABLE SAD +C0B4;C0B4;1109 1161 11AF;C0B4;1109 1161 11AF; # (살; 살; 살; 살; 살; ) HANGUL SYLLABLE SAL +C0B5;C0B5;1109 1161 11B0;C0B5;1109 1161 11B0; # (삵; 삵; 삵; 삵; 삵; ) HANGUL SYLLABLE SALG +C0B6;C0B6;1109 1161 11B1;C0B6;1109 1161 11B1; # (삶; 삶; 삶; 삶; 삶; ) HANGUL SYLLABLE SALM +C0B7;C0B7;1109 1161 11B2;C0B7;1109 1161 11B2; # (삷; 삷; 삷; 삷; 삷; ) HANGUL SYLLABLE SALB +C0B8;C0B8;1109 1161 11B3;C0B8;1109 1161 11B3; # (삸; 삸; 삸; 삸; 삸; ) HANGUL SYLLABLE SALS +C0B9;C0B9;1109 1161 11B4;C0B9;1109 1161 11B4; # (삹; 삹; 삹; 삹; 삹; ) HANGUL SYLLABLE SALT +C0BA;C0BA;1109 1161 11B5;C0BA;1109 1161 11B5; # (삺; 삺; 삺; 삺; 삺; ) HANGUL SYLLABLE SALP +C0BB;C0BB;1109 1161 11B6;C0BB;1109 1161 11B6; # (삻; 삻; 삻; 삻; 삻; ) HANGUL SYLLABLE SALH +C0BC;C0BC;1109 1161 11B7;C0BC;1109 1161 11B7; # (삼; 삼; 삼; 삼; 삼; ) HANGUL SYLLABLE SAM +C0BD;C0BD;1109 1161 11B8;C0BD;1109 1161 11B8; # (삽; 삽; 삽; 삽; 삽; ) HANGUL SYLLABLE SAB +C0BE;C0BE;1109 1161 11B9;C0BE;1109 1161 11B9; # (삾; 삾; 삾; 삾; 삾; ) HANGUL SYLLABLE SABS +C0BF;C0BF;1109 1161 11BA;C0BF;1109 1161 11BA; # (삿; 삿; 삿; 삿; 삿; ) HANGUL SYLLABLE SAS +C0C0;C0C0;1109 1161 11BB;C0C0;1109 1161 11BB; # (샀; 샀; 샀; 샀; 샀; ) HANGUL SYLLABLE SASS +C0C1;C0C1;1109 1161 11BC;C0C1;1109 1161 11BC; # (상; 상; 상; 상; 상; ) HANGUL SYLLABLE SANG +C0C2;C0C2;1109 1161 11BD;C0C2;1109 1161 11BD; # (샂; 샂; 샂; 샂; 샂; ) HANGUL SYLLABLE SAJ +C0C3;C0C3;1109 1161 11BE;C0C3;1109 1161 11BE; # (샃; 샃; 샃; 샃; 샃; ) HANGUL SYLLABLE SAC +C0C4;C0C4;1109 1161 11BF;C0C4;1109 1161 11BF; # (샄; 샄; 샄; 샄; 샄; ) HANGUL SYLLABLE SAK +C0C5;C0C5;1109 1161 11C0;C0C5;1109 1161 11C0; # (샅; 샅; 샅; 샅; 샅; ) HANGUL SYLLABLE SAT +C0C6;C0C6;1109 1161 11C1;C0C6;1109 1161 11C1; # (샆; 샆; 샆; 샆; 샆; ) HANGUL SYLLABLE SAP +C0C7;C0C7;1109 1161 11C2;C0C7;1109 1161 11C2; # (샇; 샇; 샇; 샇; 샇; ) HANGUL SYLLABLE SAH +C0C8;C0C8;1109 1162;C0C8;1109 1162; # (새; 새; 새; 새; 새; ) HANGUL SYLLABLE SAE +C0C9;C0C9;1109 1162 11A8;C0C9;1109 1162 11A8; # (색; 색; 색; 색; 색; ) HANGUL SYLLABLE SAEG +C0CA;C0CA;1109 1162 11A9;C0CA;1109 1162 11A9; # (샊; 샊; 샊; 샊; 샊; ) HANGUL SYLLABLE SAEGG +C0CB;C0CB;1109 1162 11AA;C0CB;1109 1162 11AA; # (샋; 샋; 샋; 샋; 샋; ) HANGUL SYLLABLE SAEGS +C0CC;C0CC;1109 1162 11AB;C0CC;1109 1162 11AB; # (샌; 샌; 샌; 샌; 샌; ) HANGUL SYLLABLE SAEN +C0CD;C0CD;1109 1162 11AC;C0CD;1109 1162 11AC; # (샍; 샍; 샍; 샍; 샍; ) HANGUL SYLLABLE SAENJ +C0CE;C0CE;1109 1162 11AD;C0CE;1109 1162 11AD; # (샎; 샎; 샎; 샎; 샎; ) HANGUL SYLLABLE SAENH +C0CF;C0CF;1109 1162 11AE;C0CF;1109 1162 11AE; # (샏; 샏; 샏; 샏; 샏; ) HANGUL SYLLABLE SAED +C0D0;C0D0;1109 1162 11AF;C0D0;1109 1162 11AF; # (샐; 샐; 샐; 샐; 샐; ) HANGUL SYLLABLE SAEL +C0D1;C0D1;1109 1162 11B0;C0D1;1109 1162 11B0; # (샑; 샑; 샑; 샑; 샑; ) HANGUL SYLLABLE SAELG +C0D2;C0D2;1109 1162 11B1;C0D2;1109 1162 11B1; # (샒; 샒; 샒; 샒; 샒; ) HANGUL SYLLABLE SAELM +C0D3;C0D3;1109 1162 11B2;C0D3;1109 1162 11B2; # (샓; 샓; 샓; 샓; 샓; ) HANGUL SYLLABLE SAELB +C0D4;C0D4;1109 1162 11B3;C0D4;1109 1162 11B3; # (샔; 샔; 샔; 샔; 샔; ) HANGUL SYLLABLE SAELS +C0D5;C0D5;1109 1162 11B4;C0D5;1109 1162 11B4; # (샕; 샕; 샕; 샕; 샕; ) HANGUL SYLLABLE SAELT +C0D6;C0D6;1109 1162 11B5;C0D6;1109 1162 11B5; # (샖; 샖; 샖; 샖; 샖; ) HANGUL SYLLABLE SAELP +C0D7;C0D7;1109 1162 11B6;C0D7;1109 1162 11B6; # (샗; 샗; 샗; 샗; 샗; ) HANGUL SYLLABLE SAELH +C0D8;C0D8;1109 1162 11B7;C0D8;1109 1162 11B7; # (샘; 샘; 샘; 샘; 샘; ) HANGUL SYLLABLE SAEM +C0D9;C0D9;1109 1162 11B8;C0D9;1109 1162 11B8; # (샙; 샙; 샙; 샙; 샙; ) HANGUL SYLLABLE SAEB +C0DA;C0DA;1109 1162 11B9;C0DA;1109 1162 11B9; # (샚; 샚; 샚; 샚; 샚; ) HANGUL SYLLABLE SAEBS +C0DB;C0DB;1109 1162 11BA;C0DB;1109 1162 11BA; # (샛; 샛; 샛; 샛; 샛; ) HANGUL SYLLABLE SAES +C0DC;C0DC;1109 1162 11BB;C0DC;1109 1162 11BB; # (샜; 샜; 샜; 샜; 샜; ) HANGUL SYLLABLE SAESS +C0DD;C0DD;1109 1162 11BC;C0DD;1109 1162 11BC; # (생; 생; 생; 생; 생; ) HANGUL SYLLABLE SAENG +C0DE;C0DE;1109 1162 11BD;C0DE;1109 1162 11BD; # (샞; 샞; 샞; 샞; 샞; ) HANGUL SYLLABLE SAEJ +C0DF;C0DF;1109 1162 11BE;C0DF;1109 1162 11BE; # (샟; 샟; 샟; 샟; 샟; ) HANGUL SYLLABLE SAEC +C0E0;C0E0;1109 1162 11BF;C0E0;1109 1162 11BF; # (샠; 샠; 샠; 샠; 샠; ) HANGUL SYLLABLE SAEK +C0E1;C0E1;1109 1162 11C0;C0E1;1109 1162 11C0; # (샡; 샡; 샡; 샡; 샡; ) HANGUL SYLLABLE SAET +C0E2;C0E2;1109 1162 11C1;C0E2;1109 1162 11C1; # (샢; 샢; 샢; 샢; 샢; ) HANGUL SYLLABLE SAEP +C0E3;C0E3;1109 1162 11C2;C0E3;1109 1162 11C2; # (샣; 샣; 샣; 샣; 샣; ) HANGUL SYLLABLE SAEH +C0E4;C0E4;1109 1163;C0E4;1109 1163; # (샤; 샤; 샤; 샤; 샤; ) HANGUL SYLLABLE SYA +C0E5;C0E5;1109 1163 11A8;C0E5;1109 1163 11A8; # (샥; 샥; 샥; 샥; 샥; ) HANGUL SYLLABLE SYAG +C0E6;C0E6;1109 1163 11A9;C0E6;1109 1163 11A9; # (샦; 샦; 샦; 샦; 샦; ) HANGUL SYLLABLE SYAGG +C0E7;C0E7;1109 1163 11AA;C0E7;1109 1163 11AA; # (샧; 샧; 샧; 샧; 샧; ) HANGUL SYLLABLE SYAGS +C0E8;C0E8;1109 1163 11AB;C0E8;1109 1163 11AB; # (샨; 샨; 샨; 샨; 샨; ) HANGUL SYLLABLE SYAN +C0E9;C0E9;1109 1163 11AC;C0E9;1109 1163 11AC; # (샩; 샩; 샩; 샩; 샩; ) HANGUL SYLLABLE SYANJ +C0EA;C0EA;1109 1163 11AD;C0EA;1109 1163 11AD; # (샪; 샪; 샪; 샪; 샪; ) HANGUL SYLLABLE SYANH +C0EB;C0EB;1109 1163 11AE;C0EB;1109 1163 11AE; # (샫; 샫; 샫; 샫; 샫; ) HANGUL SYLLABLE SYAD +C0EC;C0EC;1109 1163 11AF;C0EC;1109 1163 11AF; # (샬; 샬; 샬; 샬; 샬; ) HANGUL SYLLABLE SYAL +C0ED;C0ED;1109 1163 11B0;C0ED;1109 1163 11B0; # (샭; 샭; 샭; 샭; 샭; ) HANGUL SYLLABLE SYALG +C0EE;C0EE;1109 1163 11B1;C0EE;1109 1163 11B1; # (샮; 샮; 샮; 샮; 샮; ) HANGUL SYLLABLE SYALM +C0EF;C0EF;1109 1163 11B2;C0EF;1109 1163 11B2; # (샯; 샯; 샯; 샯; 샯; ) HANGUL SYLLABLE SYALB +C0F0;C0F0;1109 1163 11B3;C0F0;1109 1163 11B3; # (샰; 샰; 샰; 샰; 샰; ) HANGUL SYLLABLE SYALS +C0F1;C0F1;1109 1163 11B4;C0F1;1109 1163 11B4; # (샱; 샱; 샱; 샱; 샱; ) HANGUL SYLLABLE SYALT +C0F2;C0F2;1109 1163 11B5;C0F2;1109 1163 11B5; # (샲; 샲; 샲; 샲; 샲; ) HANGUL SYLLABLE SYALP +C0F3;C0F3;1109 1163 11B6;C0F3;1109 1163 11B6; # (샳; 샳; 샳; 샳; 샳; ) HANGUL SYLLABLE SYALH +C0F4;C0F4;1109 1163 11B7;C0F4;1109 1163 11B7; # (샴; 샴; 샴; 샴; 샴; ) HANGUL SYLLABLE SYAM +C0F5;C0F5;1109 1163 11B8;C0F5;1109 1163 11B8; # (샵; 샵; 샵; 샵; 샵; ) HANGUL SYLLABLE SYAB +C0F6;C0F6;1109 1163 11B9;C0F6;1109 1163 11B9; # (샶; 샶; 샶; 샶; 샶; ) HANGUL SYLLABLE SYABS +C0F7;C0F7;1109 1163 11BA;C0F7;1109 1163 11BA; # (샷; 샷; 샷; 샷; 샷; ) HANGUL SYLLABLE SYAS +C0F8;C0F8;1109 1163 11BB;C0F8;1109 1163 11BB; # (샸; 샸; 샸; 샸; 샸; ) HANGUL SYLLABLE SYASS +C0F9;C0F9;1109 1163 11BC;C0F9;1109 1163 11BC; # (샹; 샹; 샹; 샹; 샹; ) HANGUL SYLLABLE SYANG +C0FA;C0FA;1109 1163 11BD;C0FA;1109 1163 11BD; # (샺; 샺; 샺; 샺; 샺; ) HANGUL SYLLABLE SYAJ +C0FB;C0FB;1109 1163 11BE;C0FB;1109 1163 11BE; # (샻; 샻; 샻; 샻; 샻; ) HANGUL SYLLABLE SYAC +C0FC;C0FC;1109 1163 11BF;C0FC;1109 1163 11BF; # (샼; 샼; 샼; 샼; 샼; ) HANGUL SYLLABLE SYAK +C0FD;C0FD;1109 1163 11C0;C0FD;1109 1163 11C0; # (샽; 샽; 샽; 샽; 샽; ) HANGUL SYLLABLE SYAT +C0FE;C0FE;1109 1163 11C1;C0FE;1109 1163 11C1; # (샾; 샾; 샾; 샾; 샾; ) HANGUL SYLLABLE SYAP +C0FF;C0FF;1109 1163 11C2;C0FF;1109 1163 11C2; # (샿; 샿; 샿; 샿; 샿; ) HANGUL SYLLABLE SYAH +C100;C100;1109 1164;C100;1109 1164; # (섀; 섀; 섀; 섀; 섀; ) HANGUL SYLLABLE SYAE +C101;C101;1109 1164 11A8;C101;1109 1164 11A8; # (섁; 섁; 섁; 섁; 섁; ) HANGUL SYLLABLE SYAEG +C102;C102;1109 1164 11A9;C102;1109 1164 11A9; # (섂; 섂; 섂; 섂; 섂; ) HANGUL SYLLABLE SYAEGG +C103;C103;1109 1164 11AA;C103;1109 1164 11AA; # (섃; 섃; 섃; 섃; 섃; ) HANGUL SYLLABLE SYAEGS +C104;C104;1109 1164 11AB;C104;1109 1164 11AB; # (섄; 섄; 섄; 섄; 섄; ) HANGUL SYLLABLE SYAEN +C105;C105;1109 1164 11AC;C105;1109 1164 11AC; # (섅; 섅; 섅; 섅; 섅; ) HANGUL SYLLABLE SYAENJ +C106;C106;1109 1164 11AD;C106;1109 1164 11AD; # (섆; 섆; 섆; 섆; 섆; ) HANGUL SYLLABLE SYAENH +C107;C107;1109 1164 11AE;C107;1109 1164 11AE; # (섇; 섇; 섇; 섇; 섇; ) HANGUL SYLLABLE SYAED +C108;C108;1109 1164 11AF;C108;1109 1164 11AF; # (섈; 섈; 섈; 섈; 섈; ) HANGUL SYLLABLE SYAEL +C109;C109;1109 1164 11B0;C109;1109 1164 11B0; # (섉; 섉; 섉; 섉; 섉; ) HANGUL SYLLABLE SYAELG +C10A;C10A;1109 1164 11B1;C10A;1109 1164 11B1; # (섊; 섊; 섊; 섊; 섊; ) HANGUL SYLLABLE SYAELM +C10B;C10B;1109 1164 11B2;C10B;1109 1164 11B2; # (섋; 섋; 섋; 섋; 섋; ) HANGUL SYLLABLE SYAELB +C10C;C10C;1109 1164 11B3;C10C;1109 1164 11B3; # (섌; 섌; 섌; 섌; 섌; ) HANGUL SYLLABLE SYAELS +C10D;C10D;1109 1164 11B4;C10D;1109 1164 11B4; # (섍; 섍; 섍; 섍; 섍; ) HANGUL SYLLABLE SYAELT +C10E;C10E;1109 1164 11B5;C10E;1109 1164 11B5; # (섎; 섎; 섎; 섎; 섎; ) HANGUL SYLLABLE SYAELP +C10F;C10F;1109 1164 11B6;C10F;1109 1164 11B6; # (섏; 섏; 섏; 섏; 섏; ) HANGUL SYLLABLE SYAELH +C110;C110;1109 1164 11B7;C110;1109 1164 11B7; # (섐; 섐; 섐; 섐; 섐; ) HANGUL SYLLABLE SYAEM +C111;C111;1109 1164 11B8;C111;1109 1164 11B8; # (섑; 섑; 섑; 섑; 섑; ) HANGUL SYLLABLE SYAEB +C112;C112;1109 1164 11B9;C112;1109 1164 11B9; # (섒; 섒; 섒; 섒; 섒; ) HANGUL SYLLABLE SYAEBS +C113;C113;1109 1164 11BA;C113;1109 1164 11BA; # (섓; 섓; 섓; 섓; 섓; ) HANGUL SYLLABLE SYAES +C114;C114;1109 1164 11BB;C114;1109 1164 11BB; # (섔; 섔; 섔; 섔; 섔; ) HANGUL SYLLABLE SYAESS +C115;C115;1109 1164 11BC;C115;1109 1164 11BC; # (섕; 섕; 섕; 섕; 섕; ) HANGUL SYLLABLE SYAENG +C116;C116;1109 1164 11BD;C116;1109 1164 11BD; # (섖; 섖; 섖; 섖; 섖; ) HANGUL SYLLABLE SYAEJ +C117;C117;1109 1164 11BE;C117;1109 1164 11BE; # (섗; 섗; 섗; 섗; 섗; ) HANGUL SYLLABLE SYAEC +C118;C118;1109 1164 11BF;C118;1109 1164 11BF; # (섘; 섘; 섘; 섘; 섘; ) HANGUL SYLLABLE SYAEK +C119;C119;1109 1164 11C0;C119;1109 1164 11C0; # (섙; 섙; 섙; 섙; 섙; ) HANGUL SYLLABLE SYAET +C11A;C11A;1109 1164 11C1;C11A;1109 1164 11C1; # (섚; 섚; 섚; 섚; 섚; ) HANGUL SYLLABLE SYAEP +C11B;C11B;1109 1164 11C2;C11B;1109 1164 11C2; # (섛; 섛; 섛; 섛; 섛; ) HANGUL SYLLABLE SYAEH +C11C;C11C;1109 1165;C11C;1109 1165; # (서; 서; 서; 서; 서; ) HANGUL SYLLABLE SEO +C11D;C11D;1109 1165 11A8;C11D;1109 1165 11A8; # (석; 석; 석; 석; 석; ) HANGUL SYLLABLE SEOG +C11E;C11E;1109 1165 11A9;C11E;1109 1165 11A9; # (섞; 섞; 섞; 섞; 섞; ) HANGUL SYLLABLE SEOGG +C11F;C11F;1109 1165 11AA;C11F;1109 1165 11AA; # (섟; 섟; 섟; 섟; 섟; ) HANGUL SYLLABLE SEOGS +C120;C120;1109 1165 11AB;C120;1109 1165 11AB; # (선; 선; 선; 선; 선; ) HANGUL SYLLABLE SEON +C121;C121;1109 1165 11AC;C121;1109 1165 11AC; # (섡; 섡; 섡; 섡; 섡; ) HANGUL SYLLABLE SEONJ +C122;C122;1109 1165 11AD;C122;1109 1165 11AD; # (섢; 섢; 섢; 섢; 섢; ) HANGUL SYLLABLE SEONH +C123;C123;1109 1165 11AE;C123;1109 1165 11AE; # (섣; 섣; 섣; 섣; 섣; ) HANGUL SYLLABLE SEOD +C124;C124;1109 1165 11AF;C124;1109 1165 11AF; # (설; 설; 설; 설; 설; ) HANGUL SYLLABLE SEOL +C125;C125;1109 1165 11B0;C125;1109 1165 11B0; # (섥; 섥; 섥; 섥; 섥; ) HANGUL SYLLABLE SEOLG +C126;C126;1109 1165 11B1;C126;1109 1165 11B1; # (섦; 섦; 섦; 섦; 섦; ) HANGUL SYLLABLE SEOLM +C127;C127;1109 1165 11B2;C127;1109 1165 11B2; # (섧; 섧; 섧; 섧; 섧; ) HANGUL SYLLABLE SEOLB +C128;C128;1109 1165 11B3;C128;1109 1165 11B3; # (섨; 섨; 섨; 섨; 섨; ) HANGUL SYLLABLE SEOLS +C129;C129;1109 1165 11B4;C129;1109 1165 11B4; # (섩; 섩; 섩; 섩; 섩; ) HANGUL SYLLABLE SEOLT +C12A;C12A;1109 1165 11B5;C12A;1109 1165 11B5; # (섪; 섪; 섪; 섪; 섪; ) HANGUL SYLLABLE SEOLP +C12B;C12B;1109 1165 11B6;C12B;1109 1165 11B6; # (섫; 섫; 섫; 섫; 섫; ) HANGUL SYLLABLE SEOLH +C12C;C12C;1109 1165 11B7;C12C;1109 1165 11B7; # (섬; 섬; 섬; 섬; 섬; ) HANGUL SYLLABLE SEOM +C12D;C12D;1109 1165 11B8;C12D;1109 1165 11B8; # (섭; 섭; 섭; 섭; 섭; ) HANGUL SYLLABLE SEOB +C12E;C12E;1109 1165 11B9;C12E;1109 1165 11B9; # (섮; 섮; 섮; 섮; 섮; ) HANGUL SYLLABLE SEOBS +C12F;C12F;1109 1165 11BA;C12F;1109 1165 11BA; # (섯; 섯; 섯; 섯; 섯; ) HANGUL SYLLABLE SEOS +C130;C130;1109 1165 11BB;C130;1109 1165 11BB; # (섰; 섰; 섰; 섰; 섰; ) HANGUL SYLLABLE SEOSS +C131;C131;1109 1165 11BC;C131;1109 1165 11BC; # (성; 성; 성; 성; 성; ) HANGUL SYLLABLE SEONG +C132;C132;1109 1165 11BD;C132;1109 1165 11BD; # (섲; 섲; 섲; 섲; 섲; ) HANGUL SYLLABLE SEOJ +C133;C133;1109 1165 11BE;C133;1109 1165 11BE; # (섳; 섳; 섳; 섳; 섳; ) HANGUL SYLLABLE SEOC +C134;C134;1109 1165 11BF;C134;1109 1165 11BF; # (섴; 섴; 섴; 섴; 섴; ) HANGUL SYLLABLE SEOK +C135;C135;1109 1165 11C0;C135;1109 1165 11C0; # (섵; 섵; 섵; 섵; 섵; ) HANGUL SYLLABLE SEOT +C136;C136;1109 1165 11C1;C136;1109 1165 11C1; # (섶; 섶; 섶; 섶; 섶; ) HANGUL SYLLABLE SEOP +C137;C137;1109 1165 11C2;C137;1109 1165 11C2; # (섷; 섷; 섷; 섷; 섷; ) HANGUL SYLLABLE SEOH +C138;C138;1109 1166;C138;1109 1166; # (세; 세; 세; 세; 세; ) HANGUL SYLLABLE SE +C139;C139;1109 1166 11A8;C139;1109 1166 11A8; # (섹; 섹; 섹; 섹; 섹; ) HANGUL SYLLABLE SEG +C13A;C13A;1109 1166 11A9;C13A;1109 1166 11A9; # (섺; 섺; 섺; 섺; 섺; ) HANGUL SYLLABLE SEGG +C13B;C13B;1109 1166 11AA;C13B;1109 1166 11AA; # (섻; 섻; 섻; 섻; 섻; ) HANGUL SYLLABLE SEGS +C13C;C13C;1109 1166 11AB;C13C;1109 1166 11AB; # (센; 센; 센; 센; 센; ) HANGUL SYLLABLE SEN +C13D;C13D;1109 1166 11AC;C13D;1109 1166 11AC; # (섽; 섽; 섽; 섽; 섽; ) HANGUL SYLLABLE SENJ +C13E;C13E;1109 1166 11AD;C13E;1109 1166 11AD; # (섾; 섾; 섾; 섾; 섾; ) HANGUL SYLLABLE SENH +C13F;C13F;1109 1166 11AE;C13F;1109 1166 11AE; # (섿; 섿; 섿; 섿; 섿; ) HANGUL SYLLABLE SED +C140;C140;1109 1166 11AF;C140;1109 1166 11AF; # (셀; 셀; 셀; 셀; 셀; ) HANGUL SYLLABLE SEL +C141;C141;1109 1166 11B0;C141;1109 1166 11B0; # (셁; 셁; 셁; 셁; 셁; ) HANGUL SYLLABLE SELG +C142;C142;1109 1166 11B1;C142;1109 1166 11B1; # (셂; 셂; 셂; 셂; 셂; ) HANGUL SYLLABLE SELM +C143;C143;1109 1166 11B2;C143;1109 1166 11B2; # (셃; 셃; 셃; 셃; 셃; ) HANGUL SYLLABLE SELB +C144;C144;1109 1166 11B3;C144;1109 1166 11B3; # (셄; 셄; 셄; 셄; 셄; ) HANGUL SYLLABLE SELS +C145;C145;1109 1166 11B4;C145;1109 1166 11B4; # (셅; 셅; 셅; 셅; 셅; ) HANGUL SYLLABLE SELT +C146;C146;1109 1166 11B5;C146;1109 1166 11B5; # (셆; 셆; 셆; 셆; 셆; ) HANGUL SYLLABLE SELP +C147;C147;1109 1166 11B6;C147;1109 1166 11B6; # (셇; 셇; 셇; 셇; 셇; ) HANGUL SYLLABLE SELH +C148;C148;1109 1166 11B7;C148;1109 1166 11B7; # (셈; 셈; 셈; 셈; 셈; ) HANGUL SYLLABLE SEM +C149;C149;1109 1166 11B8;C149;1109 1166 11B8; # (셉; 셉; 셉; 셉; 셉; ) HANGUL SYLLABLE SEB +C14A;C14A;1109 1166 11B9;C14A;1109 1166 11B9; # (셊; 셊; 셊; 셊; 셊; ) HANGUL SYLLABLE SEBS +C14B;C14B;1109 1166 11BA;C14B;1109 1166 11BA; # (셋; 셋; 셋; 셋; 셋; ) HANGUL SYLLABLE SES +C14C;C14C;1109 1166 11BB;C14C;1109 1166 11BB; # (셌; 셌; 셌; 셌; 셌; ) HANGUL SYLLABLE SESS +C14D;C14D;1109 1166 11BC;C14D;1109 1166 11BC; # (셍; 셍; 셍; 셍; 셍; ) HANGUL SYLLABLE SENG +C14E;C14E;1109 1166 11BD;C14E;1109 1166 11BD; # (셎; 셎; 셎; 셎; 셎; ) HANGUL SYLLABLE SEJ +C14F;C14F;1109 1166 11BE;C14F;1109 1166 11BE; # (셏; 셏; 셏; 셏; 셏; ) HANGUL SYLLABLE SEC +C150;C150;1109 1166 11BF;C150;1109 1166 11BF; # (셐; 셐; 셐; 셐; 셐; ) HANGUL SYLLABLE SEK +C151;C151;1109 1166 11C0;C151;1109 1166 11C0; # (셑; 셑; 셑; 셑; 셑; ) HANGUL SYLLABLE SET +C152;C152;1109 1166 11C1;C152;1109 1166 11C1; # (셒; 셒; 셒; 셒; 셒; ) HANGUL SYLLABLE SEP +C153;C153;1109 1166 11C2;C153;1109 1166 11C2; # (셓; 셓; 셓; 셓; 셓; ) HANGUL SYLLABLE SEH +C154;C154;1109 1167;C154;1109 1167; # (셔; 셔; 셔; 셔; 셔; ) HANGUL SYLLABLE SYEO +C155;C155;1109 1167 11A8;C155;1109 1167 11A8; # (셕; 셕; 셕; 셕; 셕; ) HANGUL SYLLABLE SYEOG +C156;C156;1109 1167 11A9;C156;1109 1167 11A9; # (셖; 셖; 셖; 셖; 셖; ) HANGUL SYLLABLE SYEOGG +C157;C157;1109 1167 11AA;C157;1109 1167 11AA; # (셗; 셗; 셗; 셗; 셗; ) HANGUL SYLLABLE SYEOGS +C158;C158;1109 1167 11AB;C158;1109 1167 11AB; # (션; 션; 션; 션; 션; ) HANGUL SYLLABLE SYEON +C159;C159;1109 1167 11AC;C159;1109 1167 11AC; # (셙; 셙; 셙; 셙; 셙; ) HANGUL SYLLABLE SYEONJ +C15A;C15A;1109 1167 11AD;C15A;1109 1167 11AD; # (셚; 셚; 셚; 셚; 셚; ) HANGUL SYLLABLE SYEONH +C15B;C15B;1109 1167 11AE;C15B;1109 1167 11AE; # (셛; 셛; 셛; 셛; 셛; ) HANGUL SYLLABLE SYEOD +C15C;C15C;1109 1167 11AF;C15C;1109 1167 11AF; # (셜; 셜; 셜; 셜; 셜; ) HANGUL SYLLABLE SYEOL +C15D;C15D;1109 1167 11B0;C15D;1109 1167 11B0; # (셝; 셝; 셝; 셝; 셝; ) HANGUL SYLLABLE SYEOLG +C15E;C15E;1109 1167 11B1;C15E;1109 1167 11B1; # (셞; 셞; 셞; 셞; 셞; ) HANGUL SYLLABLE SYEOLM +C15F;C15F;1109 1167 11B2;C15F;1109 1167 11B2; # (셟; 셟; 셟; 셟; 셟; ) HANGUL SYLLABLE SYEOLB +C160;C160;1109 1167 11B3;C160;1109 1167 11B3; # (셠; 셠; 셠; 셠; 셠; ) HANGUL SYLLABLE SYEOLS +C161;C161;1109 1167 11B4;C161;1109 1167 11B4; # (셡; 셡; 셡; 셡; 셡; ) HANGUL SYLLABLE SYEOLT +C162;C162;1109 1167 11B5;C162;1109 1167 11B5; # (셢; 셢; 셢; 셢; 셢; ) HANGUL SYLLABLE SYEOLP +C163;C163;1109 1167 11B6;C163;1109 1167 11B6; # (셣; 셣; 셣; 셣; 셣; ) HANGUL SYLLABLE SYEOLH +C164;C164;1109 1167 11B7;C164;1109 1167 11B7; # (셤; 셤; 셤; 셤; 셤; ) HANGUL SYLLABLE SYEOM +C165;C165;1109 1167 11B8;C165;1109 1167 11B8; # (셥; 셥; 셥; 셥; 셥; ) HANGUL SYLLABLE SYEOB +C166;C166;1109 1167 11B9;C166;1109 1167 11B9; # (셦; 셦; 셦; 셦; 셦; ) HANGUL SYLLABLE SYEOBS +C167;C167;1109 1167 11BA;C167;1109 1167 11BA; # (셧; 셧; 셧; 셧; 셧; ) HANGUL SYLLABLE SYEOS +C168;C168;1109 1167 11BB;C168;1109 1167 11BB; # (셨; 셨; 셨; 셨; 셨; ) HANGUL SYLLABLE SYEOSS +C169;C169;1109 1167 11BC;C169;1109 1167 11BC; # (셩; 셩; 셩; 셩; 셩; ) HANGUL SYLLABLE SYEONG +C16A;C16A;1109 1167 11BD;C16A;1109 1167 11BD; # (셪; 셪; 셪; 셪; 셪; ) HANGUL SYLLABLE SYEOJ +C16B;C16B;1109 1167 11BE;C16B;1109 1167 11BE; # (셫; 셫; 셫; 셫; 셫; ) HANGUL SYLLABLE SYEOC +C16C;C16C;1109 1167 11BF;C16C;1109 1167 11BF; # (셬; 셬; 셬; 셬; 셬; ) HANGUL SYLLABLE SYEOK +C16D;C16D;1109 1167 11C0;C16D;1109 1167 11C0; # (셭; 셭; 셭; 셭; 셭; ) HANGUL SYLLABLE SYEOT +C16E;C16E;1109 1167 11C1;C16E;1109 1167 11C1; # (셮; 셮; 셮; 셮; 셮; ) HANGUL SYLLABLE SYEOP +C16F;C16F;1109 1167 11C2;C16F;1109 1167 11C2; # (셯; 셯; 셯; 셯; 셯; ) HANGUL SYLLABLE SYEOH +C170;C170;1109 1168;C170;1109 1168; # (셰; 셰; 셰; 셰; 셰; ) HANGUL SYLLABLE SYE +C171;C171;1109 1168 11A8;C171;1109 1168 11A8; # (셱; 셱; 셱; 셱; 셱; ) HANGUL SYLLABLE SYEG +C172;C172;1109 1168 11A9;C172;1109 1168 11A9; # (셲; 셲; 셲; 셲; 셲; ) HANGUL SYLLABLE SYEGG +C173;C173;1109 1168 11AA;C173;1109 1168 11AA; # (셳; 셳; 셳; 셳; 셳; ) HANGUL SYLLABLE SYEGS +C174;C174;1109 1168 11AB;C174;1109 1168 11AB; # (셴; 셴; 셴; 셴; 셴; ) HANGUL SYLLABLE SYEN +C175;C175;1109 1168 11AC;C175;1109 1168 11AC; # (셵; 셵; 셵; 셵; 셵; ) HANGUL SYLLABLE SYENJ +C176;C176;1109 1168 11AD;C176;1109 1168 11AD; # (셶; 셶; 셶; 셶; 셶; ) HANGUL SYLLABLE SYENH +C177;C177;1109 1168 11AE;C177;1109 1168 11AE; # (셷; 셷; 셷; 셷; 셷; ) HANGUL SYLLABLE SYED +C178;C178;1109 1168 11AF;C178;1109 1168 11AF; # (셸; 셸; 셸; 셸; 셸; ) HANGUL SYLLABLE SYEL +C179;C179;1109 1168 11B0;C179;1109 1168 11B0; # (셹; 셹; 셹; 셹; 셹; ) HANGUL SYLLABLE SYELG +C17A;C17A;1109 1168 11B1;C17A;1109 1168 11B1; # (셺; 셺; 셺; 셺; 셺; ) HANGUL SYLLABLE SYELM +C17B;C17B;1109 1168 11B2;C17B;1109 1168 11B2; # (셻; 셻; 셻; 셻; 셻; ) HANGUL SYLLABLE SYELB +C17C;C17C;1109 1168 11B3;C17C;1109 1168 11B3; # (셼; 셼; 셼; 셼; 셼; ) HANGUL SYLLABLE SYELS +C17D;C17D;1109 1168 11B4;C17D;1109 1168 11B4; # (셽; 셽; 셽; 셽; 셽; ) HANGUL SYLLABLE SYELT +C17E;C17E;1109 1168 11B5;C17E;1109 1168 11B5; # (셾; 셾; 셾; 셾; 셾; ) HANGUL SYLLABLE SYELP +C17F;C17F;1109 1168 11B6;C17F;1109 1168 11B6; # (셿; 셿; 셿; 셿; 셿; ) HANGUL SYLLABLE SYELH +C180;C180;1109 1168 11B7;C180;1109 1168 11B7; # (솀; 솀; 솀; 솀; 솀; ) HANGUL SYLLABLE SYEM +C181;C181;1109 1168 11B8;C181;1109 1168 11B8; # (솁; 솁; 솁; 솁; 솁; ) HANGUL SYLLABLE SYEB +C182;C182;1109 1168 11B9;C182;1109 1168 11B9; # (솂; 솂; 솂; 솂; 솂; ) HANGUL SYLLABLE SYEBS +C183;C183;1109 1168 11BA;C183;1109 1168 11BA; # (솃; 솃; 솃; 솃; 솃; ) HANGUL SYLLABLE SYES +C184;C184;1109 1168 11BB;C184;1109 1168 11BB; # (솄; 솄; 솄; 솄; 솄; ) HANGUL SYLLABLE SYESS +C185;C185;1109 1168 11BC;C185;1109 1168 11BC; # (솅; 솅; 솅; 솅; 솅; ) HANGUL SYLLABLE SYENG +C186;C186;1109 1168 11BD;C186;1109 1168 11BD; # (솆; 솆; 솆; 솆; 솆; ) HANGUL SYLLABLE SYEJ +C187;C187;1109 1168 11BE;C187;1109 1168 11BE; # (솇; 솇; 솇; 솇; 솇; ) HANGUL SYLLABLE SYEC +C188;C188;1109 1168 11BF;C188;1109 1168 11BF; # (솈; 솈; 솈; 솈; 솈; ) HANGUL SYLLABLE SYEK +C189;C189;1109 1168 11C0;C189;1109 1168 11C0; # (솉; 솉; 솉; 솉; 솉; ) HANGUL SYLLABLE SYET +C18A;C18A;1109 1168 11C1;C18A;1109 1168 11C1; # (솊; 솊; 솊; 솊; 솊; ) HANGUL SYLLABLE SYEP +C18B;C18B;1109 1168 11C2;C18B;1109 1168 11C2; # (솋; 솋; 솋; 솋; 솋; ) HANGUL SYLLABLE SYEH +C18C;C18C;1109 1169;C18C;1109 1169; # (소; 소; 소; 소; 소; ) HANGUL SYLLABLE SO +C18D;C18D;1109 1169 11A8;C18D;1109 1169 11A8; # (속; 속; 속; 속; 속; ) HANGUL SYLLABLE SOG +C18E;C18E;1109 1169 11A9;C18E;1109 1169 11A9; # (솎; 솎; 솎; 솎; 솎; ) HANGUL SYLLABLE SOGG +C18F;C18F;1109 1169 11AA;C18F;1109 1169 11AA; # (솏; 솏; 솏; 솏; 솏; ) HANGUL SYLLABLE SOGS +C190;C190;1109 1169 11AB;C190;1109 1169 11AB; # (손; 손; 손; 손; 손; ) HANGUL SYLLABLE SON +C191;C191;1109 1169 11AC;C191;1109 1169 11AC; # (솑; 솑; 솑; 솑; 솑; ) HANGUL SYLLABLE SONJ +C192;C192;1109 1169 11AD;C192;1109 1169 11AD; # (솒; 솒; 솒; 솒; 솒; ) HANGUL SYLLABLE SONH +C193;C193;1109 1169 11AE;C193;1109 1169 11AE; # (솓; 솓; 솓; 솓; 솓; ) HANGUL SYLLABLE SOD +C194;C194;1109 1169 11AF;C194;1109 1169 11AF; # (솔; 솔; 솔; 솔; 솔; ) HANGUL SYLLABLE SOL +C195;C195;1109 1169 11B0;C195;1109 1169 11B0; # (솕; 솕; 솕; 솕; 솕; ) HANGUL SYLLABLE SOLG +C196;C196;1109 1169 11B1;C196;1109 1169 11B1; # (솖; 솖; 솖; 솖; 솖; ) HANGUL SYLLABLE SOLM +C197;C197;1109 1169 11B2;C197;1109 1169 11B2; # (솗; 솗; 솗; 솗; 솗; ) HANGUL SYLLABLE SOLB +C198;C198;1109 1169 11B3;C198;1109 1169 11B3; # (솘; 솘; 솘; 솘; 솘; ) HANGUL SYLLABLE SOLS +C199;C199;1109 1169 11B4;C199;1109 1169 11B4; # (솙; 솙; 솙; 솙; 솙; ) HANGUL SYLLABLE SOLT +C19A;C19A;1109 1169 11B5;C19A;1109 1169 11B5; # (솚; 솚; 솚; 솚; 솚; ) HANGUL SYLLABLE SOLP +C19B;C19B;1109 1169 11B6;C19B;1109 1169 11B6; # (솛; 솛; 솛; 솛; 솛; ) HANGUL SYLLABLE SOLH +C19C;C19C;1109 1169 11B7;C19C;1109 1169 11B7; # (솜; 솜; 솜; 솜; 솜; ) HANGUL SYLLABLE SOM +C19D;C19D;1109 1169 11B8;C19D;1109 1169 11B8; # (솝; 솝; 솝; 솝; 솝; ) HANGUL SYLLABLE SOB +C19E;C19E;1109 1169 11B9;C19E;1109 1169 11B9; # (솞; 솞; 솞; 솞; 솞; ) HANGUL SYLLABLE SOBS +C19F;C19F;1109 1169 11BA;C19F;1109 1169 11BA; # (솟; 솟; 솟; 솟; 솟; ) HANGUL SYLLABLE SOS +C1A0;C1A0;1109 1169 11BB;C1A0;1109 1169 11BB; # (솠; 솠; 솠; 솠; 솠; ) HANGUL SYLLABLE SOSS +C1A1;C1A1;1109 1169 11BC;C1A1;1109 1169 11BC; # (송; 송; 송; 송; 송; ) HANGUL SYLLABLE SONG +C1A2;C1A2;1109 1169 11BD;C1A2;1109 1169 11BD; # (솢; 솢; 솢; 솢; 솢; ) HANGUL SYLLABLE SOJ +C1A3;C1A3;1109 1169 11BE;C1A3;1109 1169 11BE; # (솣; 솣; 솣; 솣; 솣; ) HANGUL SYLLABLE SOC +C1A4;C1A4;1109 1169 11BF;C1A4;1109 1169 11BF; # (솤; 솤; 솤; 솤; 솤; ) HANGUL SYLLABLE SOK +C1A5;C1A5;1109 1169 11C0;C1A5;1109 1169 11C0; # (솥; 솥; 솥; 솥; 솥; ) HANGUL SYLLABLE SOT +C1A6;C1A6;1109 1169 11C1;C1A6;1109 1169 11C1; # (솦; 솦; 솦; 솦; 솦; ) HANGUL SYLLABLE SOP +C1A7;C1A7;1109 1169 11C2;C1A7;1109 1169 11C2; # (솧; 솧; 솧; 솧; 솧; ) HANGUL SYLLABLE SOH +C1A8;C1A8;1109 116A;C1A8;1109 116A; # (솨; 솨; 솨; 솨; 솨; ) HANGUL SYLLABLE SWA +C1A9;C1A9;1109 116A 11A8;C1A9;1109 116A 11A8; # (솩; 솩; 솩; 솩; 솩; ) HANGUL SYLLABLE SWAG +C1AA;C1AA;1109 116A 11A9;C1AA;1109 116A 11A9; # (솪; 솪; 솪; 솪; 솪; ) HANGUL SYLLABLE SWAGG +C1AB;C1AB;1109 116A 11AA;C1AB;1109 116A 11AA; # (솫; 솫; 솫; 솫; 솫; ) HANGUL SYLLABLE SWAGS +C1AC;C1AC;1109 116A 11AB;C1AC;1109 116A 11AB; # (솬; 솬; 솬; 솬; 솬; ) HANGUL SYLLABLE SWAN +C1AD;C1AD;1109 116A 11AC;C1AD;1109 116A 11AC; # (솭; 솭; 솭; 솭; 솭; ) HANGUL SYLLABLE SWANJ +C1AE;C1AE;1109 116A 11AD;C1AE;1109 116A 11AD; # (솮; 솮; 솮; 솮; 솮; ) HANGUL SYLLABLE SWANH +C1AF;C1AF;1109 116A 11AE;C1AF;1109 116A 11AE; # (솯; 솯; 솯; 솯; 솯; ) HANGUL SYLLABLE SWAD +C1B0;C1B0;1109 116A 11AF;C1B0;1109 116A 11AF; # (솰; 솰; 솰; 솰; 솰; ) HANGUL SYLLABLE SWAL +C1B1;C1B1;1109 116A 11B0;C1B1;1109 116A 11B0; # (솱; 솱; 솱; 솱; 솱; ) HANGUL SYLLABLE SWALG +C1B2;C1B2;1109 116A 11B1;C1B2;1109 116A 11B1; # (솲; 솲; 솲; 솲; 솲; ) HANGUL SYLLABLE SWALM +C1B3;C1B3;1109 116A 11B2;C1B3;1109 116A 11B2; # (솳; 솳; 솳; 솳; 솳; ) HANGUL SYLLABLE SWALB +C1B4;C1B4;1109 116A 11B3;C1B4;1109 116A 11B3; # (솴; 솴; 솴; 솴; 솴; ) HANGUL SYLLABLE SWALS +C1B5;C1B5;1109 116A 11B4;C1B5;1109 116A 11B4; # (솵; 솵; 솵; 솵; 솵; ) HANGUL SYLLABLE SWALT +C1B6;C1B6;1109 116A 11B5;C1B6;1109 116A 11B5; # (솶; 솶; 솶; 솶; 솶; ) HANGUL SYLLABLE SWALP +C1B7;C1B7;1109 116A 11B6;C1B7;1109 116A 11B6; # (솷; 솷; 솷; 솷; 솷; ) HANGUL SYLLABLE SWALH +C1B8;C1B8;1109 116A 11B7;C1B8;1109 116A 11B7; # (솸; 솸; 솸; 솸; 솸; ) HANGUL SYLLABLE SWAM +C1B9;C1B9;1109 116A 11B8;C1B9;1109 116A 11B8; # (솹; 솹; 솹; 솹; 솹; ) HANGUL SYLLABLE SWAB +C1BA;C1BA;1109 116A 11B9;C1BA;1109 116A 11B9; # (솺; 솺; 솺; 솺; 솺; ) HANGUL SYLLABLE SWABS +C1BB;C1BB;1109 116A 11BA;C1BB;1109 116A 11BA; # (솻; 솻; 솻; 솻; 솻; ) HANGUL SYLLABLE SWAS +C1BC;C1BC;1109 116A 11BB;C1BC;1109 116A 11BB; # (솼; 솼; 솼; 솼; 솼; ) HANGUL SYLLABLE SWASS +C1BD;C1BD;1109 116A 11BC;C1BD;1109 116A 11BC; # (솽; 솽; 솽; 솽; 솽; ) HANGUL SYLLABLE SWANG +C1BE;C1BE;1109 116A 11BD;C1BE;1109 116A 11BD; # (솾; 솾; 솾; 솾; 솾; ) HANGUL SYLLABLE SWAJ +C1BF;C1BF;1109 116A 11BE;C1BF;1109 116A 11BE; # (솿; 솿; 솿; 솿; 솿; ) HANGUL SYLLABLE SWAC +C1C0;C1C0;1109 116A 11BF;C1C0;1109 116A 11BF; # (쇀; 쇀; 쇀; 쇀; 쇀; ) HANGUL SYLLABLE SWAK +C1C1;C1C1;1109 116A 11C0;C1C1;1109 116A 11C0; # (쇁; 쇁; 쇁; 쇁; 쇁; ) HANGUL SYLLABLE SWAT +C1C2;C1C2;1109 116A 11C1;C1C2;1109 116A 11C1; # (쇂; 쇂; 쇂; 쇂; 쇂; ) HANGUL SYLLABLE SWAP +C1C3;C1C3;1109 116A 11C2;C1C3;1109 116A 11C2; # (쇃; 쇃; 쇃; 쇃; 쇃; ) HANGUL SYLLABLE SWAH +C1C4;C1C4;1109 116B;C1C4;1109 116B; # (쇄; 쇄; 쇄; 쇄; 쇄; ) HANGUL SYLLABLE SWAE +C1C5;C1C5;1109 116B 11A8;C1C5;1109 116B 11A8; # (쇅; 쇅; 쇅; 쇅; 쇅; ) HANGUL SYLLABLE SWAEG +C1C6;C1C6;1109 116B 11A9;C1C6;1109 116B 11A9; # (쇆; 쇆; 쇆; 쇆; 쇆; ) HANGUL SYLLABLE SWAEGG +C1C7;C1C7;1109 116B 11AA;C1C7;1109 116B 11AA; # (쇇; 쇇; 쇇; 쇇; 쇇; ) HANGUL SYLLABLE SWAEGS +C1C8;C1C8;1109 116B 11AB;C1C8;1109 116B 11AB; # (쇈; 쇈; 쇈; 쇈; 쇈; ) HANGUL SYLLABLE SWAEN +C1C9;C1C9;1109 116B 11AC;C1C9;1109 116B 11AC; # (쇉; 쇉; 쇉; 쇉; 쇉; ) HANGUL SYLLABLE SWAENJ +C1CA;C1CA;1109 116B 11AD;C1CA;1109 116B 11AD; # (쇊; 쇊; 쇊; 쇊; 쇊; ) HANGUL SYLLABLE SWAENH +C1CB;C1CB;1109 116B 11AE;C1CB;1109 116B 11AE; # (쇋; 쇋; 쇋; 쇋; 쇋; ) HANGUL SYLLABLE SWAED +C1CC;C1CC;1109 116B 11AF;C1CC;1109 116B 11AF; # (쇌; 쇌; 쇌; 쇌; 쇌; ) HANGUL SYLLABLE SWAEL +C1CD;C1CD;1109 116B 11B0;C1CD;1109 116B 11B0; # (쇍; 쇍; 쇍; 쇍; 쇍; ) HANGUL SYLLABLE SWAELG +C1CE;C1CE;1109 116B 11B1;C1CE;1109 116B 11B1; # (쇎; 쇎; 쇎; 쇎; 쇎; ) HANGUL SYLLABLE SWAELM +C1CF;C1CF;1109 116B 11B2;C1CF;1109 116B 11B2; # (쇏; 쇏; 쇏; 쇏; 쇏; ) HANGUL SYLLABLE SWAELB +C1D0;C1D0;1109 116B 11B3;C1D0;1109 116B 11B3; # (쇐; 쇐; 쇐; 쇐; 쇐; ) HANGUL SYLLABLE SWAELS +C1D1;C1D1;1109 116B 11B4;C1D1;1109 116B 11B4; # (쇑; 쇑; 쇑; 쇑; 쇑; ) HANGUL SYLLABLE SWAELT +C1D2;C1D2;1109 116B 11B5;C1D2;1109 116B 11B5; # (쇒; 쇒; 쇒; 쇒; 쇒; ) HANGUL SYLLABLE SWAELP +C1D3;C1D3;1109 116B 11B6;C1D3;1109 116B 11B6; # (쇓; 쇓; 쇓; 쇓; 쇓; ) HANGUL SYLLABLE SWAELH +C1D4;C1D4;1109 116B 11B7;C1D4;1109 116B 11B7; # (쇔; 쇔; 쇔; 쇔; 쇔; ) HANGUL SYLLABLE SWAEM +C1D5;C1D5;1109 116B 11B8;C1D5;1109 116B 11B8; # (쇕; 쇕; 쇕; 쇕; 쇕; ) HANGUL SYLLABLE SWAEB +C1D6;C1D6;1109 116B 11B9;C1D6;1109 116B 11B9; # (쇖; 쇖; 쇖; 쇖; 쇖; ) HANGUL SYLLABLE SWAEBS +C1D7;C1D7;1109 116B 11BA;C1D7;1109 116B 11BA; # (쇗; 쇗; 쇗; 쇗; 쇗; ) HANGUL SYLLABLE SWAES +C1D8;C1D8;1109 116B 11BB;C1D8;1109 116B 11BB; # (쇘; 쇘; 쇘; 쇘; 쇘; ) HANGUL SYLLABLE SWAESS +C1D9;C1D9;1109 116B 11BC;C1D9;1109 116B 11BC; # (쇙; 쇙; 쇙; 쇙; 쇙; ) HANGUL SYLLABLE SWAENG +C1DA;C1DA;1109 116B 11BD;C1DA;1109 116B 11BD; # (쇚; 쇚; 쇚; 쇚; 쇚; ) HANGUL SYLLABLE SWAEJ +C1DB;C1DB;1109 116B 11BE;C1DB;1109 116B 11BE; # (쇛; 쇛; 쇛; 쇛; 쇛; ) HANGUL SYLLABLE SWAEC +C1DC;C1DC;1109 116B 11BF;C1DC;1109 116B 11BF; # (쇜; 쇜; 쇜; 쇜; 쇜; ) HANGUL SYLLABLE SWAEK +C1DD;C1DD;1109 116B 11C0;C1DD;1109 116B 11C0; # (쇝; 쇝; 쇝; 쇝; 쇝; ) HANGUL SYLLABLE SWAET +C1DE;C1DE;1109 116B 11C1;C1DE;1109 116B 11C1; # (쇞; 쇞; 쇞; 쇞; 쇞; ) HANGUL SYLLABLE SWAEP +C1DF;C1DF;1109 116B 11C2;C1DF;1109 116B 11C2; # (쇟; 쇟; 쇟; 쇟; 쇟; ) HANGUL SYLLABLE SWAEH +C1E0;C1E0;1109 116C;C1E0;1109 116C; # (쇠; 쇠; 쇠; 쇠; 쇠; ) HANGUL SYLLABLE SOE +C1E1;C1E1;1109 116C 11A8;C1E1;1109 116C 11A8; # (쇡; 쇡; 쇡; 쇡; 쇡; ) HANGUL SYLLABLE SOEG +C1E2;C1E2;1109 116C 11A9;C1E2;1109 116C 11A9; # (쇢; 쇢; 쇢; 쇢; 쇢; ) HANGUL SYLLABLE SOEGG +C1E3;C1E3;1109 116C 11AA;C1E3;1109 116C 11AA; # (쇣; 쇣; 쇣; 쇣; 쇣; ) HANGUL SYLLABLE SOEGS +C1E4;C1E4;1109 116C 11AB;C1E4;1109 116C 11AB; # (쇤; 쇤; 쇤; 쇤; 쇤; ) HANGUL SYLLABLE SOEN +C1E5;C1E5;1109 116C 11AC;C1E5;1109 116C 11AC; # (쇥; 쇥; 쇥; 쇥; 쇥; ) HANGUL SYLLABLE SOENJ +C1E6;C1E6;1109 116C 11AD;C1E6;1109 116C 11AD; # (쇦; 쇦; 쇦; 쇦; 쇦; ) HANGUL SYLLABLE SOENH +C1E7;C1E7;1109 116C 11AE;C1E7;1109 116C 11AE; # (쇧; 쇧; 쇧; 쇧; 쇧; ) HANGUL SYLLABLE SOED +C1E8;C1E8;1109 116C 11AF;C1E8;1109 116C 11AF; # (쇨; 쇨; 쇨; 쇨; 쇨; ) HANGUL SYLLABLE SOEL +C1E9;C1E9;1109 116C 11B0;C1E9;1109 116C 11B0; # (쇩; 쇩; 쇩; 쇩; 쇩; ) HANGUL SYLLABLE SOELG +C1EA;C1EA;1109 116C 11B1;C1EA;1109 116C 11B1; # (쇪; 쇪; 쇪; 쇪; 쇪; ) HANGUL SYLLABLE SOELM +C1EB;C1EB;1109 116C 11B2;C1EB;1109 116C 11B2; # (쇫; 쇫; 쇫; 쇫; 쇫; ) HANGUL SYLLABLE SOELB +C1EC;C1EC;1109 116C 11B3;C1EC;1109 116C 11B3; # (쇬; 쇬; 쇬; 쇬; 쇬; ) HANGUL SYLLABLE SOELS +C1ED;C1ED;1109 116C 11B4;C1ED;1109 116C 11B4; # (쇭; 쇭; 쇭; 쇭; 쇭; ) HANGUL SYLLABLE SOELT +C1EE;C1EE;1109 116C 11B5;C1EE;1109 116C 11B5; # (쇮; 쇮; 쇮; 쇮; 쇮; ) HANGUL SYLLABLE SOELP +C1EF;C1EF;1109 116C 11B6;C1EF;1109 116C 11B6; # (쇯; 쇯; 쇯; 쇯; 쇯; ) HANGUL SYLLABLE SOELH +C1F0;C1F0;1109 116C 11B7;C1F0;1109 116C 11B7; # (쇰; 쇰; 쇰; 쇰; 쇰; ) HANGUL SYLLABLE SOEM +C1F1;C1F1;1109 116C 11B8;C1F1;1109 116C 11B8; # (쇱; 쇱; 쇱; 쇱; 쇱; ) HANGUL SYLLABLE SOEB +C1F2;C1F2;1109 116C 11B9;C1F2;1109 116C 11B9; # (쇲; 쇲; 쇲; 쇲; 쇲; ) HANGUL SYLLABLE SOEBS +C1F3;C1F3;1109 116C 11BA;C1F3;1109 116C 11BA; # (쇳; 쇳; 쇳; 쇳; 쇳; ) HANGUL SYLLABLE SOES +C1F4;C1F4;1109 116C 11BB;C1F4;1109 116C 11BB; # (쇴; 쇴; 쇴; 쇴; 쇴; ) HANGUL SYLLABLE SOESS +C1F5;C1F5;1109 116C 11BC;C1F5;1109 116C 11BC; # (쇵; 쇵; 쇵; 쇵; 쇵; ) HANGUL SYLLABLE SOENG +C1F6;C1F6;1109 116C 11BD;C1F6;1109 116C 11BD; # (쇶; 쇶; 쇶; 쇶; 쇶; ) HANGUL SYLLABLE SOEJ +C1F7;C1F7;1109 116C 11BE;C1F7;1109 116C 11BE; # (쇷; 쇷; 쇷; 쇷; 쇷; ) HANGUL SYLLABLE SOEC +C1F8;C1F8;1109 116C 11BF;C1F8;1109 116C 11BF; # (쇸; 쇸; 쇸; 쇸; 쇸; ) HANGUL SYLLABLE SOEK +C1F9;C1F9;1109 116C 11C0;C1F9;1109 116C 11C0; # (쇹; 쇹; 쇹; 쇹; 쇹; ) HANGUL SYLLABLE SOET +C1FA;C1FA;1109 116C 11C1;C1FA;1109 116C 11C1; # (쇺; 쇺; 쇺; 쇺; 쇺; ) HANGUL SYLLABLE SOEP +C1FB;C1FB;1109 116C 11C2;C1FB;1109 116C 11C2; # (쇻; 쇻; 쇻; 쇻; 쇻; ) HANGUL SYLLABLE SOEH +C1FC;C1FC;1109 116D;C1FC;1109 116D; # (쇼; 쇼; 쇼; 쇼; 쇼; ) HANGUL SYLLABLE SYO +C1FD;C1FD;1109 116D 11A8;C1FD;1109 116D 11A8; # (쇽; 쇽; 쇽; 쇽; 쇽; ) HANGUL SYLLABLE SYOG +C1FE;C1FE;1109 116D 11A9;C1FE;1109 116D 11A9; # (쇾; 쇾; 쇾; 쇾; 쇾; ) HANGUL SYLLABLE SYOGG +C1FF;C1FF;1109 116D 11AA;C1FF;1109 116D 11AA; # (쇿; 쇿; 쇿; 쇿; 쇿; ) HANGUL SYLLABLE SYOGS +C200;C200;1109 116D 11AB;C200;1109 116D 11AB; # (숀; 숀; 숀; 숀; 숀; ) HANGUL SYLLABLE SYON +C201;C201;1109 116D 11AC;C201;1109 116D 11AC; # (숁; 숁; 숁; 숁; 숁; ) HANGUL SYLLABLE SYONJ +C202;C202;1109 116D 11AD;C202;1109 116D 11AD; # (숂; 숂; 숂; 숂; 숂; ) HANGUL SYLLABLE SYONH +C203;C203;1109 116D 11AE;C203;1109 116D 11AE; # (숃; 숃; 숃; 숃; 숃; ) HANGUL SYLLABLE SYOD +C204;C204;1109 116D 11AF;C204;1109 116D 11AF; # (숄; 숄; 숄; 숄; 숄; ) HANGUL SYLLABLE SYOL +C205;C205;1109 116D 11B0;C205;1109 116D 11B0; # (숅; 숅; 숅; 숅; 숅; ) HANGUL SYLLABLE SYOLG +C206;C206;1109 116D 11B1;C206;1109 116D 11B1; # (숆; 숆; 숆; 숆; 숆; ) HANGUL SYLLABLE SYOLM +C207;C207;1109 116D 11B2;C207;1109 116D 11B2; # (숇; 숇; 숇; 숇; 숇; ) HANGUL SYLLABLE SYOLB +C208;C208;1109 116D 11B3;C208;1109 116D 11B3; # (숈; 숈; 숈; 숈; 숈; ) HANGUL SYLLABLE SYOLS +C209;C209;1109 116D 11B4;C209;1109 116D 11B4; # (숉; 숉; 숉; 숉; 숉; ) HANGUL SYLLABLE SYOLT +C20A;C20A;1109 116D 11B5;C20A;1109 116D 11B5; # (숊; 숊; 숊; 숊; 숊; ) HANGUL SYLLABLE SYOLP +C20B;C20B;1109 116D 11B6;C20B;1109 116D 11B6; # (숋; 숋; 숋; 숋; 숋; ) HANGUL SYLLABLE SYOLH +C20C;C20C;1109 116D 11B7;C20C;1109 116D 11B7; # (숌; 숌; 숌; 숌; 숌; ) HANGUL SYLLABLE SYOM +C20D;C20D;1109 116D 11B8;C20D;1109 116D 11B8; # (숍; 숍; 숍; 숍; 숍; ) HANGUL SYLLABLE SYOB +C20E;C20E;1109 116D 11B9;C20E;1109 116D 11B9; # (숎; 숎; 숎; 숎; 숎; ) HANGUL SYLLABLE SYOBS +C20F;C20F;1109 116D 11BA;C20F;1109 116D 11BA; # (숏; 숏; 숏; 숏; 숏; ) HANGUL SYLLABLE SYOS +C210;C210;1109 116D 11BB;C210;1109 116D 11BB; # (숐; 숐; 숐; 숐; 숐; ) HANGUL SYLLABLE SYOSS +C211;C211;1109 116D 11BC;C211;1109 116D 11BC; # (숑; 숑; 숑; 숑; 숑; ) HANGUL SYLLABLE SYONG +C212;C212;1109 116D 11BD;C212;1109 116D 11BD; # (숒; 숒; 숒; 숒; 숒; ) HANGUL SYLLABLE SYOJ +C213;C213;1109 116D 11BE;C213;1109 116D 11BE; # (숓; 숓; 숓; 숓; 숓; ) HANGUL SYLLABLE SYOC +C214;C214;1109 116D 11BF;C214;1109 116D 11BF; # (숔; 숔; 숔; 숔; 숔; ) HANGUL SYLLABLE SYOK +C215;C215;1109 116D 11C0;C215;1109 116D 11C0; # (숕; 숕; 숕; 숕; 숕; ) HANGUL SYLLABLE SYOT +C216;C216;1109 116D 11C1;C216;1109 116D 11C1; # (숖; 숖; 숖; 숖; 숖; ) HANGUL SYLLABLE SYOP +C217;C217;1109 116D 11C2;C217;1109 116D 11C2; # (숗; 숗; 숗; 숗; 숗; ) HANGUL SYLLABLE SYOH +C218;C218;1109 116E;C218;1109 116E; # (수; 수; 수; 수; 수; ) HANGUL SYLLABLE SU +C219;C219;1109 116E 11A8;C219;1109 116E 11A8; # (숙; 숙; 숙; 숙; 숙; ) HANGUL SYLLABLE SUG +C21A;C21A;1109 116E 11A9;C21A;1109 116E 11A9; # (숚; 숚; 숚; 숚; 숚; ) HANGUL SYLLABLE SUGG +C21B;C21B;1109 116E 11AA;C21B;1109 116E 11AA; # (숛; 숛; 숛; 숛; 숛; ) HANGUL SYLLABLE SUGS +C21C;C21C;1109 116E 11AB;C21C;1109 116E 11AB; # (순; 순; 순; 순; 순; ) HANGUL SYLLABLE SUN +C21D;C21D;1109 116E 11AC;C21D;1109 116E 11AC; # (숝; 숝; 숝; 숝; 숝; ) HANGUL SYLLABLE SUNJ +C21E;C21E;1109 116E 11AD;C21E;1109 116E 11AD; # (숞; 숞; 숞; 숞; 숞; ) HANGUL SYLLABLE SUNH +C21F;C21F;1109 116E 11AE;C21F;1109 116E 11AE; # (숟; 숟; 숟; 숟; 숟; ) HANGUL SYLLABLE SUD +C220;C220;1109 116E 11AF;C220;1109 116E 11AF; # (술; 술; 술; 술; 술; ) HANGUL SYLLABLE SUL +C221;C221;1109 116E 11B0;C221;1109 116E 11B0; # (숡; 숡; 숡; 숡; 숡; ) HANGUL SYLLABLE SULG +C222;C222;1109 116E 11B1;C222;1109 116E 11B1; # (숢; 숢; 숢; 숢; 숢; ) HANGUL SYLLABLE SULM +C223;C223;1109 116E 11B2;C223;1109 116E 11B2; # (숣; 숣; 숣; 숣; 숣; ) HANGUL SYLLABLE SULB +C224;C224;1109 116E 11B3;C224;1109 116E 11B3; # (숤; 숤; 숤; 숤; 숤; ) HANGUL SYLLABLE SULS +C225;C225;1109 116E 11B4;C225;1109 116E 11B4; # (숥; 숥; 숥; 숥; 숥; ) HANGUL SYLLABLE SULT +C226;C226;1109 116E 11B5;C226;1109 116E 11B5; # (숦; 숦; 숦; 숦; 숦; ) HANGUL SYLLABLE SULP +C227;C227;1109 116E 11B6;C227;1109 116E 11B6; # (숧; 숧; 숧; 숧; 숧; ) HANGUL SYLLABLE SULH +C228;C228;1109 116E 11B7;C228;1109 116E 11B7; # (숨; 숨; 숨; 숨; 숨; ) HANGUL SYLLABLE SUM +C229;C229;1109 116E 11B8;C229;1109 116E 11B8; # (숩; 숩; 숩; 숩; 숩; ) HANGUL SYLLABLE SUB +C22A;C22A;1109 116E 11B9;C22A;1109 116E 11B9; # (숪; 숪; 숪; 숪; 숪; ) HANGUL SYLLABLE SUBS +C22B;C22B;1109 116E 11BA;C22B;1109 116E 11BA; # (숫; 숫; 숫; 숫; 숫; ) HANGUL SYLLABLE SUS +C22C;C22C;1109 116E 11BB;C22C;1109 116E 11BB; # (숬; 숬; 숬; 숬; 숬; ) HANGUL SYLLABLE SUSS +C22D;C22D;1109 116E 11BC;C22D;1109 116E 11BC; # (숭; 숭; 숭; 숭; 숭; ) HANGUL SYLLABLE SUNG +C22E;C22E;1109 116E 11BD;C22E;1109 116E 11BD; # (숮; 숮; 숮; 숮; 숮; ) HANGUL SYLLABLE SUJ +C22F;C22F;1109 116E 11BE;C22F;1109 116E 11BE; # (숯; 숯; 숯; 숯; 숯; ) HANGUL SYLLABLE SUC +C230;C230;1109 116E 11BF;C230;1109 116E 11BF; # (숰; 숰; 숰; 숰; 숰; ) HANGUL SYLLABLE SUK +C231;C231;1109 116E 11C0;C231;1109 116E 11C0; # (숱; 숱; 숱; 숱; 숱; ) HANGUL SYLLABLE SUT +C232;C232;1109 116E 11C1;C232;1109 116E 11C1; # (숲; 숲; 숲; 숲; 숲; ) HANGUL SYLLABLE SUP +C233;C233;1109 116E 11C2;C233;1109 116E 11C2; # (숳; 숳; 숳; 숳; 숳; ) HANGUL SYLLABLE SUH +C234;C234;1109 116F;C234;1109 116F; # (숴; 숴; 숴; 숴; 숴; ) HANGUL SYLLABLE SWEO +C235;C235;1109 116F 11A8;C235;1109 116F 11A8; # (숵; 숵; 숵; 숵; 숵; ) HANGUL SYLLABLE SWEOG +C236;C236;1109 116F 11A9;C236;1109 116F 11A9; # (숶; 숶; 숶; 숶; 숶; ) HANGUL SYLLABLE SWEOGG +C237;C237;1109 116F 11AA;C237;1109 116F 11AA; # (숷; 숷; 숷; 숷; 숷; ) HANGUL SYLLABLE SWEOGS +C238;C238;1109 116F 11AB;C238;1109 116F 11AB; # (숸; 숸; 숸; 숸; 숸; ) HANGUL SYLLABLE SWEON +C239;C239;1109 116F 11AC;C239;1109 116F 11AC; # (숹; 숹; 숹; 숹; 숹; ) HANGUL SYLLABLE SWEONJ +C23A;C23A;1109 116F 11AD;C23A;1109 116F 11AD; # (숺; 숺; 숺; 숺; 숺; ) HANGUL SYLLABLE SWEONH +C23B;C23B;1109 116F 11AE;C23B;1109 116F 11AE; # (숻; 숻; 숻; 숻; 숻; ) HANGUL SYLLABLE SWEOD +C23C;C23C;1109 116F 11AF;C23C;1109 116F 11AF; # (숼; 숼; 숼; 숼; 숼; ) HANGUL SYLLABLE SWEOL +C23D;C23D;1109 116F 11B0;C23D;1109 116F 11B0; # (숽; 숽; 숽; 숽; 숽; ) HANGUL SYLLABLE SWEOLG +C23E;C23E;1109 116F 11B1;C23E;1109 116F 11B1; # (숾; 숾; 숾; 숾; 숾; ) HANGUL SYLLABLE SWEOLM +C23F;C23F;1109 116F 11B2;C23F;1109 116F 11B2; # (숿; 숿; 숿; 숿; 숿; ) HANGUL SYLLABLE SWEOLB +C240;C240;1109 116F 11B3;C240;1109 116F 11B3; # (쉀; 쉀; 쉀; 쉀; 쉀; ) HANGUL SYLLABLE SWEOLS +C241;C241;1109 116F 11B4;C241;1109 116F 11B4; # (쉁; 쉁; 쉁; 쉁; 쉁; ) HANGUL SYLLABLE SWEOLT +C242;C242;1109 116F 11B5;C242;1109 116F 11B5; # (쉂; 쉂; 쉂; 쉂; 쉂; ) HANGUL SYLLABLE SWEOLP +C243;C243;1109 116F 11B6;C243;1109 116F 11B6; # (쉃; 쉃; 쉃; 쉃; 쉃; ) HANGUL SYLLABLE SWEOLH +C244;C244;1109 116F 11B7;C244;1109 116F 11B7; # (쉄; 쉄; 쉄; 쉄; 쉄; ) HANGUL SYLLABLE SWEOM +C245;C245;1109 116F 11B8;C245;1109 116F 11B8; # (쉅; 쉅; 쉅; 쉅; 쉅; ) HANGUL SYLLABLE SWEOB +C246;C246;1109 116F 11B9;C246;1109 116F 11B9; # (쉆; 쉆; 쉆; 쉆; 쉆; ) HANGUL SYLLABLE SWEOBS +C247;C247;1109 116F 11BA;C247;1109 116F 11BA; # (쉇; 쉇; 쉇; 쉇; 쉇; ) HANGUL SYLLABLE SWEOS +C248;C248;1109 116F 11BB;C248;1109 116F 11BB; # (쉈; 쉈; 쉈; 쉈; 쉈; ) HANGUL SYLLABLE SWEOSS +C249;C249;1109 116F 11BC;C249;1109 116F 11BC; # (쉉; 쉉; 쉉; 쉉; 쉉; ) HANGUL SYLLABLE SWEONG +C24A;C24A;1109 116F 11BD;C24A;1109 116F 11BD; # (쉊; 쉊; 쉊; 쉊; 쉊; ) HANGUL SYLLABLE SWEOJ +C24B;C24B;1109 116F 11BE;C24B;1109 116F 11BE; # (쉋; 쉋; 쉋; 쉋; 쉋; ) HANGUL SYLLABLE SWEOC +C24C;C24C;1109 116F 11BF;C24C;1109 116F 11BF; # (쉌; 쉌; 쉌; 쉌; 쉌; ) HANGUL SYLLABLE SWEOK +C24D;C24D;1109 116F 11C0;C24D;1109 116F 11C0; # (쉍; 쉍; 쉍; 쉍; 쉍; ) HANGUL SYLLABLE SWEOT +C24E;C24E;1109 116F 11C1;C24E;1109 116F 11C1; # (쉎; 쉎; 쉎; 쉎; 쉎; ) HANGUL SYLLABLE SWEOP +C24F;C24F;1109 116F 11C2;C24F;1109 116F 11C2; # (쉏; 쉏; 쉏; 쉏; 쉏; ) HANGUL SYLLABLE SWEOH +C250;C250;1109 1170;C250;1109 1170; # (쉐; 쉐; 쉐; 쉐; 쉐; ) HANGUL SYLLABLE SWE +C251;C251;1109 1170 11A8;C251;1109 1170 11A8; # (쉑; 쉑; 쉑; 쉑; 쉑; ) HANGUL SYLLABLE SWEG +C252;C252;1109 1170 11A9;C252;1109 1170 11A9; # (쉒; 쉒; 쉒; 쉒; 쉒; ) HANGUL SYLLABLE SWEGG +C253;C253;1109 1170 11AA;C253;1109 1170 11AA; # (쉓; 쉓; 쉓; 쉓; 쉓; ) HANGUL SYLLABLE SWEGS +C254;C254;1109 1170 11AB;C254;1109 1170 11AB; # (쉔; 쉔; 쉔; 쉔; 쉔; ) HANGUL SYLLABLE SWEN +C255;C255;1109 1170 11AC;C255;1109 1170 11AC; # (쉕; 쉕; 쉕; 쉕; 쉕; ) HANGUL SYLLABLE SWENJ +C256;C256;1109 1170 11AD;C256;1109 1170 11AD; # (쉖; 쉖; 쉖; 쉖; 쉖; ) HANGUL SYLLABLE SWENH +C257;C257;1109 1170 11AE;C257;1109 1170 11AE; # (쉗; 쉗; 쉗; 쉗; 쉗; ) HANGUL SYLLABLE SWED +C258;C258;1109 1170 11AF;C258;1109 1170 11AF; # (쉘; 쉘; 쉘; 쉘; 쉘; ) HANGUL SYLLABLE SWEL +C259;C259;1109 1170 11B0;C259;1109 1170 11B0; # (쉙; 쉙; 쉙; 쉙; 쉙; ) HANGUL SYLLABLE SWELG +C25A;C25A;1109 1170 11B1;C25A;1109 1170 11B1; # (쉚; 쉚; 쉚; 쉚; 쉚; ) HANGUL SYLLABLE SWELM +C25B;C25B;1109 1170 11B2;C25B;1109 1170 11B2; # (쉛; 쉛; 쉛; 쉛; 쉛; ) HANGUL SYLLABLE SWELB +C25C;C25C;1109 1170 11B3;C25C;1109 1170 11B3; # (쉜; 쉜; 쉜; 쉜; 쉜; ) HANGUL SYLLABLE SWELS +C25D;C25D;1109 1170 11B4;C25D;1109 1170 11B4; # (쉝; 쉝; 쉝; 쉝; 쉝; ) HANGUL SYLLABLE SWELT +C25E;C25E;1109 1170 11B5;C25E;1109 1170 11B5; # (쉞; 쉞; 쉞; 쉞; 쉞; ) HANGUL SYLLABLE SWELP +C25F;C25F;1109 1170 11B6;C25F;1109 1170 11B6; # (쉟; 쉟; 쉟; 쉟; 쉟; ) HANGUL SYLLABLE SWELH +C260;C260;1109 1170 11B7;C260;1109 1170 11B7; # (쉠; 쉠; 쉠; 쉠; 쉠; ) HANGUL SYLLABLE SWEM +C261;C261;1109 1170 11B8;C261;1109 1170 11B8; # (쉡; 쉡; 쉡; 쉡; 쉡; ) HANGUL SYLLABLE SWEB +C262;C262;1109 1170 11B9;C262;1109 1170 11B9; # (쉢; 쉢; 쉢; 쉢; 쉢; ) HANGUL SYLLABLE SWEBS +C263;C263;1109 1170 11BA;C263;1109 1170 11BA; # (쉣; 쉣; 쉣; 쉣; 쉣; ) HANGUL SYLLABLE SWES +C264;C264;1109 1170 11BB;C264;1109 1170 11BB; # (쉤; 쉤; 쉤; 쉤; 쉤; ) HANGUL SYLLABLE SWESS +C265;C265;1109 1170 11BC;C265;1109 1170 11BC; # (쉥; 쉥; 쉥; 쉥; 쉥; ) HANGUL SYLLABLE SWENG +C266;C266;1109 1170 11BD;C266;1109 1170 11BD; # (쉦; 쉦; 쉦; 쉦; 쉦; ) HANGUL SYLLABLE SWEJ +C267;C267;1109 1170 11BE;C267;1109 1170 11BE; # (쉧; 쉧; 쉧; 쉧; 쉧; ) HANGUL SYLLABLE SWEC +C268;C268;1109 1170 11BF;C268;1109 1170 11BF; # (쉨; 쉨; 쉨; 쉨; 쉨; ) HANGUL SYLLABLE SWEK +C269;C269;1109 1170 11C0;C269;1109 1170 11C0; # (쉩; 쉩; 쉩; 쉩; 쉩; ) HANGUL SYLLABLE SWET +C26A;C26A;1109 1170 11C1;C26A;1109 1170 11C1; # (쉪; 쉪; 쉪; 쉪; 쉪; ) HANGUL SYLLABLE SWEP +C26B;C26B;1109 1170 11C2;C26B;1109 1170 11C2; # (쉫; 쉫; 쉫; 쉫; 쉫; ) HANGUL SYLLABLE SWEH +C26C;C26C;1109 1171;C26C;1109 1171; # (쉬; 쉬; 쉬; 쉬; 쉬; ) HANGUL SYLLABLE SWI +C26D;C26D;1109 1171 11A8;C26D;1109 1171 11A8; # (쉭; 쉭; 쉭; 쉭; 쉭; ) HANGUL SYLLABLE SWIG +C26E;C26E;1109 1171 11A9;C26E;1109 1171 11A9; # (쉮; 쉮; 쉮; 쉮; 쉮; ) HANGUL SYLLABLE SWIGG +C26F;C26F;1109 1171 11AA;C26F;1109 1171 11AA; # (쉯; 쉯; 쉯; 쉯; 쉯; ) HANGUL SYLLABLE SWIGS +C270;C270;1109 1171 11AB;C270;1109 1171 11AB; # (쉰; 쉰; 쉰; 쉰; 쉰; ) HANGUL SYLLABLE SWIN +C271;C271;1109 1171 11AC;C271;1109 1171 11AC; # (쉱; 쉱; 쉱; 쉱; 쉱; ) HANGUL SYLLABLE SWINJ +C272;C272;1109 1171 11AD;C272;1109 1171 11AD; # (쉲; 쉲; 쉲; 쉲; 쉲; ) HANGUL SYLLABLE SWINH +C273;C273;1109 1171 11AE;C273;1109 1171 11AE; # (쉳; 쉳; 쉳; 쉳; 쉳; ) HANGUL SYLLABLE SWID +C274;C274;1109 1171 11AF;C274;1109 1171 11AF; # (쉴; 쉴; 쉴; 쉴; 쉴; ) HANGUL SYLLABLE SWIL +C275;C275;1109 1171 11B0;C275;1109 1171 11B0; # (쉵; 쉵; 쉵; 쉵; 쉵; ) HANGUL SYLLABLE SWILG +C276;C276;1109 1171 11B1;C276;1109 1171 11B1; # (쉶; 쉶; 쉶; 쉶; 쉶; ) HANGUL SYLLABLE SWILM +C277;C277;1109 1171 11B2;C277;1109 1171 11B2; # (쉷; 쉷; 쉷; 쉷; 쉷; ) HANGUL SYLLABLE SWILB +C278;C278;1109 1171 11B3;C278;1109 1171 11B3; # (쉸; 쉸; 쉸; 쉸; 쉸; ) HANGUL SYLLABLE SWILS +C279;C279;1109 1171 11B4;C279;1109 1171 11B4; # (쉹; 쉹; 쉹; 쉹; 쉹; ) HANGUL SYLLABLE SWILT +C27A;C27A;1109 1171 11B5;C27A;1109 1171 11B5; # (쉺; 쉺; 쉺; 쉺; 쉺; ) HANGUL SYLLABLE SWILP +C27B;C27B;1109 1171 11B6;C27B;1109 1171 11B6; # (쉻; 쉻; 쉻; 쉻; 쉻; ) HANGUL SYLLABLE SWILH +C27C;C27C;1109 1171 11B7;C27C;1109 1171 11B7; # (쉼; 쉼; 쉼; 쉼; 쉼; ) HANGUL SYLLABLE SWIM +C27D;C27D;1109 1171 11B8;C27D;1109 1171 11B8; # (쉽; 쉽; 쉽; 쉽; 쉽; ) HANGUL SYLLABLE SWIB +C27E;C27E;1109 1171 11B9;C27E;1109 1171 11B9; # (쉾; 쉾; 쉾; 쉾; 쉾; ) HANGUL SYLLABLE SWIBS +C27F;C27F;1109 1171 11BA;C27F;1109 1171 11BA; # (쉿; 쉿; 쉿; 쉿; 쉿; ) HANGUL SYLLABLE SWIS +C280;C280;1109 1171 11BB;C280;1109 1171 11BB; # (슀; 슀; 슀; 슀; 슀; ) HANGUL SYLLABLE SWISS +C281;C281;1109 1171 11BC;C281;1109 1171 11BC; # (슁; 슁; 슁; 슁; 슁; ) HANGUL SYLLABLE SWING +C282;C282;1109 1171 11BD;C282;1109 1171 11BD; # (슂; 슂; 슂; 슂; 슂; ) HANGUL SYLLABLE SWIJ +C283;C283;1109 1171 11BE;C283;1109 1171 11BE; # (슃; 슃; 슃; 슃; 슃; ) HANGUL SYLLABLE SWIC +C284;C284;1109 1171 11BF;C284;1109 1171 11BF; # (슄; 슄; 슄; 슄; 슄; ) HANGUL SYLLABLE SWIK +C285;C285;1109 1171 11C0;C285;1109 1171 11C0; # (슅; 슅; 슅; 슅; 슅; ) HANGUL SYLLABLE SWIT +C286;C286;1109 1171 11C1;C286;1109 1171 11C1; # (슆; 슆; 슆; 슆; 슆; ) HANGUL SYLLABLE SWIP +C287;C287;1109 1171 11C2;C287;1109 1171 11C2; # (슇; 슇; 슇; 슇; 슇; ) HANGUL SYLLABLE SWIH +C288;C288;1109 1172;C288;1109 1172; # (슈; 슈; 슈; 슈; 슈; ) HANGUL SYLLABLE SYU +C289;C289;1109 1172 11A8;C289;1109 1172 11A8; # (슉; 슉; 슉; 슉; 슉; ) HANGUL SYLLABLE SYUG +C28A;C28A;1109 1172 11A9;C28A;1109 1172 11A9; # (슊; 슊; 슊; 슊; 슊; ) HANGUL SYLLABLE SYUGG +C28B;C28B;1109 1172 11AA;C28B;1109 1172 11AA; # (슋; 슋; 슋; 슋; 슋; ) HANGUL SYLLABLE SYUGS +C28C;C28C;1109 1172 11AB;C28C;1109 1172 11AB; # (슌; 슌; 슌; 슌; 슌; ) HANGUL SYLLABLE SYUN +C28D;C28D;1109 1172 11AC;C28D;1109 1172 11AC; # (슍; 슍; 슍; 슍; 슍; ) HANGUL SYLLABLE SYUNJ +C28E;C28E;1109 1172 11AD;C28E;1109 1172 11AD; # (슎; 슎; 슎; 슎; 슎; ) HANGUL SYLLABLE SYUNH +C28F;C28F;1109 1172 11AE;C28F;1109 1172 11AE; # (슏; 슏; 슏; 슏; 슏; ) HANGUL SYLLABLE SYUD +C290;C290;1109 1172 11AF;C290;1109 1172 11AF; # (슐; 슐; 슐; 슐; 슐; ) HANGUL SYLLABLE SYUL +C291;C291;1109 1172 11B0;C291;1109 1172 11B0; # (슑; 슑; 슑; 슑; 슑; ) HANGUL SYLLABLE SYULG +C292;C292;1109 1172 11B1;C292;1109 1172 11B1; # (슒; 슒; 슒; 슒; 슒; ) HANGUL SYLLABLE SYULM +C293;C293;1109 1172 11B2;C293;1109 1172 11B2; # (슓; 슓; 슓; 슓; 슓; ) HANGUL SYLLABLE SYULB +C294;C294;1109 1172 11B3;C294;1109 1172 11B3; # (슔; 슔; 슔; 슔; 슔; ) HANGUL SYLLABLE SYULS +C295;C295;1109 1172 11B4;C295;1109 1172 11B4; # (슕; 슕; 슕; 슕; 슕; ) HANGUL SYLLABLE SYULT +C296;C296;1109 1172 11B5;C296;1109 1172 11B5; # (슖; 슖; 슖; 슖; 슖; ) HANGUL SYLLABLE SYULP +C297;C297;1109 1172 11B6;C297;1109 1172 11B6; # (슗; 슗; 슗; 슗; 슗; ) HANGUL SYLLABLE SYULH +C298;C298;1109 1172 11B7;C298;1109 1172 11B7; # (슘; 슘; 슘; 슘; 슘; ) HANGUL SYLLABLE SYUM +C299;C299;1109 1172 11B8;C299;1109 1172 11B8; # (슙; 슙; 슙; 슙; 슙; ) HANGUL SYLLABLE SYUB +C29A;C29A;1109 1172 11B9;C29A;1109 1172 11B9; # (슚; 슚; 슚; 슚; 슚; ) HANGUL SYLLABLE SYUBS +C29B;C29B;1109 1172 11BA;C29B;1109 1172 11BA; # (슛; 슛; 슛; 슛; 슛; ) HANGUL SYLLABLE SYUS +C29C;C29C;1109 1172 11BB;C29C;1109 1172 11BB; # (슜; 슜; 슜; 슜; 슜; ) HANGUL SYLLABLE SYUSS +C29D;C29D;1109 1172 11BC;C29D;1109 1172 11BC; # (슝; 슝; 슝; 슝; 슝; ) HANGUL SYLLABLE SYUNG +C29E;C29E;1109 1172 11BD;C29E;1109 1172 11BD; # (슞; 슞; 슞; 슞; 슞; ) HANGUL SYLLABLE SYUJ +C29F;C29F;1109 1172 11BE;C29F;1109 1172 11BE; # (슟; 슟; 슟; 슟; 슟; ) HANGUL SYLLABLE SYUC +C2A0;C2A0;1109 1172 11BF;C2A0;1109 1172 11BF; # (슠; 슠; 슠; 슠; 슠; ) HANGUL SYLLABLE SYUK +C2A1;C2A1;1109 1172 11C0;C2A1;1109 1172 11C0; # (슡; 슡; 슡; 슡; 슡; ) HANGUL SYLLABLE SYUT +C2A2;C2A2;1109 1172 11C1;C2A2;1109 1172 11C1; # (슢; 슢; 슢; 슢; 슢; ) HANGUL SYLLABLE SYUP +C2A3;C2A3;1109 1172 11C2;C2A3;1109 1172 11C2; # (슣; 슣; 슣; 슣; 슣; ) HANGUL SYLLABLE SYUH +C2A4;C2A4;1109 1173;C2A4;1109 1173; # (스; 스; 스; 스; 스; ) HANGUL SYLLABLE SEU +C2A5;C2A5;1109 1173 11A8;C2A5;1109 1173 11A8; # (슥; 슥; 슥; 슥; 슥; ) HANGUL SYLLABLE SEUG +C2A6;C2A6;1109 1173 11A9;C2A6;1109 1173 11A9; # (슦; 슦; 슦; 슦; 슦; ) HANGUL SYLLABLE SEUGG +C2A7;C2A7;1109 1173 11AA;C2A7;1109 1173 11AA; # (슧; 슧; 슧; 슧; 슧; ) HANGUL SYLLABLE SEUGS +C2A8;C2A8;1109 1173 11AB;C2A8;1109 1173 11AB; # (슨; 슨; 슨; 슨; 슨; ) HANGUL SYLLABLE SEUN +C2A9;C2A9;1109 1173 11AC;C2A9;1109 1173 11AC; # (슩; 슩; 슩; 슩; 슩; ) HANGUL SYLLABLE SEUNJ +C2AA;C2AA;1109 1173 11AD;C2AA;1109 1173 11AD; # (슪; 슪; 슪; 슪; 슪; ) HANGUL SYLLABLE SEUNH +C2AB;C2AB;1109 1173 11AE;C2AB;1109 1173 11AE; # (슫; 슫; 슫; 슫; 슫; ) HANGUL SYLLABLE SEUD +C2AC;C2AC;1109 1173 11AF;C2AC;1109 1173 11AF; # (슬; 슬; 슬; 슬; 슬; ) HANGUL SYLLABLE SEUL +C2AD;C2AD;1109 1173 11B0;C2AD;1109 1173 11B0; # (슭; 슭; 슭; 슭; 슭; ) HANGUL SYLLABLE SEULG +C2AE;C2AE;1109 1173 11B1;C2AE;1109 1173 11B1; # (슮; 슮; 슮; 슮; 슮; ) HANGUL SYLLABLE SEULM +C2AF;C2AF;1109 1173 11B2;C2AF;1109 1173 11B2; # (슯; 슯; 슯; 슯; 슯; ) HANGUL SYLLABLE SEULB +C2B0;C2B0;1109 1173 11B3;C2B0;1109 1173 11B3; # (슰; 슰; 슰; 슰; 슰; ) HANGUL SYLLABLE SEULS +C2B1;C2B1;1109 1173 11B4;C2B1;1109 1173 11B4; # (슱; 슱; 슱; 슱; 슱; ) HANGUL SYLLABLE SEULT +C2B2;C2B2;1109 1173 11B5;C2B2;1109 1173 11B5; # (슲; 슲; 슲; 슲; 슲; ) HANGUL SYLLABLE SEULP +C2B3;C2B3;1109 1173 11B6;C2B3;1109 1173 11B6; # (슳; 슳; 슳; 슳; 슳; ) HANGUL SYLLABLE SEULH +C2B4;C2B4;1109 1173 11B7;C2B4;1109 1173 11B7; # (슴; 슴; 슴; 슴; 슴; ) HANGUL SYLLABLE SEUM +C2B5;C2B5;1109 1173 11B8;C2B5;1109 1173 11B8; # (습; 습; 습; 습; 습; ) HANGUL SYLLABLE SEUB +C2B6;C2B6;1109 1173 11B9;C2B6;1109 1173 11B9; # (슶; 슶; 슶; 슶; 슶; ) HANGUL SYLLABLE SEUBS +C2B7;C2B7;1109 1173 11BA;C2B7;1109 1173 11BA; # (슷; 슷; 슷; 슷; 슷; ) HANGUL SYLLABLE SEUS +C2B8;C2B8;1109 1173 11BB;C2B8;1109 1173 11BB; # (슸; 슸; 슸; 슸; 슸; ) HANGUL SYLLABLE SEUSS +C2B9;C2B9;1109 1173 11BC;C2B9;1109 1173 11BC; # (승; 승; 승; 승; 승; ) HANGUL SYLLABLE SEUNG +C2BA;C2BA;1109 1173 11BD;C2BA;1109 1173 11BD; # (슺; 슺; 슺; 슺; 슺; ) HANGUL SYLLABLE SEUJ +C2BB;C2BB;1109 1173 11BE;C2BB;1109 1173 11BE; # (슻; 슻; 슻; 슻; 슻; ) HANGUL SYLLABLE SEUC +C2BC;C2BC;1109 1173 11BF;C2BC;1109 1173 11BF; # (슼; 슼; 슼; 슼; 슼; ) HANGUL SYLLABLE SEUK +C2BD;C2BD;1109 1173 11C0;C2BD;1109 1173 11C0; # (슽; 슽; 슽; 슽; 슽; ) HANGUL SYLLABLE SEUT +C2BE;C2BE;1109 1173 11C1;C2BE;1109 1173 11C1; # (슾; 슾; 슾; 슾; 슾; ) HANGUL SYLLABLE SEUP +C2BF;C2BF;1109 1173 11C2;C2BF;1109 1173 11C2; # (슿; 슿; 슿; 슿; 슿; ) HANGUL SYLLABLE SEUH +C2C0;C2C0;1109 1174;C2C0;1109 1174; # (싀; 싀; 싀; 싀; 싀; ) HANGUL SYLLABLE SYI +C2C1;C2C1;1109 1174 11A8;C2C1;1109 1174 11A8; # (싁; 싁; 싁; 싁; 싁; ) HANGUL SYLLABLE SYIG +C2C2;C2C2;1109 1174 11A9;C2C2;1109 1174 11A9; # (싂; 싂; 싂; 싂; 싂; ) HANGUL SYLLABLE SYIGG +C2C3;C2C3;1109 1174 11AA;C2C3;1109 1174 11AA; # (싃; 싃; 싃; 싃; 싃; ) HANGUL SYLLABLE SYIGS +C2C4;C2C4;1109 1174 11AB;C2C4;1109 1174 11AB; # (싄; 싄; 싄; 싄; 싄; ) HANGUL SYLLABLE SYIN +C2C5;C2C5;1109 1174 11AC;C2C5;1109 1174 11AC; # (싅; 싅; 싅; 싅; 싅; ) HANGUL SYLLABLE SYINJ +C2C6;C2C6;1109 1174 11AD;C2C6;1109 1174 11AD; # (싆; 싆; 싆; 싆; 싆; ) HANGUL SYLLABLE SYINH +C2C7;C2C7;1109 1174 11AE;C2C7;1109 1174 11AE; # (싇; 싇; 싇; 싇; 싇; ) HANGUL SYLLABLE SYID +C2C8;C2C8;1109 1174 11AF;C2C8;1109 1174 11AF; # (싈; 싈; 싈; 싈; 싈; ) HANGUL SYLLABLE SYIL +C2C9;C2C9;1109 1174 11B0;C2C9;1109 1174 11B0; # (싉; 싉; 싉; 싉; 싉; ) HANGUL SYLLABLE SYILG +C2CA;C2CA;1109 1174 11B1;C2CA;1109 1174 11B1; # (싊; 싊; 싊; 싊; 싊; ) HANGUL SYLLABLE SYILM +C2CB;C2CB;1109 1174 11B2;C2CB;1109 1174 11B2; # (싋; 싋; 싋; 싋; 싋; ) HANGUL SYLLABLE SYILB +C2CC;C2CC;1109 1174 11B3;C2CC;1109 1174 11B3; # (싌; 싌; 싌; 싌; 싌; ) HANGUL SYLLABLE SYILS +C2CD;C2CD;1109 1174 11B4;C2CD;1109 1174 11B4; # (싍; 싍; 싍; 싍; 싍; ) HANGUL SYLLABLE SYILT +C2CE;C2CE;1109 1174 11B5;C2CE;1109 1174 11B5; # (싎; 싎; 싎; 싎; 싎; ) HANGUL SYLLABLE SYILP +C2CF;C2CF;1109 1174 11B6;C2CF;1109 1174 11B6; # (싏; 싏; 싏; 싏; 싏; ) HANGUL SYLLABLE SYILH +C2D0;C2D0;1109 1174 11B7;C2D0;1109 1174 11B7; # (싐; 싐; 싐; 싐; 싐; ) HANGUL SYLLABLE SYIM +C2D1;C2D1;1109 1174 11B8;C2D1;1109 1174 11B8; # (싑; 싑; 싑; 싑; 싑; ) HANGUL SYLLABLE SYIB +C2D2;C2D2;1109 1174 11B9;C2D2;1109 1174 11B9; # (싒; 싒; 싒; 싒; 싒; ) HANGUL SYLLABLE SYIBS +C2D3;C2D3;1109 1174 11BA;C2D3;1109 1174 11BA; # (싓; 싓; 싓; 싓; 싓; ) HANGUL SYLLABLE SYIS +C2D4;C2D4;1109 1174 11BB;C2D4;1109 1174 11BB; # (싔; 싔; 싔; 싔; 싔; ) HANGUL SYLLABLE SYISS +C2D5;C2D5;1109 1174 11BC;C2D5;1109 1174 11BC; # (싕; 싕; 싕; 싕; 싕; ) HANGUL SYLLABLE SYING +C2D6;C2D6;1109 1174 11BD;C2D6;1109 1174 11BD; # (싖; 싖; 싖; 싖; 싖; ) HANGUL SYLLABLE SYIJ +C2D7;C2D7;1109 1174 11BE;C2D7;1109 1174 11BE; # (싗; 싗; 싗; 싗; 싗; ) HANGUL SYLLABLE SYIC +C2D8;C2D8;1109 1174 11BF;C2D8;1109 1174 11BF; # (싘; 싘; 싘; 싘; 싘; ) HANGUL SYLLABLE SYIK +C2D9;C2D9;1109 1174 11C0;C2D9;1109 1174 11C0; # (싙; 싙; 싙; 싙; 싙; ) HANGUL SYLLABLE SYIT +C2DA;C2DA;1109 1174 11C1;C2DA;1109 1174 11C1; # (싚; 싚; 싚; 싚; 싚; ) HANGUL SYLLABLE SYIP +C2DB;C2DB;1109 1174 11C2;C2DB;1109 1174 11C2; # (싛; 싛; 싛; 싛; 싛; ) HANGUL SYLLABLE SYIH +C2DC;C2DC;1109 1175;C2DC;1109 1175; # (시; 시; 시; 시; 시; ) HANGUL SYLLABLE SI +C2DD;C2DD;1109 1175 11A8;C2DD;1109 1175 11A8; # (식; 식; 식; 식; 식; ) HANGUL SYLLABLE SIG +C2DE;C2DE;1109 1175 11A9;C2DE;1109 1175 11A9; # (싞; 싞; 싞; 싞; 싞; ) HANGUL SYLLABLE SIGG +C2DF;C2DF;1109 1175 11AA;C2DF;1109 1175 11AA; # (싟; 싟; 싟; 싟; 싟; ) HANGUL SYLLABLE SIGS +C2E0;C2E0;1109 1175 11AB;C2E0;1109 1175 11AB; # (신; 신; 신; 신; 신; ) HANGUL SYLLABLE SIN +C2E1;C2E1;1109 1175 11AC;C2E1;1109 1175 11AC; # (싡; 싡; 싡; 싡; 싡; ) HANGUL SYLLABLE SINJ +C2E2;C2E2;1109 1175 11AD;C2E2;1109 1175 11AD; # (싢; 싢; 싢; 싢; 싢; ) HANGUL SYLLABLE SINH +C2E3;C2E3;1109 1175 11AE;C2E3;1109 1175 11AE; # (싣; 싣; 싣; 싣; 싣; ) HANGUL SYLLABLE SID +C2E4;C2E4;1109 1175 11AF;C2E4;1109 1175 11AF; # (실; 실; 실; 실; 실; ) HANGUL SYLLABLE SIL +C2E5;C2E5;1109 1175 11B0;C2E5;1109 1175 11B0; # (싥; 싥; 싥; 싥; 싥; ) HANGUL SYLLABLE SILG +C2E6;C2E6;1109 1175 11B1;C2E6;1109 1175 11B1; # (싦; 싦; 싦; 싦; 싦; ) HANGUL SYLLABLE SILM +C2E7;C2E7;1109 1175 11B2;C2E7;1109 1175 11B2; # (싧; 싧; 싧; 싧; 싧; ) HANGUL SYLLABLE SILB +C2E8;C2E8;1109 1175 11B3;C2E8;1109 1175 11B3; # (싨; 싨; 싨; 싨; 싨; ) HANGUL SYLLABLE SILS +C2E9;C2E9;1109 1175 11B4;C2E9;1109 1175 11B4; # (싩; 싩; 싩; 싩; 싩; ) HANGUL SYLLABLE SILT +C2EA;C2EA;1109 1175 11B5;C2EA;1109 1175 11B5; # (싪; 싪; 싪; 싪; 싪; ) HANGUL SYLLABLE SILP +C2EB;C2EB;1109 1175 11B6;C2EB;1109 1175 11B6; # (싫; 싫; 싫; 싫; 싫; ) HANGUL SYLLABLE SILH +C2EC;C2EC;1109 1175 11B7;C2EC;1109 1175 11B7; # (심; 심; 심; 심; 심; ) HANGUL SYLLABLE SIM +C2ED;C2ED;1109 1175 11B8;C2ED;1109 1175 11B8; # (십; 십; 십; 십; 십; ) HANGUL SYLLABLE SIB +C2EE;C2EE;1109 1175 11B9;C2EE;1109 1175 11B9; # (싮; 싮; 싮; 싮; 싮; ) HANGUL SYLLABLE SIBS +C2EF;C2EF;1109 1175 11BA;C2EF;1109 1175 11BA; # (싯; 싯; 싯; 싯; 싯; ) HANGUL SYLLABLE SIS +C2F0;C2F0;1109 1175 11BB;C2F0;1109 1175 11BB; # (싰; 싰; 싰; 싰; 싰; ) HANGUL SYLLABLE SISS +C2F1;C2F1;1109 1175 11BC;C2F1;1109 1175 11BC; # (싱; 싱; 싱; 싱; 싱; ) HANGUL SYLLABLE SING +C2F2;C2F2;1109 1175 11BD;C2F2;1109 1175 11BD; # (싲; 싲; 싲; 싲; 싲; ) HANGUL SYLLABLE SIJ +C2F3;C2F3;1109 1175 11BE;C2F3;1109 1175 11BE; # (싳; 싳; 싳; 싳; 싳; ) HANGUL SYLLABLE SIC +C2F4;C2F4;1109 1175 11BF;C2F4;1109 1175 11BF; # (싴; 싴; 싴; 싴; 싴; ) HANGUL SYLLABLE SIK +C2F5;C2F5;1109 1175 11C0;C2F5;1109 1175 11C0; # (싵; 싵; 싵; 싵; 싵; ) HANGUL SYLLABLE SIT +C2F6;C2F6;1109 1175 11C1;C2F6;1109 1175 11C1; # (싶; 싶; 싶; 싶; 싶; ) HANGUL SYLLABLE SIP +C2F7;C2F7;1109 1175 11C2;C2F7;1109 1175 11C2; # (싷; 싷; 싷; 싷; 싷; ) HANGUL SYLLABLE SIH +C2F8;C2F8;110A 1161;C2F8;110A 1161; # (싸; 싸; 싸; 싸; 싸; ) HANGUL SYLLABLE SSA +C2F9;C2F9;110A 1161 11A8;C2F9;110A 1161 11A8; # (싹; 싹; 싹; 싹; 싹; ) HANGUL SYLLABLE SSAG +C2FA;C2FA;110A 1161 11A9;C2FA;110A 1161 11A9; # (싺; 싺; 싺; 싺; 싺; ) HANGUL SYLLABLE SSAGG +C2FB;C2FB;110A 1161 11AA;C2FB;110A 1161 11AA; # (싻; 싻; 싻; 싻; 싻; ) HANGUL SYLLABLE SSAGS +C2FC;C2FC;110A 1161 11AB;C2FC;110A 1161 11AB; # (싼; 싼; 싼; 싼; 싼; ) HANGUL SYLLABLE SSAN +C2FD;C2FD;110A 1161 11AC;C2FD;110A 1161 11AC; # (싽; 싽; 싽; 싽; 싽; ) HANGUL SYLLABLE SSANJ +C2FE;C2FE;110A 1161 11AD;C2FE;110A 1161 11AD; # (싾; 싾; 싾; 싾; 싾; ) HANGUL SYLLABLE SSANH +C2FF;C2FF;110A 1161 11AE;C2FF;110A 1161 11AE; # (싿; 싿; 싿; 싿; 싿; ) HANGUL SYLLABLE SSAD +C300;C300;110A 1161 11AF;C300;110A 1161 11AF; # (쌀; 쌀; 쌀; 쌀; 쌀; ) HANGUL SYLLABLE SSAL +C301;C301;110A 1161 11B0;C301;110A 1161 11B0; # (쌁; 쌁; 쌁; 쌁; 쌁; ) HANGUL SYLLABLE SSALG +C302;C302;110A 1161 11B1;C302;110A 1161 11B1; # (쌂; 쌂; 쌂; 쌂; 쌂; ) HANGUL SYLLABLE SSALM +C303;C303;110A 1161 11B2;C303;110A 1161 11B2; # (쌃; 쌃; 쌃; 쌃; 쌃; ) HANGUL SYLLABLE SSALB +C304;C304;110A 1161 11B3;C304;110A 1161 11B3; # (쌄; 쌄; 쌄; 쌄; 쌄; ) HANGUL SYLLABLE SSALS +C305;C305;110A 1161 11B4;C305;110A 1161 11B4; # (쌅; 쌅; 쌅; 쌅; 쌅; ) HANGUL SYLLABLE SSALT +C306;C306;110A 1161 11B5;C306;110A 1161 11B5; # (쌆; 쌆; 쌆; 쌆; 쌆; ) HANGUL SYLLABLE SSALP +C307;C307;110A 1161 11B6;C307;110A 1161 11B6; # (쌇; 쌇; 쌇; 쌇; 쌇; ) HANGUL SYLLABLE SSALH +C308;C308;110A 1161 11B7;C308;110A 1161 11B7; # (쌈; 쌈; 쌈; 쌈; 쌈; ) HANGUL SYLLABLE SSAM +C309;C309;110A 1161 11B8;C309;110A 1161 11B8; # (쌉; 쌉; 쌉; 쌉; 쌉; ) HANGUL SYLLABLE SSAB +C30A;C30A;110A 1161 11B9;C30A;110A 1161 11B9; # (쌊; 쌊; 쌊; 쌊; 쌊; ) HANGUL SYLLABLE SSABS +C30B;C30B;110A 1161 11BA;C30B;110A 1161 11BA; # (쌋; 쌋; 쌋; 쌋; 쌋; ) HANGUL SYLLABLE SSAS +C30C;C30C;110A 1161 11BB;C30C;110A 1161 11BB; # (쌌; 쌌; 쌌; 쌌; 쌌; ) HANGUL SYLLABLE SSASS +C30D;C30D;110A 1161 11BC;C30D;110A 1161 11BC; # (쌍; 쌍; 쌍; 쌍; 쌍; ) HANGUL SYLLABLE SSANG +C30E;C30E;110A 1161 11BD;C30E;110A 1161 11BD; # (쌎; 쌎; 쌎; 쌎; 쌎; ) HANGUL SYLLABLE SSAJ +C30F;C30F;110A 1161 11BE;C30F;110A 1161 11BE; # (쌏; 쌏; 쌏; 쌏; 쌏; ) HANGUL SYLLABLE SSAC +C310;C310;110A 1161 11BF;C310;110A 1161 11BF; # (쌐; 쌐; 쌐; 쌐; 쌐; ) HANGUL SYLLABLE SSAK +C311;C311;110A 1161 11C0;C311;110A 1161 11C0; # (쌑; 쌑; 쌑; 쌑; 쌑; ) HANGUL SYLLABLE SSAT +C312;C312;110A 1161 11C1;C312;110A 1161 11C1; # (쌒; 쌒; 쌒; 쌒; 쌒; ) HANGUL SYLLABLE SSAP +C313;C313;110A 1161 11C2;C313;110A 1161 11C2; # (쌓; 쌓; 쌓; 쌓; 쌓; ) HANGUL SYLLABLE SSAH +C314;C314;110A 1162;C314;110A 1162; # (쌔; 쌔; 쌔; 쌔; 쌔; ) HANGUL SYLLABLE SSAE +C315;C315;110A 1162 11A8;C315;110A 1162 11A8; # (쌕; 쌕; 쌕; 쌕; 쌕; ) HANGUL SYLLABLE SSAEG +C316;C316;110A 1162 11A9;C316;110A 1162 11A9; # (쌖; 쌖; 쌖; 쌖; 쌖; ) HANGUL SYLLABLE SSAEGG +C317;C317;110A 1162 11AA;C317;110A 1162 11AA; # (쌗; 쌗; 쌗; 쌗; 쌗; ) HANGUL SYLLABLE SSAEGS +C318;C318;110A 1162 11AB;C318;110A 1162 11AB; # (쌘; 쌘; 쌘; 쌘; 쌘; ) HANGUL SYLLABLE SSAEN +C319;C319;110A 1162 11AC;C319;110A 1162 11AC; # (쌙; 쌙; 쌙; 쌙; 쌙; ) HANGUL SYLLABLE SSAENJ +C31A;C31A;110A 1162 11AD;C31A;110A 1162 11AD; # (쌚; 쌚; 쌚; 쌚; 쌚; ) HANGUL SYLLABLE SSAENH +C31B;C31B;110A 1162 11AE;C31B;110A 1162 11AE; # (쌛; 쌛; 쌛; 쌛; 쌛; ) HANGUL SYLLABLE SSAED +C31C;C31C;110A 1162 11AF;C31C;110A 1162 11AF; # (쌜; 쌜; 쌜; 쌜; 쌜; ) HANGUL SYLLABLE SSAEL +C31D;C31D;110A 1162 11B0;C31D;110A 1162 11B0; # (쌝; 쌝; 쌝; 쌝; 쌝; ) HANGUL SYLLABLE SSAELG +C31E;C31E;110A 1162 11B1;C31E;110A 1162 11B1; # (쌞; 쌞; 쌞; 쌞; 쌞; ) HANGUL SYLLABLE SSAELM +C31F;C31F;110A 1162 11B2;C31F;110A 1162 11B2; # (쌟; 쌟; 쌟; 쌟; 쌟; ) HANGUL SYLLABLE SSAELB +C320;C320;110A 1162 11B3;C320;110A 1162 11B3; # (쌠; 쌠; 쌠; 쌠; 쌠; ) HANGUL SYLLABLE SSAELS +C321;C321;110A 1162 11B4;C321;110A 1162 11B4; # (쌡; 쌡; 쌡; 쌡; 쌡; ) HANGUL SYLLABLE SSAELT +C322;C322;110A 1162 11B5;C322;110A 1162 11B5; # (쌢; 쌢; 쌢; 쌢; 쌢; ) HANGUL SYLLABLE SSAELP +C323;C323;110A 1162 11B6;C323;110A 1162 11B6; # (쌣; 쌣; 쌣; 쌣; 쌣; ) HANGUL SYLLABLE SSAELH +C324;C324;110A 1162 11B7;C324;110A 1162 11B7; # (쌤; 쌤; 쌤; 쌤; 쌤; ) HANGUL SYLLABLE SSAEM +C325;C325;110A 1162 11B8;C325;110A 1162 11B8; # (쌥; 쌥; 쌥; 쌥; 쌥; ) HANGUL SYLLABLE SSAEB +C326;C326;110A 1162 11B9;C326;110A 1162 11B9; # (쌦; 쌦; 쌦; 쌦; 쌦; ) HANGUL SYLLABLE SSAEBS +C327;C327;110A 1162 11BA;C327;110A 1162 11BA; # (쌧; 쌧; 쌧; 쌧; 쌧; ) HANGUL SYLLABLE SSAES +C328;C328;110A 1162 11BB;C328;110A 1162 11BB; # (쌨; 쌨; 쌨; 쌨; 쌨; ) HANGUL SYLLABLE SSAESS +C329;C329;110A 1162 11BC;C329;110A 1162 11BC; # (쌩; 쌩; 쌩; 쌩; 쌩; ) HANGUL SYLLABLE SSAENG +C32A;C32A;110A 1162 11BD;C32A;110A 1162 11BD; # (쌪; 쌪; 쌪; 쌪; 쌪; ) HANGUL SYLLABLE SSAEJ +C32B;C32B;110A 1162 11BE;C32B;110A 1162 11BE; # (쌫; 쌫; 쌫; 쌫; 쌫; ) HANGUL SYLLABLE SSAEC +C32C;C32C;110A 1162 11BF;C32C;110A 1162 11BF; # (쌬; 쌬; 쌬; 쌬; 쌬; ) HANGUL SYLLABLE SSAEK +C32D;C32D;110A 1162 11C0;C32D;110A 1162 11C0; # (쌭; 쌭; 쌭; 쌭; 쌭; ) HANGUL SYLLABLE SSAET +C32E;C32E;110A 1162 11C1;C32E;110A 1162 11C1; # (쌮; 쌮; 쌮; 쌮; 쌮; ) HANGUL SYLLABLE SSAEP +C32F;C32F;110A 1162 11C2;C32F;110A 1162 11C2; # (쌯; 쌯; 쌯; 쌯; 쌯; ) HANGUL SYLLABLE SSAEH +C330;C330;110A 1163;C330;110A 1163; # (쌰; 쌰; 쌰; 쌰; 쌰; ) HANGUL SYLLABLE SSYA +C331;C331;110A 1163 11A8;C331;110A 1163 11A8; # (쌱; 쌱; 쌱; 쌱; 쌱; ) HANGUL SYLLABLE SSYAG +C332;C332;110A 1163 11A9;C332;110A 1163 11A9; # (쌲; 쌲; 쌲; 쌲; 쌲; ) HANGUL SYLLABLE SSYAGG +C333;C333;110A 1163 11AA;C333;110A 1163 11AA; # (쌳; 쌳; 쌳; 쌳; 쌳; ) HANGUL SYLLABLE SSYAGS +C334;C334;110A 1163 11AB;C334;110A 1163 11AB; # (쌴; 쌴; 쌴; 쌴; 쌴; ) HANGUL SYLLABLE SSYAN +C335;C335;110A 1163 11AC;C335;110A 1163 11AC; # (쌵; 쌵; 쌵; 쌵; 쌵; ) HANGUL SYLLABLE SSYANJ +C336;C336;110A 1163 11AD;C336;110A 1163 11AD; # (쌶; 쌶; 쌶; 쌶; 쌶; ) HANGUL SYLLABLE SSYANH +C337;C337;110A 1163 11AE;C337;110A 1163 11AE; # (쌷; 쌷; 쌷; 쌷; 쌷; ) HANGUL SYLLABLE SSYAD +C338;C338;110A 1163 11AF;C338;110A 1163 11AF; # (쌸; 쌸; 쌸; 쌸; 쌸; ) HANGUL SYLLABLE SSYAL +C339;C339;110A 1163 11B0;C339;110A 1163 11B0; # (쌹; 쌹; 쌹; 쌹; 쌹; ) HANGUL SYLLABLE SSYALG +C33A;C33A;110A 1163 11B1;C33A;110A 1163 11B1; # (쌺; 쌺; 쌺; 쌺; 쌺; ) HANGUL SYLLABLE SSYALM +C33B;C33B;110A 1163 11B2;C33B;110A 1163 11B2; # (쌻; 쌻; 쌻; 쌻; 쌻; ) HANGUL SYLLABLE SSYALB +C33C;C33C;110A 1163 11B3;C33C;110A 1163 11B3; # (쌼; 쌼; 쌼; 쌼; 쌼; ) HANGUL SYLLABLE SSYALS +C33D;C33D;110A 1163 11B4;C33D;110A 1163 11B4; # (쌽; 쌽; 쌽; 쌽; 쌽; ) HANGUL SYLLABLE SSYALT +C33E;C33E;110A 1163 11B5;C33E;110A 1163 11B5; # (쌾; 쌾; 쌾; 쌾; 쌾; ) HANGUL SYLLABLE SSYALP +C33F;C33F;110A 1163 11B6;C33F;110A 1163 11B6; # (쌿; 쌿; 쌿; 쌿; 쌿; ) HANGUL SYLLABLE SSYALH +C340;C340;110A 1163 11B7;C340;110A 1163 11B7; # (썀; 썀; 썀; 썀; 썀; ) HANGUL SYLLABLE SSYAM +C341;C341;110A 1163 11B8;C341;110A 1163 11B8; # (썁; 썁; 썁; 썁; 썁; ) HANGUL SYLLABLE SSYAB +C342;C342;110A 1163 11B9;C342;110A 1163 11B9; # (썂; 썂; 썂; 썂; 썂; ) HANGUL SYLLABLE SSYABS +C343;C343;110A 1163 11BA;C343;110A 1163 11BA; # (썃; 썃; 썃; 썃; 썃; ) HANGUL SYLLABLE SSYAS +C344;C344;110A 1163 11BB;C344;110A 1163 11BB; # (썄; 썄; 썄; 썄; 썄; ) HANGUL SYLLABLE SSYASS +C345;C345;110A 1163 11BC;C345;110A 1163 11BC; # (썅; 썅; 썅; 썅; 썅; ) HANGUL SYLLABLE SSYANG +C346;C346;110A 1163 11BD;C346;110A 1163 11BD; # (썆; 썆; 썆; 썆; 썆; ) HANGUL SYLLABLE SSYAJ +C347;C347;110A 1163 11BE;C347;110A 1163 11BE; # (썇; 썇; 썇; 썇; 썇; ) HANGUL SYLLABLE SSYAC +C348;C348;110A 1163 11BF;C348;110A 1163 11BF; # (썈; 썈; 썈; 썈; 썈; ) HANGUL SYLLABLE SSYAK +C349;C349;110A 1163 11C0;C349;110A 1163 11C0; # (썉; 썉; 썉; 썉; 썉; ) HANGUL SYLLABLE SSYAT +C34A;C34A;110A 1163 11C1;C34A;110A 1163 11C1; # (썊; 썊; 썊; 썊; 썊; ) HANGUL SYLLABLE SSYAP +C34B;C34B;110A 1163 11C2;C34B;110A 1163 11C2; # (썋; 썋; 썋; 썋; 썋; ) HANGUL SYLLABLE SSYAH +C34C;C34C;110A 1164;C34C;110A 1164; # (썌; 썌; 썌; 썌; 썌; ) HANGUL SYLLABLE SSYAE +C34D;C34D;110A 1164 11A8;C34D;110A 1164 11A8; # (썍; 썍; 썍; 썍; 썍; ) HANGUL SYLLABLE SSYAEG +C34E;C34E;110A 1164 11A9;C34E;110A 1164 11A9; # (썎; 썎; 썎; 썎; 썎; ) HANGUL SYLLABLE SSYAEGG +C34F;C34F;110A 1164 11AA;C34F;110A 1164 11AA; # (썏; 썏; 썏; 썏; 썏; ) HANGUL SYLLABLE SSYAEGS +C350;C350;110A 1164 11AB;C350;110A 1164 11AB; # (썐; 썐; 썐; 썐; 썐; ) HANGUL SYLLABLE SSYAEN +C351;C351;110A 1164 11AC;C351;110A 1164 11AC; # (썑; 썑; 썑; 썑; 썑; ) HANGUL SYLLABLE SSYAENJ +C352;C352;110A 1164 11AD;C352;110A 1164 11AD; # (썒; 썒; 썒; 썒; 썒; ) HANGUL SYLLABLE SSYAENH +C353;C353;110A 1164 11AE;C353;110A 1164 11AE; # (썓; 썓; 썓; 썓; 썓; ) HANGUL SYLLABLE SSYAED +C354;C354;110A 1164 11AF;C354;110A 1164 11AF; # (썔; 썔; 썔; 썔; 썔; ) HANGUL SYLLABLE SSYAEL +C355;C355;110A 1164 11B0;C355;110A 1164 11B0; # (썕; 썕; 썕; 썕; 썕; ) HANGUL SYLLABLE SSYAELG +C356;C356;110A 1164 11B1;C356;110A 1164 11B1; # (썖; 썖; 썖; 썖; 썖; ) HANGUL SYLLABLE SSYAELM +C357;C357;110A 1164 11B2;C357;110A 1164 11B2; # (썗; 썗; 썗; 썗; 썗; ) HANGUL SYLLABLE SSYAELB +C358;C358;110A 1164 11B3;C358;110A 1164 11B3; # (썘; 썘; 썘; 썘; 썘; ) HANGUL SYLLABLE SSYAELS +C359;C359;110A 1164 11B4;C359;110A 1164 11B4; # (썙; 썙; 썙; 썙; 썙; ) HANGUL SYLLABLE SSYAELT +C35A;C35A;110A 1164 11B5;C35A;110A 1164 11B5; # (썚; 썚; 썚; 썚; 썚; ) HANGUL SYLLABLE SSYAELP +C35B;C35B;110A 1164 11B6;C35B;110A 1164 11B6; # (썛; 썛; 썛; 썛; 썛; ) HANGUL SYLLABLE SSYAELH +C35C;C35C;110A 1164 11B7;C35C;110A 1164 11B7; # (썜; 썜; 썜; 썜; 썜; ) HANGUL SYLLABLE SSYAEM +C35D;C35D;110A 1164 11B8;C35D;110A 1164 11B8; # (썝; 썝; 썝; 썝; 썝; ) HANGUL SYLLABLE SSYAEB +C35E;C35E;110A 1164 11B9;C35E;110A 1164 11B9; # (썞; 썞; 썞; 썞; 썞; ) HANGUL SYLLABLE SSYAEBS +C35F;C35F;110A 1164 11BA;C35F;110A 1164 11BA; # (썟; 썟; 썟; 썟; 썟; ) HANGUL SYLLABLE SSYAES +C360;C360;110A 1164 11BB;C360;110A 1164 11BB; # (썠; 썠; 썠; 썠; 썠; ) HANGUL SYLLABLE SSYAESS +C361;C361;110A 1164 11BC;C361;110A 1164 11BC; # (썡; 썡; 썡; 썡; 썡; ) HANGUL SYLLABLE SSYAENG +C362;C362;110A 1164 11BD;C362;110A 1164 11BD; # (썢; 썢; 썢; 썢; 썢; ) HANGUL SYLLABLE SSYAEJ +C363;C363;110A 1164 11BE;C363;110A 1164 11BE; # (썣; 썣; 썣; 썣; 썣; ) HANGUL SYLLABLE SSYAEC +C364;C364;110A 1164 11BF;C364;110A 1164 11BF; # (썤; 썤; 썤; 썤; 썤; ) HANGUL SYLLABLE SSYAEK +C365;C365;110A 1164 11C0;C365;110A 1164 11C0; # (썥; 썥; 썥; 썥; 썥; ) HANGUL SYLLABLE SSYAET +C366;C366;110A 1164 11C1;C366;110A 1164 11C1; # (썦; 썦; 썦; 썦; 썦; ) HANGUL SYLLABLE SSYAEP +C367;C367;110A 1164 11C2;C367;110A 1164 11C2; # (썧; 썧; 썧; 썧; 썧; ) HANGUL SYLLABLE SSYAEH +C368;C368;110A 1165;C368;110A 1165; # (써; 써; 써; 써; 써; ) HANGUL SYLLABLE SSEO +C369;C369;110A 1165 11A8;C369;110A 1165 11A8; # (썩; 썩; 썩; 썩; 썩; ) HANGUL SYLLABLE SSEOG +C36A;C36A;110A 1165 11A9;C36A;110A 1165 11A9; # (썪; 썪; 썪; 썪; 썪; ) HANGUL SYLLABLE SSEOGG +C36B;C36B;110A 1165 11AA;C36B;110A 1165 11AA; # (썫; 썫; 썫; 썫; 썫; ) HANGUL SYLLABLE SSEOGS +C36C;C36C;110A 1165 11AB;C36C;110A 1165 11AB; # (썬; 썬; 썬; 썬; 썬; ) HANGUL SYLLABLE SSEON +C36D;C36D;110A 1165 11AC;C36D;110A 1165 11AC; # (썭; 썭; 썭; 썭; 썭; ) HANGUL SYLLABLE SSEONJ +C36E;C36E;110A 1165 11AD;C36E;110A 1165 11AD; # (썮; 썮; 썮; 썮; 썮; ) HANGUL SYLLABLE SSEONH +C36F;C36F;110A 1165 11AE;C36F;110A 1165 11AE; # (썯; 썯; 썯; 썯; 썯; ) HANGUL SYLLABLE SSEOD +C370;C370;110A 1165 11AF;C370;110A 1165 11AF; # (썰; 썰; 썰; 썰; 썰; ) HANGUL SYLLABLE SSEOL +C371;C371;110A 1165 11B0;C371;110A 1165 11B0; # (썱; 썱; 썱; 썱; 썱; ) HANGUL SYLLABLE SSEOLG +C372;C372;110A 1165 11B1;C372;110A 1165 11B1; # (썲; 썲; 썲; 썲; 썲; ) HANGUL SYLLABLE SSEOLM +C373;C373;110A 1165 11B2;C373;110A 1165 11B2; # (썳; 썳; 썳; 썳; 썳; ) HANGUL SYLLABLE SSEOLB +C374;C374;110A 1165 11B3;C374;110A 1165 11B3; # (썴; 썴; 썴; 썴; 썴; ) HANGUL SYLLABLE SSEOLS +C375;C375;110A 1165 11B4;C375;110A 1165 11B4; # (썵; 썵; 썵; 썵; 썵; ) HANGUL SYLLABLE SSEOLT +C376;C376;110A 1165 11B5;C376;110A 1165 11B5; # (썶; 썶; 썶; 썶; 썶; ) HANGUL SYLLABLE SSEOLP +C377;C377;110A 1165 11B6;C377;110A 1165 11B6; # (썷; 썷; 썷; 썷; 썷; ) HANGUL SYLLABLE SSEOLH +C378;C378;110A 1165 11B7;C378;110A 1165 11B7; # (썸; 썸; 썸; 썸; 썸; ) HANGUL SYLLABLE SSEOM +C379;C379;110A 1165 11B8;C379;110A 1165 11B8; # (썹; 썹; 썹; 썹; 썹; ) HANGUL SYLLABLE SSEOB +C37A;C37A;110A 1165 11B9;C37A;110A 1165 11B9; # (썺; 썺; 썺; 썺; 썺; ) HANGUL SYLLABLE SSEOBS +C37B;C37B;110A 1165 11BA;C37B;110A 1165 11BA; # (썻; 썻; 썻; 썻; 썻; ) HANGUL SYLLABLE SSEOS +C37C;C37C;110A 1165 11BB;C37C;110A 1165 11BB; # (썼; 썼; 썼; 썼; 썼; ) HANGUL SYLLABLE SSEOSS +C37D;C37D;110A 1165 11BC;C37D;110A 1165 11BC; # (썽; 썽; 썽; 썽; 썽; ) HANGUL SYLLABLE SSEONG +C37E;C37E;110A 1165 11BD;C37E;110A 1165 11BD; # (썾; 썾; 썾; 썾; 썾; ) HANGUL SYLLABLE SSEOJ +C37F;C37F;110A 1165 11BE;C37F;110A 1165 11BE; # (썿; 썿; 썿; 썿; 썿; ) HANGUL SYLLABLE SSEOC +C380;C380;110A 1165 11BF;C380;110A 1165 11BF; # (쎀; 쎀; 쎀; 쎀; 쎀; ) HANGUL SYLLABLE SSEOK +C381;C381;110A 1165 11C0;C381;110A 1165 11C0; # (쎁; 쎁; 쎁; 쎁; 쎁; ) HANGUL SYLLABLE SSEOT +C382;C382;110A 1165 11C1;C382;110A 1165 11C1; # (쎂; 쎂; 쎂; 쎂; 쎂; ) HANGUL SYLLABLE SSEOP +C383;C383;110A 1165 11C2;C383;110A 1165 11C2; # (쎃; 쎃; 쎃; 쎃; 쎃; ) HANGUL SYLLABLE SSEOH +C384;C384;110A 1166;C384;110A 1166; # (쎄; 쎄; 쎄; 쎄; 쎄; ) HANGUL SYLLABLE SSE +C385;C385;110A 1166 11A8;C385;110A 1166 11A8; # (쎅; 쎅; 쎅; 쎅; 쎅; ) HANGUL SYLLABLE SSEG +C386;C386;110A 1166 11A9;C386;110A 1166 11A9; # (쎆; 쎆; 쎆; 쎆; 쎆; ) HANGUL SYLLABLE SSEGG +C387;C387;110A 1166 11AA;C387;110A 1166 11AA; # (쎇; 쎇; 쎇; 쎇; 쎇; ) HANGUL SYLLABLE SSEGS +C388;C388;110A 1166 11AB;C388;110A 1166 11AB; # (쎈; 쎈; 쎈; 쎈; 쎈; ) HANGUL SYLLABLE SSEN +C389;C389;110A 1166 11AC;C389;110A 1166 11AC; # (쎉; 쎉; 쎉; 쎉; 쎉; ) HANGUL SYLLABLE SSENJ +C38A;C38A;110A 1166 11AD;C38A;110A 1166 11AD; # (쎊; 쎊; 쎊; 쎊; 쎊; ) HANGUL SYLLABLE SSENH +C38B;C38B;110A 1166 11AE;C38B;110A 1166 11AE; # (쎋; 쎋; 쎋; 쎋; 쎋; ) HANGUL SYLLABLE SSED +C38C;C38C;110A 1166 11AF;C38C;110A 1166 11AF; # (쎌; 쎌; 쎌; 쎌; 쎌; ) HANGUL SYLLABLE SSEL +C38D;C38D;110A 1166 11B0;C38D;110A 1166 11B0; # (쎍; 쎍; 쎍; 쎍; 쎍; ) HANGUL SYLLABLE SSELG +C38E;C38E;110A 1166 11B1;C38E;110A 1166 11B1; # (쎎; 쎎; 쎎; 쎎; 쎎; ) HANGUL SYLLABLE SSELM +C38F;C38F;110A 1166 11B2;C38F;110A 1166 11B2; # (쎏; 쎏; 쎏; 쎏; 쎏; ) HANGUL SYLLABLE SSELB +C390;C390;110A 1166 11B3;C390;110A 1166 11B3; # (쎐; 쎐; 쎐; 쎐; 쎐; ) HANGUL SYLLABLE SSELS +C391;C391;110A 1166 11B4;C391;110A 1166 11B4; # (쎑; 쎑; 쎑; 쎑; 쎑; ) HANGUL SYLLABLE SSELT +C392;C392;110A 1166 11B5;C392;110A 1166 11B5; # (쎒; 쎒; 쎒; 쎒; 쎒; ) HANGUL SYLLABLE SSELP +C393;C393;110A 1166 11B6;C393;110A 1166 11B6; # (쎓; 쎓; 쎓; 쎓; 쎓; ) HANGUL SYLLABLE SSELH +C394;C394;110A 1166 11B7;C394;110A 1166 11B7; # (쎔; 쎔; 쎔; 쎔; 쎔; ) HANGUL SYLLABLE SSEM +C395;C395;110A 1166 11B8;C395;110A 1166 11B8; # (쎕; 쎕; 쎕; 쎕; 쎕; ) HANGUL SYLLABLE SSEB +C396;C396;110A 1166 11B9;C396;110A 1166 11B9; # (쎖; 쎖; 쎖; 쎖; 쎖; ) HANGUL SYLLABLE SSEBS +C397;C397;110A 1166 11BA;C397;110A 1166 11BA; # (쎗; 쎗; 쎗; 쎗; 쎗; ) HANGUL SYLLABLE SSES +C398;C398;110A 1166 11BB;C398;110A 1166 11BB; # (쎘; 쎘; 쎘; 쎘; 쎘; ) HANGUL SYLLABLE SSESS +C399;C399;110A 1166 11BC;C399;110A 1166 11BC; # (쎙; 쎙; 쎙; 쎙; 쎙; ) HANGUL SYLLABLE SSENG +C39A;C39A;110A 1166 11BD;C39A;110A 1166 11BD; # (쎚; 쎚; 쎚; 쎚; 쎚; ) HANGUL SYLLABLE SSEJ +C39B;C39B;110A 1166 11BE;C39B;110A 1166 11BE; # (쎛; 쎛; 쎛; 쎛; 쎛; ) HANGUL SYLLABLE SSEC +C39C;C39C;110A 1166 11BF;C39C;110A 1166 11BF; # (쎜; 쎜; 쎜; 쎜; 쎜; ) HANGUL SYLLABLE SSEK +C39D;C39D;110A 1166 11C0;C39D;110A 1166 11C0; # (쎝; 쎝; 쎝; 쎝; 쎝; ) HANGUL SYLLABLE SSET +C39E;C39E;110A 1166 11C1;C39E;110A 1166 11C1; # (쎞; 쎞; 쎞; 쎞; 쎞; ) HANGUL SYLLABLE SSEP +C39F;C39F;110A 1166 11C2;C39F;110A 1166 11C2; # (쎟; 쎟; 쎟; 쎟; 쎟; ) HANGUL SYLLABLE SSEH +C3A0;C3A0;110A 1167;C3A0;110A 1167; # (쎠; 쎠; 쎠; 쎠; 쎠; ) HANGUL SYLLABLE SSYEO +C3A1;C3A1;110A 1167 11A8;C3A1;110A 1167 11A8; # (쎡; 쎡; 쎡; 쎡; 쎡; ) HANGUL SYLLABLE SSYEOG +C3A2;C3A2;110A 1167 11A9;C3A2;110A 1167 11A9; # (쎢; 쎢; 쎢; 쎢; 쎢; ) HANGUL SYLLABLE SSYEOGG +C3A3;C3A3;110A 1167 11AA;C3A3;110A 1167 11AA; # (쎣; 쎣; 쎣; 쎣; 쎣; ) HANGUL SYLLABLE SSYEOGS +C3A4;C3A4;110A 1167 11AB;C3A4;110A 1167 11AB; # (쎤; 쎤; 쎤; 쎤; 쎤; ) HANGUL SYLLABLE SSYEON +C3A5;C3A5;110A 1167 11AC;C3A5;110A 1167 11AC; # (쎥; 쎥; 쎥; 쎥; 쎥; ) HANGUL SYLLABLE SSYEONJ +C3A6;C3A6;110A 1167 11AD;C3A6;110A 1167 11AD; # (쎦; 쎦; 쎦; 쎦; 쎦; ) HANGUL SYLLABLE SSYEONH +C3A7;C3A7;110A 1167 11AE;C3A7;110A 1167 11AE; # (쎧; 쎧; 쎧; 쎧; 쎧; ) HANGUL SYLLABLE SSYEOD +C3A8;C3A8;110A 1167 11AF;C3A8;110A 1167 11AF; # (쎨; 쎨; 쎨; 쎨; 쎨; ) HANGUL SYLLABLE SSYEOL +C3A9;C3A9;110A 1167 11B0;C3A9;110A 1167 11B0; # (쎩; 쎩; 쎩; 쎩; 쎩; ) HANGUL SYLLABLE SSYEOLG +C3AA;C3AA;110A 1167 11B1;C3AA;110A 1167 11B1; # (쎪; 쎪; 쎪; 쎪; 쎪; ) HANGUL SYLLABLE SSYEOLM +C3AB;C3AB;110A 1167 11B2;C3AB;110A 1167 11B2; # (쎫; 쎫; 쎫; 쎫; 쎫; ) HANGUL SYLLABLE SSYEOLB +C3AC;C3AC;110A 1167 11B3;C3AC;110A 1167 11B3; # (쎬; 쎬; 쎬; 쎬; 쎬; ) HANGUL SYLLABLE SSYEOLS +C3AD;C3AD;110A 1167 11B4;C3AD;110A 1167 11B4; # (쎭; 쎭; 쎭; 쎭; 쎭; ) HANGUL SYLLABLE SSYEOLT +C3AE;C3AE;110A 1167 11B5;C3AE;110A 1167 11B5; # (쎮; 쎮; 쎮; 쎮; 쎮; ) HANGUL SYLLABLE SSYEOLP +C3AF;C3AF;110A 1167 11B6;C3AF;110A 1167 11B6; # (쎯; 쎯; 쎯; 쎯; 쎯; ) HANGUL SYLLABLE SSYEOLH +C3B0;C3B0;110A 1167 11B7;C3B0;110A 1167 11B7; # (쎰; 쎰; 쎰; 쎰; 쎰; ) HANGUL SYLLABLE SSYEOM +C3B1;C3B1;110A 1167 11B8;C3B1;110A 1167 11B8; # (쎱; 쎱; 쎱; 쎱; 쎱; ) HANGUL SYLLABLE SSYEOB +C3B2;C3B2;110A 1167 11B9;C3B2;110A 1167 11B9; # (쎲; 쎲; 쎲; 쎲; 쎲; ) HANGUL SYLLABLE SSYEOBS +C3B3;C3B3;110A 1167 11BA;C3B3;110A 1167 11BA; # (쎳; 쎳; 쎳; 쎳; 쎳; ) HANGUL SYLLABLE SSYEOS +C3B4;C3B4;110A 1167 11BB;C3B4;110A 1167 11BB; # (쎴; 쎴; 쎴; 쎴; 쎴; ) HANGUL SYLLABLE SSYEOSS +C3B5;C3B5;110A 1167 11BC;C3B5;110A 1167 11BC; # (쎵; 쎵; 쎵; 쎵; 쎵; ) HANGUL SYLLABLE SSYEONG +C3B6;C3B6;110A 1167 11BD;C3B6;110A 1167 11BD; # (쎶; 쎶; 쎶; 쎶; 쎶; ) HANGUL SYLLABLE SSYEOJ +C3B7;C3B7;110A 1167 11BE;C3B7;110A 1167 11BE; # (쎷; 쎷; 쎷; 쎷; 쎷; ) HANGUL SYLLABLE SSYEOC +C3B8;C3B8;110A 1167 11BF;C3B8;110A 1167 11BF; # (쎸; 쎸; 쎸; 쎸; 쎸; ) HANGUL SYLLABLE SSYEOK +C3B9;C3B9;110A 1167 11C0;C3B9;110A 1167 11C0; # (쎹; 쎹; 쎹; 쎹; 쎹; ) HANGUL SYLLABLE SSYEOT +C3BA;C3BA;110A 1167 11C1;C3BA;110A 1167 11C1; # (쎺; 쎺; 쎺; 쎺; 쎺; ) HANGUL SYLLABLE SSYEOP +C3BB;C3BB;110A 1167 11C2;C3BB;110A 1167 11C2; # (쎻; 쎻; 쎻; 쎻; 쎻; ) HANGUL SYLLABLE SSYEOH +C3BC;C3BC;110A 1168;C3BC;110A 1168; # (쎼; 쎼; 쎼; 쎼; 쎼; ) HANGUL SYLLABLE SSYE +C3BD;C3BD;110A 1168 11A8;C3BD;110A 1168 11A8; # (쎽; 쎽; 쎽; 쎽; 쎽; ) HANGUL SYLLABLE SSYEG +C3BE;C3BE;110A 1168 11A9;C3BE;110A 1168 11A9; # (쎾; 쎾; 쎾; 쎾; 쎾; ) HANGUL SYLLABLE SSYEGG +C3BF;C3BF;110A 1168 11AA;C3BF;110A 1168 11AA; # (쎿; 쎿; 쎿; 쎿; 쎿; ) HANGUL SYLLABLE SSYEGS +C3C0;C3C0;110A 1168 11AB;C3C0;110A 1168 11AB; # (쏀; 쏀; 쏀; 쏀; 쏀; ) HANGUL SYLLABLE SSYEN +C3C1;C3C1;110A 1168 11AC;C3C1;110A 1168 11AC; # (쏁; 쏁; 쏁; 쏁; 쏁; ) HANGUL SYLLABLE SSYENJ +C3C2;C3C2;110A 1168 11AD;C3C2;110A 1168 11AD; # (쏂; 쏂; 쏂; 쏂; 쏂; ) HANGUL SYLLABLE SSYENH +C3C3;C3C3;110A 1168 11AE;C3C3;110A 1168 11AE; # (쏃; 쏃; 쏃; 쏃; 쏃; ) HANGUL SYLLABLE SSYED +C3C4;C3C4;110A 1168 11AF;C3C4;110A 1168 11AF; # (쏄; 쏄; 쏄; 쏄; 쏄; ) HANGUL SYLLABLE SSYEL +C3C5;C3C5;110A 1168 11B0;C3C5;110A 1168 11B0; # (쏅; 쏅; 쏅; 쏅; 쏅; ) HANGUL SYLLABLE SSYELG +C3C6;C3C6;110A 1168 11B1;C3C6;110A 1168 11B1; # (쏆; 쏆; 쏆; 쏆; 쏆; ) HANGUL SYLLABLE SSYELM +C3C7;C3C7;110A 1168 11B2;C3C7;110A 1168 11B2; # (쏇; 쏇; 쏇; 쏇; 쏇; ) HANGUL SYLLABLE SSYELB +C3C8;C3C8;110A 1168 11B3;C3C8;110A 1168 11B3; # (쏈; 쏈; 쏈; 쏈; 쏈; ) HANGUL SYLLABLE SSYELS +C3C9;C3C9;110A 1168 11B4;C3C9;110A 1168 11B4; # (쏉; 쏉; 쏉; 쏉; 쏉; ) HANGUL SYLLABLE SSYELT +C3CA;C3CA;110A 1168 11B5;C3CA;110A 1168 11B5; # (쏊; 쏊; 쏊; 쏊; 쏊; ) HANGUL SYLLABLE SSYELP +C3CB;C3CB;110A 1168 11B6;C3CB;110A 1168 11B6; # (쏋; 쏋; 쏋; 쏋; 쏋; ) HANGUL SYLLABLE SSYELH +C3CC;C3CC;110A 1168 11B7;C3CC;110A 1168 11B7; # (쏌; 쏌; 쏌; 쏌; 쏌; ) HANGUL SYLLABLE SSYEM +C3CD;C3CD;110A 1168 11B8;C3CD;110A 1168 11B8; # (쏍; 쏍; 쏍; 쏍; 쏍; ) HANGUL SYLLABLE SSYEB +C3CE;C3CE;110A 1168 11B9;C3CE;110A 1168 11B9; # (쏎; 쏎; 쏎; 쏎; 쏎; ) HANGUL SYLLABLE SSYEBS +C3CF;C3CF;110A 1168 11BA;C3CF;110A 1168 11BA; # (쏏; 쏏; 쏏; 쏏; 쏏; ) HANGUL SYLLABLE SSYES +C3D0;C3D0;110A 1168 11BB;C3D0;110A 1168 11BB; # (쏐; 쏐; 쏐; 쏐; 쏐; ) HANGUL SYLLABLE SSYESS +C3D1;C3D1;110A 1168 11BC;C3D1;110A 1168 11BC; # (쏑; 쏑; 쏑; 쏑; 쏑; ) HANGUL SYLLABLE SSYENG +C3D2;C3D2;110A 1168 11BD;C3D2;110A 1168 11BD; # (쏒; 쏒; 쏒; 쏒; 쏒; ) HANGUL SYLLABLE SSYEJ +C3D3;C3D3;110A 1168 11BE;C3D3;110A 1168 11BE; # (쏓; 쏓; 쏓; 쏓; 쏓; ) HANGUL SYLLABLE SSYEC +C3D4;C3D4;110A 1168 11BF;C3D4;110A 1168 11BF; # (쏔; 쏔; 쏔; 쏔; 쏔; ) HANGUL SYLLABLE SSYEK +C3D5;C3D5;110A 1168 11C0;C3D5;110A 1168 11C0; # (쏕; 쏕; 쏕; 쏕; 쏕; ) HANGUL SYLLABLE SSYET +C3D6;C3D6;110A 1168 11C1;C3D6;110A 1168 11C1; # (쏖; 쏖; 쏖; 쏖; 쏖; ) HANGUL SYLLABLE SSYEP +C3D7;C3D7;110A 1168 11C2;C3D7;110A 1168 11C2; # (쏗; 쏗; 쏗; 쏗; 쏗; ) HANGUL SYLLABLE SSYEH +C3D8;C3D8;110A 1169;C3D8;110A 1169; # (쏘; 쏘; 쏘; 쏘; 쏘; ) HANGUL SYLLABLE SSO +C3D9;C3D9;110A 1169 11A8;C3D9;110A 1169 11A8; # (쏙; 쏙; 쏙; 쏙; 쏙; ) HANGUL SYLLABLE SSOG +C3DA;C3DA;110A 1169 11A9;C3DA;110A 1169 11A9; # (쏚; 쏚; 쏚; 쏚; 쏚; ) HANGUL SYLLABLE SSOGG +C3DB;C3DB;110A 1169 11AA;C3DB;110A 1169 11AA; # (쏛; 쏛; 쏛; 쏛; 쏛; ) HANGUL SYLLABLE SSOGS +C3DC;C3DC;110A 1169 11AB;C3DC;110A 1169 11AB; # (쏜; 쏜; 쏜; 쏜; 쏜; ) HANGUL SYLLABLE SSON +C3DD;C3DD;110A 1169 11AC;C3DD;110A 1169 11AC; # (쏝; 쏝; 쏝; 쏝; 쏝; ) HANGUL SYLLABLE SSONJ +C3DE;C3DE;110A 1169 11AD;C3DE;110A 1169 11AD; # (쏞; 쏞; 쏞; 쏞; 쏞; ) HANGUL SYLLABLE SSONH +C3DF;C3DF;110A 1169 11AE;C3DF;110A 1169 11AE; # (쏟; 쏟; 쏟; 쏟; 쏟; ) HANGUL SYLLABLE SSOD +C3E0;C3E0;110A 1169 11AF;C3E0;110A 1169 11AF; # (쏠; 쏠; 쏠; 쏠; 쏠; ) HANGUL SYLLABLE SSOL +C3E1;C3E1;110A 1169 11B0;C3E1;110A 1169 11B0; # (쏡; 쏡; 쏡; 쏡; 쏡; ) HANGUL SYLLABLE SSOLG +C3E2;C3E2;110A 1169 11B1;C3E2;110A 1169 11B1; # (쏢; 쏢; 쏢; 쏢; 쏢; ) HANGUL SYLLABLE SSOLM +C3E3;C3E3;110A 1169 11B2;C3E3;110A 1169 11B2; # (쏣; 쏣; 쏣; 쏣; 쏣; ) HANGUL SYLLABLE SSOLB +C3E4;C3E4;110A 1169 11B3;C3E4;110A 1169 11B3; # (쏤; 쏤; 쏤; 쏤; 쏤; ) HANGUL SYLLABLE SSOLS +C3E5;C3E5;110A 1169 11B4;C3E5;110A 1169 11B4; # (쏥; 쏥; 쏥; 쏥; 쏥; ) HANGUL SYLLABLE SSOLT +C3E6;C3E6;110A 1169 11B5;C3E6;110A 1169 11B5; # (쏦; 쏦; 쏦; 쏦; 쏦; ) HANGUL SYLLABLE SSOLP +C3E7;C3E7;110A 1169 11B6;C3E7;110A 1169 11B6; # (쏧; 쏧; 쏧; 쏧; 쏧; ) HANGUL SYLLABLE SSOLH +C3E8;C3E8;110A 1169 11B7;C3E8;110A 1169 11B7; # (쏨; 쏨; 쏨; 쏨; 쏨; ) HANGUL SYLLABLE SSOM +C3E9;C3E9;110A 1169 11B8;C3E9;110A 1169 11B8; # (쏩; 쏩; 쏩; 쏩; 쏩; ) HANGUL SYLLABLE SSOB +C3EA;C3EA;110A 1169 11B9;C3EA;110A 1169 11B9; # (쏪; 쏪; 쏪; 쏪; 쏪; ) HANGUL SYLLABLE SSOBS +C3EB;C3EB;110A 1169 11BA;C3EB;110A 1169 11BA; # (쏫; 쏫; 쏫; 쏫; 쏫; ) HANGUL SYLLABLE SSOS +C3EC;C3EC;110A 1169 11BB;C3EC;110A 1169 11BB; # (쏬; 쏬; 쏬; 쏬; 쏬; ) HANGUL SYLLABLE SSOSS +C3ED;C3ED;110A 1169 11BC;C3ED;110A 1169 11BC; # (쏭; 쏭; 쏭; 쏭; 쏭; ) HANGUL SYLLABLE SSONG +C3EE;C3EE;110A 1169 11BD;C3EE;110A 1169 11BD; # (쏮; 쏮; 쏮; 쏮; 쏮; ) HANGUL SYLLABLE SSOJ +C3EF;C3EF;110A 1169 11BE;C3EF;110A 1169 11BE; # (쏯; 쏯; 쏯; 쏯; 쏯; ) HANGUL SYLLABLE SSOC +C3F0;C3F0;110A 1169 11BF;C3F0;110A 1169 11BF; # (쏰; 쏰; 쏰; 쏰; 쏰; ) HANGUL SYLLABLE SSOK +C3F1;C3F1;110A 1169 11C0;C3F1;110A 1169 11C0; # (쏱; 쏱; 쏱; 쏱; 쏱; ) HANGUL SYLLABLE SSOT +C3F2;C3F2;110A 1169 11C1;C3F2;110A 1169 11C1; # (쏲; 쏲; 쏲; 쏲; 쏲; ) HANGUL SYLLABLE SSOP +C3F3;C3F3;110A 1169 11C2;C3F3;110A 1169 11C2; # (쏳; 쏳; 쏳; 쏳; 쏳; ) HANGUL SYLLABLE SSOH +C3F4;C3F4;110A 116A;C3F4;110A 116A; # (쏴; 쏴; 쏴; 쏴; 쏴; ) HANGUL SYLLABLE SSWA +C3F5;C3F5;110A 116A 11A8;C3F5;110A 116A 11A8; # (쏵; 쏵; 쏵; 쏵; 쏵; ) HANGUL SYLLABLE SSWAG +C3F6;C3F6;110A 116A 11A9;C3F6;110A 116A 11A9; # (쏶; 쏶; 쏶; 쏶; 쏶; ) HANGUL SYLLABLE SSWAGG +C3F7;C3F7;110A 116A 11AA;C3F7;110A 116A 11AA; # (쏷; 쏷; 쏷; 쏷; 쏷; ) HANGUL SYLLABLE SSWAGS +C3F8;C3F8;110A 116A 11AB;C3F8;110A 116A 11AB; # (쏸; 쏸; 쏸; 쏸; 쏸; ) HANGUL SYLLABLE SSWAN +C3F9;C3F9;110A 116A 11AC;C3F9;110A 116A 11AC; # (쏹; 쏹; 쏹; 쏹; 쏹; ) HANGUL SYLLABLE SSWANJ +C3FA;C3FA;110A 116A 11AD;C3FA;110A 116A 11AD; # (쏺; 쏺; 쏺; 쏺; 쏺; ) HANGUL SYLLABLE SSWANH +C3FB;C3FB;110A 116A 11AE;C3FB;110A 116A 11AE; # (쏻; 쏻; 쏻; 쏻; 쏻; ) HANGUL SYLLABLE SSWAD +C3FC;C3FC;110A 116A 11AF;C3FC;110A 116A 11AF; # (쏼; 쏼; 쏼; 쏼; 쏼; ) HANGUL SYLLABLE SSWAL +C3FD;C3FD;110A 116A 11B0;C3FD;110A 116A 11B0; # (쏽; 쏽; 쏽; 쏽; 쏽; ) HANGUL SYLLABLE SSWALG +C3FE;C3FE;110A 116A 11B1;C3FE;110A 116A 11B1; # (쏾; 쏾; 쏾; 쏾; 쏾; ) HANGUL SYLLABLE SSWALM +C3FF;C3FF;110A 116A 11B2;C3FF;110A 116A 11B2; # (쏿; 쏿; 쏿; 쏿; 쏿; ) HANGUL SYLLABLE SSWALB +C400;C400;110A 116A 11B3;C400;110A 116A 11B3; # (쐀; 쐀; 쐀; 쐀; 쐀; ) HANGUL SYLLABLE SSWALS +C401;C401;110A 116A 11B4;C401;110A 116A 11B4; # (쐁; 쐁; 쐁; 쐁; 쐁; ) HANGUL SYLLABLE SSWALT +C402;C402;110A 116A 11B5;C402;110A 116A 11B5; # (쐂; 쐂; 쐂; 쐂; 쐂; ) HANGUL SYLLABLE SSWALP +C403;C403;110A 116A 11B6;C403;110A 116A 11B6; # (쐃; 쐃; 쐃; 쐃; 쐃; ) HANGUL SYLLABLE SSWALH +C404;C404;110A 116A 11B7;C404;110A 116A 11B7; # (쐄; 쐄; 쐄; 쐄; 쐄; ) HANGUL SYLLABLE SSWAM +C405;C405;110A 116A 11B8;C405;110A 116A 11B8; # (쐅; 쐅; 쐅; 쐅; 쐅; ) HANGUL SYLLABLE SSWAB +C406;C406;110A 116A 11B9;C406;110A 116A 11B9; # (쐆; 쐆; 쐆; 쐆; 쐆; ) HANGUL SYLLABLE SSWABS +C407;C407;110A 116A 11BA;C407;110A 116A 11BA; # (쐇; 쐇; 쐇; 쐇; 쐇; ) HANGUL SYLLABLE SSWAS +C408;C408;110A 116A 11BB;C408;110A 116A 11BB; # (쐈; 쐈; 쐈; 쐈; 쐈; ) HANGUL SYLLABLE SSWASS +C409;C409;110A 116A 11BC;C409;110A 116A 11BC; # (쐉; 쐉; 쐉; 쐉; 쐉; ) HANGUL SYLLABLE SSWANG +C40A;C40A;110A 116A 11BD;C40A;110A 116A 11BD; # (쐊; 쐊; 쐊; 쐊; 쐊; ) HANGUL SYLLABLE SSWAJ +C40B;C40B;110A 116A 11BE;C40B;110A 116A 11BE; # (쐋; 쐋; 쐋; 쐋; 쐋; ) HANGUL SYLLABLE SSWAC +C40C;C40C;110A 116A 11BF;C40C;110A 116A 11BF; # (쐌; 쐌; 쐌; 쐌; 쐌; ) HANGUL SYLLABLE SSWAK +C40D;C40D;110A 116A 11C0;C40D;110A 116A 11C0; # (쐍; 쐍; 쐍; 쐍; 쐍; ) HANGUL SYLLABLE SSWAT +C40E;C40E;110A 116A 11C1;C40E;110A 116A 11C1; # (쐎; 쐎; 쐎; 쐎; 쐎; ) HANGUL SYLLABLE SSWAP +C40F;C40F;110A 116A 11C2;C40F;110A 116A 11C2; # (쐏; 쐏; 쐏; 쐏; 쐏; ) HANGUL SYLLABLE SSWAH +C410;C410;110A 116B;C410;110A 116B; # (쐐; 쐐; 쐐; 쐐; 쐐; ) HANGUL SYLLABLE SSWAE +C411;C411;110A 116B 11A8;C411;110A 116B 11A8; # (쐑; 쐑; 쐑; 쐑; 쐑; ) HANGUL SYLLABLE SSWAEG +C412;C412;110A 116B 11A9;C412;110A 116B 11A9; # (쐒; 쐒; 쐒; 쐒; 쐒; ) HANGUL SYLLABLE SSWAEGG +C413;C413;110A 116B 11AA;C413;110A 116B 11AA; # (쐓; 쐓; 쐓; 쐓; 쐓; ) HANGUL SYLLABLE SSWAEGS +C414;C414;110A 116B 11AB;C414;110A 116B 11AB; # (쐔; 쐔; 쐔; 쐔; 쐔; ) HANGUL SYLLABLE SSWAEN +C415;C415;110A 116B 11AC;C415;110A 116B 11AC; # (쐕; 쐕; 쐕; 쐕; 쐕; ) HANGUL SYLLABLE SSWAENJ +C416;C416;110A 116B 11AD;C416;110A 116B 11AD; # (쐖; 쐖; 쐖; 쐖; 쐖; ) HANGUL SYLLABLE SSWAENH +C417;C417;110A 116B 11AE;C417;110A 116B 11AE; # (쐗; 쐗; 쐗; 쐗; 쐗; ) HANGUL SYLLABLE SSWAED +C418;C418;110A 116B 11AF;C418;110A 116B 11AF; # (쐘; 쐘; 쐘; 쐘; 쐘; ) HANGUL SYLLABLE SSWAEL +C419;C419;110A 116B 11B0;C419;110A 116B 11B0; # (쐙; 쐙; 쐙; 쐙; 쐙; ) HANGUL SYLLABLE SSWAELG +C41A;C41A;110A 116B 11B1;C41A;110A 116B 11B1; # (쐚; 쐚; 쐚; 쐚; 쐚; ) HANGUL SYLLABLE SSWAELM +C41B;C41B;110A 116B 11B2;C41B;110A 116B 11B2; # (쐛; 쐛; 쐛; 쐛; 쐛; ) HANGUL SYLLABLE SSWAELB +C41C;C41C;110A 116B 11B3;C41C;110A 116B 11B3; # (쐜; 쐜; 쐜; 쐜; 쐜; ) HANGUL SYLLABLE SSWAELS +C41D;C41D;110A 116B 11B4;C41D;110A 116B 11B4; # (쐝; 쐝; 쐝; 쐝; 쐝; ) HANGUL SYLLABLE SSWAELT +C41E;C41E;110A 116B 11B5;C41E;110A 116B 11B5; # (쐞; 쐞; 쐞; 쐞; 쐞; ) HANGUL SYLLABLE SSWAELP +C41F;C41F;110A 116B 11B6;C41F;110A 116B 11B6; # (쐟; 쐟; 쐟; 쐟; 쐟; ) HANGUL SYLLABLE SSWAELH +C420;C420;110A 116B 11B7;C420;110A 116B 11B7; # (쐠; 쐠; 쐠; 쐠; 쐠; ) HANGUL SYLLABLE SSWAEM +C421;C421;110A 116B 11B8;C421;110A 116B 11B8; # (쐡; 쐡; 쐡; 쐡; 쐡; ) HANGUL SYLLABLE SSWAEB +C422;C422;110A 116B 11B9;C422;110A 116B 11B9; # (쐢; 쐢; 쐢; 쐢; 쐢; ) HANGUL SYLLABLE SSWAEBS +C423;C423;110A 116B 11BA;C423;110A 116B 11BA; # (쐣; 쐣; 쐣; 쐣; 쐣; ) HANGUL SYLLABLE SSWAES +C424;C424;110A 116B 11BB;C424;110A 116B 11BB; # (쐤; 쐤; 쐤; 쐤; 쐤; ) HANGUL SYLLABLE SSWAESS +C425;C425;110A 116B 11BC;C425;110A 116B 11BC; # (쐥; 쐥; 쐥; 쐥; 쐥; ) HANGUL SYLLABLE SSWAENG +C426;C426;110A 116B 11BD;C426;110A 116B 11BD; # (쐦; 쐦; 쐦; 쐦; 쐦; ) HANGUL SYLLABLE SSWAEJ +C427;C427;110A 116B 11BE;C427;110A 116B 11BE; # (쐧; 쐧; 쐧; 쐧; 쐧; ) HANGUL SYLLABLE SSWAEC +C428;C428;110A 116B 11BF;C428;110A 116B 11BF; # (쐨; 쐨; 쐨; 쐨; 쐨; ) HANGUL SYLLABLE SSWAEK +C429;C429;110A 116B 11C0;C429;110A 116B 11C0; # (쐩; 쐩; 쐩; 쐩; 쐩; ) HANGUL SYLLABLE SSWAET +C42A;C42A;110A 116B 11C1;C42A;110A 116B 11C1; # (쐪; 쐪; 쐪; 쐪; 쐪; ) HANGUL SYLLABLE SSWAEP +C42B;C42B;110A 116B 11C2;C42B;110A 116B 11C2; # (쐫; 쐫; 쐫; 쐫; 쐫; ) HANGUL SYLLABLE SSWAEH +C42C;C42C;110A 116C;C42C;110A 116C; # (쐬; 쐬; 쐬; 쐬; 쐬; ) HANGUL SYLLABLE SSOE +C42D;C42D;110A 116C 11A8;C42D;110A 116C 11A8; # (쐭; 쐭; 쐭; 쐭; 쐭; ) HANGUL SYLLABLE SSOEG +C42E;C42E;110A 116C 11A9;C42E;110A 116C 11A9; # (쐮; 쐮; 쐮; 쐮; 쐮; ) HANGUL SYLLABLE SSOEGG +C42F;C42F;110A 116C 11AA;C42F;110A 116C 11AA; # (쐯; 쐯; 쐯; 쐯; 쐯; ) HANGUL SYLLABLE SSOEGS +C430;C430;110A 116C 11AB;C430;110A 116C 11AB; # (쐰; 쐰; 쐰; 쐰; 쐰; ) HANGUL SYLLABLE SSOEN +C431;C431;110A 116C 11AC;C431;110A 116C 11AC; # (쐱; 쐱; 쐱; 쐱; 쐱; ) HANGUL SYLLABLE SSOENJ +C432;C432;110A 116C 11AD;C432;110A 116C 11AD; # (쐲; 쐲; 쐲; 쐲; 쐲; ) HANGUL SYLLABLE SSOENH +C433;C433;110A 116C 11AE;C433;110A 116C 11AE; # (쐳; 쐳; 쐳; 쐳; 쐳; ) HANGUL SYLLABLE SSOED +C434;C434;110A 116C 11AF;C434;110A 116C 11AF; # (쐴; 쐴; 쐴; 쐴; 쐴; ) HANGUL SYLLABLE SSOEL +C435;C435;110A 116C 11B0;C435;110A 116C 11B0; # (쐵; 쐵; 쐵; 쐵; 쐵; ) HANGUL SYLLABLE SSOELG +C436;C436;110A 116C 11B1;C436;110A 116C 11B1; # (쐶; 쐶; 쐶; 쐶; 쐶; ) HANGUL SYLLABLE SSOELM +C437;C437;110A 116C 11B2;C437;110A 116C 11B2; # (쐷; 쐷; 쐷; 쐷; 쐷; ) HANGUL SYLLABLE SSOELB +C438;C438;110A 116C 11B3;C438;110A 116C 11B3; # (쐸; 쐸; 쐸; 쐸; 쐸; ) HANGUL SYLLABLE SSOELS +C439;C439;110A 116C 11B4;C439;110A 116C 11B4; # (쐹; 쐹; 쐹; 쐹; 쐹; ) HANGUL SYLLABLE SSOELT +C43A;C43A;110A 116C 11B5;C43A;110A 116C 11B5; # (쐺; 쐺; 쐺; 쐺; 쐺; ) HANGUL SYLLABLE SSOELP +C43B;C43B;110A 116C 11B6;C43B;110A 116C 11B6; # (쐻; 쐻; 쐻; 쐻; 쐻; ) HANGUL SYLLABLE SSOELH +C43C;C43C;110A 116C 11B7;C43C;110A 116C 11B7; # (쐼; 쐼; 쐼; 쐼; 쐼; ) HANGUL SYLLABLE SSOEM +C43D;C43D;110A 116C 11B8;C43D;110A 116C 11B8; # (쐽; 쐽; 쐽; 쐽; 쐽; ) HANGUL SYLLABLE SSOEB +C43E;C43E;110A 116C 11B9;C43E;110A 116C 11B9; # (쐾; 쐾; 쐾; 쐾; 쐾; ) HANGUL SYLLABLE SSOEBS +C43F;C43F;110A 116C 11BA;C43F;110A 116C 11BA; # (쐿; 쐿; 쐿; 쐿; 쐿; ) HANGUL SYLLABLE SSOES +C440;C440;110A 116C 11BB;C440;110A 116C 11BB; # (쑀; 쑀; 쑀; 쑀; 쑀; ) HANGUL SYLLABLE SSOESS +C441;C441;110A 116C 11BC;C441;110A 116C 11BC; # (쑁; 쑁; 쑁; 쑁; 쑁; ) HANGUL SYLLABLE SSOENG +C442;C442;110A 116C 11BD;C442;110A 116C 11BD; # (쑂; 쑂; 쑂; 쑂; 쑂; ) HANGUL SYLLABLE SSOEJ +C443;C443;110A 116C 11BE;C443;110A 116C 11BE; # (쑃; 쑃; 쑃; 쑃; 쑃; ) HANGUL SYLLABLE SSOEC +C444;C444;110A 116C 11BF;C444;110A 116C 11BF; # (쑄; 쑄; 쑄; 쑄; 쑄; ) HANGUL SYLLABLE SSOEK +C445;C445;110A 116C 11C0;C445;110A 116C 11C0; # (쑅; 쑅; 쑅; 쑅; 쑅; ) HANGUL SYLLABLE SSOET +C446;C446;110A 116C 11C1;C446;110A 116C 11C1; # (쑆; 쑆; 쑆; 쑆; 쑆; ) HANGUL SYLLABLE SSOEP +C447;C447;110A 116C 11C2;C447;110A 116C 11C2; # (쑇; 쑇; 쑇; 쑇; 쑇; ) HANGUL SYLLABLE SSOEH +C448;C448;110A 116D;C448;110A 116D; # (쑈; 쑈; 쑈; 쑈; 쑈; ) HANGUL SYLLABLE SSYO +C449;C449;110A 116D 11A8;C449;110A 116D 11A8; # (쑉; 쑉; 쑉; 쑉; 쑉; ) HANGUL SYLLABLE SSYOG +C44A;C44A;110A 116D 11A9;C44A;110A 116D 11A9; # (쑊; 쑊; 쑊; 쑊; 쑊; ) HANGUL SYLLABLE SSYOGG +C44B;C44B;110A 116D 11AA;C44B;110A 116D 11AA; # (쑋; 쑋; 쑋; 쑋; 쑋; ) HANGUL SYLLABLE SSYOGS +C44C;C44C;110A 116D 11AB;C44C;110A 116D 11AB; # (쑌; 쑌; 쑌; 쑌; 쑌; ) HANGUL SYLLABLE SSYON +C44D;C44D;110A 116D 11AC;C44D;110A 116D 11AC; # (쑍; 쑍; 쑍; 쑍; 쑍; ) HANGUL SYLLABLE SSYONJ +C44E;C44E;110A 116D 11AD;C44E;110A 116D 11AD; # (쑎; 쑎; 쑎; 쑎; 쑎; ) HANGUL SYLLABLE SSYONH +C44F;C44F;110A 116D 11AE;C44F;110A 116D 11AE; # (쑏; 쑏; 쑏; 쑏; 쑏; ) HANGUL SYLLABLE SSYOD +C450;C450;110A 116D 11AF;C450;110A 116D 11AF; # (쑐; 쑐; 쑐; 쑐; 쑐; ) HANGUL SYLLABLE SSYOL +C451;C451;110A 116D 11B0;C451;110A 116D 11B0; # (쑑; 쑑; 쑑; 쑑; 쑑; ) HANGUL SYLLABLE SSYOLG +C452;C452;110A 116D 11B1;C452;110A 116D 11B1; # (쑒; 쑒; 쑒; 쑒; 쑒; ) HANGUL SYLLABLE SSYOLM +C453;C453;110A 116D 11B2;C453;110A 116D 11B2; # (쑓; 쑓; 쑓; 쑓; 쑓; ) HANGUL SYLLABLE SSYOLB +C454;C454;110A 116D 11B3;C454;110A 116D 11B3; # (쑔; 쑔; 쑔; 쑔; 쑔; ) HANGUL SYLLABLE SSYOLS +C455;C455;110A 116D 11B4;C455;110A 116D 11B4; # (쑕; 쑕; 쑕; 쑕; 쑕; ) HANGUL SYLLABLE SSYOLT +C456;C456;110A 116D 11B5;C456;110A 116D 11B5; # (쑖; 쑖; 쑖; 쑖; 쑖; ) HANGUL SYLLABLE SSYOLP +C457;C457;110A 116D 11B6;C457;110A 116D 11B6; # (쑗; 쑗; 쑗; 쑗; 쑗; ) HANGUL SYLLABLE SSYOLH +C458;C458;110A 116D 11B7;C458;110A 116D 11B7; # (쑘; 쑘; 쑘; 쑘; 쑘; ) HANGUL SYLLABLE SSYOM +C459;C459;110A 116D 11B8;C459;110A 116D 11B8; # (쑙; 쑙; 쑙; 쑙; 쑙; ) HANGUL SYLLABLE SSYOB +C45A;C45A;110A 116D 11B9;C45A;110A 116D 11B9; # (쑚; 쑚; 쑚; 쑚; 쑚; ) HANGUL SYLLABLE SSYOBS +C45B;C45B;110A 116D 11BA;C45B;110A 116D 11BA; # (쑛; 쑛; 쑛; 쑛; 쑛; ) HANGUL SYLLABLE SSYOS +C45C;C45C;110A 116D 11BB;C45C;110A 116D 11BB; # (쑜; 쑜; 쑜; 쑜; 쑜; ) HANGUL SYLLABLE SSYOSS +C45D;C45D;110A 116D 11BC;C45D;110A 116D 11BC; # (쑝; 쑝; 쑝; 쑝; 쑝; ) HANGUL SYLLABLE SSYONG +C45E;C45E;110A 116D 11BD;C45E;110A 116D 11BD; # (쑞; 쑞; 쑞; 쑞; 쑞; ) HANGUL SYLLABLE SSYOJ +C45F;C45F;110A 116D 11BE;C45F;110A 116D 11BE; # (쑟; 쑟; 쑟; 쑟; 쑟; ) HANGUL SYLLABLE SSYOC +C460;C460;110A 116D 11BF;C460;110A 116D 11BF; # (쑠; 쑠; 쑠; 쑠; 쑠; ) HANGUL SYLLABLE SSYOK +C461;C461;110A 116D 11C0;C461;110A 116D 11C0; # (쑡; 쑡; 쑡; 쑡; 쑡; ) HANGUL SYLLABLE SSYOT +C462;C462;110A 116D 11C1;C462;110A 116D 11C1; # (쑢; 쑢; 쑢; 쑢; 쑢; ) HANGUL SYLLABLE SSYOP +C463;C463;110A 116D 11C2;C463;110A 116D 11C2; # (쑣; 쑣; 쑣; 쑣; 쑣; ) HANGUL SYLLABLE SSYOH +C464;C464;110A 116E;C464;110A 116E; # (쑤; 쑤; 쑤; 쑤; 쑤; ) HANGUL SYLLABLE SSU +C465;C465;110A 116E 11A8;C465;110A 116E 11A8; # (쑥; 쑥; 쑥; 쑥; 쑥; ) HANGUL SYLLABLE SSUG +C466;C466;110A 116E 11A9;C466;110A 116E 11A9; # (쑦; 쑦; 쑦; 쑦; 쑦; ) HANGUL SYLLABLE SSUGG +C467;C467;110A 116E 11AA;C467;110A 116E 11AA; # (쑧; 쑧; 쑧; 쑧; 쑧; ) HANGUL SYLLABLE SSUGS +C468;C468;110A 116E 11AB;C468;110A 116E 11AB; # (쑨; 쑨; 쑨; 쑨; 쑨; ) HANGUL SYLLABLE SSUN +C469;C469;110A 116E 11AC;C469;110A 116E 11AC; # (쑩; 쑩; 쑩; 쑩; 쑩; ) HANGUL SYLLABLE SSUNJ +C46A;C46A;110A 116E 11AD;C46A;110A 116E 11AD; # (쑪; 쑪; 쑪; 쑪; 쑪; ) HANGUL SYLLABLE SSUNH +C46B;C46B;110A 116E 11AE;C46B;110A 116E 11AE; # (쑫; 쑫; 쑫; 쑫; 쑫; ) HANGUL SYLLABLE SSUD +C46C;C46C;110A 116E 11AF;C46C;110A 116E 11AF; # (쑬; 쑬; 쑬; 쑬; 쑬; ) HANGUL SYLLABLE SSUL +C46D;C46D;110A 116E 11B0;C46D;110A 116E 11B0; # (쑭; 쑭; 쑭; 쑭; 쑭; ) HANGUL SYLLABLE SSULG +C46E;C46E;110A 116E 11B1;C46E;110A 116E 11B1; # (쑮; 쑮; 쑮; 쑮; 쑮; ) HANGUL SYLLABLE SSULM +C46F;C46F;110A 116E 11B2;C46F;110A 116E 11B2; # (쑯; 쑯; 쑯; 쑯; 쑯; ) HANGUL SYLLABLE SSULB +C470;C470;110A 116E 11B3;C470;110A 116E 11B3; # (쑰; 쑰; 쑰; 쑰; 쑰; ) HANGUL SYLLABLE SSULS +C471;C471;110A 116E 11B4;C471;110A 116E 11B4; # (쑱; 쑱; 쑱; 쑱; 쑱; ) HANGUL SYLLABLE SSULT +C472;C472;110A 116E 11B5;C472;110A 116E 11B5; # (쑲; 쑲; 쑲; 쑲; 쑲; ) HANGUL SYLLABLE SSULP +C473;C473;110A 116E 11B6;C473;110A 116E 11B6; # (쑳; 쑳; 쑳; 쑳; 쑳; ) HANGUL SYLLABLE SSULH +C474;C474;110A 116E 11B7;C474;110A 116E 11B7; # (쑴; 쑴; 쑴; 쑴; 쑴; ) HANGUL SYLLABLE SSUM +C475;C475;110A 116E 11B8;C475;110A 116E 11B8; # (쑵; 쑵; 쑵; 쑵; 쑵; ) HANGUL SYLLABLE SSUB +C476;C476;110A 116E 11B9;C476;110A 116E 11B9; # (쑶; 쑶; 쑶; 쑶; 쑶; ) HANGUL SYLLABLE SSUBS +C477;C477;110A 116E 11BA;C477;110A 116E 11BA; # (쑷; 쑷; 쑷; 쑷; 쑷; ) HANGUL SYLLABLE SSUS +C478;C478;110A 116E 11BB;C478;110A 116E 11BB; # (쑸; 쑸; 쑸; 쑸; 쑸; ) HANGUL SYLLABLE SSUSS +C479;C479;110A 116E 11BC;C479;110A 116E 11BC; # (쑹; 쑹; 쑹; 쑹; 쑹; ) HANGUL SYLLABLE SSUNG +C47A;C47A;110A 116E 11BD;C47A;110A 116E 11BD; # (쑺; 쑺; 쑺; 쑺; 쑺; ) HANGUL SYLLABLE SSUJ +C47B;C47B;110A 116E 11BE;C47B;110A 116E 11BE; # (쑻; 쑻; 쑻; 쑻; 쑻; ) HANGUL SYLLABLE SSUC +C47C;C47C;110A 116E 11BF;C47C;110A 116E 11BF; # (쑼; 쑼; 쑼; 쑼; 쑼; ) HANGUL SYLLABLE SSUK +C47D;C47D;110A 116E 11C0;C47D;110A 116E 11C0; # (쑽; 쑽; 쑽; 쑽; 쑽; ) HANGUL SYLLABLE SSUT +C47E;C47E;110A 116E 11C1;C47E;110A 116E 11C1; # (쑾; 쑾; 쑾; 쑾; 쑾; ) HANGUL SYLLABLE SSUP +C47F;C47F;110A 116E 11C2;C47F;110A 116E 11C2; # (쑿; 쑿; 쑿; 쑿; 쑿; ) HANGUL SYLLABLE SSUH +C480;C480;110A 116F;C480;110A 116F; # (쒀; 쒀; 쒀; 쒀; 쒀; ) HANGUL SYLLABLE SSWEO +C481;C481;110A 116F 11A8;C481;110A 116F 11A8; # (쒁; 쒁; 쒁; 쒁; 쒁; ) HANGUL SYLLABLE SSWEOG +C482;C482;110A 116F 11A9;C482;110A 116F 11A9; # (쒂; 쒂; 쒂; 쒂; 쒂; ) HANGUL SYLLABLE SSWEOGG +C483;C483;110A 116F 11AA;C483;110A 116F 11AA; # (쒃; 쒃; 쒃; 쒃; 쒃; ) HANGUL SYLLABLE SSWEOGS +C484;C484;110A 116F 11AB;C484;110A 116F 11AB; # (쒄; 쒄; 쒄; 쒄; 쒄; ) HANGUL SYLLABLE SSWEON +C485;C485;110A 116F 11AC;C485;110A 116F 11AC; # (쒅; 쒅; 쒅; 쒅; 쒅; ) HANGUL SYLLABLE SSWEONJ +C486;C486;110A 116F 11AD;C486;110A 116F 11AD; # (쒆; 쒆; 쒆; 쒆; 쒆; ) HANGUL SYLLABLE SSWEONH +C487;C487;110A 116F 11AE;C487;110A 116F 11AE; # (쒇; 쒇; 쒇; 쒇; 쒇; ) HANGUL SYLLABLE SSWEOD +C488;C488;110A 116F 11AF;C488;110A 116F 11AF; # (쒈; 쒈; 쒈; 쒈; 쒈; ) HANGUL SYLLABLE SSWEOL +C489;C489;110A 116F 11B0;C489;110A 116F 11B0; # (쒉; 쒉; 쒉; 쒉; 쒉; ) HANGUL SYLLABLE SSWEOLG +C48A;C48A;110A 116F 11B1;C48A;110A 116F 11B1; # (쒊; 쒊; 쒊; 쒊; 쒊; ) HANGUL SYLLABLE SSWEOLM +C48B;C48B;110A 116F 11B2;C48B;110A 116F 11B2; # (쒋; 쒋; 쒋; 쒋; 쒋; ) HANGUL SYLLABLE SSWEOLB +C48C;C48C;110A 116F 11B3;C48C;110A 116F 11B3; # (쒌; 쒌; 쒌; 쒌; 쒌; ) HANGUL SYLLABLE SSWEOLS +C48D;C48D;110A 116F 11B4;C48D;110A 116F 11B4; # (쒍; 쒍; 쒍; 쒍; 쒍; ) HANGUL SYLLABLE SSWEOLT +C48E;C48E;110A 116F 11B5;C48E;110A 116F 11B5; # (쒎; 쒎; 쒎; 쒎; 쒎; ) HANGUL SYLLABLE SSWEOLP +C48F;C48F;110A 116F 11B6;C48F;110A 116F 11B6; # (쒏; 쒏; 쒏; 쒏; 쒏; ) HANGUL SYLLABLE SSWEOLH +C490;C490;110A 116F 11B7;C490;110A 116F 11B7; # (쒐; 쒐; 쒐; 쒐; 쒐; ) HANGUL SYLLABLE SSWEOM +C491;C491;110A 116F 11B8;C491;110A 116F 11B8; # (쒑; 쒑; 쒑; 쒑; 쒑; ) HANGUL SYLLABLE SSWEOB +C492;C492;110A 116F 11B9;C492;110A 116F 11B9; # (쒒; 쒒; 쒒; 쒒; 쒒; ) HANGUL SYLLABLE SSWEOBS +C493;C493;110A 116F 11BA;C493;110A 116F 11BA; # (쒓; 쒓; 쒓; 쒓; 쒓; ) HANGUL SYLLABLE SSWEOS +C494;C494;110A 116F 11BB;C494;110A 116F 11BB; # (쒔; 쒔; 쒔; 쒔; 쒔; ) HANGUL SYLLABLE SSWEOSS +C495;C495;110A 116F 11BC;C495;110A 116F 11BC; # (쒕; 쒕; 쒕; 쒕; 쒕; ) HANGUL SYLLABLE SSWEONG +C496;C496;110A 116F 11BD;C496;110A 116F 11BD; # (쒖; 쒖; 쒖; 쒖; 쒖; ) HANGUL SYLLABLE SSWEOJ +C497;C497;110A 116F 11BE;C497;110A 116F 11BE; # (쒗; 쒗; 쒗; 쒗; 쒗; ) HANGUL SYLLABLE SSWEOC +C498;C498;110A 116F 11BF;C498;110A 116F 11BF; # (쒘; 쒘; 쒘; 쒘; 쒘; ) HANGUL SYLLABLE SSWEOK +C499;C499;110A 116F 11C0;C499;110A 116F 11C0; # (쒙; 쒙; 쒙; 쒙; 쒙; ) HANGUL SYLLABLE SSWEOT +C49A;C49A;110A 116F 11C1;C49A;110A 116F 11C1; # (쒚; 쒚; 쒚; 쒚; 쒚; ) HANGUL SYLLABLE SSWEOP +C49B;C49B;110A 116F 11C2;C49B;110A 116F 11C2; # (쒛; 쒛; 쒛; 쒛; 쒛; ) HANGUL SYLLABLE SSWEOH +C49C;C49C;110A 1170;C49C;110A 1170; # (쒜; 쒜; 쒜; 쒜; 쒜; ) HANGUL SYLLABLE SSWE +C49D;C49D;110A 1170 11A8;C49D;110A 1170 11A8; # (쒝; 쒝; 쒝; 쒝; 쒝; ) HANGUL SYLLABLE SSWEG +C49E;C49E;110A 1170 11A9;C49E;110A 1170 11A9; # (쒞; 쒞; 쒞; 쒞; 쒞; ) HANGUL SYLLABLE SSWEGG +C49F;C49F;110A 1170 11AA;C49F;110A 1170 11AA; # (쒟; 쒟; 쒟; 쒟; 쒟; ) HANGUL SYLLABLE SSWEGS +C4A0;C4A0;110A 1170 11AB;C4A0;110A 1170 11AB; # (쒠; 쒠; 쒠; 쒠; 쒠; ) HANGUL SYLLABLE SSWEN +C4A1;C4A1;110A 1170 11AC;C4A1;110A 1170 11AC; # (쒡; 쒡; 쒡; 쒡; 쒡; ) HANGUL SYLLABLE SSWENJ +C4A2;C4A2;110A 1170 11AD;C4A2;110A 1170 11AD; # (쒢; 쒢; 쒢; 쒢; 쒢; ) HANGUL SYLLABLE SSWENH +C4A3;C4A3;110A 1170 11AE;C4A3;110A 1170 11AE; # (쒣; 쒣; 쒣; 쒣; 쒣; ) HANGUL SYLLABLE SSWED +C4A4;C4A4;110A 1170 11AF;C4A4;110A 1170 11AF; # (쒤; 쒤; 쒤; 쒤; 쒤; ) HANGUL SYLLABLE SSWEL +C4A5;C4A5;110A 1170 11B0;C4A5;110A 1170 11B0; # (쒥; 쒥; 쒥; 쒥; 쒥; ) HANGUL SYLLABLE SSWELG +C4A6;C4A6;110A 1170 11B1;C4A6;110A 1170 11B1; # (쒦; 쒦; 쒦; 쒦; 쒦; ) HANGUL SYLLABLE SSWELM +C4A7;C4A7;110A 1170 11B2;C4A7;110A 1170 11B2; # (쒧; 쒧; 쒧; 쒧; 쒧; ) HANGUL SYLLABLE SSWELB +C4A8;C4A8;110A 1170 11B3;C4A8;110A 1170 11B3; # (쒨; 쒨; 쒨; 쒨; 쒨; ) HANGUL SYLLABLE SSWELS +C4A9;C4A9;110A 1170 11B4;C4A9;110A 1170 11B4; # (쒩; 쒩; 쒩; 쒩; 쒩; ) HANGUL SYLLABLE SSWELT +C4AA;C4AA;110A 1170 11B5;C4AA;110A 1170 11B5; # (쒪; 쒪; 쒪; 쒪; 쒪; ) HANGUL SYLLABLE SSWELP +C4AB;C4AB;110A 1170 11B6;C4AB;110A 1170 11B6; # (쒫; 쒫; 쒫; 쒫; 쒫; ) HANGUL SYLLABLE SSWELH +C4AC;C4AC;110A 1170 11B7;C4AC;110A 1170 11B7; # (쒬; 쒬; 쒬; 쒬; 쒬; ) HANGUL SYLLABLE SSWEM +C4AD;C4AD;110A 1170 11B8;C4AD;110A 1170 11B8; # (쒭; 쒭; 쒭; 쒭; 쒭; ) HANGUL SYLLABLE SSWEB +C4AE;C4AE;110A 1170 11B9;C4AE;110A 1170 11B9; # (쒮; 쒮; 쒮; 쒮; 쒮; ) HANGUL SYLLABLE SSWEBS +C4AF;C4AF;110A 1170 11BA;C4AF;110A 1170 11BA; # (쒯; 쒯; 쒯; 쒯; 쒯; ) HANGUL SYLLABLE SSWES +C4B0;C4B0;110A 1170 11BB;C4B0;110A 1170 11BB; # (쒰; 쒰; 쒰; 쒰; 쒰; ) HANGUL SYLLABLE SSWESS +C4B1;C4B1;110A 1170 11BC;C4B1;110A 1170 11BC; # (쒱; 쒱; 쒱; 쒱; 쒱; ) HANGUL SYLLABLE SSWENG +C4B2;C4B2;110A 1170 11BD;C4B2;110A 1170 11BD; # (쒲; 쒲; 쒲; 쒲; 쒲; ) HANGUL SYLLABLE SSWEJ +C4B3;C4B3;110A 1170 11BE;C4B3;110A 1170 11BE; # (쒳; 쒳; 쒳; 쒳; 쒳; ) HANGUL SYLLABLE SSWEC +C4B4;C4B4;110A 1170 11BF;C4B4;110A 1170 11BF; # (쒴; 쒴; 쒴; 쒴; 쒴; ) HANGUL SYLLABLE SSWEK +C4B5;C4B5;110A 1170 11C0;C4B5;110A 1170 11C0; # (쒵; 쒵; 쒵; 쒵; 쒵; ) HANGUL SYLLABLE SSWET +C4B6;C4B6;110A 1170 11C1;C4B6;110A 1170 11C1; # (쒶; 쒶; 쒶; 쒶; 쒶; ) HANGUL SYLLABLE SSWEP +C4B7;C4B7;110A 1170 11C2;C4B7;110A 1170 11C2; # (쒷; 쒷; 쒷; 쒷; 쒷; ) HANGUL SYLLABLE SSWEH +C4B8;C4B8;110A 1171;C4B8;110A 1171; # (쒸; 쒸; 쒸; 쒸; 쒸; ) HANGUL SYLLABLE SSWI +C4B9;C4B9;110A 1171 11A8;C4B9;110A 1171 11A8; # (쒹; 쒹; 쒹; 쒹; 쒹; ) HANGUL SYLLABLE SSWIG +C4BA;C4BA;110A 1171 11A9;C4BA;110A 1171 11A9; # (쒺; 쒺; 쒺; 쒺; 쒺; ) HANGUL SYLLABLE SSWIGG +C4BB;C4BB;110A 1171 11AA;C4BB;110A 1171 11AA; # (쒻; 쒻; 쒻; 쒻; 쒻; ) HANGUL SYLLABLE SSWIGS +C4BC;C4BC;110A 1171 11AB;C4BC;110A 1171 11AB; # (쒼; 쒼; 쒼; 쒼; 쒼; ) HANGUL SYLLABLE SSWIN +C4BD;C4BD;110A 1171 11AC;C4BD;110A 1171 11AC; # (쒽; 쒽; 쒽; 쒽; 쒽; ) HANGUL SYLLABLE SSWINJ +C4BE;C4BE;110A 1171 11AD;C4BE;110A 1171 11AD; # (쒾; 쒾; 쒾; 쒾; 쒾; ) HANGUL SYLLABLE SSWINH +C4BF;C4BF;110A 1171 11AE;C4BF;110A 1171 11AE; # (쒿; 쒿; 쒿; 쒿; 쒿; ) HANGUL SYLLABLE SSWID +C4C0;C4C0;110A 1171 11AF;C4C0;110A 1171 11AF; # (쓀; 쓀; 쓀; 쓀; 쓀; ) HANGUL SYLLABLE SSWIL +C4C1;C4C1;110A 1171 11B0;C4C1;110A 1171 11B0; # (쓁; 쓁; 쓁; 쓁; 쓁; ) HANGUL SYLLABLE SSWILG +C4C2;C4C2;110A 1171 11B1;C4C2;110A 1171 11B1; # (쓂; 쓂; 쓂; 쓂; 쓂; ) HANGUL SYLLABLE SSWILM +C4C3;C4C3;110A 1171 11B2;C4C3;110A 1171 11B2; # (쓃; 쓃; 쓃; 쓃; 쓃; ) HANGUL SYLLABLE SSWILB +C4C4;C4C4;110A 1171 11B3;C4C4;110A 1171 11B3; # (쓄; 쓄; 쓄; 쓄; 쓄; ) HANGUL SYLLABLE SSWILS +C4C5;C4C5;110A 1171 11B4;C4C5;110A 1171 11B4; # (쓅; 쓅; 쓅; 쓅; 쓅; ) HANGUL SYLLABLE SSWILT +C4C6;C4C6;110A 1171 11B5;C4C6;110A 1171 11B5; # (쓆; 쓆; 쓆; 쓆; 쓆; ) HANGUL SYLLABLE SSWILP +C4C7;C4C7;110A 1171 11B6;C4C7;110A 1171 11B6; # (쓇; 쓇; 쓇; 쓇; 쓇; ) HANGUL SYLLABLE SSWILH +C4C8;C4C8;110A 1171 11B7;C4C8;110A 1171 11B7; # (쓈; 쓈; 쓈; 쓈; 쓈; ) HANGUL SYLLABLE SSWIM +C4C9;C4C9;110A 1171 11B8;C4C9;110A 1171 11B8; # (쓉; 쓉; 쓉; 쓉; 쓉; ) HANGUL SYLLABLE SSWIB +C4CA;C4CA;110A 1171 11B9;C4CA;110A 1171 11B9; # (쓊; 쓊; 쓊; 쓊; 쓊; ) HANGUL SYLLABLE SSWIBS +C4CB;C4CB;110A 1171 11BA;C4CB;110A 1171 11BA; # (쓋; 쓋; 쓋; 쓋; 쓋; ) HANGUL SYLLABLE SSWIS +C4CC;C4CC;110A 1171 11BB;C4CC;110A 1171 11BB; # (쓌; 쓌; 쓌; 쓌; 쓌; ) HANGUL SYLLABLE SSWISS +C4CD;C4CD;110A 1171 11BC;C4CD;110A 1171 11BC; # (쓍; 쓍; 쓍; 쓍; 쓍; ) HANGUL SYLLABLE SSWING +C4CE;C4CE;110A 1171 11BD;C4CE;110A 1171 11BD; # (쓎; 쓎; 쓎; 쓎; 쓎; ) HANGUL SYLLABLE SSWIJ +C4CF;C4CF;110A 1171 11BE;C4CF;110A 1171 11BE; # (쓏; 쓏; 쓏; 쓏; 쓏; ) HANGUL SYLLABLE SSWIC +C4D0;C4D0;110A 1171 11BF;C4D0;110A 1171 11BF; # (쓐; 쓐; 쓐; 쓐; 쓐; ) HANGUL SYLLABLE SSWIK +C4D1;C4D1;110A 1171 11C0;C4D1;110A 1171 11C0; # (쓑; 쓑; 쓑; 쓑; 쓑; ) HANGUL SYLLABLE SSWIT +C4D2;C4D2;110A 1171 11C1;C4D2;110A 1171 11C1; # (쓒; 쓒; 쓒; 쓒; 쓒; ) HANGUL SYLLABLE SSWIP +C4D3;C4D3;110A 1171 11C2;C4D3;110A 1171 11C2; # (쓓; 쓓; 쓓; 쓓; 쓓; ) HANGUL SYLLABLE SSWIH +C4D4;C4D4;110A 1172;C4D4;110A 1172; # (쓔; 쓔; 쓔; 쓔; 쓔; ) HANGUL SYLLABLE SSYU +C4D5;C4D5;110A 1172 11A8;C4D5;110A 1172 11A8; # (쓕; 쓕; 쓕; 쓕; 쓕; ) HANGUL SYLLABLE SSYUG +C4D6;C4D6;110A 1172 11A9;C4D6;110A 1172 11A9; # (쓖; 쓖; 쓖; 쓖; 쓖; ) HANGUL SYLLABLE SSYUGG +C4D7;C4D7;110A 1172 11AA;C4D7;110A 1172 11AA; # (쓗; 쓗; 쓗; 쓗; 쓗; ) HANGUL SYLLABLE SSYUGS +C4D8;C4D8;110A 1172 11AB;C4D8;110A 1172 11AB; # (쓘; 쓘; 쓘; 쓘; 쓘; ) HANGUL SYLLABLE SSYUN +C4D9;C4D9;110A 1172 11AC;C4D9;110A 1172 11AC; # (쓙; 쓙; 쓙; 쓙; 쓙; ) HANGUL SYLLABLE SSYUNJ +C4DA;C4DA;110A 1172 11AD;C4DA;110A 1172 11AD; # (쓚; 쓚; 쓚; 쓚; 쓚; ) HANGUL SYLLABLE SSYUNH +C4DB;C4DB;110A 1172 11AE;C4DB;110A 1172 11AE; # (쓛; 쓛; 쓛; 쓛; 쓛; ) HANGUL SYLLABLE SSYUD +C4DC;C4DC;110A 1172 11AF;C4DC;110A 1172 11AF; # (쓜; 쓜; 쓜; 쓜; 쓜; ) HANGUL SYLLABLE SSYUL +C4DD;C4DD;110A 1172 11B0;C4DD;110A 1172 11B0; # (쓝; 쓝; 쓝; 쓝; 쓝; ) HANGUL SYLLABLE SSYULG +C4DE;C4DE;110A 1172 11B1;C4DE;110A 1172 11B1; # (쓞; 쓞; 쓞; 쓞; 쓞; ) HANGUL SYLLABLE SSYULM +C4DF;C4DF;110A 1172 11B2;C4DF;110A 1172 11B2; # (쓟; 쓟; 쓟; 쓟; 쓟; ) HANGUL SYLLABLE SSYULB +C4E0;C4E0;110A 1172 11B3;C4E0;110A 1172 11B3; # (쓠; 쓠; 쓠; 쓠; 쓠; ) HANGUL SYLLABLE SSYULS +C4E1;C4E1;110A 1172 11B4;C4E1;110A 1172 11B4; # (쓡; 쓡; 쓡; 쓡; 쓡; ) HANGUL SYLLABLE SSYULT +C4E2;C4E2;110A 1172 11B5;C4E2;110A 1172 11B5; # (쓢; 쓢; 쓢; 쓢; 쓢; ) HANGUL SYLLABLE SSYULP +C4E3;C4E3;110A 1172 11B6;C4E3;110A 1172 11B6; # (쓣; 쓣; 쓣; 쓣; 쓣; ) HANGUL SYLLABLE SSYULH +C4E4;C4E4;110A 1172 11B7;C4E4;110A 1172 11B7; # (쓤; 쓤; 쓤; 쓤; 쓤; ) HANGUL SYLLABLE SSYUM +C4E5;C4E5;110A 1172 11B8;C4E5;110A 1172 11B8; # (쓥; 쓥; 쓥; 쓥; 쓥; ) HANGUL SYLLABLE SSYUB +C4E6;C4E6;110A 1172 11B9;C4E6;110A 1172 11B9; # (쓦; 쓦; 쓦; 쓦; 쓦; ) HANGUL SYLLABLE SSYUBS +C4E7;C4E7;110A 1172 11BA;C4E7;110A 1172 11BA; # (쓧; 쓧; 쓧; 쓧; 쓧; ) HANGUL SYLLABLE SSYUS +C4E8;C4E8;110A 1172 11BB;C4E8;110A 1172 11BB; # (쓨; 쓨; 쓨; 쓨; 쓨; ) HANGUL SYLLABLE SSYUSS +C4E9;C4E9;110A 1172 11BC;C4E9;110A 1172 11BC; # (쓩; 쓩; 쓩; 쓩; 쓩; ) HANGUL SYLLABLE SSYUNG +C4EA;C4EA;110A 1172 11BD;C4EA;110A 1172 11BD; # (쓪; 쓪; 쓪; 쓪; 쓪; ) HANGUL SYLLABLE SSYUJ +C4EB;C4EB;110A 1172 11BE;C4EB;110A 1172 11BE; # (쓫; 쓫; 쓫; 쓫; 쓫; ) HANGUL SYLLABLE SSYUC +C4EC;C4EC;110A 1172 11BF;C4EC;110A 1172 11BF; # (쓬; 쓬; 쓬; 쓬; 쓬; ) HANGUL SYLLABLE SSYUK +C4ED;C4ED;110A 1172 11C0;C4ED;110A 1172 11C0; # (쓭; 쓭; 쓭; 쓭; 쓭; ) HANGUL SYLLABLE SSYUT +C4EE;C4EE;110A 1172 11C1;C4EE;110A 1172 11C1; # (쓮; 쓮; 쓮; 쓮; 쓮; ) HANGUL SYLLABLE SSYUP +C4EF;C4EF;110A 1172 11C2;C4EF;110A 1172 11C2; # (쓯; 쓯; 쓯; 쓯; 쓯; ) HANGUL SYLLABLE SSYUH +C4F0;C4F0;110A 1173;C4F0;110A 1173; # (쓰; 쓰; 쓰; 쓰; 쓰; ) HANGUL SYLLABLE SSEU +C4F1;C4F1;110A 1173 11A8;C4F1;110A 1173 11A8; # (쓱; 쓱; 쓱; 쓱; 쓱; ) HANGUL SYLLABLE SSEUG +C4F2;C4F2;110A 1173 11A9;C4F2;110A 1173 11A9; # (쓲; 쓲; 쓲; 쓲; 쓲; ) HANGUL SYLLABLE SSEUGG +C4F3;C4F3;110A 1173 11AA;C4F3;110A 1173 11AA; # (쓳; 쓳; 쓳; 쓳; 쓳; ) HANGUL SYLLABLE SSEUGS +C4F4;C4F4;110A 1173 11AB;C4F4;110A 1173 11AB; # (쓴; 쓴; 쓴; 쓴; 쓴; ) HANGUL SYLLABLE SSEUN +C4F5;C4F5;110A 1173 11AC;C4F5;110A 1173 11AC; # (쓵; 쓵; 쓵; 쓵; 쓵; ) HANGUL SYLLABLE SSEUNJ +C4F6;C4F6;110A 1173 11AD;C4F6;110A 1173 11AD; # (쓶; 쓶; 쓶; 쓶; 쓶; ) HANGUL SYLLABLE SSEUNH +C4F7;C4F7;110A 1173 11AE;C4F7;110A 1173 11AE; # (쓷; 쓷; 쓷; 쓷; 쓷; ) HANGUL SYLLABLE SSEUD +C4F8;C4F8;110A 1173 11AF;C4F8;110A 1173 11AF; # (쓸; 쓸; 쓸; 쓸; 쓸; ) HANGUL SYLLABLE SSEUL +C4F9;C4F9;110A 1173 11B0;C4F9;110A 1173 11B0; # (쓹; 쓹; 쓹; 쓹; 쓹; ) HANGUL SYLLABLE SSEULG +C4FA;C4FA;110A 1173 11B1;C4FA;110A 1173 11B1; # (쓺; 쓺; 쓺; 쓺; 쓺; ) HANGUL SYLLABLE SSEULM +C4FB;C4FB;110A 1173 11B2;C4FB;110A 1173 11B2; # (쓻; 쓻; 쓻; 쓻; 쓻; ) HANGUL SYLLABLE SSEULB +C4FC;C4FC;110A 1173 11B3;C4FC;110A 1173 11B3; # (쓼; 쓼; 쓼; 쓼; 쓼; ) HANGUL SYLLABLE SSEULS +C4FD;C4FD;110A 1173 11B4;C4FD;110A 1173 11B4; # (쓽; 쓽; 쓽; 쓽; 쓽; ) HANGUL SYLLABLE SSEULT +C4FE;C4FE;110A 1173 11B5;C4FE;110A 1173 11B5; # (쓾; 쓾; 쓾; 쓾; 쓾; ) HANGUL SYLLABLE SSEULP +C4FF;C4FF;110A 1173 11B6;C4FF;110A 1173 11B6; # (쓿; 쓿; 쓿; 쓿; 쓿; ) HANGUL SYLLABLE SSEULH +C500;C500;110A 1173 11B7;C500;110A 1173 11B7; # (씀; 씀; 씀; 씀; 씀; ) HANGUL SYLLABLE SSEUM +C501;C501;110A 1173 11B8;C501;110A 1173 11B8; # (씁; 씁; 씁; 씁; 씁; ) HANGUL SYLLABLE SSEUB +C502;C502;110A 1173 11B9;C502;110A 1173 11B9; # (씂; 씂; 씂; 씂; 씂; ) HANGUL SYLLABLE SSEUBS +C503;C503;110A 1173 11BA;C503;110A 1173 11BA; # (씃; 씃; 씃; 씃; 씃; ) HANGUL SYLLABLE SSEUS +C504;C504;110A 1173 11BB;C504;110A 1173 11BB; # (씄; 씄; 씄; 씄; 씄; ) HANGUL SYLLABLE SSEUSS +C505;C505;110A 1173 11BC;C505;110A 1173 11BC; # (씅; 씅; 씅; 씅; 씅; ) HANGUL SYLLABLE SSEUNG +C506;C506;110A 1173 11BD;C506;110A 1173 11BD; # (씆; 씆; 씆; 씆; 씆; ) HANGUL SYLLABLE SSEUJ +C507;C507;110A 1173 11BE;C507;110A 1173 11BE; # (씇; 씇; 씇; 씇; 씇; ) HANGUL SYLLABLE SSEUC +C508;C508;110A 1173 11BF;C508;110A 1173 11BF; # (씈; 씈; 씈; 씈; 씈; ) HANGUL SYLLABLE SSEUK +C509;C509;110A 1173 11C0;C509;110A 1173 11C0; # (씉; 씉; 씉; 씉; 씉; ) HANGUL SYLLABLE SSEUT +C50A;C50A;110A 1173 11C1;C50A;110A 1173 11C1; # (씊; 씊; 씊; 씊; 씊; ) HANGUL SYLLABLE SSEUP +C50B;C50B;110A 1173 11C2;C50B;110A 1173 11C2; # (씋; 씋; 씋; 씋; 씋; ) HANGUL SYLLABLE SSEUH +C50C;C50C;110A 1174;C50C;110A 1174; # (씌; 씌; 씌; 씌; 씌; ) HANGUL SYLLABLE SSYI +C50D;C50D;110A 1174 11A8;C50D;110A 1174 11A8; # (씍; 씍; 씍; 씍; 씍; ) HANGUL SYLLABLE SSYIG +C50E;C50E;110A 1174 11A9;C50E;110A 1174 11A9; # (씎; 씎; 씎; 씎; 씎; ) HANGUL SYLLABLE SSYIGG +C50F;C50F;110A 1174 11AA;C50F;110A 1174 11AA; # (씏; 씏; 씏; 씏; 씏; ) HANGUL SYLLABLE SSYIGS +C510;C510;110A 1174 11AB;C510;110A 1174 11AB; # (씐; 씐; 씐; 씐; 씐; ) HANGUL SYLLABLE SSYIN +C511;C511;110A 1174 11AC;C511;110A 1174 11AC; # (씑; 씑; 씑; 씑; 씑; ) HANGUL SYLLABLE SSYINJ +C512;C512;110A 1174 11AD;C512;110A 1174 11AD; # (씒; 씒; 씒; 씒; 씒; ) HANGUL SYLLABLE SSYINH +C513;C513;110A 1174 11AE;C513;110A 1174 11AE; # (씓; 씓; 씓; 씓; 씓; ) HANGUL SYLLABLE SSYID +C514;C514;110A 1174 11AF;C514;110A 1174 11AF; # (씔; 씔; 씔; 씔; 씔; ) HANGUL SYLLABLE SSYIL +C515;C515;110A 1174 11B0;C515;110A 1174 11B0; # (씕; 씕; 씕; 씕; 씕; ) HANGUL SYLLABLE SSYILG +C516;C516;110A 1174 11B1;C516;110A 1174 11B1; # (씖; 씖; 씖; 씖; 씖; ) HANGUL SYLLABLE SSYILM +C517;C517;110A 1174 11B2;C517;110A 1174 11B2; # (씗; 씗; 씗; 씗; 씗; ) HANGUL SYLLABLE SSYILB +C518;C518;110A 1174 11B3;C518;110A 1174 11B3; # (씘; 씘; 씘; 씘; 씘; ) HANGUL SYLLABLE SSYILS +C519;C519;110A 1174 11B4;C519;110A 1174 11B4; # (씙; 씙; 씙; 씙; 씙; ) HANGUL SYLLABLE SSYILT +C51A;C51A;110A 1174 11B5;C51A;110A 1174 11B5; # (씚; 씚; 씚; 씚; 씚; ) HANGUL SYLLABLE SSYILP +C51B;C51B;110A 1174 11B6;C51B;110A 1174 11B6; # (씛; 씛; 씛; 씛; 씛; ) HANGUL SYLLABLE SSYILH +C51C;C51C;110A 1174 11B7;C51C;110A 1174 11B7; # (씜; 씜; 씜; 씜; 씜; ) HANGUL SYLLABLE SSYIM +C51D;C51D;110A 1174 11B8;C51D;110A 1174 11B8; # (씝; 씝; 씝; 씝; 씝; ) HANGUL SYLLABLE SSYIB +C51E;C51E;110A 1174 11B9;C51E;110A 1174 11B9; # (씞; 씞; 씞; 씞; 씞; ) HANGUL SYLLABLE SSYIBS +C51F;C51F;110A 1174 11BA;C51F;110A 1174 11BA; # (씟; 씟; 씟; 씟; 씟; ) HANGUL SYLLABLE SSYIS +C520;C520;110A 1174 11BB;C520;110A 1174 11BB; # (씠; 씠; 씠; 씠; 씠; ) HANGUL SYLLABLE SSYISS +C521;C521;110A 1174 11BC;C521;110A 1174 11BC; # (씡; 씡; 씡; 씡; 씡; ) HANGUL SYLLABLE SSYING +C522;C522;110A 1174 11BD;C522;110A 1174 11BD; # (씢; 씢; 씢; 씢; 씢; ) HANGUL SYLLABLE SSYIJ +C523;C523;110A 1174 11BE;C523;110A 1174 11BE; # (씣; 씣; 씣; 씣; 씣; ) HANGUL SYLLABLE SSYIC +C524;C524;110A 1174 11BF;C524;110A 1174 11BF; # (씤; 씤; 씤; 씤; 씤; ) HANGUL SYLLABLE SSYIK +C525;C525;110A 1174 11C0;C525;110A 1174 11C0; # (씥; 씥; 씥; 씥; 씥; ) HANGUL SYLLABLE SSYIT +C526;C526;110A 1174 11C1;C526;110A 1174 11C1; # (씦; 씦; 씦; 씦; 씦; ) HANGUL SYLLABLE SSYIP +C527;C527;110A 1174 11C2;C527;110A 1174 11C2; # (씧; 씧; 씧; 씧; 씧; ) HANGUL SYLLABLE SSYIH +C528;C528;110A 1175;C528;110A 1175; # (씨; 씨; 씨; 씨; 씨; ) HANGUL SYLLABLE SSI +C529;C529;110A 1175 11A8;C529;110A 1175 11A8; # (씩; 씩; 씩; 씩; 씩; ) HANGUL SYLLABLE SSIG +C52A;C52A;110A 1175 11A9;C52A;110A 1175 11A9; # (씪; 씪; 씪; 씪; 씪; ) HANGUL SYLLABLE SSIGG +C52B;C52B;110A 1175 11AA;C52B;110A 1175 11AA; # (씫; 씫; 씫; 씫; 씫; ) HANGUL SYLLABLE SSIGS +C52C;C52C;110A 1175 11AB;C52C;110A 1175 11AB; # (씬; 씬; 씬; 씬; 씬; ) HANGUL SYLLABLE SSIN +C52D;C52D;110A 1175 11AC;C52D;110A 1175 11AC; # (씭; 씭; 씭; 씭; 씭; ) HANGUL SYLLABLE SSINJ +C52E;C52E;110A 1175 11AD;C52E;110A 1175 11AD; # (씮; 씮; 씮; 씮; 씮; ) HANGUL SYLLABLE SSINH +C52F;C52F;110A 1175 11AE;C52F;110A 1175 11AE; # (씯; 씯; 씯; 씯; 씯; ) HANGUL SYLLABLE SSID +C530;C530;110A 1175 11AF;C530;110A 1175 11AF; # (씰; 씰; 씰; 씰; 씰; ) HANGUL SYLLABLE SSIL +C531;C531;110A 1175 11B0;C531;110A 1175 11B0; # (씱; 씱; 씱; 씱; 씱; ) HANGUL SYLLABLE SSILG +C532;C532;110A 1175 11B1;C532;110A 1175 11B1; # (씲; 씲; 씲; 씲; 씲; ) HANGUL SYLLABLE SSILM +C533;C533;110A 1175 11B2;C533;110A 1175 11B2; # (씳; 씳; 씳; 씳; 씳; ) HANGUL SYLLABLE SSILB +C534;C534;110A 1175 11B3;C534;110A 1175 11B3; # (씴; 씴; 씴; 씴; 씴; ) HANGUL SYLLABLE SSILS +C535;C535;110A 1175 11B4;C535;110A 1175 11B4; # (씵; 씵; 씵; 씵; 씵; ) HANGUL SYLLABLE SSILT +C536;C536;110A 1175 11B5;C536;110A 1175 11B5; # (씶; 씶; 씶; 씶; 씶; ) HANGUL SYLLABLE SSILP +C537;C537;110A 1175 11B6;C537;110A 1175 11B6; # (씷; 씷; 씷; 씷; 씷; ) HANGUL SYLLABLE SSILH +C538;C538;110A 1175 11B7;C538;110A 1175 11B7; # (씸; 씸; 씸; 씸; 씸; ) HANGUL SYLLABLE SSIM +C539;C539;110A 1175 11B8;C539;110A 1175 11B8; # (씹; 씹; 씹; 씹; 씹; ) HANGUL SYLLABLE SSIB +C53A;C53A;110A 1175 11B9;C53A;110A 1175 11B9; # (씺; 씺; 씺; 씺; 씺; ) HANGUL SYLLABLE SSIBS +C53B;C53B;110A 1175 11BA;C53B;110A 1175 11BA; # (씻; 씻; 씻; 씻; 씻; ) HANGUL SYLLABLE SSIS +C53C;C53C;110A 1175 11BB;C53C;110A 1175 11BB; # (씼; 씼; 씼; 씼; 씼; ) HANGUL SYLLABLE SSISS +C53D;C53D;110A 1175 11BC;C53D;110A 1175 11BC; # (씽; 씽; 씽; 씽; 씽; ) HANGUL SYLLABLE SSING +C53E;C53E;110A 1175 11BD;C53E;110A 1175 11BD; # (씾; 씾; 씾; 씾; 씾; ) HANGUL SYLLABLE SSIJ +C53F;C53F;110A 1175 11BE;C53F;110A 1175 11BE; # (씿; 씿; 씿; 씿; 씿; ) HANGUL SYLLABLE SSIC +C540;C540;110A 1175 11BF;C540;110A 1175 11BF; # (앀; 앀; 앀; 앀; 앀; ) HANGUL SYLLABLE SSIK +C541;C541;110A 1175 11C0;C541;110A 1175 11C0; # (앁; 앁; 앁; 앁; 앁; ) HANGUL SYLLABLE SSIT +C542;C542;110A 1175 11C1;C542;110A 1175 11C1; # (앂; 앂; 앂; 앂; 앂; ) HANGUL SYLLABLE SSIP +C543;C543;110A 1175 11C2;C543;110A 1175 11C2; # (앃; 앃; 앃; 앃; 앃; ) HANGUL SYLLABLE SSIH +C544;C544;110B 1161;C544;110B 1161; # (아; 아; 아; 아; 아; ) HANGUL SYLLABLE A +C545;C545;110B 1161 11A8;C545;110B 1161 11A8; # (악; 악; 악; 악; 악; ) HANGUL SYLLABLE AG +C546;C546;110B 1161 11A9;C546;110B 1161 11A9; # (앆; 앆; 앆; 앆; 앆; ) HANGUL SYLLABLE AGG +C547;C547;110B 1161 11AA;C547;110B 1161 11AA; # (앇; 앇; 앇; 앇; 앇; ) HANGUL SYLLABLE AGS +C548;C548;110B 1161 11AB;C548;110B 1161 11AB; # (안; 안; 안; 안; 안; ) HANGUL SYLLABLE AN +C549;C549;110B 1161 11AC;C549;110B 1161 11AC; # (앉; 앉; 앉; 앉; 앉; ) HANGUL SYLLABLE ANJ +C54A;C54A;110B 1161 11AD;C54A;110B 1161 11AD; # (않; 않; 않; 않; 않; ) HANGUL SYLLABLE ANH +C54B;C54B;110B 1161 11AE;C54B;110B 1161 11AE; # (앋; 앋; 앋; 앋; 앋; ) HANGUL SYLLABLE AD +C54C;C54C;110B 1161 11AF;C54C;110B 1161 11AF; # (알; 알; 알; 알; 알; ) HANGUL SYLLABLE AL +C54D;C54D;110B 1161 11B0;C54D;110B 1161 11B0; # (앍; 앍; 앍; 앍; 앍; ) HANGUL SYLLABLE ALG +C54E;C54E;110B 1161 11B1;C54E;110B 1161 11B1; # (앎; 앎; 앎; 앎; 앎; ) HANGUL SYLLABLE ALM +C54F;C54F;110B 1161 11B2;C54F;110B 1161 11B2; # (앏; 앏; 앏; 앏; 앏; ) HANGUL SYLLABLE ALB +C550;C550;110B 1161 11B3;C550;110B 1161 11B3; # (앐; 앐; 앐; 앐; 앐; ) HANGUL SYLLABLE ALS +C551;C551;110B 1161 11B4;C551;110B 1161 11B4; # (앑; 앑; 앑; 앑; 앑; ) HANGUL SYLLABLE ALT +C552;C552;110B 1161 11B5;C552;110B 1161 11B5; # (앒; 앒; 앒; 앒; 앒; ) HANGUL SYLLABLE ALP +C553;C553;110B 1161 11B6;C553;110B 1161 11B6; # (앓; 앓; 앓; 앓; 앓; ) HANGUL SYLLABLE ALH +C554;C554;110B 1161 11B7;C554;110B 1161 11B7; # (암; 암; 암; 암; 암; ) HANGUL SYLLABLE AM +C555;C555;110B 1161 11B8;C555;110B 1161 11B8; # (압; 압; 압; 압; 압; ) HANGUL SYLLABLE AB +C556;C556;110B 1161 11B9;C556;110B 1161 11B9; # (앖; 앖; 앖; 앖; 앖; ) HANGUL SYLLABLE ABS +C557;C557;110B 1161 11BA;C557;110B 1161 11BA; # (앗; 앗; 앗; 앗; 앗; ) HANGUL SYLLABLE AS +C558;C558;110B 1161 11BB;C558;110B 1161 11BB; # (았; 았; 았; 았; 았; ) HANGUL SYLLABLE ASS +C559;C559;110B 1161 11BC;C559;110B 1161 11BC; # (앙; 앙; 앙; 앙; 앙; ) HANGUL SYLLABLE ANG +C55A;C55A;110B 1161 11BD;C55A;110B 1161 11BD; # (앚; 앚; 앚; 앚; 앚; ) HANGUL SYLLABLE AJ +C55B;C55B;110B 1161 11BE;C55B;110B 1161 11BE; # (앛; 앛; 앛; 앛; 앛; ) HANGUL SYLLABLE AC +C55C;C55C;110B 1161 11BF;C55C;110B 1161 11BF; # (앜; 앜; 앜; 앜; 앜; ) HANGUL SYLLABLE AK +C55D;C55D;110B 1161 11C0;C55D;110B 1161 11C0; # (앝; 앝; 앝; 앝; 앝; ) HANGUL SYLLABLE AT +C55E;C55E;110B 1161 11C1;C55E;110B 1161 11C1; # (앞; 앞; 앞; 앞; 앞; ) HANGUL SYLLABLE AP +C55F;C55F;110B 1161 11C2;C55F;110B 1161 11C2; # (앟; 앟; 앟; 앟; 앟; ) HANGUL SYLLABLE AH +C560;C560;110B 1162;C560;110B 1162; # (애; 애; 애; 애; 애; ) HANGUL SYLLABLE AE +C561;C561;110B 1162 11A8;C561;110B 1162 11A8; # (액; 액; 액; 액; 액; ) HANGUL SYLLABLE AEG +C562;C562;110B 1162 11A9;C562;110B 1162 11A9; # (앢; 앢; 앢; 앢; 앢; ) HANGUL SYLLABLE AEGG +C563;C563;110B 1162 11AA;C563;110B 1162 11AA; # (앣; 앣; 앣; 앣; 앣; ) HANGUL SYLLABLE AEGS +C564;C564;110B 1162 11AB;C564;110B 1162 11AB; # (앤; 앤; 앤; 앤; 앤; ) HANGUL SYLLABLE AEN +C565;C565;110B 1162 11AC;C565;110B 1162 11AC; # (앥; 앥; 앥; 앥; 앥; ) HANGUL SYLLABLE AENJ +C566;C566;110B 1162 11AD;C566;110B 1162 11AD; # (앦; 앦; 앦; 앦; 앦; ) HANGUL SYLLABLE AENH +C567;C567;110B 1162 11AE;C567;110B 1162 11AE; # (앧; 앧; 앧; 앧; 앧; ) HANGUL SYLLABLE AED +C568;C568;110B 1162 11AF;C568;110B 1162 11AF; # (앨; 앨; 앨; 앨; 앨; ) HANGUL SYLLABLE AEL +C569;C569;110B 1162 11B0;C569;110B 1162 11B0; # (앩; 앩; 앩; 앩; 앩; ) HANGUL SYLLABLE AELG +C56A;C56A;110B 1162 11B1;C56A;110B 1162 11B1; # (앪; 앪; 앪; 앪; 앪; ) HANGUL SYLLABLE AELM +C56B;C56B;110B 1162 11B2;C56B;110B 1162 11B2; # (앫; 앫; 앫; 앫; 앫; ) HANGUL SYLLABLE AELB +C56C;C56C;110B 1162 11B3;C56C;110B 1162 11B3; # (앬; 앬; 앬; 앬; 앬; ) HANGUL SYLLABLE AELS +C56D;C56D;110B 1162 11B4;C56D;110B 1162 11B4; # (앭; 앭; 앭; 앭; 앭; ) HANGUL SYLLABLE AELT +C56E;C56E;110B 1162 11B5;C56E;110B 1162 11B5; # (앮; 앮; 앮; 앮; 앮; ) HANGUL SYLLABLE AELP +C56F;C56F;110B 1162 11B6;C56F;110B 1162 11B6; # (앯; 앯; 앯; 앯; 앯; ) HANGUL SYLLABLE AELH +C570;C570;110B 1162 11B7;C570;110B 1162 11B7; # (앰; 앰; 앰; 앰; 앰; ) HANGUL SYLLABLE AEM +C571;C571;110B 1162 11B8;C571;110B 1162 11B8; # (앱; 앱; 앱; 앱; 앱; ) HANGUL SYLLABLE AEB +C572;C572;110B 1162 11B9;C572;110B 1162 11B9; # (앲; 앲; 앲; 앲; 앲; ) HANGUL SYLLABLE AEBS +C573;C573;110B 1162 11BA;C573;110B 1162 11BA; # (앳; 앳; 앳; 앳; 앳; ) HANGUL SYLLABLE AES +C574;C574;110B 1162 11BB;C574;110B 1162 11BB; # (앴; 앴; 앴; 앴; 앴; ) HANGUL SYLLABLE AESS +C575;C575;110B 1162 11BC;C575;110B 1162 11BC; # (앵; 앵; 앵; 앵; 앵; ) HANGUL SYLLABLE AENG +C576;C576;110B 1162 11BD;C576;110B 1162 11BD; # (앶; 앶; 앶; 앶; 앶; ) HANGUL SYLLABLE AEJ +C577;C577;110B 1162 11BE;C577;110B 1162 11BE; # (앷; 앷; 앷; 앷; 앷; ) HANGUL SYLLABLE AEC +C578;C578;110B 1162 11BF;C578;110B 1162 11BF; # (앸; 앸; 앸; 앸; 앸; ) HANGUL SYLLABLE AEK +C579;C579;110B 1162 11C0;C579;110B 1162 11C0; # (앹; 앹; 앹; 앹; 앹; ) HANGUL SYLLABLE AET +C57A;C57A;110B 1162 11C1;C57A;110B 1162 11C1; # (앺; 앺; 앺; 앺; 앺; ) HANGUL SYLLABLE AEP +C57B;C57B;110B 1162 11C2;C57B;110B 1162 11C2; # (앻; 앻; 앻; 앻; 앻; ) HANGUL SYLLABLE AEH +C57C;C57C;110B 1163;C57C;110B 1163; # (야; 야; 야; 야; 야; ) HANGUL SYLLABLE YA +C57D;C57D;110B 1163 11A8;C57D;110B 1163 11A8; # (약; 약; 약; 약; 약; ) HANGUL SYLLABLE YAG +C57E;C57E;110B 1163 11A9;C57E;110B 1163 11A9; # (앾; 앾; 앾; 앾; 앾; ) HANGUL SYLLABLE YAGG +C57F;C57F;110B 1163 11AA;C57F;110B 1163 11AA; # (앿; 앿; 앿; 앿; 앿; ) HANGUL SYLLABLE YAGS +C580;C580;110B 1163 11AB;C580;110B 1163 11AB; # (얀; 얀; 얀; 얀; 얀; ) HANGUL SYLLABLE YAN +C581;C581;110B 1163 11AC;C581;110B 1163 11AC; # (얁; 얁; 얁; 얁; 얁; ) HANGUL SYLLABLE YANJ +C582;C582;110B 1163 11AD;C582;110B 1163 11AD; # (얂; 얂; 얂; 얂; 얂; ) HANGUL SYLLABLE YANH +C583;C583;110B 1163 11AE;C583;110B 1163 11AE; # (얃; 얃; 얃; 얃; 얃; ) HANGUL SYLLABLE YAD +C584;C584;110B 1163 11AF;C584;110B 1163 11AF; # (얄; 얄; 얄; 얄; 얄; ) HANGUL SYLLABLE YAL +C585;C585;110B 1163 11B0;C585;110B 1163 11B0; # (얅; 얅; 얅; 얅; 얅; ) HANGUL SYLLABLE YALG +C586;C586;110B 1163 11B1;C586;110B 1163 11B1; # (얆; 얆; 얆; 얆; 얆; ) HANGUL SYLLABLE YALM +C587;C587;110B 1163 11B2;C587;110B 1163 11B2; # (얇; 얇; 얇; 얇; 얇; ) HANGUL SYLLABLE YALB +C588;C588;110B 1163 11B3;C588;110B 1163 11B3; # (얈; 얈; 얈; 얈; 얈; ) HANGUL SYLLABLE YALS +C589;C589;110B 1163 11B4;C589;110B 1163 11B4; # (얉; 얉; 얉; 얉; 얉; ) HANGUL SYLLABLE YALT +C58A;C58A;110B 1163 11B5;C58A;110B 1163 11B5; # (얊; 얊; 얊; 얊; 얊; ) HANGUL SYLLABLE YALP +C58B;C58B;110B 1163 11B6;C58B;110B 1163 11B6; # (얋; 얋; 얋; 얋; 얋; ) HANGUL SYLLABLE YALH +C58C;C58C;110B 1163 11B7;C58C;110B 1163 11B7; # (얌; 얌; 얌; 얌; 얌; ) HANGUL SYLLABLE YAM +C58D;C58D;110B 1163 11B8;C58D;110B 1163 11B8; # (얍; 얍; 얍; 얍; 얍; ) HANGUL SYLLABLE YAB +C58E;C58E;110B 1163 11B9;C58E;110B 1163 11B9; # (얎; 얎; 얎; 얎; 얎; ) HANGUL SYLLABLE YABS +C58F;C58F;110B 1163 11BA;C58F;110B 1163 11BA; # (얏; 얏; 얏; 얏; 얏; ) HANGUL SYLLABLE YAS +C590;C590;110B 1163 11BB;C590;110B 1163 11BB; # (얐; 얐; 얐; 얐; 얐; ) HANGUL SYLLABLE YASS +C591;C591;110B 1163 11BC;C591;110B 1163 11BC; # (양; 양; 양; 양; 양; ) HANGUL SYLLABLE YANG +C592;C592;110B 1163 11BD;C592;110B 1163 11BD; # (얒; 얒; 얒; 얒; 얒; ) HANGUL SYLLABLE YAJ +C593;C593;110B 1163 11BE;C593;110B 1163 11BE; # (얓; 얓; 얓; 얓; 얓; ) HANGUL SYLLABLE YAC +C594;C594;110B 1163 11BF;C594;110B 1163 11BF; # (얔; 얔; 얔; 얔; 얔; ) HANGUL SYLLABLE YAK +C595;C595;110B 1163 11C0;C595;110B 1163 11C0; # (얕; 얕; 얕; 얕; 얕; ) HANGUL SYLLABLE YAT +C596;C596;110B 1163 11C1;C596;110B 1163 11C1; # (얖; 얖; 얖; 얖; 얖; ) HANGUL SYLLABLE YAP +C597;C597;110B 1163 11C2;C597;110B 1163 11C2; # (얗; 얗; 얗; 얗; 얗; ) HANGUL SYLLABLE YAH +C598;C598;110B 1164;C598;110B 1164; # (얘; 얘; 얘; 얘; 얘; ) HANGUL SYLLABLE YAE +C599;C599;110B 1164 11A8;C599;110B 1164 11A8; # (얙; 얙; 얙; 얙; 얙; ) HANGUL SYLLABLE YAEG +C59A;C59A;110B 1164 11A9;C59A;110B 1164 11A9; # (얚; 얚; 얚; 얚; 얚; ) HANGUL SYLLABLE YAEGG +C59B;C59B;110B 1164 11AA;C59B;110B 1164 11AA; # (얛; 얛; 얛; 얛; 얛; ) HANGUL SYLLABLE YAEGS +C59C;C59C;110B 1164 11AB;C59C;110B 1164 11AB; # (얜; 얜; 얜; 얜; 얜; ) HANGUL SYLLABLE YAEN +C59D;C59D;110B 1164 11AC;C59D;110B 1164 11AC; # (얝; 얝; 얝; 얝; 얝; ) HANGUL SYLLABLE YAENJ +C59E;C59E;110B 1164 11AD;C59E;110B 1164 11AD; # (얞; 얞; 얞; 얞; 얞; ) HANGUL SYLLABLE YAENH +C59F;C59F;110B 1164 11AE;C59F;110B 1164 11AE; # (얟; 얟; 얟; 얟; 얟; ) HANGUL SYLLABLE YAED +C5A0;C5A0;110B 1164 11AF;C5A0;110B 1164 11AF; # (얠; 얠; 얠; 얠; 얠; ) HANGUL SYLLABLE YAEL +C5A1;C5A1;110B 1164 11B0;C5A1;110B 1164 11B0; # (얡; 얡; 얡; 얡; 얡; ) HANGUL SYLLABLE YAELG +C5A2;C5A2;110B 1164 11B1;C5A2;110B 1164 11B1; # (얢; 얢; 얢; 얢; 얢; ) HANGUL SYLLABLE YAELM +C5A3;C5A3;110B 1164 11B2;C5A3;110B 1164 11B2; # (얣; 얣; 얣; 얣; 얣; ) HANGUL SYLLABLE YAELB +C5A4;C5A4;110B 1164 11B3;C5A4;110B 1164 11B3; # (얤; 얤; 얤; 얤; 얤; ) HANGUL SYLLABLE YAELS +C5A5;C5A5;110B 1164 11B4;C5A5;110B 1164 11B4; # (얥; 얥; 얥; 얥; 얥; ) HANGUL SYLLABLE YAELT +C5A6;C5A6;110B 1164 11B5;C5A6;110B 1164 11B5; # (얦; 얦; 얦; 얦; 얦; ) HANGUL SYLLABLE YAELP +C5A7;C5A7;110B 1164 11B6;C5A7;110B 1164 11B6; # (얧; 얧; 얧; 얧; 얧; ) HANGUL SYLLABLE YAELH +C5A8;C5A8;110B 1164 11B7;C5A8;110B 1164 11B7; # (얨; 얨; 얨; 얨; 얨; ) HANGUL SYLLABLE YAEM +C5A9;C5A9;110B 1164 11B8;C5A9;110B 1164 11B8; # (얩; 얩; 얩; 얩; 얩; ) HANGUL SYLLABLE YAEB +C5AA;C5AA;110B 1164 11B9;C5AA;110B 1164 11B9; # (얪; 얪; 얪; 얪; 얪; ) HANGUL SYLLABLE YAEBS +C5AB;C5AB;110B 1164 11BA;C5AB;110B 1164 11BA; # (얫; 얫; 얫; 얫; 얫; ) HANGUL SYLLABLE YAES +C5AC;C5AC;110B 1164 11BB;C5AC;110B 1164 11BB; # (얬; 얬; 얬; 얬; 얬; ) HANGUL SYLLABLE YAESS +C5AD;C5AD;110B 1164 11BC;C5AD;110B 1164 11BC; # (얭; 얭; 얭; 얭; 얭; ) HANGUL SYLLABLE YAENG +C5AE;C5AE;110B 1164 11BD;C5AE;110B 1164 11BD; # (얮; 얮; 얮; 얮; 얮; ) HANGUL SYLLABLE YAEJ +C5AF;C5AF;110B 1164 11BE;C5AF;110B 1164 11BE; # (얯; 얯; 얯; 얯; 얯; ) HANGUL SYLLABLE YAEC +C5B0;C5B0;110B 1164 11BF;C5B0;110B 1164 11BF; # (얰; 얰; 얰; 얰; 얰; ) HANGUL SYLLABLE YAEK +C5B1;C5B1;110B 1164 11C0;C5B1;110B 1164 11C0; # (얱; 얱; 얱; 얱; 얱; ) HANGUL SYLLABLE YAET +C5B2;C5B2;110B 1164 11C1;C5B2;110B 1164 11C1; # (얲; 얲; 얲; 얲; 얲; ) HANGUL SYLLABLE YAEP +C5B3;C5B3;110B 1164 11C2;C5B3;110B 1164 11C2; # (얳; 얳; 얳; 얳; 얳; ) HANGUL SYLLABLE YAEH +C5B4;C5B4;110B 1165;C5B4;110B 1165; # (어; 어; 어; 어; 어; ) HANGUL SYLLABLE EO +C5B5;C5B5;110B 1165 11A8;C5B5;110B 1165 11A8; # (억; 억; 억; 억; 억; ) HANGUL SYLLABLE EOG +C5B6;C5B6;110B 1165 11A9;C5B6;110B 1165 11A9; # (얶; 얶; 얶; 얶; 얶; ) HANGUL SYLLABLE EOGG +C5B7;C5B7;110B 1165 11AA;C5B7;110B 1165 11AA; # (얷; 얷; 얷; 얷; 얷; ) HANGUL SYLLABLE EOGS +C5B8;C5B8;110B 1165 11AB;C5B8;110B 1165 11AB; # (언; 언; 언; 언; 언; ) HANGUL SYLLABLE EON +C5B9;C5B9;110B 1165 11AC;C5B9;110B 1165 11AC; # (얹; 얹; 얹; 얹; 얹; ) HANGUL SYLLABLE EONJ +C5BA;C5BA;110B 1165 11AD;C5BA;110B 1165 11AD; # (얺; 얺; 얺; 얺; 얺; ) HANGUL SYLLABLE EONH +C5BB;C5BB;110B 1165 11AE;C5BB;110B 1165 11AE; # (얻; 얻; 얻; 얻; 얻; ) HANGUL SYLLABLE EOD +C5BC;C5BC;110B 1165 11AF;C5BC;110B 1165 11AF; # (얼; 얼; 얼; 얼; 얼; ) HANGUL SYLLABLE EOL +C5BD;C5BD;110B 1165 11B0;C5BD;110B 1165 11B0; # (얽; 얽; 얽; 얽; 얽; ) HANGUL SYLLABLE EOLG +C5BE;C5BE;110B 1165 11B1;C5BE;110B 1165 11B1; # (얾; 얾; 얾; 얾; 얾; ) HANGUL SYLLABLE EOLM +C5BF;C5BF;110B 1165 11B2;C5BF;110B 1165 11B2; # (얿; 얿; 얿; 얿; 얿; ) HANGUL SYLLABLE EOLB +C5C0;C5C0;110B 1165 11B3;C5C0;110B 1165 11B3; # (엀; 엀; 엀; 엀; 엀; ) HANGUL SYLLABLE EOLS +C5C1;C5C1;110B 1165 11B4;C5C1;110B 1165 11B4; # (엁; 엁; 엁; 엁; 엁; ) HANGUL SYLLABLE EOLT +C5C2;C5C2;110B 1165 11B5;C5C2;110B 1165 11B5; # (엂; 엂; 엂; 엂; 엂; ) HANGUL SYLLABLE EOLP +C5C3;C5C3;110B 1165 11B6;C5C3;110B 1165 11B6; # (엃; 엃; 엃; 엃; 엃; ) HANGUL SYLLABLE EOLH +C5C4;C5C4;110B 1165 11B7;C5C4;110B 1165 11B7; # (엄; 엄; 엄; 엄; 엄; ) HANGUL SYLLABLE EOM +C5C5;C5C5;110B 1165 11B8;C5C5;110B 1165 11B8; # (업; 업; 업; 업; 업; ) HANGUL SYLLABLE EOB +C5C6;C5C6;110B 1165 11B9;C5C6;110B 1165 11B9; # (없; 없; 없; 없; 없; ) HANGUL SYLLABLE EOBS +C5C7;C5C7;110B 1165 11BA;C5C7;110B 1165 11BA; # (엇; 엇; 엇; 엇; 엇; ) HANGUL SYLLABLE EOS +C5C8;C5C8;110B 1165 11BB;C5C8;110B 1165 11BB; # (었; 었; 었; 었; 었; ) HANGUL SYLLABLE EOSS +C5C9;C5C9;110B 1165 11BC;C5C9;110B 1165 11BC; # (엉; 엉; 엉; 엉; 엉; ) HANGUL SYLLABLE EONG +C5CA;C5CA;110B 1165 11BD;C5CA;110B 1165 11BD; # (엊; 엊; 엊; 엊; 엊; ) HANGUL SYLLABLE EOJ +C5CB;C5CB;110B 1165 11BE;C5CB;110B 1165 11BE; # (엋; 엋; 엋; 엋; 엋; ) HANGUL SYLLABLE EOC +C5CC;C5CC;110B 1165 11BF;C5CC;110B 1165 11BF; # (엌; 엌; 엌; 엌; 엌; ) HANGUL SYLLABLE EOK +C5CD;C5CD;110B 1165 11C0;C5CD;110B 1165 11C0; # (엍; 엍; 엍; 엍; 엍; ) HANGUL SYLLABLE EOT +C5CE;C5CE;110B 1165 11C1;C5CE;110B 1165 11C1; # (엎; 엎; 엎; 엎; 엎; ) HANGUL SYLLABLE EOP +C5CF;C5CF;110B 1165 11C2;C5CF;110B 1165 11C2; # (엏; 엏; 엏; 엏; 엏; ) HANGUL SYLLABLE EOH +C5D0;C5D0;110B 1166;C5D0;110B 1166; # (에; 에; 에; 에; 에; ) HANGUL SYLLABLE E +C5D1;C5D1;110B 1166 11A8;C5D1;110B 1166 11A8; # (엑; 엑; 엑; 엑; 엑; ) HANGUL SYLLABLE EG +C5D2;C5D2;110B 1166 11A9;C5D2;110B 1166 11A9; # (엒; 엒; 엒; 엒; 엒; ) HANGUL SYLLABLE EGG +C5D3;C5D3;110B 1166 11AA;C5D3;110B 1166 11AA; # (엓; 엓; 엓; 엓; 엓; ) HANGUL SYLLABLE EGS +C5D4;C5D4;110B 1166 11AB;C5D4;110B 1166 11AB; # (엔; 엔; 엔; 엔; 엔; ) HANGUL SYLLABLE EN +C5D5;C5D5;110B 1166 11AC;C5D5;110B 1166 11AC; # (엕; 엕; 엕; 엕; 엕; ) HANGUL SYLLABLE ENJ +C5D6;C5D6;110B 1166 11AD;C5D6;110B 1166 11AD; # (엖; 엖; 엖; 엖; 엖; ) HANGUL SYLLABLE ENH +C5D7;C5D7;110B 1166 11AE;C5D7;110B 1166 11AE; # (엗; 엗; 엗; 엗; 엗; ) HANGUL SYLLABLE ED +C5D8;C5D8;110B 1166 11AF;C5D8;110B 1166 11AF; # (엘; 엘; 엘; 엘; 엘; ) HANGUL SYLLABLE EL +C5D9;C5D9;110B 1166 11B0;C5D9;110B 1166 11B0; # (엙; 엙; 엙; 엙; 엙; ) HANGUL SYLLABLE ELG +C5DA;C5DA;110B 1166 11B1;C5DA;110B 1166 11B1; # (엚; 엚; 엚; 엚; 엚; ) HANGUL SYLLABLE ELM +C5DB;C5DB;110B 1166 11B2;C5DB;110B 1166 11B2; # (엛; 엛; 엛; 엛; 엛; ) HANGUL SYLLABLE ELB +C5DC;C5DC;110B 1166 11B3;C5DC;110B 1166 11B3; # (엜; 엜; 엜; 엜; 엜; ) HANGUL SYLLABLE ELS +C5DD;C5DD;110B 1166 11B4;C5DD;110B 1166 11B4; # (엝; 엝; 엝; 엝; 엝; ) HANGUL SYLLABLE ELT +C5DE;C5DE;110B 1166 11B5;C5DE;110B 1166 11B5; # (엞; 엞; 엞; 엞; 엞; ) HANGUL SYLLABLE ELP +C5DF;C5DF;110B 1166 11B6;C5DF;110B 1166 11B6; # (엟; 엟; 엟; 엟; 엟; ) HANGUL SYLLABLE ELH +C5E0;C5E0;110B 1166 11B7;C5E0;110B 1166 11B7; # (엠; 엠; 엠; 엠; 엠; ) HANGUL SYLLABLE EM +C5E1;C5E1;110B 1166 11B8;C5E1;110B 1166 11B8; # (엡; 엡; 엡; 엡; 엡; ) HANGUL SYLLABLE EB +C5E2;C5E2;110B 1166 11B9;C5E2;110B 1166 11B9; # (엢; 엢; 엢; 엢; 엢; ) HANGUL SYLLABLE EBS +C5E3;C5E3;110B 1166 11BA;C5E3;110B 1166 11BA; # (엣; 엣; 엣; 엣; 엣; ) HANGUL SYLLABLE ES +C5E4;C5E4;110B 1166 11BB;C5E4;110B 1166 11BB; # (엤; 엤; 엤; 엤; 엤; ) HANGUL SYLLABLE ESS +C5E5;C5E5;110B 1166 11BC;C5E5;110B 1166 11BC; # (엥; 엥; 엥; 엥; 엥; ) HANGUL SYLLABLE ENG +C5E6;C5E6;110B 1166 11BD;C5E6;110B 1166 11BD; # (엦; 엦; 엦; 엦; 엦; ) HANGUL SYLLABLE EJ +C5E7;C5E7;110B 1166 11BE;C5E7;110B 1166 11BE; # (엧; 엧; 엧; 엧; 엧; ) HANGUL SYLLABLE EC +C5E8;C5E8;110B 1166 11BF;C5E8;110B 1166 11BF; # (엨; 엨; 엨; 엨; 엨; ) HANGUL SYLLABLE EK +C5E9;C5E9;110B 1166 11C0;C5E9;110B 1166 11C0; # (엩; 엩; 엩; 엩; 엩; ) HANGUL SYLLABLE ET +C5EA;C5EA;110B 1166 11C1;C5EA;110B 1166 11C1; # (엪; 엪; 엪; 엪; 엪; ) HANGUL SYLLABLE EP +C5EB;C5EB;110B 1166 11C2;C5EB;110B 1166 11C2; # (엫; 엫; 엫; 엫; 엫; ) HANGUL SYLLABLE EH +C5EC;C5EC;110B 1167;C5EC;110B 1167; # (여; 여; 여; 여; 여; ) HANGUL SYLLABLE YEO +C5ED;C5ED;110B 1167 11A8;C5ED;110B 1167 11A8; # (역; 역; 역; 역; 역; ) HANGUL SYLLABLE YEOG +C5EE;C5EE;110B 1167 11A9;C5EE;110B 1167 11A9; # (엮; 엮; 엮; 엮; 엮; ) HANGUL SYLLABLE YEOGG +C5EF;C5EF;110B 1167 11AA;C5EF;110B 1167 11AA; # (엯; 엯; 엯; 엯; 엯; ) HANGUL SYLLABLE YEOGS +C5F0;C5F0;110B 1167 11AB;C5F0;110B 1167 11AB; # (연; 연; 연; 연; 연; ) HANGUL SYLLABLE YEON +C5F1;C5F1;110B 1167 11AC;C5F1;110B 1167 11AC; # (엱; 엱; 엱; 엱; 엱; ) HANGUL SYLLABLE YEONJ +C5F2;C5F2;110B 1167 11AD;C5F2;110B 1167 11AD; # (엲; 엲; 엲; 엲; 엲; ) HANGUL SYLLABLE YEONH +C5F3;C5F3;110B 1167 11AE;C5F3;110B 1167 11AE; # (엳; 엳; 엳; 엳; 엳; ) HANGUL SYLLABLE YEOD +C5F4;C5F4;110B 1167 11AF;C5F4;110B 1167 11AF; # (열; 열; 열; 열; 열; ) HANGUL SYLLABLE YEOL +C5F5;C5F5;110B 1167 11B0;C5F5;110B 1167 11B0; # (엵; 엵; 엵; 엵; 엵; ) HANGUL SYLLABLE YEOLG +C5F6;C5F6;110B 1167 11B1;C5F6;110B 1167 11B1; # (엶; 엶; 엶; 엶; 엶; ) HANGUL SYLLABLE YEOLM +C5F7;C5F7;110B 1167 11B2;C5F7;110B 1167 11B2; # (엷; 엷; 엷; 엷; 엷; ) HANGUL SYLLABLE YEOLB +C5F8;C5F8;110B 1167 11B3;C5F8;110B 1167 11B3; # (엸; 엸; 엸; 엸; 엸; ) HANGUL SYLLABLE YEOLS +C5F9;C5F9;110B 1167 11B4;C5F9;110B 1167 11B4; # (엹; 엹; 엹; 엹; 엹; ) HANGUL SYLLABLE YEOLT +C5FA;C5FA;110B 1167 11B5;C5FA;110B 1167 11B5; # (엺; 엺; 엺; 엺; 엺; ) HANGUL SYLLABLE YEOLP +C5FB;C5FB;110B 1167 11B6;C5FB;110B 1167 11B6; # (엻; 엻; 엻; 엻; 엻; ) HANGUL SYLLABLE YEOLH +C5FC;C5FC;110B 1167 11B7;C5FC;110B 1167 11B7; # (염; 염; 염; 염; 염; ) HANGUL SYLLABLE YEOM +C5FD;C5FD;110B 1167 11B8;C5FD;110B 1167 11B8; # (엽; 엽; 엽; 엽; 엽; ) HANGUL SYLLABLE YEOB +C5FE;C5FE;110B 1167 11B9;C5FE;110B 1167 11B9; # (엾; 엾; 엾; 엾; 엾; ) HANGUL SYLLABLE YEOBS +C5FF;C5FF;110B 1167 11BA;C5FF;110B 1167 11BA; # (엿; 엿; 엿; 엿; 엿; ) HANGUL SYLLABLE YEOS +C600;C600;110B 1167 11BB;C600;110B 1167 11BB; # (였; 였; 였; 였; 였; ) HANGUL SYLLABLE YEOSS +C601;C601;110B 1167 11BC;C601;110B 1167 11BC; # (영; 영; 영; 영; 영; ) HANGUL SYLLABLE YEONG +C602;C602;110B 1167 11BD;C602;110B 1167 11BD; # (옂; 옂; 옂; 옂; 옂; ) HANGUL SYLLABLE YEOJ +C603;C603;110B 1167 11BE;C603;110B 1167 11BE; # (옃; 옃; 옃; 옃; 옃; ) HANGUL SYLLABLE YEOC +C604;C604;110B 1167 11BF;C604;110B 1167 11BF; # (옄; 옄; 옄; 옄; 옄; ) HANGUL SYLLABLE YEOK +C605;C605;110B 1167 11C0;C605;110B 1167 11C0; # (옅; 옅; 옅; 옅; 옅; ) HANGUL SYLLABLE YEOT +C606;C606;110B 1167 11C1;C606;110B 1167 11C1; # (옆; 옆; 옆; 옆; 옆; ) HANGUL SYLLABLE YEOP +C607;C607;110B 1167 11C2;C607;110B 1167 11C2; # (옇; 옇; 옇; 옇; 옇; ) HANGUL SYLLABLE YEOH +C608;C608;110B 1168;C608;110B 1168; # (예; 예; 예; 예; 예; ) HANGUL SYLLABLE YE +C609;C609;110B 1168 11A8;C609;110B 1168 11A8; # (옉; 옉; 옉; 옉; 옉; ) HANGUL SYLLABLE YEG +C60A;C60A;110B 1168 11A9;C60A;110B 1168 11A9; # (옊; 옊; 옊; 옊; 옊; ) HANGUL SYLLABLE YEGG +C60B;C60B;110B 1168 11AA;C60B;110B 1168 11AA; # (옋; 옋; 옋; 옋; 옋; ) HANGUL SYLLABLE YEGS +C60C;C60C;110B 1168 11AB;C60C;110B 1168 11AB; # (옌; 옌; 옌; 옌; 옌; ) HANGUL SYLLABLE YEN +C60D;C60D;110B 1168 11AC;C60D;110B 1168 11AC; # (옍; 옍; 옍; 옍; 옍; ) HANGUL SYLLABLE YENJ +C60E;C60E;110B 1168 11AD;C60E;110B 1168 11AD; # (옎; 옎; 옎; 옎; 옎; ) HANGUL SYLLABLE YENH +C60F;C60F;110B 1168 11AE;C60F;110B 1168 11AE; # (옏; 옏; 옏; 옏; 옏; ) HANGUL SYLLABLE YED +C610;C610;110B 1168 11AF;C610;110B 1168 11AF; # (옐; 옐; 옐; 옐; 옐; ) HANGUL SYLLABLE YEL +C611;C611;110B 1168 11B0;C611;110B 1168 11B0; # (옑; 옑; 옑; 옑; 옑; ) HANGUL SYLLABLE YELG +C612;C612;110B 1168 11B1;C612;110B 1168 11B1; # (옒; 옒; 옒; 옒; 옒; ) HANGUL SYLLABLE YELM +C613;C613;110B 1168 11B2;C613;110B 1168 11B2; # (옓; 옓; 옓; 옓; 옓; ) HANGUL SYLLABLE YELB +C614;C614;110B 1168 11B3;C614;110B 1168 11B3; # (옔; 옔; 옔; 옔; 옔; ) HANGUL SYLLABLE YELS +C615;C615;110B 1168 11B4;C615;110B 1168 11B4; # (옕; 옕; 옕; 옕; 옕; ) HANGUL SYLLABLE YELT +C616;C616;110B 1168 11B5;C616;110B 1168 11B5; # (옖; 옖; 옖; 옖; 옖; ) HANGUL SYLLABLE YELP +C617;C617;110B 1168 11B6;C617;110B 1168 11B6; # (옗; 옗; 옗; 옗; 옗; ) HANGUL SYLLABLE YELH +C618;C618;110B 1168 11B7;C618;110B 1168 11B7; # (옘; 옘; 옘; 옘; 옘; ) HANGUL SYLLABLE YEM +C619;C619;110B 1168 11B8;C619;110B 1168 11B8; # (옙; 옙; 옙; 옙; 옙; ) HANGUL SYLLABLE YEB +C61A;C61A;110B 1168 11B9;C61A;110B 1168 11B9; # (옚; 옚; 옚; 옚; 옚; ) HANGUL SYLLABLE YEBS +C61B;C61B;110B 1168 11BA;C61B;110B 1168 11BA; # (옛; 옛; 옛; 옛; 옛; ) HANGUL SYLLABLE YES +C61C;C61C;110B 1168 11BB;C61C;110B 1168 11BB; # (옜; 옜; 옜; 옜; 옜; ) HANGUL SYLLABLE YESS +C61D;C61D;110B 1168 11BC;C61D;110B 1168 11BC; # (옝; 옝; 옝; 옝; 옝; ) HANGUL SYLLABLE YENG +C61E;C61E;110B 1168 11BD;C61E;110B 1168 11BD; # (옞; 옞; 옞; 옞; 옞; ) HANGUL SYLLABLE YEJ +C61F;C61F;110B 1168 11BE;C61F;110B 1168 11BE; # (옟; 옟; 옟; 옟; 옟; ) HANGUL SYLLABLE YEC +C620;C620;110B 1168 11BF;C620;110B 1168 11BF; # (옠; 옠; 옠; 옠; 옠; ) HANGUL SYLLABLE YEK +C621;C621;110B 1168 11C0;C621;110B 1168 11C0; # (옡; 옡; 옡; 옡; 옡; ) HANGUL SYLLABLE YET +C622;C622;110B 1168 11C1;C622;110B 1168 11C1; # (옢; 옢; 옢; 옢; 옢; ) HANGUL SYLLABLE YEP +C623;C623;110B 1168 11C2;C623;110B 1168 11C2; # (옣; 옣; 옣; 옣; 옣; ) HANGUL SYLLABLE YEH +C624;C624;110B 1169;C624;110B 1169; # (오; 오; 오; 오; 오; ) HANGUL SYLLABLE O +C625;C625;110B 1169 11A8;C625;110B 1169 11A8; # (옥; 옥; 옥; 옥; 옥; ) HANGUL SYLLABLE OG +C626;C626;110B 1169 11A9;C626;110B 1169 11A9; # (옦; 옦; 옦; 옦; 옦; ) HANGUL SYLLABLE OGG +C627;C627;110B 1169 11AA;C627;110B 1169 11AA; # (옧; 옧; 옧; 옧; 옧; ) HANGUL SYLLABLE OGS +C628;C628;110B 1169 11AB;C628;110B 1169 11AB; # (온; 온; 온; 온; 온; ) HANGUL SYLLABLE ON +C629;C629;110B 1169 11AC;C629;110B 1169 11AC; # (옩; 옩; 옩; 옩; 옩; ) HANGUL SYLLABLE ONJ +C62A;C62A;110B 1169 11AD;C62A;110B 1169 11AD; # (옪; 옪; 옪; 옪; 옪; ) HANGUL SYLLABLE ONH +C62B;C62B;110B 1169 11AE;C62B;110B 1169 11AE; # (옫; 옫; 옫; 옫; 옫; ) HANGUL SYLLABLE OD +C62C;C62C;110B 1169 11AF;C62C;110B 1169 11AF; # (올; 올; 올; 올; 올; ) HANGUL SYLLABLE OL +C62D;C62D;110B 1169 11B0;C62D;110B 1169 11B0; # (옭; 옭; 옭; 옭; 옭; ) HANGUL SYLLABLE OLG +C62E;C62E;110B 1169 11B1;C62E;110B 1169 11B1; # (옮; 옮; 옮; 옮; 옮; ) HANGUL SYLLABLE OLM +C62F;C62F;110B 1169 11B2;C62F;110B 1169 11B2; # (옯; 옯; 옯; 옯; 옯; ) HANGUL SYLLABLE OLB +C630;C630;110B 1169 11B3;C630;110B 1169 11B3; # (옰; 옰; 옰; 옰; 옰; ) HANGUL SYLLABLE OLS +C631;C631;110B 1169 11B4;C631;110B 1169 11B4; # (옱; 옱; 옱; 옱; 옱; ) HANGUL SYLLABLE OLT +C632;C632;110B 1169 11B5;C632;110B 1169 11B5; # (옲; 옲; 옲; 옲; 옲; ) HANGUL SYLLABLE OLP +C633;C633;110B 1169 11B6;C633;110B 1169 11B6; # (옳; 옳; 옳; 옳; 옳; ) HANGUL SYLLABLE OLH +C634;C634;110B 1169 11B7;C634;110B 1169 11B7; # (옴; 옴; 옴; 옴; 옴; ) HANGUL SYLLABLE OM +C635;C635;110B 1169 11B8;C635;110B 1169 11B8; # (옵; 옵; 옵; 옵; 옵; ) HANGUL SYLLABLE OB +C636;C636;110B 1169 11B9;C636;110B 1169 11B9; # (옶; 옶; 옶; 옶; 옶; ) HANGUL SYLLABLE OBS +C637;C637;110B 1169 11BA;C637;110B 1169 11BA; # (옷; 옷; 옷; 옷; 옷; ) HANGUL SYLLABLE OS +C638;C638;110B 1169 11BB;C638;110B 1169 11BB; # (옸; 옸; 옸; 옸; 옸; ) HANGUL SYLLABLE OSS +C639;C639;110B 1169 11BC;C639;110B 1169 11BC; # (옹; 옹; 옹; 옹; 옹; ) HANGUL SYLLABLE ONG +C63A;C63A;110B 1169 11BD;C63A;110B 1169 11BD; # (옺; 옺; 옺; 옺; 옺; ) HANGUL SYLLABLE OJ +C63B;C63B;110B 1169 11BE;C63B;110B 1169 11BE; # (옻; 옻; 옻; 옻; 옻; ) HANGUL SYLLABLE OC +C63C;C63C;110B 1169 11BF;C63C;110B 1169 11BF; # (옼; 옼; 옼; 옼; 옼; ) HANGUL SYLLABLE OK +C63D;C63D;110B 1169 11C0;C63D;110B 1169 11C0; # (옽; 옽; 옽; 옽; 옽; ) HANGUL SYLLABLE OT +C63E;C63E;110B 1169 11C1;C63E;110B 1169 11C1; # (옾; 옾; 옾; 옾; 옾; ) HANGUL SYLLABLE OP +C63F;C63F;110B 1169 11C2;C63F;110B 1169 11C2; # (옿; 옿; 옿; 옿; 옿; ) HANGUL SYLLABLE OH +C640;C640;110B 116A;C640;110B 116A; # (와; 와; 와; 와; 와; ) HANGUL SYLLABLE WA +C641;C641;110B 116A 11A8;C641;110B 116A 11A8; # (왁; 왁; 왁; 왁; 왁; ) HANGUL SYLLABLE WAG +C642;C642;110B 116A 11A9;C642;110B 116A 11A9; # (왂; 왂; 왂; 왂; 왂; ) HANGUL SYLLABLE WAGG +C643;C643;110B 116A 11AA;C643;110B 116A 11AA; # (왃; 왃; 왃; 왃; 왃; ) HANGUL SYLLABLE WAGS +C644;C644;110B 116A 11AB;C644;110B 116A 11AB; # (완; 완; 완; 완; 완; ) HANGUL SYLLABLE WAN +C645;C645;110B 116A 11AC;C645;110B 116A 11AC; # (왅; 왅; 왅; 왅; 왅; ) HANGUL SYLLABLE WANJ +C646;C646;110B 116A 11AD;C646;110B 116A 11AD; # (왆; 왆; 왆; 왆; 왆; ) HANGUL SYLLABLE WANH +C647;C647;110B 116A 11AE;C647;110B 116A 11AE; # (왇; 왇; 왇; 왇; 왇; ) HANGUL SYLLABLE WAD +C648;C648;110B 116A 11AF;C648;110B 116A 11AF; # (왈; 왈; 왈; 왈; 왈; ) HANGUL SYLLABLE WAL +C649;C649;110B 116A 11B0;C649;110B 116A 11B0; # (왉; 왉; 왉; 왉; 왉; ) HANGUL SYLLABLE WALG +C64A;C64A;110B 116A 11B1;C64A;110B 116A 11B1; # (왊; 왊; 왊; 왊; 왊; ) HANGUL SYLLABLE WALM +C64B;C64B;110B 116A 11B2;C64B;110B 116A 11B2; # (왋; 왋; 왋; 왋; 왋; ) HANGUL SYLLABLE WALB +C64C;C64C;110B 116A 11B3;C64C;110B 116A 11B3; # (왌; 왌; 왌; 왌; 왌; ) HANGUL SYLLABLE WALS +C64D;C64D;110B 116A 11B4;C64D;110B 116A 11B4; # (왍; 왍; 왍; 왍; 왍; ) HANGUL SYLLABLE WALT +C64E;C64E;110B 116A 11B5;C64E;110B 116A 11B5; # (왎; 왎; 왎; 왎; 왎; ) HANGUL SYLLABLE WALP +C64F;C64F;110B 116A 11B6;C64F;110B 116A 11B6; # (왏; 왏; 왏; 왏; 왏; ) HANGUL SYLLABLE WALH +C650;C650;110B 116A 11B7;C650;110B 116A 11B7; # (왐; 왐; 왐; 왐; 왐; ) HANGUL SYLLABLE WAM +C651;C651;110B 116A 11B8;C651;110B 116A 11B8; # (왑; 왑; 왑; 왑; 왑; ) HANGUL SYLLABLE WAB +C652;C652;110B 116A 11B9;C652;110B 116A 11B9; # (왒; 왒; 왒; 왒; 왒; ) HANGUL SYLLABLE WABS +C653;C653;110B 116A 11BA;C653;110B 116A 11BA; # (왓; 왓; 왓; 왓; 왓; ) HANGUL SYLLABLE WAS +C654;C654;110B 116A 11BB;C654;110B 116A 11BB; # (왔; 왔; 왔; 왔; 왔; ) HANGUL SYLLABLE WASS +C655;C655;110B 116A 11BC;C655;110B 116A 11BC; # (왕; 왕; 왕; 왕; 왕; ) HANGUL SYLLABLE WANG +C656;C656;110B 116A 11BD;C656;110B 116A 11BD; # (왖; 왖; 왖; 왖; 왖; ) HANGUL SYLLABLE WAJ +C657;C657;110B 116A 11BE;C657;110B 116A 11BE; # (왗; 왗; 왗; 왗; 왗; ) HANGUL SYLLABLE WAC +C658;C658;110B 116A 11BF;C658;110B 116A 11BF; # (왘; 왘; 왘; 왘; 왘; ) HANGUL SYLLABLE WAK +C659;C659;110B 116A 11C0;C659;110B 116A 11C0; # (왙; 왙; 왙; 왙; 왙; ) HANGUL SYLLABLE WAT +C65A;C65A;110B 116A 11C1;C65A;110B 116A 11C1; # (왚; 왚; 왚; 왚; 왚; ) HANGUL SYLLABLE WAP +C65B;C65B;110B 116A 11C2;C65B;110B 116A 11C2; # (왛; 왛; 왛; 왛; 왛; ) HANGUL SYLLABLE WAH +C65C;C65C;110B 116B;C65C;110B 116B; # (왜; 왜; 왜; 왜; 왜; ) HANGUL SYLLABLE WAE +C65D;C65D;110B 116B 11A8;C65D;110B 116B 11A8; # (왝; 왝; 왝; 왝; 왝; ) HANGUL SYLLABLE WAEG +C65E;C65E;110B 116B 11A9;C65E;110B 116B 11A9; # (왞; 왞; 왞; 왞; 왞; ) HANGUL SYLLABLE WAEGG +C65F;C65F;110B 116B 11AA;C65F;110B 116B 11AA; # (왟; 왟; 왟; 왟; 왟; ) HANGUL SYLLABLE WAEGS +C660;C660;110B 116B 11AB;C660;110B 116B 11AB; # (왠; 왠; 왠; 왠; 왠; ) HANGUL SYLLABLE WAEN +C661;C661;110B 116B 11AC;C661;110B 116B 11AC; # (왡; 왡; 왡; 왡; 왡; ) HANGUL SYLLABLE WAENJ +C662;C662;110B 116B 11AD;C662;110B 116B 11AD; # (왢; 왢; 왢; 왢; 왢; ) HANGUL SYLLABLE WAENH +C663;C663;110B 116B 11AE;C663;110B 116B 11AE; # (왣; 왣; 왣; 왣; 왣; ) HANGUL SYLLABLE WAED +C664;C664;110B 116B 11AF;C664;110B 116B 11AF; # (왤; 왤; 왤; 왤; 왤; ) HANGUL SYLLABLE WAEL +C665;C665;110B 116B 11B0;C665;110B 116B 11B0; # (왥; 왥; 왥; 왥; 왥; ) HANGUL SYLLABLE WAELG +C666;C666;110B 116B 11B1;C666;110B 116B 11B1; # (왦; 왦; 왦; 왦; 왦; ) HANGUL SYLLABLE WAELM +C667;C667;110B 116B 11B2;C667;110B 116B 11B2; # (왧; 왧; 왧; 왧; 왧; ) HANGUL SYLLABLE WAELB +C668;C668;110B 116B 11B3;C668;110B 116B 11B3; # (왨; 왨; 왨; 왨; 왨; ) HANGUL SYLLABLE WAELS +C669;C669;110B 116B 11B4;C669;110B 116B 11B4; # (왩; 왩; 왩; 왩; 왩; ) HANGUL SYLLABLE WAELT +C66A;C66A;110B 116B 11B5;C66A;110B 116B 11B5; # (왪; 왪; 왪; 왪; 왪; ) HANGUL SYLLABLE WAELP +C66B;C66B;110B 116B 11B6;C66B;110B 116B 11B6; # (왫; 왫; 왫; 왫; 왫; ) HANGUL SYLLABLE WAELH +C66C;C66C;110B 116B 11B7;C66C;110B 116B 11B7; # (왬; 왬; 왬; 왬; 왬; ) HANGUL SYLLABLE WAEM +C66D;C66D;110B 116B 11B8;C66D;110B 116B 11B8; # (왭; 왭; 왭; 왭; 왭; ) HANGUL SYLLABLE WAEB +C66E;C66E;110B 116B 11B9;C66E;110B 116B 11B9; # (왮; 왮; 왮; 왮; 왮; ) HANGUL SYLLABLE WAEBS +C66F;C66F;110B 116B 11BA;C66F;110B 116B 11BA; # (왯; 왯; 왯; 왯; 왯; ) HANGUL SYLLABLE WAES +C670;C670;110B 116B 11BB;C670;110B 116B 11BB; # (왰; 왰; 왰; 왰; 왰; ) HANGUL SYLLABLE WAESS +C671;C671;110B 116B 11BC;C671;110B 116B 11BC; # (왱; 왱; 왱; 왱; 왱; ) HANGUL SYLLABLE WAENG +C672;C672;110B 116B 11BD;C672;110B 116B 11BD; # (왲; 왲; 왲; 왲; 왲; ) HANGUL SYLLABLE WAEJ +C673;C673;110B 116B 11BE;C673;110B 116B 11BE; # (왳; 왳; 왳; 왳; 왳; ) HANGUL SYLLABLE WAEC +C674;C674;110B 116B 11BF;C674;110B 116B 11BF; # (왴; 왴; 왴; 왴; 왴; ) HANGUL SYLLABLE WAEK +C675;C675;110B 116B 11C0;C675;110B 116B 11C0; # (왵; 왵; 왵; 왵; 왵; ) HANGUL SYLLABLE WAET +C676;C676;110B 116B 11C1;C676;110B 116B 11C1; # (왶; 왶; 왶; 왶; 왶; ) HANGUL SYLLABLE WAEP +C677;C677;110B 116B 11C2;C677;110B 116B 11C2; # (왷; 왷; 왷; 왷; 왷; ) HANGUL SYLLABLE WAEH +C678;C678;110B 116C;C678;110B 116C; # (외; 외; 외; 외; 외; ) HANGUL SYLLABLE OE +C679;C679;110B 116C 11A8;C679;110B 116C 11A8; # (왹; 왹; 왹; 왹; 왹; ) HANGUL SYLLABLE OEG +C67A;C67A;110B 116C 11A9;C67A;110B 116C 11A9; # (왺; 왺; 왺; 왺; 왺; ) HANGUL SYLLABLE OEGG +C67B;C67B;110B 116C 11AA;C67B;110B 116C 11AA; # (왻; 왻; 왻; 왻; 왻; ) HANGUL SYLLABLE OEGS +C67C;C67C;110B 116C 11AB;C67C;110B 116C 11AB; # (왼; 왼; 왼; 왼; 왼; ) HANGUL SYLLABLE OEN +C67D;C67D;110B 116C 11AC;C67D;110B 116C 11AC; # (왽; 왽; 왽; 왽; 왽; ) HANGUL SYLLABLE OENJ +C67E;C67E;110B 116C 11AD;C67E;110B 116C 11AD; # (왾; 왾; 왾; 왾; 왾; ) HANGUL SYLLABLE OENH +C67F;C67F;110B 116C 11AE;C67F;110B 116C 11AE; # (왿; 왿; 왿; 왿; 왿; ) HANGUL SYLLABLE OED +C680;C680;110B 116C 11AF;C680;110B 116C 11AF; # (욀; 욀; 욀; 욀; 욀; ) HANGUL SYLLABLE OEL +C681;C681;110B 116C 11B0;C681;110B 116C 11B0; # (욁; 욁; 욁; 욁; 욁; ) HANGUL SYLLABLE OELG +C682;C682;110B 116C 11B1;C682;110B 116C 11B1; # (욂; 욂; 욂; 욂; 욂; ) HANGUL SYLLABLE OELM +C683;C683;110B 116C 11B2;C683;110B 116C 11B2; # (욃; 욃; 욃; 욃; 욃; ) HANGUL SYLLABLE OELB +C684;C684;110B 116C 11B3;C684;110B 116C 11B3; # (욄; 욄; 욄; 욄; 욄; ) HANGUL SYLLABLE OELS +C685;C685;110B 116C 11B4;C685;110B 116C 11B4; # (욅; 욅; 욅; 욅; 욅; ) HANGUL SYLLABLE OELT +C686;C686;110B 116C 11B5;C686;110B 116C 11B5; # (욆; 욆; 욆; 욆; 욆; ) HANGUL SYLLABLE OELP +C687;C687;110B 116C 11B6;C687;110B 116C 11B6; # (욇; 욇; 욇; 욇; 욇; ) HANGUL SYLLABLE OELH +C688;C688;110B 116C 11B7;C688;110B 116C 11B7; # (욈; 욈; 욈; 욈; 욈; ) HANGUL SYLLABLE OEM +C689;C689;110B 116C 11B8;C689;110B 116C 11B8; # (욉; 욉; 욉; 욉; 욉; ) HANGUL SYLLABLE OEB +C68A;C68A;110B 116C 11B9;C68A;110B 116C 11B9; # (욊; 욊; 욊; 욊; 욊; ) HANGUL SYLLABLE OEBS +C68B;C68B;110B 116C 11BA;C68B;110B 116C 11BA; # (욋; 욋; 욋; 욋; 욋; ) HANGUL SYLLABLE OES +C68C;C68C;110B 116C 11BB;C68C;110B 116C 11BB; # (욌; 욌; 욌; 욌; 욌; ) HANGUL SYLLABLE OESS +C68D;C68D;110B 116C 11BC;C68D;110B 116C 11BC; # (욍; 욍; 욍; 욍; 욍; ) HANGUL SYLLABLE OENG +C68E;C68E;110B 116C 11BD;C68E;110B 116C 11BD; # (욎; 욎; 욎; 욎; 욎; ) HANGUL SYLLABLE OEJ +C68F;C68F;110B 116C 11BE;C68F;110B 116C 11BE; # (욏; 욏; 욏; 욏; 욏; ) HANGUL SYLLABLE OEC +C690;C690;110B 116C 11BF;C690;110B 116C 11BF; # (욐; 욐; 욐; 욐; 욐; ) HANGUL SYLLABLE OEK +C691;C691;110B 116C 11C0;C691;110B 116C 11C0; # (욑; 욑; 욑; 욑; 욑; ) HANGUL SYLLABLE OET +C692;C692;110B 116C 11C1;C692;110B 116C 11C1; # (욒; 욒; 욒; 욒; 욒; ) HANGUL SYLLABLE OEP +C693;C693;110B 116C 11C2;C693;110B 116C 11C2; # (욓; 욓; 욓; 욓; 욓; ) HANGUL SYLLABLE OEH +C694;C694;110B 116D;C694;110B 116D; # (요; 요; 요; 요; 요; ) HANGUL SYLLABLE YO +C695;C695;110B 116D 11A8;C695;110B 116D 11A8; # (욕; 욕; 욕; 욕; 욕; ) HANGUL SYLLABLE YOG +C696;C696;110B 116D 11A9;C696;110B 116D 11A9; # (욖; 욖; 욖; 욖; 욖; ) HANGUL SYLLABLE YOGG +C697;C697;110B 116D 11AA;C697;110B 116D 11AA; # (욗; 욗; 욗; 욗; 욗; ) HANGUL SYLLABLE YOGS +C698;C698;110B 116D 11AB;C698;110B 116D 11AB; # (욘; 욘; 욘; 욘; 욘; ) HANGUL SYLLABLE YON +C699;C699;110B 116D 11AC;C699;110B 116D 11AC; # (욙; 욙; 욙; 욙; 욙; ) HANGUL SYLLABLE YONJ +C69A;C69A;110B 116D 11AD;C69A;110B 116D 11AD; # (욚; 욚; 욚; 욚; 욚; ) HANGUL SYLLABLE YONH +C69B;C69B;110B 116D 11AE;C69B;110B 116D 11AE; # (욛; 욛; 욛; 욛; 욛; ) HANGUL SYLLABLE YOD +C69C;C69C;110B 116D 11AF;C69C;110B 116D 11AF; # (욜; 욜; 욜; 욜; 욜; ) HANGUL SYLLABLE YOL +C69D;C69D;110B 116D 11B0;C69D;110B 116D 11B0; # (욝; 욝; 욝; 욝; 욝; ) HANGUL SYLLABLE YOLG +C69E;C69E;110B 116D 11B1;C69E;110B 116D 11B1; # (욞; 욞; 욞; 욞; 욞; ) HANGUL SYLLABLE YOLM +C69F;C69F;110B 116D 11B2;C69F;110B 116D 11B2; # (욟; 욟; 욟; 욟; 욟; ) HANGUL SYLLABLE YOLB +C6A0;C6A0;110B 116D 11B3;C6A0;110B 116D 11B3; # (욠; 욠; 욠; 욠; 욠; ) HANGUL SYLLABLE YOLS +C6A1;C6A1;110B 116D 11B4;C6A1;110B 116D 11B4; # (욡; 욡; 욡; 욡; 욡; ) HANGUL SYLLABLE YOLT +C6A2;C6A2;110B 116D 11B5;C6A2;110B 116D 11B5; # (욢; 욢; 욢; 욢; 욢; ) HANGUL SYLLABLE YOLP +C6A3;C6A3;110B 116D 11B6;C6A3;110B 116D 11B6; # (욣; 욣; 욣; 욣; 욣; ) HANGUL SYLLABLE YOLH +C6A4;C6A4;110B 116D 11B7;C6A4;110B 116D 11B7; # (욤; 욤; 욤; 욤; 욤; ) HANGUL SYLLABLE YOM +C6A5;C6A5;110B 116D 11B8;C6A5;110B 116D 11B8; # (욥; 욥; 욥; 욥; 욥; ) HANGUL SYLLABLE YOB +C6A6;C6A6;110B 116D 11B9;C6A6;110B 116D 11B9; # (욦; 욦; 욦; 욦; 욦; ) HANGUL SYLLABLE YOBS +C6A7;C6A7;110B 116D 11BA;C6A7;110B 116D 11BA; # (욧; 욧; 욧; 욧; 욧; ) HANGUL SYLLABLE YOS +C6A8;C6A8;110B 116D 11BB;C6A8;110B 116D 11BB; # (욨; 욨; 욨; 욨; 욨; ) HANGUL SYLLABLE YOSS +C6A9;C6A9;110B 116D 11BC;C6A9;110B 116D 11BC; # (용; 용; 용; 용; 용; ) HANGUL SYLLABLE YONG +C6AA;C6AA;110B 116D 11BD;C6AA;110B 116D 11BD; # (욪; 욪; 욪; 욪; 욪; ) HANGUL SYLLABLE YOJ +C6AB;C6AB;110B 116D 11BE;C6AB;110B 116D 11BE; # (욫; 욫; 욫; 욫; 욫; ) HANGUL SYLLABLE YOC +C6AC;C6AC;110B 116D 11BF;C6AC;110B 116D 11BF; # (욬; 욬; 욬; 욬; 욬; ) HANGUL SYLLABLE YOK +C6AD;C6AD;110B 116D 11C0;C6AD;110B 116D 11C0; # (욭; 욭; 욭; 욭; 욭; ) HANGUL SYLLABLE YOT +C6AE;C6AE;110B 116D 11C1;C6AE;110B 116D 11C1; # (욮; 욮; 욮; 욮; 욮; ) HANGUL SYLLABLE YOP +C6AF;C6AF;110B 116D 11C2;C6AF;110B 116D 11C2; # (욯; 욯; 욯; 욯; 욯; ) HANGUL SYLLABLE YOH +C6B0;C6B0;110B 116E;C6B0;110B 116E; # (우; 우; 우; 우; 우; ) HANGUL SYLLABLE U +C6B1;C6B1;110B 116E 11A8;C6B1;110B 116E 11A8; # (욱; 욱; 욱; 욱; 욱; ) HANGUL SYLLABLE UG +C6B2;C6B2;110B 116E 11A9;C6B2;110B 116E 11A9; # (욲; 욲; 욲; 욲; 욲; ) HANGUL SYLLABLE UGG +C6B3;C6B3;110B 116E 11AA;C6B3;110B 116E 11AA; # (욳; 욳; 욳; 욳; 욳; ) HANGUL SYLLABLE UGS +C6B4;C6B4;110B 116E 11AB;C6B4;110B 116E 11AB; # (운; 운; 운; 운; 운; ) HANGUL SYLLABLE UN +C6B5;C6B5;110B 116E 11AC;C6B5;110B 116E 11AC; # (욵; 욵; 욵; 욵; 욵; ) HANGUL SYLLABLE UNJ +C6B6;C6B6;110B 116E 11AD;C6B6;110B 116E 11AD; # (욶; 욶; 욶; 욶; 욶; ) HANGUL SYLLABLE UNH +C6B7;C6B7;110B 116E 11AE;C6B7;110B 116E 11AE; # (욷; 욷; 욷; 욷; 욷; ) HANGUL SYLLABLE UD +C6B8;C6B8;110B 116E 11AF;C6B8;110B 116E 11AF; # (울; 울; 울; 울; 울; ) HANGUL SYLLABLE UL +C6B9;C6B9;110B 116E 11B0;C6B9;110B 116E 11B0; # (욹; 욹; 욹; 욹; 욹; ) HANGUL SYLLABLE ULG +C6BA;C6BA;110B 116E 11B1;C6BA;110B 116E 11B1; # (욺; 욺; 욺; 욺; 욺; ) HANGUL SYLLABLE ULM +C6BB;C6BB;110B 116E 11B2;C6BB;110B 116E 11B2; # (욻; 욻; 욻; 욻; 욻; ) HANGUL SYLLABLE ULB +C6BC;C6BC;110B 116E 11B3;C6BC;110B 116E 11B3; # (욼; 욼; 욼; 욼; 욼; ) HANGUL SYLLABLE ULS +C6BD;C6BD;110B 116E 11B4;C6BD;110B 116E 11B4; # (욽; 욽; 욽; 욽; 욽; ) HANGUL SYLLABLE ULT +C6BE;C6BE;110B 116E 11B5;C6BE;110B 116E 11B5; # (욾; 욾; 욾; 욾; 욾; ) HANGUL SYLLABLE ULP +C6BF;C6BF;110B 116E 11B6;C6BF;110B 116E 11B6; # (욿; 욿; 욿; 욿; 욿; ) HANGUL SYLLABLE ULH +C6C0;C6C0;110B 116E 11B7;C6C0;110B 116E 11B7; # (움; 움; 움; 움; 움; ) HANGUL SYLLABLE UM +C6C1;C6C1;110B 116E 11B8;C6C1;110B 116E 11B8; # (웁; 웁; 웁; 웁; 웁; ) HANGUL SYLLABLE UB +C6C2;C6C2;110B 116E 11B9;C6C2;110B 116E 11B9; # (웂; 웂; 웂; 웂; 웂; ) HANGUL SYLLABLE UBS +C6C3;C6C3;110B 116E 11BA;C6C3;110B 116E 11BA; # (웃; 웃; 웃; 웃; 웃; ) HANGUL SYLLABLE US +C6C4;C6C4;110B 116E 11BB;C6C4;110B 116E 11BB; # (웄; 웄; 웄; 웄; 웄; ) HANGUL SYLLABLE USS +C6C5;C6C5;110B 116E 11BC;C6C5;110B 116E 11BC; # (웅; 웅; 웅; 웅; 웅; ) HANGUL SYLLABLE UNG +C6C6;C6C6;110B 116E 11BD;C6C6;110B 116E 11BD; # (웆; 웆; 웆; 웆; 웆; ) HANGUL SYLLABLE UJ +C6C7;C6C7;110B 116E 11BE;C6C7;110B 116E 11BE; # (웇; 웇; 웇; 웇; 웇; ) HANGUL SYLLABLE UC +C6C8;C6C8;110B 116E 11BF;C6C8;110B 116E 11BF; # (웈; 웈; 웈; 웈; 웈; ) HANGUL SYLLABLE UK +C6C9;C6C9;110B 116E 11C0;C6C9;110B 116E 11C0; # (웉; 웉; 웉; 웉; 웉; ) HANGUL SYLLABLE UT +C6CA;C6CA;110B 116E 11C1;C6CA;110B 116E 11C1; # (웊; 웊; 웊; 웊; 웊; ) HANGUL SYLLABLE UP +C6CB;C6CB;110B 116E 11C2;C6CB;110B 116E 11C2; # (웋; 웋; 웋; 웋; 웋; ) HANGUL SYLLABLE UH +C6CC;C6CC;110B 116F;C6CC;110B 116F; # (워; 워; 워; 워; 워; ) HANGUL SYLLABLE WEO +C6CD;C6CD;110B 116F 11A8;C6CD;110B 116F 11A8; # (웍; 웍; 웍; 웍; 웍; ) HANGUL SYLLABLE WEOG +C6CE;C6CE;110B 116F 11A9;C6CE;110B 116F 11A9; # (웎; 웎; 웎; 웎; 웎; ) HANGUL SYLLABLE WEOGG +C6CF;C6CF;110B 116F 11AA;C6CF;110B 116F 11AA; # (웏; 웏; 웏; 웏; 웏; ) HANGUL SYLLABLE WEOGS +C6D0;C6D0;110B 116F 11AB;C6D0;110B 116F 11AB; # (원; 원; 원; 원; 원; ) HANGUL SYLLABLE WEON +C6D1;C6D1;110B 116F 11AC;C6D1;110B 116F 11AC; # (웑; 웑; 웑; 웑; 웑; ) HANGUL SYLLABLE WEONJ +C6D2;C6D2;110B 116F 11AD;C6D2;110B 116F 11AD; # (웒; 웒; 웒; 웒; 웒; ) HANGUL SYLLABLE WEONH +C6D3;C6D3;110B 116F 11AE;C6D3;110B 116F 11AE; # (웓; 웓; 웓; 웓; 웓; ) HANGUL SYLLABLE WEOD +C6D4;C6D4;110B 116F 11AF;C6D4;110B 116F 11AF; # (월; 월; 월; 월; 월; ) HANGUL SYLLABLE WEOL +C6D5;C6D5;110B 116F 11B0;C6D5;110B 116F 11B0; # (웕; 웕; 웕; 웕; 웕; ) HANGUL SYLLABLE WEOLG +C6D6;C6D6;110B 116F 11B1;C6D6;110B 116F 11B1; # (웖; 웖; 웖; 웖; 웖; ) HANGUL SYLLABLE WEOLM +C6D7;C6D7;110B 116F 11B2;C6D7;110B 116F 11B2; # (웗; 웗; 웗; 웗; 웗; ) HANGUL SYLLABLE WEOLB +C6D8;C6D8;110B 116F 11B3;C6D8;110B 116F 11B3; # (웘; 웘; 웘; 웘; 웘; ) HANGUL SYLLABLE WEOLS +C6D9;C6D9;110B 116F 11B4;C6D9;110B 116F 11B4; # (웙; 웙; 웙; 웙; 웙; ) HANGUL SYLLABLE WEOLT +C6DA;C6DA;110B 116F 11B5;C6DA;110B 116F 11B5; # (웚; 웚; 웚; 웚; 웚; ) HANGUL SYLLABLE WEOLP +C6DB;C6DB;110B 116F 11B6;C6DB;110B 116F 11B6; # (웛; 웛; 웛; 웛; 웛; ) HANGUL SYLLABLE WEOLH +C6DC;C6DC;110B 116F 11B7;C6DC;110B 116F 11B7; # (웜; 웜; 웜; 웜; 웜; ) HANGUL SYLLABLE WEOM +C6DD;C6DD;110B 116F 11B8;C6DD;110B 116F 11B8; # (웝; 웝; 웝; 웝; 웝; ) HANGUL SYLLABLE WEOB +C6DE;C6DE;110B 116F 11B9;C6DE;110B 116F 11B9; # (웞; 웞; 웞; 웞; 웞; ) HANGUL SYLLABLE WEOBS +C6DF;C6DF;110B 116F 11BA;C6DF;110B 116F 11BA; # (웟; 웟; 웟; 웟; 웟; ) HANGUL SYLLABLE WEOS +C6E0;C6E0;110B 116F 11BB;C6E0;110B 116F 11BB; # (웠; 웠; 웠; 웠; 웠; ) HANGUL SYLLABLE WEOSS +C6E1;C6E1;110B 116F 11BC;C6E1;110B 116F 11BC; # (웡; 웡; 웡; 웡; 웡; ) HANGUL SYLLABLE WEONG +C6E2;C6E2;110B 116F 11BD;C6E2;110B 116F 11BD; # (웢; 웢; 웢; 웢; 웢; ) HANGUL SYLLABLE WEOJ +C6E3;C6E3;110B 116F 11BE;C6E3;110B 116F 11BE; # (웣; 웣; 웣; 웣; 웣; ) HANGUL SYLLABLE WEOC +C6E4;C6E4;110B 116F 11BF;C6E4;110B 116F 11BF; # (웤; 웤; 웤; 웤; 웤; ) HANGUL SYLLABLE WEOK +C6E5;C6E5;110B 116F 11C0;C6E5;110B 116F 11C0; # (웥; 웥; 웥; 웥; 웥; ) HANGUL SYLLABLE WEOT +C6E6;C6E6;110B 116F 11C1;C6E6;110B 116F 11C1; # (웦; 웦; 웦; 웦; 웦; ) HANGUL SYLLABLE WEOP +C6E7;C6E7;110B 116F 11C2;C6E7;110B 116F 11C2; # (웧; 웧; 웧; 웧; 웧; ) HANGUL SYLLABLE WEOH +C6E8;C6E8;110B 1170;C6E8;110B 1170; # (웨; 웨; 웨; 웨; 웨; ) HANGUL SYLLABLE WE +C6E9;C6E9;110B 1170 11A8;C6E9;110B 1170 11A8; # (웩; 웩; 웩; 웩; 웩; ) HANGUL SYLLABLE WEG +C6EA;C6EA;110B 1170 11A9;C6EA;110B 1170 11A9; # (웪; 웪; 웪; 웪; 웪; ) HANGUL SYLLABLE WEGG +C6EB;C6EB;110B 1170 11AA;C6EB;110B 1170 11AA; # (웫; 웫; 웫; 웫; 웫; ) HANGUL SYLLABLE WEGS +C6EC;C6EC;110B 1170 11AB;C6EC;110B 1170 11AB; # (웬; 웬; 웬; 웬; 웬; ) HANGUL SYLLABLE WEN +C6ED;C6ED;110B 1170 11AC;C6ED;110B 1170 11AC; # (웭; 웭; 웭; 웭; 웭; ) HANGUL SYLLABLE WENJ +C6EE;C6EE;110B 1170 11AD;C6EE;110B 1170 11AD; # (웮; 웮; 웮; 웮; 웮; ) HANGUL SYLLABLE WENH +C6EF;C6EF;110B 1170 11AE;C6EF;110B 1170 11AE; # (웯; 웯; 웯; 웯; 웯; ) HANGUL SYLLABLE WED +C6F0;C6F0;110B 1170 11AF;C6F0;110B 1170 11AF; # (웰; 웰; 웰; 웰; 웰; ) HANGUL SYLLABLE WEL +C6F1;C6F1;110B 1170 11B0;C6F1;110B 1170 11B0; # (웱; 웱; 웱; 웱; 웱; ) HANGUL SYLLABLE WELG +C6F2;C6F2;110B 1170 11B1;C6F2;110B 1170 11B1; # (웲; 웲; 웲; 웲; 웲; ) HANGUL SYLLABLE WELM +C6F3;C6F3;110B 1170 11B2;C6F3;110B 1170 11B2; # (웳; 웳; 웳; 웳; 웳; ) HANGUL SYLLABLE WELB +C6F4;C6F4;110B 1170 11B3;C6F4;110B 1170 11B3; # (웴; 웴; 웴; 웴; 웴; ) HANGUL SYLLABLE WELS +C6F5;C6F5;110B 1170 11B4;C6F5;110B 1170 11B4; # (웵; 웵; 웵; 웵; 웵; ) HANGUL SYLLABLE WELT +C6F6;C6F6;110B 1170 11B5;C6F6;110B 1170 11B5; # (웶; 웶; 웶; 웶; 웶; ) HANGUL SYLLABLE WELP +C6F7;C6F7;110B 1170 11B6;C6F7;110B 1170 11B6; # (웷; 웷; 웷; 웷; 웷; ) HANGUL SYLLABLE WELH +C6F8;C6F8;110B 1170 11B7;C6F8;110B 1170 11B7; # (웸; 웸; 웸; 웸; 웸; ) HANGUL SYLLABLE WEM +C6F9;C6F9;110B 1170 11B8;C6F9;110B 1170 11B8; # (웹; 웹; 웹; 웹; 웹; ) HANGUL SYLLABLE WEB +C6FA;C6FA;110B 1170 11B9;C6FA;110B 1170 11B9; # (웺; 웺; 웺; 웺; 웺; ) HANGUL SYLLABLE WEBS +C6FB;C6FB;110B 1170 11BA;C6FB;110B 1170 11BA; # (웻; 웻; 웻; 웻; 웻; ) HANGUL SYLLABLE WES +C6FC;C6FC;110B 1170 11BB;C6FC;110B 1170 11BB; # (웼; 웼; 웼; 웼; 웼; ) HANGUL SYLLABLE WESS +C6FD;C6FD;110B 1170 11BC;C6FD;110B 1170 11BC; # (웽; 웽; 웽; 웽; 웽; ) HANGUL SYLLABLE WENG +C6FE;C6FE;110B 1170 11BD;C6FE;110B 1170 11BD; # (웾; 웾; 웾; 웾; 웾; ) HANGUL SYLLABLE WEJ +C6FF;C6FF;110B 1170 11BE;C6FF;110B 1170 11BE; # (웿; 웿; 웿; 웿; 웿; ) HANGUL SYLLABLE WEC +C700;C700;110B 1170 11BF;C700;110B 1170 11BF; # (윀; 윀; 윀; 윀; 윀; ) HANGUL SYLLABLE WEK +C701;C701;110B 1170 11C0;C701;110B 1170 11C0; # (윁; 윁; 윁; 윁; 윁; ) HANGUL SYLLABLE WET +C702;C702;110B 1170 11C1;C702;110B 1170 11C1; # (윂; 윂; 윂; 윂; 윂; ) HANGUL SYLLABLE WEP +C703;C703;110B 1170 11C2;C703;110B 1170 11C2; # (윃; 윃; 윃; 윃; 윃; ) HANGUL SYLLABLE WEH +C704;C704;110B 1171;C704;110B 1171; # (위; 위; 위; 위; 위; ) HANGUL SYLLABLE WI +C705;C705;110B 1171 11A8;C705;110B 1171 11A8; # (윅; 윅; 윅; 윅; 윅; ) HANGUL SYLLABLE WIG +C706;C706;110B 1171 11A9;C706;110B 1171 11A9; # (윆; 윆; 윆; 윆; 윆; ) HANGUL SYLLABLE WIGG +C707;C707;110B 1171 11AA;C707;110B 1171 11AA; # (윇; 윇; 윇; 윇; 윇; ) HANGUL SYLLABLE WIGS +C708;C708;110B 1171 11AB;C708;110B 1171 11AB; # (윈; 윈; 윈; 윈; 윈; ) HANGUL SYLLABLE WIN +C709;C709;110B 1171 11AC;C709;110B 1171 11AC; # (윉; 윉; 윉; 윉; 윉; ) HANGUL SYLLABLE WINJ +C70A;C70A;110B 1171 11AD;C70A;110B 1171 11AD; # (윊; 윊; 윊; 윊; 윊; ) HANGUL SYLLABLE WINH +C70B;C70B;110B 1171 11AE;C70B;110B 1171 11AE; # (윋; 윋; 윋; 윋; 윋; ) HANGUL SYLLABLE WID +C70C;C70C;110B 1171 11AF;C70C;110B 1171 11AF; # (윌; 윌; 윌; 윌; 윌; ) HANGUL SYLLABLE WIL +C70D;C70D;110B 1171 11B0;C70D;110B 1171 11B0; # (윍; 윍; 윍; 윍; 윍; ) HANGUL SYLLABLE WILG +C70E;C70E;110B 1171 11B1;C70E;110B 1171 11B1; # (윎; 윎; 윎; 윎; 윎; ) HANGUL SYLLABLE WILM +C70F;C70F;110B 1171 11B2;C70F;110B 1171 11B2; # (윏; 윏; 윏; 윏; 윏; ) HANGUL SYLLABLE WILB +C710;C710;110B 1171 11B3;C710;110B 1171 11B3; # (윐; 윐; 윐; 윐; 윐; ) HANGUL SYLLABLE WILS +C711;C711;110B 1171 11B4;C711;110B 1171 11B4; # (윑; 윑; 윑; 윑; 윑; ) HANGUL SYLLABLE WILT +C712;C712;110B 1171 11B5;C712;110B 1171 11B5; # (윒; 윒; 윒; 윒; 윒; ) HANGUL SYLLABLE WILP +C713;C713;110B 1171 11B6;C713;110B 1171 11B6; # (윓; 윓; 윓; 윓; 윓; ) HANGUL SYLLABLE WILH +C714;C714;110B 1171 11B7;C714;110B 1171 11B7; # (윔; 윔; 윔; 윔; 윔; ) HANGUL SYLLABLE WIM +C715;C715;110B 1171 11B8;C715;110B 1171 11B8; # (윕; 윕; 윕; 윕; 윕; ) HANGUL SYLLABLE WIB +C716;C716;110B 1171 11B9;C716;110B 1171 11B9; # (윖; 윖; 윖; 윖; 윖; ) HANGUL SYLLABLE WIBS +C717;C717;110B 1171 11BA;C717;110B 1171 11BA; # (윗; 윗; 윗; 윗; 윗; ) HANGUL SYLLABLE WIS +C718;C718;110B 1171 11BB;C718;110B 1171 11BB; # (윘; 윘; 윘; 윘; 윘; ) HANGUL SYLLABLE WISS +C719;C719;110B 1171 11BC;C719;110B 1171 11BC; # (윙; 윙; 윙; 윙; 윙; ) HANGUL SYLLABLE WING +C71A;C71A;110B 1171 11BD;C71A;110B 1171 11BD; # (윚; 윚; 윚; 윚; 윚; ) HANGUL SYLLABLE WIJ +C71B;C71B;110B 1171 11BE;C71B;110B 1171 11BE; # (윛; 윛; 윛; 윛; 윛; ) HANGUL SYLLABLE WIC +C71C;C71C;110B 1171 11BF;C71C;110B 1171 11BF; # (윜; 윜; 윜; 윜; 윜; ) HANGUL SYLLABLE WIK +C71D;C71D;110B 1171 11C0;C71D;110B 1171 11C0; # (윝; 윝; 윝; 윝; 윝; ) HANGUL SYLLABLE WIT +C71E;C71E;110B 1171 11C1;C71E;110B 1171 11C1; # (윞; 윞; 윞; 윞; 윞; ) HANGUL SYLLABLE WIP +C71F;C71F;110B 1171 11C2;C71F;110B 1171 11C2; # (윟; 윟; 윟; 윟; 윟; ) HANGUL SYLLABLE WIH +C720;C720;110B 1172;C720;110B 1172; # (유; 유; 유; 유; 유; ) HANGUL SYLLABLE YU +C721;C721;110B 1172 11A8;C721;110B 1172 11A8; # (육; 육; 육; 육; 육; ) HANGUL SYLLABLE YUG +C722;C722;110B 1172 11A9;C722;110B 1172 11A9; # (윢; 윢; 윢; 윢; 윢; ) HANGUL SYLLABLE YUGG +C723;C723;110B 1172 11AA;C723;110B 1172 11AA; # (윣; 윣; 윣; 윣; 윣; ) HANGUL SYLLABLE YUGS +C724;C724;110B 1172 11AB;C724;110B 1172 11AB; # (윤; 윤; 윤; 윤; 윤; ) HANGUL SYLLABLE YUN +C725;C725;110B 1172 11AC;C725;110B 1172 11AC; # (윥; 윥; 윥; 윥; 윥; ) HANGUL SYLLABLE YUNJ +C726;C726;110B 1172 11AD;C726;110B 1172 11AD; # (윦; 윦; 윦; 윦; 윦; ) HANGUL SYLLABLE YUNH +C727;C727;110B 1172 11AE;C727;110B 1172 11AE; # (윧; 윧; 윧; 윧; 윧; ) HANGUL SYLLABLE YUD +C728;C728;110B 1172 11AF;C728;110B 1172 11AF; # (율; 율; 율; 율; 율; ) HANGUL SYLLABLE YUL +C729;C729;110B 1172 11B0;C729;110B 1172 11B0; # (윩; 윩; 윩; 윩; 윩; ) HANGUL SYLLABLE YULG +C72A;C72A;110B 1172 11B1;C72A;110B 1172 11B1; # (윪; 윪; 윪; 윪; 윪; ) HANGUL SYLLABLE YULM +C72B;C72B;110B 1172 11B2;C72B;110B 1172 11B2; # (윫; 윫; 윫; 윫; 윫; ) HANGUL SYLLABLE YULB +C72C;C72C;110B 1172 11B3;C72C;110B 1172 11B3; # (윬; 윬; 윬; 윬; 윬; ) HANGUL SYLLABLE YULS +C72D;C72D;110B 1172 11B4;C72D;110B 1172 11B4; # (윭; 윭; 윭; 윭; 윭; ) HANGUL SYLLABLE YULT +C72E;C72E;110B 1172 11B5;C72E;110B 1172 11B5; # (윮; 윮; 윮; 윮; 윮; ) HANGUL SYLLABLE YULP +C72F;C72F;110B 1172 11B6;C72F;110B 1172 11B6; # (윯; 윯; 윯; 윯; 윯; ) HANGUL SYLLABLE YULH +C730;C730;110B 1172 11B7;C730;110B 1172 11B7; # (윰; 윰; 윰; 윰; 윰; ) HANGUL SYLLABLE YUM +C731;C731;110B 1172 11B8;C731;110B 1172 11B8; # (윱; 윱; 윱; 윱; 윱; ) HANGUL SYLLABLE YUB +C732;C732;110B 1172 11B9;C732;110B 1172 11B9; # (윲; 윲; 윲; 윲; 윲; ) HANGUL SYLLABLE YUBS +C733;C733;110B 1172 11BA;C733;110B 1172 11BA; # (윳; 윳; 윳; 윳; 윳; ) HANGUL SYLLABLE YUS +C734;C734;110B 1172 11BB;C734;110B 1172 11BB; # (윴; 윴; 윴; 윴; 윴; ) HANGUL SYLLABLE YUSS +C735;C735;110B 1172 11BC;C735;110B 1172 11BC; # (융; 융; 융; 융; 융; ) HANGUL SYLLABLE YUNG +C736;C736;110B 1172 11BD;C736;110B 1172 11BD; # (윶; 윶; 윶; 윶; 윶; ) HANGUL SYLLABLE YUJ +C737;C737;110B 1172 11BE;C737;110B 1172 11BE; # (윷; 윷; 윷; 윷; 윷; ) HANGUL SYLLABLE YUC +C738;C738;110B 1172 11BF;C738;110B 1172 11BF; # (윸; 윸; 윸; 윸; 윸; ) HANGUL SYLLABLE YUK +C739;C739;110B 1172 11C0;C739;110B 1172 11C0; # (윹; 윹; 윹; 윹; 윹; ) HANGUL SYLLABLE YUT +C73A;C73A;110B 1172 11C1;C73A;110B 1172 11C1; # (윺; 윺; 윺; 윺; 윺; ) HANGUL SYLLABLE YUP +C73B;C73B;110B 1172 11C2;C73B;110B 1172 11C2; # (윻; 윻; 윻; 윻; 윻; ) HANGUL SYLLABLE YUH +C73C;C73C;110B 1173;C73C;110B 1173; # (으; 으; 으; 으; 으; ) HANGUL SYLLABLE EU +C73D;C73D;110B 1173 11A8;C73D;110B 1173 11A8; # (윽; 윽; 윽; 윽; 윽; ) HANGUL SYLLABLE EUG +C73E;C73E;110B 1173 11A9;C73E;110B 1173 11A9; # (윾; 윾; 윾; 윾; 윾; ) HANGUL SYLLABLE EUGG +C73F;C73F;110B 1173 11AA;C73F;110B 1173 11AA; # (윿; 윿; 윿; 윿; 윿; ) HANGUL SYLLABLE EUGS +C740;C740;110B 1173 11AB;C740;110B 1173 11AB; # (은; 은; 은; 은; 은; ) HANGUL SYLLABLE EUN +C741;C741;110B 1173 11AC;C741;110B 1173 11AC; # (읁; 읁; 읁; 읁; 읁; ) HANGUL SYLLABLE EUNJ +C742;C742;110B 1173 11AD;C742;110B 1173 11AD; # (읂; 읂; 읂; 읂; 읂; ) HANGUL SYLLABLE EUNH +C743;C743;110B 1173 11AE;C743;110B 1173 11AE; # (읃; 읃; 읃; 읃; 읃; ) HANGUL SYLLABLE EUD +C744;C744;110B 1173 11AF;C744;110B 1173 11AF; # (을; 을; 을; 을; 을; ) HANGUL SYLLABLE EUL +C745;C745;110B 1173 11B0;C745;110B 1173 11B0; # (읅; 읅; 읅; 읅; 읅; ) HANGUL SYLLABLE EULG +C746;C746;110B 1173 11B1;C746;110B 1173 11B1; # (읆; 읆; 읆; 읆; 읆; ) HANGUL SYLLABLE EULM +C747;C747;110B 1173 11B2;C747;110B 1173 11B2; # (읇; 읇; 읇; 읇; 읇; ) HANGUL SYLLABLE EULB +C748;C748;110B 1173 11B3;C748;110B 1173 11B3; # (읈; 읈; 읈; 읈; 읈; ) HANGUL SYLLABLE EULS +C749;C749;110B 1173 11B4;C749;110B 1173 11B4; # (읉; 읉; 읉; 읉; 읉; ) HANGUL SYLLABLE EULT +C74A;C74A;110B 1173 11B5;C74A;110B 1173 11B5; # (읊; 읊; 읊; 읊; 읊; ) HANGUL SYLLABLE EULP +C74B;C74B;110B 1173 11B6;C74B;110B 1173 11B6; # (읋; 읋; 읋; 읋; 읋; ) HANGUL SYLLABLE EULH +C74C;C74C;110B 1173 11B7;C74C;110B 1173 11B7; # (음; 음; 음; 음; 음; ) HANGUL SYLLABLE EUM +C74D;C74D;110B 1173 11B8;C74D;110B 1173 11B8; # (읍; 읍; 읍; 읍; 읍; ) HANGUL SYLLABLE EUB +C74E;C74E;110B 1173 11B9;C74E;110B 1173 11B9; # (읎; 읎; 읎; 읎; 읎; ) HANGUL SYLLABLE EUBS +C74F;C74F;110B 1173 11BA;C74F;110B 1173 11BA; # (읏; 읏; 읏; 읏; 읏; ) HANGUL SYLLABLE EUS +C750;C750;110B 1173 11BB;C750;110B 1173 11BB; # (읐; 읐; 읐; 읐; 읐; ) HANGUL SYLLABLE EUSS +C751;C751;110B 1173 11BC;C751;110B 1173 11BC; # (응; 응; 응; 응; 응; ) HANGUL SYLLABLE EUNG +C752;C752;110B 1173 11BD;C752;110B 1173 11BD; # (읒; 읒; 읒; 읒; 읒; ) HANGUL SYLLABLE EUJ +C753;C753;110B 1173 11BE;C753;110B 1173 11BE; # (읓; 읓; 읓; 읓; 읓; ) HANGUL SYLLABLE EUC +C754;C754;110B 1173 11BF;C754;110B 1173 11BF; # (읔; 읔; 읔; 읔; 읔; ) HANGUL SYLLABLE EUK +C755;C755;110B 1173 11C0;C755;110B 1173 11C0; # (읕; 읕; 읕; 읕; 읕; ) HANGUL SYLLABLE EUT +C756;C756;110B 1173 11C1;C756;110B 1173 11C1; # (읖; 읖; 읖; 읖; 읖; ) HANGUL SYLLABLE EUP +C757;C757;110B 1173 11C2;C757;110B 1173 11C2; # (읗; 읗; 읗; 읗; 읗; ) HANGUL SYLLABLE EUH +C758;C758;110B 1174;C758;110B 1174; # (의; 의; 의; 의; 의; ) HANGUL SYLLABLE YI +C759;C759;110B 1174 11A8;C759;110B 1174 11A8; # (읙; 읙; 읙; 읙; 읙; ) HANGUL SYLLABLE YIG +C75A;C75A;110B 1174 11A9;C75A;110B 1174 11A9; # (읚; 읚; 읚; 읚; 읚; ) HANGUL SYLLABLE YIGG +C75B;C75B;110B 1174 11AA;C75B;110B 1174 11AA; # (읛; 읛; 읛; 읛; 읛; ) HANGUL SYLLABLE YIGS +C75C;C75C;110B 1174 11AB;C75C;110B 1174 11AB; # (읜; 읜; 읜; 읜; 읜; ) HANGUL SYLLABLE YIN +C75D;C75D;110B 1174 11AC;C75D;110B 1174 11AC; # (읝; 읝; 읝; 읝; 읝; ) HANGUL SYLLABLE YINJ +C75E;C75E;110B 1174 11AD;C75E;110B 1174 11AD; # (읞; 읞; 읞; 읞; 읞; ) HANGUL SYLLABLE YINH +C75F;C75F;110B 1174 11AE;C75F;110B 1174 11AE; # (읟; 읟; 읟; 읟; 읟; ) HANGUL SYLLABLE YID +C760;C760;110B 1174 11AF;C760;110B 1174 11AF; # (읠; 읠; 읠; 읠; 읠; ) HANGUL SYLLABLE YIL +C761;C761;110B 1174 11B0;C761;110B 1174 11B0; # (읡; 읡; 읡; 읡; 읡; ) HANGUL SYLLABLE YILG +C762;C762;110B 1174 11B1;C762;110B 1174 11B1; # (읢; 읢; 읢; 읢; 읢; ) HANGUL SYLLABLE YILM +C763;C763;110B 1174 11B2;C763;110B 1174 11B2; # (읣; 읣; 읣; 읣; 읣; ) HANGUL SYLLABLE YILB +C764;C764;110B 1174 11B3;C764;110B 1174 11B3; # (읤; 읤; 읤; 읤; 읤; ) HANGUL SYLLABLE YILS +C765;C765;110B 1174 11B4;C765;110B 1174 11B4; # (읥; 읥; 읥; 읥; 읥; ) HANGUL SYLLABLE YILT +C766;C766;110B 1174 11B5;C766;110B 1174 11B5; # (읦; 읦; 읦; 읦; 읦; ) HANGUL SYLLABLE YILP +C767;C767;110B 1174 11B6;C767;110B 1174 11B6; # (읧; 읧; 읧; 읧; 읧; ) HANGUL SYLLABLE YILH +C768;C768;110B 1174 11B7;C768;110B 1174 11B7; # (읨; 읨; 읨; 읨; 읨; ) HANGUL SYLLABLE YIM +C769;C769;110B 1174 11B8;C769;110B 1174 11B8; # (읩; 읩; 읩; 읩; 읩; ) HANGUL SYLLABLE YIB +C76A;C76A;110B 1174 11B9;C76A;110B 1174 11B9; # (읪; 읪; 읪; 읪; 읪; ) HANGUL SYLLABLE YIBS +C76B;C76B;110B 1174 11BA;C76B;110B 1174 11BA; # (읫; 읫; 읫; 읫; 읫; ) HANGUL SYLLABLE YIS +C76C;C76C;110B 1174 11BB;C76C;110B 1174 11BB; # (읬; 읬; 읬; 읬; 읬; ) HANGUL SYLLABLE YISS +C76D;C76D;110B 1174 11BC;C76D;110B 1174 11BC; # (읭; 읭; 읭; 읭; 읭; ) HANGUL SYLLABLE YING +C76E;C76E;110B 1174 11BD;C76E;110B 1174 11BD; # (읮; 읮; 읮; 읮; 읮; ) HANGUL SYLLABLE YIJ +C76F;C76F;110B 1174 11BE;C76F;110B 1174 11BE; # (읯; 읯; 읯; 읯; 읯; ) HANGUL SYLLABLE YIC +C770;C770;110B 1174 11BF;C770;110B 1174 11BF; # (읰; 읰; 읰; 읰; 읰; ) HANGUL SYLLABLE YIK +C771;C771;110B 1174 11C0;C771;110B 1174 11C0; # (읱; 읱; 읱; 읱; 읱; ) HANGUL SYLLABLE YIT +C772;C772;110B 1174 11C1;C772;110B 1174 11C1; # (읲; 읲; 읲; 읲; 읲; ) HANGUL SYLLABLE YIP +C773;C773;110B 1174 11C2;C773;110B 1174 11C2; # (읳; 읳; 읳; 읳; 읳; ) HANGUL SYLLABLE YIH +C774;C774;110B 1175;C774;110B 1175; # (이; 이; 이; 이; 이; ) HANGUL SYLLABLE I +C775;C775;110B 1175 11A8;C775;110B 1175 11A8; # (익; 익; 익; 익; 익; ) HANGUL SYLLABLE IG +C776;C776;110B 1175 11A9;C776;110B 1175 11A9; # (읶; 읶; 읶; 읶; 읶; ) HANGUL SYLLABLE IGG +C777;C777;110B 1175 11AA;C777;110B 1175 11AA; # (읷; 읷; 읷; 읷; 읷; ) HANGUL SYLLABLE IGS +C778;C778;110B 1175 11AB;C778;110B 1175 11AB; # (인; 인; 인; 인; 인; ) HANGUL SYLLABLE IN +C779;C779;110B 1175 11AC;C779;110B 1175 11AC; # (읹; 읹; 읹; 읹; 읹; ) HANGUL SYLLABLE INJ +C77A;C77A;110B 1175 11AD;C77A;110B 1175 11AD; # (읺; 읺; 읺; 읺; 읺; ) HANGUL SYLLABLE INH +C77B;C77B;110B 1175 11AE;C77B;110B 1175 11AE; # (읻; 읻; 읻; 읻; 읻; ) HANGUL SYLLABLE ID +C77C;C77C;110B 1175 11AF;C77C;110B 1175 11AF; # (일; 일; 일; 일; 일; ) HANGUL SYLLABLE IL +C77D;C77D;110B 1175 11B0;C77D;110B 1175 11B0; # (읽; 읽; 읽; 읽; 읽; ) HANGUL SYLLABLE ILG +C77E;C77E;110B 1175 11B1;C77E;110B 1175 11B1; # (읾; 읾; 읾; 읾; 읾; ) HANGUL SYLLABLE ILM +C77F;C77F;110B 1175 11B2;C77F;110B 1175 11B2; # (읿; 읿; 읿; 읿; 읿; ) HANGUL SYLLABLE ILB +C780;C780;110B 1175 11B3;C780;110B 1175 11B3; # (잀; 잀; 잀; 잀; 잀; ) HANGUL SYLLABLE ILS +C781;C781;110B 1175 11B4;C781;110B 1175 11B4; # (잁; 잁; 잁; 잁; 잁; ) HANGUL SYLLABLE ILT +C782;C782;110B 1175 11B5;C782;110B 1175 11B5; # (잂; 잂; 잂; 잂; 잂; ) HANGUL SYLLABLE ILP +C783;C783;110B 1175 11B6;C783;110B 1175 11B6; # (잃; 잃; 잃; 잃; 잃; ) HANGUL SYLLABLE ILH +C784;C784;110B 1175 11B7;C784;110B 1175 11B7; # (임; 임; 임; 임; 임; ) HANGUL SYLLABLE IM +C785;C785;110B 1175 11B8;C785;110B 1175 11B8; # (입; 입; 입; 입; 입; ) HANGUL SYLLABLE IB +C786;C786;110B 1175 11B9;C786;110B 1175 11B9; # (잆; 잆; 잆; 잆; 잆; ) HANGUL SYLLABLE IBS +C787;C787;110B 1175 11BA;C787;110B 1175 11BA; # (잇; 잇; 잇; 잇; 잇; ) HANGUL SYLLABLE IS +C788;C788;110B 1175 11BB;C788;110B 1175 11BB; # (있; 있; 있; 있; 있; ) HANGUL SYLLABLE ISS +C789;C789;110B 1175 11BC;C789;110B 1175 11BC; # (잉; 잉; 잉; 잉; 잉; ) HANGUL SYLLABLE ING +C78A;C78A;110B 1175 11BD;C78A;110B 1175 11BD; # (잊; 잊; 잊; 잊; 잊; ) HANGUL SYLLABLE IJ +C78B;C78B;110B 1175 11BE;C78B;110B 1175 11BE; # (잋; 잋; 잋; 잋; 잋; ) HANGUL SYLLABLE IC +C78C;C78C;110B 1175 11BF;C78C;110B 1175 11BF; # (잌; 잌; 잌; 잌; 잌; ) HANGUL SYLLABLE IK +C78D;C78D;110B 1175 11C0;C78D;110B 1175 11C0; # (잍; 잍; 잍; 잍; 잍; ) HANGUL SYLLABLE IT +C78E;C78E;110B 1175 11C1;C78E;110B 1175 11C1; # (잎; 잎; 잎; 잎; 잎; ) HANGUL SYLLABLE IP +C78F;C78F;110B 1175 11C2;C78F;110B 1175 11C2; # (잏; 잏; 잏; 잏; 잏; ) HANGUL SYLLABLE IH +C790;C790;110C 1161;C790;110C 1161; # (자; 자; 자; 자; 자; ) HANGUL SYLLABLE JA +C791;C791;110C 1161 11A8;C791;110C 1161 11A8; # (작; 작; 작; 작; 작; ) HANGUL SYLLABLE JAG +C792;C792;110C 1161 11A9;C792;110C 1161 11A9; # (잒; 잒; 잒; 잒; 잒; ) HANGUL SYLLABLE JAGG +C793;C793;110C 1161 11AA;C793;110C 1161 11AA; # (잓; 잓; 잓; 잓; 잓; ) HANGUL SYLLABLE JAGS +C794;C794;110C 1161 11AB;C794;110C 1161 11AB; # (잔; 잔; 잔; 잔; 잔; ) HANGUL SYLLABLE JAN +C795;C795;110C 1161 11AC;C795;110C 1161 11AC; # (잕; 잕; 잕; 잕; 잕; ) HANGUL SYLLABLE JANJ +C796;C796;110C 1161 11AD;C796;110C 1161 11AD; # (잖; 잖; 잖; 잖; 잖; ) HANGUL SYLLABLE JANH +C797;C797;110C 1161 11AE;C797;110C 1161 11AE; # (잗; 잗; 잗; 잗; 잗; ) HANGUL SYLLABLE JAD +C798;C798;110C 1161 11AF;C798;110C 1161 11AF; # (잘; 잘; 잘; 잘; 잘; ) HANGUL SYLLABLE JAL +C799;C799;110C 1161 11B0;C799;110C 1161 11B0; # (잙; 잙; 잙; 잙; 잙; ) HANGUL SYLLABLE JALG +C79A;C79A;110C 1161 11B1;C79A;110C 1161 11B1; # (잚; 잚; 잚; 잚; 잚; ) HANGUL SYLLABLE JALM +C79B;C79B;110C 1161 11B2;C79B;110C 1161 11B2; # (잛; 잛; 잛; 잛; 잛; ) HANGUL SYLLABLE JALB +C79C;C79C;110C 1161 11B3;C79C;110C 1161 11B3; # (잜; 잜; 잜; 잜; 잜; ) HANGUL SYLLABLE JALS +C79D;C79D;110C 1161 11B4;C79D;110C 1161 11B4; # (잝; 잝; 잝; 잝; 잝; ) HANGUL SYLLABLE JALT +C79E;C79E;110C 1161 11B5;C79E;110C 1161 11B5; # (잞; 잞; 잞; 잞; 잞; ) HANGUL SYLLABLE JALP +C79F;C79F;110C 1161 11B6;C79F;110C 1161 11B6; # (잟; 잟; 잟; 잟; 잟; ) HANGUL SYLLABLE JALH +C7A0;C7A0;110C 1161 11B7;C7A0;110C 1161 11B7; # (잠; 잠; 잠; 잠; 잠; ) HANGUL SYLLABLE JAM +C7A1;C7A1;110C 1161 11B8;C7A1;110C 1161 11B8; # (잡; 잡; 잡; 잡; 잡; ) HANGUL SYLLABLE JAB +C7A2;C7A2;110C 1161 11B9;C7A2;110C 1161 11B9; # (잢; 잢; 잢; 잢; 잢; ) HANGUL SYLLABLE JABS +C7A3;C7A3;110C 1161 11BA;C7A3;110C 1161 11BA; # (잣; 잣; 잣; 잣; 잣; ) HANGUL SYLLABLE JAS +C7A4;C7A4;110C 1161 11BB;C7A4;110C 1161 11BB; # (잤; 잤; 잤; 잤; 잤; ) HANGUL SYLLABLE JASS +C7A5;C7A5;110C 1161 11BC;C7A5;110C 1161 11BC; # (장; 장; 장; 장; 장; ) HANGUL SYLLABLE JANG +C7A6;C7A6;110C 1161 11BD;C7A6;110C 1161 11BD; # (잦; 잦; 잦; 잦; 잦; ) HANGUL SYLLABLE JAJ +C7A7;C7A7;110C 1161 11BE;C7A7;110C 1161 11BE; # (잧; 잧; 잧; 잧; 잧; ) HANGUL SYLLABLE JAC +C7A8;C7A8;110C 1161 11BF;C7A8;110C 1161 11BF; # (잨; 잨; 잨; 잨; 잨; ) HANGUL SYLLABLE JAK +C7A9;C7A9;110C 1161 11C0;C7A9;110C 1161 11C0; # (잩; 잩; 잩; 잩; 잩; ) HANGUL SYLLABLE JAT +C7AA;C7AA;110C 1161 11C1;C7AA;110C 1161 11C1; # (잪; 잪; 잪; 잪; 잪; ) HANGUL SYLLABLE JAP +C7AB;C7AB;110C 1161 11C2;C7AB;110C 1161 11C2; # (잫; 잫; 잫; 잫; 잫; ) HANGUL SYLLABLE JAH +C7AC;C7AC;110C 1162;C7AC;110C 1162; # (재; 재; 재; 재; 재; ) HANGUL SYLLABLE JAE +C7AD;C7AD;110C 1162 11A8;C7AD;110C 1162 11A8; # (잭; 잭; 잭; 잭; 잭; ) HANGUL SYLLABLE JAEG +C7AE;C7AE;110C 1162 11A9;C7AE;110C 1162 11A9; # (잮; 잮; 잮; 잮; 잮; ) HANGUL SYLLABLE JAEGG +C7AF;C7AF;110C 1162 11AA;C7AF;110C 1162 11AA; # (잯; 잯; 잯; 잯; 잯; ) HANGUL SYLLABLE JAEGS +C7B0;C7B0;110C 1162 11AB;C7B0;110C 1162 11AB; # (잰; 잰; 잰; 잰; 잰; ) HANGUL SYLLABLE JAEN +C7B1;C7B1;110C 1162 11AC;C7B1;110C 1162 11AC; # (잱; 잱; 잱; 잱; 잱; ) HANGUL SYLLABLE JAENJ +C7B2;C7B2;110C 1162 11AD;C7B2;110C 1162 11AD; # (잲; 잲; 잲; 잲; 잲; ) HANGUL SYLLABLE JAENH +C7B3;C7B3;110C 1162 11AE;C7B3;110C 1162 11AE; # (잳; 잳; 잳; 잳; 잳; ) HANGUL SYLLABLE JAED +C7B4;C7B4;110C 1162 11AF;C7B4;110C 1162 11AF; # (잴; 잴; 잴; 잴; 잴; ) HANGUL SYLLABLE JAEL +C7B5;C7B5;110C 1162 11B0;C7B5;110C 1162 11B0; # (잵; 잵; 잵; 잵; 잵; ) HANGUL SYLLABLE JAELG +C7B6;C7B6;110C 1162 11B1;C7B6;110C 1162 11B1; # (잶; 잶; 잶; 잶; 잶; ) HANGUL SYLLABLE JAELM +C7B7;C7B7;110C 1162 11B2;C7B7;110C 1162 11B2; # (잷; 잷; 잷; 잷; 잷; ) HANGUL SYLLABLE JAELB +C7B8;C7B8;110C 1162 11B3;C7B8;110C 1162 11B3; # (잸; 잸; 잸; 잸; 잸; ) HANGUL SYLLABLE JAELS +C7B9;C7B9;110C 1162 11B4;C7B9;110C 1162 11B4; # (잹; 잹; 잹; 잹; 잹; ) HANGUL SYLLABLE JAELT +C7BA;C7BA;110C 1162 11B5;C7BA;110C 1162 11B5; # (잺; 잺; 잺; 잺; 잺; ) HANGUL SYLLABLE JAELP +C7BB;C7BB;110C 1162 11B6;C7BB;110C 1162 11B6; # (잻; 잻; 잻; 잻; 잻; ) HANGUL SYLLABLE JAELH +C7BC;C7BC;110C 1162 11B7;C7BC;110C 1162 11B7; # (잼; 잼; 잼; 잼; 잼; ) HANGUL SYLLABLE JAEM +C7BD;C7BD;110C 1162 11B8;C7BD;110C 1162 11B8; # (잽; 잽; 잽; 잽; 잽; ) HANGUL SYLLABLE JAEB +C7BE;C7BE;110C 1162 11B9;C7BE;110C 1162 11B9; # (잾; 잾; 잾; 잾; 잾; ) HANGUL SYLLABLE JAEBS +C7BF;C7BF;110C 1162 11BA;C7BF;110C 1162 11BA; # (잿; 잿; 잿; 잿; 잿; ) HANGUL SYLLABLE JAES +C7C0;C7C0;110C 1162 11BB;C7C0;110C 1162 11BB; # (쟀; 쟀; 쟀; 쟀; 쟀; ) HANGUL SYLLABLE JAESS +C7C1;C7C1;110C 1162 11BC;C7C1;110C 1162 11BC; # (쟁; 쟁; 쟁; 쟁; 쟁; ) HANGUL SYLLABLE JAENG +C7C2;C7C2;110C 1162 11BD;C7C2;110C 1162 11BD; # (쟂; 쟂; 쟂; 쟂; 쟂; ) HANGUL SYLLABLE JAEJ +C7C3;C7C3;110C 1162 11BE;C7C3;110C 1162 11BE; # (쟃; 쟃; 쟃; 쟃; 쟃; ) HANGUL SYLLABLE JAEC +C7C4;C7C4;110C 1162 11BF;C7C4;110C 1162 11BF; # (쟄; 쟄; 쟄; 쟄; 쟄; ) HANGUL SYLLABLE JAEK +C7C5;C7C5;110C 1162 11C0;C7C5;110C 1162 11C0; # (쟅; 쟅; 쟅; 쟅; 쟅; ) HANGUL SYLLABLE JAET +C7C6;C7C6;110C 1162 11C1;C7C6;110C 1162 11C1; # (쟆; 쟆; 쟆; 쟆; 쟆; ) HANGUL SYLLABLE JAEP +C7C7;C7C7;110C 1162 11C2;C7C7;110C 1162 11C2; # (쟇; 쟇; 쟇; 쟇; 쟇; ) HANGUL SYLLABLE JAEH +C7C8;C7C8;110C 1163;C7C8;110C 1163; # (쟈; 쟈; 쟈; 쟈; 쟈; ) HANGUL SYLLABLE JYA +C7C9;C7C9;110C 1163 11A8;C7C9;110C 1163 11A8; # (쟉; 쟉; 쟉; 쟉; 쟉; ) HANGUL SYLLABLE JYAG +C7CA;C7CA;110C 1163 11A9;C7CA;110C 1163 11A9; # (쟊; 쟊; 쟊; 쟊; 쟊; ) HANGUL SYLLABLE JYAGG +C7CB;C7CB;110C 1163 11AA;C7CB;110C 1163 11AA; # (쟋; 쟋; 쟋; 쟋; 쟋; ) HANGUL SYLLABLE JYAGS +C7CC;C7CC;110C 1163 11AB;C7CC;110C 1163 11AB; # (쟌; 쟌; 쟌; 쟌; 쟌; ) HANGUL SYLLABLE JYAN +C7CD;C7CD;110C 1163 11AC;C7CD;110C 1163 11AC; # (쟍; 쟍; 쟍; 쟍; 쟍; ) HANGUL SYLLABLE JYANJ +C7CE;C7CE;110C 1163 11AD;C7CE;110C 1163 11AD; # (쟎; 쟎; 쟎; 쟎; 쟎; ) HANGUL SYLLABLE JYANH +C7CF;C7CF;110C 1163 11AE;C7CF;110C 1163 11AE; # (쟏; 쟏; 쟏; 쟏; 쟏; ) HANGUL SYLLABLE JYAD +C7D0;C7D0;110C 1163 11AF;C7D0;110C 1163 11AF; # (쟐; 쟐; 쟐; 쟐; 쟐; ) HANGUL SYLLABLE JYAL +C7D1;C7D1;110C 1163 11B0;C7D1;110C 1163 11B0; # (쟑; 쟑; 쟑; 쟑; 쟑; ) HANGUL SYLLABLE JYALG +C7D2;C7D2;110C 1163 11B1;C7D2;110C 1163 11B1; # (쟒; 쟒; 쟒; 쟒; 쟒; ) HANGUL SYLLABLE JYALM +C7D3;C7D3;110C 1163 11B2;C7D3;110C 1163 11B2; # (쟓; 쟓; 쟓; 쟓; 쟓; ) HANGUL SYLLABLE JYALB +C7D4;C7D4;110C 1163 11B3;C7D4;110C 1163 11B3; # (쟔; 쟔; 쟔; 쟔; 쟔; ) HANGUL SYLLABLE JYALS +C7D5;C7D5;110C 1163 11B4;C7D5;110C 1163 11B4; # (쟕; 쟕; 쟕; 쟕; 쟕; ) HANGUL SYLLABLE JYALT +C7D6;C7D6;110C 1163 11B5;C7D6;110C 1163 11B5; # (쟖; 쟖; 쟖; 쟖; 쟖; ) HANGUL SYLLABLE JYALP +C7D7;C7D7;110C 1163 11B6;C7D7;110C 1163 11B6; # (쟗; 쟗; 쟗; 쟗; 쟗; ) HANGUL SYLLABLE JYALH +C7D8;C7D8;110C 1163 11B7;C7D8;110C 1163 11B7; # (쟘; 쟘; 쟘; 쟘; 쟘; ) HANGUL SYLLABLE JYAM +C7D9;C7D9;110C 1163 11B8;C7D9;110C 1163 11B8; # (쟙; 쟙; 쟙; 쟙; 쟙; ) HANGUL SYLLABLE JYAB +C7DA;C7DA;110C 1163 11B9;C7DA;110C 1163 11B9; # (쟚; 쟚; 쟚; 쟚; 쟚; ) HANGUL SYLLABLE JYABS +C7DB;C7DB;110C 1163 11BA;C7DB;110C 1163 11BA; # (쟛; 쟛; 쟛; 쟛; 쟛; ) HANGUL SYLLABLE JYAS +C7DC;C7DC;110C 1163 11BB;C7DC;110C 1163 11BB; # (쟜; 쟜; 쟜; 쟜; 쟜; ) HANGUL SYLLABLE JYASS +C7DD;C7DD;110C 1163 11BC;C7DD;110C 1163 11BC; # (쟝; 쟝; 쟝; 쟝; 쟝; ) HANGUL SYLLABLE JYANG +C7DE;C7DE;110C 1163 11BD;C7DE;110C 1163 11BD; # (쟞; 쟞; 쟞; 쟞; 쟞; ) HANGUL SYLLABLE JYAJ +C7DF;C7DF;110C 1163 11BE;C7DF;110C 1163 11BE; # (쟟; 쟟; 쟟; 쟟; 쟟; ) HANGUL SYLLABLE JYAC +C7E0;C7E0;110C 1163 11BF;C7E0;110C 1163 11BF; # (쟠; 쟠; 쟠; 쟠; 쟠; ) HANGUL SYLLABLE JYAK +C7E1;C7E1;110C 1163 11C0;C7E1;110C 1163 11C0; # (쟡; 쟡; 쟡; 쟡; 쟡; ) HANGUL SYLLABLE JYAT +C7E2;C7E2;110C 1163 11C1;C7E2;110C 1163 11C1; # (쟢; 쟢; 쟢; 쟢; 쟢; ) HANGUL SYLLABLE JYAP +C7E3;C7E3;110C 1163 11C2;C7E3;110C 1163 11C2; # (쟣; 쟣; 쟣; 쟣; 쟣; ) HANGUL SYLLABLE JYAH +C7E4;C7E4;110C 1164;C7E4;110C 1164; # (쟤; 쟤; 쟤; 쟤; 쟤; ) HANGUL SYLLABLE JYAE +C7E5;C7E5;110C 1164 11A8;C7E5;110C 1164 11A8; # (쟥; 쟥; 쟥; 쟥; 쟥; ) HANGUL SYLLABLE JYAEG +C7E6;C7E6;110C 1164 11A9;C7E6;110C 1164 11A9; # (쟦; 쟦; 쟦; 쟦; 쟦; ) HANGUL SYLLABLE JYAEGG +C7E7;C7E7;110C 1164 11AA;C7E7;110C 1164 11AA; # (쟧; 쟧; 쟧; 쟧; 쟧; ) HANGUL SYLLABLE JYAEGS +C7E8;C7E8;110C 1164 11AB;C7E8;110C 1164 11AB; # (쟨; 쟨; 쟨; 쟨; 쟨; ) HANGUL SYLLABLE JYAEN +C7E9;C7E9;110C 1164 11AC;C7E9;110C 1164 11AC; # (쟩; 쟩; 쟩; 쟩; 쟩; ) HANGUL SYLLABLE JYAENJ +C7EA;C7EA;110C 1164 11AD;C7EA;110C 1164 11AD; # (쟪; 쟪; 쟪; 쟪; 쟪; ) HANGUL SYLLABLE JYAENH +C7EB;C7EB;110C 1164 11AE;C7EB;110C 1164 11AE; # (쟫; 쟫; 쟫; 쟫; 쟫; ) HANGUL SYLLABLE JYAED +C7EC;C7EC;110C 1164 11AF;C7EC;110C 1164 11AF; # (쟬; 쟬; 쟬; 쟬; 쟬; ) HANGUL SYLLABLE JYAEL +C7ED;C7ED;110C 1164 11B0;C7ED;110C 1164 11B0; # (쟭; 쟭; 쟭; 쟭; 쟭; ) HANGUL SYLLABLE JYAELG +C7EE;C7EE;110C 1164 11B1;C7EE;110C 1164 11B1; # (쟮; 쟮; 쟮; 쟮; 쟮; ) HANGUL SYLLABLE JYAELM +C7EF;C7EF;110C 1164 11B2;C7EF;110C 1164 11B2; # (쟯; 쟯; 쟯; 쟯; 쟯; ) HANGUL SYLLABLE JYAELB +C7F0;C7F0;110C 1164 11B3;C7F0;110C 1164 11B3; # (쟰; 쟰; 쟰; 쟰; 쟰; ) HANGUL SYLLABLE JYAELS +C7F1;C7F1;110C 1164 11B4;C7F1;110C 1164 11B4; # (쟱; 쟱; 쟱; 쟱; 쟱; ) HANGUL SYLLABLE JYAELT +C7F2;C7F2;110C 1164 11B5;C7F2;110C 1164 11B5; # (쟲; 쟲; 쟲; 쟲; 쟲; ) HANGUL SYLLABLE JYAELP +C7F3;C7F3;110C 1164 11B6;C7F3;110C 1164 11B6; # (쟳; 쟳; 쟳; 쟳; 쟳; ) HANGUL SYLLABLE JYAELH +C7F4;C7F4;110C 1164 11B7;C7F4;110C 1164 11B7; # (쟴; 쟴; 쟴; 쟴; 쟴; ) HANGUL SYLLABLE JYAEM +C7F5;C7F5;110C 1164 11B8;C7F5;110C 1164 11B8; # (쟵; 쟵; 쟵; 쟵; 쟵; ) HANGUL SYLLABLE JYAEB +C7F6;C7F6;110C 1164 11B9;C7F6;110C 1164 11B9; # (쟶; 쟶; 쟶; 쟶; 쟶; ) HANGUL SYLLABLE JYAEBS +C7F7;C7F7;110C 1164 11BA;C7F7;110C 1164 11BA; # (쟷; 쟷; 쟷; 쟷; 쟷; ) HANGUL SYLLABLE JYAES +C7F8;C7F8;110C 1164 11BB;C7F8;110C 1164 11BB; # (쟸; 쟸; 쟸; 쟸; 쟸; ) HANGUL SYLLABLE JYAESS +C7F9;C7F9;110C 1164 11BC;C7F9;110C 1164 11BC; # (쟹; 쟹; 쟹; 쟹; 쟹; ) HANGUL SYLLABLE JYAENG +C7FA;C7FA;110C 1164 11BD;C7FA;110C 1164 11BD; # (쟺; 쟺; 쟺; 쟺; 쟺; ) HANGUL SYLLABLE JYAEJ +C7FB;C7FB;110C 1164 11BE;C7FB;110C 1164 11BE; # (쟻; 쟻; 쟻; 쟻; 쟻; ) HANGUL SYLLABLE JYAEC +C7FC;C7FC;110C 1164 11BF;C7FC;110C 1164 11BF; # (쟼; 쟼; 쟼; 쟼; 쟼; ) HANGUL SYLLABLE JYAEK +C7FD;C7FD;110C 1164 11C0;C7FD;110C 1164 11C0; # (쟽; 쟽; 쟽; 쟽; 쟽; ) HANGUL SYLLABLE JYAET +C7FE;C7FE;110C 1164 11C1;C7FE;110C 1164 11C1; # (쟾; 쟾; 쟾; 쟾; 쟾; ) HANGUL SYLLABLE JYAEP +C7FF;C7FF;110C 1164 11C2;C7FF;110C 1164 11C2; # (쟿; 쟿; 쟿; 쟿; 쟿; ) HANGUL SYLLABLE JYAEH +C800;C800;110C 1165;C800;110C 1165; # (저; 저; 저; 저; 저; ) HANGUL SYLLABLE JEO +C801;C801;110C 1165 11A8;C801;110C 1165 11A8; # (적; 적; 적; 적; 적; ) HANGUL SYLLABLE JEOG +C802;C802;110C 1165 11A9;C802;110C 1165 11A9; # (젂; 젂; 젂; 젂; 젂; ) HANGUL SYLLABLE JEOGG +C803;C803;110C 1165 11AA;C803;110C 1165 11AA; # (젃; 젃; 젃; 젃; 젃; ) HANGUL SYLLABLE JEOGS +C804;C804;110C 1165 11AB;C804;110C 1165 11AB; # (전; 전; 전; 전; 전; ) HANGUL SYLLABLE JEON +C805;C805;110C 1165 11AC;C805;110C 1165 11AC; # (젅; 젅; 젅; 젅; 젅; ) HANGUL SYLLABLE JEONJ +C806;C806;110C 1165 11AD;C806;110C 1165 11AD; # (젆; 젆; 젆; 젆; 젆; ) HANGUL SYLLABLE JEONH +C807;C807;110C 1165 11AE;C807;110C 1165 11AE; # (젇; 젇; 젇; 젇; 젇; ) HANGUL SYLLABLE JEOD +C808;C808;110C 1165 11AF;C808;110C 1165 11AF; # (절; 절; 절; 절; 절; ) HANGUL SYLLABLE JEOL +C809;C809;110C 1165 11B0;C809;110C 1165 11B0; # (젉; 젉; 젉; 젉; 젉; ) HANGUL SYLLABLE JEOLG +C80A;C80A;110C 1165 11B1;C80A;110C 1165 11B1; # (젊; 젊; 젊; 젊; 젊; ) HANGUL SYLLABLE JEOLM +C80B;C80B;110C 1165 11B2;C80B;110C 1165 11B2; # (젋; 젋; 젋; 젋; 젋; ) HANGUL SYLLABLE JEOLB +C80C;C80C;110C 1165 11B3;C80C;110C 1165 11B3; # (젌; 젌; 젌; 젌; 젌; ) HANGUL SYLLABLE JEOLS +C80D;C80D;110C 1165 11B4;C80D;110C 1165 11B4; # (젍; 젍; 젍; 젍; 젍; ) HANGUL SYLLABLE JEOLT +C80E;C80E;110C 1165 11B5;C80E;110C 1165 11B5; # (젎; 젎; 젎; 젎; 젎; ) HANGUL SYLLABLE JEOLP +C80F;C80F;110C 1165 11B6;C80F;110C 1165 11B6; # (젏; 젏; 젏; 젏; 젏; ) HANGUL SYLLABLE JEOLH +C810;C810;110C 1165 11B7;C810;110C 1165 11B7; # (점; 점; 점; 점; 점; ) HANGUL SYLLABLE JEOM +C811;C811;110C 1165 11B8;C811;110C 1165 11B8; # (접; 접; 접; 접; 접; ) HANGUL SYLLABLE JEOB +C812;C812;110C 1165 11B9;C812;110C 1165 11B9; # (젒; 젒; 젒; 젒; 젒; ) HANGUL SYLLABLE JEOBS +C813;C813;110C 1165 11BA;C813;110C 1165 11BA; # (젓; 젓; 젓; 젓; 젓; ) HANGUL SYLLABLE JEOS +C814;C814;110C 1165 11BB;C814;110C 1165 11BB; # (젔; 젔; 젔; 젔; 젔; ) HANGUL SYLLABLE JEOSS +C815;C815;110C 1165 11BC;C815;110C 1165 11BC; # (정; 정; 정; 정; 정; ) HANGUL SYLLABLE JEONG +C816;C816;110C 1165 11BD;C816;110C 1165 11BD; # (젖; 젖; 젖; 젖; 젖; ) HANGUL SYLLABLE JEOJ +C817;C817;110C 1165 11BE;C817;110C 1165 11BE; # (젗; 젗; 젗; 젗; 젗; ) HANGUL SYLLABLE JEOC +C818;C818;110C 1165 11BF;C818;110C 1165 11BF; # (젘; 젘; 젘; 젘; 젘; ) HANGUL SYLLABLE JEOK +C819;C819;110C 1165 11C0;C819;110C 1165 11C0; # (젙; 젙; 젙; 젙; 젙; ) HANGUL SYLLABLE JEOT +C81A;C81A;110C 1165 11C1;C81A;110C 1165 11C1; # (젚; 젚; 젚; 젚; 젚; ) HANGUL SYLLABLE JEOP +C81B;C81B;110C 1165 11C2;C81B;110C 1165 11C2; # (젛; 젛; 젛; 젛; 젛; ) HANGUL SYLLABLE JEOH +C81C;C81C;110C 1166;C81C;110C 1166; # (제; 제; 제; 제; 제; ) HANGUL SYLLABLE JE +C81D;C81D;110C 1166 11A8;C81D;110C 1166 11A8; # (젝; 젝; 젝; 젝; 젝; ) HANGUL SYLLABLE JEG +C81E;C81E;110C 1166 11A9;C81E;110C 1166 11A9; # (젞; 젞; 젞; 젞; 젞; ) HANGUL SYLLABLE JEGG +C81F;C81F;110C 1166 11AA;C81F;110C 1166 11AA; # (젟; 젟; 젟; 젟; 젟; ) HANGUL SYLLABLE JEGS +C820;C820;110C 1166 11AB;C820;110C 1166 11AB; # (젠; 젠; 젠; 젠; 젠; ) HANGUL SYLLABLE JEN +C821;C821;110C 1166 11AC;C821;110C 1166 11AC; # (젡; 젡; 젡; 젡; 젡; ) HANGUL SYLLABLE JENJ +C822;C822;110C 1166 11AD;C822;110C 1166 11AD; # (젢; 젢; 젢; 젢; 젢; ) HANGUL SYLLABLE JENH +C823;C823;110C 1166 11AE;C823;110C 1166 11AE; # (젣; 젣; 젣; 젣; 젣; ) HANGUL SYLLABLE JED +C824;C824;110C 1166 11AF;C824;110C 1166 11AF; # (젤; 젤; 젤; 젤; 젤; ) HANGUL SYLLABLE JEL +C825;C825;110C 1166 11B0;C825;110C 1166 11B0; # (젥; 젥; 젥; 젥; 젥; ) HANGUL SYLLABLE JELG +C826;C826;110C 1166 11B1;C826;110C 1166 11B1; # (젦; 젦; 젦; 젦; 젦; ) HANGUL SYLLABLE JELM +C827;C827;110C 1166 11B2;C827;110C 1166 11B2; # (젧; 젧; 젧; 젧; 젧; ) HANGUL SYLLABLE JELB +C828;C828;110C 1166 11B3;C828;110C 1166 11B3; # (젨; 젨; 젨; 젨; 젨; ) HANGUL SYLLABLE JELS +C829;C829;110C 1166 11B4;C829;110C 1166 11B4; # (젩; 젩; 젩; 젩; 젩; ) HANGUL SYLLABLE JELT +C82A;C82A;110C 1166 11B5;C82A;110C 1166 11B5; # (젪; 젪; 젪; 젪; 젪; ) HANGUL SYLLABLE JELP +C82B;C82B;110C 1166 11B6;C82B;110C 1166 11B6; # (젫; 젫; 젫; 젫; 젫; ) HANGUL SYLLABLE JELH +C82C;C82C;110C 1166 11B7;C82C;110C 1166 11B7; # (젬; 젬; 젬; 젬; 젬; ) HANGUL SYLLABLE JEM +C82D;C82D;110C 1166 11B8;C82D;110C 1166 11B8; # (젭; 젭; 젭; 젭; 젭; ) HANGUL SYLLABLE JEB +C82E;C82E;110C 1166 11B9;C82E;110C 1166 11B9; # (젮; 젮; 젮; 젮; 젮; ) HANGUL SYLLABLE JEBS +C82F;C82F;110C 1166 11BA;C82F;110C 1166 11BA; # (젯; 젯; 젯; 젯; 젯; ) HANGUL SYLLABLE JES +C830;C830;110C 1166 11BB;C830;110C 1166 11BB; # (젰; 젰; 젰; 젰; 젰; ) HANGUL SYLLABLE JESS +C831;C831;110C 1166 11BC;C831;110C 1166 11BC; # (젱; 젱; 젱; 젱; 젱; ) HANGUL SYLLABLE JENG +C832;C832;110C 1166 11BD;C832;110C 1166 11BD; # (젲; 젲; 젲; 젲; 젲; ) HANGUL SYLLABLE JEJ +C833;C833;110C 1166 11BE;C833;110C 1166 11BE; # (젳; 젳; 젳; 젳; 젳; ) HANGUL SYLLABLE JEC +C834;C834;110C 1166 11BF;C834;110C 1166 11BF; # (젴; 젴; 젴; 젴; 젴; ) HANGUL SYLLABLE JEK +C835;C835;110C 1166 11C0;C835;110C 1166 11C0; # (젵; 젵; 젵; 젵; 젵; ) HANGUL SYLLABLE JET +C836;C836;110C 1166 11C1;C836;110C 1166 11C1; # (젶; 젶; 젶; 젶; 젶; ) HANGUL SYLLABLE JEP +C837;C837;110C 1166 11C2;C837;110C 1166 11C2; # (젷; 젷; 젷; 젷; 젷; ) HANGUL SYLLABLE JEH +C838;C838;110C 1167;C838;110C 1167; # (져; 져; 져; 져; 져; ) HANGUL SYLLABLE JYEO +C839;C839;110C 1167 11A8;C839;110C 1167 11A8; # (젹; 젹; 젹; 젹; 젹; ) HANGUL SYLLABLE JYEOG +C83A;C83A;110C 1167 11A9;C83A;110C 1167 11A9; # (젺; 젺; 젺; 젺; 젺; ) HANGUL SYLLABLE JYEOGG +C83B;C83B;110C 1167 11AA;C83B;110C 1167 11AA; # (젻; 젻; 젻; 젻; 젻; ) HANGUL SYLLABLE JYEOGS +C83C;C83C;110C 1167 11AB;C83C;110C 1167 11AB; # (젼; 젼; 젼; 젼; 젼; ) HANGUL SYLLABLE JYEON +C83D;C83D;110C 1167 11AC;C83D;110C 1167 11AC; # (젽; 젽; 젽; 젽; 젽; ) HANGUL SYLLABLE JYEONJ +C83E;C83E;110C 1167 11AD;C83E;110C 1167 11AD; # (젾; 젾; 젾; 젾; 젾; ) HANGUL SYLLABLE JYEONH +C83F;C83F;110C 1167 11AE;C83F;110C 1167 11AE; # (젿; 젿; 젿; 젿; 젿; ) HANGUL SYLLABLE JYEOD +C840;C840;110C 1167 11AF;C840;110C 1167 11AF; # (졀; 졀; 졀; 졀; 졀; ) HANGUL SYLLABLE JYEOL +C841;C841;110C 1167 11B0;C841;110C 1167 11B0; # (졁; 졁; 졁; 졁; 졁; ) HANGUL SYLLABLE JYEOLG +C842;C842;110C 1167 11B1;C842;110C 1167 11B1; # (졂; 졂; 졂; 졂; 졂; ) HANGUL SYLLABLE JYEOLM +C843;C843;110C 1167 11B2;C843;110C 1167 11B2; # (졃; 졃; 졃; 졃; 졃; ) HANGUL SYLLABLE JYEOLB +C844;C844;110C 1167 11B3;C844;110C 1167 11B3; # (졄; 졄; 졄; 졄; 졄; ) HANGUL SYLLABLE JYEOLS +C845;C845;110C 1167 11B4;C845;110C 1167 11B4; # (졅; 졅; 졅; 졅; 졅; ) HANGUL SYLLABLE JYEOLT +C846;C846;110C 1167 11B5;C846;110C 1167 11B5; # (졆; 졆; 졆; 졆; 졆; ) HANGUL SYLLABLE JYEOLP +C847;C847;110C 1167 11B6;C847;110C 1167 11B6; # (졇; 졇; 졇; 졇; 졇; ) HANGUL SYLLABLE JYEOLH +C848;C848;110C 1167 11B7;C848;110C 1167 11B7; # (졈; 졈; 졈; 졈; 졈; ) HANGUL SYLLABLE JYEOM +C849;C849;110C 1167 11B8;C849;110C 1167 11B8; # (졉; 졉; 졉; 졉; 졉; ) HANGUL SYLLABLE JYEOB +C84A;C84A;110C 1167 11B9;C84A;110C 1167 11B9; # (졊; 졊; 졊; 졊; 졊; ) HANGUL SYLLABLE JYEOBS +C84B;C84B;110C 1167 11BA;C84B;110C 1167 11BA; # (졋; 졋; 졋; 졋; 졋; ) HANGUL SYLLABLE JYEOS +C84C;C84C;110C 1167 11BB;C84C;110C 1167 11BB; # (졌; 졌; 졌; 졌; 졌; ) HANGUL SYLLABLE JYEOSS +C84D;C84D;110C 1167 11BC;C84D;110C 1167 11BC; # (졍; 졍; 졍; 졍; 졍; ) HANGUL SYLLABLE JYEONG +C84E;C84E;110C 1167 11BD;C84E;110C 1167 11BD; # (졎; 졎; 졎; 졎; 졎; ) HANGUL SYLLABLE JYEOJ +C84F;C84F;110C 1167 11BE;C84F;110C 1167 11BE; # (졏; 졏; 졏; 졏; 졏; ) HANGUL SYLLABLE JYEOC +C850;C850;110C 1167 11BF;C850;110C 1167 11BF; # (졐; 졐; 졐; 졐; 졐; ) HANGUL SYLLABLE JYEOK +C851;C851;110C 1167 11C0;C851;110C 1167 11C0; # (졑; 졑; 졑; 졑; 졑; ) HANGUL SYLLABLE JYEOT +C852;C852;110C 1167 11C1;C852;110C 1167 11C1; # (졒; 졒; 졒; 졒; 졒; ) HANGUL SYLLABLE JYEOP +C853;C853;110C 1167 11C2;C853;110C 1167 11C2; # (졓; 졓; 졓; 졓; 졓; ) HANGUL SYLLABLE JYEOH +C854;C854;110C 1168;C854;110C 1168; # (졔; 졔; 졔; 졔; 졔; ) HANGUL SYLLABLE JYE +C855;C855;110C 1168 11A8;C855;110C 1168 11A8; # (졕; 졕; 졕; 졕; 졕; ) HANGUL SYLLABLE JYEG +C856;C856;110C 1168 11A9;C856;110C 1168 11A9; # (졖; 졖; 졖; 졖; 졖; ) HANGUL SYLLABLE JYEGG +C857;C857;110C 1168 11AA;C857;110C 1168 11AA; # (졗; 졗; 졗; 졗; 졗; ) HANGUL SYLLABLE JYEGS +C858;C858;110C 1168 11AB;C858;110C 1168 11AB; # (졘; 졘; 졘; 졘; 졘; ) HANGUL SYLLABLE JYEN +C859;C859;110C 1168 11AC;C859;110C 1168 11AC; # (졙; 졙; 졙; 졙; 졙; ) HANGUL SYLLABLE JYENJ +C85A;C85A;110C 1168 11AD;C85A;110C 1168 11AD; # (졚; 졚; 졚; 졚; 졚; ) HANGUL SYLLABLE JYENH +C85B;C85B;110C 1168 11AE;C85B;110C 1168 11AE; # (졛; 졛; 졛; 졛; 졛; ) HANGUL SYLLABLE JYED +C85C;C85C;110C 1168 11AF;C85C;110C 1168 11AF; # (졜; 졜; 졜; 졜; 졜; ) HANGUL SYLLABLE JYEL +C85D;C85D;110C 1168 11B0;C85D;110C 1168 11B0; # (졝; 졝; 졝; 졝; 졝; ) HANGUL SYLLABLE JYELG +C85E;C85E;110C 1168 11B1;C85E;110C 1168 11B1; # (졞; 졞; 졞; 졞; 졞; ) HANGUL SYLLABLE JYELM +C85F;C85F;110C 1168 11B2;C85F;110C 1168 11B2; # (졟; 졟; 졟; 졟; 졟; ) HANGUL SYLLABLE JYELB +C860;C860;110C 1168 11B3;C860;110C 1168 11B3; # (졠; 졠; 졠; 졠; 졠; ) HANGUL SYLLABLE JYELS +C861;C861;110C 1168 11B4;C861;110C 1168 11B4; # (졡; 졡; 졡; 졡; 졡; ) HANGUL SYLLABLE JYELT +C862;C862;110C 1168 11B5;C862;110C 1168 11B5; # (졢; 졢; 졢; 졢; 졢; ) HANGUL SYLLABLE JYELP +C863;C863;110C 1168 11B6;C863;110C 1168 11B6; # (졣; 졣; 졣; 졣; 졣; ) HANGUL SYLLABLE JYELH +C864;C864;110C 1168 11B7;C864;110C 1168 11B7; # (졤; 졤; 졤; 졤; 졤; ) HANGUL SYLLABLE JYEM +C865;C865;110C 1168 11B8;C865;110C 1168 11B8; # (졥; 졥; 졥; 졥; 졥; ) HANGUL SYLLABLE JYEB +C866;C866;110C 1168 11B9;C866;110C 1168 11B9; # (졦; 졦; 졦; 졦; 졦; ) HANGUL SYLLABLE JYEBS +C867;C867;110C 1168 11BA;C867;110C 1168 11BA; # (졧; 졧; 졧; 졧; 졧; ) HANGUL SYLLABLE JYES +C868;C868;110C 1168 11BB;C868;110C 1168 11BB; # (졨; 졨; 졨; 졨; 졨; ) HANGUL SYLLABLE JYESS +C869;C869;110C 1168 11BC;C869;110C 1168 11BC; # (졩; 졩; 졩; 졩; 졩; ) HANGUL SYLLABLE JYENG +C86A;C86A;110C 1168 11BD;C86A;110C 1168 11BD; # (졪; 졪; 졪; 졪; 졪; ) HANGUL SYLLABLE JYEJ +C86B;C86B;110C 1168 11BE;C86B;110C 1168 11BE; # (졫; 졫; 졫; 졫; 졫; ) HANGUL SYLLABLE JYEC +C86C;C86C;110C 1168 11BF;C86C;110C 1168 11BF; # (졬; 졬; 졬; 졬; 졬; ) HANGUL SYLLABLE JYEK +C86D;C86D;110C 1168 11C0;C86D;110C 1168 11C0; # (졭; 졭; 졭; 졭; 졭; ) HANGUL SYLLABLE JYET +C86E;C86E;110C 1168 11C1;C86E;110C 1168 11C1; # (졮; 졮; 졮; 졮; 졮; ) HANGUL SYLLABLE JYEP +C86F;C86F;110C 1168 11C2;C86F;110C 1168 11C2; # (졯; 졯; 졯; 졯; 졯; ) HANGUL SYLLABLE JYEH +C870;C870;110C 1169;C870;110C 1169; # (조; 조; 조; 조; 조; ) HANGUL SYLLABLE JO +C871;C871;110C 1169 11A8;C871;110C 1169 11A8; # (족; 족; 족; 족; 족; ) HANGUL SYLLABLE JOG +C872;C872;110C 1169 11A9;C872;110C 1169 11A9; # (졲; 졲; 졲; 졲; 졲; ) HANGUL SYLLABLE JOGG +C873;C873;110C 1169 11AA;C873;110C 1169 11AA; # (졳; 졳; 졳; 졳; 졳; ) HANGUL SYLLABLE JOGS +C874;C874;110C 1169 11AB;C874;110C 1169 11AB; # (존; 존; 존; 존; 존; ) HANGUL SYLLABLE JON +C875;C875;110C 1169 11AC;C875;110C 1169 11AC; # (졵; 졵; 졵; 졵; 졵; ) HANGUL SYLLABLE JONJ +C876;C876;110C 1169 11AD;C876;110C 1169 11AD; # (졶; 졶; 졶; 졶; 졶; ) HANGUL SYLLABLE JONH +C877;C877;110C 1169 11AE;C877;110C 1169 11AE; # (졷; 졷; 졷; 졷; 졷; ) HANGUL SYLLABLE JOD +C878;C878;110C 1169 11AF;C878;110C 1169 11AF; # (졸; 졸; 졸; 졸; 졸; ) HANGUL SYLLABLE JOL +C879;C879;110C 1169 11B0;C879;110C 1169 11B0; # (졹; 졹; 졹; 졹; 졹; ) HANGUL SYLLABLE JOLG +C87A;C87A;110C 1169 11B1;C87A;110C 1169 11B1; # (졺; 졺; 졺; 졺; 졺; ) HANGUL SYLLABLE JOLM +C87B;C87B;110C 1169 11B2;C87B;110C 1169 11B2; # (졻; 졻; 졻; 졻; 졻; ) HANGUL SYLLABLE JOLB +C87C;C87C;110C 1169 11B3;C87C;110C 1169 11B3; # (졼; 졼; 졼; 졼; 졼; ) HANGUL SYLLABLE JOLS +C87D;C87D;110C 1169 11B4;C87D;110C 1169 11B4; # (졽; 졽; 졽; 졽; 졽; ) HANGUL SYLLABLE JOLT +C87E;C87E;110C 1169 11B5;C87E;110C 1169 11B5; # (졾; 졾; 졾; 졾; 졾; ) HANGUL SYLLABLE JOLP +C87F;C87F;110C 1169 11B6;C87F;110C 1169 11B6; # (졿; 졿; 졿; 졿; 졿; ) HANGUL SYLLABLE JOLH +C880;C880;110C 1169 11B7;C880;110C 1169 11B7; # (좀; 좀; 좀; 좀; 좀; ) HANGUL SYLLABLE JOM +C881;C881;110C 1169 11B8;C881;110C 1169 11B8; # (좁; 좁; 좁; 좁; 좁; ) HANGUL SYLLABLE JOB +C882;C882;110C 1169 11B9;C882;110C 1169 11B9; # (좂; 좂; 좂; 좂; 좂; ) HANGUL SYLLABLE JOBS +C883;C883;110C 1169 11BA;C883;110C 1169 11BA; # (좃; 좃; 좃; 좃; 좃; ) HANGUL SYLLABLE JOS +C884;C884;110C 1169 11BB;C884;110C 1169 11BB; # (좄; 좄; 좄; 좄; 좄; ) HANGUL SYLLABLE JOSS +C885;C885;110C 1169 11BC;C885;110C 1169 11BC; # (종; 종; 종; 종; 종; ) HANGUL SYLLABLE JONG +C886;C886;110C 1169 11BD;C886;110C 1169 11BD; # (좆; 좆; 좆; 좆; 좆; ) HANGUL SYLLABLE JOJ +C887;C887;110C 1169 11BE;C887;110C 1169 11BE; # (좇; 좇; 좇; 좇; 좇; ) HANGUL SYLLABLE JOC +C888;C888;110C 1169 11BF;C888;110C 1169 11BF; # (좈; 좈; 좈; 좈; 좈; ) HANGUL SYLLABLE JOK +C889;C889;110C 1169 11C0;C889;110C 1169 11C0; # (좉; 좉; 좉; 좉; 좉; ) HANGUL SYLLABLE JOT +C88A;C88A;110C 1169 11C1;C88A;110C 1169 11C1; # (좊; 좊; 좊; 좊; 좊; ) HANGUL SYLLABLE JOP +C88B;C88B;110C 1169 11C2;C88B;110C 1169 11C2; # (좋; 좋; 좋; 좋; 좋; ) HANGUL SYLLABLE JOH +C88C;C88C;110C 116A;C88C;110C 116A; # (좌; 좌; 좌; 좌; 좌; ) HANGUL SYLLABLE JWA +C88D;C88D;110C 116A 11A8;C88D;110C 116A 11A8; # (좍; 좍; 좍; 좍; 좍; ) HANGUL SYLLABLE JWAG +C88E;C88E;110C 116A 11A9;C88E;110C 116A 11A9; # (좎; 좎; 좎; 좎; 좎; ) HANGUL SYLLABLE JWAGG +C88F;C88F;110C 116A 11AA;C88F;110C 116A 11AA; # (좏; 좏; 좏; 좏; 좏; ) HANGUL SYLLABLE JWAGS +C890;C890;110C 116A 11AB;C890;110C 116A 11AB; # (좐; 좐; 좐; 좐; 좐; ) HANGUL SYLLABLE JWAN +C891;C891;110C 116A 11AC;C891;110C 116A 11AC; # (좑; 좑; 좑; 좑; 좑; ) HANGUL SYLLABLE JWANJ +C892;C892;110C 116A 11AD;C892;110C 116A 11AD; # (좒; 좒; 좒; 좒; 좒; ) HANGUL SYLLABLE JWANH +C893;C893;110C 116A 11AE;C893;110C 116A 11AE; # (좓; 좓; 좓; 좓; 좓; ) HANGUL SYLLABLE JWAD +C894;C894;110C 116A 11AF;C894;110C 116A 11AF; # (좔; 좔; 좔; 좔; 좔; ) HANGUL SYLLABLE JWAL +C895;C895;110C 116A 11B0;C895;110C 116A 11B0; # (좕; 좕; 좕; 좕; 좕; ) HANGUL SYLLABLE JWALG +C896;C896;110C 116A 11B1;C896;110C 116A 11B1; # (좖; 좖; 좖; 좖; 좖; ) HANGUL SYLLABLE JWALM +C897;C897;110C 116A 11B2;C897;110C 116A 11B2; # (좗; 좗; 좗; 좗; 좗; ) HANGUL SYLLABLE JWALB +C898;C898;110C 116A 11B3;C898;110C 116A 11B3; # (좘; 좘; 좘; 좘; 좘; ) HANGUL SYLLABLE JWALS +C899;C899;110C 116A 11B4;C899;110C 116A 11B4; # (좙; 좙; 좙; 좙; 좙; ) HANGUL SYLLABLE JWALT +C89A;C89A;110C 116A 11B5;C89A;110C 116A 11B5; # (좚; 좚; 좚; 좚; 좚; ) HANGUL SYLLABLE JWALP +C89B;C89B;110C 116A 11B6;C89B;110C 116A 11B6; # (좛; 좛; 좛; 좛; 좛; ) HANGUL SYLLABLE JWALH +C89C;C89C;110C 116A 11B7;C89C;110C 116A 11B7; # (좜; 좜; 좜; 좜; 좜; ) HANGUL SYLLABLE JWAM +C89D;C89D;110C 116A 11B8;C89D;110C 116A 11B8; # (좝; 좝; 좝; 좝; 좝; ) HANGUL SYLLABLE JWAB +C89E;C89E;110C 116A 11B9;C89E;110C 116A 11B9; # (좞; 좞; 좞; 좞; 좞; ) HANGUL SYLLABLE JWABS +C89F;C89F;110C 116A 11BA;C89F;110C 116A 11BA; # (좟; 좟; 좟; 좟; 좟; ) HANGUL SYLLABLE JWAS +C8A0;C8A0;110C 116A 11BB;C8A0;110C 116A 11BB; # (좠; 좠; 좠; 좠; 좠; ) HANGUL SYLLABLE JWASS +C8A1;C8A1;110C 116A 11BC;C8A1;110C 116A 11BC; # (좡; 좡; 좡; 좡; 좡; ) HANGUL SYLLABLE JWANG +C8A2;C8A2;110C 116A 11BD;C8A2;110C 116A 11BD; # (좢; 좢; 좢; 좢; 좢; ) HANGUL SYLLABLE JWAJ +C8A3;C8A3;110C 116A 11BE;C8A3;110C 116A 11BE; # (좣; 좣; 좣; 좣; 좣; ) HANGUL SYLLABLE JWAC +C8A4;C8A4;110C 116A 11BF;C8A4;110C 116A 11BF; # (좤; 좤; 좤; 좤; 좤; ) HANGUL SYLLABLE JWAK +C8A5;C8A5;110C 116A 11C0;C8A5;110C 116A 11C0; # (좥; 좥; 좥; 좥; 좥; ) HANGUL SYLLABLE JWAT +C8A6;C8A6;110C 116A 11C1;C8A6;110C 116A 11C1; # (좦; 좦; 좦; 좦; 좦; ) HANGUL SYLLABLE JWAP +C8A7;C8A7;110C 116A 11C2;C8A7;110C 116A 11C2; # (좧; 좧; 좧; 좧; 좧; ) HANGUL SYLLABLE JWAH +C8A8;C8A8;110C 116B;C8A8;110C 116B; # (좨; 좨; 좨; 좨; 좨; ) HANGUL SYLLABLE JWAE +C8A9;C8A9;110C 116B 11A8;C8A9;110C 116B 11A8; # (좩; 좩; 좩; 좩; 좩; ) HANGUL SYLLABLE JWAEG +C8AA;C8AA;110C 116B 11A9;C8AA;110C 116B 11A9; # (좪; 좪; 좪; 좪; 좪; ) HANGUL SYLLABLE JWAEGG +C8AB;C8AB;110C 116B 11AA;C8AB;110C 116B 11AA; # (좫; 좫; 좫; 좫; 좫; ) HANGUL SYLLABLE JWAEGS +C8AC;C8AC;110C 116B 11AB;C8AC;110C 116B 11AB; # (좬; 좬; 좬; 좬; 좬; ) HANGUL SYLLABLE JWAEN +C8AD;C8AD;110C 116B 11AC;C8AD;110C 116B 11AC; # (좭; 좭; 좭; 좭; 좭; ) HANGUL SYLLABLE JWAENJ +C8AE;C8AE;110C 116B 11AD;C8AE;110C 116B 11AD; # (좮; 좮; 좮; 좮; 좮; ) HANGUL SYLLABLE JWAENH +C8AF;C8AF;110C 116B 11AE;C8AF;110C 116B 11AE; # (좯; 좯; 좯; 좯; 좯; ) HANGUL SYLLABLE JWAED +C8B0;C8B0;110C 116B 11AF;C8B0;110C 116B 11AF; # (좰; 좰; 좰; 좰; 좰; ) HANGUL SYLLABLE JWAEL +C8B1;C8B1;110C 116B 11B0;C8B1;110C 116B 11B0; # (좱; 좱; 좱; 좱; 좱; ) HANGUL SYLLABLE JWAELG +C8B2;C8B2;110C 116B 11B1;C8B2;110C 116B 11B1; # (좲; 좲; 좲; 좲; 좲; ) HANGUL SYLLABLE JWAELM +C8B3;C8B3;110C 116B 11B2;C8B3;110C 116B 11B2; # (좳; 좳; 좳; 좳; 좳; ) HANGUL SYLLABLE JWAELB +C8B4;C8B4;110C 116B 11B3;C8B4;110C 116B 11B3; # (좴; 좴; 좴; 좴; 좴; ) HANGUL SYLLABLE JWAELS +C8B5;C8B5;110C 116B 11B4;C8B5;110C 116B 11B4; # (좵; 좵; 좵; 좵; 좵; ) HANGUL SYLLABLE JWAELT +C8B6;C8B6;110C 116B 11B5;C8B6;110C 116B 11B5; # (좶; 좶; 좶; 좶; 좶; ) HANGUL SYLLABLE JWAELP +C8B7;C8B7;110C 116B 11B6;C8B7;110C 116B 11B6; # (좷; 좷; 좷; 좷; 좷; ) HANGUL SYLLABLE JWAELH +C8B8;C8B8;110C 116B 11B7;C8B8;110C 116B 11B7; # (좸; 좸; 좸; 좸; 좸; ) HANGUL SYLLABLE JWAEM +C8B9;C8B9;110C 116B 11B8;C8B9;110C 116B 11B8; # (좹; 좹; 좹; 좹; 좹; ) HANGUL SYLLABLE JWAEB +C8BA;C8BA;110C 116B 11B9;C8BA;110C 116B 11B9; # (좺; 좺; 좺; 좺; 좺; ) HANGUL SYLLABLE JWAEBS +C8BB;C8BB;110C 116B 11BA;C8BB;110C 116B 11BA; # (좻; 좻; 좻; 좻; 좻; ) HANGUL SYLLABLE JWAES +C8BC;C8BC;110C 116B 11BB;C8BC;110C 116B 11BB; # (좼; 좼; 좼; 좼; 좼; ) HANGUL SYLLABLE JWAESS +C8BD;C8BD;110C 116B 11BC;C8BD;110C 116B 11BC; # (좽; 좽; 좽; 좽; 좽; ) HANGUL SYLLABLE JWAENG +C8BE;C8BE;110C 116B 11BD;C8BE;110C 116B 11BD; # (좾; 좾; 좾; 좾; 좾; ) HANGUL SYLLABLE JWAEJ +C8BF;C8BF;110C 116B 11BE;C8BF;110C 116B 11BE; # (좿; 좿; 좿; 좿; 좿; ) HANGUL SYLLABLE JWAEC +C8C0;C8C0;110C 116B 11BF;C8C0;110C 116B 11BF; # (죀; 죀; 죀; 죀; 죀; ) HANGUL SYLLABLE JWAEK +C8C1;C8C1;110C 116B 11C0;C8C1;110C 116B 11C0; # (죁; 죁; 죁; 죁; 죁; ) HANGUL SYLLABLE JWAET +C8C2;C8C2;110C 116B 11C1;C8C2;110C 116B 11C1; # (죂; 죂; 죂; 죂; 죂; ) HANGUL SYLLABLE JWAEP +C8C3;C8C3;110C 116B 11C2;C8C3;110C 116B 11C2; # (죃; 죃; 죃; 죃; 죃; ) HANGUL SYLLABLE JWAEH +C8C4;C8C4;110C 116C;C8C4;110C 116C; # (죄; 죄; 죄; 죄; 죄; ) HANGUL SYLLABLE JOE +C8C5;C8C5;110C 116C 11A8;C8C5;110C 116C 11A8; # (죅; 죅; 죅; 죅; 죅; ) HANGUL SYLLABLE JOEG +C8C6;C8C6;110C 116C 11A9;C8C6;110C 116C 11A9; # (죆; 죆; 죆; 죆; 죆; ) HANGUL SYLLABLE JOEGG +C8C7;C8C7;110C 116C 11AA;C8C7;110C 116C 11AA; # (죇; 죇; 죇; 죇; 죇; ) HANGUL SYLLABLE JOEGS +C8C8;C8C8;110C 116C 11AB;C8C8;110C 116C 11AB; # (죈; 죈; 죈; 죈; 죈; ) HANGUL SYLLABLE JOEN +C8C9;C8C9;110C 116C 11AC;C8C9;110C 116C 11AC; # (죉; 죉; 죉; 죉; 죉; ) HANGUL SYLLABLE JOENJ +C8CA;C8CA;110C 116C 11AD;C8CA;110C 116C 11AD; # (죊; 죊; 죊; 죊; 죊; ) HANGUL SYLLABLE JOENH +C8CB;C8CB;110C 116C 11AE;C8CB;110C 116C 11AE; # (죋; 죋; 죋; 죋; 죋; ) HANGUL SYLLABLE JOED +C8CC;C8CC;110C 116C 11AF;C8CC;110C 116C 11AF; # (죌; 죌; 죌; 죌; 죌; ) HANGUL SYLLABLE JOEL +C8CD;C8CD;110C 116C 11B0;C8CD;110C 116C 11B0; # (죍; 죍; 죍; 죍; 죍; ) HANGUL SYLLABLE JOELG +C8CE;C8CE;110C 116C 11B1;C8CE;110C 116C 11B1; # (죎; 죎; 죎; 죎; 죎; ) HANGUL SYLLABLE JOELM +C8CF;C8CF;110C 116C 11B2;C8CF;110C 116C 11B2; # (죏; 죏; 죏; 죏; 죏; ) HANGUL SYLLABLE JOELB +C8D0;C8D0;110C 116C 11B3;C8D0;110C 116C 11B3; # (죐; 죐; 죐; 죐; 죐; ) HANGUL SYLLABLE JOELS +C8D1;C8D1;110C 116C 11B4;C8D1;110C 116C 11B4; # (죑; 죑; 죑; 죑; 죑; ) HANGUL SYLLABLE JOELT +C8D2;C8D2;110C 116C 11B5;C8D2;110C 116C 11B5; # (죒; 죒; 죒; 죒; 죒; ) HANGUL SYLLABLE JOELP +C8D3;C8D3;110C 116C 11B6;C8D3;110C 116C 11B6; # (죓; 죓; 죓; 죓; 죓; ) HANGUL SYLLABLE JOELH +C8D4;C8D4;110C 116C 11B7;C8D4;110C 116C 11B7; # (죔; 죔; 죔; 죔; 죔; ) HANGUL SYLLABLE JOEM +C8D5;C8D5;110C 116C 11B8;C8D5;110C 116C 11B8; # (죕; 죕; 죕; 죕; 죕; ) HANGUL SYLLABLE JOEB +C8D6;C8D6;110C 116C 11B9;C8D6;110C 116C 11B9; # (죖; 죖; 죖; 죖; 죖; ) HANGUL SYLLABLE JOEBS +C8D7;C8D7;110C 116C 11BA;C8D7;110C 116C 11BA; # (죗; 죗; 죗; 죗; 죗; ) HANGUL SYLLABLE JOES +C8D8;C8D8;110C 116C 11BB;C8D8;110C 116C 11BB; # (죘; 죘; 죘; 죘; 죘; ) HANGUL SYLLABLE JOESS +C8D9;C8D9;110C 116C 11BC;C8D9;110C 116C 11BC; # (죙; 죙; 죙; 죙; 죙; ) HANGUL SYLLABLE JOENG +C8DA;C8DA;110C 116C 11BD;C8DA;110C 116C 11BD; # (죚; 죚; 죚; 죚; 죚; ) HANGUL SYLLABLE JOEJ +C8DB;C8DB;110C 116C 11BE;C8DB;110C 116C 11BE; # (죛; 죛; 죛; 죛; 죛; ) HANGUL SYLLABLE JOEC +C8DC;C8DC;110C 116C 11BF;C8DC;110C 116C 11BF; # (죜; 죜; 죜; 죜; 죜; ) HANGUL SYLLABLE JOEK +C8DD;C8DD;110C 116C 11C0;C8DD;110C 116C 11C0; # (죝; 죝; 죝; 죝; 죝; ) HANGUL SYLLABLE JOET +C8DE;C8DE;110C 116C 11C1;C8DE;110C 116C 11C1; # (죞; 죞; 죞; 죞; 죞; ) HANGUL SYLLABLE JOEP +C8DF;C8DF;110C 116C 11C2;C8DF;110C 116C 11C2; # (죟; 죟; 죟; 죟; 죟; ) HANGUL SYLLABLE JOEH +C8E0;C8E0;110C 116D;C8E0;110C 116D; # (죠; 죠; 죠; 죠; 죠; ) HANGUL SYLLABLE JYO +C8E1;C8E1;110C 116D 11A8;C8E1;110C 116D 11A8; # (죡; 죡; 죡; 죡; 죡; ) HANGUL SYLLABLE JYOG +C8E2;C8E2;110C 116D 11A9;C8E2;110C 116D 11A9; # (죢; 죢; 죢; 죢; 죢; ) HANGUL SYLLABLE JYOGG +C8E3;C8E3;110C 116D 11AA;C8E3;110C 116D 11AA; # (죣; 죣; 죣; 죣; 죣; ) HANGUL SYLLABLE JYOGS +C8E4;C8E4;110C 116D 11AB;C8E4;110C 116D 11AB; # (죤; 죤; 죤; 죤; 죤; ) HANGUL SYLLABLE JYON +C8E5;C8E5;110C 116D 11AC;C8E5;110C 116D 11AC; # (죥; 죥; 죥; 죥; 죥; ) HANGUL SYLLABLE JYONJ +C8E6;C8E6;110C 116D 11AD;C8E6;110C 116D 11AD; # (죦; 죦; 죦; 죦; 죦; ) HANGUL SYLLABLE JYONH +C8E7;C8E7;110C 116D 11AE;C8E7;110C 116D 11AE; # (죧; 죧; 죧; 죧; 죧; ) HANGUL SYLLABLE JYOD +C8E8;C8E8;110C 116D 11AF;C8E8;110C 116D 11AF; # (죨; 죨; 죨; 죨; 죨; ) HANGUL SYLLABLE JYOL +C8E9;C8E9;110C 116D 11B0;C8E9;110C 116D 11B0; # (죩; 죩; 죩; 죩; 죩; ) HANGUL SYLLABLE JYOLG +C8EA;C8EA;110C 116D 11B1;C8EA;110C 116D 11B1; # (죪; 죪; 죪; 죪; 죪; ) HANGUL SYLLABLE JYOLM +C8EB;C8EB;110C 116D 11B2;C8EB;110C 116D 11B2; # (죫; 죫; 죫; 죫; 죫; ) HANGUL SYLLABLE JYOLB +C8EC;C8EC;110C 116D 11B3;C8EC;110C 116D 11B3; # (죬; 죬; 죬; 죬; 죬; ) HANGUL SYLLABLE JYOLS +C8ED;C8ED;110C 116D 11B4;C8ED;110C 116D 11B4; # (죭; 죭; 죭; 죭; 죭; ) HANGUL SYLLABLE JYOLT +C8EE;C8EE;110C 116D 11B5;C8EE;110C 116D 11B5; # (죮; 죮; 죮; 죮; 죮; ) HANGUL SYLLABLE JYOLP +C8EF;C8EF;110C 116D 11B6;C8EF;110C 116D 11B6; # (죯; 죯; 죯; 죯; 죯; ) HANGUL SYLLABLE JYOLH +C8F0;C8F0;110C 116D 11B7;C8F0;110C 116D 11B7; # (죰; 죰; 죰; 죰; 죰; ) HANGUL SYLLABLE JYOM +C8F1;C8F1;110C 116D 11B8;C8F1;110C 116D 11B8; # (죱; 죱; 죱; 죱; 죱; ) HANGUL SYLLABLE JYOB +C8F2;C8F2;110C 116D 11B9;C8F2;110C 116D 11B9; # (죲; 죲; 죲; 죲; 죲; ) HANGUL SYLLABLE JYOBS +C8F3;C8F3;110C 116D 11BA;C8F3;110C 116D 11BA; # (죳; 죳; 죳; 죳; 죳; ) HANGUL SYLLABLE JYOS +C8F4;C8F4;110C 116D 11BB;C8F4;110C 116D 11BB; # (죴; 죴; 죴; 죴; 죴; ) HANGUL SYLLABLE JYOSS +C8F5;C8F5;110C 116D 11BC;C8F5;110C 116D 11BC; # (죵; 죵; 죵; 죵; 죵; ) HANGUL SYLLABLE JYONG +C8F6;C8F6;110C 116D 11BD;C8F6;110C 116D 11BD; # (죶; 죶; 죶; 죶; 죶; ) HANGUL SYLLABLE JYOJ +C8F7;C8F7;110C 116D 11BE;C8F7;110C 116D 11BE; # (죷; 죷; 죷; 죷; 죷; ) HANGUL SYLLABLE JYOC +C8F8;C8F8;110C 116D 11BF;C8F8;110C 116D 11BF; # (죸; 죸; 죸; 죸; 죸; ) HANGUL SYLLABLE JYOK +C8F9;C8F9;110C 116D 11C0;C8F9;110C 116D 11C0; # (죹; 죹; 죹; 죹; 죹; ) HANGUL SYLLABLE JYOT +C8FA;C8FA;110C 116D 11C1;C8FA;110C 116D 11C1; # (죺; 죺; 죺; 죺; 죺; ) HANGUL SYLLABLE JYOP +C8FB;C8FB;110C 116D 11C2;C8FB;110C 116D 11C2; # (죻; 죻; 죻; 죻; 죻; ) HANGUL SYLLABLE JYOH +C8FC;C8FC;110C 116E;C8FC;110C 116E; # (주; 주; 주; 주; 주; ) HANGUL SYLLABLE JU +C8FD;C8FD;110C 116E 11A8;C8FD;110C 116E 11A8; # (죽; 죽; 죽; 죽; 죽; ) HANGUL SYLLABLE JUG +C8FE;C8FE;110C 116E 11A9;C8FE;110C 116E 11A9; # (죾; 죾; 죾; 죾; 죾; ) HANGUL SYLLABLE JUGG +C8FF;C8FF;110C 116E 11AA;C8FF;110C 116E 11AA; # (죿; 죿; 죿; 죿; 죿; ) HANGUL SYLLABLE JUGS +C900;C900;110C 116E 11AB;C900;110C 116E 11AB; # (준; 준; 준; 준; 준; ) HANGUL SYLLABLE JUN +C901;C901;110C 116E 11AC;C901;110C 116E 11AC; # (줁; 줁; 줁; 줁; 줁; ) HANGUL SYLLABLE JUNJ +C902;C902;110C 116E 11AD;C902;110C 116E 11AD; # (줂; 줂; 줂; 줂; 줂; ) HANGUL SYLLABLE JUNH +C903;C903;110C 116E 11AE;C903;110C 116E 11AE; # (줃; 줃; 줃; 줃; 줃; ) HANGUL SYLLABLE JUD +C904;C904;110C 116E 11AF;C904;110C 116E 11AF; # (줄; 줄; 줄; 줄; 줄; ) HANGUL SYLLABLE JUL +C905;C905;110C 116E 11B0;C905;110C 116E 11B0; # (줅; 줅; 줅; 줅; 줅; ) HANGUL SYLLABLE JULG +C906;C906;110C 116E 11B1;C906;110C 116E 11B1; # (줆; 줆; 줆; 줆; 줆; ) HANGUL SYLLABLE JULM +C907;C907;110C 116E 11B2;C907;110C 116E 11B2; # (줇; 줇; 줇; 줇; 줇; ) HANGUL SYLLABLE JULB +C908;C908;110C 116E 11B3;C908;110C 116E 11B3; # (줈; 줈; 줈; 줈; 줈; ) HANGUL SYLLABLE JULS +C909;C909;110C 116E 11B4;C909;110C 116E 11B4; # (줉; 줉; 줉; 줉; 줉; ) HANGUL SYLLABLE JULT +C90A;C90A;110C 116E 11B5;C90A;110C 116E 11B5; # (줊; 줊; 줊; 줊; 줊; ) HANGUL SYLLABLE JULP +C90B;C90B;110C 116E 11B6;C90B;110C 116E 11B6; # (줋; 줋; 줋; 줋; 줋; ) HANGUL SYLLABLE JULH +C90C;C90C;110C 116E 11B7;C90C;110C 116E 11B7; # (줌; 줌; 줌; 줌; 줌; ) HANGUL SYLLABLE JUM +C90D;C90D;110C 116E 11B8;C90D;110C 116E 11B8; # (줍; 줍; 줍; 줍; 줍; ) HANGUL SYLLABLE JUB +C90E;C90E;110C 116E 11B9;C90E;110C 116E 11B9; # (줎; 줎; 줎; 줎; 줎; ) HANGUL SYLLABLE JUBS +C90F;C90F;110C 116E 11BA;C90F;110C 116E 11BA; # (줏; 줏; 줏; 줏; 줏; ) HANGUL SYLLABLE JUS +C910;C910;110C 116E 11BB;C910;110C 116E 11BB; # (줐; 줐; 줐; 줐; 줐; ) HANGUL SYLLABLE JUSS +C911;C911;110C 116E 11BC;C911;110C 116E 11BC; # (중; 중; 중; 중; 중; ) HANGUL SYLLABLE JUNG +C912;C912;110C 116E 11BD;C912;110C 116E 11BD; # (줒; 줒; 줒; 줒; 줒; ) HANGUL SYLLABLE JUJ +C913;C913;110C 116E 11BE;C913;110C 116E 11BE; # (줓; 줓; 줓; 줓; 줓; ) HANGUL SYLLABLE JUC +C914;C914;110C 116E 11BF;C914;110C 116E 11BF; # (줔; 줔; 줔; 줔; 줔; ) HANGUL SYLLABLE JUK +C915;C915;110C 116E 11C0;C915;110C 116E 11C0; # (줕; 줕; 줕; 줕; 줕; ) HANGUL SYLLABLE JUT +C916;C916;110C 116E 11C1;C916;110C 116E 11C1; # (줖; 줖; 줖; 줖; 줖; ) HANGUL SYLLABLE JUP +C917;C917;110C 116E 11C2;C917;110C 116E 11C2; # (줗; 줗; 줗; 줗; 줗; ) HANGUL SYLLABLE JUH +C918;C918;110C 116F;C918;110C 116F; # (줘; 줘; 줘; 줘; 줘; ) HANGUL SYLLABLE JWEO +C919;C919;110C 116F 11A8;C919;110C 116F 11A8; # (줙; 줙; 줙; 줙; 줙; ) HANGUL SYLLABLE JWEOG +C91A;C91A;110C 116F 11A9;C91A;110C 116F 11A9; # (줚; 줚; 줚; 줚; 줚; ) HANGUL SYLLABLE JWEOGG +C91B;C91B;110C 116F 11AA;C91B;110C 116F 11AA; # (줛; 줛; 줛; 줛; 줛; ) HANGUL SYLLABLE JWEOGS +C91C;C91C;110C 116F 11AB;C91C;110C 116F 11AB; # (줜; 줜; 줜; 줜; 줜; ) HANGUL SYLLABLE JWEON +C91D;C91D;110C 116F 11AC;C91D;110C 116F 11AC; # (줝; 줝; 줝; 줝; 줝; ) HANGUL SYLLABLE JWEONJ +C91E;C91E;110C 116F 11AD;C91E;110C 116F 11AD; # (줞; 줞; 줞; 줞; 줞; ) HANGUL SYLLABLE JWEONH +C91F;C91F;110C 116F 11AE;C91F;110C 116F 11AE; # (줟; 줟; 줟; 줟; 줟; ) HANGUL SYLLABLE JWEOD +C920;C920;110C 116F 11AF;C920;110C 116F 11AF; # (줠; 줠; 줠; 줠; 줠; ) HANGUL SYLLABLE JWEOL +C921;C921;110C 116F 11B0;C921;110C 116F 11B0; # (줡; 줡; 줡; 줡; 줡; ) HANGUL SYLLABLE JWEOLG +C922;C922;110C 116F 11B1;C922;110C 116F 11B1; # (줢; 줢; 줢; 줢; 줢; ) HANGUL SYLLABLE JWEOLM +C923;C923;110C 116F 11B2;C923;110C 116F 11B2; # (줣; 줣; 줣; 줣; 줣; ) HANGUL SYLLABLE JWEOLB +C924;C924;110C 116F 11B3;C924;110C 116F 11B3; # (줤; 줤; 줤; 줤; 줤; ) HANGUL SYLLABLE JWEOLS +C925;C925;110C 116F 11B4;C925;110C 116F 11B4; # (줥; 줥; 줥; 줥; 줥; ) HANGUL SYLLABLE JWEOLT +C926;C926;110C 116F 11B5;C926;110C 116F 11B5; # (줦; 줦; 줦; 줦; 줦; ) HANGUL SYLLABLE JWEOLP +C927;C927;110C 116F 11B6;C927;110C 116F 11B6; # (줧; 줧; 줧; 줧; 줧; ) HANGUL SYLLABLE JWEOLH +C928;C928;110C 116F 11B7;C928;110C 116F 11B7; # (줨; 줨; 줨; 줨; 줨; ) HANGUL SYLLABLE JWEOM +C929;C929;110C 116F 11B8;C929;110C 116F 11B8; # (줩; 줩; 줩; 줩; 줩; ) HANGUL SYLLABLE JWEOB +C92A;C92A;110C 116F 11B9;C92A;110C 116F 11B9; # (줪; 줪; 줪; 줪; 줪; ) HANGUL SYLLABLE JWEOBS +C92B;C92B;110C 116F 11BA;C92B;110C 116F 11BA; # (줫; 줫; 줫; 줫; 줫; ) HANGUL SYLLABLE JWEOS +C92C;C92C;110C 116F 11BB;C92C;110C 116F 11BB; # (줬; 줬; 줬; 줬; 줬; ) HANGUL SYLLABLE JWEOSS +C92D;C92D;110C 116F 11BC;C92D;110C 116F 11BC; # (줭; 줭; 줭; 줭; 줭; ) HANGUL SYLLABLE JWEONG +C92E;C92E;110C 116F 11BD;C92E;110C 116F 11BD; # (줮; 줮; 줮; 줮; 줮; ) HANGUL SYLLABLE JWEOJ +C92F;C92F;110C 116F 11BE;C92F;110C 116F 11BE; # (줯; 줯; 줯; 줯; 줯; ) HANGUL SYLLABLE JWEOC +C930;C930;110C 116F 11BF;C930;110C 116F 11BF; # (줰; 줰; 줰; 줰; 줰; ) HANGUL SYLLABLE JWEOK +C931;C931;110C 116F 11C0;C931;110C 116F 11C0; # (줱; 줱; 줱; 줱; 줱; ) HANGUL SYLLABLE JWEOT +C932;C932;110C 116F 11C1;C932;110C 116F 11C1; # (줲; 줲; 줲; 줲; 줲; ) HANGUL SYLLABLE JWEOP +C933;C933;110C 116F 11C2;C933;110C 116F 11C2; # (줳; 줳; 줳; 줳; 줳; ) HANGUL SYLLABLE JWEOH +C934;C934;110C 1170;C934;110C 1170; # (줴; 줴; 줴; 줴; 줴; ) HANGUL SYLLABLE JWE +C935;C935;110C 1170 11A8;C935;110C 1170 11A8; # (줵; 줵; 줵; 줵; 줵; ) HANGUL SYLLABLE JWEG +C936;C936;110C 1170 11A9;C936;110C 1170 11A9; # (줶; 줶; 줶; 줶; 줶; ) HANGUL SYLLABLE JWEGG +C937;C937;110C 1170 11AA;C937;110C 1170 11AA; # (줷; 줷; 줷; 줷; 줷; ) HANGUL SYLLABLE JWEGS +C938;C938;110C 1170 11AB;C938;110C 1170 11AB; # (줸; 줸; 줸; 줸; 줸; ) HANGUL SYLLABLE JWEN +C939;C939;110C 1170 11AC;C939;110C 1170 11AC; # (줹; 줹; 줹; 줹; 줹; ) HANGUL SYLLABLE JWENJ +C93A;C93A;110C 1170 11AD;C93A;110C 1170 11AD; # (줺; 줺; 줺; 줺; 줺; ) HANGUL SYLLABLE JWENH +C93B;C93B;110C 1170 11AE;C93B;110C 1170 11AE; # (줻; 줻; 줻; 줻; 줻; ) HANGUL SYLLABLE JWED +C93C;C93C;110C 1170 11AF;C93C;110C 1170 11AF; # (줼; 줼; 줼; 줼; 줼; ) HANGUL SYLLABLE JWEL +C93D;C93D;110C 1170 11B0;C93D;110C 1170 11B0; # (줽; 줽; 줽; 줽; 줽; ) HANGUL SYLLABLE JWELG +C93E;C93E;110C 1170 11B1;C93E;110C 1170 11B1; # (줾; 줾; 줾; 줾; 줾; ) HANGUL SYLLABLE JWELM +C93F;C93F;110C 1170 11B2;C93F;110C 1170 11B2; # (줿; 줿; 줿; 줿; 줿; ) HANGUL SYLLABLE JWELB +C940;C940;110C 1170 11B3;C940;110C 1170 11B3; # (쥀; 쥀; 쥀; 쥀; 쥀; ) HANGUL SYLLABLE JWELS +C941;C941;110C 1170 11B4;C941;110C 1170 11B4; # (쥁; 쥁; 쥁; 쥁; 쥁; ) HANGUL SYLLABLE JWELT +C942;C942;110C 1170 11B5;C942;110C 1170 11B5; # (쥂; 쥂; 쥂; 쥂; 쥂; ) HANGUL SYLLABLE JWELP +C943;C943;110C 1170 11B6;C943;110C 1170 11B6; # (쥃; 쥃; 쥃; 쥃; 쥃; ) HANGUL SYLLABLE JWELH +C944;C944;110C 1170 11B7;C944;110C 1170 11B7; # (쥄; 쥄; 쥄; 쥄; 쥄; ) HANGUL SYLLABLE JWEM +C945;C945;110C 1170 11B8;C945;110C 1170 11B8; # (쥅; 쥅; 쥅; 쥅; 쥅; ) HANGUL SYLLABLE JWEB +C946;C946;110C 1170 11B9;C946;110C 1170 11B9; # (쥆; 쥆; 쥆; 쥆; 쥆; ) HANGUL SYLLABLE JWEBS +C947;C947;110C 1170 11BA;C947;110C 1170 11BA; # (쥇; 쥇; 쥇; 쥇; 쥇; ) HANGUL SYLLABLE JWES +C948;C948;110C 1170 11BB;C948;110C 1170 11BB; # (쥈; 쥈; 쥈; 쥈; 쥈; ) HANGUL SYLLABLE JWESS +C949;C949;110C 1170 11BC;C949;110C 1170 11BC; # (쥉; 쥉; 쥉; 쥉; 쥉; ) HANGUL SYLLABLE JWENG +C94A;C94A;110C 1170 11BD;C94A;110C 1170 11BD; # (쥊; 쥊; 쥊; 쥊; 쥊; ) HANGUL SYLLABLE JWEJ +C94B;C94B;110C 1170 11BE;C94B;110C 1170 11BE; # (쥋; 쥋; 쥋; 쥋; 쥋; ) HANGUL SYLLABLE JWEC +C94C;C94C;110C 1170 11BF;C94C;110C 1170 11BF; # (쥌; 쥌; 쥌; 쥌; 쥌; ) HANGUL SYLLABLE JWEK +C94D;C94D;110C 1170 11C0;C94D;110C 1170 11C0; # (쥍; 쥍; 쥍; 쥍; 쥍; ) HANGUL SYLLABLE JWET +C94E;C94E;110C 1170 11C1;C94E;110C 1170 11C1; # (쥎; 쥎; 쥎; 쥎; 쥎; ) HANGUL SYLLABLE JWEP +C94F;C94F;110C 1170 11C2;C94F;110C 1170 11C2; # (쥏; 쥏; 쥏; 쥏; 쥏; ) HANGUL SYLLABLE JWEH +C950;C950;110C 1171;C950;110C 1171; # (쥐; 쥐; 쥐; 쥐; 쥐; ) HANGUL SYLLABLE JWI +C951;C951;110C 1171 11A8;C951;110C 1171 11A8; # (쥑; 쥑; 쥑; 쥑; 쥑; ) HANGUL SYLLABLE JWIG +C952;C952;110C 1171 11A9;C952;110C 1171 11A9; # (쥒; 쥒; 쥒; 쥒; 쥒; ) HANGUL SYLLABLE JWIGG +C953;C953;110C 1171 11AA;C953;110C 1171 11AA; # (쥓; 쥓; 쥓; 쥓; 쥓; ) HANGUL SYLLABLE JWIGS +C954;C954;110C 1171 11AB;C954;110C 1171 11AB; # (쥔; 쥔; 쥔; 쥔; 쥔; ) HANGUL SYLLABLE JWIN +C955;C955;110C 1171 11AC;C955;110C 1171 11AC; # (쥕; 쥕; 쥕; 쥕; 쥕; ) HANGUL SYLLABLE JWINJ +C956;C956;110C 1171 11AD;C956;110C 1171 11AD; # (쥖; 쥖; 쥖; 쥖; 쥖; ) HANGUL SYLLABLE JWINH +C957;C957;110C 1171 11AE;C957;110C 1171 11AE; # (쥗; 쥗; 쥗; 쥗; 쥗; ) HANGUL SYLLABLE JWID +C958;C958;110C 1171 11AF;C958;110C 1171 11AF; # (쥘; 쥘; 쥘; 쥘; 쥘; ) HANGUL SYLLABLE JWIL +C959;C959;110C 1171 11B0;C959;110C 1171 11B0; # (쥙; 쥙; 쥙; 쥙; 쥙; ) HANGUL SYLLABLE JWILG +C95A;C95A;110C 1171 11B1;C95A;110C 1171 11B1; # (쥚; 쥚; 쥚; 쥚; 쥚; ) HANGUL SYLLABLE JWILM +C95B;C95B;110C 1171 11B2;C95B;110C 1171 11B2; # (쥛; 쥛; 쥛; 쥛; 쥛; ) HANGUL SYLLABLE JWILB +C95C;C95C;110C 1171 11B3;C95C;110C 1171 11B3; # (쥜; 쥜; 쥜; 쥜; 쥜; ) HANGUL SYLLABLE JWILS +C95D;C95D;110C 1171 11B4;C95D;110C 1171 11B4; # (쥝; 쥝; 쥝; 쥝; 쥝; ) HANGUL SYLLABLE JWILT +C95E;C95E;110C 1171 11B5;C95E;110C 1171 11B5; # (쥞; 쥞; 쥞; 쥞; 쥞; ) HANGUL SYLLABLE JWILP +C95F;C95F;110C 1171 11B6;C95F;110C 1171 11B6; # (쥟; 쥟; 쥟; 쥟; 쥟; ) HANGUL SYLLABLE JWILH +C960;C960;110C 1171 11B7;C960;110C 1171 11B7; # (쥠; 쥠; 쥠; 쥠; 쥠; ) HANGUL SYLLABLE JWIM +C961;C961;110C 1171 11B8;C961;110C 1171 11B8; # (쥡; 쥡; 쥡; 쥡; 쥡; ) HANGUL SYLLABLE JWIB +C962;C962;110C 1171 11B9;C962;110C 1171 11B9; # (쥢; 쥢; 쥢; 쥢; 쥢; ) HANGUL SYLLABLE JWIBS +C963;C963;110C 1171 11BA;C963;110C 1171 11BA; # (쥣; 쥣; 쥣; 쥣; 쥣; ) HANGUL SYLLABLE JWIS +C964;C964;110C 1171 11BB;C964;110C 1171 11BB; # (쥤; 쥤; 쥤; 쥤; 쥤; ) HANGUL SYLLABLE JWISS +C965;C965;110C 1171 11BC;C965;110C 1171 11BC; # (쥥; 쥥; 쥥; 쥥; 쥥; ) HANGUL SYLLABLE JWING +C966;C966;110C 1171 11BD;C966;110C 1171 11BD; # (쥦; 쥦; 쥦; 쥦; 쥦; ) HANGUL SYLLABLE JWIJ +C967;C967;110C 1171 11BE;C967;110C 1171 11BE; # (쥧; 쥧; 쥧; 쥧; 쥧; ) HANGUL SYLLABLE JWIC +C968;C968;110C 1171 11BF;C968;110C 1171 11BF; # (쥨; 쥨; 쥨; 쥨; 쥨; ) HANGUL SYLLABLE JWIK +C969;C969;110C 1171 11C0;C969;110C 1171 11C0; # (쥩; 쥩; 쥩; 쥩; 쥩; ) HANGUL SYLLABLE JWIT +C96A;C96A;110C 1171 11C1;C96A;110C 1171 11C1; # (쥪; 쥪; 쥪; 쥪; 쥪; ) HANGUL SYLLABLE JWIP +C96B;C96B;110C 1171 11C2;C96B;110C 1171 11C2; # (쥫; 쥫; 쥫; 쥫; 쥫; ) HANGUL SYLLABLE JWIH +C96C;C96C;110C 1172;C96C;110C 1172; # (쥬; 쥬; 쥬; 쥬; 쥬; ) HANGUL SYLLABLE JYU +C96D;C96D;110C 1172 11A8;C96D;110C 1172 11A8; # (쥭; 쥭; 쥭; 쥭; 쥭; ) HANGUL SYLLABLE JYUG +C96E;C96E;110C 1172 11A9;C96E;110C 1172 11A9; # (쥮; 쥮; 쥮; 쥮; 쥮; ) HANGUL SYLLABLE JYUGG +C96F;C96F;110C 1172 11AA;C96F;110C 1172 11AA; # (쥯; 쥯; 쥯; 쥯; 쥯; ) HANGUL SYLLABLE JYUGS +C970;C970;110C 1172 11AB;C970;110C 1172 11AB; # (쥰; 쥰; 쥰; 쥰; 쥰; ) HANGUL SYLLABLE JYUN +C971;C971;110C 1172 11AC;C971;110C 1172 11AC; # (쥱; 쥱; 쥱; 쥱; 쥱; ) HANGUL SYLLABLE JYUNJ +C972;C972;110C 1172 11AD;C972;110C 1172 11AD; # (쥲; 쥲; 쥲; 쥲; 쥲; ) HANGUL SYLLABLE JYUNH +C973;C973;110C 1172 11AE;C973;110C 1172 11AE; # (쥳; 쥳; 쥳; 쥳; 쥳; ) HANGUL SYLLABLE JYUD +C974;C974;110C 1172 11AF;C974;110C 1172 11AF; # (쥴; 쥴; 쥴; 쥴; 쥴; ) HANGUL SYLLABLE JYUL +C975;C975;110C 1172 11B0;C975;110C 1172 11B0; # (쥵; 쥵; 쥵; 쥵; 쥵; ) HANGUL SYLLABLE JYULG +C976;C976;110C 1172 11B1;C976;110C 1172 11B1; # (쥶; 쥶; 쥶; 쥶; 쥶; ) HANGUL SYLLABLE JYULM +C977;C977;110C 1172 11B2;C977;110C 1172 11B2; # (쥷; 쥷; 쥷; 쥷; 쥷; ) HANGUL SYLLABLE JYULB +C978;C978;110C 1172 11B3;C978;110C 1172 11B3; # (쥸; 쥸; 쥸; 쥸; 쥸; ) HANGUL SYLLABLE JYULS +C979;C979;110C 1172 11B4;C979;110C 1172 11B4; # (쥹; 쥹; 쥹; 쥹; 쥹; ) HANGUL SYLLABLE JYULT +C97A;C97A;110C 1172 11B5;C97A;110C 1172 11B5; # (쥺; 쥺; 쥺; 쥺; 쥺; ) HANGUL SYLLABLE JYULP +C97B;C97B;110C 1172 11B6;C97B;110C 1172 11B6; # (쥻; 쥻; 쥻; 쥻; 쥻; ) HANGUL SYLLABLE JYULH +C97C;C97C;110C 1172 11B7;C97C;110C 1172 11B7; # (쥼; 쥼; 쥼; 쥼; 쥼; ) HANGUL SYLLABLE JYUM +C97D;C97D;110C 1172 11B8;C97D;110C 1172 11B8; # (쥽; 쥽; 쥽; 쥽; 쥽; ) HANGUL SYLLABLE JYUB +C97E;C97E;110C 1172 11B9;C97E;110C 1172 11B9; # (쥾; 쥾; 쥾; 쥾; 쥾; ) HANGUL SYLLABLE JYUBS +C97F;C97F;110C 1172 11BA;C97F;110C 1172 11BA; # (쥿; 쥿; 쥿; 쥿; 쥿; ) HANGUL SYLLABLE JYUS +C980;C980;110C 1172 11BB;C980;110C 1172 11BB; # (즀; 즀; 즀; 즀; 즀; ) HANGUL SYLLABLE JYUSS +C981;C981;110C 1172 11BC;C981;110C 1172 11BC; # (즁; 즁; 즁; 즁; 즁; ) HANGUL SYLLABLE JYUNG +C982;C982;110C 1172 11BD;C982;110C 1172 11BD; # (즂; 즂; 즂; 즂; 즂; ) HANGUL SYLLABLE JYUJ +C983;C983;110C 1172 11BE;C983;110C 1172 11BE; # (즃; 즃; 즃; 즃; 즃; ) HANGUL SYLLABLE JYUC +C984;C984;110C 1172 11BF;C984;110C 1172 11BF; # (즄; 즄; 즄; 즄; 즄; ) HANGUL SYLLABLE JYUK +C985;C985;110C 1172 11C0;C985;110C 1172 11C0; # (즅; 즅; 즅; 즅; 즅; ) HANGUL SYLLABLE JYUT +C986;C986;110C 1172 11C1;C986;110C 1172 11C1; # (즆; 즆; 즆; 즆; 즆; ) HANGUL SYLLABLE JYUP +C987;C987;110C 1172 11C2;C987;110C 1172 11C2; # (즇; 즇; 즇; 즇; 즇; ) HANGUL SYLLABLE JYUH +C988;C988;110C 1173;C988;110C 1173; # (즈; 즈; 즈; 즈; 즈; ) HANGUL SYLLABLE JEU +C989;C989;110C 1173 11A8;C989;110C 1173 11A8; # (즉; 즉; 즉; 즉; 즉; ) HANGUL SYLLABLE JEUG +C98A;C98A;110C 1173 11A9;C98A;110C 1173 11A9; # (즊; 즊; 즊; 즊; 즊; ) HANGUL SYLLABLE JEUGG +C98B;C98B;110C 1173 11AA;C98B;110C 1173 11AA; # (즋; 즋; 즋; 즋; 즋; ) HANGUL SYLLABLE JEUGS +C98C;C98C;110C 1173 11AB;C98C;110C 1173 11AB; # (즌; 즌; 즌; 즌; 즌; ) HANGUL SYLLABLE JEUN +C98D;C98D;110C 1173 11AC;C98D;110C 1173 11AC; # (즍; 즍; 즍; 즍; 즍; ) HANGUL SYLLABLE JEUNJ +C98E;C98E;110C 1173 11AD;C98E;110C 1173 11AD; # (즎; 즎; 즎; 즎; 즎; ) HANGUL SYLLABLE JEUNH +C98F;C98F;110C 1173 11AE;C98F;110C 1173 11AE; # (즏; 즏; 즏; 즏; 즏; ) HANGUL SYLLABLE JEUD +C990;C990;110C 1173 11AF;C990;110C 1173 11AF; # (즐; 즐; 즐; 즐; 즐; ) HANGUL SYLLABLE JEUL +C991;C991;110C 1173 11B0;C991;110C 1173 11B0; # (즑; 즑; 즑; 즑; 즑; ) HANGUL SYLLABLE JEULG +C992;C992;110C 1173 11B1;C992;110C 1173 11B1; # (즒; 즒; 즒; 즒; 즒; ) HANGUL SYLLABLE JEULM +C993;C993;110C 1173 11B2;C993;110C 1173 11B2; # (즓; 즓; 즓; 즓; 즓; ) HANGUL SYLLABLE JEULB +C994;C994;110C 1173 11B3;C994;110C 1173 11B3; # (즔; 즔; 즔; 즔; 즔; ) HANGUL SYLLABLE JEULS +C995;C995;110C 1173 11B4;C995;110C 1173 11B4; # (즕; 즕; 즕; 즕; 즕; ) HANGUL SYLLABLE JEULT +C996;C996;110C 1173 11B5;C996;110C 1173 11B5; # (즖; 즖; 즖; 즖; 즖; ) HANGUL SYLLABLE JEULP +C997;C997;110C 1173 11B6;C997;110C 1173 11B6; # (즗; 즗; 즗; 즗; 즗; ) HANGUL SYLLABLE JEULH +C998;C998;110C 1173 11B7;C998;110C 1173 11B7; # (즘; 즘; 즘; 즘; 즘; ) HANGUL SYLLABLE JEUM +C999;C999;110C 1173 11B8;C999;110C 1173 11B8; # (즙; 즙; 즙; 즙; 즙; ) HANGUL SYLLABLE JEUB +C99A;C99A;110C 1173 11B9;C99A;110C 1173 11B9; # (즚; 즚; 즚; 즚; 즚; ) HANGUL SYLLABLE JEUBS +C99B;C99B;110C 1173 11BA;C99B;110C 1173 11BA; # (즛; 즛; 즛; 즛; 즛; ) HANGUL SYLLABLE JEUS +C99C;C99C;110C 1173 11BB;C99C;110C 1173 11BB; # (즜; 즜; 즜; 즜; 즜; ) HANGUL SYLLABLE JEUSS +C99D;C99D;110C 1173 11BC;C99D;110C 1173 11BC; # (증; 증; 증; 증; 증; ) HANGUL SYLLABLE JEUNG +C99E;C99E;110C 1173 11BD;C99E;110C 1173 11BD; # (즞; 즞; 즞; 즞; 즞; ) HANGUL SYLLABLE JEUJ +C99F;C99F;110C 1173 11BE;C99F;110C 1173 11BE; # (즟; 즟; 즟; 즟; 즟; ) HANGUL SYLLABLE JEUC +C9A0;C9A0;110C 1173 11BF;C9A0;110C 1173 11BF; # (즠; 즠; 즠; 즠; 즠; ) HANGUL SYLLABLE JEUK +C9A1;C9A1;110C 1173 11C0;C9A1;110C 1173 11C0; # (즡; 즡; 즡; 즡; 즡; ) HANGUL SYLLABLE JEUT +C9A2;C9A2;110C 1173 11C1;C9A2;110C 1173 11C1; # (즢; 즢; 즢; 즢; 즢; ) HANGUL SYLLABLE JEUP +C9A3;C9A3;110C 1173 11C2;C9A3;110C 1173 11C2; # (즣; 즣; 즣; 즣; 즣; ) HANGUL SYLLABLE JEUH +C9A4;C9A4;110C 1174;C9A4;110C 1174; # (즤; 즤; 즤; 즤; 즤; ) HANGUL SYLLABLE JYI +C9A5;C9A5;110C 1174 11A8;C9A5;110C 1174 11A8; # (즥; 즥; 즥; 즥; 즥; ) HANGUL SYLLABLE JYIG +C9A6;C9A6;110C 1174 11A9;C9A6;110C 1174 11A9; # (즦; 즦; 즦; 즦; 즦; ) HANGUL SYLLABLE JYIGG +C9A7;C9A7;110C 1174 11AA;C9A7;110C 1174 11AA; # (즧; 즧; 즧; 즧; 즧; ) HANGUL SYLLABLE JYIGS +C9A8;C9A8;110C 1174 11AB;C9A8;110C 1174 11AB; # (즨; 즨; 즨; 즨; 즨; ) HANGUL SYLLABLE JYIN +C9A9;C9A9;110C 1174 11AC;C9A9;110C 1174 11AC; # (즩; 즩; 즩; 즩; 즩; ) HANGUL SYLLABLE JYINJ +C9AA;C9AA;110C 1174 11AD;C9AA;110C 1174 11AD; # (즪; 즪; 즪; 즪; 즪; ) HANGUL SYLLABLE JYINH +C9AB;C9AB;110C 1174 11AE;C9AB;110C 1174 11AE; # (즫; 즫; 즫; 즫; 즫; ) HANGUL SYLLABLE JYID +C9AC;C9AC;110C 1174 11AF;C9AC;110C 1174 11AF; # (즬; 즬; 즬; 즬; 즬; ) HANGUL SYLLABLE JYIL +C9AD;C9AD;110C 1174 11B0;C9AD;110C 1174 11B0; # (즭; 즭; 즭; 즭; 즭; ) HANGUL SYLLABLE JYILG +C9AE;C9AE;110C 1174 11B1;C9AE;110C 1174 11B1; # (즮; 즮; 즮; 즮; 즮; ) HANGUL SYLLABLE JYILM +C9AF;C9AF;110C 1174 11B2;C9AF;110C 1174 11B2; # (즯; 즯; 즯; 즯; 즯; ) HANGUL SYLLABLE JYILB +C9B0;C9B0;110C 1174 11B3;C9B0;110C 1174 11B3; # (즰; 즰; 즰; 즰; 즰; ) HANGUL SYLLABLE JYILS +C9B1;C9B1;110C 1174 11B4;C9B1;110C 1174 11B4; # (즱; 즱; 즱; 즱; 즱; ) HANGUL SYLLABLE JYILT +C9B2;C9B2;110C 1174 11B5;C9B2;110C 1174 11B5; # (즲; 즲; 즲; 즲; 즲; ) HANGUL SYLLABLE JYILP +C9B3;C9B3;110C 1174 11B6;C9B3;110C 1174 11B6; # (즳; 즳; 즳; 즳; 즳; ) HANGUL SYLLABLE JYILH +C9B4;C9B4;110C 1174 11B7;C9B4;110C 1174 11B7; # (즴; 즴; 즴; 즴; 즴; ) HANGUL SYLLABLE JYIM +C9B5;C9B5;110C 1174 11B8;C9B5;110C 1174 11B8; # (즵; 즵; 즵; 즵; 즵; ) HANGUL SYLLABLE JYIB +C9B6;C9B6;110C 1174 11B9;C9B6;110C 1174 11B9; # (즶; 즶; 즶; 즶; 즶; ) HANGUL SYLLABLE JYIBS +C9B7;C9B7;110C 1174 11BA;C9B7;110C 1174 11BA; # (즷; 즷; 즷; 즷; 즷; ) HANGUL SYLLABLE JYIS +C9B8;C9B8;110C 1174 11BB;C9B8;110C 1174 11BB; # (즸; 즸; 즸; 즸; 즸; ) HANGUL SYLLABLE JYISS +C9B9;C9B9;110C 1174 11BC;C9B9;110C 1174 11BC; # (즹; 즹; 즹; 즹; 즹; ) HANGUL SYLLABLE JYING +C9BA;C9BA;110C 1174 11BD;C9BA;110C 1174 11BD; # (즺; 즺; 즺; 즺; 즺; ) HANGUL SYLLABLE JYIJ +C9BB;C9BB;110C 1174 11BE;C9BB;110C 1174 11BE; # (즻; 즻; 즻; 즻; 즻; ) HANGUL SYLLABLE JYIC +C9BC;C9BC;110C 1174 11BF;C9BC;110C 1174 11BF; # (즼; 즼; 즼; 즼; 즼; ) HANGUL SYLLABLE JYIK +C9BD;C9BD;110C 1174 11C0;C9BD;110C 1174 11C0; # (즽; 즽; 즽; 즽; 즽; ) HANGUL SYLLABLE JYIT +C9BE;C9BE;110C 1174 11C1;C9BE;110C 1174 11C1; # (즾; 즾; 즾; 즾; 즾; ) HANGUL SYLLABLE JYIP +C9BF;C9BF;110C 1174 11C2;C9BF;110C 1174 11C2; # (즿; 즿; 즿; 즿; 즿; ) HANGUL SYLLABLE JYIH +C9C0;C9C0;110C 1175;C9C0;110C 1175; # (지; 지; 지; 지; 지; ) HANGUL SYLLABLE JI +C9C1;C9C1;110C 1175 11A8;C9C1;110C 1175 11A8; # (직; 직; 직; 직; 직; ) HANGUL SYLLABLE JIG +C9C2;C9C2;110C 1175 11A9;C9C2;110C 1175 11A9; # (짂; 짂; 짂; 짂; 짂; ) HANGUL SYLLABLE JIGG +C9C3;C9C3;110C 1175 11AA;C9C3;110C 1175 11AA; # (짃; 짃; 짃; 짃; 짃; ) HANGUL SYLLABLE JIGS +C9C4;C9C4;110C 1175 11AB;C9C4;110C 1175 11AB; # (진; 진; 진; 진; 진; ) HANGUL SYLLABLE JIN +C9C5;C9C5;110C 1175 11AC;C9C5;110C 1175 11AC; # (짅; 짅; 짅; 짅; 짅; ) HANGUL SYLLABLE JINJ +C9C6;C9C6;110C 1175 11AD;C9C6;110C 1175 11AD; # (짆; 짆; 짆; 짆; 짆; ) HANGUL SYLLABLE JINH +C9C7;C9C7;110C 1175 11AE;C9C7;110C 1175 11AE; # (짇; 짇; 짇; 짇; 짇; ) HANGUL SYLLABLE JID +C9C8;C9C8;110C 1175 11AF;C9C8;110C 1175 11AF; # (질; 질; 질; 질; 질; ) HANGUL SYLLABLE JIL +C9C9;C9C9;110C 1175 11B0;C9C9;110C 1175 11B0; # (짉; 짉; 짉; 짉; 짉; ) HANGUL SYLLABLE JILG +C9CA;C9CA;110C 1175 11B1;C9CA;110C 1175 11B1; # (짊; 짊; 짊; 짊; 짊; ) HANGUL SYLLABLE JILM +C9CB;C9CB;110C 1175 11B2;C9CB;110C 1175 11B2; # (짋; 짋; 짋; 짋; 짋; ) HANGUL SYLLABLE JILB +C9CC;C9CC;110C 1175 11B3;C9CC;110C 1175 11B3; # (짌; 짌; 짌; 짌; 짌; ) HANGUL SYLLABLE JILS +C9CD;C9CD;110C 1175 11B4;C9CD;110C 1175 11B4; # (짍; 짍; 짍; 짍; 짍; ) HANGUL SYLLABLE JILT +C9CE;C9CE;110C 1175 11B5;C9CE;110C 1175 11B5; # (짎; 짎; 짎; 짎; 짎; ) HANGUL SYLLABLE JILP +C9CF;C9CF;110C 1175 11B6;C9CF;110C 1175 11B6; # (짏; 짏; 짏; 짏; 짏; ) HANGUL SYLLABLE JILH +C9D0;C9D0;110C 1175 11B7;C9D0;110C 1175 11B7; # (짐; 짐; 짐; 짐; 짐; ) HANGUL SYLLABLE JIM +C9D1;C9D1;110C 1175 11B8;C9D1;110C 1175 11B8; # (집; 집; 집; 집; 집; ) HANGUL SYLLABLE JIB +C9D2;C9D2;110C 1175 11B9;C9D2;110C 1175 11B9; # (짒; 짒; 짒; 짒; 짒; ) HANGUL SYLLABLE JIBS +C9D3;C9D3;110C 1175 11BA;C9D3;110C 1175 11BA; # (짓; 짓; 짓; 짓; 짓; ) HANGUL SYLLABLE JIS +C9D4;C9D4;110C 1175 11BB;C9D4;110C 1175 11BB; # (짔; 짔; 짔; 짔; 짔; ) HANGUL SYLLABLE JISS +C9D5;C9D5;110C 1175 11BC;C9D5;110C 1175 11BC; # (징; 징; 징; 징; 징; ) HANGUL SYLLABLE JING +C9D6;C9D6;110C 1175 11BD;C9D6;110C 1175 11BD; # (짖; 짖; 짖; 짖; 짖; ) HANGUL SYLLABLE JIJ +C9D7;C9D7;110C 1175 11BE;C9D7;110C 1175 11BE; # (짗; 짗; 짗; 짗; 짗; ) HANGUL SYLLABLE JIC +C9D8;C9D8;110C 1175 11BF;C9D8;110C 1175 11BF; # (짘; 짘; 짘; 짘; 짘; ) HANGUL SYLLABLE JIK +C9D9;C9D9;110C 1175 11C0;C9D9;110C 1175 11C0; # (짙; 짙; 짙; 짙; 짙; ) HANGUL SYLLABLE JIT +C9DA;C9DA;110C 1175 11C1;C9DA;110C 1175 11C1; # (짚; 짚; 짚; 짚; 짚; ) HANGUL SYLLABLE JIP +C9DB;C9DB;110C 1175 11C2;C9DB;110C 1175 11C2; # (짛; 짛; 짛; 짛; 짛; ) HANGUL SYLLABLE JIH +C9DC;C9DC;110D 1161;C9DC;110D 1161; # (짜; 짜; 짜; 짜; 짜; ) HANGUL SYLLABLE JJA +C9DD;C9DD;110D 1161 11A8;C9DD;110D 1161 11A8; # (짝; 짝; 짝; 짝; 짝; ) HANGUL SYLLABLE JJAG +C9DE;C9DE;110D 1161 11A9;C9DE;110D 1161 11A9; # (짞; 짞; 짞; 짞; 짞; ) HANGUL SYLLABLE JJAGG +C9DF;C9DF;110D 1161 11AA;C9DF;110D 1161 11AA; # (짟; 짟; 짟; 짟; 짟; ) HANGUL SYLLABLE JJAGS +C9E0;C9E0;110D 1161 11AB;C9E0;110D 1161 11AB; # (짠; 짠; 짠; 짠; 짠; ) HANGUL SYLLABLE JJAN +C9E1;C9E1;110D 1161 11AC;C9E1;110D 1161 11AC; # (짡; 짡; 짡; 짡; 짡; ) HANGUL SYLLABLE JJANJ +C9E2;C9E2;110D 1161 11AD;C9E2;110D 1161 11AD; # (짢; 짢; 짢; 짢; 짢; ) HANGUL SYLLABLE JJANH +C9E3;C9E3;110D 1161 11AE;C9E3;110D 1161 11AE; # (짣; 짣; 짣; 짣; 짣; ) HANGUL SYLLABLE JJAD +C9E4;C9E4;110D 1161 11AF;C9E4;110D 1161 11AF; # (짤; 짤; 짤; 짤; 짤; ) HANGUL SYLLABLE JJAL +C9E5;C9E5;110D 1161 11B0;C9E5;110D 1161 11B0; # (짥; 짥; 짥; 짥; 짥; ) HANGUL SYLLABLE JJALG +C9E6;C9E6;110D 1161 11B1;C9E6;110D 1161 11B1; # (짦; 짦; 짦; 짦; 짦; ) HANGUL SYLLABLE JJALM +C9E7;C9E7;110D 1161 11B2;C9E7;110D 1161 11B2; # (짧; 짧; 짧; 짧; 짧; ) HANGUL SYLLABLE JJALB +C9E8;C9E8;110D 1161 11B3;C9E8;110D 1161 11B3; # (짨; 짨; 짨; 짨; 짨; ) HANGUL SYLLABLE JJALS +C9E9;C9E9;110D 1161 11B4;C9E9;110D 1161 11B4; # (짩; 짩; 짩; 짩; 짩; ) HANGUL SYLLABLE JJALT +C9EA;C9EA;110D 1161 11B5;C9EA;110D 1161 11B5; # (짪; 짪; 짪; 짪; 짪; ) HANGUL SYLLABLE JJALP +C9EB;C9EB;110D 1161 11B6;C9EB;110D 1161 11B6; # (짫; 짫; 짫; 짫; 짫; ) HANGUL SYLLABLE JJALH +C9EC;C9EC;110D 1161 11B7;C9EC;110D 1161 11B7; # (짬; 짬; 짬; 짬; 짬; ) HANGUL SYLLABLE JJAM +C9ED;C9ED;110D 1161 11B8;C9ED;110D 1161 11B8; # (짭; 짭; 짭; 짭; 짭; ) HANGUL SYLLABLE JJAB +C9EE;C9EE;110D 1161 11B9;C9EE;110D 1161 11B9; # (짮; 짮; 짮; 짮; 짮; ) HANGUL SYLLABLE JJABS +C9EF;C9EF;110D 1161 11BA;C9EF;110D 1161 11BA; # (짯; 짯; 짯; 짯; 짯; ) HANGUL SYLLABLE JJAS +C9F0;C9F0;110D 1161 11BB;C9F0;110D 1161 11BB; # (짰; 짰; 짰; 짰; 짰; ) HANGUL SYLLABLE JJASS +C9F1;C9F1;110D 1161 11BC;C9F1;110D 1161 11BC; # (짱; 짱; 짱; 짱; 짱; ) HANGUL SYLLABLE JJANG +C9F2;C9F2;110D 1161 11BD;C9F2;110D 1161 11BD; # (짲; 짲; 짲; 짲; 짲; ) HANGUL SYLLABLE JJAJ +C9F3;C9F3;110D 1161 11BE;C9F3;110D 1161 11BE; # (짳; 짳; 짳; 짳; 짳; ) HANGUL SYLLABLE JJAC +C9F4;C9F4;110D 1161 11BF;C9F4;110D 1161 11BF; # (짴; 짴; 짴; 짴; 짴; ) HANGUL SYLLABLE JJAK +C9F5;C9F5;110D 1161 11C0;C9F5;110D 1161 11C0; # (짵; 짵; 짵; 짵; 짵; ) HANGUL SYLLABLE JJAT +C9F6;C9F6;110D 1161 11C1;C9F6;110D 1161 11C1; # (짶; 짶; 짶; 짶; 짶; ) HANGUL SYLLABLE JJAP +C9F7;C9F7;110D 1161 11C2;C9F7;110D 1161 11C2; # (짷; 짷; 짷; 짷; 짷; ) HANGUL SYLLABLE JJAH +C9F8;C9F8;110D 1162;C9F8;110D 1162; # (째; 째; 째; 째; 째; ) HANGUL SYLLABLE JJAE +C9F9;C9F9;110D 1162 11A8;C9F9;110D 1162 11A8; # (짹; 짹; 짹; 짹; 짹; ) HANGUL SYLLABLE JJAEG +C9FA;C9FA;110D 1162 11A9;C9FA;110D 1162 11A9; # (짺; 짺; 짺; 짺; 짺; ) HANGUL SYLLABLE JJAEGG +C9FB;C9FB;110D 1162 11AA;C9FB;110D 1162 11AA; # (짻; 짻; 짻; 짻; 짻; ) HANGUL SYLLABLE JJAEGS +C9FC;C9FC;110D 1162 11AB;C9FC;110D 1162 11AB; # (짼; 짼; 짼; 짼; 짼; ) HANGUL SYLLABLE JJAEN +C9FD;C9FD;110D 1162 11AC;C9FD;110D 1162 11AC; # (짽; 짽; 짽; 짽; 짽; ) HANGUL SYLLABLE JJAENJ +C9FE;C9FE;110D 1162 11AD;C9FE;110D 1162 11AD; # (짾; 짾; 짾; 짾; 짾; ) HANGUL SYLLABLE JJAENH +C9FF;C9FF;110D 1162 11AE;C9FF;110D 1162 11AE; # (짿; 짿; 짿; 짿; 짿; ) HANGUL SYLLABLE JJAED +CA00;CA00;110D 1162 11AF;CA00;110D 1162 11AF; # (쨀; 쨀; 쨀; 쨀; 쨀; ) HANGUL SYLLABLE JJAEL +CA01;CA01;110D 1162 11B0;CA01;110D 1162 11B0; # (쨁; 쨁; 쨁; 쨁; 쨁; ) HANGUL SYLLABLE JJAELG +CA02;CA02;110D 1162 11B1;CA02;110D 1162 11B1; # (쨂; 쨂; 쨂; 쨂; 쨂; ) HANGUL SYLLABLE JJAELM +CA03;CA03;110D 1162 11B2;CA03;110D 1162 11B2; # (쨃; 쨃; 쨃; 쨃; 쨃; ) HANGUL SYLLABLE JJAELB +CA04;CA04;110D 1162 11B3;CA04;110D 1162 11B3; # (쨄; 쨄; 쨄; 쨄; 쨄; ) HANGUL SYLLABLE JJAELS +CA05;CA05;110D 1162 11B4;CA05;110D 1162 11B4; # (쨅; 쨅; 쨅; 쨅; 쨅; ) HANGUL SYLLABLE JJAELT +CA06;CA06;110D 1162 11B5;CA06;110D 1162 11B5; # (쨆; 쨆; 쨆; 쨆; 쨆; ) HANGUL SYLLABLE JJAELP +CA07;CA07;110D 1162 11B6;CA07;110D 1162 11B6; # (쨇; 쨇; 쨇; 쨇; 쨇; ) HANGUL SYLLABLE JJAELH +CA08;CA08;110D 1162 11B7;CA08;110D 1162 11B7; # (쨈; 쨈; 쨈; 쨈; 쨈; ) HANGUL SYLLABLE JJAEM +CA09;CA09;110D 1162 11B8;CA09;110D 1162 11B8; # (쨉; 쨉; 쨉; 쨉; 쨉; ) HANGUL SYLLABLE JJAEB +CA0A;CA0A;110D 1162 11B9;CA0A;110D 1162 11B9; # (쨊; 쨊; 쨊; 쨊; 쨊; ) HANGUL SYLLABLE JJAEBS +CA0B;CA0B;110D 1162 11BA;CA0B;110D 1162 11BA; # (쨋; 쨋; 쨋; 쨋; 쨋; ) HANGUL SYLLABLE JJAES +CA0C;CA0C;110D 1162 11BB;CA0C;110D 1162 11BB; # (쨌; 쨌; 쨌; 쨌; 쨌; ) HANGUL SYLLABLE JJAESS +CA0D;CA0D;110D 1162 11BC;CA0D;110D 1162 11BC; # (쨍; 쨍; 쨍; 쨍; 쨍; ) HANGUL SYLLABLE JJAENG +CA0E;CA0E;110D 1162 11BD;CA0E;110D 1162 11BD; # (쨎; 쨎; 쨎; 쨎; 쨎; ) HANGUL SYLLABLE JJAEJ +CA0F;CA0F;110D 1162 11BE;CA0F;110D 1162 11BE; # (쨏; 쨏; 쨏; 쨏; 쨏; ) HANGUL SYLLABLE JJAEC +CA10;CA10;110D 1162 11BF;CA10;110D 1162 11BF; # (쨐; 쨐; 쨐; 쨐; 쨐; ) HANGUL SYLLABLE JJAEK +CA11;CA11;110D 1162 11C0;CA11;110D 1162 11C0; # (쨑; 쨑; 쨑; 쨑; 쨑; ) HANGUL SYLLABLE JJAET +CA12;CA12;110D 1162 11C1;CA12;110D 1162 11C1; # (쨒; 쨒; 쨒; 쨒; 쨒; ) HANGUL SYLLABLE JJAEP +CA13;CA13;110D 1162 11C2;CA13;110D 1162 11C2; # (쨓; 쨓; 쨓; 쨓; 쨓; ) HANGUL SYLLABLE JJAEH +CA14;CA14;110D 1163;CA14;110D 1163; # (쨔; 쨔; 쨔; 쨔; 쨔; ) HANGUL SYLLABLE JJYA +CA15;CA15;110D 1163 11A8;CA15;110D 1163 11A8; # (쨕; 쨕; 쨕; 쨕; 쨕; ) HANGUL SYLLABLE JJYAG +CA16;CA16;110D 1163 11A9;CA16;110D 1163 11A9; # (쨖; 쨖; 쨖; 쨖; 쨖; ) HANGUL SYLLABLE JJYAGG +CA17;CA17;110D 1163 11AA;CA17;110D 1163 11AA; # (쨗; 쨗; 쨗; 쨗; 쨗; ) HANGUL SYLLABLE JJYAGS +CA18;CA18;110D 1163 11AB;CA18;110D 1163 11AB; # (쨘; 쨘; 쨘; 쨘; 쨘; ) HANGUL SYLLABLE JJYAN +CA19;CA19;110D 1163 11AC;CA19;110D 1163 11AC; # (쨙; 쨙; 쨙; 쨙; 쨙; ) HANGUL SYLLABLE JJYANJ +CA1A;CA1A;110D 1163 11AD;CA1A;110D 1163 11AD; # (쨚; 쨚; 쨚; 쨚; 쨚; ) HANGUL SYLLABLE JJYANH +CA1B;CA1B;110D 1163 11AE;CA1B;110D 1163 11AE; # (쨛; 쨛; 쨛; 쨛; 쨛; ) HANGUL SYLLABLE JJYAD +CA1C;CA1C;110D 1163 11AF;CA1C;110D 1163 11AF; # (쨜; 쨜; 쨜; 쨜; 쨜; ) HANGUL SYLLABLE JJYAL +CA1D;CA1D;110D 1163 11B0;CA1D;110D 1163 11B0; # (쨝; 쨝; 쨝; 쨝; 쨝; ) HANGUL SYLLABLE JJYALG +CA1E;CA1E;110D 1163 11B1;CA1E;110D 1163 11B1; # (쨞; 쨞; 쨞; 쨞; 쨞; ) HANGUL SYLLABLE JJYALM +CA1F;CA1F;110D 1163 11B2;CA1F;110D 1163 11B2; # (쨟; 쨟; 쨟; 쨟; 쨟; ) HANGUL SYLLABLE JJYALB +CA20;CA20;110D 1163 11B3;CA20;110D 1163 11B3; # (쨠; 쨠; 쨠; 쨠; 쨠; ) HANGUL SYLLABLE JJYALS +CA21;CA21;110D 1163 11B4;CA21;110D 1163 11B4; # (쨡; 쨡; 쨡; 쨡; 쨡; ) HANGUL SYLLABLE JJYALT +CA22;CA22;110D 1163 11B5;CA22;110D 1163 11B5; # (쨢; 쨢; 쨢; 쨢; 쨢; ) HANGUL SYLLABLE JJYALP +CA23;CA23;110D 1163 11B6;CA23;110D 1163 11B6; # (쨣; 쨣; 쨣; 쨣; 쨣; ) HANGUL SYLLABLE JJYALH +CA24;CA24;110D 1163 11B7;CA24;110D 1163 11B7; # (쨤; 쨤; 쨤; 쨤; 쨤; ) HANGUL SYLLABLE JJYAM +CA25;CA25;110D 1163 11B8;CA25;110D 1163 11B8; # (쨥; 쨥; 쨥; 쨥; 쨥; ) HANGUL SYLLABLE JJYAB +CA26;CA26;110D 1163 11B9;CA26;110D 1163 11B9; # (쨦; 쨦; 쨦; 쨦; 쨦; ) HANGUL SYLLABLE JJYABS +CA27;CA27;110D 1163 11BA;CA27;110D 1163 11BA; # (쨧; 쨧; 쨧; 쨧; 쨧; ) HANGUL SYLLABLE JJYAS +CA28;CA28;110D 1163 11BB;CA28;110D 1163 11BB; # (쨨; 쨨; 쨨; 쨨; 쨨; ) HANGUL SYLLABLE JJYASS +CA29;CA29;110D 1163 11BC;CA29;110D 1163 11BC; # (쨩; 쨩; 쨩; 쨩; 쨩; ) HANGUL SYLLABLE JJYANG +CA2A;CA2A;110D 1163 11BD;CA2A;110D 1163 11BD; # (쨪; 쨪; 쨪; 쨪; 쨪; ) HANGUL SYLLABLE JJYAJ +CA2B;CA2B;110D 1163 11BE;CA2B;110D 1163 11BE; # (쨫; 쨫; 쨫; 쨫; 쨫; ) HANGUL SYLLABLE JJYAC +CA2C;CA2C;110D 1163 11BF;CA2C;110D 1163 11BF; # (쨬; 쨬; 쨬; 쨬; 쨬; ) HANGUL SYLLABLE JJYAK +CA2D;CA2D;110D 1163 11C0;CA2D;110D 1163 11C0; # (쨭; 쨭; 쨭; 쨭; 쨭; ) HANGUL SYLLABLE JJYAT +CA2E;CA2E;110D 1163 11C1;CA2E;110D 1163 11C1; # (쨮; 쨮; 쨮; 쨮; 쨮; ) HANGUL SYLLABLE JJYAP +CA2F;CA2F;110D 1163 11C2;CA2F;110D 1163 11C2; # (쨯; 쨯; 쨯; 쨯; 쨯; ) HANGUL SYLLABLE JJYAH +CA30;CA30;110D 1164;CA30;110D 1164; # (쨰; 쨰; 쨰; 쨰; 쨰; ) HANGUL SYLLABLE JJYAE +CA31;CA31;110D 1164 11A8;CA31;110D 1164 11A8; # (쨱; 쨱; 쨱; 쨱; 쨱; ) HANGUL SYLLABLE JJYAEG +CA32;CA32;110D 1164 11A9;CA32;110D 1164 11A9; # (쨲; 쨲; 쨲; 쨲; 쨲; ) HANGUL SYLLABLE JJYAEGG +CA33;CA33;110D 1164 11AA;CA33;110D 1164 11AA; # (쨳; 쨳; 쨳; 쨳; 쨳; ) HANGUL SYLLABLE JJYAEGS +CA34;CA34;110D 1164 11AB;CA34;110D 1164 11AB; # (쨴; 쨴; 쨴; 쨴; 쨴; ) HANGUL SYLLABLE JJYAEN +CA35;CA35;110D 1164 11AC;CA35;110D 1164 11AC; # (쨵; 쨵; 쨵; 쨵; 쨵; ) HANGUL SYLLABLE JJYAENJ +CA36;CA36;110D 1164 11AD;CA36;110D 1164 11AD; # (쨶; 쨶; 쨶; 쨶; 쨶; ) HANGUL SYLLABLE JJYAENH +CA37;CA37;110D 1164 11AE;CA37;110D 1164 11AE; # (쨷; 쨷; 쨷; 쨷; 쨷; ) HANGUL SYLLABLE JJYAED +CA38;CA38;110D 1164 11AF;CA38;110D 1164 11AF; # (쨸; 쨸; 쨸; 쨸; 쨸; ) HANGUL SYLLABLE JJYAEL +CA39;CA39;110D 1164 11B0;CA39;110D 1164 11B0; # (쨹; 쨹; 쨹; 쨹; 쨹; ) HANGUL SYLLABLE JJYAELG +CA3A;CA3A;110D 1164 11B1;CA3A;110D 1164 11B1; # (쨺; 쨺; 쨺; 쨺; 쨺; ) HANGUL SYLLABLE JJYAELM +CA3B;CA3B;110D 1164 11B2;CA3B;110D 1164 11B2; # (쨻; 쨻; 쨻; 쨻; 쨻; ) HANGUL SYLLABLE JJYAELB +CA3C;CA3C;110D 1164 11B3;CA3C;110D 1164 11B3; # (쨼; 쨼; 쨼; 쨼; 쨼; ) HANGUL SYLLABLE JJYAELS +CA3D;CA3D;110D 1164 11B4;CA3D;110D 1164 11B4; # (쨽; 쨽; 쨽; 쨽; 쨽; ) HANGUL SYLLABLE JJYAELT +CA3E;CA3E;110D 1164 11B5;CA3E;110D 1164 11B5; # (쨾; 쨾; 쨾; 쨾; 쨾; ) HANGUL SYLLABLE JJYAELP +CA3F;CA3F;110D 1164 11B6;CA3F;110D 1164 11B6; # (쨿; 쨿; 쨿; 쨿; 쨿; ) HANGUL SYLLABLE JJYAELH +CA40;CA40;110D 1164 11B7;CA40;110D 1164 11B7; # (쩀; 쩀; 쩀; 쩀; 쩀; ) HANGUL SYLLABLE JJYAEM +CA41;CA41;110D 1164 11B8;CA41;110D 1164 11B8; # (쩁; 쩁; 쩁; 쩁; 쩁; ) HANGUL SYLLABLE JJYAEB +CA42;CA42;110D 1164 11B9;CA42;110D 1164 11B9; # (쩂; 쩂; 쩂; 쩂; 쩂; ) HANGUL SYLLABLE JJYAEBS +CA43;CA43;110D 1164 11BA;CA43;110D 1164 11BA; # (쩃; 쩃; 쩃; 쩃; 쩃; ) HANGUL SYLLABLE JJYAES +CA44;CA44;110D 1164 11BB;CA44;110D 1164 11BB; # (쩄; 쩄; 쩄; 쩄; 쩄; ) HANGUL SYLLABLE JJYAESS +CA45;CA45;110D 1164 11BC;CA45;110D 1164 11BC; # (쩅; 쩅; 쩅; 쩅; 쩅; ) HANGUL SYLLABLE JJYAENG +CA46;CA46;110D 1164 11BD;CA46;110D 1164 11BD; # (쩆; 쩆; 쩆; 쩆; 쩆; ) HANGUL SYLLABLE JJYAEJ +CA47;CA47;110D 1164 11BE;CA47;110D 1164 11BE; # (쩇; 쩇; 쩇; 쩇; 쩇; ) HANGUL SYLLABLE JJYAEC +CA48;CA48;110D 1164 11BF;CA48;110D 1164 11BF; # (쩈; 쩈; 쩈; 쩈; 쩈; ) HANGUL SYLLABLE JJYAEK +CA49;CA49;110D 1164 11C0;CA49;110D 1164 11C0; # (쩉; 쩉; 쩉; 쩉; 쩉; ) HANGUL SYLLABLE JJYAET +CA4A;CA4A;110D 1164 11C1;CA4A;110D 1164 11C1; # (쩊; 쩊; 쩊; 쩊; 쩊; ) HANGUL SYLLABLE JJYAEP +CA4B;CA4B;110D 1164 11C2;CA4B;110D 1164 11C2; # (쩋; 쩋; 쩋; 쩋; 쩋; ) HANGUL SYLLABLE JJYAEH +CA4C;CA4C;110D 1165;CA4C;110D 1165; # (쩌; 쩌; 쩌; 쩌; 쩌; ) HANGUL SYLLABLE JJEO +CA4D;CA4D;110D 1165 11A8;CA4D;110D 1165 11A8; # (쩍; 쩍; 쩍; 쩍; 쩍; ) HANGUL SYLLABLE JJEOG +CA4E;CA4E;110D 1165 11A9;CA4E;110D 1165 11A9; # (쩎; 쩎; 쩎; 쩎; 쩎; ) HANGUL SYLLABLE JJEOGG +CA4F;CA4F;110D 1165 11AA;CA4F;110D 1165 11AA; # (쩏; 쩏; 쩏; 쩏; 쩏; ) HANGUL SYLLABLE JJEOGS +CA50;CA50;110D 1165 11AB;CA50;110D 1165 11AB; # (쩐; 쩐; 쩐; 쩐; 쩐; ) HANGUL SYLLABLE JJEON +CA51;CA51;110D 1165 11AC;CA51;110D 1165 11AC; # (쩑; 쩑; 쩑; 쩑; 쩑; ) HANGUL SYLLABLE JJEONJ +CA52;CA52;110D 1165 11AD;CA52;110D 1165 11AD; # (쩒; 쩒; 쩒; 쩒; 쩒; ) HANGUL SYLLABLE JJEONH +CA53;CA53;110D 1165 11AE;CA53;110D 1165 11AE; # (쩓; 쩓; 쩓; 쩓; 쩓; ) HANGUL SYLLABLE JJEOD +CA54;CA54;110D 1165 11AF;CA54;110D 1165 11AF; # (쩔; 쩔; 쩔; 쩔; 쩔; ) HANGUL SYLLABLE JJEOL +CA55;CA55;110D 1165 11B0;CA55;110D 1165 11B0; # (쩕; 쩕; 쩕; 쩕; 쩕; ) HANGUL SYLLABLE JJEOLG +CA56;CA56;110D 1165 11B1;CA56;110D 1165 11B1; # (쩖; 쩖; 쩖; 쩖; 쩖; ) HANGUL SYLLABLE JJEOLM +CA57;CA57;110D 1165 11B2;CA57;110D 1165 11B2; # (쩗; 쩗; 쩗; 쩗; 쩗; ) HANGUL SYLLABLE JJEOLB +CA58;CA58;110D 1165 11B3;CA58;110D 1165 11B3; # (쩘; 쩘; 쩘; 쩘; 쩘; ) HANGUL SYLLABLE JJEOLS +CA59;CA59;110D 1165 11B4;CA59;110D 1165 11B4; # (쩙; 쩙; 쩙; 쩙; 쩙; ) HANGUL SYLLABLE JJEOLT +CA5A;CA5A;110D 1165 11B5;CA5A;110D 1165 11B5; # (쩚; 쩚; 쩚; 쩚; 쩚; ) HANGUL SYLLABLE JJEOLP +CA5B;CA5B;110D 1165 11B6;CA5B;110D 1165 11B6; # (쩛; 쩛; 쩛; 쩛; 쩛; ) HANGUL SYLLABLE JJEOLH +CA5C;CA5C;110D 1165 11B7;CA5C;110D 1165 11B7; # (쩜; 쩜; 쩜; 쩜; 쩜; ) HANGUL SYLLABLE JJEOM +CA5D;CA5D;110D 1165 11B8;CA5D;110D 1165 11B8; # (쩝; 쩝; 쩝; 쩝; 쩝; ) HANGUL SYLLABLE JJEOB +CA5E;CA5E;110D 1165 11B9;CA5E;110D 1165 11B9; # (쩞; 쩞; 쩞; 쩞; 쩞; ) HANGUL SYLLABLE JJEOBS +CA5F;CA5F;110D 1165 11BA;CA5F;110D 1165 11BA; # (쩟; 쩟; 쩟; 쩟; 쩟; ) HANGUL SYLLABLE JJEOS +CA60;CA60;110D 1165 11BB;CA60;110D 1165 11BB; # (쩠; 쩠; 쩠; 쩠; 쩠; ) HANGUL SYLLABLE JJEOSS +CA61;CA61;110D 1165 11BC;CA61;110D 1165 11BC; # (쩡; 쩡; 쩡; 쩡; 쩡; ) HANGUL SYLLABLE JJEONG +CA62;CA62;110D 1165 11BD;CA62;110D 1165 11BD; # (쩢; 쩢; 쩢; 쩢; 쩢; ) HANGUL SYLLABLE JJEOJ +CA63;CA63;110D 1165 11BE;CA63;110D 1165 11BE; # (쩣; 쩣; 쩣; 쩣; 쩣; ) HANGUL SYLLABLE JJEOC +CA64;CA64;110D 1165 11BF;CA64;110D 1165 11BF; # (쩤; 쩤; 쩤; 쩤; 쩤; ) HANGUL SYLLABLE JJEOK +CA65;CA65;110D 1165 11C0;CA65;110D 1165 11C0; # (쩥; 쩥; 쩥; 쩥; 쩥; ) HANGUL SYLLABLE JJEOT +CA66;CA66;110D 1165 11C1;CA66;110D 1165 11C1; # (쩦; 쩦; 쩦; 쩦; 쩦; ) HANGUL SYLLABLE JJEOP +CA67;CA67;110D 1165 11C2;CA67;110D 1165 11C2; # (쩧; 쩧; 쩧; 쩧; 쩧; ) HANGUL SYLLABLE JJEOH +CA68;CA68;110D 1166;CA68;110D 1166; # (쩨; 쩨; 쩨; 쩨; 쩨; ) HANGUL SYLLABLE JJE +CA69;CA69;110D 1166 11A8;CA69;110D 1166 11A8; # (쩩; 쩩; 쩩; 쩩; 쩩; ) HANGUL SYLLABLE JJEG +CA6A;CA6A;110D 1166 11A9;CA6A;110D 1166 11A9; # (쩪; 쩪; 쩪; 쩪; 쩪; ) HANGUL SYLLABLE JJEGG +CA6B;CA6B;110D 1166 11AA;CA6B;110D 1166 11AA; # (쩫; 쩫; 쩫; 쩫; 쩫; ) HANGUL SYLLABLE JJEGS +CA6C;CA6C;110D 1166 11AB;CA6C;110D 1166 11AB; # (쩬; 쩬; 쩬; 쩬; 쩬; ) HANGUL SYLLABLE JJEN +CA6D;CA6D;110D 1166 11AC;CA6D;110D 1166 11AC; # (쩭; 쩭; 쩭; 쩭; 쩭; ) HANGUL SYLLABLE JJENJ +CA6E;CA6E;110D 1166 11AD;CA6E;110D 1166 11AD; # (쩮; 쩮; 쩮; 쩮; 쩮; ) HANGUL SYLLABLE JJENH +CA6F;CA6F;110D 1166 11AE;CA6F;110D 1166 11AE; # (쩯; 쩯; 쩯; 쩯; 쩯; ) HANGUL SYLLABLE JJED +CA70;CA70;110D 1166 11AF;CA70;110D 1166 11AF; # (쩰; 쩰; 쩰; 쩰; 쩰; ) HANGUL SYLLABLE JJEL +CA71;CA71;110D 1166 11B0;CA71;110D 1166 11B0; # (쩱; 쩱; 쩱; 쩱; 쩱; ) HANGUL SYLLABLE JJELG +CA72;CA72;110D 1166 11B1;CA72;110D 1166 11B1; # (쩲; 쩲; 쩲; 쩲; 쩲; ) HANGUL SYLLABLE JJELM +CA73;CA73;110D 1166 11B2;CA73;110D 1166 11B2; # (쩳; 쩳; 쩳; 쩳; 쩳; ) HANGUL SYLLABLE JJELB +CA74;CA74;110D 1166 11B3;CA74;110D 1166 11B3; # (쩴; 쩴; 쩴; 쩴; 쩴; ) HANGUL SYLLABLE JJELS +CA75;CA75;110D 1166 11B4;CA75;110D 1166 11B4; # (쩵; 쩵; 쩵; 쩵; 쩵; ) HANGUL SYLLABLE JJELT +CA76;CA76;110D 1166 11B5;CA76;110D 1166 11B5; # (쩶; 쩶; 쩶; 쩶; 쩶; ) HANGUL SYLLABLE JJELP +CA77;CA77;110D 1166 11B6;CA77;110D 1166 11B6; # (쩷; 쩷; 쩷; 쩷; 쩷; ) HANGUL SYLLABLE JJELH +CA78;CA78;110D 1166 11B7;CA78;110D 1166 11B7; # (쩸; 쩸; 쩸; 쩸; 쩸; ) HANGUL SYLLABLE JJEM +CA79;CA79;110D 1166 11B8;CA79;110D 1166 11B8; # (쩹; 쩹; 쩹; 쩹; 쩹; ) HANGUL SYLLABLE JJEB +CA7A;CA7A;110D 1166 11B9;CA7A;110D 1166 11B9; # (쩺; 쩺; 쩺; 쩺; 쩺; ) HANGUL SYLLABLE JJEBS +CA7B;CA7B;110D 1166 11BA;CA7B;110D 1166 11BA; # (쩻; 쩻; 쩻; 쩻; 쩻; ) HANGUL SYLLABLE JJES +CA7C;CA7C;110D 1166 11BB;CA7C;110D 1166 11BB; # (쩼; 쩼; 쩼; 쩼; 쩼; ) HANGUL SYLLABLE JJESS +CA7D;CA7D;110D 1166 11BC;CA7D;110D 1166 11BC; # (쩽; 쩽; 쩽; 쩽; 쩽; ) HANGUL SYLLABLE JJENG +CA7E;CA7E;110D 1166 11BD;CA7E;110D 1166 11BD; # (쩾; 쩾; 쩾; 쩾; 쩾; ) HANGUL SYLLABLE JJEJ +CA7F;CA7F;110D 1166 11BE;CA7F;110D 1166 11BE; # (쩿; 쩿; 쩿; 쩿; 쩿; ) HANGUL SYLLABLE JJEC +CA80;CA80;110D 1166 11BF;CA80;110D 1166 11BF; # (쪀; 쪀; 쪀; 쪀; 쪀; ) HANGUL SYLLABLE JJEK +CA81;CA81;110D 1166 11C0;CA81;110D 1166 11C0; # (쪁; 쪁; 쪁; 쪁; 쪁; ) HANGUL SYLLABLE JJET +CA82;CA82;110D 1166 11C1;CA82;110D 1166 11C1; # (쪂; 쪂; 쪂; 쪂; 쪂; ) HANGUL SYLLABLE JJEP +CA83;CA83;110D 1166 11C2;CA83;110D 1166 11C2; # (쪃; 쪃; 쪃; 쪃; 쪃; ) HANGUL SYLLABLE JJEH +CA84;CA84;110D 1167;CA84;110D 1167; # (쪄; 쪄; 쪄; 쪄; 쪄; ) HANGUL SYLLABLE JJYEO +CA85;CA85;110D 1167 11A8;CA85;110D 1167 11A8; # (쪅; 쪅; 쪅; 쪅; 쪅; ) HANGUL SYLLABLE JJYEOG +CA86;CA86;110D 1167 11A9;CA86;110D 1167 11A9; # (쪆; 쪆; 쪆; 쪆; 쪆; ) HANGUL SYLLABLE JJYEOGG +CA87;CA87;110D 1167 11AA;CA87;110D 1167 11AA; # (쪇; 쪇; 쪇; 쪇; 쪇; ) HANGUL SYLLABLE JJYEOGS +CA88;CA88;110D 1167 11AB;CA88;110D 1167 11AB; # (쪈; 쪈; 쪈; 쪈; 쪈; ) HANGUL SYLLABLE JJYEON +CA89;CA89;110D 1167 11AC;CA89;110D 1167 11AC; # (쪉; 쪉; 쪉; 쪉; 쪉; ) HANGUL SYLLABLE JJYEONJ +CA8A;CA8A;110D 1167 11AD;CA8A;110D 1167 11AD; # (쪊; 쪊; 쪊; 쪊; 쪊; ) HANGUL SYLLABLE JJYEONH +CA8B;CA8B;110D 1167 11AE;CA8B;110D 1167 11AE; # (쪋; 쪋; 쪋; 쪋; 쪋; ) HANGUL SYLLABLE JJYEOD +CA8C;CA8C;110D 1167 11AF;CA8C;110D 1167 11AF; # (쪌; 쪌; 쪌; 쪌; 쪌; ) HANGUL SYLLABLE JJYEOL +CA8D;CA8D;110D 1167 11B0;CA8D;110D 1167 11B0; # (쪍; 쪍; 쪍; 쪍; 쪍; ) HANGUL SYLLABLE JJYEOLG +CA8E;CA8E;110D 1167 11B1;CA8E;110D 1167 11B1; # (쪎; 쪎; 쪎; 쪎; 쪎; ) HANGUL SYLLABLE JJYEOLM +CA8F;CA8F;110D 1167 11B2;CA8F;110D 1167 11B2; # (쪏; 쪏; 쪏; 쪏; 쪏; ) HANGUL SYLLABLE JJYEOLB +CA90;CA90;110D 1167 11B3;CA90;110D 1167 11B3; # (쪐; 쪐; 쪐; 쪐; 쪐; ) HANGUL SYLLABLE JJYEOLS +CA91;CA91;110D 1167 11B4;CA91;110D 1167 11B4; # (쪑; 쪑; 쪑; 쪑; 쪑; ) HANGUL SYLLABLE JJYEOLT +CA92;CA92;110D 1167 11B5;CA92;110D 1167 11B5; # (쪒; 쪒; 쪒; 쪒; 쪒; ) HANGUL SYLLABLE JJYEOLP +CA93;CA93;110D 1167 11B6;CA93;110D 1167 11B6; # (쪓; 쪓; 쪓; 쪓; 쪓; ) HANGUL SYLLABLE JJYEOLH +CA94;CA94;110D 1167 11B7;CA94;110D 1167 11B7; # (쪔; 쪔; 쪔; 쪔; 쪔; ) HANGUL SYLLABLE JJYEOM +CA95;CA95;110D 1167 11B8;CA95;110D 1167 11B8; # (쪕; 쪕; 쪕; 쪕; 쪕; ) HANGUL SYLLABLE JJYEOB +CA96;CA96;110D 1167 11B9;CA96;110D 1167 11B9; # (쪖; 쪖; 쪖; 쪖; 쪖; ) HANGUL SYLLABLE JJYEOBS +CA97;CA97;110D 1167 11BA;CA97;110D 1167 11BA; # (쪗; 쪗; 쪗; 쪗; 쪗; ) HANGUL SYLLABLE JJYEOS +CA98;CA98;110D 1167 11BB;CA98;110D 1167 11BB; # (쪘; 쪘; 쪘; 쪘; 쪘; ) HANGUL SYLLABLE JJYEOSS +CA99;CA99;110D 1167 11BC;CA99;110D 1167 11BC; # (쪙; 쪙; 쪙; 쪙; 쪙; ) HANGUL SYLLABLE JJYEONG +CA9A;CA9A;110D 1167 11BD;CA9A;110D 1167 11BD; # (쪚; 쪚; 쪚; 쪚; 쪚; ) HANGUL SYLLABLE JJYEOJ +CA9B;CA9B;110D 1167 11BE;CA9B;110D 1167 11BE; # (쪛; 쪛; 쪛; 쪛; 쪛; ) HANGUL SYLLABLE JJYEOC +CA9C;CA9C;110D 1167 11BF;CA9C;110D 1167 11BF; # (쪜; 쪜; 쪜; 쪜; 쪜; ) HANGUL SYLLABLE JJYEOK +CA9D;CA9D;110D 1167 11C0;CA9D;110D 1167 11C0; # (쪝; 쪝; 쪝; 쪝; 쪝; ) HANGUL SYLLABLE JJYEOT +CA9E;CA9E;110D 1167 11C1;CA9E;110D 1167 11C1; # (쪞; 쪞; 쪞; 쪞; 쪞; ) HANGUL SYLLABLE JJYEOP +CA9F;CA9F;110D 1167 11C2;CA9F;110D 1167 11C2; # (쪟; 쪟; 쪟; 쪟; 쪟; ) HANGUL SYLLABLE JJYEOH +CAA0;CAA0;110D 1168;CAA0;110D 1168; # (쪠; 쪠; 쪠; 쪠; 쪠; ) HANGUL SYLLABLE JJYE +CAA1;CAA1;110D 1168 11A8;CAA1;110D 1168 11A8; # (쪡; 쪡; 쪡; 쪡; 쪡; ) HANGUL SYLLABLE JJYEG +CAA2;CAA2;110D 1168 11A9;CAA2;110D 1168 11A9; # (쪢; 쪢; 쪢; 쪢; 쪢; ) HANGUL SYLLABLE JJYEGG +CAA3;CAA3;110D 1168 11AA;CAA3;110D 1168 11AA; # (쪣; 쪣; 쪣; 쪣; 쪣; ) HANGUL SYLLABLE JJYEGS +CAA4;CAA4;110D 1168 11AB;CAA4;110D 1168 11AB; # (쪤; 쪤; 쪤; 쪤; 쪤; ) HANGUL SYLLABLE JJYEN +CAA5;CAA5;110D 1168 11AC;CAA5;110D 1168 11AC; # (쪥; 쪥; 쪥; 쪥; 쪥; ) HANGUL SYLLABLE JJYENJ +CAA6;CAA6;110D 1168 11AD;CAA6;110D 1168 11AD; # (쪦; 쪦; 쪦; 쪦; 쪦; ) HANGUL SYLLABLE JJYENH +CAA7;CAA7;110D 1168 11AE;CAA7;110D 1168 11AE; # (쪧; 쪧; 쪧; 쪧; 쪧; ) HANGUL SYLLABLE JJYED +CAA8;CAA8;110D 1168 11AF;CAA8;110D 1168 11AF; # (쪨; 쪨; 쪨; 쪨; 쪨; ) HANGUL SYLLABLE JJYEL +CAA9;CAA9;110D 1168 11B0;CAA9;110D 1168 11B0; # (쪩; 쪩; 쪩; 쪩; 쪩; ) HANGUL SYLLABLE JJYELG +CAAA;CAAA;110D 1168 11B1;CAAA;110D 1168 11B1; # (쪪; 쪪; 쪪; 쪪; 쪪; ) HANGUL SYLLABLE JJYELM +CAAB;CAAB;110D 1168 11B2;CAAB;110D 1168 11B2; # (쪫; 쪫; 쪫; 쪫; 쪫; ) HANGUL SYLLABLE JJYELB +CAAC;CAAC;110D 1168 11B3;CAAC;110D 1168 11B3; # (쪬; 쪬; 쪬; 쪬; 쪬; ) HANGUL SYLLABLE JJYELS +CAAD;CAAD;110D 1168 11B4;CAAD;110D 1168 11B4; # (쪭; 쪭; 쪭; 쪭; 쪭; ) HANGUL SYLLABLE JJYELT +CAAE;CAAE;110D 1168 11B5;CAAE;110D 1168 11B5; # (쪮; 쪮; 쪮; 쪮; 쪮; ) HANGUL SYLLABLE JJYELP +CAAF;CAAF;110D 1168 11B6;CAAF;110D 1168 11B6; # (쪯; 쪯; 쪯; 쪯; 쪯; ) HANGUL SYLLABLE JJYELH +CAB0;CAB0;110D 1168 11B7;CAB0;110D 1168 11B7; # (쪰; 쪰; 쪰; 쪰; 쪰; ) HANGUL SYLLABLE JJYEM +CAB1;CAB1;110D 1168 11B8;CAB1;110D 1168 11B8; # (쪱; 쪱; 쪱; 쪱; 쪱; ) HANGUL SYLLABLE JJYEB +CAB2;CAB2;110D 1168 11B9;CAB2;110D 1168 11B9; # (쪲; 쪲; 쪲; 쪲; 쪲; ) HANGUL SYLLABLE JJYEBS +CAB3;CAB3;110D 1168 11BA;CAB3;110D 1168 11BA; # (쪳; 쪳; 쪳; 쪳; 쪳; ) HANGUL SYLLABLE JJYES +CAB4;CAB4;110D 1168 11BB;CAB4;110D 1168 11BB; # (쪴; 쪴; 쪴; 쪴; 쪴; ) HANGUL SYLLABLE JJYESS +CAB5;CAB5;110D 1168 11BC;CAB5;110D 1168 11BC; # (쪵; 쪵; 쪵; 쪵; 쪵; ) HANGUL SYLLABLE JJYENG +CAB6;CAB6;110D 1168 11BD;CAB6;110D 1168 11BD; # (쪶; 쪶; 쪶; 쪶; 쪶; ) HANGUL SYLLABLE JJYEJ +CAB7;CAB7;110D 1168 11BE;CAB7;110D 1168 11BE; # (쪷; 쪷; 쪷; 쪷; 쪷; ) HANGUL SYLLABLE JJYEC +CAB8;CAB8;110D 1168 11BF;CAB8;110D 1168 11BF; # (쪸; 쪸; 쪸; 쪸; 쪸; ) HANGUL SYLLABLE JJYEK +CAB9;CAB9;110D 1168 11C0;CAB9;110D 1168 11C0; # (쪹; 쪹; 쪹; 쪹; 쪹; ) HANGUL SYLLABLE JJYET +CABA;CABA;110D 1168 11C1;CABA;110D 1168 11C1; # (쪺; 쪺; 쪺; 쪺; 쪺; ) HANGUL SYLLABLE JJYEP +CABB;CABB;110D 1168 11C2;CABB;110D 1168 11C2; # (쪻; 쪻; 쪻; 쪻; 쪻; ) HANGUL SYLLABLE JJYEH +CABC;CABC;110D 1169;CABC;110D 1169; # (쪼; 쪼; 쪼; 쪼; 쪼; ) HANGUL SYLLABLE JJO +CABD;CABD;110D 1169 11A8;CABD;110D 1169 11A8; # (쪽; 쪽; 쪽; 쪽; 쪽; ) HANGUL SYLLABLE JJOG +CABE;CABE;110D 1169 11A9;CABE;110D 1169 11A9; # (쪾; 쪾; 쪾; 쪾; 쪾; ) HANGUL SYLLABLE JJOGG +CABF;CABF;110D 1169 11AA;CABF;110D 1169 11AA; # (쪿; 쪿; 쪿; 쪿; 쪿; ) HANGUL SYLLABLE JJOGS +CAC0;CAC0;110D 1169 11AB;CAC0;110D 1169 11AB; # (쫀; 쫀; 쫀; 쫀; 쫀; ) HANGUL SYLLABLE JJON +CAC1;CAC1;110D 1169 11AC;CAC1;110D 1169 11AC; # (쫁; 쫁; 쫁; 쫁; 쫁; ) HANGUL SYLLABLE JJONJ +CAC2;CAC2;110D 1169 11AD;CAC2;110D 1169 11AD; # (쫂; 쫂; 쫂; 쫂; 쫂; ) HANGUL SYLLABLE JJONH +CAC3;CAC3;110D 1169 11AE;CAC3;110D 1169 11AE; # (쫃; 쫃; 쫃; 쫃; 쫃; ) HANGUL SYLLABLE JJOD +CAC4;CAC4;110D 1169 11AF;CAC4;110D 1169 11AF; # (쫄; 쫄; 쫄; 쫄; 쫄; ) HANGUL SYLLABLE JJOL +CAC5;CAC5;110D 1169 11B0;CAC5;110D 1169 11B0; # (쫅; 쫅; 쫅; 쫅; 쫅; ) HANGUL SYLLABLE JJOLG +CAC6;CAC6;110D 1169 11B1;CAC6;110D 1169 11B1; # (쫆; 쫆; 쫆; 쫆; 쫆; ) HANGUL SYLLABLE JJOLM +CAC7;CAC7;110D 1169 11B2;CAC7;110D 1169 11B2; # (쫇; 쫇; 쫇; 쫇; 쫇; ) HANGUL SYLLABLE JJOLB +CAC8;CAC8;110D 1169 11B3;CAC8;110D 1169 11B3; # (쫈; 쫈; 쫈; 쫈; 쫈; ) HANGUL SYLLABLE JJOLS +CAC9;CAC9;110D 1169 11B4;CAC9;110D 1169 11B4; # (쫉; 쫉; 쫉; 쫉; 쫉; ) HANGUL SYLLABLE JJOLT +CACA;CACA;110D 1169 11B5;CACA;110D 1169 11B5; # (쫊; 쫊; 쫊; 쫊; 쫊; ) HANGUL SYLLABLE JJOLP +CACB;CACB;110D 1169 11B6;CACB;110D 1169 11B6; # (쫋; 쫋; 쫋; 쫋; 쫋; ) HANGUL SYLLABLE JJOLH +CACC;CACC;110D 1169 11B7;CACC;110D 1169 11B7; # (쫌; 쫌; 쫌; 쫌; 쫌; ) HANGUL SYLLABLE JJOM +CACD;CACD;110D 1169 11B8;CACD;110D 1169 11B8; # (쫍; 쫍; 쫍; 쫍; 쫍; ) HANGUL SYLLABLE JJOB +CACE;CACE;110D 1169 11B9;CACE;110D 1169 11B9; # (쫎; 쫎; 쫎; 쫎; 쫎; ) HANGUL SYLLABLE JJOBS +CACF;CACF;110D 1169 11BA;CACF;110D 1169 11BA; # (쫏; 쫏; 쫏; 쫏; 쫏; ) HANGUL SYLLABLE JJOS +CAD0;CAD0;110D 1169 11BB;CAD0;110D 1169 11BB; # (쫐; 쫐; 쫐; 쫐; 쫐; ) HANGUL SYLLABLE JJOSS +CAD1;CAD1;110D 1169 11BC;CAD1;110D 1169 11BC; # (쫑; 쫑; 쫑; 쫑; 쫑; ) HANGUL SYLLABLE JJONG +CAD2;CAD2;110D 1169 11BD;CAD2;110D 1169 11BD; # (쫒; 쫒; 쫒; 쫒; 쫒; ) HANGUL SYLLABLE JJOJ +CAD3;CAD3;110D 1169 11BE;CAD3;110D 1169 11BE; # (쫓; 쫓; 쫓; 쫓; 쫓; ) HANGUL SYLLABLE JJOC +CAD4;CAD4;110D 1169 11BF;CAD4;110D 1169 11BF; # (쫔; 쫔; 쫔; 쫔; 쫔; ) HANGUL SYLLABLE JJOK +CAD5;CAD5;110D 1169 11C0;CAD5;110D 1169 11C0; # (쫕; 쫕; 쫕; 쫕; 쫕; ) HANGUL SYLLABLE JJOT +CAD6;CAD6;110D 1169 11C1;CAD6;110D 1169 11C1; # (쫖; 쫖; 쫖; 쫖; 쫖; ) HANGUL SYLLABLE JJOP +CAD7;CAD7;110D 1169 11C2;CAD7;110D 1169 11C2; # (쫗; 쫗; 쫗; 쫗; 쫗; ) HANGUL SYLLABLE JJOH +CAD8;CAD8;110D 116A;CAD8;110D 116A; # (쫘; 쫘; 쫘; 쫘; 쫘; ) HANGUL SYLLABLE JJWA +CAD9;CAD9;110D 116A 11A8;CAD9;110D 116A 11A8; # (쫙; 쫙; 쫙; 쫙; 쫙; ) HANGUL SYLLABLE JJWAG +CADA;CADA;110D 116A 11A9;CADA;110D 116A 11A9; # (쫚; 쫚; 쫚; 쫚; 쫚; ) HANGUL SYLLABLE JJWAGG +CADB;CADB;110D 116A 11AA;CADB;110D 116A 11AA; # (쫛; 쫛; 쫛; 쫛; 쫛; ) HANGUL SYLLABLE JJWAGS +CADC;CADC;110D 116A 11AB;CADC;110D 116A 11AB; # (쫜; 쫜; 쫜; 쫜; 쫜; ) HANGUL SYLLABLE JJWAN +CADD;CADD;110D 116A 11AC;CADD;110D 116A 11AC; # (쫝; 쫝; 쫝; 쫝; 쫝; ) HANGUL SYLLABLE JJWANJ +CADE;CADE;110D 116A 11AD;CADE;110D 116A 11AD; # (쫞; 쫞; 쫞; 쫞; 쫞; ) HANGUL SYLLABLE JJWANH +CADF;CADF;110D 116A 11AE;CADF;110D 116A 11AE; # (쫟; 쫟; 쫟; 쫟; 쫟; ) HANGUL SYLLABLE JJWAD +CAE0;CAE0;110D 116A 11AF;CAE0;110D 116A 11AF; # (쫠; 쫠; 쫠; 쫠; 쫠; ) HANGUL SYLLABLE JJWAL +CAE1;CAE1;110D 116A 11B0;CAE1;110D 116A 11B0; # (쫡; 쫡; 쫡; 쫡; 쫡; ) HANGUL SYLLABLE JJWALG +CAE2;CAE2;110D 116A 11B1;CAE2;110D 116A 11B1; # (쫢; 쫢; 쫢; 쫢; 쫢; ) HANGUL SYLLABLE JJWALM +CAE3;CAE3;110D 116A 11B2;CAE3;110D 116A 11B2; # (쫣; 쫣; 쫣; 쫣; 쫣; ) HANGUL SYLLABLE JJWALB +CAE4;CAE4;110D 116A 11B3;CAE4;110D 116A 11B3; # (쫤; 쫤; 쫤; 쫤; 쫤; ) HANGUL SYLLABLE JJWALS +CAE5;CAE5;110D 116A 11B4;CAE5;110D 116A 11B4; # (쫥; 쫥; 쫥; 쫥; 쫥; ) HANGUL SYLLABLE JJWALT +CAE6;CAE6;110D 116A 11B5;CAE6;110D 116A 11B5; # (쫦; 쫦; 쫦; 쫦; 쫦; ) HANGUL SYLLABLE JJWALP +CAE7;CAE7;110D 116A 11B6;CAE7;110D 116A 11B6; # (쫧; 쫧; 쫧; 쫧; 쫧; ) HANGUL SYLLABLE JJWALH +CAE8;CAE8;110D 116A 11B7;CAE8;110D 116A 11B7; # (쫨; 쫨; 쫨; 쫨; 쫨; ) HANGUL SYLLABLE JJWAM +CAE9;CAE9;110D 116A 11B8;CAE9;110D 116A 11B8; # (쫩; 쫩; 쫩; 쫩; 쫩; ) HANGUL SYLLABLE JJWAB +CAEA;CAEA;110D 116A 11B9;CAEA;110D 116A 11B9; # (쫪; 쫪; 쫪; 쫪; 쫪; ) HANGUL SYLLABLE JJWABS +CAEB;CAEB;110D 116A 11BA;CAEB;110D 116A 11BA; # (쫫; 쫫; 쫫; 쫫; 쫫; ) HANGUL SYLLABLE JJWAS +CAEC;CAEC;110D 116A 11BB;CAEC;110D 116A 11BB; # (쫬; 쫬; 쫬; 쫬; 쫬; ) HANGUL SYLLABLE JJWASS +CAED;CAED;110D 116A 11BC;CAED;110D 116A 11BC; # (쫭; 쫭; 쫭; 쫭; 쫭; ) HANGUL SYLLABLE JJWANG +CAEE;CAEE;110D 116A 11BD;CAEE;110D 116A 11BD; # (쫮; 쫮; 쫮; 쫮; 쫮; ) HANGUL SYLLABLE JJWAJ +CAEF;CAEF;110D 116A 11BE;CAEF;110D 116A 11BE; # (쫯; 쫯; 쫯; 쫯; 쫯; ) HANGUL SYLLABLE JJWAC +CAF0;CAF0;110D 116A 11BF;CAF0;110D 116A 11BF; # (쫰; 쫰; 쫰; 쫰; 쫰; ) HANGUL SYLLABLE JJWAK +CAF1;CAF1;110D 116A 11C0;CAF1;110D 116A 11C0; # (쫱; 쫱; 쫱; 쫱; 쫱; ) HANGUL SYLLABLE JJWAT +CAF2;CAF2;110D 116A 11C1;CAF2;110D 116A 11C1; # (쫲; 쫲; 쫲; 쫲; 쫲; ) HANGUL SYLLABLE JJWAP +CAF3;CAF3;110D 116A 11C2;CAF3;110D 116A 11C2; # (쫳; 쫳; 쫳; 쫳; 쫳; ) HANGUL SYLLABLE JJWAH +CAF4;CAF4;110D 116B;CAF4;110D 116B; # (쫴; 쫴; 쫴; 쫴; 쫴; ) HANGUL SYLLABLE JJWAE +CAF5;CAF5;110D 116B 11A8;CAF5;110D 116B 11A8; # (쫵; 쫵; 쫵; 쫵; 쫵; ) HANGUL SYLLABLE JJWAEG +CAF6;CAF6;110D 116B 11A9;CAF6;110D 116B 11A9; # (쫶; 쫶; 쫶; 쫶; 쫶; ) HANGUL SYLLABLE JJWAEGG +CAF7;CAF7;110D 116B 11AA;CAF7;110D 116B 11AA; # (쫷; 쫷; 쫷; 쫷; 쫷; ) HANGUL SYLLABLE JJWAEGS +CAF8;CAF8;110D 116B 11AB;CAF8;110D 116B 11AB; # (쫸; 쫸; 쫸; 쫸; 쫸; ) HANGUL SYLLABLE JJWAEN +CAF9;CAF9;110D 116B 11AC;CAF9;110D 116B 11AC; # (쫹; 쫹; 쫹; 쫹; 쫹; ) HANGUL SYLLABLE JJWAENJ +CAFA;CAFA;110D 116B 11AD;CAFA;110D 116B 11AD; # (쫺; 쫺; 쫺; 쫺; 쫺; ) HANGUL SYLLABLE JJWAENH +CAFB;CAFB;110D 116B 11AE;CAFB;110D 116B 11AE; # (쫻; 쫻; 쫻; 쫻; 쫻; ) HANGUL SYLLABLE JJWAED +CAFC;CAFC;110D 116B 11AF;CAFC;110D 116B 11AF; # (쫼; 쫼; 쫼; 쫼; 쫼; ) HANGUL SYLLABLE JJWAEL +CAFD;CAFD;110D 116B 11B0;CAFD;110D 116B 11B0; # (쫽; 쫽; 쫽; 쫽; 쫽; ) HANGUL SYLLABLE JJWAELG +CAFE;CAFE;110D 116B 11B1;CAFE;110D 116B 11B1; # (쫾; 쫾; 쫾; 쫾; 쫾; ) HANGUL SYLLABLE JJWAELM +CAFF;CAFF;110D 116B 11B2;CAFF;110D 116B 11B2; # (쫿; 쫿; 쫿; 쫿; 쫿; ) HANGUL SYLLABLE JJWAELB +CB00;CB00;110D 116B 11B3;CB00;110D 116B 11B3; # (쬀; 쬀; 쬀; 쬀; 쬀; ) HANGUL SYLLABLE JJWAELS +CB01;CB01;110D 116B 11B4;CB01;110D 116B 11B4; # (쬁; 쬁; 쬁; 쬁; 쬁; ) HANGUL SYLLABLE JJWAELT +CB02;CB02;110D 116B 11B5;CB02;110D 116B 11B5; # (쬂; 쬂; 쬂; 쬂; 쬂; ) HANGUL SYLLABLE JJWAELP +CB03;CB03;110D 116B 11B6;CB03;110D 116B 11B6; # (쬃; 쬃; 쬃; 쬃; 쬃; ) HANGUL SYLLABLE JJWAELH +CB04;CB04;110D 116B 11B7;CB04;110D 116B 11B7; # (쬄; 쬄; 쬄; 쬄; 쬄; ) HANGUL SYLLABLE JJWAEM +CB05;CB05;110D 116B 11B8;CB05;110D 116B 11B8; # (쬅; 쬅; 쬅; 쬅; 쬅; ) HANGUL SYLLABLE JJWAEB +CB06;CB06;110D 116B 11B9;CB06;110D 116B 11B9; # (쬆; 쬆; 쬆; 쬆; 쬆; ) HANGUL SYLLABLE JJWAEBS +CB07;CB07;110D 116B 11BA;CB07;110D 116B 11BA; # (쬇; 쬇; 쬇; 쬇; 쬇; ) HANGUL SYLLABLE JJWAES +CB08;CB08;110D 116B 11BB;CB08;110D 116B 11BB; # (쬈; 쬈; 쬈; 쬈; 쬈; ) HANGUL SYLLABLE JJWAESS +CB09;CB09;110D 116B 11BC;CB09;110D 116B 11BC; # (쬉; 쬉; 쬉; 쬉; 쬉; ) HANGUL SYLLABLE JJWAENG +CB0A;CB0A;110D 116B 11BD;CB0A;110D 116B 11BD; # (쬊; 쬊; 쬊; 쬊; 쬊; ) HANGUL SYLLABLE JJWAEJ +CB0B;CB0B;110D 116B 11BE;CB0B;110D 116B 11BE; # (쬋; 쬋; 쬋; 쬋; 쬋; ) HANGUL SYLLABLE JJWAEC +CB0C;CB0C;110D 116B 11BF;CB0C;110D 116B 11BF; # (쬌; 쬌; 쬌; 쬌; 쬌; ) HANGUL SYLLABLE JJWAEK +CB0D;CB0D;110D 116B 11C0;CB0D;110D 116B 11C0; # (쬍; 쬍; 쬍; 쬍; 쬍; ) HANGUL SYLLABLE JJWAET +CB0E;CB0E;110D 116B 11C1;CB0E;110D 116B 11C1; # (쬎; 쬎; 쬎; 쬎; 쬎; ) HANGUL SYLLABLE JJWAEP +CB0F;CB0F;110D 116B 11C2;CB0F;110D 116B 11C2; # (쬏; 쬏; 쬏; 쬏; 쬏; ) HANGUL SYLLABLE JJWAEH +CB10;CB10;110D 116C;CB10;110D 116C; # (쬐; 쬐; 쬐; 쬐; 쬐; ) HANGUL SYLLABLE JJOE +CB11;CB11;110D 116C 11A8;CB11;110D 116C 11A8; # (쬑; 쬑; 쬑; 쬑; 쬑; ) HANGUL SYLLABLE JJOEG +CB12;CB12;110D 116C 11A9;CB12;110D 116C 11A9; # (쬒; 쬒; 쬒; 쬒; 쬒; ) HANGUL SYLLABLE JJOEGG +CB13;CB13;110D 116C 11AA;CB13;110D 116C 11AA; # (쬓; 쬓; 쬓; 쬓; 쬓; ) HANGUL SYLLABLE JJOEGS +CB14;CB14;110D 116C 11AB;CB14;110D 116C 11AB; # (쬔; 쬔; 쬔; 쬔; 쬔; ) HANGUL SYLLABLE JJOEN +CB15;CB15;110D 116C 11AC;CB15;110D 116C 11AC; # (쬕; 쬕; 쬕; 쬕; 쬕; ) HANGUL SYLLABLE JJOENJ +CB16;CB16;110D 116C 11AD;CB16;110D 116C 11AD; # (쬖; 쬖; 쬖; 쬖; 쬖; ) HANGUL SYLLABLE JJOENH +CB17;CB17;110D 116C 11AE;CB17;110D 116C 11AE; # (쬗; 쬗; 쬗; 쬗; 쬗; ) HANGUL SYLLABLE JJOED +CB18;CB18;110D 116C 11AF;CB18;110D 116C 11AF; # (쬘; 쬘; 쬘; 쬘; 쬘; ) HANGUL SYLLABLE JJOEL +CB19;CB19;110D 116C 11B0;CB19;110D 116C 11B0; # (쬙; 쬙; 쬙; 쬙; 쬙; ) HANGUL SYLLABLE JJOELG +CB1A;CB1A;110D 116C 11B1;CB1A;110D 116C 11B1; # (쬚; 쬚; 쬚; 쬚; 쬚; ) HANGUL SYLLABLE JJOELM +CB1B;CB1B;110D 116C 11B2;CB1B;110D 116C 11B2; # (쬛; 쬛; 쬛; 쬛; 쬛; ) HANGUL SYLLABLE JJOELB +CB1C;CB1C;110D 116C 11B3;CB1C;110D 116C 11B3; # (쬜; 쬜; 쬜; 쬜; 쬜; ) HANGUL SYLLABLE JJOELS +CB1D;CB1D;110D 116C 11B4;CB1D;110D 116C 11B4; # (쬝; 쬝; 쬝; 쬝; 쬝; ) HANGUL SYLLABLE JJOELT +CB1E;CB1E;110D 116C 11B5;CB1E;110D 116C 11B5; # (쬞; 쬞; 쬞; 쬞; 쬞; ) HANGUL SYLLABLE JJOELP +CB1F;CB1F;110D 116C 11B6;CB1F;110D 116C 11B6; # (쬟; 쬟; 쬟; 쬟; 쬟; ) HANGUL SYLLABLE JJOELH +CB20;CB20;110D 116C 11B7;CB20;110D 116C 11B7; # (쬠; 쬠; 쬠; 쬠; 쬠; ) HANGUL SYLLABLE JJOEM +CB21;CB21;110D 116C 11B8;CB21;110D 116C 11B8; # (쬡; 쬡; 쬡; 쬡; 쬡; ) HANGUL SYLLABLE JJOEB +CB22;CB22;110D 116C 11B9;CB22;110D 116C 11B9; # (쬢; 쬢; 쬢; 쬢; 쬢; ) HANGUL SYLLABLE JJOEBS +CB23;CB23;110D 116C 11BA;CB23;110D 116C 11BA; # (쬣; 쬣; 쬣; 쬣; 쬣; ) HANGUL SYLLABLE JJOES +CB24;CB24;110D 116C 11BB;CB24;110D 116C 11BB; # (쬤; 쬤; 쬤; 쬤; 쬤; ) HANGUL SYLLABLE JJOESS +CB25;CB25;110D 116C 11BC;CB25;110D 116C 11BC; # (쬥; 쬥; 쬥; 쬥; 쬥; ) HANGUL SYLLABLE JJOENG +CB26;CB26;110D 116C 11BD;CB26;110D 116C 11BD; # (쬦; 쬦; 쬦; 쬦; 쬦; ) HANGUL SYLLABLE JJOEJ +CB27;CB27;110D 116C 11BE;CB27;110D 116C 11BE; # (쬧; 쬧; 쬧; 쬧; 쬧; ) HANGUL SYLLABLE JJOEC +CB28;CB28;110D 116C 11BF;CB28;110D 116C 11BF; # (쬨; 쬨; 쬨; 쬨; 쬨; ) HANGUL SYLLABLE JJOEK +CB29;CB29;110D 116C 11C0;CB29;110D 116C 11C0; # (쬩; 쬩; 쬩; 쬩; 쬩; ) HANGUL SYLLABLE JJOET +CB2A;CB2A;110D 116C 11C1;CB2A;110D 116C 11C1; # (쬪; 쬪; 쬪; 쬪; 쬪; ) HANGUL SYLLABLE JJOEP +CB2B;CB2B;110D 116C 11C2;CB2B;110D 116C 11C2; # (쬫; 쬫; 쬫; 쬫; 쬫; ) HANGUL SYLLABLE JJOEH +CB2C;CB2C;110D 116D;CB2C;110D 116D; # (쬬; 쬬; 쬬; 쬬; 쬬; ) HANGUL SYLLABLE JJYO +CB2D;CB2D;110D 116D 11A8;CB2D;110D 116D 11A8; # (쬭; 쬭; 쬭; 쬭; 쬭; ) HANGUL SYLLABLE JJYOG +CB2E;CB2E;110D 116D 11A9;CB2E;110D 116D 11A9; # (쬮; 쬮; 쬮; 쬮; 쬮; ) HANGUL SYLLABLE JJYOGG +CB2F;CB2F;110D 116D 11AA;CB2F;110D 116D 11AA; # (쬯; 쬯; 쬯; 쬯; 쬯; ) HANGUL SYLLABLE JJYOGS +CB30;CB30;110D 116D 11AB;CB30;110D 116D 11AB; # (쬰; 쬰; 쬰; 쬰; 쬰; ) HANGUL SYLLABLE JJYON +CB31;CB31;110D 116D 11AC;CB31;110D 116D 11AC; # (쬱; 쬱; 쬱; 쬱; 쬱; ) HANGUL SYLLABLE JJYONJ +CB32;CB32;110D 116D 11AD;CB32;110D 116D 11AD; # (쬲; 쬲; 쬲; 쬲; 쬲; ) HANGUL SYLLABLE JJYONH +CB33;CB33;110D 116D 11AE;CB33;110D 116D 11AE; # (쬳; 쬳; 쬳; 쬳; 쬳; ) HANGUL SYLLABLE JJYOD +CB34;CB34;110D 116D 11AF;CB34;110D 116D 11AF; # (쬴; 쬴; 쬴; 쬴; 쬴; ) HANGUL SYLLABLE JJYOL +CB35;CB35;110D 116D 11B0;CB35;110D 116D 11B0; # (쬵; 쬵; 쬵; 쬵; 쬵; ) HANGUL SYLLABLE JJYOLG +CB36;CB36;110D 116D 11B1;CB36;110D 116D 11B1; # (쬶; 쬶; 쬶; 쬶; 쬶; ) HANGUL SYLLABLE JJYOLM +CB37;CB37;110D 116D 11B2;CB37;110D 116D 11B2; # (쬷; 쬷; 쬷; 쬷; 쬷; ) HANGUL SYLLABLE JJYOLB +CB38;CB38;110D 116D 11B3;CB38;110D 116D 11B3; # (쬸; 쬸; 쬸; 쬸; 쬸; ) HANGUL SYLLABLE JJYOLS +CB39;CB39;110D 116D 11B4;CB39;110D 116D 11B4; # (쬹; 쬹; 쬹; 쬹; 쬹; ) HANGUL SYLLABLE JJYOLT +CB3A;CB3A;110D 116D 11B5;CB3A;110D 116D 11B5; # (쬺; 쬺; 쬺; 쬺; 쬺; ) HANGUL SYLLABLE JJYOLP +CB3B;CB3B;110D 116D 11B6;CB3B;110D 116D 11B6; # (쬻; 쬻; 쬻; 쬻; 쬻; ) HANGUL SYLLABLE JJYOLH +CB3C;CB3C;110D 116D 11B7;CB3C;110D 116D 11B7; # (쬼; 쬼; 쬼; 쬼; 쬼; ) HANGUL SYLLABLE JJYOM +CB3D;CB3D;110D 116D 11B8;CB3D;110D 116D 11B8; # (쬽; 쬽; 쬽; 쬽; 쬽; ) HANGUL SYLLABLE JJYOB +CB3E;CB3E;110D 116D 11B9;CB3E;110D 116D 11B9; # (쬾; 쬾; 쬾; 쬾; 쬾; ) HANGUL SYLLABLE JJYOBS +CB3F;CB3F;110D 116D 11BA;CB3F;110D 116D 11BA; # (쬿; 쬿; 쬿; 쬿; 쬿; ) HANGUL SYLLABLE JJYOS +CB40;CB40;110D 116D 11BB;CB40;110D 116D 11BB; # (쭀; 쭀; 쭀; 쭀; 쭀; ) HANGUL SYLLABLE JJYOSS +CB41;CB41;110D 116D 11BC;CB41;110D 116D 11BC; # (쭁; 쭁; 쭁; 쭁; 쭁; ) HANGUL SYLLABLE JJYONG +CB42;CB42;110D 116D 11BD;CB42;110D 116D 11BD; # (쭂; 쭂; 쭂; 쭂; 쭂; ) HANGUL SYLLABLE JJYOJ +CB43;CB43;110D 116D 11BE;CB43;110D 116D 11BE; # (쭃; 쭃; 쭃; 쭃; 쭃; ) HANGUL SYLLABLE JJYOC +CB44;CB44;110D 116D 11BF;CB44;110D 116D 11BF; # (쭄; 쭄; 쭄; 쭄; 쭄; ) HANGUL SYLLABLE JJYOK +CB45;CB45;110D 116D 11C0;CB45;110D 116D 11C0; # (쭅; 쭅; 쭅; 쭅; 쭅; ) HANGUL SYLLABLE JJYOT +CB46;CB46;110D 116D 11C1;CB46;110D 116D 11C1; # (쭆; 쭆; 쭆; 쭆; 쭆; ) HANGUL SYLLABLE JJYOP +CB47;CB47;110D 116D 11C2;CB47;110D 116D 11C2; # (쭇; 쭇; 쭇; 쭇; 쭇; ) HANGUL SYLLABLE JJYOH +CB48;CB48;110D 116E;CB48;110D 116E; # (쭈; 쭈; 쭈; 쭈; 쭈; ) HANGUL SYLLABLE JJU +CB49;CB49;110D 116E 11A8;CB49;110D 116E 11A8; # (쭉; 쭉; 쭉; 쭉; 쭉; ) HANGUL SYLLABLE JJUG +CB4A;CB4A;110D 116E 11A9;CB4A;110D 116E 11A9; # (쭊; 쭊; 쭊; 쭊; 쭊; ) HANGUL SYLLABLE JJUGG +CB4B;CB4B;110D 116E 11AA;CB4B;110D 116E 11AA; # (쭋; 쭋; 쭋; 쭋; 쭋; ) HANGUL SYLLABLE JJUGS +CB4C;CB4C;110D 116E 11AB;CB4C;110D 116E 11AB; # (쭌; 쭌; 쭌; 쭌; 쭌; ) HANGUL SYLLABLE JJUN +CB4D;CB4D;110D 116E 11AC;CB4D;110D 116E 11AC; # (쭍; 쭍; 쭍; 쭍; 쭍; ) HANGUL SYLLABLE JJUNJ +CB4E;CB4E;110D 116E 11AD;CB4E;110D 116E 11AD; # (쭎; 쭎; 쭎; 쭎; 쭎; ) HANGUL SYLLABLE JJUNH +CB4F;CB4F;110D 116E 11AE;CB4F;110D 116E 11AE; # (쭏; 쭏; 쭏; 쭏; 쭏; ) HANGUL SYLLABLE JJUD +CB50;CB50;110D 116E 11AF;CB50;110D 116E 11AF; # (쭐; 쭐; 쭐; 쭐; 쭐; ) HANGUL SYLLABLE JJUL +CB51;CB51;110D 116E 11B0;CB51;110D 116E 11B0; # (쭑; 쭑; 쭑; 쭑; 쭑; ) HANGUL SYLLABLE JJULG +CB52;CB52;110D 116E 11B1;CB52;110D 116E 11B1; # (쭒; 쭒; 쭒; 쭒; 쭒; ) HANGUL SYLLABLE JJULM +CB53;CB53;110D 116E 11B2;CB53;110D 116E 11B2; # (쭓; 쭓; 쭓; 쭓; 쭓; ) HANGUL SYLLABLE JJULB +CB54;CB54;110D 116E 11B3;CB54;110D 116E 11B3; # (쭔; 쭔; 쭔; 쭔; 쭔; ) HANGUL SYLLABLE JJULS +CB55;CB55;110D 116E 11B4;CB55;110D 116E 11B4; # (쭕; 쭕; 쭕; 쭕; 쭕; ) HANGUL SYLLABLE JJULT +CB56;CB56;110D 116E 11B5;CB56;110D 116E 11B5; # (쭖; 쭖; 쭖; 쭖; 쭖; ) HANGUL SYLLABLE JJULP +CB57;CB57;110D 116E 11B6;CB57;110D 116E 11B6; # (쭗; 쭗; 쭗; 쭗; 쭗; ) HANGUL SYLLABLE JJULH +CB58;CB58;110D 116E 11B7;CB58;110D 116E 11B7; # (쭘; 쭘; 쭘; 쭘; 쭘; ) HANGUL SYLLABLE JJUM +CB59;CB59;110D 116E 11B8;CB59;110D 116E 11B8; # (쭙; 쭙; 쭙; 쭙; 쭙; ) HANGUL SYLLABLE JJUB +CB5A;CB5A;110D 116E 11B9;CB5A;110D 116E 11B9; # (쭚; 쭚; 쭚; 쭚; 쭚; ) HANGUL SYLLABLE JJUBS +CB5B;CB5B;110D 116E 11BA;CB5B;110D 116E 11BA; # (쭛; 쭛; 쭛; 쭛; 쭛; ) HANGUL SYLLABLE JJUS +CB5C;CB5C;110D 116E 11BB;CB5C;110D 116E 11BB; # (쭜; 쭜; 쭜; 쭜; 쭜; ) HANGUL SYLLABLE JJUSS +CB5D;CB5D;110D 116E 11BC;CB5D;110D 116E 11BC; # (쭝; 쭝; 쭝; 쭝; 쭝; ) HANGUL SYLLABLE JJUNG +CB5E;CB5E;110D 116E 11BD;CB5E;110D 116E 11BD; # (쭞; 쭞; 쭞; 쭞; 쭞; ) HANGUL SYLLABLE JJUJ +CB5F;CB5F;110D 116E 11BE;CB5F;110D 116E 11BE; # (쭟; 쭟; 쭟; 쭟; 쭟; ) HANGUL SYLLABLE JJUC +CB60;CB60;110D 116E 11BF;CB60;110D 116E 11BF; # (쭠; 쭠; 쭠; 쭠; 쭠; ) HANGUL SYLLABLE JJUK +CB61;CB61;110D 116E 11C0;CB61;110D 116E 11C0; # (쭡; 쭡; 쭡; 쭡; 쭡; ) HANGUL SYLLABLE JJUT +CB62;CB62;110D 116E 11C1;CB62;110D 116E 11C1; # (쭢; 쭢; 쭢; 쭢; 쭢; ) HANGUL SYLLABLE JJUP +CB63;CB63;110D 116E 11C2;CB63;110D 116E 11C2; # (쭣; 쭣; 쭣; 쭣; 쭣; ) HANGUL SYLLABLE JJUH +CB64;CB64;110D 116F;CB64;110D 116F; # (쭤; 쭤; 쭤; 쭤; 쭤; ) HANGUL SYLLABLE JJWEO +CB65;CB65;110D 116F 11A8;CB65;110D 116F 11A8; # (쭥; 쭥; 쭥; 쭥; 쭥; ) HANGUL SYLLABLE JJWEOG +CB66;CB66;110D 116F 11A9;CB66;110D 116F 11A9; # (쭦; 쭦; 쭦; 쭦; 쭦; ) HANGUL SYLLABLE JJWEOGG +CB67;CB67;110D 116F 11AA;CB67;110D 116F 11AA; # (쭧; 쭧; 쭧; 쭧; 쭧; ) HANGUL SYLLABLE JJWEOGS +CB68;CB68;110D 116F 11AB;CB68;110D 116F 11AB; # (쭨; 쭨; 쭨; 쭨; 쭨; ) HANGUL SYLLABLE JJWEON +CB69;CB69;110D 116F 11AC;CB69;110D 116F 11AC; # (쭩; 쭩; 쭩; 쭩; 쭩; ) HANGUL SYLLABLE JJWEONJ +CB6A;CB6A;110D 116F 11AD;CB6A;110D 116F 11AD; # (쭪; 쭪; 쭪; 쭪; 쭪; ) HANGUL SYLLABLE JJWEONH +CB6B;CB6B;110D 116F 11AE;CB6B;110D 116F 11AE; # (쭫; 쭫; 쭫; 쭫; 쭫; ) HANGUL SYLLABLE JJWEOD +CB6C;CB6C;110D 116F 11AF;CB6C;110D 116F 11AF; # (쭬; 쭬; 쭬; 쭬; 쭬; ) HANGUL SYLLABLE JJWEOL +CB6D;CB6D;110D 116F 11B0;CB6D;110D 116F 11B0; # (쭭; 쭭; 쭭; 쭭; 쭭; ) HANGUL SYLLABLE JJWEOLG +CB6E;CB6E;110D 116F 11B1;CB6E;110D 116F 11B1; # (쭮; 쭮; 쭮; 쭮; 쭮; ) HANGUL SYLLABLE JJWEOLM +CB6F;CB6F;110D 116F 11B2;CB6F;110D 116F 11B2; # (쭯; 쭯; 쭯; 쭯; 쭯; ) HANGUL SYLLABLE JJWEOLB +CB70;CB70;110D 116F 11B3;CB70;110D 116F 11B3; # (쭰; 쭰; 쭰; 쭰; 쭰; ) HANGUL SYLLABLE JJWEOLS +CB71;CB71;110D 116F 11B4;CB71;110D 116F 11B4; # (쭱; 쭱; 쭱; 쭱; 쭱; ) HANGUL SYLLABLE JJWEOLT +CB72;CB72;110D 116F 11B5;CB72;110D 116F 11B5; # (쭲; 쭲; 쭲; 쭲; 쭲; ) HANGUL SYLLABLE JJWEOLP +CB73;CB73;110D 116F 11B6;CB73;110D 116F 11B6; # (쭳; 쭳; 쭳; 쭳; 쭳; ) HANGUL SYLLABLE JJWEOLH +CB74;CB74;110D 116F 11B7;CB74;110D 116F 11B7; # (쭴; 쭴; 쭴; 쭴; 쭴; ) HANGUL SYLLABLE JJWEOM +CB75;CB75;110D 116F 11B8;CB75;110D 116F 11B8; # (쭵; 쭵; 쭵; 쭵; 쭵; ) HANGUL SYLLABLE JJWEOB +CB76;CB76;110D 116F 11B9;CB76;110D 116F 11B9; # (쭶; 쭶; 쭶; 쭶; 쭶; ) HANGUL SYLLABLE JJWEOBS +CB77;CB77;110D 116F 11BA;CB77;110D 116F 11BA; # (쭷; 쭷; 쭷; 쭷; 쭷; ) HANGUL SYLLABLE JJWEOS +CB78;CB78;110D 116F 11BB;CB78;110D 116F 11BB; # (쭸; 쭸; 쭸; 쭸; 쭸; ) HANGUL SYLLABLE JJWEOSS +CB79;CB79;110D 116F 11BC;CB79;110D 116F 11BC; # (쭹; 쭹; 쭹; 쭹; 쭹; ) HANGUL SYLLABLE JJWEONG +CB7A;CB7A;110D 116F 11BD;CB7A;110D 116F 11BD; # (쭺; 쭺; 쭺; 쭺; 쭺; ) HANGUL SYLLABLE JJWEOJ +CB7B;CB7B;110D 116F 11BE;CB7B;110D 116F 11BE; # (쭻; 쭻; 쭻; 쭻; 쭻; ) HANGUL SYLLABLE JJWEOC +CB7C;CB7C;110D 116F 11BF;CB7C;110D 116F 11BF; # (쭼; 쭼; 쭼; 쭼; 쭼; ) HANGUL SYLLABLE JJWEOK +CB7D;CB7D;110D 116F 11C0;CB7D;110D 116F 11C0; # (쭽; 쭽; 쭽; 쭽; 쭽; ) HANGUL SYLLABLE JJWEOT +CB7E;CB7E;110D 116F 11C1;CB7E;110D 116F 11C1; # (쭾; 쭾; 쭾; 쭾; 쭾; ) HANGUL SYLLABLE JJWEOP +CB7F;CB7F;110D 116F 11C2;CB7F;110D 116F 11C2; # (쭿; 쭿; 쭿; 쭿; 쭿; ) HANGUL SYLLABLE JJWEOH +CB80;CB80;110D 1170;CB80;110D 1170; # (쮀; 쮀; 쮀; 쮀; 쮀; ) HANGUL SYLLABLE JJWE +CB81;CB81;110D 1170 11A8;CB81;110D 1170 11A8; # (쮁; 쮁; 쮁; 쮁; 쮁; ) HANGUL SYLLABLE JJWEG +CB82;CB82;110D 1170 11A9;CB82;110D 1170 11A9; # (쮂; 쮂; 쮂; 쮂; 쮂; ) HANGUL SYLLABLE JJWEGG +CB83;CB83;110D 1170 11AA;CB83;110D 1170 11AA; # (쮃; 쮃; 쮃; 쮃; 쮃; ) HANGUL SYLLABLE JJWEGS +CB84;CB84;110D 1170 11AB;CB84;110D 1170 11AB; # (쮄; 쮄; 쮄; 쮄; 쮄; ) HANGUL SYLLABLE JJWEN +CB85;CB85;110D 1170 11AC;CB85;110D 1170 11AC; # (쮅; 쮅; 쮅; 쮅; 쮅; ) HANGUL SYLLABLE JJWENJ +CB86;CB86;110D 1170 11AD;CB86;110D 1170 11AD; # (쮆; 쮆; 쮆; 쮆; 쮆; ) HANGUL SYLLABLE JJWENH +CB87;CB87;110D 1170 11AE;CB87;110D 1170 11AE; # (쮇; 쮇; 쮇; 쮇; 쮇; ) HANGUL SYLLABLE JJWED +CB88;CB88;110D 1170 11AF;CB88;110D 1170 11AF; # (쮈; 쮈; 쮈; 쮈; 쮈; ) HANGUL SYLLABLE JJWEL +CB89;CB89;110D 1170 11B0;CB89;110D 1170 11B0; # (쮉; 쮉; 쮉; 쮉; 쮉; ) HANGUL SYLLABLE JJWELG +CB8A;CB8A;110D 1170 11B1;CB8A;110D 1170 11B1; # (쮊; 쮊; 쮊; 쮊; 쮊; ) HANGUL SYLLABLE JJWELM +CB8B;CB8B;110D 1170 11B2;CB8B;110D 1170 11B2; # (쮋; 쮋; 쮋; 쮋; 쮋; ) HANGUL SYLLABLE JJWELB +CB8C;CB8C;110D 1170 11B3;CB8C;110D 1170 11B3; # (쮌; 쮌; 쮌; 쮌; 쮌; ) HANGUL SYLLABLE JJWELS +CB8D;CB8D;110D 1170 11B4;CB8D;110D 1170 11B4; # (쮍; 쮍; 쮍; 쮍; 쮍; ) HANGUL SYLLABLE JJWELT +CB8E;CB8E;110D 1170 11B5;CB8E;110D 1170 11B5; # (쮎; 쮎; 쮎; 쮎; 쮎; ) HANGUL SYLLABLE JJWELP +CB8F;CB8F;110D 1170 11B6;CB8F;110D 1170 11B6; # (쮏; 쮏; 쮏; 쮏; 쮏; ) HANGUL SYLLABLE JJWELH +CB90;CB90;110D 1170 11B7;CB90;110D 1170 11B7; # (쮐; 쮐; 쮐; 쮐; 쮐; ) HANGUL SYLLABLE JJWEM +CB91;CB91;110D 1170 11B8;CB91;110D 1170 11B8; # (쮑; 쮑; 쮑; 쮑; 쮑; ) HANGUL SYLLABLE JJWEB +CB92;CB92;110D 1170 11B9;CB92;110D 1170 11B9; # (쮒; 쮒; 쮒; 쮒; 쮒; ) HANGUL SYLLABLE JJWEBS +CB93;CB93;110D 1170 11BA;CB93;110D 1170 11BA; # (쮓; 쮓; 쮓; 쮓; 쮓; ) HANGUL SYLLABLE JJWES +CB94;CB94;110D 1170 11BB;CB94;110D 1170 11BB; # (쮔; 쮔; 쮔; 쮔; 쮔; ) HANGUL SYLLABLE JJWESS +CB95;CB95;110D 1170 11BC;CB95;110D 1170 11BC; # (쮕; 쮕; 쮕; 쮕; 쮕; ) HANGUL SYLLABLE JJWENG +CB96;CB96;110D 1170 11BD;CB96;110D 1170 11BD; # (쮖; 쮖; 쮖; 쮖; 쮖; ) HANGUL SYLLABLE JJWEJ +CB97;CB97;110D 1170 11BE;CB97;110D 1170 11BE; # (쮗; 쮗; 쮗; 쮗; 쮗; ) HANGUL SYLLABLE JJWEC +CB98;CB98;110D 1170 11BF;CB98;110D 1170 11BF; # (쮘; 쮘; 쮘; 쮘; 쮘; ) HANGUL SYLLABLE JJWEK +CB99;CB99;110D 1170 11C0;CB99;110D 1170 11C0; # (쮙; 쮙; 쮙; 쮙; 쮙; ) HANGUL SYLLABLE JJWET +CB9A;CB9A;110D 1170 11C1;CB9A;110D 1170 11C1; # (쮚; 쮚; 쮚; 쮚; 쮚; ) HANGUL SYLLABLE JJWEP +CB9B;CB9B;110D 1170 11C2;CB9B;110D 1170 11C2; # (쮛; 쮛; 쮛; 쮛; 쮛; ) HANGUL SYLLABLE JJWEH +CB9C;CB9C;110D 1171;CB9C;110D 1171; # (쮜; 쮜; 쮜; 쮜; 쮜; ) HANGUL SYLLABLE JJWI +CB9D;CB9D;110D 1171 11A8;CB9D;110D 1171 11A8; # (쮝; 쮝; 쮝; 쮝; 쮝; ) HANGUL SYLLABLE JJWIG +CB9E;CB9E;110D 1171 11A9;CB9E;110D 1171 11A9; # (쮞; 쮞; 쮞; 쮞; 쮞; ) HANGUL SYLLABLE JJWIGG +CB9F;CB9F;110D 1171 11AA;CB9F;110D 1171 11AA; # (쮟; 쮟; 쮟; 쮟; 쮟; ) HANGUL SYLLABLE JJWIGS +CBA0;CBA0;110D 1171 11AB;CBA0;110D 1171 11AB; # (쮠; 쮠; 쮠; 쮠; 쮠; ) HANGUL SYLLABLE JJWIN +CBA1;CBA1;110D 1171 11AC;CBA1;110D 1171 11AC; # (쮡; 쮡; 쮡; 쮡; 쮡; ) HANGUL SYLLABLE JJWINJ +CBA2;CBA2;110D 1171 11AD;CBA2;110D 1171 11AD; # (쮢; 쮢; 쮢; 쮢; 쮢; ) HANGUL SYLLABLE JJWINH +CBA3;CBA3;110D 1171 11AE;CBA3;110D 1171 11AE; # (쮣; 쮣; 쮣; 쮣; 쮣; ) HANGUL SYLLABLE JJWID +CBA4;CBA4;110D 1171 11AF;CBA4;110D 1171 11AF; # (쮤; 쮤; 쮤; 쮤; 쮤; ) HANGUL SYLLABLE JJWIL +CBA5;CBA5;110D 1171 11B0;CBA5;110D 1171 11B0; # (쮥; 쮥; 쮥; 쮥; 쮥; ) HANGUL SYLLABLE JJWILG +CBA6;CBA6;110D 1171 11B1;CBA6;110D 1171 11B1; # (쮦; 쮦; 쮦; 쮦; 쮦; ) HANGUL SYLLABLE JJWILM +CBA7;CBA7;110D 1171 11B2;CBA7;110D 1171 11B2; # (쮧; 쮧; 쮧; 쮧; 쮧; ) HANGUL SYLLABLE JJWILB +CBA8;CBA8;110D 1171 11B3;CBA8;110D 1171 11B3; # (쮨; 쮨; 쮨; 쮨; 쮨; ) HANGUL SYLLABLE JJWILS +CBA9;CBA9;110D 1171 11B4;CBA9;110D 1171 11B4; # (쮩; 쮩; 쮩; 쮩; 쮩; ) HANGUL SYLLABLE JJWILT +CBAA;CBAA;110D 1171 11B5;CBAA;110D 1171 11B5; # (쮪; 쮪; 쮪; 쮪; 쮪; ) HANGUL SYLLABLE JJWILP +CBAB;CBAB;110D 1171 11B6;CBAB;110D 1171 11B6; # (쮫; 쮫; 쮫; 쮫; 쮫; ) HANGUL SYLLABLE JJWILH +CBAC;CBAC;110D 1171 11B7;CBAC;110D 1171 11B7; # (쮬; 쮬; 쮬; 쮬; 쮬; ) HANGUL SYLLABLE JJWIM +CBAD;CBAD;110D 1171 11B8;CBAD;110D 1171 11B8; # (쮭; 쮭; 쮭; 쮭; 쮭; ) HANGUL SYLLABLE JJWIB +CBAE;CBAE;110D 1171 11B9;CBAE;110D 1171 11B9; # (쮮; 쮮; 쮮; 쮮; 쮮; ) HANGUL SYLLABLE JJWIBS +CBAF;CBAF;110D 1171 11BA;CBAF;110D 1171 11BA; # (쮯; 쮯; 쮯; 쮯; 쮯; ) HANGUL SYLLABLE JJWIS +CBB0;CBB0;110D 1171 11BB;CBB0;110D 1171 11BB; # (쮰; 쮰; 쮰; 쮰; 쮰; ) HANGUL SYLLABLE JJWISS +CBB1;CBB1;110D 1171 11BC;CBB1;110D 1171 11BC; # (쮱; 쮱; 쮱; 쮱; 쮱; ) HANGUL SYLLABLE JJWING +CBB2;CBB2;110D 1171 11BD;CBB2;110D 1171 11BD; # (쮲; 쮲; 쮲; 쮲; 쮲; ) HANGUL SYLLABLE JJWIJ +CBB3;CBB3;110D 1171 11BE;CBB3;110D 1171 11BE; # (쮳; 쮳; 쮳; 쮳; 쮳; ) HANGUL SYLLABLE JJWIC +CBB4;CBB4;110D 1171 11BF;CBB4;110D 1171 11BF; # (쮴; 쮴; 쮴; 쮴; 쮴; ) HANGUL SYLLABLE JJWIK +CBB5;CBB5;110D 1171 11C0;CBB5;110D 1171 11C0; # (쮵; 쮵; 쮵; 쮵; 쮵; ) HANGUL SYLLABLE JJWIT +CBB6;CBB6;110D 1171 11C1;CBB6;110D 1171 11C1; # (쮶; 쮶; 쮶; 쮶; 쮶; ) HANGUL SYLLABLE JJWIP +CBB7;CBB7;110D 1171 11C2;CBB7;110D 1171 11C2; # (쮷; 쮷; 쮷; 쮷; 쮷; ) HANGUL SYLLABLE JJWIH +CBB8;CBB8;110D 1172;CBB8;110D 1172; # (쮸; 쮸; 쮸; 쮸; 쮸; ) HANGUL SYLLABLE JJYU +CBB9;CBB9;110D 1172 11A8;CBB9;110D 1172 11A8; # (쮹; 쮹; 쮹; 쮹; 쮹; ) HANGUL SYLLABLE JJYUG +CBBA;CBBA;110D 1172 11A9;CBBA;110D 1172 11A9; # (쮺; 쮺; 쮺; 쮺; 쮺; ) HANGUL SYLLABLE JJYUGG +CBBB;CBBB;110D 1172 11AA;CBBB;110D 1172 11AA; # (쮻; 쮻; 쮻; 쮻; 쮻; ) HANGUL SYLLABLE JJYUGS +CBBC;CBBC;110D 1172 11AB;CBBC;110D 1172 11AB; # (쮼; 쮼; 쮼; 쮼; 쮼; ) HANGUL SYLLABLE JJYUN +CBBD;CBBD;110D 1172 11AC;CBBD;110D 1172 11AC; # (쮽; 쮽; 쮽; 쮽; 쮽; ) HANGUL SYLLABLE JJYUNJ +CBBE;CBBE;110D 1172 11AD;CBBE;110D 1172 11AD; # (쮾; 쮾; 쮾; 쮾; 쮾; ) HANGUL SYLLABLE JJYUNH +CBBF;CBBF;110D 1172 11AE;CBBF;110D 1172 11AE; # (쮿; 쮿; 쮿; 쮿; 쮿; ) HANGUL SYLLABLE JJYUD +CBC0;CBC0;110D 1172 11AF;CBC0;110D 1172 11AF; # (쯀; 쯀; 쯀; 쯀; 쯀; ) HANGUL SYLLABLE JJYUL +CBC1;CBC1;110D 1172 11B0;CBC1;110D 1172 11B0; # (쯁; 쯁; 쯁; 쯁; 쯁; ) HANGUL SYLLABLE JJYULG +CBC2;CBC2;110D 1172 11B1;CBC2;110D 1172 11B1; # (쯂; 쯂; 쯂; 쯂; 쯂; ) HANGUL SYLLABLE JJYULM +CBC3;CBC3;110D 1172 11B2;CBC3;110D 1172 11B2; # (쯃; 쯃; 쯃; 쯃; 쯃; ) HANGUL SYLLABLE JJYULB +CBC4;CBC4;110D 1172 11B3;CBC4;110D 1172 11B3; # (쯄; 쯄; 쯄; 쯄; 쯄; ) HANGUL SYLLABLE JJYULS +CBC5;CBC5;110D 1172 11B4;CBC5;110D 1172 11B4; # (쯅; 쯅; 쯅; 쯅; 쯅; ) HANGUL SYLLABLE JJYULT +CBC6;CBC6;110D 1172 11B5;CBC6;110D 1172 11B5; # (쯆; 쯆; 쯆; 쯆; 쯆; ) HANGUL SYLLABLE JJYULP +CBC7;CBC7;110D 1172 11B6;CBC7;110D 1172 11B6; # (쯇; 쯇; 쯇; 쯇; 쯇; ) HANGUL SYLLABLE JJYULH +CBC8;CBC8;110D 1172 11B7;CBC8;110D 1172 11B7; # (쯈; 쯈; 쯈; 쯈; 쯈; ) HANGUL SYLLABLE JJYUM +CBC9;CBC9;110D 1172 11B8;CBC9;110D 1172 11B8; # (쯉; 쯉; 쯉; 쯉; 쯉; ) HANGUL SYLLABLE JJYUB +CBCA;CBCA;110D 1172 11B9;CBCA;110D 1172 11B9; # (쯊; 쯊; 쯊; 쯊; 쯊; ) HANGUL SYLLABLE JJYUBS +CBCB;CBCB;110D 1172 11BA;CBCB;110D 1172 11BA; # (쯋; 쯋; 쯋; 쯋; 쯋; ) HANGUL SYLLABLE JJYUS +CBCC;CBCC;110D 1172 11BB;CBCC;110D 1172 11BB; # (쯌; 쯌; 쯌; 쯌; 쯌; ) HANGUL SYLLABLE JJYUSS +CBCD;CBCD;110D 1172 11BC;CBCD;110D 1172 11BC; # (쯍; 쯍; 쯍; 쯍; 쯍; ) HANGUL SYLLABLE JJYUNG +CBCE;CBCE;110D 1172 11BD;CBCE;110D 1172 11BD; # (쯎; 쯎; 쯎; 쯎; 쯎; ) HANGUL SYLLABLE JJYUJ +CBCF;CBCF;110D 1172 11BE;CBCF;110D 1172 11BE; # (쯏; 쯏; 쯏; 쯏; 쯏; ) HANGUL SYLLABLE JJYUC +CBD0;CBD0;110D 1172 11BF;CBD0;110D 1172 11BF; # (쯐; 쯐; 쯐; 쯐; 쯐; ) HANGUL SYLLABLE JJYUK +CBD1;CBD1;110D 1172 11C0;CBD1;110D 1172 11C0; # (쯑; 쯑; 쯑; 쯑; 쯑; ) HANGUL SYLLABLE JJYUT +CBD2;CBD2;110D 1172 11C1;CBD2;110D 1172 11C1; # (쯒; 쯒; 쯒; 쯒; 쯒; ) HANGUL SYLLABLE JJYUP +CBD3;CBD3;110D 1172 11C2;CBD3;110D 1172 11C2; # (쯓; 쯓; 쯓; 쯓; 쯓; ) HANGUL SYLLABLE JJYUH +CBD4;CBD4;110D 1173;CBD4;110D 1173; # (쯔; 쯔; 쯔; 쯔; 쯔; ) HANGUL SYLLABLE JJEU +CBD5;CBD5;110D 1173 11A8;CBD5;110D 1173 11A8; # (쯕; 쯕; 쯕; 쯕; 쯕; ) HANGUL SYLLABLE JJEUG +CBD6;CBD6;110D 1173 11A9;CBD6;110D 1173 11A9; # (쯖; 쯖; 쯖; 쯖; 쯖; ) HANGUL SYLLABLE JJEUGG +CBD7;CBD7;110D 1173 11AA;CBD7;110D 1173 11AA; # (쯗; 쯗; 쯗; 쯗; 쯗; ) HANGUL SYLLABLE JJEUGS +CBD8;CBD8;110D 1173 11AB;CBD8;110D 1173 11AB; # (쯘; 쯘; 쯘; 쯘; 쯘; ) HANGUL SYLLABLE JJEUN +CBD9;CBD9;110D 1173 11AC;CBD9;110D 1173 11AC; # (쯙; 쯙; 쯙; 쯙; 쯙; ) HANGUL SYLLABLE JJEUNJ +CBDA;CBDA;110D 1173 11AD;CBDA;110D 1173 11AD; # (쯚; 쯚; 쯚; 쯚; 쯚; ) HANGUL SYLLABLE JJEUNH +CBDB;CBDB;110D 1173 11AE;CBDB;110D 1173 11AE; # (쯛; 쯛; 쯛; 쯛; 쯛; ) HANGUL SYLLABLE JJEUD +CBDC;CBDC;110D 1173 11AF;CBDC;110D 1173 11AF; # (쯜; 쯜; 쯜; 쯜; 쯜; ) HANGUL SYLLABLE JJEUL +CBDD;CBDD;110D 1173 11B0;CBDD;110D 1173 11B0; # (쯝; 쯝; 쯝; 쯝; 쯝; ) HANGUL SYLLABLE JJEULG +CBDE;CBDE;110D 1173 11B1;CBDE;110D 1173 11B1; # (쯞; 쯞; 쯞; 쯞; 쯞; ) HANGUL SYLLABLE JJEULM +CBDF;CBDF;110D 1173 11B2;CBDF;110D 1173 11B2; # (쯟; 쯟; 쯟; 쯟; 쯟; ) HANGUL SYLLABLE JJEULB +CBE0;CBE0;110D 1173 11B3;CBE0;110D 1173 11B3; # (쯠; 쯠; 쯠; 쯠; 쯠; ) HANGUL SYLLABLE JJEULS +CBE1;CBE1;110D 1173 11B4;CBE1;110D 1173 11B4; # (쯡; 쯡; 쯡; 쯡; 쯡; ) HANGUL SYLLABLE JJEULT +CBE2;CBE2;110D 1173 11B5;CBE2;110D 1173 11B5; # (쯢; 쯢; 쯢; 쯢; 쯢; ) HANGUL SYLLABLE JJEULP +CBE3;CBE3;110D 1173 11B6;CBE3;110D 1173 11B6; # (쯣; 쯣; 쯣; 쯣; 쯣; ) HANGUL SYLLABLE JJEULH +CBE4;CBE4;110D 1173 11B7;CBE4;110D 1173 11B7; # (쯤; 쯤; 쯤; 쯤; 쯤; ) HANGUL SYLLABLE JJEUM +CBE5;CBE5;110D 1173 11B8;CBE5;110D 1173 11B8; # (쯥; 쯥; 쯥; 쯥; 쯥; ) HANGUL SYLLABLE JJEUB +CBE6;CBE6;110D 1173 11B9;CBE6;110D 1173 11B9; # (쯦; 쯦; 쯦; 쯦; 쯦; ) HANGUL SYLLABLE JJEUBS +CBE7;CBE7;110D 1173 11BA;CBE7;110D 1173 11BA; # (쯧; 쯧; 쯧; 쯧; 쯧; ) HANGUL SYLLABLE JJEUS +CBE8;CBE8;110D 1173 11BB;CBE8;110D 1173 11BB; # (쯨; 쯨; 쯨; 쯨; 쯨; ) HANGUL SYLLABLE JJEUSS +CBE9;CBE9;110D 1173 11BC;CBE9;110D 1173 11BC; # (쯩; 쯩; 쯩; 쯩; 쯩; ) HANGUL SYLLABLE JJEUNG +CBEA;CBEA;110D 1173 11BD;CBEA;110D 1173 11BD; # (쯪; 쯪; 쯪; 쯪; 쯪; ) HANGUL SYLLABLE JJEUJ +CBEB;CBEB;110D 1173 11BE;CBEB;110D 1173 11BE; # (쯫; 쯫; 쯫; 쯫; 쯫; ) HANGUL SYLLABLE JJEUC +CBEC;CBEC;110D 1173 11BF;CBEC;110D 1173 11BF; # (쯬; 쯬; 쯬; 쯬; 쯬; ) HANGUL SYLLABLE JJEUK +CBED;CBED;110D 1173 11C0;CBED;110D 1173 11C0; # (쯭; 쯭; 쯭; 쯭; 쯭; ) HANGUL SYLLABLE JJEUT +CBEE;CBEE;110D 1173 11C1;CBEE;110D 1173 11C1; # (쯮; 쯮; 쯮; 쯮; 쯮; ) HANGUL SYLLABLE JJEUP +CBEF;CBEF;110D 1173 11C2;CBEF;110D 1173 11C2; # (쯯; 쯯; 쯯; 쯯; 쯯; ) HANGUL SYLLABLE JJEUH +CBF0;CBF0;110D 1174;CBF0;110D 1174; # (쯰; 쯰; 쯰; 쯰; 쯰; ) HANGUL SYLLABLE JJYI +CBF1;CBF1;110D 1174 11A8;CBF1;110D 1174 11A8; # (쯱; 쯱; 쯱; 쯱; 쯱; ) HANGUL SYLLABLE JJYIG +CBF2;CBF2;110D 1174 11A9;CBF2;110D 1174 11A9; # (쯲; 쯲; 쯲; 쯲; 쯲; ) HANGUL SYLLABLE JJYIGG +CBF3;CBF3;110D 1174 11AA;CBF3;110D 1174 11AA; # (쯳; 쯳; 쯳; 쯳; 쯳; ) HANGUL SYLLABLE JJYIGS +CBF4;CBF4;110D 1174 11AB;CBF4;110D 1174 11AB; # (쯴; 쯴; 쯴; 쯴; 쯴; ) HANGUL SYLLABLE JJYIN +CBF5;CBF5;110D 1174 11AC;CBF5;110D 1174 11AC; # (쯵; 쯵; 쯵; 쯵; 쯵; ) HANGUL SYLLABLE JJYINJ +CBF6;CBF6;110D 1174 11AD;CBF6;110D 1174 11AD; # (쯶; 쯶; 쯶; 쯶; 쯶; ) HANGUL SYLLABLE JJYINH +CBF7;CBF7;110D 1174 11AE;CBF7;110D 1174 11AE; # (쯷; 쯷; 쯷; 쯷; 쯷; ) HANGUL SYLLABLE JJYID +CBF8;CBF8;110D 1174 11AF;CBF8;110D 1174 11AF; # (쯸; 쯸; 쯸; 쯸; 쯸; ) HANGUL SYLLABLE JJYIL +CBF9;CBF9;110D 1174 11B0;CBF9;110D 1174 11B0; # (쯹; 쯹; 쯹; 쯹; 쯹; ) HANGUL SYLLABLE JJYILG +CBFA;CBFA;110D 1174 11B1;CBFA;110D 1174 11B1; # (쯺; 쯺; 쯺; 쯺; 쯺; ) HANGUL SYLLABLE JJYILM +CBFB;CBFB;110D 1174 11B2;CBFB;110D 1174 11B2; # (쯻; 쯻; 쯻; 쯻; 쯻; ) HANGUL SYLLABLE JJYILB +CBFC;CBFC;110D 1174 11B3;CBFC;110D 1174 11B3; # (쯼; 쯼; 쯼; 쯼; 쯼; ) HANGUL SYLLABLE JJYILS +CBFD;CBFD;110D 1174 11B4;CBFD;110D 1174 11B4; # (쯽; 쯽; 쯽; 쯽; 쯽; ) HANGUL SYLLABLE JJYILT +CBFE;CBFE;110D 1174 11B5;CBFE;110D 1174 11B5; # (쯾; 쯾; 쯾; 쯾; 쯾; ) HANGUL SYLLABLE JJYILP +CBFF;CBFF;110D 1174 11B6;CBFF;110D 1174 11B6; # (쯿; 쯿; 쯿; 쯿; 쯿; ) HANGUL SYLLABLE JJYILH +CC00;CC00;110D 1174 11B7;CC00;110D 1174 11B7; # (찀; 찀; 찀; 찀; 찀; ) HANGUL SYLLABLE JJYIM +CC01;CC01;110D 1174 11B8;CC01;110D 1174 11B8; # (찁; 찁; 찁; 찁; 찁; ) HANGUL SYLLABLE JJYIB +CC02;CC02;110D 1174 11B9;CC02;110D 1174 11B9; # (찂; 찂; 찂; 찂; 찂; ) HANGUL SYLLABLE JJYIBS +CC03;CC03;110D 1174 11BA;CC03;110D 1174 11BA; # (찃; 찃; 찃; 찃; 찃; ) HANGUL SYLLABLE JJYIS +CC04;CC04;110D 1174 11BB;CC04;110D 1174 11BB; # (찄; 찄; 찄; 찄; 찄; ) HANGUL SYLLABLE JJYISS +CC05;CC05;110D 1174 11BC;CC05;110D 1174 11BC; # (찅; 찅; 찅; 찅; 찅; ) HANGUL SYLLABLE JJYING +CC06;CC06;110D 1174 11BD;CC06;110D 1174 11BD; # (찆; 찆; 찆; 찆; 찆; ) HANGUL SYLLABLE JJYIJ +CC07;CC07;110D 1174 11BE;CC07;110D 1174 11BE; # (찇; 찇; 찇; 찇; 찇; ) HANGUL SYLLABLE JJYIC +CC08;CC08;110D 1174 11BF;CC08;110D 1174 11BF; # (찈; 찈; 찈; 찈; 찈; ) HANGUL SYLLABLE JJYIK +CC09;CC09;110D 1174 11C0;CC09;110D 1174 11C0; # (찉; 찉; 찉; 찉; 찉; ) HANGUL SYLLABLE JJYIT +CC0A;CC0A;110D 1174 11C1;CC0A;110D 1174 11C1; # (찊; 찊; 찊; 찊; 찊; ) HANGUL SYLLABLE JJYIP +CC0B;CC0B;110D 1174 11C2;CC0B;110D 1174 11C2; # (찋; 찋; 찋; 찋; 찋; ) HANGUL SYLLABLE JJYIH +CC0C;CC0C;110D 1175;CC0C;110D 1175; # (찌; 찌; 찌; 찌; 찌; ) HANGUL SYLLABLE JJI +CC0D;CC0D;110D 1175 11A8;CC0D;110D 1175 11A8; # (찍; 찍; 찍; 찍; 찍; ) HANGUL SYLLABLE JJIG +CC0E;CC0E;110D 1175 11A9;CC0E;110D 1175 11A9; # (찎; 찎; 찎; 찎; 찎; ) HANGUL SYLLABLE JJIGG +CC0F;CC0F;110D 1175 11AA;CC0F;110D 1175 11AA; # (찏; 찏; 찏; 찏; 찏; ) HANGUL SYLLABLE JJIGS +CC10;CC10;110D 1175 11AB;CC10;110D 1175 11AB; # (찐; 찐; 찐; 찐; 찐; ) HANGUL SYLLABLE JJIN +CC11;CC11;110D 1175 11AC;CC11;110D 1175 11AC; # (찑; 찑; 찑; 찑; 찑; ) HANGUL SYLLABLE JJINJ +CC12;CC12;110D 1175 11AD;CC12;110D 1175 11AD; # (찒; 찒; 찒; 찒; 찒; ) HANGUL SYLLABLE JJINH +CC13;CC13;110D 1175 11AE;CC13;110D 1175 11AE; # (찓; 찓; 찓; 찓; 찓; ) HANGUL SYLLABLE JJID +CC14;CC14;110D 1175 11AF;CC14;110D 1175 11AF; # (찔; 찔; 찔; 찔; 찔; ) HANGUL SYLLABLE JJIL +CC15;CC15;110D 1175 11B0;CC15;110D 1175 11B0; # (찕; 찕; 찕; 찕; 찕; ) HANGUL SYLLABLE JJILG +CC16;CC16;110D 1175 11B1;CC16;110D 1175 11B1; # (찖; 찖; 찖; 찖; 찖; ) HANGUL SYLLABLE JJILM +CC17;CC17;110D 1175 11B2;CC17;110D 1175 11B2; # (찗; 찗; 찗; 찗; 찗; ) HANGUL SYLLABLE JJILB +CC18;CC18;110D 1175 11B3;CC18;110D 1175 11B3; # (찘; 찘; 찘; 찘; 찘; ) HANGUL SYLLABLE JJILS +CC19;CC19;110D 1175 11B4;CC19;110D 1175 11B4; # (찙; 찙; 찙; 찙; 찙; ) HANGUL SYLLABLE JJILT +CC1A;CC1A;110D 1175 11B5;CC1A;110D 1175 11B5; # (찚; 찚; 찚; 찚; 찚; ) HANGUL SYLLABLE JJILP +CC1B;CC1B;110D 1175 11B6;CC1B;110D 1175 11B6; # (찛; 찛; 찛; 찛; 찛; ) HANGUL SYLLABLE JJILH +CC1C;CC1C;110D 1175 11B7;CC1C;110D 1175 11B7; # (찜; 찜; 찜; 찜; 찜; ) HANGUL SYLLABLE JJIM +CC1D;CC1D;110D 1175 11B8;CC1D;110D 1175 11B8; # (찝; 찝; 찝; 찝; 찝; ) HANGUL SYLLABLE JJIB +CC1E;CC1E;110D 1175 11B9;CC1E;110D 1175 11B9; # (찞; 찞; 찞; 찞; 찞; ) HANGUL SYLLABLE JJIBS +CC1F;CC1F;110D 1175 11BA;CC1F;110D 1175 11BA; # (찟; 찟; 찟; 찟; 찟; ) HANGUL SYLLABLE JJIS +CC20;CC20;110D 1175 11BB;CC20;110D 1175 11BB; # (찠; 찠; 찠; 찠; 찠; ) HANGUL SYLLABLE JJISS +CC21;CC21;110D 1175 11BC;CC21;110D 1175 11BC; # (찡; 찡; 찡; 찡; 찡; ) HANGUL SYLLABLE JJING +CC22;CC22;110D 1175 11BD;CC22;110D 1175 11BD; # (찢; 찢; 찢; 찢; 찢; ) HANGUL SYLLABLE JJIJ +CC23;CC23;110D 1175 11BE;CC23;110D 1175 11BE; # (찣; 찣; 찣; 찣; 찣; ) HANGUL SYLLABLE JJIC +CC24;CC24;110D 1175 11BF;CC24;110D 1175 11BF; # (찤; 찤; 찤; 찤; 찤; ) HANGUL SYLLABLE JJIK +CC25;CC25;110D 1175 11C0;CC25;110D 1175 11C0; # (찥; 찥; 찥; 찥; 찥; ) HANGUL SYLLABLE JJIT +CC26;CC26;110D 1175 11C1;CC26;110D 1175 11C1; # (찦; 찦; 찦; 찦; 찦; ) HANGUL SYLLABLE JJIP +CC27;CC27;110D 1175 11C2;CC27;110D 1175 11C2; # (찧; 찧; 찧; 찧; 찧; ) HANGUL SYLLABLE JJIH +CC28;CC28;110E 1161;CC28;110E 1161; # (차; 차; 차; 차; 차; ) HANGUL SYLLABLE CA +CC29;CC29;110E 1161 11A8;CC29;110E 1161 11A8; # (착; 착; 착; 착; 착; ) HANGUL SYLLABLE CAG +CC2A;CC2A;110E 1161 11A9;CC2A;110E 1161 11A9; # (찪; 찪; 찪; 찪; 찪; ) HANGUL SYLLABLE CAGG +CC2B;CC2B;110E 1161 11AA;CC2B;110E 1161 11AA; # (찫; 찫; 찫; 찫; 찫; ) HANGUL SYLLABLE CAGS +CC2C;CC2C;110E 1161 11AB;CC2C;110E 1161 11AB; # (찬; 찬; 찬; 찬; 찬; ) HANGUL SYLLABLE CAN +CC2D;CC2D;110E 1161 11AC;CC2D;110E 1161 11AC; # (찭; 찭; 찭; 찭; 찭; ) HANGUL SYLLABLE CANJ +CC2E;CC2E;110E 1161 11AD;CC2E;110E 1161 11AD; # (찮; 찮; 찮; 찮; 찮; ) HANGUL SYLLABLE CANH +CC2F;CC2F;110E 1161 11AE;CC2F;110E 1161 11AE; # (찯; 찯; 찯; 찯; 찯; ) HANGUL SYLLABLE CAD +CC30;CC30;110E 1161 11AF;CC30;110E 1161 11AF; # (찰; 찰; 찰; 찰; 찰; ) HANGUL SYLLABLE CAL +CC31;CC31;110E 1161 11B0;CC31;110E 1161 11B0; # (찱; 찱; 찱; 찱; 찱; ) HANGUL SYLLABLE CALG +CC32;CC32;110E 1161 11B1;CC32;110E 1161 11B1; # (찲; 찲; 찲; 찲; 찲; ) HANGUL SYLLABLE CALM +CC33;CC33;110E 1161 11B2;CC33;110E 1161 11B2; # (찳; 찳; 찳; 찳; 찳; ) HANGUL SYLLABLE CALB +CC34;CC34;110E 1161 11B3;CC34;110E 1161 11B3; # (찴; 찴; 찴; 찴; 찴; ) HANGUL SYLLABLE CALS +CC35;CC35;110E 1161 11B4;CC35;110E 1161 11B4; # (찵; 찵; 찵; 찵; 찵; ) HANGUL SYLLABLE CALT +CC36;CC36;110E 1161 11B5;CC36;110E 1161 11B5; # (찶; 찶; 찶; 찶; 찶; ) HANGUL SYLLABLE CALP +CC37;CC37;110E 1161 11B6;CC37;110E 1161 11B6; # (찷; 찷; 찷; 찷; 찷; ) HANGUL SYLLABLE CALH +CC38;CC38;110E 1161 11B7;CC38;110E 1161 11B7; # (참; 참; 참; 참; 참; ) HANGUL SYLLABLE CAM +CC39;CC39;110E 1161 11B8;CC39;110E 1161 11B8; # (찹; 찹; 찹; 찹; 찹; ) HANGUL SYLLABLE CAB +CC3A;CC3A;110E 1161 11B9;CC3A;110E 1161 11B9; # (찺; 찺; 찺; 찺; 찺; ) HANGUL SYLLABLE CABS +CC3B;CC3B;110E 1161 11BA;CC3B;110E 1161 11BA; # (찻; 찻; 찻; 찻; 찻; ) HANGUL SYLLABLE CAS +CC3C;CC3C;110E 1161 11BB;CC3C;110E 1161 11BB; # (찼; 찼; 찼; 찼; 찼; ) HANGUL SYLLABLE CASS +CC3D;CC3D;110E 1161 11BC;CC3D;110E 1161 11BC; # (창; 창; 창; 창; 창; ) HANGUL SYLLABLE CANG +CC3E;CC3E;110E 1161 11BD;CC3E;110E 1161 11BD; # (찾; 찾; 찾; 찾; 찾; ) HANGUL SYLLABLE CAJ +CC3F;CC3F;110E 1161 11BE;CC3F;110E 1161 11BE; # (찿; 찿; 찿; 찿; 찿; ) HANGUL SYLLABLE CAC +CC40;CC40;110E 1161 11BF;CC40;110E 1161 11BF; # (챀; 챀; 챀; 챀; 챀; ) HANGUL SYLLABLE CAK +CC41;CC41;110E 1161 11C0;CC41;110E 1161 11C0; # (챁; 챁; 챁; 챁; 챁; ) HANGUL SYLLABLE CAT +CC42;CC42;110E 1161 11C1;CC42;110E 1161 11C1; # (챂; 챂; 챂; 챂; 챂; ) HANGUL SYLLABLE CAP +CC43;CC43;110E 1161 11C2;CC43;110E 1161 11C2; # (챃; 챃; 챃; 챃; 챃; ) HANGUL SYLLABLE CAH +CC44;CC44;110E 1162;CC44;110E 1162; # (채; 채; 채; 채; 채; ) HANGUL SYLLABLE CAE +CC45;CC45;110E 1162 11A8;CC45;110E 1162 11A8; # (책; 책; 책; 책; 책; ) HANGUL SYLLABLE CAEG +CC46;CC46;110E 1162 11A9;CC46;110E 1162 11A9; # (챆; 챆; 챆; 챆; 챆; ) HANGUL SYLLABLE CAEGG +CC47;CC47;110E 1162 11AA;CC47;110E 1162 11AA; # (챇; 챇; 챇; 챇; 챇; ) HANGUL SYLLABLE CAEGS +CC48;CC48;110E 1162 11AB;CC48;110E 1162 11AB; # (챈; 챈; 챈; 챈; 챈; ) HANGUL SYLLABLE CAEN +CC49;CC49;110E 1162 11AC;CC49;110E 1162 11AC; # (챉; 챉; 챉; 챉; 챉; ) HANGUL SYLLABLE CAENJ +CC4A;CC4A;110E 1162 11AD;CC4A;110E 1162 11AD; # (챊; 챊; 챊; 챊; 챊; ) HANGUL SYLLABLE CAENH +CC4B;CC4B;110E 1162 11AE;CC4B;110E 1162 11AE; # (챋; 챋; 챋; 챋; 챋; ) HANGUL SYLLABLE CAED +CC4C;CC4C;110E 1162 11AF;CC4C;110E 1162 11AF; # (챌; 챌; 챌; 챌; 챌; ) HANGUL SYLLABLE CAEL +CC4D;CC4D;110E 1162 11B0;CC4D;110E 1162 11B0; # (챍; 챍; 챍; 챍; 챍; ) HANGUL SYLLABLE CAELG +CC4E;CC4E;110E 1162 11B1;CC4E;110E 1162 11B1; # (챎; 챎; 챎; 챎; 챎; ) HANGUL SYLLABLE CAELM +CC4F;CC4F;110E 1162 11B2;CC4F;110E 1162 11B2; # (챏; 챏; 챏; 챏; 챏; ) HANGUL SYLLABLE CAELB +CC50;CC50;110E 1162 11B3;CC50;110E 1162 11B3; # (챐; 챐; 챐; 챐; 챐; ) HANGUL SYLLABLE CAELS +CC51;CC51;110E 1162 11B4;CC51;110E 1162 11B4; # (챑; 챑; 챑; 챑; 챑; ) HANGUL SYLLABLE CAELT +CC52;CC52;110E 1162 11B5;CC52;110E 1162 11B5; # (챒; 챒; 챒; 챒; 챒; ) HANGUL SYLLABLE CAELP +CC53;CC53;110E 1162 11B6;CC53;110E 1162 11B6; # (챓; 챓; 챓; 챓; 챓; ) HANGUL SYLLABLE CAELH +CC54;CC54;110E 1162 11B7;CC54;110E 1162 11B7; # (챔; 챔; 챔; 챔; 챔; ) HANGUL SYLLABLE CAEM +CC55;CC55;110E 1162 11B8;CC55;110E 1162 11B8; # (챕; 챕; 챕; 챕; 챕; ) HANGUL SYLLABLE CAEB +CC56;CC56;110E 1162 11B9;CC56;110E 1162 11B9; # (챖; 챖; 챖; 챖; 챖; ) HANGUL SYLLABLE CAEBS +CC57;CC57;110E 1162 11BA;CC57;110E 1162 11BA; # (챗; 챗; 챗; 챗; 챗; ) HANGUL SYLLABLE CAES +CC58;CC58;110E 1162 11BB;CC58;110E 1162 11BB; # (챘; 챘; 챘; 챘; 챘; ) HANGUL SYLLABLE CAESS +CC59;CC59;110E 1162 11BC;CC59;110E 1162 11BC; # (챙; 챙; 챙; 챙; 챙; ) HANGUL SYLLABLE CAENG +CC5A;CC5A;110E 1162 11BD;CC5A;110E 1162 11BD; # (챚; 챚; 챚; 챚; 챚; ) HANGUL SYLLABLE CAEJ +CC5B;CC5B;110E 1162 11BE;CC5B;110E 1162 11BE; # (챛; 챛; 챛; 챛; 챛; ) HANGUL SYLLABLE CAEC +CC5C;CC5C;110E 1162 11BF;CC5C;110E 1162 11BF; # (챜; 챜; 챜; 챜; 챜; ) HANGUL SYLLABLE CAEK +CC5D;CC5D;110E 1162 11C0;CC5D;110E 1162 11C0; # (챝; 챝; 챝; 챝; 챝; ) HANGUL SYLLABLE CAET +CC5E;CC5E;110E 1162 11C1;CC5E;110E 1162 11C1; # (챞; 챞; 챞; 챞; 챞; ) HANGUL SYLLABLE CAEP +CC5F;CC5F;110E 1162 11C2;CC5F;110E 1162 11C2; # (챟; 챟; 챟; 챟; 챟; ) HANGUL SYLLABLE CAEH +CC60;CC60;110E 1163;CC60;110E 1163; # (챠; 챠; 챠; 챠; 챠; ) HANGUL SYLLABLE CYA +CC61;CC61;110E 1163 11A8;CC61;110E 1163 11A8; # (챡; 챡; 챡; 챡; 챡; ) HANGUL SYLLABLE CYAG +CC62;CC62;110E 1163 11A9;CC62;110E 1163 11A9; # (챢; 챢; 챢; 챢; 챢; ) HANGUL SYLLABLE CYAGG +CC63;CC63;110E 1163 11AA;CC63;110E 1163 11AA; # (챣; 챣; 챣; 챣; 챣; ) HANGUL SYLLABLE CYAGS +CC64;CC64;110E 1163 11AB;CC64;110E 1163 11AB; # (챤; 챤; 챤; 챤; 챤; ) HANGUL SYLLABLE CYAN +CC65;CC65;110E 1163 11AC;CC65;110E 1163 11AC; # (챥; 챥; 챥; 챥; 챥; ) HANGUL SYLLABLE CYANJ +CC66;CC66;110E 1163 11AD;CC66;110E 1163 11AD; # (챦; 챦; 챦; 챦; 챦; ) HANGUL SYLLABLE CYANH +CC67;CC67;110E 1163 11AE;CC67;110E 1163 11AE; # (챧; 챧; 챧; 챧; 챧; ) HANGUL SYLLABLE CYAD +CC68;CC68;110E 1163 11AF;CC68;110E 1163 11AF; # (챨; 챨; 챨; 챨; 챨; ) HANGUL SYLLABLE CYAL +CC69;CC69;110E 1163 11B0;CC69;110E 1163 11B0; # (챩; 챩; 챩; 챩; 챩; ) HANGUL SYLLABLE CYALG +CC6A;CC6A;110E 1163 11B1;CC6A;110E 1163 11B1; # (챪; 챪; 챪; 챪; 챪; ) HANGUL SYLLABLE CYALM +CC6B;CC6B;110E 1163 11B2;CC6B;110E 1163 11B2; # (챫; 챫; 챫; 챫; 챫; ) HANGUL SYLLABLE CYALB +CC6C;CC6C;110E 1163 11B3;CC6C;110E 1163 11B3; # (챬; 챬; 챬; 챬; 챬; ) HANGUL SYLLABLE CYALS +CC6D;CC6D;110E 1163 11B4;CC6D;110E 1163 11B4; # (챭; 챭; 챭; 챭; 챭; ) HANGUL SYLLABLE CYALT +CC6E;CC6E;110E 1163 11B5;CC6E;110E 1163 11B5; # (챮; 챮; 챮; 챮; 챮; ) HANGUL SYLLABLE CYALP +CC6F;CC6F;110E 1163 11B6;CC6F;110E 1163 11B6; # (챯; 챯; 챯; 챯; 챯; ) HANGUL SYLLABLE CYALH +CC70;CC70;110E 1163 11B7;CC70;110E 1163 11B7; # (챰; 챰; 챰; 챰; 챰; ) HANGUL SYLLABLE CYAM +CC71;CC71;110E 1163 11B8;CC71;110E 1163 11B8; # (챱; 챱; 챱; 챱; 챱; ) HANGUL SYLLABLE CYAB +CC72;CC72;110E 1163 11B9;CC72;110E 1163 11B9; # (챲; 챲; 챲; 챲; 챲; ) HANGUL SYLLABLE CYABS +CC73;CC73;110E 1163 11BA;CC73;110E 1163 11BA; # (챳; 챳; 챳; 챳; 챳; ) HANGUL SYLLABLE CYAS +CC74;CC74;110E 1163 11BB;CC74;110E 1163 11BB; # (챴; 챴; 챴; 챴; 챴; ) HANGUL SYLLABLE CYASS +CC75;CC75;110E 1163 11BC;CC75;110E 1163 11BC; # (챵; 챵; 챵; 챵; 챵; ) HANGUL SYLLABLE CYANG +CC76;CC76;110E 1163 11BD;CC76;110E 1163 11BD; # (챶; 챶; 챶; 챶; 챶; ) HANGUL SYLLABLE CYAJ +CC77;CC77;110E 1163 11BE;CC77;110E 1163 11BE; # (챷; 챷; 챷; 챷; 챷; ) HANGUL SYLLABLE CYAC +CC78;CC78;110E 1163 11BF;CC78;110E 1163 11BF; # (챸; 챸; 챸; 챸; 챸; ) HANGUL SYLLABLE CYAK +CC79;CC79;110E 1163 11C0;CC79;110E 1163 11C0; # (챹; 챹; 챹; 챹; 챹; ) HANGUL SYLLABLE CYAT +CC7A;CC7A;110E 1163 11C1;CC7A;110E 1163 11C1; # (챺; 챺; 챺; 챺; 챺; ) HANGUL SYLLABLE CYAP +CC7B;CC7B;110E 1163 11C2;CC7B;110E 1163 11C2; # (챻; 챻; 챻; 챻; 챻; ) HANGUL SYLLABLE CYAH +CC7C;CC7C;110E 1164;CC7C;110E 1164; # (챼; 챼; 챼; 챼; 챼; ) HANGUL SYLLABLE CYAE +CC7D;CC7D;110E 1164 11A8;CC7D;110E 1164 11A8; # (챽; 챽; 챽; 챽; 챽; ) HANGUL SYLLABLE CYAEG +CC7E;CC7E;110E 1164 11A9;CC7E;110E 1164 11A9; # (챾; 챾; 챾; 챾; 챾; ) HANGUL SYLLABLE CYAEGG +CC7F;CC7F;110E 1164 11AA;CC7F;110E 1164 11AA; # (챿; 챿; 챿; 챿; 챿; ) HANGUL SYLLABLE CYAEGS +CC80;CC80;110E 1164 11AB;CC80;110E 1164 11AB; # (첀; 첀; 첀; 첀; 첀; ) HANGUL SYLLABLE CYAEN +CC81;CC81;110E 1164 11AC;CC81;110E 1164 11AC; # (첁; 첁; 첁; 첁; 첁; ) HANGUL SYLLABLE CYAENJ +CC82;CC82;110E 1164 11AD;CC82;110E 1164 11AD; # (첂; 첂; 첂; 첂; 첂; ) HANGUL SYLLABLE CYAENH +CC83;CC83;110E 1164 11AE;CC83;110E 1164 11AE; # (첃; 첃; 첃; 첃; 첃; ) HANGUL SYLLABLE CYAED +CC84;CC84;110E 1164 11AF;CC84;110E 1164 11AF; # (첄; 첄; 첄; 첄; 첄; ) HANGUL SYLLABLE CYAEL +CC85;CC85;110E 1164 11B0;CC85;110E 1164 11B0; # (첅; 첅; 첅; 첅; 첅; ) HANGUL SYLLABLE CYAELG +CC86;CC86;110E 1164 11B1;CC86;110E 1164 11B1; # (첆; 첆; 첆; 첆; 첆; ) HANGUL SYLLABLE CYAELM +CC87;CC87;110E 1164 11B2;CC87;110E 1164 11B2; # (첇; 첇; 첇; 첇; 첇; ) HANGUL SYLLABLE CYAELB +CC88;CC88;110E 1164 11B3;CC88;110E 1164 11B3; # (첈; 첈; 첈; 첈; 첈; ) HANGUL SYLLABLE CYAELS +CC89;CC89;110E 1164 11B4;CC89;110E 1164 11B4; # (첉; 첉; 첉; 첉; 첉; ) HANGUL SYLLABLE CYAELT +CC8A;CC8A;110E 1164 11B5;CC8A;110E 1164 11B5; # (첊; 첊; 첊; 첊; 첊; ) HANGUL SYLLABLE CYAELP +CC8B;CC8B;110E 1164 11B6;CC8B;110E 1164 11B6; # (첋; 첋; 첋; 첋; 첋; ) HANGUL SYLLABLE CYAELH +CC8C;CC8C;110E 1164 11B7;CC8C;110E 1164 11B7; # (첌; 첌; 첌; 첌; 첌; ) HANGUL SYLLABLE CYAEM +CC8D;CC8D;110E 1164 11B8;CC8D;110E 1164 11B8; # (첍; 첍; 첍; 첍; 첍; ) HANGUL SYLLABLE CYAEB +CC8E;CC8E;110E 1164 11B9;CC8E;110E 1164 11B9; # (첎; 첎; 첎; 첎; 첎; ) HANGUL SYLLABLE CYAEBS +CC8F;CC8F;110E 1164 11BA;CC8F;110E 1164 11BA; # (첏; 첏; 첏; 첏; 첏; ) HANGUL SYLLABLE CYAES +CC90;CC90;110E 1164 11BB;CC90;110E 1164 11BB; # (첐; 첐; 첐; 첐; 첐; ) HANGUL SYLLABLE CYAESS +CC91;CC91;110E 1164 11BC;CC91;110E 1164 11BC; # (첑; 첑; 첑; 첑; 첑; ) HANGUL SYLLABLE CYAENG +CC92;CC92;110E 1164 11BD;CC92;110E 1164 11BD; # (첒; 첒; 첒; 첒; 첒; ) HANGUL SYLLABLE CYAEJ +CC93;CC93;110E 1164 11BE;CC93;110E 1164 11BE; # (첓; 첓; 첓; 첓; 첓; ) HANGUL SYLLABLE CYAEC +CC94;CC94;110E 1164 11BF;CC94;110E 1164 11BF; # (첔; 첔; 첔; 첔; 첔; ) HANGUL SYLLABLE CYAEK +CC95;CC95;110E 1164 11C0;CC95;110E 1164 11C0; # (첕; 첕; 첕; 첕; 첕; ) HANGUL SYLLABLE CYAET +CC96;CC96;110E 1164 11C1;CC96;110E 1164 11C1; # (첖; 첖; 첖; 첖; 첖; ) HANGUL SYLLABLE CYAEP +CC97;CC97;110E 1164 11C2;CC97;110E 1164 11C2; # (첗; 첗; 첗; 첗; 첗; ) HANGUL SYLLABLE CYAEH +CC98;CC98;110E 1165;CC98;110E 1165; # (처; 처; 처; 처; 처; ) HANGUL SYLLABLE CEO +CC99;CC99;110E 1165 11A8;CC99;110E 1165 11A8; # (척; 척; 척; 척; 척; ) HANGUL SYLLABLE CEOG +CC9A;CC9A;110E 1165 11A9;CC9A;110E 1165 11A9; # (첚; 첚; 첚; 첚; 첚; ) HANGUL SYLLABLE CEOGG +CC9B;CC9B;110E 1165 11AA;CC9B;110E 1165 11AA; # (첛; 첛; 첛; 첛; 첛; ) HANGUL SYLLABLE CEOGS +CC9C;CC9C;110E 1165 11AB;CC9C;110E 1165 11AB; # (천; 천; 천; 천; 천; ) HANGUL SYLLABLE CEON +CC9D;CC9D;110E 1165 11AC;CC9D;110E 1165 11AC; # (첝; 첝; 첝; 첝; 첝; ) HANGUL SYLLABLE CEONJ +CC9E;CC9E;110E 1165 11AD;CC9E;110E 1165 11AD; # (첞; 첞; 첞; 첞; 첞; ) HANGUL SYLLABLE CEONH +CC9F;CC9F;110E 1165 11AE;CC9F;110E 1165 11AE; # (첟; 첟; 첟; 첟; 첟; ) HANGUL SYLLABLE CEOD +CCA0;CCA0;110E 1165 11AF;CCA0;110E 1165 11AF; # (철; 철; 철; 철; 철; ) HANGUL SYLLABLE CEOL +CCA1;CCA1;110E 1165 11B0;CCA1;110E 1165 11B0; # (첡; 첡; 첡; 첡; 첡; ) HANGUL SYLLABLE CEOLG +CCA2;CCA2;110E 1165 11B1;CCA2;110E 1165 11B1; # (첢; 첢; 첢; 첢; 첢; ) HANGUL SYLLABLE CEOLM +CCA3;CCA3;110E 1165 11B2;CCA3;110E 1165 11B2; # (첣; 첣; 첣; 첣; 첣; ) HANGUL SYLLABLE CEOLB +CCA4;CCA4;110E 1165 11B3;CCA4;110E 1165 11B3; # (첤; 첤; 첤; 첤; 첤; ) HANGUL SYLLABLE CEOLS +CCA5;CCA5;110E 1165 11B4;CCA5;110E 1165 11B4; # (첥; 첥; 첥; 첥; 첥; ) HANGUL SYLLABLE CEOLT +CCA6;CCA6;110E 1165 11B5;CCA6;110E 1165 11B5; # (첦; 첦; 첦; 첦; 첦; ) HANGUL SYLLABLE CEOLP +CCA7;CCA7;110E 1165 11B6;CCA7;110E 1165 11B6; # (첧; 첧; 첧; 첧; 첧; ) HANGUL SYLLABLE CEOLH +CCA8;CCA8;110E 1165 11B7;CCA8;110E 1165 11B7; # (첨; 첨; 첨; 첨; 첨; ) HANGUL SYLLABLE CEOM +CCA9;CCA9;110E 1165 11B8;CCA9;110E 1165 11B8; # (첩; 첩; 첩; 첩; 첩; ) HANGUL SYLLABLE CEOB +CCAA;CCAA;110E 1165 11B9;CCAA;110E 1165 11B9; # (첪; 첪; 첪; 첪; 첪; ) HANGUL SYLLABLE CEOBS +CCAB;CCAB;110E 1165 11BA;CCAB;110E 1165 11BA; # (첫; 첫; 첫; 첫; 첫; ) HANGUL SYLLABLE CEOS +CCAC;CCAC;110E 1165 11BB;CCAC;110E 1165 11BB; # (첬; 첬; 첬; 첬; 첬; ) HANGUL SYLLABLE CEOSS +CCAD;CCAD;110E 1165 11BC;CCAD;110E 1165 11BC; # (청; 청; 청; 청; 청; ) HANGUL SYLLABLE CEONG +CCAE;CCAE;110E 1165 11BD;CCAE;110E 1165 11BD; # (첮; 첮; 첮; 첮; 첮; ) HANGUL SYLLABLE CEOJ +CCAF;CCAF;110E 1165 11BE;CCAF;110E 1165 11BE; # (첯; 첯; 첯; 첯; 첯; ) HANGUL SYLLABLE CEOC +CCB0;CCB0;110E 1165 11BF;CCB0;110E 1165 11BF; # (첰; 첰; 첰; 첰; 첰; ) HANGUL SYLLABLE CEOK +CCB1;CCB1;110E 1165 11C0;CCB1;110E 1165 11C0; # (첱; 첱; 첱; 첱; 첱; ) HANGUL SYLLABLE CEOT +CCB2;CCB2;110E 1165 11C1;CCB2;110E 1165 11C1; # (첲; 첲; 첲; 첲; 첲; ) HANGUL SYLLABLE CEOP +CCB3;CCB3;110E 1165 11C2;CCB3;110E 1165 11C2; # (첳; 첳; 첳; 첳; 첳; ) HANGUL SYLLABLE CEOH +CCB4;CCB4;110E 1166;CCB4;110E 1166; # (체; 체; 체; 체; 체; ) HANGUL SYLLABLE CE +CCB5;CCB5;110E 1166 11A8;CCB5;110E 1166 11A8; # (첵; 첵; 첵; 첵; 첵; ) HANGUL SYLLABLE CEG +CCB6;CCB6;110E 1166 11A9;CCB6;110E 1166 11A9; # (첶; 첶; 첶; 첶; 첶; ) HANGUL SYLLABLE CEGG +CCB7;CCB7;110E 1166 11AA;CCB7;110E 1166 11AA; # (첷; 첷; 첷; 첷; 첷; ) HANGUL SYLLABLE CEGS +CCB8;CCB8;110E 1166 11AB;CCB8;110E 1166 11AB; # (첸; 첸; 첸; 첸; 첸; ) HANGUL SYLLABLE CEN +CCB9;CCB9;110E 1166 11AC;CCB9;110E 1166 11AC; # (첹; 첹; 첹; 첹; 첹; ) HANGUL SYLLABLE CENJ +CCBA;CCBA;110E 1166 11AD;CCBA;110E 1166 11AD; # (첺; 첺; 첺; 첺; 첺; ) HANGUL SYLLABLE CENH +CCBB;CCBB;110E 1166 11AE;CCBB;110E 1166 11AE; # (첻; 첻; 첻; 첻; 첻; ) HANGUL SYLLABLE CED +CCBC;CCBC;110E 1166 11AF;CCBC;110E 1166 11AF; # (첼; 첼; 첼; 첼; 첼; ) HANGUL SYLLABLE CEL +CCBD;CCBD;110E 1166 11B0;CCBD;110E 1166 11B0; # (첽; 첽; 첽; 첽; 첽; ) HANGUL SYLLABLE CELG +CCBE;CCBE;110E 1166 11B1;CCBE;110E 1166 11B1; # (첾; 첾; 첾; 첾; 첾; ) HANGUL SYLLABLE CELM +CCBF;CCBF;110E 1166 11B2;CCBF;110E 1166 11B2; # (첿; 첿; 첿; 첿; 첿; ) HANGUL SYLLABLE CELB +CCC0;CCC0;110E 1166 11B3;CCC0;110E 1166 11B3; # (쳀; 쳀; 쳀; 쳀; 쳀; ) HANGUL SYLLABLE CELS +CCC1;CCC1;110E 1166 11B4;CCC1;110E 1166 11B4; # (쳁; 쳁; 쳁; 쳁; 쳁; ) HANGUL SYLLABLE CELT +CCC2;CCC2;110E 1166 11B5;CCC2;110E 1166 11B5; # (쳂; 쳂; 쳂; 쳂; 쳂; ) HANGUL SYLLABLE CELP +CCC3;CCC3;110E 1166 11B6;CCC3;110E 1166 11B6; # (쳃; 쳃; 쳃; 쳃; 쳃; ) HANGUL SYLLABLE CELH +CCC4;CCC4;110E 1166 11B7;CCC4;110E 1166 11B7; # (쳄; 쳄; 쳄; 쳄; 쳄; ) HANGUL SYLLABLE CEM +CCC5;CCC5;110E 1166 11B8;CCC5;110E 1166 11B8; # (쳅; 쳅; 쳅; 쳅; 쳅; ) HANGUL SYLLABLE CEB +CCC6;CCC6;110E 1166 11B9;CCC6;110E 1166 11B9; # (쳆; 쳆; 쳆; 쳆; 쳆; ) HANGUL SYLLABLE CEBS +CCC7;CCC7;110E 1166 11BA;CCC7;110E 1166 11BA; # (쳇; 쳇; 쳇; 쳇; 쳇; ) HANGUL SYLLABLE CES +CCC8;CCC8;110E 1166 11BB;CCC8;110E 1166 11BB; # (쳈; 쳈; 쳈; 쳈; 쳈; ) HANGUL SYLLABLE CESS +CCC9;CCC9;110E 1166 11BC;CCC9;110E 1166 11BC; # (쳉; 쳉; 쳉; 쳉; 쳉; ) HANGUL SYLLABLE CENG +CCCA;CCCA;110E 1166 11BD;CCCA;110E 1166 11BD; # (쳊; 쳊; 쳊; 쳊; 쳊; ) HANGUL SYLLABLE CEJ +CCCB;CCCB;110E 1166 11BE;CCCB;110E 1166 11BE; # (쳋; 쳋; 쳋; 쳋; 쳋; ) HANGUL SYLLABLE CEC +CCCC;CCCC;110E 1166 11BF;CCCC;110E 1166 11BF; # (쳌; 쳌; 쳌; 쳌; 쳌; ) HANGUL SYLLABLE CEK +CCCD;CCCD;110E 1166 11C0;CCCD;110E 1166 11C0; # (쳍; 쳍; 쳍; 쳍; 쳍; ) HANGUL SYLLABLE CET +CCCE;CCCE;110E 1166 11C1;CCCE;110E 1166 11C1; # (쳎; 쳎; 쳎; 쳎; 쳎; ) HANGUL SYLLABLE CEP +CCCF;CCCF;110E 1166 11C2;CCCF;110E 1166 11C2; # (쳏; 쳏; 쳏; 쳏; 쳏; ) HANGUL SYLLABLE CEH +CCD0;CCD0;110E 1167;CCD0;110E 1167; # (쳐; 쳐; 쳐; 쳐; 쳐; ) HANGUL SYLLABLE CYEO +CCD1;CCD1;110E 1167 11A8;CCD1;110E 1167 11A8; # (쳑; 쳑; 쳑; 쳑; 쳑; ) HANGUL SYLLABLE CYEOG +CCD2;CCD2;110E 1167 11A9;CCD2;110E 1167 11A9; # (쳒; 쳒; 쳒; 쳒; 쳒; ) HANGUL SYLLABLE CYEOGG +CCD3;CCD3;110E 1167 11AA;CCD3;110E 1167 11AA; # (쳓; 쳓; 쳓; 쳓; 쳓; ) HANGUL SYLLABLE CYEOGS +CCD4;CCD4;110E 1167 11AB;CCD4;110E 1167 11AB; # (쳔; 쳔; 쳔; 쳔; 쳔; ) HANGUL SYLLABLE CYEON +CCD5;CCD5;110E 1167 11AC;CCD5;110E 1167 11AC; # (쳕; 쳕; 쳕; 쳕; 쳕; ) HANGUL SYLLABLE CYEONJ +CCD6;CCD6;110E 1167 11AD;CCD6;110E 1167 11AD; # (쳖; 쳖; 쳖; 쳖; 쳖; ) HANGUL SYLLABLE CYEONH +CCD7;CCD7;110E 1167 11AE;CCD7;110E 1167 11AE; # (쳗; 쳗; 쳗; 쳗; 쳗; ) HANGUL SYLLABLE CYEOD +CCD8;CCD8;110E 1167 11AF;CCD8;110E 1167 11AF; # (쳘; 쳘; 쳘; 쳘; 쳘; ) HANGUL SYLLABLE CYEOL +CCD9;CCD9;110E 1167 11B0;CCD9;110E 1167 11B0; # (쳙; 쳙; 쳙; 쳙; 쳙; ) HANGUL SYLLABLE CYEOLG +CCDA;CCDA;110E 1167 11B1;CCDA;110E 1167 11B1; # (쳚; 쳚; 쳚; 쳚; 쳚; ) HANGUL SYLLABLE CYEOLM +CCDB;CCDB;110E 1167 11B2;CCDB;110E 1167 11B2; # (쳛; 쳛; 쳛; 쳛; 쳛; ) HANGUL SYLLABLE CYEOLB +CCDC;CCDC;110E 1167 11B3;CCDC;110E 1167 11B3; # (쳜; 쳜; 쳜; 쳜; 쳜; ) HANGUL SYLLABLE CYEOLS +CCDD;CCDD;110E 1167 11B4;CCDD;110E 1167 11B4; # (쳝; 쳝; 쳝; 쳝; 쳝; ) HANGUL SYLLABLE CYEOLT +CCDE;CCDE;110E 1167 11B5;CCDE;110E 1167 11B5; # (쳞; 쳞; 쳞; 쳞; 쳞; ) HANGUL SYLLABLE CYEOLP +CCDF;CCDF;110E 1167 11B6;CCDF;110E 1167 11B6; # (쳟; 쳟; 쳟; 쳟; 쳟; ) HANGUL SYLLABLE CYEOLH +CCE0;CCE0;110E 1167 11B7;CCE0;110E 1167 11B7; # (쳠; 쳠; 쳠; 쳠; 쳠; ) HANGUL SYLLABLE CYEOM +CCE1;CCE1;110E 1167 11B8;CCE1;110E 1167 11B8; # (쳡; 쳡; 쳡; 쳡; 쳡; ) HANGUL SYLLABLE CYEOB +CCE2;CCE2;110E 1167 11B9;CCE2;110E 1167 11B9; # (쳢; 쳢; 쳢; 쳢; 쳢; ) HANGUL SYLLABLE CYEOBS +CCE3;CCE3;110E 1167 11BA;CCE3;110E 1167 11BA; # (쳣; 쳣; 쳣; 쳣; 쳣; ) HANGUL SYLLABLE CYEOS +CCE4;CCE4;110E 1167 11BB;CCE4;110E 1167 11BB; # (쳤; 쳤; 쳤; 쳤; 쳤; ) HANGUL SYLLABLE CYEOSS +CCE5;CCE5;110E 1167 11BC;CCE5;110E 1167 11BC; # (쳥; 쳥; 쳥; 쳥; 쳥; ) HANGUL SYLLABLE CYEONG +CCE6;CCE6;110E 1167 11BD;CCE6;110E 1167 11BD; # (쳦; 쳦; 쳦; 쳦; 쳦; ) HANGUL SYLLABLE CYEOJ +CCE7;CCE7;110E 1167 11BE;CCE7;110E 1167 11BE; # (쳧; 쳧; 쳧; 쳧; 쳧; ) HANGUL SYLLABLE CYEOC +CCE8;CCE8;110E 1167 11BF;CCE8;110E 1167 11BF; # (쳨; 쳨; 쳨; 쳨; 쳨; ) HANGUL SYLLABLE CYEOK +CCE9;CCE9;110E 1167 11C0;CCE9;110E 1167 11C0; # (쳩; 쳩; 쳩; 쳩; 쳩; ) HANGUL SYLLABLE CYEOT +CCEA;CCEA;110E 1167 11C1;CCEA;110E 1167 11C1; # (쳪; 쳪; 쳪; 쳪; 쳪; ) HANGUL SYLLABLE CYEOP +CCEB;CCEB;110E 1167 11C2;CCEB;110E 1167 11C2; # (쳫; 쳫; 쳫; 쳫; 쳫; ) HANGUL SYLLABLE CYEOH +CCEC;CCEC;110E 1168;CCEC;110E 1168; # (쳬; 쳬; 쳬; 쳬; 쳬; ) HANGUL SYLLABLE CYE +CCED;CCED;110E 1168 11A8;CCED;110E 1168 11A8; # (쳭; 쳭; 쳭; 쳭; 쳭; ) HANGUL SYLLABLE CYEG +CCEE;CCEE;110E 1168 11A9;CCEE;110E 1168 11A9; # (쳮; 쳮; 쳮; 쳮; 쳮; ) HANGUL SYLLABLE CYEGG +CCEF;CCEF;110E 1168 11AA;CCEF;110E 1168 11AA; # (쳯; 쳯; 쳯; 쳯; 쳯; ) HANGUL SYLLABLE CYEGS +CCF0;CCF0;110E 1168 11AB;CCF0;110E 1168 11AB; # (쳰; 쳰; 쳰; 쳰; 쳰; ) HANGUL SYLLABLE CYEN +CCF1;CCF1;110E 1168 11AC;CCF1;110E 1168 11AC; # (쳱; 쳱; 쳱; 쳱; 쳱; ) HANGUL SYLLABLE CYENJ +CCF2;CCF2;110E 1168 11AD;CCF2;110E 1168 11AD; # (쳲; 쳲; 쳲; 쳲; 쳲; ) HANGUL SYLLABLE CYENH +CCF3;CCF3;110E 1168 11AE;CCF3;110E 1168 11AE; # (쳳; 쳳; 쳳; 쳳; 쳳; ) HANGUL SYLLABLE CYED +CCF4;CCF4;110E 1168 11AF;CCF4;110E 1168 11AF; # (쳴; 쳴; 쳴; 쳴; 쳴; ) HANGUL SYLLABLE CYEL +CCF5;CCF5;110E 1168 11B0;CCF5;110E 1168 11B0; # (쳵; 쳵; 쳵; 쳵; 쳵; ) HANGUL SYLLABLE CYELG +CCF6;CCF6;110E 1168 11B1;CCF6;110E 1168 11B1; # (쳶; 쳶; 쳶; 쳶; 쳶; ) HANGUL SYLLABLE CYELM +CCF7;CCF7;110E 1168 11B2;CCF7;110E 1168 11B2; # (쳷; 쳷; 쳷; 쳷; 쳷; ) HANGUL SYLLABLE CYELB +CCF8;CCF8;110E 1168 11B3;CCF8;110E 1168 11B3; # (쳸; 쳸; 쳸; 쳸; 쳸; ) HANGUL SYLLABLE CYELS +CCF9;CCF9;110E 1168 11B4;CCF9;110E 1168 11B4; # (쳹; 쳹; 쳹; 쳹; 쳹; ) HANGUL SYLLABLE CYELT +CCFA;CCFA;110E 1168 11B5;CCFA;110E 1168 11B5; # (쳺; 쳺; 쳺; 쳺; 쳺; ) HANGUL SYLLABLE CYELP +CCFB;CCFB;110E 1168 11B6;CCFB;110E 1168 11B6; # (쳻; 쳻; 쳻; 쳻; 쳻; ) HANGUL SYLLABLE CYELH +CCFC;CCFC;110E 1168 11B7;CCFC;110E 1168 11B7; # (쳼; 쳼; 쳼; 쳼; 쳼; ) HANGUL SYLLABLE CYEM +CCFD;CCFD;110E 1168 11B8;CCFD;110E 1168 11B8; # (쳽; 쳽; 쳽; 쳽; 쳽; ) HANGUL SYLLABLE CYEB +CCFE;CCFE;110E 1168 11B9;CCFE;110E 1168 11B9; # (쳾; 쳾; 쳾; 쳾; 쳾; ) HANGUL SYLLABLE CYEBS +CCFF;CCFF;110E 1168 11BA;CCFF;110E 1168 11BA; # (쳿; 쳿; 쳿; 쳿; 쳿; ) HANGUL SYLLABLE CYES +CD00;CD00;110E 1168 11BB;CD00;110E 1168 11BB; # (촀; 촀; 촀; 촀; 촀; ) HANGUL SYLLABLE CYESS +CD01;CD01;110E 1168 11BC;CD01;110E 1168 11BC; # (촁; 촁; 촁; 촁; 촁; ) HANGUL SYLLABLE CYENG +CD02;CD02;110E 1168 11BD;CD02;110E 1168 11BD; # (촂; 촂; 촂; 촂; 촂; ) HANGUL SYLLABLE CYEJ +CD03;CD03;110E 1168 11BE;CD03;110E 1168 11BE; # (촃; 촃; 촃; 촃; 촃; ) HANGUL SYLLABLE CYEC +CD04;CD04;110E 1168 11BF;CD04;110E 1168 11BF; # (촄; 촄; 촄; 촄; 촄; ) HANGUL SYLLABLE CYEK +CD05;CD05;110E 1168 11C0;CD05;110E 1168 11C0; # (촅; 촅; 촅; 촅; 촅; ) HANGUL SYLLABLE CYET +CD06;CD06;110E 1168 11C1;CD06;110E 1168 11C1; # (촆; 촆; 촆; 촆; 촆; ) HANGUL SYLLABLE CYEP +CD07;CD07;110E 1168 11C2;CD07;110E 1168 11C2; # (촇; 촇; 촇; 촇; 촇; ) HANGUL SYLLABLE CYEH +CD08;CD08;110E 1169;CD08;110E 1169; # (초; 초; 초; 초; 초; ) HANGUL SYLLABLE CO +CD09;CD09;110E 1169 11A8;CD09;110E 1169 11A8; # (촉; 촉; 촉; 촉; 촉; ) HANGUL SYLLABLE COG +CD0A;CD0A;110E 1169 11A9;CD0A;110E 1169 11A9; # (촊; 촊; 촊; 촊; 촊; ) HANGUL SYLLABLE COGG +CD0B;CD0B;110E 1169 11AA;CD0B;110E 1169 11AA; # (촋; 촋; 촋; 촋; 촋; ) HANGUL SYLLABLE COGS +CD0C;CD0C;110E 1169 11AB;CD0C;110E 1169 11AB; # (촌; 촌; 촌; 촌; 촌; ) HANGUL SYLLABLE CON +CD0D;CD0D;110E 1169 11AC;CD0D;110E 1169 11AC; # (촍; 촍; 촍; 촍; 촍; ) HANGUL SYLLABLE CONJ +CD0E;CD0E;110E 1169 11AD;CD0E;110E 1169 11AD; # (촎; 촎; 촎; 촎; 촎; ) HANGUL SYLLABLE CONH +CD0F;CD0F;110E 1169 11AE;CD0F;110E 1169 11AE; # (촏; 촏; 촏; 촏; 촏; ) HANGUL SYLLABLE COD +CD10;CD10;110E 1169 11AF;CD10;110E 1169 11AF; # (촐; 촐; 촐; 촐; 촐; ) HANGUL SYLLABLE COL +CD11;CD11;110E 1169 11B0;CD11;110E 1169 11B0; # (촑; 촑; 촑; 촑; 촑; ) HANGUL SYLLABLE COLG +CD12;CD12;110E 1169 11B1;CD12;110E 1169 11B1; # (촒; 촒; 촒; 촒; 촒; ) HANGUL SYLLABLE COLM +CD13;CD13;110E 1169 11B2;CD13;110E 1169 11B2; # (촓; 촓; 촓; 촓; 촓; ) HANGUL SYLLABLE COLB +CD14;CD14;110E 1169 11B3;CD14;110E 1169 11B3; # (촔; 촔; 촔; 촔; 촔; ) HANGUL SYLLABLE COLS +CD15;CD15;110E 1169 11B4;CD15;110E 1169 11B4; # (촕; 촕; 촕; 촕; 촕; ) HANGUL SYLLABLE COLT +CD16;CD16;110E 1169 11B5;CD16;110E 1169 11B5; # (촖; 촖; 촖; 촖; 촖; ) HANGUL SYLLABLE COLP +CD17;CD17;110E 1169 11B6;CD17;110E 1169 11B6; # (촗; 촗; 촗; 촗; 촗; ) HANGUL SYLLABLE COLH +CD18;CD18;110E 1169 11B7;CD18;110E 1169 11B7; # (촘; 촘; 촘; 촘; 촘; ) HANGUL SYLLABLE COM +CD19;CD19;110E 1169 11B8;CD19;110E 1169 11B8; # (촙; 촙; 촙; 촙; 촙; ) HANGUL SYLLABLE COB +CD1A;CD1A;110E 1169 11B9;CD1A;110E 1169 11B9; # (촚; 촚; 촚; 촚; 촚; ) HANGUL SYLLABLE COBS +CD1B;CD1B;110E 1169 11BA;CD1B;110E 1169 11BA; # (촛; 촛; 촛; 촛; 촛; ) HANGUL SYLLABLE COS +CD1C;CD1C;110E 1169 11BB;CD1C;110E 1169 11BB; # (촜; 촜; 촜; 촜; 촜; ) HANGUL SYLLABLE COSS +CD1D;CD1D;110E 1169 11BC;CD1D;110E 1169 11BC; # (총; 총; 총; 총; 총; ) HANGUL SYLLABLE CONG +CD1E;CD1E;110E 1169 11BD;CD1E;110E 1169 11BD; # (촞; 촞; 촞; 촞; 촞; ) HANGUL SYLLABLE COJ +CD1F;CD1F;110E 1169 11BE;CD1F;110E 1169 11BE; # (촟; 촟; 촟; 촟; 촟; ) HANGUL SYLLABLE COC +CD20;CD20;110E 1169 11BF;CD20;110E 1169 11BF; # (촠; 촠; 촠; 촠; 촠; ) HANGUL SYLLABLE COK +CD21;CD21;110E 1169 11C0;CD21;110E 1169 11C0; # (촡; 촡; 촡; 촡; 촡; ) HANGUL SYLLABLE COT +CD22;CD22;110E 1169 11C1;CD22;110E 1169 11C1; # (촢; 촢; 촢; 촢; 촢; ) HANGUL SYLLABLE COP +CD23;CD23;110E 1169 11C2;CD23;110E 1169 11C2; # (촣; 촣; 촣; 촣; 촣; ) HANGUL SYLLABLE COH +CD24;CD24;110E 116A;CD24;110E 116A; # (촤; 촤; 촤; 촤; 촤; ) HANGUL SYLLABLE CWA +CD25;CD25;110E 116A 11A8;CD25;110E 116A 11A8; # (촥; 촥; 촥; 촥; 촥; ) HANGUL SYLLABLE CWAG +CD26;CD26;110E 116A 11A9;CD26;110E 116A 11A9; # (촦; 촦; 촦; 촦; 촦; ) HANGUL SYLLABLE CWAGG +CD27;CD27;110E 116A 11AA;CD27;110E 116A 11AA; # (촧; 촧; 촧; 촧; 촧; ) HANGUL SYLLABLE CWAGS +CD28;CD28;110E 116A 11AB;CD28;110E 116A 11AB; # (촨; 촨; 촨; 촨; 촨; ) HANGUL SYLLABLE CWAN +CD29;CD29;110E 116A 11AC;CD29;110E 116A 11AC; # (촩; 촩; 촩; 촩; 촩; ) HANGUL SYLLABLE CWANJ +CD2A;CD2A;110E 116A 11AD;CD2A;110E 116A 11AD; # (촪; 촪; 촪; 촪; 촪; ) HANGUL SYLLABLE CWANH +CD2B;CD2B;110E 116A 11AE;CD2B;110E 116A 11AE; # (촫; 촫; 촫; 촫; 촫; ) HANGUL SYLLABLE CWAD +CD2C;CD2C;110E 116A 11AF;CD2C;110E 116A 11AF; # (촬; 촬; 촬; 촬; 촬; ) HANGUL SYLLABLE CWAL +CD2D;CD2D;110E 116A 11B0;CD2D;110E 116A 11B0; # (촭; 촭; 촭; 촭; 촭; ) HANGUL SYLLABLE CWALG +CD2E;CD2E;110E 116A 11B1;CD2E;110E 116A 11B1; # (촮; 촮; 촮; 촮; 촮; ) HANGUL SYLLABLE CWALM +CD2F;CD2F;110E 116A 11B2;CD2F;110E 116A 11B2; # (촯; 촯; 촯; 촯; 촯; ) HANGUL SYLLABLE CWALB +CD30;CD30;110E 116A 11B3;CD30;110E 116A 11B3; # (촰; 촰; 촰; 촰; 촰; ) HANGUL SYLLABLE CWALS +CD31;CD31;110E 116A 11B4;CD31;110E 116A 11B4; # (촱; 촱; 촱; 촱; 촱; ) HANGUL SYLLABLE CWALT +CD32;CD32;110E 116A 11B5;CD32;110E 116A 11B5; # (촲; 촲; 촲; 촲; 촲; ) HANGUL SYLLABLE CWALP +CD33;CD33;110E 116A 11B6;CD33;110E 116A 11B6; # (촳; 촳; 촳; 촳; 촳; ) HANGUL SYLLABLE CWALH +CD34;CD34;110E 116A 11B7;CD34;110E 116A 11B7; # (촴; 촴; 촴; 촴; 촴; ) HANGUL SYLLABLE CWAM +CD35;CD35;110E 116A 11B8;CD35;110E 116A 11B8; # (촵; 촵; 촵; 촵; 촵; ) HANGUL SYLLABLE CWAB +CD36;CD36;110E 116A 11B9;CD36;110E 116A 11B9; # (촶; 촶; 촶; 촶; 촶; ) HANGUL SYLLABLE CWABS +CD37;CD37;110E 116A 11BA;CD37;110E 116A 11BA; # (촷; 촷; 촷; 촷; 촷; ) HANGUL SYLLABLE CWAS +CD38;CD38;110E 116A 11BB;CD38;110E 116A 11BB; # (촸; 촸; 촸; 촸; 촸; ) HANGUL SYLLABLE CWASS +CD39;CD39;110E 116A 11BC;CD39;110E 116A 11BC; # (촹; 촹; 촹; 촹; 촹; ) HANGUL SYLLABLE CWANG +CD3A;CD3A;110E 116A 11BD;CD3A;110E 116A 11BD; # (촺; 촺; 촺; 촺; 촺; ) HANGUL SYLLABLE CWAJ +CD3B;CD3B;110E 116A 11BE;CD3B;110E 116A 11BE; # (촻; 촻; 촻; 촻; 촻; ) HANGUL SYLLABLE CWAC +CD3C;CD3C;110E 116A 11BF;CD3C;110E 116A 11BF; # (촼; 촼; 촼; 촼; 촼; ) HANGUL SYLLABLE CWAK +CD3D;CD3D;110E 116A 11C0;CD3D;110E 116A 11C0; # (촽; 촽; 촽; 촽; 촽; ) HANGUL SYLLABLE CWAT +CD3E;CD3E;110E 116A 11C1;CD3E;110E 116A 11C1; # (촾; 촾; 촾; 촾; 촾; ) HANGUL SYLLABLE CWAP +CD3F;CD3F;110E 116A 11C2;CD3F;110E 116A 11C2; # (촿; 촿; 촿; 촿; 촿; ) HANGUL SYLLABLE CWAH +CD40;CD40;110E 116B;CD40;110E 116B; # (쵀; 쵀; 쵀; 쵀; 쵀; ) HANGUL SYLLABLE CWAE +CD41;CD41;110E 116B 11A8;CD41;110E 116B 11A8; # (쵁; 쵁; 쵁; 쵁; 쵁; ) HANGUL SYLLABLE CWAEG +CD42;CD42;110E 116B 11A9;CD42;110E 116B 11A9; # (쵂; 쵂; 쵂; 쵂; 쵂; ) HANGUL SYLLABLE CWAEGG +CD43;CD43;110E 116B 11AA;CD43;110E 116B 11AA; # (쵃; 쵃; 쵃; 쵃; 쵃; ) HANGUL SYLLABLE CWAEGS +CD44;CD44;110E 116B 11AB;CD44;110E 116B 11AB; # (쵄; 쵄; 쵄; 쵄; 쵄; ) HANGUL SYLLABLE CWAEN +CD45;CD45;110E 116B 11AC;CD45;110E 116B 11AC; # (쵅; 쵅; 쵅; 쵅; 쵅; ) HANGUL SYLLABLE CWAENJ +CD46;CD46;110E 116B 11AD;CD46;110E 116B 11AD; # (쵆; 쵆; 쵆; 쵆; 쵆; ) HANGUL SYLLABLE CWAENH +CD47;CD47;110E 116B 11AE;CD47;110E 116B 11AE; # (쵇; 쵇; 쵇; 쵇; 쵇; ) HANGUL SYLLABLE CWAED +CD48;CD48;110E 116B 11AF;CD48;110E 116B 11AF; # (쵈; 쵈; 쵈; 쵈; 쵈; ) HANGUL SYLLABLE CWAEL +CD49;CD49;110E 116B 11B0;CD49;110E 116B 11B0; # (쵉; 쵉; 쵉; 쵉; 쵉; ) HANGUL SYLLABLE CWAELG +CD4A;CD4A;110E 116B 11B1;CD4A;110E 116B 11B1; # (쵊; 쵊; 쵊; 쵊; 쵊; ) HANGUL SYLLABLE CWAELM +CD4B;CD4B;110E 116B 11B2;CD4B;110E 116B 11B2; # (쵋; 쵋; 쵋; 쵋; 쵋; ) HANGUL SYLLABLE CWAELB +CD4C;CD4C;110E 116B 11B3;CD4C;110E 116B 11B3; # (쵌; 쵌; 쵌; 쵌; 쵌; ) HANGUL SYLLABLE CWAELS +CD4D;CD4D;110E 116B 11B4;CD4D;110E 116B 11B4; # (쵍; 쵍; 쵍; 쵍; 쵍; ) HANGUL SYLLABLE CWAELT +CD4E;CD4E;110E 116B 11B5;CD4E;110E 116B 11B5; # (쵎; 쵎; 쵎; 쵎; 쵎; ) HANGUL SYLLABLE CWAELP +CD4F;CD4F;110E 116B 11B6;CD4F;110E 116B 11B6; # (쵏; 쵏; 쵏; 쵏; 쵏; ) HANGUL SYLLABLE CWAELH +CD50;CD50;110E 116B 11B7;CD50;110E 116B 11B7; # (쵐; 쵐; 쵐; 쵐; 쵐; ) HANGUL SYLLABLE CWAEM +CD51;CD51;110E 116B 11B8;CD51;110E 116B 11B8; # (쵑; 쵑; 쵑; 쵑; 쵑; ) HANGUL SYLLABLE CWAEB +CD52;CD52;110E 116B 11B9;CD52;110E 116B 11B9; # (쵒; 쵒; 쵒; 쵒; 쵒; ) HANGUL SYLLABLE CWAEBS +CD53;CD53;110E 116B 11BA;CD53;110E 116B 11BA; # (쵓; 쵓; 쵓; 쵓; 쵓; ) HANGUL SYLLABLE CWAES +CD54;CD54;110E 116B 11BB;CD54;110E 116B 11BB; # (쵔; 쵔; 쵔; 쵔; 쵔; ) HANGUL SYLLABLE CWAESS +CD55;CD55;110E 116B 11BC;CD55;110E 116B 11BC; # (쵕; 쵕; 쵕; 쵕; 쵕; ) HANGUL SYLLABLE CWAENG +CD56;CD56;110E 116B 11BD;CD56;110E 116B 11BD; # (쵖; 쵖; 쵖; 쵖; 쵖; ) HANGUL SYLLABLE CWAEJ +CD57;CD57;110E 116B 11BE;CD57;110E 116B 11BE; # (쵗; 쵗; 쵗; 쵗; 쵗; ) HANGUL SYLLABLE CWAEC +CD58;CD58;110E 116B 11BF;CD58;110E 116B 11BF; # (쵘; 쵘; 쵘; 쵘; 쵘; ) HANGUL SYLLABLE CWAEK +CD59;CD59;110E 116B 11C0;CD59;110E 116B 11C0; # (쵙; 쵙; 쵙; 쵙; 쵙; ) HANGUL SYLLABLE CWAET +CD5A;CD5A;110E 116B 11C1;CD5A;110E 116B 11C1; # (쵚; 쵚; 쵚; 쵚; 쵚; ) HANGUL SYLLABLE CWAEP +CD5B;CD5B;110E 116B 11C2;CD5B;110E 116B 11C2; # (쵛; 쵛; 쵛; 쵛; 쵛; ) HANGUL SYLLABLE CWAEH +CD5C;CD5C;110E 116C;CD5C;110E 116C; # (최; 최; 최; 최; 최; ) HANGUL SYLLABLE COE +CD5D;CD5D;110E 116C 11A8;CD5D;110E 116C 11A8; # (쵝; 쵝; 쵝; 쵝; 쵝; ) HANGUL SYLLABLE COEG +CD5E;CD5E;110E 116C 11A9;CD5E;110E 116C 11A9; # (쵞; 쵞; 쵞; 쵞; 쵞; ) HANGUL SYLLABLE COEGG +CD5F;CD5F;110E 116C 11AA;CD5F;110E 116C 11AA; # (쵟; 쵟; 쵟; 쵟; 쵟; ) HANGUL SYLLABLE COEGS +CD60;CD60;110E 116C 11AB;CD60;110E 116C 11AB; # (쵠; 쵠; 쵠; 쵠; 쵠; ) HANGUL SYLLABLE COEN +CD61;CD61;110E 116C 11AC;CD61;110E 116C 11AC; # (쵡; 쵡; 쵡; 쵡; 쵡; ) HANGUL SYLLABLE COENJ +CD62;CD62;110E 116C 11AD;CD62;110E 116C 11AD; # (쵢; 쵢; 쵢; 쵢; 쵢; ) HANGUL SYLLABLE COENH +CD63;CD63;110E 116C 11AE;CD63;110E 116C 11AE; # (쵣; 쵣; 쵣; 쵣; 쵣; ) HANGUL SYLLABLE COED +CD64;CD64;110E 116C 11AF;CD64;110E 116C 11AF; # (쵤; 쵤; 쵤; 쵤; 쵤; ) HANGUL SYLLABLE COEL +CD65;CD65;110E 116C 11B0;CD65;110E 116C 11B0; # (쵥; 쵥; 쵥; 쵥; 쵥; ) HANGUL SYLLABLE COELG +CD66;CD66;110E 116C 11B1;CD66;110E 116C 11B1; # (쵦; 쵦; 쵦; 쵦; 쵦; ) HANGUL SYLLABLE COELM +CD67;CD67;110E 116C 11B2;CD67;110E 116C 11B2; # (쵧; 쵧; 쵧; 쵧; 쵧; ) HANGUL SYLLABLE COELB +CD68;CD68;110E 116C 11B3;CD68;110E 116C 11B3; # (쵨; 쵨; 쵨; 쵨; 쵨; ) HANGUL SYLLABLE COELS +CD69;CD69;110E 116C 11B4;CD69;110E 116C 11B4; # (쵩; 쵩; 쵩; 쵩; 쵩; ) HANGUL SYLLABLE COELT +CD6A;CD6A;110E 116C 11B5;CD6A;110E 116C 11B5; # (쵪; 쵪; 쵪; 쵪; 쵪; ) HANGUL SYLLABLE COELP +CD6B;CD6B;110E 116C 11B6;CD6B;110E 116C 11B6; # (쵫; 쵫; 쵫; 쵫; 쵫; ) HANGUL SYLLABLE COELH +CD6C;CD6C;110E 116C 11B7;CD6C;110E 116C 11B7; # (쵬; 쵬; 쵬; 쵬; 쵬; ) HANGUL SYLLABLE COEM +CD6D;CD6D;110E 116C 11B8;CD6D;110E 116C 11B8; # (쵭; 쵭; 쵭; 쵭; 쵭; ) HANGUL SYLLABLE COEB +CD6E;CD6E;110E 116C 11B9;CD6E;110E 116C 11B9; # (쵮; 쵮; 쵮; 쵮; 쵮; ) HANGUL SYLLABLE COEBS +CD6F;CD6F;110E 116C 11BA;CD6F;110E 116C 11BA; # (쵯; 쵯; 쵯; 쵯; 쵯; ) HANGUL SYLLABLE COES +CD70;CD70;110E 116C 11BB;CD70;110E 116C 11BB; # (쵰; 쵰; 쵰; 쵰; 쵰; ) HANGUL SYLLABLE COESS +CD71;CD71;110E 116C 11BC;CD71;110E 116C 11BC; # (쵱; 쵱; 쵱; 쵱; 쵱; ) HANGUL SYLLABLE COENG +CD72;CD72;110E 116C 11BD;CD72;110E 116C 11BD; # (쵲; 쵲; 쵲; 쵲; 쵲; ) HANGUL SYLLABLE COEJ +CD73;CD73;110E 116C 11BE;CD73;110E 116C 11BE; # (쵳; 쵳; 쵳; 쵳; 쵳; ) HANGUL SYLLABLE COEC +CD74;CD74;110E 116C 11BF;CD74;110E 116C 11BF; # (쵴; 쵴; 쵴; 쵴; 쵴; ) HANGUL SYLLABLE COEK +CD75;CD75;110E 116C 11C0;CD75;110E 116C 11C0; # (쵵; 쵵; 쵵; 쵵; 쵵; ) HANGUL SYLLABLE COET +CD76;CD76;110E 116C 11C1;CD76;110E 116C 11C1; # (쵶; 쵶; 쵶; 쵶; 쵶; ) HANGUL SYLLABLE COEP +CD77;CD77;110E 116C 11C2;CD77;110E 116C 11C2; # (쵷; 쵷; 쵷; 쵷; 쵷; ) HANGUL SYLLABLE COEH +CD78;CD78;110E 116D;CD78;110E 116D; # (쵸; 쵸; 쵸; 쵸; 쵸; ) HANGUL SYLLABLE CYO +CD79;CD79;110E 116D 11A8;CD79;110E 116D 11A8; # (쵹; 쵹; 쵹; 쵹; 쵹; ) HANGUL SYLLABLE CYOG +CD7A;CD7A;110E 116D 11A9;CD7A;110E 116D 11A9; # (쵺; 쵺; 쵺; 쵺; 쵺; ) HANGUL SYLLABLE CYOGG +CD7B;CD7B;110E 116D 11AA;CD7B;110E 116D 11AA; # (쵻; 쵻; 쵻; 쵻; 쵻; ) HANGUL SYLLABLE CYOGS +CD7C;CD7C;110E 116D 11AB;CD7C;110E 116D 11AB; # (쵼; 쵼; 쵼; 쵼; 쵼; ) HANGUL SYLLABLE CYON +CD7D;CD7D;110E 116D 11AC;CD7D;110E 116D 11AC; # (쵽; 쵽; 쵽; 쵽; 쵽; ) HANGUL SYLLABLE CYONJ +CD7E;CD7E;110E 116D 11AD;CD7E;110E 116D 11AD; # (쵾; 쵾; 쵾; 쵾; 쵾; ) HANGUL SYLLABLE CYONH +CD7F;CD7F;110E 116D 11AE;CD7F;110E 116D 11AE; # (쵿; 쵿; 쵿; 쵿; 쵿; ) HANGUL SYLLABLE CYOD +CD80;CD80;110E 116D 11AF;CD80;110E 116D 11AF; # (춀; 춀; 춀; 춀; 춀; ) HANGUL SYLLABLE CYOL +CD81;CD81;110E 116D 11B0;CD81;110E 116D 11B0; # (춁; 춁; 춁; 춁; 춁; ) HANGUL SYLLABLE CYOLG +CD82;CD82;110E 116D 11B1;CD82;110E 116D 11B1; # (춂; 춂; 춂; 춂; 춂; ) HANGUL SYLLABLE CYOLM +CD83;CD83;110E 116D 11B2;CD83;110E 116D 11B2; # (춃; 춃; 춃; 춃; 춃; ) HANGUL SYLLABLE CYOLB +CD84;CD84;110E 116D 11B3;CD84;110E 116D 11B3; # (춄; 춄; 춄; 춄; 춄; ) HANGUL SYLLABLE CYOLS +CD85;CD85;110E 116D 11B4;CD85;110E 116D 11B4; # (춅; 춅; 춅; 춅; 춅; ) HANGUL SYLLABLE CYOLT +CD86;CD86;110E 116D 11B5;CD86;110E 116D 11B5; # (춆; 춆; 춆; 춆; 춆; ) HANGUL SYLLABLE CYOLP +CD87;CD87;110E 116D 11B6;CD87;110E 116D 11B6; # (춇; 춇; 춇; 춇; 춇; ) HANGUL SYLLABLE CYOLH +CD88;CD88;110E 116D 11B7;CD88;110E 116D 11B7; # (춈; 춈; 춈; 춈; 춈; ) HANGUL SYLLABLE CYOM +CD89;CD89;110E 116D 11B8;CD89;110E 116D 11B8; # (춉; 춉; 춉; 춉; 춉; ) HANGUL SYLLABLE CYOB +CD8A;CD8A;110E 116D 11B9;CD8A;110E 116D 11B9; # (춊; 춊; 춊; 춊; 춊; ) HANGUL SYLLABLE CYOBS +CD8B;CD8B;110E 116D 11BA;CD8B;110E 116D 11BA; # (춋; 춋; 춋; 춋; 춋; ) HANGUL SYLLABLE CYOS +CD8C;CD8C;110E 116D 11BB;CD8C;110E 116D 11BB; # (춌; 춌; 춌; 춌; 춌; ) HANGUL SYLLABLE CYOSS +CD8D;CD8D;110E 116D 11BC;CD8D;110E 116D 11BC; # (춍; 춍; 춍; 춍; 춍; ) HANGUL SYLLABLE CYONG +CD8E;CD8E;110E 116D 11BD;CD8E;110E 116D 11BD; # (춎; 춎; 춎; 춎; 춎; ) HANGUL SYLLABLE CYOJ +CD8F;CD8F;110E 116D 11BE;CD8F;110E 116D 11BE; # (춏; 춏; 춏; 춏; 춏; ) HANGUL SYLLABLE CYOC +CD90;CD90;110E 116D 11BF;CD90;110E 116D 11BF; # (춐; 춐; 춐; 춐; 춐; ) HANGUL SYLLABLE CYOK +CD91;CD91;110E 116D 11C0;CD91;110E 116D 11C0; # (춑; 춑; 춑; 춑; 춑; ) HANGUL SYLLABLE CYOT +CD92;CD92;110E 116D 11C1;CD92;110E 116D 11C1; # (춒; 춒; 춒; 춒; 춒; ) HANGUL SYLLABLE CYOP +CD93;CD93;110E 116D 11C2;CD93;110E 116D 11C2; # (춓; 춓; 춓; 춓; 춓; ) HANGUL SYLLABLE CYOH +CD94;CD94;110E 116E;CD94;110E 116E; # (추; 추; 추; 추; 추; ) HANGUL SYLLABLE CU +CD95;CD95;110E 116E 11A8;CD95;110E 116E 11A8; # (축; 축; 축; 축; 축; ) HANGUL SYLLABLE CUG +CD96;CD96;110E 116E 11A9;CD96;110E 116E 11A9; # (춖; 춖; 춖; 춖; 춖; ) HANGUL SYLLABLE CUGG +CD97;CD97;110E 116E 11AA;CD97;110E 116E 11AA; # (춗; 춗; 춗; 춗; 춗; ) HANGUL SYLLABLE CUGS +CD98;CD98;110E 116E 11AB;CD98;110E 116E 11AB; # (춘; 춘; 춘; 춘; 춘; ) HANGUL SYLLABLE CUN +CD99;CD99;110E 116E 11AC;CD99;110E 116E 11AC; # (춙; 춙; 춙; 춙; 춙; ) HANGUL SYLLABLE CUNJ +CD9A;CD9A;110E 116E 11AD;CD9A;110E 116E 11AD; # (춚; 춚; 춚; 춚; 춚; ) HANGUL SYLLABLE CUNH +CD9B;CD9B;110E 116E 11AE;CD9B;110E 116E 11AE; # (춛; 춛; 춛; 춛; 춛; ) HANGUL SYLLABLE CUD +CD9C;CD9C;110E 116E 11AF;CD9C;110E 116E 11AF; # (출; 출; 출; 출; 출; ) HANGUL SYLLABLE CUL +CD9D;CD9D;110E 116E 11B0;CD9D;110E 116E 11B0; # (춝; 춝; 춝; 춝; 춝; ) HANGUL SYLLABLE CULG +CD9E;CD9E;110E 116E 11B1;CD9E;110E 116E 11B1; # (춞; 춞; 춞; 춞; 춞; ) HANGUL SYLLABLE CULM +CD9F;CD9F;110E 116E 11B2;CD9F;110E 116E 11B2; # (춟; 춟; 춟; 춟; 춟; ) HANGUL SYLLABLE CULB +CDA0;CDA0;110E 116E 11B3;CDA0;110E 116E 11B3; # (춠; 춠; 춠; 춠; 춠; ) HANGUL SYLLABLE CULS +CDA1;CDA1;110E 116E 11B4;CDA1;110E 116E 11B4; # (춡; 춡; 춡; 춡; 춡; ) HANGUL SYLLABLE CULT +CDA2;CDA2;110E 116E 11B5;CDA2;110E 116E 11B5; # (춢; 춢; 춢; 춢; 춢; ) HANGUL SYLLABLE CULP +CDA3;CDA3;110E 116E 11B6;CDA3;110E 116E 11B6; # (춣; 춣; 춣; 춣; 춣; ) HANGUL SYLLABLE CULH +CDA4;CDA4;110E 116E 11B7;CDA4;110E 116E 11B7; # (춤; 춤; 춤; 춤; 춤; ) HANGUL SYLLABLE CUM +CDA5;CDA5;110E 116E 11B8;CDA5;110E 116E 11B8; # (춥; 춥; 춥; 춥; 춥; ) HANGUL SYLLABLE CUB +CDA6;CDA6;110E 116E 11B9;CDA6;110E 116E 11B9; # (춦; 춦; 춦; 춦; 춦; ) HANGUL SYLLABLE CUBS +CDA7;CDA7;110E 116E 11BA;CDA7;110E 116E 11BA; # (춧; 춧; 춧; 춧; 춧; ) HANGUL SYLLABLE CUS +CDA8;CDA8;110E 116E 11BB;CDA8;110E 116E 11BB; # (춨; 춨; 춨; 춨; 춨; ) HANGUL SYLLABLE CUSS +CDA9;CDA9;110E 116E 11BC;CDA9;110E 116E 11BC; # (충; 충; 충; 충; 충; ) HANGUL SYLLABLE CUNG +CDAA;CDAA;110E 116E 11BD;CDAA;110E 116E 11BD; # (춪; 춪; 춪; 춪; 춪; ) HANGUL SYLLABLE CUJ +CDAB;CDAB;110E 116E 11BE;CDAB;110E 116E 11BE; # (춫; 춫; 춫; 춫; 춫; ) HANGUL SYLLABLE CUC +CDAC;CDAC;110E 116E 11BF;CDAC;110E 116E 11BF; # (춬; 춬; 춬; 춬; 춬; ) HANGUL SYLLABLE CUK +CDAD;CDAD;110E 116E 11C0;CDAD;110E 116E 11C0; # (춭; 춭; 춭; 춭; 춭; ) HANGUL SYLLABLE CUT +CDAE;CDAE;110E 116E 11C1;CDAE;110E 116E 11C1; # (춮; 춮; 춮; 춮; 춮; ) HANGUL SYLLABLE CUP +CDAF;CDAF;110E 116E 11C2;CDAF;110E 116E 11C2; # (춯; 춯; 춯; 춯; 춯; ) HANGUL SYLLABLE CUH +CDB0;CDB0;110E 116F;CDB0;110E 116F; # (춰; 춰; 춰; 춰; 춰; ) HANGUL SYLLABLE CWEO +CDB1;CDB1;110E 116F 11A8;CDB1;110E 116F 11A8; # (춱; 춱; 춱; 춱; 춱; ) HANGUL SYLLABLE CWEOG +CDB2;CDB2;110E 116F 11A9;CDB2;110E 116F 11A9; # (춲; 춲; 춲; 춲; 춲; ) HANGUL SYLLABLE CWEOGG +CDB3;CDB3;110E 116F 11AA;CDB3;110E 116F 11AA; # (춳; 춳; 춳; 춳; 춳; ) HANGUL SYLLABLE CWEOGS +CDB4;CDB4;110E 116F 11AB;CDB4;110E 116F 11AB; # (춴; 춴; 춴; 춴; 춴; ) HANGUL SYLLABLE CWEON +CDB5;CDB5;110E 116F 11AC;CDB5;110E 116F 11AC; # (춵; 춵; 춵; 춵; 춵; ) HANGUL SYLLABLE CWEONJ +CDB6;CDB6;110E 116F 11AD;CDB6;110E 116F 11AD; # (춶; 춶; 춶; 춶; 춶; ) HANGUL SYLLABLE CWEONH +CDB7;CDB7;110E 116F 11AE;CDB7;110E 116F 11AE; # (춷; 춷; 춷; 춷; 춷; ) HANGUL SYLLABLE CWEOD +CDB8;CDB8;110E 116F 11AF;CDB8;110E 116F 11AF; # (춸; 춸; 춸; 춸; 춸; ) HANGUL SYLLABLE CWEOL +CDB9;CDB9;110E 116F 11B0;CDB9;110E 116F 11B0; # (춹; 춹; 춹; 춹; 춹; ) HANGUL SYLLABLE CWEOLG +CDBA;CDBA;110E 116F 11B1;CDBA;110E 116F 11B1; # (춺; 춺; 춺; 춺; 춺; ) HANGUL SYLLABLE CWEOLM +CDBB;CDBB;110E 116F 11B2;CDBB;110E 116F 11B2; # (춻; 춻; 춻; 춻; 춻; ) HANGUL SYLLABLE CWEOLB +CDBC;CDBC;110E 116F 11B3;CDBC;110E 116F 11B3; # (춼; 춼; 춼; 춼; 춼; ) HANGUL SYLLABLE CWEOLS +CDBD;CDBD;110E 116F 11B4;CDBD;110E 116F 11B4; # (춽; 춽; 춽; 춽; 춽; ) HANGUL SYLLABLE CWEOLT +CDBE;CDBE;110E 116F 11B5;CDBE;110E 116F 11B5; # (춾; 춾; 춾; 춾; 춾; ) HANGUL SYLLABLE CWEOLP +CDBF;CDBF;110E 116F 11B6;CDBF;110E 116F 11B6; # (춿; 춿; 춿; 춿; 춿; ) HANGUL SYLLABLE CWEOLH +CDC0;CDC0;110E 116F 11B7;CDC0;110E 116F 11B7; # (췀; 췀; 췀; 췀; 췀; ) HANGUL SYLLABLE CWEOM +CDC1;CDC1;110E 116F 11B8;CDC1;110E 116F 11B8; # (췁; 췁; 췁; 췁; 췁; ) HANGUL SYLLABLE CWEOB +CDC2;CDC2;110E 116F 11B9;CDC2;110E 116F 11B9; # (췂; 췂; 췂; 췂; 췂; ) HANGUL SYLLABLE CWEOBS +CDC3;CDC3;110E 116F 11BA;CDC3;110E 116F 11BA; # (췃; 췃; 췃; 췃; 췃; ) HANGUL SYLLABLE CWEOS +CDC4;CDC4;110E 116F 11BB;CDC4;110E 116F 11BB; # (췄; 췄; 췄; 췄; 췄; ) HANGUL SYLLABLE CWEOSS +CDC5;CDC5;110E 116F 11BC;CDC5;110E 116F 11BC; # (췅; 췅; 췅; 췅; 췅; ) HANGUL SYLLABLE CWEONG +CDC6;CDC6;110E 116F 11BD;CDC6;110E 116F 11BD; # (췆; 췆; 췆; 췆; 췆; ) HANGUL SYLLABLE CWEOJ +CDC7;CDC7;110E 116F 11BE;CDC7;110E 116F 11BE; # (췇; 췇; 췇; 췇; 췇; ) HANGUL SYLLABLE CWEOC +CDC8;CDC8;110E 116F 11BF;CDC8;110E 116F 11BF; # (췈; 췈; 췈; 췈; 췈; ) HANGUL SYLLABLE CWEOK +CDC9;CDC9;110E 116F 11C0;CDC9;110E 116F 11C0; # (췉; 췉; 췉; 췉; 췉; ) HANGUL SYLLABLE CWEOT +CDCA;CDCA;110E 116F 11C1;CDCA;110E 116F 11C1; # (췊; 췊; 췊; 췊; 췊; ) HANGUL SYLLABLE CWEOP +CDCB;CDCB;110E 116F 11C2;CDCB;110E 116F 11C2; # (췋; 췋; 췋; 췋; 췋; ) HANGUL SYLLABLE CWEOH +CDCC;CDCC;110E 1170;CDCC;110E 1170; # (췌; 췌; 췌; 췌; 췌; ) HANGUL SYLLABLE CWE +CDCD;CDCD;110E 1170 11A8;CDCD;110E 1170 11A8; # (췍; 췍; 췍; 췍; 췍; ) HANGUL SYLLABLE CWEG +CDCE;CDCE;110E 1170 11A9;CDCE;110E 1170 11A9; # (췎; 췎; 췎; 췎; 췎; ) HANGUL SYLLABLE CWEGG +CDCF;CDCF;110E 1170 11AA;CDCF;110E 1170 11AA; # (췏; 췏; 췏; 췏; 췏; ) HANGUL SYLLABLE CWEGS +CDD0;CDD0;110E 1170 11AB;CDD0;110E 1170 11AB; # (췐; 췐; 췐; 췐; 췐; ) HANGUL SYLLABLE CWEN +CDD1;CDD1;110E 1170 11AC;CDD1;110E 1170 11AC; # (췑; 췑; 췑; 췑; 췑; ) HANGUL SYLLABLE CWENJ +CDD2;CDD2;110E 1170 11AD;CDD2;110E 1170 11AD; # (췒; 췒; 췒; 췒; 췒; ) HANGUL SYLLABLE CWENH +CDD3;CDD3;110E 1170 11AE;CDD3;110E 1170 11AE; # (췓; 췓; 췓; 췓; 췓; ) HANGUL SYLLABLE CWED +CDD4;CDD4;110E 1170 11AF;CDD4;110E 1170 11AF; # (췔; 췔; 췔; 췔; 췔; ) HANGUL SYLLABLE CWEL +CDD5;CDD5;110E 1170 11B0;CDD5;110E 1170 11B0; # (췕; 췕; 췕; 췕; 췕; ) HANGUL SYLLABLE CWELG +CDD6;CDD6;110E 1170 11B1;CDD6;110E 1170 11B1; # (췖; 췖; 췖; 췖; 췖; ) HANGUL SYLLABLE CWELM +CDD7;CDD7;110E 1170 11B2;CDD7;110E 1170 11B2; # (췗; 췗; 췗; 췗; 췗; ) HANGUL SYLLABLE CWELB +CDD8;CDD8;110E 1170 11B3;CDD8;110E 1170 11B3; # (췘; 췘; 췘; 췘; 췘; ) HANGUL SYLLABLE CWELS +CDD9;CDD9;110E 1170 11B4;CDD9;110E 1170 11B4; # (췙; 췙; 췙; 췙; 췙; ) HANGUL SYLLABLE CWELT +CDDA;CDDA;110E 1170 11B5;CDDA;110E 1170 11B5; # (췚; 췚; 췚; 췚; 췚; ) HANGUL SYLLABLE CWELP +CDDB;CDDB;110E 1170 11B6;CDDB;110E 1170 11B6; # (췛; 췛; 췛; 췛; 췛; ) HANGUL SYLLABLE CWELH +CDDC;CDDC;110E 1170 11B7;CDDC;110E 1170 11B7; # (췜; 췜; 췜; 췜; 췜; ) HANGUL SYLLABLE CWEM +CDDD;CDDD;110E 1170 11B8;CDDD;110E 1170 11B8; # (췝; 췝; 췝; 췝; 췝; ) HANGUL SYLLABLE CWEB +CDDE;CDDE;110E 1170 11B9;CDDE;110E 1170 11B9; # (췞; 췞; 췞; 췞; 췞; ) HANGUL SYLLABLE CWEBS +CDDF;CDDF;110E 1170 11BA;CDDF;110E 1170 11BA; # (췟; 췟; 췟; 췟; 췟; ) HANGUL SYLLABLE CWES +CDE0;CDE0;110E 1170 11BB;CDE0;110E 1170 11BB; # (췠; 췠; 췠; 췠; 췠; ) HANGUL SYLLABLE CWESS +CDE1;CDE1;110E 1170 11BC;CDE1;110E 1170 11BC; # (췡; 췡; 췡; 췡; 췡; ) HANGUL SYLLABLE CWENG +CDE2;CDE2;110E 1170 11BD;CDE2;110E 1170 11BD; # (췢; 췢; 췢; 췢; 췢; ) HANGUL SYLLABLE CWEJ +CDE3;CDE3;110E 1170 11BE;CDE3;110E 1170 11BE; # (췣; 췣; 췣; 췣; 췣; ) HANGUL SYLLABLE CWEC +CDE4;CDE4;110E 1170 11BF;CDE4;110E 1170 11BF; # (췤; 췤; 췤; 췤; 췤; ) HANGUL SYLLABLE CWEK +CDE5;CDE5;110E 1170 11C0;CDE5;110E 1170 11C0; # (췥; 췥; 췥; 췥; 췥; ) HANGUL SYLLABLE CWET +CDE6;CDE6;110E 1170 11C1;CDE6;110E 1170 11C1; # (췦; 췦; 췦; 췦; 췦; ) HANGUL SYLLABLE CWEP +CDE7;CDE7;110E 1170 11C2;CDE7;110E 1170 11C2; # (췧; 췧; 췧; 췧; 췧; ) HANGUL SYLLABLE CWEH +CDE8;CDE8;110E 1171;CDE8;110E 1171; # (취; 취; 취; 취; 취; ) HANGUL SYLLABLE CWI +CDE9;CDE9;110E 1171 11A8;CDE9;110E 1171 11A8; # (췩; 췩; 췩; 췩; 췩; ) HANGUL SYLLABLE CWIG +CDEA;CDEA;110E 1171 11A9;CDEA;110E 1171 11A9; # (췪; 췪; 췪; 췪; 췪; ) HANGUL SYLLABLE CWIGG +CDEB;CDEB;110E 1171 11AA;CDEB;110E 1171 11AA; # (췫; 췫; 췫; 췫; 췫; ) HANGUL SYLLABLE CWIGS +CDEC;CDEC;110E 1171 11AB;CDEC;110E 1171 11AB; # (췬; 췬; 췬; 췬; 췬; ) HANGUL SYLLABLE CWIN +CDED;CDED;110E 1171 11AC;CDED;110E 1171 11AC; # (췭; 췭; 췭; 췭; 췭; ) HANGUL SYLLABLE CWINJ +CDEE;CDEE;110E 1171 11AD;CDEE;110E 1171 11AD; # (췮; 췮; 췮; 췮; 췮; ) HANGUL SYLLABLE CWINH +CDEF;CDEF;110E 1171 11AE;CDEF;110E 1171 11AE; # (췯; 췯; 췯; 췯; 췯; ) HANGUL SYLLABLE CWID +CDF0;CDF0;110E 1171 11AF;CDF0;110E 1171 11AF; # (췰; 췰; 췰; 췰; 췰; ) HANGUL SYLLABLE CWIL +CDF1;CDF1;110E 1171 11B0;CDF1;110E 1171 11B0; # (췱; 췱; 췱; 췱; 췱; ) HANGUL SYLLABLE CWILG +CDF2;CDF2;110E 1171 11B1;CDF2;110E 1171 11B1; # (췲; 췲; 췲; 췲; 췲; ) HANGUL SYLLABLE CWILM +CDF3;CDF3;110E 1171 11B2;CDF3;110E 1171 11B2; # (췳; 췳; 췳; 췳; 췳; ) HANGUL SYLLABLE CWILB +CDF4;CDF4;110E 1171 11B3;CDF4;110E 1171 11B3; # (췴; 췴; 췴; 췴; 췴; ) HANGUL SYLLABLE CWILS +CDF5;CDF5;110E 1171 11B4;CDF5;110E 1171 11B4; # (췵; 췵; 췵; 췵; 췵; ) HANGUL SYLLABLE CWILT +CDF6;CDF6;110E 1171 11B5;CDF6;110E 1171 11B5; # (췶; 췶; 췶; 췶; 췶; ) HANGUL SYLLABLE CWILP +CDF7;CDF7;110E 1171 11B6;CDF7;110E 1171 11B6; # (췷; 췷; 췷; 췷; 췷; ) HANGUL SYLLABLE CWILH +CDF8;CDF8;110E 1171 11B7;CDF8;110E 1171 11B7; # (췸; 췸; 췸; 췸; 췸; ) HANGUL SYLLABLE CWIM +CDF9;CDF9;110E 1171 11B8;CDF9;110E 1171 11B8; # (췹; 췹; 췹; 췹; 췹; ) HANGUL SYLLABLE CWIB +CDFA;CDFA;110E 1171 11B9;CDFA;110E 1171 11B9; # (췺; 췺; 췺; 췺; 췺; ) HANGUL SYLLABLE CWIBS +CDFB;CDFB;110E 1171 11BA;CDFB;110E 1171 11BA; # (췻; 췻; 췻; 췻; 췻; ) HANGUL SYLLABLE CWIS +CDFC;CDFC;110E 1171 11BB;CDFC;110E 1171 11BB; # (췼; 췼; 췼; 췼; 췼; ) HANGUL SYLLABLE CWISS +CDFD;CDFD;110E 1171 11BC;CDFD;110E 1171 11BC; # (췽; 췽; 췽; 췽; 췽; ) HANGUL SYLLABLE CWING +CDFE;CDFE;110E 1171 11BD;CDFE;110E 1171 11BD; # (췾; 췾; 췾; 췾; 췾; ) HANGUL SYLLABLE CWIJ +CDFF;CDFF;110E 1171 11BE;CDFF;110E 1171 11BE; # (췿; 췿; 췿; 췿; 췿; ) HANGUL SYLLABLE CWIC +CE00;CE00;110E 1171 11BF;CE00;110E 1171 11BF; # (츀; 츀; 츀; 츀; 츀; ) HANGUL SYLLABLE CWIK +CE01;CE01;110E 1171 11C0;CE01;110E 1171 11C0; # (츁; 츁; 츁; 츁; 츁; ) HANGUL SYLLABLE CWIT +CE02;CE02;110E 1171 11C1;CE02;110E 1171 11C1; # (츂; 츂; 츂; 츂; 츂; ) HANGUL SYLLABLE CWIP +CE03;CE03;110E 1171 11C2;CE03;110E 1171 11C2; # (츃; 츃; 츃; 츃; 츃; ) HANGUL SYLLABLE CWIH +CE04;CE04;110E 1172;CE04;110E 1172; # (츄; 츄; 츄; 츄; 츄; ) HANGUL SYLLABLE CYU +CE05;CE05;110E 1172 11A8;CE05;110E 1172 11A8; # (츅; 츅; 츅; 츅; 츅; ) HANGUL SYLLABLE CYUG +CE06;CE06;110E 1172 11A9;CE06;110E 1172 11A9; # (츆; 츆; 츆; 츆; 츆; ) HANGUL SYLLABLE CYUGG +CE07;CE07;110E 1172 11AA;CE07;110E 1172 11AA; # (츇; 츇; 츇; 츇; 츇; ) HANGUL SYLLABLE CYUGS +CE08;CE08;110E 1172 11AB;CE08;110E 1172 11AB; # (츈; 츈; 츈; 츈; 츈; ) HANGUL SYLLABLE CYUN +CE09;CE09;110E 1172 11AC;CE09;110E 1172 11AC; # (츉; 츉; 츉; 츉; 츉; ) HANGUL SYLLABLE CYUNJ +CE0A;CE0A;110E 1172 11AD;CE0A;110E 1172 11AD; # (츊; 츊; 츊; 츊; 츊; ) HANGUL SYLLABLE CYUNH +CE0B;CE0B;110E 1172 11AE;CE0B;110E 1172 11AE; # (츋; 츋; 츋; 츋; 츋; ) HANGUL SYLLABLE CYUD +CE0C;CE0C;110E 1172 11AF;CE0C;110E 1172 11AF; # (츌; 츌; 츌; 츌; 츌; ) HANGUL SYLLABLE CYUL +CE0D;CE0D;110E 1172 11B0;CE0D;110E 1172 11B0; # (츍; 츍; 츍; 츍; 츍; ) HANGUL SYLLABLE CYULG +CE0E;CE0E;110E 1172 11B1;CE0E;110E 1172 11B1; # (츎; 츎; 츎; 츎; 츎; ) HANGUL SYLLABLE CYULM +CE0F;CE0F;110E 1172 11B2;CE0F;110E 1172 11B2; # (츏; 츏; 츏; 츏; 츏; ) HANGUL SYLLABLE CYULB +CE10;CE10;110E 1172 11B3;CE10;110E 1172 11B3; # (츐; 츐; 츐; 츐; 츐; ) HANGUL SYLLABLE CYULS +CE11;CE11;110E 1172 11B4;CE11;110E 1172 11B4; # (츑; 츑; 츑; 츑; 츑; ) HANGUL SYLLABLE CYULT +CE12;CE12;110E 1172 11B5;CE12;110E 1172 11B5; # (츒; 츒; 츒; 츒; 츒; ) HANGUL SYLLABLE CYULP +CE13;CE13;110E 1172 11B6;CE13;110E 1172 11B6; # (츓; 츓; 츓; 츓; 츓; ) HANGUL SYLLABLE CYULH +CE14;CE14;110E 1172 11B7;CE14;110E 1172 11B7; # (츔; 츔; 츔; 츔; 츔; ) HANGUL SYLLABLE CYUM +CE15;CE15;110E 1172 11B8;CE15;110E 1172 11B8; # (츕; 츕; 츕; 츕; 츕; ) HANGUL SYLLABLE CYUB +CE16;CE16;110E 1172 11B9;CE16;110E 1172 11B9; # (츖; 츖; 츖; 츖; 츖; ) HANGUL SYLLABLE CYUBS +CE17;CE17;110E 1172 11BA;CE17;110E 1172 11BA; # (츗; 츗; 츗; 츗; 츗; ) HANGUL SYLLABLE CYUS +CE18;CE18;110E 1172 11BB;CE18;110E 1172 11BB; # (츘; 츘; 츘; 츘; 츘; ) HANGUL SYLLABLE CYUSS +CE19;CE19;110E 1172 11BC;CE19;110E 1172 11BC; # (츙; 츙; 츙; 츙; 츙; ) HANGUL SYLLABLE CYUNG +CE1A;CE1A;110E 1172 11BD;CE1A;110E 1172 11BD; # (츚; 츚; 츚; 츚; 츚; ) HANGUL SYLLABLE CYUJ +CE1B;CE1B;110E 1172 11BE;CE1B;110E 1172 11BE; # (츛; 츛; 츛; 츛; 츛; ) HANGUL SYLLABLE CYUC +CE1C;CE1C;110E 1172 11BF;CE1C;110E 1172 11BF; # (츜; 츜; 츜; 츜; 츜; ) HANGUL SYLLABLE CYUK +CE1D;CE1D;110E 1172 11C0;CE1D;110E 1172 11C0; # (츝; 츝; 츝; 츝; 츝; ) HANGUL SYLLABLE CYUT +CE1E;CE1E;110E 1172 11C1;CE1E;110E 1172 11C1; # (츞; 츞; 츞; 츞; 츞; ) HANGUL SYLLABLE CYUP +CE1F;CE1F;110E 1172 11C2;CE1F;110E 1172 11C2; # (츟; 츟; 츟; 츟; 츟; ) HANGUL SYLLABLE CYUH +CE20;CE20;110E 1173;CE20;110E 1173; # (츠; 츠; 츠; 츠; 츠; ) HANGUL SYLLABLE CEU +CE21;CE21;110E 1173 11A8;CE21;110E 1173 11A8; # (측; 측; 측; 측; 측; ) HANGUL SYLLABLE CEUG +CE22;CE22;110E 1173 11A9;CE22;110E 1173 11A9; # (츢; 츢; 츢; 츢; 츢; ) HANGUL SYLLABLE CEUGG +CE23;CE23;110E 1173 11AA;CE23;110E 1173 11AA; # (츣; 츣; 츣; 츣; 츣; ) HANGUL SYLLABLE CEUGS +CE24;CE24;110E 1173 11AB;CE24;110E 1173 11AB; # (츤; 츤; 츤; 츤; 츤; ) HANGUL SYLLABLE CEUN +CE25;CE25;110E 1173 11AC;CE25;110E 1173 11AC; # (츥; 츥; 츥; 츥; 츥; ) HANGUL SYLLABLE CEUNJ +CE26;CE26;110E 1173 11AD;CE26;110E 1173 11AD; # (츦; 츦; 츦; 츦; 츦; ) HANGUL SYLLABLE CEUNH +CE27;CE27;110E 1173 11AE;CE27;110E 1173 11AE; # (츧; 츧; 츧; 츧; 츧; ) HANGUL SYLLABLE CEUD +CE28;CE28;110E 1173 11AF;CE28;110E 1173 11AF; # (츨; 츨; 츨; 츨; 츨; ) HANGUL SYLLABLE CEUL +CE29;CE29;110E 1173 11B0;CE29;110E 1173 11B0; # (츩; 츩; 츩; 츩; 츩; ) HANGUL SYLLABLE CEULG +CE2A;CE2A;110E 1173 11B1;CE2A;110E 1173 11B1; # (츪; 츪; 츪; 츪; 츪; ) HANGUL SYLLABLE CEULM +CE2B;CE2B;110E 1173 11B2;CE2B;110E 1173 11B2; # (츫; 츫; 츫; 츫; 츫; ) HANGUL SYLLABLE CEULB +CE2C;CE2C;110E 1173 11B3;CE2C;110E 1173 11B3; # (츬; 츬; 츬; 츬; 츬; ) HANGUL SYLLABLE CEULS +CE2D;CE2D;110E 1173 11B4;CE2D;110E 1173 11B4; # (츭; 츭; 츭; 츭; 츭; ) HANGUL SYLLABLE CEULT +CE2E;CE2E;110E 1173 11B5;CE2E;110E 1173 11B5; # (츮; 츮; 츮; 츮; 츮; ) HANGUL SYLLABLE CEULP +CE2F;CE2F;110E 1173 11B6;CE2F;110E 1173 11B6; # (츯; 츯; 츯; 츯; 츯; ) HANGUL SYLLABLE CEULH +CE30;CE30;110E 1173 11B7;CE30;110E 1173 11B7; # (츰; 츰; 츰; 츰; 츰; ) HANGUL SYLLABLE CEUM +CE31;CE31;110E 1173 11B8;CE31;110E 1173 11B8; # (츱; 츱; 츱; 츱; 츱; ) HANGUL SYLLABLE CEUB +CE32;CE32;110E 1173 11B9;CE32;110E 1173 11B9; # (츲; 츲; 츲; 츲; 츲; ) HANGUL SYLLABLE CEUBS +CE33;CE33;110E 1173 11BA;CE33;110E 1173 11BA; # (츳; 츳; 츳; 츳; 츳; ) HANGUL SYLLABLE CEUS +CE34;CE34;110E 1173 11BB;CE34;110E 1173 11BB; # (츴; 츴; 츴; 츴; 츴; ) HANGUL SYLLABLE CEUSS +CE35;CE35;110E 1173 11BC;CE35;110E 1173 11BC; # (층; 층; 층; 층; 층; ) HANGUL SYLLABLE CEUNG +CE36;CE36;110E 1173 11BD;CE36;110E 1173 11BD; # (츶; 츶; 츶; 츶; 츶; ) HANGUL SYLLABLE CEUJ +CE37;CE37;110E 1173 11BE;CE37;110E 1173 11BE; # (츷; 츷; 츷; 츷; 츷; ) HANGUL SYLLABLE CEUC +CE38;CE38;110E 1173 11BF;CE38;110E 1173 11BF; # (츸; 츸; 츸; 츸; 츸; ) HANGUL SYLLABLE CEUK +CE39;CE39;110E 1173 11C0;CE39;110E 1173 11C0; # (츹; 츹; 츹; 츹; 츹; ) HANGUL SYLLABLE CEUT +CE3A;CE3A;110E 1173 11C1;CE3A;110E 1173 11C1; # (츺; 츺; 츺; 츺; 츺; ) HANGUL SYLLABLE CEUP +CE3B;CE3B;110E 1173 11C2;CE3B;110E 1173 11C2; # (츻; 츻; 츻; 츻; 츻; ) HANGUL SYLLABLE CEUH +CE3C;CE3C;110E 1174;CE3C;110E 1174; # (츼; 츼; 츼; 츼; 츼; ) HANGUL SYLLABLE CYI +CE3D;CE3D;110E 1174 11A8;CE3D;110E 1174 11A8; # (츽; 츽; 츽; 츽; 츽; ) HANGUL SYLLABLE CYIG +CE3E;CE3E;110E 1174 11A9;CE3E;110E 1174 11A9; # (츾; 츾; 츾; 츾; 츾; ) HANGUL SYLLABLE CYIGG +CE3F;CE3F;110E 1174 11AA;CE3F;110E 1174 11AA; # (츿; 츿; 츿; 츿; 츿; ) HANGUL SYLLABLE CYIGS +CE40;CE40;110E 1174 11AB;CE40;110E 1174 11AB; # (칀; 칀; 칀; 칀; 칀; ) HANGUL SYLLABLE CYIN +CE41;CE41;110E 1174 11AC;CE41;110E 1174 11AC; # (칁; 칁; 칁; 칁; 칁; ) HANGUL SYLLABLE CYINJ +CE42;CE42;110E 1174 11AD;CE42;110E 1174 11AD; # (칂; 칂; 칂; 칂; 칂; ) HANGUL SYLLABLE CYINH +CE43;CE43;110E 1174 11AE;CE43;110E 1174 11AE; # (칃; 칃; 칃; 칃; 칃; ) HANGUL SYLLABLE CYID +CE44;CE44;110E 1174 11AF;CE44;110E 1174 11AF; # (칄; 칄; 칄; 칄; 칄; ) HANGUL SYLLABLE CYIL +CE45;CE45;110E 1174 11B0;CE45;110E 1174 11B0; # (칅; 칅; 칅; 칅; 칅; ) HANGUL SYLLABLE CYILG +CE46;CE46;110E 1174 11B1;CE46;110E 1174 11B1; # (칆; 칆; 칆; 칆; 칆; ) HANGUL SYLLABLE CYILM +CE47;CE47;110E 1174 11B2;CE47;110E 1174 11B2; # (칇; 칇; 칇; 칇; 칇; ) HANGUL SYLLABLE CYILB +CE48;CE48;110E 1174 11B3;CE48;110E 1174 11B3; # (칈; 칈; 칈; 칈; 칈; ) HANGUL SYLLABLE CYILS +CE49;CE49;110E 1174 11B4;CE49;110E 1174 11B4; # (칉; 칉; 칉; 칉; 칉; ) HANGUL SYLLABLE CYILT +CE4A;CE4A;110E 1174 11B5;CE4A;110E 1174 11B5; # (칊; 칊; 칊; 칊; 칊; ) HANGUL SYLLABLE CYILP +CE4B;CE4B;110E 1174 11B6;CE4B;110E 1174 11B6; # (칋; 칋; 칋; 칋; 칋; ) HANGUL SYLLABLE CYILH +CE4C;CE4C;110E 1174 11B7;CE4C;110E 1174 11B7; # (칌; 칌; 칌; 칌; 칌; ) HANGUL SYLLABLE CYIM +CE4D;CE4D;110E 1174 11B8;CE4D;110E 1174 11B8; # (칍; 칍; 칍; 칍; 칍; ) HANGUL SYLLABLE CYIB +CE4E;CE4E;110E 1174 11B9;CE4E;110E 1174 11B9; # (칎; 칎; 칎; 칎; 칎; ) HANGUL SYLLABLE CYIBS +CE4F;CE4F;110E 1174 11BA;CE4F;110E 1174 11BA; # (칏; 칏; 칏; 칏; 칏; ) HANGUL SYLLABLE CYIS +CE50;CE50;110E 1174 11BB;CE50;110E 1174 11BB; # (칐; 칐; 칐; 칐; 칐; ) HANGUL SYLLABLE CYISS +CE51;CE51;110E 1174 11BC;CE51;110E 1174 11BC; # (칑; 칑; 칑; 칑; 칑; ) HANGUL SYLLABLE CYING +CE52;CE52;110E 1174 11BD;CE52;110E 1174 11BD; # (칒; 칒; 칒; 칒; 칒; ) HANGUL SYLLABLE CYIJ +CE53;CE53;110E 1174 11BE;CE53;110E 1174 11BE; # (칓; 칓; 칓; 칓; 칓; ) HANGUL SYLLABLE CYIC +CE54;CE54;110E 1174 11BF;CE54;110E 1174 11BF; # (칔; 칔; 칔; 칔; 칔; ) HANGUL SYLLABLE CYIK +CE55;CE55;110E 1174 11C0;CE55;110E 1174 11C0; # (칕; 칕; 칕; 칕; 칕; ) HANGUL SYLLABLE CYIT +CE56;CE56;110E 1174 11C1;CE56;110E 1174 11C1; # (칖; 칖; 칖; 칖; 칖; ) HANGUL SYLLABLE CYIP +CE57;CE57;110E 1174 11C2;CE57;110E 1174 11C2; # (칗; 칗; 칗; 칗; 칗; ) HANGUL SYLLABLE CYIH +CE58;CE58;110E 1175;CE58;110E 1175; # (치; 치; 치; 치; 치; ) HANGUL SYLLABLE CI +CE59;CE59;110E 1175 11A8;CE59;110E 1175 11A8; # (칙; 칙; 칙; 칙; 칙; ) HANGUL SYLLABLE CIG +CE5A;CE5A;110E 1175 11A9;CE5A;110E 1175 11A9; # (칚; 칚; 칚; 칚; 칚; ) HANGUL SYLLABLE CIGG +CE5B;CE5B;110E 1175 11AA;CE5B;110E 1175 11AA; # (칛; 칛; 칛; 칛; 칛; ) HANGUL SYLLABLE CIGS +CE5C;CE5C;110E 1175 11AB;CE5C;110E 1175 11AB; # (친; 친; 친; 친; 친; ) HANGUL SYLLABLE CIN +CE5D;CE5D;110E 1175 11AC;CE5D;110E 1175 11AC; # (칝; 칝; 칝; 칝; 칝; ) HANGUL SYLLABLE CINJ +CE5E;CE5E;110E 1175 11AD;CE5E;110E 1175 11AD; # (칞; 칞; 칞; 칞; 칞; ) HANGUL SYLLABLE CINH +CE5F;CE5F;110E 1175 11AE;CE5F;110E 1175 11AE; # (칟; 칟; 칟; 칟; 칟; ) HANGUL SYLLABLE CID +CE60;CE60;110E 1175 11AF;CE60;110E 1175 11AF; # (칠; 칠; 칠; 칠; 칠; ) HANGUL SYLLABLE CIL +CE61;CE61;110E 1175 11B0;CE61;110E 1175 11B0; # (칡; 칡; 칡; 칡; 칡; ) HANGUL SYLLABLE CILG +CE62;CE62;110E 1175 11B1;CE62;110E 1175 11B1; # (칢; 칢; 칢; 칢; 칢; ) HANGUL SYLLABLE CILM +CE63;CE63;110E 1175 11B2;CE63;110E 1175 11B2; # (칣; 칣; 칣; 칣; 칣; ) HANGUL SYLLABLE CILB +CE64;CE64;110E 1175 11B3;CE64;110E 1175 11B3; # (칤; 칤; 칤; 칤; 칤; ) HANGUL SYLLABLE CILS +CE65;CE65;110E 1175 11B4;CE65;110E 1175 11B4; # (칥; 칥; 칥; 칥; 칥; ) HANGUL SYLLABLE CILT +CE66;CE66;110E 1175 11B5;CE66;110E 1175 11B5; # (칦; 칦; 칦; 칦; 칦; ) HANGUL SYLLABLE CILP +CE67;CE67;110E 1175 11B6;CE67;110E 1175 11B6; # (칧; 칧; 칧; 칧; 칧; ) HANGUL SYLLABLE CILH +CE68;CE68;110E 1175 11B7;CE68;110E 1175 11B7; # (침; 침; 침; 침; 침; ) HANGUL SYLLABLE CIM +CE69;CE69;110E 1175 11B8;CE69;110E 1175 11B8; # (칩; 칩; 칩; 칩; 칩; ) HANGUL SYLLABLE CIB +CE6A;CE6A;110E 1175 11B9;CE6A;110E 1175 11B9; # (칪; 칪; 칪; 칪; 칪; ) HANGUL SYLLABLE CIBS +CE6B;CE6B;110E 1175 11BA;CE6B;110E 1175 11BA; # (칫; 칫; 칫; 칫; 칫; ) HANGUL SYLLABLE CIS +CE6C;CE6C;110E 1175 11BB;CE6C;110E 1175 11BB; # (칬; 칬; 칬; 칬; 칬; ) HANGUL SYLLABLE CISS +CE6D;CE6D;110E 1175 11BC;CE6D;110E 1175 11BC; # (칭; 칭; 칭; 칭; 칭; ) HANGUL SYLLABLE CING +CE6E;CE6E;110E 1175 11BD;CE6E;110E 1175 11BD; # (칮; 칮; 칮; 칮; 칮; ) HANGUL SYLLABLE CIJ +CE6F;CE6F;110E 1175 11BE;CE6F;110E 1175 11BE; # (칯; 칯; 칯; 칯; 칯; ) HANGUL SYLLABLE CIC +CE70;CE70;110E 1175 11BF;CE70;110E 1175 11BF; # (칰; 칰; 칰; 칰; 칰; ) HANGUL SYLLABLE CIK +CE71;CE71;110E 1175 11C0;CE71;110E 1175 11C0; # (칱; 칱; 칱; 칱; 칱; ) HANGUL SYLLABLE CIT +CE72;CE72;110E 1175 11C1;CE72;110E 1175 11C1; # (칲; 칲; 칲; 칲; 칲; ) HANGUL SYLLABLE CIP +CE73;CE73;110E 1175 11C2;CE73;110E 1175 11C2; # (칳; 칳; 칳; 칳; 칳; ) HANGUL SYLLABLE CIH +CE74;CE74;110F 1161;CE74;110F 1161; # (카; 카; 카; 카; 카; ) HANGUL SYLLABLE KA +CE75;CE75;110F 1161 11A8;CE75;110F 1161 11A8; # (칵; 칵; 칵; 칵; 칵; ) HANGUL SYLLABLE KAG +CE76;CE76;110F 1161 11A9;CE76;110F 1161 11A9; # (칶; 칶; 칶; 칶; 칶; ) HANGUL SYLLABLE KAGG +CE77;CE77;110F 1161 11AA;CE77;110F 1161 11AA; # (칷; 칷; 칷; 칷; 칷; ) HANGUL SYLLABLE KAGS +CE78;CE78;110F 1161 11AB;CE78;110F 1161 11AB; # (칸; 칸; 칸; 칸; 칸; ) HANGUL SYLLABLE KAN +CE79;CE79;110F 1161 11AC;CE79;110F 1161 11AC; # (칹; 칹; 칹; 칹; 칹; ) HANGUL SYLLABLE KANJ +CE7A;CE7A;110F 1161 11AD;CE7A;110F 1161 11AD; # (칺; 칺; 칺; 칺; 칺; ) HANGUL SYLLABLE KANH +CE7B;CE7B;110F 1161 11AE;CE7B;110F 1161 11AE; # (칻; 칻; 칻; 칻; 칻; ) HANGUL SYLLABLE KAD +CE7C;CE7C;110F 1161 11AF;CE7C;110F 1161 11AF; # (칼; 칼; 칼; 칼; 칼; ) HANGUL SYLLABLE KAL +CE7D;CE7D;110F 1161 11B0;CE7D;110F 1161 11B0; # (칽; 칽; 칽; 칽; 칽; ) HANGUL SYLLABLE KALG +CE7E;CE7E;110F 1161 11B1;CE7E;110F 1161 11B1; # (칾; 칾; 칾; 칾; 칾; ) HANGUL SYLLABLE KALM +CE7F;CE7F;110F 1161 11B2;CE7F;110F 1161 11B2; # (칿; 칿; 칿; 칿; 칿; ) HANGUL SYLLABLE KALB +CE80;CE80;110F 1161 11B3;CE80;110F 1161 11B3; # (캀; 캀; 캀; 캀; 캀; ) HANGUL SYLLABLE KALS +CE81;CE81;110F 1161 11B4;CE81;110F 1161 11B4; # (캁; 캁; 캁; 캁; 캁; ) HANGUL SYLLABLE KALT +CE82;CE82;110F 1161 11B5;CE82;110F 1161 11B5; # (캂; 캂; 캂; 캂; 캂; ) HANGUL SYLLABLE KALP +CE83;CE83;110F 1161 11B6;CE83;110F 1161 11B6; # (캃; 캃; 캃; 캃; 캃; ) HANGUL SYLLABLE KALH +CE84;CE84;110F 1161 11B7;CE84;110F 1161 11B7; # (캄; 캄; 캄; 캄; 캄; ) HANGUL SYLLABLE KAM +CE85;CE85;110F 1161 11B8;CE85;110F 1161 11B8; # (캅; 캅; 캅; 캅; 캅; ) HANGUL SYLLABLE KAB +CE86;CE86;110F 1161 11B9;CE86;110F 1161 11B9; # (캆; 캆; 캆; 캆; 캆; ) HANGUL SYLLABLE KABS +CE87;CE87;110F 1161 11BA;CE87;110F 1161 11BA; # (캇; 캇; 캇; 캇; 캇; ) HANGUL SYLLABLE KAS +CE88;CE88;110F 1161 11BB;CE88;110F 1161 11BB; # (캈; 캈; 캈; 캈; 캈; ) HANGUL SYLLABLE KASS +CE89;CE89;110F 1161 11BC;CE89;110F 1161 11BC; # (캉; 캉; 캉; 캉; 캉; ) HANGUL SYLLABLE KANG +CE8A;CE8A;110F 1161 11BD;CE8A;110F 1161 11BD; # (캊; 캊; 캊; 캊; 캊; ) HANGUL SYLLABLE KAJ +CE8B;CE8B;110F 1161 11BE;CE8B;110F 1161 11BE; # (캋; 캋; 캋; 캋; 캋; ) HANGUL SYLLABLE KAC +CE8C;CE8C;110F 1161 11BF;CE8C;110F 1161 11BF; # (캌; 캌; 캌; 캌; 캌; ) HANGUL SYLLABLE KAK +CE8D;CE8D;110F 1161 11C0;CE8D;110F 1161 11C0; # (캍; 캍; 캍; 캍; 캍; ) HANGUL SYLLABLE KAT +CE8E;CE8E;110F 1161 11C1;CE8E;110F 1161 11C1; # (캎; 캎; 캎; 캎; 캎; ) HANGUL SYLLABLE KAP +CE8F;CE8F;110F 1161 11C2;CE8F;110F 1161 11C2; # (캏; 캏; 캏; 캏; 캏; ) HANGUL SYLLABLE KAH +CE90;CE90;110F 1162;CE90;110F 1162; # (캐; 캐; 캐; 캐; 캐; ) HANGUL SYLLABLE KAE +CE91;CE91;110F 1162 11A8;CE91;110F 1162 11A8; # (캑; 캑; 캑; 캑; 캑; ) HANGUL SYLLABLE KAEG +CE92;CE92;110F 1162 11A9;CE92;110F 1162 11A9; # (캒; 캒; 캒; 캒; 캒; ) HANGUL SYLLABLE KAEGG +CE93;CE93;110F 1162 11AA;CE93;110F 1162 11AA; # (캓; 캓; 캓; 캓; 캓; ) HANGUL SYLLABLE KAEGS +CE94;CE94;110F 1162 11AB;CE94;110F 1162 11AB; # (캔; 캔; 캔; 캔; 캔; ) HANGUL SYLLABLE KAEN +CE95;CE95;110F 1162 11AC;CE95;110F 1162 11AC; # (캕; 캕; 캕; 캕; 캕; ) HANGUL SYLLABLE KAENJ +CE96;CE96;110F 1162 11AD;CE96;110F 1162 11AD; # (캖; 캖; 캖; 캖; 캖; ) HANGUL SYLLABLE KAENH +CE97;CE97;110F 1162 11AE;CE97;110F 1162 11AE; # (캗; 캗; 캗; 캗; 캗; ) HANGUL SYLLABLE KAED +CE98;CE98;110F 1162 11AF;CE98;110F 1162 11AF; # (캘; 캘; 캘; 캘; 캘; ) HANGUL SYLLABLE KAEL +CE99;CE99;110F 1162 11B0;CE99;110F 1162 11B0; # (캙; 캙; 캙; 캙; 캙; ) HANGUL SYLLABLE KAELG +CE9A;CE9A;110F 1162 11B1;CE9A;110F 1162 11B1; # (캚; 캚; 캚; 캚; 캚; ) HANGUL SYLLABLE KAELM +CE9B;CE9B;110F 1162 11B2;CE9B;110F 1162 11B2; # (캛; 캛; 캛; 캛; 캛; ) HANGUL SYLLABLE KAELB +CE9C;CE9C;110F 1162 11B3;CE9C;110F 1162 11B3; # (캜; 캜; 캜; 캜; 캜; ) HANGUL SYLLABLE KAELS +CE9D;CE9D;110F 1162 11B4;CE9D;110F 1162 11B4; # (캝; 캝; 캝; 캝; 캝; ) HANGUL SYLLABLE KAELT +CE9E;CE9E;110F 1162 11B5;CE9E;110F 1162 11B5; # (캞; 캞; 캞; 캞; 캞; ) HANGUL SYLLABLE KAELP +CE9F;CE9F;110F 1162 11B6;CE9F;110F 1162 11B6; # (캟; 캟; 캟; 캟; 캟; ) HANGUL SYLLABLE KAELH +CEA0;CEA0;110F 1162 11B7;CEA0;110F 1162 11B7; # (캠; 캠; 캠; 캠; 캠; ) HANGUL SYLLABLE KAEM +CEA1;CEA1;110F 1162 11B8;CEA1;110F 1162 11B8; # (캡; 캡; 캡; 캡; 캡; ) HANGUL SYLLABLE KAEB +CEA2;CEA2;110F 1162 11B9;CEA2;110F 1162 11B9; # (캢; 캢; 캢; 캢; 캢; ) HANGUL SYLLABLE KAEBS +CEA3;CEA3;110F 1162 11BA;CEA3;110F 1162 11BA; # (캣; 캣; 캣; 캣; 캣; ) HANGUL SYLLABLE KAES +CEA4;CEA4;110F 1162 11BB;CEA4;110F 1162 11BB; # (캤; 캤; 캤; 캤; 캤; ) HANGUL SYLLABLE KAESS +CEA5;CEA5;110F 1162 11BC;CEA5;110F 1162 11BC; # (캥; 캥; 캥; 캥; 캥; ) HANGUL SYLLABLE KAENG +CEA6;CEA6;110F 1162 11BD;CEA6;110F 1162 11BD; # (캦; 캦; 캦; 캦; 캦; ) HANGUL SYLLABLE KAEJ +CEA7;CEA7;110F 1162 11BE;CEA7;110F 1162 11BE; # (캧; 캧; 캧; 캧; 캧; ) HANGUL SYLLABLE KAEC +CEA8;CEA8;110F 1162 11BF;CEA8;110F 1162 11BF; # (캨; 캨; 캨; 캨; 캨; ) HANGUL SYLLABLE KAEK +CEA9;CEA9;110F 1162 11C0;CEA9;110F 1162 11C0; # (캩; 캩; 캩; 캩; 캩; ) HANGUL SYLLABLE KAET +CEAA;CEAA;110F 1162 11C1;CEAA;110F 1162 11C1; # (캪; 캪; 캪; 캪; 캪; ) HANGUL SYLLABLE KAEP +CEAB;CEAB;110F 1162 11C2;CEAB;110F 1162 11C2; # (캫; 캫; 캫; 캫; 캫; ) HANGUL SYLLABLE KAEH +CEAC;CEAC;110F 1163;CEAC;110F 1163; # (캬; 캬; 캬; 캬; 캬; ) HANGUL SYLLABLE KYA +CEAD;CEAD;110F 1163 11A8;CEAD;110F 1163 11A8; # (캭; 캭; 캭; 캭; 캭; ) HANGUL SYLLABLE KYAG +CEAE;CEAE;110F 1163 11A9;CEAE;110F 1163 11A9; # (캮; 캮; 캮; 캮; 캮; ) HANGUL SYLLABLE KYAGG +CEAF;CEAF;110F 1163 11AA;CEAF;110F 1163 11AA; # (캯; 캯; 캯; 캯; 캯; ) HANGUL SYLLABLE KYAGS +CEB0;CEB0;110F 1163 11AB;CEB0;110F 1163 11AB; # (캰; 캰; 캰; 캰; 캰; ) HANGUL SYLLABLE KYAN +CEB1;CEB1;110F 1163 11AC;CEB1;110F 1163 11AC; # (캱; 캱; 캱; 캱; 캱; ) HANGUL SYLLABLE KYANJ +CEB2;CEB2;110F 1163 11AD;CEB2;110F 1163 11AD; # (캲; 캲; 캲; 캲; 캲; ) HANGUL SYLLABLE KYANH +CEB3;CEB3;110F 1163 11AE;CEB3;110F 1163 11AE; # (캳; 캳; 캳; 캳; 캳; ) HANGUL SYLLABLE KYAD +CEB4;CEB4;110F 1163 11AF;CEB4;110F 1163 11AF; # (캴; 캴; 캴; 캴; 캴; ) HANGUL SYLLABLE KYAL +CEB5;CEB5;110F 1163 11B0;CEB5;110F 1163 11B0; # (캵; 캵; 캵; 캵; 캵; ) HANGUL SYLLABLE KYALG +CEB6;CEB6;110F 1163 11B1;CEB6;110F 1163 11B1; # (캶; 캶; 캶; 캶; 캶; ) HANGUL SYLLABLE KYALM +CEB7;CEB7;110F 1163 11B2;CEB7;110F 1163 11B2; # (캷; 캷; 캷; 캷; 캷; ) HANGUL SYLLABLE KYALB +CEB8;CEB8;110F 1163 11B3;CEB8;110F 1163 11B3; # (캸; 캸; 캸; 캸; 캸; ) HANGUL SYLLABLE KYALS +CEB9;CEB9;110F 1163 11B4;CEB9;110F 1163 11B4; # (캹; 캹; 캹; 캹; 캹; ) HANGUL SYLLABLE KYALT +CEBA;CEBA;110F 1163 11B5;CEBA;110F 1163 11B5; # (캺; 캺; 캺; 캺; 캺; ) HANGUL SYLLABLE KYALP +CEBB;CEBB;110F 1163 11B6;CEBB;110F 1163 11B6; # (캻; 캻; 캻; 캻; 캻; ) HANGUL SYLLABLE KYALH +CEBC;CEBC;110F 1163 11B7;CEBC;110F 1163 11B7; # (캼; 캼; 캼; 캼; 캼; ) HANGUL SYLLABLE KYAM +CEBD;CEBD;110F 1163 11B8;CEBD;110F 1163 11B8; # (캽; 캽; 캽; 캽; 캽; ) HANGUL SYLLABLE KYAB +CEBE;CEBE;110F 1163 11B9;CEBE;110F 1163 11B9; # (캾; 캾; 캾; 캾; 캾; ) HANGUL SYLLABLE KYABS +CEBF;CEBF;110F 1163 11BA;CEBF;110F 1163 11BA; # (캿; 캿; 캿; 캿; 캿; ) HANGUL SYLLABLE KYAS +CEC0;CEC0;110F 1163 11BB;CEC0;110F 1163 11BB; # (컀; 컀; 컀; 컀; 컀; ) HANGUL SYLLABLE KYASS +CEC1;CEC1;110F 1163 11BC;CEC1;110F 1163 11BC; # (컁; 컁; 컁; 컁; 컁; ) HANGUL SYLLABLE KYANG +CEC2;CEC2;110F 1163 11BD;CEC2;110F 1163 11BD; # (컂; 컂; 컂; 컂; 컂; ) HANGUL SYLLABLE KYAJ +CEC3;CEC3;110F 1163 11BE;CEC3;110F 1163 11BE; # (컃; 컃; 컃; 컃; 컃; ) HANGUL SYLLABLE KYAC +CEC4;CEC4;110F 1163 11BF;CEC4;110F 1163 11BF; # (컄; 컄; 컄; 컄; 컄; ) HANGUL SYLLABLE KYAK +CEC5;CEC5;110F 1163 11C0;CEC5;110F 1163 11C0; # (컅; 컅; 컅; 컅; 컅; ) HANGUL SYLLABLE KYAT +CEC6;CEC6;110F 1163 11C1;CEC6;110F 1163 11C1; # (컆; 컆; 컆; 컆; 컆; ) HANGUL SYLLABLE KYAP +CEC7;CEC7;110F 1163 11C2;CEC7;110F 1163 11C2; # (컇; 컇; 컇; 컇; 컇; ) HANGUL SYLLABLE KYAH +CEC8;CEC8;110F 1164;CEC8;110F 1164; # (컈; 컈; 컈; 컈; 컈; ) HANGUL SYLLABLE KYAE +CEC9;CEC9;110F 1164 11A8;CEC9;110F 1164 11A8; # (컉; 컉; 컉; 컉; 컉; ) HANGUL SYLLABLE KYAEG +CECA;CECA;110F 1164 11A9;CECA;110F 1164 11A9; # (컊; 컊; 컊; 컊; 컊; ) HANGUL SYLLABLE KYAEGG +CECB;CECB;110F 1164 11AA;CECB;110F 1164 11AA; # (컋; 컋; 컋; 컋; 컋; ) HANGUL SYLLABLE KYAEGS +CECC;CECC;110F 1164 11AB;CECC;110F 1164 11AB; # (컌; 컌; 컌; 컌; 컌; ) HANGUL SYLLABLE KYAEN +CECD;CECD;110F 1164 11AC;CECD;110F 1164 11AC; # (컍; 컍; 컍; 컍; 컍; ) HANGUL SYLLABLE KYAENJ +CECE;CECE;110F 1164 11AD;CECE;110F 1164 11AD; # (컎; 컎; 컎; 컎; 컎; ) HANGUL SYLLABLE KYAENH +CECF;CECF;110F 1164 11AE;CECF;110F 1164 11AE; # (컏; 컏; 컏; 컏; 컏; ) HANGUL SYLLABLE KYAED +CED0;CED0;110F 1164 11AF;CED0;110F 1164 11AF; # (컐; 컐; 컐; 컐; 컐; ) HANGUL SYLLABLE KYAEL +CED1;CED1;110F 1164 11B0;CED1;110F 1164 11B0; # (컑; 컑; 컑; 컑; 컑; ) HANGUL SYLLABLE KYAELG +CED2;CED2;110F 1164 11B1;CED2;110F 1164 11B1; # (컒; 컒; 컒; 컒; 컒; ) HANGUL SYLLABLE KYAELM +CED3;CED3;110F 1164 11B2;CED3;110F 1164 11B2; # (컓; 컓; 컓; 컓; 컓; ) HANGUL SYLLABLE KYAELB +CED4;CED4;110F 1164 11B3;CED4;110F 1164 11B3; # (컔; 컔; 컔; 컔; 컔; ) HANGUL SYLLABLE KYAELS +CED5;CED5;110F 1164 11B4;CED5;110F 1164 11B4; # (컕; 컕; 컕; 컕; 컕; ) HANGUL SYLLABLE KYAELT +CED6;CED6;110F 1164 11B5;CED6;110F 1164 11B5; # (컖; 컖; 컖; 컖; 컖; ) HANGUL SYLLABLE KYAELP +CED7;CED7;110F 1164 11B6;CED7;110F 1164 11B6; # (컗; 컗; 컗; 컗; 컗; ) HANGUL SYLLABLE KYAELH +CED8;CED8;110F 1164 11B7;CED8;110F 1164 11B7; # (컘; 컘; 컘; 컘; 컘; ) HANGUL SYLLABLE KYAEM +CED9;CED9;110F 1164 11B8;CED9;110F 1164 11B8; # (컙; 컙; 컙; 컙; 컙; ) HANGUL SYLLABLE KYAEB +CEDA;CEDA;110F 1164 11B9;CEDA;110F 1164 11B9; # (컚; 컚; 컚; 컚; 컚; ) HANGUL SYLLABLE KYAEBS +CEDB;CEDB;110F 1164 11BA;CEDB;110F 1164 11BA; # (컛; 컛; 컛; 컛; 컛; ) HANGUL SYLLABLE KYAES +CEDC;CEDC;110F 1164 11BB;CEDC;110F 1164 11BB; # (컜; 컜; 컜; 컜; 컜; ) HANGUL SYLLABLE KYAESS +CEDD;CEDD;110F 1164 11BC;CEDD;110F 1164 11BC; # (컝; 컝; 컝; 컝; 컝; ) HANGUL SYLLABLE KYAENG +CEDE;CEDE;110F 1164 11BD;CEDE;110F 1164 11BD; # (컞; 컞; 컞; 컞; 컞; ) HANGUL SYLLABLE KYAEJ +CEDF;CEDF;110F 1164 11BE;CEDF;110F 1164 11BE; # (컟; 컟; 컟; 컟; 컟; ) HANGUL SYLLABLE KYAEC +CEE0;CEE0;110F 1164 11BF;CEE0;110F 1164 11BF; # (컠; 컠; 컠; 컠; 컠; ) HANGUL SYLLABLE KYAEK +CEE1;CEE1;110F 1164 11C0;CEE1;110F 1164 11C0; # (컡; 컡; 컡; 컡; 컡; ) HANGUL SYLLABLE KYAET +CEE2;CEE2;110F 1164 11C1;CEE2;110F 1164 11C1; # (컢; 컢; 컢; 컢; 컢; ) HANGUL SYLLABLE KYAEP +CEE3;CEE3;110F 1164 11C2;CEE3;110F 1164 11C2; # (컣; 컣; 컣; 컣; 컣; ) HANGUL SYLLABLE KYAEH +CEE4;CEE4;110F 1165;CEE4;110F 1165; # (커; 커; 커; 커; 커; ) HANGUL SYLLABLE KEO +CEE5;CEE5;110F 1165 11A8;CEE5;110F 1165 11A8; # (컥; 컥; 컥; 컥; 컥; ) HANGUL SYLLABLE KEOG +CEE6;CEE6;110F 1165 11A9;CEE6;110F 1165 11A9; # (컦; 컦; 컦; 컦; 컦; ) HANGUL SYLLABLE KEOGG +CEE7;CEE7;110F 1165 11AA;CEE7;110F 1165 11AA; # (컧; 컧; 컧; 컧; 컧; ) HANGUL SYLLABLE KEOGS +CEE8;CEE8;110F 1165 11AB;CEE8;110F 1165 11AB; # (컨; 컨; 컨; 컨; 컨; ) HANGUL SYLLABLE KEON +CEE9;CEE9;110F 1165 11AC;CEE9;110F 1165 11AC; # (컩; 컩; 컩; 컩; 컩; ) HANGUL SYLLABLE KEONJ +CEEA;CEEA;110F 1165 11AD;CEEA;110F 1165 11AD; # (컪; 컪; 컪; 컪; 컪; ) HANGUL SYLLABLE KEONH +CEEB;CEEB;110F 1165 11AE;CEEB;110F 1165 11AE; # (컫; 컫; 컫; 컫; 컫; ) HANGUL SYLLABLE KEOD +CEEC;CEEC;110F 1165 11AF;CEEC;110F 1165 11AF; # (컬; 컬; 컬; 컬; 컬; ) HANGUL SYLLABLE KEOL +CEED;CEED;110F 1165 11B0;CEED;110F 1165 11B0; # (컭; 컭; 컭; 컭; 컭; ) HANGUL SYLLABLE KEOLG +CEEE;CEEE;110F 1165 11B1;CEEE;110F 1165 11B1; # (컮; 컮; 컮; 컮; 컮; ) HANGUL SYLLABLE KEOLM +CEEF;CEEF;110F 1165 11B2;CEEF;110F 1165 11B2; # (컯; 컯; 컯; 컯; 컯; ) HANGUL SYLLABLE KEOLB +CEF0;CEF0;110F 1165 11B3;CEF0;110F 1165 11B3; # (컰; 컰; 컰; 컰; 컰; ) HANGUL SYLLABLE KEOLS +CEF1;CEF1;110F 1165 11B4;CEF1;110F 1165 11B4; # (컱; 컱; 컱; 컱; 컱; ) HANGUL SYLLABLE KEOLT +CEF2;CEF2;110F 1165 11B5;CEF2;110F 1165 11B5; # (컲; 컲; 컲; 컲; 컲; ) HANGUL SYLLABLE KEOLP +CEF3;CEF3;110F 1165 11B6;CEF3;110F 1165 11B6; # (컳; 컳; 컳; 컳; 컳; ) HANGUL SYLLABLE KEOLH +CEF4;CEF4;110F 1165 11B7;CEF4;110F 1165 11B7; # (컴; 컴; 컴; 컴; 컴; ) HANGUL SYLLABLE KEOM +CEF5;CEF5;110F 1165 11B8;CEF5;110F 1165 11B8; # (컵; 컵; 컵; 컵; 컵; ) HANGUL SYLLABLE KEOB +CEF6;CEF6;110F 1165 11B9;CEF6;110F 1165 11B9; # (컶; 컶; 컶; 컶; 컶; ) HANGUL SYLLABLE KEOBS +CEF7;CEF7;110F 1165 11BA;CEF7;110F 1165 11BA; # (컷; 컷; 컷; 컷; 컷; ) HANGUL SYLLABLE KEOS +CEF8;CEF8;110F 1165 11BB;CEF8;110F 1165 11BB; # (컸; 컸; 컸; 컸; 컸; ) HANGUL SYLLABLE KEOSS +CEF9;CEF9;110F 1165 11BC;CEF9;110F 1165 11BC; # (컹; 컹; 컹; 컹; 컹; ) HANGUL SYLLABLE KEONG +CEFA;CEFA;110F 1165 11BD;CEFA;110F 1165 11BD; # (컺; 컺; 컺; 컺; 컺; ) HANGUL SYLLABLE KEOJ +CEFB;CEFB;110F 1165 11BE;CEFB;110F 1165 11BE; # (컻; 컻; 컻; 컻; 컻; ) HANGUL SYLLABLE KEOC +CEFC;CEFC;110F 1165 11BF;CEFC;110F 1165 11BF; # (컼; 컼; 컼; 컼; 컼; ) HANGUL SYLLABLE KEOK +CEFD;CEFD;110F 1165 11C0;CEFD;110F 1165 11C0; # (컽; 컽; 컽; 컽; 컽; ) HANGUL SYLLABLE KEOT +CEFE;CEFE;110F 1165 11C1;CEFE;110F 1165 11C1; # (컾; 컾; 컾; 컾; 컾; ) HANGUL SYLLABLE KEOP +CEFF;CEFF;110F 1165 11C2;CEFF;110F 1165 11C2; # (컿; 컿; 컿; 컿; 컿; ) HANGUL SYLLABLE KEOH +CF00;CF00;110F 1166;CF00;110F 1166; # (케; 케; 케; 케; 케; ) HANGUL SYLLABLE KE +CF01;CF01;110F 1166 11A8;CF01;110F 1166 11A8; # (켁; 켁; 켁; 켁; 켁; ) HANGUL SYLLABLE KEG +CF02;CF02;110F 1166 11A9;CF02;110F 1166 11A9; # (켂; 켂; 켂; 켂; 켂; ) HANGUL SYLLABLE KEGG +CF03;CF03;110F 1166 11AA;CF03;110F 1166 11AA; # (켃; 켃; 켃; 켃; 켃; ) HANGUL SYLLABLE KEGS +CF04;CF04;110F 1166 11AB;CF04;110F 1166 11AB; # (켄; 켄; 켄; 켄; 켄; ) HANGUL SYLLABLE KEN +CF05;CF05;110F 1166 11AC;CF05;110F 1166 11AC; # (켅; 켅; 켅; 켅; 켅; ) HANGUL SYLLABLE KENJ +CF06;CF06;110F 1166 11AD;CF06;110F 1166 11AD; # (켆; 켆; 켆; 켆; 켆; ) HANGUL SYLLABLE KENH +CF07;CF07;110F 1166 11AE;CF07;110F 1166 11AE; # (켇; 켇; 켇; 켇; 켇; ) HANGUL SYLLABLE KED +CF08;CF08;110F 1166 11AF;CF08;110F 1166 11AF; # (켈; 켈; 켈; 켈; 켈; ) HANGUL SYLLABLE KEL +CF09;CF09;110F 1166 11B0;CF09;110F 1166 11B0; # (켉; 켉; 켉; 켉; 켉; ) HANGUL SYLLABLE KELG +CF0A;CF0A;110F 1166 11B1;CF0A;110F 1166 11B1; # (켊; 켊; 켊; 켊; 켊; ) HANGUL SYLLABLE KELM +CF0B;CF0B;110F 1166 11B2;CF0B;110F 1166 11B2; # (켋; 켋; 켋; 켋; 켋; ) HANGUL SYLLABLE KELB +CF0C;CF0C;110F 1166 11B3;CF0C;110F 1166 11B3; # (켌; 켌; 켌; 켌; 켌; ) HANGUL SYLLABLE KELS +CF0D;CF0D;110F 1166 11B4;CF0D;110F 1166 11B4; # (켍; 켍; 켍; 켍; 켍; ) HANGUL SYLLABLE KELT +CF0E;CF0E;110F 1166 11B5;CF0E;110F 1166 11B5; # (켎; 켎; 켎; 켎; 켎; ) HANGUL SYLLABLE KELP +CF0F;CF0F;110F 1166 11B6;CF0F;110F 1166 11B6; # (켏; 켏; 켏; 켏; 켏; ) HANGUL SYLLABLE KELH +CF10;CF10;110F 1166 11B7;CF10;110F 1166 11B7; # (켐; 켐; 켐; 켐; 켐; ) HANGUL SYLLABLE KEM +CF11;CF11;110F 1166 11B8;CF11;110F 1166 11B8; # (켑; 켑; 켑; 켑; 켑; ) HANGUL SYLLABLE KEB +CF12;CF12;110F 1166 11B9;CF12;110F 1166 11B9; # (켒; 켒; 켒; 켒; 켒; ) HANGUL SYLLABLE KEBS +CF13;CF13;110F 1166 11BA;CF13;110F 1166 11BA; # (켓; 켓; 켓; 켓; 켓; ) HANGUL SYLLABLE KES +CF14;CF14;110F 1166 11BB;CF14;110F 1166 11BB; # (켔; 켔; 켔; 켔; 켔; ) HANGUL SYLLABLE KESS +CF15;CF15;110F 1166 11BC;CF15;110F 1166 11BC; # (켕; 켕; 켕; 켕; 켕; ) HANGUL SYLLABLE KENG +CF16;CF16;110F 1166 11BD;CF16;110F 1166 11BD; # (켖; 켖; 켖; 켖; 켖; ) HANGUL SYLLABLE KEJ +CF17;CF17;110F 1166 11BE;CF17;110F 1166 11BE; # (켗; 켗; 켗; 켗; 켗; ) HANGUL SYLLABLE KEC +CF18;CF18;110F 1166 11BF;CF18;110F 1166 11BF; # (켘; 켘; 켘; 켘; 켘; ) HANGUL SYLLABLE KEK +CF19;CF19;110F 1166 11C0;CF19;110F 1166 11C0; # (켙; 켙; 켙; 켙; 켙; ) HANGUL SYLLABLE KET +CF1A;CF1A;110F 1166 11C1;CF1A;110F 1166 11C1; # (켚; 켚; 켚; 켚; 켚; ) HANGUL SYLLABLE KEP +CF1B;CF1B;110F 1166 11C2;CF1B;110F 1166 11C2; # (켛; 켛; 켛; 켛; 켛; ) HANGUL SYLLABLE KEH +CF1C;CF1C;110F 1167;CF1C;110F 1167; # (켜; 켜; 켜; 켜; 켜; ) HANGUL SYLLABLE KYEO +CF1D;CF1D;110F 1167 11A8;CF1D;110F 1167 11A8; # (켝; 켝; 켝; 켝; 켝; ) HANGUL SYLLABLE KYEOG +CF1E;CF1E;110F 1167 11A9;CF1E;110F 1167 11A9; # (켞; 켞; 켞; 켞; 켞; ) HANGUL SYLLABLE KYEOGG +CF1F;CF1F;110F 1167 11AA;CF1F;110F 1167 11AA; # (켟; 켟; 켟; 켟; 켟; ) HANGUL SYLLABLE KYEOGS +CF20;CF20;110F 1167 11AB;CF20;110F 1167 11AB; # (켠; 켠; 켠; 켠; 켠; ) HANGUL SYLLABLE KYEON +CF21;CF21;110F 1167 11AC;CF21;110F 1167 11AC; # (켡; 켡; 켡; 켡; 켡; ) HANGUL SYLLABLE KYEONJ +CF22;CF22;110F 1167 11AD;CF22;110F 1167 11AD; # (켢; 켢; 켢; 켢; 켢; ) HANGUL SYLLABLE KYEONH +CF23;CF23;110F 1167 11AE;CF23;110F 1167 11AE; # (켣; 켣; 켣; 켣; 켣; ) HANGUL SYLLABLE KYEOD +CF24;CF24;110F 1167 11AF;CF24;110F 1167 11AF; # (켤; 켤; 켤; 켤; 켤; ) HANGUL SYLLABLE KYEOL +CF25;CF25;110F 1167 11B0;CF25;110F 1167 11B0; # (켥; 켥; 켥; 켥; 켥; ) HANGUL SYLLABLE KYEOLG +CF26;CF26;110F 1167 11B1;CF26;110F 1167 11B1; # (켦; 켦; 켦; 켦; 켦; ) HANGUL SYLLABLE KYEOLM +CF27;CF27;110F 1167 11B2;CF27;110F 1167 11B2; # (켧; 켧; 켧; 켧; 켧; ) HANGUL SYLLABLE KYEOLB +CF28;CF28;110F 1167 11B3;CF28;110F 1167 11B3; # (켨; 켨; 켨; 켨; 켨; ) HANGUL SYLLABLE KYEOLS +CF29;CF29;110F 1167 11B4;CF29;110F 1167 11B4; # (켩; 켩; 켩; 켩; 켩; ) HANGUL SYLLABLE KYEOLT +CF2A;CF2A;110F 1167 11B5;CF2A;110F 1167 11B5; # (켪; 켪; 켪; 켪; 켪; ) HANGUL SYLLABLE KYEOLP +CF2B;CF2B;110F 1167 11B6;CF2B;110F 1167 11B6; # (켫; 켫; 켫; 켫; 켫; ) HANGUL SYLLABLE KYEOLH +CF2C;CF2C;110F 1167 11B7;CF2C;110F 1167 11B7; # (켬; 켬; 켬; 켬; 켬; ) HANGUL SYLLABLE KYEOM +CF2D;CF2D;110F 1167 11B8;CF2D;110F 1167 11B8; # (켭; 켭; 켭; 켭; 켭; ) HANGUL SYLLABLE KYEOB +CF2E;CF2E;110F 1167 11B9;CF2E;110F 1167 11B9; # (켮; 켮; 켮; 켮; 켮; ) HANGUL SYLLABLE KYEOBS +CF2F;CF2F;110F 1167 11BA;CF2F;110F 1167 11BA; # (켯; 켯; 켯; 켯; 켯; ) HANGUL SYLLABLE KYEOS +CF30;CF30;110F 1167 11BB;CF30;110F 1167 11BB; # (켰; 켰; 켰; 켰; 켰; ) HANGUL SYLLABLE KYEOSS +CF31;CF31;110F 1167 11BC;CF31;110F 1167 11BC; # (켱; 켱; 켱; 켱; 켱; ) HANGUL SYLLABLE KYEONG +CF32;CF32;110F 1167 11BD;CF32;110F 1167 11BD; # (켲; 켲; 켲; 켲; 켲; ) HANGUL SYLLABLE KYEOJ +CF33;CF33;110F 1167 11BE;CF33;110F 1167 11BE; # (켳; 켳; 켳; 켳; 켳; ) HANGUL SYLLABLE KYEOC +CF34;CF34;110F 1167 11BF;CF34;110F 1167 11BF; # (켴; 켴; 켴; 켴; 켴; ) HANGUL SYLLABLE KYEOK +CF35;CF35;110F 1167 11C0;CF35;110F 1167 11C0; # (켵; 켵; 켵; 켵; 켵; ) HANGUL SYLLABLE KYEOT +CF36;CF36;110F 1167 11C1;CF36;110F 1167 11C1; # (켶; 켶; 켶; 켶; 켶; ) HANGUL SYLLABLE KYEOP +CF37;CF37;110F 1167 11C2;CF37;110F 1167 11C2; # (켷; 켷; 켷; 켷; 켷; ) HANGUL SYLLABLE KYEOH +CF38;CF38;110F 1168;CF38;110F 1168; # (켸; 켸; 켸; 켸; 켸; ) HANGUL SYLLABLE KYE +CF39;CF39;110F 1168 11A8;CF39;110F 1168 11A8; # (켹; 켹; 켹; 켹; 켹; ) HANGUL SYLLABLE KYEG +CF3A;CF3A;110F 1168 11A9;CF3A;110F 1168 11A9; # (켺; 켺; 켺; 켺; 켺; ) HANGUL SYLLABLE KYEGG +CF3B;CF3B;110F 1168 11AA;CF3B;110F 1168 11AA; # (켻; 켻; 켻; 켻; 켻; ) HANGUL SYLLABLE KYEGS +CF3C;CF3C;110F 1168 11AB;CF3C;110F 1168 11AB; # (켼; 켼; 켼; 켼; 켼; ) HANGUL SYLLABLE KYEN +CF3D;CF3D;110F 1168 11AC;CF3D;110F 1168 11AC; # (켽; 켽; 켽; 켽; 켽; ) HANGUL SYLLABLE KYENJ +CF3E;CF3E;110F 1168 11AD;CF3E;110F 1168 11AD; # (켾; 켾; 켾; 켾; 켾; ) HANGUL SYLLABLE KYENH +CF3F;CF3F;110F 1168 11AE;CF3F;110F 1168 11AE; # (켿; 켿; 켿; 켿; 켿; ) HANGUL SYLLABLE KYED +CF40;CF40;110F 1168 11AF;CF40;110F 1168 11AF; # (콀; 콀; 콀; 콀; 콀; ) HANGUL SYLLABLE KYEL +CF41;CF41;110F 1168 11B0;CF41;110F 1168 11B0; # (콁; 콁; 콁; 콁; 콁; ) HANGUL SYLLABLE KYELG +CF42;CF42;110F 1168 11B1;CF42;110F 1168 11B1; # (콂; 콂; 콂; 콂; 콂; ) HANGUL SYLLABLE KYELM +CF43;CF43;110F 1168 11B2;CF43;110F 1168 11B2; # (콃; 콃; 콃; 콃; 콃; ) HANGUL SYLLABLE KYELB +CF44;CF44;110F 1168 11B3;CF44;110F 1168 11B3; # (콄; 콄; 콄; 콄; 콄; ) HANGUL SYLLABLE KYELS +CF45;CF45;110F 1168 11B4;CF45;110F 1168 11B4; # (콅; 콅; 콅; 콅; 콅; ) HANGUL SYLLABLE KYELT +CF46;CF46;110F 1168 11B5;CF46;110F 1168 11B5; # (콆; 콆; 콆; 콆; 콆; ) HANGUL SYLLABLE KYELP +CF47;CF47;110F 1168 11B6;CF47;110F 1168 11B6; # (콇; 콇; 콇; 콇; 콇; ) HANGUL SYLLABLE KYELH +CF48;CF48;110F 1168 11B7;CF48;110F 1168 11B7; # (콈; 콈; 콈; 콈; 콈; ) HANGUL SYLLABLE KYEM +CF49;CF49;110F 1168 11B8;CF49;110F 1168 11B8; # (콉; 콉; 콉; 콉; 콉; ) HANGUL SYLLABLE KYEB +CF4A;CF4A;110F 1168 11B9;CF4A;110F 1168 11B9; # (콊; 콊; 콊; 콊; 콊; ) HANGUL SYLLABLE KYEBS +CF4B;CF4B;110F 1168 11BA;CF4B;110F 1168 11BA; # (콋; 콋; 콋; 콋; 콋; ) HANGUL SYLLABLE KYES +CF4C;CF4C;110F 1168 11BB;CF4C;110F 1168 11BB; # (콌; 콌; 콌; 콌; 콌; ) HANGUL SYLLABLE KYESS +CF4D;CF4D;110F 1168 11BC;CF4D;110F 1168 11BC; # (콍; 콍; 콍; 콍; 콍; ) HANGUL SYLLABLE KYENG +CF4E;CF4E;110F 1168 11BD;CF4E;110F 1168 11BD; # (콎; 콎; 콎; 콎; 콎; ) HANGUL SYLLABLE KYEJ +CF4F;CF4F;110F 1168 11BE;CF4F;110F 1168 11BE; # (콏; 콏; 콏; 콏; 콏; ) HANGUL SYLLABLE KYEC +CF50;CF50;110F 1168 11BF;CF50;110F 1168 11BF; # (콐; 콐; 콐; 콐; 콐; ) HANGUL SYLLABLE KYEK +CF51;CF51;110F 1168 11C0;CF51;110F 1168 11C0; # (콑; 콑; 콑; 콑; 콑; ) HANGUL SYLLABLE KYET +CF52;CF52;110F 1168 11C1;CF52;110F 1168 11C1; # (콒; 콒; 콒; 콒; 콒; ) HANGUL SYLLABLE KYEP +CF53;CF53;110F 1168 11C2;CF53;110F 1168 11C2; # (콓; 콓; 콓; 콓; 콓; ) HANGUL SYLLABLE KYEH +CF54;CF54;110F 1169;CF54;110F 1169; # (코; 코; 코; 코; 코; ) HANGUL SYLLABLE KO +CF55;CF55;110F 1169 11A8;CF55;110F 1169 11A8; # (콕; 콕; 콕; 콕; 콕; ) HANGUL SYLLABLE KOG +CF56;CF56;110F 1169 11A9;CF56;110F 1169 11A9; # (콖; 콖; 콖; 콖; 콖; ) HANGUL SYLLABLE KOGG +CF57;CF57;110F 1169 11AA;CF57;110F 1169 11AA; # (콗; 콗; 콗; 콗; 콗; ) HANGUL SYLLABLE KOGS +CF58;CF58;110F 1169 11AB;CF58;110F 1169 11AB; # (콘; 콘; 콘; 콘; 콘; ) HANGUL SYLLABLE KON +CF59;CF59;110F 1169 11AC;CF59;110F 1169 11AC; # (콙; 콙; 콙; 콙; 콙; ) HANGUL SYLLABLE KONJ +CF5A;CF5A;110F 1169 11AD;CF5A;110F 1169 11AD; # (콚; 콚; 콚; 콚; 콚; ) HANGUL SYLLABLE KONH +CF5B;CF5B;110F 1169 11AE;CF5B;110F 1169 11AE; # (콛; 콛; 콛; 콛; 콛; ) HANGUL SYLLABLE KOD +CF5C;CF5C;110F 1169 11AF;CF5C;110F 1169 11AF; # (콜; 콜; 콜; 콜; 콜; ) HANGUL SYLLABLE KOL +CF5D;CF5D;110F 1169 11B0;CF5D;110F 1169 11B0; # (콝; 콝; 콝; 콝; 콝; ) HANGUL SYLLABLE KOLG +CF5E;CF5E;110F 1169 11B1;CF5E;110F 1169 11B1; # (콞; 콞; 콞; 콞; 콞; ) HANGUL SYLLABLE KOLM +CF5F;CF5F;110F 1169 11B2;CF5F;110F 1169 11B2; # (콟; 콟; 콟; 콟; 콟; ) HANGUL SYLLABLE KOLB +CF60;CF60;110F 1169 11B3;CF60;110F 1169 11B3; # (콠; 콠; 콠; 콠; 콠; ) HANGUL SYLLABLE KOLS +CF61;CF61;110F 1169 11B4;CF61;110F 1169 11B4; # (콡; 콡; 콡; 콡; 콡; ) HANGUL SYLLABLE KOLT +CF62;CF62;110F 1169 11B5;CF62;110F 1169 11B5; # (콢; 콢; 콢; 콢; 콢; ) HANGUL SYLLABLE KOLP +CF63;CF63;110F 1169 11B6;CF63;110F 1169 11B6; # (콣; 콣; 콣; 콣; 콣; ) HANGUL SYLLABLE KOLH +CF64;CF64;110F 1169 11B7;CF64;110F 1169 11B7; # (콤; 콤; 콤; 콤; 콤; ) HANGUL SYLLABLE KOM +CF65;CF65;110F 1169 11B8;CF65;110F 1169 11B8; # (콥; 콥; 콥; 콥; 콥; ) HANGUL SYLLABLE KOB +CF66;CF66;110F 1169 11B9;CF66;110F 1169 11B9; # (콦; 콦; 콦; 콦; 콦; ) HANGUL SYLLABLE KOBS +CF67;CF67;110F 1169 11BA;CF67;110F 1169 11BA; # (콧; 콧; 콧; 콧; 콧; ) HANGUL SYLLABLE KOS +CF68;CF68;110F 1169 11BB;CF68;110F 1169 11BB; # (콨; 콨; 콨; 콨; 콨; ) HANGUL SYLLABLE KOSS +CF69;CF69;110F 1169 11BC;CF69;110F 1169 11BC; # (콩; 콩; 콩; 콩; 콩; ) HANGUL SYLLABLE KONG +CF6A;CF6A;110F 1169 11BD;CF6A;110F 1169 11BD; # (콪; 콪; 콪; 콪; 콪; ) HANGUL SYLLABLE KOJ +CF6B;CF6B;110F 1169 11BE;CF6B;110F 1169 11BE; # (콫; 콫; 콫; 콫; 콫; ) HANGUL SYLLABLE KOC +CF6C;CF6C;110F 1169 11BF;CF6C;110F 1169 11BF; # (콬; 콬; 콬; 콬; 콬; ) HANGUL SYLLABLE KOK +CF6D;CF6D;110F 1169 11C0;CF6D;110F 1169 11C0; # (콭; 콭; 콭; 콭; 콭; ) HANGUL SYLLABLE KOT +CF6E;CF6E;110F 1169 11C1;CF6E;110F 1169 11C1; # (콮; 콮; 콮; 콮; 콮; ) HANGUL SYLLABLE KOP +CF6F;CF6F;110F 1169 11C2;CF6F;110F 1169 11C2; # (콯; 콯; 콯; 콯; 콯; ) HANGUL SYLLABLE KOH +CF70;CF70;110F 116A;CF70;110F 116A; # (콰; 콰; 콰; 콰; 콰; ) HANGUL SYLLABLE KWA +CF71;CF71;110F 116A 11A8;CF71;110F 116A 11A8; # (콱; 콱; 콱; 콱; 콱; ) HANGUL SYLLABLE KWAG +CF72;CF72;110F 116A 11A9;CF72;110F 116A 11A9; # (콲; 콲; 콲; 콲; 콲; ) HANGUL SYLLABLE KWAGG +CF73;CF73;110F 116A 11AA;CF73;110F 116A 11AA; # (콳; 콳; 콳; 콳; 콳; ) HANGUL SYLLABLE KWAGS +CF74;CF74;110F 116A 11AB;CF74;110F 116A 11AB; # (콴; 콴; 콴; 콴; 콴; ) HANGUL SYLLABLE KWAN +CF75;CF75;110F 116A 11AC;CF75;110F 116A 11AC; # (콵; 콵; 콵; 콵; 콵; ) HANGUL SYLLABLE KWANJ +CF76;CF76;110F 116A 11AD;CF76;110F 116A 11AD; # (콶; 콶; 콶; 콶; 콶; ) HANGUL SYLLABLE KWANH +CF77;CF77;110F 116A 11AE;CF77;110F 116A 11AE; # (콷; 콷; 콷; 콷; 콷; ) HANGUL SYLLABLE KWAD +CF78;CF78;110F 116A 11AF;CF78;110F 116A 11AF; # (콸; 콸; 콸; 콸; 콸; ) HANGUL SYLLABLE KWAL +CF79;CF79;110F 116A 11B0;CF79;110F 116A 11B0; # (콹; 콹; 콹; 콹; 콹; ) HANGUL SYLLABLE KWALG +CF7A;CF7A;110F 116A 11B1;CF7A;110F 116A 11B1; # (콺; 콺; 콺; 콺; 콺; ) HANGUL SYLLABLE KWALM +CF7B;CF7B;110F 116A 11B2;CF7B;110F 116A 11B2; # (콻; 콻; 콻; 콻; 콻; ) HANGUL SYLLABLE KWALB +CF7C;CF7C;110F 116A 11B3;CF7C;110F 116A 11B3; # (콼; 콼; 콼; 콼; 콼; ) HANGUL SYLLABLE KWALS +CF7D;CF7D;110F 116A 11B4;CF7D;110F 116A 11B4; # (콽; 콽; 콽; 콽; 콽; ) HANGUL SYLLABLE KWALT +CF7E;CF7E;110F 116A 11B5;CF7E;110F 116A 11B5; # (콾; 콾; 콾; 콾; 콾; ) HANGUL SYLLABLE KWALP +CF7F;CF7F;110F 116A 11B6;CF7F;110F 116A 11B6; # (콿; 콿; 콿; 콿; 콿; ) HANGUL SYLLABLE KWALH +CF80;CF80;110F 116A 11B7;CF80;110F 116A 11B7; # (쾀; 쾀; 쾀; 쾀; 쾀; ) HANGUL SYLLABLE KWAM +CF81;CF81;110F 116A 11B8;CF81;110F 116A 11B8; # (쾁; 쾁; 쾁; 쾁; 쾁; ) HANGUL SYLLABLE KWAB +CF82;CF82;110F 116A 11B9;CF82;110F 116A 11B9; # (쾂; 쾂; 쾂; 쾂; 쾂; ) HANGUL SYLLABLE KWABS +CF83;CF83;110F 116A 11BA;CF83;110F 116A 11BA; # (쾃; 쾃; 쾃; 쾃; 쾃; ) HANGUL SYLLABLE KWAS +CF84;CF84;110F 116A 11BB;CF84;110F 116A 11BB; # (쾄; 쾄; 쾄; 쾄; 쾄; ) HANGUL SYLLABLE KWASS +CF85;CF85;110F 116A 11BC;CF85;110F 116A 11BC; # (쾅; 쾅; 쾅; 쾅; 쾅; ) HANGUL SYLLABLE KWANG +CF86;CF86;110F 116A 11BD;CF86;110F 116A 11BD; # (쾆; 쾆; 쾆; 쾆; 쾆; ) HANGUL SYLLABLE KWAJ +CF87;CF87;110F 116A 11BE;CF87;110F 116A 11BE; # (쾇; 쾇; 쾇; 쾇; 쾇; ) HANGUL SYLLABLE KWAC +CF88;CF88;110F 116A 11BF;CF88;110F 116A 11BF; # (쾈; 쾈; 쾈; 쾈; 쾈; ) HANGUL SYLLABLE KWAK +CF89;CF89;110F 116A 11C0;CF89;110F 116A 11C0; # (쾉; 쾉; 쾉; 쾉; 쾉; ) HANGUL SYLLABLE KWAT +CF8A;CF8A;110F 116A 11C1;CF8A;110F 116A 11C1; # (쾊; 쾊; 쾊; 쾊; 쾊; ) HANGUL SYLLABLE KWAP +CF8B;CF8B;110F 116A 11C2;CF8B;110F 116A 11C2; # (쾋; 쾋; 쾋; 쾋; 쾋; ) HANGUL SYLLABLE KWAH +CF8C;CF8C;110F 116B;CF8C;110F 116B; # (쾌; 쾌; 쾌; 쾌; 쾌; ) HANGUL SYLLABLE KWAE +CF8D;CF8D;110F 116B 11A8;CF8D;110F 116B 11A8; # (쾍; 쾍; 쾍; 쾍; 쾍; ) HANGUL SYLLABLE KWAEG +CF8E;CF8E;110F 116B 11A9;CF8E;110F 116B 11A9; # (쾎; 쾎; 쾎; 쾎; 쾎; ) HANGUL SYLLABLE KWAEGG +CF8F;CF8F;110F 116B 11AA;CF8F;110F 116B 11AA; # (쾏; 쾏; 쾏; 쾏; 쾏; ) HANGUL SYLLABLE KWAEGS +CF90;CF90;110F 116B 11AB;CF90;110F 116B 11AB; # (쾐; 쾐; 쾐; 쾐; 쾐; ) HANGUL SYLLABLE KWAEN +CF91;CF91;110F 116B 11AC;CF91;110F 116B 11AC; # (쾑; 쾑; 쾑; 쾑; 쾑; ) HANGUL SYLLABLE KWAENJ +CF92;CF92;110F 116B 11AD;CF92;110F 116B 11AD; # (쾒; 쾒; 쾒; 쾒; 쾒; ) HANGUL SYLLABLE KWAENH +CF93;CF93;110F 116B 11AE;CF93;110F 116B 11AE; # (쾓; 쾓; 쾓; 쾓; 쾓; ) HANGUL SYLLABLE KWAED +CF94;CF94;110F 116B 11AF;CF94;110F 116B 11AF; # (쾔; 쾔; 쾔; 쾔; 쾔; ) HANGUL SYLLABLE KWAEL +CF95;CF95;110F 116B 11B0;CF95;110F 116B 11B0; # (쾕; 쾕; 쾕; 쾕; 쾕; ) HANGUL SYLLABLE KWAELG +CF96;CF96;110F 116B 11B1;CF96;110F 116B 11B1; # (쾖; 쾖; 쾖; 쾖; 쾖; ) HANGUL SYLLABLE KWAELM +CF97;CF97;110F 116B 11B2;CF97;110F 116B 11B2; # (쾗; 쾗; 쾗; 쾗; 쾗; ) HANGUL SYLLABLE KWAELB +CF98;CF98;110F 116B 11B3;CF98;110F 116B 11B3; # (쾘; 쾘; 쾘; 쾘; 쾘; ) HANGUL SYLLABLE KWAELS +CF99;CF99;110F 116B 11B4;CF99;110F 116B 11B4; # (쾙; 쾙; 쾙; 쾙; 쾙; ) HANGUL SYLLABLE KWAELT +CF9A;CF9A;110F 116B 11B5;CF9A;110F 116B 11B5; # (쾚; 쾚; 쾚; 쾚; 쾚; ) HANGUL SYLLABLE KWAELP +CF9B;CF9B;110F 116B 11B6;CF9B;110F 116B 11B6; # (쾛; 쾛; 쾛; 쾛; 쾛; ) HANGUL SYLLABLE KWAELH +CF9C;CF9C;110F 116B 11B7;CF9C;110F 116B 11B7; # (쾜; 쾜; 쾜; 쾜; 쾜; ) HANGUL SYLLABLE KWAEM +CF9D;CF9D;110F 116B 11B8;CF9D;110F 116B 11B8; # (쾝; 쾝; 쾝; 쾝; 쾝; ) HANGUL SYLLABLE KWAEB +CF9E;CF9E;110F 116B 11B9;CF9E;110F 116B 11B9; # (쾞; 쾞; 쾞; 쾞; 쾞; ) HANGUL SYLLABLE KWAEBS +CF9F;CF9F;110F 116B 11BA;CF9F;110F 116B 11BA; # (쾟; 쾟; 쾟; 쾟; 쾟; ) HANGUL SYLLABLE KWAES +CFA0;CFA0;110F 116B 11BB;CFA0;110F 116B 11BB; # (쾠; 쾠; 쾠; 쾠; 쾠; ) HANGUL SYLLABLE KWAESS +CFA1;CFA1;110F 116B 11BC;CFA1;110F 116B 11BC; # (쾡; 쾡; 쾡; 쾡; 쾡; ) HANGUL SYLLABLE KWAENG +CFA2;CFA2;110F 116B 11BD;CFA2;110F 116B 11BD; # (쾢; 쾢; 쾢; 쾢; 쾢; ) HANGUL SYLLABLE KWAEJ +CFA3;CFA3;110F 116B 11BE;CFA3;110F 116B 11BE; # (쾣; 쾣; 쾣; 쾣; 쾣; ) HANGUL SYLLABLE KWAEC +CFA4;CFA4;110F 116B 11BF;CFA4;110F 116B 11BF; # (쾤; 쾤; 쾤; 쾤; 쾤; ) HANGUL SYLLABLE KWAEK +CFA5;CFA5;110F 116B 11C0;CFA5;110F 116B 11C0; # (쾥; 쾥; 쾥; 쾥; 쾥; ) HANGUL SYLLABLE KWAET +CFA6;CFA6;110F 116B 11C1;CFA6;110F 116B 11C1; # (쾦; 쾦; 쾦; 쾦; 쾦; ) HANGUL SYLLABLE KWAEP +CFA7;CFA7;110F 116B 11C2;CFA7;110F 116B 11C2; # (쾧; 쾧; 쾧; 쾧; 쾧; ) HANGUL SYLLABLE KWAEH +CFA8;CFA8;110F 116C;CFA8;110F 116C; # (쾨; 쾨; 쾨; 쾨; 쾨; ) HANGUL SYLLABLE KOE +CFA9;CFA9;110F 116C 11A8;CFA9;110F 116C 11A8; # (쾩; 쾩; 쾩; 쾩; 쾩; ) HANGUL SYLLABLE KOEG +CFAA;CFAA;110F 116C 11A9;CFAA;110F 116C 11A9; # (쾪; 쾪; 쾪; 쾪; 쾪; ) HANGUL SYLLABLE KOEGG +CFAB;CFAB;110F 116C 11AA;CFAB;110F 116C 11AA; # (쾫; 쾫; 쾫; 쾫; 쾫; ) HANGUL SYLLABLE KOEGS +CFAC;CFAC;110F 116C 11AB;CFAC;110F 116C 11AB; # (쾬; 쾬; 쾬; 쾬; 쾬; ) HANGUL SYLLABLE KOEN +CFAD;CFAD;110F 116C 11AC;CFAD;110F 116C 11AC; # (쾭; 쾭; 쾭; 쾭; 쾭; ) HANGUL SYLLABLE KOENJ +CFAE;CFAE;110F 116C 11AD;CFAE;110F 116C 11AD; # (쾮; 쾮; 쾮; 쾮; 쾮; ) HANGUL SYLLABLE KOENH +CFAF;CFAF;110F 116C 11AE;CFAF;110F 116C 11AE; # (쾯; 쾯; 쾯; 쾯; 쾯; ) HANGUL SYLLABLE KOED +CFB0;CFB0;110F 116C 11AF;CFB0;110F 116C 11AF; # (쾰; 쾰; 쾰; 쾰; 쾰; ) HANGUL SYLLABLE KOEL +CFB1;CFB1;110F 116C 11B0;CFB1;110F 116C 11B0; # (쾱; 쾱; 쾱; 쾱; 쾱; ) HANGUL SYLLABLE KOELG +CFB2;CFB2;110F 116C 11B1;CFB2;110F 116C 11B1; # (쾲; 쾲; 쾲; 쾲; 쾲; ) HANGUL SYLLABLE KOELM +CFB3;CFB3;110F 116C 11B2;CFB3;110F 116C 11B2; # (쾳; 쾳; 쾳; 쾳; 쾳; ) HANGUL SYLLABLE KOELB +CFB4;CFB4;110F 116C 11B3;CFB4;110F 116C 11B3; # (쾴; 쾴; 쾴; 쾴; 쾴; ) HANGUL SYLLABLE KOELS +CFB5;CFB5;110F 116C 11B4;CFB5;110F 116C 11B4; # (쾵; 쾵; 쾵; 쾵; 쾵; ) HANGUL SYLLABLE KOELT +CFB6;CFB6;110F 116C 11B5;CFB6;110F 116C 11B5; # (쾶; 쾶; 쾶; 쾶; 쾶; ) HANGUL SYLLABLE KOELP +CFB7;CFB7;110F 116C 11B6;CFB7;110F 116C 11B6; # (쾷; 쾷; 쾷; 쾷; 쾷; ) HANGUL SYLLABLE KOELH +CFB8;CFB8;110F 116C 11B7;CFB8;110F 116C 11B7; # (쾸; 쾸; 쾸; 쾸; 쾸; ) HANGUL SYLLABLE KOEM +CFB9;CFB9;110F 116C 11B8;CFB9;110F 116C 11B8; # (쾹; 쾹; 쾹; 쾹; 쾹; ) HANGUL SYLLABLE KOEB +CFBA;CFBA;110F 116C 11B9;CFBA;110F 116C 11B9; # (쾺; 쾺; 쾺; 쾺; 쾺; ) HANGUL SYLLABLE KOEBS +CFBB;CFBB;110F 116C 11BA;CFBB;110F 116C 11BA; # (쾻; 쾻; 쾻; 쾻; 쾻; ) HANGUL SYLLABLE KOES +CFBC;CFBC;110F 116C 11BB;CFBC;110F 116C 11BB; # (쾼; 쾼; 쾼; 쾼; 쾼; ) HANGUL SYLLABLE KOESS +CFBD;CFBD;110F 116C 11BC;CFBD;110F 116C 11BC; # (쾽; 쾽; 쾽; 쾽; 쾽; ) HANGUL SYLLABLE KOENG +CFBE;CFBE;110F 116C 11BD;CFBE;110F 116C 11BD; # (쾾; 쾾; 쾾; 쾾; 쾾; ) HANGUL SYLLABLE KOEJ +CFBF;CFBF;110F 116C 11BE;CFBF;110F 116C 11BE; # (쾿; 쾿; 쾿; 쾿; 쾿; ) HANGUL SYLLABLE KOEC +CFC0;CFC0;110F 116C 11BF;CFC0;110F 116C 11BF; # (쿀; 쿀; 쿀; 쿀; 쿀; ) HANGUL SYLLABLE KOEK +CFC1;CFC1;110F 116C 11C0;CFC1;110F 116C 11C0; # (쿁; 쿁; 쿁; 쿁; 쿁; ) HANGUL SYLLABLE KOET +CFC2;CFC2;110F 116C 11C1;CFC2;110F 116C 11C1; # (쿂; 쿂; 쿂; 쿂; 쿂; ) HANGUL SYLLABLE KOEP +CFC3;CFC3;110F 116C 11C2;CFC3;110F 116C 11C2; # (쿃; 쿃; 쿃; 쿃; 쿃; ) HANGUL SYLLABLE KOEH +CFC4;CFC4;110F 116D;CFC4;110F 116D; # (쿄; 쿄; 쿄; 쿄; 쿄; ) HANGUL SYLLABLE KYO +CFC5;CFC5;110F 116D 11A8;CFC5;110F 116D 11A8; # (쿅; 쿅; 쿅; 쿅; 쿅; ) HANGUL SYLLABLE KYOG +CFC6;CFC6;110F 116D 11A9;CFC6;110F 116D 11A9; # (쿆; 쿆; 쿆; 쿆; 쿆; ) HANGUL SYLLABLE KYOGG +CFC7;CFC7;110F 116D 11AA;CFC7;110F 116D 11AA; # (쿇; 쿇; 쿇; 쿇; 쿇; ) HANGUL SYLLABLE KYOGS +CFC8;CFC8;110F 116D 11AB;CFC8;110F 116D 11AB; # (쿈; 쿈; 쿈; 쿈; 쿈; ) HANGUL SYLLABLE KYON +CFC9;CFC9;110F 116D 11AC;CFC9;110F 116D 11AC; # (쿉; 쿉; 쿉; 쿉; 쿉; ) HANGUL SYLLABLE KYONJ +CFCA;CFCA;110F 116D 11AD;CFCA;110F 116D 11AD; # (쿊; 쿊; 쿊; 쿊; 쿊; ) HANGUL SYLLABLE KYONH +CFCB;CFCB;110F 116D 11AE;CFCB;110F 116D 11AE; # (쿋; 쿋; 쿋; 쿋; 쿋; ) HANGUL SYLLABLE KYOD +CFCC;CFCC;110F 116D 11AF;CFCC;110F 116D 11AF; # (쿌; 쿌; 쿌; 쿌; 쿌; ) HANGUL SYLLABLE KYOL +CFCD;CFCD;110F 116D 11B0;CFCD;110F 116D 11B0; # (쿍; 쿍; 쿍; 쿍; 쿍; ) HANGUL SYLLABLE KYOLG +CFCE;CFCE;110F 116D 11B1;CFCE;110F 116D 11B1; # (쿎; 쿎; 쿎; 쿎; 쿎; ) HANGUL SYLLABLE KYOLM +CFCF;CFCF;110F 116D 11B2;CFCF;110F 116D 11B2; # (쿏; 쿏; 쿏; 쿏; 쿏; ) HANGUL SYLLABLE KYOLB +CFD0;CFD0;110F 116D 11B3;CFD0;110F 116D 11B3; # (쿐; 쿐; 쿐; 쿐; 쿐; ) HANGUL SYLLABLE KYOLS +CFD1;CFD1;110F 116D 11B4;CFD1;110F 116D 11B4; # (쿑; 쿑; 쿑; 쿑; 쿑; ) HANGUL SYLLABLE KYOLT +CFD2;CFD2;110F 116D 11B5;CFD2;110F 116D 11B5; # (쿒; 쿒; 쿒; 쿒; 쿒; ) HANGUL SYLLABLE KYOLP +CFD3;CFD3;110F 116D 11B6;CFD3;110F 116D 11B6; # (쿓; 쿓; 쿓; 쿓; 쿓; ) HANGUL SYLLABLE KYOLH +CFD4;CFD4;110F 116D 11B7;CFD4;110F 116D 11B7; # (쿔; 쿔; 쿔; 쿔; 쿔; ) HANGUL SYLLABLE KYOM +CFD5;CFD5;110F 116D 11B8;CFD5;110F 116D 11B8; # (쿕; 쿕; 쿕; 쿕; 쿕; ) HANGUL SYLLABLE KYOB +CFD6;CFD6;110F 116D 11B9;CFD6;110F 116D 11B9; # (쿖; 쿖; 쿖; 쿖; 쿖; ) HANGUL SYLLABLE KYOBS +CFD7;CFD7;110F 116D 11BA;CFD7;110F 116D 11BA; # (쿗; 쿗; 쿗; 쿗; 쿗; ) HANGUL SYLLABLE KYOS +CFD8;CFD8;110F 116D 11BB;CFD8;110F 116D 11BB; # (쿘; 쿘; 쿘; 쿘; 쿘; ) HANGUL SYLLABLE KYOSS +CFD9;CFD9;110F 116D 11BC;CFD9;110F 116D 11BC; # (쿙; 쿙; 쿙; 쿙; 쿙; ) HANGUL SYLLABLE KYONG +CFDA;CFDA;110F 116D 11BD;CFDA;110F 116D 11BD; # (쿚; 쿚; 쿚; 쿚; 쿚; ) HANGUL SYLLABLE KYOJ +CFDB;CFDB;110F 116D 11BE;CFDB;110F 116D 11BE; # (쿛; 쿛; 쿛; 쿛; 쿛; ) HANGUL SYLLABLE KYOC +CFDC;CFDC;110F 116D 11BF;CFDC;110F 116D 11BF; # (쿜; 쿜; 쿜; 쿜; 쿜; ) HANGUL SYLLABLE KYOK +CFDD;CFDD;110F 116D 11C0;CFDD;110F 116D 11C0; # (쿝; 쿝; 쿝; 쿝; 쿝; ) HANGUL SYLLABLE KYOT +CFDE;CFDE;110F 116D 11C1;CFDE;110F 116D 11C1; # (쿞; 쿞; 쿞; 쿞; 쿞; ) HANGUL SYLLABLE KYOP +CFDF;CFDF;110F 116D 11C2;CFDF;110F 116D 11C2; # (쿟; 쿟; 쿟; 쿟; 쿟; ) HANGUL SYLLABLE KYOH +CFE0;CFE0;110F 116E;CFE0;110F 116E; # (쿠; 쿠; 쿠; 쿠; 쿠; ) HANGUL SYLLABLE KU +CFE1;CFE1;110F 116E 11A8;CFE1;110F 116E 11A8; # (쿡; 쿡; 쿡; 쿡; 쿡; ) HANGUL SYLLABLE KUG +CFE2;CFE2;110F 116E 11A9;CFE2;110F 116E 11A9; # (쿢; 쿢; 쿢; 쿢; 쿢; ) HANGUL SYLLABLE KUGG +CFE3;CFE3;110F 116E 11AA;CFE3;110F 116E 11AA; # (쿣; 쿣; 쿣; 쿣; 쿣; ) HANGUL SYLLABLE KUGS +CFE4;CFE4;110F 116E 11AB;CFE4;110F 116E 11AB; # (쿤; 쿤; 쿤; 쿤; 쿤; ) HANGUL SYLLABLE KUN +CFE5;CFE5;110F 116E 11AC;CFE5;110F 116E 11AC; # (쿥; 쿥; 쿥; 쿥; 쿥; ) HANGUL SYLLABLE KUNJ +CFE6;CFE6;110F 116E 11AD;CFE6;110F 116E 11AD; # (쿦; 쿦; 쿦; 쿦; 쿦; ) HANGUL SYLLABLE KUNH +CFE7;CFE7;110F 116E 11AE;CFE7;110F 116E 11AE; # (쿧; 쿧; 쿧; 쿧; 쿧; ) HANGUL SYLLABLE KUD +CFE8;CFE8;110F 116E 11AF;CFE8;110F 116E 11AF; # (쿨; 쿨; 쿨; 쿨; 쿨; ) HANGUL SYLLABLE KUL +CFE9;CFE9;110F 116E 11B0;CFE9;110F 116E 11B0; # (쿩; 쿩; 쿩; 쿩; 쿩; ) HANGUL SYLLABLE KULG +CFEA;CFEA;110F 116E 11B1;CFEA;110F 116E 11B1; # (쿪; 쿪; 쿪; 쿪; 쿪; ) HANGUL SYLLABLE KULM +CFEB;CFEB;110F 116E 11B2;CFEB;110F 116E 11B2; # (쿫; 쿫; 쿫; 쿫; 쿫; ) HANGUL SYLLABLE KULB +CFEC;CFEC;110F 116E 11B3;CFEC;110F 116E 11B3; # (쿬; 쿬; 쿬; 쿬; 쿬; ) HANGUL SYLLABLE KULS +CFED;CFED;110F 116E 11B4;CFED;110F 116E 11B4; # (쿭; 쿭; 쿭; 쿭; 쿭; ) HANGUL SYLLABLE KULT +CFEE;CFEE;110F 116E 11B5;CFEE;110F 116E 11B5; # (쿮; 쿮; 쿮; 쿮; 쿮; ) HANGUL SYLLABLE KULP +CFEF;CFEF;110F 116E 11B6;CFEF;110F 116E 11B6; # (쿯; 쿯; 쿯; 쿯; 쿯; ) HANGUL SYLLABLE KULH +CFF0;CFF0;110F 116E 11B7;CFF0;110F 116E 11B7; # (쿰; 쿰; 쿰; 쿰; 쿰; ) HANGUL SYLLABLE KUM +CFF1;CFF1;110F 116E 11B8;CFF1;110F 116E 11B8; # (쿱; 쿱; 쿱; 쿱; 쿱; ) HANGUL SYLLABLE KUB +CFF2;CFF2;110F 116E 11B9;CFF2;110F 116E 11B9; # (쿲; 쿲; 쿲; 쿲; 쿲; ) HANGUL SYLLABLE KUBS +CFF3;CFF3;110F 116E 11BA;CFF3;110F 116E 11BA; # (쿳; 쿳; 쿳; 쿳; 쿳; ) HANGUL SYLLABLE KUS +CFF4;CFF4;110F 116E 11BB;CFF4;110F 116E 11BB; # (쿴; 쿴; 쿴; 쿴; 쿴; ) HANGUL SYLLABLE KUSS +CFF5;CFF5;110F 116E 11BC;CFF5;110F 116E 11BC; # (쿵; 쿵; 쿵; 쿵; 쿵; ) HANGUL SYLLABLE KUNG +CFF6;CFF6;110F 116E 11BD;CFF6;110F 116E 11BD; # (쿶; 쿶; 쿶; 쿶; 쿶; ) HANGUL SYLLABLE KUJ +CFF7;CFF7;110F 116E 11BE;CFF7;110F 116E 11BE; # (쿷; 쿷; 쿷; 쿷; 쿷; ) HANGUL SYLLABLE KUC +CFF8;CFF8;110F 116E 11BF;CFF8;110F 116E 11BF; # (쿸; 쿸; 쿸; 쿸; 쿸; ) HANGUL SYLLABLE KUK +CFF9;CFF9;110F 116E 11C0;CFF9;110F 116E 11C0; # (쿹; 쿹; 쿹; 쿹; 쿹; ) HANGUL SYLLABLE KUT +CFFA;CFFA;110F 116E 11C1;CFFA;110F 116E 11C1; # (쿺; 쿺; 쿺; 쿺; 쿺; ) HANGUL SYLLABLE KUP +CFFB;CFFB;110F 116E 11C2;CFFB;110F 116E 11C2; # (쿻; 쿻; 쿻; 쿻; 쿻; ) HANGUL SYLLABLE KUH +CFFC;CFFC;110F 116F;CFFC;110F 116F; # (쿼; 쿼; 쿼; 쿼; 쿼; ) HANGUL SYLLABLE KWEO +CFFD;CFFD;110F 116F 11A8;CFFD;110F 116F 11A8; # (쿽; 쿽; 쿽; 쿽; 쿽; ) HANGUL SYLLABLE KWEOG +CFFE;CFFE;110F 116F 11A9;CFFE;110F 116F 11A9; # (쿾; 쿾; 쿾; 쿾; 쿾; ) HANGUL SYLLABLE KWEOGG +CFFF;CFFF;110F 116F 11AA;CFFF;110F 116F 11AA; # (쿿; 쿿; 쿿; 쿿; 쿿; ) HANGUL SYLLABLE KWEOGS +D000;D000;110F 116F 11AB;D000;110F 116F 11AB; # (퀀; 퀀; 퀀; 퀀; 퀀; ) HANGUL SYLLABLE KWEON +D001;D001;110F 116F 11AC;D001;110F 116F 11AC; # (퀁; 퀁; 퀁; 퀁; 퀁; ) HANGUL SYLLABLE KWEONJ +D002;D002;110F 116F 11AD;D002;110F 116F 11AD; # (퀂; 퀂; 퀂; 퀂; 퀂; ) HANGUL SYLLABLE KWEONH +D003;D003;110F 116F 11AE;D003;110F 116F 11AE; # (퀃; 퀃; 퀃; 퀃; 퀃; ) HANGUL SYLLABLE KWEOD +D004;D004;110F 116F 11AF;D004;110F 116F 11AF; # (퀄; 퀄; 퀄; 퀄; 퀄; ) HANGUL SYLLABLE KWEOL +D005;D005;110F 116F 11B0;D005;110F 116F 11B0; # (퀅; 퀅; 퀅; 퀅; 퀅; ) HANGUL SYLLABLE KWEOLG +D006;D006;110F 116F 11B1;D006;110F 116F 11B1; # (퀆; 퀆; 퀆; 퀆; 퀆; ) HANGUL SYLLABLE KWEOLM +D007;D007;110F 116F 11B2;D007;110F 116F 11B2; # (퀇; 퀇; 퀇; 퀇; 퀇; ) HANGUL SYLLABLE KWEOLB +D008;D008;110F 116F 11B3;D008;110F 116F 11B3; # (퀈; 퀈; 퀈; 퀈; 퀈; ) HANGUL SYLLABLE KWEOLS +D009;D009;110F 116F 11B4;D009;110F 116F 11B4; # (퀉; 퀉; 퀉; 퀉; 퀉; ) HANGUL SYLLABLE KWEOLT +D00A;D00A;110F 116F 11B5;D00A;110F 116F 11B5; # (퀊; 퀊; 퀊; 퀊; 퀊; ) HANGUL SYLLABLE KWEOLP +D00B;D00B;110F 116F 11B6;D00B;110F 116F 11B6; # (퀋; 퀋; 퀋; 퀋; 퀋; ) HANGUL SYLLABLE KWEOLH +D00C;D00C;110F 116F 11B7;D00C;110F 116F 11B7; # (퀌; 퀌; 퀌; 퀌; 퀌; ) HANGUL SYLLABLE KWEOM +D00D;D00D;110F 116F 11B8;D00D;110F 116F 11B8; # (퀍; 퀍; 퀍; 퀍; 퀍; ) HANGUL SYLLABLE KWEOB +D00E;D00E;110F 116F 11B9;D00E;110F 116F 11B9; # (퀎; 퀎; 퀎; 퀎; 퀎; ) HANGUL SYLLABLE KWEOBS +D00F;D00F;110F 116F 11BA;D00F;110F 116F 11BA; # (퀏; 퀏; 퀏; 퀏; 퀏; ) HANGUL SYLLABLE KWEOS +D010;D010;110F 116F 11BB;D010;110F 116F 11BB; # (퀐; 퀐; 퀐; 퀐; 퀐; ) HANGUL SYLLABLE KWEOSS +D011;D011;110F 116F 11BC;D011;110F 116F 11BC; # (퀑; 퀑; 퀑; 퀑; 퀑; ) HANGUL SYLLABLE KWEONG +D012;D012;110F 116F 11BD;D012;110F 116F 11BD; # (퀒; 퀒; 퀒; 퀒; 퀒; ) HANGUL SYLLABLE KWEOJ +D013;D013;110F 116F 11BE;D013;110F 116F 11BE; # (퀓; 퀓; 퀓; 퀓; 퀓; ) HANGUL SYLLABLE KWEOC +D014;D014;110F 116F 11BF;D014;110F 116F 11BF; # (퀔; 퀔; 퀔; 퀔; 퀔; ) HANGUL SYLLABLE KWEOK +D015;D015;110F 116F 11C0;D015;110F 116F 11C0; # (퀕; 퀕; 퀕; 퀕; 퀕; ) HANGUL SYLLABLE KWEOT +D016;D016;110F 116F 11C1;D016;110F 116F 11C1; # (퀖; 퀖; 퀖; 퀖; 퀖; ) HANGUL SYLLABLE KWEOP +D017;D017;110F 116F 11C2;D017;110F 116F 11C2; # (퀗; 퀗; 퀗; 퀗; 퀗; ) HANGUL SYLLABLE KWEOH +D018;D018;110F 1170;D018;110F 1170; # (퀘; 퀘; 퀘; 퀘; 퀘; ) HANGUL SYLLABLE KWE +D019;D019;110F 1170 11A8;D019;110F 1170 11A8; # (퀙; 퀙; 퀙; 퀙; 퀙; ) HANGUL SYLLABLE KWEG +D01A;D01A;110F 1170 11A9;D01A;110F 1170 11A9; # (퀚; 퀚; 퀚; 퀚; 퀚; ) HANGUL SYLLABLE KWEGG +D01B;D01B;110F 1170 11AA;D01B;110F 1170 11AA; # (퀛; 퀛; 퀛; 퀛; 퀛; ) HANGUL SYLLABLE KWEGS +D01C;D01C;110F 1170 11AB;D01C;110F 1170 11AB; # (퀜; 퀜; 퀜; 퀜; 퀜; ) HANGUL SYLLABLE KWEN +D01D;D01D;110F 1170 11AC;D01D;110F 1170 11AC; # (퀝; 퀝; 퀝; 퀝; 퀝; ) HANGUL SYLLABLE KWENJ +D01E;D01E;110F 1170 11AD;D01E;110F 1170 11AD; # (퀞; 퀞; 퀞; 퀞; 퀞; ) HANGUL SYLLABLE KWENH +D01F;D01F;110F 1170 11AE;D01F;110F 1170 11AE; # (퀟; 퀟; 퀟; 퀟; 퀟; ) HANGUL SYLLABLE KWED +D020;D020;110F 1170 11AF;D020;110F 1170 11AF; # (퀠; 퀠; 퀠; 퀠; 퀠; ) HANGUL SYLLABLE KWEL +D021;D021;110F 1170 11B0;D021;110F 1170 11B0; # (퀡; 퀡; 퀡; 퀡; 퀡; ) HANGUL SYLLABLE KWELG +D022;D022;110F 1170 11B1;D022;110F 1170 11B1; # (퀢; 퀢; 퀢; 퀢; 퀢; ) HANGUL SYLLABLE KWELM +D023;D023;110F 1170 11B2;D023;110F 1170 11B2; # (퀣; 퀣; 퀣; 퀣; 퀣; ) HANGUL SYLLABLE KWELB +D024;D024;110F 1170 11B3;D024;110F 1170 11B3; # (퀤; 퀤; 퀤; 퀤; 퀤; ) HANGUL SYLLABLE KWELS +D025;D025;110F 1170 11B4;D025;110F 1170 11B4; # (퀥; 퀥; 퀥; 퀥; 퀥; ) HANGUL SYLLABLE KWELT +D026;D026;110F 1170 11B5;D026;110F 1170 11B5; # (퀦; 퀦; 퀦; 퀦; 퀦; ) HANGUL SYLLABLE KWELP +D027;D027;110F 1170 11B6;D027;110F 1170 11B6; # (퀧; 퀧; 퀧; 퀧; 퀧; ) HANGUL SYLLABLE KWELH +D028;D028;110F 1170 11B7;D028;110F 1170 11B7; # (퀨; 퀨; 퀨; 퀨; 퀨; ) HANGUL SYLLABLE KWEM +D029;D029;110F 1170 11B8;D029;110F 1170 11B8; # (퀩; 퀩; 퀩; 퀩; 퀩; ) HANGUL SYLLABLE KWEB +D02A;D02A;110F 1170 11B9;D02A;110F 1170 11B9; # (퀪; 퀪; 퀪; 퀪; 퀪; ) HANGUL SYLLABLE KWEBS +D02B;D02B;110F 1170 11BA;D02B;110F 1170 11BA; # (퀫; 퀫; 퀫; 퀫; 퀫; ) HANGUL SYLLABLE KWES +D02C;D02C;110F 1170 11BB;D02C;110F 1170 11BB; # (퀬; 퀬; 퀬; 퀬; 퀬; ) HANGUL SYLLABLE KWESS +D02D;D02D;110F 1170 11BC;D02D;110F 1170 11BC; # (퀭; 퀭; 퀭; 퀭; 퀭; ) HANGUL SYLLABLE KWENG +D02E;D02E;110F 1170 11BD;D02E;110F 1170 11BD; # (퀮; 퀮; 퀮; 퀮; 퀮; ) HANGUL SYLLABLE KWEJ +D02F;D02F;110F 1170 11BE;D02F;110F 1170 11BE; # (퀯; 퀯; 퀯; 퀯; 퀯; ) HANGUL SYLLABLE KWEC +D030;D030;110F 1170 11BF;D030;110F 1170 11BF; # (퀰; 퀰; 퀰; 퀰; 퀰; ) HANGUL SYLLABLE KWEK +D031;D031;110F 1170 11C0;D031;110F 1170 11C0; # (퀱; 퀱; 퀱; 퀱; 퀱; ) HANGUL SYLLABLE KWET +D032;D032;110F 1170 11C1;D032;110F 1170 11C1; # (퀲; 퀲; 퀲; 퀲; 퀲; ) HANGUL SYLLABLE KWEP +D033;D033;110F 1170 11C2;D033;110F 1170 11C2; # (퀳; 퀳; 퀳; 퀳; 퀳; ) HANGUL SYLLABLE KWEH +D034;D034;110F 1171;D034;110F 1171; # (퀴; 퀴; 퀴; 퀴; 퀴; ) HANGUL SYLLABLE KWI +D035;D035;110F 1171 11A8;D035;110F 1171 11A8; # (퀵; 퀵; 퀵; 퀵; 퀵; ) HANGUL SYLLABLE KWIG +D036;D036;110F 1171 11A9;D036;110F 1171 11A9; # (퀶; 퀶; 퀶; 퀶; 퀶; ) HANGUL SYLLABLE KWIGG +D037;D037;110F 1171 11AA;D037;110F 1171 11AA; # (퀷; 퀷; 퀷; 퀷; 퀷; ) HANGUL SYLLABLE KWIGS +D038;D038;110F 1171 11AB;D038;110F 1171 11AB; # (퀸; 퀸; 퀸; 퀸; 퀸; ) HANGUL SYLLABLE KWIN +D039;D039;110F 1171 11AC;D039;110F 1171 11AC; # (퀹; 퀹; 퀹; 퀹; 퀹; ) HANGUL SYLLABLE KWINJ +D03A;D03A;110F 1171 11AD;D03A;110F 1171 11AD; # (퀺; 퀺; 퀺; 퀺; 퀺; ) HANGUL SYLLABLE KWINH +D03B;D03B;110F 1171 11AE;D03B;110F 1171 11AE; # (퀻; 퀻; 퀻; 퀻; 퀻; ) HANGUL SYLLABLE KWID +D03C;D03C;110F 1171 11AF;D03C;110F 1171 11AF; # (퀼; 퀼; 퀼; 퀼; 퀼; ) HANGUL SYLLABLE KWIL +D03D;D03D;110F 1171 11B0;D03D;110F 1171 11B0; # (퀽; 퀽; 퀽; 퀽; 퀽; ) HANGUL SYLLABLE KWILG +D03E;D03E;110F 1171 11B1;D03E;110F 1171 11B1; # (퀾; 퀾; 퀾; 퀾; 퀾; ) HANGUL SYLLABLE KWILM +D03F;D03F;110F 1171 11B2;D03F;110F 1171 11B2; # (퀿; 퀿; 퀿; 퀿; 퀿; ) HANGUL SYLLABLE KWILB +D040;D040;110F 1171 11B3;D040;110F 1171 11B3; # (큀; 큀; 큀; 큀; 큀; ) HANGUL SYLLABLE KWILS +D041;D041;110F 1171 11B4;D041;110F 1171 11B4; # (큁; 큁; 큁; 큁; 큁; ) HANGUL SYLLABLE KWILT +D042;D042;110F 1171 11B5;D042;110F 1171 11B5; # (큂; 큂; 큂; 큂; 큂; ) HANGUL SYLLABLE KWILP +D043;D043;110F 1171 11B6;D043;110F 1171 11B6; # (큃; 큃; 큃; 큃; 큃; ) HANGUL SYLLABLE KWILH +D044;D044;110F 1171 11B7;D044;110F 1171 11B7; # (큄; 큄; 큄; 큄; 큄; ) HANGUL SYLLABLE KWIM +D045;D045;110F 1171 11B8;D045;110F 1171 11B8; # (큅; 큅; 큅; 큅; 큅; ) HANGUL SYLLABLE KWIB +D046;D046;110F 1171 11B9;D046;110F 1171 11B9; # (큆; 큆; 큆; 큆; 큆; ) HANGUL SYLLABLE KWIBS +D047;D047;110F 1171 11BA;D047;110F 1171 11BA; # (큇; 큇; 큇; 큇; 큇; ) HANGUL SYLLABLE KWIS +D048;D048;110F 1171 11BB;D048;110F 1171 11BB; # (큈; 큈; 큈; 큈; 큈; ) HANGUL SYLLABLE KWISS +D049;D049;110F 1171 11BC;D049;110F 1171 11BC; # (큉; 큉; 큉; 큉; 큉; ) HANGUL SYLLABLE KWING +D04A;D04A;110F 1171 11BD;D04A;110F 1171 11BD; # (큊; 큊; 큊; 큊; 큊; ) HANGUL SYLLABLE KWIJ +D04B;D04B;110F 1171 11BE;D04B;110F 1171 11BE; # (큋; 큋; 큋; 큋; 큋; ) HANGUL SYLLABLE KWIC +D04C;D04C;110F 1171 11BF;D04C;110F 1171 11BF; # (큌; 큌; 큌; 큌; 큌; ) HANGUL SYLLABLE KWIK +D04D;D04D;110F 1171 11C0;D04D;110F 1171 11C0; # (큍; 큍; 큍; 큍; 큍; ) HANGUL SYLLABLE KWIT +D04E;D04E;110F 1171 11C1;D04E;110F 1171 11C1; # (큎; 큎; 큎; 큎; 큎; ) HANGUL SYLLABLE KWIP +D04F;D04F;110F 1171 11C2;D04F;110F 1171 11C2; # (큏; 큏; 큏; 큏; 큏; ) HANGUL SYLLABLE KWIH +D050;D050;110F 1172;D050;110F 1172; # (큐; 큐; 큐; 큐; 큐; ) HANGUL SYLLABLE KYU +D051;D051;110F 1172 11A8;D051;110F 1172 11A8; # (큑; 큑; 큑; 큑; 큑; ) HANGUL SYLLABLE KYUG +D052;D052;110F 1172 11A9;D052;110F 1172 11A9; # (큒; 큒; 큒; 큒; 큒; ) HANGUL SYLLABLE KYUGG +D053;D053;110F 1172 11AA;D053;110F 1172 11AA; # (큓; 큓; 큓; 큓; 큓; ) HANGUL SYLLABLE KYUGS +D054;D054;110F 1172 11AB;D054;110F 1172 11AB; # (큔; 큔; 큔; 큔; 큔; ) HANGUL SYLLABLE KYUN +D055;D055;110F 1172 11AC;D055;110F 1172 11AC; # (큕; 큕; 큕; 큕; 큕; ) HANGUL SYLLABLE KYUNJ +D056;D056;110F 1172 11AD;D056;110F 1172 11AD; # (큖; 큖; 큖; 큖; 큖; ) HANGUL SYLLABLE KYUNH +D057;D057;110F 1172 11AE;D057;110F 1172 11AE; # (큗; 큗; 큗; 큗; 큗; ) HANGUL SYLLABLE KYUD +D058;D058;110F 1172 11AF;D058;110F 1172 11AF; # (큘; 큘; 큘; 큘; 큘; ) HANGUL SYLLABLE KYUL +D059;D059;110F 1172 11B0;D059;110F 1172 11B0; # (큙; 큙; 큙; 큙; 큙; ) HANGUL SYLLABLE KYULG +D05A;D05A;110F 1172 11B1;D05A;110F 1172 11B1; # (큚; 큚; 큚; 큚; 큚; ) HANGUL SYLLABLE KYULM +D05B;D05B;110F 1172 11B2;D05B;110F 1172 11B2; # (큛; 큛; 큛; 큛; 큛; ) HANGUL SYLLABLE KYULB +D05C;D05C;110F 1172 11B3;D05C;110F 1172 11B3; # (큜; 큜; 큜; 큜; 큜; ) HANGUL SYLLABLE KYULS +D05D;D05D;110F 1172 11B4;D05D;110F 1172 11B4; # (큝; 큝; 큝; 큝; 큝; ) HANGUL SYLLABLE KYULT +D05E;D05E;110F 1172 11B5;D05E;110F 1172 11B5; # (큞; 큞; 큞; 큞; 큞; ) HANGUL SYLLABLE KYULP +D05F;D05F;110F 1172 11B6;D05F;110F 1172 11B6; # (큟; 큟; 큟; 큟; 큟; ) HANGUL SYLLABLE KYULH +D060;D060;110F 1172 11B7;D060;110F 1172 11B7; # (큠; 큠; 큠; 큠; 큠; ) HANGUL SYLLABLE KYUM +D061;D061;110F 1172 11B8;D061;110F 1172 11B8; # (큡; 큡; 큡; 큡; 큡; ) HANGUL SYLLABLE KYUB +D062;D062;110F 1172 11B9;D062;110F 1172 11B9; # (큢; 큢; 큢; 큢; 큢; ) HANGUL SYLLABLE KYUBS +D063;D063;110F 1172 11BA;D063;110F 1172 11BA; # (큣; 큣; 큣; 큣; 큣; ) HANGUL SYLLABLE KYUS +D064;D064;110F 1172 11BB;D064;110F 1172 11BB; # (큤; 큤; 큤; 큤; 큤; ) HANGUL SYLLABLE KYUSS +D065;D065;110F 1172 11BC;D065;110F 1172 11BC; # (큥; 큥; 큥; 큥; 큥; ) HANGUL SYLLABLE KYUNG +D066;D066;110F 1172 11BD;D066;110F 1172 11BD; # (큦; 큦; 큦; 큦; 큦; ) HANGUL SYLLABLE KYUJ +D067;D067;110F 1172 11BE;D067;110F 1172 11BE; # (큧; 큧; 큧; 큧; 큧; ) HANGUL SYLLABLE KYUC +D068;D068;110F 1172 11BF;D068;110F 1172 11BF; # (큨; 큨; 큨; 큨; 큨; ) HANGUL SYLLABLE KYUK +D069;D069;110F 1172 11C0;D069;110F 1172 11C0; # (큩; 큩; 큩; 큩; 큩; ) HANGUL SYLLABLE KYUT +D06A;D06A;110F 1172 11C1;D06A;110F 1172 11C1; # (큪; 큪; 큪; 큪; 큪; ) HANGUL SYLLABLE KYUP +D06B;D06B;110F 1172 11C2;D06B;110F 1172 11C2; # (큫; 큫; 큫; 큫; 큫; ) HANGUL SYLLABLE KYUH +D06C;D06C;110F 1173;D06C;110F 1173; # (크; 크; 크; 크; 크; ) HANGUL SYLLABLE KEU +D06D;D06D;110F 1173 11A8;D06D;110F 1173 11A8; # (큭; 큭; 큭; 큭; 큭; ) HANGUL SYLLABLE KEUG +D06E;D06E;110F 1173 11A9;D06E;110F 1173 11A9; # (큮; 큮; 큮; 큮; 큮; ) HANGUL SYLLABLE KEUGG +D06F;D06F;110F 1173 11AA;D06F;110F 1173 11AA; # (큯; 큯; 큯; 큯; 큯; ) HANGUL SYLLABLE KEUGS +D070;D070;110F 1173 11AB;D070;110F 1173 11AB; # (큰; 큰; 큰; 큰; 큰; ) HANGUL SYLLABLE KEUN +D071;D071;110F 1173 11AC;D071;110F 1173 11AC; # (큱; 큱; 큱; 큱; 큱; ) HANGUL SYLLABLE KEUNJ +D072;D072;110F 1173 11AD;D072;110F 1173 11AD; # (큲; 큲; 큲; 큲; 큲; ) HANGUL SYLLABLE KEUNH +D073;D073;110F 1173 11AE;D073;110F 1173 11AE; # (큳; 큳; 큳; 큳; 큳; ) HANGUL SYLLABLE KEUD +D074;D074;110F 1173 11AF;D074;110F 1173 11AF; # (클; 클; 클; 클; 클; ) HANGUL SYLLABLE KEUL +D075;D075;110F 1173 11B0;D075;110F 1173 11B0; # (큵; 큵; 큵; 큵; 큵; ) HANGUL SYLLABLE KEULG +D076;D076;110F 1173 11B1;D076;110F 1173 11B1; # (큶; 큶; 큶; 큶; 큶; ) HANGUL SYLLABLE KEULM +D077;D077;110F 1173 11B2;D077;110F 1173 11B2; # (큷; 큷; 큷; 큷; 큷; ) HANGUL SYLLABLE KEULB +D078;D078;110F 1173 11B3;D078;110F 1173 11B3; # (큸; 큸; 큸; 큸; 큸; ) HANGUL SYLLABLE KEULS +D079;D079;110F 1173 11B4;D079;110F 1173 11B4; # (큹; 큹; 큹; 큹; 큹; ) HANGUL SYLLABLE KEULT +D07A;D07A;110F 1173 11B5;D07A;110F 1173 11B5; # (큺; 큺; 큺; 큺; 큺; ) HANGUL SYLLABLE KEULP +D07B;D07B;110F 1173 11B6;D07B;110F 1173 11B6; # (큻; 큻; 큻; 큻; 큻; ) HANGUL SYLLABLE KEULH +D07C;D07C;110F 1173 11B7;D07C;110F 1173 11B7; # (큼; 큼; 큼; 큼; 큼; ) HANGUL SYLLABLE KEUM +D07D;D07D;110F 1173 11B8;D07D;110F 1173 11B8; # (큽; 큽; 큽; 큽; 큽; ) HANGUL SYLLABLE KEUB +D07E;D07E;110F 1173 11B9;D07E;110F 1173 11B9; # (큾; 큾; 큾; 큾; 큾; ) HANGUL SYLLABLE KEUBS +D07F;D07F;110F 1173 11BA;D07F;110F 1173 11BA; # (큿; 큿; 큿; 큿; 큿; ) HANGUL SYLLABLE KEUS +D080;D080;110F 1173 11BB;D080;110F 1173 11BB; # (킀; 킀; 킀; 킀; 킀; ) HANGUL SYLLABLE KEUSS +D081;D081;110F 1173 11BC;D081;110F 1173 11BC; # (킁; 킁; 킁; 킁; 킁; ) HANGUL SYLLABLE KEUNG +D082;D082;110F 1173 11BD;D082;110F 1173 11BD; # (킂; 킂; 킂; 킂; 킂; ) HANGUL SYLLABLE KEUJ +D083;D083;110F 1173 11BE;D083;110F 1173 11BE; # (킃; 킃; 킃; 킃; 킃; ) HANGUL SYLLABLE KEUC +D084;D084;110F 1173 11BF;D084;110F 1173 11BF; # (킄; 킄; 킄; 킄; 킄; ) HANGUL SYLLABLE KEUK +D085;D085;110F 1173 11C0;D085;110F 1173 11C0; # (킅; 킅; 킅; 킅; 킅; ) HANGUL SYLLABLE KEUT +D086;D086;110F 1173 11C1;D086;110F 1173 11C1; # (킆; 킆; 킆; 킆; 킆; ) HANGUL SYLLABLE KEUP +D087;D087;110F 1173 11C2;D087;110F 1173 11C2; # (킇; 킇; 킇; 킇; 킇; ) HANGUL SYLLABLE KEUH +D088;D088;110F 1174;D088;110F 1174; # (킈; 킈; 킈; 킈; 킈; ) HANGUL SYLLABLE KYI +D089;D089;110F 1174 11A8;D089;110F 1174 11A8; # (킉; 킉; 킉; 킉; 킉; ) HANGUL SYLLABLE KYIG +D08A;D08A;110F 1174 11A9;D08A;110F 1174 11A9; # (킊; 킊; 킊; 킊; 킊; ) HANGUL SYLLABLE KYIGG +D08B;D08B;110F 1174 11AA;D08B;110F 1174 11AA; # (킋; 킋; 킋; 킋; 킋; ) HANGUL SYLLABLE KYIGS +D08C;D08C;110F 1174 11AB;D08C;110F 1174 11AB; # (킌; 킌; 킌; 킌; 킌; ) HANGUL SYLLABLE KYIN +D08D;D08D;110F 1174 11AC;D08D;110F 1174 11AC; # (킍; 킍; 킍; 킍; 킍; ) HANGUL SYLLABLE KYINJ +D08E;D08E;110F 1174 11AD;D08E;110F 1174 11AD; # (킎; 킎; 킎; 킎; 킎; ) HANGUL SYLLABLE KYINH +D08F;D08F;110F 1174 11AE;D08F;110F 1174 11AE; # (킏; 킏; 킏; 킏; 킏; ) HANGUL SYLLABLE KYID +D090;D090;110F 1174 11AF;D090;110F 1174 11AF; # (킐; 킐; 킐; 킐; 킐; ) HANGUL SYLLABLE KYIL +D091;D091;110F 1174 11B0;D091;110F 1174 11B0; # (킑; 킑; 킑; 킑; 킑; ) HANGUL SYLLABLE KYILG +D092;D092;110F 1174 11B1;D092;110F 1174 11B1; # (킒; 킒; 킒; 킒; 킒; ) HANGUL SYLLABLE KYILM +D093;D093;110F 1174 11B2;D093;110F 1174 11B2; # (킓; 킓; 킓; 킓; 킓; ) HANGUL SYLLABLE KYILB +D094;D094;110F 1174 11B3;D094;110F 1174 11B3; # (킔; 킔; 킔; 킔; 킔; ) HANGUL SYLLABLE KYILS +D095;D095;110F 1174 11B4;D095;110F 1174 11B4; # (킕; 킕; 킕; 킕; 킕; ) HANGUL SYLLABLE KYILT +D096;D096;110F 1174 11B5;D096;110F 1174 11B5; # (킖; 킖; 킖; 킖; 킖; ) HANGUL SYLLABLE KYILP +D097;D097;110F 1174 11B6;D097;110F 1174 11B6; # (킗; 킗; 킗; 킗; 킗; ) HANGUL SYLLABLE KYILH +D098;D098;110F 1174 11B7;D098;110F 1174 11B7; # (킘; 킘; 킘; 킘; 킘; ) HANGUL SYLLABLE KYIM +D099;D099;110F 1174 11B8;D099;110F 1174 11B8; # (킙; 킙; 킙; 킙; 킙; ) HANGUL SYLLABLE KYIB +D09A;D09A;110F 1174 11B9;D09A;110F 1174 11B9; # (킚; 킚; 킚; 킚; 킚; ) HANGUL SYLLABLE KYIBS +D09B;D09B;110F 1174 11BA;D09B;110F 1174 11BA; # (킛; 킛; 킛; 킛; 킛; ) HANGUL SYLLABLE KYIS +D09C;D09C;110F 1174 11BB;D09C;110F 1174 11BB; # (킜; 킜; 킜; 킜; 킜; ) HANGUL SYLLABLE KYISS +D09D;D09D;110F 1174 11BC;D09D;110F 1174 11BC; # (킝; 킝; 킝; 킝; 킝; ) HANGUL SYLLABLE KYING +D09E;D09E;110F 1174 11BD;D09E;110F 1174 11BD; # (킞; 킞; 킞; 킞; 킞; ) HANGUL SYLLABLE KYIJ +D09F;D09F;110F 1174 11BE;D09F;110F 1174 11BE; # (킟; 킟; 킟; 킟; 킟; ) HANGUL SYLLABLE KYIC +D0A0;D0A0;110F 1174 11BF;D0A0;110F 1174 11BF; # (킠; 킠; 킠; 킠; 킠; ) HANGUL SYLLABLE KYIK +D0A1;D0A1;110F 1174 11C0;D0A1;110F 1174 11C0; # (킡; 킡; 킡; 킡; 킡; ) HANGUL SYLLABLE KYIT +D0A2;D0A2;110F 1174 11C1;D0A2;110F 1174 11C1; # (킢; 킢; 킢; 킢; 킢; ) HANGUL SYLLABLE KYIP +D0A3;D0A3;110F 1174 11C2;D0A3;110F 1174 11C2; # (킣; 킣; 킣; 킣; 킣; ) HANGUL SYLLABLE KYIH +D0A4;D0A4;110F 1175;D0A4;110F 1175; # (키; 키; 키; 키; 키; ) HANGUL SYLLABLE KI +D0A5;D0A5;110F 1175 11A8;D0A5;110F 1175 11A8; # (킥; 킥; 킥; 킥; 킥; ) HANGUL SYLLABLE KIG +D0A6;D0A6;110F 1175 11A9;D0A6;110F 1175 11A9; # (킦; 킦; 킦; 킦; 킦; ) HANGUL SYLLABLE KIGG +D0A7;D0A7;110F 1175 11AA;D0A7;110F 1175 11AA; # (킧; 킧; 킧; 킧; 킧; ) HANGUL SYLLABLE KIGS +D0A8;D0A8;110F 1175 11AB;D0A8;110F 1175 11AB; # (킨; 킨; 킨; 킨; 킨; ) HANGUL SYLLABLE KIN +D0A9;D0A9;110F 1175 11AC;D0A9;110F 1175 11AC; # (킩; 킩; 킩; 킩; 킩; ) HANGUL SYLLABLE KINJ +D0AA;D0AA;110F 1175 11AD;D0AA;110F 1175 11AD; # (킪; 킪; 킪; 킪; 킪; ) HANGUL SYLLABLE KINH +D0AB;D0AB;110F 1175 11AE;D0AB;110F 1175 11AE; # (킫; 킫; 킫; 킫; 킫; ) HANGUL SYLLABLE KID +D0AC;D0AC;110F 1175 11AF;D0AC;110F 1175 11AF; # (킬; 킬; 킬; 킬; 킬; ) HANGUL SYLLABLE KIL +D0AD;D0AD;110F 1175 11B0;D0AD;110F 1175 11B0; # (킭; 킭; 킭; 킭; 킭; ) HANGUL SYLLABLE KILG +D0AE;D0AE;110F 1175 11B1;D0AE;110F 1175 11B1; # (킮; 킮; 킮; 킮; 킮; ) HANGUL SYLLABLE KILM +D0AF;D0AF;110F 1175 11B2;D0AF;110F 1175 11B2; # (킯; 킯; 킯; 킯; 킯; ) HANGUL SYLLABLE KILB +D0B0;D0B0;110F 1175 11B3;D0B0;110F 1175 11B3; # (킰; 킰; 킰; 킰; 킰; ) HANGUL SYLLABLE KILS +D0B1;D0B1;110F 1175 11B4;D0B1;110F 1175 11B4; # (킱; 킱; 킱; 킱; 킱; ) HANGUL SYLLABLE KILT +D0B2;D0B2;110F 1175 11B5;D0B2;110F 1175 11B5; # (킲; 킲; 킲; 킲; 킲; ) HANGUL SYLLABLE KILP +D0B3;D0B3;110F 1175 11B6;D0B3;110F 1175 11B6; # (킳; 킳; 킳; 킳; 킳; ) HANGUL SYLLABLE KILH +D0B4;D0B4;110F 1175 11B7;D0B4;110F 1175 11B7; # (킴; 킴; 킴; 킴; 킴; ) HANGUL SYLLABLE KIM +D0B5;D0B5;110F 1175 11B8;D0B5;110F 1175 11B8; # (킵; 킵; 킵; 킵; 킵; ) HANGUL SYLLABLE KIB +D0B6;D0B6;110F 1175 11B9;D0B6;110F 1175 11B9; # (킶; 킶; 킶; 킶; 킶; ) HANGUL SYLLABLE KIBS +D0B7;D0B7;110F 1175 11BA;D0B7;110F 1175 11BA; # (킷; 킷; 킷; 킷; 킷; ) HANGUL SYLLABLE KIS +D0B8;D0B8;110F 1175 11BB;D0B8;110F 1175 11BB; # (킸; 킸; 킸; 킸; 킸; ) HANGUL SYLLABLE KISS +D0B9;D0B9;110F 1175 11BC;D0B9;110F 1175 11BC; # (킹; 킹; 킹; 킹; 킹; ) HANGUL SYLLABLE KING +D0BA;D0BA;110F 1175 11BD;D0BA;110F 1175 11BD; # (킺; 킺; 킺; 킺; 킺; ) HANGUL SYLLABLE KIJ +D0BB;D0BB;110F 1175 11BE;D0BB;110F 1175 11BE; # (킻; 킻; 킻; 킻; 킻; ) HANGUL SYLLABLE KIC +D0BC;D0BC;110F 1175 11BF;D0BC;110F 1175 11BF; # (킼; 킼; 킼; 킼; 킼; ) HANGUL SYLLABLE KIK +D0BD;D0BD;110F 1175 11C0;D0BD;110F 1175 11C0; # (킽; 킽; 킽; 킽; 킽; ) HANGUL SYLLABLE KIT +D0BE;D0BE;110F 1175 11C1;D0BE;110F 1175 11C1; # (킾; 킾; 킾; 킾; 킾; ) HANGUL SYLLABLE KIP +D0BF;D0BF;110F 1175 11C2;D0BF;110F 1175 11C2; # (킿; 킿; 킿; 킿; 킿; ) HANGUL SYLLABLE KIH +D0C0;D0C0;1110 1161;D0C0;1110 1161; # (타; 타; 타; 타; 타; ) HANGUL SYLLABLE TA +D0C1;D0C1;1110 1161 11A8;D0C1;1110 1161 11A8; # (탁; 탁; 탁; 탁; 탁; ) HANGUL SYLLABLE TAG +D0C2;D0C2;1110 1161 11A9;D0C2;1110 1161 11A9; # (탂; 탂; 탂; 탂; 탂; ) HANGUL SYLLABLE TAGG +D0C3;D0C3;1110 1161 11AA;D0C3;1110 1161 11AA; # (탃; 탃; 탃; 탃; 탃; ) HANGUL SYLLABLE TAGS +D0C4;D0C4;1110 1161 11AB;D0C4;1110 1161 11AB; # (탄; 탄; 탄; 탄; 탄; ) HANGUL SYLLABLE TAN +D0C5;D0C5;1110 1161 11AC;D0C5;1110 1161 11AC; # (탅; 탅; 탅; 탅; 탅; ) HANGUL SYLLABLE TANJ +D0C6;D0C6;1110 1161 11AD;D0C6;1110 1161 11AD; # (탆; 탆; 탆; 탆; 탆; ) HANGUL SYLLABLE TANH +D0C7;D0C7;1110 1161 11AE;D0C7;1110 1161 11AE; # (탇; 탇; 탇; 탇; 탇; ) HANGUL SYLLABLE TAD +D0C8;D0C8;1110 1161 11AF;D0C8;1110 1161 11AF; # (탈; 탈; 탈; 탈; 탈; ) HANGUL SYLLABLE TAL +D0C9;D0C9;1110 1161 11B0;D0C9;1110 1161 11B0; # (탉; 탉; 탉; 탉; 탉; ) HANGUL SYLLABLE TALG +D0CA;D0CA;1110 1161 11B1;D0CA;1110 1161 11B1; # (탊; 탊; 탊; 탊; 탊; ) HANGUL SYLLABLE TALM +D0CB;D0CB;1110 1161 11B2;D0CB;1110 1161 11B2; # (탋; 탋; 탋; 탋; 탋; ) HANGUL SYLLABLE TALB +D0CC;D0CC;1110 1161 11B3;D0CC;1110 1161 11B3; # (탌; 탌; 탌; 탌; 탌; ) HANGUL SYLLABLE TALS +D0CD;D0CD;1110 1161 11B4;D0CD;1110 1161 11B4; # (탍; 탍; 탍; 탍; 탍; ) HANGUL SYLLABLE TALT +D0CE;D0CE;1110 1161 11B5;D0CE;1110 1161 11B5; # (탎; 탎; 탎; 탎; 탎; ) HANGUL SYLLABLE TALP +D0CF;D0CF;1110 1161 11B6;D0CF;1110 1161 11B6; # (탏; 탏; 탏; 탏; 탏; ) HANGUL SYLLABLE TALH +D0D0;D0D0;1110 1161 11B7;D0D0;1110 1161 11B7; # (탐; 탐; 탐; 탐; 탐; ) HANGUL SYLLABLE TAM +D0D1;D0D1;1110 1161 11B8;D0D1;1110 1161 11B8; # (탑; 탑; 탑; 탑; 탑; ) HANGUL SYLLABLE TAB +D0D2;D0D2;1110 1161 11B9;D0D2;1110 1161 11B9; # (탒; 탒; 탒; 탒; 탒; ) HANGUL SYLLABLE TABS +D0D3;D0D3;1110 1161 11BA;D0D3;1110 1161 11BA; # (탓; 탓; 탓; 탓; 탓; ) HANGUL SYLLABLE TAS +D0D4;D0D4;1110 1161 11BB;D0D4;1110 1161 11BB; # (탔; 탔; 탔; 탔; 탔; ) HANGUL SYLLABLE TASS +D0D5;D0D5;1110 1161 11BC;D0D5;1110 1161 11BC; # (탕; 탕; 탕; 탕; 탕; ) HANGUL SYLLABLE TANG +D0D6;D0D6;1110 1161 11BD;D0D6;1110 1161 11BD; # (탖; 탖; 탖; 탖; 탖; ) HANGUL SYLLABLE TAJ +D0D7;D0D7;1110 1161 11BE;D0D7;1110 1161 11BE; # (탗; 탗; 탗; 탗; 탗; ) HANGUL SYLLABLE TAC +D0D8;D0D8;1110 1161 11BF;D0D8;1110 1161 11BF; # (탘; 탘; 탘; 탘; 탘; ) HANGUL SYLLABLE TAK +D0D9;D0D9;1110 1161 11C0;D0D9;1110 1161 11C0; # (탙; 탙; 탙; 탙; 탙; ) HANGUL SYLLABLE TAT +D0DA;D0DA;1110 1161 11C1;D0DA;1110 1161 11C1; # (탚; 탚; 탚; 탚; 탚; ) HANGUL SYLLABLE TAP +D0DB;D0DB;1110 1161 11C2;D0DB;1110 1161 11C2; # (탛; 탛; 탛; 탛; 탛; ) HANGUL SYLLABLE TAH +D0DC;D0DC;1110 1162;D0DC;1110 1162; # (태; 태; 태; 태; 태; ) HANGUL SYLLABLE TAE +D0DD;D0DD;1110 1162 11A8;D0DD;1110 1162 11A8; # (택; 택; 택; 택; 택; ) HANGUL SYLLABLE TAEG +D0DE;D0DE;1110 1162 11A9;D0DE;1110 1162 11A9; # (탞; 탞; 탞; 탞; 탞; ) HANGUL SYLLABLE TAEGG +D0DF;D0DF;1110 1162 11AA;D0DF;1110 1162 11AA; # (탟; 탟; 탟; 탟; 탟; ) HANGUL SYLLABLE TAEGS +D0E0;D0E0;1110 1162 11AB;D0E0;1110 1162 11AB; # (탠; 탠; 탠; 탠; 탠; ) HANGUL SYLLABLE TAEN +D0E1;D0E1;1110 1162 11AC;D0E1;1110 1162 11AC; # (탡; 탡; 탡; 탡; 탡; ) HANGUL SYLLABLE TAENJ +D0E2;D0E2;1110 1162 11AD;D0E2;1110 1162 11AD; # (탢; 탢; 탢; 탢; 탢; ) HANGUL SYLLABLE TAENH +D0E3;D0E3;1110 1162 11AE;D0E3;1110 1162 11AE; # (탣; 탣; 탣; 탣; 탣; ) HANGUL SYLLABLE TAED +D0E4;D0E4;1110 1162 11AF;D0E4;1110 1162 11AF; # (탤; 탤; 탤; 탤; 탤; ) HANGUL SYLLABLE TAEL +D0E5;D0E5;1110 1162 11B0;D0E5;1110 1162 11B0; # (탥; 탥; 탥; 탥; 탥; ) HANGUL SYLLABLE TAELG +D0E6;D0E6;1110 1162 11B1;D0E6;1110 1162 11B1; # (탦; 탦; 탦; 탦; 탦; ) HANGUL SYLLABLE TAELM +D0E7;D0E7;1110 1162 11B2;D0E7;1110 1162 11B2; # (탧; 탧; 탧; 탧; 탧; ) HANGUL SYLLABLE TAELB +D0E8;D0E8;1110 1162 11B3;D0E8;1110 1162 11B3; # (탨; 탨; 탨; 탨; 탨; ) HANGUL SYLLABLE TAELS +D0E9;D0E9;1110 1162 11B4;D0E9;1110 1162 11B4; # (탩; 탩; 탩; 탩; 탩; ) HANGUL SYLLABLE TAELT +D0EA;D0EA;1110 1162 11B5;D0EA;1110 1162 11B5; # (탪; 탪; 탪; 탪; 탪; ) HANGUL SYLLABLE TAELP +D0EB;D0EB;1110 1162 11B6;D0EB;1110 1162 11B6; # (탫; 탫; 탫; 탫; 탫; ) HANGUL SYLLABLE TAELH +D0EC;D0EC;1110 1162 11B7;D0EC;1110 1162 11B7; # (탬; 탬; 탬; 탬; 탬; ) HANGUL SYLLABLE TAEM +D0ED;D0ED;1110 1162 11B8;D0ED;1110 1162 11B8; # (탭; 탭; 탭; 탭; 탭; ) HANGUL SYLLABLE TAEB +D0EE;D0EE;1110 1162 11B9;D0EE;1110 1162 11B9; # (탮; 탮; 탮; 탮; 탮; ) HANGUL SYLLABLE TAEBS +D0EF;D0EF;1110 1162 11BA;D0EF;1110 1162 11BA; # (탯; 탯; 탯; 탯; 탯; ) HANGUL SYLLABLE TAES +D0F0;D0F0;1110 1162 11BB;D0F0;1110 1162 11BB; # (탰; 탰; 탰; 탰; 탰; ) HANGUL SYLLABLE TAESS +D0F1;D0F1;1110 1162 11BC;D0F1;1110 1162 11BC; # (탱; 탱; 탱; 탱; 탱; ) HANGUL SYLLABLE TAENG +D0F2;D0F2;1110 1162 11BD;D0F2;1110 1162 11BD; # (탲; 탲; 탲; 탲; 탲; ) HANGUL SYLLABLE TAEJ +D0F3;D0F3;1110 1162 11BE;D0F3;1110 1162 11BE; # (탳; 탳; 탳; 탳; 탳; ) HANGUL SYLLABLE TAEC +D0F4;D0F4;1110 1162 11BF;D0F4;1110 1162 11BF; # (탴; 탴; 탴; 탴; 탴; ) HANGUL SYLLABLE TAEK +D0F5;D0F5;1110 1162 11C0;D0F5;1110 1162 11C0; # (탵; 탵; 탵; 탵; 탵; ) HANGUL SYLLABLE TAET +D0F6;D0F6;1110 1162 11C1;D0F6;1110 1162 11C1; # (탶; 탶; 탶; 탶; 탶; ) HANGUL SYLLABLE TAEP +D0F7;D0F7;1110 1162 11C2;D0F7;1110 1162 11C2; # (탷; 탷; 탷; 탷; 탷; ) HANGUL SYLLABLE TAEH +D0F8;D0F8;1110 1163;D0F8;1110 1163; # (탸; 탸; 탸; 탸; 탸; ) HANGUL SYLLABLE TYA +D0F9;D0F9;1110 1163 11A8;D0F9;1110 1163 11A8; # (탹; 탹; 탹; 탹; 탹; ) HANGUL SYLLABLE TYAG +D0FA;D0FA;1110 1163 11A9;D0FA;1110 1163 11A9; # (탺; 탺; 탺; 탺; 탺; ) HANGUL SYLLABLE TYAGG +D0FB;D0FB;1110 1163 11AA;D0FB;1110 1163 11AA; # (탻; 탻; 탻; 탻; 탻; ) HANGUL SYLLABLE TYAGS +D0FC;D0FC;1110 1163 11AB;D0FC;1110 1163 11AB; # (탼; 탼; 탼; 탼; 탼; ) HANGUL SYLLABLE TYAN +D0FD;D0FD;1110 1163 11AC;D0FD;1110 1163 11AC; # (탽; 탽; 탽; 탽; 탽; ) HANGUL SYLLABLE TYANJ +D0FE;D0FE;1110 1163 11AD;D0FE;1110 1163 11AD; # (탾; 탾; 탾; 탾; 탾; ) HANGUL SYLLABLE TYANH +D0FF;D0FF;1110 1163 11AE;D0FF;1110 1163 11AE; # (탿; 탿; 탿; 탿; 탿; ) HANGUL SYLLABLE TYAD +D100;D100;1110 1163 11AF;D100;1110 1163 11AF; # (턀; 턀; 턀; 턀; 턀; ) HANGUL SYLLABLE TYAL +D101;D101;1110 1163 11B0;D101;1110 1163 11B0; # (턁; 턁; 턁; 턁; 턁; ) HANGUL SYLLABLE TYALG +D102;D102;1110 1163 11B1;D102;1110 1163 11B1; # (턂; 턂; 턂; 턂; 턂; ) HANGUL SYLLABLE TYALM +D103;D103;1110 1163 11B2;D103;1110 1163 11B2; # (턃; 턃; 턃; 턃; 턃; ) HANGUL SYLLABLE TYALB +D104;D104;1110 1163 11B3;D104;1110 1163 11B3; # (턄; 턄; 턄; 턄; 턄; ) HANGUL SYLLABLE TYALS +D105;D105;1110 1163 11B4;D105;1110 1163 11B4; # (턅; 턅; 턅; 턅; 턅; ) HANGUL SYLLABLE TYALT +D106;D106;1110 1163 11B5;D106;1110 1163 11B5; # (턆; 턆; 턆; 턆; 턆; ) HANGUL SYLLABLE TYALP +D107;D107;1110 1163 11B6;D107;1110 1163 11B6; # (턇; 턇; 턇; 턇; 턇; ) HANGUL SYLLABLE TYALH +D108;D108;1110 1163 11B7;D108;1110 1163 11B7; # (턈; 턈; 턈; 턈; 턈; ) HANGUL SYLLABLE TYAM +D109;D109;1110 1163 11B8;D109;1110 1163 11B8; # (턉; 턉; 턉; 턉; 턉; ) HANGUL SYLLABLE TYAB +D10A;D10A;1110 1163 11B9;D10A;1110 1163 11B9; # (턊; 턊; 턊; 턊; 턊; ) HANGUL SYLLABLE TYABS +D10B;D10B;1110 1163 11BA;D10B;1110 1163 11BA; # (턋; 턋; 턋; 턋; 턋; ) HANGUL SYLLABLE TYAS +D10C;D10C;1110 1163 11BB;D10C;1110 1163 11BB; # (턌; 턌; 턌; 턌; 턌; ) HANGUL SYLLABLE TYASS +D10D;D10D;1110 1163 11BC;D10D;1110 1163 11BC; # (턍; 턍; 턍; 턍; 턍; ) HANGUL SYLLABLE TYANG +D10E;D10E;1110 1163 11BD;D10E;1110 1163 11BD; # (턎; 턎; 턎; 턎; 턎; ) HANGUL SYLLABLE TYAJ +D10F;D10F;1110 1163 11BE;D10F;1110 1163 11BE; # (턏; 턏; 턏; 턏; 턏; ) HANGUL SYLLABLE TYAC +D110;D110;1110 1163 11BF;D110;1110 1163 11BF; # (턐; 턐; 턐; 턐; 턐; ) HANGUL SYLLABLE TYAK +D111;D111;1110 1163 11C0;D111;1110 1163 11C0; # (턑; 턑; 턑; 턑; 턑; ) HANGUL SYLLABLE TYAT +D112;D112;1110 1163 11C1;D112;1110 1163 11C1; # (턒; 턒; 턒; 턒; 턒; ) HANGUL SYLLABLE TYAP +D113;D113;1110 1163 11C2;D113;1110 1163 11C2; # (턓; 턓; 턓; 턓; 턓; ) HANGUL SYLLABLE TYAH +D114;D114;1110 1164;D114;1110 1164; # (턔; 턔; 턔; 턔; 턔; ) HANGUL SYLLABLE TYAE +D115;D115;1110 1164 11A8;D115;1110 1164 11A8; # (턕; 턕; 턕; 턕; 턕; ) HANGUL SYLLABLE TYAEG +D116;D116;1110 1164 11A9;D116;1110 1164 11A9; # (턖; 턖; 턖; 턖; 턖; ) HANGUL SYLLABLE TYAEGG +D117;D117;1110 1164 11AA;D117;1110 1164 11AA; # (턗; 턗; 턗; 턗; 턗; ) HANGUL SYLLABLE TYAEGS +D118;D118;1110 1164 11AB;D118;1110 1164 11AB; # (턘; 턘; 턘; 턘; 턘; ) HANGUL SYLLABLE TYAEN +D119;D119;1110 1164 11AC;D119;1110 1164 11AC; # (턙; 턙; 턙; 턙; 턙; ) HANGUL SYLLABLE TYAENJ +D11A;D11A;1110 1164 11AD;D11A;1110 1164 11AD; # (턚; 턚; 턚; 턚; 턚; ) HANGUL SYLLABLE TYAENH +D11B;D11B;1110 1164 11AE;D11B;1110 1164 11AE; # (턛; 턛; 턛; 턛; 턛; ) HANGUL SYLLABLE TYAED +D11C;D11C;1110 1164 11AF;D11C;1110 1164 11AF; # (턜; 턜; 턜; 턜; 턜; ) HANGUL SYLLABLE TYAEL +D11D;D11D;1110 1164 11B0;D11D;1110 1164 11B0; # (턝; 턝; 턝; 턝; 턝; ) HANGUL SYLLABLE TYAELG +D11E;D11E;1110 1164 11B1;D11E;1110 1164 11B1; # (턞; 턞; 턞; 턞; 턞; ) HANGUL SYLLABLE TYAELM +D11F;D11F;1110 1164 11B2;D11F;1110 1164 11B2; # (턟; 턟; 턟; 턟; 턟; ) HANGUL SYLLABLE TYAELB +D120;D120;1110 1164 11B3;D120;1110 1164 11B3; # (턠; 턠; 턠; 턠; 턠; ) HANGUL SYLLABLE TYAELS +D121;D121;1110 1164 11B4;D121;1110 1164 11B4; # (턡; 턡; 턡; 턡; 턡; ) HANGUL SYLLABLE TYAELT +D122;D122;1110 1164 11B5;D122;1110 1164 11B5; # (턢; 턢; 턢; 턢; 턢; ) HANGUL SYLLABLE TYAELP +D123;D123;1110 1164 11B6;D123;1110 1164 11B6; # (턣; 턣; 턣; 턣; 턣; ) HANGUL SYLLABLE TYAELH +D124;D124;1110 1164 11B7;D124;1110 1164 11B7; # (턤; 턤; 턤; 턤; 턤; ) HANGUL SYLLABLE TYAEM +D125;D125;1110 1164 11B8;D125;1110 1164 11B8; # (턥; 턥; 턥; 턥; 턥; ) HANGUL SYLLABLE TYAEB +D126;D126;1110 1164 11B9;D126;1110 1164 11B9; # (턦; 턦; 턦; 턦; 턦; ) HANGUL SYLLABLE TYAEBS +D127;D127;1110 1164 11BA;D127;1110 1164 11BA; # (턧; 턧; 턧; 턧; 턧; ) HANGUL SYLLABLE TYAES +D128;D128;1110 1164 11BB;D128;1110 1164 11BB; # (턨; 턨; 턨; 턨; 턨; ) HANGUL SYLLABLE TYAESS +D129;D129;1110 1164 11BC;D129;1110 1164 11BC; # (턩; 턩; 턩; 턩; 턩; ) HANGUL SYLLABLE TYAENG +D12A;D12A;1110 1164 11BD;D12A;1110 1164 11BD; # (턪; 턪; 턪; 턪; 턪; ) HANGUL SYLLABLE TYAEJ +D12B;D12B;1110 1164 11BE;D12B;1110 1164 11BE; # (턫; 턫; 턫; 턫; 턫; ) HANGUL SYLLABLE TYAEC +D12C;D12C;1110 1164 11BF;D12C;1110 1164 11BF; # (턬; 턬; 턬; 턬; 턬; ) HANGUL SYLLABLE TYAEK +D12D;D12D;1110 1164 11C0;D12D;1110 1164 11C0; # (턭; 턭; 턭; 턭; 턭; ) HANGUL SYLLABLE TYAET +D12E;D12E;1110 1164 11C1;D12E;1110 1164 11C1; # (턮; 턮; 턮; 턮; 턮; ) HANGUL SYLLABLE TYAEP +D12F;D12F;1110 1164 11C2;D12F;1110 1164 11C2; # (턯; 턯; 턯; 턯; 턯; ) HANGUL SYLLABLE TYAEH +D130;D130;1110 1165;D130;1110 1165; # (터; 터; 터; 터; 터; ) HANGUL SYLLABLE TEO +D131;D131;1110 1165 11A8;D131;1110 1165 11A8; # (턱; 턱; 턱; 턱; 턱; ) HANGUL SYLLABLE TEOG +D132;D132;1110 1165 11A9;D132;1110 1165 11A9; # (턲; 턲; 턲; 턲; 턲; ) HANGUL SYLLABLE TEOGG +D133;D133;1110 1165 11AA;D133;1110 1165 11AA; # (턳; 턳; 턳; 턳; 턳; ) HANGUL SYLLABLE TEOGS +D134;D134;1110 1165 11AB;D134;1110 1165 11AB; # (턴; 턴; 턴; 턴; 턴; ) HANGUL SYLLABLE TEON +D135;D135;1110 1165 11AC;D135;1110 1165 11AC; # (턵; 턵; 턵; 턵; 턵; ) HANGUL SYLLABLE TEONJ +D136;D136;1110 1165 11AD;D136;1110 1165 11AD; # (턶; 턶; 턶; 턶; 턶; ) HANGUL SYLLABLE TEONH +D137;D137;1110 1165 11AE;D137;1110 1165 11AE; # (턷; 턷; 턷; 턷; 턷; ) HANGUL SYLLABLE TEOD +D138;D138;1110 1165 11AF;D138;1110 1165 11AF; # (털; 털; 털; 털; 털; ) HANGUL SYLLABLE TEOL +D139;D139;1110 1165 11B0;D139;1110 1165 11B0; # (턹; 턹; 턹; 턹; 턹; ) HANGUL SYLLABLE TEOLG +D13A;D13A;1110 1165 11B1;D13A;1110 1165 11B1; # (턺; 턺; 턺; 턺; 턺; ) HANGUL SYLLABLE TEOLM +D13B;D13B;1110 1165 11B2;D13B;1110 1165 11B2; # (턻; 턻; 턻; 턻; 턻; ) HANGUL SYLLABLE TEOLB +D13C;D13C;1110 1165 11B3;D13C;1110 1165 11B3; # (턼; 턼; 턼; 턼; 턼; ) HANGUL SYLLABLE TEOLS +D13D;D13D;1110 1165 11B4;D13D;1110 1165 11B4; # (턽; 턽; 턽; 턽; 턽; ) HANGUL SYLLABLE TEOLT +D13E;D13E;1110 1165 11B5;D13E;1110 1165 11B5; # (턾; 턾; 턾; 턾; 턾; ) HANGUL SYLLABLE TEOLP +D13F;D13F;1110 1165 11B6;D13F;1110 1165 11B6; # (턿; 턿; 턿; 턿; 턿; ) HANGUL SYLLABLE TEOLH +D140;D140;1110 1165 11B7;D140;1110 1165 11B7; # (텀; 텀; 텀; 텀; 텀; ) HANGUL SYLLABLE TEOM +D141;D141;1110 1165 11B8;D141;1110 1165 11B8; # (텁; 텁; 텁; 텁; 텁; ) HANGUL SYLLABLE TEOB +D142;D142;1110 1165 11B9;D142;1110 1165 11B9; # (텂; 텂; 텂; 텂; 텂; ) HANGUL SYLLABLE TEOBS +D143;D143;1110 1165 11BA;D143;1110 1165 11BA; # (텃; 텃; 텃; 텃; 텃; ) HANGUL SYLLABLE TEOS +D144;D144;1110 1165 11BB;D144;1110 1165 11BB; # (텄; 텄; 텄; 텄; 텄; ) HANGUL SYLLABLE TEOSS +D145;D145;1110 1165 11BC;D145;1110 1165 11BC; # (텅; 텅; 텅; 텅; 텅; ) HANGUL SYLLABLE TEONG +D146;D146;1110 1165 11BD;D146;1110 1165 11BD; # (텆; 텆; 텆; 텆; 텆; ) HANGUL SYLLABLE TEOJ +D147;D147;1110 1165 11BE;D147;1110 1165 11BE; # (텇; 텇; 텇; 텇; 텇; ) HANGUL SYLLABLE TEOC +D148;D148;1110 1165 11BF;D148;1110 1165 11BF; # (텈; 텈; 텈; 텈; 텈; ) HANGUL SYLLABLE TEOK +D149;D149;1110 1165 11C0;D149;1110 1165 11C0; # (텉; 텉; 텉; 텉; 텉; ) HANGUL SYLLABLE TEOT +D14A;D14A;1110 1165 11C1;D14A;1110 1165 11C1; # (텊; 텊; 텊; 텊; 텊; ) HANGUL SYLLABLE TEOP +D14B;D14B;1110 1165 11C2;D14B;1110 1165 11C2; # (텋; 텋; 텋; 텋; 텋; ) HANGUL SYLLABLE TEOH +D14C;D14C;1110 1166;D14C;1110 1166; # (테; 테; 테; 테; 테; ) HANGUL SYLLABLE TE +D14D;D14D;1110 1166 11A8;D14D;1110 1166 11A8; # (텍; 텍; 텍; 텍; 텍; ) HANGUL SYLLABLE TEG +D14E;D14E;1110 1166 11A9;D14E;1110 1166 11A9; # (텎; 텎; 텎; 텎; 텎; ) HANGUL SYLLABLE TEGG +D14F;D14F;1110 1166 11AA;D14F;1110 1166 11AA; # (텏; 텏; 텏; 텏; 텏; ) HANGUL SYLLABLE TEGS +D150;D150;1110 1166 11AB;D150;1110 1166 11AB; # (텐; 텐; 텐; 텐; 텐; ) HANGUL SYLLABLE TEN +D151;D151;1110 1166 11AC;D151;1110 1166 11AC; # (텑; 텑; 텑; 텑; 텑; ) HANGUL SYLLABLE TENJ +D152;D152;1110 1166 11AD;D152;1110 1166 11AD; # (텒; 텒; 텒; 텒; 텒; ) HANGUL SYLLABLE TENH +D153;D153;1110 1166 11AE;D153;1110 1166 11AE; # (텓; 텓; 텓; 텓; 텓; ) HANGUL SYLLABLE TED +D154;D154;1110 1166 11AF;D154;1110 1166 11AF; # (텔; 텔; 텔; 텔; 텔; ) HANGUL SYLLABLE TEL +D155;D155;1110 1166 11B0;D155;1110 1166 11B0; # (텕; 텕; 텕; 텕; 텕; ) HANGUL SYLLABLE TELG +D156;D156;1110 1166 11B1;D156;1110 1166 11B1; # (텖; 텖; 텖; 텖; 텖; ) HANGUL SYLLABLE TELM +D157;D157;1110 1166 11B2;D157;1110 1166 11B2; # (텗; 텗; 텗; 텗; 텗; ) HANGUL SYLLABLE TELB +D158;D158;1110 1166 11B3;D158;1110 1166 11B3; # (텘; 텘; 텘; 텘; 텘; ) HANGUL SYLLABLE TELS +D159;D159;1110 1166 11B4;D159;1110 1166 11B4; # (텙; 텙; 텙; 텙; 텙; ) HANGUL SYLLABLE TELT +D15A;D15A;1110 1166 11B5;D15A;1110 1166 11B5; # (텚; 텚; 텚; 텚; 텚; ) HANGUL SYLLABLE TELP +D15B;D15B;1110 1166 11B6;D15B;1110 1166 11B6; # (텛; 텛; 텛; 텛; 텛; ) HANGUL SYLLABLE TELH +D15C;D15C;1110 1166 11B7;D15C;1110 1166 11B7; # (템; 템; 템; 템; 템; ) HANGUL SYLLABLE TEM +D15D;D15D;1110 1166 11B8;D15D;1110 1166 11B8; # (텝; 텝; 텝; 텝; 텝; ) HANGUL SYLLABLE TEB +D15E;D15E;1110 1166 11B9;D15E;1110 1166 11B9; # (텞; 텞; 텞; 텞; 텞; ) HANGUL SYLLABLE TEBS +D15F;D15F;1110 1166 11BA;D15F;1110 1166 11BA; # (텟; 텟; 텟; 텟; 텟; ) HANGUL SYLLABLE TES +D160;D160;1110 1166 11BB;D160;1110 1166 11BB; # (텠; 텠; 텠; 텠; 텠; ) HANGUL SYLLABLE TESS +D161;D161;1110 1166 11BC;D161;1110 1166 11BC; # (텡; 텡; 텡; 텡; 텡; ) HANGUL SYLLABLE TENG +D162;D162;1110 1166 11BD;D162;1110 1166 11BD; # (텢; 텢; 텢; 텢; 텢; ) HANGUL SYLLABLE TEJ +D163;D163;1110 1166 11BE;D163;1110 1166 11BE; # (텣; 텣; 텣; 텣; 텣; ) HANGUL SYLLABLE TEC +D164;D164;1110 1166 11BF;D164;1110 1166 11BF; # (텤; 텤; 텤; 텤; 텤; ) HANGUL SYLLABLE TEK +D165;D165;1110 1166 11C0;D165;1110 1166 11C0; # (텥; 텥; 텥; 텥; 텥; ) HANGUL SYLLABLE TET +D166;D166;1110 1166 11C1;D166;1110 1166 11C1; # (텦; 텦; 텦; 텦; 텦; ) HANGUL SYLLABLE TEP +D167;D167;1110 1166 11C2;D167;1110 1166 11C2; # (텧; 텧; 텧; 텧; 텧; ) HANGUL SYLLABLE TEH +D168;D168;1110 1167;D168;1110 1167; # (텨; 텨; 텨; 텨; 텨; ) HANGUL SYLLABLE TYEO +D169;D169;1110 1167 11A8;D169;1110 1167 11A8; # (텩; 텩; 텩; 텩; 텩; ) HANGUL SYLLABLE TYEOG +D16A;D16A;1110 1167 11A9;D16A;1110 1167 11A9; # (텪; 텪; 텪; 텪; 텪; ) HANGUL SYLLABLE TYEOGG +D16B;D16B;1110 1167 11AA;D16B;1110 1167 11AA; # (텫; 텫; 텫; 텫; 텫; ) HANGUL SYLLABLE TYEOGS +D16C;D16C;1110 1167 11AB;D16C;1110 1167 11AB; # (텬; 텬; 텬; 텬; 텬; ) HANGUL SYLLABLE TYEON +D16D;D16D;1110 1167 11AC;D16D;1110 1167 11AC; # (텭; 텭; 텭; 텭; 텭; ) HANGUL SYLLABLE TYEONJ +D16E;D16E;1110 1167 11AD;D16E;1110 1167 11AD; # (텮; 텮; 텮; 텮; 텮; ) HANGUL SYLLABLE TYEONH +D16F;D16F;1110 1167 11AE;D16F;1110 1167 11AE; # (텯; 텯; 텯; 텯; 텯; ) HANGUL SYLLABLE TYEOD +D170;D170;1110 1167 11AF;D170;1110 1167 11AF; # (텰; 텰; 텰; 텰; 텰; ) HANGUL SYLLABLE TYEOL +D171;D171;1110 1167 11B0;D171;1110 1167 11B0; # (텱; 텱; 텱; 텱; 텱; ) HANGUL SYLLABLE TYEOLG +D172;D172;1110 1167 11B1;D172;1110 1167 11B1; # (텲; 텲; 텲; 텲; 텲; ) HANGUL SYLLABLE TYEOLM +D173;D173;1110 1167 11B2;D173;1110 1167 11B2; # (텳; 텳; 텳; 텳; 텳; ) HANGUL SYLLABLE TYEOLB +D174;D174;1110 1167 11B3;D174;1110 1167 11B3; # (텴; 텴; 텴; 텴; 텴; ) HANGUL SYLLABLE TYEOLS +D175;D175;1110 1167 11B4;D175;1110 1167 11B4; # (텵; 텵; 텵; 텵; 텵; ) HANGUL SYLLABLE TYEOLT +D176;D176;1110 1167 11B5;D176;1110 1167 11B5; # (텶; 텶; 텶; 텶; 텶; ) HANGUL SYLLABLE TYEOLP +D177;D177;1110 1167 11B6;D177;1110 1167 11B6; # (텷; 텷; 텷; 텷; 텷; ) HANGUL SYLLABLE TYEOLH +D178;D178;1110 1167 11B7;D178;1110 1167 11B7; # (텸; 텸; 텸; 텸; 텸; ) HANGUL SYLLABLE TYEOM +D179;D179;1110 1167 11B8;D179;1110 1167 11B8; # (텹; 텹; 텹; 텹; 텹; ) HANGUL SYLLABLE TYEOB +D17A;D17A;1110 1167 11B9;D17A;1110 1167 11B9; # (텺; 텺; 텺; 텺; 텺; ) HANGUL SYLLABLE TYEOBS +D17B;D17B;1110 1167 11BA;D17B;1110 1167 11BA; # (텻; 텻; 텻; 텻; 텻; ) HANGUL SYLLABLE TYEOS +D17C;D17C;1110 1167 11BB;D17C;1110 1167 11BB; # (텼; 텼; 텼; 텼; 텼; ) HANGUL SYLLABLE TYEOSS +D17D;D17D;1110 1167 11BC;D17D;1110 1167 11BC; # (텽; 텽; 텽; 텽; 텽; ) HANGUL SYLLABLE TYEONG +D17E;D17E;1110 1167 11BD;D17E;1110 1167 11BD; # (텾; 텾; 텾; 텾; 텾; ) HANGUL SYLLABLE TYEOJ +D17F;D17F;1110 1167 11BE;D17F;1110 1167 11BE; # (텿; 텿; 텿; 텿; 텿; ) HANGUL SYLLABLE TYEOC +D180;D180;1110 1167 11BF;D180;1110 1167 11BF; # (톀; 톀; 톀; 톀; 톀; ) HANGUL SYLLABLE TYEOK +D181;D181;1110 1167 11C0;D181;1110 1167 11C0; # (톁; 톁; 톁; 톁; 톁; ) HANGUL SYLLABLE TYEOT +D182;D182;1110 1167 11C1;D182;1110 1167 11C1; # (톂; 톂; 톂; 톂; 톂; ) HANGUL SYLLABLE TYEOP +D183;D183;1110 1167 11C2;D183;1110 1167 11C2; # (톃; 톃; 톃; 톃; 톃; ) HANGUL SYLLABLE TYEOH +D184;D184;1110 1168;D184;1110 1168; # (톄; 톄; 톄; 톄; 톄; ) HANGUL SYLLABLE TYE +D185;D185;1110 1168 11A8;D185;1110 1168 11A8; # (톅; 톅; 톅; 톅; 톅; ) HANGUL SYLLABLE TYEG +D186;D186;1110 1168 11A9;D186;1110 1168 11A9; # (톆; 톆; 톆; 톆; 톆; ) HANGUL SYLLABLE TYEGG +D187;D187;1110 1168 11AA;D187;1110 1168 11AA; # (톇; 톇; 톇; 톇; 톇; ) HANGUL SYLLABLE TYEGS +D188;D188;1110 1168 11AB;D188;1110 1168 11AB; # (톈; 톈; 톈; 톈; 톈; ) HANGUL SYLLABLE TYEN +D189;D189;1110 1168 11AC;D189;1110 1168 11AC; # (톉; 톉; 톉; 톉; 톉; ) HANGUL SYLLABLE TYENJ +D18A;D18A;1110 1168 11AD;D18A;1110 1168 11AD; # (톊; 톊; 톊; 톊; 톊; ) HANGUL SYLLABLE TYENH +D18B;D18B;1110 1168 11AE;D18B;1110 1168 11AE; # (톋; 톋; 톋; 톋; 톋; ) HANGUL SYLLABLE TYED +D18C;D18C;1110 1168 11AF;D18C;1110 1168 11AF; # (톌; 톌; 톌; 톌; 톌; ) HANGUL SYLLABLE TYEL +D18D;D18D;1110 1168 11B0;D18D;1110 1168 11B0; # (톍; 톍; 톍; 톍; 톍; ) HANGUL SYLLABLE TYELG +D18E;D18E;1110 1168 11B1;D18E;1110 1168 11B1; # (톎; 톎; 톎; 톎; 톎; ) HANGUL SYLLABLE TYELM +D18F;D18F;1110 1168 11B2;D18F;1110 1168 11B2; # (톏; 톏; 톏; 톏; 톏; ) HANGUL SYLLABLE TYELB +D190;D190;1110 1168 11B3;D190;1110 1168 11B3; # (톐; 톐; 톐; 톐; 톐; ) HANGUL SYLLABLE TYELS +D191;D191;1110 1168 11B4;D191;1110 1168 11B4; # (톑; 톑; 톑; 톑; 톑; ) HANGUL SYLLABLE TYELT +D192;D192;1110 1168 11B5;D192;1110 1168 11B5; # (톒; 톒; 톒; 톒; 톒; ) HANGUL SYLLABLE TYELP +D193;D193;1110 1168 11B6;D193;1110 1168 11B6; # (톓; 톓; 톓; 톓; 톓; ) HANGUL SYLLABLE TYELH +D194;D194;1110 1168 11B7;D194;1110 1168 11B7; # (톔; 톔; 톔; 톔; 톔; ) HANGUL SYLLABLE TYEM +D195;D195;1110 1168 11B8;D195;1110 1168 11B8; # (톕; 톕; 톕; 톕; 톕; ) HANGUL SYLLABLE TYEB +D196;D196;1110 1168 11B9;D196;1110 1168 11B9; # (톖; 톖; 톖; 톖; 톖; ) HANGUL SYLLABLE TYEBS +D197;D197;1110 1168 11BA;D197;1110 1168 11BA; # (톗; 톗; 톗; 톗; 톗; ) HANGUL SYLLABLE TYES +D198;D198;1110 1168 11BB;D198;1110 1168 11BB; # (톘; 톘; 톘; 톘; 톘; ) HANGUL SYLLABLE TYESS +D199;D199;1110 1168 11BC;D199;1110 1168 11BC; # (톙; 톙; 톙; 톙; 톙; ) HANGUL SYLLABLE TYENG +D19A;D19A;1110 1168 11BD;D19A;1110 1168 11BD; # (톚; 톚; 톚; 톚; 톚; ) HANGUL SYLLABLE TYEJ +D19B;D19B;1110 1168 11BE;D19B;1110 1168 11BE; # (톛; 톛; 톛; 톛; 톛; ) HANGUL SYLLABLE TYEC +D19C;D19C;1110 1168 11BF;D19C;1110 1168 11BF; # (톜; 톜; 톜; 톜; 톜; ) HANGUL SYLLABLE TYEK +D19D;D19D;1110 1168 11C0;D19D;1110 1168 11C0; # (톝; 톝; 톝; 톝; 톝; ) HANGUL SYLLABLE TYET +D19E;D19E;1110 1168 11C1;D19E;1110 1168 11C1; # (톞; 톞; 톞; 톞; 톞; ) HANGUL SYLLABLE TYEP +D19F;D19F;1110 1168 11C2;D19F;1110 1168 11C2; # (톟; 톟; 톟; 톟; 톟; ) HANGUL SYLLABLE TYEH +D1A0;D1A0;1110 1169;D1A0;1110 1169; # (토; 토; 토; 토; 토; ) HANGUL SYLLABLE TO +D1A1;D1A1;1110 1169 11A8;D1A1;1110 1169 11A8; # (톡; 톡; 톡; 톡; 톡; ) HANGUL SYLLABLE TOG +D1A2;D1A2;1110 1169 11A9;D1A2;1110 1169 11A9; # (톢; 톢; 톢; 톢; 톢; ) HANGUL SYLLABLE TOGG +D1A3;D1A3;1110 1169 11AA;D1A3;1110 1169 11AA; # (톣; 톣; 톣; 톣; 톣; ) HANGUL SYLLABLE TOGS +D1A4;D1A4;1110 1169 11AB;D1A4;1110 1169 11AB; # (톤; 톤; 톤; 톤; 톤; ) HANGUL SYLLABLE TON +D1A5;D1A5;1110 1169 11AC;D1A5;1110 1169 11AC; # (톥; 톥; 톥; 톥; 톥; ) HANGUL SYLLABLE TONJ +D1A6;D1A6;1110 1169 11AD;D1A6;1110 1169 11AD; # (톦; 톦; 톦; 톦; 톦; ) HANGUL SYLLABLE TONH +D1A7;D1A7;1110 1169 11AE;D1A7;1110 1169 11AE; # (톧; 톧; 톧; 톧; 톧; ) HANGUL SYLLABLE TOD +D1A8;D1A8;1110 1169 11AF;D1A8;1110 1169 11AF; # (톨; 톨; 톨; 톨; 톨; ) HANGUL SYLLABLE TOL +D1A9;D1A9;1110 1169 11B0;D1A9;1110 1169 11B0; # (톩; 톩; 톩; 톩; 톩; ) HANGUL SYLLABLE TOLG +D1AA;D1AA;1110 1169 11B1;D1AA;1110 1169 11B1; # (톪; 톪; 톪; 톪; 톪; ) HANGUL SYLLABLE TOLM +D1AB;D1AB;1110 1169 11B2;D1AB;1110 1169 11B2; # (톫; 톫; 톫; 톫; 톫; ) HANGUL SYLLABLE TOLB +D1AC;D1AC;1110 1169 11B3;D1AC;1110 1169 11B3; # (톬; 톬; 톬; 톬; 톬; ) HANGUL SYLLABLE TOLS +D1AD;D1AD;1110 1169 11B4;D1AD;1110 1169 11B4; # (톭; 톭; 톭; 톭; 톭; ) HANGUL SYLLABLE TOLT +D1AE;D1AE;1110 1169 11B5;D1AE;1110 1169 11B5; # (톮; 톮; 톮; 톮; 톮; ) HANGUL SYLLABLE TOLP +D1AF;D1AF;1110 1169 11B6;D1AF;1110 1169 11B6; # (톯; 톯; 톯; 톯; 톯; ) HANGUL SYLLABLE TOLH +D1B0;D1B0;1110 1169 11B7;D1B0;1110 1169 11B7; # (톰; 톰; 톰; 톰; 톰; ) HANGUL SYLLABLE TOM +D1B1;D1B1;1110 1169 11B8;D1B1;1110 1169 11B8; # (톱; 톱; 톱; 톱; 톱; ) HANGUL SYLLABLE TOB +D1B2;D1B2;1110 1169 11B9;D1B2;1110 1169 11B9; # (톲; 톲; 톲; 톲; 톲; ) HANGUL SYLLABLE TOBS +D1B3;D1B3;1110 1169 11BA;D1B3;1110 1169 11BA; # (톳; 톳; 톳; 톳; 톳; ) HANGUL SYLLABLE TOS +D1B4;D1B4;1110 1169 11BB;D1B4;1110 1169 11BB; # (톴; 톴; 톴; 톴; 톴; ) HANGUL SYLLABLE TOSS +D1B5;D1B5;1110 1169 11BC;D1B5;1110 1169 11BC; # (통; 통; 통; 통; 통; ) HANGUL SYLLABLE TONG +D1B6;D1B6;1110 1169 11BD;D1B6;1110 1169 11BD; # (톶; 톶; 톶; 톶; 톶; ) HANGUL SYLLABLE TOJ +D1B7;D1B7;1110 1169 11BE;D1B7;1110 1169 11BE; # (톷; 톷; 톷; 톷; 톷; ) HANGUL SYLLABLE TOC +D1B8;D1B8;1110 1169 11BF;D1B8;1110 1169 11BF; # (톸; 톸; 톸; 톸; 톸; ) HANGUL SYLLABLE TOK +D1B9;D1B9;1110 1169 11C0;D1B9;1110 1169 11C0; # (톹; 톹; 톹; 톹; 톹; ) HANGUL SYLLABLE TOT +D1BA;D1BA;1110 1169 11C1;D1BA;1110 1169 11C1; # (톺; 톺; 톺; 톺; 톺; ) HANGUL SYLLABLE TOP +D1BB;D1BB;1110 1169 11C2;D1BB;1110 1169 11C2; # (톻; 톻; 톻; 톻; 톻; ) HANGUL SYLLABLE TOH +D1BC;D1BC;1110 116A;D1BC;1110 116A; # (톼; 톼; 톼; 톼; 톼; ) HANGUL SYLLABLE TWA +D1BD;D1BD;1110 116A 11A8;D1BD;1110 116A 11A8; # (톽; 톽; 톽; 톽; 톽; ) HANGUL SYLLABLE TWAG +D1BE;D1BE;1110 116A 11A9;D1BE;1110 116A 11A9; # (톾; 톾; 톾; 톾; 톾; ) HANGUL SYLLABLE TWAGG +D1BF;D1BF;1110 116A 11AA;D1BF;1110 116A 11AA; # (톿; 톿; 톿; 톿; 톿; ) HANGUL SYLLABLE TWAGS +D1C0;D1C0;1110 116A 11AB;D1C0;1110 116A 11AB; # (퇀; 퇀; 퇀; 퇀; 퇀; ) HANGUL SYLLABLE TWAN +D1C1;D1C1;1110 116A 11AC;D1C1;1110 116A 11AC; # (퇁; 퇁; 퇁; 퇁; 퇁; ) HANGUL SYLLABLE TWANJ +D1C2;D1C2;1110 116A 11AD;D1C2;1110 116A 11AD; # (퇂; 퇂; 퇂; 퇂; 퇂; ) HANGUL SYLLABLE TWANH +D1C3;D1C3;1110 116A 11AE;D1C3;1110 116A 11AE; # (퇃; 퇃; 퇃; 퇃; 퇃; ) HANGUL SYLLABLE TWAD +D1C4;D1C4;1110 116A 11AF;D1C4;1110 116A 11AF; # (퇄; 퇄; 퇄; 퇄; 퇄; ) HANGUL SYLLABLE TWAL +D1C5;D1C5;1110 116A 11B0;D1C5;1110 116A 11B0; # (퇅; 퇅; 퇅; 퇅; 퇅; ) HANGUL SYLLABLE TWALG +D1C6;D1C6;1110 116A 11B1;D1C6;1110 116A 11B1; # (퇆; 퇆; 퇆; 퇆; 퇆; ) HANGUL SYLLABLE TWALM +D1C7;D1C7;1110 116A 11B2;D1C7;1110 116A 11B2; # (퇇; 퇇; 퇇; 퇇; 퇇; ) HANGUL SYLLABLE TWALB +D1C8;D1C8;1110 116A 11B3;D1C8;1110 116A 11B3; # (퇈; 퇈; 퇈; 퇈; 퇈; ) HANGUL SYLLABLE TWALS +D1C9;D1C9;1110 116A 11B4;D1C9;1110 116A 11B4; # (퇉; 퇉; 퇉; 퇉; 퇉; ) HANGUL SYLLABLE TWALT +D1CA;D1CA;1110 116A 11B5;D1CA;1110 116A 11B5; # (퇊; 퇊; 퇊; 퇊; 퇊; ) HANGUL SYLLABLE TWALP +D1CB;D1CB;1110 116A 11B6;D1CB;1110 116A 11B6; # (퇋; 퇋; 퇋; 퇋; 퇋; ) HANGUL SYLLABLE TWALH +D1CC;D1CC;1110 116A 11B7;D1CC;1110 116A 11B7; # (퇌; 퇌; 퇌; 퇌; 퇌; ) HANGUL SYLLABLE TWAM +D1CD;D1CD;1110 116A 11B8;D1CD;1110 116A 11B8; # (퇍; 퇍; 퇍; 퇍; 퇍; ) HANGUL SYLLABLE TWAB +D1CE;D1CE;1110 116A 11B9;D1CE;1110 116A 11B9; # (퇎; 퇎; 퇎; 퇎; 퇎; ) HANGUL SYLLABLE TWABS +D1CF;D1CF;1110 116A 11BA;D1CF;1110 116A 11BA; # (퇏; 퇏; 퇏; 퇏; 퇏; ) HANGUL SYLLABLE TWAS +D1D0;D1D0;1110 116A 11BB;D1D0;1110 116A 11BB; # (퇐; 퇐; 퇐; 퇐; 퇐; ) HANGUL SYLLABLE TWASS +D1D1;D1D1;1110 116A 11BC;D1D1;1110 116A 11BC; # (퇑; 퇑; 퇑; 퇑; 퇑; ) HANGUL SYLLABLE TWANG +D1D2;D1D2;1110 116A 11BD;D1D2;1110 116A 11BD; # (퇒; 퇒; 퇒; 퇒; 퇒; ) HANGUL SYLLABLE TWAJ +D1D3;D1D3;1110 116A 11BE;D1D3;1110 116A 11BE; # (퇓; 퇓; 퇓; 퇓; 퇓; ) HANGUL SYLLABLE TWAC +D1D4;D1D4;1110 116A 11BF;D1D4;1110 116A 11BF; # (퇔; 퇔; 퇔; 퇔; 퇔; ) HANGUL SYLLABLE TWAK +D1D5;D1D5;1110 116A 11C0;D1D5;1110 116A 11C0; # (퇕; 퇕; 퇕; 퇕; 퇕; ) HANGUL SYLLABLE TWAT +D1D6;D1D6;1110 116A 11C1;D1D6;1110 116A 11C1; # (퇖; 퇖; 퇖; 퇖; 퇖; ) HANGUL SYLLABLE TWAP +D1D7;D1D7;1110 116A 11C2;D1D7;1110 116A 11C2; # (퇗; 퇗; 퇗; 퇗; 퇗; ) HANGUL SYLLABLE TWAH +D1D8;D1D8;1110 116B;D1D8;1110 116B; # (퇘; 퇘; 퇘; 퇘; 퇘; ) HANGUL SYLLABLE TWAE +D1D9;D1D9;1110 116B 11A8;D1D9;1110 116B 11A8; # (퇙; 퇙; 퇙; 퇙; 퇙; ) HANGUL SYLLABLE TWAEG +D1DA;D1DA;1110 116B 11A9;D1DA;1110 116B 11A9; # (퇚; 퇚; 퇚; 퇚; 퇚; ) HANGUL SYLLABLE TWAEGG +D1DB;D1DB;1110 116B 11AA;D1DB;1110 116B 11AA; # (퇛; 퇛; 퇛; 퇛; 퇛; ) HANGUL SYLLABLE TWAEGS +D1DC;D1DC;1110 116B 11AB;D1DC;1110 116B 11AB; # (퇜; 퇜; 퇜; 퇜; 퇜; ) HANGUL SYLLABLE TWAEN +D1DD;D1DD;1110 116B 11AC;D1DD;1110 116B 11AC; # (퇝; 퇝; 퇝; 퇝; 퇝; ) HANGUL SYLLABLE TWAENJ +D1DE;D1DE;1110 116B 11AD;D1DE;1110 116B 11AD; # (퇞; 퇞; 퇞; 퇞; 퇞; ) HANGUL SYLLABLE TWAENH +D1DF;D1DF;1110 116B 11AE;D1DF;1110 116B 11AE; # (퇟; 퇟; 퇟; 퇟; 퇟; ) HANGUL SYLLABLE TWAED +D1E0;D1E0;1110 116B 11AF;D1E0;1110 116B 11AF; # (퇠; 퇠; 퇠; 퇠; 퇠; ) HANGUL SYLLABLE TWAEL +D1E1;D1E1;1110 116B 11B0;D1E1;1110 116B 11B0; # (퇡; 퇡; 퇡; 퇡; 퇡; ) HANGUL SYLLABLE TWAELG +D1E2;D1E2;1110 116B 11B1;D1E2;1110 116B 11B1; # (퇢; 퇢; 퇢; 퇢; 퇢; ) HANGUL SYLLABLE TWAELM +D1E3;D1E3;1110 116B 11B2;D1E3;1110 116B 11B2; # (퇣; 퇣; 퇣; 퇣; 퇣; ) HANGUL SYLLABLE TWAELB +D1E4;D1E4;1110 116B 11B3;D1E4;1110 116B 11B3; # (퇤; 퇤; 퇤; 퇤; 퇤; ) HANGUL SYLLABLE TWAELS +D1E5;D1E5;1110 116B 11B4;D1E5;1110 116B 11B4; # (퇥; 퇥; 퇥; 퇥; 퇥; ) HANGUL SYLLABLE TWAELT +D1E6;D1E6;1110 116B 11B5;D1E6;1110 116B 11B5; # (퇦; 퇦; 퇦; 퇦; 퇦; ) HANGUL SYLLABLE TWAELP +D1E7;D1E7;1110 116B 11B6;D1E7;1110 116B 11B6; # (퇧; 퇧; 퇧; 퇧; 퇧; ) HANGUL SYLLABLE TWAELH +D1E8;D1E8;1110 116B 11B7;D1E8;1110 116B 11B7; # (퇨; 퇨; 퇨; 퇨; 퇨; ) HANGUL SYLLABLE TWAEM +D1E9;D1E9;1110 116B 11B8;D1E9;1110 116B 11B8; # (퇩; 퇩; 퇩; 퇩; 퇩; ) HANGUL SYLLABLE TWAEB +D1EA;D1EA;1110 116B 11B9;D1EA;1110 116B 11B9; # (퇪; 퇪; 퇪; 퇪; 퇪; ) HANGUL SYLLABLE TWAEBS +D1EB;D1EB;1110 116B 11BA;D1EB;1110 116B 11BA; # (퇫; 퇫; 퇫; 퇫; 퇫; ) HANGUL SYLLABLE TWAES +D1EC;D1EC;1110 116B 11BB;D1EC;1110 116B 11BB; # (퇬; 퇬; 퇬; 퇬; 퇬; ) HANGUL SYLLABLE TWAESS +D1ED;D1ED;1110 116B 11BC;D1ED;1110 116B 11BC; # (퇭; 퇭; 퇭; 퇭; 퇭; ) HANGUL SYLLABLE TWAENG +D1EE;D1EE;1110 116B 11BD;D1EE;1110 116B 11BD; # (퇮; 퇮; 퇮; 퇮; 퇮; ) HANGUL SYLLABLE TWAEJ +D1EF;D1EF;1110 116B 11BE;D1EF;1110 116B 11BE; # (퇯; 퇯; 퇯; 퇯; 퇯; ) HANGUL SYLLABLE TWAEC +D1F0;D1F0;1110 116B 11BF;D1F0;1110 116B 11BF; # (퇰; 퇰; 퇰; 퇰; 퇰; ) HANGUL SYLLABLE TWAEK +D1F1;D1F1;1110 116B 11C0;D1F1;1110 116B 11C0; # (퇱; 퇱; 퇱; 퇱; 퇱; ) HANGUL SYLLABLE TWAET +D1F2;D1F2;1110 116B 11C1;D1F2;1110 116B 11C1; # (퇲; 퇲; 퇲; 퇲; 퇲; ) HANGUL SYLLABLE TWAEP +D1F3;D1F3;1110 116B 11C2;D1F3;1110 116B 11C2; # (퇳; 퇳; 퇳; 퇳; 퇳; ) HANGUL SYLLABLE TWAEH +D1F4;D1F4;1110 116C;D1F4;1110 116C; # (퇴; 퇴; 퇴; 퇴; 퇴; ) HANGUL SYLLABLE TOE +D1F5;D1F5;1110 116C 11A8;D1F5;1110 116C 11A8; # (퇵; 퇵; 퇵; 퇵; 퇵; ) HANGUL SYLLABLE TOEG +D1F6;D1F6;1110 116C 11A9;D1F6;1110 116C 11A9; # (퇶; 퇶; 퇶; 퇶; 퇶; ) HANGUL SYLLABLE TOEGG +D1F7;D1F7;1110 116C 11AA;D1F7;1110 116C 11AA; # (퇷; 퇷; 퇷; 퇷; 퇷; ) HANGUL SYLLABLE TOEGS +D1F8;D1F8;1110 116C 11AB;D1F8;1110 116C 11AB; # (퇸; 퇸; 퇸; 퇸; 퇸; ) HANGUL SYLLABLE TOEN +D1F9;D1F9;1110 116C 11AC;D1F9;1110 116C 11AC; # (퇹; 퇹; 퇹; 퇹; 퇹; ) HANGUL SYLLABLE TOENJ +D1FA;D1FA;1110 116C 11AD;D1FA;1110 116C 11AD; # (퇺; 퇺; 퇺; 퇺; 퇺; ) HANGUL SYLLABLE TOENH +D1FB;D1FB;1110 116C 11AE;D1FB;1110 116C 11AE; # (퇻; 퇻; 퇻; 퇻; 퇻; ) HANGUL SYLLABLE TOED +D1FC;D1FC;1110 116C 11AF;D1FC;1110 116C 11AF; # (퇼; 퇼; 퇼; 퇼; 퇼; ) HANGUL SYLLABLE TOEL +D1FD;D1FD;1110 116C 11B0;D1FD;1110 116C 11B0; # (퇽; 퇽; 퇽; 퇽; 퇽; ) HANGUL SYLLABLE TOELG +D1FE;D1FE;1110 116C 11B1;D1FE;1110 116C 11B1; # (퇾; 퇾; 퇾; 퇾; 퇾; ) HANGUL SYLLABLE TOELM +D1FF;D1FF;1110 116C 11B2;D1FF;1110 116C 11B2; # (퇿; 퇿; 퇿; 퇿; 퇿; ) HANGUL SYLLABLE TOELB +D200;D200;1110 116C 11B3;D200;1110 116C 11B3; # (툀; 툀; 툀; 툀; 툀; ) HANGUL SYLLABLE TOELS +D201;D201;1110 116C 11B4;D201;1110 116C 11B4; # (툁; 툁; 툁; 툁; 툁; ) HANGUL SYLLABLE TOELT +D202;D202;1110 116C 11B5;D202;1110 116C 11B5; # (툂; 툂; 툂; 툂; 툂; ) HANGUL SYLLABLE TOELP +D203;D203;1110 116C 11B6;D203;1110 116C 11B6; # (툃; 툃; 툃; 툃; 툃; ) HANGUL SYLLABLE TOELH +D204;D204;1110 116C 11B7;D204;1110 116C 11B7; # (툄; 툄; 툄; 툄; 툄; ) HANGUL SYLLABLE TOEM +D205;D205;1110 116C 11B8;D205;1110 116C 11B8; # (툅; 툅; 툅; 툅; 툅; ) HANGUL SYLLABLE TOEB +D206;D206;1110 116C 11B9;D206;1110 116C 11B9; # (툆; 툆; 툆; 툆; 툆; ) HANGUL SYLLABLE TOEBS +D207;D207;1110 116C 11BA;D207;1110 116C 11BA; # (툇; 툇; 툇; 툇; 툇; ) HANGUL SYLLABLE TOES +D208;D208;1110 116C 11BB;D208;1110 116C 11BB; # (툈; 툈; 툈; 툈; 툈; ) HANGUL SYLLABLE TOESS +D209;D209;1110 116C 11BC;D209;1110 116C 11BC; # (툉; 툉; 툉; 툉; 툉; ) HANGUL SYLLABLE TOENG +D20A;D20A;1110 116C 11BD;D20A;1110 116C 11BD; # (툊; 툊; 툊; 툊; 툊; ) HANGUL SYLLABLE TOEJ +D20B;D20B;1110 116C 11BE;D20B;1110 116C 11BE; # (툋; 툋; 툋; 툋; 툋; ) HANGUL SYLLABLE TOEC +D20C;D20C;1110 116C 11BF;D20C;1110 116C 11BF; # (툌; 툌; 툌; 툌; 툌; ) HANGUL SYLLABLE TOEK +D20D;D20D;1110 116C 11C0;D20D;1110 116C 11C0; # (툍; 툍; 툍; 툍; 툍; ) HANGUL SYLLABLE TOET +D20E;D20E;1110 116C 11C1;D20E;1110 116C 11C1; # (툎; 툎; 툎; 툎; 툎; ) HANGUL SYLLABLE TOEP +D20F;D20F;1110 116C 11C2;D20F;1110 116C 11C2; # (툏; 툏; 툏; 툏; 툏; ) HANGUL SYLLABLE TOEH +D210;D210;1110 116D;D210;1110 116D; # (툐; 툐; 툐; 툐; 툐; ) HANGUL SYLLABLE TYO +D211;D211;1110 116D 11A8;D211;1110 116D 11A8; # (툑; 툑; 툑; 툑; 툑; ) HANGUL SYLLABLE TYOG +D212;D212;1110 116D 11A9;D212;1110 116D 11A9; # (툒; 툒; 툒; 툒; 툒; ) HANGUL SYLLABLE TYOGG +D213;D213;1110 116D 11AA;D213;1110 116D 11AA; # (툓; 툓; 툓; 툓; 툓; ) HANGUL SYLLABLE TYOGS +D214;D214;1110 116D 11AB;D214;1110 116D 11AB; # (툔; 툔; 툔; 툔; 툔; ) HANGUL SYLLABLE TYON +D215;D215;1110 116D 11AC;D215;1110 116D 11AC; # (툕; 툕; 툕; 툕; 툕; ) HANGUL SYLLABLE TYONJ +D216;D216;1110 116D 11AD;D216;1110 116D 11AD; # (툖; 툖; 툖; 툖; 툖; ) HANGUL SYLLABLE TYONH +D217;D217;1110 116D 11AE;D217;1110 116D 11AE; # (툗; 툗; 툗; 툗; 툗; ) HANGUL SYLLABLE TYOD +D218;D218;1110 116D 11AF;D218;1110 116D 11AF; # (툘; 툘; 툘; 툘; 툘; ) HANGUL SYLLABLE TYOL +D219;D219;1110 116D 11B0;D219;1110 116D 11B0; # (툙; 툙; 툙; 툙; 툙; ) HANGUL SYLLABLE TYOLG +D21A;D21A;1110 116D 11B1;D21A;1110 116D 11B1; # (툚; 툚; 툚; 툚; 툚; ) HANGUL SYLLABLE TYOLM +D21B;D21B;1110 116D 11B2;D21B;1110 116D 11B2; # (툛; 툛; 툛; 툛; 툛; ) HANGUL SYLLABLE TYOLB +D21C;D21C;1110 116D 11B3;D21C;1110 116D 11B3; # (툜; 툜; 툜; 툜; 툜; ) HANGUL SYLLABLE TYOLS +D21D;D21D;1110 116D 11B4;D21D;1110 116D 11B4; # (툝; 툝; 툝; 툝; 툝; ) HANGUL SYLLABLE TYOLT +D21E;D21E;1110 116D 11B5;D21E;1110 116D 11B5; # (툞; 툞; 툞; 툞; 툞; ) HANGUL SYLLABLE TYOLP +D21F;D21F;1110 116D 11B6;D21F;1110 116D 11B6; # (툟; 툟; 툟; 툟; 툟; ) HANGUL SYLLABLE TYOLH +D220;D220;1110 116D 11B7;D220;1110 116D 11B7; # (툠; 툠; 툠; 툠; 툠; ) HANGUL SYLLABLE TYOM +D221;D221;1110 116D 11B8;D221;1110 116D 11B8; # (툡; 툡; 툡; 툡; 툡; ) HANGUL SYLLABLE TYOB +D222;D222;1110 116D 11B9;D222;1110 116D 11B9; # (툢; 툢; 툢; 툢; 툢; ) HANGUL SYLLABLE TYOBS +D223;D223;1110 116D 11BA;D223;1110 116D 11BA; # (툣; 툣; 툣; 툣; 툣; ) HANGUL SYLLABLE TYOS +D224;D224;1110 116D 11BB;D224;1110 116D 11BB; # (툤; 툤; 툤; 툤; 툤; ) HANGUL SYLLABLE TYOSS +D225;D225;1110 116D 11BC;D225;1110 116D 11BC; # (툥; 툥; 툥; 툥; 툥; ) HANGUL SYLLABLE TYONG +D226;D226;1110 116D 11BD;D226;1110 116D 11BD; # (툦; 툦; 툦; 툦; 툦; ) HANGUL SYLLABLE TYOJ +D227;D227;1110 116D 11BE;D227;1110 116D 11BE; # (툧; 툧; 툧; 툧; 툧; ) HANGUL SYLLABLE TYOC +D228;D228;1110 116D 11BF;D228;1110 116D 11BF; # (툨; 툨; 툨; 툨; 툨; ) HANGUL SYLLABLE TYOK +D229;D229;1110 116D 11C0;D229;1110 116D 11C0; # (툩; 툩; 툩; 툩; 툩; ) HANGUL SYLLABLE TYOT +D22A;D22A;1110 116D 11C1;D22A;1110 116D 11C1; # (툪; 툪; 툪; 툪; 툪; ) HANGUL SYLLABLE TYOP +D22B;D22B;1110 116D 11C2;D22B;1110 116D 11C2; # (툫; 툫; 툫; 툫; 툫; ) HANGUL SYLLABLE TYOH +D22C;D22C;1110 116E;D22C;1110 116E; # (투; 투; 투; 투; 투; ) HANGUL SYLLABLE TU +D22D;D22D;1110 116E 11A8;D22D;1110 116E 11A8; # (툭; 툭; 툭; 툭; 툭; ) HANGUL SYLLABLE TUG +D22E;D22E;1110 116E 11A9;D22E;1110 116E 11A9; # (툮; 툮; 툮; 툮; 툮; ) HANGUL SYLLABLE TUGG +D22F;D22F;1110 116E 11AA;D22F;1110 116E 11AA; # (툯; 툯; 툯; 툯; 툯; ) HANGUL SYLLABLE TUGS +D230;D230;1110 116E 11AB;D230;1110 116E 11AB; # (툰; 툰; 툰; 툰; 툰; ) HANGUL SYLLABLE TUN +D231;D231;1110 116E 11AC;D231;1110 116E 11AC; # (툱; 툱; 툱; 툱; 툱; ) HANGUL SYLLABLE TUNJ +D232;D232;1110 116E 11AD;D232;1110 116E 11AD; # (툲; 툲; 툲; 툲; 툲; ) HANGUL SYLLABLE TUNH +D233;D233;1110 116E 11AE;D233;1110 116E 11AE; # (툳; 툳; 툳; 툳; 툳; ) HANGUL SYLLABLE TUD +D234;D234;1110 116E 11AF;D234;1110 116E 11AF; # (툴; 툴; 툴; 툴; 툴; ) HANGUL SYLLABLE TUL +D235;D235;1110 116E 11B0;D235;1110 116E 11B0; # (툵; 툵; 툵; 툵; 툵; ) HANGUL SYLLABLE TULG +D236;D236;1110 116E 11B1;D236;1110 116E 11B1; # (툶; 툶; 툶; 툶; 툶; ) HANGUL SYLLABLE TULM +D237;D237;1110 116E 11B2;D237;1110 116E 11B2; # (툷; 툷; 툷; 툷; 툷; ) HANGUL SYLLABLE TULB +D238;D238;1110 116E 11B3;D238;1110 116E 11B3; # (툸; 툸; 툸; 툸; 툸; ) HANGUL SYLLABLE TULS +D239;D239;1110 116E 11B4;D239;1110 116E 11B4; # (툹; 툹; 툹; 툹; 툹; ) HANGUL SYLLABLE TULT +D23A;D23A;1110 116E 11B5;D23A;1110 116E 11B5; # (툺; 툺; 툺; 툺; 툺; ) HANGUL SYLLABLE TULP +D23B;D23B;1110 116E 11B6;D23B;1110 116E 11B6; # (툻; 툻; 툻; 툻; 툻; ) HANGUL SYLLABLE TULH +D23C;D23C;1110 116E 11B7;D23C;1110 116E 11B7; # (툼; 툼; 툼; 툼; 툼; ) HANGUL SYLLABLE TUM +D23D;D23D;1110 116E 11B8;D23D;1110 116E 11B8; # (툽; 툽; 툽; 툽; 툽; ) HANGUL SYLLABLE TUB +D23E;D23E;1110 116E 11B9;D23E;1110 116E 11B9; # (툾; 툾; 툾; 툾; 툾; ) HANGUL SYLLABLE TUBS +D23F;D23F;1110 116E 11BA;D23F;1110 116E 11BA; # (툿; 툿; 툿; 툿; 툿; ) HANGUL SYLLABLE TUS +D240;D240;1110 116E 11BB;D240;1110 116E 11BB; # (퉀; 퉀; 퉀; 퉀; 퉀; ) HANGUL SYLLABLE TUSS +D241;D241;1110 116E 11BC;D241;1110 116E 11BC; # (퉁; 퉁; 퉁; 퉁; 퉁; ) HANGUL SYLLABLE TUNG +D242;D242;1110 116E 11BD;D242;1110 116E 11BD; # (퉂; 퉂; 퉂; 퉂; 퉂; ) HANGUL SYLLABLE TUJ +D243;D243;1110 116E 11BE;D243;1110 116E 11BE; # (퉃; 퉃; 퉃; 퉃; 퉃; ) HANGUL SYLLABLE TUC +D244;D244;1110 116E 11BF;D244;1110 116E 11BF; # (퉄; 퉄; 퉄; 퉄; 퉄; ) HANGUL SYLLABLE TUK +D245;D245;1110 116E 11C0;D245;1110 116E 11C0; # (퉅; 퉅; 퉅; 퉅; 퉅; ) HANGUL SYLLABLE TUT +D246;D246;1110 116E 11C1;D246;1110 116E 11C1; # (퉆; 퉆; 퉆; 퉆; 퉆; ) HANGUL SYLLABLE TUP +D247;D247;1110 116E 11C2;D247;1110 116E 11C2; # (퉇; 퉇; 퉇; 퉇; 퉇; ) HANGUL SYLLABLE TUH +D248;D248;1110 116F;D248;1110 116F; # (퉈; 퉈; 퉈; 퉈; 퉈; ) HANGUL SYLLABLE TWEO +D249;D249;1110 116F 11A8;D249;1110 116F 11A8; # (퉉; 퉉; 퉉; 퉉; 퉉; ) HANGUL SYLLABLE TWEOG +D24A;D24A;1110 116F 11A9;D24A;1110 116F 11A9; # (퉊; 퉊; 퉊; 퉊; 퉊; ) HANGUL SYLLABLE TWEOGG +D24B;D24B;1110 116F 11AA;D24B;1110 116F 11AA; # (퉋; 퉋; 퉋; 퉋; 퉋; ) HANGUL SYLLABLE TWEOGS +D24C;D24C;1110 116F 11AB;D24C;1110 116F 11AB; # (퉌; 퉌; 퉌; 퉌; 퉌; ) HANGUL SYLLABLE TWEON +D24D;D24D;1110 116F 11AC;D24D;1110 116F 11AC; # (퉍; 퉍; 퉍; 퉍; 퉍; ) HANGUL SYLLABLE TWEONJ +D24E;D24E;1110 116F 11AD;D24E;1110 116F 11AD; # (퉎; 퉎; 퉎; 퉎; 퉎; ) HANGUL SYLLABLE TWEONH +D24F;D24F;1110 116F 11AE;D24F;1110 116F 11AE; # (퉏; 퉏; 퉏; 퉏; 퉏; ) HANGUL SYLLABLE TWEOD +D250;D250;1110 116F 11AF;D250;1110 116F 11AF; # (퉐; 퉐; 퉐; 퉐; 퉐; ) HANGUL SYLLABLE TWEOL +D251;D251;1110 116F 11B0;D251;1110 116F 11B0; # (퉑; 퉑; 퉑; 퉑; 퉑; ) HANGUL SYLLABLE TWEOLG +D252;D252;1110 116F 11B1;D252;1110 116F 11B1; # (퉒; 퉒; 퉒; 퉒; 퉒; ) HANGUL SYLLABLE TWEOLM +D253;D253;1110 116F 11B2;D253;1110 116F 11B2; # (퉓; 퉓; 퉓; 퉓; 퉓; ) HANGUL SYLLABLE TWEOLB +D254;D254;1110 116F 11B3;D254;1110 116F 11B3; # (퉔; 퉔; 퉔; 퉔; 퉔; ) HANGUL SYLLABLE TWEOLS +D255;D255;1110 116F 11B4;D255;1110 116F 11B4; # (퉕; 퉕; 퉕; 퉕; 퉕; ) HANGUL SYLLABLE TWEOLT +D256;D256;1110 116F 11B5;D256;1110 116F 11B5; # (퉖; 퉖; 퉖; 퉖; 퉖; ) HANGUL SYLLABLE TWEOLP +D257;D257;1110 116F 11B6;D257;1110 116F 11B6; # (퉗; 퉗; 퉗; 퉗; 퉗; ) HANGUL SYLLABLE TWEOLH +D258;D258;1110 116F 11B7;D258;1110 116F 11B7; # (퉘; 퉘; 퉘; 퉘; 퉘; ) HANGUL SYLLABLE TWEOM +D259;D259;1110 116F 11B8;D259;1110 116F 11B8; # (퉙; 퉙; 퉙; 퉙; 퉙; ) HANGUL SYLLABLE TWEOB +D25A;D25A;1110 116F 11B9;D25A;1110 116F 11B9; # (퉚; 퉚; 퉚; 퉚; 퉚; ) HANGUL SYLLABLE TWEOBS +D25B;D25B;1110 116F 11BA;D25B;1110 116F 11BA; # (퉛; 퉛; 퉛; 퉛; 퉛; ) HANGUL SYLLABLE TWEOS +D25C;D25C;1110 116F 11BB;D25C;1110 116F 11BB; # (퉜; 퉜; 퉜; 퉜; 퉜; ) HANGUL SYLLABLE TWEOSS +D25D;D25D;1110 116F 11BC;D25D;1110 116F 11BC; # (퉝; 퉝; 퉝; 퉝; 퉝; ) HANGUL SYLLABLE TWEONG +D25E;D25E;1110 116F 11BD;D25E;1110 116F 11BD; # (퉞; 퉞; 퉞; 퉞; 퉞; ) HANGUL SYLLABLE TWEOJ +D25F;D25F;1110 116F 11BE;D25F;1110 116F 11BE; # (퉟; 퉟; 퉟; 퉟; 퉟; ) HANGUL SYLLABLE TWEOC +D260;D260;1110 116F 11BF;D260;1110 116F 11BF; # (퉠; 퉠; 퉠; 퉠; 퉠; ) HANGUL SYLLABLE TWEOK +D261;D261;1110 116F 11C0;D261;1110 116F 11C0; # (퉡; 퉡; 퉡; 퉡; 퉡; ) HANGUL SYLLABLE TWEOT +D262;D262;1110 116F 11C1;D262;1110 116F 11C1; # (퉢; 퉢; 퉢; 퉢; 퉢; ) HANGUL SYLLABLE TWEOP +D263;D263;1110 116F 11C2;D263;1110 116F 11C2; # (퉣; 퉣; 퉣; 퉣; 퉣; ) HANGUL SYLLABLE TWEOH +D264;D264;1110 1170;D264;1110 1170; # (퉤; 퉤; 퉤; 퉤; 퉤; ) HANGUL SYLLABLE TWE +D265;D265;1110 1170 11A8;D265;1110 1170 11A8; # (퉥; 퉥; 퉥; 퉥; 퉥; ) HANGUL SYLLABLE TWEG +D266;D266;1110 1170 11A9;D266;1110 1170 11A9; # (퉦; 퉦; 퉦; 퉦; 퉦; ) HANGUL SYLLABLE TWEGG +D267;D267;1110 1170 11AA;D267;1110 1170 11AA; # (퉧; 퉧; 퉧; 퉧; 퉧; ) HANGUL SYLLABLE TWEGS +D268;D268;1110 1170 11AB;D268;1110 1170 11AB; # (퉨; 퉨; 퉨; 퉨; 퉨; ) HANGUL SYLLABLE TWEN +D269;D269;1110 1170 11AC;D269;1110 1170 11AC; # (퉩; 퉩; 퉩; 퉩; 퉩; ) HANGUL SYLLABLE TWENJ +D26A;D26A;1110 1170 11AD;D26A;1110 1170 11AD; # (퉪; 퉪; 퉪; 퉪; 퉪; ) HANGUL SYLLABLE TWENH +D26B;D26B;1110 1170 11AE;D26B;1110 1170 11AE; # (퉫; 퉫; 퉫; 퉫; 퉫; ) HANGUL SYLLABLE TWED +D26C;D26C;1110 1170 11AF;D26C;1110 1170 11AF; # (퉬; 퉬; 퉬; 퉬; 퉬; ) HANGUL SYLLABLE TWEL +D26D;D26D;1110 1170 11B0;D26D;1110 1170 11B0; # (퉭; 퉭; 퉭; 퉭; 퉭; ) HANGUL SYLLABLE TWELG +D26E;D26E;1110 1170 11B1;D26E;1110 1170 11B1; # (퉮; 퉮; 퉮; 퉮; 퉮; ) HANGUL SYLLABLE TWELM +D26F;D26F;1110 1170 11B2;D26F;1110 1170 11B2; # (퉯; 퉯; 퉯; 퉯; 퉯; ) HANGUL SYLLABLE TWELB +D270;D270;1110 1170 11B3;D270;1110 1170 11B3; # (퉰; 퉰; 퉰; 퉰; 퉰; ) HANGUL SYLLABLE TWELS +D271;D271;1110 1170 11B4;D271;1110 1170 11B4; # (퉱; 퉱; 퉱; 퉱; 퉱; ) HANGUL SYLLABLE TWELT +D272;D272;1110 1170 11B5;D272;1110 1170 11B5; # (퉲; 퉲; 퉲; 퉲; 퉲; ) HANGUL SYLLABLE TWELP +D273;D273;1110 1170 11B6;D273;1110 1170 11B6; # (퉳; 퉳; 퉳; 퉳; 퉳; ) HANGUL SYLLABLE TWELH +D274;D274;1110 1170 11B7;D274;1110 1170 11B7; # (퉴; 퉴; 퉴; 퉴; 퉴; ) HANGUL SYLLABLE TWEM +D275;D275;1110 1170 11B8;D275;1110 1170 11B8; # (퉵; 퉵; 퉵; 퉵; 퉵; ) HANGUL SYLLABLE TWEB +D276;D276;1110 1170 11B9;D276;1110 1170 11B9; # (퉶; 퉶; 퉶; 퉶; 퉶; ) HANGUL SYLLABLE TWEBS +D277;D277;1110 1170 11BA;D277;1110 1170 11BA; # (퉷; 퉷; 퉷; 퉷; 퉷; ) HANGUL SYLLABLE TWES +D278;D278;1110 1170 11BB;D278;1110 1170 11BB; # (퉸; 퉸; 퉸; 퉸; 퉸; ) HANGUL SYLLABLE TWESS +D279;D279;1110 1170 11BC;D279;1110 1170 11BC; # (퉹; 퉹; 퉹; 퉹; 퉹; ) HANGUL SYLLABLE TWENG +D27A;D27A;1110 1170 11BD;D27A;1110 1170 11BD; # (퉺; 퉺; 퉺; 퉺; 퉺; ) HANGUL SYLLABLE TWEJ +D27B;D27B;1110 1170 11BE;D27B;1110 1170 11BE; # (퉻; 퉻; 퉻; 퉻; 퉻; ) HANGUL SYLLABLE TWEC +D27C;D27C;1110 1170 11BF;D27C;1110 1170 11BF; # (퉼; 퉼; 퉼; 퉼; 퉼; ) HANGUL SYLLABLE TWEK +D27D;D27D;1110 1170 11C0;D27D;1110 1170 11C0; # (퉽; 퉽; 퉽; 퉽; 퉽; ) HANGUL SYLLABLE TWET +D27E;D27E;1110 1170 11C1;D27E;1110 1170 11C1; # (퉾; 퉾; 퉾; 퉾; 퉾; ) HANGUL SYLLABLE TWEP +D27F;D27F;1110 1170 11C2;D27F;1110 1170 11C2; # (퉿; 퉿; 퉿; 퉿; 퉿; ) HANGUL SYLLABLE TWEH +D280;D280;1110 1171;D280;1110 1171; # (튀; 튀; 튀; 튀; 튀; ) HANGUL SYLLABLE TWI +D281;D281;1110 1171 11A8;D281;1110 1171 11A8; # (튁; 튁; 튁; 튁; 튁; ) HANGUL SYLLABLE TWIG +D282;D282;1110 1171 11A9;D282;1110 1171 11A9; # (튂; 튂; 튂; 튂; 튂; ) HANGUL SYLLABLE TWIGG +D283;D283;1110 1171 11AA;D283;1110 1171 11AA; # (튃; 튃; 튃; 튃; 튃; ) HANGUL SYLLABLE TWIGS +D284;D284;1110 1171 11AB;D284;1110 1171 11AB; # (튄; 튄; 튄; 튄; 튄; ) HANGUL SYLLABLE TWIN +D285;D285;1110 1171 11AC;D285;1110 1171 11AC; # (튅; 튅; 튅; 튅; 튅; ) HANGUL SYLLABLE TWINJ +D286;D286;1110 1171 11AD;D286;1110 1171 11AD; # (튆; 튆; 튆; 튆; 튆; ) HANGUL SYLLABLE TWINH +D287;D287;1110 1171 11AE;D287;1110 1171 11AE; # (튇; 튇; 튇; 튇; 튇; ) HANGUL SYLLABLE TWID +D288;D288;1110 1171 11AF;D288;1110 1171 11AF; # (튈; 튈; 튈; 튈; 튈; ) HANGUL SYLLABLE TWIL +D289;D289;1110 1171 11B0;D289;1110 1171 11B0; # (튉; 튉; 튉; 튉; 튉; ) HANGUL SYLLABLE TWILG +D28A;D28A;1110 1171 11B1;D28A;1110 1171 11B1; # (튊; 튊; 튊; 튊; 튊; ) HANGUL SYLLABLE TWILM +D28B;D28B;1110 1171 11B2;D28B;1110 1171 11B2; # (튋; 튋; 튋; 튋; 튋; ) HANGUL SYLLABLE TWILB +D28C;D28C;1110 1171 11B3;D28C;1110 1171 11B3; # (튌; 튌; 튌; 튌; 튌; ) HANGUL SYLLABLE TWILS +D28D;D28D;1110 1171 11B4;D28D;1110 1171 11B4; # (튍; 튍; 튍; 튍; 튍; ) HANGUL SYLLABLE TWILT +D28E;D28E;1110 1171 11B5;D28E;1110 1171 11B5; # (튎; 튎; 튎; 튎; 튎; ) HANGUL SYLLABLE TWILP +D28F;D28F;1110 1171 11B6;D28F;1110 1171 11B6; # (튏; 튏; 튏; 튏; 튏; ) HANGUL SYLLABLE TWILH +D290;D290;1110 1171 11B7;D290;1110 1171 11B7; # (튐; 튐; 튐; 튐; 튐; ) HANGUL SYLLABLE TWIM +D291;D291;1110 1171 11B8;D291;1110 1171 11B8; # (튑; 튑; 튑; 튑; 튑; ) HANGUL SYLLABLE TWIB +D292;D292;1110 1171 11B9;D292;1110 1171 11B9; # (튒; 튒; 튒; 튒; 튒; ) HANGUL SYLLABLE TWIBS +D293;D293;1110 1171 11BA;D293;1110 1171 11BA; # (튓; 튓; 튓; 튓; 튓; ) HANGUL SYLLABLE TWIS +D294;D294;1110 1171 11BB;D294;1110 1171 11BB; # (튔; 튔; 튔; 튔; 튔; ) HANGUL SYLLABLE TWISS +D295;D295;1110 1171 11BC;D295;1110 1171 11BC; # (튕; 튕; 튕; 튕; 튕; ) HANGUL SYLLABLE TWING +D296;D296;1110 1171 11BD;D296;1110 1171 11BD; # (튖; 튖; 튖; 튖; 튖; ) HANGUL SYLLABLE TWIJ +D297;D297;1110 1171 11BE;D297;1110 1171 11BE; # (튗; 튗; 튗; 튗; 튗; ) HANGUL SYLLABLE TWIC +D298;D298;1110 1171 11BF;D298;1110 1171 11BF; # (튘; 튘; 튘; 튘; 튘; ) HANGUL SYLLABLE TWIK +D299;D299;1110 1171 11C0;D299;1110 1171 11C0; # (튙; 튙; 튙; 튙; 튙; ) HANGUL SYLLABLE TWIT +D29A;D29A;1110 1171 11C1;D29A;1110 1171 11C1; # (튚; 튚; 튚; 튚; 튚; ) HANGUL SYLLABLE TWIP +D29B;D29B;1110 1171 11C2;D29B;1110 1171 11C2; # (튛; 튛; 튛; 튛; 튛; ) HANGUL SYLLABLE TWIH +D29C;D29C;1110 1172;D29C;1110 1172; # (튜; 튜; 튜; 튜; 튜; ) HANGUL SYLLABLE TYU +D29D;D29D;1110 1172 11A8;D29D;1110 1172 11A8; # (튝; 튝; 튝; 튝; 튝; ) HANGUL SYLLABLE TYUG +D29E;D29E;1110 1172 11A9;D29E;1110 1172 11A9; # (튞; 튞; 튞; 튞; 튞; ) HANGUL SYLLABLE TYUGG +D29F;D29F;1110 1172 11AA;D29F;1110 1172 11AA; # (튟; 튟; 튟; 튟; 튟; ) HANGUL SYLLABLE TYUGS +D2A0;D2A0;1110 1172 11AB;D2A0;1110 1172 11AB; # (튠; 튠; 튠; 튠; 튠; ) HANGUL SYLLABLE TYUN +D2A1;D2A1;1110 1172 11AC;D2A1;1110 1172 11AC; # (튡; 튡; 튡; 튡; 튡; ) HANGUL SYLLABLE TYUNJ +D2A2;D2A2;1110 1172 11AD;D2A2;1110 1172 11AD; # (튢; 튢; 튢; 튢; 튢; ) HANGUL SYLLABLE TYUNH +D2A3;D2A3;1110 1172 11AE;D2A3;1110 1172 11AE; # (튣; 튣; 튣; 튣; 튣; ) HANGUL SYLLABLE TYUD +D2A4;D2A4;1110 1172 11AF;D2A4;1110 1172 11AF; # (튤; 튤; 튤; 튤; 튤; ) HANGUL SYLLABLE TYUL +D2A5;D2A5;1110 1172 11B0;D2A5;1110 1172 11B0; # (튥; 튥; 튥; 튥; 튥; ) HANGUL SYLLABLE TYULG +D2A6;D2A6;1110 1172 11B1;D2A6;1110 1172 11B1; # (튦; 튦; 튦; 튦; 튦; ) HANGUL SYLLABLE TYULM +D2A7;D2A7;1110 1172 11B2;D2A7;1110 1172 11B2; # (튧; 튧; 튧; 튧; 튧; ) HANGUL SYLLABLE TYULB +D2A8;D2A8;1110 1172 11B3;D2A8;1110 1172 11B3; # (튨; 튨; 튨; 튨; 튨; ) HANGUL SYLLABLE TYULS +D2A9;D2A9;1110 1172 11B4;D2A9;1110 1172 11B4; # (튩; 튩; 튩; 튩; 튩; ) HANGUL SYLLABLE TYULT +D2AA;D2AA;1110 1172 11B5;D2AA;1110 1172 11B5; # (튪; 튪; 튪; 튪; 튪; ) HANGUL SYLLABLE TYULP +D2AB;D2AB;1110 1172 11B6;D2AB;1110 1172 11B6; # (튫; 튫; 튫; 튫; 튫; ) HANGUL SYLLABLE TYULH +D2AC;D2AC;1110 1172 11B7;D2AC;1110 1172 11B7; # (튬; 튬; 튬; 튬; 튬; ) HANGUL SYLLABLE TYUM +D2AD;D2AD;1110 1172 11B8;D2AD;1110 1172 11B8; # (튭; 튭; 튭; 튭; 튭; ) HANGUL SYLLABLE TYUB +D2AE;D2AE;1110 1172 11B9;D2AE;1110 1172 11B9; # (튮; 튮; 튮; 튮; 튮; ) HANGUL SYLLABLE TYUBS +D2AF;D2AF;1110 1172 11BA;D2AF;1110 1172 11BA; # (튯; 튯; 튯; 튯; 튯; ) HANGUL SYLLABLE TYUS +D2B0;D2B0;1110 1172 11BB;D2B0;1110 1172 11BB; # (튰; 튰; 튰; 튰; 튰; ) HANGUL SYLLABLE TYUSS +D2B1;D2B1;1110 1172 11BC;D2B1;1110 1172 11BC; # (튱; 튱; 튱; 튱; 튱; ) HANGUL SYLLABLE TYUNG +D2B2;D2B2;1110 1172 11BD;D2B2;1110 1172 11BD; # (튲; 튲; 튲; 튲; 튲; ) HANGUL SYLLABLE TYUJ +D2B3;D2B3;1110 1172 11BE;D2B3;1110 1172 11BE; # (튳; 튳; 튳; 튳; 튳; ) HANGUL SYLLABLE TYUC +D2B4;D2B4;1110 1172 11BF;D2B4;1110 1172 11BF; # (튴; 튴; 튴; 튴; 튴; ) HANGUL SYLLABLE TYUK +D2B5;D2B5;1110 1172 11C0;D2B5;1110 1172 11C0; # (튵; 튵; 튵; 튵; 튵; ) HANGUL SYLLABLE TYUT +D2B6;D2B6;1110 1172 11C1;D2B6;1110 1172 11C1; # (튶; 튶; 튶; 튶; 튶; ) HANGUL SYLLABLE TYUP +D2B7;D2B7;1110 1172 11C2;D2B7;1110 1172 11C2; # (튷; 튷; 튷; 튷; 튷; ) HANGUL SYLLABLE TYUH +D2B8;D2B8;1110 1173;D2B8;1110 1173; # (트; 트; 트; 트; 트; ) HANGUL SYLLABLE TEU +D2B9;D2B9;1110 1173 11A8;D2B9;1110 1173 11A8; # (특; 특; 특; 특; 특; ) HANGUL SYLLABLE TEUG +D2BA;D2BA;1110 1173 11A9;D2BA;1110 1173 11A9; # (튺; 튺; 튺; 튺; 튺; ) HANGUL SYLLABLE TEUGG +D2BB;D2BB;1110 1173 11AA;D2BB;1110 1173 11AA; # (튻; 튻; 튻; 튻; 튻; ) HANGUL SYLLABLE TEUGS +D2BC;D2BC;1110 1173 11AB;D2BC;1110 1173 11AB; # (튼; 튼; 튼; 튼; 튼; ) HANGUL SYLLABLE TEUN +D2BD;D2BD;1110 1173 11AC;D2BD;1110 1173 11AC; # (튽; 튽; 튽; 튽; 튽; ) HANGUL SYLLABLE TEUNJ +D2BE;D2BE;1110 1173 11AD;D2BE;1110 1173 11AD; # (튾; 튾; 튾; 튾; 튾; ) HANGUL SYLLABLE TEUNH +D2BF;D2BF;1110 1173 11AE;D2BF;1110 1173 11AE; # (튿; 튿; 튿; 튿; 튿; ) HANGUL SYLLABLE TEUD +D2C0;D2C0;1110 1173 11AF;D2C0;1110 1173 11AF; # (틀; 틀; 틀; 틀; 틀; ) HANGUL SYLLABLE TEUL +D2C1;D2C1;1110 1173 11B0;D2C1;1110 1173 11B0; # (틁; 틁; 틁; 틁; 틁; ) HANGUL SYLLABLE TEULG +D2C2;D2C2;1110 1173 11B1;D2C2;1110 1173 11B1; # (틂; 틂; 틂; 틂; 틂; ) HANGUL SYLLABLE TEULM +D2C3;D2C3;1110 1173 11B2;D2C3;1110 1173 11B2; # (틃; 틃; 틃; 틃; 틃; ) HANGUL SYLLABLE TEULB +D2C4;D2C4;1110 1173 11B3;D2C4;1110 1173 11B3; # (틄; 틄; 틄; 틄; 틄; ) HANGUL SYLLABLE TEULS +D2C5;D2C5;1110 1173 11B4;D2C5;1110 1173 11B4; # (틅; 틅; 틅; 틅; 틅; ) HANGUL SYLLABLE TEULT +D2C6;D2C6;1110 1173 11B5;D2C6;1110 1173 11B5; # (틆; 틆; 틆; 틆; 틆; ) HANGUL SYLLABLE TEULP +D2C7;D2C7;1110 1173 11B6;D2C7;1110 1173 11B6; # (틇; 틇; 틇; 틇; 틇; ) HANGUL SYLLABLE TEULH +D2C8;D2C8;1110 1173 11B7;D2C8;1110 1173 11B7; # (틈; 틈; 틈; 틈; 틈; ) HANGUL SYLLABLE TEUM +D2C9;D2C9;1110 1173 11B8;D2C9;1110 1173 11B8; # (틉; 틉; 틉; 틉; 틉; ) HANGUL SYLLABLE TEUB +D2CA;D2CA;1110 1173 11B9;D2CA;1110 1173 11B9; # (틊; 틊; 틊; 틊; 틊; ) HANGUL SYLLABLE TEUBS +D2CB;D2CB;1110 1173 11BA;D2CB;1110 1173 11BA; # (틋; 틋; 틋; 틋; 틋; ) HANGUL SYLLABLE TEUS +D2CC;D2CC;1110 1173 11BB;D2CC;1110 1173 11BB; # (틌; 틌; 틌; 틌; 틌; ) HANGUL SYLLABLE TEUSS +D2CD;D2CD;1110 1173 11BC;D2CD;1110 1173 11BC; # (틍; 틍; 틍; 틍; 틍; ) HANGUL SYLLABLE TEUNG +D2CE;D2CE;1110 1173 11BD;D2CE;1110 1173 11BD; # (틎; 틎; 틎; 틎; 틎; ) HANGUL SYLLABLE TEUJ +D2CF;D2CF;1110 1173 11BE;D2CF;1110 1173 11BE; # (틏; 틏; 틏; 틏; 틏; ) HANGUL SYLLABLE TEUC +D2D0;D2D0;1110 1173 11BF;D2D0;1110 1173 11BF; # (틐; 틐; 틐; 틐; 틐; ) HANGUL SYLLABLE TEUK +D2D1;D2D1;1110 1173 11C0;D2D1;1110 1173 11C0; # (틑; 틑; 틑; 틑; 틑; ) HANGUL SYLLABLE TEUT +D2D2;D2D2;1110 1173 11C1;D2D2;1110 1173 11C1; # (틒; 틒; 틒; 틒; 틒; ) HANGUL SYLLABLE TEUP +D2D3;D2D3;1110 1173 11C2;D2D3;1110 1173 11C2; # (틓; 틓; 틓; 틓; 틓; ) HANGUL SYLLABLE TEUH +D2D4;D2D4;1110 1174;D2D4;1110 1174; # (틔; 틔; 틔; 틔; 틔; ) HANGUL SYLLABLE TYI +D2D5;D2D5;1110 1174 11A8;D2D5;1110 1174 11A8; # (틕; 틕; 틕; 틕; 틕; ) HANGUL SYLLABLE TYIG +D2D6;D2D6;1110 1174 11A9;D2D6;1110 1174 11A9; # (틖; 틖; 틖; 틖; 틖; ) HANGUL SYLLABLE TYIGG +D2D7;D2D7;1110 1174 11AA;D2D7;1110 1174 11AA; # (틗; 틗; 틗; 틗; 틗; ) HANGUL SYLLABLE TYIGS +D2D8;D2D8;1110 1174 11AB;D2D8;1110 1174 11AB; # (틘; 틘; 틘; 틘; 틘; ) HANGUL SYLLABLE TYIN +D2D9;D2D9;1110 1174 11AC;D2D9;1110 1174 11AC; # (틙; 틙; 틙; 틙; 틙; ) HANGUL SYLLABLE TYINJ +D2DA;D2DA;1110 1174 11AD;D2DA;1110 1174 11AD; # (틚; 틚; 틚; 틚; 틚; ) HANGUL SYLLABLE TYINH +D2DB;D2DB;1110 1174 11AE;D2DB;1110 1174 11AE; # (틛; 틛; 틛; 틛; 틛; ) HANGUL SYLLABLE TYID +D2DC;D2DC;1110 1174 11AF;D2DC;1110 1174 11AF; # (틜; 틜; 틜; 틜; 틜; ) HANGUL SYLLABLE TYIL +D2DD;D2DD;1110 1174 11B0;D2DD;1110 1174 11B0; # (틝; 틝; 틝; 틝; 틝; ) HANGUL SYLLABLE TYILG +D2DE;D2DE;1110 1174 11B1;D2DE;1110 1174 11B1; # (틞; 틞; 틞; 틞; 틞; ) HANGUL SYLLABLE TYILM +D2DF;D2DF;1110 1174 11B2;D2DF;1110 1174 11B2; # (틟; 틟; 틟; 틟; 틟; ) HANGUL SYLLABLE TYILB +D2E0;D2E0;1110 1174 11B3;D2E0;1110 1174 11B3; # (틠; 틠; 틠; 틠; 틠; ) HANGUL SYLLABLE TYILS +D2E1;D2E1;1110 1174 11B4;D2E1;1110 1174 11B4; # (틡; 틡; 틡; 틡; 틡; ) HANGUL SYLLABLE TYILT +D2E2;D2E2;1110 1174 11B5;D2E2;1110 1174 11B5; # (틢; 틢; 틢; 틢; 틢; ) HANGUL SYLLABLE TYILP +D2E3;D2E3;1110 1174 11B6;D2E3;1110 1174 11B6; # (틣; 틣; 틣; 틣; 틣; ) HANGUL SYLLABLE TYILH +D2E4;D2E4;1110 1174 11B7;D2E4;1110 1174 11B7; # (틤; 틤; 틤; 틤; 틤; ) HANGUL SYLLABLE TYIM +D2E5;D2E5;1110 1174 11B8;D2E5;1110 1174 11B8; # (틥; 틥; 틥; 틥; 틥; ) HANGUL SYLLABLE TYIB +D2E6;D2E6;1110 1174 11B9;D2E6;1110 1174 11B9; # (틦; 틦; 틦; 틦; 틦; ) HANGUL SYLLABLE TYIBS +D2E7;D2E7;1110 1174 11BA;D2E7;1110 1174 11BA; # (틧; 틧; 틧; 틧; 틧; ) HANGUL SYLLABLE TYIS +D2E8;D2E8;1110 1174 11BB;D2E8;1110 1174 11BB; # (틨; 틨; 틨; 틨; 틨; ) HANGUL SYLLABLE TYISS +D2E9;D2E9;1110 1174 11BC;D2E9;1110 1174 11BC; # (틩; 틩; 틩; 틩; 틩; ) HANGUL SYLLABLE TYING +D2EA;D2EA;1110 1174 11BD;D2EA;1110 1174 11BD; # (틪; 틪; 틪; 틪; 틪; ) HANGUL SYLLABLE TYIJ +D2EB;D2EB;1110 1174 11BE;D2EB;1110 1174 11BE; # (틫; 틫; 틫; 틫; 틫; ) HANGUL SYLLABLE TYIC +D2EC;D2EC;1110 1174 11BF;D2EC;1110 1174 11BF; # (틬; 틬; 틬; 틬; 틬; ) HANGUL SYLLABLE TYIK +D2ED;D2ED;1110 1174 11C0;D2ED;1110 1174 11C0; # (틭; 틭; 틭; 틭; 틭; ) HANGUL SYLLABLE TYIT +D2EE;D2EE;1110 1174 11C1;D2EE;1110 1174 11C1; # (틮; 틮; 틮; 틮; 틮; ) HANGUL SYLLABLE TYIP +D2EF;D2EF;1110 1174 11C2;D2EF;1110 1174 11C2; # (틯; 틯; 틯; 틯; 틯; ) HANGUL SYLLABLE TYIH +D2F0;D2F0;1110 1175;D2F0;1110 1175; # (티; 티; 티; 티; 티; ) HANGUL SYLLABLE TI +D2F1;D2F1;1110 1175 11A8;D2F1;1110 1175 11A8; # (틱; 틱; 틱; 틱; 틱; ) HANGUL SYLLABLE TIG +D2F2;D2F2;1110 1175 11A9;D2F2;1110 1175 11A9; # (틲; 틲; 틲; 틲; 틲; ) HANGUL SYLLABLE TIGG +D2F3;D2F3;1110 1175 11AA;D2F3;1110 1175 11AA; # (틳; 틳; 틳; 틳; 틳; ) HANGUL SYLLABLE TIGS +D2F4;D2F4;1110 1175 11AB;D2F4;1110 1175 11AB; # (틴; 틴; 틴; 틴; 틴; ) HANGUL SYLLABLE TIN +D2F5;D2F5;1110 1175 11AC;D2F5;1110 1175 11AC; # (틵; 틵; 틵; 틵; 틵; ) HANGUL SYLLABLE TINJ +D2F6;D2F6;1110 1175 11AD;D2F6;1110 1175 11AD; # (틶; 틶; 틶; 틶; 틶; ) HANGUL SYLLABLE TINH +D2F7;D2F7;1110 1175 11AE;D2F7;1110 1175 11AE; # (틷; 틷; 틷; 틷; 틷; ) HANGUL SYLLABLE TID +D2F8;D2F8;1110 1175 11AF;D2F8;1110 1175 11AF; # (틸; 틸; 틸; 틸; 틸; ) HANGUL SYLLABLE TIL +D2F9;D2F9;1110 1175 11B0;D2F9;1110 1175 11B0; # (틹; 틹; 틹; 틹; 틹; ) HANGUL SYLLABLE TILG +D2FA;D2FA;1110 1175 11B1;D2FA;1110 1175 11B1; # (틺; 틺; 틺; 틺; 틺; ) HANGUL SYLLABLE TILM +D2FB;D2FB;1110 1175 11B2;D2FB;1110 1175 11B2; # (틻; 틻; 틻; 틻; 틻; ) HANGUL SYLLABLE TILB +D2FC;D2FC;1110 1175 11B3;D2FC;1110 1175 11B3; # (틼; 틼; 틼; 틼; 틼; ) HANGUL SYLLABLE TILS +D2FD;D2FD;1110 1175 11B4;D2FD;1110 1175 11B4; # (틽; 틽; 틽; 틽; 틽; ) HANGUL SYLLABLE TILT +D2FE;D2FE;1110 1175 11B5;D2FE;1110 1175 11B5; # (틾; 틾; 틾; 틾; 틾; ) HANGUL SYLLABLE TILP +D2FF;D2FF;1110 1175 11B6;D2FF;1110 1175 11B6; # (틿; 틿; 틿; 틿; 틿; ) HANGUL SYLLABLE TILH +D300;D300;1110 1175 11B7;D300;1110 1175 11B7; # (팀; 팀; 팀; 팀; 팀; ) HANGUL SYLLABLE TIM +D301;D301;1110 1175 11B8;D301;1110 1175 11B8; # (팁; 팁; 팁; 팁; 팁; ) HANGUL SYLLABLE TIB +D302;D302;1110 1175 11B9;D302;1110 1175 11B9; # (팂; 팂; 팂; 팂; 팂; ) HANGUL SYLLABLE TIBS +D303;D303;1110 1175 11BA;D303;1110 1175 11BA; # (팃; 팃; 팃; 팃; 팃; ) HANGUL SYLLABLE TIS +D304;D304;1110 1175 11BB;D304;1110 1175 11BB; # (팄; 팄; 팄; 팄; 팄; ) HANGUL SYLLABLE TISS +D305;D305;1110 1175 11BC;D305;1110 1175 11BC; # (팅; 팅; 팅; 팅; 팅; ) HANGUL SYLLABLE TING +D306;D306;1110 1175 11BD;D306;1110 1175 11BD; # (팆; 팆; 팆; 팆; 팆; ) HANGUL SYLLABLE TIJ +D307;D307;1110 1175 11BE;D307;1110 1175 11BE; # (팇; 팇; 팇; 팇; 팇; ) HANGUL SYLLABLE TIC +D308;D308;1110 1175 11BF;D308;1110 1175 11BF; # (팈; 팈; 팈; 팈; 팈; ) HANGUL SYLLABLE TIK +D309;D309;1110 1175 11C0;D309;1110 1175 11C0; # (팉; 팉; 팉; 팉; 팉; ) HANGUL SYLLABLE TIT +D30A;D30A;1110 1175 11C1;D30A;1110 1175 11C1; # (팊; 팊; 팊; 팊; 팊; ) HANGUL SYLLABLE TIP +D30B;D30B;1110 1175 11C2;D30B;1110 1175 11C2; # (팋; 팋; 팋; 팋; 팋; ) HANGUL SYLLABLE TIH +D30C;D30C;1111 1161;D30C;1111 1161; # (파; 파; 파; 파; 파; ) HANGUL SYLLABLE PA +D30D;D30D;1111 1161 11A8;D30D;1111 1161 11A8; # (팍; 팍; 팍; 팍; 팍; ) HANGUL SYLLABLE PAG +D30E;D30E;1111 1161 11A9;D30E;1111 1161 11A9; # (팎; 팎; 팎; 팎; 팎; ) HANGUL SYLLABLE PAGG +D30F;D30F;1111 1161 11AA;D30F;1111 1161 11AA; # (팏; 팏; 팏; 팏; 팏; ) HANGUL SYLLABLE PAGS +D310;D310;1111 1161 11AB;D310;1111 1161 11AB; # (판; 판; 판; 판; 판; ) HANGUL SYLLABLE PAN +D311;D311;1111 1161 11AC;D311;1111 1161 11AC; # (팑; 팑; 팑; 팑; 팑; ) HANGUL SYLLABLE PANJ +D312;D312;1111 1161 11AD;D312;1111 1161 11AD; # (팒; 팒; 팒; 팒; 팒; ) HANGUL SYLLABLE PANH +D313;D313;1111 1161 11AE;D313;1111 1161 11AE; # (팓; 팓; 팓; 팓; 팓; ) HANGUL SYLLABLE PAD +D314;D314;1111 1161 11AF;D314;1111 1161 11AF; # (팔; 팔; 팔; 팔; 팔; ) HANGUL SYLLABLE PAL +D315;D315;1111 1161 11B0;D315;1111 1161 11B0; # (팕; 팕; 팕; 팕; 팕; ) HANGUL SYLLABLE PALG +D316;D316;1111 1161 11B1;D316;1111 1161 11B1; # (팖; 팖; 팖; 팖; 팖; ) HANGUL SYLLABLE PALM +D317;D317;1111 1161 11B2;D317;1111 1161 11B2; # (팗; 팗; 팗; 팗; 팗; ) HANGUL SYLLABLE PALB +D318;D318;1111 1161 11B3;D318;1111 1161 11B3; # (팘; 팘; 팘; 팘; 팘; ) HANGUL SYLLABLE PALS +D319;D319;1111 1161 11B4;D319;1111 1161 11B4; # (팙; 팙; 팙; 팙; 팙; ) HANGUL SYLLABLE PALT +D31A;D31A;1111 1161 11B5;D31A;1111 1161 11B5; # (팚; 팚; 팚; 팚; 팚; ) HANGUL SYLLABLE PALP +D31B;D31B;1111 1161 11B6;D31B;1111 1161 11B6; # (팛; 팛; 팛; 팛; 팛; ) HANGUL SYLLABLE PALH +D31C;D31C;1111 1161 11B7;D31C;1111 1161 11B7; # (팜; 팜; 팜; 팜; 팜; ) HANGUL SYLLABLE PAM +D31D;D31D;1111 1161 11B8;D31D;1111 1161 11B8; # (팝; 팝; 팝; 팝; 팝; ) HANGUL SYLLABLE PAB +D31E;D31E;1111 1161 11B9;D31E;1111 1161 11B9; # (팞; 팞; 팞; 팞; 팞; ) HANGUL SYLLABLE PABS +D31F;D31F;1111 1161 11BA;D31F;1111 1161 11BA; # (팟; 팟; 팟; 팟; 팟; ) HANGUL SYLLABLE PAS +D320;D320;1111 1161 11BB;D320;1111 1161 11BB; # (팠; 팠; 팠; 팠; 팠; ) HANGUL SYLLABLE PASS +D321;D321;1111 1161 11BC;D321;1111 1161 11BC; # (팡; 팡; 팡; 팡; 팡; ) HANGUL SYLLABLE PANG +D322;D322;1111 1161 11BD;D322;1111 1161 11BD; # (팢; 팢; 팢; 팢; 팢; ) HANGUL SYLLABLE PAJ +D323;D323;1111 1161 11BE;D323;1111 1161 11BE; # (팣; 팣; 팣; 팣; 팣; ) HANGUL SYLLABLE PAC +D324;D324;1111 1161 11BF;D324;1111 1161 11BF; # (팤; 팤; 팤; 팤; 팤; ) HANGUL SYLLABLE PAK +D325;D325;1111 1161 11C0;D325;1111 1161 11C0; # (팥; 팥; 팥; 팥; 팥; ) HANGUL SYLLABLE PAT +D326;D326;1111 1161 11C1;D326;1111 1161 11C1; # (팦; 팦; 팦; 팦; 팦; ) HANGUL SYLLABLE PAP +D327;D327;1111 1161 11C2;D327;1111 1161 11C2; # (팧; 팧; 팧; 팧; 팧; ) HANGUL SYLLABLE PAH +D328;D328;1111 1162;D328;1111 1162; # (패; 패; 패; 패; 패; ) HANGUL SYLLABLE PAE +D329;D329;1111 1162 11A8;D329;1111 1162 11A8; # (팩; 팩; 팩; 팩; 팩; ) HANGUL SYLLABLE PAEG +D32A;D32A;1111 1162 11A9;D32A;1111 1162 11A9; # (팪; 팪; 팪; 팪; 팪; ) HANGUL SYLLABLE PAEGG +D32B;D32B;1111 1162 11AA;D32B;1111 1162 11AA; # (팫; 팫; 팫; 팫; 팫; ) HANGUL SYLLABLE PAEGS +D32C;D32C;1111 1162 11AB;D32C;1111 1162 11AB; # (팬; 팬; 팬; 팬; 팬; ) HANGUL SYLLABLE PAEN +D32D;D32D;1111 1162 11AC;D32D;1111 1162 11AC; # (팭; 팭; 팭; 팭; 팭; ) HANGUL SYLLABLE PAENJ +D32E;D32E;1111 1162 11AD;D32E;1111 1162 11AD; # (팮; 팮; 팮; 팮; 팮; ) HANGUL SYLLABLE PAENH +D32F;D32F;1111 1162 11AE;D32F;1111 1162 11AE; # (팯; 팯; 팯; 팯; 팯; ) HANGUL SYLLABLE PAED +D330;D330;1111 1162 11AF;D330;1111 1162 11AF; # (팰; 팰; 팰; 팰; 팰; ) HANGUL SYLLABLE PAEL +D331;D331;1111 1162 11B0;D331;1111 1162 11B0; # (팱; 팱; 팱; 팱; 팱; ) HANGUL SYLLABLE PAELG +D332;D332;1111 1162 11B1;D332;1111 1162 11B1; # (팲; 팲; 팲; 팲; 팲; ) HANGUL SYLLABLE PAELM +D333;D333;1111 1162 11B2;D333;1111 1162 11B2; # (팳; 팳; 팳; 팳; 팳; ) HANGUL SYLLABLE PAELB +D334;D334;1111 1162 11B3;D334;1111 1162 11B3; # (팴; 팴; 팴; 팴; 팴; ) HANGUL SYLLABLE PAELS +D335;D335;1111 1162 11B4;D335;1111 1162 11B4; # (팵; 팵; 팵; 팵; 팵; ) HANGUL SYLLABLE PAELT +D336;D336;1111 1162 11B5;D336;1111 1162 11B5; # (팶; 팶; 팶; 팶; 팶; ) HANGUL SYLLABLE PAELP +D337;D337;1111 1162 11B6;D337;1111 1162 11B6; # (팷; 팷; 팷; 팷; 팷; ) HANGUL SYLLABLE PAELH +D338;D338;1111 1162 11B7;D338;1111 1162 11B7; # (팸; 팸; 팸; 팸; 팸; ) HANGUL SYLLABLE PAEM +D339;D339;1111 1162 11B8;D339;1111 1162 11B8; # (팹; 팹; 팹; 팹; 팹; ) HANGUL SYLLABLE PAEB +D33A;D33A;1111 1162 11B9;D33A;1111 1162 11B9; # (팺; 팺; 팺; 팺; 팺; ) HANGUL SYLLABLE PAEBS +D33B;D33B;1111 1162 11BA;D33B;1111 1162 11BA; # (팻; 팻; 팻; 팻; 팻; ) HANGUL SYLLABLE PAES +D33C;D33C;1111 1162 11BB;D33C;1111 1162 11BB; # (팼; 팼; 팼; 팼; 팼; ) HANGUL SYLLABLE PAESS +D33D;D33D;1111 1162 11BC;D33D;1111 1162 11BC; # (팽; 팽; 팽; 팽; 팽; ) HANGUL SYLLABLE PAENG +D33E;D33E;1111 1162 11BD;D33E;1111 1162 11BD; # (팾; 팾; 팾; 팾; 팾; ) HANGUL SYLLABLE PAEJ +D33F;D33F;1111 1162 11BE;D33F;1111 1162 11BE; # (팿; 팿; 팿; 팿; 팿; ) HANGUL SYLLABLE PAEC +D340;D340;1111 1162 11BF;D340;1111 1162 11BF; # (퍀; 퍀; 퍀; 퍀; 퍀; ) HANGUL SYLLABLE PAEK +D341;D341;1111 1162 11C0;D341;1111 1162 11C0; # (퍁; 퍁; 퍁; 퍁; 퍁; ) HANGUL SYLLABLE PAET +D342;D342;1111 1162 11C1;D342;1111 1162 11C1; # (퍂; 퍂; 퍂; 퍂; 퍂; ) HANGUL SYLLABLE PAEP +D343;D343;1111 1162 11C2;D343;1111 1162 11C2; # (퍃; 퍃; 퍃; 퍃; 퍃; ) HANGUL SYLLABLE PAEH +D344;D344;1111 1163;D344;1111 1163; # (퍄; 퍄; 퍄; 퍄; 퍄; ) HANGUL SYLLABLE PYA +D345;D345;1111 1163 11A8;D345;1111 1163 11A8; # (퍅; 퍅; 퍅; 퍅; 퍅; ) HANGUL SYLLABLE PYAG +D346;D346;1111 1163 11A9;D346;1111 1163 11A9; # (퍆; 퍆; 퍆; 퍆; 퍆; ) HANGUL SYLLABLE PYAGG +D347;D347;1111 1163 11AA;D347;1111 1163 11AA; # (퍇; 퍇; 퍇; 퍇; 퍇; ) HANGUL SYLLABLE PYAGS +D348;D348;1111 1163 11AB;D348;1111 1163 11AB; # (퍈; 퍈; 퍈; 퍈; 퍈; ) HANGUL SYLLABLE PYAN +D349;D349;1111 1163 11AC;D349;1111 1163 11AC; # (퍉; 퍉; 퍉; 퍉; 퍉; ) HANGUL SYLLABLE PYANJ +D34A;D34A;1111 1163 11AD;D34A;1111 1163 11AD; # (퍊; 퍊; 퍊; 퍊; 퍊; ) HANGUL SYLLABLE PYANH +D34B;D34B;1111 1163 11AE;D34B;1111 1163 11AE; # (퍋; 퍋; 퍋; 퍋; 퍋; ) HANGUL SYLLABLE PYAD +D34C;D34C;1111 1163 11AF;D34C;1111 1163 11AF; # (퍌; 퍌; 퍌; 퍌; 퍌; ) HANGUL SYLLABLE PYAL +D34D;D34D;1111 1163 11B0;D34D;1111 1163 11B0; # (퍍; 퍍; 퍍; 퍍; 퍍; ) HANGUL SYLLABLE PYALG +D34E;D34E;1111 1163 11B1;D34E;1111 1163 11B1; # (퍎; 퍎; 퍎; 퍎; 퍎; ) HANGUL SYLLABLE PYALM +D34F;D34F;1111 1163 11B2;D34F;1111 1163 11B2; # (퍏; 퍏; 퍏; 퍏; 퍏; ) HANGUL SYLLABLE PYALB +D350;D350;1111 1163 11B3;D350;1111 1163 11B3; # (퍐; 퍐; 퍐; 퍐; 퍐; ) HANGUL SYLLABLE PYALS +D351;D351;1111 1163 11B4;D351;1111 1163 11B4; # (퍑; 퍑; 퍑; 퍑; 퍑; ) HANGUL SYLLABLE PYALT +D352;D352;1111 1163 11B5;D352;1111 1163 11B5; # (퍒; 퍒; 퍒; 퍒; 퍒; ) HANGUL SYLLABLE PYALP +D353;D353;1111 1163 11B6;D353;1111 1163 11B6; # (퍓; 퍓; 퍓; 퍓; 퍓; ) HANGUL SYLLABLE PYALH +D354;D354;1111 1163 11B7;D354;1111 1163 11B7; # (퍔; 퍔; 퍔; 퍔; 퍔; ) HANGUL SYLLABLE PYAM +D355;D355;1111 1163 11B8;D355;1111 1163 11B8; # (퍕; 퍕; 퍕; 퍕; 퍕; ) HANGUL SYLLABLE PYAB +D356;D356;1111 1163 11B9;D356;1111 1163 11B9; # (퍖; 퍖; 퍖; 퍖; 퍖; ) HANGUL SYLLABLE PYABS +D357;D357;1111 1163 11BA;D357;1111 1163 11BA; # (퍗; 퍗; 퍗; 퍗; 퍗; ) HANGUL SYLLABLE PYAS +D358;D358;1111 1163 11BB;D358;1111 1163 11BB; # (퍘; 퍘; 퍘; 퍘; 퍘; ) HANGUL SYLLABLE PYASS +D359;D359;1111 1163 11BC;D359;1111 1163 11BC; # (퍙; 퍙; 퍙; 퍙; 퍙; ) HANGUL SYLLABLE PYANG +D35A;D35A;1111 1163 11BD;D35A;1111 1163 11BD; # (퍚; 퍚; 퍚; 퍚; 퍚; ) HANGUL SYLLABLE PYAJ +D35B;D35B;1111 1163 11BE;D35B;1111 1163 11BE; # (퍛; 퍛; 퍛; 퍛; 퍛; ) HANGUL SYLLABLE PYAC +D35C;D35C;1111 1163 11BF;D35C;1111 1163 11BF; # (퍜; 퍜; 퍜; 퍜; 퍜; ) HANGUL SYLLABLE PYAK +D35D;D35D;1111 1163 11C0;D35D;1111 1163 11C0; # (퍝; 퍝; 퍝; 퍝; 퍝; ) HANGUL SYLLABLE PYAT +D35E;D35E;1111 1163 11C1;D35E;1111 1163 11C1; # (퍞; 퍞; 퍞; 퍞; 퍞; ) HANGUL SYLLABLE PYAP +D35F;D35F;1111 1163 11C2;D35F;1111 1163 11C2; # (퍟; 퍟; 퍟; 퍟; 퍟; ) HANGUL SYLLABLE PYAH +D360;D360;1111 1164;D360;1111 1164; # (퍠; 퍠; 퍠; 퍠; 퍠; ) HANGUL SYLLABLE PYAE +D361;D361;1111 1164 11A8;D361;1111 1164 11A8; # (퍡; 퍡; 퍡; 퍡; 퍡; ) HANGUL SYLLABLE PYAEG +D362;D362;1111 1164 11A9;D362;1111 1164 11A9; # (퍢; 퍢; 퍢; 퍢; 퍢; ) HANGUL SYLLABLE PYAEGG +D363;D363;1111 1164 11AA;D363;1111 1164 11AA; # (퍣; 퍣; 퍣; 퍣; 퍣; ) HANGUL SYLLABLE PYAEGS +D364;D364;1111 1164 11AB;D364;1111 1164 11AB; # (퍤; 퍤; 퍤; 퍤; 퍤; ) HANGUL SYLLABLE PYAEN +D365;D365;1111 1164 11AC;D365;1111 1164 11AC; # (퍥; 퍥; 퍥; 퍥; 퍥; ) HANGUL SYLLABLE PYAENJ +D366;D366;1111 1164 11AD;D366;1111 1164 11AD; # (퍦; 퍦; 퍦; 퍦; 퍦; ) HANGUL SYLLABLE PYAENH +D367;D367;1111 1164 11AE;D367;1111 1164 11AE; # (퍧; 퍧; 퍧; 퍧; 퍧; ) HANGUL SYLLABLE PYAED +D368;D368;1111 1164 11AF;D368;1111 1164 11AF; # (퍨; 퍨; 퍨; 퍨; 퍨; ) HANGUL SYLLABLE PYAEL +D369;D369;1111 1164 11B0;D369;1111 1164 11B0; # (퍩; 퍩; 퍩; 퍩; 퍩; ) HANGUL SYLLABLE PYAELG +D36A;D36A;1111 1164 11B1;D36A;1111 1164 11B1; # (퍪; 퍪; 퍪; 퍪; 퍪; ) HANGUL SYLLABLE PYAELM +D36B;D36B;1111 1164 11B2;D36B;1111 1164 11B2; # (퍫; 퍫; 퍫; 퍫; 퍫; ) HANGUL SYLLABLE PYAELB +D36C;D36C;1111 1164 11B3;D36C;1111 1164 11B3; # (퍬; 퍬; 퍬; 퍬; 퍬; ) HANGUL SYLLABLE PYAELS +D36D;D36D;1111 1164 11B4;D36D;1111 1164 11B4; # (퍭; 퍭; 퍭; 퍭; 퍭; ) HANGUL SYLLABLE PYAELT +D36E;D36E;1111 1164 11B5;D36E;1111 1164 11B5; # (퍮; 퍮; 퍮; 퍮; 퍮; ) HANGUL SYLLABLE PYAELP +D36F;D36F;1111 1164 11B6;D36F;1111 1164 11B6; # (퍯; 퍯; 퍯; 퍯; 퍯; ) HANGUL SYLLABLE PYAELH +D370;D370;1111 1164 11B7;D370;1111 1164 11B7; # (퍰; 퍰; 퍰; 퍰; 퍰; ) HANGUL SYLLABLE PYAEM +D371;D371;1111 1164 11B8;D371;1111 1164 11B8; # (퍱; 퍱; 퍱; 퍱; 퍱; ) HANGUL SYLLABLE PYAEB +D372;D372;1111 1164 11B9;D372;1111 1164 11B9; # (퍲; 퍲; 퍲; 퍲; 퍲; ) HANGUL SYLLABLE PYAEBS +D373;D373;1111 1164 11BA;D373;1111 1164 11BA; # (퍳; 퍳; 퍳; 퍳; 퍳; ) HANGUL SYLLABLE PYAES +D374;D374;1111 1164 11BB;D374;1111 1164 11BB; # (퍴; 퍴; 퍴; 퍴; 퍴; ) HANGUL SYLLABLE PYAESS +D375;D375;1111 1164 11BC;D375;1111 1164 11BC; # (퍵; 퍵; 퍵; 퍵; 퍵; ) HANGUL SYLLABLE PYAENG +D376;D376;1111 1164 11BD;D376;1111 1164 11BD; # (퍶; 퍶; 퍶; 퍶; 퍶; ) HANGUL SYLLABLE PYAEJ +D377;D377;1111 1164 11BE;D377;1111 1164 11BE; # (퍷; 퍷; 퍷; 퍷; 퍷; ) HANGUL SYLLABLE PYAEC +D378;D378;1111 1164 11BF;D378;1111 1164 11BF; # (퍸; 퍸; 퍸; 퍸; 퍸; ) HANGUL SYLLABLE PYAEK +D379;D379;1111 1164 11C0;D379;1111 1164 11C0; # (퍹; 퍹; 퍹; 퍹; 퍹; ) HANGUL SYLLABLE PYAET +D37A;D37A;1111 1164 11C1;D37A;1111 1164 11C1; # (퍺; 퍺; 퍺; 퍺; 퍺; ) HANGUL SYLLABLE PYAEP +D37B;D37B;1111 1164 11C2;D37B;1111 1164 11C2; # (퍻; 퍻; 퍻; 퍻; 퍻; ) HANGUL SYLLABLE PYAEH +D37C;D37C;1111 1165;D37C;1111 1165; # (퍼; 퍼; 퍼; 퍼; 퍼; ) HANGUL SYLLABLE PEO +D37D;D37D;1111 1165 11A8;D37D;1111 1165 11A8; # (퍽; 퍽; 퍽; 퍽; 퍽; ) HANGUL SYLLABLE PEOG +D37E;D37E;1111 1165 11A9;D37E;1111 1165 11A9; # (퍾; 퍾; 퍾; 퍾; 퍾; ) HANGUL SYLLABLE PEOGG +D37F;D37F;1111 1165 11AA;D37F;1111 1165 11AA; # (퍿; 퍿; 퍿; 퍿; 퍿; ) HANGUL SYLLABLE PEOGS +D380;D380;1111 1165 11AB;D380;1111 1165 11AB; # (펀; 펀; 펀; 펀; 펀; ) HANGUL SYLLABLE PEON +D381;D381;1111 1165 11AC;D381;1111 1165 11AC; # (펁; 펁; 펁; 펁; 펁; ) HANGUL SYLLABLE PEONJ +D382;D382;1111 1165 11AD;D382;1111 1165 11AD; # (펂; 펂; 펂; 펂; 펂; ) HANGUL SYLLABLE PEONH +D383;D383;1111 1165 11AE;D383;1111 1165 11AE; # (펃; 펃; 펃; 펃; 펃; ) HANGUL SYLLABLE PEOD +D384;D384;1111 1165 11AF;D384;1111 1165 11AF; # (펄; 펄; 펄; 펄; 펄; ) HANGUL SYLLABLE PEOL +D385;D385;1111 1165 11B0;D385;1111 1165 11B0; # (펅; 펅; 펅; 펅; 펅; ) HANGUL SYLLABLE PEOLG +D386;D386;1111 1165 11B1;D386;1111 1165 11B1; # (펆; 펆; 펆; 펆; 펆; ) HANGUL SYLLABLE PEOLM +D387;D387;1111 1165 11B2;D387;1111 1165 11B2; # (펇; 펇; 펇; 펇; 펇; ) HANGUL SYLLABLE PEOLB +D388;D388;1111 1165 11B3;D388;1111 1165 11B3; # (펈; 펈; 펈; 펈; 펈; ) HANGUL SYLLABLE PEOLS +D389;D389;1111 1165 11B4;D389;1111 1165 11B4; # (펉; 펉; 펉; 펉; 펉; ) HANGUL SYLLABLE PEOLT +D38A;D38A;1111 1165 11B5;D38A;1111 1165 11B5; # (펊; 펊; 펊; 펊; 펊; ) HANGUL SYLLABLE PEOLP +D38B;D38B;1111 1165 11B6;D38B;1111 1165 11B6; # (펋; 펋; 펋; 펋; 펋; ) HANGUL SYLLABLE PEOLH +D38C;D38C;1111 1165 11B7;D38C;1111 1165 11B7; # (펌; 펌; 펌; 펌; 펌; ) HANGUL SYLLABLE PEOM +D38D;D38D;1111 1165 11B8;D38D;1111 1165 11B8; # (펍; 펍; 펍; 펍; 펍; ) HANGUL SYLLABLE PEOB +D38E;D38E;1111 1165 11B9;D38E;1111 1165 11B9; # (펎; 펎; 펎; 펎; 펎; ) HANGUL SYLLABLE PEOBS +D38F;D38F;1111 1165 11BA;D38F;1111 1165 11BA; # (펏; 펏; 펏; 펏; 펏; ) HANGUL SYLLABLE PEOS +D390;D390;1111 1165 11BB;D390;1111 1165 11BB; # (펐; 펐; 펐; 펐; 펐; ) HANGUL SYLLABLE PEOSS +D391;D391;1111 1165 11BC;D391;1111 1165 11BC; # (펑; 펑; 펑; 펑; 펑; ) HANGUL SYLLABLE PEONG +D392;D392;1111 1165 11BD;D392;1111 1165 11BD; # (펒; 펒; 펒; 펒; 펒; ) HANGUL SYLLABLE PEOJ +D393;D393;1111 1165 11BE;D393;1111 1165 11BE; # (펓; 펓; 펓; 펓; 펓; ) HANGUL SYLLABLE PEOC +D394;D394;1111 1165 11BF;D394;1111 1165 11BF; # (펔; 펔; 펔; 펔; 펔; ) HANGUL SYLLABLE PEOK +D395;D395;1111 1165 11C0;D395;1111 1165 11C0; # (펕; 펕; 펕; 펕; 펕; ) HANGUL SYLLABLE PEOT +D396;D396;1111 1165 11C1;D396;1111 1165 11C1; # (펖; 펖; 펖; 펖; 펖; ) HANGUL SYLLABLE PEOP +D397;D397;1111 1165 11C2;D397;1111 1165 11C2; # (펗; 펗; 펗; 펗; 펗; ) HANGUL SYLLABLE PEOH +D398;D398;1111 1166;D398;1111 1166; # (페; 페; 페; 페; 페; ) HANGUL SYLLABLE PE +D399;D399;1111 1166 11A8;D399;1111 1166 11A8; # (펙; 펙; 펙; 펙; 펙; ) HANGUL SYLLABLE PEG +D39A;D39A;1111 1166 11A9;D39A;1111 1166 11A9; # (펚; 펚; 펚; 펚; 펚; ) HANGUL SYLLABLE PEGG +D39B;D39B;1111 1166 11AA;D39B;1111 1166 11AA; # (펛; 펛; 펛; 펛; 펛; ) HANGUL SYLLABLE PEGS +D39C;D39C;1111 1166 11AB;D39C;1111 1166 11AB; # (펜; 펜; 펜; 펜; 펜; ) HANGUL SYLLABLE PEN +D39D;D39D;1111 1166 11AC;D39D;1111 1166 11AC; # (펝; 펝; 펝; 펝; 펝; ) HANGUL SYLLABLE PENJ +D39E;D39E;1111 1166 11AD;D39E;1111 1166 11AD; # (펞; 펞; 펞; 펞; 펞; ) HANGUL SYLLABLE PENH +D39F;D39F;1111 1166 11AE;D39F;1111 1166 11AE; # (펟; 펟; 펟; 펟; 펟; ) HANGUL SYLLABLE PED +D3A0;D3A0;1111 1166 11AF;D3A0;1111 1166 11AF; # (펠; 펠; 펠; 펠; 펠; ) HANGUL SYLLABLE PEL +D3A1;D3A1;1111 1166 11B0;D3A1;1111 1166 11B0; # (펡; 펡; 펡; 펡; 펡; ) HANGUL SYLLABLE PELG +D3A2;D3A2;1111 1166 11B1;D3A2;1111 1166 11B1; # (펢; 펢; 펢; 펢; 펢; ) HANGUL SYLLABLE PELM +D3A3;D3A3;1111 1166 11B2;D3A3;1111 1166 11B2; # (펣; 펣; 펣; 펣; 펣; ) HANGUL SYLLABLE PELB +D3A4;D3A4;1111 1166 11B3;D3A4;1111 1166 11B3; # (펤; 펤; 펤; 펤; 펤; ) HANGUL SYLLABLE PELS +D3A5;D3A5;1111 1166 11B4;D3A5;1111 1166 11B4; # (펥; 펥; 펥; 펥; 펥; ) HANGUL SYLLABLE PELT +D3A6;D3A6;1111 1166 11B5;D3A6;1111 1166 11B5; # (펦; 펦; 펦; 펦; 펦; ) HANGUL SYLLABLE PELP +D3A7;D3A7;1111 1166 11B6;D3A7;1111 1166 11B6; # (펧; 펧; 펧; 펧; 펧; ) HANGUL SYLLABLE PELH +D3A8;D3A8;1111 1166 11B7;D3A8;1111 1166 11B7; # (펨; 펨; 펨; 펨; 펨; ) HANGUL SYLLABLE PEM +D3A9;D3A9;1111 1166 11B8;D3A9;1111 1166 11B8; # (펩; 펩; 펩; 펩; 펩; ) HANGUL SYLLABLE PEB +D3AA;D3AA;1111 1166 11B9;D3AA;1111 1166 11B9; # (펪; 펪; 펪; 펪; 펪; ) HANGUL SYLLABLE PEBS +D3AB;D3AB;1111 1166 11BA;D3AB;1111 1166 11BA; # (펫; 펫; 펫; 펫; 펫; ) HANGUL SYLLABLE PES +D3AC;D3AC;1111 1166 11BB;D3AC;1111 1166 11BB; # (펬; 펬; 펬; 펬; 펬; ) HANGUL SYLLABLE PESS +D3AD;D3AD;1111 1166 11BC;D3AD;1111 1166 11BC; # (펭; 펭; 펭; 펭; 펭; ) HANGUL SYLLABLE PENG +D3AE;D3AE;1111 1166 11BD;D3AE;1111 1166 11BD; # (펮; 펮; 펮; 펮; 펮; ) HANGUL SYLLABLE PEJ +D3AF;D3AF;1111 1166 11BE;D3AF;1111 1166 11BE; # (펯; 펯; 펯; 펯; 펯; ) HANGUL SYLLABLE PEC +D3B0;D3B0;1111 1166 11BF;D3B0;1111 1166 11BF; # (펰; 펰; 펰; 펰; 펰; ) HANGUL SYLLABLE PEK +D3B1;D3B1;1111 1166 11C0;D3B1;1111 1166 11C0; # (펱; 펱; 펱; 펱; 펱; ) HANGUL SYLLABLE PET +D3B2;D3B2;1111 1166 11C1;D3B2;1111 1166 11C1; # (펲; 펲; 펲; 펲; 펲; ) HANGUL SYLLABLE PEP +D3B3;D3B3;1111 1166 11C2;D3B3;1111 1166 11C2; # (펳; 펳; 펳; 펳; 펳; ) HANGUL SYLLABLE PEH +D3B4;D3B4;1111 1167;D3B4;1111 1167; # (펴; 펴; 펴; 펴; 펴; ) HANGUL SYLLABLE PYEO +D3B5;D3B5;1111 1167 11A8;D3B5;1111 1167 11A8; # (펵; 펵; 펵; 펵; 펵; ) HANGUL SYLLABLE PYEOG +D3B6;D3B6;1111 1167 11A9;D3B6;1111 1167 11A9; # (펶; 펶; 펶; 펶; 펶; ) HANGUL SYLLABLE PYEOGG +D3B7;D3B7;1111 1167 11AA;D3B7;1111 1167 11AA; # (펷; 펷; 펷; 펷; 펷; ) HANGUL SYLLABLE PYEOGS +D3B8;D3B8;1111 1167 11AB;D3B8;1111 1167 11AB; # (편; 편; 편; 편; 편; ) HANGUL SYLLABLE PYEON +D3B9;D3B9;1111 1167 11AC;D3B9;1111 1167 11AC; # (펹; 펹; 펹; 펹; 펹; ) HANGUL SYLLABLE PYEONJ +D3BA;D3BA;1111 1167 11AD;D3BA;1111 1167 11AD; # (펺; 펺; 펺; 펺; 펺; ) HANGUL SYLLABLE PYEONH +D3BB;D3BB;1111 1167 11AE;D3BB;1111 1167 11AE; # (펻; 펻; 펻; 펻; 펻; ) HANGUL SYLLABLE PYEOD +D3BC;D3BC;1111 1167 11AF;D3BC;1111 1167 11AF; # (펼; 펼; 펼; 펼; 펼; ) HANGUL SYLLABLE PYEOL +D3BD;D3BD;1111 1167 11B0;D3BD;1111 1167 11B0; # (펽; 펽; 펽; 펽; 펽; ) HANGUL SYLLABLE PYEOLG +D3BE;D3BE;1111 1167 11B1;D3BE;1111 1167 11B1; # (펾; 펾; 펾; 펾; 펾; ) HANGUL SYLLABLE PYEOLM +D3BF;D3BF;1111 1167 11B2;D3BF;1111 1167 11B2; # (펿; 펿; 펿; 펿; 펿; ) HANGUL SYLLABLE PYEOLB +D3C0;D3C0;1111 1167 11B3;D3C0;1111 1167 11B3; # (폀; 폀; 폀; 폀; 폀; ) HANGUL SYLLABLE PYEOLS +D3C1;D3C1;1111 1167 11B4;D3C1;1111 1167 11B4; # (폁; 폁; 폁; 폁; 폁; ) HANGUL SYLLABLE PYEOLT +D3C2;D3C2;1111 1167 11B5;D3C2;1111 1167 11B5; # (폂; 폂; 폂; 폂; 폂; ) HANGUL SYLLABLE PYEOLP +D3C3;D3C3;1111 1167 11B6;D3C3;1111 1167 11B6; # (폃; 폃; 폃; 폃; 폃; ) HANGUL SYLLABLE PYEOLH +D3C4;D3C4;1111 1167 11B7;D3C4;1111 1167 11B7; # (폄; 폄; 폄; 폄; 폄; ) HANGUL SYLLABLE PYEOM +D3C5;D3C5;1111 1167 11B8;D3C5;1111 1167 11B8; # (폅; 폅; 폅; 폅; 폅; ) HANGUL SYLLABLE PYEOB +D3C6;D3C6;1111 1167 11B9;D3C6;1111 1167 11B9; # (폆; 폆; 폆; 폆; 폆; ) HANGUL SYLLABLE PYEOBS +D3C7;D3C7;1111 1167 11BA;D3C7;1111 1167 11BA; # (폇; 폇; 폇; 폇; 폇; ) HANGUL SYLLABLE PYEOS +D3C8;D3C8;1111 1167 11BB;D3C8;1111 1167 11BB; # (폈; 폈; 폈; 폈; 폈; ) HANGUL SYLLABLE PYEOSS +D3C9;D3C9;1111 1167 11BC;D3C9;1111 1167 11BC; # (평; 평; 평; 평; 평; ) HANGUL SYLLABLE PYEONG +D3CA;D3CA;1111 1167 11BD;D3CA;1111 1167 11BD; # (폊; 폊; 폊; 폊; 폊; ) HANGUL SYLLABLE PYEOJ +D3CB;D3CB;1111 1167 11BE;D3CB;1111 1167 11BE; # (폋; 폋; 폋; 폋; 폋; ) HANGUL SYLLABLE PYEOC +D3CC;D3CC;1111 1167 11BF;D3CC;1111 1167 11BF; # (폌; 폌; 폌; 폌; 폌; ) HANGUL SYLLABLE PYEOK +D3CD;D3CD;1111 1167 11C0;D3CD;1111 1167 11C0; # (폍; 폍; 폍; 폍; 폍; ) HANGUL SYLLABLE PYEOT +D3CE;D3CE;1111 1167 11C1;D3CE;1111 1167 11C1; # (폎; 폎; 폎; 폎; 폎; ) HANGUL SYLLABLE PYEOP +D3CF;D3CF;1111 1167 11C2;D3CF;1111 1167 11C2; # (폏; 폏; 폏; 폏; 폏; ) HANGUL SYLLABLE PYEOH +D3D0;D3D0;1111 1168;D3D0;1111 1168; # (폐; 폐; 폐; 폐; 폐; ) HANGUL SYLLABLE PYE +D3D1;D3D1;1111 1168 11A8;D3D1;1111 1168 11A8; # (폑; 폑; 폑; 폑; 폑; ) HANGUL SYLLABLE PYEG +D3D2;D3D2;1111 1168 11A9;D3D2;1111 1168 11A9; # (폒; 폒; 폒; 폒; 폒; ) HANGUL SYLLABLE PYEGG +D3D3;D3D3;1111 1168 11AA;D3D3;1111 1168 11AA; # (폓; 폓; 폓; 폓; 폓; ) HANGUL SYLLABLE PYEGS +D3D4;D3D4;1111 1168 11AB;D3D4;1111 1168 11AB; # (폔; 폔; 폔; 폔; 폔; ) HANGUL SYLLABLE PYEN +D3D5;D3D5;1111 1168 11AC;D3D5;1111 1168 11AC; # (폕; 폕; 폕; 폕; 폕; ) HANGUL SYLLABLE PYENJ +D3D6;D3D6;1111 1168 11AD;D3D6;1111 1168 11AD; # (폖; 폖; 폖; 폖; 폖; ) HANGUL SYLLABLE PYENH +D3D7;D3D7;1111 1168 11AE;D3D7;1111 1168 11AE; # (폗; 폗; 폗; 폗; 폗; ) HANGUL SYLLABLE PYED +D3D8;D3D8;1111 1168 11AF;D3D8;1111 1168 11AF; # (폘; 폘; 폘; 폘; 폘; ) HANGUL SYLLABLE PYEL +D3D9;D3D9;1111 1168 11B0;D3D9;1111 1168 11B0; # (폙; 폙; 폙; 폙; 폙; ) HANGUL SYLLABLE PYELG +D3DA;D3DA;1111 1168 11B1;D3DA;1111 1168 11B1; # (폚; 폚; 폚; 폚; 폚; ) HANGUL SYLLABLE PYELM +D3DB;D3DB;1111 1168 11B2;D3DB;1111 1168 11B2; # (폛; 폛; 폛; 폛; 폛; ) HANGUL SYLLABLE PYELB +D3DC;D3DC;1111 1168 11B3;D3DC;1111 1168 11B3; # (폜; 폜; 폜; 폜; 폜; ) HANGUL SYLLABLE PYELS +D3DD;D3DD;1111 1168 11B4;D3DD;1111 1168 11B4; # (폝; 폝; 폝; 폝; 폝; ) HANGUL SYLLABLE PYELT +D3DE;D3DE;1111 1168 11B5;D3DE;1111 1168 11B5; # (폞; 폞; 폞; 폞; 폞; ) HANGUL SYLLABLE PYELP +D3DF;D3DF;1111 1168 11B6;D3DF;1111 1168 11B6; # (폟; 폟; 폟; 폟; 폟; ) HANGUL SYLLABLE PYELH +D3E0;D3E0;1111 1168 11B7;D3E0;1111 1168 11B7; # (폠; 폠; 폠; 폠; 폠; ) HANGUL SYLLABLE PYEM +D3E1;D3E1;1111 1168 11B8;D3E1;1111 1168 11B8; # (폡; 폡; 폡; 폡; 폡; ) HANGUL SYLLABLE PYEB +D3E2;D3E2;1111 1168 11B9;D3E2;1111 1168 11B9; # (폢; 폢; 폢; 폢; 폢; ) HANGUL SYLLABLE PYEBS +D3E3;D3E3;1111 1168 11BA;D3E3;1111 1168 11BA; # (폣; 폣; 폣; 폣; 폣; ) HANGUL SYLLABLE PYES +D3E4;D3E4;1111 1168 11BB;D3E4;1111 1168 11BB; # (폤; 폤; 폤; 폤; 폤; ) HANGUL SYLLABLE PYESS +D3E5;D3E5;1111 1168 11BC;D3E5;1111 1168 11BC; # (폥; 폥; 폥; 폥; 폥; ) HANGUL SYLLABLE PYENG +D3E6;D3E6;1111 1168 11BD;D3E6;1111 1168 11BD; # (폦; 폦; 폦; 폦; 폦; ) HANGUL SYLLABLE PYEJ +D3E7;D3E7;1111 1168 11BE;D3E7;1111 1168 11BE; # (폧; 폧; 폧; 폧; 폧; ) HANGUL SYLLABLE PYEC +D3E8;D3E8;1111 1168 11BF;D3E8;1111 1168 11BF; # (폨; 폨; 폨; 폨; 폨; ) HANGUL SYLLABLE PYEK +D3E9;D3E9;1111 1168 11C0;D3E9;1111 1168 11C0; # (폩; 폩; 폩; 폩; 폩; ) HANGUL SYLLABLE PYET +D3EA;D3EA;1111 1168 11C1;D3EA;1111 1168 11C1; # (폪; 폪; 폪; 폪; 폪; ) HANGUL SYLLABLE PYEP +D3EB;D3EB;1111 1168 11C2;D3EB;1111 1168 11C2; # (폫; 폫; 폫; 폫; 폫; ) HANGUL SYLLABLE PYEH +D3EC;D3EC;1111 1169;D3EC;1111 1169; # (포; 포; 포; 포; 포; ) HANGUL SYLLABLE PO +D3ED;D3ED;1111 1169 11A8;D3ED;1111 1169 11A8; # (폭; 폭; 폭; 폭; 폭; ) HANGUL SYLLABLE POG +D3EE;D3EE;1111 1169 11A9;D3EE;1111 1169 11A9; # (폮; 폮; 폮; 폮; 폮; ) HANGUL SYLLABLE POGG +D3EF;D3EF;1111 1169 11AA;D3EF;1111 1169 11AA; # (폯; 폯; 폯; 폯; 폯; ) HANGUL SYLLABLE POGS +D3F0;D3F0;1111 1169 11AB;D3F0;1111 1169 11AB; # (폰; 폰; 폰; 폰; 폰; ) HANGUL SYLLABLE PON +D3F1;D3F1;1111 1169 11AC;D3F1;1111 1169 11AC; # (폱; 폱; 폱; 폱; 폱; ) HANGUL SYLLABLE PONJ +D3F2;D3F2;1111 1169 11AD;D3F2;1111 1169 11AD; # (폲; 폲; 폲; 폲; 폲; ) HANGUL SYLLABLE PONH +D3F3;D3F3;1111 1169 11AE;D3F3;1111 1169 11AE; # (폳; 폳; 폳; 폳; 폳; ) HANGUL SYLLABLE POD +D3F4;D3F4;1111 1169 11AF;D3F4;1111 1169 11AF; # (폴; 폴; 폴; 폴; 폴; ) HANGUL SYLLABLE POL +D3F5;D3F5;1111 1169 11B0;D3F5;1111 1169 11B0; # (폵; 폵; 폵; 폵; 폵; ) HANGUL SYLLABLE POLG +D3F6;D3F6;1111 1169 11B1;D3F6;1111 1169 11B1; # (폶; 폶; 폶; 폶; 폶; ) HANGUL SYLLABLE POLM +D3F7;D3F7;1111 1169 11B2;D3F7;1111 1169 11B2; # (폷; 폷; 폷; 폷; 폷; ) HANGUL SYLLABLE POLB +D3F8;D3F8;1111 1169 11B3;D3F8;1111 1169 11B3; # (폸; 폸; 폸; 폸; 폸; ) HANGUL SYLLABLE POLS +D3F9;D3F9;1111 1169 11B4;D3F9;1111 1169 11B4; # (폹; 폹; 폹; 폹; 폹; ) HANGUL SYLLABLE POLT +D3FA;D3FA;1111 1169 11B5;D3FA;1111 1169 11B5; # (폺; 폺; 폺; 폺; 폺; ) HANGUL SYLLABLE POLP +D3FB;D3FB;1111 1169 11B6;D3FB;1111 1169 11B6; # (폻; 폻; 폻; 폻; 폻; ) HANGUL SYLLABLE POLH +D3FC;D3FC;1111 1169 11B7;D3FC;1111 1169 11B7; # (폼; 폼; 폼; 폼; 폼; ) HANGUL SYLLABLE POM +D3FD;D3FD;1111 1169 11B8;D3FD;1111 1169 11B8; # (폽; 폽; 폽; 폽; 폽; ) HANGUL SYLLABLE POB +D3FE;D3FE;1111 1169 11B9;D3FE;1111 1169 11B9; # (폾; 폾; 폾; 폾; 폾; ) HANGUL SYLLABLE POBS +D3FF;D3FF;1111 1169 11BA;D3FF;1111 1169 11BA; # (폿; 폿; 폿; 폿; 폿; ) HANGUL SYLLABLE POS +D400;D400;1111 1169 11BB;D400;1111 1169 11BB; # (퐀; 퐀; 퐀; 퐀; 퐀; ) HANGUL SYLLABLE POSS +D401;D401;1111 1169 11BC;D401;1111 1169 11BC; # (퐁; 퐁; 퐁; 퐁; 퐁; ) HANGUL SYLLABLE PONG +D402;D402;1111 1169 11BD;D402;1111 1169 11BD; # (퐂; 퐂; 퐂; 퐂; 퐂; ) HANGUL SYLLABLE POJ +D403;D403;1111 1169 11BE;D403;1111 1169 11BE; # (퐃; 퐃; 퐃; 퐃; 퐃; ) HANGUL SYLLABLE POC +D404;D404;1111 1169 11BF;D404;1111 1169 11BF; # (퐄; 퐄; 퐄; 퐄; 퐄; ) HANGUL SYLLABLE POK +D405;D405;1111 1169 11C0;D405;1111 1169 11C0; # (퐅; 퐅; 퐅; 퐅; 퐅; ) HANGUL SYLLABLE POT +D406;D406;1111 1169 11C1;D406;1111 1169 11C1; # (퐆; 퐆; 퐆; 퐆; 퐆; ) HANGUL SYLLABLE POP +D407;D407;1111 1169 11C2;D407;1111 1169 11C2; # (퐇; 퐇; 퐇; 퐇; 퐇; ) HANGUL SYLLABLE POH +D408;D408;1111 116A;D408;1111 116A; # (퐈; 퐈; 퐈; 퐈; 퐈; ) HANGUL SYLLABLE PWA +D409;D409;1111 116A 11A8;D409;1111 116A 11A8; # (퐉; 퐉; 퐉; 퐉; 퐉; ) HANGUL SYLLABLE PWAG +D40A;D40A;1111 116A 11A9;D40A;1111 116A 11A9; # (퐊; 퐊; 퐊; 퐊; 퐊; ) HANGUL SYLLABLE PWAGG +D40B;D40B;1111 116A 11AA;D40B;1111 116A 11AA; # (퐋; 퐋; 퐋; 퐋; 퐋; ) HANGUL SYLLABLE PWAGS +D40C;D40C;1111 116A 11AB;D40C;1111 116A 11AB; # (퐌; 퐌; 퐌; 퐌; 퐌; ) HANGUL SYLLABLE PWAN +D40D;D40D;1111 116A 11AC;D40D;1111 116A 11AC; # (퐍; 퐍; 퐍; 퐍; 퐍; ) HANGUL SYLLABLE PWANJ +D40E;D40E;1111 116A 11AD;D40E;1111 116A 11AD; # (퐎; 퐎; 퐎; 퐎; 퐎; ) HANGUL SYLLABLE PWANH +D40F;D40F;1111 116A 11AE;D40F;1111 116A 11AE; # (퐏; 퐏; 퐏; 퐏; 퐏; ) HANGUL SYLLABLE PWAD +D410;D410;1111 116A 11AF;D410;1111 116A 11AF; # (퐐; 퐐; 퐐; 퐐; 퐐; ) HANGUL SYLLABLE PWAL +D411;D411;1111 116A 11B0;D411;1111 116A 11B0; # (퐑; 퐑; 퐑; 퐑; 퐑; ) HANGUL SYLLABLE PWALG +D412;D412;1111 116A 11B1;D412;1111 116A 11B1; # (퐒; 퐒; 퐒; 퐒; 퐒; ) HANGUL SYLLABLE PWALM +D413;D413;1111 116A 11B2;D413;1111 116A 11B2; # (퐓; 퐓; 퐓; 퐓; 퐓; ) HANGUL SYLLABLE PWALB +D414;D414;1111 116A 11B3;D414;1111 116A 11B3; # (퐔; 퐔; 퐔; 퐔; 퐔; ) HANGUL SYLLABLE PWALS +D415;D415;1111 116A 11B4;D415;1111 116A 11B4; # (퐕; 퐕; 퐕; 퐕; 퐕; ) HANGUL SYLLABLE PWALT +D416;D416;1111 116A 11B5;D416;1111 116A 11B5; # (퐖; 퐖; 퐖; 퐖; 퐖; ) HANGUL SYLLABLE PWALP +D417;D417;1111 116A 11B6;D417;1111 116A 11B6; # (퐗; 퐗; 퐗; 퐗; 퐗; ) HANGUL SYLLABLE PWALH +D418;D418;1111 116A 11B7;D418;1111 116A 11B7; # (퐘; 퐘; 퐘; 퐘; 퐘; ) HANGUL SYLLABLE PWAM +D419;D419;1111 116A 11B8;D419;1111 116A 11B8; # (퐙; 퐙; 퐙; 퐙; 퐙; ) HANGUL SYLLABLE PWAB +D41A;D41A;1111 116A 11B9;D41A;1111 116A 11B9; # (퐚; 퐚; 퐚; 퐚; 퐚; ) HANGUL SYLLABLE PWABS +D41B;D41B;1111 116A 11BA;D41B;1111 116A 11BA; # (퐛; 퐛; 퐛; 퐛; 퐛; ) HANGUL SYLLABLE PWAS +D41C;D41C;1111 116A 11BB;D41C;1111 116A 11BB; # (퐜; 퐜; 퐜; 퐜; 퐜; ) HANGUL SYLLABLE PWASS +D41D;D41D;1111 116A 11BC;D41D;1111 116A 11BC; # (퐝; 퐝; 퐝; 퐝; 퐝; ) HANGUL SYLLABLE PWANG +D41E;D41E;1111 116A 11BD;D41E;1111 116A 11BD; # (퐞; 퐞; 퐞; 퐞; 퐞; ) HANGUL SYLLABLE PWAJ +D41F;D41F;1111 116A 11BE;D41F;1111 116A 11BE; # (퐟; 퐟; 퐟; 퐟; 퐟; ) HANGUL SYLLABLE PWAC +D420;D420;1111 116A 11BF;D420;1111 116A 11BF; # (퐠; 퐠; 퐠; 퐠; 퐠; ) HANGUL SYLLABLE PWAK +D421;D421;1111 116A 11C0;D421;1111 116A 11C0; # (퐡; 퐡; 퐡; 퐡; 퐡; ) HANGUL SYLLABLE PWAT +D422;D422;1111 116A 11C1;D422;1111 116A 11C1; # (퐢; 퐢; 퐢; 퐢; 퐢; ) HANGUL SYLLABLE PWAP +D423;D423;1111 116A 11C2;D423;1111 116A 11C2; # (퐣; 퐣; 퐣; 퐣; 퐣; ) HANGUL SYLLABLE PWAH +D424;D424;1111 116B;D424;1111 116B; # (퐤; 퐤; 퐤; 퐤; 퐤; ) HANGUL SYLLABLE PWAE +D425;D425;1111 116B 11A8;D425;1111 116B 11A8; # (퐥; 퐥; 퐥; 퐥; 퐥; ) HANGUL SYLLABLE PWAEG +D426;D426;1111 116B 11A9;D426;1111 116B 11A9; # (퐦; 퐦; 퐦; 퐦; 퐦; ) HANGUL SYLLABLE PWAEGG +D427;D427;1111 116B 11AA;D427;1111 116B 11AA; # (퐧; 퐧; 퐧; 퐧; 퐧; ) HANGUL SYLLABLE PWAEGS +D428;D428;1111 116B 11AB;D428;1111 116B 11AB; # (퐨; 퐨; 퐨; 퐨; 퐨; ) HANGUL SYLLABLE PWAEN +D429;D429;1111 116B 11AC;D429;1111 116B 11AC; # (퐩; 퐩; 퐩; 퐩; 퐩; ) HANGUL SYLLABLE PWAENJ +D42A;D42A;1111 116B 11AD;D42A;1111 116B 11AD; # (퐪; 퐪; 퐪; 퐪; 퐪; ) HANGUL SYLLABLE PWAENH +D42B;D42B;1111 116B 11AE;D42B;1111 116B 11AE; # (퐫; 퐫; 퐫; 퐫; 퐫; ) HANGUL SYLLABLE PWAED +D42C;D42C;1111 116B 11AF;D42C;1111 116B 11AF; # (퐬; 퐬; 퐬; 퐬; 퐬; ) HANGUL SYLLABLE PWAEL +D42D;D42D;1111 116B 11B0;D42D;1111 116B 11B0; # (퐭; 퐭; 퐭; 퐭; 퐭; ) HANGUL SYLLABLE PWAELG +D42E;D42E;1111 116B 11B1;D42E;1111 116B 11B1; # (퐮; 퐮; 퐮; 퐮; 퐮; ) HANGUL SYLLABLE PWAELM +D42F;D42F;1111 116B 11B2;D42F;1111 116B 11B2; # (퐯; 퐯; 퐯; 퐯; 퐯; ) HANGUL SYLLABLE PWAELB +D430;D430;1111 116B 11B3;D430;1111 116B 11B3; # (퐰; 퐰; 퐰; 퐰; 퐰; ) HANGUL SYLLABLE PWAELS +D431;D431;1111 116B 11B4;D431;1111 116B 11B4; # (퐱; 퐱; 퐱; 퐱; 퐱; ) HANGUL SYLLABLE PWAELT +D432;D432;1111 116B 11B5;D432;1111 116B 11B5; # (퐲; 퐲; 퐲; 퐲; 퐲; ) HANGUL SYLLABLE PWAELP +D433;D433;1111 116B 11B6;D433;1111 116B 11B6; # (퐳; 퐳; 퐳; 퐳; 퐳; ) HANGUL SYLLABLE PWAELH +D434;D434;1111 116B 11B7;D434;1111 116B 11B7; # (퐴; 퐴; 퐴; 퐴; 퐴; ) HANGUL SYLLABLE PWAEM +D435;D435;1111 116B 11B8;D435;1111 116B 11B8; # (퐵; 퐵; 퐵; 퐵; 퐵; ) HANGUL SYLLABLE PWAEB +D436;D436;1111 116B 11B9;D436;1111 116B 11B9; # (퐶; 퐶; 퐶; 퐶; 퐶; ) HANGUL SYLLABLE PWAEBS +D437;D437;1111 116B 11BA;D437;1111 116B 11BA; # (퐷; 퐷; 퐷; 퐷; 퐷; ) HANGUL SYLLABLE PWAES +D438;D438;1111 116B 11BB;D438;1111 116B 11BB; # (퐸; 퐸; 퐸; 퐸; 퐸; ) HANGUL SYLLABLE PWAESS +D439;D439;1111 116B 11BC;D439;1111 116B 11BC; # (퐹; 퐹; 퐹; 퐹; 퐹; ) HANGUL SYLLABLE PWAENG +D43A;D43A;1111 116B 11BD;D43A;1111 116B 11BD; # (퐺; 퐺; 퐺; 퐺; 퐺; ) HANGUL SYLLABLE PWAEJ +D43B;D43B;1111 116B 11BE;D43B;1111 116B 11BE; # (퐻; 퐻; 퐻; 퐻; 퐻; ) HANGUL SYLLABLE PWAEC +D43C;D43C;1111 116B 11BF;D43C;1111 116B 11BF; # (퐼; 퐼; 퐼; 퐼; 퐼; ) HANGUL SYLLABLE PWAEK +D43D;D43D;1111 116B 11C0;D43D;1111 116B 11C0; # (퐽; 퐽; 퐽; 퐽; 퐽; ) HANGUL SYLLABLE PWAET +D43E;D43E;1111 116B 11C1;D43E;1111 116B 11C1; # (퐾; 퐾; 퐾; 퐾; 퐾; ) HANGUL SYLLABLE PWAEP +D43F;D43F;1111 116B 11C2;D43F;1111 116B 11C2; # (퐿; 퐿; 퐿; 퐿; 퐿; ) HANGUL SYLLABLE PWAEH +D440;D440;1111 116C;D440;1111 116C; # (푀; 푀; 푀; 푀; 푀; ) HANGUL SYLLABLE POE +D441;D441;1111 116C 11A8;D441;1111 116C 11A8; # (푁; 푁; 푁; 푁; 푁; ) HANGUL SYLLABLE POEG +D442;D442;1111 116C 11A9;D442;1111 116C 11A9; # (푂; 푂; 푂; 푂; 푂; ) HANGUL SYLLABLE POEGG +D443;D443;1111 116C 11AA;D443;1111 116C 11AA; # (푃; 푃; 푃; 푃; 푃; ) HANGUL SYLLABLE POEGS +D444;D444;1111 116C 11AB;D444;1111 116C 11AB; # (푄; 푄; 푄; 푄; 푄; ) HANGUL SYLLABLE POEN +D445;D445;1111 116C 11AC;D445;1111 116C 11AC; # (푅; 푅; 푅; 푅; 푅; ) HANGUL SYLLABLE POENJ +D446;D446;1111 116C 11AD;D446;1111 116C 11AD; # (푆; 푆; 푆; 푆; 푆; ) HANGUL SYLLABLE POENH +D447;D447;1111 116C 11AE;D447;1111 116C 11AE; # (푇; 푇; 푇; 푇; 푇; ) HANGUL SYLLABLE POED +D448;D448;1111 116C 11AF;D448;1111 116C 11AF; # (푈; 푈; 푈; 푈; 푈; ) HANGUL SYLLABLE POEL +D449;D449;1111 116C 11B0;D449;1111 116C 11B0; # (푉; 푉; 푉; 푉; 푉; ) HANGUL SYLLABLE POELG +D44A;D44A;1111 116C 11B1;D44A;1111 116C 11B1; # (푊; 푊; 푊; 푊; 푊; ) HANGUL SYLLABLE POELM +D44B;D44B;1111 116C 11B2;D44B;1111 116C 11B2; # (푋; 푋; 푋; 푋; 푋; ) HANGUL SYLLABLE POELB +D44C;D44C;1111 116C 11B3;D44C;1111 116C 11B3; # (푌; 푌; 푌; 푌; 푌; ) HANGUL SYLLABLE POELS +D44D;D44D;1111 116C 11B4;D44D;1111 116C 11B4; # (푍; 푍; 푍; 푍; 푍; ) HANGUL SYLLABLE POELT +D44E;D44E;1111 116C 11B5;D44E;1111 116C 11B5; # (푎; 푎; 푎; 푎; 푎; ) HANGUL SYLLABLE POELP +D44F;D44F;1111 116C 11B6;D44F;1111 116C 11B6; # (푏; 푏; 푏; 푏; 푏; ) HANGUL SYLLABLE POELH +D450;D450;1111 116C 11B7;D450;1111 116C 11B7; # (푐; 푐; 푐; 푐; 푐; ) HANGUL SYLLABLE POEM +D451;D451;1111 116C 11B8;D451;1111 116C 11B8; # (푑; 푑; 푑; 푑; 푑; ) HANGUL SYLLABLE POEB +D452;D452;1111 116C 11B9;D452;1111 116C 11B9; # (푒; 푒; 푒; 푒; 푒; ) HANGUL SYLLABLE POEBS +D453;D453;1111 116C 11BA;D453;1111 116C 11BA; # (푓; 푓; 푓; 푓; 푓; ) HANGUL SYLLABLE POES +D454;D454;1111 116C 11BB;D454;1111 116C 11BB; # (푔; 푔; 푔; 푔; 푔; ) HANGUL SYLLABLE POESS +D455;D455;1111 116C 11BC;D455;1111 116C 11BC; # (푕; 푕; 푕; 푕; 푕; ) HANGUL SYLLABLE POENG +D456;D456;1111 116C 11BD;D456;1111 116C 11BD; # (푖; 푖; 푖; 푖; 푖; ) HANGUL SYLLABLE POEJ +D457;D457;1111 116C 11BE;D457;1111 116C 11BE; # (푗; 푗; 푗; 푗; 푗; ) HANGUL SYLLABLE POEC +D458;D458;1111 116C 11BF;D458;1111 116C 11BF; # (푘; 푘; 푘; 푘; 푘; ) HANGUL SYLLABLE POEK +D459;D459;1111 116C 11C0;D459;1111 116C 11C0; # (푙; 푙; 푙; 푙; 푙; ) HANGUL SYLLABLE POET +D45A;D45A;1111 116C 11C1;D45A;1111 116C 11C1; # (푚; 푚; 푚; 푚; 푚; ) HANGUL SYLLABLE POEP +D45B;D45B;1111 116C 11C2;D45B;1111 116C 11C2; # (푛; 푛; 푛; 푛; 푛; ) HANGUL SYLLABLE POEH +D45C;D45C;1111 116D;D45C;1111 116D; # (표; 표; 표; 표; 표; ) HANGUL SYLLABLE PYO +D45D;D45D;1111 116D 11A8;D45D;1111 116D 11A8; # (푝; 푝; 푝; 푝; 푝; ) HANGUL SYLLABLE PYOG +D45E;D45E;1111 116D 11A9;D45E;1111 116D 11A9; # (푞; 푞; 푞; 푞; 푞; ) HANGUL SYLLABLE PYOGG +D45F;D45F;1111 116D 11AA;D45F;1111 116D 11AA; # (푟; 푟; 푟; 푟; 푟; ) HANGUL SYLLABLE PYOGS +D460;D460;1111 116D 11AB;D460;1111 116D 11AB; # (푠; 푠; 푠; 푠; 푠; ) HANGUL SYLLABLE PYON +D461;D461;1111 116D 11AC;D461;1111 116D 11AC; # (푡; 푡; 푡; 푡; 푡; ) HANGUL SYLLABLE PYONJ +D462;D462;1111 116D 11AD;D462;1111 116D 11AD; # (푢; 푢; 푢; 푢; 푢; ) HANGUL SYLLABLE PYONH +D463;D463;1111 116D 11AE;D463;1111 116D 11AE; # (푣; 푣; 푣; 푣; 푣; ) HANGUL SYLLABLE PYOD +D464;D464;1111 116D 11AF;D464;1111 116D 11AF; # (푤; 푤; 푤; 푤; 푤; ) HANGUL SYLLABLE PYOL +D465;D465;1111 116D 11B0;D465;1111 116D 11B0; # (푥; 푥; 푥; 푥; 푥; ) HANGUL SYLLABLE PYOLG +D466;D466;1111 116D 11B1;D466;1111 116D 11B1; # (푦; 푦; 푦; 푦; 푦; ) HANGUL SYLLABLE PYOLM +D467;D467;1111 116D 11B2;D467;1111 116D 11B2; # (푧; 푧; 푧; 푧; 푧; ) HANGUL SYLLABLE PYOLB +D468;D468;1111 116D 11B3;D468;1111 116D 11B3; # (푨; 푨; 푨; 푨; 푨; ) HANGUL SYLLABLE PYOLS +D469;D469;1111 116D 11B4;D469;1111 116D 11B4; # (푩; 푩; 푩; 푩; 푩; ) HANGUL SYLLABLE PYOLT +D46A;D46A;1111 116D 11B5;D46A;1111 116D 11B5; # (푪; 푪; 푪; 푪; 푪; ) HANGUL SYLLABLE PYOLP +D46B;D46B;1111 116D 11B6;D46B;1111 116D 11B6; # (푫; 푫; 푫; 푫; 푫; ) HANGUL SYLLABLE PYOLH +D46C;D46C;1111 116D 11B7;D46C;1111 116D 11B7; # (푬; 푬; 푬; 푬; 푬; ) HANGUL SYLLABLE PYOM +D46D;D46D;1111 116D 11B8;D46D;1111 116D 11B8; # (푭; 푭; 푭; 푭; 푭; ) HANGUL SYLLABLE PYOB +D46E;D46E;1111 116D 11B9;D46E;1111 116D 11B9; # (푮; 푮; 푮; 푮; 푮; ) HANGUL SYLLABLE PYOBS +D46F;D46F;1111 116D 11BA;D46F;1111 116D 11BA; # (푯; 푯; 푯; 푯; 푯; ) HANGUL SYLLABLE PYOS +D470;D470;1111 116D 11BB;D470;1111 116D 11BB; # (푰; 푰; 푰; 푰; 푰; ) HANGUL SYLLABLE PYOSS +D471;D471;1111 116D 11BC;D471;1111 116D 11BC; # (푱; 푱; 푱; 푱; 푱; ) HANGUL SYLLABLE PYONG +D472;D472;1111 116D 11BD;D472;1111 116D 11BD; # (푲; 푲; 푲; 푲; 푲; ) HANGUL SYLLABLE PYOJ +D473;D473;1111 116D 11BE;D473;1111 116D 11BE; # (푳; 푳; 푳; 푳; 푳; ) HANGUL SYLLABLE PYOC +D474;D474;1111 116D 11BF;D474;1111 116D 11BF; # (푴; 푴; 푴; 푴; 푴; ) HANGUL SYLLABLE PYOK +D475;D475;1111 116D 11C0;D475;1111 116D 11C0; # (푵; 푵; 푵; 푵; 푵; ) HANGUL SYLLABLE PYOT +D476;D476;1111 116D 11C1;D476;1111 116D 11C1; # (푶; 푶; 푶; 푶; 푶; ) HANGUL SYLLABLE PYOP +D477;D477;1111 116D 11C2;D477;1111 116D 11C2; # (푷; 푷; 푷; 푷; 푷; ) HANGUL SYLLABLE PYOH +D478;D478;1111 116E;D478;1111 116E; # (푸; 푸; 푸; 푸; 푸; ) HANGUL SYLLABLE PU +D479;D479;1111 116E 11A8;D479;1111 116E 11A8; # (푹; 푹; 푹; 푹; 푹; ) HANGUL SYLLABLE PUG +D47A;D47A;1111 116E 11A9;D47A;1111 116E 11A9; # (푺; 푺; 푺; 푺; 푺; ) HANGUL SYLLABLE PUGG +D47B;D47B;1111 116E 11AA;D47B;1111 116E 11AA; # (푻; 푻; 푻; 푻; 푻; ) HANGUL SYLLABLE PUGS +D47C;D47C;1111 116E 11AB;D47C;1111 116E 11AB; # (푼; 푼; 푼; 푼; 푼; ) HANGUL SYLLABLE PUN +D47D;D47D;1111 116E 11AC;D47D;1111 116E 11AC; # (푽; 푽; 푽; 푽; 푽; ) HANGUL SYLLABLE PUNJ +D47E;D47E;1111 116E 11AD;D47E;1111 116E 11AD; # (푾; 푾; 푾; 푾; 푾; ) HANGUL SYLLABLE PUNH +D47F;D47F;1111 116E 11AE;D47F;1111 116E 11AE; # (푿; 푿; 푿; 푿; 푿; ) HANGUL SYLLABLE PUD +D480;D480;1111 116E 11AF;D480;1111 116E 11AF; # (풀; 풀; 풀; 풀; 풀; ) HANGUL SYLLABLE PUL +D481;D481;1111 116E 11B0;D481;1111 116E 11B0; # (풁; 풁; 풁; 풁; 풁; ) HANGUL SYLLABLE PULG +D482;D482;1111 116E 11B1;D482;1111 116E 11B1; # (풂; 풂; 풂; 풂; 풂; ) HANGUL SYLLABLE PULM +D483;D483;1111 116E 11B2;D483;1111 116E 11B2; # (풃; 풃; 풃; 풃; 풃; ) HANGUL SYLLABLE PULB +D484;D484;1111 116E 11B3;D484;1111 116E 11B3; # (풄; 풄; 풄; 풄; 풄; ) HANGUL SYLLABLE PULS +D485;D485;1111 116E 11B4;D485;1111 116E 11B4; # (풅; 풅; 풅; 풅; 풅; ) HANGUL SYLLABLE PULT +D486;D486;1111 116E 11B5;D486;1111 116E 11B5; # (풆; 풆; 풆; 풆; 풆; ) HANGUL SYLLABLE PULP +D487;D487;1111 116E 11B6;D487;1111 116E 11B6; # (풇; 풇; 풇; 풇; 풇; ) HANGUL SYLLABLE PULH +D488;D488;1111 116E 11B7;D488;1111 116E 11B7; # (품; 품; 품; 품; 품; ) HANGUL SYLLABLE PUM +D489;D489;1111 116E 11B8;D489;1111 116E 11B8; # (풉; 풉; 풉; 풉; 풉; ) HANGUL SYLLABLE PUB +D48A;D48A;1111 116E 11B9;D48A;1111 116E 11B9; # (풊; 풊; 풊; 풊; 풊; ) HANGUL SYLLABLE PUBS +D48B;D48B;1111 116E 11BA;D48B;1111 116E 11BA; # (풋; 풋; 풋; 풋; 풋; ) HANGUL SYLLABLE PUS +D48C;D48C;1111 116E 11BB;D48C;1111 116E 11BB; # (풌; 풌; 풌; 풌; 풌; ) HANGUL SYLLABLE PUSS +D48D;D48D;1111 116E 11BC;D48D;1111 116E 11BC; # (풍; 풍; 풍; 풍; 풍; ) HANGUL SYLLABLE PUNG +D48E;D48E;1111 116E 11BD;D48E;1111 116E 11BD; # (풎; 풎; 풎; 풎; 풎; ) HANGUL SYLLABLE PUJ +D48F;D48F;1111 116E 11BE;D48F;1111 116E 11BE; # (풏; 풏; 풏; 풏; 풏; ) HANGUL SYLLABLE PUC +D490;D490;1111 116E 11BF;D490;1111 116E 11BF; # (풐; 풐; 풐; 풐; 풐; ) HANGUL SYLLABLE PUK +D491;D491;1111 116E 11C0;D491;1111 116E 11C0; # (풑; 풑; 풑; 풑; 풑; ) HANGUL SYLLABLE PUT +D492;D492;1111 116E 11C1;D492;1111 116E 11C1; # (풒; 풒; 풒; 풒; 풒; ) HANGUL SYLLABLE PUP +D493;D493;1111 116E 11C2;D493;1111 116E 11C2; # (풓; 풓; 풓; 풓; 풓; ) HANGUL SYLLABLE PUH +D494;D494;1111 116F;D494;1111 116F; # (풔; 풔; 풔; 풔; 풔; ) HANGUL SYLLABLE PWEO +D495;D495;1111 116F 11A8;D495;1111 116F 11A8; # (풕; 풕; 풕; 풕; 풕; ) HANGUL SYLLABLE PWEOG +D496;D496;1111 116F 11A9;D496;1111 116F 11A9; # (풖; 풖; 풖; 풖; 풖; ) HANGUL SYLLABLE PWEOGG +D497;D497;1111 116F 11AA;D497;1111 116F 11AA; # (풗; 풗; 풗; 풗; 풗; ) HANGUL SYLLABLE PWEOGS +D498;D498;1111 116F 11AB;D498;1111 116F 11AB; # (풘; 풘; 풘; 풘; 풘; ) HANGUL SYLLABLE PWEON +D499;D499;1111 116F 11AC;D499;1111 116F 11AC; # (풙; 풙; 풙; 풙; 풙; ) HANGUL SYLLABLE PWEONJ +D49A;D49A;1111 116F 11AD;D49A;1111 116F 11AD; # (풚; 풚; 풚; 풚; 풚; ) HANGUL SYLLABLE PWEONH +D49B;D49B;1111 116F 11AE;D49B;1111 116F 11AE; # (풛; 풛; 풛; 풛; 풛; ) HANGUL SYLLABLE PWEOD +D49C;D49C;1111 116F 11AF;D49C;1111 116F 11AF; # (풜; 풜; 풜; 풜; 풜; ) HANGUL SYLLABLE PWEOL +D49D;D49D;1111 116F 11B0;D49D;1111 116F 11B0; # (풝; 풝; 풝; 풝; 풝; ) HANGUL SYLLABLE PWEOLG +D49E;D49E;1111 116F 11B1;D49E;1111 116F 11B1; # (풞; 풞; 풞; 풞; 풞; ) HANGUL SYLLABLE PWEOLM +D49F;D49F;1111 116F 11B2;D49F;1111 116F 11B2; # (풟; 풟; 풟; 풟; 풟; ) HANGUL SYLLABLE PWEOLB +D4A0;D4A0;1111 116F 11B3;D4A0;1111 116F 11B3; # (풠; 풠; 풠; 풠; 풠; ) HANGUL SYLLABLE PWEOLS +D4A1;D4A1;1111 116F 11B4;D4A1;1111 116F 11B4; # (풡; 풡; 풡; 풡; 풡; ) HANGUL SYLLABLE PWEOLT +D4A2;D4A2;1111 116F 11B5;D4A2;1111 116F 11B5; # (풢; 풢; 풢; 풢; 풢; ) HANGUL SYLLABLE PWEOLP +D4A3;D4A3;1111 116F 11B6;D4A3;1111 116F 11B6; # (풣; 풣; 풣; 풣; 풣; ) HANGUL SYLLABLE PWEOLH +D4A4;D4A4;1111 116F 11B7;D4A4;1111 116F 11B7; # (풤; 풤; 풤; 풤; 풤; ) HANGUL SYLLABLE PWEOM +D4A5;D4A5;1111 116F 11B8;D4A5;1111 116F 11B8; # (풥; 풥; 풥; 풥; 풥; ) HANGUL SYLLABLE PWEOB +D4A6;D4A6;1111 116F 11B9;D4A6;1111 116F 11B9; # (풦; 풦; 풦; 풦; 풦; ) HANGUL SYLLABLE PWEOBS +D4A7;D4A7;1111 116F 11BA;D4A7;1111 116F 11BA; # (풧; 풧; 풧; 풧; 풧; ) HANGUL SYLLABLE PWEOS +D4A8;D4A8;1111 116F 11BB;D4A8;1111 116F 11BB; # (풨; 풨; 풨; 풨; 풨; ) HANGUL SYLLABLE PWEOSS +D4A9;D4A9;1111 116F 11BC;D4A9;1111 116F 11BC; # (풩; 풩; 풩; 풩; 풩; ) HANGUL SYLLABLE PWEONG +D4AA;D4AA;1111 116F 11BD;D4AA;1111 116F 11BD; # (풪; 풪; 풪; 풪; 풪; ) HANGUL SYLLABLE PWEOJ +D4AB;D4AB;1111 116F 11BE;D4AB;1111 116F 11BE; # (풫; 풫; 풫; 풫; 풫; ) HANGUL SYLLABLE PWEOC +D4AC;D4AC;1111 116F 11BF;D4AC;1111 116F 11BF; # (풬; 풬; 풬; 풬; 풬; ) HANGUL SYLLABLE PWEOK +D4AD;D4AD;1111 116F 11C0;D4AD;1111 116F 11C0; # (풭; 풭; 풭; 풭; 풭; ) HANGUL SYLLABLE PWEOT +D4AE;D4AE;1111 116F 11C1;D4AE;1111 116F 11C1; # (풮; 풮; 풮; 풮; 풮; ) HANGUL SYLLABLE PWEOP +D4AF;D4AF;1111 116F 11C2;D4AF;1111 116F 11C2; # (풯; 풯; 풯; 풯; 풯; ) HANGUL SYLLABLE PWEOH +D4B0;D4B0;1111 1170;D4B0;1111 1170; # (풰; 풰; 풰; 풰; 풰; ) HANGUL SYLLABLE PWE +D4B1;D4B1;1111 1170 11A8;D4B1;1111 1170 11A8; # (풱; 풱; 풱; 풱; 풱; ) HANGUL SYLLABLE PWEG +D4B2;D4B2;1111 1170 11A9;D4B2;1111 1170 11A9; # (풲; 풲; 풲; 풲; 풲; ) HANGUL SYLLABLE PWEGG +D4B3;D4B3;1111 1170 11AA;D4B3;1111 1170 11AA; # (풳; 풳; 풳; 풳; 풳; ) HANGUL SYLLABLE PWEGS +D4B4;D4B4;1111 1170 11AB;D4B4;1111 1170 11AB; # (풴; 풴; 풴; 풴; 풴; ) HANGUL SYLLABLE PWEN +D4B5;D4B5;1111 1170 11AC;D4B5;1111 1170 11AC; # (풵; 풵; 풵; 풵; 풵; ) HANGUL SYLLABLE PWENJ +D4B6;D4B6;1111 1170 11AD;D4B6;1111 1170 11AD; # (풶; 풶; 풶; 풶; 풶; ) HANGUL SYLLABLE PWENH +D4B7;D4B7;1111 1170 11AE;D4B7;1111 1170 11AE; # (풷; 풷; 풷; 풷; 풷; ) HANGUL SYLLABLE PWED +D4B8;D4B8;1111 1170 11AF;D4B8;1111 1170 11AF; # (풸; 풸; 풸; 풸; 풸; ) HANGUL SYLLABLE PWEL +D4B9;D4B9;1111 1170 11B0;D4B9;1111 1170 11B0; # (풹; 풹; 풹; 풹; 풹; ) HANGUL SYLLABLE PWELG +D4BA;D4BA;1111 1170 11B1;D4BA;1111 1170 11B1; # (풺; 풺; 풺; 풺; 풺; ) HANGUL SYLLABLE PWELM +D4BB;D4BB;1111 1170 11B2;D4BB;1111 1170 11B2; # (풻; 풻; 풻; 풻; 풻; ) HANGUL SYLLABLE PWELB +D4BC;D4BC;1111 1170 11B3;D4BC;1111 1170 11B3; # (풼; 풼; 풼; 풼; 풼; ) HANGUL SYLLABLE PWELS +D4BD;D4BD;1111 1170 11B4;D4BD;1111 1170 11B4; # (풽; 풽; 풽; 풽; 풽; ) HANGUL SYLLABLE PWELT +D4BE;D4BE;1111 1170 11B5;D4BE;1111 1170 11B5; # (풾; 풾; 풾; 풾; 풾; ) HANGUL SYLLABLE PWELP +D4BF;D4BF;1111 1170 11B6;D4BF;1111 1170 11B6; # (풿; 풿; 풿; 풿; 풿; ) HANGUL SYLLABLE PWELH +D4C0;D4C0;1111 1170 11B7;D4C0;1111 1170 11B7; # (퓀; 퓀; 퓀; 퓀; 퓀; ) HANGUL SYLLABLE PWEM +D4C1;D4C1;1111 1170 11B8;D4C1;1111 1170 11B8; # (퓁; 퓁; 퓁; 퓁; 퓁; ) HANGUL SYLLABLE PWEB +D4C2;D4C2;1111 1170 11B9;D4C2;1111 1170 11B9; # (퓂; 퓂; 퓂; 퓂; 퓂; ) HANGUL SYLLABLE PWEBS +D4C3;D4C3;1111 1170 11BA;D4C3;1111 1170 11BA; # (퓃; 퓃; 퓃; 퓃; 퓃; ) HANGUL SYLLABLE PWES +D4C4;D4C4;1111 1170 11BB;D4C4;1111 1170 11BB; # (퓄; 퓄; 퓄; 퓄; 퓄; ) HANGUL SYLLABLE PWESS +D4C5;D4C5;1111 1170 11BC;D4C5;1111 1170 11BC; # (퓅; 퓅; 퓅; 퓅; 퓅; ) HANGUL SYLLABLE PWENG +D4C6;D4C6;1111 1170 11BD;D4C6;1111 1170 11BD; # (퓆; 퓆; 퓆; 퓆; 퓆; ) HANGUL SYLLABLE PWEJ +D4C7;D4C7;1111 1170 11BE;D4C7;1111 1170 11BE; # (퓇; 퓇; 퓇; 퓇; 퓇; ) HANGUL SYLLABLE PWEC +D4C8;D4C8;1111 1170 11BF;D4C8;1111 1170 11BF; # (퓈; 퓈; 퓈; 퓈; 퓈; ) HANGUL SYLLABLE PWEK +D4C9;D4C9;1111 1170 11C0;D4C9;1111 1170 11C0; # (퓉; 퓉; 퓉; 퓉; 퓉; ) HANGUL SYLLABLE PWET +D4CA;D4CA;1111 1170 11C1;D4CA;1111 1170 11C1; # (퓊; 퓊; 퓊; 퓊; 퓊; ) HANGUL SYLLABLE PWEP +D4CB;D4CB;1111 1170 11C2;D4CB;1111 1170 11C2; # (퓋; 퓋; 퓋; 퓋; 퓋; ) HANGUL SYLLABLE PWEH +D4CC;D4CC;1111 1171;D4CC;1111 1171; # (퓌; 퓌; 퓌; 퓌; 퓌; ) HANGUL SYLLABLE PWI +D4CD;D4CD;1111 1171 11A8;D4CD;1111 1171 11A8; # (퓍; 퓍; 퓍; 퓍; 퓍; ) HANGUL SYLLABLE PWIG +D4CE;D4CE;1111 1171 11A9;D4CE;1111 1171 11A9; # (퓎; 퓎; 퓎; 퓎; 퓎; ) HANGUL SYLLABLE PWIGG +D4CF;D4CF;1111 1171 11AA;D4CF;1111 1171 11AA; # (퓏; 퓏; 퓏; 퓏; 퓏; ) HANGUL SYLLABLE PWIGS +D4D0;D4D0;1111 1171 11AB;D4D0;1111 1171 11AB; # (퓐; 퓐; 퓐; 퓐; 퓐; ) HANGUL SYLLABLE PWIN +D4D1;D4D1;1111 1171 11AC;D4D1;1111 1171 11AC; # (퓑; 퓑; 퓑; 퓑; 퓑; ) HANGUL SYLLABLE PWINJ +D4D2;D4D2;1111 1171 11AD;D4D2;1111 1171 11AD; # (퓒; 퓒; 퓒; 퓒; 퓒; ) HANGUL SYLLABLE PWINH +D4D3;D4D3;1111 1171 11AE;D4D3;1111 1171 11AE; # (퓓; 퓓; 퓓; 퓓; 퓓; ) HANGUL SYLLABLE PWID +D4D4;D4D4;1111 1171 11AF;D4D4;1111 1171 11AF; # (퓔; 퓔; 퓔; 퓔; 퓔; ) HANGUL SYLLABLE PWIL +D4D5;D4D5;1111 1171 11B0;D4D5;1111 1171 11B0; # (퓕; 퓕; 퓕; 퓕; 퓕; ) HANGUL SYLLABLE PWILG +D4D6;D4D6;1111 1171 11B1;D4D6;1111 1171 11B1; # (퓖; 퓖; 퓖; 퓖; 퓖; ) HANGUL SYLLABLE PWILM +D4D7;D4D7;1111 1171 11B2;D4D7;1111 1171 11B2; # (퓗; 퓗; 퓗; 퓗; 퓗; ) HANGUL SYLLABLE PWILB +D4D8;D4D8;1111 1171 11B3;D4D8;1111 1171 11B3; # (퓘; 퓘; 퓘; 퓘; 퓘; ) HANGUL SYLLABLE PWILS +D4D9;D4D9;1111 1171 11B4;D4D9;1111 1171 11B4; # (퓙; 퓙; 퓙; 퓙; 퓙; ) HANGUL SYLLABLE PWILT +D4DA;D4DA;1111 1171 11B5;D4DA;1111 1171 11B5; # (퓚; 퓚; 퓚; 퓚; 퓚; ) HANGUL SYLLABLE PWILP +D4DB;D4DB;1111 1171 11B6;D4DB;1111 1171 11B6; # (퓛; 퓛; 퓛; 퓛; 퓛; ) HANGUL SYLLABLE PWILH +D4DC;D4DC;1111 1171 11B7;D4DC;1111 1171 11B7; # (퓜; 퓜; 퓜; 퓜; 퓜; ) HANGUL SYLLABLE PWIM +D4DD;D4DD;1111 1171 11B8;D4DD;1111 1171 11B8; # (퓝; 퓝; 퓝; 퓝; 퓝; ) HANGUL SYLLABLE PWIB +D4DE;D4DE;1111 1171 11B9;D4DE;1111 1171 11B9; # (퓞; 퓞; 퓞; 퓞; 퓞; ) HANGUL SYLLABLE PWIBS +D4DF;D4DF;1111 1171 11BA;D4DF;1111 1171 11BA; # (퓟; 퓟; 퓟; 퓟; 퓟; ) HANGUL SYLLABLE PWIS +D4E0;D4E0;1111 1171 11BB;D4E0;1111 1171 11BB; # (퓠; 퓠; 퓠; 퓠; 퓠; ) HANGUL SYLLABLE PWISS +D4E1;D4E1;1111 1171 11BC;D4E1;1111 1171 11BC; # (퓡; 퓡; 퓡; 퓡; 퓡; ) HANGUL SYLLABLE PWING +D4E2;D4E2;1111 1171 11BD;D4E2;1111 1171 11BD; # (퓢; 퓢; 퓢; 퓢; 퓢; ) HANGUL SYLLABLE PWIJ +D4E3;D4E3;1111 1171 11BE;D4E3;1111 1171 11BE; # (퓣; 퓣; 퓣; 퓣; 퓣; ) HANGUL SYLLABLE PWIC +D4E4;D4E4;1111 1171 11BF;D4E4;1111 1171 11BF; # (퓤; 퓤; 퓤; 퓤; 퓤; ) HANGUL SYLLABLE PWIK +D4E5;D4E5;1111 1171 11C0;D4E5;1111 1171 11C0; # (퓥; 퓥; 퓥; 퓥; 퓥; ) HANGUL SYLLABLE PWIT +D4E6;D4E6;1111 1171 11C1;D4E6;1111 1171 11C1; # (퓦; 퓦; 퓦; 퓦; 퓦; ) HANGUL SYLLABLE PWIP +D4E7;D4E7;1111 1171 11C2;D4E7;1111 1171 11C2; # (퓧; 퓧; 퓧; 퓧; 퓧; ) HANGUL SYLLABLE PWIH +D4E8;D4E8;1111 1172;D4E8;1111 1172; # (퓨; 퓨; 퓨; 퓨; 퓨; ) HANGUL SYLLABLE PYU +D4E9;D4E9;1111 1172 11A8;D4E9;1111 1172 11A8; # (퓩; 퓩; 퓩; 퓩; 퓩; ) HANGUL SYLLABLE PYUG +D4EA;D4EA;1111 1172 11A9;D4EA;1111 1172 11A9; # (퓪; 퓪; 퓪; 퓪; 퓪; ) HANGUL SYLLABLE PYUGG +D4EB;D4EB;1111 1172 11AA;D4EB;1111 1172 11AA; # (퓫; 퓫; 퓫; 퓫; 퓫; ) HANGUL SYLLABLE PYUGS +D4EC;D4EC;1111 1172 11AB;D4EC;1111 1172 11AB; # (퓬; 퓬; 퓬; 퓬; 퓬; ) HANGUL SYLLABLE PYUN +D4ED;D4ED;1111 1172 11AC;D4ED;1111 1172 11AC; # (퓭; 퓭; 퓭; 퓭; 퓭; ) HANGUL SYLLABLE PYUNJ +D4EE;D4EE;1111 1172 11AD;D4EE;1111 1172 11AD; # (퓮; 퓮; 퓮; 퓮; 퓮; ) HANGUL SYLLABLE PYUNH +D4EF;D4EF;1111 1172 11AE;D4EF;1111 1172 11AE; # (퓯; 퓯; 퓯; 퓯; 퓯; ) HANGUL SYLLABLE PYUD +D4F0;D4F0;1111 1172 11AF;D4F0;1111 1172 11AF; # (퓰; 퓰; 퓰; 퓰; 퓰; ) HANGUL SYLLABLE PYUL +D4F1;D4F1;1111 1172 11B0;D4F1;1111 1172 11B0; # (퓱; 퓱; 퓱; 퓱; 퓱; ) HANGUL SYLLABLE PYULG +D4F2;D4F2;1111 1172 11B1;D4F2;1111 1172 11B1; # (퓲; 퓲; 퓲; 퓲; 퓲; ) HANGUL SYLLABLE PYULM +D4F3;D4F3;1111 1172 11B2;D4F3;1111 1172 11B2; # (퓳; 퓳; 퓳; 퓳; 퓳; ) HANGUL SYLLABLE PYULB +D4F4;D4F4;1111 1172 11B3;D4F4;1111 1172 11B3; # (퓴; 퓴; 퓴; 퓴; 퓴; ) HANGUL SYLLABLE PYULS +D4F5;D4F5;1111 1172 11B4;D4F5;1111 1172 11B4; # (퓵; 퓵; 퓵; 퓵; 퓵; ) HANGUL SYLLABLE PYULT +D4F6;D4F6;1111 1172 11B5;D4F6;1111 1172 11B5; # (퓶; 퓶; 퓶; 퓶; 퓶; ) HANGUL SYLLABLE PYULP +D4F7;D4F7;1111 1172 11B6;D4F7;1111 1172 11B6; # (퓷; 퓷; 퓷; 퓷; 퓷; ) HANGUL SYLLABLE PYULH +D4F8;D4F8;1111 1172 11B7;D4F8;1111 1172 11B7; # (퓸; 퓸; 퓸; 퓸; 퓸; ) HANGUL SYLLABLE PYUM +D4F9;D4F9;1111 1172 11B8;D4F9;1111 1172 11B8; # (퓹; 퓹; 퓹; 퓹; 퓹; ) HANGUL SYLLABLE PYUB +D4FA;D4FA;1111 1172 11B9;D4FA;1111 1172 11B9; # (퓺; 퓺; 퓺; 퓺; 퓺; ) HANGUL SYLLABLE PYUBS +D4FB;D4FB;1111 1172 11BA;D4FB;1111 1172 11BA; # (퓻; 퓻; 퓻; 퓻; 퓻; ) HANGUL SYLLABLE PYUS +D4FC;D4FC;1111 1172 11BB;D4FC;1111 1172 11BB; # (퓼; 퓼; 퓼; 퓼; 퓼; ) HANGUL SYLLABLE PYUSS +D4FD;D4FD;1111 1172 11BC;D4FD;1111 1172 11BC; # (퓽; 퓽; 퓽; 퓽; 퓽; ) HANGUL SYLLABLE PYUNG +D4FE;D4FE;1111 1172 11BD;D4FE;1111 1172 11BD; # (퓾; 퓾; 퓾; 퓾; 퓾; ) HANGUL SYLLABLE PYUJ +D4FF;D4FF;1111 1172 11BE;D4FF;1111 1172 11BE; # (퓿; 퓿; 퓿; 퓿; 퓿; ) HANGUL SYLLABLE PYUC +D500;D500;1111 1172 11BF;D500;1111 1172 11BF; # (픀; 픀; 픀; 픀; 픀; ) HANGUL SYLLABLE PYUK +D501;D501;1111 1172 11C0;D501;1111 1172 11C0; # (픁; 픁; 픁; 픁; 픁; ) HANGUL SYLLABLE PYUT +D502;D502;1111 1172 11C1;D502;1111 1172 11C1; # (픂; 픂; 픂; 픂; 픂; ) HANGUL SYLLABLE PYUP +D503;D503;1111 1172 11C2;D503;1111 1172 11C2; # (픃; 픃; 픃; 픃; 픃; ) HANGUL SYLLABLE PYUH +D504;D504;1111 1173;D504;1111 1173; # (프; 프; 프; 프; 프; ) HANGUL SYLLABLE PEU +D505;D505;1111 1173 11A8;D505;1111 1173 11A8; # (픅; 픅; 픅; 픅; 픅; ) HANGUL SYLLABLE PEUG +D506;D506;1111 1173 11A9;D506;1111 1173 11A9; # (픆; 픆; 픆; 픆; 픆; ) HANGUL SYLLABLE PEUGG +D507;D507;1111 1173 11AA;D507;1111 1173 11AA; # (픇; 픇; 픇; 픇; 픇; ) HANGUL SYLLABLE PEUGS +D508;D508;1111 1173 11AB;D508;1111 1173 11AB; # (픈; 픈; 픈; 픈; 픈; ) HANGUL SYLLABLE PEUN +D509;D509;1111 1173 11AC;D509;1111 1173 11AC; # (픉; 픉; 픉; 픉; 픉; ) HANGUL SYLLABLE PEUNJ +D50A;D50A;1111 1173 11AD;D50A;1111 1173 11AD; # (픊; 픊; 픊; 픊; 픊; ) HANGUL SYLLABLE PEUNH +D50B;D50B;1111 1173 11AE;D50B;1111 1173 11AE; # (픋; 픋; 픋; 픋; 픋; ) HANGUL SYLLABLE PEUD +D50C;D50C;1111 1173 11AF;D50C;1111 1173 11AF; # (플; 플; 플; 플; 플; ) HANGUL SYLLABLE PEUL +D50D;D50D;1111 1173 11B0;D50D;1111 1173 11B0; # (픍; 픍; 픍; 픍; 픍; ) HANGUL SYLLABLE PEULG +D50E;D50E;1111 1173 11B1;D50E;1111 1173 11B1; # (픎; 픎; 픎; 픎; 픎; ) HANGUL SYLLABLE PEULM +D50F;D50F;1111 1173 11B2;D50F;1111 1173 11B2; # (픏; 픏; 픏; 픏; 픏; ) HANGUL SYLLABLE PEULB +D510;D510;1111 1173 11B3;D510;1111 1173 11B3; # (픐; 픐; 픐; 픐; 픐; ) HANGUL SYLLABLE PEULS +D511;D511;1111 1173 11B4;D511;1111 1173 11B4; # (픑; 픑; 픑; 픑; 픑; ) HANGUL SYLLABLE PEULT +D512;D512;1111 1173 11B5;D512;1111 1173 11B5; # (픒; 픒; 픒; 픒; 픒; ) HANGUL SYLLABLE PEULP +D513;D513;1111 1173 11B6;D513;1111 1173 11B6; # (픓; 픓; 픓; 픓; 픓; ) HANGUL SYLLABLE PEULH +D514;D514;1111 1173 11B7;D514;1111 1173 11B7; # (픔; 픔; 픔; 픔; 픔; ) HANGUL SYLLABLE PEUM +D515;D515;1111 1173 11B8;D515;1111 1173 11B8; # (픕; 픕; 픕; 픕; 픕; ) HANGUL SYLLABLE PEUB +D516;D516;1111 1173 11B9;D516;1111 1173 11B9; # (픖; 픖; 픖; 픖; 픖; ) HANGUL SYLLABLE PEUBS +D517;D517;1111 1173 11BA;D517;1111 1173 11BA; # (픗; 픗; 픗; 픗; 픗; ) HANGUL SYLLABLE PEUS +D518;D518;1111 1173 11BB;D518;1111 1173 11BB; # (픘; 픘; 픘; 픘; 픘; ) HANGUL SYLLABLE PEUSS +D519;D519;1111 1173 11BC;D519;1111 1173 11BC; # (픙; 픙; 픙; 픙; 픙; ) HANGUL SYLLABLE PEUNG +D51A;D51A;1111 1173 11BD;D51A;1111 1173 11BD; # (픚; 픚; 픚; 픚; 픚; ) HANGUL SYLLABLE PEUJ +D51B;D51B;1111 1173 11BE;D51B;1111 1173 11BE; # (픛; 픛; 픛; 픛; 픛; ) HANGUL SYLLABLE PEUC +D51C;D51C;1111 1173 11BF;D51C;1111 1173 11BF; # (픜; 픜; 픜; 픜; 픜; ) HANGUL SYLLABLE PEUK +D51D;D51D;1111 1173 11C0;D51D;1111 1173 11C0; # (픝; 픝; 픝; 픝; 픝; ) HANGUL SYLLABLE PEUT +D51E;D51E;1111 1173 11C1;D51E;1111 1173 11C1; # (픞; 픞; 픞; 픞; 픞; ) HANGUL SYLLABLE PEUP +D51F;D51F;1111 1173 11C2;D51F;1111 1173 11C2; # (픟; 픟; 픟; 픟; 픟; ) HANGUL SYLLABLE PEUH +D520;D520;1111 1174;D520;1111 1174; # (픠; 픠; 픠; 픠; 픠; ) HANGUL SYLLABLE PYI +D521;D521;1111 1174 11A8;D521;1111 1174 11A8; # (픡; 픡; 픡; 픡; 픡; ) HANGUL SYLLABLE PYIG +D522;D522;1111 1174 11A9;D522;1111 1174 11A9; # (픢; 픢; 픢; 픢; 픢; ) HANGUL SYLLABLE PYIGG +D523;D523;1111 1174 11AA;D523;1111 1174 11AA; # (픣; 픣; 픣; 픣; 픣; ) HANGUL SYLLABLE PYIGS +D524;D524;1111 1174 11AB;D524;1111 1174 11AB; # (픤; 픤; 픤; 픤; 픤; ) HANGUL SYLLABLE PYIN +D525;D525;1111 1174 11AC;D525;1111 1174 11AC; # (픥; 픥; 픥; 픥; 픥; ) HANGUL SYLLABLE PYINJ +D526;D526;1111 1174 11AD;D526;1111 1174 11AD; # (픦; 픦; 픦; 픦; 픦; ) HANGUL SYLLABLE PYINH +D527;D527;1111 1174 11AE;D527;1111 1174 11AE; # (픧; 픧; 픧; 픧; 픧; ) HANGUL SYLLABLE PYID +D528;D528;1111 1174 11AF;D528;1111 1174 11AF; # (픨; 픨; 픨; 픨; 픨; ) HANGUL SYLLABLE PYIL +D529;D529;1111 1174 11B0;D529;1111 1174 11B0; # (픩; 픩; 픩; 픩; 픩; ) HANGUL SYLLABLE PYILG +D52A;D52A;1111 1174 11B1;D52A;1111 1174 11B1; # (픪; 픪; 픪; 픪; 픪; ) HANGUL SYLLABLE PYILM +D52B;D52B;1111 1174 11B2;D52B;1111 1174 11B2; # (픫; 픫; 픫; 픫; 픫; ) HANGUL SYLLABLE PYILB +D52C;D52C;1111 1174 11B3;D52C;1111 1174 11B3; # (픬; 픬; 픬; 픬; 픬; ) HANGUL SYLLABLE PYILS +D52D;D52D;1111 1174 11B4;D52D;1111 1174 11B4; # (픭; 픭; 픭; 픭; 픭; ) HANGUL SYLLABLE PYILT +D52E;D52E;1111 1174 11B5;D52E;1111 1174 11B5; # (픮; 픮; 픮; 픮; 픮; ) HANGUL SYLLABLE PYILP +D52F;D52F;1111 1174 11B6;D52F;1111 1174 11B6; # (픯; 픯; 픯; 픯; 픯; ) HANGUL SYLLABLE PYILH +D530;D530;1111 1174 11B7;D530;1111 1174 11B7; # (픰; 픰; 픰; 픰; 픰; ) HANGUL SYLLABLE PYIM +D531;D531;1111 1174 11B8;D531;1111 1174 11B8; # (픱; 픱; 픱; 픱; 픱; ) HANGUL SYLLABLE PYIB +D532;D532;1111 1174 11B9;D532;1111 1174 11B9; # (픲; 픲; 픲; 픲; 픲; ) HANGUL SYLLABLE PYIBS +D533;D533;1111 1174 11BA;D533;1111 1174 11BA; # (픳; 픳; 픳; 픳; 픳; ) HANGUL SYLLABLE PYIS +D534;D534;1111 1174 11BB;D534;1111 1174 11BB; # (픴; 픴; 픴; 픴; 픴; ) HANGUL SYLLABLE PYISS +D535;D535;1111 1174 11BC;D535;1111 1174 11BC; # (픵; 픵; 픵; 픵; 픵; ) HANGUL SYLLABLE PYING +D536;D536;1111 1174 11BD;D536;1111 1174 11BD; # (픶; 픶; 픶; 픶; 픶; ) HANGUL SYLLABLE PYIJ +D537;D537;1111 1174 11BE;D537;1111 1174 11BE; # (픷; 픷; 픷; 픷; 픷; ) HANGUL SYLLABLE PYIC +D538;D538;1111 1174 11BF;D538;1111 1174 11BF; # (픸; 픸; 픸; 픸; 픸; ) HANGUL SYLLABLE PYIK +D539;D539;1111 1174 11C0;D539;1111 1174 11C0; # (픹; 픹; 픹; 픹; 픹; ) HANGUL SYLLABLE PYIT +D53A;D53A;1111 1174 11C1;D53A;1111 1174 11C1; # (픺; 픺; 픺; 픺; 픺; ) HANGUL SYLLABLE PYIP +D53B;D53B;1111 1174 11C2;D53B;1111 1174 11C2; # (픻; 픻; 픻; 픻; 픻; ) HANGUL SYLLABLE PYIH +D53C;D53C;1111 1175;D53C;1111 1175; # (피; 피; 피; 피; 피; ) HANGUL SYLLABLE PI +D53D;D53D;1111 1175 11A8;D53D;1111 1175 11A8; # (픽; 픽; 픽; 픽; 픽; ) HANGUL SYLLABLE PIG +D53E;D53E;1111 1175 11A9;D53E;1111 1175 11A9; # (픾; 픾; 픾; 픾; 픾; ) HANGUL SYLLABLE PIGG +D53F;D53F;1111 1175 11AA;D53F;1111 1175 11AA; # (픿; 픿; 픿; 픿; 픿; ) HANGUL SYLLABLE PIGS +D540;D540;1111 1175 11AB;D540;1111 1175 11AB; # (핀; 핀; 핀; 핀; 핀; ) HANGUL SYLLABLE PIN +D541;D541;1111 1175 11AC;D541;1111 1175 11AC; # (핁; 핁; 핁; 핁; 핁; ) HANGUL SYLLABLE PINJ +D542;D542;1111 1175 11AD;D542;1111 1175 11AD; # (핂; 핂; 핂; 핂; 핂; ) HANGUL SYLLABLE PINH +D543;D543;1111 1175 11AE;D543;1111 1175 11AE; # (핃; 핃; 핃; 핃; 핃; ) HANGUL SYLLABLE PID +D544;D544;1111 1175 11AF;D544;1111 1175 11AF; # (필; 필; 필; 필; 필; ) HANGUL SYLLABLE PIL +D545;D545;1111 1175 11B0;D545;1111 1175 11B0; # (핅; 핅; 핅; 핅; 핅; ) HANGUL SYLLABLE PILG +D546;D546;1111 1175 11B1;D546;1111 1175 11B1; # (핆; 핆; 핆; 핆; 핆; ) HANGUL SYLLABLE PILM +D547;D547;1111 1175 11B2;D547;1111 1175 11B2; # (핇; 핇; 핇; 핇; 핇; ) HANGUL SYLLABLE PILB +D548;D548;1111 1175 11B3;D548;1111 1175 11B3; # (핈; 핈; 핈; 핈; 핈; ) HANGUL SYLLABLE PILS +D549;D549;1111 1175 11B4;D549;1111 1175 11B4; # (핉; 핉; 핉; 핉; 핉; ) HANGUL SYLLABLE PILT +D54A;D54A;1111 1175 11B5;D54A;1111 1175 11B5; # (핊; 핊; 핊; 핊; 핊; ) HANGUL SYLLABLE PILP +D54B;D54B;1111 1175 11B6;D54B;1111 1175 11B6; # (핋; 핋; 핋; 핋; 핋; ) HANGUL SYLLABLE PILH +D54C;D54C;1111 1175 11B7;D54C;1111 1175 11B7; # (핌; 핌; 핌; 핌; 핌; ) HANGUL SYLLABLE PIM +D54D;D54D;1111 1175 11B8;D54D;1111 1175 11B8; # (핍; 핍; 핍; 핍; 핍; ) HANGUL SYLLABLE PIB +D54E;D54E;1111 1175 11B9;D54E;1111 1175 11B9; # (핎; 핎; 핎; 핎; 핎; ) HANGUL SYLLABLE PIBS +D54F;D54F;1111 1175 11BA;D54F;1111 1175 11BA; # (핏; 핏; 핏; 핏; 핏; ) HANGUL SYLLABLE PIS +D550;D550;1111 1175 11BB;D550;1111 1175 11BB; # (핐; 핐; 핐; 핐; 핐; ) HANGUL SYLLABLE PISS +D551;D551;1111 1175 11BC;D551;1111 1175 11BC; # (핑; 핑; 핑; 핑; 핑; ) HANGUL SYLLABLE PING +D552;D552;1111 1175 11BD;D552;1111 1175 11BD; # (핒; 핒; 핒; 핒; 핒; ) HANGUL SYLLABLE PIJ +D553;D553;1111 1175 11BE;D553;1111 1175 11BE; # (핓; 핓; 핓; 핓; 핓; ) HANGUL SYLLABLE PIC +D554;D554;1111 1175 11BF;D554;1111 1175 11BF; # (핔; 핔; 핔; 핔; 핔; ) HANGUL SYLLABLE PIK +D555;D555;1111 1175 11C0;D555;1111 1175 11C0; # (핕; 핕; 핕; 핕; 핕; ) HANGUL SYLLABLE PIT +D556;D556;1111 1175 11C1;D556;1111 1175 11C1; # (핖; 핖; 핖; 핖; 핖; ) HANGUL SYLLABLE PIP +D557;D557;1111 1175 11C2;D557;1111 1175 11C2; # (핗; 핗; 핗; 핗; 핗; ) HANGUL SYLLABLE PIH +D558;D558;1112 1161;D558;1112 1161; # (하; 하; 하; 하; 하; ) HANGUL SYLLABLE HA +D559;D559;1112 1161 11A8;D559;1112 1161 11A8; # (학; 학; 학; 학; 학; ) HANGUL SYLLABLE HAG +D55A;D55A;1112 1161 11A9;D55A;1112 1161 11A9; # (핚; 핚; 핚; 핚; 핚; ) HANGUL SYLLABLE HAGG +D55B;D55B;1112 1161 11AA;D55B;1112 1161 11AA; # (핛; 핛; 핛; 핛; 핛; ) HANGUL SYLLABLE HAGS +D55C;D55C;1112 1161 11AB;D55C;1112 1161 11AB; # (한; 한; 한; 한; 한; ) HANGUL SYLLABLE HAN +D55D;D55D;1112 1161 11AC;D55D;1112 1161 11AC; # (핝; 핝; 핝; 핝; 핝; ) HANGUL SYLLABLE HANJ +D55E;D55E;1112 1161 11AD;D55E;1112 1161 11AD; # (핞; 핞; 핞; 핞; 핞; ) HANGUL SYLLABLE HANH +D55F;D55F;1112 1161 11AE;D55F;1112 1161 11AE; # (핟; 핟; 핟; 핟; 핟; ) HANGUL SYLLABLE HAD +D560;D560;1112 1161 11AF;D560;1112 1161 11AF; # (할; 할; 할; 할; 할; ) HANGUL SYLLABLE HAL +D561;D561;1112 1161 11B0;D561;1112 1161 11B0; # (핡; 핡; 핡; 핡; 핡; ) HANGUL SYLLABLE HALG +D562;D562;1112 1161 11B1;D562;1112 1161 11B1; # (핢; 핢; 핢; 핢; 핢; ) HANGUL SYLLABLE HALM +D563;D563;1112 1161 11B2;D563;1112 1161 11B2; # (핣; 핣; 핣; 핣; 핣; ) HANGUL SYLLABLE HALB +D564;D564;1112 1161 11B3;D564;1112 1161 11B3; # (핤; 핤; 핤; 핤; 핤; ) HANGUL SYLLABLE HALS +D565;D565;1112 1161 11B4;D565;1112 1161 11B4; # (핥; 핥; 핥; 핥; 핥; ) HANGUL SYLLABLE HALT +D566;D566;1112 1161 11B5;D566;1112 1161 11B5; # (핦; 핦; 핦; 핦; 핦; ) HANGUL SYLLABLE HALP +D567;D567;1112 1161 11B6;D567;1112 1161 11B6; # (핧; 핧; 핧; 핧; 핧; ) HANGUL SYLLABLE HALH +D568;D568;1112 1161 11B7;D568;1112 1161 11B7; # (함; 함; 함; 함; 함; ) HANGUL SYLLABLE HAM +D569;D569;1112 1161 11B8;D569;1112 1161 11B8; # (합; 합; 합; 합; 합; ) HANGUL SYLLABLE HAB +D56A;D56A;1112 1161 11B9;D56A;1112 1161 11B9; # (핪; 핪; 핪; 핪; 핪; ) HANGUL SYLLABLE HABS +D56B;D56B;1112 1161 11BA;D56B;1112 1161 11BA; # (핫; 핫; 핫; 핫; 핫; ) HANGUL SYLLABLE HAS +D56C;D56C;1112 1161 11BB;D56C;1112 1161 11BB; # (핬; 핬; 핬; 핬; 핬; ) HANGUL SYLLABLE HASS +D56D;D56D;1112 1161 11BC;D56D;1112 1161 11BC; # (항; 항; 항; 항; 항; ) HANGUL SYLLABLE HANG +D56E;D56E;1112 1161 11BD;D56E;1112 1161 11BD; # (핮; 핮; 핮; 핮; 핮; ) HANGUL SYLLABLE HAJ +D56F;D56F;1112 1161 11BE;D56F;1112 1161 11BE; # (핯; 핯; 핯; 핯; 핯; ) HANGUL SYLLABLE HAC +D570;D570;1112 1161 11BF;D570;1112 1161 11BF; # (핰; 핰; 핰; 핰; 핰; ) HANGUL SYLLABLE HAK +D571;D571;1112 1161 11C0;D571;1112 1161 11C0; # (핱; 핱; 핱; 핱; 핱; ) HANGUL SYLLABLE HAT +D572;D572;1112 1161 11C1;D572;1112 1161 11C1; # (핲; 핲; 핲; 핲; 핲; ) HANGUL SYLLABLE HAP +D573;D573;1112 1161 11C2;D573;1112 1161 11C2; # (핳; 핳; 핳; 핳; 핳; ) HANGUL SYLLABLE HAH +D574;D574;1112 1162;D574;1112 1162; # (해; 해; 해; 해; 해; ) HANGUL SYLLABLE HAE +D575;D575;1112 1162 11A8;D575;1112 1162 11A8; # (핵; 핵; 핵; 핵; 핵; ) HANGUL SYLLABLE HAEG +D576;D576;1112 1162 11A9;D576;1112 1162 11A9; # (핶; 핶; 핶; 핶; 핶; ) HANGUL SYLLABLE HAEGG +D577;D577;1112 1162 11AA;D577;1112 1162 11AA; # (핷; 핷; 핷; 핷; 핷; ) HANGUL SYLLABLE HAEGS +D578;D578;1112 1162 11AB;D578;1112 1162 11AB; # (핸; 핸; 핸; 핸; 핸; ) HANGUL SYLLABLE HAEN +D579;D579;1112 1162 11AC;D579;1112 1162 11AC; # (핹; 핹; 핹; 핹; 핹; ) HANGUL SYLLABLE HAENJ +D57A;D57A;1112 1162 11AD;D57A;1112 1162 11AD; # (핺; 핺; 핺; 핺; 핺; ) HANGUL SYLLABLE HAENH +D57B;D57B;1112 1162 11AE;D57B;1112 1162 11AE; # (핻; 핻; 핻; 핻; 핻; ) HANGUL SYLLABLE HAED +D57C;D57C;1112 1162 11AF;D57C;1112 1162 11AF; # (핼; 핼; 핼; 핼; 핼; ) HANGUL SYLLABLE HAEL +D57D;D57D;1112 1162 11B0;D57D;1112 1162 11B0; # (핽; 핽; 핽; 핽; 핽; ) HANGUL SYLLABLE HAELG +D57E;D57E;1112 1162 11B1;D57E;1112 1162 11B1; # (핾; 핾; 핾; 핾; 핾; ) HANGUL SYLLABLE HAELM +D57F;D57F;1112 1162 11B2;D57F;1112 1162 11B2; # (핿; 핿; 핿; 핿; 핿; ) HANGUL SYLLABLE HAELB +D580;D580;1112 1162 11B3;D580;1112 1162 11B3; # (햀; 햀; 햀; 햀; 햀; ) HANGUL SYLLABLE HAELS +D581;D581;1112 1162 11B4;D581;1112 1162 11B4; # (햁; 햁; 햁; 햁; 햁; ) HANGUL SYLLABLE HAELT +D582;D582;1112 1162 11B5;D582;1112 1162 11B5; # (햂; 햂; 햂; 햂; 햂; ) HANGUL SYLLABLE HAELP +D583;D583;1112 1162 11B6;D583;1112 1162 11B6; # (햃; 햃; 햃; 햃; 햃; ) HANGUL SYLLABLE HAELH +D584;D584;1112 1162 11B7;D584;1112 1162 11B7; # (햄; 햄; 햄; 햄; 햄; ) HANGUL SYLLABLE HAEM +D585;D585;1112 1162 11B8;D585;1112 1162 11B8; # (햅; 햅; 햅; 햅; 햅; ) HANGUL SYLLABLE HAEB +D586;D586;1112 1162 11B9;D586;1112 1162 11B9; # (햆; 햆; 햆; 햆; 햆; ) HANGUL SYLLABLE HAEBS +D587;D587;1112 1162 11BA;D587;1112 1162 11BA; # (햇; 햇; 햇; 햇; 햇; ) HANGUL SYLLABLE HAES +D588;D588;1112 1162 11BB;D588;1112 1162 11BB; # (했; 했; 했; 했; 했; ) HANGUL SYLLABLE HAESS +D589;D589;1112 1162 11BC;D589;1112 1162 11BC; # (행; 행; 행; 행; 행; ) HANGUL SYLLABLE HAENG +D58A;D58A;1112 1162 11BD;D58A;1112 1162 11BD; # (햊; 햊; 햊; 햊; 햊; ) HANGUL SYLLABLE HAEJ +D58B;D58B;1112 1162 11BE;D58B;1112 1162 11BE; # (햋; 햋; 햋; 햋; 햋; ) HANGUL SYLLABLE HAEC +D58C;D58C;1112 1162 11BF;D58C;1112 1162 11BF; # (햌; 햌; 햌; 햌; 햌; ) HANGUL SYLLABLE HAEK +D58D;D58D;1112 1162 11C0;D58D;1112 1162 11C0; # (햍; 햍; 햍; 햍; 햍; ) HANGUL SYLLABLE HAET +D58E;D58E;1112 1162 11C1;D58E;1112 1162 11C1; # (햎; 햎; 햎; 햎; 햎; ) HANGUL SYLLABLE HAEP +D58F;D58F;1112 1162 11C2;D58F;1112 1162 11C2; # (햏; 햏; 햏; 햏; 햏; ) HANGUL SYLLABLE HAEH +D590;D590;1112 1163;D590;1112 1163; # (햐; 햐; 햐; 햐; 햐; ) HANGUL SYLLABLE HYA +D591;D591;1112 1163 11A8;D591;1112 1163 11A8; # (햑; 햑; 햑; 햑; 햑; ) HANGUL SYLLABLE HYAG +D592;D592;1112 1163 11A9;D592;1112 1163 11A9; # (햒; 햒; 햒; 햒; 햒; ) HANGUL SYLLABLE HYAGG +D593;D593;1112 1163 11AA;D593;1112 1163 11AA; # (햓; 햓; 햓; 햓; 햓; ) HANGUL SYLLABLE HYAGS +D594;D594;1112 1163 11AB;D594;1112 1163 11AB; # (햔; 햔; 햔; 햔; 햔; ) HANGUL SYLLABLE HYAN +D595;D595;1112 1163 11AC;D595;1112 1163 11AC; # (햕; 햕; 햕; 햕; 햕; ) HANGUL SYLLABLE HYANJ +D596;D596;1112 1163 11AD;D596;1112 1163 11AD; # (햖; 햖; 햖; 햖; 햖; ) HANGUL SYLLABLE HYANH +D597;D597;1112 1163 11AE;D597;1112 1163 11AE; # (햗; 햗; 햗; 햗; 햗; ) HANGUL SYLLABLE HYAD +D598;D598;1112 1163 11AF;D598;1112 1163 11AF; # (햘; 햘; 햘; 햘; 햘; ) HANGUL SYLLABLE HYAL +D599;D599;1112 1163 11B0;D599;1112 1163 11B0; # (햙; 햙; 햙; 햙; 햙; ) HANGUL SYLLABLE HYALG +D59A;D59A;1112 1163 11B1;D59A;1112 1163 11B1; # (햚; 햚; 햚; 햚; 햚; ) HANGUL SYLLABLE HYALM +D59B;D59B;1112 1163 11B2;D59B;1112 1163 11B2; # (햛; 햛; 햛; 햛; 햛; ) HANGUL SYLLABLE HYALB +D59C;D59C;1112 1163 11B3;D59C;1112 1163 11B3; # (햜; 햜; 햜; 햜; 햜; ) HANGUL SYLLABLE HYALS +D59D;D59D;1112 1163 11B4;D59D;1112 1163 11B4; # (햝; 햝; 햝; 햝; 햝; ) HANGUL SYLLABLE HYALT +D59E;D59E;1112 1163 11B5;D59E;1112 1163 11B5; # (햞; 햞; 햞; 햞; 햞; ) HANGUL SYLLABLE HYALP +D59F;D59F;1112 1163 11B6;D59F;1112 1163 11B6; # (햟; 햟; 햟; 햟; 햟; ) HANGUL SYLLABLE HYALH +D5A0;D5A0;1112 1163 11B7;D5A0;1112 1163 11B7; # (햠; 햠; 햠; 햠; 햠; ) HANGUL SYLLABLE HYAM +D5A1;D5A1;1112 1163 11B8;D5A1;1112 1163 11B8; # (햡; 햡; 햡; 햡; 햡; ) HANGUL SYLLABLE HYAB +D5A2;D5A2;1112 1163 11B9;D5A2;1112 1163 11B9; # (햢; 햢; 햢; 햢; 햢; ) HANGUL SYLLABLE HYABS +D5A3;D5A3;1112 1163 11BA;D5A3;1112 1163 11BA; # (햣; 햣; 햣; 햣; 햣; ) HANGUL SYLLABLE HYAS +D5A4;D5A4;1112 1163 11BB;D5A4;1112 1163 11BB; # (햤; 햤; 햤; 햤; 햤; ) HANGUL SYLLABLE HYASS +D5A5;D5A5;1112 1163 11BC;D5A5;1112 1163 11BC; # (향; 향; 향; 향; 향; ) HANGUL SYLLABLE HYANG +D5A6;D5A6;1112 1163 11BD;D5A6;1112 1163 11BD; # (햦; 햦; 햦; 햦; 햦; ) HANGUL SYLLABLE HYAJ +D5A7;D5A7;1112 1163 11BE;D5A7;1112 1163 11BE; # (햧; 햧; 햧; 햧; 햧; ) HANGUL SYLLABLE HYAC +D5A8;D5A8;1112 1163 11BF;D5A8;1112 1163 11BF; # (햨; 햨; 햨; 햨; 햨; ) HANGUL SYLLABLE HYAK +D5A9;D5A9;1112 1163 11C0;D5A9;1112 1163 11C0; # (햩; 햩; 햩; 햩; 햩; ) HANGUL SYLLABLE HYAT +D5AA;D5AA;1112 1163 11C1;D5AA;1112 1163 11C1; # (햪; 햪; 햪; 햪; 햪; ) HANGUL SYLLABLE HYAP +D5AB;D5AB;1112 1163 11C2;D5AB;1112 1163 11C2; # (햫; 햫; 햫; 햫; 햫; ) HANGUL SYLLABLE HYAH +D5AC;D5AC;1112 1164;D5AC;1112 1164; # (햬; 햬; 햬; 햬; 햬; ) HANGUL SYLLABLE HYAE +D5AD;D5AD;1112 1164 11A8;D5AD;1112 1164 11A8; # (햭; 햭; 햭; 햭; 햭; ) HANGUL SYLLABLE HYAEG +D5AE;D5AE;1112 1164 11A9;D5AE;1112 1164 11A9; # (햮; 햮; 햮; 햮; 햮; ) HANGUL SYLLABLE HYAEGG +D5AF;D5AF;1112 1164 11AA;D5AF;1112 1164 11AA; # (햯; 햯; 햯; 햯; 햯; ) HANGUL SYLLABLE HYAEGS +D5B0;D5B0;1112 1164 11AB;D5B0;1112 1164 11AB; # (햰; 햰; 햰; 햰; 햰; ) HANGUL SYLLABLE HYAEN +D5B1;D5B1;1112 1164 11AC;D5B1;1112 1164 11AC; # (햱; 햱; 햱; 햱; 햱; ) HANGUL SYLLABLE HYAENJ +D5B2;D5B2;1112 1164 11AD;D5B2;1112 1164 11AD; # (햲; 햲; 햲; 햲; 햲; ) HANGUL SYLLABLE HYAENH +D5B3;D5B3;1112 1164 11AE;D5B3;1112 1164 11AE; # (햳; 햳; 햳; 햳; 햳; ) HANGUL SYLLABLE HYAED +D5B4;D5B4;1112 1164 11AF;D5B4;1112 1164 11AF; # (햴; 햴; 햴; 햴; 햴; ) HANGUL SYLLABLE HYAEL +D5B5;D5B5;1112 1164 11B0;D5B5;1112 1164 11B0; # (햵; 햵; 햵; 햵; 햵; ) HANGUL SYLLABLE HYAELG +D5B6;D5B6;1112 1164 11B1;D5B6;1112 1164 11B1; # (햶; 햶; 햶; 햶; 햶; ) HANGUL SYLLABLE HYAELM +D5B7;D5B7;1112 1164 11B2;D5B7;1112 1164 11B2; # (햷; 햷; 햷; 햷; 햷; ) HANGUL SYLLABLE HYAELB +D5B8;D5B8;1112 1164 11B3;D5B8;1112 1164 11B3; # (햸; 햸; 햸; 햸; 햸; ) HANGUL SYLLABLE HYAELS +D5B9;D5B9;1112 1164 11B4;D5B9;1112 1164 11B4; # (햹; 햹; 햹; 햹; 햹; ) HANGUL SYLLABLE HYAELT +D5BA;D5BA;1112 1164 11B5;D5BA;1112 1164 11B5; # (햺; 햺; 햺; 햺; 햺; ) HANGUL SYLLABLE HYAELP +D5BB;D5BB;1112 1164 11B6;D5BB;1112 1164 11B6; # (햻; 햻; 햻; 햻; 햻; ) HANGUL SYLLABLE HYAELH +D5BC;D5BC;1112 1164 11B7;D5BC;1112 1164 11B7; # (햼; 햼; 햼; 햼; 햼; ) HANGUL SYLLABLE HYAEM +D5BD;D5BD;1112 1164 11B8;D5BD;1112 1164 11B8; # (햽; 햽; 햽; 햽; 햽; ) HANGUL SYLLABLE HYAEB +D5BE;D5BE;1112 1164 11B9;D5BE;1112 1164 11B9; # (햾; 햾; 햾; 햾; 햾; ) HANGUL SYLLABLE HYAEBS +D5BF;D5BF;1112 1164 11BA;D5BF;1112 1164 11BA; # (햿; 햿; 햿; 햿; 햿; ) HANGUL SYLLABLE HYAES +D5C0;D5C0;1112 1164 11BB;D5C0;1112 1164 11BB; # (헀; 헀; 헀; 헀; 헀; ) HANGUL SYLLABLE HYAESS +D5C1;D5C1;1112 1164 11BC;D5C1;1112 1164 11BC; # (헁; 헁; 헁; 헁; 헁; ) HANGUL SYLLABLE HYAENG +D5C2;D5C2;1112 1164 11BD;D5C2;1112 1164 11BD; # (헂; 헂; 헂; 헂; 헂; ) HANGUL SYLLABLE HYAEJ +D5C3;D5C3;1112 1164 11BE;D5C3;1112 1164 11BE; # (헃; 헃; 헃; 헃; 헃; ) HANGUL SYLLABLE HYAEC +D5C4;D5C4;1112 1164 11BF;D5C4;1112 1164 11BF; # (헄; 헄; 헄; 헄; 헄; ) HANGUL SYLLABLE HYAEK +D5C5;D5C5;1112 1164 11C0;D5C5;1112 1164 11C0; # (헅; 헅; 헅; 헅; 헅; ) HANGUL SYLLABLE HYAET +D5C6;D5C6;1112 1164 11C1;D5C6;1112 1164 11C1; # (헆; 헆; 헆; 헆; 헆; ) HANGUL SYLLABLE HYAEP +D5C7;D5C7;1112 1164 11C2;D5C7;1112 1164 11C2; # (헇; 헇; 헇; 헇; 헇; ) HANGUL SYLLABLE HYAEH +D5C8;D5C8;1112 1165;D5C8;1112 1165; # (허; 허; 허; 허; 허; ) HANGUL SYLLABLE HEO +D5C9;D5C9;1112 1165 11A8;D5C9;1112 1165 11A8; # (헉; 헉; 헉; 헉; 헉; ) HANGUL SYLLABLE HEOG +D5CA;D5CA;1112 1165 11A9;D5CA;1112 1165 11A9; # (헊; 헊; 헊; 헊; 헊; ) HANGUL SYLLABLE HEOGG +D5CB;D5CB;1112 1165 11AA;D5CB;1112 1165 11AA; # (헋; 헋; 헋; 헋; 헋; ) HANGUL SYLLABLE HEOGS +D5CC;D5CC;1112 1165 11AB;D5CC;1112 1165 11AB; # (헌; 헌; 헌; 헌; 헌; ) HANGUL SYLLABLE HEON +D5CD;D5CD;1112 1165 11AC;D5CD;1112 1165 11AC; # (헍; 헍; 헍; 헍; 헍; ) HANGUL SYLLABLE HEONJ +D5CE;D5CE;1112 1165 11AD;D5CE;1112 1165 11AD; # (헎; 헎; 헎; 헎; 헎; ) HANGUL SYLLABLE HEONH +D5CF;D5CF;1112 1165 11AE;D5CF;1112 1165 11AE; # (헏; 헏; 헏; 헏; 헏; ) HANGUL SYLLABLE HEOD +D5D0;D5D0;1112 1165 11AF;D5D0;1112 1165 11AF; # (헐; 헐; 헐; 헐; 헐; ) HANGUL SYLLABLE HEOL +D5D1;D5D1;1112 1165 11B0;D5D1;1112 1165 11B0; # (헑; 헑; 헑; 헑; 헑; ) HANGUL SYLLABLE HEOLG +D5D2;D5D2;1112 1165 11B1;D5D2;1112 1165 11B1; # (헒; 헒; 헒; 헒; 헒; ) HANGUL SYLLABLE HEOLM +D5D3;D5D3;1112 1165 11B2;D5D3;1112 1165 11B2; # (헓; 헓; 헓; 헓; 헓; ) HANGUL SYLLABLE HEOLB +D5D4;D5D4;1112 1165 11B3;D5D4;1112 1165 11B3; # (헔; 헔; 헔; 헔; 헔; ) HANGUL SYLLABLE HEOLS +D5D5;D5D5;1112 1165 11B4;D5D5;1112 1165 11B4; # (헕; 헕; 헕; 헕; 헕; ) HANGUL SYLLABLE HEOLT +D5D6;D5D6;1112 1165 11B5;D5D6;1112 1165 11B5; # (헖; 헖; 헖; 헖; 헖; ) HANGUL SYLLABLE HEOLP +D5D7;D5D7;1112 1165 11B6;D5D7;1112 1165 11B6; # (헗; 헗; 헗; 헗; 헗; ) HANGUL SYLLABLE HEOLH +D5D8;D5D8;1112 1165 11B7;D5D8;1112 1165 11B7; # (험; 험; 험; 험; 험; ) HANGUL SYLLABLE HEOM +D5D9;D5D9;1112 1165 11B8;D5D9;1112 1165 11B8; # (헙; 헙; 헙; 헙; 헙; ) HANGUL SYLLABLE HEOB +D5DA;D5DA;1112 1165 11B9;D5DA;1112 1165 11B9; # (헚; 헚; 헚; 헚; 헚; ) HANGUL SYLLABLE HEOBS +D5DB;D5DB;1112 1165 11BA;D5DB;1112 1165 11BA; # (헛; 헛; 헛; 헛; 헛; ) HANGUL SYLLABLE HEOS +D5DC;D5DC;1112 1165 11BB;D5DC;1112 1165 11BB; # (헜; 헜; 헜; 헜; 헜; ) HANGUL SYLLABLE HEOSS +D5DD;D5DD;1112 1165 11BC;D5DD;1112 1165 11BC; # (헝; 헝; 헝; 헝; 헝; ) HANGUL SYLLABLE HEONG +D5DE;D5DE;1112 1165 11BD;D5DE;1112 1165 11BD; # (헞; 헞; 헞; 헞; 헞; ) HANGUL SYLLABLE HEOJ +D5DF;D5DF;1112 1165 11BE;D5DF;1112 1165 11BE; # (헟; 헟; 헟; 헟; 헟; ) HANGUL SYLLABLE HEOC +D5E0;D5E0;1112 1165 11BF;D5E0;1112 1165 11BF; # (헠; 헠; 헠; 헠; 헠; ) HANGUL SYLLABLE HEOK +D5E1;D5E1;1112 1165 11C0;D5E1;1112 1165 11C0; # (헡; 헡; 헡; 헡; 헡; ) HANGUL SYLLABLE HEOT +D5E2;D5E2;1112 1165 11C1;D5E2;1112 1165 11C1; # (헢; 헢; 헢; 헢; 헢; ) HANGUL SYLLABLE HEOP +D5E3;D5E3;1112 1165 11C2;D5E3;1112 1165 11C2; # (헣; 헣; 헣; 헣; 헣; ) HANGUL SYLLABLE HEOH +D5E4;D5E4;1112 1166;D5E4;1112 1166; # (헤; 헤; 헤; 헤; 헤; ) HANGUL SYLLABLE HE +D5E5;D5E5;1112 1166 11A8;D5E5;1112 1166 11A8; # (헥; 헥; 헥; 헥; 헥; ) HANGUL SYLLABLE HEG +D5E6;D5E6;1112 1166 11A9;D5E6;1112 1166 11A9; # (헦; 헦; 헦; 헦; 헦; ) HANGUL SYLLABLE HEGG +D5E7;D5E7;1112 1166 11AA;D5E7;1112 1166 11AA; # (헧; 헧; 헧; 헧; 헧; ) HANGUL SYLLABLE HEGS +D5E8;D5E8;1112 1166 11AB;D5E8;1112 1166 11AB; # (헨; 헨; 헨; 헨; 헨; ) HANGUL SYLLABLE HEN +D5E9;D5E9;1112 1166 11AC;D5E9;1112 1166 11AC; # (헩; 헩; 헩; 헩; 헩; ) HANGUL SYLLABLE HENJ +D5EA;D5EA;1112 1166 11AD;D5EA;1112 1166 11AD; # (헪; 헪; 헪; 헪; 헪; ) HANGUL SYLLABLE HENH +D5EB;D5EB;1112 1166 11AE;D5EB;1112 1166 11AE; # (헫; 헫; 헫; 헫; 헫; ) HANGUL SYLLABLE HED +D5EC;D5EC;1112 1166 11AF;D5EC;1112 1166 11AF; # (헬; 헬; 헬; 헬; 헬; ) HANGUL SYLLABLE HEL +D5ED;D5ED;1112 1166 11B0;D5ED;1112 1166 11B0; # (헭; 헭; 헭; 헭; 헭; ) HANGUL SYLLABLE HELG +D5EE;D5EE;1112 1166 11B1;D5EE;1112 1166 11B1; # (헮; 헮; 헮; 헮; 헮; ) HANGUL SYLLABLE HELM +D5EF;D5EF;1112 1166 11B2;D5EF;1112 1166 11B2; # (헯; 헯; 헯; 헯; 헯; ) HANGUL SYLLABLE HELB +D5F0;D5F0;1112 1166 11B3;D5F0;1112 1166 11B3; # (헰; 헰; 헰; 헰; 헰; ) HANGUL SYLLABLE HELS +D5F1;D5F1;1112 1166 11B4;D5F1;1112 1166 11B4; # (헱; 헱; 헱; 헱; 헱; ) HANGUL SYLLABLE HELT +D5F2;D5F2;1112 1166 11B5;D5F2;1112 1166 11B5; # (헲; 헲; 헲; 헲; 헲; ) HANGUL SYLLABLE HELP +D5F3;D5F3;1112 1166 11B6;D5F3;1112 1166 11B6; # (헳; 헳; 헳; 헳; 헳; ) HANGUL SYLLABLE HELH +D5F4;D5F4;1112 1166 11B7;D5F4;1112 1166 11B7; # (헴; 헴; 헴; 헴; 헴; ) HANGUL SYLLABLE HEM +D5F5;D5F5;1112 1166 11B8;D5F5;1112 1166 11B8; # (헵; 헵; 헵; 헵; 헵; ) HANGUL SYLLABLE HEB +D5F6;D5F6;1112 1166 11B9;D5F6;1112 1166 11B9; # (헶; 헶; 헶; 헶; 헶; ) HANGUL SYLLABLE HEBS +D5F7;D5F7;1112 1166 11BA;D5F7;1112 1166 11BA; # (헷; 헷; 헷; 헷; 헷; ) HANGUL SYLLABLE HES +D5F8;D5F8;1112 1166 11BB;D5F8;1112 1166 11BB; # (헸; 헸; 헸; 헸; 헸; ) HANGUL SYLLABLE HESS +D5F9;D5F9;1112 1166 11BC;D5F9;1112 1166 11BC; # (헹; 헹; 헹; 헹; 헹; ) HANGUL SYLLABLE HENG +D5FA;D5FA;1112 1166 11BD;D5FA;1112 1166 11BD; # (헺; 헺; 헺; 헺; 헺; ) HANGUL SYLLABLE HEJ +D5FB;D5FB;1112 1166 11BE;D5FB;1112 1166 11BE; # (헻; 헻; 헻; 헻; 헻; ) HANGUL SYLLABLE HEC +D5FC;D5FC;1112 1166 11BF;D5FC;1112 1166 11BF; # (헼; 헼; 헼; 헼; 헼; ) HANGUL SYLLABLE HEK +D5FD;D5FD;1112 1166 11C0;D5FD;1112 1166 11C0; # (헽; 헽; 헽; 헽; 헽; ) HANGUL SYLLABLE HET +D5FE;D5FE;1112 1166 11C1;D5FE;1112 1166 11C1; # (헾; 헾; 헾; 헾; 헾; ) HANGUL SYLLABLE HEP +D5FF;D5FF;1112 1166 11C2;D5FF;1112 1166 11C2; # (헿; 헿; 헿; 헿; 헿; ) HANGUL SYLLABLE HEH +D600;D600;1112 1167;D600;1112 1167; # (혀; 혀; 혀; 혀; 혀; ) HANGUL SYLLABLE HYEO +D601;D601;1112 1167 11A8;D601;1112 1167 11A8; # (혁; 혁; 혁; 혁; 혁; ) HANGUL SYLLABLE HYEOG +D602;D602;1112 1167 11A9;D602;1112 1167 11A9; # (혂; 혂; 혂; 혂; 혂; ) HANGUL SYLLABLE HYEOGG +D603;D603;1112 1167 11AA;D603;1112 1167 11AA; # (혃; 혃; 혃; 혃; 혃; ) HANGUL SYLLABLE HYEOGS +D604;D604;1112 1167 11AB;D604;1112 1167 11AB; # (현; 현; 현; 현; 현; ) HANGUL SYLLABLE HYEON +D605;D605;1112 1167 11AC;D605;1112 1167 11AC; # (혅; 혅; 혅; 혅; 혅; ) HANGUL SYLLABLE HYEONJ +D606;D606;1112 1167 11AD;D606;1112 1167 11AD; # (혆; 혆; 혆; 혆; 혆; ) HANGUL SYLLABLE HYEONH +D607;D607;1112 1167 11AE;D607;1112 1167 11AE; # (혇; 혇; 혇; 혇; 혇; ) HANGUL SYLLABLE HYEOD +D608;D608;1112 1167 11AF;D608;1112 1167 11AF; # (혈; 혈; 혈; 혈; 혈; ) HANGUL SYLLABLE HYEOL +D609;D609;1112 1167 11B0;D609;1112 1167 11B0; # (혉; 혉; 혉; 혉; 혉; ) HANGUL SYLLABLE HYEOLG +D60A;D60A;1112 1167 11B1;D60A;1112 1167 11B1; # (혊; 혊; 혊; 혊; 혊; ) HANGUL SYLLABLE HYEOLM +D60B;D60B;1112 1167 11B2;D60B;1112 1167 11B2; # (혋; 혋; 혋; 혋; 혋; ) HANGUL SYLLABLE HYEOLB +D60C;D60C;1112 1167 11B3;D60C;1112 1167 11B3; # (혌; 혌; 혌; 혌; 혌; ) HANGUL SYLLABLE HYEOLS +D60D;D60D;1112 1167 11B4;D60D;1112 1167 11B4; # (혍; 혍; 혍; 혍; 혍; ) HANGUL SYLLABLE HYEOLT +D60E;D60E;1112 1167 11B5;D60E;1112 1167 11B5; # (혎; 혎; 혎; 혎; 혎; ) HANGUL SYLLABLE HYEOLP +D60F;D60F;1112 1167 11B6;D60F;1112 1167 11B6; # (혏; 혏; 혏; 혏; 혏; ) HANGUL SYLLABLE HYEOLH +D610;D610;1112 1167 11B7;D610;1112 1167 11B7; # (혐; 혐; 혐; 혐; 혐; ) HANGUL SYLLABLE HYEOM +D611;D611;1112 1167 11B8;D611;1112 1167 11B8; # (협; 협; 협; 협; 협; ) HANGUL SYLLABLE HYEOB +D612;D612;1112 1167 11B9;D612;1112 1167 11B9; # (혒; 혒; 혒; 혒; 혒; ) HANGUL SYLLABLE HYEOBS +D613;D613;1112 1167 11BA;D613;1112 1167 11BA; # (혓; 혓; 혓; 혓; 혓; ) HANGUL SYLLABLE HYEOS +D614;D614;1112 1167 11BB;D614;1112 1167 11BB; # (혔; 혔; 혔; 혔; 혔; ) HANGUL SYLLABLE HYEOSS +D615;D615;1112 1167 11BC;D615;1112 1167 11BC; # (형; 형; 형; 형; 형; ) HANGUL SYLLABLE HYEONG +D616;D616;1112 1167 11BD;D616;1112 1167 11BD; # (혖; 혖; 혖; 혖; 혖; ) HANGUL SYLLABLE HYEOJ +D617;D617;1112 1167 11BE;D617;1112 1167 11BE; # (혗; 혗; 혗; 혗; 혗; ) HANGUL SYLLABLE HYEOC +D618;D618;1112 1167 11BF;D618;1112 1167 11BF; # (혘; 혘; 혘; 혘; 혘; ) HANGUL SYLLABLE HYEOK +D619;D619;1112 1167 11C0;D619;1112 1167 11C0; # (혙; 혙; 혙; 혙; 혙; ) HANGUL SYLLABLE HYEOT +D61A;D61A;1112 1167 11C1;D61A;1112 1167 11C1; # (혚; 혚; 혚; 혚; 혚; ) HANGUL SYLLABLE HYEOP +D61B;D61B;1112 1167 11C2;D61B;1112 1167 11C2; # (혛; 혛; 혛; 혛; 혛; ) HANGUL SYLLABLE HYEOH +D61C;D61C;1112 1168;D61C;1112 1168; # (혜; 혜; 혜; 혜; 혜; ) HANGUL SYLLABLE HYE +D61D;D61D;1112 1168 11A8;D61D;1112 1168 11A8; # (혝; 혝; 혝; 혝; 혝; ) HANGUL SYLLABLE HYEG +D61E;D61E;1112 1168 11A9;D61E;1112 1168 11A9; # (혞; 혞; 혞; 혞; 혞; ) HANGUL SYLLABLE HYEGG +D61F;D61F;1112 1168 11AA;D61F;1112 1168 11AA; # (혟; 혟; 혟; 혟; 혟; ) HANGUL SYLLABLE HYEGS +D620;D620;1112 1168 11AB;D620;1112 1168 11AB; # (혠; 혠; 혠; 혠; 혠; ) HANGUL SYLLABLE HYEN +D621;D621;1112 1168 11AC;D621;1112 1168 11AC; # (혡; 혡; 혡; 혡; 혡; ) HANGUL SYLLABLE HYENJ +D622;D622;1112 1168 11AD;D622;1112 1168 11AD; # (혢; 혢; 혢; 혢; 혢; ) HANGUL SYLLABLE HYENH +D623;D623;1112 1168 11AE;D623;1112 1168 11AE; # (혣; 혣; 혣; 혣; 혣; ) HANGUL SYLLABLE HYED +D624;D624;1112 1168 11AF;D624;1112 1168 11AF; # (혤; 혤; 혤; 혤; 혤; ) HANGUL SYLLABLE HYEL +D625;D625;1112 1168 11B0;D625;1112 1168 11B0; # (혥; 혥; 혥; 혥; 혥; ) HANGUL SYLLABLE HYELG +D626;D626;1112 1168 11B1;D626;1112 1168 11B1; # (혦; 혦; 혦; 혦; 혦; ) HANGUL SYLLABLE HYELM +D627;D627;1112 1168 11B2;D627;1112 1168 11B2; # (혧; 혧; 혧; 혧; 혧; ) HANGUL SYLLABLE HYELB +D628;D628;1112 1168 11B3;D628;1112 1168 11B3; # (혨; 혨; 혨; 혨; 혨; ) HANGUL SYLLABLE HYELS +D629;D629;1112 1168 11B4;D629;1112 1168 11B4; # (혩; 혩; 혩; 혩; 혩; ) HANGUL SYLLABLE HYELT +D62A;D62A;1112 1168 11B5;D62A;1112 1168 11B5; # (혪; 혪; 혪; 혪; 혪; ) HANGUL SYLLABLE HYELP +D62B;D62B;1112 1168 11B6;D62B;1112 1168 11B6; # (혫; 혫; 혫; 혫; 혫; ) HANGUL SYLLABLE HYELH +D62C;D62C;1112 1168 11B7;D62C;1112 1168 11B7; # (혬; 혬; 혬; 혬; 혬; ) HANGUL SYLLABLE HYEM +D62D;D62D;1112 1168 11B8;D62D;1112 1168 11B8; # (혭; 혭; 혭; 혭; 혭; ) HANGUL SYLLABLE HYEB +D62E;D62E;1112 1168 11B9;D62E;1112 1168 11B9; # (혮; 혮; 혮; 혮; 혮; ) HANGUL SYLLABLE HYEBS +D62F;D62F;1112 1168 11BA;D62F;1112 1168 11BA; # (혯; 혯; 혯; 혯; 혯; ) HANGUL SYLLABLE HYES +D630;D630;1112 1168 11BB;D630;1112 1168 11BB; # (혰; 혰; 혰; 혰; 혰; ) HANGUL SYLLABLE HYESS +D631;D631;1112 1168 11BC;D631;1112 1168 11BC; # (혱; 혱; 혱; 혱; 혱; ) HANGUL SYLLABLE HYENG +D632;D632;1112 1168 11BD;D632;1112 1168 11BD; # (혲; 혲; 혲; 혲; 혲; ) HANGUL SYLLABLE HYEJ +D633;D633;1112 1168 11BE;D633;1112 1168 11BE; # (혳; 혳; 혳; 혳; 혳; ) HANGUL SYLLABLE HYEC +D634;D634;1112 1168 11BF;D634;1112 1168 11BF; # (혴; 혴; 혴; 혴; 혴; ) HANGUL SYLLABLE HYEK +D635;D635;1112 1168 11C0;D635;1112 1168 11C0; # (혵; 혵; 혵; 혵; 혵; ) HANGUL SYLLABLE HYET +D636;D636;1112 1168 11C1;D636;1112 1168 11C1; # (혶; 혶; 혶; 혶; 혶; ) HANGUL SYLLABLE HYEP +D637;D637;1112 1168 11C2;D637;1112 1168 11C2; # (혷; 혷; 혷; 혷; 혷; ) HANGUL SYLLABLE HYEH +D638;D638;1112 1169;D638;1112 1169; # (호; 호; 호; 호; 호; ) HANGUL SYLLABLE HO +D639;D639;1112 1169 11A8;D639;1112 1169 11A8; # (혹; 혹; 혹; 혹; 혹; ) HANGUL SYLLABLE HOG +D63A;D63A;1112 1169 11A9;D63A;1112 1169 11A9; # (혺; 혺; 혺; 혺; 혺; ) HANGUL SYLLABLE HOGG +D63B;D63B;1112 1169 11AA;D63B;1112 1169 11AA; # (혻; 혻; 혻; 혻; 혻; ) HANGUL SYLLABLE HOGS +D63C;D63C;1112 1169 11AB;D63C;1112 1169 11AB; # (혼; 혼; 혼; 혼; 혼; ) HANGUL SYLLABLE HON +D63D;D63D;1112 1169 11AC;D63D;1112 1169 11AC; # (혽; 혽; 혽; 혽; 혽; ) HANGUL SYLLABLE HONJ +D63E;D63E;1112 1169 11AD;D63E;1112 1169 11AD; # (혾; 혾; 혾; 혾; 혾; ) HANGUL SYLLABLE HONH +D63F;D63F;1112 1169 11AE;D63F;1112 1169 11AE; # (혿; 혿; 혿; 혿; 혿; ) HANGUL SYLLABLE HOD +D640;D640;1112 1169 11AF;D640;1112 1169 11AF; # (홀; 홀; 홀; 홀; 홀; ) HANGUL SYLLABLE HOL +D641;D641;1112 1169 11B0;D641;1112 1169 11B0; # (홁; 홁; 홁; 홁; 홁; ) HANGUL SYLLABLE HOLG +D642;D642;1112 1169 11B1;D642;1112 1169 11B1; # (홂; 홂; 홂; 홂; 홂; ) HANGUL SYLLABLE HOLM +D643;D643;1112 1169 11B2;D643;1112 1169 11B2; # (홃; 홃; 홃; 홃; 홃; ) HANGUL SYLLABLE HOLB +D644;D644;1112 1169 11B3;D644;1112 1169 11B3; # (홄; 홄; 홄; 홄; 홄; ) HANGUL SYLLABLE HOLS +D645;D645;1112 1169 11B4;D645;1112 1169 11B4; # (홅; 홅; 홅; 홅; 홅; ) HANGUL SYLLABLE HOLT +D646;D646;1112 1169 11B5;D646;1112 1169 11B5; # (홆; 홆; 홆; 홆; 홆; ) HANGUL SYLLABLE HOLP +D647;D647;1112 1169 11B6;D647;1112 1169 11B6; # (홇; 홇; 홇; 홇; 홇; ) HANGUL SYLLABLE HOLH +D648;D648;1112 1169 11B7;D648;1112 1169 11B7; # (홈; 홈; 홈; 홈; 홈; ) HANGUL SYLLABLE HOM +D649;D649;1112 1169 11B8;D649;1112 1169 11B8; # (홉; 홉; 홉; 홉; 홉; ) HANGUL SYLLABLE HOB +D64A;D64A;1112 1169 11B9;D64A;1112 1169 11B9; # (홊; 홊; 홊; 홊; 홊; ) HANGUL SYLLABLE HOBS +D64B;D64B;1112 1169 11BA;D64B;1112 1169 11BA; # (홋; 홋; 홋; 홋; 홋; ) HANGUL SYLLABLE HOS +D64C;D64C;1112 1169 11BB;D64C;1112 1169 11BB; # (홌; 홌; 홌; 홌; 홌; ) HANGUL SYLLABLE HOSS +D64D;D64D;1112 1169 11BC;D64D;1112 1169 11BC; # (홍; 홍; 홍; 홍; 홍; ) HANGUL SYLLABLE HONG +D64E;D64E;1112 1169 11BD;D64E;1112 1169 11BD; # (홎; 홎; 홎; 홎; 홎; ) HANGUL SYLLABLE HOJ +D64F;D64F;1112 1169 11BE;D64F;1112 1169 11BE; # (홏; 홏; 홏; 홏; 홏; ) HANGUL SYLLABLE HOC +D650;D650;1112 1169 11BF;D650;1112 1169 11BF; # (홐; 홐; 홐; 홐; 홐; ) HANGUL SYLLABLE HOK +D651;D651;1112 1169 11C0;D651;1112 1169 11C0; # (홑; 홑; 홑; 홑; 홑; ) HANGUL SYLLABLE HOT +D652;D652;1112 1169 11C1;D652;1112 1169 11C1; # (홒; 홒; 홒; 홒; 홒; ) HANGUL SYLLABLE HOP +D653;D653;1112 1169 11C2;D653;1112 1169 11C2; # (홓; 홓; 홓; 홓; 홓; ) HANGUL SYLLABLE HOH +D654;D654;1112 116A;D654;1112 116A; # (화; 화; 화; 화; 화; ) HANGUL SYLLABLE HWA +D655;D655;1112 116A 11A8;D655;1112 116A 11A8; # (확; 확; 확; 확; 확; ) HANGUL SYLLABLE HWAG +D656;D656;1112 116A 11A9;D656;1112 116A 11A9; # (홖; 홖; 홖; 홖; 홖; ) HANGUL SYLLABLE HWAGG +D657;D657;1112 116A 11AA;D657;1112 116A 11AA; # (홗; 홗; 홗; 홗; 홗; ) HANGUL SYLLABLE HWAGS +D658;D658;1112 116A 11AB;D658;1112 116A 11AB; # (환; 환; 환; 환; 환; ) HANGUL SYLLABLE HWAN +D659;D659;1112 116A 11AC;D659;1112 116A 11AC; # (홙; 홙; 홙; 홙; 홙; ) HANGUL SYLLABLE HWANJ +D65A;D65A;1112 116A 11AD;D65A;1112 116A 11AD; # (홚; 홚; 홚; 홚; 홚; ) HANGUL SYLLABLE HWANH +D65B;D65B;1112 116A 11AE;D65B;1112 116A 11AE; # (홛; 홛; 홛; 홛; 홛; ) HANGUL SYLLABLE HWAD +D65C;D65C;1112 116A 11AF;D65C;1112 116A 11AF; # (활; 활; 활; 활; 활; ) HANGUL SYLLABLE HWAL +D65D;D65D;1112 116A 11B0;D65D;1112 116A 11B0; # (홝; 홝; 홝; 홝; 홝; ) HANGUL SYLLABLE HWALG +D65E;D65E;1112 116A 11B1;D65E;1112 116A 11B1; # (홞; 홞; 홞; 홞; 홞; ) HANGUL SYLLABLE HWALM +D65F;D65F;1112 116A 11B2;D65F;1112 116A 11B2; # (홟; 홟; 홟; 홟; 홟; ) HANGUL SYLLABLE HWALB +D660;D660;1112 116A 11B3;D660;1112 116A 11B3; # (홠; 홠; 홠; 홠; 홠; ) HANGUL SYLLABLE HWALS +D661;D661;1112 116A 11B4;D661;1112 116A 11B4; # (홡; 홡; 홡; 홡; 홡; ) HANGUL SYLLABLE HWALT +D662;D662;1112 116A 11B5;D662;1112 116A 11B5; # (홢; 홢; 홢; 홢; 홢; ) HANGUL SYLLABLE HWALP +D663;D663;1112 116A 11B6;D663;1112 116A 11B6; # (홣; 홣; 홣; 홣; 홣; ) HANGUL SYLLABLE HWALH +D664;D664;1112 116A 11B7;D664;1112 116A 11B7; # (홤; 홤; 홤; 홤; 홤; ) HANGUL SYLLABLE HWAM +D665;D665;1112 116A 11B8;D665;1112 116A 11B8; # (홥; 홥; 홥; 홥; 홥; ) HANGUL SYLLABLE HWAB +D666;D666;1112 116A 11B9;D666;1112 116A 11B9; # (홦; 홦; 홦; 홦; 홦; ) HANGUL SYLLABLE HWABS +D667;D667;1112 116A 11BA;D667;1112 116A 11BA; # (홧; 홧; 홧; 홧; 홧; ) HANGUL SYLLABLE HWAS +D668;D668;1112 116A 11BB;D668;1112 116A 11BB; # (홨; 홨; 홨; 홨; 홨; ) HANGUL SYLLABLE HWASS +D669;D669;1112 116A 11BC;D669;1112 116A 11BC; # (황; 황; 황; 황; 황; ) HANGUL SYLLABLE HWANG +D66A;D66A;1112 116A 11BD;D66A;1112 116A 11BD; # (홪; 홪; 홪; 홪; 홪; ) HANGUL SYLLABLE HWAJ +D66B;D66B;1112 116A 11BE;D66B;1112 116A 11BE; # (홫; 홫; 홫; 홫; 홫; ) HANGUL SYLLABLE HWAC +D66C;D66C;1112 116A 11BF;D66C;1112 116A 11BF; # (홬; 홬; 홬; 홬; 홬; ) HANGUL SYLLABLE HWAK +D66D;D66D;1112 116A 11C0;D66D;1112 116A 11C0; # (홭; 홭; 홭; 홭; 홭; ) HANGUL SYLLABLE HWAT +D66E;D66E;1112 116A 11C1;D66E;1112 116A 11C1; # (홮; 홮; 홮; 홮; 홮; ) HANGUL SYLLABLE HWAP +D66F;D66F;1112 116A 11C2;D66F;1112 116A 11C2; # (홯; 홯; 홯; 홯; 홯; ) HANGUL SYLLABLE HWAH +D670;D670;1112 116B;D670;1112 116B; # (홰; 홰; 홰; 홰; 홰; ) HANGUL SYLLABLE HWAE +D671;D671;1112 116B 11A8;D671;1112 116B 11A8; # (홱; 홱; 홱; 홱; 홱; ) HANGUL SYLLABLE HWAEG +D672;D672;1112 116B 11A9;D672;1112 116B 11A9; # (홲; 홲; 홲; 홲; 홲; ) HANGUL SYLLABLE HWAEGG +D673;D673;1112 116B 11AA;D673;1112 116B 11AA; # (홳; 홳; 홳; 홳; 홳; ) HANGUL SYLLABLE HWAEGS +D674;D674;1112 116B 11AB;D674;1112 116B 11AB; # (홴; 홴; 홴; 홴; 홴; ) HANGUL SYLLABLE HWAEN +D675;D675;1112 116B 11AC;D675;1112 116B 11AC; # (홵; 홵; 홵; 홵; 홵; ) HANGUL SYLLABLE HWAENJ +D676;D676;1112 116B 11AD;D676;1112 116B 11AD; # (홶; 홶; 홶; 홶; 홶; ) HANGUL SYLLABLE HWAENH +D677;D677;1112 116B 11AE;D677;1112 116B 11AE; # (홷; 홷; 홷; 홷; 홷; ) HANGUL SYLLABLE HWAED +D678;D678;1112 116B 11AF;D678;1112 116B 11AF; # (홸; 홸; 홸; 홸; 홸; ) HANGUL SYLLABLE HWAEL +D679;D679;1112 116B 11B0;D679;1112 116B 11B0; # (홹; 홹; 홹; 홹; 홹; ) HANGUL SYLLABLE HWAELG +D67A;D67A;1112 116B 11B1;D67A;1112 116B 11B1; # (홺; 홺; 홺; 홺; 홺; ) HANGUL SYLLABLE HWAELM +D67B;D67B;1112 116B 11B2;D67B;1112 116B 11B2; # (홻; 홻; 홻; 홻; 홻; ) HANGUL SYLLABLE HWAELB +D67C;D67C;1112 116B 11B3;D67C;1112 116B 11B3; # (홼; 홼; 홼; 홼; 홼; ) HANGUL SYLLABLE HWAELS +D67D;D67D;1112 116B 11B4;D67D;1112 116B 11B4; # (홽; 홽; 홽; 홽; 홽; ) HANGUL SYLLABLE HWAELT +D67E;D67E;1112 116B 11B5;D67E;1112 116B 11B5; # (홾; 홾; 홾; 홾; 홾; ) HANGUL SYLLABLE HWAELP +D67F;D67F;1112 116B 11B6;D67F;1112 116B 11B6; # (홿; 홿; 홿; 홿; 홿; ) HANGUL SYLLABLE HWAELH +D680;D680;1112 116B 11B7;D680;1112 116B 11B7; # (횀; 횀; 횀; 횀; 횀; ) HANGUL SYLLABLE HWAEM +D681;D681;1112 116B 11B8;D681;1112 116B 11B8; # (횁; 횁; 횁; 횁; 횁; ) HANGUL SYLLABLE HWAEB +D682;D682;1112 116B 11B9;D682;1112 116B 11B9; # (횂; 횂; 횂; 횂; 횂; ) HANGUL SYLLABLE HWAEBS +D683;D683;1112 116B 11BA;D683;1112 116B 11BA; # (횃; 횃; 횃; 횃; 횃; ) HANGUL SYLLABLE HWAES +D684;D684;1112 116B 11BB;D684;1112 116B 11BB; # (횄; 횄; 횄; 횄; 횄; ) HANGUL SYLLABLE HWAESS +D685;D685;1112 116B 11BC;D685;1112 116B 11BC; # (횅; 횅; 횅; 횅; 횅; ) HANGUL SYLLABLE HWAENG +D686;D686;1112 116B 11BD;D686;1112 116B 11BD; # (횆; 횆; 횆; 횆; 횆; ) HANGUL SYLLABLE HWAEJ +D687;D687;1112 116B 11BE;D687;1112 116B 11BE; # (횇; 횇; 횇; 횇; 횇; ) HANGUL SYLLABLE HWAEC +D688;D688;1112 116B 11BF;D688;1112 116B 11BF; # (횈; 횈; 횈; 횈; 횈; ) HANGUL SYLLABLE HWAEK +D689;D689;1112 116B 11C0;D689;1112 116B 11C0; # (횉; 횉; 횉; 횉; 횉; ) HANGUL SYLLABLE HWAET +D68A;D68A;1112 116B 11C1;D68A;1112 116B 11C1; # (횊; 횊; 횊; 횊; 횊; ) HANGUL SYLLABLE HWAEP +D68B;D68B;1112 116B 11C2;D68B;1112 116B 11C2; # (횋; 횋; 횋; 횋; 횋; ) HANGUL SYLLABLE HWAEH +D68C;D68C;1112 116C;D68C;1112 116C; # (회; 회; 회; 회; 회; ) HANGUL SYLLABLE HOE +D68D;D68D;1112 116C 11A8;D68D;1112 116C 11A8; # (획; 획; 획; 획; 획; ) HANGUL SYLLABLE HOEG +D68E;D68E;1112 116C 11A9;D68E;1112 116C 11A9; # (횎; 횎; 횎; 횎; 횎; ) HANGUL SYLLABLE HOEGG +D68F;D68F;1112 116C 11AA;D68F;1112 116C 11AA; # (횏; 횏; 횏; 횏; 횏; ) HANGUL SYLLABLE HOEGS +D690;D690;1112 116C 11AB;D690;1112 116C 11AB; # (횐; 횐; 횐; 횐; 횐; ) HANGUL SYLLABLE HOEN +D691;D691;1112 116C 11AC;D691;1112 116C 11AC; # (횑; 횑; 횑; 횑; 횑; ) HANGUL SYLLABLE HOENJ +D692;D692;1112 116C 11AD;D692;1112 116C 11AD; # (횒; 횒; 횒; 횒; 횒; ) HANGUL SYLLABLE HOENH +D693;D693;1112 116C 11AE;D693;1112 116C 11AE; # (횓; 횓; 횓; 횓; 횓; ) HANGUL SYLLABLE HOED +D694;D694;1112 116C 11AF;D694;1112 116C 11AF; # (횔; 횔; 횔; 횔; 횔; ) HANGUL SYLLABLE HOEL +D695;D695;1112 116C 11B0;D695;1112 116C 11B0; # (횕; 횕; 횕; 횕; 횕; ) HANGUL SYLLABLE HOELG +D696;D696;1112 116C 11B1;D696;1112 116C 11B1; # (횖; 횖; 횖; 횖; 횖; ) HANGUL SYLLABLE HOELM +D697;D697;1112 116C 11B2;D697;1112 116C 11B2; # (횗; 횗; 횗; 횗; 횗; ) HANGUL SYLLABLE HOELB +D698;D698;1112 116C 11B3;D698;1112 116C 11B3; # (횘; 횘; 횘; 횘; 횘; ) HANGUL SYLLABLE HOELS +D699;D699;1112 116C 11B4;D699;1112 116C 11B4; # (횙; 횙; 횙; 횙; 횙; ) HANGUL SYLLABLE HOELT +D69A;D69A;1112 116C 11B5;D69A;1112 116C 11B5; # (횚; 횚; 횚; 횚; 횚; ) HANGUL SYLLABLE HOELP +D69B;D69B;1112 116C 11B6;D69B;1112 116C 11B6; # (횛; 횛; 횛; 횛; 횛; ) HANGUL SYLLABLE HOELH +D69C;D69C;1112 116C 11B7;D69C;1112 116C 11B7; # (횜; 횜; 횜; 횜; 횜; ) HANGUL SYLLABLE HOEM +D69D;D69D;1112 116C 11B8;D69D;1112 116C 11B8; # (횝; 횝; 횝; 횝; 횝; ) HANGUL SYLLABLE HOEB +D69E;D69E;1112 116C 11B9;D69E;1112 116C 11B9; # (횞; 횞; 횞; 횞; 횞; ) HANGUL SYLLABLE HOEBS +D69F;D69F;1112 116C 11BA;D69F;1112 116C 11BA; # (횟; 횟; 횟; 횟; 횟; ) HANGUL SYLLABLE HOES +D6A0;D6A0;1112 116C 11BB;D6A0;1112 116C 11BB; # (횠; 횠; 횠; 횠; 횠; ) HANGUL SYLLABLE HOESS +D6A1;D6A1;1112 116C 11BC;D6A1;1112 116C 11BC; # (횡; 횡; 횡; 횡; 횡; ) HANGUL SYLLABLE HOENG +D6A2;D6A2;1112 116C 11BD;D6A2;1112 116C 11BD; # (횢; 횢; 횢; 횢; 횢; ) HANGUL SYLLABLE HOEJ +D6A3;D6A3;1112 116C 11BE;D6A3;1112 116C 11BE; # (횣; 횣; 횣; 횣; 횣; ) HANGUL SYLLABLE HOEC +D6A4;D6A4;1112 116C 11BF;D6A4;1112 116C 11BF; # (횤; 횤; 횤; 횤; 횤; ) HANGUL SYLLABLE HOEK +D6A5;D6A5;1112 116C 11C0;D6A5;1112 116C 11C0; # (횥; 횥; 횥; 횥; 횥; ) HANGUL SYLLABLE HOET +D6A6;D6A6;1112 116C 11C1;D6A6;1112 116C 11C1; # (횦; 횦; 횦; 횦; 횦; ) HANGUL SYLLABLE HOEP +D6A7;D6A7;1112 116C 11C2;D6A7;1112 116C 11C2; # (횧; 횧; 횧; 횧; 횧; ) HANGUL SYLLABLE HOEH +D6A8;D6A8;1112 116D;D6A8;1112 116D; # (효; 효; 효; 효; 효; ) HANGUL SYLLABLE HYO +D6A9;D6A9;1112 116D 11A8;D6A9;1112 116D 11A8; # (횩; 횩; 횩; 횩; 횩; ) HANGUL SYLLABLE HYOG +D6AA;D6AA;1112 116D 11A9;D6AA;1112 116D 11A9; # (횪; 횪; 횪; 횪; 횪; ) HANGUL SYLLABLE HYOGG +D6AB;D6AB;1112 116D 11AA;D6AB;1112 116D 11AA; # (횫; 횫; 횫; 횫; 횫; ) HANGUL SYLLABLE HYOGS +D6AC;D6AC;1112 116D 11AB;D6AC;1112 116D 11AB; # (횬; 횬; 횬; 횬; 횬; ) HANGUL SYLLABLE HYON +D6AD;D6AD;1112 116D 11AC;D6AD;1112 116D 11AC; # (횭; 횭; 횭; 횭; 횭; ) HANGUL SYLLABLE HYONJ +D6AE;D6AE;1112 116D 11AD;D6AE;1112 116D 11AD; # (횮; 횮; 횮; 횮; 횮; ) HANGUL SYLLABLE HYONH +D6AF;D6AF;1112 116D 11AE;D6AF;1112 116D 11AE; # (횯; 횯; 횯; 횯; 횯; ) HANGUL SYLLABLE HYOD +D6B0;D6B0;1112 116D 11AF;D6B0;1112 116D 11AF; # (횰; 횰; 횰; 횰; 횰; ) HANGUL SYLLABLE HYOL +D6B1;D6B1;1112 116D 11B0;D6B1;1112 116D 11B0; # (횱; 횱; 횱; 횱; 횱; ) HANGUL SYLLABLE HYOLG +D6B2;D6B2;1112 116D 11B1;D6B2;1112 116D 11B1; # (횲; 횲; 횲; 횲; 횲; ) HANGUL SYLLABLE HYOLM +D6B3;D6B3;1112 116D 11B2;D6B3;1112 116D 11B2; # (횳; 횳; 횳; 횳; 횳; ) HANGUL SYLLABLE HYOLB +D6B4;D6B4;1112 116D 11B3;D6B4;1112 116D 11B3; # (횴; 횴; 횴; 횴; 횴; ) HANGUL SYLLABLE HYOLS +D6B5;D6B5;1112 116D 11B4;D6B5;1112 116D 11B4; # (횵; 횵; 횵; 횵; 횵; ) HANGUL SYLLABLE HYOLT +D6B6;D6B6;1112 116D 11B5;D6B6;1112 116D 11B5; # (횶; 횶; 횶; 횶; 횶; ) HANGUL SYLLABLE HYOLP +D6B7;D6B7;1112 116D 11B6;D6B7;1112 116D 11B6; # (횷; 횷; 횷; 횷; 횷; ) HANGUL SYLLABLE HYOLH +D6B8;D6B8;1112 116D 11B7;D6B8;1112 116D 11B7; # (횸; 횸; 횸; 횸; 횸; ) HANGUL SYLLABLE HYOM +D6B9;D6B9;1112 116D 11B8;D6B9;1112 116D 11B8; # (횹; 횹; 횹; 횹; 횹; ) HANGUL SYLLABLE HYOB +D6BA;D6BA;1112 116D 11B9;D6BA;1112 116D 11B9; # (횺; 횺; 횺; 횺; 횺; ) HANGUL SYLLABLE HYOBS +D6BB;D6BB;1112 116D 11BA;D6BB;1112 116D 11BA; # (횻; 횻; 횻; 횻; 횻; ) HANGUL SYLLABLE HYOS +D6BC;D6BC;1112 116D 11BB;D6BC;1112 116D 11BB; # (횼; 횼; 횼; 횼; 횼; ) HANGUL SYLLABLE HYOSS +D6BD;D6BD;1112 116D 11BC;D6BD;1112 116D 11BC; # (횽; 횽; 횽; 횽; 횽; ) HANGUL SYLLABLE HYONG +D6BE;D6BE;1112 116D 11BD;D6BE;1112 116D 11BD; # (횾; 횾; 횾; 횾; 횾; ) HANGUL SYLLABLE HYOJ +D6BF;D6BF;1112 116D 11BE;D6BF;1112 116D 11BE; # (횿; 횿; 횿; 횿; 횿; ) HANGUL SYLLABLE HYOC +D6C0;D6C0;1112 116D 11BF;D6C0;1112 116D 11BF; # (훀; 훀; 훀; 훀; 훀; ) HANGUL SYLLABLE HYOK +D6C1;D6C1;1112 116D 11C0;D6C1;1112 116D 11C0; # (훁; 훁; 훁; 훁; 훁; ) HANGUL SYLLABLE HYOT +D6C2;D6C2;1112 116D 11C1;D6C2;1112 116D 11C1; # (훂; 훂; 훂; 훂; 훂; ) HANGUL SYLLABLE HYOP +D6C3;D6C3;1112 116D 11C2;D6C3;1112 116D 11C2; # (훃; 훃; 훃; 훃; 훃; ) HANGUL SYLLABLE HYOH +D6C4;D6C4;1112 116E;D6C4;1112 116E; # (후; 후; 후; 후; 후; ) HANGUL SYLLABLE HU +D6C5;D6C5;1112 116E 11A8;D6C5;1112 116E 11A8; # (훅; 훅; 훅; 훅; 훅; ) HANGUL SYLLABLE HUG +D6C6;D6C6;1112 116E 11A9;D6C6;1112 116E 11A9; # (훆; 훆; 훆; 훆; 훆; ) HANGUL SYLLABLE HUGG +D6C7;D6C7;1112 116E 11AA;D6C7;1112 116E 11AA; # (훇; 훇; 훇; 훇; 훇; ) HANGUL SYLLABLE HUGS +D6C8;D6C8;1112 116E 11AB;D6C8;1112 116E 11AB; # (훈; 훈; 훈; 훈; 훈; ) HANGUL SYLLABLE HUN +D6C9;D6C9;1112 116E 11AC;D6C9;1112 116E 11AC; # (훉; 훉; 훉; 훉; 훉; ) HANGUL SYLLABLE HUNJ +D6CA;D6CA;1112 116E 11AD;D6CA;1112 116E 11AD; # (훊; 훊; 훊; 훊; 훊; ) HANGUL SYLLABLE HUNH +D6CB;D6CB;1112 116E 11AE;D6CB;1112 116E 11AE; # (훋; 훋; 훋; 훋; 훋; ) HANGUL SYLLABLE HUD +D6CC;D6CC;1112 116E 11AF;D6CC;1112 116E 11AF; # (훌; 훌; 훌; 훌; 훌; ) HANGUL SYLLABLE HUL +D6CD;D6CD;1112 116E 11B0;D6CD;1112 116E 11B0; # (훍; 훍; 훍; 훍; 훍; ) HANGUL SYLLABLE HULG +D6CE;D6CE;1112 116E 11B1;D6CE;1112 116E 11B1; # (훎; 훎; 훎; 훎; 훎; ) HANGUL SYLLABLE HULM +D6CF;D6CF;1112 116E 11B2;D6CF;1112 116E 11B2; # (훏; 훏; 훏; 훏; 훏; ) HANGUL SYLLABLE HULB +D6D0;D6D0;1112 116E 11B3;D6D0;1112 116E 11B3; # (훐; 훐; 훐; 훐; 훐; ) HANGUL SYLLABLE HULS +D6D1;D6D1;1112 116E 11B4;D6D1;1112 116E 11B4; # (훑; 훑; 훑; 훑; 훑; ) HANGUL SYLLABLE HULT +D6D2;D6D2;1112 116E 11B5;D6D2;1112 116E 11B5; # (훒; 훒; 훒; 훒; 훒; ) HANGUL SYLLABLE HULP +D6D3;D6D3;1112 116E 11B6;D6D3;1112 116E 11B6; # (훓; 훓; 훓; 훓; 훓; ) HANGUL SYLLABLE HULH +D6D4;D6D4;1112 116E 11B7;D6D4;1112 116E 11B7; # (훔; 훔; 훔; 훔; 훔; ) HANGUL SYLLABLE HUM +D6D5;D6D5;1112 116E 11B8;D6D5;1112 116E 11B8; # (훕; 훕; 훕; 훕; 훕; ) HANGUL SYLLABLE HUB +D6D6;D6D6;1112 116E 11B9;D6D6;1112 116E 11B9; # (훖; 훖; 훖; 훖; 훖; ) HANGUL SYLLABLE HUBS +D6D7;D6D7;1112 116E 11BA;D6D7;1112 116E 11BA; # (훗; 훗; 훗; 훗; 훗; ) HANGUL SYLLABLE HUS +D6D8;D6D8;1112 116E 11BB;D6D8;1112 116E 11BB; # (훘; 훘; 훘; 훘; 훘; ) HANGUL SYLLABLE HUSS +D6D9;D6D9;1112 116E 11BC;D6D9;1112 116E 11BC; # (훙; 훙; 훙; 훙; 훙; ) HANGUL SYLLABLE HUNG +D6DA;D6DA;1112 116E 11BD;D6DA;1112 116E 11BD; # (훚; 훚; 훚; 훚; 훚; ) HANGUL SYLLABLE HUJ +D6DB;D6DB;1112 116E 11BE;D6DB;1112 116E 11BE; # (훛; 훛; 훛; 훛; 훛; ) HANGUL SYLLABLE HUC +D6DC;D6DC;1112 116E 11BF;D6DC;1112 116E 11BF; # (훜; 훜; 훜; 훜; 훜; ) HANGUL SYLLABLE HUK +D6DD;D6DD;1112 116E 11C0;D6DD;1112 116E 11C0; # (훝; 훝; 훝; 훝; 훝; ) HANGUL SYLLABLE HUT +D6DE;D6DE;1112 116E 11C1;D6DE;1112 116E 11C1; # (훞; 훞; 훞; 훞; 훞; ) HANGUL SYLLABLE HUP +D6DF;D6DF;1112 116E 11C2;D6DF;1112 116E 11C2; # (훟; 훟; 훟; 훟; 훟; ) HANGUL SYLLABLE HUH +D6E0;D6E0;1112 116F;D6E0;1112 116F; # (훠; 훠; 훠; 훠; 훠; ) HANGUL SYLLABLE HWEO +D6E1;D6E1;1112 116F 11A8;D6E1;1112 116F 11A8; # (훡; 훡; 훡; 훡; 훡; ) HANGUL SYLLABLE HWEOG +D6E2;D6E2;1112 116F 11A9;D6E2;1112 116F 11A9; # (훢; 훢; 훢; 훢; 훢; ) HANGUL SYLLABLE HWEOGG +D6E3;D6E3;1112 116F 11AA;D6E3;1112 116F 11AA; # (훣; 훣; 훣; 훣; 훣; ) HANGUL SYLLABLE HWEOGS +D6E4;D6E4;1112 116F 11AB;D6E4;1112 116F 11AB; # (훤; 훤; 훤; 훤; 훤; ) HANGUL SYLLABLE HWEON +D6E5;D6E5;1112 116F 11AC;D6E5;1112 116F 11AC; # (훥; 훥; 훥; 훥; 훥; ) HANGUL SYLLABLE HWEONJ +D6E6;D6E6;1112 116F 11AD;D6E6;1112 116F 11AD; # (훦; 훦; 훦; 훦; 훦; ) HANGUL SYLLABLE HWEONH +D6E7;D6E7;1112 116F 11AE;D6E7;1112 116F 11AE; # (훧; 훧; 훧; 훧; 훧; ) HANGUL SYLLABLE HWEOD +D6E8;D6E8;1112 116F 11AF;D6E8;1112 116F 11AF; # (훨; 훨; 훨; 훨; 훨; ) HANGUL SYLLABLE HWEOL +D6E9;D6E9;1112 116F 11B0;D6E9;1112 116F 11B0; # (훩; 훩; 훩; 훩; 훩; ) HANGUL SYLLABLE HWEOLG +D6EA;D6EA;1112 116F 11B1;D6EA;1112 116F 11B1; # (훪; 훪; 훪; 훪; 훪; ) HANGUL SYLLABLE HWEOLM +D6EB;D6EB;1112 116F 11B2;D6EB;1112 116F 11B2; # (훫; 훫; 훫; 훫; 훫; ) HANGUL SYLLABLE HWEOLB +D6EC;D6EC;1112 116F 11B3;D6EC;1112 116F 11B3; # (훬; 훬; 훬; 훬; 훬; ) HANGUL SYLLABLE HWEOLS +D6ED;D6ED;1112 116F 11B4;D6ED;1112 116F 11B4; # (훭; 훭; 훭; 훭; 훭; ) HANGUL SYLLABLE HWEOLT +D6EE;D6EE;1112 116F 11B5;D6EE;1112 116F 11B5; # (훮; 훮; 훮; 훮; 훮; ) HANGUL SYLLABLE HWEOLP +D6EF;D6EF;1112 116F 11B6;D6EF;1112 116F 11B6; # (훯; 훯; 훯; 훯; 훯; ) HANGUL SYLLABLE HWEOLH +D6F0;D6F0;1112 116F 11B7;D6F0;1112 116F 11B7; # (훰; 훰; 훰; 훰; 훰; ) HANGUL SYLLABLE HWEOM +D6F1;D6F1;1112 116F 11B8;D6F1;1112 116F 11B8; # (훱; 훱; 훱; 훱; 훱; ) HANGUL SYLLABLE HWEOB +D6F2;D6F2;1112 116F 11B9;D6F2;1112 116F 11B9; # (훲; 훲; 훲; 훲; 훲; ) HANGUL SYLLABLE HWEOBS +D6F3;D6F3;1112 116F 11BA;D6F3;1112 116F 11BA; # (훳; 훳; 훳; 훳; 훳; ) HANGUL SYLLABLE HWEOS +D6F4;D6F4;1112 116F 11BB;D6F4;1112 116F 11BB; # (훴; 훴; 훴; 훴; 훴; ) HANGUL SYLLABLE HWEOSS +D6F5;D6F5;1112 116F 11BC;D6F5;1112 116F 11BC; # (훵; 훵; 훵; 훵; 훵; ) HANGUL SYLLABLE HWEONG +D6F6;D6F6;1112 116F 11BD;D6F6;1112 116F 11BD; # (훶; 훶; 훶; 훶; 훶; ) HANGUL SYLLABLE HWEOJ +D6F7;D6F7;1112 116F 11BE;D6F7;1112 116F 11BE; # (훷; 훷; 훷; 훷; 훷; ) HANGUL SYLLABLE HWEOC +D6F8;D6F8;1112 116F 11BF;D6F8;1112 116F 11BF; # (훸; 훸; 훸; 훸; 훸; ) HANGUL SYLLABLE HWEOK +D6F9;D6F9;1112 116F 11C0;D6F9;1112 116F 11C0; # (훹; 훹; 훹; 훹; 훹; ) HANGUL SYLLABLE HWEOT +D6FA;D6FA;1112 116F 11C1;D6FA;1112 116F 11C1; # (훺; 훺; 훺; 훺; 훺; ) HANGUL SYLLABLE HWEOP +D6FB;D6FB;1112 116F 11C2;D6FB;1112 116F 11C2; # (훻; 훻; 훻; 훻; 훻; ) HANGUL SYLLABLE HWEOH +D6FC;D6FC;1112 1170;D6FC;1112 1170; # (훼; 훼; 훼; 훼; 훼; ) HANGUL SYLLABLE HWE +D6FD;D6FD;1112 1170 11A8;D6FD;1112 1170 11A8; # (훽; 훽; 훽; 훽; 훽; ) HANGUL SYLLABLE HWEG +D6FE;D6FE;1112 1170 11A9;D6FE;1112 1170 11A9; # (훾; 훾; 훾; 훾; 훾; ) HANGUL SYLLABLE HWEGG +D6FF;D6FF;1112 1170 11AA;D6FF;1112 1170 11AA; # (훿; 훿; 훿; 훿; 훿; ) HANGUL SYLLABLE HWEGS +D700;D700;1112 1170 11AB;D700;1112 1170 11AB; # (휀; 휀; 휀; 휀; 휀; ) HANGUL SYLLABLE HWEN +D701;D701;1112 1170 11AC;D701;1112 1170 11AC; # (휁; 휁; 휁; 휁; 휁; ) HANGUL SYLLABLE HWENJ +D702;D702;1112 1170 11AD;D702;1112 1170 11AD; # (휂; 휂; 휂; 휂; 휂; ) HANGUL SYLLABLE HWENH +D703;D703;1112 1170 11AE;D703;1112 1170 11AE; # (휃; 휃; 휃; 휃; 휃; ) HANGUL SYLLABLE HWED +D704;D704;1112 1170 11AF;D704;1112 1170 11AF; # (휄; 휄; 휄; 휄; 휄; ) HANGUL SYLLABLE HWEL +D705;D705;1112 1170 11B0;D705;1112 1170 11B0; # (휅; 휅; 휅; 휅; 휅; ) HANGUL SYLLABLE HWELG +D706;D706;1112 1170 11B1;D706;1112 1170 11B1; # (휆; 휆; 휆; 휆; 휆; ) HANGUL SYLLABLE HWELM +D707;D707;1112 1170 11B2;D707;1112 1170 11B2; # (휇; 휇; 휇; 휇; 휇; ) HANGUL SYLLABLE HWELB +D708;D708;1112 1170 11B3;D708;1112 1170 11B3; # (휈; 휈; 휈; 휈; 휈; ) HANGUL SYLLABLE HWELS +D709;D709;1112 1170 11B4;D709;1112 1170 11B4; # (휉; 휉; 휉; 휉; 휉; ) HANGUL SYLLABLE HWELT +D70A;D70A;1112 1170 11B5;D70A;1112 1170 11B5; # (휊; 휊; 휊; 휊; 휊; ) HANGUL SYLLABLE HWELP +D70B;D70B;1112 1170 11B6;D70B;1112 1170 11B6; # (휋; 휋; 휋; 휋; 휋; ) HANGUL SYLLABLE HWELH +D70C;D70C;1112 1170 11B7;D70C;1112 1170 11B7; # (휌; 휌; 휌; 휌; 휌; ) HANGUL SYLLABLE HWEM +D70D;D70D;1112 1170 11B8;D70D;1112 1170 11B8; # (휍; 휍; 휍; 휍; 휍; ) HANGUL SYLLABLE HWEB +D70E;D70E;1112 1170 11B9;D70E;1112 1170 11B9; # (휎; 휎; 휎; 휎; 휎; ) HANGUL SYLLABLE HWEBS +D70F;D70F;1112 1170 11BA;D70F;1112 1170 11BA; # (휏; 휏; 휏; 휏; 휏; ) HANGUL SYLLABLE HWES +D710;D710;1112 1170 11BB;D710;1112 1170 11BB; # (휐; 휐; 휐; 휐; 휐; ) HANGUL SYLLABLE HWESS +D711;D711;1112 1170 11BC;D711;1112 1170 11BC; # (휑; 휑; 휑; 휑; 휑; ) HANGUL SYLLABLE HWENG +D712;D712;1112 1170 11BD;D712;1112 1170 11BD; # (휒; 휒; 휒; 휒; 휒; ) HANGUL SYLLABLE HWEJ +D713;D713;1112 1170 11BE;D713;1112 1170 11BE; # (휓; 휓; 휓; 휓; 휓; ) HANGUL SYLLABLE HWEC +D714;D714;1112 1170 11BF;D714;1112 1170 11BF; # (휔; 휔; 휔; 휔; 휔; ) HANGUL SYLLABLE HWEK +D715;D715;1112 1170 11C0;D715;1112 1170 11C0; # (휕; 휕; 휕; 휕; 휕; ) HANGUL SYLLABLE HWET +D716;D716;1112 1170 11C1;D716;1112 1170 11C1; # (휖; 휖; 휖; 휖; 휖; ) HANGUL SYLLABLE HWEP +D717;D717;1112 1170 11C2;D717;1112 1170 11C2; # (휗; 휗; 휗; 휗; 휗; ) HANGUL SYLLABLE HWEH +D718;D718;1112 1171;D718;1112 1171; # (휘; 휘; 휘; 휘; 휘; ) HANGUL SYLLABLE HWI +D719;D719;1112 1171 11A8;D719;1112 1171 11A8; # (휙; 휙; 휙; 휙; 휙; ) HANGUL SYLLABLE HWIG +D71A;D71A;1112 1171 11A9;D71A;1112 1171 11A9; # (휚; 휚; 휚; 휚; 휚; ) HANGUL SYLLABLE HWIGG +D71B;D71B;1112 1171 11AA;D71B;1112 1171 11AA; # (휛; 휛; 휛; 휛; 휛; ) HANGUL SYLLABLE HWIGS +D71C;D71C;1112 1171 11AB;D71C;1112 1171 11AB; # (휜; 휜; 휜; 휜; 휜; ) HANGUL SYLLABLE HWIN +D71D;D71D;1112 1171 11AC;D71D;1112 1171 11AC; # (휝; 휝; 휝; 휝; 휝; ) HANGUL SYLLABLE HWINJ +D71E;D71E;1112 1171 11AD;D71E;1112 1171 11AD; # (휞; 휞; 휞; 휞; 휞; ) HANGUL SYLLABLE HWINH +D71F;D71F;1112 1171 11AE;D71F;1112 1171 11AE; # (휟; 휟; 휟; 휟; 휟; ) HANGUL SYLLABLE HWID +D720;D720;1112 1171 11AF;D720;1112 1171 11AF; # (휠; 휠; 휠; 휠; 휠; ) HANGUL SYLLABLE HWIL +D721;D721;1112 1171 11B0;D721;1112 1171 11B0; # (휡; 휡; 휡; 휡; 휡; ) HANGUL SYLLABLE HWILG +D722;D722;1112 1171 11B1;D722;1112 1171 11B1; # (휢; 휢; 휢; 휢; 휢; ) HANGUL SYLLABLE HWILM +D723;D723;1112 1171 11B2;D723;1112 1171 11B2; # (휣; 휣; 휣; 휣; 휣; ) HANGUL SYLLABLE HWILB +D724;D724;1112 1171 11B3;D724;1112 1171 11B3; # (휤; 휤; 휤; 휤; 휤; ) HANGUL SYLLABLE HWILS +D725;D725;1112 1171 11B4;D725;1112 1171 11B4; # (휥; 휥; 휥; 휥; 휥; ) HANGUL SYLLABLE HWILT +D726;D726;1112 1171 11B5;D726;1112 1171 11B5; # (휦; 휦; 휦; 휦; 휦; ) HANGUL SYLLABLE HWILP +D727;D727;1112 1171 11B6;D727;1112 1171 11B6; # (휧; 휧; 휧; 휧; 휧; ) HANGUL SYLLABLE HWILH +D728;D728;1112 1171 11B7;D728;1112 1171 11B7; # (휨; 휨; 휨; 휨; 휨; ) HANGUL SYLLABLE HWIM +D729;D729;1112 1171 11B8;D729;1112 1171 11B8; # (휩; 휩; 휩; 휩; 휩; ) HANGUL SYLLABLE HWIB +D72A;D72A;1112 1171 11B9;D72A;1112 1171 11B9; # (휪; 휪; 휪; 휪; 휪; ) HANGUL SYLLABLE HWIBS +D72B;D72B;1112 1171 11BA;D72B;1112 1171 11BA; # (휫; 휫; 휫; 휫; 휫; ) HANGUL SYLLABLE HWIS +D72C;D72C;1112 1171 11BB;D72C;1112 1171 11BB; # (휬; 휬; 휬; 휬; 휬; ) HANGUL SYLLABLE HWISS +D72D;D72D;1112 1171 11BC;D72D;1112 1171 11BC; # (휭; 휭; 휭; 휭; 휭; ) HANGUL SYLLABLE HWING +D72E;D72E;1112 1171 11BD;D72E;1112 1171 11BD; # (휮; 휮; 휮; 휮; 휮; ) HANGUL SYLLABLE HWIJ +D72F;D72F;1112 1171 11BE;D72F;1112 1171 11BE; # (휯; 휯; 휯; 휯; 휯; ) HANGUL SYLLABLE HWIC +D730;D730;1112 1171 11BF;D730;1112 1171 11BF; # (휰; 휰; 휰; 휰; 휰; ) HANGUL SYLLABLE HWIK +D731;D731;1112 1171 11C0;D731;1112 1171 11C0; # (휱; 휱; 휱; 휱; 휱; ) HANGUL SYLLABLE HWIT +D732;D732;1112 1171 11C1;D732;1112 1171 11C1; # (휲; 휲; 휲; 휲; 휲; ) HANGUL SYLLABLE HWIP +D733;D733;1112 1171 11C2;D733;1112 1171 11C2; # (휳; 휳; 휳; 휳; 휳; ) HANGUL SYLLABLE HWIH +D734;D734;1112 1172;D734;1112 1172; # (휴; 휴; 휴; 휴; 휴; ) HANGUL SYLLABLE HYU +D735;D735;1112 1172 11A8;D735;1112 1172 11A8; # (휵; 휵; 휵; 휵; 휵; ) HANGUL SYLLABLE HYUG +D736;D736;1112 1172 11A9;D736;1112 1172 11A9; # (휶; 휶; 휶; 휶; 휶; ) HANGUL SYLLABLE HYUGG +D737;D737;1112 1172 11AA;D737;1112 1172 11AA; # (휷; 휷; 휷; 휷; 휷; ) HANGUL SYLLABLE HYUGS +D738;D738;1112 1172 11AB;D738;1112 1172 11AB; # (휸; 휸; 휸; 휸; 휸; ) HANGUL SYLLABLE HYUN +D739;D739;1112 1172 11AC;D739;1112 1172 11AC; # (휹; 휹; 휹; 휹; 휹; ) HANGUL SYLLABLE HYUNJ +D73A;D73A;1112 1172 11AD;D73A;1112 1172 11AD; # (휺; 휺; 휺; 휺; 휺; ) HANGUL SYLLABLE HYUNH +D73B;D73B;1112 1172 11AE;D73B;1112 1172 11AE; # (휻; 휻; 휻; 휻; 휻; ) HANGUL SYLLABLE HYUD +D73C;D73C;1112 1172 11AF;D73C;1112 1172 11AF; # (휼; 휼; 휼; 휼; 휼; ) HANGUL SYLLABLE HYUL +D73D;D73D;1112 1172 11B0;D73D;1112 1172 11B0; # (휽; 휽; 휽; 휽; 휽; ) HANGUL SYLLABLE HYULG +D73E;D73E;1112 1172 11B1;D73E;1112 1172 11B1; # (휾; 휾; 휾; 휾; 휾; ) HANGUL SYLLABLE HYULM +D73F;D73F;1112 1172 11B2;D73F;1112 1172 11B2; # (휿; 휿; 휿; 휿; 휿; ) HANGUL SYLLABLE HYULB +D740;D740;1112 1172 11B3;D740;1112 1172 11B3; # (흀; 흀; 흀; 흀; 흀; ) HANGUL SYLLABLE HYULS +D741;D741;1112 1172 11B4;D741;1112 1172 11B4; # (흁; 흁; 흁; 흁; 흁; ) HANGUL SYLLABLE HYULT +D742;D742;1112 1172 11B5;D742;1112 1172 11B5; # (흂; 흂; 흂; 흂; 흂; ) HANGUL SYLLABLE HYULP +D743;D743;1112 1172 11B6;D743;1112 1172 11B6; # (흃; 흃; 흃; 흃; 흃; ) HANGUL SYLLABLE HYULH +D744;D744;1112 1172 11B7;D744;1112 1172 11B7; # (흄; 흄; 흄; 흄; 흄; ) HANGUL SYLLABLE HYUM +D745;D745;1112 1172 11B8;D745;1112 1172 11B8; # (흅; 흅; 흅; 흅; 흅; ) HANGUL SYLLABLE HYUB +D746;D746;1112 1172 11B9;D746;1112 1172 11B9; # (흆; 흆; 흆; 흆; 흆; ) HANGUL SYLLABLE HYUBS +D747;D747;1112 1172 11BA;D747;1112 1172 11BA; # (흇; 흇; 흇; 흇; 흇; ) HANGUL SYLLABLE HYUS +D748;D748;1112 1172 11BB;D748;1112 1172 11BB; # (흈; 흈; 흈; 흈; 흈; ) HANGUL SYLLABLE HYUSS +D749;D749;1112 1172 11BC;D749;1112 1172 11BC; # (흉; 흉; 흉; 흉; 흉; ) HANGUL SYLLABLE HYUNG +D74A;D74A;1112 1172 11BD;D74A;1112 1172 11BD; # (흊; 흊; 흊; 흊; 흊; ) HANGUL SYLLABLE HYUJ +D74B;D74B;1112 1172 11BE;D74B;1112 1172 11BE; # (흋; 흋; 흋; 흋; 흋; ) HANGUL SYLLABLE HYUC +D74C;D74C;1112 1172 11BF;D74C;1112 1172 11BF; # (흌; 흌; 흌; 흌; 흌; ) HANGUL SYLLABLE HYUK +D74D;D74D;1112 1172 11C0;D74D;1112 1172 11C0; # (흍; 흍; 흍; 흍; 흍; ) HANGUL SYLLABLE HYUT +D74E;D74E;1112 1172 11C1;D74E;1112 1172 11C1; # (흎; 흎; 흎; 흎; 흎; ) HANGUL SYLLABLE HYUP +D74F;D74F;1112 1172 11C2;D74F;1112 1172 11C2; # (흏; 흏; 흏; 흏; 흏; ) HANGUL SYLLABLE HYUH +D750;D750;1112 1173;D750;1112 1173; # (흐; 흐; 흐; 흐; 흐; ) HANGUL SYLLABLE HEU +D751;D751;1112 1173 11A8;D751;1112 1173 11A8; # (흑; 흑; 흑; 흑; 흑; ) HANGUL SYLLABLE HEUG +D752;D752;1112 1173 11A9;D752;1112 1173 11A9; # (흒; 흒; 흒; 흒; 흒; ) HANGUL SYLLABLE HEUGG +D753;D753;1112 1173 11AA;D753;1112 1173 11AA; # (흓; 흓; 흓; 흓; 흓; ) HANGUL SYLLABLE HEUGS +D754;D754;1112 1173 11AB;D754;1112 1173 11AB; # (흔; 흔; 흔; 흔; 흔; ) HANGUL SYLLABLE HEUN +D755;D755;1112 1173 11AC;D755;1112 1173 11AC; # (흕; 흕; 흕; 흕; 흕; ) HANGUL SYLLABLE HEUNJ +D756;D756;1112 1173 11AD;D756;1112 1173 11AD; # (흖; 흖; 흖; 흖; 흖; ) HANGUL SYLLABLE HEUNH +D757;D757;1112 1173 11AE;D757;1112 1173 11AE; # (흗; 흗; 흗; 흗; 흗; ) HANGUL SYLLABLE HEUD +D758;D758;1112 1173 11AF;D758;1112 1173 11AF; # (흘; 흘; 흘; 흘; 흘; ) HANGUL SYLLABLE HEUL +D759;D759;1112 1173 11B0;D759;1112 1173 11B0; # (흙; 흙; 흙; 흙; 흙; ) HANGUL SYLLABLE HEULG +D75A;D75A;1112 1173 11B1;D75A;1112 1173 11B1; # (흚; 흚; 흚; 흚; 흚; ) HANGUL SYLLABLE HEULM +D75B;D75B;1112 1173 11B2;D75B;1112 1173 11B2; # (흛; 흛; 흛; 흛; 흛; ) HANGUL SYLLABLE HEULB +D75C;D75C;1112 1173 11B3;D75C;1112 1173 11B3; # (흜; 흜; 흜; 흜; 흜; ) HANGUL SYLLABLE HEULS +D75D;D75D;1112 1173 11B4;D75D;1112 1173 11B4; # (흝; 흝; 흝; 흝; 흝; ) HANGUL SYLLABLE HEULT +D75E;D75E;1112 1173 11B5;D75E;1112 1173 11B5; # (흞; 흞; 흞; 흞; 흞; ) HANGUL SYLLABLE HEULP +D75F;D75F;1112 1173 11B6;D75F;1112 1173 11B6; # (흟; 흟; 흟; 흟; 흟; ) HANGUL SYLLABLE HEULH +D760;D760;1112 1173 11B7;D760;1112 1173 11B7; # (흠; 흠; 흠; 흠; 흠; ) HANGUL SYLLABLE HEUM +D761;D761;1112 1173 11B8;D761;1112 1173 11B8; # (흡; 흡; 흡; 흡; 흡; ) HANGUL SYLLABLE HEUB +D762;D762;1112 1173 11B9;D762;1112 1173 11B9; # (흢; 흢; 흢; 흢; 흢; ) HANGUL SYLLABLE HEUBS +D763;D763;1112 1173 11BA;D763;1112 1173 11BA; # (흣; 흣; 흣; 흣; 흣; ) HANGUL SYLLABLE HEUS +D764;D764;1112 1173 11BB;D764;1112 1173 11BB; # (흤; 흤; 흤; 흤; 흤; ) HANGUL SYLLABLE HEUSS +D765;D765;1112 1173 11BC;D765;1112 1173 11BC; # (흥; 흥; 흥; 흥; 흥; ) HANGUL SYLLABLE HEUNG +D766;D766;1112 1173 11BD;D766;1112 1173 11BD; # (흦; 흦; 흦; 흦; 흦; ) HANGUL SYLLABLE HEUJ +D767;D767;1112 1173 11BE;D767;1112 1173 11BE; # (흧; 흧; 흧; 흧; 흧; ) HANGUL SYLLABLE HEUC +D768;D768;1112 1173 11BF;D768;1112 1173 11BF; # (흨; 흨; 흨; 흨; 흨; ) HANGUL SYLLABLE HEUK +D769;D769;1112 1173 11C0;D769;1112 1173 11C0; # (흩; 흩; 흩; 흩; 흩; ) HANGUL SYLLABLE HEUT +D76A;D76A;1112 1173 11C1;D76A;1112 1173 11C1; # (흪; 흪; 흪; 흪; 흪; ) HANGUL SYLLABLE HEUP +D76B;D76B;1112 1173 11C2;D76B;1112 1173 11C2; # (흫; 흫; 흫; 흫; 흫; ) HANGUL SYLLABLE HEUH +D76C;D76C;1112 1174;D76C;1112 1174; # (희; 희; 희; 희; 희; ) HANGUL SYLLABLE HYI +D76D;D76D;1112 1174 11A8;D76D;1112 1174 11A8; # (흭; 흭; 흭; 흭; 흭; ) HANGUL SYLLABLE HYIG +D76E;D76E;1112 1174 11A9;D76E;1112 1174 11A9; # (흮; 흮; 흮; 흮; 흮; ) HANGUL SYLLABLE HYIGG +D76F;D76F;1112 1174 11AA;D76F;1112 1174 11AA; # (흯; 흯; 흯; 흯; 흯; ) HANGUL SYLLABLE HYIGS +D770;D770;1112 1174 11AB;D770;1112 1174 11AB; # (흰; 흰; 흰; 흰; 흰; ) HANGUL SYLLABLE HYIN +D771;D771;1112 1174 11AC;D771;1112 1174 11AC; # (흱; 흱; 흱; 흱; 흱; ) HANGUL SYLLABLE HYINJ +D772;D772;1112 1174 11AD;D772;1112 1174 11AD; # (흲; 흲; 흲; 흲; 흲; ) HANGUL SYLLABLE HYINH +D773;D773;1112 1174 11AE;D773;1112 1174 11AE; # (흳; 흳; 흳; 흳; 흳; ) HANGUL SYLLABLE HYID +D774;D774;1112 1174 11AF;D774;1112 1174 11AF; # (흴; 흴; 흴; 흴; 흴; ) HANGUL SYLLABLE HYIL +D775;D775;1112 1174 11B0;D775;1112 1174 11B0; # (흵; 흵; 흵; 흵; 흵; ) HANGUL SYLLABLE HYILG +D776;D776;1112 1174 11B1;D776;1112 1174 11B1; # (흶; 흶; 흶; 흶; 흶; ) HANGUL SYLLABLE HYILM +D777;D777;1112 1174 11B2;D777;1112 1174 11B2; # (흷; 흷; 흷; 흷; 흷; ) HANGUL SYLLABLE HYILB +D778;D778;1112 1174 11B3;D778;1112 1174 11B3; # (흸; 흸; 흸; 흸; 흸; ) HANGUL SYLLABLE HYILS +D779;D779;1112 1174 11B4;D779;1112 1174 11B4; # (흹; 흹; 흹; 흹; 흹; ) HANGUL SYLLABLE HYILT +D77A;D77A;1112 1174 11B5;D77A;1112 1174 11B5; # (흺; 흺; 흺; 흺; 흺; ) HANGUL SYLLABLE HYILP +D77B;D77B;1112 1174 11B6;D77B;1112 1174 11B6; # (흻; 흻; 흻; 흻; 흻; ) HANGUL SYLLABLE HYILH +D77C;D77C;1112 1174 11B7;D77C;1112 1174 11B7; # (흼; 흼; 흼; 흼; 흼; ) HANGUL SYLLABLE HYIM +D77D;D77D;1112 1174 11B8;D77D;1112 1174 11B8; # (흽; 흽; 흽; 흽; 흽; ) HANGUL SYLLABLE HYIB +D77E;D77E;1112 1174 11B9;D77E;1112 1174 11B9; # (흾; 흾; 흾; 흾; 흾; ) HANGUL SYLLABLE HYIBS +D77F;D77F;1112 1174 11BA;D77F;1112 1174 11BA; # (흿; 흿; 흿; 흿; 흿; ) HANGUL SYLLABLE HYIS +D780;D780;1112 1174 11BB;D780;1112 1174 11BB; # (힀; 힀; 힀; 힀; 힀; ) HANGUL SYLLABLE HYISS +D781;D781;1112 1174 11BC;D781;1112 1174 11BC; # (힁; 힁; 힁; 힁; 힁; ) HANGUL SYLLABLE HYING +D782;D782;1112 1174 11BD;D782;1112 1174 11BD; # (힂; 힂; 힂; 힂; 힂; ) HANGUL SYLLABLE HYIJ +D783;D783;1112 1174 11BE;D783;1112 1174 11BE; # (힃; 힃; 힃; 힃; 힃; ) HANGUL SYLLABLE HYIC +D784;D784;1112 1174 11BF;D784;1112 1174 11BF; # (힄; 힄; 힄; 힄; 힄; ) HANGUL SYLLABLE HYIK +D785;D785;1112 1174 11C0;D785;1112 1174 11C0; # (힅; 힅; 힅; 힅; 힅; ) HANGUL SYLLABLE HYIT +D786;D786;1112 1174 11C1;D786;1112 1174 11C1; # (힆; 힆; 힆; 힆; 힆; ) HANGUL SYLLABLE HYIP +D787;D787;1112 1174 11C2;D787;1112 1174 11C2; # (힇; 힇; 힇; 힇; 힇; ) HANGUL SYLLABLE HYIH +D788;D788;1112 1175;D788;1112 1175; # (히; 히; 히; 히; 히; ) HANGUL SYLLABLE HI +D789;D789;1112 1175 11A8;D789;1112 1175 11A8; # (힉; 힉; 힉; 힉; 힉; ) HANGUL SYLLABLE HIG +D78A;D78A;1112 1175 11A9;D78A;1112 1175 11A9; # (힊; 힊; 힊; 힊; 힊; ) HANGUL SYLLABLE HIGG +D78B;D78B;1112 1175 11AA;D78B;1112 1175 11AA; # (힋; 힋; 힋; 힋; 힋; ) HANGUL SYLLABLE HIGS +D78C;D78C;1112 1175 11AB;D78C;1112 1175 11AB; # (힌; 힌; 힌; 힌; 힌; ) HANGUL SYLLABLE HIN +D78D;D78D;1112 1175 11AC;D78D;1112 1175 11AC; # (힍; 힍; 힍; 힍; 힍; ) HANGUL SYLLABLE HINJ +D78E;D78E;1112 1175 11AD;D78E;1112 1175 11AD; # (힎; 힎; 힎; 힎; 힎; ) HANGUL SYLLABLE HINH +D78F;D78F;1112 1175 11AE;D78F;1112 1175 11AE; # (힏; 힏; 힏; 힏; 힏; ) HANGUL SYLLABLE HID +D790;D790;1112 1175 11AF;D790;1112 1175 11AF; # (힐; 힐; 힐; 힐; 힐; ) HANGUL SYLLABLE HIL +D791;D791;1112 1175 11B0;D791;1112 1175 11B0; # (힑; 힑; 힑; 힑; 힑; ) HANGUL SYLLABLE HILG +D792;D792;1112 1175 11B1;D792;1112 1175 11B1; # (힒; 힒; 힒; 힒; 힒; ) HANGUL SYLLABLE HILM +D793;D793;1112 1175 11B2;D793;1112 1175 11B2; # (힓; 힓; 힓; 힓; 힓; ) HANGUL SYLLABLE HILB +D794;D794;1112 1175 11B3;D794;1112 1175 11B3; # (힔; 힔; 힔; 힔; 힔; ) HANGUL SYLLABLE HILS +D795;D795;1112 1175 11B4;D795;1112 1175 11B4; # (힕; 힕; 힕; 힕; 힕; ) HANGUL SYLLABLE HILT +D796;D796;1112 1175 11B5;D796;1112 1175 11B5; # (힖; 힖; 힖; 힖; 힖; ) HANGUL SYLLABLE HILP +D797;D797;1112 1175 11B6;D797;1112 1175 11B6; # (힗; 힗; 힗; 힗; 힗; ) HANGUL SYLLABLE HILH +D798;D798;1112 1175 11B7;D798;1112 1175 11B7; # (힘; 힘; 힘; 힘; 힘; ) HANGUL SYLLABLE HIM +D799;D799;1112 1175 11B8;D799;1112 1175 11B8; # (힙; 힙; 힙; 힙; 힙; ) HANGUL SYLLABLE HIB +D79A;D79A;1112 1175 11B9;D79A;1112 1175 11B9; # (힚; 힚; 힚; 힚; 힚; ) HANGUL SYLLABLE HIBS +D79B;D79B;1112 1175 11BA;D79B;1112 1175 11BA; # (힛; 힛; 힛; 힛; 힛; ) HANGUL SYLLABLE HIS +D79C;D79C;1112 1175 11BB;D79C;1112 1175 11BB; # (힜; 힜; 힜; 힜; 힜; ) HANGUL SYLLABLE HISS +D79D;D79D;1112 1175 11BC;D79D;1112 1175 11BC; # (힝; 힝; 힝; 힝; 힝; ) HANGUL SYLLABLE HING +D79E;D79E;1112 1175 11BD;D79E;1112 1175 11BD; # (힞; 힞; 힞; 힞; 힞; ) HANGUL SYLLABLE HIJ +D79F;D79F;1112 1175 11BE;D79F;1112 1175 11BE; # (힟; 힟; 힟; 힟; 힟; ) HANGUL SYLLABLE HIC +D7A0;D7A0;1112 1175 11BF;D7A0;1112 1175 11BF; # (힠; 힠; 힠; 힠; 힠; ) HANGUL SYLLABLE HIK +D7A1;D7A1;1112 1175 11C0;D7A1;1112 1175 11C0; # (힡; 힡; 힡; 힡; 힡; ) HANGUL SYLLABLE HIT +D7A2;D7A2;1112 1175 11C1;D7A2;1112 1175 11C1; # (힢; 힢; 힢; 힢; 힢; ) HANGUL SYLLABLE HIP +D7A3;D7A3;1112 1175 11C2;D7A3;1112 1175 11C2; # (힣; 힣; 힣; 힣; 힣; ) HANGUL SYLLABLE HIH +F900;8C48;8C48;8C48;8C48; # (豈; 豈; 豈; 豈; 豈; ) CJK COMPATIBILITY IDEOGRAPH-F900 +F901;66F4;66F4;66F4;66F4; # (更; 更; 更; 更; 更; ) CJK COMPATIBILITY IDEOGRAPH-F901 +F902;8ECA;8ECA;8ECA;8ECA; # (車; 車; 車; 車; 車; ) CJK COMPATIBILITY IDEOGRAPH-F902 +F903;8CC8;8CC8;8CC8;8CC8; # (賈; 賈; 賈; 賈; 賈; ) CJK COMPATIBILITY IDEOGRAPH-F903 +F904;6ED1;6ED1;6ED1;6ED1; # (滑; 滑; 滑; 滑; 滑; ) CJK COMPATIBILITY IDEOGRAPH-F904 +F905;4E32;4E32;4E32;4E32; # (串; 串; 串; 串; 串; ) CJK COMPATIBILITY IDEOGRAPH-F905 +F906;53E5;53E5;53E5;53E5; # (句; 句; 句; 句; 句; ) CJK COMPATIBILITY IDEOGRAPH-F906 +F907;9F9C;9F9C;9F9C;9F9C; # (龜; 龜; 龜; 龜; 龜; ) CJK COMPATIBILITY IDEOGRAPH-F907 +F908;9F9C;9F9C;9F9C;9F9C; # (龜; 龜; 龜; 龜; 龜; ) CJK COMPATIBILITY IDEOGRAPH-F908 +F909;5951;5951;5951;5951; # (契; 契; 契; 契; 契; ) CJK COMPATIBILITY IDEOGRAPH-F909 +F90A;91D1;91D1;91D1;91D1; # (金; 金; 金; 金; 金; ) CJK COMPATIBILITY IDEOGRAPH-F90A +F90B;5587;5587;5587;5587; # (喇; 喇; 喇; 喇; 喇; ) CJK COMPATIBILITY IDEOGRAPH-F90B +F90C;5948;5948;5948;5948; # (奈; 奈; 奈; 奈; 奈; ) CJK COMPATIBILITY IDEOGRAPH-F90C +F90D;61F6;61F6;61F6;61F6; # (懶; 懶; 懶; 懶; 懶; ) CJK COMPATIBILITY IDEOGRAPH-F90D +F90E;7669;7669;7669;7669; # (癩; 癩; 癩; 癩; 癩; ) CJK COMPATIBILITY IDEOGRAPH-F90E +F90F;7F85;7F85;7F85;7F85; # (羅; 羅; 羅; 羅; 羅; ) CJK COMPATIBILITY IDEOGRAPH-F90F +F910;863F;863F;863F;863F; # (蘿; 蘿; 蘿; 蘿; 蘿; ) CJK COMPATIBILITY IDEOGRAPH-F910 +F911;87BA;87BA;87BA;87BA; # (螺; 螺; 螺; 螺; 螺; ) CJK COMPATIBILITY IDEOGRAPH-F911 +F912;88F8;88F8;88F8;88F8; # (裸; 裸; 裸; 裸; 裸; ) CJK COMPATIBILITY IDEOGRAPH-F912 +F913;908F;908F;908F;908F; # (邏; 邏; 邏; 邏; 邏; ) CJK COMPATIBILITY IDEOGRAPH-F913 +F914;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F914 +F915;6D1B;6D1B;6D1B;6D1B; # (洛; 洛; 洛; 洛; 洛; ) CJK COMPATIBILITY IDEOGRAPH-F915 +F916;70D9;70D9;70D9;70D9; # (烙; 烙; 烙; 烙; 烙; ) CJK COMPATIBILITY IDEOGRAPH-F916 +F917;73DE;73DE;73DE;73DE; # (珞; 珞; 珞; 珞; 珞; ) CJK COMPATIBILITY IDEOGRAPH-F917 +F918;843D;843D;843D;843D; # (落; 落; 落; 落; 落; ) CJK COMPATIBILITY IDEOGRAPH-F918 +F919;916A;916A;916A;916A; # (酪; 酪; 酪; 酪; 酪; ) CJK COMPATIBILITY IDEOGRAPH-F919 +F91A;99F1;99F1;99F1;99F1; # (駱; 駱; 駱; 駱; 駱; ) CJK COMPATIBILITY IDEOGRAPH-F91A +F91B;4E82;4E82;4E82;4E82; # (亂; 亂; 亂; 亂; 亂; ) CJK COMPATIBILITY IDEOGRAPH-F91B +F91C;5375;5375;5375;5375; # (卵; 卵; 卵; 卵; 卵; ) CJK COMPATIBILITY IDEOGRAPH-F91C +F91D;6B04;6B04;6B04;6B04; # (欄; 欄; 欄; 欄; 欄; ) CJK COMPATIBILITY IDEOGRAPH-F91D +F91E;721B;721B;721B;721B; # (爛; 爛; 爛; 爛; 爛; ) CJK COMPATIBILITY IDEOGRAPH-F91E +F91F;862D;862D;862D;862D; # (蘭; 蘭; 蘭; 蘭; 蘭; ) CJK COMPATIBILITY IDEOGRAPH-F91F +F920;9E1E;9E1E;9E1E;9E1E; # (鸞; 鸞; 鸞; 鸞; 鸞; ) CJK COMPATIBILITY IDEOGRAPH-F920 +F921;5D50;5D50;5D50;5D50; # (嵐; 嵐; 嵐; 嵐; 嵐; ) CJK COMPATIBILITY IDEOGRAPH-F921 +F922;6FEB;6FEB;6FEB;6FEB; # (濫; 濫; 濫; 濫; 濫; ) CJK COMPATIBILITY IDEOGRAPH-F922 +F923;85CD;85CD;85CD;85CD; # (藍; 藍; 藍; 藍; 藍; ) CJK COMPATIBILITY IDEOGRAPH-F923 +F924;8964;8964;8964;8964; # (襤; 襤; 襤; 襤; 襤; ) CJK COMPATIBILITY IDEOGRAPH-F924 +F925;62C9;62C9;62C9;62C9; # (拉; 拉; 拉; 拉; 拉; ) CJK COMPATIBILITY IDEOGRAPH-F925 +F926;81D8;81D8;81D8;81D8; # (臘; 臘; 臘; 臘; 臘; ) CJK COMPATIBILITY IDEOGRAPH-F926 +F927;881F;881F;881F;881F; # (蠟; 蠟; 蠟; 蠟; 蠟; ) CJK COMPATIBILITY IDEOGRAPH-F927 +F928;5ECA;5ECA;5ECA;5ECA; # (廊; 廊; 廊; 廊; 廊; ) CJK COMPATIBILITY IDEOGRAPH-F928 +F929;6717;6717;6717;6717; # (朗; 朗; 朗; 朗; 朗; ) CJK COMPATIBILITY IDEOGRAPH-F929 +F92A;6D6A;6D6A;6D6A;6D6A; # (浪; 浪; 浪; 浪; 浪; ) CJK COMPATIBILITY IDEOGRAPH-F92A +F92B;72FC;72FC;72FC;72FC; # (狼; 狼; 狼; 狼; 狼; ) CJK COMPATIBILITY IDEOGRAPH-F92B +F92C;90CE;90CE;90CE;90CE; # (郎; 郎; 郎; 郎; 郎; ) CJK COMPATIBILITY IDEOGRAPH-F92C +F92D;4F86;4F86;4F86;4F86; # (來; 來; 來; 來; 來; ) CJK COMPATIBILITY IDEOGRAPH-F92D +F92E;51B7;51B7;51B7;51B7; # (冷; 冷; 冷; 冷; 冷; ) CJK COMPATIBILITY IDEOGRAPH-F92E +F92F;52DE;52DE;52DE;52DE; # (勞; 勞; 勞; 勞; 勞; ) CJK COMPATIBILITY IDEOGRAPH-F92F +F930;64C4;64C4;64C4;64C4; # (擄; 擄; 擄; 擄; 擄; ) CJK COMPATIBILITY IDEOGRAPH-F930 +F931;6AD3;6AD3;6AD3;6AD3; # (櫓; 櫓; 櫓; 櫓; 櫓; ) CJK COMPATIBILITY IDEOGRAPH-F931 +F932;7210;7210;7210;7210; # (爐; 爐; 爐; 爐; 爐; ) CJK COMPATIBILITY IDEOGRAPH-F932 +F933;76E7;76E7;76E7;76E7; # (盧; 盧; 盧; 盧; 盧; ) CJK COMPATIBILITY IDEOGRAPH-F933 +F934;8001;8001;8001;8001; # (老; 老; 老; 老; 老; ) CJK COMPATIBILITY IDEOGRAPH-F934 +F935;8606;8606;8606;8606; # (蘆; 蘆; 蘆; 蘆; 蘆; ) CJK COMPATIBILITY IDEOGRAPH-F935 +F936;865C;865C;865C;865C; # (虜; 虜; 虜; 虜; 虜; ) CJK COMPATIBILITY IDEOGRAPH-F936 +F937;8DEF;8DEF;8DEF;8DEF; # (路; 路; 路; 路; 路; ) CJK COMPATIBILITY IDEOGRAPH-F937 +F938;9732;9732;9732;9732; # (露; 露; 露; 露; 露; ) CJK COMPATIBILITY IDEOGRAPH-F938 +F939;9B6F;9B6F;9B6F;9B6F; # (魯; 魯; 魯; 魯; 魯; ) CJK COMPATIBILITY IDEOGRAPH-F939 +F93A;9DFA;9DFA;9DFA;9DFA; # (鷺; 鷺; 鷺; 鷺; 鷺; ) CJK COMPATIBILITY IDEOGRAPH-F93A +F93B;788C;788C;788C;788C; # (碌; 碌; 碌; 碌; 碌; ) CJK COMPATIBILITY IDEOGRAPH-F93B +F93C;797F;797F;797F;797F; # (祿; 祿; 祿; 祿; 祿; ) CJK COMPATIBILITY IDEOGRAPH-F93C +F93D;7DA0;7DA0;7DA0;7DA0; # (綠; 綠; 綠; 綠; 綠; ) CJK COMPATIBILITY IDEOGRAPH-F93D +F93E;83C9;83C9;83C9;83C9; # (菉; 菉; 菉; 菉; 菉; ) CJK COMPATIBILITY IDEOGRAPH-F93E +F93F;9304;9304;9304;9304; # (錄; 錄; 錄; 錄; 錄; ) CJK COMPATIBILITY IDEOGRAPH-F93F +F940;9E7F;9E7F;9E7F;9E7F; # (鹿; 鹿; 鹿; 鹿; 鹿; ) CJK COMPATIBILITY IDEOGRAPH-F940 +F941;8AD6;8AD6;8AD6;8AD6; # (論; 論; 論; 論; 論; ) CJK COMPATIBILITY IDEOGRAPH-F941 +F942;58DF;58DF;58DF;58DF; # (壟; 壟; 壟; 壟; 壟; ) CJK COMPATIBILITY IDEOGRAPH-F942 +F943;5F04;5F04;5F04;5F04; # (弄; 弄; 弄; 弄; 弄; ) CJK COMPATIBILITY IDEOGRAPH-F943 +F944;7C60;7C60;7C60;7C60; # (籠; 籠; 籠; 籠; 籠; ) CJK COMPATIBILITY IDEOGRAPH-F944 +F945;807E;807E;807E;807E; # (聾; 聾; 聾; 聾; 聾; ) CJK COMPATIBILITY IDEOGRAPH-F945 +F946;7262;7262;7262;7262; # (牢; 牢; 牢; 牢; 牢; ) CJK COMPATIBILITY IDEOGRAPH-F946 +F947;78CA;78CA;78CA;78CA; # (磊; 磊; 磊; 磊; 磊; ) CJK COMPATIBILITY IDEOGRAPH-F947 +F948;8CC2;8CC2;8CC2;8CC2; # (賂; 賂; 賂; 賂; 賂; ) CJK COMPATIBILITY IDEOGRAPH-F948 +F949;96F7;96F7;96F7;96F7; # (雷; 雷; 雷; 雷; 雷; ) CJK COMPATIBILITY IDEOGRAPH-F949 +F94A;58D8;58D8;58D8;58D8; # (壘; 壘; 壘; 壘; 壘; ) CJK COMPATIBILITY IDEOGRAPH-F94A +F94B;5C62;5C62;5C62;5C62; # (屢; 屢; 屢; 屢; 屢; ) CJK COMPATIBILITY IDEOGRAPH-F94B +F94C;6A13;6A13;6A13;6A13; # (樓; 樓; 樓; 樓; 樓; ) CJK COMPATIBILITY IDEOGRAPH-F94C +F94D;6DDA;6DDA;6DDA;6DDA; # (淚; 淚; 淚; 淚; 淚; ) CJK COMPATIBILITY IDEOGRAPH-F94D +F94E;6F0F;6F0F;6F0F;6F0F; # (漏; 漏; 漏; 漏; 漏; ) CJK COMPATIBILITY IDEOGRAPH-F94E +F94F;7D2F;7D2F;7D2F;7D2F; # (累; 累; 累; 累; 累; ) CJK COMPATIBILITY IDEOGRAPH-F94F +F950;7E37;7E37;7E37;7E37; # (縷; 縷; 縷; 縷; 縷; ) CJK COMPATIBILITY IDEOGRAPH-F950 +F951;964B;964B;964B;964B; # (陋; 陋; 陋; 陋; 陋; ) CJK COMPATIBILITY IDEOGRAPH-F951 +F952;52D2;52D2;52D2;52D2; # (勒; 勒; 勒; 勒; 勒; ) CJK COMPATIBILITY IDEOGRAPH-F952 +F953;808B;808B;808B;808B; # (肋; 肋; 肋; 肋; 肋; ) CJK COMPATIBILITY IDEOGRAPH-F953 +F954;51DC;51DC;51DC;51DC; # (凜; 凜; 凜; 凜; 凜; ) CJK COMPATIBILITY IDEOGRAPH-F954 +F955;51CC;51CC;51CC;51CC; # (凌; 凌; 凌; 凌; 凌; ) CJK COMPATIBILITY IDEOGRAPH-F955 +F956;7A1C;7A1C;7A1C;7A1C; # (稜; 稜; 稜; 稜; 稜; ) CJK COMPATIBILITY IDEOGRAPH-F956 +F957;7DBE;7DBE;7DBE;7DBE; # (綾; 綾; 綾; 綾; 綾; ) CJK COMPATIBILITY IDEOGRAPH-F957 +F958;83F1;83F1;83F1;83F1; # (菱; 菱; 菱; 菱; 菱; ) CJK COMPATIBILITY IDEOGRAPH-F958 +F959;9675;9675;9675;9675; # (陵; 陵; 陵; 陵; 陵; ) CJK COMPATIBILITY IDEOGRAPH-F959 +F95A;8B80;8B80;8B80;8B80; # (讀; 讀; 讀; 讀; 讀; ) CJK COMPATIBILITY IDEOGRAPH-F95A +F95B;62CF;62CF;62CF;62CF; # (拏; 拏; 拏; 拏; 拏; ) CJK COMPATIBILITY IDEOGRAPH-F95B +F95C;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F95C +F95D;8AFE;8AFE;8AFE;8AFE; # (諾; 諾; 諾; 諾; 諾; ) CJK COMPATIBILITY IDEOGRAPH-F95D +F95E;4E39;4E39;4E39;4E39; # (丹; 丹; 丹; 丹; 丹; ) CJK COMPATIBILITY IDEOGRAPH-F95E +F95F;5BE7;5BE7;5BE7;5BE7; # (寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-F95F +F960;6012;6012;6012;6012; # (怒; 怒; 怒; 怒; 怒; ) CJK COMPATIBILITY IDEOGRAPH-F960 +F961;7387;7387;7387;7387; # (率; 率; 率; 率; 率; ) CJK COMPATIBILITY IDEOGRAPH-F961 +F962;7570;7570;7570;7570; # (異; 異; 異; 異; 異; ) CJK COMPATIBILITY IDEOGRAPH-F962 +F963;5317;5317;5317;5317; # (北; 北; 北; 北; 北; ) CJK COMPATIBILITY IDEOGRAPH-F963 +F964;78FB;78FB;78FB;78FB; # (磻; 磻; 磻; 磻; 磻; ) CJK COMPATIBILITY IDEOGRAPH-F964 +F965;4FBF;4FBF;4FBF;4FBF; # (便; 便; 便; 便; 便; ) CJK COMPATIBILITY IDEOGRAPH-F965 +F966;5FA9;5FA9;5FA9;5FA9; # (復; 復; 復; 復; 復; ) CJK COMPATIBILITY IDEOGRAPH-F966 +F967;4E0D;4E0D;4E0D;4E0D; # (不; 不; 不; 不; 不; ) CJK COMPATIBILITY IDEOGRAPH-F967 +F968;6CCC;6CCC;6CCC;6CCC; # (泌; 泌; 泌; 泌; 泌; ) CJK COMPATIBILITY IDEOGRAPH-F968 +F969;6578;6578;6578;6578; # (數; 數; 數; 數; 數; ) CJK COMPATIBILITY IDEOGRAPH-F969 +F96A;7D22;7D22;7D22;7D22; # (索; 索; 索; 索; 索; ) CJK COMPATIBILITY IDEOGRAPH-F96A +F96B;53C3;53C3;53C3;53C3; # (參; 參; 參; 參; 參; ) CJK COMPATIBILITY IDEOGRAPH-F96B +F96C;585E;585E;585E;585E; # (塞; 塞; 塞; 塞; 塞; ) CJK COMPATIBILITY IDEOGRAPH-F96C +F96D;7701;7701;7701;7701; # (省; 省; 省; 省; 省; ) CJK COMPATIBILITY IDEOGRAPH-F96D +F96E;8449;8449;8449;8449; # (葉; 葉; 葉; 葉; 葉; ) CJK COMPATIBILITY IDEOGRAPH-F96E +F96F;8AAA;8AAA;8AAA;8AAA; # (說; 說; 說; 說; 說; ) CJK COMPATIBILITY IDEOGRAPH-F96F +F970;6BBA;6BBA;6BBA;6BBA; # (殺; 殺; 殺; 殺; 殺; ) CJK COMPATIBILITY IDEOGRAPH-F970 +F971;8FB0;8FB0;8FB0;8FB0; # (辰; 辰; 辰; 辰; 辰; ) CJK COMPATIBILITY IDEOGRAPH-F971 +F972;6C88;6C88;6C88;6C88; # (沈; 沈; 沈; 沈; 沈; ) CJK COMPATIBILITY IDEOGRAPH-F972 +F973;62FE;62FE;62FE;62FE; # (拾; 拾; 拾; 拾; 拾; ) CJK COMPATIBILITY IDEOGRAPH-F973 +F974;82E5;82E5;82E5;82E5; # (若; 若; 若; 若; 若; ) CJK COMPATIBILITY IDEOGRAPH-F974 +F975;63A0;63A0;63A0;63A0; # (掠; 掠; 掠; 掠; 掠; ) CJK COMPATIBILITY IDEOGRAPH-F975 +F976;7565;7565;7565;7565; # (略; 略; 略; 略; 略; ) CJK COMPATIBILITY IDEOGRAPH-F976 +F977;4EAE;4EAE;4EAE;4EAE; # (亮; 亮; 亮; 亮; 亮; ) CJK COMPATIBILITY IDEOGRAPH-F977 +F978;5169;5169;5169;5169; # (兩; 兩; 兩; 兩; 兩; ) CJK COMPATIBILITY IDEOGRAPH-F978 +F979;51C9;51C9;51C9;51C9; # (凉; 凉; 凉; 凉; 凉; ) CJK COMPATIBILITY IDEOGRAPH-F979 +F97A;6881;6881;6881;6881; # (梁; 梁; 梁; 梁; 梁; ) CJK COMPATIBILITY IDEOGRAPH-F97A +F97B;7CE7;7CE7;7CE7;7CE7; # (糧; 糧; 糧; 糧; 糧; ) CJK COMPATIBILITY IDEOGRAPH-F97B +F97C;826F;826F;826F;826F; # (良; 良; 良; 良; 良; ) CJK COMPATIBILITY IDEOGRAPH-F97C +F97D;8AD2;8AD2;8AD2;8AD2; # (諒; 諒; 諒; 諒; 諒; ) CJK COMPATIBILITY IDEOGRAPH-F97D +F97E;91CF;91CF;91CF;91CF; # (量; 量; 量; 量; 量; ) CJK COMPATIBILITY IDEOGRAPH-F97E +F97F;52F5;52F5;52F5;52F5; # (勵; 勵; 勵; 勵; 勵; ) CJK COMPATIBILITY IDEOGRAPH-F97F +F980;5442;5442;5442;5442; # (呂; 呂; 呂; 呂; 呂; ) CJK COMPATIBILITY IDEOGRAPH-F980 +F981;5973;5973;5973;5973; # (女; 女; 女; 女; 女; ) CJK COMPATIBILITY IDEOGRAPH-F981 +F982;5EEC;5EEC;5EEC;5EEC; # (廬; 廬; 廬; 廬; 廬; ) CJK COMPATIBILITY IDEOGRAPH-F982 +F983;65C5;65C5;65C5;65C5; # (旅; 旅; 旅; 旅; 旅; ) CJK COMPATIBILITY IDEOGRAPH-F983 +F984;6FFE;6FFE;6FFE;6FFE; # (濾; 濾; 濾; 濾; 濾; ) CJK COMPATIBILITY IDEOGRAPH-F984 +F985;792A;792A;792A;792A; # (礪; 礪; 礪; 礪; 礪; ) CJK COMPATIBILITY IDEOGRAPH-F985 +F986;95AD;95AD;95AD;95AD; # (閭; 閭; 閭; 閭; 閭; ) CJK COMPATIBILITY IDEOGRAPH-F986 +F987;9A6A;9A6A;9A6A;9A6A; # (驪; 驪; 驪; 驪; 驪; ) CJK COMPATIBILITY IDEOGRAPH-F987 +F988;9E97;9E97;9E97;9E97; # (麗; 麗; 麗; 麗; 麗; ) CJK COMPATIBILITY IDEOGRAPH-F988 +F989;9ECE;9ECE;9ECE;9ECE; # (黎; 黎; 黎; 黎; 黎; ) CJK COMPATIBILITY IDEOGRAPH-F989 +F98A;529B;529B;529B;529B; # (力; 力; 力; 力; 力; ) CJK COMPATIBILITY IDEOGRAPH-F98A +F98B;66C6;66C6;66C6;66C6; # (曆; 曆; 曆; 曆; 曆; ) CJK COMPATIBILITY IDEOGRAPH-F98B +F98C;6B77;6B77;6B77;6B77; # (歷; 歷; 歷; 歷; 歷; ) CJK COMPATIBILITY IDEOGRAPH-F98C +F98D;8F62;8F62;8F62;8F62; # (轢; 轢; 轢; 轢; 轢; ) CJK COMPATIBILITY IDEOGRAPH-F98D +F98E;5E74;5E74;5E74;5E74; # (年; 年; 年; 年; 年; ) CJK COMPATIBILITY IDEOGRAPH-F98E +F98F;6190;6190;6190;6190; # (憐; 憐; 憐; 憐; 憐; ) CJK COMPATIBILITY IDEOGRAPH-F98F +F990;6200;6200;6200;6200; # (戀; 戀; 戀; 戀; 戀; ) CJK COMPATIBILITY IDEOGRAPH-F990 +F991;649A;649A;649A;649A; # (撚; 撚; 撚; 撚; 撚; ) CJK COMPATIBILITY IDEOGRAPH-F991 +F992;6F23;6F23;6F23;6F23; # (漣; 漣; 漣; 漣; 漣; ) CJK COMPATIBILITY IDEOGRAPH-F992 +F993;7149;7149;7149;7149; # (煉; 煉; 煉; 煉; 煉; ) CJK COMPATIBILITY IDEOGRAPH-F993 +F994;7489;7489;7489;7489; # (璉; 璉; 璉; 璉; 璉; ) CJK COMPATIBILITY IDEOGRAPH-F994 +F995;79CA;79CA;79CA;79CA; # (秊; 秊; 秊; 秊; 秊; ) CJK COMPATIBILITY IDEOGRAPH-F995 +F996;7DF4;7DF4;7DF4;7DF4; # (練; 練; 練; 練; 練; ) CJK COMPATIBILITY IDEOGRAPH-F996 +F997;806F;806F;806F;806F; # (聯; 聯; 聯; 聯; 聯; ) CJK COMPATIBILITY IDEOGRAPH-F997 +F998;8F26;8F26;8F26;8F26; # (輦; 輦; 輦; 輦; 輦; ) CJK COMPATIBILITY IDEOGRAPH-F998 +F999;84EE;84EE;84EE;84EE; # (蓮; 蓮; 蓮; 蓮; 蓮; ) CJK COMPATIBILITY IDEOGRAPH-F999 +F99A;9023;9023;9023;9023; # (連; 連; 連; 連; 連; ) CJK COMPATIBILITY IDEOGRAPH-F99A +F99B;934A;934A;934A;934A; # (鍊; 鍊; 鍊; 鍊; 鍊; ) CJK COMPATIBILITY IDEOGRAPH-F99B +F99C;5217;5217;5217;5217; # (列; 列; 列; 列; 列; ) CJK COMPATIBILITY IDEOGRAPH-F99C +F99D;52A3;52A3;52A3;52A3; # (劣; 劣; 劣; 劣; 劣; ) CJK COMPATIBILITY IDEOGRAPH-F99D +F99E;54BD;54BD;54BD;54BD; # (咽; 咽; 咽; 咽; 咽; ) CJK COMPATIBILITY IDEOGRAPH-F99E +F99F;70C8;70C8;70C8;70C8; # (烈; 烈; 烈; 烈; 烈; ) CJK COMPATIBILITY IDEOGRAPH-F99F +F9A0;88C2;88C2;88C2;88C2; # (裂; 裂; 裂; 裂; 裂; ) CJK COMPATIBILITY IDEOGRAPH-F9A0 +F9A1;8AAA;8AAA;8AAA;8AAA; # (說; 說; 說; 說; 說; ) CJK COMPATIBILITY IDEOGRAPH-F9A1 +F9A2;5EC9;5EC9;5EC9;5EC9; # (廉; 廉; 廉; 廉; 廉; ) CJK COMPATIBILITY IDEOGRAPH-F9A2 +F9A3;5FF5;5FF5;5FF5;5FF5; # (念; 念; 念; 念; 念; ) CJK COMPATIBILITY IDEOGRAPH-F9A3 +F9A4;637B;637B;637B;637B; # (捻; 捻; 捻; 捻; 捻; ) CJK COMPATIBILITY IDEOGRAPH-F9A4 +F9A5;6BAE;6BAE;6BAE;6BAE; # (殮; 殮; 殮; 殮; 殮; ) CJK COMPATIBILITY IDEOGRAPH-F9A5 +F9A6;7C3E;7C3E;7C3E;7C3E; # (簾; 簾; 簾; 簾; 簾; ) CJK COMPATIBILITY IDEOGRAPH-F9A6 +F9A7;7375;7375;7375;7375; # (獵; 獵; 獵; 獵; 獵; ) CJK COMPATIBILITY IDEOGRAPH-F9A7 +F9A8;4EE4;4EE4;4EE4;4EE4; # (令; 令; 令; 令; 令; ) CJK COMPATIBILITY IDEOGRAPH-F9A8 +F9A9;56F9;56F9;56F9;56F9; # (囹; 囹; 囹; 囹; 囹; ) CJK COMPATIBILITY IDEOGRAPH-F9A9 +F9AA;5BE7;5BE7;5BE7;5BE7; # (寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-F9AA +F9AB;5DBA;5DBA;5DBA;5DBA; # (嶺; 嶺; 嶺; 嶺; 嶺; ) CJK COMPATIBILITY IDEOGRAPH-F9AB +F9AC;601C;601C;601C;601C; # (怜; 怜; 怜; 怜; 怜; ) CJK COMPATIBILITY IDEOGRAPH-F9AC +F9AD;73B2;73B2;73B2;73B2; # (玲; 玲; 玲; 玲; 玲; ) CJK COMPATIBILITY IDEOGRAPH-F9AD +F9AE;7469;7469;7469;7469; # (瑩; 瑩; 瑩; 瑩; 瑩; ) CJK COMPATIBILITY IDEOGRAPH-F9AE +F9AF;7F9A;7F9A;7F9A;7F9A; # (羚; 羚; 羚; 羚; 羚; ) CJK COMPATIBILITY IDEOGRAPH-F9AF +F9B0;8046;8046;8046;8046; # (聆; 聆; 聆; 聆; 聆; ) CJK COMPATIBILITY IDEOGRAPH-F9B0 +F9B1;9234;9234;9234;9234; # (鈴; 鈴; 鈴; 鈴; 鈴; ) CJK COMPATIBILITY IDEOGRAPH-F9B1 +F9B2;96F6;96F6;96F6;96F6; # (零; 零; 零; 零; 零; ) CJK COMPATIBILITY IDEOGRAPH-F9B2 +F9B3;9748;9748;9748;9748; # (靈; 靈; 靈; 靈; 靈; ) CJK COMPATIBILITY IDEOGRAPH-F9B3 +F9B4;9818;9818;9818;9818; # (領; 領; 領; 領; 領; ) CJK COMPATIBILITY IDEOGRAPH-F9B4 +F9B5;4F8B;4F8B;4F8B;4F8B; # (例; 例; 例; 例; 例; ) CJK COMPATIBILITY IDEOGRAPH-F9B5 +F9B6;79AE;79AE;79AE;79AE; # (禮; 禮; 禮; 禮; 禮; ) CJK COMPATIBILITY IDEOGRAPH-F9B6 +F9B7;91B4;91B4;91B4;91B4; # (醴; 醴; 醴; 醴; 醴; ) CJK COMPATIBILITY IDEOGRAPH-F9B7 +F9B8;96B8;96B8;96B8;96B8; # (隸; 隸; 隸; 隸; 隸; ) CJK COMPATIBILITY IDEOGRAPH-F9B8 +F9B9;60E1;60E1;60E1;60E1; # (惡; 惡; 惡; 惡; 惡; ) CJK COMPATIBILITY IDEOGRAPH-F9B9 +F9BA;4E86;4E86;4E86;4E86; # (了; 了; 了; 了; 了; ) CJK COMPATIBILITY IDEOGRAPH-F9BA +F9BB;50DA;50DA;50DA;50DA; # (僚; 僚; 僚; 僚; 僚; ) CJK COMPATIBILITY IDEOGRAPH-F9BB +F9BC;5BEE;5BEE;5BEE;5BEE; # (寮; 寮; 寮; 寮; 寮; ) CJK COMPATIBILITY IDEOGRAPH-F9BC +F9BD;5C3F;5C3F;5C3F;5C3F; # (尿; 尿; 尿; 尿; 尿; ) CJK COMPATIBILITY IDEOGRAPH-F9BD +F9BE;6599;6599;6599;6599; # (料; 料; 料; 料; 料; ) CJK COMPATIBILITY IDEOGRAPH-F9BE +F9BF;6A02;6A02;6A02;6A02; # (樂; 樂; 樂; 樂; 樂; ) CJK COMPATIBILITY IDEOGRAPH-F9BF +F9C0;71CE;71CE;71CE;71CE; # (燎; 燎; 燎; 燎; 燎; ) CJK COMPATIBILITY IDEOGRAPH-F9C0 +F9C1;7642;7642;7642;7642; # (療; 療; 療; 療; 療; ) CJK COMPATIBILITY IDEOGRAPH-F9C1 +F9C2;84FC;84FC;84FC;84FC; # (蓼; 蓼; 蓼; 蓼; 蓼; ) CJK COMPATIBILITY IDEOGRAPH-F9C2 +F9C3;907C;907C;907C;907C; # (遼; 遼; 遼; 遼; 遼; ) CJK COMPATIBILITY IDEOGRAPH-F9C3 +F9C4;9F8D;9F8D;9F8D;9F8D; # (龍; 龍; 龍; 龍; 龍; ) CJK COMPATIBILITY IDEOGRAPH-F9C4 +F9C5;6688;6688;6688;6688; # (暈; 暈; 暈; 暈; 暈; ) CJK COMPATIBILITY IDEOGRAPH-F9C5 +F9C6;962E;962E;962E;962E; # (阮; 阮; 阮; 阮; 阮; ) CJK COMPATIBILITY IDEOGRAPH-F9C6 +F9C7;5289;5289;5289;5289; # (劉; 劉; 劉; 劉; 劉; ) CJK COMPATIBILITY IDEOGRAPH-F9C7 +F9C8;677B;677B;677B;677B; # (杻; 杻; 杻; 杻; 杻; ) CJK COMPATIBILITY IDEOGRAPH-F9C8 +F9C9;67F3;67F3;67F3;67F3; # (柳; 柳; 柳; 柳; 柳; ) CJK COMPATIBILITY IDEOGRAPH-F9C9 +F9CA;6D41;6D41;6D41;6D41; # (流; 流; 流; 流; 流; ) CJK COMPATIBILITY IDEOGRAPH-F9CA +F9CB;6E9C;6E9C;6E9C;6E9C; # (溜; 溜; 溜; 溜; 溜; ) CJK COMPATIBILITY IDEOGRAPH-F9CB +F9CC;7409;7409;7409;7409; # (琉; 琉; 琉; 琉; 琉; ) CJK COMPATIBILITY IDEOGRAPH-F9CC +F9CD;7559;7559;7559;7559; # (留; 留; 留; 留; 留; ) CJK COMPATIBILITY IDEOGRAPH-F9CD +F9CE;786B;786B;786B;786B; # (硫; 硫; 硫; 硫; 硫; ) CJK COMPATIBILITY IDEOGRAPH-F9CE +F9CF;7D10;7D10;7D10;7D10; # (紐; 紐; 紐; 紐; 紐; ) CJK COMPATIBILITY IDEOGRAPH-F9CF +F9D0;985E;985E;985E;985E; # (類; 類; 類; 類; 類; ) CJK COMPATIBILITY IDEOGRAPH-F9D0 +F9D1;516D;516D;516D;516D; # (六; 六; 六; 六; 六; ) CJK COMPATIBILITY IDEOGRAPH-F9D1 +F9D2;622E;622E;622E;622E; # (戮; 戮; 戮; 戮; 戮; ) CJK COMPATIBILITY IDEOGRAPH-F9D2 +F9D3;9678;9678;9678;9678; # (陸; 陸; 陸; 陸; 陸; ) CJK COMPATIBILITY IDEOGRAPH-F9D3 +F9D4;502B;502B;502B;502B; # (倫; 倫; 倫; 倫; 倫; ) CJK COMPATIBILITY IDEOGRAPH-F9D4 +F9D5;5D19;5D19;5D19;5D19; # (崙; 崙; 崙; 崙; 崙; ) CJK COMPATIBILITY IDEOGRAPH-F9D5 +F9D6;6DEA;6DEA;6DEA;6DEA; # (淪; 淪; 淪; 淪; 淪; ) CJK COMPATIBILITY IDEOGRAPH-F9D6 +F9D7;8F2A;8F2A;8F2A;8F2A; # (輪; 輪; 輪; 輪; 輪; ) CJK COMPATIBILITY IDEOGRAPH-F9D7 +F9D8;5F8B;5F8B;5F8B;5F8B; # (律; 律; 律; 律; 律; ) CJK COMPATIBILITY IDEOGRAPH-F9D8 +F9D9;6144;6144;6144;6144; # (慄; 慄; 慄; 慄; 慄; ) CJK COMPATIBILITY IDEOGRAPH-F9D9 +F9DA;6817;6817;6817;6817; # (栗; 栗; 栗; 栗; 栗; ) CJK COMPATIBILITY IDEOGRAPH-F9DA +F9DB;7387;7387;7387;7387; # (率; 率; 率; 率; 率; ) CJK COMPATIBILITY IDEOGRAPH-F9DB +F9DC;9686;9686;9686;9686; # (隆; 隆; 隆; 隆; 隆; ) CJK COMPATIBILITY IDEOGRAPH-F9DC +F9DD;5229;5229;5229;5229; # (利; 利; 利; 利; 利; ) CJK COMPATIBILITY IDEOGRAPH-F9DD +F9DE;540F;540F;540F;540F; # (吏; 吏; 吏; 吏; 吏; ) CJK COMPATIBILITY IDEOGRAPH-F9DE +F9DF;5C65;5C65;5C65;5C65; # (履; 履; 履; 履; 履; ) CJK COMPATIBILITY IDEOGRAPH-F9DF +F9E0;6613;6613;6613;6613; # (易; 易; 易; 易; 易; ) CJK COMPATIBILITY IDEOGRAPH-F9E0 +F9E1;674E;674E;674E;674E; # (李; 李; 李; 李; 李; ) CJK COMPATIBILITY IDEOGRAPH-F9E1 +F9E2;68A8;68A8;68A8;68A8; # (梨; 梨; 梨; 梨; 梨; ) CJK COMPATIBILITY IDEOGRAPH-F9E2 +F9E3;6CE5;6CE5;6CE5;6CE5; # (泥; 泥; 泥; 泥; 泥; ) CJK COMPATIBILITY IDEOGRAPH-F9E3 +F9E4;7406;7406;7406;7406; # (理; 理; 理; 理; 理; ) CJK COMPATIBILITY IDEOGRAPH-F9E4 +F9E5;75E2;75E2;75E2;75E2; # (痢; 痢; 痢; 痢; 痢; ) CJK COMPATIBILITY IDEOGRAPH-F9E5 +F9E6;7F79;7F79;7F79;7F79; # (罹; 罹; 罹; 罹; 罹; ) CJK COMPATIBILITY IDEOGRAPH-F9E6 +F9E7;88CF;88CF;88CF;88CF; # (裏; 裏; 裏; 裏; 裏; ) CJK COMPATIBILITY IDEOGRAPH-F9E7 +F9E8;88E1;88E1;88E1;88E1; # (裡; 裡; 裡; 裡; 裡; ) CJK COMPATIBILITY IDEOGRAPH-F9E8 +F9E9;91CC;91CC;91CC;91CC; # (里; 里; 里; 里; 里; ) CJK COMPATIBILITY IDEOGRAPH-F9E9 +F9EA;96E2;96E2;96E2;96E2; # (離; 離; 離; 離; 離; ) CJK COMPATIBILITY IDEOGRAPH-F9EA +F9EB;533F;533F;533F;533F; # (匿; 匿; 匿; 匿; 匿; ) CJK COMPATIBILITY IDEOGRAPH-F9EB +F9EC;6EBA;6EBA;6EBA;6EBA; # (溺; 溺; 溺; 溺; 溺; ) CJK COMPATIBILITY IDEOGRAPH-F9EC +F9ED;541D;541D;541D;541D; # (吝; 吝; 吝; 吝; 吝; ) CJK COMPATIBILITY IDEOGRAPH-F9ED +F9EE;71D0;71D0;71D0;71D0; # (燐; 燐; 燐; 燐; 燐; ) CJK COMPATIBILITY IDEOGRAPH-F9EE +F9EF;7498;7498;7498;7498; # (璘; 璘; 璘; 璘; 璘; ) CJK COMPATIBILITY IDEOGRAPH-F9EF +F9F0;85FA;85FA;85FA;85FA; # (藺; 藺; 藺; 藺; 藺; ) CJK COMPATIBILITY IDEOGRAPH-F9F0 +F9F1;96A3;96A3;96A3;96A3; # (隣; 隣; 隣; 隣; 隣; ) CJK COMPATIBILITY IDEOGRAPH-F9F1 +F9F2;9C57;9C57;9C57;9C57; # (鱗; 鱗; 鱗; 鱗; 鱗; ) CJK COMPATIBILITY IDEOGRAPH-F9F2 +F9F3;9E9F;9E9F;9E9F;9E9F; # (麟; 麟; 麟; 麟; 麟; ) CJK COMPATIBILITY IDEOGRAPH-F9F3 +F9F4;6797;6797;6797;6797; # (林; 林; 林; 林; 林; ) CJK COMPATIBILITY IDEOGRAPH-F9F4 +F9F5;6DCB;6DCB;6DCB;6DCB; # (淋; 淋; 淋; 淋; 淋; ) CJK COMPATIBILITY IDEOGRAPH-F9F5 +F9F6;81E8;81E8;81E8;81E8; # (臨; 臨; 臨; 臨; 臨; ) CJK COMPATIBILITY IDEOGRAPH-F9F6 +F9F7;7ACB;7ACB;7ACB;7ACB; # (立; 立; 立; 立; 立; ) CJK COMPATIBILITY IDEOGRAPH-F9F7 +F9F8;7B20;7B20;7B20;7B20; # (笠; 笠; 笠; 笠; 笠; ) CJK COMPATIBILITY IDEOGRAPH-F9F8 +F9F9;7C92;7C92;7C92;7C92; # (粒; 粒; 粒; 粒; 粒; ) CJK COMPATIBILITY IDEOGRAPH-F9F9 +F9FA;72C0;72C0;72C0;72C0; # (狀; 狀; 狀; 狀; 狀; ) CJK COMPATIBILITY IDEOGRAPH-F9FA +F9FB;7099;7099;7099;7099; # (炙; 炙; 炙; 炙; 炙; ) CJK COMPATIBILITY IDEOGRAPH-F9FB +F9FC;8B58;8B58;8B58;8B58; # (識; 識; 識; 識; 識; ) CJK COMPATIBILITY IDEOGRAPH-F9FC +F9FD;4EC0;4EC0;4EC0;4EC0; # (什; 什; 什; 什; 什; ) CJK COMPATIBILITY IDEOGRAPH-F9FD +F9FE;8336;8336;8336;8336; # (茶; 茶; 茶; 茶; 茶; ) CJK COMPATIBILITY IDEOGRAPH-F9FE +F9FF;523A;523A;523A;523A; # (刺; 刺; 刺; 刺; 刺; ) CJK COMPATIBILITY IDEOGRAPH-F9FF +FA00;5207;5207;5207;5207; # (切; 切; 切; 切; 切; ) CJK COMPATIBILITY IDEOGRAPH-FA00 +FA01;5EA6;5EA6;5EA6;5EA6; # (度; 度; 度; 度; 度; ) CJK COMPATIBILITY IDEOGRAPH-FA01 +FA02;62D3;62D3;62D3;62D3; # (拓; 拓; 拓; 拓; 拓; ) CJK COMPATIBILITY IDEOGRAPH-FA02 +FA03;7CD6;7CD6;7CD6;7CD6; # (糖; 糖; 糖; 糖; 糖; ) CJK COMPATIBILITY IDEOGRAPH-FA03 +FA04;5B85;5B85;5B85;5B85; # (宅; 宅; 宅; 宅; 宅; ) CJK COMPATIBILITY IDEOGRAPH-FA04 +FA05;6D1E;6D1E;6D1E;6D1E; # (洞; 洞; 洞; 洞; 洞; ) CJK COMPATIBILITY IDEOGRAPH-FA05 +FA06;66B4;66B4;66B4;66B4; # (暴; 暴; 暴; 暴; 暴; ) CJK COMPATIBILITY IDEOGRAPH-FA06 +FA07;8F3B;8F3B;8F3B;8F3B; # (輻; 輻; 輻; 輻; 輻; ) CJK COMPATIBILITY IDEOGRAPH-FA07 +FA08;884C;884C;884C;884C; # (行; 行; 行; 行; 行; ) CJK COMPATIBILITY IDEOGRAPH-FA08 +FA09;964D;964D;964D;964D; # (降; 降; 降; 降; 降; ) CJK COMPATIBILITY IDEOGRAPH-FA09 +FA0A;898B;898B;898B;898B; # (見; 見; 見; 見; 見; ) CJK COMPATIBILITY IDEOGRAPH-FA0A +FA0B;5ED3;5ED3;5ED3;5ED3; # (廓; 廓; 廓; 廓; 廓; ) CJK COMPATIBILITY IDEOGRAPH-FA0B +FA0C;5140;5140;5140;5140; # (兀; 兀; 兀; 兀; 兀; ) CJK COMPATIBILITY IDEOGRAPH-FA0C +FA0D;55C0;55C0;55C0;55C0; # (嗀; 嗀; 嗀; 嗀; 嗀; ) CJK COMPATIBILITY IDEOGRAPH-FA0D +FA10;585A;585A;585A;585A; # (塚; 塚; 塚; 塚; 塚; ) CJK COMPATIBILITY IDEOGRAPH-FA10 +FA12;6674;6674;6674;6674; # (晴; 晴; 晴; 晴; 晴; ) CJK COMPATIBILITY IDEOGRAPH-FA12 +FA15;51DE;51DE;51DE;51DE; # (凞; 凞; 凞; 凞; 凞; ) CJK COMPATIBILITY IDEOGRAPH-FA15 +FA16;732A;732A;732A;732A; # (猪; 猪; 猪; 猪; 猪; ) CJK COMPATIBILITY IDEOGRAPH-FA16 +FA17;76CA;76CA;76CA;76CA; # (益; 益; 益; 益; 益; ) CJK COMPATIBILITY IDEOGRAPH-FA17 +FA18;793C;793C;793C;793C; # (礼; 礼; 礼; 礼; 礼; ) CJK COMPATIBILITY IDEOGRAPH-FA18 +FA19;795E;795E;795E;795E; # (神; 神; 神; 神; 神; ) CJK COMPATIBILITY IDEOGRAPH-FA19 +FA1A;7965;7965;7965;7965; # (祥; 祥; 祥; 祥; 祥; ) CJK COMPATIBILITY IDEOGRAPH-FA1A +FA1B;798F;798F;798F;798F; # (福; 福; 福; 福; 福; ) CJK COMPATIBILITY IDEOGRAPH-FA1B +FA1C;9756;9756;9756;9756; # (靖; 靖; 靖; 靖; 靖; ) CJK COMPATIBILITY IDEOGRAPH-FA1C +FA1D;7CBE;7CBE;7CBE;7CBE; # (精; 精; 精; 精; 精; ) CJK COMPATIBILITY IDEOGRAPH-FA1D +FA1E;7FBD;7FBD;7FBD;7FBD; # (羽; 羽; 羽; 羽; 羽; ) CJK COMPATIBILITY IDEOGRAPH-FA1E +FA20;8612;8612;8612;8612; # (蘒; 蘒; 蘒; 蘒; 蘒; ) CJK COMPATIBILITY IDEOGRAPH-FA20 +FA22;8AF8;8AF8;8AF8;8AF8; # (諸; 諸; 諸; 諸; 諸; ) CJK COMPATIBILITY IDEOGRAPH-FA22 +FA25;9038;9038;9038;9038; # (逸; 逸; 逸; 逸; 逸; ) CJK COMPATIBILITY IDEOGRAPH-FA25 +FA26;90FD;90FD;90FD;90FD; # (都; 都; 都; 都; 都; ) CJK COMPATIBILITY IDEOGRAPH-FA26 +FA2A;98EF;98EF;98EF;98EF; # (飯; 飯; 飯; 飯; 飯; ) CJK COMPATIBILITY IDEOGRAPH-FA2A +FA2B;98FC;98FC;98FC;98FC; # (飼; 飼; 飼; 飼; 飼; ) CJK COMPATIBILITY IDEOGRAPH-FA2B +FA2C;9928;9928;9928;9928; # (館; 館; 館; 館; 館; ) CJK COMPATIBILITY IDEOGRAPH-FA2C +FA2D;9DB4;9DB4;9DB4;9DB4; # (鶴; 鶴; 鶴; 鶴; 鶴; ) CJK COMPATIBILITY IDEOGRAPH-FA2D +FA2E;90DE;90DE;90DE;90DE; # (郞; 郞; 郞; 郞; 郞; ) CJK COMPATIBILITY IDEOGRAPH-FA2E +FA2F;96B7;96B7;96B7;96B7; # (隷; 隷; 隷; 隷; 隷; ) CJK COMPATIBILITY IDEOGRAPH-FA2F +FA30;4FAE;4FAE;4FAE;4FAE; # (侮; 侮; 侮; 侮; 侮; ) CJK COMPATIBILITY IDEOGRAPH-FA30 +FA31;50E7;50E7;50E7;50E7; # (僧; 僧; 僧; 僧; 僧; ) CJK COMPATIBILITY IDEOGRAPH-FA31 +FA32;514D;514D;514D;514D; # (免; 免; 免; 免; 免; ) CJK COMPATIBILITY IDEOGRAPH-FA32 +FA33;52C9;52C9;52C9;52C9; # (勉; 勉; 勉; 勉; 勉; ) CJK COMPATIBILITY IDEOGRAPH-FA33 +FA34;52E4;52E4;52E4;52E4; # (勤; 勤; 勤; 勤; 勤; ) CJK COMPATIBILITY IDEOGRAPH-FA34 +FA35;5351;5351;5351;5351; # (卑; 卑; 卑; 卑; 卑; ) CJK COMPATIBILITY IDEOGRAPH-FA35 +FA36;559D;559D;559D;559D; # (喝; 喝; 喝; 喝; 喝; ) CJK COMPATIBILITY IDEOGRAPH-FA36 +FA37;5606;5606;5606;5606; # (嘆; 嘆; 嘆; 嘆; 嘆; ) CJK COMPATIBILITY IDEOGRAPH-FA37 +FA38;5668;5668;5668;5668; # (器; 器; 器; 器; 器; ) CJK COMPATIBILITY IDEOGRAPH-FA38 +FA39;5840;5840;5840;5840; # (塀; 塀; 塀; 塀; 塀; ) CJK COMPATIBILITY IDEOGRAPH-FA39 +FA3A;58A8;58A8;58A8;58A8; # (墨; 墨; 墨; 墨; 墨; ) CJK COMPATIBILITY IDEOGRAPH-FA3A +FA3B;5C64;5C64;5C64;5C64; # (層; 層; 層; 層; 層; ) CJK COMPATIBILITY IDEOGRAPH-FA3B +FA3C;5C6E;5C6E;5C6E;5C6E; # (屮; 屮; 屮; 屮; 屮; ) CJK COMPATIBILITY IDEOGRAPH-FA3C +FA3D;6094;6094;6094;6094; # (悔; 悔; 悔; 悔; 悔; ) CJK COMPATIBILITY IDEOGRAPH-FA3D +FA3E;6168;6168;6168;6168; # (慨; 慨; 慨; 慨; 慨; ) CJK COMPATIBILITY IDEOGRAPH-FA3E +FA3F;618E;618E;618E;618E; # (憎; 憎; 憎; 憎; 憎; ) CJK COMPATIBILITY IDEOGRAPH-FA3F +FA40;61F2;61F2;61F2;61F2; # (懲; 懲; 懲; 懲; 懲; ) CJK COMPATIBILITY IDEOGRAPH-FA40 +FA41;654F;654F;654F;654F; # (敏; 敏; 敏; 敏; 敏; ) CJK COMPATIBILITY IDEOGRAPH-FA41 +FA42;65E2;65E2;65E2;65E2; # (既; 既; 既; 既; 既; ) CJK COMPATIBILITY IDEOGRAPH-FA42 +FA43;6691;6691;6691;6691; # (暑; 暑; 暑; 暑; 暑; ) CJK COMPATIBILITY IDEOGRAPH-FA43 +FA44;6885;6885;6885;6885; # (梅; 梅; 梅; 梅; 梅; ) CJK COMPATIBILITY IDEOGRAPH-FA44 +FA45;6D77;6D77;6D77;6D77; # (海; 海; 海; 海; 海; ) CJK COMPATIBILITY IDEOGRAPH-FA45 +FA46;6E1A;6E1A;6E1A;6E1A; # (渚; 渚; 渚; 渚; 渚; ) CJK COMPATIBILITY IDEOGRAPH-FA46 +FA47;6F22;6F22;6F22;6F22; # (漢; 漢; 漢; 漢; 漢; ) CJK COMPATIBILITY IDEOGRAPH-FA47 +FA48;716E;716E;716E;716E; # (煮; 煮; 煮; 煮; 煮; ) CJK COMPATIBILITY IDEOGRAPH-FA48 +FA49;722B;722B;722B;722B; # (爫; 爫; 爫; 爫; 爫; ) CJK COMPATIBILITY IDEOGRAPH-FA49 +FA4A;7422;7422;7422;7422; # (琢; 琢; 琢; 琢; 琢; ) CJK COMPATIBILITY IDEOGRAPH-FA4A +FA4B;7891;7891;7891;7891; # (碑; 碑; 碑; 碑; 碑; ) CJK COMPATIBILITY IDEOGRAPH-FA4B +FA4C;793E;793E;793E;793E; # (社; 社; 社; 社; 社; ) CJK COMPATIBILITY IDEOGRAPH-FA4C +FA4D;7949;7949;7949;7949; # (祉; 祉; 祉; 祉; 祉; ) CJK COMPATIBILITY IDEOGRAPH-FA4D +FA4E;7948;7948;7948;7948; # (祈; 祈; 祈; 祈; 祈; ) CJK COMPATIBILITY IDEOGRAPH-FA4E +FA4F;7950;7950;7950;7950; # (祐; 祐; 祐; 祐; 祐; ) CJK COMPATIBILITY IDEOGRAPH-FA4F +FA50;7956;7956;7956;7956; # (祖; 祖; 祖; 祖; 祖; ) CJK COMPATIBILITY IDEOGRAPH-FA50 +FA51;795D;795D;795D;795D; # (祝; 祝; 祝; 祝; 祝; ) CJK COMPATIBILITY IDEOGRAPH-FA51 +FA52;798D;798D;798D;798D; # (禍; 禍; 禍; 禍; 禍; ) CJK COMPATIBILITY IDEOGRAPH-FA52 +FA53;798E;798E;798E;798E; # (禎; 禎; 禎; 禎; 禎; ) CJK COMPATIBILITY IDEOGRAPH-FA53 +FA54;7A40;7A40;7A40;7A40; # (穀; 穀; 穀; 穀; 穀; ) CJK COMPATIBILITY IDEOGRAPH-FA54 +FA55;7A81;7A81;7A81;7A81; # (突; 突; 突; 突; 突; ) CJK COMPATIBILITY IDEOGRAPH-FA55 +FA56;7BC0;7BC0;7BC0;7BC0; # (節; 節; 節; 節; 節; ) CJK COMPATIBILITY IDEOGRAPH-FA56 +FA57;7DF4;7DF4;7DF4;7DF4; # (練; 練; 練; 練; 練; ) CJK COMPATIBILITY IDEOGRAPH-FA57 +FA58;7E09;7E09;7E09;7E09; # (縉; 縉; 縉; 縉; 縉; ) CJK COMPATIBILITY IDEOGRAPH-FA58 +FA59;7E41;7E41;7E41;7E41; # (繁; 繁; 繁; 繁; 繁; ) CJK COMPATIBILITY IDEOGRAPH-FA59 +FA5A;7F72;7F72;7F72;7F72; # (署; 署; 署; 署; 署; ) CJK COMPATIBILITY IDEOGRAPH-FA5A +FA5B;8005;8005;8005;8005; # (者; 者; 者; 者; 者; ) CJK COMPATIBILITY IDEOGRAPH-FA5B +FA5C;81ED;81ED;81ED;81ED; # (臭; 臭; 臭; 臭; 臭; ) CJK COMPATIBILITY IDEOGRAPH-FA5C +FA5D;8279;8279;8279;8279; # (艹; 艹; 艹; 艹; 艹; ) CJK COMPATIBILITY IDEOGRAPH-FA5D +FA5E;8279;8279;8279;8279; # (艹; 艹; 艹; 艹; 艹; ) CJK COMPATIBILITY IDEOGRAPH-FA5E +FA5F;8457;8457;8457;8457; # (著; 著; 著; 著; 著; ) CJK COMPATIBILITY IDEOGRAPH-FA5F +FA60;8910;8910;8910;8910; # (褐; 褐; 褐; 褐; 褐; ) CJK COMPATIBILITY IDEOGRAPH-FA60 +FA61;8996;8996;8996;8996; # (視; 視; 視; 視; 視; ) CJK COMPATIBILITY IDEOGRAPH-FA61 +FA62;8B01;8B01;8B01;8B01; # (謁; 謁; 謁; 謁; 謁; ) CJK COMPATIBILITY IDEOGRAPH-FA62 +FA63;8B39;8B39;8B39;8B39; # (謹; 謹; 謹; 謹; 謹; ) CJK COMPATIBILITY IDEOGRAPH-FA63 +FA64;8CD3;8CD3;8CD3;8CD3; # (賓; 賓; 賓; 賓; 賓; ) CJK COMPATIBILITY IDEOGRAPH-FA64 +FA65;8D08;8D08;8D08;8D08; # (贈; 贈; 贈; 贈; 贈; ) CJK COMPATIBILITY IDEOGRAPH-FA65 +FA66;8FB6;8FB6;8FB6;8FB6; # (辶; 辶; 辶; 辶; 辶; ) CJK COMPATIBILITY IDEOGRAPH-FA66 +FA67;9038;9038;9038;9038; # (逸; 逸; 逸; 逸; 逸; ) CJK COMPATIBILITY IDEOGRAPH-FA67 +FA68;96E3;96E3;96E3;96E3; # (難; 難; 難; 難; 難; ) CJK COMPATIBILITY IDEOGRAPH-FA68 +FA69;97FF;97FF;97FF;97FF; # (響; 響; 響; 響; 響; ) CJK COMPATIBILITY IDEOGRAPH-FA69 +FA6A;983B;983B;983B;983B; # (頻; 頻; 頻; 頻; 頻; ) CJK COMPATIBILITY IDEOGRAPH-FA6A +FA6B;6075;6075;6075;6075; # (恵; 恵; 恵; 恵; 恵; ) CJK COMPATIBILITY IDEOGRAPH-FA6B +FA6C;242EE;242EE;242EE;242EE; # (𤋮; 𤋮; 𤋮; 𤋮; 𤋮; ) CJK COMPATIBILITY IDEOGRAPH-FA6C +FA6D;8218;8218;8218;8218; # (舘; 舘; 舘; 舘; 舘; ) CJK COMPATIBILITY IDEOGRAPH-FA6D +FA70;4E26;4E26;4E26;4E26; # (並; 並; 並; 並; 並; ) CJK COMPATIBILITY IDEOGRAPH-FA70 +FA71;51B5;51B5;51B5;51B5; # (况; 况; 况; 况; 况; ) CJK COMPATIBILITY IDEOGRAPH-FA71 +FA72;5168;5168;5168;5168; # (全; 全; 全; 全; 全; ) CJK COMPATIBILITY IDEOGRAPH-FA72 +FA73;4F80;4F80;4F80;4F80; # (侀; 侀; 侀; 侀; 侀; ) CJK COMPATIBILITY IDEOGRAPH-FA73 +FA74;5145;5145;5145;5145; # (充; 充; 充; 充; 充; ) CJK COMPATIBILITY IDEOGRAPH-FA74 +FA75;5180;5180;5180;5180; # (冀; 冀; 冀; 冀; 冀; ) CJK COMPATIBILITY IDEOGRAPH-FA75 +FA76;52C7;52C7;52C7;52C7; # (勇; 勇; 勇; 勇; 勇; ) CJK COMPATIBILITY IDEOGRAPH-FA76 +FA77;52FA;52FA;52FA;52FA; # (勺; 勺; 勺; 勺; 勺; ) CJK COMPATIBILITY IDEOGRAPH-FA77 +FA78;559D;559D;559D;559D; # (喝; 喝; 喝; 喝; 喝; ) CJK COMPATIBILITY IDEOGRAPH-FA78 +FA79;5555;5555;5555;5555; # (啕; 啕; 啕; 啕; 啕; ) CJK COMPATIBILITY IDEOGRAPH-FA79 +FA7A;5599;5599;5599;5599; # (喙; 喙; 喙; 喙; 喙; ) CJK COMPATIBILITY IDEOGRAPH-FA7A +FA7B;55E2;55E2;55E2;55E2; # (嗢; 嗢; 嗢; 嗢; 嗢; ) CJK COMPATIBILITY IDEOGRAPH-FA7B +FA7C;585A;585A;585A;585A; # (塚; 塚; 塚; 塚; 塚; ) CJK COMPATIBILITY IDEOGRAPH-FA7C +FA7D;58B3;58B3;58B3;58B3; # (墳; 墳; 墳; 墳; 墳; ) CJK COMPATIBILITY IDEOGRAPH-FA7D +FA7E;5944;5944;5944;5944; # (奄; 奄; 奄; 奄; 奄; ) CJK COMPATIBILITY IDEOGRAPH-FA7E +FA7F;5954;5954;5954;5954; # (奔; 奔; 奔; 奔; 奔; ) CJK COMPATIBILITY IDEOGRAPH-FA7F +FA80;5A62;5A62;5A62;5A62; # (婢; 婢; 婢; 婢; 婢; ) CJK COMPATIBILITY IDEOGRAPH-FA80 +FA81;5B28;5B28;5B28;5B28; # (嬨; 嬨; 嬨; 嬨; 嬨; ) CJK COMPATIBILITY IDEOGRAPH-FA81 +FA82;5ED2;5ED2;5ED2;5ED2; # (廒; 廒; 廒; 廒; 廒; ) CJK COMPATIBILITY IDEOGRAPH-FA82 +FA83;5ED9;5ED9;5ED9;5ED9; # (廙; 廙; 廙; 廙; 廙; ) CJK COMPATIBILITY IDEOGRAPH-FA83 +FA84;5F69;5F69;5F69;5F69; # (彩; 彩; 彩; 彩; 彩; ) CJK COMPATIBILITY IDEOGRAPH-FA84 +FA85;5FAD;5FAD;5FAD;5FAD; # (徭; 徭; 徭; 徭; 徭; ) CJK COMPATIBILITY IDEOGRAPH-FA85 +FA86;60D8;60D8;60D8;60D8; # (惘; 惘; 惘; 惘; 惘; ) CJK COMPATIBILITY IDEOGRAPH-FA86 +FA87;614E;614E;614E;614E; # (慎; 慎; 慎; 慎; 慎; ) CJK COMPATIBILITY IDEOGRAPH-FA87 +FA88;6108;6108;6108;6108; # (愈; 愈; 愈; 愈; 愈; ) CJK COMPATIBILITY IDEOGRAPH-FA88 +FA89;618E;618E;618E;618E; # (憎; 憎; 憎; 憎; 憎; ) CJK COMPATIBILITY IDEOGRAPH-FA89 +FA8A;6160;6160;6160;6160; # (慠; 慠; 慠; 慠; 慠; ) CJK COMPATIBILITY IDEOGRAPH-FA8A +FA8B;61F2;61F2;61F2;61F2; # (懲; 懲; 懲; 懲; 懲; ) CJK COMPATIBILITY IDEOGRAPH-FA8B +FA8C;6234;6234;6234;6234; # (戴; 戴; 戴; 戴; 戴; ) CJK COMPATIBILITY IDEOGRAPH-FA8C +FA8D;63C4;63C4;63C4;63C4; # (揄; 揄; 揄; 揄; 揄; ) CJK COMPATIBILITY IDEOGRAPH-FA8D +FA8E;641C;641C;641C;641C; # (搜; 搜; 搜; 搜; 搜; ) CJK COMPATIBILITY IDEOGRAPH-FA8E +FA8F;6452;6452;6452;6452; # (摒; 摒; 摒; 摒; 摒; ) CJK COMPATIBILITY IDEOGRAPH-FA8F +FA90;6556;6556;6556;6556; # (敖; 敖; 敖; 敖; 敖; ) CJK COMPATIBILITY IDEOGRAPH-FA90 +FA91;6674;6674;6674;6674; # (晴; 晴; 晴; 晴; 晴; ) CJK COMPATIBILITY IDEOGRAPH-FA91 +FA92;6717;6717;6717;6717; # (朗; 朗; 朗; 朗; 朗; ) CJK COMPATIBILITY IDEOGRAPH-FA92 +FA93;671B;671B;671B;671B; # (望; 望; 望; 望; 望; ) CJK COMPATIBILITY IDEOGRAPH-FA93 +FA94;6756;6756;6756;6756; # (杖; 杖; 杖; 杖; 杖; ) CJK COMPATIBILITY IDEOGRAPH-FA94 +FA95;6B79;6B79;6B79;6B79; # (歹; 歹; 歹; 歹; 歹; ) CJK COMPATIBILITY IDEOGRAPH-FA95 +FA96;6BBA;6BBA;6BBA;6BBA; # (殺; 殺; 殺; 殺; 殺; ) CJK COMPATIBILITY IDEOGRAPH-FA96 +FA97;6D41;6D41;6D41;6D41; # (流; 流; 流; 流; 流; ) CJK COMPATIBILITY IDEOGRAPH-FA97 +FA98;6EDB;6EDB;6EDB;6EDB; # (滛; 滛; 滛; 滛; 滛; ) CJK COMPATIBILITY IDEOGRAPH-FA98 +FA99;6ECB;6ECB;6ECB;6ECB; # (滋; 滋; 滋; 滋; 滋; ) CJK COMPATIBILITY IDEOGRAPH-FA99 +FA9A;6F22;6F22;6F22;6F22; # (漢; 漢; 漢; 漢; 漢; ) CJK COMPATIBILITY IDEOGRAPH-FA9A +FA9B;701E;701E;701E;701E; # (瀞; 瀞; 瀞; 瀞; 瀞; ) CJK COMPATIBILITY IDEOGRAPH-FA9B +FA9C;716E;716E;716E;716E; # (煮; 煮; 煮; 煮; 煮; ) CJK COMPATIBILITY IDEOGRAPH-FA9C +FA9D;77A7;77A7;77A7;77A7; # (瞧; 瞧; 瞧; 瞧; 瞧; ) CJK COMPATIBILITY IDEOGRAPH-FA9D +FA9E;7235;7235;7235;7235; # (爵; 爵; 爵; 爵; 爵; ) CJK COMPATIBILITY IDEOGRAPH-FA9E +FA9F;72AF;72AF;72AF;72AF; # (犯; 犯; 犯; 犯; 犯; ) CJK COMPATIBILITY IDEOGRAPH-FA9F +FAA0;732A;732A;732A;732A; # (猪; 猪; 猪; 猪; 猪; ) CJK COMPATIBILITY IDEOGRAPH-FAA0 +FAA1;7471;7471;7471;7471; # (瑱; 瑱; 瑱; 瑱; 瑱; ) CJK COMPATIBILITY IDEOGRAPH-FAA1 +FAA2;7506;7506;7506;7506; # (甆; 甆; 甆; 甆; 甆; ) CJK COMPATIBILITY IDEOGRAPH-FAA2 +FAA3;753B;753B;753B;753B; # (画; 画; 画; 画; 画; ) CJK COMPATIBILITY IDEOGRAPH-FAA3 +FAA4;761D;761D;761D;761D; # (瘝; 瘝; 瘝; 瘝; 瘝; ) CJK COMPATIBILITY IDEOGRAPH-FAA4 +FAA5;761F;761F;761F;761F; # (瘟; 瘟; 瘟; 瘟; 瘟; ) CJK COMPATIBILITY IDEOGRAPH-FAA5 +FAA6;76CA;76CA;76CA;76CA; # (益; 益; 益; 益; 益; ) CJK COMPATIBILITY IDEOGRAPH-FAA6 +FAA7;76DB;76DB;76DB;76DB; # (盛; 盛; 盛; 盛; 盛; ) CJK COMPATIBILITY IDEOGRAPH-FAA7 +FAA8;76F4;76F4;76F4;76F4; # (直; 直; 直; 直; 直; ) CJK COMPATIBILITY IDEOGRAPH-FAA8 +FAA9;774A;774A;774A;774A; # (睊; 睊; 睊; 睊; 睊; ) CJK COMPATIBILITY IDEOGRAPH-FAA9 +FAAA;7740;7740;7740;7740; # (着; 着; 着; 着; 着; ) CJK COMPATIBILITY IDEOGRAPH-FAAA +FAAB;78CC;78CC;78CC;78CC; # (磌; 磌; 磌; 磌; 磌; ) CJK COMPATIBILITY IDEOGRAPH-FAAB +FAAC;7AB1;7AB1;7AB1;7AB1; # (窱; 窱; 窱; 窱; 窱; ) CJK COMPATIBILITY IDEOGRAPH-FAAC +FAAD;7BC0;7BC0;7BC0;7BC0; # (節; 節; 節; 節; 節; ) CJK COMPATIBILITY IDEOGRAPH-FAAD +FAAE;7C7B;7C7B;7C7B;7C7B; # (类; 类; 类; 类; 类; ) CJK COMPATIBILITY IDEOGRAPH-FAAE +FAAF;7D5B;7D5B;7D5B;7D5B; # (絛; 絛; 絛; 絛; 絛; ) CJK COMPATIBILITY IDEOGRAPH-FAAF +FAB0;7DF4;7DF4;7DF4;7DF4; # (練; 練; 練; 練; 練; ) CJK COMPATIBILITY IDEOGRAPH-FAB0 +FAB1;7F3E;7F3E;7F3E;7F3E; # (缾; 缾; 缾; 缾; 缾; ) CJK COMPATIBILITY IDEOGRAPH-FAB1 +FAB2;8005;8005;8005;8005; # (者; 者; 者; 者; 者; ) CJK COMPATIBILITY IDEOGRAPH-FAB2 +FAB3;8352;8352;8352;8352; # (荒; 荒; 荒; 荒; 荒; ) CJK COMPATIBILITY IDEOGRAPH-FAB3 +FAB4;83EF;83EF;83EF;83EF; # (華; 華; 華; 華; 華; ) CJK COMPATIBILITY IDEOGRAPH-FAB4 +FAB5;8779;8779;8779;8779; # (蝹; 蝹; 蝹; 蝹; 蝹; ) CJK COMPATIBILITY IDEOGRAPH-FAB5 +FAB6;8941;8941;8941;8941; # (襁; 襁; 襁; 襁; 襁; ) CJK COMPATIBILITY IDEOGRAPH-FAB6 +FAB7;8986;8986;8986;8986; # (覆; 覆; 覆; 覆; 覆; ) CJK COMPATIBILITY IDEOGRAPH-FAB7 +FAB8;8996;8996;8996;8996; # (視; 視; 視; 視; 視; ) CJK COMPATIBILITY IDEOGRAPH-FAB8 +FAB9;8ABF;8ABF;8ABF;8ABF; # (調; 調; 調; 調; 調; ) CJK COMPATIBILITY IDEOGRAPH-FAB9 +FABA;8AF8;8AF8;8AF8;8AF8; # (諸; 諸; 諸; 諸; 諸; ) CJK COMPATIBILITY IDEOGRAPH-FABA +FABB;8ACB;8ACB;8ACB;8ACB; # (請; 請; 請; 請; 請; ) CJK COMPATIBILITY IDEOGRAPH-FABB +FABC;8B01;8B01;8B01;8B01; # (謁; 謁; 謁; 謁; 謁; ) CJK COMPATIBILITY IDEOGRAPH-FABC +FABD;8AFE;8AFE;8AFE;8AFE; # (諾; 諾; 諾; 諾; 諾; ) CJK COMPATIBILITY IDEOGRAPH-FABD +FABE;8AED;8AED;8AED;8AED; # (諭; 諭; 諭; 諭; 諭; ) CJK COMPATIBILITY IDEOGRAPH-FABE +FABF;8B39;8B39;8B39;8B39; # (謹; 謹; 謹; 謹; 謹; ) CJK COMPATIBILITY IDEOGRAPH-FABF +FAC0;8B8A;8B8A;8B8A;8B8A; # (變; 變; 變; 變; 變; ) CJK COMPATIBILITY IDEOGRAPH-FAC0 +FAC1;8D08;8D08;8D08;8D08; # (贈; 贈; 贈; 贈; 贈; ) CJK COMPATIBILITY IDEOGRAPH-FAC1 +FAC2;8F38;8F38;8F38;8F38; # (輸; 輸; 輸; 輸; 輸; ) CJK COMPATIBILITY IDEOGRAPH-FAC2 +FAC3;9072;9072;9072;9072; # (遲; 遲; 遲; 遲; 遲; ) CJK COMPATIBILITY IDEOGRAPH-FAC3 +FAC4;9199;9199;9199;9199; # (醙; 醙; 醙; 醙; 醙; ) CJK COMPATIBILITY IDEOGRAPH-FAC4 +FAC5;9276;9276;9276;9276; # (鉶; 鉶; 鉶; 鉶; 鉶; ) CJK COMPATIBILITY IDEOGRAPH-FAC5 +FAC6;967C;967C;967C;967C; # (陼; 陼; 陼; 陼; 陼; ) CJK COMPATIBILITY IDEOGRAPH-FAC6 +FAC7;96E3;96E3;96E3;96E3; # (難; 難; 難; 難; 難; ) CJK COMPATIBILITY IDEOGRAPH-FAC7 +FAC8;9756;9756;9756;9756; # (靖; 靖; 靖; 靖; 靖; ) CJK COMPATIBILITY IDEOGRAPH-FAC8 +FAC9;97DB;97DB;97DB;97DB; # (韛; 韛; 韛; 韛; 韛; ) CJK COMPATIBILITY IDEOGRAPH-FAC9 +FACA;97FF;97FF;97FF;97FF; # (響; 響; 響; 響; 響; ) CJK COMPATIBILITY IDEOGRAPH-FACA +FACB;980B;980B;980B;980B; # (頋; 頋; 頋; 頋; 頋; ) CJK COMPATIBILITY IDEOGRAPH-FACB +FACC;983B;983B;983B;983B; # (頻; 頻; 頻; 頻; 頻; ) CJK COMPATIBILITY IDEOGRAPH-FACC +FACD;9B12;9B12;9B12;9B12; # (鬒; 鬒; 鬒; 鬒; 鬒; ) CJK COMPATIBILITY IDEOGRAPH-FACD +FACE;9F9C;9F9C;9F9C;9F9C; # (龜; 龜; 龜; 龜; 龜; ) CJK COMPATIBILITY IDEOGRAPH-FACE +FACF;2284A;2284A;2284A;2284A; # (𢡊; 𢡊; 𢡊; 𢡊; 𢡊; ) CJK COMPATIBILITY IDEOGRAPH-FACF +FAD0;22844;22844;22844;22844; # (𢡄; 𢡄; 𢡄; 𢡄; 𢡄; ) CJK COMPATIBILITY IDEOGRAPH-FAD0 +FAD1;233D5;233D5;233D5;233D5; # (𣏕; 𣏕; 𣏕; 𣏕; 𣏕; ) CJK COMPATIBILITY IDEOGRAPH-FAD1 +FAD2;3B9D;3B9D;3B9D;3B9D; # (㮝; 㮝; 㮝; 㮝; 㮝; ) CJK COMPATIBILITY IDEOGRAPH-FAD2 +FAD3;4018;4018;4018;4018; # (䀘; 䀘; 䀘; 䀘; 䀘; ) CJK COMPATIBILITY IDEOGRAPH-FAD3 +FAD4;4039;4039;4039;4039; # (䀹; 䀹; 䀹; 䀹; 䀹; ) CJK COMPATIBILITY IDEOGRAPH-FAD4 +FAD5;25249;25249;25249;25249; # (𥉉; 𥉉; 𥉉; 𥉉; 𥉉; ) CJK COMPATIBILITY IDEOGRAPH-FAD5 +FAD6;25CD0;25CD0;25CD0;25CD0; # (𥳐; 𥳐; 𥳐; 𥳐; 𥳐; ) CJK COMPATIBILITY IDEOGRAPH-FAD6 +FAD7;27ED3;27ED3;27ED3;27ED3; # (𧻓; 𧻓; 𧻓; 𧻓; 𧻓; ) CJK COMPATIBILITY IDEOGRAPH-FAD7 +FAD8;9F43;9F43;9F43;9F43; # (齃; 齃; 齃; 齃; 齃; ) CJK COMPATIBILITY IDEOGRAPH-FAD8 +FAD9;9F8E;9F8E;9F8E;9F8E; # (龎; 龎; 龎; 龎; 龎; ) CJK COMPATIBILITY IDEOGRAPH-FAD9 +FB00;FB00;FB00;0066 0066;0066 0066; # (ff; ff; ff; ff; ff; ) LATIN SMALL LIGATURE FF +FB01;FB01;FB01;0066 0069;0066 0069; # (fi; fi; fi; fi; fi; ) LATIN SMALL LIGATURE FI +FB02;FB02;FB02;0066 006C;0066 006C; # (fl; fl; fl; fl; fl; ) LATIN SMALL LIGATURE FL +FB03;FB03;FB03;0066 0066 0069;0066 0066 0069; # (ffi; ffi; ffi; ffi; ffi; ) LATIN SMALL LIGATURE FFI +FB04;FB04;FB04;0066 0066 006C;0066 0066 006C; # (ffl; ffl; ffl; ffl; ffl; ) LATIN SMALL LIGATURE FFL +FB05;FB05;FB05;0073 0074;0073 0074; # (ſt; ſt; ſt; st; st; ) LATIN SMALL LIGATURE LONG S T +FB06;FB06;FB06;0073 0074;0073 0074; # (st; st; st; st; st; ) LATIN SMALL LIGATURE ST +FB13;FB13;FB13;0574 0576;0574 0576; # (ﬓ; ﬓ; ﬓ; մն; մն; ) ARMENIAN SMALL LIGATURE MEN NOW +FB14;FB14;FB14;0574 0565;0574 0565; # (ﬔ; ﬔ; ﬔ; մե; մե; ) ARMENIAN SMALL LIGATURE MEN ECH +FB15;FB15;FB15;0574 056B;0574 056B; # (ﬕ; ﬕ; ﬕ; մի; մի; ) ARMENIAN SMALL LIGATURE MEN INI +FB16;FB16;FB16;057E 0576;057E 0576; # (ﬖ; ﬖ; ﬖ; վն; վն; ) ARMENIAN SMALL LIGATURE VEW NOW +FB17;FB17;FB17;0574 056D;0574 056D; # (ﬗ; ﬗ; ﬗ; մխ; մխ; ) ARMENIAN SMALL LIGATURE MEN XEH +FB1D;05D9 05B4;05D9 05B4;05D9 05B4;05D9 05B4; # (יִ; י◌ִ; י◌ִ; י◌ִ; י◌ִ; ) HEBREW LETTER YOD WITH HIRIQ +FB1F;05F2 05B7;05F2 05B7;05F2 05B7;05F2 05B7; # (ײַ; ײ◌ַ; ײ◌ַ; ײ◌ַ; ײ◌ַ; ) HEBREW LIGATURE YIDDISH YOD YOD PATAH +FB20;FB20;FB20;05E2;05E2; # (ﬠ; ﬠ; ﬠ; ע; ע; ) HEBREW LETTER ALTERNATIVE AYIN +FB21;FB21;FB21;05D0;05D0; # (ﬡ; ﬡ; ﬡ; א; א; ) HEBREW LETTER WIDE ALEF +FB22;FB22;FB22;05D3;05D3; # (ﬢ; ﬢ; ﬢ; ד; ד; ) HEBREW LETTER WIDE DALET +FB23;FB23;FB23;05D4;05D4; # (ﬣ; ﬣ; ﬣ; ה; ה; ) HEBREW LETTER WIDE HE +FB24;FB24;FB24;05DB;05DB; # (ﬤ; ﬤ; ﬤ; כ; כ; ) HEBREW LETTER WIDE KAF +FB25;FB25;FB25;05DC;05DC; # (ﬥ; ﬥ; ﬥ; ל; ל; ) HEBREW LETTER WIDE LAMED +FB26;FB26;FB26;05DD;05DD; # (ﬦ; ﬦ; ﬦ; ם; ם; ) HEBREW LETTER WIDE FINAL MEM +FB27;FB27;FB27;05E8;05E8; # (ﬧ; ﬧ; ﬧ; ר; ר; ) HEBREW LETTER WIDE RESH +FB28;FB28;FB28;05EA;05EA; # (ﬨ; ﬨ; ﬨ; ת; ת; ) HEBREW LETTER WIDE TAV +FB29;FB29;FB29;002B;002B; # (﬩; ﬩; ﬩; +; +; ) HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A;05E9 05C1;05E9 05C1;05E9 05C1;05E9 05C1; # (שׁ; ש◌ׁ; ש◌ׁ; ש◌ׁ; ש◌ׁ; ) HEBREW LETTER SHIN WITH SHIN DOT +FB2B;05E9 05C2;05E9 05C2;05E9 05C2;05E9 05C2; # (שׂ; ש◌ׂ; ש◌ׂ; ש◌ׂ; ש◌ׂ; ) HEBREW LETTER SHIN WITH SIN DOT +FB2C;05E9 05BC 05C1;05E9 05BC 05C1;05E9 05BC 05C1;05E9 05BC 05C1; # (שּׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ש◌ּ◌ׁ; ) HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT +FB2D;05E9 05BC 05C2;05E9 05BC 05C2;05E9 05BC 05C2;05E9 05BC 05C2; # (שּׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ש◌ּ◌ׂ; ) HEBREW LETTER SHIN WITH DAGESH AND SIN DOT +FB2E;05D0 05B7;05D0 05B7;05D0 05B7;05D0 05B7; # (אַ; א◌ַ; א◌ַ; א◌ַ; א◌ַ; ) HEBREW LETTER ALEF WITH PATAH +FB2F;05D0 05B8;05D0 05B8;05D0 05B8;05D0 05B8; # (אָ; א◌ָ; א◌ָ; א◌ָ; א◌ָ; ) HEBREW LETTER ALEF WITH QAMATS +FB30;05D0 05BC;05D0 05BC;05D0 05BC;05D0 05BC; # (אּ; א◌ּ; א◌ּ; א◌ּ; א◌ּ; ) HEBREW LETTER ALEF WITH MAPIQ +FB31;05D1 05BC;05D1 05BC;05D1 05BC;05D1 05BC; # (בּ; ב◌ּ; ב◌ּ; ב◌ּ; ב◌ּ; ) HEBREW LETTER BET WITH DAGESH +FB32;05D2 05BC;05D2 05BC;05D2 05BC;05D2 05BC; # (גּ; ג◌ּ; ג◌ּ; ג◌ּ; ג◌ּ; ) HEBREW LETTER GIMEL WITH DAGESH +FB33;05D3 05BC;05D3 05BC;05D3 05BC;05D3 05BC; # (דּ; ד◌ּ; ד◌ּ; ד◌ּ; ד◌ּ; ) HEBREW LETTER DALET WITH DAGESH +FB34;05D4 05BC;05D4 05BC;05D4 05BC;05D4 05BC; # (הּ; ה◌ּ; ה◌ּ; ה◌ּ; ה◌ּ; ) HEBREW LETTER HE WITH MAPIQ +FB35;05D5 05BC;05D5 05BC;05D5 05BC;05D5 05BC; # (וּ; ו◌ּ; ו◌ּ; ו◌ּ; ו◌ּ; ) HEBREW LETTER VAV WITH DAGESH +FB36;05D6 05BC;05D6 05BC;05D6 05BC;05D6 05BC; # (זּ; ז◌ּ; ז◌ּ; ז◌ּ; ז◌ּ; ) HEBREW LETTER ZAYIN WITH DAGESH +FB38;05D8 05BC;05D8 05BC;05D8 05BC;05D8 05BC; # (טּ; ט◌ּ; ט◌ּ; ט◌ּ; ט◌ּ; ) HEBREW LETTER TET WITH DAGESH +FB39;05D9 05BC;05D9 05BC;05D9 05BC;05D9 05BC; # (יּ; י◌ּ; י◌ּ; י◌ּ; י◌ּ; ) HEBREW LETTER YOD WITH DAGESH +FB3A;05DA 05BC;05DA 05BC;05DA 05BC;05DA 05BC; # (ךּ; ך◌ּ; ך◌ּ; ך◌ּ; ך◌ּ; ) HEBREW LETTER FINAL KAF WITH DAGESH +FB3B;05DB 05BC;05DB 05BC;05DB 05BC;05DB 05BC; # (כּ; כ◌ּ; כ◌ּ; כ◌ּ; כ◌ּ; ) HEBREW LETTER KAF WITH DAGESH +FB3C;05DC 05BC;05DC 05BC;05DC 05BC;05DC 05BC; # (לּ; ל◌ּ; ל◌ּ; ל◌ּ; ל◌ּ; ) HEBREW LETTER LAMED WITH DAGESH +FB3E;05DE 05BC;05DE 05BC;05DE 05BC;05DE 05BC; # (מּ; מ◌ּ; מ◌ּ; מ◌ּ; מ◌ּ; ) HEBREW LETTER MEM WITH DAGESH +FB40;05E0 05BC;05E0 05BC;05E0 05BC;05E0 05BC; # (נּ; נ◌ּ; נ◌ּ; נ◌ּ; נ◌ּ; ) HEBREW LETTER NUN WITH DAGESH +FB41;05E1 05BC;05E1 05BC;05E1 05BC;05E1 05BC; # (סּ; ס◌ּ; ס◌ּ; ס◌ּ; ס◌ּ; ) HEBREW LETTER SAMEKH WITH DAGESH +FB43;05E3 05BC;05E3 05BC;05E3 05BC;05E3 05BC; # (ףּ; ף◌ּ; ף◌ּ; ף◌ּ; ף◌ּ; ) HEBREW LETTER FINAL PE WITH DAGESH +FB44;05E4 05BC;05E4 05BC;05E4 05BC;05E4 05BC; # (פּ; פ◌ּ; פ◌ּ; פ◌ּ; פ◌ּ; ) HEBREW LETTER PE WITH DAGESH +FB46;05E6 05BC;05E6 05BC;05E6 05BC;05E6 05BC; # (צּ; צ◌ּ; צ◌ּ; צ◌ּ; צ◌ּ; ) HEBREW LETTER TSADI WITH DAGESH +FB47;05E7 05BC;05E7 05BC;05E7 05BC;05E7 05BC; # (קּ; ק◌ּ; ק◌ּ; ק◌ּ; ק◌ּ; ) HEBREW LETTER QOF WITH DAGESH +FB48;05E8 05BC;05E8 05BC;05E8 05BC;05E8 05BC; # (רּ; ר◌ּ; ר◌ּ; ר◌ּ; ר◌ּ; ) HEBREW LETTER RESH WITH DAGESH +FB49;05E9 05BC;05E9 05BC;05E9 05BC;05E9 05BC; # (שּ; ש◌ּ; ש◌ּ; ש◌ּ; ש◌ּ; ) HEBREW LETTER SHIN WITH DAGESH +FB4A;05EA 05BC;05EA 05BC;05EA 05BC;05EA 05BC; # (תּ; ת◌ּ; ת◌ּ; ת◌ּ; ת◌ּ; ) HEBREW LETTER TAV WITH DAGESH +FB4B;05D5 05B9;05D5 05B9;05D5 05B9;05D5 05B9; # (וֹ; ו◌ֹ; ו◌ֹ; ו◌ֹ; ו◌ֹ; ) HEBREW LETTER VAV WITH HOLAM +FB4C;05D1 05BF;05D1 05BF;05D1 05BF;05D1 05BF; # (בֿ; ב◌ֿ; ב◌ֿ; ב◌ֿ; ב◌ֿ; ) HEBREW LETTER BET WITH RAFE +FB4D;05DB 05BF;05DB 05BF;05DB 05BF;05DB 05BF; # (כֿ; כ◌ֿ; כ◌ֿ; כ◌ֿ; כ◌ֿ; ) HEBREW LETTER KAF WITH RAFE +FB4E;05E4 05BF;05E4 05BF;05E4 05BF;05E4 05BF; # (פֿ; פ◌ֿ; פ◌ֿ; פ◌ֿ; פ◌ֿ; ) HEBREW LETTER PE WITH RAFE +FB4F;FB4F;FB4F;05D0 05DC;05D0 05DC; # (ﭏ; ﭏ; ﭏ; אל; אל; ) HEBREW LIGATURE ALEF LAMED +FB50;FB50;FB50;0671;0671; # (ﭐ; ﭐ; ﭐ; ٱ; ٱ; ) ARABIC LETTER ALEF WASLA ISOLATED FORM +FB51;FB51;FB51;0671;0671; # (ﭑ; ﭑ; ﭑ; ٱ; ٱ; ) ARABIC LETTER ALEF WASLA FINAL FORM +FB52;FB52;FB52;067B;067B; # (ﭒ; ﭒ; ﭒ; ٻ; ٻ; ) ARABIC LETTER BEEH ISOLATED FORM +FB53;FB53;FB53;067B;067B; # (ﭓ; ﭓ; ﭓ; ٻ; ٻ; ) ARABIC LETTER BEEH FINAL FORM +FB54;FB54;FB54;067B;067B; # (ﭔ; ﭔ; ﭔ; ٻ; ٻ; ) ARABIC LETTER BEEH INITIAL FORM +FB55;FB55;FB55;067B;067B; # (ﭕ; ﭕ; ﭕ; ٻ; ٻ; ) ARABIC LETTER BEEH MEDIAL FORM +FB56;FB56;FB56;067E;067E; # (ﭖ; ﭖ; ﭖ; پ; پ; ) ARABIC LETTER PEH ISOLATED FORM +FB57;FB57;FB57;067E;067E; # (ﭗ; ﭗ; ﭗ; پ; پ; ) ARABIC LETTER PEH FINAL FORM +FB58;FB58;FB58;067E;067E; # (ﭘ; ﭘ; ﭘ; پ; پ; ) ARABIC LETTER PEH INITIAL FORM +FB59;FB59;FB59;067E;067E; # (ﭙ; ﭙ; ﭙ; پ; پ; ) ARABIC LETTER PEH MEDIAL FORM +FB5A;FB5A;FB5A;0680;0680; # (ﭚ; ﭚ; ﭚ; ڀ; ڀ; ) ARABIC LETTER BEHEH ISOLATED FORM +FB5B;FB5B;FB5B;0680;0680; # (ﭛ; ﭛ; ﭛ; ڀ; ڀ; ) ARABIC LETTER BEHEH FINAL FORM +FB5C;FB5C;FB5C;0680;0680; # (ﭜ; ﭜ; ﭜ; ڀ; ڀ; ) ARABIC LETTER BEHEH INITIAL FORM +FB5D;FB5D;FB5D;0680;0680; # (ﭝ; ﭝ; ﭝ; ڀ; ڀ; ) ARABIC LETTER BEHEH MEDIAL FORM +FB5E;FB5E;FB5E;067A;067A; # (ﭞ; ﭞ; ﭞ; ٺ; ٺ; ) ARABIC LETTER TTEHEH ISOLATED FORM +FB5F;FB5F;FB5F;067A;067A; # (ﭟ; ﭟ; ﭟ; ٺ; ٺ; ) ARABIC LETTER TTEHEH FINAL FORM +FB60;FB60;FB60;067A;067A; # (ﭠ; ﭠ; ﭠ; ٺ; ٺ; ) ARABIC LETTER TTEHEH INITIAL FORM +FB61;FB61;FB61;067A;067A; # (ﭡ; ﭡ; ﭡ; ٺ; ٺ; ) ARABIC LETTER TTEHEH MEDIAL FORM +FB62;FB62;FB62;067F;067F; # (ﭢ; ﭢ; ﭢ; ٿ; ٿ; ) ARABIC LETTER TEHEH ISOLATED FORM +FB63;FB63;FB63;067F;067F; # (ﭣ; ﭣ; ﭣ; ٿ; ٿ; ) ARABIC LETTER TEHEH FINAL FORM +FB64;FB64;FB64;067F;067F; # (ﭤ; ﭤ; ﭤ; ٿ; ٿ; ) ARABIC LETTER TEHEH INITIAL FORM +FB65;FB65;FB65;067F;067F; # (ﭥ; ﭥ; ﭥ; ٿ; ٿ; ) ARABIC LETTER TEHEH MEDIAL FORM +FB66;FB66;FB66;0679;0679; # (ﭦ; ﭦ; ﭦ; ٹ; ٹ; ) ARABIC LETTER TTEH ISOLATED FORM +FB67;FB67;FB67;0679;0679; # (ﭧ; ﭧ; ﭧ; ٹ; ٹ; ) ARABIC LETTER TTEH FINAL FORM +FB68;FB68;FB68;0679;0679; # (ﭨ; ﭨ; ﭨ; ٹ; ٹ; ) ARABIC LETTER TTEH INITIAL FORM +FB69;FB69;FB69;0679;0679; # (ﭩ; ﭩ; ﭩ; ٹ; ٹ; ) ARABIC LETTER TTEH MEDIAL FORM +FB6A;FB6A;FB6A;06A4;06A4; # (ﭪ; ﭪ; ﭪ; ڤ; ڤ; ) ARABIC LETTER VEH ISOLATED FORM +FB6B;FB6B;FB6B;06A4;06A4; # (ﭫ; ﭫ; ﭫ; ڤ; ڤ; ) ARABIC LETTER VEH FINAL FORM +FB6C;FB6C;FB6C;06A4;06A4; # (ﭬ; ﭬ; ﭬ; ڤ; ڤ; ) ARABIC LETTER VEH INITIAL FORM +FB6D;FB6D;FB6D;06A4;06A4; # (ﭭ; ﭭ; ﭭ; ڤ; ڤ; ) ARABIC LETTER VEH MEDIAL FORM +FB6E;FB6E;FB6E;06A6;06A6; # (ﭮ; ﭮ; ﭮ; ڦ; ڦ; ) ARABIC LETTER PEHEH ISOLATED FORM +FB6F;FB6F;FB6F;06A6;06A6; # (ﭯ; ﭯ; ﭯ; ڦ; ڦ; ) ARABIC LETTER PEHEH FINAL FORM +FB70;FB70;FB70;06A6;06A6; # (ﭰ; ﭰ; ﭰ; ڦ; ڦ; ) ARABIC LETTER PEHEH INITIAL FORM +FB71;FB71;FB71;06A6;06A6; # (ﭱ; ﭱ; ﭱ; ڦ; ڦ; ) ARABIC LETTER PEHEH MEDIAL FORM +FB72;FB72;FB72;0684;0684; # (ﭲ; ﭲ; ﭲ; ڄ; ڄ; ) ARABIC LETTER DYEH ISOLATED FORM +FB73;FB73;FB73;0684;0684; # (ﭳ; ﭳ; ﭳ; ڄ; ڄ; ) ARABIC LETTER DYEH FINAL FORM +FB74;FB74;FB74;0684;0684; # (ﭴ; ﭴ; ﭴ; ڄ; ڄ; ) ARABIC LETTER DYEH INITIAL FORM +FB75;FB75;FB75;0684;0684; # (ﭵ; ﭵ; ﭵ; ڄ; ڄ; ) ARABIC LETTER DYEH MEDIAL FORM +FB76;FB76;FB76;0683;0683; # (ﭶ; ﭶ; ﭶ; ڃ; ڃ; ) ARABIC LETTER NYEH ISOLATED FORM +FB77;FB77;FB77;0683;0683; # (ﭷ; ﭷ; ﭷ; ڃ; ڃ; ) ARABIC LETTER NYEH FINAL FORM +FB78;FB78;FB78;0683;0683; # (ﭸ; ﭸ; ﭸ; ڃ; ڃ; ) ARABIC LETTER NYEH INITIAL FORM +FB79;FB79;FB79;0683;0683; # (ﭹ; ﭹ; ﭹ; ڃ; ڃ; ) ARABIC LETTER NYEH MEDIAL FORM +FB7A;FB7A;FB7A;0686;0686; # (ﭺ; ﭺ; ﭺ; چ; چ; ) ARABIC LETTER TCHEH ISOLATED FORM +FB7B;FB7B;FB7B;0686;0686; # (ﭻ; ﭻ; ﭻ; چ; چ; ) ARABIC LETTER TCHEH FINAL FORM +FB7C;FB7C;FB7C;0686;0686; # (ﭼ; ﭼ; ﭼ; چ; چ; ) ARABIC LETTER TCHEH INITIAL FORM +FB7D;FB7D;FB7D;0686;0686; # (ﭽ; ﭽ; ﭽ; چ; چ; ) ARABIC LETTER TCHEH MEDIAL FORM +FB7E;FB7E;FB7E;0687;0687; # (ﭾ; ﭾ; ﭾ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH ISOLATED FORM +FB7F;FB7F;FB7F;0687;0687; # (ﭿ; ﭿ; ﭿ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH FINAL FORM +FB80;FB80;FB80;0687;0687; # (ﮀ; ﮀ; ﮀ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH INITIAL FORM +FB81;FB81;FB81;0687;0687; # (ﮁ; ﮁ; ﮁ; ڇ; ڇ; ) ARABIC LETTER TCHEHEH MEDIAL FORM +FB82;FB82;FB82;068D;068D; # (ﮂ; ﮂ; ﮂ; ڍ; ڍ; ) ARABIC LETTER DDAHAL ISOLATED FORM +FB83;FB83;FB83;068D;068D; # (ﮃ; ﮃ; ﮃ; ڍ; ڍ; ) ARABIC LETTER DDAHAL FINAL FORM +FB84;FB84;FB84;068C;068C; # (ﮄ; ﮄ; ﮄ; ڌ; ڌ; ) ARABIC LETTER DAHAL ISOLATED FORM +FB85;FB85;FB85;068C;068C; # (ﮅ; ﮅ; ﮅ; ڌ; ڌ; ) ARABIC LETTER DAHAL FINAL FORM +FB86;FB86;FB86;068E;068E; # (ﮆ; ﮆ; ﮆ; ڎ; ڎ; ) ARABIC LETTER DUL ISOLATED FORM +FB87;FB87;FB87;068E;068E; # (ﮇ; ﮇ; ﮇ; ڎ; ڎ; ) ARABIC LETTER DUL FINAL FORM +FB88;FB88;FB88;0688;0688; # (ﮈ; ﮈ; ﮈ; ڈ; ڈ; ) ARABIC LETTER DDAL ISOLATED FORM +FB89;FB89;FB89;0688;0688; # (ﮉ; ﮉ; ﮉ; ڈ; ڈ; ) ARABIC LETTER DDAL FINAL FORM +FB8A;FB8A;FB8A;0698;0698; # (ﮊ; ﮊ; ﮊ; ژ; ژ; ) ARABIC LETTER JEH ISOLATED FORM +FB8B;FB8B;FB8B;0698;0698; # (ﮋ; ﮋ; ﮋ; ژ; ژ; ) ARABIC LETTER JEH FINAL FORM +FB8C;FB8C;FB8C;0691;0691; # (ﮌ; ﮌ; ﮌ; ڑ; ڑ; ) ARABIC LETTER RREH ISOLATED FORM +FB8D;FB8D;FB8D;0691;0691; # (ﮍ; ﮍ; ﮍ; ڑ; ڑ; ) ARABIC LETTER RREH FINAL FORM +FB8E;FB8E;FB8E;06A9;06A9; # (ﮎ; ﮎ; ﮎ; ک; ک; ) ARABIC LETTER KEHEH ISOLATED FORM +FB8F;FB8F;FB8F;06A9;06A9; # (ﮏ; ﮏ; ﮏ; ک; ک; ) ARABIC LETTER KEHEH FINAL FORM +FB90;FB90;FB90;06A9;06A9; # (ﮐ; ﮐ; ﮐ; ک; ک; ) ARABIC LETTER KEHEH INITIAL FORM +FB91;FB91;FB91;06A9;06A9; # (ﮑ; ﮑ; ﮑ; ک; ک; ) ARABIC LETTER KEHEH MEDIAL FORM +FB92;FB92;FB92;06AF;06AF; # (ﮒ; ﮒ; ﮒ; گ; گ; ) ARABIC LETTER GAF ISOLATED FORM +FB93;FB93;FB93;06AF;06AF; # (ﮓ; ﮓ; ﮓ; گ; گ; ) ARABIC LETTER GAF FINAL FORM +FB94;FB94;FB94;06AF;06AF; # (ﮔ; ﮔ; ﮔ; گ; گ; ) ARABIC LETTER GAF INITIAL FORM +FB95;FB95;FB95;06AF;06AF; # (ﮕ; ﮕ; ﮕ; گ; گ; ) ARABIC LETTER GAF MEDIAL FORM +FB96;FB96;FB96;06B3;06B3; # (ﮖ; ﮖ; ﮖ; ڳ; ڳ; ) ARABIC LETTER GUEH ISOLATED FORM +FB97;FB97;FB97;06B3;06B3; # (ﮗ; ﮗ; ﮗ; ڳ; ڳ; ) ARABIC LETTER GUEH FINAL FORM +FB98;FB98;FB98;06B3;06B3; # (ﮘ; ﮘ; ﮘ; ڳ; ڳ; ) ARABIC LETTER GUEH INITIAL FORM +FB99;FB99;FB99;06B3;06B3; # (ﮙ; ﮙ; ﮙ; ڳ; ڳ; ) ARABIC LETTER GUEH MEDIAL FORM +FB9A;FB9A;FB9A;06B1;06B1; # (ﮚ; ﮚ; ﮚ; ڱ; ڱ; ) ARABIC LETTER NGOEH ISOLATED FORM +FB9B;FB9B;FB9B;06B1;06B1; # (ﮛ; ﮛ; ﮛ; ڱ; ڱ; ) ARABIC LETTER NGOEH FINAL FORM +FB9C;FB9C;FB9C;06B1;06B1; # (ﮜ; ﮜ; ﮜ; ڱ; ڱ; ) ARABIC LETTER NGOEH INITIAL FORM +FB9D;FB9D;FB9D;06B1;06B1; # (ﮝ; ﮝ; ﮝ; ڱ; ڱ; ) ARABIC LETTER NGOEH MEDIAL FORM +FB9E;FB9E;FB9E;06BA;06BA; # (ﮞ; ﮞ; ﮞ; ں; ں; ) ARABIC LETTER NOON GHUNNA ISOLATED FORM +FB9F;FB9F;FB9F;06BA;06BA; # (ﮟ; ﮟ; ﮟ; ں; ں; ) ARABIC LETTER NOON GHUNNA FINAL FORM +FBA0;FBA0;FBA0;06BB;06BB; # (ﮠ; ﮠ; ﮠ; ڻ; ڻ; ) ARABIC LETTER RNOON ISOLATED FORM +FBA1;FBA1;FBA1;06BB;06BB; # (ﮡ; ﮡ; ﮡ; ڻ; ڻ; ) ARABIC LETTER RNOON FINAL FORM +FBA2;FBA2;FBA2;06BB;06BB; # (ﮢ; ﮢ; ﮢ; ڻ; ڻ; ) ARABIC LETTER RNOON INITIAL FORM +FBA3;FBA3;FBA3;06BB;06BB; # (ﮣ; ﮣ; ﮣ; ڻ; ڻ; ) ARABIC LETTER RNOON MEDIAL FORM +FBA4;FBA4;FBA4;06C0;06D5 0654; # (ﮤ; ﮤ; ﮤ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM +FBA5;FBA5;FBA5;06C0;06D5 0654; # (ﮥ; ﮥ; ﮥ; ۀ; ە◌ٔ; ) ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM +FBA6;FBA6;FBA6;06C1;06C1; # (ﮦ; ﮦ; ﮦ; ہ; ہ; ) ARABIC LETTER HEH GOAL ISOLATED FORM +FBA7;FBA7;FBA7;06C1;06C1; # (ﮧ; ﮧ; ﮧ; ہ; ہ; ) ARABIC LETTER HEH GOAL FINAL FORM +FBA8;FBA8;FBA8;06C1;06C1; # (ﮨ; ﮨ; ﮨ; ہ; ہ; ) ARABIC LETTER HEH GOAL INITIAL FORM +FBA9;FBA9;FBA9;06C1;06C1; # (ﮩ; ﮩ; ﮩ; ہ; ہ; ) ARABIC LETTER HEH GOAL MEDIAL FORM +FBAA;FBAA;FBAA;06BE;06BE; # (ﮪ; ﮪ; ﮪ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM +FBAB;FBAB;FBAB;06BE;06BE; # (ﮫ; ﮫ; ﮫ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE FINAL FORM +FBAC;FBAC;FBAC;06BE;06BE; # (ﮬ; ﮬ; ﮬ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE INITIAL FORM +FBAD;FBAD;FBAD;06BE;06BE; # (ﮭ; ﮭ; ﮭ; ھ; ھ; ) ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM +FBAE;FBAE;FBAE;06D2;06D2; # (ﮮ; ﮮ; ﮮ; ے; ے; ) ARABIC LETTER YEH BARREE ISOLATED FORM +FBAF;FBAF;FBAF;06D2;06D2; # (ﮯ; ﮯ; ﮯ; ے; ے; ) ARABIC LETTER YEH BARREE FINAL FORM +FBB0;FBB0;FBB0;06D3;06D2 0654; # (ﮰ; ﮰ; ﮰ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM +FBB1;FBB1;FBB1;06D3;06D2 0654; # (ﮱ; ﮱ; ﮱ; ۓ; ے◌ٔ; ) ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBD3;FBD3;FBD3;06AD;06AD; # (ﯓ; ﯓ; ﯓ; ڭ; ڭ; ) ARABIC LETTER NG ISOLATED FORM +FBD4;FBD4;FBD4;06AD;06AD; # (ﯔ; ﯔ; ﯔ; ڭ; ڭ; ) ARABIC LETTER NG FINAL FORM +FBD5;FBD5;FBD5;06AD;06AD; # (ﯕ; ﯕ; ﯕ; ڭ; ڭ; ) ARABIC LETTER NG INITIAL FORM +FBD6;FBD6;FBD6;06AD;06AD; # (ﯖ; ﯖ; ﯖ; ڭ; ڭ; ) ARABIC LETTER NG MEDIAL FORM +FBD7;FBD7;FBD7;06C7;06C7; # (ﯗ; ﯗ; ﯗ; ۇ; ۇ; ) ARABIC LETTER U ISOLATED FORM +FBD8;FBD8;FBD8;06C7;06C7; # (ﯘ; ﯘ; ﯘ; ۇ; ۇ; ) ARABIC LETTER U FINAL FORM +FBD9;FBD9;FBD9;06C6;06C6; # (ﯙ; ﯙ; ﯙ; ۆ; ۆ; ) ARABIC LETTER OE ISOLATED FORM +FBDA;FBDA;FBDA;06C6;06C6; # (ﯚ; ﯚ; ﯚ; ۆ; ۆ; ) ARABIC LETTER OE FINAL FORM +FBDB;FBDB;FBDB;06C8;06C8; # (ﯛ; ﯛ; ﯛ; ۈ; ۈ; ) ARABIC LETTER YU ISOLATED FORM +FBDC;FBDC;FBDC;06C8;06C8; # (ﯜ; ﯜ; ﯜ; ۈ; ۈ; ) ARABIC LETTER YU FINAL FORM +FBDD;FBDD;FBDD;06C7 0674;06C7 0674; # (ﯝ; ﯝ; ﯝ; ۇٴ; ۇٴ; ) ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM +FBDE;FBDE;FBDE;06CB;06CB; # (ﯞ; ﯞ; ﯞ; ۋ; ۋ; ) ARABIC LETTER VE ISOLATED FORM +FBDF;FBDF;FBDF;06CB;06CB; # (ﯟ; ﯟ; ﯟ; ۋ; ۋ; ) ARABIC LETTER VE FINAL FORM +FBE0;FBE0;FBE0;06C5;06C5; # (ﯠ; ﯠ; ﯠ; ۅ; ۅ; ) ARABIC LETTER KIRGHIZ OE ISOLATED FORM +FBE1;FBE1;FBE1;06C5;06C5; # (ﯡ; ﯡ; ﯡ; ۅ; ۅ; ) ARABIC LETTER KIRGHIZ OE FINAL FORM +FBE2;FBE2;FBE2;06C9;06C9; # (ﯢ; ﯢ; ﯢ; ۉ; ۉ; ) ARABIC LETTER KIRGHIZ YU ISOLATED FORM +FBE3;FBE3;FBE3;06C9;06C9; # (ﯣ; ﯣ; ﯣ; ۉ; ۉ; ) ARABIC LETTER KIRGHIZ YU FINAL FORM +FBE4;FBE4;FBE4;06D0;06D0; # (ﯤ; ﯤ; ﯤ; ې; ې; ) ARABIC LETTER E ISOLATED FORM +FBE5;FBE5;FBE5;06D0;06D0; # (ﯥ; ﯥ; ﯥ; ې; ې; ) ARABIC LETTER E FINAL FORM +FBE6;FBE6;FBE6;06D0;06D0; # (ﯦ; ﯦ; ﯦ; ې; ې; ) ARABIC LETTER E INITIAL FORM +FBE7;FBE7;FBE7;06D0;06D0; # (ﯧ; ﯧ; ﯧ; ې; ې; ) ARABIC LETTER E MEDIAL FORM +FBE8;FBE8;FBE8;0649;0649; # (ﯨ; ﯨ; ﯨ; ى; ى; ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM +FBE9;FBE9;FBE9;0649;0649; # (ﯩ; ﯩ; ﯩ; ى; ى; ) ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM +FBEA;FBEA;FBEA;0626 0627;064A 0654 0627; # (ﯪ; ﯪ; ﯪ; ئا; ي◌ٔا; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM +FBEB;FBEB;FBEB;0626 0627;064A 0654 0627; # (ﯫ; ﯫ; ﯫ; ئا; ي◌ٔا; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM +FBEC;FBEC;FBEC;0626 06D5;064A 0654 06D5; # (ﯬ; ﯬ; ﯬ; ئە; ي◌ٔە; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM +FBED;FBED;FBED;0626 06D5;064A 0654 06D5; # (ﯭ; ﯭ; ﯭ; ئە; ي◌ٔە; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM +FBEE;FBEE;FBEE;0626 0648;064A 0654 0648; # (ﯮ; ﯮ; ﯮ; ئو; ي◌ٔو; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM +FBEF;FBEF;FBEF;0626 0648;064A 0654 0648; # (ﯯ; ﯯ; ﯯ; ئو; ي◌ٔو; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM +FBF0;FBF0;FBF0;0626 06C7;064A 0654 06C7; # (ﯰ; ﯰ; ﯰ; ئۇ; ي◌ٔۇ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM +FBF1;FBF1;FBF1;0626 06C7;064A 0654 06C7; # (ﯱ; ﯱ; ﯱ; ئۇ; ي◌ٔۇ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM +FBF2;FBF2;FBF2;0626 06C6;064A 0654 06C6; # (ﯲ; ﯲ; ﯲ; ئۆ; ي◌ٔۆ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM +FBF3;FBF3;FBF3;0626 06C6;064A 0654 06C6; # (ﯳ; ﯳ; ﯳ; ئۆ; ي◌ٔۆ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM +FBF4;FBF4;FBF4;0626 06C8;064A 0654 06C8; # (ﯴ; ﯴ; ﯴ; ئۈ; ي◌ٔۈ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM +FBF5;FBF5;FBF5;0626 06C8;064A 0654 06C8; # (ﯵ; ﯵ; ﯵ; ئۈ; ي◌ٔۈ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM +FBF6;FBF6;FBF6;0626 06D0;064A 0654 06D0; # (ﯶ; ﯶ; ﯶ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM +FBF7;FBF7;FBF7;0626 06D0;064A 0654 06D0; # (ﯷ; ﯷ; ﯷ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM +FBF8;FBF8;FBF8;0626 06D0;064A 0654 06D0; # (ﯸ; ﯸ; ﯸ; ئې; ي◌ٔې; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM +FBF9;FBF9;FBF9;0626 0649;064A 0654 0649; # (ﯹ; ﯹ; ﯹ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FBFA;FBFA;FBFA;0626 0649;064A 0654 0649; # (ﯺ; ﯺ; ﯺ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FBFB;FBFB;FBFB;0626 0649;064A 0654 0649; # (ﯻ; ﯻ; ﯻ; ئى; ي◌ٔى; ) ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM +FBFC;FBFC;FBFC;06CC;06CC; # (ﯼ; ﯼ; ﯼ; ی; ی; ) ARABIC LETTER FARSI YEH ISOLATED FORM +FBFD;FBFD;FBFD;06CC;06CC; # (ﯽ; ﯽ; ﯽ; ی; ی; ) ARABIC LETTER FARSI YEH FINAL FORM +FBFE;FBFE;FBFE;06CC;06CC; # (ﯾ; ﯾ; ﯾ; ی; ی; ) ARABIC LETTER FARSI YEH INITIAL FORM +FBFF;FBFF;FBFF;06CC;06CC; # (ﯿ; ﯿ; ﯿ; ی; ی; ) ARABIC LETTER FARSI YEH MEDIAL FORM +FC00;FC00;FC00;0626 062C;064A 0654 062C; # (ﰀ; ﰀ; ﰀ; ئج; ي◌ٔج; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM +FC01;FC01;FC01;0626 062D;064A 0654 062D; # (ﰁ; ﰁ; ﰁ; ئح; ي◌ٔح; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM +FC02;FC02;FC02;0626 0645;064A 0654 0645; # (ﰂ; ﰂ; ﰂ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM +FC03;FC03;FC03;0626 0649;064A 0654 0649; # (ﰃ; ﰃ; ﰃ; ئى; ي◌ٔى; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FC04;FC04;FC04;0626 064A;064A 0654 064A; # (ﰄ; ﰄ; ﰄ; ئي; ي◌ٔي; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM +FC05;FC05;FC05;0628 062C;0628 062C; # (ﰅ; ﰅ; ﰅ; بج; بج; ) ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM +FC06;FC06;FC06;0628 062D;0628 062D; # (ﰆ; ﰆ; ﰆ; بح; بح; ) ARABIC LIGATURE BEH WITH HAH ISOLATED FORM +FC07;FC07;FC07;0628 062E;0628 062E; # (ﰇ; ﰇ; ﰇ; بخ; بخ; ) ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM +FC08;FC08;FC08;0628 0645;0628 0645; # (ﰈ; ﰈ; ﰈ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM +FC09;FC09;FC09;0628 0649;0628 0649; # (ﰉ; ﰉ; ﰉ; بى; بى; ) ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM +FC0A;FC0A;FC0A;0628 064A;0628 064A; # (ﰊ; ﰊ; ﰊ; بي; بي; ) ARABIC LIGATURE BEH WITH YEH ISOLATED FORM +FC0B;FC0B;FC0B;062A 062C;062A 062C; # (ﰋ; ﰋ; ﰋ; تج; تج; ) ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM +FC0C;FC0C;FC0C;062A 062D;062A 062D; # (ﰌ; ﰌ; ﰌ; تح; تح; ) ARABIC LIGATURE TEH WITH HAH ISOLATED FORM +FC0D;FC0D;FC0D;062A 062E;062A 062E; # (ﰍ; ﰍ; ﰍ; تخ; تخ; ) ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM +FC0E;FC0E;FC0E;062A 0645;062A 0645; # (ﰎ; ﰎ; ﰎ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM +FC0F;FC0F;FC0F;062A 0649;062A 0649; # (ﰏ; ﰏ; ﰏ; تى; تى; ) ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM +FC10;FC10;FC10;062A 064A;062A 064A; # (ﰐ; ﰐ; ﰐ; تي; تي; ) ARABIC LIGATURE TEH WITH YEH ISOLATED FORM +FC11;FC11;FC11;062B 062C;062B 062C; # (ﰑ; ﰑ; ﰑ; ثج; ثج; ) ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM +FC12;FC12;FC12;062B 0645;062B 0645; # (ﰒ; ﰒ; ﰒ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM +FC13;FC13;FC13;062B 0649;062B 0649; # (ﰓ; ﰓ; ﰓ; ثى; ثى; ) ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM +FC14;FC14;FC14;062B 064A;062B 064A; # (ﰔ; ﰔ; ﰔ; ثي; ثي; ) ARABIC LIGATURE THEH WITH YEH ISOLATED FORM +FC15;FC15;FC15;062C 062D;062C 062D; # (ﰕ; ﰕ; ﰕ; جح; جح; ) ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM +FC16;FC16;FC16;062C 0645;062C 0645; # (ﰖ; ﰖ; ﰖ; جم; جم; ) ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM +FC17;FC17;FC17;062D 062C;062D 062C; # (ﰗ; ﰗ; ﰗ; حج; حج; ) ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM +FC18;FC18;FC18;062D 0645;062D 0645; # (ﰘ; ﰘ; ﰘ; حم; حم; ) ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM +FC19;FC19;FC19;062E 062C;062E 062C; # (ﰙ; ﰙ; ﰙ; خج; خج; ) ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM +FC1A;FC1A;FC1A;062E 062D;062E 062D; # (ﰚ; ﰚ; ﰚ; خح; خح; ) ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM +FC1B;FC1B;FC1B;062E 0645;062E 0645; # (ﰛ; ﰛ; ﰛ; خم; خم; ) ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM +FC1C;FC1C;FC1C;0633 062C;0633 062C; # (ﰜ; ﰜ; ﰜ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM +FC1D;FC1D;FC1D;0633 062D;0633 062D; # (ﰝ; ﰝ; ﰝ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM +FC1E;FC1E;FC1E;0633 062E;0633 062E; # (ﰞ; ﰞ; ﰞ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM +FC1F;FC1F;FC1F;0633 0645;0633 0645; # (ﰟ; ﰟ; ﰟ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM +FC20;FC20;FC20;0635 062D;0635 062D; # (ﰠ; ﰠ; ﰠ; صح; صح; ) ARABIC LIGATURE SAD WITH HAH ISOLATED FORM +FC21;FC21;FC21;0635 0645;0635 0645; # (ﰡ; ﰡ; ﰡ; صم; صم; ) ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM +FC22;FC22;FC22;0636 062C;0636 062C; # (ﰢ; ﰢ; ﰢ; ضج; ضج; ) ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM +FC23;FC23;FC23;0636 062D;0636 062D; # (ﰣ; ﰣ; ﰣ; ضح; ضح; ) ARABIC LIGATURE DAD WITH HAH ISOLATED FORM +FC24;FC24;FC24;0636 062E;0636 062E; # (ﰤ; ﰤ; ﰤ; ضخ; ضخ; ) ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM +FC25;FC25;FC25;0636 0645;0636 0645; # (ﰥ; ﰥ; ﰥ; ضم; ضم; ) ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM +FC26;FC26;FC26;0637 062D;0637 062D; # (ﰦ; ﰦ; ﰦ; طح; طح; ) ARABIC LIGATURE TAH WITH HAH ISOLATED FORM +FC27;FC27;FC27;0637 0645;0637 0645; # (ﰧ; ﰧ; ﰧ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM +FC28;FC28;FC28;0638 0645;0638 0645; # (ﰨ; ﰨ; ﰨ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM +FC29;FC29;FC29;0639 062C;0639 062C; # (ﰩ; ﰩ; ﰩ; عج; عج; ) ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM +FC2A;FC2A;FC2A;0639 0645;0639 0645; # (ﰪ; ﰪ; ﰪ; عم; عم; ) ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM +FC2B;FC2B;FC2B;063A 062C;063A 062C; # (ﰫ; ﰫ; ﰫ; غج; غج; ) ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM +FC2C;FC2C;FC2C;063A 0645;063A 0645; # (ﰬ; ﰬ; ﰬ; غم; غم; ) ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM +FC2D;FC2D;FC2D;0641 062C;0641 062C; # (ﰭ; ﰭ; ﰭ; فج; فج; ) ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM +FC2E;FC2E;FC2E;0641 062D;0641 062D; # (ﰮ; ﰮ; ﰮ; فح; فح; ) ARABIC LIGATURE FEH WITH HAH ISOLATED FORM +FC2F;FC2F;FC2F;0641 062E;0641 062E; # (ﰯ; ﰯ; ﰯ; فخ; فخ; ) ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM +FC30;FC30;FC30;0641 0645;0641 0645; # (ﰰ; ﰰ; ﰰ; فم; فم; ) ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM +FC31;FC31;FC31;0641 0649;0641 0649; # (ﰱ; ﰱ; ﰱ; فى; فى; ) ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM +FC32;FC32;FC32;0641 064A;0641 064A; # (ﰲ; ﰲ; ﰲ; في; في; ) ARABIC LIGATURE FEH WITH YEH ISOLATED FORM +FC33;FC33;FC33;0642 062D;0642 062D; # (ﰳ; ﰳ; ﰳ; قح; قح; ) ARABIC LIGATURE QAF WITH HAH ISOLATED FORM +FC34;FC34;FC34;0642 0645;0642 0645; # (ﰴ; ﰴ; ﰴ; قم; قم; ) ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM +FC35;FC35;FC35;0642 0649;0642 0649; # (ﰵ; ﰵ; ﰵ; قى; قى; ) ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM +FC36;FC36;FC36;0642 064A;0642 064A; # (ﰶ; ﰶ; ﰶ; قي; قي; ) ARABIC LIGATURE QAF WITH YEH ISOLATED FORM +FC37;FC37;FC37;0643 0627;0643 0627; # (ﰷ; ﰷ; ﰷ; كا; كا; ) ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM +FC38;FC38;FC38;0643 062C;0643 062C; # (ﰸ; ﰸ; ﰸ; كج; كج; ) ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM +FC39;FC39;FC39;0643 062D;0643 062D; # (ﰹ; ﰹ; ﰹ; كح; كح; ) ARABIC LIGATURE KAF WITH HAH ISOLATED FORM +FC3A;FC3A;FC3A;0643 062E;0643 062E; # (ﰺ; ﰺ; ﰺ; كخ; كخ; ) ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM +FC3B;FC3B;FC3B;0643 0644;0643 0644; # (ﰻ; ﰻ; ﰻ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM ISOLATED FORM +FC3C;FC3C;FC3C;0643 0645;0643 0645; # (ﰼ; ﰼ; ﰼ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM +FC3D;FC3D;FC3D;0643 0649;0643 0649; # (ﰽ; ﰽ; ﰽ; كى; كى; ) ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM +FC3E;FC3E;FC3E;0643 064A;0643 064A; # (ﰾ; ﰾ; ﰾ; كي; كي; ) ARABIC LIGATURE KAF WITH YEH ISOLATED FORM +FC3F;FC3F;FC3F;0644 062C;0644 062C; # (ﰿ; ﰿ; ﰿ; لج; لج; ) ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM +FC40;FC40;FC40;0644 062D;0644 062D; # (ﱀ; ﱀ; ﱀ; لح; لح; ) ARABIC LIGATURE LAM WITH HAH ISOLATED FORM +FC41;FC41;FC41;0644 062E;0644 062E; # (ﱁ; ﱁ; ﱁ; لخ; لخ; ) ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM +FC42;FC42;FC42;0644 0645;0644 0645; # (ﱂ; ﱂ; ﱂ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM +FC43;FC43;FC43;0644 0649;0644 0649; # (ﱃ; ﱃ; ﱃ; لى; لى; ) ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM +FC44;FC44;FC44;0644 064A;0644 064A; # (ﱄ; ﱄ; ﱄ; لي; لي; ) ARABIC LIGATURE LAM WITH YEH ISOLATED FORM +FC45;FC45;FC45;0645 062C;0645 062C; # (ﱅ; ﱅ; ﱅ; مج; مج; ) ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM +FC46;FC46;FC46;0645 062D;0645 062D; # (ﱆ; ﱆ; ﱆ; مح; مح; ) ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM +FC47;FC47;FC47;0645 062E;0645 062E; # (ﱇ; ﱇ; ﱇ; مخ; مخ; ) ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM +FC48;FC48;FC48;0645 0645;0645 0645; # (ﱈ; ﱈ; ﱈ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM +FC49;FC49;FC49;0645 0649;0645 0649; # (ﱉ; ﱉ; ﱉ; مى; مى; ) ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM +FC4A;FC4A;FC4A;0645 064A;0645 064A; # (ﱊ; ﱊ; ﱊ; مي; مي; ) ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM +FC4B;FC4B;FC4B;0646 062C;0646 062C; # (ﱋ; ﱋ; ﱋ; نج; نج; ) ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM +FC4C;FC4C;FC4C;0646 062D;0646 062D; # (ﱌ; ﱌ; ﱌ; نح; نح; ) ARABIC LIGATURE NOON WITH HAH ISOLATED FORM +FC4D;FC4D;FC4D;0646 062E;0646 062E; # (ﱍ; ﱍ; ﱍ; نخ; نخ; ) ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM +FC4E;FC4E;FC4E;0646 0645;0646 0645; # (ﱎ; ﱎ; ﱎ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM +FC4F;FC4F;FC4F;0646 0649;0646 0649; # (ﱏ; ﱏ; ﱏ; نى; نى; ) ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM +FC50;FC50;FC50;0646 064A;0646 064A; # (ﱐ; ﱐ; ﱐ; ني; ني; ) ARABIC LIGATURE NOON WITH YEH ISOLATED FORM +FC51;FC51;FC51;0647 062C;0647 062C; # (ﱑ; ﱑ; ﱑ; هج; هج; ) ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM +FC52;FC52;FC52;0647 0645;0647 0645; # (ﱒ; ﱒ; ﱒ; هم; هم; ) ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM +FC53;FC53;FC53;0647 0649;0647 0649; # (ﱓ; ﱓ; ﱓ; هى; هى; ) ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM +FC54;FC54;FC54;0647 064A;0647 064A; # (ﱔ; ﱔ; ﱔ; هي; هي; ) ARABIC LIGATURE HEH WITH YEH ISOLATED FORM +FC55;FC55;FC55;064A 062C;064A 062C; # (ﱕ; ﱕ; ﱕ; يج; يج; ) ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM +FC56;FC56;FC56;064A 062D;064A 062D; # (ﱖ; ﱖ; ﱖ; يح; يح; ) ARABIC LIGATURE YEH WITH HAH ISOLATED FORM +FC57;FC57;FC57;064A 062E;064A 062E; # (ﱗ; ﱗ; ﱗ; يخ; يخ; ) ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM +FC58;FC58;FC58;064A 0645;064A 0645; # (ﱘ; ﱘ; ﱘ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM +FC59;FC59;FC59;064A 0649;064A 0649; # (ﱙ; ﱙ; ﱙ; يى; يى; ) ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM +FC5A;FC5A;FC5A;064A 064A;064A 064A; # (ﱚ; ﱚ; ﱚ; يي; يي; ) ARABIC LIGATURE YEH WITH YEH ISOLATED FORM +FC5B;FC5B;FC5B;0630 0670;0630 0670; # (ﱛ; ﱛ; ﱛ; ذ◌ٰ; ذ◌ٰ; ) ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5C;FC5C;FC5C;0631 0670;0631 0670; # (ﱜ; ﱜ; ﱜ; ر◌ٰ; ر◌ٰ; ) ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5D;FC5D;FC5D;0649 0670;0649 0670; # (ﱝ; ﱝ; ﱝ; ى◌ٰ; ى◌ٰ; ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5E;FC5E;FC5E;0020 064C 0651;0020 064C 0651; # (ﱞ; ﱞ; ﱞ; ◌ٌ◌ّ; ◌ٌ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM +FC5F;FC5F;FC5F;0020 064D 0651;0020 064D 0651; # (ﱟ; ﱟ; ﱟ; ◌ٍ◌ّ; ◌ٍ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM +FC60;FC60;FC60;0020 064E 0651;0020 064E 0651; # (ﱠ; ﱠ; ﱠ; ◌َ◌ّ; ◌َ◌ّ; ) ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM +FC61;FC61;FC61;0020 064F 0651;0020 064F 0651; # (ﱡ; ﱡ; ﱡ; ◌ُ◌ّ; ◌ُ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM +FC62;FC62;FC62;0020 0650 0651;0020 0650 0651; # (ﱢ; ﱢ; ﱢ; ◌ِ◌ّ; ◌ِ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM +FC63;FC63;FC63;0020 0651 0670;0020 0651 0670; # (ﱣ; ﱣ; ﱣ; ◌ّ◌ٰ; ◌ّ◌ٰ; ) ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC64;FC64;FC64;0626 0631;064A 0654 0631; # (ﱤ; ﱤ; ﱤ; ئر; ي◌ٔر; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM +FC65;FC65;FC65;0626 0632;064A 0654 0632; # (ﱥ; ﱥ; ﱥ; ئز; ي◌ٔز; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM +FC66;FC66;FC66;0626 0645;064A 0654 0645; # (ﱦ; ﱦ; ﱦ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM +FC67;FC67;FC67;0626 0646;064A 0654 0646; # (ﱧ; ﱧ; ﱧ; ئن; ي◌ٔن; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM +FC68;FC68;FC68;0626 0649;064A 0654 0649; # (ﱨ; ﱨ; ﱨ; ئى; ي◌ٔى; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FC69;FC69;FC69;0626 064A;064A 0654 064A; # (ﱩ; ﱩ; ﱩ; ئي; ي◌ٔي; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM +FC6A;FC6A;FC6A;0628 0631;0628 0631; # (ﱪ; ﱪ; ﱪ; بر; بر; ) ARABIC LIGATURE BEH WITH REH FINAL FORM +FC6B;FC6B;FC6B;0628 0632;0628 0632; # (ﱫ; ﱫ; ﱫ; بز; بز; ) ARABIC LIGATURE BEH WITH ZAIN FINAL FORM +FC6C;FC6C;FC6C;0628 0645;0628 0645; # (ﱬ; ﱬ; ﱬ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM FINAL FORM +FC6D;FC6D;FC6D;0628 0646;0628 0646; # (ﱭ; ﱭ; ﱭ; بن; بن; ) ARABIC LIGATURE BEH WITH NOON FINAL FORM +FC6E;FC6E;FC6E;0628 0649;0628 0649; # (ﱮ; ﱮ; ﱮ; بى; بى; ) ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM +FC6F;FC6F;FC6F;0628 064A;0628 064A; # (ﱯ; ﱯ; ﱯ; بي; بي; ) ARABIC LIGATURE BEH WITH YEH FINAL FORM +FC70;FC70;FC70;062A 0631;062A 0631; # (ﱰ; ﱰ; ﱰ; تر; تر; ) ARABIC LIGATURE TEH WITH REH FINAL FORM +FC71;FC71;FC71;062A 0632;062A 0632; # (ﱱ; ﱱ; ﱱ; تز; تز; ) ARABIC LIGATURE TEH WITH ZAIN FINAL FORM +FC72;FC72;FC72;062A 0645;062A 0645; # (ﱲ; ﱲ; ﱲ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM FINAL FORM +FC73;FC73;FC73;062A 0646;062A 0646; # (ﱳ; ﱳ; ﱳ; تن; تن; ) ARABIC LIGATURE TEH WITH NOON FINAL FORM +FC74;FC74;FC74;062A 0649;062A 0649; # (ﱴ; ﱴ; ﱴ; تى; تى; ) ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM +FC75;FC75;FC75;062A 064A;062A 064A; # (ﱵ; ﱵ; ﱵ; تي; تي; ) ARABIC LIGATURE TEH WITH YEH FINAL FORM +FC76;FC76;FC76;062B 0631;062B 0631; # (ﱶ; ﱶ; ﱶ; ثر; ثر; ) ARABIC LIGATURE THEH WITH REH FINAL FORM +FC77;FC77;FC77;062B 0632;062B 0632; # (ﱷ; ﱷ; ﱷ; ثز; ثز; ) ARABIC LIGATURE THEH WITH ZAIN FINAL FORM +FC78;FC78;FC78;062B 0645;062B 0645; # (ﱸ; ﱸ; ﱸ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM FINAL FORM +FC79;FC79;FC79;062B 0646;062B 0646; # (ﱹ; ﱹ; ﱹ; ثن; ثن; ) ARABIC LIGATURE THEH WITH NOON FINAL FORM +FC7A;FC7A;FC7A;062B 0649;062B 0649; # (ﱺ; ﱺ; ﱺ; ثى; ثى; ) ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM +FC7B;FC7B;FC7B;062B 064A;062B 064A; # (ﱻ; ﱻ; ﱻ; ثي; ثي; ) ARABIC LIGATURE THEH WITH YEH FINAL FORM +FC7C;FC7C;FC7C;0641 0649;0641 0649; # (ﱼ; ﱼ; ﱼ; فى; فى; ) ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM +FC7D;FC7D;FC7D;0641 064A;0641 064A; # (ﱽ; ﱽ; ﱽ; في; في; ) ARABIC LIGATURE FEH WITH YEH FINAL FORM +FC7E;FC7E;FC7E;0642 0649;0642 0649; # (ﱾ; ﱾ; ﱾ; قى; قى; ) ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM +FC7F;FC7F;FC7F;0642 064A;0642 064A; # (ﱿ; ﱿ; ﱿ; قي; قي; ) ARABIC LIGATURE QAF WITH YEH FINAL FORM +FC80;FC80;FC80;0643 0627;0643 0627; # (ﲀ; ﲀ; ﲀ; كا; كا; ) ARABIC LIGATURE KAF WITH ALEF FINAL FORM +FC81;FC81;FC81;0643 0644;0643 0644; # (ﲁ; ﲁ; ﲁ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM FINAL FORM +FC82;FC82;FC82;0643 0645;0643 0645; # (ﲂ; ﲂ; ﲂ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM FINAL FORM +FC83;FC83;FC83;0643 0649;0643 0649; # (ﲃ; ﲃ; ﲃ; كى; كى; ) ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM +FC84;FC84;FC84;0643 064A;0643 064A; # (ﲄ; ﲄ; ﲄ; كي; كي; ) ARABIC LIGATURE KAF WITH YEH FINAL FORM +FC85;FC85;FC85;0644 0645;0644 0645; # (ﲅ; ﲅ; ﲅ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM FINAL FORM +FC86;FC86;FC86;0644 0649;0644 0649; # (ﲆ; ﲆ; ﲆ; لى; لى; ) ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM +FC87;FC87;FC87;0644 064A;0644 064A; # (ﲇ; ﲇ; ﲇ; لي; لي; ) ARABIC LIGATURE LAM WITH YEH FINAL FORM +FC88;FC88;FC88;0645 0627;0645 0627; # (ﲈ; ﲈ; ﲈ; ما; ما; ) ARABIC LIGATURE MEEM WITH ALEF FINAL FORM +FC89;FC89;FC89;0645 0645;0645 0645; # (ﲉ; ﲉ; ﲉ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM FINAL FORM +FC8A;FC8A;FC8A;0646 0631;0646 0631; # (ﲊ; ﲊ; ﲊ; نر; نر; ) ARABIC LIGATURE NOON WITH REH FINAL FORM +FC8B;FC8B;FC8B;0646 0632;0646 0632; # (ﲋ; ﲋ; ﲋ; نز; نز; ) ARABIC LIGATURE NOON WITH ZAIN FINAL FORM +FC8C;FC8C;FC8C;0646 0645;0646 0645; # (ﲌ; ﲌ; ﲌ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM FINAL FORM +FC8D;FC8D;FC8D;0646 0646;0646 0646; # (ﲍ; ﲍ; ﲍ; نن; نن; ) ARABIC LIGATURE NOON WITH NOON FINAL FORM +FC8E;FC8E;FC8E;0646 0649;0646 0649; # (ﲎ; ﲎ; ﲎ; نى; نى; ) ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM +FC8F;FC8F;FC8F;0646 064A;0646 064A; # (ﲏ; ﲏ; ﲏ; ني; ني; ) ARABIC LIGATURE NOON WITH YEH FINAL FORM +FC90;FC90;FC90;0649 0670;0649 0670; # (ﲐ; ﲐ; ﲐ; ى◌ٰ; ى◌ٰ; ) ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM +FC91;FC91;FC91;064A 0631;064A 0631; # (ﲑ; ﲑ; ﲑ; ير; ير; ) ARABIC LIGATURE YEH WITH REH FINAL FORM +FC92;FC92;FC92;064A 0632;064A 0632; # (ﲒ; ﲒ; ﲒ; يز; يز; ) ARABIC LIGATURE YEH WITH ZAIN FINAL FORM +FC93;FC93;FC93;064A 0645;064A 0645; # (ﲓ; ﲓ; ﲓ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM FINAL FORM +FC94;FC94;FC94;064A 0646;064A 0646; # (ﲔ; ﲔ; ﲔ; ين; ين; ) ARABIC LIGATURE YEH WITH NOON FINAL FORM +FC95;FC95;FC95;064A 0649;064A 0649; # (ﲕ; ﲕ; ﲕ; يى; يى; ) ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM +FC96;FC96;FC96;064A 064A;064A 064A; # (ﲖ; ﲖ; ﲖ; يي; يي; ) ARABIC LIGATURE YEH WITH YEH FINAL FORM +FC97;FC97;FC97;0626 062C;064A 0654 062C; # (ﲗ; ﲗ; ﲗ; ئج; ي◌ٔج; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM +FC98;FC98;FC98;0626 062D;064A 0654 062D; # (ﲘ; ﲘ; ﲘ; ئح; ي◌ٔح; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM +FC99;FC99;FC99;0626 062E;064A 0654 062E; # (ﲙ; ﲙ; ﲙ; ئخ; ي◌ٔخ; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM +FC9A;FC9A;FC9A;0626 0645;064A 0654 0645; # (ﲚ; ﲚ; ﲚ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM +FC9B;FC9B;FC9B;0626 0647;064A 0654 0647; # (ﲛ; ﲛ; ﲛ; ئه; ي◌ٔه; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM +FC9C;FC9C;FC9C;0628 062C;0628 062C; # (ﲜ; ﲜ; ﲜ; بج; بج; ) ARABIC LIGATURE BEH WITH JEEM INITIAL FORM +FC9D;FC9D;FC9D;0628 062D;0628 062D; # (ﲝ; ﲝ; ﲝ; بح; بح; ) ARABIC LIGATURE BEH WITH HAH INITIAL FORM +FC9E;FC9E;FC9E;0628 062E;0628 062E; # (ﲞ; ﲞ; ﲞ; بخ; بخ; ) ARABIC LIGATURE BEH WITH KHAH INITIAL FORM +FC9F;FC9F;FC9F;0628 0645;0628 0645; # (ﲟ; ﲟ; ﲟ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM INITIAL FORM +FCA0;FCA0;FCA0;0628 0647;0628 0647; # (ﲠ; ﲠ; ﲠ; به; به; ) ARABIC LIGATURE BEH WITH HEH INITIAL FORM +FCA1;FCA1;FCA1;062A 062C;062A 062C; # (ﲡ; ﲡ; ﲡ; تج; تج; ) ARABIC LIGATURE TEH WITH JEEM INITIAL FORM +FCA2;FCA2;FCA2;062A 062D;062A 062D; # (ﲢ; ﲢ; ﲢ; تح; تح; ) ARABIC LIGATURE TEH WITH HAH INITIAL FORM +FCA3;FCA3;FCA3;062A 062E;062A 062E; # (ﲣ; ﲣ; ﲣ; تخ; تخ; ) ARABIC LIGATURE TEH WITH KHAH INITIAL FORM +FCA4;FCA4;FCA4;062A 0645;062A 0645; # (ﲤ; ﲤ; ﲤ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM INITIAL FORM +FCA5;FCA5;FCA5;062A 0647;062A 0647; # (ﲥ; ﲥ; ﲥ; ته; ته; ) ARABIC LIGATURE TEH WITH HEH INITIAL FORM +FCA6;FCA6;FCA6;062B 0645;062B 0645; # (ﲦ; ﲦ; ﲦ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM INITIAL FORM +FCA7;FCA7;FCA7;062C 062D;062C 062D; # (ﲧ; ﲧ; ﲧ; جح; جح; ) ARABIC LIGATURE JEEM WITH HAH INITIAL FORM +FCA8;FCA8;FCA8;062C 0645;062C 0645; # (ﲨ; ﲨ; ﲨ; جم; جم; ) ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM +FCA9;FCA9;FCA9;062D 062C;062D 062C; # (ﲩ; ﲩ; ﲩ; حج; حج; ) ARABIC LIGATURE HAH WITH JEEM INITIAL FORM +FCAA;FCAA;FCAA;062D 0645;062D 0645; # (ﲪ; ﲪ; ﲪ; حم; حم; ) ARABIC LIGATURE HAH WITH MEEM INITIAL FORM +FCAB;FCAB;FCAB;062E 062C;062E 062C; # (ﲫ; ﲫ; ﲫ; خج; خج; ) ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM +FCAC;FCAC;FCAC;062E 0645;062E 0645; # (ﲬ; ﲬ; ﲬ; خم; خم; ) ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM +FCAD;FCAD;FCAD;0633 062C;0633 062C; # (ﲭ; ﲭ; ﲭ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM +FCAE;FCAE;FCAE;0633 062D;0633 062D; # (ﲮ; ﲮ; ﲮ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH INITIAL FORM +FCAF;FCAF;FCAF;0633 062E;0633 062E; # (ﲯ; ﲯ; ﲯ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM +FCB0;FCB0;FCB0;0633 0645;0633 0645; # (ﲰ; ﲰ; ﲰ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM +FCB1;FCB1;FCB1;0635 062D;0635 062D; # (ﲱ; ﲱ; ﲱ; صح; صح; ) ARABIC LIGATURE SAD WITH HAH INITIAL FORM +FCB2;FCB2;FCB2;0635 062E;0635 062E; # (ﲲ; ﲲ; ﲲ; صخ; صخ; ) ARABIC LIGATURE SAD WITH KHAH INITIAL FORM +FCB3;FCB3;FCB3;0635 0645;0635 0645; # (ﲳ; ﲳ; ﲳ; صم; صم; ) ARABIC LIGATURE SAD WITH MEEM INITIAL FORM +FCB4;FCB4;FCB4;0636 062C;0636 062C; # (ﲴ; ﲴ; ﲴ; ضج; ضج; ) ARABIC LIGATURE DAD WITH JEEM INITIAL FORM +FCB5;FCB5;FCB5;0636 062D;0636 062D; # (ﲵ; ﲵ; ﲵ; ضح; ضح; ) ARABIC LIGATURE DAD WITH HAH INITIAL FORM +FCB6;FCB6;FCB6;0636 062E;0636 062E; # (ﲶ; ﲶ; ﲶ; ضخ; ضخ; ) ARABIC LIGATURE DAD WITH KHAH INITIAL FORM +FCB7;FCB7;FCB7;0636 0645;0636 0645; # (ﲷ; ﲷ; ﲷ; ضم; ضم; ) ARABIC LIGATURE DAD WITH MEEM INITIAL FORM +FCB8;FCB8;FCB8;0637 062D;0637 062D; # (ﲸ; ﲸ; ﲸ; طح; طح; ) ARABIC LIGATURE TAH WITH HAH INITIAL FORM +FCB9;FCB9;FCB9;0638 0645;0638 0645; # (ﲹ; ﲹ; ﲹ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM +FCBA;FCBA;FCBA;0639 062C;0639 062C; # (ﲺ; ﲺ; ﲺ; عج; عج; ) ARABIC LIGATURE AIN WITH JEEM INITIAL FORM +FCBB;FCBB;FCBB;0639 0645;0639 0645; # (ﲻ; ﲻ; ﲻ; عم; عم; ) ARABIC LIGATURE AIN WITH MEEM INITIAL FORM +FCBC;FCBC;FCBC;063A 062C;063A 062C; # (ﲼ; ﲼ; ﲼ; غج; غج; ) ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM +FCBD;FCBD;FCBD;063A 0645;063A 0645; # (ﲽ; ﲽ; ﲽ; غم; غم; ) ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM +FCBE;FCBE;FCBE;0641 062C;0641 062C; # (ﲾ; ﲾ; ﲾ; فج; فج; ) ARABIC LIGATURE FEH WITH JEEM INITIAL FORM +FCBF;FCBF;FCBF;0641 062D;0641 062D; # (ﲿ; ﲿ; ﲿ; فح; فح; ) ARABIC LIGATURE FEH WITH HAH INITIAL FORM +FCC0;FCC0;FCC0;0641 062E;0641 062E; # (ﳀ; ﳀ; ﳀ; فخ; فخ; ) ARABIC LIGATURE FEH WITH KHAH INITIAL FORM +FCC1;FCC1;FCC1;0641 0645;0641 0645; # (ﳁ; ﳁ; ﳁ; فم; فم; ) ARABIC LIGATURE FEH WITH MEEM INITIAL FORM +FCC2;FCC2;FCC2;0642 062D;0642 062D; # (ﳂ; ﳂ; ﳂ; قح; قح; ) ARABIC LIGATURE QAF WITH HAH INITIAL FORM +FCC3;FCC3;FCC3;0642 0645;0642 0645; # (ﳃ; ﳃ; ﳃ; قم; قم; ) ARABIC LIGATURE QAF WITH MEEM INITIAL FORM +FCC4;FCC4;FCC4;0643 062C;0643 062C; # (ﳄ; ﳄ; ﳄ; كج; كج; ) ARABIC LIGATURE KAF WITH JEEM INITIAL FORM +FCC5;FCC5;FCC5;0643 062D;0643 062D; # (ﳅ; ﳅ; ﳅ; كح; كح; ) ARABIC LIGATURE KAF WITH HAH INITIAL FORM +FCC6;FCC6;FCC6;0643 062E;0643 062E; # (ﳆ; ﳆ; ﳆ; كخ; كخ; ) ARABIC LIGATURE KAF WITH KHAH INITIAL FORM +FCC7;FCC7;FCC7;0643 0644;0643 0644; # (ﳇ; ﳇ; ﳇ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM INITIAL FORM +FCC8;FCC8;FCC8;0643 0645;0643 0645; # (ﳈ; ﳈ; ﳈ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM INITIAL FORM +FCC9;FCC9;FCC9;0644 062C;0644 062C; # (ﳉ; ﳉ; ﳉ; لج; لج; ) ARABIC LIGATURE LAM WITH JEEM INITIAL FORM +FCCA;FCCA;FCCA;0644 062D;0644 062D; # (ﳊ; ﳊ; ﳊ; لح; لح; ) ARABIC LIGATURE LAM WITH HAH INITIAL FORM +FCCB;FCCB;FCCB;0644 062E;0644 062E; # (ﳋ; ﳋ; ﳋ; لخ; لخ; ) ARABIC LIGATURE LAM WITH KHAH INITIAL FORM +FCCC;FCCC;FCCC;0644 0645;0644 0645; # (ﳌ; ﳌ; ﳌ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM INITIAL FORM +FCCD;FCCD;FCCD;0644 0647;0644 0647; # (ﳍ; ﳍ; ﳍ; له; له; ) ARABIC LIGATURE LAM WITH HEH INITIAL FORM +FCCE;FCCE;FCCE;0645 062C;0645 062C; # (ﳎ; ﳎ; ﳎ; مج; مج; ) ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM +FCCF;FCCF;FCCF;0645 062D;0645 062D; # (ﳏ; ﳏ; ﳏ; مح; مح; ) ARABIC LIGATURE MEEM WITH HAH INITIAL FORM +FCD0;FCD0;FCD0;0645 062E;0645 062E; # (ﳐ; ﳐ; ﳐ; مخ; مخ; ) ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM +FCD1;FCD1;FCD1;0645 0645;0645 0645; # (ﳑ; ﳑ; ﳑ; مم; مم; ) ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM +FCD2;FCD2;FCD2;0646 062C;0646 062C; # (ﳒ; ﳒ; ﳒ; نج; نج; ) ARABIC LIGATURE NOON WITH JEEM INITIAL FORM +FCD3;FCD3;FCD3;0646 062D;0646 062D; # (ﳓ; ﳓ; ﳓ; نح; نح; ) ARABIC LIGATURE NOON WITH HAH INITIAL FORM +FCD4;FCD4;FCD4;0646 062E;0646 062E; # (ﳔ; ﳔ; ﳔ; نخ; نخ; ) ARABIC LIGATURE NOON WITH KHAH INITIAL FORM +FCD5;FCD5;FCD5;0646 0645;0646 0645; # (ﳕ; ﳕ; ﳕ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM INITIAL FORM +FCD6;FCD6;FCD6;0646 0647;0646 0647; # (ﳖ; ﳖ; ﳖ; نه; نه; ) ARABIC LIGATURE NOON WITH HEH INITIAL FORM +FCD7;FCD7;FCD7;0647 062C;0647 062C; # (ﳗ; ﳗ; ﳗ; هج; هج; ) ARABIC LIGATURE HEH WITH JEEM INITIAL FORM +FCD8;FCD8;FCD8;0647 0645;0647 0645; # (ﳘ; ﳘ; ﳘ; هم; هم; ) ARABIC LIGATURE HEH WITH MEEM INITIAL FORM +FCD9;FCD9;FCD9;0647 0670;0647 0670; # (ﳙ; ﳙ; ﳙ; ه◌ٰ; ه◌ٰ; ) ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM +FCDA;FCDA;FCDA;064A 062C;064A 062C; # (ﳚ; ﳚ; ﳚ; يج; يج; ) ARABIC LIGATURE YEH WITH JEEM INITIAL FORM +FCDB;FCDB;FCDB;064A 062D;064A 062D; # (ﳛ; ﳛ; ﳛ; يح; يح; ) ARABIC LIGATURE YEH WITH HAH INITIAL FORM +FCDC;FCDC;FCDC;064A 062E;064A 062E; # (ﳜ; ﳜ; ﳜ; يخ; يخ; ) ARABIC LIGATURE YEH WITH KHAH INITIAL FORM +FCDD;FCDD;FCDD;064A 0645;064A 0645; # (ﳝ; ﳝ; ﳝ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM INITIAL FORM +FCDE;FCDE;FCDE;064A 0647;064A 0647; # (ﳞ; ﳞ; ﳞ; يه; يه; ) ARABIC LIGATURE YEH WITH HEH INITIAL FORM +FCDF;FCDF;FCDF;0626 0645;064A 0654 0645; # (ﳟ; ﳟ; ﳟ; ئم; ي◌ٔم; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM +FCE0;FCE0;FCE0;0626 0647;064A 0654 0647; # (ﳠ; ﳠ; ﳠ; ئه; ي◌ٔه; ) ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM +FCE1;FCE1;FCE1;0628 0645;0628 0645; # (ﳡ; ﳡ; ﳡ; بم; بم; ) ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM +FCE2;FCE2;FCE2;0628 0647;0628 0647; # (ﳢ; ﳢ; ﳢ; به; به; ) ARABIC LIGATURE BEH WITH HEH MEDIAL FORM +FCE3;FCE3;FCE3;062A 0645;062A 0645; # (ﳣ; ﳣ; ﳣ; تم; تم; ) ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM +FCE4;FCE4;FCE4;062A 0647;062A 0647; # (ﳤ; ﳤ; ﳤ; ته; ته; ) ARABIC LIGATURE TEH WITH HEH MEDIAL FORM +FCE5;FCE5;FCE5;062B 0645;062B 0645; # (ﳥ; ﳥ; ﳥ; ثم; ثم; ) ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM +FCE6;FCE6;FCE6;062B 0647;062B 0647; # (ﳦ; ﳦ; ﳦ; ثه; ثه; ) ARABIC LIGATURE THEH WITH HEH MEDIAL FORM +FCE7;FCE7;FCE7;0633 0645;0633 0645; # (ﳧ; ﳧ; ﳧ; سم; سم; ) ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM +FCE8;FCE8;FCE8;0633 0647;0633 0647; # (ﳨ; ﳨ; ﳨ; سه; سه; ) ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM +FCE9;FCE9;FCE9;0634 0645;0634 0645; # (ﳩ; ﳩ; ﳩ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM +FCEA;FCEA;FCEA;0634 0647;0634 0647; # (ﳪ; ﳪ; ﳪ; شه; شه; ) ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM +FCEB;FCEB;FCEB;0643 0644;0643 0644; # (ﳫ; ﳫ; ﳫ; كل; كل; ) ARABIC LIGATURE KAF WITH LAM MEDIAL FORM +FCEC;FCEC;FCEC;0643 0645;0643 0645; # (ﳬ; ﳬ; ﳬ; كم; كم; ) ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM +FCED;FCED;FCED;0644 0645;0644 0645; # (ﳭ; ﳭ; ﳭ; لم; لم; ) ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM +FCEE;FCEE;FCEE;0646 0645;0646 0645; # (ﳮ; ﳮ; ﳮ; نم; نم; ) ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM +FCEF;FCEF;FCEF;0646 0647;0646 0647; # (ﳯ; ﳯ; ﳯ; نه; نه; ) ARABIC LIGATURE NOON WITH HEH MEDIAL FORM +FCF0;FCF0;FCF0;064A 0645;064A 0645; # (ﳰ; ﳰ; ﳰ; يم; يم; ) ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM +FCF1;FCF1;FCF1;064A 0647;064A 0647; # (ﳱ; ﳱ; ﳱ; يه; يه; ) ARABIC LIGATURE YEH WITH HEH MEDIAL FORM +FCF2;FCF2;FCF2;0640 064E 0651;0640 064E 0651; # (ﳲ; ﳲ; ﳲ; ـ◌َ◌ّ; ـ◌َ◌ّ; ) ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM +FCF3;FCF3;FCF3;0640 064F 0651;0640 064F 0651; # (ﳳ; ﳳ; ﳳ; ـ◌ُ◌ّ; ـ◌ُ◌ّ; ) ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM +FCF4;FCF4;FCF4;0640 0650 0651;0640 0650 0651; # (ﳴ; ﳴ; ﳴ; ـ◌ِ◌ّ; ـ◌ِ◌ّ; ) ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM +FCF5;FCF5;FCF5;0637 0649;0637 0649; # (ﳵ; ﳵ; ﳵ; طى; طى; ) ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM +FCF6;FCF6;FCF6;0637 064A;0637 064A; # (ﳶ; ﳶ; ﳶ; طي; طي; ) ARABIC LIGATURE TAH WITH YEH ISOLATED FORM +FCF7;FCF7;FCF7;0639 0649;0639 0649; # (ﳷ; ﳷ; ﳷ; عى; عى; ) ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM +FCF8;FCF8;FCF8;0639 064A;0639 064A; # (ﳸ; ﳸ; ﳸ; عي; عي; ) ARABIC LIGATURE AIN WITH YEH ISOLATED FORM +FCF9;FCF9;FCF9;063A 0649;063A 0649; # (ﳹ; ﳹ; ﳹ; غى; غى; ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM +FCFA;FCFA;FCFA;063A 064A;063A 064A; # (ﳺ; ﳺ; ﳺ; غي; غي; ) ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM +FCFB;FCFB;FCFB;0633 0649;0633 0649; # (ﳻ; ﳻ; ﳻ; سى; سى; ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM +FCFC;FCFC;FCFC;0633 064A;0633 064A; # (ﳼ; ﳼ; ﳼ; سي; سي; ) ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM +FCFD;FCFD;FCFD;0634 0649;0634 0649; # (ﳽ; ﳽ; ﳽ; شى; شى; ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM +FCFE;FCFE;FCFE;0634 064A;0634 064A; # (ﳾ; ﳾ; ﳾ; شي; شي; ) ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM +FCFF;FCFF;FCFF;062D 0649;062D 0649; # (ﳿ; ﳿ; ﳿ; حى; حى; ) ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM +FD00;FD00;FD00;062D 064A;062D 064A; # (ﴀ; ﴀ; ﴀ; حي; حي; ) ARABIC LIGATURE HAH WITH YEH ISOLATED FORM +FD01;FD01;FD01;062C 0649;062C 0649; # (ﴁ; ﴁ; ﴁ; جى; جى; ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM +FD02;FD02;FD02;062C 064A;062C 064A; # (ﴂ; ﴂ; ﴂ; جي; جي; ) ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM +FD03;FD03;FD03;062E 0649;062E 0649; # (ﴃ; ﴃ; ﴃ; خى; خى; ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM +FD04;FD04;FD04;062E 064A;062E 064A; # (ﴄ; ﴄ; ﴄ; خي; خي; ) ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM +FD05;FD05;FD05;0635 0649;0635 0649; # (ﴅ; ﴅ; ﴅ; صى; صى; ) ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM +FD06;FD06;FD06;0635 064A;0635 064A; # (ﴆ; ﴆ; ﴆ; صي; صي; ) ARABIC LIGATURE SAD WITH YEH ISOLATED FORM +FD07;FD07;FD07;0636 0649;0636 0649; # (ﴇ; ﴇ; ﴇ; ضى; ضى; ) ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM +FD08;FD08;FD08;0636 064A;0636 064A; # (ﴈ; ﴈ; ﴈ; ضي; ضي; ) ARABIC LIGATURE DAD WITH YEH ISOLATED FORM +FD09;FD09;FD09;0634 062C;0634 062C; # (ﴉ; ﴉ; ﴉ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM +FD0A;FD0A;FD0A;0634 062D;0634 062D; # (ﴊ; ﴊ; ﴊ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM +FD0B;FD0B;FD0B;0634 062E;0634 062E; # (ﴋ; ﴋ; ﴋ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM +FD0C;FD0C;FD0C;0634 0645;0634 0645; # (ﴌ; ﴌ; ﴌ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM +FD0D;FD0D;FD0D;0634 0631;0634 0631; # (ﴍ; ﴍ; ﴍ; شر; شر; ) ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM +FD0E;FD0E;FD0E;0633 0631;0633 0631; # (ﴎ; ﴎ; ﴎ; سر; سر; ) ARABIC LIGATURE SEEN WITH REH ISOLATED FORM +FD0F;FD0F;FD0F;0635 0631;0635 0631; # (ﴏ; ﴏ; ﴏ; صر; صر; ) ARABIC LIGATURE SAD WITH REH ISOLATED FORM +FD10;FD10;FD10;0636 0631;0636 0631; # (ﴐ; ﴐ; ﴐ; ضر; ضر; ) ARABIC LIGATURE DAD WITH REH ISOLATED FORM +FD11;FD11;FD11;0637 0649;0637 0649; # (ﴑ; ﴑ; ﴑ; طى; طى; ) ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM +FD12;FD12;FD12;0637 064A;0637 064A; # (ﴒ; ﴒ; ﴒ; طي; طي; ) ARABIC LIGATURE TAH WITH YEH FINAL FORM +FD13;FD13;FD13;0639 0649;0639 0649; # (ﴓ; ﴓ; ﴓ; عى; عى; ) ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM +FD14;FD14;FD14;0639 064A;0639 064A; # (ﴔ; ﴔ; ﴔ; عي; عي; ) ARABIC LIGATURE AIN WITH YEH FINAL FORM +FD15;FD15;FD15;063A 0649;063A 0649; # (ﴕ; ﴕ; ﴕ; غى; غى; ) ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM +FD16;FD16;FD16;063A 064A;063A 064A; # (ﴖ; ﴖ; ﴖ; غي; غي; ) ARABIC LIGATURE GHAIN WITH YEH FINAL FORM +FD17;FD17;FD17;0633 0649;0633 0649; # (ﴗ; ﴗ; ﴗ; سى; سى; ) ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM +FD18;FD18;FD18;0633 064A;0633 064A; # (ﴘ; ﴘ; ﴘ; سي; سي; ) ARABIC LIGATURE SEEN WITH YEH FINAL FORM +FD19;FD19;FD19;0634 0649;0634 0649; # (ﴙ; ﴙ; ﴙ; شى; شى; ) ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM +FD1A;FD1A;FD1A;0634 064A;0634 064A; # (ﴚ; ﴚ; ﴚ; شي; شي; ) ARABIC LIGATURE SHEEN WITH YEH FINAL FORM +FD1B;FD1B;FD1B;062D 0649;062D 0649; # (ﴛ; ﴛ; ﴛ; حى; حى; ) ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM +FD1C;FD1C;FD1C;062D 064A;062D 064A; # (ﴜ; ﴜ; ﴜ; حي; حي; ) ARABIC LIGATURE HAH WITH YEH FINAL FORM +FD1D;FD1D;FD1D;062C 0649;062C 0649; # (ﴝ; ﴝ; ﴝ; جى; جى; ) ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM +FD1E;FD1E;FD1E;062C 064A;062C 064A; # (ﴞ; ﴞ; ﴞ; جي; جي; ) ARABIC LIGATURE JEEM WITH YEH FINAL FORM +FD1F;FD1F;FD1F;062E 0649;062E 0649; # (ﴟ; ﴟ; ﴟ; خى; خى; ) ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM +FD20;FD20;FD20;062E 064A;062E 064A; # (ﴠ; ﴠ; ﴠ; خي; خي; ) ARABIC LIGATURE KHAH WITH YEH FINAL FORM +FD21;FD21;FD21;0635 0649;0635 0649; # (ﴡ; ﴡ; ﴡ; صى; صى; ) ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM +FD22;FD22;FD22;0635 064A;0635 064A; # (ﴢ; ﴢ; ﴢ; صي; صي; ) ARABIC LIGATURE SAD WITH YEH FINAL FORM +FD23;FD23;FD23;0636 0649;0636 0649; # (ﴣ; ﴣ; ﴣ; ضى; ضى; ) ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM +FD24;FD24;FD24;0636 064A;0636 064A; # (ﴤ; ﴤ; ﴤ; ضي; ضي; ) ARABIC LIGATURE DAD WITH YEH FINAL FORM +FD25;FD25;FD25;0634 062C;0634 062C; # (ﴥ; ﴥ; ﴥ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM +FD26;FD26;FD26;0634 062D;0634 062D; # (ﴦ; ﴦ; ﴦ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH FINAL FORM +FD27;FD27;FD27;0634 062E;0634 062E; # (ﴧ; ﴧ; ﴧ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM +FD28;FD28;FD28;0634 0645;0634 0645; # (ﴨ; ﴨ; ﴨ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM +FD29;FD29;FD29;0634 0631;0634 0631; # (ﴩ; ﴩ; ﴩ; شر; شر; ) ARABIC LIGATURE SHEEN WITH REH FINAL FORM +FD2A;FD2A;FD2A;0633 0631;0633 0631; # (ﴪ; ﴪ; ﴪ; سر; سر; ) ARABIC LIGATURE SEEN WITH REH FINAL FORM +FD2B;FD2B;FD2B;0635 0631;0635 0631; # (ﴫ; ﴫ; ﴫ; صر; صر; ) ARABIC LIGATURE SAD WITH REH FINAL FORM +FD2C;FD2C;FD2C;0636 0631;0636 0631; # (ﴬ; ﴬ; ﴬ; ضر; ضر; ) ARABIC LIGATURE DAD WITH REH FINAL FORM +FD2D;FD2D;FD2D;0634 062C;0634 062C; # (ﴭ; ﴭ; ﴭ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM +FD2E;FD2E;FD2E;0634 062D;0634 062D; # (ﴮ; ﴮ; ﴮ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM +FD2F;FD2F;FD2F;0634 062E;0634 062E; # (ﴯ; ﴯ; ﴯ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM +FD30;FD30;FD30;0634 0645;0634 0645; # (ﴰ; ﴰ; ﴰ; شم; شم; ) ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM +FD31;FD31;FD31;0633 0647;0633 0647; # (ﴱ; ﴱ; ﴱ; سه; سه; ) ARABIC LIGATURE SEEN WITH HEH INITIAL FORM +FD32;FD32;FD32;0634 0647;0634 0647; # (ﴲ; ﴲ; ﴲ; شه; شه; ) ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM +FD33;FD33;FD33;0637 0645;0637 0645; # (ﴳ; ﴳ; ﴳ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM INITIAL FORM +FD34;FD34;FD34;0633 062C;0633 062C; # (ﴴ; ﴴ; ﴴ; سج; سج; ) ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM +FD35;FD35;FD35;0633 062D;0633 062D; # (ﴵ; ﴵ; ﴵ; سح; سح; ) ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM +FD36;FD36;FD36;0633 062E;0633 062E; # (ﴶ; ﴶ; ﴶ; سخ; سخ; ) ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM +FD37;FD37;FD37;0634 062C;0634 062C; # (ﴷ; ﴷ; ﴷ; شج; شج; ) ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM +FD38;FD38;FD38;0634 062D;0634 062D; # (ﴸ; ﴸ; ﴸ; شح; شح; ) ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM +FD39;FD39;FD39;0634 062E;0634 062E; # (ﴹ; ﴹ; ﴹ; شخ; شخ; ) ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM +FD3A;FD3A;FD3A;0637 0645;0637 0645; # (ﴺ; ﴺ; ﴺ; طم; طم; ) ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM +FD3B;FD3B;FD3B;0638 0645;0638 0645; # (ﴻ; ﴻ; ﴻ; ظم; ظم; ) ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM +FD3C;FD3C;FD3C;0627 064B;0627 064B; # (ﴼ; ﴼ; ﴼ; ا◌ً; ا◌ً; ) ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM +FD3D;FD3D;FD3D;0627 064B;0627 064B; # (ﴽ; ﴽ; ﴽ; ا◌ً; ا◌ً; ) ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD50;FD50;FD50;062A 062C 0645;062A 062C 0645; # (ﵐ; ﵐ; ﵐ; تجم; تجم; ) ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM +FD51;FD51;FD51;062A 062D 062C;062A 062D 062C; # (ﵑ; ﵑ; ﵑ; تحج; تحج; ) ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM +FD52;FD52;FD52;062A 062D 062C;062A 062D 062C; # (ﵒ; ﵒ; ﵒ; تحج; تحج; ) ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM +FD53;FD53;FD53;062A 062D 0645;062A 062D 0645; # (ﵓ; ﵓ; ﵓ; تحم; تحم; ) ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM +FD54;FD54;FD54;062A 062E 0645;062A 062E 0645; # (ﵔ; ﵔ; ﵔ; تخم; تخم; ) ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM +FD55;FD55;FD55;062A 0645 062C;062A 0645 062C; # (ﵕ; ﵕ; ﵕ; تمج; تمج; ) ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM +FD56;FD56;FD56;062A 0645 062D;062A 0645 062D; # (ﵖ; ﵖ; ﵖ; تمح; تمح; ) ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM +FD57;FD57;FD57;062A 0645 062E;062A 0645 062E; # (ﵗ; ﵗ; ﵗ; تمخ; تمخ; ) ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM +FD58;FD58;FD58;062C 0645 062D;062C 0645 062D; # (ﵘ; ﵘ; ﵘ; جمح; جمح; ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM +FD59;FD59;FD59;062C 0645 062D;062C 0645 062D; # (ﵙ; ﵙ; ﵙ; جمح; جمح; ) ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM +FD5A;FD5A;FD5A;062D 0645 064A;062D 0645 064A; # (ﵚ; ﵚ; ﵚ; حمي; حمي; ) ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM +FD5B;FD5B;FD5B;062D 0645 0649;062D 0645 0649; # (ﵛ; ﵛ; ﵛ; حمى; حمى; ) ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD5C;FD5C;FD5C;0633 062D 062C;0633 062D 062C; # (ﵜ; ﵜ; ﵜ; سحج; سحج; ) ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM +FD5D;FD5D;FD5D;0633 062C 062D;0633 062C 062D; # (ﵝ; ﵝ; ﵝ; سجح; سجح; ) ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM +FD5E;FD5E;FD5E;0633 062C 0649;0633 062C 0649; # (ﵞ; ﵞ; ﵞ; سجى; سجى; ) ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD5F;FD5F;FD5F;0633 0645 062D;0633 0645 062D; # (ﵟ; ﵟ; ﵟ; سمح; سمح; ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM +FD60;FD60;FD60;0633 0645 062D;0633 0645 062D; # (ﵠ; ﵠ; ﵠ; سمح; سمح; ) ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM +FD61;FD61;FD61;0633 0645 062C;0633 0645 062C; # (ﵡ; ﵡ; ﵡ; سمج; سمج; ) ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM +FD62;FD62;FD62;0633 0645 0645;0633 0645 0645; # (ﵢ; ﵢ; ﵢ; سمم; سمم; ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM +FD63;FD63;FD63;0633 0645 0645;0633 0645 0645; # (ﵣ; ﵣ; ﵣ; سمم; سمم; ) ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM +FD64;FD64;FD64;0635 062D 062D;0635 062D 062D; # (ﵤ; ﵤ; ﵤ; صحح; صحح; ) ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM +FD65;FD65;FD65;0635 062D 062D;0635 062D 062D; # (ﵥ; ﵥ; ﵥ; صحح; صحح; ) ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM +FD66;FD66;FD66;0635 0645 0645;0635 0645 0645; # (ﵦ; ﵦ; ﵦ; صمم; صمم; ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM +FD67;FD67;FD67;0634 062D 0645;0634 062D 0645; # (ﵧ; ﵧ; ﵧ; شحم; شحم; ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM +FD68;FD68;FD68;0634 062D 0645;0634 062D 0645; # (ﵨ; ﵨ; ﵨ; شحم; شحم; ) ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM +FD69;FD69;FD69;0634 062C 064A;0634 062C 064A; # (ﵩ; ﵩ; ﵩ; شجي; شجي; ) ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM +FD6A;FD6A;FD6A;0634 0645 062E;0634 0645 062E; # (ﵪ; ﵪ; ﵪ; شمخ; شمخ; ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM +FD6B;FD6B;FD6B;0634 0645 062E;0634 0645 062E; # (ﵫ; ﵫ; ﵫ; شمخ; شمخ; ) ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM +FD6C;FD6C;FD6C;0634 0645 0645;0634 0645 0645; # (ﵬ; ﵬ; ﵬ; شمم; شمم; ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM +FD6D;FD6D;FD6D;0634 0645 0645;0634 0645 0645; # (ﵭ; ﵭ; ﵭ; شمم; شمم; ) ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM +FD6E;FD6E;FD6E;0636 062D 0649;0636 062D 0649; # (ﵮ; ﵮ; ﵮ; ضحى; ضحى; ) ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM +FD6F;FD6F;FD6F;0636 062E 0645;0636 062E 0645; # (ﵯ; ﵯ; ﵯ; ضخم; ضخم; ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM +FD70;FD70;FD70;0636 062E 0645;0636 062E 0645; # (ﵰ; ﵰ; ﵰ; ضخم; ضخم; ) ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM +FD71;FD71;FD71;0637 0645 062D;0637 0645 062D; # (ﵱ; ﵱ; ﵱ; طمح; طمح; ) ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM +FD72;FD72;FD72;0637 0645 062D;0637 0645 062D; # (ﵲ; ﵲ; ﵲ; طمح; طمح; ) ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM +FD73;FD73;FD73;0637 0645 0645;0637 0645 0645; # (ﵳ; ﵳ; ﵳ; طمم; طمم; ) ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM +FD74;FD74;FD74;0637 0645 064A;0637 0645 064A; # (ﵴ; ﵴ; ﵴ; طمي; طمي; ) ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM +FD75;FD75;FD75;0639 062C 0645;0639 062C 0645; # (ﵵ; ﵵ; ﵵ; عجم; عجم; ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM +FD76;FD76;FD76;0639 0645 0645;0639 0645 0645; # (ﵶ; ﵶ; ﵶ; عمم; عمم; ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM +FD77;FD77;FD77;0639 0645 0645;0639 0645 0645; # (ﵷ; ﵷ; ﵷ; عمم; عمم; ) ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM +FD78;FD78;FD78;0639 0645 0649;0639 0645 0649; # (ﵸ; ﵸ; ﵸ; عمى; عمى; ) ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD79;FD79;FD79;063A 0645 0645;063A 0645 0645; # (ﵹ; ﵹ; ﵹ; غمم; غمم; ) ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM +FD7A;FD7A;FD7A;063A 0645 064A;063A 0645 064A; # (ﵺ; ﵺ; ﵺ; غمي; غمي; ) ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM +FD7B;FD7B;FD7B;063A 0645 0649;063A 0645 0649; # (ﵻ; ﵻ; ﵻ; غمى; غمى; ) ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD7C;FD7C;FD7C;0641 062E 0645;0641 062E 0645; # (ﵼ; ﵼ; ﵼ; فخم; فخم; ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM +FD7D;FD7D;FD7D;0641 062E 0645;0641 062E 0645; # (ﵽ; ﵽ; ﵽ; فخم; فخم; ) ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM +FD7E;FD7E;FD7E;0642 0645 062D;0642 0645 062D; # (ﵾ; ﵾ; ﵾ; قمح; قمح; ) ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM +FD7F;FD7F;FD7F;0642 0645 0645;0642 0645 0645; # (ﵿ; ﵿ; ﵿ; قمم; قمم; ) ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM +FD80;FD80;FD80;0644 062D 0645;0644 062D 0645; # (ﶀ; ﶀ; ﶀ; لحم; لحم; ) ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM +FD81;FD81;FD81;0644 062D 064A;0644 062D 064A; # (ﶁ; ﶁ; ﶁ; لحي; لحي; ) ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM +FD82;FD82;FD82;0644 062D 0649;0644 062D 0649; # (ﶂ; ﶂ; ﶂ; لحى; لحى; ) ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM +FD83;FD83;FD83;0644 062C 062C;0644 062C 062C; # (ﶃ; ﶃ; ﶃ; لجج; لجج; ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM +FD84;FD84;FD84;0644 062C 062C;0644 062C 062C; # (ﶄ; ﶄ; ﶄ; لجج; لجج; ) ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM +FD85;FD85;FD85;0644 062E 0645;0644 062E 0645; # (ﶅ; ﶅ; ﶅ; لخم; لخم; ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM +FD86;FD86;FD86;0644 062E 0645;0644 062E 0645; # (ﶆ; ﶆ; ﶆ; لخم; لخم; ) ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM +FD87;FD87;FD87;0644 0645 062D;0644 0645 062D; # (ﶇ; ﶇ; ﶇ; لمح; لمح; ) ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM +FD88;FD88;FD88;0644 0645 062D;0644 0645 062D; # (ﶈ; ﶈ; ﶈ; لمح; لمح; ) ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM +FD89;FD89;FD89;0645 062D 062C;0645 062D 062C; # (ﶉ; ﶉ; ﶉ; محج; محج; ) ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM +FD8A;FD8A;FD8A;0645 062D 0645;0645 062D 0645; # (ﶊ; ﶊ; ﶊ; محم; محم; ) ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM +FD8B;FD8B;FD8B;0645 062D 064A;0645 062D 064A; # (ﶋ; ﶋ; ﶋ; محي; محي; ) ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM +FD8C;FD8C;FD8C;0645 062C 062D;0645 062C 062D; # (ﶌ; ﶌ; ﶌ; مجح; مجح; ) ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM +FD8D;FD8D;FD8D;0645 062C 0645;0645 062C 0645; # (ﶍ; ﶍ; ﶍ; مجم; مجم; ) ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM +FD8E;FD8E;FD8E;0645 062E 062C;0645 062E 062C; # (ﶎ; ﶎ; ﶎ; مخج; مخج; ) ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM +FD8F;FD8F;FD8F;0645 062E 0645;0645 062E 0645; # (ﶏ; ﶏ; ﶏ; مخم; مخم; ) ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92;FD92;FD92;0645 062C 062E;0645 062C 062E; # (ﶒ; ﶒ; ﶒ; مجخ; مجخ; ) ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM +FD93;FD93;FD93;0647 0645 062C;0647 0645 062C; # (ﶓ; ﶓ; ﶓ; همج; همج; ) ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM +FD94;FD94;FD94;0647 0645 0645;0647 0645 0645; # (ﶔ; ﶔ; ﶔ; همم; همم; ) ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM +FD95;FD95;FD95;0646 062D 0645;0646 062D 0645; # (ﶕ; ﶕ; ﶕ; نحم; نحم; ) ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM +FD96;FD96;FD96;0646 062D 0649;0646 062D 0649; # (ﶖ; ﶖ; ﶖ; نحى; نحى; ) ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM +FD97;FD97;FD97;0646 062C 0645;0646 062C 0645; # (ﶗ; ﶗ; ﶗ; نجم; نجم; ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM +FD98;FD98;FD98;0646 062C 0645;0646 062C 0645; # (ﶘ; ﶘ; ﶘ; نجم; نجم; ) ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM +FD99;FD99;FD99;0646 062C 0649;0646 062C 0649; # (ﶙ; ﶙ; ﶙ; نجى; نجى; ) ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD9A;FD9A;FD9A;0646 0645 064A;0646 0645 064A; # (ﶚ; ﶚ; ﶚ; نمي; نمي; ) ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM +FD9B;FD9B;FD9B;0646 0645 0649;0646 0645 0649; # (ﶛ; ﶛ; ﶛ; نمى; نمى; ) ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD9C;FD9C;FD9C;064A 0645 0645;064A 0645 0645; # (ﶜ; ﶜ; ﶜ; يمم; يمم; ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM +FD9D;FD9D;FD9D;064A 0645 0645;064A 0645 0645; # (ﶝ; ﶝ; ﶝ; يمم; يمم; ) ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM +FD9E;FD9E;FD9E;0628 062E 064A;0628 062E 064A; # (ﶞ; ﶞ; ﶞ; بخي; بخي; ) ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM +FD9F;FD9F;FD9F;062A 062C 064A;062A 062C 064A; # (ﶟ; ﶟ; ﶟ; تجي; تجي; ) ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM +FDA0;FDA0;FDA0;062A 062C 0649;062A 062C 0649; # (ﶠ; ﶠ; ﶠ; تجى; تجى; ) ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM +FDA1;FDA1;FDA1;062A 062E 064A;062A 062E 064A; # (ﶡ; ﶡ; ﶡ; تخي; تخي; ) ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM +FDA2;FDA2;FDA2;062A 062E 0649;062A 062E 0649; # (ﶢ; ﶢ; ﶢ; تخى; تخى; ) ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA3;FDA3;FDA3;062A 0645 064A;062A 0645 064A; # (ﶣ; ﶣ; ﶣ; تمي; تمي; ) ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM +FDA4;FDA4;FDA4;062A 0645 0649;062A 0645 0649; # (ﶤ; ﶤ; ﶤ; تمى; تمى; ) ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA5;FDA5;FDA5;062C 0645 064A;062C 0645 064A; # (ﶥ; ﶥ; ﶥ; جمي; جمي; ) ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM +FDA6;FDA6;FDA6;062C 062D 0649;062C 062D 0649; # (ﶦ; ﶦ; ﶦ; جحى; جحى; ) ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM +FDA7;FDA7;FDA7;062C 0645 0649;062C 0645 0649; # (ﶧ; ﶧ; ﶧ; جمى; جمى; ) ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA8;FDA8;FDA8;0633 062E 0649;0633 062E 0649; # (ﶨ; ﶨ; ﶨ; سخى; سخى; ) ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA9;FDA9;FDA9;0635 062D 064A;0635 062D 064A; # (ﶩ; ﶩ; ﶩ; صحي; صحي; ) ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM +FDAA;FDAA;FDAA;0634 062D 064A;0634 062D 064A; # (ﶪ; ﶪ; ﶪ; شحي; شحي; ) ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM +FDAB;FDAB;FDAB;0636 062D 064A;0636 062D 064A; # (ﶫ; ﶫ; ﶫ; ضحي; ضحي; ) ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM +FDAC;FDAC;FDAC;0644 062C 064A;0644 062C 064A; # (ﶬ; ﶬ; ﶬ; لجي; لجي; ) ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM +FDAD;FDAD;FDAD;0644 0645 064A;0644 0645 064A; # (ﶭ; ﶭ; ﶭ; لمي; لمي; ) ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM +FDAE;FDAE;FDAE;064A 062D 064A;064A 062D 064A; # (ﶮ; ﶮ; ﶮ; يحي; يحي; ) ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM +FDAF;FDAF;FDAF;064A 062C 064A;064A 062C 064A; # (ﶯ; ﶯ; ﶯ; يجي; يجي; ) ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM +FDB0;FDB0;FDB0;064A 0645 064A;064A 0645 064A; # (ﶰ; ﶰ; ﶰ; يمي; يمي; ) ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM +FDB1;FDB1;FDB1;0645 0645 064A;0645 0645 064A; # (ﶱ; ﶱ; ﶱ; ممي; ممي; ) ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM +FDB2;FDB2;FDB2;0642 0645 064A;0642 0645 064A; # (ﶲ; ﶲ; ﶲ; قمي; قمي; ) ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM +FDB3;FDB3;FDB3;0646 062D 064A;0646 062D 064A; # (ﶳ; ﶳ; ﶳ; نحي; نحي; ) ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM +FDB4;FDB4;FDB4;0642 0645 062D;0642 0645 062D; # (ﶴ; ﶴ; ﶴ; قمح; قمح; ) ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM +FDB5;FDB5;FDB5;0644 062D 0645;0644 062D 0645; # (ﶵ; ﶵ; ﶵ; لحم; لحم; ) ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM +FDB6;FDB6;FDB6;0639 0645 064A;0639 0645 064A; # (ﶶ; ﶶ; ﶶ; عمي; عمي; ) ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM +FDB7;FDB7;FDB7;0643 0645 064A;0643 0645 064A; # (ﶷ; ﶷ; ﶷ; كمي; كمي; ) ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM +FDB8;FDB8;FDB8;0646 062C 062D;0646 062C 062D; # (ﶸ; ﶸ; ﶸ; نجح; نجح; ) ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM +FDB9;FDB9;FDB9;0645 062E 064A;0645 062E 064A; # (ﶹ; ﶹ; ﶹ; مخي; مخي; ) ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM +FDBA;FDBA;FDBA;0644 062C 0645;0644 062C 0645; # (ﶺ; ﶺ; ﶺ; لجم; لجم; ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM +FDBB;FDBB;FDBB;0643 0645 0645;0643 0645 0645; # (ﶻ; ﶻ; ﶻ; كمم; كمم; ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM +FDBC;FDBC;FDBC;0644 062C 0645;0644 062C 0645; # (ﶼ; ﶼ; ﶼ; لجم; لجم; ) ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM +FDBD;FDBD;FDBD;0646 062C 062D;0646 062C 062D; # (ﶽ; ﶽ; ﶽ; نجح; نجح; ) ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM +FDBE;FDBE;FDBE;062C 062D 064A;062C 062D 064A; # (ﶾ; ﶾ; ﶾ; جحي; جحي; ) ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM +FDBF;FDBF;FDBF;062D 062C 064A;062D 062C 064A; # (ﶿ; ﶿ; ﶿ; حجي; حجي; ) ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM +FDC0;FDC0;FDC0;0645 062C 064A;0645 062C 064A; # (ﷀ; ﷀ; ﷀ; مجي; مجي; ) ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM +FDC1;FDC1;FDC1;0641 0645 064A;0641 0645 064A; # (ﷁ; ﷁ; ﷁ; فمي; فمي; ) ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM +FDC2;FDC2;FDC2;0628 062D 064A;0628 062D 064A; # (ﷂ; ﷂ; ﷂ; بحي; بحي; ) ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM +FDC3;FDC3;FDC3;0643 0645 0645;0643 0645 0645; # (ﷃ; ﷃ; ﷃ; كمم; كمم; ) ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM +FDC4;FDC4;FDC4;0639 062C 0645;0639 062C 0645; # (ﷄ; ﷄ; ﷄ; عجم; عجم; ) ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM +FDC5;FDC5;FDC5;0635 0645 0645;0635 0645 0645; # (ﷅ; ﷅ; ﷅ; صمم; صمم; ) ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM +FDC6;FDC6;FDC6;0633 062E 064A;0633 062E 064A; # (ﷆ; ﷆ; ﷆ; سخي; سخي; ) ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM +FDC7;FDC7;FDC7;0646 062C 064A;0646 062C 064A; # (ﷇ; ﷇ; ﷇ; نجي; نجي; ) ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDF0;FDF0;FDF0;0635 0644 06D2;0635 0644 06D2; # (ﷰ; ﷰ; ﷰ; صلے; صلے; ) ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF1;FDF1;FDF1;0642 0644 06D2;0642 0644 06D2; # (ﷱ; ﷱ; ﷱ; قلے; قلے; ) ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF2;FDF2;FDF2;0627 0644 0644 0647;0627 0644 0644 0647; # (ﷲ; ﷲ; ﷲ; الله; الله; ) ARABIC LIGATURE ALLAH ISOLATED FORM +FDF3;FDF3;FDF3;0627 0643 0628 0631;0627 0643 0628 0631; # (ﷳ; ﷳ; ﷳ; اكبر; اكبر; ) ARABIC LIGATURE AKBAR ISOLATED FORM +FDF4;FDF4;FDF4;0645 062D 0645 062F;0645 062D 0645 062F; # (ﷴ; ﷴ; ﷴ; محمد; محمد; ) ARABIC LIGATURE MOHAMMAD ISOLATED FORM +FDF5;FDF5;FDF5;0635 0644 0639 0645;0635 0644 0639 0645; # (ﷵ; ﷵ; ﷵ; صلعم; صلعم; ) ARABIC LIGATURE SALAM ISOLATED FORM +FDF6;FDF6;FDF6;0631 0633 0648 0644;0631 0633 0648 0644; # (ﷶ; ﷶ; ﷶ; رسول; رسول; ) ARABIC LIGATURE RASOUL ISOLATED FORM +FDF7;FDF7;FDF7;0639 0644 064A 0647;0639 0644 064A 0647; # (ﷷ; ﷷ; ﷷ; عليه; عليه; ) ARABIC LIGATURE ALAYHE ISOLATED FORM +FDF8;FDF8;FDF8;0648 0633 0644 0645;0648 0633 0644 0645; # (ﷸ; ﷸ; ﷸ; وسلم; وسلم; ) ARABIC LIGATURE WASALLAM ISOLATED FORM +FDF9;FDF9;FDF9;0635 0644 0649;0635 0644 0649; # (ﷹ; ﷹ; ﷹ; صلى; صلى; ) ARABIC LIGATURE SALLA ISOLATED FORM +FDFA;FDFA;FDFA;0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645; # (ﷺ; ﷺ; ﷺ; صلى الله عليه وسلم; صلى الله عليه وسلم; ) ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM +FDFB;FDFB;FDFB;062C 0644 0020 062C 0644 0627 0644 0647;062C 0644 0020 062C 0644 0627 0644 0647; # (ﷻ; ﷻ; ﷻ; جل جلاله; جل جلاله; ) ARABIC LIGATURE JALLAJALALOUHOU +FDFC;FDFC;FDFC;0631 06CC 0627 0644;0631 06CC 0627 0644; # (﷼; ﷼; ﷼; ریال; ریال; ) RIAL SIGN +FE10;FE10;FE10;002C;002C; # (︐; ︐; ︐; ,; ,; ) PRESENTATION FORM FOR VERTICAL COMMA +FE11;FE11;FE11;3001;3001; # (︑; ︑; ︑; 、; 、; ) PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA +FE12;FE12;FE12;3002;3002; # (︒; ︒; ︒; 。; 。; ) PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE13;FE13;FE13;003A;003A; # (︓; ︓; ︓; :; :; ) PRESENTATION FORM FOR VERTICAL COLON +FE14;FE14;FE14;003B;003B; # (︔; ︔; ︔; ;; ;; ) PRESENTATION FORM FOR VERTICAL SEMICOLON +FE15;FE15;FE15;0021;0021; # (︕; ︕; ︕; !; !; ) PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK +FE16;FE16;FE16;003F;003F; # (︖; ︖; ︖; ?; ?; ) PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE17;FE17;FE17;3016;3016; # (︗; ︗; ︗; 〖; 〖; ) PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET +FE18;FE18;FE18;3017;3017; # (︘; ︘; ︘; 〗; 〗; ) PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET +FE19;FE19;FE19;002E 002E 002E;002E 002E 002E; # (︙; ︙; ︙; ...; ...; ) PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS +FE30;FE30;FE30;002E 002E;002E 002E; # (︰; ︰; ︰; ..; ..; ) PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31;FE31;FE31;2014;2014; # (︱; ︱; ︱; —; —; ) PRESENTATION FORM FOR VERTICAL EM DASH +FE32;FE32;FE32;2013;2013; # (︲; ︲; ︲; –; –; ) PRESENTATION FORM FOR VERTICAL EN DASH +FE33;FE33;FE33;005F;005F; # (︳; ︳; ︳; _; _; ) PRESENTATION FORM FOR VERTICAL LOW LINE +FE34;FE34;FE34;005F;005F; # (︴; ︴; ︴; _; _; ) PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35;FE35;FE35;0028;0028; # (︵; ︵; ︵; (; (; ) PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36;FE36;FE36;0029;0029; # (︶; ︶; ︶; ); ); ) PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37;FE37;FE37;007B;007B; # (︷; ︷; ︷; {; {; ) PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38;FE38;FE38;007D;007D; # (︸; ︸; ︸; }; }; ) PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39;FE39;FE39;3014;3014; # (︹; ︹; ︹; 〔; 〔; ) PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A;FE3A;FE3A;3015;3015; # (︺; ︺; ︺; 〕; 〕; ) PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B;FE3B;FE3B;3010;3010; # (︻; ︻; ︻; 【; 【; ) PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C;FE3C;FE3C;3011;3011; # (︼; ︼; ︼; 】; 】; ) PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D;FE3D;FE3D;300A;300A; # (︽; ︽; ︽; 《; 《; ) PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E;FE3E;FE3E;300B;300B; # (︾; ︾; ︾; 》; 》; ) PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F;FE3F;FE3F;3008;3008; # (︿; ︿; ︿; 〈; 〈; ) PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40;FE40;FE40;3009;3009; # (﹀; ﹀; ﹀; 〉; 〉; ) PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41;FE41;FE41;300C;300C; # (﹁; ﹁; ﹁; 「; 「; ) PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42;FE42;FE42;300D;300D; # (﹂; ﹂; ﹂; 」; 」; ) PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43;FE43;FE43;300E;300E; # (﹃; ﹃; ﹃; 『; 『; ) PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44;FE44;FE44;300F;300F; # (﹄; ﹄; ﹄; 』; 』; ) PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE47;FE47;FE47;005B;005B; # (﹇; ﹇; ﹇; [; [; ) PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET +FE48;FE48;FE48;005D;005D; # (﹈; ﹈; ﹈; ]; ]; ) PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET +FE49;FE49;FE49;0020 0305;0020 0305; # (﹉; ﹉; ﹉; ◌̅; ◌̅; ) DASHED OVERLINE +FE4A;FE4A;FE4A;0020 0305;0020 0305; # (﹊; ﹊; ﹊; ◌̅; ◌̅; ) CENTRELINE OVERLINE +FE4B;FE4B;FE4B;0020 0305;0020 0305; # (﹋; ﹋; ﹋; ◌̅; ◌̅; ) WAVY OVERLINE +FE4C;FE4C;FE4C;0020 0305;0020 0305; # (﹌; ﹌; ﹌; ◌̅; ◌̅; ) DOUBLE WAVY OVERLINE +FE4D;FE4D;FE4D;005F;005F; # (﹍; ﹍; ﹍; _; _; ) DASHED LOW LINE +FE4E;FE4E;FE4E;005F;005F; # (﹎; ﹎; ﹎; _; _; ) CENTRELINE LOW LINE +FE4F;FE4F;FE4F;005F;005F; # (﹏; ﹏; ﹏; _; _; ) WAVY LOW LINE +FE50;FE50;FE50;002C;002C; # (﹐; ﹐; ﹐; ,; ,; ) SMALL COMMA +FE51;FE51;FE51;3001;3001; # (﹑; ﹑; ﹑; 、; 、; ) SMALL IDEOGRAPHIC COMMA +FE52;FE52;FE52;002E;002E; # (﹒; ﹒; ﹒; .; .; ) SMALL FULL STOP +FE54;FE54;FE54;003B;003B; # (﹔; ﹔; ﹔; ;; ;; ) SMALL SEMICOLON +FE55;FE55;FE55;003A;003A; # (﹕; ﹕; ﹕; :; :; ) SMALL COLON +FE56;FE56;FE56;003F;003F; # (﹖; ﹖; ﹖; ?; ?; ) SMALL QUESTION MARK +FE57;FE57;FE57;0021;0021; # (﹗; ﹗; ﹗; !; !; ) SMALL EXCLAMATION MARK +FE58;FE58;FE58;2014;2014; # (﹘; ﹘; ﹘; —; —; ) SMALL EM DASH +FE59;FE59;FE59;0028;0028; # (﹙; ﹙; ﹙; (; (; ) SMALL LEFT PARENTHESIS +FE5A;FE5A;FE5A;0029;0029; # (﹚; ﹚; ﹚; ); ); ) SMALL RIGHT PARENTHESIS +FE5B;FE5B;FE5B;007B;007B; # (﹛; ﹛; ﹛; {; {; ) SMALL LEFT CURLY BRACKET +FE5C;FE5C;FE5C;007D;007D; # (﹜; ﹜; ﹜; }; }; ) SMALL RIGHT CURLY BRACKET +FE5D;FE5D;FE5D;3014;3014; # (﹝; ﹝; ﹝; 〔; 〔; ) SMALL LEFT TORTOISE SHELL BRACKET +FE5E;FE5E;FE5E;3015;3015; # (﹞; ﹞; ﹞; 〕; 〕; ) SMALL RIGHT TORTOISE SHELL BRACKET +FE5F;FE5F;FE5F;0023;0023; # (﹟; ﹟; ﹟; #; #; ) SMALL NUMBER SIGN +FE60;FE60;FE60;0026;0026; # (﹠; ﹠; ﹠; &; &; ) SMALL AMPERSAND +FE61;FE61;FE61;002A;002A; # (﹡; ﹡; ﹡; *; *; ) SMALL ASTERISK +FE62;FE62;FE62;002B;002B; # (﹢; ﹢; ﹢; +; +; ) SMALL PLUS SIGN +FE63;FE63;FE63;002D;002D; # (﹣; ﹣; ﹣; -; -; ) SMALL HYPHEN-MINUS +FE64;FE64;FE64;003C;003C; # (﹤; ﹤; ﹤; <; <; ) SMALL LESS-THAN SIGN +FE65;FE65;FE65;003E;003E; # (﹥; ﹥; ﹥; >; >; ) SMALL GREATER-THAN SIGN +FE66;FE66;FE66;003D;003D; # (﹦; ﹦; ﹦; =; =; ) SMALL EQUALS SIGN +FE68;FE68;FE68;005C;005C; # (﹨; ﹨; ﹨; \; \; ) SMALL REVERSE SOLIDUS +FE69;FE69;FE69;0024;0024; # (﹩; ﹩; ﹩; $; $; ) SMALL DOLLAR SIGN +FE6A;FE6A;FE6A;0025;0025; # (﹪; ﹪; ﹪; %; %; ) SMALL PERCENT SIGN +FE6B;FE6B;FE6B;0040;0040; # (﹫; ﹫; ﹫; @; @; ) SMALL COMMERCIAL AT +FE70;FE70;FE70;0020 064B;0020 064B; # (ﹰ; ﹰ; ﹰ; ◌ً; ◌ً; ) ARABIC FATHATAN ISOLATED FORM +FE71;FE71;FE71;0640 064B;0640 064B; # (ﹱ; ﹱ; ﹱ; ـ◌ً; ـ◌ً; ) ARABIC TATWEEL WITH FATHATAN ABOVE +FE72;FE72;FE72;0020 064C;0020 064C; # (ﹲ; ﹲ; ﹲ; ◌ٌ; ◌ٌ; ) ARABIC DAMMATAN ISOLATED FORM +FE74;FE74;FE74;0020 064D;0020 064D; # (ﹴ; ﹴ; ﹴ; ◌ٍ; ◌ٍ; ) ARABIC KASRATAN ISOLATED FORM +FE76;FE76;FE76;0020 064E;0020 064E; # (ﹶ; ﹶ; ﹶ; ◌َ; ◌َ; ) ARABIC FATHA ISOLATED FORM +FE77;FE77;FE77;0640 064E;0640 064E; # (ﹷ; ﹷ; ﹷ; ـ◌َ; ـ◌َ; ) ARABIC FATHA MEDIAL FORM +FE78;FE78;FE78;0020 064F;0020 064F; # (ﹸ; ﹸ; ﹸ; ◌ُ; ◌ُ; ) ARABIC DAMMA ISOLATED FORM +FE79;FE79;FE79;0640 064F;0640 064F; # (ﹹ; ﹹ; ﹹ; ـ◌ُ; ـ◌ُ; ) ARABIC DAMMA MEDIAL FORM +FE7A;FE7A;FE7A;0020 0650;0020 0650; # (ﹺ; ﹺ; ﹺ; ◌ِ; ◌ِ; ) ARABIC KASRA ISOLATED FORM +FE7B;FE7B;FE7B;0640 0650;0640 0650; # (ﹻ; ﹻ; ﹻ; ـ◌ِ; ـ◌ِ; ) ARABIC KASRA MEDIAL FORM +FE7C;FE7C;FE7C;0020 0651;0020 0651; # (ﹼ; ﹼ; ﹼ; ◌ّ; ◌ّ; ) ARABIC SHADDA ISOLATED FORM +FE7D;FE7D;FE7D;0640 0651;0640 0651; # (ﹽ; ﹽ; ﹽ; ـ◌ّ; ـ◌ّ; ) ARABIC SHADDA MEDIAL FORM +FE7E;FE7E;FE7E;0020 0652;0020 0652; # (ﹾ; ﹾ; ﹾ; ◌ْ; ◌ْ; ) ARABIC SUKUN ISOLATED FORM +FE7F;FE7F;FE7F;0640 0652;0640 0652; # (ﹿ; ﹿ; ﹿ; ـ◌ْ; ـ◌ْ; ) ARABIC SUKUN MEDIAL FORM +FE80;FE80;FE80;0621;0621; # (ﺀ; ﺀ; ﺀ; ء; ء; ) ARABIC LETTER HAMZA ISOLATED FORM +FE81;FE81;FE81;0622;0627 0653; # (ﺁ; ﺁ; ﺁ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM +FE82;FE82;FE82;0622;0627 0653; # (ﺂ; ﺂ; ﺂ; آ; ا◌ٓ; ) ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +FE83;FE83;FE83;0623;0627 0654; # (ﺃ; ﺃ; ﺃ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM +FE84;FE84;FE84;0623;0627 0654; # (ﺄ; ﺄ; ﺄ; أ; ا◌ٔ; ) ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +FE85;FE85;FE85;0624;0648 0654; # (ﺅ; ﺅ; ﺅ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM +FE86;FE86;FE86;0624;0648 0654; # (ﺆ; ﺆ; ﺆ; ؤ; و◌ٔ; ) ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +FE87;FE87;FE87;0625;0627 0655; # (ﺇ; ﺇ; ﺇ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM +FE88;FE88;FE88;0625;0627 0655; # (ﺈ; ﺈ; ﺈ; إ; ا◌ٕ; ) ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +FE89;FE89;FE89;0626;064A 0654; # (ﺉ; ﺉ; ﺉ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM +FE8A;FE8A;FE8A;0626;064A 0654; # (ﺊ; ﺊ; ﺊ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM +FE8B;FE8B;FE8B;0626;064A 0654; # (ﺋ; ﺋ; ﺋ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM +FE8C;FE8C;FE8C;0626;064A 0654; # (ﺌ; ﺌ; ﺌ; ئ; ي◌ٔ; ) ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +FE8D;FE8D;FE8D;0627;0627; # (ﺍ; ﺍ; ﺍ; ا; ا; ) ARABIC LETTER ALEF ISOLATED FORM +FE8E;FE8E;FE8E;0627;0627; # (ﺎ; ﺎ; ﺎ; ا; ا; ) ARABIC LETTER ALEF FINAL FORM +FE8F;FE8F;FE8F;0628;0628; # (ﺏ; ﺏ; ﺏ; ب; ب; ) ARABIC LETTER BEH ISOLATED FORM +FE90;FE90;FE90;0628;0628; # (ﺐ; ﺐ; ﺐ; ب; ب; ) ARABIC LETTER BEH FINAL FORM +FE91;FE91;FE91;0628;0628; # (ﺑ; ﺑ; ﺑ; ب; ب; ) ARABIC LETTER BEH INITIAL FORM +FE92;FE92;FE92;0628;0628; # (ﺒ; ﺒ; ﺒ; ب; ب; ) ARABIC LETTER BEH MEDIAL FORM +FE93;FE93;FE93;0629;0629; # (ﺓ; ﺓ; ﺓ; ة; ة; ) ARABIC LETTER TEH MARBUTA ISOLATED FORM +FE94;FE94;FE94;0629;0629; # (ﺔ; ﺔ; ﺔ; ة; ة; ) ARABIC LETTER TEH MARBUTA FINAL FORM +FE95;FE95;FE95;062A;062A; # (ﺕ; ﺕ; ﺕ; ت; ت; ) ARABIC LETTER TEH ISOLATED FORM +FE96;FE96;FE96;062A;062A; # (ﺖ; ﺖ; ﺖ; ت; ت; ) ARABIC LETTER TEH FINAL FORM +FE97;FE97;FE97;062A;062A; # (ﺗ; ﺗ; ﺗ; ت; ت; ) ARABIC LETTER TEH INITIAL FORM +FE98;FE98;FE98;062A;062A; # (ﺘ; ﺘ; ﺘ; ت; ت; ) ARABIC LETTER TEH MEDIAL FORM +FE99;FE99;FE99;062B;062B; # (ﺙ; ﺙ; ﺙ; ث; ث; ) ARABIC LETTER THEH ISOLATED FORM +FE9A;FE9A;FE9A;062B;062B; # (ﺚ; ﺚ; ﺚ; ث; ث; ) ARABIC LETTER THEH FINAL FORM +FE9B;FE9B;FE9B;062B;062B; # (ﺛ; ﺛ; ﺛ; ث; ث; ) ARABIC LETTER THEH INITIAL FORM +FE9C;FE9C;FE9C;062B;062B; # (ﺜ; ﺜ; ﺜ; ث; ث; ) ARABIC LETTER THEH MEDIAL FORM +FE9D;FE9D;FE9D;062C;062C; # (ﺝ; ﺝ; ﺝ; ج; ج; ) ARABIC LETTER JEEM ISOLATED FORM +FE9E;FE9E;FE9E;062C;062C; # (ﺞ; ﺞ; ﺞ; ج; ج; ) ARABIC LETTER JEEM FINAL FORM +FE9F;FE9F;FE9F;062C;062C; # (ﺟ; ﺟ; ﺟ; ج; ج; ) ARABIC LETTER JEEM INITIAL FORM +FEA0;FEA0;FEA0;062C;062C; # (ﺠ; ﺠ; ﺠ; ج; ج; ) ARABIC LETTER JEEM MEDIAL FORM +FEA1;FEA1;FEA1;062D;062D; # (ﺡ; ﺡ; ﺡ; ح; ح; ) ARABIC LETTER HAH ISOLATED FORM +FEA2;FEA2;FEA2;062D;062D; # (ﺢ; ﺢ; ﺢ; ح; ح; ) ARABIC LETTER HAH FINAL FORM +FEA3;FEA3;FEA3;062D;062D; # (ﺣ; ﺣ; ﺣ; ح; ح; ) ARABIC LETTER HAH INITIAL FORM +FEA4;FEA4;FEA4;062D;062D; # (ﺤ; ﺤ; ﺤ; ح; ح; ) ARABIC LETTER HAH MEDIAL FORM +FEA5;FEA5;FEA5;062E;062E; # (ﺥ; ﺥ; ﺥ; خ; خ; ) ARABIC LETTER KHAH ISOLATED FORM +FEA6;FEA6;FEA6;062E;062E; # (ﺦ; ﺦ; ﺦ; خ; خ; ) ARABIC LETTER KHAH FINAL FORM +FEA7;FEA7;FEA7;062E;062E; # (ﺧ; ﺧ; ﺧ; خ; خ; ) ARABIC LETTER KHAH INITIAL FORM +FEA8;FEA8;FEA8;062E;062E; # (ﺨ; ﺨ; ﺨ; خ; خ; ) ARABIC LETTER KHAH MEDIAL FORM +FEA9;FEA9;FEA9;062F;062F; # (ﺩ; ﺩ; ﺩ; د; د; ) ARABIC LETTER DAL ISOLATED FORM +FEAA;FEAA;FEAA;062F;062F; # (ﺪ; ﺪ; ﺪ; د; د; ) ARABIC LETTER DAL FINAL FORM +FEAB;FEAB;FEAB;0630;0630; # (ﺫ; ﺫ; ﺫ; ذ; ذ; ) ARABIC LETTER THAL ISOLATED FORM +FEAC;FEAC;FEAC;0630;0630; # (ﺬ; ﺬ; ﺬ; ذ; ذ; ) ARABIC LETTER THAL FINAL FORM +FEAD;FEAD;FEAD;0631;0631; # (ﺭ; ﺭ; ﺭ; ر; ر; ) ARABIC LETTER REH ISOLATED FORM +FEAE;FEAE;FEAE;0631;0631; # (ﺮ; ﺮ; ﺮ; ر; ر; ) ARABIC LETTER REH FINAL FORM +FEAF;FEAF;FEAF;0632;0632; # (ﺯ; ﺯ; ﺯ; ز; ز; ) ARABIC LETTER ZAIN ISOLATED FORM +FEB0;FEB0;FEB0;0632;0632; # (ﺰ; ﺰ; ﺰ; ز; ز; ) ARABIC LETTER ZAIN FINAL FORM +FEB1;FEB1;FEB1;0633;0633; # (ﺱ; ﺱ; ﺱ; س; س; ) ARABIC LETTER SEEN ISOLATED FORM +FEB2;FEB2;FEB2;0633;0633; # (ﺲ; ﺲ; ﺲ; س; س; ) ARABIC LETTER SEEN FINAL FORM +FEB3;FEB3;FEB3;0633;0633; # (ﺳ; ﺳ; ﺳ; س; س; ) ARABIC LETTER SEEN INITIAL FORM +FEB4;FEB4;FEB4;0633;0633; # (ﺴ; ﺴ; ﺴ; س; س; ) ARABIC LETTER SEEN MEDIAL FORM +FEB5;FEB5;FEB5;0634;0634; # (ﺵ; ﺵ; ﺵ; ش; ش; ) ARABIC LETTER SHEEN ISOLATED FORM +FEB6;FEB6;FEB6;0634;0634; # (ﺶ; ﺶ; ﺶ; ش; ش; ) ARABIC LETTER SHEEN FINAL FORM +FEB7;FEB7;FEB7;0634;0634; # (ﺷ; ﺷ; ﺷ; ش; ش; ) ARABIC LETTER SHEEN INITIAL FORM +FEB8;FEB8;FEB8;0634;0634; # (ﺸ; ﺸ; ﺸ; ش; ش; ) ARABIC LETTER SHEEN MEDIAL FORM +FEB9;FEB9;FEB9;0635;0635; # (ﺹ; ﺹ; ﺹ; ص; ص; ) ARABIC LETTER SAD ISOLATED FORM +FEBA;FEBA;FEBA;0635;0635; # (ﺺ; ﺺ; ﺺ; ص; ص; ) ARABIC LETTER SAD FINAL FORM +FEBB;FEBB;FEBB;0635;0635; # (ﺻ; ﺻ; ﺻ; ص; ص; ) ARABIC LETTER SAD INITIAL FORM +FEBC;FEBC;FEBC;0635;0635; # (ﺼ; ﺼ; ﺼ; ص; ص; ) ARABIC LETTER SAD MEDIAL FORM +FEBD;FEBD;FEBD;0636;0636; # (ﺽ; ﺽ; ﺽ; ض; ض; ) ARABIC LETTER DAD ISOLATED FORM +FEBE;FEBE;FEBE;0636;0636; # (ﺾ; ﺾ; ﺾ; ض; ض; ) ARABIC LETTER DAD FINAL FORM +FEBF;FEBF;FEBF;0636;0636; # (ﺿ; ﺿ; ﺿ; ض; ض; ) ARABIC LETTER DAD INITIAL FORM +FEC0;FEC0;FEC0;0636;0636; # (ﻀ; ﻀ; ﻀ; ض; ض; ) ARABIC LETTER DAD MEDIAL FORM +FEC1;FEC1;FEC1;0637;0637; # (ﻁ; ﻁ; ﻁ; ط; ط; ) ARABIC LETTER TAH ISOLATED FORM +FEC2;FEC2;FEC2;0637;0637; # (ﻂ; ﻂ; ﻂ; ط; ط; ) ARABIC LETTER TAH FINAL FORM +FEC3;FEC3;FEC3;0637;0637; # (ﻃ; ﻃ; ﻃ; ط; ط; ) ARABIC LETTER TAH INITIAL FORM +FEC4;FEC4;FEC4;0637;0637; # (ﻄ; ﻄ; ﻄ; ط; ط; ) ARABIC LETTER TAH MEDIAL FORM +FEC5;FEC5;FEC5;0638;0638; # (ﻅ; ﻅ; ﻅ; ظ; ظ; ) ARABIC LETTER ZAH ISOLATED FORM +FEC6;FEC6;FEC6;0638;0638; # (ﻆ; ﻆ; ﻆ; ظ; ظ; ) ARABIC LETTER ZAH FINAL FORM +FEC7;FEC7;FEC7;0638;0638; # (ﻇ; ﻇ; ﻇ; ظ; ظ; ) ARABIC LETTER ZAH INITIAL FORM +FEC8;FEC8;FEC8;0638;0638; # (ﻈ; ﻈ; ﻈ; ظ; ظ; ) ARABIC LETTER ZAH MEDIAL FORM +FEC9;FEC9;FEC9;0639;0639; # (ﻉ; ﻉ; ﻉ; ع; ع; ) ARABIC LETTER AIN ISOLATED FORM +FECA;FECA;FECA;0639;0639; # (ﻊ; ﻊ; ﻊ; ع; ع; ) ARABIC LETTER AIN FINAL FORM +FECB;FECB;FECB;0639;0639; # (ﻋ; ﻋ; ﻋ; ع; ع; ) ARABIC LETTER AIN INITIAL FORM +FECC;FECC;FECC;0639;0639; # (ﻌ; ﻌ; ﻌ; ع; ع; ) ARABIC LETTER AIN MEDIAL FORM +FECD;FECD;FECD;063A;063A; # (ﻍ; ﻍ; ﻍ; غ; غ; ) ARABIC LETTER GHAIN ISOLATED FORM +FECE;FECE;FECE;063A;063A; # (ﻎ; ﻎ; ﻎ; غ; غ; ) ARABIC LETTER GHAIN FINAL FORM +FECF;FECF;FECF;063A;063A; # (ﻏ; ﻏ; ﻏ; غ; غ; ) ARABIC LETTER GHAIN INITIAL FORM +FED0;FED0;FED0;063A;063A; # (ﻐ; ﻐ; ﻐ; غ; غ; ) ARABIC LETTER GHAIN MEDIAL FORM +FED1;FED1;FED1;0641;0641; # (ﻑ; ﻑ; ﻑ; ف; ف; ) ARABIC LETTER FEH ISOLATED FORM +FED2;FED2;FED2;0641;0641; # (ﻒ; ﻒ; ﻒ; ف; ف; ) ARABIC LETTER FEH FINAL FORM +FED3;FED3;FED3;0641;0641; # (ﻓ; ﻓ; ﻓ; ف; ف; ) ARABIC LETTER FEH INITIAL FORM +FED4;FED4;FED4;0641;0641; # (ﻔ; ﻔ; ﻔ; ف; ف; ) ARABIC LETTER FEH MEDIAL FORM +FED5;FED5;FED5;0642;0642; # (ﻕ; ﻕ; ﻕ; ق; ق; ) ARABIC LETTER QAF ISOLATED FORM +FED6;FED6;FED6;0642;0642; # (ﻖ; ﻖ; ﻖ; ق; ق; ) ARABIC LETTER QAF FINAL FORM +FED7;FED7;FED7;0642;0642; # (ﻗ; ﻗ; ﻗ; ق; ق; ) ARABIC LETTER QAF INITIAL FORM +FED8;FED8;FED8;0642;0642; # (ﻘ; ﻘ; ﻘ; ق; ق; ) ARABIC LETTER QAF MEDIAL FORM +FED9;FED9;FED9;0643;0643; # (ﻙ; ﻙ; ﻙ; ك; ك; ) ARABIC LETTER KAF ISOLATED FORM +FEDA;FEDA;FEDA;0643;0643; # (ﻚ; ﻚ; ﻚ; ك; ك; ) ARABIC LETTER KAF FINAL FORM +FEDB;FEDB;FEDB;0643;0643; # (ﻛ; ﻛ; ﻛ; ك; ك; ) ARABIC LETTER KAF INITIAL FORM +FEDC;FEDC;FEDC;0643;0643; # (ﻜ; ﻜ; ﻜ; ك; ك; ) ARABIC LETTER KAF MEDIAL FORM +FEDD;FEDD;FEDD;0644;0644; # (ﻝ; ﻝ; ﻝ; ل; ل; ) ARABIC LETTER LAM ISOLATED FORM +FEDE;FEDE;FEDE;0644;0644; # (ﻞ; ﻞ; ﻞ; ل; ل; ) ARABIC LETTER LAM FINAL FORM +FEDF;FEDF;FEDF;0644;0644; # (ﻟ; ﻟ; ﻟ; ل; ل; ) ARABIC LETTER LAM INITIAL FORM +FEE0;FEE0;FEE0;0644;0644; # (ﻠ; ﻠ; ﻠ; ل; ل; ) ARABIC LETTER LAM MEDIAL FORM +FEE1;FEE1;FEE1;0645;0645; # (ﻡ; ﻡ; ﻡ; م; م; ) ARABIC LETTER MEEM ISOLATED FORM +FEE2;FEE2;FEE2;0645;0645; # (ﻢ; ﻢ; ﻢ; م; م; ) ARABIC LETTER MEEM FINAL FORM +FEE3;FEE3;FEE3;0645;0645; # (ﻣ; ﻣ; ﻣ; م; م; ) ARABIC LETTER MEEM INITIAL FORM +FEE4;FEE4;FEE4;0645;0645; # (ﻤ; ﻤ; ﻤ; م; م; ) ARABIC LETTER MEEM MEDIAL FORM +FEE5;FEE5;FEE5;0646;0646; # (ﻥ; ﻥ; ﻥ; ن; ن; ) ARABIC LETTER NOON ISOLATED FORM +FEE6;FEE6;FEE6;0646;0646; # (ﻦ; ﻦ; ﻦ; ن; ن; ) ARABIC LETTER NOON FINAL FORM +FEE7;FEE7;FEE7;0646;0646; # (ﻧ; ﻧ; ﻧ; ن; ن; ) ARABIC LETTER NOON INITIAL FORM +FEE8;FEE8;FEE8;0646;0646; # (ﻨ; ﻨ; ﻨ; ن; ن; ) ARABIC LETTER NOON MEDIAL FORM +FEE9;FEE9;FEE9;0647;0647; # (ﻩ; ﻩ; ﻩ; ه; ه; ) ARABIC LETTER HEH ISOLATED FORM +FEEA;FEEA;FEEA;0647;0647; # (ﻪ; ﻪ; ﻪ; ه; ه; ) ARABIC LETTER HEH FINAL FORM +FEEB;FEEB;FEEB;0647;0647; # (ﻫ; ﻫ; ﻫ; ه; ه; ) ARABIC LETTER HEH INITIAL FORM +FEEC;FEEC;FEEC;0647;0647; # (ﻬ; ﻬ; ﻬ; ه; ه; ) ARABIC LETTER HEH MEDIAL FORM +FEED;FEED;FEED;0648;0648; # (ﻭ; ﻭ; ﻭ; و; و; ) ARABIC LETTER WAW ISOLATED FORM +FEEE;FEEE;FEEE;0648;0648; # (ﻮ; ﻮ; ﻮ; و; و; ) ARABIC LETTER WAW FINAL FORM +FEEF;FEEF;FEEF;0649;0649; # (ﻯ; ﻯ; ﻯ; ى; ى; ) ARABIC LETTER ALEF MAKSURA ISOLATED FORM +FEF0;FEF0;FEF0;0649;0649; # (ﻰ; ﻰ; ﻰ; ى; ى; ) ARABIC LETTER ALEF MAKSURA FINAL FORM +FEF1;FEF1;FEF1;064A;064A; # (ﻱ; ﻱ; ﻱ; ي; ي; ) ARABIC LETTER YEH ISOLATED FORM +FEF2;FEF2;FEF2;064A;064A; # (ﻲ; ﻲ; ﻲ; ي; ي; ) ARABIC LETTER YEH FINAL FORM +FEF3;FEF3;FEF3;064A;064A; # (ﻳ; ﻳ; ﻳ; ي; ي; ) ARABIC LETTER YEH INITIAL FORM +FEF4;FEF4;FEF4;064A;064A; # (ﻴ; ﻴ; ﻴ; ي; ي; ) ARABIC LETTER YEH MEDIAL FORM +FEF5;FEF5;FEF5;0644 0622;0644 0627 0653; # (ﻵ; ﻵ; ﻵ; لآ; لا◌ٓ; ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM +FEF6;FEF6;FEF6;0644 0622;0644 0627 0653; # (ﻶ; ﻶ; ﻶ; لآ; لا◌ٓ; ) ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +FEF7;FEF7;FEF7;0644 0623;0644 0627 0654; # (ﻷ; ﻷ; ﻷ; لأ; لا◌ٔ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM +FEF8;FEF8;FEF8;0644 0623;0644 0627 0654; # (ﻸ; ﻸ; ﻸ; لأ; لا◌ٔ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +FEF9;FEF9;FEF9;0644 0625;0644 0627 0655; # (ﻹ; ﻹ; ﻹ; لإ; لا◌ٕ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM +FEFA;FEFA;FEFA;0644 0625;0644 0627 0655; # (ﻺ; ﻺ; ﻺ; لإ; لا◌ٕ; ) ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +FEFB;FEFB;FEFB;0644 0627;0644 0627; # (ﻻ; ﻻ; ﻻ; لا; لا; ) ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM +FEFC;FEFC;FEFC;0644 0627;0644 0627; # (ﻼ; ﻼ; ﻼ; لا; لا; ) ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FF01;FF01;FF01;0021;0021; # (!; !; !; !; !; ) FULLWIDTH EXCLAMATION MARK +FF02;FF02;FF02;0022;0022; # ("; "; "; "; "; ) FULLWIDTH QUOTATION MARK +FF03;FF03;FF03;0023;0023; # (#; #; #; #; #; ) FULLWIDTH NUMBER SIGN +FF04;FF04;FF04;0024;0024; # ($; $; $; $; $; ) FULLWIDTH DOLLAR SIGN +FF05;FF05;FF05;0025;0025; # (%; %; %; %; %; ) FULLWIDTH PERCENT SIGN +FF06;FF06;FF06;0026;0026; # (&; &; &; &; &; ) FULLWIDTH AMPERSAND +FF07;FF07;FF07;0027;0027; # ('; '; '; '; '; ) FULLWIDTH APOSTROPHE +FF08;FF08;FF08;0028;0028; # ((; (; (; (; (; ) FULLWIDTH LEFT PARENTHESIS +FF09;FF09;FF09;0029;0029; # (); ); ); ); ); ) FULLWIDTH RIGHT PARENTHESIS +FF0A;FF0A;FF0A;002A;002A; # (*; *; *; *; *; ) FULLWIDTH ASTERISK +FF0B;FF0B;FF0B;002B;002B; # (+; +; +; +; +; ) FULLWIDTH PLUS SIGN +FF0C;FF0C;FF0C;002C;002C; # (,; ,; ,; ,; ,; ) FULLWIDTH COMMA +FF0D;FF0D;FF0D;002D;002D; # (-; -; -; -; -; ) FULLWIDTH HYPHEN-MINUS +FF0E;FF0E;FF0E;002E;002E; # (.; .; .; .; .; ) FULLWIDTH FULL STOP +FF0F;FF0F;FF0F;002F;002F; # (/; /; /; /; /; ) FULLWIDTH SOLIDUS +FF10;FF10;FF10;0030;0030; # (0; 0; 0; 0; 0; ) FULLWIDTH DIGIT ZERO +FF11;FF11;FF11;0031;0031; # (1; 1; 1; 1; 1; ) FULLWIDTH DIGIT ONE +FF12;FF12;FF12;0032;0032; # (2; 2; 2; 2; 2; ) FULLWIDTH DIGIT TWO +FF13;FF13;FF13;0033;0033; # (3; 3; 3; 3; 3; ) FULLWIDTH DIGIT THREE +FF14;FF14;FF14;0034;0034; # (4; 4; 4; 4; 4; ) FULLWIDTH DIGIT FOUR +FF15;FF15;FF15;0035;0035; # (5; 5; 5; 5; 5; ) FULLWIDTH DIGIT FIVE +FF16;FF16;FF16;0036;0036; # (6; 6; 6; 6; 6; ) FULLWIDTH DIGIT SIX +FF17;FF17;FF17;0037;0037; # (7; 7; 7; 7; 7; ) FULLWIDTH DIGIT SEVEN +FF18;FF18;FF18;0038;0038; # (8; 8; 8; 8; 8; ) FULLWIDTH DIGIT EIGHT +FF19;FF19;FF19;0039;0039; # (9; 9; 9; 9; 9; ) FULLWIDTH DIGIT NINE +FF1A;FF1A;FF1A;003A;003A; # (:; :; :; :; :; ) FULLWIDTH COLON +FF1B;FF1B;FF1B;003B;003B; # (;; ;; ;; ;; ;; ) FULLWIDTH SEMICOLON +FF1C;FF1C;FF1C;003C;003C; # (<; <; <; <; <; ) FULLWIDTH LESS-THAN SIGN +FF1D;FF1D;FF1D;003D;003D; # (=; =; =; =; =; ) FULLWIDTH EQUALS SIGN +FF1E;FF1E;FF1E;003E;003E; # (>; >; >; >; >; ) FULLWIDTH GREATER-THAN SIGN +FF1F;FF1F;FF1F;003F;003F; # (?; ?; ?; ?; ?; ) FULLWIDTH QUESTION MARK +FF20;FF20;FF20;0040;0040; # (@; @; @; @; @; ) FULLWIDTH COMMERCIAL AT +FF21;FF21;FF21;0041;0041; # (A; A; A; A; A; ) FULLWIDTH LATIN CAPITAL LETTER A +FF22;FF22;FF22;0042;0042; # (B; B; B; B; B; ) FULLWIDTH LATIN CAPITAL LETTER B +FF23;FF23;FF23;0043;0043; # (C; C; C; C; C; ) FULLWIDTH LATIN CAPITAL LETTER C +FF24;FF24;FF24;0044;0044; # (D; D; D; D; D; ) FULLWIDTH LATIN CAPITAL LETTER D +FF25;FF25;FF25;0045;0045; # (E; E; E; E; E; ) FULLWIDTH LATIN CAPITAL LETTER E +FF26;FF26;FF26;0046;0046; # (F; F; F; F; F; ) FULLWIDTH LATIN CAPITAL LETTER F +FF27;FF27;FF27;0047;0047; # (G; G; G; G; G; ) FULLWIDTH LATIN CAPITAL LETTER G +FF28;FF28;FF28;0048;0048; # (H; H; H; H; H; ) FULLWIDTH LATIN CAPITAL LETTER H +FF29;FF29;FF29;0049;0049; # (I; I; I; I; I; ) FULLWIDTH LATIN CAPITAL LETTER I +FF2A;FF2A;FF2A;004A;004A; # (J; J; J; J; J; ) FULLWIDTH LATIN CAPITAL LETTER J +FF2B;FF2B;FF2B;004B;004B; # (K; K; K; K; K; ) FULLWIDTH LATIN CAPITAL LETTER K +FF2C;FF2C;FF2C;004C;004C; # (L; L; L; L; L; ) FULLWIDTH LATIN CAPITAL LETTER L +FF2D;FF2D;FF2D;004D;004D; # (M; M; M; M; M; ) FULLWIDTH LATIN CAPITAL LETTER M +FF2E;FF2E;FF2E;004E;004E; # (N; N; N; N; N; ) FULLWIDTH LATIN CAPITAL LETTER N +FF2F;FF2F;FF2F;004F;004F; # (O; O; O; O; O; ) FULLWIDTH LATIN CAPITAL LETTER O +FF30;FF30;FF30;0050;0050; # (P; P; P; P; P; ) FULLWIDTH LATIN CAPITAL LETTER P +FF31;FF31;FF31;0051;0051; # (Q; Q; Q; Q; Q; ) FULLWIDTH LATIN CAPITAL LETTER Q +FF32;FF32;FF32;0052;0052; # (R; R; R; R; R; ) FULLWIDTH LATIN CAPITAL LETTER R +FF33;FF33;FF33;0053;0053; # (S; S; S; S; S; ) FULLWIDTH LATIN CAPITAL LETTER S +FF34;FF34;FF34;0054;0054; # (T; T; T; T; T; ) FULLWIDTH LATIN CAPITAL LETTER T +FF35;FF35;FF35;0055;0055; # (U; U; U; U; U; ) FULLWIDTH LATIN CAPITAL LETTER U +FF36;FF36;FF36;0056;0056; # (V; V; V; V; V; ) FULLWIDTH LATIN CAPITAL LETTER V +FF37;FF37;FF37;0057;0057; # (W; W; W; W; W; ) FULLWIDTH LATIN CAPITAL LETTER W +FF38;FF38;FF38;0058;0058; # (X; X; X; X; X; ) FULLWIDTH LATIN CAPITAL LETTER X +FF39;FF39;FF39;0059;0059; # (Y; Y; Y; Y; Y; ) FULLWIDTH LATIN CAPITAL LETTER Y +FF3A;FF3A;FF3A;005A;005A; # (Z; Z; Z; Z; Z; ) FULLWIDTH LATIN CAPITAL LETTER Z +FF3B;FF3B;FF3B;005B;005B; # ([; [; [; [; [; ) FULLWIDTH LEFT SQUARE BRACKET +FF3C;FF3C;FF3C;005C;005C; # (\; \; \; \; \; ) FULLWIDTH REVERSE SOLIDUS +FF3D;FF3D;FF3D;005D;005D; # (]; ]; ]; ]; ]; ) FULLWIDTH RIGHT SQUARE BRACKET +FF3E;FF3E;FF3E;005E;005E; # (^; ^; ^; ^; ^; ) FULLWIDTH CIRCUMFLEX ACCENT +FF3F;FF3F;FF3F;005F;005F; # (_; _; _; _; _; ) FULLWIDTH LOW LINE +FF40;FF40;FF40;0060;0060; # (`; `; `; `; `; ) FULLWIDTH GRAVE ACCENT +FF41;FF41;FF41;0061;0061; # (a; a; a; a; a; ) FULLWIDTH LATIN SMALL LETTER A +FF42;FF42;FF42;0062;0062; # (b; b; b; b; b; ) FULLWIDTH LATIN SMALL LETTER B +FF43;FF43;FF43;0063;0063; # (c; c; c; c; c; ) FULLWIDTH LATIN SMALL LETTER C +FF44;FF44;FF44;0064;0064; # (d; d; d; d; d; ) FULLWIDTH LATIN SMALL LETTER D +FF45;FF45;FF45;0065;0065; # (e; e; e; e; e; ) FULLWIDTH LATIN SMALL LETTER E +FF46;FF46;FF46;0066;0066; # (f; f; f; f; f; ) FULLWIDTH LATIN SMALL LETTER F +FF47;FF47;FF47;0067;0067; # (g; g; g; g; g; ) FULLWIDTH LATIN SMALL LETTER G +FF48;FF48;FF48;0068;0068; # (h; h; h; h; h; ) FULLWIDTH LATIN SMALL LETTER H +FF49;FF49;FF49;0069;0069; # (i; i; i; i; i; ) FULLWIDTH LATIN SMALL LETTER I +FF4A;FF4A;FF4A;006A;006A; # (j; j; j; j; j; ) FULLWIDTH LATIN SMALL LETTER J +FF4B;FF4B;FF4B;006B;006B; # (k; k; k; k; k; ) FULLWIDTH LATIN SMALL LETTER K +FF4C;FF4C;FF4C;006C;006C; # (l; l; l; l; l; ) FULLWIDTH LATIN SMALL LETTER L +FF4D;FF4D;FF4D;006D;006D; # (m; m; m; m; m; ) FULLWIDTH LATIN SMALL LETTER M +FF4E;FF4E;FF4E;006E;006E; # (n; n; n; n; n; ) FULLWIDTH LATIN SMALL LETTER N +FF4F;FF4F;FF4F;006F;006F; # (o; o; o; o; o; ) FULLWIDTH LATIN SMALL LETTER O +FF50;FF50;FF50;0070;0070; # (p; p; p; p; p; ) FULLWIDTH LATIN SMALL LETTER P +FF51;FF51;FF51;0071;0071; # (q; q; q; q; q; ) FULLWIDTH LATIN SMALL LETTER Q +FF52;FF52;FF52;0072;0072; # (r; r; r; r; r; ) FULLWIDTH LATIN SMALL LETTER R +FF53;FF53;FF53;0073;0073; # (s; s; s; s; s; ) FULLWIDTH LATIN SMALL LETTER S +FF54;FF54;FF54;0074;0074; # (t; t; t; t; t; ) FULLWIDTH LATIN SMALL LETTER T +FF55;FF55;FF55;0075;0075; # (u; u; u; u; u; ) FULLWIDTH LATIN SMALL LETTER U +FF56;FF56;FF56;0076;0076; # (v; v; v; v; v; ) FULLWIDTH LATIN SMALL LETTER V +FF57;FF57;FF57;0077;0077; # (w; w; w; w; w; ) FULLWIDTH LATIN SMALL LETTER W +FF58;FF58;FF58;0078;0078; # (x; x; x; x; x; ) FULLWIDTH LATIN SMALL LETTER X +FF59;FF59;FF59;0079;0079; # (y; y; y; y; y; ) FULLWIDTH LATIN SMALL LETTER Y +FF5A;FF5A;FF5A;007A;007A; # (z; z; z; z; z; ) FULLWIDTH LATIN SMALL LETTER Z +FF5B;FF5B;FF5B;007B;007B; # ({; {; {; {; {; ) FULLWIDTH LEFT CURLY BRACKET +FF5C;FF5C;FF5C;007C;007C; # (|; |; |; |; |; ) FULLWIDTH VERTICAL LINE +FF5D;FF5D;FF5D;007D;007D; # (}; }; }; }; }; ) FULLWIDTH RIGHT CURLY BRACKET +FF5E;FF5E;FF5E;007E;007E; # (~; ~; ~; ~; ~; ) FULLWIDTH TILDE +FF5F;FF5F;FF5F;2985;2985; # (⦅; ⦅; ⦅; ⦅; ⦅; ) FULLWIDTH LEFT WHITE PARENTHESIS +FF60;FF60;FF60;2986;2986; # (⦆; ⦆; ⦆; ⦆; ⦆; ) FULLWIDTH RIGHT WHITE PARENTHESIS +FF61;FF61;FF61;3002;3002; # (。; 。; 。; 。; 。; ) HALFWIDTH IDEOGRAPHIC FULL STOP +FF62;FF62;FF62;300C;300C; # (「; 「; 「; 「; 「; ) HALFWIDTH LEFT CORNER BRACKET +FF63;FF63;FF63;300D;300D; # (」; 」; 」; 」; 」; ) HALFWIDTH RIGHT CORNER BRACKET +FF64;FF64;FF64;3001;3001; # (、; 、; 、; 、; 、; ) HALFWIDTH IDEOGRAPHIC COMMA +FF65;FF65;FF65;30FB;30FB; # (・; ・; ・; ・; ・; ) HALFWIDTH KATAKANA MIDDLE DOT +FF66;FF66;FF66;30F2;30F2; # (ヲ; ヲ; ヲ; ヲ; ヲ; ) HALFWIDTH KATAKANA LETTER WO +FF67;FF67;FF67;30A1;30A1; # (ァ; ァ; ァ; ァ; ァ; ) HALFWIDTH KATAKANA LETTER SMALL A +FF68;FF68;FF68;30A3;30A3; # (ィ; ィ; ィ; ィ; ィ; ) HALFWIDTH KATAKANA LETTER SMALL I +FF69;FF69;FF69;30A5;30A5; # (ゥ; ゥ; ゥ; ゥ; ゥ; ) HALFWIDTH KATAKANA LETTER SMALL U +FF6A;FF6A;FF6A;30A7;30A7; # (ェ; ェ; ェ; ェ; ェ; ) HALFWIDTH KATAKANA LETTER SMALL E +FF6B;FF6B;FF6B;30A9;30A9; # (ォ; ォ; ォ; ォ; ォ; ) HALFWIDTH KATAKANA LETTER SMALL O +FF6C;FF6C;FF6C;30E3;30E3; # (ャ; ャ; ャ; ャ; ャ; ) HALFWIDTH KATAKANA LETTER SMALL YA +FF6D;FF6D;FF6D;30E5;30E5; # (ュ; ュ; ュ; ュ; ュ; ) HALFWIDTH KATAKANA LETTER SMALL YU +FF6E;FF6E;FF6E;30E7;30E7; # (ョ; ョ; ョ; ョ; ョ; ) HALFWIDTH KATAKANA LETTER SMALL YO +FF6F;FF6F;FF6F;30C3;30C3; # (ッ; ッ; ッ; ッ; ッ; ) HALFWIDTH KATAKANA LETTER SMALL TU +FF70;FF70;FF70;30FC;30FC; # (ー; ー; ー; ー; ー; ) HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71;FF71;FF71;30A2;30A2; # (ア; ア; ア; ア; ア; ) HALFWIDTH KATAKANA LETTER A +FF72;FF72;FF72;30A4;30A4; # (イ; イ; イ; イ; イ; ) HALFWIDTH KATAKANA LETTER I +FF73;FF73;FF73;30A6;30A6; # (ウ; ウ; ウ; ウ; ウ; ) HALFWIDTH KATAKANA LETTER U +FF74;FF74;FF74;30A8;30A8; # (エ; エ; エ; エ; エ; ) HALFWIDTH KATAKANA LETTER E +FF75;FF75;FF75;30AA;30AA; # (オ; オ; オ; オ; オ; ) HALFWIDTH KATAKANA LETTER O +FF76;FF76;FF76;30AB;30AB; # (カ; カ; カ; カ; カ; ) HALFWIDTH KATAKANA LETTER KA +FF77;FF77;FF77;30AD;30AD; # (キ; キ; キ; キ; キ; ) HALFWIDTH KATAKANA LETTER KI +FF78;FF78;FF78;30AF;30AF; # (ク; ク; ク; ク; ク; ) HALFWIDTH KATAKANA LETTER KU +FF79;FF79;FF79;30B1;30B1; # (ケ; ケ; ケ; ケ; ケ; ) HALFWIDTH KATAKANA LETTER KE +FF7A;FF7A;FF7A;30B3;30B3; # (コ; コ; コ; コ; コ; ) HALFWIDTH KATAKANA LETTER KO +FF7B;FF7B;FF7B;30B5;30B5; # (サ; サ; サ; サ; サ; ) HALFWIDTH KATAKANA LETTER SA +FF7C;FF7C;FF7C;30B7;30B7; # (シ; シ; シ; シ; シ; ) HALFWIDTH KATAKANA LETTER SI +FF7D;FF7D;FF7D;30B9;30B9; # (ス; ス; ス; ス; ス; ) HALFWIDTH KATAKANA LETTER SU +FF7E;FF7E;FF7E;30BB;30BB; # (セ; セ; セ; セ; セ; ) HALFWIDTH KATAKANA LETTER SE +FF7F;FF7F;FF7F;30BD;30BD; # (ソ; ソ; ソ; ソ; ソ; ) HALFWIDTH KATAKANA LETTER SO +FF80;FF80;FF80;30BF;30BF; # (タ; タ; タ; タ; タ; ) HALFWIDTH KATAKANA LETTER TA +FF81;FF81;FF81;30C1;30C1; # (チ; チ; チ; チ; チ; ) HALFWIDTH KATAKANA LETTER TI +FF82;FF82;FF82;30C4;30C4; # (ツ; ツ; ツ; ツ; ツ; ) HALFWIDTH KATAKANA LETTER TU +FF83;FF83;FF83;30C6;30C6; # (テ; テ; テ; テ; テ; ) HALFWIDTH KATAKANA LETTER TE +FF84;FF84;FF84;30C8;30C8; # (ト; ト; ト; ト; ト; ) HALFWIDTH KATAKANA LETTER TO +FF85;FF85;FF85;30CA;30CA; # (ナ; ナ; ナ; ナ; ナ; ) HALFWIDTH KATAKANA LETTER NA +FF86;FF86;FF86;30CB;30CB; # (ニ; ニ; ニ; ニ; ニ; ) HALFWIDTH KATAKANA LETTER NI +FF87;FF87;FF87;30CC;30CC; # (ヌ; ヌ; ヌ; ヌ; ヌ; ) HALFWIDTH KATAKANA LETTER NU +FF88;FF88;FF88;30CD;30CD; # (ネ; ネ; ネ; ネ; ネ; ) HALFWIDTH KATAKANA LETTER NE +FF89;FF89;FF89;30CE;30CE; # (ノ; ノ; ノ; ノ; ノ; ) HALFWIDTH KATAKANA LETTER NO +FF8A;FF8A;FF8A;30CF;30CF; # (ハ; ハ; ハ; ハ; ハ; ) HALFWIDTH KATAKANA LETTER HA +FF8B;FF8B;FF8B;30D2;30D2; # (ヒ; ヒ; ヒ; ヒ; ヒ; ) HALFWIDTH KATAKANA LETTER HI +FF8C;FF8C;FF8C;30D5;30D5; # (フ; フ; フ; フ; フ; ) HALFWIDTH KATAKANA LETTER HU +FF8D;FF8D;FF8D;30D8;30D8; # (ヘ; ヘ; ヘ; ヘ; ヘ; ) HALFWIDTH KATAKANA LETTER HE +FF8E;FF8E;FF8E;30DB;30DB; # (ホ; ホ; ホ; ホ; ホ; ) HALFWIDTH KATAKANA LETTER HO +FF8F;FF8F;FF8F;30DE;30DE; # (マ; マ; マ; マ; マ; ) HALFWIDTH KATAKANA LETTER MA +FF90;FF90;FF90;30DF;30DF; # (ミ; ミ; ミ; ミ; ミ; ) HALFWIDTH KATAKANA LETTER MI +FF91;FF91;FF91;30E0;30E0; # (ム; ム; ム; ム; ム; ) HALFWIDTH KATAKANA LETTER MU +FF92;FF92;FF92;30E1;30E1; # (メ; メ; メ; メ; メ; ) HALFWIDTH KATAKANA LETTER ME +FF93;FF93;FF93;30E2;30E2; # (モ; モ; モ; モ; モ; ) HALFWIDTH KATAKANA LETTER MO +FF94;FF94;FF94;30E4;30E4; # (ヤ; ヤ; ヤ; ヤ; ヤ; ) HALFWIDTH KATAKANA LETTER YA +FF95;FF95;FF95;30E6;30E6; # (ユ; ユ; ユ; ユ; ユ; ) HALFWIDTH KATAKANA LETTER YU +FF96;FF96;FF96;30E8;30E8; # (ヨ; ヨ; ヨ; ヨ; ヨ; ) HALFWIDTH KATAKANA LETTER YO +FF97;FF97;FF97;30E9;30E9; # (ラ; ラ; ラ; ラ; ラ; ) HALFWIDTH KATAKANA LETTER RA +FF98;FF98;FF98;30EA;30EA; # (リ; リ; リ; リ; リ; ) HALFWIDTH KATAKANA LETTER RI +FF99;FF99;FF99;30EB;30EB; # (ル; ル; ル; ル; ル; ) HALFWIDTH KATAKANA LETTER RU +FF9A;FF9A;FF9A;30EC;30EC; # (レ; レ; レ; レ; レ; ) HALFWIDTH KATAKANA LETTER RE +FF9B;FF9B;FF9B;30ED;30ED; # (ロ; ロ; ロ; ロ; ロ; ) HALFWIDTH KATAKANA LETTER RO +FF9C;FF9C;FF9C;30EF;30EF; # (ワ; ワ; ワ; ワ; ワ; ) HALFWIDTH KATAKANA LETTER WA +FF9D;FF9D;FF9D;30F3;30F3; # (ン; ン; ン; ン; ン; ) HALFWIDTH KATAKANA LETTER N +FF9E;FF9E;FF9E;3099;3099; # (゙; ゙; ゙; ◌゙; ◌゙; ) HALFWIDTH KATAKANA VOICED SOUND MARK +FF9F;FF9F;FF9F;309A;309A; # (゚; ゚; ゚; ◌゚; ◌゚; ) HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFA0;FFA0;FFA0;1160;1160; # (ᅠ; ᅠ; ᅠ; ᅠ; ᅠ; ) HALFWIDTH HANGUL FILLER +FFA1;FFA1;FFA1;1100;1100; # (ᄀ; ᄀ; ᄀ; ᄀ; ᄀ; ) HALFWIDTH HANGUL LETTER KIYEOK +FFA2;FFA2;FFA2;1101;1101; # (ᄁ; ᄁ; ᄁ; ᄁ; ᄁ; ) HALFWIDTH HANGUL LETTER SSANGKIYEOK +FFA3;FFA3;FFA3;11AA;11AA; # (ᆪ; ᆪ; ᆪ; ᆪ; ᆪ; ) HALFWIDTH HANGUL LETTER KIYEOK-SIOS +FFA4;FFA4;FFA4;1102;1102; # (ᄂ; ᄂ; ᄂ; ᄂ; ᄂ; ) HALFWIDTH HANGUL LETTER NIEUN +FFA5;FFA5;FFA5;11AC;11AC; # (ᆬ; ᆬ; ᆬ; ᆬ; ᆬ; ) HALFWIDTH HANGUL LETTER NIEUN-CIEUC +FFA6;FFA6;FFA6;11AD;11AD; # (ᆭ; ᆭ; ᆭ; ᆭ; ᆭ; ) HALFWIDTH HANGUL LETTER NIEUN-HIEUH +FFA7;FFA7;FFA7;1103;1103; # (ᄃ; ᄃ; ᄃ; ᄃ; ᄃ; ) HALFWIDTH HANGUL LETTER TIKEUT +FFA8;FFA8;FFA8;1104;1104; # (ᄄ; ᄄ; ᄄ; ᄄ; ᄄ; ) HALFWIDTH HANGUL LETTER SSANGTIKEUT +FFA9;FFA9;FFA9;1105;1105; # (ᄅ; ᄅ; ᄅ; ᄅ; ᄅ; ) HALFWIDTH HANGUL LETTER RIEUL +FFAA;FFAA;FFAA;11B0;11B0; # (ᆰ; ᆰ; ᆰ; ᆰ; ᆰ; ) HALFWIDTH HANGUL LETTER RIEUL-KIYEOK +FFAB;FFAB;FFAB;11B1;11B1; # (ᆱ; ᆱ; ᆱ; ᆱ; ᆱ; ) HALFWIDTH HANGUL LETTER RIEUL-MIEUM +FFAC;FFAC;FFAC;11B2;11B2; # (ᆲ; ᆲ; ᆲ; ᆲ; ᆲ; ) HALFWIDTH HANGUL LETTER RIEUL-PIEUP +FFAD;FFAD;FFAD;11B3;11B3; # (ᆳ; ᆳ; ᆳ; ᆳ; ᆳ; ) HALFWIDTH HANGUL LETTER RIEUL-SIOS +FFAE;FFAE;FFAE;11B4;11B4; # (ᆴ; ᆴ; ᆴ; ᆴ; ᆴ; ) HALFWIDTH HANGUL LETTER RIEUL-THIEUTH +FFAF;FFAF;FFAF;11B5;11B5; # (ᆵ; ᆵ; ᆵ; ᆵ; ᆵ; ) HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH +FFB0;FFB0;FFB0;111A;111A; # (ᄚ; ᄚ; ᄚ; ᄚ; ᄚ; ) HALFWIDTH HANGUL LETTER RIEUL-HIEUH +FFB1;FFB1;FFB1;1106;1106; # (ᄆ; ᄆ; ᄆ; ᄆ; ᄆ; ) HALFWIDTH HANGUL LETTER MIEUM +FFB2;FFB2;FFB2;1107;1107; # (ᄇ; ᄇ; ᄇ; ᄇ; ᄇ; ) HALFWIDTH HANGUL LETTER PIEUP +FFB3;FFB3;FFB3;1108;1108; # (ᄈ; ᄈ; ᄈ; ᄈ; ᄈ; ) HALFWIDTH HANGUL LETTER SSANGPIEUP +FFB4;FFB4;FFB4;1121;1121; # (ᄡ; ᄡ; ᄡ; ᄡ; ᄡ; ) HALFWIDTH HANGUL LETTER PIEUP-SIOS +FFB5;FFB5;FFB5;1109;1109; # (ᄉ; ᄉ; ᄉ; ᄉ; ᄉ; ) HALFWIDTH HANGUL LETTER SIOS +FFB6;FFB6;FFB6;110A;110A; # (ᄊ; ᄊ; ᄊ; ᄊ; ᄊ; ) HALFWIDTH HANGUL LETTER SSANGSIOS +FFB7;FFB7;FFB7;110B;110B; # (ᄋ; ᄋ; ᄋ; ᄋ; ᄋ; ) HALFWIDTH HANGUL LETTER IEUNG +FFB8;FFB8;FFB8;110C;110C; # (ᄌ; ᄌ; ᄌ; ᄌ; ᄌ; ) HALFWIDTH HANGUL LETTER CIEUC +FFB9;FFB9;FFB9;110D;110D; # (ᄍ; ᄍ; ᄍ; ᄍ; ᄍ; ) HALFWIDTH HANGUL LETTER SSANGCIEUC +FFBA;FFBA;FFBA;110E;110E; # (ᄎ; ᄎ; ᄎ; ᄎ; ᄎ; ) HALFWIDTH HANGUL LETTER CHIEUCH +FFBB;FFBB;FFBB;110F;110F; # (ᄏ; ᄏ; ᄏ; ᄏ; ᄏ; ) HALFWIDTH HANGUL LETTER KHIEUKH +FFBC;FFBC;FFBC;1110;1110; # (ᄐ; ᄐ; ᄐ; ᄐ; ᄐ; ) HALFWIDTH HANGUL LETTER THIEUTH +FFBD;FFBD;FFBD;1111;1111; # (ᄑ; ᄑ; ᄑ; ᄑ; ᄑ; ) HALFWIDTH HANGUL LETTER PHIEUPH +FFBE;FFBE;FFBE;1112;1112; # (ᄒ; ᄒ; ᄒ; ᄒ; ᄒ; ) HALFWIDTH HANGUL LETTER HIEUH +FFC2;FFC2;FFC2;1161;1161; # (ᅡ; ᅡ; ᅡ; ᅡ; ᅡ; ) HALFWIDTH HANGUL LETTER A +FFC3;FFC3;FFC3;1162;1162; # (ᅢ; ᅢ; ᅢ; ᅢ; ᅢ; ) HALFWIDTH HANGUL LETTER AE +FFC4;FFC4;FFC4;1163;1163; # (ᅣ; ᅣ; ᅣ; ᅣ; ᅣ; ) HALFWIDTH HANGUL LETTER YA +FFC5;FFC5;FFC5;1164;1164; # (ᅤ; ᅤ; ᅤ; ᅤ; ᅤ; ) HALFWIDTH HANGUL LETTER YAE +FFC6;FFC6;FFC6;1165;1165; # (ᅥ; ᅥ; ᅥ; ᅥ; ᅥ; ) HALFWIDTH HANGUL LETTER EO +FFC7;FFC7;FFC7;1166;1166; # (ᅦ; ᅦ; ᅦ; ᅦ; ᅦ; ) HALFWIDTH HANGUL LETTER E +FFCA;FFCA;FFCA;1167;1167; # (ᅧ; ᅧ; ᅧ; ᅧ; ᅧ; ) HALFWIDTH HANGUL LETTER YEO +FFCB;FFCB;FFCB;1168;1168; # (ᅨ; ᅨ; ᅨ; ᅨ; ᅨ; ) HALFWIDTH HANGUL LETTER YE +FFCC;FFCC;FFCC;1169;1169; # (ᅩ; ᅩ; ᅩ; ᅩ; ᅩ; ) HALFWIDTH HANGUL LETTER O +FFCD;FFCD;FFCD;116A;116A; # (ᅪ; ᅪ; ᅪ; ᅪ; ᅪ; ) HALFWIDTH HANGUL LETTER WA +FFCE;FFCE;FFCE;116B;116B; # (ᅫ; ᅫ; ᅫ; ᅫ; ᅫ; ) HALFWIDTH HANGUL LETTER WAE +FFCF;FFCF;FFCF;116C;116C; # (ᅬ; ᅬ; ᅬ; ᅬ; ᅬ; ) HALFWIDTH HANGUL LETTER OE +FFD2;FFD2;FFD2;116D;116D; # (ᅭ; ᅭ; ᅭ; ᅭ; ᅭ; ) HALFWIDTH HANGUL LETTER YO +FFD3;FFD3;FFD3;116E;116E; # (ᅮ; ᅮ; ᅮ; ᅮ; ᅮ; ) HALFWIDTH HANGUL LETTER U +FFD4;FFD4;FFD4;116F;116F; # (ᅯ; ᅯ; ᅯ; ᅯ; ᅯ; ) HALFWIDTH HANGUL LETTER WEO +FFD5;FFD5;FFD5;1170;1170; # (ᅰ; ᅰ; ᅰ; ᅰ; ᅰ; ) HALFWIDTH HANGUL LETTER WE +FFD6;FFD6;FFD6;1171;1171; # (ᅱ; ᅱ; ᅱ; ᅱ; ᅱ; ) HALFWIDTH HANGUL LETTER WI +FFD7;FFD7;FFD7;1172;1172; # (ᅲ; ᅲ; ᅲ; ᅲ; ᅲ; ) HALFWIDTH HANGUL LETTER YU +FFDA;FFDA;FFDA;1173;1173; # (ᅳ; ᅳ; ᅳ; ᅳ; ᅳ; ) HALFWIDTH HANGUL LETTER EU +FFDB;FFDB;FFDB;1174;1174; # (ᅴ; ᅴ; ᅴ; ᅴ; ᅴ; ) HALFWIDTH HANGUL LETTER YI +FFDC;FFDC;FFDC;1175;1175; # (ᅵ; ᅵ; ᅵ; ᅵ; ᅵ; ) HALFWIDTH HANGUL LETTER I +FFE0;FFE0;FFE0;00A2;00A2; # (¢; ¢; ¢; ¢; ¢; ) FULLWIDTH CENT SIGN +FFE1;FFE1;FFE1;00A3;00A3; # (£; £; £; £; £; ) FULLWIDTH POUND SIGN +FFE2;FFE2;FFE2;00AC;00AC; # (¬; ¬; ¬; ¬; ¬; ) FULLWIDTH NOT SIGN +FFE3;FFE3;FFE3;0020 0304;0020 0304; # ( ̄;  ̄;  ̄; ◌̄; ◌̄; ) FULLWIDTH MACRON +FFE4;FFE4;FFE4;00A6;00A6; # (¦; ¦; ¦; ¦; ¦; ) FULLWIDTH BROKEN BAR +FFE5;FFE5;FFE5;00A5;00A5; # (¥; ¥; ¥; ¥; ¥; ) FULLWIDTH YEN SIGN +FFE6;FFE6;FFE6;20A9;20A9; # (₩; ₩; ₩; ₩; ₩; ) FULLWIDTH WON SIGN +FFE8;FFE8;FFE8;2502;2502; # (│; │; │; │; │; ) HALFWIDTH FORMS LIGHT VERTICAL +FFE9;FFE9;FFE9;2190;2190; # (←; ←; ←; ←; ←; ) HALFWIDTH LEFTWARDS ARROW +FFEA;FFEA;FFEA;2191;2191; # (↑; ↑; ↑; ↑; ↑; ) HALFWIDTH UPWARDS ARROW +FFEB;FFEB;FFEB;2192;2192; # (→; →; →; →; →; ) HALFWIDTH RIGHTWARDS ARROW +FFEC;FFEC;FFEC;2193;2193; # (↓; ↓; ↓; ↓; ↓; ) HALFWIDTH DOWNWARDS ARROW +FFED;FFED;FFED;25A0;25A0; # (■; ■; ■; ■; ■; ) HALFWIDTH BLACK SQUARE +FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE +10781;10781;10781;02D0;02D0; # (𐞁; 𐞁; 𐞁; ː; ː; ) MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON +10782;10782;10782;02D1;02D1; # (𐞂; 𐞂; 𐞂; ˑ; ˑ; ) MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON +10783;10783;10783;00E6;00E6; # (𐞃; 𐞃; 𐞃; æ; æ; ) MODIFIER LETTER SMALL AE +10784;10784;10784;0299;0299; # (𐞄; 𐞄; 𐞄; ʙ; ʙ; ) MODIFIER LETTER SMALL CAPITAL B +10785;10785;10785;0253;0253; # (𐞅; 𐞅; 𐞅; ɓ; ɓ; ) MODIFIER LETTER SMALL B WITH HOOK +10787;10787;10787;02A3;02A3; # (𐞇; 𐞇; 𐞇; ʣ; ʣ; ) MODIFIER LETTER SMALL DZ DIGRAPH +10788;10788;10788;AB66;AB66; # (𐞈; 𐞈; 𐞈; ꭦ; ꭦ; ) MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK +10789;10789;10789;02A5;02A5; # (𐞉; 𐞉; 𐞉; ʥ; ʥ; ) MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL +1078A;1078A;1078A;02A4;02A4; # (𐞊; 𐞊; 𐞊; ʤ; ʤ; ) MODIFIER LETTER SMALL DEZH DIGRAPH +1078B;1078B;1078B;0256;0256; # (𐞋; 𐞋; 𐞋; ɖ; ɖ; ) MODIFIER LETTER SMALL D WITH TAIL +1078C;1078C;1078C;0257;0257; # (𐞌; 𐞌; 𐞌; ɗ; ɗ; ) MODIFIER LETTER SMALL D WITH HOOK +1078D;1078D;1078D;1D91;1D91; # (𐞍; 𐞍; 𐞍; ᶑ; ᶑ; ) MODIFIER LETTER SMALL D WITH HOOK AND TAIL +1078E;1078E;1078E;0258;0258; # (𐞎; 𐞎; 𐞎; ɘ; ɘ; ) MODIFIER LETTER SMALL REVERSED E +1078F;1078F;1078F;025E;025E; # (𐞏; 𐞏; 𐞏; ɞ; ɞ; ) MODIFIER LETTER SMALL CLOSED REVERSED OPEN E +10790;10790;10790;02A9;02A9; # (𐞐; 𐞐; 𐞐; ʩ; ʩ; ) MODIFIER LETTER SMALL FENG DIGRAPH +10791;10791;10791;0264;0264; # (𐞑; 𐞑; 𐞑; ɤ; ɤ; ) MODIFIER LETTER SMALL RAMS HORN +10792;10792;10792;0262;0262; # (𐞒; 𐞒; 𐞒; ɢ; ɢ; ) MODIFIER LETTER SMALL CAPITAL G +10793;10793;10793;0260;0260; # (𐞓; 𐞓; 𐞓; ɠ; ɠ; ) MODIFIER LETTER SMALL G WITH HOOK +10794;10794;10794;029B;029B; # (𐞔; 𐞔; 𐞔; ʛ; ʛ; ) MODIFIER LETTER SMALL CAPITAL G WITH HOOK +10795;10795;10795;0127;0127; # (𐞕; 𐞕; 𐞕; ħ; ħ; ) MODIFIER LETTER SMALL H WITH STROKE +10796;10796;10796;029C;029C; # (𐞖; 𐞖; 𐞖; ʜ; ʜ; ) MODIFIER LETTER SMALL CAPITAL H +10797;10797;10797;0267;0267; # (𐞗; 𐞗; 𐞗; ɧ; ɧ; ) MODIFIER LETTER SMALL HENG WITH HOOK +10798;10798;10798;0284;0284; # (𐞘; 𐞘; 𐞘; ʄ; ʄ; ) MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK +10799;10799;10799;02AA;02AA; # (𐞙; 𐞙; 𐞙; ʪ; ʪ; ) MODIFIER LETTER SMALL LS DIGRAPH +1079A;1079A;1079A;02AB;02AB; # (𐞚; 𐞚; 𐞚; ʫ; ʫ; ) MODIFIER LETTER SMALL LZ DIGRAPH +1079B;1079B;1079B;026C;026C; # (𐞛; 𐞛; 𐞛; ɬ; ɬ; ) MODIFIER LETTER SMALL L WITH BELT +1079C;1079C;1079C;1DF04;1DF04; # (𐞜; 𐞜; 𐞜; 𝼄; 𝼄; ) MODIFIER LETTER SMALL CAPITAL L WITH BELT +1079D;1079D;1079D;A78E;A78E; # (𐞝; 𐞝; 𐞝; ꞎ; ꞎ; ) MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT +1079E;1079E;1079E;026E;026E; # (𐞞; 𐞞; 𐞞; ɮ; ɮ; ) MODIFIER LETTER SMALL LEZH +1079F;1079F;1079F;1DF05;1DF05; # (𐞟; 𐞟; 𐞟; 𝼅; 𝼅; ) MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK +107A0;107A0;107A0;028E;028E; # (𐞠; 𐞠; 𐞠; ʎ; ʎ; ) MODIFIER LETTER SMALL TURNED Y +107A1;107A1;107A1;1DF06;1DF06; # (𐞡; 𐞡; 𐞡; 𝼆; 𝼆; ) MODIFIER LETTER SMALL TURNED Y WITH BELT +107A2;107A2;107A2;00F8;00F8; # (𐞢; 𐞢; 𐞢; ø; ø; ) MODIFIER LETTER SMALL O WITH STROKE +107A3;107A3;107A3;0276;0276; # (𐞣; 𐞣; 𐞣; ɶ; ɶ; ) MODIFIER LETTER SMALL CAPITAL OE +107A4;107A4;107A4;0277;0277; # (𐞤; 𐞤; 𐞤; ɷ; ɷ; ) MODIFIER LETTER SMALL CLOSED OMEGA +107A5;107A5;107A5;0071;0071; # (𐞥; 𐞥; 𐞥; q; q; ) MODIFIER LETTER SMALL Q +107A6;107A6;107A6;027A;027A; # (𐞦; 𐞦; 𐞦; ɺ; ɺ; ) MODIFIER LETTER SMALL TURNED R WITH LONG LEG +107A7;107A7;107A7;1DF08;1DF08; # (𐞧; 𐞧; 𐞧; 𝼈; 𝼈; ) MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK +107A8;107A8;107A8;027D;027D; # (𐞨; 𐞨; 𐞨; ɽ; ɽ; ) MODIFIER LETTER SMALL R WITH TAIL +107A9;107A9;107A9;027E;027E; # (𐞩; 𐞩; 𐞩; ɾ; ɾ; ) MODIFIER LETTER SMALL R WITH FISHHOOK +107AA;107AA;107AA;0280;0280; # (𐞪; 𐞪; 𐞪; ʀ; ʀ; ) MODIFIER LETTER SMALL CAPITAL R +107AB;107AB;107AB;02A8;02A8; # (𐞫; 𐞫; 𐞫; ʨ; ʨ; ) MODIFIER LETTER SMALL TC DIGRAPH WITH CURL +107AC;107AC;107AC;02A6;02A6; # (𐞬; 𐞬; 𐞬; ʦ; ʦ; ) MODIFIER LETTER SMALL TS DIGRAPH +107AD;107AD;107AD;AB67;AB67; # (𐞭; 𐞭; 𐞭; ꭧ; ꭧ; ) MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK +107AE;107AE;107AE;02A7;02A7; # (𐞮; 𐞮; 𐞮; ʧ; ʧ; ) MODIFIER LETTER SMALL TESH DIGRAPH +107AF;107AF;107AF;0288;0288; # (𐞯; 𐞯; 𐞯; ʈ; ʈ; ) MODIFIER LETTER SMALL T WITH RETROFLEX HOOK +107B0;107B0;107B0;2C71;2C71; # (𐞰; 𐞰; 𐞰; ⱱ; ⱱ; ) MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2;107B2;107B2;028F;028F; # (𐞲; 𐞲; 𐞲; ʏ; ʏ; ) MODIFIER LETTER SMALL CAPITAL Y +107B3;107B3;107B3;02A1;02A1; # (𐞳; 𐞳; 𐞳; ʡ; ʡ; ) MODIFIER LETTER GLOTTAL STOP WITH STROKE +107B4;107B4;107B4;02A2;02A2; # (𐞴; 𐞴; 𐞴; ʢ; ʢ; ) MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE +107B5;107B5;107B5;0298;0298; # (𐞵; 𐞵; 𐞵; ʘ; ʘ; ) MODIFIER LETTER BILABIAL CLICK +107B6;107B6;107B6;01C0;01C0; # (𐞶; 𐞶; 𐞶; ǀ; ǀ; ) MODIFIER LETTER DENTAL CLICK +107B7;107B7;107B7;01C1;01C1; # (𐞷; 𐞷; 𐞷; ǁ; ǁ; ) MODIFIER LETTER LATERAL CLICK +107B8;107B8;107B8;01C2;01C2; # (𐞸; 𐞸; 𐞸; ǂ; ǂ; ) MODIFIER LETTER ALVEOLAR CLICK +107B9;107B9;107B9;1DF0A;1DF0A; # (𐞹; 𐞹; 𐞹; 𝼊; 𝼊; ) MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK +107BA;107BA;107BA;1DF1E;1DF1E; # (𐞺; 𐞺; 𐞺; 𝼞; 𝼞; ) MODIFIER LETTER SMALL S WITH CURL +1109A;1109A;11099 110BA;1109A;11099 110BA; # (𑂚; 𑂚; 𑂙◌𑂺; 𑂚; 𑂙◌𑂺; ) KAITHI LETTER DDDHA +1109C;1109C;1109B 110BA;1109C;1109B 110BA; # (𑂜; 𑂜; 𑂛◌𑂺; 𑂜; 𑂛◌𑂺; ) KAITHI LETTER RHA +110AB;110AB;110A5 110BA;110AB;110A5 110BA; # (𑂫; 𑂫; 𑂥◌𑂺; 𑂫; 𑂥◌𑂺; ) KAITHI LETTER VA +1112E;1112E;11131 11127;1112E;11131 11127; # (◌𑄮; ◌𑄮; ◌𑄱◌𑄧; ◌𑄮; ◌𑄱◌𑄧; ) CHAKMA VOWEL SIGN O +1112F;1112F;11132 11127;1112F;11132 11127; # (◌𑄯; ◌𑄯; ◌𑄲◌𑄧; ◌𑄯; ◌𑄲◌𑄧; ) CHAKMA VOWEL SIGN AU +1134B;1134B;11347 1133E;1134B;11347 1133E; # (𑍋; 𑍋; 𑍋; 𑍋; 𑍋; ) GRANTHA VOWEL SIGN OO +1134C;1134C;11347 11357;1134C;11347 11357; # (𑍌; 𑍌; 𑍌; 𑍌; 𑍌; ) GRANTHA VOWEL SIGN AU +114BB;114BB;114B9 114BA;114BB;114B9 114BA; # (𑒻; 𑒻; 𑒹◌𑒺; 𑒻; 𑒹◌𑒺; ) TIRHUTA VOWEL SIGN AI +114BC;114BC;114B9 114B0;114BC;114B9 114B0; # (𑒼; 𑒼; 𑒼; 𑒼; 𑒼; ) TIRHUTA VOWEL SIGN O +114BE;114BE;114B9 114BD;114BE;114B9 114BD; # (𑒾; 𑒾; 𑒾; 𑒾; 𑒾; ) TIRHUTA VOWEL SIGN AU +115BA;115BA;115B8 115AF;115BA;115B8 115AF; # (𑖺; 𑖺; 𑖺; 𑖺; 𑖺; ) SIDDHAM VOWEL SIGN O +115BB;115BB;115B9 115AF;115BB;115B9 115AF; # (𑖻; 𑖻; 𑖻; 𑖻; 𑖻; ) SIDDHAM VOWEL SIGN AU +11938;11938;11935 11930;11938;11935 11930; # (𑤸; 𑤸; 𑤸; 𑤸; 𑤸; ) DIVES AKURU VOWEL SIGN O +1D15E;1D157 1D165;1D157 1D165;1D157 1D165;1D157 1D165; # (𝅗𝅥; 𝅗𝅥; 𝅗𝅥; 𝅗𝅥; 𝅗𝅥; ) MUSICAL SYMBOL HALF NOTE +1D15F;1D158 1D165;1D158 1D165;1D158 1D165;1D158 1D165; # (𝅘𝅥; 𝅘𝅥; 𝅘𝅥; 𝅘𝅥; 𝅘𝅥; ) MUSICAL SYMBOL QUARTER NOTE +1D160;1D158 1D165 1D16E;1D158 1D165 1D16E;1D158 1D165 1D16E;1D158 1D165 1D16E; # (𝅘𝅥𝅮; 𝅘𝅥𝅮; 𝅘𝅥𝅮; 𝅘𝅥𝅮; 𝅘𝅥𝅮; ) MUSICAL SYMBOL EIGHTH NOTE +1D161;1D158 1D165 1D16F;1D158 1D165 1D16F;1D158 1D165 1D16F;1D158 1D165 1D16F; # (𝅘𝅥𝅯; 𝅘𝅥𝅯; 𝅘𝅥𝅯; 𝅘𝅥𝅯; 𝅘𝅥𝅯; ) MUSICAL SYMBOL SIXTEENTH NOTE +1D162;1D158 1D165 1D170;1D158 1D165 1D170;1D158 1D165 1D170;1D158 1D165 1D170; # (𝅘𝅥𝅰; 𝅘𝅥𝅰; 𝅘𝅥𝅰; 𝅘𝅥𝅰; 𝅘𝅥𝅰; ) MUSICAL SYMBOL THIRTY-SECOND NOTE +1D163;1D158 1D165 1D171;1D158 1D165 1D171;1D158 1D165 1D171;1D158 1D165 1D171; # (𝅘𝅥𝅱; 𝅘𝅥𝅱; 𝅘𝅥𝅱; 𝅘𝅥𝅱; 𝅘𝅥𝅱; ) MUSICAL SYMBOL SIXTY-FOURTH NOTE +1D164;1D158 1D165 1D172;1D158 1D165 1D172;1D158 1D165 1D172;1D158 1D165 1D172; # (𝅘𝅥𝅲; 𝅘𝅥𝅲; 𝅘𝅥𝅲; 𝅘𝅥𝅲; 𝅘𝅥𝅲; ) MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D1BB;1D1B9 1D165;1D1B9 1D165;1D1B9 1D165;1D1B9 1D165; # (𝆹𝅥; 𝆹𝅥; 𝆹𝅥; 𝆹𝅥; 𝆹𝅥; ) MUSICAL SYMBOL MINIMA +1D1BC;1D1BA 1D165;1D1BA 1D165;1D1BA 1D165;1D1BA 1D165; # (𝆺𝅥; 𝆺𝅥; 𝆺𝅥; 𝆺𝅥; 𝆺𝅥; ) MUSICAL SYMBOL MINIMA BLACK +1D1BD;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E;1D1B9 1D165 1D16E; # (𝆹𝅥𝅮; 𝆹𝅥𝅮; 𝆹𝅥𝅮; 𝆹𝅥𝅮; 𝆹𝅥𝅮; ) MUSICAL SYMBOL SEMIMINIMA WHITE +1D1BE;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E;1D1BA 1D165 1D16E; # (𝆺𝅥𝅮; 𝆺𝅥𝅮; 𝆺𝅥𝅮; 𝆺𝅥𝅮; 𝆺𝅥𝅮; ) MUSICAL SYMBOL SEMIMINIMA BLACK +1D1BF;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F;1D1B9 1D165 1D16F; # (𝆹𝅥𝅯; 𝆹𝅥𝅯; 𝆹𝅥𝅯; 𝆹𝅥𝅯; 𝆹𝅥𝅯; ) MUSICAL SYMBOL FUSA WHITE +1D1C0;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F;1D1BA 1D165 1D16F; # (𝆺𝅥𝅯; 𝆺𝅥𝅯; 𝆺𝅥𝅯; 𝆺𝅥𝅯; 𝆺𝅥𝅯; ) MUSICAL SYMBOL FUSA BLACK +1D400;1D400;1D400;0041;0041; # (𝐀; 𝐀; 𝐀; A; A; ) MATHEMATICAL BOLD CAPITAL A +1D401;1D401;1D401;0042;0042; # (𝐁; 𝐁; 𝐁; B; B; ) MATHEMATICAL BOLD CAPITAL B +1D402;1D402;1D402;0043;0043; # (𝐂; 𝐂; 𝐂; C; C; ) MATHEMATICAL BOLD CAPITAL C +1D403;1D403;1D403;0044;0044; # (𝐃; 𝐃; 𝐃; D; D; ) MATHEMATICAL BOLD CAPITAL D +1D404;1D404;1D404;0045;0045; # (𝐄; 𝐄; 𝐄; E; E; ) MATHEMATICAL BOLD CAPITAL E +1D405;1D405;1D405;0046;0046; # (𝐅; 𝐅; 𝐅; F; F; ) MATHEMATICAL BOLD CAPITAL F +1D406;1D406;1D406;0047;0047; # (𝐆; 𝐆; 𝐆; G; G; ) MATHEMATICAL BOLD CAPITAL G +1D407;1D407;1D407;0048;0048; # (𝐇; 𝐇; 𝐇; H; H; ) MATHEMATICAL BOLD CAPITAL H +1D408;1D408;1D408;0049;0049; # (𝐈; 𝐈; 𝐈; I; I; ) MATHEMATICAL BOLD CAPITAL I +1D409;1D409;1D409;004A;004A; # (𝐉; 𝐉; 𝐉; J; J; ) MATHEMATICAL BOLD CAPITAL J +1D40A;1D40A;1D40A;004B;004B; # (𝐊; 𝐊; 𝐊; K; K; ) MATHEMATICAL BOLD CAPITAL K +1D40B;1D40B;1D40B;004C;004C; # (𝐋; 𝐋; 𝐋; L; L; ) MATHEMATICAL BOLD CAPITAL L +1D40C;1D40C;1D40C;004D;004D; # (𝐌; 𝐌; 𝐌; M; M; ) MATHEMATICAL BOLD CAPITAL M +1D40D;1D40D;1D40D;004E;004E; # (𝐍; 𝐍; 𝐍; N; N; ) MATHEMATICAL BOLD CAPITAL N +1D40E;1D40E;1D40E;004F;004F; # (𝐎; 𝐎; 𝐎; O; O; ) MATHEMATICAL BOLD CAPITAL O +1D40F;1D40F;1D40F;0050;0050; # (𝐏; 𝐏; 𝐏; P; P; ) MATHEMATICAL BOLD CAPITAL P +1D410;1D410;1D410;0051;0051; # (𝐐; 𝐐; 𝐐; Q; Q; ) MATHEMATICAL BOLD CAPITAL Q +1D411;1D411;1D411;0052;0052; # (𝐑; 𝐑; 𝐑; R; R; ) MATHEMATICAL BOLD CAPITAL R +1D412;1D412;1D412;0053;0053; # (𝐒; 𝐒; 𝐒; S; S; ) MATHEMATICAL BOLD CAPITAL S +1D413;1D413;1D413;0054;0054; # (𝐓; 𝐓; 𝐓; T; T; ) MATHEMATICAL BOLD CAPITAL T +1D414;1D414;1D414;0055;0055; # (𝐔; 𝐔; 𝐔; U; U; ) MATHEMATICAL BOLD CAPITAL U +1D415;1D415;1D415;0056;0056; # (𝐕; 𝐕; 𝐕; V; V; ) MATHEMATICAL BOLD CAPITAL V +1D416;1D416;1D416;0057;0057; # (𝐖; 𝐖; 𝐖; W; W; ) MATHEMATICAL BOLD CAPITAL W +1D417;1D417;1D417;0058;0058; # (𝐗; 𝐗; 𝐗; X; X; ) MATHEMATICAL BOLD CAPITAL X +1D418;1D418;1D418;0059;0059; # (𝐘; 𝐘; 𝐘; Y; Y; ) MATHEMATICAL BOLD CAPITAL Y +1D419;1D419;1D419;005A;005A; # (𝐙; 𝐙; 𝐙; Z; Z; ) MATHEMATICAL BOLD CAPITAL Z +1D41A;1D41A;1D41A;0061;0061; # (𝐚; 𝐚; 𝐚; a; a; ) MATHEMATICAL BOLD SMALL A +1D41B;1D41B;1D41B;0062;0062; # (𝐛; 𝐛; 𝐛; b; b; ) MATHEMATICAL BOLD SMALL B +1D41C;1D41C;1D41C;0063;0063; # (𝐜; 𝐜; 𝐜; c; c; ) MATHEMATICAL BOLD SMALL C +1D41D;1D41D;1D41D;0064;0064; # (𝐝; 𝐝; 𝐝; d; d; ) MATHEMATICAL BOLD SMALL D +1D41E;1D41E;1D41E;0065;0065; # (𝐞; 𝐞; 𝐞; e; e; ) MATHEMATICAL BOLD SMALL E +1D41F;1D41F;1D41F;0066;0066; # (𝐟; 𝐟; 𝐟; f; f; ) MATHEMATICAL BOLD SMALL F +1D420;1D420;1D420;0067;0067; # (𝐠; 𝐠; 𝐠; g; g; ) MATHEMATICAL BOLD SMALL G +1D421;1D421;1D421;0068;0068; # (𝐡; 𝐡; 𝐡; h; h; ) MATHEMATICAL BOLD SMALL H +1D422;1D422;1D422;0069;0069; # (𝐢; 𝐢; 𝐢; i; i; ) MATHEMATICAL BOLD SMALL I +1D423;1D423;1D423;006A;006A; # (𝐣; 𝐣; 𝐣; j; j; ) MATHEMATICAL BOLD SMALL J +1D424;1D424;1D424;006B;006B; # (𝐤; 𝐤; 𝐤; k; k; ) MATHEMATICAL BOLD SMALL K +1D425;1D425;1D425;006C;006C; # (𝐥; 𝐥; 𝐥; l; l; ) MATHEMATICAL BOLD SMALL L +1D426;1D426;1D426;006D;006D; # (𝐦; 𝐦; 𝐦; m; m; ) MATHEMATICAL BOLD SMALL M +1D427;1D427;1D427;006E;006E; # (𝐧; 𝐧; 𝐧; n; n; ) MATHEMATICAL BOLD SMALL N +1D428;1D428;1D428;006F;006F; # (𝐨; 𝐨; 𝐨; o; o; ) MATHEMATICAL BOLD SMALL O +1D429;1D429;1D429;0070;0070; # (𝐩; 𝐩; 𝐩; p; p; ) MATHEMATICAL BOLD SMALL P +1D42A;1D42A;1D42A;0071;0071; # (𝐪; 𝐪; 𝐪; q; q; ) MATHEMATICAL BOLD SMALL Q +1D42B;1D42B;1D42B;0072;0072; # (𝐫; 𝐫; 𝐫; r; r; ) MATHEMATICAL BOLD SMALL R +1D42C;1D42C;1D42C;0073;0073; # (𝐬; 𝐬; 𝐬; s; s; ) MATHEMATICAL BOLD SMALL S +1D42D;1D42D;1D42D;0074;0074; # (𝐭; 𝐭; 𝐭; t; t; ) MATHEMATICAL BOLD SMALL T +1D42E;1D42E;1D42E;0075;0075; # (𝐮; 𝐮; 𝐮; u; u; ) MATHEMATICAL BOLD SMALL U +1D42F;1D42F;1D42F;0076;0076; # (𝐯; 𝐯; 𝐯; v; v; ) MATHEMATICAL BOLD SMALL V +1D430;1D430;1D430;0077;0077; # (𝐰; 𝐰; 𝐰; w; w; ) MATHEMATICAL BOLD SMALL W +1D431;1D431;1D431;0078;0078; # (𝐱; 𝐱; 𝐱; x; x; ) MATHEMATICAL BOLD SMALL X +1D432;1D432;1D432;0079;0079; # (𝐲; 𝐲; 𝐲; y; y; ) MATHEMATICAL BOLD SMALL Y +1D433;1D433;1D433;007A;007A; # (𝐳; 𝐳; 𝐳; z; z; ) MATHEMATICAL BOLD SMALL Z +1D434;1D434;1D434;0041;0041; # (𝐴; 𝐴; 𝐴; A; A; ) MATHEMATICAL ITALIC CAPITAL A +1D435;1D435;1D435;0042;0042; # (𝐵; 𝐵; 𝐵; B; B; ) MATHEMATICAL ITALIC CAPITAL B +1D436;1D436;1D436;0043;0043; # (𝐶; 𝐶; 𝐶; C; C; ) MATHEMATICAL ITALIC CAPITAL C +1D437;1D437;1D437;0044;0044; # (𝐷; 𝐷; 𝐷; D; D; ) MATHEMATICAL ITALIC CAPITAL D +1D438;1D438;1D438;0045;0045; # (𝐸; 𝐸; 𝐸; E; E; ) MATHEMATICAL ITALIC CAPITAL E +1D439;1D439;1D439;0046;0046; # (𝐹; 𝐹; 𝐹; F; F; ) MATHEMATICAL ITALIC CAPITAL F +1D43A;1D43A;1D43A;0047;0047; # (𝐺; 𝐺; 𝐺; G; G; ) MATHEMATICAL ITALIC CAPITAL G +1D43B;1D43B;1D43B;0048;0048; # (𝐻; 𝐻; 𝐻; H; H; ) MATHEMATICAL ITALIC CAPITAL H +1D43C;1D43C;1D43C;0049;0049; # (𝐼; 𝐼; 𝐼; I; I; ) MATHEMATICAL ITALIC CAPITAL I +1D43D;1D43D;1D43D;004A;004A; # (𝐽; 𝐽; 𝐽; J; J; ) MATHEMATICAL ITALIC CAPITAL J +1D43E;1D43E;1D43E;004B;004B; # (𝐾; 𝐾; 𝐾; K; K; ) MATHEMATICAL ITALIC CAPITAL K +1D43F;1D43F;1D43F;004C;004C; # (𝐿; 𝐿; 𝐿; L; L; ) MATHEMATICAL ITALIC CAPITAL L +1D440;1D440;1D440;004D;004D; # (𝑀; 𝑀; 𝑀; M; M; ) MATHEMATICAL ITALIC CAPITAL M +1D441;1D441;1D441;004E;004E; # (𝑁; 𝑁; 𝑁; N; N; ) MATHEMATICAL ITALIC CAPITAL N +1D442;1D442;1D442;004F;004F; # (𝑂; 𝑂; 𝑂; O; O; ) MATHEMATICAL ITALIC CAPITAL O +1D443;1D443;1D443;0050;0050; # (𝑃; 𝑃; 𝑃; P; P; ) MATHEMATICAL ITALIC CAPITAL P +1D444;1D444;1D444;0051;0051; # (𝑄; 𝑄; 𝑄; Q; Q; ) MATHEMATICAL ITALIC CAPITAL Q +1D445;1D445;1D445;0052;0052; # (𝑅; 𝑅; 𝑅; R; R; ) MATHEMATICAL ITALIC CAPITAL R +1D446;1D446;1D446;0053;0053; # (𝑆; 𝑆; 𝑆; S; S; ) MATHEMATICAL ITALIC CAPITAL S +1D447;1D447;1D447;0054;0054; # (𝑇; 𝑇; 𝑇; T; T; ) MATHEMATICAL ITALIC CAPITAL T +1D448;1D448;1D448;0055;0055; # (𝑈; 𝑈; 𝑈; U; U; ) MATHEMATICAL ITALIC CAPITAL U +1D449;1D449;1D449;0056;0056; # (𝑉; 𝑉; 𝑉; V; V; ) MATHEMATICAL ITALIC CAPITAL V +1D44A;1D44A;1D44A;0057;0057; # (𝑊; 𝑊; 𝑊; W; W; ) MATHEMATICAL ITALIC CAPITAL W +1D44B;1D44B;1D44B;0058;0058; # (𝑋; 𝑋; 𝑋; X; X; ) MATHEMATICAL ITALIC CAPITAL X +1D44C;1D44C;1D44C;0059;0059; # (𝑌; 𝑌; 𝑌; Y; Y; ) MATHEMATICAL ITALIC CAPITAL Y +1D44D;1D44D;1D44D;005A;005A; # (𝑍; 𝑍; 𝑍; Z; Z; ) MATHEMATICAL ITALIC CAPITAL Z +1D44E;1D44E;1D44E;0061;0061; # (𝑎; 𝑎; 𝑎; a; a; ) MATHEMATICAL ITALIC SMALL A +1D44F;1D44F;1D44F;0062;0062; # (𝑏; 𝑏; 𝑏; b; b; ) MATHEMATICAL ITALIC SMALL B +1D450;1D450;1D450;0063;0063; # (𝑐; 𝑐; 𝑐; c; c; ) MATHEMATICAL ITALIC SMALL C +1D451;1D451;1D451;0064;0064; # (𝑑; 𝑑; 𝑑; d; d; ) MATHEMATICAL ITALIC SMALL D +1D452;1D452;1D452;0065;0065; # (𝑒; 𝑒; 𝑒; e; e; ) MATHEMATICAL ITALIC SMALL E +1D453;1D453;1D453;0066;0066; # (𝑓; 𝑓; 𝑓; f; f; ) MATHEMATICAL ITALIC SMALL F +1D454;1D454;1D454;0067;0067; # (𝑔; 𝑔; 𝑔; g; g; ) MATHEMATICAL ITALIC SMALL G +1D456;1D456;1D456;0069;0069; # (𝑖; 𝑖; 𝑖; i; i; ) MATHEMATICAL ITALIC SMALL I +1D457;1D457;1D457;006A;006A; # (𝑗; 𝑗; 𝑗; j; j; ) MATHEMATICAL ITALIC SMALL J +1D458;1D458;1D458;006B;006B; # (𝑘; 𝑘; 𝑘; k; k; ) MATHEMATICAL ITALIC SMALL K +1D459;1D459;1D459;006C;006C; # (𝑙; 𝑙; 𝑙; l; l; ) MATHEMATICAL ITALIC SMALL L +1D45A;1D45A;1D45A;006D;006D; # (𝑚; 𝑚; 𝑚; m; m; ) MATHEMATICAL ITALIC SMALL M +1D45B;1D45B;1D45B;006E;006E; # (𝑛; 𝑛; 𝑛; n; n; ) MATHEMATICAL ITALIC SMALL N +1D45C;1D45C;1D45C;006F;006F; # (𝑜; 𝑜; 𝑜; o; o; ) MATHEMATICAL ITALIC SMALL O +1D45D;1D45D;1D45D;0070;0070; # (𝑝; 𝑝; 𝑝; p; p; ) MATHEMATICAL ITALIC SMALL P +1D45E;1D45E;1D45E;0071;0071; # (𝑞; 𝑞; 𝑞; q; q; ) MATHEMATICAL ITALIC SMALL Q +1D45F;1D45F;1D45F;0072;0072; # (𝑟; 𝑟; 𝑟; r; r; ) MATHEMATICAL ITALIC SMALL R +1D460;1D460;1D460;0073;0073; # (𝑠; 𝑠; 𝑠; s; s; ) MATHEMATICAL ITALIC SMALL S +1D461;1D461;1D461;0074;0074; # (𝑡; 𝑡; 𝑡; t; t; ) MATHEMATICAL ITALIC SMALL T +1D462;1D462;1D462;0075;0075; # (𝑢; 𝑢; 𝑢; u; u; ) MATHEMATICAL ITALIC SMALL U +1D463;1D463;1D463;0076;0076; # (𝑣; 𝑣; 𝑣; v; v; ) MATHEMATICAL ITALIC SMALL V +1D464;1D464;1D464;0077;0077; # (𝑤; 𝑤; 𝑤; w; w; ) MATHEMATICAL ITALIC SMALL W +1D465;1D465;1D465;0078;0078; # (𝑥; 𝑥; 𝑥; x; x; ) MATHEMATICAL ITALIC SMALL X +1D466;1D466;1D466;0079;0079; # (𝑦; 𝑦; 𝑦; y; y; ) MATHEMATICAL ITALIC SMALL Y +1D467;1D467;1D467;007A;007A; # (𝑧; 𝑧; 𝑧; z; z; ) MATHEMATICAL ITALIC SMALL Z +1D468;1D468;1D468;0041;0041; # (𝑨; 𝑨; 𝑨; A; A; ) MATHEMATICAL BOLD ITALIC CAPITAL A +1D469;1D469;1D469;0042;0042; # (𝑩; 𝑩; 𝑩; B; B; ) MATHEMATICAL BOLD ITALIC CAPITAL B +1D46A;1D46A;1D46A;0043;0043; # (𝑪; 𝑪; 𝑪; C; C; ) MATHEMATICAL BOLD ITALIC CAPITAL C +1D46B;1D46B;1D46B;0044;0044; # (𝑫; 𝑫; 𝑫; D; D; ) MATHEMATICAL BOLD ITALIC CAPITAL D +1D46C;1D46C;1D46C;0045;0045; # (𝑬; 𝑬; 𝑬; E; E; ) MATHEMATICAL BOLD ITALIC CAPITAL E +1D46D;1D46D;1D46D;0046;0046; # (𝑭; 𝑭; 𝑭; F; F; ) MATHEMATICAL BOLD ITALIC CAPITAL F +1D46E;1D46E;1D46E;0047;0047; # (𝑮; 𝑮; 𝑮; G; G; ) MATHEMATICAL BOLD ITALIC CAPITAL G +1D46F;1D46F;1D46F;0048;0048; # (𝑯; 𝑯; 𝑯; H; H; ) MATHEMATICAL BOLD ITALIC CAPITAL H +1D470;1D470;1D470;0049;0049; # (𝑰; 𝑰; 𝑰; I; I; ) MATHEMATICAL BOLD ITALIC CAPITAL I +1D471;1D471;1D471;004A;004A; # (𝑱; 𝑱; 𝑱; J; J; ) MATHEMATICAL BOLD ITALIC CAPITAL J +1D472;1D472;1D472;004B;004B; # (𝑲; 𝑲; 𝑲; K; K; ) MATHEMATICAL BOLD ITALIC CAPITAL K +1D473;1D473;1D473;004C;004C; # (𝑳; 𝑳; 𝑳; L; L; ) MATHEMATICAL BOLD ITALIC CAPITAL L +1D474;1D474;1D474;004D;004D; # (𝑴; 𝑴; 𝑴; M; M; ) MATHEMATICAL BOLD ITALIC CAPITAL M +1D475;1D475;1D475;004E;004E; # (𝑵; 𝑵; 𝑵; N; N; ) MATHEMATICAL BOLD ITALIC CAPITAL N +1D476;1D476;1D476;004F;004F; # (𝑶; 𝑶; 𝑶; O; O; ) MATHEMATICAL BOLD ITALIC CAPITAL O +1D477;1D477;1D477;0050;0050; # (𝑷; 𝑷; 𝑷; P; P; ) MATHEMATICAL BOLD ITALIC CAPITAL P +1D478;1D478;1D478;0051;0051; # (𝑸; 𝑸; 𝑸; Q; Q; ) MATHEMATICAL BOLD ITALIC CAPITAL Q +1D479;1D479;1D479;0052;0052; # (𝑹; 𝑹; 𝑹; R; R; ) MATHEMATICAL BOLD ITALIC CAPITAL R +1D47A;1D47A;1D47A;0053;0053; # (𝑺; 𝑺; 𝑺; S; S; ) MATHEMATICAL BOLD ITALIC CAPITAL S +1D47B;1D47B;1D47B;0054;0054; # (𝑻; 𝑻; 𝑻; T; T; ) MATHEMATICAL BOLD ITALIC CAPITAL T +1D47C;1D47C;1D47C;0055;0055; # (𝑼; 𝑼; 𝑼; U; U; ) MATHEMATICAL BOLD ITALIC CAPITAL U +1D47D;1D47D;1D47D;0056;0056; # (𝑽; 𝑽; 𝑽; V; V; ) MATHEMATICAL BOLD ITALIC CAPITAL V +1D47E;1D47E;1D47E;0057;0057; # (𝑾; 𝑾; 𝑾; W; W; ) MATHEMATICAL BOLD ITALIC CAPITAL W +1D47F;1D47F;1D47F;0058;0058; # (𝑿; 𝑿; 𝑿; X; X; ) MATHEMATICAL BOLD ITALIC CAPITAL X +1D480;1D480;1D480;0059;0059; # (𝒀; 𝒀; 𝒀; Y; Y; ) MATHEMATICAL BOLD ITALIC CAPITAL Y +1D481;1D481;1D481;005A;005A; # (𝒁; 𝒁; 𝒁; Z; Z; ) MATHEMATICAL BOLD ITALIC CAPITAL Z +1D482;1D482;1D482;0061;0061; # (𝒂; 𝒂; 𝒂; a; a; ) MATHEMATICAL BOLD ITALIC SMALL A +1D483;1D483;1D483;0062;0062; # (𝒃; 𝒃; 𝒃; b; b; ) MATHEMATICAL BOLD ITALIC SMALL B +1D484;1D484;1D484;0063;0063; # (𝒄; 𝒄; 𝒄; c; c; ) MATHEMATICAL BOLD ITALIC SMALL C +1D485;1D485;1D485;0064;0064; # (𝒅; 𝒅; 𝒅; d; d; ) MATHEMATICAL BOLD ITALIC SMALL D +1D486;1D486;1D486;0065;0065; # (𝒆; 𝒆; 𝒆; e; e; ) MATHEMATICAL BOLD ITALIC SMALL E +1D487;1D487;1D487;0066;0066; # (𝒇; 𝒇; 𝒇; f; f; ) MATHEMATICAL BOLD ITALIC SMALL F +1D488;1D488;1D488;0067;0067; # (𝒈; 𝒈; 𝒈; g; g; ) MATHEMATICAL BOLD ITALIC SMALL G +1D489;1D489;1D489;0068;0068; # (𝒉; 𝒉; 𝒉; h; h; ) MATHEMATICAL BOLD ITALIC SMALL H +1D48A;1D48A;1D48A;0069;0069; # (𝒊; 𝒊; 𝒊; i; i; ) MATHEMATICAL BOLD ITALIC SMALL I +1D48B;1D48B;1D48B;006A;006A; # (𝒋; 𝒋; 𝒋; j; j; ) MATHEMATICAL BOLD ITALIC SMALL J +1D48C;1D48C;1D48C;006B;006B; # (𝒌; 𝒌; 𝒌; k; k; ) MATHEMATICAL BOLD ITALIC SMALL K +1D48D;1D48D;1D48D;006C;006C; # (𝒍; 𝒍; 𝒍; l; l; ) MATHEMATICAL BOLD ITALIC SMALL L +1D48E;1D48E;1D48E;006D;006D; # (𝒎; 𝒎; 𝒎; m; m; ) MATHEMATICAL BOLD ITALIC SMALL M +1D48F;1D48F;1D48F;006E;006E; # (𝒏; 𝒏; 𝒏; n; n; ) MATHEMATICAL BOLD ITALIC SMALL N +1D490;1D490;1D490;006F;006F; # (𝒐; 𝒐; 𝒐; o; o; ) MATHEMATICAL BOLD ITALIC SMALL O +1D491;1D491;1D491;0070;0070; # (𝒑; 𝒑; 𝒑; p; p; ) MATHEMATICAL BOLD ITALIC SMALL P +1D492;1D492;1D492;0071;0071; # (𝒒; 𝒒; 𝒒; q; q; ) MATHEMATICAL BOLD ITALIC SMALL Q +1D493;1D493;1D493;0072;0072; # (𝒓; 𝒓; 𝒓; r; r; ) MATHEMATICAL BOLD ITALIC SMALL R +1D494;1D494;1D494;0073;0073; # (𝒔; 𝒔; 𝒔; s; s; ) MATHEMATICAL BOLD ITALIC SMALL S +1D495;1D495;1D495;0074;0074; # (𝒕; 𝒕; 𝒕; t; t; ) MATHEMATICAL BOLD ITALIC SMALL T +1D496;1D496;1D496;0075;0075; # (𝒖; 𝒖; 𝒖; u; u; ) MATHEMATICAL BOLD ITALIC SMALL U +1D497;1D497;1D497;0076;0076; # (𝒗; 𝒗; 𝒗; v; v; ) MATHEMATICAL BOLD ITALIC SMALL V +1D498;1D498;1D498;0077;0077; # (𝒘; 𝒘; 𝒘; w; w; ) MATHEMATICAL BOLD ITALIC SMALL W +1D499;1D499;1D499;0078;0078; # (𝒙; 𝒙; 𝒙; x; x; ) MATHEMATICAL BOLD ITALIC SMALL X +1D49A;1D49A;1D49A;0079;0079; # (𝒚; 𝒚; 𝒚; y; y; ) MATHEMATICAL BOLD ITALIC SMALL Y +1D49B;1D49B;1D49B;007A;007A; # (𝒛; 𝒛; 𝒛; z; z; ) MATHEMATICAL BOLD ITALIC SMALL Z +1D49C;1D49C;1D49C;0041;0041; # (𝒜; 𝒜; 𝒜; A; A; ) MATHEMATICAL SCRIPT CAPITAL A +1D49E;1D49E;1D49E;0043;0043; # (𝒞; 𝒞; 𝒞; C; C; ) MATHEMATICAL SCRIPT CAPITAL C +1D49F;1D49F;1D49F;0044;0044; # (𝒟; 𝒟; 𝒟; D; D; ) MATHEMATICAL SCRIPT CAPITAL D +1D4A2;1D4A2;1D4A2;0047;0047; # (𝒢; 𝒢; 𝒢; G; G; ) MATHEMATICAL SCRIPT CAPITAL G +1D4A5;1D4A5;1D4A5;004A;004A; # (𝒥; 𝒥; 𝒥; J; J; ) MATHEMATICAL SCRIPT CAPITAL J +1D4A6;1D4A6;1D4A6;004B;004B; # (𝒦; 𝒦; 𝒦; K; K; ) MATHEMATICAL SCRIPT CAPITAL K +1D4A9;1D4A9;1D4A9;004E;004E; # (𝒩; 𝒩; 𝒩; N; N; ) MATHEMATICAL SCRIPT CAPITAL N +1D4AA;1D4AA;1D4AA;004F;004F; # (𝒪; 𝒪; 𝒪; O; O; ) MATHEMATICAL SCRIPT CAPITAL O +1D4AB;1D4AB;1D4AB;0050;0050; # (𝒫; 𝒫; 𝒫; P; P; ) MATHEMATICAL SCRIPT CAPITAL P +1D4AC;1D4AC;1D4AC;0051;0051; # (𝒬; 𝒬; 𝒬; Q; Q; ) MATHEMATICAL SCRIPT CAPITAL Q +1D4AE;1D4AE;1D4AE;0053;0053; # (𝒮; 𝒮; 𝒮; S; S; ) MATHEMATICAL SCRIPT CAPITAL S +1D4AF;1D4AF;1D4AF;0054;0054; # (𝒯; 𝒯; 𝒯; T; T; ) MATHEMATICAL SCRIPT CAPITAL T +1D4B0;1D4B0;1D4B0;0055;0055; # (𝒰; 𝒰; 𝒰; U; U; ) MATHEMATICAL SCRIPT CAPITAL U +1D4B1;1D4B1;1D4B1;0056;0056; # (𝒱; 𝒱; 𝒱; V; V; ) MATHEMATICAL SCRIPT CAPITAL V +1D4B2;1D4B2;1D4B2;0057;0057; # (𝒲; 𝒲; 𝒲; W; W; ) MATHEMATICAL SCRIPT CAPITAL W +1D4B3;1D4B3;1D4B3;0058;0058; # (𝒳; 𝒳; 𝒳; X; X; ) MATHEMATICAL SCRIPT CAPITAL X +1D4B4;1D4B4;1D4B4;0059;0059; # (𝒴; 𝒴; 𝒴; Y; Y; ) MATHEMATICAL SCRIPT CAPITAL Y +1D4B5;1D4B5;1D4B5;005A;005A; # (𝒵; 𝒵; 𝒵; Z; Z; ) MATHEMATICAL SCRIPT CAPITAL Z +1D4B6;1D4B6;1D4B6;0061;0061; # (𝒶; 𝒶; 𝒶; a; a; ) MATHEMATICAL SCRIPT SMALL A +1D4B7;1D4B7;1D4B7;0062;0062; # (𝒷; 𝒷; 𝒷; b; b; ) MATHEMATICAL SCRIPT SMALL B +1D4B8;1D4B8;1D4B8;0063;0063; # (𝒸; 𝒸; 𝒸; c; c; ) MATHEMATICAL SCRIPT SMALL C +1D4B9;1D4B9;1D4B9;0064;0064; # (𝒹; 𝒹; 𝒹; d; d; ) MATHEMATICAL SCRIPT SMALL D +1D4BB;1D4BB;1D4BB;0066;0066; # (𝒻; 𝒻; 𝒻; f; f; ) MATHEMATICAL SCRIPT SMALL F +1D4BD;1D4BD;1D4BD;0068;0068; # (𝒽; 𝒽; 𝒽; h; h; ) MATHEMATICAL SCRIPT SMALL H +1D4BE;1D4BE;1D4BE;0069;0069; # (𝒾; 𝒾; 𝒾; i; i; ) MATHEMATICAL SCRIPT SMALL I +1D4BF;1D4BF;1D4BF;006A;006A; # (𝒿; 𝒿; 𝒿; j; j; ) MATHEMATICAL SCRIPT SMALL J +1D4C0;1D4C0;1D4C0;006B;006B; # (𝓀; 𝓀; 𝓀; k; k; ) MATHEMATICAL SCRIPT SMALL K +1D4C1;1D4C1;1D4C1;006C;006C; # (𝓁; 𝓁; 𝓁; l; l; ) MATHEMATICAL SCRIPT SMALL L +1D4C2;1D4C2;1D4C2;006D;006D; # (𝓂; 𝓂; 𝓂; m; m; ) MATHEMATICAL SCRIPT SMALL M +1D4C3;1D4C3;1D4C3;006E;006E; # (𝓃; 𝓃; 𝓃; n; n; ) MATHEMATICAL SCRIPT SMALL N +1D4C5;1D4C5;1D4C5;0070;0070; # (𝓅; 𝓅; 𝓅; p; p; ) MATHEMATICAL SCRIPT SMALL P +1D4C6;1D4C6;1D4C6;0071;0071; # (𝓆; 𝓆; 𝓆; q; q; ) MATHEMATICAL SCRIPT SMALL Q +1D4C7;1D4C7;1D4C7;0072;0072; # (𝓇; 𝓇; 𝓇; r; r; ) MATHEMATICAL SCRIPT SMALL R +1D4C8;1D4C8;1D4C8;0073;0073; # (𝓈; 𝓈; 𝓈; s; s; ) MATHEMATICAL SCRIPT SMALL S +1D4C9;1D4C9;1D4C9;0074;0074; # (𝓉; 𝓉; 𝓉; t; t; ) MATHEMATICAL SCRIPT SMALL T +1D4CA;1D4CA;1D4CA;0075;0075; # (𝓊; 𝓊; 𝓊; u; u; ) MATHEMATICAL SCRIPT SMALL U +1D4CB;1D4CB;1D4CB;0076;0076; # (𝓋; 𝓋; 𝓋; v; v; ) MATHEMATICAL SCRIPT SMALL V +1D4CC;1D4CC;1D4CC;0077;0077; # (𝓌; 𝓌; 𝓌; w; w; ) MATHEMATICAL SCRIPT SMALL W +1D4CD;1D4CD;1D4CD;0078;0078; # (𝓍; 𝓍; 𝓍; x; x; ) MATHEMATICAL SCRIPT SMALL X +1D4CE;1D4CE;1D4CE;0079;0079; # (𝓎; 𝓎; 𝓎; y; y; ) MATHEMATICAL SCRIPT SMALL Y +1D4CF;1D4CF;1D4CF;007A;007A; # (𝓏; 𝓏; 𝓏; z; z; ) MATHEMATICAL SCRIPT SMALL Z +1D4D0;1D4D0;1D4D0;0041;0041; # (𝓐; 𝓐; 𝓐; A; A; ) MATHEMATICAL BOLD SCRIPT CAPITAL A +1D4D1;1D4D1;1D4D1;0042;0042; # (𝓑; 𝓑; 𝓑; B; B; ) MATHEMATICAL BOLD SCRIPT CAPITAL B +1D4D2;1D4D2;1D4D2;0043;0043; # (𝓒; 𝓒; 𝓒; C; C; ) MATHEMATICAL BOLD SCRIPT CAPITAL C +1D4D3;1D4D3;1D4D3;0044;0044; # (𝓓; 𝓓; 𝓓; D; D; ) MATHEMATICAL BOLD SCRIPT CAPITAL D +1D4D4;1D4D4;1D4D4;0045;0045; # (𝓔; 𝓔; 𝓔; E; E; ) MATHEMATICAL BOLD SCRIPT CAPITAL E +1D4D5;1D4D5;1D4D5;0046;0046; # (𝓕; 𝓕; 𝓕; F; F; ) MATHEMATICAL BOLD SCRIPT CAPITAL F +1D4D6;1D4D6;1D4D6;0047;0047; # (𝓖; 𝓖; 𝓖; G; G; ) MATHEMATICAL BOLD SCRIPT CAPITAL G +1D4D7;1D4D7;1D4D7;0048;0048; # (𝓗; 𝓗; 𝓗; H; H; ) MATHEMATICAL BOLD SCRIPT CAPITAL H +1D4D8;1D4D8;1D4D8;0049;0049; # (𝓘; 𝓘; 𝓘; I; I; ) MATHEMATICAL BOLD SCRIPT CAPITAL I +1D4D9;1D4D9;1D4D9;004A;004A; # (𝓙; 𝓙; 𝓙; J; J; ) MATHEMATICAL BOLD SCRIPT CAPITAL J +1D4DA;1D4DA;1D4DA;004B;004B; # (𝓚; 𝓚; 𝓚; K; K; ) MATHEMATICAL BOLD SCRIPT CAPITAL K +1D4DB;1D4DB;1D4DB;004C;004C; # (𝓛; 𝓛; 𝓛; L; L; ) MATHEMATICAL BOLD SCRIPT CAPITAL L +1D4DC;1D4DC;1D4DC;004D;004D; # (𝓜; 𝓜; 𝓜; M; M; ) MATHEMATICAL BOLD SCRIPT CAPITAL M +1D4DD;1D4DD;1D4DD;004E;004E; # (𝓝; 𝓝; 𝓝; N; N; ) MATHEMATICAL BOLD SCRIPT CAPITAL N +1D4DE;1D4DE;1D4DE;004F;004F; # (𝓞; 𝓞; 𝓞; O; O; ) MATHEMATICAL BOLD SCRIPT CAPITAL O +1D4DF;1D4DF;1D4DF;0050;0050; # (𝓟; 𝓟; 𝓟; P; P; ) MATHEMATICAL BOLD SCRIPT CAPITAL P +1D4E0;1D4E0;1D4E0;0051;0051; # (𝓠; 𝓠; 𝓠; Q; Q; ) MATHEMATICAL BOLD SCRIPT CAPITAL Q +1D4E1;1D4E1;1D4E1;0052;0052; # (𝓡; 𝓡; 𝓡; R; R; ) MATHEMATICAL BOLD SCRIPT CAPITAL R +1D4E2;1D4E2;1D4E2;0053;0053; # (𝓢; 𝓢; 𝓢; S; S; ) MATHEMATICAL BOLD SCRIPT CAPITAL S +1D4E3;1D4E3;1D4E3;0054;0054; # (𝓣; 𝓣; 𝓣; T; T; ) MATHEMATICAL BOLD SCRIPT CAPITAL T +1D4E4;1D4E4;1D4E4;0055;0055; # (𝓤; 𝓤; 𝓤; U; U; ) MATHEMATICAL BOLD SCRIPT CAPITAL U +1D4E5;1D4E5;1D4E5;0056;0056; # (𝓥; 𝓥; 𝓥; V; V; ) MATHEMATICAL BOLD SCRIPT CAPITAL V +1D4E6;1D4E6;1D4E6;0057;0057; # (𝓦; 𝓦; 𝓦; W; W; ) MATHEMATICAL BOLD SCRIPT CAPITAL W +1D4E7;1D4E7;1D4E7;0058;0058; # (𝓧; 𝓧; 𝓧; X; X; ) MATHEMATICAL BOLD SCRIPT CAPITAL X +1D4E8;1D4E8;1D4E8;0059;0059; # (𝓨; 𝓨; 𝓨; Y; Y; ) MATHEMATICAL BOLD SCRIPT CAPITAL Y +1D4E9;1D4E9;1D4E9;005A;005A; # (𝓩; 𝓩; 𝓩; Z; Z; ) MATHEMATICAL BOLD SCRIPT CAPITAL Z +1D4EA;1D4EA;1D4EA;0061;0061; # (𝓪; 𝓪; 𝓪; a; a; ) MATHEMATICAL BOLD SCRIPT SMALL A +1D4EB;1D4EB;1D4EB;0062;0062; # (𝓫; 𝓫; 𝓫; b; b; ) MATHEMATICAL BOLD SCRIPT SMALL B +1D4EC;1D4EC;1D4EC;0063;0063; # (𝓬; 𝓬; 𝓬; c; c; ) MATHEMATICAL BOLD SCRIPT SMALL C +1D4ED;1D4ED;1D4ED;0064;0064; # (𝓭; 𝓭; 𝓭; d; d; ) MATHEMATICAL BOLD SCRIPT SMALL D +1D4EE;1D4EE;1D4EE;0065;0065; # (𝓮; 𝓮; 𝓮; e; e; ) MATHEMATICAL BOLD SCRIPT SMALL E +1D4EF;1D4EF;1D4EF;0066;0066; # (𝓯; 𝓯; 𝓯; f; f; ) MATHEMATICAL BOLD SCRIPT SMALL F +1D4F0;1D4F0;1D4F0;0067;0067; # (𝓰; 𝓰; 𝓰; g; g; ) MATHEMATICAL BOLD SCRIPT SMALL G +1D4F1;1D4F1;1D4F1;0068;0068; # (𝓱; 𝓱; 𝓱; h; h; ) MATHEMATICAL BOLD SCRIPT SMALL H +1D4F2;1D4F2;1D4F2;0069;0069; # (𝓲; 𝓲; 𝓲; i; i; ) MATHEMATICAL BOLD SCRIPT SMALL I +1D4F3;1D4F3;1D4F3;006A;006A; # (𝓳; 𝓳; 𝓳; j; j; ) MATHEMATICAL BOLD SCRIPT SMALL J +1D4F4;1D4F4;1D4F4;006B;006B; # (𝓴; 𝓴; 𝓴; k; k; ) MATHEMATICAL BOLD SCRIPT SMALL K +1D4F5;1D4F5;1D4F5;006C;006C; # (𝓵; 𝓵; 𝓵; l; l; ) MATHEMATICAL BOLD SCRIPT SMALL L +1D4F6;1D4F6;1D4F6;006D;006D; # (𝓶; 𝓶; 𝓶; m; m; ) MATHEMATICAL BOLD SCRIPT SMALL M +1D4F7;1D4F7;1D4F7;006E;006E; # (𝓷; 𝓷; 𝓷; n; n; ) MATHEMATICAL BOLD SCRIPT SMALL N +1D4F8;1D4F8;1D4F8;006F;006F; # (𝓸; 𝓸; 𝓸; o; o; ) MATHEMATICAL BOLD SCRIPT SMALL O +1D4F9;1D4F9;1D4F9;0070;0070; # (𝓹; 𝓹; 𝓹; p; p; ) MATHEMATICAL BOLD SCRIPT SMALL P +1D4FA;1D4FA;1D4FA;0071;0071; # (𝓺; 𝓺; 𝓺; q; q; ) MATHEMATICAL BOLD SCRIPT SMALL Q +1D4FB;1D4FB;1D4FB;0072;0072; # (𝓻; 𝓻; 𝓻; r; r; ) MATHEMATICAL BOLD SCRIPT SMALL R +1D4FC;1D4FC;1D4FC;0073;0073; # (𝓼; 𝓼; 𝓼; s; s; ) MATHEMATICAL BOLD SCRIPT SMALL S +1D4FD;1D4FD;1D4FD;0074;0074; # (𝓽; 𝓽; 𝓽; t; t; ) MATHEMATICAL BOLD SCRIPT SMALL T +1D4FE;1D4FE;1D4FE;0075;0075; # (𝓾; 𝓾; 𝓾; u; u; ) MATHEMATICAL BOLD SCRIPT SMALL U +1D4FF;1D4FF;1D4FF;0076;0076; # (𝓿; 𝓿; 𝓿; v; v; ) MATHEMATICAL BOLD SCRIPT SMALL V +1D500;1D500;1D500;0077;0077; # (𝔀; 𝔀; 𝔀; w; w; ) MATHEMATICAL BOLD SCRIPT SMALL W +1D501;1D501;1D501;0078;0078; # (𝔁; 𝔁; 𝔁; x; x; ) MATHEMATICAL BOLD SCRIPT SMALL X +1D502;1D502;1D502;0079;0079; # (𝔂; 𝔂; 𝔂; y; y; ) MATHEMATICAL BOLD SCRIPT SMALL Y +1D503;1D503;1D503;007A;007A; # (𝔃; 𝔃; 𝔃; z; z; ) MATHEMATICAL BOLD SCRIPT SMALL Z +1D504;1D504;1D504;0041;0041; # (𝔄; 𝔄; 𝔄; A; A; ) MATHEMATICAL FRAKTUR CAPITAL A +1D505;1D505;1D505;0042;0042; # (𝔅; 𝔅; 𝔅; B; B; ) MATHEMATICAL FRAKTUR CAPITAL B +1D507;1D507;1D507;0044;0044; # (𝔇; 𝔇; 𝔇; D; D; ) MATHEMATICAL FRAKTUR CAPITAL D +1D508;1D508;1D508;0045;0045; # (𝔈; 𝔈; 𝔈; E; E; ) MATHEMATICAL FRAKTUR CAPITAL E +1D509;1D509;1D509;0046;0046; # (𝔉; 𝔉; 𝔉; F; F; ) MATHEMATICAL FRAKTUR CAPITAL F +1D50A;1D50A;1D50A;0047;0047; # (𝔊; 𝔊; 𝔊; G; G; ) MATHEMATICAL FRAKTUR CAPITAL G +1D50D;1D50D;1D50D;004A;004A; # (𝔍; 𝔍; 𝔍; J; J; ) MATHEMATICAL FRAKTUR CAPITAL J +1D50E;1D50E;1D50E;004B;004B; # (𝔎; 𝔎; 𝔎; K; K; ) MATHEMATICAL FRAKTUR CAPITAL K +1D50F;1D50F;1D50F;004C;004C; # (𝔏; 𝔏; 𝔏; L; L; ) MATHEMATICAL FRAKTUR CAPITAL L +1D510;1D510;1D510;004D;004D; # (𝔐; 𝔐; 𝔐; M; M; ) MATHEMATICAL FRAKTUR CAPITAL M +1D511;1D511;1D511;004E;004E; # (𝔑; 𝔑; 𝔑; N; N; ) MATHEMATICAL FRAKTUR CAPITAL N +1D512;1D512;1D512;004F;004F; # (𝔒; 𝔒; 𝔒; O; O; ) MATHEMATICAL FRAKTUR CAPITAL O +1D513;1D513;1D513;0050;0050; # (𝔓; 𝔓; 𝔓; P; P; ) MATHEMATICAL FRAKTUR CAPITAL P +1D514;1D514;1D514;0051;0051; # (𝔔; 𝔔; 𝔔; Q; Q; ) MATHEMATICAL FRAKTUR CAPITAL Q +1D516;1D516;1D516;0053;0053; # (𝔖; 𝔖; 𝔖; S; S; ) MATHEMATICAL FRAKTUR CAPITAL S +1D517;1D517;1D517;0054;0054; # (𝔗; 𝔗; 𝔗; T; T; ) MATHEMATICAL FRAKTUR CAPITAL T +1D518;1D518;1D518;0055;0055; # (𝔘; 𝔘; 𝔘; U; U; ) MATHEMATICAL FRAKTUR CAPITAL U +1D519;1D519;1D519;0056;0056; # (𝔙; 𝔙; 𝔙; V; V; ) MATHEMATICAL FRAKTUR CAPITAL V +1D51A;1D51A;1D51A;0057;0057; # (𝔚; 𝔚; 𝔚; W; W; ) MATHEMATICAL FRAKTUR CAPITAL W +1D51B;1D51B;1D51B;0058;0058; # (𝔛; 𝔛; 𝔛; X; X; ) MATHEMATICAL FRAKTUR CAPITAL X +1D51C;1D51C;1D51C;0059;0059; # (𝔜; 𝔜; 𝔜; Y; Y; ) MATHEMATICAL FRAKTUR CAPITAL Y +1D51E;1D51E;1D51E;0061;0061; # (𝔞; 𝔞; 𝔞; a; a; ) MATHEMATICAL FRAKTUR SMALL A +1D51F;1D51F;1D51F;0062;0062; # (𝔟; 𝔟; 𝔟; b; b; ) MATHEMATICAL FRAKTUR SMALL B +1D520;1D520;1D520;0063;0063; # (𝔠; 𝔠; 𝔠; c; c; ) MATHEMATICAL FRAKTUR SMALL C +1D521;1D521;1D521;0064;0064; # (𝔡; 𝔡; 𝔡; d; d; ) MATHEMATICAL FRAKTUR SMALL D +1D522;1D522;1D522;0065;0065; # (𝔢; 𝔢; 𝔢; e; e; ) MATHEMATICAL FRAKTUR SMALL E +1D523;1D523;1D523;0066;0066; # (𝔣; 𝔣; 𝔣; f; f; ) MATHEMATICAL FRAKTUR SMALL F +1D524;1D524;1D524;0067;0067; # (𝔤; 𝔤; 𝔤; g; g; ) MATHEMATICAL FRAKTUR SMALL G +1D525;1D525;1D525;0068;0068; # (𝔥; 𝔥; 𝔥; h; h; ) MATHEMATICAL FRAKTUR SMALL H +1D526;1D526;1D526;0069;0069; # (𝔦; 𝔦; 𝔦; i; i; ) MATHEMATICAL FRAKTUR SMALL I +1D527;1D527;1D527;006A;006A; # (𝔧; 𝔧; 𝔧; j; j; ) MATHEMATICAL FRAKTUR SMALL J +1D528;1D528;1D528;006B;006B; # (𝔨; 𝔨; 𝔨; k; k; ) MATHEMATICAL FRAKTUR SMALL K +1D529;1D529;1D529;006C;006C; # (𝔩; 𝔩; 𝔩; l; l; ) MATHEMATICAL FRAKTUR SMALL L +1D52A;1D52A;1D52A;006D;006D; # (𝔪; 𝔪; 𝔪; m; m; ) MATHEMATICAL FRAKTUR SMALL M +1D52B;1D52B;1D52B;006E;006E; # (𝔫; 𝔫; 𝔫; n; n; ) MATHEMATICAL FRAKTUR SMALL N +1D52C;1D52C;1D52C;006F;006F; # (𝔬; 𝔬; 𝔬; o; o; ) MATHEMATICAL FRAKTUR SMALL O +1D52D;1D52D;1D52D;0070;0070; # (𝔭; 𝔭; 𝔭; p; p; ) MATHEMATICAL FRAKTUR SMALL P +1D52E;1D52E;1D52E;0071;0071; # (𝔮; 𝔮; 𝔮; q; q; ) MATHEMATICAL FRAKTUR SMALL Q +1D52F;1D52F;1D52F;0072;0072; # (𝔯; 𝔯; 𝔯; r; r; ) MATHEMATICAL FRAKTUR SMALL R +1D530;1D530;1D530;0073;0073; # (𝔰; 𝔰; 𝔰; s; s; ) MATHEMATICAL FRAKTUR SMALL S +1D531;1D531;1D531;0074;0074; # (𝔱; 𝔱; 𝔱; t; t; ) MATHEMATICAL FRAKTUR SMALL T +1D532;1D532;1D532;0075;0075; # (𝔲; 𝔲; 𝔲; u; u; ) MATHEMATICAL FRAKTUR SMALL U +1D533;1D533;1D533;0076;0076; # (𝔳; 𝔳; 𝔳; v; v; ) MATHEMATICAL FRAKTUR SMALL V +1D534;1D534;1D534;0077;0077; # (𝔴; 𝔴; 𝔴; w; w; ) MATHEMATICAL FRAKTUR SMALL W +1D535;1D535;1D535;0078;0078; # (𝔵; 𝔵; 𝔵; x; x; ) MATHEMATICAL FRAKTUR SMALL X +1D536;1D536;1D536;0079;0079; # (𝔶; 𝔶; 𝔶; y; y; ) MATHEMATICAL FRAKTUR SMALL Y +1D537;1D537;1D537;007A;007A; # (𝔷; 𝔷; 𝔷; z; z; ) MATHEMATICAL FRAKTUR SMALL Z +1D538;1D538;1D538;0041;0041; # (𝔸; 𝔸; 𝔸; A; A; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL A +1D539;1D539;1D539;0042;0042; # (𝔹; 𝔹; 𝔹; B; B; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B;1D53B;1D53B;0044;0044; # (𝔻; 𝔻; 𝔻; D; D; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL D +1D53C;1D53C;1D53C;0045;0045; # (𝔼; 𝔼; 𝔼; E; E; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL E +1D53D;1D53D;1D53D;0046;0046; # (𝔽; 𝔽; 𝔽; F; F; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL F +1D53E;1D53E;1D53E;0047;0047; # (𝔾; 𝔾; 𝔾; G; G; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540;1D540;1D540;0049;0049; # (𝕀; 𝕀; 𝕀; I; I; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL I +1D541;1D541;1D541;004A;004A; # (𝕁; 𝕁; 𝕁; J; J; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL J +1D542;1D542;1D542;004B;004B; # (𝕂; 𝕂; 𝕂; K; K; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL K +1D543;1D543;1D543;004C;004C; # (𝕃; 𝕃; 𝕃; L; L; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL L +1D544;1D544;1D544;004D;004D; # (𝕄; 𝕄; 𝕄; M; M; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546;1D546;1D546;004F;004F; # (𝕆; 𝕆; 𝕆; O; O; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A;1D54A;1D54A;0053;0053; # (𝕊; 𝕊; 𝕊; S; S; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL S +1D54B;1D54B;1D54B;0054;0054; # (𝕋; 𝕋; 𝕋; T; T; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL T +1D54C;1D54C;1D54C;0055;0055; # (𝕌; 𝕌; 𝕌; U; U; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL U +1D54D;1D54D;1D54D;0056;0056; # (𝕍; 𝕍; 𝕍; V; V; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL V +1D54E;1D54E;1D54E;0057;0057; # (𝕎; 𝕎; 𝕎; W; W; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL W +1D54F;1D54F;1D54F;0058;0058; # (𝕏; 𝕏; 𝕏; X; X; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL X +1D550;1D550;1D550;0059;0059; # (𝕐; 𝕐; 𝕐; Y; Y; ) MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552;1D552;1D552;0061;0061; # (𝕒; 𝕒; 𝕒; a; a; ) MATHEMATICAL DOUBLE-STRUCK SMALL A +1D553;1D553;1D553;0062;0062; # (𝕓; 𝕓; 𝕓; b; b; ) MATHEMATICAL DOUBLE-STRUCK SMALL B +1D554;1D554;1D554;0063;0063; # (𝕔; 𝕔; 𝕔; c; c; ) MATHEMATICAL DOUBLE-STRUCK SMALL C +1D555;1D555;1D555;0064;0064; # (𝕕; 𝕕; 𝕕; d; d; ) MATHEMATICAL DOUBLE-STRUCK SMALL D +1D556;1D556;1D556;0065;0065; # (𝕖; 𝕖; 𝕖; e; e; ) MATHEMATICAL DOUBLE-STRUCK SMALL E +1D557;1D557;1D557;0066;0066; # (𝕗; 𝕗; 𝕗; f; f; ) MATHEMATICAL DOUBLE-STRUCK SMALL F +1D558;1D558;1D558;0067;0067; # (𝕘; 𝕘; 𝕘; g; g; ) MATHEMATICAL DOUBLE-STRUCK SMALL G +1D559;1D559;1D559;0068;0068; # (𝕙; 𝕙; 𝕙; h; h; ) MATHEMATICAL DOUBLE-STRUCK SMALL H +1D55A;1D55A;1D55A;0069;0069; # (𝕚; 𝕚; 𝕚; i; i; ) MATHEMATICAL DOUBLE-STRUCK SMALL I +1D55B;1D55B;1D55B;006A;006A; # (𝕛; 𝕛; 𝕛; j; j; ) MATHEMATICAL DOUBLE-STRUCK SMALL J +1D55C;1D55C;1D55C;006B;006B; # (𝕜; 𝕜; 𝕜; k; k; ) MATHEMATICAL DOUBLE-STRUCK SMALL K +1D55D;1D55D;1D55D;006C;006C; # (𝕝; 𝕝; 𝕝; l; l; ) MATHEMATICAL DOUBLE-STRUCK SMALL L +1D55E;1D55E;1D55E;006D;006D; # (𝕞; 𝕞; 𝕞; m; m; ) MATHEMATICAL DOUBLE-STRUCK SMALL M +1D55F;1D55F;1D55F;006E;006E; # (𝕟; 𝕟; 𝕟; n; n; ) MATHEMATICAL DOUBLE-STRUCK SMALL N +1D560;1D560;1D560;006F;006F; # (𝕠; 𝕠; 𝕠; o; o; ) MATHEMATICAL DOUBLE-STRUCK SMALL O +1D561;1D561;1D561;0070;0070; # (𝕡; 𝕡; 𝕡; p; p; ) MATHEMATICAL DOUBLE-STRUCK SMALL P +1D562;1D562;1D562;0071;0071; # (𝕢; 𝕢; 𝕢; q; q; ) MATHEMATICAL DOUBLE-STRUCK SMALL Q +1D563;1D563;1D563;0072;0072; # (𝕣; 𝕣; 𝕣; r; r; ) MATHEMATICAL DOUBLE-STRUCK SMALL R +1D564;1D564;1D564;0073;0073; # (𝕤; 𝕤; 𝕤; s; s; ) MATHEMATICAL DOUBLE-STRUCK SMALL S +1D565;1D565;1D565;0074;0074; # (𝕥; 𝕥; 𝕥; t; t; ) MATHEMATICAL DOUBLE-STRUCK SMALL T +1D566;1D566;1D566;0075;0075; # (𝕦; 𝕦; 𝕦; u; u; ) MATHEMATICAL DOUBLE-STRUCK SMALL U +1D567;1D567;1D567;0076;0076; # (𝕧; 𝕧; 𝕧; v; v; ) MATHEMATICAL DOUBLE-STRUCK SMALL V +1D568;1D568;1D568;0077;0077; # (𝕨; 𝕨; 𝕨; w; w; ) MATHEMATICAL DOUBLE-STRUCK SMALL W +1D569;1D569;1D569;0078;0078; # (𝕩; 𝕩; 𝕩; x; x; ) MATHEMATICAL DOUBLE-STRUCK SMALL X +1D56A;1D56A;1D56A;0079;0079; # (𝕪; 𝕪; 𝕪; y; y; ) MATHEMATICAL DOUBLE-STRUCK SMALL Y +1D56B;1D56B;1D56B;007A;007A; # (𝕫; 𝕫; 𝕫; z; z; ) MATHEMATICAL DOUBLE-STRUCK SMALL Z +1D56C;1D56C;1D56C;0041;0041; # (𝕬; 𝕬; 𝕬; A; A; ) MATHEMATICAL BOLD FRAKTUR CAPITAL A +1D56D;1D56D;1D56D;0042;0042; # (𝕭; 𝕭; 𝕭; B; B; ) MATHEMATICAL BOLD FRAKTUR CAPITAL B +1D56E;1D56E;1D56E;0043;0043; # (𝕮; 𝕮; 𝕮; C; C; ) MATHEMATICAL BOLD FRAKTUR CAPITAL C +1D56F;1D56F;1D56F;0044;0044; # (𝕯; 𝕯; 𝕯; D; D; ) MATHEMATICAL BOLD FRAKTUR CAPITAL D +1D570;1D570;1D570;0045;0045; # (𝕰; 𝕰; 𝕰; E; E; ) MATHEMATICAL BOLD FRAKTUR CAPITAL E +1D571;1D571;1D571;0046;0046; # (𝕱; 𝕱; 𝕱; F; F; ) MATHEMATICAL BOLD FRAKTUR CAPITAL F +1D572;1D572;1D572;0047;0047; # (𝕲; 𝕲; 𝕲; G; G; ) MATHEMATICAL BOLD FRAKTUR CAPITAL G +1D573;1D573;1D573;0048;0048; # (𝕳; 𝕳; 𝕳; H; H; ) MATHEMATICAL BOLD FRAKTUR CAPITAL H +1D574;1D574;1D574;0049;0049; # (𝕴; 𝕴; 𝕴; I; I; ) MATHEMATICAL BOLD FRAKTUR CAPITAL I +1D575;1D575;1D575;004A;004A; # (𝕵; 𝕵; 𝕵; J; J; ) MATHEMATICAL BOLD FRAKTUR CAPITAL J +1D576;1D576;1D576;004B;004B; # (𝕶; 𝕶; 𝕶; K; K; ) MATHEMATICAL BOLD FRAKTUR CAPITAL K +1D577;1D577;1D577;004C;004C; # (𝕷; 𝕷; 𝕷; L; L; ) MATHEMATICAL BOLD FRAKTUR CAPITAL L +1D578;1D578;1D578;004D;004D; # (𝕸; 𝕸; 𝕸; M; M; ) MATHEMATICAL BOLD FRAKTUR CAPITAL M +1D579;1D579;1D579;004E;004E; # (𝕹; 𝕹; 𝕹; N; N; ) MATHEMATICAL BOLD FRAKTUR CAPITAL N +1D57A;1D57A;1D57A;004F;004F; # (𝕺; 𝕺; 𝕺; O; O; ) MATHEMATICAL BOLD FRAKTUR CAPITAL O +1D57B;1D57B;1D57B;0050;0050; # (𝕻; 𝕻; 𝕻; P; P; ) MATHEMATICAL BOLD FRAKTUR CAPITAL P +1D57C;1D57C;1D57C;0051;0051; # (𝕼; 𝕼; 𝕼; Q; Q; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Q +1D57D;1D57D;1D57D;0052;0052; # (𝕽; 𝕽; 𝕽; R; R; ) MATHEMATICAL BOLD FRAKTUR CAPITAL R +1D57E;1D57E;1D57E;0053;0053; # (𝕾; 𝕾; 𝕾; S; S; ) MATHEMATICAL BOLD FRAKTUR CAPITAL S +1D57F;1D57F;1D57F;0054;0054; # (𝕿; 𝕿; 𝕿; T; T; ) MATHEMATICAL BOLD FRAKTUR CAPITAL T +1D580;1D580;1D580;0055;0055; # (𝖀; 𝖀; 𝖀; U; U; ) MATHEMATICAL BOLD FRAKTUR CAPITAL U +1D581;1D581;1D581;0056;0056; # (𝖁; 𝖁; 𝖁; V; V; ) MATHEMATICAL BOLD FRAKTUR CAPITAL V +1D582;1D582;1D582;0057;0057; # (𝖂; 𝖂; 𝖂; W; W; ) MATHEMATICAL BOLD FRAKTUR CAPITAL W +1D583;1D583;1D583;0058;0058; # (𝖃; 𝖃; 𝖃; X; X; ) MATHEMATICAL BOLD FRAKTUR CAPITAL X +1D584;1D584;1D584;0059;0059; # (𝖄; 𝖄; 𝖄; Y; Y; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Y +1D585;1D585;1D585;005A;005A; # (𝖅; 𝖅; 𝖅; Z; Z; ) MATHEMATICAL BOLD FRAKTUR CAPITAL Z +1D586;1D586;1D586;0061;0061; # (𝖆; 𝖆; 𝖆; a; a; ) MATHEMATICAL BOLD FRAKTUR SMALL A +1D587;1D587;1D587;0062;0062; # (𝖇; 𝖇; 𝖇; b; b; ) MATHEMATICAL BOLD FRAKTUR SMALL B +1D588;1D588;1D588;0063;0063; # (𝖈; 𝖈; 𝖈; c; c; ) MATHEMATICAL BOLD FRAKTUR SMALL C +1D589;1D589;1D589;0064;0064; # (𝖉; 𝖉; 𝖉; d; d; ) MATHEMATICAL BOLD FRAKTUR SMALL D +1D58A;1D58A;1D58A;0065;0065; # (𝖊; 𝖊; 𝖊; e; e; ) MATHEMATICAL BOLD FRAKTUR SMALL E +1D58B;1D58B;1D58B;0066;0066; # (𝖋; 𝖋; 𝖋; f; f; ) MATHEMATICAL BOLD FRAKTUR SMALL F +1D58C;1D58C;1D58C;0067;0067; # (𝖌; 𝖌; 𝖌; g; g; ) MATHEMATICAL BOLD FRAKTUR SMALL G +1D58D;1D58D;1D58D;0068;0068; # (𝖍; 𝖍; 𝖍; h; h; ) MATHEMATICAL BOLD FRAKTUR SMALL H +1D58E;1D58E;1D58E;0069;0069; # (𝖎; 𝖎; 𝖎; i; i; ) MATHEMATICAL BOLD FRAKTUR SMALL I +1D58F;1D58F;1D58F;006A;006A; # (𝖏; 𝖏; 𝖏; j; j; ) MATHEMATICAL BOLD FRAKTUR SMALL J +1D590;1D590;1D590;006B;006B; # (𝖐; 𝖐; 𝖐; k; k; ) MATHEMATICAL BOLD FRAKTUR SMALL K +1D591;1D591;1D591;006C;006C; # (𝖑; 𝖑; 𝖑; l; l; ) MATHEMATICAL BOLD FRAKTUR SMALL L +1D592;1D592;1D592;006D;006D; # (𝖒; 𝖒; 𝖒; m; m; ) MATHEMATICAL BOLD FRAKTUR SMALL M +1D593;1D593;1D593;006E;006E; # (𝖓; 𝖓; 𝖓; n; n; ) MATHEMATICAL BOLD FRAKTUR SMALL N +1D594;1D594;1D594;006F;006F; # (𝖔; 𝖔; 𝖔; o; o; ) MATHEMATICAL BOLD FRAKTUR SMALL O +1D595;1D595;1D595;0070;0070; # (𝖕; 𝖕; 𝖕; p; p; ) MATHEMATICAL BOLD FRAKTUR SMALL P +1D596;1D596;1D596;0071;0071; # (𝖖; 𝖖; 𝖖; q; q; ) MATHEMATICAL BOLD FRAKTUR SMALL Q +1D597;1D597;1D597;0072;0072; # (𝖗; 𝖗; 𝖗; r; r; ) MATHEMATICAL BOLD FRAKTUR SMALL R +1D598;1D598;1D598;0073;0073; # (𝖘; 𝖘; 𝖘; s; s; ) MATHEMATICAL BOLD FRAKTUR SMALL S +1D599;1D599;1D599;0074;0074; # (𝖙; 𝖙; 𝖙; t; t; ) MATHEMATICAL BOLD FRAKTUR SMALL T +1D59A;1D59A;1D59A;0075;0075; # (𝖚; 𝖚; 𝖚; u; u; ) MATHEMATICAL BOLD FRAKTUR SMALL U +1D59B;1D59B;1D59B;0076;0076; # (𝖛; 𝖛; 𝖛; v; v; ) MATHEMATICAL BOLD FRAKTUR SMALL V +1D59C;1D59C;1D59C;0077;0077; # (𝖜; 𝖜; 𝖜; w; w; ) MATHEMATICAL BOLD FRAKTUR SMALL W +1D59D;1D59D;1D59D;0078;0078; # (𝖝; 𝖝; 𝖝; x; x; ) MATHEMATICAL BOLD FRAKTUR SMALL X +1D59E;1D59E;1D59E;0079;0079; # (𝖞; 𝖞; 𝖞; y; y; ) MATHEMATICAL BOLD FRAKTUR SMALL Y +1D59F;1D59F;1D59F;007A;007A; # (𝖟; 𝖟; 𝖟; z; z; ) MATHEMATICAL BOLD FRAKTUR SMALL Z +1D5A0;1D5A0;1D5A0;0041;0041; # (𝖠; 𝖠; 𝖠; A; A; ) MATHEMATICAL SANS-SERIF CAPITAL A +1D5A1;1D5A1;1D5A1;0042;0042; # (𝖡; 𝖡; 𝖡; B; B; ) MATHEMATICAL SANS-SERIF CAPITAL B +1D5A2;1D5A2;1D5A2;0043;0043; # (𝖢; 𝖢; 𝖢; C; C; ) MATHEMATICAL SANS-SERIF CAPITAL C +1D5A3;1D5A3;1D5A3;0044;0044; # (𝖣; 𝖣; 𝖣; D; D; ) MATHEMATICAL SANS-SERIF CAPITAL D +1D5A4;1D5A4;1D5A4;0045;0045; # (𝖤; 𝖤; 𝖤; E; E; ) MATHEMATICAL SANS-SERIF CAPITAL E +1D5A5;1D5A5;1D5A5;0046;0046; # (𝖥; 𝖥; 𝖥; F; F; ) MATHEMATICAL SANS-SERIF CAPITAL F +1D5A6;1D5A6;1D5A6;0047;0047; # (𝖦; 𝖦; 𝖦; G; G; ) MATHEMATICAL SANS-SERIF CAPITAL G +1D5A7;1D5A7;1D5A7;0048;0048; # (𝖧; 𝖧; 𝖧; H; H; ) MATHEMATICAL SANS-SERIF CAPITAL H +1D5A8;1D5A8;1D5A8;0049;0049; # (𝖨; 𝖨; 𝖨; I; I; ) MATHEMATICAL SANS-SERIF CAPITAL I +1D5A9;1D5A9;1D5A9;004A;004A; # (𝖩; 𝖩; 𝖩; J; J; ) MATHEMATICAL SANS-SERIF CAPITAL J +1D5AA;1D5AA;1D5AA;004B;004B; # (𝖪; 𝖪; 𝖪; K; K; ) MATHEMATICAL SANS-SERIF CAPITAL K +1D5AB;1D5AB;1D5AB;004C;004C; # (𝖫; 𝖫; 𝖫; L; L; ) MATHEMATICAL SANS-SERIF CAPITAL L +1D5AC;1D5AC;1D5AC;004D;004D; # (𝖬; 𝖬; 𝖬; M; M; ) MATHEMATICAL SANS-SERIF CAPITAL M +1D5AD;1D5AD;1D5AD;004E;004E; # (𝖭; 𝖭; 𝖭; N; N; ) MATHEMATICAL SANS-SERIF CAPITAL N +1D5AE;1D5AE;1D5AE;004F;004F; # (𝖮; 𝖮; 𝖮; O; O; ) MATHEMATICAL SANS-SERIF CAPITAL O +1D5AF;1D5AF;1D5AF;0050;0050; # (𝖯; 𝖯; 𝖯; P; P; ) MATHEMATICAL SANS-SERIF CAPITAL P +1D5B0;1D5B0;1D5B0;0051;0051; # (𝖰; 𝖰; 𝖰; Q; Q; ) MATHEMATICAL SANS-SERIF CAPITAL Q +1D5B1;1D5B1;1D5B1;0052;0052; # (𝖱; 𝖱; 𝖱; R; R; ) MATHEMATICAL SANS-SERIF CAPITAL R +1D5B2;1D5B2;1D5B2;0053;0053; # (𝖲; 𝖲; 𝖲; S; S; ) MATHEMATICAL SANS-SERIF CAPITAL S +1D5B3;1D5B3;1D5B3;0054;0054; # (𝖳; 𝖳; 𝖳; T; T; ) MATHEMATICAL SANS-SERIF CAPITAL T +1D5B4;1D5B4;1D5B4;0055;0055; # (𝖴; 𝖴; 𝖴; U; U; ) MATHEMATICAL SANS-SERIF CAPITAL U +1D5B5;1D5B5;1D5B5;0056;0056; # (𝖵; 𝖵; 𝖵; V; V; ) MATHEMATICAL SANS-SERIF CAPITAL V +1D5B6;1D5B6;1D5B6;0057;0057; # (𝖶; 𝖶; 𝖶; W; W; ) MATHEMATICAL SANS-SERIF CAPITAL W +1D5B7;1D5B7;1D5B7;0058;0058; # (𝖷; 𝖷; 𝖷; X; X; ) MATHEMATICAL SANS-SERIF CAPITAL X +1D5B8;1D5B8;1D5B8;0059;0059; # (𝖸; 𝖸; 𝖸; Y; Y; ) MATHEMATICAL SANS-SERIF CAPITAL Y +1D5B9;1D5B9;1D5B9;005A;005A; # (𝖹; 𝖹; 𝖹; Z; Z; ) MATHEMATICAL SANS-SERIF CAPITAL Z +1D5BA;1D5BA;1D5BA;0061;0061; # (𝖺; 𝖺; 𝖺; a; a; ) MATHEMATICAL SANS-SERIF SMALL A +1D5BB;1D5BB;1D5BB;0062;0062; # (𝖻; 𝖻; 𝖻; b; b; ) MATHEMATICAL SANS-SERIF SMALL B +1D5BC;1D5BC;1D5BC;0063;0063; # (𝖼; 𝖼; 𝖼; c; c; ) MATHEMATICAL SANS-SERIF SMALL C +1D5BD;1D5BD;1D5BD;0064;0064; # (𝖽; 𝖽; 𝖽; d; d; ) MATHEMATICAL SANS-SERIF SMALL D +1D5BE;1D5BE;1D5BE;0065;0065; # (𝖾; 𝖾; 𝖾; e; e; ) MATHEMATICAL SANS-SERIF SMALL E +1D5BF;1D5BF;1D5BF;0066;0066; # (𝖿; 𝖿; 𝖿; f; f; ) MATHEMATICAL SANS-SERIF SMALL F +1D5C0;1D5C0;1D5C0;0067;0067; # (𝗀; 𝗀; 𝗀; g; g; ) MATHEMATICAL SANS-SERIF SMALL G +1D5C1;1D5C1;1D5C1;0068;0068; # (𝗁; 𝗁; 𝗁; h; h; ) MATHEMATICAL SANS-SERIF SMALL H +1D5C2;1D5C2;1D5C2;0069;0069; # (𝗂; 𝗂; 𝗂; i; i; ) MATHEMATICAL SANS-SERIF SMALL I +1D5C3;1D5C3;1D5C3;006A;006A; # (𝗃; 𝗃; 𝗃; j; j; ) MATHEMATICAL SANS-SERIF SMALL J +1D5C4;1D5C4;1D5C4;006B;006B; # (𝗄; 𝗄; 𝗄; k; k; ) MATHEMATICAL SANS-SERIF SMALL K +1D5C5;1D5C5;1D5C5;006C;006C; # (𝗅; 𝗅; 𝗅; l; l; ) MATHEMATICAL SANS-SERIF SMALL L +1D5C6;1D5C6;1D5C6;006D;006D; # (𝗆; 𝗆; 𝗆; m; m; ) MATHEMATICAL SANS-SERIF SMALL M +1D5C7;1D5C7;1D5C7;006E;006E; # (𝗇; 𝗇; 𝗇; n; n; ) MATHEMATICAL SANS-SERIF SMALL N +1D5C8;1D5C8;1D5C8;006F;006F; # (𝗈; 𝗈; 𝗈; o; o; ) MATHEMATICAL SANS-SERIF SMALL O +1D5C9;1D5C9;1D5C9;0070;0070; # (𝗉; 𝗉; 𝗉; p; p; ) MATHEMATICAL SANS-SERIF SMALL P +1D5CA;1D5CA;1D5CA;0071;0071; # (𝗊; 𝗊; 𝗊; q; q; ) MATHEMATICAL SANS-SERIF SMALL Q +1D5CB;1D5CB;1D5CB;0072;0072; # (𝗋; 𝗋; 𝗋; r; r; ) MATHEMATICAL SANS-SERIF SMALL R +1D5CC;1D5CC;1D5CC;0073;0073; # (𝗌; 𝗌; 𝗌; s; s; ) MATHEMATICAL SANS-SERIF SMALL S +1D5CD;1D5CD;1D5CD;0074;0074; # (𝗍; 𝗍; 𝗍; t; t; ) MATHEMATICAL SANS-SERIF SMALL T +1D5CE;1D5CE;1D5CE;0075;0075; # (𝗎; 𝗎; 𝗎; u; u; ) MATHEMATICAL SANS-SERIF SMALL U +1D5CF;1D5CF;1D5CF;0076;0076; # (𝗏; 𝗏; 𝗏; v; v; ) MATHEMATICAL SANS-SERIF SMALL V +1D5D0;1D5D0;1D5D0;0077;0077; # (𝗐; 𝗐; 𝗐; w; w; ) MATHEMATICAL SANS-SERIF SMALL W +1D5D1;1D5D1;1D5D1;0078;0078; # (𝗑; 𝗑; 𝗑; x; x; ) MATHEMATICAL SANS-SERIF SMALL X +1D5D2;1D5D2;1D5D2;0079;0079; # (𝗒; 𝗒; 𝗒; y; y; ) MATHEMATICAL SANS-SERIF SMALL Y +1D5D3;1D5D3;1D5D3;007A;007A; # (𝗓; 𝗓; 𝗓; z; z; ) MATHEMATICAL SANS-SERIF SMALL Z +1D5D4;1D5D4;1D5D4;0041;0041; # (𝗔; 𝗔; 𝗔; A; A; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL A +1D5D5;1D5D5;1D5D5;0042;0042; # (𝗕; 𝗕; 𝗕; B; B; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL B +1D5D6;1D5D6;1D5D6;0043;0043; # (𝗖; 𝗖; 𝗖; C; C; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL C +1D5D7;1D5D7;1D5D7;0044;0044; # (𝗗; 𝗗; 𝗗; D; D; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL D +1D5D8;1D5D8;1D5D8;0045;0045; # (𝗘; 𝗘; 𝗘; E; E; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL E +1D5D9;1D5D9;1D5D9;0046;0046; # (𝗙; 𝗙; 𝗙; F; F; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL F +1D5DA;1D5DA;1D5DA;0047;0047; # (𝗚; 𝗚; 𝗚; G; G; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL G +1D5DB;1D5DB;1D5DB;0048;0048; # (𝗛; 𝗛; 𝗛; H; H; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL H +1D5DC;1D5DC;1D5DC;0049;0049; # (𝗜; 𝗜; 𝗜; I; I; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL I +1D5DD;1D5DD;1D5DD;004A;004A; # (𝗝; 𝗝; 𝗝; J; J; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL J +1D5DE;1D5DE;1D5DE;004B;004B; # (𝗞; 𝗞; 𝗞; K; K; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL K +1D5DF;1D5DF;1D5DF;004C;004C; # (𝗟; 𝗟; 𝗟; L; L; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL L +1D5E0;1D5E0;1D5E0;004D;004D; # (𝗠; 𝗠; 𝗠; M; M; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL M +1D5E1;1D5E1;1D5E1;004E;004E; # (𝗡; 𝗡; 𝗡; N; N; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL N +1D5E2;1D5E2;1D5E2;004F;004F; # (𝗢; 𝗢; 𝗢; O; O; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL O +1D5E3;1D5E3;1D5E3;0050;0050; # (𝗣; 𝗣; 𝗣; P; P; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL P +1D5E4;1D5E4;1D5E4;0051;0051; # (𝗤; 𝗤; 𝗤; Q; Q; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Q +1D5E5;1D5E5;1D5E5;0052;0052; # (𝗥; 𝗥; 𝗥; R; R; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL R +1D5E6;1D5E6;1D5E6;0053;0053; # (𝗦; 𝗦; 𝗦; S; S; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL S +1D5E7;1D5E7;1D5E7;0054;0054; # (𝗧; 𝗧; 𝗧; T; T; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL T +1D5E8;1D5E8;1D5E8;0055;0055; # (𝗨; 𝗨; 𝗨; U; U; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL U +1D5E9;1D5E9;1D5E9;0056;0056; # (𝗩; 𝗩; 𝗩; V; V; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL V +1D5EA;1D5EA;1D5EA;0057;0057; # (𝗪; 𝗪; 𝗪; W; W; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL W +1D5EB;1D5EB;1D5EB;0058;0058; # (𝗫; 𝗫; 𝗫; X; X; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL X +1D5EC;1D5EC;1D5EC;0059;0059; # (𝗬; 𝗬; 𝗬; Y; Y; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Y +1D5ED;1D5ED;1D5ED;005A;005A; # (𝗭; 𝗭; 𝗭; Z; Z; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL Z +1D5EE;1D5EE;1D5EE;0061;0061; # (𝗮; 𝗮; 𝗮; a; a; ) MATHEMATICAL SANS-SERIF BOLD SMALL A +1D5EF;1D5EF;1D5EF;0062;0062; # (𝗯; 𝗯; 𝗯; b; b; ) MATHEMATICAL SANS-SERIF BOLD SMALL B +1D5F0;1D5F0;1D5F0;0063;0063; # (𝗰; 𝗰; 𝗰; c; c; ) MATHEMATICAL SANS-SERIF BOLD SMALL C +1D5F1;1D5F1;1D5F1;0064;0064; # (𝗱; 𝗱; 𝗱; d; d; ) MATHEMATICAL SANS-SERIF BOLD SMALL D +1D5F2;1D5F2;1D5F2;0065;0065; # (𝗲; 𝗲; 𝗲; e; e; ) MATHEMATICAL SANS-SERIF BOLD SMALL E +1D5F3;1D5F3;1D5F3;0066;0066; # (𝗳; 𝗳; 𝗳; f; f; ) MATHEMATICAL SANS-SERIF BOLD SMALL F +1D5F4;1D5F4;1D5F4;0067;0067; # (𝗴; 𝗴; 𝗴; g; g; ) MATHEMATICAL SANS-SERIF BOLD SMALL G +1D5F5;1D5F5;1D5F5;0068;0068; # (𝗵; 𝗵; 𝗵; h; h; ) MATHEMATICAL SANS-SERIF BOLD SMALL H +1D5F6;1D5F6;1D5F6;0069;0069; # (𝗶; 𝗶; 𝗶; i; i; ) MATHEMATICAL SANS-SERIF BOLD SMALL I +1D5F7;1D5F7;1D5F7;006A;006A; # (𝗷; 𝗷; 𝗷; j; j; ) MATHEMATICAL SANS-SERIF BOLD SMALL J +1D5F8;1D5F8;1D5F8;006B;006B; # (𝗸; 𝗸; 𝗸; k; k; ) MATHEMATICAL SANS-SERIF BOLD SMALL K +1D5F9;1D5F9;1D5F9;006C;006C; # (𝗹; 𝗹; 𝗹; l; l; ) MATHEMATICAL SANS-SERIF BOLD SMALL L +1D5FA;1D5FA;1D5FA;006D;006D; # (𝗺; 𝗺; 𝗺; m; m; ) MATHEMATICAL SANS-SERIF BOLD SMALL M +1D5FB;1D5FB;1D5FB;006E;006E; # (𝗻; 𝗻; 𝗻; n; n; ) MATHEMATICAL SANS-SERIF BOLD SMALL N +1D5FC;1D5FC;1D5FC;006F;006F; # (𝗼; 𝗼; 𝗼; o; o; ) MATHEMATICAL SANS-SERIF BOLD SMALL O +1D5FD;1D5FD;1D5FD;0070;0070; # (𝗽; 𝗽; 𝗽; p; p; ) MATHEMATICAL SANS-SERIF BOLD SMALL P +1D5FE;1D5FE;1D5FE;0071;0071; # (𝗾; 𝗾; 𝗾; q; q; ) MATHEMATICAL SANS-SERIF BOLD SMALL Q +1D5FF;1D5FF;1D5FF;0072;0072; # (𝗿; 𝗿; 𝗿; r; r; ) MATHEMATICAL SANS-SERIF BOLD SMALL R +1D600;1D600;1D600;0073;0073; # (𝘀; 𝘀; 𝘀; s; s; ) MATHEMATICAL SANS-SERIF BOLD SMALL S +1D601;1D601;1D601;0074;0074; # (𝘁; 𝘁; 𝘁; t; t; ) MATHEMATICAL SANS-SERIF BOLD SMALL T +1D602;1D602;1D602;0075;0075; # (𝘂; 𝘂; 𝘂; u; u; ) MATHEMATICAL SANS-SERIF BOLD SMALL U +1D603;1D603;1D603;0076;0076; # (𝘃; 𝘃; 𝘃; v; v; ) MATHEMATICAL SANS-SERIF BOLD SMALL V +1D604;1D604;1D604;0077;0077; # (𝘄; 𝘄; 𝘄; w; w; ) MATHEMATICAL SANS-SERIF BOLD SMALL W +1D605;1D605;1D605;0078;0078; # (𝘅; 𝘅; 𝘅; x; x; ) MATHEMATICAL SANS-SERIF BOLD SMALL X +1D606;1D606;1D606;0079;0079; # (𝘆; 𝘆; 𝘆; y; y; ) MATHEMATICAL SANS-SERIF BOLD SMALL Y +1D607;1D607;1D607;007A;007A; # (𝘇; 𝘇; 𝘇; z; z; ) MATHEMATICAL SANS-SERIF BOLD SMALL Z +1D608;1D608;1D608;0041;0041; # (𝘈; 𝘈; 𝘈; A; A; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL A +1D609;1D609;1D609;0042;0042; # (𝘉; 𝘉; 𝘉; B; B; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL B +1D60A;1D60A;1D60A;0043;0043; # (𝘊; 𝘊; 𝘊; C; C; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL C +1D60B;1D60B;1D60B;0044;0044; # (𝘋; 𝘋; 𝘋; D; D; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL D +1D60C;1D60C;1D60C;0045;0045; # (𝘌; 𝘌; 𝘌; E; E; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL E +1D60D;1D60D;1D60D;0046;0046; # (𝘍; 𝘍; 𝘍; F; F; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL F +1D60E;1D60E;1D60E;0047;0047; # (𝘎; 𝘎; 𝘎; G; G; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL G +1D60F;1D60F;1D60F;0048;0048; # (𝘏; 𝘏; 𝘏; H; H; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL H +1D610;1D610;1D610;0049;0049; # (𝘐; 𝘐; 𝘐; I; I; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL I +1D611;1D611;1D611;004A;004A; # (𝘑; 𝘑; 𝘑; J; J; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL J +1D612;1D612;1D612;004B;004B; # (𝘒; 𝘒; 𝘒; K; K; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL K +1D613;1D613;1D613;004C;004C; # (𝘓; 𝘓; 𝘓; L; L; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL L +1D614;1D614;1D614;004D;004D; # (𝘔; 𝘔; 𝘔; M; M; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL M +1D615;1D615;1D615;004E;004E; # (𝘕; 𝘕; 𝘕; N; N; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL N +1D616;1D616;1D616;004F;004F; # (𝘖; 𝘖; 𝘖; O; O; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL O +1D617;1D617;1D617;0050;0050; # (𝘗; 𝘗; 𝘗; P; P; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL P +1D618;1D618;1D618;0051;0051; # (𝘘; 𝘘; 𝘘; Q; Q; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q +1D619;1D619;1D619;0052;0052; # (𝘙; 𝘙; 𝘙; R; R; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL R +1D61A;1D61A;1D61A;0053;0053; # (𝘚; 𝘚; 𝘚; S; S; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL S +1D61B;1D61B;1D61B;0054;0054; # (𝘛; 𝘛; 𝘛; T; T; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL T +1D61C;1D61C;1D61C;0055;0055; # (𝘜; 𝘜; 𝘜; U; U; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL U +1D61D;1D61D;1D61D;0056;0056; # (𝘝; 𝘝; 𝘝; V; V; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL V +1D61E;1D61E;1D61E;0057;0057; # (𝘞; 𝘞; 𝘞; W; W; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL W +1D61F;1D61F;1D61F;0058;0058; # (𝘟; 𝘟; 𝘟; X; X; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL X +1D620;1D620;1D620;0059;0059; # (𝘠; 𝘠; 𝘠; Y; Y; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y +1D621;1D621;1D621;005A;005A; # (𝘡; 𝘡; 𝘡; Z; Z; ) MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z +1D622;1D622;1D622;0061;0061; # (𝘢; 𝘢; 𝘢; a; a; ) MATHEMATICAL SANS-SERIF ITALIC SMALL A +1D623;1D623;1D623;0062;0062; # (𝘣; 𝘣; 𝘣; b; b; ) MATHEMATICAL SANS-SERIF ITALIC SMALL B +1D624;1D624;1D624;0063;0063; # (𝘤; 𝘤; 𝘤; c; c; ) MATHEMATICAL SANS-SERIF ITALIC SMALL C +1D625;1D625;1D625;0064;0064; # (𝘥; 𝘥; 𝘥; d; d; ) MATHEMATICAL SANS-SERIF ITALIC SMALL D +1D626;1D626;1D626;0065;0065; # (𝘦; 𝘦; 𝘦; e; e; ) MATHEMATICAL SANS-SERIF ITALIC SMALL E +1D627;1D627;1D627;0066;0066; # (𝘧; 𝘧; 𝘧; f; f; ) MATHEMATICAL SANS-SERIF ITALIC SMALL F +1D628;1D628;1D628;0067;0067; # (𝘨; 𝘨; 𝘨; g; g; ) MATHEMATICAL SANS-SERIF ITALIC SMALL G +1D629;1D629;1D629;0068;0068; # (𝘩; 𝘩; 𝘩; h; h; ) MATHEMATICAL SANS-SERIF ITALIC SMALL H +1D62A;1D62A;1D62A;0069;0069; # (𝘪; 𝘪; 𝘪; i; i; ) MATHEMATICAL SANS-SERIF ITALIC SMALL I +1D62B;1D62B;1D62B;006A;006A; # (𝘫; 𝘫; 𝘫; j; j; ) MATHEMATICAL SANS-SERIF ITALIC SMALL J +1D62C;1D62C;1D62C;006B;006B; # (𝘬; 𝘬; 𝘬; k; k; ) MATHEMATICAL SANS-SERIF ITALIC SMALL K +1D62D;1D62D;1D62D;006C;006C; # (𝘭; 𝘭; 𝘭; l; l; ) MATHEMATICAL SANS-SERIF ITALIC SMALL L +1D62E;1D62E;1D62E;006D;006D; # (𝘮; 𝘮; 𝘮; m; m; ) MATHEMATICAL SANS-SERIF ITALIC SMALL M +1D62F;1D62F;1D62F;006E;006E; # (𝘯; 𝘯; 𝘯; n; n; ) MATHEMATICAL SANS-SERIF ITALIC SMALL N +1D630;1D630;1D630;006F;006F; # (𝘰; 𝘰; 𝘰; o; o; ) MATHEMATICAL SANS-SERIF ITALIC SMALL O +1D631;1D631;1D631;0070;0070; # (𝘱; 𝘱; 𝘱; p; p; ) MATHEMATICAL SANS-SERIF ITALIC SMALL P +1D632;1D632;1D632;0071;0071; # (𝘲; 𝘲; 𝘲; q; q; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Q +1D633;1D633;1D633;0072;0072; # (𝘳; 𝘳; 𝘳; r; r; ) MATHEMATICAL SANS-SERIF ITALIC SMALL R +1D634;1D634;1D634;0073;0073; # (𝘴; 𝘴; 𝘴; s; s; ) MATHEMATICAL SANS-SERIF ITALIC SMALL S +1D635;1D635;1D635;0074;0074; # (𝘵; 𝘵; 𝘵; t; t; ) MATHEMATICAL SANS-SERIF ITALIC SMALL T +1D636;1D636;1D636;0075;0075; # (𝘶; 𝘶; 𝘶; u; u; ) MATHEMATICAL SANS-SERIF ITALIC SMALL U +1D637;1D637;1D637;0076;0076; # (𝘷; 𝘷; 𝘷; v; v; ) MATHEMATICAL SANS-SERIF ITALIC SMALL V +1D638;1D638;1D638;0077;0077; # (𝘸; 𝘸; 𝘸; w; w; ) MATHEMATICAL SANS-SERIF ITALIC SMALL W +1D639;1D639;1D639;0078;0078; # (𝘹; 𝘹; 𝘹; x; x; ) MATHEMATICAL SANS-SERIF ITALIC SMALL X +1D63A;1D63A;1D63A;0079;0079; # (𝘺; 𝘺; 𝘺; y; y; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Y +1D63B;1D63B;1D63B;007A;007A; # (𝘻; 𝘻; 𝘻; z; z; ) MATHEMATICAL SANS-SERIF ITALIC SMALL Z +1D63C;1D63C;1D63C;0041;0041; # (𝘼; 𝘼; 𝘼; A; A; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A +1D63D;1D63D;1D63D;0042;0042; # (𝘽; 𝘽; 𝘽; B; B; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B +1D63E;1D63E;1D63E;0043;0043; # (𝘾; 𝘾; 𝘾; C; C; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C +1D63F;1D63F;1D63F;0044;0044; # (𝘿; 𝘿; 𝘿; D; D; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D +1D640;1D640;1D640;0045;0045; # (𝙀; 𝙀; 𝙀; E; E; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E +1D641;1D641;1D641;0046;0046; # (𝙁; 𝙁; 𝙁; F; F; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F +1D642;1D642;1D642;0047;0047; # (𝙂; 𝙂; 𝙂; G; G; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G +1D643;1D643;1D643;0048;0048; # (𝙃; 𝙃; 𝙃; H; H; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H +1D644;1D644;1D644;0049;0049; # (𝙄; 𝙄; 𝙄; I; I; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I +1D645;1D645;1D645;004A;004A; # (𝙅; 𝙅; 𝙅; J; J; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J +1D646;1D646;1D646;004B;004B; # (𝙆; 𝙆; 𝙆; K; K; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K +1D647;1D647;1D647;004C;004C; # (𝙇; 𝙇; 𝙇; L; L; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L +1D648;1D648;1D648;004D;004D; # (𝙈; 𝙈; 𝙈; M; M; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M +1D649;1D649;1D649;004E;004E; # (𝙉; 𝙉; 𝙉; N; N; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N +1D64A;1D64A;1D64A;004F;004F; # (𝙊; 𝙊; 𝙊; O; O; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O +1D64B;1D64B;1D64B;0050;0050; # (𝙋; 𝙋; 𝙋; P; P; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P +1D64C;1D64C;1D64C;0051;0051; # (𝙌; 𝙌; 𝙌; Q; Q; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q +1D64D;1D64D;1D64D;0052;0052; # (𝙍; 𝙍; 𝙍; R; R; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R +1D64E;1D64E;1D64E;0053;0053; # (𝙎; 𝙎; 𝙎; S; S; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S +1D64F;1D64F;1D64F;0054;0054; # (𝙏; 𝙏; 𝙏; T; T; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T +1D650;1D650;1D650;0055;0055; # (𝙐; 𝙐; 𝙐; U; U; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U +1D651;1D651;1D651;0056;0056; # (𝙑; 𝙑; 𝙑; V; V; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V +1D652;1D652;1D652;0057;0057; # (𝙒; 𝙒; 𝙒; W; W; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W +1D653;1D653;1D653;0058;0058; # (𝙓; 𝙓; 𝙓; X; X; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X +1D654;1D654;1D654;0059;0059; # (𝙔; 𝙔; 𝙔; Y; Y; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y +1D655;1D655;1D655;005A;005A; # (𝙕; 𝙕; 𝙕; Z; Z; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z +1D656;1D656;1D656;0061;0061; # (𝙖; 𝙖; 𝙖; a; a; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A +1D657;1D657;1D657;0062;0062; # (𝙗; 𝙗; 𝙗; b; b; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B +1D658;1D658;1D658;0063;0063; # (𝙘; 𝙘; 𝙘; c; c; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C +1D659;1D659;1D659;0064;0064; # (𝙙; 𝙙; 𝙙; d; d; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D +1D65A;1D65A;1D65A;0065;0065; # (𝙚; 𝙚; 𝙚; e; e; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E +1D65B;1D65B;1D65B;0066;0066; # (𝙛; 𝙛; 𝙛; f; f; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F +1D65C;1D65C;1D65C;0067;0067; # (𝙜; 𝙜; 𝙜; g; g; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G +1D65D;1D65D;1D65D;0068;0068; # (𝙝; 𝙝; 𝙝; h; h; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H +1D65E;1D65E;1D65E;0069;0069; # (𝙞; 𝙞; 𝙞; i; i; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I +1D65F;1D65F;1D65F;006A;006A; # (𝙟; 𝙟; 𝙟; j; j; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J +1D660;1D660;1D660;006B;006B; # (𝙠; 𝙠; 𝙠; k; k; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K +1D661;1D661;1D661;006C;006C; # (𝙡; 𝙡; 𝙡; l; l; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L +1D662;1D662;1D662;006D;006D; # (𝙢; 𝙢; 𝙢; m; m; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M +1D663;1D663;1D663;006E;006E; # (𝙣; 𝙣; 𝙣; n; n; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N +1D664;1D664;1D664;006F;006F; # (𝙤; 𝙤; 𝙤; o; o; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O +1D665;1D665;1D665;0070;0070; # (𝙥; 𝙥; 𝙥; p; p; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P +1D666;1D666;1D666;0071;0071; # (𝙦; 𝙦; 𝙦; q; q; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q +1D667;1D667;1D667;0072;0072; # (𝙧; 𝙧; 𝙧; r; r; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R +1D668;1D668;1D668;0073;0073; # (𝙨; 𝙨; 𝙨; s; s; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S +1D669;1D669;1D669;0074;0074; # (𝙩; 𝙩; 𝙩; t; t; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T +1D66A;1D66A;1D66A;0075;0075; # (𝙪; 𝙪; 𝙪; u; u; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U +1D66B;1D66B;1D66B;0076;0076; # (𝙫; 𝙫; 𝙫; v; v; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V +1D66C;1D66C;1D66C;0077;0077; # (𝙬; 𝙬; 𝙬; w; w; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W +1D66D;1D66D;1D66D;0078;0078; # (𝙭; 𝙭; 𝙭; x; x; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X +1D66E;1D66E;1D66E;0079;0079; # (𝙮; 𝙮; 𝙮; y; y; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y +1D66F;1D66F;1D66F;007A;007A; # (𝙯; 𝙯; 𝙯; z; z; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z +1D670;1D670;1D670;0041;0041; # (𝙰; 𝙰; 𝙰; A; A; ) MATHEMATICAL MONOSPACE CAPITAL A +1D671;1D671;1D671;0042;0042; # (𝙱; 𝙱; 𝙱; B; B; ) MATHEMATICAL MONOSPACE CAPITAL B +1D672;1D672;1D672;0043;0043; # (𝙲; 𝙲; 𝙲; C; C; ) MATHEMATICAL MONOSPACE CAPITAL C +1D673;1D673;1D673;0044;0044; # (𝙳; 𝙳; 𝙳; D; D; ) MATHEMATICAL MONOSPACE CAPITAL D +1D674;1D674;1D674;0045;0045; # (𝙴; 𝙴; 𝙴; E; E; ) MATHEMATICAL MONOSPACE CAPITAL E +1D675;1D675;1D675;0046;0046; # (𝙵; 𝙵; 𝙵; F; F; ) MATHEMATICAL MONOSPACE CAPITAL F +1D676;1D676;1D676;0047;0047; # (𝙶; 𝙶; 𝙶; G; G; ) MATHEMATICAL MONOSPACE CAPITAL G +1D677;1D677;1D677;0048;0048; # (𝙷; 𝙷; 𝙷; H; H; ) MATHEMATICAL MONOSPACE CAPITAL H +1D678;1D678;1D678;0049;0049; # (𝙸; 𝙸; 𝙸; I; I; ) MATHEMATICAL MONOSPACE CAPITAL I +1D679;1D679;1D679;004A;004A; # (𝙹; 𝙹; 𝙹; J; J; ) MATHEMATICAL MONOSPACE CAPITAL J +1D67A;1D67A;1D67A;004B;004B; # (𝙺; 𝙺; 𝙺; K; K; ) MATHEMATICAL MONOSPACE CAPITAL K +1D67B;1D67B;1D67B;004C;004C; # (𝙻; 𝙻; 𝙻; L; L; ) MATHEMATICAL MONOSPACE CAPITAL L +1D67C;1D67C;1D67C;004D;004D; # (𝙼; 𝙼; 𝙼; M; M; ) MATHEMATICAL MONOSPACE CAPITAL M +1D67D;1D67D;1D67D;004E;004E; # (𝙽; 𝙽; 𝙽; N; N; ) MATHEMATICAL MONOSPACE CAPITAL N +1D67E;1D67E;1D67E;004F;004F; # (𝙾; 𝙾; 𝙾; O; O; ) MATHEMATICAL MONOSPACE CAPITAL O +1D67F;1D67F;1D67F;0050;0050; # (𝙿; 𝙿; 𝙿; P; P; ) MATHEMATICAL MONOSPACE CAPITAL P +1D680;1D680;1D680;0051;0051; # (𝚀; 𝚀; 𝚀; Q; Q; ) MATHEMATICAL MONOSPACE CAPITAL Q +1D681;1D681;1D681;0052;0052; # (𝚁; 𝚁; 𝚁; R; R; ) MATHEMATICAL MONOSPACE CAPITAL R +1D682;1D682;1D682;0053;0053; # (𝚂; 𝚂; 𝚂; S; S; ) MATHEMATICAL MONOSPACE CAPITAL S +1D683;1D683;1D683;0054;0054; # (𝚃; 𝚃; 𝚃; T; T; ) MATHEMATICAL MONOSPACE CAPITAL T +1D684;1D684;1D684;0055;0055; # (𝚄; 𝚄; 𝚄; U; U; ) MATHEMATICAL MONOSPACE CAPITAL U +1D685;1D685;1D685;0056;0056; # (𝚅; 𝚅; 𝚅; V; V; ) MATHEMATICAL MONOSPACE CAPITAL V +1D686;1D686;1D686;0057;0057; # (𝚆; 𝚆; 𝚆; W; W; ) MATHEMATICAL MONOSPACE CAPITAL W +1D687;1D687;1D687;0058;0058; # (𝚇; 𝚇; 𝚇; X; X; ) MATHEMATICAL MONOSPACE CAPITAL X +1D688;1D688;1D688;0059;0059; # (𝚈; 𝚈; 𝚈; Y; Y; ) MATHEMATICAL MONOSPACE CAPITAL Y +1D689;1D689;1D689;005A;005A; # (𝚉; 𝚉; 𝚉; Z; Z; ) MATHEMATICAL MONOSPACE CAPITAL Z +1D68A;1D68A;1D68A;0061;0061; # (𝚊; 𝚊; 𝚊; a; a; ) MATHEMATICAL MONOSPACE SMALL A +1D68B;1D68B;1D68B;0062;0062; # (𝚋; 𝚋; 𝚋; b; b; ) MATHEMATICAL MONOSPACE SMALL B +1D68C;1D68C;1D68C;0063;0063; # (𝚌; 𝚌; 𝚌; c; c; ) MATHEMATICAL MONOSPACE SMALL C +1D68D;1D68D;1D68D;0064;0064; # (𝚍; 𝚍; 𝚍; d; d; ) MATHEMATICAL MONOSPACE SMALL D +1D68E;1D68E;1D68E;0065;0065; # (𝚎; 𝚎; 𝚎; e; e; ) MATHEMATICAL MONOSPACE SMALL E +1D68F;1D68F;1D68F;0066;0066; # (𝚏; 𝚏; 𝚏; f; f; ) MATHEMATICAL MONOSPACE SMALL F +1D690;1D690;1D690;0067;0067; # (𝚐; 𝚐; 𝚐; g; g; ) MATHEMATICAL MONOSPACE SMALL G +1D691;1D691;1D691;0068;0068; # (𝚑; 𝚑; 𝚑; h; h; ) MATHEMATICAL MONOSPACE SMALL H +1D692;1D692;1D692;0069;0069; # (𝚒; 𝚒; 𝚒; i; i; ) MATHEMATICAL MONOSPACE SMALL I +1D693;1D693;1D693;006A;006A; # (𝚓; 𝚓; 𝚓; j; j; ) MATHEMATICAL MONOSPACE SMALL J +1D694;1D694;1D694;006B;006B; # (𝚔; 𝚔; 𝚔; k; k; ) MATHEMATICAL MONOSPACE SMALL K +1D695;1D695;1D695;006C;006C; # (𝚕; 𝚕; 𝚕; l; l; ) MATHEMATICAL MONOSPACE SMALL L +1D696;1D696;1D696;006D;006D; # (𝚖; 𝚖; 𝚖; m; m; ) MATHEMATICAL MONOSPACE SMALL M +1D697;1D697;1D697;006E;006E; # (𝚗; 𝚗; 𝚗; n; n; ) MATHEMATICAL MONOSPACE SMALL N +1D698;1D698;1D698;006F;006F; # (𝚘; 𝚘; 𝚘; o; o; ) MATHEMATICAL MONOSPACE SMALL O +1D699;1D699;1D699;0070;0070; # (𝚙; 𝚙; 𝚙; p; p; ) MATHEMATICAL MONOSPACE SMALL P +1D69A;1D69A;1D69A;0071;0071; # (𝚚; 𝚚; 𝚚; q; q; ) MATHEMATICAL MONOSPACE SMALL Q +1D69B;1D69B;1D69B;0072;0072; # (𝚛; 𝚛; 𝚛; r; r; ) MATHEMATICAL MONOSPACE SMALL R +1D69C;1D69C;1D69C;0073;0073; # (𝚜; 𝚜; 𝚜; s; s; ) MATHEMATICAL MONOSPACE SMALL S +1D69D;1D69D;1D69D;0074;0074; # (𝚝; 𝚝; 𝚝; t; t; ) MATHEMATICAL MONOSPACE SMALL T +1D69E;1D69E;1D69E;0075;0075; # (𝚞; 𝚞; 𝚞; u; u; ) MATHEMATICAL MONOSPACE SMALL U +1D69F;1D69F;1D69F;0076;0076; # (𝚟; 𝚟; 𝚟; v; v; ) MATHEMATICAL MONOSPACE SMALL V +1D6A0;1D6A0;1D6A0;0077;0077; # (𝚠; 𝚠; 𝚠; w; w; ) MATHEMATICAL MONOSPACE SMALL W +1D6A1;1D6A1;1D6A1;0078;0078; # (𝚡; 𝚡; 𝚡; x; x; ) MATHEMATICAL MONOSPACE SMALL X +1D6A2;1D6A2;1D6A2;0079;0079; # (𝚢; 𝚢; 𝚢; y; y; ) MATHEMATICAL MONOSPACE SMALL Y +1D6A3;1D6A3;1D6A3;007A;007A; # (𝚣; 𝚣; 𝚣; z; z; ) MATHEMATICAL MONOSPACE SMALL Z +1D6A4;1D6A4;1D6A4;0131;0131; # (𝚤; 𝚤; 𝚤; ı; ı; ) MATHEMATICAL ITALIC SMALL DOTLESS I +1D6A5;1D6A5;1D6A5;0237;0237; # (𝚥; 𝚥; 𝚥; ȷ; ȷ; ) MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A8;1D6A8;1D6A8;0391;0391; # (𝚨; 𝚨; 𝚨; Α; Α; ) MATHEMATICAL BOLD CAPITAL ALPHA +1D6A9;1D6A9;1D6A9;0392;0392; # (𝚩; 𝚩; 𝚩; Β; Β; ) MATHEMATICAL BOLD CAPITAL BETA +1D6AA;1D6AA;1D6AA;0393;0393; # (𝚪; 𝚪; 𝚪; Γ; Γ; ) MATHEMATICAL BOLD CAPITAL GAMMA +1D6AB;1D6AB;1D6AB;0394;0394; # (𝚫; 𝚫; 𝚫; Δ; Δ; ) MATHEMATICAL BOLD CAPITAL DELTA +1D6AC;1D6AC;1D6AC;0395;0395; # (𝚬; 𝚬; 𝚬; Ε; Ε; ) MATHEMATICAL BOLD CAPITAL EPSILON +1D6AD;1D6AD;1D6AD;0396;0396; # (𝚭; 𝚭; 𝚭; Ζ; Ζ; ) MATHEMATICAL BOLD CAPITAL ZETA +1D6AE;1D6AE;1D6AE;0397;0397; # (𝚮; 𝚮; 𝚮; Η; Η; ) MATHEMATICAL BOLD CAPITAL ETA +1D6AF;1D6AF;1D6AF;0398;0398; # (𝚯; 𝚯; 𝚯; Θ; Θ; ) MATHEMATICAL BOLD CAPITAL THETA +1D6B0;1D6B0;1D6B0;0399;0399; # (𝚰; 𝚰; 𝚰; Ι; Ι; ) MATHEMATICAL BOLD CAPITAL IOTA +1D6B1;1D6B1;1D6B1;039A;039A; # (𝚱; 𝚱; 𝚱; Κ; Κ; ) MATHEMATICAL BOLD CAPITAL KAPPA +1D6B2;1D6B2;1D6B2;039B;039B; # (𝚲; 𝚲; 𝚲; Λ; Λ; ) MATHEMATICAL BOLD CAPITAL LAMDA +1D6B3;1D6B3;1D6B3;039C;039C; # (𝚳; 𝚳; 𝚳; Μ; Μ; ) MATHEMATICAL BOLD CAPITAL MU +1D6B4;1D6B4;1D6B4;039D;039D; # (𝚴; 𝚴; 𝚴; Ν; Ν; ) MATHEMATICAL BOLD CAPITAL NU +1D6B5;1D6B5;1D6B5;039E;039E; # (𝚵; 𝚵; 𝚵; Ξ; Ξ; ) MATHEMATICAL BOLD CAPITAL XI +1D6B6;1D6B6;1D6B6;039F;039F; # (𝚶; 𝚶; 𝚶; Ο; Ο; ) MATHEMATICAL BOLD CAPITAL OMICRON +1D6B7;1D6B7;1D6B7;03A0;03A0; # (𝚷; 𝚷; 𝚷; Π; Π; ) MATHEMATICAL BOLD CAPITAL PI +1D6B8;1D6B8;1D6B8;03A1;03A1; # (𝚸; 𝚸; 𝚸; Ρ; Ρ; ) MATHEMATICAL BOLD CAPITAL RHO +1D6B9;1D6B9;1D6B9;0398;0398; # (𝚹; 𝚹; 𝚹; Θ; Θ; ) MATHEMATICAL BOLD CAPITAL THETA SYMBOL +1D6BA;1D6BA;1D6BA;03A3;03A3; # (𝚺; 𝚺; 𝚺; Σ; Σ; ) MATHEMATICAL BOLD CAPITAL SIGMA +1D6BB;1D6BB;1D6BB;03A4;03A4; # (𝚻; 𝚻; 𝚻; Τ; Τ; ) MATHEMATICAL BOLD CAPITAL TAU +1D6BC;1D6BC;1D6BC;03A5;03A5; # (𝚼; 𝚼; 𝚼; Υ; Υ; ) MATHEMATICAL BOLD CAPITAL UPSILON +1D6BD;1D6BD;1D6BD;03A6;03A6; # (𝚽; 𝚽; 𝚽; Φ; Φ; ) MATHEMATICAL BOLD CAPITAL PHI +1D6BE;1D6BE;1D6BE;03A7;03A7; # (𝚾; 𝚾; 𝚾; Χ; Χ; ) MATHEMATICAL BOLD CAPITAL CHI +1D6BF;1D6BF;1D6BF;03A8;03A8; # (𝚿; 𝚿; 𝚿; Ψ; Ψ; ) MATHEMATICAL BOLD CAPITAL PSI +1D6C0;1D6C0;1D6C0;03A9;03A9; # (𝛀; 𝛀; 𝛀; Ω; Ω; ) MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1;1D6C1;1D6C1;2207;2207; # (𝛁; 𝛁; 𝛁; ∇; ∇; ) MATHEMATICAL BOLD NABLA +1D6C2;1D6C2;1D6C2;03B1;03B1; # (𝛂; 𝛂; 𝛂; α; α; ) MATHEMATICAL BOLD SMALL ALPHA +1D6C3;1D6C3;1D6C3;03B2;03B2; # (𝛃; 𝛃; 𝛃; β; β; ) MATHEMATICAL BOLD SMALL BETA +1D6C4;1D6C4;1D6C4;03B3;03B3; # (𝛄; 𝛄; 𝛄; γ; γ; ) MATHEMATICAL BOLD SMALL GAMMA +1D6C5;1D6C5;1D6C5;03B4;03B4; # (𝛅; 𝛅; 𝛅; δ; δ; ) MATHEMATICAL BOLD SMALL DELTA +1D6C6;1D6C6;1D6C6;03B5;03B5; # (𝛆; 𝛆; 𝛆; ε; ε; ) MATHEMATICAL BOLD SMALL EPSILON +1D6C7;1D6C7;1D6C7;03B6;03B6; # (𝛇; 𝛇; 𝛇; ζ; ζ; ) MATHEMATICAL BOLD SMALL ZETA +1D6C8;1D6C8;1D6C8;03B7;03B7; # (𝛈; 𝛈; 𝛈; η; η; ) MATHEMATICAL BOLD SMALL ETA +1D6C9;1D6C9;1D6C9;03B8;03B8; # (𝛉; 𝛉; 𝛉; θ; θ; ) MATHEMATICAL BOLD SMALL THETA +1D6CA;1D6CA;1D6CA;03B9;03B9; # (𝛊; 𝛊; 𝛊; ι; ι; ) MATHEMATICAL BOLD SMALL IOTA +1D6CB;1D6CB;1D6CB;03BA;03BA; # (𝛋; 𝛋; 𝛋; κ; κ; ) MATHEMATICAL BOLD SMALL KAPPA +1D6CC;1D6CC;1D6CC;03BB;03BB; # (𝛌; 𝛌; 𝛌; λ; λ; ) MATHEMATICAL BOLD SMALL LAMDA +1D6CD;1D6CD;1D6CD;03BC;03BC; # (𝛍; 𝛍; 𝛍; μ; μ; ) MATHEMATICAL BOLD SMALL MU +1D6CE;1D6CE;1D6CE;03BD;03BD; # (𝛎; 𝛎; 𝛎; ν; ν; ) MATHEMATICAL BOLD SMALL NU +1D6CF;1D6CF;1D6CF;03BE;03BE; # (𝛏; 𝛏; 𝛏; ξ; ξ; ) MATHEMATICAL BOLD SMALL XI +1D6D0;1D6D0;1D6D0;03BF;03BF; # (𝛐; 𝛐; 𝛐; ο; ο; ) MATHEMATICAL BOLD SMALL OMICRON +1D6D1;1D6D1;1D6D1;03C0;03C0; # (𝛑; 𝛑; 𝛑; π; π; ) MATHEMATICAL BOLD SMALL PI +1D6D2;1D6D2;1D6D2;03C1;03C1; # (𝛒; 𝛒; 𝛒; ρ; ρ; ) MATHEMATICAL BOLD SMALL RHO +1D6D3;1D6D3;1D6D3;03C2;03C2; # (𝛓; 𝛓; 𝛓; ς; ς; ) MATHEMATICAL BOLD SMALL FINAL SIGMA +1D6D4;1D6D4;1D6D4;03C3;03C3; # (𝛔; 𝛔; 𝛔; σ; σ; ) MATHEMATICAL BOLD SMALL SIGMA +1D6D5;1D6D5;1D6D5;03C4;03C4; # (𝛕; 𝛕; 𝛕; τ; τ; ) MATHEMATICAL BOLD SMALL TAU +1D6D6;1D6D6;1D6D6;03C5;03C5; # (𝛖; 𝛖; 𝛖; υ; υ; ) MATHEMATICAL BOLD SMALL UPSILON +1D6D7;1D6D7;1D6D7;03C6;03C6; # (𝛗; 𝛗; 𝛗; φ; φ; ) MATHEMATICAL BOLD SMALL PHI +1D6D8;1D6D8;1D6D8;03C7;03C7; # (𝛘; 𝛘; 𝛘; χ; χ; ) MATHEMATICAL BOLD SMALL CHI +1D6D9;1D6D9;1D6D9;03C8;03C8; # (𝛙; 𝛙; 𝛙; ψ; ψ; ) MATHEMATICAL BOLD SMALL PSI +1D6DA;1D6DA;1D6DA;03C9;03C9; # (𝛚; 𝛚; 𝛚; ω; ω; ) MATHEMATICAL BOLD SMALL OMEGA +1D6DB;1D6DB;1D6DB;2202;2202; # (𝛛; 𝛛; 𝛛; ∂; ∂; ) MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC;1D6DC;1D6DC;03B5;03B5; # (𝛜; 𝛜; 𝛜; ε; ε; ) MATHEMATICAL BOLD EPSILON SYMBOL +1D6DD;1D6DD;1D6DD;03B8;03B8; # (𝛝; 𝛝; 𝛝; θ; θ; ) MATHEMATICAL BOLD THETA SYMBOL +1D6DE;1D6DE;1D6DE;03BA;03BA; # (𝛞; 𝛞; 𝛞; κ; κ; ) MATHEMATICAL BOLD KAPPA SYMBOL +1D6DF;1D6DF;1D6DF;03C6;03C6; # (𝛟; 𝛟; 𝛟; φ; φ; ) MATHEMATICAL BOLD PHI SYMBOL +1D6E0;1D6E0;1D6E0;03C1;03C1; # (𝛠; 𝛠; 𝛠; ρ; ρ; ) MATHEMATICAL BOLD RHO SYMBOL +1D6E1;1D6E1;1D6E1;03C0;03C0; # (𝛡; 𝛡; 𝛡; π; π; ) MATHEMATICAL BOLD PI SYMBOL +1D6E2;1D6E2;1D6E2;0391;0391; # (𝛢; 𝛢; 𝛢; Α; Α; ) MATHEMATICAL ITALIC CAPITAL ALPHA +1D6E3;1D6E3;1D6E3;0392;0392; # (𝛣; 𝛣; 𝛣; Β; Β; ) MATHEMATICAL ITALIC CAPITAL BETA +1D6E4;1D6E4;1D6E4;0393;0393; # (𝛤; 𝛤; 𝛤; Γ; Γ; ) MATHEMATICAL ITALIC CAPITAL GAMMA +1D6E5;1D6E5;1D6E5;0394;0394; # (𝛥; 𝛥; 𝛥; Δ; Δ; ) MATHEMATICAL ITALIC CAPITAL DELTA +1D6E6;1D6E6;1D6E6;0395;0395; # (𝛦; 𝛦; 𝛦; Ε; Ε; ) MATHEMATICAL ITALIC CAPITAL EPSILON +1D6E7;1D6E7;1D6E7;0396;0396; # (𝛧; 𝛧; 𝛧; Ζ; Ζ; ) MATHEMATICAL ITALIC CAPITAL ZETA +1D6E8;1D6E8;1D6E8;0397;0397; # (𝛨; 𝛨; 𝛨; Η; Η; ) MATHEMATICAL ITALIC CAPITAL ETA +1D6E9;1D6E9;1D6E9;0398;0398; # (𝛩; 𝛩; 𝛩; Θ; Θ; ) MATHEMATICAL ITALIC CAPITAL THETA +1D6EA;1D6EA;1D6EA;0399;0399; # (𝛪; 𝛪; 𝛪; Ι; Ι; ) MATHEMATICAL ITALIC CAPITAL IOTA +1D6EB;1D6EB;1D6EB;039A;039A; # (𝛫; 𝛫; 𝛫; Κ; Κ; ) MATHEMATICAL ITALIC CAPITAL KAPPA +1D6EC;1D6EC;1D6EC;039B;039B; # (𝛬; 𝛬; 𝛬; Λ; Λ; ) MATHEMATICAL ITALIC CAPITAL LAMDA +1D6ED;1D6ED;1D6ED;039C;039C; # (𝛭; 𝛭; 𝛭; Μ; Μ; ) MATHEMATICAL ITALIC CAPITAL MU +1D6EE;1D6EE;1D6EE;039D;039D; # (𝛮; 𝛮; 𝛮; Ν; Ν; ) MATHEMATICAL ITALIC CAPITAL NU +1D6EF;1D6EF;1D6EF;039E;039E; # (𝛯; 𝛯; 𝛯; Ξ; Ξ; ) MATHEMATICAL ITALIC CAPITAL XI +1D6F0;1D6F0;1D6F0;039F;039F; # (𝛰; 𝛰; 𝛰; Ο; Ο; ) MATHEMATICAL ITALIC CAPITAL OMICRON +1D6F1;1D6F1;1D6F1;03A0;03A0; # (𝛱; 𝛱; 𝛱; Π; Π; ) MATHEMATICAL ITALIC CAPITAL PI +1D6F2;1D6F2;1D6F2;03A1;03A1; # (𝛲; 𝛲; 𝛲; Ρ; Ρ; ) MATHEMATICAL ITALIC CAPITAL RHO +1D6F3;1D6F3;1D6F3;0398;0398; # (𝛳; 𝛳; 𝛳; Θ; Θ; ) MATHEMATICAL ITALIC CAPITAL THETA SYMBOL +1D6F4;1D6F4;1D6F4;03A3;03A3; # (𝛴; 𝛴; 𝛴; Σ; Σ; ) MATHEMATICAL ITALIC CAPITAL SIGMA +1D6F5;1D6F5;1D6F5;03A4;03A4; # (𝛵; 𝛵; 𝛵; Τ; Τ; ) MATHEMATICAL ITALIC CAPITAL TAU +1D6F6;1D6F6;1D6F6;03A5;03A5; # (𝛶; 𝛶; 𝛶; Υ; Υ; ) MATHEMATICAL ITALIC CAPITAL UPSILON +1D6F7;1D6F7;1D6F7;03A6;03A6; # (𝛷; 𝛷; 𝛷; Φ; Φ; ) MATHEMATICAL ITALIC CAPITAL PHI +1D6F8;1D6F8;1D6F8;03A7;03A7; # (𝛸; 𝛸; 𝛸; Χ; Χ; ) MATHEMATICAL ITALIC CAPITAL CHI +1D6F9;1D6F9;1D6F9;03A8;03A8; # (𝛹; 𝛹; 𝛹; Ψ; Ψ; ) MATHEMATICAL ITALIC CAPITAL PSI +1D6FA;1D6FA;1D6FA;03A9;03A9; # (𝛺; 𝛺; 𝛺; Ω; Ω; ) MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB;1D6FB;1D6FB;2207;2207; # (𝛻; 𝛻; 𝛻; ∇; ∇; ) MATHEMATICAL ITALIC NABLA +1D6FC;1D6FC;1D6FC;03B1;03B1; # (𝛼; 𝛼; 𝛼; α; α; ) MATHEMATICAL ITALIC SMALL ALPHA +1D6FD;1D6FD;1D6FD;03B2;03B2; # (𝛽; 𝛽; 𝛽; β; β; ) MATHEMATICAL ITALIC SMALL BETA +1D6FE;1D6FE;1D6FE;03B3;03B3; # (𝛾; 𝛾; 𝛾; γ; γ; ) MATHEMATICAL ITALIC SMALL GAMMA +1D6FF;1D6FF;1D6FF;03B4;03B4; # (𝛿; 𝛿; 𝛿; δ; δ; ) MATHEMATICAL ITALIC SMALL DELTA +1D700;1D700;1D700;03B5;03B5; # (𝜀; 𝜀; 𝜀; ε; ε; ) MATHEMATICAL ITALIC SMALL EPSILON +1D701;1D701;1D701;03B6;03B6; # (𝜁; 𝜁; 𝜁; ζ; ζ; ) MATHEMATICAL ITALIC SMALL ZETA +1D702;1D702;1D702;03B7;03B7; # (𝜂; 𝜂; 𝜂; η; η; ) MATHEMATICAL ITALIC SMALL ETA +1D703;1D703;1D703;03B8;03B8; # (𝜃; 𝜃; 𝜃; θ; θ; ) MATHEMATICAL ITALIC SMALL THETA +1D704;1D704;1D704;03B9;03B9; # (𝜄; 𝜄; 𝜄; ι; ι; ) MATHEMATICAL ITALIC SMALL IOTA +1D705;1D705;1D705;03BA;03BA; # (𝜅; 𝜅; 𝜅; κ; κ; ) MATHEMATICAL ITALIC SMALL KAPPA +1D706;1D706;1D706;03BB;03BB; # (𝜆; 𝜆; 𝜆; λ; λ; ) MATHEMATICAL ITALIC SMALL LAMDA +1D707;1D707;1D707;03BC;03BC; # (𝜇; 𝜇; 𝜇; μ; μ; ) MATHEMATICAL ITALIC SMALL MU +1D708;1D708;1D708;03BD;03BD; # (𝜈; 𝜈; 𝜈; ν; ν; ) MATHEMATICAL ITALIC SMALL NU +1D709;1D709;1D709;03BE;03BE; # (𝜉; 𝜉; 𝜉; ξ; ξ; ) MATHEMATICAL ITALIC SMALL XI +1D70A;1D70A;1D70A;03BF;03BF; # (𝜊; 𝜊; 𝜊; ο; ο; ) MATHEMATICAL ITALIC SMALL OMICRON +1D70B;1D70B;1D70B;03C0;03C0; # (𝜋; 𝜋; 𝜋; π; π; ) MATHEMATICAL ITALIC SMALL PI +1D70C;1D70C;1D70C;03C1;03C1; # (𝜌; 𝜌; 𝜌; ρ; ρ; ) MATHEMATICAL ITALIC SMALL RHO +1D70D;1D70D;1D70D;03C2;03C2; # (𝜍; 𝜍; 𝜍; ς; ς; ) MATHEMATICAL ITALIC SMALL FINAL SIGMA +1D70E;1D70E;1D70E;03C3;03C3; # (𝜎; 𝜎; 𝜎; σ; σ; ) MATHEMATICAL ITALIC SMALL SIGMA +1D70F;1D70F;1D70F;03C4;03C4; # (𝜏; 𝜏; 𝜏; τ; τ; ) MATHEMATICAL ITALIC SMALL TAU +1D710;1D710;1D710;03C5;03C5; # (𝜐; 𝜐; 𝜐; υ; υ; ) MATHEMATICAL ITALIC SMALL UPSILON +1D711;1D711;1D711;03C6;03C6; # (𝜑; 𝜑; 𝜑; φ; φ; ) MATHEMATICAL ITALIC SMALL PHI +1D712;1D712;1D712;03C7;03C7; # (𝜒; 𝜒; 𝜒; χ; χ; ) MATHEMATICAL ITALIC SMALL CHI +1D713;1D713;1D713;03C8;03C8; # (𝜓; 𝜓; 𝜓; ψ; ψ; ) MATHEMATICAL ITALIC SMALL PSI +1D714;1D714;1D714;03C9;03C9; # (𝜔; 𝜔; 𝜔; ω; ω; ) MATHEMATICAL ITALIC SMALL OMEGA +1D715;1D715;1D715;2202;2202; # (𝜕; 𝜕; 𝜕; ∂; ∂; ) MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716;1D716;1D716;03B5;03B5; # (𝜖; 𝜖; 𝜖; ε; ε; ) MATHEMATICAL ITALIC EPSILON SYMBOL +1D717;1D717;1D717;03B8;03B8; # (𝜗; 𝜗; 𝜗; θ; θ; ) MATHEMATICAL ITALIC THETA SYMBOL +1D718;1D718;1D718;03BA;03BA; # (𝜘; 𝜘; 𝜘; κ; κ; ) MATHEMATICAL ITALIC KAPPA SYMBOL +1D719;1D719;1D719;03C6;03C6; # (𝜙; 𝜙; 𝜙; φ; φ; ) MATHEMATICAL ITALIC PHI SYMBOL +1D71A;1D71A;1D71A;03C1;03C1; # (𝜚; 𝜚; 𝜚; ρ; ρ; ) MATHEMATICAL ITALIC RHO SYMBOL +1D71B;1D71B;1D71B;03C0;03C0; # (𝜛; 𝜛; 𝜛; π; π; ) MATHEMATICAL ITALIC PI SYMBOL +1D71C;1D71C;1D71C;0391;0391; # (𝜜; 𝜜; 𝜜; Α; Α; ) MATHEMATICAL BOLD ITALIC CAPITAL ALPHA +1D71D;1D71D;1D71D;0392;0392; # (𝜝; 𝜝; 𝜝; Β; Β; ) MATHEMATICAL BOLD ITALIC CAPITAL BETA +1D71E;1D71E;1D71E;0393;0393; # (𝜞; 𝜞; 𝜞; Γ; Γ; ) MATHEMATICAL BOLD ITALIC CAPITAL GAMMA +1D71F;1D71F;1D71F;0394;0394; # (𝜟; 𝜟; 𝜟; Δ; Δ; ) MATHEMATICAL BOLD ITALIC CAPITAL DELTA +1D720;1D720;1D720;0395;0395; # (𝜠; 𝜠; 𝜠; Ε; Ε; ) MATHEMATICAL BOLD ITALIC CAPITAL EPSILON +1D721;1D721;1D721;0396;0396; # (𝜡; 𝜡; 𝜡; Ζ; Ζ; ) MATHEMATICAL BOLD ITALIC CAPITAL ZETA +1D722;1D722;1D722;0397;0397; # (𝜢; 𝜢; 𝜢; Η; Η; ) MATHEMATICAL BOLD ITALIC CAPITAL ETA +1D723;1D723;1D723;0398;0398; # (𝜣; 𝜣; 𝜣; Θ; Θ; ) MATHEMATICAL BOLD ITALIC CAPITAL THETA +1D724;1D724;1D724;0399;0399; # (𝜤; 𝜤; 𝜤; Ι; Ι; ) MATHEMATICAL BOLD ITALIC CAPITAL IOTA +1D725;1D725;1D725;039A;039A; # (𝜥; 𝜥; 𝜥; Κ; Κ; ) MATHEMATICAL BOLD ITALIC CAPITAL KAPPA +1D726;1D726;1D726;039B;039B; # (𝜦; 𝜦; 𝜦; Λ; Λ; ) MATHEMATICAL BOLD ITALIC CAPITAL LAMDA +1D727;1D727;1D727;039C;039C; # (𝜧; 𝜧; 𝜧; Μ; Μ; ) MATHEMATICAL BOLD ITALIC CAPITAL MU +1D728;1D728;1D728;039D;039D; # (𝜨; 𝜨; 𝜨; Ν; Ν; ) MATHEMATICAL BOLD ITALIC CAPITAL NU +1D729;1D729;1D729;039E;039E; # (𝜩; 𝜩; 𝜩; Ξ; Ξ; ) MATHEMATICAL BOLD ITALIC CAPITAL XI +1D72A;1D72A;1D72A;039F;039F; # (𝜪; 𝜪; 𝜪; Ο; Ο; ) MATHEMATICAL BOLD ITALIC CAPITAL OMICRON +1D72B;1D72B;1D72B;03A0;03A0; # (𝜫; 𝜫; 𝜫; Π; Π; ) MATHEMATICAL BOLD ITALIC CAPITAL PI +1D72C;1D72C;1D72C;03A1;03A1; # (𝜬; 𝜬; 𝜬; Ρ; Ρ; ) MATHEMATICAL BOLD ITALIC CAPITAL RHO +1D72D;1D72D;1D72D;0398;0398; # (𝜭; 𝜭; 𝜭; Θ; Θ; ) MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL +1D72E;1D72E;1D72E;03A3;03A3; # (𝜮; 𝜮; 𝜮; Σ; Σ; ) MATHEMATICAL BOLD ITALIC CAPITAL SIGMA +1D72F;1D72F;1D72F;03A4;03A4; # (𝜯; 𝜯; 𝜯; Τ; Τ; ) MATHEMATICAL BOLD ITALIC CAPITAL TAU +1D730;1D730;1D730;03A5;03A5; # (𝜰; 𝜰; 𝜰; Υ; Υ; ) MATHEMATICAL BOLD ITALIC CAPITAL UPSILON +1D731;1D731;1D731;03A6;03A6; # (𝜱; 𝜱; 𝜱; Φ; Φ; ) MATHEMATICAL BOLD ITALIC CAPITAL PHI +1D732;1D732;1D732;03A7;03A7; # (𝜲; 𝜲; 𝜲; Χ; Χ; ) MATHEMATICAL BOLD ITALIC CAPITAL CHI +1D733;1D733;1D733;03A8;03A8; # (𝜳; 𝜳; 𝜳; Ψ; Ψ; ) MATHEMATICAL BOLD ITALIC CAPITAL PSI +1D734;1D734;1D734;03A9;03A9; # (𝜴; 𝜴; 𝜴; Ω; Ω; ) MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735;1D735;1D735;2207;2207; # (𝜵; 𝜵; 𝜵; ∇; ∇; ) MATHEMATICAL BOLD ITALIC NABLA +1D736;1D736;1D736;03B1;03B1; # (𝜶; 𝜶; 𝜶; α; α; ) MATHEMATICAL BOLD ITALIC SMALL ALPHA +1D737;1D737;1D737;03B2;03B2; # (𝜷; 𝜷; 𝜷; β; β; ) MATHEMATICAL BOLD ITALIC SMALL BETA +1D738;1D738;1D738;03B3;03B3; # (𝜸; 𝜸; 𝜸; γ; γ; ) MATHEMATICAL BOLD ITALIC SMALL GAMMA +1D739;1D739;1D739;03B4;03B4; # (𝜹; 𝜹; 𝜹; δ; δ; ) MATHEMATICAL BOLD ITALIC SMALL DELTA +1D73A;1D73A;1D73A;03B5;03B5; # (𝜺; 𝜺; 𝜺; ε; ε; ) MATHEMATICAL BOLD ITALIC SMALL EPSILON +1D73B;1D73B;1D73B;03B6;03B6; # (𝜻; 𝜻; 𝜻; ζ; ζ; ) MATHEMATICAL BOLD ITALIC SMALL ZETA +1D73C;1D73C;1D73C;03B7;03B7; # (𝜼; 𝜼; 𝜼; η; η; ) MATHEMATICAL BOLD ITALIC SMALL ETA +1D73D;1D73D;1D73D;03B8;03B8; # (𝜽; 𝜽; 𝜽; θ; θ; ) MATHEMATICAL BOLD ITALIC SMALL THETA +1D73E;1D73E;1D73E;03B9;03B9; # (𝜾; 𝜾; 𝜾; ι; ι; ) MATHEMATICAL BOLD ITALIC SMALL IOTA +1D73F;1D73F;1D73F;03BA;03BA; # (𝜿; 𝜿; 𝜿; κ; κ; ) MATHEMATICAL BOLD ITALIC SMALL KAPPA +1D740;1D740;1D740;03BB;03BB; # (𝝀; 𝝀; 𝝀; λ; λ; ) MATHEMATICAL BOLD ITALIC SMALL LAMDA +1D741;1D741;1D741;03BC;03BC; # (𝝁; 𝝁; 𝝁; μ; μ; ) MATHEMATICAL BOLD ITALIC SMALL MU +1D742;1D742;1D742;03BD;03BD; # (𝝂; 𝝂; 𝝂; ν; ν; ) MATHEMATICAL BOLD ITALIC SMALL NU +1D743;1D743;1D743;03BE;03BE; # (𝝃; 𝝃; 𝝃; ξ; ξ; ) MATHEMATICAL BOLD ITALIC SMALL XI +1D744;1D744;1D744;03BF;03BF; # (𝝄; 𝝄; 𝝄; ο; ο; ) MATHEMATICAL BOLD ITALIC SMALL OMICRON +1D745;1D745;1D745;03C0;03C0; # (𝝅; 𝝅; 𝝅; π; π; ) MATHEMATICAL BOLD ITALIC SMALL PI +1D746;1D746;1D746;03C1;03C1; # (𝝆; 𝝆; 𝝆; ρ; ρ; ) MATHEMATICAL BOLD ITALIC SMALL RHO +1D747;1D747;1D747;03C2;03C2; # (𝝇; 𝝇; 𝝇; ς; ς; ) MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA +1D748;1D748;1D748;03C3;03C3; # (𝝈; 𝝈; 𝝈; σ; σ; ) MATHEMATICAL BOLD ITALIC SMALL SIGMA +1D749;1D749;1D749;03C4;03C4; # (𝝉; 𝝉; 𝝉; τ; τ; ) MATHEMATICAL BOLD ITALIC SMALL TAU +1D74A;1D74A;1D74A;03C5;03C5; # (𝝊; 𝝊; 𝝊; υ; υ; ) MATHEMATICAL BOLD ITALIC SMALL UPSILON +1D74B;1D74B;1D74B;03C6;03C6; # (𝝋; 𝝋; 𝝋; φ; φ; ) MATHEMATICAL BOLD ITALIC SMALL PHI +1D74C;1D74C;1D74C;03C7;03C7; # (𝝌; 𝝌; 𝝌; χ; χ; ) MATHEMATICAL BOLD ITALIC SMALL CHI +1D74D;1D74D;1D74D;03C8;03C8; # (𝝍; 𝝍; 𝝍; ψ; ψ; ) MATHEMATICAL BOLD ITALIC SMALL PSI +1D74E;1D74E;1D74E;03C9;03C9; # (𝝎; 𝝎; 𝝎; ω; ω; ) MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F;1D74F;1D74F;2202;2202; # (𝝏; 𝝏; 𝝏; ∂; ∂; ) MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750;1D750;1D750;03B5;03B5; # (𝝐; 𝝐; 𝝐; ε; ε; ) MATHEMATICAL BOLD ITALIC EPSILON SYMBOL +1D751;1D751;1D751;03B8;03B8; # (𝝑; 𝝑; 𝝑; θ; θ; ) MATHEMATICAL BOLD ITALIC THETA SYMBOL +1D752;1D752;1D752;03BA;03BA; # (𝝒; 𝝒; 𝝒; κ; κ; ) MATHEMATICAL BOLD ITALIC KAPPA SYMBOL +1D753;1D753;1D753;03C6;03C6; # (𝝓; 𝝓; 𝝓; φ; φ; ) MATHEMATICAL BOLD ITALIC PHI SYMBOL +1D754;1D754;1D754;03C1;03C1; # (𝝔; 𝝔; 𝝔; ρ; ρ; ) MATHEMATICAL BOLD ITALIC RHO SYMBOL +1D755;1D755;1D755;03C0;03C0; # (𝝕; 𝝕; 𝝕; π; π; ) MATHEMATICAL BOLD ITALIC PI SYMBOL +1D756;1D756;1D756;0391;0391; # (𝝖; 𝝖; 𝝖; Α; Α; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA +1D757;1D757;1D757;0392;0392; # (𝝗; 𝝗; 𝝗; Β; Β; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA +1D758;1D758;1D758;0393;0393; # (𝝘; 𝝘; 𝝘; Γ; Γ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA +1D759;1D759;1D759;0394;0394; # (𝝙; 𝝙; 𝝙; Δ; Δ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA +1D75A;1D75A;1D75A;0395;0395; # (𝝚; 𝝚; 𝝚; Ε; Ε; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON +1D75B;1D75B;1D75B;0396;0396; # (𝝛; 𝝛; 𝝛; Ζ; Ζ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA +1D75C;1D75C;1D75C;0397;0397; # (𝝜; 𝝜; 𝝜; Η; Η; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA +1D75D;1D75D;1D75D;0398;0398; # (𝝝; 𝝝; 𝝝; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA +1D75E;1D75E;1D75E;0399;0399; # (𝝞; 𝝞; 𝝞; Ι; Ι; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA +1D75F;1D75F;1D75F;039A;039A; # (𝝟; 𝝟; 𝝟; Κ; Κ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA +1D760;1D760;1D760;039B;039B; # (𝝠; 𝝠; 𝝠; Λ; Λ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA +1D761;1D761;1D761;039C;039C; # (𝝡; 𝝡; 𝝡; Μ; Μ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL MU +1D762;1D762;1D762;039D;039D; # (𝝢; 𝝢; 𝝢; Ν; Ν; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL NU +1D763;1D763;1D763;039E;039E; # (𝝣; 𝝣; 𝝣; Ξ; Ξ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL XI +1D764;1D764;1D764;039F;039F; # (𝝤; 𝝤; 𝝤; Ο; Ο; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON +1D765;1D765;1D765;03A0;03A0; # (𝝥; 𝝥; 𝝥; Π; Π; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PI +1D766;1D766;1D766;03A1;03A1; # (𝝦; 𝝦; 𝝦; Ρ; Ρ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO +1D767;1D767;1D767;0398;0398; # (𝝧; 𝝧; 𝝧; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL +1D768;1D768;1D768;03A3;03A3; # (𝝨; 𝝨; 𝝨; Σ; Σ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA +1D769;1D769;1D769;03A4;03A4; # (𝝩; 𝝩; 𝝩; Τ; Τ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU +1D76A;1D76A;1D76A;03A5;03A5; # (𝝪; 𝝪; 𝝪; Υ; Υ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON +1D76B;1D76B;1D76B;03A6;03A6; # (𝝫; 𝝫; 𝝫; Φ; Φ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI +1D76C;1D76C;1D76C;03A7;03A7; # (𝝬; 𝝬; 𝝬; Χ; Χ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI +1D76D;1D76D;1D76D;03A8;03A8; # (𝝭; 𝝭; 𝝭; Ψ; Ψ; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI +1D76E;1D76E;1D76E;03A9;03A9; # (𝝮; 𝝮; 𝝮; Ω; Ω; ) MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F;1D76F;1D76F;2207;2207; # (𝝯; 𝝯; 𝝯; ∇; ∇; ) MATHEMATICAL SANS-SERIF BOLD NABLA +1D770;1D770;1D770;03B1;03B1; # (𝝰; 𝝰; 𝝰; α; α; ) MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA +1D771;1D771;1D771;03B2;03B2; # (𝝱; 𝝱; 𝝱; β; β; ) MATHEMATICAL SANS-SERIF BOLD SMALL BETA +1D772;1D772;1D772;03B3;03B3; # (𝝲; 𝝲; 𝝲; γ; γ; ) MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA +1D773;1D773;1D773;03B4;03B4; # (𝝳; 𝝳; 𝝳; δ; δ; ) MATHEMATICAL SANS-SERIF BOLD SMALL DELTA +1D774;1D774;1D774;03B5;03B5; # (𝝴; 𝝴; 𝝴; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON +1D775;1D775;1D775;03B6;03B6; # (𝝵; 𝝵; 𝝵; ζ; ζ; ) MATHEMATICAL SANS-SERIF BOLD SMALL ZETA +1D776;1D776;1D776;03B7;03B7; # (𝝶; 𝝶; 𝝶; η; η; ) MATHEMATICAL SANS-SERIF BOLD SMALL ETA +1D777;1D777;1D777;03B8;03B8; # (𝝷; 𝝷; 𝝷; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD SMALL THETA +1D778;1D778;1D778;03B9;03B9; # (𝝸; 𝝸; 𝝸; ι; ι; ) MATHEMATICAL SANS-SERIF BOLD SMALL IOTA +1D779;1D779;1D779;03BA;03BA; # (𝝹; 𝝹; 𝝹; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA +1D77A;1D77A;1D77A;03BB;03BB; # (𝝺; 𝝺; 𝝺; λ; λ; ) MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA +1D77B;1D77B;1D77B;03BC;03BC; # (𝝻; 𝝻; 𝝻; μ; μ; ) MATHEMATICAL SANS-SERIF BOLD SMALL MU +1D77C;1D77C;1D77C;03BD;03BD; # (𝝼; 𝝼; 𝝼; ν; ν; ) MATHEMATICAL SANS-SERIF BOLD SMALL NU +1D77D;1D77D;1D77D;03BE;03BE; # (𝝽; 𝝽; 𝝽; ξ; ξ; ) MATHEMATICAL SANS-SERIF BOLD SMALL XI +1D77E;1D77E;1D77E;03BF;03BF; # (𝝾; 𝝾; 𝝾; ο; ο; ) MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON +1D77F;1D77F;1D77F;03C0;03C0; # (𝝿; 𝝿; 𝝿; π; π; ) MATHEMATICAL SANS-SERIF BOLD SMALL PI +1D780;1D780;1D780;03C1;03C1; # (𝞀; 𝞀; 𝞀; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD SMALL RHO +1D781;1D781;1D781;03C2;03C2; # (𝞁; 𝞁; 𝞁; ς; ς; ) MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA +1D782;1D782;1D782;03C3;03C3; # (𝞂; 𝞂; 𝞂; σ; σ; ) MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA +1D783;1D783;1D783;03C4;03C4; # (𝞃; 𝞃; 𝞃; τ; τ; ) MATHEMATICAL SANS-SERIF BOLD SMALL TAU +1D784;1D784;1D784;03C5;03C5; # (𝞄; 𝞄; 𝞄; υ; υ; ) MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON +1D785;1D785;1D785;03C6;03C6; # (𝞅; 𝞅; 𝞅; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD SMALL PHI +1D786;1D786;1D786;03C7;03C7; # (𝞆; 𝞆; 𝞆; χ; χ; ) MATHEMATICAL SANS-SERIF BOLD SMALL CHI +1D787;1D787;1D787;03C8;03C8; # (𝞇; 𝞇; 𝞇; ψ; ψ; ) MATHEMATICAL SANS-SERIF BOLD SMALL PSI +1D788;1D788;1D788;03C9;03C9; # (𝞈; 𝞈; 𝞈; ω; ω; ) MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789;1D789;1D789;2202;2202; # (𝞉; 𝞉; 𝞉; ∂; ∂; ) MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A;1D78A;1D78A;03B5;03B5; # (𝞊; 𝞊; 𝞊; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL +1D78B;1D78B;1D78B;03B8;03B8; # (𝞋; 𝞋; 𝞋; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL +1D78C;1D78C;1D78C;03BA;03BA; # (𝞌; 𝞌; 𝞌; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL +1D78D;1D78D;1D78D;03C6;03C6; # (𝞍; 𝞍; 𝞍; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL +1D78E;1D78E;1D78E;03C1;03C1; # (𝞎; 𝞎; 𝞎; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL +1D78F;1D78F;1D78F;03C0;03C0; # (𝞏; 𝞏; 𝞏; π; π; ) MATHEMATICAL SANS-SERIF BOLD PI SYMBOL +1D790;1D790;1D790;0391;0391; # (𝞐; 𝞐; 𝞐; Α; Α; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA +1D791;1D791;1D791;0392;0392; # (𝞑; 𝞑; 𝞑; Β; Β; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA +1D792;1D792;1D792;0393;0393; # (𝞒; 𝞒; 𝞒; Γ; Γ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA +1D793;1D793;1D793;0394;0394; # (𝞓; 𝞓; 𝞓; Δ; Δ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA +1D794;1D794;1D794;0395;0395; # (𝞔; 𝞔; 𝞔; Ε; Ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON +1D795;1D795;1D795;0396;0396; # (𝞕; 𝞕; 𝞕; Ζ; Ζ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA +1D796;1D796;1D796;0397;0397; # (𝞖; 𝞖; 𝞖; Η; Η; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA +1D797;1D797;1D797;0398;0398; # (𝞗; 𝞗; 𝞗; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA +1D798;1D798;1D798;0399;0399; # (𝞘; 𝞘; 𝞘; Ι; Ι; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA +1D799;1D799;1D799;039A;039A; # (𝞙; 𝞙; 𝞙; Κ; Κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA +1D79A;1D79A;1D79A;039B;039B; # (𝞚; 𝞚; 𝞚; Λ; Λ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA +1D79B;1D79B;1D79B;039C;039C; # (𝞛; 𝞛; 𝞛; Μ; Μ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU +1D79C;1D79C;1D79C;039D;039D; # (𝞜; 𝞜; 𝞜; Ν; Ν; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU +1D79D;1D79D;1D79D;039E;039E; # (𝞝; 𝞝; 𝞝; Ξ; Ξ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI +1D79E;1D79E;1D79E;039F;039F; # (𝞞; 𝞞; 𝞞; Ο; Ο; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON +1D79F;1D79F;1D79F;03A0;03A0; # (𝞟; 𝞟; 𝞟; Π; Π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI +1D7A0;1D7A0;1D7A0;03A1;03A1; # (𝞠; 𝞠; 𝞠; Ρ; Ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO +1D7A1;1D7A1;1D7A1;0398;0398; # (𝞡; 𝞡; 𝞡; Θ; Θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL +1D7A2;1D7A2;1D7A2;03A3;03A3; # (𝞢; 𝞢; 𝞢; Σ; Σ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA +1D7A3;1D7A3;1D7A3;03A4;03A4; # (𝞣; 𝞣; 𝞣; Τ; Τ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU +1D7A4;1D7A4;1D7A4;03A5;03A5; # (𝞤; 𝞤; 𝞤; Υ; Υ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON +1D7A5;1D7A5;1D7A5;03A6;03A6; # (𝞥; 𝞥; 𝞥; Φ; Φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI +1D7A6;1D7A6;1D7A6;03A7;03A7; # (𝞦; 𝞦; 𝞦; Χ; Χ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI +1D7A7;1D7A7;1D7A7;03A8;03A8; # (𝞧; 𝞧; 𝞧; Ψ; Ψ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI +1D7A8;1D7A8;1D7A8;03A9;03A9; # (𝞨; 𝞨; 𝞨; Ω; Ω; ) MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9;1D7A9;1D7A9;2207;2207; # (𝞩; 𝞩; 𝞩; ∇; ∇; ) MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA;1D7AA;1D7AA;03B1;03B1; # (𝞪; 𝞪; 𝞪; α; α; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA +1D7AB;1D7AB;1D7AB;03B2;03B2; # (𝞫; 𝞫; 𝞫; β; β; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA +1D7AC;1D7AC;1D7AC;03B3;03B3; # (𝞬; 𝞬; 𝞬; γ; γ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA +1D7AD;1D7AD;1D7AD;03B4;03B4; # (𝞭; 𝞭; 𝞭; δ; δ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA +1D7AE;1D7AE;1D7AE;03B5;03B5; # (𝞮; 𝞮; 𝞮; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON +1D7AF;1D7AF;1D7AF;03B6;03B6; # (𝞯; 𝞯; 𝞯; ζ; ζ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA +1D7B0;1D7B0;1D7B0;03B7;03B7; # (𝞰; 𝞰; 𝞰; η; η; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA +1D7B1;1D7B1;1D7B1;03B8;03B8; # (𝞱; 𝞱; 𝞱; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA +1D7B2;1D7B2;1D7B2;03B9;03B9; # (𝞲; 𝞲; 𝞲; ι; ι; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA +1D7B3;1D7B3;1D7B3;03BA;03BA; # (𝞳; 𝞳; 𝞳; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA +1D7B4;1D7B4;1D7B4;03BB;03BB; # (𝞴; 𝞴; 𝞴; λ; λ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA +1D7B5;1D7B5;1D7B5;03BC;03BC; # (𝞵; 𝞵; 𝞵; μ; μ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU +1D7B6;1D7B6;1D7B6;03BD;03BD; # (𝞶; 𝞶; 𝞶; ν; ν; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU +1D7B7;1D7B7;1D7B7;03BE;03BE; # (𝞷; 𝞷; 𝞷; ξ; ξ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI +1D7B8;1D7B8;1D7B8;03BF;03BF; # (𝞸; 𝞸; 𝞸; ο; ο; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON +1D7B9;1D7B9;1D7B9;03C0;03C0; # (𝞹; 𝞹; 𝞹; π; π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI +1D7BA;1D7BA;1D7BA;03C1;03C1; # (𝞺; 𝞺; 𝞺; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO +1D7BB;1D7BB;1D7BB;03C2;03C2; # (𝞻; 𝞻; 𝞻; ς; ς; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA +1D7BC;1D7BC;1D7BC;03C3;03C3; # (𝞼; 𝞼; 𝞼; σ; σ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA +1D7BD;1D7BD;1D7BD;03C4;03C4; # (𝞽; 𝞽; 𝞽; τ; τ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU +1D7BE;1D7BE;1D7BE;03C5;03C5; # (𝞾; 𝞾; 𝞾; υ; υ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON +1D7BF;1D7BF;1D7BF;03C6;03C6; # (𝞿; 𝞿; 𝞿; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI +1D7C0;1D7C0;1D7C0;03C7;03C7; # (𝟀; 𝟀; 𝟀; χ; χ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI +1D7C1;1D7C1;1D7C1;03C8;03C8; # (𝟁; 𝟁; 𝟁; ψ; ψ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI +1D7C2;1D7C2;1D7C2;03C9;03C9; # (𝟂; 𝟂; 𝟂; ω; ω; ) MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3;1D7C3;1D7C3;2202;2202; # (𝟃; 𝟃; 𝟃; ∂; ∂; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4;1D7C4;1D7C4;03B5;03B5; # (𝟄; 𝟄; 𝟄; ε; ε; ) MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL +1D7C5;1D7C5;1D7C5;03B8;03B8; # (𝟅; 𝟅; 𝟅; θ; θ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL +1D7C6;1D7C6;1D7C6;03BA;03BA; # (𝟆; 𝟆; 𝟆; κ; κ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL +1D7C7;1D7C7;1D7C7;03C6;03C6; # (𝟇; 𝟇; 𝟇; φ; φ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL +1D7C8;1D7C8;1D7C8;03C1;03C1; # (𝟈; 𝟈; 𝟈; ρ; ρ; ) MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL +1D7C9;1D7C9;1D7C9;03C0;03C0; # (𝟉; 𝟉; 𝟉; π; π; ) MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL +1D7CA;1D7CA;1D7CA;03DC;03DC; # (𝟊; 𝟊; 𝟊; Ϝ; Ϝ; ) MATHEMATICAL BOLD CAPITAL DIGAMMA +1D7CB;1D7CB;1D7CB;03DD;03DD; # (𝟋; 𝟋; 𝟋; ϝ; ϝ; ) MATHEMATICAL BOLD SMALL DIGAMMA +1D7CE;1D7CE;1D7CE;0030;0030; # (𝟎; 𝟎; 𝟎; 0; 0; ) MATHEMATICAL BOLD DIGIT ZERO +1D7CF;1D7CF;1D7CF;0031;0031; # (𝟏; 𝟏; 𝟏; 1; 1; ) MATHEMATICAL BOLD DIGIT ONE +1D7D0;1D7D0;1D7D0;0032;0032; # (𝟐; 𝟐; 𝟐; 2; 2; ) MATHEMATICAL BOLD DIGIT TWO +1D7D1;1D7D1;1D7D1;0033;0033; # (𝟑; 𝟑; 𝟑; 3; 3; ) MATHEMATICAL BOLD DIGIT THREE +1D7D2;1D7D2;1D7D2;0034;0034; # (𝟒; 𝟒; 𝟒; 4; 4; ) MATHEMATICAL BOLD DIGIT FOUR +1D7D3;1D7D3;1D7D3;0035;0035; # (𝟓; 𝟓; 𝟓; 5; 5; ) MATHEMATICAL BOLD DIGIT FIVE +1D7D4;1D7D4;1D7D4;0036;0036; # (𝟔; 𝟔; 𝟔; 6; 6; ) MATHEMATICAL BOLD DIGIT SIX +1D7D5;1D7D5;1D7D5;0037;0037; # (𝟕; 𝟕; 𝟕; 7; 7; ) MATHEMATICAL BOLD DIGIT SEVEN +1D7D6;1D7D6;1D7D6;0038;0038; # (𝟖; 𝟖; 𝟖; 8; 8; ) MATHEMATICAL BOLD DIGIT EIGHT +1D7D7;1D7D7;1D7D7;0039;0039; # (𝟗; 𝟗; 𝟗; 9; 9; ) MATHEMATICAL BOLD DIGIT NINE +1D7D8;1D7D8;1D7D8;0030;0030; # (𝟘; 𝟘; 𝟘; 0; 0; ) MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO +1D7D9;1D7D9;1D7D9;0031;0031; # (𝟙; 𝟙; 𝟙; 1; 1; ) MATHEMATICAL DOUBLE-STRUCK DIGIT ONE +1D7DA;1D7DA;1D7DA;0032;0032; # (𝟚; 𝟚; 𝟚; 2; 2; ) MATHEMATICAL DOUBLE-STRUCK DIGIT TWO +1D7DB;1D7DB;1D7DB;0033;0033; # (𝟛; 𝟛; 𝟛; 3; 3; ) MATHEMATICAL DOUBLE-STRUCK DIGIT THREE +1D7DC;1D7DC;1D7DC;0034;0034; # (𝟜; 𝟜; 𝟜; 4; 4; ) MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR +1D7DD;1D7DD;1D7DD;0035;0035; # (𝟝; 𝟝; 𝟝; 5; 5; ) MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE +1D7DE;1D7DE;1D7DE;0036;0036; # (𝟞; 𝟞; 𝟞; 6; 6; ) MATHEMATICAL DOUBLE-STRUCK DIGIT SIX +1D7DF;1D7DF;1D7DF;0037;0037; # (𝟟; 𝟟; 𝟟; 7; 7; ) MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN +1D7E0;1D7E0;1D7E0;0038;0038; # (𝟠; 𝟠; 𝟠; 8; 8; ) MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT +1D7E1;1D7E1;1D7E1;0039;0039; # (𝟡; 𝟡; 𝟡; 9; 9; ) MATHEMATICAL DOUBLE-STRUCK DIGIT NINE +1D7E2;1D7E2;1D7E2;0030;0030; # (𝟢; 𝟢; 𝟢; 0; 0; ) MATHEMATICAL SANS-SERIF DIGIT ZERO +1D7E3;1D7E3;1D7E3;0031;0031; # (𝟣; 𝟣; 𝟣; 1; 1; ) MATHEMATICAL SANS-SERIF DIGIT ONE +1D7E4;1D7E4;1D7E4;0032;0032; # (𝟤; 𝟤; 𝟤; 2; 2; ) MATHEMATICAL SANS-SERIF DIGIT TWO +1D7E5;1D7E5;1D7E5;0033;0033; # (𝟥; 𝟥; 𝟥; 3; 3; ) MATHEMATICAL SANS-SERIF DIGIT THREE +1D7E6;1D7E6;1D7E6;0034;0034; # (𝟦; 𝟦; 𝟦; 4; 4; ) MATHEMATICAL SANS-SERIF DIGIT FOUR +1D7E7;1D7E7;1D7E7;0035;0035; # (𝟧; 𝟧; 𝟧; 5; 5; ) MATHEMATICAL SANS-SERIF DIGIT FIVE +1D7E8;1D7E8;1D7E8;0036;0036; # (𝟨; 𝟨; 𝟨; 6; 6; ) MATHEMATICAL SANS-SERIF DIGIT SIX +1D7E9;1D7E9;1D7E9;0037;0037; # (𝟩; 𝟩; 𝟩; 7; 7; ) MATHEMATICAL SANS-SERIF DIGIT SEVEN +1D7EA;1D7EA;1D7EA;0038;0038; # (𝟪; 𝟪; 𝟪; 8; 8; ) MATHEMATICAL SANS-SERIF DIGIT EIGHT +1D7EB;1D7EB;1D7EB;0039;0039; # (𝟫; 𝟫; 𝟫; 9; 9; ) MATHEMATICAL SANS-SERIF DIGIT NINE +1D7EC;1D7EC;1D7EC;0030;0030; # (𝟬; 𝟬; 𝟬; 0; 0; ) MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO +1D7ED;1D7ED;1D7ED;0031;0031; # (𝟭; 𝟭; 𝟭; 1; 1; ) MATHEMATICAL SANS-SERIF BOLD DIGIT ONE +1D7EE;1D7EE;1D7EE;0032;0032; # (𝟮; 𝟮; 𝟮; 2; 2; ) MATHEMATICAL SANS-SERIF BOLD DIGIT TWO +1D7EF;1D7EF;1D7EF;0033;0033; # (𝟯; 𝟯; 𝟯; 3; 3; ) MATHEMATICAL SANS-SERIF BOLD DIGIT THREE +1D7F0;1D7F0;1D7F0;0034;0034; # (𝟰; 𝟰; 𝟰; 4; 4; ) MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR +1D7F1;1D7F1;1D7F1;0035;0035; # (𝟱; 𝟱; 𝟱; 5; 5; ) MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE +1D7F2;1D7F2;1D7F2;0036;0036; # (𝟲; 𝟲; 𝟲; 6; 6; ) MATHEMATICAL SANS-SERIF BOLD DIGIT SIX +1D7F3;1D7F3;1D7F3;0037;0037; # (𝟳; 𝟳; 𝟳; 7; 7; ) MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN +1D7F4;1D7F4;1D7F4;0038;0038; # (𝟴; 𝟴; 𝟴; 8; 8; ) MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT +1D7F5;1D7F5;1D7F5;0039;0039; # (𝟵; 𝟵; 𝟵; 9; 9; ) MATHEMATICAL SANS-SERIF BOLD DIGIT NINE +1D7F6;1D7F6;1D7F6;0030;0030; # (𝟶; 𝟶; 𝟶; 0; 0; ) MATHEMATICAL MONOSPACE DIGIT ZERO +1D7F7;1D7F7;1D7F7;0031;0031; # (𝟷; 𝟷; 𝟷; 1; 1; ) MATHEMATICAL MONOSPACE DIGIT ONE +1D7F8;1D7F8;1D7F8;0032;0032; # (𝟸; 𝟸; 𝟸; 2; 2; ) MATHEMATICAL MONOSPACE DIGIT TWO +1D7F9;1D7F9;1D7F9;0033;0033; # (𝟹; 𝟹; 𝟹; 3; 3; ) MATHEMATICAL MONOSPACE DIGIT THREE +1D7FA;1D7FA;1D7FA;0034;0034; # (𝟺; 𝟺; 𝟺; 4; 4; ) MATHEMATICAL MONOSPACE DIGIT FOUR +1D7FB;1D7FB;1D7FB;0035;0035; # (𝟻; 𝟻; 𝟻; 5; 5; ) MATHEMATICAL MONOSPACE DIGIT FIVE +1D7FC;1D7FC;1D7FC;0036;0036; # (𝟼; 𝟼; 𝟼; 6; 6; ) MATHEMATICAL MONOSPACE DIGIT SIX +1D7FD;1D7FD;1D7FD;0037;0037; # (𝟽; 𝟽; 𝟽; 7; 7; ) MATHEMATICAL MONOSPACE DIGIT SEVEN +1D7FE;1D7FE;1D7FE;0038;0038; # (𝟾; 𝟾; 𝟾; 8; 8; ) MATHEMATICAL MONOSPACE DIGIT EIGHT +1D7FF;1D7FF;1D7FF;0039;0039; # (𝟿; 𝟿; 𝟿; 9; 9; ) MATHEMATICAL MONOSPACE DIGIT NINE +1EE00;1EE00;1EE00;0627;0627; # (𞸀; 𞸀; 𞸀; ا; ا; ) ARABIC MATHEMATICAL ALEF +1EE01;1EE01;1EE01;0628;0628; # (𞸁; 𞸁; 𞸁; ب; ب; ) ARABIC MATHEMATICAL BEH +1EE02;1EE02;1EE02;062C;062C; # (𞸂; 𞸂; 𞸂; ج; ج; ) ARABIC MATHEMATICAL JEEM +1EE03;1EE03;1EE03;062F;062F; # (𞸃; 𞸃; 𞸃; د; د; ) ARABIC MATHEMATICAL DAL +1EE05;1EE05;1EE05;0648;0648; # (𞸅; 𞸅; 𞸅; و; و; ) ARABIC MATHEMATICAL WAW +1EE06;1EE06;1EE06;0632;0632; # (𞸆; 𞸆; 𞸆; ز; ز; ) ARABIC MATHEMATICAL ZAIN +1EE07;1EE07;1EE07;062D;062D; # (𞸇; 𞸇; 𞸇; ح; ح; ) ARABIC MATHEMATICAL HAH +1EE08;1EE08;1EE08;0637;0637; # (𞸈; 𞸈; 𞸈; ط; ط; ) ARABIC MATHEMATICAL TAH +1EE09;1EE09;1EE09;064A;064A; # (𞸉; 𞸉; 𞸉; ي; ي; ) ARABIC MATHEMATICAL YEH +1EE0A;1EE0A;1EE0A;0643;0643; # (𞸊; 𞸊; 𞸊; ك; ك; ) ARABIC MATHEMATICAL KAF +1EE0B;1EE0B;1EE0B;0644;0644; # (𞸋; 𞸋; 𞸋; ل; ل; ) ARABIC MATHEMATICAL LAM +1EE0C;1EE0C;1EE0C;0645;0645; # (𞸌; 𞸌; 𞸌; م; م; ) ARABIC MATHEMATICAL MEEM +1EE0D;1EE0D;1EE0D;0646;0646; # (𞸍; 𞸍; 𞸍; ن; ن; ) ARABIC MATHEMATICAL NOON +1EE0E;1EE0E;1EE0E;0633;0633; # (𞸎; 𞸎; 𞸎; س; س; ) ARABIC MATHEMATICAL SEEN +1EE0F;1EE0F;1EE0F;0639;0639; # (𞸏; 𞸏; 𞸏; ع; ع; ) ARABIC MATHEMATICAL AIN +1EE10;1EE10;1EE10;0641;0641; # (𞸐; 𞸐; 𞸐; ف; ف; ) ARABIC MATHEMATICAL FEH +1EE11;1EE11;1EE11;0635;0635; # (𞸑; 𞸑; 𞸑; ص; ص; ) ARABIC MATHEMATICAL SAD +1EE12;1EE12;1EE12;0642;0642; # (𞸒; 𞸒; 𞸒; ق; ق; ) ARABIC MATHEMATICAL QAF +1EE13;1EE13;1EE13;0631;0631; # (𞸓; 𞸓; 𞸓; ر; ر; ) ARABIC MATHEMATICAL REH +1EE14;1EE14;1EE14;0634;0634; # (𞸔; 𞸔; 𞸔; ش; ش; ) ARABIC MATHEMATICAL SHEEN +1EE15;1EE15;1EE15;062A;062A; # (𞸕; 𞸕; 𞸕; ت; ت; ) ARABIC MATHEMATICAL TEH +1EE16;1EE16;1EE16;062B;062B; # (𞸖; 𞸖; 𞸖; ث; ث; ) ARABIC MATHEMATICAL THEH +1EE17;1EE17;1EE17;062E;062E; # (𞸗; 𞸗; 𞸗; خ; خ; ) ARABIC MATHEMATICAL KHAH +1EE18;1EE18;1EE18;0630;0630; # (𞸘; 𞸘; 𞸘; ذ; ذ; ) ARABIC MATHEMATICAL THAL +1EE19;1EE19;1EE19;0636;0636; # (𞸙; 𞸙; 𞸙; ض; ض; ) ARABIC MATHEMATICAL DAD +1EE1A;1EE1A;1EE1A;0638;0638; # (𞸚; 𞸚; 𞸚; ظ; ظ; ) ARABIC MATHEMATICAL ZAH +1EE1B;1EE1B;1EE1B;063A;063A; # (𞸛; 𞸛; 𞸛; غ; غ; ) ARABIC MATHEMATICAL GHAIN +1EE1C;1EE1C;1EE1C;066E;066E; # (𞸜; 𞸜; 𞸜; ٮ; ٮ; ) ARABIC MATHEMATICAL DOTLESS BEH +1EE1D;1EE1D;1EE1D;06BA;06BA; # (𞸝; 𞸝; 𞸝; ں; ں; ) ARABIC MATHEMATICAL DOTLESS NOON +1EE1E;1EE1E;1EE1E;06A1;06A1; # (𞸞; 𞸞; 𞸞; ڡ; ڡ; ) ARABIC MATHEMATICAL DOTLESS FEH +1EE1F;1EE1F;1EE1F;066F;066F; # (𞸟; 𞸟; 𞸟; ٯ; ٯ; ) ARABIC MATHEMATICAL DOTLESS QAF +1EE21;1EE21;1EE21;0628;0628; # (𞸡; 𞸡; 𞸡; ب; ب; ) ARABIC MATHEMATICAL INITIAL BEH +1EE22;1EE22;1EE22;062C;062C; # (𞸢; 𞸢; 𞸢; ج; ج; ) ARABIC MATHEMATICAL INITIAL JEEM +1EE24;1EE24;1EE24;0647;0647; # (𞸤; 𞸤; 𞸤; ه; ه; ) ARABIC MATHEMATICAL INITIAL HEH +1EE27;1EE27;1EE27;062D;062D; # (𞸧; 𞸧; 𞸧; ح; ح; ) ARABIC MATHEMATICAL INITIAL HAH +1EE29;1EE29;1EE29;064A;064A; # (𞸩; 𞸩; 𞸩; ي; ي; ) ARABIC MATHEMATICAL INITIAL YEH +1EE2A;1EE2A;1EE2A;0643;0643; # (𞸪; 𞸪; 𞸪; ك; ك; ) ARABIC MATHEMATICAL INITIAL KAF +1EE2B;1EE2B;1EE2B;0644;0644; # (𞸫; 𞸫; 𞸫; ل; ل; ) ARABIC MATHEMATICAL INITIAL LAM +1EE2C;1EE2C;1EE2C;0645;0645; # (𞸬; 𞸬; 𞸬; م; م; ) ARABIC MATHEMATICAL INITIAL MEEM +1EE2D;1EE2D;1EE2D;0646;0646; # (𞸭; 𞸭; 𞸭; ن; ن; ) ARABIC MATHEMATICAL INITIAL NOON +1EE2E;1EE2E;1EE2E;0633;0633; # (𞸮; 𞸮; 𞸮; س; س; ) ARABIC MATHEMATICAL INITIAL SEEN +1EE2F;1EE2F;1EE2F;0639;0639; # (𞸯; 𞸯; 𞸯; ع; ع; ) ARABIC MATHEMATICAL INITIAL AIN +1EE30;1EE30;1EE30;0641;0641; # (𞸰; 𞸰; 𞸰; ف; ف; ) ARABIC MATHEMATICAL INITIAL FEH +1EE31;1EE31;1EE31;0635;0635; # (𞸱; 𞸱; 𞸱; ص; ص; ) ARABIC MATHEMATICAL INITIAL SAD +1EE32;1EE32;1EE32;0642;0642; # (𞸲; 𞸲; 𞸲; ق; ق; ) ARABIC MATHEMATICAL INITIAL QAF +1EE34;1EE34;1EE34;0634;0634; # (𞸴; 𞸴; 𞸴; ش; ش; ) ARABIC MATHEMATICAL INITIAL SHEEN +1EE35;1EE35;1EE35;062A;062A; # (𞸵; 𞸵; 𞸵; ت; ت; ) ARABIC MATHEMATICAL INITIAL TEH +1EE36;1EE36;1EE36;062B;062B; # (𞸶; 𞸶; 𞸶; ث; ث; ) ARABIC MATHEMATICAL INITIAL THEH +1EE37;1EE37;1EE37;062E;062E; # (𞸷; 𞸷; 𞸷; خ; خ; ) ARABIC MATHEMATICAL INITIAL KHAH +1EE39;1EE39;1EE39;0636;0636; # (𞸹; 𞸹; 𞸹; ض; ض; ) ARABIC MATHEMATICAL INITIAL DAD +1EE3B;1EE3B;1EE3B;063A;063A; # (𞸻; 𞸻; 𞸻; غ; غ; ) ARABIC MATHEMATICAL INITIAL GHAIN +1EE42;1EE42;1EE42;062C;062C; # (𞹂; 𞹂; 𞹂; ج; ج; ) ARABIC MATHEMATICAL TAILED JEEM +1EE47;1EE47;1EE47;062D;062D; # (𞹇; 𞹇; 𞹇; ح; ح; ) ARABIC MATHEMATICAL TAILED HAH +1EE49;1EE49;1EE49;064A;064A; # (𞹉; 𞹉; 𞹉; ي; ي; ) ARABIC MATHEMATICAL TAILED YEH +1EE4B;1EE4B;1EE4B;0644;0644; # (𞹋; 𞹋; 𞹋; ل; ل; ) ARABIC MATHEMATICAL TAILED LAM +1EE4D;1EE4D;1EE4D;0646;0646; # (𞹍; 𞹍; 𞹍; ن; ن; ) ARABIC MATHEMATICAL TAILED NOON +1EE4E;1EE4E;1EE4E;0633;0633; # (𞹎; 𞹎; 𞹎; س; س; ) ARABIC MATHEMATICAL TAILED SEEN +1EE4F;1EE4F;1EE4F;0639;0639; # (𞹏; 𞹏; 𞹏; ع; ع; ) ARABIC MATHEMATICAL TAILED AIN +1EE51;1EE51;1EE51;0635;0635; # (𞹑; 𞹑; 𞹑; ص; ص; ) ARABIC MATHEMATICAL TAILED SAD +1EE52;1EE52;1EE52;0642;0642; # (𞹒; 𞹒; 𞹒; ق; ق; ) ARABIC MATHEMATICAL TAILED QAF +1EE54;1EE54;1EE54;0634;0634; # (𞹔; 𞹔; 𞹔; ش; ش; ) ARABIC MATHEMATICAL TAILED SHEEN +1EE57;1EE57;1EE57;062E;062E; # (𞹗; 𞹗; 𞹗; خ; خ; ) ARABIC MATHEMATICAL TAILED KHAH +1EE59;1EE59;1EE59;0636;0636; # (𞹙; 𞹙; 𞹙; ض; ض; ) ARABIC MATHEMATICAL TAILED DAD +1EE5B;1EE5B;1EE5B;063A;063A; # (𞹛; 𞹛; 𞹛; غ; غ; ) ARABIC MATHEMATICAL TAILED GHAIN +1EE5D;1EE5D;1EE5D;06BA;06BA; # (𞹝; 𞹝; 𞹝; ں; ں; ) ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5F;1EE5F;1EE5F;066F;066F; # (𞹟; 𞹟; 𞹟; ٯ; ٯ; ) ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE61;1EE61;1EE61;0628;0628; # (𞹡; 𞹡; 𞹡; ب; ب; ) ARABIC MATHEMATICAL STRETCHED BEH +1EE62;1EE62;1EE62;062C;062C; # (𞹢; 𞹢; 𞹢; ج; ج; ) ARABIC MATHEMATICAL STRETCHED JEEM +1EE64;1EE64;1EE64;0647;0647; # (𞹤; 𞹤; 𞹤; ه; ه; ) ARABIC MATHEMATICAL STRETCHED HEH +1EE67;1EE67;1EE67;062D;062D; # (𞹧; 𞹧; 𞹧; ح; ح; ) ARABIC MATHEMATICAL STRETCHED HAH +1EE68;1EE68;1EE68;0637;0637; # (𞹨; 𞹨; 𞹨; ط; ط; ) ARABIC MATHEMATICAL STRETCHED TAH +1EE69;1EE69;1EE69;064A;064A; # (𞹩; 𞹩; 𞹩; ي; ي; ) ARABIC MATHEMATICAL STRETCHED YEH +1EE6A;1EE6A;1EE6A;0643;0643; # (𞹪; 𞹪; 𞹪; ك; ك; ) ARABIC MATHEMATICAL STRETCHED KAF +1EE6C;1EE6C;1EE6C;0645;0645; # (𞹬; 𞹬; 𞹬; م; م; ) ARABIC MATHEMATICAL STRETCHED MEEM +1EE6D;1EE6D;1EE6D;0646;0646; # (𞹭; 𞹭; 𞹭; ن; ن; ) ARABIC MATHEMATICAL STRETCHED NOON +1EE6E;1EE6E;1EE6E;0633;0633; # (𞹮; 𞹮; 𞹮; س; س; ) ARABIC MATHEMATICAL STRETCHED SEEN +1EE6F;1EE6F;1EE6F;0639;0639; # (𞹯; 𞹯; 𞹯; ع; ع; ) ARABIC MATHEMATICAL STRETCHED AIN +1EE70;1EE70;1EE70;0641;0641; # (𞹰; 𞹰; 𞹰; ف; ف; ) ARABIC MATHEMATICAL STRETCHED FEH +1EE71;1EE71;1EE71;0635;0635; # (𞹱; 𞹱; 𞹱; ص; ص; ) ARABIC MATHEMATICAL STRETCHED SAD +1EE72;1EE72;1EE72;0642;0642; # (𞹲; 𞹲; 𞹲; ق; ق; ) ARABIC MATHEMATICAL STRETCHED QAF +1EE74;1EE74;1EE74;0634;0634; # (𞹴; 𞹴; 𞹴; ش; ش; ) ARABIC MATHEMATICAL STRETCHED SHEEN +1EE75;1EE75;1EE75;062A;062A; # (𞹵; 𞹵; 𞹵; ت; ت; ) ARABIC MATHEMATICAL STRETCHED TEH +1EE76;1EE76;1EE76;062B;062B; # (𞹶; 𞹶; 𞹶; ث; ث; ) ARABIC MATHEMATICAL STRETCHED THEH +1EE77;1EE77;1EE77;062E;062E; # (𞹷; 𞹷; 𞹷; خ; خ; ) ARABIC MATHEMATICAL STRETCHED KHAH +1EE79;1EE79;1EE79;0636;0636; # (𞹹; 𞹹; 𞹹; ض; ض; ) ARABIC MATHEMATICAL STRETCHED DAD +1EE7A;1EE7A;1EE7A;0638;0638; # (𞹺; 𞹺; 𞹺; ظ; ظ; ) ARABIC MATHEMATICAL STRETCHED ZAH +1EE7B;1EE7B;1EE7B;063A;063A; # (𞹻; 𞹻; 𞹻; غ; غ; ) ARABIC MATHEMATICAL STRETCHED GHAIN +1EE7C;1EE7C;1EE7C;066E;066E; # (𞹼; 𞹼; 𞹼; ٮ; ٮ; ) ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7E;1EE7E;1EE7E;06A1;06A1; # (𞹾; 𞹾; 𞹾; ڡ; ڡ; ) ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE80;1EE80;1EE80;0627;0627; # (𞺀; 𞺀; 𞺀; ا; ا; ) ARABIC MATHEMATICAL LOOPED ALEF +1EE81;1EE81;1EE81;0628;0628; # (𞺁; 𞺁; 𞺁; ب; ب; ) ARABIC MATHEMATICAL LOOPED BEH +1EE82;1EE82;1EE82;062C;062C; # (𞺂; 𞺂; 𞺂; ج; ج; ) ARABIC MATHEMATICAL LOOPED JEEM +1EE83;1EE83;1EE83;062F;062F; # (𞺃; 𞺃; 𞺃; د; د; ) ARABIC MATHEMATICAL LOOPED DAL +1EE84;1EE84;1EE84;0647;0647; # (𞺄; 𞺄; 𞺄; ه; ه; ) ARABIC MATHEMATICAL LOOPED HEH +1EE85;1EE85;1EE85;0648;0648; # (𞺅; 𞺅; 𞺅; و; و; ) ARABIC MATHEMATICAL LOOPED WAW +1EE86;1EE86;1EE86;0632;0632; # (𞺆; 𞺆; 𞺆; ز; ز; ) ARABIC MATHEMATICAL LOOPED ZAIN +1EE87;1EE87;1EE87;062D;062D; # (𞺇; 𞺇; 𞺇; ح; ح; ) ARABIC MATHEMATICAL LOOPED HAH +1EE88;1EE88;1EE88;0637;0637; # (𞺈; 𞺈; 𞺈; ط; ط; ) ARABIC MATHEMATICAL LOOPED TAH +1EE89;1EE89;1EE89;064A;064A; # (𞺉; 𞺉; 𞺉; ي; ي; ) ARABIC MATHEMATICAL LOOPED YEH +1EE8B;1EE8B;1EE8B;0644;0644; # (𞺋; 𞺋; 𞺋; ل; ل; ) ARABIC MATHEMATICAL LOOPED LAM +1EE8C;1EE8C;1EE8C;0645;0645; # (𞺌; 𞺌; 𞺌; م; م; ) ARABIC MATHEMATICAL LOOPED MEEM +1EE8D;1EE8D;1EE8D;0646;0646; # (𞺍; 𞺍; 𞺍; ن; ن; ) ARABIC MATHEMATICAL LOOPED NOON +1EE8E;1EE8E;1EE8E;0633;0633; # (𞺎; 𞺎; 𞺎; س; س; ) ARABIC MATHEMATICAL LOOPED SEEN +1EE8F;1EE8F;1EE8F;0639;0639; # (𞺏; 𞺏; 𞺏; ع; ع; ) ARABIC MATHEMATICAL LOOPED AIN +1EE90;1EE90;1EE90;0641;0641; # (𞺐; 𞺐; 𞺐; ف; ف; ) ARABIC MATHEMATICAL LOOPED FEH +1EE91;1EE91;1EE91;0635;0635; # (𞺑; 𞺑; 𞺑; ص; ص; ) ARABIC MATHEMATICAL LOOPED SAD +1EE92;1EE92;1EE92;0642;0642; # (𞺒; 𞺒; 𞺒; ق; ق; ) ARABIC MATHEMATICAL LOOPED QAF +1EE93;1EE93;1EE93;0631;0631; # (𞺓; 𞺓; 𞺓; ر; ر; ) ARABIC MATHEMATICAL LOOPED REH +1EE94;1EE94;1EE94;0634;0634; # (𞺔; 𞺔; 𞺔; ش; ش; ) ARABIC MATHEMATICAL LOOPED SHEEN +1EE95;1EE95;1EE95;062A;062A; # (𞺕; 𞺕; 𞺕; ت; ت; ) ARABIC MATHEMATICAL LOOPED TEH +1EE96;1EE96;1EE96;062B;062B; # (𞺖; 𞺖; 𞺖; ث; ث; ) ARABIC MATHEMATICAL LOOPED THEH +1EE97;1EE97;1EE97;062E;062E; # (𞺗; 𞺗; 𞺗; خ; خ; ) ARABIC MATHEMATICAL LOOPED KHAH +1EE98;1EE98;1EE98;0630;0630; # (𞺘; 𞺘; 𞺘; ذ; ذ; ) ARABIC MATHEMATICAL LOOPED THAL +1EE99;1EE99;1EE99;0636;0636; # (𞺙; 𞺙; 𞺙; ض; ض; ) ARABIC MATHEMATICAL LOOPED DAD +1EE9A;1EE9A;1EE9A;0638;0638; # (𞺚; 𞺚; 𞺚; ظ; ظ; ) ARABIC MATHEMATICAL LOOPED ZAH +1EE9B;1EE9B;1EE9B;063A;063A; # (𞺛; 𞺛; 𞺛; غ; غ; ) ARABIC MATHEMATICAL LOOPED GHAIN +1EEA1;1EEA1;1EEA1;0628;0628; # (𞺡; 𞺡; 𞺡; ب; ب; ) ARABIC MATHEMATICAL DOUBLE-STRUCK BEH +1EEA2;1EEA2;1EEA2;062C;062C; # (𞺢; 𞺢; 𞺢; ج; ج; ) ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM +1EEA3;1EEA3;1EEA3;062F;062F; # (𞺣; 𞺣; 𞺣; د; د; ) ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA5;1EEA5;1EEA5;0648;0648; # (𞺥; 𞺥; 𞺥; و; و; ) ARABIC MATHEMATICAL DOUBLE-STRUCK WAW +1EEA6;1EEA6;1EEA6;0632;0632; # (𞺦; 𞺦; 𞺦; ز; ز; ) ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN +1EEA7;1EEA7;1EEA7;062D;062D; # (𞺧; 𞺧; 𞺧; ح; ح; ) ARABIC MATHEMATICAL DOUBLE-STRUCK HAH +1EEA8;1EEA8;1EEA8;0637;0637; # (𞺨; 𞺨; 𞺨; ط; ط; ) ARABIC MATHEMATICAL DOUBLE-STRUCK TAH +1EEA9;1EEA9;1EEA9;064A;064A; # (𞺩; 𞺩; 𞺩; ي; ي; ) ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAB;1EEAB;1EEAB;0644;0644; # (𞺫; 𞺫; 𞺫; ل; ل; ) ARABIC MATHEMATICAL DOUBLE-STRUCK LAM +1EEAC;1EEAC;1EEAC;0645;0645; # (𞺬; 𞺬; 𞺬; م; م; ) ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM +1EEAD;1EEAD;1EEAD;0646;0646; # (𞺭; 𞺭; 𞺭; ن; ن; ) ARABIC MATHEMATICAL DOUBLE-STRUCK NOON +1EEAE;1EEAE;1EEAE;0633;0633; # (𞺮; 𞺮; 𞺮; س; س; ) ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN +1EEAF;1EEAF;1EEAF;0639;0639; # (𞺯; 𞺯; 𞺯; ع; ع; ) ARABIC MATHEMATICAL DOUBLE-STRUCK AIN +1EEB0;1EEB0;1EEB0;0641;0641; # (𞺰; 𞺰; 𞺰; ف; ف; ) ARABIC MATHEMATICAL DOUBLE-STRUCK FEH +1EEB1;1EEB1;1EEB1;0635;0635; # (𞺱; 𞺱; 𞺱; ص; ص; ) ARABIC MATHEMATICAL DOUBLE-STRUCK SAD +1EEB2;1EEB2;1EEB2;0642;0642; # (𞺲; 𞺲; 𞺲; ق; ق; ) ARABIC MATHEMATICAL DOUBLE-STRUCK QAF +1EEB3;1EEB3;1EEB3;0631;0631; # (𞺳; 𞺳; 𞺳; ر; ر; ) ARABIC MATHEMATICAL DOUBLE-STRUCK REH +1EEB4;1EEB4;1EEB4;0634;0634; # (𞺴; 𞺴; 𞺴; ش; ش; ) ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN +1EEB5;1EEB5;1EEB5;062A;062A; # (𞺵; 𞺵; 𞺵; ت; ت; ) ARABIC MATHEMATICAL DOUBLE-STRUCK TEH +1EEB6;1EEB6;1EEB6;062B;062B; # (𞺶; 𞺶; 𞺶; ث; ث; ) ARABIC MATHEMATICAL DOUBLE-STRUCK THEH +1EEB7;1EEB7;1EEB7;062E;062E; # (𞺷; 𞺷; 𞺷; خ; خ; ) ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH +1EEB8;1EEB8;1EEB8;0630;0630; # (𞺸; 𞺸; 𞺸; ذ; ذ; ) ARABIC MATHEMATICAL DOUBLE-STRUCK THAL +1EEB9;1EEB9;1EEB9;0636;0636; # (𞺹; 𞺹; 𞺹; ض; ض; ) ARABIC MATHEMATICAL DOUBLE-STRUCK DAD +1EEBA;1EEBA;1EEBA;0638;0638; # (𞺺; 𞺺; 𞺺; ظ; ظ; ) ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH +1EEBB;1EEBB;1EEBB;063A;063A; # (𞺻; 𞺻; 𞺻; غ; غ; ) ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +1F100;1F100;1F100;0030 002E;0030 002E; # (🄀; 🄀; 🄀; 0.; 0.; ) DIGIT ZERO FULL STOP +1F101;1F101;1F101;0030 002C;0030 002C; # (🄁; 🄁; 🄁; 0,; 0,; ) DIGIT ZERO COMMA +1F102;1F102;1F102;0031 002C;0031 002C; # (🄂; 🄂; 🄂; 1,; 1,; ) DIGIT ONE COMMA +1F103;1F103;1F103;0032 002C;0032 002C; # (🄃; 🄃; 🄃; 2,; 2,; ) DIGIT TWO COMMA +1F104;1F104;1F104;0033 002C;0033 002C; # (🄄; 🄄; 🄄; 3,; 3,; ) DIGIT THREE COMMA +1F105;1F105;1F105;0034 002C;0034 002C; # (🄅; 🄅; 🄅; 4,; 4,; ) DIGIT FOUR COMMA +1F106;1F106;1F106;0035 002C;0035 002C; # (🄆; 🄆; 🄆; 5,; 5,; ) DIGIT FIVE COMMA +1F107;1F107;1F107;0036 002C;0036 002C; # (🄇; 🄇; 🄇; 6,; 6,; ) DIGIT SIX COMMA +1F108;1F108;1F108;0037 002C;0037 002C; # (🄈; 🄈; 🄈; 7,; 7,; ) DIGIT SEVEN COMMA +1F109;1F109;1F109;0038 002C;0038 002C; # (🄉; 🄉; 🄉; 8,; 8,; ) DIGIT EIGHT COMMA +1F10A;1F10A;1F10A;0039 002C;0039 002C; # (🄊; 🄊; 🄊; 9,; 9,; ) DIGIT NINE COMMA +1F110;1F110;1F110;0028 0041 0029;0028 0041 0029; # (🄐; 🄐; 🄐; (A); (A); ) PARENTHESIZED LATIN CAPITAL LETTER A +1F111;1F111;1F111;0028 0042 0029;0028 0042 0029; # (🄑; 🄑; 🄑; (B); (B); ) PARENTHESIZED LATIN CAPITAL LETTER B +1F112;1F112;1F112;0028 0043 0029;0028 0043 0029; # (🄒; 🄒; 🄒; (C); (C); ) PARENTHESIZED LATIN CAPITAL LETTER C +1F113;1F113;1F113;0028 0044 0029;0028 0044 0029; # (🄓; 🄓; 🄓; (D); (D); ) PARENTHESIZED LATIN CAPITAL LETTER D +1F114;1F114;1F114;0028 0045 0029;0028 0045 0029; # (🄔; 🄔; 🄔; (E); (E); ) PARENTHESIZED LATIN CAPITAL LETTER E +1F115;1F115;1F115;0028 0046 0029;0028 0046 0029; # (🄕; 🄕; 🄕; (F); (F); ) PARENTHESIZED LATIN CAPITAL LETTER F +1F116;1F116;1F116;0028 0047 0029;0028 0047 0029; # (🄖; 🄖; 🄖; (G); (G); ) PARENTHESIZED LATIN CAPITAL LETTER G +1F117;1F117;1F117;0028 0048 0029;0028 0048 0029; # (🄗; 🄗; 🄗; (H); (H); ) PARENTHESIZED LATIN CAPITAL LETTER H +1F118;1F118;1F118;0028 0049 0029;0028 0049 0029; # (🄘; 🄘; 🄘; (I); (I); ) PARENTHESIZED LATIN CAPITAL LETTER I +1F119;1F119;1F119;0028 004A 0029;0028 004A 0029; # (🄙; 🄙; 🄙; (J); (J); ) PARENTHESIZED LATIN CAPITAL LETTER J +1F11A;1F11A;1F11A;0028 004B 0029;0028 004B 0029; # (🄚; 🄚; 🄚; (K); (K); ) PARENTHESIZED LATIN CAPITAL LETTER K +1F11B;1F11B;1F11B;0028 004C 0029;0028 004C 0029; # (🄛; 🄛; 🄛; (L); (L); ) PARENTHESIZED LATIN CAPITAL LETTER L +1F11C;1F11C;1F11C;0028 004D 0029;0028 004D 0029; # (🄜; 🄜; 🄜; (M); (M); ) PARENTHESIZED LATIN CAPITAL LETTER M +1F11D;1F11D;1F11D;0028 004E 0029;0028 004E 0029; # (🄝; 🄝; 🄝; (N); (N); ) PARENTHESIZED LATIN CAPITAL LETTER N +1F11E;1F11E;1F11E;0028 004F 0029;0028 004F 0029; # (🄞; 🄞; 🄞; (O); (O); ) PARENTHESIZED LATIN CAPITAL LETTER O +1F11F;1F11F;1F11F;0028 0050 0029;0028 0050 0029; # (🄟; 🄟; 🄟; (P); (P); ) PARENTHESIZED LATIN CAPITAL LETTER P +1F120;1F120;1F120;0028 0051 0029;0028 0051 0029; # (🄠; 🄠; 🄠; (Q); (Q); ) PARENTHESIZED LATIN CAPITAL LETTER Q +1F121;1F121;1F121;0028 0052 0029;0028 0052 0029; # (🄡; 🄡; 🄡; (R); (R); ) PARENTHESIZED LATIN CAPITAL LETTER R +1F122;1F122;1F122;0028 0053 0029;0028 0053 0029; # (🄢; 🄢; 🄢; (S); (S); ) PARENTHESIZED LATIN CAPITAL LETTER S +1F123;1F123;1F123;0028 0054 0029;0028 0054 0029; # (🄣; 🄣; 🄣; (T); (T); ) PARENTHESIZED LATIN CAPITAL LETTER T +1F124;1F124;1F124;0028 0055 0029;0028 0055 0029; # (🄤; 🄤; 🄤; (U); (U); ) PARENTHESIZED LATIN CAPITAL LETTER U +1F125;1F125;1F125;0028 0056 0029;0028 0056 0029; # (🄥; 🄥; 🄥; (V); (V); ) PARENTHESIZED LATIN CAPITAL LETTER V +1F126;1F126;1F126;0028 0057 0029;0028 0057 0029; # (🄦; 🄦; 🄦; (W); (W); ) PARENTHESIZED LATIN CAPITAL LETTER W +1F127;1F127;1F127;0028 0058 0029;0028 0058 0029; # (🄧; 🄧; 🄧; (X); (X); ) PARENTHESIZED LATIN CAPITAL LETTER X +1F128;1F128;1F128;0028 0059 0029;0028 0059 0029; # (🄨; 🄨; 🄨; (Y); (Y); ) PARENTHESIZED LATIN CAPITAL LETTER Y +1F129;1F129;1F129;0028 005A 0029;0028 005A 0029; # (🄩; 🄩; 🄩; (Z); (Z); ) PARENTHESIZED LATIN CAPITAL LETTER Z +1F12A;1F12A;1F12A;3014 0053 3015;3014 0053 3015; # (🄪; 🄪; 🄪; 〔S〕; 〔S〕; ) TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S +1F12B;1F12B;1F12B;0043;0043; # (🄫; 🄫; 🄫; C; C; ) CIRCLED ITALIC LATIN CAPITAL LETTER C +1F12C;1F12C;1F12C;0052;0052; # (🄬; 🄬; 🄬; R; R; ) CIRCLED ITALIC LATIN CAPITAL LETTER R +1F12D;1F12D;1F12D;0043 0044;0043 0044; # (🄭; 🄭; 🄭; CD; CD; ) CIRCLED CD +1F12E;1F12E;1F12E;0057 005A;0057 005A; # (🄮; 🄮; 🄮; WZ; WZ; ) CIRCLED WZ +1F130;1F130;1F130;0041;0041; # (🄰; 🄰; 🄰; A; A; ) SQUARED LATIN CAPITAL LETTER A +1F131;1F131;1F131;0042;0042; # (🄱; 🄱; 🄱; B; B; ) SQUARED LATIN CAPITAL LETTER B +1F132;1F132;1F132;0043;0043; # (🄲; 🄲; 🄲; C; C; ) SQUARED LATIN CAPITAL LETTER C +1F133;1F133;1F133;0044;0044; # (🄳; 🄳; 🄳; D; D; ) SQUARED LATIN CAPITAL LETTER D +1F134;1F134;1F134;0045;0045; # (🄴; 🄴; 🄴; E; E; ) SQUARED LATIN CAPITAL LETTER E +1F135;1F135;1F135;0046;0046; # (🄵; 🄵; 🄵; F; F; ) SQUARED LATIN CAPITAL LETTER F +1F136;1F136;1F136;0047;0047; # (🄶; 🄶; 🄶; G; G; ) SQUARED LATIN CAPITAL LETTER G +1F137;1F137;1F137;0048;0048; # (🄷; 🄷; 🄷; H; H; ) SQUARED LATIN CAPITAL LETTER H +1F138;1F138;1F138;0049;0049; # (🄸; 🄸; 🄸; I; I; ) SQUARED LATIN CAPITAL LETTER I +1F139;1F139;1F139;004A;004A; # (🄹; 🄹; 🄹; J; J; ) SQUARED LATIN CAPITAL LETTER J +1F13A;1F13A;1F13A;004B;004B; # (🄺; 🄺; 🄺; K; K; ) SQUARED LATIN CAPITAL LETTER K +1F13B;1F13B;1F13B;004C;004C; # (🄻; 🄻; 🄻; L; L; ) SQUARED LATIN CAPITAL LETTER L +1F13C;1F13C;1F13C;004D;004D; # (🄼; 🄼; 🄼; M; M; ) SQUARED LATIN CAPITAL LETTER M +1F13D;1F13D;1F13D;004E;004E; # (🄽; 🄽; 🄽; N; N; ) SQUARED LATIN CAPITAL LETTER N +1F13E;1F13E;1F13E;004F;004F; # (🄾; 🄾; 🄾; O; O; ) SQUARED LATIN CAPITAL LETTER O +1F13F;1F13F;1F13F;0050;0050; # (🄿; 🄿; 🄿; P; P; ) SQUARED LATIN CAPITAL LETTER P +1F140;1F140;1F140;0051;0051; # (🅀; 🅀; 🅀; Q; Q; ) SQUARED LATIN CAPITAL LETTER Q +1F141;1F141;1F141;0052;0052; # (🅁; 🅁; 🅁; R; R; ) SQUARED LATIN CAPITAL LETTER R +1F142;1F142;1F142;0053;0053; # (🅂; 🅂; 🅂; S; S; ) SQUARED LATIN CAPITAL LETTER S +1F143;1F143;1F143;0054;0054; # (🅃; 🅃; 🅃; T; T; ) SQUARED LATIN CAPITAL LETTER T +1F144;1F144;1F144;0055;0055; # (🅄; 🅄; 🅄; U; U; ) SQUARED LATIN CAPITAL LETTER U +1F145;1F145;1F145;0056;0056; # (🅅; 🅅; 🅅; V; V; ) SQUARED LATIN CAPITAL LETTER V +1F146;1F146;1F146;0057;0057; # (🅆; 🅆; 🅆; W; W; ) SQUARED LATIN CAPITAL LETTER W +1F147;1F147;1F147;0058;0058; # (🅇; 🅇; 🅇; X; X; ) SQUARED LATIN CAPITAL LETTER X +1F148;1F148;1F148;0059;0059; # (🅈; 🅈; 🅈; Y; Y; ) SQUARED LATIN CAPITAL LETTER Y +1F149;1F149;1F149;005A;005A; # (🅉; 🅉; 🅉; Z; Z; ) SQUARED LATIN CAPITAL LETTER Z +1F14A;1F14A;1F14A;0048 0056;0048 0056; # (🅊; 🅊; 🅊; HV; HV; ) SQUARED HV +1F14B;1F14B;1F14B;004D 0056;004D 0056; # (🅋; 🅋; 🅋; MV; MV; ) SQUARED MV +1F14C;1F14C;1F14C;0053 0044;0053 0044; # (🅌; 🅌; 🅌; SD; SD; ) SQUARED SD +1F14D;1F14D;1F14D;0053 0053;0053 0053; # (🅍; 🅍; 🅍; SS; SS; ) SQUARED SS +1F14E;1F14E;1F14E;0050 0050 0056;0050 0050 0056; # (🅎; 🅎; 🅎; PPV; PPV; ) SQUARED PPV +1F14F;1F14F;1F14F;0057 0043;0057 0043; # (🅏; 🅏; 🅏; WC; WC; ) SQUARED WC +1F16A;1F16A;1F16A;004D 0043;004D 0043; # (🅪; 🅪; 🅪; MC; MC; ) RAISED MC SIGN +1F16B;1F16B;1F16B;004D 0044;004D 0044; # (🅫; 🅫; 🅫; MD; MD; ) RAISED MD SIGN +1F16C;1F16C;1F16C;004D 0052;004D 0052; # (🅬; 🅬; 🅬; MR; MR; ) RAISED MR SIGN +1F190;1F190;1F190;0044 004A;0044 004A; # (🆐; 🆐; 🆐; DJ; DJ; ) SQUARE DJ +1F200;1F200;1F200;307B 304B;307B 304B; # (🈀; 🈀; 🈀; ほか; ほか; ) SQUARE HIRAGANA HOKA +1F201;1F201;1F201;30B3 30B3;30B3 30B3; # (🈁; 🈁; 🈁; ココ; ココ; ) SQUARED KATAKANA KOKO +1F202;1F202;1F202;30B5;30B5; # (🈂; 🈂; 🈂; サ; サ; ) SQUARED KATAKANA SA +1F210;1F210;1F210;624B;624B; # (🈐; 🈐; 🈐; 手; 手; ) SQUARED CJK UNIFIED IDEOGRAPH-624B +1F211;1F211;1F211;5B57;5B57; # (🈑; 🈑; 🈑; 字; 字; ) SQUARED CJK UNIFIED IDEOGRAPH-5B57 +1F212;1F212;1F212;53CC;53CC; # (🈒; 🈒; 🈒; 双; 双; ) SQUARED CJK UNIFIED IDEOGRAPH-53CC +1F213;1F213;1F213;30C7;30C6 3099; # (🈓; 🈓; 🈓; デ; テ◌゙; ) SQUARED KATAKANA DE +1F214;1F214;1F214;4E8C;4E8C; # (🈔; 🈔; 🈔; 二; 二; ) SQUARED CJK UNIFIED IDEOGRAPH-4E8C +1F215;1F215;1F215;591A;591A; # (🈕; 🈕; 🈕; 多; 多; ) SQUARED CJK UNIFIED IDEOGRAPH-591A +1F216;1F216;1F216;89E3;89E3; # (🈖; 🈖; 🈖; 解; 解; ) SQUARED CJK UNIFIED IDEOGRAPH-89E3 +1F217;1F217;1F217;5929;5929; # (🈗; 🈗; 🈗; 天; 天; ) SQUARED CJK UNIFIED IDEOGRAPH-5929 +1F218;1F218;1F218;4EA4;4EA4; # (🈘; 🈘; 🈘; 交; 交; ) SQUARED CJK UNIFIED IDEOGRAPH-4EA4 +1F219;1F219;1F219;6620;6620; # (🈙; 🈙; 🈙; 映; 映; ) SQUARED CJK UNIFIED IDEOGRAPH-6620 +1F21A;1F21A;1F21A;7121;7121; # (🈚; 🈚; 🈚; 無; 無; ) SQUARED CJK UNIFIED IDEOGRAPH-7121 +1F21B;1F21B;1F21B;6599;6599; # (🈛; 🈛; 🈛; 料; 料; ) SQUARED CJK UNIFIED IDEOGRAPH-6599 +1F21C;1F21C;1F21C;524D;524D; # (🈜; 🈜; 🈜; 前; 前; ) SQUARED CJK UNIFIED IDEOGRAPH-524D +1F21D;1F21D;1F21D;5F8C;5F8C; # (🈝; 🈝; 🈝; 後; 後; ) SQUARED CJK UNIFIED IDEOGRAPH-5F8C +1F21E;1F21E;1F21E;518D;518D; # (🈞; 🈞; 🈞; 再; 再; ) SQUARED CJK UNIFIED IDEOGRAPH-518D +1F21F;1F21F;1F21F;65B0;65B0; # (🈟; 🈟; 🈟; 新; 新; ) SQUARED CJK UNIFIED IDEOGRAPH-65B0 +1F220;1F220;1F220;521D;521D; # (🈠; 🈠; 🈠; 初; 初; ) SQUARED CJK UNIFIED IDEOGRAPH-521D +1F221;1F221;1F221;7D42;7D42; # (🈡; 🈡; 🈡; 終; 終; ) SQUARED CJK UNIFIED IDEOGRAPH-7D42 +1F222;1F222;1F222;751F;751F; # (🈢; 🈢; 🈢; 生; 生; ) SQUARED CJK UNIFIED IDEOGRAPH-751F +1F223;1F223;1F223;8CA9;8CA9; # (🈣; 🈣; 🈣; 販; 販; ) SQUARED CJK UNIFIED IDEOGRAPH-8CA9 +1F224;1F224;1F224;58F0;58F0; # (🈤; 🈤; 🈤; 声; 声; ) SQUARED CJK UNIFIED IDEOGRAPH-58F0 +1F225;1F225;1F225;5439;5439; # (🈥; 🈥; 🈥; 吹; 吹; ) SQUARED CJK UNIFIED IDEOGRAPH-5439 +1F226;1F226;1F226;6F14;6F14; # (🈦; 🈦; 🈦; 演; 演; ) SQUARED CJK UNIFIED IDEOGRAPH-6F14 +1F227;1F227;1F227;6295;6295; # (🈧; 🈧; 🈧; 投; 投; ) SQUARED CJK UNIFIED IDEOGRAPH-6295 +1F228;1F228;1F228;6355;6355; # (🈨; 🈨; 🈨; 捕; 捕; ) SQUARED CJK UNIFIED IDEOGRAPH-6355 +1F229;1F229;1F229;4E00;4E00; # (🈩; 🈩; 🈩; 一; 一; ) SQUARED CJK UNIFIED IDEOGRAPH-4E00 +1F22A;1F22A;1F22A;4E09;4E09; # (🈪; 🈪; 🈪; 三; 三; ) SQUARED CJK UNIFIED IDEOGRAPH-4E09 +1F22B;1F22B;1F22B;904A;904A; # (🈫; 🈫; 🈫; 遊; 遊; ) SQUARED CJK UNIFIED IDEOGRAPH-904A +1F22C;1F22C;1F22C;5DE6;5DE6; # (🈬; 🈬; 🈬; 左; 左; ) SQUARED CJK UNIFIED IDEOGRAPH-5DE6 +1F22D;1F22D;1F22D;4E2D;4E2D; # (🈭; 🈭; 🈭; 中; 中; ) SQUARED CJK UNIFIED IDEOGRAPH-4E2D +1F22E;1F22E;1F22E;53F3;53F3; # (🈮; 🈮; 🈮; 右; 右; ) SQUARED CJK UNIFIED IDEOGRAPH-53F3 +1F22F;1F22F;1F22F;6307;6307; # (🈯; 🈯; 🈯; 指; 指; ) SQUARED CJK UNIFIED IDEOGRAPH-6307 +1F230;1F230;1F230;8D70;8D70; # (🈰; 🈰; 🈰; 走; 走; ) SQUARED CJK UNIFIED IDEOGRAPH-8D70 +1F231;1F231;1F231;6253;6253; # (🈱; 🈱; 🈱; 打; 打; ) SQUARED CJK UNIFIED IDEOGRAPH-6253 +1F232;1F232;1F232;7981;7981; # (🈲; 🈲; 🈲; 禁; 禁; ) SQUARED CJK UNIFIED IDEOGRAPH-7981 +1F233;1F233;1F233;7A7A;7A7A; # (🈳; 🈳; 🈳; 空; 空; ) SQUARED CJK UNIFIED IDEOGRAPH-7A7A +1F234;1F234;1F234;5408;5408; # (🈴; 🈴; 🈴; 合; 合; ) SQUARED CJK UNIFIED IDEOGRAPH-5408 +1F235;1F235;1F235;6E80;6E80; # (🈵; 🈵; 🈵; 満; 満; ) SQUARED CJK UNIFIED IDEOGRAPH-6E80 +1F236;1F236;1F236;6709;6709; # (🈶; 🈶; 🈶; 有; 有; ) SQUARED CJK UNIFIED IDEOGRAPH-6709 +1F237;1F237;1F237;6708;6708; # (🈷; 🈷; 🈷; 月; 月; ) SQUARED CJK UNIFIED IDEOGRAPH-6708 +1F238;1F238;1F238;7533;7533; # (🈸; 🈸; 🈸; 申; 申; ) SQUARED CJK UNIFIED IDEOGRAPH-7533 +1F239;1F239;1F239;5272;5272; # (🈹; 🈹; 🈹; 割; 割; ) SQUARED CJK UNIFIED IDEOGRAPH-5272 +1F23A;1F23A;1F23A;55B6;55B6; # (🈺; 🈺; 🈺; 営; 営; ) SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F23B;1F23B;1F23B;914D;914D; # (🈻; 🈻; 🈻; 配; 配; ) SQUARED CJK UNIFIED IDEOGRAPH-914D +1F240;1F240;1F240;3014 672C 3015;3014 672C 3015; # (🉀; 🉀; 🉀; 〔本〕; 〔本〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C +1F241;1F241;1F241;3014 4E09 3015;3014 4E09 3015; # (🉁; 🉁; 🉁; 〔三〕; 〔三〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 +1F242;1F242;1F242;3014 4E8C 3015;3014 4E8C 3015; # (🉂; 🉂; 🉂; 〔二〕; 〔二〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C +1F243;1F243;1F243;3014 5B89 3015;3014 5B89 3015; # (🉃; 🉃; 🉃; 〔安〕; 〔安〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89 +1F244;1F244;1F244;3014 70B9 3015;3014 70B9 3015; # (🉄; 🉄; 🉄; 〔点〕; 〔点〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9 +1F245;1F245;1F245;3014 6253 3015;3014 6253 3015; # (🉅; 🉅; 🉅; 〔打〕; 〔打〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253 +1F246;1F246;1F246;3014 76D7 3015;3014 76D7 3015; # (🉆; 🉆; 🉆; 〔盗〕; 〔盗〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7 +1F247;1F247;1F247;3014 52DD 3015;3014 52DD 3015; # (🉇; 🉇; 🉇; 〔勝〕; 〔勝〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD +1F248;1F248;1F248;3014 6557 3015;3014 6557 3015; # (🉈; 🉈; 🉈; 〔敗〕; 〔敗〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +1F250;1F250;1F250;5F97;5F97; # (🉐; 🉐; 🉐; 得; 得; ) CIRCLED IDEOGRAPH ADVANTAGE +1F251;1F251;1F251;53EF;53EF; # (🉑; 🉑; 🉑; 可; 可; ) CIRCLED IDEOGRAPH ACCEPT +1FBF0;1FBF0;1FBF0;0030;0030; # (🯰; 🯰; 🯰; 0; 0; ) SEGMENTED DIGIT ZERO +1FBF1;1FBF1;1FBF1;0031;0031; # (🯱; 🯱; 🯱; 1; 1; ) SEGMENTED DIGIT ONE +1FBF2;1FBF2;1FBF2;0032;0032; # (🯲; 🯲; 🯲; 2; 2; ) SEGMENTED DIGIT TWO +1FBF3;1FBF3;1FBF3;0033;0033; # (🯳; 🯳; 🯳; 3; 3; ) SEGMENTED DIGIT THREE +1FBF4;1FBF4;1FBF4;0034;0034; # (🯴; 🯴; 🯴; 4; 4; ) SEGMENTED DIGIT FOUR +1FBF5;1FBF5;1FBF5;0035;0035; # (🯵; 🯵; 🯵; 5; 5; ) SEGMENTED DIGIT FIVE +1FBF6;1FBF6;1FBF6;0036;0036; # (🯶; 🯶; 🯶; 6; 6; ) SEGMENTED DIGIT SIX +1FBF7;1FBF7;1FBF7;0037;0037; # (🯷; 🯷; 🯷; 7; 7; ) SEGMENTED DIGIT SEVEN +1FBF8;1FBF8;1FBF8;0038;0038; # (🯸; 🯸; 🯸; 8; 8; ) SEGMENTED DIGIT EIGHT +1FBF9;1FBF9;1FBF9;0039;0039; # (🯹; 🯹; 🯹; 9; 9; ) SEGMENTED DIGIT NINE +2F800;4E3D;4E3D;4E3D;4E3D; # (丽; 丽; 丽; 丽; 丽; ) CJK COMPATIBILITY IDEOGRAPH-2F800 +2F801;4E38;4E38;4E38;4E38; # (丸; 丸; 丸; 丸; 丸; ) CJK COMPATIBILITY IDEOGRAPH-2F801 +2F802;4E41;4E41;4E41;4E41; # (乁; 乁; 乁; 乁; 乁; ) CJK COMPATIBILITY IDEOGRAPH-2F802 +2F803;20122;20122;20122;20122; # (𠄢; 𠄢; 𠄢; 𠄢; 𠄢; ) CJK COMPATIBILITY IDEOGRAPH-2F803 +2F804;4F60;4F60;4F60;4F60; # (你; 你; 你; 你; 你; ) CJK COMPATIBILITY IDEOGRAPH-2F804 +2F805;4FAE;4FAE;4FAE;4FAE; # (侮; 侮; 侮; 侮; 侮; ) CJK COMPATIBILITY IDEOGRAPH-2F805 +2F806;4FBB;4FBB;4FBB;4FBB; # (侻; 侻; 侻; 侻; 侻; ) CJK COMPATIBILITY IDEOGRAPH-2F806 +2F807;5002;5002;5002;5002; # (倂; 倂; 倂; 倂; 倂; ) CJK COMPATIBILITY IDEOGRAPH-2F807 +2F808;507A;507A;507A;507A; # (偺; 偺; 偺; 偺; 偺; ) CJK COMPATIBILITY IDEOGRAPH-2F808 +2F809;5099;5099;5099;5099; # (備; 備; 備; 備; 備; ) CJK COMPATIBILITY IDEOGRAPH-2F809 +2F80A;50E7;50E7;50E7;50E7; # (僧; 僧; 僧; 僧; 僧; ) CJK COMPATIBILITY IDEOGRAPH-2F80A +2F80B;50CF;50CF;50CF;50CF; # (像; 像; 像; 像; 像; ) CJK COMPATIBILITY IDEOGRAPH-2F80B +2F80C;349E;349E;349E;349E; # (㒞; 㒞; 㒞; 㒞; 㒞; ) CJK COMPATIBILITY IDEOGRAPH-2F80C +2F80D;2063A;2063A;2063A;2063A; # (𠘺; 𠘺; 𠘺; 𠘺; 𠘺; ) CJK COMPATIBILITY IDEOGRAPH-2F80D +2F80E;514D;514D;514D;514D; # (免; 免; 免; 免; 免; ) CJK COMPATIBILITY IDEOGRAPH-2F80E +2F80F;5154;5154;5154;5154; # (兔; 兔; 兔; 兔; 兔; ) CJK COMPATIBILITY IDEOGRAPH-2F80F +2F810;5164;5164;5164;5164; # (兤; 兤; 兤; 兤; 兤; ) CJK COMPATIBILITY IDEOGRAPH-2F810 +2F811;5177;5177;5177;5177; # (具; 具; 具; 具; 具; ) CJK COMPATIBILITY IDEOGRAPH-2F811 +2F812;2051C;2051C;2051C;2051C; # (𠔜; 𠔜; 𠔜; 𠔜; 𠔜; ) CJK COMPATIBILITY IDEOGRAPH-2F812 +2F813;34B9;34B9;34B9;34B9; # (㒹; 㒹; 㒹; 㒹; 㒹; ) CJK COMPATIBILITY IDEOGRAPH-2F813 +2F814;5167;5167;5167;5167; # (內; 內; 內; 內; 內; ) CJK COMPATIBILITY IDEOGRAPH-2F814 +2F815;518D;518D;518D;518D; # (再; 再; 再; 再; 再; ) CJK COMPATIBILITY IDEOGRAPH-2F815 +2F816;2054B;2054B;2054B;2054B; # (𠕋; 𠕋; 𠕋; 𠕋; 𠕋; ) CJK COMPATIBILITY IDEOGRAPH-2F816 +2F817;5197;5197;5197;5197; # (冗; 冗; 冗; 冗; 冗; ) CJK COMPATIBILITY IDEOGRAPH-2F817 +2F818;51A4;51A4;51A4;51A4; # (冤; 冤; 冤; 冤; 冤; ) CJK COMPATIBILITY IDEOGRAPH-2F818 +2F819;4ECC;4ECC;4ECC;4ECC; # (仌; 仌; 仌; 仌; 仌; ) CJK COMPATIBILITY IDEOGRAPH-2F819 +2F81A;51AC;51AC;51AC;51AC; # (冬; 冬; 冬; 冬; 冬; ) CJK COMPATIBILITY IDEOGRAPH-2F81A +2F81B;51B5;51B5;51B5;51B5; # (况; 况; 况; 况; 况; ) CJK COMPATIBILITY IDEOGRAPH-2F81B +2F81C;291DF;291DF;291DF;291DF; # (𩇟; 𩇟; 𩇟; 𩇟; 𩇟; ) CJK COMPATIBILITY IDEOGRAPH-2F81C +2F81D;51F5;51F5;51F5;51F5; # (凵; 凵; 凵; 凵; 凵; ) CJK COMPATIBILITY IDEOGRAPH-2F81D +2F81E;5203;5203;5203;5203; # (刃; 刃; 刃; 刃; 刃; ) CJK COMPATIBILITY IDEOGRAPH-2F81E +2F81F;34DF;34DF;34DF;34DF; # (㓟; 㓟; 㓟; 㓟; 㓟; ) CJK COMPATIBILITY IDEOGRAPH-2F81F +2F820;523B;523B;523B;523B; # (刻; 刻; 刻; 刻; 刻; ) CJK COMPATIBILITY IDEOGRAPH-2F820 +2F821;5246;5246;5246;5246; # (剆; 剆; 剆; 剆; 剆; ) CJK COMPATIBILITY IDEOGRAPH-2F821 +2F822;5272;5272;5272;5272; # (割; 割; 割; 割; 割; ) CJK COMPATIBILITY IDEOGRAPH-2F822 +2F823;5277;5277;5277;5277; # (剷; 剷; 剷; 剷; 剷; ) CJK COMPATIBILITY IDEOGRAPH-2F823 +2F824;3515;3515;3515;3515; # (㔕; 㔕; 㔕; 㔕; 㔕; ) CJK COMPATIBILITY IDEOGRAPH-2F824 +2F825;52C7;52C7;52C7;52C7; # (勇; 勇; 勇; 勇; 勇; ) CJK COMPATIBILITY IDEOGRAPH-2F825 +2F826;52C9;52C9;52C9;52C9; # (勉; 勉; 勉; 勉; 勉; ) CJK COMPATIBILITY IDEOGRAPH-2F826 +2F827;52E4;52E4;52E4;52E4; # (勤; 勤; 勤; 勤; 勤; ) CJK COMPATIBILITY IDEOGRAPH-2F827 +2F828;52FA;52FA;52FA;52FA; # (勺; 勺; 勺; 勺; 勺; ) CJK COMPATIBILITY IDEOGRAPH-2F828 +2F829;5305;5305;5305;5305; # (包; 包; 包; 包; 包; ) CJK COMPATIBILITY IDEOGRAPH-2F829 +2F82A;5306;5306;5306;5306; # (匆; 匆; 匆; 匆; 匆; ) CJK COMPATIBILITY IDEOGRAPH-2F82A +2F82B;5317;5317;5317;5317; # (北; 北; 北; 北; 北; ) CJK COMPATIBILITY IDEOGRAPH-2F82B +2F82C;5349;5349;5349;5349; # (卉; 卉; 卉; 卉; 卉; ) CJK COMPATIBILITY IDEOGRAPH-2F82C +2F82D;5351;5351;5351;5351; # (卑; 卑; 卑; 卑; 卑; ) CJK COMPATIBILITY IDEOGRAPH-2F82D +2F82E;535A;535A;535A;535A; # (博; 博; 博; 博; 博; ) CJK COMPATIBILITY IDEOGRAPH-2F82E +2F82F;5373;5373;5373;5373; # (即; 即; 即; 即; 即; ) CJK COMPATIBILITY IDEOGRAPH-2F82F +2F830;537D;537D;537D;537D; # (卽; 卽; 卽; 卽; 卽; ) CJK COMPATIBILITY IDEOGRAPH-2F830 +2F831;537F;537F;537F;537F; # (卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F831 +2F832;537F;537F;537F;537F; # (卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F832 +2F833;537F;537F;537F;537F; # (卿; 卿; 卿; 卿; 卿; ) CJK COMPATIBILITY IDEOGRAPH-2F833 +2F834;20A2C;20A2C;20A2C;20A2C; # (𠨬; 𠨬; 𠨬; 𠨬; 𠨬; ) CJK COMPATIBILITY IDEOGRAPH-2F834 +2F835;7070;7070;7070;7070; # (灰; 灰; 灰; 灰; 灰; ) CJK COMPATIBILITY IDEOGRAPH-2F835 +2F836;53CA;53CA;53CA;53CA; # (及; 及; 及; 及; 及; ) CJK COMPATIBILITY IDEOGRAPH-2F836 +2F837;53DF;53DF;53DF;53DF; # (叟; 叟; 叟; 叟; 叟; ) CJK COMPATIBILITY IDEOGRAPH-2F837 +2F838;20B63;20B63;20B63;20B63; # (𠭣; 𠭣; 𠭣; 𠭣; 𠭣; ) CJK COMPATIBILITY IDEOGRAPH-2F838 +2F839;53EB;53EB;53EB;53EB; # (叫; 叫; 叫; 叫; 叫; ) CJK COMPATIBILITY IDEOGRAPH-2F839 +2F83A;53F1;53F1;53F1;53F1; # (叱; 叱; 叱; 叱; 叱; ) CJK COMPATIBILITY IDEOGRAPH-2F83A +2F83B;5406;5406;5406;5406; # (吆; 吆; 吆; 吆; 吆; ) CJK COMPATIBILITY IDEOGRAPH-2F83B +2F83C;549E;549E;549E;549E; # (咞; 咞; 咞; 咞; 咞; ) CJK COMPATIBILITY IDEOGRAPH-2F83C +2F83D;5438;5438;5438;5438; # (吸; 吸; 吸; 吸; 吸; ) CJK COMPATIBILITY IDEOGRAPH-2F83D +2F83E;5448;5448;5448;5448; # (呈; 呈; 呈; 呈; 呈; ) CJK COMPATIBILITY IDEOGRAPH-2F83E +2F83F;5468;5468;5468;5468; # (周; 周; 周; 周; 周; ) CJK COMPATIBILITY IDEOGRAPH-2F83F +2F840;54A2;54A2;54A2;54A2; # (咢; 咢; 咢; 咢; 咢; ) CJK COMPATIBILITY IDEOGRAPH-2F840 +2F841;54F6;54F6;54F6;54F6; # (哶; 哶; 哶; 哶; 哶; ) CJK COMPATIBILITY IDEOGRAPH-2F841 +2F842;5510;5510;5510;5510; # (唐; 唐; 唐; 唐; 唐; ) CJK COMPATIBILITY IDEOGRAPH-2F842 +2F843;5553;5553;5553;5553; # (啓; 啓; 啓; 啓; 啓; ) CJK COMPATIBILITY IDEOGRAPH-2F843 +2F844;5563;5563;5563;5563; # (啣; 啣; 啣; 啣; 啣; ) CJK COMPATIBILITY IDEOGRAPH-2F844 +2F845;5584;5584;5584;5584; # (善; 善; 善; 善; 善; ) CJK COMPATIBILITY IDEOGRAPH-2F845 +2F846;5584;5584;5584;5584; # (善; 善; 善; 善; 善; ) CJK COMPATIBILITY IDEOGRAPH-2F846 +2F847;5599;5599;5599;5599; # (喙; 喙; 喙; 喙; 喙; ) CJK COMPATIBILITY IDEOGRAPH-2F847 +2F848;55AB;55AB;55AB;55AB; # (喫; 喫; 喫; 喫; 喫; ) CJK COMPATIBILITY IDEOGRAPH-2F848 +2F849;55B3;55B3;55B3;55B3; # (喳; 喳; 喳; 喳; 喳; ) CJK COMPATIBILITY IDEOGRAPH-2F849 +2F84A;55C2;55C2;55C2;55C2; # (嗂; 嗂; 嗂; 嗂; 嗂; ) CJK COMPATIBILITY IDEOGRAPH-2F84A +2F84B;5716;5716;5716;5716; # (圖; 圖; 圖; 圖; 圖; ) CJK COMPATIBILITY IDEOGRAPH-2F84B +2F84C;5606;5606;5606;5606; # (嘆; 嘆; 嘆; 嘆; 嘆; ) CJK COMPATIBILITY IDEOGRAPH-2F84C +2F84D;5717;5717;5717;5717; # (圗; 圗; 圗; 圗; 圗; ) CJK COMPATIBILITY IDEOGRAPH-2F84D +2F84E;5651;5651;5651;5651; # (噑; 噑; 噑; 噑; 噑; ) CJK COMPATIBILITY IDEOGRAPH-2F84E +2F84F;5674;5674;5674;5674; # (噴; 噴; 噴; 噴; 噴; ) CJK COMPATIBILITY IDEOGRAPH-2F84F +2F850;5207;5207;5207;5207; # (切; 切; 切; 切; 切; ) CJK COMPATIBILITY IDEOGRAPH-2F850 +2F851;58EE;58EE;58EE;58EE; # (壮; 壮; 壮; 壮; 壮; ) CJK COMPATIBILITY IDEOGRAPH-2F851 +2F852;57CE;57CE;57CE;57CE; # (城; 城; 城; 城; 城; ) CJK COMPATIBILITY IDEOGRAPH-2F852 +2F853;57F4;57F4;57F4;57F4; # (埴; 埴; 埴; 埴; 埴; ) CJK COMPATIBILITY IDEOGRAPH-2F853 +2F854;580D;580D;580D;580D; # (堍; 堍; 堍; 堍; 堍; ) CJK COMPATIBILITY IDEOGRAPH-2F854 +2F855;578B;578B;578B;578B; # (型; 型; 型; 型; 型; ) CJK COMPATIBILITY IDEOGRAPH-2F855 +2F856;5832;5832;5832;5832; # (堲; 堲; 堲; 堲; 堲; ) CJK COMPATIBILITY IDEOGRAPH-2F856 +2F857;5831;5831;5831;5831; # (報; 報; 報; 報; 報; ) CJK COMPATIBILITY IDEOGRAPH-2F857 +2F858;58AC;58AC;58AC;58AC; # (墬; 墬; 墬; 墬; 墬; ) CJK COMPATIBILITY IDEOGRAPH-2F858 +2F859;214E4;214E4;214E4;214E4; # (𡓤; 𡓤; 𡓤; 𡓤; 𡓤; ) CJK COMPATIBILITY IDEOGRAPH-2F859 +2F85A;58F2;58F2;58F2;58F2; # (売; 売; 売; 売; 売; ) CJK COMPATIBILITY IDEOGRAPH-2F85A +2F85B;58F7;58F7;58F7;58F7; # (壷; 壷; 壷; 壷; 壷; ) CJK COMPATIBILITY IDEOGRAPH-2F85B +2F85C;5906;5906;5906;5906; # (夆; 夆; 夆; 夆; 夆; ) CJK COMPATIBILITY IDEOGRAPH-2F85C +2F85D;591A;591A;591A;591A; # (多; 多; 多; 多; 多; ) CJK COMPATIBILITY IDEOGRAPH-2F85D +2F85E;5922;5922;5922;5922; # (夢; 夢; 夢; 夢; 夢; ) CJK COMPATIBILITY IDEOGRAPH-2F85E +2F85F;5962;5962;5962;5962; # (奢; 奢; 奢; 奢; 奢; ) CJK COMPATIBILITY IDEOGRAPH-2F85F +2F860;216A8;216A8;216A8;216A8; # (𡚨; 𡚨; 𡚨; 𡚨; 𡚨; ) CJK COMPATIBILITY IDEOGRAPH-2F860 +2F861;216EA;216EA;216EA;216EA; # (𡛪; 𡛪; 𡛪; 𡛪; 𡛪; ) CJK COMPATIBILITY IDEOGRAPH-2F861 +2F862;59EC;59EC;59EC;59EC; # (姬; 姬; 姬; 姬; 姬; ) CJK COMPATIBILITY IDEOGRAPH-2F862 +2F863;5A1B;5A1B;5A1B;5A1B; # (娛; 娛; 娛; 娛; 娛; ) CJK COMPATIBILITY IDEOGRAPH-2F863 +2F864;5A27;5A27;5A27;5A27; # (娧; 娧; 娧; 娧; 娧; ) CJK COMPATIBILITY IDEOGRAPH-2F864 +2F865;59D8;59D8;59D8;59D8; # (姘; 姘; 姘; 姘; 姘; ) CJK COMPATIBILITY IDEOGRAPH-2F865 +2F866;5A66;5A66;5A66;5A66; # (婦; 婦; 婦; 婦; 婦; ) CJK COMPATIBILITY IDEOGRAPH-2F866 +2F867;36EE;36EE;36EE;36EE; # (㛮; 㛮; 㛮; 㛮; 㛮; ) CJK COMPATIBILITY IDEOGRAPH-2F867 +2F868;36FC;36FC;36FC;36FC; # (㛼; 㛼; 㛼; 㛼; 㛼; ) CJK COMPATIBILITY IDEOGRAPH-2F868 +2F869;5B08;5B08;5B08;5B08; # (嬈; 嬈; 嬈; 嬈; 嬈; ) CJK COMPATIBILITY IDEOGRAPH-2F869 +2F86A;5B3E;5B3E;5B3E;5B3E; # (嬾; 嬾; 嬾; 嬾; 嬾; ) CJK COMPATIBILITY IDEOGRAPH-2F86A +2F86B;5B3E;5B3E;5B3E;5B3E; # (嬾; 嬾; 嬾; 嬾; 嬾; ) CJK COMPATIBILITY IDEOGRAPH-2F86B +2F86C;219C8;219C8;219C8;219C8; # (𡧈; 𡧈; 𡧈; 𡧈; 𡧈; ) CJK COMPATIBILITY IDEOGRAPH-2F86C +2F86D;5BC3;5BC3;5BC3;5BC3; # (寃; 寃; 寃; 寃; 寃; ) CJK COMPATIBILITY IDEOGRAPH-2F86D +2F86E;5BD8;5BD8;5BD8;5BD8; # (寘; 寘; 寘; 寘; 寘; ) CJK COMPATIBILITY IDEOGRAPH-2F86E +2F86F;5BE7;5BE7;5BE7;5BE7; # (寧; 寧; 寧; 寧; 寧; ) CJK COMPATIBILITY IDEOGRAPH-2F86F +2F870;5BF3;5BF3;5BF3;5BF3; # (寳; 寳; 寳; 寳; 寳; ) CJK COMPATIBILITY IDEOGRAPH-2F870 +2F871;21B18;21B18;21B18;21B18; # (𡬘; 𡬘; 𡬘; 𡬘; 𡬘; ) CJK COMPATIBILITY IDEOGRAPH-2F871 +2F872;5BFF;5BFF;5BFF;5BFF; # (寿; 寿; 寿; 寿; 寿; ) CJK COMPATIBILITY IDEOGRAPH-2F872 +2F873;5C06;5C06;5C06;5C06; # (将; 将; 将; 将; 将; ) CJK COMPATIBILITY IDEOGRAPH-2F873 +2F874;5F53;5F53;5F53;5F53; # (当; 当; 当; 当; 当; ) CJK COMPATIBILITY IDEOGRAPH-2F874 +2F875;5C22;5C22;5C22;5C22; # (尢; 尢; 尢; 尢; 尢; ) CJK COMPATIBILITY IDEOGRAPH-2F875 +2F876;3781;3781;3781;3781; # (㞁; 㞁; 㞁; 㞁; 㞁; ) CJK COMPATIBILITY IDEOGRAPH-2F876 +2F877;5C60;5C60;5C60;5C60; # (屠; 屠; 屠; 屠; 屠; ) CJK COMPATIBILITY IDEOGRAPH-2F877 +2F878;5C6E;5C6E;5C6E;5C6E; # (屮; 屮; 屮; 屮; 屮; ) CJK COMPATIBILITY IDEOGRAPH-2F878 +2F879;5CC0;5CC0;5CC0;5CC0; # (峀; 峀; 峀; 峀; 峀; ) CJK COMPATIBILITY IDEOGRAPH-2F879 +2F87A;5C8D;5C8D;5C8D;5C8D; # (岍; 岍; 岍; 岍; 岍; ) CJK COMPATIBILITY IDEOGRAPH-2F87A +2F87B;21DE4;21DE4;21DE4;21DE4; # (𡷤; 𡷤; 𡷤; 𡷤; 𡷤; ) CJK COMPATIBILITY IDEOGRAPH-2F87B +2F87C;5D43;5D43;5D43;5D43; # (嵃; 嵃; 嵃; 嵃; 嵃; ) CJK COMPATIBILITY IDEOGRAPH-2F87C +2F87D;21DE6;21DE6;21DE6;21DE6; # (𡷦; 𡷦; 𡷦; 𡷦; 𡷦; ) CJK COMPATIBILITY IDEOGRAPH-2F87D +2F87E;5D6E;5D6E;5D6E;5D6E; # (嵮; 嵮; 嵮; 嵮; 嵮; ) CJK COMPATIBILITY IDEOGRAPH-2F87E +2F87F;5D6B;5D6B;5D6B;5D6B; # (嵫; 嵫; 嵫; 嵫; 嵫; ) CJK COMPATIBILITY IDEOGRAPH-2F87F +2F880;5D7C;5D7C;5D7C;5D7C; # (嵼; 嵼; 嵼; 嵼; 嵼; ) CJK COMPATIBILITY IDEOGRAPH-2F880 +2F881;5DE1;5DE1;5DE1;5DE1; # (巡; 巡; 巡; 巡; 巡; ) CJK COMPATIBILITY IDEOGRAPH-2F881 +2F882;5DE2;5DE2;5DE2;5DE2; # (巢; 巢; 巢; 巢; 巢; ) CJK COMPATIBILITY IDEOGRAPH-2F882 +2F883;382F;382F;382F;382F; # (㠯; 㠯; 㠯; 㠯; 㠯; ) CJK COMPATIBILITY IDEOGRAPH-2F883 +2F884;5DFD;5DFD;5DFD;5DFD; # (巽; 巽; 巽; 巽; 巽; ) CJK COMPATIBILITY IDEOGRAPH-2F884 +2F885;5E28;5E28;5E28;5E28; # (帨; 帨; 帨; 帨; 帨; ) CJK COMPATIBILITY IDEOGRAPH-2F885 +2F886;5E3D;5E3D;5E3D;5E3D; # (帽; 帽; 帽; 帽; 帽; ) CJK COMPATIBILITY IDEOGRAPH-2F886 +2F887;5E69;5E69;5E69;5E69; # (幩; 幩; 幩; 幩; 幩; ) CJK COMPATIBILITY IDEOGRAPH-2F887 +2F888;3862;3862;3862;3862; # (㡢; 㡢; 㡢; 㡢; 㡢; ) CJK COMPATIBILITY IDEOGRAPH-2F888 +2F889;22183;22183;22183;22183; # (𢆃; 𢆃; 𢆃; 𢆃; 𢆃; ) CJK COMPATIBILITY IDEOGRAPH-2F889 +2F88A;387C;387C;387C;387C; # (㡼; 㡼; 㡼; 㡼; 㡼; ) CJK COMPATIBILITY IDEOGRAPH-2F88A +2F88B;5EB0;5EB0;5EB0;5EB0; # (庰; 庰; 庰; 庰; 庰; ) CJK COMPATIBILITY IDEOGRAPH-2F88B +2F88C;5EB3;5EB3;5EB3;5EB3; # (庳; 庳; 庳; 庳; 庳; ) CJK COMPATIBILITY IDEOGRAPH-2F88C +2F88D;5EB6;5EB6;5EB6;5EB6; # (庶; 庶; 庶; 庶; 庶; ) CJK COMPATIBILITY IDEOGRAPH-2F88D +2F88E;5ECA;5ECA;5ECA;5ECA; # (廊; 廊; 廊; 廊; 廊; ) CJK COMPATIBILITY IDEOGRAPH-2F88E +2F88F;2A392;2A392;2A392;2A392; # (𪎒; 𪎒; 𪎒; 𪎒; 𪎒; ) CJK COMPATIBILITY IDEOGRAPH-2F88F +2F890;5EFE;5EFE;5EFE;5EFE; # (廾; 廾; 廾; 廾; 廾; ) CJK COMPATIBILITY IDEOGRAPH-2F890 +2F891;22331;22331;22331;22331; # (𢌱; 𢌱; 𢌱; 𢌱; 𢌱; ) CJK COMPATIBILITY IDEOGRAPH-2F891 +2F892;22331;22331;22331;22331; # (𢌱; 𢌱; 𢌱; 𢌱; 𢌱; ) CJK COMPATIBILITY IDEOGRAPH-2F892 +2F893;8201;8201;8201;8201; # (舁; 舁; 舁; 舁; 舁; ) CJK COMPATIBILITY IDEOGRAPH-2F893 +2F894;5F22;5F22;5F22;5F22; # (弢; 弢; 弢; 弢; 弢; ) CJK COMPATIBILITY IDEOGRAPH-2F894 +2F895;5F22;5F22;5F22;5F22; # (弢; 弢; 弢; 弢; 弢; ) CJK COMPATIBILITY IDEOGRAPH-2F895 +2F896;38C7;38C7;38C7;38C7; # (㣇; 㣇; 㣇; 㣇; 㣇; ) CJK COMPATIBILITY IDEOGRAPH-2F896 +2F897;232B8;232B8;232B8;232B8; # (𣊸; 𣊸; 𣊸; 𣊸; 𣊸; ) CJK COMPATIBILITY IDEOGRAPH-2F897 +2F898;261DA;261DA;261DA;261DA; # (𦇚; 𦇚; 𦇚; 𦇚; 𦇚; ) CJK COMPATIBILITY IDEOGRAPH-2F898 +2F899;5F62;5F62;5F62;5F62; # (形; 形; 形; 形; 形; ) CJK COMPATIBILITY IDEOGRAPH-2F899 +2F89A;5F6B;5F6B;5F6B;5F6B; # (彫; 彫; 彫; 彫; 彫; ) CJK COMPATIBILITY IDEOGRAPH-2F89A +2F89B;38E3;38E3;38E3;38E3; # (㣣; 㣣; 㣣; 㣣; 㣣; ) CJK COMPATIBILITY IDEOGRAPH-2F89B +2F89C;5F9A;5F9A;5F9A;5F9A; # (徚; 徚; 徚; 徚; 徚; ) CJK COMPATIBILITY IDEOGRAPH-2F89C +2F89D;5FCD;5FCD;5FCD;5FCD; # (忍; 忍; 忍; 忍; 忍; ) CJK COMPATIBILITY IDEOGRAPH-2F89D +2F89E;5FD7;5FD7;5FD7;5FD7; # (志; 志; 志; 志; 志; ) CJK COMPATIBILITY IDEOGRAPH-2F89E +2F89F;5FF9;5FF9;5FF9;5FF9; # (忹; 忹; 忹; 忹; 忹; ) CJK COMPATIBILITY IDEOGRAPH-2F89F +2F8A0;6081;6081;6081;6081; # (悁; 悁; 悁; 悁; 悁; ) CJK COMPATIBILITY IDEOGRAPH-2F8A0 +2F8A1;393A;393A;393A;393A; # (㤺; 㤺; 㤺; 㤺; 㤺; ) CJK COMPATIBILITY IDEOGRAPH-2F8A1 +2F8A2;391C;391C;391C;391C; # (㤜; 㤜; 㤜; 㤜; 㤜; ) CJK COMPATIBILITY IDEOGRAPH-2F8A2 +2F8A3;6094;6094;6094;6094; # (悔; 悔; 悔; 悔; 悔; ) CJK COMPATIBILITY IDEOGRAPH-2F8A3 +2F8A4;226D4;226D4;226D4;226D4; # (𢛔; 𢛔; 𢛔; 𢛔; 𢛔; ) CJK COMPATIBILITY IDEOGRAPH-2F8A4 +2F8A5;60C7;60C7;60C7;60C7; # (惇; 惇; 惇; 惇; 惇; ) CJK COMPATIBILITY IDEOGRAPH-2F8A5 +2F8A6;6148;6148;6148;6148; # (慈; 慈; 慈; 慈; 慈; ) CJK COMPATIBILITY IDEOGRAPH-2F8A6 +2F8A7;614C;614C;614C;614C; # (慌; 慌; 慌; 慌; 慌; ) CJK COMPATIBILITY IDEOGRAPH-2F8A7 +2F8A8;614E;614E;614E;614E; # (慎; 慎; 慎; 慎; 慎; ) CJK COMPATIBILITY IDEOGRAPH-2F8A8 +2F8A9;614C;614C;614C;614C; # (慌; 慌; 慌; 慌; 慌; ) CJK COMPATIBILITY IDEOGRAPH-2F8A9 +2F8AA;617A;617A;617A;617A; # (慺; 慺; 慺; 慺; 慺; ) CJK COMPATIBILITY IDEOGRAPH-2F8AA +2F8AB;618E;618E;618E;618E; # (憎; 憎; 憎; 憎; 憎; ) CJK COMPATIBILITY IDEOGRAPH-2F8AB +2F8AC;61B2;61B2;61B2;61B2; # (憲; 憲; 憲; 憲; 憲; ) CJK COMPATIBILITY IDEOGRAPH-2F8AC +2F8AD;61A4;61A4;61A4;61A4; # (憤; 憤; 憤; 憤; 憤; ) CJK COMPATIBILITY IDEOGRAPH-2F8AD +2F8AE;61AF;61AF;61AF;61AF; # (憯; 憯; 憯; 憯; 憯; ) CJK COMPATIBILITY IDEOGRAPH-2F8AE +2F8AF;61DE;61DE;61DE;61DE; # (懞; 懞; 懞; 懞; 懞; ) CJK COMPATIBILITY IDEOGRAPH-2F8AF +2F8B0;61F2;61F2;61F2;61F2; # (懲; 懲; 懲; 懲; 懲; ) CJK COMPATIBILITY IDEOGRAPH-2F8B0 +2F8B1;61F6;61F6;61F6;61F6; # (懶; 懶; 懶; 懶; 懶; ) CJK COMPATIBILITY IDEOGRAPH-2F8B1 +2F8B2;6210;6210;6210;6210; # (成; 成; 成; 成; 成; ) CJK COMPATIBILITY IDEOGRAPH-2F8B2 +2F8B3;621B;621B;621B;621B; # (戛; 戛; 戛; 戛; 戛; ) CJK COMPATIBILITY IDEOGRAPH-2F8B3 +2F8B4;625D;625D;625D;625D; # (扝; 扝; 扝; 扝; 扝; ) CJK COMPATIBILITY IDEOGRAPH-2F8B4 +2F8B5;62B1;62B1;62B1;62B1; # (抱; 抱; 抱; 抱; 抱; ) CJK COMPATIBILITY IDEOGRAPH-2F8B5 +2F8B6;62D4;62D4;62D4;62D4; # (拔; 拔; 拔; 拔; 拔; ) CJK COMPATIBILITY IDEOGRAPH-2F8B6 +2F8B7;6350;6350;6350;6350; # (捐; 捐; 捐; 捐; 捐; ) CJK COMPATIBILITY IDEOGRAPH-2F8B7 +2F8B8;22B0C;22B0C;22B0C;22B0C; # (𢬌; 𢬌; 𢬌; 𢬌; 𢬌; ) CJK COMPATIBILITY IDEOGRAPH-2F8B8 +2F8B9;633D;633D;633D;633D; # (挽; 挽; 挽; 挽; 挽; ) CJK COMPATIBILITY IDEOGRAPH-2F8B9 +2F8BA;62FC;62FC;62FC;62FC; # (拼; 拼; 拼; 拼; 拼; ) CJK COMPATIBILITY IDEOGRAPH-2F8BA +2F8BB;6368;6368;6368;6368; # (捨; 捨; 捨; 捨; 捨; ) CJK COMPATIBILITY IDEOGRAPH-2F8BB +2F8BC;6383;6383;6383;6383; # (掃; 掃; 掃; 掃; 掃; ) CJK COMPATIBILITY IDEOGRAPH-2F8BC +2F8BD;63E4;63E4;63E4;63E4; # (揤; 揤; 揤; 揤; 揤; ) CJK COMPATIBILITY IDEOGRAPH-2F8BD +2F8BE;22BF1;22BF1;22BF1;22BF1; # (𢯱; 𢯱; 𢯱; 𢯱; 𢯱; ) CJK COMPATIBILITY IDEOGRAPH-2F8BE +2F8BF;6422;6422;6422;6422; # (搢; 搢; 搢; 搢; 搢; ) CJK COMPATIBILITY IDEOGRAPH-2F8BF +2F8C0;63C5;63C5;63C5;63C5; # (揅; 揅; 揅; 揅; 揅; ) CJK COMPATIBILITY IDEOGRAPH-2F8C0 +2F8C1;63A9;63A9;63A9;63A9; # (掩; 掩; 掩; 掩; 掩; ) CJK COMPATIBILITY IDEOGRAPH-2F8C1 +2F8C2;3A2E;3A2E;3A2E;3A2E; # (㨮; 㨮; 㨮; 㨮; 㨮; ) CJK COMPATIBILITY IDEOGRAPH-2F8C2 +2F8C3;6469;6469;6469;6469; # (摩; 摩; 摩; 摩; 摩; ) CJK COMPATIBILITY IDEOGRAPH-2F8C3 +2F8C4;647E;647E;647E;647E; # (摾; 摾; 摾; 摾; 摾; ) CJK COMPATIBILITY IDEOGRAPH-2F8C4 +2F8C5;649D;649D;649D;649D; # (撝; 撝; 撝; 撝; 撝; ) CJK COMPATIBILITY IDEOGRAPH-2F8C5 +2F8C6;6477;6477;6477;6477; # (摷; 摷; 摷; 摷; 摷; ) CJK COMPATIBILITY IDEOGRAPH-2F8C6 +2F8C7;3A6C;3A6C;3A6C;3A6C; # (㩬; 㩬; 㩬; 㩬; 㩬; ) CJK COMPATIBILITY IDEOGRAPH-2F8C7 +2F8C8;654F;654F;654F;654F; # (敏; 敏; 敏; 敏; 敏; ) CJK COMPATIBILITY IDEOGRAPH-2F8C8 +2F8C9;656C;656C;656C;656C; # (敬; 敬; 敬; 敬; 敬; ) CJK COMPATIBILITY IDEOGRAPH-2F8C9 +2F8CA;2300A;2300A;2300A;2300A; # (𣀊; 𣀊; 𣀊; 𣀊; 𣀊; ) CJK COMPATIBILITY IDEOGRAPH-2F8CA +2F8CB;65E3;65E3;65E3;65E3; # (旣; 旣; 旣; 旣; 旣; ) CJK COMPATIBILITY IDEOGRAPH-2F8CB +2F8CC;66F8;66F8;66F8;66F8; # (書; 書; 書; 書; 書; ) CJK COMPATIBILITY IDEOGRAPH-2F8CC +2F8CD;6649;6649;6649;6649; # (晉; 晉; 晉; 晉; 晉; ) CJK COMPATIBILITY IDEOGRAPH-2F8CD +2F8CE;3B19;3B19;3B19;3B19; # (㬙; 㬙; 㬙; 㬙; 㬙; ) CJK COMPATIBILITY IDEOGRAPH-2F8CE +2F8CF;6691;6691;6691;6691; # (暑; 暑; 暑; 暑; 暑; ) CJK COMPATIBILITY IDEOGRAPH-2F8CF +2F8D0;3B08;3B08;3B08;3B08; # (㬈; 㬈; 㬈; 㬈; 㬈; ) CJK COMPATIBILITY IDEOGRAPH-2F8D0 +2F8D1;3AE4;3AE4;3AE4;3AE4; # (㫤; 㫤; 㫤; 㫤; 㫤; ) CJK COMPATIBILITY IDEOGRAPH-2F8D1 +2F8D2;5192;5192;5192;5192; # (冒; 冒; 冒; 冒; 冒; ) CJK COMPATIBILITY IDEOGRAPH-2F8D2 +2F8D3;5195;5195;5195;5195; # (冕; 冕; 冕; 冕; 冕; ) CJK COMPATIBILITY IDEOGRAPH-2F8D3 +2F8D4;6700;6700;6700;6700; # (最; 最; 最; 最; 最; ) CJK COMPATIBILITY IDEOGRAPH-2F8D4 +2F8D5;669C;669C;669C;669C; # (暜; 暜; 暜; 暜; 暜; ) CJK COMPATIBILITY IDEOGRAPH-2F8D5 +2F8D6;80AD;80AD;80AD;80AD; # (肭; 肭; 肭; 肭; 肭; ) CJK COMPATIBILITY IDEOGRAPH-2F8D6 +2F8D7;43D9;43D9;43D9;43D9; # (䏙; 䏙; 䏙; 䏙; 䏙; ) CJK COMPATIBILITY IDEOGRAPH-2F8D7 +2F8D8;6717;6717;6717;6717; # (朗; 朗; 朗; 朗; 朗; ) CJK COMPATIBILITY IDEOGRAPH-2F8D8 +2F8D9;671B;671B;671B;671B; # (望; 望; 望; 望; 望; ) CJK COMPATIBILITY IDEOGRAPH-2F8D9 +2F8DA;6721;6721;6721;6721; # (朡; 朡; 朡; 朡; 朡; ) CJK COMPATIBILITY IDEOGRAPH-2F8DA +2F8DB;675E;675E;675E;675E; # (杞; 杞; 杞; 杞; 杞; ) CJK COMPATIBILITY IDEOGRAPH-2F8DB +2F8DC;6753;6753;6753;6753; # (杓; 杓; 杓; 杓; 杓; ) CJK COMPATIBILITY IDEOGRAPH-2F8DC +2F8DD;233C3;233C3;233C3;233C3; # (𣏃; 𣏃; 𣏃; 𣏃; 𣏃; ) CJK COMPATIBILITY IDEOGRAPH-2F8DD +2F8DE;3B49;3B49;3B49;3B49; # (㭉; 㭉; 㭉; 㭉; 㭉; ) CJK COMPATIBILITY IDEOGRAPH-2F8DE +2F8DF;67FA;67FA;67FA;67FA; # (柺; 柺; 柺; 柺; 柺; ) CJK COMPATIBILITY IDEOGRAPH-2F8DF +2F8E0;6785;6785;6785;6785; # (枅; 枅; 枅; 枅; 枅; ) CJK COMPATIBILITY IDEOGRAPH-2F8E0 +2F8E1;6852;6852;6852;6852; # (桒; 桒; 桒; 桒; 桒; ) CJK COMPATIBILITY IDEOGRAPH-2F8E1 +2F8E2;6885;6885;6885;6885; # (梅; 梅; 梅; 梅; 梅; ) CJK COMPATIBILITY IDEOGRAPH-2F8E2 +2F8E3;2346D;2346D;2346D;2346D; # (𣑭; 𣑭; 𣑭; 𣑭; 𣑭; ) CJK COMPATIBILITY IDEOGRAPH-2F8E3 +2F8E4;688E;688E;688E;688E; # (梎; 梎; 梎; 梎; 梎; ) CJK COMPATIBILITY IDEOGRAPH-2F8E4 +2F8E5;681F;681F;681F;681F; # (栟; 栟; 栟; 栟; 栟; ) CJK COMPATIBILITY IDEOGRAPH-2F8E5 +2F8E6;6914;6914;6914;6914; # (椔; 椔; 椔; 椔; 椔; ) CJK COMPATIBILITY IDEOGRAPH-2F8E6 +2F8E7;3B9D;3B9D;3B9D;3B9D; # (㮝; 㮝; 㮝; 㮝; 㮝; ) CJK COMPATIBILITY IDEOGRAPH-2F8E7 +2F8E8;6942;6942;6942;6942; # (楂; 楂; 楂; 楂; 楂; ) CJK COMPATIBILITY IDEOGRAPH-2F8E8 +2F8E9;69A3;69A3;69A3;69A3; # (榣; 榣; 榣; 榣; 榣; ) CJK COMPATIBILITY IDEOGRAPH-2F8E9 +2F8EA;69EA;69EA;69EA;69EA; # (槪; 槪; 槪; 槪; 槪; ) CJK COMPATIBILITY IDEOGRAPH-2F8EA +2F8EB;6AA8;6AA8;6AA8;6AA8; # (檨; 檨; 檨; 檨; 檨; ) CJK COMPATIBILITY IDEOGRAPH-2F8EB +2F8EC;236A3;236A3;236A3;236A3; # (𣚣; 𣚣; 𣚣; 𣚣; 𣚣; ) CJK COMPATIBILITY IDEOGRAPH-2F8EC +2F8ED;6ADB;6ADB;6ADB;6ADB; # (櫛; 櫛; 櫛; 櫛; 櫛; ) CJK COMPATIBILITY IDEOGRAPH-2F8ED +2F8EE;3C18;3C18;3C18;3C18; # (㰘; 㰘; 㰘; 㰘; 㰘; ) CJK COMPATIBILITY IDEOGRAPH-2F8EE +2F8EF;6B21;6B21;6B21;6B21; # (次; 次; 次; 次; 次; ) CJK COMPATIBILITY IDEOGRAPH-2F8EF +2F8F0;238A7;238A7;238A7;238A7; # (𣢧; 𣢧; 𣢧; 𣢧; 𣢧; ) CJK COMPATIBILITY IDEOGRAPH-2F8F0 +2F8F1;6B54;6B54;6B54;6B54; # (歔; 歔; 歔; 歔; 歔; ) CJK COMPATIBILITY IDEOGRAPH-2F8F1 +2F8F2;3C4E;3C4E;3C4E;3C4E; # (㱎; 㱎; 㱎; 㱎; 㱎; ) CJK COMPATIBILITY IDEOGRAPH-2F8F2 +2F8F3;6B72;6B72;6B72;6B72; # (歲; 歲; 歲; 歲; 歲; ) CJK COMPATIBILITY IDEOGRAPH-2F8F3 +2F8F4;6B9F;6B9F;6B9F;6B9F; # (殟; 殟; 殟; 殟; 殟; ) CJK COMPATIBILITY IDEOGRAPH-2F8F4 +2F8F5;6BBA;6BBA;6BBA;6BBA; # (殺; 殺; 殺; 殺; 殺; ) CJK COMPATIBILITY IDEOGRAPH-2F8F5 +2F8F6;6BBB;6BBB;6BBB;6BBB; # (殻; 殻; 殻; 殻; 殻; ) CJK COMPATIBILITY IDEOGRAPH-2F8F6 +2F8F7;23A8D;23A8D;23A8D;23A8D; # (𣪍; 𣪍; 𣪍; 𣪍; 𣪍; ) CJK COMPATIBILITY IDEOGRAPH-2F8F7 +2F8F8;21D0B;21D0B;21D0B;21D0B; # (𡴋; 𡴋; 𡴋; 𡴋; 𡴋; ) CJK COMPATIBILITY IDEOGRAPH-2F8F8 +2F8F9;23AFA;23AFA;23AFA;23AFA; # (𣫺; 𣫺; 𣫺; 𣫺; 𣫺; ) CJK COMPATIBILITY IDEOGRAPH-2F8F9 +2F8FA;6C4E;6C4E;6C4E;6C4E; # (汎; 汎; 汎; 汎; 汎; ) CJK COMPATIBILITY IDEOGRAPH-2F8FA +2F8FB;23CBC;23CBC;23CBC;23CBC; # (𣲼; 𣲼; 𣲼; 𣲼; 𣲼; ) CJK COMPATIBILITY IDEOGRAPH-2F8FB +2F8FC;6CBF;6CBF;6CBF;6CBF; # (沿; 沿; 沿; 沿; 沿; ) CJK COMPATIBILITY IDEOGRAPH-2F8FC +2F8FD;6CCD;6CCD;6CCD;6CCD; # (泍; 泍; 泍; 泍; 泍; ) CJK COMPATIBILITY IDEOGRAPH-2F8FD +2F8FE;6C67;6C67;6C67;6C67; # (汧; 汧; 汧; 汧; 汧; ) CJK COMPATIBILITY IDEOGRAPH-2F8FE +2F8FF;6D16;6D16;6D16;6D16; # (洖; 洖; 洖; 洖; 洖; ) CJK COMPATIBILITY IDEOGRAPH-2F8FF +2F900;6D3E;6D3E;6D3E;6D3E; # (派; 派; 派; 派; 派; ) CJK COMPATIBILITY IDEOGRAPH-2F900 +2F901;6D77;6D77;6D77;6D77; # (海; 海; 海; 海; 海; ) CJK COMPATIBILITY IDEOGRAPH-2F901 +2F902;6D41;6D41;6D41;6D41; # (流; 流; 流; 流; 流; ) CJK COMPATIBILITY IDEOGRAPH-2F902 +2F903;6D69;6D69;6D69;6D69; # (浩; 浩; 浩; 浩; 浩; ) CJK COMPATIBILITY IDEOGRAPH-2F903 +2F904;6D78;6D78;6D78;6D78; # (浸; 浸; 浸; 浸; 浸; ) CJK COMPATIBILITY IDEOGRAPH-2F904 +2F905;6D85;6D85;6D85;6D85; # (涅; 涅; 涅; 涅; 涅; ) CJK COMPATIBILITY IDEOGRAPH-2F905 +2F906;23D1E;23D1E;23D1E;23D1E; # (𣴞; 𣴞; 𣴞; 𣴞; 𣴞; ) CJK COMPATIBILITY IDEOGRAPH-2F906 +2F907;6D34;6D34;6D34;6D34; # (洴; 洴; 洴; 洴; 洴; ) CJK COMPATIBILITY IDEOGRAPH-2F907 +2F908;6E2F;6E2F;6E2F;6E2F; # (港; 港; 港; 港; 港; ) CJK COMPATIBILITY IDEOGRAPH-2F908 +2F909;6E6E;6E6E;6E6E;6E6E; # (湮; 湮; 湮; 湮; 湮; ) CJK COMPATIBILITY IDEOGRAPH-2F909 +2F90A;3D33;3D33;3D33;3D33; # (㴳; 㴳; 㴳; 㴳; 㴳; ) CJK COMPATIBILITY IDEOGRAPH-2F90A +2F90B;6ECB;6ECB;6ECB;6ECB; # (滋; 滋; 滋; 滋; 滋; ) CJK COMPATIBILITY IDEOGRAPH-2F90B +2F90C;6EC7;6EC7;6EC7;6EC7; # (滇; 滇; 滇; 滇; 滇; ) CJK COMPATIBILITY IDEOGRAPH-2F90C +2F90D;23ED1;23ED1;23ED1;23ED1; # (𣻑; 𣻑; 𣻑; 𣻑; 𣻑; ) CJK COMPATIBILITY IDEOGRAPH-2F90D +2F90E;6DF9;6DF9;6DF9;6DF9; # (淹; 淹; 淹; 淹; 淹; ) CJK COMPATIBILITY IDEOGRAPH-2F90E +2F90F;6F6E;6F6E;6F6E;6F6E; # (潮; 潮; 潮; 潮; 潮; ) CJK COMPATIBILITY IDEOGRAPH-2F90F +2F910;23F5E;23F5E;23F5E;23F5E; # (𣽞; 𣽞; 𣽞; 𣽞; 𣽞; ) CJK COMPATIBILITY IDEOGRAPH-2F910 +2F911;23F8E;23F8E;23F8E;23F8E; # (𣾎; 𣾎; 𣾎; 𣾎; 𣾎; ) CJK COMPATIBILITY IDEOGRAPH-2F911 +2F912;6FC6;6FC6;6FC6;6FC6; # (濆; 濆; 濆; 濆; 濆; ) CJK COMPATIBILITY IDEOGRAPH-2F912 +2F913;7039;7039;7039;7039; # (瀹; 瀹; 瀹; 瀹; 瀹; ) CJK COMPATIBILITY IDEOGRAPH-2F913 +2F914;701E;701E;701E;701E; # (瀞; 瀞; 瀞; 瀞; 瀞; ) CJK COMPATIBILITY IDEOGRAPH-2F914 +2F915;701B;701B;701B;701B; # (瀛; 瀛; 瀛; 瀛; 瀛; ) CJK COMPATIBILITY IDEOGRAPH-2F915 +2F916;3D96;3D96;3D96;3D96; # (㶖; 㶖; 㶖; 㶖; 㶖; ) CJK COMPATIBILITY IDEOGRAPH-2F916 +2F917;704A;704A;704A;704A; # (灊; 灊; 灊; 灊; 灊; ) CJK COMPATIBILITY IDEOGRAPH-2F917 +2F918;707D;707D;707D;707D; # (災; 災; 災; 災; 災; ) CJK COMPATIBILITY IDEOGRAPH-2F918 +2F919;7077;7077;7077;7077; # (灷; 灷; 灷; 灷; 灷; ) CJK COMPATIBILITY IDEOGRAPH-2F919 +2F91A;70AD;70AD;70AD;70AD; # (炭; 炭; 炭; 炭; 炭; ) CJK COMPATIBILITY IDEOGRAPH-2F91A +2F91B;20525;20525;20525;20525; # (𠔥; 𠔥; 𠔥; 𠔥; 𠔥; ) CJK COMPATIBILITY IDEOGRAPH-2F91B +2F91C;7145;7145;7145;7145; # (煅; 煅; 煅; 煅; 煅; ) CJK COMPATIBILITY IDEOGRAPH-2F91C +2F91D;24263;24263;24263;24263; # (𤉣; 𤉣; 𤉣; 𤉣; 𤉣; ) CJK COMPATIBILITY IDEOGRAPH-2F91D +2F91E;719C;719C;719C;719C; # (熜; 熜; 熜; 熜; 熜; ) CJK COMPATIBILITY IDEOGRAPH-2F91E +2F91F;243AB;243AB;243AB;243AB; # (𤎫; 𤎫; 𤎫; 𤎫; 𤎫; ) CJK COMPATIBILITY IDEOGRAPH-2F91F +2F920;7228;7228;7228;7228; # (爨; 爨; 爨; 爨; 爨; ) CJK COMPATIBILITY IDEOGRAPH-2F920 +2F921;7235;7235;7235;7235; # (爵; 爵; 爵; 爵; 爵; ) CJK COMPATIBILITY IDEOGRAPH-2F921 +2F922;7250;7250;7250;7250; # (牐; 牐; 牐; 牐; 牐; ) CJK COMPATIBILITY IDEOGRAPH-2F922 +2F923;24608;24608;24608;24608; # (𤘈; 𤘈; 𤘈; 𤘈; 𤘈; ) CJK COMPATIBILITY IDEOGRAPH-2F923 +2F924;7280;7280;7280;7280; # (犀; 犀; 犀; 犀; 犀; ) CJK COMPATIBILITY IDEOGRAPH-2F924 +2F925;7295;7295;7295;7295; # (犕; 犕; 犕; 犕; 犕; ) CJK COMPATIBILITY IDEOGRAPH-2F925 +2F926;24735;24735;24735;24735; # (𤜵; 𤜵; 𤜵; 𤜵; 𤜵; ) CJK COMPATIBILITY IDEOGRAPH-2F926 +2F927;24814;24814;24814;24814; # (𤠔; 𤠔; 𤠔; 𤠔; 𤠔; ) CJK COMPATIBILITY IDEOGRAPH-2F927 +2F928;737A;737A;737A;737A; # (獺; 獺; 獺; 獺; 獺; ) CJK COMPATIBILITY IDEOGRAPH-2F928 +2F929;738B;738B;738B;738B; # (王; 王; 王; 王; 王; ) CJK COMPATIBILITY IDEOGRAPH-2F929 +2F92A;3EAC;3EAC;3EAC;3EAC; # (㺬; 㺬; 㺬; 㺬; 㺬; ) CJK COMPATIBILITY IDEOGRAPH-2F92A +2F92B;73A5;73A5;73A5;73A5; # (玥; 玥; 玥; 玥; 玥; ) CJK COMPATIBILITY IDEOGRAPH-2F92B +2F92C;3EB8;3EB8;3EB8;3EB8; # (㺸; 㺸; 㺸; 㺸; 㺸; ) CJK COMPATIBILITY IDEOGRAPH-2F92C +2F92D;3EB8;3EB8;3EB8;3EB8; # (㺸; 㺸; 㺸; 㺸; 㺸; ) CJK COMPATIBILITY IDEOGRAPH-2F92D +2F92E;7447;7447;7447;7447; # (瑇; 瑇; 瑇; 瑇; 瑇; ) CJK COMPATIBILITY IDEOGRAPH-2F92E +2F92F;745C;745C;745C;745C; # (瑜; 瑜; 瑜; 瑜; 瑜; ) CJK COMPATIBILITY IDEOGRAPH-2F92F +2F930;7471;7471;7471;7471; # (瑱; 瑱; 瑱; 瑱; 瑱; ) CJK COMPATIBILITY IDEOGRAPH-2F930 +2F931;7485;7485;7485;7485; # (璅; 璅; 璅; 璅; 璅; ) CJK COMPATIBILITY IDEOGRAPH-2F931 +2F932;74CA;74CA;74CA;74CA; # (瓊; 瓊; 瓊; 瓊; 瓊; ) CJK COMPATIBILITY IDEOGRAPH-2F932 +2F933;3F1B;3F1B;3F1B;3F1B; # (㼛; 㼛; 㼛; 㼛; 㼛; ) CJK COMPATIBILITY IDEOGRAPH-2F933 +2F934;7524;7524;7524;7524; # (甤; 甤; 甤; 甤; 甤; ) CJK COMPATIBILITY IDEOGRAPH-2F934 +2F935;24C36;24C36;24C36;24C36; # (𤰶; 𤰶; 𤰶; 𤰶; 𤰶; ) CJK COMPATIBILITY IDEOGRAPH-2F935 +2F936;753E;753E;753E;753E; # (甾; 甾; 甾; 甾; 甾; ) CJK COMPATIBILITY IDEOGRAPH-2F936 +2F937;24C92;24C92;24C92;24C92; # (𤲒; 𤲒; 𤲒; 𤲒; 𤲒; ) CJK COMPATIBILITY IDEOGRAPH-2F937 +2F938;7570;7570;7570;7570; # (異; 異; 異; 異; 異; ) CJK COMPATIBILITY IDEOGRAPH-2F938 +2F939;2219F;2219F;2219F;2219F; # (𢆟; 𢆟; 𢆟; 𢆟; 𢆟; ) CJK COMPATIBILITY IDEOGRAPH-2F939 +2F93A;7610;7610;7610;7610; # (瘐; 瘐; 瘐; 瘐; 瘐; ) CJK COMPATIBILITY IDEOGRAPH-2F93A +2F93B;24FA1;24FA1;24FA1;24FA1; # (𤾡; 𤾡; 𤾡; 𤾡; 𤾡; ) CJK COMPATIBILITY IDEOGRAPH-2F93B +2F93C;24FB8;24FB8;24FB8;24FB8; # (𤾸; 𤾸; 𤾸; 𤾸; 𤾸; ) CJK COMPATIBILITY IDEOGRAPH-2F93C +2F93D;25044;25044;25044;25044; # (𥁄; 𥁄; 𥁄; 𥁄; 𥁄; ) CJK COMPATIBILITY IDEOGRAPH-2F93D +2F93E;3FFC;3FFC;3FFC;3FFC; # (㿼; 㿼; 㿼; 㿼; 㿼; ) CJK COMPATIBILITY IDEOGRAPH-2F93E +2F93F;4008;4008;4008;4008; # (䀈; 䀈; 䀈; 䀈; 䀈; ) CJK COMPATIBILITY IDEOGRAPH-2F93F +2F940;76F4;76F4;76F4;76F4; # (直; 直; 直; 直; 直; ) CJK COMPATIBILITY IDEOGRAPH-2F940 +2F941;250F3;250F3;250F3;250F3; # (𥃳; 𥃳; 𥃳; 𥃳; 𥃳; ) CJK COMPATIBILITY IDEOGRAPH-2F941 +2F942;250F2;250F2;250F2;250F2; # (𥃲; 𥃲; 𥃲; 𥃲; 𥃲; ) CJK COMPATIBILITY IDEOGRAPH-2F942 +2F943;25119;25119;25119;25119; # (𥄙; 𥄙; 𥄙; 𥄙; 𥄙; ) CJK COMPATIBILITY IDEOGRAPH-2F943 +2F944;25133;25133;25133;25133; # (𥄳; 𥄳; 𥄳; 𥄳; 𥄳; ) CJK COMPATIBILITY IDEOGRAPH-2F944 +2F945;771E;771E;771E;771E; # (眞; 眞; 眞; 眞; 眞; ) CJK COMPATIBILITY IDEOGRAPH-2F945 +2F946;771F;771F;771F;771F; # (真; 真; 真; 真; 真; ) CJK COMPATIBILITY IDEOGRAPH-2F946 +2F947;771F;771F;771F;771F; # (真; 真; 真; 真; 真; ) CJK COMPATIBILITY IDEOGRAPH-2F947 +2F948;774A;774A;774A;774A; # (睊; 睊; 睊; 睊; 睊; ) CJK COMPATIBILITY IDEOGRAPH-2F948 +2F949;4039;4039;4039;4039; # (䀹; 䀹; 䀹; 䀹; 䀹; ) CJK COMPATIBILITY IDEOGRAPH-2F949 +2F94A;778B;778B;778B;778B; # (瞋; 瞋; 瞋; 瞋; 瞋; ) CJK COMPATIBILITY IDEOGRAPH-2F94A +2F94B;4046;4046;4046;4046; # (䁆; 䁆; 䁆; 䁆; 䁆; ) CJK COMPATIBILITY IDEOGRAPH-2F94B +2F94C;4096;4096;4096;4096; # (䂖; 䂖; 䂖; 䂖; 䂖; ) CJK COMPATIBILITY IDEOGRAPH-2F94C +2F94D;2541D;2541D;2541D;2541D; # (𥐝; 𥐝; 𥐝; 𥐝; 𥐝; ) CJK COMPATIBILITY IDEOGRAPH-2F94D +2F94E;784E;784E;784E;784E; # (硎; 硎; 硎; 硎; 硎; ) CJK COMPATIBILITY IDEOGRAPH-2F94E +2F94F;788C;788C;788C;788C; # (碌; 碌; 碌; 碌; 碌; ) CJK COMPATIBILITY IDEOGRAPH-2F94F +2F950;78CC;78CC;78CC;78CC; # (磌; 磌; 磌; 磌; 磌; ) CJK COMPATIBILITY IDEOGRAPH-2F950 +2F951;40E3;40E3;40E3;40E3; # (䃣; 䃣; 䃣; 䃣; 䃣; ) CJK COMPATIBILITY IDEOGRAPH-2F951 +2F952;25626;25626;25626;25626; # (𥘦; 𥘦; 𥘦; 𥘦; 𥘦; ) CJK COMPATIBILITY IDEOGRAPH-2F952 +2F953;7956;7956;7956;7956; # (祖; 祖; 祖; 祖; 祖; ) CJK COMPATIBILITY IDEOGRAPH-2F953 +2F954;2569A;2569A;2569A;2569A; # (𥚚; 𥚚; 𥚚; 𥚚; 𥚚; ) CJK COMPATIBILITY IDEOGRAPH-2F954 +2F955;256C5;256C5;256C5;256C5; # (𥛅; 𥛅; 𥛅; 𥛅; 𥛅; ) CJK COMPATIBILITY IDEOGRAPH-2F955 +2F956;798F;798F;798F;798F; # (福; 福; 福; 福; 福; ) CJK COMPATIBILITY IDEOGRAPH-2F956 +2F957;79EB;79EB;79EB;79EB; # (秫; 秫; 秫; 秫; 秫; ) CJK COMPATIBILITY IDEOGRAPH-2F957 +2F958;412F;412F;412F;412F; # (䄯; 䄯; 䄯; 䄯; 䄯; ) CJK COMPATIBILITY IDEOGRAPH-2F958 +2F959;7A40;7A40;7A40;7A40; # (穀; 穀; 穀; 穀; 穀; ) CJK COMPATIBILITY IDEOGRAPH-2F959 +2F95A;7A4A;7A4A;7A4A;7A4A; # (穊; 穊; 穊; 穊; 穊; ) CJK COMPATIBILITY IDEOGRAPH-2F95A +2F95B;7A4F;7A4F;7A4F;7A4F; # (穏; 穏; 穏; 穏; 穏; ) CJK COMPATIBILITY IDEOGRAPH-2F95B +2F95C;2597C;2597C;2597C;2597C; # (𥥼; 𥥼; 𥥼; 𥥼; 𥥼; ) CJK COMPATIBILITY IDEOGRAPH-2F95C +2F95D;25AA7;25AA7;25AA7;25AA7; # (𥪧; 𥪧; 𥪧; 𥪧; 𥪧; ) CJK COMPATIBILITY IDEOGRAPH-2F95D +2F95E;25AA7;25AA7;25AA7;25AA7; # (𥪧; 𥪧; 𥪧; 𥪧; 𥪧; ) CJK COMPATIBILITY IDEOGRAPH-2F95E +2F95F;7AEE;7AEE;7AEE;7AEE; # (竮; 竮; 竮; 竮; 竮; ) CJK COMPATIBILITY IDEOGRAPH-2F95F +2F960;4202;4202;4202;4202; # (䈂; 䈂; 䈂; 䈂; 䈂; ) CJK COMPATIBILITY IDEOGRAPH-2F960 +2F961;25BAB;25BAB;25BAB;25BAB; # (𥮫; 𥮫; 𥮫; 𥮫; 𥮫; ) CJK COMPATIBILITY IDEOGRAPH-2F961 +2F962;7BC6;7BC6;7BC6;7BC6; # (篆; 篆; 篆; 篆; 篆; ) CJK COMPATIBILITY IDEOGRAPH-2F962 +2F963;7BC9;7BC9;7BC9;7BC9; # (築; 築; 築; 築; 築; ) CJK COMPATIBILITY IDEOGRAPH-2F963 +2F964;4227;4227;4227;4227; # (䈧; 䈧; 䈧; 䈧; 䈧; ) CJK COMPATIBILITY IDEOGRAPH-2F964 +2F965;25C80;25C80;25C80;25C80; # (𥲀; 𥲀; 𥲀; 𥲀; 𥲀; ) CJK COMPATIBILITY IDEOGRAPH-2F965 +2F966;7CD2;7CD2;7CD2;7CD2; # (糒; 糒; 糒; 糒; 糒; ) CJK COMPATIBILITY IDEOGRAPH-2F966 +2F967;42A0;42A0;42A0;42A0; # (䊠; 䊠; 䊠; 䊠; 䊠; ) CJK COMPATIBILITY IDEOGRAPH-2F967 +2F968;7CE8;7CE8;7CE8;7CE8; # (糨; 糨; 糨; 糨; 糨; ) CJK COMPATIBILITY IDEOGRAPH-2F968 +2F969;7CE3;7CE3;7CE3;7CE3; # (糣; 糣; 糣; 糣; 糣; ) CJK COMPATIBILITY IDEOGRAPH-2F969 +2F96A;7D00;7D00;7D00;7D00; # (紀; 紀; 紀; 紀; 紀; ) CJK COMPATIBILITY IDEOGRAPH-2F96A +2F96B;25F86;25F86;25F86;25F86; # (𥾆; 𥾆; 𥾆; 𥾆; 𥾆; ) CJK COMPATIBILITY IDEOGRAPH-2F96B +2F96C;7D63;7D63;7D63;7D63; # (絣; 絣; 絣; 絣; 絣; ) CJK COMPATIBILITY IDEOGRAPH-2F96C +2F96D;4301;4301;4301;4301; # (䌁; 䌁; 䌁; 䌁; 䌁; ) CJK COMPATIBILITY IDEOGRAPH-2F96D +2F96E;7DC7;7DC7;7DC7;7DC7; # (緇; 緇; 緇; 緇; 緇; ) CJK COMPATIBILITY IDEOGRAPH-2F96E +2F96F;7E02;7E02;7E02;7E02; # (縂; 縂; 縂; 縂; 縂; ) CJK COMPATIBILITY IDEOGRAPH-2F96F +2F970;7E45;7E45;7E45;7E45; # (繅; 繅; 繅; 繅; 繅; ) CJK COMPATIBILITY IDEOGRAPH-2F970 +2F971;4334;4334;4334;4334; # (䌴; 䌴; 䌴; 䌴; 䌴; ) CJK COMPATIBILITY IDEOGRAPH-2F971 +2F972;26228;26228;26228;26228; # (𦈨; 𦈨; 𦈨; 𦈨; 𦈨; ) CJK COMPATIBILITY IDEOGRAPH-2F972 +2F973;26247;26247;26247;26247; # (𦉇; 𦉇; 𦉇; 𦉇; 𦉇; ) CJK COMPATIBILITY IDEOGRAPH-2F973 +2F974;4359;4359;4359;4359; # (䍙; 䍙; 䍙; 䍙; 䍙; ) CJK COMPATIBILITY IDEOGRAPH-2F974 +2F975;262D9;262D9;262D9;262D9; # (𦋙; 𦋙; 𦋙; 𦋙; 𦋙; ) CJK COMPATIBILITY IDEOGRAPH-2F975 +2F976;7F7A;7F7A;7F7A;7F7A; # (罺; 罺; 罺; 罺; 罺; ) CJK COMPATIBILITY IDEOGRAPH-2F976 +2F977;2633E;2633E;2633E;2633E; # (𦌾; 𦌾; 𦌾; 𦌾; 𦌾; ) CJK COMPATIBILITY IDEOGRAPH-2F977 +2F978;7F95;7F95;7F95;7F95; # (羕; 羕; 羕; 羕; 羕; ) CJK COMPATIBILITY IDEOGRAPH-2F978 +2F979;7FFA;7FFA;7FFA;7FFA; # (翺; 翺; 翺; 翺; 翺; ) CJK COMPATIBILITY IDEOGRAPH-2F979 +2F97A;8005;8005;8005;8005; # (者; 者; 者; 者; 者; ) CJK COMPATIBILITY IDEOGRAPH-2F97A +2F97B;264DA;264DA;264DA;264DA; # (𦓚; 𦓚; 𦓚; 𦓚; 𦓚; ) CJK COMPATIBILITY IDEOGRAPH-2F97B +2F97C;26523;26523;26523;26523; # (𦔣; 𦔣; 𦔣; 𦔣; 𦔣; ) CJK COMPATIBILITY IDEOGRAPH-2F97C +2F97D;8060;8060;8060;8060; # (聠; 聠; 聠; 聠; 聠; ) CJK COMPATIBILITY IDEOGRAPH-2F97D +2F97E;265A8;265A8;265A8;265A8; # (𦖨; 𦖨; 𦖨; 𦖨; 𦖨; ) CJK COMPATIBILITY IDEOGRAPH-2F97E +2F97F;8070;8070;8070;8070; # (聰; 聰; 聰; 聰; 聰; ) CJK COMPATIBILITY IDEOGRAPH-2F97F +2F980;2335F;2335F;2335F;2335F; # (𣍟; 𣍟; 𣍟; 𣍟; 𣍟; ) CJK COMPATIBILITY IDEOGRAPH-2F980 +2F981;43D5;43D5;43D5;43D5; # (䏕; 䏕; 䏕; 䏕; 䏕; ) CJK COMPATIBILITY IDEOGRAPH-2F981 +2F982;80B2;80B2;80B2;80B2; # (育; 育; 育; 育; 育; ) CJK COMPATIBILITY IDEOGRAPH-2F982 +2F983;8103;8103;8103;8103; # (脃; 脃; 脃; 脃; 脃; ) CJK COMPATIBILITY IDEOGRAPH-2F983 +2F984;440B;440B;440B;440B; # (䐋; 䐋; 䐋; 䐋; 䐋; ) CJK COMPATIBILITY IDEOGRAPH-2F984 +2F985;813E;813E;813E;813E; # (脾; 脾; 脾; 脾; 脾; ) CJK COMPATIBILITY IDEOGRAPH-2F985 +2F986;5AB5;5AB5;5AB5;5AB5; # (媵; 媵; 媵; 媵; 媵; ) CJK COMPATIBILITY IDEOGRAPH-2F986 +2F987;267A7;267A7;267A7;267A7; # (𦞧; 𦞧; 𦞧; 𦞧; 𦞧; ) CJK COMPATIBILITY IDEOGRAPH-2F987 +2F988;267B5;267B5;267B5;267B5; # (𦞵; 𦞵; 𦞵; 𦞵; 𦞵; ) CJK COMPATIBILITY IDEOGRAPH-2F988 +2F989;23393;23393;23393;23393; # (𣎓; 𣎓; 𣎓; 𣎓; 𣎓; ) CJK COMPATIBILITY IDEOGRAPH-2F989 +2F98A;2339C;2339C;2339C;2339C; # (𣎜; 𣎜; 𣎜; 𣎜; 𣎜; ) CJK COMPATIBILITY IDEOGRAPH-2F98A +2F98B;8201;8201;8201;8201; # (舁; 舁; 舁; 舁; 舁; ) CJK COMPATIBILITY IDEOGRAPH-2F98B +2F98C;8204;8204;8204;8204; # (舄; 舄; 舄; 舄; 舄; ) CJK COMPATIBILITY IDEOGRAPH-2F98C +2F98D;8F9E;8F9E;8F9E;8F9E; # (辞; 辞; 辞; 辞; 辞; ) CJK COMPATIBILITY IDEOGRAPH-2F98D +2F98E;446B;446B;446B;446B; # (䑫; 䑫; 䑫; 䑫; 䑫; ) CJK COMPATIBILITY IDEOGRAPH-2F98E +2F98F;8291;8291;8291;8291; # (芑; 芑; 芑; 芑; 芑; ) CJK COMPATIBILITY IDEOGRAPH-2F98F +2F990;828B;828B;828B;828B; # (芋; 芋; 芋; 芋; 芋; ) CJK COMPATIBILITY IDEOGRAPH-2F990 +2F991;829D;829D;829D;829D; # (芝; 芝; 芝; 芝; 芝; ) CJK COMPATIBILITY IDEOGRAPH-2F991 +2F992;52B3;52B3;52B3;52B3; # (劳; 劳; 劳; 劳; 劳; ) CJK COMPATIBILITY IDEOGRAPH-2F992 +2F993;82B1;82B1;82B1;82B1; # (花; 花; 花; 花; 花; ) CJK COMPATIBILITY IDEOGRAPH-2F993 +2F994;82B3;82B3;82B3;82B3; # (芳; 芳; 芳; 芳; 芳; ) CJK COMPATIBILITY IDEOGRAPH-2F994 +2F995;82BD;82BD;82BD;82BD; # (芽; 芽; 芽; 芽; 芽; ) CJK COMPATIBILITY IDEOGRAPH-2F995 +2F996;82E6;82E6;82E6;82E6; # (苦; 苦; 苦; 苦; 苦; ) CJK COMPATIBILITY IDEOGRAPH-2F996 +2F997;26B3C;26B3C;26B3C;26B3C; # (𦬼; 𦬼; 𦬼; 𦬼; 𦬼; ) CJK COMPATIBILITY IDEOGRAPH-2F997 +2F998;82E5;82E5;82E5;82E5; # (若; 若; 若; 若; 若; ) CJK COMPATIBILITY IDEOGRAPH-2F998 +2F999;831D;831D;831D;831D; # (茝; 茝; 茝; 茝; 茝; ) CJK COMPATIBILITY IDEOGRAPH-2F999 +2F99A;8363;8363;8363;8363; # (荣; 荣; 荣; 荣; 荣; ) CJK COMPATIBILITY IDEOGRAPH-2F99A +2F99B;83AD;83AD;83AD;83AD; # (莭; 莭; 莭; 莭; 莭; ) CJK COMPATIBILITY IDEOGRAPH-2F99B +2F99C;8323;8323;8323;8323; # (茣; 茣; 茣; 茣; 茣; ) CJK COMPATIBILITY IDEOGRAPH-2F99C +2F99D;83BD;83BD;83BD;83BD; # (莽; 莽; 莽; 莽; 莽; ) CJK COMPATIBILITY IDEOGRAPH-2F99D +2F99E;83E7;83E7;83E7;83E7; # (菧; 菧; 菧; 菧; 菧; ) CJK COMPATIBILITY IDEOGRAPH-2F99E +2F99F;8457;8457;8457;8457; # (著; 著; 著; 著; 著; ) CJK COMPATIBILITY IDEOGRAPH-2F99F +2F9A0;8353;8353;8353;8353; # (荓; 荓; 荓; 荓; 荓; ) CJK COMPATIBILITY IDEOGRAPH-2F9A0 +2F9A1;83CA;83CA;83CA;83CA; # (菊; 菊; 菊; 菊; 菊; ) CJK COMPATIBILITY IDEOGRAPH-2F9A1 +2F9A2;83CC;83CC;83CC;83CC; # (菌; 菌; 菌; 菌; 菌; ) CJK COMPATIBILITY IDEOGRAPH-2F9A2 +2F9A3;83DC;83DC;83DC;83DC; # (菜; 菜; 菜; 菜; 菜; ) CJK COMPATIBILITY IDEOGRAPH-2F9A3 +2F9A4;26C36;26C36;26C36;26C36; # (𦰶; 𦰶; 𦰶; 𦰶; 𦰶; ) CJK COMPATIBILITY IDEOGRAPH-2F9A4 +2F9A5;26D6B;26D6B;26D6B;26D6B; # (𦵫; 𦵫; 𦵫; 𦵫; 𦵫; ) CJK COMPATIBILITY IDEOGRAPH-2F9A5 +2F9A6;26CD5;26CD5;26CD5;26CD5; # (𦳕; 𦳕; 𦳕; 𦳕; 𦳕; ) CJK COMPATIBILITY IDEOGRAPH-2F9A6 +2F9A7;452B;452B;452B;452B; # (䔫; 䔫; 䔫; 䔫; 䔫; ) CJK COMPATIBILITY IDEOGRAPH-2F9A7 +2F9A8;84F1;84F1;84F1;84F1; # (蓱; 蓱; 蓱; 蓱; 蓱; ) CJK COMPATIBILITY IDEOGRAPH-2F9A8 +2F9A9;84F3;84F3;84F3;84F3; # (蓳; 蓳; 蓳; 蓳; 蓳; ) CJK COMPATIBILITY IDEOGRAPH-2F9A9 +2F9AA;8516;8516;8516;8516; # (蔖; 蔖; 蔖; 蔖; 蔖; ) CJK COMPATIBILITY IDEOGRAPH-2F9AA +2F9AB;273CA;273CA;273CA;273CA; # (𧏊; 𧏊; 𧏊; 𧏊; 𧏊; ) CJK COMPATIBILITY IDEOGRAPH-2F9AB +2F9AC;8564;8564;8564;8564; # (蕤; 蕤; 蕤; 蕤; 蕤; ) CJK COMPATIBILITY IDEOGRAPH-2F9AC +2F9AD;26F2C;26F2C;26F2C;26F2C; # (𦼬; 𦼬; 𦼬; 𦼬; 𦼬; ) CJK COMPATIBILITY IDEOGRAPH-2F9AD +2F9AE;455D;455D;455D;455D; # (䕝; 䕝; 䕝; 䕝; 䕝; ) CJK COMPATIBILITY IDEOGRAPH-2F9AE +2F9AF;4561;4561;4561;4561; # (䕡; 䕡; 䕡; 䕡; 䕡; ) CJK COMPATIBILITY IDEOGRAPH-2F9AF +2F9B0;26FB1;26FB1;26FB1;26FB1; # (𦾱; 𦾱; 𦾱; 𦾱; 𦾱; ) CJK COMPATIBILITY IDEOGRAPH-2F9B0 +2F9B1;270D2;270D2;270D2;270D2; # (𧃒; 𧃒; 𧃒; 𧃒; 𧃒; ) CJK COMPATIBILITY IDEOGRAPH-2F9B1 +2F9B2;456B;456B;456B;456B; # (䕫; 䕫; 䕫; 䕫; 䕫; ) CJK COMPATIBILITY IDEOGRAPH-2F9B2 +2F9B3;8650;8650;8650;8650; # (虐; 虐; 虐; 虐; 虐; ) CJK COMPATIBILITY IDEOGRAPH-2F9B3 +2F9B4;865C;865C;865C;865C; # (虜; 虜; 虜; 虜; 虜; ) CJK COMPATIBILITY IDEOGRAPH-2F9B4 +2F9B5;8667;8667;8667;8667; # (虧; 虧; 虧; 虧; 虧; ) CJK COMPATIBILITY IDEOGRAPH-2F9B5 +2F9B6;8669;8669;8669;8669; # (虩; 虩; 虩; 虩; 虩; ) CJK COMPATIBILITY IDEOGRAPH-2F9B6 +2F9B7;86A9;86A9;86A9;86A9; # (蚩; 蚩; 蚩; 蚩; 蚩; ) CJK COMPATIBILITY IDEOGRAPH-2F9B7 +2F9B8;8688;8688;8688;8688; # (蚈; 蚈; 蚈; 蚈; 蚈; ) CJK COMPATIBILITY IDEOGRAPH-2F9B8 +2F9B9;870E;870E;870E;870E; # (蜎; 蜎; 蜎; 蜎; 蜎; ) CJK COMPATIBILITY IDEOGRAPH-2F9B9 +2F9BA;86E2;86E2;86E2;86E2; # (蛢; 蛢; 蛢; 蛢; 蛢; ) CJK COMPATIBILITY IDEOGRAPH-2F9BA +2F9BB;8779;8779;8779;8779; # (蝹; 蝹; 蝹; 蝹; 蝹; ) CJK COMPATIBILITY IDEOGRAPH-2F9BB +2F9BC;8728;8728;8728;8728; # (蜨; 蜨; 蜨; 蜨; 蜨; ) CJK COMPATIBILITY IDEOGRAPH-2F9BC +2F9BD;876B;876B;876B;876B; # (蝫; 蝫; 蝫; 蝫; 蝫; ) CJK COMPATIBILITY IDEOGRAPH-2F9BD +2F9BE;8786;8786;8786;8786; # (螆; 螆; 螆; 螆; 螆; ) CJK COMPATIBILITY IDEOGRAPH-2F9BE +2F9BF;45D7;45D7;45D7;45D7; # (䗗; 䗗; 䗗; 䗗; 䗗; ) CJK COMPATIBILITY IDEOGRAPH-2F9BF +2F9C0;87E1;87E1;87E1;87E1; # (蟡; 蟡; 蟡; 蟡; 蟡; ) CJK COMPATIBILITY IDEOGRAPH-2F9C0 +2F9C1;8801;8801;8801;8801; # (蠁; 蠁; 蠁; 蠁; 蠁; ) CJK COMPATIBILITY IDEOGRAPH-2F9C1 +2F9C2;45F9;45F9;45F9;45F9; # (䗹; 䗹; 䗹; 䗹; 䗹; ) CJK COMPATIBILITY IDEOGRAPH-2F9C2 +2F9C3;8860;8860;8860;8860; # (衠; 衠; 衠; 衠; 衠; ) CJK COMPATIBILITY IDEOGRAPH-2F9C3 +2F9C4;8863;8863;8863;8863; # (衣; 衣; 衣; 衣; 衣; ) CJK COMPATIBILITY IDEOGRAPH-2F9C4 +2F9C5;27667;27667;27667;27667; # (𧙧; 𧙧; 𧙧; 𧙧; 𧙧; ) CJK COMPATIBILITY IDEOGRAPH-2F9C5 +2F9C6;88D7;88D7;88D7;88D7; # (裗; 裗; 裗; 裗; 裗; ) CJK COMPATIBILITY IDEOGRAPH-2F9C6 +2F9C7;88DE;88DE;88DE;88DE; # (裞; 裞; 裞; 裞; 裞; ) CJK COMPATIBILITY IDEOGRAPH-2F9C7 +2F9C8;4635;4635;4635;4635; # (䘵; 䘵; 䘵; 䘵; 䘵; ) CJK COMPATIBILITY IDEOGRAPH-2F9C8 +2F9C9;88FA;88FA;88FA;88FA; # (裺; 裺; 裺; 裺; 裺; ) CJK COMPATIBILITY IDEOGRAPH-2F9C9 +2F9CA;34BB;34BB;34BB;34BB; # (㒻; 㒻; 㒻; 㒻; 㒻; ) CJK COMPATIBILITY IDEOGRAPH-2F9CA +2F9CB;278AE;278AE;278AE;278AE; # (𧢮; 𧢮; 𧢮; 𧢮; 𧢮; ) CJK COMPATIBILITY IDEOGRAPH-2F9CB +2F9CC;27966;27966;27966;27966; # (𧥦; 𧥦; 𧥦; 𧥦; 𧥦; ) CJK COMPATIBILITY IDEOGRAPH-2F9CC +2F9CD;46BE;46BE;46BE;46BE; # (䚾; 䚾; 䚾; 䚾; 䚾; ) CJK COMPATIBILITY IDEOGRAPH-2F9CD +2F9CE;46C7;46C7;46C7;46C7; # (䛇; 䛇; 䛇; 䛇; 䛇; ) CJK COMPATIBILITY IDEOGRAPH-2F9CE +2F9CF;8AA0;8AA0;8AA0;8AA0; # (誠; 誠; 誠; 誠; 誠; ) CJK COMPATIBILITY IDEOGRAPH-2F9CF +2F9D0;8AED;8AED;8AED;8AED; # (諭; 諭; 諭; 諭; 諭; ) CJK COMPATIBILITY IDEOGRAPH-2F9D0 +2F9D1;8B8A;8B8A;8B8A;8B8A; # (變; 變; 變; 變; 變; ) CJK COMPATIBILITY IDEOGRAPH-2F9D1 +2F9D2;8C55;8C55;8C55;8C55; # (豕; 豕; 豕; 豕; 豕; ) CJK COMPATIBILITY IDEOGRAPH-2F9D2 +2F9D3;27CA8;27CA8;27CA8;27CA8; # (𧲨; 𧲨; 𧲨; 𧲨; 𧲨; ) CJK COMPATIBILITY IDEOGRAPH-2F9D3 +2F9D4;8CAB;8CAB;8CAB;8CAB; # (貫; 貫; 貫; 貫; 貫; ) CJK COMPATIBILITY IDEOGRAPH-2F9D4 +2F9D5;8CC1;8CC1;8CC1;8CC1; # (賁; 賁; 賁; 賁; 賁; ) CJK COMPATIBILITY IDEOGRAPH-2F9D5 +2F9D6;8D1B;8D1B;8D1B;8D1B; # (贛; 贛; 贛; 贛; 贛; ) CJK COMPATIBILITY IDEOGRAPH-2F9D6 +2F9D7;8D77;8D77;8D77;8D77; # (起; 起; 起; 起; 起; ) CJK COMPATIBILITY IDEOGRAPH-2F9D7 +2F9D8;27F2F;27F2F;27F2F;27F2F; # (𧼯; 𧼯; 𧼯; 𧼯; 𧼯; ) CJK COMPATIBILITY IDEOGRAPH-2F9D8 +2F9D9;20804;20804;20804;20804; # (𠠄; 𠠄; 𠠄; 𠠄; 𠠄; ) CJK COMPATIBILITY IDEOGRAPH-2F9D9 +2F9DA;8DCB;8DCB;8DCB;8DCB; # (跋; 跋; 跋; 跋; 跋; ) CJK COMPATIBILITY IDEOGRAPH-2F9DA +2F9DB;8DBC;8DBC;8DBC;8DBC; # (趼; 趼; 趼; 趼; 趼; ) CJK COMPATIBILITY IDEOGRAPH-2F9DB +2F9DC;8DF0;8DF0;8DF0;8DF0; # (跰; 跰; 跰; 跰; 跰; ) CJK COMPATIBILITY IDEOGRAPH-2F9DC +2F9DD;208DE;208DE;208DE;208DE; # (𠣞; 𠣞; 𠣞; 𠣞; 𠣞; ) CJK COMPATIBILITY IDEOGRAPH-2F9DD +2F9DE;8ED4;8ED4;8ED4;8ED4; # (軔; 軔; 軔; 軔; 軔; ) CJK COMPATIBILITY IDEOGRAPH-2F9DE +2F9DF;8F38;8F38;8F38;8F38; # (輸; 輸; 輸; 輸; 輸; ) CJK COMPATIBILITY IDEOGRAPH-2F9DF +2F9E0;285D2;285D2;285D2;285D2; # (𨗒; 𨗒; 𨗒; 𨗒; 𨗒; ) CJK COMPATIBILITY IDEOGRAPH-2F9E0 +2F9E1;285ED;285ED;285ED;285ED; # (𨗭; 𨗭; 𨗭; 𨗭; 𨗭; ) CJK COMPATIBILITY IDEOGRAPH-2F9E1 +2F9E2;9094;9094;9094;9094; # (邔; 邔; 邔; 邔; 邔; ) CJK COMPATIBILITY IDEOGRAPH-2F9E2 +2F9E3;90F1;90F1;90F1;90F1; # (郱; 郱; 郱; 郱; 郱; ) CJK COMPATIBILITY IDEOGRAPH-2F9E3 +2F9E4;9111;9111;9111;9111; # (鄑; 鄑; 鄑; 鄑; 鄑; ) CJK COMPATIBILITY IDEOGRAPH-2F9E4 +2F9E5;2872E;2872E;2872E;2872E; # (𨜮; 𨜮; 𨜮; 𨜮; 𨜮; ) CJK COMPATIBILITY IDEOGRAPH-2F9E5 +2F9E6;911B;911B;911B;911B; # (鄛; 鄛; 鄛; 鄛; 鄛; ) CJK COMPATIBILITY IDEOGRAPH-2F9E6 +2F9E7;9238;9238;9238;9238; # (鈸; 鈸; 鈸; 鈸; 鈸; ) CJK COMPATIBILITY IDEOGRAPH-2F9E7 +2F9E8;92D7;92D7;92D7;92D7; # (鋗; 鋗; 鋗; 鋗; 鋗; ) CJK COMPATIBILITY IDEOGRAPH-2F9E8 +2F9E9;92D8;92D8;92D8;92D8; # (鋘; 鋘; 鋘; 鋘; 鋘; ) CJK COMPATIBILITY IDEOGRAPH-2F9E9 +2F9EA;927C;927C;927C;927C; # (鉼; 鉼; 鉼; 鉼; 鉼; ) CJK COMPATIBILITY IDEOGRAPH-2F9EA +2F9EB;93F9;93F9;93F9;93F9; # (鏹; 鏹; 鏹; 鏹; 鏹; ) CJK COMPATIBILITY IDEOGRAPH-2F9EB +2F9EC;9415;9415;9415;9415; # (鐕; 鐕; 鐕; 鐕; 鐕; ) CJK COMPATIBILITY IDEOGRAPH-2F9EC +2F9ED;28BFA;28BFA;28BFA;28BFA; # (𨯺; 𨯺; 𨯺; 𨯺; 𨯺; ) CJK COMPATIBILITY IDEOGRAPH-2F9ED +2F9EE;958B;958B;958B;958B; # (開; 開; 開; 開; 開; ) CJK COMPATIBILITY IDEOGRAPH-2F9EE +2F9EF;4995;4995;4995;4995; # (䦕; 䦕; 䦕; 䦕; 䦕; ) CJK COMPATIBILITY IDEOGRAPH-2F9EF +2F9F0;95B7;95B7;95B7;95B7; # (閷; 閷; 閷; 閷; 閷; ) CJK COMPATIBILITY IDEOGRAPH-2F9F0 +2F9F1;28D77;28D77;28D77;28D77; # (𨵷; 𨵷; 𨵷; 𨵷; 𨵷; ) CJK COMPATIBILITY IDEOGRAPH-2F9F1 +2F9F2;49E6;49E6;49E6;49E6; # (䧦; 䧦; 䧦; 䧦; 䧦; ) CJK COMPATIBILITY IDEOGRAPH-2F9F2 +2F9F3;96C3;96C3;96C3;96C3; # (雃; 雃; 雃; 雃; 雃; ) CJK COMPATIBILITY IDEOGRAPH-2F9F3 +2F9F4;5DB2;5DB2;5DB2;5DB2; # (嶲; 嶲; 嶲; 嶲; 嶲; ) CJK COMPATIBILITY IDEOGRAPH-2F9F4 +2F9F5;9723;9723;9723;9723; # (霣; 霣; 霣; 霣; 霣; ) CJK COMPATIBILITY IDEOGRAPH-2F9F5 +2F9F6;29145;29145;29145;29145; # (𩅅; 𩅅; 𩅅; 𩅅; 𩅅; ) CJK COMPATIBILITY IDEOGRAPH-2F9F6 +2F9F7;2921A;2921A;2921A;2921A; # (𩈚; 𩈚; 𩈚; 𩈚; 𩈚; ) CJK COMPATIBILITY IDEOGRAPH-2F9F7 +2F9F8;4A6E;4A6E;4A6E;4A6E; # (䩮; 䩮; 䩮; 䩮; 䩮; ) CJK COMPATIBILITY IDEOGRAPH-2F9F8 +2F9F9;4A76;4A76;4A76;4A76; # (䩶; 䩶; 䩶; 䩶; 䩶; ) CJK COMPATIBILITY IDEOGRAPH-2F9F9 +2F9FA;97E0;97E0;97E0;97E0; # (韠; 韠; 韠; 韠; 韠; ) CJK COMPATIBILITY IDEOGRAPH-2F9FA +2F9FB;2940A;2940A;2940A;2940A; # (𩐊; 𩐊; 𩐊; 𩐊; 𩐊; ) CJK COMPATIBILITY IDEOGRAPH-2F9FB +2F9FC;4AB2;4AB2;4AB2;4AB2; # (䪲; 䪲; 䪲; 䪲; 䪲; ) CJK COMPATIBILITY IDEOGRAPH-2F9FC +2F9FD;29496;29496;29496;29496; # (𩒖; 𩒖; 𩒖; 𩒖; 𩒖; ) CJK COMPATIBILITY IDEOGRAPH-2F9FD +2F9FE;980B;980B;980B;980B; # (頋; 頋; 頋; 頋; 頋; ) CJK COMPATIBILITY IDEOGRAPH-2F9FE +2F9FF;980B;980B;980B;980B; # (頋; 頋; 頋; 頋; 頋; ) CJK COMPATIBILITY IDEOGRAPH-2F9FF +2FA00;9829;9829;9829;9829; # (頩; 頩; 頩; 頩; 頩; ) CJK COMPATIBILITY IDEOGRAPH-2FA00 +2FA01;295B6;295B6;295B6;295B6; # (𩖶; 𩖶; 𩖶; 𩖶; 𩖶; ) CJK COMPATIBILITY IDEOGRAPH-2FA01 +2FA02;98E2;98E2;98E2;98E2; # (飢; 飢; 飢; 飢; 飢; ) CJK COMPATIBILITY IDEOGRAPH-2FA02 +2FA03;4B33;4B33;4B33;4B33; # (䬳; 䬳; 䬳; 䬳; 䬳; ) CJK COMPATIBILITY IDEOGRAPH-2FA03 +2FA04;9929;9929;9929;9929; # (餩; 餩; 餩; 餩; 餩; ) CJK COMPATIBILITY IDEOGRAPH-2FA04 +2FA05;99A7;99A7;99A7;99A7; # (馧; 馧; 馧; 馧; 馧; ) CJK COMPATIBILITY IDEOGRAPH-2FA05 +2FA06;99C2;99C2;99C2;99C2; # (駂; 駂; 駂; 駂; 駂; ) CJK COMPATIBILITY IDEOGRAPH-2FA06 +2FA07;99FE;99FE;99FE;99FE; # (駾; 駾; 駾; 駾; 駾; ) CJK COMPATIBILITY IDEOGRAPH-2FA07 +2FA08;4BCE;4BCE;4BCE;4BCE; # (䯎; 䯎; 䯎; 䯎; 䯎; ) CJK COMPATIBILITY IDEOGRAPH-2FA08 +2FA09;29B30;29B30;29B30;29B30; # (𩬰; 𩬰; 𩬰; 𩬰; 𩬰; ) CJK COMPATIBILITY IDEOGRAPH-2FA09 +2FA0A;9B12;9B12;9B12;9B12; # (鬒; 鬒; 鬒; 鬒; 鬒; ) CJK COMPATIBILITY IDEOGRAPH-2FA0A +2FA0B;9C40;9C40;9C40;9C40; # (鱀; 鱀; 鱀; 鱀; 鱀; ) CJK COMPATIBILITY IDEOGRAPH-2FA0B +2FA0C;9CFD;9CFD;9CFD;9CFD; # (鳽; 鳽; 鳽; 鳽; 鳽; ) CJK COMPATIBILITY IDEOGRAPH-2FA0C +2FA0D;4CCE;4CCE;4CCE;4CCE; # (䳎; 䳎; 䳎; 䳎; 䳎; ) CJK COMPATIBILITY IDEOGRAPH-2FA0D +2FA0E;4CED;4CED;4CED;4CED; # (䳭; 䳭; 䳭; 䳭; 䳭; ) CJK COMPATIBILITY IDEOGRAPH-2FA0E +2FA0F;9D67;9D67;9D67;9D67; # (鵧; 鵧; 鵧; 鵧; 鵧; ) CJK COMPATIBILITY IDEOGRAPH-2FA0F +2FA10;2A0CE;2A0CE;2A0CE;2A0CE; # (𪃎; 𪃎; 𪃎; 𪃎; 𪃎; ) CJK COMPATIBILITY IDEOGRAPH-2FA10 +2FA11;4CF8;4CF8;4CF8;4CF8; # (䳸; 䳸; 䳸; 䳸; 䳸; ) CJK COMPATIBILITY IDEOGRAPH-2FA11 +2FA12;2A105;2A105;2A105;2A105; # (𪄅; 𪄅; 𪄅; 𪄅; 𪄅; ) CJK COMPATIBILITY IDEOGRAPH-2FA12 +2FA13;2A20E;2A20E;2A20E;2A20E; # (𪈎; 𪈎; 𪈎; 𪈎; 𪈎; ) CJK COMPATIBILITY IDEOGRAPH-2FA13 +2FA14;2A291;2A291;2A291;2A291; # (𪊑; 𪊑; 𪊑; 𪊑; 𪊑; ) CJK COMPATIBILITY IDEOGRAPH-2FA14 +2FA15;9EBB;9EBB;9EBB;9EBB; # (麻; 麻; 麻; 麻; 麻; ) CJK COMPATIBILITY IDEOGRAPH-2FA15 +2FA16;4D56;4D56;4D56;4D56; # (䵖; 䵖; 䵖; 䵖; 䵖; ) CJK COMPATIBILITY IDEOGRAPH-2FA16 +2FA17;9EF9;9EF9;9EF9;9EF9; # (黹; 黹; 黹; 黹; 黹; ) CJK COMPATIBILITY IDEOGRAPH-2FA17 +2FA18;9EFE;9EFE;9EFE;9EFE; # (黾; 黾; 黾; 黾; 黾; ) CJK COMPATIBILITY IDEOGRAPH-2FA18 +2FA19;9F05;9F05;9F05;9F05; # (鼅; 鼅; 鼅; 鼅; 鼅; ) CJK COMPATIBILITY IDEOGRAPH-2FA19 +2FA1A;9F0F;9F0F;9F0F;9F0F; # (鼏; 鼏; 鼏; 鼏; 鼏; ) CJK COMPATIBILITY IDEOGRAPH-2FA1A +2FA1B;9F16;9F16;9F16;9F16; # (鼖; 鼖; 鼖; 鼖; 鼖; ) CJK COMPATIBILITY IDEOGRAPH-2FA1B +2FA1C;9F3B;9F3B;9F3B;9F3B; # (鼻; 鼻; 鼻; 鼻; 鼻; ) CJK COMPATIBILITY IDEOGRAPH-2FA1C +2FA1D;2A600;2A600;2A600;2A600; # (𪘀; 𪘀; 𪘀; 𪘀; 𪘀; ) CJK COMPATIBILITY IDEOGRAPH-2FA1D +# +@Part2 # Canonical Order Test +# +0061 0315 0300 05AE 0300 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̕◌̀◌֮◌̀b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 0300 0315 0300 05AE 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̀◌̕◌̀◌֮b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0301 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062; # (a◌̕◌̀◌֮◌́b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE ACCENT, LATIN SMALL LETTER B +0061 0301 0315 0300 05AE 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062; # (a◌́◌̕◌̀◌֮b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0302 0062;00E0 05AE 0302 0315 0062;0061 05AE 0300 0302 0315 0062;00E0 05AE 0302 0315 0062;0061 05AE 0300 0302 0315 0062; # (a◌̕◌̀◌֮◌̂b; à◌֮◌̂◌̕b; a◌֮◌̀◌̂◌̕b; à◌֮◌̂◌̕b; a◌֮◌̀◌̂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CIRCUMFLEX ACCENT, LATIN SMALL LETTER B +0061 0302 0315 0300 05AE 0062;1EA7 05AE 0315 0062;0061 05AE 0302 0300 0315 0062;1EA7 05AE 0315 0062;0061 05AE 0302 0300 0315 0062; # (a◌̂◌̕◌̀◌֮b; ầ◌֮◌̕b; a◌֮◌̂◌̀◌̕b; ầ◌֮◌̕b; a◌֮◌̂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0303 0062;00E0 05AE 0303 0315 0062;0061 05AE 0300 0303 0315 0062;00E0 05AE 0303 0315 0062;0061 05AE 0300 0303 0315 0062; # (a◌̕◌̀◌֮◌̃b; à◌֮◌̃◌̕b; a◌֮◌̀◌̃◌̕b; à◌֮◌̃◌̕b; a◌֮◌̀◌̃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TILDE, LATIN SMALL LETTER B +0061 0303 0315 0300 05AE 0062;00E3 05AE 0300 0315 0062;0061 05AE 0303 0300 0315 0062;00E3 05AE 0300 0315 0062;0061 05AE 0303 0300 0315 0062; # (a◌̃◌̕◌̀◌֮b; ã◌֮◌̀◌̕b; a◌֮◌̃◌̀◌̕b; ã◌֮◌̀◌̕b; a◌֮◌̃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TILDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0304 0062;00E0 05AE 0304 0315 0062;0061 05AE 0300 0304 0315 0062;00E0 05AE 0304 0315 0062;0061 05AE 0300 0304 0315 0062; # (a◌̕◌̀◌֮◌̄b; à◌֮◌̄◌̕b; a◌֮◌̀◌̄◌̕b; à◌֮◌̄◌̕b; a◌֮◌̀◌̄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON, LATIN SMALL LETTER B +0061 0304 0315 0300 05AE 0062;0101 05AE 0300 0315 0062;0061 05AE 0304 0300 0315 0062;0101 05AE 0300 0315 0062;0061 05AE 0304 0300 0315 0062; # (a◌̄◌̕◌̀◌֮b; ā◌֮◌̀◌̕b; a◌֮◌̄◌̀◌̕b; ā◌֮◌̀◌̕b; a◌֮◌̄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0305 0062;00E0 05AE 0305 0315 0062;0061 05AE 0300 0305 0315 0062;00E0 05AE 0305 0315 0062;0061 05AE 0300 0305 0315 0062; # (a◌̕◌̀◌֮◌̅b; à◌֮◌̅◌̕b; a◌֮◌̀◌̅◌̕b; à◌֮◌̅◌̕b; a◌֮◌̀◌̅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OVERLINE, LATIN SMALL LETTER B +0061 0305 0315 0300 05AE 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062;0061 05AE 0305 0300 0315 0062; # (a◌̅◌̕◌̀◌֮b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; a◌֮◌̅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OVERLINE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0306 0062;00E0 05AE 0306 0315 0062;0061 05AE 0300 0306 0315 0062;00E0 05AE 0306 0315 0062;0061 05AE 0300 0306 0315 0062; # (a◌̕◌̀◌֮◌̆b; à◌֮◌̆◌̕b; a◌֮◌̀◌̆◌̕b; à◌֮◌̆◌̕b; a◌֮◌̀◌̆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BREVE, LATIN SMALL LETTER B +0061 0306 0315 0300 05AE 0062;1EB1 05AE 0315 0062;0061 05AE 0306 0300 0315 0062;1EB1 05AE 0315 0062;0061 05AE 0306 0300 0315 0062; # (a◌̆◌̕◌̀◌֮b; ằ◌֮◌̕b; a◌֮◌̆◌̀◌̕b; ằ◌֮◌̕b; a◌֮◌̆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BREVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0307 0062;00E0 05AE 0307 0315 0062;0061 05AE 0300 0307 0315 0062;00E0 05AE 0307 0315 0062;0061 05AE 0300 0307 0315 0062; # (a◌̕◌̀◌֮◌̇b; à◌֮◌̇◌̕b; a◌֮◌̀◌̇◌̕b; à◌֮◌̇◌̕b; a◌֮◌̀◌̇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOT ABOVE, LATIN SMALL LETTER B +0061 0307 0315 0300 05AE 0062;0227 05AE 0300 0315 0062;0061 05AE 0307 0300 0315 0062;0227 05AE 0300 0315 0062;0061 05AE 0307 0300 0315 0062; # (a◌̇◌̕◌̀◌֮b; ȧ◌֮◌̀◌̕b; a◌֮◌̇◌̀◌̕b; ȧ◌֮◌̀◌̕b; a◌֮◌̇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0308 0062;00E0 05AE 0308 0315 0062;0061 05AE 0300 0308 0315 0062;00E0 05AE 0308 0315 0062;0061 05AE 0300 0308 0315 0062; # (a◌̕◌̀◌֮◌̈b; à◌֮◌̈◌̕b; a◌֮◌̀◌̈◌̕b; à◌֮◌̈◌̕b; a◌֮◌̀◌̈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DIAERESIS, LATIN SMALL LETTER B +0061 0308 0315 0300 05AE 0062;00E4 05AE 0300 0315 0062;0061 05AE 0308 0300 0315 0062;00E4 05AE 0300 0315 0062;0061 05AE 0308 0300 0315 0062; # (a◌̈◌̕◌̀◌֮b; ä◌֮◌̀◌̕b; a◌֮◌̈◌̀◌̕b; ä◌֮◌̀◌̕b; a◌֮◌̈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0309 0062;00E0 05AE 0309 0315 0062;0061 05AE 0300 0309 0315 0062;00E0 05AE 0309 0315 0062;0061 05AE 0300 0309 0315 0062; # (a◌̕◌̀◌֮◌̉b; à◌֮◌̉◌̕b; a◌֮◌̀◌̉◌̕b; à◌֮◌̉◌̕b; a◌֮◌̀◌̉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING HOOK ABOVE, LATIN SMALL LETTER B +0061 0309 0315 0300 05AE 0062;1EA3 05AE 0300 0315 0062;0061 05AE 0309 0300 0315 0062;1EA3 05AE 0300 0315 0062;0061 05AE 0309 0300 0315 0062; # (a◌̉◌̕◌̀◌֮b; ả◌֮◌̀◌̕b; a◌֮◌̉◌̀◌̕b; ả◌֮◌̀◌̕b; a◌֮◌̉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030A 0062;00E0 05AE 030A 0315 0062;0061 05AE 0300 030A 0315 0062;00E0 05AE 030A 0315 0062;0061 05AE 0300 030A 0315 0062; # (a◌̕◌̀◌֮◌̊b; à◌֮◌̊◌̕b; a◌֮◌̀◌̊◌̕b; à◌֮◌̊◌̕b; a◌֮◌̀◌̊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RING ABOVE, LATIN SMALL LETTER B +0061 030A 0315 0300 05AE 0062;00E5 05AE 0300 0315 0062;0061 05AE 030A 0300 0315 0062;00E5 05AE 0300 0315 0062;0061 05AE 030A 0300 0315 0062; # (a◌̊◌̕◌̀◌֮b; å◌֮◌̀◌̕b; a◌֮◌̊◌̀◌̕b; å◌֮◌̀◌̕b; a◌֮◌̊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030B 0062;00E0 05AE 030B 0315 0062;0061 05AE 0300 030B 0315 0062;00E0 05AE 030B 0315 0062;0061 05AE 0300 030B 0315 0062; # (a◌̕◌̀◌֮◌̋b; à◌֮◌̋◌̕b; a◌֮◌̀◌̋◌̕b; à◌֮◌̋◌̕b; a◌֮◌̀◌̋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE ACUTE ACCENT, LATIN SMALL LETTER B +0061 030B 0315 0300 05AE 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062;0061 05AE 030B 0300 0315 0062; # (a◌̋◌̕◌̀◌֮b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; a◌֮◌̋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030C 0062;00E0 05AE 030C 0315 0062;0061 05AE 0300 030C 0315 0062;00E0 05AE 030C 0315 0062;0061 05AE 0300 030C 0315 0062; # (a◌̕◌̀◌֮◌̌b; à◌֮◌̌◌̕b; a◌֮◌̀◌̌◌̕b; à◌֮◌̌◌̕b; a◌֮◌̀◌̌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CARON, LATIN SMALL LETTER B +0061 030C 0315 0300 05AE 0062;01CE 05AE 0300 0315 0062;0061 05AE 030C 0300 0315 0062;01CE 05AE 0300 0315 0062;0061 05AE 030C 0300 0315 0062; # (a◌̌◌̕◌̀◌֮b; ǎ◌֮◌̀◌̕b; a◌֮◌̌◌̀◌̕b; ǎ◌֮◌̀◌̕b; a◌֮◌̌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CARON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030D 0062;00E0 05AE 030D 0315 0062;0061 05AE 0300 030D 0315 0062;00E0 05AE 030D 0315 0062;0061 05AE 0300 030D 0315 0062; # (a◌̕◌̀◌֮◌̍b; à◌֮◌̍◌̕b; a◌֮◌̀◌̍◌̕b; à◌֮◌̍◌̕b; a◌֮◌̀◌̍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING VERTICAL LINE ABOVE, LATIN SMALL LETTER B +0061 030D 0315 0300 05AE 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062;0061 05AE 030D 0300 0315 0062; # (a◌̍◌̕◌̀◌֮b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; a◌֮◌̍◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030E 0062;00E0 05AE 030E 0315 0062;0061 05AE 0300 030E 0315 0062;00E0 05AE 030E 0315 0062;0061 05AE 0300 030E 0315 0062; # (a◌̕◌̀◌֮◌̎b; à◌֮◌̎◌̕b; a◌֮◌̀◌̎◌̕b; à◌֮◌̎◌̕b; a◌֮◌̀◌̎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE VERTICAL LINE ABOVE, LATIN SMALL LETTER B +0061 030E 0315 0300 05AE 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062;0061 05AE 030E 0300 0315 0062; # (a◌̎◌̕◌̀◌֮b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; a◌֮◌̎◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 030F 0062;00E0 05AE 030F 0315 0062;0061 05AE 0300 030F 0315 0062;00E0 05AE 030F 0315 0062;0061 05AE 0300 030F 0315 0062; # (a◌̕◌̀◌֮◌̏b; à◌֮◌̏◌̕b; a◌֮◌̀◌̏◌̕b; à◌֮◌̏◌̕b; a◌֮◌̀◌̏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE GRAVE ACCENT, LATIN SMALL LETTER B +0061 030F 0315 0300 05AE 0062;0201 05AE 0300 0315 0062;0061 05AE 030F 0300 0315 0062;0201 05AE 0300 0315 0062;0061 05AE 030F 0300 0315 0062; # (a◌̏◌̕◌̀◌֮b; ȁ◌֮◌̀◌̕b; a◌֮◌̏◌̀◌̕b; ȁ◌֮◌̀◌̕b; a◌֮◌̏◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0310 0062;00E0 05AE 0310 0315 0062;0061 05AE 0300 0310 0315 0062;00E0 05AE 0310 0315 0062;0061 05AE 0300 0310 0315 0062; # (a◌̕◌̀◌֮◌̐b; à◌֮◌̐◌̕b; a◌֮◌̀◌̐◌̕b; à◌֮◌̐◌̕b; a◌֮◌̀◌̐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CANDRABINDU, LATIN SMALL LETTER B +0061 0310 0315 0300 05AE 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062;0061 05AE 0310 0300 0315 0062; # (a◌̐◌̕◌̀◌֮b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; a◌֮◌̐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CANDRABINDU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0311 0062;00E0 05AE 0311 0315 0062;0061 05AE 0300 0311 0315 0062;00E0 05AE 0311 0315 0062;0061 05AE 0300 0311 0315 0062; # (a◌̕◌̀◌֮◌̑b; à◌֮◌̑◌̕b; a◌֮◌̀◌̑◌̕b; à◌֮◌̑◌̕b; a◌֮◌̀◌̑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING INVERTED BREVE, LATIN SMALL LETTER B +0061 0311 0315 0300 05AE 0062;0203 05AE 0300 0315 0062;0061 05AE 0311 0300 0315 0062;0203 05AE 0300 0315 0062;0061 05AE 0311 0300 0315 0062; # (a◌̑◌̕◌̀◌֮b; ȃ◌֮◌̀◌̕b; a◌֮◌̑◌̀◌̕b; ȃ◌֮◌̀◌̕b; a◌֮◌̑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0312 0062;00E0 05AE 0312 0315 0062;0061 05AE 0300 0312 0315 0062;00E0 05AE 0312 0315 0062;0061 05AE 0300 0312 0315 0062; # (a◌̕◌̀◌֮◌̒b; à◌֮◌̒◌̕b; a◌֮◌̀◌̒◌̕b; à◌֮◌̒◌̕b; a◌֮◌̀◌̒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TURNED COMMA ABOVE, LATIN SMALL LETTER B +0061 0312 0315 0300 05AE 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062;0061 05AE 0312 0300 0315 0062; # (a◌̒◌̕◌̀◌֮b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; a◌֮◌̒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TURNED COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0313 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062; # (a◌̕◌̀◌֮◌̓b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING COMMA ABOVE, LATIN SMALL LETTER B +0061 0313 0315 0300 05AE 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062; # (a◌̓◌̕◌̀◌֮b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0314 0062;00E0 05AE 0314 0315 0062;0061 05AE 0300 0314 0315 0062;00E0 05AE 0314 0315 0062;0061 05AE 0300 0314 0315 0062; # (a◌̕◌̀◌֮◌̔b; à◌֮◌̔◌̕b; a◌֮◌̀◌̔◌̕b; à◌֮◌̔◌̕b; a◌֮◌̀◌̔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING REVERSED COMMA ABOVE, LATIN SMALL LETTER B +0061 0314 0315 0300 05AE 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062; # (a◌̔◌̕◌̀◌֮b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING REVERSED COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035C 0315 0300 0315 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062; # (a◌͜◌̕◌̀◌̕b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0315 035C 0315 0300 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062; # (a◌̕◌͜◌̕◌̀b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0316 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062; # (a◌֚◌̖◌᷺◌̖b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0316 059A 0316 1DFA 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062; # (a◌̖◌֚◌̖◌᷺b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0317 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062; # (a◌֚◌̖◌᷺◌̗b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ACUTE ACCENT BELOW, LATIN SMALL LETTER B +0061 0317 059A 0316 1DFA 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062; # (a◌̗◌֚◌̖◌᷺b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0318 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062; # (a◌֚◌̖◌᷺◌̘b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT TACK BELOW, LATIN SMALL LETTER B +0061 0318 059A 0316 1DFA 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062; # (a◌̘◌֚◌̖◌᷺b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0319 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062; # (a◌֚◌̖◌᷺◌̙b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT TACK BELOW, LATIN SMALL LETTER B +0061 0319 059A 0316 1DFA 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062; # (a◌̙◌֚◌̖◌᷺b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 035C 0315 0300 031A 0062;00E0 0315 031A 035C 0062;0061 0300 0315 031A 035C 0062;00E0 0315 031A 035C 0062;0061 0300 0315 031A 035C 0062; # (a◌͜◌̕◌̀◌̚b; à◌̕◌̚◌͜b; a◌̀◌̕◌̚◌͜b; à◌̕◌̚◌͜b; a◌̀◌̕◌̚◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING LEFT ANGLE ABOVE, LATIN SMALL LETTER B +0061 031A 035C 0315 0300 0062;00E0 031A 0315 035C 0062;0061 0300 031A 0315 035C 0062;00E0 031A 0315 035C 0062;0061 0300 031A 0315 035C 0062; # (a◌̚◌͜◌̕◌̀b; à◌̚◌̕◌͜b; a◌̀◌̚◌̕◌͜b; à◌̚◌̕◌͜b; a◌̀◌̚◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE ABOVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 031B 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062; # (a◌᷺◌̛◌᷎◌̛b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING HORN, LATIN SMALL LETTER B +0061 031B 1DFA 031B 1DCE 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062; # (a◌̛◌᷺◌̛◌᷎b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031C 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062; # (a◌֚◌̖◌᷺◌̜b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT HALF RING BELOW, LATIN SMALL LETTER B +0061 031C 059A 0316 1DFA 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062; # (a◌̜◌֚◌̖◌᷺b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031D 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062; # (a◌֚◌̖◌᷺◌̝b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING UP TACK BELOW, LATIN SMALL LETTER B +0061 031D 059A 0316 1DFA 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062; # (a◌̝◌֚◌̖◌᷺b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UP TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031E 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062; # (a◌֚◌̖◌᷺◌̞b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOWN TACK BELOW, LATIN SMALL LETTER B +0061 031E 059A 0316 1DFA 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062; # (a◌̞◌֚◌̖◌᷺b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOWN TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031F 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062; # (a◌֚◌̖◌᷺◌̟b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING PLUS SIGN BELOW, LATIN SMALL LETTER B +0061 031F 059A 0316 1DFA 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062; # (a◌̟◌֚◌̖◌᷺b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0320 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062; # (a◌֚◌̖◌᷺◌̠b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MINUS SIGN BELOW, LATIN SMALL LETTER B +0061 0320 059A 0316 1DFA 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062; # (a◌̠◌֚◌̖◌᷺b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MINUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DCE 0321 0F74 0321 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062; # (a◌᷎◌̡◌ུ◌̡b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 0321 1DCE 0321 0F74 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062; # (a◌̡◌᷎◌̡◌ུb; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING PALATALIZED HOOK BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 1DCE 0321 0F74 0322 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062; # (a◌᷎◌̡◌ུ◌̢b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING RETROFLEX HOOK BELOW, LATIN SMALL LETTER B +0061 0322 1DCE 0321 0F74 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062; # (a◌̢◌᷎◌̡◌ུb; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING RETROFLEX HOOK BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0323 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062; # (a◌֚◌̖◌᷺◌̣b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 0323 059A 0316 1DFA 0062;1EA1 1DFA 0316 059A 0062;0061 1DFA 0323 0316 059A 0062;1EA1 1DFA 0316 059A 0062;0061 1DFA 0323 0316 059A 0062; # (a◌̣◌֚◌̖◌᷺b; ạ◌᷺◌̖◌֚b; a◌᷺◌̣◌̖◌֚b; ạ◌᷺◌̖◌֚b; a◌᷺◌̣◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0324 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062; # (a◌֚◌̖◌᷺◌̤b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DIAERESIS BELOW, LATIN SMALL LETTER B +0061 0324 059A 0316 1DFA 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062; # (a◌̤◌֚◌̖◌᷺b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0325 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062; # (a◌֚◌̖◌᷺◌̥b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RING BELOW, LATIN SMALL LETTER B +0061 0325 059A 0316 1DFA 0062;1E01 1DFA 0316 059A 0062;0061 1DFA 0325 0316 059A 0062;1E01 1DFA 0316 059A 0062;0061 1DFA 0325 0316 059A 0062; # (a◌̥◌֚◌̖◌᷺b; ḁ◌᷺◌̖◌֚b; a◌᷺◌̥◌̖◌֚b; ḁ◌᷺◌̖◌֚b; a◌᷺◌̥◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0326 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062; # (a◌֚◌̖◌᷺◌̦b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING COMMA BELOW, LATIN SMALL LETTER B +0061 0326 059A 0316 1DFA 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062; # (a◌̦◌֚◌̖◌᷺b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING COMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DCE 0321 0F74 0327 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062; # (a◌᷎◌̡◌ུ◌̧b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING CEDILLA, LATIN SMALL LETTER B +0061 0327 1DCE 0321 0F74 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062; # (a◌̧◌᷎◌̡◌ུb; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING CEDILLA, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 1DCE 0321 0F74 0328 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062; # (a◌᷎◌̡◌ུ◌̨b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING OGONEK, LATIN SMALL LETTER B +0061 0328 1DCE 0321 0F74 0062;0105 0F74 0321 1DCE 0062;0061 0F74 0328 0321 1DCE 0062;0105 0F74 0321 1DCE 0062;0061 0F74 0328 0321 1DCE 0062; # (a◌̨◌᷎◌̡◌ུb; ą◌ུ◌̡◌᷎b; a◌ུ◌̨◌̡◌᷎b; ą◌ུ◌̡◌᷎b; a◌ུ◌̨◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0329 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062; # (a◌֚◌̖◌᷺◌̩b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0329 059A 0316 1DFA 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062; # (a◌̩◌֚◌̖◌᷺b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062; # (a◌֚◌̖◌᷺◌̪b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING BRIDGE BELOW, LATIN SMALL LETTER B +0061 032A 059A 0316 1DFA 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062; # (a◌̪◌֚◌̖◌᷺b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032B 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062; # (a◌֚◌̖◌᷺◌̫b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED DOUBLE ARCH BELOW, LATIN SMALL LETTER B +0061 032B 059A 0316 1DFA 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062; # (a◌̫◌֚◌̖◌᷺b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032C 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062; # (a◌֚◌̖◌᷺◌̬b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CARON BELOW, LATIN SMALL LETTER B +0061 032C 059A 0316 1DFA 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062; # (a◌̬◌֚◌̖◌᷺b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CARON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032D 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062; # (a◌֚◌̖◌᷺◌̭b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CIRCUMFLEX ACCENT BELOW, LATIN SMALL LETTER B +0061 032D 059A 0316 1DFA 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062; # (a◌̭◌֚◌̖◌᷺b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032E 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062; # (a◌֚◌̖◌᷺◌̮b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING BREVE BELOW, LATIN SMALL LETTER B +0061 032E 059A 0316 1DFA 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062; # (a◌̮◌֚◌̖◌᷺b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032F 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062; # (a◌֚◌̖◌᷺◌̯b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED BREVE BELOW, LATIN SMALL LETTER B +0061 032F 059A 0316 1DFA 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062; # (a◌̯◌֚◌̖◌᷺b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0330 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062; # (a◌֚◌̖◌᷺◌̰b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE BELOW, LATIN SMALL LETTER B +0061 0330 059A 0316 1DFA 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062; # (a◌̰◌֚◌̖◌᷺b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0331 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062; # (a◌֚◌̖◌᷺◌̱b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON BELOW, LATIN SMALL LETTER B +0061 0331 059A 0316 1DFA 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062; # (a◌̱◌֚◌̖◌᷺b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0332 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062; # (a◌֚◌̖◌᷺◌̲b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LOW LINE, LATIN SMALL LETTER B +0061 0332 059A 0316 1DFA 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062; # (a◌̲◌֚◌̖◌᷺b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0333 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062; # (a◌֚◌̖◌᷺◌̳b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE LOW LINE, LATIN SMALL LETTER B +0061 0333 059A 0316 1DFA 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062; # (a◌̳◌֚◌̖◌᷺b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 16FF0 0334 0334 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062; # (a𖿰◌̴◌̴b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0334 16FF0 0334 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062; # (a◌̴𖿰◌̴b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING TILDE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 0335 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062; # (a𖿰◌̴◌̵b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING SHORT STROKE OVERLAY, LATIN SMALL LETTER B +0061 0335 16FF0 0334 0062;0061 0335 0334 16FF0 0062;0061 0335 0334 16FF0 0062;0061 0335 0334 16FF0 0062;0061 0335 0334 16FF0 0062; # (a◌̵𖿰◌̴b; a◌̵◌̴𖿰b; a◌̵◌̴𖿰b; a◌̵◌̴𖿰b; a◌̵◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING SHORT STROKE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 0336 0062;0061 0334 0336 16FF0 0062;0061 0334 0336 16FF0 0062;0061 0334 0336 16FF0 0062;0061 0334 0336 16FF0 0062; # (a𖿰◌̴◌̶b; a◌̴◌̶𖿰b; a◌̴◌̶𖿰b; a◌̴◌̶𖿰b; a◌̴◌̶𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG STROKE OVERLAY, LATIN SMALL LETTER B +0061 0336 16FF0 0334 0062;0061 0336 0334 16FF0 0062;0061 0336 0334 16FF0 0062;0061 0336 0334 16FF0 0062;0061 0336 0334 16FF0 0062; # (a◌̶𖿰◌̴b; a◌̶◌̴𖿰b; a◌̶◌̴𖿰b; a◌̶◌̴𖿰b; a◌̶◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG STROKE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 0337 0062;0061 0334 0337 16FF0 0062;0061 0334 0337 16FF0 0062;0061 0334 0337 16FF0 0062;0061 0334 0337 16FF0 0062; # (a𖿰◌̴◌̷b; a◌̴◌̷𖿰b; a◌̴◌̷𖿰b; a◌̴◌̷𖿰b; a◌̴◌̷𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING SHORT SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 0337 16FF0 0334 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062; # (a◌̷𖿰◌̴b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING SHORT SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 0338 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062; # (a𖿰◌̴◌̸b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 0338 16FF0 0334 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062; # (a◌̸𖿰◌̴b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0339 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062; # (a◌֚◌̖◌᷺◌̹b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT HALF RING BELOW, LATIN SMALL LETTER B +0061 0339 059A 0316 1DFA 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062; # (a◌̹◌֚◌̖◌᷺b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062; # (a◌֚◌̖◌᷺◌̺b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 033A 059A 0316 1DFA 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062; # (a◌̺◌֚◌̖◌᷺b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033B 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062; # (a◌֚◌̖◌᷺◌̻b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SQUARE BELOW, LATIN SMALL LETTER B +0061 033B 059A 0316 1DFA 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062; # (a◌̻◌֚◌̖◌᷺b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SQUARE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033C 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062; # (a◌֚◌̖◌᷺◌̼b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SEAGULL BELOW, LATIN SMALL LETTER B +0061 033C 059A 0316 1DFA 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062; # (a◌̼◌֚◌̖◌᷺b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SEAGULL BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 033D 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062; # (a◌̕◌̀◌֮◌̽b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING X ABOVE, LATIN SMALL LETTER B +0061 033D 0315 0300 05AE 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062; # (a◌̽◌̕◌̀◌֮b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING X ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 033E 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062; # (a◌̕◌̀◌֮◌̾b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING VERTICAL TILDE, LATIN SMALL LETTER B +0061 033E 0315 0300 05AE 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062;0061 05AE 033E 0300 0315 0062; # (a◌̾◌̕◌̀◌֮b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; a◌֮◌̾◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING VERTICAL TILDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 033F 0062;00E0 05AE 033F 0315 0062;0061 05AE 0300 033F 0315 0062;00E0 05AE 033F 0315 0062;0061 05AE 0300 033F 0315 0062; # (a◌̕◌̀◌֮◌̿b; à◌֮◌̿◌̕b; a◌֮◌̀◌̿◌̕b; à◌֮◌̿◌̕b; a◌֮◌̀◌̿◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE OVERLINE, LATIN SMALL LETTER B +0061 033F 0315 0300 05AE 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062;0061 05AE 033F 0300 0315 0062; # (a◌̿◌̕◌̀◌֮b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; a◌֮◌̿◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE OVERLINE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0340 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̕◌̀◌֮◌̀b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE TONE MARK, LATIN SMALL LETTER B +0061 0340 0315 0300 05AE 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062;00E0 05AE 0300 0315 0062;0061 05AE 0300 0300 0315 0062; # (a◌̀◌̕◌̀◌֮b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; à◌֮◌̀◌̕b; a◌֮◌̀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE TONE MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0341 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062;00E0 05AE 0301 0315 0062;0061 05AE 0300 0301 0315 0062; # (a◌̕◌̀◌֮◌́b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; à◌֮◌́◌̕b; a◌֮◌̀◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE TONE MARK, LATIN SMALL LETTER B +0061 0341 0315 0300 05AE 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062;00E1 05AE 0300 0315 0062;0061 05AE 0301 0300 0315 0062; # (a◌́◌̕◌̀◌֮b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; á◌֮◌̀◌̕b; a◌֮◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE TONE MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0342 0062;00E0 05AE 0342 0315 0062;0061 05AE 0300 0342 0315 0062;00E0 05AE 0342 0315 0062;0061 05AE 0300 0342 0315 0062; # (a◌̕◌̀◌֮◌͂b; à◌֮◌͂◌̕b; a◌֮◌̀◌͂◌̕b; à◌֮◌͂◌̕b; a◌֮◌̀◌͂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK PERISPOMENI, LATIN SMALL LETTER B +0061 0342 0315 0300 05AE 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062;0061 05AE 0342 0300 0315 0062; # (a◌͂◌̕◌̀◌֮b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; a◌֮◌͂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK PERISPOMENI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0343 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062;00E0 05AE 0313 0315 0062;0061 05AE 0300 0313 0315 0062; # (a◌̕◌̀◌֮◌̓b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; à◌֮◌̓◌̕b; a◌֮◌̀◌̓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK KORONIS, LATIN SMALL LETTER B +0061 0343 0315 0300 05AE 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062;0061 05AE 0313 0300 0315 0062; # (a◌̓◌̕◌̀◌֮b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; a◌֮◌̓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK KORONIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0344 0062;00E0 05AE 0308 0301 0315 0062;0061 05AE 0300 0308 0301 0315 0062;00E0 05AE 0308 0301 0315 0062;0061 05AE 0300 0308 0301 0315 0062; # (a◌̕◌̀◌֮◌̈́b; à◌֮◌̈◌́◌̕b; a◌֮◌̀◌̈◌́◌̕b; à◌֮◌̈◌́◌̕b; a◌֮◌̀◌̈◌́◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK DIALYTIKA TONOS, LATIN SMALL LETTER B +0061 0344 0315 0300 05AE 0062;00E4 05AE 0301 0300 0315 0062;0061 05AE 0308 0301 0300 0315 0062;00E4 05AE 0301 0300 0315 0062;0061 05AE 0308 0301 0300 0315 0062; # (a◌̈́◌̕◌̀◌֮b; ä◌֮◌́◌̀◌̕b; a◌֮◌̈◌́◌̀◌̕b; ä◌֮◌́◌̀◌̕b; a◌֮◌̈◌́◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK DIALYTIKA TONOS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0345 035D 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062; # (a◌ͅ◌͝◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING GREEK YPOGEGRAMMENI, LATIN SMALL LETTER B +0061 0345 0345 035D 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062; # (a◌ͅ◌ͅ◌͝b; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, LATIN SMALL LETTER B +0061 0315 0300 05AE 0346 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062; # (a◌̕◌̀◌֮◌͆b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BRIDGE ABOVE, LATIN SMALL LETTER B +0061 0346 0315 0300 05AE 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062; # (a◌͆◌̕◌̀◌֮b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0347 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062; # (a◌֚◌̖◌᷺◌͇b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING EQUALS SIGN BELOW, LATIN SMALL LETTER B +0061 0347 059A 0316 1DFA 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062; # (a◌͇◌֚◌̖◌᷺b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING EQUALS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0348 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062; # (a◌֚◌̖◌᷺◌͈b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0348 059A 0316 1DFA 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062; # (a◌͈◌֚◌̖◌᷺b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0349 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062; # (a◌֚◌̖◌᷺◌͉b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ANGLE BELOW, LATIN SMALL LETTER B +0061 0349 059A 0316 1DFA 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062; # (a◌͉◌֚◌̖◌᷺b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 034A 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062; # (a◌̕◌̀◌֮◌͊b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING NOT TILDE ABOVE, LATIN SMALL LETTER B +0061 034A 0315 0300 05AE 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062; # (a◌͊◌̕◌̀◌֮b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING NOT TILDE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 034B 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062; # (a◌̕◌̀◌֮◌͋b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING HOMOTHETIC ABOVE, LATIN SMALL LETTER B +0061 034B 0315 0300 05AE 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062; # (a◌͋◌̕◌̀◌֮b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING HOMOTHETIC ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 034C 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062; # (a◌̕◌̀◌֮◌͌b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ALMOST EQUAL TO ABOVE, LATIN SMALL LETTER B +0061 034C 0315 0300 05AE 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062; # (a◌͌◌̕◌̀◌֮b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 034D 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062; # (a◌֚◌̖◌᷺◌͍b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT RIGHT ARROW BELOW, LATIN SMALL LETTER B +0061 034D 059A 0316 1DFA 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062; # (a◌͍◌֚◌̖◌᷺b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 034E 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062; # (a◌֚◌̖◌᷺◌͎b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING UPWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 034E 059A 0316 1DFA 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062; # (a◌͎◌֚◌̖◌᷺b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UPWARDS ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0350 0062;00E0 05AE 0350 0315 0062;0061 05AE 0300 0350 0315 0062;00E0 05AE 0350 0315 0062;0061 05AE 0300 0350 0315 0062; # (a◌̕◌̀◌֮◌͐b; à◌֮◌͐◌̕b; a◌֮◌̀◌͐◌̕b; à◌֮◌͐◌̕b; a◌֮◌̀◌͐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B +0061 0350 0315 0300 05AE 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062; # (a◌͐◌̕◌̀◌֮b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0351 0062;00E0 05AE 0351 0315 0062;0061 05AE 0300 0351 0315 0062;00E0 05AE 0351 0315 0062;0061 05AE 0300 0351 0315 0062; # (a◌̕◌̀◌֮◌͑b; à◌֮◌͑◌̕b; a◌֮◌̀◌͑◌̕b; à◌֮◌͑◌̕b; a◌֮◌̀◌͑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT HALF RING ABOVE, LATIN SMALL LETTER B +0061 0351 0315 0300 05AE 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062; # (a◌͑◌̕◌̀◌֮b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0352 0062;00E0 05AE 0352 0315 0062;0061 05AE 0300 0352 0315 0062;00E0 05AE 0352 0315 0062;0061 05AE 0300 0352 0315 0062; # (a◌̕◌̀◌֮◌͒b; à◌֮◌͒◌̕b; a◌֮◌̀◌͒◌̕b; à◌֮◌͒◌̕b; a◌֮◌̀◌͒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING FERMATA, LATIN SMALL LETTER B +0061 0352 0315 0300 05AE 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062; # (a◌͒◌̕◌̀◌֮b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING FERMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0353 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062; # (a◌֚◌̖◌᷺◌͓b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING X BELOW, LATIN SMALL LETTER B +0061 0353 059A 0316 1DFA 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062; # (a◌͓◌֚◌̖◌᷺b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0354 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062; # (a◌֚◌̖◌᷺◌͔b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0354 059A 0316 1DFA 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062; # (a◌͔◌֚◌̖◌᷺b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0355 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062; # (a◌֚◌̖◌᷺◌͕b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0355 059A 0316 1DFA 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062; # (a◌͕◌֚◌̖◌᷺b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0356 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062; # (a◌֚◌̖◌᷺◌͖b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0356 059A 0316 1DFA 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062; # (a◌͖◌֚◌̖◌᷺b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0357 0062;00E0 05AE 0357 0315 0062;0061 05AE 0300 0357 0315 0062;00E0 05AE 0357 0315 0062;0061 05AE 0300 0357 0315 0062; # (a◌̕◌̀◌֮◌͗b; à◌֮◌͗◌̕b; a◌֮◌̀◌͗◌̕b; à◌֮◌͗◌̕b; a◌֮◌̀◌͗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT HALF RING ABOVE, LATIN SMALL LETTER B +0061 0357 0315 0300 05AE 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062; # (a◌͗◌̕◌̀◌֮b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035C 0315 0300 0358 0062;00E0 0315 0358 035C 0062;0061 0300 0315 0358 035C 0062;00E0 0315 0358 035C 0062;0061 0300 0315 0358 035C 0062; # (a◌͜◌̕◌̀◌͘b; à◌̕◌͘◌͜b; a◌̀◌̕◌͘◌͜b; à◌̕◌͘◌͜b; a◌̀◌̕◌͘◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING DOT ABOVE RIGHT, LATIN SMALL LETTER B +0061 0358 035C 0315 0300 0062;00E0 0358 0315 035C 0062;0061 0300 0358 0315 035C 0062;00E0 0358 0315 035C 0062;0061 0300 0358 0315 035C 0062; # (a◌͘◌͜◌̕◌̀b; à◌͘◌̕◌͜b; a◌̀◌͘◌̕◌͜b; à◌͘◌̕◌͜b; a◌̀◌͘◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0359 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062; # (a◌֚◌̖◌᷺◌͙b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ASTERISK BELOW, LATIN SMALL LETTER B +0061 0359 059A 0316 1DFA 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062; # (a◌͙◌֚◌̖◌᷺b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ASTERISK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 035A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062; # (a◌֚◌̖◌᷺◌͚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE RING BELOW, LATIN SMALL LETTER B +0061 035A 059A 0316 1DFA 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062; # (a◌͚◌֚◌̖◌᷺b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 035B 0062;00E0 05AE 035B 0315 0062;0061 05AE 0300 035B 0315 0062;00E0 05AE 035B 0315 0062;0061 05AE 0300 035B 0315 0062; # (a◌̕◌̀◌֮◌͛b; à◌֮◌͛◌̕b; a◌֮◌̀◌͛◌̕b; à◌֮◌͛◌̕b; a◌֮◌̀◌͛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ZIGZAG ABOVE, LATIN SMALL LETTER B +0061 035B 0315 0300 05AE 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062; # (a◌͛◌̕◌̀◌֮b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ZIGZAG ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035D 035C 0315 035C 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062; # (a◌͝◌͜◌̕◌͜b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 035C 035D 035C 0315 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062; # (a◌͜◌͝◌͜◌̕b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0345 035D 035C 035D 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062; # (a◌ͅ◌͝◌͜◌͝b; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE BREVE, LATIN SMALL LETTER B +0061 035D 0345 035D 035C 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062;0061 035C 035D 035D 0345 0062; # (a◌͝◌ͅ◌͝◌͜b; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; a◌͜◌͝◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 0345 035D 035C 035E 0062;0061 035C 035D 035E 0345 0062;0061 035C 035D 035E 0345 0062;0061 035C 035D 035E 0345 0062;0061 035C 035D 035E 0345 0062; # (a◌ͅ◌͝◌͜◌͞b; a◌͜◌͝◌͞◌ͅb; a◌͜◌͝◌͞◌ͅb; a◌͜◌͝◌͞◌ͅb; a◌͜◌͝◌͞◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE MACRON, LATIN SMALL LETTER B +0061 035E 0345 035D 035C 0062;0061 035C 035E 035D 0345 0062;0061 035C 035E 035D 0345 0062;0061 035C 035E 035D 0345 0062;0061 035C 035E 035D 0345 0062; # (a◌͞◌ͅ◌͝◌͜b; a◌͜◌͞◌͝◌ͅb; a◌͜◌͞◌͝◌ͅb; a◌͜◌͞◌͝◌ͅb; a◌͜◌͞◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE MACRON, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 035D 035C 0315 035F 0062;0061 0315 035C 035F 035D 0062;0061 0315 035C 035F 035D 0062;0061 0315 035C 035F 035D 0062;0061 0315 035C 035F 035D 0062; # (a◌͝◌͜◌̕◌͟b; a◌̕◌͜◌͟◌͝b; a◌̕◌͜◌͟◌͝b; a◌̕◌͜◌͟◌͝b; a◌̕◌͜◌͟◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE MACRON BELOW, LATIN SMALL LETTER B +0061 035F 035D 035C 0315 0062;0061 0315 035F 035C 035D 0062;0061 0315 035F 035C 035D 0062;0061 0315 035F 035C 035D 0062;0061 0315 035F 035C 035D 0062; # (a◌͟◌͝◌͜◌̕b; a◌̕◌͟◌͜◌͝b; a◌̕◌͟◌͜◌͝b; a◌̕◌͟◌͜◌͝b; a◌̕◌͟◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE MACRON BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0345 035D 035C 0360 0062;0061 035C 035D 0360 0345 0062;0061 035C 035D 0360 0345 0062;0061 035C 035D 0360 0345 0062;0061 035C 035D 0360 0345 0062; # (a◌ͅ◌͝◌͜◌͠b; a◌͜◌͝◌͠◌ͅb; a◌͜◌͝◌͠◌ͅb; a◌͜◌͝◌͠◌ͅb; a◌͜◌͝◌͠◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE TILDE, LATIN SMALL LETTER B +0061 0360 0345 035D 035C 0062;0061 035C 0360 035D 0345 0062;0061 035C 0360 035D 0345 0062;0061 035C 0360 035D 0345 0062;0061 035C 0360 035D 0345 0062; # (a◌͠◌ͅ◌͝◌͜b; a◌͜◌͠◌͝◌ͅb; a◌͜◌͠◌͝◌ͅb; a◌͜◌͠◌͝◌ͅb; a◌͜◌͠◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 0345 035D 035C 0361 0062;0061 035C 035D 0361 0345 0062;0061 035C 035D 0361 0345 0062;0061 035C 035D 0361 0345 0062;0061 035C 035D 0361 0345 0062; # (a◌ͅ◌͝◌͜◌͡b; a◌͜◌͝◌͡◌ͅb; a◌͜◌͝◌͡◌ͅb; a◌͜◌͝◌͡◌ͅb; a◌͜◌͝◌͡◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE INVERTED BREVE, LATIN SMALL LETTER B +0061 0361 0345 035D 035C 0062;0061 035C 0361 035D 0345 0062;0061 035C 0361 035D 0345 0062;0061 035C 0361 035D 0345 0062;0061 035C 0361 035D 0345 0062; # (a◌͡◌ͅ◌͝◌͜b; a◌͜◌͡◌͝◌ͅb; a◌͜◌͡◌͝◌ͅb; a◌͜◌͡◌͝◌ͅb; a◌͜◌͡◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE INVERTED BREVE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 035D 035C 0315 0362 0062;0061 0315 035C 0362 035D 0062;0061 0315 035C 0362 035D 0062;0061 0315 035C 0362 035D 0062;0061 0315 035C 0362 035D 0062; # (a◌͝◌͜◌̕◌͢b; a◌̕◌͜◌͢◌͝b; a◌̕◌͜◌͢◌͝b; a◌̕◌͜◌͢◌͝b; a◌̕◌͜◌͢◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 0362 035D 035C 0315 0062;0061 0315 0362 035C 035D 0062;0061 0315 0362 035C 035D 0062;0061 0315 0362 035C 035D 0062;0061 0315 0362 035C 035D 0062; # (a◌͢◌͝◌͜◌̕b; a◌̕◌͢◌͜◌͝b; a◌̕◌͢◌͜◌͝b; a◌̕◌͢◌͜◌͝b; a◌̕◌͢◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RIGHTWARDS ARROW BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0363 0062;00E0 05AE 0363 0315 0062;0061 05AE 0300 0363 0315 0062;00E0 05AE 0363 0315 0062;0061 05AE 0300 0363 0315 0062; # (a◌̕◌̀◌֮◌ͣb; à◌֮◌ͣ◌̕b; a◌֮◌̀◌ͣ◌̕b; à◌֮◌ͣ◌̕b; a◌֮◌̀◌ͣ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER A, LATIN SMALL LETTER B +0061 0363 0315 0300 05AE 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062;0061 05AE 0363 0300 0315 0062; # (a◌ͣ◌̕◌̀◌֮b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; a◌֮◌ͣ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0364 0062;00E0 05AE 0364 0315 0062;0061 05AE 0300 0364 0315 0062;00E0 05AE 0364 0315 0062;0061 05AE 0300 0364 0315 0062; # (a◌̕◌̀◌֮◌ͤb; à◌֮◌ͤ◌̕b; a◌֮◌̀◌ͤ◌̕b; à◌֮◌ͤ◌̕b; a◌֮◌̀◌ͤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER E, LATIN SMALL LETTER B +0061 0364 0315 0300 05AE 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062;0061 05AE 0364 0300 0315 0062; # (a◌ͤ◌̕◌̀◌֮b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; a◌֮◌ͤ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0365 0062;00E0 05AE 0365 0315 0062;0061 05AE 0300 0365 0315 0062;00E0 05AE 0365 0315 0062;0061 05AE 0300 0365 0315 0062; # (a◌̕◌̀◌֮◌ͥb; à◌֮◌ͥ◌̕b; a◌֮◌̀◌ͥ◌̕b; à◌֮◌ͥ◌̕b; a◌֮◌̀◌ͥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER I, LATIN SMALL LETTER B +0061 0365 0315 0300 05AE 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062;0061 05AE 0365 0300 0315 0062; # (a◌ͥ◌̕◌̀◌֮b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; a◌֮◌ͥ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0366 0062;00E0 05AE 0366 0315 0062;0061 05AE 0300 0366 0315 0062;00E0 05AE 0366 0315 0062;0061 05AE 0300 0366 0315 0062; # (a◌̕◌̀◌֮◌ͦb; à◌֮◌ͦ◌̕b; a◌֮◌̀◌ͦ◌̕b; à◌֮◌ͦ◌̕b; a◌֮◌̀◌ͦ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER O, LATIN SMALL LETTER B +0061 0366 0315 0300 05AE 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062;0061 05AE 0366 0300 0315 0062; # (a◌ͦ◌̕◌̀◌֮b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; a◌֮◌ͦ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER O, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0367 0062;00E0 05AE 0367 0315 0062;0061 05AE 0300 0367 0315 0062;00E0 05AE 0367 0315 0062;0061 05AE 0300 0367 0315 0062; # (a◌̕◌̀◌֮◌ͧb; à◌֮◌ͧ◌̕b; a◌֮◌̀◌ͧ◌̕b; à◌֮◌ͧ◌̕b; a◌֮◌̀◌ͧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER U, LATIN SMALL LETTER B +0061 0367 0315 0300 05AE 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062;0061 05AE 0367 0300 0315 0062; # (a◌ͧ◌̕◌̀◌֮b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; a◌֮◌ͧ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0368 0062;00E0 05AE 0368 0315 0062;0061 05AE 0300 0368 0315 0062;00E0 05AE 0368 0315 0062;0061 05AE 0300 0368 0315 0062; # (a◌̕◌̀◌֮◌ͨb; à◌֮◌ͨ◌̕b; a◌֮◌̀◌ͨ◌̕b; à◌֮◌ͨ◌̕b; a◌֮◌̀◌ͨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER C, LATIN SMALL LETTER B +0061 0368 0315 0300 05AE 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062;0061 05AE 0368 0300 0315 0062; # (a◌ͨ◌̕◌̀◌֮b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; a◌֮◌ͨ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER C, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0369 0062;00E0 05AE 0369 0315 0062;0061 05AE 0300 0369 0315 0062;00E0 05AE 0369 0315 0062;0061 05AE 0300 0369 0315 0062; # (a◌̕◌̀◌֮◌ͩb; à◌֮◌ͩ◌̕b; a◌֮◌̀◌ͩ◌̕b; à◌֮◌ͩ◌̕b; a◌֮◌̀◌ͩ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER D, LATIN SMALL LETTER B +0061 0369 0315 0300 05AE 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062;0061 05AE 0369 0300 0315 0062; # (a◌ͩ◌̕◌̀◌֮b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; a◌֮◌ͩ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER D, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036A 0062;00E0 05AE 036A 0315 0062;0061 05AE 0300 036A 0315 0062;00E0 05AE 036A 0315 0062;0061 05AE 0300 036A 0315 0062; # (a◌̕◌̀◌֮◌ͪb; à◌֮◌ͪ◌̕b; a◌֮◌̀◌ͪ◌̕b; à◌֮◌ͪ◌̕b; a◌֮◌̀◌ͪ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER H, LATIN SMALL LETTER B +0061 036A 0315 0300 05AE 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062;0061 05AE 036A 0300 0315 0062; # (a◌ͪ◌̕◌̀◌֮b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; a◌֮◌ͪ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER H, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036B 0062;00E0 05AE 036B 0315 0062;0061 05AE 0300 036B 0315 0062;00E0 05AE 036B 0315 0062;0061 05AE 0300 036B 0315 0062; # (a◌̕◌̀◌֮◌ͫb; à◌֮◌ͫ◌̕b; a◌֮◌̀◌ͫ◌̕b; à◌֮◌ͫ◌̕b; a◌֮◌̀◌ͫ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER M, LATIN SMALL LETTER B +0061 036B 0315 0300 05AE 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062;0061 05AE 036B 0300 0315 0062; # (a◌ͫ◌̕◌̀◌֮b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; a◌֮◌ͫ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER M, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036C 0062;00E0 05AE 036C 0315 0062;0061 05AE 0300 036C 0315 0062;00E0 05AE 036C 0315 0062;0061 05AE 0300 036C 0315 0062; # (a◌̕◌̀◌֮◌ͬb; à◌֮◌ͬ◌̕b; a◌֮◌̀◌ͬ◌̕b; à◌֮◌ͬ◌̕b; a◌֮◌̀◌ͬ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER R, LATIN SMALL LETTER B +0061 036C 0315 0300 05AE 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062;0061 05AE 036C 0300 0315 0062; # (a◌ͬ◌̕◌̀◌֮b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; a◌֮◌ͬ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036D 0062;00E0 05AE 036D 0315 0062;0061 05AE 0300 036D 0315 0062;00E0 05AE 036D 0315 0062;0061 05AE 0300 036D 0315 0062; # (a◌̕◌̀◌֮◌ͭb; à◌֮◌ͭ◌̕b; a◌֮◌̀◌ͭ◌̕b; à◌֮◌ͭ◌̕b; a◌֮◌̀◌ͭ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER T, LATIN SMALL LETTER B +0061 036D 0315 0300 05AE 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062;0061 05AE 036D 0300 0315 0062; # (a◌ͭ◌̕◌̀◌֮b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; a◌֮◌ͭ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER T, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036E 0062;00E0 05AE 036E 0315 0062;0061 05AE 0300 036E 0315 0062;00E0 05AE 036E 0315 0062;0061 05AE 0300 036E 0315 0062; # (a◌̕◌̀◌֮◌ͮb; à◌֮◌ͮ◌̕b; a◌֮◌̀◌ͮ◌̕b; à◌֮◌ͮ◌̕b; a◌֮◌̀◌ͮ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER V, LATIN SMALL LETTER B +0061 036E 0315 0300 05AE 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062;0061 05AE 036E 0300 0315 0062; # (a◌ͮ◌̕◌̀◌֮b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; a◌֮◌ͮ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER V, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 036F 0062;00E0 05AE 036F 0315 0062;0061 05AE 0300 036F 0315 0062;00E0 05AE 036F 0315 0062;0061 05AE 0300 036F 0315 0062; # (a◌̕◌̀◌֮◌ͯb; à◌֮◌ͯ◌̕b; a◌֮◌̀◌ͯ◌̕b; à◌֮◌ͯ◌̕b; a◌֮◌̀◌ͯ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER X, LATIN SMALL LETTER B +0061 036F 0315 0300 05AE 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062;0061 05AE 036F 0300 0315 0062; # (a◌ͯ◌̕◌̀◌֮b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; a◌֮◌ͯ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER X, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0483 0062;00E0 05AE 0483 0315 0062;0061 05AE 0300 0483 0315 0062;00E0 05AE 0483 0315 0062;0061 05AE 0300 0483 0315 0062; # (a◌̕◌̀◌֮◌҃b; à◌֮◌҃◌̕b; a◌֮◌̀◌҃◌̕b; à◌֮◌҃◌̕b; a◌֮◌̀◌҃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO, LATIN SMALL LETTER B +0061 0483 0315 0300 05AE 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062;0061 05AE 0483 0300 0315 0062; # (a◌҃◌̕◌̀◌֮b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; a◌֮◌҃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0484 0062;00E0 05AE 0484 0315 0062;0061 05AE 0300 0484 0315 0062;00E0 05AE 0484 0315 0062;0061 05AE 0300 0484 0315 0062; # (a◌̕◌̀◌֮◌҄b; à◌֮◌҄◌̕b; a◌֮◌̀◌҄◌̕b; à◌֮◌҄◌̕b; a◌֮◌̀◌҄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PALATALIZATION, LATIN SMALL LETTER B +0061 0484 0315 0300 05AE 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062;0061 05AE 0484 0300 0315 0062; # (a◌҄◌̕◌̀◌֮b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; a◌֮◌҄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PALATALIZATION, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0485 0062;00E0 05AE 0485 0315 0062;0061 05AE 0300 0485 0315 0062;00E0 05AE 0485 0315 0062;0061 05AE 0300 0485 0315 0062; # (a◌̕◌̀◌֮◌҅b; à◌֮◌҅◌̕b; a◌֮◌̀◌҅◌̕b; à◌֮◌҅◌̕b; a◌֮◌̀◌҅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC DASIA PNEUMATA, LATIN SMALL LETTER B +0061 0485 0315 0300 05AE 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062;0061 05AE 0485 0300 0315 0062; # (a◌҅◌̕◌̀◌֮b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; a◌֮◌҅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC DASIA PNEUMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0486 0062;00E0 05AE 0486 0315 0062;0061 05AE 0300 0486 0315 0062;00E0 05AE 0486 0315 0062;0061 05AE 0300 0486 0315 0062; # (a◌̕◌̀◌֮◌҆b; à◌֮◌҆◌̕b; a◌֮◌̀◌҆◌̕b; à◌֮◌҆◌̕b; a◌֮◌̀◌҆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PSILI PNEUMATA, LATIN SMALL LETTER B +0061 0486 0315 0300 05AE 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062; # (a◌҆◌̕◌̀◌֮b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PSILI PNEUMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0487 0062;00E0 05AE 0487 0315 0062;0061 05AE 0300 0487 0315 0062;00E0 05AE 0487 0315 0062;0061 05AE 0300 0487 0315 0062; # (a◌̕◌̀◌֮◌҇b; à◌֮◌҇◌̕b; a◌֮◌̀◌҇◌̕b; à◌֮◌҇◌̕b; a◌֮◌̀◌҇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC POKRYTIE, LATIN SMALL LETTER B +0061 0487 0315 0300 05AE 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062; # (a◌҇◌̕◌̀◌֮b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC POKRYTIE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0591 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062; # (a◌֚◌̖◌᷺◌֑b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT ETNAHTA, LATIN SMALL LETTER B +0061 0591 059A 0316 1DFA 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062; # (a◌֑◌֚◌̖◌᷺b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ETNAHTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0592 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062; # (a◌̕◌̀◌֮◌֒b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SEGOL, LATIN SMALL LETTER B +0061 0592 0315 0300 05AE 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062; # (a◌֒◌̕◌̀◌֮b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT SEGOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0593 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062; # (a◌̕◌̀◌֮◌֓b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SHALSHELET, LATIN SMALL LETTER B +0061 0593 0315 0300 05AE 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062;0061 05AE 0593 0300 0315 0062; # (a◌֓◌̕◌̀◌֮b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; a◌֮◌֓◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT SHALSHELET, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0594 0062;00E0 05AE 0594 0315 0062;0061 05AE 0300 0594 0315 0062;00E0 05AE 0594 0315 0062;0061 05AE 0300 0594 0315 0062; # (a◌̕◌̀◌֮◌֔b; à◌֮◌֔◌̕b; a◌֮◌̀◌֔◌̕b; à◌֮◌֔◌̕b; a◌֮◌̀◌֔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZAQEF QATAN, LATIN SMALL LETTER B +0061 0594 0315 0300 05AE 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062; # (a◌֔◌̕◌̀◌֮b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF QATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0595 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062; # (a◌̕◌̀◌֮◌֕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZAQEF GADOL, LATIN SMALL LETTER B +0061 0595 0315 0300 05AE 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062; # (a◌֕◌̕◌̀◌֮b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF GADOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0596 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062; # (a◌֚◌̖◌᷺◌֖b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT TIPEHA, LATIN SMALL LETTER B +0061 0596 059A 0316 1DFA 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062; # (a◌֖◌֚◌̖◌᷺b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TIPEHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0597 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062; # (a◌̕◌̀◌֮◌֗b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT REVIA, LATIN SMALL LETTER B +0061 0597 0315 0300 05AE 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062; # (a◌֗◌̕◌̀◌֮b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT REVIA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0598 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062; # (a◌̕◌̀◌֮◌֘b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZARQA, LATIN SMALL LETTER B +0061 0598 0315 0300 05AE 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062;0061 05AE 0598 0300 0315 0062; # (a◌֘◌̕◌̀◌֮b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; a◌֮◌֘◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZARQA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0599 0062;00E0 05AE 0599 0315 0062;0061 05AE 0300 0599 0315 0062;00E0 05AE 0599 0315 0062;0061 05AE 0300 0599 0315 0062; # (a◌̕◌̀◌֮◌֙b; à◌֮◌֙◌̕b; a◌֮◌̀◌֙◌̕b; à◌֮◌֙◌̕b; a◌֮◌̀◌֙◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT PASHTA, LATIN SMALL LETTER B +0061 0599 0315 0300 05AE 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062; # (a◌֙◌̕◌̀◌֮b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PASHTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 302E 059A 0316 059A 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a〮◌֚◌̖◌֚b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 059A 302E 059A 0316 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a◌֚〮◌֚◌̖b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 059A 0316 1DFA 059B 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062; # (a◌֚◌̖◌᷺◌֛b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT TEVIR, LATIN SMALL LETTER B +0061 059B 059A 0316 1DFA 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062; # (a◌֛◌֚◌̖◌᷺b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TEVIR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 059C 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062; # (a◌̕◌̀◌֮◌֜b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH, LATIN SMALL LETTER B +0061 059C 0315 0300 05AE 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062; # (a◌֜◌̕◌̀◌֮b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERESH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059D 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062; # (a◌̕◌̀◌֮◌֝b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH MUQDAM, LATIN SMALL LETTER B +0061 059D 0315 0300 05AE 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062;0061 05AE 059D 0300 0315 0062; # (a◌֝◌̕◌̀◌֮b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; a◌֮◌֝◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERESH MUQDAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059E 0062;00E0 05AE 059E 0315 0062;0061 05AE 0300 059E 0315 0062;00E0 05AE 059E 0315 0062;0061 05AE 0300 059E 0315 0062; # (a◌̕◌̀◌֮◌֞b; à◌֮◌֞◌̕b; a◌֮◌̀◌֞◌̕b; à◌֮◌֞◌̕b; a◌֮◌̀◌֞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERSHAYIM, LATIN SMALL LETTER B +0061 059E 0315 0300 05AE 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062;0061 05AE 059E 0300 0315 0062; # (a◌֞◌̕◌̀◌֮b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; a◌֮◌֞◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERSHAYIM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 059F 0062;00E0 05AE 059F 0315 0062;0061 05AE 0300 059F 0315 0062;00E0 05AE 059F 0315 0062;0061 05AE 0300 059F 0315 0062; # (a◌̕◌̀◌֮◌֟b; à◌֮◌֟◌̕b; a◌֮◌̀◌֟◌̕b; à◌֮◌֟◌̕b; a◌֮◌̀◌֟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT QARNEY PARA, LATIN SMALL LETTER B +0061 059F 0315 0300 05AE 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062;0061 05AE 059F 0300 0315 0062; # (a◌֟◌̕◌̀◌֮b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; a◌֮◌֟◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT QARNEY PARA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A0 0062;00E0 05AE 05A0 0315 0062;0061 05AE 0300 05A0 0315 0062;00E0 05AE 05A0 0315 0062;0061 05AE 0300 05A0 0315 0062; # (a◌̕◌̀◌֮◌֠b; à◌֮◌֠◌̕b; a◌֮◌̀◌֠◌̕b; à◌֮◌֠◌̕b; a◌֮◌̀◌֠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT TELISHA GEDOLA, LATIN SMALL LETTER B +0061 05A0 0315 0300 05AE 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062; # (a◌֠◌̕◌̀◌֮b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA GEDOLA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A1 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062; # (a◌̕◌̀◌֮◌֡b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT PAZER, LATIN SMALL LETTER B +0061 05A1 0315 0300 05AE 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062; # (a◌֡◌̕◌̀◌֮b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PAZER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A2 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062; # (a◌֚◌̖◌᷺◌֢b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT ATNAH HAFUKH, LATIN SMALL LETTER B +0061 05A2 059A 0316 1DFA 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062; # (a◌֢◌֚◌̖◌᷺b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ATNAH HAFUKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A3 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062; # (a◌֚◌̖◌᷺◌֣b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MUNAH, LATIN SMALL LETTER B +0061 05A3 059A 0316 1DFA 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062; # (a◌֣◌֚◌̖◌᷺b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MUNAH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A4 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062; # (a◌֚◌̖◌᷺◌֤b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MAHAPAKH, LATIN SMALL LETTER B +0061 05A4 059A 0316 1DFA 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062; # (a◌֤◌֚◌̖◌᷺b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MAHAPAKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A5 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062; # (a◌֚◌̖◌᷺◌֥b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MERKHA, LATIN SMALL LETTER B +0061 05A5 059A 0316 1DFA 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062; # (a◌֥◌֚◌̖◌᷺b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A6 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062; # (a◌֚◌̖◌᷺◌֦b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MERKHA KEFULA, LATIN SMALL LETTER B +0061 05A6 059A 0316 1DFA 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062; # (a◌֦◌֚◌̖◌᷺b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA KEFULA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A7 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062; # (a◌֚◌̖◌᷺◌֧b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT DARGA, LATIN SMALL LETTER B +0061 05A7 059A 0316 1DFA 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062; # (a◌֧◌֚◌̖◌᷺b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT DARGA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A8 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062; # (a◌̕◌̀◌֮◌֨b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT QADMA, LATIN SMALL LETTER B +0061 05A8 0315 0300 05AE 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062; # (a◌֨◌̕◌̀◌֮b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT QADMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05A9 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062; # (a◌̕◌̀◌֮◌֩b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT TELISHA QETANA, LATIN SMALL LETTER B +0061 05A9 0315 0300 05AE 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062; # (a◌֩◌̕◌̀◌֮b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA QETANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05AA 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062; # (a◌֚◌̖◌᷺◌֪b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT YERAH BEN YOMO, LATIN SMALL LETTER B +0061 05AA 059A 0316 1DFA 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062; # (a◌֪◌֚◌̖◌᷺b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YERAH BEN YOMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AB 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062; # (a◌̕◌̀◌֮◌֫b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT OLE, LATIN SMALL LETTER B +0061 05AB 0315 0300 05AE 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062; # (a◌֫◌̕◌̀◌֮b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT OLE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AC 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062; # (a◌̕◌̀◌֮◌֬b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ILUY, LATIN SMALL LETTER B +0061 05AC 0315 0300 05AE 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062;0061 05AE 05AC 0300 0315 0062; # (a◌֬◌̕◌̀◌֮b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; a◌֮◌֬◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ILUY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 302E 059A 0316 05AD 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062;0061 0316 059A 05AD 302E 0062; # (a〮◌֚◌̖◌֭b; a◌̖◌֚◌֭〮b; a◌̖◌֚◌֭〮b; a◌̖◌֚◌֭〮b; a◌̖◌֚◌֭〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT DEHI, LATIN SMALL LETTER B +0061 05AD 302E 059A 0316 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062;0061 0316 05AD 059A 302E 0062; # (a◌֭〮◌֚◌̖b; a◌̖◌֭◌֚〮b; a◌̖◌֭◌֚〮b; a◌̖◌֭◌֚〮b; a◌̖◌֭◌֚〮b; ) LATIN SMALL LETTER A, HEBREW ACCENT DEHI, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 05AE 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062; # (a◌̀◌𝅭֮◌֮b; à𝅭◌֮◌֮b; a𝅭◌֮◌֮◌̀b; à𝅭◌֮◌֮b; a𝅭◌֮◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05AE 0300 05AE 1D16D 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062;00E0 1D16D 05AE 05AE 0062;0061 1D16D 05AE 05AE 0300 0062; # (a◌֮◌̀◌𝅭֮b; à𝅭◌֮◌֮b; a𝅭◌֮◌֮◌̀b; à𝅭◌֮◌֮b; a𝅭◌֮◌֮◌̀b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZINOR, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05AF 0062;00E0 05AE 05AF 0315 0062;0061 05AE 0300 05AF 0315 0062;00E0 05AE 05AF 0315 0062;0061 05AE 0300 05AF 0315 0062; # (a◌̕◌̀◌֮◌֯b; à◌֮◌֯◌̕b; a◌֮◌̀◌֯◌̕b; à◌֮◌֯◌̕b; a◌֮◌̀◌֯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW MARK MASORA CIRCLE, LATIN SMALL LETTER B +0061 05AF 0315 0300 05AE 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062;0061 05AE 05AF 0300 0315 0062; # (a◌֯◌̕◌̀◌֮b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; a◌֮◌֯◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW MARK MASORA CIRCLE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B1 05B0 094D 05B0 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062; # (a◌ֱ◌ְ◌्◌ְb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, HEBREW POINT SHEVA, LATIN SMALL LETTER B +0061 05B0 05B1 05B0 094D 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062;0061 094D 05B0 05B0 05B1 0062; # (a◌ְ◌ֱ◌ְ◌्b; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; a◌्◌ְ◌ְ◌ֱb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, LATIN SMALL LETTER B +0061 05B2 05B1 05B0 05B1 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062; # (a◌ֲ◌ֱ◌ְ◌ֱb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, HEBREW POINT HATAF SEGOL, LATIN SMALL LETTER B +0061 05B1 05B2 05B1 05B0 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062;0061 05B0 05B1 05B1 05B2 0062; # (a◌ֱ◌ֲ◌ֱ◌ְb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; a◌ְ◌ֱ◌ֱ◌ֲb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF SEGOL, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT SHEVA, LATIN SMALL LETTER B +0061 05B3 05B2 05B1 05B2 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062; # (a◌ֳ◌ֲ◌ֱ◌ֲb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, HEBREW POINT HATAF PATAH, LATIN SMALL LETTER B +0061 05B2 05B3 05B2 05B1 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062;0061 05B1 05B2 05B2 05B3 0062; # (a◌ֲ◌ֳ◌ֲ◌ֱb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; a◌ֱ◌ֲ◌ֲ◌ֳb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF SEGOL, LATIN SMALL LETTER B +0061 05B4 05B3 05B2 05B3 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062; # (a◌ִ◌ֳ◌ֲ◌ֳb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; ) LATIN SMALL LETTER A, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, HEBREW POINT HATAF QAMATS, LATIN SMALL LETTER B +0061 05B3 05B4 05B3 05B2 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062;0061 05B2 05B3 05B3 05B4 0062; # (a◌ֳ◌ִ◌ֳ◌ֲb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; a◌ֲ◌ֳ◌ֳ◌ִb; ) LATIN SMALL LETTER A, HEBREW POINT HATAF QAMATS, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HATAF PATAH, LATIN SMALL LETTER B +0061 05B5 05B4 05B3 05B4 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062; # (a◌ֵ◌ִ◌ֳ◌ִb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; ) LATIN SMALL LETTER A, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, HEBREW POINT HIRIQ, LATIN SMALL LETTER B +0061 05B4 05B5 05B4 05B3 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062;0061 05B3 05B4 05B4 05B5 0062; # (a◌ִ◌ֵ◌ִ◌ֳb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; a◌ֳ◌ִ◌ִ◌ֵb; ) LATIN SMALL LETTER A, HEBREW POINT HIRIQ, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT HATAF QAMATS, LATIN SMALL LETTER B +0061 05B6 05B5 05B4 05B5 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062; # (a◌ֶ◌ֵ◌ִ◌ֵb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; ) LATIN SMALL LETTER A, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT HIRIQ, HEBREW POINT TSERE, LATIN SMALL LETTER B +0061 05B5 05B6 05B5 05B4 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062;0061 05B4 05B5 05B5 05B6 0062; # (a◌ֵ◌ֶ◌ֵ◌ִb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; a◌ִ◌ֵ◌ֵ◌ֶb; ) LATIN SMALL LETTER A, HEBREW POINT TSERE, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT HIRIQ, LATIN SMALL LETTER B +0061 05B7 05B6 05B5 05B6 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062; # (a◌ַ◌ֶ◌ֵ◌ֶb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; ) LATIN SMALL LETTER A, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT TSERE, HEBREW POINT SEGOL, LATIN SMALL LETTER B +0061 05B6 05B7 05B6 05B5 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062;0061 05B5 05B6 05B6 05B7 0062; # (a◌ֶ◌ַ◌ֶ◌ֵb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; a◌ֵ◌ֶ◌ֶ◌ַb; ) LATIN SMALL LETTER A, HEBREW POINT SEGOL, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT TSERE, LATIN SMALL LETTER B +0061 05B8 05B7 05B6 05B7 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062; # (a◌ָ◌ַ◌ֶ◌ַb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT SEGOL, HEBREW POINT PATAH, LATIN SMALL LETTER B +0061 05B7 05B8 05B7 05B6 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062;0061 05B6 05B7 05B7 05B8 0062; # (a◌ַ◌ָ◌ַ◌ֶb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; a◌ֶ◌ַ◌ַ◌ָb; ) LATIN SMALL LETTER A, HEBREW POINT PATAH, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT SEGOL, LATIN SMALL LETTER B +0061 05B9 05B8 05B7 05B8 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062; # (a◌ֹ◌ָ◌ַ◌ָb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT QAMATS, LATIN SMALL LETTER B +0061 05B8 05B9 05B8 05B7 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062;0061 05B7 05B8 05B8 05B9 0062; # (a◌ָ◌ֹ◌ָ◌ַb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; a◌ַ◌ָ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, LATIN SMALL LETTER B +0061 05BB 05B9 05B8 05B9 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062; # (a◌ֻ◌ֹ◌ָ◌ֹb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT HOLAM, LATIN SMALL LETTER B +0061 05B9 05BB 05B9 05B8 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062;0061 05B8 05B9 05B9 05BB 0062; # (a◌ֹ◌ֻ◌ֹ◌ָb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; a◌ָ◌ֹ◌ֹ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, LATIN SMALL LETTER B +0061 05BB 05B9 05B8 05BA 0062;0061 05B8 05B9 05BA 05BB 0062;0061 05B8 05B9 05BA 05BB 0062;0061 05B8 05B9 05BA 05BB 0062;0061 05B8 05B9 05BA 05BB 0062; # (a◌ֻ◌ֹ◌ָ◌ֺb; a◌ָ◌ֹ◌ֺ◌ֻb; a◌ָ◌ֹ◌ֺ◌ֻb; a◌ָ◌ֹ◌ֺ◌ֻb; a◌ָ◌ֹ◌ֺ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT HOLAM HASER FOR VAV, LATIN SMALL LETTER B +0061 05BA 05BB 05B9 05B8 0062;0061 05B8 05BA 05B9 05BB 0062;0061 05B8 05BA 05B9 05BB 0062;0061 05B8 05BA 05B9 05BB 0062;0061 05B8 05BA 05B9 05BB 0062; # (a◌ֺ◌ֻ◌ֹ◌ָb; a◌ָ◌ֺ◌ֹ◌ֻb; a◌ָ◌ֺ◌ֹ◌ֻb; a◌ָ◌ֺ◌ֹ◌ֻb; a◌ָ◌ֺ◌ֹ◌ֻb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM HASER FOR VAV, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QAMATS, LATIN SMALL LETTER B +0061 05BC 05BB 05B9 05BB 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062; # (a◌ּ◌ֻ◌ֹ◌ֻb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; ) LATIN SMALL LETTER A, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, HEBREW POINT QUBUTS, LATIN SMALL LETTER B +0061 05BB 05BC 05BB 05B9 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062;0061 05B9 05BB 05BB 05BC 0062; # (a◌ֻ◌ּ◌ֻ◌ֹb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; a◌ֹ◌ֻ◌ֻ◌ּb; ) LATIN SMALL LETTER A, HEBREW POINT QUBUTS, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT HOLAM, LATIN SMALL LETTER B +0061 05BD 05BC 05BB 05BC 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062; # (a◌ֽ◌ּ◌ֻ◌ּb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; ) LATIN SMALL LETTER A, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, HEBREW POINT DAGESH OR MAPIQ, LATIN SMALL LETTER B +0061 05BC 05BD 05BC 05BB 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062;0061 05BB 05BC 05BC 05BD 0062; # (a◌ּ◌ֽ◌ּ◌ֻb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; a◌ֻ◌ּ◌ּ◌ֽb; ) LATIN SMALL LETTER A, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT QUBUTS, LATIN SMALL LETTER B +0061 05BF 05BD 05BC 05BD 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062; # (a◌ֿ◌ֽ◌ּ◌ֽb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; ) LATIN SMALL LETTER A, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, HEBREW POINT METEG, LATIN SMALL LETTER B +0061 05BD 05BF 05BD 05BC 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062;0061 05BC 05BD 05BD 05BF 0062; # (a◌ֽ◌ֿ◌ֽ◌ּb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; a◌ּ◌ֽ◌ֽ◌ֿb; ) LATIN SMALL LETTER A, HEBREW POINT METEG, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT DAGESH OR MAPIQ, LATIN SMALL LETTER B +0061 05C1 05BF 05BD 05BF 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062; # (a◌ׁ◌ֿ◌ֽ◌ֿb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; ) LATIN SMALL LETTER A, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT METEG, HEBREW POINT RAFE, LATIN SMALL LETTER B +0061 05BF 05C1 05BF 05BD 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062;0061 05BD 05BF 05BF 05C1 0062; # (a◌ֿ◌ׁ◌ֿ◌ֽb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; a◌ֽ◌ֿ◌ֿ◌ׁb; ) LATIN SMALL LETTER A, HEBREW POINT RAFE, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT METEG, LATIN SMALL LETTER B +0061 05C2 05C1 05BF 05C1 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062; # (a◌ׂ◌ׁ◌ֿ◌ׁb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; ) LATIN SMALL LETTER A, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, HEBREW POINT SHIN DOT, LATIN SMALL LETTER B +0061 05C1 05C2 05C1 05BF 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062;0061 05BF 05C1 05C1 05C2 0062; # (a◌ׁ◌ׂ◌ׁ◌ֿb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; a◌ֿ◌ׁ◌ׁ◌ׂb; ) LATIN SMALL LETTER A, HEBREW POINT SHIN DOT, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT RAFE, LATIN SMALL LETTER B +0061 FB1E 05C2 05C1 05C2 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062; # (a◌ﬞ◌ׂ◌ׁ◌ׂb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; ) LATIN SMALL LETTER A, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, HEBREW POINT SIN DOT, LATIN SMALL LETTER B +0061 05C2 FB1E 05C2 05C1 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062; # (a◌ׂ◌ﬞ◌ׂ◌ׁb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; ) LATIN SMALL LETTER A, HEBREW POINT SIN DOT, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE 05C4 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062; # (a◌̕◌̀◌֮◌ׄb; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW MARK UPPER DOT, LATIN SMALL LETTER B +0061 05C4 0315 0300 05AE 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062; # (a◌ׄ◌̕◌̀◌֮b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW MARK UPPER DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05C5 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062; # (a◌֚◌̖◌᷺◌ׅb; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW MARK LOWER DOT, LATIN SMALL LETTER B +0061 05C5 059A 0316 1DFA 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062; # (a◌ׅ◌֚◌̖◌᷺b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW MARK LOWER DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 05B9 05B8 05B7 05C7 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062; # (a◌ֹ◌ָ◌ַ◌ׇb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT QAMATS QATAN, LATIN SMALL LETTER B +0061 05C7 05B9 05B8 05B7 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062; # (a◌ׇ◌ֹ◌ָ◌ַb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS QATAN, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, LATIN SMALL LETTER B +0061 0315 0300 05AE 0610 0062;00E0 05AE 0610 0315 0062;0061 05AE 0300 0610 0315 0062;00E0 05AE 0610 0315 0062;0061 05AE 0300 0610 0315 0062; # (a◌̕◌̀◌֮◌ؐb; à◌֮◌ؐ◌̕b; a◌֮◌̀◌ؐ◌̕b; à◌֮◌ؐ◌̕b; a◌֮◌̀◌ؐ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM, LATIN SMALL LETTER B +0061 0610 0315 0300 05AE 0062;0061 05AE 0610 0300 0315 0062;0061 05AE 0610 0300 0315 0062;0061 05AE 0610 0300 0315 0062;0061 05AE 0610 0300 0315 0062; # (a◌ؐ◌̕◌̀◌֮b; a◌֮◌ؐ◌̀◌̕b; a◌֮◌ؐ◌̀◌̕b; a◌֮◌ؐ◌̀◌̕b; a◌֮◌ؐ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0611 0062;00E0 05AE 0611 0315 0062;0061 05AE 0300 0611 0315 0062;00E0 05AE 0611 0315 0062;0061 05AE 0300 0611 0315 0062; # (a◌̕◌̀◌֮◌ؑb; à◌֮◌ؑ◌̕b; a◌֮◌̀◌ؑ◌̕b; à◌֮◌ؑ◌̕b; a◌֮◌̀◌ؑ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN ALAYHE ASSALLAM, LATIN SMALL LETTER B +0061 0611 0315 0300 05AE 0062;0061 05AE 0611 0300 0315 0062;0061 05AE 0611 0300 0315 0062;0061 05AE 0611 0300 0315 0062;0061 05AE 0611 0300 0315 0062; # (a◌ؑ◌̕◌̀◌֮b; a◌֮◌ؑ◌̀◌̕b; a◌֮◌ؑ◌̀◌̕b; a◌֮◌ؑ◌̀◌̕b; a◌֮◌ؑ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SIGN ALAYHE ASSALLAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0612 0062;00E0 05AE 0612 0315 0062;0061 05AE 0300 0612 0315 0062;00E0 05AE 0612 0315 0062;0061 05AE 0300 0612 0315 0062; # (a◌̕◌̀◌֮◌ؒb; à◌֮◌ؒ◌̕b; a◌֮◌̀◌ؒ◌̕b; à◌֮◌ؒ◌̕b; a◌֮◌̀◌ؒ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN RAHMATULLAH ALAYHE, LATIN SMALL LETTER B +0061 0612 0315 0300 05AE 0062;0061 05AE 0612 0300 0315 0062;0061 05AE 0612 0300 0315 0062;0061 05AE 0612 0300 0315 0062;0061 05AE 0612 0300 0315 0062; # (a◌ؒ◌̕◌̀◌֮b; a◌֮◌ؒ◌̀◌̕b; a◌֮◌ؒ◌̀◌̕b; a◌֮◌ؒ◌̀◌̕b; a◌֮◌ؒ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SIGN RAHMATULLAH ALAYHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0613 0062;00E0 05AE 0613 0315 0062;0061 05AE 0300 0613 0315 0062;00E0 05AE 0613 0315 0062;0061 05AE 0300 0613 0315 0062; # (a◌̕◌̀◌֮◌ؓb; à◌֮◌ؓ◌̕b; a◌֮◌̀◌ؓ◌̕b; à◌֮◌ؓ◌̕b; a◌֮◌̀◌ؓ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN RADI ALLAHOU ANHU, LATIN SMALL LETTER B +0061 0613 0315 0300 05AE 0062;0061 05AE 0613 0300 0315 0062;0061 05AE 0613 0300 0315 0062;0061 05AE 0613 0300 0315 0062;0061 05AE 0613 0300 0315 0062; # (a◌ؓ◌̕◌̀◌֮b; a◌֮◌ؓ◌̀◌̕b; a◌֮◌ؓ◌̀◌̕b; a◌֮◌ؓ◌̀◌̕b; a◌֮◌ؓ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SIGN RADI ALLAHOU ANHU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0614 0062;00E0 05AE 0614 0315 0062;0061 05AE 0300 0614 0315 0062;00E0 05AE 0614 0315 0062;0061 05AE 0300 0614 0315 0062; # (a◌̕◌̀◌֮◌ؔb; à◌֮◌ؔ◌̕b; a◌֮◌̀◌ؔ◌̕b; à◌֮◌ؔ◌̕b; a◌֮◌̀◌ؔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN TAKHALLUS, LATIN SMALL LETTER B +0061 0614 0315 0300 05AE 0062;0061 05AE 0614 0300 0315 0062;0061 05AE 0614 0300 0315 0062;0061 05AE 0614 0300 0315 0062;0061 05AE 0614 0300 0315 0062; # (a◌ؔ◌̕◌̀◌֮b; a◌֮◌ؔ◌̀◌̕b; a◌֮◌ؔ◌̀◌̕b; a◌֮◌ؔ◌̀◌̕b; a◌֮◌ؔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SIGN TAKHALLUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0615 0062;00E0 05AE 0615 0315 0062;0061 05AE 0300 0615 0315 0062;00E0 05AE 0615 0315 0062;0061 05AE 0300 0615 0315 0062; # (a◌̕◌̀◌֮◌ؕb; à◌֮◌ؕ◌̕b; a◌֮◌̀◌ؕ◌̕b; à◌֮◌ؕ◌̕b; a◌֮◌̀◌ؕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH TAH, LATIN SMALL LETTER B +0061 0615 0315 0300 05AE 0062;0061 05AE 0615 0300 0315 0062;0061 05AE 0615 0300 0315 0062;0061 05AE 0615 0300 0315 0062;0061 05AE 0615 0300 0315 0062; # (a◌ؕ◌̕◌̀◌֮b; a◌֮◌ؕ◌̀◌̕b; a◌֮◌ؕ◌̀◌̕b; a◌֮◌ؕ◌̀◌̕b; a◌֮◌ؕ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH TAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0616 0062;00E0 05AE 0616 0315 0062;0061 05AE 0300 0616 0315 0062;00E0 05AE 0616 0315 0062;0061 05AE 0300 0616 0315 0062; # (a◌̕◌̀◌֮◌ؖb; à◌֮◌ؖ◌̕b; a◌֮◌̀◌ؖ◌̕b; à◌֮◌ؖ◌̕b; a◌֮◌̀◌ؖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH, LATIN SMALL LETTER B +0061 0616 0315 0300 05AE 0062;0061 05AE 0616 0300 0315 0062;0061 05AE 0616 0300 0315 0062;0061 05AE 0616 0300 0315 0062;0061 05AE 0616 0300 0315 0062; # (a◌ؖ◌̕◌̀◌֮b; a◌֮◌ؖ◌̀◌̕b; a◌֮◌ؖ◌̀◌̕b; a◌֮◌ؖ◌̀◌̕b; a◌֮◌ؖ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0617 0062;00E0 05AE 0617 0315 0062;0061 05AE 0300 0617 0315 0062;00E0 05AE 0617 0315 0062;0061 05AE 0300 0617 0315 0062; # (a◌̕◌̀◌֮◌ؗb; à◌֮◌ؗ◌̕b; a◌֮◌̀◌ؗ◌̕b; à◌֮◌ؗ◌̕b; a◌֮◌̀◌ؗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH ZAIN, LATIN SMALL LETTER B +0061 0617 0315 0300 05AE 0062;0061 05AE 0617 0300 0315 0062;0061 05AE 0617 0300 0315 0062;0061 05AE 0617 0300 0315 0062;0061 05AE 0617 0300 0315 0062; # (a◌ؗ◌̕◌̀◌֮b; a◌֮◌ؗ◌̀◌̕b; a◌֮◌ؗ◌̀◌̕b; a◌֮◌ؗ◌̀◌̕b; a◌֮◌ؗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH ZAIN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0619 0618 064D 0618 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062; # (a◌ؙ◌ؘ◌ٍ◌ؘb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; ) LATIN SMALL LETTER A, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC SMALL FATHA, LATIN SMALL LETTER B +0061 0618 0619 0618 064D 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062;0061 064D 0618 0618 0619 0062; # (a◌ؘ◌ؙ◌ؘ◌ٍb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; a◌ٍ◌ؘ◌ؘ◌ؙb; ) LATIN SMALL LETTER A, ARABIC SMALL FATHA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC KASRATAN, LATIN SMALL LETTER B +0061 061A 0619 0618 0619 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062; # (a◌ؚ◌ؙ◌ؘ◌ؙb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; ) LATIN SMALL LETTER A, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC SMALL DAMMA, LATIN SMALL LETTER B +0061 0619 061A 0619 0618 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062;0061 0618 0619 0619 061A 0062; # (a◌ؙ◌ؚ◌ؙ◌ؘb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; a◌ؘ◌ؙ◌ؙ◌ؚb; ) LATIN SMALL LETTER A, ARABIC SMALL DAMMA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, LATIN SMALL LETTER B +0061 0651 061A 0619 061A 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062; # (a◌ّ◌ؚ◌ؙ◌ؚb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; ) LATIN SMALL LETTER A, ARABIC SHADDA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC SMALL KASRA, LATIN SMALL LETTER B +0061 061A 0651 061A 0619 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062;0061 0619 061A 061A 0651 0062; # (a◌ؚ◌ّ◌ؚ◌ؙb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; a◌ؙ◌ؚ◌ؚ◌ّb; ) LATIN SMALL LETTER A, ARABIC SMALL KASRA, ARABIC SHADDA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, LATIN SMALL LETTER B +0061 064C 064B FB1E 064B 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062; # (a◌ٌ◌ً◌ﬞ◌ًb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC FATHATAN, LATIN SMALL LETTER B +0061 064B 064C 064B FB1E 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062;0061 FB1E 064B 064B 064C 0062; # (a◌ً◌ٌ◌ً◌ﬞb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; a◌ﬞ◌ً◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC FATHATAN, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B +0061 064D 064C 064B 064C 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062; # (a◌ٍ◌ٌ◌ً◌ٌb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, ARABIC DAMMATAN, LATIN SMALL LETTER B +0061 064C 064D 064C 064B 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062;0061 064B 064C 064C 064D 0062; # (a◌ٌ◌ٍ◌ٌ◌ًb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; a◌ً◌ٌ◌ٌ◌ٍb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, LATIN SMALL LETTER B +0061 0618 064D 064C 064D 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062; # (a◌ؘ◌ٍ◌ٌ◌ٍb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; ) LATIN SMALL LETTER A, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC KASRATAN, LATIN SMALL LETTER B +0061 064D 0618 064D 064C 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062;0061 064C 064D 064D 0618 0062; # (a◌ٍ◌ؘ◌ٍ◌ٌb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; a◌ٌ◌ٍ◌ٍ◌ؘb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, LATIN SMALL LETTER B +0061 0619 0618 064D 064E 0062;0061 064D 0618 064E 0619 0062;0061 064D 0618 064E 0619 0062;0061 064D 0618 064E 0619 0062;0061 064D 0618 064E 0619 0062; # (a◌ؙ◌ؘ◌ٍ◌َb; a◌ٍ◌ؘ◌َ◌ؙb; a◌ٍ◌ؘ◌َ◌ؙb; a◌ٍ◌ؘ◌َ◌ؙb; a◌ٍ◌ؘ◌َ◌ؙb; ) LATIN SMALL LETTER A, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC FATHA, LATIN SMALL LETTER B +0061 064E 0619 0618 064D 0062;0061 064D 064E 0618 0619 0062;0061 064D 064E 0618 0619 0062;0061 064D 064E 0618 0619 0062;0061 064D 064E 0618 0619 0062; # (a◌َ◌ؙ◌ؘ◌ٍb; a◌ٍ◌َ◌ؘ◌ؙb; a◌ٍ◌َ◌ؘ◌ؙb; a◌ٍ◌َ◌ؘ◌ؙb; a◌ٍ◌َ◌ؘ◌ؙb; ) LATIN SMALL LETTER A, ARABIC FATHA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC KASRATAN, LATIN SMALL LETTER B +0061 061A 0619 0618 064F 0062;0061 0618 0619 064F 061A 0062;0061 0618 0619 064F 061A 0062;0061 0618 0619 064F 061A 0062;0061 0618 0619 064F 061A 0062; # (a◌ؚ◌ؙ◌ؘ◌ُb; a◌ؘ◌ؙ◌ُ◌ؚb; a◌ؘ◌ؙ◌ُ◌ؚb; a◌ؘ◌ؙ◌ُ◌ؚb; a◌ؘ◌ؙ◌ُ◌ؚb; ) LATIN SMALL LETTER A, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, ARABIC DAMMA, LATIN SMALL LETTER B +0061 064F 061A 0619 0618 0062;0061 0618 064F 0619 061A 0062;0061 0618 064F 0619 061A 0062;0061 0618 064F 0619 061A 0062;0061 0618 064F 0619 061A 0062; # (a◌ُ◌ؚ◌ؙ◌ؘb; a◌ؘ◌ُ◌ؙ◌ؚb; a◌ؘ◌ُ◌ؙ◌ؚb; a◌ؘ◌ُ◌ؙ◌ؚb; a◌ؘ◌ُ◌ؙ◌ؚb; ) LATIN SMALL LETTER A, ARABIC DAMMA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC SMALL FATHA, LATIN SMALL LETTER B +0061 0651 061A 0619 0650 0062;0061 0619 061A 0650 0651 0062;0061 0619 061A 0650 0651 0062;0061 0619 061A 0650 0651 0062;0061 0619 061A 0650 0651 0062; # (a◌ّ◌ؚ◌ؙ◌ِb; a◌ؙ◌ؚ◌ِ◌ّb; a◌ؙ◌ؚ◌ِ◌ّb; a◌ؙ◌ؚ◌ِ◌ّb; a◌ؙ◌ؚ◌ِ◌ّb; ) LATIN SMALL LETTER A, ARABIC SHADDA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, ARABIC KASRA, LATIN SMALL LETTER B +0061 0650 0651 061A 0619 0062;0061 0619 0650 061A 0651 0062;0061 0619 0650 061A 0651 0062;0061 0619 0650 061A 0651 0062;0061 0619 0650 061A 0651 0062; # (a◌ِ◌ّ◌ؚ◌ؙb; a◌ؙ◌ِ◌ؚ◌ّb; a◌ؙ◌ِ◌ؚ◌ّb; a◌ؙ◌ِ◌ؚ◌ّb; a◌ؙ◌ِ◌ؚ◌ّb; ) LATIN SMALL LETTER A, ARABIC KASRA, ARABIC SHADDA, ARABIC SMALL KASRA, ARABIC SMALL DAMMA, LATIN SMALL LETTER B +0061 0652 0651 061A 0651 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062; # (a◌ْ◌ّ◌ؚ◌ّb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; ) LATIN SMALL LETTER A, ARABIC SUKUN, ARABIC SHADDA, ARABIC SMALL KASRA, ARABIC SHADDA, LATIN SMALL LETTER B +0061 0651 0652 0651 061A 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062;0061 061A 0651 0651 0652 0062; # (a◌ّ◌ْ◌ّ◌ؚb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; a◌ؚ◌ّ◌ّ◌ْb; ) LATIN SMALL LETTER A, ARABIC SHADDA, ARABIC SUKUN, ARABIC SHADDA, ARABIC SMALL KASRA, LATIN SMALL LETTER B +0061 0670 0652 0651 0652 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062; # (a◌ٰ◌ْ◌ّ◌ْb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; ) LATIN SMALL LETTER A, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC SHADDA, ARABIC SUKUN, LATIN SMALL LETTER B +0061 0652 0670 0652 0651 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062;0061 0651 0652 0652 0670 0062; # (a◌ْ◌ٰ◌ْ◌ّb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; a◌ّ◌ْ◌ْ◌ٰb; ) LATIN SMALL LETTER A, ARABIC SUKUN, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC SHADDA, LATIN SMALL LETTER B +0061 0315 0300 05AE 0653 0062;00E0 05AE 0653 0315 0062;0061 05AE 0300 0653 0315 0062;00E0 05AE 0653 0315 0062;0061 05AE 0300 0653 0315 0062; # (a◌̕◌̀◌֮◌ٓb; à◌֮◌ٓ◌̕b; a◌֮◌̀◌ٓ◌̕b; à◌֮◌ٓ◌̕b; a◌֮◌̀◌ٓ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MADDAH ABOVE, LATIN SMALL LETTER B +0061 0653 0315 0300 05AE 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062; # (a◌ٓ◌̕◌̀◌֮b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MADDAH ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0654 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062; # (a◌̕◌̀◌֮◌ٔb; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC HAMZA ABOVE, LATIN SMALL LETTER B +0061 0654 0315 0300 05AE 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062; # (a◌ٔ◌̕◌̀◌֮b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC HAMZA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0655 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062; # (a◌֚◌̖◌᷺◌ٕb; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC HAMZA BELOW, LATIN SMALL LETTER B +0061 0655 059A 0316 1DFA 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062; # (a◌ٕ◌֚◌̖◌᷺b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0656 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062; # (a◌֚◌̖◌᷺◌ٖb; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SUBSCRIPT ALEF, LATIN SMALL LETTER B +0061 0656 059A 0316 1DFA 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062; # (a◌ٖ◌֚◌̖◌᷺b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SUBSCRIPT ALEF, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0657 0062;00E0 05AE 0657 0315 0062;0061 05AE 0300 0657 0315 0062;00E0 05AE 0657 0315 0062;0061 05AE 0300 0657 0315 0062; # (a◌̕◌̀◌֮◌ٗb; à◌֮◌ٗ◌̕b; a◌֮◌̀◌ٗ◌̕b; à◌֮◌ٗ◌̕b; a◌֮◌̀◌ٗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC INVERTED DAMMA, LATIN SMALL LETTER B +0061 0657 0315 0300 05AE 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062; # (a◌ٗ◌̕◌̀◌֮b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC INVERTED DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0658 0062;00E0 05AE 0658 0315 0062;0061 05AE 0300 0658 0315 0062;00E0 05AE 0658 0315 0062;0061 05AE 0300 0658 0315 0062; # (a◌̕◌̀◌֮◌٘b; à◌֮◌٘◌̕b; a◌֮◌̀◌٘◌̕b; à◌֮◌٘◌̕b; a◌֮◌̀◌٘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MARK NOON GHUNNA, LATIN SMALL LETTER B +0061 0658 0315 0300 05AE 0062;0061 05AE 0658 0300 0315 0062;0061 05AE 0658 0300 0315 0062;0061 05AE 0658 0300 0315 0062;0061 05AE 0658 0300 0315 0062; # (a◌٘◌̕◌̀◌֮b; a◌֮◌٘◌̀◌̕b; a◌֮◌٘◌̀◌̕b; a◌֮◌٘◌̀◌̕b; a◌֮◌٘◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MARK NOON GHUNNA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0659 0062;00E0 05AE 0659 0315 0062;0061 05AE 0300 0659 0315 0062;00E0 05AE 0659 0315 0062;0061 05AE 0300 0659 0315 0062; # (a◌̕◌̀◌֮◌ٙb; à◌֮◌ٙ◌̕b; a◌֮◌̀◌ٙ◌̕b; à◌֮◌ٙ◌̕b; a◌֮◌̀◌ٙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC ZWARAKAY, LATIN SMALL LETTER B +0061 0659 0315 0300 05AE 0062;0061 05AE 0659 0300 0315 0062;0061 05AE 0659 0300 0315 0062;0061 05AE 0659 0300 0315 0062;0061 05AE 0659 0300 0315 0062; # (a◌ٙ◌̕◌̀◌֮b; a◌֮◌ٙ◌̀◌̕b; a◌֮◌ٙ◌̀◌̕b; a◌֮◌ٙ◌̀◌̕b; a◌֮◌ٙ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC ZWARAKAY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 065A 0062;00E0 05AE 065A 0315 0062;0061 05AE 0300 065A 0315 0062;00E0 05AE 065A 0315 0062;0061 05AE 0300 065A 0315 0062; # (a◌̕◌̀◌֮◌ٚb; à◌֮◌ٚ◌̕b; a◌֮◌̀◌ٚ◌̕b; à◌֮◌ٚ◌̕b; a◌֮◌̀◌ٚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC VOWEL SIGN SMALL V ABOVE, LATIN SMALL LETTER B +0061 065A 0315 0300 05AE 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062; # (a◌ٚ◌̕◌̀◌֮b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN SMALL V ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 065B 0062;00E0 05AE 065B 0315 0062;0061 05AE 0300 065B 0315 0062;00E0 05AE 065B 0315 0062;0061 05AE 0300 065B 0315 0062; # (a◌̕◌̀◌֮◌ٛb; à◌֮◌ٛ◌̕b; a◌֮◌̀◌ٛ◌̕b; à◌֮◌ٛ◌̕b; a◌֮◌̀◌ٛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC VOWEL SIGN INVERTED SMALL V ABOVE, LATIN SMALL LETTER B +0061 065B 0315 0300 05AE 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062; # (a◌ٛ◌̕◌̀◌֮b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN INVERTED SMALL V ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 065C 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062; # (a◌֚◌̖◌᷺◌ٜb; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC VOWEL SIGN DOT BELOW, LATIN SMALL LETTER B +0061 065C 059A 0316 1DFA 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062; # (a◌ٜ◌֚◌̖◌᷺b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 065D 0062;00E0 05AE 065D 0315 0062;0061 05AE 0300 065D 0315 0062;00E0 05AE 065D 0315 0062;0061 05AE 0300 065D 0315 0062; # (a◌̕◌̀◌֮◌ٝb; à◌֮◌ٝ◌̕b; a◌֮◌̀◌ٝ◌̕b; à◌֮◌ٝ◌̕b; a◌֮◌̀◌ٝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC REVERSED DAMMA, LATIN SMALL LETTER B +0061 065D 0315 0300 05AE 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062; # (a◌ٝ◌̕◌̀◌֮b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC REVERSED DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 065E 0062;00E0 05AE 065E 0315 0062;0061 05AE 0300 065E 0315 0062;00E0 05AE 065E 0315 0062;0061 05AE 0300 065E 0315 0062; # (a◌̕◌̀◌֮◌ٞb; à◌֮◌ٞ◌̕b; a◌֮◌̀◌ٞ◌̕b; à◌֮◌ٞ◌̕b; a◌֮◌̀◌ٞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC FATHA WITH TWO DOTS, LATIN SMALL LETTER B +0061 065E 0315 0300 05AE 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062; # (a◌ٞ◌̕◌̀◌֮b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH TWO DOTS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 065F 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062; # (a◌֚◌̖◌᷺◌ٟb; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC WAVY HAMZA BELOW, LATIN SMALL LETTER B +0061 065F 059A 0316 1DFA 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062; # (a◌ٟ◌֚◌̖◌᷺b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC WAVY HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0711 0670 0652 0670 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ܑ◌ٰ◌ْ◌ٰb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B +0061 0670 0711 0670 0652 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ٰ◌ܑ◌ٰ◌ْb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D6 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062; # (a◌̕◌̀◌֮◌ۖb; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA, LATIN SMALL LETTER B +0061 06D6 0315 0300 05AE 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062;0061 05AE 06D6 0300 0315 0062; # (a◌ۖ◌̕◌̀◌֮b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; a◌֮◌ۖ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D7 0062;00E0 05AE 06D7 0315 0062;0061 05AE 0300 06D7 0315 0062;00E0 05AE 06D7 0315 0062;0061 05AE 0300 06D7 0315 0062; # (a◌̕◌̀◌֮◌ۗb; à◌֮◌ۗ◌̕b; a◌֮◌̀◌ۗ◌̕b; à◌֮◌ۗ◌̕b; a◌֮◌̀◌ۗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA, LATIN SMALL LETTER B +0061 06D7 0315 0300 05AE 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062;0061 05AE 06D7 0300 0315 0062; # (a◌ۗ◌̕◌̀◌֮b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; a◌֮◌ۗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D8 0062;00E0 05AE 06D8 0315 0062;0061 05AE 0300 06D8 0315 0062;00E0 05AE 06D8 0315 0062;0061 05AE 0300 06D8 0315 0062; # (a◌̕◌̀◌֮◌ۘb; à◌֮◌ۘ◌̕b; a◌֮◌̀◌ۘ◌̕b; à◌֮◌ۘ◌̕b; a◌֮◌̀◌ۘ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MEEM INITIAL FORM, LATIN SMALL LETTER B +0061 06D8 0315 0300 05AE 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062;0061 05AE 06D8 0300 0315 0062; # (a◌ۘ◌̕◌̀◌֮b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; a◌֮◌ۘ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MEEM INITIAL FORM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06D9 0062;00E0 05AE 06D9 0315 0062;0061 05AE 0300 06D9 0315 0062;00E0 05AE 06D9 0315 0062;0061 05AE 0300 06D9 0315 0062; # (a◌̕◌̀◌֮◌ۙb; à◌֮◌ۙ◌̕b; a◌֮◌̀◌ۙ◌̕b; à◌֮◌ۙ◌̕b; a◌֮◌̀◌ۙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LAM ALEF, LATIN SMALL LETTER B +0061 06D9 0315 0300 05AE 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062;0061 05AE 06D9 0300 0315 0062; # (a◌ۙ◌̕◌̀◌֮b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; a◌֮◌ۙ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH LAM ALEF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DA 0062;00E0 05AE 06DA 0315 0062;0061 05AE 0300 06DA 0315 0062;00E0 05AE 06DA 0315 0062;0061 05AE 0300 06DA 0315 0062; # (a◌̕◌̀◌֮◌ۚb; à◌֮◌ۚ◌̕b; a◌֮◌̀◌ۚ◌̕b; à◌֮◌ۚ◌̕b; a◌֮◌̀◌ۚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH JEEM, LATIN SMALL LETTER B +0061 06DA 0315 0300 05AE 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062;0061 05AE 06DA 0300 0315 0062; # (a◌ۚ◌̕◌̀◌֮b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; a◌֮◌ۚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH JEEM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DB 0062;00E0 05AE 06DB 0315 0062;0061 05AE 0300 06DB 0315 0062;00E0 05AE 06DB 0315 0062;0061 05AE 0300 06DB 0315 0062; # (a◌̕◌̀◌֮◌ۛb; à◌֮◌ۛ◌̕b; a◌֮◌̀◌ۛ◌̕b; à◌֮◌ۛ◌̕b; a◌֮◌̀◌ۛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH THREE DOTS, LATIN SMALL LETTER B +0061 06DB 0315 0300 05AE 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062;0061 05AE 06DB 0300 0315 0062; # (a◌ۛ◌̕◌̀◌֮b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; a◌֮◌ۛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH THREE DOTS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DC 0062;00E0 05AE 06DC 0315 0062;0061 05AE 0300 06DC 0315 0062;00E0 05AE 06DC 0315 0062;0061 05AE 0300 06DC 0315 0062; # (a◌̕◌̀◌֮◌ۜb; à◌֮◌ۜ◌̕b; a◌֮◌̀◌ۜ◌̕b; à◌֮◌ۜ◌̕b; a◌֮◌̀◌ۜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SEEN, LATIN SMALL LETTER B +0061 06DC 0315 0300 05AE 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062;0061 05AE 06DC 0300 0315 0062; # (a◌ۜ◌̕◌̀◌֮b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; a◌֮◌ۜ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SEEN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06DF 0062;00E0 05AE 06DF 0315 0062;0061 05AE 0300 06DF 0315 0062;00E0 05AE 06DF 0315 0062;0061 05AE 0300 06DF 0315 0062; # (a◌̕◌̀◌֮◌۟b; à◌֮◌۟◌̕b; a◌֮◌̀◌۟◌̕b; à◌֮◌۟◌̕b; a◌֮◌̀◌۟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH ROUNDED ZERO, LATIN SMALL LETTER B +0061 06DF 0315 0300 05AE 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062;0061 05AE 06DF 0300 0315 0062; # (a◌۟◌̕◌̀◌֮b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; a◌֮◌۟◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH ROUNDED ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E0 0062;00E0 05AE 06E0 0315 0062;0061 05AE 0300 06E0 0315 0062;00E0 05AE 06E0 0315 0062;0061 05AE 0300 06E0 0315 0062; # (a◌̕◌̀◌֮◌۠b; à◌֮◌۠◌̕b; a◌֮◌̀◌۠◌̕b; à◌֮◌۠◌̕b; a◌֮◌̀◌۠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO, LATIN SMALL LETTER B +0061 06E0 0315 0300 05AE 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062;0061 05AE 06E0 0300 0315 0062; # (a◌۠◌̕◌̀◌֮b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; a◌֮◌۠◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E1 0062;00E0 05AE 06E1 0315 0062;0061 05AE 0300 06E1 0315 0062;00E0 05AE 06E1 0315 0062;0061 05AE 0300 06E1 0315 0062; # (a◌̕◌̀◌֮◌ۡb; à◌֮◌ۡ◌̕b; a◌֮◌̀◌ۡ◌̕b; à◌֮◌ۡ◌̕b; a◌֮◌̀◌ۡ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH DOTLESS HEAD OF KHAH, LATIN SMALL LETTER B +0061 06E1 0315 0300 05AE 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062; # (a◌ۡ◌̕◌̀◌֮b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH DOTLESS HEAD OF KHAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E2 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062; # (a◌̕◌̀◌֮◌ۢb; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MEEM ISOLATED FORM, LATIN SMALL LETTER B +0061 06E2 0315 0300 05AE 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062; # (a◌ۢ◌̕◌̀◌֮b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MEEM ISOLATED FORM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06E3 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062; # (a◌֚◌̖◌᷺◌ۣb; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW SEEN, LATIN SMALL LETTER B +0061 06E3 059A 0316 1DFA 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062; # (a◌ۣ◌֚◌̖◌᷺b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW SEEN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E4 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062; # (a◌̕◌̀◌֮◌ۤb; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MADDA, LATIN SMALL LETTER B +0061 06E4 0315 0300 05AE 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062; # (a◌ۤ◌̕◌̀◌֮b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E7 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062; # (a◌̕◌̀◌֮◌ۧb; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH YEH, LATIN SMALL LETTER B +0061 06E7 0315 0300 05AE 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062; # (a◌ۧ◌̕◌̀◌֮b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06E8 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062; # (a◌̕◌̀◌֮◌ۨb; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH NOON, LATIN SMALL LETTER B +0061 06E8 0315 0300 05AE 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062; # (a◌ۨ◌̕◌̀◌֮b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH NOON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06EA 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062; # (a◌֚◌̖◌᷺◌۪b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC EMPTY CENTRE LOW STOP, LATIN SMALL LETTER B +0061 06EA 059A 0316 1DFA 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062; # (a◌۪◌֚◌̖◌᷺b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE LOW STOP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 06EB 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062; # (a◌̕◌̀◌֮◌۫b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC EMPTY CENTRE HIGH STOP, LATIN SMALL LETTER B +0061 06EB 0315 0300 05AE 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062; # (a◌۫◌̕◌̀◌֮b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE HIGH STOP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 06EC 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062; # (a◌̕◌̀◌֮◌۬b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, LATIN SMALL LETTER B +0061 06EC 0315 0300 05AE 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062; # (a◌۬◌̕◌̀◌֮b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06ED 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062; # (a◌֚◌̖◌᷺◌ۭb; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW MEEM, LATIN SMALL LETTER B +0061 06ED 059A 0316 1DFA 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062; # (a◌ۭ◌֚◌̖◌᷺b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW MEEM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0C55 0711 0670 0711 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ౕ◌ܑ◌ٰ◌ܑb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, LATIN SMALL LETTER B +0061 0711 0C55 0711 0670 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ܑ◌ౕ◌ܑ◌ٰb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B +0061 0315 0300 05AE 0730 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062; # (a◌̕◌̀◌֮◌ܰb; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA ABOVE, LATIN SMALL LETTER B +0061 0730 0315 0300 05AE 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062; # (a◌ܰ◌̕◌̀◌֮b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0731 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062; # (a◌֚◌̖◌᷺◌ܱb; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC PTHAHA BELOW, LATIN SMALL LETTER B +0061 0731 059A 0316 1DFA 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062; # (a◌ܱ◌֚◌̖◌᷺b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0732 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062; # (a◌̕◌̀◌֮◌ܲb; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA DOTTED, LATIN SMALL LETTER B +0061 0732 0315 0300 05AE 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062; # (a◌ܲ◌̕◌̀◌֮b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0733 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062; # (a◌̕◌̀◌֮◌ܳb; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA ABOVE, LATIN SMALL LETTER B +0061 0733 0315 0300 05AE 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062; # (a◌ܳ◌̕◌̀◌֮b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0734 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062; # (a◌֚◌̖◌᷺◌ܴb; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC ZQAPHA BELOW, LATIN SMALL LETTER B +0061 0734 059A 0316 1DFA 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062; # (a◌ܴ◌֚◌̖◌᷺b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0735 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062; # (a◌̕◌̀◌֮◌ܵb; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA DOTTED, LATIN SMALL LETTER B +0061 0735 0315 0300 05AE 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062; # (a◌ܵ◌̕◌̀◌֮b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0736 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062; # (a◌̕◌̀◌֮◌ܶb; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RBASA ABOVE, LATIN SMALL LETTER B +0061 0736 0315 0300 05AE 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062; # (a◌ܶ◌̕◌̀◌֮b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0737 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062; # (a◌֚◌̖◌᷺◌ܷb; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC RBASA BELOW, LATIN SMALL LETTER B +0061 0737 059A 0316 1DFA 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062; # (a◌ܷ◌֚◌̖◌᷺b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0738 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062; # (a◌֚◌̖◌᷺◌ܸb; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC DOTTED ZLAMA HORIZONTAL, LATIN SMALL LETTER B +0061 0738 059A 0316 1DFA 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062; # (a◌ܸ◌֚◌̖◌᷺b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA HORIZONTAL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0739 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062; # (a◌֚◌̖◌᷺◌ܹb; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC DOTTED ZLAMA ANGULAR, LATIN SMALL LETTER B +0061 0739 059A 0316 1DFA 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062; # (a◌ܹ◌֚◌̖◌᷺b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA ANGULAR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 073A 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062; # (a◌̕◌̀◌֮◌ܺb; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC HBASA ABOVE, LATIN SMALL LETTER B +0061 073A 0315 0300 05AE 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062; # (a◌ܺ◌̕◌̀◌֮b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC HBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073B 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062; # (a◌֚◌̖◌᷺◌ܻb; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC HBASA BELOW, LATIN SMALL LETTER B +0061 073B 059A 0316 1DFA 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062; # (a◌ܻ◌֚◌̖◌᷺b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073C 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062; # (a◌֚◌̖◌᷺◌ܼb; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC HBASA-ESASA DOTTED, LATIN SMALL LETTER B +0061 073C 059A 0316 1DFA 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062; # (a◌ܼ◌֚◌̖◌᷺b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA-ESASA DOTTED, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 073D 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062; # (a◌̕◌̀◌֮◌ܽb; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ESASA ABOVE, LATIN SMALL LETTER B +0061 073D 0315 0300 05AE 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062; # (a◌ܽ◌̕◌̀◌֮b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ESASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073E 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062; # (a◌֚◌̖◌᷺◌ܾb; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC ESASA BELOW, LATIN SMALL LETTER B +0061 073E 059A 0316 1DFA 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062; # (a◌ܾ◌֚◌̖◌᷺b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ESASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 073F 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062; # (a◌̕◌̀◌֮◌ܿb; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RWAHA, LATIN SMALL LETTER B +0061 073F 0315 0300 05AE 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062; # (a◌ܿ◌̕◌̀◌֮b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RWAHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0740 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062; # (a◌̕◌̀◌֮◌݀b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC FEMININE DOT, LATIN SMALL LETTER B +0061 0740 0315 0300 05AE 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062; # (a◌݀◌̕◌̀◌֮b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC FEMININE DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0741 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062; # (a◌̕◌̀◌֮◌݁b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC QUSHSHAYA, LATIN SMALL LETTER B +0061 0741 0315 0300 05AE 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062; # (a◌݁◌̕◌̀◌֮b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC QUSHSHAYA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0742 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062; # (a◌֚◌̖◌᷺◌݂b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC RUKKAKHA, LATIN SMALL LETTER B +0061 0742 059A 0316 1DFA 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062; # (a◌݂◌֚◌̖◌᷺b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RUKKAKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0743 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062; # (a◌̕◌̀◌֮◌݃b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC TWO VERTICAL DOTS ABOVE, LATIN SMALL LETTER B +0061 0743 0315 0300 05AE 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062; # (a◌݃◌̕◌̀◌֮b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0744 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062; # (a◌֚◌̖◌᷺◌݄b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC TWO VERTICAL DOTS BELOW, LATIN SMALL LETTER B +0061 0744 059A 0316 1DFA 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062; # (a◌݄◌֚◌̖◌᷺b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0745 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062; # (a◌̕◌̀◌֮◌݅b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC THREE DOTS ABOVE, LATIN SMALL LETTER B +0061 0745 0315 0300 05AE 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062; # (a◌݅◌̕◌̀◌֮b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0746 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062; # (a◌֚◌̖◌᷺◌݆b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC THREE DOTS BELOW, LATIN SMALL LETTER B +0061 0746 059A 0316 1DFA 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062; # (a◌݆◌֚◌̖◌᷺b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0747 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062; # (a◌̕◌̀◌֮◌݇b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC OBLIQUE LINE ABOVE, LATIN SMALL LETTER B +0061 0747 0315 0300 05AE 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062; # (a◌݇◌̕◌̀◌֮b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0748 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062; # (a◌֚◌̖◌᷺◌݈b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC OBLIQUE LINE BELOW, LATIN SMALL LETTER B +0061 0748 059A 0316 1DFA 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062; # (a◌݈◌֚◌̖◌᷺b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0749 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062; # (a◌̕◌̀◌֮◌݉b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC MUSIC, LATIN SMALL LETTER B +0061 0749 0315 0300 05AE 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062; # (a◌݉◌̕◌̀◌֮b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC MUSIC, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 074A 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062; # (a◌̕◌̀◌֮◌݊b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC BARREKH, LATIN SMALL LETTER B +0061 074A 0315 0300 05AE 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062;0061 05AE 074A 0300 0315 0062; # (a◌݊◌̕◌̀◌֮b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; a◌֮◌݊◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC BARREKH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07EB 0062;00E0 05AE 07EB 0315 0062;0061 05AE 0300 07EB 0315 0062;00E0 05AE 07EB 0315 0062;0061 05AE 0300 07EB 0315 0062; # (a◌̕◌̀◌֮◌߫b; à◌֮◌߫◌̕b; a◌֮◌̀◌߫◌̕b; à◌֮◌߫◌̕b; a◌֮◌̀◌߫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING SHORT HIGH TONE, LATIN SMALL LETTER B +0061 07EB 0315 0300 05AE 0062;0061 05AE 07EB 0300 0315 0062;0061 05AE 07EB 0300 0315 0062;0061 05AE 07EB 0300 0315 0062;0061 05AE 07EB 0300 0315 0062; # (a◌߫◌̕◌̀◌֮b; a◌֮◌߫◌̀◌̕b; a◌֮◌߫◌̀◌̕b; a◌֮◌߫◌̀◌̕b; a◌֮◌߫◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING SHORT HIGH TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07EC 0062;00E0 05AE 07EC 0315 0062;0061 05AE 0300 07EC 0315 0062;00E0 05AE 07EC 0315 0062;0061 05AE 0300 07EC 0315 0062; # (a◌̕◌̀◌֮◌߬b; à◌֮◌߬◌̕b; a◌֮◌̀◌߬◌̕b; à◌֮◌߬◌̕b; a◌֮◌̀◌߬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING SHORT LOW TONE, LATIN SMALL LETTER B +0061 07EC 0315 0300 05AE 0062;0061 05AE 07EC 0300 0315 0062;0061 05AE 07EC 0300 0315 0062;0061 05AE 07EC 0300 0315 0062;0061 05AE 07EC 0300 0315 0062; # (a◌߬◌̕◌̀◌֮b; a◌֮◌߬◌̀◌̕b; a◌֮◌߬◌̀◌̕b; a◌֮◌߬◌̀◌̕b; a◌֮◌߬◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING SHORT LOW TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07ED 0062;00E0 05AE 07ED 0315 0062;0061 05AE 0300 07ED 0315 0062;00E0 05AE 07ED 0315 0062;0061 05AE 0300 07ED 0315 0062; # (a◌̕◌̀◌֮◌߭b; à◌֮◌߭◌̕b; a◌֮◌̀◌߭◌̕b; à◌֮◌߭◌̕b; a◌֮◌̀◌߭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING SHORT RISING TONE, LATIN SMALL LETTER B +0061 07ED 0315 0300 05AE 0062;0061 05AE 07ED 0300 0315 0062;0061 05AE 07ED 0300 0315 0062;0061 05AE 07ED 0300 0315 0062;0061 05AE 07ED 0300 0315 0062; # (a◌߭◌̕◌̀◌֮b; a◌֮◌߭◌̀◌̕b; a◌֮◌߭◌̀◌̕b; a◌֮◌߭◌̀◌̕b; a◌֮◌߭◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING SHORT RISING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07EE 0062;00E0 05AE 07EE 0315 0062;0061 05AE 0300 07EE 0315 0062;00E0 05AE 07EE 0315 0062;0061 05AE 0300 07EE 0315 0062; # (a◌̕◌̀◌֮◌߮b; à◌֮◌߮◌̕b; a◌֮◌̀◌߮◌̕b; à◌֮◌߮◌̕b; a◌֮◌̀◌߮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING LONG DESCENDING TONE, LATIN SMALL LETTER B +0061 07EE 0315 0300 05AE 0062;0061 05AE 07EE 0300 0315 0062;0061 05AE 07EE 0300 0315 0062;0061 05AE 07EE 0300 0315 0062;0061 05AE 07EE 0300 0315 0062; # (a◌߮◌̕◌̀◌֮b; a◌֮◌߮◌̀◌̕b; a◌֮◌߮◌̀◌̕b; a◌֮◌߮◌̀◌̕b; a◌֮◌߮◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG DESCENDING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07EF 0062;00E0 05AE 07EF 0315 0062;0061 05AE 0300 07EF 0315 0062;00E0 05AE 07EF 0315 0062;0061 05AE 0300 07EF 0315 0062; # (a◌̕◌̀◌֮◌߯b; à◌֮◌߯◌̕b; a◌֮◌̀◌߯◌̕b; à◌֮◌߯◌̕b; a◌֮◌̀◌߯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING LONG HIGH TONE, LATIN SMALL LETTER B +0061 07EF 0315 0300 05AE 0062;0061 05AE 07EF 0300 0315 0062;0061 05AE 07EF 0300 0315 0062;0061 05AE 07EF 0300 0315 0062;0061 05AE 07EF 0300 0315 0062; # (a◌߯◌̕◌̀◌֮b; a◌֮◌߯◌̀◌̕b; a◌֮◌߯◌̀◌̕b; a◌֮◌߯◌̀◌̕b; a◌֮◌߯◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG HIGH TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07F0 0062;00E0 05AE 07F0 0315 0062;0061 05AE 0300 07F0 0315 0062;00E0 05AE 07F0 0315 0062;0061 05AE 0300 07F0 0315 0062; # (a◌̕◌̀◌֮◌߰b; à◌֮◌߰◌̕b; a◌֮◌̀◌߰◌̕b; à◌֮◌߰◌̕b; a◌֮◌̀◌߰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING LONG LOW TONE, LATIN SMALL LETTER B +0061 07F0 0315 0300 05AE 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062; # (a◌߰◌̕◌̀◌֮b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG LOW TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 07F1 0062;00E0 05AE 07F1 0315 0062;0061 05AE 0300 07F1 0315 0062;00E0 05AE 07F1 0315 0062;0061 05AE 0300 07F1 0315 0062; # (a◌̕◌̀◌֮◌߱b; à◌֮◌߱◌̕b; a◌֮◌̀◌߱◌̕b; à◌֮◌߱◌̕b; a◌֮◌̀◌߱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING LONG RISING TONE, LATIN SMALL LETTER B +0061 07F1 0315 0300 05AE 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062; # (a◌߱◌̕◌̀◌֮b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG RISING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 07F2 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062; # (a◌֚◌̖◌᷺◌߲b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, NKO COMBINING NASALIZATION MARK, LATIN SMALL LETTER B +0061 07F2 059A 0316 1DFA 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062; # (a◌߲◌֚◌̖◌᷺b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; ) LATIN SMALL LETTER A, NKO COMBINING NASALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 07F3 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062; # (a◌̕◌̀◌֮◌߳b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING DOUBLE DOT ABOVE, LATIN SMALL LETTER B +0061 07F3 0315 0300 05AE 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062; # (a◌߳◌̕◌̀◌֮b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING DOUBLE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 07FD 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062; # (a◌֚◌̖◌᷺◌߽b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, NKO DANTAYALAN, LATIN SMALL LETTER B +0061 07FD 059A 0316 1DFA 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062; # (a◌߽◌֚◌̖◌᷺b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; ) LATIN SMALL LETTER A, NKO DANTAYALAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0816 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062; # (a◌̕◌̀◌֮◌ࠖb; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN, LATIN SMALL LETTER B +0061 0816 0315 0300 05AE 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062; # (a◌ࠖ◌̕◌̀◌֮b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK IN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0817 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062; # (a◌̕◌̀◌֮◌ࠗb; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN-ALAF, LATIN SMALL LETTER B +0061 0817 0315 0300 05AE 0062;0061 05AE 0817 0300 0315 0062;0061 05AE 0817 0300 0315 0062;0061 05AE 0817 0300 0315 0062;0061 05AE 0817 0300 0315 0062; # (a◌ࠗ◌̕◌̀◌֮b; a◌֮◌ࠗ◌̀◌̕b; a◌֮◌ࠗ◌̀◌̕b; a◌֮◌ࠗ◌̀◌̕b; a◌֮◌ࠗ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK IN-ALAF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0818 0062;00E0 05AE 0818 0315 0062;0061 05AE 0300 0818 0315 0062;00E0 05AE 0818 0315 0062;0061 05AE 0300 0818 0315 0062; # (a◌̕◌̀◌֮◌࠘b; à◌֮◌࠘◌̕b; a◌֮◌̀◌࠘◌̕b; à◌֮◌࠘◌̕b; a◌֮◌̀◌࠘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK OCCLUSION, LATIN SMALL LETTER B +0061 0818 0315 0300 05AE 0062;0061 05AE 0818 0300 0315 0062;0061 05AE 0818 0300 0315 0062;0061 05AE 0818 0300 0315 0062;0061 05AE 0818 0300 0315 0062; # (a◌࠘◌̕◌̀◌֮b; a◌֮◌࠘◌̀◌̕b; a◌֮◌࠘◌̀◌̕b; a◌֮◌࠘◌̀◌̕b; a◌֮◌࠘◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK OCCLUSION, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0819 0062;00E0 05AE 0819 0315 0062;0061 05AE 0300 0819 0315 0062;00E0 05AE 0819 0315 0062;0061 05AE 0300 0819 0315 0062; # (a◌̕◌̀◌֮◌࠙b; à◌֮◌࠙◌̕b; a◌֮◌̀◌࠙◌̕b; à◌֮◌࠙◌̕b; a◌֮◌̀◌࠙◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK DAGESH, LATIN SMALL LETTER B +0061 0819 0315 0300 05AE 0062;0061 05AE 0819 0300 0315 0062;0061 05AE 0819 0300 0315 0062;0061 05AE 0819 0300 0315 0062;0061 05AE 0819 0300 0315 0062; # (a◌࠙◌̕◌̀◌֮b; a◌֮◌࠙◌̀◌̕b; a◌֮◌࠙◌̀◌̕b; a◌֮◌࠙◌̀◌̕b; a◌֮◌࠙◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK DAGESH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 081B 0062;00E0 05AE 081B 0315 0062;0061 05AE 0300 081B 0315 0062;00E0 05AE 081B 0315 0062;0061 05AE 0300 081B 0315 0062; # (a◌̕◌̀◌֮◌ࠛb; à◌֮◌ࠛ◌̕b; a◌֮◌̀◌ࠛ◌̕b; à◌֮◌ࠛ◌̕b; a◌֮◌̀◌ࠛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK EPENTHETIC YUT, LATIN SMALL LETTER B +0061 081B 0315 0300 05AE 0062;0061 05AE 081B 0300 0315 0062;0061 05AE 081B 0300 0315 0062;0061 05AE 081B 0300 0315 0062;0061 05AE 081B 0300 0315 0062; # (a◌ࠛ◌̕◌̀◌֮b; a◌֮◌ࠛ◌̀◌̕b; a◌֮◌ࠛ◌̀◌̕b; a◌֮◌ࠛ◌̀◌̕b; a◌֮◌ࠛ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK EPENTHETIC YUT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 081C 0062;00E0 05AE 081C 0315 0062;0061 05AE 0300 081C 0315 0062;00E0 05AE 081C 0315 0062;0061 05AE 0300 081C 0315 0062; # (a◌̕◌̀◌֮◌ࠜb; à◌֮◌ࠜ◌̕b; a◌֮◌̀◌ࠜ◌̕b; à◌֮◌ࠜ◌̕b; a◌֮◌̀◌ࠜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN LONG E, LATIN SMALL LETTER B +0061 081C 0315 0300 05AE 0062;0061 05AE 081C 0300 0315 0062;0061 05AE 081C 0300 0315 0062;0061 05AE 081C 0300 0315 0062;0061 05AE 081C 0300 0315 0062; # (a◌ࠜ◌̕◌̀◌֮b; a◌֮◌ࠜ◌̀◌̕b; a◌֮◌ࠜ◌̀◌̕b; a◌֮◌ࠜ◌̀◌̕b; a◌֮◌ࠜ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN LONG E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 081D 0062;00E0 05AE 081D 0315 0062;0061 05AE 0300 081D 0315 0062;00E0 05AE 081D 0315 0062;0061 05AE 0300 081D 0315 0062; # (a◌̕◌̀◌֮◌ࠝb; à◌֮◌ࠝ◌̕b; a◌֮◌̀◌ࠝ◌̕b; à◌֮◌ࠝ◌̕b; a◌֮◌̀◌ࠝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN E, LATIN SMALL LETTER B +0061 081D 0315 0300 05AE 0062;0061 05AE 081D 0300 0315 0062;0061 05AE 081D 0300 0315 0062;0061 05AE 081D 0300 0315 0062;0061 05AE 081D 0300 0315 0062; # (a◌ࠝ◌̕◌̀◌֮b; a◌֮◌ࠝ◌̀◌̕b; a◌֮◌ࠝ◌̀◌̕b; a◌֮◌ࠝ◌̀◌̕b; a◌֮◌ࠝ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 081E 0062;00E0 05AE 081E 0315 0062;0061 05AE 0300 081E 0315 0062;00E0 05AE 081E 0315 0062;0061 05AE 0300 081E 0315 0062; # (a◌̕◌̀◌֮◌ࠞb; à◌֮◌ࠞ◌̕b; a◌֮◌̀◌ࠞ◌̕b; à◌֮◌ࠞ◌̕b; a◌֮◌̀◌ࠞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN OVERLONG AA, LATIN SMALL LETTER B +0061 081E 0315 0300 05AE 0062;0061 05AE 081E 0300 0315 0062;0061 05AE 081E 0300 0315 0062;0061 05AE 081E 0300 0315 0062;0061 05AE 081E 0300 0315 0062; # (a◌ࠞ◌̕◌̀◌֮b; a◌֮◌ࠞ◌̀◌̕b; a◌֮◌ࠞ◌̀◌̕b; a◌֮◌ࠞ◌̀◌̕b; a◌֮◌ࠞ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN OVERLONG AA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 081F 0062;00E0 05AE 081F 0315 0062;0061 05AE 0300 081F 0315 0062;00E0 05AE 081F 0315 0062;0061 05AE 0300 081F 0315 0062; # (a◌̕◌̀◌֮◌ࠟb; à◌֮◌ࠟ◌̕b; a◌֮◌̀◌ࠟ◌̕b; à◌֮◌ࠟ◌̕b; a◌֮◌̀◌ࠟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN LONG AA, LATIN SMALL LETTER B +0061 081F 0315 0300 05AE 0062;0061 05AE 081F 0300 0315 0062;0061 05AE 081F 0300 0315 0062;0061 05AE 081F 0300 0315 0062;0061 05AE 081F 0300 0315 0062; # (a◌ࠟ◌̕◌̀◌֮b; a◌֮◌ࠟ◌̀◌̕b; a◌֮◌ࠟ◌̀◌̕b; a◌֮◌ࠟ◌̀◌̕b; a◌֮◌ࠟ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN LONG AA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0820 0062;00E0 05AE 0820 0315 0062;0061 05AE 0300 0820 0315 0062;00E0 05AE 0820 0315 0062;0061 05AE 0300 0820 0315 0062; # (a◌̕◌̀◌֮◌ࠠb; à◌֮◌ࠠ◌̕b; a◌֮◌̀◌ࠠ◌̕b; à◌֮◌ࠠ◌̕b; a◌֮◌̀◌ࠠ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0820 0315 0300 05AE 0062;0061 05AE 0820 0300 0315 0062;0061 05AE 0820 0300 0315 0062;0061 05AE 0820 0300 0315 0062;0061 05AE 0820 0300 0315 0062; # (a◌ࠠ◌̕◌̀◌֮b; a◌֮◌ࠠ◌̀◌̕b; a◌֮◌ࠠ◌̀◌̕b; a◌֮◌ࠠ◌̀◌̕b; a◌֮◌ࠠ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN AA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0821 0062;00E0 05AE 0821 0315 0062;0061 05AE 0300 0821 0315 0062;00E0 05AE 0821 0315 0062;0061 05AE 0300 0821 0315 0062; # (a◌̕◌̀◌֮◌ࠡb; à◌֮◌ࠡ◌̕b; a◌֮◌̀◌ࠡ◌̕b; à◌֮◌ࠡ◌̕b; a◌֮◌̀◌ࠡ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN OVERLONG A, LATIN SMALL LETTER B +0061 0821 0315 0300 05AE 0062;0061 05AE 0821 0300 0315 0062;0061 05AE 0821 0300 0315 0062;0061 05AE 0821 0300 0315 0062;0061 05AE 0821 0300 0315 0062; # (a◌ࠡ◌̕◌̀◌֮b; a◌֮◌ࠡ◌̀◌̕b; a◌֮◌ࠡ◌̀◌̕b; a◌֮◌ࠡ◌̀◌̕b; a◌֮◌ࠡ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN OVERLONG A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0822 0062;00E0 05AE 0822 0315 0062;0061 05AE 0300 0822 0315 0062;00E0 05AE 0822 0315 0062;0061 05AE 0300 0822 0315 0062; # (a◌̕◌̀◌֮◌ࠢb; à◌֮◌ࠢ◌̕b; a◌֮◌̀◌ࠢ◌̕b; à◌֮◌ࠢ◌̕b; a◌֮◌̀◌ࠢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN LONG A, LATIN SMALL LETTER B +0061 0822 0315 0300 05AE 0062;0061 05AE 0822 0300 0315 0062;0061 05AE 0822 0300 0315 0062;0061 05AE 0822 0300 0315 0062;0061 05AE 0822 0300 0315 0062; # (a◌ࠢ◌̕◌̀◌֮b; a◌֮◌ࠢ◌̀◌̕b; a◌֮◌ࠢ◌̀◌̕b; a◌֮◌ࠢ◌̀◌̕b; a◌֮◌ࠢ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN LONG A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0823 0062;00E0 05AE 0823 0315 0062;0061 05AE 0300 0823 0315 0062;00E0 05AE 0823 0315 0062;0061 05AE 0300 0823 0315 0062; # (a◌̕◌̀◌֮◌ࠣb; à◌֮◌ࠣ◌̕b; a◌֮◌̀◌ࠣ◌̕b; à◌֮◌ࠣ◌̕b; a◌֮◌̀◌ࠣ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN A, LATIN SMALL LETTER B +0061 0823 0315 0300 05AE 0062;0061 05AE 0823 0300 0315 0062;0061 05AE 0823 0300 0315 0062;0061 05AE 0823 0300 0315 0062;0061 05AE 0823 0300 0315 0062; # (a◌ࠣ◌̕◌̀◌֮b; a◌֮◌ࠣ◌̀◌̕b; a◌֮◌ࠣ◌̀◌̕b; a◌֮◌ࠣ◌̀◌̕b; a◌֮◌ࠣ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0825 0062;00E0 05AE 0825 0315 0062;0061 05AE 0300 0825 0315 0062;00E0 05AE 0825 0315 0062;0061 05AE 0300 0825 0315 0062; # (a◌̕◌̀◌֮◌ࠥb; à◌֮◌ࠥ◌̕b; a◌֮◌̀◌ࠥ◌̕b; à◌֮◌ࠥ◌̕b; a◌֮◌̀◌ࠥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN SHORT A, LATIN SMALL LETTER B +0061 0825 0315 0300 05AE 0062;0061 05AE 0825 0300 0315 0062;0061 05AE 0825 0300 0315 0062;0061 05AE 0825 0300 0315 0062;0061 05AE 0825 0300 0315 0062; # (a◌ࠥ◌̕◌̀◌֮b; a◌֮◌ࠥ◌̀◌̕b; a◌֮◌ࠥ◌̀◌̕b; a◌֮◌ࠥ◌̀◌̕b; a◌֮◌ࠥ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN SHORT A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0826 0062;00E0 05AE 0826 0315 0062;0061 05AE 0300 0826 0315 0062;00E0 05AE 0826 0315 0062;0061 05AE 0300 0826 0315 0062; # (a◌̕◌̀◌֮◌ࠦb; à◌֮◌ࠦ◌̕b; a◌֮◌̀◌ࠦ◌̕b; à◌֮◌ࠦ◌̕b; a◌֮◌̀◌ࠦ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN LONG U, LATIN SMALL LETTER B +0061 0826 0315 0300 05AE 0062;0061 05AE 0826 0300 0315 0062;0061 05AE 0826 0300 0315 0062;0061 05AE 0826 0300 0315 0062;0061 05AE 0826 0300 0315 0062; # (a◌ࠦ◌̕◌̀◌֮b; a◌֮◌ࠦ◌̀◌̕b; a◌֮◌ࠦ◌̀◌̕b; a◌֮◌ࠦ◌̀◌̕b; a◌֮◌ࠦ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN LONG U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0827 0062;00E0 05AE 0827 0315 0062;0061 05AE 0300 0827 0315 0062;00E0 05AE 0827 0315 0062;0061 05AE 0300 0827 0315 0062; # (a◌̕◌̀◌֮◌ࠧb; à◌֮◌ࠧ◌̕b; a◌֮◌̀◌ࠧ◌̕b; à◌֮◌ࠧ◌̕b; a◌֮◌̀◌ࠧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 0827 0315 0300 05AE 0062;0061 05AE 0827 0300 0315 0062;0061 05AE 0827 0300 0315 0062;0061 05AE 0827 0300 0315 0062;0061 05AE 0827 0300 0315 0062; # (a◌ࠧ◌̕◌̀◌֮b; a◌֮◌ࠧ◌̀◌̕b; a◌֮◌ࠧ◌̀◌̕b; a◌֮◌ࠧ◌̀◌̕b; a◌֮◌ࠧ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0829 0062;00E0 05AE 0829 0315 0062;0061 05AE 0300 0829 0315 0062;00E0 05AE 0829 0315 0062;0061 05AE 0300 0829 0315 0062; # (a◌̕◌̀◌֮◌ࠩb; à◌֮◌ࠩ◌̕b; a◌֮◌̀◌ࠩ◌̕b; à◌֮◌ࠩ◌̕b; a◌֮◌̀◌ࠩ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN LONG I, LATIN SMALL LETTER B +0061 0829 0315 0300 05AE 0062;0061 05AE 0829 0300 0315 0062;0061 05AE 0829 0300 0315 0062;0061 05AE 0829 0300 0315 0062;0061 05AE 0829 0300 0315 0062; # (a◌ࠩ◌̕◌̀◌֮b; a◌֮◌ࠩ◌̀◌̕b; a◌֮◌ࠩ◌̀◌̕b; a◌֮◌ࠩ◌̀◌̕b; a◌֮◌ࠩ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN LONG I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 082A 0062;00E0 05AE 082A 0315 0062;0061 05AE 0300 082A 0315 0062;00E0 05AE 082A 0315 0062;0061 05AE 0300 082A 0315 0062; # (a◌̕◌̀◌֮◌ࠪb; à◌֮◌ࠪ◌̕b; a◌֮◌̀◌ࠪ◌̕b; à◌֮◌ࠪ◌̕b; a◌֮◌̀◌ࠪ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN I, LATIN SMALL LETTER B +0061 082A 0315 0300 05AE 0062;0061 05AE 082A 0300 0315 0062;0061 05AE 082A 0300 0315 0062;0061 05AE 082A 0300 0315 0062;0061 05AE 082A 0300 0315 0062; # (a◌ࠪ◌̕◌̀◌֮b; a◌֮◌ࠪ◌̀◌̕b; a◌֮◌ࠪ◌̀◌̕b; a◌֮◌ࠪ◌̀◌̕b; a◌֮◌ࠪ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 082B 0062;00E0 05AE 082B 0315 0062;0061 05AE 0300 082B 0315 0062;00E0 05AE 082B 0315 0062;0061 05AE 0300 082B 0315 0062; # (a◌̕◌̀◌֮◌ࠫb; à◌֮◌ࠫ◌̕b; a◌֮◌̀◌ࠫ◌̕b; à◌֮◌ࠫ◌̕b; a◌֮◌̀◌ࠫ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN O, LATIN SMALL LETTER B +0061 082B 0315 0300 05AE 0062;0061 05AE 082B 0300 0315 0062;0061 05AE 082B 0300 0315 0062;0061 05AE 082B 0300 0315 0062;0061 05AE 082B 0300 0315 0062; # (a◌ࠫ◌̕◌̀◌֮b; a◌֮◌ࠫ◌̀◌̕b; a◌֮◌ࠫ◌̀◌̕b; a◌֮◌ࠫ◌̀◌̕b; a◌֮◌ࠫ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN O, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 082C 0062;00E0 05AE 082C 0315 0062;0061 05AE 0300 082C 0315 0062;00E0 05AE 082C 0315 0062;0061 05AE 0300 082C 0315 0062; # (a◌̕◌̀◌֮◌ࠬb; à◌֮◌ࠬ◌̕b; a◌֮◌̀◌ࠬ◌̕b; à◌֮◌ࠬ◌̕b; a◌֮◌̀◌ࠬ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN VOWEL SIGN SUKUN, LATIN SMALL LETTER B +0061 082C 0315 0300 05AE 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062; # (a◌ࠬ◌̕◌̀◌֮b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN SUKUN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 082D 0062;00E0 05AE 082D 0315 0062;0061 05AE 0300 082D 0315 0062;00E0 05AE 082D 0315 0062;0061 05AE 0300 082D 0315 0062; # (a◌̕◌̀◌֮◌࠭b; à◌֮◌࠭◌̕b; a◌֮◌̀◌࠭◌̕b; à◌֮◌࠭◌̕b; a◌֮◌̀◌࠭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK NEQUDAA, LATIN SMALL LETTER B +0061 082D 0315 0300 05AE 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062; # (a◌࠭◌̕◌̀◌֮b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK NEQUDAA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0859 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062; # (a◌֚◌̖◌᷺◌࡙b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC AFFRICATION MARK, LATIN SMALL LETTER B +0061 0859 059A 0316 1DFA 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062; # (a◌࡙◌֚◌̖◌᷺b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC AFFRICATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 085A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062; # (a◌֚◌̖◌᷺◌࡚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC VOCALIZATION MARK, LATIN SMALL LETTER B +0061 085A 059A 0316 1DFA 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌᷺b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 085B 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062; # (a◌֚◌̖◌᷺◌࡛b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B +0061 085B 059A 0316 1DFA 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌᷺b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0898 0062;00E0 05AE 0898 0315 0062;0061 05AE 0300 0898 0315 0062;00E0 05AE 0898 0315 0062;0061 05AE 0300 0898 0315 0062; # (a◌̕◌̀◌֮◌࢘b; à◌֮◌࢘◌̕b; a◌֮◌̀◌࢘◌̕b; à◌֮◌࢘◌̕b; a◌֮◌̀◌࢘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AL-JUZ, LATIN SMALL LETTER B +0061 0898 0315 0300 05AE 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062; # (a◌࢘◌̕◌̀◌֮b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AL-JUZ, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0899 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062; # (a◌֚◌̖◌᷺◌࢙b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD ISHMAAM, LATIN SMALL LETTER B +0061 0899 059A 0316 1DFA 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062; # (a◌࢙◌֚◌̖◌᷺b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD ISHMAAM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 089A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062; # (a◌֚◌̖◌᷺◌࢚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD IMAALA, LATIN SMALL LETTER B +0061 089A 059A 0316 1DFA 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062; # (a◌࢚◌֚◌̖◌᷺b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD IMAALA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 089B 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062; # (a◌֚◌̖◌᷺◌࢛b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD TASHEEL, LATIN SMALL LETTER B +0061 089B 059A 0316 1DFA 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062; # (a◌࢛◌֚◌̖◌᷺b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD TASHEEL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 089C 0062;00E0 05AE 089C 0315 0062;0061 05AE 0300 089C 0315 0062;00E0 05AE 089C 0315 0062;0061 05AE 0300 089C 0315 0062; # (a◌̕◌̀◌֮◌࢜b; à◌֮◌࢜◌̕b; a◌֮◌̀◌࢜◌̕b; à◌֮◌࢜◌̕b; a◌֮◌̀◌࢜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MADDA WAAJIB, LATIN SMALL LETTER B +0061 089C 0315 0300 05AE 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062; # (a◌࢜◌̕◌̀◌֮b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MADDA WAAJIB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089D 0062;00E0 05AE 089D 0315 0062;0061 05AE 0300 089D 0315 0062;00E0 05AE 089D 0315 0062;0061 05AE 0300 089D 0315 0062; # (a◌̕◌̀◌֮◌࢝b; à◌֮◌࢝◌̕b; a◌֮◌̀◌࢝◌̕b; à◌֮◌࢝◌̕b; a◌֮◌̀◌࢝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SUPERSCRIPT ALEF MOKHASSAS, LATIN SMALL LETTER B +0061 089D 0315 0300 05AE 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062; # (a◌࢝◌̕◌̀◌֮b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SUPERSCRIPT ALEF MOKHASSAS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089E 0062;00E0 05AE 089E 0315 0062;0061 05AE 0300 089E 0315 0062;00E0 05AE 089E 0315 0062;0061 05AE 0300 089E 0315 0062; # (a◌̕◌̀◌֮◌࢞b; à◌֮◌࢞◌̕b; a◌֮◌̀◌࢞◌̕b; à◌֮◌࢞◌̕b; a◌֮◌̀◌࢞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLED MADDA, LATIN SMALL LETTER B +0061 089E 0315 0300 05AE 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062; # (a◌࢞◌̕◌̀◌֮b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DOUBLED MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089F 0062;00E0 05AE 089F 0315 0062;0061 05AE 0300 089F 0315 0062;00E0 05AE 089F 0315 0062;0061 05AE 0300 089F 0315 0062; # (a◌̕◌̀◌֮◌࢟b; à◌֮◌࢟◌̕b; a◌֮◌̀◌࢟◌̕b; à◌֮◌࢟◌̕b; a◌֮◌̀◌࢟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC HALF MADDA OVER MADDA, LATIN SMALL LETTER B +0061 089F 0315 0300 05AE 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062; # (a◌࢟◌̕◌̀◌֮b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC HALF MADDA OVER MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CA 0062;00E0 05AE 08CA 0315 0062;0061 05AE 0300 08CA 0315 0062;00E0 05AE 08CA 0315 0062;0061 05AE 0300 08CA 0315 0062; # (a◌̕◌̀◌֮◌࣊b; à◌֮◌࣊◌̕b; a◌֮◌̀◌࣊◌̕b; à◌֮◌࣊◌̕b; a◌֮◌̀◌࣊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH FARSI YEH, LATIN SMALL LETTER B +0061 08CA 0315 0300 05AE 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062; # (a◌࣊◌̕◌̀◌֮b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH FARSI YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CB 0062;00E0 05AE 08CB 0315 0062;0061 05AE 0300 08CB 0315 0062;00E0 05AE 08CB 0315 0062;0061 05AE 0300 08CB 0315 0062; # (a◌̕◌̀◌֮◌࣋b; à◌֮◌࣋◌̕b; a◌֮◌̀◌࣋◌̕b; à◌֮◌࣋◌̕b; a◌֮◌̀◌࣋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW, LATIN SMALL LETTER B +0061 08CB 0315 0300 05AE 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062; # (a◌࣋◌̕◌̀◌֮b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CC 0062;00E0 05AE 08CC 0315 0062;0061 05AE 0300 08CC 0315 0062;00E0 05AE 08CC 0315 0062;0061 05AE 0300 08CC 0315 0062; # (a◌̕◌̀◌֮◌࣌b; à◌֮◌࣌◌̕b; a◌֮◌̀◌࣌◌̕b; à◌֮◌࣌◌̕b; a◌֮◌̀◌࣌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD SAH, LATIN SMALL LETTER B +0061 08CC 0315 0300 05AE 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062; # (a◌࣌◌̕◌̀◌֮b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD SAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CD 0062;00E0 05AE 08CD 0315 0062;0061 05AE 0300 08CD 0315 0062;00E0 05AE 08CD 0315 0062;0061 05AE 0300 08CD 0315 0062; # (a◌̕◌̀◌֮◌࣍b; à◌֮◌࣍◌̕b; a◌֮◌̀◌࣍◌̕b; à◌֮◌࣍◌̕b; a◌֮◌̀◌࣍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH ZAH, LATIN SMALL LETTER B +0061 08CD 0315 0300 05AE 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062; # (a◌࣍◌̕◌̀◌֮b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH ZAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CE 0062;00E0 05AE 08CE 0315 0062;0061 05AE 0300 08CE 0315 0062;00E0 05AE 08CE 0315 0062;0061 05AE 0300 08CE 0315 0062; # (a◌̕◌̀◌֮◌࣎b; à◌֮◌࣎◌̕b; a◌֮◌̀◌࣎◌̕b; à◌֮◌࣎◌̕b; a◌֮◌̀◌࣎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC LARGE ROUND DOT ABOVE, LATIN SMALL LETTER B +0061 08CE 0315 0300 05AE 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062; # (a◌࣎◌̕◌̀◌֮b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08CF 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062; # (a◌֚◌̖◌᷺◌࣏b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE ROUND DOT BELOW, LATIN SMALL LETTER B +0061 08CF 059A 0316 1DFA 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062; # (a◌࣏◌֚◌̖◌᷺b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D0 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062; # (a◌֚◌̖◌᷺◌࣐b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SUKUN BELOW, LATIN SMALL LETTER B +0061 08D0 059A 0316 1DFA 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062; # (a◌࣐◌֚◌̖◌᷺b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SUKUN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D1 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062; # (a◌֚◌̖◌᷺◌࣑b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE CIRCLE BELOW, LATIN SMALL LETTER B +0061 08D1 059A 0316 1DFA 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062; # (a◌࣑◌֚◌̖◌᷺b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE CIRCLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D2 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062; # (a◌֚◌̖◌᷺◌࣒b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW, LATIN SMALL LETTER B +0061 08D2 059A 0316 1DFA 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062; # (a◌࣒◌֚◌̖◌᷺b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D3 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062; # (a◌֚◌̖◌᷺◌࣓b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WAW, LATIN SMALL LETTER B +0061 08D3 059A 0316 1DFA 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062; # (a◌࣓◌֚◌̖◌᷺b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WAW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D4 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062; # (a◌̕◌̀◌֮◌ࣔb; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AR-RUB, LATIN SMALL LETTER B +0061 08D4 0315 0300 05AE 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062; # (a◌ࣔ◌̕◌̀◌֮b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AR-RUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D5 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062; # (a◌̕◌̀◌֮◌ࣕb; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SAD, LATIN SMALL LETTER B +0061 08D5 0315 0300 05AE 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062; # (a◌ࣕ◌̕◌̀◌֮b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SAD, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D6 0062;00E0 05AE 08D6 0315 0062;0061 05AE 0300 08D6 0315 0062;00E0 05AE 08D6 0315 0062;0061 05AE 0300 08D6 0315 0062; # (a◌̕◌̀◌֮◌ࣖb; à◌֮◌ࣖ◌̕b; a◌֮◌̀◌ࣖ◌̕b; à◌֮◌ࣖ◌̕b; a◌֮◌̀◌ࣖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH AIN, LATIN SMALL LETTER B +0061 08D6 0315 0300 05AE 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062; # (a◌ࣖ◌̕◌̀◌֮b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH AIN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D7 0062;00E0 05AE 08D7 0315 0062;0061 05AE 0300 08D7 0315 0062;00E0 05AE 08D7 0315 0062;0061 05AE 0300 08D7 0315 0062; # (a◌̕◌̀◌֮◌ࣗb; à◌֮◌ࣗ◌̕b; a◌֮◌̀◌ࣗ◌̕b; à◌֮◌ࣗ◌̕b; a◌֮◌̀◌ࣗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH QAF, LATIN SMALL LETTER B +0061 08D7 0315 0300 05AE 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062; # (a◌ࣗ◌̕◌̀◌֮b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH QAF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D8 0062;00E0 05AE 08D8 0315 0062;0061 05AE 0300 08D8 0315 0062;00E0 05AE 08D8 0315 0062;0061 05AE 0300 08D8 0315 0062; # (a◌̕◌̀◌֮◌ࣘb; à◌֮◌ࣘ◌̕b; a◌֮◌̀◌ࣘ◌̕b; à◌֮◌ࣘ◌̕b; a◌֮◌̀◌ࣘ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH NOON WITH KASRA, LATIN SMALL LETTER B +0061 08D8 0315 0300 05AE 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062; # (a◌ࣘ◌̕◌̀◌֮b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH NOON WITH KASRA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D9 0062;00E0 05AE 08D9 0315 0062;0061 05AE 0300 08D9 0315 0062;00E0 05AE 08D9 0315 0062;0061 05AE 0300 08D9 0315 0062; # (a◌̕◌̀◌֮◌ࣙb; à◌֮◌ࣙ◌̕b; a◌֮◌̀◌ࣙ◌̕b; à◌֮◌ࣙ◌̕b; a◌֮◌̀◌ࣙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL LOW NOON WITH KASRA, LATIN SMALL LETTER B +0061 08D9 0315 0300 05AE 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062; # (a◌ࣙ◌̕◌̀◌֮b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW NOON WITH KASRA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DA 0062;00E0 05AE 08DA 0315 0062;0061 05AE 0300 08DA 0315 0062;00E0 05AE 08DA 0315 0062;0061 05AE 0300 08DA 0315 0062; # (a◌̕◌̀◌֮◌ࣚb; à◌֮◌ࣚ◌̕b; a◌֮◌̀◌ࣚ◌̕b; à◌֮◌ࣚ◌̕b; a◌֮◌̀◌ࣚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD ATH-THALATHA, LATIN SMALL LETTER B +0061 08DA 0315 0300 05AE 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062; # (a◌ࣚ◌̕◌̀◌֮b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD ATH-THALATHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DB 0062;00E0 05AE 08DB 0315 0062;0061 05AE 0300 08DB 0315 0062;00E0 05AE 08DB 0315 0062;0061 05AE 0300 08DB 0315 0062; # (a◌̕◌̀◌֮◌ࣛb; à◌֮◌ࣛ◌̕b; a◌֮◌̀◌ࣛ◌̕b; à◌֮◌ࣛ◌̕b; a◌֮◌̀◌ࣛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AS-SAJDA, LATIN SMALL LETTER B +0061 08DB 0315 0300 05AE 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062; # (a◌ࣛ◌̕◌̀◌֮b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AS-SAJDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DC 0062;00E0 05AE 08DC 0315 0062;0061 05AE 0300 08DC 0315 0062;00E0 05AE 08DC 0315 0062;0061 05AE 0300 08DC 0315 0062; # (a◌̕◌̀◌֮◌ࣜb; à◌֮◌ࣜ◌̕b; a◌֮◌̀◌ࣜ◌̕b; à◌֮◌ࣜ◌̕b; a◌֮◌̀◌ࣜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AN-NISF, LATIN SMALL LETTER B +0061 08DC 0315 0300 05AE 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062; # (a◌ࣜ◌̕◌̀◌֮b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AN-NISF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DD 0062;00E0 05AE 08DD 0315 0062;0061 05AE 0300 08DD 0315 0062;00E0 05AE 08DD 0315 0062;0061 05AE 0300 08DD 0315 0062; # (a◌̕◌̀◌֮◌ࣝb; à◌֮◌ࣝ◌̕b; a◌֮◌̀◌ࣝ◌̕b; à◌֮◌ࣝ◌̕b; a◌֮◌̀◌ࣝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD SAKTA, LATIN SMALL LETTER B +0061 08DD 0315 0300 05AE 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062; # (a◌ࣝ◌̕◌̀◌֮b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD SAKTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DE 0062;00E0 05AE 08DE 0315 0062;0061 05AE 0300 08DE 0315 0062;00E0 05AE 08DE 0315 0062;0061 05AE 0300 08DE 0315 0062; # (a◌̕◌̀◌֮◌ࣞb; à◌֮◌ࣞ◌̕b; a◌֮◌̀◌ࣞ◌̕b; à◌֮◌ࣞ◌̕b; a◌֮◌̀◌ࣞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD QIF, LATIN SMALL LETTER B +0061 08DE 0315 0300 05AE 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062; # (a◌ࣞ◌̕◌̀◌֮b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD QIF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DF 0062;00E0 05AE 08DF 0315 0062;0061 05AE 0300 08DF 0315 0062;00E0 05AE 08DF 0315 0062;0061 05AE 0300 08DF 0315 0062; # (a◌̕◌̀◌֮◌ࣟb; à◌֮◌ࣟ◌̕b; a◌֮◌̀◌ࣟ◌̕b; à◌֮◌ࣟ◌̕b; a◌֮◌̀◌ࣟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD WAQFA, LATIN SMALL LETTER B +0061 08DF 0315 0300 05AE 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062; # (a◌ࣟ◌̕◌̀◌֮b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD WAQFA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E0 0062;00E0 05AE 08E0 0315 0062;0061 05AE 0300 08E0 0315 0062;00E0 05AE 08E0 0315 0062;0061 05AE 0300 08E0 0315 0062; # (a◌̕◌̀◌֮◌࣠b; à◌֮◌࣠◌̕b; a◌֮◌̀◌࣠◌̕b; à◌֮◌࣠◌̕b; a◌֮◌̀◌࣠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH FOOTNOTE MARKER, LATIN SMALL LETTER B +0061 08E0 0315 0300 05AE 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062; # (a◌࣠◌̕◌̀◌֮b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH FOOTNOTE MARKER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E1 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062; # (a◌̕◌̀◌֮◌࣡b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SIGN SAFHA, LATIN SMALL LETTER B +0061 08E1 0315 0300 05AE 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062; # (a◌࣡◌̕◌̀◌֮b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SIGN SAFHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E3 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062; # (a◌֚◌̖◌᷺◌ࣣb; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TURNED DAMMA BELOW, LATIN SMALL LETTER B +0061 08E3 059A 0316 1DFA 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062; # (a◌ࣣ◌֚◌̖◌᷺b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TURNED DAMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E4 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062; # (a◌̕◌̀◌֮◌ࣤb; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY FATHA, LATIN SMALL LETTER B +0061 08E4 0315 0300 05AE 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062; # (a◌ࣤ◌̕◌̀◌֮b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY FATHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E5 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062; # (a◌̕◌̀◌֮◌ࣥb; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY DAMMA, LATIN SMALL LETTER B +0061 08E5 0315 0300 05AE 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062; # (a◌ࣥ◌̕◌̀◌֮b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E6 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062; # (a◌֚◌̖◌᷺◌ࣦb; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC CURLY KASRA, LATIN SMALL LETTER B +0061 08E6 059A 0316 1DFA 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062; # (a◌ࣦ◌֚◌̖◌᷺b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E7 0062;00E0 05AE 08E7 0315 0062;0061 05AE 0300 08E7 0315 0062;00E0 05AE 08E7 0315 0062;0061 05AE 0300 08E7 0315 0062; # (a◌̕◌̀◌֮◌ࣧb; à◌֮◌ࣧ◌̕b; a◌֮◌̀◌ࣧ◌̕b; à◌֮◌ࣧ◌̕b; a◌֮◌̀◌ࣧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY FATHATAN, LATIN SMALL LETTER B +0061 08E7 0315 0300 05AE 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062; # (a◌ࣧ◌̕◌̀◌֮b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY FATHATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E8 0062;00E0 05AE 08E8 0315 0062;0061 05AE 0300 08E8 0315 0062;00E0 05AE 08E8 0315 0062;0061 05AE 0300 08E8 0315 0062; # (a◌̕◌̀◌֮◌ࣨb; à◌֮◌ࣨ◌̕b; a◌֮◌̀◌ࣨ◌̕b; à◌֮◌ࣨ◌̕b; a◌֮◌̀◌ࣨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY DAMMATAN, LATIN SMALL LETTER B +0061 08E8 0315 0300 05AE 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062; # (a◌ࣨ◌̕◌̀◌֮b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY DAMMATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E9 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062; # (a◌֚◌̖◌᷺◌ࣩb; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC CURLY KASRATAN, LATIN SMALL LETTER B +0061 08E9 059A 0316 1DFA 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062; # (a◌ࣩ◌֚◌̖◌᷺b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRATAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08EA 0062;00E0 05AE 08EA 0315 0062;0061 05AE 0300 08EA 0315 0062;00E0 05AE 08EA 0315 0062;0061 05AE 0300 08EA 0315 0062; # (a◌̕◌̀◌֮◌࣪b; à◌֮◌࣪◌̕b; a◌֮◌̀◌࣪◌̕b; à◌֮◌࣪◌̕b; a◌֮◌̀◌࣪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE ONE DOT ABOVE, LATIN SMALL LETTER B +0061 08EA 0315 0300 05AE 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062; # (a◌࣪◌̕◌̀◌֮b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE ONE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08EB 0062;00E0 05AE 08EB 0315 0062;0061 05AE 0300 08EB 0315 0062;00E0 05AE 08EB 0315 0062;0061 05AE 0300 08EB 0315 0062; # (a◌̕◌̀◌֮◌࣫b; à◌֮◌࣫◌̕b; a◌֮◌̀◌࣫◌̕b; à◌֮◌࣫◌̕b; a◌֮◌̀◌࣫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE TWO DOTS ABOVE, LATIN SMALL LETTER B +0061 08EB 0315 0300 05AE 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062; # (a◌࣫◌̕◌̀◌֮b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08EC 0062;00E0 05AE 08EC 0315 0062;0061 05AE 0300 08EC 0315 0062;00E0 05AE 08EC 0315 0062;0061 05AE 0300 08EC 0315 0062; # (a◌̕◌̀◌֮◌࣬b; à◌֮◌࣬◌̕b; a◌֮◌̀◌࣬◌̕b; à◌֮◌࣬◌̕b; a◌֮◌̀◌࣬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE LOOP ABOVE, LATIN SMALL LETTER B +0061 08EC 0315 0300 05AE 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062; # (a◌࣬◌̕◌̀◌֮b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE LOOP ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08ED 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062; # (a◌֚◌̖◌᷺◌࣭b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE ONE DOT BELOW, LATIN SMALL LETTER B +0061 08ED 059A 0316 1DFA 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062; # (a◌࣭◌֚◌̖◌᷺b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE ONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08EE 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062; # (a◌֚◌̖◌᷺◌࣮b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B +0061 08EE 059A 0316 1DFA 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062; # (a◌࣮◌֚◌̖◌᷺b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08EF 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062; # (a◌֚◌̖◌᷺◌࣯b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE LOOP BELOW, LATIN SMALL LETTER B +0061 08EF 059A 0316 1DFA 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062; # (a◌࣯◌֚◌̖◌᷺b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE LOOP BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 064C 064B FB1E 08F0 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062; # (a◌ٌ◌ً◌ﬞ◌ࣰb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC OPEN FATHATAN, LATIN SMALL LETTER B +0061 08F0 064C 064B FB1E 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062; # (a◌ࣰ◌ٌ◌ً◌ﬞb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC OPEN FATHATAN, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B +0061 064D 064C 064B 08F1 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062; # (a◌ٍ◌ٌ◌ً◌ࣱb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, ARABIC OPEN DAMMATAN, LATIN SMALL LETTER B +0061 08F1 064D 064C 064B 0062;0061 064B 08F1 064C 064D 0062;0061 064B 08F1 064C 064D 0062;0061 064B 08F1 064C 064D 0062;0061 064B 08F1 064C 064D 0062; # (a◌ࣱ◌ٍ◌ٌ◌ًb; a◌ً◌ࣱ◌ٌ◌ٍb; a◌ً◌ࣱ◌ٌ◌ٍb; a◌ً◌ࣱ◌ٌ◌ٍb; a◌ً◌ࣱ◌ٌ◌ٍb; ) LATIN SMALL LETTER A, ARABIC OPEN DAMMATAN, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, LATIN SMALL LETTER B +0061 0618 064D 064C 08F2 0062;0061 064C 064D 08F2 0618 0062;0061 064C 064D 08F2 0618 0062;0061 064C 064D 08F2 0618 0062;0061 064C 064D 08F2 0618 0062; # (a◌ؘ◌ٍ◌ٌ◌ࣲb; a◌ٌ◌ٍ◌ࣲ◌ؘb; a◌ٌ◌ٍ◌ࣲ◌ؘb; a◌ٌ◌ٍ◌ࣲ◌ؘb; a◌ٌ◌ٍ◌ࣲ◌ؘb; ) LATIN SMALL LETTER A, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC OPEN KASRATAN, LATIN SMALL LETTER B +0061 08F2 0618 064D 064C 0062;0061 064C 08F2 064D 0618 0062;0061 064C 08F2 064D 0618 0062;0061 064C 08F2 064D 0618 0062;0061 064C 08F2 064D 0618 0062; # (a◌ࣲ◌ؘ◌ٍ◌ٌb; a◌ٌ◌ࣲ◌ٍ◌ؘb; a◌ٌ◌ࣲ◌ٍ◌ؘb; a◌ٌ◌ࣲ◌ٍ◌ؘb; a◌ٌ◌ࣲ◌ٍ◌ؘb; ) LATIN SMALL LETTER A, ARABIC OPEN KASRATAN, ARABIC SMALL FATHA, ARABIC KASRATAN, ARABIC DAMMATAN, LATIN SMALL LETTER B +0061 0315 0300 05AE 08F3 0062;00E0 05AE 08F3 0315 0062;0061 05AE 0300 08F3 0315 0062;00E0 05AE 08F3 0315 0062;0061 05AE 0300 08F3 0315 0062; # (a◌̕◌̀◌֮◌ࣳb; à◌֮◌ࣳ◌̕b; a◌֮◌̀◌ࣳ◌̕b; à◌֮◌ࣳ◌̕b; a◌֮◌̀◌ࣳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WAW, LATIN SMALL LETTER B +0061 08F3 0315 0300 05AE 0062;0061 05AE 08F3 0300 0315 0062;0061 05AE 08F3 0300 0315 0062;0061 05AE 08F3 0300 0315 0062;0061 05AE 08F3 0300 0315 0062; # (a◌ࣳ◌̕◌̀◌֮b; a◌֮◌ࣳ◌̀◌̕b; a◌֮◌ࣳ◌̀◌̕b; a◌֮◌ࣳ◌̀◌̕b; a◌֮◌ࣳ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WAW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08F4 0062;00E0 05AE 08F4 0315 0062;0061 05AE 0300 08F4 0315 0062;00E0 05AE 08F4 0315 0062;0061 05AE 0300 08F4 0315 0062; # (a◌̕◌̀◌֮◌ࣴb; à◌֮◌ࣴ◌̕b; a◌֮◌̀◌ࣴ◌̕b; à◌֮◌ࣴ◌̕b; a◌֮◌̀◌ࣴ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC FATHA WITH RING, LATIN SMALL LETTER B +0061 08F4 0315 0300 05AE 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062; # (a◌ࣴ◌̕◌̀◌֮b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH RING, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08F5 0062;00E0 05AE 08F5 0315 0062;0061 05AE 0300 08F5 0315 0062;00E0 05AE 08F5 0315 0062;0061 05AE 0300 08F5 0315 0062; # (a◌̕◌̀◌֮◌ࣵb; à◌֮◌ࣵ◌̕b; a◌֮◌̀◌ࣵ◌̕b; à◌֮◌ࣵ◌̕b; a◌֮◌̀◌ࣵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC FATHA WITH DOT ABOVE, LATIN SMALL LETTER B +0061 08F5 0315 0300 05AE 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062; # (a◌ࣵ◌̕◌̀◌֮b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08F6 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062; # (a◌֚◌̖◌᷺◌ࣶb; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC KASRA WITH DOT BELOW, LATIN SMALL LETTER B +0061 08F6 059A 0316 1DFA 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062; # (a◌ࣶ◌֚◌̖◌᷺b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC KASRA WITH DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08F7 0062;00E0 05AE 08F7 0315 0062;0061 05AE 0300 08F7 0315 0062;00E0 05AE 08F7 0315 0062;0061 05AE 0300 08F7 0315 0062; # (a◌̕◌̀◌֮◌ࣷb; à◌֮◌ࣷ◌̕b; a◌֮◌̀◌ࣷ◌̕b; à◌֮◌ࣷ◌̕b; a◌֮◌̀◌ࣷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC LEFT ARROWHEAD ABOVE, LATIN SMALL LETTER B +0061 08F7 0315 0300 05AE 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062; # (a◌ࣷ◌̕◌̀◌֮b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC LEFT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08F8 0062;00E0 05AE 08F8 0315 0062;0061 05AE 0300 08F8 0315 0062;00E0 05AE 08F8 0315 0062;0061 05AE 0300 08F8 0315 0062; # (a◌̕◌̀◌֮◌ࣸb; à◌֮◌ࣸ◌̕b; a◌֮◌̀◌ࣸ◌̕b; à◌֮◌ࣸ◌̕b; a◌֮◌̀◌ࣸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B +0061 08F8 0315 0300 05AE 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062; # (a◌ࣸ◌̕◌̀◌֮b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08F9 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062; # (a◌֚◌̖◌᷺◌ࣹb; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 08F9 059A 0316 1DFA 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062; # (a◌ࣹ◌֚◌̖◌᷺b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08FA 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062; # (a◌֚◌̖◌᷺◌ࣺb; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 08FA 059A 0316 1DFA 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062; # (a◌ࣺ◌֚◌̖◌᷺b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 08FB 0062;00E0 05AE 08FB 0315 0062;0061 05AE 0300 08FB 0315 0062;00E0 05AE 08FB 0315 0062;0061 05AE 0300 08FB 0315 0062; # (a◌̕◌̀◌֮◌ࣻb; à◌֮◌ࣻ◌̕b; a◌֮◌̀◌ࣻ◌̕b; à◌֮◌ࣻ◌̕b; a◌֮◌̀◌ࣻ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B +0061 08FB 0315 0300 05AE 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062; # (a◌ࣻ◌̕◌̀◌֮b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08FC 0062;00E0 05AE 08FC 0315 0062;0061 05AE 0300 08FC 0315 0062;00E0 05AE 08FC 0315 0062;0061 05AE 0300 08FC 0315 0062; # (a◌̕◌̀◌֮◌ࣼb; à◌֮◌ࣼ◌̕b; a◌֮◌̀◌ࣼ◌̕b; à◌֮◌ࣼ◌̕b; a◌֮◌̀◌ࣼ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT, LATIN SMALL LETTER B +0061 08FC 0315 0300 05AE 0062;0061 05AE 08FC 0300 0315 0062;0061 05AE 08FC 0300 0315 0062;0061 05AE 08FC 0300 0315 0062;0061 05AE 08FC 0300 0315 0062; # (a◌ࣼ◌̕◌̀◌֮b; a◌֮◌ࣼ◌̀◌̕b; a◌֮◌ࣼ◌̀◌̕b; a◌֮◌ࣼ◌̀◌̕b; a◌֮◌ࣼ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08FD 0062;00E0 05AE 08FD 0315 0062;0061 05AE 0300 08FD 0315 0062;00E0 05AE 08FD 0315 0062;0061 05AE 0300 08FD 0315 0062; # (a◌̕◌̀◌֮◌ࣽb; à◌֮◌ࣽ◌̕b; a◌֮◌̀◌ࣽ◌̕b; à◌֮◌ࣽ◌̕b; a◌֮◌̀◌ࣽ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC RIGHT ARROWHEAD ABOVE WITH DOT, LATIN SMALL LETTER B +0061 08FD 0315 0300 05AE 0062;0061 05AE 08FD 0300 0315 0062;0061 05AE 08FD 0300 0315 0062;0061 05AE 08FD 0300 0315 0062;0061 05AE 08FD 0300 0315 0062; # (a◌ࣽ◌̕◌̀◌֮b; a◌֮◌ࣽ◌̀◌̕b; a◌֮◌ࣽ◌̀◌̕b; a◌֮◌ࣽ◌̀◌̕b; a◌֮◌ࣽ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD ABOVE WITH DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08FE 0062;00E0 05AE 08FE 0315 0062;0061 05AE 0300 08FE 0315 0062;00E0 05AE 08FE 0315 0062;0061 05AE 0300 08FE 0315 0062; # (a◌̕◌̀◌֮◌ࣾb; à◌֮◌ࣾ◌̕b; a◌֮◌̀◌ࣾ◌̕b; à◌֮◌ࣾ◌̕b; a◌֮◌̀◌ࣾ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DAMMA WITH DOT, LATIN SMALL LETTER B +0061 08FE 0315 0300 05AE 0062;0061 05AE 08FE 0300 0315 0062;0061 05AE 08FE 0300 0315 0062;0061 05AE 08FE 0300 0315 0062;0061 05AE 08FE 0300 0315 0062; # (a◌ࣾ◌̕◌̀◌֮b; a◌֮◌ࣾ◌̀◌̕b; a◌֮◌ࣾ◌̀◌̕b; a◌֮◌ࣾ◌̀◌̕b; a◌֮◌ࣾ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DAMMA WITH DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08FF 0062;00E0 05AE 08FF 0315 0062;0061 05AE 0300 08FF 0315 0062;00E0 05AE 08FF 0315 0062;0061 05AE 0300 08FF 0315 0062; # (a◌̕◌̀◌֮◌ࣿb; à◌֮◌ࣿ◌̕b; a◌֮◌̀◌ࣿ◌̕b; à◌֮◌ࣿ◌̕b; a◌֮◌̀◌ࣿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MARK SIDEWAYS NOON GHUNNA, LATIN SMALL LETTER B +0061 08FF 0315 0300 05AE 0062;0061 05AE 08FF 0300 0315 0062;0061 05AE 08FF 0300 0315 0062;0061 05AE 08FF 0300 0315 0062;0061 05AE 08FF 0300 0315 0062; # (a◌ࣿ◌̕◌̀◌֮b; a◌֮◌ࣿ◌̀◌̕b; a◌֮◌ࣿ◌̀◌̕b; a◌֮◌ࣿ◌̀◌̕b; a◌֮◌ࣿ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MARK SIDEWAYS NOON GHUNNA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 16FF0 093C 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062; # (a◌゙◌𖿰़◌़b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 093C 3099 093C 16FF0 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062;0061 16FF0 093C 093C 3099 0062; # (a◌़◌゙◌𖿰़b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; a𖿰◌़◌़◌゙b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 094D 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062; # (a◌ְ◌्◌゙◌्b; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, LATIN SMALL LETTER B +0061 094D 05B0 094D 3099 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062; # (a◌्◌ְ◌्◌゙b; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0951 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062; # (a◌̕◌̀◌֮◌॑b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI STRESS SIGN UDATTA, LATIN SMALL LETTER B +0061 0951 0315 0300 05AE 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062; # (a◌॑◌̕◌̀◌֮b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN UDATTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0952 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062; # (a◌֚◌̖◌᷺◌॒b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, DEVANAGARI STRESS SIGN ANUDATTA, LATIN SMALL LETTER B +0061 0952 059A 0316 1DFA 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062; # (a◌॒◌֚◌̖◌᷺b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0953 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062; # (a◌̕◌̀◌֮◌॓b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI GRAVE ACCENT, LATIN SMALL LETTER B +0061 0953 0315 0300 05AE 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062; # (a◌॓◌̕◌̀◌֮b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0954 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062; # (a◌̕◌̀◌֮◌॔b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI ACUTE ACCENT, LATIN SMALL LETTER B +0061 0954 0315 0300 05AE 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062;0061 05AE 0954 0300 0315 0062; # (a◌॔◌̕◌̀◌֮b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; a◌֮◌॔◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 16FF0 09BC 0062;0061 16FF0 093C 09BC 3099 0062;0061 16FF0 093C 09BC 3099 0062;0061 16FF0 093C 09BC 3099 0062;0061 16FF0 093C 09BC 3099 0062; # (a◌゙◌𖿰़◌়b; a𖿰◌़◌়◌゙b; a𖿰◌़◌়◌゙b; a𖿰◌़◌়◌゙b; a𖿰◌़◌়◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, BENGALI SIGN NUKTA, LATIN SMALL LETTER B +0061 09BC 3099 093C 16FF0 0062;0061 16FF0 09BC 093C 3099 0062;0061 16FF0 09BC 093C 3099 0062;0061 16FF0 09BC 093C 3099 0062;0061 16FF0 09BC 093C 3099 0062; # (a◌়◌゙◌𖿰़b; a𖿰◌়◌़◌゙b; a𖿰◌়◌़◌゙b; a𖿰◌়◌़◌゙b; a𖿰◌়◌़◌゙b; ) LATIN SMALL LETTER A, BENGALI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 09CD 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062; # (a◌ְ◌्◌゙◌্b; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BENGALI SIGN VIRAMA, LATIN SMALL LETTER B +0061 09CD 05B0 094D 3099 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062; # (a◌্◌ְ◌्◌゙b; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; ) LATIN SMALL LETTER A, BENGALI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 09FE 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062; # (a◌̕◌̀◌֮◌৾b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BENGALI SANDHI MARK, LATIN SMALL LETTER B +0061 09FE 0315 0300 05AE 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062; # (a◌৾◌̕◌̀◌֮b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; ) LATIN SMALL LETTER A, BENGALI SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0A3C 0062;0061 16FF0 093C 0A3C 3099 0062;0061 16FF0 093C 0A3C 3099 0062;0061 16FF0 093C 0A3C 3099 0062;0061 16FF0 093C 0A3C 3099 0062; # (a◌゙◌𖿰़◌਼b; a𖿰◌़◌਼◌゙b; a𖿰◌़◌਼◌゙b; a𖿰◌़◌਼◌゙b; a𖿰◌़◌਼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, GURMUKHI SIGN NUKTA, LATIN SMALL LETTER B +0061 0A3C 3099 093C 16FF0 0062;0061 16FF0 0A3C 093C 3099 0062;0061 16FF0 0A3C 093C 3099 0062;0061 16FF0 0A3C 093C 3099 0062;0061 16FF0 0A3C 093C 3099 0062; # (a◌਼◌゙◌𖿰़b; a𖿰◌਼◌़◌゙b; a𖿰◌਼◌़◌゙b; a𖿰◌਼◌़◌゙b; a𖿰◌਼◌़◌゙b; ) LATIN SMALL LETTER A, GURMUKHI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 0A4D 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062; # (a◌ְ◌्◌゙◌੍b; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GURMUKHI SIGN VIRAMA, LATIN SMALL LETTER B +0061 0A4D 05B0 094D 3099 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062;0061 3099 0A4D 094D 05B0 0062; # (a◌੍◌ְ◌्◌゙b; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; a◌゙◌੍◌्◌ְb; ) LATIN SMALL LETTER A, GURMUKHI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0ABC 0062;0061 16FF0 093C 0ABC 3099 0062;0061 16FF0 093C 0ABC 3099 0062;0061 16FF0 093C 0ABC 3099 0062;0061 16FF0 093C 0ABC 3099 0062; # (a◌゙◌𖿰़◌઼b; a𖿰◌़◌઼◌゙b; a𖿰◌़◌઼◌゙b; a𖿰◌़◌઼◌゙b; a𖿰◌़◌઼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, GUJARATI SIGN NUKTA, LATIN SMALL LETTER B +0061 0ABC 3099 093C 16FF0 0062;0061 16FF0 0ABC 093C 3099 0062;0061 16FF0 0ABC 093C 3099 0062;0061 16FF0 0ABC 093C 3099 0062;0061 16FF0 0ABC 093C 3099 0062; # (a◌઼◌゙◌𖿰़b; a𖿰◌઼◌़◌゙b; a𖿰◌઼◌़◌゙b; a𖿰◌઼◌़◌゙b; a𖿰◌઼◌़◌゙b; ) LATIN SMALL LETTER A, GUJARATI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 0ACD 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062;0061 3099 094D 0ACD 05B0 0062; # (a◌ְ◌्◌゙◌્b; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; a◌゙◌्◌્◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUJARATI SIGN VIRAMA, LATIN SMALL LETTER B +0061 0ACD 05B0 094D 3099 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062;0061 3099 0ACD 094D 05B0 0062; # (a◌્◌ְ◌्◌゙b; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; a◌゙◌્◌्◌ְb; ) LATIN SMALL LETTER A, GUJARATI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0B3C 0062;0061 16FF0 093C 0B3C 3099 0062;0061 16FF0 093C 0B3C 3099 0062;0061 16FF0 093C 0B3C 3099 0062;0061 16FF0 093C 0B3C 3099 0062; # (a◌゙◌𖿰़◌଼b; a𖿰◌़◌଼◌゙b; a𖿰◌़◌଼◌゙b; a𖿰◌़◌଼◌゙b; a𖿰◌़◌଼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, ORIYA SIGN NUKTA, LATIN SMALL LETTER B +0061 0B3C 3099 093C 16FF0 0062;0061 16FF0 0B3C 093C 3099 0062;0061 16FF0 0B3C 093C 3099 0062;0061 16FF0 0B3C 093C 3099 0062;0061 16FF0 0B3C 093C 3099 0062; # (a◌଼◌゙◌𖿰़b; a𖿰◌଼◌़◌゙b; a𖿰◌଼◌़◌゙b; a𖿰◌଼◌़◌゙b; a𖿰◌଼◌़◌゙b; ) LATIN SMALL LETTER A, ORIYA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 0B4D 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062;0061 3099 094D 0B4D 05B0 0062; # (a◌ְ◌्◌゙◌୍b; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; a◌゙◌्◌୍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ORIYA SIGN VIRAMA, LATIN SMALL LETTER B +0061 0B4D 05B0 094D 3099 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062; # (a◌୍◌ְ◌्◌゙b; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; ) LATIN SMALL LETTER A, ORIYA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0BCD 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062; # (a◌ְ◌्◌゙◌்b; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAMIL SIGN VIRAMA, LATIN SMALL LETTER B +0061 0BCD 05B0 094D 3099 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062; # (a◌்◌ְ◌्◌゙b; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; ) LATIN SMALL LETTER A, TAMIL SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0C3C 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062; # (a◌゙◌𖿰़◌఼b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, TELUGU SIGN NUKTA, LATIN SMALL LETTER B +0061 0C3C 3099 093C 16FF0 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062; # (a◌఼◌゙◌𖿰़b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; ) LATIN SMALL LETTER A, TELUGU SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 0C4D 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062; # (a◌ְ◌्◌゙◌్b; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TELUGU SIGN VIRAMA, LATIN SMALL LETTER B +0061 0C4D 05B0 094D 3099 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062; # (a◌్◌ְ◌्◌゙b; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; ) LATIN SMALL LETTER A, TELUGU SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0C56 0C55 0711 0C55 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062; # (a◌ౖ◌ౕ◌ܑ◌ౕb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; ) LATIN SMALL LETTER A, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, LATIN SMALL LETTER B +0061 0C55 0C56 0C55 0711 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062; # (a◌ౕ◌ౖ◌ౕ◌ܑb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; ) LATIN SMALL LETTER A, TELUGU LENGTH MARK, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, LATIN SMALL LETTER B +0061 0E38 0C56 0C55 0C56 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062; # (a◌ุ◌ౖ◌ౕ◌ౖb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; ) LATIN SMALL LETTER A, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 0C56 0E38 0C56 0C55 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062;0061 0C55 0C56 0C56 0E38 0062; # (a◌ౖ◌ุ◌ౖ◌ౕb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; a◌ౕ◌ౖ◌ౖ◌ุb; ) LATIN SMALL LETTER A, TELUGU AI LENGTH MARK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0CBC 0062;0061 16FF0 093C 0CBC 3099 0062;0061 16FF0 093C 0CBC 3099 0062;0061 16FF0 093C 0CBC 3099 0062;0061 16FF0 093C 0CBC 3099 0062; # (a◌゙◌𖿰़◌಼b; a𖿰◌़◌಼◌゙b; a𖿰◌़◌಼◌゙b; a𖿰◌़◌಼◌゙b; a𖿰◌़◌಼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, KANNADA SIGN NUKTA, LATIN SMALL LETTER B +0061 0CBC 3099 093C 16FF0 0062;0061 16FF0 0CBC 093C 3099 0062;0061 16FF0 0CBC 093C 3099 0062;0061 16FF0 0CBC 093C 3099 0062;0061 16FF0 0CBC 093C 3099 0062; # (a◌಼◌゙◌𖿰़b; a𖿰◌಼◌़◌゙b; a𖿰◌಼◌़◌゙b; a𖿰◌಼◌़◌゙b; a𖿰◌಼◌़◌゙b; ) LATIN SMALL LETTER A, KANNADA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 0CCD 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062; # (a◌ְ◌्◌゙◌್b; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KANNADA SIGN VIRAMA, LATIN SMALL LETTER B +0061 0CCD 05B0 094D 3099 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062; # (a◌್◌ְ◌्◌゙b; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; ) LATIN SMALL LETTER A, KANNADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D3B 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062; # (a◌ְ◌्◌゙◌഻b; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VERTICAL BAR VIRAMA, LATIN SMALL LETTER B +0061 0D3B 05B0 094D 3099 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062; # (a◌഻◌ְ◌्◌゙b; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VERTICAL BAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D3C 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062; # (a◌ְ◌्◌゙◌഼b; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN CIRCULAR VIRAMA, LATIN SMALL LETTER B +0061 0D3C 05B0 094D 3099 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062; # (a◌഼◌ְ◌्◌゙b; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN CIRCULAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D4D 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062; # (a◌ְ◌्◌゙◌്b; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VIRAMA, LATIN SMALL LETTER B +0061 0D4D 05B0 094D 3099 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062; # (a◌്◌ְ◌्◌゙b; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0DCA 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062; # (a◌ְ◌्◌゙◌්b; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SINHALA SIGN AL-LAKUNA, LATIN SMALL LETTER B +0061 0DCA 05B0 094D 3099 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062;0061 3099 0DCA 094D 05B0 0062; # (a◌්◌ְ◌्◌゙b; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; a◌゙◌්◌्◌ְb; ) LATIN SMALL LETTER A, SINHALA SIGN AL-LAKUNA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0E48 0E38 0C56 0E38 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062; # (a◌่◌ุ◌ౖ◌ุb; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0E38 0E48 0E38 0C56 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062;0061 0C56 0E38 0E38 0E48 0062; # (a◌ุ◌่◌ุ◌ౖb; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; a◌ౖ◌ุ◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER SARA U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 0E48 0E38 0C56 0E39 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062;0061 0C56 0E38 0E39 0E48 0062; # (a◌่◌ุ◌ౖ◌ูb; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; a◌ౖ◌ุ◌ู◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, THAI CHARACTER SARA UU, LATIN SMALL LETTER B +0061 0E39 0E48 0E38 0C56 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062;0061 0C56 0E39 0E38 0E48 0062; # (a◌ู◌่◌ุ◌ౖb; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; a◌ౖ◌ู◌ุ◌่b; ) LATIN SMALL LETTER A, THAI CHARACTER SARA UU, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, TELUGU AI LENGTH MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0E3A 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062;0061 3099 094D 0E3A 05B0 0062; # (a◌ְ◌्◌゙◌ฺb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; a◌゙◌्◌ฺ◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, THAI CHARACTER PHINTHU, LATIN SMALL LETTER B +0061 0E3A 05B0 094D 3099 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062;0061 3099 0E3A 094D 05B0 0062; # (a◌ฺ◌ְ◌्◌゙b; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; a◌゙◌ฺ◌्◌ְb; ) LATIN SMALL LETTER A, THAI CHARACTER PHINTHU, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E48 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062; # (a◌ຸ◌่◌ุ◌่b; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 0E48 0EB8 0E48 0E38 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062;0061 0E38 0E48 0E48 0EB8 0062; # (a◌่◌ຸ◌่◌ุb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; a◌ุ◌่◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E49 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062;0061 0E38 0E48 0E49 0EB8 0062; # (a◌ຸ◌่◌ุ◌้b; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; a◌ุ◌่◌้◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI THO, LATIN SMALL LETTER B +0061 0E49 0EB8 0E48 0E38 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062;0061 0E38 0E49 0E48 0EB8 0062; # (a◌้◌ຸ◌่◌ุb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; a◌ุ◌้◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI THO, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E4A 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062;0061 0E38 0E48 0E4A 0EB8 0062; # (a◌ຸ◌่◌ุ◌๊b; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; a◌ุ◌่◌๊◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI TRI, LATIN SMALL LETTER B +0061 0E4A 0EB8 0E48 0E38 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062;0061 0E38 0E4A 0E48 0EB8 0062; # (a◌๊◌ຸ◌่◌ุb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; a◌ุ◌๊◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI TRI, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EB8 0E48 0E38 0E4B 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062;0061 0E38 0E48 0E4B 0EB8 0062; # (a◌ຸ◌่◌ุ◌๋b; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; a◌ุ◌่◌๋◌ຸb; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, THAI CHARACTER MAI CHATTAWA, LATIN SMALL LETTER B +0061 0E4B 0EB8 0E48 0E38 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062;0061 0E38 0E4B 0E48 0EB8 0062; # (a◌๋◌ຸ◌่◌ุb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; a◌ุ◌๋◌่◌ຸb; ) LATIN SMALL LETTER A, THAI CHARACTER MAI CHATTAWA, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, THAI CHARACTER SARA U, LATIN SMALL LETTER B +0061 0EC8 0EB8 0E48 0EB8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062; # (a◌່◌ຸ◌่◌ຸb; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0EB8 0EC8 0EB8 0E48 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062;0061 0E48 0EB8 0EB8 0EC8 0062; # (a◌ຸ◌່◌ຸ◌่b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; a◌่◌ຸ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO VOWEL SIGN U, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 0EC8 0EB8 0E48 0EB9 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062;0061 0E48 0EB8 0EB9 0EC8 0062; # (a◌່◌ຸ◌่◌ູb; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; a◌่◌ຸ◌ູ◌່b; ) LATIN SMALL LETTER A, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LAO VOWEL SIGN UU, LATIN SMALL LETTER B +0061 0EB9 0EC8 0EB8 0E48 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062;0061 0E48 0EB9 0EB8 0EC8 0062; # (a◌ູ◌່◌ຸ◌่b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; a◌่◌ູ◌ຸ◌່b; ) LATIN SMALL LETTER A, LAO VOWEL SIGN UU, LAO TONE MAI EK, LAO VOWEL SIGN U, THAI CHARACTER MAI EK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0EBA 0062;0061 3099 094D 0EBA 05B0 0062;0061 3099 094D 0EBA 05B0 0062;0061 3099 094D 0EBA 05B0 0062;0061 3099 094D 0EBA 05B0 0062; # (a◌ְ◌्◌゙◌຺b; a◌゙◌्◌຺◌ְb; a◌゙◌्◌຺◌ְb; a◌゙◌्◌຺◌ְb; a◌゙◌्◌຺◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LAO SIGN PALI VIRAMA, LATIN SMALL LETTER B +0061 0EBA 05B0 094D 3099 0062;0061 3099 0EBA 094D 05B0 0062;0061 3099 0EBA 094D 05B0 0062;0061 3099 0EBA 094D 05B0 0062;0061 3099 0EBA 094D 05B0 0062; # (a◌຺◌ְ◌्◌゙b; a◌゙◌຺◌्◌ְb; a◌゙◌຺◌्◌ְb; a◌゙◌຺◌्◌ְb; a◌゙◌຺◌्◌ְb; ) LATIN SMALL LETTER A, LAO SIGN PALI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0EC8 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062; # (a◌ཱ◌່◌ຸ◌່b; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI EK, LATIN SMALL LETTER B +0061 0EC8 0F71 0EC8 0EB8 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062;0061 0EB8 0EC8 0EC8 0F71 0062; # (a◌່◌ཱ◌່◌ຸb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; a◌ຸ◌່◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI EK, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0EC9 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062;0061 0EB8 0EC8 0EC9 0F71 0062; # (a◌ཱ◌່◌ຸ◌້b; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; a◌ຸ◌່◌້◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI THO, LATIN SMALL LETTER B +0061 0EC9 0F71 0EC8 0EB8 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062;0061 0EB8 0EC9 0EC8 0F71 0062; # (a◌້◌ཱ◌່◌ຸb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; a◌ຸ◌້◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI THO, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0ECA 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062;0061 0EB8 0EC8 0ECA 0F71 0062; # (a◌ཱ◌່◌ຸ◌໊b; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; a◌ຸ◌່◌໊◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI TI, LATIN SMALL LETTER B +0061 0ECA 0F71 0EC8 0EB8 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062; # (a◌໊◌ཱ◌່◌ຸb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI TI, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F71 0EC8 0EB8 0ECB 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062; # (a◌ཱ◌່◌ຸ◌໋b; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI CATAWA, LATIN SMALL LETTER B +0061 0ECB 0F71 0EC8 0EB8 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062; # (a◌໋◌ཱ◌່◌ຸb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI CATAWA, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F18 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062; # (a◌֚◌̖◌᷺◌༘b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, LATIN SMALL LETTER B +0061 0F18 059A 0316 1DFA 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062; # (a◌༘◌֚◌̖◌᷺b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F19 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062; # (a◌֚◌̖◌᷺◌༙b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, LATIN SMALL LETTER B +0061 0F19 059A 0316 1DFA 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062; # (a◌༙◌֚◌̖◌᷺b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F35 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062; # (a◌֚◌̖◌᷺◌༵b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN MARK NGAS BZUNG NYI ZLA, LATIN SMALL LETTER B +0061 0F35 059A 0316 1DFA 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062; # (a◌༵◌֚◌̖◌᷺b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG NYI ZLA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F37 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062; # (a◌֚◌̖◌᷺◌༷b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN MARK NGAS BZUNG SGOR RTAGS, LATIN SMALL LETTER B +0061 0F37 059A 0316 1DFA 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062; # (a◌༷◌֚◌̖◌᷺b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG SGOR RTAGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 0F39 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062; # (a◌᷺◌̛◌᷎◌༹b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, TIBETAN MARK TSA -PHRU, LATIN SMALL LETTER B +0061 0F39 1DFA 031B 1DCE 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062; # (a◌༹◌᷺◌̛◌᷎b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; ) LATIN SMALL LETTER A, TIBETAN MARK TSA -PHRU, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 0F72 0F71 0EC8 0F71 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ི◌ཱ◌່◌ཱb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F71 0F72 0F71 0EC8 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ཱ◌ི◌ཱ◌່b; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F72 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062; # (a◌ུ◌ི◌ཱ◌ིb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, LATIN SMALL LETTER B +0061 0F72 0F74 0F72 0F71 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062; # (a◌ི◌ུ◌ི◌ཱb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0321 0F74 0F72 0F74 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062; # (a◌̡◌ུ◌ི◌ུb; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; ) LATIN SMALL LETTER A, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 0F74 0321 0F74 0F72 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062;0061 0F72 0F74 0F74 0321 0062; # (a◌ུ◌̡◌ུ◌ིb; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; a◌ི◌ུ◌ུ◌̡b; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7A 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062;0061 0F71 0F72 0F7A 0F74 0062; # (a◌ུ◌ི◌ཱ◌ེb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; a◌ཱ◌ི◌ེ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN E, LATIN SMALL LETTER B +0061 0F7A 0F74 0F72 0F71 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062;0061 0F71 0F7A 0F72 0F74 0062; # (a◌ེ◌ུ◌ི◌ཱb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; a◌ཱ◌ེ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN E, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7B 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062;0061 0F71 0F72 0F7B 0F74 0062; # (a◌ུ◌ི◌ཱ◌ཻb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; a◌ཱ◌ི◌ཻ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN EE, LATIN SMALL LETTER B +0061 0F7B 0F74 0F72 0F71 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062;0061 0F71 0F7B 0F72 0F74 0062; # (a◌ཻ◌ུ◌ི◌ཱb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; a◌ཱ◌ཻ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN EE, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7C 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062;0061 0F71 0F72 0F7C 0F74 0062; # (a◌ུ◌ི◌ཱ◌ོb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; a◌ཱ◌ི◌ོ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN O, LATIN SMALL LETTER B +0061 0F7C 0F74 0F72 0F71 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062;0061 0F71 0F7C 0F72 0F74 0062; # (a◌ོ◌ུ◌ི◌ཱb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; a◌ཱ◌ོ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN O, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F7D 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062;0061 0F71 0F72 0F7D 0F74 0062; # (a◌ུ◌ི◌ཱ◌ཽb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; a◌ཱ◌ི◌ཽ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN OO, LATIN SMALL LETTER B +0061 0F7D 0F74 0F72 0F71 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062;0061 0F71 0F7D 0F72 0F74 0062; # (a◌ཽ◌ུ◌ི◌ཱb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; a◌ཱ◌ཽ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN OO, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0F74 0F72 0F71 0F80 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062;0061 0F71 0F72 0F80 0F74 0062; # (a◌ུ◌ི◌ཱ◌ྀb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; a◌ཱ◌ི◌ྀ◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN REVERSED I, LATIN SMALL LETTER B +0061 0F80 0F74 0F72 0F71 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062;0061 0F71 0F80 0F72 0F74 0062; # (a◌ྀ◌ུ◌ི◌ཱb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; a◌ཱ◌ྀ◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN REVERSED I, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F82 0062;00E0 05AE 0F82 0315 0062;0061 05AE 0300 0F82 0315 0062;00E0 05AE 0F82 0315 0062;0061 05AE 0300 0F82 0315 0062; # (a◌̕◌̀◌֮◌ྂb; à◌֮◌ྂ◌̕b; a◌֮◌̀◌ྂ◌̕b; à◌֮◌ྂ◌̕b; a◌֮◌̀◌ྂ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN NYI ZLA NAA DA, LATIN SMALL LETTER B +0061 0F82 0315 0300 05AE 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062;0061 05AE 0F82 0300 0315 0062; # (a◌ྂ◌̕◌̀◌֮b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; a◌֮◌ྂ◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN NYI ZLA NAA DA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F83 0062;00E0 05AE 0F83 0315 0062;0061 05AE 0300 0F83 0315 0062;00E0 05AE 0F83 0315 0062;0061 05AE 0300 0F83 0315 0062; # (a◌̕◌̀◌֮◌ྃb; à◌֮◌ྃ◌̕b; a◌֮◌̀◌ྃ◌̕b; à◌֮◌ྃ◌̕b; a◌֮◌̀◌ྃ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN SNA LDAN, LATIN SMALL LETTER B +0061 0F83 0315 0300 05AE 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062;0061 05AE 0F83 0300 0315 0062; # (a◌ྃ◌̕◌̀◌֮b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; a◌֮◌ྃ◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN SNA LDAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 0F84 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062;0061 3099 094D 0F84 05B0 0062; # (a◌ְ◌्◌゙◌྄b; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; a◌゙◌्◌྄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIBETAN MARK HALANTA, LATIN SMALL LETTER B +0061 0F84 05B0 094D 3099 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062;0061 3099 0F84 094D 05B0 0062; # (a◌྄◌ְ◌्◌゙b; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; a◌゙◌྄◌्◌ְb; ) LATIN SMALL LETTER A, TIBETAN MARK HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F86 0062;00E0 05AE 0F86 0315 0062;0061 05AE 0300 0F86 0315 0062;00E0 05AE 0F86 0315 0062;0061 05AE 0300 0F86 0315 0062; # (a◌̕◌̀◌֮◌྆b; à◌֮◌྆◌̕b; a◌֮◌̀◌྆◌̕b; à◌֮◌྆◌̕b; a◌֮◌̀◌྆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN LCI RTAGS, LATIN SMALL LETTER B +0061 0F86 0315 0300 05AE 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062; # (a◌྆◌̕◌̀◌֮b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN LCI RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 0F87 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062; # (a◌̕◌̀◌֮◌྇b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN YANG RTAGS, LATIN SMALL LETTER B +0061 0F87 0315 0300 05AE 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062; # (a◌྇◌̕◌̀◌֮b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN YANG RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0FC6 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062; # (a◌֚◌̖◌᷺◌࿆b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN SYMBOL PADMA GDAN, LATIN SMALL LETTER B +0061 0FC6 059A 0316 1DFA 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062; # (a◌࿆◌֚◌̖◌᷺b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN SYMBOL PADMA GDAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1037 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062; # (a◌゙◌𖿰़◌့b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, MYANMAR SIGN DOT BELOW, LATIN SMALL LETTER B +0061 1037 3099 093C 16FF0 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062; # (a◌့◌゙◌𖿰़b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; ) LATIN SMALL LETTER A, MYANMAR SIGN DOT BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1039 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062; # (a◌ְ◌्◌゙◌္b; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MYANMAR SIGN VIRAMA, LATIN SMALL LETTER B +0061 1039 05B0 094D 3099 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062; # (a◌္◌ְ◌्◌゙b; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; ) LATIN SMALL LETTER A, MYANMAR SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 103A 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062; # (a◌ְ◌्◌゙◌်b; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MYANMAR SIGN ASAT, LATIN SMALL LETTER B +0061 103A 05B0 094D 3099 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062; # (a◌်◌ְ◌्◌゙b; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; ) LATIN SMALL LETTER A, MYANMAR SIGN ASAT, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 108D 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062; # (a◌֚◌̖◌᷺◌ႍb; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, LATIN SMALL LETTER B +0061 108D 059A 0316 1DFA 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062; # (a◌ႍ◌֚◌̖◌᷺b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; ) LATIN SMALL LETTER A, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 135D 0062;00E0 05AE 135D 0315 0062;0061 05AE 0300 135D 0315 0062;00E0 05AE 135D 0315 0062;0061 05AE 0300 135D 0315 0062; # (a◌̕◌̀◌֮◌፝b; à◌֮◌፝◌̕b; a◌֮◌̀◌፝◌̕b; à◌֮◌፝◌̕b; a◌֮◌̀◌፝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK, LATIN SMALL LETTER B +0061 135D 0315 0300 05AE 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062; # (a◌፝◌̕◌̀◌֮b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; ) LATIN SMALL LETTER A, ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 135E 0062;00E0 05AE 135E 0315 0062;0061 05AE 0300 135E 0315 0062;00E0 05AE 135E 0315 0062;0061 05AE 0300 135E 0315 0062; # (a◌̕◌̀◌֮◌፞b; à◌֮◌፞◌̕b; a◌֮◌̀◌፞◌̕b; à◌֮◌፞◌̕b; a◌֮◌̀◌፞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ETHIOPIC COMBINING VOWEL LENGTH MARK, LATIN SMALL LETTER B +0061 135E 0315 0300 05AE 0062;0061 05AE 135E 0300 0315 0062;0061 05AE 135E 0300 0315 0062;0061 05AE 135E 0300 0315 0062;0061 05AE 135E 0300 0315 0062; # (a◌፞◌̕◌̀◌֮b; a◌֮◌፞◌̀◌̕b; a◌֮◌፞◌̀◌̕b; a◌֮◌፞◌̀◌̕b; a◌֮◌፞◌̀◌̕b; ) LATIN SMALL LETTER A, ETHIOPIC COMBINING VOWEL LENGTH MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 135F 0062;00E0 05AE 135F 0315 0062;0061 05AE 0300 135F 0315 0062;00E0 05AE 135F 0315 0062;0061 05AE 0300 135F 0315 0062; # (a◌̕◌̀◌֮◌፟b; à◌֮◌፟◌̕b; a◌֮◌̀◌፟◌̕b; à◌֮◌፟◌̕b; a◌֮◌̀◌፟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ETHIOPIC COMBINING GEMINATION MARK, LATIN SMALL LETTER B +0061 135F 0315 0300 05AE 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062; # (a◌፟◌̕◌̀◌֮b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; ) LATIN SMALL LETTER A, ETHIOPIC COMBINING GEMINATION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 1714 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062; # (a◌ְ◌्◌゙◌᜔b; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAGALOG SIGN VIRAMA, LATIN SMALL LETTER B +0061 1714 05B0 094D 3099 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062; # (a◌᜔◌ְ◌्◌゙b; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; ) LATIN SMALL LETTER A, TAGALOG SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1715 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062; # (a◌ְ◌्◌゙᜕b; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAGALOG SIGN PAMUDPOD, LATIN SMALL LETTER B +0061 1715 05B0 094D 3099 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062; # (a᜕◌ְ◌्◌゙b; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; ) LATIN SMALL LETTER A, TAGALOG SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1734 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062; # (a◌ְ◌्◌゙᜴b; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, HANUNOO SIGN PAMUDPOD, LATIN SMALL LETTER B +0061 1734 05B0 094D 3099 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062; # (a᜴◌ְ◌्◌゙b; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; ) LATIN SMALL LETTER A, HANUNOO SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 17D2 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062; # (a◌ְ◌्◌゙◌្b; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHMER SIGN COENG, LATIN SMALL LETTER B +0061 17D2 05B0 094D 3099 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062; # (a◌្◌ְ◌्◌゙b; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; ) LATIN SMALL LETTER A, KHMER SIGN COENG, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 17DD 0062;00E0 05AE 17DD 0315 0062;0061 05AE 0300 17DD 0315 0062;00E0 05AE 17DD 0315 0062;0061 05AE 0300 17DD 0315 0062; # (a◌̕◌̀◌֮◌៝b; à◌֮◌៝◌̕b; a◌֮◌̀◌៝◌̕b; à◌֮◌៝◌̕b; a◌֮◌̀◌៝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHMER SIGN ATTHACAN, LATIN SMALL LETTER B +0061 17DD 0315 0300 05AE 0062;0061 05AE 17DD 0300 0315 0062;0061 05AE 17DD 0300 0315 0062;0061 05AE 17DD 0300 0315 0062;0061 05AE 17DD 0300 0315 0062; # (a◌៝◌̕◌̀◌֮b; a◌֮◌៝◌̀◌̕b; a◌֮◌៝◌̀◌̕b; a◌֮◌៝◌̀◌̕b; a◌֮◌៝◌̀◌̕b; ) LATIN SMALL LETTER A, KHMER SIGN ATTHACAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 18A9 0062;00E0 1D16D 05AE 18A9 0062;0061 1D16D 05AE 18A9 0300 0062;00E0 1D16D 05AE 18A9 0062;0061 1D16D 05AE 18A9 0300 0062; # (a◌̀◌𝅭֮◌ᢩb; à𝅭◌֮◌ᢩb; a𝅭◌֮◌ᢩ◌̀b; à𝅭◌֮◌ᢩb; a𝅭◌֮◌ᢩ◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, MONGOLIAN LETTER ALI GALI DAGALGA, LATIN SMALL LETTER B +0061 18A9 0300 05AE 1D16D 0062;00E0 1D16D 18A9 05AE 0062;0061 1D16D 18A9 05AE 0300 0062;00E0 1D16D 18A9 05AE 0062;0061 1D16D 18A9 05AE 0300 0062; # (a◌ᢩ◌̀◌𝅭֮b; à𝅭◌ᢩ◌֮b; a𝅭◌ᢩ◌֮◌̀b; à𝅭◌ᢩ◌֮b; a𝅭◌ᢩ◌֮◌̀b; ) LATIN SMALL LETTER A, MONGOLIAN LETTER ALI GALI DAGALGA, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 302E 059A 0316 1939 0062;0061 0316 059A 1939 302E 0062;0061 0316 059A 1939 302E 0062;0061 0316 059A 1939 302E 0062;0061 0316 059A 1939 302E 0062; # (a〮◌֚◌̖◌᤹b; a◌̖◌֚◌᤹〮b; a◌̖◌֚◌᤹〮b; a◌̖◌֚◌᤹〮b; a◌̖◌֚◌᤹〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LIMBU SIGN MUKPHRENG, LATIN SMALL LETTER B +0061 1939 302E 059A 0316 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062; # (a◌᤹〮◌֚◌̖b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; ) LATIN SMALL LETTER A, LIMBU SIGN MUKPHRENG, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0315 0300 05AE 193A 0062;00E0 05AE 193A 0315 0062;0061 05AE 0300 193A 0315 0062;00E0 05AE 193A 0315 0062;0061 05AE 0300 193A 0315 0062; # (a◌̕◌̀◌֮◌᤺b; à◌֮◌᤺◌̕b; a◌֮◌̀◌᤺◌̕b; à◌֮◌᤺◌̕b; a◌֮◌̀◌᤺◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LIMBU SIGN KEMPHRENG, LATIN SMALL LETTER B +0061 193A 0315 0300 05AE 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062; # (a◌᤺◌̕◌̀◌֮b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; ) LATIN SMALL LETTER A, LIMBU SIGN KEMPHRENG, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 193B 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062; # (a◌֚◌̖◌᷺◌᤻b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LIMBU SIGN SA-I, LATIN SMALL LETTER B +0061 193B 059A 0316 1DFA 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062; # (a◌᤻◌֚◌̖◌᷺b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; ) LATIN SMALL LETTER A, LIMBU SIGN SA-I, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A17 0062;00E0 05AE 1A17 0315 0062;0061 05AE 0300 1A17 0315 0062;00E0 05AE 1A17 0315 0062;0061 05AE 0300 1A17 0315 0062; # (a◌̕◌̀◌֮◌ᨗb; à◌֮◌ᨗ◌̕b; a◌֮◌̀◌ᨗ◌̕b; à◌֮◌ᨗ◌̕b; a◌֮◌̀◌ᨗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BUGINESE VOWEL SIGN I, LATIN SMALL LETTER B +0061 1A17 0315 0300 05AE 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062; # (a◌ᨗ◌̕◌̀◌֮b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; ) LATIN SMALL LETTER A, BUGINESE VOWEL SIGN I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1A18 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062; # (a◌֚◌̖◌᷺◌ᨘb; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, BUGINESE VOWEL SIGN U, LATIN SMALL LETTER B +0061 1A18 059A 0316 1DFA 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062; # (a◌ᨘ◌֚◌̖◌᷺b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; ) LATIN SMALL LETTER A, BUGINESE VOWEL SIGN U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 05B0 094D 3099 1A60 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062; # (a◌ְ◌्◌゙◌᩠b; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAI THAM SIGN SAKOT, LATIN SMALL LETTER B +0061 1A60 05B0 094D 3099 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062; # (a◌᩠◌ְ◌्◌゙b; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; ) LATIN SMALL LETTER A, TAI THAM SIGN SAKOT, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A75 0062;00E0 05AE 1A75 0315 0062;0061 05AE 0300 1A75 0315 0062;00E0 05AE 1A75 0315 0062;0061 05AE 0300 1A75 0315 0062; # (a◌̕◌̀◌֮◌᩵b; à◌֮◌᩵◌̕b; a◌֮◌̀◌᩵◌̕b; à◌֮◌᩵◌̕b; a◌֮◌̀◌᩵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN TONE-1, LATIN SMALL LETTER B +0061 1A75 0315 0300 05AE 0062;0061 05AE 1A75 0300 0315 0062;0061 05AE 1A75 0300 0315 0062;0061 05AE 1A75 0300 0315 0062;0061 05AE 1A75 0300 0315 0062; # (a◌᩵◌̕◌̀◌֮b; a◌֮◌᩵◌̀◌̕b; a◌֮◌᩵◌̀◌̕b; a◌֮◌᩵◌̀◌̕b; a◌֮◌᩵◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN TONE-1, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A76 0062;00E0 05AE 1A76 0315 0062;0061 05AE 0300 1A76 0315 0062;00E0 05AE 1A76 0315 0062;0061 05AE 0300 1A76 0315 0062; # (a◌̕◌̀◌֮◌᩶b; à◌֮◌᩶◌̕b; a◌֮◌̀◌᩶◌̕b; à◌֮◌᩶◌̕b; a◌֮◌̀◌᩶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN TONE-2, LATIN SMALL LETTER B +0061 1A76 0315 0300 05AE 0062;0061 05AE 1A76 0300 0315 0062;0061 05AE 1A76 0300 0315 0062;0061 05AE 1A76 0300 0315 0062;0061 05AE 1A76 0300 0315 0062; # (a◌᩶◌̕◌̀◌֮b; a◌֮◌᩶◌̀◌̕b; a◌֮◌᩶◌̀◌̕b; a◌֮◌᩶◌̀◌̕b; a◌֮◌᩶◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN TONE-2, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A77 0062;00E0 05AE 1A77 0315 0062;0061 05AE 0300 1A77 0315 0062;00E0 05AE 1A77 0315 0062;0061 05AE 0300 1A77 0315 0062; # (a◌̕◌̀◌֮◌᩷b; à◌֮◌᩷◌̕b; a◌֮◌̀◌᩷◌̕b; à◌֮◌᩷◌̕b; a◌֮◌̀◌᩷◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN KHUEN TONE-3, LATIN SMALL LETTER B +0061 1A77 0315 0300 05AE 0062;0061 05AE 1A77 0300 0315 0062;0061 05AE 1A77 0300 0315 0062;0061 05AE 1A77 0300 0315 0062;0061 05AE 1A77 0300 0315 0062; # (a◌᩷◌̕◌̀◌֮b; a◌֮◌᩷◌̀◌̕b; a◌֮◌᩷◌̀◌̕b; a◌֮◌᩷◌̀◌̕b; a◌֮◌᩷◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN KHUEN TONE-3, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A78 0062;00E0 05AE 1A78 0315 0062;0061 05AE 0300 1A78 0315 0062;00E0 05AE 1A78 0315 0062;0061 05AE 0300 1A78 0315 0062; # (a◌̕◌̀◌֮◌᩸b; à◌֮◌᩸◌̕b; a◌֮◌̀◌᩸◌̕b; à◌֮◌᩸◌̕b; a◌֮◌̀◌᩸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN KHUEN TONE-4, LATIN SMALL LETTER B +0061 1A78 0315 0300 05AE 0062;0061 05AE 1A78 0300 0315 0062;0061 05AE 1A78 0300 0315 0062;0061 05AE 1A78 0300 0315 0062;0061 05AE 1A78 0300 0315 0062; # (a◌᩸◌̕◌̀◌֮b; a◌֮◌᩸◌̀◌̕b; a◌֮◌᩸◌̀◌̕b; a◌֮◌᩸◌̀◌̕b; a◌֮◌᩸◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN KHUEN TONE-4, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A79 0062;00E0 05AE 1A79 0315 0062;0061 05AE 0300 1A79 0315 0062;00E0 05AE 1A79 0315 0062;0061 05AE 0300 1A79 0315 0062; # (a◌̕◌̀◌֮◌᩹b; à◌֮◌᩹◌̕b; a◌֮◌̀◌᩹◌̕b; à◌֮◌᩹◌̕b; a◌֮◌̀◌᩹◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN KHUEN TONE-5, LATIN SMALL LETTER B +0061 1A79 0315 0300 05AE 0062;0061 05AE 1A79 0300 0315 0062;0061 05AE 1A79 0300 0315 0062;0061 05AE 1A79 0300 0315 0062;0061 05AE 1A79 0300 0315 0062; # (a◌᩹◌̕◌̀◌֮b; a◌֮◌᩹◌̀◌̕b; a◌֮◌᩹◌̀◌̕b; a◌֮◌᩹◌̀◌̕b; a◌֮◌᩹◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN KHUEN TONE-5, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A7A 0062;00E0 05AE 1A7A 0315 0062;0061 05AE 0300 1A7A 0315 0062;00E0 05AE 1A7A 0315 0062;0061 05AE 0300 1A7A 0315 0062; # (a◌̕◌̀◌֮◌᩺b; à◌֮◌᩺◌̕b; a◌֮◌̀◌᩺◌̕b; à◌֮◌᩺◌̕b; a◌֮◌̀◌᩺◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN RA HAAM, LATIN SMALL LETTER B +0061 1A7A 0315 0300 05AE 0062;0061 05AE 1A7A 0300 0315 0062;0061 05AE 1A7A 0300 0315 0062;0061 05AE 1A7A 0300 0315 0062;0061 05AE 1A7A 0300 0315 0062; # (a◌᩺◌̕◌̀◌֮b; a◌֮◌᩺◌̀◌̕b; a◌֮◌᩺◌̀◌̕b; a◌֮◌᩺◌̀◌̕b; a◌֮◌᩺◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN RA HAAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A7B 0062;00E0 05AE 1A7B 0315 0062;0061 05AE 0300 1A7B 0315 0062;00E0 05AE 1A7B 0315 0062;0061 05AE 0300 1A7B 0315 0062; # (a◌̕◌̀◌֮◌᩻b; à◌֮◌᩻◌̕b; a◌֮◌̀◌᩻◌̕b; à◌֮◌᩻◌̕b; a◌֮◌̀◌᩻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN MAI SAM, LATIN SMALL LETTER B +0061 1A7B 0315 0300 05AE 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062; # (a◌᩻◌̕◌̀◌֮b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN MAI SAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1A7C 0062;00E0 05AE 1A7C 0315 0062;0061 05AE 0300 1A7C 0315 0062;00E0 05AE 1A7C 0315 0062;0061 05AE 0300 1A7C 0315 0062; # (a◌̕◌̀◌֮◌᩼b; à◌֮◌᩼◌̕b; a◌֮◌̀◌᩼◌̕b; à◌֮◌᩼◌̕b; a◌֮◌̀◌᩼◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN KHUEN-LUE KARAN, LATIN SMALL LETTER B +0061 1A7C 0315 0300 05AE 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062; # (a◌᩼◌̕◌̀◌֮b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN KHUEN-LUE KARAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1A7F 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062; # (a◌֚◌̖◌᷺◌᩿b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TAI THAM COMBINING CRYPTOGRAMMIC DOT, LATIN SMALL LETTER B +0061 1A7F 059A 0316 1DFA 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062; # (a◌᩿◌֚◌̖◌᷺b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; ) LATIN SMALL LETTER A, TAI THAM COMBINING CRYPTOGRAMMIC DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AB0 0062;00E0 05AE 1AB0 0315 0062;0061 05AE 0300 1AB0 0315 0062;00E0 05AE 1AB0 0315 0062;0061 05AE 0300 1AB0 0315 0062; # (a◌̕◌̀◌֮◌᪰b; à◌֮◌᪰◌̕b; a◌֮◌̀◌᪰◌̕b; à◌֮◌᪰◌̕b; a◌֮◌̀◌᪰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLED CIRCUMFLEX ACCENT, LATIN SMALL LETTER B +0061 1AB0 0315 0300 05AE 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062; # (a◌᪰◌̕◌̀◌֮b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLED CIRCUMFLEX ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AB1 0062;00E0 05AE 1AB1 0315 0062;0061 05AE 0300 1AB1 0315 0062;00E0 05AE 1AB1 0315 0062;0061 05AE 0300 1AB1 0315 0062; # (a◌̕◌̀◌֮◌᪱b; à◌֮◌᪱◌̕b; a◌֮◌̀◌᪱◌̕b; à◌֮◌᪱◌̕b; a◌֮◌̀◌᪱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DIAERESIS-RING, LATIN SMALL LETTER B +0061 1AB1 0315 0300 05AE 0062;0061 05AE 1AB1 0300 0315 0062;0061 05AE 1AB1 0300 0315 0062;0061 05AE 1AB1 0300 0315 0062;0061 05AE 1AB1 0300 0315 0062; # (a◌᪱◌̕◌̀◌֮b; a◌֮◌᪱◌̀◌̕b; a◌֮◌᪱◌̀◌̕b; a◌֮◌᪱◌̀◌̕b; a◌֮◌᪱◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS-RING, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AB2 0062;00E0 05AE 1AB2 0315 0062;0061 05AE 0300 1AB2 0315 0062;00E0 05AE 1AB2 0315 0062;0061 05AE 0300 1AB2 0315 0062; # (a◌̕◌̀◌֮◌᪲b; à◌֮◌᪲◌̕b; a◌֮◌̀◌᪲◌̕b; à◌֮◌᪲◌̕b; a◌֮◌̀◌᪲◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING INFINITY, LATIN SMALL LETTER B +0061 1AB2 0315 0300 05AE 0062;0061 05AE 1AB2 0300 0315 0062;0061 05AE 1AB2 0300 0315 0062;0061 05AE 1AB2 0300 0315 0062;0061 05AE 1AB2 0300 0315 0062; # (a◌᪲◌̕◌̀◌֮b; a◌֮◌᪲◌̀◌̕b; a◌֮◌᪲◌̀◌̕b; a◌֮◌᪲◌̀◌̕b; a◌֮◌᪲◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING INFINITY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AB3 0062;00E0 05AE 1AB3 0315 0062;0061 05AE 0300 1AB3 0315 0062;00E0 05AE 1AB3 0315 0062;0061 05AE 0300 1AB3 0315 0062; # (a◌̕◌̀◌֮◌᪳b; à◌֮◌᪳◌̕b; a◌֮◌̀◌᪳◌̕b; à◌֮◌᪳◌̕b; a◌֮◌̀◌᪳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOWNWARDS ARROW, LATIN SMALL LETTER B +0061 1AB3 0315 0300 05AE 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062; # (a◌᪳◌̕◌̀◌֮b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOWNWARDS ARROW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AB4 0062;00E0 05AE 1AB4 0315 0062;0061 05AE 0300 1AB4 0315 0062;00E0 05AE 1AB4 0315 0062;0061 05AE 0300 1AB4 0315 0062; # (a◌̕◌̀◌֮◌᪴b; à◌֮◌᪴◌̕b; a◌֮◌̀◌᪴◌̕b; à◌֮◌᪴◌̕b; a◌֮◌̀◌᪴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TRIPLE DOT, LATIN SMALL LETTER B +0061 1AB4 0315 0300 05AE 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062; # (a◌᪴◌̕◌̀◌֮b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TRIPLE DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB5 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062; # (a◌֚◌̖◌᷺◌᪵b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING X-X BELOW, LATIN SMALL LETTER B +0061 1AB5 059A 0316 1DFA 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062; # (a◌᪵◌֚◌̖◌᷺b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X-X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB6 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062; # (a◌֚◌̖◌᷺◌᪶b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING WIGGLY LINE BELOW, LATIN SMALL LETTER B +0061 1AB6 059A 0316 1DFA 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062; # (a◌᪶◌֚◌̖◌᷺b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIGGLY LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB7 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062; # (a◌֚◌̖◌᷺◌᪷b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING OPEN MARK BELOW, LATIN SMALL LETTER B +0061 1AB7 059A 0316 1DFA 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062; # (a◌᪷◌֚◌̖◌᷺b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB8 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062; # (a◌֚◌̖◌᷺◌᪸b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE OPEN MARK BELOW, LATIN SMALL LETTER B +0061 1AB8 059A 0316 1DFA 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062; # (a◌᪸◌֚◌̖◌᷺b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB9 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062; # (a◌֚◌̖◌᷺◌᪹b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGHT CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B +0061 1AB9 059A 0316 1DFA 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062; # (a◌᪹◌֚◌̖◌᷺b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGHT CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABA 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062; # (a◌֚◌̖◌᷺◌᪺b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING STRONG CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B +0061 1ABA 059A 0316 1DFA 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062; # (a◌᪺◌֚◌̖◌᷺b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING STRONG CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ABB 0062;00E0 05AE 1ABB 0315 0062;0061 05AE 0300 1ABB 0315 0062;00E0 05AE 1ABB 0315 0062;0061 05AE 0300 1ABB 0315 0062; # (a◌̕◌̀◌֮◌᪻b; à◌֮◌᪻◌̕b; a◌֮◌̀◌᪻◌̕b; à◌֮◌᪻◌̕b; a◌֮◌̀◌᪻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING PARENTHESES ABOVE, LATIN SMALL LETTER B +0061 1ABB 0315 0300 05AE 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062; # (a◌᪻◌̕◌̀◌֮b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING PARENTHESES ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ABC 0062;00E0 05AE 1ABC 0315 0062;0061 05AE 0300 1ABC 0315 0062;00E0 05AE 1ABC 0315 0062;0061 05AE 0300 1ABC 0315 0062; # (a◌̕◌̀◌֮◌᪼b; à◌֮◌᪼◌̕b; a◌֮◌̀◌᪼◌̕b; à◌֮◌᪼◌̕b; a◌֮◌̀◌᪼◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE PARENTHESES ABOVE, LATIN SMALL LETTER B +0061 1ABC 0315 0300 05AE 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062; # (a◌᪼◌̕◌̀◌֮b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PARENTHESES ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABD 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062; # (a◌֚◌̖◌᷺◌᪽b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING PARENTHESES BELOW, LATIN SMALL LETTER B +0061 1ABD 059A 0316 1DFA 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062; # (a◌᪽◌֚◌̖◌᷺b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PARENTHESES BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABF 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062; # (a◌֚◌̖◌᷺◌ᪿb; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER W BELOW, LATIN SMALL LETTER B +0061 1ABF 059A 0316 1DFA 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062; # (a◌ᪿ◌֚◌̖◌᷺b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC0 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062; # (a◌֚◌̖◌᷺◌ᫀb; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER TURNED W BELOW, LATIN SMALL LETTER B +0061 1AC0 059A 0316 1DFA 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062; # (a◌ᫀ◌֚◌̖◌᷺b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER TURNED W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC1 0062;00E0 05AE 1AC1 0315 0062;0061 05AE 0300 1AC1 0315 0062;00E0 05AE 1AC1 0315 0062;0061 05AE 0300 1AC1 0315 0062; # (a◌̕◌̀◌֮◌᫁b; à◌֮◌᫁◌̕b; a◌֮◌̀◌᫁◌̕b; à◌֮◌᫁◌̕b; a◌֮◌̀◌᫁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT PARENTHESIS ABOVE LEFT, LATIN SMALL LETTER B +0061 1AC1 0315 0300 05AE 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062; # (a◌᫁◌̕◌̀◌֮b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT PARENTHESIS ABOVE LEFT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC2 0062;00E0 05AE 1AC2 0315 0062;0061 05AE 0300 1AC2 0315 0062;00E0 05AE 1AC2 0315 0062;0061 05AE 0300 1AC2 0315 0062; # (a◌̕◌̀◌֮◌᫂b; à◌֮◌᫂◌̕b; a◌֮◌̀◌᫂◌̕b; à◌֮◌᫂◌̕b; a◌֮◌̀◌᫂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT PARENTHESIS ABOVE RIGHT, LATIN SMALL LETTER B +0061 1AC2 0315 0300 05AE 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062; # (a◌᫂◌̕◌̀◌֮b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT PARENTHESIS ABOVE RIGHT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC3 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062; # (a◌֚◌̖◌᷺◌᫃b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT PARENTHESIS BELOW LEFT, LATIN SMALL LETTER B +0061 1AC3 059A 0316 1DFA 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062; # (a◌᫃◌֚◌̖◌᷺b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT PARENTHESIS BELOW LEFT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC4 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062; # (a◌֚◌̖◌᷺◌᫄b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT PARENTHESIS BELOW RIGHT, LATIN SMALL LETTER B +0061 1AC4 059A 0316 1DFA 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062; # (a◌᫄◌֚◌̖◌᷺b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT PARENTHESIS BELOW RIGHT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC5 0062;00E0 05AE 1AC5 0315 0062;0061 05AE 0300 1AC5 0315 0062;00E0 05AE 1AC5 0315 0062;0061 05AE 0300 1AC5 0315 0062; # (a◌̕◌̀◌֮◌᫅b; à◌֮◌᫅◌̕b; a◌֮◌̀◌᫅◌̕b; à◌֮◌᫅◌̕b; a◌֮◌̀◌᫅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING SQUARE BRACKETS ABOVE, LATIN SMALL LETTER B +0061 1AC5 0315 0300 05AE 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062; # (a◌᫅◌̕◌̀◌֮b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING SQUARE BRACKETS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC6 0062;00E0 05AE 1AC6 0315 0062;0061 05AE 0300 1AC6 0315 0062;00E0 05AE 1AC6 0315 0062;0061 05AE 0300 1AC6 0315 0062; # (a◌̕◌̀◌֮◌᫆b; à◌֮◌᫆◌̕b; a◌֮◌̀◌᫆◌̕b; à◌֮◌᫆◌̕b; a◌֮◌̀◌᫆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING NUMBER SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC6 0315 0300 05AE 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062; # (a◌᫆◌̕◌̀◌֮b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING NUMBER SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC7 0062;00E0 05AE 1AC7 0315 0062;0061 05AE 0300 1AC7 0315 0062;00E0 05AE 1AC7 0315 0062;0061 05AE 0300 1AC7 0315 0062; # (a◌̕◌̀◌֮◌᫇b; à◌֮◌᫇◌̕b; a◌֮◌̀◌᫇◌̕b; à◌֮◌᫇◌̕b; a◌֮◌̀◌᫇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING INVERTED DOUBLE ARCH ABOVE, LATIN SMALL LETTER B +0061 1AC7 0315 0300 05AE 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062; # (a◌᫇◌̕◌̀◌֮b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC8 0062;00E0 05AE 1AC8 0315 0062;0061 05AE 0300 1AC8 0315 0062;00E0 05AE 1AC8 0315 0062;0061 05AE 0300 1AC8 0315 0062; # (a◌̕◌̀◌֮◌᫈b; à◌֮◌᫈◌̕b; a◌֮◌̀◌᫈◌̕b; à◌֮◌᫈◌̕b; a◌֮◌̀◌᫈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING PLUS SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC8 0315 0300 05AE 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062; # (a◌᫈◌̕◌̀◌֮b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC9 0062;00E0 05AE 1AC9 0315 0062;0061 05AE 0300 1AC9 0315 0062;00E0 05AE 1AC9 0315 0062;0061 05AE 0300 1AC9 0315 0062; # (a◌̕◌̀◌֮◌᫉b; à◌֮◌᫉◌̕b; a◌֮◌̀◌᫉◌̕b; à◌֮◌᫉◌̕b; a◌֮◌̀◌᫉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE PLUS SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC9 0315 0300 05AE 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062; # (a◌᫉◌̕◌̀◌֮b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PLUS SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ACA 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062; # (a◌֚◌̖◌᷺◌᫊b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE PLUS SIGN BELOW, LATIN SMALL LETTER B +0061 1ACA 059A 0316 1DFA 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062; # (a◌᫊◌֚◌̖◌᷺b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACB 0062;00E0 05AE 1ACB 0315 0062;0061 05AE 0300 1ACB 0315 0062;00E0 05AE 1ACB 0315 0062;0061 05AE 0300 1ACB 0315 0062; # (a◌̕◌̀◌֮◌᫋b; à◌֮◌᫋◌̕b; a◌֮◌̀◌᫋◌̕b; à◌֮◌᫋◌̕b; a◌֮◌̀◌᫋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TRIPLE ACUTE ACCENT, LATIN SMALL LETTER B +0061 1ACB 0315 0300 05AE 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062; # (a◌᫋◌̕◌̀◌֮b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TRIPLE ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACC 0062;00E0 05AE 1ACC 0315 0062;0061 05AE 0300 1ACC 0315 0062;00E0 05AE 1ACC 0315 0062;0061 05AE 0300 1ACC 0315 0062; # (a◌̕◌̀◌֮◌ᫌb; à◌֮◌ᫌ◌̕b; a◌֮◌̀◌ᫌ◌̕b; à◌֮◌ᫌ◌̕b; a◌֮◌̀◌ᫌ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR G, LATIN SMALL LETTER B +0061 1ACC 0315 0300 05AE 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062; # (a◌ᫌ◌̕◌̀◌֮b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACD 0062;00E0 05AE 1ACD 0315 0062;0061 05AE 0300 1ACD 0315 0062;00E0 05AE 1ACD 0315 0062;0061 05AE 0300 1ACD 0315 0062; # (a◌̕◌̀◌֮◌ᫍb; à◌֮◌ᫍ◌̕b; a◌֮◌̀◌ᫍ◌̕b; à◌֮◌ᫍ◌̕b; a◌֮◌̀◌ᫍ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR R, LATIN SMALL LETTER B +0061 1ACD 0315 0300 05AE 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062; # (a◌ᫍ◌̕◌̀◌֮b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR R, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACE 0062;00E0 05AE 1ACE 0315 0062;0061 05AE 0300 1ACE 0315 0062;00E0 05AE 1ACE 0315 0062;0061 05AE 0300 1ACE 0315 0062; # (a◌̕◌̀◌֮◌ᫎb; à◌֮◌ᫎ◌̕b; a◌֮◌̀◌ᫎ◌̕b; à◌֮◌ᫎ◌̕b; a◌֮◌̀◌ᫎ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR T, LATIN SMALL LETTER B +0061 1ACE 0315 0300 05AE 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062; # (a◌ᫎ◌̕◌̀◌֮b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR T, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1B34 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062; # (a◌゙◌𖿰़◌᬴b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, BALINESE SIGN REREKAN, LATIN SMALL LETTER B +0061 1B34 3099 093C 16FF0 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062; # (a◌᬴◌゙◌𖿰़b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; ) LATIN SMALL LETTER A, BALINESE SIGN REREKAN, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1B44 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062; # (a◌ְ◌्◌゙᭄b; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BALINESE ADEG ADEG, LATIN SMALL LETTER B +0061 1B44 05B0 094D 3099 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062; # (a᭄◌ְ◌्◌゙b; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; ) LATIN SMALL LETTER A, BALINESE ADEG ADEG, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B6B 0062;00E0 05AE 1B6B 0315 0062;0061 05AE 0300 1B6B 0315 0062;00E0 05AE 1B6B 0315 0062;0061 05AE 0300 1B6B 0315 0062; # (a◌̕◌̀◌֮◌᭫b; à◌֮◌᭫◌̕b; a◌֮◌̀◌᭫◌̕b; à◌֮◌᭫◌̕b; a◌֮◌̀◌᭫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING TEGEH, LATIN SMALL LETTER B +0061 1B6B 0315 0300 05AE 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062; # (a◌᭫◌̕◌̀◌֮b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING TEGEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1B6C 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062; # (a◌֚◌̖◌᷺◌᭬b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, BALINESE MUSICAL SYMBOL COMBINING ENDEP, LATIN SMALL LETTER B +0061 1B6C 059A 0316 1DFA 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062; # (a◌᭬◌֚◌̖◌᷺b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING ENDEP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B6D 0062;00E0 05AE 1B6D 0315 0062;0061 05AE 0300 1B6D 0315 0062;00E0 05AE 1B6D 0315 0062;0061 05AE 0300 1B6D 0315 0062; # (a◌̕◌̀◌֮◌᭭b; à◌֮◌᭭◌̕b; a◌֮◌̀◌᭭◌̕b; à◌֮◌᭭◌̕b; a◌֮◌̀◌᭭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPUL, LATIN SMALL LETTER B +0061 1B6D 0315 0300 05AE 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062; # (a◌᭭◌̕◌̀◌֮b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING KEMPUL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B6E 0062;00E0 05AE 1B6E 0315 0062;0061 05AE 0300 1B6E 0315 0062;00E0 05AE 1B6E 0315 0062;0061 05AE 0300 1B6E 0315 0062; # (a◌̕◌̀◌֮◌᭮b; à◌֮◌᭮◌̕b; a◌֮◌̀◌᭮◌̕b; à◌֮◌᭮◌̕b; a◌֮◌̀◌᭮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPLI, LATIN SMALL LETTER B +0061 1B6E 0315 0300 05AE 0062;0061 05AE 1B6E 0300 0315 0062;0061 05AE 1B6E 0300 0315 0062;0061 05AE 1B6E 0300 0315 0062;0061 05AE 1B6E 0300 0315 0062; # (a◌᭮◌̕◌̀◌֮b; a◌֮◌᭮◌̀◌̕b; a◌֮◌᭮◌̀◌̕b; a◌֮◌᭮◌̀◌̕b; a◌֮◌᭮◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING KEMPLI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B6F 0062;00E0 05AE 1B6F 0315 0062;0061 05AE 0300 1B6F 0315 0062;00E0 05AE 1B6F 0315 0062;0061 05AE 0300 1B6F 0315 0062; # (a◌̕◌̀◌֮◌᭯b; à◌֮◌᭯◌̕b; a◌֮◌̀◌᭯◌̕b; à◌֮◌᭯◌̕b; a◌֮◌̀◌᭯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING JEGOGAN, LATIN SMALL LETTER B +0061 1B6F 0315 0300 05AE 0062;0061 05AE 1B6F 0300 0315 0062;0061 05AE 1B6F 0300 0315 0062;0061 05AE 1B6F 0300 0315 0062;0061 05AE 1B6F 0300 0315 0062; # (a◌᭯◌̕◌̀◌֮b; a◌֮◌᭯◌̀◌̕b; a◌֮◌᭯◌̀◌̕b; a◌֮◌᭯◌̀◌̕b; a◌֮◌᭯◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING JEGOGAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B70 0062;00E0 05AE 1B70 0315 0062;0061 05AE 0300 1B70 0315 0062;00E0 05AE 1B70 0315 0062;0061 05AE 0300 1B70 0315 0062; # (a◌̕◌̀◌֮◌᭰b; à◌֮◌᭰◌̕b; a◌֮◌̀◌᭰◌̕b; à◌֮◌᭰◌̕b; a◌֮◌̀◌᭰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN, LATIN SMALL LETTER B +0061 1B70 0315 0300 05AE 0062;0061 05AE 1B70 0300 0315 0062;0061 05AE 1B70 0300 0315 0062;0061 05AE 1B70 0300 0315 0062;0061 05AE 1B70 0300 0315 0062; # (a◌᭰◌̕◌̀◌֮b; a◌֮◌᭰◌̀◌̕b; a◌֮◌᭰◌̀◌̕b; a◌֮◌᭰◌̀◌̕b; a◌֮◌᭰◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B71 0062;00E0 05AE 1B71 0315 0062;0061 05AE 0300 1B71 0315 0062;00E0 05AE 1B71 0315 0062;0061 05AE 0300 1B71 0315 0062; # (a◌̕◌̀◌֮◌᭱b; à◌֮◌᭱◌̕b; a◌֮◌̀◌᭱◌̕b; à◌֮◌᭱◌̕b; a◌֮◌̀◌᭱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN, LATIN SMALL LETTER B +0061 1B71 0315 0300 05AE 0062;0061 05AE 1B71 0300 0315 0062;0061 05AE 1B71 0300 0315 0062;0061 05AE 1B71 0300 0315 0062;0061 05AE 1B71 0300 0315 0062; # (a◌᭱◌̕◌̀◌֮b; a◌֮◌᭱◌̀◌̕b; a◌֮◌᭱◌̀◌̕b; a◌֮◌᭱◌̀◌̕b; a◌֮◌᭱◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B72 0062;00E0 05AE 1B72 0315 0062;0061 05AE 0300 1B72 0315 0062;00E0 05AE 1B72 0315 0062;0061 05AE 0300 1B72 0315 0062; # (a◌̕◌̀◌֮◌᭲b; à◌֮◌᭲◌̕b; a◌֮◌̀◌᭲◌̕b; à◌֮◌᭲◌̕b; a◌֮◌̀◌᭲◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING BENDE, LATIN SMALL LETTER B +0061 1B72 0315 0300 05AE 0062;0061 05AE 1B72 0300 0315 0062;0061 05AE 1B72 0300 0315 0062;0061 05AE 1B72 0300 0315 0062;0061 05AE 1B72 0300 0315 0062; # (a◌᭲◌̕◌̀◌֮b; a◌֮◌᭲◌̀◌̕b; a◌֮◌᭲◌̀◌̕b; a◌֮◌᭲◌̀◌̕b; a◌֮◌᭲◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING BENDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1B73 0062;00E0 05AE 1B73 0315 0062;0061 05AE 0300 1B73 0315 0062;00E0 05AE 1B73 0315 0062;0061 05AE 0300 1B73 0315 0062; # (a◌̕◌̀◌֮◌᭳b; à◌֮◌᭳◌̕b; a◌֮◌̀◌᭳◌̕b; à◌֮◌᭳◌̕b; a◌֮◌̀◌᭳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING GONG, LATIN SMALL LETTER B +0061 1B73 0315 0300 05AE 0062;0061 05AE 1B73 0300 0315 0062;0061 05AE 1B73 0300 0315 0062;0061 05AE 1B73 0300 0315 0062;0061 05AE 1B73 0300 0315 0062; # (a◌᭳◌̕◌̀◌֮b; a◌֮◌᭳◌̀◌̕b; a◌֮◌᭳◌̀◌̕b; a◌֮◌᭳◌̀◌̕b; a◌֮◌᭳◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING GONG, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 1BAA 0062;0061 3099 094D 1BAA 05B0 0062;0061 3099 094D 1BAA 05B0 0062;0061 3099 094D 1BAA 05B0 0062;0061 3099 094D 1BAA 05B0 0062; # (a◌ְ◌्◌゙᮪b; a◌゙◌्᮪◌ְb; a◌゙◌्᮪◌ְb; a◌゙◌्᮪◌ְb; a◌゙◌्᮪◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SUNDANESE SIGN PAMAAEH, LATIN SMALL LETTER B +0061 1BAA 05B0 094D 3099 0062;0061 3099 1BAA 094D 05B0 0062;0061 3099 1BAA 094D 05B0 0062;0061 3099 1BAA 094D 05B0 0062;0061 3099 1BAA 094D 05B0 0062; # (a᮪◌ְ◌्◌゙b; a◌゙᮪◌्◌ְb; a◌゙᮪◌्◌ְb; a◌゙᮪◌्◌ְb; a◌゙᮪◌्◌ְb; ) LATIN SMALL LETTER A, SUNDANESE SIGN PAMAAEH, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1BAB 0062;0061 3099 094D 1BAB 05B0 0062;0061 3099 094D 1BAB 05B0 0062;0061 3099 094D 1BAB 05B0 0062;0061 3099 094D 1BAB 05B0 0062; # (a◌ְ◌्◌゙◌᮫b; a◌゙◌्◌᮫◌ְb; a◌゙◌्◌᮫◌ְb; a◌゙◌्◌᮫◌ְb; a◌゙◌्◌᮫◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SUNDANESE SIGN VIRAMA, LATIN SMALL LETTER B +0061 1BAB 05B0 094D 3099 0062;0061 3099 1BAB 094D 05B0 0062;0061 3099 1BAB 094D 05B0 0062;0061 3099 1BAB 094D 05B0 0062;0061 3099 1BAB 094D 05B0 0062; # (a◌᮫◌ְ◌्◌゙b; a◌゙◌᮫◌्◌ְb; a◌゙◌᮫◌्◌ְb; a◌゙◌᮫◌्◌ְb; a◌゙◌᮫◌्◌ְb; ) LATIN SMALL LETTER A, SUNDANESE SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1BE6 0062;0061 16FF0 093C 1BE6 3099 0062;0061 16FF0 093C 1BE6 3099 0062;0061 16FF0 093C 1BE6 3099 0062;0061 16FF0 093C 1BE6 3099 0062; # (a◌゙◌𖿰़◌᯦b; a𖿰◌़◌᯦◌゙b; a𖿰◌़◌᯦◌゙b; a𖿰◌़◌᯦◌゙b; a𖿰◌़◌᯦◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, BATAK SIGN TOMPI, LATIN SMALL LETTER B +0061 1BE6 3099 093C 16FF0 0062;0061 16FF0 1BE6 093C 3099 0062;0061 16FF0 1BE6 093C 3099 0062;0061 16FF0 1BE6 093C 3099 0062;0061 16FF0 1BE6 093C 3099 0062; # (a◌᯦◌゙◌𖿰़b; a𖿰◌᯦◌़◌゙b; a𖿰◌᯦◌़◌゙b; a𖿰◌᯦◌़◌゙b; a𖿰◌᯦◌़◌゙b; ) LATIN SMALL LETTER A, BATAK SIGN TOMPI, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1BF2 0062;0061 3099 094D 1BF2 05B0 0062;0061 3099 094D 1BF2 05B0 0062;0061 3099 094D 1BF2 05B0 0062;0061 3099 094D 1BF2 05B0 0062; # (a◌ְ◌्◌゙᯲b; a◌゙◌्᯲◌ְb; a◌゙◌्᯲◌ְb; a◌゙◌्᯲◌ְb; a◌゙◌्᯲◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BATAK PANGOLAT, LATIN SMALL LETTER B +0061 1BF2 05B0 094D 3099 0062;0061 3099 1BF2 094D 05B0 0062;0061 3099 1BF2 094D 05B0 0062;0061 3099 1BF2 094D 05B0 0062;0061 3099 1BF2 094D 05B0 0062; # (a᯲◌ְ◌्◌゙b; a◌゙᯲◌्◌ְb; a◌゙᯲◌्◌ְb; a◌゙᯲◌्◌ְb; a◌゙᯲◌्◌ְb; ) LATIN SMALL LETTER A, BATAK PANGOLAT, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1BF3 0062;0061 3099 094D 1BF3 05B0 0062;0061 3099 094D 1BF3 05B0 0062;0061 3099 094D 1BF3 05B0 0062;0061 3099 094D 1BF3 05B0 0062; # (a◌ְ◌्◌゙᯳b; a◌゙◌्᯳◌ְb; a◌゙◌्᯳◌ְb; a◌゙◌्᯳◌ְb; a◌゙◌्᯳◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BATAK PANONGONAN, LATIN SMALL LETTER B +0061 1BF3 05B0 094D 3099 0062;0061 3099 1BF3 094D 05B0 0062;0061 3099 1BF3 094D 05B0 0062;0061 3099 1BF3 094D 05B0 0062;0061 3099 1BF3 094D 05B0 0062; # (a᯳◌ְ◌्◌゙b; a◌゙᯳◌्◌ְb; a◌゙᯳◌्◌ְb; a◌゙᯳◌्◌ְb; a◌゙᯳◌्◌ְb; ) LATIN SMALL LETTER A, BATAK PANONGONAN, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1C37 0062;0061 16FF0 093C 1C37 3099 0062;0061 16FF0 093C 1C37 3099 0062;0061 16FF0 093C 1C37 3099 0062;0061 16FF0 093C 1C37 3099 0062; # (a◌゙◌𖿰़◌᰷b; a𖿰◌़◌᰷◌゙b; a𖿰◌़◌᰷◌゙b; a𖿰◌़◌᰷◌゙b; a𖿰◌़◌᰷◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LEPCHA SIGN NUKTA, LATIN SMALL LETTER B +0061 1C37 3099 093C 16FF0 0062;0061 16FF0 1C37 093C 3099 0062;0061 16FF0 1C37 093C 3099 0062;0061 16FF0 1C37 093C 3099 0062;0061 16FF0 1C37 093C 3099 0062; # (a◌᰷◌゙◌𖿰़b; a𖿰◌᰷◌़◌゙b; a𖿰◌᰷◌़◌゙b; a𖿰◌᰷◌़◌゙b; a𖿰◌᰷◌़◌゙b; ) LATIN SMALL LETTER A, LEPCHA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CD0 0062;00E0 05AE 1CD0 0315 0062;0061 05AE 0300 1CD0 0315 0062;00E0 05AE 1CD0 0315 0062;0061 05AE 0300 1CD0 0315 0062; # (a◌̕◌̀◌֮◌᳐b; à◌֮◌᳐◌̕b; a◌֮◌̀◌᳐◌̕b; à◌֮◌᳐◌̕b; a◌֮◌̀◌᳐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE KARSHANA, LATIN SMALL LETTER B +0061 1CD0 0315 0300 05AE 0062;0061 05AE 1CD0 0300 0315 0062;0061 05AE 1CD0 0300 0315 0062;0061 05AE 1CD0 0300 0315 0062;0061 05AE 1CD0 0300 0315 0062; # (a◌᳐◌̕◌̀◌֮b; a◌֮◌᳐◌̀◌̕b; a◌֮◌᳐◌̀◌̕b; a◌֮◌᳐◌̀◌̕b; a◌֮◌᳐◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE KARSHANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CD1 0062;00E0 05AE 1CD1 0315 0062;0061 05AE 0300 1CD1 0315 0062;00E0 05AE 1CD1 0315 0062;0061 05AE 0300 1CD1 0315 0062; # (a◌̕◌̀◌֮◌᳑b; à◌֮◌᳑◌̕b; a◌֮◌̀◌᳑◌̕b; à◌֮◌᳑◌̕b; a◌֮◌̀◌᳑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE SHARA, LATIN SMALL LETTER B +0061 1CD1 0315 0300 05AE 0062;0061 05AE 1CD1 0300 0315 0062;0061 05AE 1CD1 0300 0315 0062;0061 05AE 1CD1 0300 0315 0062;0061 05AE 1CD1 0300 0315 0062; # (a◌᳑◌̕◌̀◌֮b; a◌֮◌᳑◌̀◌̕b; a◌֮◌᳑◌̀◌̕b; a◌֮◌᳑◌̀◌̕b; a◌֮◌᳑◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE SHARA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CD2 0062;00E0 05AE 1CD2 0315 0062;0061 05AE 0300 1CD2 0315 0062;00E0 05AE 1CD2 0315 0062;0061 05AE 0300 1CD2 0315 0062; # (a◌̕◌̀◌֮◌᳒b; à◌֮◌᳒◌̕b; a◌֮◌̀◌᳒◌̕b; à◌֮◌᳒◌̕b; a◌֮◌̀◌᳒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE PRENKHA, LATIN SMALL LETTER B +0061 1CD2 0315 0300 05AE 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062; # (a◌᳒◌̕◌̀◌֮b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE PRENKHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 1CD4 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062; # (a𖿰◌̴◌᳔b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN YAJURVEDIC MIDLINE SVARITA, LATIN SMALL LETTER B +0061 1CD4 16FF0 0334 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062; # (a◌᳔𖿰◌̴b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN YAJURVEDIC MIDLINE SVARITA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD5 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062; # (a◌֚◌̖◌᷺◌᳕b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD5 059A 0316 1DFA 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062; # (a◌᳕◌֚◌̖◌᷺b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD6 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062; # (a◌֚◌̖◌᷺◌᳖b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD6 059A 0316 1DFA 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062; # (a◌᳖◌֚◌̖◌᷺b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD7 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062; # (a◌֚◌̖◌᷺◌᳗b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD7 059A 0316 1DFA 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062; # (a◌᳗◌֚◌̖◌᷺b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD8 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062; # (a◌֚◌̖◌᷺◌᳘b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE CANDRA BELOW, LATIN SMALL LETTER B +0061 1CD8 059A 0316 1DFA 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062; # (a◌᳘◌֚◌̖◌᷺b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE CANDRA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD9 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062; # (a◌֚◌̖◌᷺◌᳙b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, LATIN SMALL LETTER B +0061 1CD9 059A 0316 1DFA 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062; # (a◌᳙◌֚◌̖◌᷺b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CDA 0062;00E0 05AE 1CDA 0315 0062;0061 05AE 0300 1CDA 0315 0062;00E0 05AE 1CDA 0315 0062;0061 05AE 0300 1CDA 0315 0062; # (a◌̕◌̀◌֮◌᳚b; à◌֮◌᳚◌̕b; a◌֮◌̀◌᳚◌̕b; à◌֮◌᳚◌̕b; a◌֮◌̀◌᳚◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE DOUBLE SVARITA, LATIN SMALL LETTER B +0061 1CDA 0315 0300 05AE 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062; # (a◌᳚◌̕◌̀◌֮b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE DOUBLE SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CDB 0062;00E0 05AE 1CDB 0315 0062;0061 05AE 0300 1CDB 0315 0062;00E0 05AE 1CDB 0315 0062;0061 05AE 0300 1CDB 0315 0062; # (a◌̕◌̀◌֮◌᳛b; à◌֮◌᳛◌̕b; a◌֮◌̀◌᳛◌̕b; à◌֮◌᳛◌̕b; a◌֮◌̀◌᳛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE TRIPLE SVARITA, LATIN SMALL LETTER B +0061 1CDB 0315 0300 05AE 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062; # (a◌᳛◌̕◌̀◌֮b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE TRIPLE SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDC 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062; # (a◌֚◌̖◌᷺◌᳜b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE KATHAKA ANUDATTA, LATIN SMALL LETTER B +0061 1CDC 059A 0316 1DFA 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062; # (a◌᳜◌֚◌̖◌᷺b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE KATHAKA ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDD 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062; # (a◌֚◌̖◌᷺◌᳝b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE DOT BELOW, LATIN SMALL LETTER B +0061 1CDD 059A 0316 1DFA 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062; # (a◌᳝◌֚◌̖◌᷺b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDE 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062; # (a◌֚◌̖◌᷺◌᳞b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B +0061 1CDE 059A 0316 1DFA 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062; # (a◌᳞◌֚◌̖◌᷺b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDF 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062; # (a◌֚◌̖◌᷺◌᳟b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE THREE DOTS BELOW, LATIN SMALL LETTER B +0061 1CDF 059A 0316 1DFA 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062; # (a◌᳟◌֚◌̖◌᷺b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CE0 0062;00E0 05AE 1CE0 0315 0062;0061 05AE 0300 1CE0 0315 0062;00E0 05AE 1CE0 0315 0062;0061 05AE 0300 1CE0 0315 0062; # (a◌̕◌̀◌֮◌᳠b; à◌֮◌᳠◌̕b; a◌֮◌̀◌᳠◌̕b; à◌֮◌᳠◌̕b; a◌֮◌̀◌᳠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CE0 0315 0300 05AE 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062; # (a◌᳠◌̕◌̀◌֮b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 1CE2 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062; # (a𖿰◌̴◌᳢b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA SVARITA, LATIN SMALL LETTER B +0061 1CE2 16FF0 0334 0062;0061 1CE2 0334 16FF0 0062;0061 1CE2 0334 16FF0 0062;0061 1CE2 0334 16FF0 0062;0061 1CE2 0334 16FF0 0062; # (a◌᳢𖿰◌̴b; a◌᳢◌̴𖿰b; a◌᳢◌̴𖿰b; a◌᳢◌̴𖿰b; a◌᳢◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA SVARITA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE3 0062;0061 0334 1CE3 16FF0 0062;0061 0334 1CE3 16FF0 0062;0061 0334 1CE3 16FF0 0062;0061 0334 1CE3 16FF0 0062; # (a𖿰◌̴◌᳣b; a◌̴◌᳣𖿰b; a◌̴◌᳣𖿰b; a◌̴◌᳣𖿰b; a◌̴◌᳣𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA UDATTA, LATIN SMALL LETTER B +0061 1CE3 16FF0 0334 0062;0061 1CE3 0334 16FF0 0062;0061 1CE3 0334 16FF0 0062;0061 1CE3 0334 16FF0 0062;0061 1CE3 0334 16FF0 0062; # (a◌᳣𖿰◌̴b; a◌᳣◌̴𖿰b; a◌᳣◌̴𖿰b; a◌᳣◌̴𖿰b; a◌᳣◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA UDATTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE4 0062;0061 0334 1CE4 16FF0 0062;0061 0334 1CE4 16FF0 0062;0061 0334 1CE4 16FF0 0062;0061 0334 1CE4 16FF0 0062; # (a𖿰◌̴◌᳤b; a◌̴◌᳤𖿰b; a◌̴◌᳤𖿰b; a◌̴◌᳤𖿰b; a◌̴◌᳤𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN REVERSED VISARGA UDATTA, LATIN SMALL LETTER B +0061 1CE4 16FF0 0334 0062;0061 1CE4 0334 16FF0 0062;0061 1CE4 0334 16FF0 0062;0061 1CE4 0334 16FF0 0062;0061 1CE4 0334 16FF0 0062; # (a◌᳤𖿰◌̴b; a◌᳤◌̴𖿰b; a◌᳤◌̴𖿰b; a◌᳤◌̴𖿰b; a◌᳤◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN REVERSED VISARGA UDATTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE5 0062;0061 0334 1CE5 16FF0 0062;0061 0334 1CE5 16FF0 0062;0061 0334 1CE5 16FF0 0062;0061 0334 1CE5 16FF0 0062; # (a𖿰◌̴◌᳥b; a◌̴◌᳥𖿰b; a◌̴◌᳥𖿰b; a◌̴◌᳥𖿰b; a◌̴◌᳥𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA ANUDATTA, LATIN SMALL LETTER B +0061 1CE5 16FF0 0334 0062;0061 1CE5 0334 16FF0 0062;0061 1CE5 0334 16FF0 0062;0061 1CE5 0334 16FF0 0062;0061 1CE5 0334 16FF0 0062; # (a◌᳥𖿰◌̴b; a◌᳥◌̴𖿰b; a◌᳥◌̴𖿰b; a◌᳥◌̴𖿰b; a◌᳥◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA ANUDATTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE6 0062;0061 0334 1CE6 16FF0 0062;0061 0334 1CE6 16FF0 0062;0061 0334 1CE6 16FF0 0062;0061 0334 1CE6 16FF0 0062; # (a𖿰◌̴◌᳦b; a◌̴◌᳦𖿰b; a◌̴◌᳦𖿰b; a◌̴◌᳦𖿰b; a◌̴◌᳦𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN REVERSED VISARGA ANUDATTA, LATIN SMALL LETTER B +0061 1CE6 16FF0 0334 0062;0061 1CE6 0334 16FF0 0062;0061 1CE6 0334 16FF0 0062;0061 1CE6 0334 16FF0 0062;0061 1CE6 0334 16FF0 0062; # (a◌᳦𖿰◌̴b; a◌᳦◌̴𖿰b; a◌᳦◌̴𖿰b; a◌᳦◌̴𖿰b; a◌᳦◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN REVERSED VISARGA ANUDATTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE7 0062;0061 0334 1CE7 16FF0 0062;0061 0334 1CE7 16FF0 0062;0061 0334 1CE7 16FF0 0062;0061 0334 1CE7 16FF0 0062; # (a𖿰◌̴◌᳧b; a◌̴◌᳧𖿰b; a◌̴◌᳧𖿰b; a◌̴◌᳧𖿰b; a◌̴◌᳧𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA UDATTA WITH TAIL, LATIN SMALL LETTER B +0061 1CE7 16FF0 0334 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062; # (a◌᳧𖿰◌̴b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA UDATTA WITH TAIL, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1CE8 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062; # (a𖿰◌̴◌᳨b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA ANUDATTA WITH TAIL, LATIN SMALL LETTER B +0061 1CE8 16FF0 0334 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062; # (a◌᳨𖿰◌̴b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA ANUDATTA WITH TAIL, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CED 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062; # (a◌֚◌̖◌᷺◌᳭b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC SIGN TIRYAK, LATIN SMALL LETTER B +0061 1CED 059A 0316 1DFA 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062; # (a◌᳭◌֚◌̖◌᷺b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC SIGN TIRYAK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CF4 0062;00E0 05AE 1CF4 0315 0062;0061 05AE 0300 1CF4 0315 0062;00E0 05AE 1CF4 0315 0062;0061 05AE 0300 1CF4 0315 0062; # (a◌̕◌̀◌֮◌᳴b; à◌֮◌᳴◌̕b; a◌֮◌̀◌᳴◌̕b; à◌֮◌᳴◌̕b; a◌֮◌̀◌᳴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE CANDRA ABOVE, LATIN SMALL LETTER B +0061 1CF4 0315 0300 05AE 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062; # (a◌᳴◌̕◌̀◌֮b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE CANDRA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CF8 0062;00E0 05AE 1CF8 0315 0062;0061 05AE 0300 1CF8 0315 0062;00E0 05AE 1CF8 0315 0062;0061 05AE 0300 1CF8 0315 0062; # (a◌̕◌̀◌֮◌᳸b; à◌֮◌᳸◌̕b; a◌֮◌̀◌᳸◌̕b; à◌֮◌᳸◌̕b; a◌֮◌̀◌᳸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE RING ABOVE, LATIN SMALL LETTER B +0061 1CF8 0315 0300 05AE 0062;0061 05AE 1CF8 0300 0315 0062;0061 05AE 1CF8 0300 0315 0062;0061 05AE 1CF8 0300 0315 0062;0061 05AE 1CF8 0300 0315 0062; # (a◌᳸◌̕◌̀◌֮b; a◌֮◌᳸◌̀◌̕b; a◌֮◌᳸◌̀◌̕b; a◌֮◌᳸◌̀◌̕b; a◌֮◌᳸◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1CF9 0062;00E0 05AE 1CF9 0315 0062;0061 05AE 0300 1CF9 0315 0062;00E0 05AE 1CF9 0315 0062;0061 05AE 0300 1CF9 0315 0062; # (a◌̕◌̀◌֮◌᳹b; à◌֮◌᳹◌̕b; a◌֮◌̀◌᳹◌̕b; à◌֮◌᳹◌̕b; a◌֮◌̀◌᳹◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE DOUBLE RING ABOVE, LATIN SMALL LETTER B +0061 1CF9 0315 0300 05AE 0062;0061 05AE 1CF9 0300 0315 0062;0061 05AE 1CF9 0300 0315 0062;0061 05AE 1CF9 0300 0315 0062;0061 05AE 1CF9 0300 0315 0062; # (a◌᳹◌̕◌̀◌֮b; a◌֮◌᳹◌̀◌̕b; a◌֮◌᳹◌̀◌̕b; a◌֮◌᳹◌̀◌̕b; a◌֮◌᳹◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE DOUBLE RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC0 0062;00E0 05AE 1DC0 0315 0062;0061 05AE 0300 1DC0 0315 0062;00E0 05AE 1DC0 0315 0062;0061 05AE 0300 1DC0 0315 0062; # (a◌̕◌̀◌֮◌᷀b; à◌֮◌᷀◌̕b; a◌֮◌̀◌᷀◌̕b; à◌֮◌᷀◌̕b; a◌֮◌̀◌᷀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOTTED GRAVE ACCENT, LATIN SMALL LETTER B +0061 1DC0 0315 0300 05AE 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062; # (a◌᷀◌̕◌̀◌֮b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOTTED GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC1 0062;00E0 05AE 1DC1 0315 0062;0061 05AE 0300 1DC1 0315 0062;00E0 05AE 1DC1 0315 0062;0061 05AE 0300 1DC1 0315 0062; # (a◌̕◌̀◌֮◌᷁b; à◌֮◌᷁◌̕b; a◌֮◌̀◌᷁◌̕b; à◌֮◌᷁◌̕b; a◌֮◌̀◌᷁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOTTED ACUTE ACCENT, LATIN SMALL LETTER B +0061 1DC1 0315 0300 05AE 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062; # (a◌᷁◌̕◌̀◌֮b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOTTED ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DC2 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062; # (a◌֚◌̖◌᷺◌᷂b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SNAKE BELOW, LATIN SMALL LETTER B +0061 1DC2 059A 0316 1DFA 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062; # (a◌᷂◌֚◌̖◌᷺b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SNAKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC3 0062;00E0 05AE 1DC3 0315 0062;0061 05AE 0300 1DC3 0315 0062;00E0 05AE 1DC3 0315 0062;0061 05AE 0300 1DC3 0315 0062; # (a◌̕◌̀◌֮◌᷃b; à◌֮◌᷃◌̕b; a◌֮◌̀◌᷃◌̕b; à◌֮◌᷃◌̕b; a◌֮◌̀◌᷃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING SUSPENSION MARK, LATIN SMALL LETTER B +0061 1DC3 0315 0300 05AE 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062; # (a◌᷃◌̕◌̀◌֮b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING SUSPENSION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC4 0062;00E0 05AE 1DC4 0315 0062;0061 05AE 0300 1DC4 0315 0062;00E0 05AE 1DC4 0315 0062;0061 05AE 0300 1DC4 0315 0062; # (a◌̕◌̀◌֮◌᷄b; à◌֮◌᷄◌̕b; a◌֮◌̀◌᷄◌̕b; à◌֮◌᷄◌̕b; a◌֮◌̀◌᷄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON-ACUTE, LATIN SMALL LETTER B +0061 1DC4 0315 0300 05AE 0062;0061 05AE 1DC4 0300 0315 0062;0061 05AE 1DC4 0300 0315 0062;0061 05AE 1DC4 0300 0315 0062;0061 05AE 1DC4 0300 0315 0062; # (a◌᷄◌̕◌̀◌֮b; a◌֮◌᷄◌̀◌̕b; a◌֮◌᷄◌̀◌̕b; a◌֮◌᷄◌̀◌̕b; a◌֮◌᷄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON-ACUTE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC5 0062;00E0 05AE 1DC5 0315 0062;0061 05AE 0300 1DC5 0315 0062;00E0 05AE 1DC5 0315 0062;0061 05AE 0300 1DC5 0315 0062; # (a◌̕◌̀◌֮◌᷅b; à◌֮◌᷅◌̕b; a◌֮◌̀◌᷅◌̕b; à◌֮◌᷅◌̕b; a◌֮◌̀◌᷅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE-MACRON, LATIN SMALL LETTER B +0061 1DC5 0315 0300 05AE 0062;0061 05AE 1DC5 0300 0315 0062;0061 05AE 1DC5 0300 0315 0062;0061 05AE 1DC5 0300 0315 0062;0061 05AE 1DC5 0300 0315 0062; # (a◌᷅◌̕◌̀◌֮b; a◌֮◌᷅◌̀◌̕b; a◌֮◌᷅◌̀◌̕b; a◌֮◌᷅◌̀◌̕b; a◌֮◌᷅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE-MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC6 0062;00E0 05AE 1DC6 0315 0062;0061 05AE 0300 1DC6 0315 0062;00E0 05AE 1DC6 0315 0062;0061 05AE 0300 1DC6 0315 0062; # (a◌̕◌̀◌֮◌᷆b; à◌֮◌᷆◌̕b; a◌֮◌̀◌᷆◌̕b; à◌֮◌᷆◌̕b; a◌֮◌̀◌᷆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON-GRAVE, LATIN SMALL LETTER B +0061 1DC6 0315 0300 05AE 0062;0061 05AE 1DC6 0300 0315 0062;0061 05AE 1DC6 0300 0315 0062;0061 05AE 1DC6 0300 0315 0062;0061 05AE 1DC6 0300 0315 0062; # (a◌᷆◌̕◌̀◌֮b; a◌֮◌᷆◌̀◌̕b; a◌֮◌᷆◌̀◌̕b; a◌֮◌᷆◌̀◌̕b; a◌֮◌᷆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON-GRAVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC7 0062;00E0 05AE 1DC7 0315 0062;0061 05AE 0300 1DC7 0315 0062;00E0 05AE 1DC7 0315 0062;0061 05AE 0300 1DC7 0315 0062; # (a◌̕◌̀◌֮◌᷇b; à◌֮◌᷇◌̕b; a◌֮◌̀◌᷇◌̕b; à◌֮◌᷇◌̕b; a◌֮◌̀◌᷇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE-MACRON, LATIN SMALL LETTER B +0061 1DC7 0315 0300 05AE 0062;0061 05AE 1DC7 0300 0315 0062;0061 05AE 1DC7 0300 0315 0062;0061 05AE 1DC7 0300 0315 0062;0061 05AE 1DC7 0300 0315 0062; # (a◌᷇◌̕◌̀◌֮b; a◌֮◌᷇◌̀◌̕b; a◌֮◌᷇◌̀◌̕b; a◌֮◌᷇◌̀◌̕b; a◌֮◌᷇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE-MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC8 0062;00E0 05AE 1DC8 0315 0062;0061 05AE 0300 1DC8 0315 0062;00E0 05AE 1DC8 0315 0062;0061 05AE 0300 1DC8 0315 0062; # (a◌̕◌̀◌֮◌᷈b; à◌֮◌᷈◌̕b; a◌֮◌̀◌᷈◌̕b; à◌֮◌᷈◌̕b; a◌֮◌̀◌᷈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRAVE-ACUTE-GRAVE, LATIN SMALL LETTER B +0061 1DC8 0315 0300 05AE 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062; # (a◌᷈◌̕◌̀◌֮b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE-ACUTE-GRAVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DC9 0062;00E0 05AE 1DC9 0315 0062;0061 05AE 0300 1DC9 0315 0062;00E0 05AE 1DC9 0315 0062;0061 05AE 0300 1DC9 0315 0062; # (a◌̕◌̀◌֮◌᷉b; à◌֮◌᷉◌̕b; a◌֮◌̀◌᷉◌̕b; à◌֮◌᷉◌̕b; a◌֮◌̀◌᷉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE-GRAVE-ACUTE, LATIN SMALL LETTER B +0061 1DC9 0315 0300 05AE 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062; # (a◌᷉◌̕◌̀◌֮b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE-GRAVE-ACUTE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DCA 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062; # (a◌֚◌̖◌᷺◌᷊b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER R BELOW, LATIN SMALL LETTER B +0061 1DCA 059A 0316 1DFA 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062; # (a◌᷊◌֚◌̖◌᷺b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DCB 0062;00E0 05AE 1DCB 0315 0062;0061 05AE 0300 1DCB 0315 0062;00E0 05AE 1DCB 0315 0062;0061 05AE 0300 1DCB 0315 0062; # (a◌̕◌̀◌֮◌᷋b; à◌֮◌᷋◌̕b; a◌֮◌̀◌᷋◌̕b; à◌֮◌᷋◌̕b; a◌֮◌̀◌᷋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BREVE-MACRON, LATIN SMALL LETTER B +0061 1DCB 0315 0300 05AE 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062; # (a◌᷋◌̕◌̀◌֮b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BREVE-MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DCC 0062;00E0 05AE 1DCC 0315 0062;0061 05AE 0300 1DCC 0315 0062;00E0 05AE 1DCC 0315 0062;0061 05AE 0300 1DCC 0315 0062; # (a◌̕◌̀◌֮◌᷌b; à◌֮◌᷌◌̕b; a◌֮◌̀◌᷌◌̕b; à◌֮◌᷌◌̕b; a◌֮◌̀◌᷌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON-BREVE, LATIN SMALL LETTER B +0061 1DCC 0315 0300 05AE 0062;0061 05AE 1DCC 0300 0315 0062;0061 05AE 1DCC 0300 0315 0062;0061 05AE 1DCC 0300 0315 0062;0061 05AE 1DCC 0300 0315 0062; # (a◌᷌◌̕◌̀◌֮b; a◌֮◌᷌◌̀◌̕b; a◌֮◌᷌◌̀◌̕b; a◌֮◌᷌◌̀◌̕b; a◌֮◌᷌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON-BREVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0345 035D 035C 1DCD 0062;0061 035C 035D 1DCD 0345 0062;0061 035C 035D 1DCD 0345 0062;0061 035C 035D 1DCD 0345 0062;0061 035C 035D 1DCD 0345 0062; # (a◌ͅ◌͝◌͜◌᷍b; a◌͜◌͝◌᷍◌ͅb; a◌͜◌͝◌᷍◌ͅb; a◌͜◌͝◌᷍◌ͅb; a◌͜◌͝◌᷍◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING DOUBLE CIRCUMFLEX ABOVE, LATIN SMALL LETTER B +0061 1DCD 0345 035D 035C 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062; # (a◌᷍◌ͅ◌͝◌͜b; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE CIRCUMFLEX ABOVE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B +0061 031B 1DCE 0321 1DCE 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062; # (a◌̛◌᷎◌̡◌᷎b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DCE 031B 1DCE 0321 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062; # (a◌᷎◌̛◌᷎◌̡b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DCF 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062; # (a◌֚◌̖◌᷺◌᷏b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ZIGZAG BELOW, LATIN SMALL LETTER B +0061 1DCF 059A 0316 1DFA 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062; # (a◌᷏◌֚◌̖◌᷺b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ZIGZAG BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DCE 0321 0F74 1DD0 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062; # (a◌᷎◌̡◌ུ◌᷐b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING IS BELOW, LATIN SMALL LETTER B +0061 1DD0 1DCE 0321 0F74 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062; # (a◌᷐◌᷎◌̡◌ུb; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING IS BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD1 0062;00E0 05AE 1DD1 0315 0062;0061 05AE 0300 1DD1 0315 0062;00E0 05AE 1DD1 0315 0062;0061 05AE 0300 1DD1 0315 0062; # (a◌̕◌̀◌֮◌᷑b; à◌֮◌᷑◌̕b; a◌֮◌̀◌᷑◌̕b; à◌֮◌᷑◌̕b; a◌֮◌̀◌᷑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING UR ABOVE, LATIN SMALL LETTER B +0061 1DD1 0315 0300 05AE 0062;0061 05AE 1DD1 0300 0315 0062;0061 05AE 1DD1 0300 0315 0062;0061 05AE 1DD1 0300 0315 0062;0061 05AE 1DD1 0300 0315 0062; # (a◌᷑◌̕◌̀◌֮b; a◌֮◌᷑◌̀◌̕b; a◌֮◌᷑◌̀◌̕b; a◌֮◌᷑◌̀◌̕b; a◌֮◌᷑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING UR ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD2 0062;00E0 05AE 1DD2 0315 0062;0061 05AE 0300 1DD2 0315 0062;00E0 05AE 1DD2 0315 0062;0061 05AE 0300 1DD2 0315 0062; # (a◌̕◌̀◌֮◌᷒b; à◌֮◌᷒◌̕b; a◌֮◌̀◌᷒◌̕b; à◌֮◌᷒◌̕b; a◌֮◌̀◌᷒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING US ABOVE, LATIN SMALL LETTER B +0061 1DD2 0315 0300 05AE 0062;0061 05AE 1DD2 0300 0315 0062;0061 05AE 1DD2 0300 0315 0062;0061 05AE 1DD2 0300 0315 0062;0061 05AE 1DD2 0300 0315 0062; # (a◌᷒◌̕◌̀◌֮b; a◌֮◌᷒◌̀◌̕b; a◌֮◌᷒◌̀◌̕b; a◌֮◌᷒◌̀◌̕b; a◌֮◌᷒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING US ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD3 0062;00E0 05AE 1DD3 0315 0062;0061 05AE 0300 1DD3 0315 0062;00E0 05AE 1DD3 0315 0062;0061 05AE 0300 1DD3 0315 0062; # (a◌̕◌̀◌֮◌ᷓb; à◌֮◌ᷓ◌̕b; a◌֮◌̀◌ᷓ◌̕b; à◌֮◌ᷓ◌̕b; a◌֮◌̀◌ᷓ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE, LATIN SMALL LETTER B +0061 1DD3 0315 0300 05AE 0062;0061 05AE 1DD3 0300 0315 0062;0061 05AE 1DD3 0300 0315 0062;0061 05AE 1DD3 0300 0315 0062;0061 05AE 1DD3 0300 0315 0062; # (a◌ᷓ◌̕◌̀◌֮b; a◌֮◌ᷓ◌̀◌̕b; a◌֮◌ᷓ◌̀◌̕b; a◌֮◌ᷓ◌̀◌̕b; a◌֮◌ᷓ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD4 0062;00E0 05AE 1DD4 0315 0062;0061 05AE 0300 1DD4 0315 0062;00E0 05AE 1DD4 0315 0062;0061 05AE 0300 1DD4 0315 0062; # (a◌̕◌̀◌֮◌ᷔb; à◌֮◌ᷔ◌̕b; a◌֮◌̀◌ᷔ◌̕b; à◌֮◌ᷔ◌̕b; a◌֮◌̀◌ᷔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER AE, LATIN SMALL LETTER B +0061 1DD4 0315 0300 05AE 0062;0061 05AE 1DD4 0300 0315 0062;0061 05AE 1DD4 0300 0315 0062;0061 05AE 1DD4 0300 0315 0062;0061 05AE 1DD4 0300 0315 0062; # (a◌ᷔ◌̕◌̀◌֮b; a◌֮◌ᷔ◌̀◌̕b; a◌֮◌ᷔ◌̀◌̕b; a◌֮◌ᷔ◌̀◌̕b; a◌֮◌ᷔ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER AE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD5 0062;00E0 05AE 1DD5 0315 0062;0061 05AE 0300 1DD5 0315 0062;00E0 05AE 1DD5 0315 0062;0061 05AE 0300 1DD5 0315 0062; # (a◌̕◌̀◌֮◌ᷕb; à◌֮◌ᷕ◌̕b; a◌֮◌̀◌ᷕ◌̕b; à◌֮◌ᷕ◌̕b; a◌֮◌̀◌ᷕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER AO, LATIN SMALL LETTER B +0061 1DD5 0315 0300 05AE 0062;0061 05AE 1DD5 0300 0315 0062;0061 05AE 1DD5 0300 0315 0062;0061 05AE 1DD5 0300 0315 0062;0061 05AE 1DD5 0300 0315 0062; # (a◌ᷕ◌̕◌̀◌֮b; a◌֮◌ᷕ◌̀◌̕b; a◌֮◌ᷕ◌̀◌̕b; a◌֮◌ᷕ◌̀◌̕b; a◌֮◌ᷕ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER AO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD6 0062;00E0 05AE 1DD6 0315 0062;0061 05AE 0300 1DD6 0315 0062;00E0 05AE 1DD6 0315 0062;0061 05AE 0300 1DD6 0315 0062; # (a◌̕◌̀◌֮◌ᷖb; à◌֮◌ᷖ◌̕b; a◌֮◌̀◌ᷖ◌̕b; à◌֮◌ᷖ◌̕b; a◌֮◌̀◌ᷖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER AV, LATIN SMALL LETTER B +0061 1DD6 0315 0300 05AE 0062;0061 05AE 1DD6 0300 0315 0062;0061 05AE 1DD6 0300 0315 0062;0061 05AE 1DD6 0300 0315 0062;0061 05AE 1DD6 0300 0315 0062; # (a◌ᷖ◌̕◌̀◌֮b; a◌֮◌ᷖ◌̀◌̕b; a◌֮◌ᷖ◌̀◌̕b; a◌֮◌ᷖ◌̀◌̕b; a◌֮◌ᷖ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER AV, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD7 0062;00E0 05AE 1DD7 0315 0062;0061 05AE 0300 1DD7 0315 0062;00E0 05AE 1DD7 0315 0062;0061 05AE 0300 1DD7 0315 0062; # (a◌̕◌̀◌֮◌ᷗb; à◌֮◌ᷗ◌̕b; a◌֮◌̀◌ᷗ◌̕b; à◌֮◌ᷗ◌̕b; a◌֮◌̀◌ᷗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER C CEDILLA, LATIN SMALL LETTER B +0061 1DD7 0315 0300 05AE 0062;0061 05AE 1DD7 0300 0315 0062;0061 05AE 1DD7 0300 0315 0062;0061 05AE 1DD7 0300 0315 0062;0061 05AE 1DD7 0300 0315 0062; # (a◌ᷗ◌̕◌̀◌֮b; a◌֮◌ᷗ◌̀◌̕b; a◌֮◌ᷗ◌̀◌̕b; a◌֮◌ᷗ◌̀◌̕b; a◌֮◌ᷗ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER C CEDILLA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD8 0062;00E0 05AE 1DD8 0315 0062;0061 05AE 0300 1DD8 0315 0062;00E0 05AE 1DD8 0315 0062;0061 05AE 0300 1DD8 0315 0062; # (a◌̕◌̀◌֮◌ᷘb; à◌֮◌ᷘ◌̕b; a◌֮◌̀◌ᷘ◌̕b; à◌֮◌ᷘ◌̕b; a◌֮◌̀◌ᷘ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR D, LATIN SMALL LETTER B +0061 1DD8 0315 0300 05AE 0062;0061 05AE 1DD8 0300 0315 0062;0061 05AE 1DD8 0300 0315 0062;0061 05AE 1DD8 0300 0315 0062;0061 05AE 1DD8 0300 0315 0062; # (a◌ᷘ◌̕◌̀◌֮b; a◌֮◌ᷘ◌̀◌̕b; a◌֮◌ᷘ◌̀◌̕b; a◌֮◌ᷘ◌̀◌̕b; a◌֮◌ᷘ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR D, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DD9 0062;00E0 05AE 1DD9 0315 0062;0061 05AE 0300 1DD9 0315 0062;00E0 05AE 1DD9 0315 0062;0061 05AE 0300 1DD9 0315 0062; # (a◌̕◌̀◌֮◌ᷙb; à◌֮◌ᷙ◌̕b; a◌֮◌̀◌ᷙ◌̕b; à◌֮◌ᷙ◌̕b; a◌֮◌̀◌ᷙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER ETH, LATIN SMALL LETTER B +0061 1DD9 0315 0300 05AE 0062;0061 05AE 1DD9 0300 0315 0062;0061 05AE 1DD9 0300 0315 0062;0061 05AE 1DD9 0300 0315 0062;0061 05AE 1DD9 0300 0315 0062; # (a◌ᷙ◌̕◌̀◌֮b; a◌֮◌ᷙ◌̀◌̕b; a◌֮◌ᷙ◌̀◌̕b; a◌֮◌ᷙ◌̀◌̕b; a◌֮◌ᷙ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER ETH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDA 0062;00E0 05AE 1DDA 0315 0062;0061 05AE 0300 1DDA 0315 0062;00E0 05AE 1DDA 0315 0062;0061 05AE 0300 1DDA 0315 0062; # (a◌̕◌̀◌֮◌ᷚb; à◌֮◌ᷚ◌̕b; a◌֮◌̀◌ᷚ◌̕b; à◌֮◌ᷚ◌̕b; a◌֮◌̀◌ᷚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER G, LATIN SMALL LETTER B +0061 1DDA 0315 0300 05AE 0062;0061 05AE 1DDA 0300 0315 0062;0061 05AE 1DDA 0300 0315 0062;0061 05AE 1DDA 0300 0315 0062;0061 05AE 1DDA 0300 0315 0062; # (a◌ᷚ◌̕◌̀◌֮b; a◌֮◌ᷚ◌̀◌̕b; a◌֮◌ᷚ◌̀◌̕b; a◌֮◌ᷚ◌̀◌̕b; a◌֮◌ᷚ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDB 0062;00E0 05AE 1DDB 0315 0062;0061 05AE 0300 1DDB 0315 0062;00E0 05AE 1DDB 0315 0062;0061 05AE 0300 1DDB 0315 0062; # (a◌̕◌̀◌֮◌ᷛb; à◌֮◌ᷛ◌̕b; a◌֮◌̀◌ᷛ◌̕b; à◌֮◌ᷛ◌̕b; a◌֮◌̀◌ᷛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN LETTER SMALL CAPITAL G, LATIN SMALL LETTER B +0061 1DDB 0315 0300 05AE 0062;0061 05AE 1DDB 0300 0315 0062;0061 05AE 1DDB 0300 0315 0062;0061 05AE 1DDB 0300 0315 0062;0061 05AE 1DDB 0300 0315 0062; # (a◌ᷛ◌̕◌̀◌֮b; a◌֮◌ᷛ◌̀◌̕b; a◌֮◌ᷛ◌̀◌̕b; a◌֮◌ᷛ◌̀◌̕b; a◌֮◌ᷛ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN LETTER SMALL CAPITAL G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDC 0062;00E0 05AE 1DDC 0315 0062;0061 05AE 0300 1DDC 0315 0062;00E0 05AE 1DDC 0315 0062;0061 05AE 0300 1DDC 0315 0062; # (a◌̕◌̀◌֮◌ᷜb; à◌֮◌ᷜ◌̕b; a◌֮◌̀◌ᷜ◌̕b; à◌֮◌ᷜ◌̕b; a◌֮◌̀◌ᷜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER K, LATIN SMALL LETTER B +0061 1DDC 0315 0300 05AE 0062;0061 05AE 1DDC 0300 0315 0062;0061 05AE 1DDC 0300 0315 0062;0061 05AE 1DDC 0300 0315 0062;0061 05AE 1DDC 0300 0315 0062; # (a◌ᷜ◌̕◌̀◌֮b; a◌֮◌ᷜ◌̀◌̕b; a◌֮◌ᷜ◌̀◌̕b; a◌֮◌ᷜ◌̀◌̕b; a◌֮◌ᷜ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER K, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDD 0062;00E0 05AE 1DDD 0315 0062;0061 05AE 0300 1DDD 0315 0062;00E0 05AE 1DDD 0315 0062;0061 05AE 0300 1DDD 0315 0062; # (a◌̕◌̀◌֮◌ᷝb; à◌֮◌ᷝ◌̕b; a◌֮◌̀◌ᷝ◌̕b; à◌֮◌ᷝ◌̕b; a◌֮◌̀◌ᷝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER L, LATIN SMALL LETTER B +0061 1DDD 0315 0300 05AE 0062;0061 05AE 1DDD 0300 0315 0062;0061 05AE 1DDD 0300 0315 0062;0061 05AE 1DDD 0300 0315 0062;0061 05AE 1DDD 0300 0315 0062; # (a◌ᷝ◌̕◌̀◌֮b; a◌֮◌ᷝ◌̀◌̕b; a◌֮◌ᷝ◌̀◌̕b; a◌֮◌ᷝ◌̀◌̕b; a◌֮◌ᷝ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER L, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDE 0062;00E0 05AE 1DDE 0315 0062;0061 05AE 0300 1DDE 0315 0062;00E0 05AE 1DDE 0315 0062;0061 05AE 0300 1DDE 0315 0062; # (a◌̕◌̀◌֮◌ᷞb; à◌֮◌ᷞ◌̕b; a◌֮◌̀◌ᷞ◌̕b; à◌֮◌ᷞ◌̕b; a◌֮◌̀◌ᷞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN LETTER SMALL CAPITAL L, LATIN SMALL LETTER B +0061 1DDE 0315 0300 05AE 0062;0061 05AE 1DDE 0300 0315 0062;0061 05AE 1DDE 0300 0315 0062;0061 05AE 1DDE 0300 0315 0062;0061 05AE 1DDE 0300 0315 0062; # (a◌ᷞ◌̕◌̀◌֮b; a◌֮◌ᷞ◌̀◌̕b; a◌֮◌ᷞ◌̀◌̕b; a◌֮◌ᷞ◌̀◌̕b; a◌֮◌ᷞ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN LETTER SMALL CAPITAL L, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DDF 0062;00E0 05AE 1DDF 0315 0062;0061 05AE 0300 1DDF 0315 0062;00E0 05AE 1DDF 0315 0062;0061 05AE 0300 1DDF 0315 0062; # (a◌̕◌̀◌֮◌ᷟb; à◌֮◌ᷟ◌̕b; a◌֮◌̀◌ᷟ◌̕b; à◌֮◌ᷟ◌̕b; a◌֮◌̀◌ᷟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN LETTER SMALL CAPITAL M, LATIN SMALL LETTER B +0061 1DDF 0315 0300 05AE 0062;0061 05AE 1DDF 0300 0315 0062;0061 05AE 1DDF 0300 0315 0062;0061 05AE 1DDF 0300 0315 0062;0061 05AE 1DDF 0300 0315 0062; # (a◌ᷟ◌̕◌̀◌֮b; a◌֮◌ᷟ◌̀◌̕b; a◌֮◌ᷟ◌̀◌̕b; a◌֮◌ᷟ◌̀◌̕b; a◌֮◌ᷟ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN LETTER SMALL CAPITAL M, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE0 0062;00E0 05AE 1DE0 0315 0062;0061 05AE 0300 1DE0 0315 0062;00E0 05AE 1DE0 0315 0062;0061 05AE 0300 1DE0 0315 0062; # (a◌̕◌̀◌֮◌ᷠb; à◌֮◌ᷠ◌̕b; a◌֮◌̀◌ᷠ◌̕b; à◌֮◌ᷠ◌̕b; a◌֮◌̀◌ᷠ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER N, LATIN SMALL LETTER B +0061 1DE0 0315 0300 05AE 0062;0061 05AE 1DE0 0300 0315 0062;0061 05AE 1DE0 0300 0315 0062;0061 05AE 1DE0 0300 0315 0062;0061 05AE 1DE0 0300 0315 0062; # (a◌ᷠ◌̕◌̀◌֮b; a◌֮◌ᷠ◌̀◌̕b; a◌֮◌ᷠ◌̀◌̕b; a◌֮◌ᷠ◌̀◌̕b; a◌֮◌ᷠ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER N, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE1 0062;00E0 05AE 1DE1 0315 0062;0061 05AE 0300 1DE1 0315 0062;00E0 05AE 1DE1 0315 0062;0061 05AE 0300 1DE1 0315 0062; # (a◌̕◌̀◌֮◌ᷡb; à◌֮◌ᷡ◌̕b; a◌֮◌̀◌ᷡ◌̕b; à◌֮◌ᷡ◌̕b; a◌֮◌̀◌ᷡ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN LETTER SMALL CAPITAL N, LATIN SMALL LETTER B +0061 1DE1 0315 0300 05AE 0062;0061 05AE 1DE1 0300 0315 0062;0061 05AE 1DE1 0300 0315 0062;0061 05AE 1DE1 0300 0315 0062;0061 05AE 1DE1 0300 0315 0062; # (a◌ᷡ◌̕◌̀◌֮b; a◌֮◌ᷡ◌̀◌̕b; a◌֮◌ᷡ◌̀◌̕b; a◌֮◌ᷡ◌̀◌̕b; a◌֮◌ᷡ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN LETTER SMALL CAPITAL N, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE2 0062;00E0 05AE 1DE2 0315 0062;0061 05AE 0300 1DE2 0315 0062;00E0 05AE 1DE2 0315 0062;0061 05AE 0300 1DE2 0315 0062; # (a◌̕◌̀◌֮◌ᷢb; à◌֮◌ᷢ◌̕b; a◌֮◌̀◌ᷢ◌̕b; à◌֮◌ᷢ◌̕b; a◌֮◌̀◌ᷢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN LETTER SMALL CAPITAL R, LATIN SMALL LETTER B +0061 1DE2 0315 0300 05AE 0062;0061 05AE 1DE2 0300 0315 0062;0061 05AE 1DE2 0300 0315 0062;0061 05AE 1DE2 0300 0315 0062;0061 05AE 1DE2 0300 0315 0062; # (a◌ᷢ◌̕◌̀◌֮b; a◌֮◌ᷢ◌̀◌̕b; a◌֮◌ᷢ◌̀◌̕b; a◌֮◌ᷢ◌̀◌̕b; a◌֮◌ᷢ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN LETTER SMALL CAPITAL R, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE3 0062;00E0 05AE 1DE3 0315 0062;0061 05AE 0300 1DE3 0315 0062;00E0 05AE 1DE3 0315 0062;0061 05AE 0300 1DE3 0315 0062; # (a◌̕◌̀◌֮◌ᷣb; à◌֮◌ᷣ◌̕b; a◌֮◌̀◌ᷣ◌̕b; à◌֮◌ᷣ◌̕b; a◌֮◌̀◌ᷣ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER R ROTUNDA, LATIN SMALL LETTER B +0061 1DE3 0315 0300 05AE 0062;0061 05AE 1DE3 0300 0315 0062;0061 05AE 1DE3 0300 0315 0062;0061 05AE 1DE3 0300 0315 0062;0061 05AE 1DE3 0300 0315 0062; # (a◌ᷣ◌̕◌̀◌֮b; a◌֮◌ᷣ◌̀◌̕b; a◌֮◌ᷣ◌̀◌̕b; a◌֮◌ᷣ◌̀◌̕b; a◌֮◌ᷣ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R ROTUNDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE4 0062;00E0 05AE 1DE4 0315 0062;0061 05AE 0300 1DE4 0315 0062;00E0 05AE 1DE4 0315 0062;0061 05AE 0300 1DE4 0315 0062; # (a◌̕◌̀◌֮◌ᷤb; à◌֮◌ᷤ◌̕b; a◌֮◌̀◌ᷤ◌̕b; à◌֮◌ᷤ◌̕b; a◌֮◌̀◌ᷤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER S, LATIN SMALL LETTER B +0061 1DE4 0315 0300 05AE 0062;0061 05AE 1DE4 0300 0315 0062;0061 05AE 1DE4 0300 0315 0062;0061 05AE 1DE4 0300 0315 0062;0061 05AE 1DE4 0300 0315 0062; # (a◌ᷤ◌̕◌̀◌֮b; a◌֮◌ᷤ◌̀◌̕b; a◌֮◌ᷤ◌̀◌̕b; a◌֮◌ᷤ◌̀◌̕b; a◌֮◌ᷤ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER S, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE5 0062;00E0 05AE 1DE5 0315 0062;0061 05AE 0300 1DE5 0315 0062;00E0 05AE 1DE5 0315 0062;0061 05AE 0300 1DE5 0315 0062; # (a◌̕◌̀◌֮◌ᷥb; à◌֮◌ᷥ◌̕b; a◌֮◌̀◌ᷥ◌̕b; à◌֮◌ᷥ◌̕b; a◌֮◌̀◌ᷥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER LONG S, LATIN SMALL LETTER B +0061 1DE5 0315 0300 05AE 0062;0061 05AE 1DE5 0300 0315 0062;0061 05AE 1DE5 0300 0315 0062;0061 05AE 1DE5 0300 0315 0062;0061 05AE 1DE5 0300 0315 0062; # (a◌ᷥ◌̕◌̀◌֮b; a◌֮◌ᷥ◌̀◌̕b; a◌֮◌ᷥ◌̀◌̕b; a◌֮◌ᷥ◌̀◌̕b; a◌֮◌ᷥ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER LONG S, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE6 0062;00E0 05AE 1DE6 0315 0062;0061 05AE 0300 1DE6 0315 0062;00E0 05AE 1DE6 0315 0062;0061 05AE 0300 1DE6 0315 0062; # (a◌̕◌̀◌֮◌ᷦb; à◌֮◌ᷦ◌̕b; a◌֮◌̀◌ᷦ◌̕b; à◌֮◌ᷦ◌̕b; a◌֮◌̀◌ᷦ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER Z, LATIN SMALL LETTER B +0061 1DE6 0315 0300 05AE 0062;0061 05AE 1DE6 0300 0315 0062;0061 05AE 1DE6 0300 0315 0062;0061 05AE 1DE6 0300 0315 0062;0061 05AE 1DE6 0300 0315 0062; # (a◌ᷦ◌̕◌̀◌֮b; a◌֮◌ᷦ◌̀◌̕b; a◌֮◌ᷦ◌̀◌̕b; a◌֮◌ᷦ◌̀◌̕b; a◌֮◌ᷦ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER Z, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE7 0062;00E0 05AE 1DE7 0315 0062;0061 05AE 0300 1DE7 0315 0062;00E0 05AE 1DE7 0315 0062;0061 05AE 0300 1DE7 0315 0062; # (a◌̕◌̀◌֮◌ᷧb; à◌֮◌ᷧ◌̕b; a◌֮◌̀◌ᷧ◌̕b; à◌֮◌ᷧ◌̕b; a◌֮◌̀◌ᷧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER ALPHA, LATIN SMALL LETTER B +0061 1DE7 0315 0300 05AE 0062;0061 05AE 1DE7 0300 0315 0062;0061 05AE 1DE7 0300 0315 0062;0061 05AE 1DE7 0300 0315 0062;0061 05AE 1DE7 0300 0315 0062; # (a◌ᷧ◌̕◌̀◌֮b; a◌֮◌ᷧ◌̀◌̕b; a◌֮◌ᷧ◌̀◌̕b; a◌֮◌ᷧ◌̀◌̕b; a◌֮◌ᷧ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER ALPHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE8 0062;00E0 05AE 1DE8 0315 0062;0061 05AE 0300 1DE8 0315 0062;00E0 05AE 1DE8 0315 0062;0061 05AE 0300 1DE8 0315 0062; # (a◌̕◌̀◌֮◌ᷨb; à◌֮◌ᷨ◌̕b; a◌֮◌̀◌ᷨ◌̕b; à◌֮◌ᷨ◌̕b; a◌֮◌̀◌ᷨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER B, LATIN SMALL LETTER B +0061 1DE8 0315 0300 05AE 0062;0061 05AE 1DE8 0300 0315 0062;0061 05AE 1DE8 0300 0315 0062;0061 05AE 1DE8 0300 0315 0062;0061 05AE 1DE8 0300 0315 0062; # (a◌ᷨ◌̕◌̀◌֮b; a◌֮◌ᷨ◌̀◌̕b; a◌֮◌ᷨ◌̀◌̕b; a◌֮◌ᷨ◌̀◌̕b; a◌֮◌ᷨ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER B, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DE9 0062;00E0 05AE 1DE9 0315 0062;0061 05AE 0300 1DE9 0315 0062;00E0 05AE 1DE9 0315 0062;0061 05AE 0300 1DE9 0315 0062; # (a◌̕◌̀◌֮◌ᷩb; à◌֮◌ᷩ◌̕b; a◌֮◌̀◌ᷩ◌̕b; à◌֮◌ᷩ◌̕b; a◌֮◌̀◌ᷩ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER BETA, LATIN SMALL LETTER B +0061 1DE9 0315 0300 05AE 0062;0061 05AE 1DE9 0300 0315 0062;0061 05AE 1DE9 0300 0315 0062;0061 05AE 1DE9 0300 0315 0062;0061 05AE 1DE9 0300 0315 0062; # (a◌ᷩ◌̕◌̀◌֮b; a◌֮◌ᷩ◌̀◌̕b; a◌֮◌ᷩ◌̀◌̕b; a◌֮◌ᷩ◌̀◌̕b; a◌֮◌ᷩ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER BETA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DEA 0062;00E0 05AE 1DEA 0315 0062;0061 05AE 0300 1DEA 0315 0062;00E0 05AE 1DEA 0315 0062;0061 05AE 0300 1DEA 0315 0062; # (a◌̕◌̀◌֮◌ᷪb; à◌֮◌ᷪ◌̕b; a◌֮◌̀◌ᷪ◌̕b; à◌֮◌ᷪ◌̕b; a◌֮◌̀◌ᷪ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER SCHWA, LATIN SMALL LETTER B +0061 1DEA 0315 0300 05AE 0062;0061 05AE 1DEA 0300 0315 0062;0061 05AE 1DEA 0300 0315 0062;0061 05AE 1DEA 0300 0315 0062;0061 05AE 1DEA 0300 0315 0062; # (a◌ᷪ◌̕◌̀◌֮b; a◌֮◌ᷪ◌̀◌̕b; a◌֮◌ᷪ◌̀◌̕b; a◌֮◌ᷪ◌̀◌̕b; a◌֮◌ᷪ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER SCHWA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DEB 0062;00E0 05AE 1DEB 0315 0062;0061 05AE 0300 1DEB 0315 0062;00E0 05AE 1DEB 0315 0062;0061 05AE 0300 1DEB 0315 0062; # (a◌̕◌̀◌֮◌ᷫb; à◌֮◌ᷫ◌̕b; a◌֮◌̀◌ᷫ◌̕b; à◌֮◌ᷫ◌̕b; a◌֮◌̀◌ᷫ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER F, LATIN SMALL LETTER B +0061 1DEB 0315 0300 05AE 0062;0061 05AE 1DEB 0300 0315 0062;0061 05AE 1DEB 0300 0315 0062;0061 05AE 1DEB 0300 0315 0062;0061 05AE 1DEB 0300 0315 0062; # (a◌ᷫ◌̕◌̀◌֮b; a◌֮◌ᷫ◌̀◌̕b; a◌֮◌ᷫ◌̀◌̕b; a◌֮◌ᷫ◌̀◌̕b; a◌֮◌ᷫ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER F, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DEC 0062;00E0 05AE 1DEC 0315 0062;0061 05AE 0300 1DEC 0315 0062;00E0 05AE 1DEC 0315 0062;0061 05AE 0300 1DEC 0315 0062; # (a◌̕◌̀◌֮◌ᷬb; à◌֮◌ᷬ◌̕b; a◌֮◌̀◌ᷬ◌̕b; à◌֮◌ᷬ◌̕b; a◌֮◌̀◌ᷬ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE, LATIN SMALL LETTER B +0061 1DEC 0315 0300 05AE 0062;0061 05AE 1DEC 0300 0315 0062;0061 05AE 1DEC 0300 0315 0062;0061 05AE 1DEC 0300 0315 0062;0061 05AE 1DEC 0300 0315 0062; # (a◌ᷬ◌̕◌̀◌֮b; a◌֮◌ᷬ◌̀◌̕b; a◌֮◌ᷬ◌̀◌̕b; a◌֮◌ᷬ◌̀◌̕b; a◌֮◌ᷬ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DED 0062;00E0 05AE 1DED 0315 0062;0061 05AE 0300 1DED 0315 0062;00E0 05AE 1DED 0315 0062;0061 05AE 0300 1DED 0315 0062; # (a◌̕◌̀◌֮◌ᷭb; à◌֮◌ᷭ◌̕b; a◌֮◌̀◌ᷭ◌̕b; à◌֮◌ᷭ◌̕b; a◌֮◌̀◌ᷭ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE, LATIN SMALL LETTER B +0061 1DED 0315 0300 05AE 0062;0061 05AE 1DED 0300 0315 0062;0061 05AE 1DED 0300 0315 0062;0061 05AE 1DED 0300 0315 0062;0061 05AE 1DED 0300 0315 0062; # (a◌ᷭ◌̕◌̀◌֮b; a◌֮◌ᷭ◌̀◌̕b; a◌֮◌ᷭ◌̀◌̕b; a◌֮◌ᷭ◌̀◌̕b; a◌֮◌ᷭ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DEE 0062;00E0 05AE 1DEE 0315 0062;0061 05AE 0300 1DEE 0315 0062;00E0 05AE 1DEE 0315 0062;0061 05AE 0300 1DEE 0315 0062; # (a◌̕◌̀◌֮◌ᷮb; à◌֮◌ᷮ◌̕b; a◌֮◌̀◌ᷮ◌̕b; à◌֮◌ᷮ◌̕b; a◌֮◌̀◌ᷮ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER P, LATIN SMALL LETTER B +0061 1DEE 0315 0300 05AE 0062;0061 05AE 1DEE 0300 0315 0062;0061 05AE 1DEE 0300 0315 0062;0061 05AE 1DEE 0300 0315 0062;0061 05AE 1DEE 0300 0315 0062; # (a◌ᷮ◌̕◌̀◌֮b; a◌֮◌ᷮ◌̀◌̕b; a◌֮◌ᷮ◌̀◌̕b; a◌֮◌ᷮ◌̀◌̕b; a◌֮◌ᷮ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER P, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DEF 0062;00E0 05AE 1DEF 0315 0062;0061 05AE 0300 1DEF 0315 0062;00E0 05AE 1DEF 0315 0062;0061 05AE 0300 1DEF 0315 0062; # (a◌̕◌̀◌֮◌ᷯb; à◌֮◌ᷯ◌̕b; a◌֮◌̀◌ᷯ◌̕b; à◌֮◌ᷯ◌̕b; a◌֮◌̀◌ᷯ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER ESH, LATIN SMALL LETTER B +0061 1DEF 0315 0300 05AE 0062;0061 05AE 1DEF 0300 0315 0062;0061 05AE 1DEF 0300 0315 0062;0061 05AE 1DEF 0300 0315 0062;0061 05AE 1DEF 0300 0315 0062; # (a◌ᷯ◌̕◌̀◌֮b; a◌֮◌ᷯ◌̀◌̕b; a◌֮◌ᷯ◌̀◌̕b; a◌֮◌ᷯ◌̀◌̕b; a◌֮◌ᷯ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER ESH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF0 0062;00E0 05AE 1DF0 0315 0062;0061 05AE 0300 1DF0 0315 0062;00E0 05AE 1DF0 0315 0062;0061 05AE 0300 1DF0 0315 0062; # (a◌̕◌̀◌֮◌ᷰb; à◌֮◌ᷰ◌̕b; a◌֮◌̀◌ᷰ◌̕b; à◌֮◌ᷰ◌̕b; a◌֮◌̀◌ᷰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE, LATIN SMALL LETTER B +0061 1DF0 0315 0300 05AE 0062;0061 05AE 1DF0 0300 0315 0062;0061 05AE 1DF0 0300 0315 0062;0061 05AE 1DF0 0300 0315 0062;0061 05AE 1DF0 0300 0315 0062; # (a◌ᷰ◌̕◌̀◌֮b; a◌֮◌ᷰ◌̀◌̕b; a◌֮◌ᷰ◌̀◌̕b; a◌֮◌ᷰ◌̀◌̕b; a◌֮◌ᷰ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF1 0062;00E0 05AE 1DF1 0315 0062;0061 05AE 0300 1DF1 0315 0062;00E0 05AE 1DF1 0315 0062;0061 05AE 0300 1DF1 0315 0062; # (a◌̕◌̀◌֮◌ᷱb; à◌֮◌ᷱ◌̕b; a◌֮◌̀◌ᷱ◌̕b; à◌֮◌ᷱ◌̕b; a◌֮◌̀◌ᷱ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER W, LATIN SMALL LETTER B +0061 1DF1 0315 0300 05AE 0062;0061 05AE 1DF1 0300 0315 0062;0061 05AE 1DF1 0300 0315 0062;0061 05AE 1DF1 0300 0315 0062;0061 05AE 1DF1 0300 0315 0062; # (a◌ᷱ◌̕◌̀◌֮b; a◌֮◌ᷱ◌̀◌̕b; a◌֮◌ᷱ◌̀◌̕b; a◌֮◌ᷱ◌̀◌̕b; a◌֮◌ᷱ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER W, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF2 0062;00E0 05AE 1DF2 0315 0062;0061 05AE 0300 1DF2 0315 0062;00E0 05AE 1DF2 0315 0062;0061 05AE 0300 1DF2 0315 0062; # (a◌̕◌̀◌֮◌ᷲb; à◌֮◌ᷲ◌̕b; a◌֮◌̀◌ᷲ◌̕b; à◌֮◌ᷲ◌̕b; a◌֮◌̀◌ᷲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER A WITH DIAERESIS, LATIN SMALL LETTER B +0061 1DF2 0315 0300 05AE 0062;0061 05AE 1DF2 0300 0315 0062;0061 05AE 1DF2 0300 0315 0062;0061 05AE 1DF2 0300 0315 0062;0061 05AE 1DF2 0300 0315 0062; # (a◌ᷲ◌̕◌̀◌֮b; a◌֮◌ᷲ◌̀◌̕b; a◌֮◌ᷲ◌̀◌̕b; a◌֮◌ᷲ◌̀◌̕b; a◌֮◌ᷲ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER A WITH DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF3 0062;00E0 05AE 1DF3 0315 0062;0061 05AE 0300 1DF3 0315 0062;00E0 05AE 1DF3 0315 0062;0061 05AE 0300 1DF3 0315 0062; # (a◌̕◌̀◌֮◌ᷳb; à◌֮◌ᷳ◌̕b; a◌֮◌̀◌ᷳ◌̕b; à◌֮◌ᷳ◌̕b; a◌֮◌̀◌ᷳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER O WITH DIAERESIS, LATIN SMALL LETTER B +0061 1DF3 0315 0300 05AE 0062;0061 05AE 1DF3 0300 0315 0062;0061 05AE 1DF3 0300 0315 0062;0061 05AE 1DF3 0300 0315 0062;0061 05AE 1DF3 0300 0315 0062; # (a◌ᷳ◌̕◌̀◌֮b; a◌֮◌ᷳ◌̀◌̕b; a◌֮◌ᷳ◌̀◌̕b; a◌֮◌ᷳ◌̀◌̕b; a◌֮◌ᷳ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER O WITH DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF4 0062;00E0 05AE 1DF4 0315 0062;0061 05AE 0300 1DF4 0315 0062;00E0 05AE 1DF4 0315 0062;0061 05AE 0300 1DF4 0315 0062; # (a◌̕◌̀◌֮◌ᷴb; à◌֮◌ᷴ◌̕b; a◌֮◌̀◌ᷴ◌̕b; à◌֮◌ᷴ◌̕b; a◌֮◌̀◌ᷴ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER U WITH DIAERESIS, LATIN SMALL LETTER B +0061 1DF4 0315 0300 05AE 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062; # (a◌ᷴ◌̕◌̀◌֮b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U WITH DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DF5 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062; # (a◌̕◌̀◌֮◌᷵b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING UP TACK ABOVE, LATIN SMALL LETTER B +0061 1DF5 0315 0300 05AE 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062; # (a◌᷵◌̕◌̀◌֮b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING UP TACK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035C 0315 0300 1DF6 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062; # (a◌͜◌̕◌̀◌᷶b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING KAVYKA ABOVE RIGHT, LATIN SMALL LETTER B +0061 1DF6 035C 0315 0300 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062; # (a◌᷶◌͜◌̕◌̀b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 1DF7 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062; # (a◌̀◌𝅭֮◌᷷b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING KAVYKA ABOVE LEFT, LATIN SMALL LETTER B +0061 1DF7 0300 05AE 1D16D 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062; # (a◌᷷◌̀◌𝅭֮b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 1DF8 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062; # (a◌̀◌𝅭֮◌᷸b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING DOT ABOVE LEFT, LATIN SMALL LETTER B +0061 1DF8 0300 05AE 1D16D 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062; # (a◌᷸◌̀◌𝅭֮b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DF9 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062; # (a◌֚◌̖◌᷺◌᷹b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING WIDE INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 1DF9 059A 0316 1DFA 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062; # (a◌᷹◌֚◌̖◌᷺b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIDE INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0316 1DFA 031B 1DFA 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062; # (a◌̖◌᷺◌̛◌᷺b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DFA 0316 1DFA 031B 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062; # (a◌᷺◌̖◌᷺◌̛b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DFB 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062; # (a◌̕◌̀◌֮◌᷻b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DELETION MARK, LATIN SMALL LETTER B +0061 1DFB 0315 0300 05AE 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062; # (a◌᷻◌̕◌̀◌֮b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DELETION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035D 035C 0315 1DFC 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062; # (a◌͝◌͜◌̕◌᷼b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE INVERTED BREVE BELOW, LATIN SMALL LETTER B +0061 1DFC 035D 035C 0315 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062; # (a◌᷼◌͝◌͜◌̕b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE INVERTED BREVE BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DFD 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062; # (a◌֚◌̖◌᷺◌᷽b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ALMOST EQUAL TO BELOW, LATIN SMALL LETTER B +0061 1DFD 059A 0316 1DFA 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062; # (a◌᷽◌֚◌̖◌᷺b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DFE 0062;00E0 05AE 1DFE 0315 0062;0061 05AE 0300 1DFE 0315 0062;00E0 05AE 1DFE 0315 0062;0061 05AE 0300 1DFE 0315 0062; # (a◌̕◌̀◌֮◌᷾b; à◌֮◌᷾◌̕b; a◌֮◌̀◌᷾◌̕b; à◌֮◌᷾◌̕b; a◌֮◌̀◌᷾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT ARROWHEAD ABOVE, LATIN SMALL LETTER B +0061 1DFE 0315 0300 05AE 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062; # (a◌᷾◌̕◌̀◌֮b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DFF 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062; # (a◌֚◌̖◌᷺◌᷿b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 1DFF 059A 0316 1DFA 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062; # (a◌᷿◌֚◌̖◌᷺b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D0 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062; # (a◌̕◌̀◌֮◌⃐b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT HARPOON ABOVE, LATIN SMALL LETTER B +0061 20D0 0315 0300 05AE 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062; # (a◌⃐◌̕◌̀◌֮b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT HARPOON ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D1 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062; # (a◌̕◌̀◌֮◌⃑b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT HARPOON ABOVE, LATIN SMALL LETTER B +0061 20D1 0315 0300 05AE 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062;0061 05AE 20D1 0300 0315 0062; # (a◌⃑◌̕◌̀◌֮b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; a◌֮◌⃑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT HARPOON ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 20D2 0062;0061 0334 20D2 16FF0 0062;0061 0334 20D2 16FF0 0062;0061 0334 20D2 16FF0 0062;0061 0334 20D2 16FF0 0062; # (a𖿰◌̴◌⃒b; a◌̴◌⃒𖿰b; a◌̴◌⃒𖿰b; a◌̴◌⃒𖿰b; a◌̴◌⃒𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG VERTICAL LINE OVERLAY, LATIN SMALL LETTER B +0061 20D2 16FF0 0334 0062;0061 20D2 0334 16FF0 0062;0061 20D2 0334 16FF0 0062;0061 20D2 0334 16FF0 0062;0061 20D2 0334 16FF0 0062; # (a◌⃒𖿰◌̴b; a◌⃒◌̴𖿰b; a◌⃒◌̴𖿰b; a◌⃒◌̴𖿰b; a◌⃒◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG VERTICAL LINE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 20D3 0062;0061 0334 20D3 16FF0 0062;0061 0334 20D3 16FF0 0062;0061 0334 20D3 16FF0 0062;0061 0334 20D3 16FF0 0062; # (a𖿰◌̴◌⃓b; a◌̴◌⃓𖿰b; a◌̴◌⃓𖿰b; a◌̴◌⃓𖿰b; a◌̴◌⃓𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING SHORT VERTICAL LINE OVERLAY, LATIN SMALL LETTER B +0061 20D3 16FF0 0334 0062;0061 20D3 0334 16FF0 0062;0061 20D3 0334 16FF0 0062;0061 20D3 0334 16FF0 0062;0061 20D3 0334 16FF0 0062; # (a◌⃓𖿰◌̴b; a◌⃓◌̴𖿰b; a◌⃓◌̴𖿰b; a◌⃓◌̴𖿰b; a◌⃓◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING SHORT VERTICAL LINE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D4 0062;00E0 05AE 20D4 0315 0062;0061 05AE 0300 20D4 0315 0062;00E0 05AE 20D4 0315 0062;0061 05AE 0300 20D4 0315 0062; # (a◌̕◌̀◌֮◌⃔b; à◌֮◌⃔◌̕b; a◌֮◌̀◌⃔◌̕b; à◌֮◌⃔◌̕b; a◌֮◌̀◌⃔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ANTICLOCKWISE ARROW ABOVE, LATIN SMALL LETTER B +0061 20D4 0315 0300 05AE 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062;0061 05AE 20D4 0300 0315 0062; # (a◌⃔◌̕◌̀◌֮b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; a◌֮◌⃔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ANTICLOCKWISE ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D5 0062;00E0 05AE 20D5 0315 0062;0061 05AE 0300 20D5 0315 0062;00E0 05AE 20D5 0315 0062;0061 05AE 0300 20D5 0315 0062; # (a◌̕◌̀◌֮◌⃕b; à◌֮◌⃕◌̕b; a◌֮◌̀◌⃕◌̕b; à◌֮◌⃕◌̕b; a◌֮◌̀◌⃕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CLOCKWISE ARROW ABOVE, LATIN SMALL LETTER B +0061 20D5 0315 0300 05AE 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062;0061 05AE 20D5 0300 0315 0062; # (a◌⃕◌̕◌̀◌֮b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; a◌֮◌⃕◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CLOCKWISE ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D6 0062;00E0 05AE 20D6 0315 0062;0061 05AE 0300 20D6 0315 0062;00E0 05AE 20D6 0315 0062;0061 05AE 0300 20D6 0315 0062; # (a◌̕◌̀◌֮◌⃖b; à◌֮◌⃖◌̕b; a◌֮◌̀◌⃖◌̕b; à◌֮◌⃖◌̕b; a◌֮◌̀◌⃖◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT ARROW ABOVE, LATIN SMALL LETTER B +0061 20D6 0315 0300 05AE 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062;0061 05AE 20D6 0300 0315 0062; # (a◌⃖◌̕◌̀◌֮b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; a◌֮◌⃖◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20D7 0062;00E0 05AE 20D7 0315 0062;0061 05AE 0300 20D7 0315 0062;00E0 05AE 20D7 0315 0062;0061 05AE 0300 20D7 0315 0062; # (a◌̕◌̀◌֮◌⃗b; à◌֮◌⃗◌̕b; a◌֮◌̀◌⃗◌̕b; à◌֮◌⃗◌̕b; a◌֮◌̀◌⃗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT ARROW ABOVE, LATIN SMALL LETTER B +0061 20D7 0315 0300 05AE 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062;0061 05AE 20D7 0300 0315 0062; # (a◌⃗◌̕◌̀◌֮b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; a◌֮◌⃗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 20D8 0062;0061 0334 20D8 16FF0 0062;0061 0334 20D8 16FF0 0062;0061 0334 20D8 16FF0 0062;0061 0334 20D8 16FF0 0062; # (a𖿰◌̴◌⃘b; a◌̴◌⃘𖿰b; a◌̴◌⃘𖿰b; a◌̴◌⃘𖿰b; a◌̴◌⃘𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING RING OVERLAY, LATIN SMALL LETTER B +0061 20D8 16FF0 0334 0062;0061 20D8 0334 16FF0 0062;0061 20D8 0334 16FF0 0062;0061 20D8 0334 16FF0 0062;0061 20D8 0334 16FF0 0062; # (a◌⃘𖿰◌̴b; a◌⃘◌̴𖿰b; a◌⃘◌̴𖿰b; a◌⃘◌̴𖿰b; a◌⃘◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING RING OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 20D9 0062;0061 0334 20D9 16FF0 0062;0061 0334 20D9 16FF0 0062;0061 0334 20D9 16FF0 0062;0061 0334 20D9 16FF0 0062; # (a𖿰◌̴◌⃙b; a◌̴◌⃙𖿰b; a◌̴◌⃙𖿰b; a◌̴◌⃙𖿰b; a◌̴◌⃙𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING CLOCKWISE RING OVERLAY, LATIN SMALL LETTER B +0061 20D9 16FF0 0334 0062;0061 20D9 0334 16FF0 0062;0061 20D9 0334 16FF0 0062;0061 20D9 0334 16FF0 0062;0061 20D9 0334 16FF0 0062; # (a◌⃙𖿰◌̴b; a◌⃙◌̴𖿰b; a◌⃙◌̴𖿰b; a◌⃙◌̴𖿰b; a◌⃙◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING CLOCKWISE RING OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 20DA 0062;0061 0334 20DA 16FF0 0062;0061 0334 20DA 16FF0 0062;0061 0334 20DA 16FF0 0062;0061 0334 20DA 16FF0 0062; # (a𖿰◌̴◌⃚b; a◌̴◌⃚𖿰b; a◌̴◌⃚𖿰b; a◌̴◌⃚𖿰b; a◌̴◌⃚𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING ANTICLOCKWISE RING OVERLAY, LATIN SMALL LETTER B +0061 20DA 16FF0 0334 0062;0061 20DA 0334 16FF0 0062;0061 20DA 0334 16FF0 0062;0061 20DA 0334 16FF0 0062;0061 20DA 0334 16FF0 0062; # (a◌⃚𖿰◌̴b; a◌⃚◌̴𖿰b; a◌⃚◌̴𖿰b; a◌⃚◌̴𖿰b; a◌⃚◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING ANTICLOCKWISE RING OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20DB 0062;00E0 05AE 20DB 0315 0062;0061 05AE 0300 20DB 0315 0062;00E0 05AE 20DB 0315 0062;0061 05AE 0300 20DB 0315 0062; # (a◌̕◌̀◌֮◌⃛b; à◌֮◌⃛◌̕b; a◌֮◌̀◌⃛◌̕b; à◌֮◌⃛◌̕b; a◌֮◌̀◌⃛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING THREE DOTS ABOVE, LATIN SMALL LETTER B +0061 20DB 0315 0300 05AE 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062;0061 05AE 20DB 0300 0315 0062; # (a◌⃛◌̕◌̀◌֮b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; a◌֮◌⃛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING THREE DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20DC 0062;00E0 05AE 20DC 0315 0062;0061 05AE 0300 20DC 0315 0062;00E0 05AE 20DC 0315 0062;0061 05AE 0300 20DC 0315 0062; # (a◌̕◌̀◌֮◌⃜b; à◌֮◌⃜◌̕b; a◌֮◌̀◌⃜◌̕b; à◌֮◌⃜◌̕b; a◌֮◌̀◌⃜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING FOUR DOTS ABOVE, LATIN SMALL LETTER B +0061 20DC 0315 0300 05AE 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062;0061 05AE 20DC 0300 0315 0062; # (a◌⃜◌̕◌̀◌֮b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; a◌֮◌⃜◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING FOUR DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E1 0062;00E0 05AE 20E1 0315 0062;0061 05AE 0300 20E1 0315 0062;00E0 05AE 20E1 0315 0062;0061 05AE 0300 20E1 0315 0062; # (a◌̕◌̀◌֮◌⃡b; à◌֮◌⃡◌̕b; a◌֮◌̀◌⃡◌̕b; à◌֮◌⃡◌̕b; a◌֮◌̀◌⃡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT RIGHT ARROW ABOVE, LATIN SMALL LETTER B +0061 20E1 0315 0300 05AE 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062;0061 05AE 20E1 0300 0315 0062; # (a◌⃡◌̕◌̀◌֮b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; a◌֮◌⃡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 20E5 0062;0061 0334 20E5 16FF0 0062;0061 0334 20E5 16FF0 0062;0061 0334 20E5 16FF0 0062;0061 0334 20E5 16FF0 0062; # (a𖿰◌̴◌⃥b; a◌̴◌⃥𖿰b; a◌̴◌⃥𖿰b; a◌̴◌⃥𖿰b; a◌̴◌⃥𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING REVERSE SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 20E5 16FF0 0334 0062;0061 20E5 0334 16FF0 0062;0061 20E5 0334 16FF0 0062;0061 20E5 0334 16FF0 0062;0061 20E5 0334 16FF0 0062; # (a◌⃥𖿰◌̴b; a◌⃥◌̴𖿰b; a◌⃥◌̴𖿰b; a◌⃥◌̴𖿰b; a◌⃥◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING REVERSE SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 20E6 0062;0061 0334 20E6 16FF0 0062;0061 0334 20E6 16FF0 0062;0061 0334 20E6 16FF0 0062;0061 0334 20E6 16FF0 0062; # (a𖿰◌̴◌⃦b; a◌̴◌⃦𖿰b; a◌̴◌⃦𖿰b; a◌̴◌⃦𖿰b; a◌̴◌⃦𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING DOUBLE VERTICAL STROKE OVERLAY, LATIN SMALL LETTER B +0061 20E6 16FF0 0334 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062; # (a◌⃦𖿰◌̴b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL STROKE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E7 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062; # (a◌̕◌̀◌֮◌⃧b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ANNUITY SYMBOL, LATIN SMALL LETTER B +0061 20E7 0315 0300 05AE 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062; # (a◌⃧◌̕◌̀◌֮b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ANNUITY SYMBOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20E8 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062; # (a◌֚◌̖◌᷺◌⃨b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TRIPLE UNDERDOT, LATIN SMALL LETTER B +0061 20E8 059A 0316 1DFA 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062; # (a◌⃨◌֚◌̖◌᷺b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TRIPLE UNDERDOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 20E9 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062; # (a◌̕◌̀◌֮◌⃩b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING WIDE BRIDGE ABOVE, LATIN SMALL LETTER B +0061 20E9 0315 0300 05AE 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062; # (a◌⃩◌̕◌̀◌֮b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING WIDE BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 20EA 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062; # (a𖿰◌̴◌⃪b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LEFTWARDS ARROW OVERLAY, LATIN SMALL LETTER B +0061 20EA 16FF0 0334 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062; # (a◌⃪𖿰◌̴b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS ARROW OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 20EB 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062; # (a𖿰◌̴◌⃫b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG DOUBLE SOLIDUS OVERLAY, LATIN SMALL LETTER B +0061 20EB 16FF0 0334 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062; # (a◌⃫𖿰◌̴b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG DOUBLE SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EC 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062; # (a◌֚◌̖◌᷺◌⃬b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B +0061 20EC 059A 0316 1DFA 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062; # (a◌⃬◌֚◌̖◌᷺b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20ED 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062; # (a◌֚◌̖◌᷺◌⃭b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B +0061 20ED 059A 0316 1DFA 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062; # (a◌⃭◌֚◌̖◌᷺b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EE 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062; # (a◌֚◌̖◌᷺◌⃮b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ARROW BELOW, LATIN SMALL LETTER B +0061 20EE 059A 0316 1DFA 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062; # (a◌⃮◌֚◌̖◌᷺b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EF 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062; # (a◌֚◌̖◌᷺◌⃯b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROW BELOW, LATIN SMALL LETTER B +0061 20EF 059A 0316 1DFA 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062; # (a◌⃯◌֚◌̖◌᷺b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 20F0 0062;00E0 05AE 20F0 0315 0062;0061 05AE 0300 20F0 0315 0062;00E0 05AE 20F0 0315 0062;0061 05AE 0300 20F0 0315 0062; # (a◌̕◌̀◌֮◌⃰b; à◌֮◌⃰◌̕b; a◌֮◌̀◌⃰◌̕b; à◌֮◌⃰◌̕b; a◌֮◌̀◌⃰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ASTERISK ABOVE, LATIN SMALL LETTER B +0061 20F0 0315 0300 05AE 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062; # (a◌⃰◌̕◌̀◌֮b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ASTERISK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2CEF 0062;00E0 05AE 2CEF 0315 0062;0061 05AE 0300 2CEF 0315 0062;00E0 05AE 2CEF 0315 0062;0061 05AE 0300 2CEF 0315 0062; # (a◌̕◌̀◌֮◌⳯b; à◌֮◌⳯◌̕b; a◌֮◌̀◌⳯◌̕b; à◌֮◌⳯◌̕b; a◌֮◌̀◌⳯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COPTIC COMBINING NI ABOVE, LATIN SMALL LETTER B +0061 2CEF 0315 0300 05AE 0062;0061 05AE 2CEF 0300 0315 0062;0061 05AE 2CEF 0300 0315 0062;0061 05AE 2CEF 0300 0315 0062;0061 05AE 2CEF 0300 0315 0062; # (a◌⳯◌̕◌̀◌֮b; a◌֮◌⳯◌̀◌̕b; a◌֮◌⳯◌̀◌̕b; a◌֮◌⳯◌̀◌̕b; a◌֮◌⳯◌̀◌̕b; ) LATIN SMALL LETTER A, COPTIC COMBINING NI ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2CF0 0062;00E0 05AE 2CF0 0315 0062;0061 05AE 0300 2CF0 0315 0062;00E0 05AE 2CF0 0315 0062;0061 05AE 0300 2CF0 0315 0062; # (a◌̕◌̀◌֮◌⳰b; à◌֮◌⳰◌̕b; a◌֮◌̀◌⳰◌̕b; à◌֮◌⳰◌̕b; a◌֮◌̀◌⳰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COPTIC COMBINING SPIRITUS ASPER, LATIN SMALL LETTER B +0061 2CF0 0315 0300 05AE 0062;0061 05AE 2CF0 0300 0315 0062;0061 05AE 2CF0 0300 0315 0062;0061 05AE 2CF0 0300 0315 0062;0061 05AE 2CF0 0300 0315 0062; # (a◌⳰◌̕◌̀◌֮b; a◌֮◌⳰◌̀◌̕b; a◌֮◌⳰◌̀◌̕b; a◌֮◌⳰◌̀◌̕b; a◌֮◌⳰◌̀◌̕b; ) LATIN SMALL LETTER A, COPTIC COMBINING SPIRITUS ASPER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2CF1 0062;00E0 05AE 2CF1 0315 0062;0061 05AE 0300 2CF1 0315 0062;00E0 05AE 2CF1 0315 0062;0061 05AE 0300 2CF1 0315 0062; # (a◌̕◌̀◌֮◌⳱b; à◌֮◌⳱◌̕b; a◌֮◌̀◌⳱◌̕b; à◌֮◌⳱◌̕b; a◌֮◌̀◌⳱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COPTIC COMBINING SPIRITUS LENIS, LATIN SMALL LETTER B +0061 2CF1 0315 0300 05AE 0062;0061 05AE 2CF1 0300 0315 0062;0061 05AE 2CF1 0300 0315 0062;0061 05AE 2CF1 0300 0315 0062;0061 05AE 2CF1 0300 0315 0062; # (a◌⳱◌̕◌̀◌֮b; a◌֮◌⳱◌̀◌̕b; a◌֮◌⳱◌̀◌̕b; a◌֮◌⳱◌̀◌̕b; a◌֮◌⳱◌̀◌̕b; ) LATIN SMALL LETTER A, COPTIC COMBINING SPIRITUS LENIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 2D7F 0062;0061 3099 094D 2D7F 05B0 0062;0061 3099 094D 2D7F 05B0 0062;0061 3099 094D 2D7F 05B0 0062;0061 3099 094D 2D7F 05B0 0062; # (a◌ְ◌्◌゙◌⵿b; a◌゙◌्◌⵿◌ְb; a◌゙◌्◌⵿◌ְb; a◌゙◌्◌⵿◌ְb; a◌゙◌्◌⵿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIFINAGH CONSONANT JOINER, LATIN SMALL LETTER B +0061 2D7F 05B0 094D 3099 0062;0061 3099 2D7F 094D 05B0 0062;0061 3099 2D7F 094D 05B0 0062;0061 3099 2D7F 094D 05B0 0062;0061 3099 2D7F 094D 05B0 0062; # (a◌⵿◌ְ◌्◌゙b; a◌゙◌⵿◌्◌ְb; a◌゙◌⵿◌्◌ְb; a◌゙◌⵿◌्◌ְb; a◌゙◌⵿◌्◌ְb; ) LATIN SMALL LETTER A, TIFINAGH CONSONANT JOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE0 0062;00E0 05AE 2DE0 0315 0062;0061 05AE 0300 2DE0 0315 0062;00E0 05AE 2DE0 0315 0062;0061 05AE 0300 2DE0 0315 0062; # (a◌̕◌̀◌֮◌ⷠb; à◌֮◌ⷠ◌̕b; a◌֮◌̀◌ⷠ◌̕b; à◌֮◌ⷠ◌̕b; a◌֮◌̀◌ⷠ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER BE, LATIN SMALL LETTER B +0061 2DE0 0315 0300 05AE 0062;0061 05AE 2DE0 0300 0315 0062;0061 05AE 2DE0 0300 0315 0062;0061 05AE 2DE0 0300 0315 0062;0061 05AE 2DE0 0300 0315 0062; # (a◌ⷠ◌̕◌̀◌֮b; a◌֮◌ⷠ◌̀◌̕b; a◌֮◌ⷠ◌̀◌̕b; a◌֮◌ⷠ◌̀◌̕b; a◌֮◌ⷠ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER BE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE1 0062;00E0 05AE 2DE1 0315 0062;0061 05AE 0300 2DE1 0315 0062;00E0 05AE 2DE1 0315 0062;0061 05AE 0300 2DE1 0315 0062; # (a◌̕◌̀◌֮◌ⷡb; à◌֮◌ⷡ◌̕b; a◌֮◌̀◌ⷡ◌̕b; à◌֮◌ⷡ◌̕b; a◌֮◌̀◌ⷡ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER VE, LATIN SMALL LETTER B +0061 2DE1 0315 0300 05AE 0062;0061 05AE 2DE1 0300 0315 0062;0061 05AE 2DE1 0300 0315 0062;0061 05AE 2DE1 0300 0315 0062;0061 05AE 2DE1 0300 0315 0062; # (a◌ⷡ◌̕◌̀◌֮b; a◌֮◌ⷡ◌̀◌̕b; a◌֮◌ⷡ◌̀◌̕b; a◌֮◌ⷡ◌̀◌̕b; a◌֮◌ⷡ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER VE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE2 0062;00E0 05AE 2DE2 0315 0062;0061 05AE 0300 2DE2 0315 0062;00E0 05AE 2DE2 0315 0062;0061 05AE 0300 2DE2 0315 0062; # (a◌̕◌̀◌֮◌ⷢb; à◌֮◌ⷢ◌̕b; a◌֮◌̀◌ⷢ◌̕b; à◌֮◌ⷢ◌̕b; a◌֮◌̀◌ⷢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER GHE, LATIN SMALL LETTER B +0061 2DE2 0315 0300 05AE 0062;0061 05AE 2DE2 0300 0315 0062;0061 05AE 2DE2 0300 0315 0062;0061 05AE 2DE2 0300 0315 0062;0061 05AE 2DE2 0300 0315 0062; # (a◌ⷢ◌̕◌̀◌֮b; a◌֮◌ⷢ◌̀◌̕b; a◌֮◌ⷢ◌̀◌̕b; a◌֮◌ⷢ◌̀◌̕b; a◌֮◌ⷢ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER GHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE3 0062;00E0 05AE 2DE3 0315 0062;0061 05AE 0300 2DE3 0315 0062;00E0 05AE 2DE3 0315 0062;0061 05AE 0300 2DE3 0315 0062; # (a◌̕◌̀◌֮◌ⷣb; à◌֮◌ⷣ◌̕b; a◌֮◌̀◌ⷣ◌̕b; à◌֮◌ⷣ◌̕b; a◌֮◌̀◌ⷣ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER DE, LATIN SMALL LETTER B +0061 2DE3 0315 0300 05AE 0062;0061 05AE 2DE3 0300 0315 0062;0061 05AE 2DE3 0300 0315 0062;0061 05AE 2DE3 0300 0315 0062;0061 05AE 2DE3 0300 0315 0062; # (a◌ⷣ◌̕◌̀◌֮b; a◌֮◌ⷣ◌̀◌̕b; a◌֮◌ⷣ◌̀◌̕b; a◌֮◌ⷣ◌̀◌̕b; a◌֮◌ⷣ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER DE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE4 0062;00E0 05AE 2DE4 0315 0062;0061 05AE 0300 2DE4 0315 0062;00E0 05AE 2DE4 0315 0062;0061 05AE 0300 2DE4 0315 0062; # (a◌̕◌̀◌֮◌ⷤb; à◌֮◌ⷤ◌̕b; a◌֮◌̀◌ⷤ◌̕b; à◌֮◌ⷤ◌̕b; a◌֮◌̀◌ⷤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER ZHE, LATIN SMALL LETTER B +0061 2DE4 0315 0300 05AE 0062;0061 05AE 2DE4 0300 0315 0062;0061 05AE 2DE4 0300 0315 0062;0061 05AE 2DE4 0300 0315 0062;0061 05AE 2DE4 0300 0315 0062; # (a◌ⷤ◌̕◌̀◌֮b; a◌֮◌ⷤ◌̀◌̕b; a◌֮◌ⷤ◌̀◌̕b; a◌֮◌ⷤ◌̀◌̕b; a◌֮◌ⷤ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER ZHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE5 0062;00E0 05AE 2DE5 0315 0062;0061 05AE 0300 2DE5 0315 0062;00E0 05AE 2DE5 0315 0062;0061 05AE 0300 2DE5 0315 0062; # (a◌̕◌̀◌֮◌ⷥb; à◌֮◌ⷥ◌̕b; a◌֮◌̀◌ⷥ◌̕b; à◌֮◌ⷥ◌̕b; a◌֮◌̀◌ⷥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER ZE, LATIN SMALL LETTER B +0061 2DE5 0315 0300 05AE 0062;0061 05AE 2DE5 0300 0315 0062;0061 05AE 2DE5 0300 0315 0062;0061 05AE 2DE5 0300 0315 0062;0061 05AE 2DE5 0300 0315 0062; # (a◌ⷥ◌̕◌̀◌֮b; a◌֮◌ⷥ◌̀◌̕b; a◌֮◌ⷥ◌̀◌̕b; a◌֮◌ⷥ◌̀◌̕b; a◌֮◌ⷥ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER ZE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE6 0062;00E0 05AE 2DE6 0315 0062;0061 05AE 0300 2DE6 0315 0062;00E0 05AE 2DE6 0315 0062;0061 05AE 0300 2DE6 0315 0062; # (a◌̕◌̀◌֮◌ⷦb; à◌֮◌ⷦ◌̕b; a◌֮◌̀◌ⷦ◌̕b; à◌֮◌ⷦ◌̕b; a◌֮◌̀◌ⷦ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER KA, LATIN SMALL LETTER B +0061 2DE6 0315 0300 05AE 0062;0061 05AE 2DE6 0300 0315 0062;0061 05AE 2DE6 0300 0315 0062;0061 05AE 2DE6 0300 0315 0062;0061 05AE 2DE6 0300 0315 0062; # (a◌ⷦ◌̕◌̀◌֮b; a◌֮◌ⷦ◌̀◌̕b; a◌֮◌ⷦ◌̀◌̕b; a◌֮◌ⷦ◌̀◌̕b; a◌֮◌ⷦ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER KA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE7 0062;00E0 05AE 2DE7 0315 0062;0061 05AE 0300 2DE7 0315 0062;00E0 05AE 2DE7 0315 0062;0061 05AE 0300 2DE7 0315 0062; # (a◌̕◌̀◌֮◌ⷧb; à◌֮◌ⷧ◌̕b; a◌֮◌̀◌ⷧ◌̕b; à◌֮◌ⷧ◌̕b; a◌֮◌̀◌ⷧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER EL, LATIN SMALL LETTER B +0061 2DE7 0315 0300 05AE 0062;0061 05AE 2DE7 0300 0315 0062;0061 05AE 2DE7 0300 0315 0062;0061 05AE 2DE7 0300 0315 0062;0061 05AE 2DE7 0300 0315 0062; # (a◌ⷧ◌̕◌̀◌֮b; a◌֮◌ⷧ◌̀◌̕b; a◌֮◌ⷧ◌̀◌̕b; a◌֮◌ⷧ◌̀◌̕b; a◌֮◌ⷧ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER EL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE8 0062;00E0 05AE 2DE8 0315 0062;0061 05AE 0300 2DE8 0315 0062;00E0 05AE 2DE8 0315 0062;0061 05AE 0300 2DE8 0315 0062; # (a◌̕◌̀◌֮◌ⷨb; à◌֮◌ⷨ◌̕b; a◌֮◌̀◌ⷨ◌̕b; à◌֮◌ⷨ◌̕b; a◌֮◌̀◌ⷨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER EM, LATIN SMALL LETTER B +0061 2DE8 0315 0300 05AE 0062;0061 05AE 2DE8 0300 0315 0062;0061 05AE 2DE8 0300 0315 0062;0061 05AE 2DE8 0300 0315 0062;0061 05AE 2DE8 0300 0315 0062; # (a◌ⷨ◌̕◌̀◌֮b; a◌֮◌ⷨ◌̀◌̕b; a◌֮◌ⷨ◌̀◌̕b; a◌֮◌ⷨ◌̀◌̕b; a◌֮◌ⷨ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER EM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DE9 0062;00E0 05AE 2DE9 0315 0062;0061 05AE 0300 2DE9 0315 0062;00E0 05AE 2DE9 0315 0062;0061 05AE 0300 2DE9 0315 0062; # (a◌̕◌̀◌֮◌ⷩb; à◌֮◌ⷩ◌̕b; a◌֮◌̀◌ⷩ◌̕b; à◌֮◌ⷩ◌̕b; a◌֮◌̀◌ⷩ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER EN, LATIN SMALL LETTER B +0061 2DE9 0315 0300 05AE 0062;0061 05AE 2DE9 0300 0315 0062;0061 05AE 2DE9 0300 0315 0062;0061 05AE 2DE9 0300 0315 0062;0061 05AE 2DE9 0300 0315 0062; # (a◌ⷩ◌̕◌̀◌֮b; a◌֮◌ⷩ◌̀◌̕b; a◌֮◌ⷩ◌̀◌̕b; a◌֮◌ⷩ◌̀◌̕b; a◌֮◌ⷩ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER EN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DEA 0062;00E0 05AE 2DEA 0315 0062;0061 05AE 0300 2DEA 0315 0062;00E0 05AE 2DEA 0315 0062;0061 05AE 0300 2DEA 0315 0062; # (a◌̕◌̀◌֮◌ⷪb; à◌֮◌ⷪ◌̕b; a◌֮◌̀◌ⷪ◌̕b; à◌֮◌ⷪ◌̕b; a◌֮◌̀◌ⷪ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER O, LATIN SMALL LETTER B +0061 2DEA 0315 0300 05AE 0062;0061 05AE 2DEA 0300 0315 0062;0061 05AE 2DEA 0300 0315 0062;0061 05AE 2DEA 0300 0315 0062;0061 05AE 2DEA 0300 0315 0062; # (a◌ⷪ◌̕◌̀◌֮b; a◌֮◌ⷪ◌̀◌̕b; a◌֮◌ⷪ◌̀◌̕b; a◌֮◌ⷪ◌̀◌̕b; a◌֮◌ⷪ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER O, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DEB 0062;00E0 05AE 2DEB 0315 0062;0061 05AE 0300 2DEB 0315 0062;00E0 05AE 2DEB 0315 0062;0061 05AE 0300 2DEB 0315 0062; # (a◌̕◌̀◌֮◌ⷫb; à◌֮◌ⷫ◌̕b; a◌֮◌̀◌ⷫ◌̕b; à◌֮◌ⷫ◌̕b; a◌֮◌̀◌ⷫ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER PE, LATIN SMALL LETTER B +0061 2DEB 0315 0300 05AE 0062;0061 05AE 2DEB 0300 0315 0062;0061 05AE 2DEB 0300 0315 0062;0061 05AE 2DEB 0300 0315 0062;0061 05AE 2DEB 0300 0315 0062; # (a◌ⷫ◌̕◌̀◌֮b; a◌֮◌ⷫ◌̀◌̕b; a◌֮◌ⷫ◌̀◌̕b; a◌֮◌ⷫ◌̀◌̕b; a◌֮◌ⷫ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER PE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DEC 0062;00E0 05AE 2DEC 0315 0062;0061 05AE 0300 2DEC 0315 0062;00E0 05AE 2DEC 0315 0062;0061 05AE 0300 2DEC 0315 0062; # (a◌̕◌̀◌֮◌ⷬb; à◌֮◌ⷬ◌̕b; a◌֮◌̀◌ⷬ◌̕b; à◌֮◌ⷬ◌̕b; a◌֮◌̀◌ⷬ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER ER, LATIN SMALL LETTER B +0061 2DEC 0315 0300 05AE 0062;0061 05AE 2DEC 0300 0315 0062;0061 05AE 2DEC 0300 0315 0062;0061 05AE 2DEC 0300 0315 0062;0061 05AE 2DEC 0300 0315 0062; # (a◌ⷬ◌̕◌̀◌֮b; a◌֮◌ⷬ◌̀◌̕b; a◌֮◌ⷬ◌̀◌̕b; a◌֮◌ⷬ◌̀◌̕b; a◌֮◌ⷬ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER ER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DED 0062;00E0 05AE 2DED 0315 0062;0061 05AE 0300 2DED 0315 0062;00E0 05AE 2DED 0315 0062;0061 05AE 0300 2DED 0315 0062; # (a◌̕◌̀◌֮◌ⷭb; à◌֮◌ⷭ◌̕b; a◌֮◌̀◌ⷭ◌̕b; à◌֮◌ⷭ◌̕b; a◌֮◌̀◌ⷭ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER ES, LATIN SMALL LETTER B +0061 2DED 0315 0300 05AE 0062;0061 05AE 2DED 0300 0315 0062;0061 05AE 2DED 0300 0315 0062;0061 05AE 2DED 0300 0315 0062;0061 05AE 2DED 0300 0315 0062; # (a◌ⷭ◌̕◌̀◌֮b; a◌֮◌ⷭ◌̀◌̕b; a◌֮◌ⷭ◌̀◌̕b; a◌֮◌ⷭ◌̀◌̕b; a◌֮◌ⷭ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER ES, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DEE 0062;00E0 05AE 2DEE 0315 0062;0061 05AE 0300 2DEE 0315 0062;00E0 05AE 2DEE 0315 0062;0061 05AE 0300 2DEE 0315 0062; # (a◌̕◌̀◌֮◌ⷮb; à◌֮◌ⷮ◌̕b; a◌֮◌̀◌ⷮ◌̕b; à◌֮◌ⷮ◌̕b; a◌֮◌̀◌ⷮ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER TE, LATIN SMALL LETTER B +0061 2DEE 0315 0300 05AE 0062;0061 05AE 2DEE 0300 0315 0062;0061 05AE 2DEE 0300 0315 0062;0061 05AE 2DEE 0300 0315 0062;0061 05AE 2DEE 0300 0315 0062; # (a◌ⷮ◌̕◌̀◌֮b; a◌֮◌ⷮ◌̀◌̕b; a◌֮◌ⷮ◌̀◌̕b; a◌֮◌ⷮ◌̀◌̕b; a◌֮◌ⷮ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER TE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DEF 0062;00E0 05AE 2DEF 0315 0062;0061 05AE 0300 2DEF 0315 0062;00E0 05AE 2DEF 0315 0062;0061 05AE 0300 2DEF 0315 0062; # (a◌̕◌̀◌֮◌ⷯb; à◌֮◌ⷯ◌̕b; a◌֮◌̀◌ⷯ◌̕b; à◌֮◌ⷯ◌̕b; a◌֮◌̀◌ⷯ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER HA, LATIN SMALL LETTER B +0061 2DEF 0315 0300 05AE 0062;0061 05AE 2DEF 0300 0315 0062;0061 05AE 2DEF 0300 0315 0062;0061 05AE 2DEF 0300 0315 0062;0061 05AE 2DEF 0300 0315 0062; # (a◌ⷯ◌̕◌̀◌֮b; a◌֮◌ⷯ◌̀◌̕b; a◌֮◌ⷯ◌̀◌̕b; a◌֮◌ⷯ◌̀◌̕b; a◌֮◌ⷯ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER HA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF0 0062;00E0 05AE 2DF0 0315 0062;0061 05AE 0300 2DF0 0315 0062;00E0 05AE 2DF0 0315 0062;0061 05AE 0300 2DF0 0315 0062; # (a◌̕◌̀◌֮◌ⷰb; à◌֮◌ⷰ◌̕b; a◌֮◌̀◌ⷰ◌̕b; à◌֮◌ⷰ◌̕b; a◌֮◌̀◌ⷰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER TSE, LATIN SMALL LETTER B +0061 2DF0 0315 0300 05AE 0062;0061 05AE 2DF0 0300 0315 0062;0061 05AE 2DF0 0300 0315 0062;0061 05AE 2DF0 0300 0315 0062;0061 05AE 2DF0 0300 0315 0062; # (a◌ⷰ◌̕◌̀◌֮b; a◌֮◌ⷰ◌̀◌̕b; a◌֮◌ⷰ◌̀◌̕b; a◌֮◌ⷰ◌̀◌̕b; a◌֮◌ⷰ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER TSE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF1 0062;00E0 05AE 2DF1 0315 0062;0061 05AE 0300 2DF1 0315 0062;00E0 05AE 2DF1 0315 0062;0061 05AE 0300 2DF1 0315 0062; # (a◌̕◌̀◌֮◌ⷱb; à◌֮◌ⷱ◌̕b; a◌֮◌̀◌ⷱ◌̕b; à◌֮◌ⷱ◌̕b; a◌֮◌̀◌ⷱ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER CHE, LATIN SMALL LETTER B +0061 2DF1 0315 0300 05AE 0062;0061 05AE 2DF1 0300 0315 0062;0061 05AE 2DF1 0300 0315 0062;0061 05AE 2DF1 0300 0315 0062;0061 05AE 2DF1 0300 0315 0062; # (a◌ⷱ◌̕◌̀◌֮b; a◌֮◌ⷱ◌̀◌̕b; a◌֮◌ⷱ◌̀◌̕b; a◌֮◌ⷱ◌̀◌̕b; a◌֮◌ⷱ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER CHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF2 0062;00E0 05AE 2DF2 0315 0062;0061 05AE 0300 2DF2 0315 0062;00E0 05AE 2DF2 0315 0062;0061 05AE 0300 2DF2 0315 0062; # (a◌̕◌̀◌֮◌ⷲb; à◌֮◌ⷲ◌̕b; a◌֮◌̀◌ⷲ◌̕b; à◌֮◌ⷲ◌̕b; a◌֮◌̀◌ⷲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER SHA, LATIN SMALL LETTER B +0061 2DF2 0315 0300 05AE 0062;0061 05AE 2DF2 0300 0315 0062;0061 05AE 2DF2 0300 0315 0062;0061 05AE 2DF2 0300 0315 0062;0061 05AE 2DF2 0300 0315 0062; # (a◌ⷲ◌̕◌̀◌֮b; a◌֮◌ⷲ◌̀◌̕b; a◌֮◌ⷲ◌̀◌̕b; a◌֮◌ⷲ◌̀◌̕b; a◌֮◌ⷲ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER SHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF3 0062;00E0 05AE 2DF3 0315 0062;0061 05AE 0300 2DF3 0315 0062;00E0 05AE 2DF3 0315 0062;0061 05AE 0300 2DF3 0315 0062; # (a◌̕◌̀◌֮◌ⷳb; à◌֮◌ⷳ◌̕b; a◌֮◌̀◌ⷳ◌̕b; à◌֮◌ⷳ◌̕b; a◌֮◌̀◌ⷳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER SHCHA, LATIN SMALL LETTER B +0061 2DF3 0315 0300 05AE 0062;0061 05AE 2DF3 0300 0315 0062;0061 05AE 2DF3 0300 0315 0062;0061 05AE 2DF3 0300 0315 0062;0061 05AE 2DF3 0300 0315 0062; # (a◌ⷳ◌̕◌̀◌֮b; a◌֮◌ⷳ◌̀◌̕b; a◌֮◌ⷳ◌̀◌̕b; a◌֮◌ⷳ◌̀◌̕b; a◌֮◌ⷳ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER SHCHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF4 0062;00E0 05AE 2DF4 0315 0062;0061 05AE 0300 2DF4 0315 0062;00E0 05AE 2DF4 0315 0062;0061 05AE 0300 2DF4 0315 0062; # (a◌̕◌̀◌֮◌ⷴb; à◌֮◌ⷴ◌̕b; a◌֮◌̀◌ⷴ◌̕b; à◌֮◌ⷴ◌̕b; a◌֮◌̀◌ⷴ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER FITA, LATIN SMALL LETTER B +0061 2DF4 0315 0300 05AE 0062;0061 05AE 2DF4 0300 0315 0062;0061 05AE 2DF4 0300 0315 0062;0061 05AE 2DF4 0300 0315 0062;0061 05AE 2DF4 0300 0315 0062; # (a◌ⷴ◌̕◌̀◌֮b; a◌֮◌ⷴ◌̀◌̕b; a◌֮◌ⷴ◌̀◌̕b; a◌֮◌ⷴ◌̀◌̕b; a◌֮◌ⷴ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER FITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF5 0062;00E0 05AE 2DF5 0315 0062;0061 05AE 0300 2DF5 0315 0062;00E0 05AE 2DF5 0315 0062;0061 05AE 0300 2DF5 0315 0062; # (a◌̕◌̀◌֮◌ⷵb; à◌֮◌ⷵ◌̕b; a◌֮◌̀◌ⷵ◌̕b; à◌֮◌ⷵ◌̕b; a◌֮◌̀◌ⷵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER ES-TE, LATIN SMALL LETTER B +0061 2DF5 0315 0300 05AE 0062;0061 05AE 2DF5 0300 0315 0062;0061 05AE 2DF5 0300 0315 0062;0061 05AE 2DF5 0300 0315 0062;0061 05AE 2DF5 0300 0315 0062; # (a◌ⷵ◌̕◌̀◌֮b; a◌֮◌ⷵ◌̀◌̕b; a◌֮◌ⷵ◌̀◌̕b; a◌֮◌ⷵ◌̀◌̕b; a◌֮◌ⷵ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER ES-TE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF6 0062;00E0 05AE 2DF6 0315 0062;0061 05AE 0300 2DF6 0315 0062;00E0 05AE 2DF6 0315 0062;0061 05AE 0300 2DF6 0315 0062; # (a◌̕◌̀◌֮◌ⷶb; à◌֮◌ⷶ◌̕b; a◌֮◌̀◌ⷶ◌̕b; à◌֮◌ⷶ◌̕b; a◌֮◌̀◌ⷶ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER A, LATIN SMALL LETTER B +0061 2DF6 0315 0300 05AE 0062;0061 05AE 2DF6 0300 0315 0062;0061 05AE 2DF6 0300 0315 0062;0061 05AE 2DF6 0300 0315 0062;0061 05AE 2DF6 0300 0315 0062; # (a◌ⷶ◌̕◌̀◌֮b; a◌֮◌ⷶ◌̀◌̕b; a◌֮◌ⷶ◌̀◌̕b; a◌֮◌ⷶ◌̀◌̕b; a◌֮◌ⷶ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF7 0062;00E0 05AE 2DF7 0315 0062;0061 05AE 0300 2DF7 0315 0062;00E0 05AE 2DF7 0315 0062;0061 05AE 0300 2DF7 0315 0062; # (a◌̕◌̀◌֮◌ⷷb; à◌֮◌ⷷ◌̕b; a◌֮◌̀◌ⷷ◌̕b; à◌֮◌ⷷ◌̕b; a◌֮◌̀◌ⷷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IE, LATIN SMALL LETTER B +0061 2DF7 0315 0300 05AE 0062;0061 05AE 2DF7 0300 0315 0062;0061 05AE 2DF7 0300 0315 0062;0061 05AE 2DF7 0300 0315 0062;0061 05AE 2DF7 0300 0315 0062; # (a◌ⷷ◌̕◌̀◌֮b; a◌֮◌ⷷ◌̀◌̕b; a◌֮◌ⷷ◌̀◌̕b; a◌֮◌ⷷ◌̀◌̕b; a◌֮◌ⷷ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF8 0062;00E0 05AE 2DF8 0315 0062;0061 05AE 0300 2DF8 0315 0062;00E0 05AE 2DF8 0315 0062;0061 05AE 0300 2DF8 0315 0062; # (a◌̕◌̀◌֮◌ⷸb; à◌֮◌ⷸ◌̕b; a◌֮◌̀◌ⷸ◌̕b; à◌֮◌ⷸ◌̕b; a◌֮◌̀◌ⷸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER DJERV, LATIN SMALL LETTER B +0061 2DF8 0315 0300 05AE 0062;0061 05AE 2DF8 0300 0315 0062;0061 05AE 2DF8 0300 0315 0062;0061 05AE 2DF8 0300 0315 0062;0061 05AE 2DF8 0300 0315 0062; # (a◌ⷸ◌̕◌̀◌֮b; a◌֮◌ⷸ◌̀◌̕b; a◌֮◌ⷸ◌̀◌̕b; a◌֮◌ⷸ◌̀◌̕b; a◌֮◌ⷸ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER DJERV, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DF9 0062;00E0 05AE 2DF9 0315 0062;0061 05AE 0300 2DF9 0315 0062;00E0 05AE 2DF9 0315 0062;0061 05AE 0300 2DF9 0315 0062; # (a◌̕◌̀◌֮◌ⷹb; à◌֮◌ⷹ◌̕b; a◌֮◌̀◌ⷹ◌̕b; à◌֮◌ⷹ◌̕b; a◌֮◌̀◌ⷹ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER MONOGRAPH UK, LATIN SMALL LETTER B +0061 2DF9 0315 0300 05AE 0062;0061 05AE 2DF9 0300 0315 0062;0061 05AE 2DF9 0300 0315 0062;0061 05AE 2DF9 0300 0315 0062;0061 05AE 2DF9 0300 0315 0062; # (a◌ⷹ◌̕◌̀◌֮b; a◌֮◌ⷹ◌̀◌̕b; a◌֮◌ⷹ◌̀◌̕b; a◌֮◌ⷹ◌̀◌̕b; a◌֮◌ⷹ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER MONOGRAPH UK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFA 0062;00E0 05AE 2DFA 0315 0062;0061 05AE 0300 2DFA 0315 0062;00E0 05AE 2DFA 0315 0062;0061 05AE 0300 2DFA 0315 0062; # (a◌̕◌̀◌֮◌ⷺb; à◌֮◌ⷺ◌̕b; a◌֮◌̀◌ⷺ◌̕b; à◌֮◌ⷺ◌̕b; a◌֮◌̀◌ⷺ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER YAT, LATIN SMALL LETTER B +0061 2DFA 0315 0300 05AE 0062;0061 05AE 2DFA 0300 0315 0062;0061 05AE 2DFA 0300 0315 0062;0061 05AE 2DFA 0300 0315 0062;0061 05AE 2DFA 0300 0315 0062; # (a◌ⷺ◌̕◌̀◌֮b; a◌֮◌ⷺ◌̀◌̕b; a◌֮◌ⷺ◌̀◌̕b; a◌֮◌ⷺ◌̀◌̕b; a◌֮◌ⷺ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER YAT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFB 0062;00E0 05AE 2DFB 0315 0062;0061 05AE 0300 2DFB 0315 0062;00E0 05AE 2DFB 0315 0062;0061 05AE 0300 2DFB 0315 0062; # (a◌̕◌̀◌֮◌ⷻb; à◌֮◌ⷻ◌̕b; a◌֮◌̀◌ⷻ◌̕b; à◌֮◌ⷻ◌̕b; a◌֮◌̀◌ⷻ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER YU, LATIN SMALL LETTER B +0061 2DFB 0315 0300 05AE 0062;0061 05AE 2DFB 0300 0315 0062;0061 05AE 2DFB 0300 0315 0062;0061 05AE 2DFB 0300 0315 0062;0061 05AE 2DFB 0300 0315 0062; # (a◌ⷻ◌̕◌̀◌֮b; a◌֮◌ⷻ◌̀◌̕b; a◌֮◌ⷻ◌̀◌̕b; a◌֮◌ⷻ◌̀◌̕b; a◌֮◌ⷻ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER YU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFC 0062;00E0 05AE 2DFC 0315 0062;0061 05AE 0300 2DFC 0315 0062;00E0 05AE 2DFC 0315 0062;0061 05AE 0300 2DFC 0315 0062; # (a◌̕◌̀◌֮◌ⷼb; à◌֮◌ⷼ◌̕b; a◌֮◌̀◌ⷼ◌̕b; à◌֮◌ⷼ◌̕b; a◌֮◌̀◌ⷼ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IOTIFIED A, LATIN SMALL LETTER B +0061 2DFC 0315 0300 05AE 0062;0061 05AE 2DFC 0300 0315 0062;0061 05AE 2DFC 0300 0315 0062;0061 05AE 2DFC 0300 0315 0062;0061 05AE 2DFC 0300 0315 0062; # (a◌ⷼ◌̕◌̀◌֮b; a◌֮◌ⷼ◌̀◌̕b; a◌֮◌ⷼ◌̀◌̕b; a◌֮◌ⷼ◌̀◌̕b; a◌֮◌ⷼ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IOTIFIED A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFD 0062;00E0 05AE 2DFD 0315 0062;0061 05AE 0300 2DFD 0315 0062;00E0 05AE 2DFD 0315 0062;0061 05AE 0300 2DFD 0315 0062; # (a◌̕◌̀◌֮◌ⷽb; à◌֮◌ⷽ◌̕b; a◌֮◌̀◌ⷽ◌̕b; à◌֮◌ⷽ◌̕b; a◌֮◌̀◌ⷽ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER LITTLE YUS, LATIN SMALL LETTER B +0061 2DFD 0315 0300 05AE 0062;0061 05AE 2DFD 0300 0315 0062;0061 05AE 2DFD 0300 0315 0062;0061 05AE 2DFD 0300 0315 0062;0061 05AE 2DFD 0300 0315 0062; # (a◌ⷽ◌̕◌̀◌֮b; a◌֮◌ⷽ◌̀◌̕b; a◌֮◌ⷽ◌̀◌̕b; a◌֮◌ⷽ◌̀◌̕b; a◌֮◌ⷽ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER LITTLE YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFE 0062;00E0 05AE 2DFE 0315 0062;0061 05AE 0300 2DFE 0315 0062;00E0 05AE 2DFE 0315 0062;0061 05AE 0300 2DFE 0315 0062; # (a◌̕◌̀◌֮◌ⷾb; à◌֮◌ⷾ◌̕b; a◌֮◌̀◌ⷾ◌̕b; à◌֮◌ⷾ◌̕b; a◌֮◌̀◌ⷾ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER BIG YUS, LATIN SMALL LETTER B +0061 2DFE 0315 0300 05AE 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062; # (a◌ⷾ◌̕◌̀◌֮b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 2DFF 0062;00E0 05AE 2DFF 0315 0062;0061 05AE 0300 2DFF 0315 0062;00E0 05AE 2DFF 0315 0062;0061 05AE 0300 2DFF 0315 0062; # (a◌̕◌̀◌֮◌ⷿb; à◌֮◌ⷿ◌̕b; a◌֮◌̀◌ⷿ◌̕b; à◌֮◌ⷿ◌̕b; a◌֮◌̀◌ⷿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IOTIFIED BIG YUS, LATIN SMALL LETTER B +0061 2DFF 0315 0300 05AE 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062; # (a◌ⷿ◌̕◌̀◌֮b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IOTIFIED BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0316 1DFA 031B 302A 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062; # (a◌̖◌᷺◌̛◌〪b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 302A 0316 1DFA 031B 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062; # (a◌〪◌̖◌᷺◌̛b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 302B 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062; # (a◌̀◌𝅭֮◌〫b; à𝅭◌֮◌〫b; a𝅭◌֮◌〫◌̀b; à𝅭◌֮◌〫b; a𝅭◌֮◌〫◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, IDEOGRAPHIC RISING TONE MARK, LATIN SMALL LETTER B +0061 302B 0300 05AE 1D16D 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062; # (a◌〫◌̀◌𝅭֮b; à𝅭◌〫◌֮b; a𝅭◌〫◌֮◌̀b; à𝅭◌〫◌֮b; a𝅭◌〫◌֮◌̀b; ) LATIN SMALL LETTER A, IDEOGRAPHIC RISING TONE MARK, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 035C 0315 0300 302C 0062;00E0 0315 302C 035C 0062;0061 0300 0315 302C 035C 0062;00E0 0315 302C 035C 0062;0061 0300 0315 302C 035C 0062; # (a◌͜◌̕◌̀◌〬b; à◌̕◌〬◌͜b; a◌̀◌̕◌〬◌͜b; à◌̕◌〬◌͜b; a◌̀◌̕◌〬◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, IDEOGRAPHIC DEPARTING TONE MARK, LATIN SMALL LETTER B +0061 302C 035C 0315 0300 0062;00E0 302C 0315 035C 0062;0061 0300 302C 0315 035C 0062;00E0 302C 0315 035C 0062;0061 0300 302C 0315 035C 0062; # (a◌〬◌͜◌̕◌̀b; à◌〬◌̕◌͜b; a◌̀◌〬◌̕◌͜b; à◌〬◌̕◌͜b; a◌̀◌〬◌̕◌͜b; ) LATIN SMALL LETTER A, IDEOGRAPHIC DEPARTING TONE MARK, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 302E 059A 0316 302D 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062;0061 0316 059A 302D 302E 0062; # (a〮◌֚◌̖◌〭b; a◌̖◌֚◌〭〮b; a◌̖◌֚◌〭〮b; a◌̖◌֚◌〭〮b; a◌̖◌֚◌〭〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC ENTERING TONE MARK, LATIN SMALL LETTER B +0061 302D 302E 059A 0316 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062;0061 0316 302D 059A 302E 0062; # (a◌〭〮◌֚◌̖b; a◌̖◌〭◌֚〮b; a◌̖◌〭◌֚〮b; a◌̖◌〭◌֚〮b; a◌̖◌〭◌֚〮b; ) LATIN SMALL LETTER A, IDEOGRAPHIC ENTERING TONE MARK, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 1D16D 302E 059A 302E 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062; # (a〮𝅭◌֚〮b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, HANGUL SINGLE DOT TONE MARK, LATIN SMALL LETTER B +0061 302E 1D16D 302E 059A 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062;0061 059A 302E 302E 1D16D 0062; # (a〮〮𝅭◌֚b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; a◌֚〮〮𝅭b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 1D16D 302E 059A 302F 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062;0061 059A 302E 302F 1D16D 0062; # (a〮𝅭◌֚〯b; a◌֚〮〯𝅭b; a◌֚〮〯𝅭b; a◌֚〮〯𝅭b; a◌֚〮〯𝅭b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, HANGUL DOUBLE DOT TONE MARK, LATIN SMALL LETTER B +0061 302F 1D16D 302E 059A 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062;0061 059A 302F 302E 1D16D 0062; # (a〯〮𝅭◌֚b; a◌֚〯〮𝅭b; a◌֚〯〮𝅭b; a◌֚〯〮𝅭b; a◌֚〯〮𝅭b; ) LATIN SMALL LETTER A, HANGUL DOUBLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, LATIN SMALL LETTER B +0061 094D 3099 093C 3099 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062; # (a◌्◌゙◌़◌゙b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 094D 3099 093C 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062;0061 093C 3099 3099 094D 0062; # (a◌゙◌्◌゙◌़b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; a◌़◌゙◌゙◌्b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 094D 3099 093C 309A 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062;0061 093C 3099 309A 094D 0062; # (a◌्◌゙◌़◌゚b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; a◌़◌゙◌゚◌्b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK, LATIN SMALL LETTER B +0061 309A 094D 3099 093C 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062;0061 093C 309A 3099 094D 0062; # (a◌゚◌्◌゙◌़b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; a◌़◌゚◌゙◌्b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, LATIN SMALL LETTER B +0061 0315 0300 05AE A66F 0062;00E0 05AE A66F 0315 0062;0061 05AE 0300 A66F 0315 0062;00E0 05AE A66F 0315 0062;0061 05AE 0300 A66F 0315 0062; # (a◌̕◌̀◌֮◌꙯b; à◌֮◌꙯◌̕b; a◌֮◌̀◌꙯◌̕b; à◌֮◌꙯◌̕b; a◌֮◌̀◌꙯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC VZMET, LATIN SMALL LETTER B +0061 A66F 0315 0300 05AE 0062;0061 05AE A66F 0300 0315 0062;0061 05AE A66F 0300 0315 0062;0061 05AE A66F 0300 0315 0062;0061 05AE A66F 0300 0315 0062; # (a◌꙯◌̕◌̀◌֮b; a◌֮◌꙯◌̀◌̕b; a◌֮◌꙯◌̀◌̕b; a◌֮◌꙯◌̀◌̕b; a◌֮◌꙯◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC VZMET, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A674 0062;00E0 05AE A674 0315 0062;0061 05AE 0300 A674 0315 0062;00E0 05AE A674 0315 0062;0061 05AE 0300 A674 0315 0062; # (a◌̕◌̀◌֮◌ꙴb; à◌֮◌ꙴ◌̕b; a◌֮◌̀◌ꙴ◌̕b; à◌֮◌ꙴ◌̕b; a◌֮◌̀◌ꙴ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER UKRAINIAN IE, LATIN SMALL LETTER B +0061 A674 0315 0300 05AE 0062;0061 05AE A674 0300 0315 0062;0061 05AE A674 0300 0315 0062;0061 05AE A674 0300 0315 0062;0061 05AE A674 0300 0315 0062; # (a◌ꙴ◌̕◌̀◌֮b; a◌֮◌ꙴ◌̀◌̕b; a◌֮◌ꙴ◌̀◌̕b; a◌֮◌ꙴ◌̀◌̕b; a◌֮◌ꙴ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER UKRAINIAN IE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A675 0062;00E0 05AE A675 0315 0062;0061 05AE 0300 A675 0315 0062;00E0 05AE A675 0315 0062;0061 05AE 0300 A675 0315 0062; # (a◌̕◌̀◌֮◌ꙵb; à◌֮◌ꙵ◌̕b; a◌֮◌̀◌ꙵ◌̕b; à◌֮◌ꙵ◌̕b; a◌֮◌̀◌ꙵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER I, LATIN SMALL LETTER B +0061 A675 0315 0300 05AE 0062;0061 05AE A675 0300 0315 0062;0061 05AE A675 0300 0315 0062;0061 05AE A675 0300 0315 0062;0061 05AE A675 0300 0315 0062; # (a◌ꙵ◌̕◌̀◌֮b; a◌֮◌ꙵ◌̀◌̕b; a◌֮◌ꙵ◌̀◌̕b; a◌֮◌ꙵ◌̀◌̕b; a◌֮◌ꙵ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A676 0062;00E0 05AE A676 0315 0062;0061 05AE 0300 A676 0315 0062;00E0 05AE A676 0315 0062;0061 05AE 0300 A676 0315 0062; # (a◌̕◌̀◌֮◌ꙶb; à◌֮◌ꙶ◌̕b; a◌֮◌̀◌ꙶ◌̕b; à◌֮◌ꙶ◌̕b; a◌֮◌̀◌ꙶ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER YI, LATIN SMALL LETTER B +0061 A676 0315 0300 05AE 0062;0061 05AE A676 0300 0315 0062;0061 05AE A676 0300 0315 0062;0061 05AE A676 0300 0315 0062;0061 05AE A676 0300 0315 0062; # (a◌ꙶ◌̕◌̀◌֮b; a◌֮◌ꙶ◌̀◌̕b; a◌֮◌ꙶ◌̀◌̕b; a◌֮◌ꙶ◌̀◌̕b; a◌֮◌ꙶ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER YI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A677 0062;00E0 05AE A677 0315 0062;0061 05AE 0300 A677 0315 0062;00E0 05AE A677 0315 0062;0061 05AE 0300 A677 0315 0062; # (a◌̕◌̀◌֮◌ꙷb; à◌֮◌ꙷ◌̕b; a◌֮◌̀◌ꙷ◌̕b; à◌֮◌ꙷ◌̕b; a◌֮◌̀◌ꙷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER U, LATIN SMALL LETTER B +0061 A677 0315 0300 05AE 0062;0061 05AE A677 0300 0315 0062;0061 05AE A677 0300 0315 0062;0061 05AE A677 0300 0315 0062;0061 05AE A677 0300 0315 0062; # (a◌ꙷ◌̕◌̀◌֮b; a◌֮◌ꙷ◌̀◌̕b; a◌֮◌ꙷ◌̀◌̕b; a◌֮◌ꙷ◌̀◌̕b; a◌֮◌ꙷ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A678 0062;00E0 05AE A678 0315 0062;0061 05AE 0300 A678 0315 0062;00E0 05AE A678 0315 0062;0061 05AE 0300 A678 0315 0062; # (a◌̕◌̀◌֮◌ꙸb; à◌֮◌ꙸ◌̕b; a◌֮◌̀◌ꙸ◌̕b; à◌֮◌ꙸ◌̕b; a◌֮◌̀◌ꙸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER HARD SIGN, LATIN SMALL LETTER B +0061 A678 0315 0300 05AE 0062;0061 05AE A678 0300 0315 0062;0061 05AE A678 0300 0315 0062;0061 05AE A678 0300 0315 0062;0061 05AE A678 0300 0315 0062; # (a◌ꙸ◌̕◌̀◌֮b; a◌֮◌ꙸ◌̀◌̕b; a◌֮◌ꙸ◌̀◌̕b; a◌֮◌ꙸ◌̀◌̕b; a◌֮◌ꙸ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER HARD SIGN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A679 0062;00E0 05AE A679 0315 0062;0061 05AE 0300 A679 0315 0062;00E0 05AE A679 0315 0062;0061 05AE 0300 A679 0315 0062; # (a◌̕◌̀◌֮◌ꙹb; à◌֮◌ꙹ◌̕b; a◌֮◌̀◌ꙹ◌̕b; à◌֮◌ꙹ◌̕b; a◌֮◌̀◌ꙹ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER YERU, LATIN SMALL LETTER B +0061 A679 0315 0300 05AE 0062;0061 05AE A679 0300 0315 0062;0061 05AE A679 0300 0315 0062;0061 05AE A679 0300 0315 0062;0061 05AE A679 0300 0315 0062; # (a◌ꙹ◌̕◌̀◌֮b; a◌֮◌ꙹ◌̀◌̕b; a◌֮◌ꙹ◌̀◌̕b; a◌֮◌ꙹ◌̀◌̕b; a◌֮◌ꙹ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER YERU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A67A 0062;00E0 05AE A67A 0315 0062;0061 05AE 0300 A67A 0315 0062;00E0 05AE A67A 0315 0062;0061 05AE 0300 A67A 0315 0062; # (a◌̕◌̀◌֮◌ꙺb; à◌֮◌ꙺ◌̕b; a◌֮◌̀◌ꙺ◌̕b; à◌֮◌ꙺ◌̕b; a◌֮◌̀◌ꙺ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER SOFT SIGN, LATIN SMALL LETTER B +0061 A67A 0315 0300 05AE 0062;0061 05AE A67A 0300 0315 0062;0061 05AE A67A 0300 0315 0062;0061 05AE A67A 0300 0315 0062;0061 05AE A67A 0300 0315 0062; # (a◌ꙺ◌̕◌̀◌֮b; a◌֮◌ꙺ◌̀◌̕b; a◌֮◌ꙺ◌̀◌̕b; a◌֮◌ꙺ◌̀◌̕b; a◌֮◌ꙺ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER SOFT SIGN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A67B 0062;00E0 05AE A67B 0315 0062;0061 05AE 0300 A67B 0315 0062;00E0 05AE A67B 0315 0062;0061 05AE 0300 A67B 0315 0062; # (a◌̕◌̀◌֮◌ꙻb; à◌֮◌ꙻ◌̕b; a◌֮◌̀◌ꙻ◌̕b; à◌֮◌ꙻ◌̕b; a◌֮◌̀◌ꙻ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER OMEGA, LATIN SMALL LETTER B +0061 A67B 0315 0300 05AE 0062;0061 05AE A67B 0300 0315 0062;0061 05AE A67B 0300 0315 0062;0061 05AE A67B 0300 0315 0062;0061 05AE A67B 0300 0315 0062; # (a◌ꙻ◌̕◌̀◌֮b; a◌֮◌ꙻ◌̀◌̕b; a◌֮◌ꙻ◌̀◌̕b; a◌֮◌ꙻ◌̀◌̕b; a◌֮◌ꙻ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER OMEGA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A67C 0062;00E0 05AE A67C 0315 0062;0061 05AE 0300 A67C 0315 0062;00E0 05AE A67C 0315 0062;0061 05AE 0300 A67C 0315 0062; # (a◌̕◌̀◌֮◌꙼b; à◌֮◌꙼◌̕b; a◌֮◌̀◌꙼◌̕b; à◌֮◌꙼◌̕b; a◌֮◌̀◌꙼◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC KAVYKA, LATIN SMALL LETTER B +0061 A67C 0315 0300 05AE 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062; # (a◌꙼◌̕◌̀◌֮b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC KAVYKA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A67D 0062;00E0 05AE A67D 0315 0062;0061 05AE 0300 A67D 0315 0062;00E0 05AE A67D 0315 0062;0061 05AE 0300 A67D 0315 0062; # (a◌̕◌̀◌֮◌꙽b; à◌֮◌꙽◌̕b; a◌֮◌̀◌꙽◌̕b; à◌֮◌꙽◌̕b; a◌֮◌̀◌꙽◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PAYEROK, LATIN SMALL LETTER B +0061 A67D 0315 0300 05AE 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062; # (a◌꙽◌̕◌̀◌֮b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PAYEROK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A69E 0062;00E0 05AE A69E 0315 0062;0061 05AE 0300 A69E 0315 0062;00E0 05AE A69E 0315 0062;0061 05AE 0300 A69E 0315 0062; # (a◌̕◌̀◌֮◌ꚞb; à◌֮◌ꚞ◌̕b; a◌֮◌̀◌ꚞ◌̕b; à◌֮◌ꚞ◌̕b; a◌֮◌̀◌ꚞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER EF, LATIN SMALL LETTER B +0061 A69E 0315 0300 05AE 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062; # (a◌ꚞ◌̕◌̀◌֮b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER EF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A69F 0062;00E0 05AE A69F 0315 0062;0061 05AE 0300 A69F 0315 0062;00E0 05AE A69F 0315 0062;0061 05AE 0300 A69F 0315 0062; # (a◌̕◌̀◌֮◌ꚟb; à◌֮◌ꚟ◌̕b; a◌֮◌̀◌ꚟ◌̕b; à◌֮◌ꚟ◌̕b; a◌֮◌̀◌ꚟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IOTIFIED E, LATIN SMALL LETTER B +0061 A69F 0315 0300 05AE 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062; # (a◌ꚟ◌̕◌̀◌֮b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IOTIFIED E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A6F0 0062;00E0 05AE A6F0 0315 0062;0061 05AE 0300 A6F0 0315 0062;00E0 05AE A6F0 0315 0062;0061 05AE 0300 A6F0 0315 0062; # (a◌̕◌̀◌֮◌꛰b; à◌֮◌꛰◌̕b; a◌֮◌̀◌꛰◌̕b; à◌֮◌꛰◌̕b; a◌֮◌̀◌꛰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BAMUM COMBINING MARK KOQNDON, LATIN SMALL LETTER B +0061 A6F0 0315 0300 05AE 0062;0061 05AE A6F0 0300 0315 0062;0061 05AE A6F0 0300 0315 0062;0061 05AE A6F0 0300 0315 0062;0061 05AE A6F0 0300 0315 0062; # (a◌꛰◌̕◌̀◌֮b; a◌֮◌꛰◌̀◌̕b; a◌֮◌꛰◌̀◌̕b; a◌֮◌꛰◌̀◌̕b; a◌֮◌꛰◌̀◌̕b; ) LATIN SMALL LETTER A, BAMUM COMBINING MARK KOQNDON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A6F1 0062;00E0 05AE A6F1 0315 0062;0061 05AE 0300 A6F1 0315 0062;00E0 05AE A6F1 0315 0062;0061 05AE 0300 A6F1 0315 0062; # (a◌̕◌̀◌֮◌꛱b; à◌֮◌꛱◌̕b; a◌֮◌̀◌꛱◌̕b; à◌֮◌꛱◌̕b; a◌֮◌̀◌꛱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BAMUM COMBINING MARK TUKWENTIS, LATIN SMALL LETTER B +0061 A6F1 0315 0300 05AE 0062;0061 05AE A6F1 0300 0315 0062;0061 05AE A6F1 0300 0315 0062;0061 05AE A6F1 0300 0315 0062;0061 05AE A6F1 0300 0315 0062; # (a◌꛱◌̕◌̀◌֮b; a◌֮◌꛱◌̀◌̕b; a◌֮◌꛱◌̀◌̕b; a◌֮◌꛱◌̀◌̕b; a◌֮◌꛱◌̀◌̕b; ) LATIN SMALL LETTER A, BAMUM COMBINING MARK TUKWENTIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 A806 0062;0061 3099 094D A806 05B0 0062;0061 3099 094D A806 05B0 0062;0061 3099 094D A806 05B0 0062;0061 3099 094D A806 05B0 0062; # (a◌ְ◌्◌゙◌꠆b; a◌゙◌्◌꠆◌ְb; a◌゙◌्◌꠆◌ְb; a◌゙◌्◌꠆◌ְb; a◌゙◌्◌꠆◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SYLOTI NAGRI SIGN HASANTA, LATIN SMALL LETTER B +0061 A806 05B0 094D 3099 0062;0061 3099 A806 094D 05B0 0062;0061 3099 A806 094D 05B0 0062;0061 3099 A806 094D 05B0 0062;0061 3099 A806 094D 05B0 0062; # (a◌꠆◌ְ◌्◌゙b; a◌゙◌꠆◌्◌ְb; a◌゙◌꠆◌्◌ְb; a◌゙◌꠆◌्◌ְb; a◌゙◌꠆◌्◌ְb; ) LATIN SMALL LETTER A, SYLOTI NAGRI SIGN HASANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 A82C 0062;0061 3099 094D A82C 05B0 0062;0061 3099 094D A82C 05B0 0062;0061 3099 094D A82C 05B0 0062;0061 3099 094D A82C 05B0 0062; # (a◌ְ◌्◌゙◌꠬b; a◌゙◌्◌꠬◌ְb; a◌゙◌्◌꠬◌ְb; a◌゙◌्◌꠬◌ְb; a◌゙◌्◌꠬◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SYLOTI NAGRI SIGN ALTERNATE HASANTA, LATIN SMALL LETTER B +0061 A82C 05B0 094D 3099 0062;0061 3099 A82C 094D 05B0 0062;0061 3099 A82C 094D 05B0 0062;0061 3099 A82C 094D 05B0 0062;0061 3099 A82C 094D 05B0 0062; # (a◌꠬◌ְ◌्◌゙b; a◌゙◌꠬◌्◌ְb; a◌゙◌꠬◌्◌ְb; a◌゙◌꠬◌्◌ְb; a◌゙◌꠬◌्◌ְb; ) LATIN SMALL LETTER A, SYLOTI NAGRI SIGN ALTERNATE HASANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 A8C4 0062;0061 3099 094D A8C4 05B0 0062;0061 3099 094D A8C4 05B0 0062;0061 3099 094D A8C4 05B0 0062;0061 3099 094D A8C4 05B0 0062; # (a◌ְ◌्◌゙◌꣄b; a◌゙◌्◌꣄◌ְb; a◌゙◌्◌꣄◌ְb; a◌゙◌्◌꣄◌ְb; a◌゙◌्◌꣄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SAURASHTRA SIGN VIRAMA, LATIN SMALL LETTER B +0061 A8C4 05B0 094D 3099 0062;0061 3099 A8C4 094D 05B0 0062;0061 3099 A8C4 094D 05B0 0062;0061 3099 A8C4 094D 05B0 0062;0061 3099 A8C4 094D 05B0 0062; # (a◌꣄◌ְ◌्◌゙b; a◌゙◌꣄◌्◌ְb; a◌゙◌꣄◌्◌ְb; a◌゙◌꣄◌्◌ְb; a◌゙◌꣄◌्◌ְb; ) LATIN SMALL LETTER A, SAURASHTRA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E0 0062;00E0 05AE A8E0 0315 0062;0061 05AE 0300 A8E0 0315 0062;00E0 05AE A8E0 0315 0062;0061 05AE 0300 A8E0 0315 0062; # (a◌̕◌̀◌֮◌꣠b; à◌֮◌꣠◌̕b; a◌֮◌̀◌꣠◌̕b; à◌֮◌꣠◌̕b; a◌֮◌̀◌꣠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT ZERO, LATIN SMALL LETTER B +0061 A8E0 0315 0300 05AE 0062;0061 05AE A8E0 0300 0315 0062;0061 05AE A8E0 0300 0315 0062;0061 05AE A8E0 0300 0315 0062;0061 05AE A8E0 0300 0315 0062; # (a◌꣠◌̕◌̀◌֮b; a◌֮◌꣠◌̀◌̕b; a◌֮◌꣠◌̀◌̕b; a◌֮◌꣠◌̀◌̕b; a◌֮◌꣠◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E1 0062;00E0 05AE A8E1 0315 0062;0061 05AE 0300 A8E1 0315 0062;00E0 05AE A8E1 0315 0062;0061 05AE 0300 A8E1 0315 0062; # (a◌̕◌̀◌֮◌꣡b; à◌֮◌꣡◌̕b; a◌֮◌̀◌꣡◌̕b; à◌֮◌꣡◌̕b; a◌֮◌̀◌꣡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT ONE, LATIN SMALL LETTER B +0061 A8E1 0315 0300 05AE 0062;0061 05AE A8E1 0300 0315 0062;0061 05AE A8E1 0300 0315 0062;0061 05AE A8E1 0300 0315 0062;0061 05AE A8E1 0300 0315 0062; # (a◌꣡◌̕◌̀◌֮b; a◌֮◌꣡◌̀◌̕b; a◌֮◌꣡◌̀◌̕b; a◌֮◌꣡◌̀◌̕b; a◌֮◌꣡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT ONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E2 0062;00E0 05AE A8E2 0315 0062;0061 05AE 0300 A8E2 0315 0062;00E0 05AE A8E2 0315 0062;0061 05AE 0300 A8E2 0315 0062; # (a◌̕◌̀◌֮◌꣢b; à◌֮◌꣢◌̕b; a◌֮◌̀◌꣢◌̕b; à◌֮◌꣢◌̕b; a◌֮◌̀◌꣢◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT TWO, LATIN SMALL LETTER B +0061 A8E2 0315 0300 05AE 0062;0061 05AE A8E2 0300 0315 0062;0061 05AE A8E2 0300 0315 0062;0061 05AE A8E2 0300 0315 0062;0061 05AE A8E2 0300 0315 0062; # (a◌꣢◌̕◌̀◌֮b; a◌֮◌꣢◌̀◌̕b; a◌֮◌꣢◌̀◌̕b; a◌֮◌꣢◌̀◌̕b; a◌֮◌꣢◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT TWO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E3 0062;00E0 05AE A8E3 0315 0062;0061 05AE 0300 A8E3 0315 0062;00E0 05AE A8E3 0315 0062;0061 05AE 0300 A8E3 0315 0062; # (a◌̕◌̀◌֮◌꣣b; à◌֮◌꣣◌̕b; a◌֮◌̀◌꣣◌̕b; à◌֮◌꣣◌̕b; a◌֮◌̀◌꣣◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT THREE, LATIN SMALL LETTER B +0061 A8E3 0315 0300 05AE 0062;0061 05AE A8E3 0300 0315 0062;0061 05AE A8E3 0300 0315 0062;0061 05AE A8E3 0300 0315 0062;0061 05AE A8E3 0300 0315 0062; # (a◌꣣◌̕◌̀◌֮b; a◌֮◌꣣◌̀◌̕b; a◌֮◌꣣◌̀◌̕b; a◌֮◌꣣◌̀◌̕b; a◌֮◌꣣◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT THREE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E4 0062;00E0 05AE A8E4 0315 0062;0061 05AE 0300 A8E4 0315 0062;00E0 05AE A8E4 0315 0062;0061 05AE 0300 A8E4 0315 0062; # (a◌̕◌̀◌֮◌꣤b; à◌֮◌꣤◌̕b; a◌֮◌̀◌꣤◌̕b; à◌֮◌꣤◌̕b; a◌֮◌̀◌꣤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT FOUR, LATIN SMALL LETTER B +0061 A8E4 0315 0300 05AE 0062;0061 05AE A8E4 0300 0315 0062;0061 05AE A8E4 0300 0315 0062;0061 05AE A8E4 0300 0315 0062;0061 05AE A8E4 0300 0315 0062; # (a◌꣤◌̕◌̀◌֮b; a◌֮◌꣤◌̀◌̕b; a◌֮◌꣤◌̀◌̕b; a◌֮◌꣤◌̀◌̕b; a◌֮◌꣤◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT FOUR, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E5 0062;00E0 05AE A8E5 0315 0062;0061 05AE 0300 A8E5 0315 0062;00E0 05AE A8E5 0315 0062;0061 05AE 0300 A8E5 0315 0062; # (a◌̕◌̀◌֮◌꣥b; à◌֮◌꣥◌̕b; a◌֮◌̀◌꣥◌̕b; à◌֮◌꣥◌̕b; a◌֮◌̀◌꣥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT FIVE, LATIN SMALL LETTER B +0061 A8E5 0315 0300 05AE 0062;0061 05AE A8E5 0300 0315 0062;0061 05AE A8E5 0300 0315 0062;0061 05AE A8E5 0300 0315 0062;0061 05AE A8E5 0300 0315 0062; # (a◌꣥◌̕◌̀◌֮b; a◌֮◌꣥◌̀◌̕b; a◌֮◌꣥◌̀◌̕b; a◌֮◌꣥◌̀◌̕b; a◌֮◌꣥◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT FIVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E6 0062;00E0 05AE A8E6 0315 0062;0061 05AE 0300 A8E6 0315 0062;00E0 05AE A8E6 0315 0062;0061 05AE 0300 A8E6 0315 0062; # (a◌̕◌̀◌֮◌꣦b; à◌֮◌꣦◌̕b; a◌֮◌̀◌꣦◌̕b; à◌֮◌꣦◌̕b; a◌֮◌̀◌꣦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT SIX, LATIN SMALL LETTER B +0061 A8E6 0315 0300 05AE 0062;0061 05AE A8E6 0300 0315 0062;0061 05AE A8E6 0300 0315 0062;0061 05AE A8E6 0300 0315 0062;0061 05AE A8E6 0300 0315 0062; # (a◌꣦◌̕◌̀◌֮b; a◌֮◌꣦◌̀◌̕b; a◌֮◌꣦◌̀◌̕b; a◌֮◌꣦◌̀◌̕b; a◌֮◌꣦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT SIX, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E7 0062;00E0 05AE A8E7 0315 0062;0061 05AE 0300 A8E7 0315 0062;00E0 05AE A8E7 0315 0062;0061 05AE 0300 A8E7 0315 0062; # (a◌̕◌̀◌֮◌꣧b; à◌֮◌꣧◌̕b; a◌֮◌̀◌꣧◌̕b; à◌֮◌꣧◌̕b; a◌֮◌̀◌꣧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT SEVEN, LATIN SMALL LETTER B +0061 A8E7 0315 0300 05AE 0062;0061 05AE A8E7 0300 0315 0062;0061 05AE A8E7 0300 0315 0062;0061 05AE A8E7 0300 0315 0062;0061 05AE A8E7 0300 0315 0062; # (a◌꣧◌̕◌̀◌֮b; a◌֮◌꣧◌̀◌̕b; a◌֮◌꣧◌̀◌̕b; a◌֮◌꣧◌̀◌̕b; a◌֮◌꣧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT SEVEN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E8 0062;00E0 05AE A8E8 0315 0062;0061 05AE 0300 A8E8 0315 0062;00E0 05AE A8E8 0315 0062;0061 05AE 0300 A8E8 0315 0062; # (a◌̕◌̀◌֮◌꣨b; à◌֮◌꣨◌̕b; a◌֮◌̀◌꣨◌̕b; à◌֮◌꣨◌̕b; a◌֮◌̀◌꣨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT EIGHT, LATIN SMALL LETTER B +0061 A8E8 0315 0300 05AE 0062;0061 05AE A8E8 0300 0315 0062;0061 05AE A8E8 0300 0315 0062;0061 05AE A8E8 0300 0315 0062;0061 05AE A8E8 0300 0315 0062; # (a◌꣨◌̕◌̀◌֮b; a◌֮◌꣨◌̀◌̕b; a◌֮◌꣨◌̀◌̕b; a◌֮◌꣨◌̀◌̕b; a◌֮◌꣨◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT EIGHT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8E9 0062;00E0 05AE A8E9 0315 0062;0061 05AE 0300 A8E9 0315 0062;00E0 05AE A8E9 0315 0062;0061 05AE 0300 A8E9 0315 0062; # (a◌̕◌̀◌֮◌꣩b; à◌֮◌꣩◌̕b; a◌֮◌̀◌꣩◌̕b; à◌֮◌꣩◌̕b; a◌֮◌̀◌꣩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI DIGIT NINE, LATIN SMALL LETTER B +0061 A8E9 0315 0300 05AE 0062;0061 05AE A8E9 0300 0315 0062;0061 05AE A8E9 0300 0315 0062;0061 05AE A8E9 0300 0315 0062;0061 05AE A8E9 0300 0315 0062; # (a◌꣩◌̕◌̀◌֮b; a◌֮◌꣩◌̀◌̕b; a◌֮◌꣩◌̀◌̕b; a◌֮◌꣩◌̀◌̕b; a◌֮◌꣩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI DIGIT NINE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8EA 0062;00E0 05AE A8EA 0315 0062;0061 05AE 0300 A8EA 0315 0062;00E0 05AE A8EA 0315 0062;0061 05AE 0300 A8EA 0315 0062; # (a◌̕◌̀◌֮◌꣪b; à◌֮◌꣪◌̕b; a◌֮◌̀◌꣪◌̕b; à◌֮◌꣪◌̕b; a◌֮◌̀◌꣪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER A, LATIN SMALL LETTER B +0061 A8EA 0315 0300 05AE 0062;0061 05AE A8EA 0300 0315 0062;0061 05AE A8EA 0300 0315 0062;0061 05AE A8EA 0300 0315 0062;0061 05AE A8EA 0300 0315 0062; # (a◌꣪◌̕◌̀◌֮b; a◌֮◌꣪◌̀◌̕b; a◌֮◌꣪◌̀◌̕b; a◌֮◌꣪◌̀◌̕b; a◌֮◌꣪◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8EB 0062;00E0 05AE A8EB 0315 0062;0061 05AE 0300 A8EB 0315 0062;00E0 05AE A8EB 0315 0062;0061 05AE 0300 A8EB 0315 0062; # (a◌̕◌̀◌֮◌꣫b; à◌֮◌꣫◌̕b; a◌֮◌̀◌꣫◌̕b; à◌֮◌꣫◌̕b; a◌֮◌̀◌꣫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER U, LATIN SMALL LETTER B +0061 A8EB 0315 0300 05AE 0062;0061 05AE A8EB 0300 0315 0062;0061 05AE A8EB 0300 0315 0062;0061 05AE A8EB 0300 0315 0062;0061 05AE A8EB 0300 0315 0062; # (a◌꣫◌̕◌̀◌֮b; a◌֮◌꣫◌̀◌̕b; a◌֮◌꣫◌̀◌̕b; a◌֮◌꣫◌̀◌̕b; a◌֮◌꣫◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER U, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8EC 0062;00E0 05AE A8EC 0315 0062;0061 05AE 0300 A8EC 0315 0062;00E0 05AE A8EC 0315 0062;0061 05AE 0300 A8EC 0315 0062; # (a◌̕◌̀◌֮◌꣬b; à◌֮◌꣬◌̕b; a◌֮◌̀◌꣬◌̕b; à◌֮◌꣬◌̕b; a◌֮◌̀◌꣬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER KA, LATIN SMALL LETTER B +0061 A8EC 0315 0300 05AE 0062;0061 05AE A8EC 0300 0315 0062;0061 05AE A8EC 0300 0315 0062;0061 05AE A8EC 0300 0315 0062;0061 05AE A8EC 0300 0315 0062; # (a◌꣬◌̕◌̀◌֮b; a◌֮◌꣬◌̀◌̕b; a◌֮◌꣬◌̀◌̕b; a◌֮◌꣬◌̀◌̕b; a◌֮◌꣬◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER KA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8ED 0062;00E0 05AE A8ED 0315 0062;0061 05AE 0300 A8ED 0315 0062;00E0 05AE A8ED 0315 0062;0061 05AE 0300 A8ED 0315 0062; # (a◌̕◌̀◌֮◌꣭b; à◌֮◌꣭◌̕b; a◌֮◌̀◌꣭◌̕b; à◌֮◌꣭◌̕b; a◌֮◌̀◌꣭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER NA, LATIN SMALL LETTER B +0061 A8ED 0315 0300 05AE 0062;0061 05AE A8ED 0300 0315 0062;0061 05AE A8ED 0300 0315 0062;0061 05AE A8ED 0300 0315 0062;0061 05AE A8ED 0300 0315 0062; # (a◌꣭◌̕◌̀◌֮b; a◌֮◌꣭◌̀◌̕b; a◌֮◌꣭◌̀◌̕b; a◌֮◌꣭◌̀◌̕b; a◌֮◌꣭◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER NA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8EE 0062;00E0 05AE A8EE 0315 0062;0061 05AE 0300 A8EE 0315 0062;00E0 05AE A8EE 0315 0062;0061 05AE 0300 A8EE 0315 0062; # (a◌̕◌̀◌֮◌꣮b; à◌֮◌꣮◌̕b; a◌֮◌̀◌꣮◌̕b; à◌֮◌꣮◌̕b; a◌֮◌̀◌꣮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER PA, LATIN SMALL LETTER B +0061 A8EE 0315 0300 05AE 0062;0061 05AE A8EE 0300 0315 0062;0061 05AE A8EE 0300 0315 0062;0061 05AE A8EE 0300 0315 0062;0061 05AE A8EE 0300 0315 0062; # (a◌꣮◌̕◌̀◌֮b; a◌֮◌꣮◌̀◌̕b; a◌֮◌꣮◌̀◌̕b; a◌֮◌꣮◌̀◌̕b; a◌֮◌꣮◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER PA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8EF 0062;00E0 05AE A8EF 0315 0062;0061 05AE 0300 A8EF 0315 0062;00E0 05AE A8EF 0315 0062;0061 05AE 0300 A8EF 0315 0062; # (a◌̕◌̀◌֮◌꣯b; à◌֮◌꣯◌̕b; a◌֮◌̀◌꣯◌̕b; à◌֮◌꣯◌̕b; a◌֮◌̀◌꣯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER RA, LATIN SMALL LETTER B +0061 A8EF 0315 0300 05AE 0062;0061 05AE A8EF 0300 0315 0062;0061 05AE A8EF 0300 0315 0062;0061 05AE A8EF 0300 0315 0062;0061 05AE A8EF 0300 0315 0062; # (a◌꣯◌̕◌̀◌֮b; a◌֮◌꣯◌̀◌̕b; a◌֮◌꣯◌̀◌̕b; a◌֮◌꣯◌̀◌̕b; a◌֮◌꣯◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER RA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8F0 0062;00E0 05AE A8F0 0315 0062;0061 05AE 0300 A8F0 0315 0062;00E0 05AE A8F0 0315 0062;0061 05AE 0300 A8F0 0315 0062; # (a◌̕◌̀◌֮◌꣰b; à◌֮◌꣰◌̕b; a◌֮◌̀◌꣰◌̕b; à◌֮◌꣰◌̕b; a◌֮◌̀◌꣰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI LETTER VI, LATIN SMALL LETTER B +0061 A8F0 0315 0300 05AE 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062; # (a◌꣰◌̕◌̀◌֮b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER VI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A8F1 0062;00E0 05AE A8F1 0315 0062;0061 05AE 0300 A8F1 0315 0062;00E0 05AE A8F1 0315 0062;0061 05AE 0300 A8F1 0315 0062; # (a◌̕◌̀◌֮◌꣱b; à◌֮◌꣱◌̕b; a◌֮◌̀◌꣱◌̕b; à◌֮◌꣱◌̕b; a◌֮◌̀◌꣱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI SIGN AVAGRAHA, LATIN SMALL LETTER B +0061 A8F1 0315 0300 05AE 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062; # (a◌꣱◌̕◌̀◌֮b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI SIGN AVAGRAHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92B 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062; # (a◌֚◌̖◌᷺◌꤫b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE PLOPHU, LATIN SMALL LETTER B +0061 A92B 059A 0316 1DFA 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062; # (a◌꤫◌֚◌̖◌᷺b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92C 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062; # (a◌֚◌̖◌᷺◌꤬b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE CALYA, LATIN SMALL LETTER B +0061 A92C 059A 0316 1DFA 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062; # (a◌꤬◌֚◌̖◌᷺b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92D 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062; # (a◌֚◌̖◌᷺◌꤭b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE CALYA PLOPHU, LATIN SMALL LETTER B +0061 A92D 059A 0316 1DFA 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062; # (a◌꤭◌֚◌̖◌᷺b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 05B0 094D 3099 A953 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062; # (a◌ְ◌्◌゙꥓b; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, REJANG VIRAMA, LATIN SMALL LETTER B +0061 A953 05B0 094D 3099 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062; # (a꥓◌ְ◌्◌゙b; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; ) LATIN SMALL LETTER A, REJANG VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 A9B3 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062; # (a◌゙◌𖿰़◌꦳b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, JAVANESE SIGN CECAK TELU, LATIN SMALL LETTER B +0061 A9B3 3099 093C 16FF0 0062;0061 16FF0 A9B3 093C 3099 0062;0061 16FF0 A9B3 093C 3099 0062;0061 16FF0 A9B3 093C 3099 0062;0061 16FF0 A9B3 093C 3099 0062; # (a◌꦳◌゙◌𖿰़b; a𖿰◌꦳◌़◌゙b; a𖿰◌꦳◌़◌゙b; a𖿰◌꦳◌़◌゙b; a𖿰◌꦳◌़◌゙b; ) LATIN SMALL LETTER A, JAVANESE SIGN CECAK TELU, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 A9C0 0062;0061 3099 094D A9C0 05B0 0062;0061 3099 094D A9C0 05B0 0062;0061 3099 094D A9C0 05B0 0062;0061 3099 094D A9C0 05B0 0062; # (a◌ְ◌्◌゙꧀b; a◌゙◌्꧀◌ְb; a◌゙◌्꧀◌ְb; a◌゙◌्꧀◌ְb; a◌゙◌्꧀◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, JAVANESE PANGKON, LATIN SMALL LETTER B +0061 A9C0 05B0 094D 3099 0062;0061 3099 A9C0 094D 05B0 0062;0061 3099 A9C0 094D 05B0 0062;0061 3099 A9C0 094D 05B0 0062;0061 3099 A9C0 094D 05B0 0062; # (a꧀◌ְ◌्◌゙b; a◌゙꧀◌्◌ְb; a◌゙꧀◌्◌ְb; a◌゙꧀◌्◌ְb; a◌゙꧀◌्◌ְb; ) LATIN SMALL LETTER A, JAVANESE PANGKON, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE AAB0 0062;00E0 05AE AAB0 0315 0062;0061 05AE 0300 AAB0 0315 0062;00E0 05AE AAB0 0315 0062;0061 05AE 0300 AAB0 0315 0062; # (a◌̕◌̀◌֮◌ꪰb; à◌֮◌ꪰ◌̕b; a◌֮◌̀◌ꪰ◌̕b; à◌֮◌ꪰ◌̕b; a◌֮◌̀◌ꪰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET MAI KANG, LATIN SMALL LETTER B +0061 AAB0 0315 0300 05AE 0062;0061 05AE AAB0 0300 0315 0062;0061 05AE AAB0 0300 0315 0062;0061 05AE AAB0 0300 0315 0062;0061 05AE AAB0 0300 0315 0062; # (a◌ꪰ◌̕◌̀◌֮b; a◌֮◌ꪰ◌̀◌̕b; a◌֮◌ꪰ◌̀◌̕b; a◌֮◌ꪰ◌̀◌̕b; a◌֮◌ꪰ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET MAI KANG, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AAB2 0062;00E0 05AE AAB2 0315 0062;0061 05AE 0300 AAB2 0315 0062;00E0 05AE AAB2 0315 0062;0061 05AE 0300 AAB2 0315 0062; # (a◌̕◌̀◌֮◌ꪲb; à◌֮◌ꪲ◌̕b; a◌֮◌̀◌ꪲ◌̕b; à◌֮◌ꪲ◌̕b; a◌֮◌̀◌ꪲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL I, LATIN SMALL LETTER B +0061 AAB2 0315 0300 05AE 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062; # (a◌ꪲ◌̕◌̀◌֮b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AAB3 0062;00E0 05AE AAB3 0315 0062;0061 05AE 0300 AAB3 0315 0062;00E0 05AE AAB3 0315 0062;0061 05AE 0300 AAB3 0315 0062; # (a◌̕◌̀◌֮◌ꪳb; à◌֮◌ꪳ◌̕b; a◌֮◌̀◌ꪳ◌̕b; à◌֮◌ꪳ◌̕b; a◌֮◌̀◌ꪳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL UE, LATIN SMALL LETTER B +0061 AAB3 0315 0300 05AE 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062; # (a◌ꪳ◌̕◌̀◌֮b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL UE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA AAB4 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062; # (a◌֚◌̖◌᷺◌ꪴb; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TAI VIET VOWEL U, LATIN SMALL LETTER B +0061 AAB4 059A 0316 1DFA 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062; # (a◌ꪴ◌֚◌̖◌᷺b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; ) LATIN SMALL LETTER A, TAI VIET VOWEL U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE AAB7 0062;00E0 05AE AAB7 0315 0062;0061 05AE 0300 AAB7 0315 0062;00E0 05AE AAB7 0315 0062;0061 05AE 0300 AAB7 0315 0062; # (a◌̕◌̀◌֮◌ꪷb; à◌֮◌ꪷ◌̕b; a◌֮◌̀◌ꪷ◌̕b; à◌֮◌ꪷ◌̕b; a◌֮◌̀◌ꪷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET MAI KHIT, LATIN SMALL LETTER B +0061 AAB7 0315 0300 05AE 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062; # (a◌ꪷ◌̕◌̀◌֮b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET MAI KHIT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AAB8 0062;00E0 05AE AAB8 0315 0062;0061 05AE 0300 AAB8 0315 0062;00E0 05AE AAB8 0315 0062;0061 05AE 0300 AAB8 0315 0062; # (a◌̕◌̀◌֮◌ꪸb; à◌֮◌ꪸ◌̕b; a◌֮◌̀◌ꪸ◌̕b; à◌֮◌ꪸ◌̕b; a◌֮◌̀◌ꪸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL IA, LATIN SMALL LETTER B +0061 AAB8 0315 0300 05AE 0062;0061 05AE AAB8 0300 0315 0062;0061 05AE AAB8 0300 0315 0062;0061 05AE AAB8 0300 0315 0062;0061 05AE AAB8 0300 0315 0062; # (a◌ꪸ◌̕◌̀◌֮b; a◌֮◌ꪸ◌̀◌̕b; a◌֮◌ꪸ◌̀◌̕b; a◌֮◌ꪸ◌̀◌̕b; a◌֮◌ꪸ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL IA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AABE 0062;00E0 05AE AABE 0315 0062;0061 05AE 0300 AABE 0315 0062;00E0 05AE AABE 0315 0062;0061 05AE 0300 AABE 0315 0062; # (a◌̕◌̀◌֮◌ꪾb; à◌֮◌ꪾ◌̕b; a◌֮◌̀◌ꪾ◌̕b; à◌֮◌ꪾ◌̕b; a◌֮◌̀◌ꪾ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL AM, LATIN SMALL LETTER B +0061 AABE 0315 0300 05AE 0062;0061 05AE AABE 0300 0315 0062;0061 05AE AABE 0300 0315 0062;0061 05AE AABE 0300 0315 0062;0061 05AE AABE 0300 0315 0062; # (a◌ꪾ◌̕◌̀◌֮b; a◌֮◌ꪾ◌̀◌̕b; a◌֮◌ꪾ◌̀◌̕b; a◌֮◌ꪾ◌̀◌̕b; a◌֮◌ꪾ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL AM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AABF 0062;00E0 05AE AABF 0315 0062;0061 05AE 0300 AABF 0315 0062;00E0 05AE AABF 0315 0062;0061 05AE 0300 AABF 0315 0062; # (a◌̕◌̀◌֮◌꪿b; à◌֮◌꪿◌̕b; a◌֮◌̀◌꪿◌̕b; à◌֮◌꪿◌̕b; a◌֮◌̀◌꪿◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET TONE MAI EK, LATIN SMALL LETTER B +0061 AABF 0315 0300 05AE 0062;0061 05AE AABF 0300 0315 0062;0061 05AE AABF 0300 0315 0062;0061 05AE AABF 0300 0315 0062;0061 05AE AABF 0300 0315 0062; # (a◌꪿◌̕◌̀◌֮b; a◌֮◌꪿◌̀◌̕b; a◌֮◌꪿◌̀◌̕b; a◌֮◌꪿◌̀◌̕b; a◌֮◌꪿◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET TONE MAI EK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE AAC1 0062;00E0 05AE AAC1 0315 0062;0061 05AE 0300 AAC1 0315 0062;00E0 05AE AAC1 0315 0062;0061 05AE 0300 AAC1 0315 0062; # (a◌̕◌̀◌֮◌꫁b; à◌֮◌꫁◌̕b; a◌֮◌̀◌꫁◌̕b; à◌֮◌꫁◌̕b; a◌֮◌̀◌꫁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET TONE MAI THO, LATIN SMALL LETTER B +0061 AAC1 0315 0300 05AE 0062;0061 05AE AAC1 0300 0315 0062;0061 05AE AAC1 0300 0315 0062;0061 05AE AAC1 0300 0315 0062;0061 05AE AAC1 0300 0315 0062; # (a◌꫁◌̕◌̀◌֮b; a◌֮◌꫁◌̀◌̕b; a◌֮◌꫁◌̀◌̕b; a◌֮◌꫁◌̀◌̕b; a◌֮◌꫁◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET TONE MAI THO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 AAF6 0062;0061 3099 094D AAF6 05B0 0062;0061 3099 094D AAF6 05B0 0062;0061 3099 094D AAF6 05B0 0062;0061 3099 094D AAF6 05B0 0062; # (a◌ְ◌्◌゙◌꫶b; a◌゙◌्◌꫶◌ְb; a◌゙◌्◌꫶◌ְb; a◌゙◌्◌꫶◌ְb; a◌゙◌्◌꫶◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MEETEI MAYEK VIRAMA, LATIN SMALL LETTER B +0061 AAF6 05B0 094D 3099 0062;0061 3099 AAF6 094D 05B0 0062;0061 3099 AAF6 094D 05B0 0062;0061 3099 AAF6 094D 05B0 0062;0061 3099 AAF6 094D 05B0 0062; # (a◌꫶◌ְ◌्◌゙b; a◌゙◌꫶◌्◌ְb; a◌゙◌꫶◌्◌ְb; a◌゙◌꫶◌्◌ְb; a◌゙◌꫶◌्◌ְb; ) LATIN SMALL LETTER A, MEETEI MAYEK VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 ABED 0062;0061 3099 094D ABED 05B0 0062;0061 3099 094D ABED 05B0 0062;0061 3099 094D ABED 05B0 0062;0061 3099 094D ABED 05B0 0062; # (a◌ְ◌्◌゙◌꯭b; a◌゙◌्◌꯭◌ְb; a◌゙◌्◌꯭◌ְb; a◌゙◌्◌꯭◌ְb; a◌゙◌्◌꯭◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MEETEI MAYEK APUN IYEK, LATIN SMALL LETTER B +0061 ABED 05B0 094D 3099 0062;0061 3099 ABED 094D 05B0 0062;0061 3099 ABED 094D 05B0 0062;0061 3099 ABED 094D 05B0 0062;0061 3099 ABED 094D 05B0 0062; # (a◌꯭◌ְ◌्◌゙b; a◌゙◌꯭◌्◌ְb; a◌゙◌꯭◌्◌ְb; a◌゙◌꯭◌्◌ְb; a◌゙◌꯭◌्◌ְb; ) LATIN SMALL LETTER A, MEETEI MAYEK APUN IYEK, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 064B FB1E 05C2 FB1E 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062; # (a◌ً◌ﬞ◌ׂ◌ﬞb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; ) LATIN SMALL LETTER A, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B +0061 FB1E 064B FB1E 05C2 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062;0061 05C2 FB1E FB1E 064B 0062; # (a◌ﬞ◌ً◌ﬞ◌ׂb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; a◌ׂ◌ﬞ◌ﬞ◌ًb; ) LATIN SMALL LETTER A, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, LATIN SMALL LETTER B +0061 0315 0300 05AE FE20 0062;00E0 05AE FE20 0315 0062;0061 05AE 0300 FE20 0315 0062;00E0 05AE FE20 0315 0062;0061 05AE 0300 FE20 0315 0062; # (a◌̕◌̀◌֮◌︠b; à◌֮◌︠◌̕b; a◌֮◌̀◌︠◌̕b; à◌֮◌︠◌̕b; a◌֮◌̀◌︠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LIGATURE LEFT HALF, LATIN SMALL LETTER B +0061 FE20 0315 0300 05AE 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062;0061 05AE FE20 0300 0315 0062; # (a◌︠◌̕◌̀◌֮b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; a◌֮◌︠◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LIGATURE LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE21 0062;00E0 05AE FE21 0315 0062;0061 05AE 0300 FE21 0315 0062;00E0 05AE FE21 0315 0062;0061 05AE 0300 FE21 0315 0062; # (a◌̕◌̀◌֮◌︡b; à◌֮◌︡◌̕b; a◌֮◌̀◌︡◌̕b; à◌֮◌︡◌̕b; a◌֮◌̀◌︡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LIGATURE RIGHT HALF, LATIN SMALL LETTER B +0061 FE21 0315 0300 05AE 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062;0061 05AE FE21 0300 0315 0062; # (a◌︡◌̕◌̀◌֮b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; a◌֮◌︡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LIGATURE RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE22 0062;00E0 05AE FE22 0315 0062;0061 05AE 0300 FE22 0315 0062;00E0 05AE FE22 0315 0062;0061 05AE 0300 FE22 0315 0062; # (a◌̕◌̀◌֮◌︢b; à◌֮◌︢◌̕b; a◌֮◌̀◌︢◌̕b; à◌֮◌︢◌̕b; a◌֮◌̀◌︢◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE TILDE LEFT HALF, LATIN SMALL LETTER B +0061 FE22 0315 0300 05AE 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062;0061 05AE FE22 0300 0315 0062; # (a◌︢◌̕◌̀◌֮b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; a◌֮◌︢◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE23 0062;00E0 05AE FE23 0315 0062;0061 05AE 0300 FE23 0315 0062;00E0 05AE FE23 0315 0062;0061 05AE 0300 FE23 0315 0062; # (a◌̕◌̀◌֮◌︣b; à◌֮◌︣◌̕b; a◌֮◌̀◌︣◌̕b; à◌֮◌︣◌̕b; a◌֮◌̀◌︣◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE TILDE RIGHT HALF, LATIN SMALL LETTER B +0061 FE23 0315 0300 05AE 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062;0061 05AE FE23 0300 0315 0062; # (a◌︣◌̕◌̀◌֮b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; a◌֮◌︣◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE TILDE RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE24 0062;00E0 05AE FE24 0315 0062;0061 05AE 0300 FE24 0315 0062;00E0 05AE FE24 0315 0062;0061 05AE 0300 FE24 0315 0062; # (a◌̕◌̀◌֮◌︤b; à◌֮◌︤◌̕b; a◌֮◌̀◌︤◌̕b; à◌֮◌︤◌̕b; a◌֮◌̀◌︤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON LEFT HALF, LATIN SMALL LETTER B +0061 FE24 0315 0300 05AE 0062;0061 05AE FE24 0300 0315 0062;0061 05AE FE24 0300 0315 0062;0061 05AE FE24 0300 0315 0062;0061 05AE FE24 0300 0315 0062; # (a◌︤◌̕◌̀◌֮b; a◌֮◌︤◌̀◌̕b; a◌֮◌︤◌̀◌̕b; a◌֮◌︤◌̀◌̕b; a◌֮◌︤◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE25 0062;00E0 05AE FE25 0315 0062;0061 05AE 0300 FE25 0315 0062;00E0 05AE FE25 0315 0062;0061 05AE 0300 FE25 0315 0062; # (a◌̕◌̀◌֮◌︥b; à◌֮◌︥◌̕b; a◌֮◌̀◌︥◌̕b; à◌֮◌︥◌̕b; a◌֮◌̀◌︥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON RIGHT HALF, LATIN SMALL LETTER B +0061 FE25 0315 0300 05AE 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062; # (a◌︥◌̕◌̀◌֮b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE26 0062;00E0 05AE FE26 0315 0062;0061 05AE 0300 FE26 0315 0062;00E0 05AE FE26 0315 0062;0061 05AE 0300 FE26 0315 0062; # (a◌̕◌̀◌֮◌︦b; à◌֮◌︦◌̕b; a◌֮◌̀◌︦◌̕b; à◌֮◌︦◌̕b; a◌֮◌̀◌︦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CONJOINING MACRON, LATIN SMALL LETTER B +0061 FE26 0315 0300 05AE 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062; # (a◌︦◌̕◌̀◌֮b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE27 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062; # (a◌֚◌̖◌᷺◌︧b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGATURE LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE27 059A 0316 1DFA 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062; # (a◌︧◌֚◌̖◌᷺b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE28 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062; # (a◌֚◌̖◌᷺◌︨b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGATURE RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE28 059A 0316 1DFA 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062; # (a◌︨◌֚◌̖◌᷺b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE29 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062; # (a◌֚◌̖◌᷺◌︩b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE29 059A 0316 1DFA 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062; # (a◌︩◌֚◌̖◌᷺b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062; # (a◌֚◌̖◌᷺◌︪b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE2A 059A 0316 1DFA 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062; # (a◌︪◌֚◌̖◌᷺b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2B 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062; # (a◌֚◌̖◌᷺◌︫b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE2B 059A 0316 1DFA 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062; # (a◌︫◌֚◌̖◌᷺b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2C 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062; # (a◌֚◌̖◌᷺◌︬b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE2C 059A 0316 1DFA 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062; # (a◌︬◌֚◌̖◌᷺b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2D 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062; # (a◌֚◌̖◌᷺◌︭b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CONJOINING MACRON BELOW, LATIN SMALL LETTER B +0061 FE2D 059A 0316 1DFA 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062; # (a◌︭◌֚◌̖◌᷺b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE FE2E 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062; # (a◌̕◌̀◌֮◌︮b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO LEFT HALF, LATIN SMALL LETTER B +0061 FE2E 0315 0300 05AE 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062; # (a◌︮◌̕◌̀◌֮b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE2F 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062; # (a◌̕◌̀◌֮◌︯b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO RIGHT HALF, LATIN SMALL LETTER B +0061 FE2F 0315 0300 05AE 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062; # (a◌︯◌̕◌̀◌֮b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 101FD 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062; # (a◌֚◌̖◌᷺◌𐇽b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, LATIN SMALL LETTER B +0061 101FD 059A 0316 1DFA 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062; # (a◌𐇽◌֚◌̖◌᷺b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; ) LATIN SMALL LETTER A, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 102E0 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062; # (a◌֚◌̖◌᷺◌𐋠b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COPTIC EPACT THOUSANDS MARK, LATIN SMALL LETTER B +0061 102E0 059A 0316 1DFA 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062; # (a◌𐋠◌֚◌̖◌᷺b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; ) LATIN SMALL LETTER A, COPTIC EPACT THOUSANDS MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10376 0062;00E0 05AE 10376 0315 0062;0061 05AE 0300 10376 0315 0062;00E0 05AE 10376 0315 0062;0061 05AE 0300 10376 0315 0062; # (a◌̕◌̀◌֮◌𐍶b; à◌֮◌𐍶◌̕b; a◌֮◌̀◌𐍶◌̕b; à◌֮◌𐍶◌̕b; a◌֮◌̀◌𐍶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER AN, LATIN SMALL LETTER B +0061 10376 0315 0300 05AE 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062; # (a◌𐍶◌̕◌̀◌֮b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER AN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10377 0062;00E0 05AE 10377 0315 0062;0061 05AE 0300 10377 0315 0062;00E0 05AE 10377 0315 0062;0061 05AE 0300 10377 0315 0062; # (a◌̕◌̀◌֮◌𐍷b; à◌֮◌𐍷◌̕b; a◌֮◌̀◌𐍷◌̕b; à◌֮◌𐍷◌̕b; a◌֮◌̀◌𐍷◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER DOI, LATIN SMALL LETTER B +0061 10377 0315 0300 05AE 0062;0061 05AE 10377 0300 0315 0062;0061 05AE 10377 0300 0315 0062;0061 05AE 10377 0300 0315 0062;0061 05AE 10377 0300 0315 0062; # (a◌𐍷◌̕◌̀◌֮b; a◌֮◌𐍷◌̀◌̕b; a◌֮◌𐍷◌̀◌̕b; a◌֮◌𐍷◌̀◌̕b; a◌֮◌𐍷◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER DOI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10378 0062;00E0 05AE 10378 0315 0062;0061 05AE 0300 10378 0315 0062;00E0 05AE 10378 0315 0062;0061 05AE 0300 10378 0315 0062; # (a◌̕◌̀◌֮◌𐍸b; à◌֮◌𐍸◌̕b; a◌֮◌̀◌𐍸◌̕b; à◌֮◌𐍸◌̕b; a◌֮◌̀◌𐍸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER ZATA, LATIN SMALL LETTER B +0061 10378 0315 0300 05AE 0062;0061 05AE 10378 0300 0315 0062;0061 05AE 10378 0300 0315 0062;0061 05AE 10378 0300 0315 0062;0061 05AE 10378 0300 0315 0062; # (a◌𐍸◌̕◌̀◌֮b; a◌֮◌𐍸◌̀◌̕b; a◌֮◌𐍸◌̀◌̕b; a◌֮◌𐍸◌̀◌̕b; a◌֮◌𐍸◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER ZATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10379 0062;00E0 05AE 10379 0315 0062;0061 05AE 0300 10379 0315 0062;00E0 05AE 10379 0315 0062;0061 05AE 0300 10379 0315 0062; # (a◌̕◌̀◌֮◌𐍹b; à◌֮◌𐍹◌̕b; a◌֮◌̀◌𐍹◌̕b; à◌֮◌𐍹◌̕b; a◌֮◌̀◌𐍹◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER NENOE, LATIN SMALL LETTER B +0061 10379 0315 0300 05AE 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062; # (a◌𐍹◌̕◌̀◌֮b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER NENOE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1037A 0062;00E0 05AE 1037A 0315 0062;0061 05AE 0300 1037A 0315 0062;00E0 05AE 1037A 0315 0062;0061 05AE 0300 1037A 0315 0062; # (a◌̕◌̀◌֮◌𐍺b; à◌֮◌𐍺◌̕b; a◌֮◌̀◌𐍺◌̕b; à◌֮◌𐍺◌̕b; a◌֮◌̀◌𐍺◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER SII, LATIN SMALL LETTER B +0061 1037A 0315 0300 05AE 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062; # (a◌𐍺◌̕◌̀◌֮b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER SII, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10A0D 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062; # (a◌֚◌̖◌᷺◌𐨍b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KHAROSHTHI SIGN DOUBLE RING BELOW, LATIN SMALL LETTER B +0061 10A0D 059A 0316 1DFA 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062; # (a◌𐨍◌֚◌̖◌᷺b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10A0F 0062;00E0 05AE 10A0F 0315 0062;0061 05AE 0300 10A0F 0315 0062;00E0 05AE 10A0F 0315 0062;0061 05AE 0300 10A0F 0315 0062; # (a◌̕◌̀◌֮◌𐨏b; à◌֮◌𐨏◌̕b; a◌֮◌̀◌𐨏◌̕b; à◌֮◌𐨏◌̕b; a◌֮◌̀◌𐨏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHAROSHTHI SIGN VISARGA, LATIN SMALL LETTER B +0061 10A0F 0315 0300 05AE 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062; # (a◌𐨏◌̕◌̀◌֮b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN VISARGA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10A38 0062;00E0 05AE 10A38 0315 0062;0061 05AE 0300 10A38 0315 0062;00E0 05AE 10A38 0315 0062;0061 05AE 0300 10A38 0315 0062; # (a◌̕◌̀◌֮◌𐨸b; à◌֮◌𐨸◌̕b; a◌֮◌̀◌𐨸◌̕b; à◌֮◌𐨸◌̕b; a◌֮◌̀◌𐨸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHAROSHTHI SIGN BAR ABOVE, LATIN SMALL LETTER B +0061 10A38 0315 0300 05AE 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062; # (a◌𐨸◌̕◌̀◌֮b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN BAR ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 16FF0 0334 10A39 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062; # (a𖿰◌̴◌𐨹b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, KHAROSHTHI SIGN CAUDA, LATIN SMALL LETTER B +0061 10A39 16FF0 0334 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062; # (a◌𐨹𖿰◌̴b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN CAUDA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10A3A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062; # (a◌֚◌̖◌᷺◌𐨺b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KHAROSHTHI SIGN DOT BELOW, LATIN SMALL LETTER B +0061 10A3A 059A 0316 1DFA 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062; # (a◌𐨺◌֚◌̖◌᷺b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 05B0 094D 3099 10A3F 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062; # (a◌ְ◌्◌゙◌𐨿b; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHAROSHTHI VIRAMA, LATIN SMALL LETTER B +0061 10A3F 05B0 094D 3099 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062; # (a◌𐨿◌ְ◌्◌゙b; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; ) LATIN SMALL LETTER A, KHAROSHTHI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 10AE5 0062;00E0 05AE 10AE5 0315 0062;0061 05AE 0300 10AE5 0315 0062;00E0 05AE 10AE5 0315 0062;0061 05AE 0300 10AE5 0315 0062; # (a◌̕◌̀◌֮◌𐫥b; à◌֮◌𐫥◌̕b; a◌֮◌̀◌𐫥◌̕b; à◌֮◌𐫥◌̕b; a◌֮◌̀◌𐫥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MANICHAEAN ABBREVIATION MARK ABOVE, LATIN SMALL LETTER B +0061 10AE5 0315 0300 05AE 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062; # (a◌𐫥◌̕◌̀◌֮b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10AE6 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062; # (a◌֚◌̖◌᷺◌𐫦b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANICHAEAN ABBREVIATION MARK BELOW, LATIN SMALL LETTER B +0061 10AE6 059A 0316 1DFA 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062; # (a◌𐫦◌֚◌̖◌᷺b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10D24 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062; # (a◌̕◌̀◌֮◌𐴤b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN HARBAHAY, LATIN SMALL LETTER B +0061 10D24 0315 0300 05AE 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062; # (a◌𐴤◌̕◌̀◌֮b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN HARBAHAY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10D25 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062; # (a◌̕◌̀◌֮◌𐴥b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TAHALA, LATIN SMALL LETTER B +0061 10D25 0315 0300 05AE 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062; # (a◌𐴥◌̕◌̀◌֮b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TAHALA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10D26 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062; # (a◌̕◌̀◌֮◌𐴦b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TANA, LATIN SMALL LETTER B +0061 10D26 0315 0300 05AE 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062; # (a◌𐴦◌̕◌̀◌֮b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10D27 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062; # (a◌̕◌̀◌֮◌𐴧b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TASSI, LATIN SMALL LETTER B +0061 10D27 0315 0300 05AE 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062; # (a◌𐴧◌̕◌̀◌֮b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TASSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10EAB 0062;00E0 05AE 10EAB 0315 0062;0061 05AE 0300 10EAB 0315 0062;00E0 05AE 10EAB 0315 0062;0061 05AE 0300 10EAB 0315 0062; # (a◌̕◌̀◌֮◌𐺫b; à◌֮◌𐺫◌̕b; a◌֮◌̀◌𐺫◌̕b; à◌֮◌𐺫◌̕b; a◌֮◌̀◌𐺫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, YEZIDI COMBINING HAMZA MARK, LATIN SMALL LETTER B +0061 10EAB 0315 0300 05AE 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062; # (a◌𐺫◌̕◌̀◌֮b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; ) LATIN SMALL LETTER A, YEZIDI COMBINING HAMZA MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10EAC 0062;00E0 05AE 10EAC 0315 0062;0061 05AE 0300 10EAC 0315 0062;00E0 05AE 10EAC 0315 0062;0061 05AE 0300 10EAC 0315 0062; # (a◌̕◌̀◌֮◌𐺬b; à◌֮◌𐺬◌̕b; a◌֮◌̀◌𐺬◌̕b; à◌֮◌𐺬◌̕b; a◌֮◌̀◌𐺬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, YEZIDI COMBINING MADDA MARK, LATIN SMALL LETTER B +0061 10EAC 0315 0300 05AE 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062; # (a◌𐺬◌̕◌̀◌֮b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; ) LATIN SMALL LETTER A, YEZIDI COMBINING MADDA MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F46 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062; # (a◌֚◌̖◌᷺◌𐽆b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 10F46 059A 0316 1DFA 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062; # (a◌𐽆◌֚◌̖◌᷺b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F47 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062; # (a◌֚◌̖◌᷺◌𐽇b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B +0061 10F47 059A 0316 1DFA 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062; # (a◌𐽇◌֚◌̖◌᷺b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F48 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062; # (a◌̕◌̀◌֮◌𐽈b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING DOT ABOVE, LATIN SMALL LETTER B +0061 10F48 0315 0300 05AE 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062; # (a◌𐽈◌̕◌̀◌֮b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F49 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062; # (a◌̕◌̀◌֮◌𐽉b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B +0061 10F49 0315 0300 05AE 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062; # (a◌𐽉◌̕◌̀◌֮b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F4A 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062; # (a◌̕◌̀◌֮◌𐽊b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING CURVE ABOVE, LATIN SMALL LETTER B +0061 10F4A 0315 0300 05AE 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062; # (a◌𐽊◌̕◌̀◌֮b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4B 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062; # (a◌֚◌̖◌᷺◌𐽋b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING CURVE BELOW, LATIN SMALL LETTER B +0061 10F4B 059A 0316 1DFA 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062; # (a◌𐽋◌֚◌̖◌᷺b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F4C 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062; # (a◌̕◌̀◌֮◌𐽌b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING HOOK ABOVE, LATIN SMALL LETTER B +0061 10F4C 0315 0300 05AE 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062; # (a◌𐽌◌̕◌̀◌֮b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4D 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062; # (a◌֚◌̖◌᷺◌𐽍b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING HOOK BELOW, LATIN SMALL LETTER B +0061 10F4D 059A 0316 1DFA 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062; # (a◌𐽍◌֚◌̖◌᷺b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4E 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062; # (a◌֚◌̖◌᷺◌𐽎b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING LONG HOOK BELOW, LATIN SMALL LETTER B +0061 10F4E 059A 0316 1DFA 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062; # (a◌𐽎◌֚◌̖◌᷺b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING LONG HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4F 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062; # (a◌֚◌̖◌᷺◌𐽏b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING RESH BELOW, LATIN SMALL LETTER B +0061 10F4F 059A 0316 1DFA 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062; # (a◌𐽏◌֚◌̖◌᷺b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING RESH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F50 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062; # (a◌֚◌̖◌᷺◌𐽐b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING STROKE BELOW, LATIN SMALL LETTER B +0061 10F50 059A 0316 1DFA 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062; # (a◌𐽐◌֚◌̖◌᷺b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F82 0062;00E0 05AE 10F82 0315 0062;0061 05AE 0300 10F82 0315 0062;00E0 05AE 10F82 0315 0062;0061 05AE 0300 10F82 0315 0062; # (a◌̕◌̀◌֮◌𐾂b; à◌֮◌𐾂◌̕b; a◌֮◌̀◌𐾂◌̕b; à◌֮◌𐾂◌̕b; a◌֮◌̀◌𐾂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, OLD UYGHUR COMBINING DOT ABOVE, LATIN SMALL LETTER B +0061 10F82 0315 0300 05AE 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062; # (a◌𐾂◌̕◌̀◌֮b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F83 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062; # (a◌֚◌̖◌᷺◌𐾃b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, OLD UYGHUR COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 10F83 059A 0316 1DFA 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062; # (a◌𐾃◌֚◌̖◌᷺b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F84 0062;00E0 05AE 10F84 0315 0062;0061 05AE 0300 10F84 0315 0062;00E0 05AE 10F84 0315 0062;0061 05AE 0300 10F84 0315 0062; # (a◌̕◌̀◌֮◌𐾄b; à◌֮◌𐾄◌̕b; a◌֮◌̀◌𐾄◌̕b; à◌֮◌𐾄◌̕b; a◌֮◌̀◌𐾄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, OLD UYGHUR COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B +0061 10F84 0315 0300 05AE 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062; # (a◌𐾄◌̕◌̀◌֮b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F85 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062; # (a◌֚◌̖◌᷺◌𐾅b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, OLD UYGHUR COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B +0061 10F85 059A 0316 1DFA 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062; # (a◌𐾅◌֚◌̖◌᷺b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 05B0 094D 3099 11046 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062; # (a◌ְ◌्◌゙◌𑁆b; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI VIRAMA, LATIN SMALL LETTER B +0061 11046 05B0 094D 3099 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062; # (a◌𑁆◌ְ◌्◌゙b; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11070 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062; # (a◌ְ◌्◌゙◌𑁰b; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI SIGN OLD TAMIL VIRAMA, LATIN SMALL LETTER B +0061 11070 05B0 094D 3099 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062; # (a◌𑁰◌ְ◌्◌゙b; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI SIGN OLD TAMIL VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1107F 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062; # (a◌ְ◌्◌゙◌𑁿b; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI NUMBER JOINER, LATIN SMALL LETTER B +0061 1107F 05B0 094D 3099 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062; # (a◌𑁿◌ְ◌्◌゙b; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI NUMBER JOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 110B9 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062; # (a◌ְ◌्◌゙◌𑂹b; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KAITHI SIGN VIRAMA, LATIN SMALL LETTER B +0061 110B9 05B0 094D 3099 0062;0061 3099 110B9 094D 05B0 0062;0061 3099 110B9 094D 05B0 0062;0061 3099 110B9 094D 05B0 0062;0061 3099 110B9 094D 05B0 0062; # (a◌𑂹◌ְ◌्◌゙b; a◌゙◌𑂹◌्◌ְb; a◌゙◌𑂹◌्◌ְb; a◌゙◌𑂹◌्◌ְb; a◌゙◌𑂹◌्◌ְb; ) LATIN SMALL LETTER A, KAITHI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 110BA 0062;0061 16FF0 093C 110BA 3099 0062;0061 16FF0 093C 110BA 3099 0062;0061 16FF0 093C 110BA 3099 0062;0061 16FF0 093C 110BA 3099 0062; # (a◌゙◌𖿰़◌𑂺b; a𖿰◌़◌𑂺◌゙b; a𖿰◌़◌𑂺◌゙b; a𖿰◌़◌𑂺◌゙b; a𖿰◌़◌𑂺◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, KAITHI SIGN NUKTA, LATIN SMALL LETTER B +0061 110BA 3099 093C 16FF0 0062;0061 16FF0 110BA 093C 3099 0062;0061 16FF0 110BA 093C 3099 0062;0061 16FF0 110BA 093C 3099 0062;0061 16FF0 110BA 093C 3099 0062; # (a◌𑂺◌゙◌𖿰़b; a𖿰◌𑂺◌़◌゙b; a𖿰◌𑂺◌़◌゙b; a𖿰◌𑂺◌़◌゙b; a𖿰◌𑂺◌़◌゙b; ) LATIN SMALL LETTER A, KAITHI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 0315 0300 05AE 11100 0062;00E0 05AE 11100 0315 0062;0061 05AE 0300 11100 0315 0062;00E0 05AE 11100 0315 0062;0061 05AE 0300 11100 0315 0062; # (a◌̕◌̀◌֮◌𑄀b; à◌֮◌𑄀◌̕b; a◌֮◌̀◌𑄀◌̕b; à◌֮◌𑄀◌̕b; a◌֮◌̀◌𑄀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, CHAKMA SIGN CANDRABINDU, LATIN SMALL LETTER B +0061 11100 0315 0300 05AE 0062;0061 05AE 11100 0300 0315 0062;0061 05AE 11100 0300 0315 0062;0061 05AE 11100 0300 0315 0062;0061 05AE 11100 0300 0315 0062; # (a◌𑄀◌̕◌̀◌֮b; a◌֮◌𑄀◌̀◌̕b; a◌֮◌𑄀◌̀◌̕b; a◌֮◌𑄀◌̀◌̕b; a◌֮◌𑄀◌̀◌̕b; ) LATIN SMALL LETTER A, CHAKMA SIGN CANDRABINDU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11101 0062;00E0 05AE 11101 0315 0062;0061 05AE 0300 11101 0315 0062;00E0 05AE 11101 0315 0062;0061 05AE 0300 11101 0315 0062; # (a◌̕◌̀◌֮◌𑄁b; à◌֮◌𑄁◌̕b; a◌֮◌̀◌𑄁◌̕b; à◌֮◌𑄁◌̕b; a◌֮◌̀◌𑄁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, CHAKMA SIGN ANUSVARA, LATIN SMALL LETTER B +0061 11101 0315 0300 05AE 0062;0061 05AE 11101 0300 0315 0062;0061 05AE 11101 0300 0315 0062;0061 05AE 11101 0300 0315 0062;0061 05AE 11101 0300 0315 0062; # (a◌𑄁◌̕◌̀◌֮b; a◌֮◌𑄁◌̀◌̕b; a◌֮◌𑄁◌̀◌̕b; a◌֮◌𑄁◌̀◌̕b; a◌֮◌𑄁◌̀◌̕b; ) LATIN SMALL LETTER A, CHAKMA SIGN ANUSVARA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11102 0062;00E0 05AE 11102 0315 0062;0061 05AE 0300 11102 0315 0062;00E0 05AE 11102 0315 0062;0061 05AE 0300 11102 0315 0062; # (a◌̕◌̀◌֮◌𑄂b; à◌֮◌𑄂◌̕b; a◌֮◌̀◌𑄂◌̕b; à◌֮◌𑄂◌̕b; a◌֮◌̀◌𑄂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, CHAKMA SIGN VISARGA, LATIN SMALL LETTER B +0061 11102 0315 0300 05AE 0062;0061 05AE 11102 0300 0315 0062;0061 05AE 11102 0300 0315 0062;0061 05AE 11102 0300 0315 0062;0061 05AE 11102 0300 0315 0062; # (a◌𑄂◌̕◌̀◌֮b; a◌֮◌𑄂◌̀◌̕b; a◌֮◌𑄂◌̀◌̕b; a◌֮◌𑄂◌̀◌̕b; a◌֮◌𑄂◌̀◌̕b; ) LATIN SMALL LETTER A, CHAKMA SIGN VISARGA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 11133 0062;0061 3099 094D 11133 05B0 0062;0061 3099 094D 11133 05B0 0062;0061 3099 094D 11133 05B0 0062;0061 3099 094D 11133 05B0 0062; # (a◌ְ◌्◌゙◌𑄳b; a◌゙◌्◌𑄳◌ְb; a◌゙◌्◌𑄳◌ְb; a◌゙◌्◌𑄳◌ְb; a◌゙◌्◌𑄳◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, CHAKMA VIRAMA, LATIN SMALL LETTER B +0061 11133 05B0 094D 3099 0062;0061 3099 11133 094D 05B0 0062;0061 3099 11133 094D 05B0 0062;0061 3099 11133 094D 05B0 0062;0061 3099 11133 094D 05B0 0062; # (a◌𑄳◌ְ◌्◌゙b; a◌゙◌𑄳◌्◌ְb; a◌゙◌𑄳◌्◌ְb; a◌゙◌𑄳◌्◌ְb; a◌゙◌𑄳◌्◌ְb; ) LATIN SMALL LETTER A, CHAKMA VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11134 0062;0061 3099 094D 11134 05B0 0062;0061 3099 094D 11134 05B0 0062;0061 3099 094D 11134 05B0 0062;0061 3099 094D 11134 05B0 0062; # (a◌ְ◌्◌゙◌𑄴b; a◌゙◌्◌𑄴◌ְb; a◌゙◌्◌𑄴◌ְb; a◌゙◌्◌𑄴◌ְb; a◌゙◌्◌𑄴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, CHAKMA MAAYYAA, LATIN SMALL LETTER B +0061 11134 05B0 094D 3099 0062;0061 3099 11134 094D 05B0 0062;0061 3099 11134 094D 05B0 0062;0061 3099 11134 094D 05B0 0062;0061 3099 11134 094D 05B0 0062; # (a◌𑄴◌ְ◌्◌゙b; a◌゙◌𑄴◌्◌ְb; a◌゙◌𑄴◌्◌ְb; a◌゙◌𑄴◌्◌ְb; a◌゙◌𑄴◌्◌ְb; ) LATIN SMALL LETTER A, CHAKMA MAAYYAA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 11173 0062;0061 16FF0 093C 11173 3099 0062;0061 16FF0 093C 11173 3099 0062;0061 16FF0 093C 11173 3099 0062;0061 16FF0 093C 11173 3099 0062; # (a◌゙◌𖿰़◌𑅳b; a𖿰◌़◌𑅳◌゙b; a𖿰◌़◌𑅳◌゙b; a𖿰◌़◌𑅳◌゙b; a𖿰◌़◌𑅳◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, MAHAJANI SIGN NUKTA, LATIN SMALL LETTER B +0061 11173 3099 093C 16FF0 0062;0061 16FF0 11173 093C 3099 0062;0061 16FF0 11173 093C 3099 0062;0061 16FF0 11173 093C 3099 0062;0061 16FF0 11173 093C 3099 0062; # (a◌𑅳◌゙◌𖿰़b; a𖿰◌𑅳◌़◌゙b; a𖿰◌𑅳◌़◌゙b; a𖿰◌𑅳◌़◌゙b; a𖿰◌𑅳◌़◌゙b; ) LATIN SMALL LETTER A, MAHAJANI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 111C0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062; # (a◌ְ◌्◌゙𑇀b; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SHARADA SIGN VIRAMA, LATIN SMALL LETTER B +0061 111C0 05B0 094D 3099 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062; # (a𑇀◌ְ◌्◌゙b; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; ) LATIN SMALL LETTER A, SHARADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 111CA 0062;0061 16FF0 093C 111CA 3099 0062;0061 16FF0 093C 111CA 3099 0062;0061 16FF0 093C 111CA 3099 0062;0061 16FF0 093C 111CA 3099 0062; # (a◌゙◌𖿰़◌𑇊b; a𖿰◌़◌𑇊◌゙b; a𖿰◌़◌𑇊◌゙b; a𖿰◌़◌𑇊◌゙b; a𖿰◌़◌𑇊◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, SHARADA SIGN NUKTA, LATIN SMALL LETTER B +0061 111CA 3099 093C 16FF0 0062;0061 16FF0 111CA 093C 3099 0062;0061 16FF0 111CA 093C 3099 0062;0061 16FF0 111CA 093C 3099 0062;0061 16FF0 111CA 093C 3099 0062; # (a◌𑇊◌゙◌𖿰़b; a𖿰◌𑇊◌़◌゙b; a𖿰◌𑇊◌़◌゙b; a𖿰◌𑇊◌़◌゙b; a𖿰◌𑇊◌़◌゙b; ) LATIN SMALL LETTER A, SHARADA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 11235 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062; # (a◌ְ◌्◌゙𑈵b; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHOJKI SIGN VIRAMA, LATIN SMALL LETTER B +0061 11235 05B0 094D 3099 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062; # (a𑈵◌ְ◌्◌゙b; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; ) LATIN SMALL LETTER A, KHOJKI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 11236 0062;0061 16FF0 093C 11236 3099 0062;0061 16FF0 093C 11236 3099 0062;0061 16FF0 093C 11236 3099 0062;0061 16FF0 093C 11236 3099 0062; # (a◌゙◌𖿰़◌𑈶b; a𖿰◌़◌𑈶◌゙b; a𖿰◌़◌𑈶◌゙b; a𖿰◌़◌𑈶◌゙b; a𖿰◌़◌𑈶◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, KHOJKI SIGN NUKTA, LATIN SMALL LETTER B +0061 11236 3099 093C 16FF0 0062;0061 16FF0 11236 093C 3099 0062;0061 16FF0 11236 093C 3099 0062;0061 16FF0 11236 093C 3099 0062;0061 16FF0 11236 093C 3099 0062; # (a◌𑈶◌゙◌𖿰़b; a𖿰◌𑈶◌़◌゙b; a𖿰◌𑈶◌़◌゙b; a𖿰◌𑈶◌़◌゙b; a𖿰◌𑈶◌़◌゙b; ) LATIN SMALL LETTER A, KHOJKI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 3099 093C 16FF0 112E9 0062;0061 16FF0 093C 112E9 3099 0062;0061 16FF0 093C 112E9 3099 0062;0061 16FF0 093C 112E9 3099 0062;0061 16FF0 093C 112E9 3099 0062; # (a◌゙◌𖿰़◌𑋩b; a𖿰◌़◌𑋩◌゙b; a𖿰◌़◌𑋩◌゙b; a𖿰◌़◌𑋩◌゙b; a𖿰◌़◌𑋩◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, KHUDAWADI SIGN NUKTA, LATIN SMALL LETTER B +0061 112E9 3099 093C 16FF0 0062;0061 16FF0 112E9 093C 3099 0062;0061 16FF0 112E9 093C 3099 0062;0061 16FF0 112E9 093C 3099 0062;0061 16FF0 112E9 093C 3099 0062; # (a◌𑋩◌゙◌𖿰़b; a𖿰◌𑋩◌़◌゙b; a𖿰◌𑋩◌़◌゙b; a𖿰◌𑋩◌़◌゙b; a𖿰◌𑋩◌़◌゙b; ) LATIN SMALL LETTER A, KHUDAWADI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 112EA 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062; # (a◌ְ◌्◌゙◌𑋪b; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHUDAWADI SIGN VIRAMA, LATIN SMALL LETTER B +0061 112EA 05B0 094D 3099 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062; # (a◌𑋪◌ְ◌्◌゙b; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; ) LATIN SMALL LETTER A, KHUDAWADI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1133B 0062;0061 16FF0 093C 1133B 3099 0062;0061 16FF0 093C 1133B 3099 0062;0061 16FF0 093C 1133B 3099 0062;0061 16FF0 093C 1133B 3099 0062; # (a◌゙◌𖿰़◌𑌻b; a𖿰◌़◌𑌻◌゙b; a𖿰◌़◌𑌻◌゙b; a𖿰◌़◌𑌻◌゙b; a𖿰◌़◌𑌻◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING BINDU BELOW, LATIN SMALL LETTER B +0061 1133B 3099 093C 16FF0 0062;0061 16FF0 1133B 093C 3099 0062;0061 16FF0 1133B 093C 3099 0062;0061 16FF0 1133B 093C 3099 0062;0061 16FF0 1133B 093C 3099 0062; # (a◌𑌻◌゙◌𖿰़b; a𖿰◌𑌻◌़◌゙b; a𖿰◌𑌻◌़◌゙b; a𖿰◌𑌻◌़◌゙b; a𖿰◌𑌻◌़◌゙b; ) LATIN SMALL LETTER A, COMBINING BINDU BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1133C 0062;0061 16FF0 093C 1133C 3099 0062;0061 16FF0 093C 1133C 3099 0062;0061 16FF0 093C 1133C 3099 0062;0061 16FF0 093C 1133C 3099 0062; # (a◌゙◌𖿰़◌𑌼b; a𖿰◌़◌𑌼◌゙b; a𖿰◌़◌𑌼◌゙b; a𖿰◌़◌𑌼◌゙b; a𖿰◌़◌𑌼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, GRANTHA SIGN NUKTA, LATIN SMALL LETTER B +0061 1133C 3099 093C 16FF0 0062;0061 16FF0 1133C 093C 3099 0062;0061 16FF0 1133C 093C 3099 0062;0061 16FF0 1133C 093C 3099 0062;0061 16FF0 1133C 093C 3099 0062; # (a◌𑌼◌゙◌𖿰़b; a𖿰◌𑌼◌़◌゙b; a𖿰◌𑌼◌़◌゙b; a𖿰◌𑌼◌़◌゙b; a𖿰◌𑌼◌़◌゙b; ) LATIN SMALL LETTER A, GRANTHA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1134D 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062; # (a◌ְ◌्◌゙𑍍b; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GRANTHA SIGN VIRAMA, LATIN SMALL LETTER B +0061 1134D 05B0 094D 3099 0062;0061 3099 1134D 094D 05B0 0062;0061 3099 1134D 094D 05B0 0062;0061 3099 1134D 094D 05B0 0062;0061 3099 1134D 094D 05B0 0062; # (a𑍍◌ְ◌्◌゙b; a◌゙𑍍◌्◌ְb; a◌゙𑍍◌्◌ְb; a◌゙𑍍◌्◌ְb; a◌゙𑍍◌्◌ְb; ) LATIN SMALL LETTER A, GRANTHA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 11366 0062;00E0 05AE 11366 0315 0062;0061 05AE 0300 11366 0315 0062;00E0 05AE 11366 0315 0062;0061 05AE 0300 11366 0315 0062; # (a◌̕◌̀◌֮◌𑍦b; à◌֮◌𑍦◌̕b; a◌֮◌̀◌𑍦◌̕b; à◌֮◌𑍦◌̕b; a◌֮◌̀◌𑍦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT ZERO, LATIN SMALL LETTER B +0061 11366 0315 0300 05AE 0062;0061 05AE 11366 0300 0315 0062;0061 05AE 11366 0300 0315 0062;0061 05AE 11366 0300 0315 0062;0061 05AE 11366 0300 0315 0062; # (a◌𑍦◌̕◌̀◌֮b; a◌֮◌𑍦◌̀◌̕b; a◌֮◌𑍦◌̀◌̕b; a◌֮◌𑍦◌̀◌̕b; a◌֮◌𑍦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT ZERO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11367 0062;00E0 05AE 11367 0315 0062;0061 05AE 0300 11367 0315 0062;00E0 05AE 11367 0315 0062;0061 05AE 0300 11367 0315 0062; # (a◌̕◌̀◌֮◌𑍧b; à◌֮◌𑍧◌̕b; a◌֮◌̀◌𑍧◌̕b; à◌֮◌𑍧◌̕b; a◌֮◌̀◌𑍧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT ONE, LATIN SMALL LETTER B +0061 11367 0315 0300 05AE 0062;0061 05AE 11367 0300 0315 0062;0061 05AE 11367 0300 0315 0062;0061 05AE 11367 0300 0315 0062;0061 05AE 11367 0300 0315 0062; # (a◌𑍧◌̕◌̀◌֮b; a◌֮◌𑍧◌̀◌̕b; a◌֮◌𑍧◌̀◌̕b; a◌֮◌𑍧◌̀◌̕b; a◌֮◌𑍧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT ONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11368 0062;00E0 05AE 11368 0315 0062;0061 05AE 0300 11368 0315 0062;00E0 05AE 11368 0315 0062;0061 05AE 0300 11368 0315 0062; # (a◌̕◌̀◌֮◌𑍨b; à◌֮◌𑍨◌̕b; a◌֮◌̀◌𑍨◌̕b; à◌֮◌𑍨◌̕b; a◌֮◌̀◌𑍨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT TWO, LATIN SMALL LETTER B +0061 11368 0315 0300 05AE 0062;0061 05AE 11368 0300 0315 0062;0061 05AE 11368 0300 0315 0062;0061 05AE 11368 0300 0315 0062;0061 05AE 11368 0300 0315 0062; # (a◌𑍨◌̕◌̀◌֮b; a◌֮◌𑍨◌̀◌̕b; a◌֮◌𑍨◌̀◌̕b; a◌֮◌𑍨◌̀◌̕b; a◌֮◌𑍨◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT TWO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11369 0062;00E0 05AE 11369 0315 0062;0061 05AE 0300 11369 0315 0062;00E0 05AE 11369 0315 0062;0061 05AE 0300 11369 0315 0062; # (a◌̕◌̀◌֮◌𑍩b; à◌֮◌𑍩◌̕b; a◌֮◌̀◌𑍩◌̕b; à◌֮◌𑍩◌̕b; a◌֮◌̀◌𑍩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT THREE, LATIN SMALL LETTER B +0061 11369 0315 0300 05AE 0062;0061 05AE 11369 0300 0315 0062;0061 05AE 11369 0300 0315 0062;0061 05AE 11369 0300 0315 0062;0061 05AE 11369 0300 0315 0062; # (a◌𑍩◌̕◌̀◌֮b; a◌֮◌𑍩◌̀◌̕b; a◌֮◌𑍩◌̀◌̕b; a◌֮◌𑍩◌̀◌̕b; a◌֮◌𑍩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT THREE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1136A 0062;00E0 05AE 1136A 0315 0062;0061 05AE 0300 1136A 0315 0062;00E0 05AE 1136A 0315 0062;0061 05AE 0300 1136A 0315 0062; # (a◌̕◌̀◌֮◌𑍪b; à◌֮◌𑍪◌̕b; a◌֮◌̀◌𑍪◌̕b; à◌֮◌𑍪◌̕b; a◌֮◌̀◌𑍪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT FOUR, LATIN SMALL LETTER B +0061 1136A 0315 0300 05AE 0062;0061 05AE 1136A 0300 0315 0062;0061 05AE 1136A 0300 0315 0062;0061 05AE 1136A 0300 0315 0062;0061 05AE 1136A 0300 0315 0062; # (a◌𑍪◌̕◌̀◌֮b; a◌֮◌𑍪◌̀◌̕b; a◌֮◌𑍪◌̀◌̕b; a◌֮◌𑍪◌̀◌̕b; a◌֮◌𑍪◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT FOUR, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1136B 0062;00E0 05AE 1136B 0315 0062;0061 05AE 0300 1136B 0315 0062;00E0 05AE 1136B 0315 0062;0061 05AE 0300 1136B 0315 0062; # (a◌̕◌̀◌֮◌𑍫b; à◌֮◌𑍫◌̕b; a◌֮◌̀◌𑍫◌̕b; à◌֮◌𑍫◌̕b; a◌֮◌̀◌𑍫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT FIVE, LATIN SMALL LETTER B +0061 1136B 0315 0300 05AE 0062;0061 05AE 1136B 0300 0315 0062;0061 05AE 1136B 0300 0315 0062;0061 05AE 1136B 0300 0315 0062;0061 05AE 1136B 0300 0315 0062; # (a◌𑍫◌̕◌̀◌֮b; a◌֮◌𑍫◌̀◌̕b; a◌֮◌𑍫◌̀◌̕b; a◌֮◌𑍫◌̀◌̕b; a◌֮◌𑍫◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT FIVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1136C 0062;00E0 05AE 1136C 0315 0062;0061 05AE 0300 1136C 0315 0062;00E0 05AE 1136C 0315 0062;0061 05AE 0300 1136C 0315 0062; # (a◌̕◌̀◌֮◌𑍬b; à◌֮◌𑍬◌̕b; a◌֮◌̀◌𑍬◌̕b; à◌֮◌𑍬◌̕b; a◌֮◌̀◌𑍬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA DIGIT SIX, LATIN SMALL LETTER B +0061 1136C 0315 0300 05AE 0062;0061 05AE 1136C 0300 0315 0062;0061 05AE 1136C 0300 0315 0062;0061 05AE 1136C 0300 0315 0062;0061 05AE 1136C 0300 0315 0062; # (a◌𑍬◌̕◌̀◌֮b; a◌֮◌𑍬◌̀◌̕b; a◌֮◌𑍬◌̀◌̕b; a◌֮◌𑍬◌̀◌̕b; a◌֮◌𑍬◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA DIGIT SIX, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11370 0062;00E0 05AE 11370 0315 0062;0061 05AE 0300 11370 0315 0062;00E0 05AE 11370 0315 0062;0061 05AE 0300 11370 0315 0062; # (a◌̕◌̀◌֮◌𑍰b; à◌֮◌𑍰◌̕b; a◌֮◌̀◌𑍰◌̕b; à◌֮◌𑍰◌̕b; a◌֮◌̀◌𑍰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER A, LATIN SMALL LETTER B +0061 11370 0315 0300 05AE 0062;0061 05AE 11370 0300 0315 0062;0061 05AE 11370 0300 0315 0062;0061 05AE 11370 0300 0315 0062;0061 05AE 11370 0300 0315 0062; # (a◌𑍰◌̕◌̀◌֮b; a◌֮◌𑍰◌̀◌̕b; a◌֮◌𑍰◌̀◌̕b; a◌֮◌𑍰◌̀◌̕b; a◌֮◌𑍰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11371 0062;00E0 05AE 11371 0315 0062;0061 05AE 0300 11371 0315 0062;00E0 05AE 11371 0315 0062;0061 05AE 0300 11371 0315 0062; # (a◌̕◌̀◌֮◌𑍱b; à◌֮◌𑍱◌̕b; a◌֮◌̀◌𑍱◌̕b; à◌֮◌𑍱◌̕b; a◌֮◌̀◌𑍱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER KA, LATIN SMALL LETTER B +0061 11371 0315 0300 05AE 0062;0061 05AE 11371 0300 0315 0062;0061 05AE 11371 0300 0315 0062;0061 05AE 11371 0300 0315 0062;0061 05AE 11371 0300 0315 0062; # (a◌𑍱◌̕◌̀◌֮b; a◌֮◌𑍱◌̀◌̕b; a◌֮◌𑍱◌̀◌̕b; a◌֮◌𑍱◌̀◌̕b; a◌֮◌𑍱◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER KA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11372 0062;00E0 05AE 11372 0315 0062;0061 05AE 0300 11372 0315 0062;00E0 05AE 11372 0315 0062;0061 05AE 0300 11372 0315 0062; # (a◌̕◌̀◌֮◌𑍲b; à◌֮◌𑍲◌̕b; a◌֮◌̀◌𑍲◌̕b; à◌֮◌𑍲◌̕b; a◌֮◌̀◌𑍲◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER NA, LATIN SMALL LETTER B +0061 11372 0315 0300 05AE 0062;0061 05AE 11372 0300 0315 0062;0061 05AE 11372 0300 0315 0062;0061 05AE 11372 0300 0315 0062;0061 05AE 11372 0300 0315 0062; # (a◌𑍲◌̕◌̀◌֮b; a◌֮◌𑍲◌̀◌̕b; a◌֮◌𑍲◌̀◌̕b; a◌֮◌𑍲◌̀◌̕b; a◌֮◌𑍲◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER NA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11373 0062;00E0 05AE 11373 0315 0062;0061 05AE 0300 11373 0315 0062;00E0 05AE 11373 0315 0062;0061 05AE 0300 11373 0315 0062; # (a◌̕◌̀◌֮◌𑍳b; à◌֮◌𑍳◌̕b; a◌֮◌̀◌𑍳◌̕b; à◌֮◌𑍳◌̕b; a◌֮◌̀◌𑍳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER VI, LATIN SMALL LETTER B +0061 11373 0315 0300 05AE 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062; # (a◌𑍳◌̕◌̀◌֮b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER VI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 11374 0062;00E0 05AE 11374 0315 0062;0061 05AE 0300 11374 0315 0062;00E0 05AE 11374 0315 0062;0061 05AE 0300 11374 0315 0062; # (a◌̕◌̀◌֮◌𑍴b; à◌֮◌𑍴◌̕b; a◌֮◌̀◌𑍴◌̕b; à◌֮◌𑍴◌̕b; a◌֮◌̀◌𑍴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER PA, LATIN SMALL LETTER B +0061 11374 0315 0300 05AE 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062; # (a◌𑍴◌̕◌̀◌֮b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER PA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 11442 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062; # (a◌ְ◌्◌゙◌𑑂b; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, NEWA SIGN VIRAMA, LATIN SMALL LETTER B +0061 11442 05B0 094D 3099 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062; # (a◌𑑂◌ְ◌्◌゙b; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; ) LATIN SMALL LETTER A, NEWA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 11446 0062;0061 16FF0 093C 11446 3099 0062;0061 16FF0 093C 11446 3099 0062;0061 16FF0 093C 11446 3099 0062;0061 16FF0 093C 11446 3099 0062; # (a◌゙◌𖿰़◌𑑆b; a𖿰◌़◌𑑆◌゙b; a𖿰◌़◌𑑆◌゙b; a𖿰◌़◌𑑆◌゙b; a𖿰◌़◌𑑆◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, NEWA SIGN NUKTA, LATIN SMALL LETTER B +0061 11446 3099 093C 16FF0 0062;0061 16FF0 11446 093C 3099 0062;0061 16FF0 11446 093C 3099 0062;0061 16FF0 11446 093C 3099 0062;0061 16FF0 11446 093C 3099 0062; # (a◌𑑆◌゙◌𖿰़b; a𖿰◌𑑆◌़◌゙b; a𖿰◌𑑆◌़◌゙b; a𖿰◌𑑆◌़◌゙b; a𖿰◌𑑆◌़◌゙b; ) LATIN SMALL LETTER A, NEWA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 0315 0300 05AE 1145E 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062; # (a◌̕◌̀◌֮◌𑑞b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NEWA SANDHI MARK, LATIN SMALL LETTER B +0061 1145E 0315 0300 05AE 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062; # (a◌𑑞◌̕◌̀◌֮b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; ) LATIN SMALL LETTER A, NEWA SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 114C2 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062; # (a◌ְ◌्◌゙◌𑓂b; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIRHUTA SIGN VIRAMA, LATIN SMALL LETTER B +0061 114C2 05B0 094D 3099 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062; # (a◌𑓂◌ְ◌्◌゙b; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; ) LATIN SMALL LETTER A, TIRHUTA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 114C3 0062;0061 16FF0 093C 114C3 3099 0062;0061 16FF0 093C 114C3 3099 0062;0061 16FF0 093C 114C3 3099 0062;0061 16FF0 093C 114C3 3099 0062; # (a◌゙◌𖿰़◌𑓃b; a𖿰◌़◌𑓃◌゙b; a𖿰◌़◌𑓃◌゙b; a𖿰◌़◌𑓃◌゙b; a𖿰◌़◌𑓃◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, TIRHUTA SIGN NUKTA, LATIN SMALL LETTER B +0061 114C3 3099 093C 16FF0 0062;0061 16FF0 114C3 093C 3099 0062;0061 16FF0 114C3 093C 3099 0062;0061 16FF0 114C3 093C 3099 0062;0061 16FF0 114C3 093C 3099 0062; # (a◌𑓃◌゙◌𖿰़b; a𖿰◌𑓃◌़◌゙b; a𖿰◌𑓃◌़◌゙b; a𖿰◌𑓃◌़◌゙b; a𖿰◌𑓃◌़◌゙b; ) LATIN SMALL LETTER A, TIRHUTA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 115BF 0062;0061 3099 094D 115BF 05B0 0062;0061 3099 094D 115BF 05B0 0062;0061 3099 094D 115BF 05B0 0062;0061 3099 094D 115BF 05B0 0062; # (a◌ְ◌्◌゙◌𑖿b; a◌゙◌्◌𑖿◌ְb; a◌゙◌्◌𑖿◌ְb; a◌゙◌्◌𑖿◌ְb; a◌゙◌्◌𑖿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SIDDHAM SIGN VIRAMA, LATIN SMALL LETTER B +0061 115BF 05B0 094D 3099 0062;0061 3099 115BF 094D 05B0 0062;0061 3099 115BF 094D 05B0 0062;0061 3099 115BF 094D 05B0 0062;0061 3099 115BF 094D 05B0 0062; # (a◌𑖿◌ְ◌्◌゙b; a◌゙◌𑖿◌्◌ְb; a◌゙◌𑖿◌्◌ְb; a◌゙◌𑖿◌्◌ְb; a◌゙◌𑖿◌्◌ְb; ) LATIN SMALL LETTER A, SIDDHAM SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 115C0 0062;0061 16FF0 093C 115C0 3099 0062;0061 16FF0 093C 115C0 3099 0062;0061 16FF0 093C 115C0 3099 0062;0061 16FF0 093C 115C0 3099 0062; # (a◌゙◌𖿰़◌𑗀b; a𖿰◌़◌𑗀◌゙b; a𖿰◌़◌𑗀◌゙b; a𖿰◌़◌𑗀◌゙b; a𖿰◌़◌𑗀◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, SIDDHAM SIGN NUKTA, LATIN SMALL LETTER B +0061 115C0 3099 093C 16FF0 0062;0061 16FF0 115C0 093C 3099 0062;0061 16FF0 115C0 093C 3099 0062;0061 16FF0 115C0 093C 3099 0062;0061 16FF0 115C0 093C 3099 0062; # (a◌𑗀◌゙◌𖿰़b; a𖿰◌𑗀◌़◌゙b; a𖿰◌𑗀◌़◌゙b; a𖿰◌𑗀◌़◌゙b; a𖿰◌𑗀◌़◌゙b; ) LATIN SMALL LETTER A, SIDDHAM SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1163F 0062;0061 3099 094D 1163F 05B0 0062;0061 3099 094D 1163F 05B0 0062;0061 3099 094D 1163F 05B0 0062;0061 3099 094D 1163F 05B0 0062; # (a◌ְ◌्◌゙◌𑘿b; a◌゙◌्◌𑘿◌ְb; a◌゙◌्◌𑘿◌ְb; a◌゙◌्◌𑘿◌ְb; a◌゙◌्◌𑘿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MODI SIGN VIRAMA, LATIN SMALL LETTER B +0061 1163F 05B0 094D 3099 0062;0061 3099 1163F 094D 05B0 0062;0061 3099 1163F 094D 05B0 0062;0061 3099 1163F 094D 05B0 0062;0061 3099 1163F 094D 05B0 0062; # (a◌𑘿◌ְ◌्◌゙b; a◌゙◌𑘿◌्◌ְb; a◌゙◌𑘿◌्◌ְb; a◌゙◌𑘿◌्◌ְb; a◌゙◌𑘿◌्◌ְb; ) LATIN SMALL LETTER A, MODI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 116B6 0062;0061 3099 094D 116B6 05B0 0062;0061 3099 094D 116B6 05B0 0062;0061 3099 094D 116B6 05B0 0062;0061 3099 094D 116B6 05B0 0062; # (a◌ְ◌्◌゙𑚶b; a◌゙◌्𑚶◌ְb; a◌゙◌्𑚶◌ְb; a◌゙◌्𑚶◌ְb; a◌゙◌्𑚶◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAKRI SIGN VIRAMA, LATIN SMALL LETTER B +0061 116B6 05B0 094D 3099 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062; # (a𑚶◌ְ◌्◌゙b; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; ) LATIN SMALL LETTER A, TAKRI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 116B7 0062;0061 16FF0 093C 116B7 3099 0062;0061 16FF0 093C 116B7 3099 0062;0061 16FF0 093C 116B7 3099 0062;0061 16FF0 093C 116B7 3099 0062; # (a◌゙◌𖿰़◌𑚷b; a𖿰◌़◌𑚷◌゙b; a𖿰◌़◌𑚷◌゙b; a𖿰◌़◌𑚷◌゙b; a𖿰◌़◌𑚷◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, TAKRI SIGN NUKTA, LATIN SMALL LETTER B +0061 116B7 3099 093C 16FF0 0062;0061 16FF0 116B7 093C 3099 0062;0061 16FF0 116B7 093C 3099 0062;0061 16FF0 116B7 093C 3099 0062;0061 16FF0 116B7 093C 3099 0062; # (a◌𑚷◌゙◌𖿰़b; a𖿰◌𑚷◌़◌゙b; a𖿰◌𑚷◌़◌゙b; a𖿰◌𑚷◌़◌゙b; a𖿰◌𑚷◌़◌゙b; ) LATIN SMALL LETTER A, TAKRI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1172B 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062; # (a◌ְ◌्◌゙◌𑜫b; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, AHOM SIGN KILLER, LATIN SMALL LETTER B +0061 1172B 05B0 094D 3099 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062; # (a◌𑜫◌ְ◌्◌゙b; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; ) LATIN SMALL LETTER A, AHOM SIGN KILLER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11839 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062; # (a◌ְ◌्◌゙◌𑠹b; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DOGRA SIGN VIRAMA, LATIN SMALL LETTER B +0061 11839 05B0 094D 3099 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062; # (a◌𑠹◌ְ◌्◌゙b; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; ) LATIN SMALL LETTER A, DOGRA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1183A 0062;0061 16FF0 093C 1183A 3099 0062;0061 16FF0 093C 1183A 3099 0062;0061 16FF0 093C 1183A 3099 0062;0061 16FF0 093C 1183A 3099 0062; # (a◌゙◌𖿰़◌𑠺b; a𖿰◌़◌𑠺◌゙b; a𖿰◌़◌𑠺◌゙b; a𖿰◌़◌𑠺◌゙b; a𖿰◌़◌𑠺◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, DOGRA SIGN NUKTA, LATIN SMALL LETTER B +0061 1183A 3099 093C 16FF0 0062;0061 16FF0 1183A 093C 3099 0062;0061 16FF0 1183A 093C 3099 0062;0061 16FF0 1183A 093C 3099 0062;0061 16FF0 1183A 093C 3099 0062; # (a◌𑠺◌゙◌𖿰़b; a𖿰◌𑠺◌़◌゙b; a𖿰◌𑠺◌़◌゙b; a𖿰◌𑠺◌़◌゙b; a𖿰◌𑠺◌़◌゙b; ) LATIN SMALL LETTER A, DOGRA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 1193D 0062;0061 3099 094D 1193D 05B0 0062;0061 3099 094D 1193D 05B0 0062;0061 3099 094D 1193D 05B0 0062;0061 3099 094D 1193D 05B0 0062; # (a◌ְ◌्◌゙𑤽b; a◌゙◌्𑤽◌ְb; a◌゙◌्𑤽◌ְb; a◌゙◌्𑤽◌ְb; a◌゙◌्𑤽◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DIVES AKURU SIGN HALANTA, LATIN SMALL LETTER B +0061 1193D 05B0 094D 3099 0062;0061 3099 1193D 094D 05B0 0062;0061 3099 1193D 094D 05B0 0062;0061 3099 1193D 094D 05B0 0062;0061 3099 1193D 094D 05B0 0062; # (a𑤽◌ְ◌्◌゙b; a◌゙𑤽◌्◌ְb; a◌゙𑤽◌्◌ְb; a◌゙𑤽◌्◌ְb; a◌゙𑤽◌्◌ְb; ) LATIN SMALL LETTER A, DIVES AKURU SIGN HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1193E 0062;0061 3099 094D 1193E 05B0 0062;0061 3099 094D 1193E 05B0 0062;0061 3099 094D 1193E 05B0 0062;0061 3099 094D 1193E 05B0 0062; # (a◌ְ◌्◌゙◌𑤾b; a◌゙◌्◌𑤾◌ְb; a◌゙◌्◌𑤾◌ְb; a◌゙◌्◌𑤾◌ְb; a◌゙◌्◌𑤾◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DIVES AKURU VIRAMA, LATIN SMALL LETTER B +0061 1193E 05B0 094D 3099 0062;0061 3099 1193E 094D 05B0 0062;0061 3099 1193E 094D 05B0 0062;0061 3099 1193E 094D 05B0 0062;0061 3099 1193E 094D 05B0 0062; # (a◌𑤾◌ְ◌्◌゙b; a◌゙◌𑤾◌्◌ְb; a◌゙◌𑤾◌्◌ְb; a◌゙◌𑤾◌्◌ְb; a◌゙◌𑤾◌्◌ְb; ) LATIN SMALL LETTER A, DIVES AKURU VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 11943 0062;0061 16FF0 093C 11943 3099 0062;0061 16FF0 093C 11943 3099 0062;0061 16FF0 093C 11943 3099 0062;0061 16FF0 093C 11943 3099 0062; # (a◌゙◌𖿰़◌𑥃b; a𖿰◌़◌𑥃◌゙b; a𖿰◌़◌𑥃◌゙b; a𖿰◌़◌𑥃◌゙b; a𖿰◌़◌𑥃◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, DIVES AKURU SIGN NUKTA, LATIN SMALL LETTER B +0061 11943 3099 093C 16FF0 0062;0061 16FF0 11943 093C 3099 0062;0061 16FF0 11943 093C 3099 0062;0061 16FF0 11943 093C 3099 0062;0061 16FF0 11943 093C 3099 0062; # (a◌𑥃◌゙◌𖿰़b; a𖿰◌𑥃◌़◌゙b; a𖿰◌𑥃◌़◌゙b; a𖿰◌𑥃◌़◌゙b; a𖿰◌𑥃◌़◌゙b; ) LATIN SMALL LETTER A, DIVES AKURU SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 119E0 0062;0061 3099 094D 119E0 05B0 0062;0061 3099 094D 119E0 05B0 0062;0061 3099 094D 119E0 05B0 0062;0061 3099 094D 119E0 05B0 0062; # (a◌ְ◌्◌゙◌𑧠b; a◌゙◌्◌𑧠◌ְb; a◌゙◌्◌𑧠◌ְb; a◌゙◌्◌𑧠◌ְb; a◌゙◌्◌𑧠◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, NANDINAGARI SIGN VIRAMA, LATIN SMALL LETTER B +0061 119E0 05B0 094D 3099 0062;0061 3099 119E0 094D 05B0 0062;0061 3099 119E0 094D 05B0 0062;0061 3099 119E0 094D 05B0 0062;0061 3099 119E0 094D 05B0 0062; # (a◌𑧠◌ְ◌्◌゙b; a◌゙◌𑧠◌्◌ְb; a◌゙◌𑧠◌्◌ְb; a◌゙◌𑧠◌्◌ְb; a◌゙◌𑧠◌्◌ְb; ) LATIN SMALL LETTER A, NANDINAGARI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A34 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062; # (a◌ְ◌्◌゙◌𑨴b; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SIGN VIRAMA, LATIN SMALL LETTER B +0061 11A34 05B0 094D 3099 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062; # (a◌𑨴◌ְ◌्◌゙b; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A47 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062; # (a◌ְ◌्◌゙◌𑩇b; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SUBJOINER, LATIN SMALL LETTER B +0061 11A47 05B0 094D 3099 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062; # (a◌𑩇◌ְ◌्◌゙b; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A99 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062; # (a◌ְ◌्◌゙◌𑪙b; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SOYOMBO SUBJOINER, LATIN SMALL LETTER B +0061 11A99 05B0 094D 3099 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062; # (a◌𑪙◌ְ◌्◌゙b; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; ) LATIN SMALL LETTER A, SOYOMBO SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11C3F 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062; # (a◌ְ◌्◌゙◌𑰿b; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BHAIKSUKI SIGN VIRAMA, LATIN SMALL LETTER B +0061 11C3F 05B0 094D 3099 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062; # (a◌𑰿◌ְ◌्◌゙b; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; ) LATIN SMALL LETTER A, BHAIKSUKI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 11D42 0062;0061 16FF0 093C 11D42 3099 0062;0061 16FF0 093C 11D42 3099 0062;0061 16FF0 093C 11D42 3099 0062;0061 16FF0 093C 11D42 3099 0062; # (a◌゙◌𖿰़◌𑵂b; a𖿰◌़◌𑵂◌゙b; a𖿰◌़◌𑵂◌゙b; a𖿰◌़◌𑵂◌゙b; a𖿰◌़◌𑵂◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, MASARAM GONDI SIGN NUKTA, LATIN SMALL LETTER B +0061 11D42 3099 093C 16FF0 0062;0061 16FF0 11D42 093C 3099 0062;0061 16FF0 11D42 093C 3099 0062;0061 16FF0 11D42 093C 3099 0062;0061 16FF0 11D42 093C 3099 0062; # (a◌𑵂◌゙◌𖿰़b; a𖿰◌𑵂◌़◌゙b; a𖿰◌𑵂◌़◌゙b; a𖿰◌𑵂◌़◌゙b; a𖿰◌𑵂◌़◌゙b; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 05B0 094D 3099 11D44 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062; # (a◌ְ◌्◌゙◌𑵄b; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI SIGN HALANTA, LATIN SMALL LETTER B +0061 11D44 05B0 094D 3099 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062; # (a◌𑵄◌ְ◌्◌゙b; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11D45 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062; # (a◌ְ◌्◌゙◌𑵅b; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI VIRAMA, LATIN SMALL LETTER B +0061 11D45 05B0 094D 3099 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062; # (a◌𑵅◌ְ◌्◌゙b; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11D97 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062; # (a◌ְ◌्◌゙◌𑶗b; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUNJALA GONDI VIRAMA, LATIN SMALL LETTER B +0061 11D97 05B0 094D 3099 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062; # (a◌𑶗◌ְ◌्◌゙b; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; ) LATIN SMALL LETTER A, GUNJALA GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 16FF0 0334 16AF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062; # (a𖿰◌̴◌𖫰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH TONE, LATIN SMALL LETTER B +0061 16AF0 16FF0 0334 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062; # (a◌𖫰𖿰◌̴b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 16AF1 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062; # (a𖿰◌̴◌𖫱b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW TONE, LATIN SMALL LETTER B +0061 16AF1 16FF0 0334 0062;0061 16AF1 0334 16FF0 0062;0061 16AF1 0334 16FF0 0062;0061 16AF1 0334 16FF0 0062;0061 16AF1 0334 16FF0 0062; # (a◌𖫱𖿰◌̴b; a◌𖫱◌̴𖿰b; a◌𖫱◌̴𖿰b; a◌𖫱◌̴𖿰b; a◌𖫱◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING LOW TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 16AF2 0062;0061 0334 16AF2 16FF0 0062;0061 0334 16AF2 16FF0 0062;0061 0334 16AF2 16FF0 0062;0061 0334 16AF2 16FF0 0062; # (a𖿰◌̴◌𖫲b; a◌̴◌𖫲𖿰b; a◌̴◌𖫲𖿰b; a◌̴◌𖫲𖿰b; a◌̴◌𖫲𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING MID TONE, LATIN SMALL LETTER B +0061 16AF2 16FF0 0334 0062;0061 16AF2 0334 16FF0 0062;0061 16AF2 0334 16FF0 0062;0061 16AF2 0334 16FF0 0062;0061 16AF2 0334 16FF0 0062; # (a◌𖫲𖿰◌̴b; a◌𖫲◌̴𖿰b; a◌𖫲◌̴𖿰b; a◌𖫲◌̴𖿰b; a◌𖫲◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING MID TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 16AF3 0062;0061 0334 16AF3 16FF0 0062;0061 0334 16AF3 16FF0 0062;0061 0334 16AF3 16FF0 0062;0061 0334 16AF3 16FF0 0062; # (a𖿰◌̴◌𖫳b; a◌̴◌𖫳𖿰b; a◌̴◌𖫳𖿰b; a◌̴◌𖫳𖿰b; a◌̴◌𖫳𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW-MID TONE, LATIN SMALL LETTER B +0061 16AF3 16FF0 0334 0062;0061 16AF3 0334 16FF0 0062;0061 16AF3 0334 16FF0 0062;0061 16AF3 0334 16FF0 0062;0061 16AF3 0334 16FF0 0062; # (a◌𖫳𖿰◌̴b; a◌𖫳◌̴𖿰b; a◌𖫳◌̴𖿰b; a◌𖫳◌̴𖿰b; a◌𖫳◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING LOW-MID TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 16AF4 0062;0061 0334 16AF4 16FF0 0062;0061 0334 16AF4 16FF0 0062;0061 0334 16AF4 16FF0 0062;0061 0334 16AF4 16FF0 0062; # (a𖿰◌̴◌𖫴b; a◌̴◌𖫴𖿰b; a◌̴◌𖫴𖿰b; a◌̴◌𖫴𖿰b; a◌̴◌𖫴𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH-LOW TONE, LATIN SMALL LETTER B +0061 16AF4 16FF0 0334 0062;0061 16AF4 0334 16FF0 0062;0061 16AF4 0334 16FF0 0062;0061 16AF4 0334 16FF0 0062;0061 16AF4 0334 16FF0 0062; # (a◌𖫴𖿰◌̴b; a◌𖫴◌̴𖿰b; a◌𖫴◌̴𖿰b; a◌𖫴◌̴𖿰b; a◌𖫴◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH-LOW TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B30 0062;00E0 05AE 16B30 0315 0062;0061 05AE 0300 16B30 0315 0062;00E0 05AE 16B30 0315 0062;0061 05AE 0300 16B30 0315 0062; # (a◌̕◌̀◌֮◌𖬰b; à◌֮◌𖬰◌̕b; a◌֮◌̀◌𖬰◌̕b; à◌֮◌𖬰◌̕b; a◌֮◌̀◌𖬰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM TUB, LATIN SMALL LETTER B +0061 16B30 0315 0300 05AE 0062;0061 05AE 16B30 0300 0315 0062;0061 05AE 16B30 0300 0315 0062;0061 05AE 16B30 0300 0315 0062;0061 05AE 16B30 0300 0315 0062; # (a◌𖬰◌̕◌̀◌֮b; a◌֮◌𖬰◌̀◌̕b; a◌֮◌𖬰◌̀◌̕b; a◌֮◌𖬰◌̀◌̕b; a◌֮◌𖬰◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM TUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B31 0062;00E0 05AE 16B31 0315 0062;0061 05AE 0300 16B31 0315 0062;00E0 05AE 16B31 0315 0062;0061 05AE 0300 16B31 0315 0062; # (a◌̕◌̀◌֮◌𖬱b; à◌֮◌𖬱◌̕b; a◌֮◌̀◌𖬱◌̕b; à◌֮◌𖬱◌̕b; a◌֮◌̀◌𖬱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM SO, LATIN SMALL LETTER B +0061 16B31 0315 0300 05AE 0062;0061 05AE 16B31 0300 0315 0062;0061 05AE 16B31 0300 0315 0062;0061 05AE 16B31 0300 0315 0062;0061 05AE 16B31 0300 0315 0062; # (a◌𖬱◌̕◌̀◌֮b; a◌֮◌𖬱◌̀◌̕b; a◌֮◌𖬱◌̀◌̕b; a◌֮◌𖬱◌̀◌̕b; a◌֮◌𖬱◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM SO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B32 0062;00E0 05AE 16B32 0315 0062;0061 05AE 0300 16B32 0315 0062;00E0 05AE 16B32 0315 0062;0061 05AE 0300 16B32 0315 0062; # (a◌̕◌̀◌֮◌𖬲b; à◌֮◌𖬲◌̕b; a◌֮◌̀◌𖬲◌̕b; à◌֮◌𖬲◌̕b; a◌֮◌̀◌𖬲◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM KES, LATIN SMALL LETTER B +0061 16B32 0315 0300 05AE 0062;0061 05AE 16B32 0300 0315 0062;0061 05AE 16B32 0300 0315 0062;0061 05AE 16B32 0300 0315 0062;0061 05AE 16B32 0300 0315 0062; # (a◌𖬲◌̕◌̀◌֮b; a◌֮◌𖬲◌̀◌̕b; a◌֮◌𖬲◌̀◌̕b; a◌֮◌𖬲◌̀◌̕b; a◌֮◌𖬲◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM KES, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B33 0062;00E0 05AE 16B33 0315 0062;0061 05AE 0300 16B33 0315 0062;00E0 05AE 16B33 0315 0062;0061 05AE 0300 16B33 0315 0062; # (a◌̕◌̀◌֮◌𖬳b; à◌֮◌𖬳◌̕b; a◌֮◌̀◌𖬳◌̕b; à◌֮◌𖬳◌̕b; a◌֮◌̀◌𖬳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM KHAV, LATIN SMALL LETTER B +0061 16B33 0315 0300 05AE 0062;0061 05AE 16B33 0300 0315 0062;0061 05AE 16B33 0300 0315 0062;0061 05AE 16B33 0300 0315 0062;0061 05AE 16B33 0300 0315 0062; # (a◌𖬳◌̕◌̀◌֮b; a◌֮◌𖬳◌̀◌̕b; a◌֮◌𖬳◌̀◌̕b; a◌֮◌𖬳◌̀◌̕b; a◌֮◌𖬳◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM KHAV, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B34 0062;00E0 05AE 16B34 0315 0062;0061 05AE 0300 16B34 0315 0062;00E0 05AE 16B34 0315 0062;0061 05AE 0300 16B34 0315 0062; # (a◌̕◌̀◌֮◌𖬴b; à◌֮◌𖬴◌̕b; a◌֮◌̀◌𖬴◌̕b; à◌֮◌𖬴◌̕b; a◌֮◌̀◌𖬴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM SUAM, LATIN SMALL LETTER B +0061 16B34 0315 0300 05AE 0062;0061 05AE 16B34 0300 0315 0062;0061 05AE 16B34 0300 0315 0062;0061 05AE 16B34 0300 0315 0062;0061 05AE 16B34 0300 0315 0062; # (a◌𖬴◌̕◌̀◌֮b; a◌֮◌𖬴◌̀◌̕b; a◌֮◌𖬴◌̀◌̕b; a◌֮◌𖬴◌̀◌̕b; a◌֮◌𖬴◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM SUAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B35 0062;00E0 05AE 16B35 0315 0062;0061 05AE 0300 16B35 0315 0062;00E0 05AE 16B35 0315 0062;0061 05AE 0300 16B35 0315 0062; # (a◌̕◌̀◌֮◌𖬵b; à◌֮◌𖬵◌̕b; a◌֮◌̀◌𖬵◌̕b; à◌֮◌𖬵◌̕b; a◌֮◌̀◌𖬵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM HOM, LATIN SMALL LETTER B +0061 16B35 0315 0300 05AE 0062;0061 05AE 16B35 0300 0315 0062;0061 05AE 16B35 0300 0315 0062;0061 05AE 16B35 0300 0315 0062;0061 05AE 16B35 0300 0315 0062; # (a◌𖬵◌̕◌̀◌֮b; a◌֮◌𖬵◌̀◌̕b; a◌֮◌𖬵◌̀◌̕b; a◌֮◌𖬵◌̀◌̕b; a◌֮◌𖬵◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM HOM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 16B36 0062;00E0 05AE 16B36 0315 0062;0061 05AE 0300 16B36 0315 0062;00E0 05AE 16B36 0315 0062;0061 05AE 0300 16B36 0315 0062; # (a◌̕◌̀◌֮◌𖬶b; à◌֮◌𖬶◌̕b; a◌֮◌̀◌𖬶◌̕b; à◌֮◌𖬶◌̕b; a◌֮◌̀◌𖬶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, PAHAWH HMONG MARK CIM TAUM, LATIN SMALL LETTER B +0061 16B36 0315 0300 05AE 0062;0061 05AE 16B36 0300 0315 0062;0061 05AE 16B36 0300 0315 0062;0061 05AE 16B36 0300 0315 0062;0061 05AE 16B36 0300 0315 0062; # (a◌𖬶◌̕◌̀◌֮b; a◌֮◌𖬶◌̀◌̕b; a◌֮◌𖬶◌̀◌̕b; a◌֮◌𖬶◌̀◌̕b; a◌֮◌𖬶◌̀◌̕b; ) LATIN SMALL LETTER A, PAHAWH HMONG MARK CIM TAUM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 093C 16FF0 0334 16FF0 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062; # (a◌𖿰़◌̴𖿰b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +0061 16FF0 093C 16FF0 0334 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062;0061 0334 16FF0 16FF0 093C 0062; # (a𖿰◌𖿰़◌̴b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; a◌̴𖿰𖿰◌़b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 093C 16FF0 0334 16FF1 0062;0061 0334 16FF0 16FF1 093C 0062;0061 0334 16FF0 16FF1 093C 0062;0061 0334 16FF0 16FF1 093C 0062;0061 0334 16FF0 16FF1 093C 0062; # (a◌𖿰़◌̴𖿱b; a◌̴𖿰𖿱◌़b; a◌̴𖿰𖿱◌़b; a◌̴𖿰𖿱◌़b; a◌̴𖿰𖿱◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VIETNAMESE ALTERNATE READING MARK NHAY, LATIN SMALL LETTER B +0061 16FF1 093C 16FF0 0334 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062; # (a𖿱◌𖿰़◌̴b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK NHAY, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1BC9E 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062; # (a𖿰◌̴◌𛲞b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, DUPLOYAN DOUBLE MARK, LATIN SMALL LETTER B +0061 1BC9E 16FF0 0334 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062; # (a◌𛲞𖿰◌̴b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; ) LATIN SMALL LETTER A, DUPLOYAN DOUBLE MARK, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D165 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062; # (a◌᷺◌̛◌᷎𝅥b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING STEM, LATIN SMALL LETTER B +0061 1D165 1DFA 031B 1DCE 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062; # (a𝅥◌᷺◌̛◌᷎b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STEM, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D166 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062; # (a◌᷺◌̛◌᷎𝅦b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, LATIN SMALL LETTER B +0061 1D166 1DFA 031B 1DCE 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062; # (a𝅦◌᷺◌̛◌᷎b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 16FF0 0334 1D167 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062; # (a𖿰◌̴◌𝅧b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-1, LATIN SMALL LETTER B +0061 1D167 16FF0 0334 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062; # (a◌𝅧𖿰◌̴b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-1, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1D168 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062; # (a𖿰◌̴◌𝅨b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-2, LATIN SMALL LETTER B +0061 1D168 16FF0 0334 0062;0061 1D168 0334 16FF0 0062;0061 1D168 0334 16FF0 0062;0061 1D168 0334 16FF0 0062;0061 1D168 0334 16FF0 0062; # (a◌𝅨𖿰◌̴b; a◌𝅨◌̴𖿰b; a◌𝅨◌̴𖿰b; a◌𝅨◌̴𖿰b; a◌𝅨◌̴𖿰b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-2, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 16FF0 0334 1D169 0062;0061 0334 1D169 16FF0 0062;0061 0334 1D169 16FF0 0062;0061 0334 1D169 16FF0 0062;0061 0334 1D169 16FF0 0062; # (a𖿰◌̴◌𝅩b; a◌̴◌𝅩𖿰b; a◌̴◌𝅩𖿰b; a◌̴◌𝅩𖿰b; a◌̴◌𝅩𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-3, LATIN SMALL LETTER B +0061 1D169 16FF0 0334 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062; # (a◌𝅩𖿰◌̴b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-3, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05AE 1D16D 302E 1D16D 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a◌〮𝅭𝅭֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 1D16D 05AE 1D16D 302E 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a𝅭◌〮𝅭֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D16E 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062; # (a◌᷺◌̛◌᷎𝅮b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-1, LATIN SMALL LETTER B +0061 1D16E 1DFA 031B 1DCE 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062; # (a𝅮◌᷺◌̛◌᷎b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-1, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D16F 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062; # (a◌᷺◌̛◌᷎𝅯b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-2, LATIN SMALL LETTER B +0061 1D16F 1DFA 031B 1DCE 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062; # (a𝅯◌᷺◌̛◌᷎b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-2, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D170 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062; # (a◌᷺◌̛◌᷎𝅰b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-3, LATIN SMALL LETTER B +0061 1D170 1DFA 031B 1DCE 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062; # (a𝅰◌᷺◌̛◌᷎b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-3, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D171 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062; # (a◌᷺◌̛◌᷎𝅱b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-4, LATIN SMALL LETTER B +0061 1D171 1DFA 031B 1DCE 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062; # (a𝅱◌᷺◌̛◌᷎b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-4, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D172 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062; # (a◌᷺◌̛◌᷎𝅲b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-5, LATIN SMALL LETTER B +0061 1D172 1DFA 031B 1DCE 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062; # (a𝅲◌᷺◌̛◌᷎b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-5, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17B 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062; # (a◌֚◌̖◌᷺◌𝅻b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING ACCENT, LATIN SMALL LETTER B +0061 1D17B 059A 0316 1DFA 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062; # (a◌𝅻◌֚◌̖◌᷺b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17C 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062; # (a◌֚◌̖◌᷺◌𝅼b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING STACCATO, LATIN SMALL LETTER B +0061 1D17C 059A 0316 1DFA 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062; # (a◌𝅼◌֚◌̖◌᷺b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17D 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062; # (a◌֚◌̖◌᷺◌𝅽b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING TENUTO, LATIN SMALL LETTER B +0061 1D17D 059A 0316 1DFA 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062; # (a◌𝅽◌֚◌̖◌᷺b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TENUTO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17E 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062; # (a◌֚◌̖◌᷺◌𝅾b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING STACCATISSIMO, LATIN SMALL LETTER B +0061 1D17E 059A 0316 1DFA 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062; # (a◌𝅾◌֚◌̖◌᷺b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATISSIMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17F 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062; # (a◌֚◌̖◌᷺◌𝅿b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING MARCATO, LATIN SMALL LETTER B +0061 1D17F 059A 0316 1DFA 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062; # (a◌𝅿◌֚◌̖◌᷺b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D180 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062; # (a◌֚◌̖◌᷺◌𝆀b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, LATIN SMALL LETTER B +0061 1D180 059A 0316 1DFA 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062; # (a◌𝆀◌֚◌̖◌᷺b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D181 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062; # (a◌֚◌̖◌᷺◌𝆁b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, LATIN SMALL LETTER B +0061 1D181 059A 0316 1DFA 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062; # (a◌𝆁◌֚◌̖◌᷺b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D182 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062; # (a◌֚◌̖◌᷺◌𝆂b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING LOURE, LATIN SMALL LETTER B +0061 1D182 059A 0316 1DFA 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062; # (a◌𝆂◌֚◌̖◌᷺b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING LOURE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D185 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062; # (a◌̕◌̀◌֮◌𝆅b; à◌֮◌𝆅◌̕b; a◌֮◌̀◌𝆅◌̕b; à◌֮◌𝆅◌̕b; a◌֮◌̀◌𝆅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOIT, LATIN SMALL LETTER B +0061 1D185 0315 0300 05AE 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062; # (a◌𝆅◌̕◌̀◌֮b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOIT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D186 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062; # (a◌̕◌̀◌֮◌𝆆b; à◌֮◌𝆆◌̕b; a◌֮◌̀◌𝆆◌̕b; à◌֮◌𝆆◌̕b; a◌֮◌̀◌𝆆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING RIP, LATIN SMALL LETTER B +0061 1D186 0315 0300 05AE 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062;0061 05AE 1D186 0300 0315 0062; # (a◌𝆆◌̕◌̀◌֮b; a◌֮◌𝆆◌̀◌̕b; a◌֮◌𝆆◌̀◌̕b; a◌֮◌𝆆◌̀◌̕b; a◌֮◌𝆆◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING RIP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D187 0062;00E0 05AE 1D187 0315 0062;0061 05AE 0300 1D187 0315 0062;00E0 05AE 1D187 0315 0062;0061 05AE 0300 1D187 0315 0062; # (a◌̕◌̀◌֮◌𝆇b; à◌֮◌𝆇◌̕b; a◌֮◌̀◌𝆇◌̕b; à◌֮◌𝆇◌̕b; a◌֮◌̀◌𝆇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING FLIP, LATIN SMALL LETTER B +0061 1D187 0315 0300 05AE 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062;0061 05AE 1D187 0300 0315 0062; # (a◌𝆇◌̕◌̀◌֮b; a◌֮◌𝆇◌̀◌̕b; a◌֮◌𝆇◌̀◌̕b; a◌֮◌𝆇◌̀◌̕b; a◌֮◌𝆇◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLIP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D188 0062;00E0 05AE 1D188 0315 0062;0061 05AE 0300 1D188 0315 0062;00E0 05AE 1D188 0315 0062;0061 05AE 0300 1D188 0315 0062; # (a◌̕◌̀◌֮◌𝆈b; à◌֮◌𝆈◌̕b; a◌֮◌̀◌𝆈◌̕b; à◌֮◌𝆈◌̕b; a◌֮◌̀◌𝆈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING SMEAR, LATIN SMALL LETTER B +0061 1D188 0315 0300 05AE 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062; # (a◌𝆈◌̕◌̀◌֮b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SMEAR, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D189 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062; # (a◌̕◌̀◌֮◌𝆉b; à◌֮◌𝆉◌̕b; a◌֮◌̀◌𝆉◌̕b; à◌֮◌𝆉◌̕b; a◌֮◌̀◌𝆉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING BEND, LATIN SMALL LETTER B +0061 1D189 0315 0300 05AE 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062; # (a◌𝆉◌̕◌̀◌֮b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING BEND, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D18A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062; # (a◌֚◌̖◌᷺◌𝆊b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, LATIN SMALL LETTER B +0061 1D18A 059A 0316 1DFA 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062; # (a◌𝆊◌֚◌̖◌᷺b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D18B 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062; # (a◌֚◌̖◌᷺◌𝆋b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, LATIN SMALL LETTER B +0061 1D18B 059A 0316 1DFA 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062; # (a◌𝆋◌֚◌̖◌᷺b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AA 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062; # (a◌̕◌̀◌֮◌𝆪b; à◌֮◌𝆪◌̕b; a◌֮◌̀◌𝆪◌̕b; à◌֮◌𝆪◌̕b; a◌֮◌̀◌𝆪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOWN BOW, LATIN SMALL LETTER B +0061 1D1AA 0315 0300 05AE 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062; # (a◌𝆪◌̕◌̀◌֮b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOWN BOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AB 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062; # (a◌̕◌̀◌֮◌𝆫b; à◌֮◌𝆫◌̕b; a◌֮◌̀◌𝆫◌̕b; à◌֮◌𝆫◌̕b; a◌֮◌̀◌𝆫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING UP BOW, LATIN SMALL LETTER B +0061 1D1AB 0315 0300 05AE 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062;0061 05AE 1D1AB 0300 0315 0062; # (a◌𝆫◌̕◌̀◌֮b; a◌֮◌𝆫◌̀◌̕b; a◌֮◌𝆫◌̀◌̕b; a◌֮◌𝆫◌̀◌̕b; a◌֮◌𝆫◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING UP BOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AC 0062;00E0 05AE 1D1AC 0315 0062;0061 05AE 0300 1D1AC 0315 0062;00E0 05AE 1D1AC 0315 0062;0061 05AE 0300 1D1AC 0315 0062; # (a◌̕◌̀◌֮◌𝆬b; à◌֮◌𝆬◌̕b; a◌֮◌̀◌𝆬◌̕b; à◌֮◌𝆬◌̕b; a◌֮◌̀◌𝆬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING HARMONIC, LATIN SMALL LETTER B +0061 1D1AC 0315 0300 05AE 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062;0061 05AE 1D1AC 0300 0315 0062; # (a◌𝆬◌̕◌̀◌֮b; a◌֮◌𝆬◌̀◌̕b; a◌֮◌𝆬◌̀◌̕b; a◌֮◌𝆬◌̀◌̕b; a◌֮◌𝆬◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING HARMONIC, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D1AD 0062;00E0 05AE 1D1AD 0315 0062;0061 05AE 0300 1D1AD 0315 0062;00E0 05AE 1D1AD 0315 0062;0061 05AE 0300 1D1AD 0315 0062; # (a◌̕◌̀◌֮◌𝆭b; à◌֮◌𝆭◌̕b; a◌֮◌̀◌𝆭◌̕b; à◌֮◌𝆭◌̕b; a◌֮◌̀◌𝆭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING SNAP PIZZICATO, LATIN SMALL LETTER B +0061 1D1AD 0315 0300 05AE 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062;0061 05AE 1D1AD 0300 0315 0062; # (a◌𝆭◌̕◌̀◌֮b; a◌֮◌𝆭◌̀◌̕b; a◌֮◌𝆭◌̀◌̕b; a◌֮◌𝆭◌̀◌̕b; a◌֮◌𝆭◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SNAP PIZZICATO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D242 0062;00E0 05AE 1D242 0315 0062;0061 05AE 0300 1D242 0315 0062;00E0 05AE 1D242 0315 0062;0061 05AE 0300 1D242 0315 0062; # (a◌̕◌̀◌֮◌𝉂b; à◌֮◌𝉂◌̕b; a◌֮◌̀◌𝉂◌̕b; à◌֮◌𝉂◌̕b; a◌֮◌̀◌𝉂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK MUSICAL TRISEME, LATIN SMALL LETTER B +0061 1D242 0315 0300 05AE 0062;0061 05AE 1D242 0300 0315 0062;0061 05AE 1D242 0300 0315 0062;0061 05AE 1D242 0300 0315 0062;0061 05AE 1D242 0300 0315 0062; # (a◌𝉂◌̕◌̀◌֮b; a◌֮◌𝉂◌̀◌̕b; a◌֮◌𝉂◌̀◌̕b; a◌֮◌𝉂◌̀◌̕b; a◌֮◌𝉂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK MUSICAL TRISEME, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D243 0062;00E0 05AE 1D243 0315 0062;0061 05AE 0300 1D243 0315 0062;00E0 05AE 1D243 0315 0062;0061 05AE 0300 1D243 0315 0062; # (a◌̕◌̀◌֮◌𝉃b; à◌֮◌𝉃◌̕b; a◌֮◌̀◌𝉃◌̕b; à◌֮◌𝉃◌̕b; a◌֮◌̀◌𝉃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK MUSICAL TETRASEME, LATIN SMALL LETTER B +0061 1D243 0315 0300 05AE 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062; # (a◌𝉃◌̕◌̀◌֮b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK MUSICAL TETRASEME, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1D244 0062;00E0 05AE 1D244 0315 0062;0061 05AE 0300 1D244 0315 0062;00E0 05AE 1D244 0315 0062;0061 05AE 0300 1D244 0315 0062; # (a◌̕◌̀◌֮◌𝉄b; à◌֮◌𝉄◌̕b; a◌֮◌̀◌𝉄◌̕b; à◌֮◌𝉄◌̕b; a◌֮◌̀◌𝉄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK MUSICAL PENTASEME, LATIN SMALL LETTER B +0061 1D244 0315 0300 05AE 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062; # (a◌𝉄◌̕◌̀◌֮b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK MUSICAL PENTASEME, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E000 0062;00E0 05AE 1E000 0315 0062;0061 05AE 0300 1E000 0315 0062;00E0 05AE 1E000 0315 0062;0061 05AE 0300 1E000 0315 0062; # (a◌̕◌̀◌֮◌𞀀b; à◌֮◌𞀀◌̕b; a◌֮◌̀◌𞀀◌̕b; à◌֮◌𞀀◌̕b; a◌֮◌̀◌𞀀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER AZU, LATIN SMALL LETTER B +0061 1E000 0315 0300 05AE 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062; # (a◌𞀀◌̕◌̀◌֮b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER AZU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E001 0062;00E0 05AE 1E001 0315 0062;0061 05AE 0300 1E001 0315 0062;00E0 05AE 1E001 0315 0062;0061 05AE 0300 1E001 0315 0062; # (a◌̕◌̀◌֮◌𞀁b; à◌֮◌𞀁◌̕b; a◌֮◌̀◌𞀁◌̕b; à◌֮◌𞀁◌̕b; a◌֮◌̀◌𞀁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER BUKY, LATIN SMALL LETTER B +0061 1E001 0315 0300 05AE 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062; # (a◌𞀁◌̕◌̀◌֮b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER BUKY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E002 0062;00E0 05AE 1E002 0315 0062;0061 05AE 0300 1E002 0315 0062;00E0 05AE 1E002 0315 0062;0061 05AE 0300 1E002 0315 0062; # (a◌̕◌̀◌֮◌𞀂b; à◌֮◌𞀂◌̕b; a◌֮◌̀◌𞀂◌̕b; à◌֮◌𞀂◌̕b; a◌֮◌̀◌𞀂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER VEDE, LATIN SMALL LETTER B +0061 1E002 0315 0300 05AE 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062; # (a◌𞀂◌̕◌̀◌֮b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER VEDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E003 0062;00E0 05AE 1E003 0315 0062;0061 05AE 0300 1E003 0315 0062;00E0 05AE 1E003 0315 0062;0061 05AE 0300 1E003 0315 0062; # (a◌̕◌̀◌֮◌𞀃b; à◌֮◌𞀃◌̕b; a◌֮◌̀◌𞀃◌̕b; à◌֮◌𞀃◌̕b; a◌֮◌̀◌𞀃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER GLAGOLI, LATIN SMALL LETTER B +0061 1E003 0315 0300 05AE 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062; # (a◌𞀃◌̕◌̀◌֮b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER GLAGOLI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E004 0062;00E0 05AE 1E004 0315 0062;0061 05AE 0300 1E004 0315 0062;00E0 05AE 1E004 0315 0062;0061 05AE 0300 1E004 0315 0062; # (a◌̕◌̀◌֮◌𞀄b; à◌֮◌𞀄◌̕b; a◌֮◌̀◌𞀄◌̕b; à◌֮◌𞀄◌̕b; a◌֮◌̀◌𞀄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER DOBRO, LATIN SMALL LETTER B +0061 1E004 0315 0300 05AE 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062; # (a◌𞀄◌̕◌̀◌֮b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER DOBRO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E005 0062;00E0 05AE 1E005 0315 0062;0061 05AE 0300 1E005 0315 0062;00E0 05AE 1E005 0315 0062;0061 05AE 0300 1E005 0315 0062; # (a◌̕◌̀◌֮◌𞀅b; à◌֮◌𞀅◌̕b; a◌֮◌̀◌𞀅◌̕b; à◌֮◌𞀅◌̕b; a◌֮◌̀◌𞀅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YESTU, LATIN SMALL LETTER B +0061 1E005 0315 0300 05AE 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062; # (a◌𞀅◌̕◌̀◌֮b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YESTU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E006 0062;00E0 05AE 1E006 0315 0062;0061 05AE 0300 1E006 0315 0062;00E0 05AE 1E006 0315 0062;0061 05AE 0300 1E006 0315 0062; # (a◌̕◌̀◌֮◌𞀆b; à◌֮◌𞀆◌̕b; a◌֮◌̀◌𞀆◌̕b; à◌֮◌𞀆◌̕b; a◌֮◌̀◌𞀆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ZHIVETE, LATIN SMALL LETTER B +0061 1E006 0315 0300 05AE 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062; # (a◌𞀆◌̕◌̀◌֮b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ZHIVETE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E008 0062;00E0 05AE 1E008 0315 0062;0061 05AE 0300 1E008 0315 0062;00E0 05AE 1E008 0315 0062;0061 05AE 0300 1E008 0315 0062; # (a◌̕◌̀◌֮◌𞀈b; à◌֮◌𞀈◌̕b; a◌֮◌̀◌𞀈◌̕b; à◌֮◌𞀈◌̕b; a◌֮◌̀◌𞀈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ZEMLJA, LATIN SMALL LETTER B +0061 1E008 0315 0300 05AE 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062; # (a◌𞀈◌̕◌̀◌֮b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ZEMLJA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E009 0062;00E0 05AE 1E009 0315 0062;0061 05AE 0300 1E009 0315 0062;00E0 05AE 1E009 0315 0062;0061 05AE 0300 1E009 0315 0062; # (a◌̕◌̀◌֮◌𞀉b; à◌֮◌𞀉◌̕b; a◌֮◌̀◌𞀉◌̕b; à◌֮◌𞀉◌̕b; a◌֮◌̀◌𞀉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IZHE, LATIN SMALL LETTER B +0061 1E009 0315 0300 05AE 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062; # (a◌𞀉◌̕◌̀◌֮b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IZHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00A 0062;00E0 05AE 1E00A 0315 0062;0061 05AE 0300 1E00A 0315 0062;00E0 05AE 1E00A 0315 0062;0061 05AE 0300 1E00A 0315 0062; # (a◌̕◌̀◌֮◌𞀊b; à◌֮◌𞀊◌̕b; a◌֮◌̀◌𞀊◌̕b; à◌֮◌𞀊◌̕b; a◌֮◌̀◌𞀊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER INITIAL IZHE, LATIN SMALL LETTER B +0061 1E00A 0315 0300 05AE 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062; # (a◌𞀊◌̕◌̀◌֮b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER INITIAL IZHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00B 0062;00E0 05AE 1E00B 0315 0062;0061 05AE 0300 1E00B 0315 0062;00E0 05AE 1E00B 0315 0062;0061 05AE 0300 1E00B 0315 0062; # (a◌̕◌̀◌֮◌𞀋b; à◌֮◌𞀋◌̕b; a◌֮◌̀◌𞀋◌̕b; à◌֮◌𞀋◌̕b; a◌֮◌̀◌𞀋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER I, LATIN SMALL LETTER B +0061 1E00B 0315 0300 05AE 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062; # (a◌𞀋◌̕◌̀◌֮b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00C 0062;00E0 05AE 1E00C 0315 0062;0061 05AE 0300 1E00C 0315 0062;00E0 05AE 1E00C 0315 0062;0061 05AE 0300 1E00C 0315 0062; # (a◌̕◌̀◌֮◌𞀌b; à◌֮◌𞀌◌̕b; a◌֮◌̀◌𞀌◌̕b; à◌֮◌𞀌◌̕b; a◌֮◌̀◌𞀌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER DJERVI, LATIN SMALL LETTER B +0061 1E00C 0315 0300 05AE 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062; # (a◌𞀌◌̕◌̀◌֮b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER DJERVI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00D 0062;00E0 05AE 1E00D 0315 0062;0061 05AE 0300 1E00D 0315 0062;00E0 05AE 1E00D 0315 0062;0061 05AE 0300 1E00D 0315 0062; # (a◌̕◌̀◌֮◌𞀍b; à◌֮◌𞀍◌̕b; a◌֮◌̀◌𞀍◌̕b; à◌֮◌𞀍◌̕b; a◌֮◌̀◌𞀍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER KAKO, LATIN SMALL LETTER B +0061 1E00D 0315 0300 05AE 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062; # (a◌𞀍◌̕◌̀◌֮b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER KAKO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00E 0062;00E0 05AE 1E00E 0315 0062;0061 05AE 0300 1E00E 0315 0062;00E0 05AE 1E00E 0315 0062;0061 05AE 0300 1E00E 0315 0062; # (a◌̕◌̀◌֮◌𞀎b; à◌֮◌𞀎◌̕b; a◌֮◌̀◌𞀎◌̕b; à◌֮◌𞀎◌̕b; a◌֮◌̀◌𞀎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER LJUDIJE, LATIN SMALL LETTER B +0061 1E00E 0315 0300 05AE 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062; # (a◌𞀎◌̕◌̀◌֮b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER LJUDIJE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00F 0062;00E0 05AE 1E00F 0315 0062;0061 05AE 0300 1E00F 0315 0062;00E0 05AE 1E00F 0315 0062;0061 05AE 0300 1E00F 0315 0062; # (a◌̕◌̀◌֮◌𞀏b; à◌֮◌𞀏◌̕b; a◌֮◌̀◌𞀏◌̕b; à◌֮◌𞀏◌̕b; a◌֮◌̀◌𞀏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER MYSLITE, LATIN SMALL LETTER B +0061 1E00F 0315 0300 05AE 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062; # (a◌𞀏◌̕◌̀◌֮b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER MYSLITE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E010 0062;00E0 05AE 1E010 0315 0062;0061 05AE 0300 1E010 0315 0062;00E0 05AE 1E010 0315 0062;0061 05AE 0300 1E010 0315 0062; # (a◌̕◌̀◌֮◌𞀐b; à◌֮◌𞀐◌̕b; a◌֮◌̀◌𞀐◌̕b; à◌֮◌𞀐◌̕b; a◌֮◌̀◌𞀐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER NASHI, LATIN SMALL LETTER B +0061 1E010 0315 0300 05AE 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062; # (a◌𞀐◌̕◌̀◌֮b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER NASHI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E011 0062;00E0 05AE 1E011 0315 0062;0061 05AE 0300 1E011 0315 0062;00E0 05AE 1E011 0315 0062;0061 05AE 0300 1E011 0315 0062; # (a◌̕◌̀◌֮◌𞀑b; à◌֮◌𞀑◌̕b; a◌֮◌̀◌𞀑◌̕b; à◌֮◌𞀑◌̕b; a◌֮◌̀◌𞀑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ONU, LATIN SMALL LETTER B +0061 1E011 0315 0300 05AE 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062; # (a◌𞀑◌̕◌̀◌֮b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ONU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E012 0062;00E0 05AE 1E012 0315 0062;0061 05AE 0300 1E012 0315 0062;00E0 05AE 1E012 0315 0062;0061 05AE 0300 1E012 0315 0062; # (a◌̕◌̀◌֮◌𞀒b; à◌֮◌𞀒◌̕b; a◌֮◌̀◌𞀒◌̕b; à◌֮◌𞀒◌̕b; a◌֮◌̀◌𞀒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER POKOJI, LATIN SMALL LETTER B +0061 1E012 0315 0300 05AE 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062; # (a◌𞀒◌̕◌̀◌֮b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER POKOJI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E013 0062;00E0 05AE 1E013 0315 0062;0061 05AE 0300 1E013 0315 0062;00E0 05AE 1E013 0315 0062;0061 05AE 0300 1E013 0315 0062; # (a◌̕◌̀◌֮◌𞀓b; à◌֮◌𞀓◌̕b; a◌֮◌̀◌𞀓◌̕b; à◌֮◌𞀓◌̕b; a◌֮◌̀◌𞀓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER RITSI, LATIN SMALL LETTER B +0061 1E013 0315 0300 05AE 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062; # (a◌𞀓◌̕◌̀◌֮b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER RITSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E014 0062;00E0 05AE 1E014 0315 0062;0061 05AE 0300 1E014 0315 0062;00E0 05AE 1E014 0315 0062;0061 05AE 0300 1E014 0315 0062; # (a◌̕◌̀◌֮◌𞀔b; à◌֮◌𞀔◌̕b; a◌֮◌̀◌𞀔◌̕b; à◌֮◌𞀔◌̕b; a◌֮◌̀◌𞀔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SLOVO, LATIN SMALL LETTER B +0061 1E014 0315 0300 05AE 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062; # (a◌𞀔◌̕◌̀◌֮b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SLOVO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E015 0062;00E0 05AE 1E015 0315 0062;0061 05AE 0300 1E015 0315 0062;00E0 05AE 1E015 0315 0062;0061 05AE 0300 1E015 0315 0062; # (a◌̕◌̀◌֮◌𞀕b; à◌֮◌𞀕◌̕b; a◌֮◌̀◌𞀕◌̕b; à◌֮◌𞀕◌̕b; a◌֮◌̀◌𞀕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER TVRIDO, LATIN SMALL LETTER B +0061 1E015 0315 0300 05AE 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062; # (a◌𞀕◌̕◌̀◌֮b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER TVRIDO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E016 0062;00E0 05AE 1E016 0315 0062;0061 05AE 0300 1E016 0315 0062;00E0 05AE 1E016 0315 0062;0061 05AE 0300 1E016 0315 0062; # (a◌̕◌̀◌֮◌𞀖b; à◌֮◌𞀖◌̕b; a◌֮◌̀◌𞀖◌̕b; à◌֮◌𞀖◌̕b; a◌֮◌̀◌𞀖◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER UKU, LATIN SMALL LETTER B +0061 1E016 0315 0300 05AE 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062; # (a◌𞀖◌̕◌̀◌֮b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER UKU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E017 0062;00E0 05AE 1E017 0315 0062;0061 05AE 0300 1E017 0315 0062;00E0 05AE 1E017 0315 0062;0061 05AE 0300 1E017 0315 0062; # (a◌̕◌̀◌֮◌𞀗b; à◌֮◌𞀗◌̕b; a◌֮◌̀◌𞀗◌̕b; à◌֮◌𞀗◌̕b; a◌֮◌̀◌𞀗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER FRITU, LATIN SMALL LETTER B +0061 1E017 0315 0300 05AE 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062; # (a◌𞀗◌̕◌̀◌֮b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER FRITU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E018 0062;00E0 05AE 1E018 0315 0062;0061 05AE 0300 1E018 0315 0062;00E0 05AE 1E018 0315 0062;0061 05AE 0300 1E018 0315 0062; # (a◌̕◌̀◌֮◌𞀘b; à◌֮◌𞀘◌̕b; a◌֮◌̀◌𞀘◌̕b; à◌֮◌𞀘◌̕b; a◌֮◌̀◌𞀘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER HERU, LATIN SMALL LETTER B +0061 1E018 0315 0300 05AE 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062; # (a◌𞀘◌̕◌̀◌֮b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER HERU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01B 0062;00E0 05AE 1E01B 0315 0062;0061 05AE 0300 1E01B 0315 0062;00E0 05AE 1E01B 0315 0062;0061 05AE 0300 1E01B 0315 0062; # (a◌̕◌̀◌֮◌𞀛b; à◌֮◌𞀛◌̕b; a◌֮◌̀◌𞀛◌̕b; à◌֮◌𞀛◌̕b; a◌֮◌̀◌𞀛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SHTA, LATIN SMALL LETTER B +0061 1E01B 0315 0300 05AE 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062; # (a◌𞀛◌̕◌̀◌֮b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SHTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01C 0062;00E0 05AE 1E01C 0315 0062;0061 05AE 0300 1E01C 0315 0062;00E0 05AE 1E01C 0315 0062;0061 05AE 0300 1E01C 0315 0062; # (a◌̕◌̀◌֮◌𞀜b; à◌֮◌𞀜◌̕b; a◌֮◌̀◌𞀜◌̕b; à◌֮◌𞀜◌̕b; a◌֮◌̀◌𞀜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER TSI, LATIN SMALL LETTER B +0061 1E01C 0315 0300 05AE 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062; # (a◌𞀜◌̕◌̀◌֮b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER TSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01D 0062;00E0 05AE 1E01D 0315 0062;0061 05AE 0300 1E01D 0315 0062;00E0 05AE 1E01D 0315 0062;0061 05AE 0300 1E01D 0315 0062; # (a◌̕◌̀◌֮◌𞀝b; à◌֮◌𞀝◌̕b; a◌֮◌̀◌𞀝◌̕b; à◌֮◌𞀝◌̕b; a◌֮◌̀◌𞀝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER CHRIVI, LATIN SMALL LETTER B +0061 1E01D 0315 0300 05AE 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062; # (a◌𞀝◌̕◌̀◌֮b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER CHRIVI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01E 0062;00E0 05AE 1E01E 0315 0062;0061 05AE 0300 1E01E 0315 0062;00E0 05AE 1E01E 0315 0062;0061 05AE 0300 1E01E 0315 0062; # (a◌̕◌̀◌֮◌𞀞b; à◌֮◌𞀞◌̕b; a◌֮◌̀◌𞀞◌̕b; à◌֮◌𞀞◌̕b; a◌֮◌̀◌𞀞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SHA, LATIN SMALL LETTER B +0061 1E01E 0315 0300 05AE 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062; # (a◌𞀞◌̕◌̀◌֮b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01F 0062;00E0 05AE 1E01F 0315 0062;0061 05AE 0300 1E01F 0315 0062;00E0 05AE 1E01F 0315 0062;0061 05AE 0300 1E01F 0315 0062; # (a◌̕◌̀◌֮◌𞀟b; à◌֮◌𞀟◌̕b; a◌֮◌̀◌𞀟◌̕b; à◌֮◌𞀟◌̕b; a◌֮◌̀◌𞀟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YERU, LATIN SMALL LETTER B +0061 1E01F 0315 0300 05AE 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062; # (a◌𞀟◌̕◌̀◌֮b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YERU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E020 0062;00E0 05AE 1E020 0315 0062;0061 05AE 0300 1E020 0315 0062;00E0 05AE 1E020 0315 0062;0061 05AE 0300 1E020 0315 0062; # (a◌̕◌̀◌֮◌𞀠b; à◌֮◌𞀠◌̕b; a◌֮◌̀◌𞀠◌̕b; à◌֮◌𞀠◌̕b; a◌֮◌̀◌𞀠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YERI, LATIN SMALL LETTER B +0061 1E020 0315 0300 05AE 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062; # (a◌𞀠◌̕◌̀◌֮b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YERI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E021 0062;00E0 05AE 1E021 0315 0062;0061 05AE 0300 1E021 0315 0062;00E0 05AE 1E021 0315 0062;0061 05AE 0300 1E021 0315 0062; # (a◌̕◌̀◌֮◌𞀡b; à◌֮◌𞀡◌̕b; a◌֮◌̀◌𞀡◌̕b; à◌֮◌𞀡◌̕b; a◌֮◌̀◌𞀡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YATI, LATIN SMALL LETTER B +0061 1E021 0315 0300 05AE 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062; # (a◌𞀡◌̕◌̀◌֮b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YATI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E023 0062;00E0 05AE 1E023 0315 0062;0061 05AE 0300 1E023 0315 0062;00E0 05AE 1E023 0315 0062;0061 05AE 0300 1E023 0315 0062; # (a◌̕◌̀◌֮◌𞀣b; à◌֮◌𞀣◌̕b; a◌֮◌̀◌𞀣◌̕b; à◌֮◌𞀣◌̕b; a◌֮◌̀◌𞀣◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YU, LATIN SMALL LETTER B +0061 1E023 0315 0300 05AE 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062; # (a◌𞀣◌̕◌̀◌֮b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E024 0062;00E0 05AE 1E024 0315 0062;0061 05AE 0300 1E024 0315 0062;00E0 05AE 1E024 0315 0062;0061 05AE 0300 1E024 0315 0062; # (a◌̕◌̀◌֮◌𞀤b; à◌֮◌𞀤◌̕b; a◌֮◌̀◌𞀤◌̕b; à◌֮◌𞀤◌̕b; a◌֮◌̀◌𞀤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SMALL YUS, LATIN SMALL LETTER B +0061 1E024 0315 0300 05AE 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062; # (a◌𞀤◌̕◌̀◌֮b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SMALL YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E026 0062;00E0 05AE 1E026 0315 0062;0061 05AE 0300 1E026 0315 0062;00E0 05AE 1E026 0315 0062;0061 05AE 0300 1E026 0315 0062; # (a◌̕◌̀◌֮◌𞀦b; à◌֮◌𞀦◌̕b; a◌֮◌̀◌𞀦◌̕b; à◌֮◌𞀦◌̕b; a◌֮◌̀◌𞀦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YO, LATIN SMALL LETTER B +0061 1E026 0315 0300 05AE 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062; # (a◌𞀦◌̕◌̀◌֮b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E027 0062;00E0 05AE 1E027 0315 0062;0061 05AE 0300 1E027 0315 0062;00E0 05AE 1E027 0315 0062;0061 05AE 0300 1E027 0315 0062; # (a◌̕◌̀◌֮◌𞀧b; à◌֮◌𞀧◌̕b; a◌֮◌̀◌𞀧◌̕b; à◌֮◌𞀧◌̕b; a◌֮◌̀◌𞀧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS, LATIN SMALL LETTER B +0061 1E027 0315 0300 05AE 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062; # (a◌𞀧◌̕◌̀◌֮b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E028 0062;00E0 05AE 1E028 0315 0062;0061 05AE 0300 1E028 0315 0062;00E0 05AE 1E028 0315 0062;0061 05AE 0300 1E028 0315 0062; # (a◌̕◌̀◌֮◌𞀨b; à◌֮◌𞀨◌̕b; a◌֮◌̀◌𞀨◌̕b; à◌֮◌𞀨◌̕b; a◌֮◌̀◌𞀨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER BIG YUS, LATIN SMALL LETTER B +0061 1E028 0315 0300 05AE 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062; # (a◌𞀨◌̕◌̀◌֮b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E029 0062;00E0 05AE 1E029 0315 0062;0061 05AE 0300 1E029 0315 0062;00E0 05AE 1E029 0315 0062;0061 05AE 0300 1E029 0315 0062; # (a◌̕◌̀◌֮◌𞀩b; à◌֮◌𞀩◌̕b; a◌֮◌̀◌𞀩◌̕b; à◌֮◌𞀩◌̕b; a◌֮◌̀◌𞀩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IOTATED BIG YUS, LATIN SMALL LETTER B +0061 1E029 0315 0300 05AE 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062; # (a◌𞀩◌̕◌̀◌֮b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IOTATED BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E02A 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062; # (a◌̕◌̀◌֮◌𞀪b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER FITA, LATIN SMALL LETTER B +0061 1E02A 0315 0300 05AE 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062; # (a◌𞀪◌̕◌̀◌֮b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER FITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E130 0062;00E0 05AE 1E130 0315 0062;0061 05AE 0300 1E130 0315 0062;00E0 05AE 1E130 0315 0062;0061 05AE 0300 1E130 0315 0062; # (a◌̕◌̀◌֮◌𞄰b; à◌֮◌𞄰◌̕b; a◌֮◌̀◌𞄰◌̕b; à◌֮◌𞄰◌̕b; a◌֮◌̀◌𞄰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-B, LATIN SMALL LETTER B +0061 1E130 0315 0300 05AE 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062; # (a◌𞄰◌̕◌̀◌֮b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-B, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E131 0062;00E0 05AE 1E131 0315 0062;0061 05AE 0300 1E131 0315 0062;00E0 05AE 1E131 0315 0062;0061 05AE 0300 1E131 0315 0062; # (a◌̕◌̀◌֮◌𞄱b; à◌֮◌𞄱◌̕b; a◌֮◌̀◌𞄱◌̕b; à◌֮◌𞄱◌̕b; a◌֮◌̀◌𞄱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-M, LATIN SMALL LETTER B +0061 1E131 0315 0300 05AE 0062;0061 05AE 1E131 0300 0315 0062;0061 05AE 1E131 0300 0315 0062;0061 05AE 1E131 0300 0315 0062;0061 05AE 1E131 0300 0315 0062; # (a◌𞄱◌̕◌̀◌֮b; a◌֮◌𞄱◌̀◌̕b; a◌֮◌𞄱◌̀◌̕b; a◌֮◌𞄱◌̀◌̕b; a◌֮◌𞄱◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-M, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E132 0062;00E0 05AE 1E132 0315 0062;0061 05AE 0300 1E132 0315 0062;00E0 05AE 1E132 0315 0062;0061 05AE 0300 1E132 0315 0062; # (a◌̕◌̀◌֮◌𞄲b; à◌֮◌𞄲◌̕b; a◌֮◌̀◌𞄲◌̕b; à◌֮◌𞄲◌̕b; a◌֮◌̀◌𞄲◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-J, LATIN SMALL LETTER B +0061 1E132 0315 0300 05AE 0062;0061 05AE 1E132 0300 0315 0062;0061 05AE 1E132 0300 0315 0062;0061 05AE 1E132 0300 0315 0062;0061 05AE 1E132 0300 0315 0062; # (a◌𞄲◌̕◌̀◌֮b; a◌֮◌𞄲◌̀◌̕b; a◌֮◌𞄲◌̀◌̕b; a◌֮◌𞄲◌̀◌̕b; a◌֮◌𞄲◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-J, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E133 0062;00E0 05AE 1E133 0315 0062;0061 05AE 0300 1E133 0315 0062;00E0 05AE 1E133 0315 0062;0061 05AE 0300 1E133 0315 0062; # (a◌̕◌̀◌֮◌𞄳b; à◌֮◌𞄳◌̕b; a◌֮◌̀◌𞄳◌̕b; à◌֮◌𞄳◌̕b; a◌֮◌̀◌𞄳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-V, LATIN SMALL LETTER B +0061 1E133 0315 0300 05AE 0062;0061 05AE 1E133 0300 0315 0062;0061 05AE 1E133 0300 0315 0062;0061 05AE 1E133 0300 0315 0062;0061 05AE 1E133 0300 0315 0062; # (a◌𞄳◌̕◌̀◌֮b; a◌֮◌𞄳◌̀◌̕b; a◌֮◌𞄳◌̀◌̕b; a◌֮◌𞄳◌̀◌̕b; a◌֮◌𞄳◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-V, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E134 0062;00E0 05AE 1E134 0315 0062;0061 05AE 0300 1E134 0315 0062;00E0 05AE 1E134 0315 0062;0061 05AE 0300 1E134 0315 0062; # (a◌̕◌̀◌֮◌𞄴b; à◌֮◌𞄴◌̕b; a◌֮◌̀◌𞄴◌̕b; à◌֮◌𞄴◌̕b; a◌֮◌̀◌𞄴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-S, LATIN SMALL LETTER B +0061 1E134 0315 0300 05AE 0062;0061 05AE 1E134 0300 0315 0062;0061 05AE 1E134 0300 0315 0062;0061 05AE 1E134 0300 0315 0062;0061 05AE 1E134 0300 0315 0062; # (a◌𞄴◌̕◌̀◌֮b; a◌֮◌𞄴◌̀◌̕b; a◌֮◌𞄴◌̀◌̕b; a◌֮◌𞄴◌̀◌̕b; a◌֮◌𞄴◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-S, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E135 0062;00E0 05AE 1E135 0315 0062;0061 05AE 0300 1E135 0315 0062;00E0 05AE 1E135 0315 0062;0061 05AE 0300 1E135 0315 0062; # (a◌̕◌̀◌֮◌𞄵b; à◌֮◌𞄵◌̕b; a◌֮◌̀◌𞄵◌̕b; à◌֮◌𞄵◌̕b; a◌֮◌̀◌𞄵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-G, LATIN SMALL LETTER B +0061 1E135 0315 0300 05AE 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062; # (a◌𞄵◌̕◌̀◌֮b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E136 0062;00E0 05AE 1E136 0315 0062;0061 05AE 0300 1E136 0315 0062;00E0 05AE 1E136 0315 0062;0061 05AE 0300 1E136 0315 0062; # (a◌̕◌̀◌֮◌𞄶b; à◌֮◌𞄶◌̕b; a◌֮◌̀◌𞄶◌̕b; à◌֮◌𞄶◌̕b; a◌֮◌̀◌𞄶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-D, LATIN SMALL LETTER B +0061 1E136 0315 0300 05AE 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062; # (a◌𞄶◌̕◌̀◌֮b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-D, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2AE 0062;00E0 05AE 1E2AE 0315 0062;0061 05AE 0300 1E2AE 0315 0062;00E0 05AE 1E2AE 0315 0062;0061 05AE 0300 1E2AE 0315 0062; # (a◌̕◌̀◌֮◌𞊮b; à◌֮◌𞊮◌̕b; a◌֮◌̀◌𞊮◌̕b; à◌֮◌𞊮◌̕b; a◌֮◌̀◌𞊮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TOTO SIGN RISING TONE, LATIN SMALL LETTER B +0061 1E2AE 0315 0300 05AE 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062; # (a◌𞊮◌̕◌̀◌֮b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; ) LATIN SMALL LETTER A, TOTO SIGN RISING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2EC 0062;00E0 05AE 1E2EC 0315 0062;0061 05AE 0300 1E2EC 0315 0062;00E0 05AE 1E2EC 0315 0062;0061 05AE 0300 1E2EC 0315 0062; # (a◌̕◌̀◌֮◌𞋬b; à◌֮◌𞋬◌̕b; a◌֮◌̀◌𞋬◌̕b; à◌֮◌𞋬◌̕b; a◌֮◌̀◌𞋬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE TUP, LATIN SMALL LETTER B +0061 1E2EC 0315 0300 05AE 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062; # (a◌𞋬◌̕◌̀◌֮b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE TUP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2ED 0062;00E0 05AE 1E2ED 0315 0062;0061 05AE 0300 1E2ED 0315 0062;00E0 05AE 1E2ED 0315 0062;0061 05AE 0300 1E2ED 0315 0062; # (a◌̕◌̀◌֮◌𞋭b; à◌֮◌𞋭◌̕b; a◌֮◌̀◌𞋭◌̕b; à◌֮◌𞋭◌̕b; a◌֮◌̀◌𞋭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE TUPNI, LATIN SMALL LETTER B +0061 1E2ED 0315 0300 05AE 0062;0061 05AE 1E2ED 0300 0315 0062;0061 05AE 1E2ED 0300 0315 0062;0061 05AE 1E2ED 0300 0315 0062;0061 05AE 1E2ED 0300 0315 0062; # (a◌𞋭◌̕◌̀◌֮b; a◌֮◌𞋭◌̀◌̕b; a◌֮◌𞋭◌̀◌̕b; a◌֮◌𞋭◌̀◌̕b; a◌֮◌𞋭◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE TUPNI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2EE 0062;00E0 05AE 1E2EE 0315 0062;0061 05AE 0300 1E2EE 0315 0062;00E0 05AE 1E2EE 0315 0062;0061 05AE 0300 1E2EE 0315 0062; # (a◌̕◌̀◌֮◌𞋮b; à◌֮◌𞋮◌̕b; a◌֮◌̀◌𞋮◌̕b; à◌֮◌𞋮◌̕b; a◌֮◌̀◌𞋮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE KOI, LATIN SMALL LETTER B +0061 1E2EE 0315 0300 05AE 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062; # (a◌𞋮◌̕◌̀◌֮b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE KOI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2EF 0062;00E0 05AE 1E2EF 0315 0062;0061 05AE 0300 1E2EF 0315 0062;00E0 05AE 1E2EF 0315 0062;0061 05AE 0300 1E2EF 0315 0062; # (a◌̕◌̀◌֮◌𞋯b; à◌֮◌𞋯◌̕b; a◌֮◌̀◌𞋯◌̕b; à◌֮◌𞋯◌̕b; a◌֮◌̀◌𞋯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE KOINI, LATIN SMALL LETTER B +0061 1E2EF 0315 0300 05AE 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062; # (a◌𞋯◌̕◌̀◌֮b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE KOINI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D0 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062; # (a◌֚◌̖◌᷺◌𞣐b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TEENS, LATIN SMALL LETTER B +0061 1E8D0 059A 0316 1DFA 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062; # (a◌𞣐◌֚◌̖◌᷺b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D1 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062; # (a◌֚◌̖◌᷺◌𞣑b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TENS, LATIN SMALL LETTER B +0061 1E8D1 059A 0316 1DFA 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062; # (a◌𞣑◌֚◌̖◌᷺b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D2 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062; # (a◌֚◌̖◌᷺◌𞣒b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, LATIN SMALL LETTER B +0061 1E8D2 059A 0316 1DFA 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062; # (a◌𞣒◌֚◌̖◌᷺b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D3 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062; # (a◌֚◌̖◌᷺◌𞣓b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, LATIN SMALL LETTER B +0061 1E8D3 059A 0316 1DFA 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062; # (a◌𞣓◌֚◌̖◌᷺b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D4 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062; # (a◌֚◌̖◌᷺◌𞣔b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, LATIN SMALL LETTER B +0061 1E8D4 059A 0316 1DFA 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062; # (a◌𞣔◌֚◌̖◌᷺b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D5 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062; # (a◌֚◌̖◌᷺◌𞣕b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, LATIN SMALL LETTER B +0061 1E8D5 059A 0316 1DFA 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062; # (a◌𞣕◌֚◌̖◌᷺b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D6 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062; # (a◌֚◌̖◌᷺◌𞣖b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER MILLIONS, LATIN SMALL LETTER B +0061 1E8D6 059A 0316 1DFA 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062; # (a◌𞣖◌֚◌̖◌᷺b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER MILLIONS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E944 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062; # (a◌̕◌̀◌֮◌𞥄b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM ALIF LENGTHENER, LATIN SMALL LETTER B +0061 1E944 0315 0300 05AE 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062; # (a◌𞥄◌̕◌̀◌֮b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM ALIF LENGTHENER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E945 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062; # (a◌̕◌̀◌֮◌𞥅b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM VOWEL LENGTHENER, LATIN SMALL LETTER B +0061 1E945 0315 0300 05AE 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062; # (a◌𞥅◌̕◌̀◌֮b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM VOWEL LENGTHENER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E946 0062;00E0 05AE 1E946 0315 0062;0061 05AE 0300 1E946 0315 0062;00E0 05AE 1E946 0315 0062;0061 05AE 0300 1E946 0315 0062; # (a◌̕◌̀◌֮◌𞥆b; à◌֮◌𞥆◌̕b; a◌֮◌̀◌𞥆◌̕b; à◌֮◌𞥆◌̕b; a◌֮◌̀◌𞥆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM GEMINATION MARK, LATIN SMALL LETTER B +0061 1E946 0315 0300 05AE 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062; # (a◌𞥆◌̕◌̀◌֮b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM GEMINATION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E947 0062;00E0 05AE 1E947 0315 0062;0061 05AE 0300 1E947 0315 0062;00E0 05AE 1E947 0315 0062;0061 05AE 0300 1E947 0315 0062; # (a◌̕◌̀◌֮◌𞥇b; à◌֮◌𞥇◌̕b; a◌֮◌̀◌𞥇◌̕b; à◌֮◌𞥇◌̕b; a◌֮◌̀◌𞥇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM HAMZA, LATIN SMALL LETTER B +0061 1E947 0315 0300 05AE 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062; # (a◌𞥇◌̕◌̀◌֮b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM HAMZA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E948 0062;00E0 05AE 1E948 0315 0062;0061 05AE 0300 1E948 0315 0062;00E0 05AE 1E948 0315 0062;0061 05AE 0300 1E948 0315 0062; # (a◌̕◌̀◌֮◌𞥈b; à◌֮◌𞥈◌̕b; a◌֮◌̀◌𞥈◌̕b; à◌֮◌𞥈◌̕b; a◌֮◌̀◌𞥈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM CONSONANT MODIFIER, LATIN SMALL LETTER B +0061 1E948 0315 0300 05AE 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062; # (a◌𞥈◌̕◌̀◌֮b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM CONSONANT MODIFIER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E949 0062;00E0 05AE 1E949 0315 0062;0061 05AE 0300 1E949 0315 0062;00E0 05AE 1E949 0315 0062;0061 05AE 0300 1E949 0315 0062; # (a◌̕◌̀◌֮◌𞥉b; à◌֮◌𞥉◌̕b; a◌֮◌̀◌𞥉◌̕b; à◌֮◌𞥉◌̕b; a◌֮◌̀◌𞥉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM GEMINATE CONSONANT MODIFIER, LATIN SMALL LETTER B +0061 1E949 0315 0300 05AE 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062; # (a◌𞥉◌̕◌̀◌֮b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM GEMINATE CONSONANT MODIFIER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 16FF0 1E94A 0062;0061 16FF0 093C 1E94A 3099 0062;0061 16FF0 093C 1E94A 3099 0062;0061 16FF0 093C 1E94A 3099 0062;0061 16FF0 093C 1E94A 3099 0062; # (a◌゙◌𖿰़◌𞥊b; a𖿰◌़◌𞥊◌゙b; a𖿰◌़◌𞥊◌゙b; a𖿰◌़◌𞥊◌゙b; a𖿰◌़◌𞥊◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, ADLAM NUKTA, LATIN SMALL LETTER B +0061 1E94A 3099 093C 16FF0 0062;0061 16FF0 1E94A 093C 3099 0062;0061 16FF0 1E94A 093C 3099 0062;0061 16FF0 1E94A 093C 3099 0062;0061 16FF0 1E94A 093C 3099 0062; # (a◌𞥊◌゙◌𖿰़b; a𖿰◌𞥊◌़◌゙b; a𖿰◌𞥊◌़◌゙b; a𖿰◌𞥊◌़◌゙b; a𖿰◌𞥊◌़◌゙b; ) LATIN SMALL LETTER A, ADLAM NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B +# +@Part3 # PRI #29 Test +# +09C7 0334 09BE;09C7 0334 09BE;09C7 0334 09BE;09C7 0334 09BE;09C7 0334 09BE; # (ে◌̴া; ে◌̴া; ে◌̴া; ে◌̴া; ে◌̴া; ) BENGALI VOWEL SIGN E, COMBINING TILDE OVERLAY, BENGALI VOWEL SIGN AA +09C7 0334 09D7;09C7 0334 09D7;09C7 0334 09D7;09C7 0334 09D7;09C7 0334 09D7; # (ে◌̴ৗ; ে◌̴ৗ; ে◌̴ৗ; ে◌̴ৗ; ে◌̴ৗ; ) BENGALI VOWEL SIGN E, COMBINING TILDE OVERLAY, BENGALI AU LENGTH MARK +0B47 0334 0B3E;0B47 0334 0B3E;0B47 0334 0B3E;0B47 0334 0B3E;0B47 0334 0B3E; # (େ◌̴ା; େ◌̴ା; େ◌̴ା; େ◌̴ା; େ◌̴ା; ) ORIYA VOWEL SIGN E, COMBINING TILDE OVERLAY, ORIYA VOWEL SIGN AA +0B47 0334 0B56;0B47 0334 0B56;0B47 0334 0B56;0B47 0334 0B56;0B47 0334 0B56; # (େ◌̴◌ୖ; େ◌̴◌ୖ; େ◌̴◌ୖ; େ◌̴◌ୖ; େ◌̴◌ୖ; ) ORIYA VOWEL SIGN E, COMBINING TILDE OVERLAY, ORIYA AI LENGTH MARK +0B47 0334 0B57;0B47 0334 0B57;0B47 0334 0B57;0B47 0334 0B57;0B47 0334 0B57; # (େ◌̴ୗ; େ◌̴ୗ; େ◌̴ୗ; େ◌̴ୗ; େ◌̴ୗ; ) ORIYA VOWEL SIGN E, COMBINING TILDE OVERLAY, ORIYA AU LENGTH MARK +0B92 0334 0BD7;0B92 0334 0BD7;0B92 0334 0BD7;0B92 0334 0BD7;0B92 0334 0BD7; # (ஒ◌̴ௗ; ஒ◌̴ௗ; ஒ◌̴ௗ; ஒ◌̴ௗ; ஒ◌̴ௗ; ) TAMIL LETTER O, COMBINING TILDE OVERLAY, TAMIL AU LENGTH MARK +0BC6 0334 0BBE;0BC6 0334 0BBE;0BC6 0334 0BBE;0BC6 0334 0BBE;0BC6 0334 0BBE; # (ெ◌̴ா; ெ◌̴ா; ெ◌̴ா; ெ◌̴ா; ெ◌̴ா; ) TAMIL VOWEL SIGN E, COMBINING TILDE OVERLAY, TAMIL VOWEL SIGN AA +0BC6 0334 0BD7;0BC6 0334 0BD7;0BC6 0334 0BD7;0BC6 0334 0BD7;0BC6 0334 0BD7; # (ெ◌̴ௗ; ெ◌̴ௗ; ெ◌̴ௗ; ெ◌̴ௗ; ெ◌̴ௗ; ) TAMIL VOWEL SIGN E, COMBINING TILDE OVERLAY, TAMIL AU LENGTH MARK +0BC7 0334 0BBE;0BC7 0334 0BBE;0BC7 0334 0BBE;0BC7 0334 0BBE;0BC7 0334 0BBE; # (ே◌̴ா; ே◌̴ா; ே◌̴ா; ே◌̴ா; ே◌̴ா; ) TAMIL VOWEL SIGN EE, COMBINING TILDE OVERLAY, TAMIL VOWEL SIGN AA +0CBF 0334 0CD5;0CBF 0334 0CD5;0CBF 0334 0CD5;0CBF 0334 0CD5;0CBF 0334 0CD5; # (◌ಿ◌̴ೕ; ◌ಿ◌̴ೕ; ◌ಿ◌̴ೕ; ◌ಿ◌̴ೕ; ◌ಿ◌̴ೕ; ) KANNADA VOWEL SIGN I, COMBINING TILDE OVERLAY, KANNADA LENGTH MARK +0CC6 0334 0CC2;0CC6 0334 0CC2;0CC6 0334 0CC2;0CC6 0334 0CC2;0CC6 0334 0CC2; # (◌ೆ◌̴ೂ; ◌ೆ◌̴ೂ; ◌ೆ◌̴ೂ; ◌ೆ◌̴ೂ; ◌ೆ◌̴ೂ; ) KANNADA VOWEL SIGN E, COMBINING TILDE OVERLAY, KANNADA VOWEL SIGN UU +0CC6 0334 0CD5;0CC6 0334 0CD5;0CC6 0334 0CD5;0CC6 0334 0CD5;0CC6 0334 0CD5; # (◌ೆ◌̴ೕ; ◌ೆ◌̴ೕ; ◌ೆ◌̴ೕ; ◌ೆ◌̴ೕ; ◌ೆ◌̴ೕ; ) KANNADA VOWEL SIGN E, COMBINING TILDE OVERLAY, KANNADA LENGTH MARK +0CC6 0334 0CD6;0CC6 0334 0CD6;0CC6 0334 0CD6;0CC6 0334 0CD6;0CC6 0334 0CD6; # (◌ೆ◌̴ೖ; ◌ೆ◌̴ೖ; ◌ೆ◌̴ೖ; ◌ೆ◌̴ೖ; ◌ೆ◌̴ೖ; ) KANNADA VOWEL SIGN E, COMBINING TILDE OVERLAY, KANNADA AI LENGTH MARK +0CCA 0334 0CD5;0CCA 0334 0CD5;0CC6 0CC2 0334 0CD5;0CCA 0334 0CD5;0CC6 0CC2 0334 0CD5; # (ೊ◌̴ೕ; ೊ◌̴ೕ; ◌ೊ◌̴ೕ; ೊ◌̴ೕ; ◌ೊ◌̴ೕ; ) KANNADA VOWEL SIGN O, COMBINING TILDE OVERLAY, KANNADA LENGTH MARK +0D46 0334 0D3E;0D46 0334 0D3E;0D46 0334 0D3E;0D46 0334 0D3E;0D46 0334 0D3E; # (െ◌̴ാ; െ◌̴ാ; െ◌̴ാ; െ◌̴ാ; െ◌̴ാ; ) MALAYALAM VOWEL SIGN E, COMBINING TILDE OVERLAY, MALAYALAM VOWEL SIGN AA +0D46 0334 0D57;0D46 0334 0D57;0D46 0334 0D57;0D46 0334 0D57;0D46 0334 0D57; # (െ◌̴ൗ; െ◌̴ൗ; െ◌̴ൗ; െ◌̴ൗ; െ◌̴ൗ; ) MALAYALAM VOWEL SIGN E, COMBINING TILDE OVERLAY, MALAYALAM AU LENGTH MARK +0D47 0334 0D3E;0D47 0334 0D3E;0D47 0334 0D3E;0D47 0334 0D3E;0D47 0334 0D3E; # (േ◌̴ാ; േ◌̴ാ; േ◌̴ാ; േ◌̴ാ; േ◌̴ാ; ) MALAYALAM VOWEL SIGN EE, COMBINING TILDE OVERLAY, MALAYALAM VOWEL SIGN AA +0DD9 0334 0DCF;0DD9 0334 0DCF;0DD9 0334 0DCF;0DD9 0334 0DCF;0DD9 0334 0DCF; # (ෙ◌̴ා; ෙ◌̴ා; ෙ◌̴ා; ෙ◌̴ා; ෙ◌̴ා; ) SINHALA VOWEL SIGN KOMBUVA, COMBINING TILDE OVERLAY, SINHALA VOWEL SIGN AELA-PILLA +0DD9 0334 0DDF;0DD9 0334 0DDF;0DD9 0334 0DDF;0DD9 0334 0DDF;0DD9 0334 0DDF; # (ෙ◌̴ෟ; ෙ◌̴ෟ; ෙ◌̴ෟ; ෙ◌̴ෟ; ෙ◌̴ෟ; ) SINHALA VOWEL SIGN KOMBUVA, COMBINING TILDE OVERLAY, SINHALA VOWEL SIGN GAYANUKITTA +0F40 0334 0FB5;0F40 0334 0FB5;0F40 0334 0FB5;0F40 0334 0FB5;0F40 0334 0FB5; # (ཀ◌̴◌ྵ; ཀ◌̴◌ྵ; ཀ◌̴◌ྵ; ཀ◌̴◌ྵ; ཀ◌̴◌ྵ; ) TIBETAN LETTER KA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER SSA +0F42 0334 0FB7;0F42 0334 0FB7;0F42 0334 0FB7;0F42 0334 0FB7;0F42 0334 0FB7; # (ག◌̴◌ྷ; ག◌̴◌ྷ; ག◌̴◌ྷ; ག◌̴◌ྷ; ག◌̴◌ྷ; ) TIBETAN LETTER GA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F4C 0334 0FB7;0F4C 0334 0FB7;0F4C 0334 0FB7;0F4C 0334 0FB7;0F4C 0334 0FB7; # (ཌ◌̴◌ྷ; ཌ◌̴◌ྷ; ཌ◌̴◌ྷ; ཌ◌̴◌ྷ; ཌ◌̴◌ྷ; ) TIBETAN LETTER DDA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F51 0334 0FB7;0F51 0334 0FB7;0F51 0334 0FB7;0F51 0334 0FB7;0F51 0334 0FB7; # (ད◌̴◌ྷ; ད◌̴◌ྷ; ད◌̴◌ྷ; ད◌̴◌ྷ; ད◌̴◌ྷ; ) TIBETAN LETTER DA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F56 0334 0FB7;0F56 0334 0FB7;0F56 0334 0FB7;0F56 0334 0FB7;0F56 0334 0FB7; # (བ◌̴◌ྷ; བ◌̴◌ྷ; བ◌̴◌ྷ; བ◌̴◌ྷ; བ◌̴◌ྷ; ) TIBETAN LETTER BA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F5B 0334 0FB7;0F5B 0334 0FB7;0F5B 0334 0FB7;0F5B 0334 0FB7;0F5B 0334 0FB7; # (ཛ◌̴◌ྷ; ཛ◌̴◌ྷ; ཛ◌̴◌ྷ; ཛ◌̴◌ྷ; ཛ◌̴◌ྷ; ) TIBETAN LETTER DZA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F90 0334 0FB5;0F90 0334 0FB5;0F90 0334 0FB5;0F90 0334 0FB5;0F90 0334 0FB5; # (◌ྐ◌̴◌ྵ; ◌ྐ◌̴◌ྵ; ◌ྐ◌̴◌ྵ; ◌ྐ◌̴◌ྵ; ◌ྐ◌̴◌ྵ; ) TIBETAN SUBJOINED LETTER KA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER SSA +0F92 0334 0FB7;0F92 0334 0FB7;0F92 0334 0FB7;0F92 0334 0FB7;0F92 0334 0FB7; # (◌ྒ◌̴◌ྷ; ◌ྒ◌̴◌ྷ; ◌ྒ◌̴◌ྷ; ◌ྒ◌̴◌ྷ; ◌ྒ◌̴◌ྷ; ) TIBETAN SUBJOINED LETTER GA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0F9C 0334 0FB7;0F9C 0334 0FB7;0F9C 0334 0FB7;0F9C 0334 0FB7;0F9C 0334 0FB7; # (◌ྜ◌̴◌ྷ; ◌ྜ◌̴◌ྷ; ◌ྜ◌̴◌ྷ; ◌ྜ◌̴◌ྷ; ◌ྜ◌̴◌ྷ; ) TIBETAN SUBJOINED LETTER DDA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0FA1 0334 0FB7;0FA1 0334 0FB7;0FA1 0334 0FB7;0FA1 0334 0FB7;0FA1 0334 0FB7; # (◌ྡ◌̴◌ྷ; ◌ྡ◌̴◌ྷ; ◌ྡ◌̴◌ྷ; ◌ྡ◌̴◌ྷ; ◌ྡ◌̴◌ྷ; ) TIBETAN SUBJOINED LETTER DA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0FA6 0334 0FB7;0FA6 0334 0FB7;0FA6 0334 0FB7;0FA6 0334 0FB7;0FA6 0334 0FB7; # (◌ྦ◌̴◌ྷ; ◌ྦ◌̴◌ྷ; ◌ྦ◌̴◌ྷ; ◌ྦ◌̴◌ྷ; ◌ྦ◌̴◌ྷ; ) TIBETAN SUBJOINED LETTER BA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +0FAB 0334 0FB7;0FAB 0334 0FB7;0FAB 0334 0FB7;0FAB 0334 0FB7;0FAB 0334 0FB7; # (◌ྫ◌̴◌ྷ; ◌ྫ◌̴◌ྷ; ◌ྫ◌̴◌ྷ; ◌ྫ◌̴◌ྷ; ◌ྫ◌̴◌ྷ; ) TIBETAN SUBJOINED LETTER DZA, COMBINING TILDE OVERLAY, TIBETAN SUBJOINED LETTER HA +1025 0334 102E;1025 0334 102E;1025 0334 102E;1025 0334 102E;1025 0334 102E; # (ဥ◌̴◌ီ; ဥ◌̴◌ီ; ဥ◌̴◌ီ; ဥ◌̴◌ီ; ဥ◌̴◌ီ; ) MYANMAR LETTER U, COMBINING TILDE OVERLAY, MYANMAR VOWEL SIGN II +1100 0334 1161;1100 0334 1161;1100 0334 1161;1100 0334 1161;1100 0334 1161; # (ᄀ◌̴ᅡ; ᄀ◌̴ᅡ; ᄀ◌̴ᅡ; ᄀ◌̴ᅡ; ᄀ◌̴ᅡ; ) HANGUL CHOSEONG KIYEOK, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG A +1100 0334 116E;1100 0334 116E;1100 0334 116E;1100 0334 116E;1100 0334 116E; # (ᄀ◌̴ᅮ; ᄀ◌̴ᅮ; ᄀ◌̴ᅮ; ᄀ◌̴ᅮ; ᄀ◌̴ᅮ; ) HANGUL CHOSEONG KIYEOK, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG U +1101 0334 1166;1101 0334 1166;1101 0334 1166;1101 0334 1166;1101 0334 1166; # (ᄁ◌̴ᅦ; ᄁ◌̴ᅦ; ᄁ◌̴ᅦ; ᄁ◌̴ᅦ; ᄁ◌̴ᅦ; ) HANGUL CHOSEONG SSANGKIYEOK, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG E +1101 0334 1173;1101 0334 1173;1101 0334 1173;1101 0334 1173;1101 0334 1173; # (ᄁ◌̴ᅳ; ᄁ◌̴ᅳ; ᄁ◌̴ᅳ; ᄁ◌̴ᅳ; ᄁ◌̴ᅳ; ) HANGUL CHOSEONG SSANGKIYEOK, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG EU +1102 0334 116B;1102 0334 116B;1102 0334 116B;1102 0334 116B;1102 0334 116B; # (ᄂ◌̴ᅫ; ᄂ◌̴ᅫ; ᄂ◌̴ᅫ; ᄂ◌̴ᅫ; ᄂ◌̴ᅫ; ) HANGUL CHOSEONG NIEUN, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WAE +1103 0334 1163;1103 0334 1163;1103 0334 1163;1103 0334 1163;1103 0334 1163; # (ᄃ◌̴ᅣ; ᄃ◌̴ᅣ; ᄃ◌̴ᅣ; ᄃ◌̴ᅣ; ᄃ◌̴ᅣ; ) HANGUL CHOSEONG TIKEUT, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YA +1103 0334 1170;1103 0334 1170;1103 0334 1170;1103 0334 1170;1103 0334 1170; # (ᄃ◌̴ᅰ; ᄃ◌̴ᅰ; ᄃ◌̴ᅰ; ᄃ◌̴ᅰ; ᄃ◌̴ᅰ; ) HANGUL CHOSEONG TIKEUT, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WE +1104 0334 1168;1104 0334 1168;1104 0334 1168;1104 0334 1168;1104 0334 1168; # (ᄄ◌̴ᅨ; ᄄ◌̴ᅨ; ᄄ◌̴ᅨ; ᄄ◌̴ᅨ; ᄄ◌̴ᅨ; ) HANGUL CHOSEONG SSANGTIKEUT, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YE +1104 0334 1175;1104 0334 1175;1104 0334 1175;1104 0334 1175;1104 0334 1175; # (ᄄ◌̴ᅵ; ᄄ◌̴ᅵ; ᄄ◌̴ᅵ; ᄄ◌̴ᅵ; ᄄ◌̴ᅵ; ) HANGUL CHOSEONG SSANGTIKEUT, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG I +1105 0334 116D;1105 0334 116D;1105 0334 116D;1105 0334 116D;1105 0334 116D; # (ᄅ◌̴ᅭ; ᄅ◌̴ᅭ; ᄅ◌̴ᅭ; ᄅ◌̴ᅭ; ᄅ◌̴ᅭ; ) HANGUL CHOSEONG RIEUL, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YO +1106 0334 1165;1106 0334 1165;1106 0334 1165;1106 0334 1165;1106 0334 1165; # (ᄆ◌̴ᅥ; ᄆ◌̴ᅥ; ᄆ◌̴ᅥ; ᄆ◌̴ᅥ; ᄆ◌̴ᅥ; ) HANGUL CHOSEONG MIEUM, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG EO +1106 0334 1172;1106 0334 1172;1106 0334 1172;1106 0334 1172;1106 0334 1172; # (ᄆ◌̴ᅲ; ᄆ◌̴ᅲ; ᄆ◌̴ᅲ; ᄆ◌̴ᅲ; ᄆ◌̴ᅲ; ) HANGUL CHOSEONG MIEUM, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YU +1107 0334 116A;1107 0334 116A;1107 0334 116A;1107 0334 116A;1107 0334 116A; # (ᄇ◌̴ᅪ; ᄇ◌̴ᅪ; ᄇ◌̴ᅪ; ᄇ◌̴ᅪ; ᄇ◌̴ᅪ; ) HANGUL CHOSEONG PIEUP, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WA +1108 0334 1162;1108 0334 1162;1108 0334 1162;1108 0334 1162;1108 0334 1162; # (ᄈ◌̴ᅢ; ᄈ◌̴ᅢ; ᄈ◌̴ᅢ; ᄈ◌̴ᅢ; ᄈ◌̴ᅢ; ) HANGUL CHOSEONG SSANGPIEUP, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG AE +1108 0334 116F;1108 0334 116F;1108 0334 116F;1108 0334 116F;1108 0334 116F; # (ᄈ◌̴ᅯ; ᄈ◌̴ᅯ; ᄈ◌̴ᅯ; ᄈ◌̴ᅯ; ᄈ◌̴ᅯ; ) HANGUL CHOSEONG SSANGPIEUP, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WEO +1109 0334 1167;1109 0334 1167;1109 0334 1167;1109 0334 1167;1109 0334 1167; # (ᄉ◌̴ᅧ; ᄉ◌̴ᅧ; ᄉ◌̴ᅧ; ᄉ◌̴ᅧ; ᄉ◌̴ᅧ; ) HANGUL CHOSEONG SIOS, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YEO +1109 0334 1174;1109 0334 1174;1109 0334 1174;1109 0334 1174;1109 0334 1174; # (ᄉ◌̴ᅴ; ᄉ◌̴ᅴ; ᄉ◌̴ᅴ; ᄉ◌̴ᅴ; ᄉ◌̴ᅴ; ) HANGUL CHOSEONG SIOS, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YI +110A 0334 116C;110A 0334 116C;110A 0334 116C;110A 0334 116C;110A 0334 116C; # (ᄊ◌̴ᅬ; ᄊ◌̴ᅬ; ᄊ◌̴ᅬ; ᄊ◌̴ᅬ; ᄊ◌̴ᅬ; ) HANGUL CHOSEONG SSANGSIOS, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG OE +110B 0334 1164;110B 0334 1164;110B 0334 1164;110B 0334 1164;110B 0334 1164; # (ᄋ◌̴ᅤ; ᄋ◌̴ᅤ; ᄋ◌̴ᅤ; ᄋ◌̴ᅤ; ᄋ◌̴ᅤ; ) HANGUL CHOSEONG IEUNG, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YAE +110B 0334 1171;110B 0334 1171;110B 0334 1171;110B 0334 1171;110B 0334 1171; # (ᄋ◌̴ᅱ; ᄋ◌̴ᅱ; ᄋ◌̴ᅱ; ᄋ◌̴ᅱ; ᄋ◌̴ᅱ; ) HANGUL CHOSEONG IEUNG, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WI +110C 0334 1169;110C 0334 1169;110C 0334 1169;110C 0334 1169;110C 0334 1169; # (ᄌ◌̴ᅩ; ᄌ◌̴ᅩ; ᄌ◌̴ᅩ; ᄌ◌̴ᅩ; ᄌ◌̴ᅩ; ) HANGUL CHOSEONG CIEUC, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG O +110D 0334 1161;110D 0334 1161;110D 0334 1161;110D 0334 1161;110D 0334 1161; # (ᄍ◌̴ᅡ; ᄍ◌̴ᅡ; ᄍ◌̴ᅡ; ᄍ◌̴ᅡ; ᄍ◌̴ᅡ; ) HANGUL CHOSEONG SSANGCIEUC, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG A +110D 0334 116E;110D 0334 116E;110D 0334 116E;110D 0334 116E;110D 0334 116E; # (ᄍ◌̴ᅮ; ᄍ◌̴ᅮ; ᄍ◌̴ᅮ; ᄍ◌̴ᅮ; ᄍ◌̴ᅮ; ) HANGUL CHOSEONG SSANGCIEUC, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG U +110E 0334 1166;110E 0334 1166;110E 0334 1166;110E 0334 1166;110E 0334 1166; # (ᄎ◌̴ᅦ; ᄎ◌̴ᅦ; ᄎ◌̴ᅦ; ᄎ◌̴ᅦ; ᄎ◌̴ᅦ; ) HANGUL CHOSEONG CHIEUCH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG E +110E 0334 1173;110E 0334 1173;110E 0334 1173;110E 0334 1173;110E 0334 1173; # (ᄎ◌̴ᅳ; ᄎ◌̴ᅳ; ᄎ◌̴ᅳ; ᄎ◌̴ᅳ; ᄎ◌̴ᅳ; ) HANGUL CHOSEONG CHIEUCH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG EU +110F 0334 116B;110F 0334 116B;110F 0334 116B;110F 0334 116B;110F 0334 116B; # (ᄏ◌̴ᅫ; ᄏ◌̴ᅫ; ᄏ◌̴ᅫ; ᄏ◌̴ᅫ; ᄏ◌̴ᅫ; ) HANGUL CHOSEONG KHIEUKH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WAE +1110 0334 1163;1110 0334 1163;1110 0334 1163;1110 0334 1163;1110 0334 1163; # (ᄐ◌̴ᅣ; ᄐ◌̴ᅣ; ᄐ◌̴ᅣ; ᄐ◌̴ᅣ; ᄐ◌̴ᅣ; ) HANGUL CHOSEONG THIEUTH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YA +1110 0334 1170;1110 0334 1170;1110 0334 1170;1110 0334 1170;1110 0334 1170; # (ᄐ◌̴ᅰ; ᄐ◌̴ᅰ; ᄐ◌̴ᅰ; ᄐ◌̴ᅰ; ᄐ◌̴ᅰ; ) HANGUL CHOSEONG THIEUTH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG WE +1111 0334 1168;1111 0334 1168;1111 0334 1168;1111 0334 1168;1111 0334 1168; # (ᄑ◌̴ᅨ; ᄑ◌̴ᅨ; ᄑ◌̴ᅨ; ᄑ◌̴ᅨ; ᄑ◌̴ᅨ; ) HANGUL CHOSEONG PHIEUPH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YE +1111 0334 1175;1111 0334 1175;1111 0334 1175;1111 0334 1175;1111 0334 1175; # (ᄑ◌̴ᅵ; ᄑ◌̴ᅵ; ᄑ◌̴ᅵ; ᄑ◌̴ᅵ; ᄑ◌̴ᅵ; ) HANGUL CHOSEONG PHIEUPH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG I +1112 0334 116D;1112 0334 116D;1112 0334 116D;1112 0334 116D;1112 0334 116D; # (ᄒ◌̴ᅭ; ᄒ◌̴ᅭ; ᄒ◌̴ᅭ; ᄒ◌̴ᅭ; ᄒ◌̴ᅭ; ) HANGUL CHOSEONG HIEUH, COMBINING TILDE OVERLAY, HANGUL JUNGSEONG YO +1B05 0334 1B35;1B05 0334 1B35;1B05 0334 1B35;1B05 0334 1B35;1B05 0334 1B35; # (ᬅ◌̴ᬵ; ᬅ◌̴ᬵ; ᬅ◌̴ᬵ; ᬅ◌̴ᬵ; ᬅ◌̴ᬵ; ) BALINESE LETTER AKARA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B07 0334 1B35;1B07 0334 1B35;1B07 0334 1B35;1B07 0334 1B35;1B07 0334 1B35; # (ᬇ◌̴ᬵ; ᬇ◌̴ᬵ; ᬇ◌̴ᬵ; ᬇ◌̴ᬵ; ᬇ◌̴ᬵ; ) BALINESE LETTER IKARA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B09 0334 1B35;1B09 0334 1B35;1B09 0334 1B35;1B09 0334 1B35;1B09 0334 1B35; # (ᬉ◌̴ᬵ; ᬉ◌̴ᬵ; ᬉ◌̴ᬵ; ᬉ◌̴ᬵ; ᬉ◌̴ᬵ; ) BALINESE LETTER UKARA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B0B 0334 1B35;1B0B 0334 1B35;1B0B 0334 1B35;1B0B 0334 1B35;1B0B 0334 1B35; # (ᬋ◌̴ᬵ; ᬋ◌̴ᬵ; ᬋ◌̴ᬵ; ᬋ◌̴ᬵ; ᬋ◌̴ᬵ; ) BALINESE LETTER RA REPA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B0D 0334 1B35;1B0D 0334 1B35;1B0D 0334 1B35;1B0D 0334 1B35;1B0D 0334 1B35; # (ᬍ◌̴ᬵ; ᬍ◌̴ᬵ; ᬍ◌̴ᬵ; ᬍ◌̴ᬵ; ᬍ◌̴ᬵ; ) BALINESE LETTER LA LENGA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B11 0334 1B35;1B11 0334 1B35;1B11 0334 1B35;1B11 0334 1B35;1B11 0334 1B35; # (ᬑ◌̴ᬵ; ᬑ◌̴ᬵ; ᬑ◌̴ᬵ; ᬑ◌̴ᬵ; ᬑ◌̴ᬵ; ) BALINESE LETTER OKARA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B3A 0334 1B35;1B3A 0334 1B35;1B3A 0334 1B35;1B3A 0334 1B35;1B3A 0334 1B35; # (◌ᬺ◌̴ᬵ; ◌ᬺ◌̴ᬵ; ◌ᬺ◌̴ᬵ; ◌ᬺ◌̴ᬵ; ◌ᬺ◌̴ᬵ; ) BALINESE VOWEL SIGN RA REPA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B3C 0334 1B35;1B3C 0334 1B35;1B3C 0334 1B35;1B3C 0334 1B35;1B3C 0334 1B35; # (◌ᬼ◌̴ᬵ; ◌ᬼ◌̴ᬵ; ◌ᬼ◌̴ᬵ; ◌ᬼ◌̴ᬵ; ◌ᬼ◌̴ᬵ; ) BALINESE VOWEL SIGN LA LENGA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B3E 0334 1B35;1B3E 0334 1B35;1B3E 0334 1B35;1B3E 0334 1B35;1B3E 0334 1B35; # (ᬾ◌̴ᬵ; ᬾ◌̴ᬵ; ᬾ◌̴ᬵ; ᬾ◌̴ᬵ; ᬾ◌̴ᬵ; ) BALINESE VOWEL SIGN TALING, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B3F 0334 1B35;1B3F 0334 1B35;1B3F 0334 1B35;1B3F 0334 1B35;1B3F 0334 1B35; # (ᬿ◌̴ᬵ; ᬿ◌̴ᬵ; ᬿ◌̴ᬵ; ᬿ◌̴ᬵ; ᬿ◌̴ᬵ; ) BALINESE VOWEL SIGN TALING REPA, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +1B42 0334 1B35;1B42 0334 1B35;1B42 0334 1B35;1B42 0334 1B35;1B42 0334 1B35; # (◌ᭂ◌̴ᬵ; ◌ᭂ◌̴ᬵ; ◌ᭂ◌̴ᬵ; ◌ᭂ◌̴ᬵ; ◌ᭂ◌̴ᬵ; ) BALINESE VOWEL SIGN PEPET, COMBINING TILDE OVERLAY, BALINESE VOWEL SIGN TEDUNG +AC54 0334 11AE;AC54 0334 11AE;1100 1164 0334 11AE;AC54 0334 11AE;1100 1164 0334 11AE; # (걔◌̴ᆮ; 걔◌̴ᆮ; 걔◌̴ᆮ; 걔◌̴ᆮ; 걔◌̴ᆮ; ) HANGUL SYLLABLE GYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +ACA8 0334 11B5;ACA8 0334 11B5;1100 1167 0334 11B5;ACA8 0334 11B5;1100 1167 0334 11B5; # (겨◌̴ᆵ; 겨◌̴ᆵ; 겨◌̴ᆵ; 겨◌̴ᆵ; 겨◌̴ᆵ; ) HANGUL SYLLABLE GYEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +ACFC 0334 11BC;ACFC 0334 11BC;1100 116A 0334 11BC;ACFC 0334 11BC;1100 116A 0334 11BC; # (과◌̴ᆼ; 과◌̴ᆼ; 과◌̴ᆼ; 과◌̴ᆼ; 과◌̴ᆼ; ) HANGUL SYLLABLE GWA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +ADC0 0334 11AE;ADC0 0334 11AE;1100 1171 0334 11AE;ADC0 0334 11AE;1100 1171 0334 11AE; # (귀◌̴ᆮ; 귀◌̴ᆮ; 귀◌̴ᆮ; 귀◌̴ᆮ; 귀◌̴ᆮ; ) HANGUL SYLLABLE GWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +AE14 0334 11B5;AE14 0334 11B5;1100 1174 0334 11B5;AE14 0334 11B5;1100 1174 0334 11B5; # (긔◌̴ᆵ; 긔◌̴ᆵ; 긔◌̴ᆵ; 긔◌̴ᆵ; 긔◌̴ᆵ; ) HANGUL SYLLABLE GYI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +AE68 0334 11BC;AE68 0334 11BC;1101 1162 0334 11BC;AE68 0334 11BC;1101 1162 0334 11BC; # (깨◌̴ᆼ; 깨◌̴ᆼ; 깨◌̴ᆼ; 깨◌̴ᆼ; 깨◌̴ᆼ; ) HANGUL SYLLABLE GGAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +AF2C 0334 11AE;AF2C 0334 11AE;1101 1169 0334 11AE;AF2C 0334 11AE;1101 1169 0334 11AE; # (꼬◌̴ᆮ; 꼬◌̴ᆮ; 꼬◌̴ᆮ; 꼬◌̴ᆮ; 꼬◌̴ᆮ; ) HANGUL SYLLABLE GGO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +AF80 0334 11B5;AF80 0334 11B5;1101 116C 0334 11B5;AF80 0334 11B5;1101 116C 0334 11B5; # (꾀◌̴ᆵ; 꾀◌̴ᆵ; 꾀◌̴ᆵ; 꾀◌̴ᆵ; 꾀◌̴ᆵ; ) HANGUL SYLLABLE GGOE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +AFD4 0334 11BC;AFD4 0334 11BC;1101 116F 0334 11BC;AFD4 0334 11BC;1101 116F 0334 11BC; # (꿔◌̴ᆼ; 꿔◌̴ᆼ; 꿔◌̴ᆼ; 꿔◌̴ᆼ; 꿔◌̴ᆼ; ) HANGUL SYLLABLE GGWEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B098 0334 11AE;B098 0334 11AE;1102 1161 0334 11AE;B098 0334 11AE;1102 1161 0334 11AE; # (나◌̴ᆮ; 나◌̴ᆮ; 나◌̴ᆮ; 나◌̴ᆮ; 나◌̴ᆮ; ) HANGUL SYLLABLE NA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B0EC 0334 11B5;B0EC 0334 11B5;1102 1164 0334 11B5;B0EC 0334 11B5;1102 1164 0334 11B5; # (냬◌̴ᆵ; 냬◌̴ᆵ; 냬◌̴ᆵ; 냬◌̴ᆵ; 냬◌̴ᆵ; ) HANGUL SYLLABLE NYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B140 0334 11BC;B140 0334 11BC;1102 1167 0334 11BC;B140 0334 11BC;1102 1167 0334 11BC; # (녀◌̴ᆼ; 녀◌̴ᆼ; 녀◌̴ᆼ; 녀◌̴ᆼ; 녀◌̴ᆼ; ) HANGUL SYLLABLE NYEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B204 0334 11AE;B204 0334 11AE;1102 116E 0334 11AE;B204 0334 11AE;1102 116E 0334 11AE; # (누◌̴ᆮ; 누◌̴ᆮ; 누◌̴ᆮ; 누◌̴ᆮ; 누◌̴ᆮ; ) HANGUL SYLLABLE NU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B258 0334 11B5;B258 0334 11B5;1102 1171 0334 11B5;B258 0334 11B5;1102 1171 0334 11B5; # (뉘◌̴ᆵ; 뉘◌̴ᆵ; 뉘◌̴ᆵ; 뉘◌̴ᆵ; 뉘◌̴ᆵ; ) HANGUL SYLLABLE NWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B2AC 0334 11BC;B2AC 0334 11BC;1102 1174 0334 11BC;B2AC 0334 11BC;1102 1174 0334 11BC; # (늬◌̴ᆼ; 늬◌̴ᆼ; 늬◌̴ᆼ; 늬◌̴ᆼ; 늬◌̴ᆼ; ) HANGUL SYLLABLE NYI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B370 0334 11AE;B370 0334 11AE;1103 1166 0334 11AE;B370 0334 11AE;1103 1166 0334 11AE; # (데◌̴ᆮ; 데◌̴ᆮ; 데◌̴ᆮ; 데◌̴ᆮ; 데◌̴ᆮ; ) HANGUL SYLLABLE DE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B3C4 0334 11B5;B3C4 0334 11B5;1103 1169 0334 11B5;B3C4 0334 11B5;1103 1169 0334 11B5; # (도◌̴ᆵ; 도◌̴ᆵ; 도◌̴ᆵ; 도◌̴ᆵ; 도◌̴ᆵ; ) HANGUL SYLLABLE DO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B418 0334 11BC;B418 0334 11BC;1103 116C 0334 11BC;B418 0334 11BC;1103 116C 0334 11BC; # (되◌̴ᆼ; 되◌̴ᆼ; 되◌̴ᆼ; 되◌̴ᆼ; 되◌̴ᆼ; ) HANGUL SYLLABLE DOE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B4DC 0334 11AE;B4DC 0334 11AE;1103 1173 0334 11AE;B4DC 0334 11AE;1103 1173 0334 11AE; # (드◌̴ᆮ; 드◌̴ᆮ; 드◌̴ᆮ; 드◌̴ᆮ; 드◌̴ᆮ; ) HANGUL SYLLABLE DEU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B530 0334 11B5;B530 0334 11B5;1104 1161 0334 11B5;B530 0334 11B5;1104 1161 0334 11B5; # (따◌̴ᆵ; 따◌̴ᆵ; 따◌̴ᆵ; 따◌̴ᆵ; 따◌̴ᆵ; ) HANGUL SYLLABLE DDA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B584 0334 11BC;B584 0334 11BC;1104 1164 0334 11BC;B584 0334 11BC;1104 1164 0334 11BC; # (떄◌̴ᆼ; 떄◌̴ᆼ; 떄◌̴ᆼ; 떄◌̴ᆼ; 떄◌̴ᆼ; ) HANGUL SYLLABLE DDYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B648 0334 11AE;B648 0334 11AE;1104 116B 0334 11AE;B648 0334 11AE;1104 116B 0334 11AE; # (뙈◌̴ᆮ; 뙈◌̴ᆮ; 뙈◌̴ᆮ; 뙈◌̴ᆮ; 뙈◌̴ᆮ; ) HANGUL SYLLABLE DDWAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B69C 0334 11B5;B69C 0334 11B5;1104 116E 0334 11B5;B69C 0334 11B5;1104 116E 0334 11B5; # (뚜◌̴ᆵ; 뚜◌̴ᆵ; 뚜◌̴ᆵ; 뚜◌̴ᆵ; 뚜◌̴ᆵ; ) HANGUL SYLLABLE DDU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B6F0 0334 11BC;B6F0 0334 11BC;1104 1171 0334 11BC;B6F0 0334 11BC;1104 1171 0334 11BC; # (뛰◌̴ᆼ; 뛰◌̴ᆼ; 뛰◌̴ᆼ; 뛰◌̴ᆼ; 뛰◌̴ᆼ; ) HANGUL SYLLABLE DDWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B7B4 0334 11AE;B7B4 0334 11AE;1105 1163 0334 11AE;B7B4 0334 11AE;1105 1163 0334 11AE; # (랴◌̴ᆮ; 랴◌̴ᆮ; 랴◌̴ᆮ; 랴◌̴ᆮ; 랴◌̴ᆮ; ) HANGUL SYLLABLE RYA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B808 0334 11B5;B808 0334 11B5;1105 1166 0334 11B5;B808 0334 11B5;1105 1166 0334 11B5; # (레◌̴ᆵ; 레◌̴ᆵ; 레◌̴ᆵ; 레◌̴ᆵ; 레◌̴ᆵ; ) HANGUL SYLLABLE RE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B85C 0334 11BC;B85C 0334 11BC;1105 1169 0334 11BC;B85C 0334 11BC;1105 1169 0334 11BC; # (로◌̴ᆼ; 로◌̴ᆼ; 로◌̴ᆼ; 로◌̴ᆼ; 로◌̴ᆼ; ) HANGUL SYLLABLE RO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +B920 0334 11AE;B920 0334 11AE;1105 1170 0334 11AE;B920 0334 11AE;1105 1170 0334 11AE; # (뤠◌̴ᆮ; 뤠◌̴ᆮ; 뤠◌̴ᆮ; 뤠◌̴ᆮ; 뤠◌̴ᆮ; ) HANGUL SYLLABLE RWE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +B974 0334 11B5;B974 0334 11B5;1105 1173 0334 11B5;B974 0334 11B5;1105 1173 0334 11B5; # (르◌̴ᆵ; 르◌̴ᆵ; 르◌̴ᆵ; 르◌̴ᆵ; 르◌̴ᆵ; ) HANGUL SYLLABLE REU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +B9C8 0334 11BC;B9C8 0334 11BC;1106 1161 0334 11BC;B9C8 0334 11BC;1106 1161 0334 11BC; # (마◌̴ᆼ; 마◌̴ᆼ; 마◌̴ᆼ; 마◌̴ᆼ; 마◌̴ᆼ; ) HANGUL SYLLABLE MA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +BA8C 0334 11AE;BA8C 0334 11AE;1106 1168 0334 11AE;BA8C 0334 11AE;1106 1168 0334 11AE; # (몌◌̴ᆮ; 몌◌̴ᆮ; 몌◌̴ᆮ; 몌◌̴ᆮ; 몌◌̴ᆮ; ) HANGUL SYLLABLE MYE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +BAE0 0334 11B5;BAE0 0334 11B5;1106 116B 0334 11B5;BAE0 0334 11B5;1106 116B 0334 11B5; # (뫠◌̴ᆵ; 뫠◌̴ᆵ; 뫠◌̴ᆵ; 뫠◌̴ᆵ; 뫠◌̴ᆵ; ) HANGUL SYLLABLE MWAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +BB34 0334 11BC;BB34 0334 11BC;1106 116E 0334 11BC;BB34 0334 11BC;1106 116E 0334 11BC; # (무◌̴ᆼ; 무◌̴ᆼ; 무◌̴ᆼ; 무◌̴ᆼ; 무◌̴ᆼ; ) HANGUL SYLLABLE MU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +BBF8 0334 11AE;BBF8 0334 11AE;1106 1175 0334 11AE;BBF8 0334 11AE;1106 1175 0334 11AE; # (미◌̴ᆮ; 미◌̴ᆮ; 미◌̴ᆮ; 미◌̴ᆮ; 미◌̴ᆮ; ) HANGUL SYLLABLE MI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +BC4C 0334 11B5;BC4C 0334 11B5;1107 1163 0334 11B5;BC4C 0334 11B5;1107 1163 0334 11B5; # (뱌◌̴ᆵ; 뱌◌̴ᆵ; 뱌◌̴ᆵ; 뱌◌̴ᆵ; 뱌◌̴ᆵ; ) HANGUL SYLLABLE BYA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +BCA0 0334 11BC;BCA0 0334 11BC;1107 1166 0334 11BC;BCA0 0334 11BC;1107 1166 0334 11BC; # (베◌̴ᆼ; 베◌̴ᆼ; 베◌̴ᆼ; 베◌̴ᆼ; 베◌̴ᆼ; ) HANGUL SYLLABLE BE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +BD64 0334 11AE;BD64 0334 11AE;1107 116D 0334 11AE;BD64 0334 11AE;1107 116D 0334 11AE; # (뵤◌̴ᆮ; 뵤◌̴ᆮ; 뵤◌̴ᆮ; 뵤◌̴ᆮ; 뵤◌̴ᆮ; ) HANGUL SYLLABLE BYO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +BDB8 0334 11B5;BDB8 0334 11B5;1107 1170 0334 11B5;BDB8 0334 11B5;1107 1170 0334 11B5; # (붸◌̴ᆵ; 붸◌̴ᆵ; 붸◌̴ᆵ; 붸◌̴ᆵ; 붸◌̴ᆵ; ) HANGUL SYLLABLE BWE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +BE0C 0334 11BC;BE0C 0334 11BC;1107 1173 0334 11BC;BE0C 0334 11BC;1107 1173 0334 11BC; # (브◌̴ᆼ; 브◌̴ᆼ; 브◌̴ᆼ; 브◌̴ᆼ; 브◌̴ᆼ; ) HANGUL SYLLABLE BEU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +BED0 0334 11AE;BED0 0334 11AE;1108 1165 0334 11AE;BED0 0334 11AE;1108 1165 0334 11AE; # (뻐◌̴ᆮ; 뻐◌̴ᆮ; 뻐◌̴ᆮ; 뻐◌̴ᆮ; 뻐◌̴ᆮ; ) HANGUL SYLLABLE BBEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +BF24 0334 11B5;BF24 0334 11B5;1108 1168 0334 11B5;BF24 0334 11B5;1108 1168 0334 11B5; # (뼤◌̴ᆵ; 뼤◌̴ᆵ; 뼤◌̴ᆵ; 뼤◌̴ᆵ; 뼤◌̴ᆵ; ) HANGUL SYLLABLE BBYE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +BF78 0334 11BC;BF78 0334 11BC;1108 116B 0334 11BC;BF78 0334 11BC;1108 116B 0334 11BC; # (뽸◌̴ᆼ; 뽸◌̴ᆼ; 뽸◌̴ᆼ; 뽸◌̴ᆼ; 뽸◌̴ᆼ; ) HANGUL SYLLABLE BBWAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C03C 0334 11AE;C03C 0334 11AE;1108 1172 0334 11AE;C03C 0334 11AE;1108 1172 0334 11AE; # (쀼◌̴ᆮ; 쀼◌̴ᆮ; 쀼◌̴ᆮ; 쀼◌̴ᆮ; 쀼◌̴ᆮ; ) HANGUL SYLLABLE BBYU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C090 0334 11B5;C090 0334 11B5;1108 1175 0334 11B5;C090 0334 11B5;1108 1175 0334 11B5; # (삐◌̴ᆵ; 삐◌̴ᆵ; 삐◌̴ᆵ; 삐◌̴ᆵ; 삐◌̴ᆵ; ) HANGUL SYLLABLE BBI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C0E4 0334 11BC;C0E4 0334 11BC;1109 1163 0334 11BC;C0E4 0334 11BC;1109 1163 0334 11BC; # (샤◌̴ᆼ; 샤◌̴ᆼ; 샤◌̴ᆼ; 샤◌̴ᆼ; 샤◌̴ᆼ; ) HANGUL SYLLABLE SYA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C1A8 0334 11AE;C1A8 0334 11AE;1109 116A 0334 11AE;C1A8 0334 11AE;1109 116A 0334 11AE; # (솨◌̴ᆮ; 솨◌̴ᆮ; 솨◌̴ᆮ; 솨◌̴ᆮ; 솨◌̴ᆮ; ) HANGUL SYLLABLE SWA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C1FC 0334 11B5;C1FC 0334 11B5;1109 116D 0334 11B5;C1FC 0334 11B5;1109 116D 0334 11B5; # (쇼◌̴ᆵ; 쇼◌̴ᆵ; 쇼◌̴ᆵ; 쇼◌̴ᆵ; 쇼◌̴ᆵ; ) HANGUL SYLLABLE SYO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C250 0334 11BC;C250 0334 11BC;1109 1170 0334 11BC;C250 0334 11BC;1109 1170 0334 11BC; # (쉐◌̴ᆼ; 쉐◌̴ᆼ; 쉐◌̴ᆼ; 쉐◌̴ᆼ; 쉐◌̴ᆼ; ) HANGUL SYLLABLE SWE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C314 0334 11AE;C314 0334 11AE;110A 1162 0334 11AE;C314 0334 11AE;110A 1162 0334 11AE; # (쌔◌̴ᆮ; 쌔◌̴ᆮ; 쌔◌̴ᆮ; 쌔◌̴ᆮ; 쌔◌̴ᆮ; ) HANGUL SYLLABLE SSAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C368 0334 11B5;C368 0334 11B5;110A 1165 0334 11B5;C368 0334 11B5;110A 1165 0334 11B5; # (써◌̴ᆵ; 써◌̴ᆵ; 써◌̴ᆵ; 써◌̴ᆵ; 써◌̴ᆵ; ) HANGUL SYLLABLE SSEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C3BC 0334 11BC;C3BC 0334 11BC;110A 1168 0334 11BC;C3BC 0334 11BC;110A 1168 0334 11BC; # (쎼◌̴ᆼ; 쎼◌̴ᆼ; 쎼◌̴ᆼ; 쎼◌̴ᆼ; 쎼◌̴ᆼ; ) HANGUL SYLLABLE SSYE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C480 0334 11AE;C480 0334 11AE;110A 116F 0334 11AE;C480 0334 11AE;110A 116F 0334 11AE; # (쒀◌̴ᆮ; 쒀◌̴ᆮ; 쒀◌̴ᆮ; 쒀◌̴ᆮ; 쒀◌̴ᆮ; ) HANGUL SYLLABLE SSWEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C4D4 0334 11B5;C4D4 0334 11B5;110A 1172 0334 11B5;C4D4 0334 11B5;110A 1172 0334 11B5; # (쓔◌̴ᆵ; 쓔◌̴ᆵ; 쓔◌̴ᆵ; 쓔◌̴ᆵ; 쓔◌̴ᆵ; ) HANGUL SYLLABLE SSYU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C528 0334 11BC;C528 0334 11BC;110A 1175 0334 11BC;C528 0334 11BC;110A 1175 0334 11BC; # (씨◌̴ᆼ; 씨◌̴ᆼ; 씨◌̴ᆼ; 씨◌̴ᆼ; 씨◌̴ᆼ; ) HANGUL SYLLABLE SSI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C5EC 0334 11AE;C5EC 0334 11AE;110B 1167 0334 11AE;C5EC 0334 11AE;110B 1167 0334 11AE; # (여◌̴ᆮ; 여◌̴ᆮ; 여◌̴ᆮ; 여◌̴ᆮ; 여◌̴ᆮ; ) HANGUL SYLLABLE YEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C640 0334 11B5;C640 0334 11B5;110B 116A 0334 11B5;C640 0334 11B5;110B 116A 0334 11B5; # (와◌̴ᆵ; 와◌̴ᆵ; 와◌̴ᆵ; 와◌̴ᆵ; 와◌̴ᆵ; ) HANGUL SYLLABLE WA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C694 0334 11BC;C694 0334 11BC;110B 116D 0334 11BC;C694 0334 11BC;110B 116D 0334 11BC; # (요◌̴ᆼ; 요◌̴ᆼ; 요◌̴ᆼ; 요◌̴ᆼ; 요◌̴ᆼ; ) HANGUL SYLLABLE YO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C758 0334 11AE;C758 0334 11AE;110B 1174 0334 11AE;C758 0334 11AE;110B 1174 0334 11AE; # (의◌̴ᆮ; 의◌̴ᆮ; 의◌̴ᆮ; 의◌̴ᆮ; 의◌̴ᆮ; ) HANGUL SYLLABLE YI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C7AC 0334 11B5;C7AC 0334 11B5;110C 1162 0334 11B5;C7AC 0334 11B5;110C 1162 0334 11B5; # (재◌̴ᆵ; 재◌̴ᆵ; 재◌̴ᆵ; 재◌̴ᆵ; 재◌̴ᆵ; ) HANGUL SYLLABLE JAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C800 0334 11BC;C800 0334 11BC;110C 1165 0334 11BC;C800 0334 11BC;110C 1165 0334 11BC; # (저◌̴ᆼ; 저◌̴ᆼ; 저◌̴ᆼ; 저◌̴ᆼ; 저◌̴ᆼ; ) HANGUL SYLLABLE JEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +C8C4 0334 11AE;C8C4 0334 11AE;110C 116C 0334 11AE;C8C4 0334 11AE;110C 116C 0334 11AE; # (죄◌̴ᆮ; 죄◌̴ᆮ; 죄◌̴ᆮ; 죄◌̴ᆮ; 죄◌̴ᆮ; ) HANGUL SYLLABLE JOE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +C918 0334 11B5;C918 0334 11B5;110C 116F 0334 11B5;C918 0334 11B5;110C 116F 0334 11B5; # (줘◌̴ᆵ; 줘◌̴ᆵ; 줘◌̴ᆵ; 줘◌̴ᆵ; 줘◌̴ᆵ; ) HANGUL SYLLABLE JWEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +C96C 0334 11BC;C96C 0334 11BC;110C 1172 0334 11BC;C96C 0334 11BC;110C 1172 0334 11BC; # (쥬◌̴ᆼ; 쥬◌̴ᆼ; 쥬◌̴ᆼ; 쥬◌̴ᆼ; 쥬◌̴ᆼ; ) HANGUL SYLLABLE JYU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +CA30 0334 11AE;CA30 0334 11AE;110D 1164 0334 11AE;CA30 0334 11AE;110D 1164 0334 11AE; # (쨰◌̴ᆮ; 쨰◌̴ᆮ; 쨰◌̴ᆮ; 쨰◌̴ᆮ; 쨰◌̴ᆮ; ) HANGUL SYLLABLE JJYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +CA84 0334 11B5;CA84 0334 11B5;110D 1167 0334 11B5;CA84 0334 11B5;110D 1167 0334 11B5; # (쪄◌̴ᆵ; 쪄◌̴ᆵ; 쪄◌̴ᆵ; 쪄◌̴ᆵ; 쪄◌̴ᆵ; ) HANGUL SYLLABLE JJYEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +CAD8 0334 11BC;CAD8 0334 11BC;110D 116A 0334 11BC;CAD8 0334 11BC;110D 116A 0334 11BC; # (쫘◌̴ᆼ; 쫘◌̴ᆼ; 쫘◌̴ᆼ; 쫘◌̴ᆼ; 쫘◌̴ᆼ; ) HANGUL SYLLABLE JJWA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +CB9C 0334 11AE;CB9C 0334 11AE;110D 1171 0334 11AE;CB9C 0334 11AE;110D 1171 0334 11AE; # (쮜◌̴ᆮ; 쮜◌̴ᆮ; 쮜◌̴ᆮ; 쮜◌̴ᆮ; 쮜◌̴ᆮ; ) HANGUL SYLLABLE JJWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +CBF0 0334 11B5;CBF0 0334 11B5;110D 1174 0334 11B5;CBF0 0334 11B5;110D 1174 0334 11B5; # (쯰◌̴ᆵ; 쯰◌̴ᆵ; 쯰◌̴ᆵ; 쯰◌̴ᆵ; 쯰◌̴ᆵ; ) HANGUL SYLLABLE JJYI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +CC44 0334 11BC;CC44 0334 11BC;110E 1162 0334 11BC;CC44 0334 11BC;110E 1162 0334 11BC; # (채◌̴ᆼ; 채◌̴ᆼ; 채◌̴ᆼ; 채◌̴ᆼ; 채◌̴ᆼ; ) HANGUL SYLLABLE CAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +CD08 0334 11AE;CD08 0334 11AE;110E 1169 0334 11AE;CD08 0334 11AE;110E 1169 0334 11AE; # (초◌̴ᆮ; 초◌̴ᆮ; 초◌̴ᆮ; 초◌̴ᆮ; 초◌̴ᆮ; ) HANGUL SYLLABLE CO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +CD5C 0334 11B5;CD5C 0334 11B5;110E 116C 0334 11B5;CD5C 0334 11B5;110E 116C 0334 11B5; # (최◌̴ᆵ; 최◌̴ᆵ; 최◌̴ᆵ; 최◌̴ᆵ; 최◌̴ᆵ; ) HANGUL SYLLABLE COE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +CDB0 0334 11BC;CDB0 0334 11BC;110E 116F 0334 11BC;CDB0 0334 11BC;110E 116F 0334 11BC; # (춰◌̴ᆼ; 춰◌̴ᆼ; 춰◌̴ᆼ; 춰◌̴ᆼ; 춰◌̴ᆼ; ) HANGUL SYLLABLE CWEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +CE74 0334 11AE;CE74 0334 11AE;110F 1161 0334 11AE;CE74 0334 11AE;110F 1161 0334 11AE; # (카◌̴ᆮ; 카◌̴ᆮ; 카◌̴ᆮ; 카◌̴ᆮ; 카◌̴ᆮ; ) HANGUL SYLLABLE KA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +CEC8 0334 11B5;CEC8 0334 11B5;110F 1164 0334 11B5;CEC8 0334 11B5;110F 1164 0334 11B5; # (컈◌̴ᆵ; 컈◌̴ᆵ; 컈◌̴ᆵ; 컈◌̴ᆵ; 컈◌̴ᆵ; ) HANGUL SYLLABLE KYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +CF1C 0334 11BC;CF1C 0334 11BC;110F 1167 0334 11BC;CF1C 0334 11BC;110F 1167 0334 11BC; # (켜◌̴ᆼ; 켜◌̴ᆼ; 켜◌̴ᆼ; 켜◌̴ᆼ; 켜◌̴ᆼ; ) HANGUL SYLLABLE KYEO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +CFE0 0334 11AE;CFE0 0334 11AE;110F 116E 0334 11AE;CFE0 0334 11AE;110F 116E 0334 11AE; # (쿠◌̴ᆮ; 쿠◌̴ᆮ; 쿠◌̴ᆮ; 쿠◌̴ᆮ; 쿠◌̴ᆮ; ) HANGUL SYLLABLE KU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D034 0334 11B5;D034 0334 11B5;110F 1171 0334 11B5;D034 0334 11B5;110F 1171 0334 11B5; # (퀴◌̴ᆵ; 퀴◌̴ᆵ; 퀴◌̴ᆵ; 퀴◌̴ᆵ; 퀴◌̴ᆵ; ) HANGUL SYLLABLE KWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +D088 0334 11BC;D088 0334 11BC;110F 1174 0334 11BC;D088 0334 11BC;110F 1174 0334 11BC; # (킈◌̴ᆼ; 킈◌̴ᆼ; 킈◌̴ᆼ; 킈◌̴ᆼ; 킈◌̴ᆼ; ) HANGUL SYLLABLE KYI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +D14C 0334 11AE;D14C 0334 11AE;1110 1166 0334 11AE;D14C 0334 11AE;1110 1166 0334 11AE; # (테◌̴ᆮ; 테◌̴ᆮ; 테◌̴ᆮ; 테◌̴ᆮ; 테◌̴ᆮ; ) HANGUL SYLLABLE TE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D1A0 0334 11B5;D1A0 0334 11B5;1110 1169 0334 11B5;D1A0 0334 11B5;1110 1169 0334 11B5; # (토◌̴ᆵ; 토◌̴ᆵ; 토◌̴ᆵ; 토◌̴ᆵ; 토◌̴ᆵ; ) HANGUL SYLLABLE TO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +D1F4 0334 11BC;D1F4 0334 11BC;1110 116C 0334 11BC;D1F4 0334 11BC;1110 116C 0334 11BC; # (퇴◌̴ᆼ; 퇴◌̴ᆼ; 퇴◌̴ᆼ; 퇴◌̴ᆼ; 퇴◌̴ᆼ; ) HANGUL SYLLABLE TOE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +D2B8 0334 11AE;D2B8 0334 11AE;1110 1173 0334 11AE;D2B8 0334 11AE;1110 1173 0334 11AE; # (트◌̴ᆮ; 트◌̴ᆮ; 트◌̴ᆮ; 트◌̴ᆮ; 트◌̴ᆮ; ) HANGUL SYLLABLE TEU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D30C 0334 11B5;D30C 0334 11B5;1111 1161 0334 11B5;D30C 0334 11B5;1111 1161 0334 11B5; # (파◌̴ᆵ; 파◌̴ᆵ; 파◌̴ᆵ; 파◌̴ᆵ; 파◌̴ᆵ; ) HANGUL SYLLABLE PA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +D360 0334 11BC;D360 0334 11BC;1111 1164 0334 11BC;D360 0334 11BC;1111 1164 0334 11BC; # (퍠◌̴ᆼ; 퍠◌̴ᆼ; 퍠◌̴ᆼ; 퍠◌̴ᆼ; 퍠◌̴ᆼ; ) HANGUL SYLLABLE PYAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +D424 0334 11AE;D424 0334 11AE;1111 116B 0334 11AE;D424 0334 11AE;1111 116B 0334 11AE; # (퐤◌̴ᆮ; 퐤◌̴ᆮ; 퐤◌̴ᆮ; 퐤◌̴ᆮ; 퐤◌̴ᆮ; ) HANGUL SYLLABLE PWAE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D478 0334 11B5;D478 0334 11B5;1111 116E 0334 11B5;D478 0334 11B5;1111 116E 0334 11B5; # (푸◌̴ᆵ; 푸◌̴ᆵ; 푸◌̴ᆵ; 푸◌̴ᆵ; 푸◌̴ᆵ; ) HANGUL SYLLABLE PU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +D4CC 0334 11BC;D4CC 0334 11BC;1111 1171 0334 11BC;D4CC 0334 11BC;1111 1171 0334 11BC; # (퓌◌̴ᆼ; 퓌◌̴ᆼ; 퓌◌̴ᆼ; 퓌◌̴ᆼ; 퓌◌̴ᆼ; ) HANGUL SYLLABLE PWI, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +D590 0334 11AE;D590 0334 11AE;1112 1163 0334 11AE;D590 0334 11AE;1112 1163 0334 11AE; # (햐◌̴ᆮ; 햐◌̴ᆮ; 햐◌̴ᆮ; 햐◌̴ᆮ; 햐◌̴ᆮ; ) HANGUL SYLLABLE HYA, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D5E4 0334 11B5;D5E4 0334 11B5;1112 1166 0334 11B5;D5E4 0334 11B5;1112 1166 0334 11B5; # (헤◌̴ᆵ; 헤◌̴ᆵ; 헤◌̴ᆵ; 헤◌̴ᆵ; 헤◌̴ᆵ; ) HANGUL SYLLABLE HE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +D638 0334 11BC;D638 0334 11BC;1112 1169 0334 11BC;D638 0334 11BC;1112 1169 0334 11BC; # (호◌̴ᆼ; 호◌̴ᆼ; 호◌̴ᆼ; 호◌̴ᆼ; 호◌̴ᆼ; ) HANGUL SYLLABLE HO, COMBINING TILDE OVERLAY, HANGUL JONGSEONG IEUNG +D6FC 0334 11AE;D6FC 0334 11AE;1112 1170 0334 11AE;D6FC 0334 11AE;1112 1170 0334 11AE; # (훼◌̴ᆮ; 훼◌̴ᆮ; 훼◌̴ᆮ; 훼◌̴ᆮ; 훼◌̴ᆮ; ) HANGUL SYLLABLE HWE, COMBINING TILDE OVERLAY, HANGUL JONGSEONG TIKEUT +D750 0334 11B5;D750 0334 11B5;1112 1173 0334 11B5;D750 0334 11B5;1112 1173 0334 11B5; # (흐◌̴ᆵ; 흐◌̴ᆵ; 흐◌̴ᆵ; 흐◌̴ᆵ; 흐◌̴ᆵ; ) HANGUL SYLLABLE HEU, COMBINING TILDE OVERLAY, HANGUL JONGSEONG RIEUL-PHIEUPH +11131 0334 11127;11131 0334 11127;11131 0334 11127;11131 0334 11127;11131 0334 11127; # (◌𑄱◌̴◌𑄧; ◌𑄱◌̴◌𑄧; ◌𑄱◌̴◌𑄧; ◌𑄱◌̴◌𑄧; ◌𑄱◌̴◌𑄧; ) CHAKMA O MARK, COMBINING TILDE OVERLAY, CHAKMA VOWEL SIGN A +11132 0334 11127;11132 0334 11127;11132 0334 11127;11132 0334 11127;11132 0334 11127; # (◌𑄲◌̴◌𑄧; ◌𑄲◌̴◌𑄧; ◌𑄲◌̴◌𑄧; ◌𑄲◌̴◌𑄧; ◌𑄲◌̴◌𑄧; ) CHAKMA AU MARK, COMBINING TILDE OVERLAY, CHAKMA VOWEL SIGN A +11347 0334 1133E;11347 0334 1133E;11347 0334 1133E;11347 0334 1133E;11347 0334 1133E; # (𑍇◌̴𑌾; 𑍇◌̴𑌾; 𑍇◌̴𑌾; 𑍇◌̴𑌾; 𑍇◌̴𑌾; ) GRANTHA VOWEL SIGN EE, COMBINING TILDE OVERLAY, GRANTHA VOWEL SIGN AA +11347 0334 11357;11347 0334 11357;11347 0334 11357;11347 0334 11357;11347 0334 11357; # (𑍇◌̴𑍗; 𑍇◌̴𑍗; 𑍇◌̴𑍗; 𑍇◌̴𑍗; 𑍇◌̴𑍗; ) GRANTHA VOWEL SIGN EE, COMBINING TILDE OVERLAY, GRANTHA AU LENGTH MARK +114B9 0334 114B0;114B9 0334 114B0;114B9 0334 114B0;114B9 0334 114B0;114B9 0334 114B0; # (𑒹◌̴𑒰; 𑒹◌̴𑒰; 𑒹◌̴𑒰; 𑒹◌̴𑒰; 𑒹◌̴𑒰; ) TIRHUTA VOWEL SIGN E, COMBINING TILDE OVERLAY, TIRHUTA VOWEL SIGN AA +114B9 0334 114BA;114B9 0334 114BA;114B9 0334 114BA;114B9 0334 114BA;114B9 0334 114BA; # (𑒹◌̴◌𑒺; 𑒹◌̴◌𑒺; 𑒹◌̴◌𑒺; 𑒹◌̴◌𑒺; 𑒹◌̴◌𑒺; ) TIRHUTA VOWEL SIGN E, COMBINING TILDE OVERLAY, TIRHUTA VOWEL SIGN SHORT E +114B9 0334 114BD;114B9 0334 114BD;114B9 0334 114BD;114B9 0334 114BD;114B9 0334 114BD; # (𑒹◌̴𑒽; 𑒹◌̴𑒽; 𑒹◌̴𑒽; 𑒹◌̴𑒽; 𑒹◌̴𑒽; ) TIRHUTA VOWEL SIGN E, COMBINING TILDE OVERLAY, TIRHUTA VOWEL SIGN SHORT O +115B8 0334 115AF;115B8 0334 115AF;115B8 0334 115AF;115B8 0334 115AF;115B8 0334 115AF; # (𑖸◌̴𑖯; 𑖸◌̴𑖯; 𑖸◌̴𑖯; 𑖸◌̴𑖯; 𑖸◌̴𑖯; ) SIDDHAM VOWEL SIGN E, COMBINING TILDE OVERLAY, SIDDHAM VOWEL SIGN AA +115B9 0334 115AF;115B9 0334 115AF;115B9 0334 115AF;115B9 0334 115AF;115B9 0334 115AF; # (𑖹◌̴𑖯; 𑖹◌̴𑖯; 𑖹◌̴𑖯; 𑖹◌̴𑖯; 𑖹◌̴𑖯; ) SIDDHAM VOWEL SIGN AI, COMBINING TILDE OVERLAY, SIDDHAM VOWEL SIGN AA +11935 0334 11930;11935 0334 11930;11935 0334 11930;11935 0334 11930;11935 0334 11930; # (𑤵◌̴𑤰; 𑤵◌̴𑤰; 𑤵◌̴𑤰; 𑤵◌̴𑤰; 𑤵◌̴𑤰; ) DIVES AKURU VOWEL SIGN E, COMBINING TILDE OVERLAY, DIVES AKURU VOWEL SIGN AA +# +# EOF diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl index a90a2d13c726..c1f576276fa9 100644 --- a/erts/emulator/test/busy_port_SUITE.erl +++ b/erts/emulator/test/busy_port_SUITE.erl @@ -255,7 +255,7 @@ no_trap_exit(Config) when is_list(Config) -> Pid = fun_spawn(fun no_trap_exit_process/3, [self(), linked, Config]), receive {Pid, port_created, Port} -> - io:format("Process ~w created port ~w", [Pid, Port]), + ct:log("Process ~w created port ~w", [Pid, Port]), exit(Port, die); Other1 -> ct:fail({unexpected_message, Other1}) @@ -278,7 +278,7 @@ no_trap_exit_unlinked(Config) when is_list(Config) -> [self(), unlink, Config]), receive {Pid, port_created, Port} -> - io:format("Process ~w created port ~w", [Pid, Port]), + ct:log("Process ~w created port ~w", [Pid, Port]), exit(Port, die); Other1 -> ct:fail({unexpected_message, Other1}) @@ -320,7 +320,7 @@ trap_exit(Config) when is_list(Config) -> Pid = fun_spawn(fun busy_port_exit_process/2, [self(), Config]), receive {Pid, port_created, Port} -> - io:format("Process ~w created port ~w", [Pid, Port]), + ct:log("Process ~w created port ~w", [Pid, Port]), unlink(Pid), {status, suspended} = process_info(Pid, status), exit(Port, die); @@ -755,7 +755,7 @@ run_command(_M,spawn,{Args,Opts}) -> run_command(M,spawn,Args) -> run_command(M,spawn,{Args,[]}); run_command(Mod,Func,Args) -> - erlang:display({{Mod,Func,Args}, erlang:system_time(microsecond)}), + %% erlang:display({{Mod,Func,Args}, erlang:system_time(microsecond)}), apply(Mod,Func,Args). validate_scenario(Data,[{print,Var}|T]) -> @@ -869,7 +869,7 @@ chk_not_value(_, _) -> wait_for([]) -> ok; wait_for(Pids) -> - io:format("Waiting for ~p", [Pids]), + ct:log("Waiting for ~p", [Pids]), receive {'EXIT', Pid, normal} -> wait_for(lists:delete(Pid, Pids)); diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl index 95b836219e77..f74df5ca7133 100644 --- a/erts/emulator/test/code_SUITE.erl +++ b/erts/emulator/test/code_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -26,6 +26,7 @@ call_purged_fun_code_gone/1, call_purged_fun_code_reload/1, call_purged_fun_code_there/1, + call_purged_fun_code_altered/1, multi_proc_purge/1, t_check_old_code/1, external_fun/1,get_chunk/1,module_md5/1, constant_pools/1,constant_refc_binaries/1, @@ -33,8 +34,9 @@ false_dependency/1,coverage/1,fun_confusion/1, t_copy_literals/1, t_copy_literals_frags/1, erl_544/1, max_heap_size/1, - check_process_code_signal_order/1, - check_process_code_dirty_exec_proc/1]). + check_process_code_signal_order/1, + check_process_code_dirty_exec_proc/1, + call_fun_before_load/1]). -define(line_trace, 1). -include_lib("common_test/include/ct.hrl"). @@ -46,13 +48,14 @@ all() -> bad_beam_file, literal_leak, call_purged_fun_code_gone, call_purged_fun_code_reload, call_purged_fun_code_there, + call_purged_fun_code_altered, multi_proc_purge, t_check_old_code, external_fun, get_chunk, module_md5, constant_pools, constant_refc_binaries, fake_literals, false_dependency, coverage, fun_confusion, t_copy_literals, t_copy_literals_frags, erl_544, max_heap_size, check_process_code_signal_order, - check_process_code_dirty_exec_proc]. + check_process_code_dirty_exec_proc, call_fun_before_load]. init_per_suite(Config) -> erts_debug:set_internal_state(available_internal_state, true), @@ -249,6 +252,18 @@ call_purged_fun_code_there_test(Config) when is_list(Config) -> call_purged_fun_test(Priv, Data, code_there), ok. +%% GH-7288: calling a fun defined by a module that had been purged after +%% loading a different version of the same module (and therefore did not +%% inherit the old fun entries) could cause the emulator to crash. +call_purged_fun_code_altered(Config) when is_list(Config) -> + run_sys_proc_test(fun call_purged_fun_code_altered_test/1, Config). + +call_purged_fun_code_altered_test(Config) when is_list(Config) -> + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + call_purged_fun_test(Priv, Data, code_altered), + ok. + call_purged_fun_test(Priv, Data, Type) -> SrcFile = filename:join(Data, "call_purged_fun_tester.erl"), ObjFile = filename:join(Priv, "call_purged_fun_tester.beam"), @@ -257,7 +272,6 @@ call_purged_fun_test(Priv, Data, Type) -> call_purged_fun_tester:do(Priv, Data, Type, []). - multi_proc_purge(Config) when is_list(Config) -> run_sys_proc_test(fun multi_proc_purge_test/1, Config). @@ -746,11 +760,11 @@ verify_lit_terms([], _) -> ok. get_external_terms() -> - {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, []), + {ok, Peer, Node}= ?CT_PEER(), Ref = rpc:call(Node, erlang, make_ref, []), Ports = rpc:call(Node, erlang, ports, []), Pid = rpc:call(Node, erlang, self, []), - _ = test_server:stop_node(Node), + peer:stop(Peer), {Ref,hd(Ports),Pid}. %% OTP-7559: c_p->cp could contain garbage and create a false dependency @@ -1096,9 +1110,9 @@ erl_544(Config) when is_list(Config) -> File = proplists:get_value(file, Info2), StackFun = fun(_, _, _) -> false end, FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end, - Formated = + Formatted = erl_error:format_stacktrace(1, Stack, StackFun, FormatFun), - true = is_list(Formated), + true = is_list(Formatted), ok after ok = file:set_cwd(CWD) @@ -1184,6 +1198,29 @@ check_process_code_dirty_exec_proc(Config) when is_list(Config) -> false = is_process_alive(Pid), ok. +%% OTP-18016: When loading a module over itself, a race in fun loading made it +%% possible to call a local fun before the module was fully reloaded. +call_fun_before_load(Config) -> + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + Path = code:get_path(), + true = code:add_path(Priv), + try + SrcFile = filename:join(Data, "call_fun_before_load.erl"), + ObjFile = filename:join(Priv, "call_fun_before_load.beam"), + {ok,Mod,Code} = compile:file(SrcFile, [binary, report]), + {module,Mod} = code:load_binary(Mod, ObjFile, Code), + + ok = call_fun_before_load:run(ObjFile, Code), + + code:purge(call_fun_before_load) + after + code:set_path(Path), + code:delete(call_fun_before_load), + code:purge(call_fun_before_load) + end, + ok. + %% Utilities. make_sub_binary(Bin) when is_binary(Bin) -> diff --git a/erts/emulator/test/code_SUITE_data/call_fun_before_load.erl b/erts/emulator/test/code_SUITE_data/call_fun_before_load.erl new file mode 100644 index 000000000000..9ede44ebd201 --- /dev/null +++ b/erts/emulator/test/code_SUITE_data/call_fun_before_load.erl @@ -0,0 +1,45 @@ +-module(call_fun_before_load). +-export([run/2]). + +run(ObjFile, Code) -> + Ref = make_ref(), + Self = self(), + {Pid, MRef} = + spawn_monitor( + fun() -> + %% If we're called before being loaded, process_info/2 can't + %% figure out where we are, reporting that we're in an + %% unknown module rather than the current one. + Fun0 = fun(Fun) -> + {current_function, + {?MODULE, _, _}} = + process_info(self(), current_function), + Fun(Fun) + end, + + NumScheds = erlang:system_info(schedulers_online), + Workers = [spawn_link(fun() -> Fun0(Fun0) end) + || _ <- lists:seq(1, NumScheds)], + + %% Give the workers time to start before reloading ourselves. + timer:sleep(100), + + code:load_binary(?MODULE, ObjFile, Code), + + %% Give the workers time to crash before exiting. + timer:sleep(100), + + Self ! {Ref, Workers}, + + ok + end), + receive + {Ref, Workers} -> + erlang:demonitor(MRef, [flush]), + [exit(Worker, kill) || Worker <- Workers], + ok; + {'DOWN', MRef, process, Pid, {{badmatch,_}, _}} -> + ct:fail("Ran newly staged but not yet loaded code.", []); + {'DOWN', MRef, process, Pid, Reason} -> + ct:fail(Reason) + end. diff --git a/erts/emulator/test/code_SUITE_data/call_purged_fun.erl b/erts/emulator/test/code_SUITE_data/call_purged_fun.erl new file mode 100644 index 000000000000..e3a94092dc7e --- /dev/null +++ b/erts/emulator/test/code_SUITE_data/call_purged_fun.erl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2023-2023. 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(call_purged_fun). + +-export([make_fun/1, make_fun2/0]). + +make_fun(A) -> + fun(X) -> A + X end. + +make_fun2() -> + fun (F1,F2) -> + F1(), + F2() + end. diff --git a/erts/emulator/test/code_SUITE_data/call_purged_fun_altered.erl b/erts/emulator/test/code_SUITE_data/call_purged_fun_altered.erl new file mode 100644 index 000000000000..6e180afdfea2 --- /dev/null +++ b/erts/emulator/test/code_SUITE_data/call_purged_fun_altered.erl @@ -0,0 +1,37 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2023-2023. 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(call_purged_fun). + +-export([make_fun/1, make_fun2/0, dummy/1]). + +make_fun(A) -> + fun(X) -> A + X end. + +make_fun2() -> + fun (F1,F2) -> + F1(), + F2() + end. + +%% Dummy function that ensures the module MD5 is different from the alpha +%% version, keeping us from inheriting its fun entries. +dummy(I) -> + I. diff --git a/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl b/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl index 6d74b63863e3..32494807c422 100644 --- a/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl +++ b/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl @@ -7,18 +7,18 @@ do(P,D,T,O) -> do_it(P,D,T,O). do_it(Priv, Data, Type, Opts) -> - File = filename:join(Data, "my_code_test2"), - Code = filename:join(Priv, "my_code_test2"), + OrigFile = filename:join(Data, "call_purged_fun"), + Code = filename:join(Priv, "call_purged_fun"), - catch erlang:purge_module(my_code_test2), - catch erlang:delete_module(my_code_test2), - catch erlang:purge_module(my_code_test2), + catch erlang:purge_module(call_purged_fun), + catch erlang:delete_module(call_purged_fun), + catch erlang:purge_module(call_purged_fun), - {ok,my_code_test2} = c:c(File, [{outdir,Priv} | Opts]), + {ok,call_purged_fun} = c:c(OrigFile, [{outdir,Priv} | Opts]), - T = ets:new(my_code_test2_fun_table, []), - ets:insert(T, {my_fun,my_code_test2:make_fun(4711)}), - ets:insert(T, {my_fun2,my_code_test2:make_fun2()}), + T = ets:new(call_purged_fun_fun_table, []), + ets:insert(T, {my_fun,call_purged_fun:make_fun(4711)}), + ets:insert(T, {my_fun2,call_purged_fun:make_fun2()}), Papa = self(), {P0,M0} = spawn_monitor(fun () -> @@ -37,21 +37,49 @@ do_it(Priv, Data, Type, Opts) -> true; code_reload -> true; + code_altered -> + true; code_there -> false end, - true = erlang:delete_module(my_code_test2), + %% fun_info/1,2 must behave as documented on purged funs. + FunInfoBefore = fun(F) -> + {module, call_purged_fun} = erlang:fun_info(F, module), + {name, []} = erlang:fun_info(F, name), + {arity, 1} = erlang:fun_info(F, arity) + end, + FunInfoAfter = fun(F) -> + {module, call_purged_fun} = erlang:fun_info(F, module), + {name, Name} = erlang:fun_info(F, name), + true = is_atom(Name), + {arity, 1} = erlang:fun_info(F, arity) + end, + + true = erlang:delete_module(call_purged_fun), + + case Type of + code_altered -> + AlteredFile = filename:join(Data, "call_purged_fun_altered.erl"), + {ok,call_purged_fun,AlteredBin} = + compile:file(AlteredFile, [no_error_module_mismatch, + binary | Opts]), + code:load_binary(call_purged_fun, AlteredFile, AlteredBin); + _ -> + ok + end, ok = receive {P0, "going to sleep"} -> ok after 1000 -> timeout end, - Purge = start_purge(my_code_test2, PurgeType), + Purge = start_purge(call_purged_fun, PurgeType), {P1, M1} = spawn_monitor(fun () -> [{my_fun,F}] = ets:lookup(T, my_fun), + FunInfoBefore(F), 4712 = F(1), + FunInfoAfter(F), exit(completed) end), @@ -64,14 +92,18 @@ do_it(Priv, Data, Type, Opts) -> {P2, M2} = spawn_monitor(fun () -> [{my_fun,F}] = ets:lookup(T, my_fun), + FunInfoBefore(F), 4713 = F(2), + FunInfoAfter(F), exit(completed) - end), + end), {P3, M3} = spawn_monitor(fun () -> - [{my_fun,F}] = ets:lookup(T, my_fun), - 4714 = F(3), - exit(completed) - end), + [{my_fun,F}] = ets:lookup(T, my_fun), + FunInfoBefore(F), + 4714 = F(3), + FunInfoAfter(F), + exit(completed) + end), ok = wait_until(fun () -> {status, suspended} @@ -110,13 +142,17 @@ do_it(Priv, Data, Type, Opts) -> {undef, _} = wait_for_down(P1,M1), {undef, _} = wait_for_down(P2,M2), {undef, _} = wait_for_down(P3,M3); + code_altered -> + {{badfun, _}, _} = wait_for_down(P1,M1), + {{badfun, _}, _} = wait_for_down(P2,M2), + {{badfun, _}, _} = wait_for_down(P3,M3); _ -> completed = wait_for_down(P1,M1), completed = wait_for_down(P2,M2), completed = wait_for_down(P3,M3), - catch erlang:purge_module(my_code_test2), - catch erlang:delete_module(my_code_test2), - catch erlang:purge_module(my_code_test2) + catch erlang:purge_module(call_purged_fun), + catch erlang:delete_module(call_purged_fun), + catch erlang:purge_module(call_purged_fun) end, ok. diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl index bedcaf3a0896..55bc6eb06be8 100644 --- a/erts/emulator/test/decode_packet_SUITE.erl +++ b/erts/emulator/test/decode_packet_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -26,7 +26,7 @@ -export([all/0, suite/0,groups/0, init_per_testcase/2,end_per_testcase/2, - basic/1, packet_size/1, neg/1, http/1, line/1, ssl/1, otp_8536/1, + basic/1, ipv6/1, packet_size/1, neg/1, http/1, line/1, ssl/1, otp_8536/1, otp_9389/1, otp_9389_line/1]). suite() -> @@ -35,7 +35,7 @@ suite() -> all() -> [basic, packet_size, neg, http, line, ssl, otp_8536, - otp_9389, otp_9389_line]. + otp_9389, otp_9389_line, ipv6]. groups() -> []. @@ -174,11 +174,7 @@ pack(fcgi,Bin) -> PaddSz = rand:uniform(16) - 1, Psz = byte_size(Bin), Reserv = rand:uniform(256) - 1, - Padd = case PaddSz of - 0 -> <<>>; - _ -> list_to_binary([rand:uniform(256)-1 - || _<- lists:seq(1,PaddSz)]) - end, + Padd = rand:bytes(PaddSz), Res = <>, {<>, Res}; pack(tpkt,Bin) -> @@ -210,6 +206,23 @@ pack_ssl(Content, Major, Minor, Body) -> end, {Res, {ssl_tls,[],C,{Major,Minor}, Data}}. +ipv6(Config) when is_list(Config) -> + %% Test with port + Packet = <<"GET http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:4000/echo_components HTTP/1.1\r\nhost: orange\r\n\r\n">>, + {ok, {http_request, 'GET', {absoluteURI, http, <<"[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]">>, 4000, <<"/echo_components">>}, {1, 1}}, <<"host: orange\r\n\r\n">>} = + erlang:decode_packet(http_bin, Packet, []), + %% Test no port + Packet2 = <<"GET http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/1234 HTTP/1.1\r\nhost: orange\r\n\r\n">>, + {ok, {http_request, 'GET', {absoluteURI, http, <<"[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]">>, undefined, <<"/1234">>}, {1, 1}}, <<"host: orange\r\n\r\n">>} = + erlang:decode_packet(http_bin, Packet2, []), + %% Test short ipv6 form + Packet3 = <<"GET http://[::1]/1234 HTTP/1.1\r\nhost: orange\r\n\r\n">>, + {ok, {http_request, 'GET', {absoluteURI, http, <<"[::1]">>, undefined, <<"/1234">>}, {1, 1}}, <<"host: orange\r\n\r\n">>} = + erlang:decode_packet(http_bin, Packet3, []), + %% Test missing `]` + Packet4 = <<"GET http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210:4000/echo_components HTTP/1.1\r\nhost: orange\r\n\r\n">>, + {ok, {http_request, 'GET', {absoluteURI, http, <<"[FEDC">>, undefined, <<"/echo_components">>}, {1, 1}}, <<"host: orange\r\n\r\n">>} = + erlang:decode_packet(http_bin, Packet4, []). packet_size(Config) when is_list(Config) -> Packet = <<101,22,203,54,175>>, diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl index f8819b47937b..efb31f8471a9 100644 --- a/erts/emulator/test/dirty_bif_SUITE.erl +++ b/erts/emulator/test/dirty_bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2020. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -82,8 +82,8 @@ end_per_suite(_Config) -> init_per_testcase(Case, Config) -> [{testcase, Case} | Config]. -end_per_testcase(_Case, _Config) -> - ok. +end_per_testcase(_Case, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). dirty_bif(Config) when is_list(Config) -> dirty_cpu = erts_debug:dirty_cpu(scheduler,type), @@ -216,7 +216,7 @@ dirty_bif_multischedule_exception(Config) when is_list(Config) -> end. dirty_scheduler_exit(Config) when is_list(Config) -> - {ok, Node} = start_node(Config, "+SDio 1"), + {ok, Peer, Node} = ?CT_PEER(["+SDio", "1"]), [ok] = mcall(Node, [fun() -> %% Perform a dry run to ensure that all required code @@ -230,7 +230,7 @@ dirty_scheduler_exit(Config) when is_list(Config) -> io:format("Time=~p ms~n", [End-Start]), ok end]), - stop_node(Node), + peer:stop(Peer), ok. test_dirty_scheduler_exit() -> @@ -289,7 +289,7 @@ dirty_call_while_terminated(Config) when is_list(Config) -> undefined = process_info(Dirty, status), false = erlang:is_process_alive(Dirty), false = lists:member(Dirty, processes()), - %% Binary still refered by Dirty process not yet cleaned up + %% Binary still referred by Dirty process not yet cleaned up %% since the dirty bif has not yet returned... {value, {BinAddr, 4711, 2}} = lists:keysearch(4711, 2, element(2, @@ -315,7 +315,7 @@ dirty_call_while_terminated(Config) when is_list(Config) -> end. dirty_heap_access(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Me = self(), RGL = rpc:call(Node,erlang,whereis,[init]), Ref = rpc:call(Node,erlang,make_ref,[]), @@ -333,7 +333,7 @@ dirty_heap_access(Config) when is_list(Config) -> end, unlink(Dirty), exit(Dirty, kill), - stop_node(Node), + peer:stop(Peer), {comment, integer_to_list(N) ++ " GL change loops; " ++ integer_to_list(R) ++ " while running dirty"}. @@ -369,7 +369,7 @@ access_dirty_heap(Dirty, RGL, N, R) -> %% the dirty process is still alive immediately after accessing it. dirty_process_info(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, fun() -> ok end, fun(BifPid) -> PI = process_info(BifPid), @@ -381,7 +381,7 @@ dirty_process_info(Config) when is_list(Config) -> dirty_process_register(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, fun() -> ok end, fun(BifPid) -> register(test_dirty_process_register, BifPid), @@ -395,7 +395,7 @@ dirty_process_register(Config) when is_list(Config) -> dirty_process_trace(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, fun() -> %% BIFs can only be traced when their modules are loaded. code:ensure_loaded(erts_debug), @@ -554,13 +554,13 @@ wait_until(Fun) -> wait_until(Fun) end. -access_dirty_process(Config, Start, Test, Finish) -> - {ok, Node} = start_node(Config, ""), +access_dirty_process(TestCase, Start, Test, Finish) -> + {ok, Peer, Node} = ?CT_PEER(#{name => ?CT_PEER_NAME(TestCase)}), [ok] = mcall(Node, [fun() -> ok = test_dirty_process_access(Start, Test, Finish) end]), - stop_node(Node), + peer:stop(Peer), ok. test_dirty_process_access(Start, Test, Finish) -> @@ -586,23 +586,6 @@ test_dirty_process_access(Start, Test, Finish) -> end, ok = Finish(BifPid). -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). - mcall(Node, Funs) -> Parent = self(), Refs = lists:map(fun (Fun) -> diff --git a/erts/emulator/test/dirty_nif_SUITE.erl b/erts/emulator/test/dirty_nif_SUITE.erl index 9e6cbab38731..5069dfa5b9ce 100644 --- a/erts/emulator/test/dirty_nif_SUITE.erl +++ b/erts/emulator/test/dirty_nif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -29,13 +29,49 @@ -export([all/0, suite/0, init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, groups/0, dirty_nif/1, dirty_nif_send/1, dirty_nif_exception/1, call_dirty_nif_exception/1, dirty_scheduler_exit/1, dirty_call_while_terminated/1, dirty_heap_access/1, dirty_process_info/1, dirty_process_register/1, dirty_process_trace/1, code_purge/1, literal_area/1, dirty_nif_send_traced/1, - nif_whereis/1, nif_whereis_parallel/1, nif_whereis_proxy/1]). + nif_whereis/1, nif_whereis_parallel/1, nif_whereis_proxy/1, + set_halt_options_from_nif/1, + delay_halt/1, + delay_halt_old_code/1, + delay_halt_old_and_new_code/1, + flush_false/1, + on_halt/1, + on_halt_old_code/1, + on_halt_old_and_new_code/1, + sync_halt/1, + many_delay_halt/1, + many_on_halt/1]). + +-export([load_nif/2]). + +-nifs([lib_loaded/0, + call_dirty_nif/3, + send_from_dirty_nif/1, + send_wait_from_dirty_nif/1, + call_dirty_nif_exception/1, + call_dirty_nif_zero_args/0, + dirty_call_while_terminated_nif/1, + dirty_sleeper/0, + dirty_sleeper/1, + dirty_heap_access_nif/1, + whereis_term/2, + whereis_send/3, + dirty_terminating_literal_access/2, + delay_halt_normal/3, + delay_halt_io_bound/3, + delay_halt_cpu_bound/3, + sync_halt_io_bound/2, + sync_halt_cpu_bound/2, + set_halt_option_from_nif_normal/1, + set_halt_option_from_nif_io_bound/1, + set_halt_option_from_nif_cpu_bound/1]). -define(nif_stub,nif_stub_error(?LINE)). @@ -55,23 +91,38 @@ all() -> literal_area, dirty_nif_send_traced, nif_whereis, - nif_whereis_parallel]. + nif_whereis_parallel, + {group, halt_normal}, + {group, halt_dirty_cpu}, + {group, halt_dirty_io}, + {group, halt_misc}]. + +halt_sched_tests() -> + [set_halt_options_from_nif, delay_halt, delay_halt_old_code, delay_halt_old_and_new_code]. +halt_dirty_sched_tests() -> + [sync_halt, flush_false]. + +groups() -> + [{halt_normal, [parallel], halt_sched_tests()}, + {halt_dirty_cpu, [parallel], halt_sched_tests()++halt_dirty_sched_tests()}, + {halt_dirty_io, [parallel], halt_sched_tests()++halt_dirty_sched_tests()}, + {halt_misc, [parallel], [on_halt, on_halt_old_code, on_halt_old_and_new_code, many_on_halt, many_delay_halt]}]. + +init_per_group(Group, Config) -> + [{group, Group} | Config]. + +end_per_group(_, Config) -> + proplists:delete(group, Config). init_per_suite(Config) -> - case erlang:system_info(dirty_cpu_schedulers) of - N when N > 0 -> - case lib_loaded() of - false -> - ok = erlang:load_nif( - filename:join(?config(data_dir, Config), - "dirty_nif_SUITE"), []); - true -> - ok - end, - Config; - _ -> - {skipped, "No dirty scheduler support"} - end. + case lib_loaded() of + false -> + ok = erlang:load_nif(filename:join(?config(data_dir, Config), + "dirty_nif_SUITE"), []); + true -> + ok + end, + Config. end_per_suite(_Config) -> ok. @@ -82,6 +133,9 @@ init_per_testcase(Case, Config) -> end_per_testcase(_Case, _Config) -> ok. +load_nif(NifLib, LibInfo) -> + erlang:load_nif(NifLib, LibInfo). + dirty_nif(Config) when is_list(Config) -> Val1 = 42, Val2 = "Erlang", @@ -144,7 +198,7 @@ nif_raise_exceptions(NifFunc) -> end, ok, ExcTerms). dirty_scheduler_exit(Config) when is_list(Config) -> - {ok, Node} = start_node(Config, "+SDio 1"), + {ok, Peer, Node} = ?CT_PEER(["+SDio", "1"]), Path = proplists:get_value(data_dir, Config), NifLib = filename:join(Path, atom_to_list(?MODULE)), [ok] = mcall(Node, @@ -161,7 +215,7 @@ dirty_scheduler_exit(Config) when is_list(Config) -> io:format("Time=~p ms~n", [End-Start]), ok end]), - stop_node(Node), + peer:stop(Peer), ok. test_dirty_scheduler_exit() -> @@ -249,7 +303,7 @@ dirty_call_while_terminated(Config) when is_list(Config) -> end. dirty_heap_access(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Me = self(), RGL = rpc:call(Node,erlang,whereis,[init]), Ref = rpc:call(Node,erlang,make_ref,[]), @@ -267,7 +321,7 @@ dirty_heap_access(Config) when is_list(Config) -> end, unlink(Dirty), exit(Dirty, kill), - stop_node(Node), + peer:stop(Peer), {comment, integer_to_list(N) ++ " GL change loops; " ++ integer_to_list(R) ++ " while running dirty"}. @@ -303,7 +357,8 @@ access_dirty_heap(Dirty, RGL, N, R) -> %% the dirty process is still alive immediately after accessing it. dirty_process_info(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, + ?config(data_dir, Config), fun() -> ok end, fun(NifPid) -> PI = process_info(NifPid), @@ -315,7 +370,8 @@ dirty_process_info(Config) when is_list(Config) -> dirty_process_register(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, + ?config(data_dir, Config), fun() -> ok end, fun(NifPid) -> register(test_dirty_process_register, NifPid), @@ -329,7 +385,8 @@ dirty_process_register(Config) when is_list(Config) -> dirty_process_trace(Config) when is_list(Config) -> access_dirty_process( - Config, + ?FUNCTION_NAME, + ?config(data_dir, Config), fun() -> erlang:trace_pattern({?MODULE,dirty_sleeper,1}, [{'_',[],[{return_trace}]}], @@ -533,20 +590,369 @@ literal_area(Config) when is_list(Config) -> literal_area_collector_test:check_idle(5000), {comment, "Waited "++integer_to_list(TMO)++" milliseconds after purge"}. +set_halt_options_from_nif(Config) when is_list(Config) -> + case ?config(group, Config) of + halt_normal -> + error = set_halt_option_from_nif_normal(set_on_halt_handler), + error = set_halt_option_from_nif_normal(delay_halt); + halt_dirty_cpu -> + error = set_halt_option_from_nif_cpu_bound(set_on_halt_handler), + error = set_halt_option_from_nif_cpu_bound(delay_halt); + halt_dirty_io -> + error = set_halt_option_from_nif_io_bound(set_on_halt_handler), + error = set_halt_option_from_nif_io_bound(delay_halt) + end, + ok. + +delay_halt(Config) when is_list(Config) -> + delay_halt(Config, new_code). + +delay_halt_old_code(Config) when is_list(Config) -> + delay_halt(Config, old_code). + +delay_halt_old_and_new_code(Config) when is_list(Config) -> + delay_halt(Config, old_and_new_code). + +delay_halt(Config, Type) -> + Suite = filename:join(?config(data_dir, Config), ?MODULE_STRING), + Priv = proplists:get_value(priv_dir, Config), + TypeSuffix = "_"++atom_to_list(Type), + {Fun, FileName} = case ?config(group, Config) of + halt_normal -> + {fun delay_halt_normal/3, "delay_halt_normal"++TypeSuffix}; + halt_dirty_io -> + {fun delay_halt_io_bound/3, "delay_halt_io_bound"++TypeSuffix}; + halt_dirty_cpu -> + {fun delay_halt_cpu_bound/3, "delay_halt_cpu_bound"++TypeSuffix} + end, + Tester = self(), + NifFileName = filename:join(Priv, FileName), + {ok, Peer, Node} = ?CT_PEER(), + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {delay_halt}]), + ok = erpc:call(Node, file, set_cwd, [Priv]), + Proxy = spawn_link(Node, + fun () -> + receive + {delay_halt, _} = Msg -> + unlink(Tester), + Tester ! Msg + end + end), + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, fun () -> Fun(Proxy, FileName, 2) end), + receive {delay_halt, Pid} when is_pid(Pid), Node == node(Pid) -> ok end, + case Type of + new_code -> + ok; + old_code -> + true = erpc:call(Node, erlang, delete_module, [dirty_nif_SUITE]); + old_and_new_code -> + true = erpc:call(Node, erlang, delete_module, [dirty_nif_SUITE]), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {delay_halt}]), + Proxy2 = spawn_link(Node, + fun () -> + receive + {delay_halt, _} = Msg -> + unlink(Tester), + Tester ! Msg + end + end), + ok = erpc:cast(Node, fun () -> Fun(Proxy2, FileName++"_new_code", 2) end), + receive {delay_halt, Pid2} when is_pid(Pid2), Node == node(Pid2) -> ok end + end, + ok = erpc:cast(Node, erlang, halt, []), + ok = wait_until(fun () -> + {ok, <<"ok">>} == file:read_file(NifFileName) + andalso + (Type /= old_and_new_code + orelse {ok, <<"ok">>} == file:read_file(NifFileName++"_new_code")) + end, + 6000), + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("~s time=~pms", [FileName, Time]), + true = Time >= 2000, + receive {'DOWN', Mon, process, Peer, _} -> ok end, + ok. + +flush_false(Config) when is_list(Config) -> + Suite = filename:join(?config(data_dir, Config), ?MODULE_STRING), + Priv = proplists:get_value(priv_dir, Config), + {Fun, FileName} = case ?config(group, Config) of + halt_dirty_io -> + {fun delay_halt_io_bound/3, "flush_false_io_bound"}; + halt_dirty_cpu -> + {fun delay_halt_cpu_bound/3, "flush_false_cpu_bound"} + end, + Tester = self(), + NifFileName = filename:join(Priv, FileName), + OnHaltBaseName = FileName++"_on_halt", + OnHaltFileName = filename:join(Priv, OnHaltBaseName), + {ok, Peer, Node} = ?CT_PEER(), + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {sync_halt, OnHaltBaseName, 1}]), + ok = erpc:call(Node, file, set_cwd, [Priv]), + Proxy = spawn_link(Node, + fun () -> + receive + {delay_halt, _} = Msg -> + unlink(Tester), + Tester ! Msg + end + end), + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, fun () -> Fun(Proxy, FileName, 1) end), + receive {delay_halt, Pid} when is_pid(Pid), Node == node(Pid) -> ok end, + ok = erpc:cast(Node, erlang, halt, [0, [{flush,false}]]), + receive {'DOWN', Mon, process, Peer, _} -> ok end, + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("~s time=~pms", [FileName, Time]), + Wait = 3000-Time, + if Wait > 0 -> receive after Wait -> ok end; + true -> ok + end, + {error,enoent} = file:read_file(NifFileName), + {error,enoent} = file:read_file(OnHaltFileName), + ok. + +many_delay_halt(Config) when is_list(Config) -> + try + many_delay_halt_test(Config) + catch + throw:{skip, _} = Skip -> + Skip + end. + +many_delay_halt_test(Config) -> + Suite = filename:join(?config(data_dir, Config), ?MODULE_STRING), + Priv = proplists:get_value(priv_dir, Config), + Tester = self(), + {ok, Peer, Node} = ?CT_PEER(), + Chk = fun () -> + case erlang:system_info(schedulers_online) of + 1 -> throw({skip, "Too few schedulers online"}); + _ -> ok + end, + case erlang:system_info(dirty_cpu_schedulers_online) of + 1 -> throw({skip, "Too few dirty cpu schedulers online"}); + _ -> ok + end, + case erlang:system_info(dirty_io_schedulers) of + 1 -> throw({skip, "Too few dirty io schedulers online"}); + _ -> ok + end + end, + try + erpc:call(Node, Chk) + catch + throw:{skip, _} = Skip -> + peer:stop(Peer), + throw(Skip) + end, + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {delay_halt}]), + ok = erpc:call(Node, file, set_cwd, [Priv]), + ProxyFun = fun (Tag) -> + fun () -> + receive + {delay_halt, _} = Msg -> + unlink(Tester), + Tester ! {Tag, Msg} + end + end + end, + [P1, P2, P3, P4, P5] = [spawn_link(Node, ProxyFun(X)) || X <- lists:seq(1, 5)], + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, fun () -> delay_halt_io_bound(P1, "many_delay_halt_io2", 2) end), + ok = erpc:cast(Node, fun () -> delay_halt_io_bound(P2, "many_delay_halt_io1", 1) end), + ok = erpc:cast(Node, fun () -> delay_halt_cpu_bound(P3, "many_delay_halt_cpu1", 1) end), + ok = erpc:cast(Node, fun () -> delay_halt_cpu_bound(P4, "many_delay_halt_cpu2", 2) end), + _ = [receive + {X, {delay_halt, Pid}} when is_pid(Pid), Node == node(Pid) -> + ok + end || X <- lists:seq(1, 4)], + ok = erpc:cast(Node, fun () -> delay_halt_normal(P5, "many_delay_halt_normal", 1) end), + receive + {5, {delay_halt, Pid}} when is_pid(Pid), Node == node(Pid) -> + ok + end, + ok = erpc:cast(Node, erlang, halt, []), + ok = wait_until(fun () -> + {ok, <<"ok">>} == file:read_file(filename:join(Priv, "many_delay_halt_io2")) + andalso {ok, <<"ok">>} == file:read_file(filename:join(Priv, "many_delay_halt_cpu2")) + end, + 3000), + {ok, <<"ok">>} = file:read_file(filename:join(Priv, "many_delay_halt_cpu1")), + {ok, <<"ok">>} = file:read_file(filename:join(Priv, "many_delay_halt_io1")), + {ok, <<"ok">>} = file:read_file(filename:join(Priv, "many_delay_halt_normal")), + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("many_delay_halt time=~pms", [Time]), + true = Time >= 2000, + receive {'DOWN', Mon, process, Peer, _} -> ok end, + ok. + +on_halt(Config) when is_list(Config) -> + on_halt(Config, new_code). + +on_halt_old_code(Config) when is_list(Config) -> + on_halt(Config, old_code). + +on_halt_old_and_new_code(Config) when is_list(Config) -> + on_halt(Config, old_and_new_code). + +on_halt(Config, Type) -> + Suite = filename:join(?config(data_dir, Config), ?MODULE_STRING), + Priv = proplists:get_value(priv_dir, Config), + FileName = "on_halt_"++atom_to_list(Type), + OnHaltFileName = filename:join(Priv, FileName), + {ok, Peer, Node} = ?CT_PEER(), + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {on_halt, FileName, 1}]), + case Type of + new_code -> + ok; + old_code -> + true = erpc:call(Node, erlang, delete_module, [dirty_nif_SUITE]); + old_and_new_code -> + true = erpc:call(Node, erlang, delete_module, [dirty_nif_SUITE]), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {on_halt, FileName++"_new", 1}]) + end, + ok = erpc:call(Node, file, set_cwd, [Priv]), + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, erlang, halt, []), + ok = wait_until(fun () -> + {ok, <<"ok">>} == file:read_file(OnHaltFileName) + andalso (Type /= old_and_new_code + orelse {ok, <<"ok">>} == file:read_file(OnHaltFileName++"_new")) + end, + 3000), + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("~s time=~pms", [FileName, Time]), + if Type == old_and_new_code -> true = Time >= 2000; + true -> true = Time >= 1000 + end, + receive {'DOWN', Mon, process, Peer, _} -> ok end, + ok. + +on_halt_module_code_format() -> + lists:flatten(["-module(~s).~n", + "-export([load/1, lib_loaded/0]).~n", + "-nifs([lib_loaded/0]).~n", + "load(SoFile) -> erlang:load_nif(SoFile, ?MODULE_STRING).~n", + "lib_loaded() -> false.~n"]). + +many_on_halt(Config) when is_list(Config) -> + DDir = ?config(data_dir, Config), + Priv = proplists:get_value(priv_dir, Config), + OnHaltModules = ["on_halt_a","on_halt_b","on_halt_c","on_halt_d","on_halt_e","on_halt_f"], + DeleteOnHaltModules = ["on_halt_a","on_halt_c","on_halt_d","on_halt_f"], + PurgeOnHaltModules = DeleteOnHaltModules -- ["on_halt_d"], + ActiveOnHaltModules = OnHaltModules -- PurgeOnHaltModules, + lists:foreach(fun (ModStr) -> + Code = io_lib:format(on_halt_module_code_format(), [ModStr]), + ok = file:write_file(filename:join(DDir, ModStr++".erl"), Code) + end, + OnHaltModules), + {ok, Peer, Node} = ?CT_PEER(), + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, + fun () -> + ok = file:set_cwd(Priv), + lists:foreach(fun (ModStr) -> + AbsModStr = filename:join(DDir, ModStr), + {ok,Mod,Bin} = compile:file(AbsModStr, [binary]), + {module, Mod} = erlang:load_module(Mod, Bin), + ok = Mod:load(AbsModStr), + true = Mod:lib_loaded() + end, + OnHaltModules), + lists:foreach(fun (ModStr) -> + Mod = list_to_atom(ModStr), + true = erlang:delete_module(Mod) + end, DeleteOnHaltModules), + lists:foreach(fun (ModStr) -> + Mod = list_to_atom(ModStr), + true = erlang:purge_module(Mod) + end, PurgeOnHaltModules), + ok + end), + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, erlang, halt, []), + ok = wait_until(fun () -> + try + lists:foreach(fun (ModStr) -> + FileName = filename:join(Priv, ModStr), + {ok, <<"ok">>} = file:read_file(FileName) + end, ActiveOnHaltModules), + true + catch + _:_ -> + false + end + end, + 1000*(length(ActiveOnHaltModules)+1)), + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("many_on_halt time=~pms", [Time]), + true = Time >= length(ActiveOnHaltModules)*1000, + receive {'DOWN', Mon, process, Peer, _} -> ok end, + ok. + +sync_halt(Config) when is_list(Config) -> + Suite = filename:join(?config(data_dir, Config), ?MODULE_STRING), + Priv = proplists:get_value(priv_dir, Config), + {Fun, FileName} = case ?config(group, Config) of + halt_dirty_io -> + {fun sync_halt_io_bound/2, "sync_halt_io_bound"}; + halt_dirty_cpu -> + {fun sync_halt_cpu_bound/2, "sync_halt_cpu_bound"} + end, + Tester = self(), + NifFileName = filename:join(Priv, FileName), + OnHaltBaseFileName = FileName++".onhalt", + OnHaltFileName = filename:join(Priv, OnHaltBaseFileName), + {ok, Peer, Node} = ?CT_PEER(), + Mon = erlang:monitor(process, Peer), + ok = erpc:call(Node, ?MODULE, load_nif, [Suite, {sync_halt, OnHaltBaseFileName, 1}]), + ok = erpc:call(Node, file, set_cwd, [Priv]), + Proxy = spawn_link(Node, + fun () -> + receive + {sync_halt, _} = Msg -> + unlink(Tester), + Tester ! Msg + end + end), + ok = erpc:cast(Node, fun () -> Fun(Proxy, FileName) end), + receive {sync_halt, Pid} when is_pid(Pid), Node == node(Pid) -> ok end, + Start = erlang:monotonic_time(millisecond), + ok = erpc:cast(Node, erlang, halt, []), + ok = wait_until(fun () -> + {ok, <<"ok">>} == file:read_file(OnHaltFileName) + end, + 2000), + ok = wait_until(fun () -> + {ok, <<"ok">>} == file:read_file(NifFileName) + end, + 4000), + Time = erlang:monotonic_time(millisecond) - Start, + ct:log("~s time=~pms", [FileName, Time]), + true = Time >= 1000, + receive {'DOWN', Mon, process, Peer, _} -> ok end, + ok. + %% %% Internal... %% -access_dirty_process(Config, Start, Test, Finish) -> - {ok, Node} = start_node(Config, ""), +access_dirty_process(TestCase, Path, Start, Test, Finish) -> + {ok, Peer, Node} = ?CT_PEER(#{name => ?CT_PEER_NAME(TestCase)}), [ok] = mcall(Node, [fun() -> - Path = ?config(data_dir, Config), Lib = atom_to_list(?MODULE), ok = erlang:load_nif(filename:join(Path,Lib), []), ok = test_dirty_process_access(Start, Test, Finish) end]), - stop_node(Node), + peer:stop(Peer), ok. test_dirty_process_access(Start, Test, Finish) -> @@ -575,23 +981,6 @@ test_dirty_process_access(Start, Test, Finish) -> receive_any() -> receive M -> M end. -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). - mcall(Node, Funs) -> Parent = self(), Refs = lists:map(fun (Fun) -> @@ -659,7 +1048,7 @@ nif_whereis(Config) when is_list(Config) -> nif_whereis_parallel(Config) when is_list(Config) -> - %% try to be at least a little asymetric + %% try to be at least a little asymmetric NProcs = trunc(3.5 * erlang:system_info(schedulers)), NSeq = lists:seq(1, NProcs), Names = [list_to_atom("dirty_nif_whereis_proc_" ++ integer_to_list(N)) @@ -789,6 +1178,14 @@ dirty_heap_access_nif(_) -> ?nif_stub. whereis_term(_Type,_Name) -> ?nif_stub. whereis_send(_Type,_Name,_Msg) -> ?nif_stub. dirty_terminating_literal_access(_Me, _Literal) -> ?nif_stub. +delay_halt_normal(_Pid, _FileName, _Delay) -> ?nif_stub. +delay_halt_io_bound(_Pid, _FileName, _Delay) -> ?nif_stub. +delay_halt_cpu_bound(_Pid, _FileName, _Delay) -> ?nif_stub. +sync_halt_io_bound(_Pid, _FileName) -> ?nif_stub. +sync_halt_cpu_bound(_Pid, _FileName) -> ?nif_stub. +set_halt_option_from_nif_normal(_Op) -> ?nif_stub. +set_halt_option_from_nif_io_bound(_Op) -> ?nif_stub. +set_halt_option_from_nif_cpu_bound(_Op) -> ?nif_stub. nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src b/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src index 4462afd815af..55ca552cb270 100644 --- a/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src +++ b/erts/emulator/test/dirty_nif_SUITE_data/Makefile.src @@ -1,5 +1,5 @@ -NIF_LIBS = dirty_nif_SUITE@dll@ +NIF_LIBS = dirty_nif_SUITE@dll@ on_halt_a@dll@ on_halt_b@dll@ on_halt_c@dll@ on_halt_d@dll@ on_halt_e@dll@ on_halt_f@dll@ all: $(NIF_LIBS) echo_drv@dll@ diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c index fb5146278b90..94edd2f29c54 100644 --- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c +++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2020. All Rights Reserved. + * Copyright Ericsson AB 2009-2023. 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. @@ -19,11 +19,14 @@ */ #include #include +#include #ifdef __WIN32__ #include #else #include #endif +#include +#include /* * Hack to get around this function missing from the NIF API. @@ -43,8 +46,128 @@ static ERL_NIF_TERM atom_pid; static ERL_NIF_TERM atom_port; static ERL_NIF_TERM atom_send; +typedef struct { + int halting; + int on_halt_wait; + ErlNifMutex *mtx; + ErlNifCond *cnd; + char *filename; +} PrivData; + +static PrivData *make_priv_data(void) +{ + PrivData *pdata = enif_alloc(sizeof(PrivData)); + if (!pdata) + return NULL; + pdata->halting = 0; + pdata->on_halt_wait = 0; + pdata->mtx = NULL; + pdata->cnd = NULL; + pdata->filename = NULL; + return pdata; +} + +static void unload(ErlNifEnv *env, void *priv_data) +{ + if (priv_data) { + PrivData *pdata = priv_data; + if (pdata->mtx) + enif_mutex_destroy(pdata->mtx); + if (pdata->cnd) + enif_cond_destroy(pdata->cnd); + if (pdata->filename) + enif_free(pdata->filename); + enif_free(pdata); + } +} + +static void on_halt(void *priv_data); + static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + int arity; + const ERL_NIF_TERM *array; + if (enif_get_tuple(env, load_info, &arity, &array)) { + char atom_text[32]; + int err; + unsigned filename_len; + PrivData *pdata = NULL; + + if (arity < 1 || 3 < arity) + return __LINE__; + if (!enif_get_atom(env, array[0], &atom_text[0], + sizeof(atom_text), ERL_NIF_LATIN1)) { + return __LINE__; + } + pdata = make_priv_data(); + if (!pdata) + return __LINE__; + if (strcmp(atom_text, "on_halt") == 0) { + if (0 != enif_set_option(env, ERL_NIF_OPT_ON_HALT, on_halt)) { + unload(env, pdata); + return __LINE__; + } + } + else if (strcmp(atom_text, "delay_halt") == 0) { + if (0 != enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)) { + unload(env, pdata); + return __LINE__; + } + } + else if (strcmp(atom_text, "sync_halt") == 0) { + if (0 != enif_set_option(env, ERL_NIF_OPT_ON_HALT, on_halt)) { + unload(env, pdata); + return __LINE__; + } + if (0 != enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)) { + unload(env, pdata); + return __LINE__; + } + pdata->mtx = enif_mutex_create("sync_halt_dirty_nif_SUITE"); + pdata->cnd = enif_cond_create("sync_halt_dirty_nif_SUITE"); + if (!pdata->mtx || !pdata->cnd) { + unload(env, pdata); + return __LINE__; + } + } + else { + unload(env, pdata); + return __LINE__; + } + + if (arity >= 2) { + if (!enif_get_list_length(env, array[1], &filename_len)) { + unload(env, pdata); + return __LINE__; + } + if (filename_len > 0) { + filename_len++; + pdata->filename = enif_alloc(filename_len); + if (!pdata->filename) { + unload(env, pdata); + return __LINE__; + } + if (filename_len != enif_get_string(env, + array[1], + pdata->filename, + filename_len, + ERL_NIF_LATIN1)) { + unload(env, pdata); + return __LINE__; + } + } + } + if (arity == 3) { + if (!enif_get_int(env, array[2], &pdata->on_halt_wait) + || pdata->on_halt_wait < 0 + || pdata->on_halt_wait*1000 < 0) { + unload(env, pdata); + return __LINE__; + } + } + *priv_data = (void *) pdata; + } + atom_badarg = enif_make_atom(env, "badarg"); atom_error = enif_make_atom(env, "error"); atom_false = enif_make_atom(env,"false"); @@ -57,6 +180,11 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) return 0; } +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + return load(env, priv_data, load_info); +} + static ERL_NIF_TERM lib_loaded(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return enif_make_atom(env, "true"); @@ -468,6 +596,149 @@ static ERL_NIF_TERM dirty_terminating_literal_access(ErlNifEnv* env, int argc, c return self_term; } +static int fn_write_ok(char *filename) +{ + FILE *file = fopen(filename, "w"); + if (!file) + return EINVAL; + if (1 != fwrite("ok", 2, 1, file)) + return EINVAL; + fclose(file); + return 0; +} + +static int efn_write_ok(ErlNifEnv *env, const ERL_NIF_TERM arg) +{ + int res; + unsigned filename_len; + char *filename; + + if (!enif_get_list_length(env, arg, &filename_len) || filename_len < 2) { + res = EINVAL; + goto done; + } + filename_len++; + filename = enif_alloc(filename_len); + if (!filename) { + res = ENOMEM; + goto done; + } + if (filename_len != enif_get_string(env, + arg, + filename, + filename_len, + ERL_NIF_LATIN1)) { + res = EINVAL; + goto done; + } + res = fn_write_ok(filename); +done: + if (filename) + enif_free(filename); + switch (res) { + case 0: + return atom_ok; + case ENOMEM: + return enif_raise_exception(env, enif_make_atom(env, "enomem")); + default: + return enif_make_badarg(env); + } +} + +static ERL_NIF_TERM delay_halt(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM msg; + ErlNifPid receiver, self; + int res, secs; + + if (argc != 3) + return enif_make_badarg(env); + if (!enif_get_int(env, argv[2], &secs)) + return enif_make_badarg(env); + if (secs < 0 || secs*1000 < 0) + return enif_make_badarg(env); + if (!enif_self(env, &self)) + return enif_make_badarg(env); + if (!enif_get_local_pid(env, argv[0], &receiver)) + return enif_make_badarg(env); + msg = enif_make_tuple2(env, enif_make_atom(env, "delay_halt"), enif_make_pid(env, &self)); + res = enif_send(env, &receiver, NULL, msg); + if (!res) + return enif_make_badarg(env); + +#ifdef __WIN32__ + Sleep(secs*1000); +#else + sleep(secs); +#endif + return efn_write_ok(env, argv[1]); +} + +static ERL_NIF_TERM sync_halt(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM msg; + ErlNifPid receiver, self; + int res; + PrivData *pdata = enif_priv_data(env); + if (!pdata) + return enif_raise_exception(env, enif_make_atom(env, "missing_priv_data")); + if (argc != 2) + return enif_make_badarg(env); + if (!enif_self(env, &self)) + return enif_make_badarg(env); + if (!enif_get_local_pid(env, argv[0], &receiver)) + return enif_make_badarg(env); + msg = enif_make_tuple2(env, enif_make_atom(env, "sync_halt"), enif_make_pid(env, &self)); + res = enif_send(env, &receiver, NULL, msg); + if (!res) + return enif_make_badarg(env); + enif_mutex_lock(pdata->mtx); + while (!pdata->halting) + enif_cond_wait(pdata->cnd, pdata->mtx); + enif_mutex_unlock(pdata->mtx); + return efn_write_ok(env, argv[1]); +} + +static ERL_NIF_TERM set_halt_option_from_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + unsigned len; + char atom_text[32]; + if (argc != 1) + return enif_make_badarg(env); + if (!enif_get_atom(env, argv[0], &atom_text[0], sizeof(atom_text), ERL_NIF_LATIN1)) + return enif_make_badarg(env); + if (strcmp(atom_text, "set_on_halt_handler") == 0) { + if (0 == enif_set_option(env, ERL_NIF_OPT_ON_HALT, on_halt)) + return atom_ok; + return atom_error; + } + else if (strcmp(atom_text, "delay_halt") == 0) { + if (0 == enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)) + return atom_ok; + return atom_error; + } + return enif_make_badarg(env); +} + +static void on_halt(void *priv_data) +{ + PrivData *pdata = (PrivData *)priv_data; + int res; +#ifdef __WIN32__ + Sleep(pdata->on_halt_wait*1000); +#else + sleep(pdata->on_halt_wait); +#endif + if (pdata->mtx) { + enif_mutex_lock(pdata->mtx); + assert(!pdata->halting); + pdata->halting = !0; + enif_cond_broadcast(pdata->cnd); + enif_mutex_unlock(pdata->mtx); + } + res = fn_write_ok(pdata->filename); + assert(res == 0); +} static ErlNifFunc nif_funcs[] = { @@ -484,6 +755,14 @@ static ErlNifFunc nif_funcs[] = {"whereis_send", 3, whereis_send, ERL_NIF_DIRTY_JOB_IO_BOUND}, {"whereis_term", 2, whereis_term, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"dirty_terminating_literal_access", 2, dirty_terminating_literal_access, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"delay_halt_normal", 3, delay_halt, 0}, + {"delay_halt_io_bound", 3, delay_halt, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"delay_halt_cpu_bound", 3, delay_halt, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"sync_halt_io_bound", 2, sync_halt, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"sync_halt_cpu_bound", 2, sync_halt, ERL_NIF_DIRTY_JOB_CPU_BOUND}, + {"set_halt_option_from_nif_normal", 1, set_halt_option_from_nif, 0}, + {"set_halt_option_from_nif_io_bound", 1, set_halt_option_from_nif, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"set_halt_option_from_nif_cpu_bound", 1, set_halt_option_from_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND} }; -ERL_NIF_INIT(dirty_nif_SUITE,nif_funcs,load,NULL,NULL,NULL) +ERL_NIF_INIT(dirty_nif_SUITE,nif_funcs,load,NULL,upgrade,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_a.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_a.c new file mode 100644 index 000000000000..73d50a2bf19e --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_a.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_a,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_b.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_b.c new file mode 100644 index 000000000000..b9e13a17faf2 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_b.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_b,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_c.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_c.c new file mode 100644 index 000000000000..db875e7f1852 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_c.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_c,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_d.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_d.c new file mode 100644 index 000000000000..e3b64245ced8 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_d.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_d,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_e.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_e.c new file mode 100644 index 000000000000..73357c9b9d01 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_e.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_e,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_f.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_f.c new file mode 100644 index 000000000000..58b4955d4f3f --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_f.c @@ -0,0 +1,23 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +#include "on_halt_nif.c" + +ERL_NIF_INIT(on_halt_f,nif_funcs,load,NULL,NULL,unload) diff --git a/erts/emulator/test/dirty_nif_SUITE_data/on_halt_nif.c b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_nif.c new file mode 100644 index 000000000000..610b80d3f7e1 --- /dev/null +++ b/erts/emulator/test/dirty_nif_SUITE_data/on_halt_nif.c @@ -0,0 +1,96 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ +#include "erl_nif.h" +#include +#include +#ifdef __WIN32__ +#include +#else +#include +#endif +#include +#include + + +static int fn_write_ok(char *filename) +{ + FILE *file = fopen(filename, "w"); + if (!file) + return EINVAL; + if (1 != fwrite("ok", 2, 1, file)) + return EINVAL; + fclose(file); + return 0; +} + +static void on_halt(void *priv_data) +{ + int res; +#ifdef __WIN32__ + Sleep(1000); +#else + sleep(1); +#endif + assert(priv_data); + res = fn_write_ok((char *) priv_data); + assert(res == 0); +} + +static void unload(ErlNifEnv *env, void *priv_data) +{ + if (priv_data) + enif_free(priv_data); +} + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + unsigned filename_len; + char *filename; + if (0 != enif_set_option(env, ERL_NIF_OPT_ON_HALT, on_halt)) + return __LINE__; + if (!enif_get_list_length(env, load_info, &filename_len)) + return __LINE__; + if (filename_len == 0) + return __LINE__; + filename_len++; + filename = enif_alloc(filename_len); + if (!filename) + return __LINE__; + if (filename_len != enif_get_string(env, + load_info, + filename, + filename_len, + ERL_NIF_LATIN1)) { + enif_free(filename); + return __LINE__; + } + *priv_data = (void *) filename; + return 0; +} + +static ERL_NIF_TERM lib_loaded(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_make_atom(env, "true"); +} + +static ErlNifFunc nif_funcs[] = +{ + {"lib_loaded", 0, lib_loaded} +}; diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index b53feeee3a43..d577f2a1e517 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -37,14 +37,12 @@ -include_lib("common_test/include/ct.hrl"). -%-define(Line, erlang:display({line,?LINE}),). --define(Line,). - -export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2, ping/1, bulk_send_small/1, - group_leader/1, + group_leader/1, nodes2/1, optimistic_dflags/1, bulk_send_big/1, bulk_send_bigbig/1, local_send_small/1, local_send_big/1, @@ -81,6 +79,12 @@ hopefull_data_encoding/1, hopefull_export_fun_bug/1, huge_iovec/1, + is_alive/1, + dyn_node_name_monitor_node/1, + dyn_node_name_monitor/1, + async_dist_flag/1, + async_dist_port_dctrlr/1, + async_dist_proc_dctrlr/1, creation_selection/1, creation_selection_test/1]). @@ -88,7 +92,7 @@ -export([sender/3, receiver2/2, dummy_waiter/0, dead_process/0, group_leader_1/1, optimistic_dflags_echo/0, optimistic_dflags_sender/1, - roundtrip/1, bounce/1, do_dist_auto_connect/1, inet_rpc_server/1, + roundtrip/1, bounce/1, dist_parallel_sender/3, dist_parallel_receiver/0, derr_run/1, dist_evil_parallel_receiver/0, make_busy/2]). @@ -102,7 +106,7 @@ suite() -> all() -> [ping, {group, bulk_send}, {group, local_send}, - group_leader, + group_leader, nodes2, optimistic_dflags, link_to_busy, exit_to_busy, lost_exit, link_to_dead, link_to_dead_new_node, @@ -115,7 +119,8 @@ all() -> dist_entry_refc_race, start_epmd_false, no_epmd, epmd_module, system_limit, hopefull_data_encoding, hopefull_export_fun_bug, - huge_iovec, creation_selection]. + huge_iovec, is_alive, dyn_node_name_monitor_node, dyn_node_name_monitor, + {group, async_dist}, creation_selection]. groups() -> [{bulk_send, [], [bulk_send_small, bulk_send_big, bulk_send_bigbig]}, @@ -134,7 +139,11 @@ groups() -> [message_latency_large_message, message_latency_large_link_exit, message_latency_large_monitor_exit, - message_latency_large_exit2]} + message_latency_large_exit2]}, + {async_dist, [], + [async_dist_flag, + async_dist_port_dctrlr, + async_dist_proc_dctrlr]} ]. init_per_suite(Config) -> @@ -159,6 +168,15 @@ init_per_group(_, Config) -> end_per_group(_, Config) -> Config. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + case wait_until(fun() -> nodes(connected) == [] end, 10_000) of + ok -> ok; + timeout -> + erts_test_utils:ept_check_leaked_nodes(Config) + end. + %% Tests pinging a node in different ways. ping(Config) when is_list(Config) -> Times = 1024, @@ -174,10 +192,10 @@ ping(Config) when is_list(Config) -> %% Pings another node. - {ok, OtherNode} = start_node(distribution_SUITE_other), + {ok, Peer, OtherNode} = ?CT_PEER(), io:format("Pinging ~s (assumed to exist)", [OtherNode]), test_server:do_times(Times, fun() -> pong = net_adm:ping(OtherNode) end), - stop_node(OtherNode), + peer_stop(Peer, OtherNode), %% Pings our own node many times. @@ -189,55 +207,330 @@ ping(Config) when is_list(Config) -> %% Test erlang:group_leader(_, ExternalPid), i.e. DOP_GROUP_LEADER group_leader(Config) when is_list(Config) -> - ?Line Sock = start_relay_node(group_leader_1, []), - ?Line Sock2 = start_relay_node(group_leader_2, []), - try - ?Line Node2 = inet_rpc_nodename(Sock2), - ?Line {ok, ok} = do_inet_rpc(Sock, ?MODULE, group_leader_1, [Node2]) - after - ?Line stop_relay_node(Sock), - ?Line stop_relay_node(Sock2) - end, - ok. + {ok, Peer1, Node1} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"]}), + {ok, Peer2, Node2} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"]}), + pang = net_adm:ping(Node1), pang = net_adm:ping(Node2), %% extra check, may be skipped + ok = peer:call(Peer1, ?MODULE, group_leader_1, [Node2]), + peer:stop(Peer1), %% verify_nc() will fail because peer is not dist-connected + peer:stop(Peer2). group_leader_1(Node2) -> - ?Line ExtPid = spawn(Node2, fun F() -> + ExtPid = spawn(Node2, fun F() -> receive {From, group_leader} -> From ! {self(), group_leader, group_leader()} end, F() end), - ?Line GL1 = self(), - ?Line group_leader(GL1, ExtPid), - ?Line ExtPid ! {self(), group_leader}, - ?Line {ExtPid, group_leader, GL1} = receive_one(), + GL1 = self(), + group_leader(GL1, ExtPid), + ExtPid ! {self(), group_leader}, + {ExtPid, group_leader, GL1} = receive_one(), %% Kill connection and repeat test when group_leader/2 triggers auto-connect - ?Line net_kernel:monitor_nodes(true), - ?Line net_kernel:disconnect(Node2), - ?Line {nodedown, Node2} = receive_one(), - ?Line GL2 = spawn(fun() -> dummy end), - ?Line group_leader(GL2, ExtPid), - ?Line {nodeup, Node2} = receive_one(), - ?Line ExtPid ! {self(), group_leader}, - ?Line {ExtPid, group_leader, GL2} = receive_one(), + net_kernel:monitor_nodes(true), + net_kernel:disconnect(Node2), + {nodedown, Node2} = receive_one(), + GL2 = spawn(fun() -> dummy end), + group_leader(GL2, ExtPid), + {nodeup, Node2} = receive_one(), + ExtPid ! {self(), group_leader}, + {ExtPid, group_leader, GL2} = receive_one(), ok. -%% Test optimistic distribution flags toward pending connections (DFLAG_DIST_HOPEFULLY) -optimistic_dflags(Config) when is_list(Config) -> - ?Line Sender = start_relay_node(optimistic_dflags_sender, []), - ?Line Echo = start_relay_node(optimistic_dflags_echo, []), - try - ?Line {ok, ok} = do_inet_rpc(Echo, ?MODULE, optimistic_dflags_echo, []), - - ?Line EchoNode = inet_rpc_nodename(Echo), - ?Line {ok, ok} = do_inet_rpc(Sender, ?MODULE, optimistic_dflags_sender, [EchoNode]) - after - ?Line stop_relay_node(Sender), - ?Line stop_relay_node(Echo) +nodes2(Config) when is_list(Config) -> + + This = node(), + + ok = net_kernel:monitor_nodes(true, #{node_type => all, + connection_id => true}), + + AlreadyConnected = maps:from_list(lists:map(fun (N) -> + {N, true} + end, nodes(connected))), + AlreadyVisible = maps:from_list(lists:map(fun (N) -> + {N, true} + end, nodes(visible))), + AlreadyHidden = maps:from_list(lists:map(fun (N) -> + {N, true} + end, nodes(visible))), + AlreadyKnown = maps:from_list(lists:map(fun (N) -> + {N, true} + end, nodes(known))), + + {ok, PV1, V1} = ?CT_PEER(), + {ok, PH1, H1} = ?CT_PEER(["-hidden"]), + {ok, PV2, V2} = ?CT_PEER(), + {ok, PH2, H2} = ?CT_PEER(["-hidden"]), + + TestNodes = maps:from_list(lists:map(fun (N) -> + {N, true} + end, [This, V1, H1, V2, H2])), + + V1CId = receive {nodeup, V1, #{connection_id := C1, node_type := visible}} -> C1 end, + V2CId = receive {nodeup, V2, #{connection_id := C2, node_type := visible}} -> C2 end, + H1CId = receive {nodeup, H1, #{connection_id := C3, node_type := hidden}} -> C3 end, + H2CId = receive {nodeup, H2, #{connection_id := C4, node_type := hidden}} -> C4 end, + + lists:foreach(fun ({N, I}) when N == V1 -> + 2 = maps:size(I), + #{connection_id := V1CId, node_type := visible} = I; + ({N, I}) when N == V2 -> + 2 = maps:size(I), + #{connection_id := V2CId, node_type := visible} = I; + ({N, I}) when N == H1 -> + 2 = maps:size(I), + #{connection_id := H1CId, node_type := hidden} = I; + ({N, I}) when N == H2 -> + 2 = maps:size(I), + #{connection_id := H2CId, node_type := hidden} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyConnected) + end, erlang:nodes(connected, #{connection_id => true, + node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 2 = maps:size(I), + #{connection_id := V1CId, node_type := visible} = I; + ({N, I}) when N == V2 -> + 2 = maps:size(I), + #{connection_id := V2CId, node_type := visible} = I; + ({N, I}) when N == H1 -> + 2 = maps:size(I), + #{connection_id := H1CId, node_type := hidden} = I; + ({N, I}) when N == H2 -> + 2 = maps:size(I), + #{connection_id := H2CId, node_type := hidden} = I; + ({N, I}) when N == This -> + 2 = maps:size(I), + #{connection_id := undefined, node_type := this} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyConnected) + end, erlang:nodes([this, connected], #{connection_id => true, + node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 1 = maps:size(I), + #{connection_id := V1CId} = I; + ({N, I}) when N == V2 -> + 1 = maps:size(I), + #{connection_id := V2CId} = I; + ({N, I}) when N == H1 -> + 1 = maps:size(I), + #{connection_id := H1CId} = I; + ({N, I}) when N == H2 -> + 1 = maps:size(I), + #{connection_id := H2CId} = I; + ({N, I}) -> + 1 = maps:size(I), + #{connection_id := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyConnected) + end, erlang:nodes(connected, #{connection_id => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 1 = maps:size(I), + #{node_type := visible} = I; + ({N, I}) when N == V2 -> + 1 = maps:size(I), + #{node_type := visible} = I; + ({N, I}) when N == H1 -> + 1 = maps:size(I), + #{node_type := hidden} = I; + ({N, I}) when N == H2 -> + 1 = maps:size(I), + #{node_type := hidden} = I; + ({N, I}) -> + 1 = maps:size(I), + #{node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyConnected) + end, erlang:nodes(connected, #{node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 2 = maps:size(I), + #{connection_id := V1CId, node_type := visible} = I; + ({N, I}) when N == V2 -> + 2 = maps:size(I), + #{connection_id := V2CId, node_type := visible} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyVisible) + end, erlang:nodes(visible, #{connection_id => true, + node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 2 = maps:size(I), + #{connection_id := V1CId, node_type := visible} = I; + ({N, I}) when N == V2 -> + 2 = maps:size(I), + #{connection_id := V2CId, node_type := visible} = I; + ({N, I}) when N == This -> + 2 = maps:size(I), + #{connection_id := undefined, node_type := this} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyVisible) + end, erlang:nodes([this, visible], #{connection_id => true, + node_type => true})), + lists:foreach(fun ({N, I}) when N == H1 -> + 2 = maps:size(I), + #{connection_id := H1CId, node_type := hidden} = I; + ({N, I}) when N == H2 -> + 2 = maps:size(I), + #{connection_id := H2CId, node_type := hidden} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyHidden) + end, erlang:nodes(hidden, #{connection_id => true, + node_type => true})), + [{This, #{connection_id := undefined, + node_type := this}}] = erlang:nodes(this, #{connection_id => true, + node_type => true}), + [{This, #{connection_id := undefined}}] = erlang:nodes(this, #{connection_id => true}), + [{This, #{node_type := this}}] = erlang:nodes(this, #{node_type => true}), + + %% Ensure dist these dist entries are not GC:d yet... + NKV2 = rpc:call(V2, erlang, whereis, [net_kernel]), + true = is_pid(NKV2), + NKH2 = rpc:call(H2, erlang, whereis, [net_kernel]), + true = is_pid(NKH2), + + peer:stop(PV2), + peer:stop(PH2), + + receive {nodedown, V2, #{connection_id := V2CId, node_type := visible}} -> ok end, + receive {nodedown, H2, #{connection_id := H2CId, node_type := hidden}} -> ok end, + + lists:foreach(fun ({N, I}) when N == V1 -> + 2 = maps:size(I), + #{connection_id := V1CId, node_type := visible} = I; + ({N, I}) when N == V2 -> + 2 = maps:size(I), + #{connection_id := undefined, node_type := known} = I; + ({N, I}) when N == H1 -> + 2 = maps:size(I), + #{connection_id := H1CId, node_type := hidden} = I; + ({N, I}) when N == H2 -> + 2 = maps:size(I), + #{connection_id := undefined, node_type := known} = I; + ({N, I}) when N == This -> + 2 = maps:size(I), + #{connection_id := undefined, node_type := this} = I; + ({N, I}) -> + 2 = maps:size(I), + #{connection_id := _, node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyKnown) + end, erlang:nodes(known, #{connection_id => true, + node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 1 = maps:size(I), + #{node_type := visible} = I; + ({N, I}) when N == V2 -> + 1 = maps:size(I), + #{node_type := known} = I; + ({N, I}) when N == H1 -> + 1 = maps:size(I), + #{node_type := hidden} = I; + ({N, I}) when N == H2 -> + 1 = maps:size(I), + #{node_type := known} = I; + ({N, I}) when N == This -> + 1 = maps:size(I), + #{node_type := this} = I; + ({N, I}) -> + 1 = maps:size(I), + #{node_type := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyKnown) + end, erlang:nodes(known, #{node_type => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 1 = maps:size(I), + #{connection_id := V1CId} = I; + ({N, I}) when N == V2 -> + 1 = maps:size(I), + #{connection_id := undefined} = I; + ({N, I}) when N == H1 -> + 1 = maps:size(I), + #{connection_id := H1CId} = I; + ({N, I}) when N == H2 -> + 1 = maps:size(I), + #{connection_id := undefined} = I; + ({N, I}) when N == This -> + 1 = maps:size(I), + #{connection_id := undefined} = I; + ({N, I}) -> + 1 = maps:size(I), + #{connection_id := _} = I, + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyKnown) + end, erlang:nodes(known, #{connection_id => true})), + lists:foreach(fun ({N, I}) when N == V1 -> + 0 = maps:size(I), + #{} = I; + ({N, I}) when N == V2 -> + 0 = maps:size(I), + #{} = I; + ({N, I}) when N == H1 -> + 0 = maps:size(I), + #{} = I; + ({N, I}) when N == H2 -> + 0 = maps:size(I), + #{} = I; + ({N, I}) when N == This -> + 0 = maps:size(I), + #{} = I; + ({N, I}) -> + 0 = maps:size(I), + false = maps:is_key(N, TestNodes), + true = maps:is_key(N, AlreadyKnown) + end, erlang:nodes(known, #{})), + + peer:stop(PV1), + peer:stop(PH1), + + id(NKV2), + id(NKH2), + + try erlang:nodes("visible", #{connection_id => true}) + catch error:badarg -> ok + end, + try erlang:nodes([another], #{connection_id => true}) + catch error:badarg -> ok + end, + try erlang:nodes(visible, #{cid => true}) + catch error:badarg -> ok + end, + try erlang:nodes(visible, #{connection_id => yes}) + catch error:badarg -> ok + end, + try erlang:nodes(visible, #{node_type => yes}) + catch error:badarg -> ok + end, + try erlang:nodes(visible, [{connection_id, true}]) + catch error:badarg -> ok + end, + try erlang:nodes(visible, [{node_type, true}]) + catch error:badarg -> ok end, ok. +%% Test optimistic distribution flags toward pending connections (DFLAG_DIST_HOPEFULLY) +optimistic_dflags(Config) when is_list(Config) -> + {ok, PeerSender, _Sender} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"]}), + {ok, PeerEcho, Echo} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"]}), + ok = peer:call(PeerEcho, ?MODULE, optimistic_dflags_echo, []), + ok = peer:call(PeerSender, ?MODULE, optimistic_dflags_sender, [Echo]), + peer:stop(PeerSender), + peer:stop(PeerEcho). + optimistic_dflags_echo() -> P = spawn(fun F() -> receive {From, Term} -> @@ -251,25 +544,25 @@ optimistic_dflags_echo() -> ok. optimistic_dflags_sender(EchoNode) -> - ?Line net_kernel:monitor_nodes(true), + net_kernel:monitor_nodes(true), optimistic_dflags_do(EchoNode, <<1:1>>), optimistic_dflags_do(EchoNode, fun lists:map/2), ok. optimistic_dflags_do(EchoNode, Term) -> - ?Line {optimistic_dflags_echo, EchoNode} ! {self(), Term}, - ?Line {nodeup, EchoNode} = receive_one(), - ?Line {EchoPid, Term} = receive_one(), + {optimistic_dflags_echo, EchoNode} ! {self(), Term}, + {nodeup, EchoNode} = receive_one(), + {EchoPid, Term} = receive_one(), %% repeat with pid destination - ?Line net_kernel:disconnect(EchoNode), - ?Line {nodedown, EchoNode} = receive_one(), - ?Line EchoPid ! {self(), Term}, - ?Line {nodeup, EchoNode} = receive_one(), - ?Line {EchoPid, Term} = receive_one(), - - ?Line net_kernel:disconnect(EchoNode), - ?Line {nodedown, EchoNode} = receive_one(), + net_kernel:disconnect(EchoNode), + {nodedown, EchoNode} = receive_one(), + EchoPid ! {self(), Term}, + {nodeup, EchoNode} = receive_one(), + {EchoPid, Term} = receive_one(), + + net_kernel:disconnect(EchoNode), + {nodedown, EchoNode} = receive_one(), ok. @@ -287,13 +580,13 @@ bulk_send(Terms, BinSize) -> ct:timetrap({seconds, 30}), io:format("Sending ~w binaries, each of size ~w K", [Terms, BinSize]), - {ok, Node} = start_node(bulk_receiver), + {ok, Peer, Node} = ?CT_PEER(), Recv = spawn(Node, erlang, apply, [fun receiver/2, [0, 0]]), Bin = binary:copy(<<253>>, BinSize*1024), Size = Terms*size(Bin), {Elapsed, {Terms, Size}} = test_server:timecall(?MODULE, sender, [Recv, Bin, Terms]), - stop_node(Node), + peer_stop(Peer, Node), {comment, integer_to_list(round(Size/1024/max(1,Elapsed))) ++ " K/s"}. sender(To, _Bin, 0) -> @@ -327,7 +620,7 @@ bulk_sendsend2(Terms, BinSize, BusyBufSize) -> io:format("\nSending ~w binaries, each of size ~w K", [Terms, BinSize]), - {ok, NodeRecv} = start_node(bulk_receiver), + {ok, RecvPeer, NodeRecv} = ?CT_PEER(), Recv = spawn(NodeRecv, erlang, apply, [fun receiver/2, [0, 0]]), Bin = binary:copy(<<253>>, BinSize*1024), @@ -340,8 +633,7 @@ bulk_sendsend2(Terms, BinSize, BusyBufSize) -> %% default busy size and "+zdbbl 5", and if the 5 case gets %% "many many more" monitor messages, then we know we're working. - {ok, NodeSend} = start_node(bulk_sender, "+zdbbl " ++ - integer_to_list(BusyBufSize)), + {ok, SendPeer, NodeSend} = ?CT_PEER(["+zdbbl", integer_to_list(BusyBufSize)]), _Send = spawn(NodeSend, erlang, apply, [fun sendersender/4, [self(), Recv, Bin, Terms]]), {Elapsed, {_TermsN, SizeN}, MonitorCount} = @@ -353,8 +645,8 @@ bulk_sendsend2(Terms, BinSize, BusyBufSize) -> {sendersender, BigRes} -> BigRes end, - stop_node(NodeRecv), - stop_node(NodeSend), + peer_stop(RecvPeer, NodeRecv), + peer_stop(SendPeer, NodeSend), {round(SizeN/1024/Elapsed), MonitorCount}. %% Sender process to be run on a slave node @@ -455,7 +747,7 @@ receiver2(Num, TotSize) -> %% Test that link/1 to a busy distribution port works. link_to_busy(Config) when is_list(Config) -> ct:timetrap({seconds, 60}), - {ok, Node} = start_node(link_to_busy), + {ok, Peer, Node} = ?CT_PEER(), Recv = spawn(Node, erlang, apply, [fun sink/1, [link_to_busy_sink]]), Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of @@ -481,7 +773,7 @@ link_to_busy(Config) when is_list(Config) -> do_busy_test(Node, fun () -> tail_applied_linker(Recv) end), %% Done. - stop_node(Node), + peer_stop(Peer, Node), stop_busy_dist_port_tracer(Tracer), ok. @@ -501,7 +793,7 @@ tail_applied_linker(Pid) -> %% Test that exit/2 to a busy distribution port works. exit_to_busy(Config) when is_list(Config) -> ct:timetrap({seconds, 60}), - {ok, Node} = start_node(exit_to_busy), + {ok, Peer, Node} = ?CT_PEER(), Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of "true" -> start_busy_dist_port_tracer(); @@ -551,7 +843,7 @@ exit_to_busy(Config) when is_list(Config) -> end, %% Done. - stop_node(Node), + peer_stop(Peer, Node), stop_busy_dist_port_tracer(Tracer), ok. @@ -585,9 +877,12 @@ make_busy(Node, Time) when is_integer(Time) -> receive after Own -> ok end, until(fun () -> case {DCtrl, process_info(Pid, status)} of - {DPrt, {status, suspended}} when is_port(DPrt) -> true; - {DPid, {status, waiting}} when is_pid(DPid) -> true; - _ -> false + {DPrt, {status, waiting}} when is_port(DPrt) -> + verify_busy(DPrt); + {DPid, {status, waiting}} when is_pid(DPid) -> + true; + _ -> + false end end), %% then dist entry @@ -604,6 +899,28 @@ unmake_busy(Pid) -> unlink(Pid), exit(Pid, bang). +verify_busy(Port) -> + Parent = self(), + Pid = + spawn_link( + fun() -> + port_command(Port, "Just some data"), + Error = {not_busy, Port}, + exit(Parent, Error), + error(Error) + end), + receive after 30 -> ok end, + case process_info(Pid, status) of + {status, suspended} -> + unlink(Pid), + exit(Pid, kill), + true; + {status, _} = WrongStatus -> + unlink(Pid), + exit(Pid, WrongStatus), + error(WrongStatus) + end. + do_busy_test(Node, Fun) -> Busy = make_busy(Node, 1000), {P, M} = spawn_monitor(Fun), @@ -670,7 +987,7 @@ sink1() -> %% Test that EXIT and DOWN messages send to another node are not lost if %% the distribution port is busy. lost_exit(Config) when is_list(Config) -> - {ok, Node} = start_node(lost_exit), + {ok, Peer, Node} = ?CT_PEER(), Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of "true" -> start_busy_dist_port_tracer(); @@ -723,7 +1040,7 @@ lost_exit(Config) when is_list(Config) -> %% Done. stop_busy_dist_port_tracer(Tracer), - stop_node(Node), + peer_stop(Peer, Node), ok. dummy_waiter() -> @@ -736,9 +1053,7 @@ dummy_waiter() -> %% AND that the link is teared down. link_to_dead(Config) when is_list(Config) -> process_flag(trap_exit, true), - {ok, Node} = start_node(link_to_dead), - % monitor_node(Node, true), - net_adm:ping(Node), %% Ts_cross_server workaround. + {ok, Peer, Node} = ?CT_PEER(), Pid = spawn(Node, ?MODULE, dead_process, []), receive after 5000 -> ok @@ -755,13 +1070,14 @@ link_to_dead(Config) when is_list(Config) -> {links, Links} = process_info(self(), links), io:format("Pid=~p, links=~p", [Pid, Links]), false = lists:member(Pid, Links), - stop_node(Node), receive Message -> ct:fail({unexpected_message, Message}) after 3000 -> ok end, + process_flag(trap_exit, false), + peer_stop(Peer, Node), ok. dead_process() -> @@ -773,18 +1089,24 @@ link_to_dead_new_node(Config) when is_list(Config) -> process_flag(trap_exit, true), %% Start the node, get a Pid and stop the node again. - {ok, Node} = start_node(link_to_dead_new_node), + Name = ?CT_PEER_NAME(?FUNCTION_NAME), + {ok, Peer, Node} = ?CT_PEER(#{name => Name}), Pid = spawn(Node, ?MODULE, dead_process, []), - stop_node(Node), + + peer_stop(Peer, Node), + %% since exits are trapped, need to catch exiting peer + receive {'EXIT', Peer, normal} -> ok end, %% Start a new node with the same name. - {ok, Node} = start_node(link_to_dead_new_node), + {ok, Peer2, Node} = ?CT_PEER(#{name => Name}), link(Pid), + receive {'EXIT', Pid, noproc} -> ok; Other -> - stop_node(Node), + process_flag(trap_exit, false), + peer_stop(Peer2, Node), ct:fail({unexpected_message, Other}) after 5000 -> ct:fail(nothing_received) @@ -794,13 +1116,16 @@ link_to_dead_new_node(Config) when is_list(Config) -> {links, Links} = process_info(self(), links), io:format("Pid=~p, links=~p", [Pid, Links]), false = lists:member(Pid, Links), - stop_node(Node), receive Message -> + process_flag(trap_exit, false), ct:fail({unexpected_message, Message}) after 3000 -> ok end, + %% stop trapping exits, and let the peer stop + process_flag(trap_exit, false), + peer_stop(Peer2, Node), ok. %% Test that sending a port or reference to another node and back again @@ -809,13 +1134,13 @@ ref_port_roundtrip(Config) when is_list(Config) -> process_flag(trap_exit, true), Port = make_port(), Ref = make_ref(), - {ok, Node} = start_node(ref_port_roundtrip), + {ok, Peer, Node} = ?CT_PEER(), net_adm:ping(Node), Term = {Port, Ref}, io:format("Term before: ~p", [show_term(Term)]), Pid = spawn_link(Node, ?MODULE, roundtrip, [Term]), receive after 5000 -> ok end, - stop_node(Node), + peer_stop(Peer, Node), receive {'EXIT', Pid, {Port, Ref}} -> io:format("Term after: ~p", [show_term(Term)]), @@ -838,7 +1163,7 @@ roundtrip(Term) -> %% another node node and back again. nil_roundtrip(Config) when is_list(Config) -> process_flag(trap_exit, true), - {ok, Node} = start_node(nil_roundtrip), + {ok, Peer, Node} = ?CT_PEER(), net_adm:ping(Node), Pid = spawn_link(Node, ?MODULE, bounce, [self()]), Pid ! [], @@ -846,7 +1171,7 @@ nil_roundtrip(Config) when is_list(Config) -> [] -> receive {'EXIT', Pid, []} -> - stop_node(Node), + peer_stop(Peer, Node), ok end end. @@ -866,9 +1191,9 @@ stop_dist(Config) when is_list(Config) -> ++ " -noshell -pa " ++ proplists:get_value(data_dir, Config) ++ " -s run"), - %% The "true" may be followed by an error report, so ignore anything that - %% follows it. - "true\n"++_ = Str, + %% The "true" may be followed or prepended by an error report + Lines = string:lexemes(Str, "\n"), + true = lists:member("true", Lines), %% "May fail on FreeBSD due to differently configured name lookup - ask Arndt", %% if you can find him. @@ -906,7 +1231,7 @@ tr3() -> -% This has to be done by nodes with differrent cookies, otherwise global +% This has to be done by nodes with different cookies, otherwise global % will connect nodes, which is correct, but makes it hard to test. % * Start two nodes, n1 and n2. n2 with the dist_auto_connect once parameter % * n2 pings n1 -> connection @@ -919,178 +1244,66 @@ tr3() -> % * n2 now also gets pong when pinging n1 % * disconnect n2 from n1 % * n2 gets pang when pinging n1 -% * n2 forces connection by using net_kernel:connect_node (ovverrides) +% * n2 forces connection by using net_kernel:connect_node (overrides) % * n2 gets pong when pinging n1. %% Test the dist_auto_connect once kernel parameter dist_auto_connect_once(Config) when is_list(Config) -> - Sock = start_relay_node(dist_auto_connect_relay_node,[]), - NN = inet_rpc_nodename(Sock), - Sock2 = start_relay_node(dist_auto_connect_once_node, - "-kernel dist_auto_connect once"), - NN2 = inet_rpc_nodename(Sock2), - {ok,[]} = do_inet_rpc(Sock,erlang,nodes,[]), - {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), - {ok,[NN2]} = do_inet_rpc(Sock,erlang,nodes,[]), - {ok,[NN]} = do_inet_rpc(Sock2,erlang,nodes,[]), - [_,HostPartPeer] = string:lexemes(atom_to_list(NN),"@"), - [_,MyHostPart] = string:lexemes(atom_to_list(node()),"@"), + {ok, PN, NN} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"]}), + {ok, PN2, NN2} = ?CT_PEER(#{connection => 0, + args => ["-setcookie", "NONE", "-kernel", "dist_auto_connect", "once"]}), + [] = peer:call(PN,erlang,nodes,[]), + pong = peer:call(PN2,net_adm,ping,[NN]), + [NN2] = peer:call(PN,erlang,nodes,[]), + [NN] = peer:call(PN2,erlang,nodes,[]), % Give net_kernel a chance to change the state of the node to up to. receive after 1000 -> ok end, - case HostPartPeer of - MyHostPart -> - ok = stop_relay_node(Sock), - {ok,pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]); - _ -> - {ok, true} = do_inet_rpc(Sock,net_kernel,disconnect,[NN2]), - receive - after 500 -> ok - end - end, - {ok, []} = do_inet_rpc(Sock2,erlang,nodes,[]), - Sock3 = case HostPartPeer of - MyHostPart -> - start_relay_node(dist_auto_connect_relay_node,[]); - _ -> - Sock - end, + ok = peer:stop(PN), + pang = peer:call(PN2,net_adm,ping,[NN]), + [] = peer:call(PN2,erlang,nodes,[]), + %% restart NN node + {ok, PN3, NN} = ?CT_PEER(#{connection => 0, args => ["-setcookie", "NONE"], + name => hd(string:lexemes(atom_to_list(NN), "@"))}), TS1 = timestamp(), - {ok, pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]), + pang = peer:call(PN2,net_adm,ping,[NN]), TS2 = timestamp(), RefT = net_kernel:connecttime() - 1000, true = ((TS2 - TS1) < RefT), TS3 = timestamp(), - {ok, true} = do_inet_rpc(Sock2,erlang,monitor_node, - [NN,true,[allow_passive_connect]]), + true = peer:call(PN2,erlang,monitor_node, + [NN,true,[allow_passive_connect]], 60000), TS4 = timestamp(), true = ((TS4 - TS3) > RefT), - {ok, pong} = do_inet_rpc(Sock3,net_adm,ping,[NN2]), - {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), - {ok, true} = do_inet_rpc(Sock3,net_kernel,disconnect,[NN2]), + pong = peer:call(PN3,net_adm,ping,[NN2]), + pong = peer:call(PN2,net_adm,ping,[NN]), + true = peer:call(PN3,net_kernel,disconnect,[NN2]), receive after 500 -> ok end, - {ok, pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]), - {ok, true} = do_inet_rpc(Sock2,net_kernel,connect_node,[NN]), - {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), - stop_relay_node(Sock3), - stop_relay_node(Sock2). + pang = peer:call(PN2,net_adm,ping,[NN]), + true = peer:call(PN2,net_kernel,connect_node,[NN]), + pong = peer:call(PN2,net_adm,ping,[NN]), + peer:stop(PN3), + peer:stop(PN2). -%% Start a relay node and a lonely (dist_auto_connect never) node. -%% Lonely node pings relay node. That should fail. -%% Lonely node connects to relay node with net_kernel:connect_node/1. -%% Result is sent here through relay node. +%% Spawn dist_auto_connect never node, ensure it won't +%% connect to the origin with net_adm:ping(), but will with +%% explicit net_kernel:connect_node. dist_auto_connect_never(Config) when is_list(Config) -> - Self = self(), - {ok, RelayNode} = start_node(dist_auto_connect_relay), - spawn(RelayNode, - fun() -> - register(dist_auto_connect_relay, self()), - dist_auto_connect_relay(Self) - end), - {ok, Handle} = dist_auto_connect_start(dist_auto_connect, never), - Result = receive - {do_dist_auto_connect, ok} -> - ok; - {do_dist_auto_connect, Error} -> - {error, Error}; - %% The io:formats in dos_dist_auto_connect will - %% generate port output messages that are ok - Other when not is_port(element(1, Other))-> - {error, Other} - after 32000 -> - timeout - end, - stop_node(RelayNode), - Stopped = dist_auto_connect_stop(Handle), - Junk = receive - {do_dist_auto_connect, _} = J -> J - after 0 -> ok - end, - {ok, ok, ok} = {Result, Stopped, Junk}, + {ok, LonelyPeer, Node} = ?CT_PEER(#{connection => 0, args => ["-kernel", "dist_auto_connect", "never"]}), + pang = peer:call(LonelyPeer, net_adm, ping, [node()]), + false = lists:member(Node, nodes()), + true = peer:call(LonelyPeer, net_kernel, connect_node, [node()]), + true = lists:member(Node, nodes()), + peer:stop(LonelyPeer), ok. - -do_dist_auto_connect([never]) -> - Node = list_to_atom("dist_auto_connect_relay@" ++ hostname()), - io:format("~p:do_dist_auto_connect([false]) Node=~p~n", [?MODULE, Node]), - Ping = net_adm:ping(Node), - io:format("~p:do_dist_auto_connect([false]) Ping=~p~n", [?MODULE, Ping]), - Result = case Ping of - pang -> ok; - _ -> {error, Ping} - end, - io:format("~p:do_dist_auto_connect([false]) Result=~p~n", [?MODULE, Result]), - net_kernel:connect_node(Node), - catch {dist_auto_connect_relay, Node} ! {do_dist_auto_connect, Result}; -% receive after 1000 -> ok end, -% halt(); - -do_dist_auto_connect(Arg) -> - io:format("~p:do_dist_auto_connect(~p)~n", [?MODULE, Arg]), - receive after 10000 -> ok end, - halt(). - - -dist_auto_connect_start(Name, Value) when is_atom(Name) -> - dist_auto_connect_start(atom_to_list(Name), Value); -dist_auto_connect_start(Name, Value) when is_list(Name), is_atom(Value) -> - Node = list_to_atom(lists:append([Name, "@", hostname()])), - ModuleDir = filename:dirname(code:which(?MODULE)), - ValueStr = atom_to_list(Value), - Cookie = atom_to_list(erlang:get_cookie()), - Cmd = lists:append( - [%"xterm -e ", - ct:get_progname(), - % " -noinput ", - " -detached ", - long_or_short(), " ", Name, - " -setcookie ", Cookie, - " -pa ", ModuleDir, - " -s ", atom_to_list(?MODULE), - " do_dist_auto_connect ", ValueStr, - " -kernel dist_auto_connect ", ValueStr]), - io:format("~p:dist_auto_connect_start() cmd: ~p~n", [?MODULE, Cmd]), - Port = open_port({spawn, Cmd}, [stream]), - {ok, {Port, Node}}. - - -dist_auto_connect_stop({Port, Node}) -> - Pid = spawn_link(fun() -> rpc:call(Node, erlang, halt, []) end), - dist_auto_connect_stop(Port, Node, Pid, 5000). - -dist_auto_connect_stop(Port, _Node, Pid, N) when is_integer(N), N =< 0 -> - exit(Pid, normal), - catch erlang:port_close(Port), - Result = {error, node_not_down}, - io:format("~p:dist_auto_connect_stop() ~p~n", [?MODULE, Result]), - Result; -dist_auto_connect_stop(Port, Node, Pid, N) when is_integer(N) -> - case net_adm:ping(Node) of - pong -> - receive after 100 -> ok end, - dist_auto_connect_stop(Port, Node, Pid, N-100); - pang -> - exit(Pid, normal), - catch erlang:port_close(Port), - io:format("~p:dist_auto_connect_stop() ok~n", [?MODULE]), - ok - end. - - -dist_auto_connect_relay(Parent) -> - receive X -> - catch Parent ! X - end, - dist_auto_connect_relay(Parent). - - dist_parallel_send(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, RNode} = start_node(dist_parallel_receiver, "-connect_all false"), - {ok, SNode} = start_node(dist_parallel_sender, "-connect_all false"), + {ok, RPeer, RNode} = ?CT_PEER(["-connect_all", "false"]), + {ok, SPeer, SNode} = ?CT_PEER(["-connect_all", "false"]), %% WatchDog = spawn_link( %% fun () -> @@ -1150,8 +1363,8 @@ dist_parallel_send(Config) when is_list(Config) -> %% unlink(WatchDog), %% exit(WatchDog, bang), - stop_node(RNode), - stop_node(SNode), + peer_stop(RPeer, RNode), + peer_stop(SPeer, SNode), ok. @@ -1177,17 +1390,17 @@ dist_evil_parallel_receiver() -> atom_roundtrip(Config) when is_list(Config) -> AtomData = atom_data(), verify_atom_data(AtomData), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), do_atom_roundtrip(Node, AtomData), - stop_node(Node), + peer_stop(Peer, Node), ok. unicode_atom_roundtrip(Config) when is_list(Config) -> AtomData = unicode_atom_data(), verify_atom_data(AtomData), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), do_atom_roundtrip(Node, AtomData), - stop_node(Node), + peer_stop(Peer, Node), ok. do_atom_roundtrip(Node, AtomData) -> @@ -1283,17 +1496,17 @@ unicode_atom_data() -> end, lists:seq(1, 2000))]. contended_atom_cache_entry(Config) when is_list(Config) -> - contended_atom_cache_entry_test(Config, latin1). + contended_atom_cache_entry_test(latin1). contended_unicode_atom_cache_entry(Config) when is_list(Config) -> - contended_atom_cache_entry_test(Config, unicode). + contended_atom_cache_entry_test(unicode). -contended_atom_cache_entry_test(Config, Type) -> +contended_atom_cache_entry_test(Type) -> TestServer = self(), ProcessPairs = 10, Msgs = 100000, - {ok, SNode} = start_node(Config), - {ok, RNode} = start_node(Config), + {ok, SPeer, SNode} = ?CT_PEER(), + {ok, RPeer, RNode} = ?CT_PEER(), Success = make_ref(), spawn_link( SNode, @@ -1355,8 +1568,8 @@ contended_atom_cache_entry_test(Config, Type) -> Success -> ok end, - stop_node(SNode), - stop_node(RNode), + peer_stop(SPeer, SNode), + peer_stop(RPeer, RNode), ok. send_ref_atom(_To, _Ref, _Atom, 0) -> @@ -1431,15 +1644,15 @@ get_conflicting_unicode_atoms(CIX, N) -> %% they no longer fail when the latency is incorrect. However, they are %% kept as they continue to find bugs in the distribution implementation. message_latency_large_message(Config) when is_list(Config) -> - measure_latency_large_message(?FUNCTION_NAME, fun(Dropper, Payload) -> Dropper ! Payload end). + measure_latency_large_message(fun(Dropper, Payload) -> Dropper ! Payload end). message_latency_large_exit2(Config) when is_list(Config) -> - measure_latency_large_message(?FUNCTION_NAME, fun erlang:exit/2). + measure_latency_large_message(fun erlang:exit/2). message_latency_large_link_exit(Config) when is_list(Config) -> - message_latency_large_exit(?FUNCTION_NAME, fun erlang:link/1). + message_latency_large_exit(fun erlang:link/1). message_latency_large_monitor_exit(Config) when is_list(Config) -> - message_latency_large_exit(?FUNCTION_NAME, + message_latency_large_exit( fun(Dropper) -> Dropper ! {monitor, self()}, receive ok -> ok end @@ -1454,9 +1667,8 @@ message_latency_large_link_exit() -> message_latency_large_monitor_exit() -> message_latency_large_message(). -message_latency_large_exit(Nodename, ReasonFun) -> +message_latency_large_exit(ReasonFun) -> measure_latency_large_message( - Nodename, fun(Dropper, Payload) -> Pid = spawn(fun() -> receive go -> ok end, @@ -1481,11 +1693,11 @@ message_latency_large_exit(Nodename, ReasonFun) -> end end). -measure_latency_large_message(Nodename, DataFun) -> +measure_latency_large_message(DataFun) -> erlang:system_monitor(self(), [busy_dist_port]), - {ok, N} = start_node(Nodename), + {ok, Peer, N} = ?CT_PEER(), Dropper = spawn(N, fun F() -> process_flag(trap_exit, true), @@ -1519,7 +1731,7 @@ measure_latency_large_message(Nodename, DataFun) -> ct:pal("~p",[IndexTimes]), - stop_node(N), + peer_stop(Peer, N), case {lists:max(Times), lists:min(Times)} of {Max, Min} when Max * 0.25 > Min, BuildType =:= opt -> @@ -1534,8 +1746,6 @@ measure_latency_large_message(Nodename, DataFun) -> measure_latency(DataFun, Dropper, Echo, Payload) -> - TCProc = self(), - flush(), Senders = [spawn_monitor( @@ -1595,8 +1805,10 @@ flush() -> system_limit(Config) when is_list(Config) -> case erlang:system_info(wordsize) of 8 -> - case proplists:get_value(system_total_memory, - memsup:get_system_memory_data()) of + SMD = memsup:get_system_memory_data(), + case proplists:get_value( + available_memory, SMD, + proplists:get_value(system_total_memory, SMD)) of Memory when is_integer(Memory), Memory > 6*1024*1024*1024 -> test_system_limit(Config), @@ -1613,7 +1825,7 @@ test_system_limit(Config) when is_list(Config) -> Bits = ((1 bsl 32)+1)*8, HugeBin = <<0:Bits>>, HugeListBin = [lists:duplicate(2000000,2000000), HugeBin], - {ok, N1} = start_node(Config), + {ok, _Peer1, N1} = ?CT_PEER(), monitor_node(N1, true), receive {nodedown, N1} -> @@ -1686,7 +1898,7 @@ test_system_limit(Config) when is_list(Config) -> end), receive {nodedown, N1} -> ok end, - {ok, N2} = start_node(Config), + {ok, _Peer2, N2} = ?CT_PEER(), monitor_node(N2, true), P2 = spawn(N2, fun () -> @@ -1699,7 +1911,7 @@ test_system_limit(Config) when is_list(Config) -> receive {nodedown, N2} -> ok end, io:format("~n** distributed monitor down **~n~n", []), - {ok, N3} = start_node(Config), + {ok, _Peer3, N3} = ?CT_PEER(), monitor_node(N3, true), Go1 = make_ref(), LP1 = spawn(fun () -> @@ -1714,7 +1926,7 @@ test_system_limit(Config) when is_list(Config) -> end), receive {nodedown, N3} -> ok end, - {ok, N4} = start_node(Config), + {ok, _Peer4, N4} = ?CT_PEER(), monitor_node(N4, true), Go2 = make_ref(), LP2 = spawn(fun () -> @@ -1800,8 +2012,8 @@ bad_dist_structure(Config) when is_list(Config) -> ct:timetrap({seconds, 15}), %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_structure_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_structure_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), Parent = self(), P = spawn(Victim, @@ -1887,8 +2099,8 @@ bad_dist_structure(Config) when is_list(Config) -> unlink(P), P ! done, - stop_node(Offender), - stop_node(Victim), + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim), ok. %% Test various dist fragmentation errors @@ -1896,8 +2108,8 @@ bad_dist_fragments(Config) when is_list(Config) -> ct:timetrap({seconds, 15}), %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_fragment_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_fragment_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), Msg = iolist_to_binary(dmsg_ext(lists:duplicate(255,255))), @@ -1990,8 +2202,8 @@ bad_dist_fragments(Config) when is_list(Config) -> unlink(P), P ! done, - stop_node(Offender), - stop_node(Victim), + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim), ok. dmsg_frag_hdr(Frag) -> @@ -2052,8 +2264,8 @@ send_bad_fragments(Offender,VictimNode,Victim,Ctrl,WhereToPutSelf,Fragments) -> bad_dist_ext_receive(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_ext_receive_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_ext_receive_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), Parent = self(), @@ -2119,14 +2331,14 @@ bad_dist_ext_receive(Config) when is_list(Config) -> P ! done, unlink(P), verify_no_down(Offender, Victim), - stop_node(Offender), - stop_node(Victim). + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim). bad_dist_ext_process_info(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_ext_process_info_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_ext_process_info_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), Parent = self(), @@ -2181,13 +2393,13 @@ bad_dist_ext_process_info(Config) when is_list(Config) -> P ! done, unlink(P), verify_no_down(Offender, Victim), - stop_node(Offender), - stop_node(Victim). + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim). bad_dist_ext_control(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_ext_control_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_ext_control_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), pong = rpc:call(Victim, net_adm, ping, [Offender]), @@ -2201,13 +2413,13 @@ bad_dist_ext_control(Config) when is_list(Config) -> verify_down(Offender, connection_closed, Victim, killed), verify_no_down(Offender, Victim), - stop_node(Offender), - stop_node(Victim). + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim). bad_dist_ext_connection_id(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_ext_connection_id_offender, "-connect_all false"), - {ok, Victim} = start_node(bad_dist_ext_connection_id_victim, "-connect_all false"), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), Parent = self(), @@ -2268,16 +2480,14 @@ bad_dist_ext_connection_id(Config) when is_list(Config) -> P ! done, unlink(P), verify_no_down(Offender, Victim), - stop_node(Offender), - stop_node(Victim). + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim). %% OTP-14661: Bad message is discovered by erts_msg_attached_data_size bad_dist_ext_size(Config) when is_list(Config) -> %% Disabled "connect all" so global wont interfere... - {ok, Offender} = start_node(bad_dist_ext_process_info_offender, "-connect_all false"), - %%Prog = "Prog=/home/uabseri/src/otp_new3/bin/cerl -rr -debug", - Prog = [], - {ok, Victim} = start_node(bad_dist_ext_process_info_victim, "-connect_all false", Prog), + {ok, OffenderPeer, Offender} = ?CT_PEER(["-connect_all", "false"]), + {ok, VictimPeer, Victim} = ?CT_PEER(["-connect_all", "false"]), start_node_monitors([Offender,Victim]), Parent = self(), @@ -2324,8 +2534,8 @@ bad_dist_ext_size(Config) when is_list(Config) -> unlink(P), verify_no_down(Offender, Victim), - stop_node(Offender), - stop_node(Victim). + peer_stop(OffenderPeer, Offender), + peer_stop(VictimPeer, Victim). bad_dist_struct_check_msgs([]) -> @@ -2368,7 +2578,19 @@ ensure_dctrl(Node) -> end. dctrl_send(DPrt, Data) when is_port(DPrt) -> - port_command(DPrt, Data); + try prim_inet:send(DPrt, Data) of + ok -> + ok; + Result -> + io:format("~w/2: ~p~n", [?FUNCTION_NAME, Result]), + Result + catch + Class: Reason: Stacktrace -> + io:format( + "~w/2: ~p: ~p: ~p ~n", + [?FUNCTION_NAME, Class, Reason, Stacktrace]), + erlang:raise(Class, Reason, Stacktrace) + end; dctrl_send(DPid, Data) when is_pid(DPid) -> Ref = make_ref(), DPid ! {send, self(), Ref, Data}, @@ -2470,7 +2692,7 @@ send_bad_ctl(BadNode, ToNode) when is_atom(BadNode), is_atom(ToNode) -> spawn_link(BadNode, fun () -> pong = net_adm:ping(ToNode), - %% We creat a valid ctl msg and replace an + %% We create a valid ctl msg and replace an %% atom with an invalid atom cache reference <<131,Replace/binary>> = term_to_binary(replace), Ctl = dmsg_ext({?DOP_REG_SEND, @@ -2527,7 +2749,7 @@ set_internal_state(Op, Val) -> dmsg_hdr() -> [131, % Version Magic $D, % Dist header - 0]. % No atom cache referenses + 0]. % No atom cache references dmsg_bad_hdr() -> [131, % Version Magic @@ -2569,7 +2791,7 @@ dmsg_bad_tag() -> %% Will fail early at heap size calculation %% We also make sure that the binary memory of the receiving node does not grow %% without shrinking back as there used to be a memory leak on the receiving side. exit_dist_fragments(_Config) -> - {ok, Node} = start_node(?FUNCTION_NAME), + {ok, Peer, Node} = ?CT_PEER(), try ct:log("Allocations before:~n~p",[erpc:call(Node,instrument,allocations, [])]), {BinInfo, BinInfoMref} = @@ -2589,6 +2811,7 @@ exit_dist_fragments(_Config) -> end)([]) end), {Tracer, Mref} = spawn_monitor(fun gather_exited/0), + link(Tracer), %% Make sure Tracer dies if we die erlang:trace(self(), true, [{tracer, Tracer}, set_on_spawn, procs, exiting]), exit_suspend(Node), receive @@ -2617,7 +2840,7 @@ exit_dist_fragments(_Config) -> end end after - stop_node(Node) + peer:stop(Peer) end. %% Make sure that each spawned process also has exited @@ -2627,15 +2850,17 @@ gather_exited() -> gather_exited(Pids) -> receive {trace,Pid,spawned,_,_} -> - gather_exited(Pids#{ Pid => true }); - {trace,Pid,exited_out,_,_} -> + gather_exited(maps:update_with(spawned, fun(V) -> V + 1 end, 0, Pids#{ Pid => true })); + {trace,Pid,out_exited,_} -> {true, NewPids} = maps:take(Pid, Pids), - gather_exited(NewPids); - _M -> - gather_exited(Pids) + gather_exited(maps:update_with(out_exited, fun(V) -> V + 1 end, 0, NewPids)); + Trace -> + gather_exited(maps:update_with(element(3, Trace), fun(V) -> V + 1 end, 0, Pids)) after 1000 -> - if Pids == #{} -> ok; - true -> exit(Pids) + MissingPids = maps:size(maps:filter(fun(Key,_) -> not erlang:is_atom(Key) end, Pids)), + if MissingPids =:= 0 -> ok; + true -> exit({[{Pid,erlang:process_info(Pid)} || Pid <- MissingPids], + maps:filter(fun(Key,_) -> erlang:is_atom(Key) end, Pids)}) end end. @@ -2661,8 +2886,8 @@ exit_suspend(RemoteNode, N, Payload) -> fun() -> false = process_flag(trap_exit, true), RemotePid = spawn_link(RemoteNode, Echo), - Iterations = case erlang:system_info(debug_compiled) of - false -> + Iterations = case erlang:system_info(emu_type) of + opt -> 100; _ -> 10 @@ -2727,49 +2952,54 @@ exit_suspend_loop(LocalPid, RemotePid, Suspenders, Payload, N) -> start_epmd_false(Config) when is_list(Config) -> %% Start a node with the option -start_epmd false. - {ok, OtherNode} = start_node(start_epmd_false, "-start_epmd false"), + {ok, Peer, OtherNode} = ?CT_PEER(["-start_epmd", "false"]), %% We should be able to ping it, as epmd was started by us: pong = net_adm:ping(OtherNode), - stop_node(OtherNode), + peer_stop(Peer,OtherNode), ok. no_epmd(Config) when is_list(Config) -> %% Trying to start a node with -no_epmd but without passing the %% --proto_dist option should fail. - {error, timeout} = start_node(no_epmd, "-no_epmd"). + try + ?CT_PEER(#{connection => standard_io, args => ["-no_epmd"]}), + ct:fail(unexpected_no_epmd_start) + catch + exit:{boot_failed, {exit_status, 1}} -> + ok + end. epmd_module(Config) when is_list(Config) -> %% We need a relay node to test this, since the test node uses the %% standard epmd module. - {N1,_,S1} = Sock1 = start_relay_node( - epmd_module_node1, - "-epmd_module " ++ ?MODULE_STRING, - [{"ERL_AFLAGS","-sname epmd_module_node1@dummy " ++ os:getenv("ERL_AFLAGS","")}]), - Node1 = inet_rpc_nodename({N1,"dummy",S1}), - %% Ask what port it's listening on - it won't have registered with - %% epmd. - {ok, {ok, Port1}} = do_inet_rpc(Sock1, application, get_env, [kernel, dist_listen_port]), - - %% Start a second node, passing the port number as a secret - %% argument. - {N2,_,S2} = Sock2 = start_relay_node( - epmd_module_node2, - "-epmd_module " ++ ?MODULE_STRING - ++ " -other_node_port " ++ integer_to_list(Port1), - [{"ERL_AFLAGS","-sname epmd_module_node2@dummy " ++ os:getenv("ERL_AFLAGS","")}]), - Node2 = inet_rpc_nodename({N2,"dummy",S2}), + {ok, Peer1, Node1} = ?CT_PEER( + #{connection => 0, + name => "epmd_module_node1", + host => "dummy", + args => ["-setcookie", "NONE", "-epmd_module", ?MODULE_STRING]}), + %% Ask what port it's listening on - it won't have registered with epmd. + {ok, Port1} = peer:call(Peer1, application, get_env, [kernel, dist_listen_port]), + + %% Start a second node, passing the port number as a secret argument. + {ok, Peer2, Node2} = ?CT_PEER( + #{connection => 0, + name => "epmd_module_node2", + host => "dummy", + args => ["-setcookie", "NONE", "-epmd_module", ?MODULE_STRING, + "-other_node_port", integer_to_list(Port1)]}), + %% Node 1 can't ping node 2 - {ok, pang} = do_inet_rpc(Sock1, net_adm, ping, [Node2]), - {ok, []} = do_inet_rpc(Sock1, erlang, nodes, []), - {ok, []} = do_inet_rpc(Sock2, erlang, nodes, []), + pang = peer:call(Peer1, net_adm, ping, [Node2]), + [] = peer:call(Peer1, erlang, nodes, []), + [] = peer:call(Peer2, erlang, nodes, []), %% But node 2 can ping node 1 - {ok, pong} = do_inet_rpc(Sock2, net_adm, ping, [Node1]), - {ok, [Node2]} = do_inet_rpc(Sock1, erlang, nodes, []), - {ok, [Node1]} = do_inet_rpc(Sock2, erlang, nodes, []), + pong = peer:call(Peer2, net_adm, ping, [Node1]), + [Node2] = peer:call(Peer1, erlang, nodes, []), + [Node1] = peer:call(Peer2, erlang, nodes, []), - stop_relay_node(Sock2), - stop_relay_node(Sock1). + peer:stop(Peer2), + peer:stop(Peer1). %% epmd_module functions: @@ -2805,42 +3035,22 @@ address_please(_Name, "dummy", inet6) -> {ok, {0,0,0,0,0,0,0,1}}. hopefull_data_encoding(Config) when is_list(Config) -> - - FallbackCombos = [A bor B || A <- [0, ?DFLAG_EXPORT_PTR_TAG], - B <- [0, ?DFLAG_BIT_BINARIES]], - - [hopefull_data_encoding_do(FB) || FB <- FallbackCombos], - ok. - - -hopefull_data_encoding_do(Fallback) -> - io:format("Fallback = 16#~.16B\n", [Fallback]), - MkHopefullData = fun(Ref,Pid) -> mk_hopefull_data(Ref,Pid) end, - test_hopefull_data_encoding(Fallback, MkHopefullData), + test_hopefull_data_encoding(MkHopefullData), %% Test funs with hopefully encoded term in environment MkBitstringInFunEnv = fun(_,_) -> [mk_fun_with_env(<<5:7>>)] end, - test_hopefull_data_encoding(Fallback, MkBitstringInFunEnv), + test_hopefull_data_encoding(MkBitstringInFunEnv), MkExpFunInFunEnv = fun(_,_) -> [mk_fun_with_env(fun a:a/0)] end, - test_hopefull_data_encoding(Fallback, MkExpFunInFunEnv), + test_hopefull_data_encoding(MkExpFunInFunEnv), ok. mk_fun_with_env(Term) -> fun() -> Term end. -test_hopefull_data_encoding(Fallback, MkDataFun) -> - {ok, ProxyNode} = start_node(hopefull_data_normal), - {ok, BouncerNode} = start_node(hopefull_data_bouncer, "-hidden"), - case Fallback of - 0 -> - ok; - _ -> - rpc:call(BouncerNode, erts_debug, set_internal_state, - [available_internal_state, true]), - ok = rpc:call(BouncerNode, erts_debug, set_internal_state, - [remove_hopefull_dflags, Fallback]) - end, +test_hopefull_data_encoding(MkDataFun) -> + {ok, PeerProxy, ProxyNode} = ?CT_PEER(), + {ok, PeerBouncer, BouncerNode} = ?CT_PEER(["-hidden"]), Tester = self(), R1 = make_ref(), R2 = make_ref(), @@ -2870,28 +3080,18 @@ test_hopefull_data_encoding(Fallback, MkDataFun) -> end, receive [R2, HData2] -> - case Fallback of - 0 -> - HData = HData2; - _ -> - check_hopefull_fallback_data(HData, HData2, Fallback) - end + HData = HData2 end, receive [R3, HData3] -> - case Fallback of - 0 -> - HData = HData3; - _ -> - check_hopefull_fallback_data(HData, HData3, Fallback) - end + HData = HData3 end, unlink(Proxy), exit(Proxy, bye), unlink(Bouncer), exit(Bouncer, bye), - stop_node(ProxyNode), - stop_node(BouncerNode), + peer_stop(PeerProxy, ProxyNode), + peer_stop(PeerBouncer, BouncerNode), ok. bounce_loop() -> @@ -2950,62 +3150,20 @@ mk_hopefull_data(BS) -> [NewBs] end, lists:seq(BSsz-32, BSsz-17))]). -check_hopefull_fallback_data([], [], _) -> - ok; -check_hopefull_fallback_data([X|Xs],[Y|Ys], FB) -> - chk_hopefull_fallback(X, Y, FB), - check_hopefull_fallback_data(Xs, Ys, FB). - -chk_hopefull_fallback(Binary, FallbackBinary, _) when is_binary(Binary) -> - Binary = FallbackBinary; -chk_hopefull_fallback([BitStr], [{Bin, BitSize}], FB) when is_bitstring(BitStr) -> - chk_hopefull_fallback(BitStr, {Bin, BitSize}, FB); -chk_hopefull_fallback(BitStr, {Bin, BitSize}, FB) when is_bitstring(BitStr) -> - true = ((FB band ?DFLAG_BIT_BINARIES) =/= 0), - true = is_binary(Bin), - true = is_integer(BitSize), - true = BitSize > 0, - true = BitSize < 8, - Hsz = size(Bin) - 1, - <> = Bin, - IBits = I bsr (8 - BitSize), - FallbackBitStr = list_to_bitstring([Head,<>]), - BitStr = FallbackBitStr, - ok; -chk_hopefull_fallback(Func, {ModName, FuncName}, FB) when is_function(Func) -> - true = ((FB band ?DFLAG_EXPORT_PTR_TAG) =/= 0), - {M, F, _} = erlang:fun_info_mfa(Func), - M = ModName, - F = FuncName, - ok; -chk_hopefull_fallback(Fun1, Fun2, FB) when is_function(Fun1), is_function(Fun2) -> - %% Recursive diff of funs with their environments - FI1 = erlang:fun_info(Fun1), - FI2 = erlang:fun_info(Fun2), - {env, E1} = lists:keyfind(env, 1, FI1), - {env, E2} = lists:keyfind(env, 1, FI1), - chk_hopefull_fallback(E1, E2, FB), - assert_same(lists:keydelete(env, 1, FI1), - lists:keydelete(env, 1, FI2)); -chk_hopefull_fallback(A, B, _) -> - ok = assert_same(A,B). - -assert_same(A,A) -> ok. - %% ERL-1254 hopefull_export_fun_bug(Config) when is_list(Config) -> Msg = [1, fun blipp:blapp/7, 2, fun blipp:blapp/7], {dummy, dummy@dummy} ! Msg. % Would crash on debug VM -huge_iovec(Config) -> +huge_iovec(Config) when is_list(Config) -> %% Make sure that we can pass a term that will produce %% an io-vector larger than IOV_MAX over the distribution... %% IOV_MAX is typically 1024. Currently we produce an %% element in the io-vector for all off heap binaries... NoBinaries = 1 bsl 14, BinarySize = 65, - {ok, Node} = start_node(huge_iovec), + {ok, Peer, Node} = ?CT_PEER(), P = spawn_link(Node, fun () -> receive {From, Data} -> @@ -3021,7 +3179,7 @@ huge_iovec(Config) -> P ! {self(), RBL}, receive {P, EchoedRBL} -> - stop_node(Node), + peer_stop(Peer, Node), RBL = EchoedRBL end, ok. @@ -3032,15 +3190,445 @@ mk_rand_bin_list(Bytes, Binaries) -> mk_rand_bin_list(_Bytes, 0, Acc) -> Acc; mk_rand_bin_list(Bytes, Binaries, Acc) -> - mk_rand_bin_list(Bytes, Binaries-1, [mk_rand_bin(Bytes) | Acc]). + mk_rand_bin_list(Bytes, Binaries-1, [rand:bytes(Bytes) | Acc]). + +%% Try provoke DistEntry refc bugs (OTP-17513). +dist_entry_refc_race(_Config) -> + {ok, Peer, Node} = ?CT_PEER(["+zdntgc", "1"]), + Pid = spawn_link(Node, ?MODULE, derr_run, [self()]), + {Pid, done} = receive M -> M end, + peer_stop(Peer, Node), + ok. + +derr_run(Papa) -> + inet_db:set_lookup([file]), % make connection attempt fail fast + NScheds = erlang:system_info(schedulers_online), + SeqList = lists:seq(1, 25 * NScheds), + Nodes = [list_to_atom("none@host" ++ integer_to_list(Seq)) + || Seq <- SeqList], + Self = self(), + Pids = [spawn_link(fun () -> derr_sender(Self, Nodes) end) + || _ <- SeqList], + derr_count(1, 8000), + [begin unlink(P), exit(P,kill) end || P <- Pids], + Papa ! {self(), done}, + ok. + +derr_count(Max, Max) -> + done; +derr_count(N, Max) -> + receive + count -> ok + end, + case N rem 1000 of + 0 -> + io:format("Total attempts: ~bk~n", [N div 1000]); + _ -> ok + end, + derr_count(N+1, Max). + + +derr_sender(Main, Nodes) -> + [{none, Node} ! msg || Node <- Nodes], + Main ! count, + derr_sender(Main, Nodes). + +is_alive(Config) when is_list(Config) -> + %% Test that distribution is up when erlang:is_alive() return true... + Args = ["-setcookie", atom_to_list(erlang:get_cookie()), + "-pa", filename:dirname(code:which(?MODULE))], + {ok, Peer, _} = peer:start_link(#{connection => 0, args => Args}), + NodeName = peer:random_name(), + LongNames = net_kernel:longnames(), + StartOpts = #{name_domain => if LongNames -> longnames; + true -> shortnames + end}, + ThisNode = node(), + TestFun = fun () -> is_alive_test(list_to_atom(NodeName), StartOpts, ThisNode) end, + ok = peer:call(Peer, erlang, apply, [TestFun, []]), + Node = list_to_atom(NodeName++"@"++hostname()), + true = lists:member(Node, nodes()), + peer:stop(Peer), + ok. + +is_alive_test(NodeName, StartOpts, TestNode) -> + try + monitor_node(TestNode, true), + error(unexpected_success) + catch + error:notalive -> + ok + end, + Me = self(), + {Pid, Mon} = spawn_monitor(fun () -> + Me ! {self(), go}, + is_alive_tester(TestNode), + Me ! {self(), ok} + end), + receive {Pid, go} -> ok end, + receive after 500 -> ok end, + _ = net_kernel:start(NodeName, StartOpts), + receive + {Pid, ok} -> erlang:demonitor(Mon, [flush]), ok; + {'DOWN', Mon, process, Pid, Reason} -> error(Reason) + end. + +is_alive_tester(Node) -> + case erlang:is_alive() of + false -> + is_alive_tester(Node); + true -> + monitor_node(Node, true), + wait_until(fun () -> lists:member(Node, nodes()) end), + ok + end. + +dyn_node_name_monitor_node(_Config) -> + %% Test that monitor_node() does not fail when erlang:is_alive() return true + %% but we have not yet gotten a name... + Args = ["-setcookie", atom_to_list(erlang:get_cookie()), + "-pa", filename:dirname(code:which(?MODULE))], + {ok, Peer, nonode@nohost} = peer:start_link(#{connection => 0, args => Args}), + [] = nodes(), + LongNames = net_kernel:longnames(), + StartOpts = #{name_domain => if LongNames -> longnames; + true -> shortnames + end}, + ThisNode = node(), + TestFun = fun () -> dyn_node_name_monitor_node_test(StartOpts, ThisNode) end, + ok = peer:call(Peer, erlang, apply, [TestFun, []]), + peer:stop(Peer), + ok. + +dyn_node_name_monitor_node_test(StartOpts, TestNode) -> + try + monitor_node(TestNode, true), + error(unexpected_success) + catch + error:notalive -> + ok + end, + _ = net_kernel:start(undefined, StartOpts), + true = erlang:is_alive(), + true = monitor_node(TestNode, true), + receive {nodedown, TestNode} -> ok end, + true = net_kernel:connect_node(TestNode), + true = monitor_node(TestNode, true), + true = lists:member(TestNode, nodes(hidden)), + receive {nodedown, TestNode} -> error(unexpected_nodedown) + after 1000 -> ok + end, + ok. + -mk_rand_bin(Bytes) -> - mk_rand_bin(Bytes, []). +dyn_node_name_monitor(_Config) -> + %% Test that monitor() does not fail when erlang:is_alive() return true + %% but we have not yet gotten a name... + Args = ["-setcookie", atom_to_list(erlang:get_cookie()), + "-pa", filename:dirname(code:which(?MODULE))], + {ok, Peer, _} = peer:start(#{connection => 0, args => Args}), + LongNames = net_kernel:longnames(), + StartOpts = #{name_domain => if LongNames -> longnames; + true -> shortnames + end}, + ThisNode = node(), + TestFun = fun () -> dyn_node_name_monitor_test(StartOpts, ThisNode) end, + ok = peer:call(Peer, erlang, apply, [TestFun, []]), + peer:stop(Peer), + ok. + +dyn_node_name_monitor_test(StartOpts, TestNode) -> + try + monitor(process, {net_kernel, TestNode}), + error(unexpected_success) + catch + error:badarg -> + ok + end, + _ = net_kernel:start(undefined, StartOpts), + true = erlang:is_alive(), + Mon = monitor(process, {net_kernel, TestNode}), + receive + {'DOWN', Mon, process, {net_kernel, TestNode}, noconnection} -> + ok + end, + true = net_kernel:connect_node(TestNode), + Mon2 = monitor(process, {net_kernel, TestNode}), + true = lists:member(TestNode, nodes(hidden)), + receive + {'DOWN', Mon2, process, {net_kernel, TestNode}, noconnection} -> + error(unexpected_down) + after + 1000 -> + ok + end, + ok. + +async_dist_flag(Config) when is_list(Config) -> + {ok, Peer1, Node1} = ?CT_PEER(), + async_dist_flag_test(Node1, false), + peer:stop(Peer1), + {ok, Peer2, Node2} = ?CT_PEER(["+pad", "false"]), + async_dist_flag_test(Node2, false), + peer:stop(Peer2), + {ok, Peer3, Node3} = ?CT_PEER(["+pad", "true", "+pad", "false"]), + async_dist_flag_test(Node3, false), + peer:stop(Peer3), + + {ok, Peer4, Node4} = ?CT_PEER(["+pad", "true"]), + async_dist_flag_test(Node4, true), + peer:stop(Peer4), + {ok, Peer5, Node5} = ?CT_PEER(["+pad", "false", "+pad", "true"]), + async_dist_flag_test(Node5, true), + peer:stop(Peer5), -mk_rand_bin(0, Data) -> - list_to_binary(Data); -mk_rand_bin(N, Data) -> - mk_rand_bin(N-1, [rand:uniform(256) - 1 | Data]). + ok. + +async_dist_flag_test(Node, Default) when is_atom(Node), is_boolean(Default) -> + Tester = self(), + NotDefault = not Default, + + Default = erpc:call(Node, erlang, system_info, [async_dist]), + + {P1, M1} = spawn_opt(Node, fun () -> + receive after infinity -> ok end + end, [link, monitor]), + {P2, M2} = spawn_opt(Node, fun () -> + receive after infinity -> ok end + end, [link, monitor, {async_dist, false}]), + {P3, M3} = spawn_opt(Node, fun () -> + receive after infinity -> ok end + end, [link, monitor, {async_dist, true}]), + {async_dist, Default} = erpc:call(Node, erlang, process_info, [P1, async_dist]), + {async_dist, false} = erpc:call(Node, erlang, process_info, [P2, async_dist]), + {async_dist, true} = erpc:call(Node, erlang, process_info, [P3, async_dist]), + + R4 = make_ref(), + {P4, M4} = spawn_opt(Node, fun () -> + Default = process_flag(async_dist, NotDefault), + Tester ! R4, + receive after infinity -> ok end + end, [link, monitor]), + + R5 = make_ref(), + {P5, M5} = spawn_opt(Node, fun () -> + false = process_flag(async_dist, true), + Tester ! R5, + receive after infinity -> ok end + end, [link, monitor, {async_dist, false}]), + R6 = make_ref(), + {P6, M6} = spawn_opt(Node, fun () -> + true = process_flag(async_dist, false), + Tester ! R6, + receive after infinity -> ok end + end, [link, monitor, {async_dist, true}]), + receive R4 -> ok end, + {async_dist, NotDefault} = erpc:call(Node, erlang, process_info, [P4, async_dist]), + receive R5 -> ok end, + {async_dist, true} = erpc:call(Node, erlang, process_info, [P5, async_dist]), + receive R6 -> ok end, + {async_dist, false} = erpc:call(Node, erlang, process_info, [P6, async_dist]), + + + R7 = make_ref(), + {P7, M7} = spawn_opt(Node, fun () -> + Default = process_flag(async_dist, NotDefault), + NotDefault = process_flag(async_dist, NotDefault), + NotDefault = process_flag(async_dist, NotDefault), + NotDefault = process_flag(async_dist, Default), + Default = process_flag(async_dist, Default), + Default = process_flag(async_dist, Default), + Tester ! R7, + receive after infinity -> ok end + end, [link, monitor]), + receive R7 -> ok end, + + unlink(P1), + exit(P1, bang), + unlink(P2), + exit(P2, bang), + unlink(P3), + exit(P3, bang), + unlink(P4), + exit(P4, bang), + unlink(P5), + exit(P5, bang), + unlink(P6), + exit(P6, bang), + unlink(P7), + exit(P7, bang), + + receive {'DOWN', M1, process, P1, bang} -> ok end, + receive {'DOWN', M2, process, P2, bang} -> ok end, + receive {'DOWN', M3, process, P3, bang} -> ok end, + receive {'DOWN', M4, process, P4, bang} -> ok end, + receive {'DOWN', M5, process, P5, bang} -> ok end, + receive {'DOWN', M6, process, P6, bang} -> ok end, + receive {'DOWN', M7, process, P7, bang} -> ok end, + + ok. + +async_dist_port_dctrlr(Config) when is_list(Config) -> + {ok, RecvPeer, RecvNode} = ?CT_PEER(), + ok = async_dist_test(RecvNode), + peer:stop(RecvPeer), + ok. + +async_dist_proc_dctrlr(Config) when is_list(Config) -> + {ok, SendPeer, SendNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), + {ok, RecvPeer, RecvNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), + {Pid, Mon} = spawn_monitor(SendNode, + fun () -> + ok = async_dist_test(RecvNode), + exit(test_success) + end), + receive + {'DOWN', Mon, process, Pid, Reason} -> + test_success = Reason + end, + peer:stop(SendPeer), + peer:stop(RecvPeer), + ok. + +async_dist_test(Node) -> + Scale = case round(test_server:timetrap_scale_factor()/3) of + S when S < 1 -> 1; + S -> S + end, + _ = process_flag(async_dist, false), + Tester = self(), + AliveReceiver1 = spawn_link(Node, fun () -> + register(alive_receiver_1, self()), + Tester ! {registered, self()}, + receive after infinity -> ok end + end), + receive {registered, AliveReceiver1} -> ok end, + AliveReceiver2 = spawn(Node, fun () -> receive after infinity -> ok end end), + {AliveReceiver3, AR3Mon} = spawn_monitor(Node, + fun () -> + receive after infinity -> ok end + end), + {DeadReceiver, DRMon} = spawn_monitor(Node, fun () -> ok end), + receive + {'DOWN', DRMon, process, DeadReceiver, DRReason} -> + normal = DRReason + end, + Data = lists:duplicate($x, 256), + GoNuts = fun GN () -> + DeadReceiver ! hello, + GN() + end, + erpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), + erpc:cast(Node, erts_debug, set_internal_state, [block, 4000*Scale]), + DistBufFiller = spawn_link(fun () -> + process_flag(async_dist, false), + receive go_nuts -> ok end, + GoNuts() + end), + BDMon = spawn_link(fun SysMon () -> + receive + {monitor, Pid, busy_dist_port, _} -> + Tester ! {busy_dist_port, Pid} + end, + SysMon() + end), + _ = erlang:system_monitor(BDMon, [busy_dist_port]), + DistBufFiller ! go_nuts, + + %% Busy dist entry may release after it has triggered even + %% though noone is consuming anything at the receiving end. + %% Continue banging until we stop getting new busy_dist_port... + WaitFilled = fun WF (Tmo) -> + receive + {busy_dist_port, DistBufFiller} -> + WF(1000*Scale) + after + Tmo -> + ok + end + end, + WaitFilled(infinity), + + BusyDistChecker = spawn_link(fun () -> + process_flag(async_dist, false), + DeadReceiver ! hello, + exit(unexpected_return_from_bang) + end), + receive {busy_dist_port, BusyDistChecker} -> ok end, + {async_dist, false} = process_info(self(), async_dist), + {async_dist, false} = process_info(BusyDistChecker, async_dist), + false = process_flag(async_dist, true), + {async_dist, true} = process_info(self(), async_dist), + + Start = erlang:monotonic_time(millisecond), + M1 = erlang:monitor(process, AliveReceiver1), + true = is_reference(M1), + M2 = erlang:monitor(process, AliveReceiver2), + true = is_reference(M2), + {pid, Data} = AliveReceiver1 ! {pid, Data}, + {reg_name, Data} = {alive_receiver_1, Node} ! {reg_name, Data}, + true = erlang:demonitor(M1), + true = link(AliveReceiver2), + true = unlink(AliveReceiver1), + RId = spawn_request(Node, fun () -> receive bye -> ok end end, [link, monitor]), + true = is_reference(RId), + erlang:group_leader(self(), AliveReceiver2), + AR3XReason = make_ref(), + true = exit(AliveReceiver3, AR3XReason), + End = erlang:monotonic_time(millisecond), + + %% These signals should have been buffered immediately. Make sure + %% it did not take a long time... + true = 500*Scale >= End - Start, + + receive after 500*Scale -> ok end, + + unlink(BusyDistChecker), + exit(BusyDistChecker, bang), + false = is_process_alive(BusyDistChecker), + + unlink(DistBufFiller), + exit(DistBufFiller, bang), + false = is_process_alive(DistBufFiller), + + %% Verify that the signals eventually get trough when the other + %% node continue to work... + {links, []} + = erpc:call(Node, erlang, process_info, [AliveReceiver1, links]), + {links, [Tester]} + = erpc:call(Node, erlang, process_info, [AliveReceiver2, links]), + {monitored_by, []} + = erpc:call(Node, erlang, process_info, [AliveReceiver1, monitored_by]), + {monitored_by, [Tester]} + = erpc:call(Node, erlang, process_info, [AliveReceiver2, monitored_by]), + {messages, [{pid, Data}, {reg_name, Data}]} + = erpc:call(Node, erlang, process_info, [AliveReceiver1, messages]), + {group_leader, Tester} + = erpc:call(Node, erlang, process_info, [AliveReceiver2, group_leader]), + + Spawned = receive + {spawn_reply, RId, SpawnRes, Pid} -> + ok = SpawnRes, + true = is_pid(Pid), + Pid + end, + {links, [Tester]} + = erpc:call(Node, erlang, process_info, [Spawned, links]), + {monitored_by, [Tester]} + = erpc:call(Node, erlang, process_info, [Spawned, monitored_by]), + + receive + {'DOWN', AR3Mon, process, AliveReceiver3, ActualAR3XReason} -> + AR3XReason = ActualAR3XReason + end, + + unlink(AliveReceiver2), + unlink(Spawned), + + true = process_flag(async_dist, false), + {async_dist, false} = process_info(self(), async_dist), + + ok. creation_selection(Config) when is_list(Config) -> register(creation_selection_test_supervisor, self()), @@ -3157,86 +3745,31 @@ creation_selection_test([TestSupNode, LongNames, Name, Host]) -> erlang:halt(17) end. -%% Try provoke DistEntry refc bugs (OTP-17513). -dist_entry_refc_race(_Config) -> - {ok, Node} = start_node(dist_entry_refc_race, "+zdntgc 1"), - Pid = spawn_link(Node, ?MODULE, derr_run, [self()]), - {Pid, done} = receive M -> M end, - stop_node(Node), - ok. - -derr_run(Papa) -> - inet_db:set_lookup([file]), % make connection attempt fail fast - NScheds = erlang:system_info(schedulers_online), - SeqList = lists:seq(1, 25 * NScheds), - Nodes = [list_to_atom("none@host" ++ integer_to_list(Seq)) - || Seq <- SeqList], - Self = self(), - Pids = [spawn_link(fun () -> derr_sender(Self, Nodes) end) - || _ <- SeqList], - derr_count(1, 8000), - [begin unlink(P), exit(P,kill) end || P <- Pids], - Papa ! {self(), done}, - ok. - -derr_count(Max, Max) -> - done; -derr_count(N, Max) -> - receive - count -> ok - end, - case N rem 1000 of - 0 -> - io:format("Total attempts: ~bk~n", [N div 1000]); - _ -> ok - end, - derr_count(N+1, Max). - - -derr_sender(Main, Nodes) -> - [{none, Node} ! msg || Node <- Nodes], - Main ! count, - derr_sender(Main, Nodes). - - %%% Utilities id(X) -> X. -timestamp() -> - erlang:monotonic_time(millisecond). +wait_until(Fun) -> + wait_until(Fun, 24*60*60*1000). -start_node(X) -> - start_node(X, [], []). +wait_until(_Fun, Timeout) when Timeout < 0 -> + timeout; +wait_until(Fun, Timeout) -> + case catch Fun() of + true -> + ok; + _ -> + receive after 50 -> ok end, + wait_until(Fun, Timeout-50) + end. -start_node(X, Y) -> - start_node(X, Y, []). +timestamp() -> + erlang:monotonic_time(millisecond). -start_node(Name, Args, Rel) when is_atom(Name), is_list(Rel) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = atom_to_list(erlang:get_cookie()), - RelArg = case Rel of - [] -> []; - _ -> [{erl,[{release,Rel}]}] - end, - test_server:start_node(Name, slave, - [{args, - Args++" -setcookie "++Cookie++" -pa \""++Pa++"\""} - | RelArg]); -start_node(Config, Args, Rel) when is_list(Config), is_list(Rel) -> - Name = list_to_atom((atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive])))), - start_node(Name, Args, Rel). - -stop_node(Node) -> +peer_stop(Peer, Node) -> verify_nc(Node), - test_server:stop_node(Node). + peer:stop(Peer). verify_nc(Node) -> P = self(), @@ -3272,81 +3805,6 @@ freeze_node(Node, MS) -> receive DoingIt -> ok end, receive after Own -> ok end. -inet_rpc_nodename({N,H,_Sock}) -> - list_to_atom(N++"@"++H). - -do_inet_rpc({_,_,Sock},M,F,A) -> - Bin = term_to_binary({M,F,A}), - gen_tcp:send(Sock,Bin), - case gen_tcp:recv(Sock,0) of - {ok, Bin2} -> - T = binary_to_term(Bin2), - {ok,T}; - Else -> - {error, Else} - end. - -inet_rpc_server([Host, PortList]) -> - Port = list_to_integer(PortList), - {ok, Sock} = gen_tcp:connect(Host, Port,[binary, {packet, 4}, - {active, false}]), - inet_rpc_server_loop(Sock). - -inet_rpc_server_loop(Sock) -> - case gen_tcp:recv(Sock,0) of - {ok, Bin} -> - {M,F,A} = binary_to_term(Bin), - Res = (catch apply(M,F,A)), - RB = term_to_binary(Res), - gen_tcp:send(Sock,RB), - inet_rpc_server_loop(Sock); - _ -> - erlang:halt() - end. - - -start_relay_node(Node, Args) -> - start_relay_node(Node, Args, []). -start_relay_node(Node, Args, Env) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = "NOT"++atom_to_list(erlang:get_cookie()), - {ok, LSock} = gen_tcp:listen(0, [binary, {packet, 4}, {active, false}]), - {ok, Port} = inet:port(LSock), - {ok, Host} = inet:gethostname(), - RunArg = "-run " ++ atom_to_list(?MODULE) ++ " inet_rpc_server " ++ - Host ++ " " ++ integer_to_list(Port), - {ok, NN} = test_server:start_node(Node, peer, - [{env,Env}, - {args, Args ++ - " -setcookie "++Cookie++" -pa "++Pa++" "++ - RunArg}]), - [N,H] = string:lexemes(atom_to_list(NN),"@"), - {ok, Sock} = gen_tcp:accept(LSock), - pang = net_adm:ping(NN), - {N,H,Sock}. - -stop_relay_node({N,H,Sock}) -> - catch do_inet_rpc(Sock,erlang,halt,[]), - catch gen_tcp:close(Sock), - wait_dead(N,H,10). - -wait_dead(N,H,0) -> - {error,{not_dead,N,H}}; -wait_dead(N,H,X) -> - case erl_epmd:port_please(N,H) of - {port,_,_} -> - receive - after 1000 -> - ok - end, - wait_dead(N,H,X-1); - noport -> - ok; - Else -> - {error, {unexpected, Else}} - end. - - start_node_monitors(Nodes) -> Master = self(), lists:foreach(fun (Node) -> @@ -3453,13 +3911,6 @@ from(_, []) -> []. %% fun_spawn(Fun, Args) -> %% spawn_link(erlang, apply, [Fun, Args]). - -long_or_short() -> - case net_kernel:longnames() of - true -> " -name "; - false -> " -sname " - end. - until(Fun) -> case Fun() of true -> @@ -3473,8 +3924,8 @@ forever(Fun) -> Fun(), forever(Fun). -abort(Why) -> - set_internal_state(abort, Why). +%% abort(Why) -> +%% set_internal_state(abort, Why). start_busy_dist_port_tracer() -> diff --git a/erts/emulator/test/distribution_SUITE_data/run.erl b/erts/emulator/test/distribution_SUITE_data/run.erl index f574b2c02cc4..4ebf600737f4 100644 --- a/erts/emulator/test/distribution_SUITE_data/run.erl +++ b/erts/emulator/test/distribution_SUITE_data/run.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2021. 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. @@ -54,7 +54,7 @@ start() -> do_it() -> {ok, _} = net_kernel:start([fideridum,shortnames]), - {ok, Node} = slave:start(host(), heppel), + {ok, _Peer, Node} = peer:start(#{name => peer:random_name(heppel)}), P = spawn(Node, net_kernel, stop, []), B1 = term_to_binary(P), N1 = node(P), diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index b4d1e94d414c..1a512e054490 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -84,7 +84,6 @@ env/1, poll_pipe/1, lots_of_used_fds_on_boot/1, - lots_of_used_fds_on_boot_slave/1, z_test/1]). -export([bin_prefix/2]). @@ -124,7 +123,7 @@ -define(heap_binary_size, 64). suite() -> - [{ct_hooks,[ts_install_cth]}, + [{ct_hooks,[cth_log_redirect,ts_install_cth]}, {timetrap, {minutes, 1}}]. all() -> %% Keep a_test first and z_test last... @@ -172,22 +171,47 @@ groups() -> ioq_exit_timeout_async]}]. init_per_suite(Config) -> + logger:add_handler_filter(default, + checkio_filter, + {fun F(#{ msg := {string,Str}} = Log, _State) -> + case re:run(Str,"(fds in pollset)|(Bad value on output port)") of + {match,_} -> + stop; + _ -> + Log + end; + F(#{ msg := {Fmt,Args}} = Log, State) when not is_atom(Fmt) -> + F(Log#{ msg := {string,io_lib:format(Fmt,Args)}}, State); + F(Log, _State) -> + Log + end, undefined}), Config. end_per_suite(_Config) -> - catch erts_debug:set_internal_state(available_internal_state, false). + logger:remove_handler_filter(default, checkio_filter), + catch erts_debug:set_internal_state(available_internal_state, false), + + case nodes(connected) of + [] -> ok; + Nodes -> + [net_kernel:disconnect(N) || N <- Nodes], + io:format("LEAKED connections: ~p\n", [Nodes]) + end. + init_per_group(poll_thread, Config) -> - [{node_args, "+IOt 2"} | Config]; + [{node_args, ["+IOt", "2"]} | Config]; init_per_group(poll_set, Config) -> - [{node_args, "+IOt 2 +IOp 2"} | Config]; + [{node_args, ["+IOt", "2", "+IOp", "2"]} | Config]; init_per_group(polling, Config) -> case proplists:get_value(node_args, Config) of undefined -> Config; Args -> - {ok, Node} = start_node(polling, Args), - [{node, Node} | Config] + {ok, Peer, Node} = ?CT_PEER(Args), + unlink(Peer), %% otherwise it will immediately stop + setup_logger(Node), + [{node, {Peer, Node}} | Config] end; init_per_group(_GroupName, Config) -> Config. @@ -195,11 +219,11 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> case proplists:get_value(node, Config) of undefined -> - ok; - Node -> - stop_node(Node) - end, - Config. + Config; + {Peer, _Node} -> + ok = peer:stop(Peer), + {save_config, proplists:delete(node, Config)} + end. init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> CIOD = rpc(Config, @@ -210,12 +234,13 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> end, erts_debug:get_internal_state(check_io_debug) end), - erlang:display({init_per_testcase, Case}), 0 = element(1, CIOD), [{testcase, Case}|Config]. end_per_testcase(Case, Config) -> - erlang:display({end_per_testcase, Case}), + %% Logs some info about the system + ct_os_cmd("epmd -names"), + ct_os_cmd("ps aux"), try rpc(Config, fun() -> get_stable_check_io_info(), erts_debug:get_internal_state(check_io_debug) @@ -223,25 +248,23 @@ end_per_testcase(Case, Config) -> CIOD -> 0 = element(1, CIOD) catch _E:_R:_ST -> - %% Logs some info about the system - ct_os_cmd("epmd -names"), - ct_os_cmd("ps aux"), %% Restart the node case proplists:get_value(node, Config) of undefined -> ok; - Node -> - timer:sleep(1000), %% Give the node time to die - [NodeName, _] = string:lexemes(atom_to_list(Node),"@"), - {ok, Node} = start_node_final( - list_to_atom(NodeName), - proplists:get_value(node_args, Config)) + {Peer, _Node} -> + peer:stop(Peer), + {ok, Peer2, Node2} = ?CT_PEER(proplists:get_value(node_args, Config)), + unlink(Peer2), %% otherwise it will immediately stop + setup_logger(Node2), + Config2 = [{node, {Peer2, Node2}} | proplists:delete(node, Config)], + {save_config, Config2} end end, ok. ct_os_cmd(Cmd) -> - ct:log("~s: ~s",[Cmd,os:cmd(Cmd)]). + ct:log("~s: ~ts",[Cmd,os:cmd(Cmd)]). %% Test sending bad types to port with an outputv-capable driver. outputv_errors(Config) when is_list(Config) -> @@ -535,7 +558,7 @@ timer_delay(Config) when is_list(Config) -> stop_driver(Port, Name), ok. -%% Test that driver_set_timer with new timout really changes +%% Test that driver_set_timer with new timeout really changes %% the timer (ticket OTP-5942), it didn't work before timer_change(Config) when is_list(Config) -> @@ -1014,12 +1037,11 @@ chkio_test({erts_poll_info, Before}, chk_chkio_port(Port), Fun(), During = get_check_io_total(erlang:system_info(check_io)), - erlang:display(During), [0 = element(1, erts_debug:get_internal_state(check_io_debug)) || %% The pollset is not stable when running the fallback testcase Test /= ?CHKIO_USE_FALLBACK_POLLSET], - io:format("During test: ~p~n", [During]), + ct:log("During test: ~p~n", [During]), chk_chkio_port(Port), case erlang:port_control(Port, ?CHKIO_STOP, "") of Res when is_list(Res) -> @@ -1087,7 +1109,7 @@ get_stable_check_io_info(N) -> %% Merge return from erlang:system_info(check_io) %% as if it was one big pollset. get_check_io_total(ChkIo) -> - ct:log("ChkIo = ~p~n",[ChkIo]), + ct:log("ChkIo = ~p (~p)~n",[ChkIo, nodes()]), {Fallback, Rest} = get_fallback(ChkIo), OnlyPollThreads = [PS || PS <- Rest, not is_scheduler_pollset(PS)], add_fallback_infos(Fallback, @@ -1155,7 +1177,7 @@ tag_type(poll_threads) -> sum. %% driver that didn't use the same lock. The lock checker %% used to trigger on this and dump core. otp_6602(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Done = make_ref(), Parent = self(), Tester = spawn_link(Node, @@ -1170,7 +1192,7 @@ otp_6602(Config) when is_list(Config) -> end), receive Done -> ok end, unlink(Tester), - stop_node(Node), + peer:stop(Peer), ok. -define(EXPECTED_SYSTEM_INFO_NAMES1, @@ -1869,68 +1891,20 @@ lots_of_used_fds_on_boot_test(Config) -> %% open. This used to hang the whole VM at boot in %% an eternal loop trying to figure out how to size %% arrays in erts_poll() implementation. - Name = lots_of_used_fds_on_boot, - HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end, - atom_to_list(node())), - FullName = list_to_atom(atom_to_list(Name) ++ HostSuffix), - Pa = filename:dirname(code:which(?MODULE)), Prog = case catch init:get_argument(progname) of {ok,[[P]]} -> P; _ -> exit(no_progname_argument_found) end, - NameSw = case net_kernel:longnames() of - false -> "-sname "; - true -> "-name "; - _ -> exit(not_distributed_node) - end, - {ok, Pwd} = file:get_cwd(), - NameStr = atom_to_list(Name), DataDir = proplists:get_value(data_dir, Config), Wrapper = filename:join(DataDir, "lots_of_fds_used_wrapper"), - CmdLine = Wrapper ++ " " ++ Prog ++ " -noshell -noinput " - ++ NameSw ++ " " ++ NameStr ++ " " - ++ "-pa " ++ Pa ++ " " - ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr ++ " " - ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()) ++ " " - ++ "-s " ++ atom_to_list(?MODULE) ++ " lots_of_used_fds_on_boot_slave " - ++ atom_to_list(node()), - io:format("Starting node ~p: ~s~n", [FullName, CmdLine]), - net_kernel:monitor_nodes(true), - Port = case open_port({spawn, CmdLine}, [exit_status]) of - Prt when is_port(Prt) -> - Prt; - OPError -> - exit({failed_to_start_node, {open_port_error, OPError}}) - end, - receive - {Port, {exit_status, 17}} -> - {skip, "Cannot open enough fds to test this"}; - {Port, {exit_status, Error}} -> - exit({failed_to_start_node, {exit_status, Error}}); - {nodeup, FullName} -> - io:format("~p connected!~n", [FullName]), - FullName = rpc:call(FullName, erlang, node, []), - rpc:cast(FullName, erlang, halt, []), - receive - {Port, {exit_status, 0}} -> - ok; - {Port, {exit_status, Error}} -> - exit({unexpected_exit_status, Error}) - after 5000 -> - exit(missing_exit_status) - end - after 5000 -> - exit(connection_timeout) + try + {ok, Peer, _Node} = ?CT_PEER(#{connection => standard_io, exec => {Wrapper, [Prog]}}), + peer:stop(Peer) + catch + exit:{boot_failed, {exit_status, 17}} -> + {skip, "Cannot open enough fds to test this"} end. -lots_of_used_fds_on_boot_slave([Master]) -> - erlang:monitor_node(Master, true), - receive - {nodedown, Master} -> - erlang:halt() - end, - ok. - thread_mseg_alloc_cache_clean(Config) when is_list(Config) -> case {erlang:system_info(threads), erlang:system_info({allocator,mseg_alloc}), @@ -2131,12 +2105,11 @@ async_blast(Config) when is_list(Config) -> end, Ps), End = os:timestamp(), MemAfter = driver_alloc_size(), - io:format("MemBefore=~p, MemMid=~p, MemAfter=~p~n", + ct:log("MemBefore=~p, MemMid=~p, MemAfter=~p~n", [MemBefore, MemMid, MemAfter]), AsyncBlastTime = timer:now_diff(End,Start)/1000000, - io:format("AsyncBlastTime=~p~n", [AsyncBlastTime]), + ct:log("AsyncBlastTime=~p~n", [AsyncBlastTime]), MemBefore = MemAfter, - erlang:display({async_blast_time, AsyncBlastTime}), ok. thr_msg_blast_receiver(_Port, N, N) -> @@ -2187,13 +2160,12 @@ thr_msg_blast(Config) when is_list(Config) -> ok end, MemAfter = driver_alloc_size(), - io:format("MemBefore=~p, MemAfter=~p~n", + ct:log("MemBefore=~p, MemAfter=~p~n", [MemBefore, MemAfter]), ThrMsgBlastTime = timer:now_diff(End,Start)/1000000, - io:format("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]), + ct:log("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]), MemBefore = MemAfter, Res = {thr_msg_blast_time, ThrMsgBlastTime}, - erlang:display(Res), Res. -define(IN_RANGE(LoW_, VaLuE_, HiGh_), @@ -2223,7 +2195,7 @@ consume_timeslice(Config) when is_list(Config) -> %% scheduling counts. %% %% When signal is delivered immediately we must take into account - %% that process and port are "virtualy" scheduled out and in + %% that process and port are "virtually" scheduled out and in %% in the trace generated. %% %% Port ! {_, {command, _}, and port_command() differs. The send @@ -2454,8 +2426,7 @@ count_pp_sched_stop(Ps) -> PNs = lists:map(fun (P) -> {P, 0} end, Ps), receive {trace_delivered, all, Td} -> ok end, Res = count_proc_sched(Ps, PNs), - io:format("Scheduling counts: ~p~n", [Res]), - erlang:display({scheduling_counts, Res}), + ct:log("Scheduling counts: ~p~n", [Res]), Res. do_inc_pn(_P, []) -> @@ -2560,8 +2531,9 @@ check_io_debug() -> has_gethost() -> has_gethost(erlang:ports()). has_gethost([P|T]) -> - case erlang:port_info(P, name) of - {name,"inet_gethost"++_} -> + {name, Name} = erlang:port_info(P, name), + case filename:basename(Name) of + "inet_gethost"++_ -> true; _ -> has_gethost(T) @@ -2649,7 +2621,7 @@ make_refc_binaries(Term) -> transform_bins(F, Term). build_binary(Elements) -> - list_to_binary(build_list(Elements)). + rand:bytes(Elements). build_list(Elements) -> build_list(Elements, []). @@ -2733,32 +2705,14 @@ sleep(Ms) when is_integer(Ms), Ms >= 0 -> receive after Ms -> ok end. -start_node(Config) when is_list(Config) -> - start_node(proplists:get_value(testcase, Config)); -start_node(Name) -> - start_node(Name, ""). -start_node(NodeName, Args) -> - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(NodeName) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - start_node_final(Name, Args). -start_node_final(Name, Args) -> +setup_logger(Node) -> {ok, Pwd} = file:get_cwd(), - FinalArgs = [Args, " -pa ", filename:dirname(code:which(?MODULE))], - {ok, Node} = test_server:start_node(Name, slave, [{args, FinalArgs}]), - LogPath = Pwd ++ "/error_log." ++ atom_to_list(Name), + Name = hd(string:lexemes(atom_to_list(Node), "@")), + LogPath = filename:join(Pwd, "error_log." ++ Name), ct:pal("Logging to: ~s", [LogPath]), rpc:call(Node, logger, add_handler, [file_handler, logger_std_h, #{formatter => {logger_formatter,#{ single_line => false }}, - config => #{file => LogPath }}]), - {ok, Node}. - -stop_node(Node) -> - test_server:stop_node(Node). + config => #{file => LogPath }}]). wait_deallocations() -> try @@ -2776,7 +2730,8 @@ rpc(Config, Fun) -> case proplists:get_value(node, Config) of undefined -> Fun(); - Node -> + {_Peer, Node} -> + ct:log("Running RPC ~p on ~p/~p~n", [Fun, _Peer, Node]), Self = self(), Ref = make_ref(), Pid = spawn(Node, diff --git a/erts/emulator/test/driver_SUITE_data/vsn_mismatch_drv_impl.c b/erts/emulator/test/driver_SUITE_data/vsn_mismatch_drv_impl.c index 6750b8a78b70..f1fee767f079 100644 --- a/erts/emulator/test/driver_SUITE_data/vsn_mismatch_drv_impl.c +++ b/erts/emulator/test/driver_SUITE_data/vsn_mismatch_drv_impl.c @@ -22,7 +22,7 @@ * * Description: Implementation of a driver that fakes driver version. It * is used for checking that version mismatches are handled - * correct by the emulator. The following makros have to be + * correct by the emulator. The following macros have to be * defined before it can be used: * * VSN_MISMATCH_DRV_NAME_STR * * VSN_MISMATCH_DRV_NAME diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl index 654b1c45a5d9..926e32d21679 100644 --- a/erts/emulator/test/dump_SUITE.erl +++ b/erts/emulator/test/dump_SUITE.erl @@ -55,7 +55,7 @@ init_per_testcase(_, Config) -> end_per_testcase(_, Config) -> - Config. + erts_test_utils:ept_check_leaked_nodes(Config). %%% %%% The test cases ------------------------------------------------------------- @@ -67,7 +67,7 @@ signal_abort(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), - {ok, Node} = start_node(Config), + {ok, _Peer, Node} = ?CT_PEER(), false = rpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), @@ -118,7 +118,7 @@ load() -> exiting_dump(Config) when is_list(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), - {ok, Node} = start_node(Config), + {ok, _Peer, Node} = ?CT_PEER(), Self = self(), @@ -129,12 +129,13 @@ exiting_dump(Config) when is_list(Config) -> [ets:insert(T,{I,I}) || I <- lists:seq(1,1000)] end || _ <- lists:seq(1,1000)], Self ! ready, - receive ok -> ok end + receive {terminate, Pid} -> Pid ! ok end end), true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), - receive ready -> unlink(Pid), Pid ! ok end, + receive ready -> unlink(Pid), Pid ! {terminate, self()} end, + receive ok -> ok end, rpc:call(Node, erlang, halt, ["dump"]), @@ -154,8 +155,8 @@ exiting_dump(Config) when is_list(Config) -> free_dump(Config) when is_list(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), - {ok, NodeA} = start_node(Config), - {ok, NodeB} = start_node(Config), + {ok, _PeerA, NodeA} = ?CT_PEER(), + {ok, PeerB, NodeB} = ?CT_PEER(), Self = self(), @@ -209,14 +210,14 @@ free_dump(Config) when is_list(Config) -> unlink(PidB), - rpc:call(NodeB, erlang, halt, [0]), + peer:stop(PeerB), ok. %% Test that crash dumping works when heart is used heart_dump(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"heart.dump"), - {ok, Node} = start_node(Config,"-heart"), + {ok, _Peer, Node} = ?CT_PEER(#{ args => ["-heart"] }), true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP_SECONDS","10"]), rpc:call(Node, erlang, halt, ["dump"]), @@ -226,7 +227,7 @@ heart_dump(Config) -> %% Test that there is no crash dump if heart is used and DUMP_SECONDS is not set heart_no_dump(Config) -> Dump = filename:join(proplists:get_value(priv_dir, Config),"heart_no.dump"), - {ok, Node} = start_node(Config,"-heart"), + {ok, _Peer, Node} = ?CT_PEER(#{ args => ["-heart"] }), true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), true = rpc:call(Node, os, unsetenv, ["ERL_CRASH_DUMP_SECONDS"]), rpc:call(Node, erlang, halt, ["dump"]), @@ -253,16 +254,3 @@ get_dump_when_done(Dump, Sz) -> {ok, #file_info{ size = NewSz }} -> get_dump_when_done(Dump, NewSz) end. - -start_node(Config) when is_list(Config) -> - start_node(Config, ""). -start_node(Config, Extra) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Extra}]). diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl index 075051753bc4..753c41cc1dee 100644 --- a/erts/emulator/test/efile_SUITE.erl +++ b/erts/emulator/test/efile_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -19,6 +19,7 @@ -module(efile_SUITE). -export([all/0, suite/0]). +-export([init_per_testcase/2, end_per_testcase/2]). -export([iter_max_files/1, proc_zero_sized_files/1]). -export([do_iter_max_files/2]). @@ -31,6 +32,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [iter_max_files, proc_zero_sized_files]. + +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + %% %% Open as many files as possible. Do this several times and check %% that we get the same number of files every time. @@ -52,11 +59,9 @@ iter_max_files_1(Config) -> N = 10 end, %% Run on a different node in order to make the test more stable. - Dir = filename:dirname(code:which(?MODULE)), - {ok,Node} = test_server:start_node(test_iter_max_files,slave, - [{args,"-pa " ++ Dir}]), + {ok, Peer, Node} = ?CT_PEER(), L = rpc:call(Node,?MODULE,do_iter_max_files,[N, TestFile]), - test_server:stop_node(Node), + peer:stop(Peer), io:format("Number of files opened in each test:~n~w\n", [L]), verify_max_files(L), Head = hd(L), diff --git a/erts/emulator/test/emulator_bench.spec b/erts/emulator/test/emulator_bench.spec index 8b1bb71a4055..a6d07be6dba9 100644 --- a/erts/emulator/test/emulator_bench.spec +++ b/erts/emulator/test/emulator_bench.spec @@ -2,3 +2,4 @@ {groups,"../emulator_test",binary_SUITE,[iolist_size_benchmarks]}. {groups,"../emulator_test",erts_debug_SUITE,[interpreter_size_bench]}. {groups,"../emulator_test",hash_SUITE,[phash2_benchmark]}. +{groups,"../emulator_test",map_SUITE,[benchmarks]}. diff --git a/erts/emulator/test/emulator_gh.spec b/erts/emulator/test/emulator_gh.spec new file mode 100644 index 000000000000..22f627f6fe35 --- /dev/null +++ b/erts/emulator/test/emulator_gh.spec @@ -0,0 +1,4 @@ +{enable_builtin_hooks, false}. +{suites,"../emulator_test",all}. +{skip_groups,"../emulator_test",hash_SUITE,[phash2_benchmark],"Benchmark only"}. +{skip_cases,"../emulator_test",nif_SUITE,[t_dynamic_resource_call],"Unstable TC"}. diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c b/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c index 8ceb9eff08e4..7b07ae4dfe99 100644 --- a/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/basic.c @@ -242,11 +242,11 @@ testcase_run(TestCaseState_t *tcs) ASSERT_CLNUP(tcs, tres[1] == &res_tf1, erl_drv_mutex_unlock(mtx)); ASSERT_CLNUP(tcs, res_tf1 == 1, erl_drv_mutex_unlock(mtx)); - /* Test signaling when noone waits */ + /* Test signaling when no one waits */ erl_drv_cond_signal(cnd); - /* Test broadcasting when noone waits */ + /* Test broadcasting when no one waits */ erl_drv_cond_broadcast(cnd); diff --git a/erts/emulator/test/erl_link_SUITE.erl b/erts/emulator/test/erl_link_SUITE.erl index de2a62d812e1..391dfe6bf964 100644 --- a/erts/emulator/test/erl_link_SUITE.erl +++ b/erts/emulator/test/erl_link_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2021. All Rights Reserved. +%% Copyright Ericsson AB 2001-2023. 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. @@ -91,8 +91,8 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> end, Config. -end_per_testcase(_Func, _Config) -> - ok. +end_per_testcase(_Func, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). init_per_suite(Config) -> Config. @@ -111,8 +111,8 @@ links(Config) when is_list(Config) -> %% Tests distributed links dist_links(Config) when is_list(Config) -> - [NodeName] = get_names(1, dist_link), - {ok, Node} = start_node(NodeName), + {ok, _Peer, Node} = ?CT_PEER(), + rpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), common_link_test(node(), Node), TP4 = spawn(?MODULE, test_proc, []), TP5 = spawn(?MODULE, test_proc, []), @@ -174,11 +174,11 @@ common_link_test(NodeA, NodeB) -> %% Tests monitor of nodes monitor_nodes(Config) when is_list(Config) -> - [An, Bn, Cn, Dn] = get_names(4, dist_link), - {ok, A} = start_node(An), - {ok, B} = start_node(Bn), - C = list_to_atom(lists:concat([Cn, "@", hostname()])), - D = list_to_atom(lists:concat([Dn, "@", hostname()])), + {ok, PeerA, A} = ?CT_PEER(), + {ok, PeerB, B} = ?CT_PEER(), + [_, HostName] = string:lexemes(atom_to_list(node()), "@"), + C = list_to_atom(peer:random_name(?MODULE_STRING) ++ "@" ++ HostName), + D = list_to_atom(peer:random_name(?MODULE_STRING) ++ "@" ++ HostName), 0 = no_of_monitor_node(self(), A), 0 = no_of_monitor_node(self(), B), monitor_node(A, true), @@ -212,11 +212,11 @@ monitor_nodes(Config) when is_list(Config) -> check_monitor_node(self(), C, 0), check_monitor_node(self(), D, 0), - stop_node(A), + peer:stop(PeerA), receive {nodedown, A} -> ok end, check_monitor_node(self(), A, 0), check_monitor_node(self(), B, 3), - stop_node(B), + peer:stop(PeerB), receive {nodedown, B} -> ok end, receive {nodedown, B} -> ok end, receive {nodedown, B} -> ok end, @@ -235,7 +235,8 @@ process_monitors(Config) when is_list(Config) -> common_process_monitors(node(), node()), Mon1 = erlang:monitor(process,self()), [] = find_erl_monitor(self(), Mon1), - [Name] = get_names(1, process_monitors), + Name = list_to_atom(lists:concat([?FUNCTION_NAME, + integer_to_list(erlang:unique_integer([positive]))])), true = register(Name, self()), Mon2 = erlang:monitor(process, Name), [] = find_erl_monitor(self(), Mon2), @@ -252,8 +253,8 @@ process_monitors(Config) when is_list(Config) -> %% Tests distributed process monitors dist_process_monitors(Config) when is_list(Config) -> - [Name] = get_names(1,dist_process_monitors), - {ok, Node} = start_node(Name), + {ok, _Peer, Node} = ?CT_PEER(), + rpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), common_process_monitors(node(), Node), TP1 = spawn(Node, ?MODULE, test_proc, []), R1 = erlang:monitor(process, TP1), @@ -280,7 +281,8 @@ common_process_monitors(NodeA, NodeB) -> run_common_process_monitors(TP1, TP2), TP3 = spawn(NodeA, ?MODULE, test_proc, []), TP4 = spawn(NodeB, ?MODULE, test_proc, []), - [TP4N] = get_names(1, common_process_monitors), + TP4N = list_to_atom(lists:concat([?FUNCTION_NAME, + integer_to_list(erlang:unique_integer([positive]))])), true = tp_call(TP4, fun () -> register(TP4N,self()) end), run_common_process_monitors(TP3, case node() == node(TP4) of @@ -337,8 +339,7 @@ busy_dist_port_monitor(Config) when is_list(Config) -> _ -> false end, - [An] = get_names(1, busy_dist_port_monitor), - {ok, A} = start_node(An), + {ok, PeerA, A} = ?CT_PEER(), TP1 = spawn(A, ?MODULE, test_proc, []), %% Check monitor over busy port M1 = suspend_on_busy_test(A, @@ -367,7 +368,7 @@ busy_dist_port_monitor(Config) when is_list(Config) -> end end), tp_cast(TP1, fun () -> exit(normal) end), - stop_node(A), + peer:stop(PeerA), stop_busy_dist_port_tracer(Tracer), ok. @@ -379,8 +380,7 @@ busy_dist_port_link(Config) when is_list(Config) -> _ -> false end, - [An] = get_names(1, busy_dist_port_link), - {ok, A} = start_node(An), + {ok, PeerA, A} = ?CT_PEER(), TP1 = spawn(A, ?MODULE, test_proc, []), %% Check link over busy port suspend_on_busy_test(A, @@ -413,7 +413,7 @@ busy_dist_port_link(Config) when is_list(Config) -> end end), tp_cast(TP1, fun () -> exit(normal) end), - stop_node(A), + peer:stop(PeerA), stop_busy_dist_port_tracer(Tracer), ok. @@ -422,10 +422,9 @@ otp_5772_link(Config) when is_list(Config) -> otp_5772_link_test(node()). otp_5772_dist_link(Config) when is_list(Config) -> - [An] = get_names(1, otp_5772_dist_link), - {ok, A} = start_node(An), + {ok, PeerA, A} = ?CT_PEER(), otp_5772_link_test(A), - stop_node(A). + peer:stop(PeerA). otp_5772_link_test(Node) -> Prio = process_flag(priority, high), @@ -454,11 +453,9 @@ otp_5772_monitor(Config) when is_list(Config) -> otp_5772_monitor_test(node()). otp_5772_dist_monitor(Config) when is_list(Config) -> - [An] = get_names(1, otp_5772_dist_monitor), - {ok, A} = start_node(An), + {ok, PeerA, A} = ?CT_PEER(), otp_5772_monitor_test(A), - stop_node(A), - ok. + peer:stop(PeerA). otp_5772_monitor_test(Node) -> Prio = process_flag(priority, high), @@ -482,8 +479,7 @@ otp_5772_monitor_test(Node) -> ok. otp_7946(Config) when is_list(Config) -> - [NodeName] = get_names(1, otp_7946), - {ok, Node} = start_node(NodeName), + {ok, _Peer, Node} = ?CT_PEER(), Proc = rpc:call(Node, erlang, whereis, [net_kernel]), Mon = erlang:monitor(process, Proc), rpc:cast(Node, erlang, halt, []), @@ -504,10 +500,9 @@ otp_17127_local_link_with_simultaneous_link_unlink(Config) when is_list(Config) otp_17127_link_with_simultaneous_link_unlink_test(node(), node()). otp_17127_dist_link_with_simultaneous_link_unlink(Config) when is_list(Config) -> - [NodeName] = get_names(1, otp_17127), - {ok, Node} = start_node(NodeName), + {ok, Peer, Node} = ?CT_PEER(), Res = otp_17127_link_with_simultaneous_link_unlink_test(node(), Node), - stop_node(Node), + peer:stop(Peer), Res. otp_17127_link_with_simultaneous_link_unlink_test(NodeA, NodeB) -> @@ -524,10 +519,10 @@ otp_17127_local_random(Config) when is_list(Config) -> otp_17127_random_test(node(), node(), 100). otp_17127_dist_random(Config) when is_list(Config) -> - [NodeName] = get_names(1, otp_17127), - {ok, Node} = start_node(NodeName), + {ok, Peer, Node} = ?CT_PEER(), + rpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), Res = otp_17127_random_test(node(), Node, 20), - stop_node(Node), + peer:stop(Peer), Res. otp_17127_random_test(_NodeA, _NodeB, 0) -> @@ -676,9 +671,12 @@ make_busy(Node, Time) when is_integer(Time) -> receive after Own -> ok end, wait_until(fun () -> case {DCtrl, process_info(Pid, status)} of - {DPrt, {status, suspended}} when is_port(DPrt) -> true; - {DPid, {status, waiting}} when is_pid(DPid) -> true; - _ -> false + {DPrt, {status, waiting}} when is_port(DPrt) -> + verify_busy(DPrt); + {DPid, {status, waiting}} when is_pid(DPid) -> + true; + _-> + false end end), %% then dist entry @@ -695,6 +693,28 @@ unmake_busy(Pid) -> unlink(Pid), exit(Pid, bang). +verify_busy(Port) -> + Parent = self(), + Pid = + spawn_link( + fun() -> + port_command(Port, "Just some data"), + Error = {not_busy, Port}, + exit(Parent, Error), + error(Error) + end), + receive after 30 -> ok end, + case process_info(Pid, status) of + {status, suspended} -> + unlink(Pid), + exit(Pid, kill), + true; + {status, _} = WrongStatus -> + unlink(Pid), + exit(Pid, WrongStatus), + error(WrongStatus) + end. + suspend_on_busy_test(Node, Doing, Fun) -> Tester = self(), DoIt = make_ref(), @@ -1182,48 +1202,6 @@ check_monitor_node(From, Node, No) when is_pid(From), dir = target, pid = From}] = find_erl_monitor({node(From), Node}, From). -connection_id(Node) -> - try - erts_debug:get_internal_state({connection_id, Node}) - catch - _:_ -> -1 - end. - -hostname() -> - from($@, atom_to_list(node())). - -from(H, [H | T]) -> T; -from(H, [_ | T]) -> from(H, T); -from(_H, []) -> []. - -get_names(N, T) when is_atom(T) -> - get_names(N, T, []). -get_names(0, _, Acc) -> - Acc; -get_names(N, T, Acc) -> - get_names(N-1, T, [list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(T) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))) | Acc]). - -start_node(Name) -> - start_node(Name, ""). - -start_node(Name, Args) -> - Pa = filename:dirname(code:which(?MODULE)), - Res = test_server:start_node(Name, slave, [{args, Args ++ " -pa " ++ Pa}]), - {ok, Node} = Res, - rpc:call(Node, erts_debug, set_internal_state, - [available_internal_state, true]), - Res. - - -stop_node(Node) -> - test_server:stop_node(Node). - -define(COOKIE, ''). -define(DOP_LINK, 1). -define(DOP_SEND, 2). @@ -1252,7 +1230,19 @@ ensure_dctrl(Node) -> end. dctrl_send(DPrt, Data) when is_port(DPrt) -> - port_command(DPrt, Data); + try prim_inet:send(DPrt, Data) of + ok -> + ok; + Result -> + io:format("~w/2: ~p~n", [?FUNCTION_NAME, Result]), + Result + catch + Class: Reason: Stacktrace -> + io:format( + "~w/2: ~p: ~p: ~p ~n", + [?FUNCTION_NAME, Class, Reason, Stacktrace]), + erlang:raise(Class, Reason, Stacktrace) + end; dctrl_send(DPid, Data) when is_pid(DPid) -> Ref = make_ref(), DPid ! {send, self(), Ref, Data}, @@ -1285,7 +1275,7 @@ dctrl(Node) when is_atom(Node) -> dmsg_hdr() -> [131, % Version Magic $D, % Dist header - 0]. % No atom cache referenses + 0]. % No atom cache references dmsg_ext(Term) -> <<131, Res/binary>> = term_to_binary(Term), diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index 666afde1c026..2149eac41bb7 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -23,6 +23,7 @@ -include_lib("common_test/include/ct_event.hrl"). -export([all/0, suite/0, groups/0, + init_per_testcase/2, end_per_testcase/2, test_size/1,flat_size_big/1,df/1,term_type/1, instructions/1, stack_check/1, alloc_blocks_size/1, t_copy_shared/1, @@ -43,6 +44,11 @@ all() -> groups() -> [{interpreter_size_bench, [], [interpreter_size_bench]}]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + interpreter_size_bench(_Config) -> Size = erts_debug:interpreter_size(), ct_event:notify(#event{name=benchmark_data, @@ -58,12 +64,12 @@ test_size(Config) when is_list(Config) -> 0 = do_test_size([]), 0 = do_test_size(42), ConsCellSz = do_test_size(ConsCell1), - 1 = do_test_size({}), + 0 = do_test_size({}), 2 = do_test_size({[]}), 3 = do_test_size({a,b}), 7 = do_test_size({a,[b,c]}), 8 = do_test_size(#{b => 2,c => 3}), - 4 = do_test_size(#{}), + 3 = do_test_size(#{}), 32 = do_test_size(#{b => 2,c => 3,txt => "hello world"}), true = do_test_size(maps:from_list([{I,I}||I<-lists:seq(1,256)])) >= map_size_lower_bound(256), @@ -76,7 +82,7 @@ test_size(Config) when is_list(Config) -> %% Fun environment size = 0 (the smallest fun possible) SimplestFun = fun() -> ok end, - FunSz0 = 6, + FunSz0 = 5, FunSz0 = do_test_size(SimplestFun), %% Fun environment size = 1 @@ -89,7 +95,8 @@ test_size(Config) when is_list(Config) -> FunSz1 = do_test_size(fun() -> ConsCell1 end) - do_test_size(ConsCell1), - 2 = do_test_size(fun lists:sort/1), + %% External funs are the same size as local ones without environment + FunSz0 = do_test_size(fun lists:sort/1), Arch = 8 * erlang:system_info({wordsize, external}), case {Arch, do_test_size(mk_ext_pid({a@b, 1}, 17, 42))} of @@ -259,30 +266,22 @@ instructions(Config) when is_list(Config) -> alloc_blocks_size(Config) when is_list(Config) -> F = fun(Args) -> - Node = start_slave(Args), + {ok, Peer, Node} = ?CT_PEER(Args), ok = rpc:call(Node, ?MODULE, do_alloc_blocks_size, []), - true = test_server:stop_node(Node) + peer:stop(Peer) end, case test_server:is_asan() of - false -> F("+Meamax"); + false -> F(["+Meamax"]); true -> skip end, - F("+Meamin"), - F(""), + F(["+Meamin"]), + F([]), ok. do_alloc_blocks_size() -> _ = erts_debug:alloc_blocks_size(binary_alloc), ok. -start_slave(Args) -> - Name = ?MODULE_STRING ++ "_slave", - Pa = filename:dirname(code:which(?MODULE)), - {ok, Node} = test_server:start_node(list_to_atom(Name), - slave, - [{args, "-pa " ++ Pa ++ " " ++ Args}]), - Node. - id(I) -> I. diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl index 1759a464e246..dd6b0311b126 100644 --- a/erts/emulator/test/erts_test_utils.erl +++ b/erts/emulator/test/erts_test_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2020. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -19,7 +19,7 @@ %% -module(erts_test_utils). --compile(r20). +-compile(r22). %% %% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE @@ -29,7 +29,8 @@ mk_ext_port/2, mk_ext_ref/2, available_internal_state/1, - check_node_dist/0, check_node_dist/1, check_node_dist/3]). + check_node_dist/0, check_node_dist/1, check_node_dist/3, + ept_check_leaked_nodes/1]). @@ -46,6 +47,8 @@ -define(V4_PORT_EXT, $x). -define(OLD_MAX_PIDS_PORTS, ((1 bsl 28) - 1)). +-define(OLD_MAX_PID_NUM, ((1 bsl 15) - 1)). +-define(OLD_MAX_PID_SER, ((1 bsl 13) - 1)). uint64_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 64 -> [(Uint bsr 56) band 16#ff, @@ -78,27 +81,52 @@ uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> uint8(Uint) -> exit({badarg, uint8, [Uint]}). -pid_tag(bad_creation) -> ?PID_EXT; -pid_tag(Creation) when Creation =< 3 -> ?PID_EXT; -pid_tag(_Creation) -> ?NEW_PID_EXT. - -enc_creation(bad_creation) -> uint8(4); -enc_creation(Creation) when Creation =< 3 -> uint8(Creation); -enc_creation(Creation) -> uint32_be(Creation). +pid_tag(_, _, bad_creation) -> + ?PID_EXT; +pid_tag(Num, Ser, Creation) when Num =< ?OLD_MAX_PID_NUM, + Ser =< ?OLD_MAX_PID_SER, + Creation =< 3 -> + ?PID_EXT; +pid_tag(_Num, _Ser, _Creation) -> + ?NEW_PID_EXT. + +enc_creation(_, bad_creation) -> + uint8(4); +enc_creation(Num, Creation) when is_integer(Num), + Num =< ?OLD_MAX_PIDS_PORTS, + Creation =< 3 -> + uint8(Creation); +enc_creation(Nums, Creation) when is_list(Nums), + length(Nums) =< 3, + Creation =< 3 -> + uint8(Creation); +enc_creation(_Num, Creation) -> + uint32_be(Creation). + +enc_creation(_, _, bad_creation) -> + uint8(4); +enc_creation(Num, Ser, Creation) when Num =< ?OLD_MAX_PID_NUM, + Ser =< ?OLD_MAX_PID_SER, + Creation =< 3 -> + uint8(Creation); +enc_creation(_Num, _Ser, Creation) -> + uint32_be(Creation). mk_ext_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> mk_ext_pid({atom_to_list(NodeName), Creation}, Number, Serial); mk_ext_pid({NodeName, Creation}, Number, Serial) -> case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - pid_tag(Creation), + pid_tag(Number, Serial, Creation), ?ATOM_EXT, uint16_be(length(NodeName)), NodeName, uint32_be(Number), uint32_be(Serial), - enc_creation(Creation)])) of + enc_creation(Number, Serial, Creation)])) of Pid when is_pid(Pid) -> Pid; + {'EXIT', {badarg, uint32_be, _}} -> + exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); {'EXIT', {badarg, _}} -> exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); Other -> @@ -126,21 +154,23 @@ mk_ext_port({NodeName, Creation}, Number) -> true -> uint64_be(Number); false -> uint32_be(Number) end, - enc_creation(Creation)])) of + enc_creation(Number, Creation)])) of Port when is_port(Port) -> Port; + {'EXIT', {badarg, Uint, _}} when Uint == uint64_be; Uint == uint32_be -> + exit({badarg, mk_port, [{NodeName, Creation}, Number]}); {'EXIT', {badarg, _}} -> exit({badarg, mk_port, [{NodeName, Creation}, Number]}); Other -> exit({unexpected_binary_to_term_result, Other}) end. -ref_tag(bad_creation) -> ?NEW_REFERENCE_EXT; -ref_tag(Creation) when Creation =< 3 -> ?NEW_REFERENCE_EXT; -ref_tag(_Creation) -> ?NEWER_REFERENCE_EXT. +ref_tag(_Nums, bad_creation) -> ?NEW_REFERENCE_EXT; +ref_tag(Nums, Creation) when length(Nums) =< 3, Creation =< 3 -> ?NEW_REFERENCE_EXT; +ref_tag(_Nums, _Creation) -> ?NEWER_REFERENCE_EXT. mk_ext_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), - is_list(Numbers) -> + is_list(Numbers) -> mk_ext_ref({atom_to_list(NodeName), Creation}, Numbers); mk_ext_ref({NodeName, Creation}, [Number]) when is_list(NodeName), Creation =< 3, @@ -162,12 +192,12 @@ mk_ext_ref({NodeName, Creation}, [Number]) when is_list(NodeName), mk_ext_ref({NodeName, Creation}, Numbers) when is_list(NodeName), is_list(Numbers) -> case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ref_tag(Creation), + ref_tag(Numbers, Creation), uint16_be(length(Numbers)), ?ATOM_EXT, uint16_be(length(NodeName)), NodeName, - enc_creation(Creation), + enc_creation(Numbers, Creation), lists:map(fun (N) -> uint32_be(N) end, @@ -292,3 +322,21 @@ check_refc(ThisNodeName,ThisCreation,Table,EntryList) when is_list(EntryList) -> end, EntryList), ok. + +%% To be called by end_per_testcase +%% to check and kill leaked node connections. +ept_check_leaked_nodes(Config) -> + case nodes(connected) of + [] -> ok; + Nodes -> + [net_kernel:disconnect(N) || N <- Nodes], + Leaked = {"Leaked connections", Nodes}, + Fail = case proplists:get_value(tc_status, Config) of + ok -> Leaked; + {failed, Reason} -> + [Reason, {end_per_testcase, Leaked}]; + {skipped, _}=Skipped -> + [Skipped, {end_per_testcase, Leaked}] + end, + {fail, Fail} + end. diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl index 967e25f10970..0568900afd23 100644 --- a/erts/emulator/test/estone_SUITE.erl +++ b/erts/emulator/test/estone_SUITE.erl @@ -279,12 +279,12 @@ micro(int_arith) -> #micro{function = int_arith, weight = 3, loops = 4157, - str = "Small Integer arithmetics"}; + str = "Small Integer arithmetic"}; micro(float_arith) -> #micro{function = float_arith, weight = 1, loops = 5526, - str = "Float arithmetics"}; + str = "Float arithmetic"}; micro(fcalls) -> #micro{function = fcalls, weight = 5, diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl index 715299520572..38beb7c32e62 100644 --- a/erts/emulator/test/exception_SUITE.erl +++ b/erts/emulator/test/exception_SUITE.erl @@ -21,6 +21,7 @@ -module(exception_SUITE). -export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2, badmatch/1, pending_errors/1, nil_arith/1, top_of_stacktrace/1, stacktrace/1, nested_stacktrace/1, raise/1, gunilla/1, per/1, change_exception_class/1, @@ -51,6 +52,11 @@ all() -> error_3, error_info, no_line_numbers, line_numbers]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + -define(try_match(E), catch ?MODULE:bar(), {'EXIT', {{badmatch, nomatch}, _}} = (catch E = id(nomatch))). @@ -163,7 +169,7 @@ pending({Code,[{?MODULE,Func,Arity,Loc}|_]}, Func, Args, Code) pending(Reason, _Function, _Args, _Code) -> ct:fail({bad_exit_reason,Reason}). -%% Test that doing arithmetics on [] gives a badarith EXIT and not a crash. +%% Test that doing arithmetic on [] gives a badarith EXIT and not a crash. nil_arith(Config) when is_list(Config) -> ba_plus_minus_times([], []), @@ -697,7 +703,7 @@ error_info(_Config) -> end, %% Pick up external pid and port. - {ok, ExternalNode} = test_server:start_node(?FUNCTION_NAME, slave, []), + {ok, Peer, ExternalNode} = ?CT_PEER(), ExternalPid = rpc:call(ExternalNode, erlang, whereis, [code_server]), ExternalPort = hd(rpc:call(ExternalNode, erlang, ports, [])), @@ -838,6 +844,8 @@ error_info(_Config) -> {display, ["test erlang:display/1"], [no_fail]}, {display_string, [{a,b,c}]}, + {display_string, [standard_out,"test erlang:display/2"]}, + {display_string, [stdout,{a,b,c}]}, %% Internal undcoumented BIFs. {dist_ctrl_get_data, 1}, @@ -1026,7 +1034,21 @@ error_info(_Config) -> {nif_error, 1}, {nif_error, 2}, {node, [abc]}, - {nodes, [abc]}, + {nodes, [abc], [{1, ".*not a valid node type.*"}]}, + {nodes, [[abc]], [{1, ".*not a list of.*"}]}, + {nodes, [DeadProcess], [{1, ".*not a valid node type or list of valid node types.*"}]}, + {nodes, [abc, 17], [{1, ".*not a valid node type.*"},{2, ".*not a map.*"}]}, + {nodes, [hidden, 17], [{2, ".*not a map.*"}]}, + {nodes, [hidden, #{ 17 => true }], [{2, ".*invalid options in map.*"}]}, + {nodes, [hidden, #{ connection_id => 17 }], [{2, ".*invalid options in map.*"}]}, + {nodes, [hidden, #{ node_type => 17 }], [{2, ".*invalid options in map.*"}]}, + {nodes, [abc, #{}], [{1, ".*not a valid node type.*"}]}, + {nodes, [DeadProcess,#{node_type=>true}], [{1, ".*not a valid node type or list of valid node types.*"}]}, + {nodes, [visible, 17], [{2,".*not a map.*"}]}, + {nodes, [visible, #{connection_id=>blapp}], [{2,".*invalid options in map.*"}]}, + {nodes, [visible, 17], [{2,".*not a map.*"}]}, + {nodes, [known, #{connection_id=>true,node_type=>true}], [no_fail]}, + {nodes, [[this,connected], #{connection_id=>true,node_type=>true}], [no_fail]}, {phash, [any, -1]}, {phash, [any, not_integer]}, {phash2, [any], [no_fail]}, @@ -1312,7 +1334,7 @@ error_info(_Config) -> try do_error_info(L) after - test_server:stop_node(ExternalNode) + peer:stop(Peer) end. dead_process() -> @@ -1441,11 +1463,23 @@ line_numbers(Config) when is_list(Config) -> [{file,"fake_file.erl"},{line,3}]}, {?MODULE,line_numbers,1,_}|_]}} = (catch line1(bad_tag, 0)), - {'EXIT',{badarith, - [{?MODULE,line1,2, - [{file,"fake_file.erl"},{line,5}]}, - {?MODULE,line_numbers,1,_}|_]}} = - (catch line1(a, not_an_integer)), + + %% The stacktrace for operators such a '+' can vary depending on + %% whether the JIT is used or not. + case catch line1(a, not_an_integer) of + {'EXIT',{badarith, + [{erlang,'+',[not_an_integer,1],_}, + {?MODULE,line1,2, + [{file,"fake_file.erl"},{line,5}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok; + {'EXIT',{badarith, + [{?MODULE,line1,2, + [{file,"fake_file.erl"},{line,5}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok + end, + {'EXIT',{{badmatch,{ok,1}}, [{?MODULE,line1,2, [{file,"fake_file.erl"},{line,7}]}, @@ -1478,7 +1512,7 @@ line_numbers(Config) when is_list(Config) -> <<0,0>> = build_binary1(16), {'EXIT',{badarg, [{?MODULE,build_binary1,1, - [{file,"bit_syntax.erl"},{line,72503}]}, + [{file,"bit_syntax.erl"},{line,72503},{error_info,_}]}, {?MODULE,line_numbers,1, [{file,ModFile},{line,_}]}|_]}} = (catch build_binary1(bad_size)), @@ -1486,21 +1520,20 @@ line_numbers(Config) when is_list(Config) -> <<7,1,2,3>> = build_binary2(8, <<1,2,3>>), {'EXIT',{badarg, [{?MODULE,build_binary2,2, - [{file,"bit_syntax.erl"},{line,72507}]}, + [{file,"bit_syntax.erl"},{line,72507},{error_info,_}]}, {?MODULE,line_numbers,1, [{file,ModFile},{line,_}]}|_]}} = (catch build_binary2(bad_size, <<>>)), {'EXIT',{badarg, - [{erlang,bit_size,[bad_binary],[{error_info,_}]}, - {?MODULE,build_binary2,2, - [{file,"bit_syntax.erl"},{line,72507}]}, + [{?MODULE,build_binary2,2, + [{file,"bit_syntax.erl"},{line,72507},{error_info,_}]}, {?MODULE,line_numbers,1, [{file,ModFile},{line,_}]}|_]}} = (catch build_binary2(8, bad_binary)), <<"abc",357:16>> = build_binary3(<<"abc">>), {'EXIT',{badarg,[{?MODULE,build_binary3,1, - [{file,"bit_syntax.erl"},{line,72511}]}, + [{file,"bit_syntax.erl"},{line,72511},{error_info,_}]}, {?MODULE,line_numbers,1, [{file,ModFile},{line,_}]}|_]}} = (catch build_binary3(no_binary)), @@ -1529,14 +1562,29 @@ line_numbers(Config) when is_list(Config) -> {?MODULE,line_numbers,1,_}|_]}} = (catch applied_bif_2()), - {'EXIT',{badarith, - [{?MODULE,increment1,1,[{file,"increment.erl"},{line,45}]}, - {?MODULE,line_numbers,1,_}|_]}} = - (catch increment1(x)), - {'EXIT',{badarith, - [{?MODULE,increment2,1,[{file,"increment.erl"},{line,48}]}, - {?MODULE,line_numbers,1,_}|_]}} = - (catch increment2(x)), + case catch increment1(x) of + {'EXIT',{badarith, + [{erlang,'+',[x,1],_}, + {?MODULE,increment1,1,[{file,"increment.erl"},{line,45}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok; + {'EXIT',{badarith, + [{?MODULE,increment1,1,[{file,"increment.erl"},{line,45}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok + end, + + case catch increment2(x) of + {'EXIT',{badarith, + [{erlang,'+',[x,1],_}, + {?MODULE,increment2,1,[{file,"increment.erl"},{line,48}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok; + {'EXIT',{badarith, + [{?MODULE,increment2,1,[{file,"increment.erl"},{line,48}]}, + {?MODULE,line_numbers,1,_}|_]}} -> + ok + end, {'EXIT',{{badmap,not_a_map}, [{?MODULE,update_map,1,[{file,"map.erl"},{line,3}]}|_]}} = @@ -1561,6 +1609,21 @@ line_numbers(Config) when is_list(Config) -> {?MODULE,line_numbers,1,_}|_]}} = (catch crash_huge_line(gurka)), + {'EXIT',{{badrecord,[1,2,3]}, + [{?MODULE,bad_record,1,[{file,"bad_records.erl"},{line,4}]}|_]}} = + catch bad_record([1,2,3]), + + %% GH-5960: When an instruction raised an exception at the very end of the + %% instruction (e.g. badmatch), and was directly followed by a line + %% instruction, the exception was raised for the wrong line. + ok = ambiguous_line(0), + {'EXIT',{{badmatch,_}, + [{?MODULE,ambiguous_line,1,[{file,"ambiguous_line.erl"}, + {line,3}]}|_]}} = catch ambiguous_line(1), + {'EXIT',{{badmatch,_}, + [{?MODULE,ambiguous_line,1,[{file,"ambiguous_line.erl"}, + {line,4}]}|_]}} = catch ambiguous_line(2), + ok. id(I) -> I. @@ -1688,3 +1751,14 @@ foo() -> id(100). crash_huge_line(_) -> %Line 100000002 erlang:error(crash). %Line 100000003 + +-file("bad_records.erl", 1). +-record(foobar, {a,b,c,d}). %Line 2. +bad_record(R) -> %Line 3. + R#foobar.a. %Line 4. + +-file("ambiguous_line.erl", 1). +ambiguous_line(A) -> %Line 2. + true = A =/= 1, %Line 3. + true = A =/= 2, %Line 4. + ok. diff --git a/erts/emulator/test/float_SUITE.erl b/erts/emulator/test/float_SUITE.erl index 18d00e429fd9..e62f63db6f7f 100644 --- a/erts/emulator/test/float_SUITE.erl +++ b/erts/emulator/test/float_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -23,6 +23,7 @@ -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0, groups/0, + init_per_testcase/2, end_per_testcase/2, fpe/1,fp_drv/1,fp_drv_thread/1,denormalized/1,match/1, t_mul_add_ops/1,negative_zero/1, bad_float_unpack/1, write/1, cmp_zero/1, cmp_integer/1, cmp_bignum/1]). @@ -43,6 +44,11 @@ all() -> groups() -> [{comparison, [parallel], [cmp_zero, cmp_integer, cmp_bignum]}]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + %% %% OTP-7178, list_to_float on very small numbers should give 0.0 %% instead of exception, i.e. ignore underflow. @@ -65,10 +71,22 @@ negative_zero(Config) when is_list(Config) -> do_negative_zero(Op, Ops) -> Res = <<(my_apply(erlang, Op, Ops))/float>>, + + %% Test the canonical op against its mixed-type instruction Res = <<(case {Op, Ops} of {'-', [A]} -> -A; {'*', [A, B]} -> A * B end)/float>>, + + %% Test the canonical op against its type-specific instructions, if + %% applicable + Res = <<(case {Op, Ops} of + {'-', [C]} when is_float(C) -> -C; + {'-', [C]} -> -C; + {'*', [C, D]} when is_float(C), is_float(D) -> C * D; + {'*', [C, D]} -> C * D + end)/float>>, + Res. %% Forces floating point exceptions and tests that subsequent, legal, @@ -98,7 +116,7 @@ fp_drv_thread(Config) when is_list(Config) -> %% Run in a separate node since it used to crash the emulator... Parent = self(), DrvDir = proplists:get_value(data_dir, Config), - {ok,Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Tester = spawn_link(Node, fun () -> Parent ! @@ -107,7 +125,7 @@ fp_drv_thread(Config) when is_list(Config) -> DrvDir)} end), Result = receive {Tester, Res} -> Res end, - stop_node(Node), + peer:stop(Peer), Result. fp_drv_test(Test, DrvDir) -> @@ -192,7 +210,7 @@ cmp_zero(_Config) -> cmp(0.5e-323,0). cmp_integer(_Config) -> - Axis = (1 bsl 53)-2.0, %% The point where floating points become unprecise + Axis = (1 bsl 53)-2.0, %% The point where floating points become imprecise span_cmp(Axis,2,200), cmp(Axis*Axis,round(Axis)). @@ -285,23 +303,8 @@ cmp(Big,Small,BigGtSmall,BigLtSmall,SmallGtBig,SmallLtBig, id(I) -> I. -start_node(Config) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa}]). - -stop_node(Node) -> - test_server:stop_node(Node). - - %% Test that operations that might hide infinite intermediate results -%% do not supress the badarith. +%% do not suppress the badarith. hidden_inf(Config) when is_list(Config) -> ZeroP = 0.0, ZeroN = id(ZeroP) * (-1), @@ -410,7 +413,7 @@ my_apply(M, F, A) -> catch apply(id(M), id(F), A). % Unify exceptions be removing stack traces. -% and add argument info to make it easer to debug failed matches. +% and add argument info to make it easier to debug failed matches. unify({'EXIT',{Reason,_Stack}}, Info) -> {{'EXIT', Reason}, Info}; unify(Other, Info) -> diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 1a2c235d2791..0f8e7af9261c 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -21,6 +21,7 @@ -module(fun_SUITE). -export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2, bad_apply/1,bad_fun_call/1,badarity/1,ext_badarity/1, bad_arglist/1, equality/1,ordering/1, @@ -46,6 +47,12 @@ all() -> const_propagation, t_arity, t_is_function2, t_fun_info, t_fun_info_mfa,t_fun_to_list]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + + %% Test that the correct EXIT code is returned for all types of bad funs. bad_apply(Config) when is_list(Config) -> bad_apply_fc(42, [0]), @@ -574,11 +581,11 @@ refc_ets_bag(F1, Options) -> ok. refc_dist(Config) when is_list(Config) -> - {ok,Node} = start_node(fun_SUITE_refc_dist), + {ok, Peer, Node} = ?CT_PEER(), process_flag(trap_exit, true), Pid = spawn_link(Node, fun() -> receive Fun when is_function(Fun) -> - 2 = fun_refc(Fun), + 3 = fun_refc(Fun), exit({normal,Fun}) end end), F = fun() -> 42 end, @@ -595,13 +602,13 @@ refc_dist(Config) when is_list(Config) -> true = erlang:garbage_collect(), 2 = fun_refc(F), refc_dist_send(Node, F), - test_server:stop_node(Node). + peer:stop(Peer). refc_dist_send(Node, F) -> Pid = spawn_link(Node, fun() -> receive {To,Fun} when is_function(Fun) -> wait_until(fun () -> - 2 =:= fun_refc(Fun) + 3 =:= fun_refc(Fun) end), To ! Fun end @@ -629,7 +636,7 @@ refc_dist_reg_send(Node, F) -> Me ! Ref, receive {Me,Fun} when is_function(Fun) -> - 2 = fun_refc(Fun), + 3 = fun_refc(Fun), Me ! Fun end end), @@ -652,7 +659,7 @@ fun_refc(F) -> Count. const_propagation(Config) when is_list(Config) -> - Fun1 = fun start_node/1, + Fun1 = fun wait_until/1, 2 = fun_refc(Fun1), Fun2 = Fun1, my_cmp({Fun1,Fun2}), @@ -678,14 +685,14 @@ t_arity(Config) when is_list(Config) -> %% Test that the arity is transferred properly. process_flag(trap_exit, true), - {ok,Node} = start_node(fun_test_arity), + {ok, Peer, Node} = ?CT_PEER(), hello_world = spawn_call(Node, fun() -> hello_world end), 0 = spawn_call(Node, fun(X) -> X end), 42 = spawn_call(Node, fun(_X) -> A end), 43 = spawn_call(Node, fun(X, Y) -> A+X+Y end), 1 = spawn_call(Node, fun(X, Y) -> X+Y end), 45 = spawn_call(Node, fun(X, Y, Z) -> A+X+Y+Z end), - test_server:stop_node(Node), + peer:stop(Peer), ok. t_is_function2(Config) when is_list(Config) -> @@ -868,12 +875,6 @@ fun_arity(F) -> {arity,Arity} = erlang:fun_info(F, arity), Arity. -start_node(Name) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = atom_to_list(erlang:get_cookie()), - test_server:start_node(Name, slave, - [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]). - wait_until(Fun) -> case catch Fun() of true -> ok; diff --git a/erts/emulator/test/gc_SUITE.erl b/erts/emulator/test/gc_SUITE.erl index 6d0c8e0f934b..4a9e98da9b7b 100644 --- a/erts/emulator/test/gc_SUITE.erl +++ b/erts/emulator/test/gc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -32,6 +32,7 @@ grow_stack/1, grow_stack_heap/1, max_heap_size/1, + max_heap_size_large_hfrag/1, minor_major_gc_option_async/1, minor_major_gc_option_self/1, gc_signal_order/1, @@ -44,6 +45,7 @@ suite() -> all() -> [grow_heap, grow_stack, grow_stack_heap, max_heap_size, + max_heap_size_large_hfrag, minor_major_gc_option_self, minor_major_gc_option_async, gc_signal_order, gc_dirty_exec_proc, alias_signals_in_gc]. @@ -206,6 +208,30 @@ long_receive() -> ok end. +%% Trigger gc-after-bif with a large heap fragment, which provoked some bugs. +max_heap_size_large_hfrag(Config) -> + max_heap_size_large_hfrag_do(), + %% Repeat with major GC + process_flag(fullsweep_after, 0), + max_heap_size_large_hfrag_do(), + ok. + +max_heap_size_large_hfrag_do() -> + {Pid, Ref} = + spawn_opt( + fun Fun() -> + erlang:make_tuple(2000, []), + Fun() + end, + [monitor, {max_heap_size, 1000}]), + %% Verify that max heap was triggered + {'DOWN', Ref, process, Pid, killed} = + receive M -> M + after 5000 -> + ct:fail({process_did_not_die, Pid, erlang:process_info(Pid)}) + end, + ok. + minor_major_gc_option_self(_Config) -> %% Try as major, the test process will self-trigger GC check_gc_tracing_around( @@ -346,13 +372,13 @@ check_no_unexpected_messages() -> end. alias_signals_in_gc(Config) when is_list(Config) -> - %% Make sure alias signals in rootset wont cause + %% Make sure alias signals in rootset won't cause %% crashes... process_flag(scheduler, 1), process_flag(priority, normal), process_flag(message_queue_data, on_heap), Alias = alias(), - %% We deactive the alias since it is no point converting + %% We deactivate the alias since it is no point converting %% the alias signals into messages for this test... unalias(Alias), Pid = spawn_opt(fun () -> diff --git a/erts/emulator/test/guard_SUITE.erl b/erts/emulator/test/guard_SUITE.erl index f2c15953926b..5bf6871f8c09 100644 --- a/erts/emulator/test/guard_SUITE.erl +++ b/erts/emulator/test/guard_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2017. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -310,7 +310,7 @@ guard_bifs(Config) when is_list(Config) -> Big = -237849247829874297658726487367328971246284736473821617265433, Float = 387924.874, - %% Succeding use of guard bifs. + %% Succeeding use of guard bifs. try_gbif('abs/1', Big, -Big), try_gbif('float/1', Big, float(Big)), @@ -391,6 +391,18 @@ guard_bifs(Config) when is_list(Config) -> try_fail_gbif('node/0', 0, xxxx), try_fail_gbif('node/1', self(), xxx), try_fail_gbif('node/1', yyy, xxx), + + {'EXIT', {function_clause, _}} = catch gh_6634({a,b}), + {'EXIT', {function_clause, _}} = catch gh_6634(42), + + ok. + +gh_6634(X) when is_tuple(X) andalso not ok -> + %% `not ok` would be translated to an is_eq_exact instruction, + %% which the JIT would not handle correctly because it had two + %% immediate operands. In a release build incorrect code would be + %% generated, which might crash the runtime system; in a debug + %% build an assertion would fire at load time. ok. try_gbif(Id, X, Y) -> diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl index ae451a05bd75..90b96f2f97e5 100644 --- a/erts/emulator/test/hash_SUITE.erl +++ b/erts/emulator/test/hash_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -21,7 +21,7 @@ %% %% Verifying erlang:phash/2. And now also phash2/2, to some extent. %% Test the hashing algorithm for integer numbers in 2 ways: -%% 1 Test that numbers in diferent sequences get sufficiently spread +%% 1 Test that numbers in different sequences get sufficiently spread %% in a "bit pattern" way (modulo 256 etc). %% 2 Test that numbers are correctly hashed compared to a reference implementation, %% regardless of their internal representation. The hashing algorithm should never @@ -95,6 +95,7 @@ notify(X) -> test_basic/1,test_cmp/1,test_range/1,test_spread/1, test_phash2/1,otp_5292/1,bit_level_binaries/1,otp_7127/1, test_hash_zero/1, init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2, init_per_group/2, end_per_group/2]). suite() -> @@ -169,6 +170,10 @@ init_per_group(_, Config) -> end_per_group(_, Config) -> Config. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). %% Tests basic functionality of erlang:phash and that the %% hashes has not changed (neither hash nor phash) @@ -219,7 +224,7 @@ notify(X) -> %% basic_test() -> 685556714 = erlang:phash({a,b,c},16#FFFFFFFF), - 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,3), + 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,0), 16#77777777777777],16#FFFFFFFF), ExternalReference = <<131,114,0,3,100,0,13,110,111,110,111,100,101,64, 110,111,104,111,115,116,0,0,0,0,122,0,0,0,0,0,0,0,0>>, @@ -557,38 +562,41 @@ last_byte(Bin) -> <<_:NotLastByteSize/bitstring, LastByte:8>> = Bin, LastByte. + +%% This testcase needs 8-10 GB of free memory. If not enough is available +%% the testcase will fail with {erpc,noconnection} test_phash2_4GB_plus_bin(Config) when is_list(Config) -> run_when_enough_resources( fun() -> - {ok, N} = start_node(?FUNCTION_NAME), + {ok, Peer, N} = ?CT_PEER(), erpc:call(N, fun() -> - erts_debug:set_internal_state(available_internal_state, true), - %% Created Bin4GB here so it only needs to be created once - erts_debug:set_internal_state(force_gc, self()), - Bin4GB = get_4GB_bin(), - test_phash2_plus_bin_helper1(Bin4GB, <<>>, <<>>, 13708901), - erts_debug:set_internal_state(force_gc, self()), - test_phash2_plus_bin_helper1(Bin4GB, <<>>, <<3:5>>, 66617678), - erts_debug:set_internal_state(force_gc, self()), - test_phash2_plus_bin_helper1(Bin4GB, <<13>>, <<>>, 31308392), - erts_debug:set_internal_state(force_gc, self()), - erts_debug:set_internal_state(available_internal_state, false) + test_phash2_4GB_plus_bin_tc() end), - stop_node(N) + peer:stop(Peer) end). +test_phash2_4GB_plus_bin_tc() -> + erts_debug:set_internal_state(available_internal_state, true), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_4GB_bin/0, <<>>, <<>>, 13708901), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_4GB_bin/0, <<>>, <<3:5>>, 66617678), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_4GB_bin/0, <<13>>, <<>>, 31308392), + test_phash2_gc(), + erts_debug:set_internal_state(available_internal_state, false), + ok. test_phash2_10MB_plus_bin(Config) when is_list(Config) -> erts_debug:set_internal_state(available_internal_state, true), - erts_debug:set_internal_state(force_gc, self()), - Bin10MB = get_10MB_bin(), - test_phash2_plus_bin_helper1(Bin10MB, <<>>, <<>>, 22776267), - erts_debug:set_internal_state(force_gc, self()), - test_phash2_plus_bin_helper1(Bin10MB, <<>>, <<3:5>>, 124488972), - erts_debug:set_internal_state(force_gc, self()), - test_phash2_plus_bin_helper1(Bin10MB, <<13>>, <<>>, 72958346), - erts_debug:set_internal_state(force_gc, self()), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_10MB_bin/0, <<>>, <<>>, 22776267), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_10MB_bin/0, <<>>, <<3:5>>, 124488972), + test_phash2_gc(), + test_phash2_plus_bin_helper(fun get_10MB_bin/0, <<13>>, <<>>, 72958346), + test_phash2_gc(), erts_debug:set_internal_state(available_internal_state, false). get_10MB_bin() -> @@ -612,39 +620,86 @@ duplicate_iolist(IOList, 0) -> duplicate_iolist(IOList, NrOfTimes) -> duplicate_iolist([IOList, IOList], NrOfTimes - 1). -test_phash2_plus_bin_helper1(Bin4GB, ExtraBytes, ExtraBits, ExpectedHash) -> - test_phash2_plus_bin_helper2(Bin4GB, fun id/1, ExtraBytes, ExtraBits, ExpectedHash), - test_phash2_plus_bin_helper2(Bin4GB, fun make_unaligned_sub_bitstring/1, ExtraBytes, ExtraBits, ExpectedHash). -test_phash2_plus_bin_helper2(Bin, TransformerFun, ExtraBytes, ExtraBits, ExpectedHash) -> +%% This functions is written very carefully so that the binaries +%% created are released as quickly as possible. If they are not released +%% then the memory consumption going through the roof and systems will need +%% lots of memory. +test_phash2_plus_bin_helper(Bin4GB, ExtraBytes, ExtraBits, ExpectedHash) -> + ct:log("Test with ~p extra bytes and ~p extra bits", + [ExtraBytes, ExtraBits]), + test_phash2_plus_bin_helper(Bin4GB, fun id/1, ExtraBytes, ExtraBits, ExpectedHash), + ct:log("Test as unaligned sub bitstring"), + test_phash2_plus_bin_helper(Bin4GB, fun make_unaligned_sub_bitstring/1, + ExtraBytes, ExtraBits, ExpectedHash). +test_phash2_plus_bin_helper(Bin, TransformerFun, ExtraBytes, ExtraBits, ExpectedHash) -> + %% GC to free any binaries used by previous test cases + test_phash2_gc(), ExtraBitstring = << ExtraBytes/binary, ExtraBits/bitstring >>, LargerBitstring = << ExtraBytes/binary, ExtraBits/bitstring, - Bin/bitstring >>, + (Bin())/bitstring >>, + %% GC to free binary created by Bin() + test_phash2_gc(), LargerTransformedBitstring = TransformerFun(LargerBitstring), + %% GC to free binary LargerBitstring + test_phash2_gc(), ExtraBitstringHash = erlang:phash2(ExtraBitstring), ExpectedHash = case size(LargerTransformedBitstring) < 4294967296 of true -> - erts_debug:set_internal_state(force_gc, self()), erts_debug:set_internal_state(reds_left, 1), Hash = erlang:phash2(LargerTransformedBitstring), Hash = erlang:phash2(LargerTransformedBitstring), Hash; false -> - erts_debug:set_internal_state(force_gc, self()), erts_debug:set_internal_state(reds_left, 1), ExtraBitstringHash = erlang:phash2(LargerTransformedBitstring), ExtraBitstringHash = erlang:phash2(LargerTransformedBitstring), ExtraBitstringHash end. +test_phash2_gc() -> + erts_debug:set_internal_state(force_gc, self()), + wait_for_mseg_cache(10). + +%% We want to wait for the mseg cache to clear as otherwise the +%% extra refc binaries may still use memory and cause the system +%% to run out when it should not. +wait_for_mseg_cache(0) -> + io:format("Cached segments never became zero, continue anyways."); +wait_for_mseg_cache(N) -> + case get_cached_segments() of + 0 -> + %% We sleep an extra second in order for the OS to catch up + timer:sleep(1000); + NotZero -> + io:format("Cached segments = ~p, sleeping for 1 second~n", + [NotZero]), + timer:sleep(1000), + wait_for_mseg_cache(N-1) + end. + +get_cached_segments() -> + case erlang:system_info({allocator,mseg_alloc}) of + false -> + 0; + MsegInfo -> + lists:foldl( + fun({instance,_,Info}, Acc) -> + Kind = proplists:get_value(memkind, Info), + Status = proplists:get_value(status, Kind), + {cached_segments,Cached} = lists:keyfind(cached_segments, 1, Status), + Acc + Cached + end, 0, MsegInfo) + end. + run_when_enough_resources(Fun) -> Bits = 8 * erlang:system_info({wordsize,external}), Mem = total_memory(), Build = erlang:system_info(build_type), - if Bits =:= 64, is_integer(Mem), Mem >= 31, + if Bits =:= 64, is_integer(Mem), Mem >= 16, Build =/= valgrind, Build =/= asan -> Fun(); @@ -654,53 +709,22 @@ run_when_enough_resources(Fun) -> [Mem, Bits, Build])} end. -%% Total memory in GB total_memory() -> + %% Total memory in GB. try - MemoryData = memsup:get_system_memory_data(), - case lists:keysearch(total_memory, 1, MemoryData) of - {value, {total_memory, TM}} -> - TM div (1024*1024*1024); - false -> - {value, {system_total_memory, STM}} = - lists:keysearch(system_total_memory, 1, MemoryData), - STM div (1024*1024*1024) - end + SMD = memsup:get_system_memory_data(), + TM = proplists:get_value( + available_memory, SMD, + proplists:get_value( + total_memory, SMD, + proplists:get_value( + system_total_memory, SMD))), + TM div (1024*1024*1024) catch - _ : _ -> - undefined + _ : _ -> + undefined end. -start_node(X) -> - start_node(X, [], []). - -start_node(X, Y) -> - start_node(X, Y, []). - -start_node(Name, Args, Rel) when is_atom(Name), is_list(Rel) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = atom_to_list(erlang:get_cookie()), - RelArg = case Rel of - [] -> []; - _ -> [{erl,[{release,Rel}]}] - end, - test_server:start_node(Name, slave, - [{args, - Args++" -setcookie "++Cookie++" -pa \""++Pa++"\""} - | RelArg]); -start_node(Config, Args, Rel) when is_list(Config), is_list(Rel) -> - Name = list_to_atom((atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive])))), - start_node(Name, Args, Rel). - -stop_node(Node) -> - test_server:stop_node(Node). - -ifdef(FALSE). f1() -> abc. @@ -1257,9 +1281,18 @@ make_unaligned_sub_binary(Bin0) when is_binary(Bin0) -> <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), Bin. +%% This functions is written very carefully so that the bitstrings +%% created are released as quickly as possible. If they are not released +%% then the memory consumption going through the roof and systems will need +%% lots of memory. make_unaligned_sub_bitstring(Bin0) -> - Bin1 = <<0:3,Bin0/bitstring,31:5>>, Sz = erlang:bit_size(Bin0), + Bin1 = <<0:3,Bin0/bitstring,31:5>>, + make_unaligned_sub_bitstring2(Sz, Bin1). + +make_unaligned_sub_bitstring2(Sz, Bin1) -> + %% Make sure to release Bin0 if possible + erlang:garbage_collect(), <<0:3,Bin:Sz/bitstring,31:5>> = id(Bin1), Bin. diff --git a/erts/emulator/test/hash_property_test_SUITE.erl b/erts/emulator/test/hash_property_test_SUITE.erl index 70840037e797..f2d44e164baa 100644 --- a/erts/emulator/test/hash_property_test_SUITE.erl +++ b/erts/emulator/test/hash_property_test_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -30,8 +30,10 @@ -module(hash_property_test_SUITE). --export([suite/0,all/0,groups/0,init_per_suite/1, - end_per_suite/1,init_per_group/2,end_per_group/2]). +-export([suite/0,all/0,groups/0, + init_per_testcase/2, end_per_testcase/2, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2]). -export([test_phash2_no_diff/1, test_phash2_no_diff_long/1, @@ -69,6 +71,11 @@ init_per_group(_, Config) -> end_per_group(_, Config) -> Config. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + test_phash2_no_diff(Config) when is_list(Config) -> true = ct_property_test:quickcheck( phash2_properties:prop_phash2_same_with_same_input(), @@ -80,35 +87,16 @@ test_phash2_no_diff_long(Config) when is_list(Config) -> Config). test_phash2_no_diff_between_versions(Config) when is_list(Config) -> - R = "21", - case test_server:is_release_available(R) of - true -> - Rel = {release,R}, - %% We clear all ERL_FLAGS for the old node as all options may not - %% be supported. - ClearEnv = lists:foldl( - fun({Key,_Value}, Acc) -> - case re:run(Key,"^ERL_.*FLAGS$") of - {match,_} -> - [{Key,""}|Acc]; - nomatch -> - Acc - end - end, [], os:env()), - case test_server:start_node(rel21,peer,[{erl,[Rel]},{env,ClearEnv}]) of - {error, Reason} -> {skip, io_lib:format("Could not start node: ~p~n", [Reason])}; - {ok, Node} -> - try - true = ct_property_test:quickcheck( - phash2_properties:prop_phash2_same_in_different_versions(Node), - Config), - true = ct_property_test:quickcheck( - phash2_properties:prop_phash2_same_in_different_versions_with_long_input(Node), - Config) - after - test_server:stop_node(Node) - end - end; - false -> + R = integer_to_list(list_to_integer(erlang:system_info(otp_release))-2) ++ "_latest", + case ?CT_PEER_REL([], R, proplists:get_value(priv_dir, Config)) of + {ok, Peer, Node} -> + true = ct_property_test:quickcheck( + phash2_properties:prop_phash2_same_in_different_versions(Node), + Config), + true = ct_property_test:quickcheck( + phash2_properties:prop_phash2_same_in_different_versions_with_long_input(Node), + Config), + peer:stop(Peer); + not_available -> {skip, io_lib:format("Release ~s not available~n", [R])} end. diff --git a/erts/emulator/test/hello_SUITE_data/hello.erl b/erts/emulator/test/hello_SUITE_data/hello.erl index 7e77a71061c2..dc068d46215c 100644 --- a/erts/emulator/test/hello_SUITE_data/hello.erl +++ b/erts/emulator/test/hello_SUITE_data/hello.erl @@ -1662,7 +1662,7 @@ test_hibernate() -> maximum_hibernate_heap_size(Term) -> %% When hibernating, a few extra words will be allocated to hold the %% continuation pointer as well as scratch space for the interpreter/jit. - erts_debug:flat_size(Term) + 4. + erts_debug:flat_size(Term) + 8. hibernate_wake_up(0, _, _) -> ok; hibernate_wake_up(N, MaxHeapSz, Child) -> @@ -1891,12 +1891,12 @@ micro(int_arith) -> #micro{function = int_arith, weight = 3, loops = 4157, - str = "Small Integer arithmetics"}; + str = "Small Integer arithmetic"}; micro(float_arith) -> #micro{function = float_arith, weight = 1, loops = 5526, - str = "Float arithmetics"}; + str = "Float arithmetic"}; micro(fcalls) -> #micro{function = fcalls, weight = 5, diff --git a/erts/emulator/test/hibernate_SUITE.erl b/erts/emulator/test/hibernate_SUITE.erl index 6425e9c212f1..81b56ba7f84b 100644 --- a/erts/emulator/test/hibernate_SUITE.erl +++ b/erts/emulator/test/hibernate_SUITE.erl @@ -55,7 +55,7 @@ basic(Config) when is_list(Config) -> maximum_hibernate_heap_size(Term) -> %% When hibernating, a few extra words will be allocated to hold the %% continuation pointer as well as scratch space for the interpreter/jit. - erts_debug:size(Term) + 4. + erts_debug:size(Term) + 8. hibernate_wake_up(0, _, _) -> ok; hibernate_wake_up(N, MaxHeapSz, Child) -> @@ -188,7 +188,7 @@ min_heap_size(Config) when is_list(Config) -> {heap_size,HeapSz} = process_info(Child, heap_size), io:format("Heap size: ~p\n", [HeapSz]), if - HeapSz < 20 -> ok + HeapSz =< 20 -> ok end, Child ! wake_up, receive @@ -334,7 +334,7 @@ no_heap(Config) when is_list(Config) -> wait_until(fun () -> is_hibernated(H) end), [{heap_size, Size}, {total_heap_size, Size}] = process_info(H, [heap_size, total_heap_size]), - true = Size =< 4, + true = Size =< maximum_hibernate_heap_size(0), receive after 10 -> ok end, H ! again end, lists:seq(1, 100)), diff --git a/erts/emulator/test/hipe_SUITE_data/literals.erl b/erts/emulator/test/hipe_SUITE_data/literals.erl deleted file mode 100644 index 31e443970fae..000000000000 --- a/erts/emulator/test/hipe_SUITE_data/literals.erl +++ /dev/null @@ -1,26 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2016. 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(literals). - --export([a/0, b/0]). - -a() -> [a,b,c]. -b() -> {a,b,c}. diff --git a/erts/emulator/test/hipe_SUITE_data/ref_cell.erl b/erts/emulator/test/hipe_SUITE_data/ref_cell.erl deleted file mode 100644 index 2654e4077b4e..000000000000 --- a/erts/emulator/test/hipe_SUITE_data/ref_cell.erl +++ /dev/null @@ -1,64 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2016. 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(ref_cell). - --export([start_link/0, start_link_deep/0, call/2]). - --compile(native). - --define(DEPTH, 100). --define(ALLOCS, 500). - -start_link() -> - spawn_link(fun() -> loop(undefined) end). - -start_link_deep() -> - spawn_link(fun() -> go_deep(?DEPTH) end). - -%% Create a stack large enough to get a graylimit trap placed next time there's -%% a minor gc. -go_deep(0) -> - alloc_some(?ALLOCS), - loop(undefined), - 0; -go_deep(Depth) -> - go_deep(Depth-1)+1. - -%% Do some allocation to trigger a minor gc -alloc_some(Amount) -> - Check = (Amount * (Amount + 1)) div 2, - Check = lists:sum(lists:seq(1, Amount)). - -call(Pid, Call) -> - Pid ! {Call, self()}, - receive {Pid, Res} -> Res end. - -loop(Thing) -> - receive - {done, Pid} -> Pid ! {self(), done}; - {{put_res_of, Fun}, Pid} -> - NewThing = Fun(), - Pid ! {self(), put}, - loop(NewThing); - {get, Pid} -> - Pid ! {self(), Thing}, - loop(Thing) - end. diff --git a/erts/emulator/test/hipe_SUITE_data/trycatch_1.erl b/erts/emulator/test/hipe_SUITE_data/trycatch_1.erl deleted file mode 100644 index f7d0e3bd1e36..000000000000 --- a/erts/emulator/test/hipe_SUITE_data/trycatch_1.erl +++ /dev/null @@ -1,13 +0,0 @@ --module(trycatch_1). --export([one_try_catch/1,one_plain_catch/1]). - -one_try_catch(Term) -> - try - trycatch_2:two(Term) - catch - C:R:Stk -> - {C,R,Stk} - end. - -one_plain_catch(Term) -> - catch trycatch_2:two(Term). diff --git a/erts/emulator/test/hipe_SUITE_data/trycatch_2.erl b/erts/emulator/test/hipe_SUITE_data/trycatch_2.erl deleted file mode 100644 index ffac42019711..000000000000 --- a/erts/emulator/test/hipe_SUITE_data/trycatch_2.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(trycatch_2). --export([two/1]). - -two(Term) -> - Res = trycatch_3:three(Term), - foo(), - Res. - -foo() -> - ok. diff --git a/erts/emulator/test/hipe_SUITE_data/trycatch_3.erl b/erts/emulator/test/hipe_SUITE_data/trycatch_3.erl deleted file mode 100644 index 578fa0e87e60..000000000000 --- a/erts/emulator/test/hipe_SUITE_data/trycatch_3.erl +++ /dev/null @@ -1,9 +0,0 @@ --module(trycatch_3). --export([three/1]). - -three({error,Term}) -> - error(Term); -three({throw,Term}) -> - throw(Term); -three({exit,Term}) -> - exit(Term). diff --git a/erts/emulator/test/jit_SUITE.erl b/erts/emulator/test/jit_SUITE.erl new file mode 100644 index 000000000000..efd44d31edd0 --- /dev/null +++ b/erts/emulator/test/jit_SUITE.erl @@ -0,0 +1,286 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2023. 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(jit_SUITE). + +-export([suite/0, groups/0, all/0, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + init_per_testcase/2, end_per_testcase/2]). +-export([annotate/1, jmsingle/1, named_labels/1, symbols/1]). + +suite() -> + [{timetrap, {minutes, 4}}]. + +groups() -> + [{perf, [symbols, annotate]}]. + +all() -> + [{group, perf}, jmsingle, named_labels]. + +init_per_suite(Config) -> + case erlang:system_info(emu_flavor) of + jit -> + Config; + _ -> + {skip, "No point in running JIT tests on non-JIT emulator"} + end. + +end_per_suite(_Config) -> + ok. + +init_per_group(perf, Config) -> + case os:find_executable("perf") of + false -> + {skip, "perf not found"}; + _Perf -> + PerfVsn = os:cmd("perf version"), + case re:run(PerfVsn, "perf version (\\d+)\\.(\\d+)", + [{capture,all_but_first,list}]) of + {match,[Major0,Minor0]} -> + Major = list_to_integer(Major0), + Minor = list_to_integer(Minor0), + if + Major > 5; Major =:= 5, Minor >= 11 -> + BuildIdDir = "--buildid-dir " ++ + filename:join( + proplists:get_value(priv_dir, Config), + ".debug"), + DataFile = filename:join( + proplists:get_value(priv_dir, Config), + "init_test.data"), + Cmd = "perf " ++ BuildIdDir ++ " record -q -o " ++ DataFile ++ " ls", + os:cmd(Cmd), + Script = os:cmd("perf " ++ BuildIdDir ++ " script -i " ++ DataFile), + ct:log("~ts",[Script]), + case re:run(Script, "^\\W+ls",[multiline]) of + {match, _} -> + [{sobefore,get_tmp_so_files()}, + {buildiddir,BuildIdDir}|Config]; + nomatch -> + {skip, "could not run `"++ Cmd ++"`"} + end; + true -> + {skip,"too old perf version: " ++ PerfVsn} + end; + _ -> + {skip,"unknown old perf version: " ++ PerfVsn} + end + end; +init_per_group(_, Config) -> + Config. + +end_per_group(perf, Config) -> + %% perf inject writes data to /tmp and ~/.debug/tmp so we need to clean + %% that up after the tests are done. + SoToDelete = get_tmp_so_files() -- proplists:get_value(sobefore, Config), + lists:foreach( + fun(File) -> + case file:delete(File) of + {error,eperm} -> + ok = file:del_dir_r(File); + ok -> + ok + end + end, SoToDelete), + ok; +end_per_group(_, _Config) -> + ok. + +init_per_testcase(named_labels, Config) -> + %% Only run named_labels on platforms where we know it works. + case erlang:system_info(system_architecture) of + "x86" ++ _ -> + [{asmbefore,get_tmp_asm_files()}|Config]; + "aarch64" ++ _ -> + [{asmbefore,get_tmp_asm_files()}|Config]; + _ -> + {skip, "Unsupported architecture"} + end; +init_per_testcase(_Case, Config) -> + Config. + +end_per_testcase(named_labels, Config) -> + AsmToDelete = get_tmp_asm_files() -- proplists:get_value(asmbefore, Config), + lists:foreach( + fun(File) -> + ok = file:delete(File) + end, AsmToDelete), + ok; +end_per_testcase(_, _Config) -> + ok. + +get_tmp_so_files() -> + {ok, Home} = init:get_argument(home), + filelib:wildcard("/tmp/jitted-*.so") ++ + filelib:wildcard(filename:join([Home,".debug","tmp","jitted-*.so"])). + +symbols(Config) -> + BuildIdDir = proplists:get_value(buildiddir, Config), + DataFile = filename:join( + proplists:get_value(priv_dir, Config), + atom_to_list(?FUNCTION_NAME) ++ ".data"), + os:cmd("perf "++ BuildIdDir ++" record -q -o " ++ DataFile ++ " " ++ + "erl +S 1 +JPperf true -noshell -eval '[lists:seq(1,10000) || _ <- lists:seq(1,1000)].' -s init stop"), + Script = os:cmd("perf "++ BuildIdDir ++" script -i " ++ DataFile), + case re:run(Script,"\\$lists:seq[^/]+/[0-9]",[global,{capture,first,list}]) of + {match,Matches} -> + ct:log("Found these symbols: ~p",[lists:usort(Matches)]), + ok; + nomatch -> + ct:fail("Did not find lists:seq symbol in:~n~ts",[Script]) + end. + +annotate(Config) -> + BuildIdDir = proplists:get_value(buildiddir, Config), + DataFile = filename:join( + proplists:get_value(priv_dir, Config), + atom_to_list(?FUNCTION_NAME) ++ ".data"), + os:cmd("perf "++ BuildIdDir ++" record -k mono -q -o " ++ DataFile ++ " " ++ + "erl +S 1 +JPperf true -noshell -eval '[lists:seq(1,10000) || _ <- lists:seq(1,1000)].' -s init stop"), + Script = os:cmd("perf "++ BuildIdDir ++" script -i " ++ DataFile), + + %% When doing "perf inject" the symbol of each function is changed + %% from $lists:seq_loop/3 to lists:seq_loop/3. I don't know why that + %% is, seems like a very odd bug in perf... + {match, Symbols} = re:run(Script, "lists:seq[^/]+/[0-9]+", + [global,{capture,first,list}]), + [[Symbol]|_] = lists:usort(Symbols), + JitFile = DataFile ++ ".jit.data", + "" = os:cmd("perf "++ BuildIdDir ++" inject --jit -i " ++ DataFile ++ " -o " ++ JitFile), + Anno = os:cmd("perf "++ BuildIdDir ++" annotate --stdio -i " ++ JitFile ++ " " ++ Symbol ++ ""), + case re:run(Anno,"Disassembly of section .text:") of + {match,_} -> + case re:run(Anno, "lists\\.erl:\\d+") of + {match,_} -> + ok; + nomatch -> + ct:fail("Did not find source line annotation for ~ts.~n~ts", + [Symbol, Anno]) + end; + nomatch -> + ct:fail("Did not find disassembly for ~ts.~n~ts", + [Symbol, Anno]) + end. + +run_jmsingle_test(Param, ExpectSuccess, ErrorMsg) -> + Cmd = "erl +JMsingle " ++ Param ++ " -noshell " ++ + "-eval \"erlang:display(all_is_well),erlang:halt(0).\"", + Result = os:cmd(Cmd), + SuccessfulEmulatorStart = + case Result of + "all_is_well" ++ _ -> + true; + _ -> + Error = "Failed to allocate executable+writable memory", + case string:find(Result, Error) of + nomatch -> false; + _ -> internal_error + end + end, + case SuccessfulEmulatorStart of + ExpectSuccess -> + ok; + _ -> + ct:fail(ErrorMsg) + end. + +jmsingle(Config) -> + %% Smoke test to check that the emulator starts with the +JMsingle + %% true/false option and fails with a non-boolean, that is, we + %% parse the command line correctly. + case os:type() of + {_, BSD} when BSD =:= netbsd; + BSD =:= openbsd -> + %% +JMsingle true might not work on these platforms, and dump core + %% because the emulator cannot be started. + %% + %% Set the cwd to a temporary directory that we'll delete when the + %% test is done. + {ok, Cwd} = file:get_cwd(), + TestDir = filename:join(proplists:get_value(priv_dir, Config), + "jmsingle"), + ok = file:make_dir(TestDir), + try + ok = file:set_cwd(TestDir), + run_jmsingle_test("true", internal_error, + "Emulator did not print the correct diagnostic " + "(crashed?) with +JMsingle true") + after + file:set_cwd(Cwd), + file:del_dir_r(TestDir) + end; + {_, _} -> + run_jmsingle_test("true", true, + "Emulator did not start with +JMsingle true") + end, + run_jmsingle_test("false", true, + "Emulator did not start with +JMsingle false"), + run_jmsingle_test("broken", false, + "Emulator started with bad +JMsingle parameter"). + +get_tmp_asm_files() -> + {ok, Cwd} = file:get_cwd(), + filelib:wildcard(filename:join(Cwd, "*.asm")). + +named_labels(_Config) -> + %% Check that pretty printing of named labels is working. We do + %% that by loading this module in an emulator running with +JDdump + %% true and then checking that the produced jit_SUITE.asm contains + %% a label for each exported function. We also check that the + %% label for the non-exported function get_tmp_asm_files/0, which + %% is used by this test, is present. + Exports = proplists:get_value(exports, ?MODULE:module_info()), + ModName = atom_to_list(?MODULE), + ModulePath = filename:dirname(code:which(?MODULE)), + Cmd = "erl +JDdump true -noshell -pa " ++ ModulePath ++ " -eval \"" + ++ ModName ++ ":module_info(),erlang:halt(0).\"", + os:cmd(Cmd), + {ok, Cwd} = file:get_cwd(), + AsmFile = filename:join(Cwd, ModName ++ ".asm"), + {ok, Data} = file:read_file(AsmFile), + Expected = sets:from_list([ lists:flatten(io_lib:format("~p/~p", [N,A])) + || {N,A} <- Exports] + ++ ["get_tmp_asm_files/0"]), + StripSeqNo = fun(Lbl) -> + %% In the Arm JIT, labels have the form + %% @Mod:Name/Arity-SequenceNumber, so strip + %% out the Mod part and the sequence number + %% as we can't know anything about them. + case re:run(Lbl, "^.*\:(.*)-[0-9]*$", + [{capture,all_but_first,list}]) of + {match,[R]} -> R; + nomatch -> Lbl + end + end, + case re:run(Data, "^(.*)\:\n", + [global,multiline,{capture,all_but_first,list}]) of + {match,Labels} -> + Found = sets:from_list([ StripSeqNo(NA) || [NA] <- Labels]), + case sets:is_subset(Expected, Found) of + true -> + ok; + false -> + ct:fail("Expected ~p, found ~p", + [sets:to_list(Expected), sets:to_list(Found)]) + end; + _ -> + ct:fail("No labels found in assembly dump") + end. diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl index 323f9fc2d184..4cb246f093f5 100644 --- a/erts/emulator/test/lcnt_SUITE.erl +++ b/erts/emulator/test/lcnt_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017-2021. All Rights Reserved. +%% Copyright Ericsson AB 2017-2022. 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. @@ -194,6 +194,12 @@ remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) -> remove_untoggleable_locks(T); remove_untoggleable_locks([{nif_load, _, _, _} | T]) -> remove_untoggleable_locks(T); +remove_untoggleable_locks([{'crypto.ensure_engine_loaded', _, _, _} | T]) -> + %% Global lock used by crypto NIF + remove_untoggleable_locks(T); +remove_untoggleable_locks([{'init_curve_types', _, _, _} | T]) -> + %% Global lock used by crypto NIF + remove_untoggleable_locks(T); remove_untoggleable_locks([{'esock.gcnt', _, _, _} | T]) -> %% Global lock used by socket NIF remove_untoggleable_locks(T); diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl index b398e2270785..2e43e9ad5a69 100644 --- a/erts/emulator/test/list_bif_SUITE.erl +++ b/erts/emulator/test/list_bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -21,7 +21,8 @@ -module(list_bif_SUITE). -include_lib("common_test/include/ct.hrl"). --export([all/0, suite/0]). +-export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2]). -export([hd_test/1,tl_test/1,t_length/1,t_list_to_pid/1, t_list_to_ref/1, t_list_to_ext_pidportref/1, t_list_to_port/1,t_list_to_float/1,t_list_to_integer/1]). @@ -37,6 +38,11 @@ all() -> t_list_to_ref, t_list_to_ext_pidportref, t_list_to_float, t_list_to_integer]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + %% Tests list_to_integer and string:to_integer t_list_to_integer(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch list_to_integer("12373281903728109372810937209817320981321ABC")), @@ -44,14 +50,21 @@ t_list_to_integer(Config) when is_list(Config) -> 12373 = (catch list_to_integer("12373")), -12373 = (catch list_to_integer("-12373")), 12373 = (catch list_to_integer("+12373")), - {'EXIT',{badarg,_}} = ( catch list_to_integer(abc)), + {'EXIT',{badarg,_}} = (catch list_to_integer(abc)), {'EXIT',{badarg,_}} = (catch list_to_integer("")), {12373281903728109372810937209817320981321,"ABC"} = string:to_integer("12373281903728109372810937209817320981321ABC"), {-12373281903728109372810937209817320981321,"ABC"} = string:to_integer("-12373281903728109372810937209817320981321ABC"), {12,[345]} = string:to_integer([$1,$2,345]), - {error, badarg} = string:to_integer([$1,$2,a]), + {error,badarg} = string:to_integer([$1,$2,a]), {error,no_integer} = string:to_integer([$A]), {error,badarg} = string:to_integer($A), + + %% System limit. + Digits = lists:duplicate(11_000_000, $9), + {'EXIT',{system_limit,_}} = catch list_to_integer(Digits), + {'EXIT',{system_limit,_}} = catch list_to_integer(Digits, 16), + {error,system_limit} = string:to_integer(Digits), + ok. %% Test hd/1 with correct and incorrect arguments. @@ -143,7 +156,7 @@ t_list_to_ref(Config) when is_list(Config) -> %% Test list_to_pid/port/ref for external pids/ports/refs. t_list_to_ext_pidportref(Config) when is_list(Config) -> - {ok, Node} = slave:start(net_adm:localhost(), t_list_to_ext_pidportref), + {ok, Peer, Node} = ?CT_PEER(), Pid = rpc:call(Node, erlang, self, []), Port = hd(rpc:call(Node, erlang, ports, [])), Ref = rpc:call(Node, erlang, make_ref, []), @@ -175,27 +188,8 @@ t_list_to_ext_pidportref(Config) when is_list(Config) -> true = rpc:call(Node, erlang, '=:=', [Ref, Ref2]), true = rpc:call(Node, erlang, '==', [Ref, Ref2]), - %% Make sure no ugly comparison with 0-creation as wildcard is done. - Pid0 = make_0_creation(Pid), - Port0 = make_0_creation(Port), - Ref0 = make_0_creation(Ref), - false = (Pid =:= Pid0), - false = (Port =:= Port0), - false = (Ref =:= Ref0), - false = (Pid == Pid0), - false = (Port == Port0), - false = (Ref == Ref0), - - %% Check 0-creations are converted to local node creations - %% when sent to matching node name. - true = rpc:call(Node, erlang, '=:=', [Pid, Pid0]), - true = rpc:call(Node, erlang, '==', [Pid, Pid0]), - true = rpc:call(Node, erlang, '=:=', [Port, Port0]), - true = rpc:call(Node, erlang, '==', [Port, Port0]), - true = rpc:call(Node, erlang, '=:=', [Ref, Ref0]), - true = rpc:call(Node, erlang, '==', [Ref, Ref0]), - - slave:stop(Node), + + peer:stop(Peer), ok. -define(NEW_PID_EXT, 88). diff --git a/erts/emulator/test/literal_area_collector_test.erl b/erts/emulator/test/literal_area_collector_test.erl index 14583db88d59..d0b6fb382259 100644 --- a/erts/emulator/test/literal_area_collector_test.erl +++ b/erts/emulator/test/literal_area_collector_test.erl @@ -28,38 +28,29 @@ check_idle(Timeout) when is_integer(Timeout) > 0 -> ScaledTimeout = Timeout*test_server:timetrap_scale_factor(), Pid = find_literal_area_collector(), Start = erlang:monotonic_time(millisecond), - try - wait_for_idle_literal_collector(Pid, Start, ScaledTimeout, -1, 0) - catch - throw:done -> - ok - end. + Alias = alias(), + wait_for_idle_literal_collector(Pid, Alias, Start, ScaledTimeout). -wait_for_idle_literal_collector(Pid, Start, Timeout, NWaiting, WRedsStart) -> - {W, R} = case process_info(Pid, [status, reductions]) of - [{status, waiting}, {reductions, Reds}] -> - %% Assume that reds aren't bumped more than - %% 2 in order to service this process info - %% request... - case {NWaiting > 100, Reds - WRedsStart =< 2*NWaiting} of - {true, true} -> - throw(done); - {false, true} -> - {NWaiting+1, WRedsStart}; - _ -> - {0, Reds} - end; - _ -> - {-1, 0} - end, +wait_for_idle_literal_collector(Pid, Alias, Start, Timeout) -> + Ref = make_ref(), + Pid ! {get_status, Ref, Alias}, Now = erlang:monotonic_time(millisecond), - if Now - Start > Timeout -> - error({busy_literal_area_collecor_timout, Timeout}); - true -> - ok - end, - receive after 1 -> ok end, - wait_for_idle_literal_collector(Pid, Start, Timeout, W, R). + TMO = case Start + Timeout - Now of + TimeLeft when TimeLeft < 0 -> 0; + TimeLeft -> TimeLeft + end, + receive + {Ref, idle} -> + unalias(Alias), + ok; + {Ref, _} -> + receive after 10 -> ok end, + wait_for_idle_literal_collector(Pid, Alias, Start, Timeout) + after TMO -> + unalias(Alias), + receive {Ref, _} -> ok after 0 -> ok end, + error({busy_literal_area_collecor_timout, Timeout}) + end. find_literal_area_collector() -> case get('__literal_area_collector__') of diff --git a/erts/emulator/test/lttng_SUITE.erl b/erts/emulator/test/lttng_SUITE.erl index ceeff05e7555..1a0891184f9a 100644 --- a/erts/emulator/test/lttng_SUITE.erl +++ b/erts/emulator/test/lttng_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -71,10 +71,10 @@ init_per_testcase(Case, Config) -> ok = ensure_lttng_started(Name, Config), [{session, Name}|Config]. -end_per_testcase(Case, _Config) -> +end_per_testcase(Case, Config) -> Name = atom_to_list(Case), ok = ensure_lttng_stopped(Name), - ok. + erts_test_utils:ept_check_leaked_nodes(Config). %% Not tested yet %% org_erlang_otp:driver_process_exit @@ -298,14 +298,14 @@ chk_caller(Port, Callback, ExpectedCaller) -> ExpectedCaller = Caller end. -ets_load(Config) -> +ets_load(Config) when is_list(Config) -> %% Have to do on a fresh node to guarantee that carriers are created - {ok,Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Res = rpc:call(Node, ?MODULE, ets_load, []), - stop_node(Node), + peer:stop(Peer), Res. @@ -447,19 +447,3 @@ cmd(Cmd) -> io:format(">> ~ts~n", [Res]), {ok,Res}. -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl index 9399303f543c..ffb10b92854c 100644 --- a/erts/emulator/test/map_SUITE.erl +++ b/erts/emulator/test/map_SUITE.erl @@ -18,13 +18,14 @@ %% -module(map_SUITE). -export([all/0, suite/0, init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2, groups/0]). -export([t_build_and_match_literals/1, t_build_and_match_literals_large/1, t_update_literals/1, t_update_literals_large/1, t_match_and_update_literals/1, t_match_and_update_literals_large/1, t_update_map_expressions/1, - t_update_assoc/1, t_update_assoc_large/1, + t_update_assoc/1, t_update_assoc_large/1, t_update_assoc_sharing/1, t_update_exact/1, t_update_exact_large/1, t_guard_bifs/1, t_guard_sequence/1, t_guard_sequence_large/1, @@ -84,14 +85,23 @@ %% instruction-level tests t_has_map_fields/1, + t_get_map_elements/1, y_regs/1, - badmap_17/1, - %%Bugs - t_large_unequal_bins_same_hash_bug/1]). + %% Bugs + t_large_unequal_bins_same_hash_bug/1, + + %% Display + t_map_display/1]). + +%% Benchmarks +-export([benchmarks/1]). -include_lib("stdlib/include/ms_transform.hrl"). +-include_lib("common_test/include/ct_event.hrl"). +-include_lib("common_test/include/ct.hrl"). + -define(CHECK(Cond,Term), case (catch (Cond)) of true -> true; @@ -102,7 +112,7 @@ suite() -> []. all() -> - run_once() ++ [{group,main}]. + [{group,main}, benchmarks]. groups() -> [{main,[], @@ -110,7 +120,7 @@ groups() -> t_update_literals, t_update_literals_large, t_match_and_update_literals, t_match_and_update_literals_large, t_update_map_expressions, - t_update_assoc, t_update_assoc_large, + t_update_assoc, t_update_assoc_large, t_update_assoc_sharing, t_update_exact, t_update_exact_large, t_guard_bifs, t_guard_sequence, t_guard_sequence_large, @@ -157,11 +167,15 @@ groups() -> %% instruction-level tests t_has_map_fields, + t_get_map_elements, y_regs, %% Bugs - t_large_unequal_bins_same_hash_bug]}, - {once,[],[badmap_17]}]. + t_large_unequal_bins_same_hash_bug, + + %% Display + t_map_display]}, + {benchmarks, [{repeat,10}], [benchmarks]}]. run_once() -> case ?MODULE of @@ -189,6 +203,12 @@ end_per_suite(Config) -> lists:foreach(fun (A) -> application:stop(A) end, As), Config. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + + %% tests t_build_and_match_literals(Config) when is_list(Config) -> @@ -772,6 +792,45 @@ t_map_get(Config) when is_list(Config) -> (T) when map_get(x, T) =:= 1 -> ok; (T) -> false = is_map(T) end), + + %% Test unions of maps with some other type. + + M3 = id(M2), + if + is_map(M3) -> ok; + is_atom(M3) -> ok + end, + %% M3 is now known to be either a map or an atom + 1 = map_get(a, M3), + + M4 = id(M3), + if + is_map(M4) -> ok; + is_atom(M4) -> ok + end, + %% M4 is now known to be either a map or an atom + if + map_get(a, M4) =:= 1 -> ok + end, + + M5 = id(M4), + if + is_map(M5) -> ok; + is_tuple(M5) -> ok + end, + %% M5 is now known to be either a map or a tuple + 1 = map_get(a, M5), + + M6 = id(M5), + if + is_map(M6) -> ok; + is_tuple(M6) -> ok + end, + %% M6 is now known to be either a map or a tuple + if + map_get(a, M6) =:= 1 -> ok + end, + ok. t_is_map_key(Config) when is_list(Config) -> @@ -794,6 +853,9 @@ t_is_map_key(Config) when is_list(Config) -> true = is_map_key({1,1.0}, M1), true = is_map_key(<<"k2">>, M1), + true = is_map_key(id(a), M1), + true = is_map_key(id("hello"), M1), + %% error cases do_badmap(fun(T) -> {'EXIT',{{badmap,T},[{erlang,is_map_key,_,_}|_]}} = @@ -1102,6 +1164,51 @@ t_update_assoc_large(Config) when is_list(Config) -> ok. +t_update_assoc_sharing(Config) when is_list(Config) -> + Complex = id(#{nested=>map}), + + case erlang:system_info(debug_compiled) of + true -> + %% the maximum size of a flatmap in a debug-compiled + %% system is three + M0 = id(#{1=>a,2=>b,complex=>Complex}), + + %% all keys & values are the same + M1 = M0#{1=>a,complex=>Complex}, + true = erts_debug:same(M1, M0), + M1 = M0, + + %% only keys are the same + M2 = M0#{1=>new_value,complex=>Complex#{extra=>key}}, + true = same_keys(M0, M2); + false -> + M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e,complex=>Complex}), + + %% all keys & values are the same + M1 = M0#{1=>a,complex=>Complex}, + true = erts_debug:same(M1, M0), + M1 = M0, + + %% only keys are the same + M2 = M0#{1=>new_value,complex=>Complex#{extra=>key}}, + true = same_keys(M0, M2), + + M3 = M0#{2=>new_value}, + true = same_keys(M0, M3), + #{2:=new_value} = M3, + + M4 = M0#{1=>1,2=>2,3.0=>3,4=>4,5=>5,complex=>6}, + true = same_keys(M0, M4), + #{1:=1,2:=2,3.0:=3,4:=4,5:=5,complex:=6} = M4 + end, + + ok. + +same_keys(M0, M1) -> + Keys0 = erts_internal:map_to_tuple_keys(M0), + Keys1 = erts_internal:map_to_tuple_keys(M1), + erts_debug:same(Keys0, Keys1). + t_update_exact(Config) when is_list(Config) -> M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e}), @@ -1642,6 +1749,8 @@ t_map_compare(Config) when is_list(Config) -> io:format("seed = ~p\n", [rand:export_seed()]), repeat(100, fun(_) -> float_int_compare() end, []), repeat(100, fun(_) -> recursive_compare() end, []), + repeat(10, fun(_) -> atoms_compare() end, []), + repeat(10, fun(_) -> atoms_plus_compare() end, []), ok. float_int_compare() -> @@ -1649,12 +1758,51 @@ float_int_compare() -> %%io:format("Keys to use: ~p\n", [Terms]), Pairs = lists:map(fun(K) -> list_to_tuple([{K,V} || V <- Terms]) end, Terms), lists:foreach(fun(Size) -> - MapGen = fun() -> map_gen(list_to_tuple(Pairs), Size) end, + MapGen = fun() -> map_gen(Pairs, Size) end, repeat(100, fun do_compare/1, [MapGen, MapGen]) end, lists:seq(1,length(Terms))), ok. +atoms_compare() -> + Atoms = [true, false, ok, '', ?MODULE, list_to_atom(id("a new atom"))], + Pairs = lists:map(fun(K) -> list_to_tuple([{K,V} || V <- Atoms]) end, + Atoms), + lists:foreach( + fun(Size) -> + M1 = map_gen(Pairs, Size), + M2 = map_gen(Pairs, Size), + %%io:format("Atom maps to compare: ~p AND ~p\n", [M1, M2]), + do_cmp(M1, M2) + end, + lists:seq(1,length(Atoms))), + ok. + +atoms_plus_compare() -> + Atoms = [true, false, ok, '', ?MODULE, list_to_atom(id("a new atom"))], + Pairs = lists:map(fun(K) -> list_to_tuple([{K,V} || V <- Atoms]) end, + Atoms), + Small = 17, + Big1 = 1 bsl 64, + Big2 = erts_debug:copy_shared(Big1), + Float1 = float(Big1), + Float2 = float(Big2), + Others = {Small, -Small, Big1, -Big1, Big2, Float1, Float2, + [], {}, #{}, self(), make_ref(), + ok, yes, no, lists, maps, seq}, + RandOther = fun() -> element(rand:uniform(size(Others)), Others) end, + + lists:foreach( + fun(Size) -> + M = map_gen(Pairs, Size), + M1 = M#{RandOther() => RandOther()}, + M2 = M#{RandOther() => RandOther()}, + %%io:format("Maps to compare:\nM1 = ~p\nM2 = ~p\n", [M1, M2]), + do_cmp(M1, M2) + end, + lists:seq(1,length(Atoms))), + ok. + numeric_keys(N) -> lists:foldl(fun(_,Acc) -> Int = rand:uniform(N*4) - N*2, @@ -1754,8 +1902,8 @@ cmp(M1, M2, Exact) -> cmp_maps(M1, M2, Exact) -> case {maps:size(M1),maps:size(M2)} of {S,S} -> - {K1,V1} = lists:unzip(term_sort(maps:to_list(M1))), - {K2,V2} = lists:unzip(term_sort(maps:to_list(M2))), + {K1,V1} = lists:unzip(cmp_key_sort(maps:to_list(M1))), + {K2,V2} = lists:unzip(cmp_key_sort(maps:to_list(M2))), case cmp(K1, K2, true) of 0 -> cmp(V1, V2, Exact); @@ -1770,6 +1918,8 @@ cmp_others(I, F, true) when is_integer(I), is_float(F) -> -1; cmp_others(F, I, true) when is_float(F), is_integer(I) -> 1; +cmp_others(A1, A2, Exact) when is_atom(A1), is_atom(A2) -> + cmp_others(atom_to_list(A1), atom_to_list(A2), Exact); cmp_others(T1, T2, _) -> case {T1 -1; @@ -1777,6 +1927,10 @@ cmp_others(T1, T2, _) -> {false,false} -> 1 end. +cmp_key_sort(L) -> + lists:sort(fun(A,B) -> cmp(A,B,true) =< 0 end, + L). + map_gen(Pairs, Size) -> {_,L} = lists:foldl(fun(_, {Keys, Acc}) -> KI = rand:uniform(size(Keys)), @@ -1784,7 +1938,7 @@ map_gen(Pairs, Size) -> KV = element(rand:uniform(size(K)), K), {erlang:delete_element(KI,Keys), [KV | Acc]} end, - {Pairs, []}, + {list_to_tuple(Pairs), []}, lists:seq(1,Size)), maps:from_list(L). @@ -1796,12 +1950,8 @@ recursive_compare() -> %%io:format("Recursive term A = ~p\n", [A]), %%io:format("Recursive term B = ~p\n", [B]), - ?CHECK({true,false} =:= case do_cmp(A, B, false) of - -1 -> {A=B}; - 0 -> {A==B, A/=B}; - 1 -> {A>B, A= ?CHECK(0 =:= cmp(B, B2, false), {B,B2}), ok. -do_cmp(A, B, Exact) -> - C = cmp(A, B, Exact), - C. +do_cmp(A, B) -> + ?CHECK({true,false} =:= case cmp(A, B, false) of + -1 -> {A=B}; + 0 -> {A==B, A/=B}; + 1 -> {A>B, A= M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number, 18446744073709551629 => wat}, - - #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>, - 4 := number, 18446744073709551629 := wat} = maps:merge(#{}, M0), - - #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>, - 4 := number, 18446744073709551629 := wat} = maps:merge(M0, #{}), + merge_with_empty(M0), M1 = #{ "hi" => "hello again", float => 3.3, {1,2} => "tuple", 4 => integer }, @@ -2013,6 +2162,7 @@ t_bif_map_merge(Config) when is_list(Config) -> Is = lists:seq(1,N), M2 = maps:from_list([{I,I}||I<-Is]), 150000 = maps:size(M2), + merge_with_empty(M2), M3 = maps:from_list([{<>,I}||I<-Is]), 150000 = maps:size(M3), M4 = maps:merge(M2,M3), @@ -2051,6 +2201,30 @@ t_bif_map_merge(Config) when is_list(Config) -> M11 = maps:merge(M9,M10), ok = check_keys_exist(Ks1 ++ Ks2, M11), + %% Verify map and/or key tuple reuse + + MS = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>}, + merge_with_empty(MS), + MS_keys = erts_internal:map_to_tuple_keys(MS), + + %% key tuple reuse + MS_a = maps:merge(MS, #{int => 4}), + true = erts_debug:same(erts_internal:map_to_tuple_keys(MS_a), MS_keys), + %% map reuse + MS_b = maps:merge(#{int => 4}, MS), + true = erts_debug:same(MS_b, MS), + + %% mutated map reuse with literal key tuple + MS_c = maps:put(int, 4, maps:remove(int, MS)), + false = erts_debug:same(erts_internal:map_to_tuple_keys(MS_c), MS_keys), + MS_cc = maps:merge(MS, MS_c), + true = erts_debug:same(MS_cc, MS_c), + %% not only do we reuse MS_c, it has mutated to use the literal keys of MS + true = erts_debug:same(erts_internal:map_to_tuple_keys(MS_c), MS_keys), + + MS_d = maps:merge(MS_c, MS), + true = erts_debug:same(MS_d, MS), + %% error case do_badmap(fun(T) -> {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} = @@ -2066,6 +2240,15 @@ t_bif_map_merge(Config) when is_list(Config) -> end), ok. +merge_with_empty(M0) -> + M0_1 = maps:merge(#{}, M0), + M0 = M0_1, + true = erts_debug:same(M0, M0_1), + + M0_2 = maps:merge(M0, #{}), + M0 = M0_2, + true = erts_debug:same(M0, M0_2), + ok. t_bif_map_put(Config) when is_list(Config) -> M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, @@ -2927,6 +3110,10 @@ t_erts_internal_order(_Config) when is_list(_Config) -> 0 = erts_internal:cmp_term(2147483648,2147483648), 1 = erts_internal:cmp_term(2147483648,0), + %% Make sure it's not the internal flatmap order + %% where low indexed 'true' < 'a'. + -1 = erts_internal:cmp_term(a,true), + M = #{0 => 0,2147483648 => 0}, true = M =:= binary_to_term(term_to_binary(M)), true = M =:= binary_to_term(term_to_binary(M, [deterministic])), @@ -3089,7 +3276,7 @@ t_dets(_Config) -> t_tracing(_Config) -> - dbg:stop_clear(), + dbg:stop(), {ok,Tracer} = dbg:tracer(process,{fun trace_collector/2, self()}), dbg:p(self(),c), @@ -3142,7 +3329,7 @@ t_tracing(_Config) -> %% Check to extra messages timeout = getmsg(Tracer), - dbg:stop_clear(), + dbg:stop(), ok. getmsg(_Tracer) -> @@ -3187,6 +3374,19 @@ has_map_fields_3(#{a:=_,b:=_}) -> true; has_map_fields_3(#{[]:=_,42.0:=_}) -> true; has_map_fields_3(#{}) -> false. +t_get_map_elements(Config) when is_list(Config) -> + %% Tests that the JIT implementation of `get_map_elements` handles + %% collisions properly. + N = 500000, + Is = lists:seq(1, N), + Test = maps:from_list([{I,I}||I<-Is]), + [begin + #{ Key := Val } = Test, + Key = Val + end || Key <- Is], + + ok. + y_regs(Config) when is_list(Config) -> Val = [length(Config)], Map0 = y_regs_update(#{}, Val), @@ -3255,15 +3455,6 @@ do_badmap(Test) -> [],{a,b,c},[a,b],atom,10.0,42,(1 bsl 65) + 3], [Test(T) || T <- Terms]. -%% Test that a module compiled with the OTP 17 compiler will -%% generate the correct 'badmap' exception. -badmap_17(Config) -> - Mod = badmap_17, - DataDir = test_server:lookup_config(data_dir, Config), - Beam = filename:join(DataDir, Mod), - {module,Mod} = code:load_abs(Beam), - do_badmap(fun Mod:update/1). - %% Use this function to avoid compile-time evaluation of an expression. id(I) -> I. @@ -3305,8 +3496,7 @@ t_hash_entropy(Config) when is_list(Config) -> %% Provoke major GC with a lot of "fat" maps on external format in msg queue %% causing heap fragments to be allocated. t_gc_rare_map_overflow(Config) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - {ok, Node} = test_server:start_node(gc_rare_map_overflow, slave, [{args, "-pa \""++Pa++"\""}]), + {ok, Peer, Node} = ?CT_PEER(), erts_debug:set_internal_state(available_internal_state, true), try Echo = spawn_link(Node, fun Loop() -> receive {From,Msg} -> From ! Msg @@ -3337,7 +3527,7 @@ t_gc_rare_map_overflow(Config) when is_list(Config) -> after process_flag(trap_exit, false), erts_debug:set_internal_state(available_internal_state, false), - test_server:stop_node(Node) + peer:stop(Peer) end. t_gc_rare_map_overflow_do(Echo, FatMap, GcFun) -> @@ -3505,6 +3695,8 @@ t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) -> io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)]) end). + + make_map(0) -> #{}; make_map(Size) -> @@ -3536,16 +3728,212 @@ run_when_enough_resources(Fun) -> total_memory() -> %% Total memory in GB. try - MemoryData = memsup:get_system_memory_data(), - case lists:keysearch(total_memory, 1, MemoryData) of - {value, {total_memory, TM}} -> - TM div (1024*1024*1024); - false -> - {value, {system_total_memory, STM}} = - lists:keysearch(system_total_memory, 1, MemoryData), - STM div (1024*1024*1024) - end + SMD = memsup:get_system_memory_data(), + TM = proplists:get_value( + available_memory, SMD, + proplists:get_value( + total_memory, SMD, + proplists:get_value( + system_total_memory, SMD))), + TM div (1024*1024*1024) catch _ : _ -> undefined end. + +%% This test case checks that maps larger than 32 elements are readable +%% when displayed. +t_map_display(Config) when is_list(Config) -> + verify_map_term(make_nontrivial_map(33)), + verify_map_term(make_nontrivial_map(253)), + verify_map_term({a, make_nontrivial_map(77)}), + verify_map_term([make_nontrivial_map(42), + {a,make_nontrivial_map(99)}, + make_nontrivial_map(77)]), + + ok. + +make_nontrivial_map(N) -> + make_nontrivial_map(N, 32). + +make_nontrivial_map(N, Effort) -> + L = [begin + Key = case I rem 64 of + 33 when Effort > 16 -> + make_nontrivial_map(I, Effort div 2); + _ -> + I + end, + Value = case I rem 5 of + 0 -> + I * I; + 1 -> + if + Effort > 16 -> + make_nontrivial_map(33, Effort div 2); + true -> + make_map(Effort) + end; + 2 -> + lists:seq(0, I rem 16); + 3 -> + list_to_tuple(lists:seq(0, I rem 16)); + 4 -> + float(I) + end, + {Key, Value} + end || I <- lists:seq(1, N)], + maps:from_list(L). + +verify_map_term(Term) -> + Printed = string:chomp(erts_internal:term_to_string(Term)), + {ok,Tokens,1} = erl_scan:string(Printed ++ "."), + {ok,ParsedTerm} = erl_parse:parse_term(Tokens), + + case ParsedTerm of + Term -> + ok; + Other -> + io:format("Expected:\n~p\n", [Term]), + io:format("Got:\n~p", [Other]), + ct:fail(failed) + end. + +%%% +%%% Benchmarks +%%% + +-define(SMALL_MAP_SIZE, 32). +-define(BIG_MAP_SIZE, 3333). + +benchmarks(_Config) -> + N = 5000000, + + %% Looks up a known value in a flatmap and (relatively large) hashmap, + %% the value will be near the middle of the tested flatmap in an + %% attempt to make the test more representative. + lookup_literal_immed_small(N), + lookup_literal_immed_big(N), + + %% Looks up a value that _COULD_ be an immediate (and always is in this + %% test), benchmarking the common case of looking up an unknown integer + %% or similar. + %% + %% Like literal_immed_small, we try to pick a value that will be in the + %% middle of the tested flatmap. + lookup_any_immed_small(N), + lookup_any_immed_big(N), + + %% Looks up `[{}]`, looking for regressions in pre-hashed complex + %% lookups. + lookup_literal_complex_small(N), + lookup_literal_complex_big(N), + + %% Looks up some unknown complex term, looking for regressions in complex + %% lookups that need to be hashed in runtime. + lookup_any_complex_small(N), + lookup_any_complex_big(N), + + %% Looks up a bunch of keys in parallel, benchmarking maps-as-structs. + lookup_literal_multi_small(N), + lookup_literal_multi_big(N), + + ok. + +lookup_literal_immed_small(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?SMALL_MAP_SIZE), []), + F = fun(N) -> literal_immed(N, Map0, []) end, + time(?FUNCTION_NAME, F, Iterations). + +lookup_literal_immed_big(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?BIG_MAP_SIZE), []), + F = fun(N) -> literal_immed(N, Map0, []) end, + time(?FUNCTION_NAME, F, Iterations). + +literal_immed(0, _Map, Acc) -> + Acc; +literal_immed(N, Map, _) -> + #{ (?SMALL_MAP_SIZE div 2) := Acc } = Map, + literal_immed(N - 1, Map, Acc). + +lookup_any_immed_small(Iterations) -> + Size = ?SMALL_MAP_SIZE div 2 - 1, + Map = maps:from_list([{V, -V} || V <- lists:seq(-Size, Size)]), + F = fun(N) -> any_immed(N, Map, Size div 2) end, + time(?FUNCTION_NAME, F, Iterations). + +lookup_any_immed_big(Iterations) -> + Size = ?BIG_MAP_SIZE div 2 - 1, + Map = maps:from_list([{V, -V} || V <- lists:seq(-Size, Size)]), + F = fun(N) -> any_immed(N, Map, Size div 2) end, + time(?FUNCTION_NAME, F, Iterations). + +any_immed(0, _Map, Acc) -> + Acc; +any_immed(N, Map, Acc0) -> + #{ Acc0 := Acc } = Map, + any_immed(N - 1, Map, Acc). + +lookup_literal_complex_small(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?SMALL_MAP_SIZE), []), + F = fun(N) -> literal_complex(N, Map0#{ [{}] => [{}] }, [{}]) end, + time(?FUNCTION_NAME, F, Iterations). + +lookup_literal_complex_big(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?BIG_MAP_SIZE), []), + F = fun(N) -> literal_complex(N, Map0#{ [{}] => [{}] }, [{}]) end, + time(?FUNCTION_NAME, F, Iterations). + +literal_complex(0, Map, Acc) -> + {Map, Acc}; +literal_complex(N, Map, _) -> + #{ [{}] := Acc } = Map, + literal_complex(N - 1, Map, Acc). + +lookup_any_complex_small(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?SMALL_MAP_SIZE - 2), []), + F = fun(N) -> + any_complex(N, Map0#{ [{}] => {[]}, {[]} => [{}] }, [{}]) + end, + time(?FUNCTION_NAME, F, Iterations). + +lookup_any_complex_big(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?BIG_MAP_SIZE - 2), []), + F = fun(N) -> + any_complex(N, Map0#{ [{}] => {[]}, {[]} => [{}] }, [{}]) + end, + time(?FUNCTION_NAME, F, Iterations). + +any_complex(0, _Map, Acc) -> + Acc; +any_complex(N, Map, Acc0) -> + #{ Acc0 := Acc } = Map, + any_complex(N - 1, Map, Acc). + +lookup_literal_multi_small(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?SMALL_MAP_SIZE), id([])), + F = fun(N) -> literal_multi(N, Map0, []) end, + time(?FUNCTION_NAME, F, Iterations). + +lookup_literal_multi_big(Iterations) -> + Map0 = maps:from_keys(lists:seq(1, ?BIG_MAP_SIZE), id([])), + F = fun(N) -> literal_multi(N, Map0, []) end, + time(?FUNCTION_NAME, F, Iterations). + +literal_multi(0, _Map, Acc) -> + Acc; +literal_multi(N, Map, _) -> + #{ (?SMALL_MAP_SIZE div 2 + 0) := Same, + (?SMALL_MAP_SIZE div 2 + 1) := Same, + (?SMALL_MAP_SIZE div 2 - 1) := Same, + (?SMALL_MAP_SIZE div 2 + 2) := Same, + (?SMALL_MAP_SIZE div 2 - 2) := Same } = Map, + literal_multi(N - 1, Map, Same). + +time(Name, F, Iterations) -> + Time = element(1, timer:tc(F, [Iterations])), + ct_event:notify(#event{name=benchmark_data, + data=[{value, Time}, + {suite, ?MODULE_STRING}, + {name, atom_to_list(Name)}]}), + Time. diff --git a/erts/emulator/test/map_SUITE_data/badmap_17.erl b/erts/emulator/test/map_SUITE_data/badmap_17.erl deleted file mode 100644 index 887fc2e5e38c..000000000000 --- a/erts/emulator/test/map_SUITE_data/badmap_17.erl +++ /dev/null @@ -1,58 +0,0 @@ --module(badmap_17). --export([update/1]). - -%% Compile this source file with OTP 17.0. - -update(Map) -> - try - update_1(Map), - error(update_did_not_fail) - catch - error:{badmap,Map} -> - ok - end, - try - update_2(Map), - error(update_did_not_fail) - catch - error:{badmap,Map} -> - ok - end, - try - update_3(Map), - error(update_did_not_fail) - catch - error:{badmap,Map} -> - ok - end, - ok = update_4(Map), - ok = update_5(Map), - ok. - -update_1(M) -> - M#{a=>42}. - -update_2(M) -> - M#{a:=42}. - -update_3(M) -> - id(M), - M#{a=>42}. - -update_4(M) when M#{a=>b} =:= M -> - did_not_fail; -update_4(_) -> - ok. - -update_5(M) -> - id(M), - case id(true) of - true when M#{a=>b} =:= M -> - did_not_fail; - true -> - ok - end. - -id(I) -> - I. - diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl index 7f99e404239b..43e475b12555 100644 --- a/erts/emulator/test/match_spec_SUITE.erl +++ b/erts/emulator/test/match_spec_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -21,19 +21,23 @@ -module(match_spec_SUITE). -export([all/0, suite/0]). --export([test_1/1, test_2/1, test_3/1, caller_and_return_to/1, bad_match_spec_bin/1, +-export([init_per_testcase/2, end_per_testcase/2]). +-export([test_1/1, test_2/1, test_3/1, test_4a/1, test_4b/1, test_5a/1, + test_5b/1, test_6/1, caller_and_return_to/1, bad_match_spec_bin/1, trace_control_word/1, silent/1, silent_no_ms/1, silent_test/1, ms_trace2/1, ms_trace3/1, ms_trace_dead/1, boxed_and_small/1, destructive_in_test_bif/1, guard_exceptions/1, empty_list/1, - unary_plus/1, unary_minus/1, moving_labels/1]). + unary_plus/1, unary_minus/1, moving_labels/1, + guard_bifs/1]). -export([fpe/1]). -export([otp_9422/1]). -export([faulty_seq_trace/1, do_faulty_seq_trace/0]). -export([maps/1]). --export([runner/2, loop_runner/3]). +-export([runner/2, loop_runner/3, fixed_runner/2]). -export([f1/1, f2/2, f3/2, fn/1, fn/2, fn/3]). -export([do_boxed_and_small/0]). +-export([f1_test4/1, f2_test4/2, f3_test4/2]). % This test suite assumes that tracing in general works. What we test is % the match spec functionality. @@ -45,7 +49,8 @@ suite() -> {timetrap, {minutes, 1}}]. all() -> - [test_1, test_2, test_3, caller_and_return_to, bad_match_spec_bin, + [test_1, test_2, test_3, test_4a, test_4b, test_5a, test_5b, test_6, + caller_and_return_to, bad_match_spec_bin, trace_control_word, silent, silent_no_ms, silent_test, ms_trace2, ms_trace3, ms_trace_dead, boxed_and_small, destructive_in_test_bif, guard_exceptions, unary_plus, unary_minus, fpe, @@ -53,7 +58,13 @@ all() -> faulty_seq_trace, empty_list, otp_9422, - maps]. + maps, + guard_bifs]. + +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). test_1(Config) when is_list(Config) -> tr(fun() -> ?MODULE:f1(a) end, @@ -173,10 +184,148 @@ test_3(Config) when is_list(Config) -> collect(P1, [{trace, P1, call, {?MODULE, f2, [a, b]}, [true]}]), ok. +%% Test `caller_line` trace with `call` and `global` +test_4a(Config) when is_list(Config) -> + Fun = fun() -> ?MODULE:f3_test4(a, b) end, + Pat = [{'_', [],[{message, {caller_line}}]}], + P = spawn(?MODULE, runner, [self(), Fun]), + erlang:trace(P, true, [call]), + %% `global` is implied but we still mention explicitly + erlang:trace_pattern({?MODULE, f2_test4, 2}, Pat, [global]), + erlang:trace_pattern({?MODULE, f1_test4, 1}, Pat, [global]), + collect(P, [{trace, P, call, {?MODULE, f2_test4, [a, b]}, {?MODULE, f3_test4, 2, {"test4.erl", 3}}}, + {trace, P, call, {?MODULE, f1_test4, [a]}, {?MODULE, f3_test4, 2, {"test4.erl", 3}}}]), + ok. + +%% Test `caller_line` trace with `return_trace`, `call` and `global` +test_4b(Config) when is_list(Config) -> + Fun = fun() -> ?MODULE:f3_test4(a, b) end, + P = spawn(?MODULE, runner, [self(), Fun]), + Pat = [{'_', [], [{return_trace}, {message, {caller_line}}]}], + erlang:trace(P, true, [call]), + %% `global` is implied but we still mention explicitly + erlang:trace_pattern({?MODULE, f2_test4, 2}, Pat, [global]), + erlang:trace_pattern({?MODULE, f1_test4, 1}, Pat, [global]), + collect(P, [{trace, P, call, {?MODULE, f2_test4, [a, b]}, {?MODULE, f3_test4, 2, {"test4.erl", 3}}}, + {trace, P, call, {?MODULE, f1_test4, [a]}, {?MODULE, f3_test4, 2, {"test4.erl", 3}}}, + {trace, P, return_from, {?MODULE, f1_test4, 1}, {a}}, + {trace, P, return_from, {?MODULE, f2_test4, 2}, {a}} + ]), + ok. + +%% Test `caller_line` trace with `call` and `local` +test_5a(Config) when is_list(Config) -> + Fun = fun() -> f3_test5(a, b) end, + Pat = [{'_', [],[{message, {caller_line}}]}], + P = spawn(?MODULE, runner, [self(), Fun]), + erlang:trace(P, true, [call]), + %% Notice `local` function tracing + erlang:trace_pattern({?MODULE, f2_test5, 2}, Pat, [local]), + erlang:trace_pattern({?MODULE, f1_test5, 1}, Pat, [local]), + collect(P, [{trace, P, call, {?MODULE, f2_test5, [a, b]}, {?MODULE, f3_test5, 2, {"test5.erl", 3}}}, + {trace, P, call, {?MODULE, f1_test5, [a]}, {?MODULE, f3_test5, 2, {"test5.erl", 3}}}]), + ok. + +%% Test `caller_line` trace with `return_trace`, `call` and `local` +test_5b(Config) when is_list(Config) -> + Fun = fun() -> f3_test5(a, b) end, + P = spawn(?MODULE, runner, [self(), Fun]), + Pat = [{'_', [], [{return_trace}, {message, {caller_line}}]}], + erlang:trace(P, true, [call]), + %% Notice `local` function tracing + erlang:trace_pattern({?MODULE, f2_test5, 2}, Pat, [local]), + erlang:trace_pattern({?MODULE, f1_test5, 1}, Pat, [local]), + collect(P, [{trace, P, call, {?MODULE, f2_test5, [a, b]}, {?MODULE, f3_test5, 2, {"test5.erl", 3}}}, + {trace, P, call, {?MODULE, f1_test5, [a]}, {?MODULE, f3_test5, 2, {"test5.erl", 3}}}, + {trace, P, return_from, {?MODULE, f1_test5, 1}, {a}}, + {trace, P, return_from, {?MODULE, f2_test5, 2}, {a}} + ]), + ok. + +%% Test current_stacktrace/[0,1] +test_6(Config) when is_list(Config) -> + %% Test non small argument + case catch erlang:trace_pattern({?MODULE, f2_test6, '_'}, + [{'_', [], [{message, {current_stacktrace, a}}]}]) of + {'EXIT', {badarg, _}} -> ok; + Other1 -> ct:fail({noerror, Other1}) + end, + + %% Test negative + case catch erlang:trace_pattern({?MODULE, f2_test6, '_'}, + [{'_', [], [{message, {current_stacktrace, -1}}]}]) of + {'EXIT', {badarg, _}} -> ok; + Other2 -> ct:fail({noerror, Other2}) + end, + + Fun = fun() -> f5_test6() end, + Pat = [{'_', [], [{message, {current_stacktrace}}]}], + P = spawn(?MODULE, fixed_runner, [self(), Fun]), + erlang:trace(P, true, [call]), + erlang:trace_pattern({?MODULE, f2_test6, 1}, Pat, [local]), + erlang:trace_pattern({?MODULE, f1_test6, 0}, Pat, [local]), + collect(P, [{trace, P, call, {?MODULE, f2_test6, [f1]}, + [ + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]}, + {?MODULE, f5_test6, 0, [{file, "test6.erl"}, {line, 14}]}, + {?MODULE, fixed_runner, 2, [{file, "test6.erl"}, {line, 7}]} + ]}, + {trace, P, call, {?MODULE, f1_test6, []}, + [ + {?MODULE, f2_test6, 1, [{file, "test6.erl"}, {line, 25}]}, + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]}, + {?MODULE, f5_test6, 0, [{file, "test6.erl"}, {line, 14}]}, + {?MODULE, fixed_runner, 2, [{file, "test6.erl"}, {line, 7}]} + ]} + ]), + + Pat2 = [{'_', [], [{message, {current_stacktrace, 3}}]}], + P2 = spawn(?MODULE, fixed_runner, [self(), Fun]), + erlang:trace(P2, true, [call]), + erlang:trace_pattern({?MODULE, f2_test6, 1}, Pat2, [local]), + erlang:trace_pattern({?MODULE, f1_test6, 0}, Pat2, [local]), + collect(P2, [{trace, P2, call, {?MODULE, f2_test6, [f1]}, + [ + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]}, + {?MODULE, f5_test6, 0, [{file, "test6.erl"}, {line, 14}]}, + {?MODULE, fixed_runner, 2, [{file, "test6.erl"}, {line, 7}]} + ]}, + {trace, P2, call, {?MODULE, f1_test6, []}, + [ + {?MODULE, f2_test6, 1, [{file, "test6.erl"}, {line, 25}]}, + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]}, + {?MODULE, f5_test6, 0, [{file, "test6.erl"}, {line, 14}]} + ]} + ]), + + %% Test when erts_backtrace_depth is less than depth + OldDepth = erlang:system_flag(backtrace_depth, 2), + try + P3 = spawn(?MODULE, fixed_runner, [self(), Fun]), + erlang:trace(P3, true, [call]), + erlang:trace_pattern({?MODULE, f2_test6, 1}, Pat2, [local]), + erlang:trace_pattern({?MODULE, f1_test6, 0}, Pat2, [local]), + collect(P3, [{trace, P3, call, {?MODULE, f2_test6, [f1]}, + [ + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]}, + {?MODULE, f5_test6, 0, [{file, "test6.erl"}, {line, 14}]} + ]}, + {trace, P3, call, {?MODULE, f1_test6, []}, + [ + {?MODULE, f2_test6, 1, [{file, "test6.erl"}, {line, 25}]}, + {?MODULE, f3_test6, 0, [{file, "test6.erl"}, {line, 21}]} + ]} + ]) + after + erlang:system_flag(backtrace_depth, OldDepth) + end, + + ok. + %% Test that caller and return to work as they should %% There was a bug where caller would be undefined when return_to was set %% for r the bif erlang:put(). -caller_and_return_to(Config) -> +caller_and_return_to(Config) when is_list(Config) -> tr( fun do_put_wrapper/0, fun (Tracee) -> @@ -686,10 +835,9 @@ destructive_in_test_bif(Config) when is_list(Config) -> %% Test that the comparison between boxed and small does not crash emulator boxed_and_small(Config) when is_list(Config) -> - {ok, Node} = start_node(match_spec_suite_other), + {ok, Peer, Node} = ?CT_PEER(), ok = rpc:call(Node,?MODULE,do_boxed_and_small,[]), - stop_node(Node), - ok. + peer:stop(Peer). do_boxed_and_small() -> {ok, false, _, _} = erlang:match_spec_test({0,3},[{{1.47,'_'},[],['$_']}],table), @@ -700,10 +848,9 @@ do_boxed_and_small() -> %% Test that faulty seq_trace_call does not crash emulator faulty_seq_trace(Config) when is_list(Config) -> - {ok, Node} = start_node(match_spec_suite_other), + {ok, Peer, Node} = ?CT_PEER(), ok = rpc:call(Node,?MODULE,do_faulty_seq_trace,[]), - stop_node(Node), - ok. + peer:stop(Peer). do_faulty_seq_trace() -> {ok,'EXIT',_,_} = erlang:match_spec_test([],[{'_',[],[{message,{set_seq_token,yxa,true}}]}],trace), @@ -1000,7 +1147,36 @@ moving_labels(Config) when is_list(Config) -> erlang:match_spec_test({true,false}, Ms2, table), ok. - + +-record(dummy_record, {}). + +%% GH-7045: Some guard BIFs were unavailable in match specifications. +guard_bifs(_Config) -> + Matches = + [begin + BIF = list_to_tuple([F | lists:duplicate(A, '$1')]), + erlang:match_spec_test(Data, [{{'$1'}, [BIF], [{{'$1'}}]}], Kind) + end + || {F, A} <- erlang:module_info(functions), + {Data, Kind} <- [{{a}, table}, {[a], trace}], + F =/= is_record, %% Has special requirements, checked below. + erl_internal:arith_op(F, A) orelse + erl_internal:bool_op(F, A) orelse + erl_internal:comp_op(F, A) orelse + erl_internal:guard_bif(F, A)], + [] = [T || {error, _}=T <- Matches], + + IsRecord = {is_record, + '$1', + dummy_record, + record_info(size, dummy_record)}, + [{ok, _, [], []} = + erlang:match_spec_test(Data, [{{'$1'}, [IsRecord], [{{'$1'}}]}], Kind) + || {Data, Kind} <- [{{#dummy_record{}}, table}, + {[#dummy_record{}], trace}]], + + ok. + tr(Fun, MFA, Pat, Expected) -> tr(Fun, MFA, [call], Pat, [global], Expected). @@ -1155,11 +1331,54 @@ fbinmatch(<<>>, Acc) -> Acc. id(X) -> X. -start_node(Name) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = atom_to_list(erlang:get_cookie()), - test_server:start_node(Name, slave, - [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]). +-file("test4.erl", 1). +f3_test4(X,Y) -> + ?MODULE:f2_test4(X,Y), % Line 3 - This line number should remain stable + ok. + +f2_test4(X, _) -> + ?MODULE:f1_test4(X). + +f1_test4(X) -> + {X}. + +-file("test5.erl", 1). +f3_test5(X,Y) -> + f2_test5(X,Y), % Line 3 - This line number should remain stable + ok. + +f2_test5(X, _) -> + f1_test5(X). + +f1_test5(X) -> + {X}. + +-file("test6.erl", 1). +fixed_runner(Collector, Fun) -> + receive + {go, Collector} -> + go + end, + Fun(), % Line 7 - This line number should remain stable + receive + {done, Collector} -> + Collector ! {gone, self()} + end. + +f5_test6() -> + f3_test6(), % Line 14 - This line number should remain stable + f4_test6(). + +f4_test6() -> + f4. + +f3_test6() -> + f2_test6(f1), % Line 21 - This line number should remain stable + f3. + +f2_test6(X) -> + X = f1_test6(), % Line 25 - This line number should remain stable + f2. -stop_node(Node) -> - test_server:stop_node(Node). +f1_test6() -> + f1. diff --git a/erts/emulator/test/message_queue_data_SUITE.erl b/erts/emulator/test/message_queue_data_SUITE.erl index 1533026e7a4f..71921a4eda9a 100644 --- a/erts/emulator/test/message_queue_data_SUITE.erl +++ b/erts/emulator/test/message_queue_data_SUITE.erl @@ -21,6 +21,7 @@ -module(message_queue_data_SUITE). -export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). -export([basic/1, process_info_messages/1, total_heap_size/1, change_to_off_heap/1, change_to_off_heap_gc/1]). @@ -40,7 +41,12 @@ end_per_suite(_Config) -> erts_debug:set_internal_state(available_internal_state, false), ok. -all() -> +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + +all() -> [basic, process_info_messages, total_heap_size, change_to_off_heap, change_to_off_heap_gc]. @@ -54,13 +60,13 @@ basic(Config) when is_list(Config) -> basic_test(erlang:system_info(message_queue_data)), - {ok, Node1} = start_node(Config, "+hmqd off_heap"), + {ok, Peer1, Node1} = ?CT_PEER(["+hmqd", "off_heap"]), ok = rpc:call(Node1, ?MODULE, basic_test, [off_heap]), - stop_node(Node1), + peer:stop(Peer1), - {ok, Node2} = start_node(Config, "+hmqd on_heap"), + {ok, Peer2, Node2} = ?CT_PEER(["+hmqd", "on_heap"]), ok = rpc:call(Node2, ?MODULE, basic_test, [on_heap]), - stop_node(Node2), + peer:stop(Peer2), ok. @@ -326,7 +332,7 @@ wait_change_off_heap() -> %% has been made on current process if (and only if) it %% was previously changed on this process... %% - %% Work with *current* inplementation! This may change... + %% Work with *current* implementation! This may change... %% erts_debug:set_internal_state(wait, thread_progress), %% We have now flushed later ops including later op that @@ -356,17 +362,3 @@ spinner(_N, 0) -> ok; spinner(N, M) -> spinner(?MODULE:id(N) div 1, M - 1). id(N) -> N. - -start_node(Config, Opts) when is_list(Config), is_list(Opts) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl index 82494f752a92..29401c0bf3f4 100644 --- a/erts/emulator/test/monitor_SUITE.erl +++ b/erts/emulator/test/monitor_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2022. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -24,6 +24,7 @@ -include_lib("eunit/include/eunit.hrl"). -export([all/0, suite/0, groups/0, + init_per_testcase/2, end_per_testcase/2, case_1/1, case_1a/1, case_2/1, case_2a/1, mon_e_1/1, demon_e_1/1, demon_1/1, demon_2/1, demon_3/1, demonitor_flush/1, gh_5225_demonitor_alias/1, local_remove_monitor/1, remote_remove_monitor/1, mon_1/1, mon_2/1, @@ -36,7 +37,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}, - {timetrap, {minutes, 15}}]. + {timetrap, {seconds, 30}}]. all() -> [case_1, case_1a, case_2, case_2a, mon_e_1, demon_e_1, @@ -51,6 +52,11 @@ groups() -> [{remove_monitor, [], [local_remove_monitor, remote_remove_monitor]}]. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + %% A monitors B, B kills A and then exits (yielded core dump) case_1(Config) when is_list(Config) -> process_flag(trap_exit, true), @@ -141,13 +147,13 @@ expect_no_msg() -> %%% Error cases for monitor/2 mon_e_1(Config) when is_list(Config) -> - {ok, N} = test_server:start_node(hej, slave, []), + {ok, Peer, N} = ?CT_PEER(), mon_error(plutt, self()), mon_error(process, [bingo]), mon_error(process, {rex, N, junk}), mon_error(process, 1), - true = test_server:stop_node(N), + peer:stop(Peer), ok. %%% We would also like to have a test case that tries to monitor something @@ -169,7 +175,7 @@ mon_error(Type, Item) -> %%% Error cases for demonitor/1 demon_e_1(Config) when is_list(Config) -> - {ok, N} = test_server:start_node(hej, slave, []), + {ok, Peer, N} = ?CT_PEER(), demon_error(plutt, badarg), demon_error(1, badarg), @@ -192,7 +198,7 @@ demon_e_1(Config) when is_list(Config) -> ct:fail({rec, Other2}) end, - true = test_server:stop_node(N), + peer:stop(Peer), ok. demon_error(Ref, Reason) -> @@ -247,22 +253,22 @@ demon_2(Config) when is_list(Config) -> %% Distributed case for demonitor/1 (OTP-3499) demon_3(Config) when is_list(Config) -> - {ok, N} = test_server:start_node(hej, slave, []), + {ok, Peer, N} = ?CT_PEER(), %% 'DOWN' before demonitor P2 = spawn(N, timer, sleep, [100000]), R2 = erlang:monitor(process, P2), - true = test_server:stop_node(N), + peer:stop(Peer), true = erlang:demonitor(R2), expect_down(R2, P2, noconnection), - {ok, N2} = test_server:start_node(hej, slave, []), + {ok, Peer2, N2} = ?CT_PEER(), %% Demonitor before 'DOWN' P3 = spawn(N2, timer, sleep, [100000]), R3 = erlang:monitor(process, P3), true = erlang:demonitor(R3), - true = test_server:stop_node(N2), + peer:stop(Peer2), expect_no_msg(), ok. @@ -271,9 +277,9 @@ demonitor_flush(Config) when is_list(Config) -> {'EXIT', {badarg, _}} = (catch erlang:demonitor(make_ref(), flush)), {'EXIT', {badarg, _}} = (catch erlang:demonitor(make_ref(), [flus])), {'EXIT', {badarg, _}} = (catch erlang:demonitor(x, [flush])), - {ok, N} = test_server:start_node(demonitor_flush, slave, []), + {ok, Peer, N} = ?CT_PEER(), ok = demonitor_flush_test(N), - true = test_server:stop_node(N), + peer:stop(Peer), ok = demonitor_flush_test(node()). demonitor_flush_test(Node) -> @@ -336,7 +342,7 @@ local_remove_monitor(Config) when is_list(Config) -> "True = "++integer_to_list(True)++"; False = "++integer_to_list(False)}. remote_remove_monitor(Config) when is_list(Config) -> - {ok, N} = test_server:start_node(demonitor_flush, slave, []), + {ok, Peer, N} = ?CT_PEER(), Gs = generate(fun () -> start_remove_monitor_group(N) end, ?RM_MON_GROUPS), {True, False} = lists:foldl(fun (G, {T, F}) -> @@ -348,7 +354,7 @@ remote_remove_monitor(Config) when is_list(Config) -> {0, 0}, Gs), erlang:display({remote_remove_monitor, True, False}), - true = test_server:stop_node(N), + peer:stop(Peer), {comment, "True = "++integer_to_list(True)++"; False = "++integer_to_list(False)}. @@ -433,7 +439,7 @@ mon_1(Config) when is_list(Config) -> %% Distributed cases for monitor/2 mon_2(Config) when is_list(Config) -> - {ok, N1} = test_server:start_node(hej1, slave, []), + {ok, Peer, N1} = ?CT_PEER(), %% Normal case P2 = spawn(N1, timer, sleep, [4000]), @@ -454,7 +460,7 @@ mon_2(Config) when is_list(Config) -> P5 = spawn(N1, timer, sleep, [100000]), R5 = erlang:monitor(process, P5), - true = test_server:stop_node(N1), + peer:stop(Peer), expect_down(R5, P5, noconnection), @@ -465,9 +471,7 @@ mon_2(Config) when is_list(Config) -> true = (R6_Reason == noconnection) orelse (R6_Reason == noproc), %% Start a new node that can load code in this module - PA = filename:dirname(code:which(?MODULE)), - {ok, N2} = test_server:start_node - (hej2, slave, [{args, "-pa " ++ PA}]), + {ok, Peer2, N2} = ?CT_PEER(), %% Normal case (named process) P7 = start_jeeves({jeeves, N2}), @@ -489,7 +493,7 @@ mon_2(Config) when is_list(Config) -> _P10 = start_jeeves({jeeves, N2}), R10 = erlang:monitor(process, {jeeves, N2}), - true = test_server:stop_node(N2), + peer:stop(Peer2), expect_down(R10, {jeeves, N2}, noconnection), @@ -542,7 +546,6 @@ large_exit_sub(S) -> list_cleanup(Config) when is_list(Config) -> P0 = self(), M = node(), - PA = filename:dirname(code:which(?MODULE)), true = register(master_bertie, self()), %% Normal local case, monitor and demonitor @@ -578,8 +581,7 @@ list_cleanup(Config) when is_list(Config) -> {[], []} = monitors(), %% Start a new node that can load code in this module - {ok, J} = test_server:start_node - (jeeves, slave, [{args, "-pa " ++ PA}]), + {ok, Peer, J} = ?CT_PEER(), %% Normal remote case, monitor and demonitor P3 = start_jeeves({jeeves, J}), @@ -622,7 +624,7 @@ list_cleanup(Config) when is_list(Config) -> {[], [P5]} = monitors(), expect_jeeves(P5, monitors, {monitors, {[{process, P0}], []}} ), - test_server:stop_node(J), + peer:stop(Peer), timer:sleep(4000), {[], []} = monitors(), @@ -633,12 +635,7 @@ list_cleanup(Config) when is_list(Config) -> %%% Mixed internal and external monitors mixer(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - NN = [j0,j1,j2], - NL0 = [begin - {ok, J} = test_server:start_node(X,slave,[{args, "-pa " ++ PA}]), - J - end || X <- NN], + {_, Peers, NL0} = lists:unzip3([?CT_PEER() || _ <- lists:seq(1, 3)]), NL1 = lists:duplicate(2,node()) ++ NL0, Perm = perm(NL1), lists:foreach( @@ -712,7 +709,7 @@ mixer(Config) when is_list(Config) -> [tell_jeeves(P,{exit,flaff}) || P <- Js] end, Perm), - [test_server:stop_node(K) || K <- NL0], + [peer:stop(P) || P <- Peers], ok. %% Test that DOWN message for a named monitor isn't @@ -792,7 +789,7 @@ otp_5827(Config) when is_list(Config) -> end. monitor_time_offset(Config) when is_list(Config) -> - {ok, Node} = start_node(Config, "+C single_time_warp"), + {ok, Peer, Node} = ?CT_PEER(["+C", "single_time_warp"]), Me = self(), PMs = lists:map(fun (_) -> Pid = spawn(Node, @@ -822,7 +819,7 @@ monitor_time_offset(Config) when is_list(Config) -> ct:fail(Reason) end end, PMs), - stop_node(Node), + peer:stop(Peer), ok. check_monitor_time_offset(Leader) -> @@ -1151,7 +1148,7 @@ monitor_3_noproc_gh6185_test(AliasTest, TagTest) -> end, %% Process of old incarnation... - Pid = erts_test_utils:mk_ext_pid({NodeName, OldCreation}, 4711, 17), + Pid = erts_test_utils:mk_ext_pid({NodeName, OldCreation}, 4711, 0), {Tag5, TagOpt5} = TagFun(), M5 = erlang:monitor(process, Pid, AliasOpt ++ TagOpt5), receive @@ -1241,7 +1238,7 @@ monitor_3_noproc_gh6185_exit_test(AliasTest, TagTest) -> {P5, M5} = spawn_monitor(fun () -> Pid = erts_test_utils:mk_ext_pid({NodeName, OldCreation}, - 4711, 17), + 4711, 0), erlang:yield(), _ = erlang:monitor(process, Pid, AliasOpt ++ TagOpt), exit(bang) @@ -1404,22 +1401,3 @@ generate(_Fun, 0) -> []; generate(Fun, N) -> [Fun() | generate(Fun, N-1)]. - -start_node(Config, Args) -> - TestCase = proplists:get_value(testcase, Config), - PA = filename:dirname(code:which(?MODULE)), - ESTime = erlang:monotonic_time(1) + erlang:time_offset(1), - Unique = erlang:unique_integer([positive]), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(TestCase) - ++ "-" - ++ integer_to_list(ESTime) - ++ "-" - ++ integer_to_list(Unique)), - test_server:start_node(Name, - slave, - [{args, "-pa " ++ PA ++ " " ++ Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl index 1100f6cf4602..e17d56d535bf 100644 --- a/erts/emulator/test/mtx_SUITE.erl +++ b/erts/emulator/test/mtx_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -275,7 +275,7 @@ hammer_sched_rwlock_test(FreqRead, LockCheck, Blocking, WaitLocked, WaitUnlocked _ -> {_, RunTime} = statistics(runtime), io:format("RunTime=~p~n", [RunTime]), - true = RunTime < 700, + true = RunTime < max(700, Onln*12), {comment, "Run-time during test was " ++ integer_to_list(RunTime) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 9fbcde4e3a8e..359646ca5c65 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -33,6 +33,7 @@ init_per_testcase/2, end_per_testcase/2, basic/1, reload_error/1, upgrade/1, heap_frag/1, t_on_load/1, + t_nifs_attrib/1, t_load_race/1, t_call_nif_early/1, load_traced_nif/1, @@ -45,7 +46,10 @@ monitor_process_purge/1, demonitor_process/1, monitor_frenzy/1, - types/1, many_args/1, binaries/1, get_string/1, get_atom/1, + types/1, many_args/1, binaries/1, + get_string/1, get_string_length/1, + get_atom/1, get_atom_length/1, + make_new_atoms/1, make_existing_atoms/1, maps/1, api_macros/1, from_array/1, iolist_as_binary/1, resource/1, resource_binary/1, @@ -71,6 +75,7 @@ nif_whereis/1, nif_whereis_parallel/1, nif_whereis_threaded/1, nif_whereis_proxy/1, nif_ioq/1, + match_state_arg/1, pid/1, id/1, nif_term_type/1 @@ -78,6 +83,120 @@ -export([many_args_100/100]). +-nifs([lib_version/0, + call_history/0, + hold_nif_mod_priv_data/1, + nif_mod_call_history/0, + list_seq/1, + type_test/0, + tuple_2_list/1, + is_identical/2, + compare/2, + hash_nif/3, + many_args_100/100, + clone_bin/1, + make_sub_bin/3, + string_to_bin/3, + string_length/2, + atom_to_bin/3, + atom_length/2, + macros/1, + tuple_2_list_and_tuple/1, + iolist_2_bin/1, + get_resource_type/1, + init_resource_type/2, + alloc_resource/2, + make_resource/1, + get_resource/2, + release_resource/1, + release_resource_from_thread/1, + last_resource_dtor_call_nif/0, + make_new_resource/2, + check_is/11, + check_is_exception/0, + length_test/6, + make_atoms/0, + make_new_atom/2, + make_existing_atom/2, + make_strings/0, + make_new_resource_binary/1, + send_list_seq/2, + send_new_blob/2, + alloc_msgenv/0, + clear_msgenv/1, + grow_blob/2, + grow_blob/3, + send_blob/2, + send3_blob/3, + send_blob_thread/3, + join_send_thread/1, + copy_blob/1, + send_term/2, + send_copy_term/2, + reverse_list/1, + echo_int/1, + type_sizes/0, + otp_9668_nif/1, + otp_9828_nif/1, + consume_timeslice_nif/2, + call_nif_schedule/2, + call_nif_exception/1, + call_nif_nan_or_inf/1, + call_nif_atom_too_long/1, + unique_integer_nif/1, + is_process_alive_nif/1, + is_port_alive_nif/1, + term_to_binary_nif/2, + binary_to_term_nif/3, + port_command_nif/2, + format_term_nif/2, + select_nif/6, + dupe_resource_nif/1, + pipe_nif/0, + write_nif/2, + read_nif/2, + close_nif/1, + is_closed_nif/1, + clear_select_nif/1, + last_fd_stop_call/0, + alloc_monitor_resource_nif/0, + monitor_process_nif/4, + demonitor_process_nif/2, + compare_monitors_nif/2, + make_monitor_term_nif/1, + monitor_frenzy_nif/4, + ioq_nif/1, + ioq_nif/2, + ioq_nif/3, + ioq_nif/4, + whereis_send/3, + whereis_term/2, + whereis_thd_lookup/3, + whereis_thd_result/1, + is_map_nif/1, + get_map_size_nif/1, + make_new_map_nif/0, + make_map_put_nif/3, + get_map_value_nif/2, + make_map_update_nif/3, + make_map_remove_nif/2, + maps_from_list_nif/1, + sorted_list_from_maps_nif/1, + monotonic_time/1, + time_offset/1, + convert_time_unit/3, + now_time/0, + cpu_time/0, + get_local_pid_nif/1, + make_pid_nif/1, + set_pid_undefined_nif/0, + is_pid_undefined_nif/1, + compare_pids_nif/2, + term_type_nif/1, + dynamic_resource_call/4, + msa_find_y_nif/1 + ]). + -define(nif_stub,nif_stub_error(?LINE)). -define(is_resource, is_reference). @@ -85,6 +204,9 @@ -define(RT_CREATE,1). -define(RT_TAKEOVER,2). +-define(ERL_NIF_LATIN1,1). +-define(ERL_NIF_UTF8,2). + suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -97,10 +219,13 @@ all() -> {group, monitor}, monitor_frenzy, t_dynamic_resource_call, + t_nifs_attrib, t_load_race, t_call_nif_early, load_traced_nif, - binaries, get_string, get_atom, maps, api_macros, from_array, + binaries, get_string, get_string_length, + get_atom, get_atom_length, make_new_atoms, make_existing_atoms, + maps, api_macros, from_array, iolist_as_binary, resource, resource_binary, threading, send, send2, send3, send_threaded, neg, is_checks, get_length, make_atom, @@ -119,6 +244,7 @@ all() -> nif_phash2, nif_whereis, nif_whereis_parallel, nif_whereis_threaded, nif_ioq, + match_state_arg, pid, nif_term_type]. @@ -505,14 +631,42 @@ t_on_load(Config) when is_list(Config) -> verify_tmpmem(TmpMem), ok. -%% Test erlang:load_nif/2 waiting for code_write_permission. +%% Test the -nifs() attribute +t_nifs_attrib(Config) when is_list(Config) -> + TmpMem = tmpmem(), + ensure_lib_loaded(Config), + + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "nif_mod"), + {ok,nif_mod,Bin3} = compile:file(File, [binary,return_errors, + {d,'USE_NIFS_ATTRIB',3}]), + + {module,nif_mod} = code:load_binary(nif_mod,File,Bin3), + ok = nif_mod:load_nif_lib(Config, 1), + 1 = nif_mod:lib_version(), + + {ok,nif_mod,Bin2} = compile:file(File, [binary,return_errors, + {d,'USE_NIFS_ATTRIB',2}]), + {module,nif_mod} = code:load_binary(nif_mod,File,Bin2), + {error, {bad_lib, "Function not declared as nif" ++ _}} = + nif_mod:load_nif_lib(Config, 1), + + {ok,nif_mod,Bin1} = compile:file(File, [binary,return_errors, + {d,'USE_NIFS_ATTRIB',1}]), + {module,nif_mod} = code:load_binary(nif_mod,File,Bin1), + {error, {bad_lib, "Function not declared as nif" ++ _}} = + nif_mod:load_nif_lib(Config, 1), + ok. + + +%% Test erlang:load_nif/2 waiting for code_mod_permission. t_load_race(Config) -> Data = proplists:get_value(data_dir, Config), File = filename:join(Data, "nif_mod"), {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), {module,nif_mod} = erlang:load_module(nif_mod,Bin), try - erts_debug:set_internal_state(code_write_permission, true), + erts_debug:set_internal_state(code_mod_permission, true), Papa = self(), spawn_link(fun() -> ok = nif_mod:load_nif_lib(Config, 1), @@ -521,7 +675,7 @@ t_load_race(Config) -> timer:sleep(100), timeout = receive_any(0) after - true = erts_debug:set_internal_state(code_write_permission, false) + true = erts_debug:set_internal_state(code_mod_permission, false) end, "NIF loaded" = receive_any(), @@ -1011,6 +1165,7 @@ monitor_process_c(Config) -> Pid = spawn_link(fun() -> R_ptr = alloc_monitor_resource_nif(), {0,Mon} = monitor_process_nif(R_ptr, self(), true, Papa), + receive after 1000 -> ok end, [R_ptr] = monitored_by(self()), put(store, make_resource(R_ptr)), ok = release_resource(R_ptr), @@ -1018,8 +1173,8 @@ monitor_process_c(Config) -> Papa ! {self(), done, R_ptr, Mon}, exit end), - [{Pid, done, R_ptr, Mon1}, - {monitor_resource_down, R_ptr, Pid, Mon2}] = flush(2), + receive {Pid, done, R_ptr, Mon1} -> ok end, + [{monitor_resource_down, R_ptr, Pid, Mon2}] = flush(1), compare_monitors_nif(Mon1, Mon2), {R_ptr, _, 1} = last_resource_dtor_call(), ok. @@ -1298,6 +1453,8 @@ dynamic_resource_call_do(Config, NifModBin) -> {1, 1000} = dynamic_resource_call(nif_mod, with_dyncall, R, 1000), true = erlang:purge_module(nif_mod), [{unload,2,2,202}] = nif_mod_call_history(), + + keep_alive(R), ok. @@ -1477,27 +1634,304 @@ test_make_sub_bin(Bin) -> %% Test enif_get_string get_string(Config) when is_list(Config) -> ensure_lib_loaded(Config, 1), - {7, <<"hejsan",0,_:3/binary>>} = string_to_bin("hejsan",10), - {7, <<"hejsan",0,_>>} = string_to_bin("hejsan",8), - {7, <<"hejsan",0>>} = string_to_bin("hejsan",7), - {-6, <<"hejsa",0>>} = string_to_bin("hejsan",6), - {-5, <<"hejs",0>>} = string_to_bin("hejsan",5), - {-1, <<0>>} = string_to_bin("hejsan",1), - {0, <<>>} = string_to_bin("hejsan",0), - {1, <<0>>} = string_to_bin("",1), - {0, <<>>} = string_to_bin("",0), + {7, <<"hejsan", 0, _:3/binary>>} = string_to_bin("hejsan", 10, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0, _>>} = string_to_bin("hejsan", 8, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0>>} = string_to_bin("hejsan", 7, ?ERL_NIF_LATIN1), + {-6, <<"hejsa", 0>>} = string_to_bin("hejsan", 6, ?ERL_NIF_LATIN1), + {-5, <<"hejs", 0>>} = string_to_bin("hejsan", 5, ?ERL_NIF_LATIN1), + {-1, <<0>>} = string_to_bin("hejsan", 1, ?ERL_NIF_LATIN1), + {0, <<>>} = string_to_bin("hejsan", 0, ?ERL_NIF_LATIN1), + {1, <<0>>} = string_to_bin("", 1, ?ERL_NIF_LATIN1), + {0, <<>>} = string_to_bin("", 0, ?ERL_NIF_LATIN1), + {6, <<"hallå", 0, _, _>>} = string_to_bin("hallå", 8, ?ERL_NIF_LATIN1), + {6, <<"hallå", 0, _>>} = string_to_bin("hallå", 7, ?ERL_NIF_LATIN1), + {6, <<"hallå", 0>>} = string_to_bin("hallå", 6, ?ERL_NIF_LATIN1), + {-5, <<"hall", 0>>} = string_to_bin("hallå", 5, ?ERL_NIF_LATIN1), + {-4, <<"hal", 0>>} = string_to_bin("hallå", 4, ?ERL_NIF_LATIN1), + {0, <<0, _, _>>} = string_to_bin("Ω", 3, ?ERL_NIF_LATIN1), + {0, <<0, _>>} = string_to_bin("Ω", 2, ?ERL_NIF_LATIN1), + {0, <<0>>} = string_to_bin("Ω", 1, ?ERL_NIF_LATIN1), + {0, <<>>} = string_to_bin("Ω", 0, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0, _:3/binary>>} = string_to_bin("hejsan", 10, ?ERL_NIF_UTF8), + {7, <<"hejsan", 0, _>>} = string_to_bin("hejsan", 8, ?ERL_NIF_UTF8), + {7, <<"hejsan", 0>>} = string_to_bin("hejsan", 7, ?ERL_NIF_UTF8), + {-6, <<"hejsa", 0>>} = string_to_bin("hejsan", 6, ?ERL_NIF_UTF8), + {-5, <<"hejs", 0>>} = string_to_bin("hejsan", 5, ?ERL_NIF_UTF8), + {-1, <<0>>} = string_to_bin("hejsan", 1, ?ERL_NIF_UTF8), + {0, <<>>} = string_to_bin("hejsan", 0, ?ERL_NIF_UTF8), + {1, <<0>>} = string_to_bin("", 1, ?ERL_NIF_UTF8), + {0, <<>>} = string_to_bin("", 0, ?ERL_NIF_UTF8), + {7, <<"hallå"/utf8, 0, _>>} = string_to_bin("hallå", 8, ?ERL_NIF_UTF8), + {7, <<"hallå"/utf8, 0>>} = string_to_bin("hallå", 7, ?ERL_NIF_UTF8), + {-5, <<"hall", 0, _>>} = string_to_bin("hallå", 6, ?ERL_NIF_UTF8), + {-5, <<"hall", 0>>} = string_to_bin("hallå", 5, ?ERL_NIF_UTF8), + {-4, <<"hal", 0>>} = string_to_bin("hallå", 4, ?ERL_NIF_UTF8), + {3, <<"Ω"/utf8, 0>>} = string_to_bin("Ω", 3, ?ERL_NIF_UTF8), + {-1, <<0, _>>} = string_to_bin("Ω", 2, ?ERL_NIF_UTF8), + {-1, <<0>>} = string_to_bin("Ω", 1, ?ERL_NIF_UTF8), + {0, <<>>} = string_to_bin("Ω", 0, ?ERL_NIF_UTF8), + + {0, <<_:5/binary>>} = string_to_bin([-10], 5, ?ERL_NIF_LATIN1), + {0, <<_:5/binary>>} = string_to_bin([-10], 5, ?ERL_NIF_UTF8), + {0, <<_:5/binary>>} = string_to_bin([(-1 bsl 8) + $A], 5, ?ERL_NIF_LATIN1), + {0, <<_:5/binary>>} = string_to_bin([(-1 bsl 8) + $A], 5, ?ERL_NIF_UTF8), + ok. + +%% Test enif_get_string_length +get_string_length(Config) when is_list(Config) -> + ensure_lib_loaded(Config, 1), + 0 = string_length("", ?ERL_NIF_LATIN1), + 6 = string_length("hejsan", ?ERL_NIF_LATIN1), + 5 = string_length("hallå", ?ERL_NIF_LATIN1), + false = string_length("Ω", ?ERL_NIF_LATIN1), + false = string_length("hejsanΩ", ?ERL_NIF_LATIN1), + 0 = string_length("", ?ERL_NIF_UTF8), + 6 = string_length("hejsan", ?ERL_NIF_UTF8), + 6 = string_length("hallå", ?ERL_NIF_UTF8), + 2 = string_length("Ω", ?ERL_NIF_UTF8), + 8 = string_length("hejsanΩ", ?ERL_NIF_UTF8), + + false = string_length([-10], ?ERL_NIF_LATIN1), + false = string_length([-10], ?ERL_NIF_UTF8), + false = string_length([(-1 bsl 8) + $A], ?ERL_NIF_LATIN1), + false = string_length([(-1 bsl 8) + $A], ?ERL_NIF_UTF8), ok. %% Test enif_get_atom get_atom(Config) when is_list(Config) -> ensure_lib_loaded(Config, 1), - {7, <<"hejsan",0,_:3/binary>>} = atom_to_bin(hejsan,10), - {7, <<"hejsan",0,_>>} = atom_to_bin(hejsan,8), - {7, <<"hejsan",0>>} = atom_to_bin(hejsan,7), - {0, <<_:6/binary>>} = atom_to_bin(hejsan,6), - {0, <<>>} = atom_to_bin(hejsan,0), - {1, <<0>>} = atom_to_bin('',1), - {0, <<>>} = atom_to_bin('',0), + Char1ByteLatin1 = <<"a">>, + Longest1ByteLatin1AtomText = binary:copy(Char1ByteLatin1, 255), + Longest1ByteLatin1Atom = erlang:binary_to_atom(Longest1ByteLatin1AtomText, latin1), + Char2ByteLatin1 = <<"å">>, + Longest2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 255), + Longest2ByteLatin1Atom = erlang:binary_to_atom(Longest2ByteLatin1AtomText, latin1), + Char2ByteUtf8 = <<"å"/utf8>>, + Longest2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 255), + Longest2ByteUtf8Atom = erlang:binary_to_atom(Longest2ByteUtf8AtomText, utf8), + Char3ByteUtf8 = <<"ᛥ"/utf8>>, + Longest3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 255), + Longest3ByteUtf8Atom = erlang:binary_to_atom(Longest3ByteUtf8AtomText, utf8), + Char4ByteUtf8 = <<"𠜱"/utf8>>, + Longest4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 255), + Longest4ByteUtf8Atom = erlang:binary_to_atom(Longest4ByteUtf8AtomText, utf8), + {7, <<"hejsan", 0, _:3/binary>>} = atom_to_bin(hejsan, 10, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0, _>>} = atom_to_bin(hejsan, 8, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0>>} = atom_to_bin(hejsan, 7, ?ERL_NIF_LATIN1), + {0, <<_:6/binary>>} = atom_to_bin(hejsan, 6, ?ERL_NIF_LATIN1), + {0, <<>>} = atom_to_bin(hejsan, 0, ?ERL_NIF_LATIN1), + {1, <<0>>} = atom_to_bin('', 1, ?ERL_NIF_LATIN1), + {0, <<>>} = atom_to_bin('', 0, ?ERL_NIF_LATIN1), + {6, <<"hallå", 0, _>>} = atom_to_bin('hallå', 7, ?ERL_NIF_LATIN1), + {6, <<"hallå", 0>>} = atom_to_bin('hallå', 6, ?ERL_NIF_LATIN1), + {0, <<_:5/binary>>} = atom_to_bin('hallå', 5, ?ERL_NIF_LATIN1), + {0, <<_:3/binary>>} = atom_to_bin('Ω', 3, ?ERL_NIF_LATIN1), + {0, <<_:2/binary>>} = atom_to_bin('Ω', 2, ?ERL_NIF_LATIN1), + {0, <<_>>} = atom_to_bin('Ω', 1, ?ERL_NIF_LATIN1), + {256, <>} = atom_to_bin(Longest1ByteLatin1Atom, 256, ?ERL_NIF_LATIN1), + {256, <>} = atom_to_bin(Longest2ByteLatin1Atom, 256, ?ERL_NIF_LATIN1), + {256, <>} = atom_to_bin(Longest2ByteLatin1Atom, 511, ?ERL_NIF_LATIN1), + {256, <>} = atom_to_bin(Longest2ByteUtf8Atom, 256, ?ERL_NIF_LATIN1), + {256, <>} = atom_to_bin(Longest2ByteUtf8Atom, 511, ?ERL_NIF_LATIN1), + {0, <<_:256/bytes>>} = atom_to_bin(Longest3ByteUtf8Atom, 256, ?ERL_NIF_LATIN1), + {0, <<_:766/bytes>>} = atom_to_bin(Longest3ByteUtf8Atom, 766, ?ERL_NIF_LATIN1), + {0, <<_:256/bytes>>} = atom_to_bin(Longest4ByteUtf8Atom, 256, ?ERL_NIF_LATIN1), + {0, <<_:1021/bytes>>} = atom_to_bin(Longest4ByteUtf8Atom, 1021, ?ERL_NIF_LATIN1), + {7, <<"hejsan", 0, _:3/binary>>} = atom_to_bin(hejsan, 10, ?ERL_NIF_UTF8), + {7, <<"hejsan", 0, _>>} = atom_to_bin(hejsan, 8, ?ERL_NIF_UTF8), + {7, <<"hejsan", 0>>} = atom_to_bin(hejsan, 7, ?ERL_NIF_UTF8), + {0, <<_:6/binary>>} = atom_to_bin(hejsan, 6, ?ERL_NIF_UTF8), + {0, <<>>} = atom_to_bin(hejsan, 0, ?ERL_NIF_UTF8), + {1, <<0>>} = atom_to_bin('', 1, ?ERL_NIF_UTF8), + {0, <<>>} = atom_to_bin('', 0, ?ERL_NIF_UTF8), + {7, <<"hallå"/utf8, 0>>} = atom_to_bin('hallå', 7, ?ERL_NIF_UTF8), + {0, <<_:6/binary>>} = atom_to_bin('hallå', 6, ?ERL_NIF_UTF8), + {0, <<_:5/binary>>} = atom_to_bin('hallå', 5, ?ERL_NIF_UTF8), + {3, <<"Ω"/utf8, 0>>} = atom_to_bin('Ω', 3, ?ERL_NIF_UTF8), + {0, <<_:2/binary>>} = atom_to_bin('Ω', 2, ?ERL_NIF_UTF8), + {0, <<_>>} = atom_to_bin('Ω', 1, ?ERL_NIF_UTF8), + {256, <>} = atom_to_bin(Longest1ByteLatin1Atom, 256, ?ERL_NIF_UTF8), + {0, <<_:256/bytes>>} = atom_to_bin(Longest2ByteLatin1Atom, 256, ?ERL_NIF_UTF8), + {511, <>} = atom_to_bin(Longest2ByteLatin1Atom, 511, ?ERL_NIF_UTF8), + {0, <<_:256/bytes>>} = atom_to_bin(Longest2ByteUtf8Atom, 256, ?ERL_NIF_UTF8), + {511, <>} = atom_to_bin(Longest2ByteUtf8Atom, 511, ?ERL_NIF_UTF8), + {0, <<_:256/bytes>>} = atom_to_bin(Longest3ByteUtf8Atom, 256, ?ERL_NIF_UTF8), + {766, <>} = atom_to_bin(Longest3ByteUtf8Atom, 766, ?ERL_NIF_UTF8), + {0, <<_:256/bytes>>} = atom_to_bin(Longest4ByteUtf8Atom, 256, ?ERL_NIF_UTF8), + {1021, <>} = atom_to_bin(Longest4ByteUtf8Atom, 1021, ?ERL_NIF_UTF8), + ok. + +%% Test enif_get_atom_length +get_atom_length(Config) when is_list(Config) -> + ensure_lib_loaded(Config, 1), + Char1ByteLatin1 = <<"a">>, + Longest1ByteLatin1AtomText = binary:copy(Char1ByteLatin1, 255), + Longest1ByteLatin1Atom = erlang:binary_to_atom(Longest1ByteLatin1AtomText, latin1), + Char2ByteLatin1 = <<"å">>, + Longest2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 255), + Longest2ByteLatin1Atom = erlang:binary_to_atom(Longest2ByteLatin1AtomText, latin1), + Char2ByteUtf8 = <<"å"/utf8>>, + Longest2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 255), + Longest2ByteUtf8Atom = erlang:binary_to_atom(Longest2ByteUtf8AtomText, utf8), + Char3ByteUtf8 = <<"ᛥ"/utf8>>, + Longest3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 255), + Longest3ByteUtf8Atom = erlang:binary_to_atom(Longest3ByteUtf8AtomText, utf8), + Char4ByteUtf8 = <<"𠜱"/utf8>>, + Longest4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 255), + Longest4ByteUtf8Atom = erlang:binary_to_atom(Longest4ByteUtf8AtomText, utf8), + 0 = atom_length('', ?ERL_NIF_LATIN1), + 6 = atom_length('hejsan', ?ERL_NIF_LATIN1), + 5 = atom_length('hallå', ?ERL_NIF_LATIN1), + false = atom_length('Ω', ?ERL_NIF_LATIN1), + false = atom_length('hejsanΩ', ?ERL_NIF_LATIN1), + 255 = atom_length(Longest1ByteLatin1Atom, ?ERL_NIF_LATIN1), + 255 = atom_length(Longest2ByteLatin1Atom, ?ERL_NIF_LATIN1), + 255 = atom_length(Longest2ByteUtf8Atom, ?ERL_NIF_LATIN1), + false = atom_length(Longest3ByteUtf8Atom, ?ERL_NIF_LATIN1), + false = atom_length(Longest4ByteUtf8Atom, ?ERL_NIF_LATIN1), + 0 = atom_length('', ?ERL_NIF_UTF8), + 6 = atom_length('hejsan', ?ERL_NIF_UTF8), + 6 = atom_length('hallå', ?ERL_NIF_UTF8), + 2 = atom_length('Ω', ?ERL_NIF_UTF8), + 8 = atom_length('hejsanΩ', ?ERL_NIF_UTF8), + 255 = atom_length(Longest1ByteLatin1Atom, ?ERL_NIF_UTF8), + 510 = atom_length(Longest2ByteLatin1Atom, ?ERL_NIF_UTF8), + 510 = atom_length(Longest2ByteUtf8Atom, ?ERL_NIF_UTF8), + 765 = atom_length(Longest3ByteUtf8Atom, ?ERL_NIF_UTF8), + 1020 = atom_length(Longest4ByteUtf8Atom, ?ERL_NIF_UTF8), + ok. + +%% Test enif_make_new_atom_len +make_new_atoms(Config) when is_list(Config) -> + ensure_lib_loaded(Config, 1), + Char1ByteAscii = <<"a">>, + Longest1ByteAsciiAtomText = binary:copy(Char1ByteAscii, 255), + TooLong1ByteAsciiAtomText = binary:copy(Char1ByteAscii, 256), + Longest1ByteLatin1Atom = erlang:binary_to_atom(Longest1ByteAsciiAtomText, latin1), + Char2ByteLatin1 = <<"å">>, + Longest2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 255), + TooLong2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 256), + Longest2ByteLatin1Atom = erlang:binary_to_atom(Longest2ByteLatin1AtomText, latin1), + Char2ByteUtf8 = <<"å"/utf8>>, + Longest2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 255), + TooLong2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 256), + Longest2ByteUtf8Atom = erlang:binary_to_atom(Longest2ByteUtf8AtomText, utf8), + Char3ByteUtf8 = <<"ᛥ"/utf8>>, + Longest3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 255), + TooLong3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 256), + Longest3ByteUtf8Atom = erlang:binary_to_atom(Longest3ByteUtf8AtomText, utf8), + Char4ByteUtf8 = <<"𠜱"/utf8>>, + Longest4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 255), + TooLong4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 256), + Longest4ByteUtf8Atom = erlang:binary_to_atom(Longest4ByteUtf8AtomText, utf8), + hejsan = make_new_atom(<<"hejsan">>, ?ERL_NIF_LATIN1), + 'hallå' = make_new_atom(<<"hallå">>, ?ERL_NIF_LATIN1), + 'Ω' = make_new_atom(<<"Ω"/utf8>>, ?ERL_NIF_LATIN1), + '' = make_new_atom(<<>>, ?ERL_NIF_LATIN1), + Longest1ByteAsciiAtom = make_new_atom(Longest1ByteAsciiAtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(TooLong1ByteAsciiAtomText, ?ERL_NIF_LATIN1), + Longest2ByteLatin1Atom = make_new_atom(Longest2ByteLatin1AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(TooLong2ByteLatin1AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(Longest2ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(TooLong2ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(Longest3ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(TooLong3ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(Longest4ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_new_atom(TooLong4ByteUtf8AtomText, ?ERL_NIF_LATIN1), + hejsan = make_new_atom(<<"hejsan"/utf8>>, ?ERL_NIF_UTF8), + 'hallå' = make_new_atom(<<"hallå"/utf8>>, ?ERL_NIF_UTF8), + 'Ω' = make_new_atom(<<"Ω"/utf8>>, ?ERL_NIF_UTF8), + '' = make_new_atom(<<>>, ?ERL_NIF_UTF8), + Longest1ByteAsciiAtom = make_new_atom(Longest1ByteAsciiAtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(TooLong1ByteAsciiAtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(Longest2ByteLatin1AtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(TooLong2ByteLatin1AtomText, ?ERL_NIF_UTF8), + Longest2ByteUtf8Atom = make_new_atom(Longest2ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(TooLong2ByteUtf8AtomText, ?ERL_NIF_UTF8), + Longest3ByteUtf8Atom = make_new_atom(Longest3ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(TooLong3ByteUtf8AtomText, ?ERL_NIF_UTF8), + Longest4ByteUtf8Atom = make_new_atom(Longest4ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_new_atom(TooLong4ByteUtf8AtomText, ?ERL_NIF_UTF8), + ok. + +%% Test enif_make_existing_atom_len +make_existing_atoms(Config) when is_list(Config) -> + ensure_lib_loaded(Config, 1), + _Existing = [hejsan, 'hallå', 'Ω', 'Ω', ''], + Char1ByteLatin1 = <<"a">>, + Char1ByteLatin1NE = <<"u">>, + Longest1ByteLatin1AtomText = binary:copy(Char1ByteLatin1, 255), + Longest1ByteLatin1AtomTextNE = binary:copy(Char1ByteLatin1NE, 255), + TooLong1ByteLatin1AtomText = binary:copy(Char1ByteLatin1, 256), + Longest1ByteLatin1Atom = erlang:binary_to_atom(Longest1ByteLatin1AtomText, latin1), + Char2ByteLatin1 = <<"å">>, + Char2ByteLatin1NE = <<"ú">>, + Longest2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 255), + Longest2ByteLatin1AtomTextNE = binary:copy(Char2ByteLatin1NE, 255), + TooLong2ByteLatin1AtomText = binary:copy(Char2ByteLatin1, 256), + Longest2ByteLatin1Atom = erlang:binary_to_atom(Longest2ByteLatin1AtomText, latin1), + Char2ByteUtf8 = <<"å"/utf8>>, + Char2ByteUtf8NE = <<"ú"/utf8>>, + Longest2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 255), + Longest2ByteUtf8AtomTextNE = binary:copy(Char2ByteUtf8NE, 255), + TooLong2ByteUtf8AtomText = binary:copy(Char2ByteUtf8, 256), + Longest2ByteUtf8Atom = erlang:binary_to_atom(Longest2ByteUtf8AtomText, utf8), + Char3ByteUtf8 = <<"ᛥ"/utf8>>, + Char3ByteUtf8NE = <<"ᛤ"/utf8>>, + Longest3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 255), + Longest3ByteUtf8AtomTextNE = binary:copy(Char3ByteUtf8NE, 255), + TooLong3ByteUtf8AtomText = binary:copy(Char3ByteUtf8, 256), + Longest3ByteUtf8Atom = erlang:binary_to_atom(Longest3ByteUtf8AtomText, utf8), + Char4ByteUtf8 = <<"𠜱"/utf8>>, + Char4ByteUtf8NE = <<"𠴕"/utf8>>, + Longest4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 255), + Longest4ByteUtf8AtomTextNE = binary:copy(Char4ByteUtf8NE, 255), + TooLong4ByteUtf8AtomText = binary:copy(Char4ByteUtf8, 256), + Longest4ByteUtf8Atom = erlang:binary_to_atom(Longest4ByteUtf8AtomText, utf8), + hejsan = make_existing_atom(<<"hejsan">>, ?ERL_NIF_LATIN1), + 'hallå' = make_existing_atom(<<"hallå">>, ?ERL_NIF_LATIN1), + 'Ω' = make_existing_atom(<<"Ω"/utf8>>, ?ERL_NIF_LATIN1), + '' = make_existing_atom(<<>>, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(<<"hejsan1234">>, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(<<"hallå1234">>, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(<<"Ω1234"/utf8>>, ?ERL_NIF_LATIN1), + Longest1ByteLatin1Atom = make_existing_atom(Longest1ByteLatin1AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest1ByteLatin1AtomTextNE, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(TooLong1ByteLatin1AtomText, ?ERL_NIF_LATIN1), + Longest2ByteLatin1Atom = make_existing_atom(Longest2ByteLatin1AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest2ByteLatin1AtomTextNE, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(TooLong2ByteLatin1AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest2ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest2ByteUtf8AtomTextNE, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(TooLong2ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest3ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest3ByteUtf8AtomTextNE, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(TooLong3ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest4ByteUtf8AtomText, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(Longest4ByteUtf8AtomTextNE, ?ERL_NIF_LATIN1), + 0 = make_existing_atom(TooLong4ByteUtf8AtomText, ?ERL_NIF_LATIN1), + hejsan = make_existing_atom(<<"hejsan"/utf8>>, ?ERL_NIF_UTF8), + 'hallå' = make_existing_atom(<<"hallå"/utf8>>, ?ERL_NIF_UTF8), + 'Ω' = make_existing_atom(<<"Ω"/utf8>>, ?ERL_NIF_UTF8), + '' = make_existing_atom(<<>>, ?ERL_NIF_UTF8), + 0 = make_existing_atom(<<"hejsan1234"/utf8>>, ?ERL_NIF_UTF8), + 0 = make_existing_atom(<<"hallå1234"/utf8>>, ?ERL_NIF_UTF8), + 0 = make_existing_atom(<<"Ω1234"/utf8>>, ?ERL_NIF_UTF8), + Longest1ByteLatin1Atom = make_existing_atom(Longest1ByteLatin1AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest1ByteLatin1AtomTextNE, ?ERL_NIF_UTF8), + 0 = make_existing_atom(TooLong1ByteLatin1AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest2ByteLatin1AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest2ByteLatin1AtomTextNE, ?ERL_NIF_UTF8), + 0 = make_existing_atom(TooLong2ByteLatin1AtomText, ?ERL_NIF_UTF8), + Longest2ByteUtf8Atom = make_existing_atom(Longest2ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest2ByteUtf8AtomTextNE, ?ERL_NIF_UTF8), + 0 = make_existing_atom(TooLong2ByteUtf8AtomText, ?ERL_NIF_UTF8), + Longest3ByteUtf8Atom = make_existing_atom(Longest3ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest3ByteUtf8AtomTextNE, ?ERL_NIF_UTF8), + 0 = make_existing_atom(TooLong3ByteUtf8AtomText, ?ERL_NIF_UTF8), + Longest4ByteUtf8Atom = make_existing_atom(Longest4ByteUtf8AtomText, ?ERL_NIF_UTF8), + 0 = make_existing_atom(Longest4ByteUtf8AtomTextNE, ?ERL_NIF_UTF8), + 0 = make_existing_atom(TooLong4ByteUtf8AtomText, ?ERL_NIF_UTF8), ok. %% Test NIF maps handling. @@ -1720,6 +2154,12 @@ resource_neg_do(TypeA) -> ResB= make_new_resource(TypeB, <<"Bobo">>), {'EXIT',{badarg,_}} = (catch get_resource(TypeA, ResB)), {'EXIT',{badarg,_}} = (catch get_resource(TypeB, ResA)), + + %% Test init_resource_type fail outside load/upgrade + {0, ?RT_CREATE} = init_resource_type("in_vain", ?RT_CREATE), + {0, ?RT_TAKEOVER} = init_resource_type("Gold", ?RT_TAKEOVER), + {0, ?RT_CREATE bor ?RT_TAKEOVER} = + init_resource_type("Gold", ?RT_CREATE bor ?RT_TAKEOVER), ok. %% Test enif_make_resource_binary @@ -2505,8 +2945,10 @@ neg(Config) when is_list(Config) -> {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]), {module,nif_mod} = erlang:load_module(nif_mod,Bin), - {error,{load_failed,_}} = nif_mod:load_nif_lib(Config, 0), - {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init), + {error,{load_failed,"Failed to load NIF library"++_}} = nif_mod:load_nif_lib(Config, 0), + {error,{bad_lib,"Failed to find library init"++_}} = nif_mod:load_nif_lib(Config, 3), + {error,{bad_lib,"Function not found"++_}} = nif_mod:load_nif_lib(Config, 4), + {error,{bad_lib,"Duplicate NIF entry for"++_}} = nif_mod:load_nif_lib(Config, 5), verify_tmpmem(TmpMem), ok. @@ -3339,12 +3781,7 @@ random_sign() -> end. random_binary() -> - list_to_binary(random_bytes(rand:uniform(32) - 1)). - -random_bytes(0) -> - []; -random_bytes(N) when N > 0 -> - [rand:uniform(256) - 1 | random_bytes(N - 1)]. + rand:bytes(rand:uniform(32) - 1). random_pid() -> Processes = erlang:processes(), @@ -3397,7 +3834,7 @@ nif_whereis(Config) when is_list(Config) -> nif_whereis_parallel(Config) when is_list(Config) -> ensure_lib_loaded(Config), - %% try to be at least a little asymetric + %% try to be at least a little asymmetric NProcs = trunc(3.7 * erlang:system_info(schedulers)), NSeq = lists:seq(1, NProcs), Names = [list_to_atom("nif_whereis_proc_" ++ integer_to_list(N)) @@ -3798,6 +4235,30 @@ nif_term_type(Config) -> ok. +%% Verify match state arguments are not passed to declared NIFs. +match_state_arg(Config) -> + ensure_lib_loaded(Config), + Bin = term_to_binary([<<"x">> | Config]), % a non-literal binary with an $x byte + <<"nif says ok">> = msa_find_x_y(Bin), + ok. + +%% Without declaring msa_find_y_nif/1 as NIF, the compiler would do +%% optimization and pass it a match state as argument. +msa_find_x_y(<<$x, Rest/binary>>) -> + msa_find_y_nif(Rest); +msa_find_x_y(<<_, Rest/binary>>) -> + msa_find_x_y(Rest); +msa_find_x_y(<<>>) -> + "no x". + +msa_find_y_nif(<<$y, Rest/binary>>) -> + Rest; +msa_find_y_nif(<<_, Rest/binary>>) -> + msa_find_y_nif(Rest); +msa_find_y_nif(<<>>) -> + "no y". + + last_resource_dtor_call() -> erts_debug:set_internal_state(wait, aux_work), last_resource_dtor_call_nif(). @@ -3819,12 +4280,15 @@ hash_nif(_Type, _Term, _Salt) -> ?nif_stub. many_args_100(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. clone_bin(_) -> ?nif_stub. make_sub_bin(_,_,_) -> ?nif_stub. -string_to_bin(_,_) -> ?nif_stub. -atom_to_bin(_,_) -> ?nif_stub. +string_to_bin(_,_,_) -> ?nif_stub. +string_length(_,_) -> ?nif_stub. +atom_to_bin(_,_,_) -> ?nif_stub. +atom_length(_,_) -> ?nif_stub. macros(_) -> ?nif_stub. tuple_2_list_and_tuple(_) -> ?nif_stub. iolist_2_bin(_) -> ?nif_stub. get_resource_type(_) -> ?nif_stub. +init_resource_type(_,_) -> ?nif_stub. alloc_resource(_,_) -> ?nif_stub. make_resource(_) -> ?nif_stub. get_resource(_,_) -> ?nif_stub. @@ -3836,6 +4300,8 @@ check_is(_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. check_is_exception() -> ?nif_stub. length_test(_,_,_,_,_,_) -> ?nif_stub. make_atoms() -> ?nif_stub. +make_new_atom(_,_) -> ?nif_stub. +make_existing_atom(_,_) -> ?nif_stub. make_strings() -> ?nif_stub. make_new_resource_binary(_) -> ?nif_stub. send_list_seq(_,_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/Makefile.src b/erts/emulator/test/nif_SUITE_data/Makefile.src index 69dd2d67574c..ebbdfe531524 100644 --- a/erts/emulator/test/nif_SUITE_data/Makefile.src +++ b/erts/emulator/test/nif_SUITE_data/Makefile.src @@ -3,6 +3,8 @@ NIF_LIBS = nif_SUITE.1@dll@ \ nif_mod.1@dll@ \ nif_mod.2@dll@ \ nif_mod.3@dll@ \ + nif_mod.4@dll@ \ + nif_mod.5@dll@ \ nif_mod.1.2_0@dll@ \ nif_mod.2.2_0@dll@ \ nif_mod.3.2_0@dll@ \ diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index b664594c76a6..5ae97e529d54 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2021. All Rights Reserved. + * Copyright Ericsson AB 2009-2023. 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. @@ -91,6 +91,8 @@ static ERL_NIF_TERM atom_port; static ERL_NIF_TERM atom_send; static ERL_NIF_TERM atom_lookup; static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_latin1; +static ERL_NIF_TERM atom_utf8; typedef struct { @@ -280,6 +282,8 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_send = enif_make_atom(env, "send"); atom_lookup = enif_make_atom(env, "lookup"); atom_badarg = enif_make_atom(env, "badarg"); + atom_latin1 = enif_make_atom(env, "latin1"); + atom_utf8 = enif_make_atom(env, "utf8"); *priv_data = data; return 0; @@ -784,28 +788,63 @@ static ERL_NIF_TERM string_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM a { ErlNifBinary obin; unsigned size; + int encoding; int n; - if (!enif_get_int(env,argv[1],(int*)&size) - || !enif_alloc_binary(size,&obin)) { - return enif_make_badarg(env); + if (!enif_get_int(env, argv[2], &encoding) + || !enif_get_int(env, argv[1], (int *)&size) + || !enif_alloc_binary(size, &obin)) { + return enif_make_badarg(env); } - n = enif_get_string(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1); - return enif_make_tuple(env, 2, enif_make_int(env,n), - enif_make_binary(env,&obin)); + n = enif_get_string(env, argv[0], (char *)obin.data, size, + (ErlNifCharEncoding) encoding); + return enif_make_tuple(env, 2, enif_make_int(env, n), + enif_make_binary(env, &obin)); +} + +static ERL_NIF_TERM string_length(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + unsigned size; + int encoding; + + if (!enif_get_int(env, argv[1], &encoding)) { + return enif_make_badarg(env); + } + if (!enif_get_string_length(env, argv[0], &size, + (ErlNifCharEncoding)encoding)) { + return atom_false; + } + return enif_make_uint(env, size); } static ERL_NIF_TERM atom_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary obin; unsigned size; + int encoding; int n; - if (!enif_get_int(env,argv[1],(int*)&size) - || !enif_alloc_binary(size,&obin)) { - return enif_make_badarg(env); + if (!enif_get_int(env, argv[2], &encoding) + || !enif_get_int(env, argv[1], (int *)&size) + || !enif_alloc_binary(size,&obin)) { + return enif_make_badarg(env); } - n = enif_get_atom(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1); - return enif_make_tuple(env, 2, enif_make_int(env,n), - enif_make_binary(env,&obin)); + n = enif_get_atom(env, argv[0], (char *)obin.data, size, + (ErlNifCharEncoding)encoding); + return enif_make_tuple(env, 2, enif_make_int(env, n), + enif_make_binary(env, &obin)); +} + +static ERL_NIF_TERM atom_length(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + unsigned size; + int encoding; + + if (!enif_get_int(env, argv[1], &encoding)) + return enif_make_badarg(env); + if (!enif_get_atom_length(env, argv[0], &size, + (ErlNifCharEncoding)encoding)) { + return atom_false; + } + return enif_make_uint(env, size); } static ERL_NIF_TERM macros(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -893,6 +932,27 @@ static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TE return make_pointer(env, data->rt_arr[ix].vp); } +static ERL_NIF_TERM init_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + char name[20]; + int flags; + ErlNifResourceTypeInit init; + ErlNifResourceType* ret_ptr; + ErlNifResourceFlags tried; + + if (0 >= enif_get_string(env, argv[0], name, sizeof(name), ERL_NIF_UTF8) || + !enif_get_int(env, argv[1], &flags)) { + return enif_make_badarg(env); + } + /* Should fail as we are not in load/upgrade callback */ + init.members = 0; + ret_ptr = enif_init_resource_type(env, name, &init, + (ErlNifResourceFlags)flags, &tried); + + return enif_make_tuple2(env, enif_make_uint64(env, (ErlNifUInt64)ret_ptr), + enif_make_int(env, (int)tried)); +} + static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary data_bin; @@ -1143,6 +1203,41 @@ static ERL_NIF_TERM make_atoms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv arr[0],arr[1],arr[2],arr[3],arr[4],arr[5],arr[6]); } +static ERL_NIF_TERM make_new_atom(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary name_bin; + int encoding; + ERL_NIF_TERM atom_term; + int ret; + + if (!enif_get_int(env, argv[1], &encoding) + || !enif_inspect_binary(env, argv[0], &name_bin)) { + return enif_make_badarg(env); + } + if (!enif_make_new_atom_len(env, (void *)name_bin.data, name_bin.size, &atom_term, + (ErlNifCharEncoding)encoding)) { + return enif_make_int(env, 0); + } + return atom_term; +} + +static ERL_NIF_TERM make_existing_atom(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary name_bin; + int encoding; + ERL_NIF_TERM atom_term; + + if (!enif_get_int(env, argv[1], &encoding) + || !enif_inspect_binary(env, argv[0], &name_bin)) { + return enif_make_badarg(env); + } + if (!enif_make_existing_atom_len(env, (void *)name_bin.data, name_bin.size, &atom_term, + (ErlNifCharEncoding)encoding)) { + return enif_make_int(env,0); + } + return atom_term; +} + static ERL_NIF_TERM make_strings(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { const char a0string[8] = {'a','0','s','t','r','i','n','g'}; @@ -3685,6 +3780,22 @@ static ERL_NIF_TERM term_type_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a } } +static ERL_NIF_TERM msa_find_y_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary bin; + const char ok_str[] = "nif says ok"; + ERL_NIF_TERM ok_bin; + + /* just verify that arg is a binary (and not a match state) */ + if (!enif_inspect_binary(env, argv[0], &bin) || + !enif_is_binary(env, argv[0])) { + return enif_make_string(env, "nif says arg not a binary", ERL_NIF_LATIN1); + } + memcpy(enif_make_new_binary(env, strlen(ok_str), &ok_bin), + ok_str, strlen(ok_str)); + return ok_bin; +} + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, @@ -3700,12 +3811,15 @@ static ErlNifFunc nif_funcs[] = {"many_args_100", 100, many_args_100}, {"clone_bin", 1, clone_bin}, {"make_sub_bin", 3, make_sub_bin}, - {"string_to_bin", 2, string_to_bin}, - {"atom_to_bin", 2, atom_to_bin}, + {"string_to_bin", 3, string_to_bin}, + {"string_length", 2, string_length}, + {"atom_to_bin", 3, atom_to_bin}, + {"atom_length", 2, atom_length}, {"macros", 1, macros}, {"tuple_2_list_and_tuple",1,tuple_2_list_and_tuple}, {"iolist_2_bin", 1, iolist_2_bin}, {"get_resource_type", 1, get_resource_type}, + {"init_resource_type", 2, init_resource_type}, {"alloc_resource", 2, alloc_resource}, {"make_resource", 1, make_resource}, {"get_resource", 2, get_resource}, @@ -3716,6 +3830,8 @@ static ErlNifFunc nif_funcs[] = {"check_is_exception", 0, check_is_exception}, {"length_test", 6, length_test}, {"make_atoms", 0, make_atoms}, + {"make_new_atom", 2, make_new_atom}, + {"make_existing_atom", 2, make_existing_atom}, {"make_strings", 0, make_strings}, {"make_new_resource", 2, make_new_resource}, {"make_new_resource_binary", 1, make_new_resource_binary}, @@ -3794,8 +3910,8 @@ static ErlNifFunc nif_funcs[] = {"set_pid_undefined_nif", 0, set_pid_undefined_nif}, {"is_pid_undefined_nif", 1, is_pid_undefined_nif}, {"compare_pids_nif", 2, compare_pids_nif}, - {"term_type_nif", 1, term_type_nif} - + {"term_type_nif", 1, term_type_nif}, + {"msa_find_y_nif", 1, msa_find_y_nif} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,NULL,upgrade,unload) diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.4.c b/erts/emulator/test/nif_SUITE_data/nif_mod.4.c new file mode 100644 index 000000000000..78ede3fbecdc --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.4.c @@ -0,0 +1,2 @@ +#define NIF_LIB_VER 4 +#include "nif_mod.c" diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.5.c b/erts/emulator/test/nif_SUITE_data/nif_mod.5.c new file mode 100644 index 000000000000..ea6ab1a07bbc --- /dev/null +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.5.c @@ -0,0 +1,2 @@ +#define NIF_LIB_VER 5 +#include "nif_mod.c" diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c index edc2a7aac5ad..6aea10751386 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.c +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c @@ -391,6 +391,13 @@ static ErlNifFunc nif_funcs[] = #ifdef HAVE_ENIF_MONITOR_PROCESS {"monitor_process", 3, monitor_process}, #endif +#if NIF_LIB_VER == 4 + {"non_existing", 2, get_resource}, /* error: not found */ +#endif +#if NIF_LIB_VER == 5 + {"make_new_resource", 2, get_resource}, /* error: duplicate */ +#endif + /* Keep lib_version_check last to maximize the loading "patch distance" between it and lib_version */ {"lib_version_check", 0, lib_version} diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl index 1fdaf5dae47b..38e2c13a46bf 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -31,6 +31,16 @@ -define(nif_stub,nif_stub_error(?LINE)). +-ifdef(USE_NIFS_ATTRIB). +-nifs([lib_version/0, nif_api_version/0, get_priv_data_ptr/0]). +-if(?USE_NIFS_ATTRIB > 1). +-nifs([make_new_resource/2, get_resource/2, monitor_process/3]). +-if(?USE_NIFS_ATTRIB > 2). +-nifs([lib_version_check/0]). +-endif. +-endif. +-endif. + -ifdef(USE_ON_LOAD). -on_load(on_load/0). diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl index ec1ac3a042fc..13d111a1ad6f 100644 --- a/erts/emulator/test/node_container_SUITE.erl +++ b/erts/emulator/test/node_container_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -81,13 +81,44 @@ init_per_testcase(_Case, Config) when is_list(Config) -> Config. end_per_testcase(_Case, Config) when is_list(Config) -> - ok. + erts_test_utils:ept_check_leaked_nodes(Config). %%% %%% The test cases ------------------------------------------------------------- %%% --define(MAX_PIDS_PORTS, ((1 bsl 28) - 1)). +max_internal_pids_ports() -> + case erlang:system_info(wordsize) of + 8 -> (1 bsl 60) - 1; + 4 -> (1 bsl 28) - 1 + end. + +max_pids_ports() -> + (1 bsl 64) - 1. + +max_old_pids_ports() -> + (1 bsl 28) - 1. + +max_internal_pid_num() -> + (1 bsl 28) - 1. + +max_internal_pid_ser() -> + case erlang:system_info(wordsize) of + 8 -> (1 bsl 32) - 1; + 4 -> 0 + end. + +max_pid_num() -> + (1 bsl 32) - 1. + +max_pid_ser() -> + (1 bsl 32) - 1. + +max_old_pid_num() -> + (1 bsl 15) - 1. + +max_old_pid_ser() -> + (1 bsl 13) - 1. %% %% Test case: term_to_binary_to_term_eq @@ -98,17 +129,21 @@ term_to_binary_to_term_eq(Config) when is_list(Config) -> ThisNode = {node(), erlang:system_info(creation)}, % Get local node containers LPid = self(), - LXPid = mk_pid(ThisNode, 32767, 8191), + LXPid = mk_pid(ThisNode, 0, max_internal_pid_ser()), + LX2Pid = mk_pid(ThisNode, max_internal_pid_num() - 4711, max_internal_pid_ser()), LPort = hd(erlang:ports()), LXPort = mk_port(ThisNode, 268435455), + LX2Port = mk_port(ThisNode, max_internal_pids_ports() - 4711), LLRef = make_ref(), LHLRef = mk_ref(ThisNode, [47, 11]), LSRef = mk_ref(ThisNode, [4711]), % Test local nc:s LPid = binary_to_term(term_to_binary(LPid)), LXPid = binary_to_term(term_to_binary(LXPid)), + LX2Pid = binary_to_term(term_to_binary(LX2Pid)), LPort = binary_to_term(term_to_binary(LPort)), LXPort = binary_to_term(term_to_binary(LXPort)), + LX2Port = binary_to_term(term_to_binary(LX2Port)), LLRef = binary_to_term(term_to_binary(LLRef)), LHLRef = binary_to_term(term_to_binary(LHLRef)), LSRef = binary_to_term(term_to_binary(LSRef)), @@ -122,6 +157,7 @@ term_to_binary_to_term_eq(Config) when is_list(Config) -> ttbtteq_do_remote(RNode) -> RPid = mk_pid(RNode, 4711, 1), RXPid = mk_pid(RNode, 32767, 8191), + RXPid2 = mk_pid(RNode, max_pid_num(), max_pid_ser()), RPort = mk_port(RNode, 4711), RXPort = mk_port(RNode, 268435455), RXPort2 = case RNode of @@ -130,15 +166,18 @@ ttbtteq_do_remote(RNode) -> _ -> mk_port(RNode, (1 bsl 51) + 4711) end, + RXPort3 = mk_port(RNode, max_pids_ports()), RLRef = mk_ref(RNode, [4711, 4711, 4711]), RHLRef = mk_ref(RNode, [4711, 4711]), RSRef = mk_ref(RNode, [4711]), % Test remote nc:s RPid = binary_to_term(term_to_binary(RPid)), RXPid = binary_to_term(term_to_binary(RXPid)), + RXPid2 = binary_to_term(term_to_binary(RXPid2)), RPort = binary_to_term(term_to_binary(RPort)), RXPort = binary_to_term(term_to_binary(RXPort)), RXPort2 = binary_to_term(term_to_binary(RXPort2)), + RXPort3 = binary_to_term(term_to_binary(RXPort3)), RLRef = binary_to_term(term_to_binary(RLRef)), RHLRef = binary_to_term(term_to_binary(RHLRef)), RSRef = binary_to_term(term_to_binary(RSRef)), @@ -151,8 +190,7 @@ ttbtteq_do_remote(RNode) -> %% Tests that node containers that are sent between nodes stay equal to themselves. round_trip_eq(Config) when is_list(Config) -> ThisNode = {node(), erlang:system_info(creation)}, - NodeFirstName = get_nodefirstname(), - {ok, Node} = start_node(NodeFirstName), + {ok, Peer, Node} = ?CT_PEER(), Self = self(), RPid = spawn_link(Node, fun () -> @@ -162,36 +200,57 @@ round_trip_eq(Config) when is_list(Config) -> end end), SentPid = self(), - SentXPid = mk_pid(ThisNode, 17471, 8190), + SentXPid = mk_pid(ThisNode, 17471, max_internal_pid_ser()), + SentXPid2 = mk_pid(ThisNode, max_internal_pid_num(), max_internal_pid_ser()), + SentXPid3 = mk_pid({Node, 4711}, 4711, 17), + SentXPid4 = mk_pid({Node, 4711}, max_pid_num(), max_pid_ser()), SentPort = hd(erlang:ports()), SentXPort = mk_port(ThisNode, 268435451), SentXPort2 = mk_port({Node, 4711}, (1 bsl 49) + 4711), + SentXPort2 = mk_port({Node, 4711}, (1 bsl 49) + 4711), + SentXPort3 = mk_port(ThisNode, max_internal_pids_ports()), + SentXPort4 = mk_port({Node, 4711}, max_pids_ports()), SentLRef = make_ref(), SentHLRef = mk_ref(ThisNode, [4711, 17]), SentSRef = mk_ref(ThisNode, [4711]), RPid ! {Self, {SentPid, SentXPid, + SentXPid2, + SentXPid3, + SentXPid4, SentPort, SentXPort, SentXPort2, + SentXPort3, + SentXPort4, SentLRef, SentHLRef, SentSRef}}, receive {RPid, {RecPid, RecXPid, + RecXPid2, + RecXPid3, + RecXPid4, RecPort, RecXPort, RecXPort2, + RecXPort3, + RecXPort4, RecLRef, RecHLRef, RecSRef}} -> - stop_node(Node), + stop_node(Peer, Node), SentPid = RecPid, SentXPid = RecXPid, + SentXPid2 = RecXPid2, + SentXPid3 = RecXPid3, + SentXPid4 = RecXPid4, SentPort = RecPort, SentXPort = RecXPort, SentXPort2 = RecXPort2, + SentXPort3 = RecXPort3, + SentXPort4 = RecXPort4, SentLRef = RecLRef, SentHLRef = RecHLRef, SentSRef = RecSRef, @@ -328,8 +387,8 @@ cmp(Config) when is_list(Config) -> true = mk_pid({b@b, 2}, 4711, 1) =:= Pid, %% Test big external pids (> OTP-24) - MaxPidNum = (1 bsl 15) - 1, - MaxPidSer = ?MAX_PIDS_PORTS bsr 15, + MaxPidNum = max_old_pid_num(), + MaxPidSer = max_old_pid_ser(), true = mk_pid({b@b, 2}, 4711, MaxPidSer) < mk_pid({a@b, 1}, 4710, MaxPidSer+1), true = mk_pid({b@b, 2}, 4711, MaxPidSer) < mk_pid({a@b, 1}, 4710, (1 bsl 31)), true = mk_pid({b@b, 2}, 4711, MaxPidSer) < mk_pid({a@b, 1}, 4710, (1 bsl 32)-1), @@ -486,8 +545,7 @@ make_faked_pid_list(Start, No, Creation, Acc) -> %% Tests that external reference counts are incremented and decremented %% as they should for distributed links dist_link_refc(Config) when is_list(Config) -> - NodeFirstName = get_nodefirstname(), - {ok, Node} = start_node(NodeFirstName), + {ok, Peer, Node} = ?CT_PEER(), RP = spawn_execer(Node), LP = spawn_link_execer(node()), true = sync_exec(RP, fun () -> link(LP) end), @@ -510,7 +568,7 @@ dist_link_refc(Config) when is_list(Config) -> refering_entity_id({process, LP}, get_node_references({Node, NodeCre}))), exit(LP, normal), - stop_node(Node), + stop_node(Peer, Node), nc_refc_check(node()), ok. @@ -521,8 +579,7 @@ dist_link_refc(Config) when is_list(Config) -> %% Tests that external reference counts are incremented and decremented %% as they should for distributed monitors dist_monitor_refc(Config) when is_list(Config) -> - NodeFirstName = get_nodefirstname(), - {ok, Node} = start_node(NodeFirstName), + {ok, Peer, Node} = ?CT_PEER(), RP = spawn_execer(Node), LP = spawn_link_execer(node()), RMon = sync_exec(RP, fun () -> erlang:monitor(process, LP) end), @@ -563,7 +620,7 @@ dist_monitor_refc(Config) when is_list(Config) -> refering_entity_id({process, LP}, get_node_references({Node, NodeCre}))), exit(LP, normal), - stop_node(Node), + stop_node(Peer, Node), nc_refc_check(node()), ok. @@ -576,8 +633,7 @@ dist_monitor_refc(Config) when is_list(Config) -> node_controller_refc(Config) when is_list(Config) -> erts_debug:set_internal_state(available_internal_state, true), erts_debug:set_internal_state(node_tab_delayed_delete, 0), - NodeFirstName = get_nodefirstname(), - {ok, Node} = start_node(NodeFirstName), + {ok, Peer, Node} = ?CT_PEER(), true = lists:member(Node, nodes()), 1 = reference_type_count(control, get_dist_references(Node)), P = spawn_link_execer(node()), @@ -590,7 +646,7 @@ node_controller_refc(Config) when is_list(Config) -> end), Creation = rpc:call(Node, erlang, system_info, [creation]), monitor_node(Node,true), - stop_node(Node), + stop_node(Peer, Node), receive {nodedown, Node} -> ok end, DistRefs = get_dist_references(Node), true = reference_type_count(node, DistRefs) > 0, @@ -742,20 +798,20 @@ pp_wrap(What) -> io:format("post creations = ~p~n", [PostCre]), true = is_integer(PostCre), true = PreCre > PostCre, - Now = set_next_id(What, ?MAX_PIDS_PORTS div 2), + Now = set_next_id(What, max_internal_pids_ports() div 2), io:format("reset to = ~p~n", [Now]), true = is_integer(Now), ok. set_high_pp_next(What) -> - set_high_pp_next(What, ?MAX_PIDS_PORTS-1). + set_high_pp_next(What, max_internal_pids_ports()-1). set_high_pp_next(What, N) -> M = set_next_id(What, N), true = is_integer(M), - case {M >= N, M =< ?MAX_PIDS_PORTS} of + case {M >= N, M =< max_internal_pids_ports()} of {true, true} -> - ?MAX_PIDS_PORTS - M + 1; + max_internal_pids_ports() - M + 1; _ -> set_high_pp_next(What, N - 100) end. @@ -784,22 +840,24 @@ do_pp_creations(port, N) when is_integer(N) -> bad_nc(Config) when is_list(Config) -> % Make sure emulator don't crash on bad node containers... - MaxPidNum = (1 bsl 15) - 1, - MaxPidSer = ?MAX_PIDS_PORTS bsr 15, ThisNode = {node(), erlang:system_info(creation)}, {'EXIT', {badarg, mk_pid, _}} - = (catch mk_pid(ThisNode, MaxPidNum + 1, 17)), + = (catch mk_pid(ThisNode, max_internal_pid_num() + 1, 17)), {'EXIT', {badarg, mk_pid, _}} - = (catch mk_pid(ThisNode, 4711, MaxPidSer + 1)), + = (catch mk_pid(ThisNode, 4711, max_internal_pid_ser() + 1)), {'EXIT', {badarg, mk_port, _}} - = (catch mk_port(ThisNode, ?MAX_PIDS_PORTS + 1)), + = (catch mk_port(ThisNode, max_internal_pids_ports() + 1)), {'EXIT', {badarg, mk_ref, _}} = (catch mk_ref(ThisNode,[(1 bsl 18), 4711, 4711])), {'EXIT', {badarg, mk_ref, _}} = (catch mk_ref(ThisNode, [4711, 4711, 4711, 4711, 4711, 4711, 4711])), RemNode = {x@y, 2}, + {'EXIT', {badarg, mk_pid, _}} + = (catch mk_pid(RemNode, max_pid_num() + 1, 17)), + {'EXIT', {badarg, mk_pid, _}} + = (catch mk_pid(RemNode, 4711, max_pid_ser() + 1)), {'EXIT', {badarg, mk_port, _}} - = (catch mk_port(RemNode, ?MAX_PIDS_PORTS + 1)), + = (catch mk_port(RemNode, max_pids_ports() + 1)), {'EXIT', {badarg, mk_ref, _}} = (catch mk_ref(RemNode, [(1 bsl 18), 4711, 4711])), {'EXIT', {badarg, mk_ref, _}} @@ -812,14 +870,17 @@ bad_nc(Config) when is_list(Config) -> {'EXIT', {badarg, mk_ref, _}} = (catch mk_ref(BadNode, [4711, 4711, 17])), + %% OTP 24: - mk_port({x@y, 4}, ?MAX_PIDS_PORTS + 1), + mk_port({x@y, 4}, max_old_pids_ports() + 1), + mk_port({x@y, 4}, max_pids_ports()), %% OTP 24: External pids can use 32+32 bits - mk_pid(RemNode, MaxPidNum + 1, MaxPidSer), - mk_pid(RemNode, (1 bsl 32)-1, MaxPidSer), - mk_pid(RemNode, MaxPidNum, MaxPidSer + 1), - mk_pid(RemNode, MaxPidNum, (1 bsl 32)-1), + mk_pid(RemNode, max_old_pid_num() + 1, max_old_pid_ser()), + mk_pid(RemNode, (1 bsl 32)-1, max_old_pid_ser()), + mk_pid(RemNode, max_old_pid_num(), max_old_pid_ser() + 1), + mk_pid(RemNode, max_old_pid_num(), (1 bsl 32)-1), + mk_pid(RemNode, max_pid_num(), max_pid_ser()), ok. @@ -952,7 +1013,7 @@ magic_ref(Config) when is_list(Config) -> ok. persistent_term(Config) when is_list(Config) -> - {ok, Node} = start_node(get_nodefirstname()), + {ok, Peer, Node} = ?CT_PEER(), Self = self(), NcData = make_ref(), RPid = spawn_link(Node, @@ -964,7 +1025,7 @@ persistent_term(Config) when is_list(Config) -> {RPid, RPort, RRef} end, unlink(RPid), - stop_node(Node), + stop_node(Peer, Node), Stuff = lists:foldl(fun (N, Acc) -> persistent_term:put({?MODULE, N}, Data), persistent_term:erase({?MODULE, N-1}), @@ -996,7 +1057,7 @@ lost_pending_connection(Node) -> dist_entry_gc(Config) when is_list(Config) -> Me = self(), - {ok, Node} = start_node(get_nodefirstname(), "+zdntgc 0"), + {ok, Peer, Node} = ?CT_PEER(["+zdntgc", "0"]), P = spawn_link(Node, fun () -> LostNode = list_to_atom("lost_pending_connection@" ++ hostname()), @@ -1008,15 +1069,16 @@ dist_entry_gc(Config) when is_list(Config) -> {P, ok} -> ok end, unlink(P), - stop_node(Node), + stop_node(Peer, Node), ok. huge_ref(Config) when is_list(Config) -> - {ok, Node} = start_node(get_nodefirstname()), + {ok, Peer, Node} = ?CT_PEER(), HRef = mk_ref({Node, 4711}, [4711, 705676, 3456, 1000000, 3456]), io:format("HRef=~p~n", [HRef]), HRef = binary_to_term(term_to_binary(HRef)), HRef = erpc:call(Node, fun () -> HRef end), + peer:stop(Peer), ok. %% @@ -1045,14 +1107,14 @@ nc_refc_check(Node) when is_atom(Node) -> Self ! {Ref, ErrMsg, failed}, exit(normal) end), - Self ! {Ref, succeded} + Self ! {Ref, succeeded} end), receive {Ref, ErrorMsg, failed} -> io:format("~s~n", [ErrorMsg]), ct:fail(reference_count_check_failed); - {Ref, succeded} -> - io:format("Reference count check of node ~w succeded!~n", [Node]), + {Ref, succeeded} -> + io:format("Reference count check of node ~w succeeded!~n", [Node]), unlink(Pid), ok end. @@ -1119,23 +1181,9 @@ reference_type_count(Type, ReferingEntities) when is_list(ReferingEntities) -> 0, ReferingEntities). - -start_node(Name, Args) -> - Pa = filename:dirname(code:which(?MODULE)), - Res = test_server:start_node(Name, - slave, - [{args, "-pa "++Pa++" "++Args}]), - {ok, Node} = Res, - rpc:call(Node, erts_debug, set_internal_state, - [available_internal_state, true]), - Res. - -start_node(Name) -> - start_node(Name, ""). - -stop_node(Node) -> +stop_node(Peer, Node) -> nc_refc_check(Node), - true = test_server:stop_node(Node). + peer:stop(Peer). hostname() -> from($@, atom_to_list(node())). @@ -1157,9 +1205,6 @@ get_nodefirstname_string() -> ++ "-" ++ integer_to_list(erlang:unique_integer([positive])). -get_nodefirstname() -> - list_to_atom(get_nodefirstname_string()). - get_nodename() -> list_to_atom(get_nodefirstname_string() ++ "@" diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index 7d34038cbd49..c53b660bf539 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -191,15 +191,75 @@ t_float_to_string(Config) when is_list(Config) -> <> = <<16#8000000000000000:64>>, "-0.0" = float_to_list(NegZero, [{decimals, 1}, compact]), "-0.0" = float_to_list(NegZero, [{decimals, 1}]), + "-0.0" = float_to_list(NegZero, [short]), "-0.0e+00" = float_to_list(NegZero, [{scientific, 1}]), "-0.0e+00" = float_to_list(NegZero, [{scientific, 1}, compact]), <<"-0.0">> = float_to_binary(NegZero, [{decimals, 1}, compact]), <<"-0.0">> = float_to_binary(NegZero, [{decimals, 1}]), + <<"-0.0">> = float_to_binary(NegZero, [short]), <<"-0.0e+00">> = float_to_binary(NegZero, [{scientific, 1}]), <<"-0.0e+00">> = float_to_binary(NegZero, [{scientific, 1}, compact]), fts_rand_float_decimals(1000), + % test short option + + % test switch for big integers + test_fts("-9007199254740991.0", -float((1 bsl 53) -1), [short]), + test_fts("-9.007199254740992e15", -float(1 bsl 53), [short]), + test_fts("-9.007199254740992e15", -float((1 bsl 53) +1), [short]), + test_fts("9007199254740991.0", float((1 bsl 53) -1), [short]), + test_fts("9.007199254740992e15", float(1 bsl 53), [short]), + test_fts("9.007199254740992e15", float((1 bsl 53) +1), [short]), + + % test basic + test_fts("2.018", 2.018, [short]), + test_fts("-2.018", -2.018, [short]), + + % test switching logic between decimal and scientific + test_fts("1.0e-6", 1.0e-6, [short]), + test_fts("1.0e-5", 1.0e-5, [short]), + test_fts("0.0001", 1.0e-4, [short]), + test_fts("0.001", 1.0e-3, [short]), + test_fts("0.01", 1.0e-2, [short]), + test_fts("0.1", 1.0e-1, [short]), + test_fts("1.0", 1.0e0, [short]), + test_fts("10.0", 1.0e1, [short]), + test_fts("100.0", 1.0e2, [short]), + test_fts("1.0e3", 1.0e3, [short]), + test_fts("1.0e4", 1.0e4, [short]), + test_fts("1.0e5", 1.0e5, [short]), + test_fts("1.0e6", 1.0e6, [short]), + test_fts("1.0e7", 1.0e7, [short]), + test_fts("1.234e-6", 1.234e-6, [short]), + test_fts("1.234e-5", 1.234e-5, [short]), + test_fts("1.234e-4", 1.234e-4, [short]), + test_fts("0.001234", 1.234e-3, [short]), + test_fts("0.01234", 1.234e-2, [short]), + test_fts("0.1234", 1.234e-1, [short]), + test_fts("1.234", 1.234e0, [short]), + test_fts("12.34", 1.234e1, [short]), + test_fts("123.4", 1.234e2, [short]), + test_fts("1234.0", 1.234e3, [short]), + test_fts("12340.0", 1.234e4, [short]), + test_fts("1.234e5", 1.234e5, [short]), + test_fts("1.234e6", 1.234e6, [short]), + + % test the switch to subnormals + test_fts("2.2250738585072014e-308", 2.2250738585072014e-308, [short]), + + % test lots of trailing zeroes + test_fts("2.9802322387695312e-8", 2.98023223876953125e-8, [short]), + + % test some ryu regressions + test_fts("-2.109808898695963e16", -2.109808898695963e16, [short]), + test_fts("4.940656e-318", 4.940656e-318, [short]), + test_fts("1.18575755e-316", 1.18575755e-316, [short]), + test_fts("2.989102097996e-312", 2.989102097996e-312, [short]), + test_fts("9.0608011534336e15", 9.0608011534336e15, [short]), + test_fts("4.708356024711512e18", 4.708356024711512e18, [short]), + test_fts("9.409340012568248e18", 9.409340012568248e18, [short]), + test_fts("1.2345678", 1.2345678, [short]), ok. test_fts(Expect, Float) -> @@ -245,7 +305,7 @@ fts_rand_float_decimals(N) -> end, F1 = list_to_float(L1), Diff = abs(F0-F1), - MaxDiff = max_diff_decimals(F0, D), + MaxDiff = max_diff_decimals(F0, D-1), ok = case Diff =< MaxDiff of true -> ok; false -> @@ -612,9 +672,11 @@ t_string_to_integer(Config) when is_list(Config) -> {"10",''} %Base 20 ]), - %% log2 calculation overflow bug in do_integer_to_list (OTP-12624). - %% Would crash with segementation fault. - 0 = list_to_integer(lists:duplicate(10000000,$0)), + %% System limit + Digits = lists:duplicate(11_000_000, $9), + {'EXIT',{system_limit,_}} = catch list_to_integer(Digits), + {'EXIT',{system_limit,_}} = catch list_to_integer(Digits, 16), + {error,system_limit} = string:to_integer(Digits), ok. diff --git a/erts/emulator/test/op_SUITE.erl b/erts/emulator/test/op_SUITE.erl index d572e037c20c..528cbea7789d 100644 --- a/erts/emulator/test/op_SUITE.erl +++ b/erts/emulator/test/op_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -23,18 +23,20 @@ -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0, - bsl_bsr/1,logical/1,t_not/1,relop_simple/1,relop/1,complex_relop/1]). + bsl_bsr/1,logical/1,t_not/1,relop_simple/1,relop/1, + complex_relop/1,unsafe_fusing/1, + range_tests/1,combined_relops/1,typed_relop/1]). --export([]). -import(lists, [foldl/3,flatmap/2]). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 5}}]. -all() -> +all() -> [bsl_bsr, logical, t_not, relop_simple, relop, - complex_relop]. + complex_relop, unsafe_fusing, range_tests, + combined_relops, typed_relop]. %% Test the bsl and bsr operators. bsl_bsr(Config) when is_list(Config) -> @@ -292,7 +294,11 @@ relop(Config) when is_list(Config) -> Big2 = 19738924729729787487784874, F1 = float(Big1), F2 = float(Big2), - Vs0 = [a,b,-33,-33.0,0,0.0,42,42.0,Big1,Big2,F1,F2], + Bin = <<"abc">>, + BitString = <<0:7>>, + Map = #{a => b}, + Vs0 = [a,b,-33,-33.0,0,0.0,42,42.0,Big1,Big2,F1,F2, + Bin,BitString,Map], Vs = [unvalue(V) || V <- Vs0], Ops = ['==', '/=', '=:=', '=/=', '<', '=<', '>', '>='], binop(Ops, Vs). @@ -301,7 +307,10 @@ relop(Config) when is_list(Config) -> complex_relop(Config) when is_list(Config) -> Big = 99678557475484872464269855544643333, Float = float(Big), - Vs0 = [an_atom,42.0,42,Big,Float], + Bin = <<"abc">>, + BitString = <<0:7>>, + Map = #{a => b}, + Vs0 = [an_atom,42.0,42,Big,Float,Bin,BitString,Map], Vs = flatmap(fun(X) -> [unvalue({X}),unvalue([X])] end, Vs0), Ops = ['==', '/=', '=:=', '=/=', '<', '=<', '>', '>='], binop(Ops, Vs). @@ -333,18 +342,25 @@ run_test_module(Cases, GuardsOk) -> Module = erl_parse:new_anno(Module0), lists:foreach(fun(F) -> io:put_chars([erl_pp:form(F),"\n"]) end, Module), - %% Compile, load, and run the generated module. + %% Compile, load, and run the generated module. Test both with and + %% without compiler optimizations to ensure that we test both the + %% implementation of the BIFs and the BEAM instructions. + do_run_test_module(Module, []), + do_run_test_module(Module, [no_copt,no_ssa_opt,no_postopt]). + +do_run_test_module(Module, Opts) -> + {ok,Mod,Code1} = compile:forms(Module, [time|Opts]), + _ = code:delete(Mod), + _ = code:purge(Mod), - {ok,Mod,Code1} = compile:forms(Module, [time]), - code:delete(Mod), - code:purge(Mod), {module,Mod} = code:load_binary(Mod, Mod, Code1), + run_function(Mod, guard_tests), run_function(Mod, body_tests), run_function(Mod, bif_tests), true = code:delete(Mod), - code:purge(Mod), + _ = code:purge(Mod), ok. @@ -424,6 +440,544 @@ eval(E0) -> {value,Val,_Bs} -> Val end. +unsafe_fusing(_Config) -> + 0 = usec_to_seconds(id(1)), + 234_567 = usec_to_seconds(id(1_234_567_890*1_000)), + ok. + +usec_to_seconds(Usec) when is_integer(Usec) -> + %% The introduction of typed operands caused the loader + %% to incorrectly fuse the following instrutions because + %% the result register ({x,0}) from the 'div' instruction + %% seemed to be distinct from both operands of the 'rem' + %% instruction: + %% + %% {gc_bif,'div', + %% {f,0}, + %% 1, + %% [{tr,{x,0},{t_integer,any}},{integer,1000000}], + %% {x,0}}. + %% {gc_bif,'rem', + %% {f,0}, + %% 1, + %% [{tr,{x,0},{t_integer,any}},{integer,1000000}], + %% {x,0}}. + Sec = Usec div 1000000, + Sec rem 1000000. + +range_tests(_Config) -> + %% Define the limits for smalls on a 64-bit system. + {MinSmall, MaxSmall} = {-1 bsl 59, (1 bsl 59) - 1}, + case erlang:system_info(wordsize) of + 8 -> + %% Assertions. + 2 = erts_debug:flat_size(MinSmall-1), + 0 = erts_debug:flat_size(MinSmall), + 0 = erts_debug:flat_size(MaxSmall), + 2 = erts_debug:flat_size(MaxSmall+1); + 4 -> + ok + end, + + lesser = range(-1 bsl 64), + lesser = range(MinSmall), + lesser = range(0), + lesser = range(-1), + lesser = range(0.9999), + + inside = range_any(1), + inside = range_any(2), + inside = range_any(2.5), + inside = range_any(math:pi()), + inside = range_any(5), + inside = range_any(9), + inside = range_any(10), + + greater = range(10.0001), + greater = range(11), + greater = range(MaxSmall), + greater = range(1 bsl 64), + greater = range(atom), + greater = range(self()), + greater = range(make_ref()), + greater = range({a,b}), + greater = range([a,b]), + greater = range([]), + greater = range(<<1,2,3>>), + greater = range(fun() -> ok end), + greater = range(fun ?MODULE:range_tests/1), + + lesser = range(-1 bsl 64), + lesser = range(float(-1 bsl 64)), + lesser = range_big(MinSmall - 2), + lesser = range_barely_small(MinSmall - 1), + + inside = range_barely_small(MinSmall), + inside = range_barely_small(-1 bsl 58), + inside = range_barely_small(0), + inside = range_barely_small(17.75), + inside = range_barely_small(1 bsl 58), + inside = range_barely_small(MaxSmall), + + greater = range_barely_small(MaxSmall + 1), + greater = range_big(MaxSmall + 2), + greater = range_big(1 bsl 64), + greater = range_big(float(1 bsl 64)), + + lesser = range(-1 bsl 64), + lesser = range(float(-1 bsl 64)), + lesser = range_big(MinSmall - 2), + + inside = range_big(MinSmall), + inside = range_big(-1 bsl 58), + inside = range_big(0), + inside = range_big(17.75), + inside = range_big(1 bsl 58), + inside = range_big(MaxSmall), + + greater = range_big(MaxSmall + 2), + greater = range_big(1 bsl 64), + greater = range_big(float(1 bsl 64)), + + inside = int_range_1(id(-100_000)), + inside = int_range_1(id(-10)), + inside = int_range_1(id(100)), + inside = int_range_1(id(100_000)), + + outside = int_range_1(id(atom)), + outside = int_range_1(id(-1 bsl 60)), + outside = int_range_1(id(-100_001)), + outside = int_range_1(id(100_001)), + outside = int_range_1(id(1 bsl 60)), + + inside = int_range_2(id(1)), + inside = int_range_2(id(42)), + inside = int_range_2(id(16#f000_0000)), + + outside = int_range_2(id([a,list])), + outside = int_range_2(id(0)), + outside = int_range_1(id(-1 bsl 60)), + outside = int_range_1(id(1 bsl 60)), + + inside = int_range_3(id(1 bsl 28)), + inside = int_range_3(id((1 bsl 28) + 1)), + inside = int_range_3(id((1 bsl 33) + 555)), + inside = int_range_3(id((1 bsl 58) - 1)), + inside = int_range_3(id(1 bsl 58)), + + outside = int_range_3(id({a,tuple})), + outside = int_range_3(id(-1 bsl 60)), + outside = int_range_3(id(-1000)), + outside = int_range_3(id(100)), + outside = int_range_3(id((1 bsl 58) + 1)), + outside = int_range_3(id(1 bsl 60)), + + ok. + +range(X) -> + Res = range_any(X), + if + is_integer(X) -> + Res = range_any(float(X)), + Res = range_number(X), + Res = range_number(float(X)), + Res = range_int(X), + if + X =:= X band 16#ffff -> + Res = range_small_int(X); + true -> + Res + end; + is_number(X) -> + Res = range_number(X); + true -> + Res = range_big(X), + Res = range_barely_small(X) + end. + +range_any(X0) -> + X = id(X0), + case range_any_1(X) of + inside -> + inside = range_any_2(X); + Other -> + outside = range_any_2(X), + Other + end. + +%% The guard tests have different failure labels. +range_any_1(X) when 1 =< X, X =< 10 -> + inside; +range_any_1(X) when X < 1 -> + lesser; +range_any_1(X) when X > 10 -> + greater. + +%% The guard tests have the same failure label. +range_any_2(X) when 1 =< X, X =< 10 -> + inside; +range_any_2(_) -> + outside. + +range_number(X) when is_number(X) -> + case range_number_1(X) of + inside -> + inside = range_number_2(X); + Other -> + outside = range_number_2(X), + Other + end. + +range_number_1(X) when 1 =< X, X =< 10 -> + inside; +range_number_1(X) when X < 1 -> + lesser; +range_number_1(X) when X > 10 -> + greater. + +range_number_2(X) when 1 =< X, X =< 10 -> + inside; +range_number_2(_) -> + outside. + +range_int(X) when is_integer(X) -> + case range_int_1(X) of + inside -> + inside = range_int_2(X); + Other -> + outside = range_int_2(X), + Other + end. + +range_int_1(X) when 1 =< X, X =< 10 -> + inside; +range_int_1(X) when X < 1 -> + lesser; +range_int_1(X) when X > 10 -> + greater. + +range_int_2(X) when 1 =< X, X =< 10 -> + inside; +range_int_2(_) -> + outside. + +range_small_int(X) when is_integer(X) -> + case range_small_int_1(X) of + inside -> + inside = range_small_int_2(X); + Other -> + outside = range_small_int_2(X), + Other + end. + +range_small_int_1(X) when 1 =< X, X =< 10 -> + inside; +range_small_int_1(X) when X < 1 -> + lesser; +range_small_int_1(X) when X > 10 -> + greater. + +range_small_int_2(X) when 1 =< X, X =< 10 -> + inside; +range_small_int_2(_) -> + outside. + +range_barely_small(X) -> + case range_barely_small_1(X) of + inside -> + inside = range_barely_small_2(X); + Other -> + outside = range_barely_small_2(X), + Other + end. + +range_barely_small_1(X) when -1 bsl 59 =< X, X =< (1 bsl 59) - 1 -> + inside; +range_barely_small_1(X) when X < -1 bsl 59 -> + lesser; +range_barely_small_1(X) when X > (1 bsl 59) - 1 -> + greater. + +range_barely_small_2(X) when -1 bsl 59 =< X, X =< (1 bsl 59) - 1 -> + inside; +range_barely_small_2(_) -> + outside. + +range_big(X) -> + case range_big_1(X) of + inside -> + inside = range_big_2(X); + Other -> + outside = range_big_2(X), + Other + end. + +range_big_1(X) when (-1 bsl 59) - 1 =< X, X =< 1 bsl 59 -> + inside; +range_big_1(X) when X < (-1 bsl 59) - 1 -> + lesser; +range_big_1(X) when X > 1 bsl 59 -> + greater. + +range_big_2(X) when (-1 bsl 59) - 1 =< X, X =< 1 bsl 59 -> + inside; +range_big_2(_) -> + outside. + +int_range_1(X) when is_integer(X), -100_000 =< X, X =< 100_000 -> + inside; +int_range_1(_) -> + outside. + +int_range_2(X) when is_integer(X), 1 =< X, X =< 16#f000_0000 -> + inside; +int_range_2(_) -> + outside. + +int_range_3(X) when is_integer(X), 1 bsl 28 =< X, X =< 1 bsl 58 -> + inside; +int_range_3(_) -> + outside. + +combined_relops(_Config) -> + other = test_tok_char(-1 bsl 64), + other = test_tok_char($A - 1), + + var = test_tok_char($A), + var = test_tok_char($B), + var = test_tok_char($P), + var = test_tok_char($Y), + var = test_tok_char($Z), + + other = test_tok_char($Z + 1), + + var = tok_char($_), + other = tok_char(float($_)), + + other = test_tok_char(1 bsl 64), + + other = test_tok_char(atom), + other = test_tok_char(self()), + + %% + b = ge_ge_int_range_1(-200), + b = ge_ge_int_range_1(-101), + + a = ge_ge_int_range_1(-100), + a = ge_ge_int_range_1(-50), + a = ge_ge_int_range_1(-10), + + b = ge_ge_int_range_1(-9), + b = ge_ge_int_range_1(-6), + + a = ge_ge_int_range_1(-5), + + b = ge_ge_int_range_1(-4), + b = ge_ge_int_range_1(0), + b = ge_ge_int_range_1(42), + + %% + b = ge_ge_int_range_2(-1 bsl 59), + + a = ge_ge_int_range_2((-1 bsl 59) + 1), + a = ge_ge_int_range_2(-1 bsl 58), + a = ge_ge_int_range_2(-1000), + a = ge_ge_int_range_2(1 bsl 58), + a = ge_ge_int_range_2((1 bsl 59) - 10), + + b = ge_ge_int_range_2((1 bsl 59) - 9), + + a = ge_ge_int_range_2((1 bsl 59) - 5), + + b = ge_ge_int_range_2((1 bsl 59) - 4), + b = ge_ge_int_range_2((1 bsl 59) - 1), + + %% + b = ge_ge_int_range_3(-1 bsl 59), + + b = ge_ge_int_range_3((-1 bsl 59) + 1), + b = ge_ge_int_range_3(-1 bsl 58), + b = ge_ge_int_range_3(-1000), + b = ge_ge_int_range_3(1 bsl 58), + + a = ge_ge_int_range_3((1 bsl 59) - 20), + a = ge_ge_int_range_3((1 bsl 59) - 15), + a = ge_ge_int_range_3((1 bsl 59) - 10), + + b = ge_ge_int_range_3((1 bsl 59) - 9), + + a = ge_ge_int_range_3((1 bsl 59) - 5), + + b = ge_ge_int_range_3((1 bsl 59) - 4), + b = ge_ge_int_range_3((1 bsl 59) - 1), + + %% + b = ge_ge_int_range_4(-1 bsl 59), + + a = ge_ge_int_range_4((-1 bsl 59) + 1), + a = ge_ge_int_range_4((-1 bsl 59) + 3), + a = ge_ge_int_range_4((-1 bsl 59) + 5), + + b = ge_ge_int_range_4((-1 bsl 59) + 6), + b = ge_ge_int_range_4((-1 bsl 59) + 9), + + a = ge_ge_int_range_4((-1 bsl 59) + 10), + + b = ge_ge_int_range_4((-1 bsl 59) + 11), + + b = ge_ge_int_range_4(0), + b = ge_ge_int_range_4(1000), + + b = ge_ge_int_range_4((1 bsl 59) - 1), + + %% Test a sequence that can't occur in optimized code: + %% is_ge Fail Src 10 + %% is_ge Fail Src 5 + Module = {?FUNCTION_NAME,[{test,1}],[], + [{function, test, 1, 2, + [{label,1}, + {line,[{location,"t.erl",4}]}, + {func_info,{atom,?FUNCTION_NAME},{atom,test},1}, + {label,2}, + {test,is_ge,{f,4}, + [{tr,{x,0},{t_integer,{0,1000}}}, + {integer,10}]}, + {test,is_ge, + {f,3}, + [{tr,{x,0},{t_integer,{0,1000}}}, + {integer,5}]}, + {label,3}, + {move,{atom,a},{x,0}}, + return, + {label,4}, + {move,{atom,b},{x,0}}, + return]}], + 5}, + + {ok,Mod,Code} = compile:forms(Module, [from_asm,time,report]), + {module,Mod} = code:load_binary(Mod, Mod, Code), + + b = Mod:test(0), + b = Mod:test(5), + b = Mod:test(9), + + a = Mod:test(10), + a = Mod:test(11), + a = Mod:test(1000), + + true = code:delete(Mod), + _ = code:purge(Mod), + + ok. + +test_tok_char(C) -> + Result = tok_char(C), + if + is_integer(C) -> + Result = tok_char(float(C)), + Result = tok_char_int(C), + if + C band 16#FFFF =:= C -> + Result = tok_char_int_range(C); + true -> + Result + end; + true -> + Result + end. + +%% is_ge + is_lt +tok_char(C) when $A =< C, C =< $Z -> + var; +tok_char($_) -> + var; +tok_char(_) -> + other. + +%% is_ge + is_ge +tok_char_int(C) when $A =< C, C =< $Z -> + var; +tok_char_int($_) -> + var; +tok_char_int(_) -> + other. + +%% is_ge + is_ge +tok_char_int_range(C) when $A =< C, C =< $Z -> + var; +tok_char_int_range($_) -> + var; +tok_char_int_range(_) -> + other. + +%% is_ge + is_ge +ge_ge_int_range_1(X) when -100 =< X, X =< -10 -> + a; +ge_ge_int_range_1(-5) -> + a; +ge_ge_int_range_1(_) -> + b. + +ge_ge_int_range_2(X) when (-1 bsl 59) + 1 =< X, X =< (1 bsl 59) - 10 -> + a; +ge_ge_int_range_2((1 bsl 59) - 5) -> + a; +ge_ge_int_range_2(_) -> + b. + +ge_ge_int_range_3(X) when (1 bsl 59) - 20 =< X, X =< (1 bsl 59) - 10 -> + a; +ge_ge_int_range_3((1 bsl 59) - 5) -> + a; +ge_ge_int_range_3(_) -> + b. + +ge_ge_int_range_4(X) when (-1 bsl 59) + 1 =< X, X =< (-1 bsl 59) + 5 -> + a; +ge_ge_int_range_4((-1 bsl 59) + 10) -> + a; +ge_ge_int_range_4(_) -> + b. + +%% Tests operators where type hints are significant. +typed_relop(Config) when is_list(Config) -> + _ = [compare_integer_pid(1 bsl N) || N <- lists:seq(1, 64)], + + {error,<<7:3>>} = compare_bitstring({text, <<7:3>>, 0}), + {error,<<0:8>>} = compare_bitstring({text, <<0:8>>, 0}), + {error,<<0:9>>} = compare_bitstring({text, <<0:9>>, 0}), + {text, 42} = compare_bitstring({text, <<0:3>>, 42}), + + {error,<<7:3>>} = compare_bitstring({binary, <<7:3>>, 0}), + {error,<<0:8>>} = compare_bitstring({binary, <<0:8>>, 0}), + {error,<<0:9>>} = compare_bitstring({binary, <<0:9>>, 0}), + {binary, 42} = compare_bitstring({binary, <<0:3>>, 42}), + + ok. + +compare_integer_pid(N) when is_integer(N) -> + Immed = self(), + true = is_pid(Immed), + if + N >= Immed -> ct:fail("integer compared greater than pid"); + N < Immed -> ok + end. + +%% GH-7433. Equality and non-equality tests with a bitstring could fail when it +%% should succeed and vice versa. +compare_bitstring({text, Res, _Data}) when is_bitstring(Res), Res =/= <<0:3>> -> + {error, Res}; +compare_bitstring({binary, Res, _Data}) when is_bitstring(Res), Res =/= <<0:3>> -> + {error, Res}; +compare_bitstring({binary, _Res, Data}) -> + {binary, Data}; +compare_bitstring({text, _Res, Data}) -> + {text, Data}. + +%%% +%%% Utilities. +%%% + unvalue(V) -> Abstr = erl_parse:abstract(V), erl_parse:anno_to_term(Abstr). @@ -436,7 +990,10 @@ value({atom,_,X}) -> X; value({tuple,_,Es}) -> list_to_tuple(lists:map(fun(X) -> value(X) end, Es)); value({cons,_,H,T}) -> - [value(H) | value(T)]. + [value(H) | value(T)]; +value(Other) -> + {value,Value,_} = erl_eval:expr(Other, erl_eval:new_bindings()), + Value. repeat(_, 0) -> ok; repeat(Fun, N) -> diff --git a/erts/emulator/test/perf_SUITE.erl b/erts/emulator/test/perf_SUITE.erl deleted file mode 100644 index b5483fcc8aa9..000000000000 --- a/erts/emulator/test/perf_SUITE.erl +++ /dev/null @@ -1,132 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2021-2021. 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(perf_SUITE). - --export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). --export([symbols/1, annotate/1]). - -suite() -> - [{timetrap, {minutes, 4}}]. - -all() -> - [symbols, annotate]. - -init_per_suite(Config) -> - case erlang:system_info(emu_flavor) =:= jit andalso - os:find_executable("perf") =/= false of - false -> - {skip, "perf not found"}; - _Perf -> - PerfVsn = os:cmd("perf version"), - case re:run(PerfVsn, "perf version ([^.])", - [{capture,all_but_first,list}]) of - {match,[Vsn]} -> - case list_to_integer(Vsn) >= 5 of - true -> - BuildIdDir = "--buildid-dir " ++ - filename:join( - proplists:get_value(priv_dir, Config), - ".debug"), - DataFile = filename:join( - proplists:get_value(priv_dir, Config), - "init_test.data"), - Cmd = "perf " ++ BuildIdDir ++ " record -q -o " ++ DataFile ++ " ls", - os:cmd(Cmd), - Script = os:cmd("perf " ++ BuildIdDir ++ " script -i " ++ DataFile), - ct:log("~ts",[Script]), - case re:run(Script, "^\\W+ls",[multiline]) of - {match, _} -> - [{sobefore,get_tmp_so_files()}, - {buildiddir,BuildIdDir}|Config]; - nomatch -> - {skip, "could not run `"++ Cmd ++"`"} - end; - false -> - {skip,"too old perf version: " ++ PerfVsn} - end; - _ -> - {skip,"unknown old perf version: " ++ PerfVsn} - end - end. - -end_per_suite(Config) -> - %% perf inject writes data to /tmp and ~/.debug/tmp so we need to clean - %% that up after the tests are done. - SoToDelete = get_tmp_so_files() -- proplists:get_value(sobefore, Config), - lists:foreach( - fun(File) -> - case file:delete(File) of - {error,eperm} -> - ok = file:del_dir_r(File); - ok -> - ok - end - end, SoToDelete), - ok. - -get_tmp_so_files() -> - {ok, Home} = init:get_argument(home), - filelib:wildcard("/tmp/jitted-*.so") ++ - filelib:wildcard(filename:join([Home,".debug","tmp","jitted-*.so"])). - -symbols(Config) -> - BuildIdDir = proplists:get_value(buildiddir, Config), - DataFile = filename:join( - proplists:get_value(priv_dir, Config), - atom_to_list(?FUNCTION_NAME) ++ ".data"), - os:cmd("perf "++ BuildIdDir ++" record -q -o " ++ DataFile ++ " " ++ - "erl +S 1 +JPperf true -noshell -eval '[lists:seq(1,10000) || _ <- lists:seq(1,1000)].' -s init stop"), - Script = os:cmd("perf "++ BuildIdDir ++" script -i " ++ DataFile), - case re:run(Script,"\\$lists:seq[^/]+/[0-9]",[global,{capture,first,list}]) of - {match,Matches} -> - ct:log("Found these symbols: ~p",[lists:usort(Matches)]), - ok; - nomatch -> - ct:fail("Did not find lists:seq symbol in:~n~ts",[Script]) - end. - -annotate(Config) -> - BuildIdDir = proplists:get_value(buildiddir, Config), - DataFile = filename:join( - proplists:get_value(priv_dir, Config), - atom_to_list(?FUNCTION_NAME) ++ ".data"), - os:cmd("perf "++ BuildIdDir ++" record -k mono -q -o " ++ DataFile ++ " " ++ - "erl +S 1 +JPperf true -noshell -eval '[lists:seq(1,10000) || _ <- lists:seq(1,1000)].' -s init stop"), - Script = os:cmd("perf "++ BuildIdDir ++" script -i " ++ DataFile), - - %% When doing "perf inject" the symbol of each function is changed - %% from $lists:seq_loop/3 to lists:seq_loop/3. I don't know why that - %% is, seems like a very odd bug in perf... so we only include it - %% in our match if it exists - {match, Symbols} = re:run(Script, "\\$?lists:seq[^/]+/[0-9]+", - [global,{capture,first,list}]), - [Symbol|_] = lists:usort(Symbols), - JitFile = DataFile ++ ".jit.data", - "" = os:cmd("perf "++ BuildIdDir ++" inject -j -i " ++ DataFile ++ " -o " ++ JitFile), - Anno = os:cmd("perf "++ BuildIdDir ++" annotate --stdio -i " ++ JitFile ++ " " ++ Symbol ++ ""), - case re:run(Anno,"Disassembly of section .text:") of - {match,_} -> - ok; - nomatch -> - ct:log("Did not find disassembly test for ~ts.~n~ts", - [Symbol, Anno]) - end. - diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl index a96a099bf404..39dd2d34289f 100644 --- a/erts/emulator/test/persistent_term_SUITE.erl +++ b/erts/emulator/test/persistent_term_SUITE.erl @@ -76,10 +76,10 @@ end_per_suite(Config) -> init_per_testcase(_, Config) -> Config. -end_per_testcase(_, _Config) -> - ok; end_per_testcase(get_all_race, _Config) -> get_all_race_cleanup(), + ok; +end_per_testcase(_, _Config) -> ok. basic(_Config) -> @@ -604,27 +604,54 @@ collisions_delete([], _) -> colliding_keys() -> %% Collisions found by find_colliding_keys() below - L = [[77674392,148027], - [103370644,950908], - [106444046,870178], - [22217246,735880], - [18088843,694607], - [63426007,612179], - [117354942,906431], - [121434305,94282311,816072], - [118441466,93873772,783366], - [124338174,1414801,123089], - [20240282,17113486,923647], - [126495528,61463488,164994], - [125341723,5729072,445539], - [127450932,80442669,348245], - [123354692,85724182,14241288,180793], - [99159367,65959274,61680971,289939], - [107637580,104512101,62639807,181644], - [139547511,51654420,2062545,151944], - [88078274,73031465,53388204,428872], - [141314238,75761379,55699508,861797], - [88045216,59272943,21030492,180903]], + %% ct:timetrap({minutes, 60}), + %% ct:pal("Colliding keys = ~p", [find_colliding_keys()]), + Collisions = + #{ + %% Collisions for Jenkins96 hashing. + 1268203079 => [[77674392,148027], + [103370644,950908], + [106444046,870178], + [22217246,735880], + [18088843,694607], + [63426007,612179], + [117354942,906431], + [121434305,94282311,816072], + [118441466,93873772,783366], + [124338174,1414801,123089], + [20240282,17113486,923647], + [126495528,61463488,164994], + [125341723,5729072,445539], + [127450932,80442669,348245], + [123354692,85724182,14241288,180793], + [99159367,65959274,61680971,289939], + [107637580,104512101,62639807,181644], + [139547511,51654420,2062545,151944], + [88078274,73031465,53388204,428872], + [141314238,75761379,55699508,861797], + [88045216,59272943,21030492,180903]], + %% Collisions for CRC32-C hashing. + 1982459178 => [[-4294967296,654663773], + [-3758096384,117792861], + [-3221225472,1728405597], + [-2684354560,1191534685], + [-2147483648,2706162303], + [-1610612736,2169291391], + [-1073741824,3779904127], + [-536870912,3243033215], + [-3640303523,0], + [-4177174435,536870912], + [-2566561699,1073741824], + [-3103432611,1610612736], + [-1588804993,2147483648], + [-2125675905,2684354560], + [-515063169,3221225472], + [-1051934081,3758096384]] + }, + + Key = internal_hash(2), + ct:pal("internal_hash(2) = ~p", [Key]), + #{ Key := L } = Collisions, %% Verify that the keys still collide (this will fail if the %% internal hash function has been changed). @@ -649,57 +676,47 @@ internal_hash(Term) -> erts_debug:get_internal_state({internal_hash,Term}). %% Use this function to (re)generate the list in colliding_keys/0 +%% +%% Grab a coffee, it will take a while. find_colliding_keys() -> - MaxCollSz = 4, - OfEachSz = 7, erts_debug:set_internal_state(available_internal_state, true), - MaxInserts = 1 bsl 20, - T = ets:new(x, [set, private]), - ok = fck_loop_1(T, 1, MaxInserts, MaxCollSz, OfEachSz), - fck_collect(T, MaxCollSz, OfEachSz, []). - -fck_collect(_T, 1, _OfEachSz, Acc) -> - Acc; -fck_collect(T, CollSz, OfEachSz, Acc) -> - {List, _} = ets:select(T, - [{{'$1','$2'}, [{'==',{length,'$2'},CollSz}], ['$2']}], - OfEachSz), - fck_collect(T, CollSz-1, OfEachSz, List ++ Acc). - - -fck_loop_1(T, Key, 0, MaxCollSz, MaxSzLeft) -> - fck_loop_2(T, Key, MaxCollSz, MaxSzLeft); -fck_loop_1(T, Key, Inserts, MaxCollSz, MaxSzLeft) -> - Hash = internal_hash(Key), - case ets:insert_new(T, {Hash, [Key]}) of - true -> - fck_loop_1(T, Key+1, Inserts-1, MaxCollSz, MaxSzLeft); - false -> - [{Hash, KeyList}] = ets:lookup(T, Hash), - true = ets:insert(T, {Hash, [Key | KeyList]}), - fck_loop_1(T, Key+1, Inserts, MaxCollSz, MaxSzLeft) - end. - -fck_loop_2(_T, _Key, _MaxCollSz, 0) -> - ok; -fck_loop_2(T, Key, MaxCollSz, MaxSzLeft0) -> - Hash = internal_hash(Key), - case ets:lookup(T, Hash) of - [] -> - fck_loop_2(T, Key+1, MaxCollSz, MaxSzLeft0); - [{Hash, KeyList}] -> - true = ets:insert(T, {Hash, [Key | KeyList]}), - MaxSzLeft1 = case length(KeyList)+1 of - MaxCollSz -> - MaxSzLeft0 - 1; - _ -> - MaxSzLeft0 - end, - fck_loop_2(T, Key+1, MaxCollSz, MaxSzLeft1) + NumScheds = erlang:system_info(schedulers_online), + Start = -(1 bsl 32), + End = -Start, + Range = End - Start, + Step = Range div NumScheds, + timer:tc(fun() -> fck_spawn(NumScheds, NumScheds, Start, End, Step, []) end). + +fck_spawn(0, _NumScheds, _Start, _End, _Step, Refs) -> + fck_await(Refs); +fck_spawn(N, NumScheds, Start, End, Step, Refs) -> + Key = Start + (N - 1) * Step, + {_, Ref} = spawn_monitor(fun() -> exit(fck_finder(Start, End, Key)) end), + fck_spawn(N - 1, NumScheds, Start, End, Step, [Ref | Refs]). + +fck_await([Ref | Refs]) -> + receive + {'DOWN', Ref, _, _, [_Initial]} -> + %% Ignore slices where the initial value only collided with itself. + fck_await(Refs); + {'DOWN', Ref, _, _, Collisions} -> + [Collisions | fck_await(Refs)] + end; +fck_await([]) -> + []. + +fck_finder(Start, End, Key) -> + true = Key >= Start, true = Key < End, %Assertion. + fck_finder_1(Start, End, internal_hash(Key)). + +fck_finder_1(Same, Same, _Target) -> + []; +fck_finder_1(Next, End, Target) -> + case internal_hash(Next) =:= Target of + true -> [Next | fck_finder_1(Next + 1, End, Target)]; + false -> fck_finder_1(Next + 1, End, Target) end. - - %% OTP-17700 Bug skipped refc++ of shared magic reference shared_magic_ref(_Config) -> Ref = atomics:new(10, []), diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index 6d08bbf92b77..bbfb6b52ce4b 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -226,8 +226,8 @@ init_per_testcase(Case, Config) when Case =:= mon_port_driver_die; init_per_testcase(Case, Config) -> [{testcase, Case} |Config]. -end_per_testcase(_Case, _Config) -> - ok. +end_per_testcase(_Case, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). init_per_suite(Config) when is_list(Config) -> ignore_cores:init(Config). @@ -250,15 +250,9 @@ win_massive(Config) when is_list(Config) -> do_win_massive() -> ct:timetrap({minutes, 6}), - SuiteDir = filename:dirname(code:which(?MODULE)), - Ports = " +Q 8192", - {ok, Node} = - test_server:start_node(win_massive, - slave, - [{args, " -pa " ++ SuiteDir ++ Ports}]), + {ok, Peer, Node} = ?CT_PEER(["+Q", "8192"]), ok = rpc:call(Node,?MODULE,win_massive_client,[3000]), - test_server:stop_node(Node), - ok. + peer:stop(Peer). win_massive_client(N) -> {ok,P}=gen_tcp:listen(?WIN_MASSIVE_PORT,[{reuseaddr,true}]), @@ -766,13 +760,11 @@ iter_max_ports_test(Config) -> _ -> 10 end, %% Run on a different node in order to limit the effect if this test fails. - Dir = filename:dirname(code:which(?MODULE)), - {ok,Node} = test_server:start_node(test_iter_max_socks,slave, - [{args,"+Q 2048 -pa " ++ Dir}]), + {ok, Peer, Node} = ?CT_PEER(["+Q", "2048"]), L = rpc:call(Node,?MODULE,do_iter_max_ports,[Iters, Command]), - test_server:stop_node(Node), + peer:stop(Peer), - io:format("Result: ~p",[L]), + ct:log("Result: ~p",[L]), all_equal(L), all_equal(L), {comment, "Max ports: " ++ integer_to_list(hd(L))}. @@ -809,7 +801,7 @@ open_ports(Name, Settings) -> case os:type() of {unix, freebsd} -> %% FreeBsd has issues with sendmsg/recvmsg in fork - %% implementation and we therefor have to spawn + %% implementation and we therefore have to spawn %% slower to make sure that we always hit the same %% make roof. test_server:sleep(10); @@ -1307,18 +1299,12 @@ otp_3906(Config) when is_list(Config) -> otp_3906(Config, OSName) -> DataDir = filename:dirname(proplists:get_value(data_dir,Config)), - {ok, Variables} = file:consult( - filename:join([DataDir,"..","..", - "test_server","variables"])), + {ok, Variables, _} = file:path_consult(code:get_path(),"variables"), case lists:keysearch('CC', 1, Variables) of {value,{'CC', CC}} -> - SuiteDir = filename:dirname(code:which(?MODULE)), PrivDir = proplists:get_value(priv_dir, Config), Prog = otp_3906_make_prog(CC, PrivDir), - {ok, Node} = test_server:start_node(otp_3906, - slave, - [{args, " -pa " ++ SuiteDir}, - {linked, false}]), + {ok, Peer, Node} = ?CT_PEER(), OP = process_flag(priority, max), OTE = process_flag(trap_exit, true), FS = spawn_link(Node, @@ -1330,11 +1316,11 @@ otp_3906(Config, OSName) -> {failed, Reason}; {emulator_pid, EmPid} -> case otp_3906_wait_result(FS, 0, 0) of - {succeded, + {succeeded, ?OTP_3906_CHILDREN, ?OTP_3906_CHILDREN} -> - succeded; - {succeded, Forked, Exited} -> + succeeded; + {succeeded, Forked, Exited} -> otp_3906_list_defunct(EmPid, OSName), {failed, {mismatch, @@ -1347,9 +1333,9 @@ otp_3906(Config, OSName) -> end, process_flag(trap_exit, OTE), process_flag(priority, OP), - test_server:stop_node(Node), + peer:stop(Peer), case Result of - succeded -> + succeeded -> ok; _ -> ct:fail(Result) @@ -1413,8 +1399,8 @@ otp_3906_wait_result(ForkerStarter, F, E) -> otp_3906_wait_result(ForkerStarter, F, E+1); tick -> otp_3906_wait_result(ForkerStarter, F, E); - succeded -> - {succeded, F, E} + succeeded -> + {succeeded, F, E} after ?OTP_3906_TICK_TIMEOUT -> unlink(ForkerStarter), @@ -1451,7 +1437,7 @@ otp_3906_start_forker_starter(N, RefList, Sup, Prog) -> otp_3906_forker_starter(0, RefList, Sup, _) -> otp_3906_collect(RefList, Sup), unlink(Sup), - Sup ! succeded; + Sup ! succeeded; otp_3906_forker_starter(N, RefList, Sup, Prog) when length(RefList) >= ?OTP_3906_MAX_CONC_OSP -> otp_3906_forker_starter(N, otp_3906_collect_one(RefList, Sup), Sup, Prog); @@ -1773,7 +1759,7 @@ test_bat_file(Dir) -> [DN,"hello","world"] = run_echo_args(Dir,FN, [default,"hello","world"]), - %% The arg0 argumant should be ignored when running batch files + %% The arg0 argument should be ignored when running batch files [DN,"hello","world"] = run_echo_args(Dir,FN, ["knaskurt","hello","world"]), @@ -1929,6 +1915,7 @@ otp_5112(Config) when is_list(Config) -> true = lists:member(Port, Links1), Port ! {self(), {command, ""}}, wait_until(fun () -> lists:member(Port, erlang:ports()) == false end), + receive after 1000 -> ok end, %% Give signal some time to propagate... {links, Links2} = process_info(self(),links), io:format("Links2: ~p~n",[Links2]), false = lists:member(Port, Links2), %% This used to fail @@ -2256,7 +2243,7 @@ port_expect(Config, Actions, HSize, CmdLine, Options0) -> _ -> {packet, HSize} end, Options = [PortType|Options0], - io:format("open_port({spawn, ~p}, ~p)", [Cmd, Options]), + ct:log("open_port({spawn, ~p}, ~p)", [Cmd, Options]), Port = open_port({spawn, Cmd}, Options), port_expect(Port, Actions, Options), Port. diff --git a/erts/emulator/test/port_SUITE_data/port_test.c b/erts/emulator/test/port_SUITE_data/port_test.c index fa97b4c9d00e..6c56cdf956dc 100644 --- a/erts/emulator/test/port_SUITE_data/port_test.c +++ b/erts/emulator/test/port_SUITE_data/port_test.c @@ -559,7 +559,7 @@ char* spec; /* Specification for reply. */ buf = (char *) malloc(total_size); if (buf == NULL) { - fprintf(stderr, "%s: insufficent memory for reply buffer of size %d\n", + fprintf(stderr, "%s: insufficient memory for reply buffer of size %d\n", port_data->progname, (int)total_size); exit(1); } diff --git a/erts/emulator/test/port_bif_SUITE_data/port_test.c b/erts/emulator/test/port_bif_SUITE_data/port_test.c index ef6d12dc93f5..fa509d5a1562 100644 --- a/erts/emulator/test/port_bif_SUITE_data/port_test.c +++ b/erts/emulator/test/port_bif_SUITE_data/port_test.c @@ -536,7 +536,7 @@ char* spec; /* Specification for reply. */ buf = (char *) malloc(total_size); if (buf == NULL) { - fprintf(stderr, "%s: insufficent memory for reply buffer of size %d\n", + fprintf(stderr, "%s: insufficient memory for reply buffer of size %d\n", port_data->progname, total_size); exit(1); } diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 8dc2d8b7f0d6..1d546ff36e8b 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -26,6 +26,7 @@ %% process_info/1,2 %% register/2 (partially) +-include_lib("stdlib/include/assert.hrl"). -include_lib("common_test/include/ct.hrl"). -define(heap_binary_size, 64). @@ -44,20 +45,28 @@ process_info_lock_reschedule2/1, process_info_lock_reschedule3/1, process_info_garbage_collection/1, + process_info_parent/1, process_info_smoke_all/1, process_info_status_handled_signal/1, process_info_reductions/1, + process_info_self_signal/1, + process_info_self_msgq_len/1, + process_info_self_msgq_len_messages/1, + process_info_self_msgq_len_more/1, + process_info_msgq_len_no_very_long_delay/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, dist_unlink_ack_exit_leak/1, bad_register/1, - garbage_collect/1, otp_6237/1, process_info_messages/1, - process_flag_badarg/1, + garbage_collect/1, otp_6237/1, + process_info_messages/1, process_flag_badarg/1, process_flag_fullsweep_after/1, process_flag_heap_size/1, + command_line_max_heap_size/1, spawn_opt_heap_size/1, spawn_opt_max_heap_size/1, more_spawn_opt_max_heap_size/1, processes_large_tab/1, processes_default_tab/1, processes_small_tab/1, processes_this_tab/1, processes_apply_trap/1, processes_last_call_trap/1, processes_gc_trap/1, processes_term_proc_list/1, + processes_send_infant/1, otp_7738_waiting/1, otp_7738_suspended/1, otp_7738_resume/1, garb_other_running/1, @@ -80,16 +89,17 @@ spawn_request_link_parent_exit_nodedown/1, spawn_request_abandon_bif/1, dist_spawn_monitor/1, - spawn_old_node/1, - spawn_new_node/1, + spawn_against_ei_node/1, + spawn_against_old_node/1, + spawn_against_new_node/1, spawn_request_reply_option/1, alias_bif/1, monitor_alias/1, spawn_monitor_alias/1, - alias_process_exit/1, demonitor_aliasmonitor/1, down_aliasmonitor/1, - monitor_tag/1]). + monitor_tag/1, + no_pid_wrap/1]). -export([prio_server/2, prio_client/2, init/1, handle_event/2]). @@ -107,54 +117,68 @@ suite() -> all() -> [spawn_with_binaries, t_exit_1, {group, t_exit_2}, trap_exit_badarg, trap_exit_badarg_in_bif, - t_process_info, process_info_other, process_info_other_msg, - process_info_other_dist_msg, process_info_other_status, - process_info_2_list, - process_info_lock_reschedule, - process_info_lock_reschedule2, - process_info_lock_reschedule3, - process_info_other_message_queue_len_signal_race, - process_info_garbage_collection, - process_info_smoke_all, - process_info_status_handled_signal, - process_info_reductions, bump_reductions, low_prio, yield, yield2, otp_4725, - dist_unlink_ack_exit_leak, - bad_register, garbage_collect, process_info_messages, + dist_unlink_ack_exit_leak, bad_register, garbage_collect, process_flag_badarg, process_flag_fullsweep_after, process_flag_heap_size, + command_line_max_heap_size, spawn_opt_heap_size, spawn_opt_max_heap_size, more_spawn_opt_max_heap_size, spawn_huge_arglist, - spawn_request_bif, - spawn_request_monitor_demonitor, - spawn_request_monitor_child_exit, - spawn_request_link_child_exit, - spawn_request_link_parent_exit, - spawn_request_link_parent_exit_compound_reason, - spawn_request_link_parent_exit_nodedown, - spawn_request_abandon_bif, - dist_spawn_monitor, - spawn_old_node, - spawn_new_node, - spawn_request_reply_option, otp_6237, + {group, spawn_request}, + {group, process_info_bif}, {group, processes_bif}, {group, otp_7738}, garb_other_running, {group, system_task}, {group, alias}, - monitor_tag]. + monitor_tag, + no_pid_wrap]. groups() -> [{t_exit_2, [], [t_exit_2_other, t_exit_2_other_normal, self_exit, normal_suicide_exit, abnormal_suicide_exit, t_exit_2_catch, exit_and_timeout, exit_twice]}, + {spawn_request, [], + [spawn_request_bif, + spawn_request_monitor_demonitor, + spawn_request_monitor_child_exit, + spawn_request_link_child_exit, + spawn_request_link_parent_exit, + spawn_request_link_parent_exit_compound_reason, + spawn_request_link_parent_exit_nodedown, + spawn_request_abandon_bif, + dist_spawn_monitor, + spawn_against_ei_node, + spawn_against_old_node, + spawn_against_new_node, + spawn_request_reply_option]}, {processes_bif, [], [processes_large_tab, processes_default_tab, processes_small_tab, processes_this_tab, processes_last_call_trap, processes_apply_trap, - processes_gc_trap, processes_term_proc_list]}, + processes_gc_trap, processes_term_proc_list, + processes_send_infant]}, + {process_info_bif, [], + [t_process_info, process_info_messages, + process_info_other, process_info_other_msg, + process_info_other_message_queue_len_signal_race, + process_info_other_dist_msg, process_info_other_status, + process_info_2_list, + process_info_lock_reschedule, + process_info_lock_reschedule2, + process_info_lock_reschedule3, + process_info_garbage_collection, + process_info_parent, + process_info_smoke_all, + process_info_status_handled_signal, + process_info_reductions, + process_info_self_signal, + process_info_self_msgq_len, + process_info_self_msgq_len_messages, + process_info_self_msgq_len_more, + process_info_msgq_len_no_very_long_delay]}, {otp_7738, [], [otp_7738_waiting, otp_7738_suspended, otp_7738_resume]}, @@ -164,7 +188,7 @@ groups() -> gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled, otp_16436, otp_16642]}, {alias, [], - [alias_bif, monitor_alias, spawn_monitor_alias, alias_process_exit, + [alias_bif, monitor_alias, spawn_monitor_alias, demonitor_aliasmonitor, down_aliasmonitor]}]. init_per_suite(Config) -> @@ -184,15 +208,9 @@ end_per_suite(Config) -> catch erts_debug:set_internal_state(available_internal_state, false), Config. -init_per_group(alias, Config) -> - erts_debug:set_internal_state(available_internal_state, true), - Config; init_per_group(_GroupName, Config) -> Config. -end_per_group(alias, Config) -> - erts_debug:set_internal_state(available_internal_state, false), - Config; end_per_group(_GroupName, Config) -> Config. @@ -213,8 +231,9 @@ end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> erlang:system_flag(max_heap_size, #{size => 0, kill => true, + include_shared_binaries => false, error_logger => true}), - ok. + erts_test_utils:ept_check_leaked_nodes(Config). fun_spawn(Fun) -> spawn_link(erlang, apply, [Fun, []]). @@ -331,7 +350,7 @@ abnormal_suicide_exit(Config) when is_list(Config) -> Other -> ct:fail({bad_message, Other}) end. -%% Tests that exit(self(), die) cannot be catched. +%% Tests that exit(self(), die) cannot be caught. t_exit_2_catch(Config) when is_list(Config) -> process_flag(trap_exit, true), Pid = fun_spawn(fun() -> catch exit(self(), die) end), @@ -350,7 +369,19 @@ trap_exit_badarg(Config) when is_list(Config) -> ct:timetrap({seconds, 10}), start_spawner(), process_flag(trap_exit, true), - test_server:do_times(10, fun trap_exit_badarg/0), + try + %% suppress =ERROR REPORT=== emulator messages + ok = logger:add_primary_filter(suppress_log_spam, { + fun(#{meta := #{error_logger := #{emulator := true, tag := error}}}, _Report) -> + stop; + (_Meta, _Report) -> + ignore + end, ok}), + test_server:do_times(10, fun trap_exit_badarg/0), + ct:sleep(500) %% flush logging + after + ok = logger:remove_primary_filter(suppress_log_spam) + end, stop_spawner(), ok. @@ -506,7 +537,8 @@ t_process_info(Config) when is_list(Config) -> {status, running} = process_info(self(), status), {min_heap_size, 233} = process_info(self(), min_heap_size), {min_bin_vheap_size,46422} = process_info(self(), min_bin_vheap_size), - {max_heap_size, #{ size := 0, kill := true, error_logger := true}} = + {max_heap_size, #{ size := 0, kill := true, error_logger := true, + include_shared_binaries := false}} = process_info(self(), max_heap_size), {current_function,{?MODULE,t_process_info,1}} = process_info(self(), current_function), @@ -664,8 +696,9 @@ process_info_other_msg(Config) when is_list(Config) -> {min_heap_size, 233} = process_info(Pid, min_heap_size), {min_bin_vheap_size, 46422} = process_info(Pid, min_bin_vheap_size), - {max_heap_size, #{ size := 0, kill := true, error_logger := true}} = - process_info(self(), max_heap_size), + {max_heap_size, #{ size := 0, kill := true, error_logger := true, + include_shared_binaries := false}} = + process_info(Pid, max_heap_size), Pid ! stop, ok. @@ -738,7 +771,7 @@ process_info_other_dist_msg(Config) when is_list(Config) -> %% Check that process_info can handle messages that have not been %% decoded yet. %% - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Self = self(), Pid = spawn_link(fun() -> other_process(Self) end), receive {go_ahead,Pid} -> ok end, @@ -781,7 +814,7 @@ process_info_other_dist_msg(Config) when is_list(Config) -> end, {messages,[]} = process_info(Pid, messages), Pid ! stop, - stop_node(Node), + stop_node(Peer, Node), ok. process_info_other_status(Config) when is_list(Config) -> @@ -1056,6 +1089,20 @@ check_proc_infos(A, B) -> GC = lists:keysearch(garbage_collection, 1, A), GC = lists:keysearch(garbage_collection, 1, B), + {value, {garbage_collection, GClist}} = GC, + + %% This is not really documented + true = is_integer(gv(minor_gcs, GClist)), + true = is_integer(gv(fullsweep_after, GClist)), + true = is_integer(gv(min_heap_size, GClist)), + #{error_logger := Bool1, + include_shared_binaries := Bool2, + kill := Bool3, + size := MaxHeapSize} = gv(max_heap_size, GClist), + true = is_boolean(Bool1), + true = is_boolean(Bool2), + true = is_boolean(Bool3), + true = is_integer(MaxHeapSize), ok. @@ -1135,6 +1182,30 @@ process_info_garbage_collection(_Config) -> gv(Key,List) -> proplists:get_value(Key,List). +process_info_parent(Config) when is_list(Config) -> + Child = spawn_link(fun () -> receive stop -> ok end end), + ?assertEqual({parent, self()}, erlang:process_info(Child, parent)), + Child ! stop, + ?assertEqual({parent, undefined}, erlang:process_info(whereis(init), parent)), + + {ok, Peer, Node} = ?CT_PEER(), + RemoteChild = spawn_link(Node, + fun () -> + {parent, Parent} = process_info(self(), parent), + garbage_collect(), + {parent, Parent} = process_info(self(), parent), + garbage_collect(), + Parent ! remote_child_hello, + receive stop -> ok end + end), + ?assertEqual({parent, self()}, + erpc:call(Node, erlang, process_info, [RemoteChild, parent])), + receive remote_child_hello -> ok end, + unlink(RemoteChild), + RemoteChild ! stop, + peer:stop(Peer), + ok. + process_info_smoke_all_tester() -> register(process_info_smoke_all_tester, self()), put(ets_ref, ets:new(blupp, [])), @@ -1191,7 +1262,7 @@ process_info_smoke_all(Config) when is_list(Config) -> magic_ref, fullsweep_after], - {ok, Node} = start_node(Config, ""), + {ok, Peer, Node} = ?CT_PEER(), RP = spawn_link(Node, fun process_info_smoke_all_tester/0), LP = spawn_link(fun process_info_smoke_all_tester/0), RP ! {other_process, LP}, @@ -1211,7 +1282,7 @@ process_info_smoke_all(Config) when is_list(Config) -> exit(RP, kill), exit(LP, kill), false = is_process_alive(LP), - stop_node(Node), + stop_node(Peer, Node), ok. process_info_status_handled_signal(Config) when is_list(Config) -> @@ -1318,6 +1389,170 @@ pi_reductions_main_unlocker_loop(Other) -> erlang:yield(), pi_reductions_main_unlocker_loop(Other). +process_info_self_signal(Config) when is_list(Config) -> + %% Test that signals that we have sent to ourselves are + %% visible in process_info() result. This is not strictly + %% a necessary property, but implemented so now. See + %% process_info.c:process_info_bif() for more info. + Self = self(), + Ref = make_ref(), + pi_sig_spam_test(fun () -> + process_info_self_signal_spammer(Self) + end, + fun () -> + self() ! Ref, + process_info(self(), messages) + end, + fun (Res) -> + {messages, [Ref]} = Res + end). + +process_info_self_signal_spammer(To) -> + erlang:demonitor(erlang:monitor(process, To)), + process_info_self_signal_spammer(To). + +process_info_self_msgq_len(Config) when is_list(Config) -> + %% Spam ourselves with signals forcing us to flush own + %% signal queue.. + Self = self(), + pi_sig_spam_test(fun () -> + process_info_self_msgq_len_spammer(Self) + end, + fun () -> + process_info(self(), message_queue_len) + end, + fun (Res) -> + {message_queue_len, Len} = Res, + true = Len > 0, + ok + end). + + +process_info_self_msgq_len_messages(Config) when is_list(Config) -> + %% Spam ourselves with signals normally forcing us to flush own + %% signal queue, but since we also want messages wont be flushed... + Self = self(), + pi_sig_spam_test(fun () -> + process_info_self_msgq_len_spammer(Self, 100000) + end, + fun () -> + process_info(self(), + [message_queue_len, + messages]) + end, + fun (Res) -> + [{message_queue_len, Len}, + {messages, Msgs}] = Res, + Len = length(Msgs), + ok + end). + +process_info_self_msgq_len_more(Config) when is_list(Config) -> + self() ! hej, + BodyRes = process_info_self_msgq_len_more_caller_body(), + ok = process_info_self_msgq_len_more_caller_body_result(BodyRes), + TailRes = process_info_self_msgq_len_more_caller_tail(), + ok = process_info_self_msgq_len_more_caller_tail_result(TailRes), + receive hej -> ok end, + %% Check that current_function, current_location, and + %% current_stacktrace give sane results flushing or not... + Self = self(), + pi_sig_spam_test(fun () -> + process_info_self_msgq_len_spammer(Self) + end, + fun process_info_self_msgq_len_more_caller_body/0, + fun process_info_self_msgq_len_more_caller_body_result/1), + pi_sig_spam_test(fun () -> + process_info_self_msgq_len_spammer(Self) + end, + fun process_info_self_msgq_len_more_caller_tail/0, + fun process_info_self_msgq_len_more_caller_tail_result/1). + +process_info_self_msgq_len_more_caller_body() -> + Res = process_info(self(), + [message_queue_len, + current_function, + current_location, + current_stacktrace]), + id(Res). + +process_info_self_msgq_len_more_caller_body_result(Res) -> + [{message_queue_len, Len}, + {current_function, {process_SUITE,process_info_self_msgq_len_more_caller_body,0}}, + {current_location, {process_SUITE,process_info_self_msgq_len_more_caller_body,0,_}}, + {current_stacktrace, + [{process_SUITE,process_info_self_msgq_len_more_caller_body,0,_} | _]}] = Res, + true = Len > 0, + ok. + +process_info_self_msgq_len_more_caller_tail() -> + process_info(self(), + [message_queue_len, + current_function, + current_location, + current_stacktrace]). + +process_info_self_msgq_len_more_caller_tail_result(Res) -> + [{message_queue_len, Len}, + {current_function, {process_SUITE,process_info_self_msgq_len_more_caller_tail,0}}, + {current_location, {process_SUITE,process_info_self_msgq_len_more_caller_tail,0,_}}, + {current_stacktrace, + [{process_SUITE,process_info_self_msgq_len_more_caller_tail,0,_} | _]}] = Res, + true = Len > 0, + ok. + + +process_info_self_msgq_len_spammer(To) -> + process_info_self_msgq_len_spammer(To, 10000000). + +process_info_self_msgq_len_spammer(_To, 0) -> + ok; +process_info_self_msgq_len_spammer(To, N) -> + To ! hejhopp, + erlang:demonitor(erlang:monitor(process, To)), + process_info_self_msgq_len_spammer(To, N-1). + +pi_sig_spam_test(SpamFun, PITest, PICheckRes) -> + SO = erlang:system_flag(schedulers_online, 1), + try + Self = self(), + SigSpammer = spawn_link(SpamFun), + process_flag(priority, low), + receive after 10 -> ok end, + Res = PITest(), + process_flag(priority, high), + unlink(SigSpammer), + exit(SigSpammer, kill), + false = is_process_alive(SigSpammer), + PICheckRes(Res) + after + _ = erlang:system_flag(schedulers_online, SO) + end. + +process_info_msgq_len_no_very_long_delay(Config) when is_list(Config) -> + Tester = self(), + P1 = spawn_link(fun () -> + receive after infinity -> ok end + end), + {message_queue_len, 0} = process_info(self(), message_queue_len), + {message_queue_len, 0} = process_info(P1, message_queue_len), + P2 = spawn_link(fun () -> + Tester ! hello, + P1 ! hello, + receive after infinity -> ok end + end), + receive after 100 -> ok end, + {message_queue_len, 1} = process_info(self(), message_queue_len), + {message_queue_len, 1} = process_info(P1, message_queue_len), + receive hello -> ok end, + {message_queue_len, 0} = process_info(self(), message_queue_len), + unlink(P1), + exit(P1, kill), + unlink(P2), + exit(P2, kill), + false = is_process_alive(P1), + false = is_process_alive(P2), + ok. %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> @@ -1437,7 +1672,7 @@ yield(Config) when is_list(Config) -> Level when is_integer(Level) -> {skipped, "Modified timing (level " ++ integer_to_list(Level) - ++ ") is enabled. Testcase gets messed up by modfied " + ++ ") is enabled. Testcase gets messed up by modified " "timing."}; _ -> MS = erlang:system_flag(multi_scheduling, block_normal), @@ -1579,7 +1814,7 @@ next_tmsg(Pid) -> dist_unlink_ack_exit_leak(Config) when is_list(Config) -> %% Verification of nc reference counts when stopping node %% will find the bug if it exists... - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), ParentFun = fun () -> %% Give parent some work to do when @@ -1610,7 +1845,7 @@ dist_unlink_ack_exit_leak(Config) when is_list(Config) -> ok end end, PMs), - stop_node(Node), + stop_node(Peer, Node), ok. %% Test that bad arguments to register/2 cause an exception. @@ -1758,6 +1993,8 @@ process_flag_badarg(Config) when is_list(Config) -> kill => gurka }) end), chk_badarg(fun () -> process_flag(max_heap_size, #{ size => 233, error_logger => gurka }) end), + chk_badarg(fun () -> process_flag(max_heap_size, #{ size => 233, + include_shared_binaries => gurka}) end), chk_badarg(fun () -> process_flag(max_heap_size, #{ size => 233, kill => true, error_logger => gurka }) end), @@ -1843,9 +2080,9 @@ otp_6237_select_loop() -> debug_level}). processes_large_tab(Config) when is_list(Config) -> - sys_mem_cond_run(2048, fun () -> processes_large_tab_test(Config) end). + sys_mem_cond_run(2048, fun () -> processes_large_tab_test() end). -processes_large_tab_test(Config) -> +processes_large_tab_test() -> enable_internal_state(), MaxDbgLvl = 20, MinProcTabSize = 2*(1 bsl 15), @@ -1879,8 +2116,7 @@ processes_large_tab_test(Config) -> true -> MinProcTabSize; false -> ProcTabSize3 end, - {ok, LargeNode} = start_node(Config, - "+P " ++ integer_to_list(ProcTabSize)), + {ok, Peer, LargeNode} = ?CT_PEER(["+P", integer_to_list(ProcTabSize)]), Res = rpc:call(LargeNode, ?MODULE, processes_bif_test, []), case rpc:call(LargeNode, erts_debug, @@ -1890,23 +2126,23 @@ processes_large_tab_test(Config) -> Chunks > 1 -> ok; PBInfo -> ct:fail(PBInfo) end, - stop_node(LargeNode), + stop_node(Peer, LargeNode), chk_processes_bif_test_res(Res). processes_default_tab(Config) when is_list(Config) -> - sys_mem_cond_run(1024, fun () -> processes_default_tab_test(Config) end). + sys_mem_cond_run(1024, fun () -> processes_default_tab_test() end). -processes_default_tab_test(Config) -> - {ok, DefaultNode} = start_node(Config, ""), +processes_default_tab_test() -> + {ok, Peer, DefaultNode} = ?CT_PEER(), Res = rpc:call(DefaultNode, ?MODULE, processes_bif_test, []), - stop_node(DefaultNode), + stop_node(Peer, DefaultNode), chk_processes_bif_test_res(Res). processes_small_tab(Config) when is_list(Config) -> - {ok, SmallNode} = start_node(Config, "+P 1024"), + {ok, Peer, SmallNode} = ?CT_PEER(["+P","1024"]), Res = rpc:call(SmallNode, ?MODULE, processes_bif_test, []), PBInfo = rpc:call(SmallNode, erts_debug, get_internal_state, [processes_bif_info]), - stop_node(SmallNode), + stop_node(Peer, SmallNode), true = PBInfo#ptab_list_bif_info.tab_chunks < 10, chk_processes_bif_test_res(Res). @@ -2062,7 +2298,7 @@ processes_bif_test() -> false -> ok; true -> - %% Do it again with a process suspended while + %% Do it against with a process suspended while %% in the processes/0 bif. erlang:system_flag(multi_scheduling, block_normal), Suspendee = spawn_link(fun () -> @@ -2376,6 +2612,18 @@ process_flag_heap_size(Config) when is_list(Config) -> VHSize = erlang:process_flag(min_bin_vheap_size, OldVHmin), ok. +%% test that max_heap_size is correctly handled when passed via command line +command_line_max_heap_size(Config) when is_list(Config) -> + %% test maximum heap size + HMax = case erlang:system_info(wordsize) of + 8 -> (1 bsl 59) - 1; + 4 -> (1 bsl 27) - 1 + end, + {ok, Peer, Node} = ?CT_PEER(["+hmax", integer_to_list(HMax)]), + Pid = erlang:spawn(Node, fun () -> receive after infinity -> ok end end), + {max_heap_size, #{size := HMax}} = rpc:call(Node, erlang, process_info, [Pid, max_heap_size]), + peer:stop(Peer). + spawn_opt_heap_size(Config) when is_list(Config) -> HSize = 987, % must be gc fib+ number VHSize = 46422, % must be gc fib+ number @@ -2397,63 +2645,72 @@ spawn_opt_max_heap_size(_Config) -> flush() end, + spawn_opt_max_heap_size_do(fun oom_fun/1), + + io:format("Repeat tests with refc binaries\n",[]), + + spawn_opt_max_heap_size_do(fun oom_bin_fun/1), + + error_logger:delete_report_handler(?MODULE), + ok. + +spawn_opt_max_heap_size_do(OomFun) -> + Max = 2024, %% Test that numerical limit works - max_heap_size_test(1024, 1024, true, true), + max_heap_size_test(Max, Max, true, true, OomFun), %% Test that map limit works - max_heap_size_test(#{ size => 1024 }, 1024, true, true), + max_heap_size_test(#{ size => Max }, Max, true, true, OomFun), %% Test that no kill is sent - max_heap_size_test(#{ size => 1024, kill => false }, 1024, false, true), + max_heap_size_test(#{ size => Max, kill => false }, Max, false, true, OomFun), %% Test that no error_logger report is sent - max_heap_size_test(#{ size => 1024, error_logger => false }, 1024, true, false), + max_heap_size_test(#{ size => Max, error_logger => false }, Max, true, false, OomFun), %% Test that system_flag works - erlang:system_flag(max_heap_size, #{ size => 0, kill => false, - error_logger => true}), - max_heap_size_test(#{ size => 1024 }, 1024, false, true), - max_heap_size_test(#{ size => 1024, kill => true }, 1024, true, true), + erlang:system_flag(max_heap_size, OomFun(#{ size => 0, kill => false, + error_logger => true})), + max_heap_size_test(#{ size => Max }, Max, false, true, OomFun), + max_heap_size_test(#{ size => Max, kill => true }, Max, true, true, OomFun), - erlang:system_flag(max_heap_size, #{ size => 0, kill => true, - error_logger => false}), - max_heap_size_test(#{ size => 1024 }, 1024, true, false), - max_heap_size_test(#{ size => 1024, error_logger => true }, 1024, true, true), + erlang:system_flag(max_heap_size, OomFun(#{ size => 0, kill => true, + error_logger => false})), + max_heap_size_test(#{ size => Max }, Max, true, false, OomFun), + max_heap_size_test(#{ size => Max, error_logger => true }, Max, true, true, OomFun), - erlang:system_flag(max_heap_size, #{ size => 1 bsl 20, kill => true, - error_logger => true}), - max_heap_size_test(#{ }, 1 bsl 20, true, true), + erlang:system_flag(max_heap_size, OomFun(#{ size => 1 bsl 16, kill => true, + error_logger => true})), + max_heap_size_test(#{ }, 1 bsl 16, true, true, OomFun), erlang:system_flag(max_heap_size, #{ size => 0, kill => true, error_logger => true}), %% Test that ordinary case works as expected again - max_heap_size_test(1024, 1024, true, true), + max_heap_size_test(Max, Max, true, true, OomFun), + ok. - error_logger:delete_report_handler(?MODULE), - ok. +mhs_spawn_opt(Option) when map_get(size, Option) > 0; + is_integer(Option) -> + [{max_heap_size, Option}]; +mhs_spawn_opt(_) -> + []. -max_heap_size_test(Option, Size, Kill, ErrorLogger) - when map_size(Option) == 0 -> - max_heap_size_test([], Size, Kill, ErrorLogger); -max_heap_size_test(Option, Size, Kill, ErrorLogger) - when is_map(Option); is_integer(Option) -> - max_heap_size_test([{max_heap_size, Option}], Size, Kill, ErrorLogger); -max_heap_size_test(Option, Size, Kill, ErrorLogger) -> - OomFun = fun () -> oom_fun([]) end, - Pid = spawn_opt(OomFun, Option), +max_heap_size_test(Option, Size, Kill, ErrorLogger, OomFun) -> + SpOpt = mhs_spawn_opt(OomFun(Option)), + Pid = spawn_opt(fun()-> OomFun(run) end, SpOpt), {max_heap_size, MHSz} = erlang:process_info(Pid, max_heap_size), - ct:log("Default: ~p~nOption: ~p~nProc: ~p~n", - [erlang:system_info(max_heap_size), Option, MHSz]), + ct:log("Default: ~p~nOption: ~p~nProc: ~p~nSize = ~p~nSpOpt = ~p~n", + [erlang:system_info(max_heap_size), Option, MHSz, Size, SpOpt]), #{ size := Size} = MHSz, Ref = erlang:monitor(process, Pid), if Kill -> receive - {'DOWN', Ref, process, Pid, killed} -> - ok + {'DOWN', Ref, process, Pid, Reason} -> + killed = Reason end; true -> ok @@ -2484,12 +2741,37 @@ max_heap_size_test(Option, Size, Kill, ErrorLogger) -> %% Make sure that there are no unexpected messages. receive_unexpected(). -oom_fun(Acc0) -> +oom_fun(Max) when is_integer(Max) -> Max; +oom_fun(Map) when is_map(Map)-> Map; +oom_fun(run) -> + io:format("oom_fun() started\n",[]), + oom_run_fun([], 100). + +oom_run_fun(Acc0, 0) -> + done; +oom_run_fun(Acc0, N) -> %% This is tail-recursive since the compiler is smart enough to figure %% out that a body-recursive variant never returns, and loops forever %% without keeping the list alive. timer:sleep(5), - oom_fun([lists:seq(1, 1000) | Acc0]). + oom_run_fun([lists:seq(1, 1000) | Acc0], N-1). + +oom_bin_fun(Max) when is_integer(Max) -> oom_bin_fun(#{size => Max}); +oom_bin_fun(Map) when is_map(Map) -> Map#{include_shared_binaries => true}; +oom_bin_fun(run) -> + oom_bin_run_fun([], 10). + +oom_bin_run_fun(Acc0, 0) -> + done; +oom_bin_run_fun(Acc0, N) -> + timer:sleep(5), + oom_bin_run_fun([build_refc_bin(160, <<>>) | Acc0], N-1). + +build_refc_bin(0, Acc) -> + Acc; +build_refc_bin(N, Acc) -> + build_refc_bin(N-1, <>). + receive_error_messages(Pid) -> receive @@ -2705,11 +2987,11 @@ spawn_huge_arglist(Config) when is_list(Config) -> spawn_huge_arglist_test(true, node(), ArgList), io:format("Testing spawn with huge argument list on local node with Node...~n", []), spawn_huge_arglist_test(false, node(), ArgList), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), _ = rpc:call(Node, ?MODULE, module_info, []), io:format("Testing spawn with huge argument list on remote node ~p...~n", [Node]), spawn_huge_arglist_test(false, Node, ArgList), - stop_node(Node), + stop_node(Peer, Node), ok. spawn_huge_arglist_test(Local, Node, ArgList) -> @@ -2791,10 +3073,10 @@ spawn_request_bif(Config) when is_list(Config) -> spawn_request_bif_test(true, node()), io:format("Testing spawn_request() on local node with Node...~n", []), spawn_request_bif_test(false, node()), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), io:format("Testing spawn_request() on remote node ~p...~n", [Node]), spawn_request_bif_test(false, Node), - stop_node(Node), + stop_node(Peer, Node), ok. spawn_request_bif_test(Local, Node) -> @@ -3063,7 +3345,7 @@ spawn_request_bif_test(Local, Node) -> spawn_request_monitor_demonitor(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), BlockFun = fun () -> erts_debug:set_internal_state(available_internal_state, true), erts_debug:set_internal_state(block, 1000), @@ -3074,25 +3356,20 @@ spawn_request_monitor_demonitor(Config) when is_list(Config) -> spawn_request(Node, BlockFun, [{priority,max}, link]), receive after 100 -> ok end, - erlang:display(spawning), erlang:yield(), R = spawn_request(Node, timer, sleep, [10000], [monitor]), %% Should not be possible to demonitor %% before operation has succeeded... - erlang:display(premature_demonitor), {monitors, []} = process_info(self(), monitors), false = erlang:demonitor(R, [info]), %% Should be ignored by VM... - erlang:display(wait_success), receive {spawn_reply, R, ok, P} -> - erlang:display(demonitor), {monitors, [{process,P}]} = process_info(self(), monitors), true = erlang:demonitor(R, [info]), {monitors, []} = process_info(self(), monitors), exit(P, kill) end, - erlang:display(done), - stop_node(Node), + stop_node(Peer, Node), ok. spawn_request_monitor_child_exit(Config) when is_list(Config) -> @@ -3106,7 +3383,7 @@ spawn_request_monitor_child_exit(Config) when is_list(Config) -> {undef, _} = Reason1 end end, - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), R2 = spawn_request(Node, nonexisting_module, nonexisting_function, [], [{reply_tag, Tag}, monitor]), receive {Tag, R2, ok, P2} -> @@ -3115,7 +3392,7 @@ spawn_request_monitor_child_exit(Config) when is_list(Config) -> {undef, _} = Reason2 end end, - stop_node(Node), + stop_node(Peer, Node), ok. spawn_request_link_child_exit(Config) when is_list(Config) -> @@ -3130,7 +3407,7 @@ spawn_request_link_child_exit(Config) when is_list(Config) -> {undef, _} = Reason1 end end, - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), R2 = spawn_request(Node, nonexisting_module, nonexisting_function, [], [link, {reply_tag, Tag}]), receive {Tag, R2, ok, P2} -> @@ -3139,21 +3416,21 @@ spawn_request_link_child_exit(Config) when is_list(Config) -> {undef, _} = Reason2 end end, - stop_node(Node), + stop_node(Peer, Node), ok. spawn_request_link_parent_exit(Config) when is_list(Config) -> C1 = spawn_request_link_parent_exit_test(node(), false), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), C2 = spawn_request_link_parent_exit_test(Node, false), - stop_node(Node), + stop_node(Peer, Node), {comment, C1 ++ " " ++ C2}. spawn_request_link_parent_exit_compound_reason(Config) when is_list(Config) -> C1 = spawn_request_link_parent_exit_test(node(), true), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), C2 = spawn_request_link_parent_exit_test(Node, true), - stop_node(Node), + stop_node(Peer, Node), {comment, C1 ++ " " ++ C2}. spawn_request_link_parent_exit_test(Node, CompoundExitReason) -> @@ -3228,7 +3505,7 @@ spawn_request_link_parent_exit_test(Node, CompoundExitReason) -> Comment. spawn_request_link_parent_exit_nodedown(Config) when is_list(Config) -> - {ok, Node} = start_peer_node(Config), + {ok, Peer, Node} = ?CT_PEER(#{connection => 0}), N = 1000, ExitCounter = spawn(Node, fun exit_counter/0), lists:foreach(fun (_) -> @@ -3254,7 +3531,7 @@ spawn_request_link_parent_exit_nodedown(Config) when is_list(Config) -> "."]) end, io:format("~s~n", [Cmnt]), - stop_node(Node), + stop_node(Peer, Node), {comment, Cmnt}. exit_counter() -> @@ -3295,7 +3572,7 @@ spawn_request_link_parent_exit_nodedown_test(Node) -> spawn_request_abandon_bif(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), false = spawn_request_abandon(make_ref()), false = spawn_request_abandon(spawn_request(fun () -> ok end)), false = spawn_request_abandon(rpc:call(Node, erlang, make_ref, [])), @@ -3399,11 +3676,10 @@ spawn_request_abandon_bif(Config) when is_list(Config) -> end, lists:seq(1, TotOps)), 0 = gather_parent_exits(abandoned, true), - stop_node(Node), + stop_node(Peer, Node), C = "Got " ++ integer_to_list(NoA1) ++ " and " ++ integer_to_list(NoA2) ++ " abandoneds of 2*" ++ integer_to_list(TotOps) ++ " ops!", - erlang:display(C), true = NoA1 /= 0, true = NoA1 /= TotOps, true = NoA2 /= 0, @@ -3440,7 +3716,7 @@ gather_parent_exits(Reason, AllowOther, N) -> N end. dist_spawn_monitor(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), R1 = spawn_request(Node, erlang, exit, [hej], [monitor]), receive {spawn_reply, R1, ok, P1} -> @@ -3459,12 +3735,31 @@ dist_spawn_monitor(Config) when is_list(Config) -> {'DOWN', Mon3, process, P3, Reason3} -> hej = Reason3 end, - stop_node(Node), + stop_node(Peer, Node), ok. - -spawn_old_node(Config) when is_list(Config) -> - Cookie = atom_to_list(erlang:get_cookie()), - Rel = "22_latest", + +spawn_against_ei_node(Config) when is_list(Config) -> + %% Spawn against an ei node which does not support spawn + {ok, EiNode} = start_ei_node(Config), + try + %% First spawn triggering a new connection; which + %% will trigger hopeful data transcoding + %% of spawn requests... + io:format("~n~nDoing initial connect tests...~n", []), + spawn_ei_node_test(EiNode, true), + %% Spawns on an already existing connection... + io:format("~n~nDoing already connected tests...~n", []), + spawn_ei_node_test(EiNode, false), + ok + after + ok = stop_ei_node(EiNode) + end. + +spawn_against_old_node(Config) when is_list(Config) -> + %% Same spawn tests against a two releases old node as against + %% ei node above + OldRel = integer_to_list(list_to_integer(erlang:system_info(otp_release))-2), + OldRelName = OldRel ++ "_latest", %% We clear all ERL_FLAGS for the old node as all options may not %% be supported. ClearEnv = lists:foldl( @@ -3476,71 +3771,54 @@ spawn_old_node(Config) when is_list(Config) -> Acc end end, [], os:env()), - case test_server:is_release_available(Rel) of - false -> - {skipped, "No OTP 22 available"}; - true -> - {ok, OldNode} = test_server:start_node(make_nodename(Config), - peer, - [{args, " -setcookie "++Cookie}, - {env, ClearEnv}, - {erl, [{release, Rel}]}]), + case ?CT_PEER_REL(#{connection => 0, env => ClearEnv }, + OldRelName, + proplists:get_value(priv_dir, Config)) of + not_available -> + {skipped, "No OTP "++OldRel++" available"}; + {ok, Peer, OldNode} -> try %% Spawns triggering a new connection; which %% will trigger hopeful data transcoding %% of spawn requests... io:format("~n~nDoing initial connect tests...~n", []), - spawn_old_node_test(OldNode, true), - %% Spawns on an already existing connection... + spawn_node_test(OldNode, true), io:format("~n~nDoing already connected tests...~n", []), - spawn_old_node_test(OldNode, false) + %% Spawns on an already existing connection... + spawn_node_test(OldNode, false), + ok after - test_server:stop_node(OldNode) - end, - ok + peer:stop(Peer) + end end. -spawn_new_node(Config) when is_list(Config) -> - Cookie = atom_to_list(erlang:get_cookie()), - %% Test that the same operations as in spawn_old_node test - %% works as expected on current OTP... - {ok, CurrNode} = test_server:start_node(make_nodename(Config), - peer, - [{args, " -setcookie "++Cookie}]), +spawn_against_new_node(Config) when is_list(Config) -> + {ok, Peer, CurrNode} = ?CT_PEER(#{connection => 0}), try %% Spawns triggering a new connection; which %% will trigger hopeful data transcoding %% of spawn requests... io:format("~n~nDoing initial connect tests...~n", []), - spawn_current_node_test(CurrNode, true), + spawn_node_test(CurrNode, true), io:format("~n~nDoing already connected tests...~n", []), %% Spawns on an already existing connection... - spawn_current_node_test(CurrNode, false) + spawn_node_test(CurrNode, false), + ok after - test_server:stop_node(CurrNode) + peer:stop(Peer) end. -disconnect_node(Node, Disconnect) -> - case Disconnect of - false -> - ok; - true -> - monitor_node(Node, true), - erlang:disconnect_node(Node), - receive {nodedown, Node} -> ok end - end. - -spawn_old_node_test(Node, Disconnect) -> - io:format("Testing spawn_request() on old node...", []), +spawn_ei_node_test(Node, Disconnect) -> + io:format("Testing spawn_request() against ei node...", []), disconnect_node(Node, Disconnect), - R1 = spawn_request(Node, erlang, exit, [hej], [monitor, {reply_tag, a_tag}]), + Ref1 = spawn_request(Node, erlang, exit, [hej], [monitor, {reply_tag, a_tag}]), receive - {a_tag, R1, Err, Notsup} -> + {a_tag, Ref1, Err, Notsup} -> error = Err, notsup = Notsup, ok end, - io:format("Testing spawn_monitor() on old node...", []), + io:format("Testing spawn_monitor() against ei node...", []), disconnect_node(Node, Disconnect), try spawn_monitor(Node, erlang, exit, [hej]) @@ -3548,34 +3826,41 @@ spawn_old_node_test(Node, Disconnect) -> error:notsup -> ok end, - io:format("Testing spawn_opt() with monitor on old node...", []), + io:format("Testing spawn_opt() with monitor against ei node...", []), disconnect_node(Node, Disconnect), - try - spawn_opt(Node, erlang, exit, [hej], [monitor]) - catch - error:badarg -> - ok + {P0, M0} = spawn_opt(Node, erlang, exit, [hej], [monitor]), + receive + {'DOWN', M0, process, P0, R0} -> + notsup = R0 end, - io:format("Testing spawn_opt() with link on old node...", []), + io:format("Testing spawn_opt() with link against ei node...", []), disconnect_node(Node, Disconnect), process_flag(trap_exit, true), P1 = spawn_opt(Node, erlang, exit, [hej], [link]), - Node = node(P1), receive - {'EXIT', P1, hej} -> - ok + {'EXIT', P1, R1} -> + notsup = R1 end, - io:format("Testing spawn_link() on old node...", []), + io:format("Testing spawn_link() against ei node...", []), disconnect_node(Node, Disconnect), P2 = spawn_link(Node, erlang, exit, [hej]), - Node = node(P2), receive - {'EXIT', P2, hej} -> - ok + {'EXIT', P2, R2} -> + notsup = R2 + end, + ok. + +disconnect_node(_Node, false) -> + ok; +disconnect_node(Node, true) -> + lists:member(Node, nodes([visible, hidden])) andalso begin + monitor_node(Node, true), + true = erlang:disconnect_node(Node), + receive {nodedown, Node} -> ok end end. -spawn_current_node_test(Node, Disconnect) -> - io:format("Testing spawn_request() on new node...", []), +spawn_node_test(Node, Disconnect) -> + io:format("Testing spawn_request()...", []), disconnect_node(Node, Disconnect), R1 = spawn_request(Node, erlang, exit, [hej], [monitor, {reply_tag, a_tag}]), receive @@ -3585,21 +3870,21 @@ spawn_current_node_test(Node, Disconnect) -> {'DOWN', R1, process, P1, hej} -> ok end end, - io:format("Testing spawn_monitor() on new node...", []), + io:format("Testing spawn_monitor()...", []), disconnect_node(Node, Disconnect), {P2, M2} = spawn_monitor(Node, erlang, exit, [hej]), receive {'DOWN', M2, process, P2, hej} -> ok end, Node = node(P2), - io:format("Testing spawn_opt() with monitor on new node...", []), + io:format("Testing spawn_opt() with monitor...", []), disconnect_node(Node, Disconnect), {P3, M3} = spawn_opt(Node, erlang, exit, [hej], [monitor]), receive {'DOWN', M3, process, P3, hej} -> ok end, Node = node(P3), - io:format("Testing spawn_opt() with link on new node...", []), + io:format("Testing spawn_opt() with link...", []), disconnect_node(Node, Disconnect), process_flag(trap_exit, true), P4 = spawn_opt(Node, erlang, exit, [hej], [link]), @@ -3608,7 +3893,7 @@ spawn_current_node_test(Node, Disconnect) -> {'EXIT', P4, hej} -> ok end, - io:format("Testing spawn_link() on new node...", []), + io:format("Testing spawn_link()...", []), disconnect_node(Node, Disconnect), P5 = spawn_link(Node, erlang, exit, [hej]), Node = node(P5), @@ -3618,11 +3903,11 @@ spawn_current_node_test(Node, Disconnect) -> end. spawn_request_reply_option(Config) when is_list(Config) -> - spawn_request_reply_option_test(node()), - {ok, Node} = start_node(Config), - spawn_request_reply_option_test(Node). + spawn_request_reply_option_test(undefined, node()), + {ok, Peer, Node} = ?CT_PEER(), + spawn_request_reply_option_test(Peer, Node). -spawn_request_reply_option_test(Node) -> +spawn_request_reply_option_test(Peer, Node) -> io:format("Testing on node: ~p~n", [Node]), Parent = self(), Done1 = make_ref(), @@ -3685,7 +3970,7 @@ spawn_request_reply_option_test(Node) -> true -> ok; false -> - stop_node(Node), + stop_node(Peer, Node), RID9 = spawn_request(Node, fun () -> ok end, [{reply, yes}]), receive {spawn_reply, RID9, error, noconnection} -> ok @@ -3711,24 +3996,138 @@ processes_term_proc_list(Config) when is_list(Config) -> Tester = self(), Run = fun(Args) -> - {ok, Node} = start_node(Config, Args), + {ok, Peer, Node} = ?CT_PEER(Args), RT = spawn_link(Node, fun () -> receive after 1000 -> ok end, as_expected = processes_term_proc_list_test(false), Tester ! {it_worked, self()} end), receive {it_worked, RT} -> ok end, - stop_node(Node) + stop_node(Peer, Node) end, %% We have to run this test case with +S1 since instrument:allocations() %% will report a free()'d block as present until it's actually deallocated %% by its employer. - Run("+MSe true +Muatags false +S1"), - Run("+MSe true +Muatags true +S1"), + Run(["+MSe", "true", "+Muatags", "false", "+S1"]), + Run(["+MSe", "true", "+Muatags", "true", "+S1"]), ok. +%% OTP-18322: Send msg to spawning process pid returned from processes/0 +processes_send_infant(_Config) -> + case erlang:system_info(schedulers_online) of + 1 -> + {skip, "Only one scheduler online"}; + NScheds -> + processes_send_infant_do(NScheds) + end. + +processes_send_infant_do(NScheds) -> + IgnoreList = erlang:processes(), + IgnorePids = maps:from_keys(IgnoreList, ignore), + Tester = self(), + + %% To provoke bug we need sender and spawner on different schedulers. + %% Let spawners use schedulers nr 2 to NScheds + NSpawnerScheds = NScheds - 1, + NSpawners = 2 * NSpawnerScheds, + [spawn_link(fun() -> + processes_send_infant_spawner((I rem NSpawnerScheds) + 2, + Tester, Tester, 1) + end) + || I <- lists:seq(0, NSpawners-1)], + + %% and make sure sender use scheduler 1 + {Sender,SenderMon} = + spawn_opt( + fun() -> + timeout = processes_send_infant_loop(IgnorePids) + end, + [link, monitor, {scheduler,1}]), + + %% Run test for a little while and see if VM crashes + {ok, _TRef} = timer:send_after(1000, Sender, timeout), + {'DOWN', SenderMon, process, Sender, normal} = receive_any(), + + %% Stop spawners and collect stats + processes_send_infant_broadcast(erlang:processes(), + {processes_send_infant, stop}, + IgnorePids), + {TotSpawn, TheLastOfUs} = + lists:foldl(fun(_, {SpawnCnt, Pids}) -> + {Pid, Generation} = receive_any(), + io:format("Got ~p from ~p\n", [Generation, Pid]), + {SpawnCnt+Generation, [Pid | Pids]} + end, + {0, []}, + lists:seq(1, NSpawners)), + io:format("Total spawned processes: ~p\n", [TotSpawn]), + Aliens = (erlang:processes() -- IgnoreList) -- TheLastOfUs, + io:format("Alien processes: ~p\n", [Aliens]), + ok. + + + +processes_send_infant_loop(IgnorePids) -> + %% Send message identifying this test case, in case we send + %% to alien processes spawned during the test. + Msg = processes_send_infant, + processes_send_infant_broadcast(erlang:processes(), + Msg, + IgnorePids), + receive timeout -> timeout + after 0 -> + processes_send_infant_loop(IgnorePids) + end. + +processes_send_infant_broadcast([Pid | Tail], Msg, IgnorePids) -> + case maps:is_key(Pid, IgnorePids) of + false -> + Pid ! Msg; + true -> + ignore + end, + processes_send_infant_broadcast(Tail, Msg, IgnorePids); +processes_send_infant_broadcast([], _, _) -> + ok. + +processes_send_infant_spawner(Sched, Tester, Parent, Generation) -> + link(Tester), + case receive_any() of + processes_send_infant -> + case Parent of + Tester -> ok; + _ -> Parent ! {die, self()} + end, + Self = self(), + Child = spawn_opt(fun() -> + processes_send_infant_spawner(Sched, Tester, + Self, + Generation+1) + end, + [{message_queue_data, off_heap}, + {scheduler, Sched}]), + process_send_infant_spawner_epilogue(Child); + + {processes_send_infant, stop} -> + Tester ! {self(), Generation} + end. + +process_send_infant_spawner_epilogue(Child) -> + %% Parent stays alive only to ensure child gets stop message + case receive_any() of + processes_send_infant -> + process_send_infant_spawner_epilogue(Child); + {die, Child} -> + ok; + {processes_send_infant, stop}=Stop -> + %% We are not sure child was spawned when stop message was sent + %% so we relay it. + Child ! Stop + end. + + -define(CHK_TERM_PROC_LIST(MC, XB), chk_term_proc_list(?LINE, MC, XB)). @@ -4367,25 +4766,11 @@ otp_16642(Config) when is_list(Config) -> false = is_process_alive(Pid), ok. -pid_ref_table_size() -> - erts_debug:get_internal_state(pid_ref_table_size). - -check_pid_ref_table_size(PRTSz) -> - receive after 500 -> ok end, - case pid_ref_table_size() of - PRTSz -> - ok; - NewPRTSz -> - ct:fail({port_ref_table_size_mismatch, PRTSz, NewPRTSz}) - end. - alias_bif(Config) when is_list(Config) -> - PRTSz = pid_ref_table_size(), alias_bif_test(node()), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), alias_bif_test(Node), - stop_node(Node), - check_pid_ref_table_size(PRTSz), + stop_node(Peer, Node), ok. alias_bif_test(Node) -> @@ -4430,12 +4815,10 @@ alias_bif_test(Node) -> monitor_alias(Config) when is_list(Config) -> - PRTSz = pid_ref_table_size(), monitor_alias_test(node()), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), monitor_alias_test(Node), - stop_node(Node), - check_pid_ref_table_size(PRTSz), + stop_node(Peer, Node), ok. monitor_alias_test(Node) -> @@ -4519,23 +4902,21 @@ monitor_alias_test(Node) -> spawn_monitor_alias(Config) when is_list(Config) -> %% Exit signals with immediate exit reasons are sent %% in a different manner than compound exit reasons. - PRTSz = pid_ref_table_size(), - spawn_monitor_alias_test(node(), spawn_opt, normal), - spawn_monitor_alias_test(node(), spawn_opt, make_ref()), - spawn_monitor_alias_test(node(), spawn_request, normal), - spawn_monitor_alias_test(node(), spawn_request, make_ref()), - {ok, Node1} = start_node(Config), - spawn_monitor_alias_test(Node1, spawn_opt, normal), - {ok, Node2} = start_node(Config), - spawn_monitor_alias_test(Node2, spawn_opt, make_ref()), - {ok, Node3} = start_node(Config), - spawn_monitor_alias_test(Node3, spawn_request, normal), - {ok, Node4} = start_node(Config), - spawn_monitor_alias_test(Node4, spawn_request, make_ref()), - check_pid_ref_table_size(PRTSz), + spawn_monitor_alias_test(undefined, node(), spawn_opt, normal), + spawn_monitor_alias_test(undefined, node(), spawn_opt, make_ref()), + spawn_monitor_alias_test(undefined, node(), spawn_request, normal), + spawn_monitor_alias_test(undefined, node(), spawn_request, make_ref()), + {ok, Peer1, Node1} = ?CT_PEER(), + spawn_monitor_alias_test(Peer1, Node1, spawn_opt, normal), + {ok, Peer2, Node2} = ?CT_PEER(), + spawn_monitor_alias_test(Peer2, Node2, spawn_opt, make_ref()), + {ok, Peer3, Node3} = ?CT_PEER(), + spawn_monitor_alias_test(Peer3, Node3, spawn_request, normal), + {ok, Peer4, Node4} = ?CT_PEER(), + spawn_monitor_alias_test(Peer4, Node4, spawn_request, make_ref()), ok. -spawn_monitor_alias_test(Node, SpawnType, ExitReason) -> +spawn_monitor_alias_test(Peer, Node, SpawnType, ExitReason) -> Spawn = case SpawnType of spawn_opt -> fun (F, O) -> @@ -4662,7 +5043,7 @@ spawn_monitor_alias_test(Node, SpawnType, ExitReason) -> receive after infinity -> ok end end, [{monitor, [{alias, demonitor}]}]), P6 ! {alias, MA6}, - stop_node(Node), + stop_node(Peer, Node), [{MA6,1},{MA6,2},{'DOWN', MA6, _, _, noconnection}] = recv_msgs(3), {_P6_1, M6_1} = spawn_monitor(fun () -> MA6 ! {MA6, 3}, @@ -4673,30 +5054,8 @@ spawn_monitor_alias_test(Node, SpawnType, ExitReason) -> ok end. -alias_process_exit(Config) when is_list(Config) -> - Tester = self(), - CreatedAliases = make_ref(), - PRTSz = pid_ref_table_size(), - P = spawn_link(fun () -> - A0 = alias([explicit_unalias]), - A1 = alias([reply]), - A2 = monitor(process, Tester, [{alias, explicit_unalias}]), - A3 = monitor(process, Tester, [{alias, demonitor}]), - A4 = monitor(process, Tester, [{alias, reply_demonitor}]), - Tester ! CreatedAliases, - receive after infinity -> ok end, - some_module:some_function([A0, A1, A2, A3, A4]) - end), - receive CreatedAliases -> ok end, - PRTSz = erts_debug:get_internal_state(pid_ref_table_size) - 5, - unlink(P), - exit(P, kill), - false = is_process_alive(P), - check_pid_ref_table_size(PRTSz), - ok. - demonitor_aliasmonitor(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), Fun = fun () -> receive {alias, Alias} -> @@ -4715,12 +5074,12 @@ demonitor_aliasmonitor(Config) when is_list(Config) -> RPid ! {alias, AliasMonitor}, receive {alias_reply, AliasMonitor, RPid} -> ok end, exit(LPid, kill), - stop_node(Node), + peer:stop(Peer), false = is_process_alive(LPid), ok. down_aliasmonitor(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), LPid = spawn(fun () -> receive infinty -> ok end end), RPid = spawn(Node, fun () -> @@ -4737,7 +5096,7 @@ down_aliasmonitor(Config) when is_list(Config) -> %% remote use of the alias to stop working... RPid ! {alias, AliasMonitor}, receive {alias_reply, AliasMonitor, RPid} -> ok end, - stop_node(Node), + peer:stop(Peer), ok. monitor_tag(Config) when is_list(Config) -> @@ -4745,33 +5104,33 @@ monitor_tag(Config) when is_list(Config) -> %% in a different manner than compound exit reasons, and %% immediate tags are stored in a different manner than %% compound tags. - monitor_tag_test(node(), spawn_opt, immed, normal), - monitor_tag_test(node(), spawn_opt, make_ref(), normal), - monitor_tag_test(node(), spawn_opt, immed, make_ref()), - monitor_tag_test(node(), spawn_opt, make_ref(), make_ref()), - monitor_tag_test(node(), spawn_request, immed, normal), - monitor_tag_test(node(), spawn_request, make_ref(), normal), - monitor_tag_test(node(), spawn_request, immed, make_ref()), - monitor_tag_test(node(), spawn_request, make_ref(), make_ref()), - {ok, Node1} = start_node(Config), - monitor_tag_test(Node1, spawn_opt, immed, normal), - {ok, Node2} = start_node(Config), - monitor_tag_test(Node2, spawn_opt, make_ref(), normal), - {ok, Node3} = start_node(Config), - monitor_tag_test(Node3, spawn_opt, immed, make_ref()), - {ok, Node4} = start_node(Config), - monitor_tag_test(Node4, spawn_opt, make_ref(), make_ref()), - {ok, Node5} = start_node(Config), - monitor_tag_test(Node5, spawn_request, immed, normal), - {ok, Node6} = start_node(Config), - monitor_tag_test(Node6, spawn_request, make_ref(), normal), - {ok, Node7} = start_node(Config), - monitor_tag_test(Node7, spawn_request, immed, make_ref()), - {ok, Node8} = start_node(Config), - monitor_tag_test(Node8, spawn_request, make_ref(), make_ref()), + monitor_tag_test(undefined, node(), spawn_opt, immed, normal), + monitor_tag_test(undefined, node(), spawn_opt, make_ref(), normal), + monitor_tag_test(undefined, node(), spawn_opt, immed, make_ref()), + monitor_tag_test(undefined, node(), spawn_opt, make_ref(), make_ref()), + monitor_tag_test(undefined, node(), spawn_request, immed, normal), + monitor_tag_test(undefined, node(), spawn_request, make_ref(), normal), + monitor_tag_test(undefined, node(), spawn_request, immed, make_ref()), + monitor_tag_test(undefined, node(), spawn_request, make_ref(), make_ref()), + {ok, Peer1, Node1} = ?CT_PEER(), + monitor_tag_test(Peer1, Node1, spawn_opt, immed, normal), + {ok, Peer2, Node2} = ?CT_PEER(), + monitor_tag_test(Peer2, Node2, spawn_opt, make_ref(), normal), + {ok, Peer3, Node3} = ?CT_PEER(), + monitor_tag_test(Peer3, Node3, spawn_opt, immed, make_ref()), + {ok, Peer4, Node4} = ?CT_PEER(), + monitor_tag_test(Peer4, Node4, spawn_opt, make_ref(), make_ref()), + {ok, Peer5, Node5} = ?CT_PEER(), + monitor_tag_test(Peer5, Node5, spawn_request, immed, normal), + {ok, Peer6, Node6} = ?CT_PEER(), + monitor_tag_test(Peer6, Node6, spawn_request, make_ref(), normal), + {ok, Peer7, Node7} = ?CT_PEER(), + monitor_tag_test(Peer7, Node7, spawn_request, immed, make_ref()), + {ok, Peer8, Node8} = ?CT_PEER(), + monitor_tag_test(Peer8, Node8, spawn_request, make_ref(), make_ref()), ok. -monitor_tag_test(Node, SpawnType, Tag, ExitReason) -> +monitor_tag_test(Peer, Node, SpawnType, Tag, ExitReason) -> P1 = spawn(Node, fun () -> receive go -> ok end, exit(ExitReason) end), M1 = monitor(process, P1, [{tag, Tag}]), @@ -4817,7 +5176,7 @@ monitor_tag_test(Node, SpawnType, Tag, ExitReason) -> false -> {P3, M3} = Spawn(fun () -> receive after infinity -> ok end end, [{monitor, [{tag, Tag}]}]), - stop_node(Node), + stop_node(Peer, Node), [{Tag, M3, process, P3, noconnection}] = recv_msgs(1), case SpawnType == spawn_opt of @@ -4831,6 +5190,54 @@ monitor_tag_test(Node, SpawnType, Tag, ExitReason) -> ok end. +no_pid_wrap(Config) when is_list(Config) -> + process_flag(priority, high), + SOnln = erlang:system_info(schedulers_online), + Pid = spawn(fun () -> ok end), + exit(Pid, kill), + false = is_process_alive(Pid), + ChkSpwndPid = fun () -> + check_spawned_pid(Pid) + end, + MPs = maps:from_list(lists:map(fun (_) -> + {P, M} = spawn_monitor(ChkSpwndPid), + {M, P} + end, lists:seq(1, SOnln))), + Res = receive + {'DOWN', M, process, _, pid_reused} when is_map_key(M, MPs) -> + case erlang:system_info(wordsize) of + 8 -> + ct:fail("Process identifier reused"), + error; + 4 -> + {comment, + "Process identifer reused, but this is" + ++ "expected since this is a 32-bit system"} + end; + {'DOWN', _, _, _, _} = Down -> + ct:fail({unexpected_down, Down}), + error + after + 3*60*1000 -> + ok + end, + maps:foreach(fun (_, P) -> + exit(P, kill) + end, MPs), + maps:foreach(fun (_, P) -> + false = is_process_alive(P) + end, MPs), + Res. + +check_spawned_pid(OldPid) -> + Pid = spawn(fun () -> ok end), + case OldPid == Pid of + false -> + check_spawned_pid(OldPid); + true -> + exit(pid_reused) + end. + %% Internal functions recv_msgs(N) -> @@ -4860,35 +5267,10 @@ tok_loop(hopp) -> id(I) -> I. -make_nodename(Config) when is_list(Config) -> - list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))). - -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = make_nodename(Config), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -start_peer_node(Config) -> - start_peer_node(Config, ""). - -start_peer_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = make_nodename(Config), - test_server:start_node(Name, peer, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> +stop_node(Peer, Node) -> verify_nc(node()), verify_nc(Node), - test_server:stop_node(Node). + peer:stop(Peer). verify_nc(Node) -> P = self(), @@ -4932,18 +5314,135 @@ sys_mem_cond_run(OrigReqSizeMB, TestFun) when is_integer(OrigReqSizeMB) -> total_memory() -> - %% Totat memory in MB. + %% Total memory in MB. try - MemoryData = memsup:get_system_memory_data(), - case lists:keysearch(total_memory, 1, MemoryData) of - {value, {total_memory, TM}} -> - TM div (1024*1024); - false -> - {value, {system_total_memory, STM}} = - lists:keysearch(system_total_memory, 1, MemoryData), - STM div (1024*1024) - end + SMD = memsup:get_system_memory_data(), + TM = proplists:get_value( + available_memory, SMD, + proplists:get_value( + total_memory, SMD, + proplists:get_value( + system_total_memory, SMD))), + TM div (1024*1024) catch _ : _ -> undefined end. + +start_ei_node(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + FwdNodeExe = filename:join(DataDir, "fwd_node"), + Name = atom_to_list(?MODULE) + ++ "-" ++ "ei_node" + ++ "-" ++ integer_to_list(erlang:system_time(second)) + ++ "-" ++ integer_to_list(erlang:unique_integer([positive])), + Cookie = atom_to_list(erlang:get_cookie()), + HostName = get_hostname(), + Node = list_to_atom(Name++"@"++HostName), + Creation = integer_to_list(rand:uniform((1 bsl 15) - 4) + 3), + Parent = self(), + Pid = spawn_link(fun () -> + register(cnode_forward_receiver, self()), + process_flag(trap_exit, true), + Args = ["-sname", Name, + "-cookie", Cookie, + "-creation", Creation], + io:format("Starting ei_node: ~p ~p~n", + [FwdNodeExe, Args]), + Port = erlang:open_port({spawn_executable, FwdNodeExe}, + [use_stdio, {args, Args}]), + receive + {Port, {data, "accepting"}} -> ok + end, + ei_node_handler_loop(Node, Parent, Port) + end), + put({ei_node_handler, Node}, Pid), + case check_ei_node(Node) of + ok -> {ok, Node}; + Error -> Error + end. + +check_ei_node(Node) -> + Key = {ei_node_handler, Node}, + case get(Key) of + undefined -> + {error, no_handler}; + Pid when is_pid(Pid) -> + Pid ! {check_node, self()}, + receive + {check_node, Pid, Res} -> + Res + after 3000 -> + {error, no_handler_response} + end + end. + +stop_ei_node(Node) -> + case check_ei_node(Node) of + ok -> + Key = {ei_node_handler, Node}, + case get(Key) of + undefined -> + {error, no_handler}; + Pid when is_pid(Pid) -> + Pid ! {stop_node, self()}, + receive + {stop_node, Pid} -> + put(Key, undefined), + ok + after 2000 -> + {error, no_handler_response} + end + end; + Error -> + Error + end. + +ei_node_handler_loop(Node, Parent, Port) -> + receive + {'EXIT', Parent, Reason} -> + erlang:disconnect_node(Node), + (catch port_close(Port)), + exit(Reason); + {stop_node, Parent} -> + erlang:disconnect_node(Node), + (catch port_close(Port)), + Parent ! {stop_node, self()}, + exit(normal); + {check_node, Parent} -> + Ref = make_ref(), + {a_name, Node} ! Ref, + receive + Ref -> + Parent ! {check_node, self(), ok} + after + 2000 -> + Parent ! {check_node, self(), {error, no_node_response}} + end; + Msg -> + Msgs = fetch_all_messages([Msg]), + erlang:disconnect_node(Node), + (catch port_close(Port)), + exit({ei_node_handler, Node, unexpected_messages, Msgs}) + end, + ei_node_handler_loop(Node, Parent, Port). + +fetch_all_messages(Msgs) -> + receive + Msg -> + fetch_all_messages([Msg|Msgs]) + after + 0 -> + Msgs + end. + +get_hostname() -> + get_hostname(atom_to_list(node())). + +get_hostname([$@ | HostName]) -> + HostName; +get_hostname([_ | Rest]) -> + get_hostname(Rest). + +receive_any() -> + receive M -> M end. diff --git a/erts/emulator/test/process_SUITE_data/Makefile.src b/erts/emulator/test/process_SUITE_data/Makefile.src new file mode 100644 index 000000000000..0f59ee0b059f --- /dev/null +++ b/erts/emulator/test/process_SUITE_data/Makefile.src @@ -0,0 +1,39 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2021. 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% +# + +include @erl_interface_mk_include@ + +CC = @CC@ +LD = @LD@ + +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ + +LIBEI = @erl_interface_eilib@ +LIBFLAGS = $(LIBEI) @LIBS@ @erl_interface_sock_libs@ @erl_interface_threadlib@ + +all: fwd_node@exe@ + +fwd_node@exe@: fwd_node@obj@ $(LIBEI) + $(LD) @CROSSLDFLAGS@ -o $@ fwd_node@obj@ $(LIBFLAGS) + +clean: + $(RM) fwd_node@obj@ + $(RM) fwd_node@exe@ + diff --git a/erts/emulator/test/process_SUITE_data/fwd_node.c b/erts/emulator/test/process_SUITE_data/fwd_node.c new file mode 100644 index 000000000000..da26fd42249c --- /dev/null +++ b/erts/emulator/test/process_SUITE_data/fwd_node.c @@ -0,0 +1,221 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2021. 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% + */ + +#include +#include +#include +#ifdef __WIN32__ +# include +#else +# include +# include +# include +#endif +#include "ei.h" + +static void usage1(char *what); +static void usage2(char *what, char *val); +static void fail1(char *what); + +char *progname; +ei_cnode cnode; +char *node_name = NULL; +char *cookie = NULL; +short creation = -1; + +#ifdef __WIN32__ +static unsigned __stdcall ei_node_executor(LPVOID unused) +#else +static void *ei_node_executor(void *unused) +#endif +{ + int lfd, pfd, res, port; + + ei_init(); + res = ei_connect_init(&cnode, node_name, cookie, creation); + if (res < 0) + fail1("ei_connect_init"); + port = 0; + lfd = ei_listen(&cnode, &port, 5); + if (lfd < 0) + fail1("ei_listen"); + pfd = ei_publish(&cnode, port); + if (pfd < 0) + fail1("ei_publish"); + + printf("accepting"); + fflush(stdout); + + while (!0) { + ErlConnect conn; + int afd = ei_accept(&cnode, lfd, &conn); + if (afd < 0) + fail1("ei_accept"); + + while (!0) { + ei_x_buff x; + erlang_msg msg; + ei_x_new(&x); + do { + res = ei_xreceive_msg(afd, &msg, &x); + } while (res == ERL_TICK); + if (res != ERL_MSG) { + /* connection closed... */ + ei_close_connection(afd); + break; + } + + switch (msg.msgtype) { + case ERL_SEND: + case ERL_REG_SEND: + ei_send_reg_encoded(afd, &cnode.self, "cnode_forward_receiver", + x.buff, x.index); + break; + case ERL_LINK: + fail1("received link"); + break; + case ERL_UNLINK: + fail1("received unlink"); + break; + case ERL_EXIT: + fail1("received exit"); + break; + default: + fail1("received invalid signal"); + break; + } + ei_x_free(&x); + } + } + +#ifdef __WIN32__ + return 0; +#else + return NULL; +#endif +} + +int +main(int argc, char *argv[]) +{ +#ifdef __WIN32__ + unsigned tid; + HANDLE thndl; +#else + pthread_t tid; +#endif + int i; + + progname = argv[0]; + i = 1; + while (i < argc) { + if (strcmp(argv[i], "-sname") == 0) { + i++; + if (i == argc) + usage1("Missing -sname value"); + node_name = argv[i]; + } + else if (strcmp(argv[i], "-cookie") == 0) { + i++; + if (i == argc) + usage1("Missing -cookie value"); + cookie = argv[i]; + } + else if (strcmp(argv[i], "-creation") == 0) { + char *endp; + long int val; + i++; + if (i == argc) + usage1("Missing -creation value"); + val = strtol(argv[i], &endp, 10); + creation = (short) val; + if (*endp != '\0' || creation < 4) + usage2("Invalid creation", argv[i]); + } + else { + usage2("Unknown parameter", argv[i]); + } + i++; + } + + if (!node_name) + usage1("Missing -sname parameter"); + if (!cookie) + usage1("Missing -cookie parameter"); + if (creation < 0) + usage1("Missing -creation parameter"); + +#ifdef __WIN32__ + thndl = (HANDLE) _beginthreadex(NULL, 0, ei_node_executor, + NULL, 0, &tid); + if (thndl == (HANDLE) 0) + fail1("_beginthreadex() failed"); +#else + if (pthread_create(&tid, NULL, ei_node_executor, NULL) != 0) + fail1("pthread_create() failed"); +#endif + + /* Wait until stdin is closed. Terminate when that happens... */ + while (!0) { + char buf[128]; +#ifdef __WIN32__ + int res = _read(0, (void *) &buf[0], sizeof(buf)); +#else + ssize_t res = read(0, (void *) &buf[0], sizeof(buf)); +#endif + if (res == 0) + exit(0); /* erlang port closed... */ + if (res < 0 && errno != EINTR) { + fail1("read() failed"); + } + } + + return 0; +} + +static void +usage1(char *what) +{ + fprintf(stderr, + "ERROR: %s\n\n" + " Usage:\n" + " %s -sname -cookie -creation \n", + what, progname); + exit(1); +} + +static void +usage2(char *what, char *val) +{ + fprintf(stderr, + "ERROR: %s: %s\n\n" + " Usage:\n" + " %s -sname -cookie -creation \n", + what, val, progname); + exit(1); +} + +static void +fail1(char *what) +{ + fprintf(stderr, "%s FAILED: %s; %d\n", + cnode.thisalivename, what, erl_errno); + exit(1); +} diff --git a/erts/emulator/test/random_iolist.erl b/erts/emulator/test/random_iolist.erl index 555f063e0a7f..6d895e354d2b 100644 --- a/erts/emulator/test/random_iolist.erl +++ b/erts/emulator/test/random_iolist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -44,8 +44,8 @@ random_list(N,Acc) -> random_list(N-1,[random_byte() | Acc]). random_binary(N) -> - B = list_to_binary(random_list(N,[])), - case {rand:uniform(2),size(B)} of + B = rand:bytes(N), + case {rand:uniform(2),byte_size(B)} of {2,M} when M > 1 -> S = M-1, <<_:3,C:S/binary,_:5>> = B, @@ -53,6 +53,7 @@ random_binary(N) -> _ -> B end. + random_list(N) -> random_list(N,[]). diff --git a/erts/emulator/test/ref_SUITE.erl b/erts/emulator/test/ref_SUITE.erl index ba590e0a60ac..597ac51c1277 100644 --- a/erts/emulator/test/ref_SUITE.erl +++ b/erts/emulator/test/ref_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -39,7 +39,7 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{testcase, Func}|Config]. end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> - ok. + erts_test_utils:ept_check_leaked_nodes(Config). all() -> [wrap_1, compare_list, compare_ets, internal_size, external_size]. @@ -132,7 +132,7 @@ external_size(Config) when is_list(Config) -> %% matches what the documentation say in the advanced chapter of the %% efficiency guide. Note that the values in the efficiency guide %% also add the word referencing the heap structure. - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), %% Ordinary external reference ORef = check_external_size(erpc:call(Node, fun () -> make_ref() end)), @@ -145,7 +145,7 @@ external_size(Config) when is_list(Config) -> io:format("PRef = ~p~n", [PRef]), - stop_node(Node), + peer:stop(Peer), ok. check_external_size(Ref) when is_reference(Ref) -> @@ -165,25 +165,3 @@ check_external_size(Ref) when is_reference(Ref) -> error({internal_ref_size_out_of_range, Sz}) end end. - -%% Internal stuff... - -make_nodename(Config) when is_list(Config) -> - list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))). - -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = make_nodename(Config), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index 32a8511968b0..65a1c1f9256c 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -52,11 +52,13 @@ cpu_topology/1, update_cpu_info/1, sct_cmd/1, + ssrct_cmd/1, sbt_cmd/1, scheduler_threads/1, scheduler_suspend_basic/1, scheduler_suspend/1, dirty_scheduler_threads/1, + sched_poll/1, poll_threads/1, reader_groups/1, otp_16446/1, @@ -76,6 +78,7 @@ all() -> {group, scheduler_bind}, scheduler_threads, scheduler_suspend_basic, scheduler_suspend, dirty_scheduler_threads, + sched_poll, poll_threads, reader_groups, otp_16446, @@ -85,7 +88,7 @@ all() -> groups() -> [{scheduler_bind, [], [scheduler_bind_types, cpu_topology, update_cpu_info, - sct_cmd, sbt_cmd]}]. + sct_cmd, sbt_cmd, ssrct_cmd]}]. init_per_suite(Config) -> [{schedulers_online, erlang:system_info(schedulers_online)} | Config]. @@ -120,7 +123,7 @@ init_per_tc(Case, Config) -> [{testcase, Case}, {ok_res, OkRes} |Config]. end_per_testcase(_Case, Config) when is_list(Config) -> - ok. + erts_test_utils:ept_check_leaked_nodes(Config). -define(ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED, (2000*2000)). -define(DEFAULT_TEST_REDS_PER_SCHED, 200000000). @@ -283,7 +286,7 @@ bound_loop(NS, N, M, Sched) -> -define(TOPOLOGY_A_CMD, - "+sct" + ["+sct" "L0-1t0-1c0p0n0" ":L2-3t0-1c1p0n0" ":L4-5t0-1c0p1n0" @@ -291,7 +294,7 @@ bound_loop(NS, N, M, Sched) -> ":L8-9t0-1c0p2n1" ":L10-11t0-1c1p2n1" ":L12-13t0-1c0p3n1" - ":L14-15t0-1c1p3n1"). + ":L14-15t0-1c1p3n1"]). -define(TOPOLOGY_A_TERM, [{node,[{processor,[{core,[{thread,{logical,0}}, @@ -312,7 +315,7 @@ bound_loop(NS, N, M, Sched) -> {thread,{logical,15}}]}]}]}]). -define(TOPOLOGY_B_CMD, - "+sct" + ["+sct" "L0-1t0-1c0n0p0" ":L2-3t0-1c1n0p0" ":L4-5t0-1c2n1p0" @@ -320,7 +323,7 @@ bound_loop(NS, N, M, Sched) -> ":L8-9t0-1c0n2p1" ":L10-11t0-1c1n2p1" ":L12-13t0-1c2n3p1" - ":L14-15t0-1c3n3p1"). + ":L14-15t0-1c3n3p1"]). -define(TOPOLOGY_B_TERM, [{processor,[{node,[{core,[{thread,{logical,0}}, @@ -376,7 +379,7 @@ bound_loop(NS, N, M, Sched) -> -define(TOPOLOGY_C_CMD, - "+sct" + ["+sct" "L0-1t0-1c0p0n0" ":L2-3t0-1c1p0n0" ":L4-5t0-1c0p1n0" @@ -392,7 +395,7 @@ bound_loop(NS, N, M, Sched) -> ":L24-25t0-1c0n4p5" ":L26-27t0-1c1n4p5" ":L28-29t0-1c2n5p5" - ":L30-31t0-1c3n5p5"). + ":L30-31t0-1c3n5p5"]). -define(TOPOLOGY_D_TERM, [{processor,[{node,[{core,[{thread,{logical,0}}, @@ -429,7 +432,7 @@ bound_loop(NS, N, M, Sched) -> {thread,{logical,31}}]}]}]}]). -define(TOPOLOGY_D_CMD, - "+sct" + ["+sct" "L0-1t0-1c0n0p0" ":L2-3t0-1c1n0p0" ":L4-5t0-1c2n1p0" @@ -445,10 +448,10 @@ bound_loop(NS, N, M, Sched) -> ":L24-25t0-1c0p4n5" ":L26-27t0-1c1p4n5" ":L28-29t0-1c0p5n5" - ":L30-31t0-1c1p5n5"). + ":L30-31t0-1c1p5n5"]). -define(TOPOLOGY_E_CMD, - "+sct" + ["+sct" "L0-1t0-1c0p0n0" ":L2-3t0-1c1p0n0" ":L4-5t0-1c2p0n0" @@ -456,7 +459,7 @@ bound_loop(NS, N, M, Sched) -> ":L8-9t0-1c0p1n1" ":L10-11t0-1c1p1n1" ":L12-13t0-1c2p1n1" - ":L14-15t0-1c3p1n1"). + ":L14-15t0-1c3p1n1"]). -define(TOPOLOGY_E_TERM, [{node,[{processor,[{core,[{thread,{logical,0}}, @@ -477,7 +480,7 @@ bound_loop(NS, N, M, Sched) -> {thread,{logical,15}}]}]}]}]). -define(TOPOLOGY_F_CMD, - "+sct" + ["+sct" "L0-1t0-1c0n0p0" ":L2-3t0-1c1n0p0" ":L4-5t0-1c2n0p0" @@ -493,7 +496,7 @@ bound_loop(NS, N, M, Sched) -> ":L24-25t0-1c12n3p0" ":L26-27t0-1c13n3p0" ":L28-29t0-1c14n3p0" - ":L30-31t0-1c15n3p0"). + ":L30-31t0-1c15n3p0"]). -define(TOPOLOGY_F_TERM, [{processor,[{node,[{core,[{thread,{logical,0}}, @@ -550,27 +553,27 @@ bindings(Node, BindType) -> scheduler_bind_types(Config) when is_list(Config) -> OldRelFlags = clear_erl_rel_flags(), try - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_A_TERM, ?TOPOLOGY_A_CMD, a), - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_B_TERM, ?TOPOLOGY_B_CMD, b), - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_C_TERM, ?TOPOLOGY_C_CMD, c), - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_D_TERM, ?TOPOLOGY_D_CMD, d), - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_E_TERM, ?TOPOLOGY_E_CMD, e), - scheduler_bind_types_test(Config, + scheduler_bind_types_test( ?TOPOLOGY_F_TERM, ?TOPOLOGY_F_CMD, f) @@ -579,17 +582,17 @@ scheduler_bind_types(Config) when is_list(Config) -> end, ok. -scheduler_bind_types_test(Config, Topology, CmdLine, TermLetter) -> +scheduler_bind_types_test(Topology, CmdLine, TermLetter) -> io:format("Testing (~p): ~p~n", [TermLetter, Topology]), - {ok, Node0} = start_node(Config), + {ok, Peer, Node0} = ?CT_PEER(), _ = rpc:call(Node0, erlang, system_flag, [cpu_topology, Topology]), cmp(Topology, rpc:call(Node0, erlang, system_info, [cpu_topology])), check_bind_types(Node0, TermLetter), - stop_node(Node0), - {ok, Node1} = start_node(Config, CmdLine), + peer:stop(Peer), + {ok, Peer1, Node1} = ?CT_PEER(CmdLine), cmp(Topology, rpc:call(Node1, erlang, system_info, [cpu_topology])), check_bind_types(Node1, TermLetter), - stop_node(Node1). + peer:stop(Peer1). check_bind_types(Node, a) -> {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} @@ -714,7 +717,6 @@ cpu_topology(Config) when is_list(Config) -> OldRelFlags = clear_erl_rel_flags(), try cpu_topology_test( - Config, [{node,[{processor,[{core,{logical,0}}, {core,{logical,1}}]}]}, {processor,[{node,[{core,{logical,2}}, @@ -723,13 +725,12 @@ cpu_topology(Config) when is_list(Config) -> {core,{logical,5}}]}]}, {processor,[{node,[{core,{logical,6}}, {core,{logical,7}}]}]}], - "+sct " + ["+sct", "L0-1c0-1p0n0" ":L2-3c0-1n1p1" ":L4-5c0-1p2n2" - ":L6-7c0-1n3p3"), + ":L6-7c0-1n3p3"]), cpu_topology_test( - Config, [{node,[{processor,[{core,{logical,0}}, {core,{logical,1}}]}, {processor,[{core,{logical,2}}, @@ -746,7 +747,7 @@ cpu_topology(Config) when is_list(Config) -> {core,{logical,13}}]}, {node,[{core,{logical,14}}, {core,{logical,15}}]}]}], - "+sct " + ["+sct", "L0-1c0-1p0n0" ":L2-3c0-1p1n0" ":L4-5c0-1n1p2" @@ -754,9 +755,8 @@ cpu_topology(Config) when is_list(Config) -> ":L8-9c0-1p3n3" ":L10-11c0-1p4n3" ":L12-13c0-1n4p5" - ":L14-15c2-3n5p5"), + ":L14-15c2-3n5p5"]), cpu_topology_test( - Config, [{node,[{processor,[{core,{logical,0}}, {core,{logical,1}}]}]}, {processor,[{node,[{core,{logical,2}}, @@ -769,39 +769,45 @@ cpu_topology(Config) when is_list(Config) -> {core,{logical,9}}]}]}, {processor,[{node,[{core,{logical,10}}, {core,{logical,11}}]}]}], - "+sct " + ["+sct", "L0-1c0-1p0n0" ":L2-3c0-1n1p1" ":L4-5c0-1n2p2" ":L6-7c0-1p3n3" ":L8-9c0-1p4n4" - ":L10-11c0-1n5p5") + ":L10-11c0-1n5p5"]) after restore_erl_rel_flags(OldRelFlags) end, ok. -cpu_topology_test(Config, Topology, Cmd) -> +cpu_topology_test(Topology, Cmd) -> io:format("Testing~n ~p~n ~p~n", [Topology, Cmd]), - cpu_topology_bif_test(Config, Topology), - cpu_topology_cmdline_test(Config, Topology, Cmd), + cpu_topology_bif_test(Topology), + cpu_topology_cmdline_test(Topology, Cmd), ok. -cpu_topology_bif_test(_Config, false) -> +cpu_topology_bif_test(false) -> ok; -cpu_topology_bif_test(Config, Topology) -> - {ok, Node} = start_node(Config), +cpu_topology_bif_test(Topology) -> + {ok, Peer, Node} = ?CT_PEER(), _ = rpc:call(Node, erlang, system_flag, [cpu_topology, Topology]), cmp(Topology, rpc:call(Node, erlang, system_info, [cpu_topology])), - stop_node(Node), + cmp(Topology, + rpc:call(Node, erlang, system_info, [{cpu_topology, defined}])), + peer:stop(Peer), ok. -cpu_topology_cmdline_test(_Config, _Topology, false) -> +cpu_topology_cmdline_test(_Topology, false) -> ok; -cpu_topology_cmdline_test(Config, Topology, Cmd) -> - {ok, Node} = start_node(Config, Cmd), +cpu_topology_cmdline_test(Topology, Cmd) -> + {ok, Peer, Node} = ?CT_PEER(Cmd), cmp(Topology, rpc:call(Node, erlang, system_info, [cpu_topology])), - stop_node(Node), + cmp(undefined, + rpc:call(Node, erlang, system_info, [{cpu_topology, detected}])), + cmp(Topology, + rpc:call(Node, erlang, system_info, [{cpu_topology, defined}])), + peer:stop(Peer), ok. update_cpu_info(Config) when is_list(Config) -> @@ -983,19 +989,39 @@ sct_cmd(Config) when is_list(Config) -> Topology = ?TOPOLOGY_A_TERM, OldRelFlags = clear_erl_rel_flags(), try - {ok, Node} = start_node(Config, ?TOPOLOGY_A_CMD), + {ok, Peer, Node} = ?CT_PEER(?TOPOLOGY_A_CMD), cmp(Topology, rpc:call(Node, erlang, system_info, [cpu_topology])), + cmp(undefined, + rpc:call(Node, erlang, system_info, [{cpu_topology, detected}])), + cmp(Topology, + rpc:call(Node, erlang, system_info, [{cpu_topology, defined}])), cmp(Topology, rpc:call(Node, erlang, system_flag, [cpu_topology, Topology])), cmp(Topology, rpc:call(Node, erlang, system_info, [cpu_topology])), - stop_node(Node) + peer:stop(Peer) after restore_erl_rel_flags(OldRelFlags) end, ok. +ssrct_cmd(Config) when is_list(Config) -> + OldRelFlags = clear_erl_rel_flags(), + try + {ok, Peer, Node} = ?CT_PEER(["+ssrct"]), + cmp(undefined, + rpc:call(Node, erlang, system_info, [cpu_topology])), + cmp(undefined, + rpc:call(Node, erlang, system_info, [{cpu_topology, detected}])), + cmp(undefined, + rpc:call(Node, erlang, system_info, [{cpu_topology, defined}])), + peer:stop(Peer) + after + restore_erl_rel_flags(OldRelFlags) + end, + ok. + -define(BIND_TYPES, [{"u", unbound}, {"ns", no_spread}, @@ -1020,7 +1046,7 @@ sbt_cmd(Config) when is_list(Config) -> OldRelFlags = clear_erl_rel_flags(), try lists:foreach(fun ({ClBt, Bt}) -> - sbt_test(Config, CpuTCmd, + sbt_test(CpuTCmd, ClBt, Bt, LP) end, ?BIND_TYPES) @@ -1038,10 +1064,10 @@ sbt_make_topology_args() -> linux -> case erlang:system_info(logical_processors) of 1 -> - "+sctL0"; + ["+sctL0"]; N -> NS = integer_to_list(N - 1), - "+sctL0-"++NS++"p0-"++NS + ["+sctL0-"++NS++"p0-"++NS] end; _ -> false @@ -1085,11 +1111,11 @@ sbt_check_prereqs() -> throw:{skip,_Reason}=Skip -> Skip end. -sbt_test(Config, CpuTCmd, ClBt, Bt, LP) -> +sbt_test(CpuTCmd, ClBt, Bt, LP) -> io:format("Testing +sbt ~s (~p)~n", [ClBt, Bt]), LPS = integer_to_list(LP), - Cmd = CpuTCmd++" +sbt "++ClBt++" +S"++LPS++":"++LPS, - {ok, Node} = start_node(Config, Cmd), + Cmd = CpuTCmd++["+sbt", ClBt, "+S"++LPS++":"++LPS], + {ok, Peer, Node} = ?CT_PEER(Cmd), Bt = rpc:call(Node, erlang, system_info, @@ -1113,16 +1139,16 @@ sbt_test(Config, CpuTCmd, ClBt, Bt, LP) -> end, BS, tuple_to_list(SB)), - stop_node(Node), + peer:stop(Peer), ok. scheduler_threads(Config) when is_list(Config) -> - {Sched, SchedOnln, _} = get_sstate(Config, ""), + {Sched, SchedOnln, _} = get_sstate(""), %% Configure half the number of both the scheduler threads and %% the scheduler threads online. {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]), lists:max([1,SchedOnln div 2])}, - {HalfSched, HalfSchedOnln, _} = get_sstate(Config, "+SP 50:50"), + {HalfSched, HalfSchedOnln, _} = get_sstate(["+SP", "50:50"]), %% Use +S to configure 4x the number of scheduler threads and %% 4x the number of scheduler threads online, but alter that %% setting using +SP to 50% scheduler threads and 25% scheduler @@ -1131,19 +1157,19 @@ scheduler_threads(Config) when is_list(Config) -> TwiceSched = Sched*2, FourSched = integer_to_list(Sched*4), FourSchedOnln = integer_to_list(SchedOnln*4), - CombinedCmd1 = "+S "++FourSched++":"++FourSchedOnln++" +SP50:25", - {TwiceSched, SchedOnln, _} = get_sstate(Config, CombinedCmd1), + CombinedCmd1 = ["+S", FourSched++":"++FourSchedOnln, "+SP50:25"], + {TwiceSched, SchedOnln, _} = get_sstate(CombinedCmd1), %% Now do the same test but with the +S and +SP options in the %% opposite order, since order shouldn't matter. - CombinedCmd2 = "+SP50:25 +S "++FourSched++":"++FourSchedOnln, - {TwiceSched, SchedOnln, _} = get_sstate(Config, CombinedCmd2), + CombinedCmd2 = ["+SP50:25", "+S", FourSched++":"++FourSchedOnln], + {TwiceSched, SchedOnln, _} = get_sstate(CombinedCmd2), %% Apply two +SP options to make sure the second overrides the first - TwoCmd = "+SP 25:25 +SP 100:100", - {Sched, SchedOnln, _} = get_sstate(Config, TwoCmd), + TwoCmd = ["+SP", "25:25", "+SP", "100:100"], + {Sched, SchedOnln, _} = get_sstate(TwoCmd), %% Configure 50% of scheduler threads online only - {Sched, HalfSchedOnln, _} = get_sstate(Config, "+SP:50"), + {Sched, HalfSchedOnln, _} = get_sstate(["+SP:50"]), %% Configure 2x scheduler threads only - {TwiceSched, SchedOnln, _} = get_sstate(Config, "+SP 200"), + {TwiceSched, SchedOnln, _} = get_sstate(["+SP", "200"]), LProc = erlang:system_info(logical_processors), LProcAvail = erlang:system_info(logical_processors_available), @@ -1157,30 +1183,30 @@ scheduler_threads(Config) when is_list(Config) -> is_integer(LProc); is_integer(LProcAvail) -> ExpectedOnln = st_expected_onln(LProcAvail, Quota), - st_reset(Config, LProc, ExpectedOnln, FourSched, FourSchedOnln), + st_reset(LProc, ExpectedOnln, FourSched, FourSchedOnln), if LProc =:= 1; LProcAvail =:= 1 -> {comment, "Skipped reduced amount of schedulers test due " "to too few logical processors"}; LProc > 1, LProcAvail > 1 -> - st_reduced(Config, LProc, ExpectedOnln) + st_reduced(LProc, ExpectedOnln) end end. -st_reset(Config, LProc, ExpectedOnln, FourSched, FourSchedOnln) -> +st_reset(LProc, ExpectedOnln, FourSched, FourSchedOnln) -> %% Test resetting # of schedulers. - ResetCmd = "+S "++FourSched++":"++FourSchedOnln++" +S 0:0", - {LProc, ExpectedOnln, _} = get_sstate(Config, ResetCmd), + ResetCmd = ["+S", FourSched++":"++FourSchedOnln, "+S", "0:0"], + {LProc, ExpectedOnln, _} = get_sstate(ResetCmd), ok. -st_reduced(Config, LProc, ExpectedOnln) -> +st_reduced(LProc, ExpectedOnln) -> %% Test negative +S settings SchedMinus1 = LProc-1, SchedOnlnMinus1 = ExpectedOnln-1, - {SchedMinus1, SchedOnlnMinus1, _} = get_sstate(Config, "+S -1"), - {LProc, SchedOnlnMinus1, _} = get_sstate(Config, "+S :-1"), - {SchedMinus1, SchedOnlnMinus1, _} = get_sstate(Config, "+S -1:-1"), + {SchedMinus1, SchedOnlnMinus1, _} = get_sstate(["+S", "-1"]), + {LProc, SchedOnlnMinus1, _} = get_sstate(["+S", ":-1"]), + {SchedMinus1, SchedOnlnMinus1, _} = get_sstate(["+S", "-1:-1"]), ok. st_expected_onln(LProcAvail, unknown) -> LProcAvail; @@ -1192,18 +1218,19 @@ dirty_scheduler_threads(Config) when is_list(Config) -> _ -> dirty_scheduler_threads_test(Config) end. -dirty_scheduler_threads_test(Config) -> - {Sched, SchedOnln, _} = get_dsstate(Config, ""), +dirty_scheduler_threads_test(Config) when is_list(Config) -> + {Sched, SchedOnln, _} = get_dsstate(""), {HalfSched, HalfSchedOnln} = {lists:max([1,Sched div 2]), lists:max([1,SchedOnln div 2])}, - Cmd1 = "+SDcpu "++integer_to_list(HalfSched)++":"++ - integer_to_list(HalfSchedOnln), - {HalfSched, HalfSchedOnln, _} = get_dsstate(Config, Cmd1), - {HalfSched, HalfSchedOnln, _} = get_dsstate(Config, "+SDPcpu 50:50"), + Cmd1 = ["+SDcpu", integer_to_list(HalfSched)++":"++ + integer_to_list(HalfSchedOnln)], + {HalfSched, HalfSchedOnln, _} = get_dsstate(Cmd1), + {HalfSched, HalfSchedOnln, _} = get_dsstate(["+SDPcpu", "50:50"]), IOSched = 20, - {_, _, IOSched} = get_dsstate(Config, "+SDio "++integer_to_list(IOSched)), - {ok, Node} = start_node(Config, ""), + {_, _, IOSched} = get_dsstate(["+SDio", integer_to_list(IOSched)]), + {ok, Peer, Node} = ?CT_PEER(), [ok] = mcall(Node, [fun() -> dirty_schedulers_online_test() end]), + peer:stop(Peer), ok. dirty_schedulers_online_test() -> @@ -1227,16 +1254,16 @@ dirty_schedulers_online_smp_test(SchedOnln) -> QrtrDirtyCPUSchedOnln = erlang:system_info(dirty_cpu_schedulers_online), ok. -get_sstate(Config, Cmd) -> - {ok, Node} = start_node(Config, Cmd), +get_sstate(Cmd) -> + {ok, Peer, Node} = ?CT_PEER(#{ args => Cmd, env => [{"ERL_FLAGS",false}]}), [SState] = mcall(Node, [fun () -> erlang:system_info(schedulers_state) end]), - stop_node(Node), + peer:stop(Peer), SState. -get_dsstate(Config, Cmd) -> - {ok, Node} = start_node(Config, Cmd), +get_dsstate(Cmd) -> + {ok, Peer, Node} = ?CT_PEER(#{ args => Cmd, env => [{"ERL_FLAGS",false}]}), [DSCPU] = mcall(Node, [fun () -> erlang:system_info(dirty_cpu_schedulers) end]), @@ -1246,7 +1273,7 @@ get_dsstate(Config, Cmd) -> [DSIO] = mcall(Node, [fun () -> erlang:system_info(dirty_io_schedulers) end]), - stop_node(Node), + peer:stop(Peer), {DSCPU, DSCPUOnln, DSIO}. scheduler_suspend_basic(Config) when is_list(Config) -> @@ -1360,18 +1387,19 @@ scheduler_suspend_basic_test() -> scheduler_suspend(Config) when is_list(Config) -> ct:timetrap({minutes, 5}), - lists:foreach(fun (S) -> scheduler_suspend_test(Config, S) end, + lists:foreach(fun (S) -> scheduler_suspend_test(S) end, [64, 32, 16, default]), ok. -scheduler_suspend_test(Config, Schedulers) -> + +scheduler_suspend_test(Schedulers) -> Cmd = case Schedulers of default -> ""; _ -> S = integer_to_list(Schedulers), - "+S"++S++":"++S + ["+S"++S++":"++S] end, - {ok, Node} = start_node(Config, Cmd), + {ok, Peer, Node} = ?CT_PEER(Cmd), [SState] = mcall(Node, [fun () -> erlang:system_info(schedulers_state) end]), @@ -1413,7 +1441,7 @@ scheduler_suspend_test(Config, Schedulers) -> native)), erlang:system_info(schedulers_state) end]), - stop_node(Node), + peer:stop(Peer), ok. until(Pred, MaxTime) -> @@ -1502,59 +1530,102 @@ sst5_loop(N) -> erlang:system_flag(multi_scheduling, unblock_normal), sst5_loop(N-1). +%% Test scheduler polling: +IOs true|false +sched_poll(Config) when is_list(Config) -> + + Env = case os:getenv("ERL_AFLAGS") of + false -> + []; + AFLAGS1 -> + %% Remove any +IOs + AFLAGS2 = list_to_binary(re:replace(AFLAGS1, + "\\+IOs (true|false)", + "", [global])), + [{"ERL_AFLAGS", binary_to_list(AFLAGS2)}] + end, + + [PS | _] = get_iostate(""), + HaveSchedPoll = proplists:get_value(concurrent_updates, PS), + + 0 = get_sched_pollsets(["+IOs", "false"]), + if + HaveSchedPoll -> + 1 = get_sched_pollsets(["+IOs", "true"]), + 1 = get_sched_pollsets([], Env); + + not HaveSchedPoll -> + fail = get_sched_pollsets(["+IOs", "true"]), + 0 = get_sched_pollsets([], Env) + end, + fail = get_sched_pollsets(["+IOs", "bad"]), + ok. + +get_sched_pollsets(Cmd) -> + get_sched_pollsets(Cmd, []). + +get_sched_pollsets(Cmd, Env)-> + try + {ok, Peer, Node} = ?CT_PEER(#{connection => standard_io, args => Cmd, + env => [{"ERL_LIBS", false} | Env]}), + [IOStates] = mcall(Node,[fun () -> erlang:system_info(check_io) end]), + IO = [IOState || IOState <- IOStates, + %% We assume non-fallbacks without threads are scheduler pollsets + proplists:get_value(fallback, IOState) == false, + proplists:get_value(poll_threads, IOState) == 0], + peer:stop(Peer), + length(IO) % number of scheduler pollsets + catch + exit:{boot_failed, _} -> + fail + end. + poll_threads(Config) when is_list(Config) -> - {Conc, PollType, KP} = get_ioconfig(Config), - {Sched, SchedOnln, _} = get_sstate(Config, ""), + [PS | _] = get_iostate(""), + Conc = proplists:get_value(concurrent_updates, PS), - [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), - [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), - [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), + [1, 1] = get_ionum(["+IOt", "2", "+IOp", "2"]), + [1, 1, 1, 1, 1] = get_ionum(["+IOt", "5", "+IOp", "5"]), + [1, 1] = get_ionum(["+S", "2", "+IOPt", "100", "+IOPp", "100"]), if Conc -> - [5] = get_ionum(Config,"+IOt 5 +IOp 1"), - [3, 2] = get_ionum(Config,"+IOt 5 +IOp 2"), - [2, 2, 2, 2, 2] = get_ionum(Config,"+IOt 10 +IOPp 50"), + [5] = get_ionum(["+IOt", "5", "+IOp", "1"]), + [3, 2] = get_ionum(["+IOt", "5", "+IOp", "2"]), + [2, 2, 2, 2, 2] = get_ionum(["+IOt", "10", "+IOPp", "50"]), - [2] = get_ionum(Config, "+S 2 +IOPt 100"), - [4] = get_ionum(Config, "+S 4 +IOPt 100"), - [4] = get_ionum(Config, "+S 4:2 +IOPt 100"), - [4, 4] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), + [2] = get_ionum(["+S", "2", "+IOPt", "100"]), + [4] = get_ionum(["+S", "4", "+IOPt", "100"]), + [4] = get_ionum(["+S", "4:2", "+IOPt", "100"]), + [4, 4] = get_ionum(["+S", "8", "+IOPt", "100", "+IOPp", "25"]), - fail = get_ionum(Config, "+IOt 1 +IOp 2"), + fail = get_ionum(["+IOt", "1", "+IOp", "2"]), ok; not Conc -> - [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 1"), - [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 2"), - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"), + [1, 1, 1, 1, 1] = get_ionum(["+IOt", "5", "+IOp", "1"]), + [1, 1, 1, 1, 1] = get_ionum(["+IOt", "5", "+IOp", "2"]), + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(["+IOt", "10", "+IOPp", "50"]), - [1, 1] = get_ionum(Config, "+S 2 +IOPt 100"), - [1, 1, 1, 1] = get_ionum(Config, "+S 4 +IOPt 100"), - [1, 1, 1, 1] = get_ionum(Config, "+S 4:2 +IOPt 100"), - [1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), + [1, 1] = get_ionum(["+S", "2", "+IOPt", "100"]), + [1, 1, 1, 1] = get_ionum(["+S", "4", "+IOPt", "100"]), + [1, 1, 1, 1] = get_ionum(["+S", "4:2", "+IOPt", "100"]), + [1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(["+S", "8", "+IOPt", "100" "+IOPp", "25"]), - [1] = get_ionum(Config, "+IOt 1 +IOp 2"), + [1] = get_ionum(["+IOt", "1", "+IOp", "2"]), ok end, - fail = get_ionum(Config, "+IOt 1 +IOPp 101"), - fail = get_ionum(Config, "+IOt 0"), - fail = get_ionum(Config, "+IOPt 101"), + fail = get_ionum(["+IOt", "1", "+IOPp", "101"]), + fail = get_ionum(["+IOt", "0"]), + fail = get_ionum(["+IOPt", "101"]), ok. -get_ioconfig(Config) -> - [PS | _] = get_iostate(Config, ""), - {proplists:get_value(concurrent_updates, PS), - proplists:get_value(primary, PS), - proplists:get_value(kernel_poll, PS)}. - -get_ionum(Config, Cmd) -> - case get_iostate(Config, Cmd) of +get_ionum(Cmd) -> + case get_iostate(Cmd) of fail -> fail; PSs -> lists:reverse( @@ -1562,18 +1633,18 @@ get_ionum(Config, Cmd) -> [proplists:get_value(poll_threads, PS) || PS <- PSs])) end. -get_iostate(Config, Cmd)-> - case start_node(Config, Cmd) of - {ok, Node} -> - [IOStates] = mcall(Node,[fun () -> - erlang:system_info(check_io) - end]), - IO = [IOState || IOState <- IOStates, - proplists:get_value(fallback, IOState) == false, - proplists:get_value(poll_threads, IOState) /= 0], - stop_node(Node), - IO; - {error,timeout} -> +get_iostate(Cmd)-> + try + {ok, Peer, Node} = ?CT_PEER(#{connection => standard_io, args => Cmd, + env => [{"ERL_LIBS", false}]}), + [IOStates] = mcall(Node,[fun () -> erlang:system_info(check_io) end]), + IO = [IOState || IOState <- IOStates, + proplists:get_value(fallback, IOState) == false, + proplists:get_value(poll_threads, IOState) /= 0], + peer:stop(Peer), + IO + catch + exit:{boot_failed, _} -> fail end. @@ -2490,24 +2561,6 @@ active_schedulers() -> enabled -> N end end. - -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). - enable_internal_state() -> case catch erts_debug:get_internal_state(available_internal_state) of diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl index 9531c13b9a13..35f0d11e67fb 100644 --- a/erts/emulator/test/send_term_SUITE.erl +++ b/erts/emulator/test/send_term_SUITE.erl @@ -212,14 +212,14 @@ make_expected_ext2term_drv([T|Ts]) -> %% generate_external_terms_files(BaseDir) -> - {ok,Node} = slave:start(hostname(), a_node), + {ok, Peer, Node} = ?CT_PEER(), RPid = rpc:call(Node, erlang, self, []), true = is_pid(RPid), RRef = rpc:call(Node, erlang, make_ref, []), true = is_reference(RRef), RPort = hd(rpc:call(Node, erlang, ports, [])), true = is_port(RPort), - slave:stop(Node), + peer:stop(Peer), Terms = [{4711, -4711, [an_atom, "a list"]}, [1000000000000000000000,-1111111111111111, "blupp!", blipp], {RPid, {RRef, RPort}, self(), hd(erlang:ports()), make_ref()}, @@ -341,12 +341,3 @@ write_license(IoDev) -> " * and needs to be consistent with each other.~n" " */~n", io:format(IoDev, S, []). - - -hostname() -> - hostname(atom_to_list(node())). - -hostname([$@ | Hostname]) -> - list_to_atom(Hostname); -hostname([_C | Cs]) -> - hostname(Cs). diff --git a/erts/emulator/test/sensitive_SUITE.erl b/erts/emulator/test/sensitive_SUITE.erl index e3e753c6a51b..504e70a826a3 100644 --- a/erts/emulator/test/sensitive_SUITE.erl +++ b/erts/emulator/test/sensitive_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2021. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -293,7 +293,7 @@ running_trace(Config) when is_list(Config) -> {trace,Self,in,{sensitive_SUITE,running_trace,1}} | Extra] = Messages, case erlang:system_info(emu_type) of ET when ET =:= debug; ET =:= asan -> - %% F_DBG_FORCED_TRAP in erts_try_size_code_write_permission + %% F_DBG_FORCED_TRAP in erts_try_seize_code_mod_permission [{trace,Self,out,{erts_internal,trace,3}}, {trace,Self,in,{erts_internal,trace,3}}] = Extra; _ -> diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl index 7afafcd7bbf6..0c5b27a0b16c 100644 --- a/erts/emulator/test/signal_SUITE.erl +++ b/erts/emulator/test/signal_SUITE.erl @@ -32,6 +32,7 @@ -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0,init_per_suite/1, end_per_suite/1]). -export([init_per_testcase/2, end_per_testcase/2]). +-export([groups/0, init_per_group/2, end_per_group/2]). % Test cases -export([xm_sig_order/1, @@ -43,13 +44,31 @@ busy_dist_down_signal/1, busy_dist_spawn_reply_signal/1, busy_dist_unlink_ack_signal/1, - unlink_exit/1]). + unlink_exit/1, + monitor_order/1, + monitor_named_order_local/1, + monitor_named_order_remote/1, + monitor_nodes_order/1, + move_msgs_off_heap_signal_basic/1, + move_msgs_off_heap_signal_recv/1, + move_msgs_off_heap_signal_exit/1, + move_msgs_off_heap_signal_recv_exit/1, + copy_literal_area_signal_basic/1, + copy_literal_area_signal_recv/1, + copy_literal_area_signal_exit/1, + copy_literal_area_signal_recv_exit/1, + simultaneous_signals_basic/1, + simultaneous_signals_recv/1, + simultaneous_signals_exit/1, + simultaneous_signals_recv_exit/1]). + +-export([spawn_spammers/3]). init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{testcase, Func}|Config]. -end_per_testcase(_Func, _Config) -> - ok. +end_per_testcase(_Func, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). init_per_suite(Config) -> Config. @@ -71,15 +90,41 @@ all() -> busy_dist_down_signal, busy_dist_spawn_reply_signal, busy_dist_unlink_ack_signal, - unlink_exit]. + unlink_exit, + monitor_order, + monitor_named_order_local, + monitor_named_order_remote, + monitor_nodes_order, + {group, adjust_message_queue}]. + +groups() -> + [{adjust_message_queue, [], + [move_msgs_off_heap_signal_basic, + move_msgs_off_heap_signal_recv, + move_msgs_off_heap_signal_exit, + move_msgs_off_heap_signal_recv_exit, + copy_literal_area_signal_basic, + copy_literal_area_signal_recv, + copy_literal_area_signal_exit, + copy_literal_area_signal_recv_exit, + simultaneous_signals_basic, + simultaneous_signals_recv, + simultaneous_signals_exit, + simultaneous_signals_recv_exit]}]. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. %% Test that exit signals and messages are received in correct order xm_sig_order(Config) when is_list(Config) -> LNode = node(), - repeat(fun () -> xm_sig_order_test(LNode) end, 1000), - {ok, RNode} = start_node(Config), - repeat(fun () -> xm_sig_order_test(RNode) end, 1000), - stop_node(RNode), + repeat(fun (_) -> xm_sig_order_test(LNode) end, 1000), + {ok, Peer, RNode} = ?CT_PEER(), + repeat(fun (_) -> xm_sig_order_test(RNode) end, 1000), + peer:stop(Peer), ok. xm_sig_order_test(Node) -> @@ -108,10 +153,9 @@ xm_sig_order_proc() -> kill2killed(Config) when is_list(Config) -> process_flag(trap_exit, true), kill2killed_test(node()), - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), kill2killed_test(Node), - stop_node(Node), - ok. + peer:stop(Peer). kill2killed_test(Node) -> if Node == node() -> @@ -336,17 +380,24 @@ move_dirty_signal_handlers_to_first_scheduler() -> ok. busy_dist_exit_signal(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), + BusyTime = 1000, - {ok, BusyChannelNode} = start_node(Config), - {ok, OtherNode} = start_node(Config, "-proto_dist gen_tcp"), + {ok, BusyChannelPeer, BusyChannelNode} = ?CT_PEER(), + {ok, OtherPeer, OtherNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), Tester = self(), - Exiter = spawn(BusyChannelNode, - fun () -> - pong = net_adm:ping(OtherNode), - Tester ! {self(), alive}, - receive after infinity -> ok end - end), - receive {Exiter, alive} -> ok end, + {Exiter,MRef} = spawn_monitor(BusyChannelNode, + fun () -> + pong = net_adm:ping(OtherNode), + Tester ! {self(), alive}, + receive after infinity -> ok end + end), + receive + {Exiter, alive} -> + erlang:demonitor(MRef, [flush]); + {'DOWN', MRef, process, Why, normal} -> + ct:fail({exiter_died, Why}) + end, Linker = spawn_link(OtherNode, fun () -> process_flag(trap_exit, true), @@ -359,7 +410,7 @@ busy_dist_exit_signal(Config) when is_list(Config) -> exit({unexpected_message, Unexpected}) end end), - make_busy(BusyChannelNode, OtherNode, 1000), + make_busy(BusyChannelNode, OtherNode, BusyTime), exit(Exiter, tester_killed_me), receive {Linker, got_exiter_exit_message} -> @@ -369,14 +420,16 @@ busy_dist_exit_signal(Config) when is_list(Config) -> BusyTime*2 -> ct:fail(missing_exit_signal) end, - stop_node(BusyChannelNode), - stop_node(OtherNode), + peer:stop(BusyChannelPeer), + peer:stop(OtherPeer), ok. busy_dist_demonitor_signal(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), + BusyTime = 1000, - {ok, BusyChannelNode} = start_node(Config), - {ok, OtherNode} = start_node(Config, "-proto_dist gen_tcp"), + {ok, BusyChannelPeer, BusyChannelNode} = ?CT_PEER(), + {ok, OtherPeer, OtherNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), Tester = self(), Demonitorer = spawn(BusyChannelNode, fun () -> @@ -408,7 +461,7 @@ busy_dist_demonitor_signal(Config) when is_list(Config) -> end), Demonitorer ! {self(), monitor, Demonitoree}, receive {Demonitoree, monitored} -> ok end, - make_busy(BusyChannelNode, OtherNode, 1000), + make_busy(BusyChannelNode, OtherNode, BusyTime), exit(Demonitorer, tester_killed_me), receive {Demonitoree, got_demonitorer_demonitor_signal} -> @@ -418,22 +471,29 @@ busy_dist_demonitor_signal(Config) when is_list(Config) -> BusyTime*2 -> ct:fail(missing_demonitor_signal) end, - stop_node(BusyChannelNode), - stop_node(OtherNode), + peer:stop(BusyChannelPeer), + peer:stop(OtherPeer), ok. busy_dist_down_signal(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), + BusyTime = 1000, - {ok, BusyChannelNode} = start_node(Config), - {ok, OtherNode} = start_node(Config, "-proto_dist gen_tcp"), + {ok, BusyChannelPeer, BusyChannelNode} = ?CT_PEER(), + {ok, OtherPeer, OtherNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), Tester = self(), - Exiter = spawn(BusyChannelNode, - fun () -> - pong = net_adm:ping(OtherNode), - Tester ! {self(), alive}, - receive after infinity -> ok end - end), - receive {Exiter, alive} -> ok end, + {Exiter,MRef} = spawn_monitor(BusyChannelNode, + fun () -> + pong = net_adm:ping(OtherNode), + Tester ! {self(), alive}, + receive after infinity -> ok end + end), + receive + {Exiter, alive} -> + erlang:demonitor(MRef, [flush]); + {'DOWN', MRef, process, Why, normal} -> + ct:fail({exiter_died, Why}) + end, Monitorer = spawn_link(OtherNode, fun () -> process_flag(trap_exit, true), @@ -446,7 +506,7 @@ busy_dist_down_signal(Config) when is_list(Config) -> exit({unexpected_message, Unexpected}) end end), - make_busy(BusyChannelNode, OtherNode, 1000), + make_busy(BusyChannelNode, OtherNode, BusyTime), exit(Exiter, tester_killed_me), receive {Monitorer, got_exiter_down_message} -> @@ -456,14 +516,16 @@ busy_dist_down_signal(Config) when is_list(Config) -> BusyTime*2 -> ct:fail(missing_down_signal) end, - stop_node(BusyChannelNode), - stop_node(OtherNode), + peer:stop(BusyChannelPeer), + peer:stop(OtherPeer), ok. busy_dist_spawn_reply_signal(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), + BusyTime = 1000, - {ok, BusyChannelNode} = start_node(Config), - {ok, OtherNode} = start_node(Config, "-proto_dist gen_tcp"), + {ok, BusyChannelPeer, BusyChannelNode} = ?CT_PEER(), + {ok, OtherPeer, OtherNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), Tester = self(), Spawner = spawn_link(OtherNode, fun () -> @@ -482,7 +544,7 @@ busy_dist_spawn_reply_signal(Config) when is_list(Config) -> end end), receive {Spawner, ready} -> ok end, - make_busy(BusyChannelNode, OtherNode, 1000), + make_busy(BusyChannelNode, OtherNode, BusyTime), Spawner ! {self(), go}, receive {Spawner, got_spawn_reply_message} -> @@ -492,8 +554,8 @@ busy_dist_spawn_reply_signal(Config) when is_list(Config) -> BusyTime*2 -> ct:fail(missing_spawn_reply_signal) end, - stop_node(BusyChannelNode), - stop_node(OtherNode), + peer:stop(BusyChannelPeer), + peer:stop(OtherPeer), ok. -record(erl_link, {type, % process | port | dist_process @@ -502,17 +564,24 @@ busy_dist_spawn_reply_signal(Config) when is_list(Config) -> id}). busy_dist_unlink_ack_signal(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), + BusyTime = 1000, - {ok, BusyChannelNode} = start_node(Config), - {ok, OtherNode} = start_node(Config, "-proto_dist gen_tcp"), + {ok, BusyChannelPeer, BusyChannelNode} = ?CT_PEER(), + {ok, OtherPeer, OtherNode} = ?CT_PEER(["-proto_dist", "gen_tcp"]), Tester = self(), - Unlinkee = spawn(BusyChannelNode, - fun () -> - pong = net_adm:ping(OtherNode), - Tester ! {self(), alive}, - receive after infinity -> ok end - end), - receive {Unlinkee, alive} -> ok end, + {Unlinkee,MRef} = spawn_monitor(BusyChannelNode, + fun () -> + pong = net_adm:ping(OtherNode), + Tester ! {self(), alive}, + receive after infinity -> ok end + end), + receive + {Unlinkee, alive} -> + erlang:demonitor(MRef, [flush]); + {'DOWN', MRef, process, Why, normal} -> + ct:fail({unlinkee_died, Why}) + end, Unlinker = spawn_link(OtherNode, fun () -> erts_debug:set_internal_state(available_internal_state, true), @@ -535,7 +604,7 @@ busy_dist_unlink_ack_signal(Config) when is_list(Config) -> Tester ! {self(), got_unlink_ack_signal} end), receive {Unlinker, ready} -> ok end, - make_busy(BusyChannelNode, OtherNode, 1000), + make_busy(BusyChannelNode, OtherNode, BusyTime), Unlinker ! {self(), go}, receive {Unlinker, got_unlink_ack_signal} -> @@ -545,10 +614,10 @@ busy_dist_unlink_ack_signal(Config) when is_list(Config) -> BusyTime*2 -> ct:fail(missing_unlink_ack_signal) end, - stop_node(BusyChannelNode), - stop_node(OtherNode), + peer:stop(BusyChannelPeer), + peer:stop(OtherPeer), ok. - + unlink_exit(Config) when is_list(Config) -> %% OTP-18177 %% @@ -645,10 +714,430 @@ unlink_exit_test() -> ct:fail(ChildReason) end. +%% Monitors could be reordered relative to message signals when the parallel +%% signal sending optimization was active. +monitor_order(_Config) -> + process_flag(message_queue_data, off_heap), + monitor_order_1(10). + +monitor_order_1(0) -> + ok; +monitor_order_1(N) -> + Self = self(), + {Pid, MRef} = spawn_monitor(fun() -> + receive + MRef -> + %% The first message sets up + %% the parallel signal buffer, + %% the second uses it. + Self ! {self(), MRef, first}, + Self ! {self(), MRef, second} + end, + exit(normal) + end), + Pid ! MRef, + receive + {'DOWN', MRef, process, _, normal} -> + ct:fail("Down signal arrived before second message!"); + {Pid, MRef, second} -> + receive {Pid, MRef, first} -> ok end, + erlang:demonitor(MRef, [flush]), + monitor_order_1(N - 1) + end. + +%% Signal order: Message vs DOWN from local process monitored by name. +monitor_named_order_local(_Config) -> + process_flag(message_queue_data, off_heap), + erts_debug:set_internal_state(available_internal_state, true), + true = erts_debug:set_internal_state(proc_sig_buffers, true), + + LNode = node(), + repeat(fun (N) -> monitor_named_order(LNode, N) end, 100), + ok. + +%% Signal order: Message vs DOWN from remote process monitored by name. +monitor_named_order_remote(_Config) -> + process_flag(message_queue_data, off_heap), + erts_debug:set_internal_state(available_internal_state, true), + true = erts_debug:set_internal_state(proc_sig_buffers, true), + + {ok, Peer, RNode} = ?CT_PEER(), + repeat(fun (N) -> monitor_named_order(RNode, N) end, 10), + peer:stop(Peer), + ok. + +monitor_named_order(Node, N) -> + %% Send messages using pid, name and alias. + Pid = self(), + register(tester, Pid), + Name = {tester, node()}, + AliasA = alias(), + NumMsg = 1000 + N, + Sender = spawn_link(Node, + fun() -> + register(monitor_named_order, self()), + Pid ! {self(), ready}, + {go, AliasM} = receive_any(), + send_msg_seq(Pid, Name, AliasA, AliasM, NumMsg), + exit(normal) + end), + {Sender, ready} = receive_any(), + AliasM = monitor(process, {monitor_named_order,Node}, + [{alias,explicit_unalias}]), + Sender ! {go, AliasM}, + recv_msg_seq(NumMsg), + {'DOWN', AliasM, process, {monitor_named_order,Node}, normal} + = receive_any(), + unregister(tester), + unalias(AliasA), + unalias(AliasM), + ok. + +send_msg_seq(_, _, _, _, 0) -> ok; +send_msg_seq(To1, To2, To3, To4, N) -> + To1 ! N, + send_msg_seq(To2, To3, To4, To1, N-1). + +recv_msg_seq(0) -> ok; +recv_msg_seq(N) -> + N = receive M -> M end, + recv_msg_seq(N-1). + +receive_any() -> + receive M -> M end. + +receive_any(Timeout) -> + receive M -> M + after Timeout -> timeout + end. + +monitor_nodes_order(_Config) -> + process_flag(message_queue_data, off_heap), + erts_debug:set_internal_state(available_internal_state, true), + true = erts_debug:set_internal_state(proc_sig_buffers, true), + + {ok, Peer, RNode} = ?CT_PEER(#{peer_down => continue, + connection => 0}), + Self = self(), + ok = net_kernel:monitor_nodes(true, [nodedown_reason]), + [] = nodes(connected), + Pids = peer:call(Peer, ?MODULE, spawn_spammers, [64, Self, []]), + {nodeup, RNode, []} = receive_any(), + + ok = peer:cast(Peer, erlang, halt, [0]), + + [put(P, 0) || P <- Pids], % spam counters per sender + {nodedown, RNode, [{nodedown_reason,connection_closed}]} = + receive_filter_spam(), + [io:format("From spammer ~p: ~p messages\n", [P, get(P)]) || P <- Pids], + timeout = receive_any(100), % Nothing after nodedown + + {down, tcp_closed} = peer:get_state(Peer), + peer:stop(Peer), + ok. + +spawn_spammers(0, _To, Acc) -> + Acc; +spawn_spammers(N, To, Acc) -> + Pid = spawn(fun() -> spam_pid(To, 1) end), + spawn_spammers(N-1, To, [Pid | Acc]). + +spam_pid(To, N) -> + To ! {spam, self(), N}, + erlang:yield(), % Let other spammers run to get lots of different senders + spam_pid(To, N+1). + +receive_filter_spam() -> + receive + {spam, From, N} -> + match(N, get(From) + 1), + put(From, N), + receive_filter_spam(); + M -> M + end. + +move_msgs_off_heap_signal_basic(Config) when is_list(Config) -> + move_msgs_off_heap_signal_test(false, false). + +move_msgs_off_heap_signal_recv(Config) when is_list(Config) -> + move_msgs_off_heap_signal_test(true, false). + +move_msgs_off_heap_signal_exit(Config) when is_list(Config) -> + move_msgs_off_heap_signal_test(false, true). + +move_msgs_off_heap_signal_recv_exit(Config) when is_list(Config) -> + move_msgs_off_heap_signal_test(true, true). + +move_msgs_off_heap_signal_test(RecvPair, Exit) -> + erlang:trace(new_processes, true, [running_procs]), + SFact = test_server:timetrap_scale_factor(), + GoTime = erlang:monotonic_time(millisecond) + 1000*SFact, + ProcF = fun () -> + Now = erlang:monotonic_time(millisecond), + Tmo = case GoTime - Now of + Left when Left < 0 -> + erlang:display({go_time_passed, Left}), + 0; + Left -> + Left + end, + receive after Tmo -> ok end, + on_heap = process_flag(message_queue_data, off_heap), + if RecvPair -> receive_integer_pairs(infinity); + true -> receive after infinity -> ok end + end + end, + Ps = lists:map(fun (_) -> + spawn_opt(ProcF, + [link, + {message_queue_data, on_heap}]) + end, lists:seq(1, 100)), + lists:foreach(fun (P) -> + lists:foreach(fun (N) when N rem 100 == 0 -> + P ! [N|N]; + (N) -> + P ! N + end, lists:seq(1, 10000)) + end, Ps), + Now = erlang:monotonic_time(millisecond), + Tmo = case GoTime - Now + 10 of + Left when Left < 0 -> + erlang:display({go_time_passed, Left}), + 0; + Left -> + Left + end, + receive after Tmo -> ok end, + if Exit -> + _ = lists:foldl(fun (P, N) when N rem 10 -> + unlink(P), + exit(P, terminated), + N+1; + (_P, N) -> + N+1 + end, + 0, + Ps), + ok; + true -> + ok + end, + wait_traced_not_running(1000 + 200*SFact), + erlang:trace(new_processes, false, [running_procs]), + lists:foreach(fun (P) -> + unlink(P), + exit(P, kill) + end, Ps), + lists:foreach(fun (P) -> + false = is_process_alive(P) + end, Ps), + ok. + +copy_literal_area_signal_basic(Config) when is_list(Config) -> + copy_literal_area_signal_test(false, false). + +copy_literal_area_signal_recv(Config) when is_list(Config) -> + copy_literal_area_signal_test(true, false). + +copy_literal_area_signal_exit(Config) when is_list(Config) -> + copy_literal_area_signal_test(false, true). + +copy_literal_area_signal_recv_exit(Config) when is_list(Config) -> + copy_literal_area_signal_test(true, true). + +copy_literal_area_signal_test(RecvPair, Exit) -> + persistent_term:put({?MODULE, ?FUNCTION_NAME}, make_ref()), + Literal = persistent_term:get({?MODULE, ?FUNCTION_NAME}), + true = is_reference(Literal), + 0 = erts_debug:size_shared(Literal), %% Should be a literal... + ProcF = fun () -> + 0 = erts_debug:size_shared(Literal), %% Should be a literal... + if RecvPair -> + receive receive_pairs -> ok end, + receive_integer_pairs(0); + true -> + ok + end, + receive check_literal_conversion -> ok end, + receive + Literal -> + %% Should not be a literal anymore... + false = (0 == erts_debug:size_shared(Literal)) + end + end, + PMs = lists:map(fun (_) -> + spawn_opt(ProcF, [link, monitor]) + end, lists:seq(1, 100)), + lists:foreach(fun ({P,_M}) -> + lists:foreach(fun (N) when N rem 100 == 0 -> + P ! [N|N]; + (N) -> + P ! N + end, lists:seq(1, 10000)), + P ! Literal + end, PMs), + persistent_term:erase({?MODULE, ?FUNCTION_NAME}), + receive after 1 -> ok end, + if RecvPair -> + lists:foreach(fun ({P,_M}) -> + P ! receive_pairs + end, PMs); + true -> + ok + end, + if Exit -> + _ = lists:foldl(fun ({P, _M}, N) when N rem 10 -> + unlink(P), + exit(P, terminated), + N+1; + (_PM, N) -> + N+1 + end, + 0, + PMs), + ok; + true -> + ok + end, + literal_area_collector_test:check_idle(), + lists:foreach(fun ({P,_M}) -> + P ! check_literal_conversion + end, PMs), + lists:foreach(fun ({P, M}) -> + receive + {'DOWN', M, process, P, R} -> + case R of + normal -> ok; + terminated -> ok + end + end + end, PMs), + ok. + +simultaneous_signals_basic(Config) when is_list(Config) -> + simultaneous_signals_test(false, false). + +simultaneous_signals_recv(Config) when is_list(Config) -> + simultaneous_signals_test(true, false). + +simultaneous_signals_exit(Config) when is_list(Config) -> + simultaneous_signals_test(false, true). + +simultaneous_signals_recv_exit(Config) when is_list(Config) -> + simultaneous_signals_test(true, true). + +simultaneous_signals_test(RecvPairs, Exit) -> + erlang:trace(new_processes, true, [running_procs]), + persistent_term:put({?MODULE, ?FUNCTION_NAME}, make_ref()), + Literal = persistent_term:get({?MODULE, ?FUNCTION_NAME}), + true = is_reference(Literal), + 0 = erts_debug:size_shared(Literal), %% Should be a literal... + SFact = test_server:timetrap_scale_factor(), + GoTime = erlang:monotonic_time(millisecond) + 1000*SFact, + ProcF = fun () -> + 0 = erts_debug:size_shared(Literal), %% Should be a literal... + Now = erlang:monotonic_time(millisecond), + Tmo = case GoTime - Now of + Left when Left < 0 -> + erlang:display({go_time_passed, Left}), + 0; + Left -> + Left + end, + receive after Tmo -> ok end, + on_heap = process_flag(message_queue_data, off_heap), + if RecvPairs -> receive_integer_pairs(0); + true -> ok + end, + receive check_literal_conversion -> ok end, + receive + Literal -> + %% Should not be a literal anymore... + false = (0 == erts_debug:size_shared(Literal)) + end + end, + PMs = lists:map(fun (_) -> + spawn_opt(ProcF, + [link, + monitor, + {message_queue_data, on_heap}]) + end, lists:seq(1, 100)), + lists:foreach(fun ({P,_M}) -> + lists:foreach(fun (N) when N rem 100 == 0 -> + P ! [N|N]; + (N) -> + P ! N + end, lists:seq(1, 10000)), + P ! Literal + end, PMs), + Now = erlang:monotonic_time(millisecond), + Tmo = case GoTime - Now - 5 of % a bit earlier... + Left when Left < 0 -> + erlang:display({go_time_passed, Left}), + 0; + Left -> + Left + end, + receive after Tmo -> ok end, + persistent_term:erase({?MODULE, ?FUNCTION_NAME}), + receive after 10 -> ok end, + if Exit -> + _ = lists:foldl(fun ({P, _M}, N) when N rem 10 -> + unlink(P), + exit(P, terminated), + N+1; + (_PM, N) -> + N+1 + end, + 0, + PMs), + ok; + true -> + ok + end, + wait_traced_not_running(1000 + 200*SFact), + erlang:trace(new_processes, false, [running_procs]), + literal_area_collector_test:check_idle(), + lists:foreach(fun ({P,_M}) -> + P ! check_literal_conversion + end, PMs), + lists:foreach(fun ({P, M}) -> + receive + {'DOWN', M, process, P, R} -> + case R of + normal -> ok; + terminated -> ok + end + end + end, PMs), + ok. + + +wait_traced_not_running(Tmo) -> + receive + {trace,_,What,_} when What == in; + What == out -> + wait_traced_not_running(Tmo) + after + Tmo -> + ok + end. + +receive_integer_pairs(Tmo) -> + receive + [N|N] -> + receive_integer_pairs(Tmo) + after + Tmo -> + ok + end. + %% %% -- Internal utils -------------------------------------------------------- %% +match(X,X) -> ok. + load_driver(Config, Driver) -> DataDir = proplists:get_value(data_dir, Config), case erl_ddll:load_driver(DataDir, Driver) of @@ -764,8 +1253,11 @@ spam(To, Data) -> repeat(_Fun, N) when is_integer(N), N =< 0 -> ok; -repeat(Fun, N) when is_integer(N) -> +repeat(Fun, N) when is_function(Fun, 0), is_integer(N) -> Fun(), + repeat(Fun, N-1); +repeat(Fun, N) when is_function(Fun, 1), is_integer(N) -> + Fun(N), repeat(Fun, N-1). busy_wait_until(Fun) -> @@ -773,17 +1265,3 @@ busy_wait_until(Fun) -> true -> ok; _ -> busy_wait_until(Fun) end. - -start_node(Config, Args) -> - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" ++ integer_to_list(erlang:system_time(second)) - ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))), - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, slave, [{args, "-pa " ++ Pa ++ " " ++ Args}]). - -start_node(Config) -> - start_node(Config, ""). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/small_SUITE.erl b/erts/emulator/test/small_SUITE.erl index cbd40042b90a..7d49522f0592 100644 --- a/erts/emulator/test/small_SUITE.erl +++ b/erts/emulator/test/small_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2019-2021. All Rights Reserved. +%% Copyright Ericsson AB 2019-2023. 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. @@ -19,8 +19,14 @@ %% -module(small_SUITE). --export([all/0, suite/0]). --export([edge_cases/1]). +-include_lib("syntax_tools/include/merl.hrl"). + +-export([all/0, suite/0, groups/0]). +-export([edge_cases/1, + addition/1, subtraction/1, negation/1, multiplication/1, division/1, + test_bitwise/1, test_bsl/1, + element/1, + range_optimization/1]). -include_lib("common_test/include/ct.hrl"). @@ -29,7 +35,15 @@ suite() -> {timetrap, {minutes, 1}}]. all() -> - [edge_cases]. + [{group, p}]. + +groups() -> + [{p, [parallel], + [edge_cases, + addition, subtraction, negation, multiplication, division, + test_bitwise, test_bsl, + element, + range_optimization]}]. edge_cases(Config) when is_list(Config) -> {MinSmall, MaxSmall} = Limits = determine_small_limits(0), @@ -111,6 +125,1066 @@ arith_test_1(A, B, MinS, MaxS) -> ok. +%% Test that the JIT only omits the overflow check when it's safe. +addition(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = add_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_add_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_addition(Fs0, Mod), + ok. + +add_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + Seq = lists:seq(MinSmall-3, MinSmall+2) ++ + lists:seq(-5, 5), + lists:seq(MaxSmall-2, MaxSmall+2), + [{N1, N2} || N1 <- Seq, N2 <- Seq] ++ Pairs0. + +gen_add_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(integer, X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 + Y0, + Res = X1 + Y1, + Res = Y1 + X1, + Res = X0 + Y1, + Res = X1 + Y0; + '@Name@'(number0, X, Y) when is_number(X), is_number(Y), + X < _@APlusOne@, 0 =< Y, Y < _@BPlusOne@ -> + Res = X + Y, + Res = Y + X; + '@Name@'(number0, X, Y) when is_number(X), is_number(Y), + X < _@APlusOne@, -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Res = X + Y, + Res = Y + X; + '@Name@'(number1, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, 0 =< Y, Y < _@BPlusOne@ -> + Res = X + Y, + Res = Y + X; + '@Name@'(number1, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Res = X + Y, + Res = Y + X; + '@Name@'(number1, X, Y) when X > -_@APlusOne@, Y > -_@BPlusOne@ -> + Res = X + Y, + Res = Y + X. "). + +test_addition([{Name,{A,B}}|T], Mod) -> + F = fun Mod:Name/3, + try + Res0 = A + B, + Res0 = F(integer, A, B), + Res0 = F(number0, A, B), + Res0 = F(number1, A, B), + + Res1 = -A + B, + Res1 = F(integer, -A, B), + Res1 = F(number0, -A, B), + Res1 = F(number1, -A, B), + + Res2 = A + (-B), + Res2 = F(integer, A, -B), + Res2 = F(number0, A, -B), + Res2 = F(number1, A, -B), + + Res3 = -A + (-B), + Res3 = F(integer, -A, -B), + Res3 = F(number0, -A, -B), + Res3 = F(number1, -A, -B), + + AbsB = abs(B), + Res4 = A + AbsB, + Res4 = F(number0, A, AbsB), + Res4 = F(number1, A, AbsB) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + bad_arith(F, [a], B), + bad_arith(F, aa, B), + bad_arith(F, A, [b]), + bad_arith(F, A, bb), + bad_arith(F, {a,b}, {c,d}), + + test_addition(T, Mod); +test_addition([], _) -> + ok. + +bad_arith(F, A, B) -> + {'EXIT',{badarith,_}} = catch F(number1, A, B), + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +subtraction(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = sub_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_sub_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_subtraction(Fs0, Mod), + ok. + +sub_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), M - rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + [{N1, N2} || + N1 <- lists:seq(MinSmall-2, MinSmall+2), + N2 <- lists:seq(MaxSmall-2, MaxSmall+2)] ++ Pairs0. + +gen_sub_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(integer, X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 - Y0, + Res = X1 - Y1, + Res = X0 - Y1, + Res = X1 - Y0; + '@Name@'(number0, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, 0 =< Y, Y < _@BPlusOne@ -> + X - Y; + '@Name@'(number0, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + X - Y; + '@Name@'(number1, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, 0 =< Y, Y < _@BPlusOne@ -> + X - Y; + '@Name@'(number1, X, Y) when is_number(X), is_number(Y), + X > -_@APlusOne@, -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + X - Y; + '@Name@'(number1, X, Y) when X > -_@APlusOne@, Y > -_@BPlusOne@ -> + X - Y. "). + +test_subtraction([{Name,{A,B}}|T], Mod) -> + F = fun Mod:Name/3, + try + Res0 = A - B, + Res0 = F(integer, A, B), + Res0 = F(number0, A, B), + + Res1 = -A - B, + Res1 = F(integer, -A, B), + Res1 = F(number0, -A, B), + + Res2 = A - (-B), + Res2 = F(integer, A, -B), + Res2 = F(number0, A, -B), + + Res3 = -A - (-B), + Res3 = F(integer, -A, -B), + Res3 = F(number0, -A, -B), + + AbsB = abs(B), + Res4 = A - AbsB, + Res4 = F(integer, A, AbsB), + Res4 = F(number0, A, AbsB) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + bad_arith(F, [a], B), + bad_arith(F, aa, B), + bad_arith(F, A, [b]), + bad_arith(F, A, bb), + bad_arith(F, {a,b}, {c,d}), + + test_subtraction(T, Mod); +test_subtraction([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +negation(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Integers = neg_gen_integers(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Integers, 0), + Fs = [gen_neg_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_negation(Fs0, Mod), + ok. + +neg_gen_integers() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + N = 1000, + M = MaxSmall + N div 2, + Ns = [M - rand:uniform(N) || _ <- lists:seq(1, 75)], + + lists:seq(MinSmall-2, MinSmall+2) ++ lists:seq(MaxSmall-2, MaxSmall+2) ++ Ns. + +gen_neg_function({Name,A}) -> + APlusOne = abs(A) + 1, + ?Q("'@Name@'(integer0, X0) when is_integer(X0) -> + X1 = X0 rem _@APlusOne@, + Res = -X0, + Res = -X1; + '@Name@'(integer1, X) when is_integer(X), X > -_@APlusOne@ -> + -X; + '@Name@'(integer2, X) when is_integer(X), X > -_@APlusOne@ -> + -X; + '@Name@'(number, X) when is_number(X), X > -_@APlusOne@ -> + -X; + '@Name@'(number, X) when is_number(X), X > -_@APlusOne@ -> + -X; + '@Name@'(number, X) when is_number(X) -> + -X. "). + +test_negation([{Name,A}|T], Mod) -> + F = fun Mod:Name/2, + try + Res0 = -A, + Res0 = F(integer0, A), + Res0 = F(integer1, A), + Res0 = F(integer2, A), + Res0 = F(number, A), + + Res1 = A, + Res1 = F(integer0, -A), + Res1 = F(integer1, -A), + Res1 = F(integer2, -A), + Res1 = F(number, -A) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p\n", [Name,A]), + erlang:raise(C, R, Stk) + end, + + test_negation(T, Mod); +test_negation([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +multiplication(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = mul_gen_pairs(), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_mul_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_multiplication(Fs0, Mod), + ok. + +mul_gen_pairs() -> + {_, MaxSmall} = determine_small_limits(0), + NumBitsMaxSmall = num_bits(MaxSmall), + + %% Generate random pairs of smalls. + Pairs0 = [{rand:uniform(MaxSmall),rand:uniform(MaxSmall)} || + _ <- lists:seq(1, 75)], + + %% Generate pairs of numbers whose product is small. + Pairs1 = [{N, MaxSmall div N} || N <- [1,2,3,5,17,63,64,1111,22222]] ++ Pairs0, + + %% Add prime factors of 2^59 - 1 (MAX_SMALL for 64-bit architecture + %% at the time of writing). + Pairs2 = [{179951,3203431780337}|Pairs1], + + %% Generate pairs of numbers whose product are bignums. + LeastBig = MaxSmall + 1, + Divisors = [(1 bsl Pow) + Offset || + Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1), + Offset <- [0,1,17,20333]], + [{Div,ceil(LeastBig / Div)} || Div <- Divisors] ++ Pairs2. + +gen_mul_function({Name,{A,B}}) -> + APlusOne = A + 1, + BPlusOne = B + 1, + NumBitsA = num_bits(A), + NumBitsB = num_bits(B), + ?Q("'@Name@'(X0, Y0, More) when is_integer(X0), is_integer(Y0), is_boolean(More) -> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + Res = X0 * Y0, + Res = X1 * Y1, + Res = Y1 * X1, + if More -> + Res = X1 * _@B@, + Res = _@A@ * Y1, + <> = <>, + <> = <>, + Res = X2 * Y2, + Res = X1 * Y2, + Res = X2 * Y1; + true -> + Res + end; + '@Name@'(X, Y, number) when -_@APlusOne@ < X, X < _@APlusOne@, -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Res = X * Y, + Res = Y * X; + '@Name@'(X, fixed, number) when -_@APlusOne@ < X, X < _@APlusOne@ -> + X * _@B@; + '@Name@'(fixed, Y, number) when -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + _@A@ * Y. "). + +test_multiplication([{Name,{A,B}}|T], Mod) -> + F = fun Mod:Name/3, + try + Res0 = A * B, + %% io:format("~p * ~p = ~p; size = ~p\n", + %% [A,B,Res0,erts_debug:flat_size(Res0)]), + + Res0 = F(A, B, true), + Res0 = F(-A, -B, false), + Res0 = F(A, B, number), + Res0 = F(fixed, B, number), + Res0 = F(A, fixed, number), + Res0 = F(-A, -B, number), + + Res1 = -(A * B), + Res1 = F(-A, B, false), + Res1 = F(A, -B, false), + Res1 = F(-A, B, number), + Res1 = F(A, -B, number), + Res1 = F(-A, fixed, number), + Res1 = F(fixed, -B, number) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_multiplication(T, Mod); +test_multiplication([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +division(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = div_gen_pairs(), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_div_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_division(Fs0, Mod), + + 3 = ignore_rem(ignore, 10, 3), + 1 = ignore_div(ignore, 16, 5), + + ok. + +ignore_rem(_, X, Y) -> + _ = X rem Y, %Result in x0. + X div Y. %Reuse x0 for result. + +ignore_div(_, X, Y) -> + _ = X div Y, %Result in x0. + X rem Y. %Reuse x0 for result. + +div_gen_pairs() -> + {_, MaxSmall} = determine_small_limits(0), + NumBitsMaxSmall = num_bits(MaxSmall), + + Divisors = [-8,-2,-1,1,2,3,4,5,8,16,17,64,22222333] ++ + [1 bsl P || P <- lists:seq(8, 12) ++ lists:seq(26, 36)], + + %% Generate random pairs of smalls. + Pairs0 = [{rand:uniform(MaxSmall), + rand:uniform(MaxSmall) * rand_sign()} || + _ <- lists:seq(1, 50)], + Pairs1 = [{rand:uniform(MaxSmall), N} || N <- Divisors] ++ Pairs0, + Pairs2 = [{N, M} || N <- lists:seq(0, 7), M <- [-2,-1,1,2,3,4]] ++ Pairs1, + Pairs3 = [{abs(M) * (rand:uniform(10)+1) + rand:uniform(1000), M} || + M <- Divisors] ++ Pairs2, + + %% Generate pairs of numbers whose product are bignums. + [{rand:uniform(MaxSmall),1 bsl Pow} || + Pow <- lists:seq(NumBitsMaxSmall - 4, NumBitsMaxSmall - 1)] ++ Pairs3. + +rand_sign() -> + case rand:uniform() < 0.2 of + true -> -1; + false -> 1 + end. + +gen_div_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + NumBitsA = num_bits(abs(A)+1), + NumBitsB = num_bits(abs(B)+1), + ?Q("'@Name@'(integer0, X0, Y0) -> + Q = X0 div Y0, + R = X0 rem Y0, + if X0 > 0, Y0 > 0 -> + <> = <>, + <> = <>, + Q = X div Y, + R = X rem Y, + {Q, R}; + true -> + {Q, R} + end; + '@Name@'(integer1, X, fixed) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(integer2, X, fixed) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(integer3, X, fixed) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(pos_integer1, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(pos_integer2, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(pos_integer3, X, fixed) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(number0, X, Y) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(number1, X, Y) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(number2, X, fixed) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(number3, X, fixed) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(number4, X, fixed) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(any0, X, fixed) -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(any1, X, fixed) -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(any2, X, fixed) -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(X0, Y0, integer0) -> + Q = X0 div Y0, + R = X0 rem Y0, + if X0 > 0, Y0 > 0 -> + <> = <>, + <> = <>, + Q = X div Y, + R = X rem Y, + {Q, R}; + true -> + {Q, R} + end; + '@Name@'(X, fixed, integer1) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, integer2) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(X, fixed, integer3) when is_integer(X), -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, pos_integer1) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, pos_integer2) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(X, fixed, pos_integer3) when is_integer(X), 0 =< X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(X, Y, number0) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(X, Y, number1) when -_@APlusOne@ < X, X < _@APlusOne@, + -_@BPlusOne@ < Y, Y < _@BPlusOne@ -> + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(X, fixed, number2) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, number3) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(X, fixed, number4) when -_@APlusOne@ < X, X < _@APlusOne@ -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, any0) -> + Y = _@B@, + Q = X div Y, + R = X rem Y, + {Q, R}; + '@Name@'(X, fixed, any1) -> + Y = _@B@, + R = X rem Y, + Q = X div Y, + {Q, R}; + '@Name@'(X, fixed, any2) -> + Y = _@B@, + Q = X div Y, + put(prevent_div_rem_fusion, Q), + R = X rem Y, + {Q, R}. "). + +test_division([{Name,{A,B}}|T], Mod) -> + F = fun Mod:Name/3, + try + PosRes = {A div B, A rem B}, + NegRes = {-A div B, -A rem B}, + + PosRes = F(integer0, A, B), + PosRes = F(integer1, A, fixed), + PosRes = F(integer2, A, fixed), + PosRes = F(integer3, A, fixed), + PosRes = F(pos_integer1, A, fixed), + PosRes = F(pos_integer2, A, fixed), + PosRes = F(pos_integer3, A, fixed), + PosRes = F(number0, A, B), + PosRes = F(number1, A, B), + PosRes = F(number2, A, fixed), + PosRes = F(number3, A, fixed), + PosRes = F(number4, A, fixed), + PosRes = F(any0, A, fixed), + PosRes = F(any1, A, fixed), + PosRes = F(any2, A, fixed), + + PosRes = F(A, B, integer0), + PosRes = F(A, fixed, integer1), + PosRes = F(A, fixed, integer2), + PosRes = F(A, fixed, integer3), + PosRes = F(A, fixed, pos_integer1), + PosRes = F(A, fixed, pos_integer2), + PosRes = F(A, fixed, pos_integer3), + PosRes = F(A, B, number0), + PosRes = F(A, B, number1), + PosRes = F(A, fixed, number2), + PosRes = F(A, fixed, number3), + PosRes = F(A, fixed, number4), + PosRes = F(A, fixed, any0), + PosRes = F(A, fixed, any1), + PosRes = F(A, fixed, any2), + + NegRes = F(integer0, -A, B), + NegRes = F(integer1, -A, fixed), + NegRes = F(integer2, -A, fixed), + NegRes = F(integer3, -A, fixed), + NegRes = F(number0, -A, B), + NegRes = F(number1, -A, B), + NegRes = F(number2, -A, fixed), + NegRes = F(number3, -A, fixed), + NegRes = F(number4, -A, fixed), + + NegRes = F(-A, B, integer0), + NegRes = F(-A, fixed, integer1), + NegRes = F(-A, fixed, integer2), + NegRes = F(-A, fixed, integer3), + NegRes = F(-A, B, number0), + NegRes = F(-A, B, number1), + NegRes = F(-A, fixed, number2), + NegRes = F(-A, fixed, number3), + NegRes = F(-A, fixed, number4) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + + test_division(T, Mod); +test_division([], _) -> + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +test_bitwise(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = bitwise_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_bitwise_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_bitwise(Fs0, Mod), + + %% Test invalid operands. + expect_badarith(fun(X) -> 42 band X end), + expect_badarith(fun(X) -> 42 bor X end), + expect_badarith(fun(X) -> 42 bxor X end), + expect_badarith(fun(X) -> X band 42 end), + expect_badarith(fun(X) -> X bor 42 end), + expect_badarith(fun(X) -> X bxor 42 end), + expect_fc(fun(X) when is_integer(42 band X) -> ok end), + expect_fc(fun(X) when is_integer(42 bor X) -> ok end), + expect_fc(fun(X) when is_integer(42 bxor X) -> ok end), + expect_fc(fun(X) when is_integer(X band 42) -> ok end), + expect_fc(fun(X) when is_integer(X bor 42) -> ok end), + expect_fc(fun(X) when is_integer(X bxor 42) -> ok end), + + ok. + +expect_fc(Fun) -> + {'EXIT',{function_clause,_}} = catch Fun(id(bad)), + ok. + +expect_badarith(Fun) -> + {'EXIT',{badarith,_}} = catch Fun(id(bad)), + ok. + +bitwise_gen_pairs() -> + {MinSmall, MaxSmall} = determine_small_limits(0), + + %% Generate random pairs of smalls. + N = 1000, + M = MaxSmall + N div 2, + Pairs0 = [{M - rand:uniform(N), rand:uniform(N)} || + _ <- lists:seq(1, 75)], + + Seq = lists:seq(MinSmall-3, MinSmall+2) ++ + lists:seq(-5, 5), + lists:seq(MaxSmall-2, MaxSmall+2), + [{N1, N2} || N1 <- Seq, N2 <- Seq] ++ Pairs0. + +gen_bitwise_function({Name,{A,B}}) -> + APlusOne = abs(A) + 1, + BPlusOne = abs(B) + 1, + ?Q("'@Name@'(X0, Y0) when is_integer(X0), is_integer(Y0)-> + X1 = X0 rem _@APlusOne@, + Y1 = Y0 rem _@BPlusOne@, + + AndRes = X0 band Y0, + AndRes = Y0 band X0, + AndRes = X1 band Y1, + AndRes = Y1 band X1, + AndRes = X0 band Y1, + AndRes = X1 band Y0, + + OrRes = X0 bor Y0, + OrRes = Y0 bor X0, + OrRes = X1 bor Y1, + OrRes = Y1 bor X1, + OrRes = X0 bor Y1, + OrRes = X1 bor Y0, + + XorRes = X0 bxor Y0, + XorRes = Y0 bxor X0, + XorRes = X1 bxor Y1, + XorRes = Y1 bxor X1, + XorRes = X0 bxor Y1, + XorRes = X1 bxor Y0, + + {AndRes, OrRes, XorRes}; + '@Name@'(X0, fixed) when is_integer(X0) -> + X1 = X0 rem _@APlusOne@, + + AndRes = X0 band _@B@, + AndRes = _@B@ band X0, + AndRes = X1 band _@B@, + AndRes = _@B@ band X1, + + OrRes = X0 bor _@B@, + OrRes = _@B@ bor X0, + OrRes = X1 bor _@B@, + OrRes = _@B@ bor X1, + + XorRes = X0 bxor _@B@, + XorRes = _@B@ bxor X0, + XorRes = X1 bxor _@B@, + XorRes = _@B@ bxor X1, + + {AndRes, OrRes, XorRes}. + "). + +test_bitwise([{Name,{A,B}}|T], Mod) -> + try + test_bitwise_1(A, B, Mod, Name), + test_bitwise_1(-A, B, Mod, Name), + test_bitwise_1(A, -B, Mod, Name), + test_bitwise_1(-A, -B, Mod, Name), + + AndRes = A band B, + OrRes = A bor B, + XorRes = A bxor B, + {AndRes, OrRes, XorRes} = Mod:Name(A, fixed) + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,A,B]), + erlang:raise(C, R, Stk) + end, + test_bitwise(T, Mod); +test_bitwise([], _) -> + ok. + +test_bitwise_1(A, B, Mod, Name) -> + AndRes = A band B, + OrRes = A bor B, + XorRes = A bxor B, + {AndRes, OrRes, XorRes} = Mod:Name(A, B), + ok. + +%% Test that the JIT only omits the overflow check when it's safe. +test_bsl(_Config) -> + _ = rand:uniform(), %Seed generator + io:format("Seed: ~p", [rand:export_seed()]), + Mod = list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME])), + Pairs = bsl_gen_pairs(), + %% io:format("~p\n", [Pairs]), + Fs0 = gen_func_names(Pairs, 0), + Fs = [gen_bsl_function(F) || F <- Fs0], + Tree = ?Q(["-module('@Mod@').", + "-compile([export_all,nowarn_export_all])."]) ++ Fs, + %% merl:print(Tree), + {ok,_Bin} = merl:compile_and_load(Tree, []), + test_bsl(Fs0, Mod), + ok. + +bsl_gen_pairs() -> + {_MinSmall, MaxSmall} = determine_small_limits(0), + SmallBits = num_bits(MaxSmall), + + [{N,S} || + P <- lists:seq(20, SmallBits), + N <- [(1 bsl P)-rand:uniform(1000), (1 bsl P)-1, 1 bsl P], + S <- lists:seq(SmallBits-P-4, SmallBits - P + 3)]. + +gen_bsl_function({Name,{N,S}}) -> + Mask = (1 bsl num_bits(N)) - 1, + ?Q("'@Name@'(N0, fixed) -> + Res = N0 bsl _@S@, + N = N0 band _@Mask@, + Res = N0 bsl _@S@, + Res = N bsl _@S@; + '@Name@'(N0, S) when is_integer(S), 0 =< S, S =< _@S@ -> + Res = N0 bsl S, + N = N0 band _@Mask@, + Res = N0 bsl S, + Res = N bsl S. "). + +test_bsl([{Name,{N,S}}|T], Mod) -> + try + Res0 = N bsl S, + Res0 = Mod:Name(N, fixed), + + if + S >= 0 -> + Res1 = N bsl S, + Res1 = Mod:Name(N, S), + + N = Mod:Name(N, 0), + + if + S >= 2 -> + Res2 = N bsl (S - 1), + Res2 = Mod:Name(N, S - 1), + + Res3 = N bsl (S - 2), + Res3 = Mod:Name(N, S - 2); + true -> + ok + end; + S < 0 -> + {'EXIT', {function_clause,_}} = catch Mod:Name(N, S) + end + catch + C:R:Stk -> + io:format("~p failed. numbers: ~p ~p\n", [Name,N,S]), + erlang:raise(C, R, Stk) + end, + test_bsl(T, Mod); +test_bsl([], _) -> + ok. + +element(_Config) -> + %% Test element_1: Can't fail for integer arguments. + zero = element_1(0), + one = element_1(1), + two = element_1(2), + three = element_1(3), + + three = element_1(3-4), + two = element_1(2-4), + one = element_1(1-4), + zero = element_1(0-4), + + zero = element_1(0+4), + one = element_1(1+4), + + {'EXIT',{badarith,_}} = catch element_1(id(a)), + + %% Test element_2: Test that it fails for 0. + one = element_2(1), + two = element_2(2), + three = element_2(3), + + one = element_2(1+4), + two = element_2(2+4), + three = element_2(3+4), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_2(id(0)), + {'EXIT',{badarith,_}} = catch element_2(id(b)), + + %% Test element_3: Test that if fails for integers less than 1. + one = element_3(1), + two = element_3(2), + three = element_3(3), + + one = element_3(1+4), + two = element_3(2+4), + three = element_3(3+4), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_3(id(0)), + {'EXIT',{badarg,_}} = catch element_3(id(-1)), + {'EXIT',{badarg,_}} = catch element_3(id(-999)), + {'EXIT',{badarith,_}} = catch element_3(id(c)), + + %% Test element_4: Test that it fails for integers outside of the range 1..3. + one = element_4(1), + two = element_4(2), + three = element_4(3), + + one = element_4(1+8), + two = element_4(2+8), + three = element_4(3+8), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_4(id(0)), + {'EXIT',{badarg,[{erlang,element,[5,{one,two,three}],_}|_]}} = + catch element_4(id(5)), + {'EXIT',{badarg,_}} = catch element_4(id(-1)), + {'EXIT',{badarg,[{erlang,element,[-7,{one,two,three}],_}|_]}} = + catch element_4(id(-999)), + {'EXIT',{badarith,_}} = catch element_4(id(d)), + + %% Test element_5: Test that it fails for integers outside of the + %% range 0..3. + zero = element_5(0), + one = element_5(1), + two = element_5(2), + three = element_5(3), + + zero = element_5(0+8), + one = element_5(1+8), + two = element_5(2+8), + three = element_5(3+8), + + {'EXIT',{badarg,[{erlang,element,[5,{zero,one,two,three}],_}|_]}} = + catch element_5(id(4)), + {'EXIT',{badarg,[{erlang,element,[0,{zero,one,two,three}],_}|_]}} = + catch element_5(id(-1)), + {'EXIT',{badarith,_}} = catch element_5(id(e)), + + %% element_6: Test that it fails for values outside of 0..3. + zero = element_6(0), + one = element_6(1), + two = element_6(2), + three = element_6(3), + + {'EXIT',{badarg,[{erlang,element,[5,{zero,one,two,three}],_}|_]}} = + catch element_6(id(4)), + {'EXIT',{badarg,[{erlang,element,[0,{zero,one,two,three}],_}|_]}} = + catch element_6(id(-1)), + + %% Test element_7: Test that it fails for values outside of 1..3. + one = element_7(1), + two = element_7(2), + three = element_7(3), + + one = element_7(1+5), + two = element_7(2+5), + three = element_7(3+5), + + {'EXIT',{badarg,[{erlang,element,[0,{one,two,three}],_}|_]}} = + catch element_7(id(0)), + {'EXIT',{badarg,[{erlang,element,[4,{one,two,three}],_}|_]}} = + catch element_7(id(4)), + {'EXIT',{badarith,_}} = catch element_7(id(f)), + + %% element_8: Test that it works in a guard. + ok = element_8(id(1), id(a)), + error = element_8(id(1), id(b)), + error = element_8(id(-1), whatever), + error = element_8(id(0), whatever), + error = element_8(id(5), whatever), + + ok. + +element_1(N0) -> + N = N0 band 3, + element(N + 1, {zero,one,two,three}). + +element_2(N0) -> + N = N0 band 3, + element(N, {one,two,three}). + +element_3(N0) -> + N = N0 rem 4, + element(N, {one,two,three}). + +element_4(N0) -> + N = N0 rem 8, + element(N, {one,two,three}). + +element_5(N0) -> + N = N0 rem 8, + element(N + 1, {zero,one,two,three}). + +element_6(N) when is_integer(N) -> + element(N + 1, {zero,one,two,three}). + +element_7(N0) -> + N = N0 rem 5, + %% Max N is one more than the size of the tuple. + element(N, {one,two,three}). + +element_8(N0, E) -> + N = N0 rem 8, + if + element(N, {a,b,c,d}) =:= E -> + ok; + true -> + error + end. + +%% Test basic range optimization of arguments. +range_optimization(_Config) -> + immed_reg_confusion(), + + ok. + +%% The JIT confused x15/y15 with smalls when checking whether an argument fell +%% within the range of a small, because `is_small(arg.getValue())` happened to +%% be true. +immed_reg_confusion() -> + M = any_integer(1), + N = any_integer(1 bsl 128), + Res = any_integer(M bor N), + + Res = bor_x0_x15(M, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, N), + + ok. + +bor_x0_x15(_x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7, _x8, _x9, + _x10, _x11, _x12, _x13, _x14, _x15) -> + _x0 bor _x15. + +any_integer(I) -> + case id(I) of + N when is_integer(N) -> N + end. + +%%% +%%% Helpers. +%%% + +gen_func_names([E|Es], I) -> + Name = list_to_atom("f" ++ integer_to_list(I)), + [{Name,E}|gen_func_names(Es, I+1)]; +gen_func_names([], _) -> []. + +num_bits(Int) when Int >= 0 -> + num_bits(Int, 0). + +num_bits(0, N) -> N; +num_bits(Int, N) -> num_bits(Int bsr 1, N + 1). + %% Verifies that N is a small when it should be verify_kind(N, MinS, MaxS) -> true = is_small(N) =:= (N >= MinS andalso N =< MaxS). diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl index 5b46342127c1..b59390a85482 100644 --- a/erts/emulator/test/smoke_test_SUITE.erl +++ b/erts/emulator/test/smoke_test_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2018. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -24,71 +24,63 @@ %-compile(export_all). -export([all/0, suite/0, - init_per_testcase/2, end_per_testcase/2]). + init_per_testcase/2, end_per_testcase/2]). -export([boot_combo/1, native_atomics/1, jump_table/1]). suite() -> - [{ct_hooks,[ts_install_cth]}, - {timetrap, {minutes, 2}}]. + [{ct_hooks, [ts_install_cth]}, + {timetrap, {minutes, 2}}]. -all() -> +all() -> [boot_combo, native_atomics, jump_table]. init_per_testcase(boot_combo = Case, Config) when is_list(Config) -> case erlang:system_info(build_type) of - opt -> - init_per_tc(Case, Config); - _ -> - {skip,"Cannot test boot_combo in special builds since beam.* may not exist"} + opt -> + init_per_tc(Case, Config); + _ -> + {skip, "Cannot test boot_combo in special builds since beam.* may not exist"} end; init_per_testcase(Case, Config) when is_list(Config) -> init_per_tc(Case, Config). init_per_tc(Case, Config) -> - [{testcase, Case}|Config]. + [{testcase, Case} | Config]. end_per_testcase(_Case, Config) when is_list(Config) -> - ok. + erts_test_utils:ept_check_leaked_nodes(Config). %%% %%% The test cases ------------------------------------------------------------- %%% boot_combo(Config) when is_list(Config) -> - ZFlags = os:getenv("ERL_ZFLAGS", ""), - NOOP = fun () -> ok end, - A42 = fun () -> - case erlang:system_info(threads) of - true -> - 42 = erlang:system_info(thread_pool_size); - false -> - ok - end - end, - try - chk_boot(Config, "+Ktrue", NOOP), - chk_boot(Config, "+A42", A42), - chk_boot(Config, "+Ktrue +A42", A42), - - WBTArgs = ["very_short", "short", "medium", "long", "very_long"], - WTArgs = ["very_low", "low", "medium", "high", "very_high"], - [chk_boot(Config, - " +sbwt " ++ WBT ++ - " +sbwtdcpu " ++ WBT ++ - " +sbwtdio " ++ WBT ++ - " +swt " ++ WT ++ - " +swtdcpu " ++ WT ++ - " +swtdio " ++ WT, NOOP) || WBT <- WBTArgs, WT <- WTArgs], - - WSArgs = ["legacy", "default"], - [chk_boot(Config, " +sws " ++ WS, NOOP) || WS <- WSArgs], - - %% A lot more combos could be implemented... - ok - after - os:putenv("ERL_ZFLAGS", ZFlags) - end. + NOOP = fun() -> ok end, + A42 = fun() -> + case erlang:system_info(threads) of + true -> + 42 = erlang:system_info(thread_pool_size); + false -> + ok + end + end, + + chk_boot(["+Ktrue"], NOOP), + chk_boot(["+A42"], A42), + chk_boot(["+Ktrue", "+A42"], A42), + + WBTArgs = ["very_short", "short", "medium", "long", "very_long"], + WTArgs = ["very_low", "low", "medium", "high", "very_high"], + [chk_boot(["+sbwt", WBT, + "+sbwtdcpu", WBT, + "+sbwtdio", WBT, + "+swt", WT, + "+swtdcpu", WT, + "+swtdio", WT], NOOP) || WBT <- WBTArgs, WT <- WTArgs], + + WSArgs = ["legacy", "default"], + [chk_boot(["+sws", WS], NOOP) || WS <- WSArgs]. native_atomics(Config) when is_list(Config) -> NA32Key = "32-bit native atomics", @@ -96,70 +88,55 @@ native_atomics(Config) when is_list(Config) -> DWNAKey = "Double word native atomics", EthreadInfo = erlang:system_info(ethread_info), io:format("~p~n", [EthreadInfo]), - {value,{NA32Key, NA32, _}} = lists:keysearch(NA32Key, 1, EthreadInfo), - {value,{NA64Key, NA64, _}} = lists:keysearch(NA64Key, 1, EthreadInfo), - {value,{DWNAKey, DWNA, _}} = lists:keysearch(DWNAKey, 1, EthreadInfo), + {value, {NA32Key, NA32, _}} = lists:keysearch(NA32Key, 1, EthreadInfo), + {value, {NA64Key, NA64, _}} = lists:keysearch(NA64Key, 1, EthreadInfo), + {value, {DWNAKey, DWNA, _}} = lists:keysearch(DWNAKey, 1, EthreadInfo), case {erlang:system_info(build_type), NA32, NA64, DWNA} of - {opt, "no", "no", _} -> - ct:fail(optimized_smp_runtime_without_native_atomics); - _ -> - {comment, - NA32 ++ " 32-bit, " - ++ NA64 ++ " 64-bit, and " - ++ DWNA ++ " double word native atomics"} + {opt, "no", "no", _} -> + ct:fail(optimized_smp_runtime_without_native_atomics); + _ -> + {comment, + NA32 ++ " 32-bit, " + ++ NA64 ++ " 64-bit, and " + ++ DWNA ++ " double word native atomics"} end. jump_table(Config) when is_list(Config) -> case erlang:system_info(beam_jump_table) of - true -> - ok; - false -> - case erlang:system_info(build_type) of - opt -> - ct:fail(optimized_without_beam_jump_table); - BT -> - {comment, "No beam jump table, but build type is " ++ atom_to_list(BT)} - end + true -> + ok; + false -> + case erlang:system_info(build_type) of + opt -> + ct:fail(optimized_without_beam_jump_table); + BT -> + {comment, "No beam jump table, but build type is " ++ atom_to_list(BT)} + end end. - + %%% %%% Aux functions -------------------------------------------------------------- %%% -chk_boot(Config, Args, Fun) -> - true = os:putenv("ERL_ZFLAGS", Args), +chk_boot(Args, Fun) -> Success = make_ref(), Parent = self(), - io:format("--- Testing ~s~n", [Args]), - {ok, Node} = start_node(Config), - Pid = spawn_link(Node, fun () -> - Fun(), - Parent ! {self(), Success} - end), + io:format("--- Testing ~s~n", [lists:join(" ", Args)]), + {ok, Peer, Node} = ?CT_PEER(Args), + %% if spawn_link is used, race condition happens when + %% remote process exits with 'noconnection' reason and fails + %% the test case + Pid = spawn(Node, fun() -> + Fun(), + Parent ! {self(), Success} + end), receive - {Pid, Success} -> - Node = node(Pid), - stop_node(Node), - io:format("--- Success!~n", []), - ok + {Pid, Success} -> + Node = node(Pid), + peer:stop(Peer), + io:format("--- Success!~n", []), + ok end. -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - Opts = [{args, "-pa "++Pa++" "++Args}], - test_server:start_node(Name, slave, Opts). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index c230aa9f194c..014c0a114e3d 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -382,7 +382,7 @@ run_scheduler_wall_time_test(Type) -> Pid end, StartDirtyHog = fun(Func) -> - F = fun () -> + F = fun() -> erts_debug:Func(alive_waitexiting, MeMySelfAndI) end, @@ -470,7 +470,7 @@ online_statistics(Stats) -> DirtyCPUSchedulersOnline = erlang:system_info(dirty_cpu_schedulers_online), DirtyIOSchedulersOnline = erlang:system_info(dirty_io_schedulers), SortedStats = lists:sort(Stats), - ct:pal("Stats: ~p~n", [SortedStats]), + ct:log("Stats: ~p~n", [SortedStats]), SchedulersStats = lists:sublist(SortedStats, 1, SchedulersOnline), DirtyCPUSchedulersStats = diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl index 7c547fde7aa3..76efe053f58a 100644 --- a/erts/emulator/test/system_info_SUITE.erl +++ b/erts/emulator/test/system_info_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -62,8 +62,8 @@ init_per_testcase(_, Config) -> end_per_testcase(procs_bug, Config) -> procs_bug(end_per_testcase, Config); -end_per_testcase(_, _) -> - ok. +end_per_testcase(_, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). %%% %%% The test cases ------------------------------------------------------------- @@ -502,16 +502,6 @@ mapn(_Fun, 0) -> mapn(Fun, N) -> [Fun(N) | mapn(Fun, N-1)]. - -get_node_name(Config) -> - list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))). - ets_count(Config) when is_list(Config) -> [ets_count_do([Type | Named]) || Type <- [set, bag, duplicate_bag, ordered_set], @@ -530,77 +520,33 @@ ets_count_do(Opts) -> %% Verify system_info(ets_limit) reflects max ETS table settings. ets_limit(Config0) when is_list(Config0) -> - Config = [{testcase,ets_limit}|Config0], - true = is_integer(get_ets_limit(Config)), - 12345 = get_ets_limit(Config, 12345), + true = is_integer(get_ets_limit(0)), + 12345 = get_ets_limit(12345), ok. -get_ets_limit(Config) -> - get_ets_limit(Config, 0). -get_ets_limit(Config, EtsMax) -> +get_ets_limit(EtsMax) -> Envs = case EtsMax of 0 -> []; - _ -> [{"ERL_MAX_ETS_TABLES", integer_to_list(EtsMax)}] + _ -> ["-env", "ERL_MAX_ETS_TABLES", integer_to_list(EtsMax)] end, - {ok, Node} = start_node_ets(Config, Envs), - Me = self(), - Ref = make_ref(), - spawn_link(Node, - fun() -> - Res = erlang:system_info(ets_limit), - unlink(Me), - Me ! {Ref, Res} - end), - receive - {Ref, Res} -> - Res - end, - stop_node(Node), + {ok, Peer, Node} = ?CT_PEER(Envs), + Res = rpc:call(Node, erlang, system_info, [ets_limit]), + peer:stop(Peer), Res. -start_node_ets(Config, Envs) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(get_node_name(Config), peer, - [{args, "-pa "++Pa}, {env, Envs}]). - -start_node_atm(Config, AtomsMax) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(get_node_name(Config), peer, - [{args, "-pa "++ Pa ++ AtomsMax}]). - -stop_node(Node) -> - test_server:stop_node(Node). - %% Verify system_info(atom_limit) reflects max atoms settings %% (using " +t"). atom_limit(Config0) when is_list(Config0) -> - Config = [{testcase,atom_limit}|Config0], - 2186042 = get_atom_limit(Config, " +t 2186042 "), - ok. - -get_atom_limit(Config, AtomsMax) -> - {ok, Node} = start_node_atm(Config, AtomsMax), - Me = self(), - Ref = make_ref(), - spawn_link(Node, - fun() -> - Res = erlang:system_info(atom_limit), - unlink(Me), - Me ! {Ref, Res} - end), - receive - {Ref, Res} -> - Res - end, - stop_node(Node), - Res. + {ok, Peer, Node} = ?CT_PEER(["+t", "2186042"]), + 2186042 = rpc:call(Node, erlang, system_info, [atom_limit]), + peer:stop(Peer). %% Verify that system_info(atom_count) works. atom_count(Config) when is_list(Config) -> Limit = erlang:system_info(atom_limit), Count1 = erlang:system_info(atom_count), - list_to_atom(integer_to_list(erlang:unique_integer())), + _ = list_to_atom(integer_to_list(erlang:unique_integer())), Count2 = erlang:system_info(atom_count), true = Limit >= Count2, true = Count2 > Count1, diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl index 96b36bd69c7e..ce3e796da53c 100644 --- a/erts/emulator/test/time_SUITE.erl +++ b/erts/emulator/test/time_SUITE.erl @@ -70,8 +70,8 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{testcase, Func}|Config]. -end_per_testcase(_Func, _Config) -> - ok. +end_per_testcase(_Func, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -110,9 +110,7 @@ local_to_univ_utc(Config) when is_list(Config) -> case os:type() of {unix,_} -> %% TZ variable has a meaning - {ok, Node} = - test_server:start_node(local_univ_utc,peer, - [{args, "-env TZ UTC"}]), + {ok, Peer, Node} = ?CT_PEER(["-env", "TZ", "UTC"]), {{2008,8,1},{0,0,0}} = rpc:call(Node, erlang,localtime_to_universaltime, @@ -127,17 +125,33 @@ local_to_univ_utc(Config) when is_list(Config) -> rpc:call(Node, calendar,local_time_to_universal_time_dst, [{{2008, 8, 1}, {0, 0, 0}}]), - test_server:stop_node(Node), - ok; + peer:stop(Peer); _ -> {skip,"Only valid on Unix"} end. %% Tests conversion from universal to local time. +%% These cases are currently implemented only for MET and fail in +%% all other timezones +is_stockholm_time() -> + case os:type() of + {win32, _} -> case os:cmd("tzutil /g") of + "W. Europe Standard Time"++_ -> true; + _ -> false + end; + {unix, _} -> case os:cmd("date '+%Z'") of + "ME"++_ -> true; %% covers MET/MEST + "CE"++_ -> true; %% covers CET/CEST + _ -> false + end + end. univ_to_local(Config) when is_list(Config) -> - test_univ_to_local(test_data()). + case is_stockholm_time() of + true -> test_univ_to_local(test_data()); + false -> {skip, "This test is only valid for Stockholm timezone"} + end. test_univ_to_local([{Utc, Local}|Rest]) -> io:format("Testing ~p => ~p~n", [Local, Utc]), @@ -149,7 +163,10 @@ test_univ_to_local([]) -> %% Tests conversion from local to universal time. local_to_univ(Config) when is_list(Config) -> - test_local_to_univ(test_data()). + case is_stockholm_time() of + true -> test_local_to_univ(test_data()); + false -> {skip, "This test is only valid for Stockholm timezone"} + end. test_local_to_univ([{Utc, Local}|Rest]) -> io:format("Testing ~p => ~p~n", [Utc, Local]), @@ -243,7 +260,7 @@ compare_local_and_universal(Times) when Times > 0 -> Diff when abs(Diff) < AcceptableDiff -> ok; Diff -> - io:format("More than ~p seconds difference betwen " + io:format("More than ~p seconds difference between " "local and universal time", [Diff]), ct:fail(huge_diff) end. @@ -433,41 +450,39 @@ now_update1(0) -> time_warp_modes(Config) when is_list(Config) -> %% All time warp modes always supported in %% combination with no time correction... - check_time_warp_mode(Config, false, no_time_warp), - check_time_warp_mode(Config, false, single_time_warp), - check_time_warp_mode(Config, false, multi_time_warp), + check_time_warp_mode(false, no_time_warp), + check_time_warp_mode(false, single_time_warp), + check_time_warp_mode(false, multi_time_warp), erts_debug:set_internal_state(available_internal_state, true), try case erts_debug:get_internal_state({check_time_config, true, no_time_warp}) of false -> ok; - true -> check_time_warp_mode(Config, true, no_time_warp) + true -> check_time_warp_mode(true, no_time_warp) end, case erts_debug:get_internal_state({check_time_config, true, single_time_warp}) of false -> ok; - true -> check_time_warp_mode(Config, true, single_time_warp) + true -> check_time_warp_mode(true, single_time_warp) end, case erts_debug:get_internal_state({check_time_config, true, multi_time_warp}) of false -> ok; - true -> check_time_warp_mode(Config, true, multi_time_warp) + true -> check_time_warp_mode(true, multi_time_warp) end after erts_debug:set_internal_state(available_internal_state, false) end. -check_time_warp_mode(Config, TimeCorrection, TimeWarpMode) -> +check_time_warp_mode(TimeCorrection, TimeWarpMode) -> io:format("~n~n~n***** Testing TimeCorrection=~p TimeWarpMode=~p *****~n", [TimeCorrection, TimeWarpMode]), Mon = erlang:monitor(time_offset, clock_service), _ = erlang:time_offset(), Start = erlang:monotonic_time(1000), MonotonicityTimeout = 2000, - {ok, Node} = start_node(Config, - "+c " ++ atom_to_list(TimeCorrection) - ++ " +C " ++ atom_to_list(TimeWarpMode)), + {ok, Peer, Node} = ?CT_PEER(["+c", atom_to_list(TimeCorrection), "+C", atom_to_list(TimeWarpMode)]), StartTime = rpc:call(Node, erlang, system_info, [start_time]), Me = self(), MonotincityTestStarted = make_ref(), @@ -496,7 +511,7 @@ check_time_warp_mode(Config, TimeCorrection, TimeWarpMode) -> millisecond), io:format("UpMilliSeconds=~p~n", [UpMilliSeconds]), End = erlang:monotonic_time(millisecond), - stop_node(Node), + peer:stop(Peer), try true = (UpMilliSeconds > (98*MonotonicityTimeout) div 100), true = (UpMilliSeconds < (102*(End-Start)) div 100) @@ -904,6 +919,12 @@ test_data() -> case os:cmd("date '+%Z'") of "SAST"++_ -> {2,2}; + "PDT"++_ -> + {-8,-7}; + "PST"++_ -> + {-8,-7}; + "UTC"++_ -> + {0,0}; _ -> {?timezone,?dst_timezone} end; @@ -1029,22 +1050,3 @@ bad_dates() -> {{1996, 4, 30}, {12, 0, -1}}, % Sec {{1996, 4, 30}, {12, 0, 60}}]. - -start_node(Config, Args) -> - TestCase = proplists:get_value(testcase, Config), - PA = filename:dirname(code:which(?MODULE)), - ESTime = erlang:monotonic_time(1) + erlang:time_offset(1), - Unique = erlang:unique_integer([positive]), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(TestCase) - ++ "-" - ++ integer_to_list(ESTime) - ++ "-" - ++ integer_to_list(Unique)), - test_server:start_node(Name, - slave, - [{args, "-pa " ++ PA ++ " " ++ Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl index c02d2c767f07..5866553b3cc3 100644 --- a/erts/emulator/test/timer_bif_SUITE.erl +++ b/erts/emulator/test/timer_bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2022. 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. @@ -47,8 +47,8 @@ init_per_testcase(_Case, Config) -> end, Config. -end_per_testcase(_Case, _Config) -> - ok. +end_per_testcase(_Case, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). init_per_suite(Config) -> erts_debug:set_internal_state(available_internal_state, true), @@ -228,13 +228,10 @@ start_timer_e(Config) when is_list(Config) -> {'EXIT', _} = (catch erlang:start_timer(4.5, self(), hej)), {'EXIT', _} = (catch erlang:start_timer(a, self(), hej)), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), Pid = spawn(Node, timer, sleep, [10000]), {'EXIT', _} = (catch erlang:start_timer(1000, Pid, hej)), - stop_slave(Node), - - - ok. + peer:stop(Peer). %% Error cases for send_after/3 send_after_e(Config) when is_list(Config) -> @@ -245,11 +242,10 @@ send_after_e(Config) when is_list(Config) -> {'EXIT', _} = (catch erlang:send_after(4.5, self(), hej)), {'EXIT', _} = (catch erlang:send_after(a, self(), hej)), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), Pid = spawn(Node, timer, sleep, [10000]), {'EXIT', _} = (catch erlang:send_after(1000, Pid, hej)), - stop_slave(Node), - ok. + peer:stop(Peer). %% Error cases for cancel_timer/1 cancel_timer_e(Config) when is_list(Config) -> @@ -384,7 +380,7 @@ evil_timers(Config) when is_list(Config) -> %% in memory Self = self(), R1 = make_ref(), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), spawn_link(Node, fun () -> Self ! {R1, @@ -396,7 +392,7 @@ evil_timers(Config) when is_list(Config) -> fun (A, B) -> A + B end]]} end), ExtList = receive {R1, L} -> L end, - stop_slave(Node), + peer:stop(Peer), BinList = [<<"bla">>, <<"blipp">>, <<"blupp">>, @@ -813,17 +809,6 @@ get_msg() -> empty end. -start_slave() -> - Pa = filename:dirname(code:which(?MODULE)), - Name = atom_to_list(?MODULE) - ++ "-" ++ integer_to_list(erlang:system_time(second)) - ++ "-" ++ integer_to_list(erlang:unique_integer([positive])), - {ok, Node} = test_server:start_node(Name, slave, [{args, "-pa " ++ Pa}]), - Node. - -stop_slave(Node) -> - test_server:stop_node(Node). - collect(Last) -> collect(Last, []). diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index d25e8b6634bb..37f47cff3068 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -73,7 +73,8 @@ end_per_testcase(_Case, Config) -> Receiver = proplists:get_value(receiver, Config), unlink(Receiver), exit(Receiver, die), - ok. + + erts_test_utils:ept_check_leaked_nodes(Config). %% No longer testing anything, just reporting whether cpu_timestamp %% is enabled or not. @@ -130,8 +131,7 @@ receive_trace(Config) when is_list(Config) -> {true, true}]), %% Remote messages - OtherName = atom_to_list(?MODULE)++"_receive_trace", - {ok, OtherNode} = start_node(OtherName), + {ok, Peer, OtherNode} = ?CT_PEER(), RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]), io:format("RemoteProc = ~p ~n", [RemoteProc]), @@ -179,7 +179,7 @@ receive_trace(Config) when is_list(Config) -> F2(NN, {true, true}), unlink(RemoteProc), - true = stop_node(OtherNode), + peer:stop(Peer), %% Timeout Receiver ! {set_timeout, 10}, @@ -647,8 +647,7 @@ procs_trace(Config) when is_list(Config) -> dist_procs_trace(Config) when is_list(Config) -> ct:timetrap({seconds, 15}), - OtherName = atom_to_list(?MODULE)++"_dist_procs_trace", - {ok, OtherNode} = start_node(OtherName), + {ok, Peer, OtherNode} = ?CT_PEER(), Self = self(), process_flag(trap_exit, true), %% @@ -695,7 +694,7 @@ dist_procs_trace(Config) when is_list(Config) -> %% %% exit (with registered name, due to link) - Name = list_to_atom(OtherName), + Name = list_to_atom(hd(string:lexemes(atom_to_list(OtherNode), "@"))), Reason2 = make_ref(), Proc1 ! {link_please, Proc2}, {trace, Proc1, link, Proc2} = receive_first_trace(), @@ -708,8 +707,7 @@ dist_procs_trace(Config) when is_list(Config) -> receive_nothing(), %% %% Done. - true = stop_node(OtherNode), - ok. + peer:stop(Peer). %% Test trace(new, How, [procs]). procs_new_trace(Config) when is_list(Config) -> @@ -1724,7 +1722,7 @@ trace_delivered(Config) when is_list(Config) -> %% This testcase checks that receive trace works on exit signal messages %% when the sender of the exit signal is the process itself. -trap_exit_self_receive(Config) -> +trap_exit_self_receive(Config) when is_list(Config) -> Parent = self(), Proc = spawn_link(fun() -> process(Parent) end), @@ -1754,7 +1752,7 @@ trace_info_badarg(Config) when is_list(Config) -> %% An incoming suspend monitor down wasn't handled %% correct when the local monitor half had been %% removed with an emulator crash as result. -erl_704(Config) -> +erl_704(Config) when is_list(Config) -> erl_704_test(100). erl_704_test(0) -> @@ -1944,16 +1942,6 @@ fun_spawn(Fun, Args) -> spawn_link(erlang, apply, [Fun, Args]). -start_node(Name) -> - Pa = filename:dirname(code:which(?MODULE)), - Cookie = atom_to_list(erlang:get_cookie()), - test_server:start_node(Name, slave, - [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]). - -stop_node(Node) -> - test_server:stop_node(Node). - - wait_for_empty_runq(DeadLine) -> case statistics(run_queue) of 0 -> true; diff --git a/erts/emulator/test/trace_call_memory_SUITE.erl b/erts/emulator/test/trace_call_memory_SUITE.erl new file mode 100644 index 000000000000..59d1873e4926 --- /dev/null +++ b/erts/emulator/test/trace_call_memory_SUITE.erl @@ -0,0 +1,366 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2023. 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(trace_call_memory_SUITE). +-author("maximfca@gmail.com"). + + +%% Test server callbacks +-export([ + suite/0, + all/0, + init_per_testcase/2, + end_per_testcase/2 +]). + +%% Test cases exports +-export([ + basic/0, basic/1, + late_trace/0, late_trace/1, + skip/0, skip/1, + message/0, message/1, + parallel_map/0, parallel_map/1, + trace_all/0, trace_all/1, + spawn_memory/0, spawn_memory/1, spawn_memory_internal/1, + spawn_memory_lambda/1, + conflict_traces/0, conflict_traces/1, + big_words/0, big_words/1 +]). + +init_per_testcase(_Case, Config) -> + Config. + +end_per_testcase(basic, _Config) -> + erlang:trace_pattern({?MODULE, alloc_2tup, 0}, false, [call_memory]), + erlang:trace(self(), false, [call]); +end_per_testcase(late_trace, _Config) -> + erlang:trace_pattern({?MODULE, '_', '_'}, false, [call_memory]); +end_per_testcase(skip, _Config) -> + erlang:trace_pattern({?MODULE, '_', '_'}, false, [call_memory]), + erlang:trace(self(), false, [call]); +end_per_testcase(message, _Config) -> + erlang:trace_pattern({?MODULE, receive_message, 0}, false, [call_memory]), + erlang:trace(all, false, [call]); +end_per_testcase(parallel_map, _Config) -> + erlang:trace_pattern({?MODULE, '_', '_'}, false, [call_memory]), + erlang:trace(all, false, [call]); +end_per_testcase(trace_all, _Config) -> + erlang:trace_pattern({'_', '_', '_'}, false, [call_memory]), + erlang:trace(all, false, [call]); +end_per_testcase(spawn_memory, _Config) -> + erlang:trace_pattern({?MODULE, spawn_memory_internal, '_'}, false, [call_memory]), + erlang:trace(self(), false, [call]); +end_per_testcase(spawn_memory_lambda, _Config) -> + erlang:trace_pattern({erlang, apply, 2}, false, [call_memory]), + erlang:trace(self(), false, [call]); +end_per_testcase(conflict_traces, _Config) -> + erlang:trace_pattern({?MODULE, '_', '_'}, false, [call_memory]), + erlang:trace(self(), false, [call]); +end_per_testcase(big_words, _Config) -> + erlang:trace_pattern({?MODULE,alloc_tuples,2}, false, [call_memory]), + erlang:trace(self(), false, [call]). + + +suite() -> + [{timetrap, {seconds, 60}}]. + +all() -> + [basic, late_trace, skip, message, parallel_map, trace_all, spawn_memory, + spawn_memory_lambda, conflict_traces, big_words]. + +%% allocation functions +alloc_2tup() -> + {self(),self()}. %% a non literal + +receive_message() -> + receive + Msg -> Msg + end. + +basic() -> + [{doc, "Assert that two-tuple allocated 3-word structure on the heap"}]. + +basic(Config) when is_list(Config) -> + Self = self(), + Traced = {?MODULE, alloc_2tup, 0}, + 1 = erlang:trace_pattern(Traced, true, [call_memory]), + 1 = erlang:trace(Self, true, [call]), + alloc_2tup(), + {call_memory, [{Self, 1, 3}]} = erlang:trace_info(Traced, call_memory), + alloc_2tup(), + {call_memory, [{Self, 2, 6}]} = erlang:trace_info(Traced, call_memory), + %% test that GC works correctly + erlang:garbage_collect(), + alloc_2tup(), + {call_memory, [{Self, 3, 9}]} = erlang:trace_info(Traced, call_memory), + 1 = erlang:trace(Self, false, [call]), + 1 = erlang:trace_pattern(Traced, false, [call_memory]). + +late_trace() -> + [{doc, "Tests that garbage_collect call done before tracing is enabled works as expected"}]. + +late_trace(Config) when is_list(Config) -> + Control = self(), + Pid = spawn_link( + fun () -> + _ = late_trace_inner(), + 1 = erlang:trace_pattern({?MODULE, late_trace_inner, 0}, true, [call_memory]), + 1 = erlang:trace(self(), true, [call]), + _ = late_trace_inner(), + Control ! continue, + receive + stop -> + 1 = erlang:trace_pattern({?MODULE, late_trace_inner, 0}, false, [call_memory]) + end + end), + NonLiteral = non_literal_9(), + MRef = monitor(process, Pid), + Pid ! NonLiteral, + Pid ! NonLiteral, + receive continue -> ok end, + {call_memory, [{Pid, 1, 12}]} = erlang:trace_info({?MODULE, late_trace_inner, 0}, call_memory), + Pid ! stop, + receive {'DOWN', MRef, process, Pid, _} -> ok end. + +late_trace_inner() -> + Ref = alloc_2tup(), %% 3 words + receive _Msg -> Ref end. %% 9 more words + +non_literal_9() -> + %% 9 words in total: 6 words for the list, 3 for the tuple + erlang:insert_element(2, erlang:insert_element(1, {}, atom), lists:seq(1, 3)). + +skip() -> + [{doc, "Tests that skipped trace for a function accumulates in an upper level caller"}]. + +skip(Config) when is_list(Config) -> + Self = self(), + 1 = erlang:trace_pattern({?MODULE, upper, 0}, true, [call_memory]), + 1 = erlang:trace_pattern({?MODULE, lower, 1}, true, [call_memory]), + 1 = erlang:trace(Self, true, [call]), + upper(), + {call_memory, [{Self, 1, 8 * 2}]} = erlang:trace_info({?MODULE, lower, 1}, call_memory), + {call_memory, [{Self, 1, 3 + 3 + 6}]} = erlang:trace_info({?MODULE, upper, 0}, call_memory). + +upper() -> + Ref = alloc_2tup(), %% 3 + X = middle(Ref), %% 3 in middle, and 8 in lower (but lower has its own accounting) + {1, 2, 3, X, Ref}. %% extra 6 words (5 elements and 1 tuple size) + +middle(_Ref) -> + Ref2 = alloc_2tup(), %% 3 - but accounted in 'upper/0' instead + lower(8), + Ref2. + +lower(Max) -> + lists:seq(1, Max). + +message() -> + [{doc, "Assert that receiving a message results in memory trace"}]. + +message(Config) when is_list(Config) -> + Control = self(), + Traced = {?MODULE, receive_message, 0}, + NonLiteral = non_literal_9(), + 1 = erlang:trace_pattern(Traced, true, [call_memory]), + 1 = erlang:trace(self(), true, [call, set_on_first_spawn]), + Pid = spawn_link( + fun Wrap() -> + receive + pre -> + receive_message(), + Control ! done, + Wrap(); + stop -> + ok + end + end), + 1 = erlang:trace(self(), false, [call, set_on_first_spawn]), + %% first, check that sending a (non-matched) message does not result in a negative allocation + Pid ! NonLiteral, + timer:sleep(500), + {call_memory, []} = erlang:trace_info(Traced, call_memory), + %% enter the receive_message/0 + Pid ! pre, + %% wait for 'done' response + receive done -> ok end, + {call_memory, [{Pid, 1, 9}]} = erlang:trace_info(Traced, call_memory), + %% once again, just in case, to verify that decrementing "allocated" worked + Pid ! pre, + Pid ! NonLiteral, + receive done -> ok end, + {call_memory, [{Pid, 2, 18}]} = erlang:trace_info(Traced, call_memory), + 1 = erlang:trace_pattern(Traced, false, [call_memory]). + +parallel_map() -> + [{doc, "Test memory profiling with spawned processes"}]. + +parallel_map(Config) when is_list(Config) -> + _ = erlang:trace_pattern({?MODULE, '_', '_'}, true, [call_memory]), + 1 = erlang:trace(self(), true, [call, set_on_spawn]), + Pid = spawn_link(fun do_parallel/0), + MRef = monitor(process, Pid), + Pid ! pre_stop, + Pid ! {stop, 1}, + receive + {'DOWN', MRef, process, Pid, _} -> + %% alloc_2tup called 3 times (once per process) + {call_memory, [{_, 1, 3}, {_, 1, 3}, {_, 1, 3}]} = + erlang:trace_info({?MODULE, alloc_2tup, 0}, call_memory), + %% receive_message called 8 times (3 from "Allocs", 3 from "Grand", and 2 from the runner) + %% from 7 processes, but only 3*6 Grand processes and 3 words for the runner are on the heap + {call_memory, RecvMsg} = erlang:trace_info({?MODULE, receive_message, 0}, call_memory), + {7, 8, 21} = collapse_procs(RecvMsg) + end. + +do_parallel() -> + Allocs = [spawn_link(fun() -> alloc_2tup(), receive_message() end) || _ <- lists:seq(1, 3)], + Grand = [spawn_link(fun() -> receive_message() end) || _ <- lists:seq(1, 3)], + pre_stop = receive_message(), + [P ! {atom, <<"1234">>} || P <- Grand], %% 6 words on the heap: 3 for binary, 3 for tuple + {stop, 1} = receive_message(), + [exit(P, normal) || P <- Allocs]. + +trace_all() -> + [{doc, "Enables memory tracing for all processes, mainly ensuring there are no core dumps"}]. + +trace_all(Config) when is_list(Config) -> + _ = erlang:trace_pattern({'_', '_', '_'}, true, [call_memory]), + _ = erlang:trace(all, true, [call]), + do_heavy_lifting(), + _ = erlang:trace(all, false, [call]), + Profile = profile_memory(), + %% it'd be better to introduce more checks, but for now see that + %% at least some action happened + true = is_map_key(application_controller, Profile). + +do_heavy_lifting() -> + {ok, []} = application:ensure_all_started(kernel). + +profile_memory() -> + profile_modules(code:all_loaded(), #{}). + +profile_modules([], Acc) -> + Acc; +profile_modules([{Module, _} | Tail], Acc) -> + Funcs = try Module:module_info(functions) + catch error:undef -> [] % ignore homebrewed without module_info + end, + case profile_functions(Module, Funcs, #{}) of + Empty when Empty =:= #{} -> + profile_modules(Tail, Acc); + NonEmpty -> + profile_modules(Tail, Acc#{Module => NonEmpty}) + end. + +profile_functions(_Module, [], Acc) -> + Acc; +profile_functions(Module, [{Fun, Arity} | Tail], Acc) -> + case erlang:trace_info({Module, Fun, Arity}, call_memory) of + {call_memory, Skip} when Skip =:= []; Skip =:= false -> + profile_functions(Module, Tail, Acc); + {call_memory, Mem} -> + profile_functions(Module, Tail, Acc#{{Fun, Arity} => collapse_procs(Mem)}) + end. + +collapse_procs(Processes) -> + lists:foldl( + fun ({_Pid, Calls, Words}, {Procs, TotCalls, TotWords}) -> + {Procs + 1, TotCalls + Calls, TotWords + Words} + end, {0, 0, 0}, Processes). + +spawn_memory() -> + [{doc, "Tests that when a process is spawned, initial memory correctly attributed to the initial call"}]. + +spawn_memory(Config) when is_list(Config) -> + LostSharing = lists:seq(1, 16), + _ = erlang:trace_pattern({?MODULE, spawn_memory_internal, 1}, true, [call_memory]), + 1 = erlang:trace(self(), true, [call, set_on_first_spawn]), + Pid = erlang:spawn_link(?MODULE, spawn_memory_internal, [LostSharing]), + MRef = monitor(process, Pid), + receive {'DOWN', MRef, process, Pid, _} -> ok end, + 1 = erlang:trace(self(), false, [all]), + %% 16-elements list translates into 34-words for spawn + {call_memory, [{Pid, 1, 34}]} = erlang:trace_info({?MODULE, spawn_memory_internal, 1}, call_memory). + +spawn_memory_lambda(Config) when is_list(Config) -> + %% check that tracing with context captured through lambda also works - but reports erlang:apply + LostSharing = lists:seq(1, 16), + _ = erlang:trace_pattern({erlang, apply, 2}, true, [call_memory]), + 1 = erlang:trace(self(), true, [call, set_on_first_spawn]), + Pid = erlang:spawn_link(fun () -> spawn_memory_internal(LostSharing) end), + MRef = monitor(process, Pid), + receive {'DOWN', MRef, process, Pid, _} -> ok end, + 1 = erlang:trace(self(), false, [all]), + %% 16-elements list translates into 34-words for spawn, and 6 more words for apply itself + {call_memory, [{Pid, 1, 40}]} = erlang:trace_info({erlang, apply, 2}, call_memory). + +spawn_memory_internal(Array) -> + Array. + +conflict_traces() -> + [{doc, "Verify that call_time and call_memory don't break each other"}]. + +conflict_traces(Config) when is_list(Config) -> + Self = self(), + Traced = {?MODULE, alloc_2tup, 0}, + %% start call_memory trace + 1 = erlang:trace_pattern(Traced, true, [call_memory]), + 1 = erlang:trace(Self, true, [call]), + alloc_2tup(), + {call_memory, [{Self, 1, 3}]} = erlang:trace_info(Traced, call_memory), + %% start/stop call_time trace + 1 = erlang:trace_pattern(Traced, true, [call_time]), + alloc_2tup(), %% this goes to both time and memory + {call_time, [{Self, 1, _, _}]} = erlang:trace_info(Traced, call_time), + 1 = erlang:trace_pattern(Traced, false, [call_time]), + %% memory is unaffected + alloc_2tup(), + {call_memory, [{Self, 3, 9}]} = erlang:trace_info(Traced, call_memory), + %% + 1 = erlang:trace(Self, false, [call]), + 1 = erlang:trace_pattern(Traced, false, [call_memory]). + +big_words() -> + [{doc, "Test that Words counter can be a bignum on 32-bit"}]. + +big_words(Config) when is_list(Config) -> + Self = self(), + Traced = {?MODULE, alloc_tuples, 2}, + 1 = erlang:trace_pattern(Traced, true, [call_memory]), + 1 = erlang:trace(Self, true, [call]), + Words = (1 bsl 27), + case {erts_debug:size(Words), 8*erlang:system_info(wordsize)} of + {2, 32} -> ok; + {0, 64} -> ok + end, + TupleSz = 1023, + TupleCnt = Words div (TupleSz + 1), + alloc_tuples(TupleCnt, TupleSz), + CallCnt = TupleCnt + 1, + {call_memory, [{Self, CallCnt, Words}]} = erlang:trace_info(Traced, call_memory), + 1 = erlang:trace(Self, false, [call]), + 1 = erlang:trace_pattern(Traced, false, [call_memory]). + + +alloc_tuples(0, _) -> + ok; +alloc_tuples(N, TupleSz) -> + erlang:make_tuple(TupleSz, []), + alloc_tuples(N-1, TupleSz). diff --git a/erts/emulator/test/trace_call_time_SUITE.erl b/erts/emulator/test/trace_call_time_SUITE.erl index 2da660c88111..26687129bbb4 100644 --- a/erts/emulator/test/trace_call_time_SUITE.erl +++ b/erts/emulator/test/trace_call_time_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -71,13 +71,15 @@ bif/1, nif/1]). init_per_testcase(_Case, Config) -> - erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_time,call_count]), + erlang:trace_pattern({'_','_','_'}, false, + [local,meta,call_time,call_count,call_memory]), erlang:trace_pattern(on_load, false, [local,meta,call_time,call_count]), timer:now_diff(now(),now()), Config. end_per_testcase(_Case, _Config) -> - erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_time,call_count]), + erlang:trace_pattern({'_','_','_'}, false, + [local,meta,call_time,call_count,call_memory]), erlang:trace_pattern(on_load, false, [local,meta,call_time,call_count]), erlang:trace(all, false, [all]), ok. @@ -96,7 +98,7 @@ all() -> %% Tests basic call time trace basic(Config) when is_list(Config) -> P = erlang:trace_pattern({'_','_','_'}, false, [call_time]), - M = 1000, + M = 900, %% 1 = erlang:trace_pattern({?MODULE,seq, '_'}, true, [call_time]), 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_time]), @@ -298,12 +300,14 @@ combo(Config) when is_list(Config) -> 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_time]), 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, MetaMs, [{meta,MetaTracer}]), 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_count]), + 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_memory]), % bifs 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, [], [local]), 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_time]), 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, MetaMs, [{meta,MetaTracer}]), 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_count]), + 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_memory]), 1 = erlang:trace(Self, true, [{tracer,LocalTracer} | Flags]), %% @@ -319,12 +323,14 @@ combo(Config) when is_list(Config) -> %% check empty trace_info for ?MODULE:seq_r/3 {all,[_|_]=TraceInfo} = erlang:trace_info({?MODULE,seq_r,3}, all), + io:format("TraceInfo=~p\n",[TraceInfo]), {value,{traced,local}} = lists:keysearch(traced, 1, TraceInfo), {value,{match_spec,[]}} = lists:keysearch(match_spec, 1, TraceInfo), {value,{meta,MetaTracer}} = lists:keysearch(meta, 1, TraceInfo), {value,{meta_match_spec,MetaMs}} = lists:keysearch(meta_match_spec, 1, TraceInfo), {value,{call_count,0}} = lists:keysearch(call_count, 1, TraceInfo), {value,{call_time,[]}} = lists:keysearch(call_time, 1, TraceInfo), + {value,{call_memory,[]}} = lists:keysearch(call_memory, 1, TraceInfo), %% check empty trace_info for erlang:term_to_binary/1 {all, [_|_] = TraceInfoBif} = erlang:trace_info({erlang, term_to_binary, 1}, all), @@ -334,6 +340,7 @@ combo(Config) when is_list(Config) -> {value,{meta_match_spec,MetaMs}} = lists:keysearch(meta_match_spec, 1, TraceInfoBif), {value,{call_count,0}} = lists:keysearch(call_count, 1, TraceInfoBif), {value,{call_time,[]}} = lists:keysearch(call_time, 1, TraceInfoBif), + {value,{call_memory,[]}} = lists:keysearch(call_memory, 1, TraceInfoBif), %% [3,2,1] = seq_r(1, 3, fun(X) -> X+1 end), @@ -405,11 +412,21 @@ bif(Config) when is_list(Config) -> Pid = setup(), {L, Tot1} = execute(Pid, fun() -> with_bif(M) end), - {call_time,[{Pid,_,S,Us}]} = erlang:trace_info({?MODULE,with_bif,1}, call_time), - T1 = Tot1 - (S*1000000 + Us), - - ok = check_trace_info({erlang, binary_to_term, 1}, [{Pid, M - 1, 0, 0}], T1/2), - ok = check_trace_info({erlang, term_to_binary, 1}, [{Pid, M - 1, 0, 0}], T1/2), + {call_time,[{Pid,_,S,Us}]}=WB = erlang:trace_info({?MODULE,with_bif,1}, call_time), + T1 = Tot1 - (S*1000_000 + Us), + + B2T = erlang:trace_info({erlang, binary_to_term, 1}, call_time), + T2B = erlang:trace_info({erlang, term_to_binary, 1}, call_time), + io:format("with_bif = ~p\n", [WB]), + io:format("binary_to_term = ~p\n", [B2T]), + io:format("term_to_binary = ~p\n", [T2B]), + Sum = us(WB) + us(B2T) + us(T2B), + io:format("Sum = ~p us\n", [Sum]), + io:format("Tot1 = ~p us Diff = ~p us\n", [Tot1, Tot1-Sum]), + ok = check_trace_info_ret({erlang, binary_to_term, 1}, [{Pid, M-1, 0, 0}], + T1/2, B2T), + ok = check_trace_info_ret({erlang, term_to_binary, 1}, [{Pid, M-1, 0, 0}], + T1/2, T2B), % disable term2binary @@ -425,6 +442,9 @@ bif(Config) when is_list(Config) -> Pid ! quit, ok. +us({call_time,[{_,_,S,Us}]}) -> + S*1000_000 + Us. + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Tests tracing of nifs @@ -705,23 +725,35 @@ seq_r(Start, Stop, Succ, R) -> seq_r(Succ(Start), Stop, Succ, [Start | R]). % Check call time tracing data and print mismatches -check_trace_info(Mfa, [{Pid, ExpectedC,_,_}] = Expect, Time) -> - {call_time,[{Pid,C,S,Us}]} = erlang:trace_info(Mfa, call_time), +check_trace_info(Mfa, Expect, Time) -> + check_trace_info_ret(Mfa, Expect, Time, erlang:trace_info(Mfa, call_time)). + +check_trace_info_ret(Mfa, [{Pid, ExpectedC,_,_}] = Expect, Time, TraceInfo) -> + {call_time,[{Pid,Cnt,S,Us}]} = TraceInfo, + {Mod, Name, Arity} = Mfa, IsBuiltin = erlang:is_builtin(Mod, Name, Arity), - if + ok = if %% Call count on BIFs may exceed number of calls as they often trap to %% themselves. - IsBuiltin, C >= ExpectedC, S >= 0, Us >= 0, - abs(1 - Time/(S*1000000 + Us)) < ?R_ERROR; - abs(Time - S*1000000 - Us) < ?US_ERROR -> + IsBuiltin, Cnt >= ExpectedC -> ok; - not IsBuiltin, C =:= ExpectedC, S >= 0, Us >= 0, - abs(1 - Time/(S*1000000 + Us)) < ?R_ERROR; - abs(Time - S*1000000 - Us) < ?US_ERROR -> + not IsBuiltin, Cnt =:= ExpectedC -> + ok; + true -> + io:format("Expected ~p -> {call_time, ~p}~n" + " - got call count ~w~p", + [Mfa, Expect, Cnt]), + count_error + end, + + true = (S >= 0), + true = (Us >= 0), + Sum = S*1000_000 + Us, + if + abs(1 - Time/Sum) < ?R_ERROR; abs(Time - Sum) < ?US_ERROR -> ok; true -> - Sum = S*1000000 + Us, io:format("Expected ~p -> {call_time, ~p (Time ~p us)}~n - got ~w " "s. ~w us. = ~w us. - ~w -> delta ~w (ratio ~.2f, " "should be 1.0)~n", @@ -729,8 +761,8 @@ check_trace_info(Mfa, [{Pid, ExpectedC,_,_}] = Expect, Time) -> S, Us, Sum, Time, Sum - Time, Time/Sum]), time_error end; -check_trace_info(Mfa, Expect, _) -> - case erlang:trace_info(Mfa, call_time) of +check_trace_info_ret(Mfa, Expect, _, TraceInfo) -> + case TraceInfo of {call_time, Expect} -> ok; Other -> @@ -793,7 +825,7 @@ setup() -> setup(Opts) -> Pid = spawn_opt(fun() -> loop() end, - [link, {max_heap_size, 10000}]), + [link, {max_heap_size, 12000}]), 1 = erlang:trace(Pid, true, [call|Opts]), Pid. diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl index 8cf8c81b7ab3..741d5c10d9a7 100644 --- a/erts/emulator/test/trace_local_SUITE.erl +++ b/erts/emulator/test/trace_local_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -744,15 +744,27 @@ exception_test(Opts) -> shutdown(); true -> Exceptions = exceptions(), - lists:foreach( - fun ({Func,Args}) -> - exception_test_setup( - [procs|ProcFlags], - PatFlags), - exception_test(Opts, Func, Args), - shutdown() - end, - Exceptions) + try + %% suppress =ERROR REPORT=== emulator messages + ok = logger:add_primary_filter(suppress_log_spam, { + fun(#{meta := #{error_logger := #{emulator := true, tag := error}}}, _) -> + stop; + (_Meta, _Msg) -> + ignore + end, ok}), + lists:foreach( + fun ({Func,Args}) -> + exception_test_setup( + [procs|ProcFlags], + PatFlags), + exception_test(Opts, Func, Args), + shutdown() + end, + Exceptions) + after + %% remove the suppression for ERROR REPORTS + ok = logger:remove_primary_filter(suppress_log_spam) + end end, ok. @@ -778,7 +790,7 @@ exceptions() -> exception_test_setup(ProcFlags, PatFlags) -> Pid = setup(ProcFlags), - io:format("=== exception_test_setup(~p, ~p): ~p~n", + ct:log("=== exception_test_setup(~p, ~p): ~p~n", [ProcFlags,PatFlags,Pid]), Mprog = [{'_',[],[{exception_trace}]}], erlang:trace_pattern({?MODULE,'_','_'}, Mprog, PatFlags), @@ -792,7 +804,7 @@ exception_test_setup(ProcFlags, PatFlags) -> -record(exc_opts, {nocatch=false, meta=false}). exception_test(Opts, Func0, Args0) -> - io:format("=== exception_test(~p, ~p, ~p)~n", + ct:log("=== exception_test(~p, ~p, ~p)~n", [Opts,Func0,abbr(Args0)]), Apply = proplists:get_bool(apply, Opts), Function = proplists:get_bool(function, Opts), @@ -803,16 +815,16 @@ exception_test(Opts, Func0, Args0) -> %% Func0 and Args0 are for the innermost call, now we will %% wrap them in wrappers... {Func1,Args1} = - case Function of - true -> {fun exc/2,[Func0,Args0]}; - false -> {Func0,Args0} - end, + case Function of + true -> {fun(F, As) -> exc(F, As) end, [Func0,Args0]}; + false -> {Func0,Args0} + end, {Func,Args} = - case Apply of - true -> {{erlang,apply},[Func1,Args1]}; - false -> {Func1,Args1} - end, + case Apply of + true -> {{erlang,apply},[Func1,Args1]}; + false -> {Func1,Args1} + end, R1 = exc_slave(ExcOpts, Func, Args), Stack2 = [{?MODULE,exc_top,3,[]},{?MODULE,slave,2,[]}], diff --git a/erts/emulator/test/tuple_SUITE.erl b/erts/emulator/test/tuple_SUITE.erl index 8427825cd44e..e665c55003b6 100644 --- a/erts/emulator/test/tuple_SUITE.erl +++ b/erts/emulator/test/tuple_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -125,10 +125,17 @@ t_element(Config) when is_list(Config) -> a = element(1, {a}), a = element(1, {a, b}), - List = lists:seq(1, 4096), - Tuple = list_to_tuple(lists:seq(1, 4096)), + List = lists:seq(1, 16384), + Tuple = list_to_tuple(List), get_elements(List, Tuple, 1), + get_literal_elements(Tuple), + get_literal_tuple_elements(Tuple), + + {31,32, 63,64, 127,128, 255,256, 511,512, 1023,1024, + 2047,2048, 4095,4096, 8191,8192, 16383, 16384} = + get_literal_tuple_element_pairs(Tuple), + {'EXIT', {badarg, _}} = (catch element(0, id({a,b}))), {'EXIT', {badarg, _}} = (catch element(3, id({a,b}))), {'EXIT', {badarg, _}} = (catch element(1, id({}))), @@ -150,7 +157,110 @@ get_elements([Element|Rest], Tuple, Pos) -> get_elements(Rest, Tuple, Pos+1); get_elements([], _Tuple, _Pos) -> ok. - + +get_literal_elements(Tuple) -> + 31 = element(31, Tuple), + 32 = element(32, Tuple), + + 63 = element(63, Tuple), + 64 = element(64, Tuple), + + 127 = element(127, Tuple), + 128 = element(128, Tuple), + + 255 = element(255, Tuple), + 256 = element(256, Tuple), + + 511 = element(511, Tuple), + 512 = element(512, Tuple), + + 1023 = element(1023, Tuple), + 1024 = element(1024, Tuple), + + 2047 = element(2047, Tuple), + 2048 = element(2048, Tuple), + + 4095 = element(4095, Tuple), + 4096 = element(4096, Tuple), + + 8191 = element(8191, Tuple), + 8192 = element(8192, Tuple), + + 16383 = element(16383, Tuple), + 16384 = element(16384, Tuple), + + ok. + +get_literal_tuple_elements(Tuple) when tuple_size(Tuple) =:= 16384 -> + %% Since the tuple size is known, the element/2 calls will be + %% rewritten to get_tuple_element instructions. + + 31 = element(31, Tuple), + 32 = element(32, Tuple), + + 63 = element(63, Tuple), + 64 = element(64, Tuple), + + 127 = element(127, Tuple), + 128 = element(128, Tuple), + + 255 = element(255, Tuple), + 256 = element(256, Tuple), + + 511 = element(511, Tuple), + 512 = element(512, Tuple), + + 1023 = element(1023, Tuple), + 1024 = element(1024, Tuple), + + 2047 = element(2047, Tuple), + 2048 = element(2048, Tuple), + + 4095 = element(4095, Tuple), + 4096 = element(4096, Tuple), + + 8191 = element(8191, Tuple), + 8192 = element(8192, Tuple), + + 16383 = element(16383, Tuple), + 16384 = element(16384, Tuple), + + ok. + +get_literal_tuple_element_pairs(Tuple) when tuple_size(Tuple) =:= 16384 -> + %% Since the tuple size is known, the element/2 calls will be + %% rewritten to get_tuple_element instructions. + + {element(31, Tuple), + element(32, Tuple), + + element(63, Tuple), + element(64, Tuple), + + element(127, Tuple), + element(128, Tuple), + + element(255, Tuple), + element(256, Tuple), + + element(511, Tuple), + element(512, Tuple), + + element(1023, Tuple), + element(1024, Tuple), + + element(2047, Tuple), + element(2048, Tuple), + + element(4095, Tuple), + element(4096, Tuple), + + element(8191, Tuple), + element(8192, Tuple), + + element(16383, Tuple), + element(16384, Tuple)}. + %% Tests set_element/3. t_setelement(Config) when is_list(Config) -> @@ -158,9 +268,9 @@ t_setelement(Config) when is_list(Config) -> {x,2} = setelement(1, id({1,2}), x), {1,x} = setelement(2, id({1,2}), x), - Tuple = list_to_tuple(lists:duplicate(2048, x)), + Tuple = list_to_tuple(lists:duplicate(16385, x)), NewTuple = set_all_elements(Tuple, 1), - NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)), + NewTuple = list_to_tuple(lists:seq(1+7, 16385+7)), {'EXIT', {badarg, _}} = (catch setelement(0, {a, b}, x)), {'EXIT', {badarg, _}} = (catch setelement(3, {a, b}, x)), @@ -174,6 +284,9 @@ t_setelement(Config) when is_list(Config) -> setelement(1, setelement(2, setelement(3, AnotherTuple, gurka), 3.0), 93748793749387837476555412), + NewNewTuple = set_literal_tuple_elements(NewTuple), + verify_set_elements(1, NewNewTuple), + ok. set_all_elements(Tuple, Pos) when Pos =< size(Tuple) -> @@ -181,6 +294,71 @@ set_all_elements(Tuple, Pos) when Pos =< size(Tuple) -> set_all_elements(Tuple, Pos) when Pos > size(Tuple) -> Tuple. +set_literal_tuple_elements(Tuple0) when tuple_size(Tuple0) =:= 16385 -> + %% Since the tuple size is known, the setelement/3 calls will be + %% rewritten to set_tuple_element instructions. + Tuple1 = setelement(16385, Tuple0, -16385), + Tuple2 = setelement(16384, Tuple1, -16384), + + Tuple3 = setelement(8192, Tuple2, -8192), + Tuple4 = setelement(8191, Tuple3, -8191), + + Tuple5 = setelement(4096, Tuple4, -4096), + Tuple6 = setelement(4095, Tuple5, -4095), + + Tuple7 = setelement(2048, Tuple6, -2048), + Tuple8 = setelement(2047, Tuple7, -2047), + + Tuple9 = setelement(1024, Tuple8, -1024), + Tuple10 = setelement(1023, Tuple9, -1023), + + Tuple11 = setelement(512, Tuple10, -512), + Tuple12 = setelement(511, Tuple11, -511), + + Tuple13 = setelement(256, Tuple12, -256), + Tuple14 = setelement(255, Tuple13, -255), + + Tuple15 = setelement(128, Tuple14, -128), + Tuple16 = setelement(127, Tuple15, -127), + + Tuple17 = setelement(64, Tuple16, -64), + Tuple18 = setelement(63, Tuple17, -63), + + Tuple19 = setelement(32, Tuple18, -32), + Tuple20 = setelement(31, Tuple19, -31), + + Tuple21 = setelement(16, Tuple20, -16), + Tuple22 = setelement(15, Tuple21, -15), + + Tuple23 = setelement(8, Tuple22, -8), + Tuple24 = setelement(7, Tuple23, -7), + + Tuple25 = setelement(4, Tuple24, -4), + Tuple26 = setelement(3, Tuple25, -3), + + Tuple27 = setelement(2, Tuple26, -2), + setelement(1, Tuple27, -1). + +verify_set_elements(16385, Tuple) -> + -16385 = element(16385, Tuple), + ok; +verify_set_elements(N, Tuple) -> + El = element(N, Tuple), + if + El =:= N + 7 -> + true = not (is_power_of_two(N + 1) andalso is_power_of_two(N)), + verify_set_elements(N + 1, Tuple); + El =:= -N -> + true = is_power_of_two(N + 1) orelse is_power_of_two(N), + verify_set_elements(N + 1, Tuple); + true -> + io:format("element(~p) =:= ~p\n", [N,El]), + ct:fail(bad_element) + end. + +is_power_of_two(N) -> + N band (N - 1) =:= 0. + %% Tests list_to_tuple/1. t_list_to_tuple(Config) when is_list(Config) -> @@ -205,7 +383,7 @@ t_list_to_tuple(Config) when is_list(Config) -> t_list_to_upper_boundry_tuple(Config) when is_list(Config) -> sys_mem_cond_run(2048, fun () -> - %% test upper boundry, 16777215 elements + %% test upper boundary, 16777215 elements MaxSize = 1 bsl 24 - 1, MaxTuple = list_to_tuple(lists:seq(1, MaxSize)), MaxSize = size(MaxTuple), @@ -254,7 +432,7 @@ t_make_tuple_2(Config) when is_list(Config) -> t_make_upper_boundry_tuple_2(Config) when is_list(Config) -> sys_mem_cond_run(2048, fun () -> - %% test upper boundry, 16777215 elements + %% test upper boundary, 16777215 elements t_make_tuple(1 bsl 24 - 1, a) end). @@ -347,7 +525,7 @@ t_append_element(Config) when is_list(Config) -> t_append_element_upper_boundry(Config) when is_list(Config) -> sys_mem_cond_run(2048, fun () -> - %% test upper boundry, 16777215 elements + %% test upper boundary, 16777215 elements MaxSize = 1 bsl 24 - 1, MaxTuple = list_to_tuple(lists:seq(1, MaxSize)), {'EXIT',{badarg,_}} = (catch erlang:append_element(MaxTuple, a)), @@ -419,7 +597,7 @@ get_two_tuple_elements(Config) -> true = code:delete(GTTEMod), code:purge(GTTEMod), - %% Compile from the pre-generated BEAM assmebly code file. (In case that the + %% Compile from the pre-generated BEAM assembly code file. (In case that the %% compiler's code generation has changed.) {ok,GTTEMod,Code2} = compile:file(GTTETestsFile, [from_asm,binary,report,time]), {module,GTTEMod} = code:load_binary(GTTEMod, GTTEMod, Code2), @@ -445,17 +623,16 @@ sys_mem_cond_run(ReqSizeMB, TestFun) when is_integer(ReqSizeMB) -> total_memory() -> - %% Totat memory in MB. + %% Total memory in MB. try - MemoryData = memsup:get_system_memory_data(), - case lists:keysearch(total_memory, 1, MemoryData) of - {value, {total_memory, TM}} -> - TM div (1024*1024); - false -> - {value, {system_total_memory, STM}} = - lists:keysearch(system_total_memory, 1, MemoryData), - STM div (1024*1024) - end + SMD = memsup:get_system_memory_data(), + TM = proplists:get_value( + available_memory, SMD, + proplists:get_value( + total_memory, SMD, + proplists:get_value( + system_total_memory, SMD))), + TM div (1024*1024) catch _ : _ -> undefined diff --git a/erts/emulator/test/tuple_SUITE_data/get_two_tuple_elements.S b/erts/emulator/test/tuple_SUITE_data/get_two_tuple_elements.S index dc873fe73f48..577442428449 100644 --- a/erts/emulator/test/tuple_SUITE_data/get_two_tuple_elements.S +++ b/erts/emulator/test/tuple_SUITE_data/get_two_tuple_elements.S @@ -63,7 +63,7 @@ {trim,2,0}. {line,[{location,"get_two_tuple_elements.erl",5}]}. {call,2,{f,5}}. - {'%',{var_info,{x,0},[{type,number}]}}. + {'%',{var_info,{x,0},[{type,{t_number,any}}]}}. {test,is_eq_exact,{f,3},[{x,0},{integer,3}]}. {move,{atom,ok},{x,0}}. {deallocate,0}. diff --git a/erts/emulator/test/unique_SUITE.erl b/erts/emulator/test/unique_SUITE.erl index cfc37bd44ff7..d041ed563278 100644 --- a/erts/emulator/test/unique_SUITE.erl +++ b/erts/emulator/test/unique_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2017. All Rights Reserved. +%% Copyright Ericsson AB 2014-2022. 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. @@ -21,6 +21,7 @@ -module(unique_SUITE). -export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). -export([unique_monotonic_integer_white_box/1, unique_integer_white_box/1]). @@ -47,6 +48,11 @@ end_per_suite(_Config) -> erts_debug:set_internal_state(available_internal_state, false), ok. +init_per_testcase(_TestCase, Config) -> + Config. +end_per_testcase(_TestCase, Config) -> + erts_test_utils:ept_check_leaked_nodes(Config). + %% %% %% Unique counter white box test case @@ -54,7 +60,7 @@ end_per_suite(_Config) -> %% unique_monotonic_integer_white_box(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), TestServer = self(), Success = make_ref(), %% Run this in a separate node, so we don't mess up @@ -72,8 +78,7 @@ unique_monotonic_integer_white_box(Config) when is_list(Config) -> ok end, erlang:demonitor(Mon, [flush]), - stop_node(Node), - ok. + peer:stop(Peer). set_unique_monotonic_integer_state(MinCounter, NextValue) -> true = erts_debug:set_internal_state(unique_monotonic_integer_state, @@ -355,21 +360,3 @@ check_unique_integer_around(Int, #uniqint_info{min_int = MinInt, print_ret_val(File, Line, Value) -> io:format("~s:~p: ~p~n", [File, Line, Value]), Value. - -start_node(Config) -> - start_node(Config, []). -start_node(Config, Opts) when is_list(Config), is_list(Opts) -> - Pa = filename:dirname(code:which(?MODULE)), - A = erlang:monotonic_time(1) + erlang:time_offset(1), - B = erlang:unique_integer([positive]), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(A) - ++ "-" - ++ integer_to_list(B)), - test_server:start_node(Name, slave, [{args, Opts++" -pa "++Pa}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/erts/emulator/test/z_SUITE.erl b/erts/emulator/test/z_SUITE.erl index 5b2e77dfa23a..cb178704eb2d 100644 --- a/erts/emulator/test/z_SUITE.erl +++ b/erts/emulator/test/z_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2020. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -169,7 +169,7 @@ schedulers_alive(Config) when is_list(Config) -> enabled -> ok end, erts_debug:set_internal_state(available_internal_state, true), - %% node_and_dist_references will use emulator interal thread blocking... + %% node_and_dist_references will use emulator internal thread blocking... erts_debug:get_internal_state(node_and_dist_references), erts_debug:set_internal_state(available_internal_state, false), io:format("Testing not blocked~n"), @@ -330,8 +330,9 @@ check_io_debug_test() -> has_gethost() -> has_gethost(erlang:ports()). has_gethost([P|T]) -> - case erlang:port_info(P, name) of - {name,"inet_gethost"++_} -> + {name, Name} = erlang:port_info(P, name), + case filename:basename(Name) of + "inet_gethost"++_ -> true; _ -> has_gethost(T) @@ -346,7 +347,7 @@ lc_graph(Config) when is_list(Config) -> ok. leaked_processes(Config) when is_list(Config) -> - %% Replace the defualt timetrap with a timetrap with + %% Replace the default timetrap with a timetrap with %% known pid. test_server:timetrap_cancel(), Dog = test_server:timetrap(test_server:minutes(5)), diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index 867f6319382e..c7ea03202610 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -49,6 +49,10 @@ my $code_pointers_are_short = 0; # Whether code pointers (to C code) are short. my $code_model = 'unknown'; my $jit = 'no'; my %defs; # Defines (from command line). +my $pending_errors = 0; # Number of pending errors. + +# Intentionally unused macros, predicates, and generators. +my %intentionally_unused; # This is shift counts and mask for the packer. my $WHOLE_WORD = ''; @@ -178,8 +182,82 @@ my %arg_size = ('r' => 0, # x(0) - x register zero, 'h' => 1, # character (not used) 'l' => 1, # float reg 'q' => 1, # literal term + 'M' => 1, # pointer to raw string + 'H' => 1, # exception handler ); +# Maps operand type to the argument classes used by the JIT. +my %arg_jit_class = ('r' => 'ArgXRegister', + 'x' => 'ArgXRegister', + 'y' => 'ArgYRegister', + 'a' => 'ArgAtom', + 'n' => 'ArgNil', + 'c' => 'ArgConstant', + 's' => 'ArgSource', + 'S' => 'ArgRegister', + 'd' => 'ArgRegister', + 'f' => 'ArgLabel', + 'j' => 'ArgLabel', + 'e' => 'ArgExport', + 'L' => 'ArgLabel', + 't' => 'ArgWord', + 'I' => 'ArgWord', + 'W' => 'ArgWord', + 'b' => 'ArgWord', + 'F' => 'ArgLambda', + 'A' => 'ArgWord', + 'P' => 'ArgWord', + 'Q' => 'ArgWord', + 'h' => 'ArgWord', + 'l' => 'ArgFRegister', + 'q' => 'ArgLiteral', + 'M' => 'ArgBytePtr', + 'H' => 'ArgCatch', + ); + +# Define a lattice for the parameter classes used in the JIT. +# +# The classes are represented as a bitset where each class is represented by +# a single bit, which is combined with that of its superclasses, letting us +# find the best superclass for a given set of classes by AND-ing them together. +my %arg_jit_lattice; +{ + # Perl lacks enums, lovely :( + my $iota = 0; + my %jcl; + + $jcl{'ArgVal'} = (1 << $iota++), + + $jcl{'ArgBytePtr'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgCatch'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgExport'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgLabel'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgLambda'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgSource'} = $jcl{'ArgVal'} | (1 << $iota++); + $jcl{'ArgWord'} = $jcl{'ArgVal'} | (1 << $iota++); + + $jcl{'ArgConstant'} = $jcl{'ArgSource'} | (1 << $iota++); + $jcl{'ArgRegister'} = $jcl{'ArgSource'} | (1 << $iota++); + + $jcl{'ArgLiteral'} = $jcl{'ArgConstant'} | (1 << $iota++); + $jcl{'ArgImmed'} = $jcl{'ArgConstant'} | (1 << $iota++); + + $jcl{'ArgAtom'} = $jcl{'ArgImmed'} | (1 << $iota++); + $jcl{'ArgNil'} = $jcl{'ArgImmed'} | (1 << $iota++); + $jcl{'ArgSmall'} = $jcl{'ArgImmed'} | (1 << $iota++); + + $jcl{'ArgXRegister'} = $jcl{'ArgRegister'} | (1 << $iota++); + $jcl{'ArgYRegister'} = $jcl{'ArgRegister'} | (1 << $iota++); + $jcl{'ArgFRegister'} = $jcl{'ArgRegister'} | (1 << $iota++); + + foreach my $class (keys %jcl) { + my $bits = $jcl{$class}; + $jcl{$bits} = $class; + } + + %arg_jit_lattice = %jcl; +} + # # Types that are forbidden to use for specific operations. # @@ -256,6 +334,8 @@ sub define_type_bit { define_type_bit('e', $type_bit{'u'}); define_type_bit('Q', $type_bit{'u'}); define_type_bit('P', $type_bit{'u'}); + define_type_bit('M', $type_bit{'u'}); + define_type_bit('H', $type_bit{'u'}); } # @@ -371,8 +451,13 @@ while (<>) { } chomp; if (s/\\$//) { - $_ .= <>; - redo unless eof(ARGV); + error("line continuation with `\\` is no longer allowed"); + } elsif (/([|]|=>)$/) { + # Automatically continue a line that ends in '|' or '=>'. + my $next_line = <>; + $_ .= $next_line; + chomp $next_line; + redo unless eof(ARGV) or $next_line eq ''; } next if /^\s*$/; next if /^\#/; @@ -448,6 +533,24 @@ while (<>) { next; } + # + # Handle %unused. + # + if (/^\%unused\s+(\S+)/) { + my $name = $1; + error("Illegal predicate/generator name '$name'") + unless $name =~ /^[a-z][.\w\d_]*$/; + $intentionally_unused{$name} = 1; + next; + } + + # + # Handle unrecognized % directives. + # + if (/^\%(\S+)/) { + error("Unrecognized directive '%$1'"); + } + # # Handle transformations. # @@ -569,7 +672,6 @@ $num_file_opcodes = @gen_opname; # or use forbidden types. # -my $any_errors; foreach my $key (keys %specific_op) { my($arity) = (split('/', $key))[1]; my @specific_ops = @{$specific_op{$key}}; @@ -594,17 +696,18 @@ foreach my $key (keys %specific_op) { my $cleaned_arg = $arg; $cleaned_arg =~ s/[?]$//; if ($jit ne 'no' and $cleaned_arg eq 'r') { - warn "specific instruction '$name @args' uses type 'r' which is is not supported for BeamAsm\n"; - $any_errors = 1; + pending_error("specific instruction '$name @args' uses type " . + "'r' which is is not supported for BeamAsm"); } elsif ($forbidden_type{$cleaned_arg}) { - warn "specific instruction '$name @args' uses forbidden type '$arg'\n"; - $any_errors = 1; + pending_error("specific instruction '$name @args' uses " . + "forbidden type '$arg'\n"); } } } } -error("there were previous type errors") if $any_errors; +error("beam_makeops: terminating because there were previous errors") + if $pending_errors > 0; # # Produce output for the chosen target. @@ -612,12 +715,16 @@ error("there were previous type errors") if $any_errors; &$target(); +error("beam_makeops: terminating because there were previous errors") + if $pending_errors > 0; + # # Ensure that all C code implementations have been used. # { my(@unused) = grep(!$c_code_used{$_}, keys %c_code); - foreach my $unused (@unused) { + @unused = grep(!$intentionally_unused{$_}, @unused); + foreach my $unused (sort @unused) { my(undef,$where) = @{$c_code{$unused}}; warn "$where: $unused is unused\n"; } @@ -633,6 +740,13 @@ sub emulator_output { my $name; my $key; # Loop variable. + foreach $key (sort keys %c_code) { + if ($intentionally_unused{$key}) { + delete $c_code{$key}; + } +# print STDERR "$key: ", defined($c_code{$key}), "\n"; + } + # Initialize common information always needed. foreach $key (keys %specific_op) { foreach (@{$specific_op{$key}}) { @@ -692,11 +806,11 @@ sub emulator_output { } if ($varargs) { - # We pass variable argument lists as a vector of ArgVal, + # We pass variable argument lists as a Span of ArgVal, # slicing our argument vector after the argument count. $body .= $sep . - "std::vector(" . - "args.cbegin() + " . scalar(@args) . ", args.cend())"; + "args.subspan(" . scalar(@args) . "," . + "args.size() - " . scalar(@args) . ")"; } $body .= ");"; @@ -715,17 +829,33 @@ sub emulator_output { # Sort the generated code to create beamasm_protos.h deterministically foreach $key (sort keys %specific_op) { - foreach (@{$specific_op{$key}}) { - my($name, $hotness, $varargs, @args) = @$_; + my @specific_ops = @{$specific_op{$key}}; + my ($name, + $hotness, + $varargs, + @combined_signs) = @{shift @specific_ops}; + + # We want to reduce all specific ops to the same prototype, so + # their signs must be combined to find the right argument types. + foreach (@specific_ops) { + my (undef, undef, undef, @specific_signs) = @$_; + + for my $i (0..$#combined_signs) { + $combined_signs[$i] .= $specific_signs[$i]; + } + } - @args = ("const ArgVal&") x @args; - if ($varargs) { - push @args, "const std::vector&"; - } + my @typed_args; + for my $signs (@combined_signs) { + my $class = get_jit_class($signs); + push @typed_args, "const $class&"; + } - print "void emit_$name(", join(", ", @args), ");\n"; - last; # We only want to print one prototype + if ($varargs) { + push @typed_args, "const Span&"; } + + print "void emit_$name(", join(", ", @typed_args), ");\n"; } } @@ -1010,7 +1140,10 @@ sub emulator_output { print '#include "erl_term.h"', "\n"; print '#include "erl_map.h"', "\n"; print '#include "big.h"', "\n"; + print '#include "erl_bits.h"', "\n"; + print '#include "erl_binary.h"', "\n"; print '#include "beam_transform_helpers.h"', "\n"; + print '#include "erl_global_literals.h"', "\n"; print "\n"; gen_tr_code('pred.'); gen_tr_func('int', 'erts_beam_eval_predicate', @pred_table); @@ -1248,6 +1381,13 @@ sub parse_c_args { @res; } +sub pending_error { + my(@message) = @_; + my($where) = $. ? "$ARGV($.): " : ""; + $pending_errors++; + warn $where, @message, "\n"; +} + sub error { my(@message) = @_; my($where) = $. ? "$ARGV($.): " : ""; @@ -2010,7 +2150,7 @@ sub do_pack_one { # to the left of the current micro instruction. If that is the # case, it is essential that we generate stacking and # unstacking instructions even when no packing is - # possible. (build_pack_spec() will remove any unecessary + # possible. (build_pack_spec() will remove any unnecessary # stacking and unstacking operations.) # # Here is an example. Say that we have this instruction: @@ -2356,10 +2496,14 @@ sub parse_transformation { local($_) = @_; my($orig) = $_; - my($from, $to) = split(/\s*=>\s*/); + my($from, $to, @rest) = split(/\s*=>\s*/); my(@op); my $rest_var; + if (@rest) { + error("only one '=>' operator is allowed"); + } + # The source instructions. my(@from) = split(/\s*\|\s*/, $from); @@ -2386,15 +2530,22 @@ sub parse_transformation { error("garbage after call to '$name()'"); } @to = (compile_transform_function($name, split(/\s*,\s*/, $arglist))); + } elsif ($to =~ /^\s*_\s*$/) { + # _ means that instructions on the left side should be removed. + @to = (); } else { @to = split(/\s*\|\s*/, $to); + if (@to == 0) { + error("the right-hand side of a transformation must not be empty;\n" . + " use _ to indicate that no instructions should be produced"); + } foreach (@to) { (@op) = split; (undef,$_) = compile_transform(0, $rest_var, @op); } } $orig =~ tr/ \t/ /s; - push(@transformations, [$., $orig, [@from], [reverse @to]]); + push(@transformations, ["$ARGV($.)", $orig, [@from], [reverse @to]]); } sub compile_transform_function { @@ -2599,7 +2750,7 @@ sub tr_gen_from { my($var_num) = 0; my(@code); my($op, $ref); # Loop variables. - my $where = "left side of transformation in line $line: "; + my $where = "$line: (left of =>): "; my $may_fail = 0; my $is_first = 1; my @instrs; @@ -2708,14 +2859,14 @@ sub tr_gen_from { if ($var ne '') { if (defined $var{$var}) { - $ignored_var = ''; - $may_fail = 1; - my $op = make_op($var, 'is_same_var', $var{$var}); - op_slot_usage($op, $var{$var}); - push(@code, $op); + my $msg = "variable $var used more than once\n" . + " (repeated variables in matching is not supported;\n" . + " use the predicate equal(Var1, Var2) " . + "to compare variables)"; + pending_error($where, $msg); } elsif ($type eq '*') { foreach my $type (values %var_type) { - error("only one use of a '*' variable is " . + error($where, "only one use of a '*' variable is " . "allowed on the left hand side of " . "a transformation") if $type eq 'array'; @@ -2797,7 +2948,7 @@ sub tr_gen_to { my(%var_type) = %$var_type_ref; my(@code) = @$code_ref; my($op, $ref); # Loop variables. - my($where) = "right side of transformation in line $line: "; + my($where) = "$line: (right of =>): "; my $last_instr = $code[$#code]; my $cannot_fail = is_instr($last_instr, 'commit') && @@ -2918,7 +3069,7 @@ sub group_tr { my($lref) = @_; # - # Group tranformations (while keeping the order) that all match the same + # Group transformations (while keeping the order) that all match the same # second instruction. # for (my $i = 0; $i < @$lref; $i++) { @@ -3303,3 +3454,25 @@ sub include_files() { print '#include "beam_load.h"', "\n"; print "\n"; } + +# Converts a sign string to its most specific argument class, e.g. "an" becomes +# 'ArgImmed' because both are immediates, and "anx" becomes 'ArgSource' because +# all of them are sources. +sub get_jit_class { + my $signs__ = shift; + $signs__ =~ s/[?]//g; + + my @signs = split //, $signs__; + + my $type = $arg_jit_class{shift(@signs)}; + my $combined_bits = $arg_jit_lattice{$type}; + + foreach my $sign (@signs) { + my $next_type = $arg_jit_class{$sign}; + my $next_bits = $arg_jit_lattice{$next_type}; + + $combined_bits &= $next_bits; + } + + return $arg_jit_lattice{$combined_bits}; +} diff --git a/erts/emulator/utils/count b/erts/emulator/utils/count index e0a5e8bb9a19..859137ed969c 100755 --- a/erts/emulator/utils/count +++ b/erts/emulator/utils/count @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2021. 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. @@ -24,7 +24,7 @@ main(_) -> DisDir = "./dis", ok = filelib:ensure_dir(filename:join(DisDir, "dummy")), - io:format("Dissambling to ~s\n", [DisDir]), + io:format("Disassembling to ~s\n", [DisDir]), ok = file:set_cwd(DisDir), Path = code:get_path() -- ["."], Beams0 = [filelib:wildcard(filename:join(Dir, "*.beam")) || @@ -98,7 +98,7 @@ increment(Key, Inc) -> end. %%% -%%% Counting sempahore to limit the number of processes that +%%% Counting semaphore to limit the number of processes that %%% can run concurrently. %%% diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab index b55a926c0c90..567b7aad6046 100755 --- a/erts/emulator/utils/make_driver_tab +++ b/erts/emulator/utils/make_driver_tab @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2023. 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. @@ -107,7 +107,7 @@ foreach (@static_drivers) { } print " {NULL}\n};\n"; -print "void erts_init_static_drivers() {\n"; +print "void erts_init_static_drivers(void) {\n"; my $index = 0; foreach (@static_drivers) { @@ -130,38 +130,19 @@ foreach (@static_nifs) { } # The array itself -print "static ErtsStaticNifEntry static_nif_tab[] =\n{\n"; +print "ErtsStaticNif erts_static_nif_tab[] =\n{\n"; foreach (@emu_nifs) { my $d = ${_}; $d =~ s/\.debug//; # strip .debug - print " {\"${_}\", &".$d."_nif_init, 0},\n"; + print " {&".$d."_nif_init, 0, THE_NON_VALUE, NULL},\n"; } foreach (@static_nifs) { my $d = ${_}; $d =~ s/\.debug//; # strip .debug - print " {\"${_}\", &".$d."_nif_init, 1},\n"; + print " {&".$d."_nif_init, 1, THE_NON_VALUE, NULL},\n"; } -print " {NULL,NULL}\n};\n"; - -print <nif_name != NULL; p++) - if (strncmp(p->nif_name, name, len) == 0 && p->nif_name[len] == 0) - return p; - return NULL; -} - -int erts_is_static_nif(void *handle) { - ErtsStaticNifEntry* p; - for (p = static_nif_tab; p->nif_name != NULL; p++) - if (((void*)p->nif_init) == handle) - return 1; - return 0; -} - -EOF +print " {NULL}\n};\n"; # That's it diff --git a/erts/emulator/utils/make_preload b/erts/emulator/utils/make_preload index b596fb0fa26b..e8f59def1a53 100755 --- a/erts/emulator/utils/make_preload +++ b/erts/emulator/utils/make_preload @@ -150,7 +150,9 @@ sub beam_strip { 'ExpT' => 1, 'StrT' => 1, 'FunT' => 1, - 'LitT' => 1); + 'LitT' => 1, + 'Type' => 1 + ); die "$file: can't read Beam files for OTP R4 or earlier (sorry)" if $beam =~ /^\x7fBEAM!/; diff --git a/erts/emulator/zlib/compress.c b/erts/emulator/zlib/compress.c index e2db404abf88..2ad5326c14ec 100644 --- a/erts/emulator/zlib/compress.c +++ b/erts/emulator/zlib/compress.c @@ -19,7 +19,7 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) +int ZEXPORT compress2(dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) /* =========================================================================== */ -int ZEXPORT compress (dest, destLen, source, sourceLen) +int ZEXPORT compress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen) If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -uLong ZEXPORT compressBound (sourceLen) +uLong ZEXPORT compressBound(sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + diff --git a/erts/emulator/zlib/crc32.c b/erts/emulator/zlib/crc32.c index a1bdce5c23c6..f8357b083f76 100644 --- a/erts/emulator/zlib/crc32.c +++ b/erts/emulator/zlib/crc32.c @@ -98,13 +98,22 @@ # endif #endif +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + /* Local functions. */ local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); -/* If available, use the ARM processor CRC32 instruction. */ -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 -# define ARMCRC32 +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) @@ -630,7 +639,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; /* Compute the CRC up to a word boundary. */ while (len && ((z_size_t)buf & 7) != 0) { @@ -645,8 +654,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x - instruction per cycle. Each CRC is calcuated on Z_BATCH words. The three - CRCs are combined into a single CRC after each set of batches. */ + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; @@ -749,7 +758,7 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ - crc ^= 0xffffffff; + crc = (~crc) & 0xffffffff; #ifdef W @@ -1077,7 +1086,7 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2) #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ - return multmodp(x2nmodp(len2, 3), crc1) ^ crc2; + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ @@ -1086,7 +1095,7 @@ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc2; z_off_t len2; { - return crc32_combine64(crc1, crc2, len2); + return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ @@ -1103,14 +1112,14 @@ uLong ZEXPORT crc32_combine_gen64(len2) uLong ZEXPORT crc32_combine_gen(len2) z_off_t len2; { - return crc32_combine_gen64(len2); + return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ -uLong crc32_combine_op(crc1, crc2, op) +uLong ZEXPORT crc32_combine_op(crc1, crc2, op) uLong crc1; uLong crc2; uLong op; { - return multmodp(op, crc1) ^ crc2; + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } diff --git a/erts/emulator/zlib/deflate.c b/erts/emulator/zlib/deflate.c index 799fb93cc04b..4a689db35989 100644 --- a/erts/emulator/zlib/deflate.c +++ b/erts/emulator/zlib/deflate.c @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.12 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -87,13 +87,7 @@ local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, @@ -160,7 +154,7 @@ local const config configuration_table[10] = { * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -191,9 +185,9 @@ local const config configuration_table[10] = { */ #define CLEAR_HASH(s) \ do { \ - s->head[s->hash_size-1] = NIL; \ + s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ - (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== @@ -285,6 +279,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -314,7 +310,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); @@ -340,11 +336,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is @@ -390,7 +386,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) +local int deflateStateCheck(strm) z_streamp strm; { deflate_state *s; @@ -413,7 +409,7 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; @@ -482,7 +478,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; @@ -504,7 +500,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) +int ZEXPORT deflateResetKeep(strm) z_streamp strm; { deflate_state *s; @@ -542,7 +538,7 @@ int ZEXPORT deflateResetKeep (strm) } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) +int ZEXPORT deflateReset(strm) z_streamp strm; { int ret; @@ -554,7 +550,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) +int ZEXPORT deflateSetHeader(strm, head) z_streamp strm; gz_headerp head; { @@ -565,7 +561,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) +int ZEXPORT deflatePending(strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; @@ -579,7 +575,7 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) +int ZEXPORT deflatePrime(strm, bits, value) z_streamp strm; int bits; int value; @@ -674,36 +670,50 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -740,11 +750,12 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -754,7 +765,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) +local void putShortMSB(s, b) deflate_state *s; uInt b; { @@ -801,7 +812,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) +int ZEXPORT deflate(strm, flush) z_streamp strm; int flush; { @@ -856,7 +867,7 @@ int ZEXPORT deflate (strm, flush) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1116,7 +1127,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) +int ZEXPORT deflateEnd(strm) z_streamp strm; { int status; @@ -1142,7 +1153,7 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) +int ZEXPORT deflateCopy(dest, source) z_streamp dest; z_streamp source; { @@ -1231,7 +1242,7 @@ local unsigned read_buf(strm, buf, size) /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -local void lm_init (s) +local void lm_init(s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; @@ -1252,11 +1263,6 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif } #ifndef FASTEST @@ -1269,10 +1275,6 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ @@ -1297,10 +1299,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -1318,7 +1320,8 @@ local uInt longest_match(s, cur_match) */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); @@ -1336,43 +1339,44 @@ local uInt longest_match(s, cur_match) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1382,7 +1386,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1391,7 +1395,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -1403,9 +1408,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -1415,7 +1420,6 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } -#endif /* ASMV */ #else /* FASTEST */ @@ -1436,7 +1440,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -1446,7 +1451,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1456,7 +1461,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1465,7 +1470,7 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); @@ -1501,7 +1506,7 @@ local void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1547,9 +1552,9 @@ local void fill_window(s) /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ - if (s->strstart >= wsize+MAX_DIST(s)) { + if (s->strstart >= wsize + MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; @@ -1680,7 +1685,7 @@ local void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; @@ -1890,7 +1895,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1938,7 +1943,7 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1949,7 +1954,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1993,7 +1998,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -2035,17 +2040,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -2063,8 +2068,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -2082,8 +2087,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -2140,7 +2145,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -2155,7 +2161,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2195,7 +2201,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); diff --git a/erts/emulator/zlib/deflate.h b/erts/emulator/zlib/deflate.h index 17c226113b08..1a06cd5f25d1 100644 --- a/erts/emulator/zlib/deflate.h +++ b/erts/emulator/zlib/deflate.h @@ -329,8 +329,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ - s->sym_buf[s->sym_next++] = dist; \ - s->sym_buf[s->sym_next++] = dist >> 8; \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ diff --git a/erts/emulator/zlib/inflate.c b/erts/emulator/zlib/inflate.c index 7be8c63662a7..8acbef44e993 100644 --- a/erts/emulator/zlib/inflate.c +++ b/erts/emulator/zlib/inflate.c @@ -168,6 +168,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -764,8 +766,9 @@ int flush; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); diff --git a/erts/emulator/zlib/inftrees.c b/erts/emulator/zlib/inftrees.c index 09462a740b12..57d2793bec93 100644 --- a/erts/emulator/zlib/inftrees.c +++ b/erts/emulator/zlib/inftrees.c @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.12 Copyright 1995-2022 Mark Adler "; + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/erts/emulator/zlib/inftrees.h b/erts/emulator/zlib/inftrees.h index baa53a0b1a19..f53665311c16 100644 --- a/erts/emulator/zlib/inftrees.h +++ b/erts/emulator/zlib/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. diff --git a/erts/emulator/zlib/trees.c b/erts/emulator/zlib/trees.c index f73fd99c37bd..5f305c47221e 100644 --- a/erts/emulator/zlib/trees.c +++ b/erts/emulator/zlib/trees.c @@ -193,7 +193,7 @@ local void send_bits(s, value, length) s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { @@ -256,7 +256,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -312,7 +312,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -321,7 +321,7 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header() { @@ -458,7 +458,7 @@ local void pqdownheap(s, tree, k) while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -507,7 +507,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -518,7 +518,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -530,10 +530,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -569,7 +569,7 @@ local void gen_bitlen(s, desc) * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -local void gen_codes (tree, max_code, bl_count) +local void gen_codes(tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ @@ -583,13 +583,13 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ - Assert (code + bl_count[MAX_BITS]-1 == (1<heap_len = 0, s->heap_max = HEAP_SIZE; @@ -652,7 +652,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -700,7 +700,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) +local void scan_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -714,10 +714,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -745,7 +745,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) +local void send_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -758,11 +758,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -773,13 +773,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -807,8 +807,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -819,7 +819,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -841,19 +841,19 @@ local void send_all_trees(s, lcodes, dcodes, blcodes) Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } @@ -866,7 +866,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); @@ -877,7 +877,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } @@ -943,14 +943,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -960,7 +963,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -971,21 +974,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -1004,22 +1003,22 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) +int ZLIB_INTERNAL _tr_tally(s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ { - s->sym_buf[s->sym_next++] = dist; - s->sym_buf[s->sym_next++] = dist >> 8; - s->sym_buf[s->sym_next++] = lc; + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1031,7 +1030,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); @@ -1061,7 +1060,7 @@ local void compress_block(s, ltree, dtree) } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ + send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; @@ -1177,6 +1176,6 @@ local void bi_windup(s) s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; + s->bits_sent = (s->bits_sent + 7) & ~7; #endif } diff --git a/erts/emulator/zlib/uncompr.c b/erts/emulator/zlib/uncompr.c index f03a1a865e34..f9532f46c1a6 100644 --- a/erts/emulator/zlib/uncompr.c +++ b/erts/emulator/zlib/uncompr.c @@ -24,7 +24,7 @@ Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ -int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) +int ZEXPORT uncompress2(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -83,7 +83,7 @@ int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) err; } -int ZEXPORT uncompress (dest, destLen, source, sourceLen) +int ZEXPORT uncompress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; diff --git a/erts/emulator/zlib/zconf.h b/erts/emulator/zlib/zconf.h index 5e1d68a004e9..bf977d3e70ad 100644 --- a/erts/emulator/zlib/zconf.h +++ b/erts/emulator/zlib/zconf.h @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -349,6 +352,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +473,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/erts/emulator/zlib/zlib.h b/erts/emulator/zlib/zlib.h index 4a98e38bf34c..953cb5012dc2 100644 --- a/erts/emulator/zlib/zlib.h +++ b/erts/emulator/zlib/zlib.h @@ -1,5 +1,5 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 11th, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.12" -#define ZLIB_VERNUM 0x12c0 +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 +#define ZLIB_VER_REVISION 13 #define ZLIB_VER_SUBREVISION 0 /* @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -660,7 +660,7 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -915,7 +915,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. @@ -1437,12 +1437,12 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); @@ -1913,7 +1913,7 @@ ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) diff --git a/erts/emulator/zlib/zutil.c b/erts/emulator/zlib/zutil.c index dcab28a0d517..9543ae825e32 100644 --- a/erts/emulator/zlib/zutil.c +++ b/erts/emulator/zlib/zutil.c @@ -61,9 +61,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,7 +121,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) +void ZLIB_INTERNAL z_error(m) char *m; { fprintf(stderr, "%s\n", m); @@ -214,7 +216,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,7 +242,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; @@ -277,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); @@ -302,7 +304,7 @@ extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) +voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) voidpf opaque; unsigned items; unsigned size; @@ -312,7 +314,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) +void ZLIB_INTERNAL zcfree(opaque, ptr) voidpf opaque; voidpf ptr; { diff --git a/erts/emulator/zlib/zutil.h b/erts/emulator/zlib/zutil.h index d9a20ae1bf4c..0bc7f4ecd1c0 100644 --- a/erts/emulator/zlib/zutil.h +++ b/erts/emulator/zlib/zutil.h @@ -193,6 +193,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); #endif /* common defaults */ diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c index c76f32d3cdd3..e71a0528dd44 100644 --- a/erts/epmd/src/epmd.c +++ b/erts/epmd/src/epmd.c @@ -2,7 +2,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2021. 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. @@ -253,7 +253,7 @@ static void run_daemon(EpmdVars *g) if (( child_pid = fork()) < 0) { #ifdef HAVE_SYSLOG_H - syslog(LOG_ERR,"erlang mapper daemon cant fork %m"); + syslog(LOG_ERR,"erlang mapper daemon can't fork %m"); #endif epmd_cleanup_exit(g,1); } @@ -265,7 +265,7 @@ static void run_daemon(EpmdVars *g) if (setsid() < 0) { - dbg_perror(g,"epmd: Cant setsid()"); + dbg_perror(g,"epmd: Can't setsid()"); epmd_cleanup_exit(g,1); } @@ -279,7 +279,7 @@ static void run_daemon(EpmdVars *g) if ((child_pid = fork()) < 0) { #ifdef HAVE_SYSLOG_H - syslog(LOG_ERR,"erlang mapper daemon cant fork 2'nd time %m"); + syslog(LOG_ERR,"erlang mapper daemon can't fork 2'nd time %m"); #endif epmd_cleanup_exit(g,1); } diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index e09dd0ac9512..ed2ca330741a 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -2,7 +2,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2020. All Rights Reserved. + * Copyright Ericsson AB 1998-2021. 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. @@ -50,15 +50,9 @@ #include #ifndef __WIN32__ -# ifdef TIME_WITH_SYS_TIME -# include -# include -# else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif +# include +# ifdef HAVE_SYS_TIME_H +# include # endif #endif diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 52fb9e47f368..77b0a25fc8d4 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -2,7 +2,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2022. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -559,7 +559,7 @@ void run(EpmdVars *g) /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() - * could succeed. Go do do another select(), in case there + * could succeed. Go do another select(), in case there * are more incoming connections waiting to be accepted. */ goto select_again; @@ -745,12 +745,7 @@ static unsigned int get_creation(Node* node) /* buf is actually one byte larger than bsize, giving place for null termination */ -static void do_request(g, fd, s, buf, bsize) - EpmdVars *g; - int fd; - Connection *s; - char *buf; - int bsize; +static void do_request(EpmdVars *g, int fd, Connection *s, char *buf, int bsize) { char wbuf[OUTBUF_SIZE]; /* Buffer for writing */ int i; diff --git a/erts/epmd/test/epmd.spec.vxworks b/erts/epmd/test/epmd.spec.vxworks deleted file mode 100644 index 476308b4812f..000000000000 --- a/erts/epmd/test/epmd.spec.vxworks +++ /dev/null @@ -1,2 +0,0 @@ -{topcase, {dir, "../epmd_test"}}. -{skip,{epmd_rx_SUITE,"EPMD RX does simply not work on VxWorks"}}. diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl index e0dc61878a8a..b7240ffa299f 100644 --- a/erts/epmd/test/epmd_SUITE.erl +++ b/erts/epmd/test/epmd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2017. All Rights Reserved. +%% Copyright Ericsson AB 1998-2021. 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. @@ -737,7 +737,7 @@ alltrue([_|_]) -> false. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Ensure that we cannot register throug a nonlocal connection +%% Ensure that we cannot register through a nonlocal connection no_nonlocal_register(Config) when is_list(Config) -> case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of {SSH,Name} when is_list(Name), is_list(SSH) -> diff --git a/erts/etc/Makefile b/erts/etc/Makefile index 788dfff13226..b482e08d8f97 100644 --- a/erts/etc/Makefile +++ b/erts/etc/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2016. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -18,6 +18,7 @@ # %CopyrightEnd% # include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk SUB_DIRECTORIES = common ifeq ($(TARGET),win32) diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index e5ff9590782f..3c5a5cee64ba 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -168,7 +168,6 @@ INSTALL_PROGS = \ $(BINDIR)/erlsrv.exe \ $(BINDIR)/erl.exe \ $(BINDIR)/erl_log.exe\ - $(BINDIR)/werl.exe \ $(BINDIR)/$(ERLEXEC) \ $(INSTALL_EMBEDDED_PROGS) @@ -216,6 +215,12 @@ INSTALL_PROGS = \ $(INSTALL_EMBEDDED_PROGS) endif +CREATE_DIRS=$(OBJDIR) $(BINDIR) + +ifneq ($(strip $(CREATE_DIRS)),) +_create_dirs := $(shell mkdir -p $(CREATE_DIRS)) +endif + .PHONY: etc etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(EXTRA_LIBS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) @@ -267,13 +272,12 @@ endif rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl_log.o - rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/werl.o rm -f $(TEXTFILES) rm -f *~ core #------------------------------------------------------------------------ # Windows specific targets -# The windows platform is quite different from the others. erl/werl are small C programs +# The windows platform is quite different from the others. erl are small C programs # loading a DLL. INI files are used instead of environment variables and the Install # script is actually a program, also Install has an INI file which tells of emulator # versions etc. @@ -287,9 +291,6 @@ $(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init $(BINDIR)/erl@EXEEXT@: $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) -$(BINDIR)/werl@EXEEXT@: $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) - $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) - $(BINDIR)/erl_log@EXEEXT@: $(OBJDIR)/erl_log.o $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl_log.o @@ -336,11 +337,14 @@ OTP_VSN_COMMA_SEP := $(wordlist 1,4, $(OTP_VSN_COMMA_SEP)) ERTS_VSN_COMMA_SEP := $(subst $(SPACE_CHAR),$(COMMA_CHAR),$(ERTS_VSN_COMMA_SEP)) OTP_VSN_COMMA_SEP := $(subst $(SPACE_CHAR),$(COMMA_CHAR),$(OTP_VSN_COMMA_SEP)) +YEAR := $(shell date +%Y) + $(WINETC)/version.h: $(WINETC)/version.h.src $(vsn_verbose)sed -e 's;%ERTS_VERSION%;$(VSN);' \ -e 's;%ERTS_VERSION_INTS%;$(ERTS_VSN_COMMA_SEP);' \ -e 's;%OTP_VERSION%;$(OTP_VERSION);' \ -e 's;%OTP_VERSION_INTS%;$(OTP_VSN_COMMA_SEP);' \ + -e 's;%YEAR%;$(YEAR);' \ $(WINETC)/version.h.src > $(WINETC)/version.h $(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico \ @@ -367,10 +371,6 @@ $(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \ $(OBJDIR)/erlsrv_logmess.h $(RC_GENERATED) $(V_CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $< -$(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ - -DWIN32_WERL -o $@ -c $(WINETC)/erl.c - $(OBJDIR)/erl_log.o: $(WINETC)/erl_log.c $(RC_GENERATED) $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(WINETC)/erl_log.c @@ -517,6 +517,8 @@ erl.src: $(UXETC)/erl.src.src ../../vsn.mk $(TARGET)/Makefile $(vsn_verbose)sed -e 's;%EMULATOR%;$(EMULATOR);' \ -e 's;%EMULATOR_NUMBER%;$(EMULATOR_NUMBER);' \ -e 's;%VSN%;$(VSN);' \ + -e 's;%DYN_ERL_PATH%;../erts-$(VSN)/bin/dyn_erl;' \ + -e 's;%DYN_ROOTDIR_BASE_EXT%;;' \ $(UXETC)/erl.src.src > erl.src # ---------------------------------------------------- diff --git a/erts/etc/common/ct_run.c b/erts/etc/common/ct_run.c index 0e9c2bea8350..bea4892ce21e 100644 --- a/erts/etc/common/ct_run.c +++ b/erts/etc/common/ct_run.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2021. All Rights Reserved. + * Copyright Ericsson AB 2010-2023. 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. @@ -77,7 +77,6 @@ static void* emalloc(size_t size); static void efree(void *p); #endif static char* strsave(char* string); -static void push_words(char* src); static int run_erlang(char* name, char** argv); static char* get_default_emulator(char* progname); #ifdef __WIN32__ @@ -187,8 +186,7 @@ int main(int argc, char** argv) eargv_base = (char **) emalloc(eargv_size*sizeof(char*)); eargv = eargv_base; eargc = 0; - push_words(emulator); - free(emulator); + PUSH(emulator); eargc_base = eargc; eargv = eargv + eargv_size/2; eargc = 0; @@ -319,26 +317,6 @@ int main(int argc, char** argv) return run_erlang(eargv[0], eargv); } -static void -push_words(char* src) -{ - char sbuf[MAXPATHLEN]; - char* dst; - - dst = sbuf; - while ((*dst++ = *src++) != '\0') { - if (isspace((int)*src)) { - *dst = '\0'; - PUSH(strsave(sbuf)); - dst = sbuf; - do { - src++; - } while (isspace((int)*src)); - } - } - if (sbuf[0]) - PUSH(strsave(sbuf)); -} #ifdef __WIN32__ wchar_t *make_commandline(char **argv) { diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c index 6cded377334b..1493c6f6ffa9 100644 --- a/erts/etc/common/erlc.c +++ b/erts/etc/common/erlc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2021. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -742,14 +742,16 @@ call_compile_server(char** argv) ei_x_encode_atom(&args, "encoding"); ei_x_encode_atom(&args, get_encoding()); ei_x_encode_atom(&args, "cwd"); - ei_x_encode_string(&args, cwd); + ei_x_encode_binary(&args, cwd, strlen(cwd)); ei_x_encode_atom(&args, "env"); encode_env(&args); ei_x_encode_atom(&args, "command_line"); argc = 0; while (argv[argc]) { + char *arg; ei_x_encode_list_header(&args, 1); - ei_x_encode_string(&args, possibly_unquote(argv[argc])); + arg = possibly_unquote(argv[argc]); + ei_x_encode_binary(&args, arg, strlen(arg)); argc++; } ei_x_encode_empty_list(&args); /* End of command_line */ @@ -773,7 +775,6 @@ call_compile_server(char** argv) /* * Decode the answer. */ - dec_index = 0; if (ei_decode_atom(reply.buff, &dec_index, atom) == 0 && strcmp(atom, "wrong_config") == 0) { diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index bda9a94a9549..888df87e3507 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2022. 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. @@ -39,14 +39,12 @@ #define DIRSEP "\\" #define PATHSEP ";" #define NULL_DEVICE "nul" -#define BINARY_EXT "" #define DLL_EXT ".dll" #define EMULATOR_EXECUTABLE "beam.dll" #else #define PATHSEP ":" #define DIRSEP "/" #define NULL_DEVICE "/dev/null" -#define BINARY_EXT "" #define EMULATOR_EXECUTABLE "beam" #endif @@ -77,6 +75,7 @@ static char *plusM_au_alloc_switches[] = { "acul", "acnl", "acfml", + "acful", "cp", "e", "t", @@ -104,7 +103,6 @@ static char *plusM_other_switches[] = { "usac", "im", "is", - "it", "lpm", "Mamcbf", "Mrmcbf", @@ -154,6 +152,7 @@ static char *plush_val_switches[] = { "max", "maxk", "maxel", + "maxib", "mqd", "", NULL @@ -219,7 +218,6 @@ static char* possibly_quote(char* arg); /* * Functions from win_erlexec.c */ -int start_win_emulator(char* emu, char *startprog,char** argv, int start_detached); int start_emulator(char* emu, char*start_prog, char** argv, int start_detached); #endif @@ -247,7 +245,7 @@ static const char* emu_flavor = DEFAULT_SUFFIX; /* Flavor of emulator (smp, jit #ifdef __WIN32__ static char *start_emulator_program = NULL; /* For detached mode - - erl.exe/werl.exe */ + erl.exe */ static char* key_val_name = ERLANG_VERSION; /* Used by the registry * access functions. */ @@ -257,7 +255,6 @@ static int config_script_cnt = 0; static int got_start_erl = 0; static HANDLE this_module_handle; -static int run_werl; static WCHAR *utf8_to_utf16(unsigned char *bytes); static char *utf16_to_utf8(WCHAR *wstr); static WCHAR *latin1_to_utf16(char *str); @@ -415,7 +412,7 @@ static void add_boot_config(void) #define NEXT_ARG_CHECK() NEXT_ARG_CHECK_NAMED(argv[i]) #ifdef __WIN32__ -__declspec(dllexport) int win_erlexec(int argc, char **argv, HANDLE module, int windowed) +__declspec(dllexport) int win_erlexec(int argc, char **argv, HANDLE module) #else int main(int argc, char **argv) #endif @@ -436,7 +433,6 @@ int main(int argc, char **argv) #ifdef __WIN32__ this_module_handle = module; - run_werl = windowed; /* if we started this erl just to get a detached emulator, * the arguments are already prepared for beam, so we skip * directly to start_emulator */ @@ -454,21 +450,18 @@ int main(int argc, char **argv) Eargsp[argc] = NULL; emu = argv[0]; start_emulator_program = strsave(argv[0]); - goto skip_arg_massage; - } - free_env_val(s); -#else - int reset_cerl_detached = 0; - - s = get_env("CERL_DETACHED_PROG"); - if (s && strcmp(s, "") != 0) { - emu = s; - start_detached = 1; - reset_cerl_detached = 1; - ensure_EargsSz(argc + 1); - memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *)); - Eargsp[argc] = emu; - Eargsp[argc] = NULL; + /* We set the stdandard handles to nul in order for prim_tty_nif + and erlang:display_string to work without returning ebadf for + detached emulators */ + SetStdHandle(STD_INPUT_HANDLE, + CreateFile("nul", GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)); + SetStdHandle(STD_OUTPUT_HANDLE, + CreateFile("nul", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)); + SetStdHandle(STD_ERROR_HANDLE, + CreateFile("nul", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)); goto skip_arg_massage; } free_env_val(s); @@ -538,7 +531,7 @@ int main(int argc, char **argv) emu = add_extra_suffixes(emu); emu_name = strsave(emu); - erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s" BINARY_EXT, bindir, emu); + erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s", bindir, emu); emu = strsave(tmpStr); s = get_env("ESCRIPT_NAME"); @@ -666,13 +659,12 @@ int main(int argc, char **argv) break; case 'd': - if (strcmp(argv[i], "-detached") != 0) { - add_arg(argv[i]); - } else { - start_detached = 1; - add_args("-noshell", "-noinput", NULL); - } - break; + add_arg(argv[i]); + if (strcmp(argv[i], "-detached") == 0) { + start_detached = 1; + add_args("-noshell", "-noinput", NULL); + } + break; case 'e': if (strcmp(argv[i], "-extra") == 0) { @@ -876,6 +868,16 @@ int main(int argc, char **argv) i++; break; } + if (argv[i][2] == 'O' && argv[i][3] == 's') { + if (argv[i][4] != '\0') + goto the_default; + NEXT_ARG_CHECK(); + argv[i][0] = '-'; + add_Eargs(argv[i]); + add_Eargs(argv[i+1]); + i++; + break; + } usage(argv[i]); break; case 'J': @@ -1005,8 +1007,10 @@ int main(int argc, char **argv) } break; case 'p': - if (argv[i][2] != 'c' || argv[i][3] != '\0') + if (!(argv[i][2] == 'c' && argv[i][3] == '\0') + && !(argv[i][2] == 'a' && argv[i][3] == 'd' && argv[i][4] == '\0')) { goto the_default; + } NEXT_ARG_CHECK(); argv[i][0] = '-'; add_Eargs(argv[i]); @@ -1081,6 +1085,8 @@ int main(int argc, char **argv) add_Eargs("--"); add_Eargs("-root"); add_Eargs(rootdir); + add_Eargs("-bindir"); + add_Eargs(bindir); add_Eargs("-progname"); add_Eargs(progname); add_Eargs("--"); @@ -1120,36 +1126,15 @@ int main(int argc, char **argv) skip_arg_massage: /*DebugBreak();*/ - if (run_werl) { - if (start_detached) { - char *p; - /* transform werl to erl */ - p = start_emulator_program+strlen(start_emulator_program); - while (--p >= start_emulator_program && *p != '/' && *p != '\\' && - *p != 'W' && *p != 'w') - ; - if (p >= start_emulator_program && (*p == 'W' || *p == 'w') && - (p[1] == 'E' || p[1] == 'e') && (p[2] == 'R' || p[2] == 'r') && - (p[3] == 'L' || p[3] == 'l')) { - memmove(p,p+1,strlen(p)); - } - } - return start_win_emulator(emu, start_emulator_program, Eargsp, start_detached); - } else { - return start_emulator(emu, start_emulator_program, Eargsp, start_detached); - } + return start_emulator(emu, start_emulator_program, Eargsp, start_detached); #else - skip_arg_massage: if (start_detached) { int status = fork(); if (status != 0) /* Parent */ return 0; - if (reset_cerl_detached) - putenv("CERL_DETACHED_PROG="); - /* Detach from controlling terminal */ #ifdef HAVE_SETSID setsid(); @@ -1239,7 +1224,7 @@ usage_aux(void) "[-emu_type TYPE] [-emu_flavor FLAVOR] " "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] " "[+C MODE] [+dcg DECENTRALIZED_COUNTER_GROUPS_LIMIT] [+h HEAP_SIZE_OPTION] " - "[+J[Pperf] JIT_OPTION] " + "[+J[Pperf|Msingle] JIT_OPTION] " "[+M ] [+P MAX_PROCS] [+Q MAX_PORTS] " "[+R COMPAT_REL] " "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] " @@ -1607,6 +1592,14 @@ static void get_parameters(int argc, char** argv) emu = EMULATOR_EXECUTABLE; start_emulator_program = strsave(argv[0]); + /* in wsl argv[0] is given as "erl.exe", but start_emulator_program should be + an absolute path, so we prepend BINDIR to it */ + if (strcmp(start_emulator_program, "erl.exe") == 0) { + erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s", bindir, + start_emulator_program); + start_emulator_program = strsave(tmpStr); + } + free(ini_filename); } @@ -1713,7 +1706,7 @@ static char **build_args_from_string(char *string, int allow_comments) { int argc = 0; char **argv = NULL; - int alloced = 0; + int allocated = 0; char **cur_s = NULL; /* Initialized to avoid warning. */ int s_alloced = 0; int s_pos = 0; @@ -1732,15 +1725,15 @@ static char **build_args_from_string(char *string, int allow_comments) if (!p) return NULL; - argv = emalloc(sizeof(char *) * (alloced = 10)); + argv = emalloc(sizeof(char *) * (allocated = 10)); state = Start; for(;;) { switch (state) { case Start: if (!*p) goto done; - if (argc >= alloced - 2) { /* Make room for extra NULL and "--" */ - argv = erealloc(argv, (alloced += 10) * sizeof(char *)); + if (argc >= allocated - 2) { /* Make room for extra NULL and "--" */ + argv = erealloc(argv, (allocated += 10) * sizeof(char *)); } cur_s = argc + argv; *cur_s = NULL; diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c index 078937e67698..c7418b2ace39 100644 --- a/erts/etc/common/escript.c +++ b/erts/etc/common/escript.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2018. All Rights Reserved. + * Copyright Ericsson AB 2007-2023. 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. @@ -286,7 +286,7 @@ find_prog(char *origpath) beg = end + 1; continue; } - strncpy(dir, beg, sz); + memcpy(dir, beg, sz); dir[sz] = '\0'; beg = end + 1; @@ -510,8 +510,8 @@ main(int argc, char** argv) PUSH(emulator); PUSH("+B"); - PUSH2("-boot", "no_dot_erlang"); PUSH("-noshell"); + PUSH2("-boot", "no_dot_erlang"); /* * Read options from the %%! row in the script and add them as args diff --git a/erts/etc/common/etc_common.h b/erts/etc/common/etc_common.h index 6e4c326ae632..8f6398fa71bc 100644 --- a/erts/etc/common/etc_common.h +++ b/erts/etc/common/etc_common.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2017-2021. All Rights Reserved. + * Copyright Ericsson AB 2017-2023. 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. @@ -35,6 +35,7 @@ # include # include # include +# include // _getcwd #endif #include @@ -59,11 +60,18 @@ #include "erl_printf.h" #ifdef __WIN32__ -/* FIXE ME config_win32.h? */ +/* FIXME config_win32.h? */ #define HAVE_STRERROR 1 #define snprintf _snprintf #endif +#ifdef __IOS__ +#ifdef system +#undef system +#endif +#define system(X) 0 +#endif + #ifdef DEBUG # define ASSERT(Cnd) ((void)((Cnd) ? 1 : abort())) #else diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index de50eb88c837..e8ddaf8ae002 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -63,7 +63,7 @@ * This program communicates with Erlang through the standard * input and output file descriptors (0 and 1). These descriptors * (and the standard error descriptor 2) must NOT be closed - * explicitely by this program at termination (in UNIX it is + * explicitly by this program at termination (in UNIX it is * taken care of by the operating system itself). * * END OF FILE @@ -74,16 +74,7 @@ * */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef __WIN32__ -#include -#include -#include -#include -#endif +#include "etc_common.h" /* * Implement time correction using times() call even on Linuxes @@ -91,13 +82,7 @@ * a phony gethrtime in this file as the time questions are so infrequent. */ -#include #include -#include - -#include - -#include #include #include @@ -350,7 +335,7 @@ int main(int argc, char **argv) { AllocConsole(); conh = freopen("CONOUT$","w",stderr); if (conh != NULL) - fprintf(conh,"console alloced\n"); + fprintf(conh,"console allocated\n"); } debugf("stderr\n"); } @@ -369,8 +354,7 @@ int main(int argc, char **argv) { * message loop */ static int -message_loop(erlin_fd, erlout_fd) - int erlin_fd, erlout_fd; +message_loop(int erlin_fd, int erlout_fd) { int i; time_t now, last_received; @@ -423,7 +407,7 @@ message_loop(erlin_fd, erlout_fd) #endif /* * Maybe heart beat time-out - * If we havn't got anything in 60 seconds we reboot, even if we may + * If we haven't got anything in 60 seconds we reboot, even if we may * have got something in the last 5 seconds. We may end up here if * the system clock is adjusted with more than 55 seconds, but we * regard this as en error and reboot anyway. @@ -689,7 +673,7 @@ do_terminate(int erlin_fd, int reason) { case R_ERROR: default: { -#if defined(__WIN32__) /* Not VxWorks */ +#if defined(__WIN32__) if(!cmd[0]) { char *command = get_env(HEART_COMMAND_ENV); if(!command) @@ -791,8 +775,7 @@ int wait_until_close_write_or_env_tmo(int tmo) { * Sends an HEART_ACK. */ static int -notify_ack(fd) - int fd; +notify_ack(int fd) { struct msg m; @@ -839,9 +822,7 @@ heart_cmd_reply(int fd, char *s) * FIXME. */ static int -write_message(fd, mp) - int fd; - struct msg *mp; +write_message(int fd, struct msg *mp) { int len = ntohs(mp->len); @@ -868,9 +849,7 @@ write_message(fd, mp) * message. */ static int -read_message(fd, mp) - int fd; - struct msg *mp; +read_message(int fd, struct msg *mp) { int rlen, i; unsigned char* tmp; @@ -906,9 +885,7 @@ read_message(fd, mp) * bytes read (i.e. len) , 0 if eof, or < 0 if error. len must be > 0. */ static int -read_fill(fd, buf, len) - int fd, len; - char *buf; +read_fill(int fd, char *buf, int len) { int i, got = 0; @@ -929,9 +906,7 @@ read_fill(fd, buf, len) * 0 if eof, or < 0 if error. len > maxlen > 0 must hold. */ static int -read_skip(fd, buf, maxlen, len) - int fd, maxlen, len; - char *buf; +read_skip(int fd, char *buf, int maxlen, int len) { int i, got = 0; char c; diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c index 60a4073d1e6b..422384c17928 100644 --- a/erts/etc/common/inet_gethost.c +++ b/erts/etc/common/inet_gethost.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2021. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -973,7 +973,7 @@ static void main_loop(void) } if (BEE_GREEDY()) { - DEBUGF(4,("Beeing greedy!")); + DEBUGF(4,("Being greedy!")); if ((cw = pick_worker_greedy(domainbuff)) != NULL) { /* Put it in the worker specific que if the domainname matches... */ @@ -1483,7 +1483,7 @@ static int ignore_reply(Worker *pw) #endif /* !WIN32 */ /* - * Domain name "parsing" and worker specific queing + * Domain name "parsing" and worker specific queueing */ static void domaincopy(AddrByte *out, AddrByte *in) { @@ -1754,12 +1754,11 @@ static int worker_loop(void) /* Decode the request... */ serial = get_serial(req); if (OP_CONTROL == (op = get_op(req))) { - CtlType ctl; if (serial != INVALID_SERIAL) { DEBUGF(1, ("Worker got invalid serial: %d.", serial)); exit(0); } - switch (ctl = get_ctl(req)) { + switch (get_ctl(req)) { case SETOPT_DEBUG_LEVEL: debug_level = get_debug_level(req); DEBUGF(debug_level, @@ -2333,7 +2332,7 @@ static int read_exact(HANDLE fd, void *vbuff, DWORD nbytes, HANDLE ev) } } } else { - DEBUGF(4,("Read completed syncronously, result %d",ret)); + DEBUGF(4,("Read completed synchronously, result %d",ret)); } if (ret == 0) { DEBUGF(1, ("End of file detected as zero read from pipe.")); @@ -2369,7 +2368,7 @@ static int write_exact(HANDLE fd, AddrByte *buff, DWORD len, HANDLE ev) stat = WriteFile(fd,buff,x,&res,&ov); if (!stat) { if ((err = GetLastError()) == ERROR_IO_PENDING) { - DEBUGF(4,("Overlapped write, waiting for competion...")); + DEBUGF(4,("Overlapped write, waiting for completion...")); WaitForSingleObject(ov.hEvent,INFINITE); stat = GetOverlappedResult(fd,&ov,&res,TRUE); DEBUGF(4,("Overlapped write, completed with status %d," @@ -2383,7 +2382,7 @@ static int write_exact(HANDLE fd, AddrByte *buff, DWORD len, HANDLE ev) } } } else { - DEBUGF(4,("Write completed syncronously, result %d",res)); + DEBUGF(4,("Write completed synchronously, result %d",res)); } if (res < x) { diff --git a/erts/etc/darwin/Info.plist b/erts/etc/darwin/Info.plist deleted file mode 100644 index 38965245885d..000000000000 --- a/erts/etc/darwin/Info.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - NSAppTransportSecurity - - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - NSIncludesSubdomains - - - - - - diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src index 7437e073e067..b00dd09f1aca 100644 --- a/erts/etc/unix/Install.src +++ b/erts/etc/unix/Install.src @@ -81,7 +81,9 @@ chmod 755 erl # Create start file for embedded system use, # (cd "$ERL_ROOT/erts-%I_VSN%/bin"; - sed -e "s;%FINAL_ROOTDIR%;$TARGET_ERL_ROOT;" start.src > start; + sed -e "s;%FINAL_ROOTDIR%;$TARGET_ERL_ROOT;" \ + -e "s;%VSN%;%I_VSN%;" \ + start.src > start; chmod 755 start) cd "$ERL_ROOT/bin" @@ -111,10 +113,9 @@ cp -p "$ERL_ROOT/erts-%I_VSN%/bin/to_erl" . cp -p "$ERL_ROOT/erts-%I_VSN%/bin/start" . sed -e "s;%EMU%;%EMULATOR%%EMULATOR_NUMBER%;" "$ERL_ROOT/erts-%I_VSN%/bin/start_erl.src" > start_erl chmod 755 start_erl -echo "" echo %I_VSN% %I_SYSTEM_VSN% > "$ERL_ROOT/releases/start_erl.data" -sed -e "s;%ERL_ROOT%;$TARGET_ERL_ROOT;" "$ERL_ROOT/releases/RELEASES.src" > "$ERL_ROOT/releases/RELEASES" +sed -e "s;%ERL_ROOT%/;;" "$ERL_ROOT/releases/RELEASES.src" > "$ERL_ROOT/releases/RELEASES" if [ "$start_option" = "query" ] then diff --git a/erts/etc/unix/Makefile b/erts/etc/unix/Makefile index bd1c6d541172..179cce765ff6 100644 --- a/erts/etc/unix/Makefile +++ b/erts/etc/unix/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2013-2020. All Rights Reserved. +# Copyright Ericsson AB 2013-2022. 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. @@ -24,7 +24,7 @@ include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk include ../../vsn.mk -opt debug lcnt: etc +$(TYPES): etc .PHONY: etc etc: etp-commands diff --git a/erts/etc/unix/RELNOTES b/erts/etc/unix/RELNOTES index 7b4a1746fef1..97aec2b10079 100644 --- a/erts/etc/unix/RELNOTES +++ b/erts/etc/unix/RELNOTES @@ -1,7 +1,7 @@ %CopyrightBegin% - Copyright Ericsson AB 1996-2016. All Rights Reserved. + Copyright Ericsson AB 1996-2021. 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. @@ -191,9 +191,9 @@ the 4.2 system, but there is a number of incompatibilities. could fail after a large series of printouts without any newlines "\n" at all. --- Formating of floats: a '9' would sometimes become a ':'. +-- Formatting of floats: a '9' would sometimes become a ':'. --- Formating with the use of '*' and negativ size fields now work +-- Formatting with the use of '*' and negative size fields now work as expected. -- The format of the 'EXIT' values is now ALWAYS the same @@ -264,7 +264,7 @@ QNX -- The 4.3 system is not object code compatible with 4.2. This means that all source code has to be recompiled. It is not possible to load 4.2 object code. It is also not - possible to run distribution between 4.3 and erlier versions + possible to run distribution between 4.3 and earlier versions due to the new alive check. -- The external term format has been changed. This will only affect diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src index d74d008c5130..05deeea3e363 100644 --- a/erts/etc/unix/cerl.src +++ b/erts/etc/unix/cerl.src @@ -47,6 +47,8 @@ # -icount Run emulator compiled for instruction counting # -rr Run emulator under "rr record" # Can be combined with compile targets (like -debug) except valgrind. +# -rr replay|eplay [rr-replay-options] +# Run "rr replay" without or with emacs # -nox Unset the DISPLAY variable to disable us of X Windows # # FIXME For GDB you can also set the break point using "-break FUNCTION". @@ -81,9 +83,28 @@ run_asan=no run_rr=no skip_erlexec=no +prog="$0" +progdir="`dirname ${prog}`" +dyn_erl_path="${progdir}/%DYN_ERL_PATH%" +if [ -f "$dyn_erl_path" ] +then + dyn_rootdir=`${dyn_erl_path} --realpath` + dyn_rootdir=`dirname ${dyn_rootdir}` + dyn_rootdir=`dirname ${dyn_rootdir}` +else + dyn_rootdir="" +fi + # Default rootdir ROOTDIR=%SRC_ROOTDIR% -BINDIR="$ROOTDIR/bin/`$ROOTDIR/erts/autoconf/config.guess`" + +if [ "$dyn_rootdir" != "$ROOTDIR" ] && [ "$dyn_rootdir" != "" ] +then + # It is likely that the files have been copied or moved + ROOTDIR="$dyn_rootdir" +fi + +BINDIR="$ROOTDIR/bin/`$ROOTDIR/make/autoconf/config.guess`" TARGET=%TARGET% #BINDIR="$ROOTDIR/bin/%TARGET%" PROGNAME=$ROOTDIR/bin/cerl @@ -233,7 +254,7 @@ while [ $# -gt 0 ]; do cargs="$cargs -rr" run_rr=yes case "$1" in - "replay"|"ps") + "replay"|"eplay"|"ps") ;; *) skip_erlexec=yes @@ -380,15 +401,21 @@ if [ "x$GDB" = "x" ]; then exec $taskset1 valgrind $valgrind_xml $valgrind_log $vgflags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@" fi elif [ $run_rr = yes ]; then - if [ $1 = replay ]; then + if [ $1 = replay ] || [ $1 = eplay ]; then + rr_cmd=$1 shift cmdfile="/tmp/.cerlgdb.$$" echo "set \$etp_beam_executable = \"$BINDIR/$EMU_NAME\"" > $cmdfile if [ "$1" = "-p" ]; then echo 'set $etp_rr_run_until_beam = 1' >> $cmdfile fi - cat $ROOTDIR/erts/etc/unix/etp-commands >> $cmdfile - exec rr replay -x $cmdfile $* + echo "source $ROOTDIR/erts/etc/unix/etp-commands" >> $cmdfile + if [ $rr_cmd = replay ]; then + exec rr replay -x $cmdfile $* + else + # eplay + exec emacs -eval "(progn (gdb \"rr replay -i=mi -x $cmdfile $*\"))" + fi elif [ $1 = ps ]; then shift rr ps $* | head -1 @@ -414,7 +441,7 @@ elif [ "x$GDB" = "xgdb" ]; then case "x$core" in x) # Get emu args to use from erlexec... - beam_args=`$EXEC -emu_args_exit ${1+"$@"}` + beam_args=`$EXEC -emu_args_exit $xargs ${1+"$@"}` gdbcmd="--args $EMU_NAME $beam_args" ;; x/*) @@ -434,7 +461,7 @@ elif [ "x$GDB" = "xgdb" ]; then elif [ "x$GDB" = "xlldb" ]; then case "x$core" in x) - beam_args=`$EXEC -emu_args_exit ${1+"$@"}` + beam_args=`$EXEC -emu_args_exit $xargs ${1+"$@"}` lldbcmd="-- $beam_args" ;; *) diff --git a/erts/etc/unix/dyn_erl.c b/erts/etc/unix/dyn_erl.c index 60817d7e651f..28f56d645d35 100644 --- a/erts/etc/unix/dyn_erl.c +++ b/erts/etc/unix/dyn_erl.c @@ -362,6 +362,15 @@ main(int argc, char **argv) char progname[PATH_MAX]; /* Name of this program. */ char erlexec[PATH_MAX]; /* Path to erlexec */ + if (argc == 2 && strcmp(argv[1], "--realpath") == 0) { + abspath = find_prog(argv[0]); + /* Remove program name from output */ + for (p = abspath+strlen(abspath)-1;p >= abspath && *p != '/'; --p) + ; + *p = '\0'; + printf("%s", abspath); + return 0; + } /* Determine progname */ abspath = find_prog(argv[0]); strcpy(progname, abspath); diff --git a/erts/etc/unix/erl.src.src b/erts/etc/unix/erl.src.src index 0983132ac157..536fa139d995 100644 --- a/erts/etc/unix/erl.src.src +++ b/erts/etc/unix/erl.src.src @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -18,15 +18,38 @@ # # %CopyrightEnd% # +prog="$0" +progdir=`dirname "${prog}"` +dyn_erl_path="${progdir}/%DYN_ERL_PATH%" +if [ ! -f "$dyn_erl_path" ] +then + dyn_erl_path="${progdir}/dyn_erl" +fi + +if [ -f "$dyn_erl_path" ] +then + dyn_rootdir=`"${dyn_erl_path}" --realpath` + dyn_rootdir=`dirname "${dyn_rootdir}"` + dyn_rootdir=`dirname "${dyn_rootdir}"` + dyn_rootdir="${dyn_rootdir}%DYN_ROOTDIR_BASE_EXT%" +else + dyn_rootdir="" +fi + if [ -z "$ERL_ROOTDIR" ] then ROOTDIR="%FINAL_ROOTDIR%" + if [ "$dyn_rootdir" != "$ROOTDIR" ] && [ "$dyn_rootdir" != "" ] + then + # It is likely that the files have been copied or moved + ROOTDIR="$dyn_rootdir" + fi else ROOTDIR="$ERL_ROOTDIR" fi -BINDIR=$ROOTDIR/erts-%VSN%/bin +BINDIR="$ROOTDIR/erts-%VSN%/bin" EMU=%EMULATOR%%EMULATOR_NUMBER% -PROGNAME=`echo $0 | sed 's/.*\///'` +PROGNAME=`basename "$0"` export EMU export ROOTDIR export BINDIR diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index 179d0a041ea5..0e764c24307b 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -54,9 +54,9 @@ document etp-help % % Special commands for not really terms: % etp-mfa, etp-cp, etp-disasm, -% etp-msgq, etpf-msgq, -% etp-stacktrace, etp-stacktrace-emu, etp-stackdump, etp-stackdump-emu, -% etpf-stackdump, etp-dictdump +% etp-msgq, etpf-msgq, +% etp-stacktrace, etp-stacktrace-emu, etp-stacktrace-jit, +% etp-stackdump, etp-stackdump-emu, etpf-stackdump, etp-dictdump % etp-process-info, etp-process-info-x, etp-process-memory-info % etp-port-info, etp-port-state, etp-port-sched-flags % etp-heapdump, etp-offheapdump, etpf-offheapdump, @@ -67,8 +67,8 @@ document etp-help % etp-overlapped-heaps, etp-chart, etp-chart-start, etp-chart-end % % System inspection -% etp-system-info, etp-schedulers, etp-process, etp-ports, etp-lc-dump, -% etp-migration-info, etp-processes, etp-processes-x, etp-processes-memory, +% etp-system-info, etp-schedulers, etp-processes, etp-processes-x, etp-ports, +% etp-lc-dump, etp-migration-info, etp-processes-memory, % etp-compile-info, etp-config-h-info % % Platform specific (when gdb fails you) @@ -140,7 +140,7 @@ define etp-1 else if (($arg0) & 0x3) == 2 if $etp_flat - printf "", (($arg0) etp_ptr_mask) + printf "", (($arg0) & etp_ptr_mask) else etp-boxed-1 ($arg0) ($arg1) end @@ -1154,17 +1154,24 @@ document etp-mfa % % Take an Eterm* to an MFA function name entry and print it. % These can be found e.g in the process structure; -% process_tab[i]->current and process_tab[i]->initial. +% ((Process*)erts_proc->r.o.tab[i])->current and &(((Process*)erts_proc->r.o.tab[i])->u.initial) %--------------------------------------------------------------------------- end define etp-export-get - # Args: Eterm Eterm Uint + # Args: M F A [code_ix] set $etp_h = (((Eterm)$arg0 >> 6) * ((Eterm)$arg1 >> 6)) ^ (Uint)$arg2 + if $argc == 3 + set $etp_code_ix = the_active_code_index.counter + end + if $argc == 4 + set $etp_code_ix = $arg3 + end + #hash_get_slot - set $etp_t = &export_tables[the_active_code_index.counter].htable + set $etp_t = &export_tables[$etp_code_ix].htable set $etp_h ^= $etp_h >> $etp_t->shift if $etp_arch64 set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift @@ -1188,9 +1195,10 @@ end document etp-export-get %--------------------------------------------------------- -% etp-export-get module function arity +% etp-export-get module function arity [code_ix] % % Lookup and print pointer to Export entry. +% code_ix is optional, default is the_active_code_index % Example: % (gdb) etp-string-to-atom "erlang" % $1 = 13323 @@ -1207,8 +1215,15 @@ define etp-module-get set $etp_ix = ((Eterm)$arg0 >> 6) set $etp_h = $etp_ix + if $argc == 1 + set $etp_code_ix = the_active_code_index.counter + end + if $argc == 2 + set $etp_code_ix = $arg1 + end + #hash_get_slot - set $etp_t = &module_tables[the_active_code_index.counter].htable + set $etp_t = &module_tables[$etp_code_ix].htable set $etp_h ^= $etp_h >> $etp_t->shift if $etp_arch64 set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift @@ -1232,9 +1247,10 @@ end document etp-module-get %--------------------------------------------------------- -% etp-module-get module +% etp-module-get module [code_ix] % % Lookup and print pointer to Module entry. +% code_ix is optional, default is the_active_code_index % Example: % (gdb) etp-string-to-atom "erlang" % $1 = 13323 @@ -1243,19 +1259,67 @@ document etp-module-get %--------------------------------------------------------- end +define etp-cp-line-info +# Args: code_header mfa function_index cp +# +# Non-reentrant, sets $etp_cp_line_name and $etp_cp_line_number +# + set $etp_line_hdr = (BeamCodeHeader*)($arg0) + set $etp_line_mfa = (ErtsCodeMFA*)($arg1) + set $etp_line_fidx = (Eterm)($arg2) + set $etp_line_cp = (Eterm)($arg3) + set $etp_cp_line_name = $etp_nil + set $etp_cp_line_number = 0 + set $etp_line_table = $etp_line_hdr->line_table + if $etp_line_table != 0 + set $etp_line_low = (void**)$etp_line_table->func_tab[$etp_line_fidx] + set $etp_line_high = (void**)$etp_line_table->func_tab[$etp_line_fidx+1] + set $etp_line_idx = -1 + while $etp_line_high > $etp_line_low + set $etp_line_mid = $etp_line_low + ($etp_line_high - $etp_line_low) / 2 + if $etp_line_cp < $etp_line_mid[0] + set $etp_line_high = $etp_line_mid + else + if $etp_line_cp < $etp_line_mid[1] + # Found it! + set $etp_line_idx = $etp_line_mid - (void**)$etp_line_table->func_tab[0] + loop_break + else + set $etp_line_low = $etp_line_mid + 1 + end + end + end + set $etp_cp_line_name = $etp_nil + set $etp_cp_line_number = 0 + if $etp_line_idx != -1 + if $etp_line_table->loc_size == 2 + set $etp_loc = (Uint32)$etp_line_table->loc_tab.p2[$etp_line_idx] + else + set $etp_loc = (Uint32)$etp_line_table->loc_tab.p4[$etp_line_idx] + end + if $etp_loc != 0 + set $etp_loc_file = $etp_loc >> 24 + set $etp_cp_line_number = $etp_loc & ((1 << 24) - 1) + set $etp_cp_line_name = $etp_line_table->fname_ptr[$etp_loc_file] + end + end + end +end define etp-cp-func-info-1 # Args: Eterm cp # -# Non-reentrant, takes cp, sets $etp_cp_p to MFA in func_info +# Non-reentrant, takes cp, sets $etp_cp_p to MFA in func_info, as well as +# $etp_cp_line_name and $etp_cp_line_number # set $etp_cp = (Eterm)($arg0) - set $etp_ranges = &r[(int)the_active_code_index] + set $etp_ranges = &r[(int)the_active_code_index.counter] set $etp_cp_low = $etp_ranges->modules set $etp_cp_high = $etp_cp_low + $etp_ranges->n set $etp_cp_mid = (Range*)$etp_ranges->mid + set $etp_cp_range = 0 set $etp_cp_p = 0 - # + # Find range while $etp_cp_low < $etp_cp_high if $etp_cp < $etp_cp_mid->start set $etp_cp_high = $etp_cp_mid @@ -1263,30 +1327,36 @@ define etp-cp-func-info-1 if $etp_cp > (BeamInstr*)$etp_cp_mid->end set $etp_cp_low = $etp_cp_mid + 1 else - set $etp_cp_p = $etp_cp_low = $etp_cp_high = $etp_cp_mid + set $etp_cp_range = $etp_cp_low = $etp_cp_high = $etp_cp_mid + loop_break end end set $etp_cp_mid = $etp_cp_low + ($etp_cp_high-$etp_cp_low)/2 end - if $etp_cp_p - # 13 = MI_FUNCTIONS - set $etp_cp_low = &((Eterm**)$etp_cp_p->start)[13] - # 0 = MI_NUM_FUNCTIONS - set $etp_cp_high = $etp_cp_low + ((Eterm*)$etp_cp_p->start)[0] + # Find MFA + if $etp_cp_range + set $etp_cp_hdr = (BeamCodeHeader*)$etp_cp_range->start + set $etp_cp_low = (ErtsCodeInfo**)$etp_cp_hdr->functions + set $etp_cp_high = $etp_cp_low + $etp_cp_hdr->num_functions set $etp_cp_p = 0 + set $etp_cp_fidx = 0 while $etp_cp_low < $etp_cp_high set $etp_cp_mid = $etp_cp_low + ($etp_cp_high-$etp_cp_low)/2 if $etp_cp < $etp_cp_mid[0] set $etp_cp_high = $etp_cp_mid else if $etp_cp < $etp_cp_mid[1] - set $etp_cp_p = $etp_cp_mid[0]+2 + set $etp_cp_fidx = $etp_cp_mid - (ErtsCodeInfo**)$etp_cp_hdr->functions + set $etp_cp_p = &$etp_cp_mid[0]->mfa set $etp_cp_low = $etp_cp_high = $etp_cp_mid + loop_break else set $etp_cp_low = $etp_cp_mid + 1 end end end + # Find line number + etp-cp-line-info $etp_cp_hdr $etp_cp_p $etp_cp_fidx $etp_cp end if $etp_cp_p set $cp_cp_p_offset = ($etp_cp-((Eterm)($etp_cp_p-2))) @@ -1304,8 +1374,13 @@ define etp-cp-1 if $etp_cp_p printf "#Cp" etp-mfa-1 $etp_cp_p $cp_cp_p_offset + if $etp_cp_line_name != $etp_nil + printf " @ " + etp-1 $etp_cp_line_name 0 + printf ":%u", $etp_cp_line_number + end else - if $etp_cp == beam_apply+1 + if $etp_cp == beam_normal_exit printf "#Cp" else if ($etp_cp) == beam_return_trace @@ -1652,7 +1727,7 @@ document etp-msgq % Sequential trace tokens are included in comments and % the current match position in the queue is marked '<='. % -% A process's message queue is process_tab[i]->sig_qs. +% A process's message queue is ((Process*)erts_proc->r.o.tab[i])->sig_qs. %--------------------------------------------------------------------------- end @@ -1681,7 +1756,7 @@ define etp-stack-preamble set $etp_stack_end = ($arg0)->hend if ($arg0)->state.counter & 0x8000 printf "%%%%%% WARNING: The process is currently running, so c_p->stop will not be correct\r\n" - printf "%%%%%% Consider using -emu variant instead\r\n" + printf "%%%%%% Consider using -emu or -jit variant instead\r\n" end printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p if ($arg0)->i != 0 @@ -1698,6 +1773,15 @@ define etp-stack-preamble-emu etp ((BeamInstr)I) end +define etp-stack-preamble-jit + set $etp_stack_end = ((Process*)$r13)->hend + set $etp_stack_p = (Eterm*)$rsp + printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p + printf "I: " + set $etp_stack_i = ((Eterm)$rip) & ~0x3 + etp $etp_stack_i +end + define etp-stacktrace-1 set $etp_stack_stop = (Eterm*)($arg0) set $etp_stack_send = (Eterm*)($arg1) @@ -1732,6 +1816,24 @@ document etp-stacktrace-emu %--------------------------------------------------------------------------- end +define etp-stacktrace-jit +# Args: none +# +# Non-reentrant +# + etp-stack-preamble-jit + etp-stacktrace-1 $etp_stack_p $etp_stack_end +end + +document etp-stacktrace-jit +%--------------------------------------------------------------------------- +% etp-stacktrace-jit +% +% Prints a stacktrace for the current process, assuming that we're running +% jitted code. +%--------------------------------------------------------------------------- +end + define etp-stacktrace # Args: Process* # @@ -1776,16 +1878,34 @@ define etp-stackdump-emu etp-stackdump-1 $etp_stack_p $etp_stack_end end -document etp-stacktrace-emu +document etp-stackdump-emu %--------------------------------------------------------------------------- -% etp-stacktrace-emu Process* +% etp-stackdump-emu Process* % -% Take an Process* and print a stactdump for the process. +% Take an Process* and print a stackdump for the process. % This macro assumes that the current frame is the process_main frame % and that E is not optimized out. %--------------------------------------------------------------------------- end +define etp-stackdump-jit +# Args: none +# +# Non-reentrant +# + etp-stack-preamble-jit + etp-stackdump-1 $etp_stack_p $etp_stack_end +end + +document etp-stackdump-jit +%--------------------------------------------------------------------------- +% etp-stackdump-emu +% +% Prints a stackdump for the current process, assuming that we're running +% jitted code. +%--------------------------------------------------------------------------- +end + define etp-stackdump # Args: Process* # @@ -1801,7 +1921,7 @@ document etp-stackdump % % Take an Process* and print a stackdump for the process. % The stackdump consists of all pushed values on the stack. -% All code continuation pointers are preceeded with a line +% All code continuation pointers are preceded with a line % of dashes to make the stack frames more visible. %--------------------------------------------------------------------------- end @@ -2043,24 +2163,45 @@ define etp-term-dump-pid end define etp-term-dump-header -# Args: Header term + # Args: Header term if (($arg0) & 0x3f) == 0 - printf "| H:%4d-tuple ", ($arg0) >> 6 + printf "| H:%4u-tuple ", ($arg0) >> 6 else set $etp_heapdump_skips = ($arg0) >> 6 if ((($arg0) & 0x3f) == 0x18) - printf "| H: float %3d ", ($arg0) >> 6 + printf "| H: float %3u ", ($arg0) >> 6 else if ((($arg0) & 0x3f) == 0x28) - # sub-binary printf "| H: sub-bin " else - if ((($arg0) & 0x3f) == 0x8) - # pos-bignum - printf "| H:bignum %3u ", ($arg0) >> 6 + if ((($arg0) & 0x3f) == 0x24) + printf "| H: heap-bin " else - printf "| header %5d ", ($arg0) >> 6 - end + if ((($arg0) & 0x3f) == 0x20) + printf "| H: refc-bin " + else + if ((($arg0) & 0x3f) == 0x8) + # pos-bignum + printf "| H:bignum %3u ", ($arg0) >> 6 + else + if ((($arg0) & 0x3f) == 0x14) + printf "| H:fun %6u ", ($arg0) >> 6 + else + if ((($arg0) & 0xbc) == 0x3c) + set $etp_heapdump_skips = (($arg0)>>(6+2)) & 0xff + printf "| flatmap %5u ", $etp_heapdump_skips + else + if ((($arg0) & 0xbc) == 0xbc) + set $etp_heapdump_skips = (($arg0)>>(6+2)) & 0xff + printf "| hashmap %4u ", $etp_heapdump_skips + else + printf "| header %5u ", ($arg0) >> 6 + end + end + end + end + end + end end end end @@ -2211,10 +2352,8 @@ define etp-monitor-info-int printf "\n Other: " etp-1 $etp_mon->other.item end - if $etp_mon->type == 7 + if $etp_mon->type == 8 printf "Alias" - printf "\n Other: " - etp-1 $etp_mon->other.item end printf "\n" etp-mon-lnk-flags-int $etp_mon->flags @@ -2356,7 +2495,7 @@ define etp-proc-state-int printf "active | " end if ($arg0 & 0x1000) - printf "unused | " + printf "maybe-self-sigs | " end if ($arg0 & 0x800) printf "exiting | " @@ -2448,6 +2587,9 @@ define etp-proc-flags-int printf "GARBAGE<%x> ", ($arg0 & ~((1 << 25)-1)) end if ($arg0 & (1 << 24)) + printf "DEBUG-forced-trap " + end + if ($arg0 & (1 << 23)) printf "fragmented-send " end if ($arg0 & (1 << 22)) @@ -3088,6 +3230,196 @@ document etp-ports %--------------------------------------------------------------------------- end +define etp-dist-entry + set $ede_de = $arg0 + printf " Name: " + etp $ede_de->sysname + printf " State: " + if $ede_de->state == 0 + printf "IDLE\n" + end + if $ede_de->state == 1 + printf "PENDING\n" + end + if $ede_de->state == 2 + printf "CONNECTED\n" + end + if $ede_de->state == 4 + printf "EXITING\n" + end + printf " Creation: %ld\n", $ede_de->creation + printf " Queue Flags: " + if $ede_de->qflgs.counter & (1 << 0) + printf "BUSY " + end + if $ede_de->qflgs.counter & (1 << 1) + printf "EXIT " + end + if $ede_de->qflgs.counter & (1 << 2) + printf "REQ_INFO " + end + if $ede_de->qflgs.counter & (1 << 3) + printf "PORT_CTRL " + end + if $ede_de->qflgs.counter & (1 << 4) + printf "PROC_CTRL " + end + printf "\n Queue Size: %ld\n", $ede_de->qsize.counter + printf " Suspended: " + set $ede_suspended_first = $ede_de->suspended + if $ede_suspended_first != 0 + etp-1 $ede_suspended_first->u.pid + printf " " + set $ede_suspended = $ede_suspended_first->next + while $ede_suspended != $ede_suspended_first + etp-1 $ede_suspended->u.pid + printf " " + set $ede_suspended = $ede_suspended->next + end + end + printf "\n Flags: " + if $ede_de->dflags & ((Uint64)0x01) + printf "PUBLISHED " + end + if $ede_de->dflags & ((Uint64)0x02) + printf "ATOM_CACHE " + end + if $ede_de->dflags & ((Uint64)0x04) + printf "EXTENDED_REFERENCES " + end + if $ede_de->dflags & ((Uint64)0x08) + printf "DIST_MONITOR " + end + if $ede_de->dflags & ((Uint64)0x10) + printf "FUN_TAGS " + end + if $ede_de->dflags & ((Uint64)0x20) + printf "DIST_MONITOR_NAME " + end + if $ede_de->dflags & ((Uint64)0x40) + printf "HIDDEN_ATOM_CACHE " + end + if $ede_de->dflags & ((Uint64)0x80) + printf "NEW_FUN_TAGS " + end + if $ede_de->dflags & ((Uint64)0x100) + printf "EXTENDED_PIDS_PORTS " + end + if $ede_de->dflags & ((Uint64)0x200) + printf "EXPORT_PTR_TAG " + end + if $ede_de->dflags & ((Uint64)0x400) + printf "BIT_BINARIES " + end + if $ede_de->dflags & ((Uint64)0x800) + printf "NEW_FLOATS " + end + if $ede_de->dflags & ((Uint64)0x1000) + printf "UNICODE_IO " + end + if $ede_de->dflags & ((Uint64)0x2000) + printf "DIST_HDR_ATOM_CACHE " + end + if $ede_de->dflags & ((Uint64)0x4000) + printf "SMALL_ATOM_TAGS " + end + if $ede_de->dflags & ((Uint64)0x8000) + printf "ETS_COMPRESSED " + end + if $ede_de->dflags & ((Uint64)0x10000) + printf "UTF8_ATOMS " + end + if $ede_de->dflags & ((Uint64)0x20000) + printf "MAP_TAG " + end + if $ede_de->dflags & ((Uint64)0x40000) + printf "BIG_CREATION " + end + if $ede_de->dflags & ((Uint64)0x80000) + printf "SEND_SENDER " + end + if $ede_de->dflags & ((Uint64)0x100000) + printf "BIG_SEQTRACE_LABELS " + end + if $ede_de->dflags & ((Uint64)0x200000) + printf "PENDING_CONNECT " + end + if $ede_de->dflags & ((Uint64)0x400000) + printf "EXIT_PAYLOAD " + end + if $ede_de->dflags & ((Uint64)0x800000) + printf "FRAGMENTS " + end + if $ede_de->dflags & ((Uint64)0x1000000) + printf "HANDSHAKE_23 " + end + if $ede_de->dflags & ((Uint64)0x2000000) + printf "UNLINK_ID " + end + if $ede_de->dflags & ((Uint64)0x4000000) + printf "MANDATORY_25_DIGEST " + end + if $ede_de->dflags & ((Uint64)0xf8000000) + printf "RESERVED " + end + if $ede_de->dflags & (((Uint64)0x1) << 32) + printf "SPAWN " + end + if $ede_de->dflags & (((Uint64)0x2) << 32) + printf "NAME_ME " + end + if $ede_de->dflags & (((Uint64)0x4) << 32) + printf "V4_NC " + end + if $ede_de->dflags & (((Uint64)0x8) << 32) + printf "ALIAS " + end + printf "\n Pointer: (DistEntry*)%p\n", $ede_de +end + +document etp-dist-entry +%--------------------------------------------------------------------------- +% etp-dist-entry DistEntry* +% +% Print information about the DistEntry* +%--------------------------------------------------------------------------- +end + +define etp-dist + set $de = erts_visible_dist_entries + while $de != 0 + printf "--- visible\n" + etp-dist-entry $de + set $de = $de->next + end + set $de = erts_hidden_dist_entries + while $de != 0 + printf "--- hidden\n" + etp-dist-entry $de + set $de = $de->next + end + set $de = erts_pending_dist_entries + while $de != 0 + printf "--- pending\n" + etp-dist-entry $de + set $de = $de->next + end + set $de = erts_not_connected_dist_entries + while $de != 0 + printf "--- not connected\n" + etp-dist-entry $de + set $de = $de->next + end +end + +document etp-dist +%--------------------------------------------------------------------------- +% etp-dist +% +% Print information about all current dist entries +%--------------------------------------------------------------------------- +end + define etp-rq-flags-int # Args: int # @@ -3490,7 +3822,7 @@ document etp-disasm %--------------------------------------------------------------------------- % etp-fds BeamInstr* (BeamInstr*) % -% Disassemble the instructions inbetween arg0 and arg1, +% Disassemble the instructions between arg0 and arg1, % if no second argument is given only the current % instruction is printed. %--------------------------------------------------------------------------- @@ -4558,7 +4890,7 @@ define etp-lc-dump if 0 <= $etp_lc_dump_thread_locked->id && $etp_lc_dump_thread_locked->id < sizeof(erts_lock_order)/sizeof(erts_lc_lock_order_t) printf " %s:", erts_lock_order[$etp_lc_dump_thread_locked->id].name else - printf " unkown:" + printf " unknown:" end if ($etp_lc_dump_thread_locked->extra & 0x3) == 0x3 etp-1 $etp_lc_dump_thread_locked->extra diff --git a/erts/etc/unix/etp-thr.py b/erts/etc/unix/etp-thr.py index fb82dcaf1fc7..be4593039c8a 100644 --- a/erts/etc/unix/etp-thr.py +++ b/erts/etc/unix/etp-thr.py @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2013-2016. All Rights Reserved. +# Copyright Ericsson AB 2013-2021. 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. @@ -33,6 +33,12 @@ def get_thread_name(t): return "child_waiter"; elif f.name() == "sched_thread_func": return "scheduler"; + elif f.name() == "sched_dirty_cpu_thread_func": + return "dirty_cpu_scheduler"; + elif f.name() == "sched_dirty_io_thread_func": + return "dirty_io_scheduler"; + elif f.name() == "poll_thread": + return "poll_thread"; elif f.name() == "aux_thread": return "aux"; f = f.older(); diff --git a/erts/etc/unix/etp.py b/erts/etc/unix/etp.py index 38c9e184088f..ac4ff2a1181a 100644 --- a/erts/etc/unix/etp.py +++ b/erts/etc/unix/etp.py @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2013-2021. All Rights Reserved. +# Copyright Ericsson AB 2013-2023. 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. @@ -686,10 +686,10 @@ def strip_literal_tag(valobj): return valobj def init(target): - names = ['beam_apply', 'beam_normal_exit', 'beam_exit', 'beam_save_calls', - 'beam_bif_export_trap', 'beam_export_trampoline', 'beam_continue_exit', - 'beam_return_to_trace', 'beam_return_trace', 'beam_exception_trace', - 'beam_return_time_trace'] + names = ['beam_run_process', 'beam_normal_exit', 'beam_exit', 'beam_save_calls_export', + 'beam_save_calls_fun', 'beam_bif_export_trap', 'beam_export_trampoline', + 'beam_continue_exit', 'beam_return_to_trace', 'beam_return_trace', + 'beam_exception_trace', 'beam_call_trace_return'] for name in names: code_pointers[global_var(name, target).unsigned] = name diff --git a/erts/etc/unix/format_man_pages b/erts/etc/unix/format_man_pages index 0afff13571da..851ec3107667 100644 --- a/erts/etc/unix/format_man_pages +++ b/erts/etc/unix/format_man_pages @@ -3,7 +3,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2021. 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. @@ -92,7 +92,7 @@ case :"$TARGET" in ## /usr/sbin/makewhatis -v $ERL_ROOT/man -c $ERL_ROOT/man > /dev/null 2>&1 if [ ! -x /usr/bin/groff ]; then - echo "Cannot find groff - no formating of manual pages" + echo "Cannot find groff - no formatting of manual pages" exit fi diff --git a/erts/etc/unix/jit-reader.c b/erts/etc/unix/jit-reader.c index 83481ba4f2dc..4b2714222afd 100644 --- a/erts/etc/unix/jit-reader.c +++ b/erts/etc/unix/jit-reader.c @@ -22,66 +22,187 @@ static FILE *log = NULL; #define LOG(...) #endif +typedef enum { + X64_RBP = 6, /* Frame pointer iff native frames are enabled */ + X64_RSP = 7, /* Stack pointer when using native stack */ + X64_R12 = 12, /* Stack pointer when using non-native stack */ + X64_R13 = 13, /* Current process */ + X64_RIP = 16 +} X64Register; + +typedef enum { + /* Return address only */ + ERTS_FRAME_LAYOUT_RA, + /* Frame pointer, return address */ + ERTS_FRAME_LAYOUT_FP_RA +} ErtsFrameLayout; + +struct emulator_info { + /* 0 = regular, 1 = frame pointers */ + int frame_layout; + const void *normal_exit; +}; + +struct module_info { + uint64_t base_address; + uint32_t range_count; + uint32_t code_size; + /* Module name, including null terminator. */ + uint16_t name_length; + char name[]; + /* array of range_info structures */ +}; + +struct range_info { + uint32_t start_offset; + uint32_t end_offset; + uint32_t line_count; + /* Range name, including null terminator. */ + uint16_t name_length; + char name[]; + /* array of line_info structures */ +}; + +struct line_info { + uint32_t start_offset; + uint32_t line_number; + /* File name, including null terminator. */ + uint16_t file_length; + char file[]; +}; + +enum debug_info_header { + DEBUG_INFO_HEADER_EMULATOR = 0, + DEBUG_INFO_HEADER_MODULE = 1, +}; + +struct debug_info { + enum debug_info_header header; + union { + struct emulator_info emu; + struct module_info mod; + } payload; +}; typedef struct range { GDB_CORE_ADDR start; GDB_CORE_ADDR end; - int global; +#ifdef HARD_DEBUG char *name; +#endif } range; typedef struct priv { range *ranges; int num_ranges; - uint64_t normal_exit; + ErtsFrameLayout frame_layout; + const void *normal_exit; } priv; +static enum gdb_status read_module_info(struct gdb_reader_funcs *self, + struct gdb_symbol_callbacks *cb, + struct module_info *module_info) { + struct gdb_object *obj = cb->object_open(cb); + GDB_CORE_ADDR mod_start, mod_end; + char *symfile = (char*)module_info; + priv *priv = self->priv_data; + + symfile += sizeof(*module_info) + module_info->name_length; + + mod_start = module_info->base_address; + mod_end = mod_start + module_info->code_size; + + priv->ranges = realloc(priv->ranges, (priv->num_ranges + 1) * sizeof(range)); + priv->ranges[priv->num_ranges].start = mod_start; + priv->ranges[priv->num_ranges].end = mod_end; +#ifdef HARD_DEBUG + priv->ranges[priv->num_ranges].name = strdup(module_info->name); +#endif + priv->num_ranges += 1; + + LOG("Add module `%s` (0x%lx, 0x%lx)\r\n", + module_info->name, mod_start, mod_end); + + for (int range = 0; range < module_info->range_count; range++) { + struct range_info *range_info; + struct gdb_symtab *symtab; + GDB_CORE_ADDR begin, end; + + range_info = (struct range_info *)symfile; + symfile += sizeof(*range_info) + range_info->name_length; + + begin = mod_start + range_info->start_offset; + end = mod_start + range_info->end_offset; + + LOG("Add range `%s` (0x%lx, 0x%lx), %u lines\r\n", + range_info->name, + begin, end, + range_info->line_count); + + /* A bug in GDB < 9 forces us to open and close the symtab for each + * iteration. */ + symtab = cb->symtab_open(cb, obj, module_info->name); + cb->block_open(cb, symtab, NULL, begin, end, range_info->name); + cb->symtab_close(cb, symtab); + + for (int line = 0; line < range_info->line_count; line++) { + struct gdb_line_mapping line_mapping; + struct line_info *line_info; + + line_info = (struct line_info *)symfile; + symfile += sizeof(*line_info) + line_info->file_length; + + line_mapping.pc = mod_start + line_info->start_offset; + line_mapping.line = line_info->line_number; + + LOG("\t%s:%u\r\n", line_info->file, line_info->line_number); + + /* The symbol table must be opened and closed on every single line + * for file names to work properly, as there is no other way to + * tell GDB that a certain line belongs to a different file than + * the rest of the table. Sigh. */ + symtab = cb->symtab_open(cb, obj, line_info->file); + + cb->block_open(cb, symtab, NULL, line_mapping.pc, end, + range_info->name); + cb->line_mapping_add(cb, symtab, 1, &line_mapping); + cb->symtab_close(cb, symtab); + } + } + + cb->object_close(cb, obj); + + return GDB_SUCCESS; +} + +static enum gdb_status read_emulator_info(struct gdb_reader_funcs *self, + struct gdb_symbol_callbacks *cb, + struct emulator_info *emulator_info) { + priv *priv = self->priv_data; + + priv->frame_layout = emulator_info->frame_layout; + priv->normal_exit = emulator_info->normal_exit; + + LOG("initialize: frame layout = %i\r\n", priv->frame_layout); + + return GDB_SUCCESS; +} static enum gdb_status read_debug_info(struct gdb_reader_funcs *self, struct gdb_symbol_callbacks *cb, void *memory, long memory_sz) { - priv *priv = self->priv_data; - uint64_t num_functions = *(uint64_t*)memory; - if (num_functions == 0) { - /* Initialize */ - priv->normal_exit = *(uint64_t*)(memory + sizeof(uint64_t)); - LOG("initialize: normal_exit=%p\r\n",(void*)priv->normal_exit); - } else { - GDB_CORE_ADDR mod_start = *(GDB_CORE_ADDR *)(memory + sizeof(uint64_t)); - GDB_CORE_ADDR mod_end = mod_start + *(uint64_t*)(memory + sizeof(uint64_t)*2); - char* module = memory + sizeof(uint64_t)*3; - char* curr = module + strlen(module) + 1; - int i; - struct gdb_object *obj = cb->object_open(cb); - - priv->ranges = realloc(priv->ranges, sizeof(range) * ++priv->num_ranges); - priv->ranges[priv->num_ranges-1].start = mod_start; - priv->ranges[priv->num_ranges-1].end = mod_end; - priv->ranges[priv->num_ranges-1].name = strdup(module); - priv->ranges[priv->num_ranges-1].global = !strcmp(module, "global"); - - LOG("Add module %s (0x%lx, 0x%lx)\r\n", module, mod_start, mod_end); - - for (i = 0; i < num_functions; i++) { - // get begin and end of code segment - // A bug in GDB < 9 forces us to open and close the symtab for each iteration - struct gdb_symtab *symtab = cb->symtab_open(cb, obj, module); - GDB_CORE_ADDR begin = *(GDB_CORE_ADDR*)curr; - GDB_CORE_ADDR end = *(GDB_CORE_ADDR*)(curr + sizeof(GDB_CORE_ADDR)); - // get name of function - const char *name = (const char*)(curr + sizeof(GDB_CORE_ADDR) * 2); - curr += strlen(name) + 1 + sizeof(GDB_CORE_ADDR) * 2; - - LOG("Add %s (0x%lx, 0x%lx)\r\n", name, begin, end); - - // returned value has no use - cb->block_open(cb, symtab, NULL, begin, end, name); - cb->symtab_close(cb, symtab); - } + struct debug_info *debug_info = memory; + + (void)memory_sz; - cb->object_close(cb, obj); + switch (debug_info->header) { + case DEBUG_INFO_HEADER_EMULATOR: + return read_emulator_info(self, cb, &debug_info->payload.emu); + case DEBUG_INFO_HEADER_MODULE: + return read_module_info(self, cb, &debug_info->payload.mod); } - return GDB_SUCCESS; + + return GDB_FAIL; } static void regfree(struct gdb_reg_value *reg) { @@ -89,132 +210,149 @@ static void regfree(struct gdb_reg_value *reg) { } static struct range *get_range(priv *priv, GDB_CORE_ADDR rip) { - int i; - for (i = 0; i < priv->num_ranges; i++) - if (rip >= priv->ranges[i].start && rip < priv->ranges[i].end) + for (int i = 0; i < priv->num_ranges; i++) { + if (rip >= priv->ranges[i].start && rip < priv->ranges[i].end) { return &priv->ranges[i]; + } + } + return NULL; } -static enum gdb_status unwind(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb) { - int i; - priv *priv = self->priv_data; - GDB_CORE_ADDR rip = *(GDB_CORE_ADDR*)cb->reg_get(cb,16)->value; - GDB_CORE_ADDR rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb,7)->value; - GDB_CORE_ADDR rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb,6)->value; - struct range *range = get_range(priv, rip); +static enum gdb_status unwind(struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb) { + GDB_CORE_ADDR rbp, rsp, rip; + struct range *range; + priv *priv; + + rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RBP)->value; + rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RSP)->value; + rip = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RIP)->value; + + priv = self->priv_data; + range = get_range(priv, rip); /* Check that rip points to one of the addresses that we handle */ if (range) { - struct gdb_reg_value *prev_rsp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)), - *prev_rip = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)), - *prev_rbp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); - - LOG("UNWIND match %s: rip: 0x%lx rsp: 0x%lx rbp: 0x%lx \r\n", range->name, rip, rsp, rbp); - /* We use the normal frame-pointer logic to unwind the stack, which means - that rbp will point to where we stored the previous frames rbp. Also - the previous frames address will be at rbp + 1 and the previous frames - rsp will be rbp + 2. - - 0x00: <- prev_rsp - 0x80: prev call addr - 0x10: prev rbp <- curr rbp - 0x18: current frame - 0x20: <- curr rip - - */ - - for (i = 0; i < 16; i++) { - if (i != 16 && i != 7 && i != 6) { - struct gdb_reg_value *reg = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); - reg->free = ®free; - reg->defined = 1; - reg->size = sizeof(char*); - *(GDB_CORE_ADDR*)reg->value = *(GDB_CORE_ADDR*)cb->reg_get(cb,i)->value; - cb->reg_set(cb, i, reg); - } - } + struct gdb_reg_value *prev_rbp, *prev_rsp, *prev_rip; + + prev_rbp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); + prev_rsp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); + prev_rip = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); + + LOG("UNWIND match %s: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx \r\n", + range->name, rbp, rsp, rip); - prev_rsp->free = ®free; - prev_rsp->defined = 1; - prev_rsp->size = sizeof(char*); prev_rbp->free = ®free; prev_rbp->defined = 1; prev_rbp->size = sizeof(char*); + prev_rsp->free = ®free; + prev_rsp->defined = 1; + prev_rsp->size = sizeof(char*); prev_rip->free = ®free; prev_rip->defined = 1; prev_rip->size = sizeof(char*); - if (range->global) { - - cb->target_read(rbp + 1 * sizeof(char*), &prev_rip->value, sizeof(char*)); - ((GDB_CORE_ADDR*)prev_rsp->value)[0] = rbp + sizeof(char*) * 2; - cb->target_read(rbp + 0 * sizeof(char*), &prev_rbp->value, sizeof(char*)); - + if (priv->frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { + /* Frame pointers are enabled, which means that rbp will point to + * where we stored the previous frames rbp. Also the previous + * frames address will be at rbp + 8 and the previous frames rsp + * will be rbp + 16. + * + * 0x00: <- prev_rsp + * 0x08: prev call addr + * 0x10: prev rbp <- curr rbp + * 0x18: current frame + * 0x20: <- curr rip */ + cb->target_read(rbp + 1 * sizeof(char*), &prev_rip->value, + sizeof(char*)); + cb->target_read(rbp + 0 * sizeof(char*), &prev_rbp->value, + sizeof(char*)); + *(GDB_CORE_ADDR*)prev_rsp->value = rbp + sizeof(char*[2]); } else { + /* Normal frame layout, we need to scan the stack. */ + cb->target_read(rsp, &prev_rip->value, sizeof(char*)); - if (rip == priv->normal_exit) { - LOG("Normal exit\r\n"); - ((GDB_CORE_ADDR*)prev_rsp->value)[0] = rsp; - ((GDB_CORE_ADDR*)prev_rbp->value)[0] = rbp; - ((GDB_CORE_ADDR*)prev_rip->value)[0] = rip; - } else { + for (rsp += sizeof(char*); ; rsp += sizeof(char*)) { cb->target_read(rsp, &prev_rip->value, sizeof(char*)); - for (rsp += sizeof(char*); ; rsp += sizeof(char*)) { - cb->target_read(rsp, &prev_rip->value, sizeof(char*)); - LOG("rsp: 0x%lx rip: 0x%lx\r\n", rsp, *(GDB_CORE_ADDR*)prev_rip->value); - /* Check if it is a cp */ - if ((*(GDB_CORE_ADDR*)prev_rip->value & 0x3) == 0) { - break; - } + LOG("rsp: 0x%lx rip: 0x%lx\r\n", + rsp, *(GDB_CORE_ADDR*)prev_rip->value); + + /* Check if it is a cp */ + if ((*(GDB_CORE_ADDR*)prev_rip->value & 0x3) == 0) { + break; } - ((GDB_CORE_ADDR*)prev_rsp->value)[0] = rsp; - ((GDB_CORE_ADDR*)prev_rbp->value)[0] = rsp - sizeof(char*); } + + *(GDB_CORE_ADDR*)prev_rsp->value = rsp; + *(GDB_CORE_ADDR*)prev_rbp->value = rsp - sizeof(char*); + } + + if (*(GDB_CORE_ADDR*)prev_rip->value == (uintptr_t)priv->normal_exit) { + LOG("Normal exit\r\n"); + *(GDB_CORE_ADDR*)prev_rsp->value = 0; + *(GDB_CORE_ADDR*)prev_rbp->value = 0; + } else { + LOG("UNWIND prev: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx\r\n", + *(GDB_CORE_ADDR*)prev_rbp->value, + *(GDB_CORE_ADDR*)prev_rsp->value, + *(GDB_CORE_ADDR*)prev_rip->value); } - LOG("UNWIND prev: rip: 0x%lx rsp: 0x%lx rbp: 0x%lx\r\n", - *(GDB_CORE_ADDR*)prev_rip->value, - *(GDB_CORE_ADDR*)prev_rsp->value, - *(GDB_CORE_ADDR*)prev_rbp->value); + cb->reg_set(cb, X64_RIP, prev_rip); + cb->reg_set(cb, X64_RSP, prev_rsp); + cb->reg_set(cb, X64_RBP, prev_rbp); - cb->reg_set(cb, 16, prev_rip); - cb->reg_set(cb, 7, prev_rsp); - cb->reg_set(cb, 6, prev_rbp); return GDB_SUCCESS; } - LOG("UNWIND no match: rip: 0x%lx rsp: 0x%lx rbp: 0x%lx\r\n", rip, rsp, rbp); + + LOG("UNWIND no match: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx\r\n", rbp, rsp, rip); return GDB_FAIL; } -static struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cb){ - priv *priv = self->priv_data; +static struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, + struct gdb_unwind_callbacks *cb){ struct gdb_frame_id frame = {0, 0}; - GDB_CORE_ADDR rip = *(GDB_CORE_ADDR*)cb->reg_get(cb,16)->value; - GDB_CORE_ADDR rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb,6)->value; - GDB_CORE_ADDR rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb,7)->value; - struct range *range = get_range(priv, rip); + GDB_CORE_ADDR rbp, rsp, rip; + struct range *range; + priv *priv; + + rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RBP)->value; + rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RSP)->value; + rip = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RIP)->value; + + priv = self->priv_data; + range = get_range(priv, rip); + LOG("FRAME: rip: 0x%lx rsp: 0x%lx rbp: 0x%lx \r\n", rip, rsp, rbp); + if (range) { frame.code_address = rip; - if (range->global) { + + if (priv->frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { frame.stack_address = rbp + sizeof(char*); } else { GDB_CORE_ADDR prev_rip; + for (rsp += sizeof(char*); ; rsp += sizeof(char*)) { cb->target_read(rsp, &prev_rip, sizeof(char*)); + LOG("rsp: 0x%lx rip: 0x%lx\r\n", rsp, prev_rip); + /* Check if it is a cp */ if ((prev_rip & 0x3) == 0) { break; } } + frame.stack_address = rsp; } } + LOG("FRAME: code_address: 0x%lx stack_address: 0x%lx\r\n", frame.code_address, frame.stack_address); + return frame; } @@ -225,6 +363,7 @@ static void destroy(struct gdb_reader_funcs *self){ struct gdb_reader_funcs *gdb_init_reader(void){ struct gdb_reader_funcs *funcs = malloc(sizeof(struct gdb_reader_funcs)); priv *priv_data = malloc(sizeof(priv)); + priv_data->num_ranges = 1; priv_data->ranges = malloc(sizeof(range)); priv_data->ranges[0].start = 0; diff --git a/erts/etc/unix/makewhatis b/erts/etc/unix/makewhatis index 047c6efdfa40..0d047fe8c465 100644 --- a/erts/etc/unix/makewhatis +++ b/erts/etc/unix/makewhatis @@ -22,7 +22,7 @@ # on my 486DX66). # 960401 - aeb: slight adaptation to work correctly with cat pages. # 960510 - added fixes by brennan@raven.ca.boeing.com, author of mawk. -# 971012 - replaced "test -z" - it doesnt work on SunOS 4.1.3_U1. +# 971012 - replaced "test -z" - it doesn't work on SunOS 4.1.3_U1. # 980710 - be more careful with TMPFILE # # Note for Slackware users: "makewhatis -v -w -c" will work. @@ -40,7 +40,7 @@ DEFCATPATH=/usr/man/preformat:/usr/man # We try here to be careful (and avoid preconstructed symlinks) # in case makewhatis is run as root, by creating a subdirectory of /tmp. # If that fails we use $HOME. -# The code below uses test -O which doesnt work on all systems. +# The code below uses test -O which doesn't work on all systems. TMPFILE=$HOME/whatis$$ TMPFILEDIR=/tmp/whatis$$ if [ ! -d $TMPFILEDIR ]; then diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c index 73758daec8cc..615764663058 100644 --- a/erts/etc/unix/run_erl.c +++ b/erts/etc/unix/run_erl.c @@ -828,7 +828,7 @@ static int find_next_log_num(void) { /* open_log() * Opens a log file (with given index) for writing. Writing may be - * at the end or a trucnating write, according to flags. + * at the end or a truncating write, according to flags. * A LOGGING STARTED and time stamp message is inserted into the log file */ static int open_log(int log_num, int flags) @@ -988,7 +988,7 @@ static int open_pty_master(char **ptyslave, int *sfdp) /* X is in "pqrs" and Y in "0123456789abcdef" but FreeBSD */ /* and some Linux version has extended this. */ - /* This code could probebly be improved alot. For example look at */ + /* This code could probebly be improved a lot. For example look at */ /* http://www.xcf.berkeley.edu/~ali/K0D/UNIX/PTY/code/pty.c.html */ /* http://www.xcf.berkeley.edu/~ali/K0D/UNIX/PTY/code/upty.h.html */ @@ -1368,7 +1368,7 @@ static int sf_close(int fd) { return close(fd); } -/* Extract any control sequences that are ment only for run_erl +/* Extract any control sequences that are meant only for run_erl * and should not be forwarded to the pty. */ static int extract_ctrl_seq(char* buf, int len) diff --git a/erts/etc/unix/start.src b/erts/etc/unix/start.src index 4cf0e899e429..e645e3a18b9a 100644 --- a/erts/etc/unix/start.src +++ b/erts/etc/unix/start.src @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -25,9 +25,31 @@ # # Usage: start [Data] # +prog="$0" +progdir="`dirname ${prog}`" +dyn_erl_path="${progdir}/../erts-%VSN%/bin/dyn_erl" +if [ ! -f "$dyn_erl_path" ] +then + dyn_erl_path="${progdir}/dyn_erl" +fi + +if [ -f "$dyn_erl_path" ] +then + dyn_rootdir=`${dyn_erl_path} --realpath` + dyn_rootdir=`dirname ${dyn_rootdir}` + dyn_rootdir=`dirname ${dyn_rootdir}` +else + dyn_rootdir="" +fi + if [ -z "$ERL_ROOTDIR" ] then ROOTDIR="%FINAL_ROOTDIR%" + if [ "$dyn_rootdir" != "$ROOTDIR" ] && [ "$dyn_rootdir" != "" ] + then + # It is likely that the files have been copied or moved + ROOTDIR="$dyn_rootdir" + fi else ROOTDIR="$ERL_ROOTDIR" fi diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index d684b9c3a3ae..4de4ac4d64ae 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -82,13 +82,13 @@ # define STRERROR(x) "" #endif -#define noDEBUG +#define noDEBUG_TOERL #define PIPE_DIR "/tmp/" #define PIPE_STUBNAME "erlang.pipe" #define PIPE_STUBLEN strlen(PIPE_STUBNAME) -#ifdef DEBUG +#ifdef DEBUG_TOERL #define STATUS(s) { fprintf(stderr, (s)); fflush(stderr); } #else #define STATUS(s) @@ -106,7 +106,7 @@ static int protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */ static int write_all(int fd, const char* buf, int len); static int window_size_seq(char* buf, size_t bufsz); static int version_handshake(char* buf, int len, int wfd); -#ifdef DEBUG +#ifdef DEBUG_TOERL static void show_terminal_settings(struct termios *); #endif @@ -155,7 +155,7 @@ int main(int argc, char **argv) pipeIx = 2; } -#ifdef DEBUG +#ifdef DEBUG_TOERL fprintf(stderr, "%s: pid is : %d\n", argv[0], (int)getpid()); #endif @@ -209,25 +209,25 @@ int main(int argc, char **argv) } if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { -#ifdef DEBUG +#ifdef DEBUG_TOERL fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); exit(1); } -#ifdef DEBUG +#ifdef DEBUG_TOERL fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1); #endif if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { -#ifdef DEBUG +#ifdef DEBUG_TOERL fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); close(rfd); exit(1); } -#ifdef DEBUG +#ifdef DEBUG_TOERL fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2); #endif @@ -245,7 +245,7 @@ int main(int argc, char **argv) } tty_smode = tty_rmode; tty_eof = '\004'; /* Ctrl+D to exit */ -#ifdef DEBUG +#ifdef DEBUG_TOERL show_terminal_settings(&tty_rmode); #endif tty_smode.c_iflag = @@ -347,7 +347,7 @@ int main(int argc, char **argv) tcsetattr(0, TCSADRAIN, &tty_smode); -#ifdef DEBUG +#ifdef DEBUG_TOERL show_terminal_settings(&tty_smode); #endif /* @@ -420,7 +420,7 @@ int main(int argc, char **argv) } if (len) { -#ifdef DEBUG +#ifdef DEBUG_TOERL write_all(1, buf, len); #endif if (write_all(wfd, buf, len) != len) { @@ -487,7 +487,7 @@ int main(int argc, char **argv) } /* - * Reset terminal characterstics + * Reset terminal characteristics * XXX */ tcsetattr(0, TCSADRAIN, &tty_rmode); @@ -580,7 +580,7 @@ static int version_handshake(char* buf, int len, int wfd) } -#ifdef DEBUG +#ifdef DEBUG_TOERL #define S(x) ((x) > 0 ? 1 : 0) static void show_terminal_settings(struct termios *t) diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c index 1b8f894dc946..7ed338d74419 100644 --- a/erts/etc/win32/Install.c +++ b/erts/etc/win32/Install.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2021. All Rights Reserved. + * Copyright Ericsson AB 2003-2023. 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. @@ -24,6 +24,7 @@ */ #include +#include #include #include #include "init_file.h" @@ -47,11 +48,12 @@ int wmain(int argc, wchar_t **argv) InitFile *ini_file; InitSection *ini_section; HANDLE module = GetModuleHandle(NULL); - wchar_t *binaries[] = { L"erl.exe", L"werl.exe", L"erlc.exe", L"erl_call.exe", + wchar_t *binaries[] = { L"erl.exe", L"erlc.exe", L"erl_call.exe", L"dialyzer.exe", L"typer.exe", L"escript.exe", L"ct_run.exe", NULL }; wchar_t *scripts[] = { L"start_clean.boot", L"start_sasl.boot", L"no_dot_erlang.boot", NULL }; + wchar_t *links[][2] = { { L"erl.exe", L"werl.exe" }, NULL }; wchar_t fromname[MAX_PATH]; wchar_t toname[MAX_PATH]; size_t converted; @@ -175,7 +177,32 @@ int wmain(int argc, wchar_t **argv) fprintf(stderr,"Continuing installation anyway...\n"); } } - + + for (i = 0; links[i][0] != NULL; ++i) { + swprintf(toname,MAX_PATH,L"%s\\%s",bin_dir,links[i][1]); + if (!CreateSymbolicLinkW(toname,links[i][0],0)) { + DWORD err = GetLastError(); + if (err == ERROR_PRIVILEGE_NOT_HELD) { + fprintf(stderr,"Must be administrator to create link, copying %S instead.\n", + links[i][0]); + swprintf(fromname,MAX_PATH,L"%s\\%s",bin_dir,links[i][0]); + if (!CopyFileW(fromname,toname,FALSE)) { + fprintf(stderr,"Could not copy file %S to %S\n", + fromname,toname); + fprintf(stderr,"Continuing installation anyway...\n"); + } + } else { + wchar_t buf[256]; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, (sizeof(buf) / sizeof(wchar_t)), NULL); + fprintf(stderr,"Could not create links from %S to %S %d: %S\n", + fromname, toname, err, buf); + fprintf(stderr,"Continuing installation anyway...\n"); + } + } + } + for (i = 0; scripts[i] != NULL; ++i) { swprintf(fromname,MAX_PATH,L"%s\\%s",release_dir,scripts[i]); swprintf(toname,MAX_PATH,L"%s\\%s",bin_dir,scripts[i]); diff --git a/erts/etc/win32/Makefile b/erts/etc/win32/Makefile index c6376ebe7405..04c3633403c7 100644 --- a/erts/etc/win32/Makefile +++ b/erts/etc/win32/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -39,7 +39,6 @@ ROOTDIR = $(ERL_TOP)/erts INSTALL_PROGS = \ $(BINDIR)/inet_gethost.exe \ $(BINDIR)/erl.exe \ - $(BINDIR)/werl.exe \ $(BINDIR)/heart.exe \ $(BINDIR)/erlc.exe \ $(BINDIR)/erlsrv.exe \ diff --git a/erts/etc/win32/cygwin_tools/mingw/cc.sh b/erts/etc/win32/cygwin_tools/mingw/cc.sh index 0b321a509978..681476d6eb55 100755 --- a/erts/etc/win32/cygwin_tools/mingw/cc.sh +++ b/erts/etc/win32/cygwin_tools/mingw/cc.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2006-2016. All Rights Reserved. +# Copyright Ericsson AB 2006-2021. 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. @@ -269,7 +269,7 @@ if [ $LINKING = true ]; then *) out_spec="-o $OUTFILE";; esac - # Descide which standard library to link against + # Decide which standard library to link against case $MD in -ML) stdlib="-lLIBC";; diff --git a/erts/etc/win32/cygwin_tools/mingw/coffix.c b/erts/etc/win32/cygwin_tools/mingw/coffix.c index ff3f3de3d119..4ba0ae04e5e6 100644 --- a/erts/etc/win32/cygwin_tools/mingw/coffix.c +++ b/erts/etc/win32/cygwin_tools/mingw/coffix.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2016. All Rights Reserved. + * Copyright Ericsson AB 2006-2021. 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. @@ -43,7 +43,7 @@ static int v_printf(char *format, ...); char *progname; -int verbouse = 0; +int verbose = 0; int main(int argc, char **argv) { @@ -66,7 +66,7 @@ int main(int argc, char **argv) break; case 'v': case 'V': - verbouse = 1; + verbose = 1; default: fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]); break; @@ -152,7 +152,7 @@ static int v_printf(char *format, ...) { va_list ap; int ret = 0; - if (verbouse) { + if (verbose) { va_start(ap, format); ret = vfprintf(stdout, format, ap); va_end(ap); diff --git a/erts/etc/win32/cygwin_tools/vc/cc.sh b/erts/etc/win32/cygwin_tools/vc/cc.sh index 9eeb004f0e17..5dc9666eeab3 100755 --- a/erts/etc/win32/cygwin_tools/vc/cc.sh +++ b/erts/etc/win32/cygwin_tools/vc/cc.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2016. All Rights Reserved. +# Copyright Ericsson AB 2002-2021. 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. @@ -38,7 +38,7 @@ ERR_FILE=/tmp/cl.exe.$$.2 MD_FORCED=false # If we're preprocession (only) i.e. -E PREPROCESSING=false -# If we're generating dependencies (implies preprocesing) +# If we're generating dependencies (implies preprocessing) DEPENDENCIES=false # If this is supposed to be a debug build DEBUG_BUILD=false @@ -297,7 +297,7 @@ if [ $LINKING = true ]; then *) out_spec="-o $OUTFILE";; esac - # Descide which standard library to link against + # Decide which standard library to link against case $MD in -ML) stdlib="-lLIBC";; diff --git a/erts/etc/win32/cygwin_tools/vc/coffix.c b/erts/etc/win32/cygwin_tools/vc/coffix.c index bf1096c4253e..3221ad6d8558 100644 --- a/erts/etc/win32/cygwin_tools/vc/coffix.c +++ b/erts/etc/win32/cygwin_tools/vc/coffix.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2016. All Rights Reserved. + * Copyright Ericsson AB 1999-2021. 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. @@ -43,7 +43,7 @@ static int v_printf(char *format, ...); char *progname; -int verbouse = 0; +int verbose = 0; int main(int argc, char **argv) { @@ -66,7 +66,7 @@ int main(int argc, char **argv) break; case 'v': case 'V': - verbouse = 1; + verbose = 1; default: fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]); break; @@ -152,7 +152,7 @@ static int v_printf(char *format, ...) { va_list ap; int ret = 0; - if (verbouse) { + if (verbose) { va_start(ap, format); ret = vfprintf(stdout, format, ap); va_end(ap); diff --git a/erts/etc/win32/erl.c b/erts/etc/win32/erl.c index 99a41b99e5f9..1b6f89c11c57 100644 --- a/erts/etc/win32/erl.c +++ b/erts/etc/win32/erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2021. All Rights Reserved. + * Copyright Ericsson AB 2003-2023. 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. @@ -23,7 +23,7 @@ #include #include "init_file.h" -typedef int ErlexecFunction(int, char **, HANDLE, int); +typedef int ErlexecFunction(int, char **, HANDLE); #define INI_FILENAME L"erl.ini" #define INI_SECTION "erlang" @@ -35,18 +35,8 @@ static void error(char* format, ...); static wchar_t *erlexec_name; static wchar_t *erlexec_dir; -#ifdef WIN32_WERL -#define WERL 1 -int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - PWSTR szCmdLine, int iCmdShow) -{ - int argc = __argc; - wchar_t **argv = __wargv; -#else -#define WERL 0 int wmain(int argc, wchar_t **argv) { -#endif HANDLE erlexec_handle; /* Instance */ ErlexecFunction *win_erlexec; wchar_t *path = malloc(100*sizeof(wchar_t)); @@ -120,7 +110,7 @@ int wmain(int argc, wchar_t **argv) } #endif - return (*win_erlexec)(argc,utf8argv,erlexec_handle,WERL); + return (*win_erlexec)(argc,utf8argv,erlexec_handle); } @@ -316,7 +306,6 @@ static void get_parameters(void) free(ini_filename); } - static void error(char* format, ...) { char sbuf[2048]; @@ -326,11 +315,6 @@ static void error(char* format, ...) vsprintf(sbuf, format, ap); va_end(ap); -#ifndef WIN32_WERL - fprintf(stderr, "%s\n", sbuf); -#else - MessageBox(NULL, sbuf, "Werl", MB_OK|MB_ICONERROR); -#endif + fprintf(stderr, "%s\n", sbuf); exit(1); } - diff --git a/erts/etc/win32/erl.rc b/erts/etc/win32/erl.rc index 035c4a288115..13974c750b4f 100644 --- a/erts/etc/win32/erl.rc +++ b/erts/etc/win32/erl.rc @@ -1,7 +1,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 1998-2021. All Rights Reserved. +// Copyright Ericsson AB 1998-2023. 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. @@ -31,10 +31,10 @@ VS_VERSION_INFO VERSIONINFO { BLOCK "040904e4" { - VALUE "CompanyName", "Ericsson\0" + VALUE "CompanyName", "Ericsson AB\0" VALUE "FileDescription", "Erlang\0" VALUE "FileVersion", ERTS_VERSION_STR - VALUE "LegalCopyright", "Ericsson. All rights reserved.\0" + VALUE "LegalCopyright", OTP_LEGAL_STR VALUE "ProductName", "Erlang/OTP\0" VALUE "ProductVersion", OTP_VERSION_STR } diff --git a/erts/etc/win32/erl_log.c b/erts/etc/win32/erl_log.c index b77491b16901..8cebef271958 100644 --- a/erts/etc/win32/erl_log.c +++ b/erts/etc/win32/erl_log.c @@ -21,7 +21,7 @@ * erl_log: * * Provides a simple debug log for the Erlang emulator. - * It simples echoes its standard intput to the console. + * It simples echoes its standard input to the console. * * Author: Bjorn Gustavsson * Created: 1996-12-06 diff --git a/erts/etc/win32/erlsrv/erlsrv_service.c b/erts/etc/win32/erlsrv/erlsrv_service.c index fb0ca120ac56..2745888091ae 100644 --- a/erts/etc/win32/erlsrv/erlsrv_service.c +++ b/erts/etc/win32/erlsrv/erlsrv_service.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2021. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -535,10 +535,14 @@ static BOOL start_a_service(ServerInfo *srvi){ HANDLE hJob = CreateJobObject(NULL, NULL); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; /* - * Causes all processes associated with the job to terminate when the - * last handle to the job is closed. - */ - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + * JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE + * Causes all processes associated with the job to terminate when the + * last handle to the job is closed. + * + * JOB_OBJECT_LIMIT_BREAKAWAY_OK + * Sometimes we want to break out, for example to start programs in another windows session + */ + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK; SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); if (AssignProcessToJobObject(hJob, GetCurrentProcess()) == FALSE) { log_error(L"Could not AssignProcessToJobObject"); @@ -920,7 +924,7 @@ static VOID WINAPI service_main_loop(DWORD argc, wchar_t **argv){ L"The service is not restarted, ignoring OnFail option."); } else { log_error(L"Erlang machine seems to die " - L"continously, not restarted."); + L"continuously, not restarted."); } CloseHandle(eventStop); set_stopped(ERROR_PROCESS_ABORTED); diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh index 0c15139bd50d..ee24e4bab6d9 100644 --- a/erts/etc/win32/msys_tools/vc/cc.sh +++ b/erts/etc/win32/msys_tools/vc/cc.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2020. All Rights Reserved. +# Copyright Ericsson AB 2002-2021. 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. @@ -39,7 +39,7 @@ ERR_FILE=/tmp/cl.exe.$$.2 MD_FORCED=false # If we're preprocession (only) i.e. -E PREPROCESSING=false -# If we're generating dependencies (implies preprocesing) +# If we're generating dependencies (implies preprocessing) DEPENDENCIES=false # If this is supposed to be a debug build DEBUG_BUILD=false @@ -310,7 +310,7 @@ if [ $LINKING = true ]; then *) out_spec="-o $OUTFILE";; esac - # Descide which standard library to link against + # Decide which standard library to link against case $MD in -ML) stdlib="-lLIBC";; diff --git a/erts/etc/win32/msys_tools/vc/coffix.c b/erts/etc/win32/msys_tools/vc/coffix.c index bf1096c4253e..3221ad6d8558 100644 --- a/erts/etc/win32/msys_tools/vc/coffix.c +++ b/erts/etc/win32/msys_tools/vc/coffix.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2016. All Rights Reserved. + * Copyright Ericsson AB 1999-2021. 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. @@ -43,7 +43,7 @@ static int v_printf(char *format, ...); char *progname; -int verbouse = 0; +int verbose = 0; int main(int argc, char **argv) { @@ -66,7 +66,7 @@ int main(int argc, char **argv) break; case 'v': case 'V': - verbouse = 1; + verbose = 1; default: fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]); break; @@ -152,7 +152,7 @@ static int v_printf(char *format, ...) { va_list ap; int ret = 0; - if (verbouse) { + if (verbose) { va_start(ap, format); ret = vfprintf(stdout, format, ap); va_end(ap); diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile index a0c21a5f5d28..dd4bbd4de670 100644 --- a/erts/etc/win32/nsis/Makefile +++ b/erts/etc/win32/nsis/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2021. All Rights Reserved. +# Copyright Ericsson AB 2003-2023. 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. @@ -68,18 +68,25 @@ REDIST_DLL_NAME=$(shell (sh ./dll_version_helper.sh -n "$(NICEREDISTFILE)" || ec # $(info $$REDIST_DLL_NAME = [${REDIST_DLL_NAME}]) # $(info $$REDIST_FILE = [${REDIST_FILE}]) +VERSION_TICKETS_FILE=$(shell (w32_path.sh -m "$(ERL_TOP)/make/otp_version_tickets" 2>/dev/null || echo "NOTFOUND")) +# NSIS really want the product version number to be at least 4 digits long +OTP_VERSION_LONG=$(shell $(ERL_TOP)/bootstrap/bin/escript.exe vsn_number.escript $(OTP_VERSION) $(VERSION_TICKETS_FILE)) +YEAR=$(shell date +%Y) + release_spec: @NSIS_VER=`makensis.exe -version`; \ case $$NSIS_VER in \ - v2.0b*) \ + v2.* | v3.0 | v3.01) \ echo "Unsupported NSIS version: $$NSIS_VER";;\ - v2.* | v3.*) \ - echo '!define OTP_VERSION "$(SYSTEM_VSN)"' > $(VERSION_HEADER);\ - echo '!define OTP_RELEASE_VERSION "$(OTP_VERSION)"' >> $(VERSION_HEADER);\ + v3.*) \ + echo '!define OTP_RELEASE "$(SYSTEM_VSN)"' > $(VERSION_HEADER);\ + echo '!define OTP_VERSION "$(OTP_VERSION)"' >> $(VERSION_HEADER);\ + echo '!define OTP_VERSION_LONG "$(OTP_VERSION_LONG)"' >> $(VERSION_HEADER);\ echo '!define ERTS_VERSION "$(VSN)"' >> $(VERSION_HEADER);\ echo '!define TESTROOT "$(WTESTROOT)"' >> $(VERSION_HEADER);\ echo '!define OUTFILEDIR "$(WTARGET_DIR)"' >> $(VERSION_HEADER);\ echo '!define WINTYPE "$(WINTYPE)"' >> $(VERSION_HEADER);\ + echo '!define YEAR "$(YEAR)"' >> $(VERSION_HEADER);\ if [ -f $(CUSTOM_MODERN) ];\ then \ echo '!define HAVE_CUSTOM_MODERN 1' >> $(VERSION_HEADER); \ @@ -96,6 +103,8 @@ release_spec: then \ echo '!define HAVE_DOCS 1' >> $(VERSION_HEADER); \ fi;\ + echo "OTP_VERSION = [${OTP_VERSION}]"; \ + echo "OTP_VERSION_LONG = [${OTP_VERSION_LONG}]"; \ echo "Running $(MAKENSIS) $(MAKENSISFLAGS) erlang20.nsi";\ $(MAKENSIS) $(MAKENSISFLAGS) erlang20.nsi;;\ *) \ diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index e744db8bf3be..5380a57742c5 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -7,7 +7,7 @@ ; ; %CopyrightBegin% ; -; Copyright Ericsson AB 2012-2021. All Rights Reserved. +; Copyright Ericsson AB 2012-2023. 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. @@ -32,7 +32,7 @@ !include "erlang.nsh" ; All release specific parameters come from this - Name "${OTP_PRODUCT} ${OTP_VERSION}" + Name "${OTP_PRODUCT} ${OTP_RELEASE}" !include "MUI.nsh" !include "WordFunc.nsh" @@ -52,13 +52,13 @@ Var STARTMENU_FOLDER !define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" ;General - OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_RELEASE_VERSION}.exe" + OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_VERSION}.exe" ;Folder selection page !if ${WINTYPE} == "win64" - InstallDir "$PROGRAMFILES64\erl-${OTP_RELEASE_VERSION}" + InstallDir "$PROGRAMFILES64\Erlang OTP" !else - InstallDir "$PROGRAMFILES\erl-${OTP_RELEASE_VERSION}" + InstallDir "$PROGRAMFILES\Erlang OTP" !endif ;Remember install folder InstallDirRegKey HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" "" @@ -66,9 +66,9 @@ Var STARTMENU_FOLDER ; Set the default start menu folder !if ${WINTYPE} == "win64" - !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (x64)" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_RELEASE} (x64)" !else - !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (i386)" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_RELEASE} (i386)" !endif ;-------------------------------- @@ -99,6 +99,17 @@ Var STARTMENU_FOLDER !insertmacro MUI_LANGUAGE "English" +;-------------------------------- +; Installer file properties + +VIProductVersion "${OTP_VERSION_LONG}" +VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "Ericsson AB" +VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${OTP_VERSION}" +VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "Erlang/OTP installer" +VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright Ericsson AB 2010-${YEAR}. All Rights Reserved." +VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "Erlang/OTP" +VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "${OTP_VERSION}" + ;-------------------------------- ;Language Strings @@ -144,21 +155,19 @@ SubSection /e "Erlang" SecErlang Section "Development" SecErlangDev SectionIn 1 RO - + SetOutPath "$INSTDIR" - -; Don't let Users nor Autenticated Users group create new files -; Avoid dll injection when installing to non /Program Files/ dirs - - StrCmp $INSTDIR $InstallDir cp_files - ; Remove ANY inherited access control + +; Don't let Users nor Authenticated Users group create new files +; Avoid dll injection when installing to non /Program Files/ dirs + + ; Remove ANY inherited access control ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /inheritance:r' SW_HIDE - ; Grant Admin full control + ; Grant Admin full control ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-5-32-544:(OI)(CI)F' SW_HIDE - ; Grant Normal Users read+execute control + ; Grant Normal Users read+execute control ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-1-0:(OI)(CI)RX' SW_HIDE -cp_files: File "${TESTROOT}\Install.ini" File "${TESTROOT}\Install.exe" SetOutPath "$INSTDIR\releases" @@ -190,7 +199,7 @@ cp_files: CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" continue_create: CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Erlang.lnk" \ - "$INSTDIR\bin\werl.exe" + "$INSTDIR\bin\erl.exe" !insertmacro MUI_STARTMENU_WRITE_END ; And once again, the verbosity... @@ -201,7 +210,7 @@ continue_create: StrCmp $MYTEMP "" 0 done_startmenu -; If startmenu was skipped, this might be unnecessary, but wont hurt... +; If startmenu was skipped, this might be unnecessary, but won't hurt... WriteRegStr HKCU "Software\Ericsson\Erlang\${ERTS_VERSION}" \ "" $INSTDIR WriteRegStr HKCU "${MY_STARTMENUPAGE_REGISTRY_KEY}" \ @@ -214,22 +223,28 @@ done_startmenu: WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ - "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})" + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" + WriteRegStr HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "DisplayVersion" "${OTP_VERSION}" + WriteRegStr HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "Publisher" "Ericsson AB" WriteRegStr HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "UninstallString" "$INSTDIR\Uninstall.exe" WriteRegDWORD HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "NoModify" 1 WriteRegDWORD HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "NoRepair" 1 ; Check that the registry could be written, we only check one key, ; but it should be sufficient... ReadRegStr $MYTEMP HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "NoRepair" StrCmp $MYTEMP "" 0 done @@ -238,16 +253,22 @@ done_startmenu: ; do the things below... WriteRegStr HKCU \ - "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ - "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})" + "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" + WriteRegStr HKCU \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "DisplayVersion" "${OTP_VERSION}" + WriteRegStr HKCU \ + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ + "Publisher" "Ericsson AB" WriteRegStr HKCU \ - "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "UninstallString" "$INSTDIR\Uninstall.exe" WriteRegDWORD HKCU \ - "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "NoModify" 1 WriteRegDWORD HKCU \ - "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" \ "NoRepair" 1 done: @@ -464,9 +485,9 @@ noshortcuts: DeleteRegKey /ifempty HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" DeleteRegKey /ifempty HKCU "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" DeleteRegKey HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" DeleteRegKey HKCU \ - "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" + "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP" ; Now remove shell/file associations we'we made... diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh index f3fa476fec0d..f551bc752749 100755 --- a/erts/etc/win32/nsis/find_redist.sh +++ b/erts/etc/win32/nsis/find_redist.sh @@ -153,7 +153,7 @@ fi # Frantic search through two roots with different # version directories. We want to be very specific about the -# directory structures as we wouldnt want to find the wrong +# directory structures as we wouldn't want to find the wrong # redistributables... #echo $BPATH_LIST diff --git a/erts/etc/win32/nsis/vsn_number.escript b/erts/etc/win32/nsis/vsn_number.escript new file mode 100644 index 000000000000..785486004201 --- /dev/null +++ b/erts/etc/win32/nsis/vsn_number.escript @@ -0,0 +1,16 @@ + + +main([OtpVsn, WinPathFile]) -> + try + {ok, Bin} = file:read_file(WinPathFile), + <<"OTP-", _/binary>> = Bin, + case [list_to_integer(Str) || Str <- string:lexemes(OtpVsn, ".")] of + [_,_,_,_|_] -> io:format("~s~n", [OtpVsn]); + [_,_,_] -> io:format("~s.0~n",[OtpVsn]); + [_,_] -> io:format("~s.0.0~n",[OtpVsn]); + [_] -> io:format("~s.0.0.0~n",[OtpVsn]) + end + catch _:_R:_ST -> %% release candidate or development branch set fake version as 0.0.0.0 + %% io:format("Err: ~p ~p~n ~p~n",[_R,_ST, WinPathFile]), + io:format("0.0.0.0~n") + end. diff --git a/erts/etc/win32/port_entry.c b/erts/etc/win32/port_entry.c index 8b1d3a44b878..50d8f31ba2cf 100644 --- a/erts/etc/win32/port_entry.c +++ b/erts/etc/win32/port_entry.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2016. All Rights Reserved. + * Copyright Ericsson AB 1998-2021. 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. @@ -23,7 +23,7 @@ ** erlang process is run as a service. ** Note that this entry point is only for ** Console programs, Windowing programs can just route the WM_QUERYENDSESSION -** and WM_ENDSESSION to the default window procedure to aquire the same +** and WM_ENDSESSION to the default window procedure to acquire the same ** functionality. ** ** Creator Patrik Nyblom diff --git a/erts/etc/win32/start_erl.c b/erts/etc/win32/start_erl.c index 07bcd19b816c..b555dc8c1e7d 100644 --- a/erts/etc/win32/start_erl.c +++ b/erts/etc/win32/start_erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2016. All Rights Reserved. + * Copyright Ericsson AB 1998-2021. 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. @@ -260,7 +260,7 @@ void parse_commandline(void) fprintf(stderr, "NoConfig=TRUE\n"); #endif } else { - fprintf(stderr, "Unkown option: '%S'\n", cmdline); + fprintf(stderr, "Unknown option: '%S'\n", cmdline); exit_help("Unknown command line option"); } break; diff --git a/erts/etc/win32/version.h.src b/erts/etc/win32/version.h.src index 266ebda47dd7..45c1e9944ebe 100644 --- a/erts/etc/win32/version.h.src +++ b/erts/etc/win32/version.h.src @@ -5,3 +5,5 @@ #define OTP_VERSION_INTS %OTP_VERSION_INTS% #define OTP_VERSION_STR "%OTP_VERSION%\0" + +#define OTP_LEGAL_STR "Copyright Ericsson AB 2010-%YEAR%. All Rights Reserved.\0" diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c index 7b21ed37850c..21129ddc3c61 100644 --- a/erts/etc/win32/win_erlexec.c +++ b/erts/etc/win32/win_erlexec.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2021. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -48,7 +48,6 @@ static char* win32_errorstr(int error); static int has_console(void); static char** fnuttify_argv(char **argv); static void free_fnuttified(char **v); -static int windowed = 0; #ifdef LOAD_BEAM_DYNAMICALLY typedef int SysGetKeyFunction(int); @@ -133,103 +132,6 @@ free_env_val(char *value) free(value); } - -int -start_win_emulator(char* utf8emu, char *utf8start_prog, char** utf8argv, int start_detached) -{ - int len; - int argc = 0; - - windowed = 1; - while (utf8argv[argc] != NULL) { - ++argc; - } - - if (start_detached) { - wchar_t *start_prog=NULL; - int result; - int i; - wchar_t **argv; - close(0); - close(1); - close(2); - - set_env("ERL_CONSOLE_MODE", "detached"); - set_env(DLL_ENV, utf8emu); - - utf8argv[0] = utf8start_prog; - utf8argv = fnuttify_argv(utf8argv); - - len = MultiByteToWideChar(CP_UTF8, 0, utf8start_prog, -1, NULL, 0); - start_prog = malloc(len*sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, utf8start_prog, -1, start_prog, len); - - /* Convert utf8argv to multibyte argv */ - argv = malloc((argc+1) * sizeof(wchar_t*)); - for (i=0; i>$CC_SH_DEBUG_LOG echo cl.exe $params >>$CC_SH_DEBUG_LOG fi - eval cl.exe $params >$MSG_FILE 2>$ERR_FILE + eval cl.exe $params > $MSG_FILE 2> $ERR_FILE RES=$? - if test $PREPROCESSING = false; then - cat $ERR_FILE >&2 - tail -n +2 $MSG_FILE - else - tail -n +2 $ERR_FILE >&2 - if test $DEPENDENCIES = true; then - perl -e ' + tail -n +2 $ERR_FILE | grep -v LNK1561 >&2 + if grep "LNK1561" $ERR_FILE; then + rm -f $ERR_FILE $MSG_FILE + rm -rf $TMPOBJDIR + exit $RES + fi + perl -e ' +my $deps = ""; +my @sources = split(" ",$ARGV[1]); + +open(FH, "<", $ARGV[0]) or die $!; + +sub flushDeps() { + if ($deps ne "") { + ## To start a new shell can be very slow so we run all + ## the wslpath translations in a single run + my @paths = split("\n",`for x in $deps; do wslpath -u "\$x"; done`); + foreach (@paths) { + print "\\\n $_"; + } + print "\n\n"; + } +} + +while () { + $_ =~ tr/\r\n/\n/d; + if (/^(.*)\.(c|cpp)$/) { + my $target = "$1"; + flushDeps(); + $deps = shift(@sources) . " "; + print $target.".o:"; + } + if (/^Note: including file:\s*(.*)$/) { + ## Ignore any deps that comes from "Program Files" + next if /Program Files/; + my $file = $1; + $file =~ s/\\/\//g; + $deps .= "'"'"'$file'"'"' "; + } +} +flushDeps(); +' $MSG_FILE "$MPATH" + + rm -f $ERR_FILE $MSG_FILE +else + # Compile + for x in $SOURCES; do + # Compile each source + if [ $LINKING = false ]; then + # We should have an output defined, which is a directory + # or an object file + case $OUTFILE in + /*.o) + # Simple output, SOURCES should be one single + n=`echo $SOURCES | wc -w`; + if [ $n -gt 1 ]; then + echo "cc.sh:Error, multiple sources, one object output."; + exit 1; + else + output_filename=`echo $OUTFILE`; + fi;; + *.o) + # Relative path needs no translation + n=`echo $SOURCES | wc -w` + if [ $n -gt 1 ]; then + echo "cc.sh:Error, multiple sources, one object output." + exit 1 + else + output_filename=$OUTFILE + fi;; + /*) + # Absolute directory + o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'` + output_filename=`echo $OUTFILE` + output_filename="$output_filename/${o}";; + *) + # Relative_directory or empty string (.//x.o is valid) + o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'` + output_filename="./${OUTFILE}/${o}";; + esac + else + # We are linking, which means we build objects in a temporary + # directory and link from there. We should retain the basename + # of each source to make examining the exe easier... + o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'` + output_filename=$TMPOBJDIR/$o + ACCUM_OBJECTS="$ACCUM_OBJECTS $output_filename" + fi + # Now we know enough, lets try a compilation... + if [ $USEABSPATH = true ]; then + MPATH=`w32_path.sh -a -d $x` + else + MPATH=`w32_path.sh -d $x` + fi + if [ $PREPROCESSING = true ]; then + output_flag="-E" + else + output_flag="/FS -c -Fo`w32_path.sh -a -d ${output_filename}`" + fi + params="$COMMON_CFLAGS $MD $DEBUG_FLAGS $OPTIMIZE_FLAGS \ + $CMD ${output_flag} $MPATH" + if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then + echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG + echo cl.exe $params >>$CC_SH_DEBUG_LOG + fi + eval cl.exe $params >$MSG_FILE 2>$ERR_FILE + RES=$? + if test $PREPROCESSING = false; then + cat $ERR_FILE >&2 + tail -n +2 $MSG_FILE + else + tail -n +2 $ERR_FILE >&2 + if test $DEPENDENCIES = true; then + perl -e ' my $file = "'$x'"; while (<>) { next unless /^#line/; @@ -331,18 +400,18 @@ if (@f) { print "\n\n"; print STDERR "Made dependencies for $file\n"; }' $MSG_FILE - else - cat $MSG_FILE - fi - fi - rm -f $ERR_FILE $MSG_FILE - if [ $RES != 0 ]; then - echo Failed: cl.exe $params - rm -rf $TMPOBJDIR - exit $RES - fi -done - + else + cat $MSG_FILE + fi + fi + rm -f $ERR_FILE $MSG_FILE + if [ $RES != 0 ]; then + echo Failed: cl.exe $params + rm -rf $TMPOBJDIR + exit $RES + fi + done +fi # If we got here, we succeeded in compiling (if there were anything to compile) # The output filename should name an executable if we're linking if [ $LINKING = true ]; then @@ -360,7 +429,7 @@ if [ $LINKING = true ]; then *) out_spec="-o $OUTFILE";; esac - # Descide which standard library to link against + # Decide which standard library to link against case $MD in -ML) stdlib="-lLIBC";; diff --git a/erts/etc/win32/wsl_tools/vc/coffix.c b/erts/etc/win32/wsl_tools/vc/coffix.c index 25b04e12dae4..5d7c25504504 100755 --- a/erts/etc/win32/wsl_tools/vc/coffix.c +++ b/erts/etc/win32/wsl_tools/vc/coffix.c @@ -43,7 +43,7 @@ static int v_printf(char *format, ...); char *progname; -int verbouse = 0; +int verbose = 0; int main(int argc, char **argv) { @@ -66,7 +66,7 @@ int main(int argc, char **argv) break; case 'v': case 'V': - verbouse = 1; + verbose = 1; default: fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]); break; @@ -152,7 +152,7 @@ static int v_printf(char *format, ...) { va_list ap; int ret = 0; - if (verbouse) { + if (verbose) { va_start(ap, format); ret = vfprintf(stdout, format, ap); va_end(ap); diff --git a/erts/example/matrix_nif.erl b/erts/example/matrix_nif.erl index bdc7228ac074..c6420b6de48d 100644 --- a/erts/example/matrix_nif.erl +++ b/erts/example/matrix_nif.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -26,6 +26,9 @@ -export([create/3, pos/3, add/2, size_of/1, to_term/1]). +-nifs([create/3, pos/3, add/2, size_of/1, to_term/1]). + + -define(nif, nif_error(?LINE)). -on_load(on_load/0). diff --git a/erts/example/time_compat.erl b/erts/example/time_compat.erl index 6472a271b629..169f5587b2b0 100644 --- a/erts/example/time_compat.erl +++ b/erts/example/time_compat.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2016. All Rights Reserved. +%% Copyright Ericsson AB 2014-2021. 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. @@ -26,7 +26,7 @@ %% versions. This way your code can automatically take advantage %% of the improvements in the API when available. This is an %% example of how to implement such an API, but it can be used -%% as is if you want to. Just add (a preferrably renamed version of) +%% as is if you want to. Just add (a preferably renamed version of) %% this module to your project, and call the API via this module %% instead of calling the BIFs directly. %% @@ -199,7 +199,7 @@ unique_integer(Modifiers) -> case is_valid_modifier_list(Modifiers) of true -> %% now() converted to an integer - %% fullfill the requirements of + %% fulfill the requirements of %% all modifiers: unique, positive, %% and monotonic... {MS, S, US} = erlang:now(), diff --git a/erts/include/erl_memory_trace_parser.h b/erts/include/erl_memory_trace_parser.h deleted file mode 100644 index 3170ebc0d015..000000000000 --- a/erts/include/erl_memory_trace_parser.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2016. 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% - */ - - -/* - * Description: - * - * Author: Rickard Green - */ - -#ifndef ERL_MTRACE_PARSER_H__ -#define ERL_MTRACE_PARSER_H__ - -#include -#include "erl_fixed_size_int_types.h" - -/* emtp_parse() return values */ -#define EMTP_MIN_ERROR EMTP_NO_TRACE_ERROR - -#define EMTP_NO_TRACE_ERROR (-11) -#define EMTP_HEADER_TAG_IN_BODY_ERROR (-10) -#define EMTP_BODY_TAG_IN_HEADER_ERROR ( -9) -#define EMTP_NOT_SUPPORTED_MTRACE_VERSION_ERROR ( -8) -#define EMTP_NOT_AN_ERL_MTRACE_ERROR ( -7) -#define EMTP_NO_MEMORY_ERROR ( -6) -#define EMTP_BAD_OP_SIZE_ERROR ( -5) -#define EMTP_NO_OPERATIONS_ERROR ( -4) -#define EMTP_NOT_SUPPORTED_64_BITS_TRACE_ERROR ( -3) -#define EMTP_PARSE_ERROR ( -2) -#define EMTP_UNKNOWN_TAG_ERROR ( -1) -#define EMTP_END_OF_TRACE ( 0) -#define EMTP_END_OF_TRACE_GARBAGE_FOLLOWS ( 1) -#define EMTP_ALL_OPS_FILLED ( 2) -#define EMTP_NEED_MORE_TRACE ( 3) -#define EMTP_HEADER_PARSED ( 4) - -/* Allocator flags */ -#define EMTP_ALLOCATOR_FLAG_HAVE_USED_CARRIERS_INFO (1 << 0) - -/* Block type flags */ -/* #define EMTP_BLOCK_TYPE_FLAG_X */ - - -typedef struct { - usgnd_int_32 major; - usgnd_int_32 minor; -} emtp_version; - -typedef struct { - emtp_version parser; - emtp_version trace; -} emtp_versions; - -typedef struct { - int valid; - usgnd_int_32 flags; - char * name; - struct { - usgnd_int_16 no_providers; - usgnd_int_16 * provider; - } carrier; -} emtp_allocator; - -typedef struct { - int valid; - usgnd_int_32 flags; - char * name; - sgnd_int_32 allocator; -} emtp_block_type; - -typedef struct { - emtp_versions version; - int bits; - char * nodename; - char * hostname; - char * pid; - struct { - usgnd_int_32 year; - usgnd_int_32 month; - usgnd_int_32 day; - usgnd_int_32 hour; - usgnd_int_32 minute; - usgnd_int_32 second; - usgnd_int_32 micro_second; - } start_time; - usgnd_int_16 segment_ix; - usgnd_int_16 max_allocator_ix; - emtp_allocator ** allocator; - usgnd_int_16 max_block_type_ix; - emtp_block_type ** block_type; - int have_carrier_info; - int have_segment_carrier_info; -} emtp_info; - -typedef struct emtp_state_ emtp_state; - -enum emtp_op_type_ { - EMTP_UNDEF = 0, - EMTP_ALLOC = 1, - EMTP_REALLOC = 2, - EMTP_FREE = 3, - EMTP_CARRIER_ALLOC = 4, - EMTP_CARRIER_REALLOC = 5, - EMTP_CARRIER_FREE = 6, - EMTP_STOP = 7, - EMTP_EXIT = 8 -}; - -typedef enum emtp_op_type_ emtp_op_type; - -typedef struct { - usgnd_int_16 type; - usgnd_int_16 carrier_type; - usgnd_int_max new_ptr; - usgnd_int_max prev_ptr; - usgnd_int_max new_size; -} emtp_block_op; - -typedef struct { - emtp_op_type type; - struct { - usgnd_int_32 secs; - usgnd_int_32 usecs; - } time; - union { - emtp_block_op block; - usgnd_int_32 exit_status; - } u; -} emtp_operation; - -const char *emtp_error_string(int); -int emtp_get_info(emtp_info *ip, size_t *isz, emtp_state *sp); -emtp_state *emtp_state_new(void * (*alloc)(size_t), - void * (*realloc)(void *, size_t), - void (*free)(void *)); -void emtp_state_destroy(emtp_state *sp); -int emtp_parse(emtp_state *sp, - usgnd_int_8 **tracepp, size_t *trace_lenp, - emtp_operation *op_start, size_t op_size, size_t *op_lenp); -#endif diff --git a/erts/include/internal/erl_memory_trace_protocol.h b/erts/include/internal/erl_memory_trace_protocol.h deleted file mode 100644 index d3e0bcc1f457..000000000000 --- a/erts/include/internal/erl_memory_trace_protocol.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2016. 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% - */ - - -/* - * Description: - * - * Author: Rickard Green - */ - -#ifndef ERL_MEMORY_TRACE_PROTOCOL_H__ -#define ERL_MEMORY_TRACE_PROTOCOL_H__ - -/* - * Increase ERTS_MT_MAJOR_VSN and set ERTS_MT_MINOR_VSN to 0 - * when backward incompatible changes are made in the protocol. - * - * Increase ERTS_MT_MINOR_VSN when backward compatible changes are - * made in the protocol. - */ -#define ERTS_MT_MAJOR_VSN (2) -#define ERTS_MT_MINOR_VSN (0) - -/* Trace flags */ - -#define ERTS_MT_64_BIT_FLAG (1 << 0) -#define ERTS_MT_CRR_INFO (1 << 1) -#define ERTS_MT_SEG_CRR_INFO (1 << 2) - -/* Header flags */ -/* Allocator flags */ - -#define ERTS_MT_ALLCTR_USD_CRR_INFO (1 << 0) - -/* Block type flags */ - - - -/* Entry tags */ - -#define ERTS_MT_V1_ALLOCATOR_TAG (1) -#define ERTS_MT_V1_BLOCK_TYPE_TAG (2) -#define ERTS_MT_V1_ALLOC_TAG (3) -#define ERTS_MT_V1_REALLOC_NPB_TAG (4) -#define ERTS_MT_V1_REALLOC_MV_TAG (5) -#define ERTS_MT_V1_REALLOC_NMV_TAG (6) -#define ERTS_MT_V1_FREE_TAG (7) -#define ERTS_MT_V1_TIME_INC_TAG (8) -#define ERTS_MT_V1_STOP_TAG (9) -#define ERTS_MT_V1_EXIT_TAG (10) - -#define ERTS_MT_END_OF_HDR_TAG (0) -#define ERTS_MT_ALLOCATOR_HDR_TAG (1) -#define ERTS_MT_BLOCK_TYPE_HDR_TAG (2) - -#define ERTS_MT_EXIT_BDY_TAG (0) -#define ERTS_MT_STOP_BDY_TAG (1) -#define ERTS_MT_ALLOC_BDY_TAG (2) -#define ERTS_MT_REALLOC_BDY_TAG (3) -#define ERTS_MT_FREE_BDY_TAG (4) -#define ERTS_MT_CRR_ALLOC_BDY_TAG (5) -#define ERTS_MT_CRR_REALLOC_BDY_TAG (6) -#define ERTS_MT_CRR_FREE_BDY_TAG (7) -#define ERTS_MT_TIME_INC_BDY_TAG (8) -#define ERTS_MT_X_BDY_TAG (9) - -/* X subtags */ -#if 0 -#define ERTS_MT_X_ _BDY_TAG (0) -#endif - -#define ERTS_MT_START_WORD (0xfff04711) -/* Entry header fields */ - -#define ERTS_MT_UI8_MSB_EHDR_FLD_SZ (0) -#define ERTS_MT_UI16_MSB_EHDR_FLD_SZ (1) -#define ERTS_MT_UI32_MSB_EHDR_FLD_SZ (2) -#define ERTS_MT_UI64_MSB_EHDR_FLD_SZ (3) -#define ERTS_MT_UI_MSB_EHDR_FLD_SZ ERTS_MT_UI64_MSB_EHDR_FLD_SZ -#define ERTS_MT_TAG_EHDR_FLD_SZ (4) - -#define ERTS_MT_UI8_MSB_EHDR_FLD_MSK ((1 << ERTS_MT_UI8_MSB_EHDR_FLD_SZ)-1) -#define ERTS_MT_UI16_MSB_EHDR_FLD_MSK ((1 << ERTS_MT_UI16_MSB_EHDR_FLD_SZ)-1) -#define ERTS_MT_UI32_MSB_EHDR_FLD_MSK ((1 << ERTS_MT_UI32_MSB_EHDR_FLD_SZ)-1) -#define ERTS_MT_UI64_MSB_EHDR_FLD_MSK ((1 << ERTS_MT_UI64_MSB_EHDR_FLD_SZ)-1) -#define ERTS_MT_UI_MSB_EHDR_FLD_MSK ERTS_MT_UI64_MSB_EHDR_FLD_MSK -#define ERTS_MT_TAG_EHDR_FLD_MSK ((1 << ERTS_MT_TAG_EHDR_FLD_SZ)-1) - -/* Time increment word */ -#define ERTS_MT_TIME_INC_SECS_SHIFT 20 -#define ERTS_MT_TIME_INC_USECS_SHIFT 0 - -#define ERTS_MT_TIME_INC_SECS_MASK ((1 << 12) - 1) -#define ERTS_MT_TIME_INC_USECS_MASK ((1 << 20) - 1) - - -#define ERTS_MT_MAX_V1_HEADER_ENTRY_SIZE (2 + 2 + 1 + 255 + 2) -/* Largest v1 header entry is block type entry (ERTS_MT_V1_BLOCK_TYPE_TAG) */ -#define ERTS_MT_MAX_V1_BODY_ENTRY_SIZE (2 + 8 + 8 + 8 + 4) -/* Largest body entry is realloc moved entry (ERTS_MT_V1_REALLOC_MV_TAG) */ - - -#define ERTS_MT_MAX_HEADER_ENTRY_SIZE (1 + 2 + 2 + 1 + 255 + 2) -/* Largest header entry is block type entry (ERTS_MT_BLOCK_TYPE_TAG) */ -#define ERTS_MT_MAX_BODY_ENTRY_SIZE ERTS_MT_MAX_CRR_REALLOC_SIZE -/* Largest body entry is carrier realloc entry (ERTS_MT_CRR_REALLOC_BDY_TAG) */ - -/* - * - * Entry header: - * - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ... |MSB2|MSB1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Time inc entry field: - * - * 31 23 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Seconds | Micro Seconds | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -#define ERTS_MT_MAX_CRR_ALLOC_SIZE (1 + 2 + 2 + 2 + 8 + 8 + 4) - -/* - * ERTS_MT_CRR_ALLOC_BDY_TAG: - * N 1 2 3 4 5 - * MSB 1-0 1-0 7|3-0 7|3-0 3-0 - * SZ 1 2 2-1 2-1 8|4-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI16 UI64|UI32 UI64|UI32 UI32 - * +---+----+...--+...--+...-------+...-------+...-------+ - * |Tag| Hdr|CType| Type| Out ptr | In size | Time inc | - * +---+----+...--+...--+...-------+...-------+...-------+ - * - */ - -#define ERTS_MT_MAX_ALLOC_SIZE (1 + 2 + 2 + 8 + 8 + 4) -/* - * ERTS_MT_ALLOC_BDY_TAG: - * N 1 2 3 4 - * MSB 1-0 7|3-0 7|3-0 3-0 - * SZ 1 2 2-1 8|4-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI64|UI32 UI64|UI32 UI32 - * +---+----+...--+...-------+...-------+...-------+ - * |Tag| Hdr| Type| Out ptr | In size | Time inc | - * +---+----+...--+...-------+...-------+...-------+ - * - */ - -#define ERTS_MT_MAX_CRR_REALLOC_SIZE (1 + 2 + 2 + 2 + 8 + 8 + 8 + 4) -/* - * ERTS_MT_CRR_REALLOC_BDY_TAG: - * N 1 2 3 4 5 6 - * MSB 1-0 1-0 7|3-0 7|3-0 7|3-0 3-0 - * SZ 1 2 2-1 2-1 8|4-1 8|4-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI16 UI64|UI32 UI64|UI32 UI64|UI32 UI32 - * +---+----+...--+...--+...-------+...-------+...-------+...-------+ - * |Tag| Hdr|CType| Type| Out ptr | In ptr | In size | Time inc | - * +---+----+...--+...--+...-------+...-------+...-------+...-------+ - * - */ - -#define ERTS_MT_MAX_REALLOC_SIZE (1 + 2 + 2 + 8 + 8 + 8 + 4) -/* - * ERTS_MT_REALLOC_BDY_TAG: - * N 1 2 3 4 5 - * MSB 1-0 7|3-0 7|3-0 7|3-0 3-0 - * SZ 1 2 2-1 8|4-1 8|4-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI64|UI32 UI64|UI32 UI64|UI32 UI32 - * +---+----+...--+...-------+...-------+...-------+...-------+ - * |Tag| Hdr| Type| Out ptr | In ptr | In size | Time inc | - * +---+----+...--+...-------+...-------+...-------+...-------+ - * - */ - -#define ERTS_MT_MAX_CRR_FREE_SIZE (1 + 2 + 2 + 2 + 8 + 4) -/* - * ERTS_MT_CRR_FREE_BDY_TAG: - * N 1 2 3 4 - * MSB 1-0 1-0 7|3-0 3-0 - * SZ 1 2 2-1 2-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI16 UI64|UI32 UI32 - * +---+----+...--+...--+...-------+...-------+ - * |Tag| Hdr|CType| Type| In ptr | Time inc | - * +---+----+...--+...--+...-------+...-------+ - * - */ - -#define ERTS_MT_MAX_FREE_SIZE (1 + 2 + 2 + 8 + 4) -/* - * ERTS_MT_FREE_BDY_TAG: - * N 1 2 3 - * MSB 1-0 7|3-0 3-0 - * SZ 1 2 2-1 8|4-1 4-1 - * UIT UI8 UI16 UI16 UI64|UI32 UI32 - * +---+----+...--+...-------+...-------+ - * |Tag| Hdr| Type| In ptr | Time inc | - * +---+----+...--+...-------+...-------+ - * - */ - -/* - * ERTS_MT_X_BDY_TAG: - * N - * MSB - * SZ 1 2 1 - * UIT UI8 UI16 UI8 - * +---+-----+------+... ...+ - * |Tag|TotSz|SubTag| | - * +---+-----+------+... ...+ - * - * ^ ^ - * | | - * +------ TotSz bytes -----+ - * - * X for extension - * - * * Tag equals ERTS_MT_X_BDY_TAG. - * * TotSz contains the total size of the entry. - * * SubTag is used to distinguish between different sub entries - * passed in X entries. - * - */ - - - -#endif /* #ifndef ERL_MEMORY_TRACE_PROTOCOL_H__ */ - diff --git a/erts/include/internal/erl_misc_utils.h b/erts/include/internal/erl_misc_utils.h index b05aeae964a3..3e6352150d53 100644 --- a/erts/include/internal/erl_misc_utils.h +++ b/erts/include/internal/erl_misc_utils.h @@ -35,7 +35,7 @@ typedef struct { erts_cpu_info_t *erts_cpu_info_create(void); void erts_cpu_info_destroy(erts_cpu_info_t *cpuinfo); -int erts_cpu_info_update(erts_cpu_info_t *cpuinfo); +int erts_cpu_info_update(erts_cpu_info_t *cpuinfo, int skip_read_topology); int erts_get_cpu_configured(erts_cpu_info_t *cpuinfo); int erts_get_cpu_online(erts_cpu_info_t *cpuinfo); int erts_get_cpu_available(erts_cpu_info_t *cpuinfo); diff --git a/erts/include/internal/ethr_atomics.h b/erts/include/internal/ethr_atomics.h index 06568201ad3a..02cbc7584b8e 100644 --- a/erts/include/internal/ethr_atomics.h +++ b/erts/include/internal/ethr_atomics.h @@ -10,7 +10,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2016. All Rights Reserved. + * Copyright Ericsson AB 2011-2021. 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. @@ -62,7 +62,7 @@ * - read * - init * - * Appart from a function implementing the atomic operation + * Apart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following * implied memory barrier semantics: diff --git a/erts/include/internal/ethr_internal.h b/erts/include/internal/ethr_internal.h index 986e2b84de6d..44c26ba952fd 100644 --- a/erts/include/internal/ethr_internal.h +++ b/erts/include/internal/ethr_internal.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2020. All Rights Reserved. + * Copyright Ericsson AB 2010-2021. 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. @@ -56,28 +56,22 @@ ethr_ts_event *ethr_get_tse__(void); ETHR_PROTO_NORETURN__ ethr_abort__(void); #ifdef ETHR_INCLUDE_MONOTONIC_CLOCK__ -#undef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME -#if defined(ETHR_HAVE_CLOCK_GETTIME_MONOTONIC) \ - || defined(ETHR_HAVE_MACH_CLOCK_GET_TIME) \ - || defined(ETHR_HAVE_GETHRTIME) -#ifdef ETHR_TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef ETHR_HAVE_SYS_TIME_H -# include -# else +# undef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME +# if defined(ETHR_HAVE_CLOCK_GETTIME_MONOTONIC) \ + || defined(ETHR_HAVE_MACH_CLOCK_GET_TIME) \ + || defined(ETHR_HAVE_GETHRTIME) # include +# ifdef ETHR_HAVE_SYS_TIME_H +# include +# endif # endif -#endif -#ifdef ETHR_HAVE_MACH_CLOCK_GET_TIME -#include -#include -#endif -#define ETHR_HAVE_ETHR_GET_MONOTONIC_TIME +# ifdef ETHR_HAVE_MACH_CLOCK_GET_TIME +# include +# include +# endif +# define ETHR_HAVE_ETHR_GET_MONOTONIC_TIME ethr_sint64_t ethr_get_monotonic_time(void); int ethr_get_monotonic_time_is_broken(void); -#endif #endif /* ETHR_INCLUDE_MONOTONIC_CLOCK__ */ void ethr_init_event__(void); diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h index 8ef3b1e40bfc..4a9fa8b3f553 100644 --- a/erts/include/internal/ethr_mutex.h +++ b/erts/include/internal/ethr_mutex.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2016. All Rights Reserved. + * Copyright Ericsson AB 2010-2022. 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. @@ -341,6 +341,7 @@ struct ethr_rwmutex_ { int ethr_rwmutex_set_reader_group(int); int ethr_rwmutex_init_opt(ethr_rwmutex *, ethr_rwmutex_opt *); int ethr_rwmutex_init(ethr_rwmutex *); +size_t ethr_rwmutex_size(ethr_rwmutex *); int ethr_rwmutex_destroy(ethr_rwmutex *); #if defined(ETHR_USE_OWN_RWMTX_IMPL__) \ || !defined(ETHR_TRY_INLINE_FUNCS) \ diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index a683ccee9b55..e1aa6d412699 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2021. All Rights Reserved. + * Copyright Ericsson AB 2004-2023. 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. @@ -95,10 +95,12 @@ #endif ETHR_PROTO_NORETURN__ -ethr_assert_failed(const char *file, int line, const char *func, char *a); +ethr_assert_failed(const char *file, int line, const char *func, const char *a); #ifdef ETHR_DEBUG -#define ETHR_ASSERT(A) \ - ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__, #A))) +#define ETHR_ASSERT(A) \ + ((void) ((A) ? \ + ((void) 1) : \ + ethr_assert_failed(__FILE__, __LINE__, __func__, #A))) #else #define ETHR_ASSERT(A) ((void) 1) #endif @@ -312,6 +314,10 @@ ETHR_PROTO_NORETURN__ ethr_fatal_error__(const char *file, ETHR_X86_RUNTIME_CONF_HAVE_META(nonstop_tsc_s3) # define ETHR_X86_RUNTIME_CONF_HAVE_NO_NONSTOP_TSC_S3__ \ ETHR_X86_RUNTIME_CONF_HAVE_NO_META(nonstop_tsc_s3) +# define ETHR_X86_RUNTIME_CONF_HAVE_CPUID__ \ + ETHR_X86_RUNTIME_CONF_HAVE_META(cpuid) +# define ETHR_X86_RUNTIME_CONF_HAVE_NO_CPUID__ \ + ETHR_X86_RUNTIME_CONF_HAVE_NO_META(cpuid) #endif @@ -336,6 +342,7 @@ typedef struct { int have_tsc_reliable; int have_nonstop_tsc; int have_nonstop_tsc_s3; + int have_cpuid; #endif #if defined(ETHR_PPC_RUNTIME_CONF__) int have_lwsync; @@ -490,10 +497,11 @@ typedef struct { typedef struct { int detached; /* boolean (default false) */ int suggested_stack_size; /* kilo words (default sys dependent) */ - char *name; /* max 14 char long (default no-name) */ + char *name; /* max 15 char long (default no-name) */ } ethr_thr_opts; #define ETHR_THR_OPTS_DEFAULT_INITER {0, -1, NULL} +#define ETHR_THR_NAME_MAX 15 #if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__) # define ETHR_NEED_SPINLOCK_PROTOTYPES__ diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in index aeb00ef2308b..7a399aac6522 100644 --- a/erts/include/internal/ethread_header_config.h.in +++ b/erts/include/internal/ethread_header_config.h.in @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2021. All Rights Reserved. + * Copyright Ericsson AB 2004-2023. 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. @@ -106,6 +106,11 @@ an ARM processor with ARM DMB instruction support, or not */ #undef ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION +/* Define as a boolean indicating whether you have a gcc compatible compiler + capable of generating the ARM 'isb sy' instruction, and are compiling for + an ARM processor with ARM ISB instruction support, or not */ +#undef ETHR_HAVE_GCC_ASM_ARM_ISB_SY_INSTRUCTION + /* Define as a bitmask corresponding to the word sizes that __sync_synchronize() can handle on your system */ #undef ETHR_HAVE___sync_synchronize @@ -182,7 +187,7 @@ /* Define if you use a gcc that supports the double word cmpxchg instruction */ #undef ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT -/* Define if gcc wont let you clobber ebx with cmpxchg8b and position +/* Define if gcc won't let you clobber ebx with cmpxchg8b and position independent code */ #undef ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX diff --git a/erts/include/internal/gcc/ethr_dw_atomic.h b/erts/include/internal/gcc/ethr_dw_atomic.h index 7e2d46c3543c..f1afd1283927 100644 --- a/erts/include/internal/gcc/ethr_dw_atomic.h +++ b/erts/include/internal/gcc/ethr_dw_atomic.h @@ -72,7 +72,7 @@ typedef volatile ETHR_NATIVE_SU_DW_SINT_T * ethr_native_dw_ptr_t; * This code assumes 8 byte aligned memory in 64-bit mode, and 4 byte * aligned memory in 32-bit mode. A malloc implementation that does * not adhere to these alignment requirements is seriously broken, - * and we wont bother trying to work around it. + * and we won't bother trying to work around it. * * Since memory alignment may be off by one word we need to align at * runtime. We, therefore, need an extra word allocated. diff --git a/erts/include/internal/gcc/ethr_membar.h b/erts/include/internal/gcc/ethr_membar.h index 56344452d320..8572d9975a83 100644 --- a/erts/include/internal/gcc/ethr_membar.h +++ b/erts/include/internal/gcc/ethr_membar.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2021. All Rights Reserved. + * Copyright Ericsson AB 2011-2023. 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. @@ -31,9 +31,9 @@ * ordered around it according to the semantics of the * barrier specified. * - * The C11 aproch is different. The __atomic builtins + * The C11 approach is different. The __atomic builtins * API takes a memory model parameter. Assuming that all - * memory syncronizations using the involved atomic + * memory synchronizations using the involved atomic * variables are made using this API, the synchronizations * will adhere to the memory models used. That is, you do * *not* know how loads and stores will be ordered around @@ -69,7 +69,7 @@ * Why is this? Since all synchronizations is expected * to be made using the __atomic builtins, memory * barriers only have to be issued by some of them, - * and you do not know which ones wont issue memory + * and you do not know which ones won't issue memory * barriers. * * One can easily be fooled into believing that when @@ -93,8 +93,8 @@ * __ATOMIC_ACQUIRE and __ATOMIC_RELEASE memory * models. This since an __atomic builtin memory * access using the __ATOMIC_ACQUIRE must at least - * issue an aquire memory barrier and an __atomic - * builtin memory acess with the __ATOMIC_RELEASE + * issue an acquire memory barrier and an __atomic + * builtin memory access with the __ATOMIC_RELEASE * memory model must at least issue a release memory * barrier. Otherwise the two cannot be paired. * 4. All __atomic builtins accessing memory using the @@ -141,6 +141,21 @@ #define ETHR_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory") +#if ETHR_HAVE_GCC_ASM_ARM_ISB_SY_INSTRUCTION +#define ETHR_INSTRUCTION_BARRIER ethr_instruction_fence__() + +static __inline__ __attribute__((__always_inline__)) void +ethr_instruction_fence__(void) +{ + __asm__ __volatile__("isb sy" : : : "memory"); +} +#else +/* !! Note that we DO NOT define a fallback !! + * + * See the definition of ERTS_THR_INSTRUCTION_BARRIER in erl_threads.h for + * details. */ +#endif + #if ETHR_HAVE_GCC_ASM_ARM_DMB_INSTRUCTION static __inline__ __attribute__((__always_inline__)) void @@ -240,7 +255,7 @@ ethr_full_fence__(void) #endif /* - * Define ETHR_READ_DEPEND_MEMORY_BARRIER for all architechtures + * Define ETHR_READ_DEPEND_MEMORY_BARRIER for all architectures * not known to order data dependent loads * * This is a bit too conservative, but better safe than sorry... diff --git a/erts/include/internal/i386/ethr_dw_atomic.h b/erts/include/internal/i386/ethr_dw_atomic.h index e3dbc82518b8..45cd668ac554 100644 --- a/erts/include/internal/i386/ethr_dw_atomic.h +++ b/erts/include/internal/i386/ethr_dw_atomic.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2020. All Rights Reserved. + * Copyright Ericsson AB 2011-2021. 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. @@ -67,7 +67,7 @@ typedef volatile ethr_native_sint128_t__ * ethr_native_dw_ptr_t; * This code assumes 8 byte aligned memory in 64-bit mode, and 4 byte * aligned memory in 32-bit mode. A malloc implementation that does * not adhere to these alignment requirements is seriously broken, - * and we wont bother trying to work around it. + * and we won't bother trying to work around it. * * Since memory alignment may be off by one word we need to align at * runtime. We, therefore, need an extra word allocated. @@ -159,7 +159,7 @@ ethr_native_dw_atomic_cmpxchg_mb(ethr_native_dw_atomic_t *var, #if ETHR_NO_CLOBBER_EBX__ && ETHR_CMPXCHG8B_REGISTER_SHORTAGE /* - * gcc wont let us use ebx as input and we + * gcc won't let us use ebx as input and we * get a register shortage */ @@ -176,7 +176,7 @@ ethr_native_dw_atomic_cmpxchg_mb(ethr_native_dw_atomic_t *var, #elif ETHR_NO_CLOBBER_EBX__ /* - * gcc wont let us use ebx as input + * gcc won't let us use ebx as input */ __asm__ __volatile__( diff --git a/erts/include/internal/i386/ethr_membar.h b/erts/include/internal/i386/ethr_membar.h index d1b72cd538c1..cd00ab59746f 100644 --- a/erts/include/internal/i386/ethr_membar.h +++ b/erts/include/internal/i386/ethr_membar.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2016. All Rights Reserved. + * Copyright Ericsson AB 2011-2023. 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. @@ -31,6 +31,27 @@ #define ETHR_StoreLoad (1 << 2) #define ETHR_StoreStore (1 << 3) +#ifdef ETHR_X86_RUNTIME_CONF__ +#define ETHR_INSTRUCTION_BARRIER ethr_instruction_fence__() + +static __inline__ __attribute__((__always_inline__)) void +ethr_instruction_fence__(void) +{ + ETHR_ASSERT(ETHR_X86_RUNTIME_CONF_HAVE_CPUID__); + +#if ETHR_SIZEOF_PTR == 4 +__asm__ __volatile__("cpuid\n\t" :: "a"(0) : "ebx", "ecx", "edx", "memory"); +#else +__asm__ __volatile__("cpuid\n\t" :: "a"(0) : "rbx", "rcx", "rdx", "memory"); +#endif +} +#else +/* !! Note that we DO NOT define a fallback !! + * + * See the definition of ERTS_THR_INSTRUCTION_BARRIER in erl_threads.h for + * details. */ +#endif + #define ETHR_NO_SSE2_MEMORY_BARRIER__ \ do { \ volatile ethr_sint32_t x__ = 0; \ diff --git a/erts/include/internal/win/ethr_dw_atomic.h b/erts/include/internal/win/ethr_dw_atomic.h index 03311f6025e5..6275852f9399 100644 --- a/erts/include/internal/win/ethr_dw_atomic.h +++ b/erts/include/internal/win/ethr_dw_atomic.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2020. All Rights Reserved. + * Copyright Ericsson AB 2011-2021. 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. @@ -74,7 +74,7 @@ typedef volatile __int64 * ethr_native_dw_ptr_t; * This code assumes 8 byte aligned memory in 64-bit mode, and 4 byte * aligned memory in 32-bit mode. A malloc implementation that does * not adhere to these alignment requirements is seriously broken, - * and we wont bother trying to work around it. + * and we won't bother trying to work around it. * * Since memory alignment may be off by one word we need to align at * runtime. We, therefore, need an extra word allocated. diff --git a/erts/include/internal/win/ethr_membar.h b/erts/include/internal/win/ethr_membar.h index c018f6d8695e..80b0e0e53314 100644 --- a/erts/include/internal/win/ethr_membar.h +++ b/erts/include/internal/win/ethr_membar.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2016. All Rights Reserved. + * Copyright Ericsson AB 2011-2023. 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. @@ -54,9 +54,28 @@ do { \ #elif defined(_M_AMD64) || defined(_M_IX86) +#include #include #include +#ifdef ETHR_X86_RUNTIME_CONF__ +#define ETHR_INSTRUCTION_BARRIER ethr_instruction_fence__() +#pragma intrinsic(__cpuid) + +static ETHR_FORCE_INLINE void +ethr_instruction_fence__(void) +{ + int ignored[4]; + ETHR_ASSERT(ETHR_X86_RUNTIME_CONF_HAVE_CPUID__); + __cpuid(ignored, 0); +} +#else +/* !! Note that we DO NOT define a fallback !! + * + * See the definition of ERTS_THR_INSTRUCTION_BARRIER in erl_threads.h for + * details. */ +#endif + #if ETHR_SIZEOF_PTR == 4 # define ETHR_NO_SSE2_MB__ ETHR_MB_USING_INTERLOCKED__ #endif diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in index d5a5fd0f4d2a..392d10f49341 100644 --- a/erts/lib_src/Makefile.in +++ b/erts/lib_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2021. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -94,7 +94,11 @@ CFLAGS += -DERTS_OPCODE_COUNTER_SUPPORT PRE_LD= else override TYPE=opt +ifeq (@JIT_ENABLED@, yes) +OMIT_OMIT_FP=yes +else OMIT_FP=true +endif TYPE_SUFFIX= PRE_LD= endif @@ -170,15 +174,6 @@ else THR_DEFS = $(filter-out -D_GNU_SOURCE%, $(ETHR_DEFS)) endif -# -# erts (public) library -# - -ERTS_LIB_SRCS = common/erl_memory_trace_parser.c - -ERTS_LIB_DIR=../lib/$(TARGET) -CREATE_DIRS += $(ERTS_LIB_DIR) - ifeq ($(USING_VC),yes) # Windows obj dir MD_OBJ_DIR=$(OBJ_DIR)/MD @@ -191,10 +186,10 @@ CREATE_DIRS += $(MD_OBJ_DIR) \ $(MT_OBJ_DIR) \ $(MTd_OBJ_DIR) -ERTS_MD_LIB_OBJS=$(addprefix $(MD_OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) -ERTS_MDd_LIB_OBJS=$(addprefix $(MDd_OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) -ERTS_MT_LIB_OBJS=$(addprefix $(MT_OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) -ERTS_MTd_LIB_OBJS=$(addprefix $(MTd_OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) +ERTS_MD_LIB_OBJS=$(addprefix $(MD_OBJ_DIR)/,$(notdir $(.c=.o))) +ERTS_MDd_LIB_OBJS=$(addprefix $(MDd_OBJ_DIR)/,$(notdir $(.c=.o))) +ERTS_MT_LIB_OBJS=$(addprefix $(MT_OBJ_DIR)/,$(notdir $(.c=.o))) +ERTS_MTd_LIB_OBJS=$(addprefix $(MTd_OBJ_DIR)/,$(notdir $(.c=.o))) else # --- Not windows --- @@ -202,31 +197,9 @@ else # --- Not windows --- ifneq ($(strip $(ETHR_LIB_NAME)),) r_OBJ_DIR = $(OBJ_DIR)/r CREATE_DIRS += $(r_OBJ_DIR) -ERTS_r_LIB_OBJS=$(addprefix $(r_OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) -endif -ERTS_LIB_OBJS=$(addprefix $(OBJ_DIR)/,$(notdir $(ERTS_LIB_SRCS:.c=.o))) - -endif - -ifeq ($(USING_VC),yes) -ERTS_MD_LIB=$(ERTS_LIB_DIR)/$(LIB_PREFIX)erts_MD$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_MDd_LIB=$(ERTS_LIB_DIR)/$(LIB_PREFIX)erts_MDd$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_MT_LIB=$(ERTS_LIB_DIR)/$(LIB_PREFIX)erts_MT$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_MTd_LIB=$(ERTS_LIB_DIR)/$(LIB_PREFIX)erts_MTd$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_LIBS += \ - $(ERTS_MD_LIB) \ - $(ERTS_MDd_LIB) \ - $(ERTS_MT_LIB) \ - $(ERTS_MTd_LIB) -else - -ERTS_LIB = $(ERTS_LIB_DIR)/$(LIB_PREFIX)erts$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_LIBS += $(ERTS_LIB) - -ifneq ($(strip $(ETHR_LIB_NAME)),) -ERTS_r_LIB = $(ERTS_LIB_DIR)/$(LIB_PREFIX)erts_r$(TYPE_SUFFIX)$(LIB_SUFFIX) -ERTS_LIBS += $(ERTS_r_LIB) +ERTS_r_LIB_OBJS=$(addprefix $(r_OBJ_DIR)/,$(notdir $(.c=.o))) endif +ERTS_LIB_OBJS=$(addprefix $(OBJ_DIR)/,$(notdir $(.c=.o))) endif @@ -340,17 +313,8 @@ YCF_SOURCE_DIR=$(ERL_TOP)/erts/lib_src/yielding_c_fun include $(YCF_SOURCE_DIR)/main_target.mk -$(OBJ_DIR)/MADE: $(YCF_EXECUTABLE) $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS) +$(OBJ_DIR)/MADE: $(YCF_EXECUTABLE) $(ETHREAD_LIB) $(ERTS_INTERNAL_LIBS) $(gen_verbose) -ifeq ($(OMIT_OMIT_FP),yes) - @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' - @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' - @echo '* * * *' - @echo '* * NOTE: Omit frame pointer optimization has been omitted * *' - @echo '* * * *' - @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' - @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' -endif $(V_at)echo $? > $(OBJ_DIR)/MADE # @@ -462,10 +426,8 @@ include ../vsn.mk RELSYSDIR = $(RELEASE_PATH)/erts-$(VSN) RELEASE_INCLUDES= \ - $(ERTS_INCL)/erl_memory_trace_parser.h \ $(ERTS_INCL)/$(TARGET)/erl_int_sizes_config.h \ $(ERTS_INCL)/erl_fixed_size_int_types.h -RELEASE_LIBS=$(ERTS_LIBS) INTERNAL_RELEASE_INCLUDES= \ $(ERTS_INCL_INT)/README \ @@ -479,7 +441,6 @@ INTERNAL_RELEASE_INCLUDES= \ $(ERTS_INCL_INT)/$(TARGET)/ethread_header_config.h \ $(ERTS_INCL_INT)/erl_printf.h \ $(ERTS_INCL_INT)/erl_printf_format.h \ - $(ERTS_INCL_INT)/erl_memory_trace_protocol.h \ $(ERTS_INCL_INT)/erl_misc_utils.h \ $(ERTS_INCL_INT)/erl_errno.h @@ -511,12 +472,6 @@ ifneq ($(strip $(INTERNAL_X_RELEASE_INCLUDE_DIRS)),) "$(RELSYSDIR)/include/internal/$$xdir"; \ done endif -ifneq ($(strip $(RELEASE_LIBS)),) - $(INSTALL_DIR) "$(RELSYSDIR)/lib" - $(INSTALL_DIR) "$(RELEASE_PATH)/usr/lib" - $(INSTALL_DATA) $(RELEASE_LIBS) "$(RELSYSDIR)/lib" - $(INSTALL_DATA) $(RELEASE_LIBS) "$(RELEASE_PATH)/usr/lib" -endif ifneq ($(strip $(INTERNAL_RELEASE_LIBS)),) $(INSTALL_DIR) "$(RELSYSDIR)/lib/internal" $(INSTALL_DATA) $(INTERNAL_RELEASE_LIBS) "$(RELSYSDIR)/lib/internal" diff --git a/erts/lib_src/common/erl_memory_trace_parser.c b/erts/lib_src/common/erl_memory_trace_parser.c deleted file mode 100644 index 0232708ad11a..000000000000 --- a/erts/lib_src/common/erl_memory_trace_parser.c +++ /dev/null @@ -1,1962 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2004-2016. 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% - */ - - -/* - * Description: - * - * Author: Rickard Green - */ - -#include "erl_memory_trace_parser.h" -#include "erl_memory_trace_protocol.h" -#include /* For memcpy */ - -#ifdef DEBUG -#include -#define ASSERT assert -#define PRINT_ERROR_ORIGIN 1 -#if PRINT_ERROR_ORIGIN -#include -#endif -#define PRINT_PARSED_OP 0 -#if PRINT_PARSED_OP -#include -static void print_op(emtp_operation *op_p); -#endif -static void hexdump(void *start, void *end); -#else -#define PRINT_ERROR_ORIGIN 0 -#define PRINT_PARSED_OP 0 -#define ASSERT(B) -#endif - - -#if ERTS_MT_MAJOR_VSN != 2 || ERTS_MT_MINOR_VSN != 0 -#error trace version mismatch (expected version 2.0) -/* Make sure that older versions are supported when implementing - support for newer versions! */ -#endif - - -#if defined(__GNUC__) -# define EMTP_CAN_INLINE 1 -# define EMTP_INLINE __inline__ -#elif defined(__WIN32__) -# define EMTP_CAN_INLINE 1 -# define EMTP_INLINE __forceinline -#else -# define EMTP_CAN_INLINE 0 -# define EMTP_INLINE -#endif - - -#define UI8_SZ 1 -#define UI16_SZ 2 -#define UI32_SZ 4 -#define UI64_SZ 8 - -#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) - -#define DEFAULT_OVERFLOW_BUF_SZ 128 - -#define UNKNOWN_BLOCK_TYPE_IX (-1) -#define UNKNOWN_ALLOCATOR_IX (-1) - -#define INVALID_SIZE (((sgnd_int_32) 1) << 31) -#define INVALID_RESULT ((int) INVALID_SIZE) - -typedef enum { - EMTP_PROGRESS_PARSE_HDR_VSN, - EMTP_PROGRESS_PARSE_HDR_PROLOG, - EMTP_PROGRESS_ALLOC_HDR_INFO, - EMTP_PROGRESS_PARSE_TAGGED_HDR, - EMTP_PROGRESS_PARSE_BODY, - EMTP_PROGRESS_ENDED -} emtp_progress; - -struct emtp_state_ { - - /* Trace version */ - emtp_version version; - - /* Flags */ - usgnd_int_32 flags; - - /* Progress */ - emtp_progress progress; - - /* Name, host, and pid as strings */ - char nodename[256]; - char hostname[256]; - char pid[256]; - - /* Local time on the traced node when the node started */ - struct { - usgnd_int_32 year; - usgnd_int_32 month; - usgnd_int_32 day; - usgnd_int_32 hour; - usgnd_int_32 minute; - usgnd_int_32 second; - usgnd_int_32 micro_second; - } start_time; - - /* Function to parse body with */ - int (*parse_body_func)(emtp_state *, - usgnd_int_8 **, - usgnd_int_8 *, - emtp_operation **, - emtp_operation *, - size_t); - /* Current time elapsed */ - struct { - usgnd_int_32 secs; - usgnd_int_32 usecs; - } time; - - /* */ - - int force_return; - - /* Overflow buffer */ - size_t overflow_size; - size_t overflow_buf_size; - usgnd_int_8 * overflow; - sgnd_int_32 fetch_size; - int known_need; - - usgnd_int_16 segment_ix; - usgnd_int_16 max_allocator_ix; - emtp_allocator ** allocator; - usgnd_int_16 max_block_type_ix; - emtp_block_type ** block_type; - - /* Memory allocation functions */ - void * (*alloc)(size_t); - void * (*realloc)(void *, size_t); - void (*free)(void *); - -}; - -static char unknown_allocator[] = "unknown_allocator"; -static char unknown_block_type[] = "unknown_block_type"; - -const char * -emtp_error_string(int res) -{ - switch (res) { - case EMTP_NO_TRACE_ERROR: - return "no trace error"; - case EMTP_HEADER_TAG_IN_BODY_ERROR: - return "header tag in body error"; - case EMTP_BODY_TAG_IN_HEADER_ERROR: - return "body tag in header error"; - case EMTP_NOT_SUPPORTED_MTRACE_VERSION_ERROR: - return "not supported mtrace version error"; - case EMTP_NOT_AN_ERL_MTRACE_ERROR: - return "not an erl mtrace error"; - case EMTP_NO_MEMORY_ERROR: - return "no memory error"; - case EMTP_BAD_OP_SIZE_ERROR: - return "bad op size error"; - case EMTP_NO_OPERATIONS_ERROR: - return "no operations error"; - case EMTP_NOT_SUPPORTED_64_BITS_TRACE_ERROR: - return "not supported 64 bits trace error"; - case EMTP_PARSE_ERROR: - return "parse error"; - case EMTP_UNKNOWN_TAG_ERROR: - return "unknown tag error"; - case EMTP_END_OF_TRACE: - return "end of trace"; - case EMTP_END_OF_TRACE_GARBAGE_FOLLOWS: - return "end of trace; garbage follows"; - case EMTP_ALL_OPS_FILLED: - return "all operations filled"; - case EMTP_NEED_MORE_TRACE: - return "need more trace"; - case EMTP_HEADER_PARSED: - return "header parsed"; - default: - return NULL; - } - -} - -int -emtp_get_info(emtp_info *infop, size_t *info_szp, emtp_state *statep) -{ - if (!infop || !info_szp || *info_szp < sizeof(emtp_info)) - return 0; - - infop->version.parser.major = ERTS_MT_MAJOR_VSN; - infop->version.parser.minor = ERTS_MT_MINOR_VSN; - - *info_szp = sizeof(emtp_version); - - if (!statep || statep->version.major == 0) - return 1; - - infop->version.trace.major = statep->version.major; - infop->version.trace.minor = statep->version.minor; - - *info_szp = sizeof(emtp_versions); - - if (statep->progress != EMTP_PROGRESS_PARSE_BODY - && statep->progress != EMTP_PROGRESS_ENDED) - return 1; - - infop->bits = (statep->flags & ERTS_MT_64_BIT_FLAG - ? 64 - : 32); - - infop->nodename = statep->nodename; - infop->hostname = statep->hostname; - infop->pid = statep->pid; - - infop->start_time.year = statep->start_time.year; - infop->start_time.month = statep->start_time.month; - infop->start_time.day = statep->start_time.day; - infop->start_time.hour = statep->start_time.hour; - infop->start_time.minute = statep->start_time.minute; - infop->start_time.second = statep->start_time.second; - infop->start_time.micro_second = statep->start_time.micro_second; - - infop->have_carrier_info = statep->flags & ERTS_MT_CRR_INFO; - infop->have_segment_carrier_info = statep->flags & ERTS_MT_SEG_CRR_INFO; - infop->segment_ix = statep->segment_ix; - infop->max_allocator_ix = statep->max_allocator_ix; - infop->allocator = statep->allocator; - infop->max_block_type_ix = statep->max_block_type_ix; - infop->block_type = statep->block_type; - - *info_szp = sizeof(emtp_info); - - return 1; -} - -emtp_state * -emtp_state_new(void * (*alloc)(size_t), - void * (*realloc)(void *, size_t), - void (*free)(void *)) -{ - emtp_state *statep; - - if (!alloc || !realloc || !free) - return NULL; - - statep = (emtp_state *) (*alloc)(sizeof(emtp_state)); - if (!statep) - return NULL; - - statep->version.major = 0; - statep->version.minor = 0; - statep->flags = 0; - statep->progress = EMTP_PROGRESS_PARSE_HDR_VSN; - - statep->nodename[0] = '\0'; - statep->hostname[0] = '\0'; - statep->pid[0] = '\0'; - - statep->start_time.year = 0; - statep->start_time.month = 0; - statep->start_time.day = 0; - statep->start_time.hour = 0; - statep->start_time.minute = 0; - statep->start_time.second = 0; - statep->start_time.micro_second = 0; - - statep->parse_body_func = NULL; - statep->time.secs = 0; - statep->time.usecs = 0; - statep->force_return = 0; - statep->overflow_size = 0; - statep->overflow_buf_size = DEFAULT_OVERFLOW_BUF_SZ; - statep->overflow = - (usgnd_int_8 *) (*alloc)(DEFAULT_OVERFLOW_BUF_SZ*sizeof(usgnd_int_8)); - statep->fetch_size = 0; - statep->known_need = 0; - statep->segment_ix = 0; - statep->max_allocator_ix = 0; - statep->allocator = NULL; - statep->max_block_type_ix = 0; - statep->block_type = NULL; - statep->alloc = alloc; - statep->realloc = realloc; - statep->free = free; - - return statep; -} - -void -emtp_state_destroy(emtp_state *statep) -{ - void (*freep)(void *); - int i; - - if (!statep) - return; - - freep = statep->free; - - if (statep->overflow) - (*freep)((void *) statep->overflow); - - if (statep->allocator) { - for (i = -1; i <= statep->max_allocator_ix; i++) { - if (statep->allocator[i]) { - if (statep->allocator[i]->name - && statep->allocator[i]->name != unknown_allocator) - (*freep)((void *) statep->allocator[i]->name); - if (statep->allocator[i]->carrier.provider) - (*freep)((void *) statep->allocator[i]->carrier.provider); - (*freep)((void *) statep->allocator[i]); - } - } - statep->allocator--; - (*freep)((void *) statep->allocator); - } - - if (statep->block_type) { - for (i = -1; i <= statep->max_block_type_ix; i++) { - if (statep->block_type[i]) { - if (statep->block_type[i]->name - && statep->block_type[i]->name != unknown_block_type) - (*freep)((void *) statep->block_type[i]->name); - (*freep)((void *) statep->block_type[i]); - } - } - statep->block_type--; - (*freep)((void *) statep->block_type); - } - - (*freep)((void *) statep); -} - -/* - * The following macros are for use in emtp_parse(), parse_vX_body, - * and parse_header. - * - * Note that some of them depend on function local variable names - * and lables: - * - * Variables: - * * result -> the result to return - * * statep -> pointer to the state - * - * Lables: - * * restore_return -> restore then return result - */ - - -#define GET_UI8(UI, BP) ((UI) = *((BP)++)) -#define SKIP_UI8(BP) ((BP)++) - -#define GET_UI16(UI, BP) \ - do { \ - (UI) = ((( (usgnd_int_16) (BP)[0]) << 8) \ - | ((usgnd_int_16) (BP)[1])); \ - (BP) += UI16_SZ; \ -} while(0) -#define SKIP_UI16(BP) ((BP) += UI16_SZ) - - -#define GET_UI32(UI, BP) \ - do { \ - (UI) = ((( (usgnd_int_32) (BP)[0]) << 24) \ - | (((usgnd_int_32) (BP)[1]) << 16) \ - | (((usgnd_int_32) (BP)[2]) << 8) \ - | ( (usgnd_int_32) (BP)[3])); \ - (BP) += UI32_SZ; \ -} while(0) -#define SKIP_UI32(BP) ((BP) += UI32_SZ) - -#define GET_UI64(UI, BP) \ - do { \ - (UI) = ((( (usgnd_int_64) (BP)[0]) << 56) \ - | (((usgnd_int_64) (BP)[1]) << 48) \ - | (((usgnd_int_64) (BP)[2]) << 40) \ - | (((usgnd_int_64) (BP)[3]) << 32) \ - | (((usgnd_int_64) (BP)[4]) << 24) \ - | (((usgnd_int_64) (BP)[5]) << 16) \ - | (((usgnd_int_64) (BP)[6]) << 8) \ - | ( (usgnd_int_64) (BP)[7])); \ - (BP) += UI64_SZ; \ -} while(0) -#define SKIP_UI64(BP) ((BP) += UI64_SZ) - -#define GET_VSZ_UI16(UI, BP, MSB) \ -do { \ - usgnd_int_16 ui_ = 0; \ - switch ((MSB)) { \ - case 1: ui_ |= (usgnd_int_16) *((BP)++); ui_ <<= 8; \ - case 0: ui_ |= (usgnd_int_16) *((BP)++); break; \ - default: ERROR(EMTP_PARSE_ERROR); \ - } \ - (UI) = ui_; \ -} while (0) - -#define GET_VSZ_UI32(UI, BP, MSB) \ -do { \ - usgnd_int_32 ui_ = 0; \ - switch ((MSB)) { \ - case 3: ui_ |= (usgnd_int_32) *((BP)++); ui_ <<= 8; \ - case 2: ui_ |= (usgnd_int_32) *((BP)++); ui_ <<= 8; \ - case 1: ui_ |= (usgnd_int_32) *((BP)++); ui_ <<= 8; \ - case 0: ui_ |= (usgnd_int_32) *((BP)++); break; \ - default: ERROR(EMTP_PARSE_ERROR); \ - } \ - (UI) = ui_; \ -} while (0) - -#define GET_VSZ_UI64(UI, BP, MSB) \ -do { \ - usgnd_int_64 ui_ = 0; \ - switch ((MSB)) { \ - case 7: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 6: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 5: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 4: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 3: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 2: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 1: ui_ |= (usgnd_int_64) *((BP)++); ui_ <<= 8; \ - case 0: ui_ |= (usgnd_int_64) *((BP)++); break; \ - default: ERROR(EMTP_PARSE_ERROR); \ - } \ - (UI) = ui_; \ -} while (0) - - -#if HAVE_INT_64 -#define GET_VSZ_UIMAX(UI, BP, MSB) \ -do { \ - usgnd_int_64 ui64_; \ - GET_VSZ_UI64(ui64_, (BP), (MSB)); \ - (UI) = (usgnd_int_max) ui64_; \ -} while (0) -#else -#define GET_VSZ_UIMAX(UI, BP, MSB) \ -do { \ - usgnd_int_32 ui32_; \ - GET_VSZ_UI32(ui32_, (BP), (MSB)); \ - (UI) = (usgnd_int_max) ui32_; \ -} while (0) -#endif - - - -#define INC_TIME(C_SECS, C_USECS, SECS, USECS) \ -do { \ - if ((USECS) >= 1000000) \ - ERROR(EMTP_PARSE_ERROR); \ - (C_SECS) += (SECS); \ - (C_USECS) += (USECS); \ - if ((C_USECS) >= 1000000) { \ - (C_USECS) -= 1000000; \ - (C_SECS)++; \ - } \ -} while (0) - -#if PRINT_ERROR_ORIGIN -#include -#define ERROR(E) \ -do { \ - result = (E); \ - fprintf(stderr,"ERROR:%s:%d: result=%d\n",__FILE__,__LINE__,result);\ - statep->force_return = 1; abort(); \ - goto restore_return; \ -} while (0) -#else -#define ERROR(E) do { \ - result = (E); \ - statep->force_return = 1; \ - goto restore_return; \ -} while (0) -#endif - -#define NEED(NSZ, TSZ) \ -do { \ - sgnd_int_32 need_ = (NSZ); \ - if (need_ > (TSZ)) { \ - statep->known_need = 1; \ - statep->fetch_size = need_; \ - result = EMTP_NEED_MORE_TRACE; \ - goto restore_return; \ - } \ -} while (0) - -#define NEED_AT_LEAST(NSZ, FSZ, TSZ) \ -do { \ - sgnd_int_32 need_ = (NSZ); \ - ASSERT(need_ <= (FSZ)); \ - if (need_ > (TSZ)) { \ - statep->known_need = 0; \ - statep->fetch_size = (FSZ); \ - result = EMTP_NEED_MORE_TRACE; \ - goto restore_return; \ - } \ -} while (0) - - -#define SECS_PER_DAY (60*60*24) -#define IS_LEAP_YEAR(X) (((X) % 4 == 0 && (X) % 100 != 0) || (X) % 400 == 0) - -static void -set_start_time(emtp_state *state, - usgnd_int_32 giga_seconds, - usgnd_int_32 seconds, - usgnd_int_32 micro_seconds) -{ - /* Input is elapsed time since 1970-01-01 00:00.000000 (UTC) */ - - usgnd_int_32 year, days_of_this_year, days, secs, month; - usgnd_int_32 days_of_month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; - - days = 1000000000 / SECS_PER_DAY; - secs = 1000000000 % SECS_PER_DAY; - days *= giga_seconds; - secs *= giga_seconds; - secs += seconds; - days += secs / SECS_PER_DAY; - secs %= SECS_PER_DAY; - days++; - - year = 1969; - days_of_this_year = 0; - while (days > days_of_this_year) { - days -= days_of_this_year; - year++; - days_of_this_year = 365 + (IS_LEAP_YEAR(year) ? 1 : 0); - } - - for (month = 1; month <= 12; month++) { - usgnd_int_32 days_of_this_month = days_of_month[month]; - if (month == 2 && IS_LEAP_YEAR(year)) - days_of_this_month++; - if (days <= days_of_this_month) - break; - days -= days_of_this_month; - } - - state->start_time.year = year; - state->start_time.month = month; - state->start_time.day = days; - state->start_time.hour = secs / (60*60); - secs %= 60*60; - state->start_time.minute = secs / 60; - state->start_time.second = secs % 60; - state->start_time.micro_second = micro_seconds; -} - -static int -parse_v1_body(emtp_state *statep, - usgnd_int_8 **tracepp, usgnd_int_8 *trace_endp, - emtp_operation **op_pp, emtp_operation *op_endp, size_t op_size) -{ - /* "cache" some frequently used values */ - register usgnd_int_8 *c_p = *tracepp; - register emtp_operation *op_p = *op_pp; - register usgnd_int_32 current_secs = statep->time.secs; - register usgnd_int_32 current_usecs = statep->time.usecs; - - sgnd_int_32 trace_size = trace_endp - c_p; - usgnd_int_8 *tracep = c_p; - int result = 0; - - usgnd_int_16 max_block_type = statep->max_block_type_ix; - - while (trace_size >= UI16_SZ) { - usgnd_int_16 ehdr, tag; - unsigned time_inc_msb; - - GET_UI16(ehdr, c_p); - tag = ehdr & ERTS_MT_TAG_EHDR_FLD_MSK; - switch (tag) { - case ERTS_MT_V1_ALLOC_TAG: - - op_p->type = EMTP_ALLOC; - - alloc_common: { - usgnd_int_16 block_type; - unsigned block_type_msb, new_ptr_msb, new_size_msb; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - block_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - new_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - new_size_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ - + 4 - + block_type_msb - + new_ptr_msb - + new_size_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UI16(block_type, c_p, block_type_msb); - if (block_type > max_block_type) - ERROR(EMTP_PARSE_ERROR); - op_p->u.block.type = (int) block_type; - - GET_VSZ_UIMAX(op_p->u.block.new_ptr, c_p, new_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.new_size, c_p, new_size_msb); - - op_p->u.block.prev_ptr = 0; - } - - read_time_inc: { - usgnd_int_32 secs, usecs, time_inc; - - GET_VSZ_UI32(time_inc, c_p, time_inc_msb); - - secs = ((time_inc >> ERTS_MT_TIME_INC_SECS_SHIFT) - & ERTS_MT_TIME_INC_SECS_MASK); - usecs = ((time_inc >> ERTS_MT_TIME_INC_USECS_SHIFT) - & ERTS_MT_TIME_INC_USECS_MASK); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - op_p->time.secs = current_secs; - op_p->time.usecs = current_usecs; - -#if PRINT_PARSED_OP - print_op(op_p); -#endif - - op_p = (emtp_operation *) (((char *) op_p) + op_size); - break; - } - - case ERTS_MT_V1_REALLOC_NPB_TAG: - op_p->type = EMTP_REALLOC; - goto alloc_common; - - case ERTS_MT_V1_REALLOC_MV_TAG: { - unsigned new_ptr_msb, prev_ptr_msb, new_size_msb; - - op_p->type = EMTP_REALLOC; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - new_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - prev_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - new_size_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ - + 4 - + new_ptr_msb - + prev_ptr_msb - + new_size_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UIMAX(op_p->u.block.new_ptr, c_p, new_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.prev_ptr, c_p, prev_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.new_size, c_p, new_size_msb); - - op_p->u.block.type = UNKNOWN_BLOCK_TYPE_IX; - goto read_time_inc; - } - - case ERTS_MT_V1_REALLOC_NMV_TAG: { - usgnd_int_max new_ptr; - unsigned new_ptr_msb, new_size_msb; - - op_p->type = EMTP_REALLOC; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - new_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - new_size_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ - + 3 - + new_ptr_msb - + new_size_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UIMAX(new_ptr, c_p, new_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.new_size, c_p, new_size_msb); - - op_p->u.block.new_ptr = new_ptr; - op_p->u.block.prev_ptr = new_ptr; - - op_p->u.block.type = UNKNOWN_BLOCK_TYPE_IX; - goto read_time_inc; - } - - case ERTS_MT_V1_FREE_TAG: { - unsigned prev_ptr_msb; - - op_p->type = EMTP_FREE; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - prev_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ - + 2 - + prev_ptr_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UIMAX(op_p->u.block.prev_ptr, c_p, prev_ptr_msb); - - op_p->u.block.new_ptr = 0; - op_p->u.block.new_size = 0; - - op_p->u.block.type = UNKNOWN_BLOCK_TYPE_IX; - goto read_time_inc; - } - - case ERTS_MT_V1_TIME_INC_TAG: { - unsigned secs_msb, usecs_msb; - usgnd_int_32 secs, usecs; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - - secs_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI32_MSB_EHDR_FLD_SZ; - - usecs_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ + 2 + secs_msb + usecs_msb, trace_size); - - GET_VSZ_UI32(secs, c_p, secs_msb); - GET_VSZ_UI32(usecs, c_p, usecs_msb); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - break; - } - - case ERTS_MT_V1_STOP_TAG: - - op_p->type = EMTP_STOP; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ + 1 + time_inc_msb, trace_size); - - goto read_ending_time_inc; - - case ERTS_MT_V1_EXIT_TAG: { - unsigned exit_status_msb; - - op_p->type = EMTP_EXIT; - - ehdr >>= ERTS_MT_TAG_EHDR_FLD_SZ; - exit_status_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI32_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ + 2 + exit_status_msb + time_inc_msb, - trace_size); - - GET_VSZ_UI32(op_p->u.exit_status, c_p, exit_status_msb); - - read_ending_time_inc: { - usgnd_int_32 secs, usecs, time_inc; - - GET_VSZ_UI32(time_inc, c_p, time_inc_msb); - - secs = ((time_inc >> ERTS_MT_TIME_INC_SECS_SHIFT) - & ERTS_MT_TIME_INC_SECS_MASK); - usecs = ((time_inc >> ERTS_MT_TIME_INC_USECS_SHIFT) - & ERTS_MT_TIME_INC_USECS_MASK); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - op_p->time.secs = current_secs; - op_p->time.usecs = current_usecs; - -#if PRINT_PARSED_OP - print_op(op_p); -#endif - - op_p = (emtp_operation *) (((char *) op_p) + op_size); - statep->force_return = 1; - statep->progress = EMTP_PROGRESS_ENDED; - - tracep = c_p; - trace_size = trace_endp - tracep; - result = (trace_size - ? EMTP_END_OF_TRACE_GARBAGE_FOLLOWS - : EMTP_END_OF_TRACE); - goto restore_return; - } - } - - case ERTS_MT_V1_ALLOCATOR_TAG: - case ERTS_MT_V1_BLOCK_TYPE_TAG: - -#ifdef DEBUG - hexdump(tracep, trace_endp); -#endif - ERROR(EMTP_HEADER_TAG_IN_BODY_ERROR); - - default: - -#ifdef DEBUG - hexdump(tracep, trace_endp); -#endif - ERROR(EMTP_UNKNOWN_TAG_ERROR); - } - - tracep = c_p; - trace_size = trace_endp - tracep; - - if (op_p >= op_endp) { - statep->force_return = 1; - result = EMTP_ALL_OPS_FILLED; - goto restore_return; - } - } - - statep->known_need = 0; - statep->fetch_size = ERTS_MT_MAX_V1_BODY_ENTRY_SIZE; - - result = EMTP_NEED_MORE_TRACE; - - restore_return: - *tracepp = tracep; - *op_pp = op_p; - statep->time.secs = current_secs; - statep->time.usecs = current_usecs; - - return result; -} - -#define GET_ALLOC_MSBS(EHDR, BT, NP, NS, TI) \ -do { \ - (BT) = (EHDR) & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; \ - (EHDR) >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; \ - (NP) = (EHDR) & ERTS_MT_UI_MSB_EHDR_FLD_MSK; \ - (EHDR) >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; \ - (NS) = (EHDR) & ERTS_MT_UI_MSB_EHDR_FLD_MSK; \ - (EHDR) >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; \ - (TI) = (EHDR) & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; \ -} while (0) - - -static EMTP_INLINE int -parse_v2_body(emtp_state *statep, - usgnd_int_8 **tracepp, usgnd_int_8 *trace_endp, - emtp_operation **op_pp, emtp_operation *op_endp, size_t op_size) -{ - /* "cache" some frequently used values */ - register usgnd_int_8 *c_p = *tracepp; - register emtp_operation *op_p = *op_pp; - register usgnd_int_32 current_secs = statep->time.secs; - register usgnd_int_32 current_usecs = statep->time.usecs; - - sgnd_int_32 trace_size = trace_endp - c_p; - usgnd_int_8 *tracep = c_p; - int result = 0; - - while (trace_size >= UI8_SZ + UI16_SZ) { - usgnd_int_8 tag; - usgnd_int_16 ehdr; - unsigned time_inc_msb; - - tag = *(c_p++); - - GET_UI16(ehdr, c_p); - - switch (tag) { - - case ERTS_MT_CRR_ALLOC_BDY_TAG: { - usgnd_int_16 type; - unsigned carrier_bytes, carrier_type_msb, block_type_msb, - new_ptr_msb, new_size_msb; - - op_p->type = EMTP_CARRIER_ALLOC; - - carrier_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - - if (trace_size < ERTS_MT_MAX_CRR_ALLOC_SIZE) - NEED_AT_LEAST(UI8_SZ + UI16_SZ + 1 + carrier_type_msb, - ERTS_MT_MAX_CRR_ALLOC_SIZE, - trace_size); - - GET_VSZ_UI16(type, c_p, carrier_type_msb); - op_p->u.block.carrier_type = (int) type; - - carrier_bytes = carrier_type_msb + 1; - goto alloc_common; - - case ERTS_MT_ALLOC_BDY_TAG: - - op_p->type = EMTP_ALLOC; - carrier_bytes = 0; - - alloc_common: - block_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - new_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - new_size_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - if (trace_size < ERTS_MT_MAX_CRR_ALLOC_SIZE) - NEED(UI8_SZ - + UI16_SZ - + 4 - + carrier_bytes - + block_type_msb - + new_ptr_msb - + new_size_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UI16(type, c_p, block_type_msb); - op_p->u.block.type = (int) type; - - GET_VSZ_UIMAX(op_p->u.block.new_ptr, c_p, new_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.new_size, c_p, new_size_msb); - - op_p->u.block.prev_ptr = 0; - } - - read_time_inc: { - usgnd_int_32 secs, usecs, time_inc; - - GET_VSZ_UI32(time_inc, c_p, time_inc_msb); - - secs = ((time_inc >> ERTS_MT_TIME_INC_SECS_SHIFT) - & ERTS_MT_TIME_INC_SECS_MASK); - usecs = ((time_inc >> ERTS_MT_TIME_INC_USECS_SHIFT) - & ERTS_MT_TIME_INC_USECS_MASK); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - op_p->time.secs = current_secs; - op_p->time.usecs = current_usecs; - -#if PRINT_PARSED_OP - print_op(op_p); -#endif - - op_p = (emtp_operation *) (((char *) op_p) + op_size); - break; - } - - case ERTS_MT_CRR_REALLOC_BDY_TAG: { - usgnd_int_16 type; - unsigned carrier_bytes, carrier_type_msb, block_type_msb, - new_ptr_msb, prev_ptr_msb, new_size_msb; - - op_p->type = EMTP_CARRIER_REALLOC; - - carrier_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - - if (trace_size < ERTS_MT_MAX_CRR_REALLOC_SIZE) - NEED_AT_LEAST(UI8_SZ + UI16_SZ + 1 + carrier_type_msb, - ERTS_MT_MAX_CRR_REALLOC_SIZE, - trace_size); - - GET_VSZ_UI16(type, c_p, carrier_type_msb); - op_p->u.block.carrier_type = (int) type; - - carrier_bytes = carrier_type_msb + 1; - goto realloc_common; - - case ERTS_MT_REALLOC_BDY_TAG: - - op_p->type = EMTP_REALLOC; - carrier_bytes = 0; - - realloc_common: - - block_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - new_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - prev_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - new_size_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - if (trace_size < ERTS_MT_MAX_CRR_REALLOC_SIZE) - NEED(UI8_SZ - + UI16_SZ - + 5 - + carrier_bytes - + block_type_msb - + new_ptr_msb - + prev_ptr_msb - + new_size_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UI16(op_p->u.block.type, c_p, block_type_msb); - GET_VSZ_UIMAX(op_p->u.block.new_ptr, c_p, new_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.prev_ptr, c_p, prev_ptr_msb); - GET_VSZ_UIMAX(op_p->u.block.new_size, c_p, new_size_msb); - - goto read_time_inc; - } - - case ERTS_MT_CRR_FREE_BDY_TAG: { - usgnd_int_16 type; - unsigned carrier_bytes, carrier_type_msb, block_type_msb, - prev_ptr_msb; - - op_p->type = EMTP_CARRIER_FREE; - - carrier_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - - if (trace_size < ERTS_MT_MAX_CRR_FREE_SIZE) - NEED_AT_LEAST(UI8_SZ + UI16_SZ + 1 + carrier_type_msb, - ERTS_MT_MAX_CRR_FREE_SIZE, - trace_size); - - GET_VSZ_UI16(type, c_p, carrier_type_msb); - op_p->u.block.carrier_type = (int) type; - - carrier_bytes = carrier_type_msb + 1; - goto free_common; - - case ERTS_MT_FREE_BDY_TAG: - - op_p->type = EMTP_FREE; - carrier_bytes = 0; - - free_common: - - block_type_msb = ehdr & ERTS_MT_UI16_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI16_MSB_EHDR_FLD_SZ; - prev_ptr_msb = ehdr & ERTS_MT_UI_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - if (trace_size < ERTS_MT_MAX_CRR_FREE_SIZE) - NEED(UI8_SZ - + UI16_SZ - + 3 - + carrier_bytes - + block_type_msb - + prev_ptr_msb - + time_inc_msb, - trace_size); - - GET_VSZ_UI16(op_p->u.block.type, c_p, block_type_msb); - GET_VSZ_UIMAX(op_p->u.block.prev_ptr, c_p, prev_ptr_msb); - - op_p->u.block.new_ptr = 0; - op_p->u.block.new_size = 0; - - goto read_time_inc; - } - - case ERTS_MT_TIME_INC_BDY_TAG: { - unsigned secs_msb, usecs_msb; - usgnd_int_32 secs, usecs; - - secs_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI32_MSB_EHDR_FLD_SZ; - usecs_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI8_SZ + UI16_SZ + 2 + secs_msb + usecs_msb, trace_size); - - GET_VSZ_UI32(secs, c_p, secs_msb); - GET_VSZ_UI32(usecs, c_p, usecs_msb); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - break; - } - - case ERTS_MT_STOP_BDY_TAG: - - op_p->type = EMTP_STOP; - - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ + 1 + time_inc_msb, trace_size); - - goto read_ending_time_inc; - - case ERTS_MT_EXIT_BDY_TAG: { - unsigned exit_status_msb; - - op_p->type = EMTP_EXIT; - - exit_status_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - ehdr >>= ERTS_MT_UI32_MSB_EHDR_FLD_SZ; - time_inc_msb = ehdr & ERTS_MT_UI32_MSB_EHDR_FLD_MSK; - - NEED(UI16_SZ + 2 + exit_status_msb + time_inc_msb, trace_size); - - GET_VSZ_UI32(op_p->u.exit_status, c_p, exit_status_msb); - - read_ending_time_inc: { - usgnd_int_32 secs, usecs, time_inc; - - GET_VSZ_UI32(time_inc, c_p, time_inc_msb); - - secs = ((time_inc >> ERTS_MT_TIME_INC_SECS_SHIFT) - & ERTS_MT_TIME_INC_SECS_MASK); - usecs = ((time_inc >> ERTS_MT_TIME_INC_USECS_SHIFT) - & ERTS_MT_TIME_INC_USECS_MASK); - - INC_TIME(current_secs, current_usecs, secs, usecs); - - op_p->time.secs = current_secs; - op_p->time.usecs = current_usecs; - -#if PRINT_PARSED_OP - print_op(op_p); -#endif - - op_p = (emtp_operation *) (((char *) op_p) + op_size); - statep->force_return = 1; - statep->progress = EMTP_PROGRESS_ENDED; - - tracep = c_p; - trace_size = trace_endp - tracep; - result = (trace_size - ? EMTP_END_OF_TRACE_GARBAGE_FOLLOWS - : EMTP_END_OF_TRACE); - goto restore_return; - } - } - - case ERTS_MT_X_BDY_TAG: { - /* X for extension - * ehdr contains total size of entry - * - * Entry should at least consist of tag (1 byte), - * total size (2 bytes) and subtag (1 byte). - */ - if (ehdr < UI8_SZ + UI16_SZ + UI8_SZ) - ERROR(EMTP_PARSE_ERROR); - NEED(ehdr, trace_size); - c_p = tracep + ehdr; /* No subtags known yet skip entry... */ - break; - } - - default: -#ifdef DEBUG - hexdump(c_p-2, trace_endp); -#endif - ERROR(EMTP_UNKNOWN_TAG_ERROR); - } - - tracep = c_p; - trace_size = trace_endp - tracep; - - if (op_p >= op_endp) { - statep->force_return = 1; - result = EMTP_ALL_OPS_FILLED; - goto restore_return; - } - } - - statep->known_need = 0; - statep->fetch_size = ERTS_MT_MAX_BODY_ENTRY_SIZE; - - result = EMTP_NEED_MORE_TRACE; - - restore_return: - *tracepp = tracep; - *op_pp = op_p; - statep->time.secs = current_secs; - statep->time.usecs = current_usecs; - - return result; -} - -static void -remove_unused_allocators(emtp_state *statep) -{ - emtp_allocator *allctr; - sgnd_int_32 i, j, k; - for (i = -1; i <= statep->max_block_type_ix; i++) { - if (statep->block_type[i]->valid) { - allctr = statep->allocator[statep->block_type[i]->allocator]; - if (allctr->name != unknown_allocator) - allctr->valid = 1; - } - } - for (i = -1; i <= statep->max_allocator_ix; i++) { - allctr = statep->allocator[i]; - if (allctr->valid && allctr->carrier.provider) { - for (j = 0; j < allctr->carrier.no_providers; j++) { - k = allctr->carrier.provider[j]; - if (statep->allocator[k]->name != unknown_allocator) - statep->allocator[k]->valid = 1; - } - } - } - for (i = -1; i <= statep->max_allocator_ix; i++) { - allctr = statep->allocator[i]; - if (!allctr->valid) { - allctr->flags = 0; - if (allctr->name != unknown_allocator) { - (*statep->free)((void *) allctr->name); - allctr->name = unknown_allocator; - } - allctr->carrier.no_providers = 0; - if (allctr->carrier.provider) { - (*statep->free)((void *) allctr->carrier.provider); - } - } - } -} - -static int -parse_header(emtp_state *statep, - usgnd_int_8 **tracepp, usgnd_int_8 *trace_endp) -{ - sgnd_int_32 trace_size; - usgnd_int_8 *tracep; - int i, result; - - tracep = *tracepp; - - switch (statep->progress) { - case EMTP_PROGRESS_PARSE_HDR_VSN: { - usgnd_int_32 start_word; - - trace_size = trace_endp - tracep; - NEED(3*UI32_SZ, trace_size); - - GET_UI32(start_word, tracep); - if (start_word != ERTS_MT_START_WORD) - return EMTP_NOT_AN_ERL_MTRACE_ERROR; - - GET_UI32(statep->version.major, tracep); - GET_UI32(statep->version.minor, tracep); - - statep->progress = EMTP_PROGRESS_PARSE_HDR_PROLOG; - } - case EMTP_PROGRESS_PARSE_HDR_PROLOG: - - trace_size = trace_endp - tracep; - - switch (statep->version.major) { - case 1: { - NEED(2*UI32_SZ + 2*UI16_SZ, trace_size); - - GET_UI32(statep->flags, tracep); - SKIP_UI32(tracep); /* ignore this; may contain garbage! */ - GET_UI16(statep->max_allocator_ix, tracep); - GET_UI16(statep->max_block_type_ix, tracep); - - statep->parse_body_func = parse_v1_body; - - break; - } - case 2: { - usgnd_int_32 giga_seconds; - usgnd_int_32 seconds; - usgnd_int_32 micro_seconds; - usgnd_int_8 len; - usgnd_int_8 *hdr_prolog_start; - usgnd_int_32 hdr_prolog_sz; - NEED(UI32_SZ, trace_size); - hdr_prolog_start = tracep; - GET_UI32(hdr_prolog_sz, tracep); - NEED(hdr_prolog_sz - UI32_SZ, trace_size); - - GET_UI32(statep->flags, tracep); - GET_UI16(statep->segment_ix, tracep); - GET_UI16(statep->max_allocator_ix, tracep); - GET_UI16(statep->max_block_type_ix, tracep); - - GET_UI32(giga_seconds, tracep); - GET_UI32(seconds, tracep); - GET_UI32(micro_seconds, tracep); - - set_start_time(statep, giga_seconds, seconds, micro_seconds); - - GET_UI8(len, tracep); - memcpy((void *) statep->nodename, (void *) tracep, (size_t) len); - statep->nodename[len] = '\0'; - tracep += len; - - GET_UI8(len, tracep); - memcpy((void *) statep->hostname, (void *) tracep, (size_t) len); - statep->hostname[len] = '\0'; - tracep += len; - - GET_UI8(len, tracep); - memcpy((void *) statep->pid, (void *) tracep, (size_t) len); - statep->pid[len] = '\0'; - tracep += len; - - - - /* Skip things in header prolog we dont know about */ - tracep = hdr_prolog_start + hdr_prolog_sz; - -#if EMTP_CAN_INLINE - statep->parse_body_func = NULL; -#else - statep->parse_body_func = parse_v2_body; -#endif - - break; - } - default: - return EMTP_NOT_SUPPORTED_MTRACE_VERSION_ERROR; - } - - statep->progress = EMTP_PROGRESS_ALLOC_HDR_INFO; - - case EMTP_PROGRESS_ALLOC_HDR_INFO: - - /* Allocator info */ - if (!statep->allocator) { - statep->allocator = (emtp_allocator **) - (*statep->alloc)((statep->max_allocator_ix + 2) - * sizeof(emtp_allocator *)); - if (!statep->allocator) - ERROR(EMTP_NO_MEMORY_ERROR); - statep->allocator++; - for (i = -1; i <= statep->max_allocator_ix; i++) - statep->allocator[i] = NULL; - for (i = -1; i <= statep->max_allocator_ix; i++) { - statep->allocator[i] = (emtp_allocator *) - (*statep->alloc)(sizeof(emtp_allocator)); - if (!statep->allocator[i]) - ERROR(EMTP_NO_MEMORY_ERROR); - statep->allocator[i]->valid = 0; - statep->allocator[i]->flags = 0; - statep->allocator[i]->name = unknown_allocator; - statep->allocator[i]->carrier.no_providers = 0; - statep->allocator[i]->carrier.provider = NULL; - } - - } - - /* Block type info */ - if (!statep->block_type) { - statep->block_type = (emtp_block_type **) - (*statep->alloc)((statep->max_block_type_ix + 2) - * sizeof(emtp_block_type *)); - if (!statep->block_type) - ERROR(EMTP_NO_MEMORY_ERROR); - statep->block_type++; - for (i = -1; i <= statep->max_block_type_ix; i++) - statep->block_type[i] = NULL; - for (i = -1; i <= statep->max_block_type_ix; i++) { - statep->block_type[i] = (emtp_block_type *) - (*statep->alloc)(sizeof(emtp_block_type)); - if (!statep->block_type[i]) - ERROR(EMTP_NO_MEMORY_ERROR); - statep->block_type[i]->valid = 0; - statep->block_type[i]->flags = 0; - statep->block_type[i]->name = unknown_block_type; - statep->block_type[i]->allocator = UNKNOWN_ALLOCATOR_IX; - } - - } - - statep->progress = EMTP_PROGRESS_PARSE_TAGGED_HDR; - - case EMTP_PROGRESS_PARSE_TAGGED_HDR: { - usgnd_int_8 *c_p = tracep; - trace_size = trace_endp - tracep; - - switch (statep->version.major) { - case 1: /* Version 1.X ---------------------------------------------- */ - - while (trace_size >= UI16_SZ) { - size_t str_len; - usgnd_int_16 ehdr; - - GET_UI16(ehdr, c_p); - - switch (ehdr & ERTS_MT_TAG_EHDR_FLD_MSK) { - case ERTS_MT_V1_ALLOCATOR_TAG: { - usgnd_int_16 a_ix; - - NEED_AT_LEAST(2*UI16_SZ + UI8_SZ, - ERTS_MT_MAX_HEADER_ENTRY_SIZE, - trace_size); - - GET_UI16(a_ix, c_p); - if (a_ix > statep->max_allocator_ix) - ERROR(EMTP_PARSE_ERROR); - - GET_UI8(str_len, c_p); - - NEED(2*UI16_SZ + UI8_SZ + str_len, trace_size); - - statep->allocator[a_ix]->name - = (char *) (*statep->alloc)(str_len + 1); - if (!statep->allocator[a_ix]->name) - ERROR(EMTP_NO_MEMORY_ERROR); - - memcpy((void *) statep->allocator[a_ix]->name, - (void *) c_p, - str_len); - c_p += str_len; - - statep->allocator[a_ix]->name[str_len] = '\0'; - break; - } - case ERTS_MT_V1_BLOCK_TYPE_TAG: { - usgnd_int_16 bt_ix, a_ix; - - NEED_AT_LEAST(2*UI16_SZ + UI8_SZ, - ERTS_MT_MAX_HEADER_ENTRY_SIZE, - trace_size); - - GET_UI16(bt_ix, c_p); - if (bt_ix > statep->max_block_type_ix) - ERROR(EMTP_PARSE_ERROR); - - GET_UI8(str_len, c_p); - - NEED(2*UI16_SZ + UI8_SZ + str_len + UI16_SZ, trace_size); - - statep->block_type[bt_ix]->name - = (char *) (*statep->alloc)(str_len + 1); - - if (!statep->block_type[bt_ix]->name) - ERROR(EMTP_NO_MEMORY_ERROR); - - memcpy((void *) statep->block_type[bt_ix]->name, - (void *) c_p, - str_len); - c_p += str_len; - - statep->block_type[bt_ix]->name[str_len] = '\0'; - - GET_UI16(a_ix, c_p); - - if (a_ix > statep->max_allocator_ix) - ERROR(EMTP_PARSE_ERROR); - - statep->block_type[bt_ix]->allocator = (sgnd_int_32) a_ix; - statep->block_type[bt_ix]->valid = 1; - break; - } - - case ERTS_MT_V1_ALLOC_TAG: - case ERTS_MT_V1_REALLOC_NPB_TAG: - case ERTS_MT_V1_REALLOC_MV_TAG: - case ERTS_MT_V1_REALLOC_NMV_TAG: - case ERTS_MT_V1_FREE_TAG: - case ERTS_MT_V1_TIME_INC_TAG: - case ERTS_MT_V1_STOP_TAG: - case ERTS_MT_V1_EXIT_TAG: - remove_unused_allocators(statep); - statep->progress = EMTP_PROGRESS_PARSE_BODY; - result = EMTP_HEADER_PARSED; - statep->force_return = 1; - goto restore_return; - default: - ERROR(EMTP_UNKNOWN_TAG_ERROR); - } - - tracep = c_p; - trace_size = trace_endp - tracep; - } - - statep->fetch_size = ERTS_MT_MAX_V1_HEADER_ENTRY_SIZE; - break; - - case 2: /* Version 2.X ---------------------------------------------- */ - - while (trace_size >= UI8_SZ + UI16_SZ) { - usgnd_int_16 entry_sz; - size_t str_len; - usgnd_int_8 tag; - - GET_UI8(tag, c_p); - GET_UI16(entry_sz, c_p); - NEED(entry_sz, trace_size); - - switch (tag) { - case ERTS_MT_ALLOCATOR_HDR_TAG: { - usgnd_int_8 crr_prvds; - usgnd_int_16 a_ix, aflgs; - - if (entry_sz - < UI8_SZ + 3*UI16_SZ + UI8_SZ + 0 + UI8_SZ) - ERROR(EMTP_PARSE_ERROR); - - GET_UI16(aflgs, c_p); - GET_UI16(a_ix, c_p); - if (a_ix > statep->max_allocator_ix) - ERROR(EMTP_PARSE_ERROR); - - if (aflgs & ERTS_MT_ALLCTR_USD_CRR_INFO) - statep->allocator[a_ix]->flags - |= EMTP_ALLOCATOR_FLAG_HAVE_USED_CARRIERS_INFO; - - GET_UI8(str_len, c_p); - - if (entry_sz - < UI8_SZ + 3*UI16_SZ + UI8_SZ + str_len + UI8_SZ) - ERROR(EMTP_PARSE_ERROR); - - statep->allocator[a_ix]->name - = (char *) (*statep->alloc)(str_len + 1); - if (!statep->allocator[a_ix]->name) - ERROR(EMTP_NO_MEMORY_ERROR); - - memcpy((void *) statep->allocator[a_ix]->name, - (void *) c_p, - str_len); - c_p += str_len; - - statep->allocator[a_ix]->name[str_len] = '\0'; - - GET_UI8(crr_prvds, c_p); - if (entry_sz < (UI8_SZ - + 3*UI16_SZ - + UI8_SZ - + str_len - + UI8_SZ - + crr_prvds*UI16_SZ)) - ERROR(EMTP_PARSE_ERROR); - statep->allocator[a_ix]->carrier.no_providers - = (usgnd_int_16) crr_prvds; - statep->allocator[a_ix]->carrier.provider = (usgnd_int_16 *) - (*statep->alloc)(crr_prvds*sizeof(usgnd_int_16)); - if (!statep->allocator[a_ix]->carrier.provider) - ERROR(EMTP_NO_MEMORY_ERROR); - for (i = 0; i < crr_prvds; i++) { - usgnd_int_16 cp_ix; - GET_UI16(cp_ix, c_p); - if (cp_ix > statep->max_allocator_ix) - ERROR(EMTP_PARSE_ERROR); - statep->allocator[a_ix]->carrier.provider[i] = cp_ix; - } - - break; - } - - case ERTS_MT_BLOCK_TYPE_HDR_TAG: { - usgnd_int_16 bt_ix, a_ix; - - if (entry_sz - < UI8_SZ + 3*UI16_SZ + UI8_SZ + 0 + UI16_SZ) - ERROR(EMTP_PARSE_ERROR); - - SKIP_UI16(c_p); /* bitflags */ - GET_UI16(bt_ix, c_p); - if (bt_ix > statep->max_block_type_ix) - ERROR(EMTP_PARSE_ERROR); - - GET_UI8(str_len, c_p); - - if (entry_sz - < UI8_SZ + 3*UI16_SZ + UI8_SZ + str_len + UI16_SZ) - ERROR(EMTP_PARSE_ERROR); - - statep->block_type[bt_ix]->name - = (char *) (*statep->alloc)(str_len + 1); - - if (!statep->block_type[bt_ix]->name) - ERROR(EMTP_NO_MEMORY_ERROR); - - memcpy((void *) statep->block_type[bt_ix]->name, - (void *) c_p, - str_len); - c_p += str_len; - - statep->block_type[bt_ix]->name[str_len] = '\0'; - - GET_UI16(a_ix, c_p); - - if (a_ix > statep->max_allocator_ix) - ERROR(EMTP_PARSE_ERROR); - - statep->block_type[bt_ix]->allocator = (sgnd_int_32) a_ix; - statep->block_type[bt_ix]->valid = 1; - break; - } - - case ERTS_MT_END_OF_HDR_TAG: - tracep = tracep + ((size_t) entry_sz); - remove_unused_allocators(statep); - statep->progress = EMTP_PROGRESS_PARSE_BODY; - result = EMTP_HEADER_PARSED; - statep->force_return = 1; - goto restore_return; - - default: - /* Skip tags that we do not understand. */ - break; - } - - tracep = tracep + ((size_t) entry_sz); - ASSERT(c_p <= tracep); - c_p = tracep; - trace_size = trace_endp - tracep; - } - - statep->fetch_size = UI8_SZ + UI16_SZ; - break; - default: /* Not supported version --------------------------------- */ - ASSERT(0); - } - - break; - } - default: - ASSERT(0); - } - - statep->known_need = 0; - result = EMTP_NEED_MORE_TRACE; - - restore_return: - - *tracepp = tracep; - - return result; - -} - - -int -emtp_parse(emtp_state *statep, - usgnd_int_8 **tracepp, size_t *trace_lenp, - emtp_operation *op_start, size_t op_size, size_t *op_lenp) -{ - int result, have_all_in_overflow; - usgnd_int_8 *tracep, *trace_endp; - emtp_operation *op_p, *op_endp; - - - have_all_in_overflow = 0; - - op_p = op_start; - - if (!statep) - return EMTP_NO_MEMORY_ERROR; - - if (!tracepp || !trace_lenp) - return EMTP_NO_TRACE_ERROR; - - if (*trace_lenp <= 0) { - if (op_lenp) - *op_lenp = 0; - return EMTP_NEED_MORE_TRACE; - } - - statep->force_return = 0; - - if (statep->overflow_size) { /* Overflow from prevoius parse */ - sgnd_int_32 tsz; - sgnd_int_32 sz; - - fetch_for_overflow: - sz = statep->fetch_size - statep->overflow_size; - ASSERT(sz > 0); - - if (*trace_lenp <= sz) { - have_all_in_overflow = 1; - sz = *trace_lenp; - } - - if (sz > statep->overflow_buf_size) { - size_t buf_sz = statep->overflow_size + sz; - void *buf = (*statep->realloc)((void *) statep->overflow, buf_sz); - if (!buf) - return EMTP_NO_MEMORY_ERROR; - statep->overflow_buf_size = buf_sz; - statep->overflow = (usgnd_int_8 *) buf; - } - - memcpy((void *) (statep->overflow + statep->overflow_size), - (void *) *tracepp, - sz); - - tsz = statep->overflow_size + sz; - - tracep = statep->overflow; - trace_endp = statep->overflow + tsz; - - if (tsz < statep->fetch_size && statep->known_need) { - ASSERT(have_all_in_overflow); - statep->overflow_size = tsz; - op_endp = NULL; - result = EMTP_NEED_MORE_TRACE; - goto restore_return; - } - } - else { - tracep = *tracepp; - trace_endp = tracep + *trace_lenp; - } - - if (statep->progress == EMTP_PROGRESS_PARSE_BODY) { - -#if !HAVE_INT_64 - if (statep->flags & ERTS_MT_64_BIT_FLAG) - return EMTP_NOT_SUPPORTED_64_BITS_TRACE_ERROR; -#endif - - if (op_size < sizeof(emtp_operation)) - return EMTP_BAD_OP_SIZE_ERROR; - if (!op_start || !op_lenp || *op_lenp < 1) - return EMTP_NO_OPERATIONS_ERROR; - op_endp = (emtp_operation *) (((char *) op_start) + (*op_lenp)*op_size); - - restart_parse_body: -#if EMTP_CAN_INLINE - if (statep->parse_body_func) -#endif - result = (*statep->parse_body_func)(statep, - &tracep, trace_endp, - &op_p, op_endp, op_size); -#if EMTP_CAN_INLINE - else - result = parse_v2_body(statep, - &tracep, trace_endp, - &op_p, op_endp, op_size); -#endif - } - else { - restart_parse_header: - op_endp = NULL; - if (statep->progress == EMTP_PROGRESS_ENDED) { - result = EMTP_END_OF_TRACE; - goto restore_return; - } - result = parse_header(statep, &tracep, trace_endp); - } - - /* Check overflow */ - if (statep->overflow_size) { - if (tracep == statep->overflow) { - /* Nothing parsed, i.e. less new input than 1 entry :( */ - if (!have_all_in_overflow) - goto fetch_for_overflow; - statep->overflow_size = trace_endp - tracep; - trace_endp = tracep = *tracepp + *trace_lenp; - } - else { - size_t sz = tracep - (statep->overflow + statep->overflow_size); - - ASSERT(sz > 0); - - statep->overflow_size = 0; - - tracep = *tracepp + sz; - trace_endp = *tracepp + *trace_lenp; - ASSERT(trace_endp >= tracep); - if (!statep->force_return && (trace_endp - tracep)) { - if (statep->progress == EMTP_PROGRESS_PARSE_BODY) - goto restart_parse_body; - else - goto restart_parse_header; - } - /* else: got it all in the overflow buffer */ - } - } - else { - size_t sz = trace_endp - tracep; - if (!statep->force_return && sz) { - if (sz >= statep->fetch_size) { - ASSERT(0); - ERROR(EMTP_PARSE_ERROR); - } - if (sz > statep->overflow_buf_size) { - (*statep->free)((void *) statep->overflow); - statep->overflow = (usgnd_int_8 *) (*statep->alloc)(sz); - if (!statep->overflow) { - statep->overflow_buf_size = 0; - return EMTP_NO_MEMORY_ERROR; - } - statep->overflow_buf_size = sz; - } - memcpy((void *) statep->overflow, tracep, sz); - statep->overflow_size = sz; - ASSERT(tracep + sz == trace_endp); - tracep = trace_endp; - } - } - - restore_return: - ASSERT(trace_endp >= tracep); - - *tracepp = tracep; - *trace_lenp = trace_endp - tracep; - - if (op_lenp && op_size > 0) - *op_lenp = (int) (((char *) op_p) - ((char *) op_start))/op_size; - - return result; -} - -#ifdef DEBUG -static void -hexdump(void *start, void *end) -{ - unsigned char *p = (unsigned char *) start; - - fprintf(stderr, "hexdump: "); - while ((void *) p < end) { - fprintf(stderr, "%x", (unsigned) *p); - p++; - } - fprintf(stderr, "\n"); -} - -#if PRINT_PARSED_OP -static void -print_op(emtp_operation *op_p) -{ - switch (op_p->type) { - case EMTP_ALLOC: - fprintf(stderr, - "alloc: " - "type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "sz=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.new_ptr, - op_p->u.block.new_size, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_REALLOC: - fprintf(stderr, - "realloc: " - "type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "prev_ptr=%" USGND_INT_MAX_FSTR ", " - "sz=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.new_ptr, - op_p->u.block.prev_ptr, - op_p->u.block.new_size, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_FREE: - fprintf(stderr, - "free: " - "type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.prev_ptr, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_CARRIER_ALLOC: - fprintf(stderr, - "carrier_alloc: " - "type=%" USGND_INT_16_FSTR ", " - "carrier_type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "sz=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.carrier_type, - op_p->u.block.new_ptr, - op_p->u.block.new_size, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_CARRIER_REALLOC: - fprintf(stderr, - "carrier_realloc: " - "type=%" USGND_INT_16_FSTR ", " - "carrier_type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "prev_ptr=%" USGND_INT_MAX_FSTR ", " - "sz=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.carrier_type, - op_p->u.block.new_ptr, - op_p->u.block.prev_ptr, - op_p->u.block.new_size, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_CARRIER_FREE: - fprintf(stderr, - "carrier_free: " - "type=%" USGND_INT_16_FSTR ", " - "carrier_type=%" USGND_INT_16_FSTR ", " - "ptr=%" USGND_INT_MAX_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.block.type, - op_p->u.block.carrier_type, - op_p->u.block.prev_ptr, - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_STOP: - fprintf(stderr, - "stop: " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->time.secs, - op_p->time.usecs); - break; - case EMTP_EXIT: - fprintf(stderr, - "exit: " - "status=%" USGND_INT_32_FSTR ", " - "(secs=%" USGND_INT_32_FSTR ", usecs=%" USGND_INT_32_FSTR ")" - "\n", - op_p->u.exit_status, - op_p->time.secs, - op_p->time.usecs); - break; - default: - fprintf(stderr, "Unknown op type: %d\n", op_p->type); - break; - } -} - -#endif -#endif diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index b35d53be7db2..5f011b8b2e53 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2020. All Rights Reserved. + * Copyright Ericsson AB 2006-2023. 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. @@ -41,15 +41,9 @@ # ifdef SYS_SELECT_H # include # endif -# if TIME_WITH_SYS_TIME -# include -# include -# else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif +# include +# if HAVE_SYS_TIME_H +# include # endif # include # include @@ -240,7 +234,7 @@ erts_cpu_info_create(void) cpuinfo->online = -1; cpuinfo->available = -1; cpuinfo->quota = -1; - erts_cpu_info_update(cpuinfo); + erts_cpu_info_update(cpuinfo, 1); return cpuinfo; } @@ -265,7 +259,8 @@ erts_cpu_info_destroy(erts_cpu_info_t *cpuinfo) } int -erts_cpu_info_update(erts_cpu_info_t *cpuinfo) +erts_cpu_info_update(erts_cpu_info_t *cpuinfo, + int skip_read_topology) { int changed = 0; int configured = 0; @@ -430,7 +425,9 @@ erts_cpu_info_update(erts_cpu_info_t *cpuinfo) old_topology_size = cpuinfo->topology_size; cpuinfo->topology = NULL; - read_topology(cpuinfo); + if (!skip_read_topology) { + read_topology(cpuinfo); + } if (cpuinfo->topology_size != old_topology_size || (old_topology_size != 0 @@ -1129,7 +1126,7 @@ get_cgroup_path(const char *controller, const char **path) { * This fails if any of the fs options contain a hyphen, but this is * not likely to happen on a cgroup, so we just skip such lines. */ if (sscanf(line_buf, - "%*d %*d %*d:%*d %4095s %4095s %*s %*[^-]- " + "%*d %*d %*d:%*d %4095s %4095s %*s%*[^-]- " "%63s %*s %511[^\n]\n", root_path, mount_path, fs_type, fs_flags) != 4) { diff --git a/erts/lib_src/common/ethr_atomics.c b/erts/lib_src/common/ethr_atomics.c index 1594d78f5e84..ead086e86614 100644 --- a/erts/lib_src/common/ethr_atomics.c +++ b/erts/lib_src/common/ethr_atomics.c @@ -10,7 +10,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2016. All Rights Reserved. + * Copyright Ericsson AB 2011-2021. 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. @@ -62,7 +62,7 @@ * - read * - init * - * Appart from a function implementing the atomic operation + * Apart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following * implied memory barrier semantics: diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c index d51cb5a9fb70..937401cff521 100644 --- a/erts/lib_src/common/ethr_aux.c +++ b/erts/lib_src/common/ethr_aux.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2021. All Rights Reserved. + * Copyright Ericsson AB 2010-2023. 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. @@ -107,6 +107,8 @@ x86_init(void) ethr_x86_cpuid__(&eax, &ebx, &ecx, &edx); + ethr_runtime__.conf.have_cpuid = (eax > 0); + if (eax > 0 && (ETHR_IS_X86_VENDOR("GenuineIntel", ebx, ecx, edx) || ETHR_IS_X86_VENDOR("AuthenticAMD", ebx, ecx, edx) @@ -752,7 +754,7 @@ ETHR_IMPL_NORETURN__ ethr_fatal_error__(const char *file, } ETHR_IMPL_NORETURN__ -ethr_assert_failed(const char *file, int line, const char *func, char *a) +ethr_assert_failed(const char *file, int line, const char *func, const char *a) { fprintf(stderr, "%s:%d: %s(): Assertion failed: %s\n", file, line, func, a); ethr_abort__(); diff --git a/erts/lib_src/common/ethr_cbf.c b/erts/lib_src/common/ethr_cbf.c index 037559be2261..87278ef60437 100644 --- a/erts/lib_src/common/ethr_cbf.c +++ b/erts/lib_src/common/ethr_cbf.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2016. All Rights Reserved. + * Copyright Ericsson AB 2010-2021. 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. @@ -21,7 +21,7 @@ /* * We keep this function alone in a separate file so the - * compiler wont optimize it away. + * compiler won't optimize it away. */ #ifdef HAVE_CONFIG_H diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c index dc25c7a759ad..636adfe397ca 100644 --- a/erts/lib_src/common/ethr_mutex.c +++ b/erts/lib_src/common/ethr_mutex.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2021. All Rights Reserved. + * Copyright Ericsson AB 2010-2022. 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. @@ -884,7 +884,7 @@ enqueue_mtx(ethr_mutex *mtx, ethr_ts_event *tse_start, ethr_ts_event *tse_end) * is not currently locked by current thread, we almost certainly have a * hard to debug race condition. There might however be some (strange) * use for it. POSIX also allow a call to `pthread_cond_signal' or - * `pthread_cond_broadcast' even though the the associated mutex isn't + * `pthread_cond_broadcast' even though the associated mutex isn't * locked by the caller. Therefore, we also allow this kind of strange * usage, but optimize for the case where the mutex is locked by the * calling thread. @@ -1905,7 +1905,7 @@ rwmutex_freqread_rdrs_dec_chk_wakeup(ethr_rwmutex *rwmtx, * A writer that just enqueued (not seen by us * in flag field) may depend on someone else * completing the runlock. We just took over - * that responsibilty since we modified reader + * that responsibility since we modified reader * groups. */ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0); @@ -2720,6 +2720,28 @@ ethr_rwmutex_init(ethr_rwmutex *rwmtx) return ethr_rwmutex_init_opt(rwmtx, NULL); } +size_t +ethr_rwmutex_size(ethr_rwmutex *rwmtx) { +#if ETHR_XCHK + if (ethr_not_inited__) { + ETHR_ASSERT(0); + return EACCES; + } + if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) { + ETHR_ASSERT(0); + return EINVAL; + } +#endif + switch (rwmtx->type) { + case ETHR_RWMUTEX_TYPE_FREQUENT_READ: + return sizeof(ethr_rwmtx_readers_array__) * (reader_groups_array_size + 1); + case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: + return sizeof(ethr_rwmtx_readers_array__) * (main_threads_array_size + 1); + default: + return 0; + } +} + int ethr_rwmutex_destroy(ethr_rwmutex *rwmtx) { @@ -3098,6 +3120,11 @@ ethr_rwmutex_init_opt(ethr_rwmutex *rwmtx, ethr_rwmutex_opt *opt) return ethr_rwmutex_init(rwmtx); } +size_t +ethr_rwmutex_size(ethr_rwmutex *rwmtx) { + return 0; +} + int ethr_rwmutex_destroy(ethr_rwmutex *rwmtx) { diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index f7262c02b15f..da4f1af11d12 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2020. All Rights Reserved. + * Copyright Ericsson AB 2010-2023. 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. @@ -30,15 +30,9 @@ #define ETHR_CHILD_WAIT_SPIN_COUNT 4000 #include -#ifdef ETHR_TIME_WITH_SYS_TIME -# include +#include +#ifdef ETHR_HAVE_SYS_TIME_H # include -#else -# ifdef ETHR_HAVE_SYS_TIME_H -# include -# else -# include -# endif #endif #include #include @@ -87,7 +81,7 @@ typedef struct { void *prep_func_res; size_t stacksize; char *name; - char name_buff[32]; + char name_buff[ETHR_THR_NAME_MAX + 1]; } ethr_thr_wrap_data__; static void *thr_wrapper(void *vtwd) @@ -152,7 +146,7 @@ ppc_init__(void) { int pid; - /* If anything what so ever failes we assume no lwsync for safety */ + /* If anything what so ever fails we assume no lwsync for safety */ ethr_runtime__.conf.have_lwsync = 0; /* @@ -225,7 +219,7 @@ ethr_x86_cpuid__(int *eax, int *ebx, int *ecx, int *edx) #endif #if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ /* - * When position independet code is used in 32-bit mode, the B register + * When position independent code is used in 32-bit mode, the B register * is used for storage of global offset table address, and we may not * use it as input or output in an asm. We need to save and restore the * B register explicitly (for some reason gcc doesn't provide this @@ -340,21 +334,9 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, twd.stacksize = 0; if (opts && opts->name) { - size_t nlen = sizeof(twd.name_buff); -#ifdef __HAIKU__ - if (nlen > B_OS_NAME_LENGTH) - nlen = B_OS_NAME_LENGTH; -#else - /* - * Length of 16 is known to work. At least pthread_setname_np() - * is documented to fail on too long name string, but documentation - * does not say what the limit is. Do not have the time to dig - * further into that now... - */ - if (nlen > 16) - nlen = 16; -#endif - snprintf(twd.name_buff, nlen, "%s", opts->name); + if (strlen(opts->name) >= sizeof(twd.name_buff)) + return EINVAL; + strcpy(twd.name_buff, opts->name); twd.name = twd.name_buff; } else twd.name = NULL; @@ -512,6 +494,8 @@ ethr_getname(ethr_tid tid, char *buf, size_t len) void ethr_setname(char *name) { + if (strlen(name) > ETHR_THR_NAME_MAX) + return; #if defined(ETHR_HAVE_PTHREAD_SETNAME_NP_2) pthread_setname_np(ethr_self(), name); #elif defined(ETHR_HAVE_PTHREAD_SET_NAME_NP_2) diff --git a/erts/lib_src/utils/make_atomics_api b/erts/lib_src/utils/make_atomics_api index f960b97c875a..48b36025bf14 100755 --- a/erts/lib_src/utils/make_atomics_api +++ b/erts/lib_src/utils/make_atomics_api @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2021. 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. @@ -1463,7 +1463,7 @@ comments() -> end, ?DW_ATOMIC_OPS), " * - * Appart from a function implementing the atomic operation + * Apart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following * implied memory barrier semantics:", diff --git a/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/README.md b/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/README.md index ab89576f085c..a6a6d3a1e59f 100644 --- a/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/README.md +++ b/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/README.md @@ -10,7 +10,7 @@ Supports a subset of the syntax and semantics of the Python standard library imp ### Current status All supported regex-operators seem to work properly according to the test-set, with the following exception: -There is a problem with ranges (e.g. `[0-9]` for a digit 0-9) combined with inverted character-cases, e.g. `[^ab]` for anything but 'a' or 'b' - like `[^-0-9]` for anything not '-' or a digit 0-9. I think the code mathces too broadly in that case. +There is a problem with ranges (e.g. `[0-9]` for a digit 0-9) combined with inverted character-cases, e.g. `[^ab]` for anything but 'a' or 'b' - like `[^-0-9]` for anything not '-' or a digit 0-9. I think the code matches too broadly in that case. I think you should test the patterns you are going to use. You can easily modify the test-harness to generate tests for your intended patterns to check for compliance. diff --git a/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/UPGRADE_NOTE b/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/UPGRADE_NOTE new file mode 100644 index 000000000000..b895003a6989 --- /dev/null +++ b/erts/lib_src/yielding_c_fun/lib/tiny_regex_c/UPGRADE_NOTE @@ -0,0 +1,10 @@ +The scripts folder (contained test python scripts) that existed in the +original repository has been removed as it was not used and contained a +license text that was incompatible with Erlang/OTP's license. + +The tests folder that exited in the original repository has also been +removed because it was not used. + +The file GIT_VERSION contains information of which repository URL and +GIT version the code in this folder was fetched from. The GIT_VERSION +file should be updated if the code in this folder is upgraded. \ No newline at end of file diff --git a/erts/lib_src/yielding_c_fun/main_target.mk b/erts/lib_src/yielding_c_fun/main_target.mk index 4c97d4d9cf90..0b06ce860cf1 100644 --- a/erts/lib_src/yielding_c_fun/main_target.mk +++ b/erts/lib_src/yielding_c_fun/main_target.mk @@ -26,16 +26,18 @@ YCF_SOURCES = $(sort $(wildcard $(YCF_SOURCE_DIR)/*.c) $(YCF_EXTRA_SOURCES)) YCF_OBJECTS = $(addprefix $(YCF_OBJ_DIR)/,$(notdir $(YCF_SOURCES:.c=.o))) -YCF_CFLAGS = $(filter-out -Wstrict-prototypes -Wdeclaration-after-statement -Wmissing-prototypes,$(CFLAGS)) +# YCF is a short lived tool leaking memory deliberately. Disable all sanitizers. +YCF_CFLAGS = $(filter-out -Wstrict-prototypes -Wdeclaration-after-statement -Wmissing-prototypes -fsanitize%,$(CFLAGS)) +YCF_LDFLAGS = $(filter-out -fsanitize%,$(LDFLAGS)) $(YCF_EXECUTABLE): $(YCF_OBJECTS) - $(V_LD) $(YCF_CFLAGS) $(LDFLAGS) $(YCF_OBJECTS) -o $@ + $(V_LD) $(YCF_CFLAGS) $(YCF_LDFLAGS) $(YCF_OBJECTS) -o $@ $(YCF_OBJ_DIR)/%.o: $(YCF_SOURCE_DIR)/lib/tiny_regex_c/%.c $(YCF_HEADERS) - $(V_CC) $(YCF_CFLAGS) $(LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ + $(V_CC) $(YCF_CFLAGS) $(YCF_LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ $(YCF_OBJ_DIR)/%.o: $(YCF_SOURCE_DIR)/lib/simple_c_gc/%.c $(YCF_HEADERS) - $(V_CC) $(YCF_CFLAGS) $(LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ + $(V_CC) $(YCF_CFLAGS) $(YCF_LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ $(YCF_OBJ_DIR)/%.o: $(YCF_SOURCE_DIR)/%.c $(YCF_HEADERS) - $(V_CC) $(YCF_CFLAGS) $(LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ + $(V_CC) $(YCF_CFLAGS) $(YCF_LDFLAGS) $(YCF_INCLUDE_DIRS) -c $< -o $@ diff --git a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/README.md b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/README.md index 167a69d08c5c..f3d2e8e49a6a 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/README.md +++ b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/README.md @@ -13,7 +13,7 @@ At the moment, only SHA-256 is implemented. - ANSI C with as little specific C99 as possible (e.g. extended integer types are used, but not bool). -- Portable. Makes no assumptions on the target system's endianess or +- Portable. Makes no assumptions on the target system's endianness or word size. - The SHA-256 implementation is a straightforward implementation of diff --git a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256.c b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256.c index 4338531d7e47..c485596e1b7c 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256.c +++ b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256.c @@ -93,7 +93,7 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) * Now: * - either there is enough space left for the total length, and we can conclude, * - or there is too little space left, and we have to pad the rest of this chunk with zeroes. - * In the latter case, we will conclude at the next invokation of this function. + * In the latter case, we will conclude at the next invocation of this function. */ if (space_in_chunk >= TOTAL_LEN_LEN) { const size_t left = space_in_chunk - TOTAL_LEN_LEN; diff --git a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256_orginal.c b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256_orginal.c index 53d6ff2e2a16..f706429fc65d 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256_orginal.c +++ b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha-2/sha-256_orginal.c @@ -89,7 +89,7 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) * Now: * - either there is enough space left for the total length, and we can conclude, * - or there is too little space left, and we have to pad the rest of this chunk with zeroes. - * In the latter case, we will conclude at the next invokation of this function. + * In the latter case, we will conclude at the next invocation of this function. */ if (space_in_chunk >= TOTAL_LEN_LEN) { const size_t left = space_in_chunk - TOTAL_LEN_LEN; diff --git a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha256_nif.c b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha256_nif.c index 6ad22c1dcd78..a7c6746806b1 100644 --- a/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha256_nif.c +++ b/erts/lib_src/yielding_c_fun/test/examples/sha256_erlang_nif/c_src/sha256_nif.c @@ -105,7 +105,7 @@ sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return enif_make_badarg(env); } - /* Copy the input binary to the work environemnt so it will be kept when we are yielding */ + /* Copy the input binary to the work environment so it will be kept when we are yielding */ ERL_NIF_TERM input_bin_term = enif_make_copy(work_env, argv[0]); ErlNifBinary input_bin; enif_inspect_binary(work_env, input_bin_term, &input_bin); diff --git a/erts/lib_src/yielding_c_fun/ycf_lexer.c b/erts/lib_src/yielding_c_fun/ycf_lexer.c index 91426b88c287..781a5db1661f 100644 --- a/erts/lib_src/yielding_c_fun/ycf_lexer.c +++ b/erts/lib_src/yielding_c_fun/ycf_lexer.c @@ -127,7 +127,7 @@ int string_litteral_finder(symbol_finder* f, char* text){ if(starts_with(&(text[pos]), "\"")){ return pos + 1; }else { - printf("Broken string litteral\n"); + printf("Broken string literal\n"); exit(1); } } diff --git a/erts/lib_src/yielding_c_fun/ycf_node.c b/erts/lib_src/yielding_c_fun/ycf_node.c index 82f4b9f6b522..6afc23db83d9 100644 --- a/erts/lib_src/yielding_c_fun/ycf_node.c +++ b/erts/lib_src/yielding_c_fun/ycf_node.c @@ -897,7 +897,7 @@ void ycf_node_normalize_function(ycf_node* fun){ ycf_node_insert_scopes_in_complex_statements(&fun->u.function.body); /* Move out declarations from for loops */ ycf_node_normalize_for_var_declarations(&fun->u.function.body); - /* Move in code declations to top of scope */ + /* Move in code declarations to top of scope */ ycf_node_move_in_code_var_declarations_to_top(&fun->u.function.body); /* Normalize declarations */ ycf_node_normalize_init_definitions_in_scope(&fun->u.function.body); diff --git a/erts/lib_src/yielding_c_fun/ycf_printers.c b/erts/lib_src/yielding_c_fun/ycf_printers.c index 23c10d5fa50c..1326243dc37e 100644 --- a/erts/lib_src/yielding_c_fun/ycf_printers.c +++ b/erts/lib_src/yielding_c_fun/ycf_printers.c @@ -348,7 +348,7 @@ void print_definition(ycf_node_definition d){ void print_scope(ycf_node_code_scope node){ printf("NODE: scope\n"); printf(">>>>>>>>>>>>>>>>>>>>>>>\n"); - printf("Defenition Nodes:\n"); + printf("Definition Nodes:\n"); struct ycf_node* n = node.definition_nodes.head; while(n != NULL){ print_abstract_syntax_tree(n); diff --git a/erts/lib_src/yielding_c_fun/ycf_yield_fun.c b/erts/lib_src/yielding_c_fun/ycf_yield_fun.c index c03cbc19efc8..90d372df1ec0 100644 --- a/erts/lib_src/yielding_c_fun/ycf_yield_fun.c +++ b/erts/lib_src/yielding_c_fun/ycf_yield_fun.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB and Kjell Winblad 2019-2021. All Rights Reserved. + * Copyright Ericsson AB and Kjell Winblad 2019-2023. 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. @@ -140,7 +140,7 @@ ycf_node* mk_print_offsets_for_struct_fields(char* ycf_trap_state_name, } char* ret = ycf_string_new(("static void %s_print_offsets_for_struct_fields(void);\n" - "static void %s_print_offsets_for_struct_fields() {\n" + "static void %s_print_offsets_for_struct_fields(void) {\n" "fprintf(stderr, \"Field offsets for struct %s:\\n\");\n" "%s\n" "}\n"), @@ -906,13 +906,13 @@ void ast_add_yield_code_generated_define(ycf_node* source_out_tree/*Will be chan "#include \n" "static void* ycf_find_stack_bottom_conservative_helper(void);\n" "static void* ycf_find_stack_bottom_conservative(void);\n" - "static void* ycf_find_stack_bottom_conservative_helper() {\n" + "static void* ycf_find_stack_bottom_conservative_helper(void) {\n" " void* p = NULL;\n" " volatile intptr_t tmp = (intptr_t)&p;\n" " /* codechecker_intentional [StackAddrEscapeBase] */\n" " return (void*)tmp;\n" "}\n" - "static void* ycf_find_stack_bottom_conservative() {\n" + "static void* ycf_find_stack_bottom_conservative(void) {\n" " jmp_buf env;\n" " setjmp(env);\n" "\n" @@ -994,7 +994,7 @@ void ast_add_yield_code_generated_define(ycf_node* source_out_tree/*Will be chan " * static int test(){ return 0;}\n" " * YCF_GCC_DIAG_ON(unused-function)\n" " *\n" - " * These macros were orginally authored by Jonathan Wakely and has\n" + " * These macros were originally authored by Jonathan Wakely and has\n" " * been modified by Patrick Horgan.\n" " *\n" " * Source: http://dbp-consulting.com/tutorials/SuppressingGCCWarnings.html\n" @@ -1653,7 +1653,7 @@ ycf_node* ast_get_ast_with_yieldified_function(ycf_node* source_tree, ycf_node_rename_function(&fun_change->u.function, ycf_string_new("%s_ycf_gen_yielding", yielding_function_name)); - /* Remove unecessary scopes */ + /* Remove unnecessary scopes */ ycf_node_remove_unecessary_scopes(&fun_change->u.function.body); /* Exit with error message if a function call to a yielding function is not transformed */ diff --git a/erts/prebuild.keep b/erts/prebuild.keep index a2e6bd485b80..8e695ec83aa8 100644 --- a/erts/prebuild.keep +++ b/erts/prebuild.keep @@ -1 +1 @@ -doc/ +doc diff --git a/erts/preloaded/ebin/atomics.beam b/erts/preloaded/ebin/atomics.beam index 7fdd2502a40a..46816a472d28 100644 Binary files a/erts/preloaded/ebin/atomics.beam and b/erts/preloaded/ebin/atomics.beam differ diff --git a/erts/preloaded/ebin/counters.beam b/erts/preloaded/ebin/counters.beam index 0eb323940e0e..d693a3bb8ba9 100644 Binary files a/erts/preloaded/ebin/counters.beam and b/erts/preloaded/ebin/counters.beam differ diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam index 4bcd62ed4330..cb7e6e25856b 100644 Binary files a/erts/preloaded/ebin/erl_init.beam and b/erts/preloaded/ebin/erl_init.beam differ diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index 1ec35ba8fd4a..a46d58d7a521 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam index a82a17a2f572..f7a53f657945 100644 Binary files a/erts/preloaded/ebin/erl_tracer.beam and b/erts/preloaded/ebin/erl_tracer.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 0ee7f50d6c57..00ea9e5775fb 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index f2b141f2b3b4..04fc2208bac2 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam index 948fef678511..24bcc53c3ecf 100644 Binary files a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam and b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 5f2c0418ab92..21b4f05210bd 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam index b6a13f403471..54c0f4c819a0 100644 Binary files a/erts/preloaded/ebin/erts_literal_area_collector.beam and b/erts/preloaded/ebin/erts_literal_area_collector.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index fe06d5c1f4fd..01f650f771d8 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam index d11de4ef6d90..461882747936 100644 Binary files a/erts/preloaded/ebin/persistent_term.beam and b/erts/preloaded/ebin/persistent_term.beam differ diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam index af58495025db..fa74efcfeb58 100644 Binary files a/erts/preloaded/ebin/prim_buffer.beam and b/erts/preloaded/ebin/prim_buffer.beam differ diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam index 7c85e0e41bd3..8a5c4ee49d3f 100644 Binary files a/erts/preloaded/ebin/prim_eval.beam and b/erts/preloaded/ebin/prim_eval.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index d5d2d3ab8d5c..3b4d892eed1f 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index ad098eeb68b5..883010b373ef 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_net.beam b/erts/preloaded/ebin/prim_net.beam index 0f52635d3b1b..0495ec0d779b 100644 Binary files a/erts/preloaded/ebin/prim_net.beam and b/erts/preloaded/ebin/prim_net.beam differ diff --git a/erts/preloaded/ebin/prim_socket.beam b/erts/preloaded/ebin/prim_socket.beam index 1fb181caabaa..26c2cacb48d9 100644 Binary files a/erts/preloaded/ebin/prim_socket.beam and b/erts/preloaded/ebin/prim_socket.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index fd6c4730235c..a5d1a6553b4d 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/socket_registry.beam b/erts/preloaded/ebin/socket_registry.beam index 41036b0355c1..55b4305b1c25 100644 Binary files a/erts/preloaded/ebin/socket_registry.beam and b/erts/preloaded/ebin/socket_registry.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index a73471d301aa..fc1d029f27bd 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 521e5b6f6758..1994aa1302b3 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -33,14 +33,10 @@ STATIC_EBIN=../ebin include $(ERL_TOP)/erts/vsn.mk include $(ERL_TOP)/lib/kernel/vsn.mk -ifeq ($(USE_ESOCK), yes) PRE_LOADED_ERL_ESOCK_MODULES = \ socket_registry \ prim_socket \ prim_net -else -PRE_LOADED_ERL_ESOCK_MODULES = -endif PRE_LOADED_ERL_MODULES = \ erl_prim_loader \ @@ -81,11 +77,7 @@ STATIC_TARGET_FILES = $(PRE_LOADED_MODULES:%=$(STATIC_EBIN)/%.$(EMULATOR)) APP_FILE= erts.app APP_SRC= $(APP_FILE).src APP_TARGET= $(STATIC_EBIN)/$(APP_FILE) -ifeq ($(USE_ESOCK), yes) APP_ESOCK_MODS= prim_net, prim_socket, socket_registry, -else -APP_ESOCK_MODS= -endif KERNEL_SRC=$(ERL_TOP)/lib/kernel/src @@ -94,6 +86,10 @@ STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include ERL_COMPILE_FLAGS += +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_COMPILE_FLAGS += deterministic +endif + DIA_PLT = erts-preloaded.plt DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis ifeq ($(DIAW_EH),true) diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index 90401994173e..2d426f37d4cd 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2017. All Rights Reserved. +%% Copyright Ericsson AB 2013-2022. 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. @@ -39,7 +39,12 @@ main([BeamFile,AbstrFile]) -> fix_options(CInf0) -> CInf1 = binary_to_term(CInf0), - {options,Opts0} = lists:keyfind(options, 1, CInf1), - Opts = Opts0 -- [from_asm], + Opts = + case lists:keyfind(options, 1, CInf1) of + {options,Opts0} -> + Opts0 -- [from_asm]; + false -> + [] + end, CInf = lists:keyreplace(options, 1, CInf1, {options,Opts}), {term_to_binary(CInf), Opts}. diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 20fda619b855..4442d00914ce 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -53,10 +53,10 @@ -export([set_primary_archive/4]). %% Used by test suites --export([purge_archive_cache/0]). +-export([purge_archive_cache/0, get_modules/3]). -%% Used by init and the code server. --export([get_modules/2,get_modules/3, is_basename/1]). +%% Used by init and the code server +-export([get_modules/2, is_basename/1]). -include_lib("kernel/include/file.hrl"). diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index c810069d17d2..20416d02c25e 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -2,6 +2,8 @@ -export([enabled/3, trace/5, on_load/0]). +-nifs([enabled/3, trace/5]). + -type tracee() :: port() | pid() | undefined. -type trace_tag_running_ports() :: in | out | in_exiting | out_exiting | out_exited. diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index e53b33e721c9..110e6e62894b 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -36,7 +36,7 @@ -export([dmonitor_node/3]). -export([delay_trap/2]). -export([set_cookie/1, set_cookie/2, get_cookie/0, get_cookie/1]). --export([nodes/0]). +-export([nodes/0, nodes/1, nodes/2]). -export([integer_to_list/2]). -export([integer_to_binary/2]). @@ -86,14 +86,15 @@ -type boolean() :: true | false. -type byte() :: 0..255. -type char() :: 0..16#10FFFF. +-type dynamic() :: dynamic(). -type float() :: float(). -type function() :: fun(). -type identifier() :: pid() | port() | reference(). -type integer() :: integer(). -type iodata() :: iolist() | binary(). -type iolist() :: maybe_improper_list(byte() | binary() | iolist(), binary() | []). --type list() :: list(). --type list(ContentType) :: list(ContentType). +-type list() :: [any()]. +-type list(ContentType) :: [ContentType]. -type map() :: #{ any() => any() }. -type maybe_improper_list() :: maybe_improper_list(any(), any()). -type maybe_improper_list(ContentType, TerminationType) :: maybe_improper_list(ContentType, TerminationType). @@ -123,7 +124,7 @@ -type timeout() :: 'infinity' | non_neg_integer(). -type tuple() :: tuple(). -export_type([any/0, arity/0, atom/0, binary/0, bitstring/0, bool/0, boolean/0, byte/0, - char/0, float/0, function/0, identifier/0, integer/0, iodata/0, iolist/0, + char/0, dynamic/0, float/0, function/0, identifier/0, integer/0, iodata/0, iolist/0, list/0, list/1, map/0, maybe_improper_list/0, maybe_improper_list/2, mfa/0, module/0, neg_integer/0, nil/0, no_return/0, node/0, non_neg_integer/0, none/0, nonempty_binary/0, nonempty_bitstring/0, nonempty_improper_list/2, @@ -187,6 +188,9 @@ -type iovec() :: [binary()]. -export_type([iovec/0]). +%% Type for the destination of sends. +-export_type([send_destination/0]). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Native code BIF stubs and their types %% (BIF's actually implemented in this module goes last in the file) @@ -213,7 +217,7 @@ -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). -export([delete_module/1, demonitor/1, demonitor/2, display/1]). --export([display_nl/0, display_string/1, erase/0, erase/1]). +-export([display_string/1, display_string/2, erase/0, erase/1]). -export([error/1, error/2, error/3, exit/1, exit/2, exit_signal/2, external_size/1]). -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_binary/1, float_to_binary/2, @@ -266,7 +270,7 @@ is_list/1, is_map/1, is_number/1, is_pid/1, is_port/1, is_record/2, is_record/3, is_reference/1, is_tuple/1, load_module/2, load_nif/2, localtime_to_universaltime/2, make_fun/3, - make_tuple/2, make_tuple/3, nodes/1, open_port/2, + make_tuple/2, make_tuple/3, open_port/2, port_call/2, port_call/3, port_info/1, port_info/2, process_flag/2, process_info/2, send/2, send/3, seq_trace_info/1, setelement/3, @@ -386,7 +390,7 @@ {meta, module(), term() } | {meta_match_spec, trace_match_spec() | false | undefined} | {call_count, non_neg_integer() | boolean() | undefined} | - {call_time, [{pid(), non_neg_integer(), + {call_time | call_memory, [{pid(), non_neg_integer(), non_neg_integer(), non_neg_integer()}] | boolean() | undefined}. -type trace_info_flag() :: @@ -1006,15 +1010,21 @@ unalias(_Alias) -> display(_Term) -> erlang:nif_error(undefined). -%% display_nl/0 --spec erlang:display_nl() -> true. -display_nl() -> - erlang:nif_error(undefined). - %% display_string/1 -spec erlang:display_string(P1) -> true when + P1 :: string() | binary(). +display_string(String) -> + try erlang:display_string(stderr, String) + catch error:badarg:ST -> + [{erlang, display_string, _, [ErrorInfo]}|_] = ST, + erlang:error(badarg, [String], [ErrorInfo]) + end. + +%% display_string/2 +-spec erlang:display_string(Device, P1) -> true when + Device :: stdin | stdout | stderr, P1 :: string(). -display_string(_P1) -> +display_string(_Stream,_P1) -> erlang:nif_error(undefined). %% dt_append_vm_tag_data/1 @@ -1131,7 +1141,11 @@ external_size(_Term) -> %% external_size/2 -spec erlang:external_size(Term, Options) -> non_neg_integer() when Term :: term(), - Options :: [{minor_version, Version :: non_neg_integer()}]. + Options :: [compressed | + {compressed, Level :: 0..9} | + deterministic | + {minor_version, Version :: 0..2} | + local ]. external_size(_Term, _Options) -> erlang:nif_error(undefined). @@ -1170,7 +1184,8 @@ float_to_binary(_Float) -> Options :: [Option], Option :: {decimals, Decimals :: 0..253} | {scientific, Decimals :: 0..249} | - compact. + compact | + short. float_to_binary(_Float, _Options) -> erlang:nif_error(undefined). @@ -1186,7 +1201,8 @@ float_to_list(_Float) -> Options :: [Option], Option :: {decimals, Decimals :: 0..253} | {scientific, Decimals :: 0..249} | - compact. + compact | + short. float_to_list(_Float, _Options) -> erlang:nif_error(undefined). @@ -1365,8 +1381,13 @@ halt() -> %% halt/1 %% Shadowed by erl_bif_types: erlang:halt/1 --spec halt(Status) -> no_return() when - Status :: non_neg_integer() | 'abort' | string(). +-spec halt(Status :: non_neg_integer()) -> + no_return(); + (Abort :: abort) -> + no_return(); + (CrashDumpSlogan :: string()) -> + no_return(). + -dialyzer({no_return, halt/1}). halt(Status) -> try @@ -1377,11 +1398,18 @@ halt(Status) -> %% halt/2 %% Shadowed by erl_bif_types: erlang:halt/2 --spec halt(Status, Options) -> no_return() when - Status :: non_neg_integer() | 'abort' | string(), - Options :: [Option], - Option :: {flush, boolean()}. -halt(_Status, _Options) -> +-type halt_options() :: + [{flush, boolean()}]. + +-spec halt(Status :: non_neg_integer(), Options :: halt_options()) -> + no_return(); + (Abort :: abort, Options :: halt_options()) -> + no_return(); + (CrashDumpSlogan :: string(), Options :: halt_options()) -> + no_return(). + +-dialyzer({no_return, halt/2}). +halt(_, _) -> erlang:nif_error(undefined). %% has_prepared_code_on_load/1 @@ -1440,7 +1468,7 @@ iolist_to_iovec(_IoListOrBinary) -> %% is_alive/0 -spec is_alive() -> boolean(). is_alive() -> - erlang:nif_error(undefined). + erlang:node() =/= nonode@nohost orelse erts_internal:dynamic_node_name(). %% is_builtin/3 -spec erlang:is_builtin(Module, Function, Arity) -> boolean() when @@ -1997,6 +2025,7 @@ put(_Key, _Val) -> erlang:nif_error(undefined). %% raise/3 +%% Shadowed by erl_bif_types: erlang:raise/3 -spec erlang:raise(Class, Reason, Stacktrace) -> 'badarg' when Class :: 'error' | 'exit' | 'throw', Reason :: term(), @@ -2117,8 +2146,8 @@ setnode(_P1, _P2) -> -spec erlang:setnode(Node, DistCtrlr, Opts) -> dist_handle() when Node :: atom(), DistCtrlr :: port() | pid(), - Opts :: {integer(), integer(), pos_integer()}. -setnode(Node, DistCtrlr, {_Flags, _Ver, _Creation} = Opts) -> + Opts :: {integer(), pos_integer()}. +setnode(Node, DistCtrlr, {_Flags, _Creation} = Opts) -> case case erts_internal:create_dist_channel(Node, DistCtrlr, Opts) of {ok, DH} -> DH; {message, Ref} -> receive {Ref, Res} -> Res end; @@ -2303,7 +2332,7 @@ trace_delivered(_Tracee) -> Function :: atom(), Arity :: arity(), Item :: flags | tracer | traced | match_spec - | meta | meta_match_spec | call_count | call_time | all, + | meta | meta_match_spec | call_count | call_time | call_memory | all, Res :: trace_info_return(). trace_info(_PidPortFuncEvent, _Item) -> erlang:nif_error(undefined). @@ -2394,8 +2423,9 @@ get_module_info(_Module, _Item) -> erlang:nif_error(undefined). %% Shadowed by erl_bif_types: erlang:hd/1 --spec hd(List) -> term() when - List :: [term(), ...]. +-spec hd(List) -> Head when + List :: nonempty_maybe_improper_list(), + Head :: term(). hd(_List) -> erlang:nif_error(undefined). @@ -2510,7 +2540,8 @@ is_tuple(_Term) -> -spec load_module(Module, Binary) -> {module, Module} | {error, Reason} when Module :: module(), Binary :: binary(), - Reason :: badfile | not_purged | on_load. + Reason :: badfile | not_purged | on_load + | {features_not_allowed, [atom()]}. load_module(Mod, Code) -> try case erlang:prepare_loading(Mod, Code) of @@ -2569,13 +2600,6 @@ make_tuple(_Arity,_InitialValue) -> make_tuple(_Arity,_DefaultValue,_InitList) -> erlang:nif_error(undefined). --spec nodes(Arg) -> Nodes when - Arg :: NodeType | [NodeType], - NodeType :: visible | hidden | connected | this | known, - Nodes :: [node()]. -nodes(_Arg) -> - erlang:nif_error(undefined). - -spec open_port(PortName, PortSettings) -> port() when PortName :: {spawn, Command :: string() | binary()} | {spawn_driver, Command :: string() | binary()} | @@ -2617,7 +2641,10 @@ open_port(PortName, PortSettings) -> -type message_queue_data() :: off_heap | on_heap. --spec process_flag(trap_exit, Boolean) -> OldBoolean when +-spec process_flag(async_dist, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + (trap_exit, Boolean) -> OldBoolean when Boolean :: boolean(), OldBoolean :: boolean(); (error_handler, Module) -> OldModule when @@ -2655,6 +2682,7 @@ process_flag(_Flag, _Value) -> erlang:nif_error(undefined). -type process_info_item() :: + async_dist | backtrace | binary | catchlevel | @@ -2678,6 +2706,7 @@ process_flag(_Flag, _Value) -> monitored_by | monitors | message_queue_data | + parent | priority | reductions | registered_name | @@ -2690,6 +2719,7 @@ process_flag(_Flag, _Value) -> trap_exit. -type process_info_result_item() :: + {async_dist, Enabled :: boolean()} | {backtrace, Bin :: binary()} | {binary, BinInfo :: [{non_neg_integer(), non_neg_integer(), @@ -2722,6 +2752,7 @@ process_flag(_Flag, _Value) -> Monitors :: [{process | port, Pid :: pid() | port() | {RegName :: atom(), Node :: node()}}]} | {message_queue_data, MQD :: message_queue_data()} | + {parent, pid() | undefined} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | {registered_name, [] | (Atom :: atom())} | @@ -2758,13 +2789,13 @@ process_info(_Pid,_ItemSpec) -> erlang:nif_error(undefined). -spec erlang:send(Dest, Msg) -> Msg when - Dest :: dst(), + Dest :: send_destination(), Msg :: term(). send(_Dest,_Msg) -> erlang:nif_error(undefined). -spec erlang:send(Dest, Msg, Options) -> Res when - Dest :: dst(), + Dest :: send_destination(), Msg :: term(), Options :: [nosuspend | noconnect], Res :: ok | nosuspend | noconnect. @@ -2945,7 +2976,8 @@ term_to_binary(_Term) -> Options :: [compressed | {compressed, Level :: 0..9} | deterministic | - {minor_version, Version :: 0..2} ]. + {minor_version, Version :: 0..2} | + local ]. term_to_binary(_Term, _Options) -> erlang:nif_error(undefined). @@ -2959,13 +2991,15 @@ term_to_iovec(_Term) -> Options :: [compressed | {compressed, Level :: 0..9} | deterministic | - {minor_version, Version :: 0..2} ]. + {minor_version, Version :: 0..2} | + local ]. term_to_iovec(_Term, _Options) -> erlang:nif_error(undefined). %% Shadowed by erl_bif_types: erlang:tl/1 --spec tl(List) -> term() when - List :: nonempty_maybe_improper_list(). +-spec tl(List) -> Tail when + List :: nonempty_maybe_improper_list(), + Tail :: term(). tl(_List) -> erlang:nif_error(undefined). @@ -2993,7 +3027,8 @@ trace_pattern(MFA, MatchSpec) -> meta | {meta, Pid :: pid()} | {meta, TracerModule :: module(), TracerState :: term()} | call_count | - call_time. + call_time | + call_memory. -spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer() when MatchSpec :: (MatchSpecList :: trace_match_spec()) @@ -3063,6 +3098,7 @@ tuple_to_list(_Tuple) -> CpuTopology :: cpu_topology(); ({cpu_topology, defined | detected | used}) -> CpuTopology when CpuTopology :: cpu_topology(); + (cpu_quota) -> pos_integer() | unknown; (creation) -> integer(); (debug_compiled) -> boolean(); (delayed_node_table_gc) -> infinity | non_neg_integer(); @@ -3071,8 +3107,8 @@ tuple_to_list(_Tuple) -> (dirty_io_schedulers) -> non_neg_integer(); (dist) -> binary(); (dist_buf_busy_limit) -> non_neg_integer(); - (dist_ctrl) -> {Node :: node(), - ControllingEntity :: port() | pid()}; + (dist_ctrl) -> [{Node :: node(), + ControllingEntity :: port() | pid()}]; (driver_version) -> string(); (dynamic_trace) -> none | dtrace | systemtap; (dynamic_trace_probes) -> boolean(); @@ -3139,6 +3175,7 @@ tuple_to_list(_Tuple) -> (update_cpu_info) -> changed | unchanged; (version) -> string(); (wordsize | {wordsize, internal} | {wordsize, external}) -> 4 | 8; + (async_dist) -> boolean(); (overview) -> boolean(); %% Deliberately left undocumented (sequential_tracer) -> {sequential_tracer, pid() | port() | {module(),term()} | false}. @@ -3257,7 +3294,8 @@ spawn_monitor(M, F, A) -> %% TODO change size => to := when -type maps support is finalized | #{ size => non_neg_integer(), kill => boolean(), - error_logger => boolean() }. + error_logger => boolean(), + include_shared_binaries => boolean() }. -type spawn_opt_option() :: link @@ -3268,7 +3306,8 @@ spawn_monitor(M, F, A) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()} | {max_heap_size, Size :: max_heap_size()} - | {message_queue_data, MQD :: message_queue_data()}. + | {message_queue_data, MQD :: message_queue_data()} + | {async_dist, Enabled :: boolean()}. -spec spawn_opt(Fun, Options) -> pid() | {pid(), reference()} when Fun :: function(), @@ -3450,68 +3489,20 @@ spawn_opt(N, M, F, A, O) when erlang:is_atom(N), end; {spawn_reply, Ref, error, badopt} -> badarg_with_cause([N, M, F, A, O], badopt); - {spawn_reply, Ref, error, noconnection} -> - try + {spawn_reply, Ref, error, Err0} when Err0 == noconnection; + Err0 == notsup -> + try erlang:spawn_opt(erts_internal,crasher, - [N,M,F,A,O,noconnection], O) + [N,M,F,A,O,Err0], O) catch _:Err1 -> error_with_info(Err1, [N, M, F, A, O]) end; - {spawn_reply, Ref, error, notsup} -> - case old_remote_spawn_opt(N, M, F, A, O) of - Pid when erlang:is_pid(Pid) -> - Pid; - Err2 -> - error_with_info(Err2, [N, M, F, A, O]) - end; - {spawn_reply, Ref, error, Err3} -> - error_with_info(Err3, [N, M, F, A, O]) + {spawn_reply, Ref, error, Err2} -> + error_with_info(Err2, [N, M, F, A, O]) end; spawn_opt(N,M,F,A,O) -> badarg_with_info([N,M,F,A,O]). - -old_remote_spawn_opt(N, M, F, A, O) -> - case lists:member(monitor, O) of - true -> - badarg; - _ -> - {L,NO} = lists:foldl(fun (link, {_, NewOpts}) -> - {link, NewOpts}; - (Opt, {LO, NewOpts}) -> - {LO, [Opt|NewOpts]} - end, - {no_link,[]}, - O), - case catch gen_server:call({net_kernel,N}, - {spawn_opt,M,F,A,NO,L,erlang:group_leader()}, - infinity) of - Pid when erlang:is_pid(Pid) -> - Pid; - Error -> - case remote_spawn_error(Error, {L, N, M, F, A, NO}) of - {fault, Fault} -> - Fault; - Pid -> - Pid - end - end - end. - -remote_spawn_error({'EXIT', {{nodedown,N}, _}}, {L, N, M, F, A, O}) -> - {Opts, LL} = case L =:= link of - true -> - {[link|O], [link]}; - false -> - {O, []} - end, - erlang:spawn_opt(erts_internal,crasher,[N,M,F,A,Opts,noconnection], LL); -remote_spawn_error({'EXIT', {Reason, _}}, _) -> - {fault, Reason}; -remote_spawn_error({'EXIT', Reason}, _) -> - {fault, Reason}; -remote_spawn_error(Other, _) -> - {fault, Other}. %% %% spawn_request/1 @@ -3698,7 +3689,28 @@ yield() -> -spec nodes() -> Nodes when Nodes :: [node()]. nodes() -> - erlang:nodes(visible). + erlang:nif_error(undefined). + +-spec nodes(Arg) -> Nodes when + Arg :: NodeType | [NodeType], + NodeType :: visible | hidden | connected | this | known, + Nodes :: [node()]. +nodes(_Arg) -> + erlang:nif_error(undefined). + +-spec nodes(Arg, InfoOpts) -> [NodeInfo] when + NodeType :: visible | hidden | connected | this | known, + Arg :: NodeType | [NodeType], + InfoOpts :: #{connection_id => boolean(), + node_type => boolean()}, + NodeTypeInfo :: visible | hidden | this | known, + ConnectionId :: undefined | integer(), + Info :: #{connection_id => ConnectionId, + node_type => NodeTypeInfo}, + NodeInfo :: {node(), Info}. + +nodes(_Args, _Opts) -> + erlang:nif_error(undefined). -spec disconnect_node(Node) -> boolean() | ignored when Node :: node(). @@ -3723,14 +3735,14 @@ fun_info_1([K|Ks], Fun, A) -> end; fun_info_1([], _, A) -> A. --type dst() :: pid() - | reference() - | port() - | (RegName :: atom()) - | {RegName :: atom(), Node :: node()}. +-type send_destination() :: pid() + | reference() + | port() + | (RegName :: atom()) + | {RegName :: atom(), Node :: node()}. -spec erlang:send_nosuspend(Dest, Msg) -> boolean() when - Dest :: dst(), + Dest :: send_destination(), Msg :: term(). send_nosuspend(Pid, Msg) -> try @@ -3740,7 +3752,7 @@ send_nosuspend(Pid, Msg) -> end. -spec erlang:send_nosuspend(Dest, Msg, Options) -> boolean() when - Dest :: dst(), + Dest :: send_destination(), Msg :: term(), Options :: [noconnect]. send_nosuspend(Pid, Msg, Opts) -> @@ -4235,17 +4247,23 @@ rvrs(Xs) -> rvrs(Xs, []). rvrs([],Ys) -> Ys; rvrs([X|Xs],Ys) -> rvrs(Xs, [X|Ys]). +%% Shadowed by erl_bif_types: erlang:min/2 -spec min(Term1, Term2) -> Minimum when Term1 :: term(), Term2 :: term(), Minimum :: term(). +%% In Erlang/OTP 26, min/2 is a guard BIF. This implementation is kept +%% for backward compatibility with code compiled with an earlier version. min(A, B) when A > B -> B; min(A, _) -> A. +%% Shadowed by erl_bif_types: erlang:max/2 -spec max(Term1, Term2) -> Maximum when Term1 :: term(), Term2 :: term(), Maximum :: term(). +%% In Erlang/OTP 26, max/2 is a guard BIF. This implementation is kept +%% for backward compatibility with code compiled with an earlier version. max(A, B) when A < B -> B; max(A, _) -> A. @@ -4662,7 +4680,7 @@ gc_info(Ref, N, {OrigColls,OrigRecl}) -> 'not'(_A) -> erlang:nif_error(undefined). --spec erlang:'!'(dst(), term()) -> term(). +-spec erlang:'!'(send_destination(), term()) -> term(). '!'(_Dst, _Msg) -> erlang:nif_error(undefined). diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index 94fd77b80d44..17cb04e62e14 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -42,7 +42,7 @@ {registered, []}, {applications, []}, {env, []}, - {runtime_dependencies, ["stdlib-3.13", "kernel-8.3", "sasl-3.3"]} + {runtime_dependencies, ["stdlib-4.1", "kernel-9.0", "sasl-3.3"]} ]}. %% vim: ft=erlang diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 9f6bd6e2893c..120466bc6f4a 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -411,7 +411,7 @@ do_test_hard_purge(Mod, From, Ref, Reqs) -> end. test_progress(_State, _From, _Ref, died) -> - %% Test process died; continue so we wont + %% Test process died; continue so we won't %% leave the system in an inconsistent %% state... died; diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 6cd5314511a3..72d292721551 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -33,6 +33,7 @@ -export([cmp_term/2]). -export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1, map_next/3]). +-export([mc_iterator/1, mc_refill/1]). -export([open_port/2, port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -118,6 +119,10 @@ -export([binary_to_integer/2, list_to_integer/2]). +-export([dynamic_node_name/0, dynamic_node_name/1]). + +-export([term_to_string/1, term_to_string/2]). + %% %% Await result of send to port %% @@ -430,7 +435,7 @@ map_hashmap_children(_M) -> %% return the next assoc in the iterator and a new iterator -spec map_next(I, M, A) -> {K,V,NI} | list() when - I :: non_neg_integer(), + I :: non_neg_integer() | list(), M :: map(), K :: term(), V :: term(), @@ -440,6 +445,61 @@ map_hashmap_children(_M) -> map_next(_I, _M, _A) -> erlang:nif_error(undefined). +%% Introduced in Erlang/OTP 26. This function is a helper, called from +%% code generated by the compiler. It must be kept compatible as long +%% code calling this helper can still be loaded. +-spec mc_iterator(MapOrIter) -> NI when + MapOrIter :: map() | maps:iterator(), + NI :: term(). + +mc_iterator(Map) when is_map(Map) -> + erts_internal:map_next(0, Map, iterator); +mc_iterator([Path | Map]) -> + %% This is probably an iterator. + try erts_internal:map_next(Path, Map, iterator) of + Iter -> + Iter + catch + error:badarg -> + [] + end; +mc_iterator(MapIter) -> + %% Possible "used" iterator. Must validate it. + case is_map_iter(MapIter) of + true -> MapIter; + false -> [] + end. + +is_map_iter({_, _, Iter}) -> + is_map_iter(Iter); +is_map_iter(Iter) -> + case Iter of + [Path | Map] -> + try erts_internal:map_next(Path, Map, iterator) of + _ -> + true + catch + error:badarg -> + false + end; + none -> true; + _ -> false + end. + +%% Introduced in Erlang/OTP 26. This function is a helper, called from +%% code generated by the compiler. It must be kept compatible as long +%% code calling this helper can still be loaded. +-spec mc_refill(IM) -> {K,V,NI} when + IM :: nonempty_improper_list(I, M), + I :: non_neg_integer(), + M :: map(), + K :: term(), + V :: term(), + NI :: term(). + +mc_refill([Path | Map]) -> + erts_internal:map_next(Path, Map, iterator). + -spec erts_internal:flush_monitor_messages(Ref, Multi, Res) -> term() when Ref :: reference(), Multi :: boolean(), @@ -744,11 +804,10 @@ process_display(_Pid, _Type) -> process_flag(_Pid, _Flag, _Value) -> erlang:nif_error(undefined). --spec create_dist_channel(Node, DistCtrlr, {Flags, Ver, Cr}) -> Result when +-spec create_dist_channel(Node, DistCtrlr, {Flags, Cr}) -> Result when Node :: atom(), DistCtrlr :: port() | pid(), Flags :: integer(), - Ver :: integer(), Cr :: pos_integer(), Result :: {'ok', erlang:dist_handle()} | {'message', reference()} @@ -799,7 +858,7 @@ spawn_system_process(_Mod, _Func, _Args) -> %% -spec ets_lookup_binary_info(Tab, Key) -> BinInfo when - Tab :: ets:tab(), + Tab :: ets:table(), Key :: term(), BinInfo :: [{non_neg_integer(), non_neg_integer(), non_neg_integer()}]. @@ -813,20 +872,20 @@ ets_super_user(_Bool) -> erlang:nif_error(undef). -spec ets_raw_first(Tab) -> term() when - Tab :: ets:tab(). + Tab :: ets:table(). ets_raw_first(_Tab) -> erlang:nif_error(undef). -spec ets_raw_next(Tab, Key) -> term() when - Tab :: ets:tab(), + Tab :: ets:table(), Key :: term(). ets_raw_next(_Tab, _Key) -> erlang:nif_error(undef). -spec ets_info_binary(Tab) -> BinInfo when - Tab :: ets:tab(), + Tab :: ets:table(), BinInfo :: [{non_neg_integer(), non_neg_integer(), non_neg_integer()}]. ets_info_binary(Tab) -> @@ -998,3 +1057,39 @@ binary_to_integer(_Bin, _Base) -> Base :: 2..36. list_to_integer(_List, _Base) -> erlang:nif_error(undefined). + +%% +%% Is dynamic node name enabled? +%% +-spec dynamic_node_name() -> boolean(). + +dynamic_node_name() -> + case persistent_term:get({?MODULE, dynamic_node_name}, false) of + false -> false; + _ -> true + end. + +%% +%% Save whether dynamic node name is enabled or not. +%% +-spec dynamic_node_name(boolean()) -> ok. + +dynamic_node_name(true) -> + persistent_term:put({?MODULE, dynamic_node_name}, true); +dynamic_node_name(false) -> + case dynamic_node_name() of + false -> ok; + _ -> _ = persistent_term:erase({?MODULE, dynamic_node_name}), ok + end. + +-spec term_to_string(T :: term()) -> string(). + +term_to_string(T) -> + term_to_string(T, undefined). + +-spec term_to_string(T, Limit) -> string() when + T :: term(), + Limit :: undefined | pos_integer(). + +term_to_string(_T, _Limit) -> + erlang:nif_error(undefined). diff --git a/erts/preloaded/src/erts_literal_area_collector.erl b/erts/preloaded/src/erts_literal_area_collector.erl index 8a73ed1685a8..bb2ad6b91901 100644 --- a/erts/preloaded/src/erts_literal_area_collector.erl +++ b/erts/preloaded/src/erts_literal_area_collector.erl @@ -62,39 +62,46 @@ msg_loop(Area, {Ongoing, NeedIReq} = OReqInfo, GcOutstnd, NeedGC) -> switch_area(); %% Process (_Pid) has completed the request... - {copy_literals, {Area, _GcAllowed, _Pid}, ok} when Ongoing == 1, - NeedIReq == [] -> + {copy_literals, {Area, _ReqType, _Pid}, ok} when Ongoing == 1, + NeedIReq == [] -> switch_area(); %% Last process completed... - {copy_literals, {Area, false, _Pid}, ok} -> + {copy_literals, {Area, init, _Pid}, ok} -> msg_loop(Area, check_send_copy_req(Area, Ongoing-1, NeedIReq), GcOutstnd, NeedGC); - {copy_literals, {Area, true, _Pid}, ok} when NeedGC == [] -> + {copy_literals, {Area, ReqType, _Pid}, ok} when NeedGC == [], + ReqType /= init -> msg_loop(Area, check_send_copy_req(Area, Ongoing-1, NeedIReq), GcOutstnd-1, []); - {copy_literals, {Area, true, _Pid}, ok} -> - send_copy_req(hd(NeedGC), Area, true), - msg_loop(Area, {Ongoing-1, NeedIReq}, GcOutstnd, tl(NeedGC)); + {copy_literals, {Area, ReqType, _Pid}, ok} when ReqType /= init -> + [{GCPid,GCWork} | NewNeedGC] = NeedGC, + send_copy_req(GCPid, Area, GCWork), + msg_loop(Area, {Ongoing-1, NeedIReq}, GcOutstnd, NewNeedGC); %% Process (Pid) failed to complete the request %% since it needs to garbage collect in order to %% complete the request... - {copy_literals, {Area, false, Pid}, need_gc} when GcOutstnd < ?MAX_GC_OUTSTND -> - send_copy_req(Pid, Area, true), + {copy_literals, {Area, init, Pid}, GCWork} when GcOutstnd + < ?MAX_GC_OUTSTND -> + send_copy_req(Pid, Area, GCWork), msg_loop(Area, OReqInfo, GcOutstnd+1, NeedGC); - {copy_literals, {Area, false, Pid}, need_gc} -> + {copy_literals, {Area, init, Pid}, GCWork} -> msg_loop(Area, check_send_copy_req(Area, Ongoing, NeedIReq), - GcOutstnd, [Pid|NeedGC]); + GcOutstnd, [{Pid,GCWork} | NeedGC]); %% Not handled message regarding the area that we %% currently are working with. Crash the VM so %% we notice this bug... - {copy_literals, {Area, _, _}, _} = Msg when erlang:is_reference(Area) -> + {copy_literals, {Area, _, _}, _} = Msg -> exit({not_handled_message, Msg}); {change_prio, From, Ref, Prio} -> change_prio(From, Ref, Prio), msg_loop(Area, OReqInfo, GcOutstnd, NeedGC); + {get_status, Ref, From} when is_pid(From); is_reference(From) -> + From ! {Ref, if Ongoing == 0 -> idle; true -> working end}, + msg_loop(Area, OReqInfo, GcOutstnd, NeedGC); + %% Unexpected garbage message. Get rid of it... _Ignore -> msg_loop(Area, OReqInfo, GcOutstnd, NeedGC) @@ -126,7 +133,7 @@ switch_area() -> check_send_copy_req(_Area, Ongoing, []) -> {Ongoing, []}; check_send_copy_req(Area, Ongoing, [Pid|Pids]) -> - send_copy_req(Pid, Area, false), + send_copy_req(Pid, Area, init), {Ongoing+1, Pids}. send_copy_reqs(Ps, Area, OReqLim) -> @@ -137,23 +144,23 @@ send_copy_reqs([], _Area, _OReqLim, N) -> send_copy_reqs(Ps, _Area, OReqLim, N) when N >= OReqLim -> {N, Ps}; send_copy_reqs([P|Ps], Area, OReqLim, N) -> - send_copy_req(P, Area, false), + send_copy_req(P, Area, init), send_copy_reqs(Ps, Area, OReqLim, N+1). -send_copy_req(P, Area, GC) -> - erts_literal_area_collector:send_copy_request(P, Area, GC). +send_copy_req(P, Area, How) -> + erts_literal_area_collector:send_copy_request(P, Area, How). -spec release_area_switch() -> boolean(). release_area_switch() -> erlang:nif_error(undef). %% Implemented in beam_bif_load.c --spec send_copy_request(To, AreaId, GcAllowed) -> 'ok' when +-spec send_copy_request(To, AreaId, How) -> 'ok' when To :: pid(), AreaId :: term(), - GcAllowed :: boolean(). + How :: 'init' | 'check_gc' | 'need_gc'. -send_copy_request(_To, _AreaId, _GcAllowed) -> +send_copy_request(_To, _AreaId, _How) -> erlang:nif_error(undef). %% Implemented in beam_bif_load.c change_prio(From, Ref, Prio) -> diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 784696e834e2..1f7ef2808559 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -98,6 +98,17 @@ debug(false, _) -> ok; debug(_, T) -> erlang:display(T). +debug(false, _, Fun) -> + Fun(); +debug(_, T, Fun) -> + erlang:display(T), + T1 = erlang:monotonic_time(), + Val = Fun(), + T2 = erlang:monotonic_time(), + Time = erlang:convert_time_unit(T2 - T1, native, microsecond), + erlang:display({done_in_microseconds, Time}), + Val. + -spec get_configfd(integer()) -> none | term(). get_configfd(ConfigFdId) -> request({get_configfd, ConfigFdId}). @@ -304,60 +315,9 @@ boot(Start,Flags,Args) -> bootpid = BootPid}, boot_loop(BootPid,State). -%%% Convert a term to a printable string, if possible. -to_string(X, D) when is_list(X), D < 4 -> % assume string - F = flatten(X, []), - case printable_list(F) of - true when length(F) > 0 -> F; - _false -> - List = [to_string(E, D+1) || E <- X], - flatten(["[",join(List),"]"], []) - end; -to_string(X, _D) when is_list(X) -> - "[_]"; -to_string(X, _D) when is_atom(X) -> - atom_to_list(X); -to_string(X, _D) when is_pid(X) -> - pid_to_list(X); -to_string(X, _D) when is_float(X) -> - float_to_list(X); -to_string(X, _D) when is_integer(X) -> - integer_to_list(X); -to_string(X, D) when is_tuple(X), D < 4 -> - List = [to_string(E, D+1) || E <- tuple_to_list(X)], - flatten(["{",join(List),"}"], []); -to_string(X, _D) when is_tuple(X) -> - "{_}"; -to_string(_X, _D) -> - "". % can't do anything with it - -%% This is an incorrect and narrow definition of printable characters. -%% The correct one is in io_lib:printable_list/1 -%% -printable_list([H|T]) when is_integer(H), H >= 32, H =< 126 -> - printable_list(T); -printable_list([$\n|T]) -> printable_list(T); -printable_list([$\r|T]) -> printable_list(T); -printable_list([$\t|T]) -> printable_list(T); -printable_list([]) -> true; -printable_list(_) -> false. - -join([] = T) -> - T; -join([_Elem] = T) -> - T; -join([Elem|T]) -> - [Elem,","|join(T)]. - -flatten([H|T], Tail) when is_list(H) -> - flatten(H, flatten(T, Tail)); -flatten([H|T], Tail) -> - [H|flatten(T, Tail)]; -flatten([], Tail) -> - Tail. - things_to_string([X|Rest]) -> - " (" ++ to_string(X, 0) ++ ")" ++ things_to_string(Rest); + " (" ++ erts_internal:term_to_string(X, 32768) ++ ")" ++ + things_to_string(Rest); things_to_string([]) -> "". @@ -396,8 +356,8 @@ boot_loop(BootPid, State) -> loop(State#state{status = {started,PS}, subscribed = []}); {'EXIT',BootPid,Reason} -> - erlang:display({"init terminating in do_boot",Reason}), - crash("init terminating in do_boot", [Reason]); + % erlang:display({"init terminating in do_boot",Reason}), + crash("Runtime terminating during boot", [Reason]); {'EXIT',Pid,Reason} -> Kernel = State#state.kernel, terminate(Pid,Kernel,Reason), %% If Pid is a Kernel pid, halt()! @@ -462,9 +422,9 @@ new_kernelpid({_Name,ignore},BootPid,State) -> BootPid ! {self(),ignore}, State; new_kernelpid({Name,What},BootPid,State) -> - erlang:display({"could not start kernel pid",Name,What}), + % erlang:display({"could not start kernel pid",Name,What}), clear_system(false,BootPid,State), - crash("could not start kernel pid", [Name, What]). + crash("Could not start kernel pid", [Name, What]). %% Here is the main loop after the system has booted. @@ -558,7 +518,7 @@ do_handle_msg(Msg,State) -> true -> logger:info("init got unexpected: ~p", [X], #{ error_logger=>#{tag=>info_msg}}); false -> - erlang:display_string("init got unexpected: "), + erlang:display_string(stdout, "init got unexpected: "), erlang:display(X) end end @@ -591,7 +551,7 @@ set_flag(_Flag,false,Flags) -> {ok,Flags}; set_flag(Flag,Value,Flags) when is_list(Value) -> %% The flag here can be -boot or -config, which means the value is - %% a file name! Thus the file name encoding is used when coverting. + %% a file name! Thus the file name encoding is used when converting. Encoding = file:native_name_encoding(), case catch unicode:characters_to_binary(Value,Encoding,Encoding) of {'EXIT',_} -> @@ -833,8 +793,9 @@ del(_Item, []) -> []. terminate(Pid,Kernel,Reason) -> case kernel_pid(Pid,Kernel) of {ok,Name} -> + %% If you change this time, also change the time in logger_simple_h.erl sleep(500), %% Flush error printouts! - erlang:display({"Kernel pid terminated",Name,Reason}), + % erlang:display({"Kernel pid terminated",Name,Reason}), crash("Kernel pid terminated", [Name, Reason]); _ -> false @@ -889,6 +850,7 @@ do_boot(Flags,Start) -> do_boot(Init,Flags,Start) -> process_flag(trap_exit,true), Root = get_root(Flags), + true = check_bindir(Flags), Path = get_flag_list(path, Flags, false), {Pa,Pz} = PathFls = path_flags(Flags), start_prim_loader(Init, bs2ss(Path), PathFls), @@ -923,6 +885,14 @@ get_root(Flags) -> exit(no_or_multiple_root_variables) end. +check_bindir(Flags) -> + case get_argument(bindir, Flags) of + {ok,[[_Bindir]]} -> + true; + _ -> + exit(no_or_multiple_bindir_variables) + end. + get_boot_vars(Root, Flags) -> BootVars = get_boot_vars_1(#{}, Flags), RootKey = <<"ROOT">>, @@ -1003,10 +973,13 @@ eval_script([{preLoaded,_}|T], #es{}=Es) -> eval_script(T, Es); eval_script([{path,Path}|T], #es{path=false,pa=Pa,pz=Pz, path_choice=PathChoice, - vars=Vars}=Es) -> - RealPath0 = make_path(Pa, Pz, Path, Vars), - RealPath = patch_path(RealPath0, PathChoice), - erl_prim_loader:set_path(RealPath), + vars=Vars,debug=Deb}=Es) -> + debug(Deb, {path,Path}, + fun() -> + RealPath0 = make_path(Pa, Pz, Path, Vars), + RealPath = patch_path(RealPath0, PathChoice), + erl_prim_loader:set_path(RealPath) + end), eval_script(T, Es); eval_script([{path,_}|T], #es{}=Es) -> %% Ignore, use the command line -path flag. @@ -1029,12 +1002,10 @@ eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad}=Es) eval_script(T, Es); eval_script([{kernelProcess,Server,{Mod,Fun,Args}}|T], #es{init=Init,debug=Deb}=Es) -> - debug(Deb, {start,Server}), - start_in_kernel(Server, Mod, Fun, Args, Init), + debug(Deb, {start,Server}, fun() -> start_in_kernel(Server, Mod, Fun, Args, Init) end), eval_script(T, Es); eval_script([{apply,{Mod,Fun,Args}}=Apply|T], #es{debug=Deb}=Es) -> - debug(Deb, Apply), - apply(Mod, Fun, Args), + debug(Deb, Apply, fun() -> apply(Mod, Fun, Args) end), eval_script(T, Es); eval_script([], #es{}) -> ok; @@ -1216,21 +1187,54 @@ start_it([]) -> ok; start_it({eval,Bin}) -> Str = b2s(Bin), - {ok,Ts,_} = erl_scan:string(Str), - Ts1 = case reverse(Ts) of - [{dot,_}|_] -> Ts; - TsR -> reverse([{dot,erl_anno:new(1)} | TsR]) - end, - {ok,Expr} = erl_parse:parse_exprs(Ts1), - {value, _Value, _Bs} = erl_eval:exprs(Expr, erl_eval:new_bindings()), - ok; -start_it([_|_]=MFA) -> - case MFA of - [M] -> M:start(); - [M,F] -> M:F(); - [M,F|Args] -> M:F(Args) % Args is a list + try + {ok,Ts,_} = erl_scan:string(Str), + Ts1 = case reverse(Ts) of + [{dot,_}|_] -> Ts; + TsR -> reverse([{dot,erl_anno:new(1)} | TsR]) + end, + {ok,Expr} = erl_parse:parse_exprs(Ts1), + {value, _Value, _Bs} = erl_eval:exprs(Expr, erl_eval:new_bindings()), + ok + catch E:R:ST -> + Message = [<<"Error! Failed to eval: ">>, Bin, <<"\r\n\r\n">>], + erlang:display_string(binary_to_list(iolist_to_binary(Message))), + erlang:raise(E,R,ST) + end; +start_it([M|FA]) -> + case code:ensure_loaded(M) of + {module, M} -> + case FA of + [] -> M:start(); + [F] -> M:F(); + [F|Args] -> M:F(Args) % Args is a list + end; + + {error, Reason} -> + Message = [explain_ensure_loaded_error(M, Reason), <<"\r\n\r\n">>], + erlang:display_string(binary_to_list(iolist_to_binary(Message))), + erlang:error(undef) end. +explain_ensure_loaded_error(M, badfile) -> + S = [<<"it requires a more recent Erlang/OTP version " + "or its .beam file was corrupted.\r\n" + "(You are running Erlang/OTP ">>, + erlang:system_info(otp_release), <<".)">>], + explain_add_head(M, S); +explain_ensure_loaded_error(M, nofile) -> + S = <<"it cannot be found. Make sure that the module name is correct and\r\n", + "that its .beam file is in the code path.">>, + explain_add_head(M, S); +explain_ensure_loaded_error(M, Other) -> + [<<"Error! Failed to load module '", (atom_to_binary(M))/binary, + "'. Reason: ">>, + atom_to_binary(Other)]. + +explain_add_head(M, S) -> + [<<"Error! Failed to load module '", (atom_to_binary(M))/binary, + "' because ">>, S]. + %% Load a module. do_load_module(Mod, BinCode) -> @@ -1448,7 +1452,7 @@ archive_extension() -> run_on_load_handlers() -> Ref = monitor(process, ?ON_LOAD_HANDLER), - catch ?ON_LOAD_HANDLER ! run_on_load, + _ = catch ?ON_LOAD_HANDLER ! {run_on_load, Ref}, receive {'DOWN',Ref,process,_,noproc} -> %% There is no on_load handler process, @@ -1456,12 +1460,13 @@ run_on_load_handlers() -> %% called and it is not the first time we %% pass through here. ok; - {'DOWN',Ref,process,_,on_load_done} -> + {'DOWN',Ref,process,_,Ref} -> + %% All on_load handlers have run succesfully ok; - {'DOWN',Ref,process,_,Res} -> + {'DOWN',Ref,process,_,Reason} -> %% Failure to run an on_load handler. %% This is fatal during start-up. - exit(Res) + exit(Reason) end. start_on_load_handler_process() -> @@ -1477,34 +1482,37 @@ on_load_loop(Mods, Debug0) -> on_load_loop(Mods, Debug); {loaded,Mod} -> on_load_loop([Mod|Mods], Debug0); - run_on_load -> + {run_on_load, Ref} -> run_on_load_handlers(Mods, Debug0), - exit(on_load_done) + exit(Ref) end. run_on_load_handlers([M|Ms], Debug) -> - debug(Debug, {running_on_load_handler,M}), + debug(Debug, + {running_on_load_handler,M}, + fun() -> run_on_load_handler(M, Debug) end), + run_on_load_handlers(Ms, Debug); +run_on_load_handlers([], _) -> ok. + +run_on_load_handler(M, Debug) -> Fun = fun() -> - Res = erlang:call_on_load_function(M), - exit(Res) - end, + Res = erlang:call_on_load_function(M), + exit(Res) + end, {Pid,Ref} = spawn_monitor(Fun), receive - {'DOWN',Ref,process,Pid,OnLoadRes} -> - Keep = OnLoadRes =:= ok, - erlang:finish_after_on_load(M, Keep), - case Keep of - false -> - Error = {on_load_function_failed,M,OnLoadRes}, - debug(Debug, Error), - exit(Error); - true -> - debug(Debug, {on_load_handler_returned_ok,M}), - run_on_load_handlers(Ms, Debug) - end - end; -run_on_load_handlers([], _) -> ok. - + {'DOWN',Ref,process,Pid,OnLoadRes} -> + Keep = OnLoadRes =:= ok, + erlang:finish_after_on_load(M, Keep), + case Keep of + false -> + Error = {on_load_function_failed,M,OnLoadRes}, + debug(Debug, Error), + exit(Error); + true -> + debug(Debug, {on_load_handler_returned_ok,M}) + end + end. %% debug profile (light variant of eprof) debug_profile_start() -> @@ -1552,6 +1560,8 @@ collect_mfas([MFA|MFAs],Info) -> collect_mfas(MFAs,Info); {call_time, false} -> collect_mfas(MFAs,Info); + {call_time, undefined} -> + collect_mfas(MFAs,Info); {call_time, Data} -> case collect_mfa(MFA,Data,0,0) of {{0,_},_} -> diff --git a/erts/preloaded/src/prim_buffer.erl b/erts/preloaded/src/prim_buffer.erl index e0d35a67927e..7ee29753330f 100644 --- a/erts/preloaded/src/prim_buffer.erl +++ b/erts/preloaded/src/prim_buffer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017. All Rights Reserved. +%% Copyright Ericsson AB 2017-2022. 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. @@ -34,6 +34,9 @@ -export([try_lock/1, unlock/1]). +-nifs([new/0, size/1, peek_head/1, copying_read/2, write/2, skip/2, + find_byte_index/2, try_lock/1, unlock/1]). + -type prim_buffer() :: term(). %% Controls when to copy rather than extract sub-binaries from the buffer, @@ -106,7 +109,7 @@ skip(_Buffer, _Size) -> wipe(Buffer) -> skip(Buffer, prim_buffer:size(Buffer)). -%% Finds the start-index of the first occurence of Needle, for implementing +%% Finds the start-index of the first occurrence of Needle, for implementing %% read_line and similar. -spec find_byte_index(Buffer, Needle) -> Result when Buffer :: prim_buffer(), diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 4c588b9ca532..3e9f578b656b 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -64,6 +64,17 @@ internal_normalize_utf8/1, is_translatable/1]). +-nifs([open_nif/2, close_nif/1, read_nif/2, write_nif/2, pread_nif/3, + pwrite_nif/3, seek_nif/3, sync_nif/2, truncate_nif/1, allocate_nif/3, + advise_nif/4, read_handle_info_nif/1, + make_hard_link_nif/2, make_soft_link_nif/2, rename_nif/2, + read_info_nif/2, set_permissions_nif/2, set_owner_nif/3, set_time_nif/4, + read_link_nif/1, list_dir_nif/1, make_dir_nif/1, del_file_nif/1, + del_dir_nif/1, get_device_cwd_nif/1, set_cwd_nif/1, get_cwd_nif/0, + ipread_s32bu_p32bu_nif/3, read_file_nif/1, + get_handle_nif/1, delayed_close_nif/1, altname_nif/1, + file_desc_to_ref_nif/1]). + -type prim_file_name() :: string() | unicode:unicode_binary(). -type prim_file_name_error() :: 'error' | 'ignore' | 'warning'. @@ -642,6 +653,8 @@ read_handle_info_1(Fd, TimeType) -> error:_ -> {error, badarg} end. +adjust_times(FileInfo, posix) -> + FileInfo; adjust_times(FileInfo, TimeType) -> CTime = from_posix_seconds(FileInfo#file_info.ctime, TimeType), MTime = from_posix_seconds(FileInfo#file_info.mtime, TimeType), @@ -866,8 +879,6 @@ is_path_translatable(Path) -> %% We want to use posix time in all prim but erl_prim_loader makes that tricky %% It is probably needed to redo the whole erl_prim_loader -from_posix_seconds(Seconds, posix) when is_integer(Seconds) -> - Seconds; from_posix_seconds(Seconds, universal) when is_integer(Seconds) -> erlang:posixtime_to_universaltime(Seconds); from_posix_seconds(Seconds, local) when is_integer(Seconds) -> diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index ff083d9fc15a..a9264d551add 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,8 +1,8 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2023. 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 @@ -14,7 +14,7 @@ %% 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% %% %% The SCTP protocol was added 2006 @@ -28,7 +28,7 @@ -export([open/3, open/4, fdopen/4, fdopen/5, close/1]). -export([bind/3, listen/1, listen/2, peeloff/2]). --export([connect/3, connect/4, async_connect/4]). +-export([connect/3, connect/4, async_connect/4, connectx/2, connectx/3]). -export([accept/1, accept/2, accept/3, async_accept/2]). -export([shutdown/2]). -export([send/2, send/3, sendto/4, sendmsg/3, sendfile/4]). @@ -332,7 +332,7 @@ bindx_check_addrs([Addr|Addrs]) -> bindx_check_addrs([]) -> true. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason} %% @@ -409,6 +409,41 @@ async_connect0(S, Addr, Time) -> {error, _}=Error -> Error end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% CONNECTX(insock(), IPs, Port) -> {ok, AssocId} | {error, Reason} +%% CONNECTX(insock(), SockAddrs) -> {ok, AssocId} | {error, Reason} +%% +%% For SCTP sockets only +%% +%% connect the insock() to the addresses given by IPs and Port or SockAddrs +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +connectx(S, IPs, Port) -> + connectx(S, {IPs, Port}). + +connectx(S, AddrList) -> + case type_value(set, addr_list, AddrList) of + true -> + connectx0(S, AddrList); + false -> + {error, einval} + end. + + +connectx0(S, Addrs) -> + Args = [enc_time(-1),enc_value(set, addr_list, Addrs)], + case ctl_cmd(S, ?INET_REQ_CONNECT, Args) of + {ok, [R1,R0]} -> + Ref = ?u16(R1,R0), + receive + {inet_async, S, Ref, Status} -> + Status + end; + Error -> + Error + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% ACCEPT(insock() [,Timeout][,FamilyOpts] ) -> {ok,insock()} | {error, Reason} @@ -529,48 +564,33 @@ peeloff(S, AssocId) -> %% send(S, Data, OptList) when is_port(S), is_list(OptList) -> ?DBG_FORMAT("prim_inet:send(~p, _, ~p)~n", [S,OptList]), - try erlang:port_command(S, Data, OptList) of - false -> % Port busy and nosuspend option passed + Mref = monitor(port, S), + MrefBin = term_to_binary(Mref, [local]), + MrefBinSize = byte_size(MrefBin), + MrefBinSize = MrefBinSize band 16#FFFF, + try + erlang:port_command( + S, [<>, Data], OptList) + of + false -> % Port busy when nosuspend option was passed ?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []), - {error,busy}; - true -> - send_recv_reply(S, undefined) - catch - error:_Error -> + {error,busy}; + true -> + receive + {inet_reply,S,Status,Mref} -> + demonitor(Mref, [flush]), + Status; + {'DOWN',Mref,_,_,_Reason} -> + ?DBG_FORMAT( + "prim_inet:send_recv_reply(~p, _) 'DOWN' ~p~n", + [S,_Reason]), + {error,closed} + end + catch error: _ -> ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []), {error,einval} end. -send_recv_reply(S, Mref) -> - ReplyTimeout = - case Mref of - undefined -> - ?INET_CLOSE_TIMEOUT; - _ -> - infinity - end, - receive - {inet_reply,S,Status} -> - ?DBG_FORMAT( - "prim_inet:send_recv_reply(~p, _): inet_reply ~p~n", - [S,Status]), - case Mref of - undefined -> ok; - _ -> - demonitor(Mref, [flush]), - ok - end, - Status; - {'DOWN',Mref,_,_,_Reason} when Mref =/= undefined -> - ?DBG_FORMAT( - "prim_inet:send_recv_reply(~p, _) 'DOWN' ~p~n", - [S,_Reason]), - {error,closed} - after ReplyTimeout -> - send_recv_reply(S, monitor(port, S)) - end. - - send(S, Data) -> send(S, Data, []). @@ -610,10 +630,19 @@ do_sendto(S, Address, AncOpts, Data) -> [enc_value(set, addr, Address), enc_value(set, uint32, AncDataLen), AncData, Data], - try erlang:port_command(S, PortCommandData) of + Ref = make_ref(), + RefBin = term_to_binary(Ref, [local]), + RefBinSize = byte_size(RefBin), + RefBinSize = RefBinSize band 16#FFFF, + try + erlang:port_command( + S, + [<>, + PortCommandData]) + of true -> receive - {inet_reply,S,Reply} -> + {inet_reply,S,Reply,Ref} -> ?DBG_FORMAT( "prim_inet:sendto() -> ~p~n", [Reply]), Reply @@ -634,7 +663,6 @@ do_sendto(S, Address, AncOpts, Data) -> "prim_inet:sendto() -> {error,einval}~n", []), {error,einval} end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -1478,6 +1506,9 @@ is_sockopt_val(Opt, Val) -> %% Socket options processing: Encoding option NAMES: %% enc_opt(reuseaddr) -> ?INET_OPT_REUSEADDR; +enc_opt(reuseport) -> ?INET_OPT_REUSEPORT; +enc_opt(reuseport_lb) -> ?INET_OPT_REUSEPORT_LB; +enc_opt(exclusiveaddruse) -> ?INET_OPT_EXCLUSIVEADDRUSE; enc_opt(keepalive) -> ?INET_OPT_KEEPALIVE; enc_opt(dontroute) -> ?INET_OPT_DONTROUTE; enc_opt(linger) -> ?INET_OPT_LINGER; @@ -1521,6 +1552,7 @@ enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM; enc_opt(raw) -> ?INET_OPT_RAW; enc_opt(bind_to_device) -> ?INET_OPT_BIND_TO_DEVICE; +enc_opt(debug) -> ?INET_OPT_DEBUG; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; enc_opt(sctp_associnfo) -> ?SCTP_OPT_ASSOCINFO; @@ -1545,6 +1577,9 @@ enc_opt(sctp_get_peer_addr_info) -> ?SCTP_OPT_GET_PEER_ADDR_INFO. %% Decoding option NAMES: %% dec_opt(?INET_OPT_REUSEADDR) -> reuseaddr; +dec_opt(?INET_OPT_REUSEPORT) -> reuseport; +dec_opt(?INET_OPT_REUSEPORT_LB) -> reuseport_lb; +dec_opt(?INET_OPT_EXCLUSIVEADDRUSE) -> exclusiveaddruse; dec_opt(?INET_OPT_KEEPALIVE) -> keepalive; dec_opt(?INET_OPT_DONTROUTE) -> dontroute; dec_opt(?INET_OPT_LINGER) -> linger; @@ -1588,6 +1623,7 @@ dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(?INET_OPT_BIND_TO_DEVICE) -> bind_to_device; +dec_opt(?INET_OPT_DEBUG) -> debug; dec_opt(I) when is_integer(I) -> undefined. @@ -1605,7 +1641,7 @@ dec_opt(I) when is_integer(I) -> undefined. %% The use of [] and [[Type,Default]] is commented out in enc_value/2 %% and type_value/2 below since they are only used in record fields. %% And record fields does not call enc_value/2 nor type_value/2. -%% Anyone introducing these metatypes otherwhere will have to activate +%% Anyone introducing these metatypes elsewhere will have to activate %% those clauses in enc_value/2 and type_value/2. You have been warned! type_opt(get, raw) -> [{[int],[int],[binary_or_uint]}]; @@ -1627,6 +1663,9 @@ type_opt(_, Opt) -> %% Types of option values, by option name: %% type_opt_1(reuseaddr) -> bool; +type_opt_1(reuseport) -> bool; +type_opt_1(reuseport_lb) -> bool; +type_opt_1(exclusiveaddruse) -> bool; type_opt_1(keepalive) -> bool; type_opt_1(dontroute) -> bool; type_opt_1(linger) -> {bool,int}; @@ -1647,9 +1686,9 @@ type_opt_1(ipv6_v6only) -> bool; %% multicast type_opt_1(multicast_ttl) -> int; type_opt_1(multicast_loop) -> bool; -type_opt_1(multicast_if) -> ip; -type_opt_1(add_membership) -> {ip,ip}; -type_opt_1(drop_membership) -> {ip,ip}; +type_opt_1(multicast_if) -> mif; +type_opt_1(add_membership) -> membership; +type_opt_1(drop_membership) -> membership; %% driver options type_opt_1(header) -> uint; type_opt_1(buffer) -> int; @@ -1696,6 +1735,7 @@ type_opt_1(read_packets) -> uint; type_opt_1(netns) -> binary; type_opt_1(show_econnreset) -> bool; type_opt_1(bind_to_device) -> binary; +type_opt_1(debug) -> bool; %% %% SCTP options (to be set). If the type is a record type, the corresponding %% record signature is returned, otherwise, an "elementary" type tag @@ -1883,7 +1923,23 @@ type_value_2(uint16, X) when X band 16#ffff =:= X -> true; type_value_2(uint8, X) when X band 16#ff =:= X -> true; type_value_2(time, infinity) -> true; type_value_2(time, X) when is_integer(X), X >= 0 -> true; -type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true; +%% type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true; +type_value_2(mif,{A,B,C,D}) when ?ip(A,B,C,D) -> true; +type_value_2(mif,Idx) when is_integer(Idx) -> true; +type_value_2(membership,{{A1,B1,C1,D1}, {A2,B2,C2,D2}}) + when ?ip(A1,B1,C1,D1) andalso ?ip(A2,B2,C2,D2) -> true; +type_value_2(membership,{{A1,B1,C1,D1}, any}) + when ?ip(A1,B1,C1,D1) -> true; +type_value_2(membership,{{A1,B1,C1,D1}, {A2,B2,C2,D2}, Idx}) + when ?ip(A1,B1,C1,D1) andalso + ?ip(A2,B2,C2,D2) andalso + is_integer(Idx) -> true; +type_value_2(membership,{{A1,B1,C1,D1}, any, Idx}) + when ?ip(A1,B1,C1,D1) andalso + is_integer(Idx) -> true; +type_value_2(membership,{{A,B,C,D,E,F,G,H}, Idx}) + when ?ip6(A,B,C,D,E,F,G,H) andalso + is_integer(Idx) -> true; %% type_value_2(addr, {any,Port}) -> type_value_2(uint16, Port); @@ -1907,15 +1963,19 @@ type_value_2(addr, {inet6,{{A,B,C,D,E,F,G,H},Port}}) when ?ip6(A,B,C,D,E,F,G,H) -> type_value_2(uint16, Port); type_value_2(addr, #{family := inet, - addr := {A,B,C,D}, - port := Port}) - when ?ip(A,B,C,D) -> - type_value_2(uint16, Port); + addr := Addr, + port := Port}) -> + (Addr =:= any orelse + Addr =:= loopback orelse + ?ip(Addr)) + andalso type_value_2(uint16, Port); type_value_2(addr, #{family := inet6, - addr := {A,B,C,D,E,F,G,H}, - port := Port}) - when ?ip6(A,B,C,D,E,F,G,H) -> - type_value_2(uint16, Port); + addr := Addr, + port := Port}) -> + (Addr =:= any orelse + Addr =:= loopback orelse + ?ip6(Addr)) + andalso type_value_2(uint16, Port); type_value_2(addr, {local,Addr}) -> if is_binary(Addr) -> @@ -1936,6 +1996,16 @@ type_value_2(addr, {local,Addr}) -> false end end; +type_value_2(addr_list, [_|_]=SockAddrs) + when length(SockAddrs) =< 255 -> + lists:all(fun(SockAddr) -> type_value_2(addr, SockAddr) end, SockAddrs); +type_value_2(addr_list, {[_|_] = IPs, Port}) + when length(IPs) =< 255 -> + lists:all(fun({A,B,C,D}) when ?ip(A,B,C,D) -> true; + ({A,B,C,D,E,F,G,H}) when ?ip6(A,B,C,D,E,F,G,H) -> true; + (_) -> false + end, IPs) + andalso type_value_2(uint16, Port); %% type_value_2(ether,[X1,X2,X3,X4,X5,X6]) when ?ether(X1,X2,X3,X4,X5,X6) -> true; @@ -2029,21 +2099,58 @@ enc_value_tuple(_, _, _, _) -> []. %% %% Encoding of option VALUES: %% -enc_value_2(bool, true) -> [0,0,0,1]; -enc_value_2(bool, false) -> [0,0,0,0]; -enc_value_2(bool8, true) -> [1]; -enc_value_2(bool8, false) -> [0]; -enc_value_2(int, Val) -> ?int32(Val); -enc_value_2(uint, Val) -> ?int32(Val); -enc_value_2(uint32, Val) -> ?int32(Val); -enc_value_2(uint24, Val) -> ?int24(Val); -enc_value_2(uint16, Val) -> ?int16(Val); -enc_value_2(uint8, Val) -> ?int8(Val); -enc_value_2(time, infinity) -> ?int32(-1); -enc_value_2(time, Val) -> ?int32(Val); -enc_value_2(ip,{A,B,C,D}) -> [A,B,C,D]; -enc_value_2(ip, any) -> [0,0,0,0]; -enc_value_2(ip, loopback) -> [127,0,0,1]; +enc_value_2(bool, true) -> [0,0,0,1]; +enc_value_2(bool, false) -> [0,0,0,0]; +enc_value_2(bool8, true) -> [1]; +enc_value_2(bool8, false) -> [0]; +enc_value_2(int, Val) -> ?int32(Val); +enc_value_2(uint, Val) -> ?int32(Val); +enc_value_2(uint32, Val) -> ?int32(Val); +enc_value_2(uint24, Val) -> ?int24(Val); +enc_value_2(uint16, Val) -> ?int16(Val); +enc_value_2(uint8, Val) -> ?int8(Val); +enc_value_2(time, infinity) -> ?int32(-1); +enc_value_2(time, Val) -> ?int32(Val); +%% enc_value_2(ip, IP) +%% when (tuple_size(IP) =:= 4) -> ip4_to_bytes(IP); +%% enc_value_2(ip, any) -> ip4_any(); +%% enc_value_2(ip, loopback) -> ip4_loopback(); +enc_value_2(mif, IP) + when (tuple_size(IP) =:= 4) -> ip4_to_bytes(IP); +enc_value_2(mif, Idx) + when is_integer(Idx) -> ?int32(Idx); +enc_value_2(membership, {IP1, IP2}) + when (tuple_size(IP1) =:= 4) andalso + (tuple_size(IP2) =:= 4) -> + enc_value_2(membership, {IP1, IP2, 0}); +enc_value_2(membership, {IP1, IP2}) + when (tuple_size(IP1) =:= 4) andalso + (IP2 =:= any) -> + enc_value_2(membership, {IP1, IP2, 0}); +%% enc_value_2(membership, {IP1, any = _IP2}) +%% when (tuple_size(IP1) =:= 4) -> +%% [?INET_AF_INET, ?int32(0), ip4_to_bytes(IP1), ip4_any()]; +enc_value_2(membership, {IP1, IP2, Idx}) + when (tuple_size(IP1) =:= 4) andalso + (tuple_size(IP2) =:= 4) andalso + is_integer(Idx) -> + %% The reason for turning this thing around (the interface + %% before the two address'es) so that we as much as possible + %% "look like" IPv6...se below + [?int32(?INET_AF_INET), ?int32(Idx), ip4_to_bytes(IP1), ip4_to_bytes(IP2)]; +enc_value_2(membership, {IP1, any = _IP2, Idx}) + when (tuple_size(IP1) =:= 4) andalso + is_integer(Idx) -> + [?int32(?INET_AF_INET), ?int32(Idx), ip4_to_bytes(IP1), ip4_any()]; +enc_value_2(membership, {IP, Idx}) + when (tuple_size(IP) =:= 8) andalso + is_integer(Idx) -> + %% The reason for turning this thing around (the interface + %% before the address) is because of the inet-driver (it reads out a + %% 32-bit value for *all* options, so we might as well put a 32-bit + %% value "first". + [?int32(?INET_AF_INET6), ?int32(Idx), ip6_to_bytes(IP)]; + %% enc_value_2(addr, {any,Port}) -> [?INET_AF_ANY|?int16(Port)]; @@ -2055,27 +2162,19 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6,?int16(Port),ip6_to_bytes(IP),?int32(0),?int32(0)]; enc_value_2(addr, #{family := inet, addr := IP, - port := Port}) when (tuple_size(IP) =:= 4) -> + port := Port}) -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; enc_value_2(addr, #{family := inet6, addr := IP, port := Port, flowinfo := FlowInfo, - scope_id := ScopeID}) when (tuple_size(IP) =:= 8) -> + scope_id := ScopeID}) -> [?INET_AF_INET6,?int16(Port),ip6_to_bytes(IP),?int32(FlowInfo),?int32(ScopeID)]; enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) -> [?INET_AF_LOCAL,iolist_size(File)|File]; %% -enc_value_2(addr, {inet,{any,Port}}) -> - [?INET_AF_INET,?int16(Port)|ip4_to_bytes({0,0,0,0})]; -enc_value_2(addr, {inet,{loopback,Port}}) -> - [?INET_AF_INET,?int16(Port)|ip4_to_bytes({127,0,0,1})]; enc_value_2(addr, {inet,{IP,Port}}) -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; -enc_value_2(addr, {inet6,{any,Port}}) -> - [?INET_AF_INET6,?int16(Port),ip6_to_bytes({0,0,0,0,0,0,0,0}),?int32(0),?int32(0)]; -enc_value_2(addr, {inet6,{loopback,Port}}) -> - [?INET_AF_INET6,?int16(Port),ip6_to_bytes({0,0,0,0,0,0,0,1}),?int32(0),?int32(0)]; enc_value_2(addr, {inet6,{IP,Port}}) -> [?INET_AF_INET6,?int16(Port),ip6_to_bytes(IP),?int32(0),?int32(0)]; enc_value_2(addr, {local,Addr}) -> @@ -2091,6 +2190,12 @@ enc_value_2(addr, {local,Addr}) -> Addr, file:native_name_encoding()) end, [?INET_AF_LOCAL,byte_size(Bin),Bin]; +enc_value_2(addr_list, {IPs, Port}) -> + [?INET_AF_LIST, length(IPs) | + [enc_value_2(addr, {IP, Port}) || IP <- IPs]]; +enc_value_2(addr_list, SockAddrs) -> + [?INET_AF_LIST, length(SockAddrs) | + [enc_value_2(addr, SockAddr) || SockAddr <- SockAddrs]]; %% enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs; enc_value_2(sockaddr, any) -> @@ -2125,7 +2230,7 @@ enc_value_2(binary_or_uint,Datum) when is_integer(Datum) -> %% -%% Decoding of option VALUES receved from "getopt": +%% Decoding of option VALUES received from "getopt": %% NOT required for SCTP, as it always returns ready terms, not lists: %% dec_value(bool, [0,0,0,0|T]) -> {false,T}; @@ -2145,7 +2250,15 @@ dec_value(time, [X3,X2,X1,X0|T]) -> -1 -> {infinity, T}; Val -> {Val, T} end; -dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T}; +%% dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T}; +dec_value(mif, [A,B,C,D, X3,X2,X1,X0|T]) -> + Domain = ?i32(X3, X2, X1, X0), + case Domain of + ?INET_AF_INET -> + {{A,B,C,D}, T}; + ?INET_AF_INET6 -> + {?i32(A,B,C,D), T} + end; %% dec_value(ether, [X1,X2,X3,X4,X5,X6|T]) -> {[X1,X2,X3,X4,X5,X6],T}; dec_value(sockaddr, [X|T]) -> get_ip(X, T); @@ -2451,7 +2564,8 @@ decode_ifopts([B | Buf], Acc) -> undefined -> {error, einval}; Opt -> - {Val,T} = dec_value(type_ifopt(Opt), Buf), + OptType = type_ifopt(Opt), + {Val,T} = dec_value(OptType, Buf), decode_ifopts(T, [{Opt,Val} | Acc]) end; decode_ifopts(_,Acc) -> {ok,Acc}. @@ -2518,7 +2632,7 @@ dec_subs([]) -> []. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -%% handle statictics options +%% handle statistics options %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2658,7 +2772,7 @@ rev([C|L],Acc) -> rev(L,[C|Acc]); rev([],Acc) -> Acc. split(N, L) -> split(N, L, []). -split(0, L, R) when is_list(L) -> {rev(R),L}; +split(0, L, R) when is_list(L); is_binary(L) -> {rev(R),L}; split(N, [H|T], R) when is_integer(N), N > 0 -> split(N-1, T, [H|R]). len(L, N) -> len(L, N, 0). @@ -2731,13 +2845,38 @@ utf8_to_characters(Bs, U, 0) -> utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B -> utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1). +ip4_to_bytes(any) -> + ip4_any(); +ip4_to_bytes(loopback) -> + ip4_loopback(); ip4_to_bytes({A,B,C,D}) -> [A band 16#ff, B band 16#ff, C band 16#ff, D band 16#ff]. +ip4_any() -> [0,0,0,0]. +ip4_loopback() -> [127,0,0,1]. + + +ip6_to_bytes(any) -> + ip6_any(); +ip6_to_bytes(loopback) -> + ip6_loopback(); ip6_to_bytes({A,B,C,D,E,F,G,H}) -> [?int16(A), ?int16(B), ?int16(C), ?int16(D), ?int16(E), ?int16(F), ?int16(G), ?int16(H)]. +ip6_any() -> + Z1 = ?int16(0), + Z2 = [Z1, Z1], + Z3 = [Z2, Z2], + [Z3, Z3]. + +ip6_loopback() -> + Z1 = ?int16(0), + Z2 = [Z1, Z1], + Z3 = [Z2, Z2], + [Z3, Z2, Z1, ?int16(1)]. + + get_addrs([]) -> []; get_addrs([F|Addrs]) -> diff --git a/erts/preloaded/src/prim_net.erl b/erts/preloaded/src/prim_net.erl index abe77d4ec7f0..d70201d12902 100644 --- a/erts/preloaded/src/prim_net.erl +++ b/erts/preloaded/src/prim_net.erl @@ -34,6 +34,10 @@ getnameinfo/2, getaddrinfo/2, getifaddrs/1, + get_adapters_addresses/1, + get_if_entry/1, + get_interface_info/1, + get_ip_address_table/1, if_name2index/1, if_index2name/1, @@ -41,37 +45,236 @@ ]). -export_type([ - address_info/0, - ifaddrs/0, - name_info/0, - - ifaddrs_flag/0, - ifaddrs_flags/0, - - name_info_flag/0, - name_info_flag_ext/0, - name_info_flags/0, - - network_interface_name/0, - network_interface_index/0 + getifaddrs_args/0, + interface_info_args/0, + if_entry_args/0, + ip_address_table_args/0, + + if_type/0, + if_admin_status/0, + internal_if_oper_status/0, + mib_if_row/0, + + ip_adapter_index_map/0, + ip_interface_info/0, + + mib_ip_address_row/0, + mib_ip_address_table/0, + + adapters_addresses_flags/0, + adapters_addresses_args/0, + adapter_unicast_dad_state/0, + adapter_unicast_prefix_origin/0, + adapter_unicast_suffix_origin/0, + adapter_unicast_flags/0, + adapter_unicast_addr/0, + adapter_anycast_flags/0, + adapter_anycast_addr/0, + adapter_multicast_flags/0, + adapter_multicast_addr/0, + adapter_dns_server_addr/0, + adapter_flags/0, + adapter_type/0, + adapter_oper_status/0, + adapter_prefix/0, + adapter_addresses/0, + adapters_addresses/0 ]). +-type getifaddrs_args() :: #{netns => string()}. + -type ifaddrs_flag() :: up | broadcast | debug | loopback | pointopoint | - notrailers | running | noarp | promisc | master | slave | + notrailers | running | noarp | promisc | + master | slave | multicast | portsel | automedia | dynamic. -type ifaddrs_flags() :: [ifaddrs_flag()]. %% Note that not all of these fields are mandatory. -%% Actually there are (error) cases when only the name will be included. -%% And broadaddr and dstaddr are mutually exclusive! +%% *Also*, broadaddr and dstaddr are mutually exclusive! -type ifaddrs() :: #{name := string(), flags := ifaddrs_flags(), - addr := socket:sockaddr(), - netmask := socket:sockaddr(), - broadaddr := socket:sockaddr(), - dstaddr := socket:sockaddr()}. + addr => socket:sockaddr(), + netmask => socket:sockaddr(), + %% 'broadaddr' and 'dstaddr' are mutually exclusive + broadaddr => socket:sockaddr(), + dstaddr => socket:sockaddr()}. + +-type interface_info_args() :: #{debug => boolean()}. +-type if_entry_args() :: #{index := non_neg_integer(), + debug => boolean()}. +-type ip_address_table_args() :: #{debug => boolean()}. + +-type if_type() :: other | ethernet_csmacd | iso88025_tokenring | + fddi | ppp | software_loopback | atm | ieee80211 | + tunnel | ieee1394 | ieee80216_wman | wwanpp | wwanpp2. +-type if_admin_status() :: non_operational | + unreachable | + disconnected | + connecting | connected | + operational | + non_neg_integer(). +-type internal_if_oper_status() :: non_operational | + unreachable | + disconnected | + connecting | connected | + operational | + non_neg_integer(). +-type mib_if_row() :: #{name := string(), + index := non_neg_integer(), + type := if_type(), + mtu := non_neg_integer(), + speed := non_neg_integer(), + phys_addr := binary(), + admin_status := if_admin_status(), + internal_oper_status := internal_if_oper_status(), + last_change := non_neg_integer(), + in_octets := non_neg_integer(), + in_ucast_pkts := non_neg_integer(), + in_nucast_pkts := non_neg_integer(), + in_discards := non_neg_integer(), + in_errors := non_neg_integer(), + in_unknown_protos := non_neg_integer(), + out_octets := non_neg_integer(), + out_ucast_pkts := non_neg_integer(), + out_nucast_pkts := non_neg_integer(), + out_discards := non_neg_integer(), + out_errors := non_neg_integer(), + out_qlen := non_neg_integer(), + description := binary()}. + +-type ip_adapter_index_map() :: #{index := integer(), + name := string()}. + +-type ip_interface_info() :: [ip_adapter_index_map()]. + +%% addr: The IPv4 address in network byte order. +%% index: The index of the interface associated with this +%% IPv4 address. +%% mask: The subnet mask for the IPv4 address in network +%% byte order. +%% broadcast_addr: The broadcast address in network byte order. +%% A broadcast address is typically the IPv4 address +%% with the host portion set to either all zeros or +%% all ones. +%% reasm_size: The maximum re-assembly size for received datagrams. +-type mib_ip_address_row() :: #{addr := non_neg_integer(), + index := non_neg_integer(), + mask := non_neg_integer(), + broadcast_addr := non_neg_integer(), + reasm_size := non_neg_integer()}. +-type mib_ip_address_table() :: [mib_ip_address_row()]. + +-type adapters_addresses_flags() :: + #{skip_unicast => boolean(), % default false + skip_anycast => boolean(), % default true + skip_multicast => boolean(), % default true + skip_dns_server => boolean(), % default true + skip_friendly_name => boolean(), % default true + include_prefix => boolean(), % default true + include_wins_info => boolean(), % default false + include_gateways => boolean(), % default false + include_all_interfaces => boolean(), % default false + include_all_compartments => boolean(), % default false + include_tunnel_bindingorder => boolean()}. % default false) + +%% defaults to: +%% #{family => unspec, +%% flags => #{skip_unicast => false +%% skip_anycast => true +%% skip_multicast => true +%% skip_dns_server => true +%% skip_friendly_name => true +%% include_prefix => true +%% include_wins_info => false +%% include_gateways => false +%% include_all_interfaces => false +%% include_all_compartments => false +%% include_tunnel_bindingorder => false}, +%% debug => false}. +-type adapters_addresses_args() :: #{family => unspec | inet | inet6, + flags => adapters_addresses_flags(), + debug => boolean()}. + +-type adapter_unicast_dad_state() :: invalid | tentative | duplicate | + deprecated | preferred | + integer(). +-type adapter_unicast_prefix_origin() :: other | manual | well_known | dhcp | + router_advertisement | unchanged | + integer(). +-type adapter_unicast_suffix_origin() :: other | manual | well_known | dhcp | + link_layer_address | random | + unchanged | + integer(). +-type adapter_unicast_flags() :: #{dns_eligible := boolean(), + transient := boolean()}. + +-type adapter_unicast_addr() :: + #{addr := socket:sockaddr(), + dad_state := adapter_unicast_dad_state(), + flags := adapter_unicast_flags(), + prefix_origin := adapter_unicast_prefix_origin(), + suffix_origin := adapter_unicast_suffix_origin(), + lease_lifetime := non_neg_integer(), + preferred_lifetime := non_neg_integer(), + valid_lifetime := non_neg_integer()}. + +-type adapter_anycast_flags() :: #{dns_eligible := boolean(), + transient := boolean()}. + +-type adapter_anycast_addr() :: #{addr := socket:sockaddr(), + flags := adapter_anycast_flags()}. + +-type adapter_multicast_flags() :: #{dns_eligible := boolean(), + transient := boolean()}. + +-type adapter_multicast_addr() :: #{addr := socket:sockaddr(), + flags := adapter_multicast_flags()}. + +-type adapter_dns_server_addr() :: #{addr := socket:sockaddr()}. + +-type adapter_flags() :: #{ddns_enabled := boolean(), + register_adapter_suffix := boolean(), + dhcp_v4_enabled := boolean(), + receive_only := boolean(), + no_multicast := boolean(), + ipv6_other_stateful_config := boolean(), + netbios_over_tcpip_enabled := boolean(), + ipv4_enabled := boolean(), + ipv6_enabled := boolean(), + ipv6_managed_address_config_supported := boolean()}. + +-type adapter_type() :: other | ethernet_csmacd | iso88025_tokenring | + fddi | ppp | software_loopback | atm | ieee80211 | + tunnel | ieee1394 | ieee80216_wman | wwanpp | wwanpp2 | + integer(). + +-type adapter_oper_status() :: up | down | testing | dormant | not_present | + lower_layer_down | + integer(). + +-type adapter_prefix() :: #{addr := socket:sockaddr(), + length := non_neg_integer()}. +-type adapter_addresses() :: + #{index := non_neg_integer(), + name := string(), + unicast_addrs := [adapter_unicast_addr()], + anycast_addrs := [adapter_anycast_addr()], + multicast_addrs := [adapter_multicast_addr()], + dns_server_addrs := [adapter_dns_server_addr()], + dns_suffix := string(), + description := string(), + friendly_name := string(), + phys_addr := binary(), + flags := adapter_flags(), + mtu := non_neg_integer(), + type := adapter_type(), + oper_status := adapter_oper_status(), + zone_indices := [non_neg_integer()], % Length 16 + ipv6_index := non_neg_integer(), + prefixes := [adapter_prefix()]}. +-type adapters_addresses() :: [adapter_addresses()]. -type name_info_flag() :: namereqd | dgram | @@ -93,6 +296,56 @@ -type network_interface_index() :: non_neg_integer(). +-define(NO_SKIPS_ALL_INCLUDES, + #{skip_unicast => false, + skip_anycast => false, + skip_multicast => false, + skip_dns_server => false, + skip_friendly_name => false, + include_prefix => true, + include_wins_info => true, + include_gateways => true, + include_all_interfaces => true, + include_all_compartments => true, + include_tunnel_bindingorder => true}). +-define(ALL_SKIPS_NO_INCLUDES, + #{skip_unicast => true, + skip_anycast => true, + skip_multicast => true, + skip_dns_server => true, + skip_friendly_name => true, + include_prefix => false, + include_wins_info => false, + include_gateways => false, + include_all_interfaces => false, + include_all_compartments => false, + include_tunnel_bindingorder => false}). +-define(NO_SKIPS_NO_INCLUDES, + #{skip_unicast => false, + skip_anycast => false, + skip_multicast => false, + skip_dns_server => false, + skip_friendly_name => false, + include_prefix => false, + include_wins_info => false, + include_gateways => false, + include_all_interfaces => false, + include_all_compartments => false, + include_tunnel_bindingorder => false}). +-define(ALL_SKIPS_ALL_INCLUDES, + #{skip_unicast => true, + skip_anycast => true, + skip_multicast => true, + skip_dns_server => true, + skip_friendly_name => true, + include_prefix => true, + include_wins_info => true, + include_gateways => true, + include_all_interfaces => true, + include_all_compartments => true, + include_tunnel_bindingorder => true}). + + %% =========================================================================== %% %% Administrative and utility API @@ -109,10 +362,13 @@ on_load() -> Extra :: map(). on_load(Extra) -> - ok = erlang:load_nif(atom_to_list(net), Extra). + %% This will fail if the user has disabled esock support, making all NIFs + %% fall back to their Erlang implementation which throws `notsup`. + _ = erlang:load_nif(atom_to_list(net), Extra), + ok. --spec info() -> list(). +-spec info() -> map(). info() -> nif_info(). @@ -230,6 +486,84 @@ getifaddrs(Extra) when is_map(Extra) -> +%% =========================================================================== +%% +%% get_adapters_addresses - Get adapters addresses +%% + +-spec get_adapters_addresses(Args) -> {ok, Addrs} | {error, Reason} when + Args :: default | + no_skips_all_includes | no_skips_no_includes | + all_skips_no_includes | all_skips_all_includes | + adapters_addresses_args(), + Addrs :: adapters_addresses(), + Reason :: term(). + +get_adapters_addresses(default) -> + Args = #{}, + get_adapters_addresses(Args); +get_adapters_addresses(no_skips_all_includes) -> + Args = #{flags => ?NO_SKIPS_ALL_INCLUDES}, + get_adapters_addresses(Args); +get_adapters_addresses(no_skips_no_includes) -> + Args = #{flags => ?NO_SKIPS_NO_INCLUDES}, + get_adapters_addresses(Args); +get_adapters_addresses(all_skips_no_includes) -> + Args = #{flags => ?ALL_SKIPS_NO_INCLUDES}, + get_adapters_addresses(Args); +get_adapters_addresses(all_skips_all_includes) -> + Args = #{flags => ?ALL_SKIPS_ALL_INCLUDES}, + get_adapters_addresses(Args); +get_adapters_addresses(Args) when is_map(Args) -> + nif_get_adapters_addresses(Args). + + + +%% =========================================================================== +%% +%% get_interface_info - Get interface info +%% + +-spec get_interface_info(Args) -> {ok, IfInfo} | {error, Reason} when + Args :: interface_info_args(), + IfInfo :: ip_interface_info(), + Reason :: term(). + +get_interface_info(Args) when is_map(Args) -> + nif_get_interface_info(Args). + + + +%% =========================================================================== +%% +%% get_if_entry - Get interface info +%% + +-spec get_if_entry(Args) -> {ok, Info} | {error, Reason} when + Args :: if_entry_args(), + Info :: mib_if_row(), + Reason :: term(). + +get_if_entry(Args) when is_map(Args) -> + nif_get_if_entry(Args). + + + +%% =========================================================================== +%% +%% get_ip_address_table - Get (mib) address table +%% + +-spec get_ip_address_table(Args) -> {ok, Info} | {error, Reason} when + Args :: ip_address_table_args(), + Info :: term(), + Reason :: term(). + +get_ip_address_table(Args) when is_map(Args) -> + nif_get_ip_address_table(Args). + + + %% =========================================================================== %% %% if_name2index - Mappings between network interface names and indexes: @@ -320,29 +654,41 @@ if_names() -> %% =========================================================================== nif_info() -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_command(_Cmd) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_gethostname() -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_getnameinfo(_Addr, _Flags) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_getaddrinfo(_Host, _Service, _Hints) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_getifaddrs(_Extra) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). + +nif_get_adapters_addresses(_Args) -> + erlang:nif_error(notsup). + +nif_get_if_entry(_Args) -> + erlang:nif_error(notsup). + +nif_get_interface_info(_Args) -> + erlang:nif_error(notsup). + +nif_get_ip_address_table(_Args) -> + erlang:nif_error(notsup). nif_if_name2index(_Name) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_if_index2name(_Id) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_if_names() -> - erlang:nif_error(undef). + erlang:nif_error(notsup). diff --git a/erts/preloaded/src/prim_socket.erl b/erts/preloaded/src/prim_socket.erl index ec92aeb4bf94..8da47bba82ee 100644 --- a/erts/preloaded/src/prim_socket.erl +++ b/erts/preloaded/src/prim_socket.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2021. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -49,6 +49,14 @@ -export([enc_sockaddr/1, p_get/1]). +-nifs([nif_info/0, nif_info/1, nif_supports/0, nif_supports/1, nif_command/1, + nif_open/2, nif_open/4, nif_bind/2, nif_connect/1, nif_connect/3, + nif_listen/2, nif_accept/2, nif_send/4, nif_sendto/5, nif_sendmsg/5, + nif_sendfile/5, nif_sendfile/4, nif_sendfile/1, nif_recv/4, + nif_recvfrom/4, nif_recvmsg/5, nif_close/1, nif_shutdown/2, + nif_setopt/5, nif_getopt/3, nif_getopt/4, nif_sockname/1, + nif_peername/1, nif_ioctl/2, nif_ioctl/3, nif_ioctl/4, nif_cancel/3, + nif_finalize_close/1]). %% Also in socket -define(REGISTRY, socket_registry). @@ -145,8 +153,9 @@ on_load(Extra) when is_map(Extra) -> socket_debug => true, debug_filename => enc_path(DebugFilename)} end, - ok = erlang:load_nif(atom_to_list(?MODULE), Extra_2), - %% + %% This will fail if the user has disabled esock support, making all NIFs + %% fall back to their Erlang implementation which throws `notsup`. + _ = erlang:load_nif(atom_to_list(?MODULE), Extra_2), init(). init() -> @@ -503,6 +512,10 @@ send(SockRef, Bin, EFlags, SendRef) when is_integer(EFlags) -> {select, Written} -> <<_:Written/binary, RestBin/binary>> = Bin, {select, RestBin, EFlags}; + + completion = C -> + C; + {error, _Reason} = Result -> Result end; @@ -549,11 +562,13 @@ sendto(SockRef, Bin, To, Flags, SendRef) -> sockaddr -> {error, {invalid, {Cause, To}}} end; + ok -> ok; {ok, Written} -> <<_:Written/binary, RestBin/binary>> = Bin, {ok, RestBin}; + select -> Cont = {To, ETo, EFlags}, {select, Cont}; @@ -561,6 +576,10 @@ sendto(SockRef, Bin, To, Flags, SendRef) -> <<_:Written/binary, RestBin/binary>> = Bin, Cont = {To, ETo, EFlags}, {select, RestBin, Cont}; + + completion = C-> + C; + {error, _Reason} = Result -> Result end @@ -612,6 +631,7 @@ sendmsg_result( sendmsg_result( SockRef, RestIOV, Cont, SendRef, true, nif_sendmsg(SockRef, EMsg, EFlags, SendRef, RestIOV)); + select -> if HasWritten -> @@ -622,6 +642,11 @@ sendmsg_result( {select, Written} -> RestIOV = rest_iov(Written, IOV), {select, RestIOV, Cont}; + + %% Either the message was written or not. No half ways... + completion = C -> + C; + {error, Reason} = Error-> if HasWritten -> @@ -1128,58 +1153,58 @@ p_get(Name) -> %% NIF functions %% -nif_info() -> erlang:nif_error(undef). -nif_info(_SockRef) -> erlang:nif_error(undef). +nif_info() -> erlang:nif_error(notsup). +nif_info(_SockRef) -> erlang:nif_error(notsup). -nif_command(_Command) -> erlang:nif_error(undef). +nif_command(_Command) -> erlang:nif_error(notsup). -nif_supports() -> erlang:nif_error(undef). -nif_supports(_Key) -> erlang:nif_error(undef). +nif_supports() -> erlang:nif_error(notsup). +nif_supports(_Key) -> erlang:nif_error(notsup). -nif_open(_FD, _Opts) -> erlang:nif_error(undef). -nif_open(_Domain, _Type, _Protocol, _Opts) -> erlang:nif_error(undef). +nif_open(_FD, _Opts) -> erlang:nif_error(notsup). +nif_open(_Domain, _Type, _Protocol, _Opts) -> erlang:nif_error(notsup). -nif_bind(_SockRef, _SockAddr) -> erlang:nif_error(undef). -nif_bind(_SockRef, _SockAddrs, _Action) -> erlang:nif_error(undef). +nif_bind(_SockRef, _SockAddr) -> erlang:nif_error(notsup). +nif_bind(_SockRef, _SockAddrs, _Action) -> erlang:nif_error(notsup). -nif_connect(_SockRef) -> erlang:nif_error(undef). -nif_connect(_SockRef, _ConnectRef, _SockAddr) -> erlang:nif_error(undef). +nif_connect(_SockRef) -> erlang:nif_error(notsup). +nif_connect(_SockRef, _ConnectRef, _SockAddr) -> erlang:nif_error(notsup). -nif_listen(_SockRef, _Backlog) -> erlang:nif_error(undef). +nif_listen(_SockRef, _Backlog) -> erlang:nif_error(notsup). -nif_accept(_SockRef, _Ref) -> erlang:nif_error(undef). +nif_accept(_SockRef, _Ref) -> erlang:nif_error(notsup). -nif_send(_SockRef, _Bin, _Flags, _SendRef) -> erlang:nif_error(undef). -nif_sendto(_SockRef, _Bin, _Dest, _Flags, _SendRef) -> erlang:nif_error(undef). -nif_sendmsg(_SockRef, _Msg, _Flags, _SendRef, _IOV) -> erlang:nif_error(undef). +nif_send(_SockRef, _Bin, _Flags, _SendRef) -> erlang:nif_error(notsup). +nif_sendto(_SockRef, _Bin, _Dest, _Flags, _SendRef) -> erlang:nif_error(notsup). +nif_sendmsg(_SockRef, _Msg, _Flags, _SendRef, _IOV) -> erlang:nif_error(notsup). nif_sendfile(_SockRef, _SendRef, _Offset, _Count, _InFileRef) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). nif_sendfile(_SockRef, _SendRef, _Offset, _Count) -> - erlang:nif_error(undef). -nif_sendfile(_SockRef) -> erlang:nif_error(undef). + erlang:nif_error(notsup). +nif_sendfile(_SockRef) -> erlang:nif_error(notsup). -nif_recv(_SockRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(undef). -nif_recvfrom(_SockRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(undef). +nif_recv(_SockRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(notsup). +nif_recvfrom(_SockRef, _Length, _Flags, _RecvRef) -> erlang:nif_error(notsup). nif_recvmsg(_SockRef, _BufSz, _CtrlSz, _Flags, _RecvRef) -> - erlang:nif_error(undef). + erlang:nif_error(notsup). -nif_close(_SockRef) -> erlang:nif_error(undef). -nif_finalize_close(_SockRef) -> erlang:nif_error(undef). -nif_shutdown(_SockRef, _How) -> erlang:nif_error(undef). +nif_close(_SockRef) -> erlang:nif_error(notsup). +nif_finalize_close(_SockRef) -> erlang:nif_error(notsup). +nif_shutdown(_SockRef, _How) -> erlang:nif_error(notsup). -nif_setopt(_SockRef, _Lev, _Opt, _Val, _NativeVal) -> erlang:nif_error(undef). -nif_getopt(_SockRef, _Lev, _Opt) -> erlang:nif_error(undef). -nif_getopt(_SockRef, _Lev, _Opt, _ValSpec) -> erlang:nif_error(undef). +nif_setopt(_SockRef, _Lev, _Opt, _Val, _NativeVal) -> erlang:nif_error(notsup). +nif_getopt(_SockRef, _Lev, _Opt) -> erlang:nif_error(notsup). +nif_getopt(_SockRef, _Lev, _Opt, _ValSpec) -> erlang:nif_error(notsup). -nif_sockname(_SockRef) -> erlang:nif_error(undef). -nif_peername(_SockRef) -> erlang:nif_error(undef). +nif_sockname(_SockRef) -> erlang:nif_error(notsup). +nif_peername(_SockRef) -> erlang:nif_error(notsup). -nif_ioctl(_SockRef, _GReq) -> erlang:nif_error(undef). -nif_ioctl(_SockRef, _GReq, _Arg) -> erlang:nif_error(undef). -nif_ioctl(_SockRef, _SReq, _Arg1, _Arg2) -> erlang:nif_error(undef). +nif_ioctl(_SockRef, _GReq) -> erlang:nif_error(notsup). +nif_ioctl(_SockRef, _GReq, _Arg) -> erlang:nif_error(notsup). +nif_ioctl(_SockRef, _SReq, _Arg1, _Arg2) -> erlang:nif_error(notsup). -nif_cancel(_SockRef, _Op, _SelectRef) -> erlang:nif_error(undef). +nif_cancel(_SockRef, _Op, _SelectRef) -> erlang:nif_error(notsup). %% =========================================================================== diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index ca5cfec0e3fc..51dbf498a264 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -42,7 +42,7 @@ -define(READ_BLOCK_SIZE, 16*1024). %% for debugging, to turn off catch --define(CATCH, catch). +-define(CATCH(Expr), (catch (Expr))). -record(primzip_file, {name, @@ -203,7 +203,7 @@ get_z_all(?DEFLATED, Compressed, Z, _F) -> ok = zlib:inflateInit(Z, -?MAX_WBITS), Uncompressed = zlib:inflate(Z, Compressed), %%_CRC = zlib:crc32(Z), - ?CATCH zlib:inflateEnd(Z), + _ = ?CATCH(zlib:inflateEnd(Z)), erlang:iolist_to_binary(Uncompressed); % {erlang:iolist_to_binary(Uncompressed), CRC} get_z_all(?STORED, Stored, _Z, _F) -> %%CRC0 = zlib:crc32(Z, <<>>), @@ -350,7 +350,7 @@ prim_file_io({file_info, F}, _) -> {error, E} -> throw(E) end; prim_file_io({open, FN, Opts}, _) -> - case ?CATCH prim_file:open(FN, Opts++[binary]) of + case prim_file:open(FN, Opts++[binary]) of {ok, H} -> H; {error, E} -> diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index d34d99429115..4862547f4a98 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -52,6 +52,14 @@ -export_type([zstream/0, zflush/0, zlevel/0, zwindowbits/0, zmemlevel/0, zstrategy/0]). +-nifs([close_nif/1, open_nif/0, set_controller_nif/2, deflateInit_nif/6, + deflateSetDictionary_nif/2, deflateReset_nif/1, deflateEnd_nif/1, + deflateParams_nif/3, deflate_nif/4, inflateInit_nif/3, + inflateSetDictionary_nif/2, inflateGetDictionary_nif/1, + inflateReset_nif/1, inflateEnd_nif/1, inflate_nif/4, crc32_nif/1, + getStash_nif/1, clearStash_nif/1, setStash_nif/2, getBufSize_nif/1, + setBufSize_nif/2, enqueue_nif/2]). + %% flush argument encoding -define(Z_NO_FLUSH, 0). -define(Z_SYNC_FLUSH, 2). diff --git a/erts/test/Makefile b/erts/test/Makefile index 1fe230adafdc..b44f28f3c866 100644 --- a/erts/test/Makefile +++ b/erts/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2016. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -38,9 +38,13 @@ MODULES= \ run_erl_SUITE \ erlexec_SUITE \ z_SUITE \ - upgrade_SUITE + upgrade_SUITE \ + parallel_messages_SUITE -ERL_FILES= $(MODULES:%=%.erl) +ERTS_MODULES= erts_test_utils + +ERL_FILES= $(MODULES:%=%.erl) \ + $(ERTS_MODULES:%=$(ERL_TOP)/erts/emulator/test/%.erl) TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) @@ -84,6 +88,8 @@ release_tests_spec: opt $(INSTALL_DATA) system.spec system.dynspec system_smoke.spec \ $(ERL_FILES) $(TARGET_FILES) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" + cp "$(ERL_TOP)/otp_versions.table" "$(ERL_TOP)/erts/test/otp_SUITE_data" + cp "$(ERL_TOP)/make/otp_version_tickets" "$(ERL_TOP)/erts/test/otp_SUITE_data" tar cf - *_SUITE_data utils | (cd "$(RELSYSDIR)"; tar xf -) release_docs_spec: diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl index 544d1a8dcb8d..49f9f039453e 100644 --- a/erts/test/erl_print_SUITE.erl +++ b/erts/test/erl_print_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -96,10 +96,18 @@ erlang_display(Config) when is_list(Config) -> MyCre = my_cre(), + {Ser1, Ser2, LPort} = case erlang:system_info(wordsize) of + 4 -> {0, 0, 1 bsl 27}; + 8 -> {42, 1 bsl 30, 1 bsl 40} + end, + %% pids - chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)), + chk_display(mk_pid_xstr({node(), MyCre}, 4711, Ser1)), + chk_display(mk_pid_xstr({node(), MyCre}, 1 bsl 27, Ser2)), chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)), + chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 1 bsl 27, Ser2)), chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)), + chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 1 bsl 27, Ser2)), chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)), chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)), @@ -107,12 +115,18 @@ erlang_display(Config) when is_list(Config) -> %% ports chk_display(mk_port_xstr({node(), MyCre}, 4711)), + chk_display(mk_port_xstr({node(), MyCre}, LPort)), chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)), + chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, LPort)), chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)), + chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, LPort)), chk_display(mk_port_xstr({c@d, MyCre}, 4711)), + chk_display(mk_port_xstr({c@d, MyCre}, LPort)), chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)), + chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, LPort)), chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)), + chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, LPort)), %% refs chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])), @@ -123,7 +137,7 @@ erlang_display(Config) when is_list(Config) -> chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])), chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])), - %% Compund terms + %% Compound terms {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41), {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712), {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]), @@ -160,8 +174,8 @@ get_chnl_no(NodeName) when is_atom(NodeName) -> erts_debug:get_internal_state({channel_number, NodeName}). chk_display(Term, Expect) when is_list(Expect) -> - Dstr = erts_debug:display(Term), - case Expect ++ io_lib:nl() of + Dstr = erts_internal:term_to_string(Term), + case Expect of Dstr -> io:format("Test of \"~p\" succeeded.~n" " Expected and got: ~s~n", @@ -316,102 +330,14 @@ run_case(Config, TestArgs, Fun) -> ct:fail({open_port_failed, Error}) end. +mk_pid(Node, Number, Serial) -> + erts_test_utils:mk_ext_pid(Node, Number, Serial). --define(VERSION_MAGIC, 131). - --define(ATOM_EXT, 100). --define(REFERENCE_EXT, 101). --define(PORT_EXT, 102). --define(PID_EXT, 103). --define(NEW_REFERENCE_EXT, 114). --define(NEW_PID_EXT, $X). --define(NEW_PORT_EXT, $Y). --define(NEWER_REFERENCE_EXT, $Z). - -uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> - [(Uint bsr 24) band 16#ff, - (Uint bsr 16) band 16#ff, - (Uint bsr 8) band 16#ff, - Uint band 16#ff]; -uint32_be(Uint) -> - exit({badarg, uint32_be, [Uint]}). - - -uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> - [(Uint bsr 8) band 16#ff, - Uint band 16#ff]; -uint16_be(Uint) -> - exit({badarg, uint16_be, [Uint]}). - -uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> - Uint band 16#ff; -uint8(Uint) -> - exit({badarg, uint8, [Uint]}). - - - -mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> - mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); -mk_pid({NodeName, Creation}, Number, Serial) -> - case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?NEW_PID_EXT, - ?ATOM_EXT, - uint16_be(length(NodeName)), - NodeName, - uint32_be(Number), - uint32_be(Serial), - uint32_be(Creation)])) of - Pid when is_pid(Pid) -> - Pid; - {'EXIT', {badarg, _}} -> - exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); - Other -> - exit({unexpected_binary_to_term_result, Other}) - end. - -mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> - mk_port({atom_to_list(NodeName), Creation}, Number); -mk_port({NodeName, Creation}, Number) -> - case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?NEW_PORT_EXT, - ?ATOM_EXT, - uint16_be(length(NodeName)), - NodeName, - uint32_be(Number), - uint32_be(Creation)])) of - Port when is_port(Port) -> - Port; - {'EXIT', {badarg, _}} -> - exit({badarg, mk_port, [{NodeName, Creation}, Number]}); - Other -> - exit({unexpected_binary_to_term_result, Other}) - end. +mk_port(Node, Number) -> + erts_test_utils:mk_ext_port(Node, Number). -mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), - is_integer(Creation), - is_list(Numbers) -> - mk_ref({atom_to_list(NodeName), Creation}, Numbers); -mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), - is_integer(Creation), - is_list(Numbers) -> - case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?NEWER_REFERENCE_EXT, - uint16_be(length(Numbers)), - ?ATOM_EXT, - uint16_be(length(NodeName)), - NodeName, - uint32_be(Creation), - lists:map(fun (N) -> - uint32_be(N) - end, - Numbers)])) of - Ref when is_reference(Ref) -> - Ref; - {'EXIT', {badarg, _}} -> - exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]}); - Other -> - exit({unexpected_binary_to_term_result, Other}) - end. +mk_ref(Node, Numbers) -> + erts_test_utils:mk_ext_ref(Node, Numbers). my_cre() -> erlang:system_info(creation). diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl index f5a5f8bf5c6a..a5ff8355fa41 100644 --- a/erts/test/erlc_SUITE.erl +++ b/erts/test/erlc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -21,27 +21,57 @@ %% Tests the erlc command by compiling various types of files. --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, compile_erl/1, +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + init_per_testcase/2, end_per_testcase/2, + compile_erl/1, compile_yecc/1, compile_script/1, compile_mib/1, good_citizen/1, deep_cwd/1, arg_overflow/1, - make_dep_options/1]). + make_dep_options/1, + unicode_paths/1, + features_erlc_describe/1, + features_erlc_unknown/1, + features_directives/1, + features_atom_warnings/1, + features_macros/1, + features_disable/1, + features_all/1, + features_load/1, + features_runtime/1, + features_include/1, + features/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> - [{group,with_server},{group,without_server}]. +all() -> + [{group,with_server},{group,without_server}, + {group,features_with_server}]. groups() -> Tests = tests(), [{with_server,[],Tests}, - {without_server,[],Tests}]. + {features_with_server,[],feature_tests()}, + {without_server,[],Tests ++ feature_tests()}]. tests() -> [compile_erl, compile_yecc, compile_script, compile_mib, - good_citizen, deep_cwd, arg_overflow, make_dep_options]. + good_citizen, deep_cwd, arg_overflow, make_dep_options, + unicode_paths]. + +feature_tests() -> + [features_erlc_describe, + features_erlc_unknown, + features_directives, + features_atom_warnings, + features_macros, + features_disable, + features_all, + features_load, + features_runtime, + features_include, + features]. init_per_suite(Config) -> Config. @@ -52,6 +82,10 @@ end_per_suite(_Config) -> init_per_group(with_server, Config) -> os:putenv("ERLC_USE_SERVER", "yes"), Config; +init_per_group(features_with_server, Config) -> + os:putenv("ERLC_USE_SERVER", "yes"), + timer:sleep(12 * 1000), + Config; init_per_group(without_server, Config) -> os:putenv("ERLC_USE_SERVER", "no"), Config; @@ -60,8 +94,28 @@ init_per_group(_, Config) -> end_per_group(_GroupName, Config) -> os:unsetenv("ERLC_USE_SERVER"), + os:unsetenv("OTP_TEST_FEATURES"), + Config. + +init_per_testcase(TestCase, Config) -> + case lists:member(TestCase, feature_tests()) of + true -> + os:putenv("OTP_TEST_FEATURES", "true"); + false -> + ok + end, Config. +end_per_testcase(TestCase, Config) -> + case lists:member(TestCase, feature_tests()) of + true -> + os:putenv("OTP_TEST_FEATURES", "true"); + false -> + ok + end, + Config. + + %% Copy from erlc_SUITE_data/include/erl_test.hrl. -record(person, {name, shoe_size}). @@ -150,7 +204,7 @@ compile_mib(Config) when is_list(Config) -> %% Try -W option and more verbose. ok = file:delete(Output), - case test_server:os_type() of + case os:type() of {unix,_} -> run(Config, Cmd, FileName, "-W +'{verbosity,info}'", ["\\[GOOD-MIB[.]mib\\]\\[INF\\]: No accessfunction for 'sysDescr' => using default", @@ -435,6 +489,610 @@ make_dep_options(Config) -> false = exists(BeamFileName), ok. +unicode_paths(Config) -> + case {os:type(), file:native_name_encoding()} of + {{win32,_}, _} -> {skip, "Unicode paths not supported on windows"}; + {_,latin1} -> {skip, "Cannot interpret unicode filenames when native_name_encoding is latin1"}; + _ -> + DepRE = ["_OK_"], + {SrcDir,OutDir0,Cmd0} = get_cmd(Config), + OutDir = filename:join(OutDir0,"😀"), + ok = case file:make_dir(OutDir) of + {error, eexist} -> ok; + ok -> ok; + E -> E + end, + Cmd = Cmd0 ++ " +brief -o "++OutDir, + FileName = filename:join([SrcDir, "😀", "erl_test_unicode.erl"]), + BeamFileName = filename:join(OutDir, "erl_test_unicode.beam"), + run(Config, Cmd, FileName, "", DepRE), + true = exists(BeamFileName), + file:delete(BeamFileName), + file:delete(OutDir), + ok + end. + +%%% Tests related to the features mechanism +%% Support macros and functions +-define(OK(Lines), Lines ++ ["_OK_"]). +-define(NOTOK(Lines), Lines ++ ["_ERROR_"]). + +flatfmt(FStr, Args) -> + lists:flatten(io_lib:format(FStr, Args)). + +defopt(Name) -> flatfmt("-D~w", [Name]). +defopt(Name, Value) -> flatfmt("-D~w=~w", [Name, Value]). + +longopt(enable, Ftr) -> flatfmt("-enable-feature ~w", [Ftr]); +longopt(disable, Ftr) -> flatfmt("-disable-feature ~w", [Ftr]). + +plusopt(enable, Ftr) -> flatfmt("+\"{feature, ~w, enable}\"", [Ftr]); +plusopt(disable, Ftr) -> flatfmt("+\"{feature, ~w, disable}\"", [Ftr]). + +options(Opts) -> lists:flatten(lists:join(" ", Opts)). + +peer(Args) -> + {ok, Peer, Node} = + ?CT_PEER(#{args => Args, + connection => 0}), + {Peer, Node}. + +%% Error messages to expect +nosingle(Ftr) -> flatfmt("the feature '~w' does not exist", [Ftr]). + +nomultiple(Ftrs) -> + Q = fun(A) -> flatfmt("'~w'", [A]) end, + flatfmt("the features ~s and '~w' do not exist", + [lists:join(", ", + lists:map(Q, lists:droplast(Ftrs))), + lists:last(Ftrs)]). + +not_config(Ftr) -> flatfmt("the feature '~w' is not configurable", [Ftr]). + +syntax(Offender) -> flatfmt("syntax error before: ~w", [Offender]). + +misplaced_directive() -> + "feature directive not allowed after exports or record definitions". + +atom_warning(Atom, Ftr) -> + flatfmt("atom '~w' is reserved in the experimental feature '~w'", + [Atom, Ftr]). + +compile_fun(Config) -> + {SrcDir, OutDir, Cmd} = get_cmd(Config), + Compile = fun(FName, Opts, Expected) -> + Path = case FName of + "" -> ""; + FName -> filename:join(SrcDir, FName) + end, + run(Config, Cmd, Path, Opts, Expected) + end, + {Compile, SrcDir, OutDir}. + +%% Tests +features_erlc_describe(Config) when is_list(Config) -> + {Compile, _, _} = compile_fun(Config), + + Compile("", "-list-features", + ?NOTOK(["Available features:", + "approved_ftr_1", + "approved_ftr_2", + "experimental_ftr_1", + "experimental_ftr_2"])), + + Compile("", "-describe-feature experimental_ftr_1", + ?NOTOK(["experimental_ftr_1", + "Type", + "Status", + "Keywords", + skip_lines])), + + Compile("", "-describe-feature loop_macro", + ?NOTOK(["Unknown feature: loop_macro"])). + +features_erlc_unknown(Config) when is_list(Config) -> + {Compile, _, _} = compile_fun(Config), + + %% Test for single invalid feature, using long and +options + Compile("nofile.erl", longopt(enable, no_ftr), + ?NOTOK([nosingle(no_ftr)])), + Compile("nofile.erl", plusopt(enable, no_ftr), + ?NOTOK([nosingle(no_ftr)])), + Compile("nofile.erl", longopt(disable, no_ftr), + ?NOTOK([nosingle(no_ftr)])), + Compile("nofile.erl", plusopt(disable, no_ftr), + ?NOTOK([nosingle(no_ftr)])), + + %% Test for multiple invalid features + Compile("nofile.erl", options([longopt(enable, no_ftr), + longopt(enable, un_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr])])), + Compile("nofile.erl", options([longopt(enable, no_ftr), + longopt(enable, un_ftr), + longopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + Compile("nofile.erl", options([plusopt(enable, no_ftr), + plusopt(enable, un_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr])])), + Compile("nofile.erl", options([plusopt(enable, no_ftr), + plusopt(enable, un_ftr), + plusopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + + Compile("nofile.erl", options([longopt(enable, no_ftr), + plusopt(enable, un_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr])])), + Compile("nofile.erl", options([plusopt(enable, no_ftr), + longopt(enable, un_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr])])), + + Compile("nofile.erl", options([longopt(enable, no_ftr), + longopt(enable, un_ftr), + plusopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + Compile("nofile.erl", options([longopt(enable, no_ftr), + plusopt(enable, un_ftr), + plusopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + + Compile("nofile.erl", options([longopt(enable, no_ftr), + plusopt(enable, un_ftr), + longopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + Compile("nofile.erl", options([plusopt(enable, no_ftr), + plusopt(enable, un_ftr), + longopt(disable, mis_ftr)]), + ?NOTOK([nomultiple([no_ftr, un_ftr, mis_ftr])])), + + %% Rejected and permanent features can not be configured. + %% Rejected feature + Compile("nofile.erl", + options([longopt(enable, rejected_ftr)]), + ?NOTOK([not_config(rejected_ftr), + skip_lines])), + + %% Permanent feature + Compile("nofile.erl", + options([longopt(enable, permanent_ftr)]), + ?NOTOK([not_config(permanent_ftr), + skip_lines])). + +features_directives(Config) when is_list(Config) -> + {Compile, _, _} = compile_fun(Config), + + %% Test for misplaced feature directive (enable) + Compile("f_directives.erl", + options([defopt(misplaced_enable)]), + ?NOTOK([misplaced_directive(), + "[0-9]+\| -feature.*misplaced", + skip_lines])), + %% Test for misplaced feature directive (disable) + Compile("f_directives.erl", + options([defopt(misplaced_disable)]), + ?NOTOK([misplaced_directive(), + "[0-9]+\| -feature.*misplaced", + skip_lines])), + + %% Test for unknown feature in directive (enable) + Compile("f_directives.erl", + options([defopt(enable_unknown)]), + ?NOTOK([nosingle(unlesser), + "[0-9]+\| -feature", + skip_lines])), + %% Test for unknown feature in directive (disable) + Compile("f_directives.erl", + options([defopt(disable_unknown)]), + ?NOTOK([nosingle(unlesser), + "[0-9]+\| -feature", + skip_lines])), + + %% Enable a feature on the command line and disable the same in a + %% directive + Compile("f_directives.erl", + options([longopt(enable, experimental_ftr_2), + defopt(disable_exp2), + defopt(no_dir_enable_exp2)]), + ?OK([])). + +features_atom_warnings(Config) when is_list(Config) -> + {Compile, _, _} = compile_fun(Config), + + %% Check for keyword warnings. Not all are checked. + Compile("ignorant.erl", "+warn_keywords", + ?OK([atom_warning(until, experimental_ftr_2), + skip_lines, + atom_warning(ifn, experimental_ftr_1), + skip_lines, + atom_warning(while, experimental_ftr_2), + skip_lines])), + + %% Check for keyword warnings, resulting in error. + %% Not all warnings are checked. + Compile("ignorant.erl", "+warn_keywords -Werror", + ?NOTOK([skip_lines, + atom_warning(until, experimental_ftr_2), + skip_lines, + atom_warning(ifn, experimental_ftr_1), + skip_lines, + atom_warning(while, experimental_ftr_2), + skip_lines])), + + %% Check for keyword warnings. Not all warnings are checked. + %% This file has a -compile attribute for keyword warnings. + Compile("ignorant_directive.erl", "", + ?OK([atom_warning(ifn, experimental_ftr_1), + skip_lines, + atom_warning(while, experimental_ftr_2), + skip_lines, + atom_warning(until, experimental_ftr_2), + skip_lines])), + + %% Override warning attribute inside file + Compile("ignorant_directive.erl", "+nowarn_keywords", + ?OK([])), + + %% File has quoted atoms which are keywords in experimental_ftr_2. + %% We should see no warnings. + Compile("foo.erl", options([longopt(enable, experimental_ftr_2), + "+warn_keywords"]), + ?OK([])). + +features(Config) when is_list(Config) -> + {Compile, _, _} = compile_fun(Config), + + %% Simple compile - baseline for this file. Really needed? + %% It uses atoms that are keywords in experimental features. + Compile("ignorant.erl", + [], + ?OK([])), + + %% Enable and disable the same feature on the command line to + %% check that the ordering semantics is honoured. + Compile("ignorant.erl", + options([longopt(enable, experimental_ftr_1), + longopt(disable, experimental_ftr_1)]), + ?OK([])), + + %% As above, with +options + Compile("ignorant.erl", + options([plusopt(enable, experimental_ftr_1), + plusopt(disable, experimental_ftr_1)]), + ?OK([])), + + %% Mixed options + Compile("ignorant.erl", + options([longopt(enable, experimental_ftr_1), + plusopt(disable, experimental_ftr_1)]), + ?OK([])), + + %% Mixed options + Compile("ignorant.erl", + options([plusopt(enable, experimental_ftr_1), + longopt(disable, experimental_ftr_1)]), + ?OK([])), + + %% Enable a feature and see errors + Compile("ignorant.erl", + options([longopt(enable, experimental_ftr_1)]), + ?NOTOK([syntax(ifn), + skip_lines, + syntax(ifn), + skip_lines])), + + %% Enable another feature and see other errors + Compile("ignorant.erl", + options([longopt(enable, experimental_ftr_2)]), + ?NOTOK([syntax(until), + skip_lines, + syntax(until), + skip_lines, + syntax(while), + skip_lines, + syntax(while), + skip_lines, + syntax(until), + skip_lines])), + + %% Enable both features and see even more errors + Compile("ignorant.erl", + options([longopt(enable, experimental_ftr_1), + longopt(enable, experimental_ftr_2)]), + ?NOTOK([syntax(until), + skip_lines, + syntax(until), + skip_lines, + syntax(ifn), + skip_lines, + syntax(while), + skip_lines, + syntax(until), + skip_lines, + syntax(ifn), + skip_lines])), + + ok. + +features_macros(Config) when is_list(Config) -> + {Compile, _, OutDir} = compile_fun(Config), + + Compile("f_macros.erl", "", ?OK([])), + + {Peer0, Node0} = peer(["-pa", OutDir]), + Call = fun(Node, Fun) -> + erpc:call(Node, f_macros, Fun, []) + end, + + {module, f_macros} = + erpc:call(Node0, code, load_file, [f_macros]), + + true = Call(Node0, has_experimental), + false = Call(Node0, has_hindley_milner), + false = Call(Node0, with_hm), + false = Call(Node0, uses_experimental), + false = Call(Node0, uses_exp2), + + peer:stop(Peer0), + + Compile("f_macros.erl", longopt(enable, experimental_ftr_1), + ?OK([])), + + {Peer1, Node1} = peer(["-pa", OutDir]), + + true = erpc:call(Node1, erlang, module_loaded, [erl_features]), + + %% Starting from OTP 26, compile-time features don't need to be + %% enabled in the runtime system. + {module, f_macros} = + erpc:call(Node1, code, load_file, [f_macros]), + %% Check features enabled during compilation + [approved_ftr_1, approved_ftr_2, experimental_ftr_1] = + erpc:call(Node1, erl_features, used, [f_macros]), + + peer:stop(Peer1), + + %% Restart with feature enabled in runtime + {Peer2, Node2} = peer(["-pa", OutDir, + "-enable-feature","experimental_ftr_1"]), + %% Now we can load it + {module, f_macros} = + erpc:call(Node2, code, load_file, [f_macros]), + + true = Call(Node2, uses_experimental), + false = Call(Node2, uses_exp2), + peer:stop(Peer2), + + Compile("f_macros.erl", longopt(enable, experimental_ftr_2), + ?OK([])), + {Peer3, Node3} = peer(["-pa", OutDir, + "-enable-feature","experimental_ftr_2"]), + false = Call(Node3, uses_experimental), + true = Call(Node3, uses_exp2), + peer:stop(Peer3), + + Compile("f_macros.erl", options([longopt(enable, experimental_ftr_1), + longopt(enable, experimental_ftr_2)]), + ?OK([])), + {Peer4, Node4} = peer(["-pa", OutDir, + "-enable-feature","experimental_ftr_1", + "-enable-feature","experimental_ftr_2"]), + true = Call(Node4, uses_experimental), + true = Call(Node4, uses_exp2), + peer:stop(Peer4), + + ok. + +features_disable(Config) when is_list(Config) -> + {Compile, _, OutDir} = compile_fun(Config), + + Call = fun(Node, Fun) -> + erpc:call(Node, f_disable, Fun, []) + end, + + Compile("f_disable.erl", options([longopt(enable, experimental_ftr_1), + longopt(enable, experimental_ftr_2)]), + ?OK([])), + + {Peer, Node} = peer(["-pa", OutDir, + "-enable-feature","experimental_ftr_1", + "-enable-feature","experimental_ftr_2"]), + %% Check features enabled during compilation + [approved_ftr_2] = + erpc:call(Node, erl_features, used, [f_disable]), + + no_experimental = Call(Node, no_experimental), + no_exp2 = Call(Node, no_ftrs), + peer:stop(Peer), + + ok. + +features_all(Config) when is_list(Config) -> + {Compile, _, OutDir} = compile_fun(Config), + + Compile("foo.erl", longopt(enable, all), + ?OK([])), + + {Peer0, Node0} = peer(["-pa", OutDir]), + %% Check features enabled during compilation + [approved_ftr_1,approved_ftr_2,experimental_ftr_1,experimental_ftr_2] = + erpc:call(Node0, erl_features, used, [foo]), + peer:stop(Peer0), + + Compile("foo.erl", longopt(disable, all), + ?OK([])), + + {Peer1, Node1} = peer(["-pa", OutDir]), + %% Check features enabled during compilation + [] = erpc:call(Node1, erl_features, used, [foo]), + {module, foo} = erpc:call(Node1, code, load_file, [foo]), + peer:stop(Peer1), + + Compile("foo.erl", options([longopt(disable, all), + longopt(enable, approved_ftr_2)]), + ?OK([])), + + {Peer2, Node2} = peer(["-pa", OutDir, + "-disable-feature", "all"]), + %% Check features enabled during compilation + [approved_ftr_2] = erpc:call(Node2, erl_features, used, [foo]), + peer:stop(Peer2), + + ok. + +features_load(Config) when is_list(Config) -> + {_Compile, SrcDir, _OutDir} = compile_fun(Config), + + %% Note that we put SrcDir in the load path as there is where we + %% have the precompiled beam file. + {Peer0, Node0} = peer(["-pa", SrcDir]), + + %% For a file compiled with an older version, i.e., with no Meta + %% chunk, we should see no used features. + [] = erpc:call(Node0, erl_features, used, [older]), + %% .. and we should be able to load it. + {module,older} = erpc:call(Node0, code, load_file, [older]), + + [] = erpc:call(Node0, erl_features, used, + [filename:join(SrcDir, "older.beam")]), + + %% Behaviour for non existent modules + not_found = erpc:call(Node0, erl_features, used, [none]), + not_found = erpc:call(Node0, erl_features, used, ["none.beam"]), + peer:stop(Peer0), + + ok. + +features_runtime(Config) when is_list(Config) -> + AllFtrs = [approved_ftr_1, + approved_ftr_2, + experimental_ftr_1, + experimental_ftr_2, + permanent_ftr, + rejected_ftr], + ConfigFtrs = [approved_ftr_1, + approved_ftr_2, + experimental_ftr_1, + experimental_ftr_2], + Approved = [approved_ftr_2, + approved_ftr_1], + + {_Compile, _SrcDir, _OutDir} = compile_fun(Config), + + {Peer0, Node0} = peer([]), + + %% Get all known features + AllFtrs = erpc:call(Node0, erl_features, all, []), + ConfigFtrs = erpc:call(Node0, erl_features, configurable, []), + Approved = erpc:call(Node0, erl_features, enabled, []), + + %% Keywords from enabled (here the approved) features + %% (does not need to be quoted since it comes from the peer node) + [unless] = erpc:call(Node0, erl_features, keywords, []), + + Info = erpc:call(Node0, erl_features, info, [permanent_ftr]), + true = is_map(Info), + true = lists:all(fun(K) -> is_map_key(K, Info) end, + [status,type,description,short,experimental]), + + %% Try to get info for unknown feature - raises error + try + erpc:call(Node0, erl_features, info, [unknown_feature]) of + Value -> + ct:fail({value_returned_for_unknown_feature, Value}) + catch + error:{exception, invalid_feature, _} -> + ok; + Class:Reason -> + ct:fail({unexpected_exception, {Class, Reason}}) + end, + + peer:stop(Peer0), + + {Peer1, Node1} = peer(["-enable-feature", "experimental_ftr_2"]), + [experimental_ftr_2, approved_ftr_2, approved_ftr_1] = + erpc:call(Node1, erl_features, enabled, []), + [while, until, unless] = erpc:call(Node1, erl_features, keywords, []), + + peer:stop(Peer1), + + {Peer2, Node2} = peer(["-disable-feature", "all"]), + [] = erpc:call(Node2, erl_features, enabled, []), + [] = erpc:call(Node2, erl_features, keywords, []), + + peer:stop(Peer2), + ok. + +features_include(Config) when is_list(Config) -> + {Compile, _SrcDir, OutDir} = compile_fun(Config), + + %% Ensure that the feature experimental_ftr_1 is enabled in the + %% include file and generates an error + Compile("f_include_1.erl", [], + ?NOTOK([syntax(ifn), + skip_lines])), + + %% This will disable a feature after a record has been defined. + %% Error expected + Compile("f_include_1.erl", defopt(end_include), + ?NOTOK([misplaced_directive(), + skip_lines])), + + %% Ensure that the macro knows that experimental_ftr_1 is enabled + %% in the include file. + Compile("f_include_2.erl", defopt(end_include), + ?OK([])), + + {Peer0, Node0} = peer(["-pa", OutDir, + "-enable-feature", "experimental_ftr_1"]), + + {module, f_include_2} = erpc:call(Node0, code, load_file, [f_include_2]), + active = erpc:call(Node0, f_include_2, foo, [2]), + peer:stop(Peer0), + + Compile("f_include_3.erl", [], + ?OK([])), + + {Peer1, Node1} = peer(["-pa", OutDir, + "-enable-feature", "all"]), + exp2_enabled = erpc:call(Node1, f_include_3, foo, [1]), + peer:stop(Peer1), + + Compile("f_include_3.erl", defopt(end_prefix), + ?NOTOK([misplaced_directive(), + "experimental_ftr_2", + skip_lines])), + + Compile("f_include_exp2.erl", defopt(enable_exp_2, 0), + ?OK([])), + {Peer2, Node2} = peer(["-pa", OutDir]), + {conditional, on, until} = erpc:call(Node2, f_include_exp2, foo, []), + peer:stop(Peer2), + + Compile("f_include_exp2.erl", + options([defopt(enable_exp_2, 0), + longopt(enable, experimental_ftr_2)]), + ?NOTOK([syntax(until), + skip_lines])), + + Compile("f_include_exp2.erl", + options([defopt(enable_exp_2, 1)]), + ?NOTOK([syntax(until), + skip_lines])), + + Compile("f_include_exp2.erl", + options([defopt(enable_exp_2, 2), + longopt(enable, experimental_ftr_2)]), + ?OK([])), + + {Peer3, Node3} = peer(["-pa", OutDir, + "-enable-feature", "experimental_ftr_2"]), + {conditional, off, none} = erpc:call(Node3, f_include_exp2, foo, []), + + [approved_ftr_1, approved_ftr_2, experimental_ftr_2] = + erpc:call(Node3, erl_features, used, [f_include_exp2]), + peer:stop(Peer3), + + ok. + %% Runs a command. run(Config, Cmd0, Name, Options, Expect) -> @@ -447,7 +1105,7 @@ verify_result(Result, Expect) -> Messages = split(Result, [], []), io:format("Result: ~p", [Messages]), io:format("Expected: ~p", [Expect]), - match_messages(Messages, Expect). + match_messages_x(Messages, Expect). %% insert What before Item, crash if Item is not found insert_before(Item, What, [Item|List]) -> @@ -466,15 +1124,27 @@ split([], [], Lines) -> split([], Current, Lines) -> split([], [], [lists:reverse(Current)|Lines]). -match_messages([Msg|Rest1], [Regexp|Rest2]) -> - case re:run(Msg, Regexp, [{capture,none}, unicode]) of +match_messages_x(Msgs0, Regexps0) -> + Msgs = lists:droplast(Msgs0), + Regexps = lists:droplast(Regexps0), + Return = lists:last(Msgs0), + ExpRet = lists:last(Regexps0), + match_messages(Msgs, Regexps), + match_one(Return, ExpRet). + +match_messages(_, [skip_lines]) -> + ok; +match_messages([_Msg|Rest1], [skip_one|Rest2]) -> + match_messages(Rest1, Rest2); +match_messages([Msg|Rest1], [skip_lines, Regexp|Rest2]) -> + case match(Msg, Regexp) of match -> - ok; + match_messages(Rest1, Rest2); nomatch -> - io:format("Not matching: ~s\n", [Msg]), - io:format("Regexp : ~s\n", [Regexp]), - ct:fail(message_mismatch) - end, + match_messages(Rest1, [skip_lines, Regexp|Rest2]) + end; +match_messages([Msg|Rest1], [Regexp|Rest2]) -> + match_one(Msg, Regexp), match_messages(Rest1, Rest2); match_messages([], [Expect|Rest]) -> ct:fail({too_few_messages, [Expect|Rest]}); @@ -483,6 +1153,19 @@ match_messages([Msg|Rest], []) -> match_messages([], []) -> ok. +match_one(Msg, Regexp) -> + case match(Msg, Regexp) of + match -> + ok; + nomatch -> + io:format("Not matching: ~s\n", [Msg]), + io:format("Regexp : ~s\n", [Regexp]), + ct:fail(message_mismatch) + end. + +match(Msg, Regexp) -> + re:run(Msg, Regexp, [{capture,none}, unicode]). + get_cmd(Cfg) -> {SrcDir, IncDir, OutDir} = get_dirs(Cfg), Cmd = erlc() ++ " -I" ++ IncDir ++ " -o" ++ OutDir ++ " ", @@ -509,7 +1192,7 @@ run_command(Config, Cmd) -> TmpDir = filename:join(proplists:get_value(priv_dir, Config), "tmp"), file:make_dir(TmpDir), {RunFile, Run, Script} = run_command(TmpDir, os:type(), Cmd), - ok = file:write_file(filename:join(TmpDir, RunFile), unicode:characters_to_binary(Script)), + ok = file:write_file(RunFile, unicode:characters_to_binary(Script)), os:cmd(Run). run_command(Dir, {win32, _}, Cmd) -> diff --git a/erts/test/erlc_SUITE_data/src/enable.hrl b/erts/test/erlc_SUITE_data/src/enable.hrl new file mode 100644 index 000000000000..9d5934723b07 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/enable.hrl @@ -0,0 +1 @@ +-feature(experimental_ftr_2, enable). diff --git a/erts/test/erlc_SUITE_data/src/exp2.hrl b/erts/test/erlc_SUITE_data/src/exp2.hrl new file mode 100644 index 000000000000..91fa3b39b56a --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/exp2.hrl @@ -0,0 +1,6 @@ +-if(?enable_exp_2 > 0). +-feature(experimental_ftr_2, enable). +-record(conditional, {on=off, 'until'=none}). +-else. +-record(conditional, {on=on, until=until}). +-endif. diff --git a/erts/test/erlc_SUITE_data/src/f_directives.erl b/erts/test/erlc_SUITE_data/src/f_directives.erl new file mode 100644 index 000000000000..f8fe4fbf1a3f --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_directives.erl @@ -0,0 +1,67 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(f_directives). + +-ifdef(disable_unknown). +-feature(unlesser, disable). +-endif. + +-ifdef(enable_unknown). +-feature(unlesser, enable). +-endif. + +%% This module uses both features experimental_ftr_1 and +%% experimental_ftr_2, so atoms belonging to these need to be quoted. + +-feature(experimental_ftr_1, enable). + +-ifndef(no_dir_enable_exp2). +-feature(experimental_ftr_2, enable). +-endif. + +-ifdef(disable_exp2). +-feature(experimental_ftr_2, disable). +-endif. + +-export([bar/0, + foo/0]). + +-ifdef(misplaced_enable). +%% This is out of place and will result in an error +-feature(misplaced, enable). +-endif. + +-ifdef(misplaced_disable). +%% This is out of place and will result in an error +-feature(misplaced, disable). +-endif. + +bar() -> + ['ifn']. + +-ifdef(disable_exp2). +foo() -> + %% Note: experimental_ftr_2 not active here + ['ifn', while, until, 'if']. +-else. +foo() -> + ['ifn', 'while', 'until', 'if']. +-endif. diff --git a/erts/test/erlc_SUITE_data/src/f_disable.erl b/erts/test/erlc_SUITE_data/src/f_disable.erl new file mode 100644 index 000000000000..d106e038d88b --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_disable.erl @@ -0,0 +1,46 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(f_disable). + +-feature(experimental_ftr_1, disable). +-feature(experimental_ftr_2, disable). +-feature(approved_ftr_1, disable). + +-export([no_experimental/0, + no_ftrs/0]). + +-if(?FEATURE_ENABLED(experimental_ftr_1)). +-define(FOO, has_experimental). +-else. +-define(FOO, no_experimental). +-endif. + +no_experimental() -> + ?FOO. + +-if(?FEATURE_ENABLED(experimental_ftr_2)). +-define(BAR, has_exp2). +-else. +-define(BAR, no_exp2). +-endif. + +no_ftrs() -> + ?BAR. diff --git a/erts/test/erlc_SUITE_data/src/f_include_1.erl b/erts/test/erlc_SUITE_data/src/f_include_1.erl new file mode 100644 index 000000000000..27ea93565ab5 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_include_1.erl @@ -0,0 +1,18 @@ +-module(f_include_1). + +-feature(experimental_ftr_1, enable). + +-ifdef(end_include). +-feature(experimental_ftr_2, enable). +-endif. + +%% This defines a record, so ends the prefix. +-include("is_enabled.hrl"). + +-ifdef(end_include). +-feature(approved_ftr_1, disable). +-endif. + +-export([foo/1]). + +foo(1) -> one. diff --git a/erts/test/erlc_SUITE_data/src/f_include_2.erl b/erts/test/erlc_SUITE_data/src/f_include_2.erl new file mode 100644 index 000000000000..a31d44e43fc9 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_include_2.erl @@ -0,0 +1,12 @@ +-module(f_include_2). + +-feature(experimental_ftr_1, enable). + +%% Include file defines a macro, conditional on whether experimental_ftr_1 +%% is enabled. +-include("macro_enabled.hrl"). + +%% At this point the prefix will definitely end, if it has not already +-export([foo/1]). + +foo(2) -> ?UNLESS. diff --git a/erts/test/erlc_SUITE_data/src/f_include_3.erl b/erts/test/erlc_SUITE_data/src/f_include_3.erl new file mode 100644 index 000000000000..cce18ca2d4fe --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_include_3.erl @@ -0,0 +1,21 @@ +-module(f_include_3). + +-feature(experimental_ftr_1, enable). + +-ifdef(end_prefix). +-record(constant, {value = 42}). +-endif. + +%% Enable feature inside include file +-include("enable.hrl"). + +%% At this point the prefix will definitely end, if it has not already +-export([foo/1]). + +-if(?FEATURE_ENABLED(experimental_ftr_2)). +foo(1) -> + exp2_enabled. +-else. +foo(1) -> + exp2_disabled. +-endif. diff --git a/erts/test/erlc_SUITE_data/src/f_include_exp2.erl b/erts/test/erlc_SUITE_data/src/f_include_exp2.erl new file mode 100644 index 000000000000..aef3a5a5f4c7 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_include_exp2.erl @@ -0,0 +1,18 @@ +-module(f_include_exp2). + +-include("exp2.hrl"). + +-export([foo/0, + bar/0]). + + +foo() -> + #conditional{}. + +-if(?enable_exp_2 == 1). +bar() -> + until. +-else. +bar() -> + no. +-endif. diff --git a/erts/test/erlc_SUITE_data/src/f_macros.erl b/erts/test/erlc_SUITE_data/src/f_macros.erl new file mode 100644 index 000000000000..72b73ece528b --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/f_macros.erl @@ -0,0 +1,65 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(f_macros). + +-export([has_experimental/0, + has_hindley_milner/0, + with_hm/0, + uses_experimental/0, + uses_exp2/0 + ]). + +%% This test feature exists +-if(?FEATURE_AVAILABLE(experimental_ftr_1)). +has_experimental() -> + true. +-else. +has_experimental() -> + false. +-endif. + +%% This feature will probably never exist :-( +-if(?FEATURE_AVAILABLE(hindley_milner)). +has_hindley_milner() -> + true. +-else. +has_hindley_milner() -> + false. +-endif. + +with_hm() -> + ?FEATURE_ENABLED(hindley_milner). + +-if(?FEATURE_ENABLED(experimental_ftr_1)). +uses_experimental() -> + true. +-else. +uses_experimental() -> + false. +-endif. + +-if(?FEATURE_ENABLED(experimental_ftr_2)). +uses_exp2() -> + true. +-else. +uses_exp2() -> + false. +-endif. diff --git a/erts/test/erlc_SUITE_data/src/foo.erl b/erts/test/erlc_SUITE_data/src/foo.erl new file mode 100644 index 000000000000..b3716803aac8 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/foo.erl @@ -0,0 +1,6 @@ +-module foo. + +-export [foo/0]. + +foo() -> + ['while', 'until']. diff --git a/erts/test/erlc_SUITE_data/src/ignorant.erl b/erts/test/erlc_SUITE_data/src/ignorant.erl new file mode 100644 index 000000000000..f0ae7e6b5da5 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/ignorant.erl @@ -0,0 +1,44 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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 is ignorant about any features and thus use 'ifn', +%% 'while' and 'until' as ordinary atoms. + +-module(ignorant). + +-export([foo/0, + frob/1, + bar/0, + until/1, + baz/1]). + +until(X) -> + until(X). + +foo() -> + [ifn, while, until]. + +frob(while) -> false. + +bar() -> + [until, while]. + +baz(ifn) -> + {true, 'ifnot'}. diff --git a/erts/test/erlc_SUITE_data/src/ignorant_directive.erl b/erts/test/erlc_SUITE_data/src/ignorant_directive.erl new file mode 100644 index 000000000000..5ad8c23e3c56 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/ignorant_directive.erl @@ -0,0 +1,42 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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 is ignorant about any features and thus use 'ifn', +%% 'while and 'until' as ordinary atoms. + +-module(ignorant_directive). + +-compile(warn_keywords). + +-export([foo/0, + frob/1, + bar/0, + baz/1]). + +foo() -> + [ifn, while, until]. + +frob(while) -> false. + +bar() -> + [until, while]. + +baz(ifn) -> + true. diff --git a/erts/test/erlc_SUITE_data/src/is_enabled.hrl b/erts/test/erlc_SUITE_data/src/is_enabled.hrl new file mode 100644 index 000000000000..e91cfeda8e61 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/is_enabled.hrl @@ -0,0 +1,3 @@ +%% This will fail when experimental_ftr_1 is not enabled +%% or end the prefix when it is enabled +-record(random, {ifn = 42, unless = 17}). diff --git a/erts/test/erlc_SUITE_data/src/macro_enabled.hrl b/erts/test/erlc_SUITE_data/src/macro_enabled.hrl new file mode 100644 index 000000000000..c23cfd6c710a --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/macro_enabled.hrl @@ -0,0 +1,5 @@ +-if(?FEATURE_ENABLED(experimental_ftr_1)). +-define(UNLESS, active). +-else. +-define(UNLESS, inactive). +-endif. diff --git a/erts/test/erlc_SUITE_data/src/older.beam b/erts/test/erlc_SUITE_data/src/older.beam new file mode 100644 index 000000000000..c2b677586a79 Binary files /dev/null and b/erts/test/erlc_SUITE_data/src/older.beam differ diff --git a/erts/test/erlc_SUITE_data/src/older.erl b/erts/test/erlc_SUITE_data/src/older.erl new file mode 100644 index 000000000000..06bb154e28d9 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/older.erl @@ -0,0 +1,6 @@ +-module(older). + +-export([none/0]). + +none() -> + old. diff --git "a/erts/test/erlc_SUITE_data/src/\360\237\230\200/erl_test_unicode.erl" "b/erts/test/erlc_SUITE_data/src/\360\237\230\200/erl_test_unicode.erl" new file mode 100644 index 000000000000..32a208b7e20e --- /dev/null +++ "b/erts/test/erlc_SUITE_data/src/\360\237\230\200/erl_test_unicode.erl" @@ -0,0 +1,25 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2016. 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(erl_test_unicode). +-export(['😀'/1]). + +'😀'(0) -> + '😀'. diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl index 8d7ecebc2399..ab2439be096f 100644 --- a/erts/test/erlexec_SUITE.erl +++ b/erts/test/erlexec_SUITE.erl @@ -82,7 +82,7 @@ argument_separation(Config) when is_list(Config) -> {ok,[[]]} = rpc:call(SName,init,get_argument,[atest]), {ok,[[]]} = rpc:call(SName,init,get_argument,[cmd_test]), {ok,[[]]} = rpc:call(SName,init,get_argument,[test]), - error = rpc:call(SName,init,get_argument,[unkown]), + error = rpc:call(SName,init,get_argument,[unknown]), ["cmd_param","env_param","zenv_param"] = rpc:call(SName,init,get_plain_arguments,[]), ok = cleanup_nodes(), ok. diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl index 19f738c5720e..4c2c1139dfcb 100644 --- a/erts/test/ethread_SUITE.erl +++ b/erts/test/ethread_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -43,7 +43,8 @@ rwspinlock/1, rwmutex/1, atomic/1, - dw_atomic_massage/1]). + dw_atomic_massage/1, + thread_name/1]). -include_lib("common_test/include/ct.hrl"). @@ -65,7 +66,8 @@ all() -> rwspinlock, rwmutex, atomic, - dw_atomic_massage]. + dw_atomic_massage, + thread_name]. init_per_testcase(Case, Config) -> case inet:gethostname() of @@ -158,6 +160,10 @@ atomic(Config) -> dw_atomic_massage(Config) -> run_case(Config, "dw_atomic_massage", ""). +%% Tests thread names. +thread_name(Config) -> + run_case(Config, "thread_name", ""). + %% %% %% Auxiliary functions diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c index 048acd6a9502..377aabac24fc 100644 --- a/erts/test/ethread_SUITE_data/ethread_tests.c +++ b/erts/test/ethread_SUITE_data/ethread_tests.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2021. All Rights Reserved. + * Copyright Ericsson AB 2004-2023. 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. @@ -41,7 +41,7 @@ #define PRINT_VA_LIST(FRMT) \ do { \ - if (FRMT && FRMT != '\0') { \ + if (FRMT && *(FRMT) != '\0') { \ va_list args; \ va_start(args, FRMT); \ vfprintf(stderr, FRMT, args); \ @@ -1757,6 +1757,7 @@ at_dw_thr(void *vval) break; } } + return NULL; } static void @@ -1783,6 +1784,120 @@ dw_atomic_massage_test(void) } } +static ethr_mutex thread_name_mutex; +static ethr_cond thread_name_cond; +static int thread_name_state; + +static void * +thread_name_thread(void *my_tid) +{ + int res; + + ethr_mutex_lock(&thread_name_mutex); + thread_name_state = 1; + while (thread_name_state == 1) { + res = ethr_cond_wait(&thread_name_cond, &thread_name_mutex); + ASSERT(res == 0); + } + ethr_mutex_unlock(&thread_name_mutex); + return NULL; +} + +static void +thread_name(void) +{ + static const ethr_thr_opts default_thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; + ethr_tid tid; + ethr_thr_opts thr_opts; + int res; + char buf[ETHR_THR_NAME_MAX + 1]; + + res = ethr_mutex_init(&thread_name_mutex); + ASSERT(res == 0); + res = ethr_cond_init(&thread_name_cond); + ASSERT(res == 0); + + if (ethr_getname(ethr_self(), buf, sizeof(buf)) == ENOSYS) { + skip("thread names are not supported"); + return; + } + + /* create a thread with the minimum name length */ + thread_name_state = 0; + + memcpy(&thr_opts, &default_thr_opts, sizeof(thr_opts)); + thr_opts.name = ""; + res = ethr_thr_create(&tid, thread_name_thread, NULL, &thr_opts); + ASSERT(res == 0); + + memset(buf, 0xFF, sizeof(buf)); + res = ethr_getname(tid, buf, sizeof(buf)); + ASSERT(res == 0); + + res = strcmp(buf, ""); + ASSERT(res == 0); + + ethr_mutex_lock(&thread_name_mutex); + thread_name_state = 0; + ethr_cond_signal(&thread_name_cond); + ethr_mutex_unlock(&thread_name_mutex); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + + /* create a thread with a middling name length */ + thread_name_state = 0; + + memcpy(&thr_opts, &default_thr_opts, sizeof(thr_opts)); + thr_opts.name = "123456789"; + res = ethr_thr_create(&tid, thread_name_thread, NULL, &thr_opts); + ASSERT(res == 0); + + memset(buf, 0xFF, sizeof(buf)); + res = ethr_getname(tid, buf, sizeof(buf)); + ASSERT(res == 0); + + res = strcmp(buf, "123456789"); + ASSERT(res == 0); + + ethr_mutex_lock(&thread_name_mutex); + thread_name_state = 0; + ethr_cond_signal(&thread_name_cond); + ethr_mutex_unlock(&thread_name_mutex); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + + /* create a thread with the maximum name length */ + thread_name_state = 0; + + memcpy(&thr_opts, &default_thr_opts, sizeof(thr_opts)); + thr_opts.name = "123456789012345"; + res = ethr_thr_create(&tid, thread_name_thread, NULL, &thr_opts); + ASSERT(res == 0); + + memset(buf, 0xFF, sizeof(buf)); + res = ethr_getname(tid, buf, sizeof(buf)); + ASSERT(res == 0); + + res = strcmp(buf, "123456789012345"); + ASSERT(res == 0); + + ethr_mutex_lock(&thread_name_mutex); + thread_name_state = 0; + ethr_cond_signal(&thread_name_cond); + ethr_mutex_unlock(&thread_name_mutex); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + + /* create a thread with an over-sized name length */ + memcpy(&thr_opts, &default_thr_opts, sizeof(thr_opts)); + thr_opts.name = "1234567890123456"; + res = ethr_thr_create(&tid, thread_name_thread, NULL, &thr_opts); + ASSERT(res == EINVAL); +} + void * at_thread(void *unused) { @@ -1958,6 +2073,8 @@ main(int argc, char *argv[]) atomic_test(); else if (strcmp(testcase, "dw_atomic_massage") == 0) dw_atomic_massage_test(); + else if (strcmp(testcase, "thread_name") == 0) + thread_name(); else skip("Test case \"%s\" not implemented yet", testcase); diff --git a/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl index b2a0445ec156..5754bf5d3bee 100644 --- a/erts/test/nt_SUITE.erl +++ b/erts/test/nt_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-2021. 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. @@ -195,7 +195,7 @@ user_env(Config) when is_list(Config) -> remove_service(Name), ok. -%% Check that services are stopped and started syncronous and that +%% Check that services are stopped and started synchronous and that %% failed stopactions kill the erlang machine anyway. synced(Config) when is_list(Config) -> Name0 = "test_service_4", diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index a4c0f7a50cef..a8424ea46ff3 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2022. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -27,7 +27,8 @@ call_to_size_1/1,call_to_now_0/1,strong_components/1, erl_file_encoding/1,xml_file_encoding/1, runtime_dependencies_functions/1, - runtime_dependencies_modules/1]). + runtime_dependencies_modules/1, + test_runtime_dependencies_versions/1]). -include_lib("common_test/include/ct.hrl"). @@ -35,15 +36,17 @@ suite() -> [{ct_hooks,[ts_install_cth]}, - {timetrap, {minutes, 10}}]. + {timetrap, {minutes, 30}}]. -all() -> +all() -> [undefined_functions, deprecated_not_in_obsolete, obsolete_but_not_deprecated, call_to_deprecated, call_to_size_1, call_to_now_0, strong_components, erl_file_encoding, xml_file_encoding, runtime_dependencies_functions, - runtime_dependencies_modules]. + runtime_dependencies_modules, + test_runtime_dependencies_versions +]. init_per_suite(Config) -> Server = start_xref_server(daily_xref, functions), @@ -140,7 +143,7 @@ wx_filter(Undef) -> end. diameter_filter(Undef) -> - %% Filter away function calls that are catched. + %% Filter away function calls that are caught. filter(fun({{diameter_lib,_,_},{erlang,convert_time_unit,3}}) -> false; ({{diameter_lib,_,_},{erlang,monotonic_time,0}}) -> @@ -215,17 +218,13 @@ call_to_deprecated(Config) when is_list(Config) -> {comment,integer_to_list(length(DeprecatedCalls))++" calls to deprecated functions"}. call_to_size_1(Config) when is_list(Config) -> - %% Applications that do not call erlang:size/1: - Apps = [asn1,compiler,debugger,kernel,observer,parsetools, - runtime_tools,stdlib,tools], + %% Forbid the use of erlang:size/1 in all applications. + Apps = all_otp_applications(Config), not_recommended_calls(Config, Apps, {erlang,size,1}). call_to_now_0(Config) when is_list(Config) -> - %% Applications that do not call erlang:now/1: - Apps = [asn1,common_test,compiler,debugger,dialyzer, - kernel,mnesia,observer,parsetools,reltool, - runtime_tools,sasl,stdlib,syntax_tools, - tools], + %% Forbid the use of erlang:now/1 in all applications except et. + Apps = all_otp_applications(Config) -- [et], not_recommended_calls(Config, Apps, {erlang,now,0}). not_recommended_calls(Config, Apps0, MFA) -> @@ -278,9 +277,20 @@ not_recommended_calls(Config, Apps0, MFA) -> {comment, Mess} end; _ -> - ct:fail({length(CallsToMFA),calls_to_size_1}) + ct:fail({length(CallsToMFA),calls_to,MFA}) end. +all_otp_applications(Config) -> + Server = proplists:get_value(xref_server, Config), + {ok,AllApplications} = xref:q(Server, "A"), + OtpAppsMap = get_otp_applications(Config), + [App || App <- AllApplications, is_map_key(App, OtpAppsMap)]. + +get_otp_applications(Config) -> + DataDir = proplists:get_value(data_dir, Config), + [Current|_] = read_otp_version_table(DataDir), + read_version_lines([Current]). + is_present_application(Name, Server) -> Q = io_lib:format("~w : App", [Name]), case xref:q(Server, lists:flatten(Q)) of @@ -472,6 +482,189 @@ check_apps_deps([{App, Deps}|AppDeps], IgnoreApps) -> end end. +%% +%% Test that the runtime dependencies have not become stale. +%% + +%% Path of installed OTP releases. +-define(OTP_RELEASES, "/usr/local/otp/releases"). + +%% Wildcard to match all releases from OTP 17. +-define(OTP_RELEASE_WC, "{sles10_64_17_patched,ubuntu16_64_*_patched}"). + +test_runtime_dependencies_versions(Config) -> + DataDir = proplists:get_value(data_dir, Config), + + OtpReleases = ?OTP_RELEASES, + OtpReleasesWc = filename:join(OtpReleases, ?OTP_RELEASE_WC), + + IgnoreApps = [], + IgnoreUndefs = ignore_undefs(), + + FirstVersionForApp = get_first_app_versions(DataDir), + + case {element(1, os:type()) =:= unix, + not is_development_build(DataDir), + filelib:is_dir(OtpReleases)} of + {true, true, true} -> + test_runtime_dependencies_versions_rels( + IgnoreApps, + IgnoreUndefs, + FirstVersionForApp, + OtpReleasesWc); + {false, _, _} -> + {skip, "This test only runs on Unix systems"}; + {_, false, _} -> + {skip, + "This test case is designed to run in the Erlang/OTP teams " + "test system for daily tests. The test case depends on that " + "app versions have been set correctly by scripts that " + "are executed before creating builds for the daily tests."}; + {_, _ ,false} -> + {skip, "Can not do the tests without a proper releases dir. " + "Check that " ++ OtpReleases ++ " is set up correctly."} + end. + +ignore_undefs() -> + Socket = case lists:member(prim_socket, erlang:pre_loaded()) of + true -> + #{}; + false -> + Ignore = #{{prim_socket,'_','_'} => true, + {socket_registry,'_','_'} => true, + {prim_net,'_','_'} => true }, + #{kernel => Ignore, erts => Ignore} + end, + Socket#{eunit => + %% Intentional call to nonexisting function + #{{eunit_test, nonexisting_function, 0} => true}, + diameter => + %% The following functions are optional dependencies for diameter + #{{dbg,ctp,0} => true, + {dbg,p,2} => true, + {dbg,stop,0} => true, + {dbg,trace_port,2} => true, + {dbg,tracer,2} => true, + {erl_prettypr,format,1} => true, + {erl_syntax,form_list,1} => true}, + common_test => + %% ftp:start/0 has been part of the ftp application from + %% the beginning so it is unclear why xref report this + %% as undefined + #{{ftp,start,0} => true}}. + +%% Read the otp_versions.table file and create a mapping from application name +%% the first version for each application. +get_first_app_versions(DataDir) -> + Lines = read_otp_version_table(DataDir), + read_version_lines(Lines). + +test_runtime_dependencies_versions_rels(IgnoreApps, IgnoreUndefs, + FirstVersionForApp, OtpReleasesWc) -> + AppVersionToPath = version_to_path(OtpReleasesWc), + Deps = [Dep || {App,_,_}=Dep <- get_deps(FirstVersionForApp), + not lists:member(App, IgnoreApps)], + case test_deps(Deps, IgnoreUndefs, AppVersionToPath, FirstVersionForApp) of + [] -> + ok; + [_|_]=Undefs -> + _ = [print_undefs(Undef) || Undef <- Undefs], + ct:fail({length(Undefs),errors}) + end. + +print_undefs({_App,AppPath,Deps,Undefs}) -> + App = filename:basename(filename:dirname(AppPath)), + io:format("Undefined functions in ~ts:", [App]), + io:put_chars([io_lib:format(" ~p:~p/~p\n", [M,F,A]) || + {M,F,A} <- Undefs]), + io:format("Dependencies: ~ts\n", [lists:join(" ", Deps)]). + +version_to_path(OtpReleasesWc) -> + CurrentWc = filename:join([code:lib_dir(), "*-*", "ebin"]), + LibWc = filename:join([OtpReleasesWc, "lib", "*-*", "ebin"]), + Dirs = lists:sort(filelib:wildcard(CurrentWc) ++ filelib:wildcard(LibWc)), + All = [{filename:basename(filename:dirname(Dir)),Dir} || Dir <- Dirs], + maps:from_list(All). + +get_deps(FirstVersionForApp) -> + Paths = [begin + Dir = filename:dirname(Path), + [App0 | _] = string:split(filename:basename(Dir), "-"), + App = list_to_atom(App0), + AppFile = filename:join(Path, App0 ++ ".app"), + {Path, App, AppFile} + end || Path <- code:get_path(), + filename:basename(Path) =:= "ebin"], + %% Only keep applications included in OTP. + Apps = [Triple || {_, App, AppFile}=Triple <- Paths, + filelib:is_file(AppFile), + is_map_key(App, FirstVersionForApp)], + [{App, Path, get_runtime_deps(App, AppFile)} || {Path, App, AppFile} <- Apps]. + +get_runtime_deps(App, AppFile) -> + {ok,[{application, App, Info}]} = file:consult(AppFile), + case lists:keyfind(runtime_dependencies, 1, Info) of + {runtime_dependencies, RDeps} -> + RDeps; + false -> + [] + end. + +test_deps([{Name,Path,Deps}|Apps], IgnoreUndefs, AppVersionToPath, FirstVersionForApp) -> + case test_dep(Name, Path, Deps, AppVersionToPath, FirstVersionForApp, IgnoreUndefs) of + ok -> + test_deps(Apps, IgnoreUndefs, AppVersionToPath, FirstVersionForApp); + {error, Error} -> + [Error|test_deps(Apps, IgnoreUndefs, AppVersionToPath, FirstVersionForApp)] + end; +test_deps([], _IgnoreUndefs, _AppVersionToPath, _FirstVersionForApp) -> + []. + +test_dep(App, AppPath, Deps, AppVersionToPath, FirstVersionForApp, IgnoreUndefs) -> + DepPaths = [get_app_path(Dep, AppVersionToPath, FirstVersionForApp, App) || + Dep <- Deps], + + Server = xref_server_test_dep, + {ok, _} = xref:start(Server, []), + xref:set_default(Server, [{verbose,false}, + {warnings,false}, + {builtins,true}]), + ok = xref:set_library_path(Server, DepPaths), + {ok, _} = xref:add_directory(Server, AppPath), + {ok, Undef0} = xref:analyze(Server, undefined_functions), + xref:stop(Server), + + %% Filter out undefined functions that we should ignore. + Ignore = maps:get(App, IgnoreUndefs, #{}), + Undef = [MFA || {M,F,_A}=MFA <- Undef0, + not is_map_key(MFA, Ignore), + not is_map_key({M,'_','_'}, Ignore), + not is_map_key({M,F,'_'}, Ignore)], + case Undef of + [] -> + ok; + [_|_] -> + {error, {App, AppPath, Deps, Undef}} + end. + +get_app_path(App, AppVersionToPath, FirstVersionForApp, ReferencedBy) -> + case AppVersionToPath of + #{App := Path} -> + Path; + #{} -> + [Name0, _Version] = string:split(App, "-"), + Name = list_to_existing_atom(Name0), + First = map_get(Name, FirstVersionForApp), + io:format("WARNING: ~ts referenced by ~ts is too old; using ~ts instead\n", + [App, ReferencedBy, First]), + map_get(First, AppVersionToPath) + end. + +is_development_build(DataDir) -> + OTPVersionTicketsPath = filename:join(DataDir, "otp_version_tickets"), + {ok, FileContentBin} = file:read_file(OTPVersionTicketsPath), + string:trim(binary_to_list(FileContentBin), both, "\n ") =:= "DEVELOPMENT". + %%% %%% Common help functions. %%% @@ -541,3 +734,25 @@ start_xref_server(Server, Mode) -> end end, Server. + +read_otp_version_table(DataDir) -> + VersionTableFile = filename:join(DataDir, "otp_versions.table"), + {ok, Contents} = file:read_file(VersionTableFile), + binary:split(Contents, <<"\n">>, [global,trim]). + +read_version_lines(Lines) -> + read_version_lines(Lines, #{}). + +read_version_lines([Line|Lines], Map0) -> + [<<"OTP-",_/binary>>, <<":">> | Apps] = binary:split(Line, <<" ">>, [global,trim]), + Map = lists:foldl(fun(App, Acc) -> + case binary:split(App, <<"-">>) of + [Name, _Version] -> + Acc#{binary_to_atom(Name) => binary_to_list(App)}; + [_] -> + Acc + end + end, Map0, Apps), + read_version_lines(Lines, Map); +read_version_lines([], Map) -> + Map. diff --git a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args3 b/erts/test/otp_SUITE_data/.keep similarity index 100% rename from lib/dialyzer/test/race_SUITE_data/results/ets_insert_args3 rename to erts/test/otp_SUITE_data/.keep diff --git a/erts/test/parallel_messages_SUITE.erl b/erts/test/parallel_messages_SUITE.erl new file mode 100644 index 000000000000..9c5d6b4f2822 --- /dev/null +++ b/erts/test/parallel_messages_SUITE.erl @@ -0,0 +1,465 @@ +-module(parallel_messages_SUITE). + +-export([all/0, + suite/0, + test_throughput_benchmark/1, + test_message_queue_data_switching/1, + throughput_benchmark/0, + large_throughput_benchmark/0]). + +all() -> [test_throughput_benchmark, + test_message_queue_data_switching]. + +suite() -> + [{timetrap, {minutes, 90}}]. + +get_op([{_,O}], _RandNum) -> + O; +get_op([{Prob,O}|Rest], RandNum) -> + case RandNum < Prob of + true -> O; + false -> get_op(Rest, RandNum) + end. +do_op(ProbHelpTab, Operations, Receiver) -> + RandNum = rand:uniform(), + Op = get_op(ProbHelpTab, RandNum), + TheOp = Operations(Op), + TheOp(Receiver). +do_work(WorksDoneSoFar, ProbHelpTab, Operations, Receiver) -> + receive + stop -> WorksDoneSoFar + after + 0 -> do_op(ProbHelpTab, Operations, Receiver), + do_work(WorksDoneSoFar + 1, ProbHelpTab, Operations, Receiver) + end. + +-record(parallel_messages_bench_config, + {benchmark_duration_ms = 500, + recover_time_ms = 500, + thread_counts = not_set, + nr_of_repeats = 1, + report_receive_throughput = [false, true], + spawn_opts = [[{message_queue_data, off_heap}]], + scenarios = + [ + [ + {1.0, {message_size, 1}} + ], + [ + {1.0, {exit_signal_size, 3}} + ], + [ + {0.5, {exit_signal_size, 1}}, + {0.5, {message_size, 1}} + ] + ], + notify_res_fun = fun(_Name, _Throughput) -> ok end, + print_result_paths_fun = + fun(ResultPath, _LatestResultPath) -> + Comment = + io_lib:format("Result visualization",[ResultPath]), + {comment, Comment} + end + }). + +stdout_notify_res(ResultPath, LatestResultPath) -> + io:format("Result Location: /~s~n", [ResultPath]), + io:format("Latest Result Location: ~s~n", [LatestResultPath]). + + +throughput_benchmark( + #parallel_messages_bench_config{ + benchmark_duration_ms = BenchmarkDurationMs, + recover_time_ms = RecoverTimeMs, + thread_counts = ThreadCountsOpt, + nr_of_repeats = NrOfRepeats, + report_receive_throughput = ReportReceiveThroughputList, + spawn_opts = SpawnOptsList, + scenarios = Scenarios, + notify_res_fun = NotifyResFun, + print_result_paths_fun = PrintResultPathsFun}) -> + NrOfSchedulers = erlang:system_info(schedulers), + %Parent = self(), + %% Mapping benchmark operation names to their action + Operations = + fun({message_size, Size}) -> + case get(Size) of + undefined -> + Msg = lists:seq(1, Size), + NewSendFun = + fun(Receiver) -> + Receiver ! Msg + end, + put(Size, NewSendFun), + NewSendFun; + SendFun -> + SendFun + end; + ({exit_signal_size, Size} = SigType) -> + case get(SigType) of + undefined -> + Msg = lists:seq(1, Size), + NewSendFun = + fun(Receiver) -> + erlang:exit(Receiver, Msg) + end, + put(SigType, NewSendFun), + NewSendFun; + SendFun -> + SendFun + end; + ({message_queue_data_change, off_heap}) -> + fun(Receiver) -> + Receiver ! off_heap + end; + ({message_queue_data_change, on_heap}) -> + fun(Receiver) -> + Receiver ! on_heap + end + end, + %% Helper functions + CalculateThreadCounts = + fun Calculate([Count|Rest]) -> + case Count > NrOfSchedulers of + true -> lists:reverse(Rest); + false -> Calculate([Count*2,Count|Rest]) + end + end, + CalculateOpsProbHelpTab = + fun Calculate([{_, OpName}], _) -> + [{1.0, OpName}]; + Calculate([{OpPropability, OpName}|Res], Current) -> + NewCurrent = Current + OpPropability, + [{NewCurrent, OpName}| Calculate(Res, NewCurrent)] + end, + RenderScenario = + fun R([], StringSoFar) -> + StringSoFar; + R([{Fraction, Operation}], StringSoFar) -> + io_lib:format("~s ~f% ~w",[StringSoFar, Fraction * 100.0, Operation]); + R([{Fraction, Operation}|Rest], StringSoFar) -> + R(Rest, + io_lib:format("~s ~f% ~w, ",[StringSoFar, Fraction * 100.0, Operation])) + end, + DataHolder = + fun DataHolderFun(Data)-> + receive + {get_data, Pid} -> Pid ! {message_bench_data, Data}; + D -> DataHolderFun([Data,D]) + end + end, + DataHolderPid = spawn_link(fun()-> DataHolder([]) end), + PrintData = + fun (Str, List) -> + io:format(Str, List), + DataHolderPid ! io_lib:format(Str, List) + end, + GetData = + fun () -> + DataHolderPid ! {get_data, self()}, + receive {message_bench_data, Data} -> Data end + end, + %% Function that runs a benchmark instance and returns the number + %% of operations that were performed and how long time they took + %% to perform + RunBenchmark = + fun({NrOfProcs, Scenario, Duration, SpawnOpts}) -> + ProbHelpTab = CalculateOpsProbHelpTab(Scenario, 0), + ParentPid = self(), + ReceiveFun = + fun ReceiveFun(NrOfStops, ReceiveCount) when NrOfStops =:= NrOfProcs -> + ParentPid ! {done_nothing_more_to_receive, ReceiveCount}; + ReceiveFun(NrOfStops, ReceiveCount) -> + receive + Msg -> + case Msg of + stop -> + ReceiveFun(NrOfStops + 1, ReceiveCount); + off_heap -> + erlang:process_flag(message_queue_data, off_heap), + ReceiveFun(NrOfStops, ReceiveCount + 1); + on_heap -> + erlang:process_flag(message_queue_data, on_heap), + ReceiveFun(NrOfStops, ReceiveCount + 1); + _X -> + ReceiveFun(NrOfStops, ReceiveCount + 1) + end + end + end, + Receiver = + spawn_opt( + fun() -> + process_flag(trap_exit, true), + ReceiveFun(0, 0) + end, + SpawnOpts), + Worker = + fun() -> + receive start -> ok end, + WorksDone = + do_work(0, ProbHelpTab, Operations, Receiver), + ParentPid ! {works_done, WorksDone}, + Receiver ! stop + end, + ChildPids = + lists:map(fun(_N) -> spawn_link(Worker) end, lists:seq(1, NrOfProcs)), + erlang:garbage_collect(), + timer:sleep(RecoverTimeMs), + lists:foreach(fun(Pid) -> Pid ! start end, ChildPids), + timer:sleep(Duration), + lists:foreach(fun(Pid) -> Pid ! stop end, ChildPids), + TotalWorksDone = lists:foldl( + fun(_, Sum) -> + receive + {works_done, Count} -> Sum + Count + end + end, 0, ChildPids), + {TimeAfterSends, ok} = + timer:tc( + fun() -> + receive + {done_nothing_more_to_receive, ReceiveCount} -> + %% Sanity check + ReceiveCount = TotalWorksDone, + ok + end + end), + {Duration + (TimeAfterSends div 1000), TotalWorksDone} + end, + RunBenchmarkInSepProcess = + fun(ParameterTuple) -> + P = self(), + Results = + [begin + spawn_link(fun()-> P ! {bench_result, RunBenchmark(ParameterTuple)} end), + receive {bench_result, Res} -> Res end + end || _ <- lists:seq(1, NrOfRepeats)], + {R1, R2} = lists:foldl(fun ({I1, I2}, {A1, A2}) -> + {I1 + A1, I2 + A2} + end, {0, 0}, Results), + {R1 / NrOfRepeats, R2 / NrOfRepeats} + end, + RunBenchmarkAndReport = + fun(ThreadCount, + Scenario, + Duration, + ReportReceive, + SpawnOpts) -> + {ReceiveTime, NrOfSends} = + RunBenchmarkInSepProcess({ThreadCount, + Scenario, + Duration, + SpawnOpts}), + Throughput = + case ReportReceive of + true -> + NrOfSends/(ReceiveTime/1000.0); + false -> + NrOfSends/(Duration/1000.0) + end, + PrintData("; ~f",[Throughput]), + Name = io_lib:format("Scenario: ~w, " + "# of Processes: ~w", + [Scenario, ThreadCount]), + NotifyResFun(Name, Throughput) + end, + ThreadCounts = + case ThreadCountsOpt of + not_set -> + CalculateThreadCounts([1]); + _ -> ThreadCountsOpt + end, + Version = + (fun() -> + VersionString = erlang:system_info(system_version), + case re:run(VersionString, "\\[(source\\-[^\\]]+)\\]") of + {match, [_, {StartPos, Length}]} -> + string:slice(VersionString, StartPos, Length); + _ -> + erlang:system_info(otp_release) + end + end)(), + %% Run the benchmark + PrintData("# Each instance of the benchmark runs for ~w seconds:~n", [BenchmarkDurationMs/1000]), + PrintData("# The result of a benchmark instance is presented as a number representing~n",[]), + PrintData("# the number of operations performed per second:~n~n~n",[]), + PrintData("# To plot graphs for the results below:~n",[]), + PrintData("# 1. Open \"$ERL_TOP/erts/test/parallel_messages_SUITE_data/visualize_throughput.html\" in a web browser~n",[]), + PrintData("# 2. Copy the lines between \"#BENCHMARK STARTED$\" and \"#BENCHMARK ENDED$\" below~n",[]), + PrintData("# 3. Paste the lines copied in step 2 to the text box in the browser window opened in~n",[]), + PrintData("# step 1 and press the Render button~n~n",[]), + PrintData("#BENCHMARK STARTED$~n",[]), + %% The following loop runs all benchmark scenarios and prints the results (i.e, operations/second) + lists:foreach( + fun(SpawnOpts) -> + lists:foreach( + fun(Scenario) -> + lists:foreach( + fun(ReportReceiveThroughput) -> + PrintData("Scenario: ~s, send_duration=~w ms, ~s, Spawn Options=~w$~n", + [case ReportReceiveThroughput of + true -> "Receive Throughput"; + false -> "Send Throughput" + end, + BenchmarkDurationMs, + RenderScenario(Scenario, ""), + SpawnOpts]), + lists:foreach( + fun(ThreadCount) -> + PrintData("; ~w",[ThreadCount]) + end, + ThreadCounts), + PrintData("$~n",[]), + PrintData(Version,[]), + lists:foreach( + fun(ThreadCount) -> + %erlang:display({thread_count, ThreadCount}), + RunBenchmarkAndReport(ThreadCount, + Scenario, + BenchmarkDurationMs, + ReportReceiveThroughput, + SpawnOpts) + end, + ThreadCounts), + PrintData("$~n",[]) + end, + ReportReceiveThroughputList) + end, + Scenarios) + end, + SpawnOptsList), + PrintData("~n#BENCHMARK ENDED$~n~n",[]), + DataDir = filename:join(filename:dirname(code:which(?MODULE)), "parallel_messages_SUITE_data"), + TemplatePath = filename:join(DataDir, "visualize_throughput.html"), + {ok, Template} = file:read_file(TemplatePath), + OutputData = string:replace(Template, "#bench_data_placeholder", GetData()), + OutputPath1 = filename:join(DataDir, "message_bench_result.html"), + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_datetime(erlang:timestamp()), + StrTime = lists:flatten(io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w",[Year,Month,Day,Hour,Minute,Second])), + OutputPath2 = filename:join(DataDir, io_lib:format("message_bench_result_~s.html", [StrTime])), + file:write_file(OutputPath1, OutputData), + file:write_file(OutputPath2, OutputData), + PrintResultPathsFun(OutputPath2, OutputPath1). + + +throughput_benchmark() -> + throughput_benchmark( + #parallel_messages_bench_config{ + benchmark_duration_ms = 500, + recover_time_ms = 500, + thread_counts = not_set, + nr_of_repeats = 1, + report_receive_throughput = [false, true], + spawn_opts = [[{message_queue_data, off_heap}]], + scenarios = + [ + [ + {1.0, {message_size, 1}} + ], + [ + {1.0, {exit_signal_size, 3}} + ], + [ + {0.5, {exit_signal_size, 1}}, + {0.5, {message_size, 1}} + ] + ], + notify_res_fun = fun(_Name, _Throughput) -> ok end, + print_result_paths_fun = + fun(ResultPath, _LatestResultPath) -> + Comment = + io_lib:format("Result visualization",[ResultPath]), + {comment, Comment} + end + }). + +test_throughput_benchmark(_) -> + throughput_benchmark(). + +large_throughput_benchmark() -> + throughput_benchmark( + #parallel_messages_bench_config{ + benchmark_duration_ms = 1000, + recover_time_ms = 1000, + thread_counts = [1,2,4,8,15,16,31,32,47,48,63,64], + nr_of_repeats = 3, + report_receive_throughput = [false, true], + spawn_opts = [[{message_queue_data, off_heap}]], + scenarios = + [ + [ + {1.0, {message_size, 1}} + ], + [ + {1.0, {message_size, 10}} + ], + [ + {1.0, {message_size, 100}} + ], + [ + {1.0, {message_size, 1000}} + ], + [ + {1.0, {exit_signal_size, 1}} + ], + [ + {1.0, {exit_signal_size, 10}} + ], + [ + {1.0, {exit_signal_size, 100}} + ], + [ + {1.0, {exit_signal_size, 1000}} + ], + [ + {0.5, {exit_signal_size, 1}}, + {0.5, {message_size, 1}} + ], + [ + {0.5, {exit_signal_size, 10}}, + {0.5, {message_size, 10}} + ], + [ + {0.5, {exit_signal_size, 100}}, + {0.5, {message_size, 100}} + ], + [ + {0.5, {exit_signal_size, 1000}}, + {0.5, {message_size, 1000}} + ] + ], + notify_res_fun = + fun(Name, Throughput) -> + io:format("~n~n#Name: ~s Throughput: ~w~n~n", [Name, Throughput]) + end, + print_result_paths_fun = + fun stdout_notify_res/2 + }). + +test_message_queue_data_switching(_) -> + throughput_benchmark( + #parallel_messages_bench_config{ + benchmark_duration_ms = 100, + recover_time_ms = 500, + thread_counts = [1,2,4], + nr_of_repeats = 1, + report_receive_throughput = [true], + spawn_opts = [[{message_queue_data, off_heap}]], + scenarios = + [ + [ + {0.499995, {exit_signal_size, 1}}, + {0.499995, {message_size, 1}}, + %% About 1 in 100k changes message data type + {0.000005, {message_queue_data_change, off_heap}}, + {0.000005, {message_queue_data_change, on_heap}} + ] + ], + notify_res_fun = fun(_Name, _Throughput) -> ok end, + print_result_paths_fun = + fun(ResultPath, _LatestResultPath) -> + Comment = + io_lib:format("Result visualization",[ResultPath]), + {comment, Comment} + end + }). diff --git a/erts/test/parallel_messages_SUITE_data/visualize_throughput.html b/erts/test/parallel_messages_SUITE_data/visualize_throughput.html new file mode 100644 index 000000000000..c4ed94b679a8 --- /dev/null +++ b/erts/test/parallel_messages_SUITE_data/visualize_throughput.html @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Message Send/Receive Benchmark Result Viewer + + + +
+

Message Send/Receive Benchmark Result Viewer

+

+ This page generates graphs from data produced by the Message Send/Receive Benchmark which is defined in the function parallel_messages_SUITE:test_throughput_benchmark/1 (see "$ERL_TOP/erts/test/parallel_messages_SUITE.erl"). +

+

+ Note that one can paste results from several benchmark runs into the field below. Results from the same scenario but from different benchmark runs will be relabeled and plotted in the same graph automatically. +

+

+ Note also that that lines can be hidden by clicking on the corresponding label. +

+ Paste the generated data in the field below and press the Render button: +
+ +
+ Include Throughput Plot +
+ Include % More Throughput Than Worst Plot +
+ Include % Less Throughput Than Best Plot +
+ Bar Plot +
+ Same X Spacing Between Points +
+ + + + + + + + diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl index 3a0e4e160040..9c26852e0057 100644 --- a/erts/test/upgrade_SUITE.erl +++ b/erts/test/upgrade_SUITE.erl @@ -20,7 +20,7 @@ -compile(export_all). --compile(r21). +-compile(r22). -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl index 18a42f7c28c7..d6120061db31 100644 --- a/erts/test/z_SUITE.erl +++ b/erts/test/z_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -26,7 +26,8 @@ -include_lib("kernel/include/file.hrl"). --record(core_search_conf, {search_dir, +-record(core_search_conf, {db_top_dir, + search_dir, extra_search_dir, cerl, file, @@ -113,7 +114,8 @@ core_search_conf(RunByTS, DBTop, XDir) -> _ -> XDir end end, - #core_search_conf{search_dir = SearchDir, + #core_search_conf{db_top_dir = DBTop, + search_dir = SearchDir, extra_search_dir = XSearchDir, cerl = find_cerl(DBTop), file = os:find_executable("file"), @@ -326,11 +328,59 @@ core_file_search(#core_search_conf{search_dir = Base, case {RunByTS, ICores, FCores} of {true, [], []} -> ok; {true, _, []} -> {comment, Res}; - {true, _, _} -> ct:fail(Res); - _ -> Res + {true, _, _} -> + docker_export_otp_src(Conf), + ct:fail(Res); + _ -> + Res end end. +docker_export_otp_src(#core_search_conf{db_top_dir = DbTop}) -> + %% If this is a docker run, export the otp_src directory + %% to not get lost when the docker image is purged. + try + case {is_dir(DbTop), is_dir("/daily_build/otp_src/erts")} of + {true, true} -> + %% Stolen from get_otp_src script. + %% Basically it's a recursive copy of otp_src dir + %% with preserved permissions, etc. + run("cd /daily_build && " + "tar -cf - otp_src | (cd "++DbTop++" && tar -xpf -)"), + OtpSrc = DbTop ++ "/otp_src", + run("cd " ++ OtpSrc ++ "/erts && " + "ERL_TOP=" ++ OtpSrc ++ " make local_setup"), + io:format("otp_src directory exported from docker image"); + _ -> + ok + end + catch + C:E:S -> + io:format("Failed to export otp_src directory:" + "Exception: ~p\nReason: ~p\nStack: ~p\n", + [C, E, S]) + end. + +run(Cmd) -> + Options = [binary, exit_status,stderr_to_stdout,{line,4096}], + Port = open_port({spawn,"sh -c \"" ++ Cmd ++ "\""}, Options), + run_loop(Cmd, Port, []). + +run_loop(Cmd, Port, Output) -> + receive + {Port, {exit_status,0}} -> + lists:reverse(Output); + {Port, {exit_status,Status}} -> + io:format("Failed command (~p): ~p\nOutput: ~p\n", [Status, Cmd, Output]), + error(bailout); + {Port, {data,{eol,Bin}}} -> + run_loop(Cmd, Port, [Bin|Output]); + Msg -> + io:format("Unexpected message: ~p\nCommand was: ~p\n", [Msg, Cmd]), + error(bailout) + end. + + win32_search(RunByTS, DBTop) -> case os:getenv("WSLENV") of false when RunByTS -> diff --git a/erts/vsn.mk b/erts/vsn.mk index f33d834d19c3..9177d3f635fb 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 12.3.2.13 +VSN = 14.1 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/Makefile b/lib/Makefile index 067f00787b53..465e1073e900 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -56,28 +56,11 @@ ifdef BUILD_STATIC_LIBS SUB_DIRECTORIES = asn1 crypto else ifdef BOOTSTRAP - SUB_DIRECTORIES = \ - kernel stdlib compiler - else - ifdef SECONDARY_BOOTSTRAP - ifdef TINY_BUILD - SUB_DIRECTORIES = parsetools sasl - else - SUB_DIRECTORIES = parsetools asn1/src - endif - else - ifdef TERTIARY_BOOTSTRAP - SUB_DIRECTORIES = snmp sasl erl_interface jinterface syntax_tools wx public_key - else - ifdef DOC_BOOTSTRAP - SUB_DIRECTORIES = xmerl edoc erl_docgen public_key - else # Not bootstrap build - SUB_DIRECTORIES = $(ERTS_APPLICATIONS) \ - $(ERLANG_APPLICATIONS) \ - $(EXTRA_APPLICATIONS) - endif - endif - endif + SUB_DIRECTORIES = $(BOOTSTRAP) + else # Not bootstrap build + SUB_DIRECTORIES = $(ERTS_APPLICATIONS) \ + $(ERLANG_APPLICATIONS) \ + $(EXTRA_APPLICATIONS) endif endif diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile index 8fb3360f8388..82a6b6e87ac7 100644 --- a/lib/asn1/c_src/Makefile +++ b/lib/asn1/c_src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2021. All Rights Reserved. +# Copyright Ericsson AB 2002-2022. 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. @@ -99,7 +99,8 @@ _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) opt: $(NIF_SHARED_OBJ_FILE) -debug: opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt static_lib: $(NIF_LIB_FILE) diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 0258f7fbd2f6..c8234a2cdb1c 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2021. All Rights Reserved. + * Copyright Ericsson AB 2002-2023. 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. @@ -228,7 +228,7 @@ static int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf, case 30: /* If we call the following bytes, in the buffer in_ptr points at, - By1,By2,Rest then Rest is the value that will be transfered to + By1,By2,Rest then Rest is the value that will be transferred to the completed buffer. By1 tells how many of the rightmost bits in Rest that should not be used. By2 is the length of Rest in bytes.*/ in_unused = (int) *(++in_ptr); @@ -245,7 +245,7 @@ static int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf, case 31: /* If we call the following bytes, in the buffer in_ptr points at, - By1,By2,By3,Rest then Rest is the value that will be transfered to + By1,By2,By3,Rest then Rest is the value that will be transferred to the completed buffer. By1 tells how many of the rightmost bits in Rest that should not be used. By2 and By3 is the length of Rest in bytes.*/ @@ -834,7 +834,7 @@ static int per_insert_octets_except_unused(int no_bytes, unsigned char **input_p * List is like: [{TagNo,Value},{TagNo,Value},...] * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest * is the empty binary. - * If some error occured during the decoding of the in_buf an error is returned. + * If some error occurred during the decoding of the in_buf an error is returned. */ static int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int in_buf_len, unsigned int *err_pos) { @@ -1087,7 +1087,7 @@ static int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, uns } } - // We need atleast 5 bytes to encode the next tlv + // We need at least 5 bytes to encode the next tlv if (ber_check_memory(curr, 3)) return ASN1_ERROR; @@ -1167,7 +1167,7 @@ static mem_chunk_t *ber_new_chunk(unsigned int length) { new->next = NULL; new->top = enif_alloc(sizeof(char) * length); if (new->top == NULL) { - free(new); + enif_free(new); return NULL; } new->curr = new->top + length - 1; diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index e4c5a2a3eeb1..7b38499d483a 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -4,7 +4,7 @@
- 19972020 + 19972022 Ericsson AB. All Rights Reserved. @@ -83,7 +83,7 @@ legacy_bit_string | legacy_erlang_types | noobj | {n2n, EnumTypeName} |{outdir, Dir} | {i, IncludeDir} | asn1config | undec_rest | no_ok_wrapper | - {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors + {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors | deterministic OldOption = ber | per Reason = term() Prefix = string() @@ -346,6 +346,11 @@ File3.asn

Causes warnings to be treated as errors.

+ deterministic + +

Causes all non-deterministic options to be stripped from the + -asn1_info() attribute.

+

Any more option that is applied is passed to the final step when the generated .erl file is compiled. diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index 544974a13e2c..c53f969384a0 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -4,7 +4,7 @@

- 20042021 + 20042022 Ericsson AB. All Rights Reserved. @@ -32,6 +32,132 @@

This document describes the changes made to the asn1 application.

+
Asn1 5.2 + +
Fixed Bugs and Malfunctions + + +

The ASN.1 compiler would ignore a constraint such as + (SIZE (1..4), ...), causing incorrect behavior of + the encoding and decoding function for the PER and UPER + backends. Corrected to handle the constraint in the same + way as (SIZE (1..4, ...)).

+

+ Own Id: OTP-18729 Aux Id: PR-7575

+
+
+
+ + +
Improvements and New Features + + +

The JER backend has been internally refactored in a + way that is compatible for applications that use the + documented API. However, for a group of ASN.1 modules + that depend on each other (for example, + S1AP-PDU-Descriptions, S1AP-Contents, and so on), + all modules in the group must be recompiled if on of the + group members is recompiled.

+

+ Own Id: OTP-18748 Aux Id: ERIERL-957, PR-7637

+
+
+
+ +
+ +
Asn1 5.1 + +
Fixed Bugs and Malfunctions + + +

+ The ASN.1 compiler used to reject correctly specified + RELATIVE-OID values containing other RELATIVE-OID values. + This is now corrected.

+

+ Own Id: OTP-18534 Aux Id: ERIERL-737, PR-7039

+
+
+
+ + +
Improvements and New Features + + +

Minor code improvements.

+

+ Own Id: OTP-18441

+
+ +

Handling of on_load modules during boot has + been improved by adding an extra step in the boot order + for embedded mode that runs all on_load handlers, + instead of relying on explicit invocation of them, later, + when the kernel supervision tree starts.

This is + mostly a code improvement and OTP internal simplification + to avoid future bugs and to simplify code maintenance. +

+

+ Own Id: OTP-18447

+
+
+
+ +
+ +
Asn1 5.0.21 + +
Fixed Bugs and Malfunctions + + +

For the per and uper ASN.1 encoding + rules, encoding and decoding the SEQUENCE OF and + SET OF constructs with 16384 items or more is now + supported.

+

+ Own Id: OTP-18245 Aux Id: ERIERL-859

+
+
+
+ +
+ +
Asn1 5.0.20 + +
Improvements and New Features + + +

There is a new configure option, + --enable-deterministic-build, which will apply the + deterministic compiler option when building + Erlang/OTP. The deterministic option has been + improved to eliminate more sources of non-determinism in + several applications.

+

+ Own Id: OTP-18165 Aux Id: PR-5965

+
+
+
+ +
+ +
Asn1 5.0.19 + +
Fixed Bugs and Malfunctions + + +

The atom maybe has been quoted in the source + code.

+

+ Own Id: OTP-17980

+
+
+
+ +
+
Asn1 5.0.18.1
Fixed Bugs and Malfunctions @@ -360,7 +486,7 @@ decoding a recursively enclosed term the length was not propagated to that term decoding, so if the length of the enclosed term was longer than the enclosing that error - was not dectected

A hard coded C stack limitation + was not detected

A hard coded C stack limitation for decoding recursive ASN.1 terms has been introduced. This is currently set to 8 kWords giving a nesting depth of about 1000 levels. Deeper terms can not be decoded, @@ -422,7 +548,7 @@

Compiling an ASN.1 module using the option {n2n, - EnumTypeName} when EnumTypeName contains a hypen like for + EnumTypeName} when EnumTypeName contains a hyphen like for example Cause-Misc caused syntax errors when compiling the generated Erlang code. This is now corrected.

@@ -1077,7 +1203,7 @@

The ASN.1 compiler will now always include necessary run-time functions in the generated Erlang modules - (except for asn1rt_nif which is still neeeded). If + (except for asn1rt_nif which is still needed). If the option 'inline' is used the ASN.1 compiler will generate a warning. But if '{inline,OutputFile}' is use, the ASN.1 compiler diff --git a/lib/asn1/examples/ecn_internaldoc.txt b/lib/asn1/examples/ecn_internaldoc.txt index 71e2b7a2f1af..909adc6fe82a 100644 --- a/lib/asn1/examples/ecn_internaldoc.txt +++ b/lib/asn1/examples/ecn_internaldoc.txt @@ -27,7 +27,7 @@ enable the use of ECN in the OTP ASN1 compiler. - Unaligned PER backend. Often seems the unaligned PER encoding as the prefferred main method in ECN applications. One of the goals with ECN is to use less space for encoding to decrease - the use of bandwith in transmission. This goal is highly + the use of bandwidth in transmission. This goal is highly supported by unaligned PER. diff --git a/lib/asn1/examples/encode_decode_formats.txt b/lib/asn1/examples/encode_decode_formats.txt index 62774cf13bd9..5b5748c196a9 100644 --- a/lib/asn1/examples/encode_decode_formats.txt +++ b/lib/asn1/examples/encode_decode_formats.txt @@ -13,4 +13,4 @@ per_bin, optimize | binary | binary | -iolist: deep list with binaries and lists as componets \ No newline at end of file +iolist: deep list with binaries and lists as components \ No newline at end of file diff --git a/lib/asn1/notes.html b/lib/asn1/notes.html index c7da5496c823..9e3feefef7dd 100644 --- a/lib/asn1/notes.html +++ b/lib/asn1/notes.html @@ -52,7 +52,7 @@

Fixed errors and malfunctions

  • An error due to unchecked referenced imported type resulted in missing tag in some table constraint cases. This error is - now corrected. Error occured during decode in + now corrected. Error occurred during decode in ber_bin optimized version. (Own Id: OTP-5022)

  • @@ -103,7 +103,7 @@

    Fixed errors and malfunctions

  • - Object Identifier values with two components and teh first was a + Object Identifier values with two components and the first was a value reference failed due to parsing conflicts. Now it is corrected. (Own Id: OTP-4895)

    @@ -195,12 +195,12 @@

    Fixed errors and malfunctions

    diff --git a/lib/kernel/test/ram_file_SUITE_data/realmen.html b/lib/kernel/test/ram_file_SUITE_data/realmen.html index c810a5d088f3..eaaa65523a9f 100644 --- a/lib/kernel/test/ram_file_SUITE_data/realmen.html +++ b/lib/kernel/test/ram_file_SUITE_data/realmen.html @@ -121,7 +121,7 @@

    STRUCTURED PROGRAMMING

    Programmers know, the only useful data structure is the array. Strings, lists, structures, sets -- these are all special cases of arrays and and can be treated that way just as easily without -messing up your programing language with all sorts of +messing up your programming language with all sorts of complications. The worst thing about fancy data types is that you have to declare them, and Real Programming Languages, as we all know, have implicit typing based on the first letter of the (six character) @@ -237,7 +237,7 @@

    PROGRAMMING TOOLS

    impossible to modify the operating system code with negative subscripts. Worst of all, bounds checking is inefficient. -
  • Source code maintainance systems. A Real Programmer keeps his +
  • Source code maintenance systems. A Real Programmer keeps his code locked up in a card file, because it implies that its owner cannot leave his important programs unguarded [5]. @@ -318,7 +318,7 @@

    THE REAL PROGRAMMER AT WORK

    it, providing there's enough money in it. There are several Real Programmers building video games at Atari, for example. (But not playing them. A Real Programmer knows how to beat the machine every -time: no challange in that.) Everyone working at LucasFilm is a Real +time: no challenge in that.) Everyone working at LucasFilm is a Real Programmer. (It would be crazy to turn down the money of 50 million Star Wars fans.) The proportion of Real Programmers in Computer Graphics is somewhat lower than the norm, mostly because nobody has @@ -384,7 +384,7 @@

    THE REAL PROGRAMMER'S NATURAL HABITAT

    and the Principles of Operation open to some particularly interesting pages. -
  • Taped to the wall is a line-printer Snoopy calender for the year +
  • Taped to the wall is a line-printer Snoopy calendar for the year 1969.
  • Strewn about the floor are several wrappers for peanut butter @@ -396,7 +396,7 @@

    THE REAL PROGRAMMER'S NATURAL HABITAT

  • Underneath the Oreos is a flow-charting template, left there by the previous occupant of the office. (Real Programmers write programs, -not documentation. Leave that to the maintainence people.) +not documentation. Leave that to the maintenance people.)

    diff --git a/lib/kernel/test/rpc_SUITE.erl b/lib/kernel/test/rpc_SUITE.erl index 90ca4addcdbd..8f77a9a30e31 100644 --- a/lib/kernel/test/rpc_SUITE.erl +++ b/lib/kernel/test/rpc_SUITE.erl @@ -44,6 +44,13 @@ -include_lib("common_test/include/ct.hrl"). +-ifndef(CT_PEER). +%% This module needs to compile on old nodes... +-define(CT_PEER(), {ok, undefined, undefined}). +-define(CT_PEER(Opts), {ok, undefined, undefined}). +-define(CT_PEER_REL(Opts, Release, PrivDir), {ok, undefined, undefined}). +-endif. + suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. @@ -89,17 +96,11 @@ off_heap(_Config) -> %% Test different rpc calls. call(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - %% Note. First part of nodename sets response delay in seconds - {ok, N1} = test_server:start_node('3_rpc_SUITE_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('1_rcp_SUITE_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N3} = test_server:start_node('4_rcp_SUITE_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N4} = test_server:start_node('8_rcp_SUITE_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - ok = io:format("~p~n", [[N1, N2, N3]]), + {ok, _P1, N1} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "3"]), + {ok, _P2, N2} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "1"]), + {ok, _P3, N3} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "4"]), + {ok, _P4, N4} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "8"]), + ok = io:format("~p~n", [[N1, N2, N3, N4]]), {hej,_,N1} = rpc:call(N1, ?MODULE, f, []), {hej,_,N2} = rpc:call(N2, ?MODULE, f, [], 2000), {badrpc,timeout} = rpc:call(N3, ?MODULE, f, [], 2000), @@ -107,10 +108,6 @@ call(Config) when is_list(Config) -> [] = flush([]), {hej,_,N4} = rpc:call(N4, ?MODULE, f, []), {badrpc, nodedown} = rpc:call(gurka, ?MODULE, f, []), - test_server:stop_node(N1), - test_server:stop_node(N2), - test_server:stop_node(N3), - test_server:stop_node(N4), ok. @@ -120,9 +117,9 @@ call_reqtmo(Config) when is_list(Config) -> [self(), SendMe], Timeout) end, - reqtmo_test(Config, Fun). + reqtmo_test(Fun). -reqtmo_test(Config, Test) -> +reqtmo_test(Test) -> %% Tests that we time out in time also when the request itself %% does not get through. A typical issue we have had %% in the past, is that the timeout has not triggered until @@ -132,7 +129,7 @@ reqtmo_test(Config, Test) -> WaitBlock = 100, BlockTime = 1000, - {ok, Node} = start_node(Config), + {ok, Peer, Node} = ?CT_PEER(), erpc:call(Node, erts_debug, set_internal_state, [available_internal_state, true]), @@ -158,7 +155,7 @@ reqtmo_test(Config, Test) -> after 0 -> ok end, - stop_node(Node), + peer:stop(Peer), {comment, "Timeout = " ++ integer_to_list(Timeout) @@ -167,16 +164,10 @@ reqtmo_test(Config, Test) -> %% Test different rpc calls. block_call(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - %% Note. First part of nodename sets response delay in seconds - {ok, N1} = test_server:start_node('3_rpc_SUITE_block_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('1_rcp_SUITE_block_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N3} = test_server:start_node('4_rcp_SUITE_block_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N4} = test_server:start_node('8_rcp_SUITE_block_call', slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, _P1, N1} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "3"]), + {ok, _P2, N2} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "1"]), + {ok, _P3, N3} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "4"]), + {ok, _P4, N4} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "8"]), ok = io:format("~p~n", [[N1, N2, N3]]), {hej,_,N1} = rpc:block_call(N1, ?MODULE, f, []), {hej,_,N2} = rpc:block_call(N2, ?MODULE, f, [], 2000), @@ -184,56 +175,36 @@ block_call(Config) when is_list(Config) -> receive after 6000 -> ok end, [] = flush([]), {hej,_,N4} = rpc:block_call(N4, ?MODULE, f, []), - test_server:stop_node(N1), - test_server:stop_node(N2), - test_server:stop_node(N3), - test_server:stop_node(N4), ok. %% OTP-3449. multicall(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - %% Note. First part of nodename sets response delay in seconds - {ok, N1} = test_server:start_node('3_rpc_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('1_rcp_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, _P1, N1} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "3"]), + {ok, _P2, N2} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "1"]), ok = io:format("~p~n", [[N1, N2]]), {[{hej,_,N1},{hej,_,N2}],[]} = rpc:multicall([N1, N2], ?MODULE, f, []), Msgs = flush([]), [] = Msgs, - test_server:stop_node(N1), - test_server:stop_node(N2), ok. multicall_timeout(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - %% Note. First part of nodename sets response delay in seconds - {ok, N1} = test_server:start_node('11_rpc_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('8_rpc_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N3} = test_server:start_node('5_rpc_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N4} = test_server:start_node('2_rcp_SUITE_multicall', slave, - [{args, "-connect_all false -pa " ++ PA}]), - ok = io:format("~p~n", [[N1, N2]]), + {ok, _P1, N1} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "11"]), + {ok, _P2, N2} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "8"]), + {ok, _P3, N3} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "5"]), + {ok, _P4, N4} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "2"]), + ok = io:format("~p~n", [[N1, N2, N3, N4]]), {[{hej,_,N3},{hej,_,N4}],[N1, N2]} = rpc:multicall([N3, N1, N2, N4], ?MODULE, f, [], 6000), ct:sleep({seconds,8}), %Wait for late answers Msgs = flush([]), [] = Msgs, - test_server:stop_node(N1), - test_server:stop_node(N2), - test_server:stop_node(N3), - test_server:stop_node(N4), ok. multicall_reqtmo(Config) when is_list(Config) -> - {ok, QuickNode1} = start_node(Config), - {ok, QuickNode2} = start_node(Config), + {ok, Peer1, QuickNode1} = ?CT_PEER(), + {ok, Peer2, QuickNode2} = ?CT_PEER(), Fun = fun (Node, SendMe, Timeout) -> Me = self(), SlowSend = fun () -> @@ -249,18 +220,15 @@ multicall_reqtmo(Config) when is_list(Config) -> erlang, apply, [SlowSend, []], Timeout) end, - Res = reqtmo_test(Config, Fun), - stop_node(QuickNode1), - stop_node(QuickNode2), + Res = reqtmo_test(Fun), + peer:stop(Peer1), + peer:stop(Peer2), Res. multicall_dies(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - {ok, N1} = test_server:start_node('rpc_SUITE_multicall_dies_1', slave, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('rcp_SUITE_multicall_dies_2', slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, P1, N1} = ?CT_PEER(["-connect_all", "false"]), + {ok, P2, N2} = ?CT_PEER(["-connect_all", "false"]), Nodes = [N1, N2], %% {[{badrpc, {'EXIT', normal}}, {badrpc, {'EXIT', normal}}], []} = @@ -290,8 +258,8 @@ multicall_dies(Config) when is_list(Config) -> {[{badrpc, {'EXIT', killed}}, {badrpc, {'EXIT', killed}}], []} = do_multicall(Nodes, ?MODULE, suicide, [exit, kill]), %% - test_server:stop_node(N1), - test_server:stop_node(N2), + peer:stop(P1), + peer:stop(P2), ok. do_multicall(Nodes, Mod, Func, Args) -> @@ -311,11 +279,8 @@ multicall_node_dies(Config) when is_list(Config) -> do_multicall_2_nodes_dies(Mod, Func, Args) -> ok = io:format("~p:~p~p~n", [Mod, Func, Args]), - PA = filename:dirname(code:which(?MODULE)), - {ok, N1} = test_server:start_node('rpc_SUITE_multicall_node_dies_1', peer, - [{args, "-connect_all false -pa " ++ PA}]), - {ok, N2} = test_server:start_node('rcp_SUITE_multicall_node_dies_2', peer, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, _P1, N1} = ?CT_PEER(#{connection => 0, args => ["-connect_all", "false"]}), + {ok, _P2, N2} = ?CT_PEER(#{connection => 0, args => ["-connect_all", "false"]}), Nodes = [N1, N2], case {Mod, Func, rpc:multicall(Nodes, Mod, Func, Args)} of {_, _, {[], Nodes}} -> @@ -336,9 +301,7 @@ do_multicall_2_nodes_dies(Mod, Func, Args) -> %% OTP-3766. called_dies(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - {ok, N} = test_server:start_node(rpc_SUITE_called_dies, slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, P, N} = ?CT_PEER(["-connect_all", "false"]), %% rep(fun (Tag, Call, Args) -> {Tag,{badrpc,{'EXIT',normal}}} = @@ -425,7 +388,7 @@ called_dies(Config) when is_list(Config) -> end, N, ?MODULE, suicide, [exit,kill]), %% [] = flush([]), - test_server:stop_node(N), + peer:stop(P), ok. rep(Fun, N, M, F, A) -> @@ -470,27 +433,22 @@ suicide(Mod, Func, Args) -> called_node_dies(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - node_rep( fun (Call, Args) -> {badrpc,nodedown} = apply(rpc, Call, Args) - end, "rpc_SUITE_called_node_dies_1", - PA, ?MODULE, suicide, [erlang,halt,[]]), + end, ?MODULE, suicide, [erlang,halt,[]]), node_rep( fun (Call, Args) -> {badrpc,nodedown} = apply(rpc, Call, Args) - end, "rpc_SUITE_called_node_dies_2", - PA, ?MODULE, suicide, [init,stop,[]]), + end, ?MODULE, suicide, [init,stop,[]]), node_rep( fun (block_call, Args=[_|_]) -> {badrpc,{'EXIT',{killed,_}}} = apply(rpc, block_call, Args); (call, Args=[_|_]) -> {badrpc,nodedown} = apply(rpc, call, Args) - end, "rpc_SUITE_called_node_dies_3", - PA, ?MODULE, suicide, [erlang,exit,[rex,kill]]), + end, ?MODULE, suicide, [erlang,exit,[rex,kill]]), node_rep( fun (block_call, _Args) -> @@ -498,31 +456,24 @@ called_node_dies(Config) when is_list(Config) -> ok; (Call, Args=[_|_]) -> {badrpc,nodedown} = apply(rpc, Call, Args) - end, "rpc_SUITE_called_node_dies_4", - PA, ?MODULE, suicide, [rpc,stop,[]]), + end, ?MODULE, suicide, [rpc,stop,[]]), ok. -node_rep(Fun, Name, PA, M, F, A) -> - node_rep_call(a, call, [M,F,A], Fun, Name, PA), - node_rep_call(b, call, [M,F,A,infinity], Fun, Name, PA), - node_rep_call(c, block_call, [M,F,A], Fun, Name, PA), - node_rep_call(d, block_call, [M,F,A,infinity], Fun, Name, PA). +node_rep(Fun, M, F, A) -> + node_rep_call(call, [M,F,A], Fun), + node_rep_call(call, [M,F,A,infinity], Fun), + node_rep_call(block_call, [M,F,A], Fun), + node_rep_call(block_call, [M,F,A,infinity], Fun). -node_rep_call(Tag, Call, Args, Fun, Name0, PA) -> - Name = list_to_atom(Name0 ++ "_" ++ atom_to_list(Tag)), - {ok, N} = test_server:start_node(Name, slave, - [{args, "-connect_all false -pa " ++ PA}]), +node_rep_call(Call, Args, Fun) -> + {ok, _P, N} = ?CT_PEER(#{connection => 0, args => ["-connect_all", "false"]}), Fun(Call, [N|Args]), - catch test_server:stop_node(N), ok. %% OTP-3766. called_throws(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - %% - {ok, N} = test_server:start_node(rpc_SUITE_called_throws, slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, P, N} = ?CT_PEER(["-connect_all", "false"]), %% rep(fun (Tag, Call, Args) -> {Tag,up} = @@ -533,21 +484,19 @@ called_throws(Config) when is_list(Config) -> {Tag,apply(rpc, Call, Args)} end, N, erlang, throw, [{'EXIT',reason}]), %% - test_server:stop_node(N), + peer:stop(P), ok. call_benchmark(Config) when is_list(Config) -> - PA = filename:dirname(code:which(?MODULE)), - {ok, Node} = test_server:start_node(rpc_SUITE_call_benchmark, slave, - [{args, "-connect_all false -pa " ++ PA}]), + {ok, Peer, Node} = ?CT_PEER(["-connect_all", "false"]), Iter = case erlang:system_info(modified_timing_level) of undefined -> 10000; _ -> 500 %Modified timing - spawn is slower end, Res = do_call_benchmark(Node, Iter), - test_server:stop_node(Node), + peer:stop(Peer), Res. do_call_benchmark(Node, M) when is_integer(M), M > 0 -> @@ -567,12 +516,10 @@ do_call_benchmark(Node, I, M) -> do_call_benchmark(Node, I+1, M). async_call(Config) when is_list(Config) -> + {ok, _Peer1, Node1} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "1"]), + {ok, _Peer2, Node2} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "10"]), + {ok, _Peer3, Node3} = ?CT_PEER(["-connect_all", "false", "-rpc_test_delay", "20"]), %% Note: First part of nodename sets response delay in seconds. - PA = filename:dirname(code:which(?MODULE)), - NodeArgs = [{args,"-connect_all false -pa "++ PA}], - {ok,Node1} = test_server:start_node('1_rpc_SUITE_call', slave, NodeArgs), - {ok,Node2} = test_server:start_node('10_rpc_SUITE_call', slave, NodeArgs), - {ok,Node3} = test_server:start_node('20_rpc_SUITE_call', slave, NodeArgs), Promise1 = rpc:async_call(Node1, ?MODULE, f, []), Promise2 = rpc:async_call(Node2, ?MODULE, f, []), Promise3 = rpc:async_call(Node3, ?MODULE, f, []), @@ -588,32 +535,37 @@ async_call(Config) when is_list(Config) -> %% Wait for the Node2 and Node3. {value,{hej,_,Node2}} = rpc:nb_yield(Promise2, infinity), {hej,_,Node3} = rpc:yield(Promise3), - ok. call_against_old_node(Config) -> - case start_22_node(Config) of - {ok, Node22} -> - Node22 = rpc:call(Node22, erlang, node, []), - stop_node(Node22), - ok; - _ -> - {skipped, "No OTP 22 available"} + {OldRelName, OldRel} = old_release(), + case ?CT_PEER_REL(#{connection => 0}, + OldRelName, + proplists:get_value(priv_dir, Config)) of + not_available -> + {skipped, "No OTP "++OldRel++" available"}; + {ok, PeerOld, NodeOld} -> + NodeOld = rpc:call(NodeOld, erlang, node, []), + peer:stop(PeerOld), + ok end. multicall_mix(Config) -> - {ok, Node1} = start_peer_node(Config), - {ok, Node2} = start_peer_node(Config), - {Node3, OldNodeTest} = case start_22_node(Config) of - {ok, N3} -> - {N3, true}; - _ -> - {ok, N3} = start_peer_node(Config), - {N3, false} - end, - {ok, Node4} = start_peer_node(Config), - {ok, Node5} = start_peer_node(Config), - stop_node(Node2), + {ok, _Peer1, Node1} = ?CT_PEER(#{connection => 0}), + {ok, Peer2, Node2} = ?CT_PEER(#{connection => 0}), + {OldRelName, OldRel} = old_release(), + {{ok, _Peer3, Node3}, OldNodeTest} + = case ?CT_PEER_REL(#{connection => 0}, + OldRelName, + proplists:get_value(priv_dir, Config)) of + {ok, _, _} = OldNRes -> + {OldNRes, true}; + not_available -> + {?CT_PEER(#{connection => 0}), false} + end, + {ok, _Peer4, Node4} = ?CT_PEER(#{connection => 0}), + {ok, _Peer5, Node5} = ?CT_PEER(#{connection => 0}), + peer:stop(Peer2), [] = flush([]), @@ -711,8 +663,8 @@ multicall_mix(Config) -> [] = flush([]), case OldNodeTest of - true -> {comment, "Test with OTP 22 node as well"}; - false -> {comment, "Test without OTP 22"} + true -> {comment, "Test with OTP "++OldRel++" node as well"}; + false -> {comment, "Test without OTP "++OldRel} end. call_func1(X) -> @@ -768,51 +720,51 @@ timeout_limit(Config) when is_list(Config) -> call_old_against_new(Config) -> - case test_server:is_release_available("22_latest") of - false -> - {skipped, "No OTP 22 available"}; - true -> - test_on_22_node(Config, call_old_against_new_test, 1, 1) + try + test_on_old_node(Config, call_old_against_new_test, 1, 1) + catch + throw:{skipped, _} = Skipped -> + Skipped end. -call_old_against_new_test([Node22], [NodeCurr]) -> - %% Excecuted on an OTP 22 node +call_old_against_new_test([NodeOld], [NodeCurr]) -> + %% Executed on an OTP old node - Node22 = rpc:call(Node22, erlang, node, []), + NodeOld = rpc:call(NodeOld, erlang, node, []), NodeCurr = rpc:call(NodeCurr, erlang, node, []), - {badrpc, {'EXIT', bang}} = rpc:call(Node22, erlang, exit, [bang]), + {badrpc, {'EXIT', bang}} = rpc:call(NodeOld, erlang, exit, [bang]), {badrpc, {'EXIT', bang}} = rpc:call(NodeCurr, erlang, exit, [bang]), - {badrpc, {'EXIT', {blong, _}}} = rpc:call(Node22, erlang, error, [blong]), + {badrpc, {'EXIT', {blong, _}}} = rpc:call(NodeOld, erlang, error, [blong]), {badrpc, {'EXIT', {blong, _}}} = rpc:call(NodeCurr, erlang, error, [blong]), - bling = rpc:call(Node22, erlang, throw, [bling]), + bling = rpc:call(NodeOld, erlang, throw, [bling]), bling = rpc:call(NodeCurr, erlang, throw, [bling]), - {badrpc, timeout} = rpc:call(Node22, timer, sleep, [1000], 100), + {badrpc, timeout} = rpc:call(NodeOld, timer, sleep, [1000], 100), {badrpc, timeout} = rpc:call(NodeCurr, timer, sleep, [1000], 100), - {badrpc, nodedown} = rpc:call(Node22, erlang, halt, []), + {badrpc, nodedown} = rpc:call(NodeOld, erlang, halt, []), {badrpc, nodedown} = rpc:call(NodeCurr, erlang, halt, []), - {badrpc, nodedown} = rpc:call(Node22, erlang, node, []), + {badrpc, nodedown} = rpc:call(NodeOld, erlang, node, []), {badrpc, nodedown} = rpc:call(NodeCurr, erlang, node, []), ok. multicall_old_against_new(Config) -> - case test_server:is_release_available("22_latest") of - false -> - {skipped, "No OTP 22 available"}; - true -> - test_on_22_node(Config, multicall_old_against_new_test, 2, 2) + try + test_on_old_node(Config, multicall_old_against_new_test, 2, 2) + catch + throw:{skipped, _} = Skipped -> + Skipped end. -multicall_old_against_new_test([Node22A, Node22B], [NodeCurrA, NodeCurrB]) -> - %% Excecuted on an OTP 22 node +multicall_old_against_new_test([NodeOldA, NodeOldB], [NodeCurrA, NodeCurrB]) -> + %% Executed on an OTP old node - AllNodes = [NodeCurrA, Node22A, NodeCurrB, Node22B], + AllNodes = [NodeCurrA, NodeOldA, NodeCurrB, NodeOldB], NoNodes = length(AllNodes), {AllNodes, []} = rpc:multicall(AllNodes, erlang, node, []), @@ -839,32 +791,32 @@ multicall_old_against_new_test([Node22A, Node22B], [NodeCurrA, NodeCurrB]) -> ok. cast_old_against_new(Config) -> - case test_server:is_release_available("22_latest") of - false -> - {skipped, "No OTP 22 available"}; - true -> - test_on_22_node(Config, cast_old_against_new_test, 1, 1) + try + test_on_old_node(Config, cast_old_against_new_test, 1, 1) + catch + throw:{skipped, _} = Skipped -> + Skipped end. -cast_old_against_new_test([Node22], [NodeCurr]) -> - %% Excecuted on an OTP 22 node +cast_old_against_new_test([NodeOld], [NodeCurr]) -> + %% Executed on an OTP old node Me = self(), Ref = make_ref(), - true = rpc:cast(Node22, erlang, send, [Me, {Ref, 1}]), + true = rpc:cast(NodeOld, erlang, send, [Me, {Ref, 1}]), receive {Ref, 1} -> ok end, true = rpc:cast(NodeCurr, erlang, send, [Me, {Ref, 2}]), receive {Ref, 2} -> ok end, - true = rpc:cast(Node22, erlang, halt, []), + true = rpc:cast(NodeOld, erlang, halt, []), true = rpc:cast(NodeCurr, erlang, halt, []), - monitor_node(Node22, true), - receive {nodedown, Node22} -> ok end, + monitor_node(NodeOld, true), + receive {nodedown, NodeOld} -> ok end, monitor_node(NodeCurr, true), receive {nodedown, NodeCurr} -> ok end, - true = rpc:cast(Node22, erlang, send, [Me, {Ref, 3}]), + true = rpc:cast(NodeOld, erlang, send, [Me, {Ref, 3}]), true = rpc:cast(NodeCurr, erlang, send, [Me, {Ref, 4}]), receive Msg -> error({unexcpected_message, Msg}) @@ -875,42 +827,9 @@ cast_old_against_new_test([Node22], [NodeCurr]) -> %%% Utility functions. %%% -start_peer_node(Config) -> - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" ++ integer_to_list(erlang:system_time(second)) - ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))), - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, peer, [{args, "-pa " ++ Pa}]). - -start_node(Config) -> - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" ++ integer_to_list(erlang:system_time(second)) - ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))), - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, slave, [{args, "-pa " ++ Pa}]). - -start_22_node(Config) -> - Rel = "22_latest", - case test_server:is_release_available(Rel) of - false -> - notsup; - true -> - Cookie = atom_to_list(erlang:get_cookie()), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" ++ integer_to_list(erlang:system_time(second)) - ++ "-" ++ integer_to_list(erlang:unique_integer([positive]))), - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, - peer, - [{args, "-pa " ++ Pa ++ " -setcookie "++Cookie}, - {erl, [{release, Rel}]}]) - end. - -stop_node(Node) -> - test_server:stop_node(Node). +old_release() -> + OldRel = integer_to_list(list_to_integer(erlang:system_info(otp_release))-2), + {OldRel++"_latest", OldRel}. flush(L) -> receive @@ -921,8 +840,11 @@ flush(L) -> end. t() -> - [N | _] = string:tokens(atom_to_list(node()), "_"), - 1000*list_to_integer(N). + Delay = case init:get_argument(rpc_test_delay) of + {ok,[[D]]} -> list_to_integer(D); + _ -> 0 + end, + 1000*Delay. f() -> timer:sleep(T=t()), @@ -933,33 +855,37 @@ f2() -> timer:sleep(500), halt(). -test_on_22_node(Config, Test, No22, NoCurr) -> - Nodes22 = lists:map(fun (_) -> - {ok, N} = start_22_node(Config), - N - end, - lists:seq(1, No22+1)), - NodesCurr = lists:map(fun (_) -> - {ok, N} = start_node(Config), - N - end, - lists:seq(1, NoCurr)), - - %% Recompile rpc_SUITE on OTP 22 node and load it on all OTP 22 nodes... +test_on_old_node(Config, Test, NoOld, NoCurr) -> + {OldRelName, OldRel} = old_release(), + NodesOldRes = lists:map(fun (_) -> + case ?CT_PEER_REL(#{connection => 0}, + OldRelName, + proplists:get_value(priv_dir, Config)) of + not_available -> + throw({skipped, "No OTP "++OldRel++" available"}); + {ok, _, _} = Ok -> + Ok + end + end, + lists:seq(1, NoOld+1)), + NodesCurrRes = lists:map(fun (_) -> + {ok, _, _} = ?CT_PEER() + end, + lists:seq(1, NoCurr)), + NFun = fun ({ok, _Peer, Node}) -> Node end, + NodesOld = lists:map(NFun, NodesOldRes), + NodesCurr = lists:map(NFun, NodesCurrRes), + + %% Recompile rpc_SUITE on old node and load it on all old nodes... SrcFile = filename:rootname(code:which(?MODULE)) ++ ".erl", - {ok, ?MODULE, BeamCode} = rpc:call(hd(Nodes22), compile, file, [SrcFile, [binary]]), - LoadResult = lists:duplicate(length(Nodes22), {module, ?MODULE}), - {LoadResult, []} = rpc:multicall(Nodes22, code, load_binary, [?MODULE, SrcFile, BeamCode]), - try - %% Excecute test on first OTP 22 node... - Pid = spawn_link(hd(Nodes22), ?MODULE, Test, [tl(Nodes22), NodesCurr]), - Mon = erlang:monitor(process, Pid), - receive - {'DOWN', Mon, process, Pid, Reason} when Reason == normal; Reason == noproc -> - ok - end - after - lists:foreach(fun (N) -> stop_node(N) end, Nodes22), - lists:foreach(fun (N) -> stop_node(N) end, NodesCurr) + {ok, ?MODULE, BeamCode} = rpc:call(hd(NodesOld), compile, file, [SrcFile, [binary]]), + LoadResult = lists:duplicate(length(NodesOld), {module, ?MODULE}), + {LoadResult, []} = rpc:multicall(NodesOld, code, load_binary, [?MODULE, SrcFile, BeamCode]), + %% Execute test on first old node... + Pid = spawn_link(hd(NodesOld), ?MODULE, Test, [tl(NodesOld), NodesCurr]), + Mon = erlang:monitor(process, Pid), + receive + {'DOWN', Mon, process, Pid, Reason} when Reason == normal; Reason == noproc -> + ok end, ok. diff --git a/lib/kernel/test/rtnode.erl b/lib/kernel/test/rtnode.erl new file mode 100644 index 000000000000..ffa0613ca7a0 --- /dev/null +++ b/lib/kernel/test/rtnode.erl @@ -0,0 +1,575 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2022. 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(rtnode). + +-export([run/1, run/2, run/3, run/4, start/1, start/3, start/4, send_commands/4, stop/1, + start_runerl_command/3, + check_logs/3, check_logs/4, read_logs/1, dump_logs/1, + get_default_shell/0, get_progs/0, create_tempdir/0, timeout/1]). + +-include_lib("common_test/include/ct.hrl"). + +%% -define(debug, true). + +-ifdef(debug). +-define(dbg(Data),io:format(standard_error, "DBG: ~p\r\n",[Data])). +-else. +-define(dbg(Data),noop). +-endif. + +-export([toerl_server/4]). + +%% +%% Tool for running interactive shell, used by interactive_shell and io_proto SUITE +%% +run(C) -> + run(C, [], [], []). + +run(C, N) -> + run(C, N, [], []). + +run(Commands, Nodename, ErlPrefix) -> + run(Commands, Nodename, ErlPrefix, []). + +run(Commands, Nodename, ErlPrefix, Args) -> + case start(Nodename, ErlPrefix, Args) of + {ok, _SPid, CPid, Node, RTState} -> + Res = catch send_commands(Node, CPid, Commands, 1), + Logs = stop(RTState), + case Res of + ok -> + dump_logs(Logs), + ok; + _ -> + dump_logs(Logs), + ok = Res + end, + {ok, Logs}; + Skip -> + Skip + end. + +start(Args) -> + start([], " ", Args, []). +start(Nodename, ErlPrefix, Args) -> + start(Nodename, ErlPrefix, Args, []). +start(Nodename, ErlPrefix, Args, Options) -> + case get_progs(Options) of + {error,Reason} -> + {skip,Reason}; + {RunErl,ToErl,[Erl|ErlArgs] = ErlWArgs} -> + case create_tempdir() of + {error, Reason2} -> + {skip, Reason2}; + Tempdir when ErlPrefix =/= [] -> + {SPid, Node} = + start_runerl_node(RunErl, + ErlPrefix++"\\\""++Erl++"\\\" "++ + lists:join($\s, ErlArgs), + Tempdir,Nodename,Args), + CPid = start_toerl_server(ToErl,Tempdir,undefined), + {ok, SPid, CPid, Node, {CPid, SPid, ToErl, Tempdir}}; + Tempdir -> + {SPid, Node} = start_peer_runerl_node(RunErl,ErlWArgs,Tempdir,Nodename,Args), + CPid = start_toerl_server(ToErl,Tempdir,SPid), + {ok, SPid, CPid, Node, {CPid, SPid, ToErl, Tempdir}} + end + end. + +stop({CPid, SPid, ToErl, Tempdir}) -> + %% Unlink from peer so that we don't crash when peer quits + unlink(SPid), + case stop_runerl_node(CPid) of + {error,_} -> + catch stop_try_harder(ToErl, Tempdir, SPid); + _ -> + ok + end, + wait_for_runerl_server(SPid), + Logs = read_logs(Tempdir), + file:del_dir_r(Tempdir), + Logs. + +stop_try_harder(ToErl, Tempdir, SPid) -> + CPid = start_toerl_server(ToErl, Tempdir, SPid), + ok = send_commands(undefined, CPid, + [{putline,[7]}, + {expect, " --> $"}, + {putline, "s"}, + {putline, "c"}, + {putline, ""}], 1), + stop_runerl_node(CPid). + +timeout(longest) -> + timeout(long) + timeout(normal); +timeout(long) -> + 2 * timeout(normal); +timeout(short) -> + timeout(normal) div 10; +timeout(normal) -> + 10000 * test_server:timetrap_scale_factor(). + +send_commands(Node, CPid, [{sleep, X}|T], N) -> + ?dbg({sleep, X}), + receive + after X -> + send_commands(Node, CPid, T, N+1) + end; +send_commands(Node, CPid, [{expect, Expect}|T], N) when is_list(Expect) -> + send_commands(Node, CPid, [{expect, unicode, Expect}|T], N); +send_commands(Node, CPid, [{expect, Encoding, Expect}|T], N) when is_list(Expect) -> + ?dbg({expect, Expect}), + case command(CPid, {expect, Encoding, [Expect], timeout(normal)}) of + ok -> + send_commands(Node, CPid, T, N + 1); + {expect_timeout, Got} -> + ct:pal("expect timed out waiting for ~p\ngot: ~p\n", [Expect,Got]), + {error, timeout}; + Other -> + Other + end; +send_commands(Node, CPid, [{putline, Line}|T], N) -> + send_commands(Node, CPid, [{putdata, Line ++ "\n"}|T], N); +send_commands(Node, CPid, [{putdata, Data}|T], N) -> + ?dbg({putdata, Data}), + case command(CPid, {send_data, Data}) of + ok -> + send_commands(Node, CPid, T, N+1); + Error -> + Error + end; +send_commands(Node, CPid, [{eval, Fun}|T], N) -> + ?dbg({eval, Node, Fun}), + case erpc:call(Node, Fun) of + ok -> + ?dbg({eval, ok}), + send_commands(Node, CPid, T, N+1); + Error -> + ?dbg({eval, Error}), + Error + end; +send_commands(_Node, _CPid, [], _) -> + ok. + +command(Pid, Req) -> + Timeout = timeout(longest), + Ref = erlang:monitor(process, Pid), + Pid ! {self(), Ref, Req}, + receive + {Ref, Reply} -> + erlang:demonitor(Ref, [flush]), + Reply; + {'DOWN', Ref, _, _, Reason} -> + {error, Reason} + after Timeout -> + io:format("timeout while executing ~p\n", [Req]), + {error, timeout} + end. + +wait_for_runerl_server(SPid) -> + Ref = erlang:monitor(process, SPid), + Timeout = timeout(long), + receive + {'DOWN', Ref, process, SPid, _Reason} -> + ok + after Timeout -> + {error, runerl_server_timeout} + end. + +stop_runerl_node(CPid) -> + Ref = erlang:monitor(process, CPid), + CPid ! {self(), kill_emulator}, + Timeout = timeout(longest), + receive + {'DOWN', Ref, process, CPid, noproc} -> + ok; + {'DOWN', Ref, process, CPid, normal} -> + ok; + {'DOWN', Ref, process, CPid, {error, Reason}} -> + {error, Reason} + after Timeout -> + {error, toerl_server_timeout} + end. + +get_progs() -> + case os:type() of + {unix,freebsd} -> + {error,"Can't use run_erl on FreeBSD"}; + {unix,openbsd} -> + {error,"Can't use run_erl on OpenBSD"}; + {unix,_} -> + RunErl = find_executable("run_erl"), + ToErl = find_executable("to_erl"), + Erl = string:split(ct:get_progname()," ",all), + {RunErl, ToErl, Erl}; + _ -> + {error,"Not a Unix OS"} + end. +get_progs(Opts) -> + case get_progs() of + {RunErl, ToErl, Erl} -> + case proplists:get_value(release, Opts) of + undefined -> {RunErl, ToErl, Erl}; + Release -> + case test_server_node:find_release(Release) of + none -> {error, "Could not find release "++Release}; + R -> {RunErl, ToErl, [R]} + end + end; + E -> E + end. + + +find_executable(Name) -> + case os:find_executable(Name) of + Prog when is_list(Prog) -> + Prog; + false -> + throw("Could not find " ++ Name) + end. + +create_tempdir() -> + create_tempdir(filename:join(["/tmp","rtnode"++os:getpid()]),$A). + +create_tempdir(Dir,X) when X > $Z, X < $a -> + create_tempdir(Dir,$a); +create_tempdir(Dir,X) when X > $z -> + Estr = lists:flatten( + io_lib:format("Unable to create ~s, reason eexist", + [Dir++[$z]])), + {error, Estr}; +create_tempdir(Dir0, Ch) -> + %% Expect fairly standard unix. + Dir = Dir0++[Ch], + case file:make_dir(Dir) of + {error, eexist} -> + create_tempdir(Dir0, Ch+1); + {error, Reason} -> + Estr = lists:flatten( + io_lib:format("Unable to create ~s, reason ~p", + [Dir,Reason])), + {error,Estr}; + ok -> + Dir + end. + +start_runerl_node(RunErl,Erl,Tempdir,Nodename,Args) -> + {XArg, Node} = + case Nodename of + [] -> + {[], undefined}; + _ -> + NodenameStr = if is_atom(Nodename) -> atom_to_list(Nodename); + true -> Nodename + end, + [_Name,Host] = string:split(atom_to_list(node()), "@"), + {" -sname "++ NodenameStr ++ + " -setcookie "++atom_to_list(erlang:get_cookie()), + list_to_atom(NodenameStr ++ "@" ++ Host)} + end, + {spawn(fun() -> start_runerl_command(RunErl, Tempdir, Erl ++ XArg ++ " " ++ Args) end), + Node}. + +start_runerl_command(RunErl, Tempdir, Cmd) -> + FullCmd = "\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++" \""++Cmd++"\"", + ct:pal("~ts",[FullCmd]), + os:cmd(FullCmd). + +start_peer_runerl_node(RunErl,Erl,Tempdir,[],Args) -> + start_peer_runerl_node(RunErl,Erl,Tempdir,peer:random_name(),Args); +start_peer_runerl_node(RunErl,Erl,Tempdir,Nodename,Args) -> + {ok, Peer, Node} = + ?CT_PEER(#{ name => Nodename, + exec => {RunErl,Erl}, + detached => false, + shutdown => 10000, + post_process_args => + fun(As) -> + [Tempdir++"/",Tempdir, + lists:flatten( + lists:join( + " ",[[$',A,$'] || A <- As]))] + end, + args => ["-connect_all","false"|Args] }), + Self = self(), + TraceLog = filename:join(Tempdir,Nodename++".trace"), + ct:pal("Link to trace: file://~ts",[TraceLog]), + + spawn(Node, + fun() -> + try + %% {ok, _} = dbg:tracer(file, TraceLog), + %% dbg:p(whereis(user_drv),[c,m,timestamp]), + %% dbg:p(whereis(user_drv_reader),[c,m,timestamp]), + %% dbg:p(whereis(user_drv_writer),[c,m,timestamp]), + %% dbg:p(whereis(user),[c,m,timestamp]), + %% dbg:tp(user_drv,x), + %% dbg:tp(prim_tty,x), + %% dbg:tpl(prim_tty,read_nif,x), + Ref = monitor(process, Self), + receive {'DOWN',Ref,_,_,_} -> ok end + catch E:R:ST -> + io:format(user,"~p:~p:~p",[E,R,ST]), + erlang:raise(E,R,ST) + end + end), + {Peer, Node}. + +start_toerl_server(ToErl,Tempdir,SPid) -> + Pid = spawn(?MODULE,toerl_server,[self(),ToErl,Tempdir,SPid]), + receive + {Pid,started} -> + Pid; + {Pid,error,Reason} -> + {error,Reason} + end. + +try_to_erl(_Command, 0) -> + {error, cannot_to_erl}; +try_to_erl(Command, N) -> + ?dbg({?LINE,N}), + Port = open_port({spawn, Command},[eof]), + Timeout = timeout(short) div 2, + receive + {Port, eof} -> + timer:sleep(Timeout), + try_to_erl(Command, N-1) + after Timeout -> + ?dbg(Port), + Port + end. + +toerl_server(Parent, ToErl, TempDir, SPid) -> + Port = try_to_erl("\""++ToErl++"\" "++TempDir++"/ 2>/dev/null", 8), + case Port of + P when is_port(P) -> + Parent ! {self(),started}; + {error,Other} -> + Parent ! {self(),error,Other}, + exit(Other) + end, + + {ok, InitialData} = file:read_file(filename:join(TempDir,"erlang.log.1")), + + State = #{port => Port, acc => unicode:characters_to_list(InitialData), spid => SPid}, + case toerl_loop(State) of + normal -> + ok; + {error, Reason} -> + error_logger:error_msg("toerl_server exit with reason ~p~n", + [Reason]), + exit(Reason) + end. + +toerl_loop(#{port := Port} = State0) -> + ?dbg({toerl_loop, Port, map_get(acc, State0), + maps:get(match, State0, nomatch)}), + + State = handle_expect(State0), + + receive + {Port,{data,Data}} when is_port(Port) -> + ?dbg({?LINE,Port,{data,Data}}), + toerl_loop(State#{acc => map_get(acc, State) ++ Data}); + {Pid, Ref, {expect, Encoding, Expect, Timeout}} -> + toerl_loop(init_expect(Pid, Ref, Encoding, Expect, Timeout, State)); + {Pid, Ref, {send_data, Data}} -> + ?dbg({?LINE,Port,{send_data,Data}}), + Port ! {self(), {command, Data}}, + Pid ! {Ref, ok}, + toerl_loop(State); + {_Pid, kill_emulator} -> + kill_emulator(State); + {timeout,Timer,expect_timeout} -> + toerl_loop(handle_expect_timeout(Timer, State)); + {Port, eof} -> + {error, unexpected_eof}; + Other -> + {error, {unexpected, Other}} + end. + +kill_emulator(#{spid := SPid, port := Port}) when is_pid(SPid) -> + catch peer:stop(SPid), + wait_for_eof(Port); +kill_emulator(#{port := Port}) -> + %% If the line happens to end in a ".", issuing "init:stop()." + %% will result in a syntax error. To avoid that, issue a "\n" + %% before "init:stop().". + Port ! {self(),{command, "\ninit:stop().\n"}}, + wait_for_eof(Port). + +wait_for_eof(Port) -> + receive + {Port,eof} -> + normal; + _Other -> + wait_for_eof(Port) + after + timeout(long) -> + {error, kill_timeout} + end. + +init_expect(Pid, Ref, Encoding, ExpectList, Timeout, State) -> + try compile_expect(ExpectList, Encoding) of + Expect -> + Exp = #{expect => Expect, + ref => Ref, + source => ExpectList, + timer => erlang:start_timer(Timeout, self(), expect_timeout), + from => Pid}, + State#{expect => Exp} + catch + Class:Reason:Stk -> + io:put_chars("Compilation of expect pattern failed:"), + io:format("~p\n", [ExpectList]), + io:put_chars(erl_error:format_exception(Class, Reason, Stk)), + exit(expect_pattern_error) + end. + +handle_expect(#{acc := Acc, expect := Exp} = State) -> + #{expect := Expect, from := Pid, ref := Ref} = Exp, + case Expect(Acc) of + nomatch -> + State; + {matched, Eaten, Result} -> + ?dbg({matched, Eaten, Result}), + Pid ! {Ref, Result}, + finish_expect(Eaten, State) + end; +handle_expect(State) -> + State. + +handle_expect_timeout(Timer, State) -> + #{acc := Acc, expect := Exp} = State, + #{expect := Expect, timer := Timer, from := Pid, ref := Ref} = Exp, + case Expect({timeout, Acc}) of + nomatch -> + Result = {expect_timeout, Acc}, + Pid ! {Ref, Result}, + finish_expect(0, State); + {matched, Eaten, Result} -> + Pid ! {Ref, Result}, + finish_expect(Eaten, State) + end. + +finish_expect(Eaten, #{acc := Acc0, + expect := #{timer := Timer}}=State) -> + erlang:cancel_timer(Timer), + receive + {timeout,Timer,timeout} -> + ok + after 0 -> + ok + end, + Acc = lists:nthtail(Eaten, Acc0), + maps:remove(expect, State#{acc := Acc}). + +compile_expect([{timeout,Action}|T], E) when is_function(Action, 1) -> + Next = compile_expect(T, E), + fun({timeout, _}=Tm) -> + {matched, 0, Action(Tm)}; + (Subject) -> + Next(Subject) + end; +compile_expect([{{re,RE0},Action}|T], E) when is_binary(RE0), is_function(Action, 1) -> + {ok, RE} = re:compile(RE0, [unicode || E =:= unicode]), + Next = compile_expect(T, E), + fun({timeout, _}=Subject) -> + Next(Subject); + (Subject) -> + BinarySubject = if + E =:= unicode -> + unicode:characters_to_binary(list_to_binary(Subject)); + E =:= latin1 -> + list_to_binary(Subject) + end, + case re:run(BinarySubject, RE, [{capture,first,index}]) of + nomatch -> + Next(Subject); + {match, [{Pos,Len}]} -> + Matched = binary:part(BinarySubject, Pos, Len), + {matched, Pos+Len, Action(Matched)} + end + end; +compile_expect([RE|T], E) when is_list(RE) -> + Ok = fun(_) -> ok end, + compile_expect([{{re,unicode:characters_to_binary(RE, unicode, E)},Ok}|T], E); +compile_expect([], _E) -> + fun(_) -> + nomatch + end. + +check_logs(Logname, Pattern, Logs) -> + check_logs(Logname, Pattern, true, Logs). +check_logs(Logname, Pattern, Match, Logs) -> + case re:run(maps:get(Logname, Logs), Pattern) of + {match, [_]} when Match -> + ok; + nomatch when not Match -> + ok; + _ -> + dump_logs(Logs), + ct:fail("~p not found in log ~ts",[Pattern, Logname]) + end. + +dump_logs(Logs) -> + maps:foreach( + fun(File, Data) -> + try re:replace(Data,"\e","\\\\e",[unicode,global]) of + D -> ct:pal("~ts: ~ts",[File, D]) + catch error:badarg -> + ct:pal("~ts: ~s",[File, re:replace(Data,"\e","\\\\e",[global])]) + end + end, Logs). + +read_logs(Tempdir) -> + {ok, LogFiles0} = file:list_dir(Tempdir), + + %% Make sure that we only read log files and not any named pipes. + LogFiles = [F || F <- LogFiles0, + case F of + "erlang.log" ++ _ -> true; + _ -> false + end], + + lists:foldl( + fun(File, Acc) -> + case file:read_file(filename:join(Tempdir, File)) of + {ok, Data} -> + Acc#{ File => Data }; + _ -> + Acc + end + end, #{}, LogFiles). + +get_default_shell() -> + case get_progs() of + {error,_} -> + noshell; + _ -> + try + run([{putline,""}, + {putline, "is_pid(whereis(user_drv))."}, + {expect, "true\r\n"}]), + new + catch _E:_R -> + old + end + end. diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index e7bed5651026..af409e33db1a 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -350,7 +350,9 @@ t_sendfile_recvduring(Config) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), spawn_link(fun() -> - timer:sleep(1), + %% We sleep to allow file:sendfile to be + %% called before this send. + timer:sleep(10), ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1) end), @@ -488,10 +490,9 @@ sendfile_send(Host, Send, Orig, SockOpts) -> Opts = [binary,{packet,0}|SockOpts], io:format("connect with opts = ~p\n", [Opts]), {ok, Sock} = gen_tcp:connect(Host, Port, Opts), - Data = case proplists:get_value(arity,erlang:fun_info(Send)) of - 1 -> + Data = if is_function(Send, 1) -> Send(Sock); - 2 -> + is_function(Send, 2) -> Send(Sock, SFServer) end, ok = gen_tcp:close(Sock), diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index f6140d16edbd..6e3cb08af3d3 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -19,9 +19,6 @@ %% -module(seq_trace_SUITE). -%% label_capability_mismatch needs to run a part of the test on an OTP 20 node. --compile(r20). - -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2]). @@ -30,7 +27,7 @@ send/1, distributed_send/1, recv/1, distributed_recv/1, trace_exit/1, distributed_exit/1, call/1, port/1, port_clean_token/1, - match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1, + match_set_seq_token/1, gc_seq_token/1, send_literal/1,inherit_on_spawn/1,inherit_on_dist_spawn/1, dist_spawn_error/1]). @@ -57,7 +54,7 @@ all() -> old_heap_token, mature_heap_token, distributed_exit, call, port, match_set_seq_token, port_clean_token, - gc_seq_token, label_capability_mismatch, + gc_seq_token, inherit_on_spawn, inherit_on_dist_spawn, dist_spawn_error]. groups() -> @@ -249,10 +246,7 @@ distributed_send(Config) when is_list(Config) -> lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES). do_distributed_send(TsType) -> - {ok,Node} = start_node(seq_trace_other,[]), - {_,Dir} = code:is_loaded(?MODULE), - Mdir = filename:dirname(Dir), - true = rpc:call(Node,code,add_patha,[Mdir]), + {ok, Peer, Node} = ?CT_PEER(), seq_trace:reset_trace(), start_tracer(), Tester = self(), @@ -276,7 +270,7 @@ do_distributed_send(TsType) -> Self = self(), seq_trace:reset_trace(), - stop_node(Node), + peer:stop(Peer), [{Label,{send,_,Self,Receiver,send}, Ts1}, {Label,{send,_,Self,{n_time_receiver,Node}, "dsend"}, Ts2}, {Label,{send,_,Self,Alias,"alias_dsend"}, Ts3} @@ -317,10 +311,7 @@ distributed_recv(Config) when is_list(Config) -> lists:foreach(fun do_distributed_recv/1, ?TIMESTAMP_MODES). do_distributed_recv(TsType) -> - {ok,Node} = start_node(seq_trace_other,[]), - {_,Dir} = code:is_loaded(?MODULE), - Mdir = filename:dirname(Dir), - true = rpc:call(Node,code,add_patha,[Mdir]), + {ok, Peer, Node} = ?CT_PEER(), seq_trace:reset_trace(), rpc:call(Node,?MODULE,start_tracer,[]), Tester = self(), @@ -346,7 +337,7 @@ do_distributed_recv(TsType) -> Self = self(), seq_trace:reset_trace(), Result = rpc:call(Node,?MODULE,stop_tracer,[2]), - stop_node(Node), + peer:stop(Peer), ok = io:format("~p~n",[Result]), [{Label,{'receive',_,Self,Receiver,'alias_receive'}, Ts1}, {Label,{'receive',_,Self,Receiver,'receive'}, Ts2}] = Result, @@ -390,10 +381,7 @@ distributed_exit(Config) when is_list(Config) -> lists:foreach(fun do_distributed_exit/1, ?TIMESTAMP_MODES). do_distributed_exit(TsType) -> - {ok, Node} = start_node(seq_trace_other, []), - {_, Dir} = code:is_loaded(?MODULE), - Mdir = filename:dirname(Dir), - true = rpc:call(Node, code, add_patha, [Mdir]), + {ok, Peer, Node} = ?CT_PEER(), seq_trace:reset_trace(), rpc:call(Node, ?MODULE, start_tracer,[]), Receiver = spawn_link(Node, ?MODULE, one_time_receiver, [exit]), @@ -411,81 +399,14 @@ do_distributed_exit(TsType) -> Self = self(), Result = rpc:call(Node, ?MODULE, stop_tracer, [1]), seq_trace:reset_trace(), - stop_node(Node), + process_flag(trap_exit, false), + peer:stop(Peer), ok = io:format("~p~n", [Result]), [{0, {send, {1, 2}, Receiver, Self, {'EXIT', Receiver, {exit, {before, exit}}}}, Ts}] = Result, check_ts(TsType, Ts). -label_capability_mismatch(Config) when is_list(Config) -> - Releases = ["20_latest"], - Available = [Rel || Rel <- Releases, test_server:is_release_available(Rel)], - case Available of - [] -> {skipped, "No incompatible releases available"}; - _ -> - lists:foreach(fun do_incompatible_labels/1, Available), - lists:foreach(fun do_compatible_labels/1, Available), - ok - end. - -do_incompatible_labels(Rel) -> - Cookie = atom_to_list(erlang:get_cookie()), - {ok, Node} = test_server:start_node( - list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, - [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]), - - {_,Dir} = code:is_loaded(?MODULE), - Mdir = filename:dirname(Dir), - true = rpc:call(Node,code,add_patha,[Mdir]), - seq_trace:reset_trace(), - true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])), - Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - - %% This node does not support arbitrary labels, so it must fail with a - %% timeout as the token is dropped silently. - seq_trace:set_token(label,make_ref()), - seq_trace:set_token('receive',true), - - Receiver ! 'receive', - %% let the other process receive the message: - receive after 10 -> ok end, - seq_trace:reset_trace(), - - {error,timeout} = rpc:call(Node,?MODULE,stop_tracer,[1]), - stop_node(Node), - ok. - -do_compatible_labels(Rel) -> - Cookie = atom_to_list(erlang:get_cookie()), - {ok, Node} = test_server:start_node( - list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, - [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]), - - {_,Dir} = code:is_loaded(?MODULE), - Mdir = filename:dirname(Dir), - true = rpc:call(Node,code,add_patha,[Mdir]), - seq_trace:reset_trace(), - true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])), - Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - - %% This node does not support arbitrary labels, but small integers should - %% still work. - Label = 1234, - seq_trace:set_token(label,Label), - seq_trace:set_token('receive',true), - - Receiver ! 'receive', - %% let the other process receive the message: - receive after 10 -> ok end, - Self = self(), - seq_trace:reset_trace(), - Result = rpc:call(Node,?MODULE,stop_tracer,[1]), - stop_node(Node), - ok = io:format("~p~n",[Result]), - [{Label,{'receive',_,Self,Receiver,'receive'}, _}] = Result, - ok. - -call(doc) -> +call(doc) -> "Tests special forms {is_seq_trace} and {get_seq_token} " "in trace match specs."; call(Config) when is_list(Config) -> @@ -734,8 +655,7 @@ inherit_on_dist_spawn(Config) when is_list(Config) -> inherit_on_dist_spawn_test(Spawn) -> io:format("Testing ~p()~n", [Spawn]), - Pa = "-pa "++filename:dirname(code:which(?MODULE)), - {ok, Node} = start_node(seq_trace_dist_spawn, Pa), + {ok, Peer, Node} = ?CT_PEER(), %% ensure module is loaded on remote node... _ = rpc:call(Node, ?MODULE, module_info, []), @@ -865,13 +785,12 @@ inherit_on_dist_spawn_test(Spawn) -> unlink(Other), - stop_node(Node), + peer:stop(Peer), ok. dist_spawn_error(Config) when is_list(Config) -> - Pa = "-pa "++filename:dirname(code:which(?MODULE)), - {ok, Node} = start_node(seq_trace_dist_spawn, Pa), + {ok, Peer, Node} = ?CT_PEER(), %% ensure module is loaded on remote node... _ = rpc:call(Node, ?MODULE, module_info, []), @@ -957,7 +876,7 @@ dist_spawn_error(Config) when is_list(Config) -> {spawn_reply, ReqId, error, badopt}}, _} = StSpawnReplyNode, - stop_node(Node), + peer:stop(Peer), ok. @@ -1079,7 +998,7 @@ match_set_seq_token(Config) when is_list(Config) -> %% All the timeout stuff is here to get decent accuracy of the error %% return value, instead of just 'timeout'. %% - {ok, Sandbox} = start_node(seq_trace_other, []), + {ok, Peer, Sandbox} = ?CT_PEER(), true = rpc:call(Sandbox, code, add_patha, [filename:dirname(code:which(?MODULE))]), Lbl = 4711, @@ -1124,7 +1043,7 @@ match_set_seq_token(Config) when is_list(Config) -> ok = check_match_set_seq_token_log(Lbl, SortedLog), %% - stop_node(Sandbox), + peer:stop(Peer), ok. %% OTP-4222 Match spec 'set_seq_token' corrupts heap @@ -1230,7 +1149,7 @@ gc_seq_token(Config) when is_list(Config) -> %% All the timeout stuff is here to get decent accuracy of the error %% return value, instead of just 'timeout'. %% - {ok, Sandbox} = start_node(seq_trace_other, []), + {ok, Peer, Sandbox} = ?CT_PEER(), true = rpc:call(Sandbox, code, add_patha, [filename:dirname(code:which(?MODULE))]), Label = 4711, @@ -1268,7 +1187,7 @@ gc_seq_token(Config) when is_list(Config) -> {error, "Test node hung"} end, %% - stop_node(Sandbox), + peer:stop(Peer), ok. do_gc_seq_token(Label) -> @@ -1554,12 +1473,6 @@ check_ts(strict_monotonic_timestamp, Ts) -> end, ok. -start_node(Name, Param) -> - test_server:start_node(Name, peer, [{args, Param}]). - -stop_node(Node) -> - test_server:stop_node(Node). - load_tracer(Config) -> Path = proplists:get_value(data_dir, Config), ok = erl_ddll:load_driver(Path, echo_drv), diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 03ee74ef2964..6626e7af6027 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2022. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -24,9 +24,13 @@ %% Variable that controls which 'groups' are to run (with default values) %% %% ESOCK_TEST_API: include +%% ESOCK_TEST_REG: include +%% ESOCK_TEST_MON: include +%% ESOCK_TEST_IOCTL: include %% ESOCK_TEST_SOCK_CLOSE: include %% ESOCK_TEST_TRAFFIC: include -%% ESOCK_TEST_TTEST: exclude +%% ESOCK_TEST_TICKETS: include +%% ESOCK_TEST_TTEST: include %% %% Variable that controls "verbosity" of the test case(s): %% @@ -37,22 +41,52 @@ %% the actual time it takes for the test case to complete %% will be longer; setup, completion, ...) %% -%% ESOCK_TEST_TTEST_RUNTIME: 10 seconds +%% ESOCK_TEST_TTEST_RUNTIME: 1 second %% Format of values: [] %% Where unit is: ms | s | m %% ms - milli seconds %% s - seconds (default) %% m - minutes %% +%% The ttest takes a long time to run, even when the runtime is small, +%% because there are such a large number of test cases. +%% So, by default only the 'small' test cases are included in a test run. +%% The following environment variables control which are included and +%% excluded. +%% +%% ESOCK_TEST_TTEST_SMALL: included +%% ESOCK_TEST_TTEST_MEDIUM: excluded +%% ESOCK_TEST_TTEST_LARGE: excluded +%% %% Run the entire test suite: -%% ts:run(emulator, socket_SUITE, [batch]). +%% ts:run(kernel, socket_SUITE, [batch]). %% %% Run a specific group: -%% ts:run(emulator, socket_SUITE, {group, foo}, [batch]). +%% ts:run(kernel, socket_SUITE, {group, foo}, [batch]). %% %% Run a specific test case: -%% ts:run(emulator, socket_SUITE, foo, [batch]). +%% ts:run(kernel, socket_SUITE, foo, [batch]). +%% +%% (cd /mnt/c/$LOCAL_TESTS/26/kernel_test/ && $ERL_TOP/bin/win32/erl.exe -sname kernel-26-tester -pa c:$LOCAL_TESTS/26/test_server) +%% application:set_env(kernel, test_inet_backends, true). +%% S = fun() -> ts:run(kernel, socket_SUITE, [batch]) end. +%% S = fun(SUITE) -> ts:run(kernel, SUITE, [batch]) end. +%% S = fun() -> ct:run_test([{suite, socket_SUITE}]) end. +%% S = fun(SUITE) -> ct:run_test([{suite, SUITE}]) end. +%% G = fun(GROUP) -> ts:run(kernel, socket_SUITE, {group, GROUP}, [batch]) end. +%% G = fun(SUITE, GROUP) -> ts:run(kernel, SUITE, {group, GROUP}, [batch]) end. +%% G = fun(GROUP) -> ct:run_test([{suite, socket_SUITE}, {group, GROUP}]) end. +%% G = fun(SUITE, GROUP) -> ct:run_test([{suite, SUITE}, {group, GROUP}]) end. +%% T = fun(TC) -> ts:run(kernel, socket_SUITE, TC, [batch]) end. +%% T = fun(TC) -> ct:run_test([{suite, socket_SUITE}, {testcase, TC}]) end. +%% T = fun(S, TC) -> ct:run_test([{suite, S}, {testcase, TC}]) end. +%% T = fun(S, G, TC) -> ct:run_test([{suite, S}, {group, G}, {testcase, TC}]) end. +%% +%% Some official info about AF_UNIX +%% https://devblogs.microsoft.com/commandline/windowswsl-interop-with-af_unix/ + + -module(socket_SUITE). @@ -75,6 +109,10 @@ api_m_error_bind/1, %% *** API Basic *** + api_b_simple_open_and_close_udp4/1, + api_b_simple_open_and_close_udp6/1, + api_b_simple_open_and_close_tcp4/1, + api_b_simple_open_and_close_tcp6/1, api_b_open_and_info_udp4/1, api_b_open_and_info_udp6/1, api_b_open_and_info_tcp4/1, @@ -183,6 +221,8 @@ api_opt_sock_keepalive/1, api_opt_sock_linger/1, api_opt_sock_mark/1, + api_opt_sock_maxdg/1, + api_opt_sock_max_msg_size/1, api_opt_sock_oobinline/1, api_opt_sock_passcred_tcp4/1, api_opt_sock_peek_off_tcpL/1, @@ -192,12 +232,15 @@ api_opt_sock_rcvbuf_udp4/1, api_opt_sock_rcvlowat_udp4/1, api_opt_sock_rcvtimeo_udp4/1, + api_opt_sock_reuseaddr/1, + api_opt_sock_exclusiveaddruse/1, + api_opt_sock_bsp_state/1, api_opt_sock_sndbuf_udp4/1, api_opt_sock_sndlowat_udp4/1, api_opt_sock_sndtimeo_udp4/1, api_opt_sock_timestamp_udp4/1, api_opt_sock_timestamp_tcp4/1, - api_opt_ip_add_drop_membership/1, + api_opt_ip_add_drop_membership/0, api_opt_ip_add_drop_membership/1, api_opt_ip_pktinfo_udp4/1, api_opt_ip_recvopts_udp4/1, api_opt_ip_recvorigdstaddr_udp4/1, @@ -216,6 +259,9 @@ api_opt_tcp_cork_tcp4/1, api_opt_tcp_maxseg_tcp4/1, api_opt_tcp_nodelay_tcp4/1, + api_opt_tcp_keepcnt_tcp4/1, + api_opt_tcp_keepidle_tcp4/1, + api_opt_tcp_keepintvl_tcp4/1, api_opt_udp_cork_udp4/1, %% *** API Operation Timeout *** @@ -300,6 +346,8 @@ %% Socket IOCTL simple ioctl_simple1/1, + ioctl_simple2/1, + ioctl_nread/1, %% Socket IOCTL get requests ioctl_get_gifname/1, ioctl_get_gifindex/1, @@ -312,6 +360,7 @@ ioctl_get_giftxqlen/1, ioctl_get_gifflags/1, ioctl_get_gifmap/1, + ioctl_tcp_info/1, %% ioctl_set_requests/1, %% *** Traffic *** @@ -413,6 +462,15 @@ ttest_sgenf_csockt_large_tcp4/1, ttest_sgenf_csockt_large_tcp6/1, + %% Server: transport = gen_tcp(socket), active = false + %% Client: transport = socket(tcp) + ttest_sgsf_csockf_small_tcp4/1, + ttest_sgsf_csockf_small_tcp6/1, + ttest_sgsf_csockf_medium_tcp4/1, + ttest_sgsf_csockf_medium_tcp6/1, + ttest_sgsf_csockf_large_tcp4/1, + ttest_sgsf_csockf_large_tcp6/1, + %% Server: transport = gen_tcp, active = once %% Client: transport = gen_tcp ttest_sgeno_cgenf_small_tcp4/1, @@ -477,10 +535,10 @@ ttest_sgent_cgent_small_tcp4/1, ttest_sgent_cgent_small_tcp6/1, - ttest_sgent_cgent_medium_tcp4/1, - ttest_sgent_cgent_medium_tcp6/1, - ttest_sgent_cgent_large_tcp4/1, - ttest_sgent_cgent_large_tcp6/1, + ttest_sgent_cgent_medium_tcp4/0, ttest_sgent_cgent_medium_tcp4/1, + ttest_sgent_cgent_medium_tcp6/0, ttest_sgent_cgent_medium_tcp6/1, + ttest_sgent_cgent_large_tcp4/0, ttest_sgent_cgent_large_tcp4/1, + ttest_sgent_cgent_large_tcp6/0, ttest_sgent_cgent_large_tcp6/1, %% Server: transport = gen_tcp, active = true %% Client: transport = socket(tcp) @@ -528,6 +586,15 @@ ttest_ssockf_cgent_large_tcp4/1, ttest_ssockf_cgent_large_tcp6/1, + %% Server: transport = socket(tcp), active = false + %% Client: transport = gen_tcp(socket) + ttest_ssockf_cgsf_small_tcp4/1, + ttest_ssockf_cgsf_small_tcp6/1, + ttest_ssockf_cgsf_medium_tcp4/1, + ttest_ssockf_cgsf_medium_tcp6/1, + ttest_ssockf_cgsf_large_tcp4/1, + ttest_ssockf_cgsf_large_tcp6/1, + %% Server: transport = socket(tcp), active = false %% Client: transport = socket(tcp) ttest_ssockf_csockf_small_tcp4/1, @@ -670,10 +737,17 @@ ttest_ssockt_csockt_large_tcp6/1, ttest_ssockt_csockt_large_tcpL/1, + ttest_simple_ssockt_csocko_small_tcp4/1, + ttest_simple_ssockt_csocko_small_tcp6/1, + ttest_simple_ssockt_csocko_small_tcpL/1, + %% Tickets otp16359_maccept_tcp4/1, otp16359_maccept_tcp6/1, - otp16359_maccept_tcpL/1 + otp16359_maccept_tcpL/1, + otp18240_accept_mon_leak_tcp4/1, + otp18240_accept_mon_leak_tcp6/1, + otp18635/1 ]). @@ -684,6 +758,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(LIB, socket_test_lib). +-define(KLIB, kernel_test_lib). -define(TTEST_LIB, socket_test_ttest_lib). -define(LOGGER, socket_test_logger). @@ -712,9 +787,32 @@ -define(TPP_SMALL_NUM, 5000). -define(TPP_MEDIUM_NUM, 500). -define(TPP_LARGE_NUM, 50). --define(TPP_NUM(Config, Base), (Base) div lookup(esock_factor, 1, Config)). +-define(TPP_NUM(Config, Base), (Base) div lookup(kernel_factor, 1, Config)). + +-define(WINDOWS, {win32,nt}). + +-define(TTEST_RUNTIME, ?SECS(1)). +-define(TTEST_MIN_FACTOR, 3). +-define(TTEST_MIN_FACTOR_WIN, ?TTEST_MIN_FACTOR-1). +-define(TTEST_DEFAULT_SMALL_MAX_OUTSTANDING, 50). +-define(TTEST_DEFAULT_MEDIUM_MAX_OUTSTANDING, + ?TTEST_MK_DEFAULT_MAX_OUTSTANDING( + ?TTEST_DEFAULT_SMALL_MAX_OUTSTANDING)). +-define(TTEST_DEFAULT_LARGE_MAX_OUTSTANDING, + ?TTEST_MK_DEFAULT_MAX_OUTSTANDING( + ?TTEST_DEFAULT_MEDIUM_MAX_OUTSTANDING)). --define(TTEST_RUNTIME, ?SECS(10)). +-define(TTEST_MK_DEFAULT_MAX_OUTSTANDING(__X__), + if ((__X__) >= 5) -> + (__X__) div 5; + true -> + 1 + end). + +-define(START_NODE(NamePre), + ?START_NODE(NamePre, 5000)). +-define(START_NODE(NamePre, Timeout), + start_node(?CT_PEER_NAME(NamePre), Timeout)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -725,12 +823,12 @@ suite() -> all() -> Groups = [{api, "ESOCK_TEST_API", include}, - {reg, undefined, include}, - {monitor, undefined, include}, - {ioctl, undefined, include}, + {reg, "ESOCK_TEST_REG", include}, + {monitor, "ESOCK_TEST_MON", include}, + {ioctl, "ESOCK_TEST_IOCTL", include}, {socket_close, "ESOCK_TEST_SOCK_CLOSE", include}, {traffic, "ESOCK_TEST_TRAFFIC", include}, - {ttest, "ESOCK_TEST_TTEST", exclude}, + {ttest, "ESOCK_TEST_TTEST", include}, {tickets, "ESOCK_TEST_TICKETS", include}], [use_group(Group, Env, Default) || {Group, Env, Default} <- Groups]. @@ -808,6 +906,9 @@ groups() -> {ttest_sgenf_csockf, [], ttest_sgenf_csockf_cases()}, {ttest_sgenf_csocko, [], ttest_sgenf_csocko_cases()}, {ttest_sgenf_csockt, [], ttest_sgenf_csockt_cases()}, + {ttest_sgsf, [], ttest_sgsf_cases()}, + {ttest_sgsf_csock, [], ttest_sgsf_csock_cases()}, + {ttest_sgsf_csockf, [], ttest_sgsf_csockf_cases()}, {ttest_sgeno, [], ttest_sgeno_cases()}, {ttest_sgeno_cgen, [], ttest_sgeno_cgen_cases()}, {ttest_sgeno_cgenf, [], ttest_sgeno_cgenf_cases()}, @@ -831,6 +932,8 @@ groups() -> {ttest_ssockf_cgenf, [], ttest_ssockf_cgenf_cases()}, {ttest_ssockf_cgeno, [], ttest_ssockf_cgeno_cases()}, {ttest_ssockf_cgent, [], ttest_ssockf_cgent_cases()}, + {ttest_ssockf_cgs, [], ttest_ssockf_cgs_cases()}, + {ttest_ssockf_cgsf, [], ttest_ssockf_cgsf_cases()}, {ttest_ssockf_csock, [], ttest_ssockf_csock_cases()}, {ttest_ssockf_csockf, [], ttest_ssockf_csockf_cases()}, {ttest_ssockf_csocko, [], ttest_ssockf_csocko_cases()}, @@ -853,10 +956,14 @@ groups() -> {ttest_ssockt_csockf, [], ttest_ssockt_csockf_cases()}, {ttest_ssockt_csocko, [], ttest_ssockt_csocko_cases()}, {ttest_ssockt_csockt, [], ttest_ssockt_csockt_cases()}, + {ttest_simple_ssockt, [], ttest_simple_ssockt_cases()}, + {ttest_simple_ssockt_csock, [], ttest_simple_ssockt_csock_cases()}, + {ttest_simple_ssockt_csocko, [], ttest_simple_ssockt_csocko_cases()}, %% Ticket groups {tickets, [], tickets_cases()}, - {otp16359, [], otp16359_cases()} + {otp16359, [], otp16359_cases()}, + {otp18240, [], otp18240_cases()} ]. api_cases() -> @@ -880,6 +987,10 @@ api_misc_cases() -> api_basic_cases() -> [ + api_b_simple_open_and_close_udp4, + api_b_simple_open_and_close_udp6, + api_b_simple_open_and_close_tcp4, + api_b_simple_open_and_close_tcp6, api_b_open_and_info_udp4, api_b_open_and_info_udp6, api_b_open_and_info_tcp4, @@ -1008,6 +1119,8 @@ api_options_socket_cases() -> api_opt_sock_keepalive, api_opt_sock_linger, api_opt_sock_mark, + api_opt_sock_maxdg, + api_opt_sock_max_msg_size, api_opt_sock_oobinline, {group, api_option_sock_passcred}, api_opt_sock_peek_off_tcpL, @@ -1016,7 +1129,11 @@ api_options_socket_cases() -> {group, api_option_sock_buf}, {group, api_option_sock_lowat}, {group, api_option_sock_timeo}, - {group, api_option_sock_timestamp} + {group, api_option_sock_timestamp}, + api_opt_sock_reuseaddr, + api_opt_sock_exclusiveaddruse, + api_opt_sock_bsp_state + ]. api_option_sock_acceptconn_cases() -> @@ -1098,8 +1215,11 @@ api_options_tcp_cases() -> %% api_opt_tcp_cork_tcp6, api_opt_tcp_maxseg_tcp4, %% api_opt_tcp_maxseg_tcp6, - api_opt_tcp_nodelay_tcp4%, + api_opt_tcp_nodelay_tcp4, %% api_opt_tcp_nodelay_tcp6 + api_opt_tcp_keepcnt_tcp4, + api_opt_tcp_keepidle_tcp4, + api_opt_tcp_keepintvl_tcp4 ]. api_options_udp_cases() -> @@ -1240,7 +1360,9 @@ ioctl_cases() -> ioctl_simple_cases() -> [ - ioctl_simple1 + ioctl_simple1, + ioctl_simple2, + ioctl_nread ]. @@ -1256,7 +1378,8 @@ ioctl_get_cases() -> ioctl_get_gifhwaddr, ioctl_get_giftxqlen, ioctl_get_gifflags, - ioctl_get_gifmap + ioctl_get_gifmap, + ioctl_tcp_info ]. @@ -1344,7 +1467,82 @@ traffic_pp_sendmsg_recvmsg_cases() -> traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6, traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL ]. - + +%% Condition for running the ttest cases. +%% No point in running these cases unless the machine is +%% reasonably fast. +ttest_condition(Config) -> + OsType = os:type(), + case ?config(kernel_factor, Config) of + Factor when (OsType =:= ?WINDOWS) andalso + is_integer(Factor) andalso + (Factor =< ?TTEST_MIN_FACTOR_WIN) -> + ok; + Factor when is_integer(Factor) andalso (Factor =< ?TTEST_MIN_FACTOR) -> + ok; + Factor when is_integer(Factor) -> + {skip, ?F("Too slow for TTest (~w)", [Factor])}; + _ -> + {skip, "Too slow for TTest (undef)"} + end. + +ttest_small_max_outstanding(Config) -> + EnvKey = "ESOCK_TEST_TTEST_SMALL_MAX_OUTSTANDING", + Default = ?TTEST_DEFAULT_SMALL_MAX_OUTSTANDING, + DefaultMaxOutstanding = ttest_max_outstanding(Config, EnvKey, Default), + ttest_max_outstanding(Config, DefaultMaxOutstanding). + +ttest_medium_max_outstanding(Config) -> + SmallMaxOutstanding = ttest_small_max_outstanding(Config), + EnvKey = "ESOCK_TEST_TTEST_MEDIUM_MAX_OUTSTANDING", + Default = ?TTEST_MK_DEFAULT_MAX_OUTSTANDING( + SmallMaxOutstanding), + DefaultMaxOutstanding = ttest_max_outstanding(Config, EnvKey, Default), + ttest_max_outstanding(Config, DefaultMaxOutstanding). + +ttest_large_max_outstanding(Config) -> + MediumMaxOutstanding = ttest_medium_max_outstanding(Config), + EnvKey = "ESOCK_TEST_TTEST_LARGE_MAX_OUTSTANDING", + Default = ?TTEST_MK_DEFAULT_MAX_OUTSTANDING( + MediumMaxOutstanding), + DefaultMaxOutstanding = ttest_max_outstanding(Config, EnvKey, Default), + ttest_max_outstanding(Config, DefaultMaxOutstanding). + +ttest_max_outstanding(Config, Default) + when is_integer(Default) andalso (Default > 1) -> + %% Note that we should not even get here if factor > 4 + case ?config(kernel_factor, Config) of + 1 -> Default; + 2 when (Default >= 2) -> Default div 2; + 3 when (Default >= 4) -> Default div 4; + _ when (Default >= 8) -> Default div 8; + _ -> 1 + end; +ttest_max_outstanding(_, _) -> + 1. + +ttest_max_outstanding(Config, EnvKey, Default) -> + Key = list_to_atom(string:to_lower(EnvKey)), + case lists:keysearch(Key, 1, Config) of + {value, {Key, MO}} when is_integer(MO) andalso (MO > 0) -> + MO; + _ -> + case os:getenv(EnvKey) of + false -> + Default; + Val -> + try list_to_integer(Val) of + MO when (MO > 0) -> + MO; + _ -> + 1 + catch + _:_:_ -> + Default + end + end + end. + ttest_cases() -> [ %% Server: transport = gen_tcp, active = false @@ -1356,6 +1554,9 @@ ttest_cases() -> %% Server: transport = gen_tcp, active = true {group, ttest_sgent}, + %% Server: transport = gen_tcp(socket), active = false + {group, ttest_sgsf}, + %% Server: transport = socket(tcp), active = false {group, ttest_ssockf}, @@ -1363,7 +1564,10 @@ ttest_cases() -> {group, ttest_ssocko}, %% Server: transport = socket(tcp), active = true - {group, ttest_ssockt} + {group, ttest_ssockt}, + + %% simple: Server: transport = socket(tcp), active = true + {group, ttest_simple_ssockt} ]. @@ -1384,47 +1588,84 @@ ttest_sgenf_cgen_cases() -> {group, ttest_sgenf_cgent} ]. +%% Server: transport = gen_tcp(socket), active = false +ttest_sgsf_cases() -> + [ + %% {group, ttest_sgenf_cgen}, + {group, ttest_sgsf_csock} + ]. + %% Server: transport = gen_tcp, active = false %% Client: transport = gen_tcp, active = false -ttest_sgenf_cgenf_cases() -> - [ - ttest_sgenf_cgenf_small_tcp4, - ttest_sgenf_cgenf_small_tcp6, - ttest_sgenf_cgenf_medium_tcp4, - ttest_sgenf_cgenf_medium_tcp6, +ttest_conditional_cases(Env, Default, Cases) -> + case os:getenv(Env) of + false -> + Default; + Val -> + case list_to_atom(string:to_lower(Val)) of + Use when (Use =:= include) orelse + (Use =:= enable) orelse + (Use =:= true) -> + Cases; + _ -> % Assumed to be explicitly *disabled* + [] + end + end. + +ttest_small_conditional_cases(Cases) -> + ttest_conditional_cases("ESOCK_TEST_TTEST_SMALL", Cases, Cases). - ttest_sgenf_cgenf_large_tcp4, - ttest_sgenf_cgenf_large_tcp6 - ]. +ttest_medium_conditional_cases(Cases) -> + ttest_conditional_cases("ESOCK_TEST_TTEST_MEDIUM", [], Cases). + +ttest_large_conditional_cases(Cases) -> + ttest_conditional_cases("ESOCK_TEST_TTEST_LARGE", [], Cases). + +ttest_select_conditional_cases(Small, Medium, Large) -> + ttest_small_conditional_cases(Small) ++ + ttest_medium_conditional_cases(Medium) ++ + ttest_large_conditional_cases(Large). + +ttest_sgenf_cgenf_cases() -> + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_cgenf_small_tcp4, + ttest_sgenf_cgenf_small_tcp6], + %% Medium + [ttest_sgenf_cgenf_medium_tcp4, + ttest_sgenf_cgenf_medium_tcp6], + %% Large + [ttest_sgenf_cgenf_large_tcp4, + ttest_sgenf_cgenf_large_tcp6]). %% Server: transport = gen_tcp, active = false %% Client: transport = gen_tcp, active = once ttest_sgenf_cgeno_cases() -> - [ - ttest_sgenf_cgeno_small_tcp4, - ttest_sgenf_cgeno_small_tcp6, - - ttest_sgenf_cgeno_medium_tcp4, - ttest_sgenf_cgeno_medium_tcp6, - - ttest_sgenf_cgeno_large_tcp4, - ttest_sgenf_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_cgeno_small_tcp4, + ttest_sgenf_cgeno_small_tcp6], + %% Medium + [ttest_sgenf_cgeno_medium_tcp4, + ttest_sgenf_cgeno_medium_tcp6], + %% Large + [ttest_sgenf_cgeno_large_tcp4, + ttest_sgenf_cgeno_large_tcp6]). %% Server: transport = gen_tcp, active = false %% Client: transport = gen_tcp, active = true ttest_sgenf_cgent_cases() -> - [ - ttest_sgenf_cgent_small_tcp4, - ttest_sgenf_cgent_small_tcp6, - - ttest_sgenf_cgent_medium_tcp4, - ttest_sgenf_cgent_medium_tcp6, - - ttest_sgenf_cgent_large_tcp4, - ttest_sgenf_cgent_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_cgent_small_tcp4, + ttest_sgenf_cgent_small_tcp6], + %% Medium + [ttest_sgenf_cgent_medium_tcp4, + ttest_sgenf_cgent_medium_tcp6], + %% Large + [ttest_sgenf_cgent_large_tcp4, + ttest_sgenf_cgent_large_tcp6]). %% Server: transport = gen_tcp, active = false %% Client: transport = socket(tcp) @@ -1436,41 +1677,62 @@ ttest_sgenf_csock_cases() -> ]. ttest_sgenf_csockf_cases() -> - [ - ttest_sgenf_csockf_small_tcp4, - ttest_sgenf_csockf_small_tcp6, - - ttest_sgenf_csockf_medium_tcp4, - ttest_sgenf_csockf_medium_tcp6, - - ttest_sgenf_csockf_large_tcp4, - ttest_sgenf_csockf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_csockf_small_tcp4, + ttest_sgenf_csockf_small_tcp6], + %% Medium + [ttest_sgenf_csockf_medium_tcp4, + ttest_sgenf_csockf_medium_tcp6], + %% Large + [ttest_sgenf_csockf_large_tcp4, + ttest_sgenf_csockf_large_tcp6]). ttest_sgenf_csocko_cases() -> - [ - ttest_sgenf_csocko_small_tcp4, - ttest_sgenf_csocko_small_tcp6, - - ttest_sgenf_csocko_medium_tcp4, - ttest_sgenf_csocko_medium_tcp6, - - ttest_sgenf_csocko_large_tcp4, - ttest_sgenf_csocko_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_csocko_small_tcp4, + ttest_sgenf_csocko_small_tcp6], + %% Medium + [ttest_sgenf_csocko_medium_tcp4, + ttest_sgenf_csocko_medium_tcp6], + %% Large + [ttest_sgenf_csocko_large_tcp4, + ttest_sgenf_csocko_large_tcp6]). ttest_sgenf_csockt_cases() -> + ttest_select_conditional_cases( + %% Small + [ttest_sgenf_csockt_small_tcp4, + ttest_sgenf_csockt_small_tcp6], + %% Medium + [ttest_sgenf_csockt_medium_tcp4, + ttest_sgenf_csockt_medium_tcp6], + %% Large + [ttest_sgenf_csockt_large_tcp4, + ttest_sgenf_csockt_large_tcp6]). + +%% Server: transport = gen_tcp(socket), active = false +%% Client: transport = socket(tcp) +ttest_sgsf_csock_cases() -> [ - ttest_sgenf_csockt_small_tcp4, - ttest_sgenf_csockt_small_tcp6, - - ttest_sgenf_csockt_medium_tcp4, - ttest_sgenf_csockt_medium_tcp6, - - ttest_sgenf_csockt_large_tcp4, - ttest_sgenf_csockt_large_tcp6 + {group, ttest_sgsf_csockf}%% , + %% {group, ttest_sgsf_csocko}, + %% {group, ttest_sgsf_csockt} ]. +ttest_sgsf_csockf_cases() -> + ttest_select_conditional_cases( + %% Small + [ttest_sgsf_csockf_small_tcp4, + ttest_sgsf_csockf_small_tcp6], + %% Medium + [ttest_sgsf_csockf_medium_tcp4, + ttest_sgsf_csockf_medium_tcp6], + %% Large + [ttest_sgsf_csockf_large_tcp4, + ttest_sgsf_csockf_large_tcp6]). + %% Server: transport = gen_tcp, active = once ttest_sgeno_cases() -> [ @@ -1490,44 +1752,44 @@ ttest_sgeno_cgen_cases() -> %% Server: transport = gen_tcp, active = once %% Client: transport = gen_tcp, active = false ttest_sgeno_cgenf_cases() -> - [ - ttest_sgeno_cgenf_small_tcp4, - ttest_sgeno_cgenf_small_tcp6, - - ttest_sgeno_cgenf_medium_tcp4, - ttest_sgeno_cgenf_medium_tcp6, - - ttest_sgeno_cgenf_large_tcp4, - ttest_sgeno_cgenf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_cgenf_small_tcp4, + ttest_sgeno_cgenf_small_tcp6], + %% Medium + [ttest_sgeno_cgenf_medium_tcp4, + ttest_sgeno_cgenf_medium_tcp6], + %% Large + [ttest_sgeno_cgenf_large_tcp4, + ttest_sgeno_cgenf_large_tcp6]). %% Server: transport = gen_tcp, active = once %% Client: transport = gen_tcp, active = once ttest_sgeno_cgeno_cases() -> - [ - ttest_sgeno_cgeno_small_tcp4, - ttest_sgeno_cgeno_small_tcp6, - - ttest_sgeno_cgeno_medium_tcp4, - ttest_sgeno_cgeno_medium_tcp6, - - ttest_sgeno_cgeno_large_tcp4, - ttest_sgeno_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_cgeno_small_tcp4, + ttest_sgeno_cgeno_small_tcp6], + %% Medium + [ttest_sgeno_cgeno_medium_tcp4, + ttest_sgeno_cgeno_medium_tcp6], + %% Large + [ttest_sgeno_cgeno_large_tcp4, + ttest_sgeno_cgeno_large_tcp6]). %% Server: transport = gen_tcp, active = once %% Client: transport = gen_tcp, active = true ttest_sgeno_cgent_cases() -> - [ - ttest_sgeno_cgent_small_tcp4, - ttest_sgeno_cgent_small_tcp6, - - ttest_sgeno_cgent_medium_tcp4, - ttest_sgeno_cgent_medium_tcp6, - - ttest_sgeno_cgent_large_tcp4, - ttest_sgeno_cgent_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_cgent_small_tcp4, + ttest_sgeno_cgent_small_tcp6], + %% Medium + [ttest_sgeno_cgent_medium_tcp4, + ttest_sgeno_cgent_medium_tcp6], + %% Large + [ttest_sgeno_cgent_large_tcp4, + ttest_sgeno_cgent_large_tcp6]). %% Server: transport = gen_tcp, active = once %% Client: transport = socket(tcp) @@ -1539,40 +1801,40 @@ ttest_sgeno_csock_cases() -> ]. ttest_sgeno_csockf_cases() -> - [ - ttest_sgeno_csockf_small_tcp4, - ttest_sgeno_csockf_small_tcp6, - - ttest_sgeno_csockf_medium_tcp4, - ttest_sgeno_csockf_medium_tcp6, - - ttest_sgeno_csockf_large_tcp4, - ttest_sgeno_csockf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_csockf_small_tcp4, + ttest_sgeno_csockf_small_tcp6], + %% Medium + [ttest_sgeno_csockf_medium_tcp4, + ttest_sgeno_csockf_medium_tcp6], + %% Large + [ttest_sgeno_csockf_large_tcp4, + ttest_sgeno_csockf_large_tcp6]). ttest_sgeno_csocko_cases() -> - [ - ttest_sgeno_csocko_small_tcp4, - ttest_sgeno_csocko_small_tcp6, - - ttest_sgeno_csocko_medium_tcp4, - ttest_sgeno_csocko_medium_tcp6, - - ttest_sgeno_csocko_large_tcp4, - ttest_sgeno_csocko_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_csocko_small_tcp4, + ttest_sgeno_csocko_small_tcp6], + %% Medium + [ttest_sgeno_csocko_medium_tcp4, + ttest_sgeno_csocko_medium_tcp6], + %% Large + [ttest_sgeno_csocko_large_tcp4, + ttest_sgeno_csocko_large_tcp6]). ttest_sgeno_csockt_cases() -> - [ - ttest_sgeno_csockt_small_tcp4, - ttest_sgeno_csockt_small_tcp6, - - ttest_sgeno_csockt_medium_tcp4, - ttest_sgeno_csockt_medium_tcp6, - - ttest_sgeno_csockt_large_tcp4, - ttest_sgeno_csockt_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgeno_csockt_small_tcp4, + ttest_sgeno_csockt_small_tcp6], + %% Medium + [ttest_sgeno_csockt_medium_tcp4, + ttest_sgeno_csockt_medium_tcp6], + %% Large + [ttest_sgeno_csockt_large_tcp4, + ttest_sgeno_csockt_large_tcp6]). %% Server: transport = gen_tcp, active = true ttest_sgent_cases() -> @@ -1593,44 +1855,44 @@ ttest_sgent_cgen_cases() -> %% Server: transport = gen_tcp, active = true %% Client: transport = gen_tcp, active = false ttest_sgent_cgenf_cases() -> - [ - ttest_sgent_cgenf_small_tcp4, - ttest_sgent_cgenf_small_tcp6, - - ttest_sgent_cgenf_medium_tcp4, - ttest_sgent_cgenf_medium_tcp6, - - ttest_sgent_cgenf_large_tcp4, - ttest_sgent_cgenf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_cgenf_small_tcp4, + ttest_sgent_cgenf_small_tcp6], + %% Medium + [ttest_sgent_cgenf_medium_tcp4, + ttest_sgent_cgenf_medium_tcp6], + %% Large + [ttest_sgent_cgenf_large_tcp4, + ttest_sgent_cgenf_large_tcp6]). %% Server: transport = gen_tcp, active = true %% Client: transport = gen_tcp, active = once ttest_sgent_cgeno_cases() -> - [ - ttest_sgent_cgeno_small_tcp4, - ttest_sgent_cgeno_small_tcp6, - - ttest_sgent_cgeno_medium_tcp4, - ttest_sgent_cgeno_medium_tcp6, - - ttest_sgent_cgeno_large_tcp4, - ttest_sgent_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_cgeno_small_tcp4, + ttest_sgent_cgeno_small_tcp6], + %% Medium + [ttest_sgent_cgeno_medium_tcp4, + ttest_sgent_cgeno_medium_tcp6], + %% Large + [ttest_sgent_cgeno_large_tcp4, + ttest_sgent_cgeno_large_tcp6]). %% Server: transport = gen_tcp, active = true %% Client: transport = gen_tcp, active = true ttest_sgent_cgent_cases() -> - [ - ttest_sgent_cgent_small_tcp4, - ttest_sgent_cgent_small_tcp6, - - ttest_sgent_cgent_medium_tcp4, - ttest_sgent_cgent_medium_tcp6, - - ttest_sgent_cgent_large_tcp4, - ttest_sgent_cgent_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_cgent_small_tcp4, + ttest_sgent_cgent_small_tcp6], + %% Medium + [ttest_sgent_cgent_medium_tcp4, + ttest_sgent_cgent_medium_tcp6], + %% Large + [ttest_sgent_cgent_large_tcp4, + ttest_sgent_cgent_large_tcp6]). %% Server: transport = gen_tcp, active = true %% Client: transport = socket(tcp) @@ -1642,46 +1904,47 @@ ttest_sgent_csock_cases() -> ]. ttest_sgent_csockf_cases() -> - [ - ttest_sgent_csockf_small_tcp4, - ttest_sgent_csockf_small_tcp6, - - ttest_sgent_csockf_medium_tcp4, - ttest_sgent_csockf_medium_tcp6, - - ttest_sgent_csockf_large_tcp4, - ttest_sgent_csockf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_csockf_small_tcp4, + ttest_sgent_csockf_small_tcp6], + %% Medium + [ttest_sgent_csockf_medium_tcp4, + ttest_sgent_csockf_medium_tcp6], + %% Large + [ttest_sgent_csockf_large_tcp4, + ttest_sgent_csockf_large_tcp6]). ttest_sgent_csocko_cases() -> - [ - ttest_sgent_csocko_small_tcp4, - ttest_sgent_csocko_small_tcp6, - - ttest_sgent_csocko_medium_tcp4, - ttest_sgent_csocko_medium_tcp6, - - ttest_sgent_csocko_large_tcp4, - ttest_sgent_csocko_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_csocko_small_tcp4, + ttest_sgent_csocko_small_tcp6], + %% Medium + [ttest_sgent_csocko_medium_tcp4, + ttest_sgent_csocko_medium_tcp6], + %% Large + [ttest_sgent_csocko_large_tcp4, + ttest_sgent_csocko_large_tcp6]). ttest_sgent_csockt_cases() -> - [ - ttest_sgent_csockt_small_tcp4, - ttest_sgent_csockt_small_tcp6, - - ttest_sgent_csockt_medium_tcp4, - ttest_sgent_csockt_medium_tcp6, - - ttest_sgent_csockt_large_tcp4, - ttest_sgent_csockt_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_sgent_csockt_small_tcp4, + ttest_sgent_csockt_small_tcp6], + %% Medium + [ttest_sgent_csockt_medium_tcp4, + ttest_sgent_csockt_medium_tcp6], + %% Large + [ttest_sgent_csockt_large_tcp4, + ttest_sgent_csockt_large_tcp6]). %% Server: transport = socket(tcp), active = false ttest_ssockf_cases() -> [ {group, ttest_ssockf_cgen}, - {group, ttest_ssockf_csock} + {group, ttest_ssockf_csock}, + {group, ttest_ssockf_cgsf} ]. %% Server: transport = socket(tcp), active = false @@ -1696,45 +1959,68 @@ ttest_ssockf_cgen_cases() -> %% Server: transport = socket(tcp), active = false %% Client: transport = gen_tcp, active = false ttest_ssockf_cgenf_cases() -> - [ - ttest_ssockf_cgenf_small_tcp4, - ttest_ssockf_cgenf_small_tcp6, - - ttest_ssockf_cgenf_medium_tcp4, - ttest_ssockf_cgenf_medium_tcp6, - - ttest_ssockf_cgenf_large_tcp4, - ttest_ssockf_cgenf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_cgenf_small_tcp4, + ttest_ssockf_cgenf_small_tcp6], + %% Medium + [ttest_ssockf_cgenf_medium_tcp4, + ttest_ssockf_cgenf_medium_tcp6], + %% Large + [ttest_ssockf_cgenf_large_tcp4, + ttest_ssockf_cgenf_large_tcp6]). %% Server: transport = socket(tcp), active = false %% Client: transport = gen_tcp, active = once ttest_ssockf_cgeno_cases() -> - [ - ttest_ssockf_cgeno_small_tcp4, - ttest_ssockf_cgeno_small_tcp6, - - ttest_ssockf_cgeno_medium_tcp4, - ttest_ssockf_cgeno_medium_tcp6, - - ttest_ssockf_cgeno_large_tcp4, - ttest_ssockf_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_cgeno_small_tcp4, + ttest_ssockf_cgeno_small_tcp6], + %% Medium + [ttest_ssockf_cgeno_medium_tcp4, + ttest_ssockf_cgeno_medium_tcp6], + %% Large + [ttest_ssockf_cgeno_large_tcp4, + ttest_ssockf_cgeno_large_tcp6]). %% Server: transport = socket(tcp), active = false %% Client: transport = gen_tcp, active = true ttest_ssockf_cgent_cases() -> - [ - ttest_ssockf_cgent_small_tcp4, - ttest_ssockf_cgent_small_tcp6, + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_cgent_small_tcp4, + ttest_ssockf_cgent_small_tcp6], + %% Medium + [ttest_ssockf_cgent_medium_tcp4, + ttest_ssockf_cgent_medium_tcp6], + %% Large + [ttest_ssockf_cgent_large_tcp4, + ttest_ssockf_cgent_large_tcp6]). - ttest_ssockf_cgent_medium_tcp4, - ttest_ssockf_cgent_medium_tcp6, - - ttest_ssockf_cgent_large_tcp4, - ttest_ssockf_cgent_large_tcp6 +%% Server: transport = socket(tcp), active = false +%% Client: transport = gen_tcp(socket) +ttest_ssockf_cgs_cases() -> + [ + {group, ttest_ssockf_cgsf}%% , + %% {group, ttest_ssockf_cgeno}, + %% {group, ttest_ssockf_cgent} ]. +%% Server: transport = socket(tcp), active = false +%% Client: transport = gen_tcp(socket), active = false +ttest_ssockf_cgsf_cases() -> + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_cgsf_small_tcp4, + ttest_ssockf_cgsf_small_tcp6], + %% Medium + [ttest_ssockf_cgsf_medium_tcp4, + ttest_ssockf_cgsf_medium_tcp6], + %% Large + [ttest_ssockf_cgsf_large_tcp4, + ttest_ssockf_cgsf_large_tcp6]). + %% Server: transport = socket(tcp), active = false %% Client: transport = socket(tcp) ttest_ssockf_csock_cases() -> @@ -1747,53 +2033,53 @@ ttest_ssockf_csock_cases() -> %% Server: transport = socket(tcp), active = false %% Client: transport = socket(tcp), active = false ttest_ssockf_csockf_cases() -> - [ - ttest_ssockf_csockf_small_tcp4, - ttest_ssockf_csockf_small_tcp6, - ttest_ssockf_csockf_small_tcpL, - - ttest_ssockf_csockf_medium_tcp4, - ttest_ssockf_csockf_medium_tcp6, - ttest_ssockf_csockf_medium_tcpL, - - ttest_ssockf_csockf_large_tcp4, - ttest_ssockf_csockf_large_tcp6, - ttest_ssockf_csockf_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_csockf_small_tcp4, + ttest_ssockf_csockf_small_tcp6, + ttest_ssockf_csockf_small_tcpL], + %% Medium + [ttest_ssockf_csockf_medium_tcp4, + ttest_ssockf_csockf_medium_tcp6, + ttest_ssockf_csockf_medium_tcpL], + %% Large + [ttest_ssockf_csockf_large_tcp4, + ttest_ssockf_csockf_large_tcp6, + ttest_ssockf_csockf_large_tcpL]). %% Server: transport = socket(tcp), active = false %% Client: transport = socket(tcp), active = once ttest_ssockf_csocko_cases() -> - [ - ttest_ssockf_csocko_small_tcp4, - ttest_ssockf_csocko_small_tcp6, - ttest_ssockf_csocko_small_tcpL, - - ttest_ssockf_csocko_medium_tcp4, - ttest_ssockf_csocko_medium_tcp6, - ttest_ssockf_csocko_medium_tcpL, - - ttest_ssockf_csocko_large_tcp4, - ttest_ssockf_csocko_large_tcp6, - ttest_ssockf_csocko_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_csocko_small_tcp4, + ttest_ssockf_csocko_small_tcp6, + ttest_ssockf_csocko_small_tcpL], + %% Medium + [ttest_ssockf_csocko_medium_tcp4, + ttest_ssockf_csocko_medium_tcp6, + ttest_ssockf_csocko_medium_tcpL], + %% Large + [ttest_ssockf_csocko_large_tcp4, + ttest_ssockf_csocko_large_tcp6, + ttest_ssockf_csocko_large_tcpL]). %% Server: transport = socket(tcp), active = false %% Client: transport = socket(tcp), active = true ttest_ssockf_csockt_cases() -> - [ - ttest_ssockf_csockt_small_tcp4, - ttest_ssockf_csockt_small_tcp6, - ttest_ssockf_csockt_small_tcpL, - - ttest_ssockf_csockt_medium_tcp4, - ttest_ssockf_csockt_medium_tcp6, - ttest_ssockf_csockt_medium_tcpL, - - ttest_ssockf_csockt_large_tcp4, - ttest_ssockf_csockt_large_tcp6, - ttest_ssockf_csockt_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockf_csockt_small_tcp4, + ttest_ssockf_csockt_small_tcp6, + ttest_ssockf_csockt_small_tcpL], + %% Medium + [ttest_ssockf_csockt_medium_tcp4, + ttest_ssockf_csockt_medium_tcp6, + ttest_ssockf_csockt_medium_tcpL], + %% Large + [ttest_ssockf_csockt_large_tcp4, + ttest_ssockf_csockt_large_tcp6, + ttest_ssockf_csockt_large_tcpL]). %% Server: transport = socket(tcp), active = once ttest_ssocko_cases() -> @@ -1814,44 +2100,44 @@ ttest_ssocko_cgen_cases() -> %% Server: transport = socket(tcp), active = once %% Client: transport = gen_tcp, active = false ttest_ssocko_cgenf_cases() -> - [ - ttest_ssocko_cgenf_small_tcp4, - ttest_ssocko_cgenf_small_tcp6, - - ttest_ssocko_cgenf_medium_tcp4, - ttest_ssocko_cgenf_medium_tcp6, - - ttest_ssocko_cgenf_large_tcp4, - ttest_ssocko_cgenf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_cgenf_small_tcp4, + ttest_ssocko_cgenf_small_tcp6], + %% Medium + [ttest_ssocko_cgenf_medium_tcp4, + ttest_ssocko_cgenf_medium_tcp6], + %% Large + [ttest_ssocko_cgenf_large_tcp4, + ttest_ssocko_cgenf_large_tcp6]). %% Server: transport = socket(tcp), active = once %% Client: transport = gen_tcp, active = once ttest_ssocko_cgeno_cases() -> - [ - ttest_ssocko_cgeno_small_tcp4, - ttest_ssocko_cgeno_small_tcp6, - - ttest_ssocko_cgeno_medium_tcp4, - ttest_ssocko_cgeno_medium_tcp6, - - ttest_ssocko_cgeno_large_tcp4, - ttest_ssocko_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_cgeno_small_tcp4, + ttest_ssocko_cgeno_small_tcp6], + %% Medium + [ttest_ssocko_cgeno_medium_tcp4, + ttest_ssocko_cgeno_medium_tcp6], + %% Large + [ttest_ssocko_cgeno_large_tcp4, + ttest_ssocko_cgeno_large_tcp6]). %% Server: transport = socket(tcp), active = once %% Client: transport = gen_tcp, active = true ttest_ssocko_cgent_cases() -> - [ - ttest_ssocko_cgent_small_tcp4, - ttest_ssocko_cgent_small_tcp6, - - ttest_ssocko_cgent_medium_tcp4, - ttest_ssocko_cgent_medium_tcp6, - - ttest_ssocko_cgent_large_tcp4, - ttest_ssocko_cgent_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_cgent_small_tcp4, + ttest_ssocko_cgent_small_tcp6], + %% Medium + [ttest_ssocko_cgent_medium_tcp4, + ttest_ssocko_cgent_medium_tcp6], + %% Large + [ttest_ssocko_cgent_large_tcp4, + ttest_ssocko_cgent_large_tcp6]). %% Server: transport = socket(tcp), active = once %% Client: transport = socket(tcp) @@ -1865,53 +2151,53 @@ ttest_ssocko_csock_cases() -> %% Server: transport = socket(tcp), active = once %% Client: transport = socket(tcp), active = false ttest_ssocko_csockf_cases() -> - [ - ttest_ssocko_csockf_small_tcp4, - ttest_ssocko_csockf_small_tcp6, - ttest_ssocko_csockf_small_tcpL, - - ttest_ssocko_csockf_medium_tcp4, - ttest_ssocko_csockf_medium_tcp6, - ttest_ssocko_csockf_medium_tcpL, - - ttest_ssocko_csockf_large_tcp4, - ttest_ssocko_csockf_large_tcp6, - ttest_ssocko_csockf_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_csockf_small_tcp4, + ttest_ssocko_csockf_small_tcp6, + ttest_ssocko_csockf_small_tcpL], + %% Medium + [ttest_ssocko_csockf_medium_tcp4, + ttest_ssocko_csockf_medium_tcp6, + ttest_ssocko_csockf_medium_tcpL], + %% Large + [ttest_ssocko_csockf_large_tcp4, + ttest_ssocko_csockf_large_tcp6, + ttest_ssocko_csockf_large_tcpL]). %% Server: transport = socket(tcp), active = once %% Client: transport = socket(tcp), active = once ttest_ssocko_csocko_cases() -> - [ - ttest_ssocko_csocko_small_tcp4, - ttest_ssocko_csocko_small_tcp6, - ttest_ssocko_csocko_small_tcpL, - - ttest_ssocko_csocko_medium_tcp4, - ttest_ssocko_csocko_medium_tcp6, - ttest_ssocko_csocko_medium_tcpL, - - ttest_ssocko_csocko_large_tcp4, - ttest_ssocko_csocko_large_tcp6, - ttest_ssocko_csocko_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_csocko_small_tcp4, + ttest_ssocko_csocko_small_tcp6, + ttest_ssocko_csocko_small_tcpL], + %% Medium + [ttest_ssocko_csocko_medium_tcp4, + ttest_ssocko_csocko_medium_tcp6, + ttest_ssocko_csocko_medium_tcpL], + %% Large + [ttest_ssocko_csocko_large_tcp4, + ttest_ssocko_csocko_large_tcp6, + ttest_ssocko_csocko_large_tcpL]). %% Server: transport = socket(tcp), active = once %% Client: transport = socket(tcp), active = true ttest_ssocko_csockt_cases() -> - [ - ttest_ssocko_csockt_small_tcp4, - ttest_ssocko_csockt_small_tcp6, - ttest_ssocko_csockt_small_tcpL, - - ttest_ssocko_csockt_medium_tcp4, - ttest_ssocko_csockt_medium_tcp6, - ttest_ssocko_csockt_medium_tcpL, - - ttest_ssocko_csockt_large_tcp4, - ttest_ssocko_csockt_large_tcp6, - ttest_ssocko_csockt_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssocko_csockt_small_tcp4, + ttest_ssocko_csockt_small_tcp6, + ttest_ssocko_csockt_small_tcpL], + %% Medium + [ttest_ssocko_csockt_medium_tcp4, + ttest_ssocko_csockt_medium_tcp6, + ttest_ssocko_csockt_medium_tcpL], + %% Large + [ttest_ssocko_csockt_large_tcp4, + ttest_ssocko_csockt_large_tcp6, + ttest_ssocko_csockt_large_tcpL]). %% Server: transport = socket(tcp), active = true ttest_ssockt_cases() -> @@ -1932,44 +2218,44 @@ ttest_ssockt_cgen_cases() -> %% Server: transport = socket(tcp), active = true %% Client: transport = gen_tcp, active = false ttest_ssockt_cgenf_cases() -> - [ - ttest_ssockt_cgenf_small_tcp4, - ttest_ssockt_cgenf_small_tcp6, - - ttest_ssockt_cgenf_medium_tcp4, - ttest_ssockt_cgenf_medium_tcp6, - - ttest_ssockt_cgenf_large_tcp4, - ttest_ssockt_cgenf_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_cgenf_small_tcp4, + ttest_ssockt_cgenf_small_tcp6], + %% Medium + [ttest_ssockt_cgenf_medium_tcp4, + ttest_ssockt_cgenf_medium_tcp6], + %% Large + [ttest_ssockt_cgenf_large_tcp4, + ttest_ssockt_cgenf_large_tcp6]). %% Server: transport = socket(tcp), active = true %% Client: transport = gen_tcp, active = once ttest_ssockt_cgeno_cases() -> - [ - ttest_ssockt_cgeno_small_tcp4, - ttest_ssockt_cgeno_small_tcp6, - - ttest_ssockt_cgeno_medium_tcp4, - ttest_ssockt_cgeno_medium_tcp6, - - ttest_ssockt_cgeno_large_tcp4, - ttest_ssockt_cgeno_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_cgeno_small_tcp4, + ttest_ssockt_cgeno_small_tcp6], + %% Medium + [ttest_ssockt_cgeno_medium_tcp4, + ttest_ssockt_cgeno_medium_tcp6], + %% Large + [ttest_ssockt_cgeno_large_tcp4, + ttest_ssockt_cgeno_large_tcp6]). %% Server: transport = socket(tcp), active = true %% Client: transport = gen_tcp, active = true ttest_ssockt_cgent_cases() -> - [ - ttest_ssockt_cgent_small_tcp4, - ttest_ssockt_cgent_small_tcp6, - - ttest_ssockt_cgent_medium_tcp4, - ttest_ssockt_cgent_medium_tcp6, - - ttest_ssockt_cgent_large_tcp4, - ttest_ssockt_cgent_large_tcp6 - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_cgent_small_tcp4, + ttest_ssockt_cgent_small_tcp6], + %% Medium + [ttest_ssockt_cgent_medium_tcp4, + ttest_ssockt_cgent_medium_tcp6], + %% Large + [ttest_ssockt_cgent_large_tcp4, + ttest_ssockt_cgent_large_tcp6]). %% Server: transport = socket(tcp), active = true %% Client: transport = socket(tcp) @@ -1983,57 +2269,87 @@ ttest_ssockt_csock_cases() -> %% Server: transport = socket(tcp), active = true %% Client: transport = socket(tcp), active = false ttest_ssockt_csockf_cases() -> - [ - ttest_ssockt_csockf_small_tcp4, - ttest_ssockt_csockf_small_tcp6, - ttest_ssockt_csockf_small_tcpL, - - ttest_ssockt_csockf_medium_tcp4, - ttest_ssockt_csockf_medium_tcp6, - ttest_ssockt_csockf_medium_tcpL, - - ttest_ssockt_csockf_large_tcp4, - ttest_ssockt_csockf_large_tcp6, - ttest_ssockt_csockf_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_csockf_small_tcp4, + ttest_ssockt_csockf_small_tcp6, + ttest_ssockt_csockf_small_tcpL], + %% Medium + [ttest_ssockt_csockf_medium_tcp4, + ttest_ssockt_csockf_medium_tcp6, + ttest_ssockt_csockf_medium_tcpL], + %% Large + [ttest_ssockt_csockf_large_tcp4, + ttest_ssockt_csockf_large_tcp6, + ttest_ssockt_csockf_large_tcpL]). %% Server: transport = socket(tcp), active = true %% Client: transport = socket(tcp), active = once ttest_ssockt_csocko_cases() -> - [ - ttest_ssockt_csocko_small_tcp4, - ttest_ssockt_csocko_small_tcp6, - ttest_ssockt_csocko_small_tcpL, - - ttest_ssockt_csocko_medium_tcp4, - ttest_ssockt_csocko_medium_tcp6, - ttest_ssockt_csocko_medium_tcpL, - - ttest_ssockt_csocko_large_tcp4, - ttest_ssockt_csocko_large_tcp6, - ttest_ssockt_csocko_large_tcpL - ]. + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_csocko_small_tcp4, + ttest_ssockt_csocko_small_tcp6, + ttest_ssockt_csocko_small_tcpL], + %% Medium + [ttest_ssockt_csocko_medium_tcp4, + ttest_ssockt_csocko_medium_tcp6, + ttest_ssockt_csocko_medium_tcpL], + %% Large + [ttest_ssockt_csocko_large_tcp4, + ttest_ssockt_csocko_large_tcp6, + ttest_ssockt_csocko_large_tcpL]). %% Server: transport = socket(tcp), active = true %% Client: transport = socket(tcp), active = true ttest_ssockt_csockt_cases() -> - [ - ttest_ssockt_csockt_small_tcp4, - ttest_ssockt_csockt_small_tcp6, - ttest_ssockt_csockt_small_tcpL, + ttest_select_conditional_cases( + %% Small + [ttest_ssockt_csockt_small_tcp4, + ttest_ssockt_csockt_small_tcp6, + ttest_ssockt_csockt_small_tcpL], + %% Medium + [ttest_ssockt_csockt_medium_tcp4, + ttest_ssockt_csockt_medium_tcp6, + ttest_ssockt_csockt_medium_tcpL], + %% Large + [ttest_ssockt_csockt_large_tcp4, + ttest_ssockt_csockt_large_tcp6, + ttest_ssockt_csockt_large_tcpL]). - ttest_ssockt_csockt_medium_tcp4, - ttest_ssockt_csockt_medium_tcp6, - ttest_ssockt_csockt_medium_tcpL, +%% Server: transport = socket(tcp), active = true +ttest_simple_ssockt_cases() -> + [ + {group, ttest_simple_ssockt_csock} + ]. - ttest_ssockt_csockt_large_tcp4, - ttest_ssockt_csockt_large_tcp6, - ttest_ssockt_csockt_large_tcpL +%% Server: transport = socket(tcp), active = true +%% Client: transport = socket(tcp) +ttest_simple_ssockt_csock_cases() -> + [ + %% {group, ttest_simple_ssockt_csockf}, + {group, ttest_simple_ssockt_csocko}%% , + %% {group, ttest_simple_ssockt_csockt} ]. +%% Server: transport = socket(tcp), active = true +%% Client: transport = socket(tcp), active = once +ttest_simple_ssockt_csocko_cases() -> + ttest_select_conditional_cases( + %% Small + [ttest_simple_ssockt_csocko_small_tcp4, + ttest_simple_ssockt_csocko_small_tcp6, + ttest_simple_ssockt_csocko_small_tcpL], + %% Medium + [], + %% Large + []). + tickets_cases() -> [ - {group, otp16359} + {group, otp16359}, + {group, otp18240}, + otp18635 ]. otp16359_cases() -> @@ -2044,38 +2360,58 @@ otp16359_cases() -> ]. +otp18240_cases() -> + [ + otp18240_accept_mon_leak_tcp4, + otp18240_accept_mon_leak_tcp6 + ]. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -init_per_suite(Config) -> - io:format("init_per_suite -> entry with" - "~n Config: ~p" - "~n", [Config]), - ct:timetrap(?MINS(2)), - Factor = analyze_and_print_host_info(), +init_per_suite(Config0) -> + ?P("init_per_suite -> entry with" + "~n Config: ~p" + "~n Nodes: ~p", [Config0, erlang:nodes()]), + try socket:info() of #{} -> - socket:use_registry(false), - case quiet_mode(Config) of - default -> - case ?LOGGER:start() of - ok -> - [{esock_factor, Factor} | Config]; - {error, Reason} -> - io:format("init_per_suite -> Failed starting logger" - "~n Reason: ~p" - "~n", [Reason]), - {skip, "Failed starting logger"} - end; - Quiet -> - case ?LOGGER:start(Quiet) of - ok -> - [{esock_factor, Factor}, - {esock_test_quiet, Quiet} | Config]; - {error, Reason} -> - io:format("init_per_suite -> Failed starting logger" - "~n Reason: ~p" - "~n", [Reason]), - {skip, "Failed starting logger"} + case ?KLIB:init_per_suite(Config0) of + {skip, _} = SKIP -> + SKIP; + + Config1 when is_list(Config1) -> + + ?P("init_per_suite -> end when " + "~n Config: ~p", [Config1]), + + %% We need a monitor on this node also + kernel_test_sys_monitor:start(), + + socket:use_registry(false), + case quiet_mode(Config1) of + default -> + case ?LOGGER:start() of + ok -> + Config1; + {error, Reason} -> + ?P("init_per_suite -> " + "Failed starting logger" + "~n Reason: ~p" + "~n", [Reason]), + {skip, "Failed starting logger"} + end; + Quiet -> + case ?LOGGER:start(Quiet) of + ok -> + [{esock_test_quiet, Quiet} | Config1]; + {error, Reason} -> + ?P("init_per_suite -> " + "Failed starting logger" + "~n Reason: ~p" + "~n", [Reason]), + {skip, "Failed starting logger"} + end end end catch @@ -2085,9 +2421,23 @@ init_per_suite(Config) -> {skip, "esock not configured"} end. -end_per_suite(_) -> +end_per_suite(Config0) -> + + ?P("end_per_suite -> entry with" + "~n Config: ~p" + "~n Nodes: ~p", [Config0, erlang:nodes()]), + + %% Stop the local monitor + kernel_test_sys_monitor:stop(), + (catch ?LOGGER:stop()), - ok. + + Config1 = ?KLIB:end_per_suite(Config0), + + ?P("end_per_suite -> " + "~n Nodes: ~p", [erlang:nodes()]), + + Config1. init_per_group(api_sendfile = GroupName, Config) -> @@ -2124,7 +2474,7 @@ init_per_group(GroupName, Config) "~n", [GroupName, Config]), %% Maybe we should skip the entire suite for this platform, %% but for now we just skip these groups, which seem to - %% have problems (slave node start). + %% have problems (node start). %% As stated elsewhere, its not really Fedora 16, but %% the *really* slow VM that is the issue. try is_old_fedora16() of @@ -2138,12 +2488,18 @@ init_per_group(ttest = _GroupName, Config) -> io:format("init_per_group(~w) -> entry with" "~n Config: ~p" "~n", [_GroupName, Config]), - ttest_manager_start(), - case lists:keysearch(esock_test_ttest_runtime, 1, Config) of - {value, _} -> - Config; - false -> - [{esock_test_ttest_runtime, which_ttest_runtime_env()} | Config] + case ttest_condition(Config) of + ok -> + ttest_manager_start(), + case lists:keysearch(esock_test_ttest_runtime, 1, Config) of + {value, _} -> + Config; + false -> + [{esock_test_ttest_runtime, which_ttest_runtime_env()} | + Config] + end; + {skip, _} = SKIP -> + SKIP end; init_per_group(api_async_ref, Config) -> [{select_handle, true} | Config]; @@ -2211,10 +2567,6 @@ double_data(N, Data) -> %% that we can call the "global" info function and that it returns %% a non-empty map... -api_m_info(suite) -> - []; -api_m_info(doc) -> - []; api_m_info(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_m_info, @@ -2244,10 +2596,6 @@ api_m_info() -> %% At the same time, it will test the info function (since it uses it %% for verification). -api_m_debug(suite) -> - []; -api_m_debug(doc) -> - []; api_m_debug(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_m_debug, @@ -2408,14 +2756,104 @@ api_m_error_bind(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and then close. +api_b_simple_open_and_close_udp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> + InitState = #{domain => inet, + type => dgram, + protocol => udp}, + ok = api_b_simple_open_and_close(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and then close. +api_b_simple_open_and_close_udp6(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv6() end, + fun() -> + InitState = #{domain => inet6, + type => dgram, + protocol => udp}, + ok = api_b_simple_open_and_close(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and then close. +api_b_simple_open_and_close_tcp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = api_b_simple_open_and_close(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and then close. +api_b_simple_open_and_close_tcp6(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv6() end, + fun() -> + InitState = #{domain => inet6, + type => stream, + protocol => tcp}, + ok = api_b_simple_open_and_close(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_b_simple_open_and_close(InitState) -> + Seq = + [ + #{desc => "open", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Protocol} = State) -> + case socket:open(Domain, Type, Protocol) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + + ?SEV_SLEEP(?SECS(1)), + + #{desc => "close socket", + cmd => fun(#{sock := Sock} = _State) -> + socket:close(Sock) + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + Evaluator = ?SEV_START("tester", Seq, InitState), + ok = ?SEV_AWAIT_FINISH([Evaluator]). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically open (create) and info of an IPv4 UDP (dgram) socket. %% With some extra checks... -api_b_open_and_info_udp4(suite) -> - []; -api_b_open_and_info_udp4(doc) -> - []; api_b_open_and_info_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_info_udp4, @@ -2432,10 +2870,6 @@ api_b_open_and_info_udp4(_Config) when is_list(_Config) -> %% Basically open (create) and info of an IPv6 UDP (dgram) socket. %% With some extra checks... -api_b_open_and_info_udp6(suite) -> - []; -api_b_open_and_info_udp6(doc) -> - []; api_b_open_and_info_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_info_udp6, @@ -2453,10 +2887,6 @@ api_b_open_and_info_udp6(_Config) when is_list(_Config) -> %% Basically open (create) and info of an IPv4 TCP (stream) socket. %% With some extra checks... -api_b_open_and_info_tcp4(suite) -> - []; -api_b_open_and_info_tcp4(doc) -> - []; api_b_open_and_info_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_info_tcp4, @@ -2473,10 +2903,6 @@ api_b_open_and_info_tcp4(_Config) when is_list(_Config) -> %% Basically open (create) and info of an IPv6 TCP (stream) socket. %% With some extra checks... -api_b_open_and_info_tcp6(suite) -> - []; -api_b_open_and_info_tcp6(doc) -> - []; api_b_open_and_info_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_info_tcp6, @@ -2554,10 +2980,6 @@ api_b_open_and_info(InitState) -> %% Basically open (create) and close an IPv4 UDP (dgram) socket. %% With some extra checks... -api_b_open_and_close_udp4(suite) -> - []; -api_b_open_and_close_udp4(doc) -> - []; api_b_open_and_close_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_udp4, @@ -2573,10 +2995,6 @@ api_b_open_and_close_udp4(_Config) when is_list(_Config) -> %% Basically open (create) and close an IPv6 UDP (dgram) socket. %% With some extra checks... -api_b_open_and_close_udp6(suite) -> - []; -api_b_open_and_close_udp6(doc) -> - []; api_b_open_and_close_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_udp6, @@ -2593,10 +3011,6 @@ api_b_open_and_close_udp6(_Config) when is_list(_Config) -> %% Basically open (create) and close an IPv4 TCP (stream) socket. %% With some extra checks... -api_b_open_and_close_tcp4(suite) -> - []; -api_b_open_and_close_tcp4(doc) -> - []; api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_tcp4, @@ -2612,10 +3026,6 @@ api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> %% Basically open (create) and close an IPv6 TCP (stream) socket. %% With some extra checks... -api_b_open_and_close_tcp6(suite) -> - []; -api_b_open_and_close_tcp6(doc) -> - []; api_b_open_and_close_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_tcp6, @@ -2632,14 +3042,13 @@ api_b_open_and_close_tcp6(_Config) when is_list(_Config) -> %% Basically open (create) and close an Unix Domain dgram (UDP) socket. %% With some extra checks... -api_b_open_and_close_udpL(suite) -> - []; -api_b_open_and_close_udpL(doc) -> - []; api_b_open_and_close_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> InitState = #{domain => local, type => dgram, @@ -2652,10 +3061,6 @@ api_b_open_and_close_udpL(_Config) when is_list(_Config) -> %% Basically open (create) and close an Unix Domain stream (TCP) socket. %% With some extra checks... -api_b_open_and_close_tcpL(suite) -> - []; -api_b_open_and_close_tcpL(doc) -> - []; api_b_open_and_close_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_tcpL, @@ -2672,14 +3077,13 @@ api_b_open_and_close_tcpL(_Config) when is_list(_Config) -> %% Basically open (create) and close an Unix Domain dgram (UDP) socket. %% With some extra checks... -api_b_open_and_close_seqpL(suite) -> - []; -api_b_open_and_close_seqpL(doc) -> - []; api_b_open_and_close_seqpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> InitState = #{domain => local, type => seqpacket, @@ -2692,10 +3096,6 @@ api_b_open_and_close_seqpL(_Config) when is_list(_Config) -> %% Basically open (create) and close an IPv4 SCTP (seqpacket) socket. %% With some extra checks... -api_b_open_and_close_sctp4(suite) -> - []; -api_b_open_and_close_sctp4(doc) -> - []; api_b_open_and_close_sctp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_close_sctp4, @@ -2783,7 +3183,7 @@ api_b_open_and_close(InitState) -> protocol := ExpProtocol}, {ok, Protocol}}) -> %% On OpenBSD (at least 6.6) something screwy happens %% when domain = local. - %% It will report a completly different protocol (icmp) + %% It will report a completely different protocol (icmp) %% but everything still works. So we skip if this happens %% on OpenBSD... case os:type() of @@ -2847,10 +3247,6 @@ api_b_open_and_close(InitState) -> %% Basically open (create) and (maybe) close an RAW socket. -api_b_open_and_maybe_close_raw(suite) -> - []; -api_b_open_and_maybe_close_raw(doc) -> - []; api_b_open_and_maybe_close_raw(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_open_and_maybe_close_raw, @@ -2913,13 +3309,10 @@ do_api_b_open_and_maybe_close_raw(InitState) -> %% Basically send and receive on an IPv4 UDP (dgram) socket using %% sendto and recvfrom.. -api_b_sendto_and_recvfrom_udp4(suite) -> - []; -api_b_sendto_and_recvfrom_udp4(doc) -> - []; api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_sendto_and_recvfrom_udp4, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data, Dest) -> socket:sendto(Sock, Data, Dest) @@ -2939,15 +3332,12 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> %% Basically send and receive on an IPv4 UDP (dgram) socket using %% sendto and recvfrom. -api_b_sendto_and_recvfrom_udpL(suite) -> - []; -api_b_sendto_and_recvfrom_udpL(doc) -> - []; api_b_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_sendto_and_recvfrom_udpL, fun() -> has_support_unix_domain_socket(), + is_not_windows(), unix_domain_socket_host_cond() end, fun() -> @@ -2969,13 +3359,10 @@ api_b_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) -> %% Basically send and receive on an IPv4 UDP (dgram) socket %% using sendmsg and recvmsg. -api_b_sendmsg_and_recvmsg_udp4(suite) -> - []; -api_b_sendmsg_and_recvmsg_udp4(doc) -> - []; api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_sendmsg_and_recvmsg_udp4, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data, Dest) -> %% We need tests for this, @@ -3013,15 +3400,12 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> %% Basically send and receive on an IPv4 UDP (dgram) socket %% using sendmsg and recvmsg. -api_b_sendmsg_and_recvmsg_udpL(suite) -> - []; -api_b_sendmsg_and_recvmsg_udpL(doc) -> - []; api_b_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_sendmsg_and_recvmsg_udpL, fun() -> has_support_unix_domain_socket(), + is_not_windows(), unix_domain_socket_host_cond() end, fun() -> @@ -3201,13 +3585,10 @@ api_b_send_and_recv_udp(InitState) -> %% Basically send and receive using the "common" functions (send and recv) %% on an IPv4 TCP (stream) socket. -api_b_send_and_recv_tcp4(suite) -> - []; -api_b_send_and_recv_tcp4(doc) -> - []; api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_b_send_and_recv_tcp4, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data) -> socket:send(Sock, Data) @@ -3228,10 +3609,6 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> %% Basically send and receive using the "common" functions (send and recv) %% on an Unix Domain (stream) socket (TCP). -api_b_send_and_recv_tcpL(suite) -> - []; -api_b_send_and_recv_tcpL(doc) -> - []; api_b_send_and_recv_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_b_send_and_recv_tcpL, @@ -3256,14 +3633,13 @@ api_b_send_and_recv_tcpL(_Config) when is_list(_Config) -> %% Basically send and receive using the "common" functions (send and recv) %% on an Unix Domain seqpacket socket. -api_b_send_and_recv_seqpL(suite) -> - []; -api_b_send_and_recv_seqpL(doc) -> - []; api_b_send_and_recv_seqpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(?FUNCTION_NAME, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> Send = fun(Sock, Data) -> socket:send(Sock, Data) @@ -3284,13 +3660,13 @@ api_b_send_and_recv_seqpL(_Config) when is_list(_Config) -> %% Basically send and receive using the msg functions (sendmsg and recvmsg) %% on an IPv4 TCP (stream) socket. -api_b_sendmsg_and_recvmsg_tcp4(suite) -> - []; -api_b_sendmsg_and_recvmsg_tcp4(doc) -> - []; api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_b_sendmsg_and_recvmsg_tcp4, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> Send = fun(Sock, Data) -> Msg = #{iov => [Data]}, @@ -3321,14 +3697,13 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> %% Basically send and receive using the msg functions (sendmsg and recvmsg) %% on an Unix Domain (stream) socket (TCP). -api_b_sendmsg_and_recvmsg_tcpL(suite) -> - []; -api_b_sendmsg_and_recvmsg_tcpL(doc) -> - []; api_b_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_b_sendmsg_and_recvmsg_tcpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> Send = fun(Sock, Data) -> Msg = #{iov => [Data]}, @@ -3374,14 +3749,13 @@ api_b_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) -> %% Basically send and receive using the msg functions (sendmsg and recvmsg) %% on an Unix Domain (stream) socket (TCP). -api_b_sendmsg_and_recvmsg_seqpL(suite) -> - []; -api_b_sendmsg_and_recvmsg_seqpL(doc) -> - []; api_b_sendmsg_and_recvmsg_seqpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(?FUNCTION_NAME, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> Send = fun(Sock, Data) -> @@ -3428,6 +3802,7 @@ api_b_sendmsg_and_recvmsg_seqpL(_Config) when is_list(_Config) -> api_b_send_and_recv_conn(InitState) -> process_flag(trap_exit, true), + ServerSeq = [ %% *** Wait for start order *** @@ -3446,6 +3821,7 @@ api_b_send_and_recv_conn(InitState) -> #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> LSA = which_local_socket_addr(Domain), + ?SEV_IPRINT("LSA: ~p", [LSA]), {ok, State#{lsa => LSA}} end}, #{desc => "create listen socket", @@ -3465,11 +3841,18 @@ api_b_send_and_recv_conn(InitState) -> cmd => fun(#{domain := local, lsock := LSock, lsa := LSA} = _State) -> + ?SEV_IPRINT("try bind to: " + "~n ~p", [LSA]), + %% _ = socket:setopt(LSock, otp, debug, true), case socket:bind(LSock, LSA) of ok -> %% We do not care about the port for local + %% _ = socket:setopt(LSock, otp, debug, false), ok; - {error, _} = ERROR -> + {error, Reason} = ERROR -> + %% _ = socket:setopt(LSock, otp, debug, false), + ?SEV_EPRINT("failed binding: " + "~n ~p", [Reason]), ERROR end; (#{lsock := LSock, lsa := LSA} = State) -> @@ -3504,11 +3887,17 @@ api_b_send_and_recv_conn(InitState) -> end}, #{desc => "await connection", cmd => fun(#{lsock := LSock} = State) -> + %% _ = socket:setopt(LSock, otp, debug, true), + ?SEV_IPRINT("try accept"), case socket:accept(LSock) of {ok, Sock} -> + %% _ = socket:setopt(LSock, otp, debug, false), ?SEV_IPRINT("accepted: ~n ~p", [Sock]), {ok, State#{csock => Sock}}; - {error, _} = ERROR -> + {error, Reason} = ERROR -> + %% _ = socket:setopt(LSock, otp, debug, false), + ?SEV_EPRINT("accept failed: " + "~n ~p", [Reason]), ERROR end end}, @@ -3842,10 +4231,6 @@ api_b_send_and_recv_conn(InitState) -> %% Basically send and receive on an IPv4 SCTP (seqpacket) socket %% using sendmsg and recvmsg. -api_b_sendmsg_and_recvmsg_sctp4(suite) -> - []; -api_b_sendmsg_and_recvmsg_sctp4(doc) -> - []; api_b_sendmsg_and_recvmsg_sctp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_b_sendmsg_and_recvmsg_sctp4, @@ -4384,6 +4769,7 @@ api_b_send_and_recv_sctp(_InitState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% api_b_sendmsg_iov_dgram_inet(Config) when is_list(Config) -> + has_support_ipv4(), api_b_sendmsg_iov_dgram(inet). %% api_b_sendmsg_iov_dgram_inet6(Config) when is_list(Config) -> @@ -4392,54 +4778,77 @@ api_b_sendmsg_iov_dgram_inet6(Config) when is_list(Config) -> %% api_b_sendmsg_iov_dgram_local(Config) when is_list(Config) -> has_support_unix_domain_socket(), + is_not_windows(), % on Windows, local only works for stream sockets api_b_sendmsg_iov_dgram(local). api_b_sendmsg_iov_stream_inet(Config) when is_list(Config) -> + has_support_ipv4(), + is_not_windows(), % sendmsg does not work on Windows api_b_sendmsg_iov_stream(inet). %% api_b_sendmsg_iov_stream_inet6(Config) when is_list(Config) -> has_support_ipv6(), + is_not_windows(), % sendmsg does not work on Windows api_b_sendmsg_iov_stream(inet6). %% api_b_sendmsg_iov_stream_local(Config) when is_list(Config) -> has_support_unix_domain_socket(), + is_not_windows(), % sendmsg does not work on Windows api_b_sendmsg_iov_stream(local). api_b_sendmsg_iov_dgram(Domain) -> + ?P("api_b_sendmsg_iov_dgram -> entry with" + "~n Domain: ~p", [Domain]), ?TT(?SECS(5)), #{iov_max := IOVMax} = socket:info(), + ?P("api_b_sendmsg_iov_dgram -> IOVMax: ~p", [IOVMax]), IOV = lists:map( fun (N) -> <<(rand:uniform(N) - 1)>> end, lists:duplicate(IOVMax, 256)), IOVTooLarge = IOV ++ IOV, Data = erlang:iolist_to_binary(IOV), - {ok, Sa} = socket:open(Domain, dgram), + ?P("api_b_sendmsg_iov_dgram -> a: create socket"), + {ok, Sa} = socket:open(Domain, dgram, #{debug => true}), try + ?P("api_b_sendmsg_iov_dgram -> b: create socket"), {ok, Sb} = socket:open(Domain, dgram), try + ?P("api_b_sendmsg_iov_dgram -> a: bind socket"), ok = socket:bind(Sa, which_local_socket_addr(Domain)), + ?P("api_b_sendmsg_iov_dgram -> b: bind socket"), ok = socket:bind(Sb, which_local_socket_addr(Domain)), + ?P("api_b_sendmsg_iov_dgram -> a: get sockname"), {ok, Aa} = socket:sockname(Sa), + ?P("api_b_sendmsg_iov_dgram -> b: get sockname"), {ok, Ab} = socket:sockname(Sb), %% + ?P("api_b_sendmsg_iov_dgram -> a: sendmsg"), ok = socket:sendmsg(Sa, #{addr => Ab, iov => IOV}), + ?P("api_b_sendmsg_iov_dgram -> b: recvfrom"), {ok, {Aa, Data}} = socket:recvfrom(Sb), %% + ?P("api_b_sendmsg_iov_dgram -> b: sendmsg (too large => fail)"), {error, {invalid, _}} = socket:sendmsg(Sb, #{addr => Aa, iov => IOVTooLarge}), + ?P("api_b_sendmsg_iov_dgram -> done"), ok after + ?P("api_b_sendmsg_iov_dgram -> b: close socket"), socket:close(Sb) end after + ?P("api_b_sendmsg_iov_dgram -> a: close socket"), socket:close(Sa) end. api_b_sendmsg_iov_stream(Domain) -> + ?P("api_b_sendmsg_iov_stream -> entry with" + "~n Domain: ~p", [Domain]), ?TT(?SECS(5)), #{iov_max := IOVMax} = socket:info(), + ?P("api_b_sendmsg_iov_stream -> IOVMax: ~p", [IOVMax]), IOV = lists:map( fun (N) -> <<(rand:uniform(N) - 1)>> end, @@ -4447,38 +4856,68 @@ api_b_sendmsg_iov_stream(Domain) -> IOVTooLarge = IOV ++ IOV, Data = erlang:iolist_to_binary(IOV), DataTooLarge = erlang:iolist_to_binary(IOVTooLarge), + ?P("api_b_sendmsg_iov_stream -> create stream socket a"), {ok, Sa} = socket:open(Domain, stream), try + case os:type() of + {win32,nt} -> + ?P("api_b_sendmsg_iov_stream-> [win] a: bind socket"), + ok = socket:bind(Sa, which_local_socket_addr(Domain)); + _ -> + ok + end, + ?P("api_b_sendmsg_iov_stream -> create stream socket b"), {ok, Sb} = socket:open(Domain, stream), try + ?P("api_b_sendmsg_iov_stream -> b: bind socket"), ok = socket:bind(Sb, which_local_socket_addr(Domain)), + ?P("api_b_sendmsg_iov_stream -> b: get sockname"), {ok, Ab} = socket:sockname(Sb), + ?P("api_b_sendmsg_iov_stream -> b: make socket listen"), ok = socket:listen(Sb), + ?P("api_b_sendmsg_iov_stream -> a: connect socket to b"), ok = socket:connect(Sa, Ab), + ?P("api_b_sendmsg_iov_stream -> a: get sockname"), {ok, Aa} = socket:sockname(Sa), + ?P("api_b_sendmsg_iov_stream -> a: get peername"), {ok, Ab} = socket:peername(Sa), + ?P("api_b_sendmsg_iov_stream -> accept connection (=> c)"), {ok, Sc} = socket:accept(Sb), try + ?P("api_b_sendmsg_iov_stream -> c: get sockname"), {ok, Ab} = socket:sockname(Sc), + ?P("api_b_sendmsg_iov_stream -> c: get peername"), {ok, Aa} = socket:peername(Sc), %% + ?P("api_b_sendmsg_iov_stream -> a: sendmsg"), ok = socket:sendmsg(Sa, #{iov => IOV}), + ?P("api_b_sendmsg_iov_stream -> c: recv"), {ok, Data} = socket:recv(Sc, byte_size(Data)), + ?P("api_b_sendmsg_iov_stream -> c: sendmsg (too large)"), ok = socket:sendmsg(Sc, #{iov => IOVTooLarge}), + ?P("api_b_sendmsg_iov_stream -> a: recv"), {ok, DataTooLarge} = socket:recv(Sa, byte_size(DataTooLarge)), + ?P("api_b_sendmsg_iov_stream -> done"), ok + catch + error:notsup = Reason:_ -> + ?P("api_b_sendmsg_iov_stream -> notsup"), + exit({skip, Reason}) after socket:close(Sc) end after + ?P("api_b_sendmsg_iov_stream -> after - b: close socket"), socket:close(Sb) end after + ?P("api_b_sendmsg_iov_stream -> after - a: close socket"), socket:close(Sa) end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% @@ -4489,6 +4928,7 @@ api_b_sendmsg_iov_stream(Domain) -> api_sendfile_inet(Config) when is_list(Config) -> has_support_sendfile(), + has_support_ipv4(), api_sendfile(inet, Config, fun socket:sendfile/2). api_sendfile_inet6(Config) when is_list(Config) -> @@ -4505,6 +4945,7 @@ api_sendfile_local(Config) when is_list(Config) -> api_sendfile_loop_inet(Config) when is_list(Config) -> has_support_sendfile(), + has_support_ipv4(), api_sendfile(inet, Config, fun sendfile_loop/2). api_sendfile_loop_inet6(Config) when is_list(Config) -> @@ -4650,13 +5091,10 @@ api_sendfile_verify_block(S, Data, M, Block, N) -> %% With some extra checks... %% IPv4 %% Without dup -api_ffd_open_wod_and_info_udp4(suite) -> - []; -api_ffd_open_wod_and_info_udp4(doc) -> - []; api_ffd_open_wod_and_info_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wod_and_info_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => dgram, @@ -4673,10 +5111,6 @@ api_ffd_open_wod_and_info_udp4(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% Without dup -api_ffd_open_wod_and_info_udp6(suite) -> - []; -api_ffd_open_wod_and_info_udp6(doc) -> - []; api_ffd_open_wod_and_info_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wod_and_info_udp6, @@ -4697,13 +5131,10 @@ api_ffd_open_wod_and_info_udp6(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv4 %% With dup -api_ffd_open_wd_and_info_udp4(suite) -> - []; -api_ffd_open_wd_and_info_udp4(doc) -> - []; api_ffd_open_wd_and_info_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_wd_open_and_info_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => dgram, @@ -4720,10 +5151,6 @@ api_ffd_open_wd_and_info_udp4(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% With dup -api_ffd_open_wd_and_info_udp6(suite) -> - []; -api_ffd_open_wd_and_info_udp6(doc) -> - []; api_ffd_open_wd_and_info_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_wd_open_and_info_udp6, @@ -4744,13 +5171,10 @@ api_ffd_open_wd_and_info_udp6(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% Without dup -api_ffd_open_wod_and_info_tcp4(suite) -> - []; -api_ffd_open_wod_and_info_tcp4(doc) -> - []; api_ffd_open_wod_and_info_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wod_and_info_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => stream, @@ -4767,10 +5191,6 @@ api_ffd_open_wod_and_info_tcp4(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% Without dup -api_ffd_open_wod_and_info_tcp6(suite) -> - []; -api_ffd_open_wod_and_info_tcp6(doc) -> - []; api_ffd_open_wod_and_info_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wod_and_info_tcp6, @@ -4791,13 +5211,10 @@ api_ffd_open_wod_and_info_tcp6(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% With dup -api_ffd_open_wd_and_info_tcp4(suite) -> - []; -api_ffd_open_wd_and_info_tcp4(doc) -> - []; api_ffd_open_wd_and_info_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wd_and_info_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => stream, @@ -4814,10 +5231,6 @@ api_ffd_open_wd_and_info_tcp4(_Config) when is_list(_Config) -> %% With some extra checks... %% IPv6 %% With dup -api_ffd_open_wd_and_info_tcp6(suite) -> - []; -api_ffd_open_wd_and_info_tcp6(doc) -> - []; api_ffd_open_wd_and_info_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_wd_and_info_tcp6, @@ -5025,7 +5438,7 @@ api_ffd_open_and_info(InitState) -> %% Basically open a socket (1) and then create another socket (2) from %% its file descriptor *without* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv4 UDP (dgram) socket. @@ -5039,13 +5452,10 @@ api_ffd_open_and_info(InitState) -> %% %% %% -api_ffd_open_and_open_wod_and_send_udp4(suite) -> - []; -api_ffd_open_and_open_wod_and_send_udp4(doc) -> - []; api_ffd_open_and_open_wod_and_send_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_and_open_wod_and_send_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => dgram, @@ -5060,7 +5470,7 @@ api_ffd_open_and_open_wod_and_send_udp4(_Config) when is_list(_Config) -> %% Basically open a socket (1) and then create another socket (2) from %% its file descriptor *without* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv6 UDP (dgram) socket. @@ -5074,10 +5484,6 @@ api_ffd_open_and_open_wod_and_send_udp4(_Config) when is_list(_Config) -> %% %% %% -api_ffd_open_and_open_wod_and_send_udp6(suite) -> - []; -api_ffd_open_and_open_wod_and_send_udp6(doc) -> - []; api_ffd_open_and_open_wod_and_send_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_and_open_wod_and_send_udp6, @@ -5096,18 +5502,15 @@ api_ffd_open_and_open_wod_and_send_udp6(_Config) when is_list(_Config) -> %% Basically open a socket (1) and then create another socket (2) from %% its file descriptor *with* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv4 UDP (dgram) socket. %% -api_ffd_open_and_open_wd_and_send_udp4(suite) -> - []; -api_ffd_open_and_open_wd_and_send_udp4(doc) -> - []; api_ffd_open_and_open_wd_and_send_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_and_open_wd_and_send_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => dgram, @@ -5122,15 +5525,11 @@ api_ffd_open_and_open_wd_and_send_udp4(_Config) when is_list(_Config) -> %% Basically open a socket (1) and then create another socket (2) from %% its file descriptor *with* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv6 UDP (dgram) socket. %% -api_ffd_open_and_open_wd_and_send_udp6(suite) -> - []; -api_ffd_open_and_open_wd_and_send_udp6(doc) -> - []; api_ffd_open_and_open_wd_and_send_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_and_open_wd_and_send_udp6, @@ -5748,7 +6147,7 @@ api_ffd_open_and_open_and_send_udp2(InitState) -> %% Basically open a socket (1), connect to a server and then create %% another socket (2) from its file descriptor *without* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv4 TCP (stream) socket. @@ -5762,10 +6161,6 @@ api_ffd_open_and_open_and_send_udp2(InitState) -> %% %% %% -api_ffd_open_connect_and_open_wod_and_send_tcp4(suite) -> - []; -api_ffd_open_connect_and_open_wod_and_send_tcp4(doc) -> - []; api_ffd_open_connect_and_open_wod_and_send_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_connect_and_open_wod_and_send_tcp4, @@ -5783,7 +6178,7 @@ api_ffd_open_connect_and_open_wod_and_send_tcp4(_Config) when is_list(_Config) - %% Basically open a socket (1), connect to a server and then create %% another socket (2) from its file descriptor *without* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv6 TCP (stream) socket. @@ -5797,10 +6192,6 @@ api_ffd_open_connect_and_open_wod_and_send_tcp4(_Config) when is_list(_Config) - %% %% %% -api_ffd_open_connect_and_open_wod_and_send_tcp6(suite) -> - []; -api_ffd_open_connect_and_open_wod_and_send_tcp6(doc) -> - []; api_ffd_open_connect_and_open_wod_and_send_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_connect_and_open_wod_and_send_tcp6, @@ -5819,14 +6210,10 @@ api_ffd_open_connect_and_open_wod_and_send_tcp6(_Config) when is_list(_Config) - %% Basically open a socket (1), connect to a server and then create %% another socket (2) from its file descriptor *with* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv4 TCP (stream) socket. -api_ffd_open_connect_and_open_wd_and_send_tcp4(suite) -> - []; -api_ffd_open_connect_and_open_wd_and_send_tcp4(doc) -> - []; api_ffd_open_connect_and_open_wd_and_send_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_connect_and_open_wd_and_send_tcp4, @@ -5845,14 +6232,10 @@ api_ffd_open_connect_and_open_wd_and_send_tcp4(_Config) when is_list(_Config) -> %% Basically open a socket (1), connect to a server and then create %% another socket (2) from its file descriptor *with* dup. -%% Exchange som data from via both "client" sockets. +%% Exchange some data from via both "client" sockets. %% Finally close the second socket. Ensure that the original socket %% has not been closed (test by sending some data). %% IPv6 TCP (stream) socket. -api_ffd_open_connect_and_open_wd_and_send_tcp6(suite) -> - []; -api_ffd_open_connect_and_open_wd_and_send_tcp6(doc) -> - []; api_ffd_open_connect_and_open_wd_and_send_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_ffd_open_connect_and_open_wd_and_send_tcp6, @@ -6524,14 +6907,10 @@ api_ffd_open_connect_and_open_and_send_tcp2(InitState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically establish a TCP connection via an async connect. IPv4. - -api_a_connect_tcp4(suite) -> - []; -api_a_connect_tcp4(doc) -> - []; api_a_connect_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), tc_try(api_a_connect_tcp4, + fun() -> has_support_ipv4() end, fun() -> ok = api_a_connect_tcpD(inet, nowait(Config)) end). @@ -6540,11 +6919,6 @@ api_a_connect_tcp4(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically establish a TCP connection via an async connect. IPv6. - -api_a_connect_tcp6(suite) -> - []; -api_a_connect_tcp6(doc) -> - []; api_a_connect_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), tc_try(api_a_connect_tcp6, @@ -6570,7 +6944,7 @@ api_a_connect_tcpD(Domain, Nowait) -> connect => Connect, send => Send, recv => Recv, - connect_sref => Nowait}, + connect_ref => Nowait}, api_a_connect_tcp(InitState). @@ -6761,41 +7135,67 @@ api_a_connect_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, async_connect) end}, #{desc => "connect (async) to server", - cmd => fun(#{sock := Sock, - server_sa := SSA, - connect := Connect, - connect_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + server_sa := SSA, + connect := Connect, + connect_ref := SR} = State) -> case Connect(Sock, SSA) of ok -> ?SEV_IPRINT("ok -> " "unexpected success => SKIP", []), {skip, unexpected_success}; + {select, {select_info, ST, SelectRef}} when SR =:= nowait -> ?SEV_IPRINT("select nowait ->" "~n tag: ~p" "~n ref: ~p", [ST, SelectRef]), - {ok, State#{connect_stag => ST, - connect_sref => SelectRef}}; + {ok, State#{asynch_tag => select, + connect_tag => ST, + connect_ref => SelectRef}}; {select, {select_info, ST, SR}} when is_reference(SR) -> ?SEV_IPRINT("select ref ->" "~n tag: ~p" "~n ref: ~p", [ST, SR]), - {ok, State#{connect_stag => ST}}; + {ok, State#{asynch_tag => select, + connect_tag => ST}}; + + {completion, + {completion_info, CT, CompletionRef}} + when SR =:= nowait -> + ?SEV_IPRINT("completion nowait ->" + "~n tag: ~p" + "~n ref: ~p", + [CT, CompletionRef]), + {ok, State#{asynch_tag => completion, + connect_tag => CT, + connect_ref => CompletionRef}}; + {completion, + {completion_info, CT, CR}} + when is_reference(CR) -> + ?SEV_IPRINT("completion ref ->" + "~n tag: ~p" + "~n ref: ~p", [CT, CR]), + {ok, State#{asynch_tag => completion, + connect_tag => CT}}; + {error, _} = ERROR -> ERROR end end}, - #{desc => "announce ready (connect select)", + #{desc => "announce ready (connect select|completion)", cmd => fun(#{tester := Tester}) -> ?SEV_ANNOUNCE_READY(Tester, connect_select), ok end}, - #{desc => "await select message", - cmd => fun(#{sock := Sock, connect_sref := Ref}) -> + #{desc => "await select|completion message", + cmd => fun(#{sock := Sock, + asynch_tag := select, + connect_tag := connect, + connect_ref := Ref}) -> receive {'$socket', Sock, select, Ref} -> ?SEV_IPRINT("select message ->" @@ -6806,15 +7206,35 @@ api_a_connect_tcp(InitState) -> "~n message queue: ~p", [mq()]), {error, timeout} + end; + (#{sock := Sock, + asynch_tag := completion, + connect_tag := connect, + connect_ref := Ref}) -> + receive + {'$socket', Sock, completion, {Ref, ok = Res}} -> + ?SEV_IPRINT("completion message ->" + "~n ref: ~p" + "~n res: ~p", [Ref, Res]), + ok + after 5000 -> + ?SEV_EPRINT("timeout: " + "~n message queue: ~p", + [mq()]), + {error, timeout} end end}, - #{desc => "announce ready (select)", + #{desc => "announce ready (select|completion)", cmd => fun(#{tester := Tester}) -> ?SEV_ANNOUNCE_READY(Tester, select), ok end}, - #{desc => "connect (async) to server", - cmd => fun(#{sock := Sock, server_sa := SSA, connect := Connect}) -> + #{desc => "(maybe) connect (async) to server", + cmd => fun(#{sock := Sock, + server_sa := SSA, + asynch_tag := select, + connect_tag := connect, + connect := Connect}) -> case Connect(Sock, SSA) of ok -> ok; @@ -6822,7 +7242,13 @@ api_a_connect_tcp(InitState) -> {error, {unexpected_select, SelectInfo}}; {error, _} = ERROR -> ERROR - end + end; + (#{sock := _Sock, + server_sa := _SSA, + asynch_tag := completion, + connect_tag := connect, + connect := _Connect}) -> + ok end}, #{desc => "announce ready (connect)", cmd => fun(#{tester := Tester}) -> @@ -7061,14 +7487,11 @@ api_a_connect_tcp(InitState) -> %% select message). Note that we only do this for the recvfrom, %% since its much more difficult to "arrange" for sendto. %% -api_a_sendto_and_recvfrom_udp4(suite) -> - []; -api_a_sendto_and_recvfrom_udp4(doc) -> - []; api_a_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> ?TT(?SECS(5)), Nowait = nowait(Config), - tc_try(api_a_sendto_and_recvfrom_udp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data, Dest) -> socket:sendto(Sock, Data, Dest) @@ -7076,10 +7499,10 @@ api_a_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> Recv = fun(Sock) -> socket:recvfrom(Sock, 0, Nowait) end, - InitState = #{domain => inet, - send => Send, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + send => Send, + recv => Recv, + recv_ref => Nowait}, ok = api_a_send_and_recv_udp(InitState) end). @@ -7093,14 +7516,10 @@ api_a_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> %% select message). Note that we only do this for the recvfrom, %% since its much more difficult to "arrange" for sendto. %% -api_a_sendto_and_recvfrom_udp6(suite) -> - []; -api_a_sendto_and_recvfrom_udp6(doc) -> - []; api_a_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> ?TT(?SECS(5)), Nowait = nowait(Config), - tc_try(api_a_sendto_and_recvfrom_udp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Send = fun(Sock, Data, Dest) -> @@ -7109,10 +7528,10 @@ api_a_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> Recv = fun(Sock) -> socket:recvfrom(Sock, 0, Nowait) end, - InitState = #{domain => inet6, - send => Send, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + send => Send, + recv => Recv, + recv_ref => Nowait}, ok = api_a_send_and_recv_udp(InitState) end). @@ -7126,14 +7545,11 @@ api_a_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> %% select message). Note that we only do this for the recvmsg, %% since its much more difficult to "arrange" for sendmsg. %% -api_a_sendmsg_and_recvmsg_udp4(suite) -> - []; -api_a_sendmsg_and_recvmsg_udp4(doc) -> - []; api_a_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> ?TT(?SECS(5)), Nowait = nowait(Config), tc_try(api_a_sendmsg_and_recvmsg_udp4, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data, Dest) -> Msg = #{addr => Dest, @@ -7150,14 +7566,16 @@ api_a_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - send => Send, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + send => Send, + recv => Recv, + recv_ref => Nowait}, ok = api_a_send_and_recv_udp(InitState) end). @@ -7171,10 +7589,6 @@ api_a_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> %% select message). Note that we only do this for the recvmsg, %% since its much more difficult to "arrange" for sendmsg. %% -api_a_sendmsg_and_recvmsg_udp6(suite) -> - []; -api_a_sendmsg_and_recvmsg_udp6(doc) -> - []; api_a_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) -> ?TT(?SECS(5)), Nowait = nowait(Config), @@ -7196,14 +7610,16 @@ api_a_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - send => Send, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + send => Send, + recv => Recv, + recv_ref => Nowait}, ok = api_a_send_and_recv_udp(InitState) end). @@ -7264,25 +7680,45 @@ api_a_send_and_recv_udp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of {select, {select_info, Tag, RecvRef}} - when SR =:= nowait -> + when Ref =:= nowait -> ?SEV_IPRINT("expected select nowait: " "~n Tag: ~p" "~n Ref: ~p", [Tag, RecvRef]), - {ok, State#{recv_stag => Tag, - recv_sref => RecvRef}}; - {select, {select_info, Tag, SR}} - when is_reference(SR) -> + {ok, State#{async_tag => select, + recv_tag => Tag, + recv_ref => RecvRef}}; + {select, {select_info, Tag, Ref}} + when is_reference(Ref) -> ?SEV_IPRINT("expected select ref: " "~n Tag: ~p" - "~n Ref: ~p", [Tag, SR]), - {ok, State#{recv_stag => Tag}}; + "~n Ref: ~p", [Tag, Ref]), + {ok, State#{async_tag => select, + recv_tag => Tag}}; + + {completion, {completion_info, Tag, RecvRef}} + when Ref =:= nowait -> + ?SEV_IPRINT("expected select nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, RecvRef]), + {ok, State#{async_tag => completion, + recv_tag => Tag, + recv_ref => RecvRef}}; + {completion, {completion_info, Tag, Ref}} + when is_reference(Ref) -> + ?SEV_IPRINT("expected completion ref: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, Ref]), + {ok, State#{async_tag => completion, + recv_tag => Tag}}; + {ok, X} -> - {error, {unexpected_succes, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -7292,29 +7728,74 @@ api_a_send_and_recv_udp(InitState) -> ?SEV_ANNOUNCE_READY(Tester, recv_select), ok end}, - #{desc => "await select message", - cmd => fun(#{sock := Sock, recv_sref := RecvRef}) -> + #{desc => "await select|completion message", + cmd => fun(#{async_tag := select, + sock := Sock, + recv_ref := RecvRef}) -> receive {'$socket', Sock, select, RecvRef} -> ok after 5000 -> - ?SEV_EPRINT("message queue: ~p", [mq()]), + ?SEV_EPRINT("timeout when: " + "~n Socket Info: ~p" + "~n Message Queue: ~p", + [socket:info(Sock), mq()]), + {error, timeout} + end; + (#{async_tag := completion, + sock := Sock, + recv_ref := RecvRef} = State) -> + receive + %% Recvfrom + {'$socket', Sock, completion, + {RecvRef, {ok, {Src, ?BASIC_REQ}}}} -> + {ok, State#{req_src => Src}}; + %% Recvmsg + {'$socket', Sock, completion, + {RecvRef, {ok, #{addr := Src, + iov := [?BASIC_REQ]}}}} -> + {ok, State#{req_src => Src}}; + {'$socket', Sock, completion, + {RecvRef, {ok, Unexpected}}} -> + ?SEV_EPRINT("Unexpected success result: " + "~n ~p", [Unexpected]), + {error, {unexpected_success_result, + Unexpected}}; + {'$socket', Sock, completion, + {RecvRef, {error, Reason} = ERROR}} -> + ?SEV_EPRINT("completion with error: " + "~n ~p", [Reason]), + ERROR + after 5000 -> + ?SEV_EPRINT("timeout when: " + "~n Socket Info: ~p" + "~n Message Queue: ~p", + [socket:info(Sock), mq()]), {error, timeout} end end}, #{desc => "announce ready (select)", cmd => fun(#{tester := Tester}) -> + %% We are actually done *if* this was + %% a completion event, but to make the + %% test case simple... ?SEV_ANNOUNCE_READY(Tester, select), ok end}, - #{desc => "now read the data (request)", - cmd => fun(#{sock := Sock, recv := Recv} = State) -> + #{desc => "now read the data (request), for select", + cmd => fun(#{async_tag := select, + sock := Sock, + recv := Recv} = State) -> case Recv(Sock) of {ok, {Src, ?BASIC_REQ}} -> {ok, State#{req_src => Src}}; {error, _} = ERROR -> ERROR - end + end; + (#{async_tag := completion} = _State) -> + %% We are already done! + ?SEV_IPRINT("Already done!"), + ok end}, #{desc => "announce ready (recv request)", cmd => fun(#{tester := Tester}) -> @@ -7342,10 +7823,11 @@ api_a_send_and_recv_udp(InitState) -> case ?SEV_AWAIT_TERMINATE(Tester, tester) of ok -> State2 = maps:remove(tester, State), - State3 = maps:remove(recv_stag, State2), - State4 = maps:remove(recv_sref, State3), - State5 = maps:remove(req_src, State4), - {ok, State5}; + State3 = maps:remove(async_tag, State2), + State4 = maps:remove(recv_tag, State3), + State5 = maps:remove(recv_ref, State4), + State6 = maps:remove(req_src, State5), + {ok, State6}; {error, _} = ERROR -> ERROR end @@ -7385,8 +7867,7 @@ api_a_send_and_recv_udp(InitState) -> #{desc => "open socket", cmd => fun(#{domain := Domain} = State) -> Sock = sock_open(Domain, dgram, udp), - SA = sock_sockname(Sock), - {ok, State#{sock => Sock, sa => SA}} + {ok, State#{sock => Sock}} end}, #{desc => "bind socket (to local address)", cmd => fun(#{sock := Sock, lsa := LSA}) -> @@ -7397,6 +7878,11 @@ api_a_send_and_recv_udp(InitState) -> ERROR end end}, + #{desc => "sockname", + cmd => fun(#{sock := Sock} = State) -> + SA = sock_sockname(Sock), + {ok, State#{sa => SA}} + end}, #{desc => "announce ready (init)", cmd => fun(#{tester := Tester}) -> ?SEV_ANNOUNCE_READY(Tester, init), @@ -7422,17 +7908,28 @@ api_a_send_and_recv_udp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, #{desc => "try recv reply (with nowait)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of {select, {select_info, Tag, RecvRef}} - when SR =:= nowait -> - {ok, State#{recv_stag => Tag, - recv_sref => RecvRef}}; - {select, {select_info, Tag, SR}} - when is_reference(SR) -> - {ok, State#{recv_stag => Tag}}; + when Ref =:= nowait -> + {ok, State#{async_tag => select, + recv_tag => Tag, + recv_ref => RecvRef}}; + {select, {select_info, Tag, Ref}} + when is_reference(Ref) -> + {ok, State#{async_tag => select, + recv_tag => Tag}}; + {completion, {completion_info, Tag, RecvRef}} + when Ref =:= nowait -> + {ok, State#{async_tag => completion, + recv_tag => Tag, + recv_ref => RecvRef}}; + {completion, {completion_info, Tag, Ref}} + when is_reference(Ref) -> + {ok, State#{async_tag => completion, + recv_tag => Tag}}; {ok, X} -> {error, {unexpected_select_info, X}}; {error, _} = ERROR -> @@ -7445,10 +7942,20 @@ api_a_send_and_recv_udp(InitState) -> ok end}, #{desc => "await select message", - cmd => fun(#{sock := Sock, recv_sref := RecvRef}) -> + cmd => fun(#{async_tag := select, + sock := Sock, + recv_ref := RecvRef}) -> receive {'$socket', Sock, select, RecvRef} -> ok + end; + (#{async_tag := completion, + sock := Sock, + recv_ref := RecvRef}) -> + receive + {'$socket', Sock, completion, + {RecvRef, {ok, _}}} -> + ok end end}, #{desc => "announce ready (select)", @@ -7457,13 +7964,18 @@ api_a_send_and_recv_udp(InitState) -> ok end}, #{desc => "now read the data (reply)", - cmd => fun(#{sock := Sock, recv := Recv}) -> + cmd => fun(#{async_tag := select, + sock := Sock, + recv := Recv}) -> case Recv(Sock) of {ok, {_Src, ?BASIC_REP}} -> ok; {error, _} = ERROR -> ERROR - end + end; + (#{async_tag := completion}) -> + ?SEV_IPRINT("Already read!"), + ok end}, #{desc => "announce ready (recv reply)", cmd => fun(#{tester := Tester}) -> @@ -7477,9 +7989,10 @@ api_a_send_and_recv_udp(InitState) -> case ?SEV_AWAIT_TERMINATE(Tester, tester) of ok -> State2 = maps:remove(tester, State), - State3 = maps:remove(recv_stag, State2), - State4 = maps:remove(recv_sref, State3), - {ok, State4}; + State3 = maps:remove(async_tag, State2), + State4 = maps:remove(recv_tag, State3), + State5 = maps:remove(recv_ref, State4), + {ok, State5}; {error, _} = ERROR -> ERROR end @@ -7652,14 +8165,11 @@ api_a_send_and_recv_udp(InitState) -> %% select message). Note that we only do this for the recv, %% since its much more difficult to "arrange" for send. %% We *also* test async for accept. -api_a_send_and_recv_tcp4(suite) -> - []; -api_a_send_and_recv_tcp4(doc) -> - []; api_a_send_and_recv_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), tc_try(api_a_send_and_recv_tcp4, + fun() -> has_support_ipv4() end, fun() -> Send = fun(Sock, Data) -> socket:send(Sock, Data) @@ -7684,10 +8194,6 @@ api_a_send_and_recv_tcp4(Config) when is_list(Config) -> %% select message). Note that we only do this for the recv, %% since its much more difficult to "arrange" for send. %% We *also* test async for accept. -api_a_send_and_recv_tcp6(suite) -> - []; -api_a_send_and_recv_tcp6(doc) -> - []; api_a_send_and_recv_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), @@ -7717,14 +8223,14 @@ api_a_send_and_recv_tcp6(Config) when is_list(Config) -> %% select message). Note that we only do this for the recvmsg, %% since its much more difficult to "arrange" for sendmsg. %% We *also* test async for accept. -api_a_sendmsg_and_recvmsg_tcp4(suite) -> - []; -api_a_sendmsg_and_recvmsg_tcp4(doc) -> - []; api_a_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), tc_try(api_a_sendmsg_and_recvmsg_tcp4, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> Send = fun(Sock, Data) -> Msg = #{iov => [Data]}, @@ -7757,10 +8263,6 @@ api_a_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> %% select message). Note that we only do this for the recvmsg, %% since its much more difficult to "arrange" for sendmsg. %% We *also* test async for accept. -api_a_sendmsg_and_recvmsg_tcp6(suite) -> - []; -api_a_sendmsg_and_recvmsg_tcp6(doc) -> - []; api_a_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), @@ -7854,20 +8356,40 @@ api_a_send_and_recv_tcp(Config, InitState) -> case socket:accept(LSock, Nowait) of {select, {select_info, Tag, Ref}} when Nowait =:= nowait -> - ?SEV_IPRINT("accept select nowait: " + ?SEV_IPRINT("select accept message: " "~n Tag: ~p" "~n Ref: ~p", [Tag, Ref]), - {ok, State#{accept_stag => Tag, + {ok, State#{sorc => select, + accept_stag => Tag, accept_sref => Ref}}; {select, {select_info, Tag, Nowait}} when is_reference(Nowait) -> - ?SEV_IPRINT("accept select ref: " + ?SEV_IPRINT("select accept result: " "~n Tag: ~p" "~n Ref: ~p", [Tag, Nowait]), - {ok, State#{accept_stag => Tag, + {ok, State#{sorc => select, + accept_stag => Tag, accept_sref => Nowait}}; + + {completion, {completion_info, Tag, Ref}} + when Nowait =:= nowait -> + ?SEV_IPRINT("completion accept result: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, Ref]), + {ok, State#{sorc => completion, + accept_stag => Tag, + accept_sref => Ref}}; + {completion, {completion_info, Tag, Nowait}} + when is_reference(Nowait) -> + ?SEV_IPRINT("completion accept result: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, Nowait]), + {ok, State#{sorc => completion, + accept_stag => Tag, + accept_sref => Nowait}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; {error, _} = ERROR -> ERROR end @@ -7877,11 +8399,25 @@ api_a_send_and_recv_tcp(Config, InitState) -> ?SEV_ANNOUNCE_READY(Tester, accept_select), ok end}, - #{desc => "await select message", - cmd => fun(#{lsock := Sock, accept_sref := Ref}) -> + #{desc => "await select|completion message", + cmd => fun(#{lsock := Sock, accept_sref := Ref} = State) -> receive {'$socket', Sock, select, Ref} -> - ok + ?SEV_IPRINT("select message: " + "ready for accept"), + ok; + {'$socket', Sock, completion, + {Ref, {ok, CSock}}} -> + ?SEV_IPRINT("completion message: accepted: " + "~n CSock: ~p", [Sock]), + {ok, State#{csock => CSock}} + after 5000 -> + ?SEV_EPRINT("select|completion message timeout:" + "~n Sock: ~p" + "~n Ref: ~p" + "~n Message Queue: ~p", + [Sock, Ref, mq()]), + {error, timeout} end end}, #{desc => "announce ready (select)", @@ -7889,8 +8425,9 @@ api_a_send_and_recv_tcp(Config, InitState) -> ?SEV_ANNOUNCE_READY(Tester, select), ok end}, - #{desc => "await connection (again)", - cmd => fun(#{lsock := LSock} = State) -> + #{desc => "try accept (again)", + cmd => fun(#{lsock := LSock, sorc := select} = State) -> + ?SEV_IPRINT("try accept again"), case socket:accept(LSock, nowait) of {ok, Sock} -> ?SEV_IPRINT("accepted: " @@ -7898,7 +8435,10 @@ api_a_send_and_recv_tcp(Config, InitState) -> {ok, State#{csock => Sock}}; {error, _} = ERROR -> ERROR - end + end; + (#{sorc := completion})-> + ?SEV_IPRINT("already accepted"), + ok end}, #{desc => "announce ready (accept)", cmd => fun(#{tester := Tester}) -> @@ -7911,8 +8451,8 @@ api_a_send_and_recv_tcp(Config, InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv_req) end}, #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{csock := Sock, - recv := Recv, + cmd => fun(#{csock := Sock, + recv := Recv, recv_sref := SR} = State) -> case Recv(Sock) of {select, {select_info, Tag, Ref}} @@ -7928,8 +8468,23 @@ api_a_send_and_recv_tcp(Config, InitState) -> "~n Tag: ~p" "~n Ref: ~p", [Tag, SR]), {ok, State#{recv_stag => Tag}}; + + {completion, {completion_info, Tag, Ref}} + when SR =:= nowait -> + ?SEV_IPRINT("recv completion nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, Ref]), + {ok, State#{recv_stag => Tag, + recv_sref => Ref}}; + {completion, {completion_info, Tag, SR}} + when is_reference(SR) -> + ?SEV_IPRINT("recv completion ref: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, SR]), + {ok, State#{recv_stag => Tag}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; {error, _} = ERROR -> ERROR end @@ -7939,11 +8494,20 @@ api_a_send_and_recv_tcp(Config, InitState) -> ?SEV_ANNOUNCE_READY(Tester, recv_select), ok end}, - #{desc => "await select message", + #{desc => "await select|completion message", cmd => fun(#{csock := Sock, recv_sref := RecvRef}) -> receive {'$socket', Sock, select, RecvRef} -> - ok + ok; + {'$socket', Sock, completion, + {RecvRef, {ok, ?BASIC_REQ}}} -> + ?SEV_IPRINT("received expected data"), + ok; + {'$socket', Sock, completion, + {RecvRef, {error, Reason} = ERROR}} -> + ?SEV_EPRINT("received unexpected error: " + "~n ~p", [Reason]), + ERROR end end}, #{desc => "announce ready (select)", @@ -7952,13 +8516,19 @@ api_a_send_and_recv_tcp(Config, InitState) -> ok end}, #{desc => "now read the data (request)", - cmd => fun(#{csock := Sock, recv := Recv} = _State) -> + cmd => fun(#{sorc := select, + csock := Sock, + recv := Recv} = _State) -> case Recv(Sock) of {ok, ?BASIC_REQ} -> + ?SEV_IPRINT("read expected data"), ok; {error, _} = ERROR -> ERROR - end + end; + (#{sorc := completion}) -> + ?SEV_IPRINT("already received"), + ok end}, #{desc => "announce ready (recv request)", cmd => fun(#{tester := Tester}) -> @@ -8078,7 +8648,7 @@ api_a_send_and_recv_tcp(Config, InitState) -> ok end}, - #{desc => "try recv reply (with nowait, expect select)", + #{desc => "try recv reply (with nowait, expect select|completion)", cmd => fun(#{sock := Sock, recv := Recv, recv_sref := SR} = State) -> @@ -8088,16 +8658,35 @@ api_a_send_and_recv_tcp(Config, InitState) -> ?SEV_IPRINT("recv select nowait: " "~n Tag: ~p" "~n Ref: ~p", [Tag, Ref]), - {ok, State#{recv_stag => Tag, + {ok, State#{sorc => select, + recv_stag => Tag, recv_sref => Ref}}; {select, {select_info, Tag, SR}} when is_reference(SR) -> ?SEV_IPRINT("recv select ref: " "~n Tag: ~p" "~n Ref: ~p", [Tag, SR]), - {ok, State#{recv_stag => Tag}}; + {ok, State#{sorc => select, + recv_stag => Tag}}; + + {completion, {completion_info, Tag, Ref}} + when SR =:= nowait -> + ?SEV_IPRINT("recv completion nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, Ref]), + {ok, State#{sorc => completion, + recv_stag => Tag, + recv_sref => Ref}}; + {completion, {completion_info, Tag, SR}} + when is_reference(SR) -> + ?SEV_IPRINT("recv completion ref: " + "~n Tag: ~p" + "~n Ref: ~p", [Tag, SR]), + {ok, State#{sorc => completion, + recv_stag => Tag}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; {error, _} = ERROR -> ERROR end @@ -8111,6 +8700,10 @@ api_a_send_and_recv_tcp(Config, InitState) -> cmd => fun(#{sock := Sock, recv_sref := RecvRef}) -> receive {'$socket', Sock, select, RecvRef} -> + ok; + {'$socket', Sock, completion, + {RecvRef, {ok, ?BASIC_REP}}} -> + ?SEV_IPRINT("received expected reply"), ok end end}, @@ -8120,8 +8713,13 @@ api_a_send_and_recv_tcp(Config, InitState) -> ok end}, #{desc => "now read the data (reply)", - cmd => fun(#{sock := Sock, recv := Recv}) -> + cmd => fun(#{sorc := select, sock := Sock, recv := Recv}) -> {ok, ?BASIC_REP} = Recv(Sock), + ?SEV_IPRINT("[select] received expected reply"), + ok; + (#{sorc := completion}) -> + ?SEV_IPRINT("[completion] " + "expected reply already received"), ok end}, #{desc => "announce ready (recv reply)", @@ -8320,14 +8918,11 @@ api_a_send_and_recv_tcp(Config, InitState) -> %% Basically we make an async (Timeout = nowait) call to recvfrom, %% wait some time and then cancel. IPv4 %% -api_a_recvfrom_cancel_udp4(suite) -> - []; -api_a_recvfrom_cancel_udp4(doc) -> - []; api_a_recvfrom_cancel_udp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvfrom_cancel_udp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> case socket:recvfrom(Sock, 0, Nowait) of @@ -8335,13 +8930,15 @@ api_a_recvfrom_cancel_udp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_udp(InitState) end). @@ -8352,14 +8949,10 @@ api_a_recvfrom_cancel_udp4(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recvfrom, %% wait some time and then cancel. IPv6 %% -api_a_recvfrom_cancel_udp6(suite) -> - []; -api_a_recvfrom_cancel_udp6(doc) -> - []; api_a_recvfrom_cancel_udp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvfrom_cancel_udp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Recv = fun(Sock) -> @@ -8368,13 +8961,15 @@ api_a_recvfrom_cancel_udp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_udp(InitState) end). @@ -8385,14 +8980,11 @@ api_a_recvfrom_cancel_udp6(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recvmsg, %% wait some time and then cancel. IPv4 %% -api_a_recvmsg_cancel_udp4(suite) -> - []; -api_a_recvmsg_cancel_udp4(doc) -> - []; api_a_recvmsg_cancel_udp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvmsg_cancel_udp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> case socket:recvmsg(Sock, Nowait) of @@ -8400,13 +8992,15 @@ api_a_recvmsg_cancel_udp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_udp(InitState) end). @@ -8417,14 +9011,10 @@ api_a_recvmsg_cancel_udp4(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recvmsg, %% wait some time and then cancel. IPv6 %% -api_a_recvmsg_cancel_udp6(suite) -> - []; -api_a_recvmsg_cancel_udp6(doc) -> - []; api_a_recvmsg_cancel_udp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvmsg_cancel_udp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Recv = fun(Sock) -> @@ -8433,13 +9023,15 @@ api_a_recvmsg_cancel_udp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_udp(InitState) end). @@ -8499,19 +9091,28 @@ api_a_recv_cancel_udp(InitState) -> cmd => fun(#{tester := Tester} = _State) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, - #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + #{desc => "try recv request (with nowait, expect select|completion)", + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, SelectInfo} when SR =:= nowait -> - {ok, State#{recv_select_info => SelectInfo}}; + {select, SI} when Ref =:= nowait -> + {ok, State#{recv_select_info => SI}}; {select, - {select_info, _Tag, SR} = SelectInfo} - when is_reference(SR) -> - {ok, State#{recv_select_info => SelectInfo}}; + {select_info, _Tag, Ref} = SI} + when is_reference(Ref) -> + {ok, State#{recv_select_info => SI}}; + + {completion, CI} when Ref =:= nowait -> + {ok, State#{recv_completion_info => CI}}; + {completion, + {completion_info, _Tag, Ref} = CI} + when is_reference(Ref) -> + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -8521,11 +9122,15 @@ api_a_recv_cancel_udp(InitState) -> ?SEV_ANNOUNCE_READY(Tester, recv_select), ok end}, - #{desc => "await select message (without success)", + #{desc => "wait for select message - without success", cmd => fun(#{sock := Sock}) -> receive {'$socket', Sock, select, Ref} -> - {error, {unexpected_select, Ref}} + {error, {unexpected_select, Ref}}; + + {'$socket', Sock, completion, C} -> + {error, {unexpected_completion, C}} + after 5000 -> ok end @@ -8540,9 +9145,12 @@ api_a_recv_cancel_udp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, cancel) end}, #{desc => "cancel", - cmd => fun(#{sock := Sock, recv_select_info := SelectInfo}) -> - ok = socket:cancel(Sock, SelectInfo) + cmd => fun(#{sock := Sock, recv_select_info := SI}) -> + ok = socket:cancel(Sock, SI); + (#{sock := Sock, recv_completion_info := CI}) -> + ok = socket:cancel(Sock, CI) end}, + #{desc => "announce ready (cancel)", cmd => fun(#{tester := Tester}) -> ?SEV_ANNOUNCE_READY(Tester, cancel), @@ -8554,11 +9162,10 @@ api_a_recv_cancel_udp(InitState) -> cmd => fun(#{tester := Tester} = State) -> case ?SEV_AWAIT_TERMINATE(Tester, tester) of ok -> - State2 = maps:remove(tester, State), - State3 = maps:remove(recv_stag, State2), - State4 = maps:remove(recv_sref, State3), - State5 = maps:remove(req_src, State4), - {ok, State5}; + State2 = maps:remove(tester, State), + State3 = maps:remove(recv_ref, State2), + State4 = maps:remove(req_src, State3), + {ok, State4}; {error, _} = ERROR -> ERROR end @@ -8661,14 +9268,11 @@ api_a_recv_cancel_udp(InitState) -> %% Basically we make an async (Timeout = nowait) call to accept, %% wait some time and then cancel. IPv4 %% -api_a_accept_cancel_tcp4(suite) -> - []; -api_a_accept_cancel_tcp4(doc) -> - []; api_a_accept_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_accept_cancel_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Accept = fun(Sock) -> case socket:accept(Sock, Nowait) of @@ -8676,13 +9280,15 @@ api_a_accept_cancel_tcp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - accept => Accept, - accept_sref => Nowait}, + InitState = #{domain => inet, + accept => Accept, + accept_ref => Nowait}, ok = api_a_accept_cancel_tcp(InitState) end). @@ -8694,14 +9300,10 @@ api_a_accept_cancel_tcp4(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to accept, %% wait some time and then cancel. IPv6 %% -api_a_accept_cancel_tcp6(suite) -> - []; -api_a_accept_cancel_tcp6(doc) -> - []; api_a_accept_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_accept_cancel_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Accept = fun(Sock) -> @@ -8710,13 +9312,15 @@ api_a_accept_cancel_tcp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - accept => Accept, - accept_sref => Nowait}, + InitState = #{domain => inet6, + accept => Accept, + accept_ref => Nowait}, ok = api_a_accept_cancel_tcp(InitState) end). @@ -8782,28 +9386,39 @@ api_a_accept_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, accept) end}, #{desc => "await connection (nowait)", - cmd => fun(#{lsock := LSock, - accept := Accept, - accept_sref := SR} = State) -> + cmd => fun(#{lsock := LSock, + accept := Accept, + accept_ref := Ref} = State) -> case Accept(LSock) of - {select, {select_info, T, R} = SelectInfo} - when SR =:= nowait -> + {select, {select_info, T, R} = SI} + when Ref =:= nowait -> ?SEV_IPRINT("accept select nowait: " "~n T: ~p" "~n R: ~p", [T, R]), - {ok, - State#{accept_select_info => - SelectInfo}}; - {select, {select_info, T, SR} = SelectInfo} - when is_reference(SR) -> + {ok, State#{accept_select_info => SI}}; + {select, {select_info, T, Ref} = SI} + when is_reference(Ref) -> ?SEV_IPRINT("accept select ref: " "~n T: ~p" - "~n R: ~p", [T, SR]), - {ok, - State#{accept_select_info => - SelectInfo}}; + "~n R: ~p", [T, Ref]), + {ok, State#{accept_select_info => SI}}; + + {completion, {completion_info, T, R} = CI} + when Ref =:= nowait -> + ?SEV_IPRINT("accept completion nowait: " + "~n T: ~p" + "~n R: ~p", [T, R]), + {ok, State#{accept_completion_info => CI}}; + {completion, {completion_info, T, Ref} = CI} + when is_reference(Ref) -> + ?SEV_IPRINT("accept completion ref: " + "~n T: ~p" + "~n R: ~p", [T, Ref]), + {ok, State#{accept_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -8817,7 +9432,11 @@ api_a_accept_cancel_tcp(InitState) -> cmd => fun(#{lsock := Sock}) -> receive {'$socket', Sock, select, Ref} -> - {error, {unexpected_select, Ref}} + {error, {unexpected_select, Ref}}; + + {'$socket', Sock, completion, C} -> + {error, {unexpected_completion, C}} + after 5000 -> ok end @@ -8832,8 +9451,12 @@ api_a_accept_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, cancel) end}, #{desc => "cancel", - cmd => fun(#{lsock := Sock, accept_select_info := SelectInfo}) -> - ok = socket:cancel(Sock, SelectInfo) + cmd => fun(#{lsock := Sock, + accept_select_info := SelectInfo}) -> + ok = socket:cancel(Sock, SelectInfo); + (#{lsock := Sock, + accept_completion_info := CompletionInfo}) -> + ok = socket:cancel(Sock, CompletionInfo) end}, #{desc => "announce ready (cancel)", cmd => fun(#{tester := Tester}) -> @@ -8941,21 +9564,18 @@ api_a_accept_cancel_tcp(InitState) -> %% Basically we make an async (Timeout = nowait) call to recv, %% wait some time and then cancel. IPv4 %% -api_a_recv_cancel_tcp4(suite) -> - []; -api_a_recv_cancel_tcp4(doc) -> - []; api_a_recv_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recv_cancel_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock, 0, Nowait) end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_tcp(InitState) end). @@ -8966,22 +9586,18 @@ api_a_recv_cancel_tcp4(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recv, %% wait some time and then cancel. IPv6 %% -api_a_recv_cancel_tcp6(suite) -> - []; -api_a_recv_cancel_tcp6(doc) -> - []; api_a_recv_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recv_cancel_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock, 0, Nowait) end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_tcp(InitState) end). @@ -8992,21 +9608,21 @@ api_a_recv_cancel_tcp6(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recvmsg, %% wait some time and then cancel. IPv4 %% -api_a_recvmsg_cancel_tcp4(suite) -> - []; -api_a_recvmsg_cancel_tcp4(doc) -> - []; api_a_recvmsg_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvmsg_cancel_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock, Nowait) end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_tcp(InitState) end). @@ -9017,22 +9633,21 @@ api_a_recvmsg_cancel_tcp4(Config) when is_list(Config) -> %% Basically we make an async (Timeout = nowait) call to recvmsg, %% wait some time and then cancel. IPv6 %% -api_a_recvmsg_cancel_tcp6(suite) -> - []; -api_a_recvmsg_cancel_tcp6(doc) -> - []; api_a_recvmsg_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(10)), Nowait = nowait(Config), - tc_try(api_a_recvmsg_cancel_tcp6, - fun() -> has_support_ipv6() end, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), + has_support_ipv6() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock, Nowait) end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_recv_cancel_tcp(InitState) end). @@ -9115,27 +9730,43 @@ api_a_recv_cancel_tcp(InitState) -> cmd => fun(#{tester := Tester} = _State) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, - #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{csock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + + #{desc => "try recv request (with nowait, expect select|completion)", + cmd => fun(#{csock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, {select_info, T, R} = SelectInfo} - when SR =:= nowait -> + {select, {select_info, T, R} = SI} + when Ref =:= nowait -> ?SEV_IPRINT("recv select nowait: " "~n Tag: ~p" "~n Ref: ~p", [T, R]), - {ok, - State#{recv_select_info => SelectInfo}}; - {select, {select_info, T, SR} = SelectInfo} - when is_reference(SR) -> + {ok, State#{recv_select_info => SI}}; + {select, {select_info, T, Ref} = SI} + when is_reference(Ref) -> ?SEV_IPRINT("recv select ref: " "~n Tag: ~p" - "~n Ref: ~p", [T, SR]), - {ok, - State#{recv_select_info => SelectInfo}}; + "~n Ref: ~p", [T, Ref]), + {ok, State#{recv_select_info => SI}}; + + {completion, + {completion_info, T, R} = CI} + when Ref =:= nowait -> + ?SEV_IPRINT("recv completion nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [T, R]), + {ok, State#{recv_completion_info => CI}}; + {completion, + {completion_info, T, Ref} = CI} + when is_reference(Ref) -> + ?SEV_IPRINT("recv completion ref: " + "~n Tag: ~p" + "~n Ref: ~p", [T, Ref]), + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -9149,7 +9780,11 @@ api_a_recv_cancel_tcp(InitState) -> cmd => fun(#{csock := Sock}) -> receive {'$socket', Sock, select, Ref} -> - {error, {unexpected_select, Ref}} + {error, {unexpected_select, Ref}}; + + {'$socket', Sock, completion, C} -> + {error, {unexpected_completion, C}} + after 5000 -> ok end @@ -9164,8 +9799,11 @@ api_a_recv_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, cancel) end}, #{desc => "cancel", - cmd => fun(#{csock := Sock, recv_select_info := SelectInfo}) -> - ok = socket:cancel(Sock, SelectInfo) + cmd => fun(#{csock := Sock, recv_select_info := SI}) -> + ok = socket:cancel(Sock, SI); + + (#{csock := Sock, recv_completion_info := CI}) -> + ok = socket:cancel(Sock, CI) end}, #{desc => "announce ready (cancel)", cmd => fun(#{tester := Tester}) -> @@ -9407,14 +10045,11 @@ api_a_recv_cancel_tcp(InitState) -> %% (from *several* processes), wait some time and then cancel. %% This should result in abort messages to the 'other' processes. IPv4 %% -api_a_mrecvfrom_cancel_udp4(suite) -> - []; -api_a_mrecvfrom_cancel_udp4(doc) -> - []; api_a_mrecvfrom_cancel_udp4(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), tc_try(api_a_mrecvfrom_cancel_udp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> case socket:recvfrom(Sock, 0, Nowait) of @@ -9422,13 +10057,15 @@ api_a_mrecvfrom_cancel_udp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_udp(InitState) end). @@ -9440,10 +10077,6 @@ api_a_mrecvfrom_cancel_udp4(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel. %% This should result in abort messages to the 'other' processes. IPv6 %% -api_a_mrecvfrom_cancel_udp6(suite) -> - []; -api_a_mrecvfrom_cancel_udp6(doc) -> - []; api_a_mrecvfrom_cancel_udp6(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), @@ -9456,13 +10089,15 @@ api_a_mrecvfrom_cancel_udp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_udp(InitState) end). @@ -9474,14 +10109,11 @@ api_a_mrecvfrom_cancel_udp6(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel. %% This should result in abort messages to the 'other' processes. IPv4 %% -api_a_mrecvmsg_cancel_udp4(suite) -> - []; -api_a_mrecvmsg_cancel_udp4(doc) -> - []; api_a_mrecvmsg_cancel_udp4(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), tc_try(api_a_mrecvmsg_cancel_udp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> case socket:recvmsg(Sock, Nowait) of @@ -9489,13 +10121,15 @@ api_a_mrecvmsg_cancel_udp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_udp(InitState) end). @@ -9507,10 +10141,6 @@ api_a_mrecvmsg_cancel_udp4(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel. %% This should result in abort messages to the 'other' processes. IPv6 %% -api_a_mrecvmsg_cancel_udp6(suite) -> - []; -api_a_mrecvmsg_cancel_udp6(doc) -> - []; api_a_mrecvmsg_cancel_udp6(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), @@ -9523,13 +10153,15 @@ api_a_mrecvmsg_cancel_udp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_udp(InitState) end). @@ -9589,21 +10221,27 @@ api_a_mrecv_cancel_udp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, SelectInfo} - when SR =:= nowait -> - {ok, - State#{recv_select_info => SelectInfo}}; - {select, - {select_info, _Tag, SR} = SelectInfo} - when is_reference(SR) -> - {ok, - State#{recv_select_info => SelectInfo}}; + {select, SI} + when Ref =:= nowait -> + {ok, State#{recv_select_info => SI}}; + {select, {select_info, _Tag, Ref} = SI} + when is_reference(Ref) -> + {ok, State#{recv_select_info => SI}}; + + {completion, CI} + when Ref =:= nowait -> + {ok, State#{recv_completion_info => CI}}; + {completion, {completion_info, _Tag, Ref} = CI} + when is_reference(Ref) -> + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -9615,7 +10253,8 @@ api_a_mrecv_cancel_udp(InitState) -> end}, #{desc => "await abort message", cmd => fun(#{sock := Sock, - recv_select_info := {select_info, _, Ref}} = State) -> + recv_select_info := {select_info, _, Ref}} = + State) -> receive {'$socket', Sock, select, Ref} -> {error, {unexpected_select, Ref}}; @@ -9624,6 +10263,18 @@ api_a_mrecv_cancel_udp(InitState) -> after 5000 -> ?SEV_EPRINT("message queue: ~p", [mq()]), {error, timeout} + end; + (#{sock := Sock, + recv_completion_info := {completion_info, _, Ref}} = + State) -> + receive + {'$socket', Sock, completion, {Ref, CS}} -> + {error, {unexpected_completion, CS}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(sock, State)} + after 5000 -> + ?SEV_EPRINT("message queue: ~p", [mq()]), + {error, timeout} end end}, #{desc => "announce ready (abort)", @@ -9637,11 +10288,9 @@ api_a_mrecv_cancel_udp(InitState) -> cmd => fun(#{tester := Tester} = State) -> case ?SEV_AWAIT_TERMINATE(Tester, tester) of ok -> - State2 = maps:remove(tester, State), - State3 = maps:remove(recv_stag, State2), - State4 = maps:remove(recv_sref, State3), - State5 = maps:remove(req_src, State4), - {ok, State5}; + State2 = maps:remove(tester, State), + State3 = maps:remove(recv_ref, State2), + {ok, State3}; {error, _} = ERROR -> ERROR end @@ -9677,20 +10326,27 @@ api_a_mrecv_cancel_udp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, SelectInfo} when SR =:= nowait -> - {ok, - State#{recv_select_info => SelectInfo}}; + {select, SI} when Ref =:= nowait -> + {ok, State#{recv_select_info => SI}}; {select, - {select_info, _Tag, SR} = SelectInfo} - when is_reference(SR) -> - {ok, - State#{recv_select_info => SelectInfo}}; + {select_info, _Tag, Ref} = SI} + when is_reference(Ref) -> + {ok, State#{recv_select_info => SI}}; + + {completion, CI} when Ref =:= nowait -> + {ok, State#{recv_completion_info => CI}}; + {completion, + {completion_info, _Tag, Ref} = CI} + when is_reference(Ref) -> + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -9711,6 +10367,19 @@ api_a_mrecv_cancel_udp(InitState) -> after 5000 -> ?SEV_EPRINT("message queue: ~p", [mq()]), {error, timeout} + end; + + (#{sock := Sock, + recv_completion_info := {completion_info, _, Ref}} = + State) -> + receive + {'$socket', Sock, completion, {Ref, CS}} -> + {error, {unexpected_completion, CS}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(sock, State)} + after 5000 -> + ?SEV_EPRINT("message queue: ~p", [mq()]), + {error, timeout} end end}, #{desc => "announce ready (abort)", @@ -9726,9 +10395,10 @@ api_a_mrecv_cancel_udp(InitState) -> ok -> ?SEV_IPRINT("terminating"), State1 = maps:remove(recv_select_info, State), - State2 = maps:remove(tester, State1), - State3 = maps:remove(sock, State2), - {ok, State3}; + State2 = maps:remove(recv_completion_info, State1), + State3 = maps:remove(tester, State2), + State4 = maps:remove(sock, State3), + {ok, State4}; {error, _} = ERROR -> ERROR end @@ -9928,14 +10598,11 @@ api_a_mrecv_cancel_udp(InitState) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv4 %% -api_a_maccept_cancel_tcp4(suite) -> - []; -api_a_maccept_cancel_tcp4(doc) -> - []; api_a_maccept_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), tc_try(api_a_maccept_cancel_tcp4, + fun() -> has_support_ipv4() end, fun() -> Accept = fun(Sock) -> case socket:accept(Sock, Nowait) of @@ -9943,13 +10610,15 @@ api_a_maccept_cancel_tcp4(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet, - accept => Accept, - accept_sref => Nowait}, + InitState = #{domain => inet, + accept => Accept, + accept_ref => Nowait}, ok = api_a_maccept_cancel_tcp(InitState) end). @@ -9962,10 +10631,6 @@ api_a_maccept_cancel_tcp4(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv6 %% -api_a_maccept_cancel_tcp6(suite) -> - []; -api_a_maccept_cancel_tcp6(doc) -> - []; api_a_maccept_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), @@ -9978,13 +10643,15 @@ api_a_maccept_cancel_tcp6(Config) when is_list(Config) -> OK; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end end, - InitState = #{domain => inet6, - accept => Accept, - accept_sref => Nowait}, + InitState = #{domain => inet6, + accept => Accept, + accept_ref => Nowait}, ok = api_a_maccept_cancel_tcp(InitState) end). @@ -10050,28 +10717,39 @@ api_a_maccept_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, accept) end}, #{desc => "await connection (nowait)", - cmd => fun(#{lsock := LSock, - accept := Accept, - accept_sref := SR} = State) -> + cmd => fun(#{lsock := LSock, + accept := Accept, + accept_ref := Ref} = State) -> case Accept(LSock) of - {select, {select_info, T, R} = SelectInfo} - when SR =:= nowait -> + {select, {select_info, T, R} = SI} + when Ref =:= nowait -> ?SEV_IPRINT("accept select nowait: " "~n T: ~p" "~n R: ~p", [T, R]), - {ok, - State#{accept_select_info => - SelectInfo}}; - {select, {select_info, T, SR} = SelectInfo} - when is_reference(SR) -> + {ok, State#{accept_select_info => SI}}; + {select, {select_info, T, Ref} = SI} + when is_reference(Ref) -> ?SEV_IPRINT("accept select ref: " "~n T: ~p" - "~n R: ~p", [T, SR]), - {ok, - State#{accept_select_info => - SelectInfo}}; + "~n R: ~p", [T, Ref]), + {ok, State#{accept_select_info => SI}}; + + {completion, {completion_info, T, R} = CI} + when Ref =:= nowait -> + ?SEV_IPRINT("accept completion nowait: " + "~n T: ~p" + "~n R: ~p", [T, R]), + {ok, State#{accept_completion_info => CI}}; + {completion, {completion_info, T, Ref} = CI} + when is_reference(Ref) -> + ?SEV_IPRINT("accept completion ref: " + "~n T: ~p" + "~n R: ~p", [T, Ref]), + {ok, State#{accept_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -10090,7 +10768,26 @@ api_a_maccept_cancel_tcp(InitState) -> {'$socket', Sock, abort, {Ref, closed}} -> {ok, maps:remove(lsock, State)} after 5000 -> - ?SEV_EPRINT("message queue: ~p", [mq()]), + ?SEV_EPRINT("timeout when: " + "~n Sock: ~p" + "~n Ref: ~p" + "~n message queue: ~p", + [Sock, Ref, mq()]), + {error, timeout} + end; + (#{lsock := Sock, + accept_completion_info := {completion_info, _, Ref}} = State) -> + receive + {'$socket', Sock, completion, {Ref, _} = C} -> + {error, {unexpected_completion, C}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(lsock, State)} + after 5000 -> + ?SEV_EPRINT("timeout when: " + "~n Sock: ~p" + "~n Ref: ~p" + "~n message queue: ~p", + [Sock, Ref, mq()]), {error, timeout} end end}, @@ -10141,22 +10838,25 @@ api_a_maccept_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, accept) end}, #{desc => "try accept request (with nowait, expect select)", - cmd => fun(#{lsock := Sock, - accept := Accept, - accept_sref := SR} = State) -> + cmd => fun(#{lsock := Sock, + accept := Accept, + accept_ref := Ref} = State) -> case Accept(Sock) of - {select, SelectInfo} when SR =:= nowait -> - {ok, - State#{accept_select_info => - SelectInfo}}; - {select, - {select_info, _Tag, SR} = SelectInfo} - when is_reference(SR) -> - {ok, - State#{accept_select_info => - SelectInfo}}; + {select, SI} when Ref =:= nowait -> + {ok, State#{accept_select_info => SI}}; + {select, {select_info, _Tag, Ref} = SI} + when is_reference(Ref) -> + {ok, State#{accept_select_info => SI}}; + + {completion, CI} when Ref =:= nowait -> + {ok, State#{accept_completion_info => CI}}; + {completion, {completion_info, _Tag, Ref} = CI} + when is_reference(Ref) -> + {ok, State#{accept_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -10175,7 +10875,26 @@ api_a_maccept_cancel_tcp(InitState) -> {'$socket', Sock, abort, {Ref, closed}} -> {ok, maps:remove(sock, State)} after 5000 -> - ?SEV_EPRINT("message queue: ~p", [mq()]), + ?SEV_EPRINT("timeout when: " + "~n Sock: ~p" + "~n Ref: ~p" + "~n message queue: ~p", + [Sock, Ref, mq()]), + {error, timeout} + end; + (#{lsock := Sock, + accept_completion_info := {completion_info, _, Ref}} = State) -> + receive + {'$socket', Sock, completion, {Ref, _} = C} -> + {error, {unexpected_completion, C}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(sock, State)} + after 5000 -> + ?SEV_EPRINT("timeout when: " + "~n Sock: ~p" + "~n Ref: ~p" + "~n message queue: ~p", + [Sock, Ref, mq()]), {error, timeout} end end}, @@ -10193,8 +10912,9 @@ api_a_maccept_cancel_tcp(InitState) -> ?SEV_IPRINT("terminating"), State1 = maps:remove(tester, State), State2 = maps:remove(accept_select_info, State1), - State3 = maps:remove(lsock, State2), - {ok, State3}; + State3 = maps:remove(accept_completion_info, State2), + State4 = maps:remove(lsock, State3), + {ok, State4}; {error, _} = ERROR -> ERROR end @@ -10387,21 +11107,18 @@ api_a_maccept_cancel_tcp(InitState) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv4 %% -api_a_mrecv_cancel_tcp4(suite) -> - []; -api_a_mrecv_cancel_tcp4(doc) -> - []; api_a_mrecv_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), - tc_try(api_a_mrecv_cancel_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock, 0, Nowait) end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_tcp(InitState) end). @@ -10413,22 +11130,18 @@ api_a_mrecv_cancel_tcp4(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv6 %% -api_a_mrecv_cancel_tcp6(suite) -> - []; -api_a_mrecv_cancel_tcp6(doc) -> - []; api_a_mrecv_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), - tc_try(api_a_mrecv_cancel_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock, 0, Nowait) end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_tcp(InitState) end). @@ -10440,21 +11153,21 @@ api_a_mrecv_cancel_tcp6(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv4 %% -api_a_mrecvmsg_cancel_tcp4(suite) -> - []; -api_a_mrecvmsg_cancel_tcp4(doc) -> - []; api_a_mrecvmsg_cancel_tcp4(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), - tc_try(api_a_mrecvmsg_cancel_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock, Nowait) end, - InitState = #{domain => inet, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_tcp(InitState) end). @@ -10466,22 +11179,21 @@ api_a_mrecvmsg_cancel_tcp4(Config) when is_list(Config) -> %% (from *several* processes), wait some time and then cancel, %% This should result in abort messages to the 'other' processes. IPv6 %% -api_a_mrecvmsg_cancel_tcp6(suite) -> - []; -api_a_mrecvmsg_cancel_tcp6(doc) -> - []; api_a_mrecvmsg_cancel_tcp6(Config) when is_list(Config) -> ?TT(?SECS(20)), Nowait = nowait(Config), - tc_try(api_a_mrecvmsg_cancel_tcp6, - fun() -> has_support_ipv6() end, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), + has_support_ipv6() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock, Nowait) end, - InitState = #{domain => inet6, - recv => Recv, - recv_sref => Nowait}, + InitState = #{domain => inet6, + recv => Recv, + recv_ref => Nowait}, ok = api_a_mrecv_cancel_tcp(InitState) end). @@ -10564,25 +11276,40 @@ api_a_mrecv_cancel_tcp(InitState) -> cmd => fun(#{tester := Tester} = _State) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, - #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{csock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + #{desc => "try recv request (with nowait, expect select|completion)", + cmd => fun(#{csock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, {select_info, T, R} = SelectInfo} - when SR =:= nowait -> + {select, {select_info, T, R} = SI} + when Ref =:= nowait -> ?SEV_IPRINT("recv select nowait: " "~n Tag: ~p" "~n Ref: ~p", [T, R]), - {ok, State#{recv_select_info => SelectInfo}}; - {select, {select_info, T, SR} = SelectInfo} - when is_reference(SR) -> + {ok, State#{recv_select_info => SI}}; + {select, {select_info, T, Ref} = SI} + when is_reference(Ref) -> ?SEV_IPRINT("recv select nowait: " "~n Tag: ~p" - "~n Ref: ~p", [T, SR]), - {ok, State#{recv_select_info => SelectInfo}}; + "~n Ref: ~p", [T, Ref]), + {ok, State#{recv_select_info => SI}}; + + {completion, {completion_info, T, R} = CI} + when Ref =:= nowait -> + ?SEV_IPRINT("recv completion nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [T, R]), + {ok, State#{recv_completion_info => CI}}; + {completion, {completion_info, T, Ref} = CI} + when is_reference(Ref) -> + ?SEV_IPRINT("recv completion nowait: " + "~n Tag: ~p" + "~n Ref: ~p", [T, Ref]), + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -10592,7 +11319,7 @@ api_a_mrecv_cancel_tcp(InitState) -> ?SEV_ANNOUNCE_READY(Tester, recv_select), ok end}, - #{desc => "await select message", + #{desc => "await select|completion message", cmd => fun(#{csock := Sock, recv_select_info := {select_info, _, Ref}} = State) -> receive @@ -10602,6 +11329,16 @@ api_a_mrecv_cancel_tcp(InitState) -> {ok, maps:remove(sock, State)} after 5000 -> ok + end; + (#{csock := Sock, + recv_completion_info := {completion_info, _, Ref}} = State) -> + receive + {'$socket', Sock, completion, {Ref, _} = C} -> + {error, {unexpected_completion, C}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(sock, State)} + after 5000 -> + ok end end}, #{desc => "announce ready (abort)", @@ -10654,20 +11391,25 @@ api_a_mrecv_cancel_tcp(InitState) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) end}, #{desc => "try recv request (with nowait, expect select)", - cmd => fun(#{sock := Sock, - recv := Recv, - recv_sref := SR} = State) -> + cmd => fun(#{sock := Sock, + recv := Recv, + recv_ref := Ref} = State) -> case Recv(Sock) of - {select, SelectInfo} when SR =:= nowait -> - {ok, - State#{recv_select_info => SelectInfo}}; - {select, - {select_info, _Tag, SR} = SelectInfo} - when is_reference(SR) -> - {ok, - State#{recv_select_info => SelectInfo}}; + {select, SI} when Ref =:= nowait -> + {ok, State#{recv_select_info => SI}}; + {select, {select_info, _Tag, Ref} = SI} + when is_reference(Ref) -> + {ok, State#{recv_select_info => SI}}; + + {completion, CI} when Ref =:= nowait -> + {ok, State#{recv_completion_info => CI}}; + {completion, {completion_info, _Tag, Ref} = CI} + when is_reference(Ref) -> + {ok, State#{recv_completion_info => CI}}; + {ok, X} -> - {error, {unexpected_select_info, X}}; + {error, {unexpected_success, X}}; + {error, _} = ERROR -> ERROR end @@ -10688,6 +11430,17 @@ api_a_mrecv_cancel_tcp(InitState) -> after 5000 -> ?SEV_EPRINT("message queue: ~p", [mq()]), {error, timeout} + end; + (#{sock := Sock, + recv_completion_info := {completion_info, _, Ref}} = State) -> + receive + {'$socket', Sock, completion, {Ref, _} = C} -> + {error, {unexpected_completion, C}}; + {'$socket', Sock, abort, {Ref, closed}} -> + {ok, maps:remove(sock, State)} + after 5000 -> + ?SEV_EPRINT("message queue: ~p", [mq()]), + {error, timeout} end end}, #{desc => "announce ready (abort)", @@ -10703,9 +11456,10 @@ api_a_mrecv_cancel_tcp(InitState) -> ok -> ?SEV_IPRINT("terminating"), State1 = maps:remove(recv_select_info, State), - State2 = maps:remove(tester, State1), - State3 = maps:remove(sock, State2), - {ok, State3}; + State2 = maps:remove(recv_completion_info, State1), + State3 = maps:remove(tester, State2), + State4 = maps:remove(sock, State3), + {ok, State4}; {error, _} = ERROR -> ERROR end @@ -11037,10 +11791,6 @@ api_a_mrecv_cancel_tcp(InitState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Perform some simple getopt and setopt with the level = otp options -api_opt_simple_otp_options(suite) -> - []; -api_opt_simple_otp_options(doc) -> - []; api_opt_simple_otp_options(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_simple_otp_options, @@ -11304,7 +12054,8 @@ api_opt_simple_otp_options() -> %% *** We are done *** #{desc => "finish", - cmd => fun(_) -> + cmd => fun(#{ dummy := Dummy }) -> + Dummy ! die, {ok, normal} end} ], @@ -11324,10 +12075,6 @@ api_opt_simple_otp_options() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Perform some simple getopt and setopt otp meta option -api_opt_simple_otp_meta_option(suite) -> - []; -api_opt_simple_otp_meta_option(doc) -> - []; api_opt_simple_otp_meta_option(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_simple_otp_meta_option, @@ -11504,14 +12251,12 @@ api_opt_simple_otp_meta_option() -> %% Perform some simple operations with the rcvbuf otp option %% The operations we test here are only for type = stream and %% protocol = tcp. -api_opt_simple_otp_rcvbuf_option(suite) -> - []; -api_opt_simple_otp_rcvbuf_option(doc) -> - []; api_opt_simple_otp_rcvbuf_option(_Config) when is_list(_Config) -> ?TT(?SECS(15)), - tc_try(api_opt_simple_otp_rcvbuf_option, - fun() -> api_opt_simple_otp_rcvbuf_option() end). + tc_try(?FUNCTION_NAME, + fun() -> + api_opt_simple_otp_rcvbuf_option() + end). api_opt_simple_otp_rcvbuf_option() -> Get = fun(S) -> @@ -11650,6 +12395,12 @@ api_opt_simple_otp_rcvbuf_option() -> end}, #{desc => "attempt to recv", cmd => fun(#{sock := Sock, msg_sz := MsgSz} = _State) -> + ?SEV_IPRINT("try recv ~w bytes when rcvbuf is ~s", + [MsgSz, + case Get(Sock) of + {ok, RcvBuf} -> f("~w", [RcvBuf]); + {error, _} -> "-" + end]), case socket:recv(Sock) of {ok, Data} when (size(Data) =:= MsgSz) -> ok; @@ -11707,6 +12458,10 @@ api_opt_simple_otp_rcvbuf_option() -> cmd => fun(#{tester := Tester} = State) -> case ?SEV_AWAIT_CONTINUE(Tester, tester, recv) of {ok, {ExpSz, NewRcvBuf}} -> + ?SEV_IPRINT("set new rcvbuf:" + "~n New RcvBuf: ~p" + "~n Expect Size: ~p", + [ExpSz, NewRcvBuf]), {ok, State#{msg_sz => ExpSz, rcvbuf => NewRcvBuf}}; {error, _} = ERROR -> @@ -11717,7 +12472,8 @@ api_opt_simple_otp_rcvbuf_option() -> cmd => fun(#{sock := Sock, rcvbuf := NewRcvBuf} = _State) -> case Set(Sock, NewRcvBuf) of ok -> - ?SEV_IPRINT("set new rcvbuf: ~p", [NewRcvBuf]), + ?SEV_IPRINT("set new rcvbuf: ~p", + [NewRcvBuf]), ok; {error, _} = ERROR -> ERROR @@ -12012,7 +12768,13 @@ api_opt_simple_otp_rcvbuf_option() -> #{desc => "order server continue (recv 1)", cmd => fun(#{server := Server, data := Data} = _State) -> MsgSz = size(Data), - NewRcvBuf = {2 + (MsgSz div 1024), 1024}, + NewRcvBuf = + case os:type() of + {win32, nt} -> + (((2 * MsgSz) div 1024) + 1) * 1024; + _ -> + {2 + (MsgSz div 1024), 1024} + end, ?SEV_ANNOUNCE_CONTINUE(Server, recv, NewRcvBuf), ok end}, @@ -12049,7 +12811,13 @@ api_opt_simple_otp_rcvbuf_option() -> #{desc => "order server continue (recv 2)", cmd => fun(#{server := Server, data := Data} = _State) -> MsgSz = size(Data), - NewRcvBuf = {2 + (MsgSz div 2048), 2048}, + NewRcvBuf = + case os:type() of + {win32, nt} -> + (((3 * MsgSz) div 1024) + 1) * 1024; + _ -> + {2 + (MsgSz div 2048), 2048} + end, ?SEV_ANNOUNCE_CONTINUE(Server, recv, NewRcvBuf), ok end}, @@ -12086,12 +12854,18 @@ api_opt_simple_otp_rcvbuf_option() -> ?SEV_SLEEP(?SECS(1)), #{desc => "order server continue (recv 3)", cmd => fun(#{server := Server, data := Data} = _State) -> - MsgSz = size(Data), - BufSz = 2048, - N = MsgSz div BufSz - 1, - NewRcvBuf = {N, BufSz}, + MsgSz = size(Data), + BufSz = 2048, + N = MsgSz div BufSz - 1, + {ExpSz, NewRcvBuf} = + case os:type() of + {win32, nt} -> + {N*BufSz, N*BufSz}; + _ -> + {N*BufSz, {N, BufSz}} + end, ?SEV_ANNOUNCE_CONTINUE(Server, recv, - {N*BufSz, NewRcvBuf}) + {ExpSz, NewRcvBuf}) end}, #{desc => "await client ready (send 3)", cmd => fun(#{server := Server, @@ -12150,7 +12924,7 @@ api_opt_simple_otp_rcvbuf_option() -> %% Create a data binary of 6*1024 bytes Data = list_to_binary(lists:duplicate(6*4, lists:seq(0, 255))), - InitState = #{domain => inet, + InitState = #{domain => inet_or_inet6(), data => Data}, i("create server evaluator"), @@ -12175,10 +12949,6 @@ api_opt_simple_otp_rcvbuf_option() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Perform some simple getopt and setopt with the level = otp options -api_opt_simple_otp_controlling_process(suite) -> - []; -api_opt_simple_otp_controlling_process(doc) -> - []; api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_simple_otp_controlling_process, @@ -12399,7 +13169,7 @@ api_opt_simple_otp_controlling_process() -> Client1 = ?SEV_START("tcp-client", ClientSeq, ClientInitState1), i("start tcp (stream) tester evaluator"), - TesterInitState1 = #{domain => inet, + TesterInitState1 = #{domain => inet, type => stream, protocol => tcp, client => Client1#ev.pid}, @@ -12413,7 +13183,7 @@ api_opt_simple_otp_controlling_process() -> Client2 = ?SEV_START("udp-client", ClientSeq, ClientInitState2), i("start udp (dgram) tester evaluator"), - TesterInitState2 = #{domain => inet, + TesterInitState2 = #{domain => inet, type => dgram, protocol => udp, client => Client2#ev.pid}, @@ -12429,10 +13199,6 @@ api_opt_simple_otp_controlling_process() -> %% Tests the socket option acceptconn for UDP. %% This should be possible to get but not set. -api_opt_sock_acceptconn_udp(suite) -> - []; -api_opt_sock_acceptconn_udp(doc) -> - []; api_opt_sock_acceptconn_udp(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_sock_acceptconn_udp, @@ -12561,7 +13327,7 @@ api_opt_sock_acceptconn_udp() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -12577,10 +13343,6 @@ api_opt_sock_acceptconn_udp() -> %% Tests the socket option acceptconn for TCP. %% This should be possible to get but not set. -api_opt_sock_acceptconn_tcp(suite) -> - []; -api_opt_sock_acceptconn_tcp(doc) -> - []; api_opt_sock_acceptconn_tcp(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_sock_acceptconn_tcp, @@ -12917,7 +13679,7 @@ api_opt_sock_acceptconn_tcp() -> ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -12932,10 +13694,6 @@ api_opt_sock_acceptconn_tcp() -> %% Tests the socket option acceptfilter. PLACEHOLDER! -api_opt_sock_acceptfilter(suite) -> - []; -api_opt_sock_acceptfilter(doc) -> - []; api_opt_sock_acceptfilter(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_sock_acceptfilter, @@ -12948,12 +13706,8 @@ api_opt_sock_acceptfilter(_Config) when is_list(_Config) -> %% Tests the socket option bindtodevice. %% It has not always been possible to 'get' this option -%% (atleast on linux). +%% (at least on linux). -api_opt_sock_bindtodevice(suite) -> - []; -api_opt_sock_bindtodevice(doc) -> - []; api_opt_sock_bindtodevice(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_sock_bindtodevice, @@ -12974,7 +13728,7 @@ api_opt_sock_bindtodevice() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of + case which_local_host_info(Domain) of {ok, #{name := Name, addr := Addr}} -> ?SEV_IPRINT("local host info (~p): " "~n Name: ~p" @@ -13221,7 +13975,7 @@ api_opt_sock_bindtodevice() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -13238,10 +13992,6 @@ api_opt_sock_bindtodevice() -> %% Make it possible for datagram sockets to send packets to a broadcast %% address (IPv4 only). -api_opt_sock_broadcast(suite) -> - []; -api_opt_sock_broadcast(doc) -> - []; api_opt_sock_broadcast(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_sock_broadcast, @@ -13262,10 +14012,11 @@ api_opt_sock_broadcast() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of + case which_local_host_info(Domain) of {ok, #{name := Name, addr := Addr, - broadaddr := BAddr}} -> + broadaddr := BAddr}} + when (BAddr =/= undefined) -> ?SEV_IPRINT("local host info: " "~n Name: ~p" "~n Addr: ~p" @@ -13277,6 +14028,8 @@ api_opt_sock_broadcast() -> addr => BAddr}, {ok, State#{lsa => LSA, bsa => BSA}}; + {ok, _} -> + {skip, no_broadcast_address}; {error, _} = ERROR -> ERROR end @@ -13350,6 +14103,11 @@ api_opt_sock_broadcast() -> ?SEV_IPRINT("Expected Success (bound): ~p", [Port]), {ok, State#{sa2 => BSA#{port => Port}}}; + {error, eaddrnotavail = Reason} -> + ?SEV_IPRINT("~p => " + "SKIP subnet-directed broadcast test", + [Reason]), + {ok, State#{sa2 => skip}}; {error, Reason} = ERROR -> ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]), @@ -13357,7 +14115,10 @@ api_opt_sock_broadcast() -> end end}, #{desc => "[socket 2] UDP socket sockname", - cmd => fun(#{sock2 := Sock} = _State) -> + cmd => fun(#{sa2 := skip} = _State) -> + ?SEV_IPRINT("SKIP subnet-directed broadcast test"), + ok; + (#{sock2 := Sock} = _State) -> case socket:sockname(Sock) of {ok, SA} -> ?SEV_IPRINT("SA: ~p", [SA]), @@ -13463,12 +14224,12 @@ api_opt_sock_broadcast() -> #{desc => "[socket 3] try send to limited broadcast address", cmd => fun(#{sa1 := skip} = _State) -> - ?SEV_IPRINT("SKIP limited broadcast test"), + ?SEV_IPRINT("SKIP limited broadcast test (send)"), ok; (#{sock3 := Sock, sa1 := Dest} = _State) -> Data = list_to_binary("hejsan"), - ?SEV_IPRINT("try send to bradcast address: " + ?SEV_IPRINT("try send to broadcast address: " "~n ~p", [Dest]), case socket:sendto(Sock, Data, Dest) of ok -> @@ -13483,7 +14244,7 @@ api_opt_sock_broadcast() -> end}, #{desc => "[socket 1] try recv", cmd => fun(#{sa1 := skip} = _State) -> - ?SEV_IPRINT("SKIP limited broadcast test"), + ?SEV_IPRINT("SKIP limited broadcast test (recv)"), ok; (#{sock1 := Sock} = State) -> case socket:recvfrom(Sock, 0, 5000) of @@ -13510,17 +14271,29 @@ api_opt_sock_broadcast() -> ?SEV_SLEEP(?SECS(1)), - #{desc => "[socket 3] try send to subnet-directed broadcast address", - cmd => fun(#{sock3 := Sock, + #{desc => "[socket 2] try send to subnet-directed broadcast address", + cmd => fun(#{sa2 := skip} = _State) -> + ?SEV_IPRINT("SKIP subnet-directed broadcast test " + "(send)"), + ok; + (#{sock2 := Sock, sa2 := Dest} = _State) -> Data = list_to_binary("hejsan"), - ?SEV_IPRINT("try send to bradcast address: " + ?SEV_IPRINT("try send to broadcast address: " "~n ~p", [Dest]), case socket:sendto(Sock, Data, Dest) of ok -> ?SEV_IPRINT("Expected Success: " "broadcast message sent"), ok; + {error, eaddrnotavail = Reason} -> + ?SEV_EPRINT("Unexpected Failure: ~p => SKIP", + [Reason]), + {skip, Reason}; + {error, eacces = Reason} -> + ?SEV_EPRINT("Unexpected Failure: ~p => SKIP", + [Reason]), + {skip, Reason}; {error, Reason} = ERROR -> ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]), @@ -13528,13 +14301,17 @@ api_opt_sock_broadcast() -> end end}, #{desc => "[socket 2] try recv", - cmd => fun(#{sock2 := Sock, sa1 := SA1} = _State) -> + cmd => fun(#{sa2 := skip} = _State) -> + ?SEV_IPRINT("SKIP subnet-directed broadcast test " + "(recv)"), + ok; + (#{sock2 := Sock, sa2 := SA2} = _State) -> case socket:recvfrom(Sock, 0, 5000) of {ok, _} -> ?SEV_IPRINT("Expected Success: " "received message"), ok; - {error, timeout = Reason} when (SA1 =:= skip) -> + {error, timeout = Reason} when (SA2 =:= skip) -> ?SEV_IPRINT("Unexpected Failure: ~p", [Reason]), {skip, "receive timeout"}; @@ -13572,7 +14349,7 @@ api_opt_sock_broadcast() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -13588,13 +14365,9 @@ api_opt_sock_broadcast() -> %% Tests the socket option debug. %% On linux, this test requires that the user running the test to have %% CAP_NET_ADMIN capabilities or be root (effective user ID of 0), -%% therefor we explicitly test for the result eacces when attempting to +%% therefore we explicitly test for the result eacces when attempting to %% set, and skip if we get it. -api_opt_sock_debug(suite) -> - []; -api_opt_sock_debug(doc) -> - []; api_opt_sock_debug(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_debug, @@ -13615,21 +14388,16 @@ api_opt_sock_debug() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of + case which_local_host_info(Domain) of {ok, #{name := Name, - addr := Addr, - broadaddr := BAddr}} -> + addr := Addr}} -> ?SEV_IPRINT("local host info: " "~n Name: ~p" - "~n Addr: ~p" - "~n Broadcast Addr: ~p", - [Name, Addr, BAddr]), + "~n Addr: ~p", + [Name, Addr]), LSA = #{family => Domain, addr => Addr}, - BSA = #{family => Domain, - addr => BAddr}, - {ok, State#{lsa => LSA, - bsa => BSA}}; + {ok, State#{lsa => LSA}}; {error, _} = ERROR -> ERROR end @@ -13697,7 +14465,7 @@ api_opt_sock_debug() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -13713,10 +14481,6 @@ api_opt_sock_debug() -> %% Tests the socket option domain. %% This is a read only option. Also not available on all platforms. -api_opt_sock_domain(suite) -> - []; -api_opt_sock_domain(doc) -> - []; api_opt_sock_domain(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_domain, @@ -13734,21 +14498,16 @@ api_opt_sock_domain() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of - {ok, #{name := Name, - addr := Addr, - broadaddr := BAddr}} -> + case which_local_host_info(Domain) of + {ok, #{name := Name, + addr := Addr}} -> ?SEV_IPRINT("local host info: " - "~n Name: ~p" - "~n Addr: ~p" - "~n Broadcast Addr: ~p", - [Name, Addr, BAddr]), + "~n Name: ~p" + "~n Addr: ~p", + [Name, Addr]), LSA = #{family => Domain, addr => Addr}, - BSA = #{family => Domain, - addr => BAddr}, - {ok, State#{lsa => LSA, - bsa => BSA}}; + {ok, State#{lsa => LSA}}; {error, _} = ERROR -> ERROR end @@ -13815,7 +14574,7 @@ api_opt_sock_domain() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -13838,10 +14597,6 @@ api_opt_sock_domain() -> %% other side"), we only test if we can set and get the value. %% Better then nothing. -api_opt_sock_dontroute(suite) -> - []; -api_opt_sock_dontroute(doc) -> - []; api_opt_sock_dontroute(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_dontroute, @@ -13862,21 +14617,16 @@ api_opt_sock_dontroute() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of - {ok, #{name := Name, - addr := Addr, - broadaddr := BAddr}} -> + case which_local_host_info(Domain) of + {ok, #{name := Name, + addr := Addr}} -> ?SEV_IPRINT("local host info: " - "~n Name: ~p" - "~n Addr: ~p" - "~n Broadcast Addr: ~p", - [Name, Addr, BAddr]), + "~n Name: ~p" + "~n Addr: ~p", + [Name, Addr]), LSA = #{family => Domain, addr => Addr}, - BSA = #{family => Domain, - addr => BAddr}, - {ok, State#{lsa => LSA, - bsa => BSA}}; + {ok, State#{lsa => LSA}}; {error, _} = ERROR -> ERROR end @@ -13946,7 +14696,7 @@ api_opt_sock_dontroute() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -13961,10 +14711,6 @@ api_opt_sock_dontroute() -> %% Tests the socket option error. PLACEHOLDER! -api_opt_sock_error(suite) -> - []; -api_opt_sock_error(doc) -> - []; api_opt_sock_error(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_error, @@ -13980,10 +14726,6 @@ api_opt_sock_error(_Config) when is_list(_Config) -> %% the underlying TCP timeouts. So, for now, we just test that we can %% change the value. -api_opt_sock_keepalive(suite) -> - []; -api_opt_sock_keepalive(doc) -> - []; api_opt_sock_keepalive(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_keepalive, @@ -14004,21 +14746,16 @@ api_opt_sock_keepalive() -> [ #{desc => "which local address", cmd => fun(#{domain := Domain} = State) -> - case ?LIB:which_local_host_info(Domain) of + case which_local_host_info(Domain) of {ok, #{name := Name, - addr := Addr, - broadaddr := BAddr}} -> + addr := Addr}} -> ?SEV_IPRINT("local host info: " - "~n Name: ~p" - "~n Addr: ~p" - "~n Broadcast Addr: ~p", - [Name, Addr, BAddr]), + "~n Name: ~p" + "~n Addr: ~p", + [Name, Addr]), LSA = #{family => Domain, addr => Addr}, - BSA = #{family => Domain, - addr => BAddr}, - {ok, State#{lsa => LSA, - bsa => BSA}}; + {ok, State#{lsa => LSA}}; {error, _} = ERROR -> ERROR end @@ -14090,7 +14827,7 @@ api_opt_sock_keepalive() -> ?SEV_FINISH_NORMAL ], - Domain = inet, + Domain = inet_or_inet6(), i("start tester evaluator"), InitState = #{domain => Domain}, @@ -14101,14 +14838,395 @@ api_opt_sock_keepalive() -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the socket option reuseaddr. +%% This is the most basic of tests. We only test that we can set the +%% option and then read back. + +api_opt_sock_reuseaddr(_Config) when is_list(_Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + %% [IPv4] Nothing to do with the option, + %% [IPv4] but we use it the test so make + %% [IPv4] use we have it. + has_support_ipv4(), + has_support_sock_reuseaddr() + end, + fun() -> api_opt_sock_reuseaddr() end). + + +api_opt_sock_reuseaddr() -> + api_opt_simple_bool(inet, socket, stream, reuseaddr, + #{bind => false}). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the socket option exclusiveaddruse. +%% This is the most basic of tests. We only test that we can set the +%% option and then read back. + +api_opt_sock_exclusiveaddruse(_Config) when is_list(_Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + %% [IPv4] Nothing to do with the option, + %% [IPv4] but we use it the test so make + %% [IPv4] use we have it. + has_support_ipv4(), + has_support_sock_exclusiveaddruse() + end, + fun() -> api_opt_sock_exclusiveaddruse() end). + + +api_opt_sock_exclusiveaddruse() -> + api_opt_simple_bool(inet, socket, stream, exclusiveaddruse, + #{bind => false}). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% *Simple* test for a bool option. +%% This basically just tests that we can set and get the option. +%% This assumes that the option is supported. +%% What if its required that the socket is bound before set/get? +%% What if its required that set/get is done before bind? + +api_opt_simple_bool(Domain, Level, Type, Option, InitState) -> + + Set = fun(S, Val) when is_boolean(Val) -> + socket:setopt(S, Level, Option, Val) + end, + Get = fun(S) -> + socket:getopt(S, Level, Option) + end, + + TesterSeq = + [ + #{desc => "(maybe) which local address", + cmd => fun(#{bind := true} = State) -> + case ?LIB:which_local_host_info(Domain) of + {ok, #{name := Name, + addr := Addr}} -> + ?SEV_IPRINT("local host info: " + "~n Name: ~p" + "~n Addr: ~p", + [Name, Addr]), + LSA = #{family => Domain, + addr => Addr}, + {ok, State#{lsa => LSA}}; + {error, _} = ERROR -> + ERROR + end; + (_State) -> + ?SEV_IPRINT("ignore get local address"), + ok + end}, + + #{desc => "create socket", + cmd => fun(State) -> + case socket:open(Domain, Type) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + + #{desc => "(maybe) bind", + cmd => fun(#{bind := true, lsa := LSA, sock := Sock} = _State) -> + ?SEV_IPRINT("try binding"), + socket:bind(Sock, LSA); + (_State) -> + ?SEV_IPRINT("ignore binding"), + ok + end}, + + #{desc => "Get current value", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock) of + {ok, Val} when is_boolean(Val) -> + ?SEV_IPRINT("Success: ~p", [Val]), + {ok, State#{Option => Val}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Unexpected failure: ~p", + [Reason]), + ERROR + end + end}, + #{desc => "Try change the value", + cmd => fun(#{sock := Sock} = State) -> + Current = maps:get(Option, State), + New = not Current, + ?SEV_IPRINT("Try change value from ~p to ~p", + [Current, New]), + case Set(Sock, New) of + ok -> + ?SEV_IPRINT("Expected Success"), + {ok, State#{Option => New}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Unexpected Failure: ~p", + [Reason]), + ERROR + end + end}, + #{desc => "Verify (new) current value", + cmd => fun(#{sock := Sock} = State) -> + Val = maps:get(Option, State), + case Get(Sock) of + {ok, Val} -> + ?SEV_IPRINT("Expected Success (~p)", [Val]), + ok; + {ok, OtherVal} -> + ?SEV_IPRINT("Unexpected Success: ~p", + [OtherVal]), + {error, {unexpected_success_value, + Val, OtherVal}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Unexpected failure: ~p", + [Reason]), + ERROR + end + end}, + + %% *** Termination *** + #{desc => "close socket", + cmd => fun(#{sock := Sock} = State0) -> + socket:close(Sock), + State1 = maps:remove(sock, State0), + {ok, State1} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + i("start tester evaluator"), + Tester = ?SEV_START("tester", TesterSeq, InitState), + + i("await evaluator(s)"), + ok = ?SEV_AWAIT_FINISH([Tester]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the socket option bsp_state. +%% This is the most basic of tests. We test that we can, +%% create sockets, bind and connect and extract bsp-state +%% in the various state(s) of the socket. +%% For both dgram and stream sockets. + +api_opt_sock_bsp_state(_Config) when is_list(_Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + %% This is not a 'IPv4' option, + %% but since we used it in the test... + has_support_ipv4(), + has_support_sock_bsp_state() + end, + fun() -> api_opt_sock_bsp_state() end). + + +api_opt_sock_bsp_state() -> + LSA = which_local_socket_addr(inet), + BspState = fun(S) -> + case socket:getopt(S, socket, bsp_state) of + {ok, BS} -> + BS; + {error, Reason} -> + ?FAIL({getopt_bsp_state, Reason}) + end + end, + CreateSock = fun(T, P) -> + case socket:open(inet, T, P) of + {ok, Sock} -> + Sock; + {error, Reason} -> + skip({socket_create_fail, Reason}) + end + end, + CloseSock = fun(S) -> + socket:close(S) + end, + BindSock = fun(S, SA) -> + case socket:bind(S, SA) of + ok -> + ok; + {error, Reason} -> + ?FAIL({bind, Reason}) + end + end, + Sockname = fun(S) -> + case socket:sockname(S) of + {ok, SA} -> + SA; + {error, Reason} -> + ?FAIL({sockname, Reason}) + end + end, + %% Setopt = fun(S, L, O, V) -> + %% socket:setopt(S, L, O, V) + %% end, + %% SetOtpOpt = fun(S, O, V) -> Setopt(S, otp, O, V) end, + %% SetDebug = fun(S, D) when is_boolean(D) -> SetOptOpt(S, debug, D) end, + %% EnableDebug = fun(S) -> SetDebug(S, true) end, + ConnectSock = fun(S, SA) -> + case socket:connect(S, SA) of + ok -> + ok; + {error, Reason} -> + ?FAIL({connect, Reason}) + end + end, + ListenSock = fun(S) -> + case socket:listen(S) of + ok -> + ok; + {error, Reason} -> + ?FAIL({listen, Reason}) + end + end, + AcceptSock = fun(S) -> + case socket:accept(S) of + {ok, A} -> + A; + {error, Reason} -> + ?FAIL({accept, Reason}) + end + end, + + VerifyBspState = fun(S, Type, Proto, + Bound, Connected) -> + verify_bsp_state(S, Type, Proto, + Bound, Connected) + end, + + ?P("Create UDP socket 1:"), + US1 = CreateSock(dgram, udp), + ?P("UDP[1] [Unbound | Unconnected] => ~p", [BspState(US1)]), + VerifyBspState(BspState(US1), dgram, udp, false, false), + + ?P("Create UDP socket 2:"), + US2 = CreateSock(dgram, udp), + ?P("UDP[2] [Unbound | Unconnected] => ~p", [BspState(US2)]), + VerifyBspState(BspState(US2), dgram, udp, false, false), + + ?P("Bind UDP socket 1"), + BindSock(US1, LSA), + ?P("UDP[1] [Bound | Unconnected] => ~p", [BspState(US1)]), + VerifyBspState(BspState(US1), dgram, udp, true, false), + + ?P("Bind UDP socket 2"), + BindSock(US2, LSA), + ?P("UDP[2] [Bound | Unconnected] => ~p", [BspState(US2)]), + VerifyBspState(BspState(US2), dgram, udp, true, false), + + %% We have not yet implemented 'connect' for UDP on Windows, + %% so we leave this commented for now: + + %% ?P("socknames"), + %% USN1 = Sockname(US1), + %% USN2 = Sockname(US2), + + %% ?P("enable debug for US1"), + %% EnableDebug(US1), + + %% ?P("Connect UDP socket 1 to" + %% "~n ~p", [USN2]), + %% ConnectSock(US1, USN2), + %% ?P("UDP[1] [Bound | Connected] => ~p", [BspState(US1)]), + + %% ?P("Connect UDP socket 2 to" + %% "~n ~p", [USN1]), + %% ConnectSock(US2, USN1), + %% ?P("UDP[2] [Bound | Connected] => ~p", [BspState(US2)]), + + + ?P("Create TCP socket 1:"), + TS1 = CreateSock(stream, tcp), + ?P("TCP[1] [Unbound | Unconnected] => ~p", [BspState(TS1)]), + VerifyBspState(BspState(TS1), stream, tcp, false, false), + + ?P("Create TCP socket 2 (listen):"), + TS2 = CreateSock(stream, tcp), + ?P("TCP[2] [Unbound | Unconnected] => ~p", [BspState(TS2)]), + VerifyBspState(BspState(TS2), stream, tcp, false, false), + + ?P("Bind TCP socket 1"), + BindSock(TS1, LSA), + ?P("TCP[1] [Bound | Unconnected] => ~p", [BspState(TS1)]), + VerifyBspState(BspState(TS1), stream, tcp, true, false), + + ?P("Bind TCP socket 2"), + BindSock(TS2, LSA), + ?P("TCP[2] [Bound | Unconnected] => ~p", [BspState(TS2)]), + VerifyBspState(BspState(TS2), stream, tcp, true, false), + + ?P("Make TCP socket 2 listen"), + ListenSock(TS2), + + ?P("socknames"), + TSN2 = Sockname(TS2), + + ?P("Connect TCP socket 1 to" + "~n ~p", [TSN2]), + ConnectSock(TS1, TSN2), + ?P("TCP[1] [Bound | Connected] => ~p", [BspState(TS1)]), + VerifyBspState(BspState(TS1), stream, tcp, true, true), + + ?P("Accept TCP socket 3"), + TS3 = AcceptSock(TS2), + ?P("TCP[3] [Bound | Connected] => ~p", [BspState(TS3)]), + VerifyBspState(BspState(TS3), stream, tcp, true, true), + + ?P("Close socket(s)"), + CloseSock(TS3), + CloseSock(TS2), + CloseSock(TS1), + + ?P("done"), + ok. + + +verify_bsp_state(#{type := T, + protocol := P, + local_addr := LA, + remote_addr := RA}, + Type, Proto, + Bound, Connected) when (T =:= Type) andalso (P =:= Proto) -> + case {Bound, LA} of + {false, undefined} -> + ok; + {true, _} when (LA =/= undefined) -> + ok; + _ -> + ?FAIL({invalid_bound_la, Bound, LA}) + end, + case {Connected, RA} of + {false, undefined} -> + ok; + {true, _} when (RA =/= undefined) -> + ok; + _ -> + ?FAIL({invalid_connected_ra, Connected, RA}) + end, + ok; +verify_bsp_state(#{type := T, + protocol := P}, + Type, Proto, + _Bound, _Connected) -> + ?FAIL({invalid_type_or_proto, {T, Type}, {P, Proto}}). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Tests the socket option linger. PLACEHOLDER! -api_opt_sock_linger(suite) -> - []; -api_opt_sock_linger(doc) -> - []; api_opt_sock_linger(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_linger, @@ -14121,10 +15239,6 @@ api_opt_sock_linger(_Config) when is_list(_Config) -> %% Tests the socket option mark. PLACEHOLDER! -api_opt_sock_mark(suite) -> - []; -api_opt_sock_mark(doc) -> - []; api_opt_sock_mark(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_opt_sock_mark, @@ -14133,6 +15247,60 @@ api_opt_sock_mark(_Config) when is_list(_Config) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the socket option maxdg. + +api_opt_sock_maxdg(_Config) when is_list(_Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + %% This is not a 'IPv4' option, + %% but since we used it in the test... + has_support_ipv4(), + has_support_sock_maxdg() + end, + fun() -> do_api_opt_sock_maxdg() end). + +do_api_opt_sock_maxdg() -> + ?P("create DGRAM socket"), + {ok, S} = socket:open(inet, dgram), + ?P("get maxdg"), + case socket:getopt(S, socket, maxdg) of + {ok, Sz} -> + ?P("success: Sz = ~p", [Sz]), + ok; + {error, Reason} -> + ?FAIL({failed_get_maxdg, Reason}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests the socket option max_msg_size. + +api_opt_sock_max_msg_size(_Config) when is_list(_Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + %% This is not a 'IPv4' option, + %% but since we used it in the test... + has_support_ipv4(), + has_support_sock_max_msg_size() + end, + fun() -> do_api_opt_sock_max_msg_size() end). + +do_api_opt_sock_max_msg_size() -> + {ok, S} = socket:open(inet, dgram), + case socket:getopt(S, socket, max_msg_size) of + {ok, Sz} -> + ?P("success: Sz = ~p", [Sz]), + ok; + {error, Reason} -> + ?FAIL({failed_get_max_msg_size, Reason}) + end. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case tries to test that the oobinline socket 'socket' option @@ -14141,7 +15309,7 @@ api_opt_sock_mark(_Config) when is_list(_Config) -> %% %% socket:setopt(Sock, socket, oobinline, boolean()). %% -%% This works on linux of some version (atleast linux kernel 4.15.0), +%% This works on linux of some version (at least linux kernel 4.15.0), %% but not on FreeBSD (12) for some reason. Until we have figured out %% exctly why, we skip a bunch of OSs... %% @@ -14150,10 +15318,6 @@ api_opt_sock_mark(_Config) when is_list(_Config) -> %% linux but maybe not in, say, FreeBSD). %% -api_opt_sock_oobinline(suite) -> - []; -api_opt_sock_oobinline(doc) -> - []; api_opt_sock_oobinline(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_ooinline, @@ -14179,7 +15343,7 @@ api_opt_sock_oobinline(_Config) when is_list(_Config) -> (Sock, false) -> socket:recv(Sock) end, - InitState = #{domain => inet, + InitState = #{domain => inet_or_inet6(), proto => tcp, send => Send, recv => Recv, @@ -14783,10 +15947,6 @@ do_api_opt_sock_oobinline(InitState) -> %% As it is now, the client does *not* get any credentials! %% Until this has been done, this case is skipped!. -api_opt_sock_passcred_tcp4(suite) -> - []; -api_opt_sock_passcred_tcp4(doc) -> - []; api_opt_sock_passcred_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_passcred_tcp4, @@ -15574,10 +16734,6 @@ api_opt_sock_passcred_tcp(InitState) -> %% %% -api_opt_sock_peek_off_tcpL(suite) -> - []; -api_opt_sock_peek_off_tcpL(doc) -> - []; api_opt_sock_peek_off_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_peek_off_tcpL, @@ -16125,7 +17281,7 @@ api_opt_sock_peek_off(InitState) -> %% There is no way to be sure that the data has actually arrived, %% and with no data on the server side, the peek will fail. - %% Hopfully a sleep will take care of this... + %% Hopefully a sleep will take care of this... ?SEV_SLEEP(?SECS(1)), %% 1) peek @@ -16288,7 +17444,7 @@ api_opt_sock_peek_off(InitState) -> %% Tests that we get the peer credentials for a connected unix domain %% TCP (stream) socket. -%% That is, all we need to do is to create a slave node, and have +%% That is, all we need to do is to create a node, and have %% process connect from that to a local (unix domain socket) socket. %% %% THIS IS A PLACEHOLDER!! @@ -16297,10 +17453,6 @@ api_opt_sock_peek_off(InitState) -> %% and decode it... %% -api_opt_sock_peercred_tcpL(suite) -> - []; -api_opt_sock_peercred_tcpL(doc) -> - []; api_opt_sock_peercred_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_peercred_tcpL, @@ -16477,11 +17629,11 @@ api_opt_sock_peercred_tcp(_InitState) -> %% #{desc => "create node", %% cmd => fun(#{host := Host} = State) -> %% ?SEV_IPRINT("try create node on ~p", [Host]), - %% case start_node(Host, client) of - %% {ok, Node} -> + %% case ?CT_PEER() of + %% {ok, Peer, Node} -> %% ?SEV_IPRINT("client node ~p started", %% [Node]), - %% {ok, State#{node => Node}}; + %% {ok, State#{node => Node, peer => Peer}}; %% {error, Reason} -> %% {skip, Reason} %% end @@ -16590,8 +17742,8 @@ api_opt_sock_peercred_tcp(_InitState) -> %% {ok, State1} %% end}, %% #{desc => "stop client node", - %% cmd => fun(#{node := Node} = _State) -> - %% stop_node(Node) + %% cmd => fun(#{peer := Peer} = _State) -> + %% peer:stop(Peer) %% end}, %% #{desc => "await client node termination", %% cmd => fun(#{node := Node} = State) -> @@ -16836,14 +17988,10 @@ api_opt_sock_peercred_tcp(_InitState) -> %% %% -api_opt_sock_priority_udp4(suite) -> - []; -api_opt_sock_priority_udp4(doc) -> - []; api_opt_sock_priority_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_priority_udp4, - fun() -> has_support_sock_priority() end, + fun() -> has_support_ipv4(), has_support_sock_priority() end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, socket, priority, Value) @@ -16869,14 +18017,10 @@ api_opt_sock_priority_udp4(_Config) when is_list(_Config) -> %% %% -api_opt_sock_priority_tcp4(suite) -> - []; -api_opt_sock_priority_tcp4(doc) -> - []; api_opt_sock_priority_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_priority_tcp4, - fun() -> has_support_sock_priority() end, + fun() -> has_support_ipv4(), has_support_sock_priority() end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, socket, priority, Value) @@ -17010,14 +18154,10 @@ api_opt_sock_priority(InitState) -> %% %% -api_opt_sock_rcvbuf_udp4(suite) -> - []; -api_opt_sock_rcvbuf_udp4(doc) -> - []; api_opt_sock_rcvbuf_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_rcvbuf_udp4, - fun() -> has_support_sock_rcvbuf() end, + fun() -> has_support_ipv4(), has_support_sock_rcvbuf() end, fun() -> ok = api_opt_sock_buf_udp4(rcvbuf) end). @@ -17031,14 +18171,10 @@ api_opt_sock_rcvbuf_udp4(_Config) when is_list(_Config) -> %% %% -api_opt_sock_sndbuf_udp4(suite) -> - []; -api_opt_sock_sndbuf_udp4(doc) -> - []; api_opt_sock_sndbuf_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_sndbuf_udp4, - fun() -> has_support_sock_sndbuf() end, + fun() -> has_support_ipv4(), has_support_sock_sndbuf() end, fun() -> ok = api_opt_sock_buf_udp4(sndbuf) end). @@ -17167,14 +18303,10 @@ api_opt_sock_buf(InitState) -> %% but we don't (we just set the value and read it back...) %% -api_opt_sock_rcvtimeo_udp4(suite) -> - []; -api_opt_sock_rcvtimeo_udp4(doc) -> - []; api_opt_sock_rcvtimeo_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_rcvtimeo_udp4, - fun() -> has_support_sock_rcvtimeo() end, + fun() -> has_support_ipv4(), has_support_sock_rcvtimeo() end, fun() -> ok = api_opt_sock_timeo_udp4(rcvtimeo) end). @@ -17188,14 +18320,10 @@ api_opt_sock_rcvtimeo_udp4(_Config) when is_list(_Config) -> %% %% -api_opt_sock_sndtimeo_udp4(suite) -> - []; -api_opt_sock_sndtimeo_udp4(doc) -> - []; api_opt_sock_sndtimeo_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_sndtimeo_udp4, - fun() -> has_support_sock_sndtimeo() end, + fun() -> has_support_ipv4(), has_support_sock_sndtimeo() end, fun() -> ok = api_opt_sock_timeo_udp4(sndtimeo) end). @@ -17291,7 +18419,7 @@ api_opt_sock_timeo(InitState) -> ok; {ok, #{sec := Sec}} when (ExpSec =:= Sec) -> %% For some reason OpenBSD "adjusts" the timeout, - %% so that usec does not (allways match) + %% so that usec does not (always match) ?SEV_IPRINT("timeout (approx) validated"), ok; {ok, TO} -> @@ -17338,14 +18466,14 @@ api_opt_sock_timeo(InitState) -> %% %% -api_opt_sock_rcvlowat_udp4(suite) -> - []; -api_opt_sock_rcvlowat_udp4(doc) -> - []; api_opt_sock_rcvlowat_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_rcvlowat_udp4, - fun() -> has_support_sock_rcvlowat() end, + fun() -> + is_not_windows(), % einval on Windows + has_support_ipv4(), + has_support_sock_rcvlowat() + end, fun() -> ok = api_opt_sock_lowat_udp4(rcvlowat) end). @@ -17361,14 +18489,14 @@ api_opt_sock_rcvlowat_udp4(_Config) when is_list(_Config) -> %% so we skip if we get ENOPROTOOPT when attempting a change. %% -api_opt_sock_sndlowat_udp4(suite) -> - []; -api_opt_sock_sndlowat_udp4(doc) -> - []; api_opt_sock_sndlowat_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_sndlowat_udp4, - fun() -> has_support_sock_sndlowat() end, + fun() -> + is_not_windows(), % einval on Windows + has_support_ipv4(), + has_support_sock_sndlowat() + end, fun() -> ok = api_opt_sock_lowat_udp4(sndlowat) end). @@ -17505,14 +18633,10 @@ api_opt_sock_lowat(InitState) -> %% All subsequent *received* messages will be timestamped. %% -api_opt_sock_timestamp_udp4(suite) -> - []; -api_opt_sock_timestamp_udp4(doc) -> - []; api_opt_sock_timestamp_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_timestamp_udp4, - fun() -> has_support_sock_timestamp() end, + fun() -> has_support_ipv4(), has_support_sock_timestamp() end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, socket, timestamp, Value) @@ -17891,14 +19015,11 @@ api_opt_sock_timestamp_udp(InitState) -> %% Don't actually know if its the distro or the (kernel) version... %% -api_opt_sock_timestamp_tcp4(suite) -> - []; -api_opt_sock_timestamp_tcp4(doc) -> - []; api_opt_sock_timestamp_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_sock_timestamp_tcp4, fun() -> + has_support_ipv4(), has_support_sock_timestamp(), is_good_enough_linux({4,4,120}), is_not_freebsd(), @@ -18311,7 +19432,7 @@ api_opt_sock_timestamp_tcp(InitState) -> ERROR end end}, - %% Linux pecularity observed here... + %% Linux peculiarity observed here... %% Detected on Kernel 4.15.0-72 x96_64. %% The option set to enable receiving timestamps just above %% has failed to be effective down in "await recv reply 2 @@ -18696,10 +19817,9 @@ api_opt_sock_timestamp_tcp(InitState) -> %% When sending, the dest will be the multicast address %% and port of the receiving socket. %% Receiving socket: Bound to the multicast address and port. -api_opt_ip_add_drop_membership(suite) -> - []; -api_opt_ip_add_drop_membership(doc) -> - ["OTP-15908 (ERL-980)"]; +api_opt_ip_add_drop_membership() -> + [{doc, "OTP-15908 (ERL-980)"}]. + api_opt_ip_add_drop_membership(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(api_opt_ip_add_drop_membership, @@ -18708,10 +19828,10 @@ api_opt_ip_add_drop_membership(_Config) when is_list(_Config) -> has_support_ip_drop_membership(), has_support_ip_multicast() end, - fun() -> api_opt_ip_add_drop_membership() end). + fun() -> api_opt_ip_add_drop_membership_do() end). -api_opt_ip_add_drop_membership() -> +api_opt_ip_add_drop_membership_do() -> Set = fun(S, Key, Val) -> socket:setopt(S, ip, Key, Val) end, @@ -19038,14 +20158,10 @@ which_local_host_ifname(Domain) -> %% we do not test!! %% -api_opt_ip_pktinfo_udp4(suite) -> - []; -api_opt_ip_pktinfo_udp4(doc) -> - []; api_opt_ip_pktinfo_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), - tc_try(api_opt_ip_pktinfo_udp4, - fun() -> has_support_ip_pktinfo() end, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4(), has_support_ip_pktinfo() end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, ip, pktinfo, Value) @@ -19053,6 +20169,367 @@ api_opt_ip_pktinfo_udp4(_Config) when is_list(_Config) -> Get = fun(Sock) -> socket:getopt(Sock, ip, pktinfo) end, + Send = fun(Sock, Data, Dest, default) -> + Msg = #{addr => Dest, + iov => [Data]}, + socket:sendmsg(Sock, Msg); + (Sock, Data, Dest, Info) -> + %% We do not support this at the moment!!! + CMsg = #{level => ip, + type => pktinfo, + data => Info}, + Msg = #{addr => Dest, + ctrl => [CMsg], + iov => [Data]}, + socket:sendmsg(Sock, Msg) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + ctrl := CMsgs, + iov := [Data]}} -> + {ok, {Source, CMsgs, Data}}; + {error, _} = ERROR -> + ERROR + end + end, + InitState = #{domain => inet, + proto => udp, + send => Send, + recv => Recv, + set => Set, + get => Get}, + ok = api_opt_ip_pktinfo_udp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_ip_pktinfo_udp(InitState) -> + Seq = + [ + #{desc => "local address", + cmd => fun(#{domain := local = Domain} = State) -> + LSASrc = which_local_socket_addr(Domain), + LSADst = which_local_socket_addr(Domain), + {ok, State#{lsa_src => LSASrc, + lsa_dst => LSADst}}; + (#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa_src => LSA, + lsa_dst => LSA}} + end}, + + #{desc => "open src socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + Sock = sock_open(Domain, dgram, Proto), + {ok, State#{sock_src => Sock}} + end}, + #{desc => "bind src", + cmd => fun(#{sock_src := Sock, lsa_src := LSA}) -> + case sock_bind(Sock, LSA) of + ok -> + ?SEV_IPRINT("src bound"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("src bind failed: ~p", [Reason]), + ERROR + end + end}, + #{desc => "sockname src socket", + cmd => fun(#{sock_src := Sock} = State) -> + SASrc = sock_sockname(Sock), + ?SEV_IPRINT("src sockaddr: " + "~n ~p", [SASrc]), + {ok, State#{sa_src => SASrc}} + end}, + + #{desc => "open dst socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + Sock = sock_open(Domain, dgram, Proto), + {ok, State#{sock_dst => Sock}} + end}, + #{desc => "bind dst", + cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) -> + case sock_bind(Sock, LSA) of + ok -> + ?SEV_IPRINT("src bound"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("src bind failed: ~p", [Reason]), + ERROR + end + end}, + #{desc => "sockname dst socket", + cmd => fun(#{sock_dst := Sock} = State) -> + SADst = sock_sockname(Sock), + ?SEV_IPRINT("dst sockaddr: " + "~n ~p", [SADst]), + {ok, State#{sa_dst => SADst}} + end}, + #{desc => "get default pktinfo for dst socket", + cmd => fun(#{sock_dst := Sock, get := Get} = _State) -> + case Get(Sock) of + {ok, false = Value} -> + ?SEV_IPRINT("dst recvttl: ~p", [Value]), + ok; + {ok, Unexpected} -> + ?SEV_EPRINT("Unexpected src pktinfo: ~p", + [Unexpected]), + {error, {unexpected, Unexpected}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Failed getting (default) pktinfo:" + " ~p", [Reason]), + ERROR + end + end}, + + #{desc => "send req (to dst) (wo (explicit) pktinfo)", + cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> + Send(Sock, ?BASIC_REQ, Dst, default) + end}, + #{desc => "recv req (from src)", + cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> + case Recv(Sock) of + {ok, {Src, [], ?BASIC_REQ}} -> + ok; + {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Recv Source: ~p" + "~n Expect CHdrs: ~p" + "~n Recv CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Recv Msg: ~p", + [Src, BadSrc, + [], BadCHdrs, + ?BASIC_REQ, BadReq]), + {error, {unexpected_data, UnexpData}}; + {ok, UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Expect CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Unexp Data: ~p", + [Src, [], ?BASIC_REQ, UnexpData]), + {error, {unexpected_data, UnexpData}}; + {error, _} = ERROR -> + %% At the moment there is no way to get + %% status or state for the socket... + ERROR + end + end}, + + + %% *** We do not *yet* support sending pktinfo *** + + %% #{desc => "send req (to dst) (w explicit pktinfo)", + %% cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> + %% Send(Sock, ?BASIC_REQ, Dst, PktInfo) + %% end}, + %% #{desc => "recv req (from src) - wo pktinfo", + %% cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> + %% case Recv(Sock) of + %% {ok, {Src, [], ?BASIC_REQ}} -> + %% ok; + %% {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> + %% ?SEV_EPRINT("Unexpected msg: " + %% "~n Expect Source: ~p" + %% "~n Recv Source: ~p" + %% "~n Expect CHdrs: ~p" + %% "~n Recv CHdrs: ~p" + %% "~n Expect Msg: ~p" + %% "~n Recv Msg: ~p", + %% [Src, BadSrc, + %% [], BadCHdrs, + %% ?BASIC_REQ, BadReq]), + %% {error, {unexpected_data, UnexpData}}; + %% {ok, UnexpData} -> + %% ?SEV_EPRINT("Unexpected msg: " + %% "~n Expect Source: ~p" + %% "~n Expect CHdrs: ~p" + %% "~n Expect Msg: ~p" + %% "~n Unexp Data: ~p", + %% [Src, [], ?BASIC_REQ, UnexpData]), + %% {error, {unexpected_data, UnexpData}}; + %% {error, _} = ERROR -> + %% %% At the moment there is no way to get + %% %% status or state for the socket... + %% ERROR + %% end + %% end}, + + #{desc => "enable pktinfo on dst socket", + cmd => fun(#{sock_dst := Sock, set := Set} = _State) -> + case Set(Sock, true) of + ok -> + ?SEV_IPRINT("dst pktinfo enabled"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Failed setting pktinfo:" + " ~p", [Reason]), + ERROR + end + end}, + + #{desc => "send req (to dst) (wo explicit pktinfo)", + cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> + Send(Sock, ?BASIC_REQ, Dst, default) + end}, + #{desc => "recv req (from src) - w default pktinfo", + cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> + case Recv(Sock) of + {ok, {Src, [#{level := ip, + type := pktinfo, + value := #{addr := Addr, + ifindex := IfIdx, + spec_dst := SpecDst}}], + ?BASIC_REQ}} -> + ?SEV_IPRINT("Got (default) Pkt Info: " + "~n Addr: ~p" + "~n If Index: ~p" + "~n Spec Dst: ~p", + [Addr, IfIdx, SpecDst]), + ok; + {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Recv Source: ~p" + "~n Expect CHdrs: ~p" + "~n Recv CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Recv Msg: ~p", + [Src, BadSrc, + [], BadCHdrs, + ?BASIC_REQ, BadReq]), + {error, {unexpected_data, UnexpData}}; + {ok, UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Expect CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Unexp Data: ~p", + [Src, [], ?BASIC_REQ, UnexpData]), + {error, {unexpected_data, UnexpData}}; + {error, _} = ERROR -> + %% At the moment there is no way to get + %% status or state for the socket... + ERROR + end + end}, + + + %% *** We do not *yet* support sending pktinfo *** + + %% #{desc => "send req (to dst) (w explicit pktinfo)", + %% cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> + %% Send(Sock, ?BASIC_REQ, Dst, PktInfo) + %% end}, + %% #{desc => "recv req (from src) - w ttl = 100", + %% cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> + %% case Recv(Sock) of + %% {ok, {Src, [#{level := ip, + %% type := ttl, + %% data := PktInfo}], ?BASIC_REQ}} -> + %% ?SEV_IPRINT("Got Pkt Info: " + %% "~n ~p", [Info]), + %% ok; + %% {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> + %% ?SEV_EPRINT("Unexpected msg: " + %% "~n Expect Source: ~p" + %% "~n Recv Source: ~p" + %% "~n Expect CHdrs: ~p" + %% "~n Recv CHdrs: ~p" + %% "~n Expect Msg: ~p" + %% "~n Recv Msg: ~p", + %% [Src, BadSrc, + %% [], BadCHdrs, + %% ?BASIC_REQ, BadReq]), + %% {error, {unexpected_data, UnexpData}}; + %% {ok, UnexpData} -> + %% ?SEV_EPRINT("Unexpected msg: " + %% "~n Expect Source: ~p" + %% "~n Expect CHdrs: ~p" + %% "~n Expect Msg: ~p" + %% "~n Unexp Data: ~p", + %% [Src, [], ?BASIC_REQ, UnexpData]), + %% {error, {unexpected_data, UnexpData}}; + %% {error, _} = ERROR -> + %% %% At the moment there is no way to get + %% %% status or state for the socket... + %% ERROR + %% end + %% end}, + + #{desc => "close src socket", + cmd => fun(#{sock_src := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock_src, State)} + end}, + #{desc => "close dst socket", + cmd => fun(#{sock_dst := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock_dst, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + Evaluator = ?SEV_START("tester", Seq, InitState), + ok = ?SEV_AWAIT_FINISH([Evaluator]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests that the options control message header is received when +%% setting the socket 'ip' option recvopts is set to true when using +%% sendmsg/recvmsg on an IPv4 UDP (dgram) socket. +%% So, this is done on the receiving side: +%% +%% socket:setopt(Sock, ip, recvopts, boolean()). +%% +%% For all subsequent *received* messages, the options control message +%% header will be with the message. +%% +%% Note that it *should* be possible to explicitly send options also, +%% but this have not yet been implemented (in socket), so that part +%% we do not test!! +%% +%% +%% +%% +%% This test does not currently work. The recvopts is supposed to +%% result in a IP_OPTIONS control message header but does not! +%% So, exactly how we are suppose to use this option is unknown. +%% So, let the test code remain, but skip until we have figured out +%% how to test this. +%% +%% +%% + +api_opt_ip_recvopts_udp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_opt_ip_recvopts_udp4, + fun() -> + has_support_ipv4(), + has_support_ip_recvopts(), + %% We also use the recvtos and timestamp options + %% in this test, so at least one of them must + %% be supported + has_support_ip_recvtos_and_or_sock_timestamp(), + not_yet_implemented() + + end, + fun() -> + Set = fun(Sock, Value) -> + socket:setopt(Sock, ip, recvopts, Value) + end, + Get = fun(Sock) -> + socket:getopt(Sock, ip, recvopts) + end, Send = fun(Sock, Data, Dest, default) -> Msg = #{addr => Dest, iov => [Data]}, @@ -19060,371 +20537,7 @@ api_opt_ip_pktinfo_udp4(_Config) when is_list(_Config) -> (Sock, Data, Dest, Info) -> %% We do not support this at the moment!!! CMsg = #{level => ip, - type => pktinfo, - data => Info}, - Msg = #{addr => Dest, - ctrl => [CMsg], - iov => [Data]}, - socket:sendmsg(Sock, Msg) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - ctrl := CMsgs, - iov := [Data]}} -> - {ok, {Source, CMsgs, Data}}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet, - proto => udp, - send => Send, - recv => Recv, - set => Set, - get => Get}, - ok = api_opt_ip_pktinfo_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_opt_ip_pktinfo_udp(InitState) -> - Seq = - [ - #{desc => "local address", - cmd => fun(#{domain := local = Domain} = State) -> - LSASrc = which_local_socket_addr(Domain), - LSADst = which_local_socket_addr(Domain), - {ok, State#{lsa_src => LSASrc, - lsa_dst => LSADst}}; - (#{domain := Domain} = State) -> - LSA = which_local_socket_addr(Domain), - {ok, State#{lsa_src => LSA, - lsa_dst => LSA}} - end}, - - #{desc => "open src socket", - cmd => fun(#{domain := Domain, - proto := Proto} = State) -> - Sock = sock_open(Domain, dgram, Proto), - {ok, State#{sock_src => Sock}} - end}, - #{desc => "bind src", - cmd => fun(#{sock_src := Sock, lsa_src := LSA}) -> - case sock_bind(Sock, LSA) of - ok -> - ?SEV_IPRINT("src bound"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("src bind failed: ~p", [Reason]), - ERROR - end - end}, - #{desc => "sockname src socket", - cmd => fun(#{sock_src := Sock} = State) -> - SASrc = sock_sockname(Sock), - ?SEV_IPRINT("src sockaddr: " - "~n ~p", [SASrc]), - {ok, State#{sa_src => SASrc}} - end}, - - #{desc => "open dst socket", - cmd => fun(#{domain := Domain, - proto := Proto} = State) -> - Sock = sock_open(Domain, dgram, Proto), - {ok, State#{sock_dst => Sock}} - end}, - #{desc => "bind dst", - cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) -> - case sock_bind(Sock, LSA) of - ok -> - ?SEV_IPRINT("src bound"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("src bind failed: ~p", [Reason]), - ERROR - end - end}, - #{desc => "sockname dst socket", - cmd => fun(#{sock_dst := Sock} = State) -> - SADst = sock_sockname(Sock), - ?SEV_IPRINT("dst sockaddr: " - "~n ~p", [SADst]), - {ok, State#{sa_dst => SADst}} - end}, - #{desc => "default pktinfo for dst socket", - cmd => fun(#{sock_dst := Sock, get := Get} = _State) -> - case Get(Sock) of - {ok, false = Value} -> - ?SEV_IPRINT("dst recvttl: ~p", [Value]), - ok; - {ok, Unexpected} -> - ?SEV_EPRINT("Unexpected src recvtos: ~p", - [Unexpected]), - {error, {unexpected, Unexpected}}; - {error, Reason} = ERROR -> - ?SEV_EPRINT("Failed getting (default) timestamp:" - " ~p", [Reason]), - ERROR - end - end}, - - #{desc => "send req (to dst) (wo (explicit) pktinfo)", - cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - Send(Sock, ?BASIC_REQ, Dst, default) - end}, - #{desc => "recv req (from src)", - cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> - case Recv(Sock) of - {ok, {Src, [], ?BASIC_REQ}} -> - ok; - {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Recv Source: ~p" - "~n Expect CHdrs: ~p" - "~n Recv CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Recv Msg: ~p", - [Src, BadSrc, - [], BadCHdrs, - ?BASIC_REQ, BadReq]), - {error, {unexpected_data, UnexpData}}; - {ok, UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Expect CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Unexp Data: ~p", - [Src, [], ?BASIC_REQ, UnexpData]), - {error, {unexpected_data, UnexpData}}; - {error, _} = ERROR -> - %% At the moment there is no way to get - %% status or state for the socket... - ERROR - end - end}, - - - %% *** We do not *yet* support sending pktinfo *** - - %% #{desc => "send req (to dst) (w explicit pktinfo)", - %% cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - %% Send(Sock, ?BASIC_REQ, Dst, PktInfo) - %% end}, - %% #{desc => "recv req (from src) - wo pktinfo", - %% cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> - %% case Recv(Sock) of - %% {ok, {Src, [], ?BASIC_REQ}} -> - %% ok; - %% {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> - %% ?SEV_EPRINT("Unexpected msg: " - %% "~n Expect Source: ~p" - %% "~n Recv Source: ~p" - %% "~n Expect CHdrs: ~p" - %% "~n Recv CHdrs: ~p" - %% "~n Expect Msg: ~p" - %% "~n Recv Msg: ~p", - %% [Src, BadSrc, - %% [], BadCHdrs, - %% ?BASIC_REQ, BadReq]), - %% {error, {unexpected_data, UnexpData}}; - %% {ok, UnexpData} -> - %% ?SEV_EPRINT("Unexpected msg: " - %% "~n Expect Source: ~p" - %% "~n Expect CHdrs: ~p" - %% "~n Expect Msg: ~p" - %% "~n Unexp Data: ~p", - %% [Src, [], ?BASIC_REQ, UnexpData]), - %% {error, {unexpected_data, UnexpData}}; - %% {error, _} = ERROR -> - %% %% At the moment there is no way to get - %% %% status or state for the socket... - %% ERROR - %% end - %% end}, - - #{desc => "enable pktinfo on dst socket", - cmd => fun(#{sock_dst := Sock, set := Set} = _State) -> - case Set(Sock, true) of - ok -> - ?SEV_IPRINT("dst pktinfo enabled"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("Failed setting pktinfo:" - " ~p", [Reason]), - ERROR - end - end}, - - #{desc => "send req (to dst) (wo explicit pktinfo)", - cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - Send(Sock, ?BASIC_REQ, Dst, default) - end}, - #{desc => "recv req (from src) - w default pktinfo", - cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> - case Recv(Sock) of - {ok, {Src, [#{level := ip, - type := pktinfo, - value := #{addr := Addr, - ifindex := IfIdx, - spec_dst := SpecDst}}], - ?BASIC_REQ}} -> - ?SEV_IPRINT("Got (default) Pkt Info: " - "~n Addr: ~p" - "~n If Index: ~p" - "~n Spec Dst: ~p", - [Addr, IfIdx, SpecDst]), - ok; - {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Recv Source: ~p" - "~n Expect CHdrs: ~p" - "~n Recv CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Recv Msg: ~p", - [Src, BadSrc, - [], BadCHdrs, - ?BASIC_REQ, BadReq]), - {error, {unexpected_data, UnexpData}}; - {ok, UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Expect CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Unexp Data: ~p", - [Src, [], ?BASIC_REQ, UnexpData]), - {error, {unexpected_data, UnexpData}}; - {error, _} = ERROR -> - %% At the moment there is no way to get - %% status or state for the socket... - ERROR - end - end}, - - - %% *** We do not *yet* support sending pktinfo *** - - %% #{desc => "send req (to dst) (w explicit pktinfo)", - %% cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - %% Send(Sock, ?BASIC_REQ, Dst, PktInfo) - %% end}, - %% #{desc => "recv req (from src) - w ttl = 100", - %% cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> - %% case Recv(Sock) of - %% {ok, {Src, [#{level := ip, - %% type := ttl, - %% data := PktInfo}], ?BASIC_REQ}} -> - %% ?SEV_IPRINT("Got Pkt Info: " - %% "~n ~p", [Info]), - %% ok; - %% {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> - %% ?SEV_EPRINT("Unexpected msg: " - %% "~n Expect Source: ~p" - %% "~n Recv Source: ~p" - %% "~n Expect CHdrs: ~p" - %% "~n Recv CHdrs: ~p" - %% "~n Expect Msg: ~p" - %% "~n Recv Msg: ~p", - %% [Src, BadSrc, - %% [], BadCHdrs, - %% ?BASIC_REQ, BadReq]), - %% {error, {unexpected_data, UnexpData}}; - %% {ok, UnexpData} -> - %% ?SEV_EPRINT("Unexpected msg: " - %% "~n Expect Source: ~p" - %% "~n Expect CHdrs: ~p" - %% "~n Expect Msg: ~p" - %% "~n Unexp Data: ~p", - %% [Src, [], ?BASIC_REQ, UnexpData]), - %% {error, {unexpected_data, UnexpData}}; - %% {error, _} = ERROR -> - %% %% At the moment there is no way to get - %% %% status or state for the socket... - %% ERROR - %% end - %% end}, - - #{desc => "close src socket", - cmd => fun(#{sock_src := Sock} = State) -> - ok = socket:close(Sock), - {ok, maps:remove(sock_src, State)} - end}, - #{desc => "close dst socket", - cmd => fun(#{sock_dst := Sock} = State) -> - ok = socket:close(Sock), - {ok, maps:remove(sock_dst, State)} - end}, - - %% *** We are done *** - ?SEV_FINISH_NORMAL - ], - Evaluator = ?SEV_START("tester", Seq, InitState), - ok = ?SEV_AWAIT_FINISH([Evaluator]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Tests that the options control message header is received when -%% setting the socket 'ip' option recvopts is set to true when using -%% sendmsg/recvmsg on an IPv4 UDP (dgram) socket. -%% So, this is done on the receiving side: -%% -%% socket:setopt(Sock, ip, recvopts, boolean()). -%% -%% For all subsequent *received* messages, the options control message -%% header will be with the message. -%% -%% Note that it *should* be possible to explicitly send options also, -%% but this have not yet been implemented (in socket), so that part -%% we do not test!! -%% -%% -%% -%% -%% This test does not currently work. The recvopts is supposed to -%% result in a IP_OPTIONS control message header but does not! -%% So, exactly how we are suppose to use this option is unknown. -%% So, let the test code remain, but skip until we have figured out -%% how to test this. -%% -%% -%% - -api_opt_ip_recvopts_udp4(suite) -> - []; -api_opt_ip_recvopts_udp4(doc) -> - []; -api_opt_ip_recvopts_udp4(_Config) when is_list(_Config) -> - ?TT(?SECS(5)), - tc_try(api_opt_ip_recvopts_udp4, - fun() -> - has_support_ip_recvopts(), - %% We also use the recvtos and timestamp options - %% in this test, so at least one of them must - %% be supported - has_support_ip_recvtos_and_or_sock_timestamp(), - not_yet_implemented() - - end, - fun() -> - Set = fun(Sock, Value) -> - socket:setopt(Sock, ip, recvopts, Value) - end, - Get = fun(Sock) -> - socket:getopt(Sock, ip, recvopts) - end, - Send = fun(Sock, Data, Dest, default) -> - Msg = #{addr => Dest, - iov => [Data]}, - socket:sendmsg(Sock, Msg); - (Sock, Data, Dest, Info) -> - %% We do not support this at the moment!!! - CMsg = #{level => ip, - type => options, + type => options, data => Info}, Msg = #{addr => Dest, ctrl => [CMsg], @@ -19853,14 +20966,10 @@ api_opt_ip_recvopts_udp(InitState) -> %% %% -api_opt_ip_recvorigdstaddr_udp4(suite) -> - []; -api_opt_ip_recvorigdstaddr_udp4(doc) -> - []; api_opt_ip_recvorigdstaddr_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ip_recvorigdstaddr_udp4, - fun() -> has_support_ip_recvorigdstaddr() end, + fun() -> has_support_ipv4(), has_support_ip_recvorigdstaddr() end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, ip, recvorigdstaddr, Value) @@ -20109,14 +21218,12 @@ api_opt_ip_recvorigdstaddr_udp(InitState) -> %% that method. Instead, set tos (true) on the sending socket. %% -api_opt_ip_recvtos_udp4(suite) -> - []; -api_opt_ip_recvtos_udp4(doc) -> - []; api_opt_ip_recvtos_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ip_recvtos_udp4, fun() -> + is_not_windows(), % IP_TOS on windows + has_support_ipv4(), has_support_ip_recvtos(), has_support_ip_tos() % Used in the test end, @@ -20485,15 +21592,17 @@ api_opt_ip_recvtos_udp(InitState) -> %% Maybe we should send and receive from different VMs, until then %% skip darwin and OpenBSD. %% +%% Windows: +%% It seems like its possible to set and get the recvttl option, +%% but not to use the ttl control message header when sending. +%% The following is the list of types (for level ip) which are listed +%% as supported: IP_ORIGINAL_ARRIVAL_IF, IP_PKTINFO and IP_ECN -api_opt_ip_recvttl_udp4(suite) -> - []; -api_opt_ip_recvttl_udp4(doc) -> - []; api_opt_ip_recvttl_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), - tc_try(api_opt_ip_recvttl_udp4, + tc_try(?FUNCTION_NAME, fun() -> + has_support_ipv4(), has_support_ip_recvttl(), is_not_openbsd(), is_not_darwin() @@ -20507,15 +21616,15 @@ api_opt_ip_recvttl_udp4(_Config) when is_list(_Config) -> end, Send = fun(Sock, Data, Dest, default) -> Msg = #{addr => Dest, - iov => [Data]}, + iov => [Data]}, socket:sendmsg(Sock, Msg); (Sock, Data, Dest, TTL) -> CMsg = #{level => ip, - type => ttl, - value => TTL}, + type => ttl, + value => TTL}, Msg = #{addr => Dest, - ctrl => [CMsg], - iov => [Data]}, + ctrl => [CMsg], + iov => [Data]}, socket:sendmsg(Sock, Msg) end, Recv = fun(Sock) -> @@ -20680,6 +21789,69 @@ api_opt_ip_recvttl_udp(InitState) -> (catch socket:close(SSock)), (catch socket:close(DSock)), {skip, Reason}; + + {error, + {get_overlapped_result, + #{file := File, + function := Function, + line := Line, + raw_info := RawInfo, + info := invalid_parameter = Info}}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TTL: " + "~p => SKIP: " + "~n File: ~s" + "~n Function: ~s" + "~n Line: ~p" + "~n Raw Info: ~p", + [Info, + File, Function, Line, + RawInfo]), + (catch socket:close(SSock)), + (catch socket:close(DSock)), + {skip, + ?F("Cannot send with TTL: ~p", [Info])}; + {error, {get_overlapped_result, + invalid_parameter = Info}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TTL: " + "~p => SKIP", [Info]), + (catch socket:close(SSock)), + (catch socket:close(DSock)), + {skip, + ?F("Cannot send with TTL: ~p", [Info])}; + + {error, + {completion_status, + #{file := File, + function := Function, + line := Line, + raw_info := RawInfo, + info := invalid_parameter = Info}}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TTL: " + "~p => SKIP: " + "~n File: ~s" + "~n Function: ~s" + "~n Line: ~p" + "~n Raw Info: ~p", + [Info, + File, Function, Line, + RawInfo]), + (catch socket:close(SSock)), + (catch socket:close(DSock)), + {skip, + ?F("Cannot send with TTL: ~p", [Info])}; + {error, {completion_status, + invalid_parameter = Info}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TTL: " + "~p => SKIP", [Info]), + (catch socket:close(SSock)), + (catch socket:close(DSock)), + {skip, + ?F("Cannot send with TTL: ~p", [Info])}; + {error, _Reason} = ERROR -> ERROR end @@ -20872,14 +22044,14 @@ api_opt_ip_recvttl_udp(InitState) -> %% Default value is supposed to be '0'. %% -api_opt_ip_tos_udp4(suite) -> - []; -api_opt_ip_tos_udp4(doc) -> - []; api_opt_ip_tos_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), - tc_try(api_opt_ip_tos_udp4, - fun() -> has_support_ip_tos() end, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), % IP_TOS on windows + has_support_ipv4(), + has_support_ip_tos() + end, fun() -> Set = fun(Sock, Value) -> socket:setopt(Sock, ip, tos, Value) @@ -20900,7 +22072,7 @@ api_opt_ip_tos_udp(InitState) -> process_flag(trap_exit, true), %% mincost is not supported on all platforms. %% For instance, Solaris 10, does not have that constant. - %% Instead it has two others with, what appers to be, + %% Instead it has two others with, what appears to be, %% completely different meanings... %% So, avoid the complication by not using this value... %% TOS1 = mincost, TOS1Str = atom_to_list(TOS1), @@ -21118,14 +22290,11 @@ api_opt_ip_tos_udp(InitState) -> %% queue can be read. %% -api_opt_ip_recverr_udp4(suite) -> - []; -api_opt_ip_recverr_udp4(doc) -> - []; api_opt_ip_recverr_udp4(Config) when is_list(Config) -> ?TT(?SECS(5)), tc_try(api_opt_ip_recverr_udp4, fun() -> + has_support_ipv4(), has_support_ip_recverr() end, fun() -> @@ -21157,10 +22326,6 @@ api_opt_ip_recverr_udp4(Config) when is_list(Config) -> %% queue can be read. %% -api_opt_ipv6_recverr_udp6(suite) -> - []; -api_opt_ipv6_recverr_udp6(doc) -> - []; api_opt_ipv6_recverr_udp6(Config) when is_list(Config) -> ?TT(?SECS(5)), tc_try(api_opt_ipv6_recverr_udp6, @@ -21241,16 +22406,33 @@ api_opt_recverr_udp(Config, InitState) -> {select, SelectInfo} when RecvRef =:= nowait -> ?SEV_IPRINT("expected select nowait: " "~n ~p", [SelectInfo]), - {ok, State#{rselect => SelectInfo}}; + {ok, State#{async_tag => select, + rselect => SelectInfo}}; {select, {select_info, _Tag, RecvRef} = SelectInfo} when is_reference(RecvRef) -> ?SEV_IPRINT("expected select ref: " "~n ~p", [SelectInfo]), - {ok, State#{rselect => SelectInfo}}; + {ok, State#{async_tag => select, + rselect => SelectInfo}}; + + {completion, CI} when RecvRef =:= nowait -> + ?SEV_IPRINT("expected completion nowait: " + "~n ~p", [CI]), + {ok, State#{asynch_tag => completion, + rcompletion => CI}}; + {completion, + {completion_info, _Tag, RecvRef} = CI} + when is_reference(RecvRef) -> + ?SEV_IPRINT("expected completion ref: " + "~n ~p", [CI]), + {ok, State#{asynch_tag => completion, + rcompletion => CI}}; + {ok, _} -> - ?SEV_EPRINT("unexpected successs"), + ?SEV_EPRINT("unexpected success"), {error, unexpected_success}; + {error, Reason} = ERROR -> ?SEV_EPRINT("unexpected error: ~p", [Reason]), ERROR @@ -21259,8 +22441,8 @@ api_opt_recverr_udp(Config, InitState) -> #{desc => "try send to nowhere", cmd => fun(#{domain := Domain, - sock := Sock, - send := Send} = State) -> + sock := Sock, + send := Send} = State) -> SendRef = nowait(Config), Dest = #{family => Domain, addr => if @@ -21273,18 +22455,40 @@ api_opt_recverr_udp(Config, InitState) -> case Send(Sock, <<"ping">>, Dest, SendRef) of ok -> ?SEV_IPRINT("sent"), - ok; + {ok, State#{sent => true}}; + {select, SelectInfo} when SendRef =:= nowait -> ?SEV_IPRINT("expected select nowait: ~p", [SelectInfo]), - {ok, State#{sselect => SelectInfo}}; + {ok, State#{sent => false, + asynch_tag => select, + sselect => SelectInfo}}; {select, {select_info, _Tag, SendRef} = SelectInfo} when is_reference(SendRef) -> ?SEV_IPRINT("expected select ref: ~p", [SelectInfo]), - {ok, State#{sselect => SelectInfo}}; + {ok, State#{sent => false, + asynch_tag => select, + sselect => SelectInfo}}; + + {completion, CI} + when SendRef =:= nowait -> + ?SEV_IPRINT("expected completion nowait: ~p", + [CI]), + {ok, State#{sent => false, + asynch_tag => completion, + scompletion => CI}}; + {completion, + {completion_info, _Tag, SendRef} = CI} + when is_reference(SendRef) -> + ?SEV_IPRINT("expected completion ref: ~p", + [CI]), + {ok, State#{sent => false, + asynch_tag => completion, + scompletion => CI}}; + {error, Reason} = ERROR -> ?SEV_EPRINT("unexpected error: ~p", [Reason]), @@ -21292,25 +22496,58 @@ api_opt_recverr_udp(Config, InitState) -> end end}, - #{desc => "await receive select message", - cmd => fun(#{sock := Sock, - rselect := {select_info, _, Ref}} = _State) -> + #{desc => "await receive select|completion message", + cmd => fun(#{sent := false, + asynch_tag := select, + sock := Sock, + rselect := {select_info, _, Ref}} = _State) -> receive {'$socket', Sock, select, Ref} -> - ?SEV_IPRINT("received expected (read) select message: " + ?SEV_IPRINT("received expected (read) " + "select message: " "~n ~p", [Ref]), ok - end + end; + (#{sent := false, + asynch_tag := completion, + sock := Sock, + rcompletion := {completion_info, _, Ref}} = _State) -> + receive + {'$socket', Sock, completion, + {Ref, {error, econnrefused = Reason}}} -> + ?SEV_IPRINT("expected failure: ~p", + [Reason]), + ok; + + {'$socket', Sock, completion, + {Ref, {ok, _}}} -> + ?SEV_EPRINT("unexpected success"), + {error, unexpected_success}; + {'$socket', Sock, completion, + {Ref, {error, Reason} = ERROR}} -> + ?SEV_IPRINT("unexpected failure: ~p", + [Reason]), + ERROR + + end; + (#{sent := true} = _State) -> + ?SEV_IPRINT("no action needed"), + ok end}, #{desc => "try recv - expect econnrefused", - cmd => fun(#{sock := Sock, recv := Recv} = _State) -> + cmd => fun(#{asynch_tag := completion} = _State) -> + ?SEV_IPRINT("already processed"), + ok; + (#{sock := Sock, + recv := Recv} = _State) -> case Recv(Sock, infinity) of {error, econnrefused = Reason} -> - ?SEV_IPRINT("expected failure: ~p", [Reason]), + ?SEV_IPRINT("expected failure: ~p", + [Reason]), ok; {ok, _} -> - ?SEV_EPRINT("unexpected successs"), + ?SEV_EPRINT("unexpected success"), {error, unexpected_success}; {select, SelectInfo} -> ?SEV_EPRINT("unexpected select: ~p", @@ -21345,10 +22582,17 @@ api_opt_recverr_udp(Config, InitState) -> {ok, {Addr, <<"ring">>}} -> ?SEV_IPRINT("receive expected"), ok; + {select, SelectInfo} -> ?SEV_EPRINT("unexpected select: ~p", [SelectInfo]), {error, unexpected_success}; + + {completion, CompletionInfo} -> + ?SEV_EPRINT("unexpected completion: ~p", + [CompletionInfo]), + {error, unexpected_success}; + {error, Reason} = ERROR -> ?SEV_EPRINT("unexpected error: ~p", [Reason]), @@ -21357,7 +22601,7 @@ api_opt_recverr_udp(Config, InitState) -> end}, #{desc => "try recv error queue", - cmd => fun(#{domain := Domain, sock := Sock}) -> + cmd => fun(#{domain := Domain, sock := Sock} = State) -> %% Note that not all platforms that support %% recverr, actually supports "encoding" the data %% part, so we need to adjust for that. @@ -21388,7 +22632,7 @@ api_opt_recverr_udp(Config, InitState) -> }]} = Msg} -> ?SEV_IPRINT("expected error queue (decoded): " "~n ~p", [Msg]), - ok; + {ok, State#{asynch_tag => none}}; {ok, #{addr := #{family := Domain, addr := _Addr}, flags := [errqueue], @@ -21396,7 +22640,30 @@ api_opt_recverr_udp(Config, InitState) -> value := [#{level := Level, type := recverr}]} = _Msg} -> ?SEV_IPRINT("expected error queue"), - ok; + {ok, State#{asynch_tag => none}}; + + {completion, CI} -> + ?SEV_IPRINT("completion: " + "~n ~p", [CI]), + {ok, State#{asynch_tag => completion, + completion => CI}}; + + {error, timeout = Reason} = ERROR -> + case os:type() of + {win32, nt} -> + ?SEV_IPRINT("failed reading " + "error queue: " + "~n ~p", [Reason]), + {skip, + "Test case does not " + "work on Windows"}; + _ -> + ?SEV_EPRINT("failed reading " + "error queue: " + "~n ~p", [Reason]), + ERROR + end; + {error, Reason} = ERROR -> ?SEV_EPRINT("failed reading error queue: " "~n ~p", [Reason]), @@ -21404,6 +22671,29 @@ api_opt_recverr_udp(Config, InitState) -> end end}, + #{desc => "await receive select message", + cmd => fun(#{asynch_tag := completion, + sock := Sock, + completion := {completion_info, _, Ref}} = _State) -> + receive + {'$socket', Sock, completion, + {Ref, {ok, Info}}} -> + ?SEV_EPRINT("expected success: " + "~n ~p", [Info]), + ok; + + {'$socket', Sock, completion, + {Ref, {error, Reason} = ERROR}} -> + ?SEV_IPRINT("unexpected failure: ~p", + [Reason]), + ERROR + + end; + (#{asynch_tag := none} = _State) -> + ?SEV_IPRINT("no action needed"), + ok + end}, + #{desc => "close socket", cmd => fun(#{sock := Sock} = State) -> ok = socket:close(Sock), @@ -21448,19 +22738,22 @@ api_opt_recverr_udp(Config, InitState) -> %% the test (since its a IPv4 test case). %% -api_opt_ip_mopts_udp4(suite) -> - []; -api_opt_ip_mopts_udp4(doc) -> - []; api_opt_ip_mopts_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), - tc_try(api_opt_ip_mopts_udp4, + tc_try(?FUNCTION_NAME, fun() -> - case is_any_options_supported( - [{ip, pktinfo}, - {ip, recvorigdstaddr}, - {ip, recvtos}, - {ip, recvttl}]) of + has_support_ipv4(), + Opts = + [{ip, pktinfo}, + {ip, recvorigdstaddr}] ++ + case os:type() of + {win32, nt} -> + []; + _ -> + [{ip, recvtos}, + {ip, recvttl}] + end, + case is_any_options_supported(Opts) of true -> ok; false -> @@ -21496,42 +22789,49 @@ api_opt_ip_mopts_udp4(_Config) when is_list(_Config) -> false -> [] end ++ - case socket:is_supported(options, ip, recvtos) of - true -> - %% It seems that sending any of the - %% TOS or TTL values will fail on: - %% FreeBSD - %% Linux when - %% version =< 3.12.60 (at least) - %% Don't know when this starts working, - %% but it works on: - %% Ubunto 16.04.6 => 4.15.0-65 - %% SLES 12 SP2 => 4.4.120-92.70 - %% so don't! - %% - %% The latest we know it not to work was a - %% SLES 12 (plain) at 3.12.50-52.54 - %% - [{ip, recvtos, tos, - case os:type() of - {unix, freebsd} -> - default; - {unix, linux} -> - case os:version() of - Vsn when Vsn > {3,12,60} -> - 42; - _ -> - default - end; - _ -> - 42 - end}]; - false -> - [] + case os:type() of + {win32, nt} -> + []; + _ -> + case socket:is_supported(options, ip, recvtos) of + true -> + %% It seems that sending any of the + %% TOS or TTL values will fail on: + %% FreeBSD + %% Linux when + %% version =< 3.12.60 (at least) + %% Don't know when this starts + %% working, but it works on: + %% Ubunto 16.04.6 => 4.15.0-65 + %% SLES 12 SP2 => 4.4.120-92.70 + %% so don't! + %% + %% The latest we know it not to work + %% was a SLES 12 (plain) at 3.12.50-52.54 + %% + [{ip, recvtos, tos, + case os:type() of + {unix, freebsd} -> + default; + {unix, linux} -> + case os:version() of + Vsn when Vsn > {3,12,60} -> + 42; + _ -> + default + end; + _ -> + 42 + end}]; + false -> + [] + end end ++ case os:type() of {unix, darwin} -> []; + {win32, nt} -> + []; _ -> case socket:is_supported(options, ip, recvttl) of true -> @@ -21566,21 +22866,22 @@ api_opt_ip_mopts_udp4(_Config) when is_list(_Config) -> end, Enable = fun(Sock, Level, Opt) -> - ?SEV_IPRINT("try enable [~w] ~p", [Level, Opt]), + ?SEV_IPRINT("try enable [~w] ~p", + [Level, Opt]), socket:setopt(Sock, Level, Opt, true) end, Send = fun(Sock, Data, Dest, []) -> Msg = #{addr => Dest, - iov => [Data]}, + iov => [Data]}, socket:sendmsg(Sock, Msg); (Sock, Data, Dest, Hdrs) when is_list(Hdrs) -> CMsgs = [#{level => Level, - type => Type, - value => Val} || - {Level, Type, Val} <- Hdrs], + type => Type, + value => Val} || + {Level, Type, Val} <- Hdrs], Msg = #{addr => Dest, - ctrl => CMsgs, - iov => [Data]}, + ctrl => CMsgs, + iov => [Data]}, socket:sendmsg(Sock, Msg) end, Recv = fun(Sock) -> @@ -21789,10 +23090,6 @@ api_opt_ip_mopts_udp(InitState) -> %% although we only test this with dgram. %% -api_opt_ipv6_recvpktinfo_udp6(suite) -> - []; -api_opt_ipv6_recvpktinfo_udp6(doc) -> - []; api_opt_ipv6_recvpktinfo_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ipv6_recvpktinfo_udp6, @@ -22052,14 +23349,10 @@ api_opt_ipv6_recvpktinfo_udp(InitState) -> %% There seem to be some weirdness with the definition of this %% option, so its defined in an include file we don't include %% (directly or indirectly). And since some of the defines -%% are occure in a file we *do* include (via netinet/in.h), we +%% occur in a file we *do* include (via netinet/in.h), we %% leave it as is for now... %% -api_opt_ipv6_flowinfo_udp6(suite) -> - []; -api_opt_ipv6_flowinfo_udp6(doc) -> - []; api_opt_ipv6_flowinfo_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ipv6_flowinfo_udp6, @@ -22315,10 +23608,6 @@ api_opt_ipv6_flowinfo_udp(InitState) -> %% %% -api_opt_ipv6_hoplimit_udp6(suite) -> - []; -api_opt_ipv6_hoplimit_udp6(doc) -> - []; api_opt_ipv6_hoplimit_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ipv6_hoplimit_udp6, @@ -22606,10 +23895,6 @@ api_opt_ipv6_hoplimit_udp(InitState) -> %% %% -api_opt_ipv6_tclass_udp6(suite) -> - []; -api_opt_ipv6_tclass_udp6(doc) -> - []; api_opt_ipv6_tclass_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_ipv6_tclass_udp6, @@ -22860,7 +24145,68 @@ api_opt_ipv6_tclass_udp(InitState) -> #{desc => "send req (to dst) (w explicit tc = 1)", cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - Send(Sock, ?BASIC_REQ, Dst, 1) + case Send(Sock, ?BASIC_REQ, Dst, 1) of + {error, + {get_overlapped_result, + #{file := File, + function := Function, + line := Line, + raw_info := RawInfo, + info := invalid_parameter = Info}}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TClass: " + "~p => SKIP: " + "~n File: ~s" + "~n Function: ~s" + "~n Line: ~p" + "~n Raw Info: ~p", + [Info, + File, Function, Line, + RawInfo]), + (catch socket:close(Sock)), + {skip, + ?F("Cannot send with TClass: ~p", [Info])}; + {error, {get_overlapped_result, + invalid_parameter = Info}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TClass: " + "~p => SKIP", [Info]), + (catch socket:close(Sock)), + {skip, + ?F("Cannot send with TClass: ~p", [Info])}; + + {error, + {completion_status, + #{file := File, + function := Function, + line := Line, + raw_info := RawInfo, + info := invalid_parameter = Info}}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TClass: " + "~p => SKIP: " + "~n File: ~s" + "~n Function: ~s" + "~n Line: ~p" + "~n Raw Info: ~p", + [Info, + File, Function, Line, + RawInfo]), + (catch socket:close(Sock)), + {skip, + ?F("Cannot send with TClass: ~p", [Info])}; + {error, {completion_status, + invalid_parameter = Info}} -> + %% IF we can't send it the test will not work + ?SEV_EPRINT("Cannot send TClass: " + "~p => SKIP", [Info]), + (catch socket:close(Sock)), + {skip, + ?F("Cannot send with TClass: ~p", [Info])}; + + Other -> + Other + end end}, #{desc => "recv req (from src)", cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> @@ -22907,321 +24253,332 @@ api_opt_ipv6_tclass_udp(InitState) -> value => "something"}, ?BASIC_REQ, UnexpData]), {error, {unexpected_data, UnexpData}}; - {error, _} = ERROR -> - %% At the moment there is no way to get - %% status or state for the socket... - ERROR - end - end}, - - #{desc => "close src socket", - cmd => fun(#{sock_src := Sock} = State) -> - ok = socket:close(Sock), - {ok, maps:remove(sock_src, State)} - end}, - #{desc => "close dst socket", - cmd => fun(#{sock_dst := Sock} = State) -> - ok = socket:close(Sock), - {ok, maps:remove(sock_dst, State)} - end}, - - %% *** We are done *** - ?SEV_FINISH_NORMAL - ], - Evaluator = ?SEV_START("tester", Seq, InitState), - ok = ?SEV_AWAIT_FINISH([Evaluator]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This intended to test "all" of the (currently) supported IPv6 -%% options that results in control message header(s). -%% So, this is done on the receiving side: -%% -%% socket:setopt(Sock, ipv6, Flag, boolean()). -%% -%% For all subsequent *received* messages, a control message header -%% for each of the enabled options will be received with the message. -%% -%% Only allowed for dgram and raw, -%% although we only test this with dgram. -%% -%% Currently we *try* to use the following opts: -%% -%% recvpktinfo | pktinfo => pktinfo -%% flowinfo => flowinfo -%% recvhoplimit | hoplimit => hoplimit -%% recvtclass | tclass => tclass -%% -%% -%% Every time we add a test case for a new option (that results in -%% a control message hedare), we should also add it here. -%% -%% Even though this is a IPv6 test case, we add the 'socket' timestamp -%% option (just to fill up), but in the test to see if we should run -%% the test (since its a IPv6 test case). -%% - -api_opt_ipv6_mopts_udp6(suite) -> - []; -api_opt_ipv6_mopts_udp6(doc) -> - []; -api_opt_ipv6_mopts_udp6(_Config) when is_list(_Config) -> - ?TT(?SECS(5)), - tc_try(api_opt_ipv6_mopts_udp6, - fun() -> - has_support_ipv6(), - case is_any_options_supported( - [{ipv6, recvpktinfo}, - {ipv6, flowinfo}, - {ipv6, recvhoplimit}, - {ipv6, hoplimit}, - {ipv6, recvtclass}, - {ipv6, tclass}]) of - true -> - ok; - false -> - skip("None of the needed options are supported") - end, - %% The problem here is hoplimit on darwin 9.8.0, - %% but I can't be bothered to adjust the test case, - %% just skip on that machine (there is only one)... - is_good_enough_darwin({9,8,0}), - is_good_enough_montavista("4.0.1") - end, - fun() -> - %% If we get this far, we *know* that at least one of the - %% options are available. - - %% This is list of all the options and there resulting - %% control message header type(s): - %% [{'ipv6 socket option', 'control message header type'}] - Opts = - case socket:is_supported(options, socket, timestamp) of - true -> - [{socket, timestamp, timestamp, default}]; - false -> - [] - end ++ - case socket:is_supported(options, ipv6, recvpktinfo) of - true -> - [{ipv6, recvpktinfo, pktinfo, default}]; - false -> - [] - end ++ - case socket:is_supported(options, ipv6, flowinfo) of - true -> - [{ipv6, flowinfo, flowinfo, default}]; - false -> - [] - end ++ - case socket:is_supported(options, ipv6, recvhoplimit) of - true -> - [{ipv6, recvhoplimit, hoplimit, default}]; - false -> - case socket:is_supported(options, ipv6, hoplimit) of - true -> - [{ipv6, hoplimit, hoplimit, default}]; - false -> - [] - end - end ++ - case socket:is_supported(options, ipv6, recvtclass) of - true -> - [{ipv6, recvtclass, tclass, 42}]; - false -> - case socket:is_supported(options, ipv6, tclass) of - true -> - [{ipv6, tclass, tclass, 42}]; - false -> - [] - end - end, - - Enable = fun(Sock, Level, Opt) -> - ?SEV_IPRINT("try enable [~w] ~p", [Level, Opt]), - socket:setopt(Sock, Level, Opt, true) - end, - Send = fun(Sock, Data, Dest, []) -> - Msg = #{addr => Dest, - iov => [Data]}, - socket:sendmsg(Sock, Msg); - (Sock, Data, Dest, Hdrs) when is_list(Hdrs) -> - CMsgs = [#{level => Level, - type => Type, - data => Val} || - {Level, Type, Val} <- Hdrs], - Msg = #{addr => Dest, - ctrl => CMsgs, - iov => [Data]}, - socket:sendmsg(Sock, Msg) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - ctrl := CMsgs, - iov := [Data]}} -> - {ok, {Source, CMsgs, Data}}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet6, - proto => udp, - opts => Opts, - send => Send, - recv => Recv, - enable => Enable}, - ok = api_opt_ipv6_mopts_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_opt_ipv6_mopts_udp(InitState) -> - Seq = - [ - #{desc => "local address", - cmd => fun(#{domain := Domain} = State) -> - LSA = which_local_socket_addr(Domain), - {ok, State#{lsa_src => LSA, - lsa_dst => LSA}} - end}, - - #{desc => "open src socket", - cmd => fun(#{domain := Domain, - proto := Proto} = State) -> - Sock = sock_open(Domain, dgram, Proto), - {ok, State#{sock_src => Sock}} - end}, - #{desc => "bind src", - cmd => fun(#{sock_src := Sock, lsa_src := LSA}) -> - case sock_bind(Sock, LSA) of - ok -> - ?SEV_IPRINT("src bound"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("src bind failed: ~p", [Reason]), - ERROR - end - end}, - #{desc => "sockname src socket", - cmd => fun(#{sock_src := Sock} = State) -> - SASrc = sock_sockname(Sock), - ?SEV_IPRINT("src sockaddr: " - "~n ~p", [SASrc]), - {ok, State#{sa_src => SASrc}} - end}, - - #{desc => "open dst socket", - cmd => fun(#{domain := Domain, - proto := Proto} = State) -> - Sock = sock_open(Domain, dgram, Proto), - {ok, State#{sock_dst => Sock}} - end}, - #{desc => "bind dst", - cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) -> - case sock_bind(Sock, LSA) of - ok -> - ?SEV_IPRINT("src bound"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("src bind failed: ~p", [Reason]), - ERROR - end - end}, - #{desc => "sockname dst socket", - cmd => fun(#{sock_dst := Sock} = State) -> - SADst = sock_sockname(Sock), - ?SEV_IPRINT("dst sockaddr: " - "~n ~p", [SADst]), - {ok, State#{sa_dst => SADst}} - end}, - #{desc => "enable options on dst socket", - cmd => fun(#{sock_dst := DSock, - sock_src := SSock, - opts := Opts, - enable := Enable} = _State) -> - %% If we fail to enable *any* of the options, - %% we give up. - E = fun({Level, Opt, _, _}) -> - case Enable(DSock, Level, Opt) of - ok -> - ?SEV_IPRINT("dst [~w] ~w enabled", - [Level, Opt]), - ok; - {error, enoprotoopt = Reason} -> - ?SEV_EPRINT("Expected " - "Failure: " - "~p => SKIP", - [Reason]), - (catch socket:close(DSock)), - (catch socket:close(SSock)), - {skip, Reason}; - {error, Reason} = ERROR -> - ?SEV_EPRINT("Failed " - "setting ~w:" - " ~p", - [Opt, Reason]), - throw(ERROR) - end - end, - lists:foreach(E, Opts), - ok - end}, - - #{desc => "send req (to dst)", - cmd => fun(#{sock_src := Sock, - sa_dst := Dst, - opts := Opts, - send := Send}) -> - Hdrs = [{Level, Type, Data} || - {Level, _, Type, Data} <- - Opts, (Data =/= default)], - Send(Sock, ?BASIC_REQ, Dst, Hdrs) - end}, - #{desc => "recv req (from src)", - cmd => fun(#{sock_dst := Sock, - sa_src := Src, - recv := Recv, - opts := Opts}) -> - case Recv(Sock) of - {ok, {Src, CMsgs, ?BASIC_REQ}} - when length(CMsgs) =:= length(Opts) -> - ?SEV_IPRINT("Got (expected) cmsg headers: " - "~n ~p", [CMsgs]), - %% We should really verify the headers: - %% values, types and so on... - ok; - {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Recv Source: ~p" - "~n Expect CHdrs: ~p" - "~n Recv CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Recv Msg: ~p", - [Src, BadSrc, - [{Level, Type} || - {Level, _, Type, _} <- Opts], - BadCHdrs, - ?BASIC_REQ, BadReq]), - {error, {unexpected_data, UnexpData}}; - {ok, UnexpData} -> - ?SEV_EPRINT("Unexpected msg: " - "~n Expect Source: ~p" - "~n Expect CHdrs: ~p" - "~n Expect Msg: ~p" - "~n Unexp Data: ~p", - [Src, - [{Level, Type} || - {Level, _, Type, _} <- Opts], - ?BASIC_REQ, - UnexpData]), - {error, {unexpected_data, UnexpData}}; - {error, _} = ERROR -> + {error, _} = ERROR -> + %% At the moment there is no way to get + %% status or state for the socket... + ERROR + end + end}, + + #{desc => "close src socket", + cmd => fun(#{sock_src := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock_src, State)} + end}, + #{desc => "close dst socket", + cmd => fun(#{sock_dst := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock_dst, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + Evaluator = ?SEV_START("tester", Seq, InitState), + ok = ?SEV_AWAIT_FINISH([Evaluator]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This intended to test "all" of the (currently) supported IPv6 +%% options that results in control message header(s). +%% So, this is done on the receiving side: +%% +%% socket:setopt(Sock, ipv6, Flag, boolean()). +%% +%% For all subsequent *received* messages, a control message header +%% for each of the enabled options will be received with the message. +%% +%% Only allowed for dgram and raw, +%% although we only test this with dgram. +%% +%% Currently we *try* to use the following opts: +%% +%% recvpktinfo | pktinfo => pktinfo +%% flowinfo => flowinfo +%% recvhoplimit | hoplimit => hoplimit +%% recvtclass | tclass => tclass +%% +%% +%% Every time we add a test case for a new option (that results in +%% a control message hedare), we should also add it here. +%% +%% Even though this is a IPv6 test case, we add the 'socket' timestamp +%% option (just to fill up), but in the test to see if we should run +%% the test (since its a IPv6 test case). +%% + +api_opt_ipv6_mopts_udp6(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_opt_ipv6_mopts_udp6, + fun() -> + has_support_ipv6(), + Opts = + [{ipv6, recvpktinfo}, + {ipv6, flowinfo}, + {ipv6, recvhoplimit}, + {ipv6, hoplimit}] ++ + case os:type() of + {win32, nt} -> + []; + _ -> + [{ipv6, recvtclass}, + {ipv6, tclass}] + end, + case is_any_options_supported(Opts) of + true -> + ok; + false -> + skip("None of the needed options are supported") + end, + %% The problem here is hoplimit on darwin 9.8.0, + %% but I can't be bothered to adjust the test case, + %% just skip on that machine (there is only one)... + is_good_enough_darwin({9,8,0}), + is_good_enough_montavista("4.0.1") + end, + fun() -> + %% If we get this far, we *know* that at least one of the + %% options are available. + + %% This is list of all the options and there resulting + %% control message header type(s): + %% [{'ipv6 socket option', 'control message header type'}] + Opts = + case socket:is_supported(options, socket, timestamp) of + true -> + [{socket, timestamp, timestamp, default}]; + false -> + [] + end ++ + case socket:is_supported(options, ipv6, recvpktinfo) of + true -> + [{ipv6, recvpktinfo, pktinfo, default}]; + false -> + [] + end ++ + case socket:is_supported(options, ipv6, flowinfo) of + true -> + [{ipv6, flowinfo, flowinfo, default}]; + false -> + [] + end ++ + case socket:is_supported(options, ipv6, recvhoplimit) of + true -> + [{ipv6, recvhoplimit, hoplimit, default}]; + false -> + case socket:is_supported(options, ipv6, hoplimit) of + true -> + [{ipv6, hoplimit, hoplimit, default}]; + false -> + [] + end + end ++ + case os:type() of + {win32, nt} -> + []; + _ -> + case socket:is_supported(options, + ipv6, recvtclass) of + true -> + [{ipv6, recvtclass, tclass, 42}]; + false -> + case socket:is_supported(options, + ipv6, tclass) of + true -> + [{ipv6, tclass, tclass, 42}]; + false -> + [] + end + end + end, + + Enable = fun(Sock, Level, Opt) -> + ?SEV_IPRINT("try enable [~w] ~p", + [Level, Opt]), + socket:setopt(Sock, Level, Opt, true) + end, + Send = fun(Sock, Data, Dest, []) -> + Msg = #{addr => Dest, + iov => [Data]}, + socket:sendmsg(Sock, Msg); + (Sock, Data, Dest, Hdrs) when is_list(Hdrs) -> + CMsgs = [#{level => Level, + type => Type, + data => Val} || + {Level, Type, Val} <- Hdrs], + Msg = #{addr => Dest, + ctrl => CMsgs, + iov => [Data]}, + socket:sendmsg(Sock, Msg) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + ctrl := CMsgs, + iov := [Data]}} -> + {ok, {Source, CMsgs, Data}}; + {error, _} = ERROR -> + ERROR + end + end, + InitState = #{domain => inet6, + proto => udp, + opts => Opts, + send => Send, + recv => Recv, + enable => Enable}, + ok = api_opt_ipv6_mopts_udp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_ipv6_mopts_udp(InitState) -> + Seq = + [ + #{desc => "local address", + cmd => fun(#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa_src => LSA, + lsa_dst => LSA}} + end}, + + #{desc => "open src socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + Sock = sock_open(Domain, dgram, Proto), + {ok, State#{sock_src => Sock}} + end}, + #{desc => "bind src", + cmd => fun(#{sock_src := Sock, lsa_src := LSA}) -> + case sock_bind(Sock, LSA) of + ok -> + ?SEV_IPRINT("src bound"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("src bind failed: ~p", [Reason]), + ERROR + end + end}, + #{desc => "sockname src socket", + cmd => fun(#{sock_src := Sock} = State) -> + SASrc = sock_sockname(Sock), + ?SEV_IPRINT("src sockaddr: " + "~n ~p", [SASrc]), + {ok, State#{sa_src => SASrc}} + end}, + + #{desc => "open dst socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + Sock = sock_open(Domain, dgram, Proto), + {ok, State#{sock_dst => Sock}} + end}, + #{desc => "bind dst", + cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) -> + case sock_bind(Sock, LSA) of + ok -> + ?SEV_IPRINT("src bound"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("src bind failed: ~p", [Reason]), + ERROR + end + end}, + #{desc => "sockname dst socket", + cmd => fun(#{sock_dst := Sock} = State) -> + SADst = sock_sockname(Sock), + ?SEV_IPRINT("dst sockaddr: " + "~n ~p", [SADst]), + {ok, State#{sa_dst => SADst}} + end}, + + #{desc => "enable options on dst socket", + cmd => fun(#{sock_dst := DSock, + sock_src := SSock, + opts := Opts, + enable := Enable} = _State) -> + %% If we fail to enable *any* of the options, + %% we give up. + E = fun({Level, Opt, _, _}) -> + case Enable(DSock, Level, Opt) of + ok -> + ?SEV_IPRINT("dst [~w] ~w enabled", + [Level, Opt]), + ok; + {error, enoprotoopt = Reason} -> + ?SEV_EPRINT("Expected " + "Failure: " + "~p => SKIP", + [Reason]), + (catch socket:close(DSock)), + (catch socket:close(SSock)), + {skip, Reason}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("Failed " + "setting ~w:" + " ~p", + [Opt, Reason]), + throw(ERROR) + end + end, + lists:foreach(E, Opts), + ok + end}, + + #{desc => "send req (to dst)", + cmd => fun(#{sock_src := Sock, + sa_dst := Dst, + opts := Opts, + send := Send}) -> + Hdrs = [{Level, Type, Data} || + {Level, _, Type, Data} <- + Opts, (Data =/= default)], + Send(Sock, ?BASIC_REQ, Dst, Hdrs) + end}, + #{desc => "recv req (from src)", + cmd => fun(#{sock_dst := Sock, + sa_src := Src, + recv := Recv, + opts := Opts}) -> + case Recv(Sock) of + {ok, {Src, CMsgs, ?BASIC_REQ}} + when length(CMsgs) =:= length(Opts) -> + ?SEV_IPRINT("Got (expected) cmsg headers: " + "~n ~p", [CMsgs]), + %% We should really verify the headers: + %% values, types and so on... + ok; + {ok, {BadSrc, BadCHdrs, BadReq} = UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Recv Source: ~p" + "~n Expect CHdrs: ~p" + "~n Recv CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Recv Msg: ~p", + [Src, BadSrc, + [{Level, Type} || + {Level, _, Type, _} <- Opts], + BadCHdrs, + ?BASIC_REQ, BadReq]), + {error, {unexpected_data, UnexpData}}; + {ok, UnexpData} -> + ?SEV_EPRINT("Unexpected msg: " + "~n Expect Source: ~p" + "~n Expect CHdrs: ~p" + "~n Expect Msg: ~p" + "~n Unexp Data: ~p", + [Src, + [{Level, Type} || + {Level, _, Type, _} <- Opts], + ?BASIC_REQ, + UnexpData]), + {error, {unexpected_data, UnexpData}}; + {error, _} = ERROR -> %% At the moment there is no way to get %% status or state for the socket... ERROR @@ -23254,18 +24611,14 @@ api_opt_ipv6_mopts_udp(InitState) -> %% According to the man page (on linux) for this option it *should* be %% possible to both get and set *allowed* algorithms. But when we attempt %% to set, we get 'enoent'. -%% Accoring to /proc/sys/net/ipv4/tcp_allowed_congestion_control that +%% According to /proc/sys/net/ipv4/tcp_allowed_congestion_control that %% allgorithm was allowed, so... %% For now, we only test that we can get (it could be a bug in our code) -api_opt_tcp_congestion_tcp4(suite) -> - []; -api_opt_tcp_congestion_tcp4(doc) -> - []; api_opt_tcp_congestion_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_tcp_congestion_tcp4, - fun() -> has_support_tcp_congestion() end, + fun() -> has_support_ipv4(), has_support_tcp_congestion() end, fun() -> Set = fun(Sock, Value) when is_list(Value) -> socket:setopt(Sock, tcp, congestion, Value) @@ -23449,14 +24802,10 @@ api_opt_tcp_congestion_tcp(InitState) -> %% Reading the man page it seems like (on linux) that the %% value resets itself after some (short) time... -api_opt_tcp_cork_tcp4(suite) -> - []; -api_opt_tcp_cork_tcp4(doc) -> - []; api_opt_tcp_cork_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_tcp_cork_tcp4, - fun() -> has_support_tcp_cork() end, + fun() -> has_support_ipv4(), has_support_tcp_cork() end, fun() -> Set = fun(Sock, Value) when is_boolean(Value) -> socket:setopt(Sock, tcp, cork, Value) @@ -23568,17 +24917,16 @@ api_opt_tcp_cork_tcp(InitState) -> %% %% Note that there is no point in reading this value back, %% since the kernel imposes its own rules with regard -%% to what is an acceptible value. +%% to what is an acceptable value. %% -api_opt_tcp_maxseg_tcp4(suite) -> - []; -api_opt_tcp_maxseg_tcp4(doc) -> - []; api_opt_tcp_maxseg_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), - tc_try(api_opt_tcp_maxseg_tcp4, - fun() -> has_support_tcp_maxseg() end, + tc_try(?FUNCTION_NAME, + fun() -> + has_support_ipv4(), + has_support_tcp_maxseg() + end, fun() -> Set = fun(Sock, Value) when is_integer(Value) -> socket:setopt(Sock, tcp, maxseg, Value) @@ -23631,49 +24979,886 @@ api_opt_tcp_maxseg_tcp(InitState) -> %% The actual test - #{desc => "get (default) maxseg", + #{desc => "get (default) maxseg", + cmd => fun(#{sock := Sock, get := Get} = State) -> + case Get(Sock) of + {ok, DefMaxSeg} -> + ?SEV_IPRINT("maxseg default: ~p", [DefMaxSeg]), + {ok, State#{def_maxseg => DefMaxSeg}}; + {error, enoprotoopt = Reason} -> + {skip, Reason}; + {error, _} = ERROR -> + ERROR + end + end}, + + %% Note that there is no point in reading this value back, + %% since the kernel imposes its own rules with regard + %% to what is an acceptable value. + %% So, even if the set operation is a success, the value + %% still might not have changed. + %% + %% Note that not all platforms allow this to be set! + %% Since this is the *last* operation in the test sequence + %% (before termination) we also accept error reason = einval + %% as success (rather then skip). + %% The same goes for the error reason = enoprotoopt (Solaris). + #{desc => "(maybe) change maxseg (default + 16)", + cmd => fun(#{sock := Sock, + set := Set, + def_maxseg := DefMaxSeg} = _State) -> + NewMaxSeg = DefMaxSeg + 16, + case Set(Sock, NewMaxSeg) of + ok -> + ?SEV_IPRINT("maxseg (maybe) changed (to ~w)", + [NewMaxSeg]), + ok; + {error, Reason} when (Reason =:= einval) orelse + (Reason =:= enoprotoopt) -> + ?SEV_IPRINT("change not allowed (~w)", + [Reason]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** Termination *** + #{desc => "close connection socket", + cmd => fun(#{sock := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + i("start tester evaluator"), + Tester = ?SEV_START("tester", TesterSeq, InitState), + + ok = ?SEV_AWAIT_FINISH([Tester]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests that the nodelay tcp socket option. +%% +%% This is a very simple test. We simple set and get the value. +%% To test that it has an effect is just "to much work"... + +api_opt_tcp_nodelay_tcp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(api_opt_tcp_nodelay_tcp4, + fun() -> has_support_ipv4(), has_support_tcp_nodelay() end, + fun() -> + Set = fun(Sock, Value) when is_boolean(Value) -> + socket:setopt(Sock, tcp, nodelay, Value) + end, + Get = fun(Sock) -> + socket:getopt(Sock, tcp, nodelay) + end, + InitState = #{domain => inet, + proto => tcp, + set => Set, + get => Get}, + ok = api_opt_tcp_nodelay_tcp(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_tcp_nodelay_tcp(InitState) -> + process_flag(trap_exit, true), + TesterSeq = + [ + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + case socket:open(Domain, stream, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> + case sock_bind(Sock, LSA) of + ok -> + Port = sock_port(Sock), + ?SEV_IPRINT("bound to port: ~w", [Port]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + + + %% The actual test + #{desc => "get (default) nodelay (= false)", + cmd => fun(#{sock := Sock, get := Get} = _State) -> + case Get(Sock) of + {ok, false = Value} -> + ?SEV_IPRINT("nodelay default: ~p", [Value]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "enable nodelay (=> true)", + cmd => fun(#{sock := Sock, set := Set} = _State) -> + case Set(Sock, true) of + ok -> + ?SEV_IPRINT("nodelay enabled"), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get nodelay (= true)", + cmd => fun(#{sock := Sock, get := Get} = _State) -> + case Get(Sock) of + {ok, true = Value} -> + ?SEV_IPRINT("nodelay: ~p", [Value]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + + + %% *** Termination *** + #{desc => "close socket", + cmd => fun(#{sock := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + i("start tester evaluator"), + Tester = ?SEV_START("tester", TesterSeq, InitState), + + ok = ?SEV_AWAIT_FINISH([Tester]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests that the keepcnt tcp socket option. +%% +%% "The maximum number of keepalive probes TCP should send before +%% dropping the connection" +%% + +api_opt_tcp_keepcnt_tcp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4(), has_support_tcp_keepcnt() end, + fun() -> + Set = fun(Sock, Value) when is_integer(Value) -> + socket:setopt(Sock, tcp, keepcnt, Value) + end, + Get = fun(Sock) -> + socket:getopt(Sock, tcp, keepcnt) + end, + InitState = #{domain => inet, + proto => tcp, + set => Set, + get => Get}, + ok = api_opt_tcp_keepcnt_tcp(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_tcp_keepcnt_tcp(InitState) -> + process_flag(trap_exit, true), + ServerSeq = + [ + %% *** Wait for start order *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + Tester = ?SEV_AWAIT_START(), + {ok, State#{tester => Tester}} + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester}) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + case socket:open(Domain, stream, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := LSock, lsa := LSA} = _State) -> + case sock_bind(LSock, LSA) of + ok -> + Port = sock_port(LSock), + ?SEV_IPRINT("bound to port: ~w", [Port]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (init)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, init), + ok + end}, + + + %% The actual test + #{desc => "await continue (get keepcnt(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepcnt) + end}, + #{desc => "get keepcnt", + cmd => fun(#{sock := Sock, get := Get} = State) -> + case Get(Sock) of + {ok, KeepCnt} -> + ?SEV_IPRINT("keepcnt: ~p", [KeepCnt]), + {ok, State#{keepcnt => KeepCnt}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (get keepcnt(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepcnt), + ok + end}, + + + #{desc => "await continue (set keepcnt)", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, set_keepcnt) + end}, + #{desc => "set keepcnt", + cmd => fun(#{sock := Sock, + set := Set, + keepcnt := KeepCnt} = State) -> + NewKeepCnt = + if + (KeepCnt >= 255) -> + KeepCnt - 1; + true -> + KeepCnt + 1 + end, + case Set(Sock, NewKeepCnt) of + ok -> + ?SEV_IPRINT("keepcnt updated (to ~p)", + [NewKeepCnt]), + {ok, State#{keepcnt => NewKeepCnt}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (set keepcnt)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, set_keepcnt), + ok + end}, + + + #{desc => "await continue (get keepcnt(2))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepcnt) + end}, + #{desc => "get keepcnt(2)", + cmd => fun(#{sock := Sock, + get := Get, + keepcnt := ExpKeepCnt} = _State) -> + case Get(Sock) of + {ok, KeepCnt} when (ExpKeepCnt =:= KeepCnt) -> + ?SEV_IPRINT("expected keepcnt (~p)", + [ExpKeepCnt]), + ok; + {ok, KeepCnt} -> + ?SEV_EPRINT("unexpected keepcnt:" + "~n Expected KeepCnt: ~p" + "~n Actual KeepCnt: ~p", + [ExpKeepCnt, KeepCnt]), + {error, + {unexpected_keepcnt, ExpKeepCnt, KeepCnt}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("failed get keepcnt: " + "~n ~p", [Reason]), + ERROR + end + end}, + #{desc => "announce ready (get keepcnt)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepcnt), + ok + end}, + + + %% *** Termination *** + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + case ?SEV_AWAIT_TERMINATE(Tester, tester) of + ok -> + {ok, maps:remove(tester, State)}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "close connection socket", + cmd => fun(#{sock := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + + TesterSeq = + [ + %% *** Init part *** + #{desc => "monitor server", + cmd => fun(#{server := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + + %% Start the server + #{desc => "order server start", + cmd => fun(#{server := Pid} = _State) -> + ?SEV_ANNOUNCE_START(Pid), + ok + end}, + #{desc => "await server ready (init)", + cmd => fun(#{server := Pid} = _State) -> + ok = ?SEV_AWAIT_READY(Pid, server, init), + ok + end}, + + %% *** The actual test *** + #{desc => "order server to continue (with get-keepcnt(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepcnt), + ok + end}, + #{desc => "await server ready (get-keepcnt(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepcnt) + end}, + + #{desc => "order server to continue (with set-keepcnt)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, set_keepcnt), + ok + end}, + #{desc => "await server ready (set-keepcnt)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, set_keepcnt) + end}, + + #{desc => "order server to continue (with get-keepcnt(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepcnt), + ok + end}, + #{desc => "await server ready (get-keepcnt(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepcnt) + end}, + + + %% *** Termination *** + #{desc => "order server to terminate", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_TERMINATE(Server), + ok + end}, + #{desc => "await server termination", + cmd => fun(#{server := Server} = State) -> + ?SEV_AWAIT_TERMINATION(Server), + State1 = maps:remove(server, State), + {ok, State1} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + + i("start server evaluator"), + Server = ?SEV_START("server", ServerSeq, InitState), + + i("start tester evaluator"), + TesterInitState = #{server => Server#ev.pid}, + Tester = ?SEV_START("tester", TesterSeq, TesterInitState), + + ok = ?SEV_AWAIT_FINISH([Server, Tester]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests that the keepidle tcp socket option. +%% +%% "Gets or sets the number of seconds a TCP connection will remain +%% idle before keepalive probes are sent to the remote." +%% + +api_opt_tcp_keepidle_tcp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4(), has_support_tcp_keepidle() end, + fun() -> + Set = fun(Sock, Value) when is_integer(Value) -> + socket:setopt(Sock, tcp, keepidle, Value) + end, + Get = fun(Sock) -> + socket:getopt(Sock, tcp, keepidle) + end, + InitState = #{domain => inet, + proto => tcp, + set => Set, + get => Get}, + ok = api_opt_tcp_keepidle_tcp(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_tcp_keepidle_tcp(InitState) -> + process_flag(trap_exit, true), + ServerSeq = + [ + %% *** Wait for start order *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + Tester = ?SEV_AWAIT_START(), + {ok, State#{tester => Tester}} + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester}) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + case socket:open(Domain, stream, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := LSock, lsa := LSA} = _State) -> + case sock_bind(LSock, LSA) of + ok -> + Port = sock_port(LSock), + ?SEV_IPRINT("bound to port: ~w", [Port]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (init)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, init), + ok + end}, + + + %% The actual test + #{desc => "await continue (get keepidle(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepidle) + end}, + #{desc => "get keepidle", + cmd => fun(#{sock := Sock, get := Get} = State) -> + case Get(Sock) of + {ok, KeepIdle} -> + ?SEV_IPRINT("keepidle: ~p", [KeepIdle]), + {ok, State#{keepidle => KeepIdle}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (get keepidle(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepidle), + ok + end}, + + + #{desc => "await continue (set keepidle)", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, set_keepidle) + end}, + #{desc => "set keepidle", + cmd => fun(#{sock := Sock, + set := Set, + keepidle := KeepIdle} = State) -> + NewKeepIdle = KeepIdle + 1, + case Set(Sock, NewKeepIdle) of + ok -> + ?SEV_IPRINT("keepidle updated (to ~p)", + [NewKeepIdle]), + {ok, State#{keepidle => NewKeepIdle}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (set keepidle)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, set_keepidle), + ok + end}, + + + #{desc => "await continue (get keepidle(2))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepidle) + end}, + #{desc => "get keepidle(2)", + cmd => fun(#{sock := Sock, + get := Get, + keepidle := ExpKeepIdle} = _State) -> + case Get(Sock) of + {ok, KeepIdle} when (ExpKeepIdle =:= KeepIdle) -> + ?SEV_IPRINT("expected keepidle (~p)", + [ExpKeepIdle]), + ok; + {ok, KeepIdle} -> + ?SEV_EPRINT("unexpected keepidle:" + "~n Expected KeepIdle: ~p" + "~n Actual KeepIdle: ~p", + [ExpKeepIdle, KeepIdle]), + {error, + {unexpected_keepidle, + ExpKeepIdle, KeepIdle}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("failed get keepidle: " + "~n ~p", [Reason]), + ERROR + end + end}, + #{desc => "announce ready (get keepidle(2))", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepidle), + ok + end}, + + + %% *** Termination *** + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + case ?SEV_AWAIT_TERMINATE(Tester, tester) of + ok -> + {ok, maps:remove(tester, State)}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "close connection socket", + cmd => fun(#{sock := Sock} = State) -> + ok = socket:close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + + TesterSeq = + [ + %% *** Init part *** + #{desc => "monitor server", + cmd => fun(#{server := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + + %% Start the server + #{desc => "order server start", + cmd => fun(#{server := Pid} = _State) -> + ?SEV_ANNOUNCE_START(Pid), + ok + end}, + #{desc => "await server ready (init)", + cmd => fun(#{server := Pid} = _State) -> + ok = ?SEV_AWAIT_READY(Pid, server, init), + ok + end}, + + %% *** The actual test *** + #{desc => "order server to continue (with get-keepidle(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepidle), + ok + end}, + #{desc => "await server ready (get-keepidle(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepidle) + end}, + + #{desc => "order server to continue (with set-keepidle)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, set_keepidle), + ok + end}, + #{desc => "await server ready (set-keepidle)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, set_keepidle) + end}, + + #{desc => "order server to continue (with get-keepidle(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepidle), + ok + end}, + #{desc => "await server ready (get-keepidle(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepidle) + end}, + + + %% *** Termination *** + #{desc => "order server to terminate", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_TERMINATE(Server), + ok + end}, + #{desc => "await server termination", + cmd => fun(#{server := Server} = State) -> + ?SEV_AWAIT_TERMINATION(Server), + State1 = maps:remove(server, State), + {ok, State1} + end}, + + %% *** We are done *** + ?SEV_FINISH_NORMAL + ], + + + i("start server evaluator"), + Server = ?SEV_START("server", ServerSeq, InitState), + + i("start tester evaluator"), + TesterInitState = #{server => Server#ev.pid}, + Tester = ?SEV_START("tester", TesterSeq, TesterInitState), + + ok = ?SEV_AWAIT_FINISH([Server, Tester]). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Tests that the keepintvl tcp socket option. +%% +%% "Gets or sets the number of seconds a TCP connection will wait for +%% a keepalive response before sending another keepalive probe." +%% + +api_opt_tcp_keepintvl_tcp4(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4(), has_support_tcp_keepintvl() end, + fun() -> + Set = fun(Sock, Value) when is_integer(Value) -> + socket:setopt(Sock, tcp, keepintvl, Value) + end, + Get = fun(Sock) -> + socket:getopt(Sock, tcp, keepintvl) + end, + InitState = #{domain => inet, + proto => tcp, + set => Set, + get => Get}, + ok = api_opt_tcp_keepintvl_tcp(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_opt_tcp_keepintvl_tcp(InitState) -> + process_flag(trap_exit, true), + ServerSeq = + [ + %% *** Wait for start order *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + Tester = ?SEV_AWAIT_START(), + {ok, State#{tester => Tester}} + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester}) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LSA = which_local_socket_addr(Domain), + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + proto := Proto} = State) -> + case socket:open(Domain, stream, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := LSock, lsa := LSA} = _State) -> + case sock_bind(LSock, LSA) of + ok -> + Port = sock_port(LSock), + ?SEV_IPRINT("bound to port: ~w", [Port]), + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (init)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, init), + ok + end}, + + + %% The actual test + #{desc => "await continue (get keepintvl(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepintvl) + end}, + #{desc => "get keepintvl", cmd => fun(#{sock := Sock, get := Get} = State) -> case Get(Sock) of - {ok, DefMaxSeg} -> - ?SEV_IPRINT("maxseg default: ~p", [DefMaxSeg]), - {ok, State#{def_maxseg => DefMaxSeg}}; + {ok, KeepIntVl} -> + ?SEV_IPRINT("keepintvl: ~p", [KeepIntVl]), + {ok, State#{keepintvl => KeepIntVl}}; {error, _} = ERROR -> ERROR end end}, - - %% Note that there is no point in reading this value back, - %% since the kernel imposes its own rules with regard - %% to what is an acceptible value. - %% So, even if the set operation is a success, the value - %% still might not have changed. - %% - %% Note that not all platforms allow this to be set! - %% Since this is the *last* operation in the test sequence - %% (before termination) we also accept error reason = einval - %% as success (rather then skip). - %% The same goes for the error reason = enoprotoopt (Solaris). - #{desc => "(maybe) change maxseg (default + 16)", - cmd => fun(#{sock := Sock, - set := Set, - def_maxseg := DefMaxSeg} = _State) -> - NewMaxSeg = DefMaxSeg + 16, - case Set(Sock, NewMaxSeg) of + #{desc => "announce ready (get keepintvl(1))", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepintvl), + ok + end}, + + + #{desc => "await continue (set keepintvl)", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, set_keepintvl) + end}, + #{desc => "set keepintvl", + cmd => fun(#{sock := Sock, + set := Set, + keepintvl := KeepIntVl} = State) -> + NewKeepIntVl = KeepIntVl + 1, + case Set(Sock, NewKeepIntVl) of ok -> - ?SEV_IPRINT("maxseg (maybe) changed (to ~w)", - [NewMaxSeg]), - ok; - {error, Reason} when (Reason =:= einval) orelse - (Reason =:= enoprotoopt) -> - ?SEV_IPRINT("change not allowed (~w)", - [Reason]), - ok; + ?SEV_IPRINT("keepIntVl updated (to ~p)", + [NewKeepIntVl]), + {ok, State#{keepintvl => NewKeepIntVl}}; {error, _} = ERROR -> ERROR end end}, + #{desc => "announce ready (set keepintvl)", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, set_keepintvl), + ok + end}, + + + #{desc => "await continue (get keepintvl(2))", + cmd => fun(#{tester := Tester}) -> + ?SEV_AWAIT_CONTINUE(Tester, tester, get_keepintvl) + end}, + #{desc => "get keepintvl(2)", + cmd => fun(#{sock := Sock, + get := Get, + keepintvl := ExpKeepIntVl} = _State) -> + case Get(Sock) of + {ok, KeepIntVl} + when (ExpKeepIntVl =:= KeepIntVl) -> + ?SEV_IPRINT("expected keepintvl (~p)", + [ExpKeepIntVl]), + ok; + {ok, KeepIntVl} -> + ?SEV_EPRINT("unexpected keepintvl:" + "~n Expected KeepIntVl: ~p" + "~n Actual KeepIntVl: ~p", + [ExpKeepIntVl, KeepIntVl]), + {error, + {unexpected_keepintvl, + ExpKeepIntVl, KeepIntVl}}; + {error, Reason} = ERROR -> + ?SEV_EPRINT("failed get keepintvl: " + "~n ~p", [Reason]), + ERROR + end + end}, + #{desc => "announce ready (get keepintvl(2))", + cmd => fun(#{tester := Tester}) -> + ?SEV_ANNOUNCE_READY(Tester, get_keepintvl), + ok + end}, + %% *** Termination *** + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + case ?SEV_AWAIT_TERMINATE(Tester, tester) of + ok -> + {ok, maps:remove(tester, State)}; + {error, _} = ERROR -> + ERROR + end + end}, #{desc => "close connection socket", cmd => fun(#{sock := Sock} = State) -> ok = socket:close(Sock), @@ -23684,127 +25869,86 @@ api_opt_tcp_maxseg_tcp(InitState) -> ?SEV_FINISH_NORMAL ], - i("start tester evaluator"), - Tester = ?SEV_START("tester", TesterSeq, InitState), - - ok = ?SEV_AWAIT_FINISH([Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Tests that the nodelay tcp socket option. -%% -%% This is a very simple test. We simple set and get the value. -%% To test that it has an effect is just "to much work"... - -api_opt_tcp_nodelay_tcp4(suite) -> - []; -api_opt_tcp_nodelay_tcp4(doc) -> - []; -api_opt_tcp_nodelay_tcp4(_Config) when is_list(_Config) -> - ?TT(?SECS(5)), - tc_try(api_opt_tcp_nodelay_tcp4, - fun() -> has_support_tcp_nodelay() end, - fun() -> - Set = fun(Sock, Value) when is_boolean(Value) -> - socket:setopt(Sock, tcp, nodelay, Value) - end, - Get = fun(Sock) -> - socket:getopt(Sock, tcp, nodelay) - end, - InitState = #{domain => inet, - proto => tcp, - set => Set, - get => Get}, - ok = api_opt_tcp_nodelay_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_opt_tcp_nodelay_tcp(InitState) -> - process_flag(trap_exit, true), TesterSeq = [ %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LSA = which_local_socket_addr(Domain), - {ok, State#{lsa => LSA}} + #{desc => "monitor server", + cmd => fun(#{server := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain, - proto := Proto} = State) -> - case socket:open(Domain, stream, Proto) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end + + %% Start the server + #{desc => "order server start", + cmd => fun(#{server := Pid} = _State) -> + ?SEV_ANNOUNCE_START(Pid), + ok end}, - #{desc => "bind to local address", - cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> - case sock_bind(Sock, LSA) of - ok -> - Port = sock_port(Sock), - ?SEV_IPRINT("bound to port: ~w", [Port]), - ok; - {error, _} = ERROR -> - ERROR - end + #{desc => "await server ready (init)", + cmd => fun(#{server := Pid} = _State) -> + ok = ?SEV_AWAIT_READY(Pid, server, init), + ok end}, + %% *** The actual test *** + #{desc => "order server to continue (with get-keepintvl(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepintvl), + ok + end}, + #{desc => "await server ready (get-keepintvl(1))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepintvl) + end}, - %% The actual test - #{desc => "get (default) nodelay (= false)", - cmd => fun(#{sock := Sock, get := Get} = _State) -> - case Get(Sock) of - {ok, false = Value} -> - ?SEV_IPRINT("nodelay default: ~p", [Value]), - ok; - {error, _} = ERROR -> - ERROR - end + #{desc => "order server to continue (with set-keepintvl)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, set_keepintvl), + ok end}, - #{desc => "enable nodelay (=> true)", - cmd => fun(#{sock := Sock, set := Set} = _State) -> - case Set(Sock, true) of - ok -> - ?SEV_IPRINT("nodelay enabled"), - ok; - {error, _} = ERROR -> - ERROR - end + #{desc => "await server ready (set-keepintvl)", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, set_keepintvl) end}, - #{desc => "get nodelay (= true)", - cmd => fun(#{sock := Sock, get := Get} = _State) -> - case Get(Sock) of - {ok, true = Value} -> - ?SEV_IPRINT("nodelay: ~p", [Value]), - ok; - {error, _} = ERROR -> - ERROR - end + + #{desc => "order server to continue (with get-keepintvl(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_CONTINUE(Server, get_keepintvl), + ok + end}, + #{desc => "await server ready (get-keepintvl(2))", + cmd => fun(#{server := Server} = _State) -> + ?SEV_AWAIT_READY(Server, server, get_keepintvl) end}, %% *** Termination *** - #{desc => "close socket", - cmd => fun(#{sock := Sock} = State) -> - ok = socket:close(Sock), - {ok, maps:remove(sock, State)} + #{desc => "order server to terminate", + cmd => fun(#{server := Server} = _State) -> + ?SEV_ANNOUNCE_TERMINATE(Server), + ok + end}, + #{desc => "await server termination", + cmd => fun(#{server := Server} = State) -> + ?SEV_AWAIT_TERMINATION(Server), + State1 = maps:remove(server, State), + {ok, State1} end}, %% *** We are done *** ?SEV_FINISH_NORMAL ], + + i("start server evaluator"), + Server = ?SEV_START("server", ServerSeq, InitState), + i("start tester evaluator"), - Tester = ?SEV_START("tester", TesterSeq, InitState), + TesterInitState = #{server => Server#ev.pid}, + Tester = ?SEV_START("tester", TesterSeq, TesterInitState), - ok = ?SEV_AWAIT_FINISH([Tester]). + ok = ?SEV_AWAIT_FINISH([Server, Tester]). @@ -23816,14 +25960,10 @@ api_opt_tcp_nodelay_tcp(InitState) -> %% To test that it has an effect is just "to much work"... %% -api_opt_udp_cork_udp4(suite) -> - []; -api_opt_udp_cork_udp4(doc) -> - []; api_opt_udp_cork_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(api_opt_udp_cork_udp4, - fun() -> has_support_udp_cork() end, + fun() -> has_support_ipv4(), has_support_udp_cork() end, fun() -> Set = fun(Sock, Value) when is_boolean(Value) -> socket:setopt(Sock, udp, cork, Value) @@ -23939,13 +26079,9 @@ api_opt_udp_cork_udp(InitState) -> %% This test case is intended to test the connect timeout option %% on an IPv4 TCP (stream) socket. -api_to_connect_tcp4(suite) -> - []; -api_to_connect_tcp4(doc) -> - []; api_to_connect_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - Cond = fun() -> api_to_connect_cond() end, + Cond = fun() -> has_support_ipv4(), api_to_connect_cond() end, tc_try(api_to_connect_tcp4, Cond, fun() -> @@ -23961,7 +26097,7 @@ api_to_connect_cond() -> %% I don't know exactly at which version this starts to work. %% I know it does not work for 4.4.*, but is does for 4.15. -%% So, just to simplify, we require atleast 4.15 +%% So, just to simplify, we require at least 4.15 api_to_connect_cond({unix, linux}, {Maj, Min, _Rev}) -> if (Maj > 4) -> @@ -23998,10 +26134,6 @@ api_to_connect_cond(_, _) -> %% This test case is intended to test the connect timeout option %% on an IPv6 TCP (stream) socket. -api_to_connect_tcp6(suite) -> - []; -api_to_connect_tcp6(doc) -> - []; api_to_connect_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_connect_tcp6, @@ -24019,7 +26151,7 @@ api_to_connect_tcp6(_Config) when is_list(_Config) -> %% We use the backlog (listen) argument to test this. %% Note that the behaviour of the TCP "server side" can vary when %% a client connect to a "busy" server (full backlog). -%% For instance, on FreeBSD (11.2) the reponse when the backlog is full +%% For instance, on FreeBSD (11.2) the response when the backlog is full %% is a econreset. api_to_connect_tcp(InitState) -> @@ -24119,16 +26251,9 @@ api_to_connect_tcp(InitState) -> {ok, State#{local_sa => LSA}} end}, #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - ?SEV_IPRINT("try create node on ~p", [Host]), - case start_node(Host, client) of - {ok, Node} -> - ?SEV_IPRINT("client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end + cmd => fun(#{host := _Host} = State) -> + {Peer, Node} = ?START_NODE("client"), + {ok, State#{node => Node, peer => Peer}} end}, #{desc => "monitor client node", cmd => fun(#{node := Node} = _State) -> @@ -24233,9 +26358,9 @@ api_to_connect_tcp(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -24257,14 +26382,14 @@ api_to_connect_tcp(InitState) -> receive {nodedown, Node} -> ?SEV_IPRINT("nodedown received - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end; (#{node_stop := error} = State) -> ?SEV_IPRINT("Failed node stop - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end}, @@ -24511,13 +26636,10 @@ api_to_connect_tcp_await_timeout3([Sock|Socka]) -> %% This test case is intended to test the accept timeout option %% on an IPv4 TCP (stream) socket. -api_to_accept_tcp4(suite) -> - []; -api_to_accept_tcp4(doc) -> - []; api_to_accept_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_accept_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, timeout => 5000}, ok = api_to_accept_tcp(InitState) @@ -24528,13 +26650,9 @@ api_to_accept_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the accept timeout option %% on an IPv6 TCP (stream) socket. -api_to_accept_tcp6(suite) -> - []; -api_to_accept_tcp6(doc) -> - []; api_to_accept_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(api_to_accept_tcp4, + tc_try(api_to_accept_tcp6, fun() -> has_support_ipv6() end, fun() -> InitState = #{domain => inet6, timeout => 5000}, @@ -24625,13 +26743,10 @@ api_to_accept_tcp(InitState) -> %% This test case is intended to test the multi accept timeout option %% on an IPv4 TCP (stream) socket with multiple acceptor processes %% (three in this case). -api_to_maccept_tcp4(suite) -> - []; -api_to_maccept_tcp4(doc) -> - []; api_to_maccept_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(20)), tc_try(api_to_maccept_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, timeout => 5000}, ok = api_to_maccept_tcp(InitState) @@ -24642,13 +26757,9 @@ api_to_maccept_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the accept timeout option %% on an IPv6 TCP (stream) socket. -api_to_maccept_tcp6(suite) -> - []; -api_to_maccept_tcp6(doc) -> - []; api_to_maccept_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(20)), - tc_try(api_to_maccept_tcp4, + tc_try(api_to_maccept_tcp6, fun() -> has_support_ipv6() end, fun() -> InitState = #{domain => inet6, timeout => 5000}, @@ -24995,12 +27106,9 @@ api_to_maccept_tcp(InitState) -> %% This test case is intended to test the send timeout option %% on an IPv4 TCP (stream) socket. -api_to_send_tcp4(suite) -> - []; -api_to_send_tcp4(doc) -> - []; api_to_send_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_send_tcp4, + fun() -> has_support_ipv4() end, fun() -> not_yet_implemented()%% , %% ok = api_to_send_tcp(inet) @@ -25011,10 +27119,6 @@ api_to_send_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the send timeout option %% on an IPv6 TCP (stream) socket. -api_to_send_tcp6(suite) -> - []; -api_to_send_tcp6(doc) -> - []; api_to_send_tcp6(_Config) when is_list(_Config) -> tc_try(api_to_send_tcp6, fun() -> has_support_ipv6() end, @@ -25028,12 +27132,9 @@ api_to_send_tcp6(_Config) when is_list(_Config) -> %% This test case is intended to test the sendto timeout option %% on an IPv4 UDP (dgram) socket. -api_to_sendto_udp4(suite) -> - []; -api_to_sendto_udp4(doc) -> - []; api_to_sendto_udp4(_Config) when is_list(_Config) -> tc_try(api_to_sendto_udp4, + fun () -> has_support_ipv4() end, fun() -> not_yet_implemented()%% , %% ok = api_to_sendto_to_udp(inet) @@ -25044,10 +27145,6 @@ api_to_sendto_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the sendto timeout option %% on an IPv6 UDP (dgram) socket. -api_to_sendto_udp6(suite) -> - []; -api_to_sendto_udp6(doc) -> - []; api_to_sendto_udp6(_Config) when is_list(_Config) -> tc_try(api_to_sendto_udp6, fun() -> has_support_ipv6() end, @@ -25061,12 +27158,9 @@ api_to_sendto_udp6(_Config) when is_list(_Config) -> %% This test case is intended to test the sendmsg timeout option %% on an IPv4 TCP (stream) socket. -api_to_sendmsg_tcp4(suite) -> - []; -api_to_sendmsg_tcp4(doc) -> - []; api_to_sendmsg_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_sendmsg_tcp4, + fun() -> has_support_ipv4() end, fun() -> not_yet_implemented()%% , %% ok = api_to_sendmsg_tcp(inet) @@ -25077,10 +27171,6 @@ api_to_sendmsg_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the sendmsg timeout option %% on an IPv6 TCP (stream) socket. -api_to_sendmsg_tcp6(suite) -> - []; -api_to_sendmsg_tcp6(doc) -> - []; api_to_sendmsg_tcp6(_Config) when is_list(_Config) -> tc_try(api_to_sendmsg_tcp6, fun() -> has_support_ipv6() end, @@ -25095,12 +27185,9 @@ api_to_sendmsg_tcp6(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv4 UDP (dgram) socket. To test this we must connect %% the socket. -api_to_recv_udp4(suite) -> - []; -api_to_recv_udp4(doc) -> - []; api_to_recv_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recv_udp4, + fun() -> has_support_ipv4() end, fun() -> not_yet_implemented()%%, %%ok = api_to_recv_udp(inet) @@ -25112,10 +27199,6 @@ api_to_recv_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv6 UDP (dgram) socket. To test this we must connect %% the socket. -api_to_recv_udp6(suite) -> - []; -api_to_recv_udp6(doc) -> - []; api_to_recv_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recv_udp6, fun() -> has_support_ipv6() end, @@ -25129,13 +27212,10 @@ api_to_recv_udp6(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv4 TCP (stream) socket. -api_to_recv_tcp4(suite) -> - []; -api_to_recv_tcp4(doc) -> - []; api_to_recv_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recv_tcp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end, InitState = #{domain => inet, @@ -25149,10 +27229,6 @@ api_to_recv_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv6 TCP (stream) socket. -api_to_recv_tcp6(suite) -> - []; -api_to_recv_tcp6(doc) -> - []; api_to_recv_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recv_tcp6, @@ -25486,13 +27562,10 @@ api_to_receive_tcp(InitState) -> %% This test case is intended to test the recvfrom timeout option %% on an IPv4 UDP (dgram) socket. -api_to_recvfrom_udp4(suite) -> - []; -api_to_recvfrom_udp4(doc) -> - []; api_to_recvfrom_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvfrom_udp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end, InitState = #{domain => inet, @@ -25506,10 +27579,6 @@ api_to_recvfrom_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvfrom timeout option %% on an IPv6 UDP (dgram) socket. -api_to_recvfrom_udp6(suite) -> - []; -api_to_recvfrom_udp6(doc) -> - []; api_to_recvfrom_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvfrom_udp6, @@ -25602,13 +27671,10 @@ api_to_receive_udp(InitState) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv4 UDP (dgram) socket. -api_to_recvmsg_udp4(suite) -> - []; -api_to_recvmsg_udp4(doc) -> - []; api_to_recvmsg_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvmsg_udp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, InitState = #{domain => inet, @@ -25622,10 +27688,6 @@ api_to_recvmsg_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv6 UDP (dgram) socket. -api_to_recvmsg_udp6(suite) -> - []; -api_to_recvmsg_udp6(doc) -> - []; api_to_recvmsg_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvmsg_udp6, @@ -25643,13 +27705,10 @@ api_to_recvmsg_udp6(_Config) when is_list(_Config) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv4 TCP (stream) socket. -api_to_recvmsg_tcp4(suite) -> - []; -api_to_recvmsg_tcp4(doc) -> - []; api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvmsg_tcp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, InitState = #{domain => inet, @@ -25663,10 +27722,6 @@ api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv6 TCP (stream) socket. -api_to_recvmsg_tcp6(suite) -> - []; -api_to_recvmsg_tcp6(doc) -> - []; api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(api_to_recvmsg_tcp6, @@ -25693,10 +27748,6 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> %% We create a bunch of different sockets and ensure that the registry %% has the correct info. -reg_s_single_open_and_close_and_count(suite) -> - []; -reg_s_single_open_and_close_and_count(doc) -> - []; reg_s_single_open_and_close_and_count(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(reg_s_single_open_and_close_and_count, @@ -25708,6 +27759,8 @@ reg_s_single_open_and_close_and_count(_Config) when is_list(_Config) -> reg_s_single_open_and_close_and_count() -> socket:use_registry(true), + {OS, _} = os:type(), + %% We may have some sockets already existing. %% Make sure we dont count them when we test. Existing = socket:which_sockets(), @@ -25748,11 +27801,15 @@ reg_s_single_open_and_close_and_count() -> [] end ++ case SupportsLOCAL of - true -> + true when (OS =/= win32) -> [ {local, stream, default}, {local, dgram, default} ]; + true -> + [ + {local, stream, default} + ]; false -> [] end ++ @@ -25962,8 +28019,8 @@ reg_s_single_open_and_close_and_count() -> OwnSockets = lists:sort( [fun({D, T})-> i("create ~w:~w socket", [D, T]), - {ok, OS} = socket:open(D, T, default), - OS + {ok, OSocks} = socket:open(D, T, default), + OSocks end(SockInfo) || SockInfo <- [{inet, dgram}, {inet, dgram}, @@ -26086,10 +28143,6 @@ reg_sr_num2(Existing, F) -> %% We create a bunch of different sockets and ensure that the registry %% has the correct info. -reg_s_optional_open_and_close_and_count(suite) -> - []; -reg_s_optional_open_and_close_and_count(doc) -> - []; reg_s_optional_open_and_close_and_count(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(reg_s_optional_open_and_close_and_count, @@ -26198,10 +28251,6 @@ reg_s_optional_open_and_close_and_count() -> %% Create one socket, monitor from a different process then close socket. %% The process that did the monitor shall receive a socket DOWN. -monitor_simple_open_and_close(suite) -> - []; -monitor_simple_open_and_close(doc) -> - []; monitor_simple_open_and_close(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_simple_open_and_close, @@ -26458,10 +28507,6 @@ mon_simple_open_and_close(InitState) -> %% owner process. %% The process that did the monitor shall receive a socket DOWN. -monitor_simple_open_and_exit(suite) -> - []; -monitor_simple_open_and_exit(doc) -> - []; monitor_simple_open_and_exit(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_simple_open_and_exit, @@ -26653,10 +28698,6 @@ mon_simple_open_and_exit(InitState) -> %% (demonitor) and then close socket. %% The process that did the monitor shall *not* receive a socket DOWN. -monitor_simple_open_and_demon_and_close(suite) -> - []; -monitor_simple_open_and_demon_and_close(doc) -> - []; monitor_simple_open_and_demon_and_close(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_simple_open_and_demon_and_close, @@ -26848,10 +28889,6 @@ mon_simple_open_and_demon_and_close(InitState) -> %% Create several sockets, monitor from a different process then close %% socket. The process that did the monitor shall receive a socket DOWN. -monitor_open_and_close_multi_socks(suite) -> - []; -monitor_open_and_close_multi_socks(doc) -> - []; monitor_open_and_close_multi_socks(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_close_multi_socks, @@ -27293,10 +29330,6 @@ mon_open_and_close_multi_socks(InitState) -> %% the owner process. %% The process that did the monitor shall receive a socket DOWN. -monitor_open_and_exit_multi_socks(suite) -> - []; -monitor_open_and_exit_multi_socks(doc) -> - []; monitor_open_and_exit_multi_socks(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_exit_multi_socks, @@ -27614,10 +29647,6 @@ mon_open_and_exit_multi_socks(InitState) -> %% The process that did the monitor shall receive a socket DOWN for %% the sockets that are still monitored. -monitor_open_and_demon_and_close_multi_socks(suite) -> - []; -monitor_open_and_demon_and_close_multi_socks(doc) -> - []; monitor_open_and_demon_and_close_multi_socks(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_demon_and_close_multi_socks, @@ -27987,10 +30016,6 @@ mon_open_and_demon_and_close_multi_socks(InitState) -> %% processes, then close socket (from 'owner'). %% The processes that did the monitor shall receive a socket DOWN. -monitor_open_and_close_multi_mon(suite) -> - []; -monitor_open_and_close_multi_mon(doc) -> - []; monitor_open_and_close_multi_mon(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_close_multi_mon, @@ -28580,10 +30605,6 @@ mon_open_and_close_multi_mon(InitState) -> %% processes, then close socket (from 'owner'). %% The processes that did the monitor shall receive a socket DOWN. -monitor_open_and_exit_multi_mon(suite) -> - []; -monitor_open_and_exit_multi_mon(doc) -> - []; monitor_open_and_exit_multi_mon(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_exit_multi_mon, @@ -29138,10 +31159,6 @@ mon_open_and_exit_multi_mon(InitState) -> %% The processes that did the monitor shall receive one socket DOWN for %% each socket. -monitor_open_and_close_multi_socks_and_mon(suite) -> - []; -monitor_open_and_close_multi_socks_and_mon(doc) -> - []; monitor_open_and_close_multi_socks_and_mon(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(monitor_open_and_close_multi_socks_and_mon, @@ -30096,10 +32113,6 @@ mon_open_and_close_multi_socks_and_mon(InitState) -> %% The processes that did the monitor shall receive one socket DOWN for %% each socket. -monitor_open_and_exit_multi_socks_and_mon(suite) -> - []; -monitor_open_and_exit_multi_socks_and_mon(doc) -> - []; monitor_open_and_exit_multi_socks_and_mon(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(monitor_open_and_exit_multi_socks_and_mon, @@ -30847,10 +32860,6 @@ mon_open_and_exit_multi_socks_and_mon(InitState) -> %% The processes that did the monitor shall receive one socket DOWN for %% each socket. -monitor_closed_socket(suite) -> - []; -monitor_closed_socket(doc) -> - []; monitor_closed_socket(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(monitor_closed_socket, @@ -31146,10 +33155,6 @@ mon_closed_socket(InitState) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 TCP (stream) socket. -sc_cpe_socket_cleanup_tcp4(suite) -> - []; -sc_cpe_socket_cleanup_tcp4(doc) -> - []; sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_tcp4, @@ -31166,10 +33171,6 @@ sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 TCP (stream) socket. -sc_cpe_socket_cleanup_tcp6(suite) -> - []; -sc_cpe_socket_cleanup_tcp6(doc) -> - []; sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_tcp6, @@ -31187,10 +33188,6 @@ sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a Unix Domain (stream) socket (TCP). -sc_cpe_socket_cleanup_tcpL(suite) -> - []; -sc_cpe_socket_cleanup_tcpL(doc) -> - []; sc_cpe_socket_cleanup_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_tcpL, @@ -31208,13 +33205,10 @@ sc_cpe_socket_cleanup_tcpL(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 UDP (dgram) socket. -sc_cpe_socket_cleanup_udp4(suite) -> - []; -sc_cpe_socket_cleanup_udp4(doc) -> - []; sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, type => dgram, @@ -31229,10 +33223,6 @@ sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) -> %% (removed) when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 UDP (dgram) socket. -sc_cpe_socket_cleanup_udp6(suite) -> - []; -sc_cpe_socket_cleanup_udp6(doc) -> - []; sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_udp6, @@ -31250,14 +33240,13 @@ sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a Unix Domain (dgram) socket (UDP). -sc_cpe_socket_cleanup_udpL(suite) -> - []; -sc_cpe_socket_cleanup_udpL(doc) -> - []; sc_cpe_socket_cleanup_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_cpe_socket_cleanup_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> InitState = #{domain => local, type => dgram, @@ -31303,7 +33292,7 @@ sc_cpe_socket_cleanup(InitState) -> end}, %% *** The actual test *** - %% We *intentially* leave the socket "as is", no explicit close + %% We *intentionally* leave the socket "as is", no explicit close #{desc => "await terminate (from tester)", cmd => fun(#{tester := Tester} = State) -> case ?SEV_AWAIT_TERMINATE(Tester, tester) of @@ -31412,13 +33401,10 @@ sc_cpe_socket_cleanup(InitState) -> %% %% -sc_lc_recv_response_tcp4(suite) -> - []; -sc_lc_recv_response_tcp4(doc) -> - []; sc_lc_recv_response_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_recv_response_tcp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock) end, InitState = #{domain => inet, @@ -31433,10 +33419,6 @@ sc_lc_recv_response_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is IPv6. -sc_lc_recv_response_tcp6(suite) -> - []; -sc_lc_recv_response_tcp6(doc) -> - []; sc_lc_recv_response_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_recv_response_tcp6, @@ -31455,14 +33437,12 @@ sc_lc_recv_response_tcp6(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is Unix Domain (stream) socket. -sc_lc_recv_response_tcpL(suite) -> - []; -sc_lc_recv_response_tcpL(doc) -> - []; sc_lc_recv_response_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_recv_response_tcpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket() + end, fun() -> Recv = fun(Sock) -> socket:recv(Sock) end, InitState = #{domain => local, @@ -31647,7 +33627,7 @@ sc_lc_receive_response_tcp(InitState) -> ], %% The point of this is to perform the recv for which - %% we are testing the reponse. + %% we are testing the response. HandlerSeq = [ %% *** Wait for start order part *** @@ -32099,15 +34079,14 @@ sc_lc_receive_response_tcp(InitState) -> %% Socket is IPv4. %% -sc_lc_recvfrom_response_udp4(suite) -> - []; -sc_lc_recvfrom_response_udp4(doc) -> - []; sc_lc_recvfrom_response_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_lc_recvfrom_response_udp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> - Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end, + Recv = fun(Sock, To) -> + socket:recvfrom(Sock, [], To) + end, InitState = #{domain => inet, protocol => udp, recv => Recv}, @@ -32120,16 +34099,14 @@ sc_lc_recvfrom_response_udp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is IPv6. -sc_lc_recvfrom_response_udp6(suite) -> - []; -sc_lc_recvfrom_response_udp6(doc) -> - []; sc_lc_recvfrom_response_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_lc_recvfrom_response_udp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> - Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end, + Recv = fun(Sock, To) -> + socket:recvfrom(Sock, [], To) + end, InitState = #{domain => inet6, protocol => udp, recv => Recv}, @@ -32142,14 +34119,13 @@ sc_lc_recvfrom_response_udp6(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is Unix Domainm (dgram) socket. -sc_lc_recvfrom_response_udpL(suite) -> - []; -sc_lc_recvfrom_response_udpL(doc) -> - []; sc_lc_recvfrom_response_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_lc_recvfrom_response_udpL, - fun() -> has_support_unix_domain_socket() end, + tc_try(?FUNCTION_NAME, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) @@ -32187,10 +34163,24 @@ sc_lc_receive_response_udp(InitState) -> #{desc => "open socket", cmd => fun(#{domain := Domain, protocol := Proto} = State) -> Sock = sock_open(Domain, dgram, Proto), - %% SA = sock_sockname(Sock), + {ok, State#{sock => Sock}} + end}, + #{desc => "bind socket", + cmd => fun(#{sock := Sock, local_sa := LSA}) -> + case sock_bind(Sock, LSA) of + ok -> + ?SEV_IPRINT("src bound"), + ok; + {error, Reason} = ERROR -> + ?SEV_EPRINT("src bind failed: ~p", [Reason]), + ERROR + end + end}, + #{desc => "socket name", + cmd => fun(#{sock := Sock} = State) -> case socket:sockname(Sock) of {ok, SA} -> - {ok, State#{sock => Sock, sa => SA}}; + {ok, State#{sa => SA}}; {error, eafnosupport = Reason} -> ?SEV_IPRINT("Failed get socket name: " "~n ~p", [Reason]), @@ -32202,17 +34192,6 @@ sc_lc_receive_response_udp(InitState) -> ERROR end end}, - #{desc => "bind socket", - cmd => fun(#{sock := Sock, local_sa := LSA}) -> - case sock_bind(Sock, LSA) of - ok -> - ?SEV_IPRINT("src bound"), - ok; - {error, Reason} = ERROR -> - ?SEV_EPRINT("src bind failed: ~p", [Reason]), - ERROR - end - end}, #{desc => "announce ready (init)", cmd => fun(#{tester := Tester, sock := Sock}) -> ?SEV_ANNOUNCE_READY(Tester, init, Sock), @@ -32419,7 +34398,7 @@ sc_lc_receive_response_udp(InitState) -> %% The actual test - %% Make all the seondary servers continue, with an infinit recvfrom + %% Make all the seondary servers continue, with an infinite recvfrom %% and then the prim-server with a timed recvfrom. %% After the prim server notifies us (about the timeout) we order it %% to close the socket, which should cause the all the secondary @@ -32571,13 +34550,13 @@ sc_lc_receive_response_udp(InitState) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv4. -sc_lc_recvmsg_response_tcp4(suite) -> - []; -sc_lc_recvmsg_response_tcp4(doc) -> - []; sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(sc_lc_recvmsg_response_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), % recvmsg does not work on Windows + has_support_ipv4() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock) end, InitState = #{domain => inet, @@ -32592,14 +34571,13 @@ sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv6. -sc_lc_recvmsg_response_tcp6(suite) -> - []; -sc_lc_recvmsg_response_tcp6(doc) -> - []; sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(sc_recvmsg_response_tcp6, - fun() -> has_support_ipv6() end, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), % recvmsg does not work on Windows + has_support_ipv6() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock) end, InitState = #{domain => inet6, @@ -32614,14 +34592,13 @@ sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is Unix Domain (stream) socket. -sc_lc_recvmsg_response_tcpL(suite) -> - []; -sc_lc_recvmsg_response_tcpL(doc) -> - []; sc_lc_recvmsg_response_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(sc_recvmsg_response_tcpL, - fun() -> has_support_unix_domain_socket() end, + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), % recvmsg does not work on Windows + has_support_unix_domain_socket() + end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock) end, InitState = #{domain => local, @@ -32636,12 +34613,9 @@ sc_lc_recvmsg_response_tcpL(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv4. -sc_lc_recvmsg_response_udp4(suite) -> - []; -sc_lc_recvmsg_response_udp4(doc) -> - []; sc_lc_recvmsg_response_udp4(_Config) when is_list(_Config) -> tc_try(sc_lc_recvmsg_response_udp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(10)), Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, @@ -32657,10 +34631,6 @@ sc_lc_recvmsg_response_udp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv6. -sc_lc_recvmsg_response_udp6(suite) -> - []; -sc_lc_recvmsg_response_udp6(doc) -> - []; sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) -> tc_try(sc_recvmsg_response_udp6, fun() -> has_support_ipv6() end, @@ -32680,14 +34650,13 @@ sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is Unix Domain (dgram) socket. -sc_lc_recvmsg_response_udpL(suite) -> - []; -sc_lc_recvmsg_response_udpL(doc) -> - []; sc_lc_recvmsg_response_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_recvmsg_response_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, InitState = #{domain => local, @@ -32705,13 +34674,10 @@ sc_lc_recvmsg_response_udpL(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv4. -sc_lc_acceptor_response_tcp4(suite) -> - []; -sc_lc_acceptor_response_tcp4(doc) -> - []; sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_acceptor_response_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, protocol => tcp}, @@ -32726,10 +34692,6 @@ sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv6. -sc_lc_acceptor_response_tcp6(suite) -> - []; -sc_lc_acceptor_response_tcp6(doc) -> - []; sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_acceptor_response_tcp6, @@ -32748,10 +34710,6 @@ sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is Unix Domain (stream) socket. -sc_lc_acceptor_response_tcpL(suite) -> - []; -sc_lc_acceptor_response_tcpL(doc) -> - []; sc_lc_acceptor_response_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(sc_lc_acceptor_response_tcpL, @@ -33020,7 +34978,7 @@ sc_lc_acceptor_response_tcp(InitState) -> %% The actual test - %% Make all the seondary servers continue, with an infinit recvfrom + %% Make all the seondary servers continue, with an infinite recvfrom %% and then the prim-server with a timed recvfrom. %% After the prim server notifies us (about the timeout) we order it %% to close the socket, which should cause the all the secondary @@ -33176,13 +35134,10 @@ sc_lc_acceptor_response_tcp(InitState) -> %% now, we will make do with different VMs on the same host. %% -sc_rc_recv_response_tcp4(suite) -> - []; -sc_rc_recv_response_tcp4(doc) -> - []; sc_rc_recv_response_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_rc_recv_response_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock) end, InitState = #{domain => inet, @@ -33197,13 +35152,9 @@ sc_rc_recv_response_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recv function. %% Socket is IPv6. -sc_rc_recv_response_tcp6(suite) -> - []; -sc_rc_recv_response_tcp6(doc) -> - []; sc_rc_recv_response_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_rc_recv_response_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock) end, @@ -33219,13 +35170,9 @@ sc_rc_recv_response_tcp6(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recv function. %% Socket is Unix Domain (stream) socket. -sc_rc_recv_response_tcpL(suite) -> - []; -sc_rc_recv_response_tcpL(doc) -> - []; sc_rc_recv_response_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_rc_recv_response_tcpL, + tc_try(?FUNCTION_NAME, fun() -> has_support_unix_domain_socket() end, fun() -> Recv = fun(Sock) -> socket:recv(Sock) end, @@ -33383,6 +35330,8 @@ sc_rc_receive_response_tcp(InitState) -> ?SEV_ANNOUNCE_READY(Tester, accept), ok end}, + + #{desc => "await continue (recv)", cmd => fun(#{tester := Tester} = _State) -> ?SEV_AWAIT_CONTINUE(Tester, tester, recv) @@ -33403,19 +35352,31 @@ sc_rc_receive_response_tcp(InitState) -> ok end}, #{desc => "await ready from handler 1 (recv)", - cmd => fun(#{tester := Tester, handler1 := Pid} = _State) -> - case ?SEV_AWAIT_READY(Pid, handler1, recv, - [{tester, Tester}]) of + cmd => fun(#{tester := Tester, + handler1 := Pid1, + handler2 := Pid2, + handler3 := Pid3} = _State) -> + case ?SEV_AWAIT_READY(Pid1, handler1, recv, + [{tester, Tester}, + {handler2, Pid2}, + {handler3, Pid3}]) of {ok, Result} -> Result; - {error, _} = ERROR -> + {error, Reason} = ERROR -> + ?SEV_EPRINT("Unexpected failure: " + "~n ~p", [Reason]), ERROR end end}, #{desc => "await ready from handler 2 (recv)", - cmd => fun(#{tester := Tester, handler2 := Pid} = _State) -> - case ?SEV_AWAIT_READY(Pid, handler2, recv, - [{tester, Tester}]) of + cmd => fun(#{tester := Tester, + handler1 := Pid1, + handler2 := Pid2, + handler3 := Pid3} = _State) -> + case ?SEV_AWAIT_READY(Pid2, handler2, recv, + [{tester, Tester}, + {handler1, Pid1}, + {handler3, Pid3}]) of {ok, Result} -> Result; {error, _} = ERROR -> @@ -33423,9 +35384,14 @@ sc_rc_receive_response_tcp(InitState) -> end end}, #{desc => "await ready from handler 3 (recv)", - cmd => fun(#{tester := Tester, handler3 := Pid} = _State) -> - case ?SEV_AWAIT_READY(Pid, handler3, recv, - [{tester, Tester}]) of + cmd => fun(#{tester := Tester, + handler1 := Pid1, + handler2 := Pid2, + handler3 := Pid3} = _State) -> + case ?SEV_AWAIT_READY(Pid3, handler3, recv, + [{tester, Tester}, + {handler1, Pid1}, + {handler2, Pid2}]) of {ok, Result} -> Result; {error, _} = ERROR -> @@ -33535,19 +35501,11 @@ sc_rc_receive_response_tcp(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host, node_id := NodeID} = State) -> - case start_node(Host, - l2a(f("client_~w", [NodeID]))) of - {ok, Node} -> - ?SEV_IPRINT("client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - ?SEV_EPRINT("failed starting " - "client node ~p (=> SKIP):" - "~n ~p", [NodeID, Reason]), - {skip, Reason} - end + cmd => fun(#{node_id := NodeID} = State) -> + {Peer, Node} = + ?START_NODE(?CT_PEER_NAME(f("client_~w", + [NodeID]))), + {ok, State#{node => Node, peer => Peer}} end}, #{desc => "monitor client node 1", cmd => fun(#{node := Node} = _State) -> @@ -33665,9 +35623,9 @@ sc_rc_receive_response_tcp(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -33690,14 +35648,14 @@ sc_rc_receive_response_tcp(InitState) -> receive {nodedown, Node} -> ?SEV_IPRINT("nodedown received - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end; (#{node_stop := error} = State) -> ?SEV_IPRINT("Failed node stop - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end}, @@ -33989,9 +35947,9 @@ sc_rc_receive_response_tcp(InitState) -> Tester = ?SEV_START("tester", TesterSeq, TesterInitState), i("await evaluator"), - ?line ok = ?SEV_AWAIT_FINISH([Server, - Client1, Client2, Client3, - Tester]). + ok = ?SEV_AWAIT_FINISH([Server, + Client1, Client2, Client3, + Tester]). sc_rc_tcp_client_start(Node) -> @@ -34134,14 +36092,20 @@ sc_rc_tcp_handler_recv(Recv, Sock) -> try Recv(Sock) of {error, closed} -> ok; - {ok, _} -> - ?SEV_IPRINT("unexpected success"), + {ok, Data} -> + ?SEV_IPRINT("unexpected success: " + "~n (Unexp) Data: ~p" + "~n Socket Info: ~p", [Data, socket:info(Sock)]), {error, unexpected_success}; {error, Reason} = ERROR -> ?SEV_IPRINT("receive error: " "~n ~p", [Reason]), ERROR catch + error:notsup = Error:Stack -> + ?SEV_IPRINT("receive ~w error: skip" + "~n Stack: ~p", [Error, Stack]), + exit({skip, Error}); C:E:S -> ?SEV_IPRINT("receive failure: " "~n Class: ~p" @@ -34161,13 +36125,10 @@ sc_rc_tcp_handler_announce_ready(Parent, Slogan, Result) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv4. -sc_rc_recvmsg_response_tcp4(suite) -> - []; -sc_rc_recvmsg_response_tcp4(doc) -> - []; sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_rc_recvmsg_response_tcp4, + fun() -> has_support_ipv4() end, fun() -> Recv = fun(Sock) -> socket:recvmsg(Sock) end, InitState = #{domain => inet, @@ -34182,10 +36143,6 @@ sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv6. -sc_rc_recvmsg_response_tcp6(suite) -> - []; -sc_rc_recvmsg_response_tcp6(doc) -> - []; sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_rc_recvmsg_response_tcp6, @@ -34204,10 +36161,6 @@ sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is Unix Domain (stream) socket. -sc_rc_recvmsg_response_tcpL(suite) -> - []; -sc_rc_recvmsg_response_tcpL(doc) -> - []; sc_rc_recvmsg_response_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(sc_rc_recvmsg_response_tcpL, @@ -34234,13 +36187,10 @@ sc_rc_recvmsg_response_tcpL(_Config) when is_list(_Config) -> %% This would of course not work for Unix Domain sockets. %% -sc_rs_recv_send_shutdown_receive_tcp4(suite) -> - []; -sc_rs_recv_send_shutdown_receive_tcp4(doc) -> - []; sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), - tc_try(sc_rs_recv_send_shutdown_receive_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> MsgData = ?DATA, Recv = fun(Sock) -> @@ -34265,12 +36215,8 @@ sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) -> %% reader attempts a recv. %% Socket is IPv6. -sc_rs_recv_send_shutdown_receive_tcp6(suite) -> - []; -sc_rs_recv_send_shutdown_receive_tcp6(doc) -> - []; sc_rs_recv_send_shutdown_receive_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_rs_recv_send_shutdown_receive_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> ?TT(?SECS(10)), @@ -34297,13 +36243,9 @@ sc_rs_recv_send_shutdown_receive_tcp6(_Config) when is_list(_Config) -> %% reader attempts a recv. %% Socket is Unix Domain (stream) socket. -sc_rs_recv_send_shutdown_receive_tcpL(suite) -> - []; -sc_rs_recv_send_shutdown_receive_tcpL(doc) -> - []; sc_rs_recv_send_shutdown_receive_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(sc_rs_recv_send_shutdown_receive_tcpL, + tc_try(?FUNCTION_NAME, fun() -> has_support_unix_domain_socket() end, fun() -> MsgData = ?DATA, @@ -34539,15 +36481,9 @@ sc_rs_send_shutdown_receive_tcp(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, client) of - {ok, Node} -> - ?SEV_IPRINT("client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end + cmd => fun(State) -> + {Peer, Node} = ?START_NODE("client"), + {ok, State#{peer => Peer, node => Node}} end}, #{desc => "monitor client node", cmd => fun(#{node := Node} = _State) -> @@ -34712,9 +36648,9 @@ sc_rs_send_shutdown_receive_tcp(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -34736,14 +36672,14 @@ sc_rs_send_shutdown_receive_tcp(InitState) -> receive {nodedown, Node} -> ?SEV_IPRINT("nodedown received - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end; (#{node_stop := error} = State) -> ?SEV_IPRINT("Failed node stop - cleanup"), - State1 = maps:remove(node_id, State), - State2 = maps:remove(node, State1), + State1 = maps:remove(peer, State), + State2 = maps:remove(node, State1), {ok, State2} end}, @@ -35034,11 +36970,14 @@ sc_rs_tcp_client_connect(Sock, ServerSA) -> sc_rs_tcp_client_send(Sock, Send, Data) -> i("sc_rs_tcp_client_send -> entry"), - case Send(Sock, Data) of + try Send(Sock, Data) of ok -> ok; {error, Reason} -> exit({send, Reason}) + catch + error : notsup = Reason : _ -> + exit({skip, Reason}) end. sc_rs_tcp_client_shutdown(Sock) -> @@ -35106,7 +37045,7 @@ sc_rs_tcp_handler_await(Parent, Slogan) -> ?SEV_IPRINT("await ~w", [Slogan]), ?SEV_AWAIT_CONTINUE(Parent, parent, Slogan). -%% This hould actually work - we leave it for now +%% This should actually work - we leave it for now sc_rs_tcp_handler_recv(Recv, Sock, First) -> ?SEV_IPRINT("recv"), try Recv(Sock) of @@ -35122,6 +37061,8 @@ sc_rs_tcp_handler_recv(Recv, Sock, First) -> "~n ~p", [Reason]), ERROR catch + error : notsup = Reason : _ -> + exit({skip, Reason}); C:E:S -> ?SEV_IPRINT("receive failure: " "~n Class: ~p" @@ -35143,12 +37084,9 @@ sc_rs_tcp_handler_announce_ready(Parent, Slogan, Result) -> %% reader attempts a recv. %% Socket is IPv4. -sc_rs_recvmsg_send_shutdown_receive_tcp4(suite) -> - []; -sc_rs_recvmsg_send_shutdown_receive_tcp4(doc) -> - []; sc_rs_recvmsg_send_shutdown_receive_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_rs_recvmsg_send_shutdown_receive_tcp4, + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(30)), MsgData = ?DATA, @@ -35182,12 +37120,8 @@ sc_rs_recvmsg_send_shutdown_receive_tcp4(_Config) when is_list(_Config) -> %% reader attempts a recv. %% Socket is IPv6. -sc_rs_recvmsg_send_shutdown_receive_tcp6(suite) -> - []; -sc_rs_recvmsg_send_shutdown_receive_tcp6(doc) -> - []; sc_rs_recvmsg_send_shutdown_receive_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_rs_recvmsg_send_shutdown_receive_tcp6, + tc_try(?FUNCTION_NAME, fun() -> has_support_ipv6() end, fun() -> ?TT(?SECS(10)), @@ -35222,13 +37156,9 @@ sc_rs_recvmsg_send_shutdown_receive_tcp6(_Config) when is_list(_Config) -> %% reader attempts a recv. %% Socket is UNix Domain (stream) socket. -sc_rs_recvmsg_send_shutdown_receive_tcpL(suite) -> - []; -sc_rs_recvmsg_send_shutdown_receive_tcpL(doc) -> - []; sc_rs_recvmsg_send_shutdown_receive_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), - tc_try(sc_rs_recvmsg_send_shutdown_receive_tcpL, + tc_try(?FUNCTION_NAME, fun() -> has_support_unix_domain_socket() end, fun() -> {ok, CWD} = file:get_cwd(), @@ -35268,14 +37198,34 @@ sc_rs_recvmsg_send_shutdown_receive_tcpL(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to (simply) test "some" ioctl features. +%% This test case is intended to (*really* simply) test +%% "some" ioctl features. %% -ioctl_simple1(suite) -> - []; -ioctl_simple1(doc) -> - []; ioctl_simple1(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> + has_support_ioctl_requests() + end, + fun() -> + InitState = #{}, + ok = do_ioctl_simple1(InitState) + end). + + +do_ioctl_simple1(_State) -> + Requests = socket:supports(ioctl_requests), + ?P("Requests: ~p", [Requests]), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to (simply) test "some" ioctl features. +%% + +ioctl_simple2(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, fun() -> @@ -35284,11 +37234,11 @@ ioctl_simple1(_Config) when is_list(_Config) -> end, fun() -> InitState = #{}, - ok = do_ioctl_simple(InitState) + ok = do_ioctl_simple2(InitState) end). -do_ioctl_simple(_State) -> +do_ioctl_simple2(_State) -> i("create dummy dgram:UDP socket"), {ok, Sock1} = socket:open(inet, dgram, udp), i("perform simple ioctl (expect success)"), @@ -35352,15 +37302,86 @@ do_ioctl_simple(_State) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to (simply) test the ioctl nread feature. +%% + +ioctl_nread(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> + has_support_ioctl_requests(), + has_support_ioctl_nread() + end, + fun() -> + InitState = #{}, + ok = do_ioctl_nread(InitState) + end). + +do_ioctl_nread(_) -> + i("Get local socket address"), + LSA = which_local_socket_addr(inet), + i("Use LSA: ~p", [LSA]), + + i("Create dgram:UDP socket 1"), + {ok, S1} = socket:open(inet, dgram, udp), + + i("Bind socket 1"), + ok = socket:bind(S1, LSA), + + i("Create dgram:UDP socket 2"), + {ok, S2} = socket:open(inet, dgram, udp), + + i("Bind socket 2"), + ok = socket:bind(S2, LSA), + + i("Check data to read - expect 0 bytes"), + {ok, 0} = socket:ioctl(S1, nread), + + i("Get socket 1 port number"), + {ok, #{port := Port1}} = socket:sockname(S1), + + i("Send data to socket 1 (from socket 2)"), + Data = <<0,1,2,3,4,5,6,7,8,9>>, + DataSz = byte_size(Data), + ok = socket:sendto(S2, Data, LSA#{port => Port1}), + + i("Give it some time to arrive"), + ?SLEEP(?SECS(1)), + + i("Verify that the correct amount of data (atleast ~p) is available", [DataSz]), + case socket:ioctl(S1, nread) of + {ok, DataSize} when (DataSize >= DataSz) -> + i("Success: " + "~n Min Size: ~p" + "~n Actual Size: ~p", [DataSz, DataSize]), + ok; + {ok, DataSize} -> + i("Unexpected data size: " + "~n Expected (min) Size: ~p" + "~n Actual Size: ~p", [DataSz, DataSize]), + ct:fail({invalid_data_size, DataSz, DataSize}) + end, + + i("Read the data"), + {ok, {_, Data}} = socket:recvfrom(S1), + + i("Verify that the data has been read (no more data is available)"), + {ok, 0} = socket:ioctl(S1, nread), + + i("Cleanup"), + socket:close(S1), + socket:close(S2), + + i("Done"), + ok. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% These test case(s) are intended to (simply) test "some" ioctl get %% request(s). %% -ioctl_get_gifname(suite) -> - []; -ioctl_get_gifname(doc) -> - []; ioctl_get_gifname(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35410,10 +37431,6 @@ do_ioctl_get_gifname(_State) -> %% --- gifindex --- -ioctl_get_gifindex(suite) -> - []; -ioctl_get_gifindex(doc) -> - []; ioctl_get_gifindex(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35465,10 +37482,6 @@ do_ioctl_get_gifindex(_State) -> %% --- gifaddr --- -ioctl_get_gifaddr(suite) -> - []; -ioctl_get_gifaddr(doc) -> - []; ioctl_get_gifaddr(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35532,10 +37545,6 @@ do_ioctl_get_gifaddr(_State) -> %% --- gifdstaddr --- -ioctl_get_gifdstaddr(suite) -> - []; -ioctl_get_gifdstaddr(doc) -> - []; ioctl_get_gifdstaddr(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35550,17 +37559,17 @@ ioctl_get_gifdstaddr(_Config) when is_list(_Config) -> do_ioctl_get_gifdstaddr(_State) -> - Domain = inet, + Domain = inet_or_inet6(), LSA = which_local_socket_addr(Domain), i("create and init listen stream:TCP socket"), - {ok, LSock} = socket:open(inet, stream, tcp), + {ok, LSock} = socket:open(Domain, stream, tcp), ok = socket:bind(LSock, LSA#{port => 0}), ok = socket:listen(LSock), {ok, #{port := LPort}} = socket:sockname(LSock), i("create and init connection stream:TCP socket"), - {ok, CSock} = socket:open(inet, stream, tcp), + {ok, CSock} = socket:open(Domain, stream, tcp), i("attempt connect (nowait)"), {ok, ASock} = @@ -35625,16 +37634,13 @@ verify_gifdstaddr(Sock, Prefix, IfIdx, IfName) -> "~n ~p", [Prefix, IfName, IfIdx, Crap]), socket:close(Sock), ?FAIL({unexpected_addr, Prefix, IfName, IfIdx, Crap}); - {error, eaddrnotavail = Reason} -> + {error, IgnoredReason} when IgnoredReason =:= eaddrnotavail; + IgnoredReason =:= eperm; + IgnoredReason =:= enotty -> i("[~s] got unexpected error for interface ~p (~w) => " "SKIP interface" - "~n Reason: ~p", [Prefix, IfName, IfIdx, Reason]), + "~n Reason: ~p", [Prefix, IfName, IfIdx, IgnoredReason]), ignore; - {error, eperm = Reason} -> - i("[~s] got unexpected error for interface ~p (~w) => " - "SKIP interface" - "~n Reason: ~p", [Prefix, IfName, IfIdx, Reason]), - ignore; {error, einval = Reason} when (OsFam =:= unix) andalso ((OsName =:= darwin) orelse (OsName =:= freebsd) orelse @@ -35656,10 +37662,6 @@ verify_gifdstaddr(Sock, Prefix, IfIdx, IfName) -> %% --- gifbrdaddr --- -ioctl_get_gifbrdaddr(suite) -> - []; -ioctl_get_gifbrdaddr(doc) -> - []; ioctl_get_gifbrdaddr(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35674,17 +37676,17 @@ ioctl_get_gifbrdaddr(_Config) when is_list(_Config) -> do_ioctl_get_gifbrdaddr(_State) -> - Domain = inet, + Domain = inet_or_inet6(), LSA = which_local_socket_addr(Domain), i("create and init listen stream:TCP socket"), - {ok, LSock} = socket:open(inet, stream, tcp), + {ok, LSock} = socket:open(Domain, stream, tcp), ok = socket:bind(LSock, LSA#{port => 0}), ok = socket:listen(LSock), {ok, #{port := LPort}} = socket:sockname(LSock), i("create and init connection stream:TCP socket"), - {ok, CSock} = socket:open(inet, stream, tcp), + {ok, CSock} = socket:open(Domain, stream, tcp), i("attempt connect (nowait)"), {ok, ASock} = @@ -35748,16 +37750,13 @@ verify_gifbrdaddr(Sock, Prefix, IfIdx, IfName) -> "~n ~p", [Prefix, IfName, IfIdx, Crap]), socket:close(Sock), ?FAIL({unexpected_addr, IfName, IfIdx, Crap}); - {error, eaddrnotavail = Reason} -> + {error, IgnoredReason} when IgnoredReason =:= eaddrnotavail; + IgnoredReason =:= eperm; + IgnoredReason =:= enotty -> i("[~s] got unexpected error for interface ~p (~w) => " - "SKIP interface" - "~n Reason: ~p", [Prefix, IfName, IfIdx, Reason]), + "SKIP interface" + "~n Reason: ~p", [Prefix, IfName, IfIdx, IgnoredReason]), ignore; - {error, eperm = Reason} -> - i("[~s] got unexpected error for interface ~p (~w) => " - "SKIP interface" - "~n Reason: ~p", [Prefix, IfName, IfIdx, Reason]), - ignore; {error, einval = Reason} when (OsFam =:= unix) andalso ((OsName =:= darwin) orelse (OsName =:= freebsd) orelse @@ -35778,10 +37777,6 @@ verify_gifbrdaddr(Sock, Prefix, IfIdx, IfName) -> %% --- gifnetmask --- -ioctl_get_gifnetmask(suite) -> - []; -ioctl_get_gifnetmask(doc) -> - []; ioctl_get_gifnetmask(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35844,10 +37839,6 @@ do_ioctl_get_gifnetmask(_State) -> %% --- gifmtu --- -ioctl_get_gifmtu(suite) -> - []; -ioctl_get_gifmtu(doc) -> - []; ioctl_get_gifmtu(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35900,10 +37891,6 @@ do_ioctl_get_gifmtu(_State) -> %% --- gifhwaddr --- -ioctl_get_gifhwaddr(suite) -> - []; -ioctl_get_gifhwaddr(doc) -> - []; ioctl_get_gifhwaddr(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -35929,22 +37916,8 @@ do_ioctl_get_gifhwaddr(_State) -> %% This a *very* simple test... %% ...just to check that we actually get an socket address _ = [case socket:ioctl(Sock, gifhwaddr, IfName) of - {ok, #{family := ArphdrFam, - addr := Addr}} when is_atom(ArphdrFam) -> - case erlang:atom_to_list(ArphdrFam) of - "arphrd_" ++ _ -> - i("got (expected) (HW) socket address for " - "interface ~p (~w): " - "~n (~w) ~p", [IfName, IfIdx, ArphdrFam, Addr]), - ok; - _ -> - i(" got unexpected family for interface ~p (~w)" - "~n ~p", [IfName, IfIdx, ArphdrFam]), - socket:close(Sock), - ?FAIL({unexpected_family, IfName, IfIdx, ArphdrFam}) - end; {ok, #{family := Fam, - addr := Addr}} when is_integer(Fam) -> + addr := Addr}} when is_atom(Fam) orelse is_integer(Fam) -> i("got (expected) socket address for interface ~p (~w): " "~n (~w) ~p", [IfName, IfIdx, Fam, Addr]), ok; @@ -35971,10 +37944,6 @@ do_ioctl_get_gifhwaddr(_State) -> %% --- giftxqlen --- -ioctl_get_giftxqlen(suite) -> - []; -ioctl_get_giftxqlen(doc) -> - []; ioctl_get_giftxqlen(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, @@ -36025,57 +37994,105 @@ do_ioctl_get_giftxqlen(_State) -> -%% --- gifflags --- +%% --- gifflags --- + +ioctl_get_gifflags(_Config) when is_list(_Config) -> + ?TT(?SECS(5)), + tc_try(?FUNCTION_NAME, + fun() -> + has_support_net_if_names(), + has_support_ioctl_gifflags() + end, + fun() -> + InitState = #{}, + ok = do_ioctl_get_gifflags(InitState) + end). + + +do_ioctl_get_gifflags(_State) -> + i("create dummy stream:TCP socket"), + {ok, Sock} = socket:open(inet, stream, tcp), + + i("get if names"), + {ok, IfNames} = net:if_names(), + + AllFlags = [Flag || {Flag, Supported} <- + socket:supports(ioctl_flags), Supported =:= true], + + i("try ioctl all if indexes: " + "~n ~p", [IfNames]), + %% This a *very* simple test... + %% ...just to check that we actually get an socket address + _ = [case socket:ioctl(Sock, gifflags, IfName) of + {ok, Flags} when is_list(Flags) -> + i("got flags for interface ~p (~w): " + "~n ~p", [IfName, IfIdx, Flags]), + case Flags -- AllFlags of + [] -> + i("flags accounted for"), + ok; + ExtraFlags -> + i(" got superfluous flags for interface ~p (~w)" + "~n Received Flags: ~p" + "~n Superfluous Flags: ~p" + "~n All Supported Flags: ~p" + "~n", [IfName, IfIdx, Flags, ExtraFlags, AllFlags]), + socket:close(Sock), + ?FAIL({unexpected_superfluous_flags, + IfName, IfIdx, Flags, ExtraFlags, AllFlags}) + end; + {ok, Crap} -> + %% Oups?! + i(" got unexpected result for interface ~p (~w)" + "~n ~p", [IfName, IfIdx, Crap]), + socket:close(Sock), + ?FAIL({unexpected_mtu, IfName, IfIdx, Crap}); + {error, Reason} -> + i(" got unexpected error for interface ~p (~w)" + "~n Reason: ~p", [IfName, IfIdx, Reason]), + socket:close(Sock), + ?FAIL({unexpected_failure, IfName, IfIdx, Reason}) + end || {IfIdx, IfName} <- IfNames], + + i("close dummy stream:TCP socket"), + ok = socket:close(Sock), + + i("done"), + ok. + + + +%% --- gifmap --- -ioctl_get_gifflags(suite) -> - []; -ioctl_get_gifflags(doc) -> - []; -ioctl_get_gifflags(_Config) when is_list(_Config) -> +ioctl_get_gifmap(_Config) when is_list(_Config) -> ?TT(?SECS(5)), tc_try(?FUNCTION_NAME, fun() -> has_support_net_if_names(), - has_support_ioctl_gifflags() + has_support_ioctl_gifmap() end, fun() -> InitState = #{}, - ok = do_ioctl_get_gifflags(InitState) + ok = do_ioctl_get_gifmap(InitState) end). -do_ioctl_get_gifflags(_State) -> +do_ioctl_get_gifmap(_State) -> i("create dummy stream:TCP socket"), {ok, Sock} = socket:open(inet, stream, tcp), i("get if names"), {ok, IfNames} = net:if_names(), - AllFlags = [Flag || {Flag, Supported} <- - socket:supports(ioctl_flags), Supported =:= true], - i("try ioctl all if indexes: " "~n ~p", [IfNames]), %% This a *very* simple test... %% ...just to check that we actually get an socket address - _ = [case socket:ioctl(Sock, gifflags, IfName) of - {ok, Flags} when is_list(Flags) -> - i("got flags for interface ~p (~w): " - "~n ~p", [IfName, IfIdx, Flags]), - case Flags -- AllFlags of - [] -> - i("flags accounted for"), - ok; - ExtraFlags -> - i(" got superfluous flags for interface ~p (~w)" - "~n Received Flags: ~p" - "~n Superfluous Flags: ~p" - "~n All Supported Flags: ~p" - "~n", [IfName, IfIdx, Flags, ExtraFlags, AllFlags]), - socket:close(Sock), - ?FAIL({unexpected_superfluous_flags, - IfName, IfIdx, Flags, ExtraFlags, AllFlags}) - end; + _ = [case socket:ioctl(Sock, gifmap, IfName) of + {ok, Map} when is_map(Map) -> + i("got (expected) map for interface ~p (~w): " + "~n ~p", [IfName, IfIdx, Map]), + ok; {ok, Crap} -> %% Oups?! i(" got unexpected result for interface ~p (~w)" @@ -36097,56 +38114,195 @@ do_ioctl_get_gifflags(_State) -> -%% --- gifmap --- -ioctl_get_gifmap(suite) -> - []; -ioctl_get_gifmap(doc) -> - []; -ioctl_get_gifmap(_Config) when is_list(_Config) -> - ?TT(?SECS(5)), - tc_try(?FUNCTION_NAME, - fun() -> - has_support_net_if_names(), - has_support_ioctl_gifmap() - end, - fun() -> - InitState = #{}, - ok = do_ioctl_get_gifmap(InitState) - end). +%% --- tcp_info --- +ioctl_tcp_info(_Config) when is_list(_Config) -> + ?TT(?SECS(15)), + Cond = fun() -> + has_support_ioctl_tcp_info() + end, + TC = fun() -> + Domain = inet, + case which_local_addr(Domain) of + {ok, Addr} -> + State = #{domain => Domain, + laddr => Addr}, + do_ioctl_tcp_info(State); + {error, Reason} -> + skip({no_local_addr, Reason}) + end + end, + tc_try(?FUNCTION_NAME, Cond, TC). -do_ioctl_get_gifmap(_State) -> - i("create dummy stream:TCP socket"), - {ok, Sock} = socket:open(inet, stream, tcp), - i("get if names"), - {ok, IfNames} = net:if_names(), +do_ioctl_tcp_info(#{domain := Domain, + laddr := LAddr} = _State) -> + LSA = #{family => Domain, addr => LAddr}, - i("try ioctl all if indexes: " - "~n ~p", [IfNames]), - %% This a *very* simple test... - %% ...just to check that we actually get an socket address - _ = [case socket:ioctl(Sock, gifmap, IfName) of - {ok, Map} when is_map(Map) -> - i("got (expected) map for interface ~p (~w): " - "~n ~p", [IfName, IfIdx, Map]), - ok; - {ok, Crap} -> - %% Oups?! - i(" got unexpected result for interface ~p (~w)" - "~n ~p", [IfName, IfIdx, Crap]), - socket:close(Sock), - ?FAIL({unexpected_mtu, IfName, IfIdx, Crap}); - {error, Reason} -> - i(" got unexpected error for interface ~p (~w)" - "~n Reason: ~p", [IfName, IfIdx, Reason]), - socket:close(Sock), - ?FAIL({unexpected_failure, IfName, IfIdx, Reason}) - end || {IfIdx, IfName} <- IfNames], + i("[server] create stream:TCP server listen socket"), + {ok, L} = socket:open(Domain, stream, tcp), - i("close dummy stream:TCP socket"), - ok = socket:close(Sock), + i("[server] bind to ~p", [LSA]), + ok = socket:bind(L, LSA), + + i("[server] make listen socket"), + ok = socket:listen(L), + + i("[server] get sockname"), + {ok, SSA} = socket:sockname(L), + + + i("[client] create stream:TCP socket"), + {ok, C} = socket:open(Domain, stream, tcp), + + i("[client] bind to ~p", [LSA]), + ok = socket:bind(C, LSA), + + i("[client] connect to server: " + "~n ~p", [SSA]), + ok = socket:connect(C, SSA), + + + i("[server] accept connection"), + {ok, A} = socket:accept(L), + + + i("[client] try get tcp info"), + case socket:ioctl(C, tcp_info) of + {ok, CTcpInfo0} -> + i("[client] tcp info: " + "~n ~p" + "~n", [CTcpInfo0]), + ok; + {error, CReason0} -> + i("[client] failed get TCP info: " + "~n ~p" + "~n", [CReason0]), + skip({client_tcp_info, 0, CReason0}) + end, + + i("[server] try get tcp info"), + case socket:ioctl(A, tcp_info) of + {ok, ATcpInfo0} -> + i("[server] tcp info: " + "~n ~p" + "~n", [ATcpInfo0]), + ok; + {error, AReason0} -> + i("[server] failed get TCP info: " + "~n ~p" + "~n", [AReason0]), + skip({server_tcp_info, 0, AReason0}) + end, + + + Data = <<0,1,2,3,4,5,6,7,8,9, + 0,1,2,3,4,5,6,7,8,9>>, + DSz = byte_size(Data), + i("[client] send some data"), + ok = socket:send(C, Data), + + i("[client] try get tcp info (verify bytes-out)"), + case socket:ioctl(C, tcp_info) of + {ok, #{bytes_out := BytesOut} = CTcpInfo1} when (BytesOut =:= DSz) -> + i("[client] tcp info: " + "~n ~p" + "~n", [CTcpInfo1]), + ok; + {error, CReason1} -> + i("[client] failed get TCP info: " + "~n ~p" + "~n", [CReason1]), + skip({client_tcp_info, 1, CReason1}) + end, + + i("[server] try get tcp info (verify bytes-in)"), + case socket:ioctl(A, tcp_info) of + {ok, #{bytes_in := BytesIn} = ATcpInfo1} when (BytesIn =:= DSz) -> + i("[server] tcp info: " + "~n ~p" + "~n", [ATcpInfo1]), + ok; + {error, AReason1} -> + i("[server] failed get TCP info: " + "~n ~p" + "~n", [AReason1]), + skip({server_tcp_info, 1, AReason1}) + end, + + + i("[server] recv some data"), + {ok, _} = socket:recv(A), + + i("[client] try get tcp info"), + {ok, CConnTime2} = + case socket:ioctl(C, tcp_info) of + {ok, #{connection_time := CCT2} = CTcpInfo2} -> + i("[client] tcp info: " + "~n ~p" + "~n", [CTcpInfo2]), + {ok, CCT2}; + {error, CReason2} -> + i("[client] failed get TCP info: " + "~n ~p" + "~n", [CReason2]), + skip({client_tcp_info, 2, CReason2}) + end, + + i("[server] try get tcp info"), + {ok, AConnTime2} = + case socket:ioctl(A, tcp_info) of + {ok, #{connection_time := ACT2} = ATcpInfo2} -> + i("[server] tcp info: " + "~n ~p" + "~n", [ATcpInfo2]), + {ok, ACT2}; + {error, AReason2} -> + i("[server] failed get TCP info: " + "~n ~p" + "~n", [AReason2]), + skip({server_tcp_info, 2, AReason2}) + end, + + SLEEP = ?SECS(5), + ?SLEEP(SLEEP), + + i("[client] try get tcp info (verify connection time)"), + case socket:ioctl(C, tcp_info) of + {ok, #{connection_time := CCT3} = CTcpInfo3} + when (CCT3 >= (SLEEP+CConnTime2)) -> + i("[client] tcp info: " + "~n ~p" + "~n", [CTcpInfo3]), + ok; + {error, CReason3} -> + i("[client] failed get TCP info: " + "~n ~p" + "~n", [CReason3]), + skip({client_tcp_info, 3, CReason3}) + end, + + i("[server] try get tcp info (verify connection time)"), + case socket:ioctl(A, tcp_info) of + {ok, #{connection_time := ACT3} = ATcpInfo3} + when (ACT3 >= (SLEEP+AConnTime2)) -> + i("[server] tcp info: " + "~n ~p" + "~n", [ATcpInfo3]), + ok; + {error, AReason3} -> + i("[server] failed get TCP info: " + "~n ~p" + "~n", [AReason3]), + skip({server_tcp_info, 3, AReason3}) + end, + + + i("cleanup"), + ok = socket:close(L), + ok = socket:close(A), + ok = socket:close(C), i("done"), ok. @@ -36160,13 +38316,10 @@ do_ioctl_get_gifmap(_State) -> %% So that its easy to extend, we use fun's for read and write. %% We use TCP on IPv4. -traffic_send_and_recv_counters_tcp4(suite) -> - []; -traffic_send_and_recv_counters_tcp4(doc) -> - []; traffic_send_and_recv_counters_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_send_and_recv_counters_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, proto => tcp, @@ -36182,10 +38335,6 @@ traffic_send_and_recv_counters_tcp4(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use TCP on IPv6. -traffic_send_and_recv_counters_tcp6(suite) -> - []; -traffic_send_and_recv_counters_tcp6(doc) -> - []; traffic_send_and_recv_counters_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_send_and_recv_counters_tcp6, @@ -36205,10 +38354,6 @@ traffic_send_and_recv_counters_tcp6(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use default (TCP) on local. -traffic_send_and_recv_counters_tcpL(suite) -> - []; -traffic_send_and_recv_counters_tcpL(doc) -> - []; traffic_send_and_recv_counters_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_send_and_recv_counters_tcpL, @@ -36228,13 +38373,13 @@ traffic_send_and_recv_counters_tcpL(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use TCP on IPv4. -traffic_sendmsg_and_recvmsg_counters_tcp4(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_tcp4(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_tcp4, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> InitState = #{domain => inet, proto => tcp, @@ -36260,14 +38405,13 @@ traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use TCP on IPv6. -traffic_sendmsg_and_recvmsg_counters_tcp6(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_tcp6(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_tcp6, - fun() -> has_support_ipv6() end, + fun() -> + is_not_windows(), + has_support_ipv6() + end, fun() -> InitState = #{domain => inet6, proto => tcp, @@ -36293,10 +38437,6 @@ traffic_sendmsg_and_recvmsg_counters_tcp6(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use default (TCP) on local. -traffic_sendmsg_and_recvmsg_counters_tcpL(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_tcpL(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_tcpL, @@ -37365,13 +39505,10 @@ traffic_sar_counters_validation2(Counters, [{Cnt, Val}|ValidateCounters]) -> %% So that its easy to extend, we use fun's for read and write. %% We use UDP on IPv4. -traffic_sendto_and_recvfrom_counters_udp4(suite) -> - []; -traffic_sendto_and_recvfrom_counters_udp4(doc) -> - []; traffic_sendto_and_recvfrom_counters_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendto_and_recvfrom_counters_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, proto => udp, @@ -37391,10 +39528,6 @@ traffic_sendto_and_recvfrom_counters_udp4(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use UDP on IPv6. -traffic_sendto_and_recvfrom_counters_udp6(suite) -> - []; -traffic_sendto_and_recvfrom_counters_udp6(doc) -> - []; traffic_sendto_and_recvfrom_counters_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendto_and_recvfrom_counters_udp6, @@ -37418,14 +39551,13 @@ traffic_sendto_and_recvfrom_counters_udp6(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use default (UDP) on local. -traffic_sendto_and_recvfrom_counters_udpL(suite) -> - []; -traffic_sendto_and_recvfrom_counters_udpL(doc) -> - []; traffic_sendto_and_recvfrom_counters_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendto_and_recvfrom_counters_udp4, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> InitState = #{domain => local, proto => default, @@ -37445,13 +39577,10 @@ traffic_sendto_and_recvfrom_counters_udpL(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use UDP on IPv4. -traffic_sendmsg_and_recvmsg_counters_udp4(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_udp4(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_udp4(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_udp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, proto => udp, @@ -37479,10 +39608,6 @@ traffic_sendmsg_and_recvmsg_counters_udp4(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use UDP on IPv6. -traffic_sendmsg_and_recvmsg_counters_udp6(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_udp6(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_udp6(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_udp6, @@ -37514,14 +39639,13 @@ traffic_sendmsg_and_recvmsg_counters_udp6(_Config) when is_list(_Config) -> %% So that its easy to extend, we use fun's for read and write. %% We use default (UDP) on local. -traffic_sendmsg_and_recvmsg_counters_udpL(suite) -> - []; -traffic_sendmsg_and_recvmsg_counters_udpL(doc) -> - []; traffic_sendmsg_and_recvmsg_counters_udpL(_Config) when is_list(_Config) -> ?TT(?SECS(15)), tc_try(traffic_sendmsg_and_recvmsg_counters_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> InitState = #{domain => local, proto => default, @@ -38377,13 +40501,10 @@ traffic_send_and_recv_udp(InitState) -> %% Second, send in a bunch of "small" chunks, and read in one "big" chunk. %% Socket is IPv4. -traffic_send_and_recv_chunks_tcp4(suite) -> - []; -traffic_send_and_recv_chunks_tcp4(doc) -> - []; traffic_send_and_recv_chunks_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(traffic_send_and_recv_chunks_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, proto => tcp}, @@ -38399,10 +40520,6 @@ traffic_send_and_recv_chunks_tcp4(_Config) when is_list(_Config) -> %% Second, send in a bunch of "small" chunks, and read in one "big" chunk. %% Socket is IPv6. -traffic_send_and_recv_chunks_tcp6(suite) -> - []; -traffic_send_and_recv_chunks_tcp6(doc) -> - []; traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(traffic_send_and_recv_chunks_tcp6, @@ -38421,10 +40538,6 @@ traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) -> %% Second, send in a bunch of "small" chunks, and read in one "big" chunk. %% Socket is UNix Domain (Stream) socket. -traffic_send_and_recv_chunks_tcpL(suite) -> - []; -traffic_send_and_recv_chunks_tcpL(doc) -> - []; traffic_send_and_recv_chunks_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(30)), tc_try(traffic_send_and_recv_chunks_tcp6, @@ -38732,15 +40845,9 @@ traffic_send_and_recv_chunks_tcp(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, client) of - {ok, Node} -> - ?SEV_IPRINT("(remote) client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end + cmd => fun(State) -> + {Peer, Node} = ?START_NODE("client"), + {ok, State#{peer => Peer, node => Node}} end}, #{desc => "monitor client node", cmd => fun(#{node := Node} = _State) -> @@ -39104,9 +41211,9 @@ traffic_send_and_recv_chunks_tcp(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -39352,7 +41459,7 @@ traffic_snr_tcp_client(Parent) -> traffic_snr_tcp_client_send_loop(Parent, Sock) -> case ?SEV_AWAIT_CONTINUE(Parent, parent, send) of - {ok, stop} -> % Breakes the loop + {ok, stop} -> % Breaks the loop ?SEV_ANNOUNCE_READY(Parent, send, ok), ok; {ok, Data} -> @@ -39457,15 +41564,12 @@ traffic_snr_tcp_client_await_terminate(Parent) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv4. -traffic_ping_pong_small_send_and_recv_tcp4(suite) -> - []; -traffic_ping_pong_small_send_and_recv_tcp4(doc) -> - []; traffic_ping_pong_small_send_and_recv_tcp4(Config) when is_list(Config) -> ?TT(?SECS(15)), Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_send_and_recv_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, proto => tcp, @@ -39485,10 +41589,6 @@ traffic_ping_pong_small_send_and_recv_tcp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv6. -traffic_ping_pong_small_send_and_recv_tcp6(suite) -> - []; -traffic_ping_pong_small_send_and_recv_tcp6(doc) -> - []; traffic_ping_pong_small_send_and_recv_tcp6(Config) when is_list(Config) -> ?TT(?SECS(15)), Msg = l2b(?TPP_SMALL), @@ -39513,10 +41613,6 @@ traffic_ping_pong_small_send_and_recv_tcp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for Unix Domain (stream) socket. -traffic_ping_pong_small_send_and_recv_tcpL(suite) -> - []; -traffic_ping_pong_small_send_and_recv_tcpL(doc) -> - []; traffic_ping_pong_small_send_and_recv_tcpL(Config) when is_list(Config) -> ?TT(?SECS(15)), Msg = l2b(?TPP_SMALL), @@ -39541,14 +41637,11 @@ traffic_ping_pong_small_send_and_recv_tcpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv4. -traffic_ping_pong_medium_send_and_recv_tcp4(suite) -> - []; -traffic_ping_pong_medium_send_and_recv_tcp4(doc) -> - []; traffic_ping_pong_medium_send_and_recv_tcp4(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_send_and_recv_tcp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(30)), InitState = #{domain => inet, @@ -39568,10 +41661,6 @@ traffic_ping_pong_medium_send_and_recv_tcp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv6. -traffic_ping_pong_medium_send_and_recv_tcp6(suite) -> - []; -traffic_ping_pong_medium_send_and_recv_tcp6(doc) -> - []; traffic_ping_pong_medium_send_and_recv_tcp6(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), @@ -39597,10 +41686,6 @@ traffic_ping_pong_medium_send_and_recv_tcp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for Unix Domain (stream) socket. -traffic_ping_pong_medium_send_and_recv_tcpL(suite) -> - []; -traffic_ping_pong_medium_send_and_recv_tcpL(doc) -> - []; traffic_ping_pong_medium_send_and_recv_tcpL(Config) when is_list(Config) -> ?TT(?SECS(30)), Msg = l2b(?TPP_MEDIUM), @@ -39626,16 +41711,13 @@ traffic_ping_pong_medium_send_and_recv_tcpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for IPv4. -traffic_ping_pong_large_send_and_recv_tcp4(suite) -> - []; -traffic_ping_pong_large_send_and_recv_tcp4(doc) -> - []; traffic_ping_pong_large_send_and_recv_tcp4(Config) when is_list(Config) -> ?TT(?SECS(60)), Msg = l2b(?TPP_LARGE), Num = ?TPP_NUM(Config, ?TPP_LARGE_NUM), tc_try(traffic_ping_pong_large_send_and_recv_tcp4, - fun() -> is_old_fedora16(), + fun() -> has_support_ipv4(), + is_old_fedora16(), is_slow_ubuntu(Config) end, fun() -> InitState = #{domain => inet, @@ -39655,10 +41737,6 @@ traffic_ping_pong_large_send_and_recv_tcp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for IPv6. -traffic_ping_pong_large_send_and_recv_tcp6(suite) -> - []; -traffic_ping_pong_large_send_and_recv_tcp6(doc) -> - []; traffic_ping_pong_large_send_and_recv_tcp6(Config) when is_list(Config) -> ?TT(?SECS(60)), Msg = l2b(?TPP_LARGE), @@ -39686,10 +41764,6 @@ traffic_ping_pong_large_send_and_recv_tcp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for UNix Domain (stream) socket. -traffic_ping_pong_large_send_and_recv_tcpL(suite) -> - []; -traffic_ping_pong_large_send_and_recv_tcpL(doc) -> - []; traffic_ping_pong_large_send_and_recv_tcpL(Config) when is_list(Config) -> ?TT(?SECS(60)), Msg = l2b(?TPP_LARGE), @@ -39747,7 +41821,7 @@ is_old_fedora16(_) -> %% not actually needed. %% The host in question is a Ubuntu 20.04... is_slow_ubuntu(Config) -> - case lookup(esock_factor, 1, Config) of + case lookup(kernel_factor, 1, Config) of F when is_integer(F) andalso (F > 1) -> case os:type() of {unix, linux} -> @@ -39774,14 +41848,11 @@ is_slow_ubuntu(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv4. -traffic_ping_pong_small_sendto_and_recvfrom_udp4(suite) -> - []; -traffic_ping_pong_small_sendto_and_recvfrom_udp4(doc) -> - []; traffic_ping_pong_small_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(45)), InitState = #{domain => inet, @@ -39801,10 +41872,6 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv6. -traffic_ping_pong_small_sendto_and_recvfrom_udp6(suite) -> - []; -traffic_ping_pong_small_sendto_and_recvfrom_udp6(doc) -> - []; traffic_ping_pong_small_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), @@ -39830,15 +41897,14 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for Unix Domain (dgram) socket. -traffic_ping_pong_small_sendto_and_recvfrom_udpL(suite) -> - []; -traffic_ping_pong_small_sendto_and_recvfrom_udpL(doc) -> - []; traffic_ping_pong_small_sendto_and_recvfrom_udpL(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> ?TT(?SECS(45)), InitState = #{domain => local, @@ -39859,14 +41925,11 @@ traffic_ping_pong_small_sendto_and_recvfrom_udpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv4. -traffic_ping_pong_medium_sendto_and_recvfrom_udp4(suite) -> - []; -traffic_ping_pong_medium_sendto_and_recvfrom_udp4(doc) -> - []; traffic_ping_pong_medium_sendto_and_recvfrom_udp4(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendto_and_recvfrom_udp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(45)), InitState = #{domain => inet, @@ -39886,10 +41949,6 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp4(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv6. -traffic_ping_pong_medium_sendto_and_recvfrom_udp6(suite) -> - []; -traffic_ping_pong_medium_sendto_and_recvfrom_udp6(doc) -> - []; traffic_ping_pong_medium_sendto_and_recvfrom_udp6(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), @@ -39915,15 +41974,14 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp6(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for Unix Domain (dgram) socket. -traffic_ping_pong_medium_sendto_and_recvfrom_udpL(suite) -> - []; -traffic_ping_pong_medium_sendto_and_recvfrom_udpL(doc) -> - []; traffic_ping_pong_medium_sendto_and_recvfrom_udpL(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendto_and_recvfrom_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> ?TT(?SECS(45)), InitState = #{domain => local, @@ -39944,14 +42002,14 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udpL(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv4. -traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> ?TT(?SECS(20)), InitState = #{domain => inet, @@ -39971,15 +42029,14 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv6. -traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6, - fun() -> has_support_ipv6() end, + fun() -> + is_not_windows(), + has_support_ipv6() + end, fun() -> ?TT(?SECS(20)), InitState = #{domain => inet6, @@ -39999,15 +42056,14 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for Unix Domain (stream) socket. -traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + is_not_windows(), + has_support_unix_domain_socket() + end, fun() -> ?TT(?SECS(20)), InitState = #{domain => local, @@ -40027,14 +42083,14 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv4. -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4, + fun() -> + is_not_windows(), + has_support_ipv4() + end, fun() -> ?TT(?SECS(30)), InitState = #{domain => inet, @@ -40054,15 +42110,14 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv6. -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6, - fun() -> has_support_ipv6() end, + fun() -> + is_not_windows(), + has_support_ipv6() + end, fun() -> ?TT(?SECS(30)), InitState = #{domain => inet6, @@ -40082,15 +42137,14 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for Unix Domain (stream) socket. -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + is_not_windows(), + has_support_unix_domain_socket() + end, fun() -> ?TT(?SECS(30)), InitState = #{domain => local, @@ -40110,15 +42164,15 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for IPv4. -traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4(suite) -> - []; -traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4(doc) -> - []; traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) -> Msg = l2b(?TPP_LARGE), Num = ?TPP_NUM(Config, ?TPP_LARGE_NUM), tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4, - fun() -> traffic_ping_pong_large_sendmsg_and_recvmsg_cond() end, + fun() -> + is_not_windows(), + has_support_ipv4(), + traffic_ping_pong_large_sendmsg_and_recvmsg_cond() + end, fun() -> ?TT(?SECS(60)), InitState = #{domain => inet, @@ -40148,15 +42202,12 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_cond(_, _) -> %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for IPv6. -traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(suite) -> - []; -traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(doc) -> - []; traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> Msg = l2b(?TPP_LARGE), Num = ?TPP_NUM(Config, ?TPP_LARGE_NUM), tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6, fun() -> + is_not_windows(), has_support_ipv6(), traffic_ping_pong_large_sendmsg_and_recvmsg_cond() end, @@ -40180,15 +42231,14 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'large' message test case, for Unix Domain (stream) socket. -traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(suite) -> - []; -traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(doc) -> - []; traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) -> Msg = l2b(?TPP_LARGE), Num = ?TPP_NUM(Config, ?TPP_LARGE_NUM), tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + is_not_windows(), + has_support_unix_domain_socket() + end, fun() -> ?TT(?SECS(60)), InitState = #{domain => local, @@ -40209,14 +42259,11 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv4. -traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(60)), InitState = #{domain => inet, @@ -40236,10 +42283,6 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for IPv6. -traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), @@ -40264,15 +42307,14 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'small' message test case, for Unix Domain (dgram) socket. -traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(suite) -> - []; -traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(doc) -> - []; traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(Config) when is_list(Config) -> Msg = l2b(?TPP_SMALL), Num = ?TPP_NUM(Config, ?TPP_SMALL_NUM), tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> ?TT(?SECS(60)), InitState = #{domain => local, @@ -40292,14 +42334,11 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(Config) when is_list(Config) -> %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv4. -traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4, + fun() -> has_support_ipv4() end, fun() -> ?TT(?SECS(60)), InitState = #{domain => inet, @@ -40319,10 +42358,6 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for IPv6. -traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), @@ -40348,15 +42383,14 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(Config) when is_list(Config) - %% repeated a set number of times (more times the small the message). %% This is the 'medium' message test case, for Unix Domain (dgram) socket. -traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(suite) -> - []; -traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(doc) -> - []; traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(Config) when is_list(Config) -> Msg = l2b(?TPP_MEDIUM), Num = ?TPP_NUM(Config, ?TPP_MEDIUM_NUM), tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL, - fun() -> has_support_unix_domain_socket() end, + fun() -> + has_support_unix_domain_socket(), + is_not_windows() + end, fun() -> ?TT(?SECS(60)), InitState = #{domain => local, @@ -40431,7 +42465,7 @@ traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState) -> traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) -> Fun = fun(Sock) -> {ok, RcvSz} = socket:getopt(Sock, socket, rcvbuf), - ?SEV_IPRINT("RcvBuf is ~p (needs atleast ~p)", + ?SEV_IPRINT("RcvBuf is ~p (needs at least ~p)", [RcvSz, 16+size(Msg)]), if (RcvSz < size(Msg)) -> NewRcvSz = 1024+size(Msg), @@ -40449,7 +42483,7 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) -> ok end, {ok, SndSz} = socket:getopt(Sock, socket, sndbuf), - ?SEV_IPRINT("SndBuf is ~p (needs atleast ~p)", + ?SEV_IPRINT("SndBuf is ~p (needs at least ~p)", [SndSz, 16+size(Msg)]), if (SndSz < size(Msg)) -> NewSndSz = 1024+size(Msg), @@ -40466,7 +42500,12 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) -> true -> ok end, - ok = socket:setopt(Sock, otp, rcvbuf, {12, 1024}) + case os:type() of + {win32, nt} -> + ok = socket:setopt(Sock, otp, rcvbuf, 12*1024); + _ -> + ok = socket:setopt(Sock, otp, rcvbuf, {12, 1024}) + end end, traffic_ping_pong_send_and_receive_tcp2(InitState#{buf_init => Fun}). @@ -40681,15 +42720,9 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, client) of - {ok, Node} -> - ?SEV_IPRINT("(remote) client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end + cmd => fun(State) -> + {Peer, Node} = ?START_NODE("client"), + {ok, State#{peer => Peer, node => Node}} end}, #{desc => "monitor client node", cmd => fun(#{node := Node} = _State) -> @@ -40834,9 +42867,9 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -40989,36 +43022,63 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) -> {CSent, CReceived, _, CStart, CStop} = CRes, STime = tdiff(SStart, SStop), CTime = tdiff(CStart, CStop), - %% Note that the sizes we are counting is only - %% the "data" part of the messages. There is also - %% fixed header for each message, which of cource - %% is small for the large messages, but comparatively - %% big for the small messages! - ?SEV_IPRINT("Results: ~w messages exchanged" - "~n Server: ~w msec" - "~n ~.2f msec/message (roundtrip)" - "~n ~.2f messages/msec (roundtrip)" - "~n ~w bytes/msec sent" - "~n ~w bytes/msec received" - "~n Client: ~w msec" - "~n ~.2f msec/message (roundtrip)" - "~n ~.2f messages/msec (roundtrip)" - "~n ~w bytes/msec sent" - "~n ~w bytes/msec received", + ?SEV_IPRINT("process result data:" + "~n Num: ~p" + "~n Server Sent: ~p" + "~n Server Recv: ~p" + "~n Server Start: ~p" + "~n Server Stop: ~p" + "~n Server Time: ~p" + "~n Client Sent: ~p" + "~n Client Recv: ~p" + "~n Client Start: ~p" + "~n Client Stop: ~p" + "~n Client Time: ~p", [Num, + SSent, SReceived, SStart, SStop, STime, - STime / Num, - Num / STime, - SSent div STime, - SReceived div STime, - CTime, - CTime / Num, - Num / CTime, - CSent div CTime, - CReceived div CTime]), - State1 = maps:remove(server_result, State), - State2 = maps:remove(client_result, State1), - {ok, State2} + CSent, CReceived, CStart, CStop, + CTime]), + if + (STime =:= 0) orelse + (CTime =:= 0) -> + {skip, + ?F("Invalid exec time(s): ~w , ~w", + [STime, CTime])}; + true -> + %% Note that the sizes we are counting is + %% only the "data" part of the messages. + %% There is also fixed header for each + %% message, which of course is small for + %% the large messages, but comparatively + %% big for the small messages! + ?SEV_IPRINT( + "Results: ~w messages exchanged" + "~n Server: ~w msec" + "~n ~.2f msec/message (roundtrip)" + "~n ~.2f messages/msec (roundtrip)" + "~n ~w bytes/msec sent" + "~n ~w bytes/msec received" + "~n Client: ~w msec" + "~n ~.2f msec/message (roundtrip)" + "~n ~.2f messages/msec (roundtrip)" + "~n ~w bytes/msec sent" + "~n ~w bytes/msec received", + [Num, + STime, + STime / Num, + Num / STime, + SSent div STime, + SReceived div STime, + CTime, + CTime / Num, + Num / CTime, + CSent div CTime, + CReceived div CTime]), + State1 = maps:remove(server_result, State), + State2 = maps:remove(client_result, State1), + {ok, State2} + end end}, %% Terminations @@ -41393,14 +43453,6 @@ tpp_tcp_send_msg(Sock, Send, Msg, AccSz) when is_binary(Msg) -> %% size_of_iovec([B|IOVec], Sz) -> %% size_of_iovec(IOVec, Sz+size(B)). -mq() -> - mq(self()). - -mq(Pid) when is_pid(Pid) -> - Tag = messages, - {Tag, Msgs} = process_info(Pid, Tag), - Msgs. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -41674,15 +43726,9 @@ traffic_ping_pong_send_and_receive_udp2(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, client) of - {ok, Node} -> - ?SEV_IPRINT("(remote) client node ~p started", - [Node]), - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end + cmd => fun(State) -> + {Peer, Node} = ?START_NODE("client"), + {ok, State#{peer => Peer, node => Node}} end}, #{desc => "monitor client node", cmd => fun(#{node := Node} = _State) -> @@ -41783,9 +43829,9 @@ traffic_ping_pong_send_and_receive_udp2(InitState) -> {ok, State1} end}, #{desc => "stop client node", - cmd => fun(#{node := Node} = State) -> + cmd => fun(#{peer := Peer} = State) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -41915,25 +43961,33 @@ traffic_ping_pong_send_and_receive_udp2(InitState) -> num := Num} = State) -> {CSent, CReceived, CStart, CStop} = CRes, CTime = tdiff(CStart, CStop), - %% Note that the sizes we are counting is only - %% the "data" part of the messages. There is also - %% fixed header for each message, which of cource - %% is small for the large messages, but comparatively - %% big for the small messages! - ?SEV_IPRINT("Results: ~w messages exchanged" - "~n Client: ~w msec" - "~n ~.2f msec/message (roundtrip)" - "~n ~.2f messages/msec (roundtrip)" - "~n ~w bytes/msec sent" - "~n ~w bytes/msec received", - [Num, - CTime, - CTime / Num, - Num / CTime, - CSent div CTime, - CReceived div CTime]), - State1 = maps:remove(client_result, State), - {ok, State1} + if + (CTime =:= 0) -> + {skip, + ?F("Invalid exec time: ~w ", [CTime])}; + true -> + %% Note that the sizes we are counting is + %% only the "data" part of the messages. + %% There is also fixed header for each + %% message, which of course is small for + %% the large messages, but comparatively + %% big for the small messages! + ?SEV_IPRINT( + "Results: ~w messages exchanged" + "~n Client: ~w msec" + "~n ~.2f msec/message (roundtrip)" + "~n ~.2f messages/msec (roundtrip)" + "~n ~w bytes/msec sent" + "~n ~w bytes/msec received", + [Num, + CTime, + CTime / Num, + Num / CTime, + CSent div CTime, + CReceived div CTime]), + State1 = maps:remove(client_result, State), + {ok, State1} + end end}, %% Terminations @@ -42194,7 +44248,7 @@ tpp_udp_recv(Sock, Recv, Tag) -> ERROR catch C:E:S -> - {error, {catched, C, E, S}} + {error, {caught, C, E, S}} end. tpp_udp_send_req(Sock, Send, Data, Dest) -> @@ -42306,18 +44360,14 @@ tpp_udp_sock_close(Sock, Path) -> %% Domain: inet %% -ttest_sgenf_cgenf_small_tcp4(suite) -> - []; -ttest_sgenf_cgenf_small_tcp4(doc) -> - []; ttest_sgenf_cgenf_small_tcp4(Config) when is_list(Config) -> - Runtime = which_ttest_runtime(Config), + Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_small_tcp4, Runtime, inet, gen, false, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42330,10 +44380,6 @@ ttest_sgenf_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgenf_small_tcp6(suite) -> - []; -ttest_sgenf_cgenf_small_tcp6(doc) -> - []; ttest_sgenf_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_small_tcp6, @@ -42341,7 +44387,7 @@ ttest_sgenf_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42354,10 +44400,6 @@ ttest_sgenf_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgenf_medium_tcp4(suite) -> - []; -ttest_sgenf_cgenf_medium_tcp4(doc) -> - []; ttest_sgenf_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_medium_tcp4, @@ -42365,7 +44407,7 @@ ttest_sgenf_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42378,10 +44420,6 @@ ttest_sgenf_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgenf_medium_tcp6(suite) -> - []; -ttest_sgenf_cgenf_medium_tcp6(doc) -> - []; ttest_sgenf_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_medium_tcp6, @@ -42389,7 +44427,7 @@ ttest_sgenf_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42402,10 +44440,6 @@ ttest_sgenf_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgenf_large_tcp4(suite) -> - []; -ttest_sgenf_cgenf_large_tcp4(doc) -> - []; ttest_sgenf_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_large_tcp4, @@ -42413,7 +44447,7 @@ ttest_sgenf_cgenf_large_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42426,10 +44460,6 @@ ttest_sgenf_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgenf_large_tcp6(suite) -> - []; -ttest_sgenf_cgenf_large_tcp6(doc) -> - []; ttest_sgenf_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgenf_large_tcp6, @@ -42437,7 +44467,7 @@ ttest_sgenf_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42450,10 +44480,6 @@ ttest_sgenf_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgeno_small_tcp4(suite) -> - []; -ttest_sgenf_cgeno_small_tcp4(doc) -> - []; ttest_sgenf_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_small_tcp4, @@ -42461,7 +44487,7 @@ ttest_sgenf_cgeno_small_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42474,10 +44500,6 @@ ttest_sgenf_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgeno_small_tcp6(suite) -> - []; -ttest_sgenf_cgeno_small_tcp6(doc) -> - []; ttest_sgenf_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_small_tcp6, @@ -42485,7 +44507,7 @@ ttest_sgenf_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42498,10 +44520,6 @@ ttest_sgenf_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgeno_medium_tcp4(suite) -> - []; -ttest_sgenf_cgeno_medium_tcp4(doc) -> - []; ttest_sgenf_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_medium_tcp4, @@ -42509,7 +44527,7 @@ ttest_sgenf_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42522,10 +44540,6 @@ ttest_sgenf_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgeno_medium_tcp6(suite) -> - []; -ttest_sgenf_cgeno_medium_tcp6(doc) -> - []; ttest_sgenf_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_medium_tcp6, @@ -42533,7 +44547,7 @@ ttest_sgenf_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42546,10 +44560,6 @@ ttest_sgenf_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgeno_large_tcp4(suite) -> - []; -ttest_sgenf_cgeno_large_tcp4(doc) -> - []; ttest_sgenf_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_large_tcp4, @@ -42557,7 +44567,7 @@ ttest_sgenf_cgeno_large_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42570,10 +44580,6 @@ ttest_sgenf_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgeno_large_tcp6(suite) -> - []; -ttest_sgenf_cgeno_large_tcp6(doc) -> - []; ttest_sgenf_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_large_tcp6, @@ -42581,7 +44587,7 @@ ttest_sgenf_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42594,10 +44600,6 @@ ttest_sgenf_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgent_small_tcp4(suite) -> - []; -ttest_sgenf_cgent_small_tcp4(doc) -> - []; ttest_sgenf_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgent_small_tcp4, @@ -42605,7 +44607,7 @@ ttest_sgenf_cgent_small_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42618,10 +44620,6 @@ ttest_sgenf_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgent_small_tcp6(suite) -> - []; -ttest_sgenf_cgent_small_tcp6(doc) -> - []; ttest_sgenf_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgeno_small_tcp6, @@ -42629,7 +44627,7 @@ ttest_sgenf_cgent_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42642,10 +44640,6 @@ ttest_sgenf_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgent_medium_tcp4(suite) -> - []; -ttest_sgenf_cgent_medium_tcp4(doc) -> - []; ttest_sgenf_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgent_medium_tcp4, @@ -42653,7 +44647,7 @@ ttest_sgenf_cgent_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42666,10 +44660,6 @@ ttest_sgenf_cgent_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgent_medium_tcp6(suite) -> - []; -ttest_sgenf_cgent_medium_tcp6(doc) -> - []; ttest_sgenf_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgent_medium_tcp6, @@ -42677,7 +44667,7 @@ ttest_sgenf_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42690,10 +44680,6 @@ ttest_sgenf_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_cgent_large_tcp4(suite) -> - []; -ttest_sgenf_cgent_large_tcp4(doc) -> - []; ttest_sgenf_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgent_large_tcp4, @@ -42701,7 +44687,7 @@ ttest_sgenf_cgent_large_tcp4(Config) when is_list(Config) -> inet, gen, false, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42714,10 +44700,6 @@ ttest_sgenf_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_cgent_large_tcp6(suite) -> - []; -ttest_sgenf_cgent_large_tcp6(doc) -> - []; ttest_sgenf_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_cgent_large_tcp6, @@ -42725,7 +44707,7 @@ ttest_sgenf_cgent_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42738,10 +44720,6 @@ ttest_sgenf_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockf_small_tcp4(suite) -> - []; -ttest_sgenf_csockf_small_tcp4(doc) -> - []; ttest_sgenf_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_small_tcp4, @@ -42749,7 +44727,7 @@ ttest_sgenf_csockf_small_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42762,10 +44740,6 @@ ttest_sgenf_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockf_small_tcp6(suite) -> - []; -ttest_sgenf_csockf_small_tcp6(doc) -> - []; ttest_sgenf_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_small_tcp6, @@ -42773,7 +44747,7 @@ ttest_sgenf_csockf_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42786,10 +44760,6 @@ ttest_sgenf_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockf_medium_tcp4(suite) -> - []; -ttest_sgenf_csockf_medium_tcp4(doc) -> - []; ttest_sgenf_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_medium_tcp4, @@ -42797,7 +44767,7 @@ ttest_sgenf_csockf_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42810,10 +44780,6 @@ ttest_sgenf_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockf_medium_tcp6(suite) -> - []; -ttest_sgenf_csockf_medium_tcp6(doc) -> - []; ttest_sgenf_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_medium_tcp6, @@ -42821,7 +44787,7 @@ ttest_sgenf_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42834,10 +44800,6 @@ ttest_sgenf_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockf_large_tcp4(suite) -> - []; -ttest_sgenf_csockf_large_tcp4(doc) -> - []; ttest_sgenf_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_large_tcp4, @@ -42845,7 +44807,7 @@ ttest_sgenf_csockf_large_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -42858,10 +44820,6 @@ ttest_sgenf_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockf_large_tcp6(suite) -> - []; -ttest_sgenf_csockf_large_tcp6(doc) -> - []; ttest_sgenf_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockf_large_tcp6, @@ -42869,7 +44827,127 @@ ttest_sgenf_csockf_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: small (=1) +%% Domain: inet +%% + +ttest_sgsf_csockf_small_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + gs, false, + sock, false, + 1, ttest_small_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: small (=1) +%% Domain: inet6 +%% + +ttest_sgsf_csockf_small_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + gs, false, + sock, false, + 1, ttest_small_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: medium (=2) +%% Domain: inet +%% + +ttest_sgsf_csockf_medium_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + gs, false, + sock, false, + 2, ttest_medium_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: medium (=2) +%% Domain: inet6 +%% + +ttest_sgsf_csockf_medium_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + gs, false, + sock, false, + 2, ttest_medium_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: large (=3) +%% Domain: inet +%% + +ttest_sgsf_csockf_large_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + gs, false, + sock, false, + 3, ttest_large_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = gen_tcp(socket), Active = false +%% Client: Transport = socket(tcp), Active = false +%% Message Size: large (=3) +%% Domain: inet6 +%% + +ttest_sgsf_csockf_large_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + gs, false, + sock, false, + 3, ttest_large_max_outstanding(Config)). @@ -42882,10 +44960,6 @@ ttest_sgenf_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csocko_small_tcp4(suite) -> - []; -ttest_sgenf_csocko_small_tcp4(doc) -> - []; ttest_sgenf_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_small_tcp4, @@ -42893,7 +44967,7 @@ ttest_sgenf_csocko_small_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42906,10 +44980,6 @@ ttest_sgenf_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csocko_small_tcp6(suite) -> - []; -ttest_sgenf_csocko_small_tcp6(doc) -> - []; ttest_sgenf_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_small_tcp6, @@ -42917,7 +44987,7 @@ ttest_sgenf_csocko_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -42930,10 +45000,6 @@ ttest_sgenf_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csocko_medium_tcp4(suite) -> - []; -ttest_sgenf_csocko_medium_tcp4(doc) -> - []; ttest_sgenf_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_medium_tcp4, @@ -42941,7 +45007,7 @@ ttest_sgenf_csocko_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42954,10 +45020,6 @@ ttest_sgenf_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csocko_medium_tcp6(suite) -> - []; -ttest_sgenf_csocko_medium_tcp6(doc) -> - []; ttest_sgenf_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_medium_tcp6, @@ -42965,7 +45027,7 @@ ttest_sgenf_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -42978,10 +45040,6 @@ ttest_sgenf_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csocko_large_tcp4(suite) -> - []; -ttest_sgenf_csocko_large_tcp4(doc) -> - []; ttest_sgenf_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_large_tcp4, @@ -42989,7 +45047,7 @@ ttest_sgenf_csocko_large_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43002,10 +45060,6 @@ ttest_sgenf_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csocko_large_tcp6(suite) -> - []; -ttest_sgenf_csocko_large_tcp6(doc) -> - []; ttest_sgenf_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_large_tcp6, @@ -43013,7 +45067,7 @@ ttest_sgenf_csocko_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43026,10 +45080,6 @@ ttest_sgenf_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockt_small_tcp4(suite) -> - []; -ttest_sgenf_csockt_small_tcp4(doc) -> - []; ttest_sgenf_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockt_small_tcp4, @@ -43037,7 +45087,7 @@ ttest_sgenf_csockt_small_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43050,10 +45100,6 @@ ttest_sgenf_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockt_small_tcp6(suite) -> - []; -ttest_sgenf_csockt_small_tcp6(doc) -> - []; ttest_sgenf_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csocko_small_tcp6, @@ -43061,7 +45107,7 @@ ttest_sgenf_csockt_small_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43074,10 +45120,6 @@ ttest_sgenf_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockt_medium_tcp4(suite) -> - []; -ttest_sgenf_csockt_medium_tcp4(doc) -> - []; ttest_sgenf_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockt_medium_tcp4, @@ -43085,7 +45127,7 @@ ttest_sgenf_csockt_medium_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43098,10 +45140,6 @@ ttest_sgenf_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockt_medium_tcp6(suite) -> - []; -ttest_sgenf_csockt_medium_tcp6(doc) -> - []; ttest_sgenf_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockt_medium_tcp6, @@ -43109,7 +45147,7 @@ ttest_sgenf_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43122,10 +45160,6 @@ ttest_sgenf_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgenf_csockt_large_tcp4(suite) -> - []; -ttest_sgenf_csockt_large_tcp4(doc) -> - []; ttest_sgenf_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockt_large_tcp4, @@ -43133,7 +45167,7 @@ ttest_sgenf_csockt_large_tcp4(Config) when is_list(Config) -> inet, gen, false, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43146,10 +45180,6 @@ ttest_sgenf_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgenf_csockt_large_tcp6(suite) -> - []; -ttest_sgenf_csockt_large_tcp6(doc) -> - []; ttest_sgenf_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgenf_csockt_large_tcp6, @@ -43157,7 +45187,7 @@ ttest_sgenf_csockt_large_tcp6(Config) when is_list(Config) -> inet6, gen, false, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43170,10 +45200,6 @@ ttest_sgenf_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgenf_small_tcp4(suite) -> - []; -ttest_sgeno_cgenf_small_tcp4(doc) -> - []; ttest_sgeno_cgenf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_small_tcp4, @@ -43181,7 +45207,7 @@ ttest_sgeno_cgenf_small_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43194,10 +45220,6 @@ ttest_sgeno_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgenf_small_tcp6(suite) -> - []; -ttest_sgeno_cgenf_small_tcp6(doc) -> - []; ttest_sgeno_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_small_tcp6, @@ -43205,7 +45227,7 @@ ttest_sgeno_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43218,10 +45240,6 @@ ttest_sgeno_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgenf_medium_tcp4(suite) -> - []; -ttest_sgeno_cgenf_medium_tcp4(doc) -> - []; ttest_sgeno_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_medium_tcp4, @@ -43229,7 +45247,7 @@ ttest_sgeno_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43242,10 +45260,6 @@ ttest_sgeno_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgenf_medium_tcp6(suite) -> - []; -ttest_sgeno_cgenf_medium_tcp6(doc) -> - []; ttest_sgeno_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_medium_tcp6, @@ -43253,7 +45267,7 @@ ttest_sgeno_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43266,10 +45280,6 @@ ttest_sgeno_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgenf_large_tcp4(suite) -> - []; -ttest_sgeno_cgenf_large_tcp4(doc) -> - []; ttest_sgeno_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_large_tcp4, @@ -43277,7 +45287,7 @@ ttest_sgeno_cgenf_large_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43290,10 +45300,6 @@ ttest_sgeno_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgenf_large_tcp6(suite) -> - []; -ttest_sgeno_cgenf_large_tcp6(doc) -> - []; ttest_sgeno_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgenf_large_tcp6, @@ -43301,7 +45307,7 @@ ttest_sgeno_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43314,10 +45320,6 @@ ttest_sgeno_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgeno_small_tcp4(suite) -> - []; -ttest_sgeno_cgeno_small_tcp4(doc) -> - []; ttest_sgeno_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_small_tcp4, @@ -43325,7 +45327,7 @@ ttest_sgeno_cgeno_small_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43338,10 +45340,6 @@ ttest_sgeno_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgeno_small_tcp6(suite) -> - []; -ttest_sgeno_cgeno_small_tcp6(doc) -> - []; ttest_sgeno_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_small_tcp6, @@ -43349,7 +45347,7 @@ ttest_sgeno_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43362,10 +45360,6 @@ ttest_sgeno_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgeno_medium_tcp4(suite) -> - []; -ttest_sgeno_cgeno_medium_tcp4(doc) -> - []; ttest_sgeno_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_medium_tcp4, @@ -43373,7 +45367,7 @@ ttest_sgeno_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43386,10 +45380,6 @@ ttest_sgeno_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgeno_medium_tcp6(suite) -> - []; -ttest_sgeno_cgeno_medium_tcp6(doc) -> - []; ttest_sgeno_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_medium_tcp6, @@ -43397,7 +45387,7 @@ ttest_sgeno_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43410,10 +45400,6 @@ ttest_sgeno_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgeno_large_tcp4(suite) -> - []; -ttest_sgeno_cgeno_large_tcp4(doc) -> - []; ttest_sgeno_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_large_tcp4, @@ -43421,7 +45407,7 @@ ttest_sgeno_cgeno_large_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43434,10 +45420,6 @@ ttest_sgeno_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgeno_large_tcp6(suite) -> - []; -ttest_sgeno_cgeno_large_tcp6(doc) -> - []; ttest_sgeno_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_large_tcp6, @@ -43445,7 +45427,7 @@ ttest_sgeno_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43458,10 +45440,6 @@ ttest_sgeno_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgent_small_tcp4(suite) -> - []; -ttest_sgeno_cgent_small_tcp4(doc) -> - []; ttest_sgeno_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgent_small_tcp4, @@ -43469,7 +45447,7 @@ ttest_sgeno_cgent_small_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43482,10 +45460,6 @@ ttest_sgeno_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgent_small_tcp6(suite) -> - []; -ttest_sgeno_cgent_small_tcp6(doc) -> - []; ttest_sgeno_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgeno_small_tcp6, @@ -43493,7 +45467,7 @@ ttest_sgeno_cgent_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43506,10 +45480,6 @@ ttest_sgeno_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgent_medium_tcp4(suite) -> - []; -ttest_sgeno_cgent_medium_tcp4(doc) -> - []; ttest_sgeno_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgent_medium_tcp4, @@ -43517,7 +45487,7 @@ ttest_sgeno_cgent_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43530,10 +45500,6 @@ ttest_sgeno_cgent_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgent_medium_tcp6(suite) -> - []; -ttest_sgeno_cgent_medium_tcp6(doc) -> - []; ttest_sgeno_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgent_medium_tcp6, @@ -43541,7 +45507,7 @@ ttest_sgeno_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43554,10 +45520,6 @@ ttest_sgeno_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_cgent_large_tcp4(suite) -> - []; -ttest_sgeno_cgent_large_tcp4(doc) -> - []; ttest_sgeno_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgent_large_tcp4, @@ -43565,7 +45527,7 @@ ttest_sgeno_cgent_large_tcp4(Config) when is_list(Config) -> inet, gen, once, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43578,10 +45540,6 @@ ttest_sgeno_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_cgent_large_tcp6(suite) -> - []; -ttest_sgeno_cgent_large_tcp6(doc) -> - []; ttest_sgeno_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_cgent_large_tcp6, @@ -43589,7 +45547,7 @@ ttest_sgeno_cgent_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43602,10 +45560,6 @@ ttest_sgeno_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockf_small_tcp4(suite) -> - []; -ttest_sgeno_csockf_small_tcp4(doc) -> - []; ttest_sgeno_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_small_tcp4, @@ -43613,7 +45567,7 @@ ttest_sgeno_csockf_small_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43626,10 +45580,6 @@ ttest_sgeno_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockf_small_tcp6(suite) -> - []; -ttest_sgeno_csockf_small_tcp6(doc) -> - []; ttest_sgeno_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_small_tcp6, @@ -43637,7 +45587,7 @@ ttest_sgeno_csockf_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43650,10 +45600,6 @@ ttest_sgeno_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockf_medium_tcp4(suite) -> - []; -ttest_sgeno_csockf_medium_tcp4(doc) -> - []; ttest_sgeno_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_medium_tcp4, @@ -43661,7 +45607,7 @@ ttest_sgeno_csockf_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43674,10 +45620,6 @@ ttest_sgeno_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockf_medium_tcp6(suite) -> - []; -ttest_sgeno_csockf_medium_tcp6(doc) -> - []; ttest_sgeno_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_medium_tcp6, @@ -43685,7 +45627,7 @@ ttest_sgeno_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43698,10 +45640,6 @@ ttest_sgeno_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockf_large_tcp4(suite) -> - []; -ttest_sgeno_csockf_large_tcp4(doc) -> - []; ttest_sgeno_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_large_tcp4, @@ -43709,7 +45647,7 @@ ttest_sgeno_csockf_large_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43722,10 +45660,6 @@ ttest_sgeno_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockf_large_tcp6(suite) -> - []; -ttest_sgeno_csockf_large_tcp6(doc) -> - []; ttest_sgeno_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockf_large_tcp6, @@ -43733,7 +45667,7 @@ ttest_sgeno_csockf_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43746,10 +45680,6 @@ ttest_sgeno_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csocko_small_tcp4(suite) -> - []; -ttest_sgeno_csocko_small_tcp4(doc) -> - []; ttest_sgeno_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_small_tcp4, @@ -43757,7 +45687,7 @@ ttest_sgeno_csocko_small_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43770,10 +45700,6 @@ ttest_sgeno_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csocko_small_tcp6(suite) -> - []; -ttest_sgeno_csocko_small_tcp6(doc) -> - []; ttest_sgeno_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_small_tcp6, @@ -43781,7 +45707,7 @@ ttest_sgeno_csocko_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43794,10 +45720,6 @@ ttest_sgeno_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csocko_medium_tcp4(suite) -> - []; -ttest_sgeno_csocko_medium_tcp4(doc) -> - []; ttest_sgeno_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_medium_tcp4, @@ -43805,7 +45727,7 @@ ttest_sgeno_csocko_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43818,10 +45740,6 @@ ttest_sgeno_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csocko_medium_tcp6(suite) -> - []; -ttest_sgeno_csocko_medium_tcp6(doc) -> - []; ttest_sgeno_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_medium_tcp6, @@ -43829,7 +45747,7 @@ ttest_sgeno_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43842,10 +45760,6 @@ ttest_sgeno_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csocko_large_tcp4(suite) -> - []; -ttest_sgeno_csocko_large_tcp4(doc) -> - []; ttest_sgeno_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_large_tcp4, @@ -43853,7 +45767,7 @@ ttest_sgeno_csocko_large_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43866,10 +45780,6 @@ ttest_sgeno_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csocko_large_tcp6(suite) -> - []; -ttest_sgeno_csocko_large_tcp6(doc) -> - []; ttest_sgeno_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_large_tcp6, @@ -43877,7 +45787,7 @@ ttest_sgeno_csocko_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -43890,10 +45800,6 @@ ttest_sgeno_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockt_small_tcp4(suite) -> - []; -ttest_sgeno_csockt_small_tcp4(doc) -> - []; ttest_sgeno_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockt_small_tcp4, @@ -43901,7 +45807,7 @@ ttest_sgeno_csockt_small_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43914,10 +45820,6 @@ ttest_sgeno_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockt_small_tcp6(suite) -> - []; -ttest_sgeno_csockt_small_tcp6(doc) -> - []; ttest_sgeno_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csocko_small_tcp6, @@ -43925,7 +45827,7 @@ ttest_sgeno_csockt_small_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -43938,10 +45840,6 @@ ttest_sgeno_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockt_medium_tcp4(suite) -> - []; -ttest_sgeno_csockt_medium_tcp4(doc) -> - []; ttest_sgeno_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockt_medium_tcp4, @@ -43949,7 +45847,7 @@ ttest_sgeno_csockt_medium_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43962,10 +45860,6 @@ ttest_sgeno_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockt_medium_tcp6(suite) -> - []; -ttest_sgeno_csockt_medium_tcp6(doc) -> - []; ttest_sgeno_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockt_medium_tcp6, @@ -43973,7 +45867,7 @@ ttest_sgeno_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -43986,10 +45880,6 @@ ttest_sgeno_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgeno_csockt_large_tcp4(suite) -> - []; -ttest_sgeno_csockt_large_tcp4(doc) -> - []; ttest_sgeno_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockt_large_tcp4, @@ -43997,7 +45887,7 @@ ttest_sgeno_csockt_large_tcp4(Config) when is_list(Config) -> inet, gen, once, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44010,10 +45900,6 @@ ttest_sgeno_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgeno_csockt_large_tcp6(suite) -> - []; -ttest_sgeno_csockt_large_tcp6(doc) -> - []; ttest_sgeno_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgeno_csockt_large_tcp6, @@ -44021,7 +45907,7 @@ ttest_sgeno_csockt_large_tcp6(Config) when is_list(Config) -> inet6, gen, once, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44034,10 +45920,6 @@ ttest_sgeno_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgenf_small_tcp4(suite) -> - []; -ttest_sgent_cgenf_small_tcp4(doc) -> - []; ttest_sgent_cgenf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_small_tcp4, @@ -44045,7 +45927,7 @@ ttest_sgent_cgenf_small_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44058,10 +45940,6 @@ ttest_sgent_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgenf_small_tcp6(suite) -> - []; -ttest_sgent_cgenf_small_tcp6(doc) -> - []; ttest_sgent_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_small_tcp6, @@ -44069,7 +45947,7 @@ ttest_sgent_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44082,10 +45960,6 @@ ttest_sgent_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgenf_medium_tcp4(suite) -> - []; -ttest_sgent_cgenf_medium_tcp4(doc) -> - []; ttest_sgent_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_medium_tcp4, @@ -44093,7 +45967,7 @@ ttest_sgent_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44106,10 +45980,6 @@ ttest_sgent_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgenf_medium_tcp6(suite) -> - []; -ttest_sgent_cgenf_medium_tcp6(doc) -> - []; ttest_sgent_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_medium_tcp6, @@ -44117,7 +45987,7 @@ ttest_sgent_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44130,10 +46000,6 @@ ttest_sgent_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgenf_large_tcp4(suite) -> - []; -ttest_sgent_cgenf_large_tcp4(doc) -> - []; ttest_sgent_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_large_tcp4, @@ -44141,7 +46007,7 @@ ttest_sgent_cgenf_large_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44154,10 +46020,6 @@ ttest_sgent_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgenf_large_tcp6(suite) -> - []; -ttest_sgent_cgenf_large_tcp6(doc) -> - []; ttest_sgent_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgenf_large_tcp6, @@ -44165,7 +46027,7 @@ ttest_sgent_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44178,10 +46040,6 @@ ttest_sgent_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgeno_small_tcp4(suite) -> - []; -ttest_sgent_cgeno_small_tcp4(doc) -> - []; ttest_sgent_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_small_tcp4, @@ -44189,7 +46047,7 @@ ttest_sgent_cgeno_small_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44202,10 +46060,6 @@ ttest_sgent_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgeno_small_tcp6(suite) -> - []; -ttest_sgent_cgeno_small_tcp6(doc) -> - []; ttest_sgent_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_small_tcp6, @@ -44213,7 +46067,7 @@ ttest_sgent_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44226,10 +46080,6 @@ ttest_sgent_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgeno_medium_tcp4(suite) -> - []; -ttest_sgent_cgeno_medium_tcp4(doc) -> - []; ttest_sgent_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_medium_tcp4, @@ -44237,7 +46087,7 @@ ttest_sgent_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44250,10 +46100,6 @@ ttest_sgent_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgeno_medium_tcp6(suite) -> - []; -ttest_sgent_cgeno_medium_tcp6(doc) -> - []; ttest_sgent_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_medium_tcp6, @@ -44261,7 +46107,7 @@ ttest_sgent_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44274,10 +46120,6 @@ ttest_sgent_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgeno_large_tcp4(suite) -> - []; -ttest_sgent_cgeno_large_tcp4(doc) -> - []; ttest_sgent_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_large_tcp4, @@ -44285,7 +46127,7 @@ ttest_sgent_cgeno_large_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44298,10 +46140,6 @@ ttest_sgent_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgeno_large_tcp6(suite) -> - []; -ttest_sgent_cgeno_large_tcp6(doc) -> - []; ttest_sgent_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_large_tcp6, @@ -44309,7 +46147,7 @@ ttest_sgent_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44322,10 +46160,6 @@ ttest_sgent_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgent_small_tcp4(suite) -> - []; -ttest_sgent_cgent_small_tcp4(doc) -> - []; ttest_sgent_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgent_small_tcp4, @@ -44333,7 +46167,7 @@ ttest_sgent_cgent_small_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44346,10 +46180,6 @@ ttest_sgent_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgent_small_tcp6(suite) -> - []; -ttest_sgent_cgent_small_tcp6(doc) -> - []; ttest_sgent_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgeno_small_tcp6, @@ -44357,7 +46187,7 @@ ttest_sgent_cgent_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44370,10 +46200,9 @@ ttest_sgent_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgent_medium_tcp4(suite) -> - []; -ttest_sgent_cgent_medium_tcp4(doc) -> - ["Server(gen,true), Client(gen,true), Domain=inet, msg=medium"]; +ttest_sgent_cgent_medium_tcp4() -> + [{doc, "Server(gen,true), Client(gen,true), Domain=inet, msg=medium"}]. + ttest_sgent_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgent_medium_tcp4, @@ -44381,7 +46210,7 @@ ttest_sgent_cgent_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44393,11 +46222,9 @@ ttest_sgent_cgent_medium_tcp4(Config) when is_list(Config) -> %% Message Size: medium (=2) %% Domain: inet6 %% +ttest_sgent_cgent_medium_tcp6() -> + [{doc, "Server(gen,true), Client(gen,true), Domain=inet6, msg=medium"}]. -ttest_sgent_cgent_medium_tcp6(suite) -> - []; -ttest_sgent_cgent_medium_tcp6(doc) -> - ["Server(gen,true), Client(gen,true), Domain=inet6, msg=medium"]; ttest_sgent_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgent_medium_tcp6, @@ -44405,7 +46232,7 @@ ttest_sgent_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44418,10 +46245,9 @@ ttest_sgent_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_cgent_large_tcp4(suite) -> - []; -ttest_sgent_cgent_large_tcp4(doc) -> - ["Server(gen,true), Client(gen,true), Domain=inet, msg=large"]; +ttest_sgent_cgent_large_tcp4() -> + [{doc, "Server(gen,true), Client(gen,true), Domain=inet, msg=large"}]. + ttest_sgent_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgent_large_tcp4, @@ -44429,7 +46255,7 @@ ttest_sgent_cgent_large_tcp4(Config) when is_list(Config) -> inet, gen, true, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44442,10 +46268,9 @@ ttest_sgent_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_cgent_large_tcp6(suite) -> - []; -ttest_sgent_cgent_large_tcp6(doc) -> - ["Server(gen,true), Client(gen,true), Domain=inet6, msg=large"]; +ttest_sgent_cgent_large_tcp6() -> + [{doc, "Server(gen,true), Client(gen,true), Domain=inet6, msg=large"}]. + ttest_sgent_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_cgent_large_tcp6, @@ -44453,7 +46278,7 @@ ttest_sgent_cgent_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44466,10 +46291,7 @@ ttest_sgent_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockf_small_tcp4(suite) -> - []; -ttest_sgent_csockf_small_tcp4(doc) -> - []; + ttest_sgent_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_small_tcp4, @@ -44477,7 +46299,7 @@ ttest_sgent_csockf_small_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44490,10 +46312,6 @@ ttest_sgent_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockf_small_tcp6(suite) -> - []; -ttest_sgent_csockf_small_tcp6(doc) -> - []; ttest_sgent_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_small_tcp6, @@ -44501,7 +46319,7 @@ ttest_sgent_csockf_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44514,10 +46332,6 @@ ttest_sgent_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockf_medium_tcp4(suite) -> - []; -ttest_sgent_csockf_medium_tcp4(doc) -> - []; ttest_sgent_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_medium_tcp4, @@ -44525,7 +46339,7 @@ ttest_sgent_csockf_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44538,10 +46352,6 @@ ttest_sgent_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockf_medium_tcp6(suite) -> - []; -ttest_sgent_csockf_medium_tcp6(doc) -> - []; ttest_sgent_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_medium_tcp6, @@ -44549,7 +46359,7 @@ ttest_sgent_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44562,10 +46372,6 @@ ttest_sgent_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockf_large_tcp4(suite) -> - []; -ttest_sgent_csockf_large_tcp4(doc) -> - []; ttest_sgent_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_large_tcp4, @@ -44573,7 +46379,7 @@ ttest_sgent_csockf_large_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44586,10 +46392,6 @@ ttest_sgent_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockf_large_tcp6(suite) -> - []; -ttest_sgent_csockf_large_tcp6(doc) -> - []; ttest_sgent_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockf_large_tcp6, @@ -44597,7 +46399,7 @@ ttest_sgent_csockf_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44610,10 +46412,6 @@ ttest_sgent_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csocko_small_tcp4(suite) -> - []; -ttest_sgent_csocko_small_tcp4(doc) -> - []; ttest_sgent_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_small_tcp4, @@ -44621,7 +46419,7 @@ ttest_sgent_csocko_small_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44634,10 +46432,6 @@ ttest_sgent_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csocko_small_tcp6(suite) -> - []; -ttest_sgent_csocko_small_tcp6(doc) -> - []; ttest_sgent_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_small_tcp6, @@ -44645,7 +46439,7 @@ ttest_sgent_csocko_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44658,10 +46452,6 @@ ttest_sgent_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csocko_medium_tcp4(suite) -> - []; -ttest_sgent_csocko_medium_tcp4(doc) -> - []; ttest_sgent_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_medium_tcp4, @@ -44669,7 +46459,7 @@ ttest_sgent_csocko_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44682,10 +46472,6 @@ ttest_sgent_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csocko_medium_tcp6(suite) -> - []; -ttest_sgent_csocko_medium_tcp6(doc) -> - []; ttest_sgent_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_medium_tcp6, @@ -44693,7 +46479,7 @@ ttest_sgent_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44706,10 +46492,6 @@ ttest_sgent_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csocko_large_tcp4(suite) -> - []; -ttest_sgent_csocko_large_tcp4(doc) -> - []; ttest_sgent_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_large_tcp4, @@ -44717,7 +46499,7 @@ ttest_sgent_csocko_large_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44730,10 +46512,6 @@ ttest_sgent_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csocko_large_tcp6(suite) -> - []; -ttest_sgent_csocko_large_tcp6(doc) -> - []; ttest_sgent_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_large_tcp6, @@ -44741,7 +46519,7 @@ ttest_sgent_csocko_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44754,10 +46532,6 @@ ttest_sgent_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockt_small_tcp4(suite) -> - []; -ttest_sgent_csockt_small_tcp4(doc) -> - []; ttest_sgent_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockt_small_tcp4, @@ -44765,7 +46539,7 @@ ttest_sgent_csockt_small_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44778,10 +46552,6 @@ ttest_sgent_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockt_small_tcp6(suite) -> - []; -ttest_sgent_csockt_small_tcp6(doc) -> - []; ttest_sgent_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csocko_small_tcp6, @@ -44789,7 +46559,7 @@ ttest_sgent_csockt_small_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44802,10 +46572,6 @@ ttest_sgent_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockt_medium_tcp4(suite) -> - []; -ttest_sgent_csockt_medium_tcp4(doc) -> - []; ttest_sgent_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockt_medium_tcp4, @@ -44813,7 +46579,7 @@ ttest_sgent_csockt_medium_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44826,10 +46592,6 @@ ttest_sgent_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockt_medium_tcp6(suite) -> - []; -ttest_sgent_csockt_medium_tcp6(doc) -> - []; ttest_sgent_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockt_medium_tcp6, @@ -44837,7 +46599,7 @@ ttest_sgent_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44850,10 +46612,6 @@ ttest_sgent_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_sgent_csockt_large_tcp4(suite) -> - []; -ttest_sgent_csockt_large_tcp4(doc) -> - []; ttest_sgent_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockt_large_tcp4, @@ -44861,7 +46619,7 @@ ttest_sgent_csockt_large_tcp4(Config) when is_list(Config) -> inet, gen, true, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44874,10 +46632,6 @@ ttest_sgent_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_sgent_csockt_large_tcp6(suite) -> - []; -ttest_sgent_csockt_large_tcp6(doc) -> - []; ttest_sgent_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_sgent_csockt_large_tcp6, @@ -44885,7 +46639,7 @@ ttest_sgent_csockt_large_tcp6(Config) when is_list(Config) -> inet6, gen, true, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -44898,10 +46652,6 @@ ttest_sgent_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgenf_small_tcp4(suite) -> - []; -ttest_ssockf_cgenf_small_tcp4(doc) -> - []; ttest_ssockf_cgenf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_small_tcp4, @@ -44909,7 +46659,7 @@ ttest_ssockf_cgenf_small_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44922,10 +46672,6 @@ ttest_ssockf_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgenf_small_tcp6(suite) -> - []; -ttest_ssockf_cgenf_small_tcp6(doc) -> - []; ttest_ssockf_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_small_tcp6, @@ -44933,7 +46679,7 @@ ttest_ssockf_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -44946,10 +46692,6 @@ ttest_ssockf_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgenf_medium_tcp4(suite) -> - []; -ttest_ssockf_cgenf_medium_tcp4(doc) -> - []; ttest_ssockf_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_medium_tcp4, @@ -44957,7 +46699,7 @@ ttest_ssockf_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44970,10 +46712,6 @@ ttest_ssockf_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgenf_medium_tcp6(suite) -> - []; -ttest_ssockf_cgenf_medium_tcp6(doc) -> - []; ttest_ssockf_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_medium_tcp6, @@ -44981,7 +46719,7 @@ ttest_ssockf_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -44994,10 +46732,6 @@ ttest_ssockf_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgenf_large_tcp4(suite) -> - []; -ttest_ssockf_cgenf_large_tcp4(doc) -> - []; ttest_ssockf_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_large_tcp4, @@ -45005,7 +46739,7 @@ ttest_ssockf_cgenf_large_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45018,10 +46752,6 @@ ttest_ssockf_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgenf_large_tcp6(suite) -> - []; -ttest_ssockf_cgenf_large_tcp6(doc) -> - []; ttest_ssockf_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgenf_large_tcp6, @@ -45029,7 +46759,7 @@ ttest_ssockf_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45042,10 +46772,6 @@ ttest_ssockf_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgeno_small_tcp4(suite) -> - []; -ttest_ssockf_cgeno_small_tcp4(doc) -> - []; ttest_ssockf_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_small_tcp4, @@ -45053,7 +46779,7 @@ ttest_ssockf_cgeno_small_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45066,10 +46792,6 @@ ttest_ssockf_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgeno_small_tcp6(suite) -> - []; -ttest_ssockf_cgeno_small_tcp6(doc) -> - []; ttest_ssockf_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_small_tcp6, @@ -45077,7 +46799,7 @@ ttest_ssockf_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45090,10 +46812,6 @@ ttest_ssockf_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgeno_medium_tcp4(suite) -> - []; -ttest_ssockf_cgeno_medium_tcp4(doc) -> - []; ttest_ssockf_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_medium_tcp4, @@ -45101,7 +46819,7 @@ ttest_ssockf_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45114,10 +46832,6 @@ ttest_ssockf_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgeno_medium_tcp6(suite) -> - []; -ttest_ssockf_cgeno_medium_tcp6(doc) -> - []; ttest_ssockf_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_medium_tcp6, @@ -45125,7 +46839,7 @@ ttest_ssockf_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45138,10 +46852,6 @@ ttest_ssockf_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgeno_large_tcp4(suite) -> - []; -ttest_ssockf_cgeno_large_tcp4(doc) -> - []; ttest_ssockf_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_large_tcp4, @@ -45149,7 +46859,7 @@ ttest_ssockf_cgeno_large_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45162,10 +46872,6 @@ ttest_ssockf_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgeno_large_tcp6(suite) -> - []; -ttest_ssockf_cgeno_large_tcp6(doc) -> - []; ttest_ssockf_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_large_tcp6, @@ -45173,7 +46879,7 @@ ttest_ssockf_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45186,10 +46892,6 @@ ttest_ssockf_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgent_small_tcp4(suite) -> - []; -ttest_ssockf_cgent_small_tcp4(doc) -> - []; ttest_ssockf_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgent_small_tcp4, @@ -45197,7 +46899,7 @@ ttest_ssockf_cgent_small_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45210,10 +46912,6 @@ ttest_ssockf_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgent_small_tcp6(suite) -> - []; -ttest_ssockf_cgent_small_tcp6(doc) -> - []; ttest_ssockf_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgeno_small_tcp6, @@ -45221,7 +46919,7 @@ ttest_ssockf_cgent_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45234,10 +46932,6 @@ ttest_ssockf_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgent_medium_tcp4(suite) -> - []; -ttest_ssockf_cgent_medium_tcp4(doc) -> - []; ttest_ssockf_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgent_medium_tcp4, @@ -45245,7 +46939,7 @@ ttest_ssockf_cgent_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45258,10 +46952,6 @@ ttest_ssockf_cgent_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgent_medium_tcp6(suite) -> - []; -ttest_ssockf_cgent_medium_tcp6(doc) -> - []; ttest_ssockf_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgent_medium_tcp6, @@ -45269,7 +46959,7 @@ ttest_ssockf_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45282,10 +46972,6 @@ ttest_ssockf_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_cgent_large_tcp4(suite) -> - []; -ttest_ssockf_cgent_large_tcp4(doc) -> - []; ttest_ssockf_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgent_large_tcp4, @@ -45293,7 +46979,7 @@ ttest_ssockf_cgent_large_tcp4(Config) when is_list(Config) -> inet, sock, false, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45306,10 +46992,6 @@ ttest_ssockf_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_cgent_large_tcp6(suite) -> - []; -ttest_ssockf_cgent_large_tcp6(doc) -> - []; ttest_ssockf_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_cgent_large_tcp6, @@ -45317,7 +46999,127 @@ ttest_ssockf_cgent_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: small (=1) +%% Domain: inet +%% + +ttest_ssockf_cgsf_small_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + sock, false, + gs, false, + 1, ttest_small_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: small (=1) +%% Domain: inet6 +%% + +ttest_ssockf_cgsf_small_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + sock, false, + gs, false, + 1, ttest_small_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: medium (=2) +%% Domain: inet +%% + +ttest_ssockf_cgsf_medium_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + sock, false, + gs, false, + 2, ttest_medium_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: medium (=2) +%% Domain: inet6 +%% + +ttest_ssockf_cgsf_medium_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + sock, false, + gs, false, + 2, ttest_medium_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: large (=3) +%% Domain: inet +%% + +ttest_ssockf_cgsf_large_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + sock, false, + gs, false, + 3, ttest_large_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = false +%% Client: Transport = gen_tcp(socket), Active = false +%% Message Size: large (=3) +%% Domain: inet6 +%% + +ttest_ssockf_cgsf_large_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + sock, false, + gs, false, + 3, ttest_large_max_outstanding(Config)). @@ -45330,10 +47132,6 @@ ttest_ssockf_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockf_small_tcp4(suite) -> - []; -ttest_ssockf_csockf_small_tcp4(doc) -> - []; ttest_ssockf_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_small_tcp4, @@ -45341,7 +47139,7 @@ ttest_ssockf_csockf_small_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45354,10 +47152,6 @@ ttest_ssockf_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockf_small_tcp6(suite) -> - []; -ttest_ssockf_csockf_small_tcp6(doc) -> - []; ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_small_tcp6, @@ -45365,7 +47159,7 @@ ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45378,10 +47172,6 @@ ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockf_small_tcpL(suite) -> - []; -ttest_ssockf_csockf_small_tcpL(doc) -> - []; ttest_ssockf_csockf_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_small_tcpL, @@ -45389,7 +47179,7 @@ ttest_ssockf_csockf_small_tcpL(Config) when is_list(Config) -> local, sock, false, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45402,10 +47192,6 @@ ttest_ssockf_csockf_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockf_medium_tcp4(suite) -> - []; -ttest_ssockf_csockf_medium_tcp4(doc) -> - []; ttest_ssockf_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_medium_tcp4, @@ -45413,7 +47199,7 @@ ttest_ssockf_csockf_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45426,10 +47212,6 @@ ttest_ssockf_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockf_medium_tcp6(suite) -> - []; -ttest_ssockf_csockf_medium_tcp6(doc) -> - []; ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_medium_tcp6, @@ -45437,7 +47219,7 @@ ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45450,10 +47232,6 @@ ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockf_medium_tcpL(suite) -> - []; -ttest_ssockf_csockf_medium_tcpL(doc) -> - []; ttest_ssockf_csockf_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_medium_tcpL, @@ -45461,7 +47239,7 @@ ttest_ssockf_csockf_medium_tcpL(Config) when is_list(Config) -> local, sock, false, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45474,10 +47252,6 @@ ttest_ssockf_csockf_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockf_large_tcp4(suite) -> - []; -ttest_ssockf_csockf_large_tcp4(doc) -> - []; ttest_ssockf_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_large_tcp4, @@ -45485,7 +47259,7 @@ ttest_ssockf_csockf_large_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45498,10 +47272,6 @@ ttest_ssockf_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockf_large_tcp6(suite) -> - []; -ttest_ssockf_csockf_large_tcp6(doc) -> - []; ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_large_tcp6, @@ -45509,7 +47279,7 @@ ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45522,10 +47292,6 @@ ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockf_large_tcpL(suite) -> - []; -ttest_ssockf_csockf_large_tcpL(doc) -> - []; ttest_ssockf_csockf_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockf_large_tcpL, @@ -45533,7 +47299,7 @@ ttest_ssockf_csockf_large_tcpL(Config) when is_list(Config) -> local, sock, false, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45546,10 +47312,6 @@ ttest_ssockf_csockf_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csocko_small_tcp4(suite) -> - []; -ttest_ssockf_csocko_small_tcp4(doc) -> - []; ttest_ssockf_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_small_tcp4, @@ -45557,7 +47319,7 @@ ttest_ssockf_csocko_small_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45570,10 +47332,6 @@ ttest_ssockf_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csocko_small_tcp6(suite) -> - []; -ttest_ssockf_csocko_small_tcp6(doc) -> - []; ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_small_tcp6, @@ -45581,7 +47339,7 @@ ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45594,10 +47352,6 @@ ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csocko_small_tcpL(suite) -> - []; -ttest_ssockf_csocko_small_tcpL(doc) -> - []; ttest_ssockf_csocko_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_small_tcpL, @@ -45605,7 +47359,7 @@ ttest_ssockf_csocko_small_tcpL(Config) when is_list(Config) -> local, sock, false, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45618,10 +47372,6 @@ ttest_ssockf_csocko_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csocko_medium_tcp4(suite) -> - []; -ttest_ssockf_csocko_medium_tcp4(doc) -> - []; ttest_ssockf_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_medium_tcp4, @@ -45629,7 +47379,7 @@ ttest_ssockf_csocko_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45642,10 +47392,6 @@ ttest_ssockf_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csocko_medium_tcp6(suite) -> - []; -ttest_ssockf_csocko_medium_tcp6(doc) -> - []; ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_medium_tcp6, @@ -45653,7 +47399,7 @@ ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45666,10 +47412,6 @@ ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csocko_medium_tcpL(suite) -> - []; -ttest_ssockf_csocko_medium_tcpL(doc) -> - []; ttest_ssockf_csocko_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_medium_tcpL, @@ -45677,7 +47419,7 @@ ttest_ssockf_csocko_medium_tcpL(Config) when is_list(Config) -> local, sock, false, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45690,10 +47432,6 @@ ttest_ssockf_csocko_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csocko_large_tcp4(suite) -> - []; -ttest_ssockf_csocko_large_tcp4(doc) -> - []; ttest_ssockf_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_large_tcp4, @@ -45701,7 +47439,7 @@ ttest_ssockf_csocko_large_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45714,10 +47452,6 @@ ttest_ssockf_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csocko_large_tcp6(suite) -> - []; -ttest_ssockf_csocko_large_tcp6(doc) -> - []; ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_large_tcp6, @@ -45725,7 +47459,7 @@ ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45738,10 +47472,6 @@ ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csocko_large_tcpL(suite) -> - []; -ttest_ssockf_csocko_large_tcpL(doc) -> - []; ttest_ssockf_csocko_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_large_tcpL, @@ -45749,7 +47479,7 @@ ttest_ssockf_csocko_large_tcpL(Config) when is_list(Config) -> local, sock, false, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45762,10 +47492,6 @@ ttest_ssockf_csocko_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockt_small_tcp4(suite) -> - []; -ttest_ssockf_csockt_small_tcp4(doc) -> - []; ttest_ssockf_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_small_tcp4, @@ -45773,7 +47499,7 @@ ttest_ssockf_csockt_small_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45786,10 +47512,6 @@ ttest_ssockf_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockt_small_tcp6(suite) -> - []; -ttest_ssockf_csockt_small_tcp6(doc) -> - []; ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_small_tcp6, @@ -45797,7 +47519,7 @@ ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45810,10 +47532,6 @@ ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockt_small_tcpL(suite) -> - []; -ttest_ssockf_csockt_small_tcpL(doc) -> - []; ttest_ssockf_csockt_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csocko_small_tcpL, @@ -45821,7 +47539,7 @@ ttest_ssockf_csockt_small_tcpL(Config) when is_list(Config) -> local, sock, false, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -45834,10 +47552,6 @@ ttest_ssockf_csockt_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockt_medium_tcp4(suite) -> - []; -ttest_ssockf_csockt_medium_tcp4(doc) -> - []; ttest_ssockf_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_medium_tcp4, @@ -45845,7 +47559,7 @@ ttest_ssockf_csockt_medium_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45858,10 +47572,6 @@ ttest_ssockf_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockt_medium_tcp6(suite) -> - []; -ttest_ssockf_csockt_medium_tcp6(doc) -> - []; ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_medium_tcp6, @@ -45869,7 +47579,7 @@ ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45882,10 +47592,6 @@ ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockt_medium_tcpL(suite) -> - []; -ttest_ssockf_csockt_medium_tcpL(doc) -> - []; ttest_ssockf_csockt_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_medium_tcpL, @@ -45893,7 +47599,7 @@ ttest_ssockf_csockt_medium_tcpL(Config) when is_list(Config) -> local, sock, false, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -45906,10 +47612,6 @@ ttest_ssockf_csockt_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockf_csockt_large_tcp4(suite) -> - []; -ttest_ssockf_csockt_large_tcp4(doc) -> - []; ttest_ssockf_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_large_tcp4, @@ -45917,7 +47619,7 @@ ttest_ssockf_csockt_large_tcp4(Config) when is_list(Config) -> inet, sock, false, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45930,10 +47632,6 @@ ttest_ssockf_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockf_csockt_large_tcp6(suite) -> - []; -ttest_ssockf_csockt_large_tcp6(doc) -> - []; ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_large_tcp6, @@ -45941,7 +47639,7 @@ ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) -> inet6, sock, false, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45954,10 +47652,6 @@ ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockf_csockt_large_tcpL(suite) -> - []; -ttest_ssockf_csockt_large_tcpL(doc) -> - []; ttest_ssockf_csockt_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockf_csockt_large_tcpL, @@ -45965,7 +47659,7 @@ ttest_ssockf_csockt_large_tcpL(Config) when is_list(Config) -> local, sock, false, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -45978,10 +47672,6 @@ ttest_ssockf_csockt_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgenf_small_tcp4(suite) -> - []; -ttest_ssocko_cgenf_small_tcp4(doc) -> - []; ttest_ssocko_cgenf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_small_tcp4, @@ -45989,7 +47679,7 @@ ttest_ssocko_cgenf_small_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46002,10 +47692,6 @@ ttest_ssocko_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgenf_small_tcp6(suite) -> - []; -ttest_ssocko_cgenf_small_tcp6(doc) -> - []; ttest_ssocko_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_small_tcp6, @@ -46013,7 +47699,7 @@ ttest_ssocko_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46026,10 +47712,6 @@ ttest_ssocko_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgenf_medium_tcp4(suite) -> - []; -ttest_ssocko_cgenf_medium_tcp4(doc) -> - []; ttest_ssocko_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_medium_tcp4, @@ -46037,7 +47719,7 @@ ttest_ssocko_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46050,10 +47732,6 @@ ttest_ssocko_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgenf_medium_tcp6(suite) -> - []; -ttest_ssocko_cgenf_medium_tcp6(doc) -> - []; ttest_ssocko_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_medium_tcp6, @@ -46061,7 +47739,7 @@ ttest_ssocko_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46074,10 +47752,6 @@ ttest_ssocko_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgenf_large_tcp4(suite) -> - []; -ttest_ssocko_cgenf_large_tcp4(doc) -> - []; ttest_ssocko_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_large_tcp4, @@ -46085,7 +47759,7 @@ ttest_ssocko_cgenf_large_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46098,10 +47772,6 @@ ttest_ssocko_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgenf_large_tcp6(suite) -> - []; -ttest_ssocko_cgenf_large_tcp6(doc) -> - []; ttest_ssocko_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgenf_large_tcp6, @@ -46109,7 +47779,7 @@ ttest_ssocko_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46122,10 +47792,6 @@ ttest_ssocko_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgeno_small_tcp4(suite) -> - []; -ttest_ssocko_cgeno_small_tcp4(doc) -> - []; ttest_ssocko_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_small_tcp4, @@ -46133,7 +47799,7 @@ ttest_ssocko_cgeno_small_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46146,10 +47812,6 @@ ttest_ssocko_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgeno_small_tcp6(suite) -> - []; -ttest_ssocko_cgeno_small_tcp6(doc) -> - []; ttest_ssocko_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_small_tcp6, @@ -46157,7 +47819,7 @@ ttest_ssocko_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46170,10 +47832,6 @@ ttest_ssocko_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgeno_medium_tcp4(suite) -> - []; -ttest_ssocko_cgeno_medium_tcp4(doc) -> - []; ttest_ssocko_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_medium_tcp4, @@ -46181,7 +47839,7 @@ ttest_ssocko_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46194,10 +47852,6 @@ ttest_ssocko_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgeno_medium_tcp6(suite) -> - []; -ttest_ssocko_cgeno_medium_tcp6(doc) -> - []; ttest_ssocko_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_medium_tcp6, @@ -46205,7 +47859,7 @@ ttest_ssocko_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46218,10 +47872,6 @@ ttest_ssocko_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgeno_large_tcp4(suite) -> - []; -ttest_ssocko_cgeno_large_tcp4(doc) -> - []; ttest_ssocko_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_large_tcp4, @@ -46229,7 +47879,7 @@ ttest_ssocko_cgeno_large_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46242,10 +47892,6 @@ ttest_ssocko_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgeno_large_tcp6(suite) -> - []; -ttest_ssocko_cgeno_large_tcp6(doc) -> - []; ttest_ssocko_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgeno_large_tcp6, @@ -46253,7 +47899,7 @@ ttest_ssocko_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46266,10 +47912,6 @@ ttest_ssocko_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgent_small_tcp4(suite) -> - []; -ttest_ssocko_cgent_small_tcp4(doc) -> - []; ttest_ssocko_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_small_tcp4, @@ -46277,7 +47919,7 @@ ttest_ssocko_cgent_small_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46290,10 +47932,6 @@ ttest_ssocko_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgent_small_tcp6(suite) -> - []; -ttest_ssocko_cgent_small_tcp6(doc) -> - []; ttest_ssocko_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_small_tcp6, @@ -46301,7 +47939,7 @@ ttest_ssocko_cgent_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46314,10 +47952,6 @@ ttest_ssocko_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgent_medium_tcp4(suite) -> - []; -ttest_ssocko_cgent_medium_tcp4(doc) -> - []; ttest_ssocko_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_medium_tcp4, @@ -46325,7 +47959,7 @@ ttest_ssocko_cgent_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46338,10 +47972,6 @@ ttest_ssocko_cgent_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgent_medium_tcp6(suite) -> - []; -ttest_ssocko_cgent_medium_tcp6(doc) -> - []; ttest_ssocko_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_medium_tcp6, @@ -46349,7 +47979,7 @@ ttest_ssocko_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46362,10 +47992,6 @@ ttest_ssocko_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_cgent_large_tcp4(suite) -> - []; -ttest_ssocko_cgent_large_tcp4(doc) -> - []; ttest_ssocko_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_large_tcp4, @@ -46373,7 +47999,7 @@ ttest_ssocko_cgent_large_tcp4(Config) when is_list(Config) -> inet, sock, once, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46386,10 +48012,6 @@ ttest_ssocko_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_cgent_large_tcp6(suite) -> - []; -ttest_ssocko_cgent_large_tcp6(doc) -> - []; ttest_ssocko_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_cgent_large_tcp6, @@ -46397,7 +48019,7 @@ ttest_ssocko_cgent_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46410,10 +48032,6 @@ ttest_ssocko_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockf_small_tcp4(suite) -> - []; -ttest_ssocko_csockf_small_tcp4(doc) -> - []; ttest_ssocko_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_small_tcp4, @@ -46421,7 +48039,7 @@ ttest_ssocko_csockf_small_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46434,10 +48052,6 @@ ttest_ssocko_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockf_small_tcp6(suite) -> - []; -ttest_ssocko_csockf_small_tcp6(doc) -> - []; ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_small_tcp6, @@ -46445,7 +48059,7 @@ ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46458,10 +48072,6 @@ ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockf_small_tcpL(suite) -> - []; -ttest_ssocko_csockf_small_tcpL(doc) -> - []; ttest_ssocko_csockf_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_small_tcpL, @@ -46469,7 +48079,7 @@ ttest_ssocko_csockf_small_tcpL(Config) when is_list(Config) -> local, sock, once, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46482,10 +48092,6 @@ ttest_ssocko_csockf_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockf_medium_tcp4(suite) -> - []; -ttest_ssocko_csockf_medium_tcp4(doc) -> - []; ttest_ssocko_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_medium_tcp4, @@ -46493,7 +48099,7 @@ ttest_ssocko_csockf_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46506,10 +48112,6 @@ ttest_ssocko_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockf_medium_tcp6(suite) -> - []; -ttest_ssocko_csockf_medium_tcp6(doc) -> - []; ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_medium_tcp6, @@ -46517,7 +48119,7 @@ ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46530,10 +48132,6 @@ ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockf_medium_tcpL(suite) -> - []; -ttest_ssocko_csockf_medium_tcpL(doc) -> - []; ttest_ssocko_csockf_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_medium_tcpL, @@ -46541,7 +48139,7 @@ ttest_ssocko_csockf_medium_tcpL(Config) when is_list(Config) -> local, sock, once, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46554,10 +48152,6 @@ ttest_ssocko_csockf_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockf_large_tcp4(suite) -> - []; -ttest_ssocko_csockf_large_tcp4(doc) -> - []; ttest_ssocko_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_large_tcp4, @@ -46565,7 +48159,7 @@ ttest_ssocko_csockf_large_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46578,10 +48172,6 @@ ttest_ssocko_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockf_large_tcp6(suite) -> - []; -ttest_ssocko_csockf_large_tcp6(doc) -> - []; ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_large_tcp6, @@ -46589,7 +48179,7 @@ ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46602,10 +48192,6 @@ ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockf_large_tcpL(suite) -> - []; -ttest_ssocko_csockf_large_tcpL(doc) -> - []; ttest_ssocko_csockf_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockf_large_tcpL, @@ -46613,7 +48199,7 @@ ttest_ssocko_csockf_large_tcpL(Config) when is_list(Config) -> local, sock, once, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46626,10 +48212,6 @@ ttest_ssocko_csockf_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csocko_small_tcp4(suite) -> - []; -ttest_ssocko_csocko_small_tcp4(doc) -> - []; ttest_ssocko_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_small_tcp4, @@ -46637,7 +48219,7 @@ ttest_ssocko_csocko_small_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46650,10 +48232,6 @@ ttest_ssocko_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csocko_small_tcp6(suite) -> - []; -ttest_ssocko_csocko_small_tcp6(doc) -> - []; ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_small_tcp6, @@ -46661,7 +48239,7 @@ ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46674,10 +48252,6 @@ ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csocko_small_tcpL(suite) -> - []; -ttest_ssocko_csocko_small_tcpL(doc) -> - []; ttest_ssocko_csocko_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_small_tcpL, @@ -46685,7 +48259,7 @@ ttest_ssocko_csocko_small_tcpL(Config) when is_list(Config) -> local, sock, once, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46698,10 +48272,6 @@ ttest_ssocko_csocko_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csocko_medium_tcp4(suite) -> - []; -ttest_ssocko_csocko_medium_tcp4(doc) -> - []; ttest_ssocko_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_medium_tcp4, @@ -46709,7 +48279,7 @@ ttest_ssocko_csocko_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46722,10 +48292,6 @@ ttest_ssocko_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csocko_medium_tcp6(suite) -> - []; -ttest_ssocko_csocko_medium_tcp6(doc) -> - []; ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_medium_tcp6, @@ -46733,7 +48299,7 @@ ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46746,10 +48312,6 @@ ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csocko_medium_tcpL(suite) -> - []; -ttest_ssocko_csocko_medium_tcpL(doc) -> - []; ttest_ssocko_csocko_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_medium_tcpL, @@ -46757,7 +48319,7 @@ ttest_ssocko_csocko_medium_tcpL(Config) when is_list(Config) -> local, sock, once, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46770,10 +48332,6 @@ ttest_ssocko_csocko_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csocko_large_tcp4(suite) -> - []; -ttest_ssocko_csocko_large_tcp4(doc) -> - []; ttest_ssocko_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_large_tcp4, @@ -46781,7 +48339,7 @@ ttest_ssocko_csocko_large_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46794,10 +48352,6 @@ ttest_ssocko_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csocko_large_tcp6(suite) -> - []; -ttest_ssocko_csocko_large_tcp6(doc) -> - []; ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_large_tcp6, @@ -46805,7 +48359,7 @@ ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46818,10 +48372,6 @@ ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csocko_large_tcpL(suite) -> - []; -ttest_ssocko_csocko_large_tcpL(doc) -> - []; ttest_ssocko_csocko_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_large_tcpL, @@ -46829,7 +48379,7 @@ ttest_ssocko_csocko_large_tcpL(Config) when is_list(Config) -> local, sock, once, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -46842,10 +48392,6 @@ ttest_ssocko_csocko_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockt_small_tcp4(suite) -> - []; -ttest_ssocko_csockt_small_tcp4(doc) -> - []; ttest_ssocko_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_small_tcp4, @@ -46853,7 +48399,7 @@ ttest_ssocko_csockt_small_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46866,10 +48412,6 @@ ttest_ssocko_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockt_small_tcp6(suite) -> - []; -ttest_ssocko_csockt_small_tcp6(doc) -> - []; ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_small_tcp6, @@ -46877,7 +48419,7 @@ ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46890,10 +48432,6 @@ ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockt_small_tcpL(suite) -> - []; -ttest_ssocko_csockt_small_tcpL(doc) -> - []; ttest_ssocko_csockt_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csocko_small_tcpL, @@ -46901,7 +48439,7 @@ ttest_ssocko_csockt_small_tcpL(Config) when is_list(Config) -> local, sock, once, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -46914,10 +48452,6 @@ ttest_ssocko_csockt_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockt_medium_tcp4(suite) -> - []; -ttest_ssocko_csockt_medium_tcp4(doc) -> - []; ttest_ssocko_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_medium_tcp4, @@ -46925,7 +48459,7 @@ ttest_ssocko_csockt_medium_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46938,10 +48472,6 @@ ttest_ssocko_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockt_medium_tcp6(suite) -> - []; -ttest_ssocko_csockt_medium_tcp6(doc) -> - []; ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_medium_tcp6, @@ -46949,7 +48479,7 @@ ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46962,10 +48492,6 @@ ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockt_medium_tcpL(suite) -> - []; -ttest_ssocko_csockt_medium_tcpL(doc) -> - []; ttest_ssocko_csockt_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_medium_tcpL, @@ -46973,7 +48499,7 @@ ttest_ssocko_csockt_medium_tcpL(Config) when is_list(Config) -> local, sock, once, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -46986,10 +48512,6 @@ ttest_ssocko_csockt_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssocko_csockt_large_tcp4(suite) -> - []; -ttest_ssocko_csockt_large_tcp4(doc) -> - []; ttest_ssocko_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_large_tcp4, @@ -46997,7 +48519,7 @@ ttest_ssocko_csockt_large_tcp4(Config) when is_list(Config) -> inet, sock, once, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47010,10 +48532,6 @@ ttest_ssocko_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssocko_csockt_large_tcp6(suite) -> - []; -ttest_ssocko_csockt_large_tcp6(doc) -> - []; ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_large_tcp6, @@ -47021,7 +48539,7 @@ ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) -> inet6, sock, once, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47034,10 +48552,6 @@ ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssocko_csockt_large_tcpL(suite) -> - []; -ttest_ssocko_csockt_large_tcpL(doc) -> - []; ttest_ssocko_csockt_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssocko_csockt_large_tcpL, @@ -47045,7 +48559,7 @@ ttest_ssocko_csockt_large_tcpL(Config) when is_list(Config) -> local, sock, once, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47058,10 +48572,6 @@ ttest_ssocko_csockt_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgenf_small_tcp4(suite) -> - []; -ttest_ssockt_cgenf_small_tcp4(doc) -> - []; ttest_ssockt_cgenf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_small_tcp4, @@ -47069,7 +48579,7 @@ ttest_ssockt_cgenf_small_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47082,10 +48592,6 @@ ttest_ssockt_cgenf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgenf_small_tcp6(suite) -> - []; -ttest_ssockt_cgenf_small_tcp6(doc) -> - []; ttest_ssockt_cgenf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_small_tcp6, @@ -47093,7 +48599,7 @@ ttest_ssockt_cgenf_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47106,10 +48612,6 @@ ttest_ssockt_cgenf_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgenf_medium_tcp4(suite) -> - []; -ttest_ssockt_cgenf_medium_tcp4(doc) -> - []; ttest_ssockt_cgenf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_medium_tcp4, @@ -47117,7 +48619,7 @@ ttest_ssockt_cgenf_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47130,10 +48632,6 @@ ttest_ssockt_cgenf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgenf_medium_tcp6(suite) -> - []; -ttest_ssockt_cgenf_medium_tcp6(doc) -> - []; ttest_ssockt_cgenf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_medium_tcp6, @@ -47141,7 +48639,7 @@ ttest_ssockt_cgenf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47154,10 +48652,6 @@ ttest_ssockt_cgenf_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgenf_large_tcp4(suite) -> - []; -ttest_ssockt_cgenf_large_tcp4(doc) -> - []; ttest_ssockt_cgenf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_large_tcp4, @@ -47165,7 +48659,7 @@ ttest_ssockt_cgenf_large_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47178,10 +48672,6 @@ ttest_ssockt_cgenf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgenf_large_tcp6(suite) -> - []; -ttest_ssockt_cgenf_large_tcp6(doc) -> - []; ttest_ssockt_cgenf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgenf_large_tcp6, @@ -47189,7 +48679,7 @@ ttest_ssockt_cgenf_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47202,10 +48692,6 @@ ttest_ssockt_cgenf_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgeno_small_tcp4(suite) -> - []; -ttest_ssockt_cgeno_small_tcp4(doc) -> - []; ttest_ssockt_cgeno_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_small_tcp4, @@ -47213,7 +48699,7 @@ ttest_ssockt_cgeno_small_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47226,10 +48712,6 @@ ttest_ssockt_cgeno_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgeno_small_tcp6(suite) -> - []; -ttest_ssockt_cgeno_small_tcp6(doc) -> - []; ttest_ssockt_cgeno_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_small_tcp6, @@ -47237,7 +48719,7 @@ ttest_ssockt_cgeno_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47250,10 +48732,6 @@ ttest_ssockt_cgeno_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgeno_medium_tcp4(suite) -> - []; -ttest_ssockt_cgeno_medium_tcp4(doc) -> - []; ttest_ssockt_cgeno_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_medium_tcp4, @@ -47261,7 +48739,7 @@ ttest_ssockt_cgeno_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47274,10 +48752,6 @@ ttest_ssockt_cgeno_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgeno_medium_tcp6(suite) -> - []; -ttest_ssockt_cgeno_medium_tcp6(doc) -> - []; ttest_ssockt_cgeno_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_medium_tcp6, @@ -47285,7 +48759,7 @@ ttest_ssockt_cgeno_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47298,10 +48772,6 @@ ttest_ssockt_cgeno_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgeno_large_tcp4(suite) -> - []; -ttest_ssockt_cgeno_large_tcp4(doc) -> - []; ttest_ssockt_cgeno_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_large_tcp4, @@ -47309,7 +48779,7 @@ ttest_ssockt_cgeno_large_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47322,10 +48792,6 @@ ttest_ssockt_cgeno_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgeno_large_tcp6(suite) -> - []; -ttest_ssockt_cgeno_large_tcp6(doc) -> - []; ttest_ssockt_cgeno_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgeno_large_tcp6, @@ -47333,7 +48799,7 @@ ttest_ssockt_cgeno_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47346,10 +48812,6 @@ ttest_ssockt_cgeno_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgent_small_tcp4(suite) -> - []; -ttest_ssockt_cgent_small_tcp4(doc) -> - []; ttest_ssockt_cgent_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_small_tcp4, @@ -47357,7 +48819,7 @@ ttest_ssockt_cgent_small_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47370,10 +48832,6 @@ ttest_ssockt_cgent_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgent_small_tcp6(suite) -> - []; -ttest_ssockt_cgent_small_tcp6(doc) -> - []; ttest_ssockt_cgent_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_small_tcp6, @@ -47381,7 +48839,7 @@ ttest_ssockt_cgent_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47394,10 +48852,6 @@ ttest_ssockt_cgent_small_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgent_medium_tcp4(suite) -> - []; -ttest_ssockt_cgent_medium_tcp4(doc) -> - []; ttest_ssockt_cgent_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_medium_tcp4, @@ -47405,7 +48859,7 @@ ttest_ssockt_cgent_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47418,10 +48872,6 @@ ttest_ssockt_cgent_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgent_medium_tcp6(suite) -> - []; -ttest_ssockt_cgent_medium_tcp6(doc) -> - []; ttest_ssockt_cgent_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_medium_tcp6, @@ -47429,7 +48879,7 @@ ttest_ssockt_cgent_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47442,10 +48892,6 @@ ttest_ssockt_cgent_medium_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_cgent_large_tcp4(suite) -> - []; -ttest_ssockt_cgent_large_tcp4(doc) -> - []; ttest_ssockt_cgent_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_large_tcp4, @@ -47453,7 +48899,7 @@ ttest_ssockt_cgent_large_tcp4(Config) when is_list(Config) -> inet, sock, true, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47466,10 +48912,6 @@ ttest_ssockt_cgent_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_cgent_large_tcp6(suite) -> - []; -ttest_ssockt_cgent_large_tcp6(doc) -> - []; ttest_ssockt_cgent_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_cgent_large_tcp6, @@ -47477,7 +48919,7 @@ ttest_ssockt_cgent_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, gen, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47490,10 +48932,6 @@ ttest_ssockt_cgent_large_tcp6(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockf_small_tcp4(suite) -> - []; -ttest_ssockt_csockf_small_tcp4(doc) -> - []; ttest_ssockt_csockf_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_small_tcp4, @@ -47501,7 +48939,7 @@ ttest_ssockt_csockf_small_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47514,10 +48952,6 @@ ttest_ssockt_csockf_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockf_small_tcp6(suite) -> - []; -ttest_ssockt_csockf_small_tcp6(doc) -> - []; ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_small_tcp6, @@ -47525,7 +48959,7 @@ ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47538,10 +48972,6 @@ ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockf_small_tcpL(suite) -> - []; -ttest_ssockt_csockf_small_tcpL(doc) -> - []; ttest_ssockt_csockf_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_small_tcpL, @@ -47549,7 +48979,7 @@ ttest_ssockt_csockf_small_tcpL(Config) when is_list(Config) -> local, sock, true, sock, false, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47562,10 +48992,6 @@ ttest_ssockt_csockf_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockf_medium_tcp4(suite) -> - []; -ttest_ssockt_csockf_medium_tcp4(doc) -> - []; ttest_ssockt_csockf_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_medium_tcp4, @@ -47573,7 +48999,7 @@ ttest_ssockt_csockf_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47586,10 +49012,6 @@ ttest_ssockt_csockf_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockf_medium_tcp6(suite) -> - []; -ttest_ssockt_csockf_medium_tcp6(doc) -> - []; ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_medium_tcp6, @@ -47597,7 +49019,7 @@ ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47610,10 +49032,6 @@ ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockf_medium_tcpL(suite) -> - []; -ttest_ssockt_csockf_medium_tcpL(doc) -> - []; ttest_ssockt_csockf_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_medium_tcpL, @@ -47621,7 +49039,7 @@ ttest_ssockt_csockf_medium_tcpL(Config) when is_list(Config) -> local, sock, true, sock, false, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47634,10 +49052,6 @@ ttest_ssockt_csockf_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockf_large_tcp4(suite) -> - []; -ttest_ssockt_csockf_large_tcp4(doc) -> - []; ttest_ssockt_csockf_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_large_tcp4, @@ -47645,7 +49059,7 @@ ttest_ssockt_csockf_large_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47658,10 +49072,6 @@ ttest_ssockt_csockf_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockf_large_tcp6(suite) -> - []; -ttest_ssockt_csockf_large_tcp6(doc) -> - []; ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_large_tcp6, @@ -47669,7 +49079,7 @@ ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47682,10 +49092,6 @@ ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockf_large_tcpL(suite) -> - []; -ttest_ssockt_csockf_large_tcpL(doc) -> - []; ttest_ssockt_csockf_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockf_large_tcpL, @@ -47693,7 +49099,7 @@ ttest_ssockt_csockf_large_tcpL(Config) when is_list(Config) -> local, sock, true, sock, false, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47706,10 +49112,6 @@ ttest_ssockt_csockf_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csocko_small_tcp4(suite) -> - []; -ttest_ssockt_csocko_small_tcp4(doc) -> - []; ttest_ssockt_csocko_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_small_tcp4, @@ -47717,7 +49119,7 @@ ttest_ssockt_csocko_small_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47730,10 +49132,6 @@ ttest_ssockt_csocko_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csocko_small_tcp6(suite) -> - []; -ttest_ssockt_csocko_small_tcp6(doc) -> - []; ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_small_tcp6, @@ -47741,7 +49139,7 @@ ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47754,10 +49152,6 @@ ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csocko_small_tcpL(suite) -> - []; -ttest_ssockt_csocko_small_tcpL(doc) -> - []; ttest_ssockt_csocko_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_small_tcpL, @@ -47765,7 +49159,7 @@ ttest_ssockt_csocko_small_tcpL(Config) when is_list(Config) -> local, sock, true, sock, once, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47778,10 +49172,6 @@ ttest_ssockt_csocko_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csocko_medium_tcp4(suite) -> - []; -ttest_ssockt_csocko_medium_tcp4(doc) -> - []; ttest_ssockt_csocko_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_medium_tcp4, @@ -47789,7 +49179,7 @@ ttest_ssockt_csocko_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47802,10 +49192,6 @@ ttest_ssockt_csocko_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csocko_medium_tcp6(suite) -> - []; -ttest_ssockt_csocko_medium_tcp6(doc) -> - []; ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_medium_tcp6, @@ -47813,7 +49199,7 @@ ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47826,10 +49212,6 @@ ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csocko_medium_tcpL(suite) -> - []; -ttest_ssockt_csocko_medium_tcpL(doc) -> - []; ttest_ssockt_csocko_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_medium_tcpL, @@ -47837,7 +49219,7 @@ ttest_ssockt_csocko_medium_tcpL(Config) when is_list(Config) -> local, sock, true, sock, once, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -47850,10 +49232,6 @@ ttest_ssockt_csocko_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csocko_large_tcp4(suite) -> - []; -ttest_ssockt_csocko_large_tcp4(doc) -> - []; ttest_ssockt_csocko_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_large_tcp4, @@ -47861,7 +49239,7 @@ ttest_ssockt_csocko_large_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47874,10 +49252,6 @@ ttest_ssockt_csocko_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csocko_large_tcp6(suite) -> - []; -ttest_ssockt_csocko_large_tcp6(doc) -> - []; ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_large_tcp6, @@ -47885,7 +49259,7 @@ ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47898,10 +49272,6 @@ ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csocko_large_tcpL(suite) -> - []; -ttest_ssockt_csocko_large_tcpL(doc) -> - []; ttest_ssockt_csocko_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_large_tcpL, @@ -47909,7 +49279,7 @@ ttest_ssockt_csocko_large_tcpL(Config) when is_list(Config) -> local, sock, true, sock, once, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -47922,10 +49292,6 @@ ttest_ssockt_csocko_large_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockt_small_tcp4(suite) -> - []; -ttest_ssockt_csockt_small_tcp4(doc) -> - []; ttest_ssockt_csockt_small_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_small_tcp4, @@ -47933,7 +49299,7 @@ ttest_ssockt_csockt_small_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47946,10 +49312,6 @@ ttest_ssockt_csockt_small_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockt_small_tcp6(suite) -> - []; -ttest_ssockt_csockt_small_tcp6(doc) -> - []; ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_small_tcp6, @@ -47957,7 +49319,7 @@ ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47970,10 +49332,6 @@ ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockt_small_tcpL(suite) -> - []; -ttest_ssockt_csockt_small_tcpL(doc) -> - []; ttest_ssockt_csockt_small_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csocko_small_tcpL, @@ -47981,7 +49339,7 @@ ttest_ssockt_csockt_small_tcpL(Config) when is_list(Config) -> local, sock, true, sock, true, - 1, 200). + 1, ttest_small_max_outstanding(Config)). @@ -47994,10 +49352,6 @@ ttest_ssockt_csockt_small_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockt_medium_tcp4(suite) -> - []; -ttest_ssockt_csockt_medium_tcp4(doc) -> - []; ttest_ssockt_csockt_medium_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_medium_tcp4, @@ -48005,7 +49359,7 @@ ttest_ssockt_csockt_medium_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -48018,10 +49372,6 @@ ttest_ssockt_csockt_medium_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockt_medium_tcp6(suite) -> - []; -ttest_ssockt_csockt_medium_tcp6(doc) -> - []; ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_medium_tcp6, @@ -48029,7 +49379,7 @@ ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -48042,10 +49392,6 @@ ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockt_medium_tcpL(suite) -> - []; -ttest_ssockt_csockt_medium_tcpL(doc) -> - []; ttest_ssockt_csockt_medium_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_medium_tcpL, @@ -48053,7 +49399,7 @@ ttest_ssockt_csockt_medium_tcpL(Config) when is_list(Config) -> local, sock, true, sock, true, - 2, 20). + 2, ttest_medium_max_outstanding(Config)). @@ -48066,10 +49412,6 @@ ttest_ssockt_csockt_medium_tcpL(Config) when is_list(Config) -> %% Domain: inet %% -ttest_ssockt_csockt_large_tcp4(suite) -> - []; -ttest_ssockt_csockt_large_tcp4(doc) -> - []; ttest_ssockt_csockt_large_tcp4(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_large_tcp4, @@ -48077,7 +49419,7 @@ ttest_ssockt_csockt_large_tcp4(Config) when is_list(Config) -> inet, sock, true, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -48090,10 +49432,6 @@ ttest_ssockt_csockt_large_tcp4(Config) when is_list(Config) -> %% Domain: inet6 %% -ttest_ssockt_csockt_large_tcp6(suite) -> - []; -ttest_ssockt_csockt_large_tcp6(doc) -> - []; ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_large_tcp6, @@ -48101,7 +49439,7 @@ ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) -> inet6, sock, true, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). @@ -48114,10 +49452,6 @@ ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) -> %% Domain: local %% -ttest_ssockt_csockt_large_tcpL(suite) -> - []; -ttest_ssockt_csockt_large_tcpL(doc) -> - []; ttest_ssockt_csockt_large_tcpL(Config) when is_list(Config) -> Runtime = which_ttest_runtime(Config), ttest_tcp(ttest_ssockt_csockt_large_tcpL, @@ -48125,7 +49459,71 @@ ttest_ssockt_csockt_large_tcpL(Config) when is_list(Config) -> local, sock, true, sock, true, - 3, 2). + 3, ttest_large_max_outstanding(Config)). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = true +%% Client: Transport = socket(tcp), Active = once +%% Message Size: small (=1) +%% Domain: inet +%% Remote: false (run everything on the local node) +%% + +ttest_simple_ssockt_csocko_small_tcp4(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet, + sock, true, + sock, once, + 1, ttest_small_max_outstanding(Config), + false). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = true +%% Client: Transport = socket(tcp), Active = once +%% Message Size: small (=1) +%% Domain: inet6 +%% + +ttest_simple_ssockt_csocko_small_tcp6(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + inet6, + sock, true, + sock, once, + 1, ttest_small_max_outstanding(Config), + false). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case uses the time test (ttest) utility to implement a +%% ping-pong like test case. +%% Server: Transport = socket(tcp), Active = true +%% Client: Transport = socket(tcp), Active = once +%% Message Size: small (=1) +%% Domain: local +%% + +ttest_simple_ssockt_csocko_small_tcpL(Config) when is_list(Config) -> + Runtime = which_ttest_runtime(Config), + ttest_tcp(?FUNCTION_NAME, + Runtime, + local, + sock, true, + sock, once, + 1, ttest_small_max_outstanding(Config), + false). + @@ -48187,6 +49585,20 @@ ttest_tcp(TC, ServerMod, ServerActive, ClientMod, ClientActive, MsgID, MaxOutstanding) -> + ttest_tcp(TC, + Runtime, + Domain, + ServerMod, ServerActive, + ClientMod, ClientActive, + MsgID, MaxOutstanding, true). + +ttest_tcp(TC, + Runtime, + Domain, + ServerMod, ServerActive, + ClientMod, ClientActive, + MsgID, MaxOutstanding, + Remote) -> tc_try(TC, fun() -> if @@ -48195,10 +49607,12 @@ ttest_tcp(TC, %% On darwin we seem to hit the system limit(s) %% much earlier. %% The tests "mostly" work, but random cases fail - %% (even on reasonably powerfull machines), + %% (even on reasonably powerful machines), %% so its much simpler to just skip on darwin... has_support_unix_domain_socket(), - is_not_darwin(); + is_not_darwin(); + (Domain =:= inet) -> + has_support_ipv4(); (Domain =:= inet6) -> has_support_ipv6(); true -> ok @@ -48208,6 +49622,19 @@ ttest_tcp(TC, %% This may be overkill, depending on the runtime, %% but better safe then sorry... ?TT(Runtime + ?SECS(60)), + ?P("Parameters: " + "~n Domain: ~p" + "~n Message ID: ~p" + "~n Max Outstanding: ~p" + "~n Running Time: ~p" + "~n Server Module: ~p" + "~n Server Active: ~p" + "~n Client Module: ~p" + "~n Client Active: ~p" + "~n Remote: ~p", + [Domain, MsgID, MaxOutstanding, Runtime, + ServerMod, ServerActive, ClientMod, ClientActive, + Remote]), InitState = #{domain => Domain, msg_id => MsgID, max_outstanding => MaxOutstanding, @@ -48215,7 +49642,8 @@ ttest_tcp(TC, server_mod => ServerMod, server_active => ServerActive, client_mod => ClientMod, - client_active => ClientActive}, + client_active => ClientActive, + remote => Remote}, ok = ttest_tcp(InitState) end). @@ -48239,19 +49667,25 @@ ttest_tcp(InitState) -> %% *** Init part *** - #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, server) of - {ok, Node} -> - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end - end}, - #{desc => "monitor server node", - cmd => fun(#{node := Node} = _State) -> + #{desc => "(maybe) create node", + cmd => fun(#{remote := true} = State) -> + {Peer, Node} = ?START_NODE("server"), + ?SEV_IPRINT("server node created:" + "~n Peer: ~p" + "~n Node: ~p", [Peer, Node]), + {ok, State#{peer => Peer, node => Node}}; + (State) -> + ?SEV_IPRINT("use local node for server"), + {ok, State#{peer => undefined, node => node()}} + end}, + #{desc => "(maybe) monitor server node", + cmd => fun(#{node := Node} = _State) when (Node =/= node) -> true = erlang:monitor_node(Node, true), - ok + ?SEV_IPRINT("~p monitored", [Node]), + ok; + (_State) -> + ?SEV_IPRINT("nothing"), + ok end}, #{desc => "start ttest (remote) server", cmd => fun(#{domain := local = Domain, @@ -48261,6 +49695,9 @@ ttest_tcp(InitState) -> case ttest_tcp_server_start(Node, Domain, Mod, Active) of {ok, {{Pid, _}, Path}} -> + ?SEV_IPRINT("server started: " + "~n Pid: ~p" + "~n Path: ~p", [Pid, Path]), {ok, State#{rserver => Pid, path => Path}}; {error, _} = ERROR -> @@ -48273,6 +49710,11 @@ ttest_tcp(InitState) -> case ttest_tcp_server_start(Node, Domain, Mod, Active) of {ok, {{Pid, _}, {Addr, Port}}} -> + ?SEV_IPRINT("server started: " + "~n Pid: ~p" + "~n Addr: ~p" + "~n Port: ~p", + [Pid, Addr, Port]), {ok, State#{rserver => Pid, addr => Addr, port => Port}}; @@ -48301,8 +49743,11 @@ ttest_tcp(InitState) -> case ?SEV_AWAIT_TERMINATE(Tester, tester, [{rserver, RServer}]) of ok -> + ?SEV_IPRINT("received termination request"), {ok, maps:remove(tester, State)}; - {error, _} = ERROR -> + {error, Reason} = ERROR -> + ?SEV_EPRINT("received unexpected error: " + "~n ~p", [Reason]), ERROR end end}, @@ -48320,10 +49765,10 @@ ttest_tcp(InitState) -> State1 = maps:remove(rserver, State), {ok, State1} end}, - #{desc => "stop (server) node", - cmd => fun(#{node := Node} = State) -> + #{desc => "(maybe) stop (server) node", + cmd => fun(#{peer := Peer} = State) when (Peer =/= undefined) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -48337,10 +49782,14 @@ ttest_tcp(InitState) -> "~n Error: ~p" "~n Stack: ~p",[C, E, S]), State#{node_stop => error} - end} + end}; + (_) -> + ?SEV_IPRINT("nothing"), + ok end}, - #{desc => "await (server) node termination", - cmd => fun(#{node := Node, node_stop := ok} = State) -> + #{desc => "(maybe) await (server) node termination", + cmd => fun(#{node := Node, node_stop := ok} = State) + when (Node =/= node()) -> ?SEV_IPRINT("Success node stop - await nodedown"), receive {nodedown, Node} -> @@ -48351,6 +49800,10 @@ ttest_tcp(InitState) -> (#{node_stop := error} = State) -> ?SEV_IPRINT("Failed node stop - cleanup"), State1 = maps:remove(node, State), + {ok, State1}; + (State) -> + ?SEV_IPRINT("nothing"), + State1 = maps:remove(node, State), {ok, State1} end}, @@ -48366,11 +49819,17 @@ ttest_tcp(InitState) -> cmd => fun(#{domain := local} = State) -> {Tester, ServerPath} = ?SEV_AWAIT_START(), + ?SEV_IPRINT("started with server info: " + "~n Path: ~p", [ServerPath]), {ok, State#{tester => Tester, server_path => ServerPath}}; (State) -> {Tester, {ServerAddr, ServerPort}} = ?SEV_AWAIT_START(), + ?SEV_IPRINT("started with server info: " + "~n Addr: ~p" + "~n Port: ~p", + [ServerAddr, ServerPort]), {ok, State#{tester => Tester, server_addr => ServerAddr, server_port => ServerPort}} @@ -48384,18 +49843,24 @@ ttest_tcp(InitState) -> %% *** Init part *** #{desc => "create node", - cmd => fun(#{host := Host} = State) -> - case start_node(Host, client) of - {ok, Node} -> - {ok, State#{node => Node}}; - {error, Reason} -> - {skip, Reason} - end - end}, - #{desc => "monitor client node", - cmd => fun(#{node := Node} = _State) -> + cmd => fun(#{remote := true, host := _Host} = State) -> + %% Because peer does not accept a host argument, + %% we can no longer start "remote" nodes... + %% Not that we actually did that. We always + %% used local-host. + {Peer, Node} = ?START_NODE("client"), + {ok, State#{peer => Peer, node => Node}}; + (State) -> + {ok, State#{peer => undefined, node => node()}} + end}, + #{desc => "(maybe) monitor client node", + cmd => fun(#{node := Node} = _State) when (Node =/= node()) -> true = erlang:monitor_node(Node, true), - ok + ?SEV_IPRINT("~p monitored", [Node]), + ok; + (_) -> + ?SEV_IPRINT("nothing"), + ok end}, #{desc => "announce ready (init)", cmd => fun(#{tester := Tester}) -> @@ -48457,6 +49922,19 @@ ttest_tcp(InitState) -> RunTime) of {ok, {Pid, _MRef}} -> {ok, State#{rclient => Pid}}; + {error, {connect, Reason, ServerInfo} = EI} -> + ?SEV_EPRINT("Failed connecting to server: " + "~n Reason: ~p" + "~n Server: ~p", + [Reason, ServerInfo]), + case Reason of + eaddrnotavail -> + {skip, Reason}; + network_unreachable -> + {skip, Reason}; + _ -> + {error, EI} + end; {error, _} = ERROR -> ERROR end @@ -48496,10 +49974,10 @@ ttest_tcp(InitState) -> ERROR end end}, - #{desc => "stop (client) node", - cmd => fun(#{node := Node} = State) -> + #{desc => "(maybe) stop (client) node", + cmd => fun(#{peer := Peer} = State) when (Peer =/= undefined) -> {ok, - try stop_node(Node) of + try peer:stop(Peer) of ok -> State#{node_stop => ok}; {error, Reason} -> @@ -48513,10 +49991,14 @@ ttest_tcp(InitState) -> "~n Error: ~p" "~n Stack: ~p",[C, E, S]), State#{node_stop => error} - end} + end}; + (_) -> + ?SEV_IPRINT("nothing"), + ok end}, - #{desc => "await (client) node termination", - cmd => fun(#{node := Node, node_stop := ok} = State) -> + #{desc => "(maybe) await (client) node termination", + cmd => fun(#{node := Node, node_stop := ok} = State) + when (Node =/= node()) -> ?SEV_IPRINT("Success node stop - await nodedown"), receive {nodedown, Node} -> @@ -48527,7 +50009,10 @@ ttest_tcp(InitState) -> (#{node_stop := error} = State) -> ?SEV_IPRINT("Failed node stop - cleanup"), State1 = maps:remove(node, State), - {ok, State1} + {ok, State1}; + (_) -> + ?SEV_IPRINT("nothing"), + ok end}, @@ -48750,6 +50235,10 @@ ttest_tcp_server_start(Node, Domain, gen, Active) -> TransportMod = socket_test_ttest_tcp_gen, Transport = {TransportMod, #{domain => Domain}}, socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active); +ttest_tcp_server_start(Node, Domain, gs, Active) -> + TransportMod = socket_test_ttest_tcp_gs, + Transport = {TransportMod, #{domain => Domain}}, + socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active); ttest_tcp_server_start(Node, Domain, sock, Active) -> TransportMod = socket_test_ttest_tcp_socket, Transport = {TransportMod, #{domain => Domain, @@ -48772,6 +50261,18 @@ ttest_tcp_client_start(Node, ServerInfo, Active, MsgID, MaxOutstanding, RunTime); +ttest_tcp_client_start(Node, + Notify, + Domain, gs, + ServerInfo, Active, MsgID, MaxOutstanding, RunTime) -> + TransportMod = socket_test_ttest_tcp_gs, + Transport = {TransportMod, #{domain => Domain}}, + socket_test_ttest_tcp_client:start_monitor(Node, + Notify, + Transport, + ServerInfo, + Active, + MsgID, MaxOutstanding, RunTime); ttest_tcp_client_start(Node, Notify, Domain, sock, @@ -48831,7 +50332,7 @@ ttest_report(Domain, bytes = NumBytes, msgs = NumMsgs}, %% If we run just one test case, the group init has never been run - %% and therefor the ttest manager is not running (we also don't actually + %% and therefore the ttest manager is not running (we also don't actually %% care about collecting reports in that case). (catch global:send(?TTEST_MANAGER, Report)), ok. @@ -48978,13 +50479,10 @@ which_ttest_reports(Domain, MsgID) -> %% Create several acceptor processes (processes that calls socket:accept/1) %% and then a couple of clients connects to them without any problems. %% TCP, IPv4. -otp16359_maccept_tcp4(suite) -> - []; -otp16359_maccept_tcp4(doc) -> - []; otp16359_maccept_tcp4(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(otp16359_maccept_tcp4, + fun() -> has_support_ipv4() end, fun() -> InitState = #{domain => inet, protocol => tcp}, @@ -48997,10 +50495,6 @@ otp16359_maccept_tcp4(_Config) when is_list(_Config) -> %% Create several acceptor processes (processes that calls socket:accept/1) %% and then a couple of clients connects to them without any problems. %% TCP, IPv6. -otp16359_maccept_tcp6(suite) -> - []; -otp16359_maccept_tcp6(doc) -> - []; otp16359_maccept_tcp6(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(otp16359_maccept_tcp6, @@ -49017,10 +50511,6 @@ otp16359_maccept_tcp6(_Config) when is_list(_Config) -> %% Create several acceptor processes (processes that calls socket:accept/1) %% and then a couple of clients connects to them without any problems. %% TCP, UNix Domain Sockets. -otp16359_maccept_tcpL(suite) -> - []; -otp16359_maccept_tcpL(doc) -> - []; otp16359_maccept_tcpL(_Config) when is_list(_Config) -> ?TT(?SECS(10)), tc_try(otp16359_maccept_tcpL, @@ -49635,66 +51125,369 @@ otp16359_maccept_tcp(InitState) -> Tester]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is to verify that we do not leak monitors. +otp18240_accept_mon_leak_tcp4(Config) when is_list(Config) -> + ?TT(?SECS(30)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv4() end, + fun() -> + InitState = #{domain => inet, + protocol => tcp, + num_socks => 10}, + ok = otp18240_accept_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This mechanism has only one purpose: So that we are able to kill -%% the node-starter process if it takes to long. The node-starter -%% runs on the local node. -%% This crapola is hopefully temporary, but we have seen that on -%% some platforms the ct_slave:start simply hangs. --define(NODE_START_TIMEOUT, 10000). -start_node(Host, NodeName) -> - start_node(Host, NodeName, ?NODE_START_TIMEOUT). +%% This test case is to verify that we do not leak monitors. +otp18240_accept_mon_leak_tcp6(Config) when is_list(Config) -> + ?TT(?SECS(30)), + tc_try(?FUNCTION_NAME, + fun() -> has_support_ipv6() end, + fun() -> + InitState = #{domain => inet6, + protocol => tcp, + num_socks => 10}, + ok = otp18240_accept_tcp(InitState) + end). + -start_node(Host, NodeName, Timeout) -> - {NodeStarter, _} = - spawn_monitor(fun() -> exit(start_unique_node(Host, NodeName)) end), +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +otp18240_accept_tcp(#{domain := Domain, + protocol := Proto, + num_socks := NumSocks}) -> + Self = self(), + {Pid, Mon} = spawn_monitor(fun() -> + otp18240_acceptor(Self, + Domain, Proto, + NumSocks) + end), + otp18240_await_acceptor(Pid, Mon). + +otp18240_await_acceptor(Pid, Mon) -> receive - {'DOWN', _, process, NodeStarter, Result} -> - %% i("Node Starter (~p) reported: ~p", [NodeStarter, Result]), - Result - after Timeout -> - exit(NodeStarter, kill), - {error, {failed_starting_node, NodeName, timeout}} + {'DOWN', Mon, process, Pid, ok} -> + i("acceptor successfully terminated"), + ok; + {'DOWN', Mon, process, Pid, {skip, _} = SKIP} -> + i("acceptor successfully terminated"), + exit(SKIP); + {'DOWN', Mon, process, Pid, Info} -> + i("acceptor unexpected termination: " + "~n ~p", [Info]), + exit({unexpected_result, Info}) + after 5000 -> + i("acceptor process (~p) info" + "~n Refs: ~p" + "~n Info: ~p", + [Pid, monitored_by(Pid), erlang:process_info(Pid)]), + otp18240_await_acceptor(Pid, Mon) end. -start_unique_node(Host, NodeName) -> - UniqueNodeName = f("~w_~w", [NodeName, erlang:system_time(millisecond)]), - case do_start_node(Host, UniqueNodeName) of - {ok, _} = OK -> - global:sync(), - %% i("Node ~p started: " - %% "~n Nodes: ~p" - %% "~n Logger: ~p" - %% "~n Global Names: ~p", - %% [NodeName, nodes(), - %% global:whereis_name(socket_test_logger), - %% global:registered_names()]), - OK; - {error, Reason, _} -> - {error, Reason} +otp18240_acceptor(Parent, Domain, Proto, NumSocks) -> + i("[acceptor] begin with: " + "~n Parent: ~p" + "~n Domain: ~p" + "~n Protocol: ~p", [Parent, Domain, Proto]), + MonitoredBy0 = monitored_by(), + ?SLEEP(?SECS(5)), + Addr = case ?LIB:which_local_host_info(Domain) of + {ok, #{addr := A}} -> + A; + {error, Reason} -> + exit({skip, Reason}) + end, + {ok, LSock} = socket:open(Domain, stream, Proto, + #{use_registry => false}), + ok = socket:bind(LSock, #{family => Domain, addr => Addr, port => 0}), + ok = socket:listen(LSock, NumSocks), + ?SLEEP(?SECS(5)), + MonitoredBy1 = monitored_by(), + i("[acceptor]: listen socket created" + "~n 'Montored By' before listen socket: ~p" + "~n 'Montored By' after listen socket: ~p", + [MonitoredBy0, MonitoredBy1]), + + [LSockMon] = MonitoredBy1 -- MonitoredBy0, + + i("[acceptor]: " + "~n Listen Socket Monitor: ~p" + "~n Listen Socket info: ~p", + [LSockMon, socket:info(LSock)]), + + {ok, #{port := Port}} = socket:sockname(LSock), + + i("[acceptor] create ~w clients (connectors)", [NumSocks]), + _Clients = [spawn_link(fun() -> + otp18240_client(CID, + Domain, Proto, + Addr, Port) + end) || CID <- lists:seq(1, NumSocks)], + + i("[acceptor] accept ~w connections", [NumSocks]), + ServSocks = [otp18240_do_accept(AID, LSock) || + AID <- lists:seq(1, NumSocks)], + + i("[acceptor] close accepted connections when: " + "~n Listen Socket info: ~p", [socket:info(LSock)]), + _ = [otp18240_do_close(S) || S <- ServSocks], + + %% at this point in time there should be no monitors from NIFs, + %% because we're not accepting anything + i("[acceptor] check monitor status"), + MonitoredBy2 = monitored_by(), + MonitoredBy3 = MonitoredBy2 -- [Parent, LSockMon], + i("[acceptor] monitor status: " + "~n UnRefs: ~p" + "~n MonitoredBy2: ~p" + "~n MonitoredBy3: ~p", + [[Parent, LSockMon], MonitoredBy2, MonitoredBy3]), + if + ([] =:= MonitoredBy3) -> + i("[acceptor] done"), + socket:close(LSock), + exit(ok); + true -> + socket:close(LSock), + i("[acceptor] Unexpected monitors: " + "~n ~p", [MonitoredBy2]), + exit({unexpected_monitors, MonitoredBy2}) end. -do_start_node(Host, NodeName) when is_list(NodeName) -> - do_start_node(Host, list_to_atom(NodeName)); -do_start_node(Host, NodeName) when is_atom(NodeName) -> - Dir = filename:dirname(code:which(?MODULE)), - Flags = "-pa " ++ Dir, - Opts = [{monitor_master, true}, {erl_flags, Flags}], - ct_slave:start(Host, NodeName, Opts). +otp18240_client(ID, Domain, Proto, Addr, PortNo) -> + i("[connector ~w] try create connector socket", [ID]), + {ok, Sock} = socket:open(Domain, stream, Proto, #{use_registry => false}), + ok = socket:bind(Sock, #{family => Domain, addr => Addr, port => 0}), + %% ok = socket:setopt(Sock, otp, debug, true), + i("[connector ~w] try connect", [ID]), + case socket:connect(Sock, + #{family => Domain, addr => Addr, port => PortNo}) of + ok -> + i("[connector ~w] connected - now try recv", [ID]), + case socket:recv(Sock) of + {ok, Data} -> + i("[connector ~w] received unexpected data: " + "~n ~p", [ID, Data]), + (catch socket:close(Sock)), + exit('unexpected data'); + {error, closed} -> + i("[connector ~w] expected socket close", [ID]); + {error, Reason} -> + i("[connector ~w] unexpected error when reading: " + "~n ~p", [ID, Reason]), + (catch socket:close(Sock)) + end; + {error, {completion_status, #{info := invalid_netname = R} = Reason}} -> + i("[connector ~w] failed connecting: " + "~n ~p", [ID, Reason]), + (catch socket:close(Sock)), + exit({skip, R}); + {error, {completion_status, invalid_netname = Reason}} -> + i("[connector ~w] failed connecting: " + "~n ~p", [ID, Reason]), + (catch socket:close(Sock)), + exit({skip, Reason}); + {error, enetunreach = Reason} -> + i("[connector ~w] failed connecting: " + "~n ~p", [ID, Reason]), + (catch socket:close(Sock)), + exit({skip, Reason}); -stop_node(Node) -> - case ct_slave:stop(Node) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR + {error, Reason} -> + i("[connector ~w] failed connecting: " + "~n ~p", [ID, Reason]), + (catch socket:close(Sock)) + end, + i("[connector ~w] done", [ID]), + ok. + + +otp18240_do_accept(ID, LSock) -> + i("[acceptor ~w] try accept", [ID]), + {ok, Sock} = socket:accept(LSock), + i("[acceptor ~w] accepted: ~p", [ID, Sock]), + {ID, Sock}. + + +otp18240_do_close({ID, Sock}) -> + i("[acceptor ~w] try close ~p", [ID, Sock]), + case socket:close(Sock) of + ok -> + i("[acceptor ~w] socket closed", [ID]), + ok; + {error, Reason} -> + i("[acceptor ~w] failed close socket: " + "~n ~p", [ID, Reason]), + error end. - + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is to verify that we do not leak monitors. +otp18635(Config) when is_list(Config) -> + ?TT(?SECS(10)), + tc_try(?FUNCTION_NAME, + fun() -> + is_not_windows(), + has_support_ipv4() + end, + fun() -> + InitState = #{}, + ok = do_otp18635(InitState) + end). + + +do_otp18635(_) -> + Parent = self(), + + ?P("try create (listen) socket when" + "~n (gen socket) info: ~p" + "~n Sockets: ~p", + [socket:info(), socket:which_sockets()]), + + ?P("Get \"proper\" local socket address"), + LSA = which_local_socket_addr(inet), + + {ok, LSock} = socket:open(inet, stream, #{use_registry => true}), + + ?P("bind (listen) socket to: " + "~n ~p", [LSA]), + ok = socket:bind(LSock, LSA), + + ?P("make listen socket"), + ok = socket:listen(LSock), + + ?P("get sockname for listen socket"), + {ok, SA} = socket:sockname(LSock), + + %% ok = socket:setopt(LSock, otp, debug, true), + + % show handle returned from nowait accept + ?P("try accept with timeout = nowait - expect select when" + "~n (gen socket) info: ~p" + "~n Sockets: ~p", + [socket:info(), socket:which_sockets()]), + {select, {select_info, _, Handle}} = socket:accept(LSock, nowait), + ?P("expected select result: " + "~n Select Handle: ~p" + "~n (gen socket) info: ~p" + "~n Sockets: ~p", + [Handle, socket:info(), socket:which_sockets()]), + + ?SLEEP(?SECS(1)), + + %% perform a blocking accept that will fail (timeout) + ?P("attempt accept with timeout = 500 - expect failure (timeout)"), + {error, timeout} = socket:accept(LSock, 500), + + ?P("await abort message for the first accept call: " + "~n Select Handle: ~p" + "~n (gen socket) info: ~p" + "~n Sockets: ~p", + [Handle, socket:info(), socket:which_sockets()]), + receive + {'$socket', LSock, abort, {Handle, cancelled}} -> + ?P("received expected abort message"), + ok + end, + + %% spawn a client to connect + ?P("spawn connector when" + "~n (gen socket) info: ~p" + "~n Listen Socket info: ~p" + "~n Sockets: ~p", + [socket:info(), socket:info(LSock), socket:which_sockets()]), + {Connector, MRef} = + spawn_monitor( + fun() -> + ?P("[connector] try create socket"), + {ok, CSock} = socket:open(inet, stream), + ?P("[connector] try connect: " + "~n (server) ~p", [SA]), + ok = socket:connect(CSock, SA), + ?P("[connector] connected - inform parent"), + Parent ! {self(), connected}, + ?P("[connector] await termination command"), + receive + {Parent, terminate} -> + ?P("[connector] terminate - close socket"), + (catch socket:close(CSock)), + exit(normal) + end + end), + + ?P("await (connection-) confirmation from connector (~p)", [Connector]), + receive + {Connector, connected} -> + ?P("connector connected"), + ok + end, + + %% We should *not* get *any* select messages; + %% since the second call (that *replaced* the current active request) + %% timeout out + ?P("wait for a select message that should never come"), + Result = + receive + {'$socket', LSock, select, AnyHandle} -> + ?P("received unexpected select message when" + "~n Unexpected Handle: ~p" + "~n (gen socket) info: ~p" + "~n Listen Socket info: ~p" + "~n Sockets: ~p", + [AnyHandle, + socket:info(), socket:info(LSock), socket:which_sockets()]), + error + after 5000 -> + ?P("expected timeout"), + ok + end, + + ?P("try accept the waiting connection when" + "~n (gen socket) info: ~p" + "~n Listen Socket info: ~p" + "~n Sockets: ~p", + [socket:info(), socket:info(LSock), socket:which_sockets()]), + + {ok, ASock} = socket:accept(LSock), + + ?P("connection accepted" + "~n (gen socket) info: ~p" + "~n Accepted socket: ~p" + "~n Accepted Socket info: ~p" + "~n Listen Socket info: ~p" + "~n Sockets: ~p", + [socket:info(), + ASock, + socket:info(ASock), + socket:info(LSock), + socket:which_sockets()]), + + ?P("cleanup"), + socket:close(LSock), + socket:close(ASock), + Connector ! {self(), terminate}, + receive + {'DOWN', MRef, process, Connector, _} -> + ?P("connector terminated"), + ok + end, + + ?SLEEP(?SECS(1)), + + ?P("done when" + "~n (gen socket) info: ~p" + "~n Sockets: ~p", [socket:info(), socket:which_sockets()]), + + Result. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -49778,37 +51571,11 @@ local_host() -> %% The point of this is to "ensure" that paths from different test runs %% don't clash. + mk_unique_path() -> - [NodeName | _] = string:tokens(atom_to_list(node()), [$@]), - Path = ?LIB:f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]), - ensure_unique_path(Path). - -ensure_unique_path(Path) -> - case file:read_file_info(Path) of - {ok, _} -> % Ouch, append a unique ID and try again - ensure_unique_path(Path, 1); - {error, _} -> - %% We assume this means it does not exist yet... - %% If we have several process in paralell trying to create - %% (unique) path's, then we are in trouble. To *really* be - %% on the safe side we should have a (central) path registry... - encode_path(Path) - end. + ?LIB:mk_unique_path(). -ensure_unique_path(Path, ID) when (ID < 100) -> % If this is not enough... - NewPath = ?LIB:f("~s_~w", [Path, ID]), - case file:read_file_info(NewPath) of - {ok, _} -> % Ouch, this also existed, increment and try again - ensure_unique_path(Path, ID + 1); - {error, _} -> % We assume this means it does not exist yet... - encode_path(NewPath) - end; -ensure_unique_path(_, _) -> - skip("Could not create unique path"). -encode_path(Path) -> - unicode:characters_to_binary(Path, file:native_name_encoding()). - which_local_socket_addr(local = Domain) -> #{family => Domain, path => mk_unique_path()}; @@ -49817,14 +51584,22 @@ which_local_socket_addr(local = Domain) -> %% We should really implement this using the (new) net module, %% but until that gets the necessary functionality... which_local_socket_addr(Domain) -> - case ?LIB:which_local_host_info(Domain) of - {ok, #{addr := Addr}} -> + case ?KLIB:which_local_host_info(Domain) of + {ok, [#{addr := Addr}|_]} -> #{family => Domain, addr => Addr}; {error, Reason} -> ?FAIL(Reason) end. +which_local_host_info(Domain) -> + case ?KLIB:which_local_host_info(Domain) of + {ok, [Info|_]} -> + {ok, Info#{family => Domain}}; + {error, Reason} -> + ?FAIL(Reason) + end. + which_local_addr(local = _Domain) -> @@ -49834,8 +51609,16 @@ which_local_addr(local = _Domain) -> %% We should really implement this using the (new) net module, %% but until that gets the necessary functionality... which_local_addr(Domain) -> - ?LIB:which_local_addr(Domain). + ?KLIB:which_local_addr(Domain). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +monitored_by() -> + monitored_by(self()). +monitored_by(Pid) -> + {monitored_by, Refs} = erlang:process_info(Pid, monitored_by), + Refs. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -49878,6 +51661,7 @@ has_support_sock_bindtodevice() -> has_support_socket_option_sock(bindtodevice). has_support_sock_broadcast() -> + has_support_ipv4(), has_support_socket_option_sock(broadcast), case ?LIB:which_local_host_info(inet) of {ok, #{flags := Flags}} -> @@ -49903,6 +51687,21 @@ has_support_sock_dontroute() -> has_support_sock_keepalive() -> has_support_socket_option_sock(keepalive). +has_support_sock_reuseaddr() -> + has_support_socket_option_sock(reuseaddr). + +has_support_sock_bsp_state() -> + has_support_socket_option_sock(bsp_state). + +has_support_sock_exclusiveaddruse() -> + has_support_socket_option_sock(exclusiveaddruse). + +has_support_sock_maxdg() -> + has_support_socket_option_sock(maxdg). + +has_support_sock_max_msg_size() -> + has_support_socket_option_sock(max_msg_size). + has_support_sock_oobinline() -> has_support_socket_option_sock(oobinline). @@ -50026,6 +51825,15 @@ has_support_tcp_maxseg() -> has_support_tcp_nodelay() -> has_support_socket_option_tcp(nodelay). +has_support_tcp_keepcnt() -> + has_support_socket_option_tcp(keepcnt). + +has_support_tcp_keepidle() -> + has_support_socket_option_tcp(keepidle). + +has_support_tcp_keepintvl() -> + has_support_socket_option_tcp(keepintvl). + %% --- UDP socket option test functions --- @@ -50131,11 +51939,19 @@ is_not_netbsd() -> is_not_darwin() -> is_not_platform(darwin, "Darwin"). +is_not_windows() -> + case os:type() of + {win32, nt} -> + skip("This does not work on Windows"); + _ -> + ok + end. + is_not_platform(Platform, PlatformStr) when is_atom(Platform) andalso is_list(PlatformStr) -> case os:type() of - {unix, Platform} -> - skip("This does not work on " ++ PlatformStr); + {unix, Platform} -> + skip("This does not work on " ++ PlatformStr); _ -> ok end. @@ -50150,16 +51966,11 @@ unix_domain_socket_host_cond(_, _) -> ok. has_support_unix_domain_socket() -> - case os:type() of - {win32, _} -> - skip("Not supported"); - _ -> - case socket:is_supported(local) of - true -> - ok; - false -> - skip("Not supported") - end + case socket:is_supported(local) of + true -> + ok; + false -> + skip("Not supported") end. has_support_sctp() -> @@ -50180,10 +51991,23 @@ has_support_sctp() -> %% The idea is that this function shall test if the test host has -%% support for IPv6. If not, there is no point in running IPv6 tests. +%% support for IPv4 or IPv6. If not, there is no point in running corresponding tests. %% Currently we just skip. +has_support_ipv4() -> + ?KLIB:has_support_ipv4(). + has_support_ipv6() -> - ?LIB:has_support_ipv6(). + ?KLIB:has_support_ipv6(). + +inet_or_inet6() -> + try + has_support_ipv4(), + inet + catch + throw:{skip, _Reason} -> + has_support_ipv6(), + inet6 + end. has_support_sendfile() -> try socket:is_supported(sendfile) of @@ -50222,6 +52046,9 @@ has_support_ioctl_requests() -> has_support_ioctl_gifconf() -> has_support_ioctl_request(gifconf). +has_support_ioctl_nread() -> + has_support_ioctl_request(nread). + has_support_ioctl_gifname() -> has_support_ioctl_request(gifname). @@ -50255,6 +52082,9 @@ has_support_ioctl_gifflags() -> has_support_ioctl_gifmap() -> has_support_ioctl_request(gifmap). +has_support_ioctl_tcp_info() -> + has_support_ioctl_request(tcp_info). + has_support_ioctl_request(Req) when is_atom(Req) -> try socket:is_supported(ioctl_requests, Req) of true -> @@ -50409,19 +52239,19 @@ tc_try(Case, TCCondFun, TCFun) end catch C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> - %% i("catched[tc] (skip): " + %% i("caught[tc] (skip): " %% "~n C: ~p" %% "~n SKIP: ~p" %% "~n", [C, SKIP]), - tc_end( f("skipping(catched,~w,tc)", [C]) ), + tc_end( f("skipping(caught,~w,tc)", [C]) ), SKIP; C:E:S -> - %% i("catched[tc]: " + %% i("caught[tc]: " %% "~n C: ~p" %% "~n E: ~p" %% "~n S: ~p" %% "~n", [C, E, S]), - tc_end( f("failed(catched,~w,tc)", [C]) ), + tc_end( f("failed(caught,~w,tc)", [C]) ), erlang:raise(C, E, S) end; {skip, _} = SKIP -> @@ -50432,19 +52262,19 @@ tc_try(Case, TCCondFun, TCFun) exit({tc_cond_failed, Reason}) catch C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> - %% i("catched[cond] (skip): " + %% i("caught[cond] (skip): " %% "~n C: ~p" %% "~n SKIP: ~p" %% "~n", [C, SKIP]), - tc_end( f("skipping(catched,~w,cond)", [C]) ), + tc_end( f("skipping(caught,~w,cond)", [C]) ), SKIP; C:E:S -> - %% i("catched[cond]: " + %% i("caught[cond]: " %% "~n C: ~p" %% "~n E: ~p" %% "~n S: ~p" %% "~n", [C, E, S]), - tc_end( f("failed(catched,~w,cond)", [C]) ), + tc_end( f("failed(caught,~w,cond)", [C]) ), erlang:raise(C, E, S) end. @@ -50472,1020 +52302,42 @@ tc_which_name() -> end. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This function prints various host info, which might be usefull -%% when analyzing the test suite (results). -%% It also returns a "factor" that can be used when deciding -%% the load for some test cases (traffic). Such as run time or -%% number of iterations. This only works for some OSes (linux). -%% Also, mostly it just returns the factor 1. -%% At this time we just look at BogoMIPS! -analyze_and_print_host_info() -> - {OsFam, OsName} = os:type(), - Version = - case os:version() of - {Maj, Min, Rel} -> - f("~w.~w.~w", [Maj, Min, Rel]); - VStr -> - VStr - end, - case {OsFam, OsName} of - {unix, linux} -> - analyze_and_print_linux_host_info(Version); - {unix, openbsd} -> - analyze_and_print_openbsd_host_info(Version); - {unix, freebsd} -> - analyze_and_print_freebsd_host_info(Version); - {unix, netbsd} -> - analyze_and_print_netbsd_host_info(Version); - {unix, sunos} -> - analyze_and_print_solaris_host_info(Version); - {win32, nt} -> - analyze_and_print_win_host_info(Version); - _ -> - io:format("OS Family: ~p" - "~n OS Type: ~p" - "~n Version: ~p" - "~n Num Schedulers: ~s" - "~n", [OsFam, OsName, Version, str_num_schedulers()]), - num_schedulers_to_factor() - end. - -str_num_schedulers() -> - try erlang:system_info(schedulers) of - N -> f("~w", [N]) - catch - _:_:_ -> "-" - end. - -num_schedulers_to_factor() -> - try erlang:system_info(schedulers) of - 1 -> - 10; - 2 -> - 5; - N when (N =< 6) -> - 2; - _ -> - 1 - catch - _:_:_ -> - 10 - end. - - - -%% --- Linux --- - -linux_which_distro(Version) -> - case file:read_file_info("/etc/issue") of - {ok, _} -> - case [string:trim(S) || - S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of - [DistroStr|_] -> - io:format("Linux: ~s" - "~n ~s" - "~n", - [Version, DistroStr]), - case DistroStr of - "Wind River Linux" ++ _ -> - wind_river; - "MontaVista" ++ _ -> - montavista; - "Yellow Dog" ++ _ -> - yellow_dog; - _ -> - other - end; - X -> - io:format("Linux: ~s" - "~n ~p" - "~n", - [Version, X]), - other - end; - _ -> - io:format("Linux: ~s" - "~n", [Version]), - other - end. - - -analyze_and_print_linux_host_info(Version) -> - Distro = linux_which_distro(Version), - Factor = - case (catch linux_which_cpuinfo(Distro)) of - {ok, {CPU, BogoMIPS}} -> - io:format("CPU: " - "~n Model: ~s" - "~n BogoMIPS: ~w" - "~n Num Schedulers: ~s" - "~n", [CPU, BogoMIPS, str_num_schedulers()]), - if - (BogoMIPS > 20000) -> - 1; - (BogoMIPS > 10000) -> - 2; - (BogoMIPS > 5000) -> - 3; - (BogoMIPS > 2000) -> - 5; - (BogoMIPS > 1000) -> - 8; - true -> - 10 - end; - {ok, CPU} -> - io:format("CPU: " - "~n Model: ~s" - "~n Num Schedulers: ~s" - "~n", [CPU, str_num_schedulers()]), - num_schedulers_to_factor(); - _ -> - 5 - end, - %% Check if we need to adjust the factor because of the memory - try linux_which_meminfo() of - AddFactor -> - Factor + AddFactor - catch - _:_:_ -> - Factor - end. - - -linux_cpuinfo_lookup(Key) when is_list(Key) -> - linux_info_lookup(Key, "/proc/cpuinfo"). - -linux_cpuinfo_cpu() -> - case linux_cpuinfo_lookup("cpu") of - [Model] -> - Model; - _ -> - "-" - end. - -linux_cpuinfo_motherboard() -> - case linux_cpuinfo_lookup("motherboard") of - [MB] -> - MB; - _ -> - "-" - end. - -linux_cpuinfo_bogomips() -> - case linux_cpuinfo_lookup("bogomips") of - BMips when is_list(BMips) -> - try lists:sum([bogomips_to_int(BM) || BM <- BMips]) - catch - _:_:_ -> - "-" - end; - _ -> - "-" - end. - -linux_cpuinfo_total_bogomips() -> - case linux_cpuinfo_lookup("total bogomips") of - [TBM] -> - try bogomips_to_int(TBM) - catch - _:_:_ -> - "-" - end; - _ -> - "-" - end. - -bogomips_to_int(BM) -> - try list_to_float(BM) of - F -> - floor(F) - catch - _:_:_ -> - try list_to_integer(BM) of - I -> - I - catch - _:_:_ -> - throw(noinfo) - end - end. - -linux_cpuinfo_model() -> - case linux_cpuinfo_lookup("model") of - [M] -> - M; - _ -> - "-" - end. - -linux_cpuinfo_platform() -> - case linux_cpuinfo_lookup("platform") of - [P] -> - P; - _ -> - "-" - end. - -linux_cpuinfo_model_name() -> - case linux_cpuinfo_lookup("model name") of - [P|_] -> - P; - _X -> - "-" - end. - -linux_cpuinfo_processor() -> - case linux_cpuinfo_lookup("Processor") of - [P] -> - P; - _ -> - "-" - end. - -linux_which_cpuinfo(montavista) -> - CPU = - case linux_cpuinfo_cpu() of - "-" -> - throw(noinfo); - Model -> - case linux_cpuinfo_motherboard() of - "-" -> - Model; - MB -> - Model ++ " (" ++ MB ++ ")" - end - end, - case linux_cpuinfo_bogomips() of - "-" -> - {ok, CPU}; - BMips -> - {ok, {CPU, BMips}} - end; - -linux_which_cpuinfo(yellow_dog) -> - CPU = - case linux_cpuinfo_cpu() of - "-" -> - throw(noinfo); - Model -> - case linux_cpuinfo_motherboard() of - "-" -> - Model; - MB -> - Model ++ " (" ++ MB ++ ")" - end - end, - {ok, CPU}; - -linux_which_cpuinfo(wind_river) -> - CPU = - case linux_cpuinfo_model() of - "-" -> - throw(noinfo); - Model -> - case linux_cpuinfo_platform() of - "-" -> - Model; - Platform -> - Model ++ " (" ++ Platform ++ ")" - end - end, - case linux_cpuinfo_total_bogomips() of - "-" -> - {ok, CPU}; - BMips -> - {ok, {CPU, BMips}} - end; - -linux_which_cpuinfo(other) -> - %% Check for x86 (Intel or AMD) - CPU = - case linux_cpuinfo_model_name() of - "-" -> - %% ARM (at least some distros...) - case linux_cpuinfo_processor() of - "-" -> - %% Ok, we give up - throw(noinfo); - Proc -> - Proc - end; - ModelName -> - ModelName - end, - case linux_cpuinfo_bogomips() of - "-" -> - {ok, CPU}; - BMips -> - {ok, {CPU, BMips}} - end. - -linux_meminfo_lookup(Key) when is_list(Key) -> - linux_info_lookup(Key, "/proc/meminfo"). - -linux_meminfo_memtotal() -> - case linux_meminfo_lookup("MemTotal") of - [X] -> - X; - _ -> - "-" - end. - -%% We *add* the value this return to the Factor. -linux_which_meminfo() -> - case linux_meminfo_memtotal() of - "-" -> - 0; - MemTotal -> - io:format("Memory:" - "~n ~s" - "~n", [MemTotal]), - case string:tokens(MemTotal, [$ ]) of - [MemSzStr, MemUnit] -> - MemSz2 = list_to_integer(MemSzStr), - MemSz3 = - case string:to_lower(MemUnit) of - "kb" -> - MemSz2; - "mb" -> - MemSz2*1024; - "gb" -> - MemSz2*1024*1024; - _ -> - throw(noinfo) - end, - if - (MemSz3 >= 8388608) -> - 0; - (MemSz3 >= 4194304) -> - 1; - (MemSz3 >= 2097152) -> - 3; - true -> - 5 - end; - _X -> - 0 - end - end. - - -linux_info_lookup(Key, File) -> - try [string:trim(S) || S <- string:tokens(os:cmd("grep " ++ "\"" ++ Key ++ "\"" ++ " " ++ File), [$:,$\n])] of - Info -> - linux_info_lookup_collect(Key, Info, []) - catch - _:_:_ -> - "-" - end. - -linux_info_lookup_collect(_Key, [], Values) -> - lists:reverse(Values); -linux_info_lookup_collect(Key, [Key, Value|Rest], Values) -> - linux_info_lookup_collect(Key, Rest, [Value|Values]); -linux_info_lookup_collect(_, _, Values) -> - lists:reverse(Values). - - -%% --- OpenBSD --- - -%% Just to be clear: This is ***not*** scientific... -analyze_and_print_openbsd_host_info(Version) -> - io:format("OpenBSD:" - "~n Version: ~p" - "~n", [Version]), - Extract = - fun(Key) -> - string:tokens(string:trim(os:cmd("sysctl " ++ Key)), [$=]) - end, - try - begin - CPU = - case Extract("hw.model") of - ["hw.model", Model] -> - string:trim(Model); - _ -> - "-" - end, - CPUSpeed = - case Extract("hw.cpuspeed") of - ["hw.cpuspeed", Speed] -> - list_to_integer(Speed); - _ -> - -1 - end, - NCPU = - case Extract("hw.ncpufound") of - ["hw.ncpufound", N] -> - list_to_integer(N); - _ -> - -1 - end, - Memory = - case Extract("hw.physmem") of - ["hw.physmem", PhysMem] -> - list_to_integer(PhysMem) div 1024; - _ -> - -1 - end, - io:format("CPU:" - "~n Model: ~s" - "~n Speed: ~w" - "~n N: ~w" - "~nMemory:" - "~n ~w KB" - "~n", [CPU, CPUSpeed, NCPU, Memory]), - CPUFactor = - if - (CPUSpeed =:= -1) -> - 1; - (CPUSpeed >= 2000) -> - if - (NCPU >= 4) -> - 1; - (NCPU >= 2) -> - 2; - true -> - 3 - end; - true -> - if - (NCPU >= 4) -> - 2; - (NCPU >= 2) -> - 3; - true -> - 4 - end - end, - MemAddFactor = - if - (Memory =:= -1) -> - 0; - (Memory >= 8388608) -> - 0; - (Memory >= 4194304) -> - 1; - (Memory >= 2097152) -> - 2; - true -> - 3 - end, - CPUFactor + MemAddFactor - end - catch - _:_:_ -> - 1 - end. - - -%% --- FreeBSD --- - -analyze_and_print_freebsd_host_info(Version) -> - io:format("FreeBSD:" - "~n Version: ~p" - "~n", [Version]), - %% This test require that the program 'sysctl' is in the path. - %% First test with 'which sysctl', if that does not work - %% try with 'which /sbin/sysctl'. If that does not work either, - %% we skip the test... - try - begin - SysCtl = - case string:trim(os:cmd("which sysctl")) of - [] -> - case string:trim(os:cmd("which /sbin/sysctl")) of - [] -> - throw(sysctl); - SC2 -> - SC2 - end; - SC1 -> - SC1 - end, - Extract = - fun(Key) -> - string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), - [$:]) - end, - CPU = analyze_freebsd_cpu(Extract), - CPUSpeed = analyze_freebsd_cpu_speed(Extract), - NCPU = analyze_freebsd_ncpu(Extract), - Memory = analyze_freebsd_memory(Extract), - io:format("CPU:" - "~n Model: ~s" - "~n Speed: ~w" - "~n N: ~w" - "~n Num Schedulers: ~w" - "~nMemory:" - "~n ~w KB" - "~n", - [CPU, CPUSpeed, NCPU, - erlang:system_info(schedulers), Memory]), - CPUFactor = - if - (CPUSpeed =:= -1) -> - 1; - (CPUSpeed >= 2000) -> - if - (NCPU >= 4) -> - 1; - (NCPU >= 2) -> - 2; - true -> - 3 - end; - true -> - if - (NCPU =:= -1) -> - 1; - (NCPU >= 4) -> - 2; - (NCPU >= 2) -> - 3; - true -> - 4 - end - end, - MemAddFactor = - if - (Memory =:= -1) -> - 0; - (Memory >= 8388608) -> - 0; - (Memory >= 4194304) -> - 1; - (Memory >= 2097152) -> - 2; - true -> - 3 - end, - CPUFactor + MemAddFactor - end - catch - _:_:_ -> - io:format("CPU:" - "~n Num Schedulers: ~w" - "~n", [erlang:system_info(schedulers)]), - case erlang:system_info(schedulers) of - 1 -> - 10; - 2 -> - 5; - _ -> - 2 - end - end. - -analyze_freebsd_cpu(Extract) -> - analyze_freebsd_item(Extract, "hw.model", fun(X) -> X end, "-"). - -analyze_freebsd_cpu_speed(Extract) -> - analyze_freebsd_item(Extract, - "hw.clockrate", - fun(X) -> list_to_integer(X) end, - -1). - -analyze_freebsd_ncpu(Extract) -> - analyze_freebsd_item(Extract, - "hw.ncpu", - fun(X) -> list_to_integer(X) end, - -1). - -analyze_freebsd_memory(Extract) -> - analyze_freebsd_item(Extract, - "hw.physmem", - fun(X) -> list_to_integer(X) div 1024 end, - -1). - -analyze_freebsd_item(Extract, Key, Process, Default) -> - try - begin - case Extract(Key) of - [Key, Model] -> - Process(string:trim(Model)); - _ -> - Default - end - end - catch - _:_:_ -> - Default - end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% --- NetBSD --- +%% start_node(Name) -> +%% start_node(Name, 5000). -analyze_and_print_netbsd_host_info(Version) -> - io:format("NetBSD:" - "~n Version: ~p" - "~n", [Version]), - %% This test require that the program 'sysctl' is in the path. - %% First test with 'which sysctl', if that does not work - %% try with 'which /sbin/sysctl'. If that does not work either, - %% we skip the test... - try - begin - SysCtl = - case string:trim(os:cmd("which sysctl")) of - [] -> - case string:trim(os:cmd("which /sbin/sysctl")) of - [] -> - throw(sysctl); - SC2 -> - SC2 - end; - SC1 -> - SC1 - end, - Extract = - fun(Key) -> - [string:trim(S) || - S <- - string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)), - [$=])] - end, - CPU = analyze_netbsd_cpu(Extract), - Machine = analyze_netbsd_machine(Extract), - Arch = analyze_netbsd_machine_arch(Extract), - CPUSpeed = analyze_netbsd_cpu_speed(Extract), - NCPU = analyze_netbsd_ncpu(Extract), - Memory = analyze_netbsd_memory(Extract), - io:format("CPU:" - "~n Model: ~s (~s, ~s)" - "~n Speed: ~w MHz" - "~n N: ~w" - "~n Num Schedulers: ~w" - "~nMemory:" - "~n ~w KB" - "~n", - [CPU, Machine, Arch, CPUSpeed, NCPU, - erlang:system_info(schedulers), Memory]), - CPUFactor = - if - (CPUSpeed =:= -1) -> - 1; - (CPUSpeed >= 2000) -> - if - (NCPU >= 4) -> - 1; - (NCPU >= 2) -> - 2; - true -> - 3 - end; - true -> - if - (NCPU =:= -1) -> - 1; - (NCPU >= 4) -> - 2; - (NCPU >= 2) -> - 3; - true -> - 4 - end - end, - MemAddFactor = - if - (Memory =:= -1) -> - 0; - (Memory >= 8388608) -> - 0; - (Memory >= 4194304) -> - 1; - (Memory >= 2097152) -> - 2; - true -> - 3 - end, - CPUFactor + MemAddFactor - end +start_node(Name, Timeout) when is_integer(Timeout) andalso (Timeout > 0) -> + try ?CT_PEER(#{name => Name, wait_boot => Timeout}) of + {ok, Peer, Node} -> + ?SEV_IPRINT("Started node ~p", [Name]), + {Peer, Node}; + {error, Reason} -> + ?SEV_EPRINT("failed starting node ~p (=> SKIP):" + "~n ~p", [Name, Reason]), + skip(Reason) catch - _:_:_ -> - io:format("CPU:" - "~n Num Schedulers: ~w" - "~n", [erlang:system_info(schedulers)]), - case erlang:system_info(schedulers) of - 1 -> - 10; - 2 -> - 5; - _ -> - 2 - end + Class:Reason:Stack -> + ?SEV_EPRINT("Failed starting node: " + "~n Class: ~p" + "~n Reason: ~p" + "~n Stack: ~p", + [Class, Reason, Stack]), + skip({node_start, Class, Reason}) end. -analyze_netbsd_cpu(Extract) -> - analyze_netbsd_item(Extract, "hw.model", fun(X) -> X end, "-"). - -analyze_netbsd_machine(Extract) -> - analyze_netbsd_item(Extract, "hw.machine", fun(X) -> X end, "-"). - -analyze_netbsd_machine_arch(Extract) -> - analyze_netbsd_item(Extract, "hw.machine_arch", fun(X) -> X end, "-"). - -analyze_netbsd_cpu_speed(Extract) -> - analyze_netbsd_item(Extract, "machdep.dmi.processor-frequency", - fun(X) -> case string:tokens(X, [$\ ]) of - [MHz, "MHz"] -> - list_to_integer(MHz); - _ -> - -1 - end - end, "-"). - -analyze_netbsd_ncpu(Extract) -> - analyze_netbsd_item(Extract, - "hw.ncpu", - fun(X) -> list_to_integer(X) end, - -1). - -analyze_netbsd_memory(Extract) -> - analyze_netbsd_item(Extract, - "hw.physmem64", - fun(X) -> list_to_integer(X) div 1024 end, - -1). - -analyze_netbsd_item(Extract, Key, Process, Default) -> - analyze_freebsd_item(Extract, Key, Process, Default). - - - -%% --- Solaris --- - -analyze_and_print_solaris_host_info(Version) -> - Release = - case file:read_file_info("/etc/release") of - {ok, _} -> - case [string:trim(S) || S <- string:tokens(os:cmd("cat /etc/release"), [$\n])] of - [Rel | _] -> - Rel; - _ -> - "-" - end; - _ -> - "-" - end, - %% Display the firmware device tree root properties (prtconf -b) - Props = [list_to_tuple([string:trim(PS) || PS <- Prop]) || - Prop <- [string:tokens(S, [$:]) || - S <- string:tokens(os:cmd("prtconf -b"), [$\n])]], - BannerName = case lists:keysearch("banner-name", 1, Props) of - {value, {_, BN}} -> - string:trim(BN); - _ -> - "-" - end, - InstructionSet = - case string:trim(os:cmd("isainfo -k")) of - "Pseudo-terminal will not" ++ _ -> - "-"; - IS -> - IS - end, - PtrConf = [list_to_tuple([string:trim(S) || S <- Items]) || Items <- [string:tokens(S, [$:]) || S <- string:tokens(os:cmd("prtconf"), [$\n])], length(Items) > 1], - SysConf = - case lists:keysearch("System Configuration", 1, PtrConf) of - {value, {_, SC}} -> - SC; - _ -> - "-" - end, - NumPhysProc = - begin - NPPStr = string:trim(os:cmd("psrinfo -p")), - try list_to_integer(NPPStr) of - _ -> - NPPStr - catch - _:_:_ -> - "-" - end - end, - NumProc = try integer_to_list(length(string:tokens(os:cmd("psrinfo"), [$\n]))) of - NPStr -> - NPStr - catch - _:_:_ -> - "-" - end, - MemSz = - case lists:keysearch("Memory size", 1, PtrConf) of - {value, {_, MS}} -> - MS; - _ -> - "-" - end, - io:format("Solaris: ~s" - "~n Release: ~s" - "~n Banner Name: ~s" - "~n Instruction Set: ~s" - "~n CPUs: ~s (~s)" - "~n System Config: ~s" - "~n Memory Size: ~s" - "~n Num Schedulers: ~s" - "~n~n", [Version, Release, BannerName, InstructionSet, - NumPhysProc, NumProc, - SysConf, MemSz, - str_num_schedulers()]), - MemFactor = - try string:tokens(MemSz, [$ ]) of - [SzStr, "Mega" ++ _] -> - try list_to_integer(SzStr) of - Sz when Sz > 8192 -> - 0; - Sz when Sz > 4096 -> - 1; - Sz when Sz > 2048 -> - 2; - _ -> - 5 - catch - _:_:_ -> - 10 - end; - [SzStr, "Giga" ++ _] -> - try list_to_integer(SzStr) of - Sz when Sz > 8 -> - 0; - Sz when Sz > 4 -> - 1; - Sz when Sz > 2 -> - 2; - _ -> - 5 - catch - _:_:_ -> - 10 - end; - _ -> - 10 - catch - _:_:_ -> - 10 - end, - try erlang:system_info(schedulers) of - 1 -> - 10; - 2 -> - 5; - N when (N =< 6) -> - 2; - _ -> - 1 - catch - _:_:_ -> - 10 - end + MemFactor. - - -%% --- Windows --- - -analyze_and_print_win_host_info(Version) -> - SysInfo = which_win_system_info(), - OsName = win_sys_info_lookup(os_name, SysInfo), - OsVersion = win_sys_info_lookup(os_version, SysInfo), - SysMan = win_sys_info_lookup(system_manufacturer, SysInfo), - SysMod = win_sys_info_lookup(system_model, SysInfo), - NumProcs = win_sys_info_lookup(num_processors, SysInfo), - TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo), - io:format("Windows: ~s" - "~n OS Version: ~s (~p)" - "~n System Manufacturer: ~s" - "~n System Model: ~s" - "~n Number of Processor(s): ~s" - "~n Total Physical Memory: ~s" - "~n Num Schedulers: ~s" - "~n", [OsName, OsVersion, Version, - SysMan, SysMod, NumProcs, TotPhysMem, - str_num_schedulers()]), - MemFactor = - try - begin - [MStr, MUnit|_] = - string:tokens(lists:delete($,, TotPhysMem), [$\ ]), - case string:to_lower(MUnit) of - "gb" -> - try list_to_integer(MStr) of - M when M > 8 -> - 0; - M when M > 4 -> - 1; - M when M > 2 -> - 2; - _ -> - 5 - catch - _:_:_ -> - 10 - end; - "mb" -> - try list_to_integer(MStr) of - M when M > 8192 -> - 0; - M when M > 4096 -> - 1; - M when M > 2048 -> - 2; - _ -> - 5 - catch - _:_:_ -> - 10 - end; - _ -> - 10 - end - end - catch - _:_:_ -> - 10 - end, - CPUFactor = - case erlang:system_info(schedulers) of - 1 -> - 10; - 2 -> - 5; - _ -> - 2 - end, - CPUFactor + MemFactor. - -win_sys_info_lookup(Key, SysInfo) -> - win_sys_info_lookup(Key, SysInfo, "-"). - -win_sys_info_lookup(Key, SysInfo, Def) -> - case lists:keysearch(Key, 1, SysInfo) of - {value, {Key, Value}} -> - Value; - false -> - Def - end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This function only extracts the prop(s) we actually care about! -%% On some hosts this (systeminfo) takes a *long time* (several minutes). -%% And since there is no way to provide a timeout to the os command call, -%% we have to wrap it in a process. -which_win_system_info() -> - F = fun() -> - try - begin - SysInfo = os:cmd("systeminfo"), - process_win_system_info( - string:tokens(SysInfo, [$\r, $\n]), []) - end - catch - C:E:S -> - io:format("Failed get or process System info: " - " Error Class: ~p" - " Error: ~p" - " Stack: ~p" - "~n", [C, E, S]), - [] - end - end, - ?LIB:pcall(F, ?MINS(1), []). - -process_win_system_info([], Acc) -> - Acc; -process_win_system_info([H|T], Acc) -> - case string:tokens(H, [$:]) of - [Key, Value] -> - case string:to_lower(Key) of - "os name" -> - process_win_system_info(T, - [{os_name, string:trim(Value)}|Acc]); - "os version" -> - process_win_system_info(T, - [{os_version, string:trim(Value)}|Acc]); - "system manufacturer" -> - process_win_system_info(T, - [{system_manufacturer, string:trim(Value)}|Acc]); - "system model" -> - process_win_system_info(T, - [{system_model, string:trim(Value)}|Acc]); - "processor(s)" -> - [NumProcStr|_] = string:tokens(Value, [$\ ]), - T2 = lists:nthtail(list_to_integer(NumProcStr), T), - process_win_system_info(T2, - [{num_processors, NumProcStr}|Acc]); - "total physical memory" -> - process_win_system_info(T, - [{total_phys_memory, string:trim(Value)}|Acc]); - _ -> - process_win_system_info(T, Acc) - end; - _ -> - process_win_system_info(T, Acc) - end. - +mq() -> + mq(self()). +mq(Pid) when is_pid(Pid) -> + {messages, MQ} = process_info(Pid, messages), + MQ. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% nowait(Config) -> @@ -51502,9 +52354,6 @@ sock_port(S) -> {ok, #{}} -> undefined end. -l2a(S) when is_list(S) -> - list_to_atom(S). - l2b(L) when is_list(L) -> list_to_binary(L). diff --git a/lib/kernel/test/socket_test_evaluator.erl b/lib/kernel/test/socket_test_evaluator.erl index 70ab63bbc7ec..49b529461ff6 100644 --- a/lib/kernel/test/socket_test_evaluator.erl +++ b/lib/kernel/test/socket_test_evaluator.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2022. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -26,7 +26,7 @@ await_finish/1 ]). -%% Functions used by evaluators to interact with eachother +%% Functions used by evaluators to interact with each other -export([ %% Announce functions %% (Send an announcement from one evaluator to another) @@ -134,11 +134,16 @@ loop(ID, [#{desc := Desc, "~n ~p", [ID, Reason]), exit({command_failed, ID, Reason, State}) catch + error:notsup = Reason:Stack -> + ?SEV_IPRINT("command ~w skip: " + "~n ~p" + "~n ~p", [ID, Reason, Stack]), + exit({skip, Reason}); C:{skip, command} = E:_ when ((C =:= throw) orelse (C =:= exit)) -> %% Secondary skip exit(E); C:{skip, R} = E:_ when ((C =:= throw) orelse (C =:= exit)) -> - ?SEV_IPRINT("command ~w skip catched(~w): " + ?SEV_IPRINT("command ~w skip caught(~w): " "~n Reason: ~p", [ID, C, R]), exit(E); C:E:S -> @@ -166,7 +171,7 @@ await_finish([], _OK, Fails) -> Fails; await_finish(Evs, OK, Fails) -> receive - %% Successfull termination of evaluator + %% Successful termination of evaluator {'DOWN', _MRef, process, Pid, normal} -> {Evs2, OK2, Fails2} = await_finish_normal(Pid, Evs, OK, Fails), await_finish(Evs2, OK2, Fails2); @@ -176,14 +181,14 @@ await_finish(Evs, OK, Fails) -> %% The evaluator can skip the test case: {'DOWN', _MRef, process, Pid, {skip, Reason}} -> - %% ?SEV_IPRINT("await_finish -> skip (down) received: " - %% "~n Pid: ~p" - %% "~n Reason: ~p", [Pid, Reason]), + ?SEV_IPRINT("await_finish -> skip (down) received: " + "~n Pid: ~p" + "~n Reason: ~p", [Pid, Reason]), await_finish_skip(Pid, Reason, Evs, OK); {'EXIT', Pid, {skip, Reason}} -> - %% ?SEV_IPRINT("await_finish -> skip (exit) received: " - %% "~n Pid: ~p" - %% "~n Reason: ~p", [Pid, Reason]), + ?SEV_IPRINT("await_finish -> skip (exit) received: " + "~n Pid: ~p" + "~n Reason: ~p", [Pid, Reason]), await_finish_skip(Pid, Reason, Evs, OK); %% Evaluator failed @@ -242,7 +247,9 @@ await_finish_skip(Pid, Reason, Evs, OK) -> end, Evs end, + ?SEV_IPRINT("ensure (~w) evaluator(s) are terminated", [length(Evs)]), await_evs_terminated(Evs2), + ?SEV_IPRINT("issue skip"), ?LIB:skip(Reason). await_evs_terminated(Evs) -> @@ -576,7 +583,7 @@ await(ExpPid, Name, Announcement, Slogan, OtherPids) {'DOWN', _, process, Pid, {skip, SkipReason}} when (Pid =:= ExpPid) -> iprint("Unexpected SKIP from ~w (~p): " "~n ~p", [Name, Pid, SkipReason]), - ?LIB:skip({Name, SkipReason}); + ?LIB:skip(SkipReason); {'DOWN', _, process, Pid, Reason} when (Pid =:= ExpPid) -> eprint("Unexpected DOWN from ~w (~p): " "~n ~p", [Name, Pid, Reason]), @@ -590,10 +597,16 @@ await(ExpPid, Name, Announcement, Slogan, OtherPids) "~n OtherPids: " "~n ~p", [OtherPid, Reason, OtherPids]), await(ExpPid, Name, Announcement, Slogan, OtherPids); + {skip, SkipName, SkipReason} -> + iprint("Unexpected other SKIP from ~w (~p): " + "~n ~p", [SkipName, OtherPid, SkipReason]), + ?LIB:skip(SkipReason); {error, _} = ERROR -> ERROR end - after infinity -> % For easy debugging, just change to some valid time (5000) + + %% For easy debugging, just change to some valid time (5000) + after infinity -> iprint("await -> timeout for msg from ~p (~w): " "~n Announcement: ~p" "~n Slogan: ~p" @@ -613,9 +626,14 @@ pi(Pid, Item) -> check_down(Pid, DownReason, Pids) -> case lists:keysearch(Pid, 2, Pids) of {value, {Name, _}} -> - eprint("Unexpected DOWN from ~w (~p): " - "~n ~p", [Name, Pid, DownReason]), - {error, {unexpected_exit, Name, DownReason}}; + case DownReason of + {skip, Reason} -> + {skip, Name, Reason}; + _ -> + eprint("Unexpected DOWN from ~w (~p): " + "~n ~p", [Name, Pid, DownReason]), + {error, {unexpected_exit, Name, DownReason}} + end; false -> ok end. diff --git a/lib/kernel/test/socket_test_lib.erl b/lib/kernel/test/socket_test_lib.erl index 56da2997e76c..2d8b4f5181da 100644 --- a/lib/kernel/test/socket_test_lib.erl +++ b/lib/kernel/test/socket_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2022. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -41,8 +41,10 @@ print/1, print/2, %% Generic 'has support' test function(s) + has_support_ipv4/0, has_support_ipv6/0, + mk_unique_path/0, which_local_host_info/1, which_local_addr/1, @@ -54,6 +56,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(LIB, kernel_test_lib). -define(FAIL(R), exit(R)). @@ -123,73 +126,131 @@ print(F, A) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -has_support_ipv6() -> - case socket:is_supported(ipv6) of - true -> - ok; - false -> - skip("IPv6 Not Supported") - end, - Domain = inet6, - LocalAddr = - case which_local_addr(Domain) of - {ok, Addr} -> - Addr; - {error, R1} -> - skip(f("Local Address eval failed: ~p", [R1])) - end, - ServerSock = - case socket:open(Domain, dgram, udp) of - {ok, SS} -> - SS; - {error, R2} -> - skip(f("(server) socket open failed: ~p", [R2])) - end, - LocalSA = #{family => Domain, addr => LocalAddr}, - ServerPort = - case socket:bind(ServerSock, LocalSA) of - ok -> - {ok, #{port := P1}} = socket:sockname(ServerSock), - P1; - {error, R3} -> - socket:close(ServerSock), - skip(f("(server) socket bind failed: ~p", [R3])) - end, - ServerSA = LocalSA#{port => ServerPort}, - ClientSock = - case socket:open(Domain, dgram, udp) of - {ok, CS} -> - CS; - {error, R4} -> - skip(f("(client) socket open failed: ~p", [R4])) - end, - case socket:bind(ClientSock, LocalSA) of - ok -> - ok; - {error, R5} -> - socket:close(ServerSock), - socket:close(ClientSock), - skip(f("(client) socket bind failed: ~p", [R5])) - end, - case socket:sendto(ClientSock, <<"hejsan">>, ServerSA) of - ok -> - ok; - {error, R6} -> - socket:close(ServerSock), - socket:close(ClientSock), - skip(f("failed socket sendto test: ~p", [R6])) - end, - case socket:recvfrom(ServerSock) of - {ok, {_, <<"hejsan">>}} -> - socket:close(ServerSock), - socket:close(ClientSock), +has_support_ipv4() -> + case which_local_addr(inet) of + {ok, _Addr} -> ok; - {error, R7} -> - socket:close(ServerSock), - socket:close(ClientSock), - skip(f("failed socket recvfrom test: ~p", [R7])) - end. - + {error, R1} -> + skip(f("Local Address eval failed: ~p", [R1])) + end. + +has_support_ipv6() -> + try + begin + case socket:is_supported(ipv6) of + true -> + ok; + false -> + skip("IPv6 Not Supported") + end, + Domain = inet6, + LocalAddr = + case which_local_addr(Domain) of + {ok, Addr} -> + Addr; + {error, R1} -> + skip(f("Local Address eval failed: ~p", [R1])) + end, + ServerSock = + case socket:open(Domain, dgram, udp) of + {ok, SS} -> + SS; + {error, R2} -> + skip(f("(server) socket open failed: ~p", [R2])) + end, + LocalSA = #{family => Domain, addr => LocalAddr}, + ServerPort = + case socket:bind(ServerSock, LocalSA) of + ok -> + {ok, #{port := P1}} = socket:sockname(ServerSock), + P1; + {error, R3} -> + socket:close(ServerSock), + skip(f("(server) socket bind failed: ~p", [R3])) + end, + ServerSA = LocalSA#{port => ServerPort}, + ClientSock = + case socket:open(Domain, dgram, udp) of + {ok, CS} -> + CS; + {error, R4} -> + skip(f("(client) socket open failed: ~p", [R4])) + end, + case socket:bind(ClientSock, LocalSA) of + ok -> + ok; + {error, R5} -> + socket:close(ServerSock), + socket:close(ClientSock), + skip(f("(client) socket bind failed: ~p", [R5])) + end, + case socket:sendto(ClientSock, <<"hejsan">>, ServerSA) of + ok -> + ok; + {error, R6} -> + socket:close(ServerSock), + socket:close(ClientSock), + skip(f("failed socket sendto test: ~p", [R6])) + end, + case socket:recvfrom(ServerSock) of + {ok, {_, <<"hejsan">>}} -> + socket:close(ServerSock), + socket:close(ClientSock), + ok; + {error, R7} -> + socket:close(ServerSock), + socket:close(ClientSock), + skip(f("failed socket recvfrom test: ~p", [R7])) + end + end + catch + error : notsup -> + skip("Not supported: socket") + end. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +mk_unique_path() -> + {OSF, _} = os:type(), + mk_unique_path(OSF). + +mk_unique_path(win32) -> + [NodeName | _] = string:tokens(atom_to_list(node()), [$@]), + Path = f("esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]), + ensure_unique_path(Path, ".sock"); +mk_unique_path(_) -> + [NodeName | _] = string:tokens(atom_to_list(node()), [$@]), + Path = f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]), + ensure_unique_path(Path, ""). + +ensure_unique_path(Path, Ext) -> + NewPath = Path ++ Ext, + case file:read_file_info(NewPath) of + {ok, _} -> % Ouch, append a unique ID and try again + ensure_unique_path(Path, Ext, 1); + {error, _} -> + %% We assume this means it does not exist yet... + %% If we have several process in parallel trying to create + %% (unique) path's, then we are in trouble. To *really* be + %% on the safe side we should have a (central) path registry... + encode_path(NewPath) + end. + +ensure_unique_path(Path, Ext, ID) when (ID < 100) -> % If this is not enough... + NewPath = f("~s_~w", [Path, ID]) ++ Ext, + case file:read_file_info(NewPath) of + {ok, _} -> % Ouch, this also existed, increment and try again + ensure_unique_path(Path, Ext, ID + 1); + {error, _} -> % We assume this means it does not exist yet... + encode_path(NewPath) + end; +ensure_unique_path(_, _, _) -> + skip("Could not create unique path"). + +encode_path(Path) -> + unicode:characters_to_binary(Path, file:native_name_encoding()). @@ -210,92 +271,13 @@ which_local_addr(Domain) -> %% Returns the interface (name), flags and address (not 127...) %% of the local host. which_local_host_info(Domain) -> - case inet:getifaddrs() of - {ok, IFL} -> - which_local_host_info(Domain, IFL); + case ?LIB:which_local_host_info(Domain) of + {ok, [H|_]} -> + {ok, H}; {error, _} = ERROR -> ERROR end. -which_local_host_info(_Domain, []) -> - {error, no_address}; -which_local_host_info(Domain, [{"docker" ++ _, _}|IFL]) -> - which_local_host_info(Domain, IFL); -which_local_host_info(Domain, [{"br-" ++ _, _}|IFL]) -> - which_local_host_info(Domain, IFL); -which_local_host_info(Domain, [{Name, IFO}|IFL]) -> - case if_is_running_and_not_loopback(IFO) of - true -> - try which_local_host_info2(Domain, IFO) of - Info -> - {ok, Info#{name => Name}} - catch - throw:_:_ -> - which_local_host_info(Domain, IFL) - end; - false -> - which_local_host_info(Domain, IFL) - end; -which_local_host_info(Domain, [_|IFL]) -> - which_local_host_info(Domain, IFL). - -if_is_running_and_not_loopback(If) -> - lists:keymember(flags, 1, If) andalso - begin - {value, {flags, Flags}} = lists:keysearch(flags, 1, If), - (not lists:member(loopback, Flags)) andalso - lists:member(running, Flags) - end. - - -which_local_host_info2(inet = _Domain, IFO) -> - Addr = which_local_host_info3(addr, IFO, - fun({A, _, _, _}) when (A =/= 127) -> true; - (_) -> false - end), - NetMask = which_local_host_info3(netmask, IFO, - fun({_, _, _, _}) -> true; - (_) -> false - end), - BroadAddr = which_local_host_info3(broadaddr, IFO, - fun({_, _, _, _}) -> true; - (_) -> false - end), - Flags = which_local_host_info3(flags, IFO, fun(_) -> true end), - #{flags => Flags, - addr => Addr, - broadaddr => BroadAddr, - netmask => NetMask}; -which_local_host_info2(inet6 = _Domain, IFO) -> - Addr = which_local_host_info3(addr, IFO, - fun({A, _, _, _, _, _, _, _}) - when (A =/= 0) andalso - (A =/= 16#fe80) -> true; - (_) -> false - end), - NetMask = which_local_host_info3(netmask, IFO, - fun({_, _, _, _, _, _, _, _}) -> true; - (_) -> false - end), - Flags = which_local_host_info3(flags, IFO, fun(_) -> true end), - #{flags => Flags, - addr => Addr, - netmask => NetMask}. - -which_local_host_info3(_Key, [], _) -> - throw({error, no_address}); -which_local_host_info3(Key, [{Key, Val}|IFO], Check) -> - case Check(Val) of - true -> - Val; - false -> - which_local_host_info3(Key, IFO, Check) - end; -which_local_host_info3(Key, [_|IFO], Check) -> - which_local_host_info3(Key, IFO, Check). - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -303,7 +285,7 @@ not_yet_implemented() -> skip("not yet implemented"). skip(Reason) -> - throw({skip, Reason}). + exit({skip, Reason}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/kernel/test/socket_test_ttest_tcp_client.erl b/lib/kernel/test/socket_test_ttest_tcp_client.erl index ec9d75495f99..b062b82b2582 100644 --- a/lib/kernel/test/socket_test_ttest_tcp_client.erl +++ b/lib/kernel/test/socket_test_ttest_tcp_client.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2021. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -112,7 +112,7 @@ start_monitor(_, Notify, Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) -> case do_start(false, self(), Notify, - Transport, Active, ServerInfo, + Transport, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) of {ok, Pid} -> MRef = erlang:monitor(process, Pid), @@ -178,7 +178,7 @@ do_start(Quiet, is_function(Notify) andalso (is_atom(Transport) orelse is_tuple(Transport)) andalso (is_boolean(Active) orelse (Active =:= once)) andalso - (is_tuple(ServerInfo) orelse is_list(ServerInfo)) andalso + (is_tuple(ServerInfo) orelse is_list(ServerInfo) orelse is_binary(ServerInfo)) andalso (is_integer(MsgID) andalso (MsgID >= 1) andalso (MsgID =< 3)) andalso (is_integer(MaxOutstanding) andalso (MaxOutstanding > 0)) andalso (is_integer(RunTime) andalso (RunTime > 0)) -> @@ -206,7 +206,13 @@ do_start(Quiet, %% We should not normally stop this (it terminates when its done). stop(Pid) when is_pid(Pid) -> - req(Pid, stop). + case req(Pid, stop, 2 * ?RECV_TIMEOUT) of + {error, timeout} -> + exit(Pid, kill), + ok; + Else -> + Else + end. %% ========================================================================== @@ -262,8 +268,17 @@ init(Quiet, bcnt => 0, num => undefined, acc => <<>>}), + if not Quiet -> ?I("send result"); + true -> ok + end, Notify(Results), + if not Quiet -> ?I("close socket"); + true -> ok + end, (catch Mod:close(Sock)), + if not Quiet -> ?I("done"); + true -> ok + end, exit(normal); {error, Reason} -> ?E("connect failed: ~p" @@ -617,7 +632,11 @@ maybe_activate(_, _, _) -> %% ========================================================================== -req(Pid, Req) -> +%% req(Pid, Req) -> +%% req(Pid, Req, infinity). + +req(Pid, Req, Timeout) when (Timeout =:= infinity) orelse + (is_integer(Timeout) andalso (Timeout >= 0)) -> Ref = make_ref(), Pid ! {?MODULE, Ref, Pid, Req}, receive @@ -625,6 +644,8 @@ req(Pid, Req) -> {error, {exit, Reason}}; {?MODULE, Ref, Reply} -> Reply + after Timeout -> + {error, timeout} end. reply(Pid, Ref, Reply) -> diff --git a/lib/kernel/test/socket_test_ttest_tcp_client_gs.erl b/lib/kernel/test/socket_test_ttest_tcp_client_gs.erl new file mode 100644 index 000000000000..1dd24d660b16 --- /dev/null +++ b/lib/kernel/test/socket_test_ttest_tcp_client_gs.erl @@ -0,0 +1,49 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2023-2023. 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(socket_test_ttest_tcp_client_gs). + +-export([ + start/2, start/3, start/5, start/6, + stop/1 + ]). + +-define(TRANSPORT_MOD, socket_test_ttest_tcp_gs). + +start(ServerInfo, Active) -> + socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, ServerInfo, Active). + +start(ServerInfo, Active, MsgID) -> + socket_test_ttest_tcp_client:start(?TRANSPORT_MOD, ServerInfo, Active, MsgID). + +start(ServerInfo, Active, MsgID, MaxOutstanding, RunTime) -> + socket_test_ttest_tcp_client:start(false, + ?TRANSPORT_MOD, + ServerInfo, Active, + MsgID, MaxOutstanding, RunTime). + +start(Quiet, ServerInfo, Active, MsgID, MaxOutstanding, RunTime) -> + socket_test_ttest_tcp_client:start(Quiet, + ?TRANSPORT_MOD, + ServerInfo, Active, + MsgID, MaxOutstanding, RunTime). + +stop(Pid) -> + socket_test_ttest_tcp_client:stop(Pid). diff --git a/lib/kernel/test/socket_test_ttest_tcp_gs.erl b/lib/kernel/test/socket_test_ttest_tcp_gs.erl new file mode 100644 index 000000000000..d6545c729e10 --- /dev/null +++ b/lib/kernel/test/socket_test_ttest_tcp_gs.erl @@ -0,0 +1,140 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2023-2023. 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(socket_test_ttest_tcp_gs). + +-export([ + accept/1, accept/2, + active/2, + close/1, + connect/2, connect/3, + controlling_process/2, + listen/0, listen/1, listen/2, + peername/1, + port/1, + recv/2, recv/3, + send/2, + shutdown/2, + sockname/1 + ]). + + +-define(LIB, socket_test_lib). + +%% ========================================================================== + +accept(Sock) -> + case gen_tcp:accept(Sock) of + {ok, NewSock} -> + {ok, NewSock}; + {error, _} = ERROR -> + ERROR + end. + +accept(Sock, Timeout) -> + case gen_tcp:accept(Sock, Timeout) of + {ok, NewSock} -> + {ok, NewSock}; + {error, _} = ERROR -> + ERROR + end. + + +active(Sock, NewActive) + when (is_boolean(NewActive) orelse (NewActive =:= once)) -> + inet:setopts(Sock, [{active, NewActive}]). + + +close(Sock) -> + gen_tcp:close(Sock). + + +connect(Addr, Port) -> + Opts = [{inet_backend, socket}, + binary, {packet, raw}, {active, false}, {buffer, 32*1024}], + do_connect(Addr, Port, Opts). + +connect(Addr, Port, #{domain := Domain}) -> + Opts = [{inet_backend, socket}, + Domain, binary, {packet, raw}, {active, false}, {buffer, 32*1024}], + do_connect(Addr, Port, Opts). + +do_connect(Addr, Port, Opts) -> + case gen_tcp:connect(Addr, Port, Opts) of + {ok, Sock} -> + {ok, Sock}; + {error, _} = ERROR -> + ERROR + end. + +controlling_process(Sock, NewPid) -> + gen_tcp:controlling_process(Sock, NewPid). + + +%% Create a listen socket +listen() -> + listen(0). + +listen(Port) -> + listen(Port, #{domain => inet}). + +listen(Port, #{domain := Domain}) when is_integer(Port) andalso (Port >= 0) -> + case ?LIB:which_local_host_info(Domain) of + {ok, #{addr := Addr}} -> + Opts = [{inet_backend, socket}, + Domain, + binary, {ip, Addr}, {packet, raw}, {active, false}, + {buffer, 32*1024}], + gen_tcp:listen(Port, Opts); + {error, _} = ERROR -> + ERROR + end. + + +peername(Sock) -> + inet:peername(Sock). + + +port(Sock) -> + inet:port(Sock). + + +recv(Sock, Length) -> + gen_tcp:recv(Sock, Length). +recv(Sock, Length, Timeout) -> + gen_tcp:recv(Sock, Length, Timeout). + + +send(Sock, Data) -> + gen_tcp:send(Sock, Data). + + +shutdown(Sock, How) -> + gen_tcp:shutdown(Sock, How). + + +sockname(Sock) -> + inet:sockname(Sock). + + +%% ========================================================================== + + + diff --git a/lib/kernel/test/socket_test_ttest_tcp_server.erl b/lib/kernel/test/socket_test_ttest_tcp_server.erl index d8cacd750ce1..1d471ebc630a 100644 --- a/lib/kernel/test/socket_test_ttest_tcp_server.erl +++ b/lib/kernel/test/socket_test_ttest_tcp_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2021. All Rights Reserved. +%% Copyright Ericsson AB 2018-2022. 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. @@ -25,7 +25,7 @@ %% %% There are three ways to run the server: active, passive or active-once. %% -%% The server does only two things; accept connnections and then reply +%% The server does only two things; accept connections and then reply %% to requests (actually the handler(s) does that). No timing or counting. %% That is all done by the clients. %% @@ -116,7 +116,13 @@ do_start(Parent, Transport, Active) stop(Pid) when is_pid(Pid) -> - req(Pid, stop). + case req(Pid, stop, 2 * ?ACC_TIMEOUT) of + {error, timeout} -> + exit(Pid, kill), + ok; + Else -> + Else + end. %% ========================================================================== @@ -146,7 +152,7 @@ server_init(Starter, Parent, Transport, Active) -> {error, SNReason} -> exit({sockname, SNReason}) end; - is_list(PortOrPath) -> + is_list(PortOrPath) orelse is_binary(PortOrPath) -> ?I("listening on:" "~n Path: ~s" "~n", [PortOrPath]), @@ -248,7 +254,9 @@ format_peername({Addr, Port}) -> ?F("~p, ~p", [Addr, Port]) end; format_peername(Path) when is_list(Path) -> - Path. + Path; +format_peername(Path) when is_binary(Path) -> + binary_to_list(Path). maybe_start_stats_timer(#{active := Active, stats_interval := Time}, Handler) when (Active =/= false) andalso (is_integer(Time) andalso (Time > 0)) -> @@ -274,9 +282,16 @@ server_handle_message(#{mod := Mod, State; {?MODULE, Ref, Parent, stop} -> + ?I("received stop from parent ~p", [Parent]), reply(Parent, Ref, ok), - lists:foreach(fun(P) -> handler_stop(P) end, H), + ?I("try stop ~w handler(s)", [length(H)]), + lists:foreach(fun(P) -> + ?I("try stop handler ~p", [P]), + handler_stop(P) + end, H), + ?I("try close listen socket"), (catch Mod:close(LSock)), + ?I("stopped"), exit(normal); {'DOWN', _MRef, process, Pid, Reason} -> @@ -299,10 +314,12 @@ server_handle_stats(ProcStr, Pid) -> server_handle_down(Pid, Reason, #{handlers := Handlers} = State) -> case lists:delete(Pid, Handlers) of Handlers -> - ?I("unknown process ~p died", [Pid]), + ?I("unknown process ~p died: " + "~n ~p", [Pid, Reason]), State; Handlers2 -> - server_handle_handler_down(Pid, Reason, State#{handlers => Handlers2}) + server_handle_handler_down(Pid, Reason, + State#{handlers => Handlers2}) end. @@ -341,7 +358,7 @@ server_handle_handler_down(Pid, bcnt => AccBCnt2, hcnt => AccHCnt2}; server_handle_handler_down(Pid, Reason, State) -> - ?I("handler ~p terminated: " + ?E("handler ~p terminated: " "~n ~p", [Pid, Reason]), State. @@ -358,7 +375,14 @@ handler_continue(Pid, Mod, Sock, Active) -> req(Pid, {continue, Mod, Sock, Active}). handler_stop(Pid) -> - req(Pid, stop). + case req(Pid, stop, 2 * ?RECV_TIMEOUT) of + {error, timeout} -> + ?E("timeout attempting to stop handler ~p => try kill", [Pid]), + exit(Pid, kill), + ok; + Else -> + Else + end. handler_init(Parent) -> ?I("starting"), @@ -415,7 +439,7 @@ handler_recv_message(#{mod := Mod, %% When "active" (once or true), we receive one data "message", which may %% contain any number of requests or only part of a request. Then we %% process this data together with whatever we had "accumulated" from -%% prevous messages. Each request will be extracted and replied to. If +%% previous messages. Each request will be extracted and replied to. If %% there is some data left, not enough for a complete request, we store %% this in 'acc' (accumulate it). handler_recv_message(#{mod := Mod, @@ -551,9 +575,19 @@ handler_done(#{start := Start, exit({done, ?TDIFF(Start, Stop), MCnt, BCnt}). -handler_handle_message(#{parent := Parent} = State) -> +handler_handle_message(#{mod := Mod, sock := Sock, parent := Parent} = State) -> receive + {?MODULE, Ref, Parent, stop} -> + ?I("handler: received stop from parent ~p", [Parent]), + reply(Parent, Ref, ok), + (catch Mod:close(Sock)), + ?I("handler: stopped"), + exit(normal); + {'EXIT', Parent, Reason} -> + ?E("handler: parent ~p exit: " + "~n ~p", [Parent, Reason]), + (catch Mod:close(Sock)), exit({parent_exit, Reason}) after 0 -> State @@ -625,6 +659,10 @@ handler_maybe_activate(_, _, _) -> %% ========================================================================== req(Pid, Req) -> + req(Pid, Req, infinity). + +req(Pid, Req, Timeout) when (Timeout =:= infinity) orelse + (is_integer(Timeout) andalso (Timeout >= 0)) -> Ref = make_ref(), Pid ! {?MODULE, Ref, self(), Req}, receive @@ -632,6 +670,8 @@ req(Pid, Req) -> {error, {exit, Reason}}; {?MODULE, Ref, Reply} -> Reply + after Timeout -> + {error, timeout} end. reply(Pid, Ref, Reply) -> diff --git a/lib/kernel/test/socket_test_ttest_tcp_server_gs.erl b/lib/kernel/test/socket_test_ttest_tcp_server_gs.erl new file mode 100644 index 000000000000..dfb90bf4e440 --- /dev/null +++ b/lib/kernel/test/socket_test_ttest_tcp_server_gs.erl @@ -0,0 +1,39 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2023-2023. 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(socket_test_ttest_tcp_server_gs). + +-export([ + start/1, start/2, + stop/1 + ]). + +-define(TRANSPORT_MOD, socket_test_ttest_tcp_gs). +-define(MOD(D), {?TRANSPORT_MOD, #{domain => D}}). + +start(Active) -> + start(inet, Active). + +start(Domain, Active) -> + socket_test_ttest_tcp_server:start(?MOD(Domain), Active). + + +stop(Pid) -> + socket_test_ttest_tcp_server:stop(Pid). diff --git a/lib/kernel/test/socket_test_ttest_tcp_socket.erl b/lib/kernel/test/socket_test_ttest_tcp_socket.erl index d949e51da13c..b38056f92500 100644 --- a/lib/kernel/test/socket_test_ttest_tcp_socket.erl +++ b/lib/kernel/test/socket_test_ttest_tcp_socket.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2018-2021. All Rights Reserved. +%% Copyright Ericsson AB 2018-2023. 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. @@ -55,6 +55,15 @@ Reason}). +-define(SELECT_INFO(TAG, REF), {select_info, TAG, REF}). +-define(COMPLETION_INFO(TAG, REF), {completion_info, TAG, REF}). + +-define(SELECT_MSG(SOCK, REF), + {'$socket', (SOCK), select, (REF)}). +-define(COMPLETION_MSG(SOCK, REF, STATUS), + {'$socket', (SOCK), completion, {(REF), (STATUS)}}). + + %% ========================================================================== %% This does not really work. Its just a placeholder for the time being... @@ -84,7 +93,7 @@ accept(#{sock := LSock, opts := #{async := Async, ERROR end. -%% If a timeout has been explictly specified, then we do not use +%% If a timeout has been explicitly specified, then we do not use %% async here. We will pass it on to the reader process. accept(#{sock := LSock, opts := #{async := Async, method := Method} = Opts}, Timeout) -> @@ -120,7 +129,7 @@ close(#{sock := Sock, reader := Pid}) -> Res. %% Create a socket and connect it to a peer -connect(ServerPath) when is_list(ServerPath) -> +connect(ServerPath) when is_list(ServerPath) orelse is_binary(ServerPath) -> Domain = local, ClientPath = mk_unique_path(), LocalSA = #{family => Domain, @@ -145,7 +154,7 @@ connect(Addr, Port) when is_tuple(Addr) andalso is_integer(Port) -> do_connect(LocalSA, ServerSA, Cleanup, Opts); connect(ServerPath, #{domain := local = Domain} = Opts) - when is_list(ServerPath) -> + when is_list(ServerPath) orelse is_binary(ServerPath) -> ClientPath = mk_unique_path(), LocalSA = #{family => Domain, path => ClientPath}, @@ -204,8 +213,8 @@ do_connect(LocalSA, ServerSA, Cleanup, #{domain := Domain, end. mk_unique_path() -> - [NodeName | _] = string:tokens(atom_to_list(node()), [$@]), - ?LIB:f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]). + ?LIB:mk_unique_path(). + maybe_start_stats_timer(#{stats_to := Pid, stats_interval := T}, @@ -233,13 +242,14 @@ listen() -> listen(Port) when is_integer(Port) -> listen(Port, #{domain => inet, async => false, method => plain}); -listen(Path) when is_list(Path) -> +listen(Path) when is_list(Path) orelse is_binary(Path) -> listen(Path, #{domain => local, async => false, method => plain}). listen(0, #{domain := local} = Opts) -> listen(mk_unique_path(), Opts); listen(Path, #{domain := local = Domain} = Opts) - when is_list(Path) andalso (Path =/= []) -> + when (is_list(Path) andalso (Path =/= [])) orelse + (is_binary(Path) andalso (Path =/= <<"">>)) -> SA = #{family => Domain, path => Path}, Cleanup = fun() -> os:cmd("unlink " ++ Path), ok end, @@ -370,8 +380,9 @@ reader_init(ControllingProcess, Sock, Async, Active, Method) reader_loop(#{ctrl_proc => ControllingProcess, ctrl_proc_mref => MRef, async => Async, - select_info => undefined, - select_num => 0, % Count the number of select messages + asynch_info => undefined, + %% Count the number of select|completion messages + asynch_num => 0, active => Active, sock => Sock, method => Method}). @@ -451,13 +462,16 @@ reader_loop(#{active := once, end; reader_loop(#{active := once, async := true, - select_info := undefined, + asynch_info := undefined, sock := Sock, method := Method, ctrl_proc := Pid} = State) -> case do_recv(Method, Sock, nowait) of {select, SelectInfo} -> - reader_loop(State#{select_info => SelectInfo}); + reader_loop(State#{asynch_info => SelectInfo}); + {completion, CompletionInfo} -> + reader_loop(State#{asynch_info => CompletionInfo}); + {ok, Data} -> Pid ! ?DATA_MSG(Sock, Method, Data), reader_loop(State#{active => false}); @@ -472,11 +486,17 @@ reader_loop(#{active := once, end; reader_loop(#{active := once, async := true, - select_info := {select_info, _, Ref}, - select_num := N, + asynch_info := AsynchInfo, + asynch_num := N, sock := Sock, method := Method, - ctrl_proc := Pid} = State) -> + ctrl_proc := Pid} = State) when (AsynchInfo =/= undefined) -> + Ref = case AsynchInfo of + ?SELECT_INFO(_, SR) -> + SR; + ?COMPLETION_INFO(_, CR) -> + CR + end, receive {?MODULE, stop} -> reader_exit(State, stop); @@ -500,18 +520,42 @@ reader_loop(#{active := once, reader_loop(State) end; - {'$socket', Sock, select, Ref} -> + ?SELECT_MSG(Sock, Ref) -> case do_recv(Method, Sock, nowait) of {ok, Data} when is_binary(Data) -> Pid ! ?DATA_MSG(Sock, Method, Data), reader_loop(State#{active => false, - select_info => undefined, - select_num => N+1}); - + asynch_info => undefined, + asynch_num => N+1}); + {error, closed} = E1 -> Pid ! ?CLOSED_MSG(Sock, Method), reader_exit(State, E1); - + + {error, Reason} = E2 -> + Pid ! ?ERROR_MSG(Sock, Method, Reason), + reader_exit(State, E2) + end; + + ?COMPLETION_MSG(Sock, Ref, Result) -> + %% Note that *Windows* does not support sendmsg/recvmsg + %% but we assume we can get it. Just to be future proof + case Result of + {ok, Data} when is_binary(Data) -> + Pid ! ?DATA_MSG(Sock, Method, Data), + reader_loop(State#{active => false, + asynch_info => undefined, + asynch_num => N+1}); + {ok, #{iov := [Data]}} when is_binary(Data) -> + Pid ! ?DATA_MSG(Sock, Method, Data), + reader_loop(State#{active => false, + asynch_info => undefined, + asynch_num => N+1}); + + {error, closed} = E1 -> + Pid ! ?CLOSED_MSG(Sock, Method), + reader_exit(State, E1); + {error, Reason} = E2 -> Pid ! ?ERROR_MSG(Sock, Method, Reason), reader_exit(State, E2) @@ -565,13 +609,16 @@ reader_loop(#{active := true, end; reader_loop(#{active := true, async := true, - select_info := undefined, + asynch_info := undefined, sock := Sock, method := Method, ctrl_proc := Pid} = State) -> case do_recv(Method, Sock) of {select, SelectInfo} -> - reader_loop(State#{select_info => SelectInfo}); + reader_loop(State#{asynch_info => SelectInfo}); + {completion, CompletionInfo} -> + reader_loop(State#{asynch_info => CompletionInfo}); + {ok, Data} -> Pid ! ?DATA_MSG(Sock, Method, Data), reader_loop(State); @@ -586,11 +633,17 @@ reader_loop(#{active := true, end; reader_loop(#{active := true, async := true, - select_info := {select_info, _, Ref}, - select_num := N, + asynch_info := AsynchInfo, + asynch_num := N, sock := Sock, method := Method, - ctrl_proc := Pid} = State) -> + ctrl_proc := Pid} = State) when (AsynchInfo =/= undefined) -> + Ref = case AsynchInfo of + ?SELECT_INFO(_, SR) -> + SR; + ?COMPLETION_INFO(_, CR) -> + CR + end, receive {?MODULE, stop} -> reader_exit(State, stop); @@ -614,17 +667,41 @@ reader_loop(#{active := true, reader_loop(State) end; - {'$socket', Sock, select, Ref} -> + ?SELECT_MSG(Sock, Ref) -> case do_recv(Method, Sock, nowait) of {ok, Data} when is_binary(Data) -> Pid ! ?DATA_MSG(Sock, Method, Data), - reader_loop(State#{select_info => undefined, - select_num => N+1}); + reader_loop(State#{asynch_info => undefined, + asynch_num => N+1}); {error, closed} = E1 -> Pid ! ?CLOSED_MSG(Sock, Method), reader_exit(State, E1); + {error, Reason} = E2 -> + Pid ! ?ERROR_MSG(Sock, Method, Reason), + reader_exit(State, E2) + end; + + ?COMPLETION_MSG(Sock, Ref, Result) -> + %% Note that *Windows* does not support sendmsg/recvmsg + %% but we assume we can get it. Just to be future proof + case Result of + {ok, Data} when is_binary(Data) -> + Pid ! ?DATA_MSG(Sock, Method, Data), + reader_loop(State#{active => false, + asynch_info => undefined, + asynch_num => N+1}); + {ok, #{iov := [Data]}} when is_binary(Data) -> + Pid ! ?DATA_MSG(Sock, Method, Data), + reader_loop(State#{active => false, + asynch_info => undefined, + asynch_num => N+1}); + + {error, closed} = E1 -> + Pid ! ?CLOSED_MSG(Sock, Method), + reader_exit(State, E1); + {error, Reason} = E2 -> Pid ! ?ERROR_MSG(Sock, Method, Reason), reader_exit(State, E2) @@ -643,6 +720,8 @@ do_recv(msg, Sock, Timeout) -> {ok, Bin}; {select, _} = SELECT -> SELECT; + {completion, _} = COMPLETION -> + COMPLETION; {error, _} = ERROR -> ERROR end. @@ -653,55 +732,55 @@ reader_exit(#{async := false, active := Active}, stop) -> exit(normal); reader_exit(#{async := true, active := Active, - select_info := SelectInfo, - select_num := N}, stop) -> + asynch_info := AsynchInfo, + asynch_num := N}, stop) -> vp("reader stopped when active: ~w" - "~n Current select info: ~p" - "~n Number of select messages: ~p", [Active, SelectInfo, N]), + "~n Current asynch info: ~p" + "~n Number of asynch messages: ~p", [Active, AsynchInfo, N]), exit(normal); reader_exit(#{async := false, active := Active}, {ctrl_exit, normal}) -> vp("reader ctrl exit when active: ~w", [Active]), exit(normal); reader_exit(#{async := true, active := Active, - select_info := SelectInfo, - select_num := N}, {ctrl_exit, normal}) -> + asynch_info := AsynchInfo, + asynch_num := N}, {ctrl_exit, normal}) -> vp("reader ctrl exit when active: ~w" - "~n Current select info: ~p" - "~n Number of select messages: ~p", [Active, SelectInfo, N]), + "~n Current asynch info: ~p" + "~n Number of asynch messages: ~p", [Active, AsynchInfo, N]), exit(normal); reader_exit(#{async := false, active := Active}, {ctrl_exit, Reason}) -> vp("reader exit when ctrl crash when active: ~w", [Active]), exit({controlling_process, Reason}); reader_exit(#{async := true, active := Active, - select_info := SelectInfo, - select_num := N}, {ctrl_exit, Reason}) -> + asynch_info := AsynchInfo, + asynch_num := N}, {ctrl_exit, Reason}) -> vp("reader exit when ctrl crash when active: ~w" - "~n Current select info: ~p" - "~n Number of select messages: ~p", [Active, SelectInfo, N]), + "~n Current asynch info: ~p" + "~n Number of asynch messages: ~p", [Active, AsynchInfo, N]), exit({controlling_process, Reason}); reader_exit(#{async := false, active := Active}, {error, closed}) -> vp("reader exit when socket closed when active: ~w", [Active]), exit(normal); reader_exit(#{async := true, active := Active, - select_info := SelectInfo, - select_num := N}, {error, closed}) -> + asynch_info := AsynchInfo, + asynch_num := N}, {error, closed}) -> vp("reader exit when socket closed when active: ~w " - "~n Current select info: ~p" - "~n Number of select messages: ~p", [Active, SelectInfo, N]), + "~n Current asynch info: ~p" + "~n Number of asynch messages: ~p", [Active, AsynchInfo, N]), exit(normal); reader_exit(#{async := false, active := Active}, {error, Reason}) -> vp("reader exit when socket error when active: ~w", [Active]), exit(Reason); reader_exit(#{async := true, active := Active, - select_info := SelectInfo, - select_num := N}, {error, Reason}) -> + asynch_info := AsynchInfo, + asynch_num := N}, {error, Reason}) -> vp("reader exit when socket error when active: ~w: " - "~n Current select info: ~p" - "~n Number of select messages: ~p", [Active, SelectInfo, N]), + "~n Current asynch info: ~p" + "~n Number of asynch messages: ~p", [Active, AsynchInfo, N]), exit(Reason). diff --git a/lib/kernel/test/standard_error_SUITE.erl b/lib/kernel/test/standard_error_SUITE.erl index 1d9026dc58ec..792d086847a6 100644 --- a/lib/kernel/test/standard_error_SUITE.erl +++ b/lib/kernel/test/standard_error_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2016. All Rights Reserved. +%% Copyright Ericsson AB 2014-2023. 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. @@ -34,8 +34,10 @@ badarg(Config) when is_list(Config) -> true = erlang:is_process_alive(whereis(standard_error)), ok. +%% Check that standard_out and standard_error have the same encoding getopts(Config) when is_list(Config) -> - [{encoding,latin1}] = io:getopts(standard_error), + Encoding = proplists:get_value(encoding, io:getopts(user)), + Encoding = proplists:get_value(encoding, io:getopts(standard_error)), ok. %% Test that writing a lot of output to standard_error does not cause the diff --git a/lib/kernel/test/tty.cover b/lib/kernel/test/tty.cover new file mode 100644 index 000000000000..cf4d26ea8e1a --- /dev/null +++ b/lib/kernel/test/tty.cover @@ -0,0 +1,3 @@ +%% -*- erlang -*- +{incl_mods,[prim_tty, user_drv, group, shell, edlin, edlin_expand, io_lib]}. + diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 15fe78578d56..9d2fed5df517 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 8.3.2.3 +KERNEL_VSN = 9.1 diff --git a/lib/megaco/Makefile b/lib/megaco/Makefile index ebddcec5e71d..0250167791b5 100644 --- a/lib/megaco/Makefile +++ b/lib/megaco/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -98,7 +98,13 @@ else FLEX_SCANNER_REENTRANT_ENABLER = --enable-megaco-reentrant-flex-scanner endif -CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER) +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_DETERMINISTIC_ENABLER = --enable-deterministic-build +else + ERL_DETERMINISTIC_ENABLER = --disable-deterministic-build +endif + +CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER) $(ERL_DETERMINISTIC_ENABLER) DIA_PLT = ./priv/plt/$(APPLICATION).plt @@ -115,7 +121,7 @@ include $(ERL_TOP)/make/otp_subdir.mk reconf: (cd $(ERL_TOP) && \ - ./otp_build configure && \ + ./otp_build configure $(ERL_DETERMINISTIC_ENABLER) && \ cd $(ERL_TOP)/../libraries/megaco) conf: do_configure @@ -203,5 +209,6 @@ $(APP_TAR_FILE): $(APP_DIR) (cd "$(APP_RELEASE_DIR)"; gtar zcf "$(subst $(space),\ ,$@)" $(DIR_NAME)) DIA_PLT_APPS=asn1 runtime_tools et debugger +TEST_NEEDS_RELEASE=true include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/megaco/configure b/lib/megaco/configure index fac90552ce8a..a74de6797790 100755 --- a/lib/megaco/configure +++ b/lib/megaco/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +221,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +253,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +292,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +310,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +332,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +341,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +380,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +398,35 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +438,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +467,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +511,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +525,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +542,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,50 +614,46 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' ac_unique_file="vsn.mk" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS PERL @@ -638,9 +673,6 @@ DED_GCC DED_CC DED_LD DED_THR_DEFS -EGREP -GREP -CPP GETCONF OTP_EXTRA_FLAGS ERLANG_OSTYPE @@ -659,6 +691,10 @@ CPPFLAGS LDFLAGS CFLAGS CC +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -711,7 +747,6 @@ ac_user_opts=' enable_option_checking enable_megaco_reentrant_flex_scanner enable_megaco_flex_scanner_lineno -enable_sanitizers ' ac_precious_vars='build_alias host_alias @@ -720,8 +755,7 @@ CC CFLAGS LDFLAGS LIBS -CPPFLAGS -CPP' +CPPFLAGS' # Initialize some variables set by options. @@ -790,8 +824,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -832,9 +864,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -858,9 +890,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1071,9 +1103,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1087,9 +1119,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1133,9 +1165,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1151,7 +1183,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1215,7 +1247,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1333,6 +1365,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1348,8 +1381,6 @@ Optional Features: --disable-megaco-reentrant-flex-scanner disable reentrant megaco flex scanner --enable-megaco-flex-scanner-lineno enable megaco flex scanner lineno --disable-megaco-flex-scanner-lineno disable megaco flex scanner lineno - --enable-sanitizers[=comma-separated list of sanitizers] - Default=address,undefined Some influential environment variables: CC C compiler command @@ -1359,7 +1390,6 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory - CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1380,9 +1410,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1410,7 +1440,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1418,7 +1449,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1428,9 +1459,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1447,14 +1478,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1462,14 +1493,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1485,14 +1517,14 @@ fi ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1500,17 +1532,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1531,11 +1564,12 @@ fi ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -1543,16 +1577,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -1570,156 +1597,66 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -} # ac_fn_c_check_header_mongrel +} # ac_fn_c_check_header_compile # ac_fn_c_try_run LINENO # ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -1729,25 +1666,26 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status @@ -1758,37 +1696,6 @@ fi } # ac_fn_c_try_run -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes @@ -1803,7 +1710,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -1813,14 +1720,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1830,9 +1738,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -1840,14 +1749,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -1857,14 +1766,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -1874,9 +1784,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -1884,14 +1795,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -1899,7 +1810,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1909,12 +1820,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -1924,12 +1836,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -1957,9 +1869,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2011,8 +1944,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2047,7 +1984,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2082,11 +2019,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2097,8 +2036,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2122,7 +2061,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2130,14 +2069,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2145,15 +2084,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2161,8 +2100,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2176,63 +2115,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2242,139 +2166,623 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; -ac_aux_dir= -for ac_dir in ${ERL_TOP}/erts/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" break fi + ac_first_candidate=false + + as_found=false done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in ${ERL_TOP}/erts/autoconf" "$LINENO" 5 +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi + # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2393,21 +2801,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2426,11 +2835,118 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=win32 + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 fi + + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2439,11 +2955,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2451,11 +2968,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2466,11 +2987,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2479,11 +3000,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2491,11 +3013,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2506,11 +3032,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2518,8 +3044,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2532,11 +3058,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2544,11 +3071,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2559,11 +3090,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2572,11 +3103,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2585,15 +3117,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2609,18 +3145,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2631,11 +3167,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2643,11 +3180,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2658,11 +3199,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2675,11 +3216,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2687,11 +3229,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2702,11 +3248,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2718,34 +3264,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi +else + CC="$ac_cv_prog_CC" fi fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2755,7 +3405,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -2763,7 +3413,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2775,9 +3425,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -2798,11 +3448,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2819,7 +3470,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2835,44 +3486,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -2886,15 +3539,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -2903,7 +3556,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -2915,8 +3568,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -2924,10 +3577,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -2935,39 +3588,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2981,11 +3635,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -2994,31 +3649,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3028,29 +3684,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3059,57 +3719,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3124,94 +3787,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3232,111 +3945,111 @@ MIXED_VSL=no MIXED_VC=no MIXED_MINGW=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 -$as_echo_n "checking for mixed mingw-gcc and native VC++ environment... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 +printf %s "checking for mixed mingw-gcc and native VC++ environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then if test -x /usr/bin/msys-?.0.dll; then CFLAGS="$CFLAGS -O2" MIXED_MSYS=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 -$as_echo "MSYS and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 +printf "%s\n" "MSYS and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" MIXED_CYGWIN=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 -$as_echo "Cygwin and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 +printf "%s\n" "Cygwin and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /bin/wslpath; then CFLAGS="$CFLAGS -O2" MIXED_WSL=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 -$as_echo "WSL and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 +printf "%s\n" "WSL and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$MIXED_MSYS" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 -$as_echo_n "checking for mixed cygwin and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 +printf %s "checking for mixed cygwin and native MinGW environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then if test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 -$as_echo_n "checking for mixed MSYS and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 +printf %s "checking for mixed MSYS and native MinGW environment... " >&6; } if test "x$GCC" = x"yes"; then if test -x /usr/bin/msys-=.0.dll; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 -$as_echo_n "checking if we mix cygwin with any native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 +printf %s "checking if we mix cygwin with any native compiler... " >&6; } if test "X$MIXED_CYGWIN" = "Xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 -$as_echo_n "checking if we mix msys with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 +printf %s "checking if we mix msys with another native compiler... " >&6; } if test "X$MIXED_MSYS" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 -$as_echo_n "checking if we mix WSL with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 +printf %s "checking if we mix WSL with another native compiler... " >&6; } if test "X$MIXED_WSL" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi @@ -3346,13 +4059,14 @@ fi # Check whether --enable-megaco_reentrant_flex_scanner was given. -if test "${enable_megaco_reentrant_flex_scanner+set}" = set; then : +if test ${enable_megaco_reentrant_flex_scanner+y} +then : enableval=$enable_megaco_reentrant_flex_scanner; if test x${enable_megaco_reentrant_flex_scanner} = xno ; then ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false else ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true fi -else +else $as_nop ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true fi @@ -3364,11 +4078,12 @@ for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LEX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LEX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else @@ -3376,11 +4091,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3391,11 +4110,11 @@ fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 -$as_echo "$LEX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +printf "%s\n" "$LEX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3403,15 +4122,26 @@ fi done test -n "$LEX" || LEX=":" -if test "x$LEX" != "x:"; then - cat >conftest.l <<_ACEOF + if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%{ +#ifdef __cplusplus +extern "C" +#endif +int yywrap(void); +%} %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ - yyless ((input () != 0)); } +#ifdef __cplusplus + yyless ((yyinput () != 0)); +#else + yyless ((input () != 0)); +#endif + } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% @@ -3419,101 +4149,144 @@ f { unput (yytext[0]); } extern char *yytext; #endif int +yywrap (void) +{ + return 1; +} +int main (void) { - return ! yylex () + ! yywrap (); + return ! yylex (); } _ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex output file root" >&5 +printf %s "checking for lex output file root... " >&6; } +if test ${ac_cv_prog_lex_root+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +ac_cv_prog_lex_root=unknown { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 -$as_echo_n "checking lex output file root... " >&6; } -if ${ac_cv_prog_lex_root+:} false; then : - $as_echo_n "(cached) " >&6 -else - + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy -else - as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 -$as_echo "$ac_cv_prog_lex_root" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +printf "%s\n" "$ac_cv_prog_lex_root" >&6; } +if test "$ac_cv_prog_lex_root" = unknown +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot find output from $LEX; giving up on $LEX" >&5 +printf "%s\n" "$as_me: WARNING: cannot find output from $LEX; giving up on $LEX" >&2;} + LEX=: LEXLIB= +fi LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root -if test -z "${LEXLIB+set}"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 -$as_echo_n "checking lex library... " >&6; } -if ${ac_cv_lib_lex+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${LEXLIB+y} +then : + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex library" >&5 +printf %s "checking for lex library... " >&6; } +if test ${ac_cv_lib_lex+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ac_save_LIBS="$LIBS" + ac_found=false + for ac_cv_lib_lex in 'none needed' -lfl -ll 'not found'; do + case $ac_cv_lib_lex in #( + 'none needed') : + ;; #( + 'not found') : + break ;; #( + *) : + LIBS="$ac_cv_lib_lex $ac_save_LIBS" ;; #( + *) : + ;; +esac - ac_save_LIBS=$LIBS - ac_cv_lib_lex='none needed' - for ac_lib in '' -lfl -ll; do - LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_lex=$ac_lib +if ac_fn_c_try_link "$LINENO" +then : + ac_found=: fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - test "$ac_cv_lib_lex" != 'none needed' && break + if $ac_found; then + break + fi done - LIBS=$ac_save_LIBS + LIBS="$ac_save_LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 -$as_echo "$ac_cv_lib_lex" >&6; } - test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +printf "%s\n" "$ac_cv_lib_lex" >&6; } + if test "$ac_cv_lib_lex" = 'not found' +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: required lex library not found; giving up on $LEX" >&5 +printf "%s\n" "$as_me: WARNING: required lex library not found; giving up on $LEX" >&2;} + LEX=: LEXLIB= +elif test "$ac_cv_lib_lex" = 'none needed' +then : + LEXLIB='' +else $as_nop + LEXLIB=$ac_cv_lib_lex +fi + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 -$as_echo_n "checking whether yytext is a pointer... " >&6; } -if ${ac_cv_prog_lex_yytext_pointer+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "$LEX" != : +then : + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +printf %s "checking whether yytext is a pointer... " >&6; } +if test ${ac_cv_prog_lex_yytext_pointer+y} +then : + printf %s "(cached) " >&6 +else $as_nop # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no -ac_save_LIBS=$LIBS -LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_lex_yytext_pointer=yes fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_save_LIBS +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 -$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +printf "%s\n" "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then -$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h +printf "%s\n" "#define YYTEXT_POINTER 1" >>confdefs.h + +fi fi rm -f conftest.l $LEX_OUTPUT_ROOT.c @@ -3553,25 +4326,25 @@ int main ( int argc, char * argv[] ) return 0; } EOF -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for reentrant capable flex" >&5 -$as_echo_n "checking for reentrant capable flex... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for reentrant capable flex" >&5 +printf %s "checking for reentrant capable flex... " >&6; } if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$flex_compile\""; } >&5 (eval $flex_compile) 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest.c; then ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else echo "configure: failed program was:" 1>&5 cat conftest.flex 1>&5 echo "configure: PATH was $PATH" 1>&5 ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi @@ -3582,13 +4355,14 @@ fi # Check whether --enable-megaco_flex_scanner_lineno was given. -if test "${enable_megaco_flex_scanner_lineno+set}" = set; then : +if test ${enable_megaco_flex_scanner_lineno+y} +then : enableval=$enable_megaco_flex_scanner_lineno; if test x${enable_megaco_flex_scanner_lineno} = xno ; then ENABLE_MEGACO_FLEX_SCANNER_LINENO=false else ENABLE_MEGACO_FLEX_SCANNER_LINENO=true fi -else +else $as_nop ENABLE_MEGACO_FLEX_SCANNER_LINENO=true fi @@ -3613,481 +4387,108 @@ fi if test "x$GCC" = xyes; then # Treat certain GCC warnings as errors - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $CFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="-Werror=return-type $CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - -fi - - - -# Check whether --enable-sanitizers was given. -if test "${enable_sanitizers+set}" = set; then : - enableval=$enable_sanitizers; -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=address,undefined" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" - -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* + if test "X$can_enable_flag" = "Xtrue" +then : -fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + CFLAGS="-Werror=return-type $CFLAGS" -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif +else $as_nop -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done -fi -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF -fi -done +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi + + NEED_NPTL_PTHREAD_H=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 -$as_echo_n "checking for native win32 threads... " >&6; } -if test "X$host_os" = "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 +printf %s "checking for native win32 threads... " >&6; } +if test "X$host_os" = "Xwin32" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } THR_DEFS="-DWIN32_THREADS" THR_LIBS= THR_LIB_NAME=win32_threads THR_LIB_TYPE=win32_threads -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } THR_DEFS= THR_LIBS= THR_LIB_NAME= THR_LIB_TYPE=posix_unknown - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4096,40 +4497,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread_pthread_create=yes -else +else $as_nop ac_cv_lib_pthread_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : THR_LIBS="-lpthread" fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 -$as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 +printf %s "checking for pthread_create in -lc_r... " >&6; } +if test ${ac_cv_lib_c_r_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4138,96 +4541,112 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_r_pthread_create=yes -else +else $as_nop ac_cv_lib_c_r_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +if test "x$ac_cv_lib_c_r_pthread_create" = xyes +then : THR_LIBS="-lc_r" fi - fi - if test "x$THR_LIBS" = "x"; then - ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes; then : +fi + + if test "x$THR_LIBS" = "x" +then : + + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : THR_LIBS="none_needed" fi - fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 -$as_echo_n "checking if the '-pthread' switch can be used... " >&6; } +fi + + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 +printf %s "checking if the '-pthread' switch can be used... " >&6; } saved_cflags=$CFLAGS CFLAGS="$CFLAGS -pthread" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_create((void*)0,(void*)0,(void*)0,(void*)0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : THR_DEFS="-pthread" THR_LIBS="-pthread" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$saved_cflags if test "x$THR_LIBS" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - fi - if test "x$THR_LIBS" != "x"; then +fi + + if test "x$THR_LIBS" != "x" +then : + THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" THR_LIB_NAME=pthread if test "x$THR_LIBS" = "xnone_needed"; then THR_LIBS= fi - case $host_os in - solaris*) - THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;; - linux*) + case $host_os in #( + solaris*) : + + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" + ;; #( + linux*) : + THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" -if test "$cross_compiling" != "yes"; then +if test "$cross_compiling" != "yes" +then : + # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -4235,11 +4654,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4251,23 +4674,26 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else + +else $as_nop + host_getconf="$host_alias-getconf" # Extract the first word of "$host_getconf", so it can be a program name with args. set dummy $host_getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -4275,11 +4701,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="$host_getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4291,25 +4721,28 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then + if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != "" +then : + GETCONF= prfx="$erl_xcomp_sysroot" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. set dummy ${ac_tool_prefix}getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. @@ -4320,11 +4753,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4336,11 +4773,11 @@ esac fi GETCONF=$ac_cv_path_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4349,11 +4786,12 @@ if test -z "$ac_cv_path_GETCONF"; then ac_pt_GETCONF=$GETCONF # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. @@ -4364,11 +4802,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4380,11 +4822,11 @@ esac fi ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF if test -n "$ac_pt_GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 -$as_echo "$ac_pt_GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 +printf "%s\n" "$ac_pt_GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_GETCONF" = x; then @@ -4392,8 +4834,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac GETCONF=$ac_pt_GETCONF @@ -4402,11 +4844,13 @@ else GETCONF="$ac_cv_path_GETCONF" fi - fi + fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 -$as_echo_n "checking for Native POSIX Thread Library... " >&6; } +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 +printf %s "checking for Native POSIX Thread Library... " >&6; } libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` if test $? -eq 0; then case "$libpthr_vsn" in @@ -4422,24 +4866,28 @@ $as_echo_n "checking for Native POSIX Thread Library... " >&6; } else nptl=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 -$as_echo "$nptl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 +printf "%s\n" "$nptl" >&6; } if test $nptl = cross; then nptl=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi - if test $nptl = yes; then + if test $nptl = yes +then : + THR_LIB_TYPE=posix_nptl need_nptl_incldir=no - ac_fn_c_check_header_mongrel "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_nptl_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_nptl_pthread_h" = xyes +then : need_nptl_incldir=yes NEED_NPTL_PTHREAD_H=yes fi + if test $need_nptl_incldir = yes +then : - if test $need_nptl_incldir = yes; then # Ahh... nptl_path="$C_INCLUDE_PATH:$CPATH" if test X$cross_compiling != Xyes; then @@ -4460,13 +4908,13 @@ fi IFS=$save_ifs nptl_incldir= for dir in $nptl_ws_path; do - as_ac_Header=`$as_echo "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + as_ac_Header=`printf "%s\n" "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : nptl_incldir=$dir/nptl fi - if test "x$nptl_incldir" != "x"; then THR_DEFS="$THR_DEFS -isystem $nptl_incldir" break @@ -4475,38 +4923,43 @@ fi if test "x$nptl_incldir" = "x"; then as_fn_error $? "Failed to locate nptl system include directory" "$LINENO" 5 fi - fi - fi - ;; - *) ;; - esac + +fi + +fi + ;; #( + *) : + ;; +esac saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $THR_DEFS" - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : -$as_echo "#define HAVE_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes +then : \ -$as_echo "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h fi - CPPFLAGS=$saved_cppflags - fi + +fi + fi @@ -4550,181 +5003,253 @@ case "$host_cpu" in esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Wdeclaration-after-statement $DED_WARN_FLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WARN_FLAGS="-Wdeclaration-after-statement $DED_WARN_FLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)... " >&6; } +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=return-type $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=implicit $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=implicit $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=undef $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=undef $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$DED_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common" DED_INCLUDE=$DED_SYS_INCLUDE DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS" -if test "x$GCC" = xyes; then +if test "x$GCC" = xyes +then : + # Use -fno-common for gcc, that is link error if multiple definitions of # global variables are encountered. This is ISO C compliant. # Until version 10, gcc has had -fcommon as default, which allows and merges # such dubious duplicates. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-fno-common $DED_CFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_CFLAGS="-fno-common $DED_CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-strict-aliasing to DED_CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-strict-aliasing to DED_CFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fno-strict-aliasing $DED_CFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + DED_CFLAGS="-fno-strict-aliasing $DED_CFLAGS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi DED_STATIC_CFLAGS="$DED_CFLAGS" DED_CFLAGS="$DED_CFLAGS -fPIC" # Remove -fPIE and -fno-PIE DED_CFLAGS=`echo $DED_CFLAGS | sed 's/-f\(no-\)\?PIE//g'` + fi DED_EXT=so @@ -4811,17 +5336,19 @@ case $host_os in # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -4830,14 +5357,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h case "$ac_cv_sizeof_void_p" in @@ -4904,11 +5429,12 @@ test "$DED_LDFLAGS_CONFTEST" != "" || DED_LDFLAGS_CONFTEST="$DED_LDFLAGS" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DED_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DED_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$DED_LD"; then ac_cv_prog_DED_LD="$DED_LD" # Let the user override the test. else @@ -4916,11 +5442,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DED_LD="${ac_tool_prefix}ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4931,11 +5461,11 @@ fi fi DED_LD=$ac_cv_prog_DED_LD if test -n "$DED_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 -$as_echo "$DED_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 +printf "%s\n" "$DED_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4944,11 +5474,12 @@ if test -z "$ac_cv_prog_DED_LD"; then ac_ct_DED_LD=$DED_LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DED_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DED_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_DED_LD"; then ac_cv_prog_ac_ct_DED_LD="$ac_ct_DED_LD" # Let the user override the test. else @@ -4956,11 +5487,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DED_LD="ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4971,11 +5506,11 @@ fi fi ac_ct_DED_LD=$ac_cv_prog_ac_ct_DED_LD if test -n "$ac_ct_DED_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DED_LD" >&5 -$as_echo "$ac_ct_DED_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DED_LD" >&5 +printf "%s\n" "$ac_ct_DED_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DED_LD" = x; then @@ -4983,8 +5518,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DED_LD=$ac_ct_DED_LD @@ -4995,37 +5530,37 @@ fi test "$DED_LD" != "false" || as_fn_error $? "No linker found" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for static compiler flags" >&5 -$as_echo_n "checking for static compiler flags... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for static compiler flags" >&5 +printf %s "checking for static compiler flags... " >&6; } DED_STATIC_CFLAGS="$DED_WERRORFLAGS $DED_WFLAGS $DED_THR_DEFS $DED_STATIC_CFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_STATIC_CFLAGS" >&5 -$as_echo "$DED_STATIC_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for basic compiler flags for loadable drivers" >&5 -$as_echo_n "checking for basic compiler flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_STATIC_CFLAGS" >&5 +printf "%s\n" "$DED_STATIC_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for basic compiler flags for loadable drivers" >&5 +printf %s "checking for basic compiler flags for loadable drivers... " >&6; } DED_BASIC_CFLAGS=$DED_CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 -$as_echo "$DED_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler flags for loadable drivers" >&5 -$as_echo_n "checking for compiler flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 +printf "%s\n" "$DED_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler flags for loadable drivers" >&5 +printf %s "checking for compiler flags for loadable drivers... " >&6; } DED_CFLAGS="$DED_WERRORFLAGS $DED_WARN_FLAGS $DED_THR_DEFS $DED_CFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 -$as_echo "$DED_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker for loadable drivers" >&5 -$as_echo_n "checking for linker for loadable drivers... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 -$as_echo "$DED_LD" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker flags for loadable drivers" >&5 -$as_echo_n "checking for linker flags for loadable drivers... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LDFLAGS" >&5 -$as_echo "$DED_LDFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'runtime library path' linker flag" >&5 -$as_echo_n "checking for 'runtime library path' linker flag... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 +printf "%s\n" "$DED_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker for loadable drivers" >&5 +printf %s "checking for linker for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 +printf "%s\n" "$DED_LD" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker flags for loadable drivers" >&5 +printf %s "checking for linker flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LDFLAGS" >&5 +printf "%s\n" "$DED_LDFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 'runtime library path' linker flag" >&5 +printf %s "checking for 'runtime library path' linker flag... " >&6; } if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&5 -$as_echo "$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&5 +printf "%s\n" "$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } fi @@ -5050,11 +5585,12 @@ fi # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PERL+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PERL+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$PERL"; then ac_cv_prog_PERL="$PERL" # Let the user override the test. else @@ -5062,11 +5598,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PERL="perl" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5078,11 +5618,11 @@ fi fi PERL=$ac_cv_prog_PERL if test -n "$PERL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 -$as_echo "$PERL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf "%s\n" "$PERL" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5119,8 +5659,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -5150,15 +5690,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -5172,8 +5712,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -5226,7 +5766,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -5242,8 +5782,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -5266,14 +5806,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -5283,46 +5825,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -5331,13 +5873,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -5346,8 +5881,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -5359,30 +5898,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -5395,13 +5914,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -5428,18 +5948,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -5451,12 +5973,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -5487,7 +6010,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -5509,6 +6032,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -5522,6 +6049,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -5563,7 +6096,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -5572,7 +6105,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -5635,7 +6168,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -5684,14 +6217,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -5728,21 +6263,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -5770,7 +6305,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -5784,7 +6319,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -5809,7 +6344,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -6037,7 +6572,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -6045,17 +6580,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -6072,7 +6607,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6096,9 +6631,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -6151,8 +6686,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -6194,9 +6729,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -6243,8 +6778,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ac_config_files="$ac_config_files src/flex/$host/Makefile:src/flex/Makefile.in" @@ -6276,8 +6811,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -6307,15 +6842,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -6329,8 +6864,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -6383,7 +6918,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -6399,8 +6934,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -6423,14 +6958,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -6440,46 +6977,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -6488,13 +7025,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -6503,8 +7033,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -6516,30 +7050,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -6552,13 +7066,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -6585,18 +7100,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -6608,12 +7125,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -6644,7 +7162,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -6666,6 +7184,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -6679,6 +7201,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -6720,7 +7248,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -6729,7 +7257,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6792,7 +7320,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -6841,14 +7369,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -6885,21 +7415,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -6927,7 +7457,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -6941,7 +7471,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -6967,7 +7497,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -7195,7 +7725,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -7203,17 +7733,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -7230,7 +7760,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -7254,9 +7784,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -7309,8 +7839,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -7352,9 +7882,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -7401,8 +7931,9 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/lib/megaco/configure.ac b/lib/megaco/configure.ac new file mode 100644 index 000000000000..8d6af651c8bc --- /dev/null +++ b/lib/megaco/configure.ac @@ -0,0 +1,176 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- +dnl +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 2001-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% +dnl + +dnl define([AC_CACHE_LOAD], )dnl +dnl define([AC_CACHE_SAVE], )dnl + + +AC_INIT +AC_CONFIG_SRCDIR([vsn.mk]) +AC_PREREQ([2.71]) + +m4_include([otp.m4]) + +AC_CONFIG_AUX_DIR([${ERL_TOP}/make/autoconf]) + +ERL_CANONICAL_SYSTEM_TYPE + +dnl ---------------------------------------------------------------------- +dnl Checks for programs. +dnl ---------------------------------------------------------------------- + +AC_PROG_CC + +LM_WINDOWS_ENVIRONMENT + +AC_DEFUN(ERL_REENTRANT_FLEX, +[flex_compile='$LEX -R -Pconftest -oconftest.c conftest.flex 1>&AS_MESSAGE_LOG_FD' +changequote(253, 273)dnl +cat > conftest.flex <\n yy_pop_state( yyscanner ); +[^\n]+ fprintf( yyout, "%s\n", yytext); + +%% + +int main ( int argc, char * argv[] ) +{ + yyscan_t scanner; + + yylex_init ( &scanner ); + yylex ( scanner ); + yylex_destroy ( scanner ); + return 0; +} +EOF +changequote([, ])dnl +AC_MSG_CHECKING(for reentrant capable flex) +if AC_TRY_EVAL(flex_compile) && test -s conftest.c; then + ifelse([$1], , :, [ + $1]) + AC_MSG_RESULT([yes]) +else + echo "configure: failed program was:" 1>&AS_MESSAGE_LOG_FD + cat conftest.flex 1>&AS_MESSAGE_LOG_FD + echo "configure: PATH was $PATH" 1>&AS_MESSAGE_LOG_FD +ifelse([$2], , , [ + $2 +])dnl + AC_MSG_RESULT([no]) +fi +]) + + +dnl +dnl Shall we attempt to use reentrant flex scanner or not +dnl +AC_ARG_ENABLE(megaco_reentrant_flex_scanner, +[ --enable-megaco-reentrant-flex-scanner enable reentrant megaco flex scanner + --disable-megaco-reentrant-flex-scanner disable reentrant megaco flex scanner], + if test x${enable_megaco_reentrant_flex_scanner} = xno ; then + ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false + else + ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true + fi, + ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true) + + +dnl +dnl flex is needed by megaco. lex wont do! +dnl + +AC_PROG_LEX([noyywrap]) +if test "$LEX" != flex; then + ENABLE_MEGACO_FLEX_SCANNER=false +else + ENABLE_MEGACO_FLEX_SCANNER=true + dnl Check if we can generate a reentrant scanner + dnl ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true + if ${ENABLE_REENTRANT_MEGACO_FLEX_SCANNER} = true ; then + ERL_REENTRANT_FLEX(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true, + ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false) + fi +fi +AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER) +AC_SUBST(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER) + + + +dnl +dnl For increased performance it is possible to disable lineno +dnl +AC_ARG_ENABLE(megaco_flex_scanner_lineno, +[ --enable-megaco-flex-scanner-lineno enable megaco flex scanner lineno + --disable-megaco-flex-scanner-lineno disable megaco flex scanner lineno], + if test x${enable_megaco_flex_scanner_lineno} = xno ; then + ENABLE_MEGACO_FLEX_SCANNER_LINENO=false + else + ENABLE_MEGACO_FLEX_SCANNER_LINENO=true + fi, + ENABLE_MEGACO_FLEX_SCANNER_LINENO=true) +AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER_LINENO) + + +dnl This is the os flavour, should be unix or win32 +if test "X$host" = "Xwin32"; then + ERLANG_OSTYPE=win32 +else + ERLANG_OSTYPE=unix +fi + +AC_SUBST(ERLANG_OSTYPE) + +dnl Magic test for clearcase. +if test -d ../../system; then + OTP_EXTRA_FLAGS=-DOTP_RELEASE +else + OTP_EXTRA_FLAGS= +fi +AC_SUBST(OTP_EXTRA_FLAGS) + +if test "x$GCC" = xyes; then + # Treat certain GCC warnings as errors + LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) +fi + +ERL_DED + +AC_CHECK_PROG(PERL, perl, perl, no_perl) +if test "$PERL" = no_perl; then + AC_MSG_ERROR([Perl is required to build the flex scanner!]) +fi + +AC_CONFIG_FILES([examples/meas/Makefile:examples/meas/Makefile.in]) +AC_OUTPUT +AC_CONFIG_FILES([src/flex/$host/Makefile:src/flex/Makefile.in]) +AC_OUTPUT + diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in deleted file mode 100644 index 789fbbed0436..000000000000 --- a/lib/megaco/configure.in +++ /dev/null @@ -1,194 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -*-m4-*- -dnl -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 2001-2020. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% -dnl - -dnl define([AC_CACHE_LOAD], )dnl -dnl define([AC_CACHE_SAVE], )dnl - - -AC_INIT(vsn.mk) - -AC_CONFIG_AUX_DIRS(${ERL_TOP}/erts/autoconf) - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -else - host_os=win32 -fi - -dnl ---------------------------------------------------------------------- -dnl Checks for programs. -dnl ---------------------------------------------------------------------- - -AC_PROG_CC - -LM_WINDOWS_ENVIRONMENT - -AC_DEFUN(ERL_REENTRANT_FLEX, -[flex_compile='$LEX -R -Pconftest -oconftest.c conftest.flex 1>&AC_FD_CC' -changequote(253, 273)dnl -cat > conftest.flex <\n yy_pop_state( yyscanner ); -[^\n]+ fprintf( yyout, "%s\n", yytext); - -%% - -int main ( int argc, char * argv[] ) -{ - yyscan_t scanner; - - yylex_init ( &scanner ); - yylex ( scanner ); - yylex_destroy ( scanner ); - return 0; -} -EOF -changequote([, ])dnl -AC_MSG_CHECKING(for reentrant capable flex) -if AC_TRY_EVAL(flex_compile) && test -s conftest.c; then - ifelse([$1], , :, [ - $1]) - AC_MSG_RESULT([yes]) -else - echo "configure: failed program was:" 1>&AC_FD_CC - cat conftest.flex 1>&AC_FD_CC - echo "configure: PATH was $PATH" 1>&AC_FD_CC -ifelse([$2], , , [ - $2 -])dnl - AC_MSG_RESULT([no]) -fi -]) - - -dnl -dnl Shall we attempt to use reentrant flex scanner or not -dnl -AC_ARG_ENABLE(megaco_reentrant_flex_scanner, -[ --enable-megaco-reentrant-flex-scanner enable reentrant megaco flex scanner - --disable-megaco-reentrant-flex-scanner disable reentrant megaco flex scanner], - if test x${enable_megaco_reentrant_flex_scanner} = xno ; then - ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false - else - ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true - fi, - ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true) - - -dnl -dnl flex is needed by megaco. lex wont do! -dnl - -AC_PROG_LEX -if test "$LEX" != flex; then - ENABLE_MEGACO_FLEX_SCANNER=false -else - ENABLE_MEGACO_FLEX_SCANNER=true - dnl Check if we can generate a reentrant scanner - dnl ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true - if ${ENABLE_REENTRANT_MEGACO_FLEX_SCANNER} = true ; then - ERL_REENTRANT_FLEX(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true, - ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false) - fi -fi -AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER) -AC_SUBST(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER) - - - -dnl -dnl For increased performance it is possible to disable lineno -dnl -AC_ARG_ENABLE(megaco_flex_scanner_lineno, -[ --enable-megaco-flex-scanner-lineno enable megaco flex scanner lineno - --disable-megaco-flex-scanner-lineno disable megaco flex scanner lineno], - if test x${enable_megaco_flex_scanner_lineno} = xno ; then - ENABLE_MEGACO_FLEX_SCANNER_LINENO=false - else - ENABLE_MEGACO_FLEX_SCANNER_LINENO=true - fi, - ENABLE_MEGACO_FLEX_SCANNER_LINENO=true) -AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER_LINENO) - - -dnl This is the os flavour, should be unix or win32 -if test "X$host" = "Xwin32"; then - ERLANG_OSTYPE=win32 -else - ERLANG_OSTYPE=unix -fi - -AC_SUBST(ERLANG_OSTYPE) - -dnl Magic test for clearcase. -if test -d ../../system; then - OTP_EXTRA_FLAGS=-DOTP_RELEASE -else - OTP_EXTRA_FLAGS= -fi -AC_SUBST(OTP_EXTRA_FLAGS) - -if test "x$GCC" = xyes; then - # Treat certain GCC warnings as errors - LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) -fi - -dnl ---------------------------------------------------------------------- -dnl Enable -fsanitize= flags. -dnl ---------------------------------------------------------------------- - -m4_define(DEFAULT_SANITIZERS, [address,undefined]) -AC_ARG_ENABLE( - sanitizers, - AS_HELP_STRING( - [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], - [Default=DEFAULT_SANITIZERS]), -[ -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" -]) - -ERL_DED - -AC_CHECK_PROG(PERL, perl, perl, no_perl) -if test "$PERL" = no_perl; then - AC_MSG_ERROR([Perl is required to build the flex scanner!]) -fi - -AC_OUTPUT(examples/meas/Makefile:examples/meas/Makefile.in) -AC_OUTPUT(src/flex/$host/Makefile:src/flex/Makefile.in) - diff --git a/lib/megaco/doc/src/megaco_intro.xml b/lib/megaco/doc/src/megaco_intro.xml index f43b86c63391..606ee16d5a82 100644 --- a/lib/megaco/doc/src/megaco_intro.xml +++ b/lib/megaco/doc/src/megaco_intro.xml @@ -4,7 +4,7 @@

    - 20002020 + 20002023 Ericsson AB. All Rights Reserved. @@ -73,7 +73,7 @@
    Prerequisites -

    The following prerequisites is required for understanding the +

    The following prerequisites are required for understanding the material in the Megaco User's Guide:

    diff --git a/lib/megaco/doc/src/megaco_tcp.xml b/lib/megaco/doc/src/megaco_tcp.xml index eee44ef7f23d..013b3f5e66cb 100644 --- a/lib/megaco/doc/src/megaco_tcp.xml +++ b/lib/megaco/doc/src/megaco_tcp.xml @@ -4,7 +4,7 @@
    - 20002021 + 20002023 Ericsson AB. All Rights Reserved. @@ -56,12 +56,24 @@ TransportRef = pid() | regname() OptionListPerPort = [Option] - Option = {port, integer()} | {options, list()} | {receive_handle, term()} | {inet_backend, default | inet | socket} + Option = {port, integer()} | + {options, list()} | + {receive_handle, term()} | + {inet_backend, default | inet | socket}

    This function is used for starting new TPKT listening socket for TCP/IP. The option list contains the socket definitions.

    + + + +

    Choose the inet-backend.

    +

    This option make it possible to use a + different inet-backend ('default', 'inet' or 'socket').

    +

    Default is default (system default).

    +
    +
    @@ -100,6 +112,13 @@

    Default value is megaco.

    + + +

    Choose the inet-backend.

    +

    This option make it possible to use a + different inet-backend ('default', 'inet' or 'socket').

    +

    Default is default (system default).

    +
    diff --git a/lib/megaco/doc/src/megaco_udp.xml b/lib/megaco/doc/src/megaco_udp.xml index f9dc551f6c1a..80a25ce702c1 100644 --- a/lib/megaco/doc/src/megaco_udp.xml +++ b/lib/megaco/doc/src/megaco_udp.xml @@ -4,7 +4,7 @@
    - 20002021 + 20002023 Ericsson AB. All Rights Reserved. @@ -85,6 +85,13 @@

    Default value is megaco.

    + + +

    Choose the inet-backend.

    +

    This option make it possible to use a + different inet-backend ('default', 'inet' or 'socket').

    +

    Default is default (system default).

    +
    diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml index 8787d63375f6..f331ed3697a3 100644 --- a/lib/megaco/doc/src/notes.xml +++ b/lib/megaco/doc/src/notes.xml @@ -37,7 +37,145 @@ section is the version number of Megaco.

    -
    Megaco 4.3 +
    Megaco 4.5 + +
    Improvements and New Features + + +

    + Make megaco transports handle gen_tcp | gen_udp with + socket backend on Windows (completion).

    +

    + Own Id: OTP-18599 Aux Id: OTP-18029

    +
    +
    +
    + +
    + +
    Megaco 4.4.4 + +
    Fixed Bugs and Malfunctions + + +

    + Removed configure option --enable-sanitizers. It + was untested and broken. Address sanitizer for the + emulator has better support by the asan build + target.

    +

    + Own Id: OTP-18538 Aux Id: GH-7031, PR-7078

    +
    +
    +
    + +
    + +
    Megaco 4.4.3 + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Megaco 4.4.2 + +
    Improvements and New Features + + +

    + A very minor improvement to the measurement tool.

    +

    + Own Id: OTP-18298

    +
    +
    +
    + +
    + +
    Megaco 4.4.1 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed various dialyzer related issues in the examples and + the application proper.

    +

    + Own Id: OTP-18179 Aux Id: ERIERL-836

    +
    +
    +
    + + +
    Improvements and New Features + + +

    There is a new configure option, + --enable-deterministic-build, which will apply the + deterministic compiler option when building + Erlang/OTP. The deterministic option has been + improved to eliminate more sources of non-determinism in + several applications.

    +

    + Own Id: OTP-18165 Aux Id: PR-5965

    +
    +
    +
    + +
    + +
    Megaco 4.4 + +
    Improvements and New Features + + +

    + Input for configure scripts adapted to + autoconf 2.71.

    +

    + Own Id: OTP-17414 Aux Id: PR-4967

    +
    + +

    + Megaco test suite(s) use the new peer module for node + starts.

    +

    + Own Id: OTP-17910

    +
    +
    +
    + +
    + +
    Megaco 4.3
    Fixed Bugs and Malfunctions diff --git a/lib/megaco/examples/meas/Makefile.in b/lib/megaco/examples/meas/Makefile.in index 4ff5cd270313..216f03fc041b 100644 --- a/lib/megaco/examples/meas/Makefile.in +++ b/lib/megaco/examples/meas/Makefile.in @@ -86,6 +86,21 @@ ERL_COMPILE_FLAGS += \ -pa $(ERL_TOP)/lib/megaco/ebin \ -I../include +DIA_PLT = megaco_example_meas.plt +DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis +ifeq ($(DIAW_EH),true) +DIA_WARNINGS += -Werror_handling +endif +ifeq ($(DIAW_US),true) +DIA_WARNINGS += -Wunderspecs +endif +ifeq ($(DIAW_UR),true) +DIA_WARNINGS += -Wunmatched_returns +endif +DIA_PLT_APPS = \ + erts et asn1 kernel stdlib compiler debugger \ + runtime_tools crypto mnesia wx + # ---------------------------------------------------- # Special Build Targets @@ -95,8 +110,8 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) @@ -104,13 +119,17 @@ script_skeletons: $(SCRIPT_SKELETONS) info: @echo "MODULES = $(MODULES)" - @echo "ERL_FILED = $(ERL_FILES)" + @echo "ERL_FILES = $(ERL_FILES)" @echo "" @echo "SCRIPT_SKELETON_SRC = $(SCRIPT_SKELETON_SRC)" @echo "SCRIPT_SKELETONS = $(SCRIPT_SKELETONS)" @echo "" @echo "TARGET_FILES = $(TARGET_FILES)" @echo "" + @echo "DIA_PLT = $(DIA_PLT)" + @echo "DIA_ANALYSIS = $(DIA_ANALYSIS)" + @echo "DIA_PLT_APPS = $(DIA_PLT_APPS)" + @echo "" clean: rm -f $(TARGET_FILES) @@ -140,6 +159,28 @@ release_spec: opt release_docs_spec: +dclean: + rm -f $(DIA_PLT) + rm -f $(DIA_ANALYSIS) + +dialyzer_plt: $(DIA_PLT) + +$(DIA_PLT): $(ERL_FILES) + @echo "Building $(basename $(DIA_PLT)) plt file" + @dialyzer --build_plt \ + --output_plt $@ \ + --apps --apps $(sort $(APPLICATION) $(DIA_PLT_APPS)) \ + --output $(DIA_ANALYSIS) \ + --verbose + +dialyzer: $(DIA_PLT) + @echo "Running dialyzer on megaco example meas" + @dialyzer --plt $< \ + $(ERL_TOP)/lib/megaco/examples/meas \ + $(DIA_WARNINGS) \ + --verbose + + # ---------------------------------------------------- # Include dependencies # ---------------------------------------------------- diff --git a/lib/megaco/examples/meas/megaco_codec_meas.erl b/lib/megaco/examples/meas/megaco_codec_meas.erl index ae28fa43a084..ceeaa355047b 100644 --- a/lib/megaco/examples/meas/megaco_codec_meas.erl +++ b/lib/megaco/examples/meas/megaco_codec_meas.erl @@ -46,11 +46,11 @@ %% API %% Avoid warning for local function error/2 clashing with autoimported BIF. -compile({no_auto_import,[error/2]}). --export([start/0, start/1]). +-export([start/0, start/1, start/2]). -export([start1/0]). %% Internal exports --export([do_measure_codec/8, do_measure_codec_loop/7]). +-export([do_measure_codec/7, do_measure_codec_loop/7]). -export([flex_scanner_handler/1]). @@ -74,6 +74,8 @@ -define(DEFAULT_MESSAGE_PACKAGE, megaco_codec_transform:default_message_package()). +-define(DEFAULT_OPTS, #{verbose => true}). + -define(FTS(), formated_timestamp()). @@ -87,18 +89,22 @@ start1() -> start(). start() -> - meas_init(1, ?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS). + meas_init(1, ?DEFAULT_OPTS, ?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS). start([MessagePackage]) -> - do_start(1, MessagePackage, ?MEASURE_CODECS); + do_start(1, ?DEFAULT_OPTS, MessagePackage, ?MEASURE_CODECS); start(Factor) when is_integer(Factor) andalso (Factor > 0) -> - do_start(Factor, ?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS); + do_start(Factor, ?DEFAULT_OPTS, ?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS); start(MessagePackage) -> - do_start(1, MessagePackage, ?MEASURE_CODECS). + do_start(1, ?DEFAULT_OPTS, MessagePackage, ?MEASURE_CODECS). + +start(Factor, Opts) when is_integer(Factor) andalso (Factor > 0) andalso + is_map(Opts) -> + do_start(Factor, Opts, ?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS). -do_start(Factor, MessagePackageRaw, Codecs) -> +do_start(Factor, Opts, MessagePackageRaw, Codecs) -> MessagePackage = parse_message_package(MessagePackageRaw), - meas_init(Factor, MessagePackage, Codecs). + meas_init(Factor, Opts, MessagePackage, Codecs). parse_message_package(MessagePackageRaw) when is_list(MessagePackageRaw) -> list_to_atom(MessagePackageRaw); @@ -118,7 +124,7 @@ parse_message_package(BadMessagePackage) -> %% pretty | compact | ber | per | erlang %% -meas_init(Factor, MessagePackage, Codecs) -> +meas_init(Factor, Opts, MessagePackage, Codecs) -> %% process_flag(trap_exit, true), io:format("~nRun meas on message package: ~p~n~n", [MessagePackage]), display_os_info(), @@ -129,7 +135,7 @@ meas_init(Factor, MessagePackage, Codecs) -> case megaco_codec_transform:messages(MessagePackage) of Messages when is_list(Messages) -> ExpandedMessages = expand_messages(Codecs, Messages), - Results = t1(Factor, ExpandedMessages, []), + Results = t1(Factor, Opts, ExpandedMessages, []), display_time(Started, os:timestamp()), store_results(Results); Error -> @@ -144,12 +150,8 @@ display_os_info() -> Str -> Str end, - case os:type() of - {OsFam, OsName} -> - io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]); - OsFam -> - io:format("OS: ~p: ~s~n", [OsFam, V]) - end. + {OsFam, OsName} = os:type(), + io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]). display_system_info() -> SysArch = string:strip(erlang:system_info(system_architecture),right,$\n), @@ -163,6 +165,16 @@ display_app_info() -> display_megaco_info(), display_asn1_info(). +%% The instruction, nowarn_function, is because I can't figure out +%% how to suppress the warnings about +%% megaco_flex_scanner:is_enabled/0 and +%% megaco_flex_scanner:is_reentrant_enabled/0: +%% +%% "The pattern 'false' can never match the type 'true'" +%% +%% This is because the result of calling these function(s) is +%% basically decided at compile time (true or false). +-dialyzer({nowarn_function, display_megaco_info/0}). display_megaco_info() -> MI = megaco:module_info(), {value, {attributes, Attr}} = lists:keysearch(attributes, 1, MI), @@ -236,26 +248,26 @@ format_diff(Start, Fin) -> -t1(_Factor, [], Results) -> +t1(_Factor, _Opts, [], Results) -> lists:reverse(Results); -t1(Factor, [{Id, Codec, Conf, _, _} = ECodec|EMsgs], Results) -> - case (catch measure(Factor, ECodec)) of +t1(Factor, Opts, [{Id, Codec, Conf, _, _} = ECodec|EMsgs], Results) -> + case (catch measure(Factor, Opts, ECodec)) of {'EXIT', Reason} -> error("measure of codec ~p exited: ~n~p", [Codec, Reason]), - t1(Factor, EMsgs, Results); + t1(Factor, Opts, EMsgs, Results); {error, Reason} -> error("skipping codec ~p: ~n~p", [Codec, Reason]), - t1(Factor, EMsgs, Results); + t1(Factor, Opts, EMsgs, Results); {ok, Res} -> - t1(Factor, EMsgs, [{Id, Conf, Res}| Results]) + t1(Factor, Opts, EMsgs, [{Id, Conf, Res}| Results]) end. -measure(Factor, {Id, Codec, Conf, Count, Msgs}) -> +measure(Factor, Opts, {Id, Codec, Conf, Count, Msgs}) -> io:format("[~s] measure using codec ~p ~p~n ", [?FTS(), Codec, Conf]), {Init, Conf1} = measure_init(Conf), Conf2 = [{version3,?V3}|Conf1], - Res = measure(Factor, Id, Codec, Conf2, Msgs, [], Count), + Res = measure(Factor, Opts, Id, Codec, Conf2, Msgs, [], Count), measure_fin(Init), Res. @@ -303,9 +315,7 @@ expand_codec(Codec) -> {Codec, megaco_erl_dist_encoder, [compressed], 400}, {Codec, megaco_erl_dist_encoder, [megaco_compressed], 10000}, {Codec, megaco_erl_dist_encoder, [], 10000} - ]; - Else -> - exit({error, {invalid_codec, Else}}) + ] end. @@ -322,10 +332,10 @@ measure_fin(_) -> ok. -measure(_Factor, _Dir, _Codec, _Conf, [], [], _MCount) -> +measure(_Factor, _Opts, _Dir, _Codec, _Conf, [], [], _MCount) -> {error, no_messages}; -measure(_Factor, _Dir, _Codec, _Conf, [], Res, _MCount) -> +measure(_Factor, _Opts, _Dir, _Codec, _Conf, [], Res, _MCount) -> Eavg = avg([Etime/Ecnt || #stat{ecount = Ecnt, etime = Etime} <- Res]), Davg = avg([Dtime/Dcnt || #stat{dcount = Dcnt, dtime = Dtime} <- Res]), @@ -340,33 +350,41 @@ measure(_Factor, _Dir, _Codec, _Conf, [], Res, _MCount) -> {ok, lists:reverse(Res)}; -measure(Factor, Dir, Codec, Conf, [{Name, Bin}|Msgs], Results, MCount) -> - io:format(" ~p", [Name]), - case (catch do_measure(Factor, Dir, Codec, Conf, Name, Bin, MCount)) of +measure(Factor, #{verbose := Verbose} = Opts, + Dir, Codec, Conf, [{Name, Bin}|Msgs], Results, MCount) -> + vprint(Verbose, " ~p", [Name]), + case (catch do_measure(Factor, Opts, + Dir, Codec, Conf, Name, Bin, MCount)) of {ok, Stat} -> - measure(Factor, Dir, Codec, Conf, Msgs, [Stat | Results], MCount); + measure(Factor, Opts, + Dir, Codec, Conf, Msgs, [Stat | Results], MCount); {error, S} -> - io:format("~n[~s] ~s failed: ~n", [?FTS(), Name]), + if + (Verbose =:= true) -> + io:format("~n[~s] ~s failed: ~n", [?FTS(), Name]); + true -> + io:format("[~s] ~s failed: ~n", [?FTS(), Name]) + end, error(S,[]), - measure(Factor, Dir, Codec, Conf, Msgs, Results, MCount); + measure(Factor, Opts, Dir, Codec, Conf, Msgs, Results, MCount); {info, S} -> - case get(verbose) of + vprint(Verbose, "~n"), + case Verbose orelse get(verbose) of true -> - io:format("~n", []), info(S,[]); _ -> - io:format("~n~s skipped~n", [Name]) + io:format("~s skipped~n", [Name]) end, - measure(Factor, Dir, Codec, Conf, Msgs, Results, MCount) + measure(Factor, Opts, Dir, Codec, Conf, Msgs, Results, MCount) end. -do_measure(Factor, _Id, Codec, Conf, Name, BinMsg, MCount) -> +do_measure(Factor, Opts, _Id, Codec, Conf, Name, BinMsg, MCount) -> %% io:format("~n~s~n", [binary_to_list(BinMsg)]), - {Version, NewBin} = detect_version(Codec, Conf, BinMsg), + {Version, NewBin} = detect_version(Opts, Codec, Conf, BinMsg), {Msg, Dcnt, Dtime} = measure_decode(Factor, Codec, Conf, Version, NewBin, MCount), {_, Ecnt, Etime} = @@ -377,16 +395,21 @@ do_measure(Factor, _Id, Codec, Conf, Name, BinMsg, MCount) -> dcount = Dcnt, dtime = Dtime, size = size(NewBin)}}. -detect_version(Codec, Conf, Bin) -> +detect_version(#{verbose := Verbose} = _Opts, Codec, Conf, Bin) -> case (catch Codec:version_of(Conf, Bin)) of {ok, V} -> - io:format("[~w]", [V]), - {ok, M} = Codec:decode_message(Conf, V, Bin), + vprint(Verbose, "[~w]", [V]), + {ok, M} = Codec:decode_message(Conf, V, Bin), {ok, NewBin} = Codec:encode_message(Conf, V, M), - io:format("[~w]", [size(NewBin)]), + vprint(Verbose, "[~w]", [size(NewBin)]), {V, NewBin}; Error -> - io:format("~nversion detection failed:~n~p", [Error]), + if + (Verbose =:= true) -> + io:format("~nversion detection failed:~n~p", [Error]); + true -> + io:format("version detection failed:~n~p", [Error]) + end, Error end. @@ -416,20 +439,21 @@ measure_codec(Factor, Codec, Func, Conf, Version, Bin, MCount) is_atom(Func) andalso is_list(Conf) andalso is_integer(MCount) andalso (MCount > 0) -> - Self = self(), - Pid = spawn_link(?MODULE, do_measure_codec, - [Factor, Self, Codec, Func, Conf, Version, Bin, MCount]), + {Pid, MRef} = + spawn_monitor(?MODULE, do_measure_codec, + [Factor, Codec, Func, Conf, Version, Bin, MCount]), receive - {measure_result, Pid, Func, Res} -> + {'DOWN', MRef, process, Pid, {measure_result, Res}} -> {ok, Res}; - {error, Pid, Error} -> + {'DOWN', MRef, process, Pid, {error, Error}} -> {error, Error}; - Else -> + {'DOWN', MRef, process, Pid, Else} -> {error, {unexpected_result, Else}} after ?MEASURE_TIMEOUT -> Info = case (catch process_info(Pid)) of I when is_list(I) -> + erlang:demonitor(MRef), exit(Pid, kill), I; _ -> @@ -439,23 +463,17 @@ measure_codec(Factor, Codec, Func, Conf, Version, Bin, MCount) end. -do_measure_codec(Factor, Parent, Codec, Func, Conf, Version, Bin, MCount) -> +do_measure_codec(Factor, Codec, Func, Conf, Version, Bin, MCount) -> {ok, Count} = measure_warmup(Codec, Func, Conf, Version, Bin, MCount), Count2 = Count div Factor, - %% io:format("do_measure_codec(~w, ~w) -> warmed up:" - %% "~n MCount: ~w" - %% "~n Count: ~w" - %% "~n Count2: ~w", [Codec, Func, MCount, Count, Count2]), Res = timer:tc(?MODULE, do_measure_codec_loop, [Codec, Func, Conf, Version, Bin, Count2, dummy]), case Res of {Time, {ok, M}} -> - %% io:format("~w ", [Time]), - Parent ! {measure_result, self(), Func, {M, Count2, Time}}; + exit({measure_result, {M, Count2, Time}}); {_Time, Error} -> - Parent ! {error, self(), Error} - end, - unlink(Parent). % Make sure Parent don't get our exit signal + exit({error, Error}) + end. %% This function does more or less what the real measure function @@ -467,11 +485,17 @@ measure_warmup(Codec, Func, Conf, Version, M, MCount) -> Res = timer:tc(?MODULE, do_measure_codec_loop, [Codec, Func, Conf, Version, M, MCount, dummy]), case Res of - {Time, {ok, _}} when is_integer(Time) -> + {Time, {ok, _}} when is_integer(Time) andalso (Time > 0) -> %% OK so far, now calculate the count: - Count = round(?MEASURE_COUNT_TIME/(Time/MCount)), - %% io:format("~w ", [Count]), - {ok, Count}; + %% For some reason we get a 'badarith' on some platforms + %% here. Since this is just the warmup we can try-catch. + try round(?MEASURE_COUNT_TIME/(Time/MCount)) of + Count -> + {ok, Count} + catch + _:_:_ -> + {error, {failed_calculated_count, Time, MCount}} + end; {Time, Error} -> {error, {warmup_failed, Time, Error}} end. @@ -664,6 +688,17 @@ flex_scanner_handler(Pid, PortOrPorts) -> end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +vprint(Verbose, F) -> + vprint(Verbose, F, []). + +vprint(true, F, A) -> + io:format(F, A); +vprint(_, _, _) -> + ok. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% info(F, A) -> diff --git a/lib/megaco/examples/meas/megaco_codec_mstone1.erl b/lib/megaco/examples/meas/megaco_codec_mstone1.erl index 0d3615e7a310..9ed253dd0f83 100644 --- a/lib/megaco/examples/meas/megaco_codec_mstone1.erl +++ b/lib/megaco/examples/meas/megaco_codec_mstone1.erl @@ -229,7 +229,7 @@ do_mstone(MessagePackage, RunTime, Factor, Codecs, DrvInclude) -> ?LIB:display_system_info(), ?LIB:display_app_info(), io:format("~n", []), - case ?LIB:start_flex_scanner() of + try ?LIB:start_flex_scanner() of {Pid, Conf} when is_pid(Pid) -> put(flex_scanner_conf, Conf), EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, DrvInclude), @@ -238,8 +238,9 @@ do_mstone(MessagePackage, RunTime, Factor, Codecs, DrvInclude) -> ?LIB:stop_flex_scanner(Pid), io:format("~n", []), io:format("MStone: ~p~n", [MStone]), - done; - {error, Reason} = ERROR -> + done + catch + throw:{error, Reason} = ERROR -> io:format(" Failed starting flex scanner: " "~n ~p", [Reason]), ERROR diff --git a/lib/megaco/examples/meas/megaco_codec_mstone2.erl b/lib/megaco/examples/meas/megaco_codec_mstone2.erl index 3a8c1e691659..0368ecc38e74 100644 --- a/lib/megaco/examples/meas/megaco_codec_mstone2.erl +++ b/lib/megaco/examples/meas/megaco_codec_mstone2.erl @@ -113,7 +113,7 @@ start([RunTimeAtom, Mode, MessagePackage]) ?LIB:parse_runtime(RunTimeAtom), Mode, MessagePackage); start(RunTime) when is_integer(RunTime) andalso (RunTime > 0) -> do_start(?DEFAULT_FACTOR, - time:minutes(RunTime), ?DEFAULT_MODE, ?DEFAULT_MESSAGE_PACKAGE); + timer:minutes(RunTime), ?DEFAULT_MODE, ?DEFAULT_MESSAGE_PACKAGE); start(MessagePackage) -> do_start(?DEFAULT_FACTOR, ?DEFAULT_RUN_TIME, ?DEFAULT_MODE, MessagePackage). @@ -304,30 +304,26 @@ loader(Factor, RunTime, Mode, Codecs, MessagePackage) -> case (catch init(Factor, RunTime, Mode, Codecs, MessagePackage)) of {ok, State} -> loader_loop(running, State); - Error -> + {error, Reason} = Error -> + io:format(" Failed starting loader: " + "~n ~p", [Reason]), exit(Error) end. init(Factor, RunTime, Mode, Codecs, MessagePackage) -> ets:new(mstone, [set, private, named_table, {keypos, 1}]), ets:insert(mstone, {worker_cnt, 0}), - case ?LIB:start_flex_scanner() of - {Pid, FlexConf} when is_pid(Pid) -> - io:format("prepare messages", []), - EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, Mode), - io:format("~ninit codec data", []), - CodecData = init_codec_data(Factor, EMessages, FlexConf), - Timer = erlang:send_after(RunTime, self(), mstone_finished), - io:format(" => ~w concurrent workers~n", [length(CodecData)]), - {ok, #state{timer = Timer, - idle = CodecData, - flex_handler = Pid, - flex_conf = FlexConf}}; - {error, Reason} = ERROR -> - io:format(" Failed starting flex scanner: " - "~n ~p", [Reason]), - ERROR - end. + {Pid, FlexConf} = ?LIB:start_flex_scanner(), + io:format("prepare messages", []), + EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, Mode), + io:format("~ninit codec data", []), + CodecData = init_codec_data(Factor, EMessages, FlexConf), + Timer = erlang:send_after(RunTime, self(), mstone_finished), + io:format(" => ~w concurrent workers~n", [length(CodecData)]), + {ok, #state{timer = Timer, + idle = CodecData, + flex_handler = Pid, + flex_conf = FlexConf}}. init_codec_data(Factor, EMsgs, FlexConf) -> init_codec_data_expand(Factor, init_codec_data(EMsgs, FlexConf)). @@ -345,7 +341,7 @@ init_codec_data(Codec, Mod, Conf0, Msgs0, FlexConf) when is_atom(Codec) andalso is_atom(Mod) andalso is_list(Conf0) andalso - is_list(Msgs0) -> + is_list(Msgs0) -> io:format(".", []), Conf = [{version3,?VERSION3}|init_codec_conf(FlexConf, Conf0)], Msgs = [?LIB:detect_version(Mod, Conf, Bin) || {_, Bin} <- Msgs0], diff --git a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl index 4ab230c65be8..7044a1743084 100644 --- a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl +++ b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl @@ -83,12 +83,8 @@ display_os_info() -> Str -> Str end, - case os:type() of - {OsFam, OsName} -> - io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]); - OsFam -> - io:format("OS: ~p: ~s~n", [OsFam, V]) - end. + {OsFam, OsName} = os:type(), + io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]). %%---------------------------------------------------------------------- @@ -191,12 +187,8 @@ display_alloc_info([{Alloc, Mem}|AllocInfo]) -> display_alloc_info(AllocInfo). alloc_info() -> - case erlang:system_info(allocator) of - {_Allocator, _Version, Features, _Settings} -> - alloc_info(Features); - _ -> - [] - end. + {_Allocator, _Version, Features, _Settings} = erlang:system_info(allocator), + alloc_info(Features). alloc_info(Allocators) -> Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc, diff --git a/lib/megaco/examples/simple/Makefile b/lib/megaco/examples/simple/Makefile index 00c0b7e65ea8..8f1ca41433d0 100644 --- a/lib/megaco/examples/simple/Makefile +++ b/lib/megaco/examples/simple/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2016. All Rights Reserved. +# Copyright Ericsson AB 2001-2022. 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. @@ -100,13 +100,29 @@ MGC_START_ARGS += "{debug,false}" endif +DIA_PLT = megaco_example_simple.plt +DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis +ifeq ($(DIAW_EH),true) +DIA_WARNINGS += -Werror_handling +endif +ifeq ($(DIAW_US),true) +DIA_WARNINGS += -Wunderspecs +endif +ifeq ($(DIAW_UR),true) +DIA_WARNINGS += -Wunmatched_returns +endif +DIA_PLT_APPS = \ + erts asn1 et kernel stdlib compiler debugger \ + runtime_tools crypto mnesia wx + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- opt: $(TARGET_FILES) -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt clean: rm -f $(TARGET_FILES) @@ -114,8 +130,36 @@ clean: docs: -info: +info: @echo "MEGACO_ROOT_DIR = $(MEGACO_ROOT_DIR)" + @echo "" + @echo "DIA_PLT = $(DIA_PLT)" + @echo "DIA_ANALYSIS = $(DIA_ANALYSIS)" + @echo "DIA_PLT_APPS = $(DIA_PLT_APPS)" + @echo "" + + +dclean: + rm -f $(DIA_PLT) + rm -f $(DIA_ANALYSIS) + +dialyzer_plt: $(DIA_PLT) + +$(DIA_PLT): $(ERL_FILES) + @echo "Building $(basename $(DIA_PLT)) plt file" + @dialyzer --build_plt \ + --output_plt $@ \ + --apps --apps $(sort $(APPLICATION) $(DIA_PLT_APPS)) \ + --output $(DIA_ANALYSIS) \ + --verbose + +dialyzer: $(DIA_PLT) + @echo "Running dialyzer on megaco example simple" + @dialyzer --plt $< \ + -r ../../ebin \ + $(DIA_WARNINGS) \ + --verbose + # ---------------------------------------------------- # Special Build Targets diff --git a/lib/megaco/examples/simple/megaco_simple_mg.erl b/lib/megaco/examples/simple/megaco_simple_mg.erl index 83293b810d5a..b71cf3c6287d 100644 --- a/lib/megaco/examples/simple/megaco_simple_mg.erl +++ b/lib/megaco/examples/simple/megaco_simple_mg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2016. All Rights Reserved. +%% Copyright Ericsson AB 2001-2022. 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. @@ -108,6 +108,13 @@ get_arg(Key, Args) -> {value, {Key, Val}} = lists:keysearch(Key, 1, Args), Val. + +-spec init_batch(ReplyTo :: pid(), + MgcHost :: term(), + Trace :: term(), + Debug :: term()) -> + no_return(). + init_batch(ReplyTo, MgcHost, Trace, Debug) -> register(?MODULE, self()), Res = start(MgcHost, Trace, Debug), diff --git a/lib/megaco/examples/simple/megaco_simple_mgc.erl b/lib/megaco/examples/simple/megaco_simple_mgc.erl index 8a78262b86a2..40a27955f495 100644 --- a/lib/megaco/examples/simple/megaco_simple_mgc.erl +++ b/lib/megaco/examples/simple/megaco_simple_mgc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2019. All Rights Reserved. +%% Copyright Ericsson AB 2001-2022. 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. @@ -406,7 +406,13 @@ start_batch(Args0) -> io:format("~p(~p): ~p~n", [?MODULE, ?LINE, Res]), Res end. + +-spec init_batch(ReplyTo :: pid(), + Trace :: term(), + Debug :: term()) -> + no_return(). + init_batch(ReplyTo, Trace, Debug) -> register(?MODULE, self()), Res = start(Trace, Debug), diff --git a/lib/megaco/src/app/Makefile b/lib/megaco/src/app/Makefile index ab45548099cd..c681b88428e5 100644 --- a/lib/megaco/src/app/Makefile +++ b/lib/megaco/src/app/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2016. All Rights Reserved. +# Copyright Ericsson AB 2007-2022. 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. @@ -74,8 +74,8 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) diff --git a/lib/megaco/src/app/megaco.erl b/lib/megaco/src/app/megaco.erl index de6caaae3b01..d0816b1dd06e 100644 --- a/lib/megaco/src/app/megaco.erl +++ b/lib/megaco/src/app/megaco.erl @@ -721,10 +721,10 @@ nc() -> nc(Mods). nc(all) -> - application:load(?APPLICATION), + _ = application:load(?APPLICATION), case application:get_key(?APPLICATION, modules) of {ok, Mods} -> - application:unload(?APPLICATION), + _ = application:unload(?APPLICATION), nc(Mods); _ -> {error, not_found} @@ -741,10 +741,10 @@ ni() -> end. ni(all) -> - application:load(?APPLICATION), + _ = application:load(?APPLICATION), case application:get_key(?APPLICATION, modules) of {ok, Mods} -> - application:unload(?APPLICATION), + _ = application:unload(?APPLICATION), ni(Mods); _ -> {error, not_found} diff --git a/lib/megaco/src/app/megaco.mk b/lib/megaco/src/app/megaco.mk index a887dd42bc96..ce2b265ffc23 100644 --- a/lib/megaco/src/app/megaco.mk +++ b/lib/megaco/src/app/megaco.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2021. All Rights Reserved. +# Copyright Ericsson AB 2007-2022. 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. @@ -42,6 +42,12 @@ ifeq ($(WARN_UNUSED_WARS), true) ERL_COMPILE_FLAGS += +warn_unused_vars endif +ifeq ($(ERL_DETERMINISTIC),yes) +ERL_COMPILE_FLAGS += +deterministic +YRL_FLAGS += +deterministic +XRL_FLAGS += +deterministic +endif + MEGACO_APP_VSN_COMPILE_FLAGS = \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' diff --git a/lib/megaco/src/binary/Makefile b/lib/megaco/src/binary/Makefile index 9e33fe3ae5c7..9ecb649f0cbd 100644 --- a/lib/megaco/src/binary/Makefile +++ b/lib/megaco/src/binary/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2000-2020. All Rights Reserved. +# Copyright Ericsson AB 2000-2022. 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. @@ -100,8 +100,8 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: prebuild $(TARGET_FILES) diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk index ca2872975cbe..c03f557e2420 100644 --- a/lib/megaco/src/binary/depend.mk +++ b/lib/megaco/src/binary/depend.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2020. All Rights Reserved. +# Copyright Ericsson AB 2001-2022. 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. @@ -35,6 +35,10 @@ ifeq ($(MEGACO_INLINE_ASN1_RT),true) ASN1_CT_OPTS += +inline endif +ifeq ($(ERL_DETERMINISTIC),yes) +ASN1_CT_OPTS += +deterministic +endif + BER_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config BER_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config BER_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config diff --git a/lib/megaco/src/engine/Makefile b/lib/megaco/src/engine/Makefile index 869b516b056c..cc4974e09d98 100644 --- a/lib/megaco/src/engine/Makefile +++ b/lib/megaco/src/engine/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2016. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -74,8 +74,8 @@ ERL_COMPILE_FLAGS += \ $(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl index 0805acab9b9c..1b019fd53527 100644 --- a/lib/megaco/src/engine/megaco_config.erl +++ b/lib/megaco/src/engine/megaco_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -899,9 +899,9 @@ init([Parent]) -> do_init() -> ?megaco_test_init(), - ets:new(megaco_config, [public, named_table, {keypos, 1}]), - ets:new(megaco_local_conn, [public, named_table, {keypos, 2}]), - ets:new(megaco_remote_conn, [public, named_table, {keypos, 2}, bag]), + _ = ets:new(megaco_config, [public, named_table, {keypos, 1}]), + _ = ets:new(megaco_local_conn, [public, named_table, {keypos, 2}]), + _ = ets:new(megaco_remote_conn, [public, named_table, {keypos, 2}, bag]), megaco_stats:init(megaco_stats, global_snmp_counters()), init_scanner(), init_user_defaults(), @@ -1467,7 +1467,7 @@ handle_start_user(Mid, Config) -> case catch user_info(Mid, mid) of {'EXIT', _} -> DefaultConfig = user_info(default, all), - do_handle_start_user(Mid, DefaultConfig), + _ = do_handle_start_user(Mid, DefaultConfig), do_handle_start_user(Mid, Config); _LocalMid -> {error, {user_already_exists, Mid}} @@ -1482,7 +1482,7 @@ do_handle_start_user(UserMid, [{Item, Val} | Rest]) -> {error, Reason} end; do_handle_start_user(UserMid, []) -> - do_update_user(UserMid, mid, UserMid), + _ = do_update_user(UserMid, mid, UserMid), ok; do_handle_start_user(UserMid, BadConfig) -> ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}), @@ -1715,7 +1715,7 @@ update_auto_ack(#conn_data{trans_timer = To, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{auto_ack = true, trans_sender = Pid}; @@ -1746,7 +1746,7 @@ update_trans_ack(#conn_data{trans_timer = To, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_ack = true, trans_sender = Pid}; @@ -1775,7 +1775,7 @@ update_trans_req(#conn_data{trans_timer = To, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_req = true, trans_sender = Pid}; @@ -1799,7 +1799,7 @@ update_trans_timer(#conn_data{auto_ack = true, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_timer = To, trans_sender = Pid}; @@ -1817,7 +1817,7 @@ update_trans_timer(#conn_data{trans_req = true, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_timer = To, trans_sender = Pid}; @@ -1968,7 +1968,7 @@ trans_sender_start(#conn_data{conn_handle = CH, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_sender = Pid}; @@ -1997,7 +1997,7 @@ trans_sender_start(#conn_data{conn_handle = CH, %% sender goes down. %% Do we need to store the ref? Will we ever need to %% cancel this (apply_at_exit)? - megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), + _ = megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid), CD#conn_data{trans_sender = Pid}; @@ -2150,7 +2150,7 @@ update_snmp_counters(CH, PrelCH, [Counter|Counters]) -> PrelKey = {PrelCH, Counter}, Key = {CH, Counter}, [{PrelKey,PrelVal}] = ets:lookup(megaco_stats, PrelKey), - ets:update_counter(megaco_stats, Key, PrelVal), + _ = ets:update_counter(megaco_stats, Key, PrelVal), ets:delete(megaco_stats, PrelKey), update_snmp_counters(CH, PrelCH, Counters). diff --git a/lib/megaco/src/engine/megaco_digit_map.erl b/lib/megaco/src/engine/megaco_digit_map.erl index 5b8b1f3b8f5d..820cb2179e7f 100644 --- a/lib/megaco/src/engine/megaco_digit_map.erl +++ b/lib/megaco/src/engine/megaco_digit_map.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -842,7 +842,7 @@ cast(Pid, Event) -> test(DigitMap, Events) -> Self = self(), Pid = spawn_link(?MODULE, test_eval, [DigitMap, Self]), - report(Pid, Events), + _ = report(Pid, Events), receive {Self, Pid, Res} -> Res; diff --git a/lib/megaco/src/engine/megaco_filter.erl b/lib/megaco/src/engine/megaco_filter.erl index 4bd3bd518bfd..74326a0cedf0 100644 --- a/lib/megaco/src/engine/megaco_filter.erl +++ b/lib/megaco/src/engine/megaco_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2016. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -300,10 +300,10 @@ do_filter_contents([H | T], E, ConnData, Contents) -> E2 = case E#event.label of [$s, $e, $n, $d, $ , $b, $y, $t, $e, $s | Tail] -> - L = lists:concat(["send ", size(Bin), " bytes", Tail]), + L = lists:concat(["send ", byte_size(Bin), " bytes", Tail]), E#event{label = L}; [$r, $e, $c, $e, $i, $v, $e, $ , $b, $y, $t, $e, $s | Tail] -> - L = lists:concat(["receive ", size(Bin), " bytes", Tail]), + L = lists:concat(["receive ", byte_size(Bin), " bytes", Tail]), E#event{label = L}; _ -> E diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl index 2a9ecee2a709..dfb10dc869b4 100644 --- a/lib/megaco/src/engine/megaco_messenger.erl +++ b/lib/megaco/src/engine/megaco_messenger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2019. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -545,7 +545,7 @@ disconnect(ConnHandle, DiscoReason) case megaco_config:disconnect(ConnHandle) of {ok, ConnData, RemoteConnData} -> ControlRef = ConnData#conn_data.monitor_ref, - cancel_apply_at_exit(ControlRef), + _ = cancel_apply_at_exit(ControlRef), handle_disconnect_callback(ConnData, DiscoReason), ControlNode = node_of_control_pid(ConnData#conn_data.control_pid), case ControlNode =:= node() of @@ -554,7 +554,7 @@ disconnect(ConnHandle, DiscoReason) CancelFun = fun(RCD) -> UserRef = RCD#remote_conn_data.monitor_ref, - cancel_apply_at_exit(UserRef), + _ = cancel_apply_at_exit(UserRef), RCD#remote_conn_data.user_node end, Nodes = lists:map(CancelFun, RemoteConnData), @@ -602,7 +602,7 @@ disconnect_remote(_Reason, ConnHandle, UserNode) -> case megaco_config:disconnect_remote(ConnHandle, UserNode) of [RCD] -> Ref = RCD#remote_conn_data.monitor_ref, - cancel_apply_at_exit(Ref), + _ = cancel_apply_at_exit(Ref), ok; [] -> {error, {no_connection, ConnHandle}} @@ -619,9 +619,10 @@ receive_message(ReceiveHandle, ControlPid, SendHandle, Bin) -> receive_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra) -> Opts = [link , {min_heap_size, 5000}], - spawn_opt(?MODULE, - process_received_message, - [ReceiveHandle, ControlPid, SendHandle, Bin, self(), Extra], Opts), + _ = spawn_opt(?MODULE, + process_received_message, + [ReceiveHandle, + ControlPid, SendHandle, Bin, self(), Extra], Opts), ok. %% This function is called via the spawn_opt function with the link @@ -1131,20 +1132,20 @@ prepare_autoconnecting_trans(ConnData, [Trans | Rest], AckList, ReqList, Extra) Limit = ConnData#conn_data.sent_pending_limit, TransId = to_remote_trans_id(ConnData2), - case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of - ok -> - send_pending(ConnData2); - error -> - %% Pending limit: - %% In this (granted, highly hypothetical case) - %% we would make the user very confused if we - %% called the abort callback function, since - %% the request callback function has not yet - %% been called. Alas, we skip this call here. - send_pending_limit_error(ConnData); - aborted -> - ignore - end, + _ = case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of + ok -> + send_pending(ConnData2); + error -> + %% Pending limit: + %% In this (granted, highly hypothetical case) + %% we would make the user very confused if we + %% called the abort callback function, since + %% the request callback function has not yet + %% been called. Alas, we skip this call here. + send_pending_limit_error(ConnData); + aborted -> + ignore + end, prepare_autoconnecting_trans(ConnData2, Rest, AckList, ReqList, Extra); _ -> @@ -1251,8 +1252,8 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) -> ?report_debug(ConnData, "prepare request: conflicting requests", [TransId]), - send_pending(ConnData), - megaco_monitor:cancel_apply_after(PendingRef), + _ = send_pending(ConnData), + _ = megaco_monitor:cancel_apply_after(PendingRef), prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra) end; @@ -1294,7 +1295,7 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) -> %% %% ------------------------------------------ - send_pending(ConnData), + _ = send_pending(ConnData), prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra); @@ -1330,8 +1331,8 @@ prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) -> %% State == prepare: %% The user does not know about this request %% so we can safely perform cleanup. - %% - megaco_monitor:cancel_apply_after(Ref), + %% + _ = megaco_monitor:cancel_apply_after(Ref), send_pending_limit_error(ConnData), if State == eval_request -> @@ -1682,7 +1683,7 @@ do_handle_request(AckAction, {ok, Bin}, ConnData, TransId) %% - Delete the pending counter %% - megaco_monitor:cancel_apply_after(PendingRef), + _ = megaco_monitor:cancel_apply_after(PendingRef), megaco_config:del_pending_counter(sent, TransId), Method = timer_method(AckAction), @@ -1725,7 +1726,7 @@ do_handle_request(AckAction, {ok, {Sent, NotSent}}, ConnData, TransId) %% - Delete the pending counter %% - megaco_monitor:cancel_apply_after(PendingRef), + _ = megaco_monitor:cancel_apply_after(PendingRef), megaco_config:del_pending_counter(sent, TransId), Method = timer_method(AckAction), @@ -2178,7 +2179,7 @@ handle_recv_pending(#conn_data{long_request_resend = LRR, %% We can now drop the "bytes", since we will %% not resend from now on. - megaco_monitor:cancel_apply_after(Ref), + _ = megaco_monitor:cancel_apply_after(Ref), {WaitFor, CurrTimer} = megaco_timer:init(InitTimer), ConnHandle = ConnData#conn_data.conn_handle, M = ?MODULE, @@ -2234,7 +2235,7 @@ handle_recv_pending(#conn_data{conn_handle = ConnHandle} = ConnData, TransId, %% We just need to recalculate the timer, i.e. %% increment the timer (one "slot" has been consumed). - megaco_monitor:cancel_apply_after(Ref), + _ = megaco_monitor:cancel_apply_after(Ref), {WaitFor, Timer2} = megaco_timer:restart(CurrTimer), ConnHandle = ConnData#conn_data.conn_handle, M = ?MODULE, @@ -2256,12 +2257,12 @@ handle_recv_pending_error(ConnData, TransId, Req, T, Extra) -> megaco_monitor:delete_request(TransId), %% 2) Possibly cancel the timer - case Req#request.timer_ref of - {_, Ref} -> - megaco_monitor:cancel_apply_after(Ref); - _ -> - ok - end, + _ = case Req#request.timer_ref of + {_, Ref} -> + megaco_monitor:cancel_apply_after(Ref); + _ -> + ok + end, %% 3) Delete the (receive) pending counter megaco_config:del_pending_counter(recv, TransId), @@ -2310,10 +2311,10 @@ handle_reply( [T]), %% Stop the request timer - megaco_monitor:cancel_apply_after(Ref), %% OTP-4843 + _ = megaco_monitor:cancel_apply_after(Ref), %% OTP-4843 %% Acknowledge the segment - send_segment_reply(ConnData, SN), + _ = send_segment_reply(ConnData, SN), %% First segment for this reply NewFields = @@ -2353,7 +2354,7 @@ handle_reply( [T]), %% Acknowledge the segment - send_segment_reply(ConnData, SN), + _ = send_segment_reply(ConnData, SN), %% Updated/handle received segment case lists:member(SN, Segs) of @@ -2400,7 +2401,7 @@ handle_reply( [T]), %% Acknowledge the segment - send_segment_reply(ConnData, SN), + _ = send_segment_reply(ConnData, SN), %% Updated received segments case lists:member(SN, Segs) of @@ -2413,9 +2414,9 @@ handle_reply( Last = case is_all_segments([SN | Segs]) of {true, _Sorted} -> - megaco_monitor:cancel_apply_after(SegRef), + _ = megaco_monitor:cancel_apply_after(SegRef), megaco_monitor:delete_request(TransId), - send_ack(ConnData), + _ = send_ack(ConnData), true; {false, Sorted} -> megaco_monitor:update_request_field(TransId, @@ -2477,10 +2478,10 @@ handle_reply( "first/complete seg", [T]), %% Stop the request timer - megaco_monitor:cancel_apply_after(Ref), %% OTP-4843 + _ = megaco_monitor:cancel_apply_after(Ref), %% OTP-4843 %% Acknowledge the ("last") segment - send_segment_reply_complete(ConnData, SN), + _ = send_segment_reply_complete(ConnData, SN), %% It is ofcourse pointless to split %% a transaction into just one segment, @@ -2508,7 +2509,7 @@ handle_reply( true -> %% Just one segment! megaco_monitor:delete_request(TransId), - send_ack(ConnData), + _ = send_ack(ConnData), true end, @@ -2537,7 +2538,7 @@ handle_reply( [T]), %% Acknowledge the ("last") segment - send_segment_reply_complete(ConnData, SN), + _ = send_segment_reply_complete(ConnData, SN), %% Updated received segments %% This is _probably_ the last segment, but some of @@ -2555,7 +2556,7 @@ handle_reply( "[segmented] trans reply - " "complete set", [T]), megaco_monitor:delete_request(TransId), - send_ack(ConnData), + _ = send_ack(ConnData), true; {false, Sorted} -> ConnHandle = ConnData#conn_data.conn_handle, @@ -2736,11 +2737,11 @@ do_handle_reply(CD, %% This is the first reply (maybe of many) megaco_monitor:delete_request(TransId), megaco_monitor:request_lockcnt_del(TransId), - megaco_monitor:cancel_apply_after(Ref), % OTP-4843 + _ = megaco_monitor:cancel_apply_after(Ref), % OTP-4843 megaco_config:del_pending_counter(recv, TransId), % OTP-7189 %% Send acknowledgement - maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD), + _ = maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD), UserReply = case T#megaco_transaction_reply.transactionResult of @@ -2778,7 +2779,7 @@ do_handle_reply(CD, %% This *is* the first reply!! %% 1) Stop resend timer {_Type, Ref} = Req#request.timer_ref, % OTP-4843 - megaco_monitor:cancel_apply_after(Ref), % OTP-4843 + _ = megaco_monitor:cancel_apply_after(Ref), % OTP-4843 %% 2) Delete pending counter megaco_config:del_pending_counter(recv, TransId), % OTP-7189 @@ -2793,7 +2794,7 @@ do_handle_reply(CD, RKAWaitFor), %% 4) Maybe send acknowledgement (three-way-handshake) - maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD), + _ = maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD), %% 5) And finally store the updated request record Req2 = Req#request{keep_alive_ref = RKARef}, @@ -2869,11 +2870,11 @@ handle_segment_reply(CD, handle_segment_reply_callback(CD, TransId, SN, SC, Extra), case lists:keysearch(SN, 1, Sent) of {value, {SN, _Bin, SegTmr}} -> - megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK + _ = megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK case lists:keydelete(SN, 1, Sent) of [] -> %% We are done Ref = Rep#reply.timer_ref, - megaco_monitor:cancel_apply_after(Ref), + _ = megaco_monitor:cancel_apply_after(Ref), megaco_monitor:update_reply_field(TransId2, #reply.bytes, []), @@ -2896,7 +2897,7 @@ handle_segment_reply(CD, handle_segment_reply_callback(CD, TransId, SN, SC, Extra), case lists:keysearch(SN, 1, Sent) of {value, {SN, _Bin, SegTmr}} -> - megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK + _ = megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK NewSent = lists:keydelete(SN, 1, Sent), [{SN2, Bin2}|NewNotSent] = NotSent, case send_reply_segment(CD, "send trans reply segment", @@ -3026,14 +3027,14 @@ handle_ack(ConnData, OrigAckStatus, handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra). handle_ack_cleanup(TransId, ReplyRef, PendingRef) -> - megaco_monitor:cancel_apply_after(ReplyRef), - megaco_monitor:cancel_apply_after(PendingRef), + _ = megaco_monitor:cancel_apply_after(ReplyRef), + _ = megaco_monitor:cancel_apply_after(PendingRef), megaco_monitor:delete_reply(TransId), megaco_config:del_pending_counter(sent, TransId). %% BMK: Still existing? cancel_segment_timers(SegSent) when is_list(SegSent) -> Cancel = fun({_, _, Ref}) -> - megaco_monitor:cancel_apply_after(Ref) + megaco_monitor:cancel_apply_after(Ref) end, lists:foreach(Cancel, SegSent); cancel_segment_timers(_) -> @@ -4033,7 +4034,7 @@ send_reply(#conn_data{serial = Serial, {ok, Bin} when is_binary(Bin) andalso (TransReq =:= true) -> ?rt2("send_reply - pass it on to the transaction sender", [size(Bin)]), - megaco_trans_sender:send_reply(TransSnd, Bin), + _ = megaco_trans_sender:send_reply(TransSnd, Bin), {ok, Bin}; {ok, Bin} when is_binary(Bin) -> @@ -4070,7 +4071,7 @@ send_reply(#conn_data{serial = Serial, error_msg("failed encoding transaction reply body: ~s", [format_encode_error_reason(Reason)]), Body = {transactions, [{transactionReply, TR3}]}, - megaco_messenger_misc:send_body(CD, TraceLabel, Body), + _ = megaco_messenger_misc:send_body(CD, TraceLabel, Body), Error end. @@ -4457,7 +4458,7 @@ do_receive_reply_remote(ConnData, TransId, UserReply, Extra) -> megaco_monitor:delete_request(TransId), megaco_monitor:request_lockcnt_del(TransId), - megaco_monitor:cancel_apply_after(Ref), % OTP-4843 + _ = megaco_monitor:cancel_apply_after(Ref), % OTP-4843 megaco_config:del_pending_counter(recv, TransId), % OTP-7189 ConnData2 = ConnData#conn_data{user_mod = UserMod, @@ -4471,7 +4472,7 @@ cancel_reply(ConnData, #reply{state = waiting_for_ack, user_mod = UserMod, user_args = UserArgs} = Rep, Reason) -> ?report_trace(ignore, "cancel reply [waiting_for_ack]", [Rep]), - megaco_monitor:cancel_apply_after(Rep#reply.pending_timer_ref), + _ = megaco_monitor:cancel_apply_after(Rep#reply.pending_timer_ref), Serial = (Rep#reply.trans_id)#trans_id.serial, ConnData2 = ConnData#conn_data{serial = Serial, user_mod = UserMod, @@ -4486,8 +4487,8 @@ cancel_reply(_ConnData, #reply{state = aborted} = Rep, _Reason) -> timer_ref = ReplyRef, pending_timer_ref = PendingRef} = Rep, megaco_monitor:delete_reply(TransId), - megaco_monitor:cancel_apply_after(ReplyRef), - megaco_monitor:cancel_apply_after(PendingRef), % Still running? + _ = megaco_monitor:cancel_apply_after(ReplyRef), + _ = megaco_monitor:cancel_apply_after(PendingRef), % Still running? megaco_config:del_pending_counter(sent, TransId), % Still existing? ok; @@ -4497,8 +4498,8 @@ cancel_reply(_ConnData, Rep, ignore) -> timer_ref = ReplyRef, pending_timer_ref = PendingRef} = Rep, megaco_monitor:delete_reply(TransId), - megaco_monitor:cancel_apply_after(ReplyRef), - megaco_monitor:cancel_apply_after(PendingRef), % Still running? + _ = megaco_monitor:cancel_apply_after(ReplyRef), + _ = megaco_monitor:cancel_apply_after(PendingRef), % Still running? megaco_config:del_pending_counter(sent, TransId), % Still existing? ok; @@ -4508,7 +4509,7 @@ cancel_reply(_CD, _Rep, _Reason) -> request_keep_alive_timeout(ConnHandle, TransId) -> megaco_config:del_pending_counter(ConnHandle, TransId), - megaco_monitor:lookup_request(TransId), + _ = megaco_monitor:lookup_request(TransId), ok. @@ -4853,7 +4854,7 @@ handle_reply_timer_timeout(ConnHandle, TransId) -> {_Converted, #reply{pending_timer_ref = Ref, % aborted? bytes = SegSent}} -> % may be a binary - megaco_monitor:cancel_apply_after(Ref), + _ = megaco_monitor:cancel_apply_after(Ref), cancel_segment_timers(SegSent), megaco_monitor:delete_reply(TransId), megaco_config:del_pending_counter(sent, TransId); @@ -4979,7 +4980,7 @@ handle_pending_timeout(CD, TransId, Timer) -> %% %% --------------------------------------------- - send_pending(CD), + _ = send_pending(CD), case Timer of timeout -> %% We are done diff --git a/lib/megaco/src/engine/megaco_messenger_misc.erl b/lib/megaco/src/engine/megaco_messenger_misc.erl index 091f64e5b47b..d671bcafad84 100644 --- a/lib/megaco/src/engine/megaco_messenger_misc.erl +++ b/lib/megaco/src/engine/megaco_messenger_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -217,7 +217,7 @@ encode_action_replies(#conn_data{protocol_version = V, [AR|ARs], Size, Acc) -> case (catch Mod:encode_action_reply(Conf, V, AR)) of {ok, Bin} when is_binary(Bin) -> - encode_action_replies(CD, ARs, Size + size(Bin), [Bin|Acc]); + encode_action_replies(CD, ARs, Size + byte_size(Bin), [Bin|Acc]); {'EXIT', {undef, _}} -> throw({error, not_implemented}); {error, not_implemented} = Error1 -> diff --git a/lib/megaco/src/engine/megaco_monitor.erl b/lib/megaco/src/engine/megaco_monitor.erl index efda4d371635..34bd3a67069c 100644 --- a/lib/megaco/src/engine/megaco_monitor.erl +++ b/lib/megaco/src/engine/megaco_monitor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2020. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -232,8 +232,8 @@ cast(Msg) -> init([Parent]) -> ?d("init -> entry", []), process_flag(trap_exit, true), - ets:new(megaco_requests, [public, named_table, {keypos, 2}]), - ets:new(megaco_replies, [public, named_table, {keypos, 2}]), + _ = ets:new(megaco_requests, [public, named_table, {keypos, 2}]), + _ = ets:new(megaco_replies, [public, named_table, {keypos, 2}]), ?d("init -> done", []), {ok, #state{parent_pid = Parent}}. diff --git a/lib/megaco/src/engine/megaco_stats.erl b/lib/megaco/src/engine/megaco_stats.erl index 1ca9faedb4da..bf9d790074b0 100644 --- a/lib/megaco/src/engine/megaco_stats.erl +++ b/lib/megaco/src/engine/megaco_stats.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2016. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -48,7 +48,7 @@ init(Name) -> init(Name, []). init(Name, GlobalCounters) -> - ets:new(Name, [public, named_table, {keypos, 1}]), + _ = ets:new(Name, [public, named_table, {keypos, 1}]), ets:insert(Name, {global_counters, GlobalCounters}), create_global_snmp_counters(Name, GlobalCounters). diff --git a/lib/megaco/src/engine/megaco_trans_sender.erl b/lib/megaco/src/engine/megaco_trans_sender.erl index 871a0741719a..84a72e82f581 100644 --- a/lib/megaco/src/engine/megaco_trans_sender.erl +++ b/lib/megaco/src/engine/megaco_trans_sender.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -162,17 +162,17 @@ loop(#state{reqs = [], acks = [], timeout = Timeout} = S, _) -> {send_ack_now, Serial} -> ?d("loop(empty) -> received send_ack_now [~w] request", [Serial]), - send_msg(S#state.conn_handle, [], [Serial]), + _ = send_msg(S#state.conn_handle, [], [Serial]), loop(S, Timeout); - {send_req, Tid, Req} when size(Req) >= S#state.req_maxsize -> + {send_req, Tid, Req} when is_binary(Req), byte_size(Req) >= S#state.req_maxsize -> ?d("loop(empty) -> received (big) send_req request ~w", [Tid]), - send_msg(S#state.conn_handle, [{Tid, Req}], []), + _ = send_msg(S#state.conn_handle, [{Tid, Req}], []), loop(S, Timeout); - {send_req, Tid, Req} -> + {send_req, Tid, Req} when is_binary(Req) -> ?d("loop(empty) -> received send_req request ~w", [Tid]), - loop(S#state{req_sz = size(Req), reqs = [{Tid,Req}]}, Timeout); + loop(S#state{req_sz = byte_size(Req), reqs = [{Tid,Req}]}, Timeout); {send_reqs, Tids, Reqs} -> ?d("loop(empty) -> received send_reqs request: ~w", [Tids]), @@ -381,7 +381,7 @@ loop(#state{reqs = Reqs, acks = Acks, timeout = Timeout} = S, _To) -> handle_send_req(Tid, Req, #state{conn_handle = CH, req_maxsize = MaxSz, reqs = Reqs, acks = Acks} = S) - when size(Req) >= MaxSz -> + when is_binary(Req), byte_size(Req) >= MaxSz -> ?d("handle_send_req -> request bigger then maxsize ~w", [MaxSz]), handle_send_result( send_msg(CH, Reqs, Acks) ), handle_send_result( send_msg(CH, [{Tid, Req}], []) ), @@ -407,7 +407,7 @@ handle_send_req(Tid, Req, ), {S#state{req_sz = 0, reqs = [], acks = []}, true}; - false when size(Req) + ReqSz >= MaxSz -> + false when is_binary(Req), byte_size(Req) + ReqSz >= MaxSz -> %% We finally passed the req-maxsize limit ?d("handle_send_req -> maxsize ~w passed", [MaxSz]), handle_send_result( @@ -415,10 +415,10 @@ handle_send_req(Tid, Req, ), {S#state{req_sz = 0, reqs = [], acks = []}, true}; - false -> + false when is_binary(Req) -> %% Still not time to send ?d("handle_send_req -> nothing to be sent",[]), - {S#state{req_sz = ReqSz + size(Req), reqs = [{Tid, Req}|Reqs]}, + {S#state{req_sz = ReqSz + byte_size(Req), reqs = [{Tid, Req}|Reqs]}, false} end. @@ -494,33 +494,33 @@ maybe_send_reqs(_CH, [], _Acks, Acc, AccSz, _MaxSz, Sent) -> "~n length(Acc): ~w", [Sent, AccSz, length(Acc)]), {Acc, AccSz, Sent}; maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, _AccSz, MaxSz, _Sent) - when size(Req) >= MaxSz -> + when is_binary(Req), byte_size(Req) >= MaxSz -> %% The request was above the maxsize limit, so first send %% what's in store and the the big request. ?d("maybe_send_reqs -> entry when request [~w] size (~w) > max size" "~n Acks: ~w" - "~n length(Acc): ~w", [Tid, size(Req), Acks, length(Acc)]), + "~n length(Acc): ~w", [Tid, byte_size(Req), Acks, length(Acc)]), handle_send_result( send_msg(CH, Acc, Acks) ), handle_send_result( send_msg(CH, [{Tid, Req}], []) ), maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true); maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, _Sent) - when AccSz + size(Req) >= MaxSz -> + when is_binary(Req), AccSz + byte_size(Req) >= MaxSz -> %% We _did_ pass the maxsize limit with this request, so send ?d("maybe_send_reqs -> entry when sum of requests (~w) > max size" "~n Tid: ~w" "~n Acks: ~w" - "~n length(Acc): ~w", [Tid, size(Req) + AccSz, Acks, length(Acc)]), + "~n length(Acc): ~w", [Tid, byte_size(Req) + AccSz, Acks, length(Acc)]), handle_send_result( send_msg(CH, [{Tid, Req}|Acc], Acks) ), maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true); -maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, Sent) -> +maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, Sent) when is_binary(Req) -> ?d("maybe_send_reqs -> entry when" "~n Tid: ~w" "~n size(Req): ~w" "~n Acks: ~w" "~n length(Acc): ~w" - "~n AccSz: ~w", [Tid, size(Req), Acks, length(Acc), AccSz]), + "~n AccSz: ~w", [Tid, byte_size(Req), Acks, length(Acc), AccSz]), NewAcc = [{Tid,Req}|Acc], - NewAccSz = AccSz + size(Req), + NewAccSz = AccSz + byte_size(Req), maybe_send_reqs(CH, Reqs, Acks, NewAcc, NewAccSz, MaxSz, Sent). @@ -548,7 +548,7 @@ send_reply(CH, Reply, MaxSz, _ReqSz, Reqs, Acks) -> "~n length(Reqs): ~w" "~n length(Acks): ~w", [length(Reqs), length(Acks)]), case megaco_config:lookup_local_conn(CH) of - [CD] when size(Reply) > MaxSz -> + [CD] when is_binary(Reply), byte_size(Reply) > MaxSz -> handle_send_result( send_msg(CD, lists:reverse(Reqs), Acks) ), Rep = {transactionReply, Reply}, do_send_msg(CD, Rep, [], []); @@ -691,7 +691,7 @@ system_continue(_Parent, _Dbg, {S,To}) -> system_terminate(Reason, _Parent, _Dbg, {S, _}) -> #state{conn_handle = CH, reqs = Reqs, acks = Acks} = S, - send_msg(CH, Reqs, Acks), + _ = send_msg(CH, Reqs, Acks), exit(Reason). system_code_change(S, _Module, _OLdVsn, _Extra) -> diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in index cd409fa54fff..3649e2c39201 100644 --- a/lib/megaco/src/flex/Makefile.in +++ b/lib/megaco/src/flex/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2020. All Rights Reserved. +# Copyright Ericsson AB 2001-2022. 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. @@ -187,9 +187,9 @@ endif # ---------------------------------------------------- ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true) -debug opt: $(TARGET_FILES) $(C_TARGETS) solibs +$(TYPES): $(TARGET_FILES) $(C_TARGETS) solibs else -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) endif clean: diff --git a/lib/megaco/src/flex/megaco_flex_scanner.erl b/lib/megaco/src/flex/megaco_flex_scanner.erl index 174d430fb2c9..bcc58b7e8de1 100644 --- a/lib/megaco/src/flex/megaco_flex_scanner.erl +++ b/lib/megaco/src/flex/megaco_flex_scanner.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2020. All Rights Reserved. +%% Copyright Ericsson AB 2001-2023. 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. @@ -32,10 +32,12 @@ -define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)). -dialyzer({nowarn_function, is_enabled/0}). +-spec is_enabled() -> boolean(). is_enabled() -> (true =:= ?ENABLE_MEGACO_FLEX_SCANNER). -dialyzer({nowarn_function, is_reentrant_enabled/0}). +-spec is_reentrant_enabled() -> boolean(). is_reentrant_enabled() -> (true =:= ?MEGACO_REENTRANT_FLEX_SCANNER). @@ -46,8 +48,8 @@ is_scanner_port(Port, Ports) when is_tuple(Ports) -> is_scanner_port(_, _) -> false. -is_own_port(Port, Ports) -> - is_own_port(Port, size(Ports), Ports). +is_own_port(Port, Ports) when is_tuple(Ports)-> + is_own_port(Port, tuple_size(Ports), Ports). is_own_port(_Port, 0, _Ports) -> false; @@ -72,7 +74,7 @@ start(SMP) when ((SMP =:= true) orelse (SMP =:= false)) -> do_start(SMP) -> Path = lib_dir(), - erl_ddll:start(), + _ = erl_ddll:start(), load_driver(Path), PortOrPorts = open_drv_port(SMP), {ok, PortOrPorts}. @@ -117,7 +119,7 @@ open_drv_port() -> Port when is_port(Port) -> Port; {'EXIT', Reason} -> - erl_ddll:unload_driver(drv_name()), + _ = erl_ddll:unload_driver(drv_name()), throw({error, {open_port, Reason}}) end. @@ -136,13 +138,13 @@ drv_name() -> stop(Port) when is_port(Port) -> erlang:port_close(Port), - erl_ddll:unload_driver(drv_name()), + _ = erl_ddll:unload_driver(drv_name()), stopped; stop(Ports) when is_tuple(Ports) -> stop(tuple_to_list(Ports)); stop(Ports) when is_list(Ports) -> lists:foreach(fun(Port) -> erlang:port_close(Port) end, Ports), - erl_ddll:unload_driver(drv_name()), + _ = erl_ddll:unload_driver(drv_name()), stopped. diff --git a/lib/megaco/src/tcp/Makefile b/lib/megaco/src/tcp/Makefile index d07db3fa4b49..ef4232244ac2 100644 --- a/lib/megaco/src/tcp/Makefile +++ b/lib/megaco/src/tcp/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2000-2016. All Rights Reserved. +# Copyright Ericsson AB 2000-2022. 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. @@ -67,8 +67,8 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/megaco/src/tcp/megaco_tcp.erl b/lib/megaco/src/tcp/megaco_tcp.erl index 6ff8e5793fd4..e23167be71bc 100644 --- a/lib/megaco/src/tcp/megaco_tcp.erl +++ b/lib/megaco/src/tcp/megaco_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -33,6 +33,7 @@ %%----------------------------------------------------------------- %% Include files %%----------------------------------------------------------------- +-define(megaco_debug, true). -include_lib("megaco/include/megaco.hrl"). -include_lib("megaco/src/tcp/megaco_tcp.hrl"). -include_lib("megaco/src/app/megaco_internal.hrl"). @@ -183,18 +184,31 @@ connect(SupPid, Parameters) -> port = Port, options = Options, inet_backend = IB} = Rec, - - IpOpt = + + %% When using 'socket on Windows': + %% Unless 'Options' contain the 'ip' option, + %% we *will* use our own value (selected from net:getifaddr/1). + %% If 'host' is a string, we need to check 'Options' + %% to see if 'local' is present (which does not, currently, + %% work on Windows)? + %% If not (local), we *assume* domain = 'inet'. + + IpOpts = case IB of default -> []; _ -> [{inet_backend, IB}] - end ++ [binary, {packet, tpkt}, {active, once} | Options], + end ++ [binary, {packet, tpkt}, {active, once} | + post_process_opts(Host, IB, Options)], %%------------------------------------------------------ %% Connect the other side - case (catch gen_tcp:connect(Host, Port, IpOpt)) of + ?d1("connect -> connect with: " + "~n Host: ~p" + "~n Port: ~p" + "~n IpOpts: ~p", [Host, Port, IpOpts]), + case (catch gen_tcp:connect(Host, Port, IpOpts)) of {ok, Socket} -> ?d1("connect -> connected: " "~n Socket: ~p", [Socket]), @@ -205,7 +219,7 @@ connect(SupPid, Parameters) -> {ok, Pid} -> ?d1("connect -> connection started: " "~n Pid: ~p", [Pid]), - gen_tcp:controlling_process(Socket, Pid), + _ = gen_tcp:controlling_process(Socket, Pid), ?d2("connect -> control transferred"), {ok, Socket, Pid}; {error, Reason} -> @@ -217,14 +231,14 @@ connect(SupPid, Parameters) -> {error, Reason} -> ?d1("connect -> failed connecting: " "~n Reason: ~p", [Reason]), - Error = {error, {gen_tcp_connect, Reason, {Host, Port, IpOpt}}}, + Error = {error, {gen_tcp_connect, Reason, {Host, Port, IpOpts}}}, ?tcp_debug(Rec, "tcp connect failed", [Error]), Error; {'EXIT', _Reason} = Exit -> ?d1("connect -> connect exited: " "~n Exit: ~p", [Exit]), - Error = {error, {gen_tcp_connect, Exit, {Host, Port, IpOpt}}}, + Error = {error, {gen_tcp_connect, Exit, {Host, Port, IpOpts}}}, ?tcp_debug(Rec, "tcp connect failed", [Error]), Error @@ -239,6 +253,123 @@ connect(SupPid, Parameters) -> end. +%% In some cases we must bind and therefor we must have the +%% ip (or ifaddr) option. +post_process_opts(Host, socket = _IB, Opts) -> + case os:type() of + {win32, nt} -> + %% We must bind, and therefor we must provide a "proper" address. + %% Therefor...we need to figure out our domain. + post_process_opts(Host, Opts); + _ -> + Opts + end; +post_process_opts(_Host, _IB, Opts) -> + Opts. + + +%% Socket on Windows: We need the ip (or ifaddr) option +post_process_opts(Host, Opts) -> + case lists:keymember(ip, 1, Opts) orelse + lists:keymember(ifaddr, 1, Opts) of + true -> + %% No need to do anything, user has provided an address + Opts; + false -> + %% We need to figure out a proper address and provide + %% the ip option our selves. + post_process_opts2(Host, Opts) + end. + +%% We do not have the ip (or ifaddr) option +post_process_opts2(Host, Opts) + when is_tuple(Host) andalso (tuple_size(Host) =:= 4) -> + post_process_opts3(inet, Opts); +post_process_opts2(Host, Opts) + when is_tuple(Host) andalso (tuple_size(Host) =:= 8) -> + post_process_opts3(inet6, Opts); +%% This works even if Host is 'undefined' +post_process_opts2(Host, Opts) when is_atom(Host) -> + case lists:member(inet, Opts) of + true -> + post_process_opts3(inet, Opts); + false -> + case lists:member(inet6, Opts) of + true -> + post_process_opts3(inet6, Opts); + false -> + post_process_opts3(inet, Opts) + end + end; +post_process_opts2(Host, Opts) when is_list(Host) -> + %% Either hostname (inet or inet6) or a path (local) + case lists:member(inet, Opts) of + true -> + post_process_opts3(inet, Opts); + false -> + case lists:member(inet6, Opts) of + true -> + post_process_opts3(inet6, Opts); + false -> + case lists:member(local, Opts) of + true -> + %% Not supported on windows, + %% so we leave it as is and... + Opts; + false -> + post_process_opts3(inet, Opts) + end + end + end. + +post_process_opts3(Domain, Opts) -> + case net:getifaddrs(Domain) of + {ok, IfAddrs} -> + post_process_opts4(Domain, IfAddrs, Opts); + {error, _} -> + Opts + end. + +post_process_opts4(_Domain, [] = _IfAddrs, Opts) -> + Opts; +post_process_opts4(inet, + [#{addr := #{family := inet, + addr := {A, B, _, _}}} | IfAddrs], + Opts) + when (A =:= 127) orelse ((A =:= 169) andalso (B =:= 254)) -> + post_process_opts4(inet, IfAddrs, Opts); +post_process_opts4(inet, + [#{addr := #{family := inet, + addr := Addr}, + flags := Flags} | IfAddrs], + Opts) -> + case lists:member(up, Flags) of + true -> + [{ip, Addr} | Opts]; + false -> + post_process_opts4(inet, IfAddrs, Opts) + end; +post_process_opts4(inet6, + [#{addr := #{family := inet6, + addr := {A, _, _, _, _, _, _, _}}} | IfAddrs], + Opts) + when (A =:= 0) orelse (A =:= 16#fe80) -> + post_process_opts4(inet6, IfAddrs, Opts); +post_process_opts4(inet6, + [#{addr := #{family := inet6, + addr := Addr}, + flags := Flags} | IfAddrs], + Opts) -> + %% The loopback should really have been covered above, but just in case... + case lists:member(up, Flags) andalso (not lists:member(loopback, Flags)) of + true -> + [{ip, Addr} | Opts]; + false -> + post_process_opts4(inet6, IfAddrs, Opts) + end. + + + %%----------------------------------------------------------------- %% Func: send_message %% Description: Function is used for sending data on the TCP socket @@ -249,18 +380,18 @@ send_message(Socket, Data) -> "~n size(Data): ~p", [Socket, sz(Data)]), {Size, NewData} = add_tpkt_header(Data), Res = gen_tcp:send(Socket, NewData), - case Res of - ok -> - incNumOutMessages(Socket), - incNumOutOctets(Socket, Size); - _ -> - ok - end, + _ = case Res of + ok -> + incNumOutMessages(Socket), + incNumOutOctets(Socket, Size); + _ -> + ok + end, Res. -ifdef(megaco_debug). sz(Bin) when is_binary(Bin) -> - size(Bin); + byte_size(Bin); sz(List) when is_list(List) -> length(List). -endif. @@ -486,7 +617,9 @@ setup(SupPid, Options) -> "~n Options: ~p", [SupPid, Options]), Mand = [port, receive_handle], case parse_options(Options, #megaco_tcp{}, Mand) of - {ok, TcpRec} -> + {ok, #megaco_tcp{port = Port, + options = Opts, + inet_backend = IB} = TcpRec} -> ?d1("setup -> options parsed" "~n TcpRec: ~p", [TcpRec]), @@ -494,20 +627,22 @@ setup(SupPid, Options) -> %%------------------------------------------------------ %% Setup the listen socket IpOpts = - case TcpRec#megaco_tcp.inet_backend of + case IB of default -> []; - IB -> + _ -> [{inet_backend, IB}] end ++ - [binary, {packet, tpkt}, {active, once}, - {reuseaddr, true} | TcpRec#megaco_tcp.options], - Port = TcpRec#megaco_tcp.port, + [binary, {packet, tpkt}, {active, once}, {reuseaddr, true} | + post_process_opts(undefined, IB, Opts)], + ?d1("setup -> listen with: " + "~n Port: ~p" + "~n IpOpts: ~p", [Port, IpOpts]), case catch gen_tcp:listen(Port, IpOpts) of {ok, LSock} -> ?d1("setup -> listen ok" - "~n Listen: ~p", [Listen]), + "~n Listen: ~p", [LSock]), %%----------------------------------------------- %% Startup the accept process that will wait for @@ -633,11 +768,11 @@ create_acceptor(Pid, Rec, TopSup, Listen) -> %% Description: Function is used to add the TPKT header %%----------------------------------------------------------------- add_tpkt_header(Data) when is_binary(Data) -> - L = size(Data) + 4, + L = byte_size(Data) + 4, {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff ,Data]}; add_tpkt_header(IOList) when is_list(IOList) -> Binary = list_to_binary(IOList), - L = size(Binary) + 4, + L = byte_size(Binary) + 4, {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff , Binary]}. %%----------------------------------------------------------------- diff --git a/lib/megaco/src/tcp/megaco_tcp_connection.erl b/lib/megaco/src/tcp/megaco_tcp_connection.erl index 136bfda2e54f..fa31f7a510a2 100644 --- a/lib/megaco/src/tcp/megaco_tcp_connection.erl +++ b/lib/megaco/src/tcp/megaco_tcp_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -141,28 +141,28 @@ handle_info({tcp_error, _Socket}, TcpRec) -> {stop, shutdown, TcpRec}; handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>}, #megaco_tcp{socket = Socket, serialize = false} = TcpRec) - when Length < ?GC_MSG_LIMIT -> + when is_binary(Msg), Length < ?GC_MSG_LIMIT -> #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, incNumInMessages(Socket), - incNumInOctets(Socket, 4+size(Msg)), + incNumInOctets(Socket, 4+byte_size(Msg)), apply(Mod, receive_message, [RH, self(), Socket, Msg]), - inet:setopts(Socket, [{active, once}]), + _ = inet:setopts(Socket, [{active, once}]), {noreply, TcpRec}; handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>}, - #megaco_tcp{socket = Socket, serialize = false} = TcpRec) -> + #megaco_tcp{socket = Socket, serialize = false} = TcpRec) when is_binary(Msg)-> #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, incNumInMessages(Socket), - incNumInOctets(Socket, 4+size(Msg)), + incNumInOctets(Socket, 4+byte_size(Msg)), receive_message(Mod, RH, Socket, Length, Msg), - inet:setopts(Socket, [{active, once}]), + _ = inet:setopts(Socket, [{active, once}]), {noreply, TcpRec}; handle_info({tcp, Socket, <<3:8, _X:8, _Length:16, Msg/binary>>}, - #megaco_tcp{socket = Socket, serialize = true} = TcpRec) -> + #megaco_tcp{socket = Socket, serialize = true} = TcpRec) when is_binary(Msg) -> #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, incNumInMessages(Socket), - incNumInOctets(Socket, 4+size(Msg)), + incNumInOctets(Socket, 4+byte_size(Msg)), process_received_message(Mod, RH, Socket, Msg), - inet:setopts(Socket, [{active, once}]), + _ = inet:setopts(Socket, [{active, once}]), {noreply, TcpRec}; handle_info({tcp, Socket, Msg}, TcpRec) -> incNumErrors(Socket), @@ -188,8 +188,8 @@ process_received_message(Mod, RH, SH, Msg) -> receive_message(Mod, RH, SendHandle, Length, Msg) -> Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}], - spawn_opt(?MODULE, handle_received_message, - [Mod, RH, self(), SendHandle, Msg], Opts), + _ = spawn_opt(?MODULE, handle_received_message, + [Mod, RH, self(), SendHandle, Msg], Opts), ok. diff --git a/lib/megaco/src/text/Makefile b/lib/megaco/src/text/Makefile index bb5f80403bb8..6872b0ec04ca 100644 --- a/lib/megaco/src/text/Makefile +++ b/lib/megaco/src/text/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2000-2020. All Rights Reserved. +# Copyright Ericsson AB 2000-2022. 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. @@ -81,8 +81,8 @@ endif # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/megaco/src/udp/Makefile b/lib/megaco/src/udp/Makefile index 028a63e98e37..5699c3e952d1 100644 --- a/lib/megaco/src/udp/Makefile +++ b/lib/megaco/src/udp/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2000-2016. All Rights Reserved. +# Copyright Ericsson AB 2000-2022. 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. @@ -66,8 +66,8 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/megaco/src/udp/megaco_udp.erl b/lib/megaco/src/udp/megaco_udp.erl index 099f4b7455b1..37960161e2d6 100644 --- a/lib/megaco/src/udp/megaco_udp.erl +++ b/lib/megaco/src/udp/megaco_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -110,26 +110,28 @@ stop_transport(Pid, Reason) -> open(SupPid, Options) -> Mand = [port, receive_handle], case parse_options(Options, #megaco_udp{}, Mand) of - {ok, UdpRec} -> + {ok, #megaco_udp{port = Port, + options = Opts, + inet_backend = IB} = UdpRec} -> %%------------------------------------------------------ %% Setup the socket IpOpts = - case UdpRec#megaco_udp.inet_backend of + case IB of default -> []; IB -> [{inet_backend, IB}] end ++ [binary, {reuseaddr, true}, {active, once} | - UdpRec#megaco_udp.options], - case (catch gen_udp:open(UdpRec#megaco_udp.port, IpOpts)) of + post_process_opts(IB, Opts)], + case (catch gen_udp:open(Port, IpOpts)) of {ok, Socket} -> ?udp_debug(UdpRec, "udp open", []), NewUdpRec = UdpRec#megaco_udp{socket = Socket}, case start_udp_server(SupPid, NewUdpRec) of {ok, ControlPid} -> - gen_udp:controlling_process(Socket, ControlPid), + _ = gen_udp:controlling_process(Socket, ControlPid), {ok, Socket, ControlPid}; {error, Reason} -> Error = {error, {could_not_start_udp_server, Reason}}, @@ -154,6 +156,95 @@ open(SupPid, Options) -> end. +%% In some cases we must bind and therefor we must have the +%% ip (or ifaddr) option. +post_process_opts(socket = _IB, Opts) -> + case os:type() of + {win32, nt} -> + %% We must bind, and therefor we must provide a "proper" address. + %% Therefor...we need to figure out our domain. + post_process_opts(Opts); + _ -> + Opts + end; +post_process_opts(_IB, Opts) -> + Opts. + + +%% Socket on Windows: We need the ip (or ifaddr) option +post_process_opts(Opts) -> + case lists:keymember(ip, 1, Opts) orelse + lists:keymember(ifaddr, 1, Opts) of + true -> + %% No need to do anything, user has provided an address + Opts; + false -> + %% We need to figure out a proper address and provide + %% the ip option our selves. + post_process_opts2(Opts) + end. + +post_process_opts2(Opts) -> + case lists:member(inet, Opts) of + true -> + post_process_opts3(inet, Opts); + false -> + case lists:member(inet6, Opts) of + true -> + post_process_opts3(inet6, Opts); + false -> + post_process_opts3(inet, Opts) + end + end. + +post_process_opts3(Domain, Opts) -> + case net:getifaddrs(Domain) of + {ok, IfAddrs} -> + post_process_opts4(Domain, IfAddrs, Opts); + {error, _} -> + Opts + end. + +post_process_opts4(_Domain, [] = _IfAddrs, Opts) -> + Opts; +post_process_opts4(inet, + [#{addr := #{family := inet, + addr := {A, B, _, _}}} | IfAddrs], + Opts) + when (A =:= 127) orelse ((A =:= 169) andalso (B =:= 254)) -> + post_process_opts4(inet, IfAddrs, Opts); +post_process_opts4(inet, + [#{addr := #{family := inet, + addr := Addr}, + flags := Flags} | IfAddrs], + Opts) -> + case lists:member(up, Flags) of + true -> + [{ip, Addr} | Opts]; + false -> + post_process_opts4(inet, IfAddrs, Opts) + end; +post_process_opts4(inet6, + [#{addr := #{family := inet6, + addr := {A, _, _, _, _, _, _, _}}} | IfAddrs], + Opts) + when (A =:= 0) orelse (A =:= 16#fe80) -> + post_process_opts4(inet6, IfAddrs, Opts); +post_process_opts4(inet6, + [#{addr := #{family := inet6, + addr := Addr}, + flags := Flags} | IfAddrs], + Opts) -> + %% The loopback should really have been covered above, but just in case... + case lists:member(up, Flags) andalso (not lists:member(loopback, Flags)) of + true -> + [{ip, Addr} | Opts]; + false -> + post_process_opts4(inet6, IfAddrs, Opts) + end. + + + %%----------------------------------------------------------------- %% Func: socket %% Description: Returns the inet socket @@ -220,13 +311,13 @@ create_snmp_counters(SH, [Counter|Counters]) -> send_message(SH, Data) when is_record(SH, send_handle) -> #send_handle{socket = Socket, addr = Addr, port = Port} = SH, Res = gen_udp:send(Socket, Addr, Port, Data), - case Res of - ok -> - incNumOutMessages(SH), - incNumOutOctets(SH, size(Data)); - _ -> - ok - end, + _ = case Res of + ok -> + incNumOutMessages(SH), + incNumOutOctets(SH, byte_size(Data)); + _ -> + ok + end, Res; send_message(SH, _Data) -> {error, {bad_send_handle, SH}}. diff --git a/lib/megaco/src/udp/megaco_udp_server.erl b/lib/megaco/src/udp/megaco_udp_server.erl index 5abb4165aec6..68a495d8bbdc 100644 --- a/lib/megaco/src/udp/megaco_udp_server.erl +++ b/lib/megaco/src/udp/megaco_udp_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -150,10 +150,10 @@ handle_cast(Msg, UdpRec) -> %% from the socket and exit codes. %%----------------------------------------------------------------- handle_info({udp, _Socket, Ip, Port, Msg}, - #megaco_udp{serialize = false} = UdpRec) -> + #megaco_udp{serialize = false} = UdpRec) when is_binary(Msg) -> #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec, SH = megaco_udp:create_send_handle(Socket, Ip, Port), - MsgSize = size(Msg), + MsgSize = byte_size(Msg), incNumInMessages(SH), incNumInOctets(SH, MsgSize), case MsgSize of @@ -162,17 +162,17 @@ handle_info({udp, _Socket, Ip, Port, Msg}, Sz -> receive_message(Mod, RH, SH, Sz, Msg) end, - activate(Socket), + _ = activate(Socket), {noreply, UdpRec}; handle_info({udp, _Socket, Ip, Port, Msg}, - #megaco_udp{serialize = true} = UdpRec) -> + #megaco_udp{serialize = true} = UdpRec) when is_binary(Msg) -> #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec, SH = megaco_udp:create_send_handle(Socket, Ip, Port), - MsgSize = size(Msg), + MsgSize = byte_size(Msg), incNumInMessages(SH), incNumInOctets(SH, MsgSize), process_received_message(Mod, RH, SH, Msg), - activate(Socket), + _ = activate(Socket), {noreply, UdpRec}; handle_info(Info, UdpRec) -> warning_msg("received unexpected info: " diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile index 0ea33883db13..eced232a47e8 100644 --- a/lib/megaco/test/Makefile +++ b/lib/megaco/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2020. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -90,6 +90,8 @@ ERL_COMPILE_FLAGS += $(MEGACO_ERL_COMPILE_FLAGS) # We have a behaviour in the test catalog (megaco_test_generator) ERL_COMPILE_FLAGS += -pa ../../megaco/test +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) + ERL_PATH = -pa ../../megaco/examples/simple \ -pa ../../megaco/ebin \ -pa ../../et/ebin @@ -128,7 +130,7 @@ endif # Targets # ---------------------------------------------------- -tests debug opt: $(BUILDTARGET) +tests $(TYPES): $(BUILDTARGET) targets: $(TARGET_FILES) diff --git a/lib/megaco/test/megaco_actions_SUITE.erl b/lib/megaco/test/megaco_actions_SUITE.erl index c4d245a504b9..ac634988a758 100644 --- a/lib/megaco/test/megaco_actions_SUITE.erl +++ b/lib/megaco/test/megaco_actions_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2019. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -189,6 +189,16 @@ end_per_testcase(Case, Config) -> megaco_test_lib:end_per_testcase(Case, Config). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +mgc_start(Node, ET) -> + ?MGC_START(Node, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY). + +mgc_stop(Mgc) -> + ?MGC_STOP(Mgc). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% pretty_text(suite) -> @@ -196,14 +206,17 @@ pretty_text(suite) -> pretty_text(doc) -> []; pretty_text(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - i("pretty_text -> starting"), + Pre = fun req_and_rep_pre/0, + Case = fun(Nodes) -> do_pretty_text(Nodes, Config) end, + Post = fun req_and_rep_post/1, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + - Codec = pretty_text, - Version = 1, +do_pretty_text(Nodes, Config) -> + Codec = pretty_text, + Version = 1, EncodingConfig = [], - req_and_rep(Config, Codec, Version, EncodingConfig). + req_and_rep(Nodes, Config, Codec, Version, EncodingConfig). flex_pretty_text(suite) -> @@ -219,14 +232,16 @@ compact_text(suite) -> compact_text(doc) -> []; compact_text(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - i("compact_text -> starting"), - - Codec = compact_text, - Version = 1, + Pre = fun req_and_rep_pre/0, + Case = fun(Nodes) -> do_compact_text(Nodes, Config) end, + Post = fun req_and_rep_post/1, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_compact_text(Nodes, Config) -> + Codec = compact_text, + Version = 1, EncodingConfig = [], - req_and_rep(Config, Codec, Version, EncodingConfig). + req_and_rep(Nodes, Config, Codec, Version, EncodingConfig). flex_compact_text(suite) -> @@ -242,14 +257,16 @@ erl_dist(suite) -> erl_dist(doc) -> []; erl_dist(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - i("erl_dist -> starting"), - - Codec = erl_dist, - Version = 1, + Pre = fun req_and_rep_pre/0, + Case = fun(Nodes) -> do_erl_dist(Nodes, Config) end, + Post = fun req_and_rep_post/1, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_erl_dist(Nodes, Config) -> + Codec = erl_dist, + Version = 1, EncodingConfig = [], - req_and_rep(Config, Codec, Version, EncodingConfig). + req_and_rep(Nodes, Config, Codec, Version, EncodingConfig). erl_dist_mc(suite) -> @@ -257,37 +274,45 @@ erl_dist_mc(suite) -> erl_dist_mc(doc) -> []; erl_dist_mc(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - i("erl_dist_mc -> starting"), - - Codec = erl_dist, - Version = 1, + Pre = fun req_and_rep_pre/0, + Case = fun(Nodes) -> do_erl_dist_mc(Nodes, Config) end, + Post = fun req_and_rep_post/1, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_erl_dist_mc(Nodes, Config) -> + Codec = erl_dist, + Version = 1, EncodingConfig = [megaco_compressed], - req_and_rep(Config, Codec, Version, EncodingConfig). + req_and_rep(Nodes, Config, Codec, Version, EncodingConfig). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -req_and_rep(Config, Codec, _Version, EC) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - i("req_and_rep -> starting"), +req_and_rep_pre() -> MgcNode = make_node_name(mgc), Mg1Node = make_node_name(mg1), Mg2Node = make_node_name(mg2), - d("req_and_rep -> Nodes: " - "~n MgcNode: ~p" - "~n Mg1Node: ~p" - "~n Mg2Node: ~p", + d("req_and_rep_pre -> start nodes: " + "~n MgcNode: ~p" + "~n Mg1Node: ~p" + "~n Mg2Node: ~p", [MgcNode, Mg1Node, Mg2Node]), - ok = ?START_NODES([MgcNode, Mg1Node, Mg2Node]), + Nodes = [MgcNode, Mg1Node, Mg2Node], + ok = ?START_NODES(Nodes, true), + Nodes. + +req_and_rep_post(Nodes) -> + d("req_and_rep_post -> stop nodes"), + ?STOP_NODES(lists:reverse(Nodes)). + + +req_and_rep([MgcNode, Mg1Node, Mg2Node], + Config, Codec, _Version, EC) when is_list(Config) -> %% Start the MGC and MGs i("req_and_rep -> start the MGC"), ET = [{Codec, EC, tcp}, {Codec, EC, udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY), + {ok, Mgc} = mgc_start(MgcNode, ET), i("req_and_rep -> start and connect the MGs"), MgConf0 = [{Mg1Node, "mg1", Codec, EC, tcp, ?MG_VERBOSITY}, @@ -363,7 +388,7 @@ req_and_rep(Config, Codec, _Version, EC) when is_list(Config) -> %% Tell Mgc to stop i("req_and_rep -> stop the MGC"), - ?MGC_STOP(Mgc), + mgc_stop(Mgc), i("req_and_rep -> done", []), ok. @@ -460,6 +485,16 @@ sleep(X) -> receive after X -> ok end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +try_tc(TCName, Pre, Case, Post) -> + try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post). + +try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> + ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% i(F) -> @@ -469,8 +504,8 @@ i(F, A) -> print(info, get(verbosity), "", F, A). -%% d(F) -> -%% d(F, []). +d(F) -> + d(F, []). d(F, A) -> print(debug, get(verbosity), "DBG: ", F, A). diff --git a/lib/megaco/test/megaco_codec_v1_SUITE.erl b/lib/megaco/test/megaco_codec_v1_SUITE.erl index c458e0b5796f..0f88dd8d9ac7 100644 --- a/lib/megaco/test/megaco_codec_v1_SUITE.erl +++ b/lib/megaco/test/megaco_codec_v1_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2019. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -508,6 +508,8 @@ end_per_suite(suite) -> []; end_per_suite(doc) -> []; end_per_suite(Config0) when is_list(Config0) -> + ?ANNOUNCE_SUITE_END(), + p("end_per_suite -> entry with" "~n Config: ~p" "~n Nodes: ~p", [Config0, erlang:nodes()]), @@ -541,15 +543,20 @@ init_per_group(Group, Config) -> ?ANNOUNCE_GROUP_INIT(Group), Config. -end_per_group(flex_pretty_tickets, Config) -> +end_per_group(flex_pretty_tickets = Group, Config) -> + ?ANNOUNCE_GROUP_END(Group), flex_pretty_finish(Config); -end_per_group(flex_compact_tickets, Config) -> +end_per_group(flex_compact_tickets = Group, Config) -> + ?ANNOUNCE_GROUP_END(Group), flex_compact_finish(Config); -end_per_group(flex_compact, Config) -> +end_per_group(flex_compact = Group, Config) -> + ?ANNOUNCE_GROUP_END(Group), flex_compact_finish(Config); -end_per_group(flex_pretty, Config) -> +end_per_group(flex_pretty = Group, Config) -> + ?ANNOUNCE_GROUP_END(Group), flex_pretty_finish(Config); -end_per_group(_GroupName, Config) -> +end_per_group(Group, Config) -> + ?ANNOUNCE_GROUP_END(Group), Config. diff --git a/lib/megaco/test/megaco_examples_SUITE.erl b/lib/megaco/test/megaco_examples_SUITE.erl index dc3dfb7967bc..084749ce6025 100644 --- a/lib/megaco/test/megaco_examples_SUITE.erl +++ b/lib/megaco/test/megaco_examples_SUITE.erl @@ -45,6 +45,8 @@ -include_lib("megaco/include/megaco.hrl"). -include_lib("megaco/include/megaco_message_v1.hrl"). +-define(TEST_VERBOSITY, debug). + %%====================================================================== %% Common Test interface functions @@ -341,14 +343,32 @@ purge_example(Mods) -> simple(suite) -> []; simple(Config) when is_list(Config) -> - process_flag(trap_exit, true), - d("simple -> create node name(s)"), - [_Local, MGC, MG] = ?LIB:mk_nodes(3), %% Grrr - Nodes = [MGC, MG], - - d("simple -> start nodes"), - ok = ?LIB:start_nodes(Nodes, ?MODULE, ?LINE), - + Pre = fun() -> + d("simple -> " + "create (3) node name(s) (includes the own node)"), + %% We actually need two *new* nodes, + %% but the function includes the own node, + %% so we need to ask for one more. + [_Local, MGC, MG] = ?MK_NODES(3), + Nodes = [MGC, MG], + + d("simple -> start nodes: " + "~n ~p", [Nodes]), + ok = ?START_NODES(Nodes, true), + Nodes + end, + Case = fun(Nodes) -> + do_simple(Config, Nodes) + end, + Post = fun(Nodes) -> + d("simple -> stop nodes" + "~n ~p", [Nodes]), + ?STOP_NODES(Nodes) + end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + + +do_simple(_Config, [MGC, MG]) -> MGCId = "MGC", MGId = "MG", @@ -472,12 +492,6 @@ simple(Config) when is_list(Config) -> ok end, - d("simple -> stop ~p", [MGC]), - slave:stop(MGC), - - d("simple -> stop ~p", [MG]), - slave:stop(MG), - d("simple -> done", []), ok. @@ -597,32 +611,40 @@ users(Proxy) -> meas(suite) -> []; meas(Config) when is_list(Config) -> - process_flag(trap_exit, true), - MFactor = ?config(megaco_factor, Config), - {Time, Factor} = - if - (MFactor =:= 1) -> - {3, 100}; - (MFactor =:= 2) -> - {4, 100}; - (MFactor =:= 3) -> - {4, 200}; - (MFactor =:= 4) -> - {5, 200}; - (MFactor =:= 5) -> - {5, 400}; - true -> - {6, 400} - end, - p("Run with: " - "~n Timetrap: ~p mins" - "~n Factor: ~p", [Time, Factor]), - ct:timetrap(?MINS(Time)), - WorkerNode = ?config(worker_node, Config), - do_meas(?FUNCTION_NAME, WorkerNode, megaco_codec_meas, start, [Factor]). - -do_meas(SName, Node, Mod, Func, Args) -> - put(sname, SName), + Pre = fun() -> + MFactor = ?config(megaco_factor, Config), + {Time, Factor} = + if + (MFactor =:= 1) -> + {3, 100}; + (MFactor =:= 2) -> + {4, 100}; + (MFactor =:= 3) -> + {4, 200}; + (MFactor =:= 4) -> + {5, 300}; + (MFactor =:= 5) -> + {5, 400}; + (MFactor =:= 6) -> + {6, 500}; + true -> + {10, 600} + end, + p("Run with: " + "~n Timetrap: ~p mins" + "~n Factor: ~p", [Time, Factor]), + ct:timetrap(?MINS(Time)), + WorkerNode = ?config(worker_node, Config), + {Factor, WorkerNode} + end, + Opts = #{verbose => false}, + Case = fun({Factor, WorkerNode}) -> + do_meas(WorkerNode, megaco_codec_meas, start, [Factor, Opts]) + end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_meas(Node, Mod, Func, Args) -> F = fun() -> exit( rpc:call(Node, Mod, Func, Args) ) end, @@ -646,11 +668,19 @@ do_meas(SName, Node, Mod, Func, Args) -> {'DOWN', MRef, process, Pid, Reason} -> p("worker process terminated: " "~n ~p", [Reason]), - ok + ok; + + {'EXIT', TCPid, {timetrap_timeout = R, TCTimeout, TCSTack}} -> + p("received timetrap timeout (~w ms) from ~p => " + "Kill executor process" + "~n TC Stack: ~p", [TCTimeout, TCPid, TCSTack]), + exit(Pid, kill), + ?SKIP(R) end, ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% ------------------ meas:mstone1 ------------------------ @@ -658,23 +688,30 @@ do_meas(SName, Node, Mod, Func, Args) -> mstone1(suite) -> []; mstone1(Config) when is_list(Config) -> - process_flag(trap_exit, true), - WorkerNode = ?config(worker_node, Config), - %% The point of this is - %% to make sure we utilize as much of the host as possible... - RunTime = 1, % Minute - NumSched = try erlang:system_info(schedulers_online) of N -> N - catch _:_:_ -> 1 - end, - Factor = 1 + (NumSched div 12), - Mod = megaco_codec_mstone1, - Func = start, - Args = [RunTime, Factor], - p("Run with: " - "~n Run Time: ~p min(s)" - "~n Factor: ~p", [RunTime, Factor]), - ct:timetrap(?MINS(RunTime + 1)), - do_meas(?FUNCTION_NAME, WorkerNode, Mod, Func, Args). + Pre = fun() -> + %% The point of this is to make sure we + %% utilize as much of the host as possible... + RunTime = 1, % Minute + NumSched = + try erlang:system_info(schedulers_online) of N -> N + catch _:_:_ -> 1 + end, + Factor = 1 + (NumSched div 12), + ct:timetrap(?MINS(RunTime + 1)), + {RunTime, Factor, ?config(worker_node, Config)} + end, + Case = fun({RunTime, Factor, WorkerNode}) -> + Mod = megaco_codec_mstone1, + Func = start, + Args = [RunTime, Factor], + p("Run with: " + "~n Run Time: ~p min(s)" + "~n Factor: ~p", [RunTime, Factor]), + do_meas(WorkerNode, Mod, Func, Args) + end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -684,23 +721,29 @@ mstone1(Config) when is_list(Config) -> mstone2(suite) -> []; mstone2(Config) when is_list(Config) -> - process_flag(trap_exit, true), - WorkerNode = ?config(worker_node, Config), - RunTime = 1, % Minutes - NumSched = try erlang:system_info(schedulers_online) of N -> N - catch _:_:_ -> 1 - end, - Factor = 1 + (NumSched div 12), - Mode = standard, - Mod = megaco_codec_mstone2, - Func = start, - Args = [Factor, RunTime, Mode], - p("Run with: " - "~n Factor: ~p" - "~n Run Time: ~p min(s)" - "~n Mode: ~p", [Factor, RunTime, Mode]), - ct:timetrap(?MINS(RunTime + 1)), - do_meas(?FUNCTION_NAME, WorkerNode, Mod, Func, Args). + Pre = fun() -> + RunTime = 1, % Minutes + NumSched = + try erlang:system_info(schedulers_online) of N -> N + catch _:_:_ -> 1 + end, + Factor = 1 + (NumSched div 12), + ct:timetrap(?MINS(RunTime + 1)), + {Factor, RunTime, ?config(worker_node, Config)} + end, + Case = fun({Factor, RunTime, WorkerNode}) -> + Mode = standard, + Mod = megaco_codec_mstone2, + Func = start, + Args = [Factor, RunTime, Mode], + p("Run with: " + "~n Factor: ~p" + "~n Run Time: ~p min(s)" + "~n Mode: ~p", [Factor, RunTime, Mode]), + do_meas(WorkerNode, Mod, Func, Args) + end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -729,6 +772,16 @@ unique_node_name(Pre) -> list_to_atom(?F("~s@~s", [?UNIQUE(Pre), Host])). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +try_tc(TCName, Pre, Case, Post) -> + try_tc(TCName, "EX-TESTER", ?TEST_VERBOSITY, Pre, Case, Post). + +try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> + ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% p(F) -> diff --git a/lib/megaco/test/megaco_load_SUITE.erl b/lib/megaco/test/megaco_load_SUITE.erl index 42e1a122a4e0..0d019a272cb3 100644 --- a/lib/megaco/test/megaco_load_SUITE.erl +++ b/lib/megaco/test/megaco_load_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -22,6 +22,26 @@ %%---------------------------------------------------------------------- %% Purpose: Verify the application specifics of the Megaco application %%---------------------------------------------------------------------- +%% +%% application:set_env(megaco, test_inet_backends, true). +%% +%% S = fun() -> ts:run(kernel, megaco_load_SUITE, [batch]) end. +%% S = fun(SUITE) -> ts:run(kernel, SUITE, [batch]) end. +%% S = fun() -> ct:run_test([{suite, megaco_load_SUITE}]) end. +%% S = fun(SUITE) -> ct:run_test([{suite, SUITE}]) end. +%% G = fun(GROUP) -> ts:run(kernel, megaco_load_SUITE, {group, GROUP}, [batch]) end. +%% G = fun(SUITE, GROUP) -> ts:run(kernel, SUITE, {group, GROUP}, [batch]) end. +%% G = fun(GROUP) -> ct:run_test([{suite, megaco_load_SUITE}, {group, GROUP}]) end. +%% G = fun(SUITE, GROUP) -> ct:run_test([{suite, SUITE}, {group, GROUP}]) end. +%% T = fun(TC) -> ts:run(kernel, megaco_load_SUITE, TC, [batch]) end. +%% T = fun(TC) -> ct:run_test([{suite, megaco_load_SUITE}, {testcase, TC}]) end. +%% T = fun(TC) -> ct:run_test([{suite, megaco_load_SUITE}, {group, inet_backend_socket}, {testcase, TC}]) end. +%% T = fun(S, TC) -> ct:run_test([{suite, S}, {testcase, TC}]) end. +%% T = fun(S, G, TC) -> ct:run_test([{suite, S}, {group, G}, {testcase, TC}]) end. +%% +%%---------------------------------------------------------------------- +%% + -module(megaco_load_SUITE). -export([ @@ -613,7 +633,6 @@ multi_load(MGs, Conf, NumLoaders, NumReqs) -> "~n Conf: ~p" "~n NumLoaders: ~p" "~n NumReqs: ~p", [MGs, Conf, NumLoaders, NumReqs]), - Pids = multi_load_collector_start(MGs, Conf, NumLoaders, NumReqs, []), case timer:tc(?MODULE, do_multi_load, [Pids, NumLoaders, NumReqs]) of {Time, {ok, OKs, []}} -> @@ -652,8 +671,8 @@ get_env(Key, Env) -> multi_load_collector(Parent, Node, Mid, Conf, NumLoaders, NumReqs, Env) -> put(verbosity, get_env(verbosity, Env)), - put(tc, get_env(tc, Env)), - put(sname, get_env(sname, Env) ++ "-loader"), + put(tc, get_env(tc, Env)), + put(sname, get_env(sname, Env) ++ "-loader"), case ?MG_START(Node, Mid, text, tcp, Conf, ?MG_VERBOSITY) of {ok, Pid} -> d("MG ~p user info: ~n~p", [Mid, ?MG_USER_INFO(Pid, all)]), diff --git a/lib/megaco/test/megaco_mess_SUITE.erl b/lib/megaco/test/megaco_mess_SUITE.erl index 9ff3ac14685a..c89559281252 100644 --- a/lib/megaco/test/megaco_mess_SUITE.erl +++ b/lib/megaco/test/megaco_mess_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -9891,6 +9891,9 @@ otp_6442_resend_request1(suite) -> []; otp_6442_resend_request1(Config) when is_list(Config) -> Pre = fun() -> + put(verbosity, debug), + put(tc, ?FUNCTION_NAME), + MgNode = make_node_name(mg), d("start (MG) node: ~p", [MgNode]), Nodes = [MgNode], @@ -10262,6 +10265,9 @@ otp_6442_resend_request2(suite) -> []; otp_6442_resend_request2(Config) when is_list(Config) -> Pre = fun() -> + put(verbosity, debug), + put(tc, ?FUNCTION_NAME), + MgNode = make_node_name(mg), d("start (MG) node: ~p", [MgNode]), Nodes = [MgNode], @@ -10571,6 +10577,9 @@ otp_6442_resend_reply1(suite) -> otp_6442_resend_reply1(Config) when is_list(Config) -> Factor = ?config(megaco_factor, Config), Pre = fun() -> + put(verbosity, debug), + put(tc, ?FUNCTION_NAME), + MgNode = make_node_name(mg), d("start (MG) node: ~p", [MgNode]), Nodes = [MgNode], @@ -11353,12 +11362,13 @@ otp_6442_resend_reply2_err_desc(T) -> otp_6865_request_and_reply_plain_extra1(suite) -> []; otp_6865_request_and_reply_plain_extra1(Config) when is_list(Config) -> - ?ACQUIRE_NODES(1, Config), + Pre = fun() -> undefined end, + Case = fun(X) -> do_otp_6865_request_and_reply_plain_extra1(X, Config) end, + Post = fun(_) -> ok end, + try_tc(otp6865e1, Pre, Case, Post). - put(sname, "TEST"), - put(verbosity, debug), - put(tc, otp6865e1), - i("starting"), +do_otp_6865_request_and_reply_plain_extra1(_, Config) -> + ?ACQUIRE_NODES(1, Config), d("start test case controller",[]), ok = megaco_tc_controller:start_link(), @@ -11453,11 +11463,25 @@ otp_6865_request_and_reply_plain_extra2(suite) -> otp_6865_request_and_reply_plain_extra2(doc) -> []; otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, otp6865e2), - i("starting"), + Pre = fun() -> + MgcNode = make_node_name(mgc), + MgNode = make_node_name(mg), + d("start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + Nodes + end, + Case = fun do_otp_6865_request_and_reply_plain_extra2/1, + Post = fun(Nodes) -> + d("stop nodes"), + ?STOP_NODES(lists:reverse(Nodes)) + end, + try_tc(otp6865e2, Pre, Case, Post). +do_otp_6865_request_and_reply_plain_extra2([MgcNode, MgNode]) -> d("start tc controller"), ok = megaco_tc_controller:start_link(), @@ -11466,16 +11490,6 @@ otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) -> ExtraInfo = otp6865e2_extra_info, ok = megaco_tc_controller:insert(extra_transport_info, ExtraInfo), - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - Nodes = [MgcNode, MgNode], - ok = ?START_NODES(Nodes, true), - - d("[MGC] start the simulator "), {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode), @@ -11521,10 +11535,6 @@ otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) -> i("stop tc controller"), ok = megaco_tc_controller:stop(), - %% Cleanup - d("stop nodes"), - ?STOP_NODES(lists:reverse(Nodes)), - i("done", []), ok. diff --git a/lib/megaco/test/megaco_mib_SUITE.erl b/lib/megaco/test/megaco_mib_SUITE.erl index 965e368f73e1..c5b3f7f19865 100644 --- a/lib/megaco/test/megaco_mib_SUITE.erl +++ b/lib/megaco/test/megaco_mib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2020. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -675,11 +675,15 @@ traffic_verify_counter(Name, Counter, Counters, Expected) -> {value, {Counter, Val}} -> i("counter ~w *not* verified for ~p: " "~n Expected: ~w" - "~n Actual: ~w", [Counter, Name, Expected, Val]), - exit({illegal_counter_value, Counter, Val, Expected, Name}); + "~n Actual: ~w" + "~n Counters: ~w", + [Counter, Name, Expected, Val, Counters]), + exit({illegal_counter_value, Name, Counter, Expected, Val, + Counters}); false -> - i("counter ~w *not* found for ~p", [Counter, Name]), - exit({not_found, Counter, Counters, Name, Expected}) + i("counter ~w *not* found for ~p: " + "~n Counters: ~p", [Counter, Name, Counters]), + exit({not_found, Name, Counter, Counters, Expected}) end. @@ -1200,7 +1204,7 @@ start_mg(Node, Mid, Encoding, Transport, Verbosity) -> mg(Parent, Verbosity, Config) -> process_flag(trap_exit, true), put(verbosity, Verbosity), - put(sname, "MG"), + put(sname, get_mg_sname(Config)), i("mg -> starting"), {Mid, ConnHandle} = mg_init(Config), notify_started(Parent), @@ -1208,6 +1212,14 @@ mg(Parent, Verbosity, Config) -> i("mg -> started"), mg_loop(S). +get_mg_sname(Config) -> + case get_conf(local_mid, Config) of + {deviceName, Name} -> + Name; + _ -> + "MG" +end. + mg_init(Config) -> d("mg_init -> entry"), Mid = get_conf(local_mid, Config), diff --git a/lib/megaco/test/megaco_pending_limit_SUITE.erl b/lib/megaco/test/megaco_pending_limit_SUITE.erl index d5db6e6bc0b5..dfe52535c9f4 100644 --- a/lib/megaco/test/megaco_pending_limit_SUITE.erl +++ b/lib/megaco/test/megaco_pending_limit_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2019. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -46,31 +46,6 @@ ]). --ifdef(megaco_hipe_special). --export([ - %% Case: recv_limit_exceeded1 - rle1_mgc_verify_service_change_req_msg/2, - rle1_mgc_verify_notify_req_msg/1, - rle1_mg_verify_handle_connect/1, - rle1_mg_verify_service_change_rep/1, - rle1_mg_verify_trans_rep/1, - - %% Case: otp_4956 - otp_4956_mgc_verify_handle_connect/1, - otp_4956_mgc_verify_service_change_req/2, - otp_4956_mgc_verify_notify_req1/1, - otp_4956_mgc_verify_notify_req2/1, - otp_4956_mgc_verify_handle_trans_req_abort/1, - otp_4956_mgc_verify_handle_disconnect/1, - otp_4956_mg_verify_service_change_rep_msg/1, - otp_4956_mg_verify_pending_msg/1, - otp_4956_mg_verify_pending_limit_msg/1, - - %% Utility - encode_msg/3, - decode_msg/3 - ]). --endif. -include_lib("megaco/include/megaco.hrl"). -include_lib("megaco/include/megaco_message_v1.hrl"). @@ -89,6 +64,10 @@ -define(MGC_START(Pid, Mid, ET, Conf, Verb), megaco_test_mgc:start(Pid, Mid, ET, Conf, Verb)). +-define(MGC_START(Pid, ET, Conf), + ?MGC_START(Pid, {deviceName, "ctrl"}, ET, Conf, ?MGC_VERBOSITY)). +-define(MGC_START(Pid, ET), + ?MGC_START(Pid, ET, [])). -define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)). -define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)). -define(MGC_RESET_STATS(Pid), megaco_test_mgc:reset_stats(Pid)). @@ -110,6 +89,10 @@ -define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb), megaco_test_mg:start(Pid, Mid, Enc, Transp, Conf, Verb)). +-define(MG_START(Pid, Enc, Transp, Conf), + ?MG_START(Pid, {deviceName, "mg"}, Enc, Transp, Conf, ?MG_VERBOSITY)). +-define(MG_START(Pid, Enc, Transp), + ?MG_START(Pid, Enc, Transp, [])). -define(MG_STOP(Pid), megaco_test_mg:stop(Pid)). -define(MG_GET_STATS(Pid, No), megaco_test_mg:get_stats(Pid, No)). -define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)). @@ -278,30 +261,39 @@ sent_timer_late_reply(suite) -> sent_timer_late_reply(doc) -> "..."; sent_timer_late_reply(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_timer_late_reply), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_stlr_mgc), + MgNode = make_node_name(pl_stlr_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_timer_late_reply(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_timer_late_reply(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], MgcConf = [{megaco_trace, false}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, MgcConf, ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET, MgcConf), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConf = [{megaco_trace, io}], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConf, ?MG_VERBOSITY), + MgConf = [{megaco_trace, io}], + {ok, Mg} = ?MG_START(MgNode, text, tcp, MgConf), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -342,11 +334,7 @@ sent_timer_late_reply(Config) when is_list(Config) -> i("[MGC] stop"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. @@ -357,29 +345,37 @@ sent_timer_exceeded(suite) -> sent_timer_exceeded(doc) -> "..."; sent_timer_exceeded(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_timer_exceeded), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_ste_mgc), + MgNode = make_node_name(pl_ste_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_timer_exceeded(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_timer_exceeded(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), - i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + i("[MG] start"), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -419,11 +415,7 @@ sent_timer_exceeded(Config) when is_list(Config) -> i("[MGC] stop"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. @@ -434,29 +426,37 @@ sent_timer_exceeded_long(suite) -> sent_timer_exceeded_long(doc) -> "..."; sent_timer_exceeded_long(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_timer_exceeded_long), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_stel_mgc), + MgNode = make_node_name(pl_stel_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_timer_exceeded_long(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_timer_exceeded_long(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -494,11 +494,7 @@ sent_timer_exceeded_long(Config) when is_list(Config) -> i("[MGC] stop"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. @@ -508,35 +504,42 @@ sent_timer_exceeded_long(Config) when is_list(Config) -> %% This test case can only be run with the stack compiled with %% the MEGACO_TEST_CODE flag. Therefor there is no point in %% including this test case in the usual test suite --ifdef(MEGACO_TEST_CODE). sent_resend_late_reply(suite) -> []; sent_resend_late_reply(doc) -> "..."; sent_resend_late_reply(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_resend_late_reply), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun megaco_test_code/0, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_srlr_mgc), + MgNode = make_node_name(pl_srlr_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_resend_late_reply(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_resend_late_reply(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -594,53 +597,48 @@ sent_resend_late_reply(Config) when is_list(Config) -> i("done", []), ok. --else. - -sent_resend_late_reply(suite) -> - []; -sent_resend_late_reply(doc) -> - "..."; -sent_resend_late_reply(Config) when is_list(Config) -> - ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true"). - --endif. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case can only be run with the stack compiled with %% the MEGACO_TEST_CODE flag. Therefor there is no point in %% including this test case in the usual test suite --ifdef(MEGACO_TEST_CODE). sent_resend_exceeded(suite) -> []; sent_resend_exceeded(doc) -> "..."; sent_resend_exceeded(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_resend_exceeded), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun megaco_test_code/0, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_sre_mgc), + MgNode = make_node_name(pl_sre_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_resend_exceeded(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_resend_exceeded(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -686,60 +684,51 @@ sent_resend_exceeded(Config) when is_list(Config) -> i("[MGC] stop"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. --else. - -sent_resend_exceeded(suite) -> - []; -sent_resend_exceeded(doc) -> - "..."; -sent_resend_exceeded(Config) when is_list(Config) -> - ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true"). - --endif. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case can only be run with the stack compiled with %% the MEGACO_TEST_CODE flag. Therefor there is no point in %% including this test case in the usual test suite --ifdef(MEGACO_TEST_CODE). sent_resend_exceeded_long(suite) -> []; sent_resend_exceeded_long(doc) -> "..."; sent_resend_exceeded_long(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, sent_resend_exceeded_long), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun megaco_test_code/0, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_srel_mgc), + MgNode = make_node_name(pl_srel_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_sent_resend_exceeded_long(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_sent_resend_exceeded_long(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -786,26 +775,10 @@ sent_resend_exceeded_long(Config) when is_list(Config) -> i("[MGC] stop"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. --else. - -sent_resend_exceeded_long(suite) -> - []; -sent_resend_exceeded_long(doc) -> - "..."; -sent_resend_exceeded_long(Config) when is_list(Config) -> - ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true"). - --endif. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% %%% %%% Received peinding test cases %%% @@ -817,19 +790,30 @@ recv_limit_exceeded1(suite) -> recv_limit_exceeded1(doc) -> "Received pending limit exceeded (exactly)"; recv_limit_exceeded1(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, rle1), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_rle_mgc), + MgNode = make_node_name(pl_rle_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_recv_limit_exceeded1(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_recv_limit_exceeded1(#{nodes := [MgcNode, MgNode]}) -> d("[MGC] start the simulator "), {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode), @@ -868,27 +852,13 @@ recv_limit_exceeded1(Config) when is_list(Config) -> i("[MG] stop generator"), megaco_test_megaco_generator:stop(Mg), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. %% %% MGC generator stuff %% --ifdef(megaco_hipe_special). --define(rle1_mgc_decode_msg_fun(Mod, Conf), - {?MODULE, decode_msg, [Mod, Conf]}). --define(rle1_mgc_encode_msg_fun(Mod, Conf), - {?MODULE, encode_msg, [Mod, Conf]}). --define(rle1_mgc_verify_service_change_req_msg_fun(Mid), - {?MODULE, rle1_mgc_verify_service_change_req_msg, [Mid]}). --define(rle1_mgc_verify_notify_req_msg_fun(), - {?MODULE, rle1_mgc_verify_notify_req_msg, []}). --else. -define(rle1_mgc_decode_msg_fun(Mod, Conf), rle1_mgc_decode_msg_fun(Mod, Conf)). -define(rle1_mgc_encode_msg_fun(Mod, Conf), @@ -897,7 +867,6 @@ recv_limit_exceeded1(Config) when is_list(Config) -> rle1_mgc_verify_service_change_req_msg_fun(Mid)). -define(rle1_mgc_verify_notify_req_msg_fun(), rle1_mgc_verify_notify_req_msg_fun()). --endif. rle1_mgc_event_sequence(text, tcp) -> Mid = {deviceName,"ctrl"}, @@ -942,17 +911,15 @@ rle1_mgc_event_sequence2(Mid, EM, EC) -> ], EvSeq. --ifndef(megaco_hipe_special). rle1_mgc_encode_msg_fun(Mod, Conf) -> fun(M) -> encode_msg(M, Mod, Conf) end. rle1_mgc_decode_msg_fun(Mod, Conf) -> - fun(M) -> + fun(M) -> decode_msg(M, Mod, Conf) end. --endif. rle1_mgc_service_change_reply_msg(Mid, TransId, Cid) -> SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid}, @@ -983,12 +950,10 @@ rle1_mgc_pending_msg(Mid, TransId) -> messageBody = Body}, #'MegacoMessage'{mess = Mess}. --ifndef(megaco_hipe_special). rle1_mgc_verify_service_change_req_msg_fun(Mid) -> fun(M) -> rle1_mgc_verify_service_change_req_msg(M, Mid) end. --endif. rle1_mgc_verify_service_change_req_msg(#'MegacoMessage'{mess = Mess} = M, _Mid1) -> @@ -1018,12 +983,10 @@ rle1_mgc_verify_service_change_req_msg(#'MegacoMessage'{mess = Mess} = M, rle1_mgc_verify_service_change_req_msg(M, _Mid) -> {error, {invalid_message, M}}. --ifndef(megaco_hipe_special). rle1_mgc_verify_notify_req_msg_fun() -> fun(M) -> rle1_mgc_verify_notify_req_msg(M) end. --endif. rle1_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) -> io:format("rle1_mgc_verify_notify_req_msg -> entry with" @@ -1054,21 +1017,12 @@ rle1_mgc_verify_notify_req_msg(M) -> %% %% MG generator stuff %% --ifdef(megaco_hipe_special). --define(rle1_mg_verify_handle_connect_fun(), - {?MODULE, rle1_mg_verify_handle_connect, []}). --define(rle1_mg_verify_service_change_rep_fun(), - {?MODULE, rle1_mg_verify_service_change_rep, []}). --define(rle1_mg_verify_trans_rep_fun(), - {?MODULE, rle1_mg_verify_trans_rep, []}). --else. -define(rle1_mg_verify_handle_connect_fun(), fun rle1_mg_verify_handle_connect/1). -define(rle1_mg_verify_service_change_rep_fun(), fun rle1_mg_verify_service_change_rep/1). -define(rle1_mg_verify_trans_rep_fun(), fun rle1_mg_verify_trans_rep/1). --endif. rle1_mg_event_sequence(text, tcp) -> Mid = {deviceName,"mg"}, @@ -1222,23 +1176,34 @@ recv_limit_exceeded2(Config) when is_list(Config) -> otp_4956(suite) -> []; otp_4956(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, otp_4956), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - - d("[MGC] start the simulator "), + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_4956_mgc), + MgNode = make_node_name(pl_4956_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_otp_4956(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_otp_4956(#{nodes := [MgcNode, MgNode]}) -> + i("[MGC] start the simulator "), {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode), - d("[MGC] create the event sequence"), + i("[MGC] create the event sequence"), MgcEvSeq = otp_4956_mgc_event_sequence(text, tcp), i("wait some time before starting the MGC simulation"), @@ -1273,10 +1238,6 @@ otp_4956(Config) when is_list(Config) -> i("[MG] stop generator"), megaco_test_tcp_generator:stop(Mg), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - i("done", []), ok. @@ -1284,20 +1245,6 @@ otp_4956(Config) when is_list(Config) -> %% %% MGC generator stuff %% --ifdef(megaco_hipe_special). --define(otp_4956_mgc_verify_handle_connect_fun(), - {?MODULE, otp_4956_mgc_verify_handle_connect, []}). --define(otp_4956_mgc_verify_service_change_req_fun(Mid), - {?MODULE, otp_4956_mgc_verify_service_change_req, [Mid]}). --define(otp_4956_mgc_verify_notify_req1_fun(), - {?MODULE, otp_4956_mgc_verify_notify_req1, []}). --define(otp_4956_mgc_verify_notify_req2_fun(), - {?MODULE, otp_4956_mgc_verify_notify_req2, []}). --define(otp_4956_mgc_verify_handle_trans_req_abort_fun(), - {?MODULE, otp_4956_mgc_verify_handle_trans_req_abort, []}). --define(otp_4956_mgc_verify_handle_disconnect_fun(), - {?MODULE, otp_4956_mgc_verify_handle_disconnect, []}). --else. -define(otp_4956_mgc_verify_handle_connect_fun(), otp_4956_mgc_verify_handle_connect_fun()). -define(otp_4956_mgc_verify_service_change_req_fun(Mid), @@ -1310,7 +1257,6 @@ otp_4956(Config) when is_list(Config) -> otp_4956_mgc_verify_handle_trans_req_abort_fun()). -define(otp_4956_mgc_verify_handle_disconnect_fun(), fun otp_4956_mgc_verify_handle_disconnect/1). --endif. otp_4956_mgc_event_sequence(text, tcp) -> Mid = {deviceName,"ctrl"}, @@ -1355,24 +1301,20 @@ otp_4956_mgc_event_sequence(text, tcp) -> EvSeq. --ifndef(megaco_hipe_special). otp_4956_mgc_verify_handle_connect_fun() -> fun(M) -> otp_4956_mgc_verify_handle_connect(M) end. --endif. otp_4956_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) -> {ok, CH, ok}; otp_4956_mgc_verify_handle_connect(Else) -> {error, Else, ok}. --ifndef(megaco_hipe_special). otp_4956_mgc_verify_service_change_req_fun(Mid) -> fun(Req) -> otp_4956_mgc_verify_service_change_req(Req, Mid) end. --endif. otp_4956_mgc_verify_service_change_req( {handle_trans_request, _, ?VERSION, [AR]}, Mid) -> @@ -1434,12 +1376,10 @@ otp_4956_mgc_verify_service_change_req(Else, _Mid) -> ErrReply = {discard_ack, ED}, {error, Else, ErrReply}. --ifndef(megaco_hipe_special). otp_4956_mgc_verify_notify_req1_fun() -> fun(Req) -> otp_4956_mgc_verify_notify_req1(Req) end. --endif. otp_4956_mgc_verify_notify_req1({handle_trans_request, _, ?VERSION, [AR]}) -> io:format("otp_4956_mgc_verify_notify_req1 -> entry with" @@ -1470,12 +1410,10 @@ otp_4956_mgc_verify_notify_req1(Else) -> ErrReply = {discard_ack, ED}, {error, Else, ErrReply}. --ifndef(megaco_hipe_special). otp_4956_mgc_verify_notify_req2_fun() -> fun(Ev) -> otp_4956_mgc_verify_notify_req2(Ev) end. --endif. otp_4956_mgc_verify_notify_req2({handle_trans_request, _, ?VERSION, [AR]}) -> case AR of @@ -1500,12 +1438,10 @@ otp_4956_mgc_verify_notify_req2(Else) -> ErrReply = {discard_ack, ED}, {error, Else, ErrReply}. --ifndef(megaco_hipe_special). otp_4956_mgc_verify_handle_trans_req_abort_fun() -> fun(Req) -> otp_4956_mgc_verify_handle_trans_req_abort(Req) end. --endif. otp_4956_mgc_verify_handle_trans_req_abort({handle_trans_request_abort, CH, ?VERSION, 2, Pid}) -> @@ -1574,18 +1510,6 @@ otp_4956_mgc_notify_reply_ar(Cid, TermId) -> %% %% MG generator stuff %% --ifdef(megaco_hipe_special). --define(otp_4956_mg_decode_msg_fun(Mod, Conf), - {?MODULE, decode_msg, [Mod, Conf]}). --define(otp_4956_mg_encode_msg_fun(Mod, Conf), - {?MODULE, encode_msg, [Mod, Conf]}). --define(otp_4956_mg_verify_service_change_rep_msg_fun(), - {?MODULE, otp_4956_mg_verify_service_change_rep_msg, []}). --define(otp_4956_mg_verify_pending_msg_fun(), - {?MODULE, otp_4956_mg_verify_pending_msg, []}). --define(otp_4956_mg_verify_pending_limit_msg_fun(), - {?MODULE, otp_4956_mg_verify_pending_limit_msg, []}). --else. -define(otp_4956_mg_decode_msg_fun(Mod, Conf), otp_4956_mg_decode_msg_fun(Mod, Conf)). -define(otp_4956_mg_encode_msg_fun(Mod, Conf), @@ -1596,7 +1520,6 @@ otp_4956_mgc_notify_reply_ar(Cid, TermId) -> otp_4956_mg_verify_pending_msg_fun()). -define(otp_4956_mg_verify_pending_limit_msg_fun(), otp_4956_mg_verify_pending_limit_msg_fun()). --endif. otp_4956_mg_event_sequence(text, tcp) -> DecodeFun = ?otp_4956_mg_decode_msg_fun(megaco_pretty_text_encoder, []), @@ -1642,7 +1565,6 @@ otp_4956_mg_event_sequence(text, tcp) -> ], EvSeq. --ifndef(megaco_hipe_special). otp_4956_mg_encode_msg_fun(Mod, Conf) -> fun(M) -> encode_msg(M, Mod, Conf) @@ -1652,14 +1574,11 @@ otp_4956_mg_decode_msg_fun(Mod, Conf) -> fun(M) -> decode_msg(M, Mod, Conf) end. --endif. --ifndef(megaco_hipe_special). otp_4956_mg_verify_service_change_rep_msg_fun() -> fun(M) -> otp_4956_mg_verify_service_change_rep_msg(M) end. --endif. otp_4956_mg_verify_service_change_rep_msg( #'MegacoMessage'{mess = Mess} = M) -> @@ -1687,12 +1606,10 @@ otp_4956_mg_verify_service_change_rep_msg( otp_4956_mg_verify_service_change_rep_msg(M) -> {error, {invalid_message, M}}. --ifndef(megaco_hipe_special). otp_4956_mg_verify_pending_msg_fun() -> fun(M) -> otp_4956_mg_verify_pending_msg(M) end. --endif. otp_4956_mg_verify_pending_msg(#'MegacoMessage'{mess = Mess} = M) -> io:format("otp_4956_mg_verify_pending_msg -> entry with" @@ -1710,12 +1627,10 @@ otp_4956_mg_verify_pending_msg(M) -> "~n", [M]), {error, {invalid_message, M}}. --ifndef(megaco_hipe_special). otp_4956_mg_verify_pending_limit_msg_fun() -> fun(M) -> otp_4956_mg_verify_pending_limit_msg(M) end. --endif. otp_4956_mg_verify_pending_limit_msg(#'MegacoMessage'{mess = Mess} = M) -> io:format("otp_4956_mg_verify_pending_limit_msg -> entry with" @@ -1784,29 +1699,37 @@ otp_5310(suite) -> otp_5310(doc) -> "..."; otp_5310(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, otp_5310), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_5310_mgc), + MgNode = make_node_name(pl_5310_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_otp_5310(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_otp_5310(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}], - {ok, Mgc} = - ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), @@ -1897,18 +1820,6 @@ otp_5310(Config) when is_list(Config) -> UserReps3 = ?MGC_USER_INFO(Mgc, replies), d("[MGC] UserReps3: ~p", [UserReps3]), - %% Tell MG to stop - i("[MG] stop"), - ?MG_STOP(Mg), - - %% Tell Mgc to stop - i("[MGC] stop"), - ?MGC_STOP(Mgc), - - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - i("done", []), ok. @@ -1951,29 +1862,37 @@ otp_5619(suite) -> otp_5619(doc) -> "..."; otp_5619(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(sname, "TEST"), - put(tc, otp_5619), - i("starting"), - - MgcNode = make_node_name(mgc), - MgNode = make_node_name(mg), - d("start nodes: " - "~n MgcNode: ~p" - "~n MgNode: ~p", - [MgcNode, MgNode]), - ok = ?START_NODES([MgcNode, MgNode], true), - + Cond = fun() -> ok end, + Pre = fun() -> + put(tc, ?FUNCTION_NAME), + MgcNode = make_node_name(pl_5619_mgc), + MgNode = make_node_name(pl_5619_mg), + i("try start nodes: " + "~n MgcNode: ~p" + "~n MgNode: ~p", + [MgcNode, MgNode]), + Nodes = [MgcNode, MgNode], + ok = ?START_NODES(Nodes, true), + #{nodes => Nodes} + end, + Case = fun(State) -> + do_otp_5619(State) + end, + Post = fun(#{nodes := Nodes}) -> + i("stop nodes"), + ?STOP_NODES(Nodes), + ok + end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_otp_5619(#{nodes := [MgcNode, MgNode]}) -> %% Start the MGC and MGs i("[MGC] start"), - MgcMid = {deviceName, "ctrl"}, ET = [{text, tcp}, {text, udp}, {binary, tcp}, {binary, udp}], - {ok, Mgc} = ?MGC_START(MgcNode, MgcMid, ET, [], ?MGC_VERBOSITY), + {ok, Mgc} = ?MGC_START(MgcNode, ET), i("[MG] start"), - MgMid = {deviceName, "mg"}, - MgConfig = [], - {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), + {ok, Mg} = ?MG_START(MgNode, text, tcp), d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]), d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]), @@ -2027,11 +1946,7 @@ otp_5619(Config) when is_list(Config) -> i("[MGC] stop~n"), ?MGC_STOP(Mgc), - %% Cleanup - d("stop nodes"), - ?STOP_NODES([MgcNode, MgNode]), - - i("done", []), + i("done"), ok. @@ -2160,14 +2075,12 @@ cre_megacoMessage(Mess) -> %% having received the first pending (which %% indicates that the other side _IS_ %% working on the request). --ifdef(MEGACO_TEST_CODE). init_request_timer({short, Ref}) -> {long, Ref}; init_request_timer(O) -> O. --endif. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2187,12 +2100,6 @@ decode_msg(M, Mod, Conf) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% tim() -> -%% {A,B,C} = erlang:now(), -%% A*1000000000+B*1000+(C div 1000). - - make_node_name(Name) -> case string:tokens(atom_to_list(node()), [$@]) of [_,Host] -> @@ -2216,11 +2123,31 @@ await_completion(Ids) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +try_tc(TCName, Cond, Pre, Case, Post) -> + try_tc(TCName, "TEST", ?TEST_VERBOSITY, Cond, Pre, Case, Post). + +try_tc(TCName, Name, Verbosity, Cond, Pre, Case, Post) -> + ?TRY_TC(TCName, Name, Verbosity, Cond, Pre, Case, Post). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sleep(X) -> receive after X -> ok end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-ifdef(MEGACO_TEST_CODE). +megaco_test_code() -> + ok. +-else. +megaco_test_code() -> + exit({skip, "Included only if compiled with USE_MEGACO_TEST_CODE=true"}). +-endif. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% p(F, A) -> diff --git a/lib/megaco/test/megaco_tcp_SUITE.erl b/lib/megaco/test/megaco_tcp_SUITE.erl index 43ecb335be89..300772e56485 100644 --- a/lib/megaco/test/megaco_tcp_SUITE.erl +++ b/lib/megaco/test/megaco_tcp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -318,10 +318,10 @@ start_and_stop(doc) -> start_and_stop(Config) when is_list(Config) -> Pre = fun() -> p("create nodes"), - ServerNode = make_node_name(server), - ClientNode = make_node_name(client), + ServerNode = make_node_name(t_sas_server), + ClientNode = make_node_name(t_sas_client), Nodes = [ServerNode, ClientNode], - ok = ?START_NODES(Nodes), + ok = ?START_NODES(Nodes, true), Nodes end, Case = fun(X) -> do_start_and_stop(Config, X) end, @@ -461,10 +461,10 @@ sendreceive(suite) -> sendreceive(Config) when is_list(Config) -> Pre = fun() -> p("create nodes"), - ServerNode = make_node_name(server), - ClientNode = make_node_name(client), + ServerNode = make_node_name(t_sr_server), + ClientNode = make_node_name(t_sr_client), Nodes = [ServerNode, ClientNode], - ok = ?START_NODES(Nodes), + ok = ?START_NODES(Nodes, true), Nodes end, Case = fun(X) -> do_sendreceive(Config, X) end, @@ -673,10 +673,10 @@ block_unblock(suite) -> block_unblock(Config) when is_list(Config) -> Pre = fun() -> p("create nodes"), - ServerNode = make_node_name(server), - ClientNode = make_node_name(client), + ServerNode = make_node_name(t_bb_server), + ClientNode = make_node_name(t_bb_client), Nodes = [ServerNode, ClientNode], - ok = ?START_NODES(Nodes), + ok = ?START_NODES(Nodes, true), Nodes end, Case = fun(X) -> do_block_unblock(Config, X) end, @@ -1054,14 +1054,22 @@ process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) await_server_listening(Server, Client) -> receive {listening, Server} -> - p("received listening message from server [~p] => " + p("[await-server-listening] " + "received listening message from server [~p] => " "send continue to client [~p]" "~n", [Server, Client]), Client ! {continue, self()}, ok; {'EXIT', Server, SReason} -> + p("[await-server-listening] unexpected server (~p) exit: " + "~n ~p" + "~n", [Server, SReason]), exit({server_crash, SReason}); {'EXIT', Client, CReason} -> + p("[await-server-listening] " + "unexpected client (~p) exit: " + "~n ~p" + "~n", [Client, CReason]), exit({client_crash, CReason}) after 5000 -> %% There is no normal reason why this should take any time. @@ -1076,13 +1084,22 @@ await_server_listening(Server, Client) -> await_client_blocked(Server, Client) -> receive {blocked, Client} -> - p("received blocked message from client [~p] => " + p("[await-client-blocked] " + "received blocked message from client [~p] => " "send continue to server [~p]~n", [Client, Server]), Server ! {continue, self()}, ok; {'EXIT', Client, CReason} -> + p("[await-client-blocked] " + "unexpected client (~p) exit: " + "~n ~p" + "~n", [Client, CReason]), exit({client_crash, CReason}); {'EXIT', Server, SReason} -> + p("[await-client-blocked] " + "unexpected server (~p) exit: " + "~n ~p" + "~n", [Server, SReason]), exit({server_crash, SReason}) after 5000 -> %% There is no normal reason why this should take any time. diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl index 8e7c3bec682f..727ea37e1131 100644 --- a/lib/megaco/test/megaco_test_lib.erl +++ b/lib/megaco/test/megaco_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2022. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -50,7 +50,7 @@ display_system_info/1, display_system_info/2, display_system_info/3, executor/1, executor/2, - try_tc/6, + try_tc/6, try_tc/7, prepare_test_case/5, @@ -62,7 +62,9 @@ stop_nodes/3, stop_node/3, + ping/1, ping/2, + which_inet_backend/1, is_socket_backend/1, inet_backend_opts/1, explicit_inet_backend/0, test_inet_backends/0, @@ -75,9 +77,12 @@ -export([proxy_init/2]). +%% Convenient exports... +-export([analyze_and_print_host_info/0]). + -include("megaco_test_lib.hrl"). --record('REASON', {mod, line, desc}). +%% -record('REASON', {mod, line, desc}). %% ---------------------------------------------------------------- @@ -363,19 +368,11 @@ display_system_info(WhenStr, ModFuncStr) -> %% Stores the result in the process dictionary if mismatch error(Actual, Mod, Line) -> - global:send(megaco_global_logger, {failed, Mod, Line}), log(" Bad result: ~p~n", [Actual], Mod, Line), Label = lists:concat([Mod, "(", Line, ") unexpected result"]), megaco:report_event(60, Mod, Mod, Label, [{line, Mod, Line}, {error, Actual}]), - case global:whereis_name(megaco_test_case_sup) of - undefined -> - ignore; - Pid -> - Fail = #'REASON'{mod = Mod, line = Line, desc = Actual}, - Pid ! {fail, self(), Fail} - end, - Actual. + exit(Actual). log(Format, Args, Mod, Line) -> case global:whereis_name(megaco_global_logger) of @@ -717,43 +714,421 @@ num_schedulers_to_factor() -> end. - +ts_extra_platform_label() -> + case os:getenv("TS_EXTRA_PLATFORM_LABEL") of + false -> "-"; + Val -> Val + end. + +ts_scale_factor() -> + case timetrap_scale_factor() of + N when is_integer(N) andalso (N > 0) -> + N - 1; + _ -> + 0 + end. + +simplify_label("Systemtap" ++ _) -> + {host, systemtap}; +simplify_label("Meamax" ++ _) -> + {host, meamax}; +simplify_label("Cover" ++ _) -> + {host, cover}; +simplify_label(Label) -> + case string:find(string:to_lower(Label), "docker") of + "docker" ++ _ -> + docker; + _ -> + {host, undefined} + end. + +label2factor(docker) -> + 4; +label2factor({host, meamax}) -> + 2; +label2factor({host, cover}) -> + 6; +label2factor({host, _}) -> + 0. + linux_which_distro(Version) -> - case file:read_file_info("/etc/issue") of + Label = ts_extra_platform_label(), + Checks = + [fun() -> do_linux_which_distro_os_release(Version, Label) end, + fun() -> do_linux_which_distro_suse_release(Version, Label) end, + fun() -> do_linux_which_distro_fedora_release(Version, Label) end, + fun() -> do_linux_which_distro_issue(Version, Label) end], + try linux_which_distro("", Version, Label, Checks) + catch + throw:{distro, Distro} -> + Distro + end. + +linux_which_distro("", Version, Label, []) -> + io:format("Linux: ~s" + "~n Label: ~s" + "~n Product Name: ~s" + "~n", [Version, Label, + linux_product_name()]), + {other, simplify_label(Label)}; +linux_which_distro(DestroStr, Version, Label, []) -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Label: ~s" + "~n Product Name: ~s" + "~n", [Version, DestroStr, Label, + linux_product_name()]), + {other, simplify_label(Label)}; +linux_which_distro(Default, Version, Label, [Check|Checks]) -> + try Check() of + DistroStr when is_list(DistroStr) -> + linux_which_distro(DistroStr, Version, Label, Checks); + retry -> + linux_which_distro(Default, Version, Label, Checks); + {error, _Reason} -> + linux_which_distro(Default, Version, Label, Checks) + catch + throw:{error, _Reason} -> + linux_which_distro(Default, Version, Label, Checks) + end. + + +do_linux_which_distro_os_release(Version, Label) -> + case file:read_file_info("/etc/os-release") of + {ok, _} -> + %% We want to 'catch' if our processing is wrong, + %% that's why we catch and re-throw the distro. + %% Actual errors will be returned as 'ignore'. + try + begin + Info = linux_process_os_release(), + {value, {_, DistroStr}} = lists:keysearch(name, 1, Info), + {value, {_, VersionNo}} = lists:keysearch(version, 1, Info), + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, VersionNo, Label, + linux_product_name()]), + throw({distro, + {linux_distro_str_to_distro_id(DistroStr), + simplify_label(Label)}}) + end + catch + throw:{distro, _} = DISTRO -> + throw(DISTRO); + _:_ -> + retry + end; + _ -> + retry + end. + + +linux_process_os_release() -> + %% Read the "raw" file + Raw = os:cmd("cat /etc/os-release"), + %% Split it into lines + Lines1 = string:tokens(Raw, [$\n]), + %% Just in case, skip any lines starting with '#'. + Lines2 = linux_process_os_release1(Lines1), + %% Each (remaining) line *should* be: = + %% Both sides will be strings, the value side will be a quoted string... + %% Convert those into a 2-tuple list: [{Tag, Value}] + linux_process_os_release2(Lines2). + +linux_process_os_release1(Lines) -> + linux_process_os_release1(Lines, []). + +linux_process_os_release1([], Acc) -> + lists:reverse(Acc); +linux_process_os_release1([H|T], Acc) -> + case H of + "#" ++ _ -> + linux_process_os_release1(T, Acc); + _ -> + linux_process_os_release1(T, [H|Acc]) + end. + +linux_process_os_release2(Lines) -> + linux_process_os_release2(Lines, []). + +linux_process_os_release2([], Acc) -> + lists:reverse(Acc); +linux_process_os_release2([H|T], Acc) -> + case linux_process_os_release3(H) of + {value, Value} -> + linux_process_os_release2(T, [Value|Acc]); + false -> + linux_process_os_release2(T, Acc) + end. + +linux_process_os_release3(H) -> + case [string:strip(S) || S <- string:tokens(H, [$=])] of + [Tag, Value] -> + Tag2 = list_to_atom(string:to_lower(Tag)), + Value2 = string:strip(Value, both, $"), + linux_process_os_release4(Tag2, Value2); + _ -> + false + end. + +linux_process_os_release4(name = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(version = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(version_id = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(id = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(pretty_name = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(_Tag, _Value) -> + false. + +linux_distro_str_to_distro_id("Debian" ++ _) -> + debian; +linux_distro_str_to_distro_id("Fedora" ++ _) -> + fedora; +linux_distro_str_to_distro_id("Linux Mint" ++ _) -> + linux_mint; +linux_distro_str_to_distro_id("MontaVista" ++ _) -> + montavista; +linux_distro_str_to_distro_id("openSUSE" ++ _) -> + suse; +linux_distro_str_to_distro_id("SLES" ++ _) -> + sles; +linux_distro_str_to_distro_id("Ubuntu" ++ _) -> + ubuntu; +linux_distro_str_to_distro_id("Wind River Linux" ++ _) -> + wind_river; +linux_distro_str_to_distro_id("Yellow Dog" ++ _) -> + yellow_dog; +linux_distro_str_to_distro_id(X) -> + X. + + +do_linux_which_distro_fedora_release(Version, Label) -> + %% Check if fedora + case file:read_file_info("/etc/fedora-release") of {ok, _} -> case [string:trim(S) || - S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of - [DistroStr|_] -> + S <- string:tokens(os:cmd("cat /etc/fedora-release"), + [$\n])] of + [DistroStr | _] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]); + _ -> io:format("Linux: ~s" - "~n ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" "~n", - [Version, DistroStr]), + [Version, "Fedora", Label, + linux_product_name()]) + end, + throw({distro, {fedora, simplify_label(Label)}}); + _ -> + throw({error, not_found}) + end. + +do_linux_which_distro_suse_release(Version, Label) -> + %% Check if its a SuSE + case file:read_file_info("/etc/SUSE-brand") of + {ok, _} -> + case file:read_file_info("/etc/SuSE-release") of + {ok, _} -> + case [string:trim(S) || + S <- string:tokens(os:cmd("cat /etc/SuSE-release"), + [$\n])] of + ["SUSE Linux Enterprise Server" ++ _ = DistroStr | _] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, {sles, simplify_label(Label)}}); + [DistroStr | _] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, "SuSE", Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}) + end; + _ -> + case string:tokens(os:cmd("cat /etc/SUSE-brand"), [$\n]) of + ["SLE" = DistroStr, VERSION | _] -> + case [string:strip(S) || + S <- string:tokens(VERSION, [$=])] of + ["VERSION", VersionNo] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, + DistroStr, VersionNo, + Label, + linux_product_name()]), + throw({distro, + {sles, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {sles, simplify_label(Label)}}) + end; + ["openSUSE" = DistroStr, VERSION | _] -> + case [string:strip(S) || + S <- string:tokens(VERSION, [$=])] of + ["VERSION", VersionNo] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, + DistroStr, VersionNo, + Label, + linux_product_name()]), + throw({distro, + {suse, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {suse, simplify_label(Label)}}) + end; + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, "Unknown SUSE", Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}) + end + end; + _ -> + throw({error, not_found}) + end. + +do_linux_which_distro_issue(Version, Label) -> + case file:read_file_info("/etc/issue") of + {ok, _} -> + case [string:trim(S) || + S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of + [DistroStr | _] -> case DistroStr of "Wind River Linux" ++ _ -> - wind_river; + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {wind_river, simplify_label(Label)}}); "MontaVista" ++ _ -> - montavista; + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {montavista, simplify_label(Label)}}); "Yellow Dog" ++ _ -> - yellow_dog; + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {yellow_dog, simplify_label(Label)}}); + "Ubuntu" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {ubuntu, simplify_label(Label)}}); + "Linux Mint" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {linux_mint, simplify_label(Label)}}); + "Debian" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {debian, simplify_label(Label)}}); _ -> - other + DistroStr end; X -> - io:format("Linux: ~s" - "~n ~p" - "~n", - [Version, X]), - other + X end; _ -> - io:format("Linux: ~s" - "~n", [Version]), - other + throw({error, not_found}) end. + - analyze_and_print_linux_host_info(Version) -> - Distro = linux_which_distro(Version), + {Distro, Label} = linux_which_distro(Version), + %% 'VirtFactor' will be 0 unless virtual + VirtFactor = linux_virt_factor(), Factor = case (catch linux_which_cpuinfo(Distro)) of {ok, {CPU, BogoMIPS}} -> @@ -765,14 +1140,18 @@ analyze_and_print_linux_host_info(Version) -> if (BogoMIPS > 50000) -> 1; - (BogoMIPS > 30000) -> + (BogoMIPS > 40000) -> 2; - (BogoMIPS > 10000) -> + (BogoMIPS > 30000) -> 3; - (BogoMIPS > 5000) -> + (BogoMIPS > 20000) -> + 4; + (BogoMIPS > 10000) -> 5; - (BogoMIPS > 3000) -> + (BogoMIPS > 5000) -> 8; + (BogoMIPS > 3000) -> + 12; true -> 10 end; @@ -805,21 +1184,53 @@ analyze_and_print_linux_host_info(Version) -> _ -> 5 end, + AddLabelFactor = label2factor(Label), %% Check if we need to adjust the factor because of the memory - try linux_which_meminfo() of - AddFactor -> - {Factor + AddFactor, []} - catch - _:_:_ -> - {Factor, []} - end. + AddMemFactor = try linux_which_meminfo() + catch _:_:_ -> 0 + end, + TSScaleFactor = case timetrap_scale_factor() of + N when is_integer(N) andalso (N > 0) -> + N - 1; + _ -> + 0 + end, + io:format("Factor calc:" + "~n Base Factor: ~w" + "~n Label Factor: ~w" + "~n Mem Factor: ~w" + "~n Virtual Factor: ~w" + "~n TS Scale Factor: ~w" + "~n", [Factor, AddLabelFactor, AddMemFactor, VirtFactor, + TSScaleFactor]), + {Factor + AddLabelFactor + AddMemFactor + VirtFactor + TSScaleFactor, + [{label, Label}]}. + + +linux_virt_factor() -> + linux_virt_factor(linux_product_name()). + +linux_virt_factor("VMware" ++ _) -> + 2; +linux_virt_factor("VirtualBox" ++ _) -> + 4; +linux_virt_factor(_) -> + 0. linux_cpuinfo_lookup(Key) when is_list(Key) -> linux_info_lookup(Key, "/proc/cpuinfo"). linux_cpuinfo_bogomips() -> - case linux_cpuinfo_lookup("bogomips") of + case linux_cpuinfo_bogomips("bogomips") of + "-" -> + linux_cpuinfo_bogomips("BogoMIPS"); + Res -> + Res + end. + +linux_cpuinfo_bogomips(Key) -> + case linux_cpuinfo_lookup(Key) of [] -> "-"; BMips when is_list(BMips) -> @@ -864,7 +1275,14 @@ linux_cpuinfo_model() -> [M] -> M; _ -> - "-" + %% Note that some distros/platforms, + %% the first char is Capital, that is: Model... + case linux_cpuinfo_lookup("Model") of + [M] -> + M; + _ -> + "-" + end end. linux_cpuinfo_platform() -> @@ -907,6 +1325,14 @@ linux_cpuinfo_processor() -> "-" end. +linux_cpuinfo_machine() -> + case linux_cpuinfo_lookup("machine") of + [M] -> + M; + _ -> + "-" + end. + linux_cpuinfo_clock() -> %% This is written as: "3783.000000MHz" %% So, check unit MHz (handle nothing else). @@ -991,6 +1417,52 @@ linux_which_cpuinfo(wind_river) -> {ok, {CPU, BMips}} end; +linux_which_cpuinfo(Distro) when (Distro =:= debian) orelse + (Distro =:= fedora) orelse + (Distro =:= linux_mint) orelse + (Distro =:= sles) orelse + (Distro =:= suse) orelse + (Distro =:= ubuntu) orelse + (Distro =:= other) -> + CPU = + case linux_cpuinfo_model_name() of + "-" -> + %% This is for POWER9 + case linux_cpuinfo_cpu() of + "POWER9" ++ _ = PowerCPU -> + Machine = + case linux_cpuinfo_machine() of + "-" -> + ""; + M -> + " (" ++ M ++ ")" + end, + PowerCPU ++ Machine; + _X -> + %% ARM (at least some distros...) + case linux_cpuinfo_processor() of + "-" -> + case linux_cpuinfo_model() of + "-" -> + %% Ok, we give up + throw(noinfo); + Model -> + Model + end; + Proc -> + Proc + end + end; + ModelName -> + ModelName + end, + case linux_cpuinfo_bogomips() of + "-" -> + {ok, CPU}; + BMips -> + {ok, {CPU, BMips}} + end; + linux_which_cpuinfo(other) -> %% Check for x86 (Intel or AMD or Power) CPU = @@ -1072,6 +1544,22 @@ linux_which_meminfo() -> end. +linux_product_name() -> + ProductNameFile = "/sys/devices/virtual/dmi/id/product_name", + case file:read_file_info(ProductNameFile) of + {ok, _} -> + case os:cmd("cat " ++ ProductNameFile) of + false -> + "-"; + Info -> + string:trim(Info) + end; + _ -> + "-" + end. + + + %% Just to be clear: This is ***not*** scientific... analyze_and_print_openbsd_host_info(Version) -> io:format("OpenBSD:" @@ -1120,45 +1608,78 @@ analyze_and_print_openbsd_host_info(Version) -> "~n", [CPU, CPUSpeed, NCPU, Memory]), CPUFactor = if - (CPUSpeed =:= -1) -> - 1; - (CPUSpeed >= 2000) -> + (CPUSpeed >= 3000) -> if - (NCPU >= 4) -> + (NCPU >= 8) -> 1; + (NCPU >= 6) -> + 2; + (NCPU >= 4) -> + 3; (NCPU >= 2) -> + 4; + true -> + 10 + end; + (CPUSpeed >= 2000) -> + if + (NCPU >= 8) -> 2; + (NCPU >= 6) -> + 3; + (NCPU >= 4) -> + 4; + (NCPU >= 2) -> + 5; true -> - 3 + 12 + end; + (CPUSpeed >= 1000) -> + if + (NCPU >= 8) -> + 3; + (NCPU >= 6) -> + 4; + (NCPU >= 4) -> + 5; + (NCPU >= 2) -> + 6; + true -> + 14 end; true -> if + (NCPU >= 8) -> + 4; + (NCPU >= 6) -> + 6; (NCPU >= 4) -> - 2; + 8; (NCPU >= 2) -> - 3; + 10; true -> - 4 + 20 end end, MemAddFactor = if - (Memory =:= -1) -> + (Memory >= 16777216) -> 0; (Memory >= 8388608) -> - 0; - (Memory >= 4194304) -> 1; + (Memory >= 4194304) -> + 3; (Memory >= 2097152) -> - 2; + 5; true -> - 3 + 10 end, {CPUFactor + MemAddFactor, []} end catch _:_:_ -> - {5, []} + io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), + {10, []} end. @@ -1449,47 +1970,57 @@ analyze_and_print_darwin_host_info(Version) -> %% we need to find some other way to find some info... %% Also, I suppose its possible that we for some other %% reason *fail* to get the info... - case analyze_darwin_software_info() of - [] -> - io:format("Darwin:" - "~n Version: ~s" - "~n Num Online Schedulers: ~s" - "~n", [Version, str_num_schedulers()]), - {num_schedulers_to_factor(), []}; - SwInfo when is_list(SwInfo) -> - SystemVersion = analyze_darwin_sw_system_version(SwInfo), - KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), - HwInfo = analyze_darwin_hardware_info(), - ModelName = analyze_darwin_hw_model_name(HwInfo), - ModelId = analyze_darwin_hw_model_identifier(HwInfo), - ProcName = analyze_darwin_hw_processor_name(HwInfo), - ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), - NumProc = analyze_darwin_hw_number_of_processors(HwInfo), - NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), - Memory = analyze_darwin_hw_memory(HwInfo), - io:format("Darwin:" - "~n System Version: ~s" - "~n Kernel Version: ~s" - "~n Model: ~s (~s)" - "~n Processor: ~s (~s, ~s, ~s)" - "~n Memory: ~s" - "~n Num Online Schedulers: ~s" - "~n", [SystemVersion, KernelVersion, - ModelName, ModelId, - ProcName, ProcSpeed, NumProc, NumCores, - Memory, - str_num_schedulers()]), - CPUFactor = analyze_darwin_cpu_to_factor(ProcName, - ProcSpeed, - NumProc, - NumCores), - MemFactor = analyze_darwin_memory_to_factor(Memory), - if (MemFactor =:= 1) -> - {CPUFactor, []}; - true -> - {CPUFactor + MemFactor, []} - end - end. + Label = ts_extra_platform_label(), + {BaseFactor, MemFactor} = + case analyze_darwin_software_info() of + [] -> + io:format("Darwin:" + "~n Version: ~s" + "~n Num Online Schedulers: ~s" + "~n TS Extra Platform Label: ~s" + "~n", [Version, str_num_schedulers(), Label]), + {num_schedulers_to_factor(), 1}; + SwInfo when is_list(SwInfo) -> + SystemVersion = analyze_darwin_sw_system_version(SwInfo), + KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), + HwInfo = analyze_darwin_hardware_info(), + ModelName = analyze_darwin_hw_model_name(HwInfo), + ModelId = analyze_darwin_hw_model_identifier(HwInfo), + {Processor, CPUFactor} = analyze_darwin_hw_processor(HwInfo), + Memory = analyze_darwin_hw_memory(HwInfo), + io:format("Darwin:" + "~n System Version: ~s" + "~n Kernel Version: ~s" + "~n Model: ~s (~s)" + "~n Processor: ~s" + "~n Memory: ~s" + "~n Num Online Schedulers: ~s" + "~n TS Extra Platform Label: ~s" + "~n~n", + [SystemVersion, KernelVersion, + ModelName, ModelId, + Processor, + Memory, + str_num_schedulers(), Label]), + {CPUFactor, analyze_darwin_memory_to_factor(Memory)} + end, + AddLabelFactor = label2factor(simplify_label(Label)), + AddMemFactor = if + (MemFactor > 0) -> + MemFactor - 1; + true -> + 0 + end, + TSScaleFactor = ts_scale_factor(), + io:format("Factor calc:" + "~n Base Factor: ~w" + "~n Label Factor: ~w" + "~n Mem Factor: ~w" + "~n TS Scale Factor: ~w" + "~n~n", + [BaseFactor, AddLabelFactor, AddMemFactor, TSScaleFactor]), + {BaseFactor + AddLabelFactor + AddMemFactor + TSScaleFactor, + [{label, Label}]}. analyze_darwin_sw_system_version(SwInfo) -> proplists:get_value("system version", SwInfo, "-"). @@ -1500,12 +2031,38 @@ analyze_darwin_sw_kernel_version(SwInfo) -> analyze_darwin_software_info() -> analyze_darwin_system_profiler("SPSoftwareDataType"). +analyze_darwin_hw_chip(HwInfo) -> + proplists:get_value("chip", HwInfo, "-"). + analyze_darwin_hw_model_name(HwInfo) -> proplists:get_value("model name", HwInfo, "-"). analyze_darwin_hw_model_identifier(HwInfo) -> proplists:get_value("model identifier", HwInfo, "-"). +analyze_darwin_hw_processor(HwInfo) -> + case analyze_darwin_hw_processor_name(HwInfo) of + "-" -> % Maybe Apple Chip + case analyze_darwin_hw_chip(HwInfo) of + "-" -> + "-"; + Chip -> + NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), + CPUFactor = analyze_darwin_cpu_to_factor(Chip, NumCores), + {f("~s [~s]", [Chip, NumCores]), CPUFactor} + end; + ProcName -> + ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), + NumProc = analyze_darwin_hw_number_of_processors(HwInfo), + NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), + CPUFactor = analyze_darwin_cpu_to_factor(ProcName, + ProcSpeed, + NumProc, + NumCores), + {f("~s [~s, ~s, ~s]", + [ProcName, ProcSpeed, NumProc, NumCores]), CPUFactor} + end. + analyze_darwin_hw_processor_name(HwInfo) -> case proplists:get_value("processor name", HwInfo, "-") of "-" -> @@ -1540,17 +2097,25 @@ analyze_darwin_hardware_info() -> %% "Key: Value1:Value2" analyze_darwin_system_profiler(DataType) -> %% First, make sure the program actually exist: - case os:cmd("which system_profiler") of + case string:trim(os:cmd("which system_profiler")) of [] -> - []; - _ -> - D0 = os:cmd("system_profiler " ++ DataType), - D1 = string:tokens(D0, [$\n]), - D2 = [string:trim(S1) || S1 <- D1], - D3 = [string:tokens(S2, [$:]) || S2 <- D2], - analyze_darwin_system_profiler2(D3) + case string:trim(os:cmd("which /usr/sbin/system_profiler")) of + [] -> + []; + Cmd1 -> + analyze_darwin_system_profiler(Cmd1, DataType) + end; + Cmd2 -> + analyze_darwin_system_profiler(Cmd2, DataType) end. +analyze_darwin_system_profiler(Cmd, DataType) -> + D0 = os:cmd(Cmd ++ " " ++ DataType), + D1 = string:tokens(D0, [$\n]), + D2 = [string:trim(S1) || S1 <- D1], + D3 = [string:tokens(S2, [$:]) || S2 <- D2], + analyze_darwin_system_profiler2(D3). + analyze_darwin_system_profiler2(L) -> analyze_darwin_system_profiler2(L, []). @@ -1600,6 +2165,12 @@ analyze_darwin_memory_to_factor(Mem) -> end. +analyze_darwin_cpu_to_factor("Apple" ++ _ = _Chip, _NumCores) -> + 1; +analyze_darwin_cpu_to_factor(_Chip, _NumCores) -> + 8. + + %% The speed is a string: " " %% the speed may be a float, which we transforms into an integer of MHz. %% To calculate a factor based on processor speed, number of procs @@ -2133,68 +2704,199 @@ executor(Fun, Timeout) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -try_tc(TCName, Name, Verbosity, Pre, Case, Post) - when is_function(Pre, 0) andalso +try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> + Cond = fun() -> ok end, + try_tc(TCName, Name, Verbosity, Cond, Pre, Case, Post). + +try_tc(TCName, Name, Verbosity, Cond, Pre, Case, Post) + when is_function(Cond, 0) andalso + is_function(Pre, 0) andalso is_function(Case, 1) andalso is_function(Post, 1) -> - process_flag(trap_exit, true), - put(verbosity, Verbosity), - put(sname, Name), - put(tc, TCName), - p("try_tc -> starting: try pre"), - try Pre() of - State -> - p("try_tc -> pre done: try test case"), - try Case(State) of - Res -> - p("try_tc -> test case done: try post"), - _ = executor(fun() -> Post(State) end), - p("try_tc -> done"), - Res + tc_begin(TCName, Name, Verbosity), + try Cond() of + ok -> + tc_print("starting: try pre"), + try Pre() of + State -> + tc_print("pre done: try test case"), + try + begin + Res = Case(State), + sleep(seconds(1)), + tc_print("test case done: try post"), + _ = executor(fun() -> + put(verbosity, Verbosity), + put(sname, Name), + put(tc, TCName), + Post(State) + end), + tc_end("ok"), + Res + end + catch + C:{skip, _} = SKIP:_ when (C =:= throw) orelse + (C =:= exit) -> + tc_print("test case (~w) skip: try post", [C]), + _ = executor(fun() -> + put(verbosity, Verbosity), + put(sname, Name), + put(tc, TCName), + Post(State) + end), + tc_end( f("skipping(caught,~w,tc)", [C]) ), + SKIP; + C:E:S -> + %% We always check the system events + %% before we accept a failure. + %% We do *not* run the Post here because it might + %% generate sys events itself... + p("try_tc -> test case failed: try post"), + _ = executor(fun() -> Post(State) end), + case megaco_test_global_sys_monitor:events() of + [] -> + tc_print("test case failed: try post"), + _ = executor(fun() -> + put(verbosity, + Verbosity), + put(sname, Name), + put(tc, TCName), + Post(State) + end), + tc_end( f("failed(caught,~w,tc)", [C]) ), + erlang:raise(C, E, S); + SysEvs -> + tc_print("System Events " + "received during tc: " + "~n ~p" + "~nwhen tc failed:" + "~n C: ~p" + "~n E: ~p" + "~n S: ~p", + [SysEvs, C, E, S]), + _ = executor(fun() -> + put(verbosity, + Verbosity), + put(sname, Name), + put(tc, TCName), + Post(State) + end), + tc_end( f("skipping(catched-sysevs,~w,tc)", + [C]) ), + SKIP = + {skip, "TC failure with system events"}, + SKIP + end + end catch - throw:{skip, _} = SKIP:_ -> - p("try_tc -> test case (throw) skip: try post"), - _ = executor(fun() -> Post(State) end), - p("try_tc -> test case (throw) skip: done"), - SKIP; - exit:{skip, _} = SKIP:_ -> - p("try_tc -> test case (exit) skip: try post"), - _ = executor(fun() -> Post(State) end), - p("try_tc -> test case (exit) skip: done"), + C:{skip, _} = SKIP:_ when (C =:= throw) orelse + (C =:= exit) -> + tc_end( f("skipping(caught,~w,tc-pre)", [C]) ), SKIP; C:E:S -> - p("try_tc -> test case failed: try post"), - _ = executor(fun() -> Post(State) end), case megaco_test_global_sys_monitor:events() of [] -> - p("try_tc -> test case failed: done"), - exit({case_catched, C, E, S}); + tc_print("tc-pre failed: auto-skip" + "~n C: ~p" + "~n E: ~p" + "~n S: ~p", + [C, E, S]), + tc_end( f("auto-skip(caught,~w,tc-pre)", [C]) ), + SKIP = {skip, f("TC-Pre failure (~w)", [C])}, + SKIP; SysEvs -> - p("try_tc -> test case failed with system event(s): " - "~n ~p", [SysEvs]), - {skip, "TC failure with system events"} + tc_print("System Events received: " + "~n ~p" + "~nwhen tc-pre failed:" + "~n C: ~p" + "~n E: ~p" + "~n S: ~p", + [SysEvs, C, E, S], "", ""), + tc_end( f("skipping(catched-sysevs,~w,tc-pre)", + [C]) ), + SKIP = {skip, "TC-Pre failure with system events"}, + SKIP end - end - catch - throw:{skip, _} = SKIP:_ -> - p("try_tc -> pre (throw) skip"), + end; + {skip, _} = SKIP -> + tc_end("skipping(cond)"), SKIP; - exit:{skip, _} = SKIP:_ -> - p("try_tc -> pre (exit) skip"), + {error, Reason} -> + tc_end("failed(cond)"), + exit({tc_cond_failed, Reason}) + catch + C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> + tc_end( f("skipping(caught,~w,cond)", [C]) ), SKIP; C:E:S -> + %% We always check the system events before we accept a failure case megaco_test_global_sys_monitor:events() of [] -> - p("try_tc -> pre failed: done"), - exit({pre_catched, C, E, S}); + tc_end( f("failed(caught,~w,cond)", [C]) ), + erlang:raise(C, E, S); SysEvs -> - p("try_tc -> pre failed with system event(s): " - "~n ~p", [SysEvs]), - {skip, "TC pre failure with system events"} + tc_print("System Events received: " + "~n ~p", [SysEvs], "", ""), + tc_end( f("skipping(catched-sysevs,~w,cond)", [C]) ), + SKIP = {skip, "TC cond failure with system events"}, + SKIP end end. +tc_set_name(N) when is_atom(N) -> + tc_set_name(atom_to_list(N)); +tc_set_name(N) when is_list(N) -> + put(tc_name, N). + +tc_get_name() -> + get(tc_name). + +tc_begin(TC, Name, Verbosity) -> + OldVal = process_flag(trap_exit, true), + put(old_trap_exit, OldVal), + tc_set_name(TC), + put(sname, Name), + put(verbosity, Verbosity), + tc_print("begin ***", + "~n----------------------------------------------------~n", ""). + +tc_end(Result) when is_list(Result) -> + OldVal = erase(old_trap_exit), + process_flag(trap_exit, OldVal), + tc_print("done: ~s", [Result], + "", "----------------------------------------------------~n~n"), + ok. + +tc_print(F) -> + tc_print(F, [], "", ""). + +tc_print(F, A) -> + tc_print(F, A, "", ""). + +tc_print(F, Before, After) -> + tc_print(F, [], Before, After). + +tc_print(F, A, Before, After) -> + Name = tc_which_name(), + FStr = f("*** [~s][~s][~p] " ++ F ++ "~n", + [formated_timestamp(), Name, self() | A]), + io:format(user, Before ++ FStr ++ After, []), + io:format(standard_io, Before ++ FStr ++ After, []). + +tc_which_name() -> + case tc_get_name() of + undefined -> + case get(sname) of + undefined -> + ""; + SName when is_list(SName) -> + SName + end; + Name when is_list(Name) -> + Name + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2234,20 +2936,24 @@ lookup_config(Key,Config) -> [] end. -mk_nodes(N) when (N > 0) -> - mk_nodes(N, []). -mk_nodes(0, Nodes) -> +mk_nodes(1 = _N) -> + [node()]; +mk_nodes(N) when is_integer(N) andalso (N > 1) -> + OwnNode = node(), + [Name0, Host] = node_to_name_and_host(OwnNode), + Uniq = erlang:unique_integer([positive]), + Name = + list_to_atom(lists:concat([Name0, "_", integer_to_list(Uniq)])), + [OwnNode | mk_nodes(N-1, Name, Host, [])]. + +mk_nodes(0, _BaseName, _Host, Nodes) -> Nodes; -mk_nodes(N, []) -> - mk_nodes(N - 1, [node()]); -mk_nodes(N, Nodes) when N > 0 -> - Head = hd(Nodes), - [Name, Host] = node_to_name_and_host(Head), - Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. - -mk_node(N, Name, Host) -> - list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). +mk_nodes(N, BaseName, Host, Nodes) -> + mk_nodes(N-1, BaseName, Host, [mk_node(N, BaseName, Host)|Nodes]). + +mk_node(N, BaseName, Host) -> + list_to_atom(lists:concat([BaseName, "_", integer_to_list(N), "@", Host])). %% Returns [Name, Host] node_to_name_and_host(Node) -> @@ -2284,10 +2990,11 @@ start_node(Node, Force, File, Line) start_node(Node, Force, false, File, Line). start_node(Node, Force, Retry, File, Line) -> - case net_adm:ping(Node) of + p("start_node -> check if node ~p already running", [Node]), + case ping(Node, ?SECS(5)) of %% Do not require a *new* node pong when (Force =:= false) -> - p("node ~p already running", [Node]), + p("start_node -> node ~p already running", [Node]), ok; %% Do require a *new* node, so kill this one and try again @@ -2308,26 +3015,40 @@ start_node(Node, Force, Retry, File, Line) -> % Not (yet) running pang -> + p("start_node -> node ~p not running - create args", [Node]), [Name, Host] = node_to_name_and_host(Node), Pa = filename:dirname(code:which(?MODULE)), - Args = " -pa " ++ Pa ++ + Args0 = " -pa " ++ Pa ++ " -s " ++ atom_to_list(megaco_test_sys_monitor) ++ " start" ++ " -s global sync", - p("try start node ~p", [Node]), - case slave:start_link(Host, Name, Args) of - {ok, NewNode} when NewNode =:= Node -> + Args = string:tokens(Args0, [$\ ]), + p("start_node -> try start node ~p", [Node]), + PeerOpts = #{name => Name, + host => Host, + args => Args}, + case peer:start(PeerOpts) of + {ok, _Peer, NewNode} when NewNode =:= Node -> p("node ~p started - now set path, cwd and sync", [Node]), - Path = code:get_path(), + Path = code:get_path(), {ok, Cwd} = file:get_cwd(), - true = rpc:call(Node, code, set_path, [Path]), - ok = rpc:call(Node, file, set_cwd, [Cwd]), - true = rpc:call(Node, code, set_path, [Path]), - {_, []} = rpc:multicall(global, sync, []), + true = rpc:call(Node, code, set_path, [Path]), + ok = rpc:call(Node, file, set_cwd, [Cwd]), + true = rpc:call(Node, code, set_path, [Path]), + {_, []} = rpc:multicall(global, sync, []), ok; + {ok, _Peer, NewNode} -> + e("wrong node started: " + "~n Expected: ~p" + "~n Got: ~p", [Node, NewNode]), + stop_node(NewNode), + fatal_skip({invalid_node_start, NewNode, Node}, File, Line); Other -> e("failed starting node ~p: ~p", [Node, Other]), - fatal_skip({cannot_start_node, Node, Other}, File, Line) - end + fatal_skip({cannot_start_node, Node, Other}, File, Line) + end; + + timeout -> + fatal_skip({ping_timeout, Node}, File, Line) end. @@ -2379,12 +3100,24 @@ stop_node(Node) -> end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +timetrap_scale_factor() -> + case (catch test_server:timetrap_scale_factor()) of + {'EXIT', _} -> + 1; + N -> + N + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% f(F, A) -> lists:flatten(io_lib:format(F, A)). +e(F) -> + e(F, []). e(F, A) -> print("ERROR", F, A). @@ -2418,25 +3151,17 @@ explicit_inet_backend() -> end. test_inet_backends() -> - case init:get_argument(megaco) of - {ok, SnmpArgs} when is_list(SnmpArgs) -> - test_inet_backends(SnmpArgs, atom_to_list(?FUNCTION_NAME)); - error -> - false - end. - -test_inet_backends([], _) -> - false; -test_inet_backends([[Key, Val] | _], Key) -> - case list_to_atom(string:to_lower(Val)) of - Bool when is_boolean(Bool) -> - Bool; + case application:get_all_env(megaco) of + Env when is_list(Env) -> + case lists:keysearch(test_inet_backends, 1, Env) of + {value, {test_inet_backends, true}} -> + true; + _ -> + false + end; _ -> - false - end; -test_inet_backends([_|Args], Key) -> - test_inet_backends(Args, Key). - + false + end. inet_backend_opts(Config) when is_list(Config) -> case lists:keysearch(socket_create_opts, 1, Config) of @@ -2446,13 +3171,16 @@ inet_backend_opts(Config) when is_list(Config) -> [] end. -is_socket_backend(Config) when is_list(Config) -> +which_inet_backend(Config) -> case lists:keysearch(socket_create_opts, 1, Config) of - {value, {socket_create_opts, [{inet_backend, socket}]}} -> - true; + {value, {socket_create_opts, [{inet_backend, Backend}]}} -> + Backend; _ -> - false + default end. + +is_socket_backend(Config) when is_list(Config) -> + (which_inet_backend(Config) =:= socket). open(Config, Pid, Opts) @@ -2470,3 +3198,49 @@ connect(Config, Ref, Opts) InetBackendOpts = inet_backend_opts(Config), megaco_tcp:connect(Ref, InetBackendOpts ++ Opts). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% The point of this cludge is to make it possible to specify a +%% timeout for the ping, since it can actually hang. +ping(Node) -> + ping(Node, infinity). + +ping(Node, Timeout) + when is_atom(Node) andalso + ((is_integer(Timeout) andalso (Timeout > 0)) orelse + (Timeout =:= infinity)) -> + {Pid, Mon} = erlang:spawn_monitor(fun() -> exit(net_adm:ping(Node)) end), + receive + {'DOWN', Mon, process, Pid, Info} when (Info =:= pong) orelse + (Info =:= pang) -> + Info; + {'DOWN', Mon, process, Pid, Info} -> + e("unexpected ping result: " + "~n ~p", [Info]), + exit({unexpected_ping_result, Info}); + {'EXIT', TCPid, {timetrap_timeout, TCTimeout, TCSTack}} -> + p("received timetrap timeout (~w ms) from ~p => Kill ping process" + "~n TC Stack: ~p", [TCTimeout, TCPid, TCSTack]), + kill_and_wait(Pid, Mon, "ping"), + timeout + after Timeout -> + e("unexpected ping timeout"), + kill_and_wait(Pid, Mon, "ping"), + timeout + end. + + +kill_and_wait(Pid, MRef, PStr) -> + exit(Pid, kill), + %% We do this in case we get some info about 'where' + %% the process is hanging... + receive + {'DOWN', MRef, process, Pid, Info} -> + p("~s process terminated (forced) with" + "~n ~p", [PStr, Info]), + ok + after 100 -> % Give it a second... + ok + end. + diff --git a/lib/megaco/test/megaco_test_lib.hrl b/lib/megaco/test/megaco_test_lib.hrl index 43a1bfd0f8fb..46bffdf81807 100644 --- a/lib/megaco/test/megaco_test_lib.hrl +++ b/lib/megaco/test/megaco_test_lib.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2022. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -90,11 +90,14 @@ -define(TRY_TC(TCN, N, V, PRE, CASE, POST), ?LIB:try_tc(TCN, N, V, PRE, CASE, POST)). +-define(TRY_TC(TCN, N, V, COND, PRE, CASE, POST), + ?LIB:try_tc(TCN, N, V, COND, PRE, CASE, POST)). -define(ACQUIRE_NODES(N, Config), ?LIB:prepare_test_case([init, {stop_app, megaco}], N, Config, ?FILE, ?LINE)). +-define(MK_NODES(N), ?LIB:mk_nodes(N)). -define(START_NODE(Node, Force), ?LIB:start_node(Node, Force, ?FILE, ?LINE)). -define(START_NODE(Node), ?START_NODE(Node, false)). -define(START_NODES(Nodes, Force), ?LIB:start_nodes(Nodes, Force, ?FILE, ?LINE)). @@ -115,6 +118,7 @@ -define(INET_BACKEND_OPTS(C), ?LIB:inet_backend_opts(C)). -define(EXPLICIT_INET_BACKEND(), ?LIB:explicit_inet_backend()). -define(TEST_INET_BACKENDS(), ?LIB:test_inet_backends()). +-define(WHICH_INET_BACKEND(C), ?LIB:which_inet_backend(C)). -define(IS_SOCKET_BACKEND(C), ?LIB:is_socket_backend(C)). -define(OPEN(C, P, O), ?LIB:open(C, P, O)). @@ -124,13 +128,21 @@ -define(ANNOUNCE_SUITE_INIT(), io:format(user, "~n*** ~s *** suite ~w init~n~n", [?FTS(), ?MODULE])). +-define(ANNOUNCE_SUITE_END(), + io:format(user, "~n*** ~s *** suite ~w end~n~n", [?FTS(), ?MODULE])). -define(ANNOUNCE_GROUP_INIT(GR), io:format(user, "~n*** ~s *** group ~w:~w init~n~n", [?FTS(), ?MODULE, GR])). +-define(ANNOUNCE_GROUP_END(GR), + io:format(user, "~n*** ~s *** group ~w:~w end~n~n", + [?FTS(), ?MODULE, GR])). -define(ANNOUNCE_CASE_INIT(C), io:format(user, "~n*** ~s *** case ~w:~w init~n~n", [?FTS(), ?MODULE, C])). +-define(ANNOUNCE_CASE_END(C), + io:format(user, "~n*** ~s *** case ~w:~w end~n~n", + [?FTS(), ?MODULE, C])). --define(UNIQUE(__PreName__), +-define(UNIQUE(PreName), list_to_atom( - ?F("~w_~w", [__PreName__, erlang:system_time(millisecond)]))). + ?F("~w_~w", [(PreName), erlang:system_time(millisecond)]))). diff --git a/lib/megaco/test/megaco_timer_SUITE.erl b/lib/megaco/test/megaco_timer_SUITE.erl index c150dad897c8..2cdd83481bd5 100644 --- a/lib/megaco/test/megaco_timer_SUITE.erl +++ b/lib/megaco/test/megaco_timer_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2019. All Rights Reserved. +%% Copyright Ericsson AB 2007-2022. 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. @@ -143,9 +143,6 @@ end_per_group(_GroupName, Config) -> %% ----- %% -%% init_per_testcase(multi_user_extreme_load = Case, Config) -> -%% C = lists:keydelete(tc_timeout, 1, Config), -%% do_init_per_testcase(Case, [{tc_timeout, min(20)}|C]); init_per_testcase(Case, Config) -> do_init_per_testcase(Case, Config). @@ -183,6 +180,12 @@ simple_init(suite) -> simple_init(doc) -> []; simple_init(Config) when is_list(Config) -> + Pre = fun() -> #{} end, + Case = fun(_) -> do_simple_init() end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_simple_init() -> put(verbosity, ?TEST_VERBOSITY), put(tc, si), put(sname, "TEST"), @@ -297,6 +300,12 @@ simple_usage(suite) -> simple_usage(doc) -> []; simple_usage(Config) when is_list(Config) -> + Pre = fun() -> #{} end, + Case = fun(_) -> do_simple_usage() end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Pre, Case, Post). + +do_simple_usage() -> put(verbosity, ?TEST_VERBOSITY), put(tc, su), put(sname, "TEST"), @@ -389,23 +398,34 @@ integer_timer_start_and_expire(suite) -> integer_timer_start_and_expire(doc) -> []; integer_timer_start_and_expire(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(tc, itsae), - put(sname, "TEST"), - i("starting"), - + Cond = fun() -> + Key = megaco_factor, + case lists:keysearch(Key, 1, Config) of + {value, {Key, F}} when (F > 5) -> + {skip, ?F("Megaco Factor (~w) > 5", [F])}; + _ -> + ok + end + end, + Pre = fun() -> #{} end, + Case = fun(_) -> do_integer_timer_start_and_expire() end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_integer_timer_start_and_expire() -> Timeout = 5000, + i("start timer"), Ref = tmr_start(Timeout), + i("await timer expire"), receive - {timeout, Timeout} -> - ok + {timeout, Timeout} -> + i("received expected timer expire message"), + ok after Timeout + 500 -> - tmr_stop(Ref), - no_timeout() - end, - - i("done", []), - ok. + i("timeout-message timeout"), + tmr_stop(Ref), + no_timeout() + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -415,9 +435,21 @@ integer_timer_start_and_stop(suite) -> integer_timer_start_and_stop(doc) -> []; integer_timer_start_and_stop(Config) when is_list(Config) -> - put(verbosity, ?TEST_VERBOSITY), - put(tc, itsas), - put(sname, "TEST"), + Cond = fun() -> + Key = megaco_factor, + case lists:keysearch(Key, 1, Config) of + {value, {Key, F}} when (F > 5) -> + {skip, ?F("Megaco Factor (~w) > 5", [F])}; + _ -> + ok + end + end, + Pre = fun() -> #{} end, + Case = fun(_) -> do_integer_timer_start_and_stop() end, + Post = fun(_) -> ok end, + try_tc(?FUNCTION_NAME, Cond, Pre, Case, Post). + +do_integer_timer_start_and_stop() -> i("starting"), Timeout = 5000, @@ -473,6 +505,16 @@ timeout(Pid, Timeout, Tc) -> Pid ! {timeout, Timeout}. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +try_tc(Name, Pre, Case, Post) -> + Cond = fun() -> ok end, + try_tc(Name, Cond, Pre, Case, Post). + +try_tc(Name, Cond, Pre, Case, Post) -> + ?TRY_TC(Name, "TEST", ?TEST_VERBOSITY, Cond, Pre, Case, Post). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unexpected_result(A, B) -> diff --git a/lib/megaco/test/megaco_trans_SUITE.erl b/lib/megaco/test/megaco_trans_SUITE.erl index 0fe90a852402..0d98cb389583 100644 --- a/lib/megaco/test/megaco_trans_SUITE.erl +++ b/lib/megaco/test/megaco_trans_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -381,13 +381,23 @@ multi_ack_timeout(suite) -> multi_ack_timeout(doc) -> []; multi_ack_timeout(Config) when is_list(Config) -> + Cond = fun() -> + %% Regardless of other criteria, + %% if the factor is to high => SKIP + case lists:keysearch(megaco_factor, 1, Config) of + {value, {megaco_factor, MF}} when (MF >= 10) -> + ?SKIP({factor_too_high, MF}); + {value, _} -> + ok; + false -> + ?SKIP(factor_undefined) + end, + + Skippable = [win32, {unix, [darwin, sunos]}], + Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, + ?NON_PC_TC_MAYBE_SKIP(Config, Condition) + end, Pre = fun() -> - %% - Skippable = [win32, {unix, [darwin, linux, sunos]}], - Condition = fun() -> ?OS_BASED_SKIP(Skippable) end, - ?NON_PC_TC_MAYBE_SKIP(Config, Condition), - %% - MgcNode = make_node_name(mgc), MgNode = make_node_name(mg), d("start nodes: " @@ -396,18 +406,39 @@ multi_ack_timeout(Config) when is_list(Config) -> [MgcNode, MgNode]), Nodes = [MgcNode, MgNode], ok = ?START_NODES(Nodes), - Nodes + Factor = case lists:keysearch(megaco_factor, 1, Config) of + {value, {megaco_factor, MF}} -> + MF; + false -> + ?SKIP(factor_undefined) + end, + MaxCount = + if + (Factor =:= 1) -> + 20; + (Factor =:= 2) -> + 15; + (Factor < 5) -> + 10; + true -> + 5 + end, + #{nodes => Nodes, + max_count => MaxCount, + ttimeout => ?SECS(10), + timeout => ?SECS(60)} end, Case = fun do_multi_ack_timeout/1, - Post = fun(Nodes) -> + Post = fun(#{nodes := Nodes}) -> d("stop nodes"), ?STOP_NODES(lists:reverse(Nodes)) end, - try_tc(multi_ack_timeout, Pre, Case, Post). + try_tc(multi_ack_timeout, Cond, Pre, Case, Post). -do_multi_ack_timeout([MgcNode, MgNode]) -> - - MaxCount = 20, +do_multi_ack_timeout(#{nodes := [MgcNode, MgNode], + max_count := MaxCount, + ttimeout := TTimeout, + timeout := Timeout}) -> %% Start the MGC and MGs i("[MGC] start"), @@ -419,7 +450,7 @@ do_multi_ack_timeout([MgcNode, MgNode]) -> MgMid = {deviceName, "mg"}, MgConfig = [{auto_ack, true}, {trans_ack, true}, - {trans_timer, 10000}, + {trans_timer, TTimeout}, {trans_ack_maxcount, MaxCount + 10}], Mg = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY), @@ -446,7 +477,7 @@ do_multi_ack_timeout([MgcNode, MgNode]) -> ?MG_NOTIF_RAR(Mg), d("await the ack(s)"), - await_ack(Mgc, MaxCount, 60000, ok), + await_ack(Mgc, MaxCount, Timeout, ok), i("wait some time before closing down"), sleep(5000), @@ -9537,12 +9568,13 @@ await_ack(User, N, Timeout, Expected) {ack_received, User, UnExpected} -> e("await_ack -> received unexpected ack result: ~p" "~n when" + "~n User: ~p" "~n N: ~p" "~n Remaining: ~p", - [UnExpected, N, Timeout - (tim() - T)]), - exit({unexpected_ack_result, UnExpected, Expected}) + [UnExpected, User, N, Timeout - (tim() - T)]), + exit({unexpected_ack_result, User, UnExpected, Expected}) after Timeout -> - exit({await_ack_timeout, N}) + exit({await_ack_timeout, N, User}) end; await_ack(User, N, infinity, Expected) when N > 0 -> d("await_ack -> entry with N: ~p", [N]), @@ -9553,8 +9585,9 @@ await_ack(User, N, infinity, Expected) when N > 0 -> {ack_received, User, UnExpected} -> e("await_ack -> unexpected ack result: ~p" "~n when" - "~n N: ~p", [UnExpected, N]), - exit({unexpected_ack_result, UnExpected, Expected}) + "~n User: ~p" + "~n N: ~p", [UnExpected, User, N]), + exit({unexpected_ack_result, User, UnExpected, Expected}) end. @@ -9640,12 +9673,25 @@ mg_start(Pid, Mid, Enc, Transp, Conf, Verb) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -try_tc(TCName, Pre, Case, Post) -> +try_tc(TCName, Pre, Case, Post) when is_atom(TCName) andalso + is_function(Pre, 0) andalso + is_function(Case, 1) andalso + is_function(Post, 1) -> try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post). +try_tc(TCName, Cond, Pre, Case, Post) when is_atom(TCName) andalso + is_function(Cond, 0) andalso + is_function(Pre, 0) andalso + is_function(Case, 1) andalso + is_function(Post, 1) -> + try_tc(TCName, "TEST", ?TEST_VERBOSITY, Cond, Pre, Case, Post). + try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post). +try_tc(TCName, Name, Verbosity, Cond, Pre, Case, Post) -> + ?TRY_TC(TCName, Name, Verbosity, Cond, Pre, Case, Post). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/megaco/test/megaco_udp_SUITE.erl b/lib/megaco/test/megaco_udp_SUITE.erl index 461b56fad446..8fa3388a9fab 100644 --- a/lib/megaco/test/megaco_udp_SUITE.erl +++ b/lib/megaco/test/megaco_udp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021 All Rights Reserved. +%% Copyright Ericsson AB 2000-2023 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. @@ -1118,8 +1118,10 @@ server_open(Config, #{transport_ref := Ref} = State, Options) "~n ControlPid: ~p", [Socket, ControlPid]), {ok, State#{handle => {socket, Socket}, % Temporary control_pid => ControlPid}}; - {error, {could_not_open_udp_port, eaddrinuse}} -> - {skip, {server, eaddrinuse}}; + {error, {could_not_open_udp_port, SkipReason}} + when (SkipReason =:= eaddrinuse) orelse + (SkipReason =:= eacces) -> + {skip, {server, SkipReason}}; {error, _} = ERROR -> ERROR catch @@ -1233,8 +1235,10 @@ client_open(Config, #{transport_ref := Ref} = State, Options) {ok, State#{handle => {socket, Socket}, socket => Socket, control_pid => ControlPid}}; - {error, {could_not_open_udp_port, eaddrinuse}} -> - {skip, {client, eaddrinuse}}; + {error, {could_not_open_udp_port, SkipReason}} + when (SkipReason =:= eaddrinuse) orelse + (SkipReason =:= eacces) -> + {skip, {client, SkipReason}}; {error, _} = ERROR -> ERROR catch diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index d1fd7c372ae5..e8f861f2d969 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = megaco -MEGACO_VSN = 4.3 +MEGACO_VSN = 4.5 PRE_VSN = APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" diff --git a/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc index 41c85d97f183..eb25f5778731 100644 --- a/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc @@ -177,7 +177,7 @@ Transformer = which identifies the particular record in that table. The combination of the table name and a key is an arity two tuple {Tab, Key} called the OID. For more information about - the relationship beween the record name and the table name, see + the relationship between the record name and the table name, see Record Names versus Table Names.

    What makes the Mnesia data model an extended relational model diff --git a/lib/mnesia/doc/src/Mnesia_chap4.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap4.xmlsrc index fd9bea83230b..937caf10f0a5 100644 --- a/lib/mnesia/doc/src/Mnesia_chap4.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap4.xmlsrc @@ -520,10 +520,10 @@ It is much more efficient. - The funcion + The function dirty_update_counter/2 is performed as an atomic operation although it is not protected - by a transaction. Therfore no table update is lost if two + by a transaction. Therefore no table update is lost if two processes simultaneously execute the function dirty_update_counter/2. diff --git a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc index ef5e136446bb..3ef8d08220b3 100644 --- a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc @@ -4,7 +4,7 @@

    - 19972020 + 19972022 Ericsson AB. All Rights Reserved. @@ -720,7 +720,7 @@ dets:close(N). Source and Target are opaque data used exclusively by the modules SourceMod and - TargetMod for initializing the backup medias. + TargetMod for initializing the backup media. Acc is an initial accumulator value. diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 9791a576109f..8e285d78ce8b 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -772,7 +772,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies) table is aborted, unless a majority of the table replicas are available for the commit. When used on a fragmented table, all fragments are given the same - the same majority setting.

    + majority setting.

    {ram_copies, Nodelist}, where @@ -1153,7 +1153,7 @@ mnesia:create_table(person, or negative number. However, counters can never become less than zero. There are two significant differences between this function and the action of first reading the record, - performing the arithmetics, and then writing the record:

    + performing the arithmetic, and then writing the record:

    It is much more efficient. @@ -2609,6 +2609,7 @@ mnesia:create_table(employee, + @@ -2674,13 +2675,20 @@ raise(Name, Amount) -> several processes running on different nodes can concurrently execute the function raise/2 without interfering with each other.

    -

    Since Mnesia detects deadlocks, a transaction can be - restarted any number of times. This function attempts a - restart as specified in Retries. Retries must - be an integer greater than 0 or the atom infinity. - Default is infinity.

    +

    + Since Mnesia detects deadlocks, a transaction can be + restarted any number of times and therefore the Fun shall not + have any side effects such as waiting for specific messages. + This function attempts a restart as many times as specified in Retries. + Retries must be an integer greater than 0 or the atom infinity, + default is infinity. + Mnesia uses exit exceptions to signal that a transaction needs to be + restarted, thus a Fun must not catch exit exceptions with reason + {aborted, term()}. +

    + Changes format on all records in table Tab. @@ -2955,7 +2963,7 @@ raise(Name, Amount) ->

    -mnesia dump_log_write_threshold Max. Max is an integer that specifies the maximum number of writes allowed to the transaction log before - a new dump of the log is performed. Default is 100 + a new dump of the log is performed. Default is 1000 log writes.

    diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 1a914f2396d0..18beb7e28629 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -39,6 +39,174 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.

    +
    Mnesia 4.22.1 + +
    Fixed Bugs and Malfunctions + + +

    + Do not delete old backup file if the new backup fails.

    +

    + Own Id: OTP-18711 Aux Id: ERIERL-963

    +
    +
    +
    + +
    + +
    Mnesia 4.22 + +
    Improvements and New Features + + +

    + Added debug statistics for active transactions.

    +

    + Own Id: OTP-18309 Aux Id: PR-6377

    +
    + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    Mnesia 4.21.4.1 + +
    Fixed Bugs and Malfunctions + + +

    + Do not delete old backup file if the new backup fails.

    +

    + Own Id: OTP-18711 Aux Id: ERIERL-963

    +
    +
    +
    + +
    + +
    Mnesia 4.21.4 + +
    Fixed Bugs and Malfunctions + + +

    + Improved consistency for dirty writes when a table was + added with add_table_copy/3.

    +

    + Fixed a problem with sticky write, which could lead to + inconsistent data.

    +

    + Own Id: OTP-18412

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Mnesia 4.21.3 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed crash which could happen during startup if too many + decisions where sent from remote nodes.

    +

    + Own Id: OTP-18319 Aux Id: ERIERL-875

    +
    +
    +
    + +
    + +
    Mnesia 4.21.2 + +
    Fixed Bugs and Malfunctions + + +

    + Don't fill the logs if mnesia can't connect to all nodes, + due to partitioned network.

    +

    + Own Id: OTP-18288 Aux Id: ERIERL-868

    +
    +
    +
    + +
    + +
    Mnesia 4.21.1 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed add_table_copy which could leave a table + lock if the receiving node went down during the + operation.

    +

    + Own Id: OTP-18128 Aux Id: PR-6013

    +
    +
    +
    + +
    + +
    Mnesia 4.21 + +
    Improvements and New Features + + +

    + Documentation fixes.

    +

    + Own Id: OTP-17930

    +
    +
    +
    + +
    +
    Mnesia 4.20.4.2
    Fixed Bugs and Malfunctions @@ -62,7 +230,7 @@
    -
    Mnesia 4.20.4.1 +
    Mnesia 4.20.4.1
    Fixed Bugs and Malfunctions diff --git a/lib/mnesia/examples/Makefile b/lib/mnesia/examples/Makefile index 5580f0bdcb8c..e5eb2de940c1 100644 --- a/lib/mnesia/examples/Makefile +++ b/lib/mnesia/examples/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -66,7 +66,7 @@ EBIN = . # ---------------------------------------------------- # Make Rules # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) *~ diff --git a/lib/mnesia/examples/bench/README b/lib/mnesia/examples/bench/README index b8209b19b804..52225c5f7d34 100644 --- a/lib/mnesia/examples/bench/README +++ b/lib/mnesia/examples/bench/README @@ -45,7 +45,7 @@ In order to be able to automatically start remote Erlang nodes, you need to: - put the $ERL_TOP/bin directory in your path on all nodes - - bind IP adresses to hostnames (e.g via DNS or /etc/hosts) + - bind IP addresses to hostnames (e.g via DNS or /etc/hosts) - enable usage of ssh so it does not prompt for password If you cannot achieve this, it is possible to run the benchmark @@ -79,11 +79,11 @@ Given some arguments such as Args = ['YourConfigFile', {statistics_detail, debug}]. -the invokation of +the invocation of bench:run(Args). -is equivivalent with: +is equivalent with: SlaveNodes = bench:start_all(Args). bench:populate(Args). diff --git a/lib/mnesia/examples/mnesia_tpcb.erl b/lib/mnesia/examples/mnesia_tpcb.erl index fb39ee321d93..6a78d4f1d07f 100644 --- a/lib/mnesia/examples/mnesia_tpcb.erl +++ b/lib/mnesia/examples/mnesia_tpcb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -35,7 +35,7 @@ %% a database system. %% %% The definition of the TPC-B states lots of detailed rules and -%% conditions that must be fullfilled, e.g. how the ACID (atomicity, +%% conditions that must be fulfilled, e.g. how the ACID (atomicity, %% consistency, isolation and durability) properties are verified, %% how the random numbers must be distributed, minimum sizes of %% the different types of records, minimum duration of the benchmark, diff --git a/lib/mnesia/include/Makefile b/lib/mnesia/include/Makefile index 6eed4d716fb6..1c96482d87b6 100644 --- a/lib/mnesia/include/Makefile +++ b/lib/mnesia/include/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2016. All Rights Reserved. +# Copyright Ericsson AB 1998-2022. 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. @@ -42,7 +42,7 @@ INCLUDE_FILES = # ---------------------------------------------------- # Make Rules # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile index dce7a359d366..72aa054fb326 100644 --- a/lib/mnesia/src/Makefile +++ b/lib/mnesia/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -106,8 +106,8 @@ ERL_COMPILE_FLAGS += \ opt: $(TARGET_FILES) -debug: - @${MAKE} TYPE=debug +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt clean: rm -f $(TARGET_FILES) diff --git a/lib/mnesia/src/mnesia.app.src b/lib/mnesia/src/mnesia.app.src index 77bd1a78166f..6ce0c68de8cd 100644 --- a/lib/mnesia/src/mnesia.app.src +++ b/lib/mnesia/src/mnesia.app.src @@ -51,4 +51,4 @@ ]}, {applications, [kernel, stdlib]}, {mod, {mnesia_app, []}}, - {runtime_dependencies, ["stdlib-3.4","kernel-5.3","erts-9.0"]}]}. + {runtime_dependencies, ["stdlib-5.0","kernel-5.3","erts-9.0"]}]}. diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 35e2d8dd10ac..bb5858b3f832 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -513,7 +513,7 @@ wrap_trans(State, Fun, Args, Retries, Mod, Kind) -> %% read lock is only set on the first node %% Nodes may either be a list of nodes or one node as an atom %% Mnesia on all Nodes must be connected to each other, but -%% it is not neccessary that they are up and running. +%% it is not necessary that they are up and running. -spec lock(LockItem, LockKind) -> list() | tuple() | no_return() when LockItem :: {'record', table(), Key::term()} | {'table', table()} | diff --git a/lib/mnesia/src/mnesia_backup.erl b/lib/mnesia/src/mnesia_backup.erl index 719e010c1791..31b0a40e9270 100644 --- a/lib/mnesia/src/mnesia_backup.erl +++ b/lib/mnesia/src/mnesia_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -30,7 +30,7 @@ %% write an own module the same interface as mnesia_backup and %% configure Mnesia so the alternate module performs the actual %% accesses to the backup media. This means that the user may put -%% the backup on medias that Mnesia does not know about, possibly +%% the backup on media that Mnesia does not know about, possibly %% on hosts where Erlang is not running. %% %% The OpaqueData argument is never interpreted by other parts of @@ -79,7 +79,6 @@ open_write(OpaqueData) -> File = OpaqueData, Tmp = lists:concat([File,".BUPTMP"]), file:delete(Tmp), - file:delete(File), case disk_log:open([{name, make_ref()}, {file, Tmp}, {repair, false}, @@ -112,6 +111,7 @@ commit_write(OpaqueData) -> ok -> case disk_log:close(B#backup.file_desc) of ok -> + file:delete(B#backup.file), case file:rename(B#backup.tmp_file, B#backup.file) of ok -> {ok, B#backup.file}; diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 4b4be695d28d..1fe7f4ae2674 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -809,7 +809,7 @@ restore_tables(Recs, Header, Schema, Ext, {start, LocalTabs}) -> restore_tables([], _Header, _Schema, _Ext, State) -> State. -%% Creates all neccessary dat files and inserts +%% Creates all necessary dat files and inserts %% the table definitions in the schema table %% %% Returns a list of local_tab tuples for all local tables diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl index c67c7400363d..ed1c0df605e9 100644 --- a/lib/mnesia/src/mnesia_checkpoint.erl +++ b/lib/mnesia/src/mnesia_checkpoint.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021 +%% Copyright Ericsson AB 1996-2023 %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -306,7 +306,7 @@ really_retain(Name, Tab) -> %% %% {min, MinTabs} %% Minimize redundancy and only keep checkpoint info together with -%% one replica, preferrably at the local node. If any node involved +%% one replica, preferably at the local node. If any node involved %% the checkpoint goes down, the checkpoint is deactivated. %% %% {max, MaxTabs} @@ -319,7 +319,7 @@ really_retain(Name, Tab) -> %% {ram_overrides_dump, Tabs} %% Only applicable for ram_copies. Bool controls which versions of %% the records that should be included in the checkpoint state. -%% true means that the latest comitted records in ram (i.e. the +%% true means that the latest committed records in ram (i.e. the %% records that the application accesses) should be included %% in the checkpoint. false means that the records dumped to %% dat-files (the records that will be loaded at startup) should @@ -632,7 +632,8 @@ init(Cp) -> catch error:Reason -> %% system limit Msg = "Cannot create an ets table for pending transactions", Error = {error, {system_limit, Name, Msg, Reason}}, - proc_lib:init_ack(Cp#checkpoint_args.supervisor, Error) + proc_lib:init_fail( + Cp#checkpoint_args.supervisor, Error, {exit, normal}) end. prepare_tab(Cp, R) -> diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index f19960360fef..02d873040b91 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -342,7 +342,7 @@ get_network_copy(Tid, Tab, Cs) -> ok -> Reason = {dumper,{add_table_copy, Tid}}, Work = #net_load{table = Tab,reason = Reason,cstruct = Cs}, - %% I'll need this cause it's linked trough the subscriber + %% I'll need this cause it's linked through the subscriber %% might be solved by using monitor in subscr instead. process_flag(trap_exit, true), Load = load_table_fun(Work), @@ -375,7 +375,7 @@ get_network_copy(Tid, Tab, Cs) -> %% no need for sync, since mnesia_controller not started yet %% schema_trans -> %% already synced with mnesia_controller since the dumper -%% is syncronously started from mnesia_controller +%% is synchronously started from mnesia_controller create_table(Tab) -> Cs = val({Tab, cstruct}), @@ -1019,7 +1019,7 @@ handle_cast(Msg, State) when State#state.schema_is_merged /= true -> %% This must be done after schema_is_merged otherwise adopt_orphan %% might trigger a table load from wrong nodes as a result of that we don't -%% know which tables we can load safly first. +%% know which tables we can load safely first. handle_cast({im_running, Node, NewFriends}, State) -> LocalTabs = mnesia_lib:local_active_tables() -- [schema], RemoveLocalOnly = fun(Tab) -> not val({Tab, local_content}) end, @@ -1449,7 +1449,7 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) -> case lists:member(Node, DiscCopyHolders) of _ when BeingCreated == true -> orphan_tables(Tabs, Node, Ns, Local, Remote); - _ when Read == node() -> %% Allready loaded + _ when Read == node() -> %% Already loaded orphan_tables(Tabs, Node, Ns, Local, Remote); true when Active == [] -> case DiscCopyHolders -- Ns of @@ -2171,7 +2171,7 @@ load_and_reply(ReplyTo, Worker) -> spawn_link(SendAndReply). %% Now it is time to load the table -%% but first we must check if it still is neccessary +%% but first we must check if it still is necessary load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=ReplyTo}) -> LocalC = val({Tab, local_content}), AccessMode = val({Tab, access_mode}), diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl index aea1f9308328..e6b02b501a8c 100644 --- a/lib/mnesia/src/mnesia_dumper.erl +++ b/lib/mnesia/src/mnesia_dumper.erl @@ -526,8 +526,8 @@ disc_delete_table(Tab, Storage) -> disc_delete_indecies(Tab, Cs, Storage) -> case storage_semantics(Storage) of disc_only_copies -> - Indecies = Cs#cstruct.index, - mnesia_index:del_transient(Tab, Indecies, Storage); + Indices = Cs#cstruct.index, + mnesia_index:del_transient(Tab, Indices, Storage); _ -> ok end. @@ -815,7 +815,7 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) -> ram_copies -> ignore; _ -> - %% Indecies are still created by loader + %% Indices are still created by loader disc_delete_indecies(Tab, Cs, Storage) %% disc_delete_table(Tab, Storage) end, @@ -1433,10 +1433,10 @@ chunk_from_log(eof, _, _, _) -> %% %% This is a poor mans substitute for a fair scheduler algorithm %% in the Erlang emulator. The mnesia_dumper process performs many -%% costly BIF invokations and must pay for this. But since the +%% costly BIF invocations and must pay for this. But since the %% Emulator does not handle this properly we must compensate for %% this with some form of load regulation of ourselves in order to -%% not steal all computation power in the Erlang Emulator ans make +%% not steal all computation power in the Erlang Emulator and make %% other processes starve. Hopefully this is a temporary solution. start_regulator() -> diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index 8f7dd321b031..1b4b55e07100 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -1,7 +1,7 @@ %%% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2018. All Rights Reserved. +%% Copyright Ericsson AB 1998-2021. 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. @@ -1103,7 +1103,7 @@ make_add_node(Tab, Node) -> mnesia:abort({bad_type, Tab, Node}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Delet a node from the node pool of a fragmented table +%% Delete a node from the node pool of a fragmented table make_multi_del_node(Tab, Node) -> verify_multi(Tab), diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl index d9f7da8edaba..fbfca9142136 100644 --- a/lib/mnesia/src/mnesia_index.erl +++ b/lib/mnesia/src/mnesia_index.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -332,7 +332,7 @@ init_disc_index(Tab, disc_only_copies, [{Pos,_Pref} | Tail]) -> Storage = disc_only_copies, Key = mnesia_lib:db_first(Storage, Tab), Recs = mnesia_lib:db_get(Storage, Tab, Key), - BinSize = size(term_to_binary(Recs)), + BinSize = byte_size(term_to_binary(Recs)), KeysPerChunk = (4000 div BinSize) + 1, Init = {start, KeysPerChunk}, mnesia_lib:db_fixtable(Storage, Tab, true), diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl index 4dce5cefc0af..84750835d92b 100644 --- a/lib/mnesia/src/mnesia_lib.erl +++ b/lib/mnesia/src/mnesia_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -568,10 +568,10 @@ set_remote_where_to_read(Tab, Ignore) -> end, Available = mnesia_lib:intersect(val({current, db_nodes}), Valid -- Ignore), DiscOnlyC = val({Tab, disc_only_copies}), - Prefered = Available -- DiscOnlyC, + Preferred = Available -- DiscOnlyC, if - Prefered /= [] -> - set({Tab, where_to_read}, hd(Prefered)); + Preferred /= [] -> + set({Tab, where_to_read}, hd(Preferred)); Available /= [] -> set({Tab, where_to_read}, hd(Available)); true -> @@ -936,7 +936,7 @@ error_desc(mnesia_down) -> "A transaction involving objects at some remote " "node which died while transaction was executing" "*and* object(s) are no longer available elsewhere" "in the network"; -error_desc(not_a_db_node) -> "A node which is non existant in " +error_desc(not_a_db_node) -> "A node which is non existent in " "the schema was mentioned"; error_desc(bad_type) -> "Bad type on some provided arguments"; error_desc(node_not_running) -> "Node not running"; @@ -950,7 +950,7 @@ error_desc({error, Reason}) -> error_desc(Reason); error_desc({aborted, Reason}) -> error_desc(Reason); -error_desc(Reason) when is_tuple(Reason), size(Reason) > 0 -> +error_desc(Reason) when tuple_size(Reason) > 0 -> setelement(1, Reason, error_desc(element(1, Reason))); error_desc(Reason) -> Reason. diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index b16d00da6116..9c039652bdc0 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2022. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -222,7 +222,6 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> ok -> set({Tab, load_node}, Node), set({Tab, load_reason}, Reason), - mnesia_controller:i_have_tab(Tab, Cs), dbg_out("Table ~tp copied from ~p to ~p~n", [Tab, Node, node()]), {loaded, ok}; Err = {error, _} when element(1, Reason) == dumper -> @@ -267,7 +266,7 @@ init_receiver(Node, Tab,Storage,Cs,Reason) -> end, %% Check that table still exists Active = val({Tab, active_replicas}), - %% Check that we havn't loaded it already + %% Check that we haven't loaded it already case val({Tab,where_to_read}) == node() of true -> ok; _ -> @@ -291,7 +290,11 @@ init_receiver(Node, Tab,Storage,Cs,Reason) -> {atomic, {error,Result}} -> fatal("Cannot create table ~tp: ~tp~n", [[Tab, Storage], Result]); - {atomic, Result} -> Result; + {atomic, ok} -> + mnesia_controller:i_have_tab(Tab, Cs), + ok; + {atomic, Result} -> + Result; {aborted, nomore} -> restart; {aborted, _Reas} -> verbose("Receiver failed on ~tp from ~p:~nReason: ~tp~n", @@ -334,7 +337,7 @@ table_init_fun(SenderPid, Storage) -> ok end. -%% Add_table_copy get's it's own locks. +%% Add_table_copy gets it's own locks. start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,{add_table_copy,_}}) -> Init = table_init_fun(SenderPid, Storage), case do_init_table(Tab,Storage,Cs,SenderPid,TabSize,DetsData,self(), Init) of @@ -555,14 +558,17 @@ init_table(Tab, _, Fun, _DetsInfo,_) -> finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) -> TabRef = {Storage, Tab}, - subscr_postprocess(TabRef, Cs#cstruct.record_name), case handle_last(TabRef, Cs#cstruct.type, DatBin) of ok -> - mnesia_index:init_index(Tab, Storage), - snmpify(Tab, Storage), + subscr_postprocess(TabRef, Cs#cstruct.record_name), %% OrigTabRec must not be the spawned tab-receiver %% due to old protocol. SenderPid ! {OrigTabRec, no_more}, + Ref = monitor(process, SenderPid), + %% and all remaining events + subscr_receiver(TabRef, Cs#cstruct.record_name, Ref), + mnesia_index:init_index(Tab, Storage), + snmpify(Tab, Storage), mnesia_tm:unblock_tab(Tab), ok; {error, Reason} -> @@ -582,22 +588,21 @@ subscr_postprocess(TabRef, RecName) -> handle_subscr_event(Event, TabRef, RecName) end, ok, SubscrCache), ets:delete(SubscrCache) - end, - % and all remaining events - subscr_receiver(TabRef, RecName). + end. -subscr_receiver(TabRef = {_, Tab}, RecName) -> +subscr_receiver(TabRef = {_, Tab}, RecName, Ref) -> receive {mnesia_table_event, {_Op, Val, _Tid}} = Event when element(1, Val) =:= Tab; element(1, Val) =:= schema -> handle_subscr_event(Event, TabRef, RecName), - subscr_receiver(TabRef, RecName); + subscr_receiver(TabRef, RecName, Ref); {'EXIT', Pid, Reason} -> handle_exit(Pid, Reason), - subscr_receiver(TabRef, RecName) - after 0 -> - ok + subscr_receiver(TabRef, RecName, Ref); + + {'DOWN', Ref, process, _, _} -> + ok end. handle_subscr_event(Event, TabRef = {_, Tab}, RecName) -> @@ -760,7 +765,7 @@ calc_nokeys(Storage, Tab) -> %% Calculate #keys per transfer Key = mnesia_lib:db_first(Storage, Tab), Recs = mnesia_lib:db_get(Storage, Tab, Key), - BinSize = size(term_to_binary(Recs)), + BinSize = byte_size(term_to_binary(Recs)), (max_transfer_size() div BinSize) + 1. send_table(Pid, Tab, RemoteS, Reason) -> @@ -1014,12 +1019,15 @@ finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) -> mnesia_checkpoint:tm_add_copy(Tab, RecNode), DatBin = dat2bin(Tab, ?catch_val({Tab, storage_type}), RemoteS), Pid ! {self(), {no_more, DatBin}}, - cleanup_tab_copier(Pid, Storage, Tab), receive {Pid, no_more} -> % Dont bother about the spurious 'more' message + %% Sync mnesia_tm (before unsubscribing) + mnesia_tm:sync(), + cleanup_tab_copier(Pid, Storage, Tab), no_more; {copier_done, Node} -> verbose("Tab receiver ~tp crashed (more): ~p~n", [Tab, Node]), + cleanup_tab_copier(Pid, Storage, Tab), receiver_died end end diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 671dea2a1497..aa7f94ee9f59 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -201,14 +201,14 @@ loop(State) -> end; %% If test_set_sticky fails, we send this to all nodes - %% after aquiring a real write lock on Oid + %% after acquiring a real write lock on Oid {stick, {Tab, _}, N} -> ?ets_insert(mnesia_sticky_locks, {Tab, N}), loop(State); %% The caller which sends this message, must have first - %% aquired a write lock on the entire table + %% acquired a write lock on the entire table {unstick, Tab} -> ?ets_delete(mnesia_sticky_locks, Tab), loop(State); @@ -649,7 +649,7 @@ ix_read_res(Tab,IxKey,Pos) -> %% ********************* end server code ******************** %% The following code executes at the client side of a transactions -%% Aquire a write lock, but do a read, used by +%% Acquire a write lock, but do a read, used by %% mnesia:wread/1 rwlock(Tid, Store, Oid) -> @@ -712,7 +712,7 @@ check_majority(Tab, HaveNs) -> ok end. -%% aquire a sticky wlock, a sticky lock is a lock +%% acquire a sticky wlock, a sticky lock is a lock %% which remains at this node after the termination of the %% transaction. @@ -761,12 +761,14 @@ do_sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) -> exit({aborted, Reason}); {?MODULE, N, not_stuck} -> not_stuck(Tid, Store, Tab, Key, Oid, Lock, N), + ?ets_insert(Store, {sticky, true}), dirty_sticky_lock(Tab, Key, [N], Lock); {mnesia_down, Node} -> EMsg = {aborted, {node_not_running, Node}}, flush_remaining([N], Node, EMsg); {?MODULE, N, {stuck_elsewhere, _N2}} -> stuck_elsewhere(Tid, Store, Tab, Key, Oid, Lock), + ?ets_insert(Store, {sticky, true}), dirty_sticky_lock(Tab, Key, [N], Lock) end. @@ -809,11 +811,11 @@ dirty_sticky_lock(Tab, Key, Nodes, Lock) -> sticky_wlock_table(Tid, Store, Tab) -> sticky_lock(Tid, Store, {Tab, ?ALL}, write). -%% aquire a wlock on Oid +%% acquire a wlock on Oid %% We store a {Tabname, write, Tid} in all locktables %% on all nodes containing a copy of Tabname %% We also store an item {{locks, Tab, Key}, write} in the -%% local store when we have aquired the lock. +%% local store when we have acquired the lock. %% wlock(Tid, Store, Oid) -> wlock(Tid, Store, Oid, _CheckMajority = true). @@ -882,7 +884,7 @@ get_wlocks_on_nodes([Node | Tail], Orig, Store, Request, Oid) -> case node() of Node -> %% Local done try one more get_wlocks_on_nodes(Tail, Orig, Store, Request, Oid); - _ -> %% The first succeded cont with the rest + _ -> %% The first succeeded cont with the rest get_wlocks_on_nodes(Tail, Store, Request), receive_wlocks(Tail, Orig, Store, Oid) end; @@ -996,7 +998,7 @@ return_granted_or_nodes(_ , _Nodes) -> granted. %% locks table on the node where we actually do pick up the object %% and we also store an item {lock, Oid, read} in our local store %% so that we can release any locks we hold when we commit. -%% This function not only aquires a read lock, but also reads the object +%% This function not only acquires a read lock, but also reads the object %% Oid's are always {Tab, Key} tuples rlock(Tid, Store, Oid) -> diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl index 03411ace4110..b1514bfbe64e 100644 --- a/lib/mnesia/src/mnesia_log.erl +++ b/lib/mnesia/src/mnesia_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -48,7 +48,7 @@ %% with the same interface as mnesia_backup and configure %% Mnesia so the alternate module performs the actual accesses %% to the backup media. This means that the user may put the -%% backup on medias that Mnesia does not know about possibly on +%% backup on media that Mnesia does not know about possibly on %% hosts where Erlang is not running. %% %% All these logs have to some extent a common structure. @@ -93,7 +93,7 @@ %% The log file structure for the mnesia_down log is as follows. %% %% After the mnesia log section follows a mnesia_down section -%% containg lists with yoyo records as single element. +%% containing lists with yoyo records as single element. %% %% +-----------------+ %% | mnesia log head | diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index aee84887dc3f..dbd4a9c42f5d 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -136,7 +136,7 @@ unsafe_create_external(Tab, Alias, Mod, Cs) -> disconnect(Node) -> cast({disconnect, Node}). -%% Returns GoodNoodes +%% Returns GoodNodes %% Creates a link to each compatible monitor and %% protocol_version to agreed version upon success diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl index 36b4a29fc286..820e1429945f 100644 --- a/lib/mnesia/src/mnesia_recover.erl +++ b/lib/mnesia/src/mnesia_recover.erl @@ -130,7 +130,7 @@ allow_garb() -> cast(allow_garb). -%% The transaction log has either been swiched (latest -> previous) or +%% The transaction log has either been switched (latest -> previous) or %% there is nothing to be dumped. This means that the previous %% transaction log only may contain commit records which refers to %% transactions noted in the last two of the 'Prev' tables. All other @@ -428,7 +428,7 @@ check_what_happened([H | T], Aborts, Commits) -> check_what_happened([], Aborts, Commits) -> if Aborts == 0, Commits == 0 -> aborted; % None of the active nodes knows - Aborts > 0 -> aborted; % Someody has aborted + Aborts > 0 -> aborted; % Somebody has aborted Aborts == 0, Commits > 0 -> committed % All has committed end. @@ -674,7 +674,7 @@ handle_call({connect_nodes, Ns}, From, State) -> erlang:send_after(2, self(), {connect_nodes,Ns,From}), {noreply, State}; [] -> - %% No good noodes to connect to! + %% No good nodes to connect to! %% We can't use reply here because this function can be %% called from handle_info gen_server:reply(From, {[], AlreadyConnected}), @@ -1083,7 +1083,7 @@ merge_decisions(Node, D, NewD0) -> NewD#decision.outcome == aborted -> %% Interesting! We have already committed, %% but someone else has aborted. Now we - %% have a nice little inconcistency. The + %% have a nice little inconsistency. The %% other guy (or some one else) has %% enforced a recovery decision when %% max_wait_for_decision was exceeded. @@ -1096,11 +1096,11 @@ merge_decisions(Node, D, NewD0) -> OldD#decision{outcome = aborted}; OldD#decision.outcome == aborted -> - %% aborted overrrides anything + %% aborted overrides anything OldD#decision{outcome = aborted}; NewD#decision.outcome == aborted -> - %% aborted overrrides anything + %% aborted overrides anything OldD#decision{outcome = aborted}; OldD#decision.outcome == committed, @@ -1236,7 +1236,7 @@ arrange([To | ToNodes], D, Acc, ForceSend) when is_record(D, decision) -> arrange([To | ToNodes], {trans_tid, serial, Serial}, Acc, ForceSend) -> %% Do the lamport thing plus release the others - %% from uncertainity. + %% from uncertainty. Acc2 = add_decision(To, {trans_tid, serial, Serial}, Acc), arrange(ToNodes, {trans_tid, serial, Serial}, Acc2, ForceSend); diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 0872cbf4a05a..ed4f7a8784ba 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -957,13 +957,13 @@ get_ext_types_disc_() -> [] end. -%% Convert attribute name to integer if neccessary +%% Convert attribute name to integer if necessary attr_tab_to_pos(_Tab, Pos) when is_integer(Pos) -> Pos; attr_tab_to_pos(Tab, Attr) -> attr_to_pos(Attr, val({Tab, attributes})). -%% Convert attribute name to integer if neccessary +%% Convert attribute name to integer if necessary attr_to_pos({_} = P, _) -> P; attr_to_pos(Pos, _Attrs) when is_integer(Pos) -> Pos; @@ -1024,14 +1024,14 @@ verify_cstruct(#cstruct{} = Cs) -> expand_index_attrs(#cstruct{index = Ix, attributes = Attrs, name = Tab} = Cs) -> - Prefered = prefered_index_types(Cs), - expand_index_attrs(Ix, Tab, Attrs, Prefered). + Preferred = prefered_index_types(Cs), + expand_index_attrs(Ix, Tab, Attrs, Preferred). -expand_index_attrs(Ix, Tab, Attrs, Prefered) -> +expand_index_attrs(Ix, Tab, Attrs, Preferred) -> lists:map(fun(P) when is_integer(P); is_atom(P) -> - {attr_to_pos(P, Attrs), Prefered}; + {attr_to_pos(P, Attrs), Preferred}; ({A} = P) when is_atom(A) -> - {P, Prefered}; + {P, Preferred}; ({P, Type}) -> {attr_to_pos(P, Attrs), Type}; (_Other) -> @@ -1186,7 +1186,7 @@ assert_correct_cstruct(Cs) when is_record(Cs, cstruct) -> verify(true, mnesia_snmp_hook:check_ustruct(Snmp), {badarg, Tab, {snmp, Snmp}}), - CheckProp = fun(Prop) when is_tuple(Prop), size(Prop) >= 1 -> ok; + CheckProp = fun(Prop) when tuple_size(Prop) >= 1 -> ok; (Prop) -> mnesia:abort({bad_type, Tab, {user_properties, [Prop]}}) @@ -1352,7 +1352,7 @@ check_active([], _Expl, _Tab) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Function for definining an external backend type +%% Function for defining an external backend type add_backend_type(Name, Module) -> case schema_transaction(fun() -> do_add_backend_type(Name, Module) end) of @@ -2126,7 +2126,7 @@ make_change_table_majority(Tab, Majority) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -write_table_property(Tab, Prop) when is_tuple(Prop), size(Prop) >= 1 -> +write_table_property(Tab, Prop) when tuple_size(Prop) >= 1 -> schema_transaction(fun() -> do_write_table_property(Tab, Prop) end); write_table_property(Tab, Prop) -> {aborted, {bad_type, Tab, Prop}}. @@ -2472,6 +2472,7 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) -> {loaded, ok} -> %% Tables are created by mnesia_loader get_network code insert_cstruct(Tid, Cs, true), + mnesia_controller:i_have_tab(Tab, Cs), {true, optional}; {not_loaded, ErrReason} -> Reason = {system_limit, Tab, {Node, ErrReason}}, @@ -2809,7 +2810,7 @@ transform_objs(Fun, Tab, RecName, Key, A, Storage, Type, Acc) -> transform_obj(Tab, RecName, Key, Fun, [Obj|Rest], NewArity, Type, Ws, Ds) -> NewObj = Fun(Obj), if - size(NewObj) /= NewArity -> + tuple_size(NewObj) /= NewArity -> exit({"Bad arity", Obj, NewObj}); NewObj == Obj -> transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, Type, Ws, Ds); @@ -3095,7 +3096,7 @@ ext_real_suffixes(Ext) -> [M || {_,M} <- Ext]) catch error:E -> - verbose("Cant find real ext suffixes (~tp)~n", [E]), + verbose("Can't find real ext suffixes (~tp)~n", [E]), [] end. @@ -3104,7 +3105,7 @@ ext_tmp_suffixes(Ext) -> [M || {_,M} <- Ext]) catch error:E -> - verbose("Cant find tmp ext suffixes (~tp)~n", [E]), + verbose("Can't find tmp ext suffixes (~tp)~n", [E]), [] end. diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl index 58a20c605167..ff89770eaf16 100644 --- a/lib/mnesia/src/mnesia_snmp_hook.erl +++ b/lib/mnesia/src/mnesia_snmp_hook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -124,7 +124,7 @@ key_to_oid(Tab, Key, [{key, Types}]) -> key_to_oid_i(Key, integer) when is_integer(Key) -> [Key]; key_to_oid_i(Key, fix_string) when is_list(Key) -> Key; key_to_oid_i(Key, string) when is_list(Key) -> [length(Key) | Key]; -key_to_oid_i(Key, Types) -> keys_to_oid(size(Key), Key, [], Types). +key_to_oid_i(Key, Types) when is_tuple(Key) -> keys_to_oid(tuple_size(Key), Key, [], Types). keys_to_oid(0, _Key, Oid, _Types) -> Oid; keys_to_oid(N, Key, Oid, Types) -> @@ -134,7 +134,7 @@ keys_to_oid(N, Key, Oid, Types) -> %%-------------------------------------------------- %% The reverse of the above, i.e. snmp oid to mnesia key. %% This can be lookup up in tree but that might be on a remote node. -%% It's probably faster to look it up, but use when it migth be remote +%% It's probably faster to look it up, but use when it might be remote oid_to_key(Oid, Tab) -> [{key, Types}] = mnesia_lib:val({Tab,snmp}), oid_to_key_1(Types, Oid). @@ -144,7 +144,7 @@ oid_to_key_1(fix_string, Key) -> Key; oid_to_key_1(string, [_|Key]) -> Key; oid_to_key_1(Tuple, Oid) -> try - List = oid_to_key_2(1, size(Tuple), Tuple, Oid), + List = oid_to_key_2(1, tuple_size(Tuple), Tuple, Oid), list_to_tuple(List) catch _:_ -> unknown @@ -208,7 +208,7 @@ get_next_index(Name, RowIndex) -> %% Purpose: Get the mnesia key corresponding to the RowIndex. %% Args: Name is the name of the table (atom) %% RowIndex is an Oid -%% Returns: {ok, Key} | undefiend +%% Returns: {ok, Key} | undefined %%----------------------------------------------------------------- get_mnesia_key(Name, RowIndex) -> Tree = mnesia_lib:val({Name, {index, snmp}}), diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl index 21a308cfb6f9..d0c298e4253c 100644 --- a/lib/mnesia/src/mnesia_subscr.erl +++ b/lib/mnesia/src/mnesia_subscr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -148,7 +148,7 @@ report_table_event(Tab, Tid, Obj, Op) -> end end. -%% Backwards compatible for the moment when mnesia_tm get's updated! +%% Backwards compatible for the moment when mnesia_tm gets updated! report_table_event(Subscr, Tab, Tid, Obj, Op) -> report_table_event(Subscr, Tab, Tid, Obj, Op, undefined). @@ -173,7 +173,7 @@ report_table_event({subscribers, S1, S2}, Tab, Tid, Obj, Op, Old) -> Extended = what(Tab, Tid, Obj, Op, Old), deliver(S2, Extended); -%% Backwards compatible for the moment when mnesia_tm get's updated! +%% Backwards compatible for the moment when mnesia_tm gets updated! report_table_event({subscribers, Subscr}, Tab, Tid, Obj, Op, Old) -> report_table_event({subscribers, Subscr, []}, Tab, Tid, Obj, Op, Old). diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index 5a070cf0cde5..d7b123d1e52d 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -32,6 +32,7 @@ do_update_op/3, get_info/1, get_transactions/0, + get_transactions_count/0, info/1, mnesia_down/1, prepare_checkpoint/2, @@ -42,6 +43,7 @@ put_activity_id/2, block_tab/1, unblock_tab/1, + sync/0, fixtable/3, new_cr_format/1 ]). @@ -181,7 +183,7 @@ tmpid(Pid) -> %% Returns a list of participant transaction Tid's mnesia_down(Node) -> - %% Syncronously call needed in order to avoid + %% Synchronously call needed in order to avoid %% race with mnesia_tm's coordinator processes %% that may restart and acquire new locks. %% mnesia_monitor takes care of the sync @@ -205,6 +207,17 @@ block_tab(Tab) -> unblock_tab(Tab) -> req({unblock_tab, Tab}). +fixtable(Tab, Lock, Me) -> + case req({fixtable, [Tab,Lock,Me]}) of + error -> + exit({no_exists, Tab}); + Else -> + Else + end. + +sync() -> + req(sync). + doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=Sup}=State) -> receive {_From, {async_dirty, Tid, Commit, Tab}} -> @@ -250,25 +263,30 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= [{tid, Tid}, {prot, Protocol}]), mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), Commit = new_cr_format(Commit0), - Pid = - if - node(Tid#tid.pid) =:= node() -> - error({internal_error, local_node}); - Protocol =:= asym_trans orelse Protocol =:= sync_asym_trans -> - Args = [Protocol, tmpid(From), Tid, Commit, DiscNs, RamNs], - spawn_link(?MODULE, commit_participant, Args); - true -> %% *_sym_trans - reply(From, {vote_yes, Tid}), - nopid - end, - P = #participant{tid = Tid, - pid = Pid, - commit = Commit, - disc_nodes = DiscNs, - ram_nodes = RamNs, - protocol = Protocol}, - State2 = State#state{participants = gb_trees:insert(Tid,P,Participants)}, - doit_loop(State2); + case is_blocked(State#state.blocked_tabs, Commit) of + false -> + Pid = + if + node(Tid#tid.pid) =:= node() -> + error({internal_error, local_node}); + Protocol =:= asym_trans orelse Protocol =:= sync_asym_trans -> + Args = [Protocol, tmpid(From), Tid, Commit, DiscNs, RamNs], + spawn_link(?MODULE, commit_participant, Args); + true -> %% *_sym_trans + reply(From, {vote_yes, Tid}), + nopid + end, + P = #participant{tid = Tid, + pid = Pid, + commit = Commit, + disc_nodes = DiscNs, + ram_nodes = RamNs, + protocol = Protocol}, + State2 = State#state{participants = gb_trees:insert(Tid,P,Participants)}, + doit_loop(State2); + true -> + reply(From, {vote_no, Tid, {bad_commit, node()}}, State) + end; {Tid, do_commit} -> case gb_trees:lookup(Tid, Participants) of @@ -406,6 +424,10 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= reply(From, {info, gb_trees:values(Participants), gb_trees:to_list(Coordinators)}, State); + {From, transactions_count} -> + reply(From, {transactions_count, gb_trees:size(Participants), + gb_trees:size(Coordinators)}, State); + {mnesia_down, N} -> verbose("Got mnesia_down from ~p, reconfiguring...~n", [N]), reconfigure_coordinators(N, gb_trees:to_list(Coordinators)), @@ -449,6 +471,9 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= reply(From, ok, State2) end; + {From, sync} -> + reply(From, ok, State); + {From, {prepare_checkpoint, Cp}} -> Res = mnesia_checkpoint:tm_prepare(Cp), case Res of @@ -478,6 +503,28 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= doit_loop(State) end. +is_blocked([], _Commit) -> + false; +is_blocked([Tab|Tabs], #commit{ram_copies=RCs, disc_copies=DCs, + disc_only_copies=DOs, ext=Exts} = Commit) -> + is_blocked_tab(RCs, Tab) orelse + is_blocked_tab(DCs, Tab) orelse + is_blocked_tab(DOs, Tab) orelse + is_blocked_ext_tab(Exts, Tab) orelse + is_blocked(Tabs, Commit). + +is_blocked_tab([{{Tab,_},_,_}|_Ops], Tab) -> true; +is_blocked_tab([_|Ops], Tab) -> is_blocked_tab(Ops, Tab); +is_blocked_tab([],_) -> false. + +is_blocked_ext_tab([], _Tab) -> + false; +is_blocked_ext_tab(Exts, Tab) -> + case lists:keyfind(ext_copies, 1, Exts) of + false -> false; + {_, ExtOps} -> is_blocked_tab([Op || {_, Op} <- ExtOps], Tab) + end. + do_sync_dirty(From, Tid, Commit, _Tab) -> ?eval_debug_fun({?MODULE, sync_dirty, pre}, [{tid, Tid}]), Res = do_dirty(Tid, Commit), @@ -598,7 +645,7 @@ recover_coordinator(Tid, Etabs) -> recover_coordinator(Tid, Protocol, Outcome, Local, DiscNs, RamNs), ?eval_debug_fun({?MODULE, recover_coordinator, post}, [{tid, Tid}, {outcome, Outcome}, {prot, Protocol}]); - false -> %% When killed before store havn't been copied to + false -> %% When killed before store haven't been copied to ok %% to the new nested trans store. end catch _:Reason:Stacktrace -> @@ -881,7 +928,7 @@ try_again(_) -> no. %% We can only restart toplevel transactions. %% If a deadlock situation occurs in a nested transaction %% The whole thing including all nested transactions need to be -%% restarted. The stack is thus popped by a consequtive series of +%% restarted. The stack is thus popped by a consecutive series of %% exit({aborted, #cyclic{}}) calls restart(Mod, Tid, Ts, Fun, Args, Factor0, Retries0, Type, Why) -> @@ -1070,7 +1117,7 @@ dirty(Protocol, Item) -> async_dirty -> %% Send commit records to the other involved nodes, %% but do only wait for one node to complete. - %% Preferrably, the local node if possible. + %% Preferably, the local node if possible. ReadNode = val({Tab, where_to_read}), {WaitFor, FirstRes} = async_send_dirty(Tid, CR, Tab, ReadNode), @@ -1088,7 +1135,7 @@ dirty(Protocol, Item) -> %% This is the commit function, The first thing it does, %% is to find out which nodes that have been participating %% in this particular transaction, all of the mnesia_locker:lock* -%% functions insert the names of the nodes where it aquires locks +%% functions insert the names of the nodes where it acquires locks %% into the local shadow Store %% This function exacutes in the context of the user process t_commit(Type) -> @@ -1379,7 +1426,7 @@ multi_commit(read_only, _Maj = [], Tid, CR, _Store) -> multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> %% This lightweight commit protocol is used when all - %% the involved tables are replicated symetrically. + %% the involved tables are replicated symmetrically. %% Their storage types must match on each node. %% %% 1 Ask the other involved nodes if they want to commit @@ -1431,7 +1478,7 @@ multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> multi_commit(sync_sym_trans, _Maj = [], Tid, CR, Store) -> %% This protocol is the same as sym_trans except that it - %% uses syncronized calls to disk_log and syncronized commits + %% uses synchronized calls to disk_log and synchronized commits %% when several nodes are involved. {DiscNs, RamNs} = commit_nodes(CR, [], []), @@ -1754,7 +1801,7 @@ commit_participant(Protocol, Coord, Tid, Bin, C0, DiscNs, _RamNs) -> do_abort(Tid, Bin) when is_binary(Bin) -> %% Possible optimization: - %% If we want we could pass arround a flag + %% If we want we could pass around a flag %% that tells us whether the binary contains %% schema ops or not. Only if the binary %% contains schema ops there are meningful @@ -2121,6 +2168,14 @@ tr_status(Tid,Participant) -> false -> coordinator end. +get_transactions_count() -> + case req(transactions_count) of + {transactions_count, ParticipantsCount, CoordinatorsCount} -> + {ParticipantsCount, CoordinatorsCount}; + Error -> + Error + end. + get_info(Timeout) -> case whereis(?MODULE) of undefined -> @@ -2326,14 +2381,6 @@ do_stop(#state{coordinators = Coordinators}) -> mnesia_log:stop(), exit(shutdown). -fixtable(Tab, Lock, Me) -> - case req({fixtable, [Tab,Lock,Me]}) of - error -> - exit({no_exists, Tab}); - Else -> - Else - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%% %% System upgrade diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index b77be46e7ac4..c3fbad88ca1b 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -91,6 +91,7 @@ RELSYSDIR = $(RELEASE_PATH)/mnesia_test # FLAGS # ---------------------------------------------------- #ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -98,7 +99,7 @@ EBIN = . # Targets # ---------------------------------------------------- -tests debug opt: $(TARGET_FILES) +tests $(TYPES): $(TARGET_FILES) $(TARGET_FILES): $(HRL_FILES) diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl index 5e95e1dce75b..123d16023f11 100644 --- a/lib/mnesia/test/mnesia_SUITE.erl +++ b/lib/mnesia/test/mnesia_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -42,7 +42,7 @@ suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}]. %% Verify that Mnesia really is a distributed real-time DBMS. %% This is the test suite of the Mnesia DBMS. The test suite -%% covers many aspects of usage and is indended to be developed +%% covers many aspects of usage and is intended to be developed %% incrementally. The test suite is divided into a hierarchy of test %% suites where the leafs actually implements the test cases. %% The intention of each test case and sub test suite can be @@ -162,8 +162,8 @@ clean_up_suite(suite) -> []; clean_up_suite(Config) when is_list(Config)-> mnesia:kill(), - Slaves = mnesia_test_lib:lookup_config(nodenames, Config), - Nodes = lists:delete(node(), Slaves), + NodeNames = mnesia_test_lib:lookup_config(nodenames, Config), + Nodes = lists:delete(node(), NodeNames), rpc:multicall(Nodes, erlang, halt, []), ok. diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl index 4764f9e7c0e9..e079100a4cd0 100644 --- a/lib/mnesia/test/mnesia_atomicity_test.erl +++ b/lib/mnesia/test/mnesia_atomicity_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -111,7 +111,7 @@ explicit_abort_in_middle_of_trans(Config) when is_list(Config) -> %% Start a transaction on one node {success, [A]} = ?start_activities([Node1]), - %% store an object in the Tab - first tranaction + %% store an object in the Tab - first transaction ?start_transactions([A]), A ! fun() -> mnesia:write(Rec1A) % returns ok when successful @@ -136,7 +136,7 @@ explicit_abort_in_middle_of_trans(Config) when is_list(Config) -> %% Start a second transactionprocess, after the first failed {success, [B]} = ?start_activities([Node1]), - %% check, whether the interupted transaction had no influence on the db + %% check, whether the interrupted transaction had no influence on the db ?start_transactions([B]), B ! fun() -> ?match([Rec1A], mnesia:read({Tab, 1})), @@ -163,7 +163,7 @@ runtime_error_in_middle_of_trans(Config) when is_list(Config) -> %% Start a transaction on one node {success, [A]} = ?start_activities([Node1]), - %% store an object in the Tab - first tranaction + %% store an object in the Tab - first transaction ?start_transactions([A]), A ! fun() -> mnesia:write(Rec1A) % returns ok when successful @@ -188,7 +188,7 @@ runtime_error_in_middle_of_trans(Config) when is_list(Config) -> %% Start a second transactionprocess, after the first failed {success, [B]} = ?start_activities([Node1]), - %% check, whether the interupted transaction had no influence on the db + %% check, whether the interrupted transaction had no influence on the db ?start_transactions([B]), B ! fun() -> ?match([Rec1A], mnesia:read({Tab, 1})), @@ -215,7 +215,7 @@ kill_self_in_middle_of_trans(Config) when is_list(Config) -> %% Start a transaction on one node {success, [A]} = ?start_activities([Node1]), - %% store an object in the Tab - first tranaction + %% store an object in the Tab - first transaction ?start_transactions([A]), A ! fun() -> mnesia:write(Rec1A) % returns ok when successful @@ -244,7 +244,7 @@ kill_self_in_middle_of_trans(Config) when is_list(Config) -> %% Start a second transactionprocess, after the first failed {success, [B]} = ?start_activities([Node1]), - %% check, whether the interupted transaction had no influence on the db + %% check, whether the interrupted transaction had no influence on the db ?start_transactions([B]), B ! fun() -> ?match([Rec1A], mnesia:read({Tab, 1})), @@ -271,7 +271,7 @@ throw_in_middle_of_trans(Config) when is_list(Config) -> %% Start a transaction on one node {success, [A]} = ?start_activities([Node1]), - %% store an object in the Tab - first tranaction + %% store an object in the Tab - first transaction ?start_transactions([A]), A ! fun() -> mnesia:write(Rec1A) % returns ok when successful @@ -297,7 +297,7 @@ throw_in_middle_of_trans(Config) when is_list(Config) -> %% Start a second transactionprocess, after the first failed {success, [B]} = ?start_activities([Node1]), - %% check, whether the interupted transaction had no influence on the db + %% check, whether the interrupted transaction had no influence on the db ?start_transactions([B]), B ! fun() -> ?match([Rec1A], mnesia:read({Tab, 1})), @@ -542,7 +542,7 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> io:format("waiting for A (~p on ~p) to be in the queue ~n", [A, [N1, N2]]), wait_for_a(A, [N1, N2]), - io:format("Queus ~p~n", + io:format("Queues ~p~n", [[{N,rpc:call(N, mnesia, system_info, [lock_queue])} || N <- Nodes]]), KillNode = node(B), @@ -743,7 +743,7 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> Wait(Wait), A ! go_ahead, - %% the sticky write doesnt work on remote nodes !!! + %% the sticky write doesn't work on remote nodes !!! ExpectedMsg = case RestartOp of sw when ReplicaNeed == two -> @@ -765,7 +765,7 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> %% the expected result depends on the transaction of - %% fun A - when that doesnt change the object in the + %% fun A - when that doesn't change the object in the %% table (e.g. it is a read) then the predefined %% value {Tabname, 1, c} is expected to be the result here diff --git a/lib/mnesia/test/mnesia_config_backup.erl b/lib/mnesia/test/mnesia_config_backup.erl index 239101ca92db..a39e41f63da1 100644 --- a/lib/mnesia/test/mnesia_config_backup.erl +++ b/lib/mnesia/test/mnesia_config_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -36,7 +36,7 @@ %% write an own module the same interface as mnesia_backup and %% configure Mnesia so the alternate module performs the actual %% accesses to the backup media. This means that the user may put -%% the backup on medias that Mnesia does not know about, possibly +%% the backup on media that Mnesia does not know about, possibly %% on hosts where Erlang is not running. %% %% The OpaqueData argument is never interpreted by other parts of diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl index 7f584e35f902..4ba560e25d36 100644 --- a/lib/mnesia/test/mnesia_config_test.erl +++ b/lib/mnesia/test/mnesia_config_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -106,7 +106,7 @@ all() -> dump_log_load_regulation, {group, dump_log_thresholds}, dump_log_update_in_place, event_module, backend_plugin_registration, - inconsistent_database, max_wait_for_decision, + inconsistent_database, %% max_wait_for_decision, send_compressed, app_test, {group, schema_config}, unknown_config]. @@ -937,7 +937,7 @@ start_first_one_disc_less_then_two_more_disc_less(Config) when is_list(Config) - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% schema_location_and_extra_db_nodes_combinations(doc)-> - ["Test schema loaction and extra_db_nodes combinations."]; + ["Test schema location and extra_db_nodes combinations."]; schema_location_and_extra_db_nodes_combinations(suite) -> []; schema_location_and_extra_db_nodes_combinations(Config) when is_list(Config) -> [N1, N2] = Nodes = ?init(2, Config), diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl index 46bafaf65c9b..73093b9227d5 100644 --- a/lib/mnesia/test/mnesia_consistency_test.erl +++ b/lib/mnesia/test/mnesia_consistency_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -27,7 +27,6 @@ all/0, groups/0]). -export([consistency_after_change_table_copy_type/1, - consistency_after_rename_of_node/1, consistency_after_restart_1_ram/1, consistency_after_restart_1_disc/1, consistency_after_restart_1_disc_only/1, @@ -110,9 +109,8 @@ all() -> {group, consistency_after_del_replica}, {group, consistency_after_move_replica}, {group, consistency_after_transform_table}, - consistency_after_change_table_copy_type, + %% consistency_after_change_table_copy_type, {group, consistency_after_restore}, - consistency_after_rename_of_node, {group, checkpoint_retainer_consistency}, {group, backup_consistency}]. @@ -341,7 +339,7 @@ receive_messages(ListOfMsgs) -> ?verbose("I (~p) got msg ~p from ~p ~n", [self(),Msg, Pid]), [{Pid, Msg} | receive_messages(ListOfMsgs -- [Msg])] end; - Else -> ?warning("Recevied unexpected Msg~n ~p ~n", [Else]) + Else -> ?warning("Received unexpected Msg~n ~p ~n", [Else]) after timer:minutes(3) -> ?error("Timeout in receive msgs while waiting for ~p~n", [ListOfMsgs]) @@ -381,7 +379,7 @@ consistency_after_restart(ReplicaType, NodeConfig, Config) -> TpcbConfig = tpcb_config(ReplicaType, NodeConfig, Nodes, [Node1]), mnesia_tpcb:init(TpcbConfig), A ! fun () -> mnesia_tpcb:run(TpcbConfig) end, - timer:sleep(timer:seconds(10)), + timer:sleep(timer:seconds(3)), mnesia_test_lib:kill_mnesia([Node1]), %% Start and wait for tables to be loaded on all nodes timer:sleep(timer:seconds(3)), @@ -408,7 +406,7 @@ consistency_after_dump_tables(ReplicaType, NodeConfig, Config) -> TpcbConfig = tpcb_config(ReplicaType, NodeConfig, Nodes, []), mnesia_tpcb:init(TpcbConfig), A ! fun() -> mnesia_tpcb:run(TpcbConfig) end, - timer:sleep(timer:seconds(10)), + timer:sleep(timer:seconds(3)), ?match({atomic, ok}, rpc:call(Node1, mnesia, dump_tables, [[branch, teller, account, history]])), mnesia_tpcb:stop(), @@ -459,7 +457,7 @@ consistency_after_add_replica(ReplicaType, NodeConfig, Config) -> TpcbConfig = tpcb_config(ReplicaType, NodeConfig, Nodes, []), mnesia_tpcb:init(TpcbConfig), A ! fun () -> mnesia_tpcb:run(TpcbConfig) end, - timer:sleep(timer:seconds(10)), + timer:sleep(timer:seconds(2)), ?match({atomic, ok}, mnesia:add_table_copy(account, AddNode, ReplicaType)), mnesia_tpcb:stop(), ?match(ok, mnesia_tpcb:verify_tabs()), @@ -501,7 +499,7 @@ consistency_after_del_replica(ReplicaType, NodeConfig, Config) -> TpcbConfig = tpcb_config(ReplicaType, NodeConfig, Nodes, []), mnesia_tpcb:init(TpcbConfig), A ! fun () -> mnesia_tpcb:run(TpcbConfig) end, - timer:sleep(timer:seconds(10)), + timer:sleep(timer:seconds(3)), ?match({atomic, ok}, mnesia:del_table_copy(account, Node2)), mnesia_tpcb:stop(), ?match(ok, mnesia_tpcb:verify_tabs()), @@ -543,7 +541,7 @@ consistency_after_move_replica(ReplicaType, NodeConfig, Config) -> TpcbConfig = tpcb_config(ReplicaType, NodeConfig, Nodes -- [Node2], []), mnesia_tpcb:init(TpcbConfig), A ! fun () -> mnesia_tpcb:run(TpcbConfig) end, - timer:sleep(timer:seconds(10)), + timer:sleep(timer:seconds(3)), ?match({atomic, ok}, mnesia:move_table_copy(account, Node1, Node2)), ?log("First move completed from node ~p to ~p ~n", [Node1, Node2]), ?match({atomic, ok}, mnesia:move_table_copy(account, Node2, Node1)), @@ -585,8 +583,8 @@ consistency_after_transform_table(Type, Config) -> [k,a,n]) || Tab <- Tabs]), [?match([k,a,n], mnesia:table_info(Tab, attributes)) || Tab <- Tabs], - Filter = fun(Tab) -> mnesia:foldl(fun(A, Acc) when size(A) == 3 -> [A|Acc]; - (A, Acc) when size(A) == 4 -> Acc + Filter = fun(Tab) -> mnesia:foldl(fun(A, Acc) when tuple_size(A) == 3 -> [A|Acc]; + (A, Acc) when tuple_size(A) == 4 -> Acc end, [], Tab) end, @@ -638,7 +636,7 @@ consistency_after_fallback_3_disc_only(Config) when is_list(Config) -> consistency_after_fallback(ReplicaType, NodeConfig, Config) -> put(mnesia_test_verbose, true), %%?verbose("Starting consistency_after_fallback2 at ~p~n", [self()]), - Delay = 5, + Delay = 3, Nodes = ?acquire_nodes(NodeConfig, [{tc_timeout, timer:minutes(10)} | Config]), Node1 = hd(Nodes), %%?verbose("Mnesia info: ~p~n", [mnesia:info()]), @@ -821,11 +819,6 @@ restore_verify_tabs([Tab | R]) -> restore_verify_tabs([]) -> ok. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -consistency_after_rename_of_node(doc) -> - ["Skipped because it is an unimportant case."]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -867,7 +860,7 @@ updates_during_checkpoint_activation_3_disc_only(Config) when is_list(Config) -> updates_during_checkpoint_activation(ReplicaType,NodeConfig,Config) -> %%?verbose("updates_during_checkpoint_activation2 at ~p~n", [self()]), - Delay = 5, + Delay = 2, Nodes = ?acquire_nodes(NodeConfig, Config), Node1 = hd(Nodes), %%?verbose("Mnesia info: ~p~n", [mnesia:info()]), @@ -922,7 +915,7 @@ updates_during_checkpoint_iteration_2_disc_only(Config) when is_list(Config) -> updates_during_checkpoint_iteration(ReplicaType,NodeConfig,Config) -> %?verbose("updates_during_checkpoint_iteration2 at ~p~n", [self()]), - Delay = 5, + Delay = 2, Nodes = ?acquire_nodes(NodeConfig, Config), Node1 = hd(Nodes), %?verbose("Mnesia info: ~p~n", [mnesia:info()]), diff --git a/lib/mnesia/test/mnesia_dbn_meters.erl b/lib/mnesia/test/mnesia_dbn_meters.erl index 407d7c65b8b9..d66da2fb6bf4 100644 --- a/lib/mnesia/test/mnesia_dbn_meters.erl +++ b/lib/mnesia/test/mnesia_dbn_meters.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -64,12 +64,12 @@ start(Config,Nodes,Meters) -> config(one_ram_only,[Single|_]) -> [{ram_copies,[Single]}]; -config(ram_and_ram,[Master|[Slave|_]]) -> - [{ram_copies,[Master,Slave]}]; +config(ram_and_ram,[N1,N2|_]) -> + [{ram_copies,[N1,N2]}]; config(one_disc_only,[Single|_]) -> [{disc_copies,[Single]}]; -config(disc_and_disc,[Master|[Slave|_]]) -> - [{disc_copies,[Master,Slave]}]; +config(disc_and_disc,[N1,N2|_]) -> + [{disc_copies,[N1,N2]}]; config(Config,Nodes) -> io:format(" Config ~p not supported or too few nodes ~p given~n",[Config,Nodes]). diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl index e883931e36f3..e684faf7b050 100644 --- a/lib/mnesia/test/mnesia_dirty_access_test.erl +++ b/lib/mnesia/test/mnesia_dirty_access_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -844,12 +844,12 @@ del_table(CallFrom, DelNode, [Node1, Node2, Node3]) -> Pid3 = spawn_link(Node3, ?MODULE, update_trans, [Tab, 3, 0]), - dbg:tracer(process, {fun(Msg,_) -> tracer(Msg) end, void}), + %% dbg:tracer(process, {fun(Msg,_) -> tracer(Msg) end, void}), %% dbg:n(Node2), %% dbg:n(Node3), %% dbg:tp('_', []), %% dbg:tpl(dets, [timestamp]), - dbg:p(Pid1, [m,c,timestamp]), + %% dbg:p(Pid1, [m,c,timestamp]), ?match({atomic, ok}, rpc:call(CallFrom, mnesia, del_table_copy, [Tab, DelNode])), @@ -872,17 +872,6 @@ del_table(CallFrom, DelNode, [Node1, Node2, Node3]) -> verify_oids(Tab, Node1, Node2, Node3, R1, R2, R3), ?verify_mnesia([Node1, Node2, Node3], []). -tracer({trace_ts, _, send, Msg, Pid, {_,S,Ms}}) -> - io:format("~p:~p ~p >> ~w ~n",[S,Ms,Pid,Msg]); -tracer({trace_ts, _, 'receive', Msg, {_,S,Ms}}) -> - io:format("~p:~p << ~w ~n",[S,Ms,Msg]); - - -tracer(Msg) -> - io:format("UMsg ~p ~n",[Msg]), - ok. - - add_table_copy_1(suite) -> []; add_table_copy_1(Config) when is_list(Config) -> @@ -929,6 +918,22 @@ add_table(CallFrom, AddNode, [Node1, Node2, Node3], Def) -> verify_oids(Tab, Node1, Node2, Node3, R1, R2, R3), ?verify_mnesia([Node1, Node2, Node3], []). + +tracer({trace_ts, From, send, Msg, To, {_,S,Ms}}) -> + io:format("~p:~p ~p(~p) >>~p ~w ~n",[S,Ms,From,node(From),To,Msg]); +tracer({trace_ts, Pid, 'receive', Msg, {_,S,Ms}}) -> + io:format("~p:~p ~p(~p) << ~w ~n",[S,Ms,Pid,node(Pid),Msg]); + +tracer({trace_ts, Pid, call, MFA, ST, {_,S,Ms}}) -> + io:format("~p:~p ~p(~p) ~w ~w ~n",[S,Ms,Pid,node(Pid),MFA, ST]); +tracer({trace_ts, Pid, return_from, MFA, Ret, {_,S,Ms}}) -> + io:format("~p:~p ~p(~p) ~w => ~w ~n",[S,Ms,Pid,node(Pid),MFA,Ret]); + +tracer(Msg) -> + io:format("UMsg ~p ~n",[Msg]), + ok. + + move_table_copy_1(suite) -> []; move_table_copy_1(Config) when is_list(Config) -> [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl index ccbfdc9738ef..986d0efcb542 100644 --- a/lib/mnesia/test/mnesia_durability_test.erl +++ b/lib/mnesia/test/mnesia_durability_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -503,7 +503,7 @@ load_when_down_from_all_other_replica_nodes(Config) when is_list(Config) -> ?match([], mnesia_test_lib:kill_mnesia([N2])), ?match({atomic,ok},rpc:call(N3,mnesia,transaction,[Write_one,[33,33]])), ?match([], mnesia_test_lib:kill_mnesia([N3])), - ?verbose("Mnesia stoped on all three nodes.~n",[]), + ?verbose("Mnesia stopped on all three nodes.~n",[]), %%Start Mnesia on N3; wait for 'test_rec' table to load ?match(ok, rpc:call(N3, mnesia, start, [])), @@ -528,7 +528,7 @@ load_when_down_from_all_other_replica_nodes(Config) when is_list(Config) -> late_load_transforms_into_disc_load(doc) -> ["Difficult case that needs instrumentation of Mnesia.", "A table is force loaded, and Mnesia decides to load it from another ", - "Mnesia node because it is avaliable there. The other Mnesia node then ", + "Mnesia node because it is available there. The other Mnesia node then ", "dies in mid copy which shall make the first Mnesia node to really ", "force load from disc.", "Check this by starting N1 and N2 and replicating a table between ", @@ -1028,7 +1028,7 @@ master_nodes(Config) when is_list(Config) -> ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 2000])), %% Test 6: Force load on table that couldn't be loaded due to master - %% table setttings, loads other active replicas i.e. from C + %% table settings, loads other active replicas i.e. from C ?match(yes, rpc:call(A, mnesia, force_load_table, [Tab])), ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])), @@ -1041,7 +1041,7 @@ master_nodes(Config) when is_list(Config) -> ?match([{Tab, 1, update_2}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])), %% Test 7: Master [B] and B is down the table should not be loaded, - %% force_load when there are no active replicas availible + %% force_load when there are no active replicas available %% should generate a load of a local table ?match(ok, rpc:call(A, mnesia, set_master_nodes, [Tab, [B]])), @@ -1138,7 +1138,7 @@ master_on_non_local_tables(Config) when is_list(Config) -> remote_force_load_with_local_master_node(doc) -> ["Force load a table on a remote node while the ", "local node is down. Start the local node and ", - "verfify that the tables is loaded from disc locally " + "verify that the tables is loaded from disc locally " "if the local node has itself as master node and ", "the remote node has both the local and remote node ", "as master nodes"]; @@ -1345,13 +1345,13 @@ dump_ram_copies(Config) when is_list(Config) -> %% start Mnesia only on node 3 ?verbose("starting mnesia on Node3~n",[]), - %% test_lib:mnesia_start doesnt work, because it waits + %% test_lib:mnesia_start doesn't work, because it waits %% for the schema on all nodes ... ??? ?match(ok,rpc:call(Node3,mnesia,start,[]) ), ?match(ok,rpc:call(Node3,mnesia,wait_for_tables, [[Tab],timer:seconds(30)] ) ), - %% node3 shall have the conents of the dump + %% node3 shall have the contents of the dump cross_check_tables([C],Tab,{[{Tab,1,4711}],[{Tab,2,42}],[{Tab,3,256}]}), %% start Mnesia on the other 2 nodes, too @@ -1569,7 +1569,7 @@ receive_messages(ListOfMsgs) -> [{Pid, Msg} | receive_messages(ListOfMsgs -- [Msg])] end; - Else -> ?warning("Recevied unexpected Msg~n ~p ~n", [Else]) + Else -> ?warning("Received unexpected Msg~n ~p ~n", [Else]) after timer:seconds(40) -> ?error("Timeout in receive msgs while waiting for ~p~n", [ListOfMsgs]) diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl index 45b11f2f3f27..ec0d3ca3e0b2 100644 --- a/lib/mnesia/test/mnesia_evil_backup.erl +++ b/lib/mnesia/test/mnesia_evil_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2017. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -141,7 +141,7 @@ global_backup_checkpoint(Config) when is_list(Config) -> ?match(ok, mnesia:backup_checkpoint(cp_name, File)), ?match({error, _}, mnesia:backup_checkpoint(cp_name_nonexist, File)), ?match(ok, mnesia:backup_checkpoint(cp_name, File2, mnesia_backup)), - ?match({error, _}, file:delete(File)), + ?match(ok, file:delete(File)), ?match(ok, file:delete(File2)), ?verify_mnesia(Nodes, []). @@ -761,7 +761,10 @@ sops_with_checkpoint(Config) when is_list(Config) -> ?match(ok, mnesia:dirty_write({Tab,8,-8})), ?match({atomic,ok}, mnesia:delete_table(Tab)), + ?match(true, filelib:is_file(File2)), ?match({error,_}, mnesia:backup_checkpoint(cp2, File2)), + ?match(true, filelib:is_file(File2)), + ?match({'EXIT',_}, mnesia:dirty_write({Tab,9,-9})), ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])), @@ -772,6 +775,7 @@ sops_with_checkpoint(Config) when is_list(Config) -> end end, [Test(N) || N <- mnesia:dirty_all_keys(Tab)], + ok = file:delete(File2), ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])), %% Mnesia crashes when deleting a table during backup diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 1dcb0ac678c0..3a697ba16de4 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -697,7 +697,7 @@ verify_ll_queue(N) -> ?match(granted,mnesia_controller:block_controller()), case mnesia_controller:get_info(1000) of {info,{state,_,true,[],_Loader,[],[],[],_,_,_,_,_,_}} -> - %% Very slow SMP machines havn't loaded it yet.. + %% Very slow SMP machines haven't loaded it yet.. mnesia_controller:unblock_controller(), timer:sleep(10), verify_ll_queue(N-1); @@ -1344,7 +1344,7 @@ offline_set_master_nodes(Config) when is_list(Config) -> ?verify_mnesia(Nodes, []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Syncronize table with log or disc +%% Synchronize table with log or disc %% %% Dump ram tables on disc @@ -2140,7 +2140,7 @@ test_ext_sub(Tab1, Tab2, Tab3) -> subscribe_standard(doc) -> - ["Tests system events and the orignal table events"]; + ["Tests system events and the original table events"]; subscribe_standard(suite) -> []; subscribe_standard(Config) when is_list(Config)-> [N1, N2]=?acquire_nodes(2, Config), diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl index 3bbb6e4d7780..53062ca3eb60 100644 --- a/lib/mnesia/test/mnesia_examples_test.erl +++ b/lib/mnesia/test/mnesia_examples_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -44,7 +44,8 @@ end_per_testcase(Func, Conf) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> - [bup, company, meter, {group, tpcb}]. + [bup, %% company, + meter, {group, tpcb}]. groups() -> [{tpcb, [], diff --git a/lib/mnesia/test/mnesia_frag_test.erl b/lib/mnesia/test/mnesia_frag_test.erl index 7b37fcb6849d..c390ae3508a3 100644 --- a/lib/mnesia/test/mnesia_frag_test.erl +++ b/lib/mnesia/test/mnesia_frag_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2018. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -185,7 +185,7 @@ nice_multi(Config) when is_list(Config) -> ?match([{Node2, 2}, {Node1, 2}], frag_dist(Tab)), %% And connect another table to it, via a foreign key - TabF = frag_slave, + TabF = frag_node, PropsF = [{foreign_key, {Tab, foreign_id}}], DefF = [{frag_properties, PropsF}, {attributes, [id, foreign_id]}], @@ -322,7 +322,7 @@ nice_access(Config) when is_list(Config) -> [frag_write(Tab, {Tab, Id, Id}) || Id <- lists:seq(1, 400)], %% And connect another table to it, via a foreign key - TabF = frag_access_slave, + TabF = frag_access_extra, PropsF = [{foreign_key, {Tab, val}}], DefF = [{frag_properties, PropsF}, {index, [val]}], diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 601f46e45f7d..759735a7ea02 100644 --- a/lib/mnesia/test/mnesia_isolation_test.erl +++ b/lib/mnesia/test/mnesia_isolation_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2022. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -608,7 +608,7 @@ sticky_sync(Config) when is_list(Config) -> %% In first transaction we initialise {dc, I} record with value 0 First = fun() -> %% Do a lot of writes into ram copies table - %% which on the Slave in do_commit will be + %% which on the N2 in do_commit will be %% processed first lists:foreach(fun(J) -> ok = mnesia:write(ec, {ec, J, 0}, write) end, lists:seq(1, 750)), @@ -630,11 +630,6 @@ sticky_sync(Config) when is_list(Config) -> %% Fill 1000 dc records. At the end all dc records should have value 1. {Time, ok} = timer:tc(fun() -> lists:foreach(TestFun, lists:seq(1,200)) end), - io:format("200 trans done in ~p ~n",[Time div (1000000)]), - case (Time div (1000000)) < 20 of - true -> lists:foreach(TestFun, lists:seq(201,1000)); - false -> ignore %% Some virtual test machines are really slow.. - end, io:format("Written, check content~n",[]), All = fun() -> mnesia:select(dc, [ {{dc, '_', 0}, [] ,['$_']} ]) end, ?match({atomic, []}, rpc:call(N1, mnesia, sync_transaction, [All])), @@ -967,7 +962,7 @@ snmp_open_table(Config) when is_list(Config) -> A ! end_trans, %% Kill A, locks should be released ?match_receive({A,{atomic,end_trans}}), - %% Locks released! op should be exec. Can take a while (thats the timeout) + %% Locks released! op should be exec. Can take a while (that's the timeout) receive Msg -> ?match({Pid, {atomic, ok}}, Msg) after @@ -999,7 +994,7 @@ snmp_close_table(Config) when is_list(Config) -> A ! end_trans, %% Kill A, locks should be released ?match_receive({A,{atomic,end_trans}}), - %% Locks released! op should be exec. Can take a while (thats the timeout) + %% Locks released! op should be exec. Can take a while (that's the timeout) receive Msg -> ?match({Pid, {atomic, ok}}, Msg) after @@ -1729,7 +1724,7 @@ write_shadows(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:transaction(Fun1)), Fun2 = fun() -> - %% write shadow old write - is the confirmed value visable + %% write shadow old write - is the confirmed value visible %% in the shadow ? ?match([RecA1], mnesia:read({Tab, a})), ?match([RecA1], mnesia:wread({Tab, a})), @@ -1738,14 +1733,14 @@ write_shadows(Config) when is_list(Config) -> ?match([RecA1], mnesia:index_match_object(PatA1, ValPos)), ?match([RecA1], mnesia:index_read(Tab, 1, ValPos)), - %% write shadow new write - is a new value visable instead + %% write shadow new write - is a new value visible instead %% of the old value ? ?match(ok, mnesia:write(RecA2)), ?match([RecA2], mnesia:read({Tab, a})), ?match([RecA2], mnesia:wread({Tab, a})), ?match([], mnesia:match_object(PatA1)), %% delete shadow old but not new write - ?match([RecA2], mnesia:match_object(PatA2)), %% is the new value visable + ?match([RecA2], mnesia:match_object(PatA2)), %% is the new value visible ?match([a], mnesia:all_keys(Tab)), ?match([RecA2], mnesia:index_match_object(PatA2, ValPos)), @@ -1798,7 +1793,7 @@ delete_shadows(Config) when is_list(Config) -> ?match([], mnesia:index_match_object(PatA1, ValPos)), ?match([], mnesia:index_read(Tab, 1, ValPos)), - %% delete shadow old but not new write - is the new value visable + %% delete shadow old but not new write - is the new value visible %% when the old one was deleted ? ?match(ok, mnesia:write(RecA2)), @@ -1883,7 +1878,7 @@ write_delete_shadows_bag(Config) when is_list(Config) -> ?match([], mnesia:index_match_object(PatA1, ValPos)), ?match([], mnesia:index_read(Tab, 1, ValPos)), - %% delete shadow old but not new write - are both new value visable + %% delete shadow old but not new write - are both new value visible %% when the old one was deleted ? ?match(ok, mnesia:write(RecA2)), ?match(ok, mnesia:write(RecA3)), @@ -2143,7 +2138,7 @@ removed_resources([_N1,N2,N3], DeleteRes) -> nasty(suite) -> []; nasty(doc) -> - ["Tries to fullfill a rather nasty locking scenario, where we have had " + ["Tries to fulfill a rather nasty locking scenario, where we have had " "bugs, the testcase tries a combination of locks in locker queue"]; %% This testcase no longer works as it was intended to show errors when diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl index b5749408f8d7..498550c8ecb9 100644 --- a/lib/mnesia/test/mnesia_recovery_test.erl +++ b/lib/mnesia/test/mnesia_recovery_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -28,7 +28,6 @@ -export([coord_dies/1, after_full_disc_partition/1, disc_less/1, garb_decision/1, - system_upgrade/1, delete_during_start/1, no_master_2/1, no_master_3/1, one_master_2/1, one_master_3/1, two_master_2/1, two_master_3/1, all_master_2/1, @@ -120,9 +119,9 @@ all() -> [{group, mnesia_down}, {group, explicit_stop}, coord_dies, {group, schema_trans}, {group, async_dirty}, {group, sync_dirty}, {group, sym_trans}, - {group, asym_trans}, after_full_disc_partition, - {group, after_corrupt_files}, disc_less, garb_decision, - system_upgrade]. + {group, asym_trans}, %% after_full_disc_partition, + {group, after_corrupt_files}, disc_less, garb_decision + ]. groups() -> [{schema_trans, [], @@ -1341,7 +1340,7 @@ garb_of_decisions(Kill, Nodes, Tid_list, Trans_res) -> case length(Tid_list) of 1 -> %% If there was only one transaction, it should be logged as - %% comitted on every node! + %% committed on every node! [Tid1] = Tid_list, verify_garb_transient_logs(Nodes, [Tid1], committed); 2 -> @@ -1455,7 +1454,7 @@ receive_messages(ListOfMsgs, File, Line) -> [{Pid, Msg} | receive_messages(ListOfMsgs -- [Msg], File, Line)] end; Else -> mnesia_test_lib:log("<>WARNING<>~n" - "Recevied unexpected or bad formatted msg~n ~p ~n" + "Received unexpected or bad formatted msg~n ~p ~n" "While waiting for ~p~n", [Else, ListOfMsgs], File, Line), receive_messages(ListOfMsgs, File, Line) @@ -1645,9 +1644,6 @@ disc_less(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -system_upgrade(doc) -> - ["Test on-line and off-line upgrade of the Mnesia application"]. - garb_decision(doc) -> ["Test that decisions are garbed correctly."]; garb_decision(suite) -> []; diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index 979491502659..6bf44295b367 100644 --- a/lib/mnesia/test/mnesia_test_lib.erl +++ b/lib/mnesia/test/mnesia_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -44,7 +44,7 @@ %%% specified in the Config, the test case is skipped. If there %%% was enough node names in the Config, X of them are selected %%% and if some of them happens to be down they are restarted -%%% via the slave module. When all nodes are up and running a +%%% via the peer module. When all nodes are up and running a %%% disk resident schema is created on all nodes and Mnesia is %%% started a on all nodes. This means that all test cases may %%% assume that Mnesia is up and running on all acquired nodes. @@ -62,7 +62,7 @@ %%% test(TestCases) %%% %%% Run parts of the test suite. Uses test/2. -%%% Reads Config from mnesia_test.config and starts them if neccessary. +%%% Reads Config from mnesia_test.config and starts them if necessary. %%% Kills Mnesia and wipes out the Mnesia directories as a starter. %%% %%% test(TestCases, Config) @@ -97,9 +97,7 @@ select_nodes/4, init_nodes/3, error/4, - slave_start_link/0, - slave_start_link/1, - slave_sup/0, + node_sup/0, start_mnesia/1, start_mnesia/2, @@ -236,26 +234,14 @@ mk_nodes(N, Nodes) when N > 0 -> mk_node(N, Name, Host) -> list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). -slave_start_link() -> - slave_start_link(node()). +node_start_link(Host, Name) -> + node_start_link(Host, Name, 10). -slave_start_link(Node) -> - [Local, Host] = node_to_name_and_host(Node), - Count = erlang:unique_integer([positive]), - List = [Local, "_", Count], - Name = list_to_atom(lists:concat(List)), - slave_start_link(list_to_atom(Host), Name). - -slave_start_link(Host, Name) -> - slave_start_link(Host, Name, 10). - -slave_start_link(Host, Name, Retries) -> +node_start_link(Host, Name, Retries) -> Debug = atom_to_list(mnesia:system_info(debug)), - Args = "-mnesia debug " ++ Debug ++ - " -pa " ++ - filename:dirname(code:which(?MODULE)) ++ - " -pa " ++ - filename:dirname(code:which(mnesia)), + Args = ["-mnesia", "debug", Debug, + "-pa", filename:dirname(code:which(?MODULE)), + "-pa", filename:dirname(code:which(mnesia))], case starter(Host, Name, Args) of {ok, NewNode} -> ?match(pong, net_adm:ping(NewNode)), @@ -264,22 +250,23 @@ slave_start_link(Host, Name, Retries) -> ok = rpc:call(NewNode, file, set_cwd, [Cwd]), true = rpc:call(NewNode, code, set_path, [Path]), ok = rpc:call(NewNode, error_logger, tty, [false]), - spawn_link(NewNode, ?MODULE, slave_sup, []), + spawn_link(NewNode, ?MODULE, node_sup, []), rpc:multicall([node() | nodes()], global, sync, []), {ok, NewNode}; {error, Reason} when Retries == 0-> {error, Reason}; {error, Reason} -> - io:format("Could not start slavenode ~p ~p retrying~n", + io:format("Could not start node ~p ~p retrying~n", [{Host, Name, Args}, Reason]), timer:sleep(500), - slave_start_link(Host, Name, Retries - 1) + node_start_link(Host, Name, Retries - 1) end. starter(Host, Name, Args) -> - slave:start(Host, Name, Args). + {ok, _, Node} = peer:start(#{host => Host, name => Name, args => Args}), + {ok, Node}. -slave_sup() -> +node_sup() -> process_flag(trap_exit, true), receive {'EXIT', _, _} -> @@ -722,7 +709,7 @@ kill_tc(Pid, Time) -> "in ~p min~n", [Time div (1000*60)]), Files = mnesia_lib:dist_coredump(), ?log("Cores dumped to:~n ~p~n", [Files]), - %% Genarate erlang crashdumps. + %% Generate erlang crashdumps. %% GenDump = fun(Node) -> %% File = "CRASH_" ++ atom_to_list(Node) ++ ".dump", %% rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP", File]), @@ -759,7 +746,7 @@ init_nodes([Node | Nodes], File, Line) -> [Node | init_nodes(Nodes, File, Line)]; pang -> [Name, Host] = node_to_name_and_host(Node), - case slave_start_link(Host, Name) of + case node_start_link(Host, Name) of {ok, Node1} -> Path = code:get_path(), true = rpc:call(Node1, code, set_path, [Path]), diff --git a/lib/mnesia/test/mnesia_tpcb.erl b/lib/mnesia/test/mnesia_tpcb.erl index fb39ee321d93..6a78d4f1d07f 100644 --- a/lib/mnesia/test/mnesia_tpcb.erl +++ b/lib/mnesia/test/mnesia_tpcb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -35,7 +35,7 @@ %% a database system. %% %% The definition of the TPC-B states lots of detailed rules and -%% conditions that must be fullfilled, e.g. how the ACID (atomicity, +%% conditions that must be fulfilled, e.g. how the ACID (atomicity, %% consistency, isolation and durability) properties are verified, %% how the random numbers must be distributed, minimum sizes of %% the different types of records, minimum duration of the benchmark, diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl index 65206a85af48..f1901b38f569 100644 --- a/lib/mnesia/test/mnesia_trans_access_test.erl +++ b/lib/mnesia/test/mnesia_trans_access_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -28,7 +28,7 @@ -export([write/1, read/1, wread/1, delete/1, delete_object_bag/1, delete_object_set/1, - match_object/1, select/1, select14/1, all_keys/1, transaction/1, + match_object/1, select/1, select14/1, all_keys/1, transaction/1, transaction_counters/1, basic_nested/1, mix_of_nested_activities/1, nested_trans_both_ok/1, nested_trans_child_dies/1, nested_trans_parent_dies/1, nested_trans_both_dies/1, @@ -65,7 +65,7 @@ end_per_testcase(Func, Conf) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> [write, read, wread, delete, delete_object_bag, delete_object_set, - match_object, select, select14, all_keys, transaction, + match_object, select, select14, all_keys, transaction, transaction_counters, {group, nested_activities}, {group, index_tabs}, {group, index_lifecycle}]. @@ -546,6 +546,28 @@ transaction(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +transaction_counters(suite) -> []; +transaction_counters(Config) -> + Nodes = ?acquire_nodes(1, Config), + + {atomic, {{Participants1, Coordinators1}, {Participants2, Coordinators2}}} = + mnesia:transaction(fun get_transactions_counters/0), + + ?match(Coordinators1, Coordinators2), + ?match(Coordinators1, 1), + ?match(Participants1, Participants2), + ?match(Participants1, 0), + + ?verify_mnesia(Nodes, []). + +get_transactions_counters() -> + {count_sides(mnesia_tm:get_transactions()), mnesia_tm:get_transactions_count()}. + +count_sides(TransactionsList) -> + lists:foldl( + fun({_Tid, _Pid, participant}, {Participants, Coordinators}) -> {Participants + 1, Coordinators}; + ({_Tid, _Pid, coordinator}, {Participants, Coordinators}) -> {Participants, Coordinators + 1} + end, {0, 0}, TransactionsList). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -722,7 +744,7 @@ nested_transactions(Config, Child, Father) -> {[{Tab, father, not_updated}], [{Tab, child, not_updated}]} end, - %% Syncronize things!! + %% Synchronize things!! ?match({atomic, ok}, mnesia:sync_transaction(fun() -> mnesia:write({Tab, sync, sync}) end)), ?match(ChildRes, rpc:call(Node1, mnesia, dirty_read, [{Tab, child}])), @@ -1196,7 +1218,7 @@ index_delete_object(Config) when is_list(Config) -> ?verify_mnesia(Nodes, []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Add and drop indecies +%% Add and drop indices add_table_index_ram(suite) -> []; diff --git a/lib/mnesia/test/mt.erl b/lib/mnesia/test/mt.erl index c1859bef3f10..b5eea3069083 100644 --- a/lib/mnesia/test/mt.erl +++ b/lib/mnesia/test/mt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -235,7 +235,7 @@ ping() -> Nodes = mnesia_test_lib:select_nodes(all, Config, ?FILE, ?LINE), [{N, net_adm:ping(N)} || N <- Nodes]. -%% Slave start all nodes in config spec +%% Start all nodes in config spec start_nodes() -> Config = read_config(), Nodes = mnesia_test_lib:select_nodes(all, Config, ?FILE, ?LINE), @@ -245,30 +245,32 @@ start_nodes() -> %% loop one testcase /suite until it fails loop(Case) -> - loop_1(Case,-1,read_config()). + loop_1(Case,1,infinity,read_config()). loop(M,F) when is_atom(F) -> - loop_1({M,F},-1,read_config()); + loop_1({M,F},1, infinity, read_config()); loop(Case,N) when is_integer(N) -> - loop_1(Case, N,read_config()). + loop_1(Case, 1, N,read_config()). loop(M,F,N) when is_integer(N) -> - loop_1({M,F},N,read_config()). + loop_1({M,F},1, N,read_config()). + +loop_1(Case,N,Max,Config) when N < Max -> + io:format("~nLoop test ~p ~n", [abs(N)]), -loop_1(Case,N,Config) when N /= 0 -> - io:format("Loop test ~p ~n", [abs(N)]), case ok_result(Res = t(Case,Config)) of true -> - loop_1(Case,N-1,Config); + loop_1(Case,N+1,Max,Config); error -> + io:format("Failed after ~p~n", [N]), Res end; -loop_1(_,_,_) -> +loop_1(_,_,_,_) -> ok. - + ok_result([{_T,{ok,_,_}}|R]) -> ok_result(R); -ok_result([{_T,{TC,List}}|R]) when is_tuple(TC), is_list(List) -> +ok_result([{_T,{TC,List}}|R]) when is_tuple(TC), is_list(List) -> ok_result(List) andalso ok_result(R); ok_result([]) -> true; ok_result(_) -> error. diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 54884fc493bc..6de36caf8002 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.20.4.2 +MNESIA_VSN = 4.22.1 diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml index ef95459d1ea9..52c3771bdb43 100644 --- a/lib/observer/doc/src/notes.xml +++ b/lib/observer/doc/src/notes.xml @@ -32,6 +32,134 @@

    This document describes the changes made to the Observer application.

    +
    Observer 2.15.1 + +
    Fixed Bugs and Malfunctions + + +

    + Closing the trace log window via the menu did not work.

    +

    + Own Id: OTP-18722 Aux Id: PR-7462

    +
    +
    +
    + +
    + +
    Observer 2.15 + +
    Improvements and New Features + + +

    Runtime dependencies have been updated.

    +

    + Own Id: OTP-18350

    +
    + +

    + Added start/1, start_and_wait functions/1|2 + functions.

    +

    + Own Id: OTP-18430 Aux Id: PR-6397

    +
    + +

    + Deprecates dbg:stop_clear/0 because it is simply a + function alias to dbg:stop/0

    +

    + Own Id: OTP-18478 Aux Id: GH-6903

    +
    +
    +
    + +
    + +
    Observer 2.14 + +
    Fixed Bugs and Malfunctions + + +

    + A WX event race could causes a crash in when handling + socket or port info.

    +

    + Own Id: OTP-18339

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Improve the nodes menu to include more nodes.

    +

    + Own Id: OTP-18269 Aux Id: PR-6030

    +
    +
    +
    + +
    + +
    Observer 2.13 + +
    Improvements and New Features + + +

    + Fixed units in gui.

    +

    + Own Id: OTP-18151 Aux Id: PR-6063

    +
    +
    +
    + +
    + +
    Observer 2.12 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed default handling of Mac specific menus.

    +

    + Own Id: OTP-17996 Aux Id: PR-5795

    +
    + +

    + Reading port socket options on macOS and Windows "skips" + invalid options.

    +

    + Own Id: OTP-18012 Aux Id: #5798

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + The configuration files .erlang, .erlang.cookie + and .erlang.crypt + can now be located in the XDG Config Home directory.

    +

    + See the documentation for each file and + filename:basedir/2 for more details.

    +

    + Own Id: OTP-17554 Aux Id: GH-5016 PR-5408 OTP-17821

    +
    +
    +
    + +
    +
    Observer 2.11.1
    Fixed Bugs and Malfunctions diff --git a/lib/observer/doc/src/observer.xml b/lib/observer/doc/src/observer.xml index 3fa59db70a38..9185c4be0d33 100644 --- a/lib/observer/doc/src/observer.xml +++ b/lib/observer/doc/src/observer.xml @@ -4,7 +4,7 @@
    - 20112021 + 20112023 Ericsson AB, All Rights Reserved @@ -52,8 +52,41 @@ Start the Observer GUI.

    Starts the Observer GUI. - To stop the tool, close the window. -

    + To stop the tool, close the window or call + stop/0. +

    +
    + + + start(Node) -> ok + Start the Observer GUI connected against Node. + +

    Starts the Observer GUI and tries to connect it to Node.

    +
    +
    + + start_and_wait() -> ok + Start the Observer GUI blocking. + +

    Starts the Observer GUI and only return when it is either stopped or + the window is closed

    +
    +
    + + start_and_wait(Node) -> ok + Start the Observer GUI blocking and connect it to Node. + +

    Starts the Observer GUI and only return when it is either stopped or + the window is closed, connects it directly to Node like + start/1. +

    +
    +
    + + stop() -> ok + Stop the Observer GUI. + +

    Stops the Observer GUI.

    diff --git a/lib/observer/doc/src/observer_ug.xml b/lib/observer/doc/src/observer_ug.xml index b0e8ef5872a5..348e613c8557 100644 --- a/lib/observer/doc/src/observer_ug.xml +++ b/lib/observer/doc/src/observer_ug.xml @@ -252,7 +252,7 @@
    Sockets Tab -

    Tab Sockets is devided into two parts. +

    Tab Sockets is divided into two parts. The first part contains general socket information and the second part @@ -314,7 +314,7 @@ Table Viewer Tab

    Tab Table Viewer lists tables. By default, ETS tables are displayed whereas unreadable private ETS tables and tables created by OTP - applications are not diplayed. Use menu View to view "system" + applications are not displayed. Use menu View to view "system" ETS tables, unreadable ETS tables, or Mnesia tables.

    Double-click to view the table content, or right-click and @@ -360,7 +360,7 @@ the Ports tab. A special new identifier, meaning all processes, or ports, started after trace start, can be added with buttons Add 'new' Processes and Add - 'new' Ports, respecively. + 'new' Ports, respectively.

    When adding processes or ports, a window with trace options is diff --git a/lib/observer/doc/src/ttb_ug.xml b/lib/observer/doc/src/ttb_ug.xml index be24db1aac92..0411694c4ec7 100644 --- a/lib/observer/doc/src/ttb_ug.xml +++ b/lib/observer/doc/src/ttb_ug.xml @@ -394,7 +394,7 @@ check(stop) -> this way is then merged with all other traces.

    The autostart feature requires more data to be stored on traced nodes. By default, the data is stored automatically - to the file named "ttb_autostart.bin" in the currect working directory + to the file named "ttb_autostart.bin" in the current working directory (cwd) of the traced node. Users can change this behaviour (that is, on diskless nodes) by specifying their own module to handle autostart data diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile index 4280557d45e3..2edb2ceb3e2d 100644 --- a/lib/observer/src/Makefile +++ b/lib/observer/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2021. All Rights Reserved. +# Copyright Ericsson AB 2002-2022. 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. @@ -128,7 +128,7 @@ ERL_COMPILE_FLAGS += \ # ---------------------------------------------------- # Targets # ---------------------------------------------------- -opt debug: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/observer/src/cdv_proc_cb.erl b/lib/observer/src/cdv_proc_cb.erl index 11830065b758..dafd8ab5d22b 100644 --- a/lib/observer/src/cdv_proc_cb.erl +++ b/lib/observer/src/cdv_proc_cb.erl @@ -153,7 +153,7 @@ info_fields() -> {"Old Binary vheap", old_bin_vheap}, {"Binary vheap unused", bin_vheap_unused}, {"Old Binary vheap unused", old_bin_vheap_unused}, - {"Number of Heap Fragements", num_heap_frag}, + {"Number of Heap Fragments", num_heap_frag}, {"Heap Fragment Data",heap_frag_data}, {"New Heap Start", new_heap_start}, {"New Heap Top", new_heap_top}, diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index b876ce29452b..2e9c79a6f33c 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2022. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -1399,7 +1399,7 @@ get_pid_from_name(Name,Node) -> [{_,Pid}] when is_pid(Pid) -> pid_to_list(Pid); _ -> - "" + "" end; _ -> "" @@ -1652,7 +1652,7 @@ read_heap_lines_1(Fd, Acc) -> %% Reduce the memory consumption by converting the %% line to a binary. Measurements show that it may also - %% be benefical for performance, too, because it makes the + %% be beneficial for performance, too, because it makes the %% garbage collections cheaper. Line = list_to_binary(Line1), @@ -3357,7 +3357,7 @@ collect(Pids,Acc) -> collect(lists:delete(Pid,Pids),[Result|Acc]); {'DOWN', _Ref, process, Pid, _Error} -> Warning = - "WARNING: an error occured while parsing data.\n" ++ + "WARNING: an error occurred while parsing data.\n" ++ case get(truncated) of true -> "This might be because the dump is truncated.\n"; false -> "" diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl index 856e558e6c93..b6362f6d9d37 100644 --- a/lib/observer/src/crashdump_viewer.hrl +++ b/lib/observer/src/crashdump_viewer.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2018. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -42,7 +42,7 @@ }). -record(proc, - %% Initial data according to the follwoing: + %% Initial data according to the following: %% %% msg_q_len, reds, memory and stack_heap are integers because it must %% be possible to sort on them. All other fields are strings diff --git a/lib/observer/src/etop.erl b/lib/observer/src/etop.erl index f0990f1f25ac..78ffe658e4f5 100644 --- a/lib/observer/src/etop.erl +++ b/lib/observer/src/etop.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2017. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -38,7 +38,7 @@ help() -> "Options are:~n" " node atom Required The erlang node to measure ~n" " port integer The used port, NOTE: due to a bug this program~n" - " will hang if the port is not avaiable~n" + " will hang if the port is not available~n" " accumulate boolean If true execution time is accumulated ~n" " lines integer Number of displayed processes~n" " interval integer Display update interval in secs~n" diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src index 09f959dabf0b..083987014322 100644 --- a/lib/observer/src/observer.app.src +++ b/lib/observer/src/observer.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -67,7 +67,5 @@ {registered, []}, {applications, [kernel, stdlib]}, {env, []}, - {runtime_dependencies, ["wx-1.2","stdlib-3.13","runtime_tools-1.17", - "kernel-8.1","et-1.5","erts-11.0"]}]}. - - + {runtime_dependencies, ["wx-2.3","stdlib-5.0","runtime_tools-1.19", + "kernel-9.0","et-1.5","erts-14.0"]}]}. diff --git a/lib/observer/src/observer.erl b/lib/observer/src/observer.erl index 79ba7fd61419..b2a878e54e17 100644 --- a/lib/observer/src/observer.erl +++ b/lib/observer/src/observer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -19,11 +19,51 @@ -module(observer). --export([start/0, stop/0]). +-export([start/0, start/1, start_and_wait/0, start_and_wait/1, stop/0]). start() -> observer_wx:start(). +start(Node) when is_atom(Node) -> + start([Node]); +start([Node]) -> + Node1 = to_atom(Node), + case net_kernel:connect_node(Node1) of + true -> + case observer_wx:start() of + ok -> + observer_wx:set_node(Node1), + ok; + Err -> + Err + end; + _ -> + {error, failed_to_connect} + end. + +start_and_wait() -> + ok = start(), + MonitorRef = monitor(process, observer), + receive + {'DOWN', MonitorRef, process, _, _} -> + ok + end. + +start_and_wait(Node) when is_atom(Node) -> + start_and_wait([Node]); +start_and_wait(List) when is_list(List) -> + ok = start(List), + MonitorRef = monitor(process, observer), + receive + {'DOWN', MonitorRef, process, _, _} -> + ok + end. + stop() -> observer_wx:stop(). + +to_atom(Node) when is_atom(Node) -> + Node; +to_atom(Node) when is_list(Node) -> + list_to_atom(Node). diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index b4c2663d0d19..438fa80ce288 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -299,13 +299,13 @@ to_str({Unit, X}) when (Unit==bytes orelse Unit==time_ms) andalso is_list(X) -> catch error:badarg -> X end; to_str({bytes, B}) -> - KB = B div 1024, - MB = KB div 1024, - GB = MB div 1024, + KiB = B div 1024, + MiB = KiB div 1024, + GiB = MiB div 1024, if - GB > 10 -> integer_to_list(GB) ++ " GB"; - MB > 10 -> integer_to_list(MB) ++ " MB"; - KB > 0 -> integer_to_list(KB) ++ " kB"; + GiB > 10 -> integer_to_list(GiB) ++ " GiB"; + MiB > 10 -> integer_to_list(MiB) ++ " MiB"; + KiB > 0 -> integer_to_list(KiB) ++ " KiB"; true -> integer_to_list(B) ++ " B" end; to_str({{words,WSz}, Sz}) -> diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl index a11ae4175a71..4e16319d2be3 100644 --- a/lib/observer/src/observer_port_wx.erl +++ b/lib/observer/src/observer_port_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -147,12 +147,19 @@ handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) -> observer_lib:set_listctrl_col_size(Grid, W), {noreply, State}; -handle_event(#wx{event=#wxList{type=command_list_item_activated, - itemIndex=Index}}, - State=#state{grid=Grid, ports=Ports, open_wins=Opened}) -> - Port = lists:nth(Index+1, Ports), - NewOpened = display_port_info(Grid, Port, Opened), - {noreply, State#state{open_wins=NewOpened}}; +handle_event(#wx{event = #wxList{type = command_list_item_activated, + itemIndex = Index}}, + State = #state{grid = Grid, + ports = Ports, + open_wins = Opened}) -> + if + length(Ports) >= (Index+1) -> + Port = lists:nth(Index+1, Ports), + NewOpened = display_port_info(Grid, Port, Opened), + {noreply, State#state{open_wins=NewOpened}}; + true -> % Race - should we do somthing here? + {noreply, State} + end; handle_event(#wx{event=#wxList{type=command_list_item_right_click, itemIndex=Index}}, diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index 7ffdba262ac7..a22f76a4c710 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -339,7 +339,7 @@ fetch_state_info2(Pid, M) -> %% Formatted status ? case lists:keyfind(format_status, 1, rpc:call(node(Pid), M, module_info, [exports])) of false -> Opt = {"Format", unknown}; - _ -> Opt = {"Format", overriden} + _ -> Opt = {"Format", overridden} end, [{"Behaviour", B}, Opt, {"State",OtherFormat}]; {badrpc,{'EXIT',{timeout, _}}} -> [] diff --git a/lib/observer/src/observer_sock_wx.erl b/lib/observer/src/observer_sock_wx.erl index 3ab8f0d27aa0..4b936f6f3acb 100644 --- a/lib/observer/src/observer_sock_wx.erl +++ b/lib/observer/src/observer_sock_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2021-2021. All Rights Reserved. +%% Copyright Ericsson AB 2021-2022. 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. @@ -241,9 +241,14 @@ handle_event(#wx{event = #wxList{type = command_list_item_activated, State = #state{grid = Grid, sockets = Sockets, open_wins = Opened}) -> - Socket = lists:nth(Index+1, Sockets), - NewOpened = display_socket_info(Grid, Socket, Opened), - {noreply, State#state{open_wins = NewOpened}}; + if + length(Sockets) >= (Index+1) -> + Socket = lists:nth(Index+1, Sockets), + NewOpened = display_socket_info(Grid, Socket, Opened), + {noreply, State#state{open_wins = NewOpened}}; + true -> % Race - should we do somthing here? + {noreply, State} + end; handle_event(#wx{event = #wxList{type = command_list_item_right_click, itemIndex = Index}}, diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl index 8c2ffd77b408..25086b10b768 100644 --- a/lib/observer/src/observer_sys_wx.erl +++ b/lib/observer/src/observer_sys_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2017. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -138,10 +138,10 @@ info_fields() -> {"Async thread pool size", thread_pool_size} ]}], - Cpu = [{"CPU's and Threads", - [{"Logical CPU's", logical_processors}, - {"Online Logical CPU's", logical_processors_online}, - {"Available Logical CPU's", logical_processors_available}, + Cpu = [{"CPUs and Threads", + [{"Logical CPUs", logical_processors}, + {"Online Logical CPUs", logical_processors_online}, + {"Available Logical CPUs", logical_processors_available}, {"Schedulers", schedulers}, {"Online schedulers", schedulers_online}, {"Available schedulers", schedulers_available} diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl index 5b8d4f556859..487e257901a0 100644 --- a/lib/observer/src/observer_trace_wx.erl +++ b/lib/observer/src/observer_trace_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -361,7 +361,7 @@ handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, command (TProcs == []) andalso (TPorts == []) andalso throw({error, "No processes or ports traced"}), (Nodes == []) andalso throw({error, "No nodes traced"}), HaveCallTrace = fun(#titem{opts=Os}) -> lists:member(functions,Os) end, - WStr = "Call trace actived but no trace patterns used", + WStr = "Call trace activated but no trace patterns used", (TPs == []) andalso lists:any(HaveCallTrace, TProcs) andalso observer_wx:create_txt_dialog(Panel, WStr, "Warning", ?wxICON_WARNING), @@ -398,6 +398,10 @@ handle_event(#wx{id=Id, obj=LogWin, event=Ev}, {noreply, State} end; +handle_event(#wx{id=?wxID_CLOSE, obj=Obj, event=#wxCommand{type=command_menu_selected}}, State) -> + wxWindow:close(Obj, []), + {noreply, State}; + handle_event(#wx{id=?LOG_CLEAR, userData=TCtrl}, State) -> wxTextCtrl:clear(TCtrl), {noreply, State}; @@ -697,7 +701,7 @@ handle_event(#wx{id=?REMOVE_NODES}, #state{n_view=Nview, nodes=Ns0} = State) -> {noreply, State#state{nodes = Ns}}; handle_event(#wx{id=ID, event = What}, State) -> - io:format("~p:~p: Unhandled event: ~p, ~tp ~n", [?MODULE, ?LINE, ID, What]), + io:format(user,"~p:~p: Unhandled event: ~p, ~tp ~n", [?MODULE, ?LINE, ID, What]), {noreply, State}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -763,7 +767,7 @@ do_add_patterns({Module, NewPs}, State=#state{tpatterns=TPs0, m_view=Mview, f_vi {Old, [], []} -> State; {MPatterns, _New, _Changed} -> - %% if dynamicly updates update New and Changed + %% if dynamically updates update New and Changed TPs = dict:store(Module, MPatterns, TPs0), update_modules_view(lists:sort(dict:fetch_keys(TPs)), Module, Mview), update_functions_view(dict:fetch(Module, TPs), Fview), @@ -1048,7 +1052,7 @@ textformat(Trace) when element(1, Trace) == trace_ts, tuple_size(Trace) >= 4 -> textformat(Trace) when element(1, Trace) == drop, tuple_size(Trace) =:= 2 -> io_lib:format("*** Dropped ~p messages.~n", [element(2,Trace)]); textformat(Trace) when element(1, Trace) == seq_trace, tuple_size(Trace) >= 3 -> - io_lib:format("*** Seq trace not implmented.~n", []); + io_lib:format("*** Seq trace not implemented.~n", []); textformat(_) -> "". diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl index 07e2fb1b2904..530f8c2a6ff9 100644 --- a/lib/observer/src/observer_wx.erl +++ b/lib/observer/src/observer_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -22,13 +22,15 @@ -export([start/0, stop/0]). -export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0, get_menubar/0, - get_scale/0, set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]). + get_scale/0, set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2, + set_node/1]). -export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3, handle_call/3, handle_info/2, check_page_title/1]). %% Includes -include_lib("wx/include/wx.hrl"). +-include_lib("kernel/include/file.hrl"). -include("observer_defs.hrl"). @@ -88,6 +90,9 @@ get_tracer() -> get_active_node() -> wx_object:call(observer, get_active_node). +set_node(Node) -> + wx_object:call(observer, {set_node, Node}). + get_menubar() -> wx_object:call(observer, get_menubar). @@ -157,7 +162,7 @@ setup(#state{frame = Frame} = State) -> wxNotebook:connect(Notebook, command_notebook_page_changed, [{skip, true}, {id, ?ID_NOTEBOOK}]), wxFrame:connect(Frame, close_window, []), - wxMenu:connect(Frame, command_menu_selected), + wxMenu:connect(Frame, command_menu_selected, [{skip, true}]), wxFrame:show(Frame), %% Freeze and thaw is buggy currently @@ -390,6 +395,10 @@ handle_event(#wx{id = Id, event = #wxCommand{type = command_menu_selected}}, end, {noreply, change_node_view(Node, LState)}; +handle_event(#wx{id = Id, event = #wxCommand{type = command_menu_selected}}, State) + when Id >= ?wxID_OSX_MENU_FIRST, Id =< ?wxID_OSX_MENU_LAST -> + {noreply, State}; + handle_event(Event, #state{active_tab=Pid} = State) -> Pid ! Event, {noreply, State}. @@ -422,6 +431,10 @@ handle_call(get_tracer, _From, State=#state{panels=Panels}) -> handle_call(get_active_node, _From, State=#state{node=Node}) -> {reply, Node, State}; +handle_call({set_node, Node}, _From, State) -> + State2 = change_node_view(Node, State), + {reply, ok, State2}; + handle_call(get_menubar, _From, State=#state{menubar=MenuBar}) -> {reply, MenuBar, State}; @@ -450,6 +463,7 @@ handle_info({nodedown, Node}, State3 = update_node_list(State2), Msg = ["Node down: " | atom_to_list(Node)], create_txt_dialog(Frame, Msg, "Node down", ?wxICON_EXCLAMATION), + filter_nodedown_messages(Node), {noreply, State3}; handle_info({open_link, Id0}, State = #state{panels=Panels,frame=Frame}) -> @@ -494,10 +508,10 @@ handle_info(_Info, State) -> {noreply, State}. stop_servers(#state{node=Node, log=LogOn, panels=Panels} = _State) -> - LogOn andalso rpc:block_call(Node, rb, stop, []), Me = self(), - save_config(Panels), Stop = fun() -> + LogOn andalso rpc:block_call(Node, rb, stop, []), + save_config(Panels), try _ = [wx_object:stop(Panel) || {_, Panel, _} <- Panels], ok @@ -558,7 +572,7 @@ try_rpc(Node, Mod, Func, Args) -> return_to_localnode(Frame, Node) -> case node() =/= Node of true -> - create_txt_dialog(Frame, "Error occured on remote node", + create_txt_dialog(Frame, "Error occurred on remote node", "Error", ?wxICON_ERROR), disconnect_node(Node); false -> @@ -658,14 +672,16 @@ create_connect_dialog(connect, #state{frame = Frame}) -> wxWindow:setSizerAndFit(Dialog, VSizer), wxSizer:setSizeHints(VSizer, Dialog), {ok,[[HomeDir]]} = init:get_argument(home), - CookiePath = filename:join(HomeDir, ".erlang.cookie"), - DefaultCookie = case filelib:is_file(CookiePath) of - true -> - {ok, Bin} = file:read_file(CookiePath), - binary_to_list(Bin); - false -> - "" - end, + XDGHome = filename:basedir(user_config,"erlang"), + DefaultCookie = + case file:path_open([HomeDir,XDGHome], ".erlang.cookie", [read]) of + {ok, File, _} -> + {ok, #file_info{ size = Sz }} = file:read_file_info(File), + {ok, Data} = file:read(File, Sz), + Data; + _ -> + "" + end, wxTextCtrl:setValue(CookieCtrl, DefaultCookie), case wxDialog:showModal(Dialog) of ?wxID_OK -> @@ -740,21 +756,45 @@ get_nodes() -> Nodes0 = case erlang:is_alive() of false -> []; true -> - case net_adm:names() of - {error, _} -> nodes(); - {ok, Names} -> - epmd_nodes(Names) ++ nodes() - end + case net_adm:names() of + {error, _} -> []; + {ok, Names} -> epmd_nodes(Names) + end + ++ + [node() | nodes(connected)] end, Nodes = lists:usort(Nodes0), + WarningText = "WARNING: connecting to non-erlang nodes may crash them", {_, Menues} = lists:foldl(fun(Node, {Id, Acc}) when Id < ?LAST_NODES_MENU_ID -> {Id + 1, [#create_menu{id=Id + ?FIRST_NODES_MENU_ID, - text=atom_to_list(Node)} | Acc]} + text=atom_to_list(Node), + help=WarningText} | Acc]} end, {1, []}, Nodes), {Nodes, lists:reverse(Menues)}. -epmd_nodes(Names) -> +%% see erl_epmd:(listen_)port_please/2 +erl_dist_port() -> + try + erl_epmd = net_kernel:epmd_module(), + {ok, [[StringPort]]} = init:get_argument(erl_epmd_port), + list_to_integer(StringPort) + catch + _:_ -> + undefined + end. + +%% If the default epmd module erl_epmd is used and erl_epmd_port is +%% set to `DistPort' then it is only possible to connect to the node +%% listening on DistPort (if any), so exclude other nodes registered +%% in EPMD +epmd_nodes(Names0) -> + Names = case erl_dist_port() of + undefined -> + Names0; + DistPort -> + [NP || NP = {_, Port} <- Names0, Port =:= DistPort] + end, [_, Host] = string:lexemes(atom_to_list(node()),"@"), [list_to_atom(Name ++ [$@|Host]) || {Name, _} <- Names]. @@ -833,7 +873,7 @@ is_rb_compatible(Node) -> is_rb_server_running(Node, LogState) -> %% If already started, somebody else may use it. - %% We cannot use it too, as far log file would be overriden. Not fair. + %% We cannot use it too, as far log file would be overridden. Not fair. case rpc:block_call(Node, erlang, whereis, [rb_server]) of Pid when is_pid(Pid), (LogState == false) -> throw("Error: rb_server is already started and maybe used by someone."); @@ -843,6 +883,14 @@ is_rb_server_running(Node, LogState) -> ok end. +filter_nodedown_messages(Node) -> + receive + {nodedown, Node} -> + filter_nodedown_messages(Node) + after + 0 -> + ok + end. %% d(F) -> %% d(F, []). diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl index 29a572d7feab..bf220a7f05e4 100644 --- a/lib/observer/src/ttb.erl +++ b/lib/observer/src/ttb.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2017. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -784,7 +784,7 @@ do_stop(nofetch, Sender, NodeInfo, SessionInfo) -> ok, NodeInfo), stop_ip_to_file_trace_ports(SessionInfo), - dbg:stop_clear(), + dbg:stop(), ets:delete(?history_table), Sender ! {?MODULE, stopped}; @@ -807,7 +807,7 @@ do_stop({FetchOrFormat, UserDir}, Sender, NodeInfo, SessionInfo) -> [], NodeInfo), stop_ip_to_file_trace_ports(SessionInfo), - dbg:stop_clear(), + dbg:stop(), AllNodes = lists:map( fun({Node,MetaFile}) -> @@ -1055,7 +1055,7 @@ format(Files,Out,Handler,DisableSort) when is_list(Files), is_list(hd(Files)) -> file:close(Fd), ets:delete(?MODULE), case StopDbg of - true -> dbg:stop_clear(); + true -> dbg:stop(); false -> ok end, R. @@ -1199,7 +1199,7 @@ start_client(FileOrWrap,Traci) -> {fun handler/2, dict:to_list(Traci)}). handler(Trace,Traci) -> - %%We return our own Traci so that it not necesarry to look it up + %%We return our own Traci so that it not necessary to look it up %%This may take time if something huge has been written to it receive {get,Collector} -> Collector ! {self(),{Trace,Traci}}; diff --git a/lib/observer/src/ttb_et.erl b/lib/observer/src/ttb_et.erl index f90a7f6dcf32..39c4c2180c8f 100644 --- a/lib/observer/src/ttb_et.erl +++ b/lib/observer/src/ttb_et.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2018. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -52,7 +52,7 @@ collector(Trace) -> %% all events backwards and collect call/return information: %% %% MFA collected from return_to events is added to call and -%% return_from events as {caller,MFA} and {return_to,MFA} respecively. +%% return_from events as {caller,MFA} and {return_to,MFA} respectively. %% MFA collected from call events is added to return_to events as %% {return_from,MFA} %% diff --git a/lib/observer/test/Makefile b/lib/observer/test/Makefile index 1dc7a7e11bf3..114f77400f53 100644 --- a/lib/observer/test/Makefile +++ b/lib/observer/test/Makefile @@ -52,6 +52,7 @@ RELSYSDIR = $(RELEASE_PATH)/observer_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +warnings_as_errors +nowarn_export_all +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -68,7 +69,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) \ $(MODULES) > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index 83455def934f..8a5dd1011c5e 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -25,7 +25,7 @@ dump_persistent_terms/0, create_persistent_terms/0, dump_global_literals/0]). --compile(r20). +-compile(r22). -include_lib("common_test/include/ct.hrl"). n1_proc(N2,Creator) -> diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 230ab6ceed6a..2777e5f99557 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -187,7 +187,7 @@ start_stop(Config) when is_list(Config) -> ok. recv_downs([]) -> - ct:log("'DOWN' received from all registered proceses~n", []), + ct:log("'DOWN' received from all registered processes~n", []), ok; recv_downs(Regs) -> receive diff --git a/lib/observer/test/etop_SUITE.erl b/lib/observer/test/etop_SUITE.erl index e324c9bbb1c7..8b112cba3766 100644 --- a/lib/observer/test/etop_SUITE.erl +++ b/lib/observer/test/etop_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -31,7 +31,7 @@ -define(default_timeout, test_server:minutes(1)). init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), + Dog=test_server:timetrap(?default_timeout), [{watchdog, Dog}|Config]. end_per_testcase(Case, Config) -> try apply(?MODULE,Case,[cleanup,Config]) @@ -64,23 +64,23 @@ end_per_group(_GroupName, Config) -> %% Start etop with text presentation text(_) -> - ?line {ok,Node} = test_server:start_node(node2,peer,[]), + {ok,Node} = test_server:start_node(node2,peer,[]), %% Must spawn this process, else the test case will never end. - ?line spawn_link(etop,start,[[{node,Node},{output,text},{interval,3}]]), - ?line timer:sleep(4000), - ?line etop:config(interval,2), - ?line timer:sleep(3000), - ?line etop:config(lines,5), - ?line timer:sleep(3000), - ?line etop:config(accumulate,true), - ?line timer:sleep(3000), - ?line etop:config(sort,reductions), - ?line timer:sleep(3000), - ?line etop:config(sort,memory), - ?line timer:sleep(3000), - ?line etop:config(sort,msg_q), - ?line timer:sleep(3000), + spawn_link(etop,start,[[{node,Node},{output,text},{interval,3}]]), + timer:sleep(4000), + etop:config(interval,2), + timer:sleep(3000), + etop:config(lines,5), + timer:sleep(3000), + etop:config(accumulate,true), + timer:sleep(3000), + etop:config(sort,reductions), + timer:sleep(3000), + etop:config(sort,memory), + timer:sleep(3000), + etop:config(sort,msg_q), + timer:sleep(3000), ok. text(cleanup,_Config) -> etop:stop(), @@ -93,26 +93,26 @@ text_tracing_off(suite) -> text_tracing_off(doc) -> ["Start etop with text presentation, and tracing turned off"]; text_tracing_off(Config) when is_list(Config) -> - ?line {ok,Node} = test_server:start_node(node2,peer,[]), + {ok,Node} = test_server:start_node(node2,peer,[]), %% Must spawn this process, else the test case will never end. - ?line spawn_link(etop,start,[[{node,Node}, + spawn_link(etop,start,[[{node,Node}, {output,text}, {interval,3}, {tracing,off}]]), - ?line timer:sleep(4000), - ?line etop:config(interval,2), - ?line timer:sleep(3000), - ?line etop:config(lines,5), - ?line timer:sleep(3000), - ?line etop:config(accumulate,true), - ?line timer:sleep(3000), - ?line etop:config(sort,memory), - ?line timer:sleep(3000), - ?line etop:config(sort,msg_q), - ?line timer:sleep(3000), - ?line etop:config(sort,runtime), % this should not crash, but has no effect - ?line timer:sleep(3000), + timer:sleep(4000), + etop:config(interval,2), + timer:sleep(3000), + etop:config(lines,5), + timer:sleep(3000), + etop:config(accumulate,true), + timer:sleep(3000), + etop:config(sort,memory), + timer:sleep(3000), + etop:config(sort,msg_q), + timer:sleep(3000), + etop:config(sort,runtime), % this should not crash, but has no effect + timer:sleep(3000), ok. text_tracing_off(cleanup,_Config) -> etop:stop(), diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl index 575f63b956ad..0c0d7412516b 100644 --- a/lib/observer/test/observer_SUITE.erl +++ b/lib/observer/test/observer_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2023. 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. @@ -35,7 +35,8 @@ %% Test cases -export([app_file/1, appup_file/1, basic/1, process_win/1, table_win/1, - port_win_when_tab_not_initiated/1 + port_win_when_tab_not_initiated/1, + blocking_start/1, remote_node/1 ]). %% Default timetrap timeout (set in init_per_testcase) @@ -58,7 +59,9 @@ groups() -> [basic, process_win, table_win, - port_win_when_tab_not_initiated + port_win_when_tab_not_initiated, + blocking_start, + remote_node ] }]. @@ -74,17 +77,47 @@ end_per_suite(Config) -> ok. +%% init_per_testcase(basic = Case, Config) -> +%% ?P("init_per_testcase(~w) -> entry with" +%% "~n Config: ~p", [Case, Config]), +%% {ok, Host} = inet:gethostname(), +%% {ok, IFL} = inet:getifaddrs(), +%% init_per_testcase2(Case, [{host, Host}, {ifl, IFL} | Config]); init_per_testcase(Case, Config) -> ?P("init_per_testcase(~w) -> entry with" "~n Config: ~p", [Case, Config]), + init_per_testcase2(Case, Config). + +init_per_testcase2(Case, Config) -> + ?P("init_per_testcase(~w) -> entry", [Case]), Dog = test_server:timetrap(?default_timeout), [{watchdog, Dog} | Config]. +%% end_per_testcase(basic = Case, Config) -> +%% ?P("end_per_testcase(~w) -> entry with" +%% "~n Config: ~p", [Case, Config]), +%% case lists:keysearch(tc_status, 1, Config) of +%% {value, {tc_status, ok}} -> +%% ?P("end_per_testcase(~w) -> successful", [Case]), +%% ok; +%% {value, _} -> +%% ?P("end_per_testcase(~w) -> try ensure observer stopped", [Case]), +%% ensure_observer_stopped(); +%% _ -> +%% ?P("end_per_testcase(~w) -> nop status", [Case]), +%% ok +%% end, +%% end_per_testcase2(Case, Config); end_per_testcase(Case, Config) -> ?P("end_per_testcase(~w) -> entry with" "~n Config: ~p", [Case, Config]), + end_per_testcase2(Case, Config). + +end_per_testcase2(Case, Config) -> + ?P("end_per_testcase2(~w) -> entry - try cancel watchdog", [Case]), Dog = ?config(watchdog, Config), test_server:timetrap_cancel(Dog), + ?P("end_per_testcase2(~w) -> done", [Case]), ok. @@ -139,14 +172,14 @@ app_file(suite) -> app_file(doc) -> ["Testing .app file"]; app_file(Config) when is_list(Config) -> - ?line ok = test_server:app_test(observer), + ok = test_server:app_test(observer), ok. + %% Testing .appup file appup_file(Config) when is_list(Config) -> ok = test_server:appup_test(observer). --define(DBG(Foo), io:format("~p: ~p~n",[?LINE, catch Foo])). basic(suite) -> []; basic(doc) -> [""]; @@ -159,10 +192,19 @@ basic(Config) when is_list(Config) -> wx:new(), ?P("basic -> try wx destroy"), wx:destroy(), - timer:send_after(100, "foobar"), + timer:start(), ?P("basic -> try start distribution"), {foo, node@machine} ! dummy_msg, %% start distribution stuff %% Otherwise ever lasting servers gets added to procs + + %% It takes some time for all the procs to start, + %% so give it some time. + %% Note that this is a problem *only* if this test suite + %% is run *on its own*. If all the observer suite(s) are run + %% (ex: ts:run(observer, [batch]), then this problem does + %% not occcur. + timer:sleep(5000), + ?P("basic -> procs before"), ProcsBefore = processes(), ProcInfoBefore = [{P,process_info(P)} || P <- ProcsBefore], @@ -179,6 +221,7 @@ basic(Config) when is_list(Config) -> ?P("basic -> check selection (=0)"), 0 = wxNotebook:getSelection(Notebook), ?P("basic -> wait some time..."), + timer:sleep(500), Check = fun(N, TestMore) -> TestMore andalso @@ -198,7 +241,7 @@ basic(Config) when is_list(Config) -> ?P("basic -> try verify that we resized"), [_|_] = [Check(N, true) || N <- lists:seq(0, Count-1)], - ?P("basic -> try stop observer (async)"), + ?P("basic -> try stop observer"), ok = observer:stop(), timer:sleep(2000), %% stop is async ?P("basic -> try verify observer stopped"), @@ -206,15 +249,16 @@ basic(Config) when is_list(Config) -> NumProcsAfter = length(ProcsAfter), if NumProcsAfter =/= NumProcsBefore -> BeforeNotAfter = ProcsBefore -- ProcsAfter, + AfterNotBefore = ProcsAfter -- ProcsBefore, ?P("basic -> *not* fully stopped:" "~n Number of Procs before: ~p" "~n Number of Procs after: ~p", - [NumProcsAfter, NumProcsBefore]), + [NumProcsBefore, NumProcsAfter]), ct:log("Before but not after:~n~p~n", [[{P,I} || {P,I} <- ProcInfoBefore, lists:member(P,BeforeNotAfter)]]), ct:log("After but not before:~n~p~n", - [[{P,process_info(P)} || P <- ProcsAfter -- ProcsBefore]]), + [[{P,process_info(P)} || P <- AfterNotBefore]]), ensure_observer_stopped(), ct:fail("leaking processes"); true -> @@ -427,6 +471,40 @@ table_win(Config) when is_list(Config) -> ?P("table_win -> done"), ok. +remote_node(_Config) -> + {ok, Peer, Node} = ?CT_PEER(), + ok = observer:start(Node), + timer:sleep(1000), + Node = observer_wx:get_active_node(), + observer:stop(), + ensure_observer_stopped(?SECS(3)), + peer:stop(Peer). + +blocking_start(_Config) -> + {Pid, SpawnerRef} = spawn_monitor(fun observer:start_and_wait/0), + timer:sleep(1000), + ObserverRef = monitor(process, observer), + receive + {'DOWN', ObserverRef, _, _, Reason} -> + error({observer_stopped_unexpectedly, Reason}); + {'DOWN', SpawnerRef, _, _, Reason} -> + error({spawner_stopped_unexpectedly, Reason}) + after + 500 -> + ok + end, + observer:stop(), + ensure_observer_stopped(?SECS(3)), + receive + {'DOWN', ObserverRef, _, _, _} -> + ok + after + 500 -> + error(observer_should_have_stopped) + end, + false = erlang:is_process_alive(Pid), + ok. + %% Test PR-1296/OTP-14151 %% Clicking a link to a port before the port tab has been activated the %% first time crashes observer. diff --git a/lib/observer/test/ttb_SUITE.erl b/lib/observer/test/ttb_SUITE.erl index ab02cdabb4e8..d44f89d92cd4 100644 --- a/lib/observer/test/ttb_SUITE.erl +++ b/lib/observer/test/ttb_SUITE.erl @@ -2,7 +2,7 @@ %% %CopyrightBegin% %% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -40,7 +40,7 @@ -define(DIRNAME, "ddtemp"). init_per_testcase(Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), + Dog=test_server:timetrap(?default_timeout), ttb:stop(), rm(?OUTPUT), [rm(Upload) || Upload<-filelib:wildcard("ttb_upload*")], @@ -115,74 +115,74 @@ file(suite) -> file(doc) -> ["Start tracing on multiple nodes, single file"]; file(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"file"), - ?line {ok,[Node]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"file"), + {ok,[Node]} = ttb:tracer(Node,[{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{S,[{matched,Node,_}]}]} = ttb:p(S,call), - ?line {ok,[OtherNode]} = + {ok,[{S,[{matched,Node,_}]}]} = ttb:p(S,call), + {ok,[OtherNode]} = ttb:tracer([Node,OtherNode],[{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[]} = ttb:tracer([Node,OtherNode], + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[]} = ttb:tracer([Node,OtherNode], [{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), - ?line ok = ttb:format(filename:join(Privdir, + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), + ok = ttb:format(filename:join(Privdir, atom_to_list(OtherNode)++"-file")), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), ok. file(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). file_no_pi(suite) -> []; file_no_pi(doc) -> ["Start tracing on multiple nodes, single file, no process information"]; file_no_pi(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"file"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"file"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, {handler,{fun myhandler/4, S}}, {process_info,false}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), - ?line ok = ttb:format(filename:join(Privdir, + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")), + ok = ttb:format(filename:join(Privdir, atom_to_list(OtherNode)++"-file")), - ?line [{trace_ts,LocalProc,call,{?MODULE,foo,[]}, {_,_,_}}, + [{trace_ts,LocalProc,call,{?MODULE,foo,[]}, {_,_,_}}, end_of_trace, {trace_ts,RemoteProc,call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), - ?line true = is_pid(LocalProc), - ?line true = is_pid(RemoteProc), + true = is_pid(LocalProc), + true = is_pid(RemoteProc), ok. file_no_pi(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). file_fetch(suite) -> @@ -190,67 +190,67 @@ file_fetch(suite) -> file_fetch(doc) -> ["stop with the fetch option, i.e. collect all files when ttb is stopped"]; file_fetch(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line ThisDir = filename:join(Privdir,this), - ?line ok = file:make_dir(ThisDir), - ?line OtherDir = filename:join(Privdir,other), - ?line ok = file:make_dir(OtherDir), - ?line ThisFile = filename:join(ThisDir,"file_fetch"), - ?line OtherFile = filename:join(OtherDir,"file_fetch"), + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + ThisDir = filename:join(Privdir,this), + ok = file:make_dir(ThisDir), + OtherDir = filename:join(Privdir,other), + ok = file:make_dir(OtherDir), + ThisFile = filename:join(ThisDir,"file_fetch"), + OtherFile = filename:join(OtherDir,"file_fetch"), %% I'm setting priv_dir as cwd, so ttb_upload directory is created there %% and not in any other strange place! - ?line {ok,Cwd} = file:get_cwd(), - ?line ok = file:set_cwd(Privdir), + {ok,Cwd} = file:get_cwd(), + ok = file:set_cwd(Privdir), - ?line {ok,[Node]} = + {ok,[Node]} = ttb:tracer(Node,[{file, ThisFile}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[OtherNode]} = + {ok,[OtherNode]} = ttb:tracer([OtherNode],[{file, OtherFile}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line test_server:capture_start(), - ?line ttb:stop([return_fetch_dir]), - ?line test_server:capture_stop(), - ?line [StoreString] = test_server:capture_get(), - ?line UploadDir = + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + test_server:capture_start(), + ttb:stop([return_fetch_dir]), + test_server:capture_stop(), + [StoreString] = test_server:capture_get(), + UploadDir = lists:last(string:lexemes(lists:flatten(StoreString),"$ \n")), %% check that files are no longer in original directories... - ?line ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch"), - ?line ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch.ti"), -% ?line false = lists:member(TrcLog,ThisList), -% ?line false = lists:member(TIFile,ThisList), + ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch"), + ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch.ti"), +% false = lists:member(TrcLog,ThisList), +% false = lists:member(TIFile,ThisList), - ?line {ok,OtherList} = file:list_dir(OtherDir), - ?line false = lists:member(atom_to_list(OtherNode)++"-file_fetch",OtherList), - ?line false = lists:member(atom_to_list(OtherNode)++"-file_fetch.ti", + {ok,OtherList} = file:list_dir(OtherDir), + false = lists:member(atom_to_list(OtherNode)++"-file_fetch",OtherList), + false = lists:member(atom_to_list(OtherNode)++"-file_fetch.ti", OtherList), %% but instead in ttb_upload directory, where they can be formatted - ?line ok = ttb:format(filename:join(UploadDir, + ok = ttb:format(filename:join(UploadDir, atom_to_list(Node)++"-file_fetch")), - ?line ok = ttb:format(filename:join(UploadDir, + ok = ttb:format(filename:join(UploadDir, atom_to_list(OtherNode)++"-file_fetch")), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), - ?line ok = file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), ok. file_fetch(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). wrap(suite) -> @@ -258,44 +258,44 @@ wrap(suite) -> wrap(doc) -> ["Start tracing on multiple nodes, wrap files"]; wrap(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"wrap"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"wrap"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format(filename:join(Privdir, + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format(filename:join(Privdir, atom_to_list(Node)++"-wrap.*.wrp")), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), - ?line ok = ttb:format(filename:join(Privdir, + ok = ttb:format(filename:join(Privdir, atom_to_list(OtherNode)++"-wrap.*.wrp")), - ?line [{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), %% Check that merge does not crash even if the timestamp flag is not on. - ?line ok = ttb:format( + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-wrap.*.wrp"), filename:join(Privdir, atom_to_list(OtherNode)++"-wrap.*.wrp")],[{disable_sort,true}]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}}, @@ -305,37 +305,37 @@ wrap(Config) when is_list(Config) -> ok. wrap(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). wrap_merge(suite) -> []; wrap_merge(doc) -> ["Start tracing on multiple nodes, wrap files, merge logs from both nodes"]; wrap_merge(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"wrap_merge"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"wrap_merge"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]}=ttb:p(all,[call,timestamp]), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + {ok,[{all,[{matched,_,_},{matched,_,_}]}]}=ttb:p(all,[call,timestamp]), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-wrap_merge.*.wrp"), filename:join(Privdir, atom_to_list(OtherNode)++"-wrap_merge.*.wrp")]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, {trace_ts,_,call,{?MODULE,foo,[]},_}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, {trace_ts,_,call,{?MODULE,foo,[]},_}, @@ -345,7 +345,7 @@ wrap_merge(Config) when is_list(Config) -> ok. wrap_merge(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). wrap_merge_fetch_format(suite) -> @@ -353,31 +353,31 @@ wrap_merge_fetch_format(suite) -> wrap_merge_fetch_format(doc) -> ["Start tracing on multiple nodes, wrap files, fetch and format at stop"]; wrap_merge_fetch_format(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"wrap_merge_fetch_format"), + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"wrap_merge_fetch_format"), %% I'm setting priv_dir as cwd, so ttb_upload directory is created there %% and not in any other strange place! - ?line {ok,Cwd} = file:get_cwd(), - ?line ok = file:set_cwd(Privdir), + {ok,Cwd} = file:get_cwd(), + ok = file:set_cwd(Privdir), - ?line {ok,[_,_]} = + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]}=ttb:p(all,[call,timestamp]), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([format]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, + {ok,[{all,[{matched,_,_},{matched,_,_}]}]}=ttb:p(all,[call,timestamp]), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([format]), + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_}, {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_}, {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_}, @@ -385,55 +385,55 @@ wrap_merge_fetch_format(Config) when is_list(Config) -> {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_}, end_of_trace] = flush(), - ?line ok = file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), ok. wrap_merge_fetch_format(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). write_config1(suite) -> []; write_config1(doc) -> ["Write config given commands"]; write_config1(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"write_config1"), - ?line ok = ttb:write_config(File, + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + + Privdir=priv_dir(Config), + File = filename:join(Privdir,"write_config1"), + ok = ttb:write_config(File, [{ttb,tracer,[[Node,OtherNode], [{file, File}, {handler,{fun myhandler/4,S}}]]}, {ttb,p,[all,call]}, {ttb,tp,[?MODULE,foo,[]]}]), - ?line [_,_,_] = ttb:list_config(File), - ?line ok = ttb:run_config(File), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + [_,_,_] = ttb:list_config(File), + ok = ttb:run_config(File), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config1"), filename:join(Privdir, atom_to_list(OtherNode)++"-write_config1")]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), case metatest(Other,OtherNode,Privdir,"-write_config1.ti") of {error,Reason} -> timer:sleep(5000), - ?line ok = ttb:format( + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config1"), filename:join(Privdir, atom_to_list(OtherNode)++ "-write_config1")]), - ?line io:format("\nTrying again: ~p\n",[flush()]), - ?line ct:fail(Reason); + io:format("\nTrying again: ~p\n",[flush()]), + ct:fail(Reason); ok -> ok end, @@ -441,58 +441,58 @@ write_config1(Config) when is_list(Config) -> write_config1(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). write_config2(suite) -> []; write_config2(doc) -> ["Write config from history (all)"]; write_config2(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"write_config2"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"write_config2"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ok = ttb:write_config(File,all), - ?line ttb:stop(), - ?line [_,_,_] = ttb:list_config(File), - ?line ok = ttb:run_config(File), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ok = ttb:write_config(File,all), + ttb:stop(), + [_,_,_] = ttb:list_config(File), + ok = ttb:run_config(File), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config2"), filename:join(Privdir, atom_to_list(OtherNode)++"-write_config2")]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), case metatest(Other,OtherNode,Privdir,"-write_config2.ti") of {error,Reason} -> timer:sleep(5000), - ?line ok = ttb:format( + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config2"), filename:join(Privdir, atom_to_list(OtherNode)++ "-write_config2")]), - ?line io:format("\nTrying again: ~p\n",[flush()]), - ?line ct:fail(Reason); + io:format("\nTrying again: ~p\n",[flush()]), + ct:fail(Reason); ok -> ok end, ok. write_config2(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). write_config3(suite) -> @@ -500,65 +500,65 @@ write_config3(suite) -> write_config3(doc) -> ["Write config from history (selected and append)"]; write_config3(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"write_config3"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"write_config3"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ok = ttb:write_config(File,[1,2]), - ?line ttb:stop([nofetch]), - ?line [_,_] = ttb:list_config(File), - ?line ok = ttb:run_config(File), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ok = ttb:write_config(File,[1,2]), + ttb:stop([nofetch]), + [_,_] = ttb:list_config(File), + ok = ttb:run_config(File), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config3"), filename:join(Privdir, atom_to_list(OtherNode)++"-write_config3")]), - ?line [end_of_trace] = flush(), %foo is not traced + [end_of_trace] = flush(), %foo is not traced - ?line ok = ttb:write_config(File,[{ttb,tp,[?MODULE,foo,[]]}], + ok = ttb:write_config(File,[{ttb,tp,[?MODULE,foo,[]]}], [append]), - ?line [_,_,_] = ttb:list_config(File), - ?line ok = ttb:run_config(File), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + [_,_,_] = ttb:list_config(File), + ok = ttb:run_config(File), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config3"), filename:join(Privdir, atom_to_list(OtherNode)++"-write_config3")]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), case metatest(Other,OtherNode,Privdir,"-write_config3.ti") of {error,Reason} -> timer:sleep(5000), - ?line ok = ttb:format( + ok = ttb:format( [filename:join(Privdir, atom_to_list(Node)++"-write_config3"), filename:join(Privdir, atom_to_list(OtherNode)++ "-write_config3")]), - ?line io:format("\nTrying again: ~p\n",[flush()]), - ?line ct:fail(Reason); + io:format("\nTrying again: ~p\n",[flush()]), + ct:fail(Reason); ok -> ok end, ok. write_config3(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). @@ -567,39 +567,39 @@ history(suite) -> history(doc) -> ["List history and execute entry from history"]; history(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - - ?line Nodes = [Node,OtherNode], - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"history"), - ?line StartOpts = [{file, File}, + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + + Nodes = [Node,OtherNode], + Privdir=priv_dir(Config), + File = filename:join(Privdir,"history"), + StartOpts = [{file, File}, {handler,{fun myhandler/4, S}}], - ?line {ok,[_,_]} = ttb:tracer(Nodes,StartOpts), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:ctp(?MODULE,foo), - ?line [{1,{ttb,tracer,[Nodes,StartOpts]}}, + {ok,[_,_]} = ttb:tracer(Nodes,StartOpts), + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:ctp(?MODULE,foo), + [{1,{ttb,tracer,[Nodes,StartOpts]}}, {2,{ttb,p,[all,call]}}, {3,{ttb,tp,[?MODULE,foo,[]]}}, {4,{ttb,ctp,[?MODULE,foo]}}] = ttb:list_history(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ok = ttb:run_history(3), - ?line ?MODULE:foo(), - ?line ok = ttb:run_history([3,4]), - ?line ?MODULE:foo(), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + rpc:call(OtherNode,?MODULE,foo,[]), + ok = ttb:run_history(3), + ?MODULE:foo(), + ok = ttb:run_history([3,4]), + ?MODULE:foo(), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir,atom_to_list(Node)++"-history"), filename:join(Privdir,atom_to_list(OtherNode)++"-history")]), - ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), ok. history(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). write_trace_info(suite) -> @@ -607,34 +607,34 @@ write_trace_info(suite) -> write_trace_info(doc) -> ["Write trace info and give handler explicitly in format command"]; write_trace_info(Config) when is_list(Config) -> - ?line Node = node(), - ?line {ok,OtherNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"write_trace_info"), - ?line {ok,[_,_]} = + Node = node(), + {ok,OtherNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"write_trace_info"), + {ok,[_,_]} = ttb:tracer([Node,OtherNode],[{file, File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), - ?line ok = ttb:write_trace_info(mytraceinfo,fun() -> node() end), - ?line ?MODULE:foo(), - ?line rpc:call(OtherNode,?MODULE,foo,[]), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call), + {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]), + ok = ttb:write_trace_info(mytraceinfo,fun() -> node() end), + ?MODULE:foo(), + rpc:call(OtherNode,?MODULE,foo,[]), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir,atom_to_list(Node)++"-write_trace_info"), filename:join(Privdir, atom_to_list(OtherNode)++"-write_trace_info")], [{handler,{fun otherhandler/4,S}}]), - ?line [{{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},[Node]}, + [{{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},[Node]}, {{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},[OtherNode]}, end_of_trace] = flush(), ok. write_trace_info(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). seq_trace(suite) -> @@ -642,22 +642,22 @@ seq_trace(suite) -> seq_trace(doc) -> ["Test sequential tracing"]; seq_trace(Config) when is_list(Config) -> - ?line S = self(), + S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"seq_trace"), - ?line {ok,[Node]} = ttb:tracer(node(),[{file,File}, + Privdir=priv_dir(Config), + File = filename:join(Privdir,"seq_trace"), + {ok,[Node]} = ttb:tracer(node(),[{file,File}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{new,[{matched,Node,0}]}]} = ttb:p(new,call), - ?line {ok,[{matched,Node,1},{saved,1}]} = + {ok,[{new,[{matched,Node,0}]}]} = ttb:p(new,call), + {ok,[{matched,Node,1},{saved,1}]} = ttb:tpl(?MODULE,seq,0,ttb:seq_trigger_ms(send)), - ?line Start = spawn(fun() -> seq() end), - ?line timer:sleep(300), - ?line ttb:stop([nofetch]), - ?line ok = ttb:format( + Start = spawn(fun() -> seq() end), + timer:sleep(300), + ttb:stop([nofetch]), + ok = ttb:format( [filename:join(Privdir,atom_to_list(Node)++"-seq_trace")]), - ?line [{trace_ts,StartProc,call,{?MODULE,seq,[]},{_,_,_}}, + [{trace_ts,StartProc,call,{?MODULE,seq,[]},{_,_,_}}, {seq_trace,0,{send,{First, Seq0},StartProc,P1Proc,SpawnRequest1}}, {seq_trace,0,{send,{Seq0, Seq1},P1Proc,StartProc,SpawnReply1}}, {seq_trace,0,{send,{Seq2, Seq3},StartProc,P2Proc,SpawnRequest2}}, @@ -726,68 +726,68 @@ diskless(suite) -> diskless(doc) -> ["Start tracing on diskless remote node"]; diskless(Config) when is_list(Config) -> - ?line {ok,RemoteNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"diskless"), - ?line {ok,[RemoteNode]} = + {ok,RemoteNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"diskless"), + {ok,[RemoteNode]} = ttb:tracer([RemoteNode],[{file, {local, File}}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,RemoteNode,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,RemoteNode,1}]} = ttb:tp(?MODULE,foo,[]), + {ok,[{all,[{matched,RemoteNode,_}]}]} = ttb:p(all,call), + {ok,[{matched,RemoteNode,1}]} = ttb:tp(?MODULE,foo,[]), - ?line rpc:call(RemoteNode,?MODULE,foo,[]), - ?line timer:sleep(5000), % needed for the IP port to flush - ?line ttb:stop([nofetch]), - ?line ok = ttb:format(filename:join(Privdir, + rpc:call(RemoteNode,?MODULE,foo,[]), + timer:sleep(5000), % needed for the IP port to flush + ttb:stop([nofetch]), + ok = ttb:format(filename:join(Privdir, atom_to_list(RemoteNode)++"-diskless")), - ?line [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), ok. diskless(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). diskless_wrap(suite) -> []; diskless_wrap(doc) -> ["Start tracing on diskless remote node, save to local wrapped file"]; diskless_wrap(Config) when is_list(Config) -> - ?line {ok,RemoteNode} = test_server:start_node(node2,slave,[]), - ?line c:nl(?MODULE), - ?line S = self(), - ?line Privdir=priv_dir(Config), - ?line File = filename:join(Privdir,"diskless"), - ?line {ok,[RemoteNode]} = + {ok,RemoteNode} = test_server:start_node(node2,slave,[]), + c:nl(?MODULE), + S = self(), + Privdir=priv_dir(Config), + File = filename:join(Privdir,"diskless"), + {ok,[RemoteNode]} = ttb:tracer([RemoteNode],[{file, {local, {wrap,File,200,3}}}, {handler,{fun myhandler/4, S}}]), - ?line {ok,[{all,[{matched,RemoteNode,_}]}]} = ttb:p(all,call), - ?line {ok,[{matched,RemoteNode,1}]} = ttb:tp(?MODULE,foo,[]), + {ok,[{all,[{matched,RemoteNode,_}]}]} = ttb:p(all,call), + {ok,[{matched,RemoteNode,1}]} = ttb:tp(?MODULE,foo,[]), - ?line rpc:call(RemoteNode,?MODULE,foo,[]), - ?line timer:sleep(5000), % needed for the IP port to flush - ?line ttb:stop([nofetch]), - ?line ok = ttb:format(filename:join(Privdir, + rpc:call(RemoteNode,?MODULE,foo,[]), + timer:sleep(5000), % needed for the IP port to flush + ttb:stop([nofetch]), + ok = ttb:format(filename:join(Privdir, atom_to_list(RemoteNode)++"-diskless.*.wrp")), - ?line [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}}, + [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}}, end_of_trace] = flush(), ok. diskless_wrap(cleanup,_Config) -> - ?line test_server:stop_node(ttb_helper:get_node(node2)). + test_server:stop_node(ttb_helper:get_node(node2)). otp_4967_1(suite) -> []; otp_4967_1(doc) -> ["OTP-4967: clear flag"]; otp_4967_1(Config) when is_list(Config) -> - ?line {ok,[Node]} = ttb:tracer(), - ?line {ok,[{all,[{matched,Node,_}]}]} = ttb:p(all,call), - ?line {ok,[{all,[{matched,Node,_}]}]} = ttb:p(all,clear), - ?line stopped = ttb:stop(), + {ok,[Node]} = ttb:tracer(), + {ok,[{all,[{matched,Node,_}]}]} = ttb:p(all,call), + {ok,[{all,[{matched,Node,_}]}]} = ttb:p(all,clear), + stopped = ttb:stop(), ok. @@ -797,37 +797,37 @@ otp_4967_2(doc) -> ["OTP-4967: Trace message sent to {Name, Node}"]; otp_4967_2(Config) when is_list(Config) -> io:format("1: ~p",[erlang:timestamp()]), - ?line Privdir = priv_dir(Config), + Privdir = priv_dir(Config), io:format("2: ~p",[erlang:timestamp()]), - ?line File = filename:join(Privdir,"otp_4967"), + File = filename:join(Privdir,"otp_4967"), io:format("3: ~p",[erlang:timestamp()]), - ?line S = self(), + S = self(), io:format("4: ~p",[erlang:timestamp()]), - ?line {ok,[Node]} = + {ok,[Node]} = ttb:tracer(node(),[{file, File}, {handler,{fun myhandler/4, S}}]), io:format("5: ~p",[erlang:timestamp()]), %% Test that delayed registration of a process works. receive after 200 -> ok end, - ?line register(otp_4967,self()), + register(otp_4967,self()), io:format("6: ~p",[erlang:timestamp()]), - ?line {ok,[{S,[{matched,Node,1}]}]} = ttb:p(self(),s), + {ok,[{S,[{matched,Node,1}]}]} = ttb:p(self(),s), io:format("7: ~p",[erlang:timestamp()]), - ?line {otp_4967,node()} ! heihopp, + {otp_4967,node()} ! heihopp, io:format("8: ~p",[erlang:timestamp()]), - ?line stopped = ttb:stop([format]), + stopped = ttb:stop([format]), io:format("9: ~p",[erlang:timestamp()]), - ?line Msgs = flush(), + Msgs = flush(), io:format("10: ~p",[erlang:timestamp()]), - ?line io:format("Messages received: \n~p\n",[Msgs]), + io:format("Messages received: \n~p\n",[Msgs]), io:format("11: ~p",[erlang:timestamp()]), - ?line true = lists:member(heihopp,Msgs), % the heihopp message itself + true = lists:member(heihopp,Msgs), % the heihopp message itself io:format("13: ~p",[erlang:timestamp()]), - ?line {value,{trace_ts,_,send,heihopp,{_,otp_4967,Node},{_,_,_}}} = + {value,{trace_ts,_,send,heihopp,{_,otp_4967,Node},{_,_,_}}} = lists:keysearch(heihopp,4,Msgs), % trace trace of the heihopp message io:format("14: ~p",[erlang:timestamp()]), - ?line end_of_trace = lists:last(Msgs), % end of the trace + end_of_trace = lists:last(Msgs), % end of the trace ok. @@ -876,7 +876,7 @@ flush(Acc) -> end. foo() -> - %% Sync between nodes is not always exact, so here is a litle timeout to + %% Sync between nodes is not always exact, so here is a little timeout to %% make sure traces come i correct sequence when merging. %% In the real world there is no way to avoid this kind of trouble timer:sleep(100), @@ -909,8 +909,8 @@ metatest(Proc,Node,Privdir,Filename) -> end. check_gone(Dir,File) -> - ?line {ok,List} = file:list_dir(Dir), - ?line case lists:member(File,List) of + {ok,List} = file:list_dir(Dir), + case lists:member(File,List) of true -> timer:sleep(2000), {ok,NewList} = file:list_dir(Dir), @@ -928,11 +928,11 @@ check_gone(Dir,File) -> end. start_client_and_server() -> - ?line {ok,ClientNode} = test_server:start_node(client,slave,[]), - ?line ok = ttb_helper:c(code, add_paths, [code:get_path()]), - ?line {ok,ServerNode} = test_server:start_node(server,slave,[]), - ?line ok = ttb_helper:s(code, add_paths, [code:get_path()]), - ?line ttb_helper:clear(), + {ok,ClientNode} = test_server:start_node(client,slave,[]), + ok = ttb_helper:c(code, add_paths, [code:get_path()]), + {ok,ServerNode} = test_server:start_node(server,slave,[]), + ok = ttb_helper:s(code, add_paths, [code:get_path()]), + ttb_helper:clear(), {ServerNode, ClientNode}. stop_client_and_server() -> @@ -940,8 +940,8 @@ stop_client_and_server() -> ServerNode = ttb_helper:get_node(server), erlang:monitor_node(ClientNode,true), erlang:monitor_node(ServerNode,true), - ?line test_server:stop_node(ClientNode), - ?line test_server:stop_node(ServerNode), + test_server:stop_node(ClientNode), + test_server:stop_node(ServerNode), wait_for_client_and_server_stop(ClientNode,ServerNode). wait_for_client_and_server_stop(undefined,undefined) -> @@ -957,20 +957,20 @@ wait_for_client_and_server_stop(ClientNode,ServerNode) -> end. begin_trace(ServerNode, ClientNode, Dest) -> - ?line {ok, _} = + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, Dest}]), - ?line ttb:p(all, call), - ?line ttb:tp(server, received, []), - ?line ttb:tp(client, put, []), - ?line ttb:tp(client, get, []). + ttb:p(all, call), + ttb:tp(server, received, []), + ttb:tp(client, put, []), + ttb:tp(client, get, []). begin_trace_local(ServerNode, ClientNode, Dest) -> - ?line {ok, _} = + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, Dest}]), - ?line ttb:p(all, call), - ?line ttb:tpl(server, received, []), - ?line ttb:tpl(client, put, []), - ?line ttb:tpl(client, get, []). + ttb:p(all, call), + ttb:tpl(server, received, []), + ttb:tpl(client, put, []), + ttb:tpl(client, get, []). check_size(N, Dest, Output, ServerNode, ClientNode) -> begin_trace(ServerNode, ClientNode, Dest), @@ -997,16 +997,16 @@ fetch_when_no_option_given(suite) -> fetch_when_no_option_given(doc) -> ["Fetch when no option given"]; fetch_when_no_option_given(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line {ok, Privdir} = file:get_cwd(), - ?line [] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")), + {ServerNode, ClientNode} = start_client_and_server(), + {ok, Privdir} = file:get_cwd(), + [] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")), begin_trace(ServerNode, ClientNode, ?FNAME), - ?line ttb_helper:msgs(4), - ?line stopped = ttb:stop(), - ?line [_] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")). + ttb_helper:msgs(4), + stopped = ttb:stop(), + [_] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")). fetch_when_no_option_given(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). basic_ttb_run_ip_port(suite) -> @@ -1014,123 +1014,123 @@ basic_ttb_run_ip_port(suite) -> basic_ttb_run_ip_port(doc) -> ["Basic ttb run ip port"]; basic_ttb_run_ip_port(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line check_size(1, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(10, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode). + {ServerNode, ClientNode} = start_client_and_server(), + check_size(1, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), + check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), + check_size(10, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode). basic_ttb_run_ip_port(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). basic_ttb_run_file_port(suite) -> []; basic_ttb_run_file_port(doc) -> ["Basic ttb run file port"]; basic_ttb_run_file_port(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line check_size(1, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line check_size(10, ?FNAME, ?OUTPUT, ServerNode, ClientNode). + {ServerNode, ClientNode} = start_client_and_server(), + check_size(1, ?FNAME, ?OUTPUT, ServerNode, ClientNode), + check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), + check_size(10, ?FNAME, ?OUTPUT, ServerNode, ClientNode). basic_ttb_run_file_port(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). return_fetch_dir_implies_fetch(suite) -> []; return_fetch_dir_implies_fetch(doc) -> ["Return_fetch_dir implies fetch"]; return_fetch_dir_implies_fetch(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, ?FNAME), - ?line ttb_helper:msgs(2), - ?line {_,_} = ttb:stop([return_fetch_dir]). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, ?FNAME), + ttb_helper:msgs(2), + {_,_} = ttb:stop([return_fetch_dir]). return_fetch_dir_implies_fetch(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). logfile_name_in_fetch_dir(suite) -> []; logfile_name_in_fetch_dir(doc) -> ["Logfile name in fetch dir"]; logfile_name_in_fetch_dir(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}), - ?line {_,Dir} = ttb:stop([return_fetch_dir]), - ?line P1 = lists:nth(3, string:lexemes(filename:basename(Dir), "_")), - ?line P2 = hd(string:lexemes(P1, "-")), - ?line _File = P2. + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, {local, ?FNAME}), + {_,Dir} = ttb:stop([return_fetch_dir]), + P1 = lists:nth(3, string:lexemes(filename:basename(Dir), "_")), + P2 = hd(string:lexemes(P1, "-")), + _File = P2. logfile_name_in_fetch_dir(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). upload_to_my_logdir(suite) -> []; upload_to_my_logdir(doc) -> ["Upload to my logdir"]; upload_to_my_logdir(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line {ok, _} = + {ServerNode, ClientNode} = start_client_and_server(), + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), - ?line {stopped,_} = ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}]), - ?line true = filelib:is_file(?DIRNAME), - ?line [] = filelib:wildcard("ttb_upload_"++?FNAME). + {stopped,_} = ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}]), + true = filelib:is_file(?DIRNAME), + [] = filelib:wildcard("ttb_upload_"++?FNAME). upload_to_my_logdir(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). upload_to_my_existing_logdir(suite) -> []; upload_to_my_existing_logdir(doc) -> ["Upload to my existing logdir"]; upload_to_my_existing_logdir(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line ok = file:make_dir(?DIRNAME), - ?line {ok, _} = + {ServerNode, ClientNode} = start_client_and_server(), + ok = file:make_dir(?DIRNAME), + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), - ?line {error,_,_} = (catch ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}])), - ?line {stopped,_} = ttb:stop(return_fetch_dir). + {error,_,_} = (catch ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}])), + {stopped,_} = ttb:stop(return_fetch_dir). upload_to_my_existing_logdir(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). fetch_with_options_not_as_list(suite) -> []; fetch_with_options_not_as_list(doc) -> ["Fetch with options not as list"]; fetch_with_options_not_as_list(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line {ok, _} = + {ServerNode, ClientNode} = start_client_and_server(), + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), - ?line {stopped, D} = ttb:stop(return_fetch_dir), - ?line false = filelib:is_file(?OUTPUT), - ?line ttb:format(D, {out, ?OUTPUT}), - ?line true = filelib:is_file(?OUTPUT). + {stopped, D} = ttb:stop(return_fetch_dir), + false = filelib:is_file(?OUTPUT), + ttb:format(D, {out, ?OUTPUT}), + true = filelib:is_file(?OUTPUT). fetch_with_options_not_as_list(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). error_when_formatting_multiple_files_4393(suite) -> []; error_when_formatting_multiple_files_4393(doc) -> ["Error when formatting multiple files"]; error_when_formatting_multiple_files_4393(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, ?FNAME), - ?line ttb_helper:msgs(2), - ?line {_, Dir} = ttb:stop(return_fetch_dir), - ?line Files = [filename:join(Dir, atom_to_list(ServerNode) ++ "-" ++ ?FNAME), + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, ?FNAME), + ttb_helper:msgs(2), + {_, Dir} = ttb:stop(return_fetch_dir), + Files = [filename:join(Dir, atom_to_list(ServerNode) ++ "-" ++ ?FNAME), filename:join(Dir, atom_to_list(ClientNode) ++ "-" ++ ?FNAME)], - ?line ok = ttb:format(Files). + ok = ttb:format(Files). error_when_formatting_multiple_files_4393(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). format_on_trace_stop(suite) -> []; format_on_trace_stop(doc) -> ["Format on trace stop"]; format_on_trace_stop(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}), - ?line ttb_helper:msgs_ip(2), - ?line file:delete("HANDLER_OK"), - ?line {_,_} = ttb:stop([fetch, return_fetch_dir, {format, {handler, marking_call_handler()}}]), - ?line true = filelib:is_file("HANDLER_OK"), - ?line ok = file:delete("HANDLER_OK"). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, {local, ?FNAME}), + ttb_helper:msgs_ip(2), + file:delete("HANDLER_OK"), + {_,_} = ttb:stop([fetch, return_fetch_dir, {format, {handler, marking_call_handler()}}]), + true = filelib:is_file("HANDLER_OK"), + ok = file:delete("HANDLER_OK"). format_on_trace_stop(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). %% The following three tests are for the issue "fixes fetch fail when nodes on the same host %% have different cwd" @@ -1139,41 +1139,41 @@ trace_to_remote_files_on_localhost_with_different_pwd(suite) -> trace_to_remote_files_on_localhost_with_different_pwd(doc) -> ["Trace to remote files on localhost with different pwd"]; trace_to_remote_files_on_localhost_with_different_pwd(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line ok = file:set_cwd(".."), - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), - ?line ok = file:set_cwd(OldDir). + {ok, OldDir} = file:get_cwd(), + ok = file:set_cwd(".."), + {ServerNode, ClientNode} = start_client_and_server(), + check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode), + ok = file:set_cwd(OldDir). trace_to_remote_files_on_localhost_with_different_pwd(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_to_local_files_on_localhost_with_different_pwd(suite) -> []; trace_to_local_files_on_localhost_with_different_pwd(doc) -> ["Trace to local files on localhost with different pwd"]; trace_to_local_files_on_localhost_with_different_pwd(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line ok = file:set_cwd(".."), - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), - ?line ok = file:set_cwd(OldDir). + {ok, OldDir} = file:get_cwd(), + ok = file:set_cwd(".."), + {ServerNode, ClientNode} = start_client_and_server(), + check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode), + ok = file:set_cwd(OldDir). trace_to_local_files_on_localhost_with_different_pwd(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_to_remote_files_on_localhost_with_different_pwd_abs(suite) -> []; trace_to_remote_files_on_localhost_with_different_pwd_abs(doc) -> ["Trace to remote files on localhost with different pwd abs"]; trace_to_remote_files_on_localhost_with_different_pwd_abs(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line ok = file:set_cwd(".."), - ?line {ok, Path} = file:get_cwd(), - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line File = filename:join(Path, ?FNAME), - ?line check_size(2, File, ?OUTPUT, ServerNode, ClientNode), - ?line ok = file:set_cwd(OldDir). + {ok, OldDir} = file:get_cwd(), + ok = file:set_cwd(".."), + {ok, Path} = file:get_cwd(), + {ServerNode, ClientNode} = start_client_and_server(), + File = filename:join(Path, ?FNAME), + check_size(2, File, ?OUTPUT, ServerNode, ClientNode), + ok = file:set_cwd(OldDir). trace_to_remote_files_on_localhost_with_different_pwd_abs(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). %% Trace is not affected by changes of cwd on control node or remote nodes during tracing %% (three tests) @@ -1182,20 +1182,20 @@ changing_cwd_on_control_node(suite) -> changing_cwd_on_control_node(doc) -> ["Changing cwd on control node during tracing is safe"]; changing_cwd_on_control_node(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, ?FNAME), - ?line NumMsgs = 3, - ?line ttb_helper:msgs(NumMsgs), - ?line ok = file:set_cwd(".."), - ?line ttb_helper:msgs(NumMsgs), - ?line {_, D} = ttb:stop([fetch, return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), - ?line {ok, Ret} = file:consult(?OUTPUT), + {ok, OldDir} = file:get_cwd(), + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, ?FNAME), + NumMsgs = 3, + ttb_helper:msgs(NumMsgs), + ok = file:set_cwd(".."), + ttb_helper:msgs(NumMsgs), + {_, D} = ttb:stop([fetch, return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), + {ok, Ret} = file:consult(?OUTPUT), check_output(2*(NumMsgs + 1),Ret), ok = file:set_cwd(OldDir). changing_cwd_on_control_node(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). changing_cwd_on_control_node_with_local_trace(suite) -> []; @@ -1216,156 +1216,156 @@ changing_cwd_on_control_node_with_local_trace(Config) when is_list(Config) -> check_output(Expected, Ret), ok = file:set_cwd(OldDir). changing_cwd_on_control_node_with_local_trace(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). changing_cwd_on_remote_node(suite) -> []; changing_cwd_on_remote_node(doc) -> ["Changing cwd on remote node during tracing is safe"]; changing_cwd_on_remote_node(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace(ServerNode, ClientNode, ?FNAME), - ?line NumMsgs = 2, - ?line ttb_helper:msgs(NumMsgs), - ?line ok = rpc:call(ClientNode, file, set_cwd, [".."]), - ?line ttb_helper:msgs(NumMsgs), - ?line {_, D} = ttb:stop([fetch, return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), - ?line {ok, Ret} = file:consult(?OUTPUT), + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace(ServerNode, ClientNode, ?FNAME), + NumMsgs = 2, + ttb_helper:msgs(NumMsgs), + ok = rpc:call(ClientNode, file, set_cwd, [".."]), + ttb_helper:msgs(NumMsgs), + {_, D} = ttb:stop([fetch, return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), + {ok, Ret} = file:consult(?OUTPUT), check_output(2*(NumMsgs + 1),Ret). changing_cwd_on_remote_node(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). one_command_trace_setup(suite) -> []; one_command_trace_setup(doc) -> ["One command trace setup"]; one_command_trace_setup(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line ttb:start_trace([ClientNode, ServerNode], + {ServerNode, ClientNode} = start_client_and_server(), + ttb:start_trace([ClientNode, ServerNode], [{server, received, '_', []}, {client, put, 1, []}, {client, get, '_', []}], {all, call}, [{file, ?FNAME}]), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop(return_fetch_dir), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), - ?line {ok, Ret} = file:consult(?OUTPUT), - ?line 5 = length(Ret). + ttb_helper:msgs(2), + {_, D} = ttb:stop(return_fetch_dir), + ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]), + {ok, Ret} = file:consult(?OUTPUT), + 5 = length(Ret). one_command_trace_setup(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). dbg_style_fetch(suite) -> []; dbg_style_fetch(doc) -> ["Dbg style fetch"]; dbg_style_fetch(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line DirSize = length(element(2, file:list_dir("."))), - ?line ttb:start_trace([ClientNode, ServerNode], + {ServerNode, ClientNode} = start_client_and_server(), + DirSize = length(element(2, file:list_dir("."))), + ttb:start_trace([ClientNode, ServerNode], [{server, received, '_', []}, {client, put, 1, []}, {client, get, '_', []}], {all, call}, [{shell, only}]), - ?line DirSize = length(element(2, file:list_dir("."))), - ?line ttb_helper:msgs(2), - ?line DirSize = length(element(2, file:list_dir("."))), - ?line stopped, ttb:stop(format), + DirSize = length(element(2, file:list_dir("."))), + ttb_helper:msgs(2), + DirSize = length(element(2, file:list_dir("."))), + stopped, ttb:stop(format), %%+1 -> ttb_last_trace - ?line true = (DirSize + 1 == length(element(2, file:list_dir(".")))), - ?line {ok,[{all, [{matched,_,_}, {matched,_,_}]}]} = + true = (DirSize + 1 == length(element(2, file:list_dir(".")))), + {ok,[{all, [{matched,_,_}, {matched,_,_}]}]} = ttb:start_trace([ClientNode, ServerNode], [{server, received, '_', []}, {client, put, 1, []}, {client, get, '_', []}], {all, call}, [{shell, only}]), - ?line ttb:stop(). + ttb:stop(). dbg_style_fetch(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). shell_tracing_init(suite) -> []; shell_tracing_init(doc) -> ["Shell tracing init"]; shell_tracing_init(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line ttb:tracer([ClientNode, ServerNode], shell), - ?line ttb:stop(), - ?line ttb:tracer([ClientNode, ServerNode], + {ServerNode, ClientNode} = start_client_and_server(), + ttb:tracer([ClientNode, ServerNode], shell), + ttb:stop(), + ttb:tracer([ClientNode, ServerNode], [{file, {local, ?FNAME}}, shell]), - ?line ttb:stop(), - ?line local_client_required_on_shell_tracing = + ttb:stop(), + local_client_required_on_shell_tracing = try ttb:tracer([ClientNode, ServerNode],[{file, ?FNAME}, shell]) catch exit:local_client_required_on_shell_tracing -> local_client_required_on_shell_tracing end. shell_tracing_init(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). only_one_state_for_format_handler(suite) -> []; only_one_state_for_format_handler(doc) -> ["Only one state for format handler"]; only_one_state_for_format_handler(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_local(ServerNode, ClientNode, ?FNAME), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, counter_call_handler()}]), - ?line {ok, Ret} = file:consult(?OUTPUT), - ?line [5] = Ret. + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_local(ServerNode, ClientNode, ?FNAME), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, counter_call_handler()}]), + {ok, Ret} = file:consult(?OUTPUT), + [5] = Ret. only_one_state_for_format_handler(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). only_one_state_with_default_format_handler(suite) -> []; only_one_state_with_default_format_handler(doc) -> ["Only one state with default format handler"]; only_one_state_with_default_format_handler(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_local(ServerNode, ClientNode, ?FNAME), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}]), - ?line true = filelib:is_file(?OUTPUT). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_local(ServerNode, ClientNode, ?FNAME), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}]), + true = filelib:is_file(?OUTPUT). only_one_state_with_default_format_handler(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). only_one_state_with_initial_format_handler(suite) -> []; only_one_state_with_initial_format_handler(doc) -> ["Only one state with initial format handler"]; only_one_state_with_initial_format_handler(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line {ok, _} = + {ServerNode, ClientNode} = start_client_and_server(), + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}, {handler, counter_call_handler()}]), - ?line ttb:p(all, call), - ?line ttb:tpl(server, received, []), - ?line ttb:tpl(client, put, []), - ?line ttb:tpl(client, get, []), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}]), - ?line {ok, Ret} = file:consult(?OUTPUT), - ?line [5] = Ret. + ttb:p(all, call), + ttb:tpl(server, received, []), + ttb:tpl(client, put, []), + ttb:tpl(client, get, []), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}]), + {ok, Ret} = file:consult(?OUTPUT), + [5] = Ret. only_one_state_with_initial_format_handler(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). run_trace_with_shortcut(Shortcut, Ret, F) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line {ok, _} = + {ServerNode, ClientNode} = start_client_and_server(), + {ok, _} = ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]), - ?line ttb:p(all, call), - ?line ttb:F(client, put, Shortcut), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler()}]), - ?line {ok, Ret} =file:consult(?OUTPUT), - ?line stop_client_and_server(). + ttb:p(all, call), + ttb:F(client, put, Shortcut), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler()}]), + {ok, Ret} =file:consult(?OUTPUT), + stop_client_and_server(). fun_for(return) -> {codestr, "fun(_) -> return_trace() end"}; @@ -1377,48 +1377,48 @@ run_trace_with_shortcut1(suite) -> run_trace_with_shortcut1(doc) -> ["Run trace with shortcut 1"]; run_trace_with_shortcut1(Config) when is_list(Config) -> - ?line run_trace_with_shortcut(caller, [ok,ok], tp), - ?line run_trace_with_shortcut(caller, [ok,ok], tpl). + run_trace_with_shortcut(caller, [ok,ok], tp), + run_trace_with_shortcut(caller, [ok,ok], tpl). run_trace_with_shortcut1(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). run_trace_with_shortcut2(suite) -> []; run_trace_with_shortcut2(doc) -> ["Run trace with shortcut 2"]; run_trace_with_shortcut2(Config) when is_list(Config) -> - ?line run_trace_with_shortcut(return, [ok,ok], tp), - ?line run_trace_with_shortcut(return, [ok,ok], tpl). + run_trace_with_shortcut(return, [ok,ok], tp), + run_trace_with_shortcut(return, [ok,ok], tpl). run_trace_with_shortcut2(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). run_trace_with_shortcut3(suite) -> []; run_trace_with_shortcut3(doc) -> ["Run trace with shortcut 3"]; run_trace_with_shortcut3(Config) when is_list(Config) -> - ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tp), - ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tpl). + run_trace_with_shortcut(fun_for(return), [ok,ok], tp), + run_trace_with_shortcut(fun_for(return), [ok,ok], tpl). run_trace_with_shortcut3(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). run_trace_with_shortcut4(suite) -> []; run_trace_with_shortcut4(doc) -> ["Run trace with shortcut 4"]; run_trace_with_shortcut4(Config) when is_list(Config) -> - ?line run_trace_with_shortcut(fun_for(msg_false), [], tp), - ?line run_trace_with_shortcut(fun_for(msg_false), [], tpl). + run_trace_with_shortcut(fun_for(msg_false), [], tp), + run_trace_with_shortcut(fun_for(msg_false), [], tpl). run_trace_with_shortcut4(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). cant_specify_local_and_flush(suite) -> []; cant_specify_local_and_flush(doc) -> ["Can't specify local and flush"]; cant_specify_local_and_flush(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line flush_unsupported_with_ip_trace_port = + {ServerNode, ClientNode} = start_client_and_server(), + flush_unsupported_with_ip_trace_port = try ttb:tracer([ServerNode, ClientNode], [{flush, 1000}, {file, {local, ?FNAME}}]) catch @@ -1426,37 +1426,37 @@ cant_specify_local_and_flush(Config) when is_list(Config) -> flush_unsupported_with_ip_trace_port end. cant_specify_local_and_flush(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_sorted_by_default(suite) -> []; trace_sorted_by_default(doc) -> ["Trace sorted by default"]; trace_sorted_by_default(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_local(ServerNode, ClientNode, ?FILE), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, false}]), + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_local(ServerNode, ClientNode, ?FILE), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, false}]), {ok, Ret} = file:consult(?OUTPUT), - ?line [ClientNode,ServerNode,ClientNode,ServerNode,ServerNode] = Ret. + [ClientNode,ServerNode,ClientNode,ServerNode,ServerNode] = Ret. trace_sorted_by_default(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). disable_sorting(suite) -> []; disable_sorting(doc) -> ["Disable sorting"]; disable_sorting(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_local(ServerNode, ClientNode, ?FILE), - ?line ttb_helper:msgs(2), - ?line {_, D} = ttb:stop([return_fetch_dir]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, true}]), + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_local(ServerNode, ClientNode, ?FILE), + ttb_helper:msgs(2), + {_, D} = ttb:stop([return_fetch_dir]), + ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, true}]), {ok, Ret} = file:consult(?OUTPUT), - ?line [ClientNode,ClientNode,ServerNode,ServerNode,ServerNode] = Ret. + [ClientNode,ClientNode,ServerNode,ServerNode,ServerNode] = Ret. disable_sorting(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). %% ----------------------------------------------------------------------------- %% tests for autoresume of tracing @@ -1467,71 +1467,71 @@ trace_resumed_after_node_restart(suite) -> trace_resumed_after_node_restart(doc) -> ["Test trace resumed after node restart, trace to files on remote node."]; trace_resumed_after_node_restart(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_with_resume(ServerNode, ClientNode, ?FNAME), - ?line logic(2,6,file). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_with_resume(ServerNode, ClientNode, ?FNAME), + logic(2,6,file). trace_resumed_after_node_restart(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_resumed_after_node_restart_ip(suite) -> []; trace_resumed_after_node_restart_ip(doc) -> ["Test trace resumed after node restart, trace via tcp/ip to local node."]; trace_resumed_after_node_restart_ip(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_with_resume(ServerNode, ClientNode, {local, ?FNAME}), - ?line logic(2,6,local). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_with_resume(ServerNode, ClientNode, {local, ?FNAME}), + logic(2,6,local). trace_resumed_after_node_restart_ip(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_resumed_after_node_restart_wrap(suite) -> []; trace_resumed_after_node_restart_wrap(doc) -> ["Test trace resumed after node restart, wrap option."]; trace_resumed_after_node_restart_wrap(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), - ?line logic(1,4,file). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), + logic(1,4,file). trace_resumed_after_node_restart_wrap(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). trace_resumed_after_node_restart_wrap_mult(suite) -> []; trace_resumed_after_node_restart_wrap_mult(doc) -> ["Test trace resumed after node restart, wrap option, multiple files."]; trace_resumed_after_node_restart_wrap_mult(Config) when is_list(Config) -> - ?line {ServerNode, ClientNode} = start_client_and_server(), - ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), - ?line logic(20,8,file). + {ServerNode, ClientNode} = start_client_and_server(), + begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}), + logic(20,8,file). trace_resumed_after_node_restart_wrap_mult(cleanup,_Config) -> - ?line stop_client_and_server(). + stop_client_and_server(). logic(N, M, TracingType) -> helper_msgs(N, TracingType), test_server:stop_node(ttb_helper:get_node(client)), timer:sleep(2500), - ?line {ok,_ClientNode} = test_server:start_node(client,slave,[]), + {ok,_ClientNode} = test_server:start_node(client,slave,[]), ct:log("client started",[]), - ?line ok = ttb_helper:c(code, add_paths, [code:get_path()]), + ok = ttb_helper:c(code, add_paths, [code:get_path()]), ct:log("paths added",[]), - ?line ttb_helper:c(client, init, []), + ttb_helper:c(client, init, []), ct:log("client initiated",[]), - ?line helper_msgs(N, TracingType), + helper_msgs(N, TracingType), ct:log("helper msgs sent and flushed",[]), - ?line {_, D} = ttb:stop([return_fetch_dir]), + {_, D} = ttb:stop([return_fetch_dir]), ct:log("stopped ~p",[D]), - ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler2()}]), + ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler2()}]), ct:log("formatted ~p",[{D,?OUTPUT}]), - ?line {ok, Ret} = file:consult(?OUTPUT), + {ok, Ret} = file:consult(?OUTPUT), ct:log("consulted: ~p",[Ret]), check_output(M,Ret). begin_trace_with_resume(ServerNode, ClientNode, Dest) -> - ?line {ok, _} = ttb:tracer([ServerNode,ClientNode], [{file, Dest}, resume]), - ?line ttb:p(all, [call, timestamp]), - ?line ttb:tp(server, received, []), - ?line ttb:tp(client, put, []), - ?line ttb:tp(client, get, []). + {ok, _} = ttb:tracer([ServerNode,ClientNode], [{file, Dest}, resume]), + ttb:p(all, [call, timestamp]), + ttb:tp(server, received, []), + ttb:tp(client, put, []), + ttb:tp(client, get, []). ret_caller_call_handler2() -> {fun(A, {trace_ts, _, call, _, _} ,_,_) -> io:format(A, "ok.~n", []); diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk index 5ea7b062fc4f..f6713cde072c 100644 --- a/lib/observer/vsn.mk +++ b/lib/observer/vsn.mk @@ -1 +1 @@ -OBSERVER_VSN = 2.11.1 +OBSERVER_VSN = 2.15.1 diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index 5a01630cbc2c..e99f16624ea7 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2021. All Rights Reserved. + * Copyright Ericsson AB 1999-2023. 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. @@ -1328,7 +1328,7 @@ static db_result_msg encode_column_name_list(SQLSMALLINT num_of_columns, &nullable))) DO_EXIT(EXIT_DESC); - if(sql_type == SQL_LONGVARCHAR || sql_type == SQL_LONGVARBINARY || sql_type == SQL_WLONGVARCHAR) + if(size == 0 && (sql_type == SQL_LONGVARCHAR || sql_type == SQL_LONGVARBINARY || sql_type == SQL_WLONGVARCHAR)) size = MAXCOLSIZE; (columns(state)[i]).type.decimal_digits = dec_digits; diff --git a/lib/odbc/configure b/lib/odbc/configure index a167f1b0ece9..12df3656c65e 100755 --- a/lib/odbc/configure +++ b/lib/odbc/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +221,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +253,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +292,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +310,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +332,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +341,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +380,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +398,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +430,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +459,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +503,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +517,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +534,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,50 +606,46 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' ac_unique_file="c_src/odbcserver.c" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS ODBC_INCLUDE @@ -629,7 +656,6 @@ THR_DEFS GETCONF EGREP GREP -CPP RM LD SET_MAKE @@ -642,6 +668,10 @@ CPPFLAGS LDFLAGS CFLAGS CC +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -693,7 +723,6 @@ ac_subst_files='' ac_user_opts=' enable_option_checking with_odbc -enable_sanitizers ' ac_precious_vars='build_alias host_alias @@ -702,8 +731,7 @@ CC CFLAGS LDFLAGS LIBS -CPPFLAGS -CPP' +CPPFLAGS' # Initialize some variables set by options. @@ -772,8 +800,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -814,9 +840,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -840,9 +866,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1053,9 +1079,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1069,9 +1095,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1115,9 +1141,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1133,7 +1159,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1197,7 +1223,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1315,6 +1341,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1322,13 +1349,6 @@ if test -n "$ac_init_help"; then cat <<\_ACEOF -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-sanitizers[=comma-separated list of sanitizers] - Default=address,undefined - Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) @@ -1344,7 +1364,6 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory - CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1365,9 +1384,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1395,7 +1414,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1403,7 +1423,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1413,9 +1433,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1432,14 +1452,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1447,14 +1467,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1470,14 +1491,14 @@ fi ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1485,17 +1506,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1516,11 +1538,12 @@ fi ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -1528,16 +1551,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -1555,194 +1571,29 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in @@ -1750,26 +1601,28 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -1781,17 +1634,18 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -1799,12 +1653,13 @@ if (sizeof ($2)) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -1812,18 +1667,19 @@ if (sizeof (($2))) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop eval "$3=yes" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -1835,16 +1691,17 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (ac_aggr.$3) @@ -1853,14 +1710,15 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) @@ -1869,22 +1727,66 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop eval "$4=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes @@ -1899,7 +1801,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -1909,14 +1811,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1926,9 +1829,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -1936,14 +1840,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -1953,14 +1857,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -1970,9 +1875,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -1980,14 +1886,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -1995,7 +1901,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2005,12 +1911,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -2020,12 +1927,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -2053,9 +1960,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2107,8 +2035,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2143,7 +2075,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2178,11 +2110,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2193,8 +2127,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2218,7 +2152,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2226,14 +2160,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2241,15 +2175,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2257,8 +2191,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2272,63 +2206,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2338,61 +2257,476 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in @@ -2402,11 +2736,12 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -2420,57 +2755,125 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_aux_dir= -for ac_dir in ${ERL_TOP}/erts/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in ${ERL_TOP}/erts/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2489,21 +2892,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2522,22 +2926,116 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=win32 + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac -# Check whether --with-odbc was given. -if test "${with_odbc+set}" = set; then : - withval=$with_odbc; + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 fi -if test "$with_odbc" = "no"; then - rm -f "$ERL_TOP/lib/odbc/SKIP" +# Check whether --with-odbc was given. +if test ${with_odbc+y} +then : + withval=$with_odbc; +fi + -else erl_xcomp_without_sysroot=no if test "$cross_compiling" = "yes"; then @@ -2549,6 +3047,15 @@ else fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2557,11 +3064,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2569,11 +3077,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2584,11 +3096,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2597,11 +3109,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2609,11 +3122,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2624,11 +3141,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2636,8 +3153,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2650,11 +3167,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2662,11 +3180,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2677,11 +3199,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2690,11 +3212,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2703,15 +3226,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2727,18 +3254,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2749,11 +3276,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2761,11 +3289,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2776,11 +3308,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2793,11 +3325,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2805,11 +3338,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2820,11 +3357,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2836,34 +3373,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2873,7 +3514,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -2881,7 +3522,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2893,9 +3534,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -2916,11 +3557,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2937,7 +3579,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2953,44 +3595,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -3004,15 +3648,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3021,7 +3665,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3033,8 +3677,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3042,10 +3686,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3053,39 +3697,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3099,11 +3744,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3112,31 +3758,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3146,29 +3793,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3177,57 +3828,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3242,94 +3896,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3350,123 +4054,124 @@ MIXED_VSL=no MIXED_VC=no MIXED_MINGW=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 -$as_echo_n "checking for mixed mingw-gcc and native VC++ environment... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 +printf %s "checking for mixed mingw-gcc and native VC++ environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then if test -x /usr/bin/msys-?.0.dll; then CFLAGS="$CFLAGS -O2" MIXED_MSYS=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 -$as_echo "MSYS and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 +printf "%s\n" "MSYS and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" MIXED_CYGWIN=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 -$as_echo "Cygwin and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 +printf "%s\n" "Cygwin and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /bin/wslpath; then CFLAGS="$CFLAGS -O2" MIXED_WSL=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 -$as_echo "WSL and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 +printf "%s\n" "WSL and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$MIXED_MSYS" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 -$as_echo_n "checking for mixed cygwin and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 +printf %s "checking for mixed cygwin and native MinGW environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then if test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 -$as_echo_n "checking for mixed MSYS and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 +printf %s "checking for mixed MSYS and native MinGW environment... " >&6; } if test "x$GCC" = x"yes"; then if test -x /usr/bin/msys-=.0.dll; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 -$as_echo_n "checking if we mix cygwin with any native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 +printf %s "checking if we mix cygwin with any native compiler... " >&6; } if test "X$MIXED_CYGWIN" = "Xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 -$as_echo_n "checking if we mix msys with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 +printf %s "checking if we mix msys with another native compiler... " >&6; } if test "X$MIXED_MSYS" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 -$as_echo_n "checking if we mix WSL with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 +printf %s "checking if we mix WSL with another native compiler... " >&6; } if test "X$MIXED_WSL" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else +ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval test \${ac_cv_prog_make_${ac_make}_set+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @@ -3482,12 +4187,12 @@ esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } SET_MAKE= else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi @@ -3496,11 +4201,12 @@ for ac_prog in ld.sh do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$LD"; then ac_cv_prog_LD="$LD" # Let the user override the test. else @@ -3508,11 +4214,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LD="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3523,11 +4233,11 @@ fi fi LD=$ac_cv_prog_LD if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -$as_echo "$LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +printf "%s\n" "$LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3537,11 +4247,12 @@ done if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$LD"; then ac_cv_prog_LD="$LD" # Let the user override the test. else @@ -3549,11 +4260,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LD="${ac_tool_prefix}ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3564,11 +4279,11 @@ fi fi LD=$ac_cv_prog_LD if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -$as_echo "$LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +printf "%s\n" "$LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3577,11 +4292,12 @@ if test -z "$ac_cv_prog_LD"; then ac_ct_LD=$LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_LD"; then ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. else @@ -3589,11 +4305,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LD="ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3604,11 +4324,11 @@ fi fi ac_ct_LD=$ac_cv_prog_ac_ct_LD if test -n "$ac_ct_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 -$as_echo "$ac_ct_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 +printf "%s\n" "$ac_ct_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LD" = x; then @@ -3616,8 +4336,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LD=$ac_ct_LD @@ -3633,11 +4353,12 @@ _search_path=/bin:/usr/bin:/usr/local/bin:$PATH # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_RM+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_RM+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. @@ -3647,11 +4368,15 @@ else for as_dir in $_search_path do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_RM="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3664,11 +4389,11 @@ esac fi RM=$ac_cv_path_RM if test -n "$RM"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 -$as_echo "$RM" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 +printf "%s\n" "$RM" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3679,6 +4404,115 @@ fi _search_path= +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +if test "$with_odbc" = "no" +then : + + + rm -f "$ERL_TOP/lib/odbc/SKIP" + + +else $as_nop + + + # Sockets #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. @@ -3698,20 +4532,23 @@ _search_path= # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- erl_checkBoth=0 - ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" -if test "x$ac_cv_func_connect" = xyes; then : +if test "x$ac_cv_func_connect" = xyes +then : erl_checkSocket=0 -else +else $as_nop erl_checkSocket=1 fi -if test "$erl_checkSocket" = 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 -$as_echo_n "checking for socket in -lsocket... " >&6; } -if ${ac_cv_lib_socket_socket+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "$erl_checkSocket" = 1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +printf %s "checking for socket in -lsocket... " >&6; } +if test ${ac_cv_lib_socket_socket+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3720,56 +4557,62 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char socket (); int -main () +main (void) { return socket (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_socket_socket=yes -else +else $as_nop ac_cv_lib_socket_socket=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 -$as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +printf "%s\n" "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = xyes +then : LIBS="$LIBS -lsocket" -else +else $as_nop erl_checkBoth=1 fi + fi -if test "$erl_checkBoth" = 1; then +if test "$erl_checkBoth" = 1 +then : + tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" -if test "x$ac_cv_func_accept" = xyes; then : +if test "x$ac_cv_func_accept" = xyes +then : odbc_erl_checkNsl=0 -else +else $as_nop LIBS=$tk_oldLibs fi + fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 -$as_echo_n "checking for main in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_gethostbyname" = xyes +then : + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 +printf %s "checking for main in -lnsl... " >&6; } +if test ${ac_cv_lib_nsl_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3777,37 +4620,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_nsl_main=yes -else +else $as_nop ac_cv_lib_nsl_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 -$as_echo "$ac_cv_lib_nsl_main" >&6; } -if test "x$ac_cv_lib_nsl_main" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 +printf "%s\n" "$ac_cv_lib_nsl_main" >&6; } +if test "x$ac_cv_lib_nsl_main" = xyes +then : LIBS="$LIBS -lnsl" fi fi -case "$host_os" in - haiku*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 -$as_echo_n "checking for socket in -lnetwork... " >&6; } -if ${ac_cv_lib_network_socket+:} false; then : - $as_echo_n "(cached) " >&6 -else +case "$host_os" in #( + haiku*) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 +printf %s "checking for socket in -lnetwork... " >&6; } +if test ${ac_cv_lib_network_socket+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3816,247 +4663,47 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char socket (); int -main () +main (void) { return socket (); ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_network_socket=yes -else - ac_cv_lib_network_socket=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 -$as_echo "$ac_cv_lib_network_socket" >&6; } -if test "x$ac_cv_lib_network_socket" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBNETWORK 1 -_ACEOF - - LIBS="-lnetwork $LIBS" - -fi - - ;; -esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_network_socket=yes +else $as_nop + ac_cv_lib_network_socket=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 +printf "%s\n" "$ac_cv_lib_network_socket" >&6; } +if test "x$ac_cv_lib_network_socket" = xyes +then : + printf "%s\n" "#define HAVE_LIBNETWORK 1" >>confdefs.h + + LIBS="-lnetwork $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" + + ;; #( + *) : + ;; +esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else @@ -4067,10 +4714,15 @@ else for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP @@ -4079,13 +4731,13 @@ case `"$ac_path_EGREP" --version 2>&1` in ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 - $as_echo_n 0123456789 >"conftest.in" + printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val @@ -4114,195 +4766,87 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : -else - ac_cv_header_stdc=no -fi -rm -f conftest* +ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" +if test "x$ac_cv_header_fcntl_h" = xyes +then : + printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" +if test "x$ac_cv_header_netdb_h" = xyes +then : + printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext fi +ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes +then : + printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" +if test "x$ac_cv_header_string_h" = xyes +then : + printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi - -done - - -for ac_header in fcntl.h netdb.h stdlib.h string.h sys/socket.h winsock2.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" +if test "x$ac_cv_header_winsock2_h" = xyes +then : + printf "%s\n" "#define HAVE_WINSOCK2_H 1" >>confdefs.h fi -done - -for ac_header in windows.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" -if test "x$ac_cv_header_windows_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_WINDOWS_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes +then : + printf "%s\n" "#define HAVE_WINDOWS_H 1" >>confdefs.h fi -done - -for ac_header in sql.h sqlext.h + for ac_header in sql.h sqlext.h do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_WINDOWS_H # include #endif " -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF odbc_required_headers=yes -else +else $as_nop odbc_required_headers=no fi done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +printf %s "checking for an ANSI C-conforming const... " >&6; } +if test ${ac_cv_c_const+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __cplusplus @@ -4315,7 +4859,7 @@ main () /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. + /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ @@ -4343,7 +4887,7 @@ main () iptr p = 0; ++p; } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; @@ -4359,29 +4903,29 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_const=yes -else +else $as_nop ac_cv_c_const=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then -$as_echo "#define const /**/" >>confdefs.h +printf "%s\n" "#define const /**/" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$ac_cv_type_size_t" = xyes +then : -else +else $as_nop -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF +printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi @@ -4392,27 +4936,27 @@ ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_addr" "ac_cv_member_s #include #endif " -if test "x$ac_cv_member_struct_sockaddr_in6_sin6_addr" = xyes; then : +if test "x$ac_cv_member_struct_sockaddr_in6_sin6_addr" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_ADDR 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_ADDR 1" >>confdefs.h fi -for ac_func in memset socket -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" +if test "x$ac_cv_func_memset" = xyes +then : + printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" +if test "x$ac_cv_func_socket" = xyes +then : + printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi -done # ODBC @@ -4422,29 +4966,34 @@ $RM -f "$ERL_TOP/lib/odbc/SKIP" NEED_NPTL_PTHREAD_H=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 -$as_echo_n "checking for native win32 threads... " >&6; } -if test "X$host_os" = "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 +printf %s "checking for native win32 threads... " >&6; } +if test "X$host_os" = "Xwin32" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } THR_DEFS="-DWIN32_THREADS" THR_LIBS= THR_LIB_NAME=win32_threads THR_LIB_TYPE=win32_threads -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } THR_DEFS= THR_LIBS= THR_LIB_NAME= THR_LIB_TYPE=posix_unknown - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4453,40 +5002,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread_pthread_create=yes -else +else $as_nop ac_cv_lib_pthread_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : THR_LIBS="-lpthread" fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 -$as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 +printf %s "checking for pthread_create in -lc_r... " >&6; } +if test ${ac_cv_lib_c_r_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4495,96 +5046,112 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_r_pthread_create=yes -else +else $as_nop ac_cv_lib_c_r_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +if test "x$ac_cv_lib_c_r_pthread_create" = xyes +then : THR_LIBS="-lc_r" fi - fi - if test "x$THR_LIBS" = "x"; then - ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes; then : +fi + + if test "x$THR_LIBS" = "x" +then : + + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : THR_LIBS="none_needed" fi - fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 -$as_echo_n "checking if the '-pthread' switch can be used... " >&6; } +fi + + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 +printf %s "checking if the '-pthread' switch can be used... " >&6; } saved_cflags=$CFLAGS CFLAGS="$CFLAGS -pthread" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_create((void*)0,(void*)0,(void*)0,(void*)0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : THR_DEFS="-pthread" THR_LIBS="-pthread" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$saved_cflags if test "x$THR_LIBS" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - fi - if test "x$THR_LIBS" != "x"; then +fi + + if test "x$THR_LIBS" != "x" +then : + THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" THR_LIB_NAME=pthread if test "x$THR_LIBS" = "xnone_needed"; then THR_LIBS= fi - case $host_os in - solaris*) - THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;; - linux*) + case $host_os in #( + solaris*) : + + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" + ;; #( + linux*) : + THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" -if test "$cross_compiling" != "yes"; then +if test "$cross_compiling" != "yes" +then : + # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -4592,11 +5159,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4608,23 +5179,26 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else + +else $as_nop + host_getconf="$host_alias-getconf" # Extract the first word of "$host_getconf", so it can be a program name with args. set dummy $host_getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -4632,11 +5206,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="$host_getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4648,25 +5226,28 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then + if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != "" +then : + GETCONF= prfx="$erl_xcomp_sysroot" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. set dummy ${ac_tool_prefix}getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. @@ -4677,11 +5258,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4693,11 +5278,11 @@ esac fi GETCONF=$ac_cv_path_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4706,11 +5291,12 @@ if test -z "$ac_cv_path_GETCONF"; then ac_pt_GETCONF=$GETCONF # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. @@ -4721,11 +5307,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4737,11 +5327,11 @@ esac fi ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF if test -n "$ac_pt_GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 -$as_echo "$ac_pt_GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 +printf "%s\n" "$ac_pt_GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_GETCONF" = x; then @@ -4749,8 +5339,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac GETCONF=$ac_pt_GETCONF @@ -4759,11 +5349,13 @@ else GETCONF="$ac_cv_path_GETCONF" fi - fi + +fi + fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 -$as_echo_n "checking for Native POSIX Thread Library... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 +printf %s "checking for Native POSIX Thread Library... " >&6; } libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` if test $? -eq 0; then case "$libpthr_vsn" in @@ -4779,24 +5371,28 @@ $as_echo_n "checking for Native POSIX Thread Library... " >&6; } else nptl=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 -$as_echo "$nptl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 +printf "%s\n" "$nptl" >&6; } if test $nptl = cross; then nptl=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi - if test $nptl = yes; then + if test $nptl = yes +then : + THR_LIB_TYPE=posix_nptl need_nptl_incldir=no - ac_fn_c_check_header_mongrel "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_nptl_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_nptl_pthread_h" = xyes +then : need_nptl_incldir=yes NEED_NPTL_PTHREAD_H=yes fi + if test $need_nptl_incldir = yes +then : - if test $need_nptl_incldir = yes; then # Ahh... nptl_path="$C_INCLUDE_PATH:$CPATH" if test X$cross_compiling != Xyes; then @@ -4817,13 +5413,13 @@ fi IFS=$save_ifs nptl_incldir= for dir in $nptl_ws_path; do - as_ac_Header=`$as_echo "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + as_ac_Header=`printf "%s\n" "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : nptl_incldir=$dir/nptl fi - if test "x$nptl_incldir" != "x"; then THR_DEFS="$THR_DEFS -isystem $nptl_incldir" break @@ -4832,38 +5428,43 @@ fi if test "x$nptl_incldir" = "x"; then as_fn_error $? "Failed to locate nptl system include directory" "$LINENO" 5 fi - fi - fi - ;; - *) ;; - esac + +fi + +fi + ;; #( + *) : + ;; +esac saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $THR_DEFS" - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : -$as_echo "#define HAVE_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes +then : \ -$as_echo "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h fi - CPPFLAGS=$saved_cppflags - fi + +fi + fi @@ -4872,8 +5473,9 @@ fi odbc_lib_link_success=no - case $host_os in - darwin1[0-9].*) +case $host_os in #( + darwin1[0-9].*) : + TARGET_FLAGS="-DUNIX" if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then ODBC_LIB= -L"/usr/local/lib" @@ -4883,11 +5485,12 @@ odbc_lib_link_success=no ODBC_INCLUDE="-I$with_odbc/include" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -liodbc" >&5 -$as_echo_n "checking for SQLAllocHandle in -liodbc... " >&6; } -if ${ac_cv_lib_iodbc_SQLAllocHandle+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -liodbc" >&5 +printf %s "checking for SQLAllocHandle in -liodbc... " >&6; } +if test ${ac_cv_lib_iodbc_SQLAllocHandle+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-liodbc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4896,43 +5499,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char SQLAllocHandle (); int -main () +main (void) { return SQLAllocHandle (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_iodbc_SQLAllocHandle=yes -else +else $as_nop ac_cv_lib_iodbc_SQLAllocHandle=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iodbc_SQLAllocHandle" >&5 -$as_echo "$ac_cv_lib_iodbc_SQLAllocHandle" >&6; } -if test "x$ac_cv_lib_iodbc_SQLAllocHandle" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iodbc_SQLAllocHandle" >&5 +printf "%s\n" "$ac_cv_lib_iodbc_SQLAllocHandle" >&6; } +if test "x$ac_cv_lib_iodbc_SQLAllocHandle" = xyes +then : ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes fi - ;; - haiku*) + ;; #( + haiku*) : + TARGET_FLAGS="-DUNIX" ODBC_LIB= -L"/system/lib" ODBC_INCLUDE="-I/system/develop/headers" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 -$as_echo_n "checking for SQLAllocHandle in -lodbc... " >&6; } -if ${ac_cv_lib_odbc_SQLAllocHandle+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 +printf %s "checking for SQLAllocHandle in -lodbc... " >&6; } +if test ${ac_cv_lib_odbc_SQLAllocHandle+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lodbc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4941,41 +5545,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char SQLAllocHandle (); int -main () +main (void) { return SQLAllocHandle (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_odbc_SQLAllocHandle=yes -else +else $as_nop ac_cv_lib_odbc_SQLAllocHandle=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 -$as_echo "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } -if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 +printf "%s\n" "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } +if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes +then : ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes fi - ;; - win32|cygwin) + ;; #( + win32|cygwin) : + TARGET_FLAGS="-DWIN32" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lws2_32" >&5 -$as_echo_n "checking for main in -lws2_32... " >&6; } -if ${ac_cv_lib_ws2_32_main+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lws2_32" >&5 +printf %s "checking for main in -lws2_32... " >&6; } +if test ${ac_cv_lib_ws2_32_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lws2_32 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4983,28 +5588,28 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ws2_32_main=yes -else +else $as_nop ac_cv_lib_ws2_32_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ws2_32_main" >&5 -$as_echo "$ac_cv_lib_ws2_32_main" >&6; } -if test "x$ac_cv_lib_ws2_32_main" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBWS2_32 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ws2_32_main" >&5 +printf "%s\n" "$ac_cv_lib_ws2_32_main" >&6; } +if test "x$ac_cv_lib_ws2_32_main" = xyes +then : + printf "%s\n" "#define HAVE_LIBWS2_32 1" >>confdefs.h LIBS="-lws2_32 $LIBS" @@ -5017,11 +5622,12 @@ fi ODBC_LIB=-L"$with_odbc/lib" ODBC_INCLUDE="-I$with_odbc/include" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lodbc32" >&5 -$as_echo_n "checking for main in -lodbc32... " >&6; } -if ${ac_cv_lib_odbc32_main+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lodbc32" >&5 +printf %s "checking for main in -lodbc32... " >&6; } +if test ${ac_cv_lib_odbc32_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lodbc32 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5029,55 +5635,62 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_odbc32_main=yes -else +else $as_nop ac_cv_lib_odbc32_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc32_main" >&5 -$as_echo "$ac_cv_lib_odbc32_main" >&6; } -if test "x$ac_cv_lib_odbc32_main" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc32_main" >&5 +printf "%s\n" "$ac_cv_lib_odbc32_main" >&6; } +if test "x$ac_cv_lib_odbc32_main" = xyes +then : ODBC_LIB="$ODBC_LIB -lodbc32"; odbc_lib_link_success=yes fi - ;; - *) + ;; #( + *) : + TARGET_FLAGS="-DUNIX" - case "$erl_xcomp_without_sysroot-$with_odbc" in - yes-yes | yes- ) + case "$erl_xcomp_without_sysroot-$with_odbc" in #( + yes-yes | yes-) : + msg="Dont know where to search for odbc (setting erl_xcomp_sysroot will help)" - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $msg" >&5 -$as_echo "$as_me: WARNING: $msg" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $msg" >&5 +printf "%s\n" "$as_me: WARNING: $msg" >&2;} echo "$msg" > "$ERL_TOP/lib/odbc/SKIP" odbc_lib_link_success=wont_try - ;; - no-yes | no- ) + ;; #( + no-yes | no-) : + # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -5086,18 +5699,16 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for odbc in standard locations" >&5 -$as_echo_n "checking for odbc in standard locations... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for odbc in standard locations" >&5 +printf %s "checking for odbc in standard locations... " >&6; } for rdir in /usr/local/odbc /usr/local /usr/odbc \ /usr /opt/local/pgm/odbc /usr/local/pgm/odbc \ "$with_odbc"; do @@ -5116,19 +5727,20 @@ $as_echo_n "checking for odbc in standard locations... " >&6; } break done if test "x$is_odbc_std_location" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No odbc library found skipping odbc" >&5 -$as_echo "$as_me: WARNING: No odbc library found skipping odbc" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No odbc library found skipping odbc" >&5 +printf "%s\n" "$as_me: WARNING: No odbc library found skipping odbc" >&2;} echo "No odbc library found" > "$ERL_TOP/lib/odbc/SKIP" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ODBC_LIB" >&5 -$as_echo "$ODBC_LIB" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 -$as_echo_n "checking for SQLAllocHandle in -lodbc... " >&6; } -if ${ac_cv_lib_odbc_SQLAllocHandle+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ODBC_LIB" >&5 +printf "%s\n" "$ODBC_LIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 +printf %s "checking for SQLAllocHandle in -lodbc... " >&6; } +if test ${ac_cv_lib_odbc_SQLAllocHandle+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lodbc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5137,44 +5749,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char SQLAllocHandle (); int -main () +main (void) { return SQLAllocHandle (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_odbc_SQLAllocHandle=yes -else +else $as_nop ac_cv_lib_odbc_SQLAllocHandle=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 -$as_echo "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } -if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 +printf "%s\n" "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } +if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes +then : ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes fi fi - ;; + ;; #( + *) : - *) ODBC_LIB=-L"$with_odbc/lib" ODBC_INCLUDE="-I$with_odbc/include" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 -$as_echo_n "checking for SQLAllocHandle in -lodbc... " >&6; } -if ${ac_cv_lib_odbc_SQLAllocHandle+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SQLAllocHandle in -lodbc" >&5 +printf %s "checking for SQLAllocHandle in -lodbc... " >&6; } +if test ${ac_cv_lib_odbc_SQLAllocHandle+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lodbc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5183,105 +5795,98 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char SQLAllocHandle (); int -main () +main (void) { return SQLAllocHandle (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_odbc_SQLAllocHandle=yes -else +else $as_nop ac_cv_lib_odbc_SQLAllocHandle=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 -$as_echo "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } -if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_odbc_SQLAllocHandle" >&5 +printf "%s\n" "$ac_cv_lib_odbc_SQLAllocHandle" >&6; } +if test "x$ac_cv_lib_odbc_SQLAllocHandle" = xyes +then : ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes fi - ;; - esac - ;; + ;; +esac + ;; esac if test $odbc_required_headers = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"ODBC library - header check failed\"" >&5 -$as_echo "$as_me: WARNING: \"ODBC library - header check failed\"" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"ODBC library - header check failed\"" >&5 +printf "%s\n" "$as_me: WARNING: \"ODBC library - header check failed\"" >&2;} echo "ODBC library - header check failed" > $ERL_TOP/lib/odbc/SKIP fi if test $odbc_lib_link_success = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"ODBC library - link check failed\"" >&5 -$as_echo "$as_me: WARNING: \"ODBC library - link check failed\"" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"ODBC library - link check failed\"" >&5 +printf "%s\n" "$as_me: WARNING: \"ODBC library - link check failed\"" >&2;} echo "ODBC library - link check failed" > $ERL_TOP/lib/odbc/SKIP fi + fi -if test "x$GCC" = xyes; then +if test "x$GCC" = xyes +then : + # Treat certain GCC warnings as errors - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $CFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } CFLAGS="-Werror=return-type $CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -fi +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi -# Check whether --enable-sanitizers was given. -if test "${enable_sanitizers+set}" = set; then : - enableval=$enable_sanitizers; -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=address,undefined" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" fi - ac_config_files="$ac_config_files c_src/$host/Makefile:c_src/Makefile.in" cat >confcache <<\_ACEOF @@ -5311,8 +5916,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -5342,15 +5947,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -5364,8 +5969,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -5418,7 +6023,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -5434,8 +6039,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -5458,14 +6063,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -5475,46 +6082,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -5523,13 +6130,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -5538,8 +6138,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -5551,30 +6155,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -5587,13 +6171,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -5620,18 +6205,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -5643,12 +6230,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -5679,7 +6267,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -5701,6 +6289,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -5714,6 +6306,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -5755,7 +6353,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -5764,7 +6362,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -5827,7 +6425,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -5876,14 +6474,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -5920,21 +6520,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -5962,7 +6562,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -5976,7 +6576,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -6001,7 +6601,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -6229,7 +6829,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -6237,17 +6837,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -6264,7 +6864,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6288,9 +6888,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -6343,8 +6943,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -6386,9 +6986,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -6435,7 +7035,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/lib/odbc/configure.ac b/lib/odbc/configure.ac new file mode 100644 index 000000000000..febdd044a573 --- /dev/null +++ b/lib/odbc/configure.ac @@ -0,0 +1,260 @@ +dnl +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 2005-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% +dnl + +dnl define([AC_CACHE_LOAD], )dnl +dnl define([AC_CACHE_SAVE], )dnl + + +dnl Process this file with autoconf to produce a configure script. +AC_INIT +AC_CONFIG_SRCDIR([c_src/odbcserver.c]) +AC_PREREQ([2.71]) + +m4_include([otp.m4]) + +AC_CONFIG_AUX_DIR([${ERL_TOP}/make/autoconf]) + +ERL_CANONICAL_SYSTEM_TYPE + +AC_ARG_WITH(odbc, +[ --with-odbc=PATH specify location of ODBC include and lib + --with-odbc use ODBC (default) + --without-odbc don't use ODBC]) + +ERL_XCOMP_SYSROOT_INIT + +dnl Checks for programs. +AC_PROG_CC + +dnl --------------------------------------------------------------------- +dnl Special windows stuff regarding CFLAGS and details in the environment... +dnl --------------------------------------------------------------------- +LM_WINDOWS_ENVIRONMENT + +AC_PROG_MAKE_SET + +AC_CHECK_PROGS(LD, ld.sh) +AC_CHECK_TOOL(LD, ld, '$(CC)') + +AC_SUBST(LD) + +_search_path=/bin:/usr/bin:/usr/local/bin:$PATH + +AC_PATH_PROG(RM, rm, false, $_search_path) +if test "$ac_cv_path_RM" = false; then + AC_MSG_ERROR([No 'rm' command found]) +fi + +_search_path= + +AS_IF([test "$with_odbc" = "no"], + [ + + rm -f "$ERL_TOP/lib/odbc/SKIP" + + ], + [ + dnl "$with_odbc" != "no" + + +# Sockets +#-------------------------------------------------------------------- +# Check for the existence of the -lsocket and -lnsl libraries. +# The order here is important, so that they end up in the right +# order in the command line generated by make. Here are some +# special considerations: +# 1. Use "connect" and "accept" to check for -lsocket, and +# "gethostbyname" to check for -lnsl. +# 2. Use each function name only once: can't redo a check because +# autoconf caches the results of the last check and won't redo it. +# 3. Use -lnsl and -lsocket only if they supply procedures that +# aren't already present in the normal libraries. This is because +# IRIX 5.2 has libraries, but they aren't needed and they're +# bogus: they goof up name resolution if used. +# 4. On some SVR4 systems, can't use -lsocket without -lnsl too. +# To get around this problem, check for both libraries together +# if -lsocket doesn't work by itself. +#-------------------------------------------------------------------- +erl_checkBoth=0 +AC_CHECK_FUNC(connect, erl_checkSocket=0, erl_checkSocket=1) +AS_IF([test "$erl_checkSocket" = 1], + [ + AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket", erl_checkBoth=1) + ]) +AS_IF([test "$erl_checkBoth" = 1], + [ + tk_oldLibs=$LIBS + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, odbc_erl_checkNsl=0, [LIBS=$tk_oldLibs]) + ]) +AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"])) +AS_CASE(["$host_os"], + [haiku*], + [ + AC_CHECK_LIB(network, socket) + ]) + +dnl Checks for header files. +AC_CHECK_INCLUDES_DEFAULT +AC_PROG_EGREP + +AC_CHECK_HEADERS([fcntl.h netdb.h stdlib.h string.h sys/socket.h winsock2.h]) +AC_CHECK_HEADERS([windows.h]) +AC_CHECK_HEADERS([sql.h sqlext.h], [odbc_required_headers=yes], [odbc_required_headers=no], +[[#ifdef HAVE_WINDOWS_H + # include + #endif + ]]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_addr], [], [], + [#if HAVE_WINSOCK2_H + #include + #include + #else + #include + #endif]) + +dnl Checks for library functions. +AC_CHECK_FUNCS([memset socket]) + +# ODBC +$RM -f "$ERL_TOP/lib/odbc/SKIP" + +LM_CHECK_THR_LIB +AC_SUBST(THR_DEFS) +AC_SUBST(THR_LIBS) + +odbc_lib_link_success=no +AC_SUBST(TARGET_FLAGS) +AS_CASE([$host_os], + + [darwin1[[0-9]].*], + [ + TARGET_FLAGS="-DUNIX" + if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then + ODBC_LIB= -L"/usr/local/lib" + ODBC_INCLUDE="-I/usr/local/include" + else + ODBC_LIB=-L"$with_odbc/lib" + ODBC_INCLUDE="-I$with_odbc/include" + fi + + AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) + ], + + [haiku*], + [ + TARGET_FLAGS="-DUNIX" + ODBC_LIB= -L"/system/lib" + ODBC_INCLUDE="-I/system/develop/headers" + dnl Haiku's package manager will deal with this for us + AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) + ], + + [win32|cygwin], + [ + TARGET_FLAGS="-DWIN32" + AC_CHECK_LIB(ws2_32, main) + if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then + ODBC_LIB="" + ODBC_INCLUDE="" + else + ODBC_LIB=-L"$with_odbc/lib" + ODBC_INCLUDE="-I$with_odbc/include" + fi + AC_CHECK_LIB(odbc32, main, [ODBC_LIB="$ODBC_LIB -lodbc32"; odbc_lib_link_success=yes]) + ], + + [ + TARGET_FLAGS="-DUNIX" + AS_CASE(["$erl_xcomp_without_sysroot-$with_odbc"], + + [yes-yes | yes-], + [ + msg="Dont know where to search for odbc (setting erl_xcomp_sysroot will help)" + AC_MSG_WARN([$msg]) + echo "$msg" > "$ERL_TOP/lib/odbc/SKIP" + odbc_lib_link_success=wont_try + ], + + [no-yes | no-], + [ + AC_CHECK_SIZEOF(void *) + AC_MSG_CHECKING([for odbc in standard locations]) + for rdir in /usr/local/odbc /usr/local /usr/odbc \ + /usr /opt/local/pgm/odbc /usr/local/pgm/odbc \ + "$with_odbc"; do + test -f "$erl_xcomp_isysroot$rdir/include/sql.h" || continue + is_odbc_std_location=yes + libdir="$erl_xcomp_sysroot$rdir/lib" + if test "$ac_cv_sizeof_void_p" = "8"; then + dnl "/." in test is important (dir symlinks) + if test -d "${libdir}64/."; then + libdir="${libdir}64" + elif test -d "${libdir}/64/."; then + libdir="${libdir}/64" + fi + fi + ODBC_LIB="-L$libdir" + ODBC_INCLUDE="-I$erl_xcomp_isysroot$rdir/include" + break + done + if test "x$is_odbc_std_location" != "xyes"; then + AC_MSG_RESULT(no) + AC_MSG_WARN([No odbc library found skipping odbc]) + echo "No odbc library found" > "$ERL_TOP/lib/odbc/SKIP" + else + AC_MSG_RESULT($ODBC_LIB) + AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) + fi + ], + + [ + ODBC_LIB=-L"$with_odbc/lib" + ODBC_INCLUDE="-I$with_odbc/include" + AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) + ]) + ]) + +if test $odbc_required_headers = no; then + AC_MSG_WARN(["ODBC library - header check failed"]) + echo "ODBC library - header check failed" > $ERL_TOP/lib/odbc/SKIP +fi +if test $odbc_lib_link_success = no; then + AC_MSG_WARN(["ODBC library - link check failed"]) + echo "ODBC library - link check failed" > $ERL_TOP/lib/odbc/SKIP +fi + +AC_SUBST(ODBC_LIB) +AC_SUBST(ODBC_INCLUDE) + + ]) dnl "$with_odbc" != "no" + +AS_IF([test "x$GCC" = xyes], + [ + # Treat certain GCC warnings as errors + LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) + ]) + +AC_CONFIG_FILES([c_src/$host/Makefile:c_src/Makefile.in]) +AC_OUTPUT diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in deleted file mode 100644 index f11eb7079699..000000000000 --- a/lib/odbc/configure.in +++ /dev/null @@ -1,262 +0,0 @@ -dnl -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 2005-2021. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% -dnl - -dnl define([AC_CACHE_LOAD], )dnl -dnl define([AC_CACHE_SAVE], )dnl - - -dnl Process this file with autoconf to produce a configure script. -AC_INIT(c_src/odbcserver.c) - -AC_CONFIG_AUX_DIRS(${ERL_TOP}/erts/autoconf) - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -else - host_os=win32 -fi - -AC_ARG_WITH(odbc, -[ --with-odbc=PATH specify location of ODBC include and lib - --with-odbc use ODBC (default) - --without-odbc don't use ODBC]) - -if test "$with_odbc" = "no"; then - - rm -f "$ERL_TOP/lib/odbc/SKIP" - -else dnl "$with_odbc" != "no" - -ERL_XCOMP_SYSROOT_INIT - -dnl Checks for programs. -AC_PROG_CC - -dnl --------------------------------------------------------------------- -dnl Special windows stuff regarding CFLAGS and details in the environment... -dnl --------------------------------------------------------------------- -LM_WINDOWS_ENVIRONMENT - -AC_PROG_MAKE_SET - -AC_CHECK_PROGS(LD, ld.sh) -AC_CHECK_TOOL(LD, ld, '$(CC)') - -AC_SUBST(LD) - -_search_path=/bin:/usr/bin:/usr/local/bin:$PATH - -AC_PATH_PROG(RM, rm, false, $_search_path) -if test "$ac_cv_path_RM" = false; then - AC_MSG_ERROR([No 'rm' command found]) -fi - -_search_path= - - -# Sockets -#-------------------------------------------------------------------- -# Check for the existence of the -lsocket and -lnsl libraries. -# The order here is important, so that they end up in the right -# order in the command line generated by make. Here are some -# special considerations: -# 1. Use "connect" and "accept" to check for -lsocket, and -# "gethostbyname" to check for -lnsl. -# 2. Use each function name only once: can't redo a check because -# autoconf caches the results of the last check and won't redo it. -# 3. Use -lnsl and -lsocket only if they supply procedures that -# aren't already present in the normal libraries. This is because -# IRIX 5.2 has libraries, but they aren't needed and they're -# bogus: they goof up name resolution if used. -# 4. On some SVR4 systems, can't use -lsocket without -lnsl too. -# To get around this problem, check for both libraries together -# if -lsocket doesn't work by itself. -#-------------------------------------------------------------------- -erl_checkBoth=0 -AC_CHECK_FUNC(connect, erl_checkSocket=0, erl_checkSocket=1) -if test "$erl_checkSocket" = 1; then - AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket", erl_checkBoth=1) -fi -if test "$erl_checkBoth" = 1; then - tk_oldLibs=$LIBS - LIBS="$LIBS -lsocket -lnsl" - AC_CHECK_FUNC(accept, odbc_erl_checkNsl=0, [LIBS=$tk_oldLibs]) -fi -AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"])) -case "$host_os" in - haiku*) - AC_CHECK_LIB(network, socket) - ;; -esac - -dnl Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h netdb.h stdlib.h string.h sys/socket.h winsock2.h]) -AC_CHECK_HEADERS([windows.h]) -AC_CHECK_HEADERS([sql.h sqlext.h], [odbc_required_headers=yes], [odbc_required_headers=no], -[[#ifdef HAVE_WINDOWS_H - # include - #endif - ]]) - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_SIZE_T -AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_addr], [], [], - [#if HAVE_WINSOCK2_H - #include - #include - #else - #include - #endif]) - -dnl Checks for library functions. -AC_CHECK_FUNCS([memset socket]) - -# ODBC -$RM -f "$ERL_TOP/lib/odbc/SKIP" - -LM_CHECK_THR_LIB -AC_SUBST(THR_DEFS) -AC_SUBST(THR_LIBS) - -odbc_lib_link_success=no -AC_SUBST(TARGET_FLAGS) - case $host_os in - darwin1[[0-9]].*) - TARGET_FLAGS="-DUNIX" - if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then - ODBC_LIB= -L"/usr/local/lib" - ODBC_INCLUDE="-I/usr/local/include" - else - ODBC_LIB=-L"$with_odbc/lib" - ODBC_INCLUDE="-I$with_odbc/include" - fi - - AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) - ;; - haiku*) - TARGET_FLAGS="-DUNIX" - ODBC_LIB= -L"/system/lib" - ODBC_INCLUDE="-I/system/develop/headers" - dnl Haiku's package manager will deal with this for us - AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) - ;; - win32|cygwin) - TARGET_FLAGS="-DWIN32" - AC_CHECK_LIB(ws2_32, main) - if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then - ODBC_LIB="" - ODBC_INCLUDE="" - else - ODBC_LIB=-L"$with_odbc/lib" - ODBC_INCLUDE="-I$with_odbc/include" - fi - AC_CHECK_LIB(odbc32, main, [ODBC_LIB="$ODBC_LIB -lodbc32"; odbc_lib_link_success=yes]) - ;; - *) - TARGET_FLAGS="-DUNIX" - case "$erl_xcomp_without_sysroot-$with_odbc" in - yes-yes | yes- ) - msg="Dont know where to search for odbc (setting erl_xcomp_sysroot will help)" - AC_MSG_WARN([$msg]) - echo "$msg" > "$ERL_TOP/lib/odbc/SKIP" - odbc_lib_link_success=wont_try - ;; - no-yes | no- ) - AC_CHECK_SIZEOF(void *) - AC_MSG_CHECKING([for odbc in standard locations]) - for rdir in /usr/local/odbc /usr/local /usr/odbc \ - /usr /opt/local/pgm/odbc /usr/local/pgm/odbc \ - "$with_odbc"; do - test -f "$erl_xcomp_isysroot$rdir/include/sql.h" || continue - is_odbc_std_location=yes - libdir="$erl_xcomp_sysroot$rdir/lib" - if test "$ac_cv_sizeof_void_p" = "8"; then - dnl "/." in test is important (dir symlinks) - if test -d "${libdir}64/."; then - libdir="${libdir}64" - elif test -d "${libdir}/64/."; then - libdir="${libdir}/64" - fi - fi - ODBC_LIB="-L$libdir" - ODBC_INCLUDE="-I$erl_xcomp_isysroot$rdir/include" - break - done - if test "x$is_odbc_std_location" != "xyes"; then - AC_MSG_RESULT(no) - AC_MSG_WARN([No odbc library found skipping odbc]) - echo "No odbc library found" > "$ERL_TOP/lib/odbc/SKIP" - else - AC_MSG_RESULT($ODBC_LIB) - AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) - fi - ;; - - *) - ODBC_LIB=-L"$with_odbc/lib" - ODBC_INCLUDE="-I$with_odbc/include" - AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes]) - ;; - esac - ;; -esac - -if test $odbc_required_headers = no; then - AC_MSG_WARN(["ODBC library - header check failed"]) - echo "ODBC library - header check failed" > $ERL_TOP/lib/odbc/SKIP -fi -if test $odbc_lib_link_success = no; then - AC_MSG_WARN(["ODBC library - link check failed"]) - echo "ODBC library - link check failed" > $ERL_TOP/lib/odbc/SKIP -fi - -AC_SUBST(ODBC_LIB) -AC_SUBST(ODBC_INCLUDE) - -fi dnl "$with_odbc" != "no" - -if test "x$GCC" = xyes; then - # Treat certain GCC warnings as errors - LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) -fi - -dnl ---------------------------------------------------------------------- -dnl Enable -fsanitize= flags. -dnl ---------------------------------------------------------------------- - -m4_define(DEFAULT_SANITIZERS, [address,undefined]) -AC_ARG_ENABLE( - sanitizers, - AS_HELP_STRING( - [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], - [Default=DEFAULT_SANITIZERS]), -[ -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" -]) - -AC_OUTPUT(c_src/$host/Makefile:c_src/Makefile.in) diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml index 33b232fc84f9..c1df6c476b02 100644 --- a/lib/odbc/doc/src/notes.xml +++ b/lib/odbc/doc/src/notes.xml @@ -32,7 +32,39 @@

    This document describes the changes made to the odbc application.

    -
    ODBC 2.13.5 +
    ODBC 2.14.1 + +
    Improvements and New Features + + +

    + Allow larger column sizes than 8001 in case DB supports + it.

    +

    + Own Id: OTP-18539

    +
    +
    +
    + +
    + +
    ODBC 2.14 + +
    Improvements and New Features + + +

    + Input for configure scripts adapted to + autoconf 2.71.

    +

    + Own Id: OTP-17414 Aux Id: PR-4967

    +
    +
    +
    + +
    + +
    ODBC 2.13.5
    Fixed Bugs and Malfunctions diff --git a/lib/odbc/src/Makefile b/lib/odbc/src/Makefile index 7ca59495ed35..e18628e94d93 100644 --- a/lib/odbc/src/Makefile +++ b/lib/odbc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2016. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -83,7 +83,7 @@ ERL_COMPILE_FLAGS += -I$(INCLUDE) \ #debug: # @${MAKE} TYPE=debug opt -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: rm -f $(TARGET_FILES) diff --git a/lib/odbc/test/Makefile b/lib/odbc/test/Makefile index c90f76a83db5..ab184ac06ba3 100644 --- a/lib/odbc/test/Makefile +++ b/lib/odbc/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2016. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -72,11 +72,13 @@ RELSYSDIR = $(RELEASE_PATH)/odbc_test ERL_COMPILE_FLAGS += $(INCLUDES) \ +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -tests debug opt: $(BUILDTARGET) +tests $(TYPES): $(BUILDTARGET) targets: $(TARGET_FILES) diff --git a/lib/odbc/test/mysql.erl b/lib/odbc/test/mysql.erl index 69b136e74380..1bba1482c9cd 100644 --- a/lib/odbc/test/mysql.erl +++ b/lib/odbc/test/mysql.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -27,7 +27,7 @@ %------------------------------------------------------------------------- connection_string() -> - case test_server:os_type() of + case os:type() of {unix, linux} -> "DSN=MySQL;Database=odbctest;Uid=odbctest;Pwd=gurka;CHARSET=utf8;SSTMT=SET NAMES 'utf8';"; {unix, sunos} -> diff --git a/lib/odbc/test/postgres.erl b/lib/odbc/test/postgres.erl index 7c45e488998c..717d42a505e7 100644 --- a/lib/odbc/test/postgres.erl +++ b/lib/odbc/test/postgres.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -27,7 +27,7 @@ %------------------------------------------------------------------------- connection_string() -> - case test_server:os_type() of + case os:type() of {unix, sunos} -> "DSN=Postgres;UID=odbctest"; {unix, linux} -> diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index 04aea9d2a4e1..3694ab678b76 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1 +1 @@ -ODBC_VSN = 2.13.5 +ODBC_VSN = 2.14.1 diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c index 415168fc72b9..fd04d35987ad 100644 --- a/lib/os_mon/c_src/cpu_sup.c +++ b/lib/os_mon/c_src/cpu_sup.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2021. All Rights Reserved. + * Copyright Ericsson AB 1997-2023. 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. @@ -87,6 +87,11 @@ typedef struct { #define CU_BSD_VALUES (6) #endif +#if defined(__OpenBSD__) +#include +#include +#define CU_OPENBSD_VALUES (6) +#endif #define FD_IN (0) #define FD_OUT (1) @@ -178,12 +183,17 @@ static int processors_online() { void getsysctl(const char *, void *, size_t); #endif +#if defined(__OpenBSD__) +static int getncpu(void); +static int getncpuonline(void); +#endif + int main(int argc, char** argv) { char cmd; int rc; int sz; unsigned int *rv; -#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) ||defined(__FreeBSD__) +#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__OpenBSD__) unsigned int no_of_cpus = 0; #endif @@ -207,6 +217,15 @@ int main(int argc, char** argv) { } #endif +#if defined(__OpenBSD__) + no_of_cpus = getncpu(); + if ( no_of_cpus == -1 ) + error("cpu_sup: sysctl error"); + + if ( (rv = (unsigned int*)malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_OPENBSD_VALUES))) == NULL) + error("cpu_sup: malloc error"); +#endif + #if defined(__FreeBSD__) getsysctl("hw.ncpu", &no_of_cpus, sizeof(int)); if ( (rv = (unsigned int*)malloc(sizeof(unsigned int)*(2 + 2*no_of_cpus*CU_BSD_VALUES))) == NULL) { @@ -244,7 +263,7 @@ int main(int argc, char** argv) { case AVG5: bsd_loadavg(1); break; case AVG15: bsd_loadavg(2); break; #endif -#if defined(__sun__) || defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) +#if defined(__sun__) || defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__OpenBSD__) case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break; #endif case QUIT: free((void*)rv); return 0; @@ -707,11 +726,77 @@ static void util_measure(unsigned int **result_vec, int *result_sz) { rv[10] = CU_HARD_IRQ; rv[11] = cpu_times[CP_INTR + offset]; rv += CU_BSD_VALUES*2; } - + + free((void*) cpu_times); *result_sz = 2 + 2*CU_BSD_VALUES * no_of_cpus; } #endif +/* ---------------------------- * + * OpenBSD stat functions * + * ---------------------------- */ + +#if defined(__OpenBSD__) +static int getncpu(void) { + const int mib[] = { CTL_HW, HW_NCPU }; + int numcpu; + size_t size = sizeof(numcpu); + + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &numcpu, &size, NULL, 0) == -1) + error("cpu_sup: sysctl error"); + + return(numcpu); +} + +static int getncpuonline(void) { + const int mib[] = { CTL_HW, HW_NCPUONLINE }; + int numcpu; + size_t size = sizeof(numcpu); + + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &numcpu, &size, NULL, 0) == -1) + error("cpu_sup: sysctl error"); + + return(numcpu); +} + +static void util_measure(unsigned int **result_vec, int *result_sz) { + static int mib[] = { CTL_KERN, KERN_CPTIME2, 0 }; + size_t size_cpu_times; + int64_t *cpu_times; + unsigned int *rv = NULL; + int i; + int ncpuonline = getncpuonline(); + + rv = *result_vec; + rv[0] = ncpuonline; + rv[1] = CU_OPENBSD_VALUES; + ++rv; /* first value is number of cpus */ + ++rv; /* second value is number of entries */ + + size_cpu_times = sizeof(int64_t) * CPUSTATES; + cpu_times = malloc(size_cpu_times); + if (!cpu_times) + error("cpu_sup: malloc error"); + + for (i = 0; i < ncpuonline; ++i) { + mib[2] = i; + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), cpu_times, &size_cpu_times, NULL, 0) == -1) + error("cpu_sup: sysctl error"); + + rv[ 0] = CU_CPU_ID; rv[ 1] = i; + rv[ 2] = CU_USER; rv[ 3] = (unsigned int)cpu_times[CP_USER]; + rv[ 4] = CU_NICE_USER; rv[ 5] = (unsigned int)cpu_times[CP_NICE]; + rv[ 6] = CU_KERNEL; rv[ 7] = (unsigned int)cpu_times[CP_SYS]; + rv[ 8] = CU_IDLE; rv[ 9] = (unsigned int)cpu_times[CP_IDLE]; + rv[10] = CU_HARD_IRQ; rv[11] = (unsigned int)cpu_times[CP_INTR]; + rv += CU_OPENBSD_VALUES*2; + } + free((void*) cpu_times); + + *result_sz = 2 + 2*CU_OPENBSD_VALUES * ncpuonline; +} +#endif + /* ---------------------------- * * Generic functions * diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c index 7ea7456003ce..96f662da1940 100644 --- a/lib/os_mon/c_src/memsup.c +++ b/lib/os_mon/c_src/memsup.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2021. All Rights Reserved. + * Copyright Ericsson AB 1996-2023. 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. @@ -66,7 +66,7 @@ * This program communicates with Erlang through the standard * input and output file descriptors (0 and 1). These descriptors * (and the standard error descriptor 2) must NOT be closed - * explicitely by this program at termination (in UNIX it is + * explicitly by this program at termination (in UNIX it is * taken care of by the operating system itself; in VxWorks * it is taken care of by the spawn driver part of the Emulator). * @@ -176,7 +176,7 @@ static void print_error(const char *,...); * PageTables: 9368 kB 2.5.41+ * VmallocTotal: 34359738367 kB ?? total size of vmalloc memory area * VmallocUsed: 57376 kB ?? amount of vmalloc area which is used - * VmallocChunk: 34359677947 kB ?? largest contigious block of vmalloc area which is free + * VmallocChunk: 34359677947 kB ?? largest contiguous block of vmalloc area which is free * ReverseMaps: 5738 2.5.41+ number of rmap pte chains * SwapCached: 0 kB 2.5.??+ * HugePages_Total: 0 2.5.??+ @@ -609,6 +609,8 @@ message_loop(int erlin_fd) case SHOW_SYSTEM_MEM: extended_show_mem(); break; + case EXIT: + return; default: /* ignore all other messages */ break; } diff --git a/lib/os_mon/c_src/memsup.h b/lib/os_mon/c_src/memsup.h index fa65db784a0f..ae53ec61014e 100644 --- a/lib/os_mon/c_src/memsup.h +++ b/lib/os_mon/c_src/memsup.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2021. All Rights Reserved. + * Copyright Ericsson AB 1998-2023. 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. @@ -30,6 +30,8 @@ /* Extended memory statistics */ /*IG*/ #define SHOW_SYSTEM_MEM 2 +#define EXIT 3 + /* Tags for the extended statistics */ /*IG*/ #define SHOW_SYSTEM_MEM_END 0 /*IG*/ #define MEM_SYSTEM_TOTAL 1 diff --git a/lib/os_mon/c_src/nteventlog/elog_format.h b/lib/os_mon/c_src/nteventlog/elog_format.h index d92e2a81c3d6..e753100001ac 100644 --- a/lib/os_mon/c_src/nteventlog/elog_format.h +++ b/lib/os_mon/c_src/nteventlog/elog_format.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2016. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -34,7 +34,7 @@ char *format_message(MessageFiles mf, DWORD id, * Formats an eventlog message with the messagefiles * in mf, the ID id, the stringarray strings, * containing numstrings strings into buff. - * if bufflen is to small or anything else failes, + * if bufflen is to small or anything else fails, * the return value is NULL. */ diff --git a/lib/os_mon/c_src/nteventlog/elog_main.c b/lib/os_mon/c_src/nteventlog/elog_main.c index a7b59e516b31..bed558f80f58 100644 --- a/lib/os_mon/c_src/nteventlog/elog_main.c +++ b/lib/os_mon/c_src/nteventlog/elog_main.c @@ -285,7 +285,7 @@ BOOL output_record(char *category, EVENTLOGRECORD *event){ * number and timestamp, and sends them to * stdout. If timestamp does * not correspond with record number, the - * log is concidered wrapped around + * log is considered wrapped around * and is reread from the beginning. * time is ignored if 0. * If record_number is 0, the whole log is read (if there is one). diff --git a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c index 1920268af964..96a2625e730b 100644 --- a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c +++ b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2016. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -31,7 +31,7 @@ static char *stdin_buff = NULL; static int stdin_siz = 0; static int stdin_len = 0; static int stdin_eof = 0; -/* end syncronized objects */ +/* end synchronized objects */ static int stdin_is_console = 0; static HANDLE stdin_event; diff --git a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h index b8f08bb4125b..4677477753e5 100644 --- a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h +++ b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2016. All Rights Reserved. + * Copyright Ericsson AB 1998-2022. 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. @@ -22,11 +22,11 @@ /* * Module: elog_pipe_stdin * Purpouse: Read data from stdin when stdin is a pipe - * and deliver events only when data is really availabel or + * and deliver events only when data is really available or * end of file is reached. * If we would wait on an ordinary pipe handle, we * would return immediately as it's always "signaled". - * some kind of asyncronous I/O in the win32 way is + * some kind of asynchronous I/O in the win32 way is * not possible as it's not supported on anonymous pipes * (besides we have not opened the file ourselves so we * cannot specify that we want async I/O...). @@ -66,7 +66,7 @@ BOOL setup_pipe_stdin(void); /* * Initializes the module, returns TRUE if OK. * If stdin is a console, no thread is created - * and the event objet returned by get_Stdin_event + * and the event object returned by get_Stdin_event * will be the console handle. * Check if stdin was a console with the console_stdin() * function. diff --git a/lib/os_mon/c_src/win32sysinfo.c b/lib/os_mon/c_src/win32sysinfo.c index 67b3f7491056..85622e00760d 100644 --- a/lib/os_mon/c_src/win32sysinfo.c +++ b/lib/os_mon/c_src/win32sysinfo.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2016. All Rights Reserved. + * Copyright Ericsson AB 1997-2022. 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. @@ -55,7 +55,7 @@ * get_disk_info 'd'Driveroot (where Driveroot is a string like this "A:\\" * (request info of specific drive) - * The result is returned with the same format as above exept that + * The result is returned with the same format as above except that * Type will be DRIVE_NOT_EXIST if the drive does not exist. * * get_mem_info 'm' (request info about memory) @@ -265,31 +265,30 @@ message_loop() print_error("Erlang has closed"); return; } + if ((res = read(0, &cmd, cmdLen)) == cmdLen){ if (cmdLen == 1) { - switch (cmd[0]) { - case MEM_INFO: - get_avail_mem_ext(); - return_answer(OK); - break; - case DISK_INFO: - get_disk_info_all(); - return_answer(OK); - break; - default: /* ignore all other messages */ - break; - } /* switch */ + switch (cmd[0]) { + case MEM_INFO: + get_avail_mem_ext(); + return_answer(OK); + break; + case DISK_INFO: + get_disk_info_all(); + return_answer(OK); + break; + default: /* ignore all other messages */ + break; + } /* switch */ } - else - if ((res > 0) && (cmd[0]==DISK_INFO)) { - cmd[cmdLen] = 0; - output_drive_info(&cmd[1]); - return_answer("OK"); - return; - } - else - return_answer("xEND"); - } + else { + if ((res > 0) && (cmd[0]==DISK_INFO)) { + cmd[cmdLen] = 0; + output_drive_info(&cmd[1]); + } + return_answer(OK); + } + } else if (res == 0) { print_error("Erlang has closed"); return; @@ -297,8 +296,8 @@ message_loop() else { print_error("Error reading from Erlang"); return; - } - } + } + } } int main(int argc, char ** argv){ diff --git a/lib/os_mon/doc/src/cpu_sup.xml b/lib/os_mon/doc/src/cpu_sup.xml index e9dd930cf1c2..ffbb01cb4027 100644 --- a/lib/os_mon/doc/src/cpu_sup.xml +++ b/lib/os_mon/doc/src/cpu_sup.xml @@ -4,7 +4,7 @@
    - 19972021 + 19972023 Ericsson AB. All Rights Reserved. @@ -35,7 +35,7 @@ and CPU utilization. It is part of the OS_Mon application, see os_mon(6). Available for Unix, although CPU utilization values (util/0,1) are only - available for Solaris, Linux and FreeBSD.

    + available for Solaris, Linux, FreeBSD and OpenBSD.

    The load values are proportional to how long time a runnable Unix process has to spend in the run queue before it is scheduled. Accordingly, higher values mean more system load. The returned diff --git a/lib/os_mon/doc/src/disksup.xml b/lib/os_mon/doc/src/disksup.xml index 47eff80ff5e0..97872c9f3bf1 100644 --- a/lib/os_mon/doc/src/disksup.xml +++ b/lib/os_mon/doc/src/disksup.xml @@ -4,7 +4,7 @@

    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -57,15 +57,42 @@ longer valid.

    + + + time() + +

    Supported units:

    + + integer() >= 1 + +

    The time interval in minutes.

    +
    + {TimeUnit, Time} + +

    + The time interval Time in a time unit specified by TimeUnit where + TimeUnit is of the type + erlang:time_unit() + and Time is a positive integer. The time interval needs to be at least one + millisecond long. +

    +
    +
    +
    +
    +
    +
    Configuration

    The following configuration parameters can be used to change the default values for time interval and threshold:

    - disk_space_check_interval = int()>0 + + disk_space_check_interval = time() + -

    The time interval, in minutes, for the periodic disk space +

    The time interval for the periodic disk space check. The default is 30 minutes.

    disk_almost_full_threshold = float() @@ -95,15 +122,15 @@ get_disk_data() -> [DiskData] Get data for the disks in the system - DiskData = {Id, KByte, Capacity} + DiskData = {Id, TotalKiB, Capacity}  Id = string() -  KByte = int() +  TotalKiB = int()  Capacity = int()

    Returns the result of the latest disk check. Id is a - string that identifies the disk or partition. KByte is - the total size of the disk or partition in kbytes. + string that identifies the disk or partition. TotalKiB is + the total size of the disk or partition in kibibytes. Capacity is the percentage of disk space used.

    The function is asynchronous in the sense that it does not invoke a disk check, but returns the latest available value.

    @@ -111,6 +138,47 @@ available.

    + + get_disk_info() -> [DiskData] + Immediately get information for the disks in the system + + DiskData = {Id, TotalKiB, AvailableKiB, Capacity} +  Id = string() +  TotalKiB = int() +  AvailableKiB = int() +  Capacity = int() + + +

    Immediately fetches total space, available space and capacity for local disks. + Id is a string that identifies the disk or partition. + TotalKiB is the total size of the disk or partition in kibibytes. + AvailableKiB is the disk space used in kibibytes. + Capacity is the percentage of disk space used.

    +

    Returns [{"none",0,0,0}] if disksup is not + available.

    +
    +
    + + get_disk_info(Path) -> DiskData + Immediately get information for a single path + + DiskData = [{Id, TotalKiB, AvailableKiB, Capacity}] +  Id = string() +  TotalKiB = int() +  AvailableKiB = int() +  Capacity = int() + + +

    Immediately fetches total space, available space and capacity for a path. + Id is a string that identifies the disk or partition. + TotalKiB is the total size of the disk or partition in kibibytes. + AvailableKiB is the disk space used in kibibytes. + Capacity is the percentage of disk space used.

    +

    Returns [{Path,0,0,0}] if the Path is invalid or space + can't be determined. Returns [{"none",0,0,0}] if disksup is not + available.

    +
    +
    get_check_interval() -> MS Get time interval, in milliseconds, for the periodic disk space check @@ -123,13 +191,13 @@ - set_check_interval(Minutes) -> ok - Set time interval, in minutes, for the periodic disk space check + set_check_interval(Time) -> ok + Set time interval for the periodic disk space check - Minutes = int()>=1 + Time = time() -

    Changes the time interval, given in minutes, for the periodic +

    Changes the time interval for the periodic disk space check.

    The change will take effect after the next disk space check and is non-persist. That is, in case of a process restart, diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml index f510329619b5..164566b2c3fb 100644 --- a/lib/os_mon/doc/src/notes.xml +++ b/lib/os_mon/doc/src/notes.xml @@ -31,6 +31,110 @@

    This document describes the changes made to the OS_Mon application.

    +
    Os_Mon 2.9 + +
    Fixed Bugs and Malfunctions + + +

    + Fix internal os_mon_sysinfo:get_disk_info/1 function to + not crash when run on Windows with multiple drives.

    +

    + Own Id: OTP-18246 Aux Id: PR-6284 GH-6156

    +
    + +

    + Fixed a memory leak when calling cpu_sup:util/0,1 + on FreeBSD.

    +

    + Own Id: OTP-18546 Aux Id: GH-7070, PR-7071

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + The disksup:get_disk_info/0 + and disksup:get_disk_info/1 + functions have been introduced. These can be used in + order to immediately fetch information about current disk + usage.

    +

    + Own Id: OTP-18303 Aux Id: PR-6384

    +
    + +

    Runtime dependencies have been updated.

    +

    + Own Id: OTP-18350

    +
    + +

    + Support for cpu_sup:util() on OpenBSD.

    +

    + Own Id: OTP-18566 Aux Id: PR-7080

    +
    +
    +
    + +
    + +
    Os_Mon 2.8.2 + +
    Fixed Bugs and Malfunctions + + +

    + Avoid error report from failing erlang:port_close + at shutdown of cpu_sup and memsup. Bug + exists since OTP 25.3 (os_mon-2.8.1).

    +

    + Own Id: OTP-18559 Aux Id: ERIERL-942

    +
    +
    +
    + +
    + +
    Os_Mon 2.8.1 + +
    Fixed Bugs and Malfunctions + + +

    + The port programs used by cpu_sup and + memsup are now gracefully shut down when + cpu_sup and memsup are shut down.

    +

    + Own Id: OTP-18469 Aux Id: PR-6689

    +
    +
    +
    + +
    + +
    Os_Mon 2.8 + +
    Improvements and New Features + + +

    + The disk_space_check_interval + configuration parameter of disksup can now be set + to values smaller than a minute.

    +

    + Own Id: OTP-18304 Aux Id: PR-6385

    +
    +
    +
    + +
    +
    Os_Mon 2.7.1
    Fixed Bugs and Malfunctions @@ -698,7 +802,7 @@

    - Memsup did not read memory correctly on MaxOSX + Memsup did not read memory correctly on macOS X Snowleopard. This has now been corrected. (Thanks to Joel Reymont)

    diff --git a/lib/os_mon/include/memsup.hrl b/lib/os_mon/include/memsup.hrl index 2f76cfe9b31d..df2278aaf6f0 100644 --- a/lib/os_mon/include/memsup.hrl +++ b/lib/os_mon/include/memsup.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -26,6 +26,7 @@ -define( SHOW_MEM , 1 ). -define( SHOW_SYSTEM_MEM , 2 ). +-define( EXIT , 3 ). -define( SHOW_SYSTEM_MEM_END , 8#0 ). %% tags for extended statistics -define( MEM_SYSTEM_TOTAL , 1 ). diff --git a/lib/os_mon/src/Makefile b/lib/os_mon/src/Makefile index 48a896265b54..e28fb1254890 100644 --- a/lib/os_mon/src/Makefile +++ b/lib/os_mon/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -65,7 +65,7 @@ ERL_COMPILE_FLAGS += -I$(INCLUDE) -Werror # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl index b4283bb43694..a82dfd996161 100644 --- a/lib/os_mon/src/cpu_sup.erl +++ b/lib/os_mon/src/cpu_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -163,6 +163,7 @@ handle_call({?util, D, PC}, {Client, _Tag}, when Flavor == sunos; Flavor == linux; Flavor == freebsd; + Flavor == openbsd; Flavor == darwin -> case measurement_server_call(State#state.server, {?util, D, PC, Client}) of {error, Reason} -> @@ -495,9 +496,6 @@ measurement_server_init() -> measurement_server_loop(State) -> receive - {_, quit} -> - State#internal.port ! {self(), ?quit}, - ok; {'DOWN',Monitor,process,_,_} -> measurement_server_loop(State#internal{ util = lists:keydelete( Monitor, @@ -528,6 +526,14 @@ measurement_server_loop(State) -> {'EXIT', OldPid, _n} when State#internal.port == OldPid -> {ok, NewPid} = port_server_start_link(), measurement_server_loop(State#internal{port = NewPid}); + {'EXIT', _, normal} -> + case State#internal.port of + not_used -> + ok; + Srv -> + Srv ! {self(), ?quit}, + ok + end; _Other -> measurement_server_loop(State) end. @@ -608,8 +614,8 @@ port_server_loop(Port, Timeout) -> % Close port and this server {Pid, ?quit} -> - port_command(Port, ?quit), - port_close(Port), + Port ! {self(), {command, ?quit}}, + Port ! {self(), close}, Pid ! {self(), {data, quit}}, ok; diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl index 80f833bb498a..8df01f9eb91f 100644 --- a/lib/os_mon/src/disksup.erl +++ b/lib/os_mon/src/disksup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -22,7 +22,7 @@ %% API -export([start_link/0]). --export([get_disk_data/0, +-export([get_disk_data/0, get_disk_info/0, get_disk_info/1, get_check_interval/0, set_check_interval/1, get_almost_full_threshold/0, set_almost_full_threshold/1]). -export([dummy_reply/1, param_type/2, param_default/1]). @@ -46,14 +46,20 @@ start_link() -> get_disk_data() -> os_mon:call(disksup, get_disk_data, infinity). +get_disk_info() -> + os_mon:call(disksup, get_disk_info, infinity). + +get_disk_info(Path) -> + os_mon:call(disksup, {get_disk_info, Path}, infinity). + get_check_interval() -> os_mon:call(disksup, get_check_interval, infinity). -set_check_interval(Minutes) -> - case param_type(disk_space_check_interval, Minutes) of - true -> - os_mon:call(disksup, {set_check_interval, Minutes}, infinity); - false -> - erlang:error(badarg) +set_check_interval(Value) -> + case param_type(disk_space_check_interval, Value) of + true -> + os_mon:call(disksup, {set_check_interval, Value}, infinity); + false -> + erlang:error(badarg) end. get_almost_full_threshold() -> @@ -68,8 +74,17 @@ set_almost_full_threshold(Float) -> dummy_reply(get_disk_data) -> [{"none", 0, 0}]; +dummy_reply(get_disk_info) -> + [{"none", 0, 0, 0}]; +dummy_reply({get_disk_info, Path}) -> + [{Path, 0, 0, 0}]; dummy_reply(get_check_interval) -> - minutes_to_ms(os_mon:get_env(disksup, disk_space_check_interval)); + case os_mon:get_env(disksup, disk_space_check_interval) of + {TimeUnit, Time} -> + erlang:convert_time_unit(Time, TimeUnit, millisecond); + Minute -> + minutes_to_ms(Minute) + end; dummy_reply({set_check_interval, _}) -> ok; dummy_reply(get_almost_full_threshold) -> @@ -77,6 +92,13 @@ dummy_reply(get_almost_full_threshold) -> dummy_reply({set_almost_full_threshold, _}) -> ok. +param_type(disk_space_check_interval, {TimeUnit, Time}) -> + try erlang:convert_time_unit(Time, TimeUnit, millisecond) of + MsTime when MsTime > 0 -> true; + _ -> false + catch + _:_ -> false + end; param_type(disk_space_check_interval, Val) when is_integer(Val), Val>=1 -> true; param_type(disk_almost_full_threshold, Val) when is_number(Val), @@ -120,20 +142,34 @@ init([]) -> %% Read the values of some configuration parameters Threshold = os_mon:get_env(disksup, disk_almost_full_threshold), - Timeout = os_mon:get_env(disksup, disk_space_check_interval), + Timeout = case os_mon:get_env(disksup, disk_space_check_interval) of + {TimeUnit, Time} -> + erlang:convert_time_unit(Time, TimeUnit, millisecond); + Minutes -> + minutes_to_ms(Minutes) + end, %% Initiation first disk check self() ! timeout, {ok, #state{port=Port, os=OS, threshold=round(Threshold*100), - timeout=minutes_to_ms(Timeout)}}. + timeout=Timeout}}. handle_call(get_disk_data, _From, State) -> {reply, State#state.diskdata, State}; +handle_call(get_disk_info, _From, #state{os = OS, port = Port} = State) -> + {reply, get_disk_info(OS, Port), State}; + +handle_call({get_disk_info, Path}, _From, #state{os = OS, port = Port} = State) -> + {reply, get_disk_info(Path, OS, Port), State}; + handle_call(get_check_interval, _From, State) -> {reply, State#state.timeout, State}; +handle_call({set_check_interval, {TimeUnit, Time}}, _From, State) -> + Timeout = erlang:convert_time_unit(Time, TimeUnit, millisecond), + {reply, ok, State#state{timeout=Timeout}}; handle_call({set_check_interval, Minutes}, _From, State) -> Timeout = minutes_to_ms(Minutes), {reply, ok, State#state{timeout=Timeout}}; @@ -241,6 +277,134 @@ find_cmd(Cmd, Path) -> Found end. +%%-- Run "df" based on OS ---------------------------------------------- +run_df(OS, Port) -> + run_df("", OS, Port). + +run_df(Path, {unix, solaris}, Port) -> + my_cmd("/usr/bin/df -lk " ++ Path, Port); +run_df(Path, {unix, irix}, Port) -> + my_cmd("/usr/sbin/df -lk " ++ Path, Port); +run_df(Path, {unix, linux}, Port) -> + Df = find_cmd("df", "/bin"), + my_cmd(Df ++ " -lk -x squashfs " ++ Path, Port); +run_df(Path, {unix, posix}, Port) -> + my_cmd("df -k -P " ++ Path, Port); +run_df(Path, {unix, dragonfly}, Port) -> + my_cmd("/bin/df -k -t ufs,hammer " ++ Path, Port); +run_df(Path, {unix, freebsd}, Port) -> + my_cmd("/bin/df -k -l " ++ Path, Port); +run_df(Path, {unix, openbsd}, Port) -> + my_cmd("/bin/df -k -l " ++ Path, Port); +run_df(Path, {unix, netbsd}, Port) -> + my_cmd("/bin/df -k -t ffs " ++ Path, Port); +run_df(Path, {unix, sunos4}, Port) -> + my_cmd("df " ++ Path, Port); +run_df(Path, {unix, darwin}, Port) -> + my_cmd("/bin/df -i -k -t ufs,hfs,apfs " ++ Path, Port). + +%%--Get disk info------------------------------------------------------- +%% We use as many absolute paths as possible below as there may be stale +%% NFS handles in the PATH which cause these commands to hang. +get_disk_info(OS, Port) -> + get_disk_info("", OS, Port). + +get_disk_info(Path, OS, Port) -> + case do_get_disk_info(Path, OS, Port) of + [] -> dummy_reply({get_disk_info, Path}); + DiskInfo -> DiskInfo + end. + +do_get_disk_info("", {win32, _}, not_used) -> + Result = os_mon_sysinfo:get_disk_info(), + disk_info_win32(Result); +do_get_disk_info(DriveRoot, {win32, _}, not_used) -> + Result = os_mon_sysinfo:get_disk_info(DriveRoot), + disk_info_win32(Result); +do_get_disk_info(Path, {unix, solaris}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, irix}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_irix(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, linux}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, posix}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, dragonfly}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, freebsd}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, openbsd}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, netbsd}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, sunos4}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_solaris(skip_to_eol(Result)); +do_get_disk_info(Path, {unix, darwin}=OS, Port) -> + Result = run_df(Path, OS, Port), + disk_info_susv3(skip_to_eol(Result)). + +disk_info_win32([]) -> + []; +disk_info_win32([H|T]) -> + case io_lib:fread("~s~s~d~d~d", H) of + {ok, [Drive, "DRIVE_FIXED", BAvail, BTot, _TotFree], _RestStr} -> + KiBTotal = BTot div 1024, + KiBAvailable = BAvail div 1024, + BUsed = BTot - BAvail, + Capacity = trunc(math:ceil(100 * (BUsed / BTot))), + [{Drive, KiBTotal, KiBAvailable, Capacity} | disk_info_win32(T)]; + {ok, _, _RestStr} -> + disk_info_win32(T); + _Other -> + [] + end. + +% This code works for Linux and FreeBSD as well +disk_info_solaris("") -> + []; +disk_info_solaris("\n") -> + []; +disk_info_solaris(Str) -> + case parse_df(Str, posix) of + {ok, {KiBTotal, KiBAvailable, Capacity, MntOn}, RestStr} -> + [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_solaris(RestStr)]; + _Other -> + disk_info_solaris(skip_to_eol(Str)) + end. + +%% Irix: like Linux with an extra FS type column and no '%'. +disk_info_irix("") -> []; +disk_info_irix("\n") -> []; +disk_info_irix(Str) -> + case io_lib:fread("~s~s~d~d~d~d~s", Str) of + {ok, [_FS, _FSType, KiBAvailable, Capacity, _Avail, KiBTotal, MntOn], RestStr} -> + [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_irix(RestStr)]; + _Other -> + disk_info_irix(skip_to_eol(Str)) + end. + +% Parse per SUSv3 specification, notably recent OS X +disk_info_susv3("") -> + []; +disk_info_susv3("\n") -> + []; +disk_info_susv3(Str) -> + case parse_df(Str, susv3) of + {ok, {KiBTotal, KiBAvailable, Capacity, MntOn}, RestStr} -> + [{MntOn, KiBTotal, KiBAvailable, Capacity} | disk_info_susv3(RestStr)]; + _Other -> + disk_info_susv3(skip_to_eol(Str)) + end. + %%--Check disk space---------------------------------------------------- %% We use as many absolute paths as possible below as there may be stale @@ -248,36 +412,35 @@ find_cmd(Cmd, Path) -> check_disk_space({win32,_}, not_used, Threshold) -> Result = os_mon_sysinfo:get_disk_info(), check_disks_win32(Result, Threshold); -check_disk_space({unix, solaris}, Port, Threshold) -> - Result = my_cmd("/usr/bin/df -lk", Port), +check_disk_space({unix, solaris}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, irix}, Port, Threshold) -> - Result = my_cmd("/usr/sbin/df -lk",Port), +check_disk_space({unix, irix}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_irix(skip_to_eol(Result), Threshold); -check_disk_space({unix, linux}, Port, Threshold) -> - Df = find_cmd("df", "/bin"), - Result = my_cmd(Df ++ " -lk -x squashfs", Port), +check_disk_space({unix, linux}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, posix}, Port, Threshold) -> - Result = my_cmd("df -k -P", Port), +check_disk_space({unix, posix}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, dragonfly}, Port, Threshold) -> - Result = my_cmd("/bin/df -k -t ufs,hammer", Port), +check_disk_space({unix, dragonfly}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, freebsd}, Port, Threshold) -> - Result = my_cmd("/bin/df -k -l", Port), +check_disk_space({unix, freebsd}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, openbsd}, Port, Threshold) -> - Result = my_cmd("/bin/df -k -l", Port), +check_disk_space({unix, openbsd}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, netbsd}, Port, Threshold) -> - Result = my_cmd("/bin/df -k -t ffs", Port), +check_disk_space({unix, netbsd}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, sunos4}, Port, Threshold) -> - Result = my_cmd("df", Port), +check_disk_space({unix, sunos4}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_solaris(skip_to_eol(Result), Threshold); -check_disk_space({unix, darwin}, Port, Threshold) -> - Result = my_cmd("/bin/df -i -k -t ufs,hfs,apfs", Port), +check_disk_space({unix, darwin}=OS, Port, Threshold) -> + Result = run_df(OS, Port), check_disks_susv3(skip_to_eol(Result), Threshold). % This code works for Linux and FreeBSD as well @@ -287,14 +450,14 @@ check_disks_solaris("\n", _Threshold) -> []; check_disks_solaris(Str, Threshold) -> case parse_df(Str, posix) of - {ok, {KB, Cap, MntOn}, RestStr} -> + {ok, {KiBTotal, _KiBAvailable, Capacity, MntOn}, RestStr} -> if - Cap >= Threshold -> + Capacity >= Threshold -> set_alarm({disk_almost_full, MntOn}, []); true -> clear_alarm({disk_almost_full, MntOn}) end, - [{MntOn, KB, Cap} | + [{MntOn, KiBTotal, Capacity} | check_disks_solaris(RestStr, Threshold)]; _Other -> check_disks_solaris(skip_to_eol(Str),Threshold) @@ -349,15 +512,15 @@ parse_df_take_word_percent(Input) -> %% and capacity), skip % sign, (optionally for susv3 can also skip IUsed, IFree %% and ICap% fields) then take remaining characters as the mount path -spec parse_df(string(), posix | susv3) -> - {error, parse_df} | {ok, {integer(), integer(), list()}, string()}. + {error, parse_df} | {ok, {integer(), integer(), integer(), list()}, string()}. parse_df(Input0, Flavor) -> %% Format of Posix/Linux df output looks like Header + Lines %% Filesystem 1024-blocks Used Available Capacity Mounted on %% udev 2467108 0 2467108 0% /dev Input1 = parse_df_skip_word(Input0), % skip device path field - {KbStr, Input2} = parse_df_take_word(Input1), % take Kb field + {KiBTotalStr, Input2} = parse_df_take_word(Input1), % take Kb field Input3 = parse_df_skip_word(Input2), % skip Used field - Input4 = parse_df_skip_word(Input3), % skip Avail field + {KiBAvailableStr, Input4} = parse_df_take_word(Input3), % take Capacity% field; drop a % sign following the capacity {CapacityStr, Input5} = parse_df_take_word_percent(Input4), @@ -381,9 +544,10 @@ parse_df(Input0, Flavor) -> Remaining = lists:dropwhile(fun(X) -> not parse_df_is_not_eol(X) end, Input7), try - Kb = erlang:list_to_integer(KbStr), + KiBTotal = erlang:list_to_integer(KiBTotalStr), + KiBAvailable = erlang:list_to_integer(KiBAvailableStr), Capacity = erlang:list_to_integer(CapacityStr), - {ok, {Kb, Capacity, MountPath}, Remaining} + {ok, {KiBTotal, KiBAvailable, Capacity, MountPath}, Remaining} catch error:badarg -> {error, parse_df} end. @@ -395,14 +559,14 @@ check_disks_susv3("\n", _Threshold) -> []; check_disks_susv3(Str, Threshold) -> case parse_df(Str, susv3) of - {ok, {KB, Cap, MntOn}, RestStr} -> + {ok, {KiBTotal, _KiBAvailable, Capacity, MntOn}, RestStr} -> if - Cap >= Threshold -> + Capacity >= Threshold -> set_alarm({disk_almost_full, MntOn}, []); true -> clear_alarm({disk_almost_full, MntOn}) end, - [{MntOn, KB, Cap} | + [{MntOn, KiBTotal, Capacity} | check_disks_susv3(RestStr, Threshold)]; _Other -> check_disks_susv3(skip_to_eol(Str),Threshold) diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index e4f60b9972a7..c467adc2e5ab 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -651,6 +651,10 @@ port_init() -> start_portprogram() -> os_mon:open_port("memsup",[{packet,1}]). +port_shutdown(Port) -> + Port ! {self(), {command, [?EXIT]}}, + Port ! {self(), close}. + %% The connected process loops are a bit awkward (several different %% functions doing almost the same thing) as %% a) strategies for receiving regular memory data and extensive @@ -674,13 +678,13 @@ port_idle(Port) -> %% Received after reply already has been delivered... port_idle(Port); close -> - port_close(Port); + port_shutdown(Port); {Port, {data, Data}} -> exit({port_error, Data}); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. get_memory_usage(Port, Alloc, Memsup) -> @@ -694,11 +698,11 @@ get_memory_usage(Port, Alloc, Memsup) -> cancel -> get_memory_usage_cancelled(Port, Alloc); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. get_memory_usage_cancelled(Port, Alloc) -> receive @@ -707,11 +711,11 @@ get_memory_usage_cancelled(Port, Alloc) -> {Port, {data, _Data}} -> port_idle(Port); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. tag2atag(Port, Tag) -> @@ -734,11 +738,11 @@ get_ext_memory_usage(Port, Accum, Memsup) -> ext_cancel -> get_ext_memory_usage_cancelled(Port); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. get_ext_memory_usage_cancelled(Port) -> receive @@ -748,11 +752,11 @@ get_ext_memory_usage_cancelled(Port) -> get_ext_memory_usage_cancelled(tag2atag(Port, Tag), Port); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. get_ext_memory_usage(ATag, Port, Accum0, Memsup) -> @@ -769,22 +773,22 @@ get_ext_memory_usage(ATag, Port, Accum0, Memsup) -> cancel -> get_ext_memory_usage_cancelled(ATag, Port); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. get_ext_memory_usage_cancelled(_ATag, Port) -> receive {Port, {data, _Data}} -> get_ext_memory_usage_cancelled(Port); close -> - port_close(Port); + port_shutdown(Port); {'EXIT', Port, Reason} -> exit({port_died, Reason}); {'EXIT', _Memsup, _Reason} -> - port_close(Port) + port_shutdown(Port) end. %%--Collect process data------------------------------------------------ diff --git a/lib/os_mon/src/os_mon.app.src b/lib/os_mon/src/os_mon.app.src index 2b1f7dc85b85..e78e8dae27af 100644 --- a/lib/os_mon/src/os_mon.app.src +++ b/lib/os_mon/src/os_mon.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -31,4 +31,4 @@ {start_memsup, true}, {start_os_sup, false}]}, {mod, {os_mon, []}}, - {runtime_dependencies, ["stdlib-2.0","sasl-2.4","kernel-3.0","erts-6.0"]}]}. + {runtime_dependencies, ["stdlib-5.0","sasl-4.2.1","kernel-9.0","erts-14.0"]}]}. diff --git a/lib/os_mon/src/os_mon_sysinfo.erl b/lib/os_mon/src/os_mon_sysinfo.erl index 4f5a682a1fc2..5e9fdd7ae945 100644 --- a/lib/os_mon/src/os_mon_sysinfo.erl +++ b/lib/os_mon/src/os_mon_sysinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -45,7 +45,7 @@ get_disk_info() -> gen_server:call(os_mon_sysinfo, get_disk_info). get_disk_info(DriveRoot) -> - gen_server:call(os_mon_sysinfo, {get_disk_info,DriveRoot}). + gen_server:call(os_mon_sysinfo, {get_disk_info, DriveRoot}). get_mem_info() -> gen_server:call(os_mon_sysinfo, get_mem_info). @@ -65,8 +65,8 @@ init([]) -> handle_call(get_disk_info, _From, State) -> {reply, get_disk_info1(State#state.port), State}; -handle_call({get_disk_info,RootList}, _From, State) -> - {reply, get_disk_info1(State#state.port,RootList), State}; +handle_call({get_disk_info, DriveRoot}, _From, State) -> + {reply, get_disk_info1(State#state.port, DriveRoot), State}; handle_call(get_mem_info, _From, State) -> {reply, get_mem_info1(State#state.port), State}. @@ -108,8 +108,8 @@ get_disk_info1(Port) -> Port ! {self(),{command,[?DISK_INFO]}}, get_data(Port,[]). -get_disk_info1(Port,PathList) -> - Port ! {self(),{command,[?DISK_INFO|[P++[0]||P <- PathList]]}}, +get_disk_info1(Port, DriveRoot) -> + Port ! {self(), {command,[?DISK_INFO|DriveRoot++[0]]}}, get_data(Port,[]). get_mem_info1(Port) -> diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile index 73618e5fae8d..df7b606c068b 100644 --- a/lib/os_mon/test/Makefile +++ b/lib/os_mon/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -55,6 +55,7 @@ RELSYSDIR = $(RELEASE_PATH)/os_mon_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/snmp/include +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets @@ -64,7 +65,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl index 03aa6cd355d2..9040d8693b96 100644 --- a/lib/os_mon/test/cpu_sup_SUITE.erl +++ b/lib/os_mon/test/cpu_sup_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -56,15 +56,18 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - case test_server:os_type() of + case os:type() of {unix, sunos} -> [load_api, util_api, util_values, port, unavailable]; {unix, linux} -> [load_api, util_api, util_values, port, unavailable]; {unix, freebsd} -> [load_api, util_api, util_values, port, unavailable]; + {unix, openbsd} -> + [load_api, util_api, util_values, port, unavailable]; {unix, darwin} -> [load_api, util_api, util_values, port, unavailable]; + {unix, netbsd} -> [unavailable]; {unix, _OSname} -> [load_api]; _OS -> [unavailable] end. diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl index fe27ea90461c..48e158080156 100644 --- a/lib/os_mon/test/disksup_SUITE.erl +++ b/lib/os_mon/test/disksup_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -61,7 +61,7 @@ all() -> Bugs = [otp_5910], Always = [api, config, alarm, port, posix_only, unavailable, parse_df_output_posix, parse_df_output_susv3] ++ Bugs, - case test_server:os_type() of + case os:type() of {unix, _OSname} -> Always; {win32, _OSname} -> Always; _OS -> [unavailable] @@ -73,6 +73,9 @@ api(Config) when is_list(Config) -> %% get_disk_data() ok = check_get_disk_data(), + %% get_disk_info() + ok = check_get_disk_info(), + %% get_check_interval() 1800000 = disksup:get_check_interval(), @@ -83,6 +86,15 @@ api(Config) when is_list(Config) -> 1200000 = disksup:get_check_interval(), ok = disksup:set_check_interval(30), + %% set_check_interval({TimeUnit, Time}) + ok = disksup:set_check_interval({second, 1}), + 1000 = disksup:get_check_interval(), + {'EXIT',{badarg,_}} = (catch disksup:set_check_interval({second, 0.5})), + {'EXIT',{badarg,_}} = (catch disksup:set_check_interval({badarg, 1})), + {'EXIT',{badarg,_}} = (catch disksup:set_check_interval({nanosecond, 1})), + 1000 = disksup:get_check_interval(), + ok = disksup:set_check_interval(30), + %% get_almost_full_threshold() 80 = disksup:get_almost_full_threshold(), @@ -110,6 +122,13 @@ config(Config) when is_list(Config) -> 1740000 = disksup:get_check_interval(), 81 = disksup:get_almost_full_threshold(), + ok = application:set_env(os_mon, disk_space_check_interval, {second, 2}), + + ok = supervisor:terminate_child(os_mon_sup, disksup), + {ok, _Child2} = supervisor:restart_child(os_mon_sup, disksup), + + 2000 = disksup:get_check_interval(), + %% Also try this with bad parameter values, should be ignored ok = application:set_env(os_mon, disk_space_check_interval, 0.5), @@ -117,11 +136,32 @@ config(Config) when is_list(Config) -> application:set_env(os_mon, disk_almost_full_threshold, -0.81), ok = supervisor:terminate_child(os_mon_sup, disksup), - {ok, _Child2} = supervisor:restart_child(os_mon_sup, disksup), + {ok, _Child3} = supervisor:restart_child(os_mon_sup, disksup), 1800000 = disksup:get_check_interval(), 80 = disksup:get_almost_full_threshold(), + ok = application:set_env(os_mon, disk_space_check_interval, {second, 0.5}), + + ok = supervisor:terminate_child(os_mon_sup, disksup), + {ok, _Child4} = supervisor:restart_child(os_mon_sup, disksup), + + 1800000 = disksup:get_check_interval(), + + ok = application:set_env(os_mon, disk_space_check_interval, {badarg, 1}), + + ok = supervisor:terminate_child(os_mon_sup, disksup), + {ok, _Child5} = supervisor:restart_child(os_mon_sup, disksup), + + 1800000 = disksup:get_check_interval(), + + ok = application:set_env(os_mon, disk_space_check_interval, {nanosecond, 1}), + + ok = supervisor:terminate_child(os_mon_sup, disksup), + {ok, _Child6} = supervisor:restart_child(os_mon_sup, disksup), + + 1800000 = disksup:get_check_interval(), + %% Reset configuration parameters ok = application:set_env(os_mon, disk_space_check_interval, 30), ok = application:set_env(os_mon, disk_almost_full_threshold, 0.80), @@ -332,8 +372,8 @@ otp_5910(Config) when is_list(Config) -> 0 -> [{_Id,_Kbyte,Cap}|_] = Data, io:format("Data ~p Threshold ~p ~n",[Data, Cap-1]), - ok = disksup:set_almost_full_threshold((Cap-1)/100), - Cap-1; + ok = disksup:set_almost_full_threshold((max(0, Cap-1))/100), + max(0, Cap-1); _N -> Threshold0 end, ok = application:set_env(os_mon, disk_almost_full_threshold, Threshold/100), @@ -402,9 +442,28 @@ check_get_disk_data() -> true = KByte>0, ok. +check_get_disk_info() -> + DiskInfo = disksup:get_disk_info(), + [{Id, TotalKiB, AvailableKiB, Capacity}|_] = DiskInfo, + true = io_lib:printable_list(Id), + true = is_integer(TotalKiB), + true = is_integer(AvailableKiB), + true = is_integer(Capacity), + true = TotalKiB > 0, + true = AvailableKiB > 0, + + [DiskInfoRoot|_] = disksup:get_disk_info("/"), + {"/", TotalKiBRoot, AvailableKiBRoot, CapacityRoot} = DiskInfoRoot, + true = is_integer(TotalKiBRoot), + true = is_integer(AvailableKiBRoot), + true = is_integer(CapacityRoot), + true = TotalKiBRoot > 0, + true = AvailableKiBRoot > 0, + ok. + % filter get_disk_data and remove entriew with zero capacity % "non-normal" filesystems report zero capacity -% - Perhaps errorneous 'df -k -l'? +% - Perhaps erroneous 'df -k -l'? % - Always list filesystems by type '-t ufs,zfs,..' instead? % It is unclear what the intention was from the beginning. get_disk_data() -> @@ -424,11 +483,11 @@ parse_df_output_posix(Config) when is_list(Config) -> %% Have a simple example with no funny spaces in mount path Posix1 = "tmpfs 498048 7288 490760 2% /run\n", - {ok, {498048, 2, "/run"}, ""} = disksup:parse_df(Posix1, posix), + {ok, {498048, 490760, 2, "/run"}, ""} = disksup:parse_df(Posix1, posix), %% Have a mount path with some spaces in it Posix2 = "tmpfs 498048 7288 490760 2% /spaces 1 2\n", - {ok, {498048, 2, "/spaces 1 2"}, ""} = disksup:parse_df(Posix2, posix). + {ok, {498048, 490760, 2, "/spaces 1 2"}, ""} = disksup:parse_df(Posix2, posix). %% @doc Test various expected inputs to 'df' command output (Darwin/SUSv3) parse_df_output_susv3(Config) when is_list(Config) -> @@ -441,9 +500,9 @@ parse_df_output_susv3(Config) when is_list(Config) -> %% Have a simple example with no funny spaces in mount path Darwin1 = "/dev/disk1 243949060 157002380 86690680 65% 2029724 " ++ "4292937555 0% /\n", - {ok, {243949060, 65, "/"}, ""} = disksup:parse_df(Darwin1, susv3), + {ok, {243949060, 86690680, 65, "/"}, ""} = disksup:parse_df(Darwin1, susv3), %% Have a mount path with some spaces in it Darwin2 = "/dev/disk1 243949060 157002380 86690680 65% 2029724 " ++ "4292937555 0% /spaces 1 2\n", - {ok, {243949060, 65, "/spaces 1 2"}, ""} = disksup:parse_df(Darwin2, susv3). + {ok, {243949060, 86690680, 65, "/spaces 1 2"}, ""} = disksup:parse_df(Darwin2, susv3). diff --git a/lib/os_mon/test/memsup_SUITE.erl b/lib/os_mon/test/memsup_SUITE.erl index b2944e280483..1f66ea0afac4 100644 --- a/lib/os_mon/test/memsup_SUITE.erl +++ b/lib/os_mon/test/memsup_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -63,7 +63,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - All = case test_server:os_type() of + All = case os:type() of {unix, sunos} -> [api, alarm1, alarm2, process, config, timeout, unavailable, port]; @@ -551,7 +551,7 @@ timeout(Config) when is_list(Config) -> %% Linux should be handled the same way as solaris. - % TimeoutMsg = case test_server:os_type() of + % TimeoutMsg = case os:type() of % {unix, sunos} -> ext_collection_timeout; % {unix, linux} -> reg_collection_timeout % end, @@ -722,14 +722,14 @@ otp_5910(Config) when is_list(Config) -> ok = application:start(os_mon), ok. -improved_system_memory_data(Config) -> - {ok, Node} = start_node(Config), +improved_system_memory_data(Config) when is_list(Config) -> + {ok, Peer, Node} = ?CT_PEER(), ok = rpc:call(Node, application, start, [sasl]), ok = rpc:call(Node, application, start, [os_mon]), ExtMemData = rpc:call(Node, memsup, get_system_memory_data, []), - stop_node(Node), + peer:stop(Peer), Tags = ?SYSTEM_MEMORY_DATA_TAGS, AvailableMemoryPresent @@ -785,7 +785,7 @@ force_collection(TimerRef) -> erlang:trace(whereis(memsup), false, ['receive']), flush(), collection_timeout; - timout -> + timeout -> erlang:trace(whereis(memsup), false, ['receive']), flush(), timeout; @@ -802,20 +802,3 @@ flush() -> after 0 -> ok end. - -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) when is_list(Config) -> - Pa = filename:dirname(code:which(?MODULE)), - Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" - ++ integer_to_list(erlang:system_time(second)) - ++ "-" - ++ integer_to_list(erlang:unique_integer([positive]))), - test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). - -stop_node(Node) -> - test_server:stop_node(Node). diff --git a/lib/os_mon/test/os_mon_SUITE.erl b/lib/os_mon/test/os_mon_SUITE.erl index c373b5d85169..7eec6d0eaf2d 100644 --- a/lib/os_mon/test/os_mon_SUITE.erl +++ b/lib/os_mon/test/os_mon_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -31,7 +31,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - case test_server:os_type() of + case os:type() of {unix, sunos} -> [app_file, appup_file, config]; _OS -> [app_file, appup_file] end. diff --git a/lib/os_mon/test/os_sup_SUITE.erl b/lib/os_mon/test/os_sup_SUITE.erl index febd3b5f12d5..75bcfdd07598 100644 --- a/lib/os_mon/test/os_sup_SUITE.erl +++ b/lib/os_mon/test/os_sup_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -56,7 +56,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - case test_server:os_type() of + case os:type() of {unix, sunos} -> [message, config, port]; {win32, _OSname} -> [message]; OS -> @@ -76,7 +76,7 @@ message(Config) when is_list(Config) -> %% Check with message_receptor that it has been received ct:sleep({seconds,1}), Msg = - case test_server:os_type() of + case os:type() of {unix, sunos} -> {?TAG, Data}; {win32, _} -> diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk index a85ec42981e1..b109e7a0ab15 100644 --- a/lib/os_mon/vsn.mk +++ b/lib/os_mon/vsn.mk @@ -1 +1 @@ -OS_MON_VSN = 2.7.1 +OS_MON_VSN = 2.9 diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml index 153374e16a68..56c44caadb23 100644 --- a/lib/parsetools/doc/src/leex.xml +++ b/lib/parsetools/doc/src/leex.xml @@ -4,7 +4,7 @@

    - 20092020 + 20092023 Ericsson AB. All Rights Reserved. @@ -110,6 +110,27 @@

    Causes warnings to be treated as errors.

    + {deterministic, boolean()} + +

    Causes generated -file() attributes to only include + the basename of the file path.

    +
    + {error_location, line | column} + +

    If set to column, error location will be + {Line,Column} tuple instead of just Line. Also, StartLoc + and EndLoc in string/2, token/3, and tokens/3 + functions will be {Line,Column} tuple instead of just Line. + Default is line. Note that you can use TokenLoc for token + location independently, even if the error_location is set to line.

    +

    Unicode characters are counted as many columns as they use bytes + to represent.

    +
    + {tab_size, pos_integer()} + +

    Sets the width of \t character (only relevant if error_location + is set to column). Default is 8.

    +

    Any of the Boolean options can be set to true by stating the name of the option. For example, verbose @@ -142,17 +163,18 @@ Module:string(String) -> StringRet - Module:string(String, StartLine) -> StringRet + Module:string(String, StartLoc) -> StringRet Generated by Leex String = string() - StringRet = {ok,Tokens,EndLine} | ErrorInfo + StringRet = {ok,Tokens,EndLoc} | ErrorInfo Tokens = [Token] - EndLine = StartLine = erl_anno:line() + StartLoc = EndLoc = erl_anno:location()

    Scans String and returns all the tokens in it, or an - error.

    + error. StartLoc and EndLoc are either erl_anno:line() + or erl_anno:location(), depending on the error_location option.

    It is an error if not all of the characters in String are consumed.

    @@ -161,7 +183,7 @@ Module:token(Cont, Chars) -> {more,Cont1} | {done,TokenRet,RestChars} - Module:token(Cont, Chars, StartLine) -> {more,Cont1} + Module:token(Cont, Chars, StartLoc) -> {more,Cont1} | {done,TokenRet,RestChars} Generated by Leex @@ -169,10 +191,10 @@ Cont = [] | Cont1 Cont1 = tuple() Chars = RestChars = string() | eof - TokenRet = {ok, Token, EndLine} - | {eof, EndLine} + TokenRet = {ok, Token, EndLoc} + | {eof, EndLoc} | ErrorInfo - StartLine = EndLine = erl_anno:line() + StartLoc = EndLoc = erl_anno:location()

    This is a re-entrant call to try and scan one token from @@ -188,7 +210,7 @@ but used through the i/o system where it can typically be called in an application by:

    -io:request(InFile, {get_until,unicode,Prompt,Module,token,[Line]}) +io:request(InFile, {get_until,unicode,Prompt,Module,token,[Loc]}) -> TokenRet
    @@ -196,7 +218,7 @@ io:request(InFile, {get_until,unicode,Prompt,Module,token,[Line]}) Module:tokens(Cont, Chars) -> {more,Cont1} | {done,TokensRet,RestChars} - Module:tokens(Cont, Chars, StartLine) -> + Module:tokens(Cont, Chars, StartLoc) -> {more,Cont1} | {done,TokensRet,RestChars} Generated by Leex @@ -204,11 +226,11 @@ io:request(InFile, {get_until,unicode,Prompt,Module,token,[Line]}) Cont = [] | Cont1 Cont1 = tuple() Chars = RestChars = string() | eof - TokensRet = {ok, Tokens, EndLine} - | {eof, EndLine} + TokensRet = {ok, Tokens, EndLoc} + | {eof, EndLoc} | ErrorInfo Tokens = [Token] - StartLine = EndLine = erl_anno:line() + StartLoc = EndLoc = erl_anno:location()

    This is a re-entrant call to try and scan tokens from @@ -222,20 +244,20 @@ io:request(InFile, {get_until,unicode,Prompt,Module,token,[Line]}) [].

    This functions differs from token in that it will - continue to scan tokens upto and including an + continue to scan tokens up to and including an {end_token,Token} has been scanned (see next section). It will then return all the tokens. This is typically used for scanning grammars like Erlang where there is an explicit end token, '.'. If no end token is found then the whole file will be scanned and returned. If - an error occurs then all tokens upto and including the next + an error occurs then all tokens up to and including the next end token will be skipped.

    It is not designed to be called directly by an application but used through the i/o system where it can typically be called in an application by:

    -io:request(InFile, {get_until,unicode,Prompt,Module,tokens,[Line]}) +io:request(InFile, {get_until,unicode,Prompt,Module,tokens,[Loc]}) -> TokensRet
    @@ -315,6 +337,14 @@ NAME = VALUE TokenLine

    The line number where the token occurred.

    + TokenCol +

    The column number where the token occurred + (column of the first character included in the token).

    +
    + TokenLoc +

    Token location. Expands to {TokenLine,TokenCol} (even + when error_location is set to line.

    +

    The code must return:

    diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml index 32a95f51a870..f5fb18c80152 100644 --- a/lib/parsetools/doc/src/notes.xml +++ b/lib/parsetools/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 19972021 + 19972022 Ericsson AB. All Rights Reserved. @@ -31,6 +31,56 @@

    This document describes the changes made to the Parsetools application.

    +
    Parsetools 2.5 + +
    Improvements and New Features + + +

    Leex has been extended with optional column number + support.

    +

    + Own Id: OTP-18491 Aux Id: PR-6882

    +
    +
    +
    + +
    + +
    Parsetools 2.4.1 + +
    Improvements and New Features + + +

    There is a new configure option, + --enable-deterministic-build, which will apply the + deterministic compiler option when building + Erlang/OTP. The deterministic option has been + improved to eliminate more sources of non-determinism in + several applications.

    +

    + Own Id: OTP-18165 Aux Id: PR-5965

    +
    +
    +
    + +
    + +
    Parsetools 2.4 + +
    Improvements and New Features + + +

    In the generated code, yecc will now quote all + atoms coming from terminals in the grammar, in order to + avoid conflicts with future reserved words.

    +

    + Own Id: OTP-17755

    +
    +
    +
    + +
    +
    Parsetools 2.3.2
    Fixed Bugs and Malfunctions @@ -456,7 +506,7 @@
    Improvements and New Features -

    The formating of Yecc's error messages has been +

    The formatting of Yecc's error messages has been improved. (Thanks to Joe Armstrong.)

    Own Id: OTP-8919

    diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml index 60c1bdb8f0ce..4d639d1f21be 100644 --- a/lib/parsetools/doc/src/yecc.xml +++ b/lib/parsetools/doc/src/yecc.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962022 Ericsson AB. All Rights Reserved. @@ -134,6 +134,11 @@ is column, the location includes a line number and a column number. Default is column. + {deterministic, boolean()} + +

    Causes generated -file() attributes to only include the + basename of the file path.

    +

    Any of the Boolean options can be set to true by stating the name of the option. For example, verbose @@ -361,7 +366,7 @@ element -> list : '$1'. (a b c).. This still assumes that this was the first input line that the scanner tokenized:

    -{cons, {atom, 1, a,} {cons, {atom, 1, b}, +{cons, {atom, 1, a}, {cons, {atom, 1, b}, {cons, {atom, 1, c}, nil}}}

    The associated code contains pseudo variables '$1', '$2', '$3', etc. which refer to (are bound to) the values associated previously by the parser with diff --git a/lib/parsetools/include/leexinc.hrl b/lib/parsetools/include/leexinc.hrl index 2a74c252ff52..a06584ff793d 100644 --- a/lib/parsetools/include/leexinc.hrl +++ b/lib/parsetools/include/leexinc.hrl @@ -16,261 +16,269 @@ format_error({illegal,S}) -> ["illegal characters ",io_lib:write_string(S)]; format_error({user,S}) -> S. -string(String) -> string(String, 1). - -string(String, Line) -> string(String, Line, String, []). - -%% string(InChars, Line, TokenChars, Tokens) -> -%% {ok,Tokens,Line} | {error,ErrorInfo,Line}. -%% Note the line number going into yystate, L0, is line of token -%% start while line number returned is line of token end. We want line -%% of token start. - -string([], L, [], Ts) -> % No partial tokens! - {ok,yyrev(Ts),L}; -string(Ics0, L0, Tcs, Ts) -> - case yystate(yystate(), Ics0, L0, 0, reject, 0) of - {A,Alen,Ics1,L1} -> % Accepting end state - string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts); - {A,Alen,Ics1,L1,_S1} -> % Accepting transistion state - string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts); - {reject,_Alen,Tlen,_Ics1,L1,_S1} -> % After a non-accepting state - {error,{L0,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},L1}; - {A,Alen,Tlen,_Ics1,L1,_S1} -> +%% string(InChars) -> +%% string(InChars, Loc) -> +%% {ok,Tokens,EndLoc} | {error,ErrorInfo,EndLoc}. +%% Loc is the starting location of the token, while EndLoc is the first not scanned +%% location. Location is either Line or {Line,Column}, depending on the "error_location" option. + +##str + +do_string([], L, C, [], Ts) -> % No partial tokens! + {ok,yyrev(Ts),{L,C}}; +do_string(Ics0, L0, C0, Tcs, Ts) -> + case yystate(yystate(), Ics0, L0, C0, 0, reject, 0) of + {A,Alen,Ics1,L1,_C1} -> % Accepting end state + C2 = adjust_col(Tcs, Alen, C0), + string_cont(Ics1, L1, C2, yyaction(A, Alen, Tcs, L0, C0), Ts); + {A,Alen,Ics1,L1,_C1,_S1} -> % Accepting transition state + C2 = adjust_col(Tcs, Alen, C0), + string_cont(Ics1, L1, C2, yyaction(A, Alen, Tcs, L0, C0), Ts); + {reject,_Alen,Tlen,_Ics1,_L1,_C1,_S1} -> % After a non-accepting state + {error,{{L0, C0} ,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},{L0, C0}}; + {A,Alen,Tlen,_Ics1,L1, C1,_S1}-> Tcs1 = yysuf(Tcs, Alen), L2 = adjust_line(Tlen, Alen, Tcs1, L1), - string_cont(Tcs1, L2, yyaction(A, Alen, Tcs, L0), Ts) + C2 = adjust_col(Tcs, Alen, C1), + string_cont(Tcs1, L2, C2, yyaction(A, Alen, Tcs, L0,C0), Ts) end. -%% string_cont(RestChars, Line, Token, Tokens) +%% string_cont(RestChars, Line, Col, Token, Tokens) %% Test for and remove the end token wrapper. Push back characters %% are prepended to RestChars. --dialyzer({nowarn_function, string_cont/4}). +-dialyzer({nowarn_function, string_cont/5}). -string_cont(Rest, Line, {token,T}, Ts) -> - string(Rest, Line, Rest, [T|Ts]); -string_cont(Rest, Line, {token,T,Push}, Ts) -> +string_cont(Rest, Line, Col, {token,T}, Ts) -> + do_string(Rest, Line, Col, Rest, [T|Ts]); +string_cont(Rest, Line, Col, {token,T,Push}, Ts) -> NewRest = Push ++ Rest, - string(NewRest, Line, NewRest, [T|Ts]); -string_cont(Rest, Line, {end_token,T}, Ts) -> - string(Rest, Line, Rest, [T|Ts]); -string_cont(Rest, Line, {end_token,T,Push}, Ts) -> + do_string(NewRest, Line, Col, NewRest, [T|Ts]); +string_cont(Rest, Line, Col, {end_token,T}, Ts) -> + do_string(Rest, Line, Col, Rest, [T|Ts]); +string_cont(Rest, Line, Col, {end_token,T,Push}, Ts) -> NewRest = Push ++ Rest, - string(NewRest, Line, NewRest, [T|Ts]); -string_cont(Rest, Line, skip_token, Ts) -> - string(Rest, Line, Rest, Ts); -string_cont(Rest, Line, {skip_token,Push}, Ts) -> + do_string(NewRest, Line, Col, NewRest, [T|Ts]); +string_cont(Rest, Line, Col, skip_token, Ts) -> + do_string(Rest, Line, Col, Rest, Ts); +string_cont(Rest, Line, Col, {skip_token,Push}, Ts) -> NewRest = Push ++ Rest, - string(NewRest, Line, NewRest, Ts); -string_cont(_Rest, Line, {error,S}, _Ts) -> - {error,{Line,?MODULE,{user,S}},Line}. + do_string(NewRest, Line, Col, NewRest, Ts); +string_cont(_Rest, Line, Col, {error,S}, _Ts) -> + {error,{{Line, Col},?MODULE,{user,S}},{Line,Col}}. %% token(Continuation, Chars) -> -%% token(Continuation, Chars, Line) -> +%% token(Continuation, Chars, Loc) -> %% {more,Continuation} | {done,ReturnVal,RestChars}. %% Must be careful when re-entering to append the latest characters to the %% after characters in an accept. The continuation is: -%% {token,State,CurrLine,TokenChars,TokenLen,TokenLine,AccAction,AccLen} +%% {token,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCol,AccAction,AccLen} -token(Cont, Chars) -> token(Cont, Chars, 1). +##tkn -token([], Chars, Line) -> - token(yystate(), Chars, Line, Chars, 0, Line, reject, 0); -token({token,State,Line,Tcs,Tlen,Tline,Action,Alen}, Chars, _) -> - token(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Action, Alen). +do_token([], Chars, Line, Col) -> + token(yystate(), Chars, Line, Col, Chars, 0, Line, Col, reject, 0); +do_token({token,State,Line,Col,Tcs,Tlen,Tline,Tcol,Action,Alen}, Chars, _, _) -> + token(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Action, Alen). -%% token(State, InChars, Line, TokenChars, TokenLen, TokenLine, +%% token(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol %% AcceptAction, AcceptLen) -> %% {more,Continuation} | {done,ReturnVal,RestChars}. %% The argument order is chosen to be more efficient. -token(S0, Ics0, L0, Tcs, Tlen0, Tline, A0, Alen0) -> - case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of +token(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of %% Accepting end state, we have a token. - {A1,Alen1,Ics1,L1} -> - token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline)); + {A1,Alen1,Ics1,L1,C1} -> + C2 = adjust_col(Tcs, Alen1, C1), + token_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol)); %% Accepting transition state, can take more chars. - {A1,Alen1,[],L1,S1} -> % Need more chars to check - {more,{token,S1,L1,Tcs,Alen1,Tline,A1,Alen1}}; - {A1,Alen1,Ics1,L1,_S1} -> % Take what we got - token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline)); + {A1,Alen1,[],L1,C1,S1} -> % Need more chars to check + {more,{token,S1,L1,C1,Tcs,Alen1,Tline,Tcol,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> % Take what we got + C2 = adjust_col(Tcs, Alen1, C1), + token_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol)); %% After a non-accepting state, maybe reach accept state later. - {A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check - {more,{token,S1,L1,Tcs,Tlen1,Tline,A1,Alen1}}; - {reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % Need more chars to check + {more,{token,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,A1,Alen1}}; + {reject,_Alen1,Tlen1,eof,L1,C1,_S1} -> % No token match %% Check for partial token which is error. - Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE, + Ret = if Tlen1 > 0 -> {error,{{Tline,Tcol},?MODULE, %% Skip eof tail in Tcs. - {illegal,yypre(Tcs, Tlen1)}},L1}; - true -> {eof,L1} + {illegal,yypre(Tcs, Tlen1)}},{L1,C1}}; + true -> {eof,{L1,C1}} end, {done,Ret,eof}; - {reject,_Alen1,Tlen1,Ics1,L1,_S1} -> % No token match - Error = {Tline,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, - {done,{error,Error,L1},Ics1}; - {A1,Alen1,Tlen1,_Ics1,L1,_S1} -> % Use last accept match + {reject,_Alen1,Tlen1,Ics1,_L1,_C1,_S1} -> % No token match + Error = {{Tline,Tcol},?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, + {done,{error,Error,{Tline,Tcol}},Ics1}; + {A1,Alen1,Tlen1,_Ics1,L1,_C1,_S1} -> % Use last accept match Tcs1 = yysuf(Tcs, Alen1), L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), - token_cont(Tcs1, L2, yyaction(A1, Alen1, Tcs, Tline)) + C2 = C0 + Alen1, + token_cont(Tcs1, L2, C2, yyaction(A1, Alen1, Tcs, Tline, Tcol)) end. -%% token_cont(RestChars, Line, Token) +%% token_cont(RestChars, Line, Col, Token) %% If we have a token or error then return done, else if we have a %% skip_token then continue. --dialyzer({nowarn_function, token_cont/3}). +-dialyzer({nowarn_function, token_cont/4}). -token_cont(Rest, Line, {token,T}) -> - {done,{ok,T,Line},Rest}; -token_cont(Rest, Line, {token,T,Push}) -> +token_cont(Rest, Line, Col, {token,T}) -> + {done,{ok,T,{Line,Col}},Rest}; +token_cont(Rest, Line, Col, {token,T,Push}) -> NewRest = Push ++ Rest, - {done,{ok,T,Line},NewRest}; -token_cont(Rest, Line, {end_token,T}) -> - {done,{ok,T,Line},Rest}; -token_cont(Rest, Line, {end_token,T,Push}) -> + {done,{ok,T,{Line,Col}},NewRest}; +token_cont(Rest, Line, Col, {end_token,T}) -> + {done,{ok,T,{Line,Col}},Rest}; +token_cont(Rest, Line, Col, {end_token,T,Push}) -> NewRest = Push ++ Rest, - {done,{ok,T,Line},NewRest}; -token_cont(Rest, Line, skip_token) -> - token(yystate(), Rest, Line, Rest, 0, Line, reject, 0); -token_cont(Rest, Line, {skip_token,Push}) -> + {done,{ok,T,{Line,Col}},NewRest}; +token_cont(Rest, Line, Col, skip_token) -> + token(yystate(), Rest, Line, Col, Rest, 0, Line, Col, reject, 0); +token_cont(Rest, Line, Col, {skip_token,Push}) -> NewRest = Push ++ Rest, - token(yystate(), NewRest, Line, NewRest, 0, Line, reject, 0); -token_cont(Rest, Line, {error,S}) -> - {done,{error,{Line,?MODULE,{user,S}},Line},Rest}. + token(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, reject, 0); +token_cont(Rest, Line, Col, {error,S}) -> + {done,{error,{{Line, Col},?MODULE,{user,S}},{Line, Col}},Rest}. -%% tokens(Continuation, Chars, Line) -> +%% tokens(Continuation, Chars) -> +%% tokens(Continuation, Chars, Loc) -> %% {more,Continuation} | {done,ReturnVal,RestChars}. %% Must be careful when re-entering to append the latest characters to the %% after characters in an accept. The continuation is: -%% {tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Tokens,AccAction,AccLen} -%% {skip_tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Error,AccAction,AccLen} +%% {tokens,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCur,Tokens,AccAction,AccLen} +%% {skip_tokens,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCur,Error,AccAction,AccLen} -tokens(Cont, Chars) -> tokens(Cont, Chars, 1). +##tks -tokens([], Chars, Line) -> - tokens(yystate(), Chars, Line, Chars, 0, Line, [], reject, 0); -tokens({tokens,State,Line,Tcs,Tlen,Tline,Ts,Action,Alen}, Chars, _) -> - tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Ts, Action, Alen); -tokens({skip_tokens,State,Line,Tcs,Tlen,Tline,Error,Action,Alen}, Chars, _) -> - skip_tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Error, Action, Alen). +do_tokens([], Chars, Line, Col) -> + tokens(yystate(), Chars, Line, Col, Chars, 0, Line, Col, [], reject, 0); +do_tokens({tokens,State,Line,Col,Tcs,Tlen,Tline,Tcol,Ts,Action,Alen}, Chars, _,_) -> + tokens(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Ts, Action, Alen); +do_tokens({skip_tokens,State,Line, Col, Tcs,Tlen,Tline,Tcol,Error,Action,Alen}, Chars, _,_) -> + skip_tokens(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Error, Action, Alen). -%% tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens, +%% tokens(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol,Tokens, %% AcceptAction, AcceptLen) -> %% {more,Continuation} | {done,ReturnVal,RestChars}. -tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Ts, A0, Alen0) -> - case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of +tokens(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, Ts, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of %% Accepting end state, we have a token. - {A1,Alen1,Ics1,L1} -> - tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts); + {A1,Alen1,Ics1,L1,C1} -> + C2 = adjust_col(Tcs, Alen1, C1), + tokens_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline, Tcol), Ts); %% Accepting transition state, can take more chars. - {A1,Alen1,[],L1,S1} -> % Need more chars to check - {more,{tokens,S1,L1,Tcs,Alen1,Tline,Ts,A1,Alen1}}; - {A1,Alen1,Ics1,L1,_S1} -> % Take what we got - tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts); + {A1,Alen1,[],L1,C1,S1} -> % Need more chars to check + {more,{tokens,S1,L1,C1,Tcs,Alen1,Tline,Tcol,Ts,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> % Take what we got + C2 = adjust_col(Tcs, Alen1, C1), + tokens_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol), Ts); %% After a non-accepting state, maybe reach accept state later. - {A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check - {more,{tokens,S1,L1,Tcs,Tlen1,Tline,Ts,A1,Alen1}}; - {reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % Need more chars to check + {more,{tokens,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,Ts,A1,Alen1}}; + {reject,_Alen1,Tlen1,eof,L1,C1,_S1} -> % No token match %% Check for partial token which is error, no need to skip here. - Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE, + Ret = if Tlen1 > 0 -> {error,{{Tline,Tcol},?MODULE, %% Skip eof tail in Tcs. - {illegal,yypre(Tcs, Tlen1)}},L1}; - Ts == [] -> {eof,L1}; - true -> {ok,yyrev(Ts),L1} + {illegal,yypre(Tcs, Tlen1)}},{L1,C1}}; + Ts == [] -> {eof,{L1,C1}}; + true -> {ok,yyrev(Ts),{L1,C1}} end, {done,Ret,eof}; - {reject,_Alen1,Tlen1,_Ics1,L1,_S1} -> + {reject,_Alen1,Tlen1,_Ics1,L1,C1,_S1} -> %% Skip rest of tokens. - Error = {L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, - skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error); - {A1,Alen1,Tlen1,_Ics1,L1,_S1} -> - Token = yyaction(A1, Alen1, Tcs, Tline), + Error = {{L1,C1},?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, + skip_tokens(yysuf(Tcs, Tlen1+1), L1, C1, Error); + {A1,Alen1,Tlen1,_Ics1,L1,_C1,_S1} -> + Token = yyaction(A1, Alen1, Tcs, Tline,Tcol), Tcs1 = yysuf(Tcs, Alen1), L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), - tokens_cont(Tcs1, L2, Token, Ts) + C2 = C0 + Alen1, + tokens_cont(Tcs1, L2, C2, Token, Ts) end. -%% tokens_cont(RestChars, Line, Token, Tokens) +%% tokens_cont(RestChars, Line, Column, Token, Tokens) %% If we have an end_token or error then return done, else if we have %% a token then save it and continue, else if we have a skip_token %% just continue. --dialyzer({nowarn_function, tokens_cont/4}). +-dialyzer({nowarn_function, tokens_cont/5}). -tokens_cont(Rest, Line, {token,T}, Ts) -> - tokens(yystate(), Rest, Line, Rest, 0, Line, [T|Ts], reject, 0); -tokens_cont(Rest, Line, {token,T,Push}, Ts) -> +tokens_cont(Rest, Line, Col, {token,T}, Ts) -> + tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, [T|Ts], reject, 0); +tokens_cont(Rest, Line, Col, {token,T,Push}, Ts) -> NewRest = Push ++ Rest, - tokens(yystate(), NewRest, Line, NewRest, 0, Line, [T|Ts], reject, 0); -tokens_cont(Rest, Line, {end_token,T}, Ts) -> - {done,{ok,yyrev(Ts, [T]),Line},Rest}; -tokens_cont(Rest, Line, {end_token,T,Push}, Ts) -> + tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, [T|Ts], reject, 0); +tokens_cont(Rest, Line, Col, {end_token,T}, Ts) -> + {done,{ok,yyrev(Ts, [T]),{Line,Col}},Rest}; +tokens_cont(Rest, Line, Col, {end_token,T,Push}, Ts) -> NewRest = Push ++ Rest, - {done,{ok,yyrev(Ts, [T]),Line},NewRest}; -tokens_cont(Rest, Line, skip_token, Ts) -> - tokens(yystate(), Rest, Line, Rest, 0, Line, Ts, reject, 0); -tokens_cont(Rest, Line, {skip_token,Push}, Ts) -> + {done,{ok,yyrev(Ts, [T]),{Line, Col}},NewRest}; +tokens_cont(Rest, Line, Col, skip_token, Ts) -> + tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Ts, reject, 0); +tokens_cont(Rest, Line, Col, {skip_token,Push}, Ts) -> NewRest = Push ++ Rest, - tokens(yystate(), NewRest, Line, NewRest, 0, Line, Ts, reject, 0); -tokens_cont(Rest, Line, {error,S}, _Ts) -> - skip_tokens(Rest, Line, {Line,?MODULE,{user,S}}). + tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Ts, reject, 0); +tokens_cont(Rest, Line, Col, {error,S}, _Ts) -> + skip_tokens(Rest, Line, Col, {{Line,Col},?MODULE,{user,S}}). -%%skip_tokens(InChars, Line, Error) -> {done,{error,Error,Line},Ics}. +%% skip_tokens(InChars, Line, Col, Error) -> {done,{error,Error,{Line,Col}},Ics}. %% Skip tokens until an end token, junk everything and return the error. -skip_tokens(Ics, Line, Error) -> - skip_tokens(yystate(), Ics, Line, Ics, 0, Line, Error, reject, 0). +skip_tokens(Ics, Line, Col, Error) -> + skip_tokens(yystate(), Ics, Line, Col, Ics, 0, Line, Col, Error, reject, 0). -%% skip_tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens, +%% skip_tokens(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol, Tokens, %% AcceptAction, AcceptLen) -> %% {more,Continuation} | {done,ReturnVal,RestChars}. -skip_tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Error, A0, Alen0) -> - case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of - {A1,Alen1,Ics1,L1} -> % Accepting end state - skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error); - {A1,Alen1,[],L1,S1} -> % After an accepting state - {more,{skip_tokens,S1,L1,Tcs,Alen1,Tline,Error,A1,Alen1}}; - {A1,Alen1,Ics1,L1,_S1} -> - skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error); - {A1,Alen1,Tlen1,[],L1,S1} -> % After a non-accepting state - {more,{skip_tokens,S1,L1,Tcs,Tlen1,Tline,Error,A1,Alen1}}; - {reject,_Alen1,_Tlen1,eof,L1,_S1} -> - {done,{error,Error,L1},eof}; - {reject,_Alen1,Tlen1,_Ics1,L1,_S1} -> - skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error); - {A1,Alen1,Tlen1,_Ics1,L1,_S1} -> - Token = yyaction(A1, Alen1, Tcs, Tline), +skip_tokens(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, Error, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of + {A1,Alen1,Ics1,L1, C1} -> % Accepting end state + skip_cont(Ics1, L1, C1, yyaction(A1, Alen1, Tcs, Tline, Tcol), Error); + {A1,Alen1,[],L1,C1, S1} -> % After an accepting state + {more,{skip_tokens,S1,L1,C1,Tcs,Alen1,Tline,Tcol,Error,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> + skip_cont(Ics1, L1, C1, yyaction(A1, Alen1, Tcs, Tline, Tcol), Error); + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % After a non-accepting state + {more,{skip_tokens,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,Error,A1,Alen1}}; + {reject,_Alen1,_Tlen1,eof,L1,C1,_S1} -> + {done,{error,Error,{L1,C1}},eof}; + {reject,_Alen1,Tlen1,_Ics1,L1,C1,_S1} -> + skip_tokens(yysuf(Tcs, Tlen1+1), L1, C1,Error); + {A1,Alen1,Tlen1,_Ics1,L1,C1,_S1} -> + Token = yyaction(A1, Alen1, Tcs, Tline, Tcol), Tcs1 = yysuf(Tcs, Alen1), L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), - skip_cont(Tcs1, L2, Token, Error) + skip_cont(Tcs1, L2, C1, Token, Error) end. -%% skip_cont(RestChars, Line, Token, Error) +%% skip_cont(RestChars, Line, Col, Token, Error) %% Skip tokens until we have an end_token or error then return done %% with the original rror. --dialyzer({nowarn_function, skip_cont/4}). +-dialyzer({nowarn_function, skip_cont/5}). -skip_cont(Rest, Line, {token,_T}, Error) -> - skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0); -skip_cont(Rest, Line, {token,_T,Push}, Error) -> +skip_cont(Rest, Line, Col, {token,_T}, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {token,_T,Push}, Error) -> NewRest = Push ++ Rest, - skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0); -skip_cont(Rest, Line, {end_token,_T}, Error) -> - {done,{error,Error,Line},Rest}; -skip_cont(Rest, Line, {end_token,_T,Push}, Error) -> + skip_tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {end_token,_T}, Error) -> + {done,{error,Error,{Line,Col}},Rest}; +skip_cont(Rest, Line, Col, {end_token,_T,Push}, Error) -> NewRest = Push ++ Rest, - {done,{error,Error,Line},NewRest}; -skip_cont(Rest, Line, skip_token, Error) -> - skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0); -skip_cont(Rest, Line, {skip_token,Push}, Error) -> + {done,{error,Error,{Line,Col}},NewRest}; +skip_cont(Rest, Line, Col, skip_token, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {skip_token,Push}, Error) -> NewRest = Push ++ Rest, - skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0); -skip_cont(Rest, Line, {error,_S}, Error) -> - skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0). + skip_tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {error,_S}, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0). -compile({nowarn_unused_function, [yyrev/1, yyrev/2, yypre/2, yysuf/2]}). @@ -292,21 +300,44 @@ adjust_line(T, A, [$\n|Cs], L) -> adjust_line(T, A, [_|Cs], L) -> adjust_line(T-1, A, Cs, L). +%% adjust_col(Chars, AcceptLength, Col) -> NewCol +%% Handle newlines, tabs and unicode chars. +adjust_col(_, 0, Col) -> + Col; +adjust_col([$\n | R], L, _) -> + adjust_col(R, L-1, 1); +adjust_col([$\t | R], L, Col) -> + adjust_col(R, L-1, tab_forward(Col)+1); +adjust_col([C | R], L, Col) when C>=0 andalso C=< 16#7F -> + adjust_col(R, L-1, Col+1); +adjust_col([C | R], L, Col) when C>= 16#80 andalso C=< 16#7FF -> + adjust_col(R, L-1, Col+2); +adjust_col([C | R], L, Col) when C>= 16#800 andalso C=< 16#FFFF -> + adjust_col(R, L-1, Col+3); +adjust_col([C | R], L, Col) when C>= 16#10000 andalso C=< 16#10FFFF -> + adjust_col(R, L-1, Col+4). + +tab_forward(C) -> + D = C rem tab_size(), + A = tab_size()-D, + C+A. + +##tab_size + %% yystate() -> InitialState. -%% yystate(State, InChars, Line, CurrTokLen, AcceptAction, AcceptLen) -> -%% {Action, AcceptLen, RestChars, Line} | -%% {Action, AcceptLen, RestChars, Line, State} | -%% {reject, AcceptLen, CurrTokLen, RestChars, Line, State} | -%% {Action, AcceptLen, CurrTokLen, RestChars, Line, State}. +%% yystate(State, InChars, Line, Col, CurrTokLen, AcceptAction, AcceptLen) -> +%% {Action, AcceptLen, RestChars, Line, Col} | +%% {Action, AcceptLen, RestChars, Line, Col, State} | +%% {reject, AcceptLen, CurrTokLen, RestChars, Line, Col, State} | +%% {Action, AcceptLen, CurrTokLen, RestChars, Line, Col, State}. %% Generated state transition functions. The non-accepting end state %% return signal either an unrecognised character or end of current %% input. ##dfa -%% yyaction(Action, TokenLength, TokenChars, TokenLine) -> +%% yyaction(Action, TokenLength, TokenChars, TokenLine, TokenCol) -> %% {token,Token} | {end_token, Token} | skip_token | {error,String}. %% Generated action function. ##actions - diff --git a/lib/parsetools/src/Makefile b/lib/parsetools/src/Makefile index ba206904ece4..c7971750a707 100644 --- a/lib/parsetools/src/Makefile +++ b/lib/parsetools/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -66,7 +66,7 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/stdlib/include \ # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl index 37f3fb7114f1..c5e61b8149d6 100644 --- a/lib/parsetools/src/leex.erl +++ b/lib/parsetools/src/leex.erl @@ -78,9 +78,10 @@ compile(Input0, Output0, Output = assure_extension(shorten_filename(Output0), ".erl"), Includefile = lists:sublist(Includes, 1), Werror = proplists:get_bool(warnings_as_errors, Specific), + Deterministic = proplists:get_bool(deterministic, Specific), Opts = [{scannerfile,Output},{includefile,Includefile},{verbose,Verbose}, {report_errors,true},{report_warnings,WarnLevel > 0}, - {warnings_as_errors, Werror}], + {warnings_as_errors, Werror}, {deterministic, Deterministic}], case file(Input, Opts) of {ok, _} -> ok; @@ -117,6 +118,9 @@ file(File) -> file(File, []). | {'scannerfile', Scannerfile :: file:filename()} | {'verbose', boolean()} | {'warnings_as_errors', boolean()} + | {'deterministic', boolean()} + | {'error_location', line | column} + | {'tab_size', pos_integer()} | 'dfa_graph' | 'report_errors' | 'report_warnings' | 'report' | 'return_errors' | 'return_warnings' | 'return' @@ -279,6 +283,12 @@ check_options([{Option, Boolean} | Options], AllOptions, L) false -> badarg end; +check_options([{error_location, Loc}=O | Options], AllOptions, L) + when Loc =:= line; Loc =:= column -> + check_options(Options, AllOptions, [O | L]); +check_options([{tab_size, S}=O | Options], AllOptions, L) + when is_integer(S) andalso S>0 -> + check_options(Options, AllOptions, [O | L]); check_options([], _AllOptions, L) -> L; check_options(_Options, _, _L) -> @@ -287,7 +297,7 @@ check_options(_Options, _, _L) -> all_options() -> [dfa_graph,includefile,report_errors,report_warnings, return_errors,return_warnings,scannerfile,verbose, - warnings_as_errors]. + warnings_as_errors,deterministic,error_location,tab_size]. default_option(dfa_graph) -> false; default_option(includefile) -> []; @@ -297,7 +307,10 @@ default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(scannerfile) -> []; default_option(verbose) -> false; -default_option(warnings_as_errors) -> false. +default_option(warnings_as_errors) -> false; +default_option(deterministic) -> false; +default_option(error_location) -> line; +default_option(tab_size) -> 8. atom_option(dfa_graph) -> {dfa_graph,true}; atom_option(report_errors) -> {report_errors,true}; @@ -306,6 +319,7 @@ atom_option(warnings_as_errors) -> {warnings_as_errors,true}; atom_option(return_errors) -> {return_errors,true}; atom_option(verbose) -> {verbose,true}; atom_option(return_warnings) -> {return_warnings,true}; +atom_option(deterministic) -> {deterministic,true}; atom_option(Key) -> Key. is_filename(T) -> @@ -575,7 +589,7 @@ collect_action(Ifile, Chars, L0, Cont0) -> %% parse_rule(RegExpString, RegExpLine, ActionTokens, Macros, Counter, State) -> %% {ok,{RE,Action},ActionData,State}. -%% Parse one regexp after performing macro substition. +%% Parse one regexp after performing macro substitution. parse_rule(S, Line, [{dot,_}], Ms, N, St) -> case parse_rule_regexp(S, Ms, St) of @@ -592,7 +606,9 @@ parse_rule(S, Line, Atoks, Ms, N, St) -> TokenChars = var_used('TokenChars', Atoks), TokenLen = var_used('TokenLen', Atoks), TokenLine = var_used('TokenLine', Atoks), - {ok,{R,N},{N,Atoks,TokenChars,TokenLen,TokenLine},St}; + TokenCol = var_used('TokenCol', Atoks), + TokenLoc = var_used('TokenLoc', Atoks), + {ok,{R,N},{N,Atoks,TokenChars,TokenLen,TokenLine,TokenCol,TokenLoc},St}; {error,E} -> add_error({Line,leex,E}, St) end. @@ -1126,7 +1142,7 @@ comp_crs([], Last) -> [{Last,maxchar}]. %% build_dfa(NFA, NfaFirstState) -> {DFA,DfaFirstState}. %% Build a DFA from an NFA using "subset construction". The major %% difference from the book is that we keep the marked and unmarked -%% DFA states in seperate lists. New DFA states are added to the +%% DFA states in separate lists. New DFA states are added to the %% unmarked list and states are marked by moving them to the marked %% list. We assume that the NFA accepting state numbers are in %% ascending order for the rules and use ordsets to keep this order. @@ -1264,7 +1280,7 @@ accept([], _) -> noaccept. %% minimise_dfa(DFA, DfaFirst) -> {DFA,DfaFirst}. %% Minimise the DFA by removing equivalent states. We consider a %% state if both the transitions and the their accept state is the -%% same. First repeatedly run throught the DFA state list removing +%% same. First repeatedly run through the DFA state list removing %% equivalent states and updating remaining transitions with %% remaining equivalent state numbers. When no more reductions are %% possible then pack the remaining state numbers to get consecutive @@ -1362,7 +1378,8 @@ out_file(St0, DFA, DF, Actions, Code) -> set_encoding(St0, Ofile), try output_encoding_comment(Ofile, St0), - output_file_directive(Ofile, St0#leex.ifile, 0), + Deterministic = proplists:get_bool(deterministic, St0#leex.opts), + output_file_directive(Ofile, St0#leex.ifile, Deterministic, 0), out_file(Ifile, Ofile, St0, DFA, DF, Actions, Code, 1), verbose_print(St0, "ok~n", []), @@ -1400,15 +1417,22 @@ inc_file_name(Filename) -> %% characters. out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L) -> + Deterministic = proplists:get_bool(deterministic, St#leex.opts), case io:get_line(Ifile, leex) of - eof -> output_file_directive(Ofile, St#leex.ifile, L); - {error, _} -> add_error(St#leex.ifile, {L, leex, cannot_parse}, St); + eof -> + output_file_directive(Ofile, St#leex.ifile, Deterministic, L); + {error, _} -> + add_error(St#leex.ifile, {L, leex, cannot_parse}, St); Line -> case string:slice(Line, 0, 5) of "##mod" -> out_module(Ofile, St); "##cod" -> out_erlang_code(Ofile, St, Code, L); + "##str" -> out_string(Ofile, St#leex.opts); + "##tkn" -> out_token(Ofile, St#leex.opts); + "##tks" -> out_tokens(Ofile, St#leex.opts); + "##tab" -> out_tab_size(Ofile, St#leex.opts); "##dfa" -> out_dfa(Ofile, St, DFA, Code, DF, L); - "##act" -> out_actions(Ofile, St#leex.xfile, Actions); + "##act" -> out_actions(Ofile, St#leex.xfile, Deterministic, Actions); _ -> io:put_chars(Ofile, Line) end, out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L+1) @@ -1419,7 +1443,8 @@ out_module(File, St) -> out_erlang_code(File, St, Code, L) -> {CodeL,CodePos,_NCodeLines} = Code, - output_file_directive(File, St#leex.xfile, CodeL), + Deterministic = proplists:get_bool(deterministic, St#leex.opts), + output_file_directive(File, St#leex.xfile, Deterministic, CodeL), {ok,Xfile} = file:open(St#leex.xfile, [read]), try set_encoding(St, Xfile), @@ -1429,7 +1454,93 @@ out_erlang_code(File, St, Code, L) -> ok = file:close(Xfile) end, io:nl(File), - output_file_directive(File, St#leex.ifile, L). + output_file_directive(File, St#leex.ifile, Deterministic, L). + +out_tab_size(File, Opts) -> + Size = proplists:get_value(tab_size, Opts), + io:fwrite(File, "tab_size() -> ~p.\n", [Size]). + +%% Exclude column number if needed +out_string(File, Opts) -> + out_string_1(File, Opts), + out_string_2(File, Opts), + Vars = lists:join(", ",["Ics","L0","C0","Tcs","Ts"]), + out_head(File,string,Vars), + EL = proplists:get_value(error_location, Opts), + case EL of + column -> + io:fwrite(File," do_string(~s).\n",[Vars]); + line -> + io:fwrite(File," case do_string(~s) of\n",[Vars]), + io:fwrite(File," {ok, T, {L,_}} -> {ok, T, L};\n",[]), + io:fwrite(File," {error, {{EL,_},M,D}, {L,_}} ->\n",[]), + io:fwrite(File," EI = {EL,M,D},\n",[]), + io:fwrite(File," {error, EI, L}\n",[]), + io:fwrite(File," end.\n",[]) + end. + +out_string_1(File, Opts) -> + out_head(File,string,"Ics"), + EL = proplists:get_value(error_location, Opts), + DefLoc = case EL of + column -> "{1,1}"; + line -> "1" + end, + io:fwrite(File," string(~s).\n",["Ics,"++DefLoc]). + +out_string_2(File, Opts) -> + EL = proplists:get_value(error_location, Opts), + case EL of + column -> + out_head(File,string,"Ics,{L0,C0}"), + CallVars = lists:join(", ", ["Ics","L0","C0","Ics","[]"]), + io:fwrite(File," string(~s).\n",[CallVars]); + line -> + out_head(File,string,"Ics,L0"), + CallVars = lists:join(", ", ["Ics","L0","1","Ics","[]"]), + io:fwrite(File," string(~s).\n",[CallVars]) + end. + +out_token(File, Opts) -> + out_tokens_wrapper(File, Opts, token). + +out_tokens(File, Opts) -> + out_tokens_wrapper(File, Opts, tokens). + +out_tokens_wrapper(File, Opts, Fun) -> + out_token_2(File, Opts, Fun), + EL = proplists:get_value(error_location, Opts), + case EL of + column -> + VarsCol = lists:join(", ",["Cont","Chars","{Line,Col}"]), + out_head(File, Fun, VarsCol), + io:fwrite(File," do_~s(~s).\n",[Fun,"Cont,Chars,Line,Col"]); + line -> + VarsCol = lists:join(", ",["Cont","Chars","Line"]), + out_head(File, Fun, VarsCol), + io:fwrite(File," case do_~s(~s) of\n",[Fun,"Cont,Chars,Line,1"]), + io:fwrite(File," {more, _} = C -> C;\n",[]), + io:fwrite(File," {done, Ret0, R} ->\n",[]), + io:fwrite(File," Ret1 = case Ret0 of\n",[]), + io:fwrite(File," {ok, T, {L,_}} -> {ok, T, L};\n",[]), + io:fwrite(File," {eof, {L,_}} -> {eof, L};\n",[]), + io:fwrite(File," {error, {{EL,_},M,D},{L,_}} -> {error, {EL,M,D},L}\n",[]), + io:fwrite(File," end,\n",[]), + io:fwrite(File," {done, Ret1, R}\n",[]), + io:fwrite(File," end.\n",[]) + end. + +out_token_2(File, Opts, Fun) -> + out_head(File, Fun, "Cont,Chars"), + EL = proplists:get_value(error_location, Opts), + DefLoc = case EL of + column -> "{1,1}"; + line -> "1" + end, + io:fwrite(File," ~s(~s).\n",[Fun,"Cont,Chars,"++DefLoc]). + +out_head(File, Fun, Vars) -> + io:fwrite(File, "~s(~s) -> \n",[Fun,Vars]). file_copy(From, To) -> case io:get_line(From, leex) of @@ -1441,40 +1552,41 @@ file_copy(From, To) -> out_dfa(File, St, DFA, Code, DF, L) -> {_CodeL,_CodePos,NCodeLines} = Code, + Deterministic = proplists:get_bool(deterministic, St#leex.opts), %% Three file attributes before this one... - output_file_directive(File, St#leex.efile, L+(NCodeLines-1)+3), + output_file_directive(File, St#leex.efile, Deterministic, L+(NCodeLines-1)+3), io:fwrite(File, "yystate() -> ~w.~n~n", [DF]), foreach(fun (S) -> out_trans(File, S) end, DFA), - io:fwrite(File, "yystate(S, Ics, Line, Tlen, Action, Alen) ->~n", []), - io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,S}.~n", []). + io:fwrite(File, "yystate(S, Ics, Line, Col, Tlen, Action, Alen) ->~n", []), + io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,Col,S}.~n", []). out_trans(File, #dfa_state{no=N,trans=[],accept={accept,A}}) -> %% Accepting end state, guaranteed done. - io:fwrite(File, "yystate(~w, Ics, Line, Tlen, _, _) ->~n", [N]), - io:fwrite(File, " {~w,Tlen,Ics,Line};~n", [A]); + io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, _, _) ->~n", [N]), + io:fwrite(File, " {~w,Tlen,Ics,Line,Col};~n", [A]); out_trans(File, #dfa_state{no=N,trans=Tr,accept={accept,A}}) -> %% Accepting state, but there maybe more. foreach(fun (T) -> out_accept_tran(File, N, A, T) end, pack_trans(Tr)), - io:fwrite(File, "yystate(~w, Ics, Line, Tlen, _, _) ->~n", [N]), - io:fwrite(File, " {~w,Tlen,Ics,Line,~w};~n", [A,N]); + io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, _, _) ->~n", [N]), + io:fwrite(File, " {~w,Tlen,Ics,Line,Col,~w};~n", [A,N]); out_trans(File, #dfa_state{no=N,trans=Tr,accept=noaccept}) -> %% Non-accepting transition state. foreach(fun (T) -> out_noaccept_tran(File, N, T) end, pack_trans(Tr)), - io:fwrite(File, "yystate(~w, Ics, Line, Tlen, Action, Alen) ->~n", [N]), - io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,~w};~n", [N]). + io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, Action, Alen) ->~n", [N]), + io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,Col,~w};~n", [N]). out_accept_tran(File, N, A, {{Cf,maxchar},S}) -> out_accept_head_max(File, N, Cf), - out_accept_body(File, S, "Line", A); + out_accept_body(File, S, "Line", "Col", A); out_accept_tran(File, N, A, {{Cf,Cl},S}) -> out_accept_head_range(File, N, Cf, Cl), - out_accept_body(File, S, "Line", A); + out_accept_body(File, S, "Line", "Col", A); out_accept_tran(File, N, A, {$\n,S}) -> out_accept_head_1(File, N, $\n), - out_accept_body(File, S, "Line+1", A); + out_accept_body(File, S, "Line+1", "1", A); out_accept_tran(File, N, A, {C,S}) -> out_accept_head_1(File, N, C), - out_accept_body(File, S, "Line", A). + out_accept_body(File, S, "Line", "Col", A). out_accept_head_1(File, State, Char) -> out_head_1(File, State, Char, "_", "_"). @@ -1485,21 +1597,21 @@ out_accept_head_max(File, State, Min) -> out_accept_head_range(File, State, Min, Max) -> out_head_range(File, State, Min, Max, "_", "_"). -out_accept_body(File, Next, Line, Action) -> - out_body(File, Next, Line, io_lib:write(Action), "Tlen"). +out_accept_body(File, Next, Line, Col, Action) -> + out_body(File, Next, Line, Col, io_lib:write(Action), "Tlen"). out_noaccept_tran(File, N, {{Cf,maxchar},S}) -> out_noaccept_head_max(File, N, Cf), - out_noaccept_body(File, S, "Line"); + out_noaccept_body(File, S, "Line", "Col"); out_noaccept_tran(File, N, {{Cf,Cl},S}) -> out_noaccept_head_range(File, N, Cf, Cl), - out_noaccept_body(File, S, "Line"); + out_noaccept_body(File, S, "Line", "Col"); out_noaccept_tran(File, N, {$\n,S}) -> out_noaccept_head_1(File, N, $\n), - out_noaccept_body(File, S, "Line+1"); + out_noaccept_body(File, S, "Line+1", "1"); out_noaccept_tran(File, N, {C,S}) -> out_noaccept_head_1(File, N, C), - out_noaccept_body(File, S, "Line"). + out_noaccept_body(File, S, "Line", "Col"). out_noaccept_head_1(File, State, Char) -> out_head_1(File, State, Char, "Action", "Alen"). @@ -1510,24 +1622,27 @@ out_noaccept_head_max(File, State, Min) -> out_noaccept_head_range(File, State, Min, Max) -> out_head_range(File, State, Min, Max, "Action", "Alen"). -out_noaccept_body(File, Next, Line) -> - out_body(File, Next, Line, "Action", "Alen"). +out_noaccept_body(File, Next, Line, Col) -> + out_body(File, Next, Line, Col, "Action", "Alen"). +out_head_1(File, State, Char = $\n, Action, Alen) -> + io:fwrite(File, "yystate(~w, [~w|Ics], Line, _, Tlen, ~s, ~s) ->\n", + [State,Char,Action,Alen]); out_head_1(File, State, Char, Action, Alen) -> - io:fwrite(File, "yystate(~w, [~w|Ics], Line, Tlen, ~s, ~s) ->\n", + io:fwrite(File, "yystate(~w, [~w|Ics], Line, Col, Tlen, ~s, ~s) ->\n", [State,Char,Action,Alen]). out_head_max(File, State, Min, Action, Alen) -> - io:fwrite(File, "yystate(~w, [C|Ics], Line, Tlen, ~s, ~s) when C >= ~w ->\n", + io:fwrite(File, "yystate(~w, [C|Ics], Line, Col, Tlen, ~s, ~s) when C >= ~w ->\n", [State,Action,Alen,Min]). out_head_range(File, State, Min, Max, Action, Alen) -> - io:fwrite(File, "yystate(~w, [C|Ics], Line, Tlen, ~s, ~s) when C >= ~w, C =< ~w ->\n", + io:fwrite(File, "yystate(~w, [C|Ics], Line, Col, Tlen, ~s, ~s) when C >= ~w, C =< ~w ->\n", [State,Action,Alen,Min,Max]). -out_body(File, Next, Line, Action, Alen) -> - io:fwrite(File, " yystate(~w, Ics, ~s, Tlen+1, ~s, ~s);\n", - [Next,Line,Action,Alen]). +out_body(File, Next, Line, Col, Action, Alen) -> + io:fwrite(File, " yystate(~w, Ics, ~s, ~s, Tlen+1, ~s, ~s);\n", + [Next,Line,Col,Action,Alen]). %% pack_trans([{Crange,State}]) -> [{Crange,State}] when %% Crange = {Char,Char} | Char. @@ -1565,37 +1680,38 @@ pack_trans([Tr|Trs], Pt) -> % The default uninteresting case pack_trans(Trs, Pt ++ [Tr]); pack_trans([], Pt) -> Pt. -%% out_actions(File, XrlFile, ActionList) -> ok. +%% out_actions(File, XrlFile, Deterministic, ActionList) -> ok. %% Write out the action table. -out_actions(File, XrlFile, As) -> +out_actions(File, XrlFile, Deterministic, As) -> As1 = prep_out_actions(As), foreach(fun (A) -> out_action(File, A) end, As1), - io:fwrite(File, "yyaction(_, _, _, _) -> error.~n", []), - foreach(fun (A) -> out_action_code(File, XrlFile, A) end, As1). + io:fwrite(File, "yyaction(_, _, _, _, _) -> error.~n", []), + foreach(fun (A) -> out_action_code(File, XrlFile, Deterministic, A) end, As1). prep_out_actions(As) -> map(fun ({A,empty_action}) -> {A,empty_action}; - ({A,Code,TokenChars,TokenLen,TokenLine}) -> + ({A,Code,TokenChars,TokenLen,TokenLine,TokenCol,TokenLoc}) -> Vs = [{TokenChars,"TokenChars"}, {TokenLen,"TokenLen"}, - {TokenLine,"TokenLine"}, + {TokenLine or TokenLoc,"TokenLine"}, + {TokenCol or TokenLoc,"TokenCol"}, {TokenChars,"YYtcs"}, {TokenLen or TokenChars,"TokenLen"}], Vars = [if F -> S; true -> "_" end || {F,S} <- Vs], Name = list_to_atom(lists:concat([yyaction_,A])), - [Chars,Len,Line,_,_] = Vars, - Args = [V || V <- [Chars,Len,Line], V =/= "_"], + [Chars,Len,Line,Col,_,_] = Vars, + Args = [V || V <- [Chars,Len,Line,Col], V =/= "_"], ArgsChars = lists:join(", ", Args), - {A,Code,Vars,Name,Args,ArgsChars} + {A,Code,Vars,Name,Args,ArgsChars, TokenLoc} end, As). out_action(File, {A,empty_action}) -> - io:fwrite(File, "yyaction(~w, _, _, _) -> skip_token;~n", [A]); -out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars}) -> - [_,_,Line,Tcs,Len] = Vars, - io:fwrite(File, "yyaction(~w, ~s, ~s, ~s) ->~n", [A,Len,Tcs,Line]), + io:fwrite(File, "yyaction(~w, _, _, _, _) -> skip_token;~n", [A]); +out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars,_TokenLoc}) -> + [_,_,Line,Col,Tcs,Len] = Vars, + io:fwrite(File, "yyaction(~w, ~s, ~s, ~s, ~s) ->~n", [A,Len,Tcs,Line,Col]), if Tcs =/= "_" -> io:fwrite(File, " TokenChars = yypre(YYtcs, TokenLen),~n", []); @@ -1603,15 +1719,19 @@ out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars}) -> end, io:fwrite(File, " ~s(~s);~n", [Name, ArgsChars]). -out_action_code(_File, _XrlFile, {_A,empty_action}) -> +out_action_code(_File, _XrlFile, _Deterministic, {_A,empty_action}) -> ok; -out_action_code(File, XrlFile, {_A,Code,_Vars,Name,Args,ArgsChars}) -> +out_action_code(File, XrlFile, Deterministic, {_A,Code,_Vars,Name,Args,ArgsChars, TokenLoc}) -> %% Should set the file to the .erl file, but instead assumes that %% ?LEEXINC is syntactically correct. io:fwrite(File, "\n-compile({inline,~w/~w}).\n", [Name, length(Args)]), L = erl_scan:line(hd(Code)), - output_file_directive(File, XrlFile, L-2), + output_file_directive(File, XrlFile, Deterministic, L-2), io:fwrite(File, "~s(~s) ->~n", [Name, ArgsChars]), + if + TokenLoc -> io:fwrite(File," TokenLoc={TokenLine,TokenCol},~n",[]); + true -> ok + end, io:fwrite(File, " ~ts\n", [pp_tokens(Code, L, File)]). %% pp_tokens(Tokens, Line, File) -> [char()]. @@ -1710,12 +1830,18 @@ output_encoding_comment(_File, #leex{encoding = none}) -> output_encoding_comment(File, #leex{encoding = Encoding}) -> io:fwrite(File, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]). -output_file_directive(File, Filename, Line) -> +output_file_directive(File, Filename, Deterministic, Line) -> io:fwrite(File, <<"-file(~ts, ~w).\n">>, - [format_filename(Filename, File), Line]). - -format_filename(Filename0, File) -> - Filename = filename:flatten(Filename0), + [format_filename(Filename, File, Deterministic), Line]). + +format_filename(Filename0, File, Deterministic) -> + Filename = + case Deterministic of + true -> + filename:basename(filename:flatten(Filename0)); + false -> + filename:flatten(Filename0) + end, case enc(File) of unicode -> io_lib:write_string(Filename); latin1 -> io_lib:write_string_as_latin1(Filename) diff --git a/lib/parsetools/src/parsetools.app.src b/lib/parsetools/src/parsetools.app.src index a7b258820aa2..e67e3e38f2a4 100644 --- a/lib/parsetools/src/parsetools.app.src +++ b/lib/parsetools/src/parsetools.app.src @@ -12,7 +12,7 @@ {env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]} ] }, - {runtime_dependencies, ["stdlib-2.5","kernel-3.0","erts-6.0"]} + {runtime_dependencies, ["stdlib-3.4","kernel-3.0","erts-6.0"]} ] }. diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index 0e5b5d4388de..ffd04a163131 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -117,7 +117,7 @@ %% when debugging). %% Non-terminals are also given integer codes, starting with -1. The -%% absolut value of the code is used for indexing a tuple of lists of +%% absolute value of the code is used for indexing a tuple of lists of %% rules. -define(SYMBOLS_AS_CODES, true). @@ -141,9 +141,10 @@ compile(Input0, Output0, Output = shorten_filename(Output0), Includefile = lists:sublist(Includes, 1), Werror = proplists:get_bool(warnings_as_errors, Specific), + Deterministic = proplists:get_bool(deterministic, Specific), Opts = [{parserfile,Output}, {includefile,Includefile}, {verbose,Verbose}, {report_errors, true}, {report_warnings, WarnLevel > 0}, - {warnings_as_errors, Werror}], + {warnings_as_errors, Werror}, {deterministic, Deterministic}], case file(Input, Opts) of {ok, _OutFile} -> ok; @@ -265,6 +266,7 @@ file(GrammarFile) -> | {'parserfile', Parserfile :: file:filename()} | {'verbose', boolean()} | {'warnings_as_errors', boolean()} + | {'deterministic', boolean()} | 'report_errors' | 'report_warnings' | 'report' | 'return_errors' | 'return_warnings' | 'return' | 'verbose' | 'warnings_as_errors'. @@ -407,7 +409,7 @@ check_options(_Options, _, _L) -> all_options() -> [error_location, file_attributes, includefile, parserfile, report_errors, report_warnings, return_errors, return_warnings, - time, verbose, warnings_as_errors]. + time, verbose, warnings_as_errors, deterministic]. default_option(error_location) -> column; default_option(file_attributes) -> true; @@ -419,7 +421,8 @@ default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(time) -> false; default_option(verbose) -> false; -default_option(warnings_as_errors) -> false. +default_option(warnings_as_errors) -> false; +default_option(deterministic) -> false. atom_option(file_attributes) -> {file_attributes, true}; atom_option(report_errors) -> {report_errors, true}; @@ -429,6 +432,7 @@ atom_option(return_warnings) -> {return_warnings, true}; atom_option(time) -> {time, true}; atom_option(verbose) -> {verbose, true}; atom_option(warnings_as_errors) -> {warnings_as_errors, true}; +atom_option(deterministic) -> {deterministic, true}; atom_option(Key) -> Key. is_filename(T) -> @@ -1317,7 +1321,7 @@ compute_state(Seed, Tables) -> Closure = keysort(1, erase()), state_items(Closure, [], [], Tables#tabs.rp_rhs). -%% Collects a uniqe id for the state (all rule pointers). +%% Collects a unique id for the state (all rule pointers). state_items([{RP, LA} | L], Is, Id, RpRhs) -> I = #item{rule_pointer = RP, look_ahead = LA, rhs = element(RP, RpRhs)}, state_items(L, [I | Is], [RP | Id], RpRhs); @@ -1911,13 +1915,13 @@ report_conflict(Conflict, St, ActionName, How) -> if St#yecc.verbose -> io:fwrite(<<"~s\n">>, [format_conflict(Conflict)]), - Formated = format_symbol(ActionName), + Formatted = format_symbol(ActionName), case How of prec -> - io:fwrite(<<"Resolved in favor of ~ts.\n\n">>, [Formated]); + io:fwrite(<<"Resolved in favor of ~ts.\n\n">>, [Formatted]); default -> io:fwrite(<<"Conflict resolved in favor of ~ts.\n\n">>, - [Formated]) + [Formatted]) end; true -> ok @@ -2130,7 +2134,7 @@ output_goto_fini(F, NT, #yecc{includefile_version = {1,1}}=St0) -> [F]), fwrite(St, ?YECC_BUG(<<"{~ts, State, missing_in_goto_table}">>, - [quoted_atom(St0, NT)]), + [quoted_atom(NT)]), []); output_goto_fini(_F, _NT, St) -> fwrite(St, <<".\n\n">>, []). @@ -2255,13 +2259,13 @@ output_action(St, State, Terminal, #reduce{}=Action, IsFirst, SI) -> output_action(St0, State, Terminal, #shift{state = NewState}, IsFirst, _SI) -> St10 = delim(St0, IsFirst), St = fwrite(St10, <<"yeccpars2_~w(S, ~ts, Ss, Stack, T, Ts, Tzr) ->\n">>, - [State, quoted_atom(St10, Terminal)]), + [State, quoted_atom(Terminal)]), output_call_to_includefile(NewState, St); output_action(St0, State, Terminal, accept, IsFirst, _SI) -> St10 = delim(St0, IsFirst), St = fwrite(St10, <<"yeccpars2_~w(_S, ~ts, _Ss, Stack, _T, _Ts, _Tzr) ->\n">>, - [State, quoted_atom(St10, Terminal)]), + [State, quoted_atom(Terminal)]), fwrite(St, <<" {ok, hd(Stack)}">>, []); output_action(St, _State, _Terminal, nonassoc, _IsFirst, _SI) -> St. @@ -2287,7 +2291,7 @@ output_reduce(St0, State, Terminal, IsFirst, StateInfo) -> St10 = delim(St0, IsFirst), QuotedTerminal = if - is_atom(Terminal) -> quoted_atom(St10, Terminal); + is_atom(Terminal) -> quoted_atom(Terminal); true -> Terminal end, St20 = fwrite(St10, @@ -2341,11 +2345,13 @@ delim(St, true) -> delim(St, false) -> fwrite(St, <<";\n">>, []). -quoted_atom(#yecc{encoding = latin1}, Atom) when is_atom(Atom) -> - io_lib:write_atom_as_latin1(Atom); -quoted_atom(_St, Atomic) -> - io_lib:write(Atomic). - +%% Always quote atoms to ensure compatibility with future reserved words. +quoted_atom(Atom) when is_atom(Atom) -> + case lists:flatten(io_lib:write_atom_as_latin1(Atom)) of + "'" ++ _ = Quoted -> Quoted; + NotQuoted -> ["'", NotQuoted, "'"] + end. + output_inlined(St, UserCodeActions, Infile) -> foldl(fun(#user_code{funname = InlinedFunctionName, action = Action}, St_0) -> @@ -2407,13 +2413,23 @@ output_nowarn(St, Function, Suffix, Arity) -> inlined_function_name(St, State, Terminal) -> End = case Terminal of "Cat" -> []; - _ -> [quoted_atom(St, Terminal)] + _ -> [safe_atom_chars(St, Terminal)] end, list_to_atom(concat([yeccpars2_, State, '_'] ++ End)). -compile({nowarn_unused_function,function_name/3}). function_name(St, Name, Suf) -> - list_to_atom(concat([Name, '_'] ++ [quoted_atom(St, Suf)])). + list_to_atom(concat([Name, '_', safe_atom_chars(St, Suf)])). + +safe_atom_chars(St, Atom) when is_atom(Atom) -> + case St of + #yecc{encoding = latin1} -> + io_lib:write_atom_as_latin1(Atom); + #yecc{} -> + atom_to_list(Atom) + end; +safe_atom_chars(_St, Atomic) -> + io_lib:write(Atomic). rule(RulePointer, St) -> #rule{n = N, location = Location, symbols = Symbols} = @@ -2683,7 +2699,12 @@ nl(#yecc{outport = Outport, line = Line}=St) -> St#yecc{line = Line + 1}. format_filename(Filename0, St) -> - Filename = filename:flatten(Filename0), + Deterministic = proplists:get_bool(deterministic, St#yecc.options), + Filename = + case Deterministic of + true -> filename:basename(filename:flatten(Filename0)); + false -> filename:flatten(Filename0) + end, case lists:keyfind(encoding, 1, io:getopts(St#yecc.outport)) of {encoding, unicode} -> io_lib:write_string(Filename); _ -> io_lib:write_string_as_latin1(Filename) diff --git a/lib/parsetools/test/Makefile b/lib/parsetools/test/Makefile index 046b29067bf5..23cb9709e1fc 100644 --- a/lib/parsetools/test/Makefile +++ b/lib/parsetools/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2016. All Rights Reserved. +# Copyright Ericsson AB 2005-2022. 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. @@ -42,6 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/parsetools_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -54,7 +55,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl index 1518c5d91ef4..28142222f7f7 100644 --- a/lib/parsetools/test/leex_SUITE.erl +++ b/lib/parsetools/test/leex_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -22,6 +22,7 @@ %-define(debug, true). -include_lib("stdlib/include/erl_compile.hrl"). +-include_lib("stdlib/include/assert.hrl"). -include_lib("kernel/include/file.hrl"). -ifdef(debug). @@ -39,12 +40,12 @@ init_per_testcase/2, end_per_testcase/2]). -export([ - file/1, compile/1, syntax/1, + file/1, compile/1, syntax/1, deterministic/1, pt/1, man/1, ex/1, ex2/1, not_yet/1, line_wrap/1, otp_10302/1, otp_11286/1, unicode/1, otp_13916/1, otp_14285/1, - otp_17023/1, compiler_warnings/1]). + otp_17023/1, compiler_warnings/1, column_support/1]). % Default timetrap timeout (set in init_per_testcase). -define(default_timeout, test_server:minutes(1)). @@ -64,8 +65,8 @@ all() -> [{group, checks}, {group, examples}, {group, tickets}, {group, bugs}]. groups() -> - [{checks, [], [file, compile, syntax]}, - {examples, [], [pt, man, ex, ex2, not_yet, unicode]}, + [{checks, [], [file, compile, syntax, deterministic]}, + {examples, [], [pt, man, ex, ex2, not_yet, unicode, column_support]}, {tickets, [], [otp_10302, otp_11286, otp_13916, otp_14285, otp_17023, compiler_warnings]}, {bugs, [], [line_wrap]}]. @@ -117,6 +118,17 @@ file(Config) when is_list(Config) -> {'EXIT', {badarg, _}} = (catch leex:file(Filename, includefile)), + {'EXIT', {badarg, _}} = + (catch leex:file(Filename, {tab_size,0})), + {'EXIT', {badarg, _}} = + (catch leex:file(Filename, {tab_size,"4"})), + {'EXIT', {badarg, _}} = + (catch leex:file(Filename, {tab_size,3.5})), + {'EXIT', {badarg, _}} = + (catch leex:file(Filename, {error_location,{line,column}})), + {'EXIT', {badarg, _}} = + (catch leex:file(Filename, {error_location,col})), + Mini = <<"Definitions.\n" "D = [0-9]\n" "Rules.\n" @@ -368,6 +380,42 @@ syntax(Config) when is_list(Config) -> leex:file(Filename, Ret), ok. +deterministic(doc) -> + "Check leex respects the +deterministic flag."; +deterministic(suite) -> []; +deterministic(Config) when is_list(Config) -> + Dir = ?privdir, + Filename = filename:join(Dir, "file.xrl"), + Scannerfile = filename:join(Dir, "file.erl"), + Mini = <<"Definitions.\n" + "D = [0-9]\n" + "Rules.\n" + "{L}+ : {token,{word,TokenLine,TokenChars}}.\n" + "Erlang code.\n">>, + ok = file:write_file(Filename, Mini), + + %% Generated leex scanners include the leexinc.hrl header file by default, + %% so we'll get a -file attribute corresponding to that include. In + %% deterministic mode, that include should only use the basename, + %% "leexinc.hrl", but otherwise, it should contain the full path. + + %% Matches when OTP is not installed (e.g. /lib/parsetools/include/leexinc.hrl) + %% and when it is (e.g. /lib/parsetools-2.3.2/include/leexinc.hrl) + AbsolutePathSuffix = ".*/lib/parsetools.*/include/leexinc\.hrl", + + ok = leex:compile(Filename, Scannerfile, #options{specific=[deterministic]}), + {ok, FormsDet} = epp:parse_file(Scannerfile,[]), + ?assertMatch(false, search_for_file_attr(AbsolutePathSuffix, FormsDet)), + ?assertMatch({value, _}, search_for_file_attr("leexinc\.hrl", FormsDet)), + file:delete(Scannerfile), + + ok = leex:compile(Filename, Scannerfile, #options{}), + {ok, Forms} = epp:parse_file(Scannerfile,[]), + ?assertMatch({value, _}, search_for_file_attr(AbsolutePathSuffix, Forms)), + file:delete(Scannerfile), + + file:delete(Filename), + ok. pt(doc) -> "Pushing back characters."; @@ -380,17 +428,17 @@ pt(Config) when is_list(Config) -> "L = [a-z]\n" "Rules.\n" - "{L}+ : {token,{word,TokenLine,TokenChars}}.\n" + "{L}+ : {token,{word,TokenLoc,TokenChars}}.\n" "abc{D}+ : {skip_token,\"sture\" ++ string:substr(TokenChars, 4)}.\n" - "{D}+ : {token,{integer,TokenLine,list_to_integer(TokenChars)}}.\n" + "{D}+ : {token,{integer,TokenLoc,list_to_integer(TokenChars)}}.\n" "\\s : .\n" "\\r\\n : {end_token,{crlf,TokenLine}}.\n" "Erlang code.\n" "-export([t/0]).\n" "t() -> - {ok,[{word,1,\"sture\"},{integer,1,123}],1} = - string(\"abc123\"), ok. ">>, + {ok,[{word,{1,7},\"sture\"},{integer,{1,12},123}],{1,15}} = + string(\"abc123\"), ok. ">>, default, ok}], @@ -405,10 +453,10 @@ unicode(Config) when is_list(Config) -> "Definitions.\n" "RTLarrow = (←)\n" "Rules.\n" - "{RTLarrow} : {token,{\"←\",TokenLine}}.\n" + "{RTLarrow} : {token,{\"←\",TokenLoc}}.\n" "Erlang code.\n" "-export([t/0]).\n" - "t() -> {ok, [{\"←\", 1}], 1} = string(\"←\"), ok.">>, + "t() -> {ok, [{\"←\", {1,1}}], {1,4}} = string(\"←\"), ok.">>, default, ok}], @@ -423,34 +471,33 @@ man(Config) when is_list(Config) -> <<"Definitions.\n" "Rules.\n" "[a-z][0-9a-zA-Z_]* :\n" - " {token,{atom,TokenLine,list_to_atom(TokenChars)}}.\n" + " {token,{atom,TokenLoc,list_to_atom(TokenChars)}}.\n" "[A-Z_][0-9a-zA-Z_]* :\n" - " {token,{var,TokenLine,list_to_atom(TokenChars)}}.\n" + " {token,{var,TokenLoc,list_to_atom(TokenChars)}}.\n" "(\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)? : \n" - " {token,{float,TokenLine,list_to_float(TokenChars)}}.\n" + " {token,{float,TokenLoc,list_to_float(TokenChars)}}.\n" "\\s : skip_token.\n" "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{float,1,3.14},{atom,1,atom},{var,1,'V314'}],1} =\n" + " {ok,[{float,{1,1},3.14},{atom,{1,5},atom},{var,{1,10},'V314'}],{1,14}} =\n" " string(\"3.14atom V314\"),\n" " ok.\n">>, default, ok}, - - {man_2, + {man_2, <<"Definitions.\n" "D = [0-9]\n" "Rules.\n" "{D}+ :\n" - " {token,{integer,TokenLine,list_to_integer(TokenChars)}}.\n" + " {token,{integer,TokenLoc,list_to_integer(TokenChars)}}.\n" "{D}+\\.{D}+((E|e)(\\+|\\-)?{D}+)? :\n" - " {token,{float,TokenLine,list_to_float(TokenChars)}}.\n" + " {token,{float,TokenLoc,list_to_float(TokenChars)}}.\n" "\\s : skip_token.\n" "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{float,1,3.14},{integer,1,314}],1} = \n" + " {ok,[{float,{1,1},3.14},{integer,{1,6},314}],{1,9}} = \n" " string(\"3.14 314\"),\n" " ok.\n">>, default, @@ -468,13 +515,13 @@ ex(Config) when is_list(Config) -> "D = [0-543-705-982]\n" "Rules.\n" "{D}+ :\n" - " {token,{integer,TokenLine,list_to_integer(TokenChars)}}.\n" + " {token,{integer,TokenLoc,list_to_integer(TokenChars)}}.\n" "[^235]+ :\n" - " {token,{list_to_atom(TokenChars),TokenLine}}.\n" + " {token,{list_to_atom(TokenChars),TokenLoc}}.\n" "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{integer,1,12},{' c\\na',1},{integer,2,34},{b789a,2}],2} =\n" + " {ok,[{integer,{1,1},12},{' c\\na',{1,3}},{integer,{2,2},34},{b789a,{2,4}}],{2,9}} =\n" " string(\"12 c\\na34b789a\"),\n" " ok.\n">>, default, @@ -491,7 +538,7 @@ ex(Config) when is_list(Config) -> "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[chars,zyx],1} = string(\"abcdef zyx123\"),\n" + " {ok,[chars,zyx],{1,14}} = string(\"abcdef zyx123\"),\n" " ok.\n">>, default, ok}, @@ -504,7 +551,7 @@ ex(Config) when is_list(Config) -> "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[],1} = string(\"\"), ok.\n">>, % string("a") would loop... + " {ok,[],{1,1}} = string(\"\"), ok.\n">>, % string("a") would loop... default, ok}, @@ -537,12 +584,12 @@ ex(Config) when is_list(Config) -> "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{white,\"\\b\\f\"}],1} = string(\"\\b\\f\"),\n" - " {ok,[{form,\"ff\\f\"}],1} = string(\"ff\\f\"),\n" - " {ok,[{string,\"\\\"foo\\\"\"}],1} = string(\"\\\"foo\\\"\"),\n" - " {ok,[{char,\"$.\"}],1} = string(\"$\\.\"),\n" - " {ok,[{list,\"[a,b,c]\"}],1} = string(\"[a,b,c]\"),\n" - " {ok,[{other,\"$^\\\\\"}],1} = string(\"$^\\\\\"),\n" + " {ok,[{white,\"\\b\\f\"}],{1,3}} = string(\"\\b\\f\"),\n" + " {ok,[{form,\"ff\\f\"}],{1,4}} = string(\"ff\\f\"),\n" + " {ok,[{string,\"\\\"foo\\\"\"}],{1,6}} = string(\"\\\"foo\\\"\"),\n" + " {ok,[{char,\"$.\"}],{1,3}} = string(\"$\\.\"),\n" + " {ok,[{list,\"[a,b,c]\"}],{1,8}} = string(\"[a,b,c]\"),\n" + " {ok,[{other,\"$^\\\\\"}],{1,4}} = string(\"$^\\\\\"),\n" " ok.\n">>, default, ok}, @@ -570,7 +617,7 @@ ex(Config) when is_list(Config) -> "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{hex,[17,171,48,172]}],1} =\n" + " {ok,[{hex,[17,171,48,172]}],{1,7}} =\n" " string(\"\\x{11}\\xab0\\xac\"),\n" " ok.\n">>, default, @@ -600,47 +647,47 @@ WS = ([\\000-\\s]|%.*) Rules. {D}+\\.{D}+((E|e)(\\+|\\-)?{D}+)? : - {token,{float,TokenLine,list_to_float(TokenChars)}}. -{D}+#{H}+ : base(TokenLine, TokenChars). -{D}+ : {token,{integer,TokenLine,list_to_integer(TokenChars)}}. + {token,{float,TokenLoc,list_to_float(TokenChars)}}. +{D}+#{H}+ : base(TokenLoc, TokenChars). +{D}+ : {token,{integer,TokenLoc,list_to_integer(TokenChars)}}. {L}{A}* : Atom = list_to_atom(TokenChars), {token,case reserved_word(Atom) of - true -> {Atom,TokenLine}; - false -> {atom,TokenLine,Atom} + true -> {Atom,TokenLoc}; + false -> {atom,TokenLoc,Atom} end}. '(\\\\\\^.|\\\\.|[^'])*' : %% Strip quotes. S = lists:sublist(TokenChars, 2, TokenLen - 2), case catch list_to_atom(string_gen(S)) of {'EXIT',_} -> {error,\"illegal atom \" ++ TokenChars}; - Atom -> {token,{atom,TokenLine,Atom}} + Atom -> {token,{atom,TokenLoc,Atom}} end. -({U}|_){A}* : {token,{var,TokenLine,list_to_atom(TokenChars)}}. +({U}|_){A}* : {token,{var,TokenLoc,list_to_atom(TokenChars)}}. \"(\\\\\\^.|\\\\.|[^\"])*\" : %% Strip quotes. S = lists:sublist(TokenChars, 2, TokenLen - 2), - {token,{string,TokenLine,string_gen(S)}}. + {token,{string,TokenLoc,string_gen(S)}}. \\$(\\\\{O}{O}{O}|\\\\\\^.|\\\\.|.) : - {token,{char,TokenLine,cc_convert(TokenChars)}}. --> : {token,{'->',TokenLine}}. -:- : {token,{':-',TokenLine}}. -\\|\\| : {token,{'||',TokenLine}}. -<- : {token,{'<-',TokenLine}}. -\\+\\+ : {token,{'++',TokenLine}}. --- : {token,{'--',TokenLine}}. -=/= : {token,{'=/=',TokenLine}}. -== : {token,{'==',TokenLine}}. -=:= : {token,{'=:=',TokenLine}}. -/= : {token,{'/=',TokenLine}}. ->= : {token,{'>=',TokenLine}}. -=< : {token,{'=<',TokenLine}}. -<= : {token,{'<=',TokenLine}}. -<< : {token,{'<<',TokenLine}}. ->> : {token,{'>>',TokenLine}}. -:: : {token,{'::',TokenLine}}. + {token,{char,TokenLoc,cc_convert(TokenChars)}}. +-> : {token,{'->',TokenLoc}}. +:- : {token,{':-',TokenLoc}}. +\\|\\| : {token,{'||',TokenLoc}}. +<- : {token,{'<-',TokenLoc}}. +\\+\\+ : {token,{'++',TokenLoc}}. +-- : {token,{'--',TokenLoc}}. +=/= : {token,{'=/=',TokenLoc}}. +== : {token,{'==',TokenLoc}}. +=:= : {token,{'=:=',TokenLoc}}. +/= : {token,{'/=',TokenLoc}}. +>= : {token,{'>=',TokenLoc}}. +=< : {token,{'=<',TokenLoc}}. +<= : {token,{'<=',TokenLoc}}. +<< : {token,{'<<',TokenLoc}}. +>> : {token,{'>>',TokenLoc}}. +:: : {token,{'::',TokenLoc}}. []()[}{|!?/;:,.*+#<>=-] : - {token,{list_to_atom(TokenChars),TokenLine}}. -\\.{WS} : {end_token,{dot,TokenLine}}. + {token,{list_to_atom(TokenChars),TokenLoc}}. +\\.{WS} : {end_token,{dot,TokenLoc}}. {WS}+ : skip_token. Erlang code. @@ -738,7 +785,7 @@ escape_char(C) -> C. XrlFile = filename:join(Dir, "erlang_scan.xrl"), ok = file:write_file(XrlFile, Xrl), ErlFile = filename:join(Dir, "erlang_scan.erl"), - {ok, _} = leex:file(XrlFile, []), + {ok, _} = leex:file(XrlFile, [{error_location, column}]), {ok, _} = compile:file(ErlFile, [{outdir,Dir}]), code:purge(erlang_scan), AbsFile = filename:rootname(ErlFile, ".erl"), @@ -748,79 +795,79 @@ escape_char(C) -> C. erlang_scan:tokens(Cont, Chars, Location) end, F1 = fun(Cont, Chars, Location) -> - erlang_scan:token(Cont, Chars, Location) - end, + erlang_scan:token(Cont, Chars, Location) + end, fun() -> S = "ab cd. ", - {ok, Ts, 1} = scan_tokens_1(S, F, 1), - {ok, Ts, 1} = scan_token_1(S, F1, 1), - {ok, Ts, 1} = scan_tokens(S, F, 1), - {ok, Ts, 1} = erlang_scan:string(S, 1) + {ok, Ts, {1,8}} = scan_tokens_1(S, F, {1,1}), + {ok, Ts, {1,8}} = scan_token_1(S, F1, {1,1}), + {ok, Ts, {1,8}} = scan_tokens(S, F, {1,1}), + {ok, Ts, {1,8}} = erlang_scan:string(S, {1,1}) end(), fun() -> S = "'ab\n cd'. ", - {ok, Ts, 2} = scan_tokens_1(S, F, 1), - {ok, Ts, 2} = scan_token_1(S, F1, 1), - {ok, Ts, 2} = scan_tokens(S, F, 1), - {ok, Ts, 2} = erlang_scan:string(S, 1) + {ok, Ts, {2,7}} = scan_tokens_1(S, F, {1,1}), + {ok, Ts, {2,7}} = scan_token_1(S, F1, {1,1}), + {ok, Ts, {2,7}} = scan_tokens(S, F, {1,1}), + {ok, Ts, {2,7}} = erlang_scan:string(S, {1,1}) end(), fun() -> S = "99. ", - {ok, Ts, 1} = scan_tokens_1(S, F, 1), - {ok, Ts, 1} = scan_token_1(S, F1, 1), - {ok, Ts, 1} = scan_tokens(S, F, 1), - {ok, Ts, 1} = erlang_scan:string(S, 1) + {ok, Ts, {1,5}} = scan_tokens_1(S, F, {1,1}), + {ok, Ts, {1,5}} = scan_token_1(S, F1, {1,1}), + {ok, Ts, {1,5}} = scan_tokens(S, F, {1,1}), + {ok, Ts, {1,5}} = erlang_scan:string(S, {1,1}) end(), - {ok,[{integer,1,99},{dot,1}],1} = erlang_scan:string("99. "), + {ok,[{integer,{1,1},99},{dot,{1,3}}],{1,5}} = erlang_scan:string("99. "), fun() -> Atom = "'" ++ lists:duplicate(1000,$a) ++ "'", S = Atom ++ ". ", Reason = "illegal atom " ++ Atom, - Err = {error,{1,erlang_scan,{user,Reason}},1}, - {done,Err,[]} = scan_tokens_1(S, F, 1), - {done,Err,[]} = scan_token_1(S, F1, 1), - {done,Err,[]} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1003},erlang_scan,{user,Reason}},{1,1003}}, + {done,Err,[]} = scan_tokens_1(S, F, {1,1}), + {done,Err,[]} = scan_token_1(S, F1, {1,1}), + {done,Err,[]} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), fun() -> S = "\x{aaa}. ", - Err = {error,{1,erlang_scan,{illegal,[2730]}},1}, - {done,Err,[]} = scan_tokens_1(S, F, 1), - {done,Err,[_]} = scan_token_1(S, F1, 1), % Note: Rest non-empty - {done,Err,[]} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1},erlang_scan,{illegal,[2730]}},{1,1}}, + {done,Err,[]} = scan_tokens_1(S, F, {1,1}), + {done,Err,[_]} = scan_token_1(S, F1, {1,1}), % Note: Rest non-empty + {done,Err,[]} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), fun() -> S = "\x{aaa} + 1. 34", - Err = {error,{1,erlang_scan,{illegal,[2730]}},1}, - {done,Err,[]} = scan_tokens_1(S, F, 1), - {done,Err,[_]} = scan_token_1(S, F1, 1), % Note: Rest non-empty - {done,Err,"34"} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1},erlang_scan,{illegal,[2730]}},{1,1}}, + {done,Err,[]} = scan_tokens_1(S, F, {1,1}), + {done,Err,[_]} = scan_token_1(S, F1, {1,1}), % Note: Rest non-empty + {done,Err,"34"} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), fun() -> S = "\x{aaa} \x{bbb}. 34", - Err = {error,{1,erlang_scan,{illegal,[2730]}},1}, - {done,Err,[]} = scan_tokens_1(S, F, 1), - {done,Err,[_]} = scan_token_1(S, F1, 1), % Note: Rest non-empty - {done,Err,"34"} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1},erlang_scan,{illegal,[2730]}},{1,1}}, + {done,Err,[]} = scan_tokens_1(S, F, {1,1}), + {done,Err,[_]} = scan_token_1(S, F1, {1,1}), % Note: Rest non-empty + {done,Err,"34"} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), fun() -> S = "\x{aaa} 18#34. 34", - Err = {error,{1,erlang_scan,{illegal,[2730]}},1}, - {done,Err,[]} = scan_tokens_1(S, F, 1), - {done,Err,[_]} = scan_token_1(S, F1, 1), % Note: Rest non-empty - {done,Err,"34"} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1},erlang_scan,{illegal,[2730]}},{1,1}}, + {done,Err,[]} = scan_tokens_1(S, F, {1,1}), + {done,Err,[_]} = scan_token_1(S, F1, {1,1}), % Note: Rest non-empty + {done,Err,"34"} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), fun() -> S = "\x{aaa}"++eof, - Err = {error,{1,erlang_scan,{illegal,[2730]}},1}, - {done,Err,eof} = scan_tokens_1(S, F, 1), - {done,Err,[_]} = scan_token_1(S, F1, 1), % Note: Rest non-empty - {done,Err,eof} = scan_tokens(S, F, 1), - Err = erlang_scan:string(S, 1) + Err = {error,{{1,1},erlang_scan,{illegal,[2730]}},{1,1}}, + {done,Err,eof} = scan_tokens_1(S, F, {1,1}), + {done,Err,[_]} = scan_token_1(S, F1, {1,1}), % Note: Rest non-empty + {done,Err,eof} = scan_tokens(S, F, {1,1}), + Err = erlang_scan:string(S, {1,1}) end(), ok. @@ -875,8 +922,8 @@ line_wrap(Config) when is_list(Config) -> <<" Definitions. Rules. -[a]+[\\n]*= : {token, {first, TokenLine}}. -[a]+ : {token, {second, TokenLine}}. +[a]+[\\n]*= : {token, {first, TokenLoc}}. +[a]+ : {token, {second, TokenLoc}}. [\\s\\r\\n\\t]+ : skip_token. Erlang code. ">>, @@ -891,20 +938,20 @@ Erlang code. code:load_abs(AbsFile, test_line_wrap), fun() -> S = "aaa\naaa", - {ok,[{second,1},{second,2}],2} = test_line_wrap:string(S) + {ok,[{second,{1,1}},{second,{2,1}}],2} = test_line_wrap:string(S) end(), fun() -> S = "aaa\naaa", - {ok,[{second,3},{second,4}],4} = test_line_wrap:string(S, 3) + {ok,[{second,{3,1}},{second,{4,1}}],4} = test_line_wrap:string(S, 3) end(), fun() -> - {done,{ok,{second,1},1},"\na"} = test_line_wrap:token([], "a\na"), + {done,{ok,{second,{1,1}},1},"\na"} = test_line_wrap:token([], "a\na"), {more,Cont1} = test_line_wrap:token([], "\na"), - {done,{ok,{second,2},2},eof} = test_line_wrap:token(Cont1, eof) + {done,{ok,{second,{2,1}},2},eof} = test_line_wrap:token(Cont1, eof) end(), fun() -> {more,Cont1} = test_line_wrap:tokens([], "a\na"), - {done,{ok,[{second,1},{second,2}],2},eof} = test_line_wrap:tokens(Cont1, eof) + {done,{ok,[{second,{1,1}},{second,{2,1}}],2},eof} = test_line_wrap:tokens(Cont1, eof) end(), ok. @@ -1007,7 +1054,7 @@ otp_10302(Config) when is_list(Config) -> "-export([t/0]).\n" "t() ->\n" " %% Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"\n" - " {ok, [R], 1} = string(\"tip\"),\n" + " {ok, [R], {1,4}} = string(\"tip\"),\n" " {tip,foo,'Häpp',[1024,66],[246,114,110,95,1024]} = R,\n" " Häpp = foo,\n" " {tip, Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,\n" @@ -1028,7 +1075,7 @@ otp_10302(Config) when is_list(Config) -> "-export([t/0]).\n" "t() ->\n" " %% Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"\n" - " {ok, [R], 1} = string(\"tip\"),\n" + " {ok, [R], {1,4}} = string(\"tip\"),\n" " {tip,foo,'Häpp',[1024,66],[195,182,114,110,95,208,128]} = R,\n" " Häpp = foo,\n" " {tip, Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,\n" @@ -1043,7 +1090,7 @@ otp_11286(doc) -> "OTP-11286. A Unicode filename bug; both Leex and Yecc."; otp_11286(suite) -> []; otp_11286(Config) when is_list(Config) -> - Node = start_node(otp_11286, "+fnu"), + {ok, Peer, Node} = ?CT_PEER(["+fnu"]), Dir = ?privdir, UName = [1024] ++ "u", UDir = filename:join(Dir, UName), @@ -1087,7 +1134,7 @@ otp_11286(Config) when is_list(Config) -> {ok,_,_} = rpc:call(Node, compile, file, [Scannerfile,[basic_validation,return]]), - true = test_server:stop_node(Node), + peer:stop(Peer), ok. otp_13916(doc) -> @@ -1102,23 +1149,23 @@ otp_13916(Config) when is_list(Config) -> "Rules.\n" "%% mark line break(s) and empty lines by token 'break'\n" "%% in order to use as delimiters\n" - "{B}({S}*{B})+ : {token, {break, TokenLine}}.\n" - "{B} : {token, {break, TokenLine}}.\n" - "{S}+ : {token, {blank, TokenLine, TokenChars}}.\n" - "{W}+ : {token, {word, TokenLine, TokenChars}}.\n" + "{B}({S}*{B})+ : {token, {break, TokenLoc}}.\n" + "{B} : {token, {break, TokenLoc}}.\n" + "{S}+ : {token, {blank, TokenLoc, TokenChars}}.\n" + "{W}+ : {token, {word, TokenLoc, TokenChars}}.\n" "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,[{break,1},{blank,4,\" \"},{word,4,\"breaks\"}],4} =\n" + " {ok,[{break,{1,1}},{blank,{4,1},\" \"},{word,{4,3},\"breaks\"}],{4,9}} =\n" " string(\"\\n\\n \\n breaks\"),\n" - " {ok,[{break,1},{word,4,\"works\"}],4} =\n" + "{ok,[{break,{1,1}},{word,{4,1},\"works\"}],{4,6}} =\n" " string(\"\\n\\n \\nworks\"),\n" - " {ok,[{break,1},{word,4,\"L4\"},{break,4},\n" - " {word,5,\"L5\"},{break,5},{word,7,\"L7\"}], 7} =\n" + " {ok,[{break,{1,1}},{word,{4,1},\"L4\"},{break,{4,3}},\n" + " {word,{5,1},\"L5\"},{break,{5,3}},{word,{7,1},\"L7\"}], {7,3}} =\n" " string(\"\\n\\n \\nL4\\nL5\\n\\nL7\"),\n" - " {ok,[{break,1},{blank,4,\" \"},{word,4,\"L4\"},\n" - " {break,4},{blank,5,\" \"},{word,5,\"L5\"},\n" - " {break,5},{blank,7,\" \"},{word,7,\"L7\"}], 7} =\n" + "{ok,[{break,{1,1}},{blank,{4,1},\" \"},{word,{4,2} ,\"L4\"},\n" + " {break,{4,4}},{blank,{5,1},\" \"},{word,{5,2},\"L5\"},\n" + " {break,{5,4}},{blank,{7,1},\" \"},{word,{7,2},\"L7\"}], {7,4}} =\n" " string(\"\\n\\n \\n L4\\n L5\\n\\n L7\"),\n" " ok.\n">>, default, @@ -1127,8 +1174,7 @@ otp_13916(Config) when is_list(Config) -> ok. otp_14285(Config) -> - Dir = ?privdir, - + %% x{400} takes 2 bytes to represent Ts = [{otp_14285_1, <<"%% encoding: latin-1\n" "Definitions.\n" @@ -1138,11 +1184,11 @@ otp_14285(Config) -> "U = [\\x{400}]\n" "Rules.\n" "{L}+ : {token,l}.\n" - "{U}+ : {token,'\\x{400}'}.\n" + "{U}+ : {token,{TokenLine,'\\x{400}'}}.\n" "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,['\\x{400}'],1} = string(\"\\x{400}\"), ok.\n">>, + " {ok,[{1,'\\x{400}'}],{1,3}} = string(\"\\x{400}\"), ok.\n">>, default, ok}, {otp_14285_2, @@ -1158,7 +1204,7 @@ otp_14285(Config) -> "Erlang code.\n" "-export([t/0]).\n" "t() ->\n" - " {ok,['\x{400}'],1} = string(\"\x{400}\"), ok.\n">>, + " {ok,['\x{400}'],{1,3}} = string(\"\x{400}\"), ok.\n"/utf8>>, default, ok}], run(Config, Ts), @@ -1190,6 +1236,54 @@ otp_17023(Config) -> end, ok. +%% Additional tests added with column support +column_support(Config) -> + Ts = [{token_col_var, + <<"Definitions.\n" + "D = [0-9]\n" + "W = [\\s\\n]\n" + "Rules.\n" + "{W}+ :\n" + "skip_token.\n" + "{D}+ :\n" + "{token,{integer,{TokenLine,TokenCol},list_to_integer(TokenChars)}}.\n" + "{D}+\\.{D}+((E|e)(\\+|\\-)?{D}+)? :\n" + "{token,{float,{TokenLine,TokenCol},list_to_float(TokenChars)}}.\n" + "Erlang code.\n" + "-export([t/0]).\n" + "t() ->\n" + "{ok,[{float, {2,1}, 4.44},{integer, {3,3}, 5},{integer, {7,3}, 7}],{8,2}}" + "= string(\"\n4.44 \n 5 \n \n\n\n 7 \n \"), ok.\n">>, + default, + ok}, + {tab, + <<"Definitions.\n" + "Rules.\n" + "[a]+[\\n]*= : {token, {first, TokenLoc}}.\n" + "[a]+ : {token, {second, TokenLoc}}.\n" + "[\\s\\r\\n\\t]+ : skip_token.\n" + "Erlang code.\n" + "-export([t/0]).\n" + "t() ->\n" + "{ok,[{second,{1,27}},{second,{2,19}}],{2,25}} = string(\" \t \t\t a\\n \t \t aaa\t\"), ok.\n">>, + default, + ok}, + {tab_custom_size, + <<"Definitions.\n" + "Rules.\n" + "[a]+[\\n]*= : {token, {first, TokenLoc}}.\n" + "[a]+ : {token, {second, TokenLoc}}.\n" + "[\\s\\r\\n\\t]+ : skip_token.\n" + "Erlang code.\n" + "-export([t/0]).\n" + "t() ->\n" + "{ok,[{second,{1,15}},{second,{2,9}}],{2,16}} = string(\" \t \t\t a\\n \t \t aaa\t\"), ok.\n">>, + default, + [{tab_size,3}], + ok}], + run(Config, Ts), + ok. + %% OTP-17499. GH-4918. compiler_warnings(Config) -> Xrl = @@ -1210,17 +1304,6 @@ erlang:display({erlfile,ErlFile}), {ok, compiler_warnings, []} = compile:file(ErlFile, [return]), ok. -start_node(Name, Args) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), - ct:log("Trying to start ~w@~s~n", [Name,Host]), - case test_server:start_node(Name, peer, [{args,Args}]) of - {error,Reason} -> - ct:fail(Reason); - {ok,Node} -> - ct:log("Node ~p started~n", [Node]), - Node - end. - unwritable(Fname) -> {ok, Info} = file:read_file_info(Fname), Mode = Info#file_info.mode - 8#00200, @@ -1232,18 +1315,23 @@ writable(Fname) -> ok = file:write_file_info(Fname, Info#file_info{mode = Mode}). run(Config, Tests) -> - F = fun({N,P,Pre,E}) -> - case catch run_test(Config, P, Pre) of - E -> - ok; - Bad -> - ct:fail("~nTest ~p failed. Expected~n ~p~n" - "but got~n ~p~n", [N, E, Bad]) - end + F = fun F({N,P,Pre,E}) -> + F({N,P,Pre,[],E}); + F({N,P,Pre,Opts,E}) -> + case catch run_test(Config,P,Pre,Opts) of + E -> + ok; + Bad -> + ct:fail("~nTest ~p failed. Expected~n ~p~n" + "but got~n ~p~n", [N, E, Bad]) + end end, lists:foreach(F, Tests). run_test(Config, Def, Pre) -> + run_test(Config, Def, Pre, []). + +run_test(Config, Def, Pre, LOpts0) -> %% io:format("testing ~s~n", [binary_to_list(Def)]), DefFile = 'leex_test.xrl', Filename = 'leex_test.erl', @@ -1252,14 +1340,14 @@ run_test(Config, Def, Pre) -> ErlFile = filename:join(DataDir, Filename), Opts = [return, warn_unused_vars,{outdir,DataDir}], ok = file:write_file(XrlFile, Def), - LOpts = [return, {report, false} | + LOpts = LOpts0 ++ [return, {report, false} | case Pre of default -> []; _ -> [{includefile,Pre}] end], - XOpts = [verbose, dfa_graph], % just to get some code coverage... + XOpts = [verbose, dfa_graph, {error_location, column}], % just to get some code coverage... LRet = leex:file(XrlFile, XOpts ++ LOpts), case LRet of {ok, _Outfile, _LWs} -> @@ -1285,3 +1373,13 @@ extract(File, {error, Es, Ws}) -> {errors, extract(File, Es), extract(File, Ws)}; extract(File, Ts) -> lists:append([T || {F, T} <- Ts, F =:= File]). + +search_for_file_attr(PartialFilePathRegex, Forms) -> + lists:search(fun + ({attribute, _, file, {FileAttr, _}}) -> + case re:run(FileAttr, PartialFilePathRegex, [unicode]) of + nomatch -> false; + _ -> true + end; + (_) -> false end, + Forms). diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl index 5162315076f3..383969e7a83a 100644 --- a/lib/parsetools/test/yecc_SUITE.erl +++ b/lib/parsetools/test/yecc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -22,6 +22,7 @@ %-define(debug, true). -include_lib("stdlib/include/erl_compile.hrl"). +-include_lib("stdlib/include/assert.hrl"). -ifdef(debug). -define(config(X,Y), foo). @@ -40,7 +41,7 @@ -export([app_test/1, file/1, syntax/1, compile/1, rules/1, expect/1, - conflicts/1, + conflicts/1, deterministic/1, empty/1, prec/1, yeccpre/1, lalr/1, old_yecc/1, other_examples/1, @@ -70,7 +71,7 @@ all() -> groups() -> [{checks, [], - [file, syntax, compile, rules, expect, conflicts]}, + [file, syntax, compile, rules, expect, conflicts, deterministic]}, {examples, [], [empty, prec, yeccpre, lalr, old_yecc, other_examples]}, {bugs, [], @@ -269,7 +270,7 @@ syntax(Config) when is_list(Config) -> nt -> t.">>), {ok,_,[{_,[{{2,13},yecc,bad_declaration}]}]} = yecc:file(Filename, Ret), - ?line {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = + {ok,_,[{_,[{2,yecc,bad_declaration}]}]} = yecc:file(Filename, [{error_location, line} | Ret]), %% Syntax error found by yeccparser. @@ -926,6 +927,43 @@ conflicts(Config) when is_list(Config) -> file:delete(Filename), ok. +deterministic(doc) -> + "Check yecc respects the +deterministic flag."; +deterministic(suite) -> []; +deterministic(Config) when is_list(Config) -> + Dir = ?privdir, + Filename = filename:join(Dir, "file.yrl"), + Parserfile = filename:join(Dir, "file.erl"), + ok = file:write_file(Filename, + <<"Nonterminals nt. + Terminals t. + Rootsymbol nt. + nt -> t.">>), + + %% Generated yecc parsers need to include the yeccpre.hrl + %% header file, so we'll get a -file attribute corresponding + %% to that include. In deterministic mode, that include should + %% only use the basename, "yeccpre.hrl", but otherwise, it should + %% contain the full path. + + %% Matches when OTP is not installed (e.g. /lib/parsetools/include/yeccpre.hrl) + %% and when it is (e.g. /lib/parsetools-2.3.2/include/yeccpre.hrl) + AbsolutePathSuffix = "/lib/parsetools.*/include/yeccpre\.hrl", + + ok = yecc:compile(Filename, Parserfile, #options{specific=[deterministic]}), + {ok, FormsDet} = epp:parse_file(Parserfile,[]), + ?assertMatch(false, search_for_file_attr(AbsolutePathSuffix, FormsDet)), + ?assertMatch({value, _}, search_for_file_attr("yeccpre\.hrl", FormsDet)), + file:delete(Parserfile), + + ok = yecc:compile(Filename, Parserfile, #options{}), + {ok, Forms} = epp:parse_file(Parserfile,[]), + ?assertMatch({value, _}, search_for_file_attr(AbsolutePathSuffix, Forms)), + file:delete(Parserfile), + + file:delete(Filename), + ok. + empty(doc) -> "'$empty'."; empty(suite) -> []; @@ -1851,7 +1889,7 @@ otp_7969(Config) when is_list(Config) -> ok. otp_8919(doc) -> - "OTP-8919. Improve formating of Yecc error messages."; + "OTP-8919. Improve formatting of Yecc error messages."; otp_8919(suite) -> []; otp_8919(Config) when is_list(Config) -> A1 = erl_anno:new(1), @@ -2042,7 +2080,7 @@ otp_11286(doc) -> "OTP-11286. A Unicode filename bug; both Leex and Yecc."; otp_11286(suite) -> []; otp_11286(Config) when is_list(Config) -> - Node = start_node(otp_11286, "+fnu"), + {ok, Peer, Node} = ?CT_PEER(["+fnu"]), Dir = ?privdir, UName = [1024] ++ "u", UDir = filename:join(Dir, UName), @@ -2082,7 +2120,7 @@ otp_11286(Config) when is_list(Config) -> Opts = [return, warn_unused_vars,{outdir,Dir}], {ok,_,_} = rpc:call(Node, compile, file, [ErlFile, Opts]), - true = test_server:stop_node(Node), + peer:stop(Peer), ok. otp_14285(Config) -> @@ -2214,17 +2252,6 @@ otp_17535(Config) when is_list(Config) -> {ok, _, []} = compile:file(ErlFile, [return]), ok. -start_node(Name, Args) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), - ct:log("Trying to start ~w@~s~n", [Name,Host]), - case test_server:start_node(Name, peer, [{args,Args}]) of - {error,Reason} -> - ct:fail(Reason); - {ok,Node} -> - ct:log("Node ~p started~n", [Node]), - Node - end. - yeccpre_size() -> yeccpre_size(default_yeccpre()). @@ -2295,3 +2322,13 @@ process_list() -> safe_second_element({_,Info}) -> Info; safe_second_element(Other) -> Other. + +search_for_file_attr(PartialFilePathRegex, Forms) -> + lists:search(fun + ({attribute, _, file, {FileAttr, _}}) -> + case re:run(FileAttr, PartialFilePathRegex, [unicode]) of + nomatch -> false; + _ -> true + end; + (_) -> false end, + Forms). diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk index d68af7fd01c0..003682dd60a8 100644 --- a/lib/parsetools/vsn.mk +++ b/lib/parsetools/vsn.mk @@ -1 +1 @@ -PARSETOOLS_VSN = 2.3.2 +PARSETOOLS_VSN = 2.5 diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore index d30fe62c9d9f..bd43ec2abd35 100644 --- a/lib/public_key/.gitignore +++ b/lib/public_key/.gitignore @@ -1,7 +1,10 @@ # public_key -asn1/*.asn1db -asn1/*.erl -asn1/*.hrl +src/*.asn1db +src/OTP-PUB-KEY.erl +src/OTP-PUB-KEY.hrl +src/PKCS-FRAME.erl +src/PKCS-FRAME.hrl include/OTP-PUB-KEY.hrl include/PKCS-FRAME.hrl +priv/lib/ diff --git a/lib/public_key/Makefile b/lib/public_key/Makefile index c033d4bfcd8c..a47614036513 100644 --- a/lib/public_key/Makefile +++ b/lib/public_key/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -26,7 +26,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # ---------------------------------------------------- -SUB_DIRECTORIES = asn1 src doc/src +SUB_DIRECTORIES = asn1 src c_src doc/src include vsn.mk VSN = $(PUBLIC_KEY_VSN) diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1 index e0f4c3a011b3..926afe5b292d 100644 --- a/lib/public_key/asn1/ECPrivateKey.asn1 +++ b/lib/public_key/asn1/ECPrivateKey.asn1 @@ -19,7 +19,7 @@ ECPrivateKey ::= SEQUENCE { privateKey CurvePrivateKey, parameters [0] EcpkParameters OPTIONAL, publicKey [1] CurvePublicKey OPTIONAL, - -- Should be PKCS-8 Attributes but problem at the moment with PKCS-8 beeing part + -- Should be PKCS-8 Attributes but problem at the moment with PKCS-8 being part -- of PCKS-FRAME and PKIX1Algorithms88 is part of OTP-PUB-KEY. Procrastinate -- the solution as it mostly not used anyway attributes ANY OPTIONAL diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile index 1fef16846330..c1adf58ed49e 100644 --- a/lib/public_key/asn1/Makefile +++ b/lib/public_key/asn1/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2020. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -18,6 +18,9 @@ # %CopyrightEnd% # +EGEN = ../src +ESRC = ../src + include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -39,28 +42,26 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN) .SUFFIXES: .asn1 .PRECIOUS: %.erl +INCLUDE = ../include +EBIN = ../ebin + ASN_TOP = OTP-PUB-KEY PKCS-FRAME ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \ PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-7 PKCS-8 PKCS-10 PKCS5v2-0 OTP-PKIX \ InformationFramework RFC5639 CMSAesRsaesOaep ASN_ASNS = $(ASN_MODULES:%=%.asn1) -ASN_ERLS = $(ASN_TOP:%=%.erl) +ASN_ERLS = $(ASN_TOP:%=$(ESRC)/%.erl) ASN_HRLS = $(ASN_TOP:%=%.hrl) ASN_CONFIGS = OTP-PUB-KEY.asn1config ASN_DBS = $(ASN_MODULES:%=%.asn1db) OTP-PUB-KEY.asn1db ASN_TABLES = $(ASN_MODULES:%=%.table) -GEN_MODULES = -GEN_ERLS = $(GEN_MODULES:%=%.erl) ERL_MODULES = $(ASN_TOP) $(GEN_MODULES) TARGET_FILES= $(ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) HRL_FILES = $(ASN_HRLS:%=$(INCLUDE)/%) -INCLUDE = ../include -EBIN = ../ebin - # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -69,22 +70,26 @@ ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS) ASN_FLAGS = -bber +der +noobj +asn1config +ifeq ($(ERL_DETERMINISTIC),yes) + ASN_FLAGS += +deterministic +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) $(HRL_FILES) +$(TYPES): $(TARGET_FILES) $(HRL_FILES) clean: - -rm -f $(ASN_ERLS) $(GEN_ERLS) $(ASN_HRLS) $(HRL_FILES) $(ASN_DBS) \ + -rm -f $(ASN_ERLS) $(ASN_HRLS) $(HRL_FILES) $(ASN_DBS) \ $(ASN_TABLES) $(TARGET_FILES) *.beam *~ docs: -%.erl %.hrl: %.set.asn - $(asn_verbose)erlc $(ASN_FLAGS) $< +$(ESRC)/%.erl $(ESRC)/%.hrl: %.set.asn + $(asn_verbose)erlc $(ASN_FLAGS) -o $(ESRC) $< -$(INCLUDE)/%.hrl: %.hrl +$(INCLUDE)/%.hrl: $(ESRC)/%.hrl $(gen_verbose)cp -p $< $@ # ---------------------------------------------------- @@ -96,8 +101,10 @@ release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/include" $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include" $(INSTALL_DIR) "$(RELSYSDIR)/asn1" - $(INSTALL_DATA) $(ASN_ASNS) $(ASN_ERLS) $(ASN_HRLS) $(ASN_CONFIGS) \ - $(GEN_ERLS) "$(RELSYSDIR)/asn1" + $(INSTALL_DATA) $(ASN_ASNS) $(ASN_CONFIGS) \ + "$(RELSYSDIR)/asn1" + $(INSTALL_DIR) "$(RELSYSDIR)/src" + $(INSTALL_DATA) $(ASN_ERLS) "$(RELSYSDIR)/src" $(INSTALL_DIR) "$(RELSYSDIR)/ebin" $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin" @@ -106,7 +113,7 @@ release_docs_spec: # # Dependencies -$(EBIN)/OTP-PUB-KEY.beam: OTP-PUB-KEY.erl OTP-PUB-KEY.hrl +$(EBIN)/OTP-PUB-KEY.beam: $(ESRC)/OTP-PUB-KEY.erl $(INCLUDE)/OTP-PUB-KEY.hrl OTP-PUB-KEY.erl OTP-PUB-KEY.hrl: OTP-PUB-KEY.asn1db OTP-PUB-KEY.asn1db: PKIX1Algorithms88.asn1 \ PKIX1Explicit88.asn1 \ @@ -120,7 +127,7 @@ OTP-PUB-KEY.asn1db: PKIX1Algorithms88.asn1 \ OTP-PKIX.asn1 \ RFC5639.asn1 -$(EBIN)/PKCS-FRAME.beam: PKCS-FRAME.erl PKCS-FRAME.hrl +$(EBIN)/PKCS-FRAME.beam: $(ESRC)/PKCS-FRAME.erl $(INCLUDE)/PKCS-FRAME.hrl PKCS-FRAME.erl PKCS-FRAME.hrl: PKCS-FRAME.asn1db PKCS-FRAME.asn1db: PKCS5v2-0.asn1\ PKCS-8.asn1\ diff --git a/lib/public_key/c_src/Makefile b/lib/public_key/c_src/Makefile new file mode 100644 index 000000000000..064868af42cd --- /dev/null +++ b/lib/public_key/c_src/Makefile @@ -0,0 +1,127 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2022. 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% +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(PUBLIC_KEY_VSN) + +# ---------------------------------------------------- +# The following variables differ on different systems, we set +# reasonable defaults, if something different is needed it should +# be set for that system only. +# ---------------------------------------------------- +CC = $(DED_CC) +CFLAGS = $(DED_CFLAGS) -I./ +LD = $(DED_LD) +SHELL = /bin/sh +#LIBS = $(DED_LIBS) @LIBS@ +LIBS = $(DED_LIBS) +LDFLAGS += $(DED_LDFLAGS) + +PUBKEY_LIBNAME = public_key + +SYSINCLUDE = $(DED_SYS_INCLUDE) + +PUBKEY_INCLUDES = $(SYSINCLUDE) + +ifeq ($(TYPE),debug) +TYPEMARKER = .debug +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG @DEBUG_FLAGS@ +else +ifeq ($(TYPE),valgrind) +TYPEMARKER = .valgrind +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND +else +TYPEMARKER = +TYPE_FLAGS = $(CFLAGS) +endif +endif + +#DEFS = @DEFS@ +#CONFIG_H_DIR = @ERTS_CONFIG_H_IDIR@ + +ALL_CFLAGS = $(DEFS) $(CONFIG_H_DIR) $(TYPE_FLAGS) $(PUBKEY_INCLUDES) \ + -I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET) + +ROOTDIR = $(ERL_TOP)/lib +PRIVDIR = ../priv +LIBDIR = $(PRIVDIR)/lib/$(TARGET) +OBJDIR = $(PRIVDIR)/obj/$(TARGET) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN) + +# ---------------------------------------------------- +# Misc Macros +# ---------------------------------------------------- + +ifeq ($(TARGET),win32) +PUBKEY_LIB = $(LIBDIR)/$(PUBKEY_LIBNAME)$(TYPEMARKER).$(DED_EXT) +DIRS = $(OBJDIR) $(LIBDIR) +endif + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) + +debug opt valgrind lcnt asan: $(DIRS) $(PUBKEY_LIB) + +$(OBJDIR): + -@mkdir -p $(OBJDIR) + +$(LIBDIR): + -@mkdir -p $(LIBDIR) + +$(OBJDIR)/%$(TYPEMARKER).o: %.c + $(V_CC) -c -o $@ $(ALL_CFLAGS) $< + +$(LIBDIR)/%$(TYPEMARKER).$(DED_EXT): $(OBJDIR)/%$(TYPEMARKER).o + $(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + rm -f $(PUBKEY_LIB) + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifeq ($(TARGET),win32) +release_spec: opt + $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib" + $(INSTALL_PROGRAM) $(PUBKEY_LIB) "$(RELSYSDIR)/priv/lib" +else +release_spec: opt + +endif +release_docs_spec: diff --git a/lib/public_key/c_src/public_key.c b/lib/public_key/c_src/public_key.c new file mode 100644 index 000000000000..fb6fc2b3b364 --- /dev/null +++ b/lib/public_key/c_src/public_key.c @@ -0,0 +1,107 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2022. 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% + */ + +/* + * Purpose: CaCert fetcher + */ + +#include + +#ifdef WINVER /* Windows */ +#define WIN32_LEAN_AND_MEAN +#include +#include +#pragma comment(lib, "crypt32.lib") +#endif + +ERL_NIF_TERM ATOM_PKCS_7_ASN_ENCODING; +ERL_NIF_TERM ATOM_X509_ASN_ENCODING; +ERL_NIF_TERM ATOM_UNKNOWN; + +ERL_NIF_TERM ATOM_OPEN_ERROR; + +static ERL_NIF_TERM os_cacerts(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + ATOM_UNKNOWN = enif_make_atom(env,"unknown"); + ATOM_OPEN_ERROR = enif_make_atom(env, "internal_error"); + ATOM_PKCS_7_ASN_ENCODING = enif_make_atom(env,"pkcs_7_asn_encoding"); + ATOM_X509_ASN_ENCODING = enif_make_atom(env,"x509_asn_encoding"); + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, + ERL_NIF_TERM load_info) +{ + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ +} + +static ErlNifFunc nif_funcs[] = + { + {"os_cacerts", 0, os_cacerts, 0}, + }; + +ERL_NIF_INIT(pubkey_os_cacerts, nif_funcs, load, NULL, upgrade, unload) + + +#ifdef WINVER +ERL_NIF_TERM os_cacerts(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + HANDLE hStoreHandle = NULL; + PCCERT_CONTEXT pCertContext = NULL; + ERL_NIF_TERM head, tail, der, enc; + unsigned char * data; + + hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, + // CERT_SYSTEM_STORE_LOCAL_MACHINE, + CERT_SYSTEM_STORE_CURRENT_USER, + L"ROOT"); + if (!hStoreHandle) { + return ATOM_OPEN_ERROR; + } + + tail = enif_make_list(env, 0); + while((pCertContext = CertEnumCertificatesInStore(hStoreHandle,pCertContext))) { + switch (pCertContext->dwCertEncodingType) { + case X509_ASN_ENCODING: + enc = ATOM_X509_ASN_ENCODING; + break; + case PKCS_7_ASN_ENCODING: + enc = ATOM_PKCS_7_ASN_ENCODING; + break; + default: + enc = ATOM_UNKNOWN; + } + data = enif_make_new_binary(env, pCertContext->cbCertEncoded, &der); + memcpy(data, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded); + head = enif_make_tuple2(env, enc, der); + tail = enif_make_list_cell(env, head, tail); + } + + CertCloseStore(hStoreHandle, 0); + return tail; +} +#endif diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml index 2e81a9effd29..3f7cfbf1f3da 100644 --- a/lib/public_key/doc/src/notes.xml +++ b/lib/public_key/doc/src/notes.xml @@ -5,7 +5,7 @@

    2008 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -35,6 +35,214 @@ notes.xml
    +
    Public_Key 1.14.1 + +
    Fixed Bugs and Malfunctions + + +

    + Country name comparison shall be case insensitive

    +

    + Own Id: OTP-18718 Aux Id: GH-7546

    +
    + +

    + Add check to disallow duplicate certs in a path

    +

    + Own Id: OTP-18723 Aux Id: GH-6394

    +
    +
    +
    + +
    + +
    Public_Key 1.14 + +
    Improvements and New Features + + +

    Handling of on_load modules during boot has + been improved by adding an extra step in the boot order + for embedded mode that runs all on_load handlers, + instead of relying on explicit invocation of them, later, + when the kernel supervision tree starts.

    This is + mostly a code improvement and OTP internal simplification + to avoid future bugs and to simplify code maintenance. +

    +

    + Own Id: OTP-18447

    +
    +
    +
    + +
    + +
    Public_Key 1.13.3.1 + +
    Fixed Bugs and Malfunctions + + +

    + Country name comparison shall be case insensitive

    +

    + Own Id: OTP-18718 Aux Id: GH-7546

    +
    +
    +
    + +
    + +
    Public_Key 1.13.3 + +
    Fixed Bugs and Malfunctions + + +

    + As different solutions of verifying certificate + revocation exists move the decode of + 'CRLDistributionPoints' so that it will only be decode. + When it is actually used in the verification process. + This would enable interoperability with systems that use + certificates with an invalid empty CRLDistributionPoints + extension that they want to ignore and make verification + by other means.

    +

    + Own Id: OTP-18316 Aux Id: GH-6402, PR-6883

    +
    + +

    + public_key:pkix_path_validation validates certificates + expiring after 2050

    +

    + Own Id: OTP-18356 Aux Id: GH-6403

    +
    + +

    + Do not leave exit message in message queue after calling + cacerts_load() on MacOS.

    +

    + Own Id: OTP-18392 Aux Id: GH-6656

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Public_Key 1.13.2 + +
    Fixed Bugs and Malfunctions + + +

    + Disregard LDAP URIs when HTTP URIs are expected.

    +

    + Own Id: OTP-18333 Aux Id: GH-6363

    +
    +
    +
    + +
    + +
    Public_Key 1.13.1 + +
    Fixed Bugs and Malfunctions + + +

    + Support more Linux distributions in cacerts_load/0.

    +

    + Own Id: OTP-18154 Aux Id: PR-6002

    +
    + +

    + Correct asn1 typenames available in type pki_asn1_type()

    +

    + Own Id: OTP-18189 Aux Id: ERIERL-829

    +
    + +

    + Sign/verify does now behave as in OTP-24 and earlier for + eddsa.

    +

    + Own Id: OTP-18205 Aux Id: GH-6219

    +
    +
    +
    + +
    + +
    Public_Key 1.13 + +
    Improvements and New Features + + +

    + Added functions to retrieve OS provided CA-certs.

    +

    + Own Id: OTP-17798 Aux Id: GH-5760

    +
    + +

    + Allow key file passwords to be input as a single binary, + that is we change the data type to be the more for the + purpose logical data type iodata() instead of string().

    +

    + Own Id: OTP-17890

    +
    + +

    + The deprecated public_key functions ssh_decode/2, + ssh_encode/2, ssh_hostkey_fingerprint/1 and + ssh_hostkey_fingerprint/2 are removed.

    +

    + They are replaced by ssh_file:decode/2, + ssh_file:encode/2, ssh:hostkey_fingerprint/1 and + ssh:hostkey_fingerprint/2 respectively.

    +

    + Note that the decode/2 and encode/2 are not exact + replacement functions, some minor changes may be needed. + Se the manual for more information.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17921

    +
    +
    +
    + +
    +
    Public_Key 1.12.0.1
    Fixed Bugs and Malfunctions @@ -441,7 +649,7 @@

    - Support Pasword based encryption with AES

    + Support Password based encryption with AES

    Own Id: OTP-15870 Aux Id: ERL-952

    @@ -612,7 +820,7 @@

    - Compleate PKCS-8 encoding support and enhance the + Complete PKCS-8 encoding support and enhance the decoding of 'PrivateKeyInfo' to conform to the rest of Erlang public_key API.

    @@ -709,7 +917,7 @@ saltlength setting
    * X9.31 RSA padding.
    * sha, sha224, sha256, sha384, and sha512 for dss signatures as mentioned in NIST SP 800-57 Part 1.
    * ripemd160 to - be used for rsa signatures.

    + be used for RSA signatures.

    This is a manual merge of half of the pull request 838 by potatosalad from Sept 2015.

    @@ -720,7 +928,7 @@

    Add API function pkix_test_data/1 for facilitating automated testing. This is useful for applications that - preform X509-certifcate path validation of so called + perform X509-certifcate path validation of so called certificate chains, such as TLS.

    Own Id: OTP-14181

    @@ -904,7 +1112,7 @@

    - Add different upper bounds for diffrent string types as + Add different upper bounds for different string types as suggested by comment in PKIX1Explicit88.

    Own Id: OTP-13132

    @@ -1108,7 +1316,7 @@

    Add support for ISO oids 1.3.14.3.2.29 and 1.3.14.3.2.27 - that are somtimes used instead of the PKCS defined oids + that are sometimes used instead of the PKCS defined oids 1.2.840.113549.1.1.5 and 1.2.840.10040.4.3. Add function pkix_sign_types:/1 that translates oids to to algorithm atoms ex:

    @@ -1201,7 +1409,7 @@

    ssh_decode now handles comments, at the end of the line, - containing withe spaces correctly

    + containing with spaces correctly

    Own Id: OTP-9361

    @@ -1219,7 +1427,7 @@

    - public_key now supports PKCS-10 and includes exprimental + public_key now supports PKCS-10 and includes experimental support for PKCS-7

    Own Id: OTP-10509 Aux Id: kunagi-291 [202]

    diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 76179ceb6f61..501b7be95465 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -122,10 +122,7 @@ - -

    The tagged ed_pub format will not be returned from any public_key - functions but can be used as input, should be considered deprecated.

    @@ -145,10 +142,7 @@ - -

    The tagged ed_pri format will not be returned from any public_key - functions but can be used as input, should be considered deprecated.

    @@ -271,18 +265,47 @@ - - - - - + + - + + + Clears any loaded CA certificates. + +

    Clears any loaded CA certificates, returns true if any was loaded. +

    +
    +
    + + + Returns CA certificates. + +

    Returns the trusted CA certificates if any are loaded, otherwise + uses cacerts_load/0 to load them. + The function fails if no cacerts could be loaded.

    +
    +
    - + + + Loads OS specific CA certificates. + +

    Loads the OS supplied trusted CA certificates. +

    +
    +
    + + + + Loads CA certificates. + +

    Loads the trusted CA certificates from a file. +

    +
    +
    @@ -801,7 +824,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, critical = false}]

    Hostname is the result of calling net_adm:localhost() in the Erlang node - where this funcion is called. + where this function is called.

    @@ -952,106 +975,6 @@ end - - - Decodes an SSH file-binary. - - -

    This function is deprecated and should not be used in new programs. Use - ssh_file:decode/2 - instead. -

    -
    -

    Decodes an SSH file-binary. In the case of known_hosts or - auth_keys, the binary can include one or more lines of the - file. Returns a list of public keys and their attributes, possible - attribute values depends on the file type represented by the - binary. -

    -

    If the Type is ssh2_pubkey, the result will be - Decoded_ssh2_pubkey. Otherwise it will be Decoded_OtherType. -

    - - RFC4716 attributes - see RFC 4716. -

    {headers, [{string(), utf8_string()}]}

    - auth_key attributes - see manual page for sshd. - {comment, string()} - {options, [string()]} -

    {bits, integer()} - In SSH version 1 files.

    - known_host attributes - see manual page for sshd. - {hostnames, [string()]} - {comment, string()} -

    {bits, integer()} - In SSH version 1 files.

    -
    -

    Example: {ok, SshBin} = file:read_file("known_hosts"). -

    -

    If Type is public_key the binary can be either - an RFC4716 public key or an OpenSSH public key.

    -
    -
    - - - - Encodes a list of SSH file entries to a binary. - - -

    This function is deprecated and should not be used in new programs. Use - ssh_file:encode/2 - instead. -

    -
    -

    Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible - attributes depend on the file type, see - ssh_decode/2 . -

    -

    If the Type is ssh2_pubkey, the InData shall be - InData_ssh2_pubkey. Otherwise it shall be OtherInData. -

    -
    -
    - - - ssh_hostkey_fingerprint(HostKey) -> string() - ssh_hostkey_fingerprint(DigestType, HostKey) -> string() - ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()] - Calculates a ssh fingerprint for a hostkey. - - HostKey = public_key() - DigestType = digest_type() - - -

    Calculates a ssh fingerprint from a public host key as openssh does.

    - -

    This function is deprecated and should not be used in new programs. Use - ssh:hostkey_fingerprint/1 or - ssh:hostkey_fingerprint/2 - instead. -

    -
    -

    The algorithm in ssh_hostkey_fingerprint/1 is md5 to be compatible with older - ssh-keygen commands. The string from the second variant is prepended by the algorithm name - in uppercase as in newer ssh-keygen commands.

    -

    Examples:

    - - 2> public_key:ssh_hostkey_fingerprint(Key). - "f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84" - - 3> public_key:ssh_hostkey_fingerprint(md5,Key). - "MD5:f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84" - - 4> public_key:ssh_hostkey_fingerprint(sha,Key). - "SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY" - - 5> public_key:ssh_hostkey_fingerprint(sha256,Key). - "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ" - - 6> public_key:ssh_hostkey_fingerprint([sha,sha256],Key). - ["SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY", - "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"] - -
    -
    - diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml index b783785347d0..2a8203121d6b 100644 --- a/lib/public_key/doc/src/using_public_key.xml +++ b/lib/public_key/doc/src/using_public_key.xml @@ -4,7 +4,7 @@
    - 20112021 + 20112022 Ericsson AB. All Rights Reserved. @@ -87,7 +87,7 @@

    An RSA private key encrypted with a password can look as follows:

    1> {ok, PemBin} = file:read_file("rsa.pem"). -{ok,<<"Bag Attribut"...>>} +{ok,<<"Bag Attribute"...>>}

    The following PEM file has only one entry, a private RSA key:

    2>[RSAEntry] = public_key:pem_decode(PemBin). @@ -382,7 +382,7 @@ Msg = public_key:decrypt_public(RsaEncrypted, PublicKey), Msg = public_key:decrypt_private(RsaEncrypted, PrivateKey),

    You normally do only one of the encrypt or decrypt operations, - and the peer does the other. This normaly used in legacy applications + and the peer does the other. This normally used in legacy applications as a primitive digital signature.

    @@ -426,12 +426,12 @@ true = public_key:verify(Digest, none, Signature, PublicKey), checks that the certificate is not revoked, not forged or not out-of-date.

    There are however attacks that are not detected by those checks. Suppose a bad guy has - succeded with a DNS infection. Then the client could belive it is connecting to one host but + succeeded with a DNS infection. Then the client could believe it is connecting to one host but ends up at another but evil one. Though it is evil, it could have a perfectly legal certificate! The certificate has a valid signature, it is not revoked, the certificate chain is not faked and has a trusted root and so on.

    -

    To detect that the server is not the intended one, the client must additionaly perform +

    To detect that the server is not the intended one, the client must additionally perform a hostname verification. This procedure is described in RFC 6125. The idea is that the certificate lists the hostnames it could be fetched from. This is checked by the certificate issuer when @@ -447,13 +447,13 @@ true = public_key:verify(Digest, none, Signature, PublicKey), It is possible for a client to hook in modified rules using the options list.

    Some terminology is needed: the certificate presents hostname(s) on which it is valid. - Those are called Presented IDs. The hostname(s) the client belives it connects to + Those are called Presented IDs. The hostname(s) the client believes it connects to are called Reference IDs. The matching rules aims to verify that there is at least one of the Reference IDs that matches one of the Presented IDs. If not, the verification fails.

    The IDs contains normal fully qualified domain names like e.g foo.example.com, but IP addresses are not recommended. The rfc describes why this is not recommended as well - as security considerations about how to aquire the Reference IDs. + as security considerations about how to acquire the Reference IDs.

    Internationalized domain names are not supported.

    @@ -525,7 +525,7 @@ true = public_key:verify(Digest, none, Signature, PublicKey), field, the Subject field MUST NOT be used for host name checking, even if it contains valid CN names. Therefore only kb.example.org and https://www.example.org matches. The match fails - both for example.com and foo.example.com becuase they are in the Subject + both for example.com and foo.example.com because they are in the Subject field which is not checked because the Subject Alternate Name field is present.

    @@ -599,7 +599,7 @@ true = public_key:verify(Digest, none, Signature, PublicKey), Re-defining the match operation

    The default matching handles dns_id and uri_id. In an uri_id the value is tested for - equality with a value from the Subject Alternate Name. If som other kind of matching + equality with a value from the Subject Alternate Name. If some other kind of matching is needed, use the match_fun option.

    The match_fun takes two arguments and returns either true, @@ -626,8 +626,8 @@ true = public_key:verify(Digest, none, Signature, PublicKey), field and from the Subject Alternate Name field.

    The default matching transformes the ascii values in strings to lowercase before comparing. - The match_fun is however called without any transfomation applied to the strings. The - reason is to enable the user to do unforseen handling of the strings where the original format + The match_fun is however called without any transformation applied to the strings. The + reason is to enable the user to do unforeseen handling of the strings where the original format is needed.

    @@ -672,99 +672,4 @@ true = public_key:verify(Digest, none, Signature, PublicKey),
    -
    - SSH Files - -

    SSH typically uses PEM files for private keys but has its - own file format for storing public keys. The public_key - application can be used to parse the content of SSH public-key files.

    - -
    - RFC 4716 SSH Public-Key Files - -

    RFC 4716 SSH files looks confusingly like PEM files, - but there are some differences:

    - 1> {ok, SshBin} = file:read_file("ssh2_rsa_pub"). -{ok, <<"---- BEGIN SSH2 PUBLIC KEY ----\nAAAA"...>>} - -

    This is equivalent to calling public_key:ssh_decode(SshBin, rfc4716_public_key): -

    - 2> public_key:ssh_decode(SshBin, public_key). -[{#'RSAPublicKey'{modulus = 794430685...91663, - publicExponent = 35}, []}] - -
    - -
    - OpenSSH Public-Key Format -

    OpenSSH public-key format looks as follows:

    - 1> {ok, SshBin} = file:read_file("openssh_dsa_pub"). -{ok,<<"ssh-dss AAAAB3Nza"...>>} - -

    This is equivalent to calling public_key:ssh_decode(SshBin, openssh_public_key): -

    - 2> public_key:ssh_decode(SshBin, public_key). -[{{15642692...694280725, - #'Dss-Parms'{p = 17291273936...696123221, - q = 1255626590179665817295475654204371833735706001853, - g = 10454211196...480338645}}, - [{comment,"dhopson@VMUbuntu-DSH"}]}] -
    - -
    - Known Hosts - OpenSSH Format -

    Known hosts - OpenSSH format looks as follows:

    - 1> {ok, SshBin} = file:read_file("known_hosts"). -{ok,<<"hostname.domain.com,192.168.0.1 ssh-rsa AAAAB...>>} - -

    Returns a list of public keys and their related attributes. - Each pair of key and attribute corresponds to one entry in - the known hosts file:

    - - 2> public_key:ssh_decode(SshBin, known_hosts). -[{#'RSAPublicKey'{modulus = 1498979460408...72721699, - publicExponent = 35}, - [{hostnames,["hostname.domain.com","192.168.0.1"]}]}, - {#'RSAPublicKey'{modulus = 14989794604088...2721699, - publicExponent = 35}, - [{comment,"foo@bar.com"}, - {hostnames,["|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA="]}]}] -
    - -
    - Authorized Keys - OpenSSH Format -

    Authorized keys - OpenSSH format looks as follows:

    - - 1> {ok, SshBin} = file:read_file("auth_keys"). -{ok, <<"command=\"dump /home\",no-pty,no-port-forwarding ssh-rsa AAA...>>} - -

    Returns a list of public keys and their related attributes. - Each pair of key and attribute corresponds to one entry in - the authorized key file:

    - - 2> public_key:ssh_decode(SshBin, auth_keys). -[{#'RSAPublicKey'{modulus = 794430685...691663, - publicExponent = 35}, - [{comment,"dhopson@VMUbuntu-DSH"}, - {options,["command=\"dump/home\"","no-pty", - "no-port-forwarding"]}]}, - {{1564269258491...607694280725, - #'Dss-Parms'{p = 17291273936185...763696123221, - q = 1255626590179665817295475654204371833735706001853, - g = 10454211195705...60511039590076780999046480338645}}, - [{comment,"dhopson@VMUbuntu-DSH"}]}] -
    - -
    - Creating an SSH File from Public-Key Data - -

    If you got a public key PubKey and a related list of - attributes Attributes as returned - by ssh_decode/2, you can create a new SSH file, for example:

    - N> SshBin = public_key:ssh_encode([{PubKey, Attributes}], openssh_public_key), -<<"ssh-rsa "...>> -N+1> file:write_file("id_rsa.pub", SshBin). -ok -
    -
    diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile index e27f02eea95e..9b2b4427946f 100644 --- a/lib/public_key/src/Makefile +++ b/lib/public_key/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -47,7 +47,8 @@ MODULES = \ pubkey_cert \ pubkey_cert_records \ pubkey_crl\ - pubkey_ocsp + pubkey_ocsp \ + pubkey_os_cacerts HRL_FILES = $(INCLUDE)/public_key.hrl @@ -85,7 +86,7 @@ ERL_COMPILE_FLAGS += $(PUB_KEY_ERL_FLAGS) \ # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(HRL_FILES) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(HRL_FILES) $(EBIN)/pubkey_ssh.$(EMULATOR): pubkey_moduli.hrl diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index abe69d9ae2c2..be9a5969069b 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -72,7 +72,7 @@ verify_data(DerCert) -> -spec init_validation_state(#'OTPCertificate'{}, integer(), list()) -> #path_validation_state{}. %% -%% Description: Creates inital version of path_validation_state for +%% Description: Creates initial version of path_validation_state for %% basic path validation of x509 certificates. %%-------------------------------------------------------------------- init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen, @@ -134,7 +134,7 @@ prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{ }. %%-------------------------------------------------------------------- --spec validate_time(#'OTPCertificate'{}, term(), fun()) -> term(). +-spec validate_time(#'OTPCertificate'{}, term(), fun()) -> term() | no_return(). %% %% Description: Check that the certificate validity period includes the %% current time. @@ -144,8 +144,8 @@ validate_time(OtpCert, UserState, VerifyFun) -> {'Validity', NotBeforeStr, NotAfterStr} = TBSCert#'OTPTBSCertificate'.validity, Now = calendar:datetime_to_gregorian_seconds(calendar:universal_time()), - NotBefore = time_str_2_gregorian_sec(NotBeforeStr), - NotAfter = time_str_2_gregorian_sec(NotAfterStr), + NotBefore = time_str_2_gregorian_sec(notBefore, NotBeforeStr), + NotAfter = time_str_2_gregorian_sec(notAfter, NotAfterStr), case ((NotBefore =< Now) and (Now =< NotAfter)) of true -> @@ -154,7 +154,7 @@ validate_time(OtpCert, UserState, VerifyFun) -> verify_fun(OtpCert, {bad_cert, cert_expired}, UserState, VerifyFun) end. %%-------------------------------------------------------------------- --spec validate_issuer(#'OTPCertificate'{}, term(), term(), fun()) -> term(). +-spec validate_issuer(#'OTPCertificate'{}, term(), term(), fun()) -> term() | no_return(). %% %% Description: Check that the certificate issuer name is the working_issuer_name %% in path_validation_state. @@ -169,7 +169,7 @@ validate_issuer(OtpCert, Issuer, UserState, VerifyFun) -> end. %%-------------------------------------------------------------------- -spec validate_signature(#'OTPCertificate'{}, DER::binary(), - term(),term(), term(), fun()) -> term(). + term(),term(), term(), fun()) -> term() | no_return(). %% %% Description: Check that the signature on the certificate can be verified using @@ -187,7 +187,7 @@ validate_signature(OtpCert, DerCert, Key, KeyParams, end. %%-------------------------------------------------------------------- -spec validate_names(#'OTPCertificate'{}, no_constraints | list(), list(), - term(), term(), fun())-> term(). + term(), term(), fun())-> term() | no_return(). %% %% Description: Validate Subject Alternative Name. %%-------------------------------------------------------------------- @@ -247,7 +247,7 @@ validate_extensions(OtpCert, ValidationState, UserState, VerifyFun) -> -spec normalize_general_name({rdnSequence, term()}| binary()) -> {rdnSequence, term()}. %% %% Description: Normalizes a general name so that it can be easily -%% compared to another genral name. +%% compared to another general name. %%-------------------------------------------------------------------- normalize_general_name({rdnSequence, Issuer}) -> NormIssuer = do_normalize_general_name(Issuer), @@ -333,7 +333,7 @@ is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate = %%-------------------------------------------------------------------- -spec verify_fun(#'OTPCertificate'{}, {bad_cert, atom()} | {extension, #'Extension'{}}| - valid | valid_peer, term(), fun()) -> term(). + valid | valid_peer, term(), fun()) -> term() | no_return(). %% %% Description: Gives the user application the opportunity handle path %% validation errors and unknown extensions and optional do other @@ -370,6 +370,9 @@ select_extension(_, asn1_NOVALUE) -> undefined; select_extension(_, []) -> undefined; +select_extension(Id, [#'Extension'{extnID = ?'id-ce-cRLDistributionPoints' = Id, + extnValue = Value} = Extension | _]) when is_binary(Value) -> + Extension#'Extension'{extnValue = public_key:der_decode('CRLDistributionPoints', Value)}; select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) -> Extension; select_extension(Id, [_ | Extensions]) -> @@ -408,9 +411,8 @@ match_name(emailAddress, Name, [PermittedName | Rest]) -> match_name(dNSName, Name, [PermittedName | Rest]) -> Fun = fun(Domain, [$.|Domain]) -> true; (Name1,Name2) -> - lists:suffix(string:to_lower(Name2), - string:to_lower(Name1)) - end, + is_suffix(Name2, Name1) + end, match_name(Fun, Name, [$.|PermittedName], Rest); match_name(x400Address, OrAddress, [PermittedAddr | Rest]) -> @@ -558,11 +560,11 @@ root_cert(Name, Opts) -> %%-------------------------------------------------------------------- do_normalize_general_name(Issuer) -> Normalize = fun([{Description, Type, {printableString, Value}}]) -> - NewValue = string:to_lower(strip_spaces(Value)), - [{Description, Type, {printableString, NewValue}}]; - (Atter) -> - Atter - end, + NewValue = string:casefold(strip_spaces(Value, false)), + [{Description, Type, {printableString, NewValue}}]; + (Atter) -> + Atter + end, lists:map(Normalize, Issuer). %% See rfc3280 4.1.2.6 Subject: regarding emails. @@ -633,19 +635,44 @@ public_key_info(PublicKeyInfo, end, {Algorithm, PublicKey, NewPublicKeyParams}. -time_str_2_gregorian_sec({utcTime, [Y1,Y2,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,Z]}) -> - case list_to_integer([Y1,Y2]) of - N when N >= 50 -> - time_str_2_gregorian_sec({generalTime, - [$1,$9,Y1,Y2,M1,M2,D1,D2, - H1,H2,M3,M4,S1,S2,Z]}); - _ -> - time_str_2_gregorian_sec({generalTime, - [$2,$0,Y1,Y2,M1,M2,D1,D2, - H1,H2,M3,M4,S1,S2,Z]}) - end; - -time_str_2_gregorian_sec({_,[Y1,Y2,Y3,Y4,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,$Z]}) -> +%% time_str_2_gregorian_sec/2 is a wrapper (decorator pattern) over +%% time_str_2_gregorian_sec/1. the decorator deals with notBefore and notAfter +%% property differently when we pass utcTime because the data format is +%% ambiguous YYMMDD. on generalTime the year ambiguity cannot happen because +%% years are expressed in a 4-digit format, i.e., YYYYMMDD. +-spec time_str_2_gregorian_sec(PeriodOfTime, Time) -> Seconds :: non_neg_integer() when + PeriodOfTime :: notBefore | notAfter, + Time :: {utcTime | generalTime, [non_neg_integer() | char()]}. +time_str_2_gregorian_sec(notBefore, {utcTime, [FirstDigitYear | _]=UtcTime}) -> + %% To be compliant with PKITS Certification Path Validation, + %% we must accept certificates with notBefore = 50, meaning 1950. + %% Once the PKITS certification path validation is updated, + %% we must update this function body and test case + %% {"4.2.3", "Valid pre2000 UTC notBefore Date Test3 EE"} + %% in pkits_SUITE.erl + Y1 = erlang:list_to_integer([FirstDigitYear]), + YearPrefix = case (Y1 > 4 andalso Y1 =< 9) of + true -> [$1, $9]; + false -> + {Y, _M, _D} = erlang:date(), + integer_to_list(Y div 100) + end, + time_str_2_gregorian_sec({generalTime, YearPrefix ++ UtcTime}); + +time_str_2_gregorian_sec(notAfter, {utcTime, UtcTime}) -> + SlidingDate = sliding_year_window(UtcTime), + time_str_2_gregorian_sec({generalTime, SlidingDate}); + +time_str_2_gregorian_sec(_, {generalTime, _Time}=GeneralTime) -> + time_str_2_gregorian_sec(GeneralTime). + +%% converts 'Time' as a string into gregorian time in seconds. +-spec time_str_2_gregorian_sec(Time) -> Seconds :: non_neg_integer() when + Time :: {generalTime | utcTime, string()}. +time_str_2_gregorian_sec({utcTime, UtcTime}) -> + time_str_2_gregorian_sec(notAfter, {utcTime, UtcTime}); + +time_str_2_gregorian_sec({generalTime,[Y1,Y2,Y3,Y4,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,$Z]}) -> Year = list_to_integer([Y1, Y2, Y3, Y4]), Month = list_to_integer([M1, M2]), Day = list_to_integer([D1, D2]), @@ -655,6 +682,28 @@ time_str_2_gregorian_sec({_,[Y1,Y2,Y3,Y4,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,$Z]}) -> calendar:datetime_to_gregorian_seconds({{Year, Month, Day}, {Hour, Min, Sec}}). +%% Sliding window algorithm to calculate the time. +%% The value is set as taking {Y1, Y2} from the first two digits of +%% current_date - 50 or current_date - 49. +sliding_year_window([Y1,Y2,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,Z]) -> + {{CurrentYear,_, _}, _} = calendar:universal_time(), + LastTwoDigitYear = CurrentYear rem 100, + MinYear = mod(LastTwoDigitYear - 50, 100), + YearWindow = case list_to_integer([Y1,Y2]) of + N when N < MinYear -> CurrentYear + 50; + N when N >= MinYear -> CurrentYear - 49 + end, + [Year1, Year2] = integer_to_list(YearWindow div 100), + [Year1,Year2,Y1,Y2,M1,M2,D1,D2,H1,H2,M3,M4,S1,S2,Z]. + + +%% Helper function to perform modulo calculation for integer +-spec mod(A :: integer(), B :: non_neg_integer()) -> non_neg_integer(). +mod(A, B) when A > 0 -> A rem B; +mod(A, B) when A < 0 -> mod(A+B, B); +mod(0, _) -> 0. + + is_dir_name([], [], _Exact) -> true; is_dir_name([H|R1],[H|R2], Exact) -> is_dir_name(R1,R2, Exact); is_dir_name([[{'AttributeTypeAndValue', Type, What1}]|Rest1], @@ -668,14 +717,28 @@ is_dir_name(_,[],false) -> is_dir_name(_,_,_) -> false. -is_dir_name2(Value, Value) -> true; -is_dir_name2({printableString, Value1}, {printableString, Value2}) -> - string:to_lower(strip_spaces(Value1)) =:= - string:to_lower(strip_spaces(Value2)); -is_dir_name2({utf8String, Value1}, String) -> - is_dir_name2({printableString, unicode:characters_to_list(Value1)}, String); -is_dir_name2(String, {utf8String, Value1}) -> - is_dir_name2(String, {printableString, unicode:characters_to_list(Value1)}); +%% attribute values in types other than PrintableString are case +%% sensitive (this permits matching of attribute values as binary +%% objects); that is term comparison will compare. Rules origninate +%% from RFC 3280 section 4.1.24. However fallback to case insensite +%% matching also for utf8 strings, as this is done by the +%% pkits_suite interop suite +is_dir_name2(Str, Str) -> + true; +is_dir_name2({T1, Str1}, Str2) + when T1 == printableString; T1 == utf8String -> + is_dir_name2(Str1, Str2); +is_dir_name2(Str1, {T2, Str2}) + when T2 == printableString; T2 == utf8String -> + is_dir_name2(Str1, Str2); +is_dir_name2(Str1, Str2) + when (is_list(Str1) orelse is_binary(Str1)) andalso + (is_list(Str2) orelse is_binary(Str2)) -> + %%attribute values in PrintableString are compared after + %%removing leading and trailing white space and converting internal + %%substrings of one or more consecutive white space characters to a + %%single space. They are case insensetive. + string:equal(strip_spaces(Str1, true), strip_spaces(Str2, true), true); is_dir_name2(_, _) -> false. @@ -693,13 +756,19 @@ decode_general_name([{directoryName, Issuer}]) -> decode_general_name([{_, Issuer}]) -> Issuer. -%% Strip all leading and trailing spaces and make -%% sure there is no double spaces in between. -strip_spaces(String) -> - NewString = - lists:foldl(fun(Char, Acc) -> Acc ++ Char ++ " " end, [], - string:tokens(String, " ")), - string:strip(NewString). +strip_spaces(String0, KeepDeep) -> + Trimmed = string:trim(String0), + strip_many_spaces(string:split(Trimmed, " ", all), KeepDeep). + +strip_many_spaces([OnlySingleSpace], _) -> + OnlySingleSpace; +strip_many_spaces(Strings, KeepDeep) -> + Split = [string:trim(Str, leading, " ") || Str <- Strings, Str /= []], + DeepList = lists:join(" ", Split), + case KeepDeep of + true -> DeepList; + false -> unicode:characters_to_list(DeepList) + end. %% No extensions present validate_extensions(OtpCert, asn1_NOVALUE, ValidationState, ExistBasicCon, @@ -1027,6 +1096,8 @@ is_permitted_ip([CandidatIp | CandidatIpRest], mask_cmp(Canditate, Permitted, Mask) -> (Canditate band Mask) == Permitted. +is_valid_host_or_domain([], _) -> + false; %% Can happen if URI was not a HTTP URI is_valid_host_or_domain(Canditate, [$.|_] = Permitted) -> is_suffix(Permitted, Canditate); is_valid_host_or_domain(Canditate, Permitted) -> @@ -1047,9 +1118,9 @@ is_valid_email_address(Canditate, Permitted, [_, _]) -> case_insensitive_match(Canditate, Permitted). is_suffix(Suffix, Str) -> - lists:suffix(string:to_lower(Suffix), string:to_lower(Str)). + lists:suffix(string:casefold(Suffix), string:casefold(Str)). case_insensitive_match(Str1, Str2) -> - string:to_lower(Str1) == string:to_lower(Str2). + string:equal(Str1, Str2, true). is_or_address(Address, Canditate) -> %% TODO: Is case_insensitive_match sufficient? @@ -1301,7 +1372,7 @@ cert_chain(Role, IssuerCert, IssuerKey, [PeerOpts], _, Acc) -> cert_chain(Role, IssuerCert, IssuerKey, [CAOpts | Rest], N, Acc) -> Key = gen_key(proplists:get_value(key, CAOpts, default_key_gen())), Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "webadmin", - " Intermidiate CA " ++ integer_to_list(N), CAOpts, ca), + " Intermediate CA " ++ integer_to_list(N), CAOpts, ca), cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, encode_key(IssuerKey)} | Acc]). cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer}}, diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl index 592bd4c9381d..0bcbe84f87e3 100644 --- a/lib/public_key/src/pubkey_cert_records.erl +++ b/lib/public_key/src/pubkey_cert_records.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -44,7 +44,7 @@ decode_cert(DerCert) -> %%-------------------------------------------------------------------- -spec transform(term(), encode | decode) ->term(). %% -%% Description: Transforms between encoded and decode otp formated +%% Description: Transforms between encoded and decode otp formatted %% certificate parts. %%-------------------------------------------------------------------- @@ -262,21 +262,20 @@ extension_id(?'id-ce-keyUsage') -> 'KeyUsage'; extension_id(?'id-ce-privateKeyUsagePeriod') -> 'PrivateKeyUsagePeriod'; extension_id(?'id-ce-certificatePolicies') -> 'CertificatePolicies'; extension_id(?'id-ce-policyMappings') -> 'PolicyMappings'; -extension_id(?'id-ce-subjectAltName') -> 'SubjectAltName'; -extension_id(?'id-ce-issuerAltName') -> 'IssuerAltName'; +extension_id(?'id-ce-subjectAltName') -> 'SubjectAltName'; +extension_id(?'id-ce-issuerAltName') -> 'IssuerAltName'; extension_id(?'id-ce-subjectDirectoryAttributes') -> 'SubjectDirectoryAttributes'; -extension_id(?'id-ce-basicConstraints' ) -> 'BasicConstraints'; -extension_id(?'id-ce-nameConstraints') -> 'NameConstraints'; -extension_id(?'id-ce-policyConstraints') -> 'PolicyConstraints'; -extension_id(?'id-ce-cRLDistributionPoints') -> 'CRLDistributionPoints'; -extension_id(?'id-ce-extKeyUsage') -> 'ExtKeyUsageSyntax'; -extension_id(?'id-ce-inhibitAnyPolicy') -> 'InhibitAnyPolicy'; +extension_id(?'id-ce-basicConstraints' ) -> 'BasicConstraints'; +extension_id(?'id-ce-nameConstraints') -> 'NameConstraints'; +extension_id(?'id-ce-policyConstraints') -> 'PolicyConstraints'; +extension_id(?'id-ce-extKeyUsage') -> 'ExtKeyUsageSyntax'; +extension_id(?'id-ce-inhibitAnyPolicy') -> 'InhibitAnyPolicy'; extension_id(?'id-ce-freshestCRL') -> 'FreshestCRL'; -%% Missing in public_key doc +extension_id(?'id-ce-issuingDistributionPoint') -> 'IssuingDistributionPoint'; +%% Missing in public_key doc extension_id(?'id-pe-authorityInfoAccess') -> 'AuthorityInfoAccessSyntax'; extension_id(?'id-pe-subjectInfoAccess') -> 'SubjectInfoAccessSyntax'; extension_id(?'id-ce-cRLNumber') -> 'CRLNumber'; -extension_id(?'id-ce-issuingDistributionPoint') -> 'IssuingDistributionPoint'; extension_id(?'id-ce-deltaCRLIndicator') -> 'BaseCRLNumber'; extension_id(?'id-ce-cRLReasons') -> 'CRLReason'; extension_id(?'id-ce-certificateIssuer') -> 'CertificateIssuer'; diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl index 71154248636b..5bbc34ba535e 100644 --- a/lib/public_key/src/pubkey_crl.erl +++ b/lib/public_key/src/pubkey_crl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2020. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -298,7 +298,7 @@ is_all_reasons(Mask, AllReasonsFun) -> %% As the "uspecified" reason should not %% be explicitly used according to RFC 3280 %% and the conformance tests have test cases - %% that should succed, and that does not specify + %% that should succeed, and that does not specify %% "unspecified", we tolorate that it is not included. sets:is_subset(sets:del_element(unspecified, AllReasons), Mask) end. diff --git a/lib/public_key/src/pubkey_ocsp.erl b/lib/public_key/src/pubkey_ocsp.erl index 249b4306605c..6bdb9a563f8b 100644 --- a/lib/public_key/src/pubkey_ocsp.erl +++ b/lib/public_key/src/pubkey_ocsp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -19,18 +19,55 @@ %% -module(pubkey_ocsp). - -include("public_key.hrl"). --export([otp_cert/1, - get_ocsp_responder_id/1, +-export([find_single_response/3, + get_acceptable_response_types_extn/0, get_nonce_extn/1, - decode_ocsp_response/1, + get_ocsp_responder_id/1, + ocsp_status/1, verify_ocsp_response/3, - get_acceptable_response_types_extn/0, - find_single_response/3, - ocsp_status/1]). + decode_ocsp_response/1]). +%% Tracing +-export([handle_trace/3]). + +-spec get_ocsp_responder_id(#'Certificate'{}) -> binary(). +get_ocsp_responder_id(#'Certificate'{tbsCertificate = TbsCert}) -> + public_key:der_encode( + 'ResponderID', {byName, TbsCert#'TBSCertificate'.subject}). + +-spec get_nonce_extn(undefined | binary()) -> undefined | #'Extension'{}. +get_nonce_extn(undefined) -> + undefined; +get_nonce_extn(Nonce) when is_binary(Nonce) -> + #'Extension'{ + extnID = ?'id-pkix-ocsp-nonce', + extnValue = Nonce + }. + +-spec verify_ocsp_response(#'BasicOCSPResponse'{}, list(), undefined | binary()) -> + {ok, term()} | {error, term()}. +verify_ocsp_response(OCSPResponse, ResponderCerts, Nonce) -> + do_verify_ocsp_response(OCSPResponse, ResponderCerts, Nonce). + +-spec get_acceptable_response_types_extn() -> #'Extension'{}. +get_acceptable_response_types_extn() -> + #'Extension'{ + extnID = ?'id-pkix-ocsp-response', + extnValue = public_key:der_encode( + 'AcceptableResponses', [?'id-pkix-ocsp-basic']) + }. + +-spec find_single_response(#'OTPCertificate'{}, #'OTPCertificate'{}, + [#'SingleResponse'{}]) -> + {ok, #'SingleResponse'{}} | {error, no_matched_response}. +find_single_response(Cert, IssuerCert, SingleResponseList) -> + IssuerName = get_subject_name(IssuerCert), + IssuerKey = get_public_key(IssuerCert), + SerialNum = get_serial_num(Cert), + match_single_response(IssuerName, IssuerKey, SerialNum, SingleResponseList). +-spec ocsp_status({atom(), term()}) -> atom() | {atom(), {atom(), term()}}. ocsp_status({good, _}) -> valid; ocsp_status({unknown, Reason}) -> @@ -38,61 +75,64 @@ ocsp_status({unknown, Reason}) -> ocsp_status({revoked, Reason}) -> {bad_cert, {revoked, Reason}}. -%%-------------------------------------------------------------------- --spec verify_ocsp_response(binary(), list(), undefined | binary()) -> - {ok, term()} | {error, term()}. -%% -%% Description: Verify the OCSP response to get the certificate status -%%-------------------------------------------------------------------- -verify_ocsp_response(OCSPResponseDer, ResponderCerts, Nonce) -> - do_verify_ocsp_response( - decode_ocsp_response(OCSPResponseDer), ResponderCerts, Nonce - ). +decode_ocsp_response(ResponseDer) -> + Resp = public_key:der_decode('OCSPResponse', ResponseDer), + case Resp#'OCSPResponse'.responseStatus of + successful -> + decode_response_bytes( + Resp#'OCSPResponse'.responseBytes + ); + Error -> + {error, Error} + end. %%-------------------------------------------------------------------- --spec do_verify_ocsp_response({ok, #'BasicOCSPResponse'{}} | {error, term()}, - list(), undefined | binary()) -> - {ok, term()} | {error, term()}. -%% -%% Description: Verify the OCSP response to get the certificate status -%%-------------------------------------------------------------------- -do_verify_ocsp_response( - {ok, #'BasicOCSPResponse'{ - tbsResponseData = ResponseData, - signatureAlgorithm = SignatureAlgo, - signature = Signature, - certs = Certs - }}, ResponderCerts, Nonce) -> +match_single_response(_IssuerName, _IssuerKey, _SerialNum, []) -> + {error, no_matched_response}; +match_single_response(IssuerName, IssuerKey, SerialNum, + [#'SingleResponse'{ + certID = #'CertID'{hashAlgorithm = Algo} = CertID} = + Response | Responses]) -> + HashType = public_key:pkix_hash_type(Algo#'AlgorithmIdentifier'.algorithm), + case (SerialNum == CertID#'CertID'.serialNumber) andalso + (crypto:hash(HashType, IssuerName) == CertID#'CertID'.issuerNameHash) andalso + (crypto:hash(HashType, IssuerKey) == CertID#'CertID'.issuerKeyHash) of + true -> + {ok, Response}; + false -> + match_single_response(IssuerName, IssuerKey, SerialNum, Responses) + end. - #'ResponseData'{ - responderID = ResponderID - } = ResponseData, +get_serial_num(#'OTPCertificate'{tbsCertificate = TbsCert}) -> + TbsCert#'OTPTBSCertificate'.serialNumber. +decode_response_bytes(#'ResponseBytes'{ + responseType = ?'id-pkix-ocsp-basic', + response = Data}) -> + {ok, public_key:der_decode('BasicOCSPResponse', Data)}; +decode_response_bytes(#'ResponseBytes'{responseType = RespType}) -> + {error, {ocsp_response_type_not_supported, RespType}}. + +do_verify_ocsp_response(#'BasicOCSPResponse'{ + tbsResponseData = ResponseData, + signatureAlgorithm = SignatureAlgo, + signature = Signature}, + ResponderCerts, Nonce) -> + #'ResponseData'{responderID = ResponderID} = ResponseData, case verify_ocsp_signature( - public_key:der_encode('ResponseData', ResponseData), - SignatureAlgo#'AlgorithmIdentifier'.algorithm, - Signature, Certs ++ ResponderCerts, - ResponderID) of + public_key:der_encode('ResponseData', ResponseData), + SignatureAlgo#'AlgorithmIdentifier'.algorithm, + Signature, ResponderCerts, + ResponderID) of ok -> verify_ocsp_nonce(ResponseData, Nonce); {error, Reason} -> {error, Reason} - end; -do_verify_ocsp_response({error, Reason}, _ResponderCerts, _Nonce) -> - {error, Reason}. + end. -%%-------------------------------------------------------------------- --spec verify_ocsp_nonce(#'ResponseData'{}, undefined | binary()) -> - {ok, term()} | {error, nonce_mismatch}. -%% -%% Description: Check if the nonces matches in OCSP response -%%-------------------------------------------------------------------- verify_ocsp_nonce(ResponseData, Nonce) -> - #'ResponseData'{ - responses = Responses, - responseExtensions = ResponseExtns - } = ResponseData, - + #'ResponseData'{responses = Responses, responseExtensions = ResponseExtns} = + ResponseData, case get_nonce_value(ResponseExtns) of Nonce -> {ok, Responses}; @@ -100,12 +140,6 @@ verify_ocsp_nonce(ResponseData, Nonce) -> {error, nonce_mismatch} end. -%%-------------------------------------------------------------------- --spec get_nonce_value(asn1_NOVALUE | list()) -> - undefined | binary(). -%% -%% Description: Get the nonce value from extensions -%%-------------------------------------------------------------------- %% no extensions present in response get_nonce_value(asn1_NOVALUE) -> undefined; @@ -119,44 +153,8 @@ get_nonce_value([#'Extension'{ get_nonce_value([_Extn | Rest]) -> get_nonce_value(Rest). -%%-------------------------------------------------------------------- --spec decode_ocsp_response(binary()) -> - {ok, #'BasicOCSPResponse'{}} | {error, term()}. -%% -%% Description: Decode the OCSP response der -%%-------------------------------------------------------------------- -decode_ocsp_response(Response) -> - Resp = public_key:der_decode('OCSPResponse', Response), - case Resp#'OCSPResponse'.responseStatus of - successful -> - decode_response_bytes( - Resp#'OCSPResponse'.responseBytes - ); - Error -> - {error, Error} - end. - -%%-------------------------------------------------------------------- --spec decode_response_bytes(#'ResponseBytes'{}) -> - {ok, #'BasicOCSPResponse'{}} | {error, term()}. -%% -%% Description: Get basic ocsp response field -%%-------------------------------------------------------------------- -decode_response_bytes(#'ResponseBytes'{ - responseType = ?'id-pkix-ocsp-basic', - response = Data}) -> - {ok, public_key:der_decode('BasicOCSPResponse', Data)}; -decode_response_bytes(#'ResponseBytes'{responseType = RespType}) -> - {error, {ocsp_response_type_not_supported, RespType}}. - -%%-------------------------------------------------------------------- --spec verify_ocsp_signature(binary(), term(), term(), list(), term()) -> - ok | {error, term()}. -%% -%% Description: Verify the signature of OCSP response -%%-------------------------------------------------------------------- -verify_ocsp_signature( - ResponseDataDer, SignatureAlgo, Signature, Certs, ResponderID) -> +verify_ocsp_signature(ResponseDataDer, SignatureAlgo, Signature, + Certs, ResponderID) -> case find_responder_cert(ResponderID, Certs) of {ok, Cert} -> do_verify_ocsp_signature( @@ -165,12 +163,6 @@ verify_ocsp_signature( {error, Reason} end. -%%-------------------------------------------------------------------- --spec find_responder_cert(term(), list()) -> - {ok, #'Certificate'{} | #'OTPCertificate'{}} | {error, term()}. -%% -%% Description: Find the OCSP responder's cert in input list -%%-------------------------------------------------------------------- find_responder_cert(_ResponderID, []) -> {error, ocsp_responder_cert_not_found}; find_responder_cert(ResponderID, [Cert | TCerts]) -> @@ -181,87 +173,29 @@ find_responder_cert(ResponderID, [Cert | TCerts]) -> find_responder_cert(ResponderID, TCerts) end. -%%-------------------------------------------------------------------- --spec do_verify_ocsp_signature( - binary(), term(), term(), #'Certificate'{} | #'OTPCertificate'{}) -> - ok | {error, term()}. -%% -%% Description: Verify the signature of OCSP response -%%-------------------------------------------------------------------- do_verify_ocsp_signature(ResponseDataDer, Signature, AlgorithmID, Cert) -> {DigestType, _SignatureType} = public_key:pkix_sign_types(AlgorithmID), case public_key:verify( - ResponseDataDer, DigestType, Signature, - get_public_key_rec(Cert)) of + ResponseDataDer, DigestType, Signature, + get_public_key_rec(Cert)) of true -> ok; false -> {error, ocsp_response_bad_signature} end. -%%-------------------------------------------------------------------- --spec get_public_key_rec(#'Certificate'{} | #'OTPCertificate'{}) -> - term(). -%% -%% Description: Get the subject public key field -%%-------------------------------------------------------------------- -get_public_key_rec(#'Certificate'{} = Cert) -> - get_public_key_rec(otp_cert(Cert)); get_public_key_rec(#'OTPCertificate'{tbsCertificate = TbsCert}) -> PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo, PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey. -%%-------------------------------------------------------------------- --spec is_responder(tuple(), #'Certificate'{} | #'OTPCertificate'{}) -> - boolean(). -%% -%% Description: Check if is OCSP responder's cert -%%-------------------------------------------------------------------- is_responder({byName, Name}, Cert) -> public_key:der_encode('Name', Name) == get_subject_name(Cert); is_responder({byKey, Key}, Cert) -> Key == crypto:hash(sha, get_public_key(Cert)). -%%-------------------------------------------------------------------- --spec otp_cert(#'Certificate'{} | #'OTPCertificate'{} | binary()) -> - #'OTPCertificate'{}. -%% -%% Description: Convert to #'OTPCertificate'{} -%%-------------------------------------------------------------------- -otp_cert(#'OTPCertificate'{} = Cert) -> - Cert; -otp_cert(#'Certificate'{} = Cert) -> - public_key:pkix_decode_cert( - public_key:der_encode('Certificate', Cert), otp); -otp_cert(CertDer) when is_binary(CertDer) -> - public_key:pkix_decode_cert(CertDer, otp). - -%%-------------------------------------------------------------------- --spec get_ocsp_responder_id(#'Certificate'{}) -> binary(). -%% -%% Description: Get the OCSP responder ID der -%%-------------------------------------------------------------------- -get_ocsp_responder_id(#'Certificate'{tbsCertificate = TbsCert}) -> - public_key:der_encode( - 'ResponderID', {byName, TbsCert#'TBSCertificate'.subject}). - -%%-------------------------------------------------------------------- --spec get_subject_name(#'Certificate'{} | #'OTPCertificate'{}) -> binary(). -%% -%% Description: Get the subject der from cert -%%-------------------------------------------------------------------- -get_subject_name(#'Certificate'{} = Cert) -> - get_subject_name(otp_cert(Cert)); get_subject_name(#'OTPCertificate'{tbsCertificate = TbsCert}) -> public_key:pkix_encode('Name', TbsCert#'OTPTBSCertificate'.subject, otp). -%%-------------------------------------------------------------------- --spec get_public_key(#'Certificate'{} | #'OTPCertificate'{}) -> binary(). -%% -%% Description: Get the public key from cert -%%-------------------------------------------------------------------- -get_public_key(#'Certificate'{} = Cert) -> - get_public_key(otp_cert(Cert)); get_public_key(#'OTPCertificate'{tbsCertificate = TbsCert}) -> PKInfo = TbsCert#'OTPTBSCertificate'.subjectPublicKeyInfo, enc_pub_key(PKInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey). @@ -273,73 +207,35 @@ enc_pub_key({DsaInt, #'Dss-Parms'{}}) when is_integer(DsaInt) -> enc_pub_key({#'ECPoint'{point = Key}, _ECParam}) -> Key. -%%-------------------------------------------------------------------- --spec get_nonce_extn(undefined | binary()) -> undefined | #'Extension'{}. -%% -%% Description: Get an OCSP nonce der -%%-------------------------------------------------------------------- -get_nonce_extn(undefined) -> - undefined; -get_nonce_extn(Nonce) when is_binary(Nonce) -> - #'Extension'{ - extnID = ?'id-pkix-ocsp-nonce', - extnValue = Nonce - }. - -%%-------------------------------------------------------------------- --spec get_acceptable_response_types_extn() -> #'Extension'{}. -%% -%% Description: Get an acceptable response types der -%%-------------------------------------------------------------------- -get_acceptable_response_types_extn() -> - #'Extension'{ - extnID = ?'id-pkix-ocsp-response', - extnValue = public_key:der_encode( - 'AcceptableResponses', [?'id-pkix-ocsp-basic']) - }. - -%%-------------------------------------------------------------------- --spec get_serial_num(binary | #'Certificate'{} | #'OTPCertificate'{}) -> - term(). -%% -%% Description: Get the serial number of a certificate -%%-------------------------------------------------------------------- -get_serial_num(Cert) -> - #'OTPCertificate'{tbsCertificate = TbsCert} = otp_cert(Cert), - TbsCert#'OTPTBSCertificate'.serialNumber. - - -%%-------------------------------------------------------------------- -%% -spec find_single_response(#'OTPCertificate'{}, #'OTPCertificate'{}, -%% [#'SingleResponse'{}]) -> -%% #'SingleResponse'{} | {error, no_matched_response}. -%% %% -%% Description: Find the matched single response. -%%-------------------------------------------------------------------- -find_single_response(Cert, IssuerCert, SingleResponseList) -> - IssuerName = get_subject_name(IssuerCert), - IssuerKey = get_public_key(IssuerCert), - SerialNum = get_serial_num(Cert), - match_single_response( - IssuerName, IssuerKey, SerialNum, SingleResponseList). - -match_single_response(_IssuerName, _IssuerKey, _SerialNum, []) -> - {error, no_matched_response}; -match_single_response( - IssuerName, IssuerKey, SerialNum, - [#'SingleResponse'{ - certID = #'CertID'{hashAlgorithm = Algo} = CertID - } = Response | Responses]) -> - HashType = public_key:pkix_hash_type( - Algo#'AlgorithmIdentifier'.algorithm), - case (SerialNum == CertID#'CertID'.serialNumber) andalso - (crypto:hash( - HashType, IssuerName) == CertID#'CertID'.issuerNameHash) andalso - (crypto:hash( - HashType, IssuerKey) == CertID#'CertID'.issuerKeyHash) of - true -> - {ok, Response}; - false -> - match_single_response(IssuerName, IssuerKey, SerialNum, Responses) - end. - +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(csp, + {call, {?MODULE, do_verify_ocsp_response, [BasicOcspResponse | _]}}, Stack) -> + #'BasicOCSPResponse'{ + tbsResponseData = + #'ResponseData'{responderID = ResponderID, + producedAt = ProducedAt}} = BasicOcspResponse, + {io_lib:format("ResponderId = ~W producedAt = ~p", [ResponderID, 5, ProducedAt]), Stack}; +handle_trace(csp, + {call, {?MODULE, match_single_response, + [_IssuerName, _IssuerKey, _SerialNum, + [#'SingleResponse'{thisUpdate = ThisUpdate, + nextUpdate = NextUpdate}]]}}, Stack) -> + {io_lib:format("ThisUpdate = ~p NextUpdate = ~p", [ThisUpdate, NextUpdate]), Stack}; +handle_trace(csp, + {call, {?MODULE, is_responder, [Id, Cert]}}, Stack) -> + {io_lib:format("~nId = ~P~nCert = ~P", [Id, 10, Cert, 10]), Stack}; +handle_trace(csp, + {call, {?MODULE, find_single_response, [Cert, IssuerCert | _]}}, Stack) -> + {io_lib:format("#2 OCSP validation started~nCert = ~W IssuerCert = ~W", + [Cert, 7, IssuerCert, 7]), Stack}; + %% {io_lib:format("#2 OCSP validation started~nCert = ~s IssuerCert = ~s", + %% [ssl_test_lib:format_cert(Cert), + %% ssl_test_lib:format_cert(IssuerCert)]), Stack}; + +handle_trace(csp, + {return_from, {?MODULE, is_responder, 2}, Return}, + Stack) -> + {io_lib:format("Return = ~p", [Return]), Stack}. diff --git a/lib/public_key/src/pubkey_os_cacerts.erl b/lib/public_key/src/pubkey_os_cacerts.erl new file mode 100644 index 000000000000..93f0e48353ac --- /dev/null +++ b/lib/public_key/src/pubkey_os_cacerts.erl @@ -0,0 +1,218 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2023. 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(pubkey_os_cacerts). + +-include("public_key.hrl"). +-export([load/0, load/1, get/0, clear/0]). + +-on_load(on_load/0). +-nifs([os_cacerts/0]). + +%% API + +%% Return cacerts +-spec get() -> [public_key:combined_cert()]. +get() -> + case persistent_term:get(?MODULE, not_loaded) of + not_loaded -> + ok = load(), + persistent_term:get(?MODULE); + CaCerts -> + CaCerts + end. + +%% (Re)Load default os cacerts and cache result. +-spec load() -> ok | {error, Reason::term()}. +load() -> + case os:type() of + {unix, linux} -> + load_from_file(linux_paths()); + {unix, openbsd} -> + load_from_file(bsd_paths()); + {unix, freebsd} -> + load_from_file(bsd_paths()); + {unix, netbsd} -> + load_from_file(bsd_paths()); + {unix, sunos} -> + load_from_files(sunos_path()); + {win32, _} -> + load_win32(); + {unix, darwin} -> + load_darwin(); + Os -> + {error, {enotsup, Os}} + end. + +%% (Re)Load cacerts from file and cache result. +%% The file-paths will be tried in order. +%% Can be used when load/0 doesn't work for an unsupported os type. +-spec load([file:filename_all()]) -> ok | {error, Reason::term()}. +load(Paths) -> + load_from_file(Paths). + + +%% cleanup persistent_key +-spec clear() -> boolean(). +clear() -> + persistent_term:erase(?MODULE). + +%% Implementation +load_from_file([Path|Paths]) when is_list(Path); is_binary(Path) -> + try + {ok, Binary} = file:read_file(Path), + ok = decode_result(Binary) + catch _:_Reason -> + load_from_file(Paths) + end; +load_from_file([]) -> + {error, enoent}. + +decode_result(Binary) -> + try + MakeCert = fun({'Certificate', Der, not_encrypted}, Acc) -> + try + Decoded = public_key:pkix_decode_cert(Der, otp), + [#cert{der=Der, otp=Decoded}|Acc] + catch _:_ -> + Acc + end + end, + Certs = lists:foldl(MakeCert, [], pubkey_pem:decode(Binary)), + store(Certs) + catch _:Reason -> + {error, Reason} + end. + + +load_from_files(Path) -> + MakeCert = fun(FileName, Acc) -> + try + {ok, Bin} = file:read_file(FileName), + [#cert{der=Der, otp=public_key:pkix_decode_cert(Der, otp)} + || {'Certificate', Der, not_encrypted} <- pubkey_pem:decode(Bin)] + ++ Acc + catch _:_ -> + Acc + end + end, + Certs = filelib:fold_files(Path, ".*\.pem", false, MakeCert, []), + store(Certs). + + +load_win32() -> + Dec = fun({_Enc, Der}, Acc) -> + try + Decoded = public_key:pkix_decode_cert(Der, otp), + [#cert{der=Der, otp=Decoded}|Acc] + catch _:_ -> + Acc + end + end, + store(lists:foldl(Dec, [], os_cacerts())). + +load_darwin() -> + %% Could/should probably be re-written to use Keychain Access API + KeyChainFile = "/System/Library/Keychains/SystemRootCertificates.keychain", + Args = ["export", "-t", "certs", "-f", "pemseq", "-k", KeyChainFile], + try run_cmd("/usr/bin/security", Args) of + {ok, Bin} -> decode_result(Bin); + Err -> Err + catch error:Reason -> + {error, {eopnotsupp, Reason}} + end. + +store([]) -> + {error, no_cacerts_found}; +store(CaCerts) -> + persistent_term:put(?MODULE, CaCerts). + +linux_paths() -> + ["/etc/ssl/certs/ca-certificates.crt", %% Debian, Ubuntu, Gentoo + "/etc/pki/tls/certs/ca-bundle.crt", %% Fedora, RHEL 6, Amazon Linux + "/etc/ssl/ca-bundle.pem", %% OpenSUSE + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", %% CentOS, RHEL 7 + "/etc/ssl/cert.pem" %% Alpine Linux + ]. + +bsd_paths() -> + ["/usr/local/share/certs/ca-root-nss.crt", + "/etc/ssl/cert.pem", + "/etc/openssl/certs/cacert.pem", %% netbsd (if installed) + "/etc/openssl/certs/ca-certificates.crt" + ]. + +sunos_path() -> + "/etc/certs/CA/". + +run_cmd(Cmd, Args) -> + Opts = [binary, exit_status, stderr_to_stdout], + Port = open_port({spawn_executable, Cmd}, [{args, Args}|Opts]), + unlink(Port), + cmd_data(Port, <<>>). + +cmd_data(Port, Acc) -> + receive + {Port, {data, Bin}} -> + cmd_data(Port, <>); + {Port, {exit_status, 0}} -> + {ok, Acc}; + {Port, {exit_status, Status}} -> + {error, {eopnotsupp, Status, Acc}} + end. + +%%% +%%% NIF placeholders +%%% + +-spec os_cacerts() -> [{Encoding::atom(), Cert::binary()}]. + +os_cacerts() -> + erlang:nif_error(nif_not_loaded). + +on_load() -> + case os:type() of + {win32, _} -> load_nif(); + _ -> ok + end. + +load_nif() -> + PrivDir = code:priv_dir(public_key), + LibName = "public_key", + Lib = filename:join([PrivDir, "lib", LibName]), + case erlang:load_nif(Lib, 0) of + ok -> ok; + {error, {load_failed, _}}=Error1 -> + Arch = erlang:system_info(system_architecture), + ArchLibDir = filename:join([PrivDir, "lib", Arch]), + Candidate = + filelib:wildcard( + filename:join([ArchLibDir,LibName ++ "*" ]), + erl_prim_loader), + case Candidate of + [] -> Error1; + _ -> + ArchLib = filename:join([ArchLibDir, LibName]), + erlang:load_nif(ArchLib, 0) + end; + Error1 -> Error1 + end. diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl index dc327567e4d4..27c21129b430 100644 --- a/lib/public_key/src/pubkey_pbe.erl +++ b/lib/public_key/src/pubkey_pbe.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2020. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -33,7 +33,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec encode(binary(), string(), string(), term()) -> binary(). +-spec encode(binary(), iodata(), string(), term()) -> binary(). %% %% Description: Performs password based encoding %%-------------------------------------------------------------------- @@ -57,7 +57,7 @@ encode(Data, Password, "AES-256-CBC"= Cipher, KeyDevParams) -> crypto:crypto_one_time(aes_256_cbc, Key, IV, pbe_pad(Data, block_size(aes_256_cbc)), true). %%-------------------------------------------------------------------- --spec decode(binary(), string(), string(), term()) -> binary(). +-spec decode(binary(), iodata(), string(), term()) -> binary(). %% %% Description: Performs password based decoding %%-------------------------------------------------------------------- diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 4aa965e14f4b..e28fd4019cea 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -72,7 +72,7 @@ encode(PemEntries) -> -spec decipher({public_key:pki_asn1_type(), DerEncrypted::binary(), {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{} | {#'PBEParameter'{}, atom()}}}, - string()) -> Der::binary(). + iodata()) -> Der::binary(). %% %% Description: Deciphers a decrypted pem entry. %%-------------------------------------------------------------------- @@ -82,7 +82,7 @@ decipher({_, DecryptDer, {Cipher, KeyDevParams}}, Password) -> %%-------------------------------------------------------------------- -spec cipher(Der::binary(), {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{} | {#'PBEParameter'{}, atom()}}, - string()) -> binary(). + iodata()) -> binary(). %% %% Description: Ciphers a PEM entry %%-------------------------------------------------------------------- diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl index 9a9505f55849..36c3ebf55854 100644 --- a/lib/public_key/src/pubkey_ssh.erl +++ b/lib/public_key/src/pubkey_ssh.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2020. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -19,70 +19,16 @@ %% -module(pubkey_ssh). --include("public_key.hrl"). -include("pubkey_moduli.hrl"). - --export([decode/2, encode/2, - dh_gex_group/4, - dh_gex_group_sizes/0, -pad/2, new_openssh_encode/1, new_openssh_decode/1 % For test and experiments +-export([dh_gex_group/4, + dh_gex_group_sizes/0 ]). --define(UINT32(X), X:32/unsigned-big-integer). --define(STRING(X), ?UINT32((byte_size(X))), (X)/binary). - --define(DEC_BIN(X,Len), ?UINT32(Len), X:Len/binary ). --define(DEC_MPINT(I,Len), ?DEC_INT(I,Len) ). --define(DEC_INT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ). - --define(Empint(X), (mpint(X))/binary ). --define(Estring(X), (string(X))/binary ). - --define(b64enc(X), base64:encode(iolist_to_binary(X)) ). --define(b64mime_dec(X), base64:mime_decode(iolist_to_binary(X)) ). - -%% Max encoded line length is 72, but conformance examples use 68 -%% Comment from rfc 4716: "The following are some examples of public -%% key files that are compliant (note that the examples all wrap -%% before 72 bytes to meet IETF document requirements; however, they -%% are still compliant.)" So we choose to use 68 also. --define(ENCODED_LINE_LENGTH, 68). - - %%==================================================================== %% Internal application API %%==================================================================== -%%-------------------------------------------------------------------- -%% Description: Decodes a ssh file-binary. -%%-------------------------------------------------------------------- -decode(Bin, public_key)-> - PKtype = - case binary:match(Bin, begin_marker()) of - nomatch -> openssh_public_key; - _ -> rfc4716_public_key - end, - decode(Bin, PKtype); -decode(Bin, rfc4716_public_key) -> - rfc4716_decode(Bin); -decode(Bin, ssh2_pubkey) -> - ssh2_pubkey_decode(Bin); -decode(Bin, new_openssh) -> - new_openssh_decode(Bin); -decode(Bin, Type) -> - openssh_decode(Bin, Type). - -%%-------------------------------------------------------------------- -%% Description: Encodes a list of ssh file entries. -%%-------------------------------------------------------------------- -encode(Bin, ssh2_pubkey) -> - ssh2_pubkey_encode(Bin); -encode(Entries, Type) -> - iolist_to_binary(lists:map(fun({Key, Attributes}) -> - do_encode(Type, Key, Attributes) - end, Entries)). - %%-------------------------------------------------------------------- %% Description: Returns Generator and Modulus given MinSize, WantedSize %% and MaxSize @@ -102,6 +48,11 @@ dh_gex_group(Min, N, Max, Groups) -> dh_gex_group_sizes()-> [KeyLen || {KeyLen,_} <- ?dh_default_groups]. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + %% Select the one with K closest to N but within the interval [Min,Max] select_by_keylen(Min, N, Max, [{K,_Gs}|Groups]) when K < Min -> @@ -123,533 +74,3 @@ select_by_keylen(Min, N, Max, [{K,Gs}|Groups], {Kprev,GsPrev}) -> select_by_keylen(_Min, _N, _Max, [],GPprev) -> %% is between Min and Max GPprev. - - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -begin_marker() -> - <<"---- BEGIN SSH2 PUBLIC KEY ----">>. -end_marker() -> - <<"---- END SSH2 PUBLIC KEY ----">>. - -rfc4716_decode(Bin) -> - Lines = binary:split(Bin, <<"\n">>, [global]), - do_rfc4716_decode(Lines, []). - -do_rfc4716_decode([<<"---- BEGIN SSH2 PUBLIC KEY ----", _/binary>> | Lines], Acc) -> - do_rfc4716_decode(Lines, Acc); -%% Ignore empty lines before or after begin/end - markers. -do_rfc4716_decode([<<>> | Lines], Acc) -> - do_rfc4716_decode(Lines, Acc); -do_rfc4716_decode([], Acc) -> - lists:reverse(Acc); -do_rfc4716_decode(Lines, Acc) -> - {Headers, PubKey, Rest} = rfc4716_decode_lines(Lines, []), - case Headers of - [_|_] -> - do_rfc4716_decode(Rest, [{PubKey, [{headers, Headers}]} | Acc]); - _ -> - do_rfc4716_decode(Rest, [{PubKey, []} | Acc]) - end. - -rfc4716_decode_lines([Line | Lines], Acc) -> - case binary:last(Line) of - $\\ -> - NewLine = binary:replace(Line,<<"\\">>, hd(Lines), []), - rfc4716_decode_lines([NewLine | tl(Lines)], Acc); - _ -> - rfc4716_decode_line(Line, Lines, Acc) - end. - -rfc4716_decode_line(Line, Lines, Acc) -> - case binary:split(Line, <<":">>) of - [Tag, Value] -> - rfc4716_decode_lines(Lines, [{string_decode(Tag), unicode_decode(Value)} | Acc]); - _ -> - {Body, Rest} = join_entry([Line | Lines], []), - {lists:reverse(Acc), rfc4716_pubkey_decode(?b64mime_dec(Body)), Rest} - end. - -join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([Line | Lines], Entry) -> - join_entry(Lines, [Line | Entry]). - - -rfc4716_pubkey_decode(BinKey) -> ssh2_pubkey_decode(BinKey). - - -%% From https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key -new_openssh_decode(<<"openssh-key-v1",0, - ?DEC_BIN(CipherName, _L1), - ?DEC_BIN(KdfName, _L2), - ?DEC_BIN(KdfOptions, _L3), - ?UINT32(N), % number of keys - ?DEC_BIN(PublicKey, _L4), - ?DEC_BIN(Encrypted, _L5), - _Rest/binary - >>) -> - %%io:format("CipherName = ~p~nKdfName = ~p~nKdfOptions = ~p~nPublicKey = ~p~nN = ~p~nEncrypted = ~p~nRest = ~p~n", [CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted, _Rest]), - new_openssh_decode(CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted). - -new_openssh_decode(<<"none">>, <<"none">>, <<"">>, _PublicKey, 1, - <>) -> - case {Type,PrivPubKey} of - {<<"ssh-ed25519">>, - <>} -> - {ed_pri, ed25519, PubKey, PrivKey}; - - {<<"ssh-ed448">>, - <>} -> % "Intelligent" guess from - % https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-ed448 - {ed_pri, ed448, PubKey, PrivKey} - end. - - -new_openssh_encode({ed_pri,_,PubKey,PrivKey}=Key) -> - Type = key_type(Key), - CheckInt = 17*256+17, %crypto:strong_rand_bytes(4), - Comment = <<>>, - PublicKey = <>, - CipherName = <<"none">>, - KdfName = <<"none">>, - KdfOptions = <<>>, - BlockSize = 8, % Crypto dependent - NumKeys = 1, - Encrypted0 = <>), - ?STRING(Comment) - >>, - Pad = pad(size(Encrypted0), BlockSize), - Encrypted = <>, - <<"openssh-key-v1",0, - ?STRING(CipherName), - ?STRING(KdfName), - ?STRING(KdfOptions), - ?UINT32(NumKeys), - ?STRING(PublicKey), - ?STRING(Encrypted)>>. - -pad(N, BlockSize) when N>BlockSize -> pad(N rem BlockSize, BlockSize); -pad(N, BlockSize) -> list_to_binary(lists:seq(1,BlockSize-N)). - - -openssh_decode(Bin, FileType) -> - Lines = binary:split(Bin, <<"\n">>, [global]), - do_openssh_decode(FileType, Lines, []). - -do_openssh_decode(_, [], Acc) -> - lists:reverse(Acc); -%% Ignore empty lines -do_openssh_decode(FileType, [<<>> | Lines], Acc) -> - do_openssh_decode(FileType, Lines, Acc); -%% Ignore lines that start with # -do_openssh_decode(FileType,[<<"#", _/binary>> | Lines], Acc) -> - do_openssh_decode(FileType, Lines, Acc); -do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) -> - case decode_auth_keys(Line) of - {ssh2, {options, [Options, KeyType, Base64Enc| Comment]}} -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - decode_comment(Comment) ++ [{options, comma_list_decode(Options)}]} | Acc]); - {ssh2, {no_options, [KeyType, Base64Enc| Comment]}} -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - decode_comment(Comment)} | Acc]); - {ssh1, {options, [Options, Bits, Exponent, Modulus | Comment]}} -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - decode_comment(Comment) ++ [{options, comma_list_decode(Options)}, - {bits, integer_decode(Bits)}] - } | Acc]); - {ssh1, {no_options, [Bits, Exponent, Modulus | Comment]}} -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - decode_comment(Comment) ++ [{bits, integer_decode(Bits)}] - } | Acc]) - end; - -do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) -> - case decode_known_hosts(Line) of - {ssh2, [HostNames, KeyType, Base64Enc| Comment]} -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - decode_comment(Comment) ++ - [{hostnames, comma_list_decode(HostNames)}]}| Acc]); - {ssh1, [HostNames, Bits, Exponent, Modulus | Comment]} -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - decode_comment(Comment) ++ - [{hostnames, comma_list_decode(HostNames)}, - {bits, integer_decode(Bits)}]} - | Acc]) - end; - -do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> - [KeyType, Base64Enc | Comment0] = split_n(2, Line, []), - KnownKeyType = - case KeyType of - <<"ssh-rsa">> -> true; - <<"ssh-dss">> -> true; - <<"ecdsa-sha2-",Curve/binary>> -> is_ssh_curvename(Curve); - <<"ssh-ed25519">> -> true; - <<"ssh-ed448">> -> true; - _ -> false - end, - - case Comment0 of - [] when KnownKeyType==true -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - []} | Acc]); - _ when KnownKeyType==true -> - Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n), - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, Comment}]} | Acc]); - _ when KnownKeyType==false -> - do_openssh_decode(FileType, Lines, Acc) - end. - - -decode_comment([]) -> - []; -decode_comment(Comment) -> - [{comment, string_decode(iolist_to_binary(Comment))}]. - - -openssh_pubkey_decode(Type, Base64Enc) -> - try - <> = ?b64mime_dec(Base64Enc), - ssh2_pubkey_decode(Type, Bin) - catch - _:_ -> - {Type, ?b64mime_dec(Base64Enc)} - end. - - -ssh1_rsa_pubkey_decode(MBin, EBin) -> - #'RSAPublicKey'{modulus = integer_decode(MBin), - publicExponent = integer_decode(EBin)}. - -integer_decode(BinStr) -> - list_to_integer(binary_to_list(BinStr)). - -string_decode(BinStr) -> - unicode_decode(BinStr). - -unicode_decode(BinStr) -> - unicode:characters_to_list(BinStr). - -comma_list_decode(BinOpts) -> - CommaList = binary:split(BinOpts, <<",">>, [global]), - lists:map(fun(Item) -> - binary_to_list(Item) - end, CommaList). - -do_encode(rfc4716_public_key, Key, Attributes) -> - rfc4716_encode(Key, proplists:get_value(headers, Attributes, []), []); - -do_encode(Type, Key, Attributes) -> - openssh_encode(Type, Key, Attributes). - -rfc4716_encode(Key, [],[]) -> - iolist_to_binary([begin_marker(),"\n", - split_lines(?b64enc(ssh2_pubkey_encode(Key))), - "\n", end_marker(), "\n"]); -rfc4716_encode(Key, [], [_|_] = Acc) -> - iolist_to_binary([begin_marker(), "\n", - lists:reverse(Acc), - split_lines(?b64enc(ssh2_pubkey_encode(Key))), - "\n", end_marker(), "\n"]); -rfc4716_encode(Key, [ Header | Headers], Acc) -> - LinesStr = rfc4716_encode_header(Header), - rfc4716_encode(Key, Headers, [LinesStr | Acc]). - -rfc4716_encode_header({Tag, Value}) -> - TagLen = length(Tag), - ValueLen = length(Value), - case TagLen + 1 + ValueLen of - N when N > ?ENCODED_LINE_LENGTH -> - NumOfChars = ?ENCODED_LINE_LENGTH - (TagLen + 1), - {First, Rest} = lists:split(NumOfChars, Value), - [Tag,":" , First, [$\\], "\n", rfc4716_encode_value(Rest) , "\n"]; - _ -> - [Tag, ":", Value, "\n"] - end. - -rfc4716_encode_value(Value) -> - case length(Value) of - N when N > ?ENCODED_LINE_LENGTH -> - {First, Rest} = lists:split(?ENCODED_LINE_LENGTH, Value), - [First, [$\\], "\n", rfc4716_encode_value(Rest)]; - _ -> - Value - end. - -openssh_encode(openssh_public_key, Key, Attributes) -> - Comment = proplists:get_value(comment, Attributes, ""), - Enc = ?b64enc(ssh2_pubkey_encode(Key)), - iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]); - -openssh_encode(auth_keys, Key, Attributes) -> - Comment = proplists:get_value(comment, Attributes, ""), - Options = proplists:get_value(options, Attributes, undefined), - Bits = proplists:get_value(bits, Attributes, undefined), - case Bits of - undefined -> - openssh_ssh2_auth_keys_encode(Options, Key, Comment); - _ -> - openssh_ssh1_auth_keys_encode(Options, Bits, Key, Comment) - end; -openssh_encode(known_hosts, Key, Attributes) -> - Comment = proplists:get_value(comment, Attributes, ""), - Hostnames = proplists:get_value(hostnames, Attributes), - Bits = proplists:get_value(bits, Attributes, undefined), - case Bits of - undefined -> - openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment); - _ -> - openssh_ssh1_known_hosts_encode(Hostnames, Bits, Key, Comment) - end. - -openssh_ssh2_auth_keys_encode(undefined, Key, Comment) -> - iolist_to_binary([key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]); -openssh_ssh2_auth_keys_encode(Options, Key, Comment) -> - iolist_to_binary([comma_list_encode(Options, []), " ", - key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]). - -openssh_ssh1_auth_keys_encode(undefined, Bits, - #'RSAPublicKey'{modulus = N, publicExponent = E}, - Comment) -> - iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N), - line_end(Comment)]); -openssh_ssh1_auth_keys_encode(Options, Bits, - #'RSAPublicKey'{modulus = N, publicExponent = E}, - Comment) -> - iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits), - " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]). - -openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) -> - iolist_to_binary([comma_list_encode(Hostnames, []), " ", - key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]). - -openssh_ssh1_known_hosts_encode(Hostnames, Bits, - #'RSAPublicKey'{modulus = N, publicExponent = E}, - Comment) -> - iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ", - integer_to_list(E)," ", integer_to_list(N), line_end(Comment)]). - -line_end("") -> - "\n"; -line_end(Comment) -> - [" ", Comment, "\n"]. - -key_type(#'RSAPublicKey'{}) -> <<"ssh-rsa">>; -key_type({_, #'Dss-Parms'{}}) -> <<"ssh-dss">>; -key_type({ed_pub,ed25519,_}) -> <<"ssh-ed25519">>; -key_type({ed_pub,ed448,_}) -> <<"ssh-ed448">>; -key_type({ed_pri,ed25519,_,_}) -> <<"ssh-ed25519">>; -key_type({ed_pri,ed448,_,_}) -> <<"ssh-ed448">>; -key_type({#'ECPoint'{}, {namedCurve,Curve}}) -> <<"ecdsa-sha2-", (public_key:oid2ssh_curvename(Curve))/binary>>. - -comma_list_encode([Option], []) -> - Option; -comma_list_encode([Option], Acc) -> - Acc ++ "," ++ Option; -comma_list_encode([Option | Rest], []) -> - comma_list_encode(Rest, Option); -comma_list_encode([Option | Rest], Acc) -> - comma_list_encode(Rest, Acc ++ "," ++ Option). - - -ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) -> - <>), ?Empint(E), ?Empint(N)>>; -ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> - <>), ?Empint(P), ?Empint(Q), ?Empint(G), ?Empint(Y)>>; -ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) -> - Curve = public_key:oid2ssh_curvename(OID), - <>; -ssh2_pubkey_encode({ed_pub, ed25519, Key}) -> - <>), ?Estring(Key)>>; -ssh2_pubkey_encode({ed_pub, ed448, Key}) -> - <>), ?Estring(Key)>>. - - - -ssh2_pubkey_decode(<>) -> - ssh2_pubkey_decode(Type, Bin). - -%% ssh2_pubkey_decode(<<"rsa-sha2-256">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, Bin); -%% ssh2_pubkey_decode(<<"rsa-sha2-512">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, Bin); -ssh2_pubkey_decode(<<"ssh-rsa">>, - <>) -> - #'RSAPublicKey'{modulus = N, - publicExponent = E}; - -ssh2_pubkey_decode(<<"ssh-dss">>, - <>) -> - {Y, #'Dss-Parms'{p = P, - q = Q, - g = G}}; - -ssh2_pubkey_decode(<<"ecdsa-sha2-",Id/binary>>, - <>) -> - {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}; - -ssh2_pubkey_decode(<<"ssh-ed25519">>, - <>) -> - {ed_pub, ed25519, Key}; - -ssh2_pubkey_decode(<<"ssh-ed448">>, - <>) -> - {ed_pub, ed448, Key}. - - - - -is_key_field(<<"ssh-dss">>) -> true; -is_key_field(<<"ssh-rsa">>) -> true; -is_key_field(<<"ssh-ed25519">>) -> true; -is_key_field(<<"ssh-ed448">>) -> true; -is_key_field(<<"ecdsa-sha2-",Id/binary>>) -> is_ssh_curvename(Id); -is_key_field(_) -> false. - -is_bits_field(Part) -> - try list_to_integer(binary_to_list(Part)) of - _ -> - true - catch _:_ -> - false - end. - -split_lines(<>) -> - [Text]; -split_lines(<>) -> - [Text, $\n | split_lines(Rest)]; -split_lines(Bin) -> - [Bin]. - -decode_auth_keys(Line) -> - [First, Rest] = binary:split(Line, <<" ">>, []), - case is_key_field(First) of - true -> - {ssh2, decode_auth_keys_ssh2(First, Rest)}; - false -> - case is_bits_field(First) of - true -> - {ssh1, decode_auth_keys_ssh1(First, Rest)}; - false -> - decode_auth_keys(First, Rest) - end - end. - -decode_auth_keys(First, Line) -> - [Second, Rest] = binary:split(Line, <<" ">>, []), - case is_key_field(Second) of - true -> - {ssh2, decode_auth_keys_ssh2(First, Second, Rest)}; - false -> - case is_bits_field(Second) of - true -> - {ssh1, decode_auth_keys_ssh1(First, Second, Rest)}; - false -> - decode_auth_keys(<>, Rest) - end - end. - -decode_auth_keys_ssh2(KeyType, Rest) -> - {no_options, [KeyType | split_n(1, Rest, [])]}. - -decode_auth_keys_ssh2(Options, Next, Rest) -> - {options, [Options, Next | split_n(1, Rest, [])]}. - -decode_auth_keys_ssh1(Options, Next, Rest) -> - {options, [Options, Next | split_n(2, Rest, [])]}. - -decode_auth_keys_ssh1(First, Rest) -> - {no_options, [First | split_n(2, Rest, [])]}. - -decode_known_hosts(Line) -> - [First, Rest] = binary:split(Line, <<" ">>, []), - [Second, Rest1] = binary:split(Rest, <<" ">>, []), - - case is_bits_field(Second) of - true -> - {ssh1, decode_known_hosts_ssh1(First, Second, Rest1)}; - false -> - {ssh2, decode_known_hosts_ssh2(First, Second, Rest1)} - end. - -decode_known_hosts_ssh1(Hostnames, Bits, Rest) -> - [Hostnames, Bits | split_n(2, Rest, [])]. - -decode_known_hosts_ssh2(Hostnames, KeyType, Rest) -> - [Hostnames, KeyType | split_n(1, Rest, [])]. - -split_n(0, <<>>, Acc) -> - lists:reverse(Acc); -split_n(0, Bin, Acc) -> - lists:reverse([Bin | Acc]); -split_n(N, Bin, Acc) -> - case binary:split(Bin, <<" ">>, []) of - [First, Rest] -> - split_n(N-1, Rest, [First | Acc]); - [Last] -> - split_n(0, <<>>, [Last | Acc]) - end. -%% large integer in a binary with 32bit length -%% MP representaion (SSH2) -mpint(X) when X < 0 -> mpint_neg(X); -mpint(X) -> mpint_pos(X). - -mpint_neg(X) -> - Bin = int_to_bin_neg(X, []), - <>. - -mpint_pos(X) -> - Bin = int_to_bin_pos(X, []), - <> = Bin, - if MSB band 16#80 == 16#80 -> - B = << 0, Bin/binary>>, - <>; - true -> - <> - end. - -int_to_bin_pos(0,Ds=[_|_]) -> - list_to_binary(Ds); -int_to_bin_pos(X,Ds) -> - int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). - -int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> - list_to_binary(Ds); -int_to_bin_neg(X,Ds) -> - int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). - - -string(X) when is_binary(X) -> - << ?STRING(X) >>; -string(X) -> - B = list_to_binary(X), - << ?STRING(B) >>. - -is_ssh_curvename(Id) -> try public_key:ssh_curvename2oid(Id) of _ -> true - catch _:_ -> false - end. - diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src index 6be7cd3bc494..5d8f936e33bc 100644 --- a/lib/public_key/src/public_key.app.src +++ b/lib/public_key/src/public_key.app.src @@ -9,13 +9,14 @@ pubkey_cert_records, pubkey_crl, pubkey_ocsp, + pubkey_os_cacerts, 'OTP-PUB-KEY', 'PKCS-FRAME' ]}, {applications, [asn1, crypto, kernel, stdlib]}, {registered, []}, {env, []}, - {runtime_dependencies, ["stdlib-3.5","kernel-3.0","erts-6.0","crypto-3.8", + {runtime_dependencies, ["stdlib-3.5","kernel-3.0","erts-6.0","crypto-4.6", "asn1-3.0"]} ] }. diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 06c6fc062527..33b404089a0f 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -52,7 +52,6 @@ pkix_path_validation/3, pkix_verify_hostname/2, pkix_verify_hostname/3, pkix_verify_hostname_match_fun/1, - ssh_curvename2oid/1, oid2ssh_curvename/1, pkix_crls_validate/3, pkix_dist_point/1, pkix_dist_points/1, @@ -64,27 +63,23 @@ pkix_test_root_cert/2, pkix_ocsp_validate/5, ocsp_responder_id/1, - ocsp_extensions/1 + ocsp_extensions/1, + cacerts_get/0, + cacerts_load/0, + cacerts_load/1, + cacerts_clear/0 ]). +%% Tracing +-export([handle_trace/3]). %%---------------- -%% To be moved to ssh and deprecated: --export([ssh_decode/2, ssh_encode/2, - ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2 - ]). - --deprecated([{ssh_decode,2, "use ssh_file:decode/2 instead"}, - {ssh_encode,2, "use ssh_file:encode/2 instead"}, - {ssh_hostkey_fingerprint,1, "use ssh:hostkey_fingerprint/1 instead"}, - {ssh_hostkey_fingerprint,2, "use ssh:hostkey_fingerprint/2 instead"} - ]). - --compile([{nowarn_deprecated_function, - [{public_key,ssh_decode,2}, - {public_key,ssh_encode,2} - ]} +%% Moved to ssh +-removed([{ssh_decode,2, "use ssh_file:decode/2 instead"}, + {ssh_encode,2, "use ssh_file:encode/2 instead"}, + {ssh_hostkey_fingerprint,1, "use ssh:hostkey_fingerprint/1 instead"}, + {ssh_hostkey_fingerprint,2, "use ssh:hostkey_fingerprint/2 instead"} ]). - +-export([ssh_curvename2oid/1, oid2ssh_curvename/1]). %% When removing for OTP-25.0, remember to also remove %% - most of pubkey_ssh.erl except %% + dh_gex_group/4 @@ -100,7 +95,6 @@ pem_entry/0, pki_asn1_type/0, asn1_type/0, - ssh_file/0, der_encoded/0, key_params/0, digest_type/0, @@ -131,9 +125,7 @@ -type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}. -type ec_private_key() :: #'ECPrivateKey'{}. -type ed_public_key() :: {#'ECPoint'{}, ed_params()}. --type ed_legacy_pubkey() :: {ed_pub, ed25519|ed448, Key::binary()}. -type ed_private_key() :: #'ECPrivateKey'{parameters :: ed_params()}. --type ed_legacy_privkey() :: {ed_pri, ed25519|ed448, Pub::binary(), Priv::binary()}. -type ed_oid_name() :: 'id-Ed25519' | 'id-Ed448'. -type ed_params() :: {namedCurve, ed_oid_name()}. -type key_params() :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} | @@ -158,8 +150,6 @@ -type salt() :: binary(). % crypto:strong_rand_bytes(8) -type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl --type ssh_file() :: openssh_public_key | rfc4716_public_key | known_hosts | - auth_keys. -type digest_type() :: none % None is for backwards compatibility | sha1 % Backwards compatibility | crypto:rsa_digest_type() @@ -170,7 +160,7 @@ -type oid() :: tuple(). -type cert_id() :: {SerialNr::integer(), issuer_name()} . -type issuer_name() :: {rdnSequence,[[#'AttributeTypeAndValue'{}]]} . --type bad_cert_reason() :: cert_expired | invalid_issuer | invalid_signature | name_not_permitted | missing_basic_constraint | invalid_key_usage | {revoked, crl_reason()} | atom(). +-type bad_cert_reason() :: cert_expired | invalid_issuer | invalid_signature | name_not_permitted | missing_basic_constraint | invalid_key_usage | duplicate_cert_in_path | {revoked, crl_reason()} | atom(). -type combined_cert() :: #cert{}. -type cert() :: der_cert() | otp_cert(). @@ -235,15 +225,13 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) -> ECCParams = der_decode('EcpkParameters', Params), {#'ECPoint'{point = Key0}, ECCParams} end; -pem_entry_decode({{no_asn1,new_openssh}, Special, not_encrypted}) -> - ssh_decode(Special, new_openssh); pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type), is_binary(Der) -> der_decode(Asn1Type, Der). -spec pem_entry_decode(PemEntry, Password) -> term() when PemEntry :: pem_entry(), - Password :: string() | fun(() -> string()). + Password :: iodata() | fun(() -> iodata()). pem_entry_decode(PemEntry, PasswordFun) when is_function(PasswordFun) -> pem_entry_decode(PemEntry, PasswordFun()); pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type), @@ -313,7 +301,7 @@ pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> Entity :: term(), InfoPwd :: {CipherInfo,Password}, CipherInfo :: cipher_info(), - Password :: string() . + Password :: iodata() . pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo, Password}) when is_atom(Asn1Type) andalso is_list(Password) andalso @@ -827,7 +815,7 @@ pkix_hash_type('id-md5') -> -spec sign(Msg, DigestType, Key) -> Signature when Msg :: binary() | {digest,binary()}, DigestType :: digest_type(), - Key :: private_key() | ed_legacy_privkey(), + Key :: private_key(), Signature :: binary() . sign(DigestOrPlainText, DigestType, Key) -> sign(DigestOrPlainText, DigestType, Key, []). @@ -835,7 +823,7 @@ sign(DigestOrPlainText, DigestType, Key) -> -spec sign(Msg, DigestType, Key, Options) -> Signature when Msg :: binary() | {digest,binary()}, DigestType :: digest_type(), - Key :: private_key() | ed_legacy_privkey(), + Key :: private_key(), Options :: crypto:pk_sign_verify_opts(), Signature :: binary() . sign(Digest, none, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) -> @@ -846,7 +834,12 @@ sign(DigestOrPlainText, DigestType, Key, Options) -> badarg -> erlang:error(badarg, [DigestOrPlainText, DigestType, Key, Options]); {Algorithm, CryptoKey} -> - crypto:sign(Algorithm, DigestType, DigestOrPlainText, CryptoKey, Options) + try crypto:sign(Algorithm, DigestType, DigestOrPlainText, CryptoKey, Options) + catch %% Compatible with old error schema + error:{notsup,_,_} -> error(notsup); + error:{error,_,_} -> error(error); + error:{badarg,_,_} -> error(badarg) + end end. %%-------------------------------------------------------------------- @@ -856,7 +849,7 @@ sign(DigestOrPlainText, DigestType, Key, Options) -> boolean() when Msg :: binary() | {digest, binary()}, DigestType :: digest_type(), Signature :: binary(), - Key :: public_key() | ed_legacy_pubkey(). + Key :: public_key(). verify(DigestOrPlainText, DigestType, Signature, Key) -> verify(DigestOrPlainText, DigestType, Signature, Key, []). @@ -865,7 +858,7 @@ verify(DigestOrPlainText, DigestType, Signature, Key) -> boolean() when Msg :: binary() | {digest, binary()}, DigestType :: digest_type(), Signature :: binary(), - Key :: public_key() | ed_legacy_pubkey(), + Key :: public_key(), Options :: crypto:pk_sign_verify_opts(). verify(Digest, none, Signature, Key = {_, #'Dss-Parms'{}}, Options) when is_binary(Digest) -> @@ -876,7 +869,12 @@ verify(DigestOrPlainText, DigestType, Signature, Key, Options) when is_binary(Si badarg -> erlang:error(badarg, [DigestOrPlainText, DigestType, Signature, Key, Options]); {Algorithm, CryptoKey} -> - crypto:verify(Algorithm, DigestType, DigestOrPlainText, Signature, CryptoKey, Options) + try crypto:verify(Algorithm, DigestType, DigestOrPlainText, Signature, CryptoKey, Options) + catch %% Compatible with old error schema + error:{notsup,_,_} -> error(notsup); + error:{error,_,_} -> error(error); + error:{badarg,_,_} -> error(badarg) + end end; verify(_,_,_,_,_) -> %% If Signature is a bitstring and not a binary we know already at this @@ -1163,7 +1161,12 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) MaxPathDefault, [{verify_fun, {VerifyFun, UserState1}} | proplists:delete(verify_fun, Options)]), - path_validation(CertChain, ValidationState) + case exists_duplicate_cert(CertChain) of + true -> + {error, {bad_cert, duplicate_cert_in_path}}; + false -> + path_validation(CertChain, ValidationState) + end catch throw:{bad_cert, _} = Result -> {error, Result} @@ -1300,58 +1303,6 @@ pkix_verify_hostname_match_fun(https) -> (_, _) -> default end. -%%-------------------------------------------------------------------- --spec ssh_decode(SshBin, Type) -> - Decoded - when SshBin :: binary(), - Type :: ssh2_pubkey | OtherType | InternalType, - OtherType :: public_key | ssh_file(), - InternalType :: new_openssh, - Decoded :: Decoded_ssh2_pubkey - | Decoded_OtherType, - Decoded_ssh2_pubkey :: public_key() | ed_legacy_pubkey(), - Decoded_OtherType :: [{public_key() | ed_legacy_pubkey(), Attributes}], - Attributes :: [{atom(),term()}] . -%% -%% Description: Decodes a ssh file-binary. In the case of know_hosts -%% or auth_keys the binary may include one or more lines of the -%% file. Returns a list of public keys and their attributes, possible -%% attribute values depends on the file type represented by the -%% binary. -%%-------------------------------------------------------------------- -ssh_decode(SshBin, Type) when is_binary(SshBin), - Type == public_key; - Type == rfc4716_public_key; - Type == openssh_public_key; - Type == auth_keys; - Type == known_hosts; - Type == ssh2_pubkey; - Type == new_openssh -> - pubkey_ssh:decode(SshBin, Type). - -%%-------------------------------------------------------------------- --spec ssh_encode(InData, Type) -> - binary() - when Type :: ssh2_pubkey | OtherType, - OtherType :: public_key | ssh_file(), - InData :: InData_ssh2_pubkey | OtherInData, - InData_ssh2_pubkey :: public_key() | ed_legacy_pubkey(), - OtherInData :: [{Key,Attributes}], - Key :: public_key() | ed_legacy_pubkey(), - Attributes :: [{atom(),term()}] . -%% -%% Description: Encodes a list of ssh file entries (public keys and -%% attributes) to a binary. Possible attributes depends on the file -%% type. -%%-------------------------------------------------------------------- -ssh_encode(Entries, Type) when is_list(Entries), - Type == rfc4716_public_key; - Type == openssh_public_key; - Type == auth_keys; - Type == known_hosts; - Type == ssh2_pubkey -> - pubkey_ssh:encode(Entries, Type). - %%-------------------------------------------------------------------- -spec ssh_curvename2oid(binary()) -> oid(). @@ -1371,51 +1322,6 @@ oid2ssh_curvename(?'secp256r1') -> <<"nistp256">>; oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>; oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>. -%%-------------------------------------------------------------------- --spec ssh_hostkey_fingerprint(public_key()) -> string(). - -ssh_hostkey_fingerprint(Key) -> - sshfp_string(md5, public_key:ssh_encode(Key,ssh2_pubkey) ). - - --spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string() - ; ([digest_type()], public_key()) -> [string()] - . -ssh_hostkey_fingerprint(HashAlgs, Key) when is_list(HashAlgs) -> - EncKey = public_key:ssh_encode(Key, ssh2_pubkey), - [sshfp_full_string(HashAlg,EncKey) || HashAlg <- HashAlgs]; -ssh_hostkey_fingerprint(HashAlg, Key) when is_atom(HashAlg) -> - EncKey = public_key:ssh_encode(Key, ssh2_pubkey), - sshfp_full_string(HashAlg, EncKey). - - -sshfp_string(HashAlg, EncodedKey) -> - %% Other HashAlgs than md5 will be printed with - %% other formats than hextstr by - %% ssh-keygen -E -lf - fp_fmt(sshfp_fmt(HashAlg), crypto:hash(HashAlg, EncodedKey)). - -sshfp_full_string(HashAlg, EncKey) -> - lists:concat([sshfp_alg_name(HashAlg), - [$: | sshfp_string(HashAlg, EncKey)] - ]). - -sshfp_alg_name(sha) -> "SHA1"; -sshfp_alg_name(Alg) -> string:to_upper(atom_to_list(Alg)). - -sshfp_fmt(md5) -> hexstr; -sshfp_fmt(_) -> b64. - -fp_fmt(hexstr, Bin) -> - lists:flatten(string:join([io_lib:format("~2.16.0b",[C1]) || <> <= Bin], ":")); -fp_fmt(b64, Bin) -> - %% This function clause *seems* to be - %% [C || C<-base64:encode_to_string(Bin), C =/= $=] - %% but I am not sure. Must be checked. - B64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - BitsInLast = 8*size(Bin) rem 6, - Padding = (6-BitsInLast) rem 6, % Want BitsInLast = [1:5] to map to padding [5:1] and 0 -> 0 - [lists:nth(C+1,B64Chars) || <> <= <> ]. %%-------------------------------------------------------------------- -spec short_name_hash(Name) -> string() when Name :: issuer_name() . @@ -1473,14 +1379,37 @@ pkix_test_root_cert(Name, Opts) -> %% Description: Validate OCSP staple response %%-------------------------------------------------------------------- -pkix_ocsp_validate(DerCert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) when is_binary(DerCert) -> - pkix_ocsp_validate(pkix_decode_cert(DerCert, otp), IssuerCert, OcspRespDer, ResponderCerts, NonceExt); -pkix_ocsp_validate(Cert, DerIssuerCert, OcspRespDer, ResponderCerts, NonceExt) when is_binary(DerIssuerCert) -> - pkix_ocsp_validate(Cert, pkix_decode_cert(DerIssuerCert, otp), OcspRespDer, ResponderCerts, NonceExt); +pkix_ocsp_validate(DerCert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) + when is_binary(DerCert) -> + pkix_ocsp_validate(pkix_decode_cert(DerCert, otp), IssuerCert, OcspRespDer, + ResponderCerts, NonceExt); +pkix_ocsp_validate(Cert, DerIssuerCert, OcspRespDer, ResponderCerts, NonceExt) + when is_binary(DerIssuerCert) -> + pkix_ocsp_validate(Cert, pkix_decode_cert(DerIssuerCert, otp), OcspRespDer, + ResponderCerts, NonceExt); pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) -> - case ocsp_responses(OcspRespDer, ResponderCerts, NonceExt) of + OcspResponse = pubkey_ocsp:decode_ocsp_response(OcspRespDer), + OcspCertResponses = + case OcspResponse of + {ok, BasicOcspResponse = #'BasicOCSPResponse'{certs = Certs}} -> + OcspResponseCerts = [otp_cert(C) || C <- Certs], + UserResponderCerts = + [otp_cert(pkix_decode_cert(C, plain)) || C <- ResponderCerts], + pubkey_ocsp:verify_ocsp_response( + BasicOcspResponse, OcspResponseCerts ++ UserResponderCerts, + NonceExt); + {error, _} = Error -> + Error + end, + case OcspCertResponses of {ok, Responses} -> - ocsp_status(Cert, IssuerCert, Responses); + case pubkey_ocsp:find_single_response( + otp_cert(Cert), otp_cert(IssuerCert), Responses) of + {ok, #'SingleResponse'{certStatus = CertStatus}} -> + pubkey_ocsp:ocsp_status(CertStatus); + {error, no_matched_response = Reason} -> + {bad_cert, {revocation_status_undetermined, Reason}} + end; {error, Reason} -> {bad_cert, {revocation_status_undetermined, Reason}} end. @@ -1495,12 +1424,45 @@ ocsp_extensions(Nonce) -> erlang:is_record(Extn, 'Extension')]. %%-------------------------------------------------------------------- --spec ocsp_responder_id(#'Certificate'{}) -> binary(). +-spec ocsp_responder_id(binary()) -> binary(). %% %% Description: Get the OCSP responder ID der %%-------------------------------------------------------------------- -ocsp_responder_id(Cert) -> - pubkey_ocsp:get_ocsp_responder_id(Cert). +ocsp_responder_id(CertDer) -> + pubkey_ocsp:get_ocsp_responder_id(pkix_decode_cert(CertDer, plain)). + +%%-------------------------------------------------------------------- +-spec cacerts_get() -> [combined_cert()]. +%% +%% Description: Get loaded cacerts, if none are loaded it will try to +%% load OS provided cacerts +%%-------------------------------------------------------------------- +cacerts_get() -> + pubkey_os_cacerts:get(). + +%%-------------------------------------------------------------------- +-spec cacerts_load() -> ok | {error, Reason::term()}. +%% +%% Description: (Re)Load OS provided cacerts +%%-------------------------------------------------------------------- +cacerts_load() -> + pubkey_os_cacerts:load(). + +%%-------------------------------------------------------------------- +-spec cacerts_load(File::file:filename_all()) -> ok | {error, Reason::term()}. +%% +%% Description: (Re)Load cacerts from a file +%%-------------------------------------------------------------------- +cacerts_load(File) -> + pubkey_os_cacerts:load([File]). + +%%-------------------------------------------------------------------- +-spec cacerts_clear() -> boolean(). +%% +%% Description: Clears loaded cacerts, returns true if any was loaded. +%%-------------------------------------------------------------------- +cacerts_clear() -> + pubkey_os_cacerts:clear(). %%-------------------------------------------------------------------- %%% Internal functions @@ -1596,6 +1558,20 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) -> Der = pubkey_pem:decipher(PemEntry, Password), der_decode(Asn1Type, Der). +%% The only way a path with duplicates could be somehow wrongly +%% passed is if the certs are located together and also are +%% self-signed. This is what we need to possible protect against. We +%% only check for togetherness here as it helps with the case not +%% otherwise caught. It can result in a different error message for +%% cases already failing before but that is not important, the +%% important thing is that it will be rejected. +exists_duplicate_cert([]) -> + false; +exists_duplicate_cert([Cert, Cert | _]) -> + true; +exists_duplicate_cert([_ | Rest]) -> + exists_duplicate_cert(Rest). + path_validation([], #path_validation_state{working_public_key_algorithm = Algorithm, working_public_key = @@ -1685,7 +1661,9 @@ otp_cert(Der) when is_binary(Der) -> otp_cert(#'OTPCertificate'{} = Cert) -> Cert; otp_cert(#cert{otp = OtpCert}) -> - OtpCert. + OtpCert; +otp_cert(#'Certificate'{} = Cert) -> + pkix_decode_cert(der_encode('Certificate', Cert), otp). der_cert(#'OTPCertificate'{} = Cert) -> pkix_encode('OTPCertificate', Cert, otp); @@ -2001,7 +1979,7 @@ verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 4 -> %% IPv4 try list_to_tuple(P) - == if is_tuple(R), size(R)==4 -> R; + == if tuple_size(R)==4 -> R; is_list(R) -> ok(inet:parse_ipv4strict_address(R)) end catch @@ -2013,7 +1991,7 @@ verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 16 -> %% IPv6. The length 16 is due to the certificate specification. try l16_to_tup(P) - == if is_tuple(R), size(R)==8 -> R; + == if tuple_size(R)==8 -> R; is_list(R) -> ok(inet:parse_ipv6strict_address(R)) end catch @@ -2049,8 +2027,8 @@ match_wild(_, _) -> false. %% Match the parts after the only wildcard by comparing them from the end match_wild_suffixes(A, B) -> match_wild_sfx(lists:reverse(A), lists:reverse(B)). -match_wild_sfx([$*|_], _) -> false; % Bad name (no wildcards alowed) -match_wild_sfx(_, [$*|_]) -> false; % Bad pattern (no more wildcards alowed) +match_wild_sfx([$*|_], _) -> false; % Bad name (no wildcards allowed) +match_wild_sfx(_, [$*|_]) -> false; % Bad pattern (no more wildcards allowed) match_wild_sfx([A|Ar], [A|Br]) -> match_wild_sfx(Ar, Br); match_wild_sfx(Ar, []) -> not lists:member($*, Ar); % Chk for bad name (= wildcards) match_wild_sfx(_, _) -> false. @@ -2094,18 +2072,39 @@ format_details([]) -> no_relevant_crls; format_details(Details) -> Details. - -ocsp_status(Cert, IssuerCert, Responses) -> - case pubkey_ocsp:find_single_response(Cert, IssuerCert, Responses) of - {ok, #'SingleResponse'{certStatus = CertStatus}} -> - pubkey_ocsp:ocsp_status(CertStatus); - {error, no_matched_response = Reason} -> - {bad_cert, {revocation_status_undetermined, Reason}} - end. - -ocsp_responses(OCSPResponseDer, ResponderCerts, Nonce) -> - pubkey_ocsp:verify_ocsp_response(OCSPResponseDer, - ResponderCerts, Nonce). subject_public_key_info(Alg, PubKey) -> #'OTPSubjectPublicKeyInfo'{algorithm = Alg, subjectPublicKey = PubKey}. + +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(csp, + {call, {?MODULE, ocsp_responder_id, [Cert]}}, Stack) -> + {io_lib:format("pkix_decode_cert(Cert, plain) = ~W", [Cert, 5]), + %% {io_lib:format("pkix_decode_cert(Cert, plain) = ~s", [ssl_test_lib:format_cert(Cert)]), + Stack}; +handle_trace(csp, + {return_from, {?MODULE, ocsp_responder_id, 1}, Return}, + Stack) -> + {io_lib:format("OCSP Responder ID = ~P", [Return, 10]), Stack}; +handle_trace(crt, + {call, {?MODULE, pkix_decode_cert, [Cert, _Type]}}, Stack) -> + {io_lib:format("Cert = ~W", [Cert, 5]), Stack}; + %% {io_lib:format("Cert = ~s", [ssl_test_lib:format_cert(Cert)]), Stack}; +handle_trace(csp, + {call, {?MODULE, pkix_ocsp_validate, [Cert, IssuerCert | _]}}, Stack) -> + {io_lib:format("#2 OCSP validation started~nCert = ~W IssuerCert = ~W", + [Cert, 7, IssuerCert, 7]), Stack}; + %% {io_lib:format("#2 OCSP validation started~nCert = ~s IssuerCert = ~s", + %% [ssl_test_lib:format_cert(Cert), + %% ssl_test_lib:format_cert(IssuerCert)]), Stack}; +handle_trace(csp, + {call, {?MODULE, otp_cert, [Cert]}}, Stack) -> + {io_lib:format("Cert = ~W", [Cert, 5]), Stack}; + %% {io_lib:format("Cert = ~s", [ssl_test_lib:format_cert(otp_cert(Cert))]), Stack}; +handle_trace(csp, + {return_from, {?MODULE, pkix_ocsp_validate, 5}, Return}, + Stack) -> + {io_lib:format("#2 OCSP validation result = ~p", [Return]), Stack}. diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile index 89e82a5f3463..57879c20e667 100644 --- a/lib/public_key/test/Makefile +++ b/lib/public_key/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2020. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -33,7 +33,7 @@ MODULES= \ public_key_SUITE \ pbe_SUITE \ pkits_SUITE \ - pubkey_ssh_SUITE + pubkey_cert_SUITE ERL_FILES= $(MODULES:%=%.erl) @@ -56,6 +56,7 @@ RELSYSDIR = $(RELEASE_PATH)/public_key_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += $(INCLUDES) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -63,7 +64,7 @@ EBIN = . # Targets # ---------------------------------------------------- -tests debug opt: $(TARGET_FILES) +tests $(TYPES): $(TARGET_FILES) clean: diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl index e2a94dd886f9..a56c8e369185 100644 --- a/lib/public_key/test/erl_make_certs.erl +++ b/lib/public_key/test/erl_make_certs.erl @@ -47,7 +47,7 @@ %% {title, Title} %% {dnQualifer, DnQ} %% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) -%% (obs IssuerKey migth be {Key, Password} +%% (obs IssuerKey might be {Key, Password} %% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key %% %% @@ -368,7 +368,7 @@ make_key(ec, _Opts) -> gen_rsa2(Size) -> try - %% The numbers 2048,17 is choosen to not cause the cryptolib on + %% The numbers 2048,17 is chosen to not cause the cryptolib on %% FIPS-enabled test machines be mad at us. public_key:generate_key({rsa, 2048, 17}) catch diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl index 4745698293b2..f3ed9f9b1db6 100644 --- a/lib/public_key/test/pbe_SUITE.erl +++ b/lib/public_key/test/pbe_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2020. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -219,12 +219,24 @@ pbdkdf2(Config) when is_list(Config) -> pbes1() -> [{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES1"}]. pbes1(Config) when is_list(Config) -> - decode_encode_key_file("pbes1_des_cbc_md5_enc_key.pem", "password", "DES-CBC", Config). + case lists:member(des_cbc, crypto:supports(ciphers)) + andalso lists:member(md5, crypto:supports(hashs)) + of + true -> + decode_encode_key_file("pbes1_des_cbc_md5_enc_key.pem", "password", "DES-CBC", Config); + false -> + {skip, alg_not_supported} + end. pbes2() -> [{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES2"}]. pbes2(Config) when is_list(Config) -> - decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config), + case lists:member(des_cbc, crypto:supports(ciphers)) of + true -> + decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config); + false -> + ok + end, decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config), decode_encode_key_file("pbes2_aes_128_enc_key.pem", "password", "AES-128-CBC", Config), decode_encode_key_file("pbes2_aes_192_enc_key.pem", "password", "AES-192-CBC", Config), diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index ba3efdba0944..baa212ff65af 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -19,7 +19,7 @@ %% -%% Se specification here: +%% See specification here: %% http://csrc.nist.gov/groups/ST/crypto_apps_infra/pki/pkitesting.html -module(pkits_SUITE). @@ -300,24 +300,24 @@ end_per_testcase(_Func, Config) -> %%--------------------------- signature_verification-------------------------------------------------- valid_rsa_signature() -> - [{doc, "Test rsa signatur verification"}]. + [{doc, "Test rsa signature verification"}]. valid_rsa_signature(Config) when is_list(Config) -> run([{ "4.1.1", "Valid Certificate Path Test1 EE", ok}]). invalid_rsa_signature() -> - [{doc,"Test rsa signatur verification"}]. + [{doc,"Test rsa signature verification"}]. invalid_rsa_signature(Config) when is_list(Config) -> run([{ "4.1.2", "Invalid CA Signature Test2 EE", {bad_cert,invalid_signature}}, { "4.1.3", "Invalid EE Signature Test3 EE", {bad_cert,invalid_signature}}]). valid_dsa_signature() -> - [{doc,"Test dsa signatur verification"}]. + [{doc,"Test dsa signature verification"}]. valid_dsa_signature(Config) when is_list(Config) -> run([{ "4.1.4", "Valid DSA Signatures Test4 EE", ok}, { "4.1.5", "Valid DSA Parameter Inheritance Test5 EE", ok}]). invalid_dsa_signature() -> - [{doc,"Test dsa signatur verification"}]. + [{doc,"Test dsa signature verification"}]. invalid_dsa_signature(Config) when is_list(Config) -> run([{ "4.1.6", "Invalid DSA Signature Test6 EE",{bad_cert,invalid_signature}}]). @@ -332,7 +332,7 @@ not_before_valid() -> [{doc,"Test valid periods"}]. not_before_valid(Config) when is_list(Config) -> run([{ "4.2.3", "Valid pre2000 UTC notBefore Date Test3 EE", ok}, - { "4.2.4", "Valid GeneralizedTime notBefore Date Test4 EE", ok}]). + { "4.2.4", "Valid GeneralizedTime notBefore Date Test4 EE", ok}]). not_after_invalid() -> [{doc,"Test valid periods"}]. @@ -379,7 +379,7 @@ string_name_chain() -> [{doc,"Test name chaining"}]. string_name_chain(Config) when is_list(Config) -> run([{ "4.3.9", "Valid UTF8String Encoded Names Test9 EE", ok}, - %%{ "4.3.10", "Valid Rollover from PrintableString to UTF8String Test10 EE", ok}, + { "4.3.10", "Valid Rollover from PrintableString to UTF8String Test10 EE", ok}, { "4.3.11", "Valid UTF8String Case Insensitive Match Test11 EE", ok}]). %%----------------------------verifying_paths_with_self_issued_certificates------------------------------------------------- @@ -805,7 +805,7 @@ invalid_crl_issuer(Config) when is_list(Config) -> ]). %% Although this test is valid it has a circular dependency. As a result -%% an attempt is made to reursively checks a CRL path and rejected due to +%% an attempt is made to recursively checks a CRL path and rejected due to %% a CRL path validation error. PKITS notes suggest this test does not %% need to be run due to this issue. %% { "4.14.30", "Valid cRLIssuer Test30", 54 } @@ -828,13 +828,24 @@ unknown_not_critical_extension(Config) when is_list(Config) -> %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- +-spec run([tuple()]) -> ok. run(Tests) -> [TA] = read_certs("Trust Anchor Root Certificate"), run(Tests, TA). +-spec run([Entry] | Entry, TA) -> ok when + TA :: public_key:pem_entry(), + Entry :: {CA, Test, Result} | {CA, Test, Result, CertificateBodies}, + CA :: public_key:pem_entry(), + Test :: string(), + Result :: atom(), + CertificateBodies :: [binary()]. run({Chap, Test, Result}, TA) -> - CertChain = cas(Chap) ++ read_certs(Test), - Options = path_validation_options(TA, Chap,Test), + run({Chap, Test, Result, read_certs(Test)}, TA); + +run({Chap, Test, Result, CertsBody}, TA) -> + CertChain = cas(Chap) ++ CertsBody, + Options = path_validation_options(Chap), try public_key:pkix_path_validation(TA, CertChain, Options) of {Result, _} -> ok; {error,Result} when Result =/= ok -> @@ -851,15 +862,14 @@ run({Chap, Test, Result}, TA) -> exit(crash) end; -run([Test|Rest],TA) -> - run(Test,TA), - run(Rest,TA); -run([],_) -> ok. +run(Tests,TA) when is_list(Tests) -> + lists:foreach(fun (T) -> run(T, TA) end, Tests), + ok. -path_validation_options(TA, Chap, Test) -> +path_validation_options(Chap) -> case needs_crl_options(Chap) of true -> - crl_options(TA, Chap, Test); + crl_options(Chap); false -> Fun = fun(_,{bad_cert, _} = Reason, _) -> @@ -873,9 +883,14 @@ path_validation_options(TA, Chap, Test) -> [{verify_fun, {Fun, []}}] end. +-spec read_certs(TestCase :: string()) -> [CertificateContent :: binary()]. read_certs(Test) -> File = cert_file(Test), Ders = erl_make_certs:pem_to_der(File), + extract_certificate(Ders). + +-spec extract_certificate(Certificates :: [public_key:pem_entry()]) -> CertificateContent :: binary(). +extract_certificate(Ders) -> [Cert || {'Certificate', Cert, not_encrypted} <- Ders]. read_crls(Test) -> @@ -883,13 +898,15 @@ read_crls(Test) -> Ders = erl_make_certs:pem_to_der(File), [CRL || {'CertificateList', CRL, not_encrypted} <- Ders]. +-spec cert_file(TestCase :: string()) -> FilenamePath :: string(). cert_file(Test) -> file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem"). +-spec crl_file(TestCase :: string()) -> FilenamePath :: string(). crl_file(Test) -> file(?CRL, lists:append(string:tokens(Test, " -")) ++ ".pem"). - +-spec file(Subdir :: string(), Filename :: string()) -> FilenamePath :: string(). file(Sub,File) -> TestDir = case get(datadir) of undefined -> "./pkits_SUITE_data"; @@ -939,7 +956,7 @@ needs_crl_options("4.15" ++ _) -> needs_crl_options(_) -> false. -crl_options(_TA, Chap, _Test) -> +crl_options(Chap) -> CRLNames = crl_names(Chap), CRLs = crls(CRLNames), Paths = lists:map(fun(CRLName) -> crl_path(CRLName) end, CRLNames), @@ -966,16 +983,12 @@ crl_options(_TA, Chap, _Test) -> CRLInfo = lists:reverse(CRLInfo0), PathDb = crl_path_db(lists:reverse(Crls), Paths, []), - Fun = fun(DP, CRLtoValidate, Id, PathDb0) -> - trusted_cert_and_path(DP, CRLtoValidate, Id, PathDb0) - end, - case CRLInfo of [] -> {valid, UserState}; [_|_] -> case public_key:pkix_crls_validate(OtpCert, CRLInfo, - [{issuer_fun,{Fun, PathDb}}]) of + [{issuer_fun,{fun trusted_cert_and_path/4, PathDb}}]) of valid -> {valid, UserState}; Reason -> @@ -1089,6 +1102,7 @@ dp_crlissuer_to_issuer(DPCRLIssuer) -> %%%%%%%%%%%%%%% CA mappings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec cas(Chap :: string()) -> [Certificates :: public_key:pem_entry()]. cas(Chap) -> CAS = intermidiate_cas(Chap), lists:foldl(fun([], Acc) -> @@ -1097,7 +1111,8 @@ cas(Chap) -> [CACert] = read_certs(CA), [CACert | Acc] end, [], CAS). - + +-spec intermidiate_cas(Chap :: string()) -> [CACert :: string()]. intermidiate_cas(Chap) when Chap == "4.1.1"; Chap == "4.1.3"; Chap == "4.2.2"; @@ -1463,7 +1478,8 @@ intermidiate_cas(Chap) when Chap == "4.5.8" -> %%%%%%%%%%%%%%% CRL mappings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +crl_names("4.3.10") -> + ["PrintableString to UTF8String CA CRL"]; crl_names("4.4.1") -> ["Trust Anchor Root CRL"]; crl_names("4.4.2") -> diff --git a/lib/public_key/test/pkits_SUITE_data/pkits/smime-pem/RolloverfromPrintableStringtoUTF8StringCACert.pem b/lib/public_key/test/pkits_SUITE_data/pkits/smime-pem/RolloverfromPrintableStringtoUTF8StringCACert.pem index 17e4e8259c01..e8cdc66af538 100644 --- a/lib/public_key/test/pkits_SUITE_data/pkits/smime-pem/RolloverfromPrintableStringtoUTF8StringCACert.pem +++ b/lib/public_key/test/pkits_SUITE_data/pkits/smime-pem/RolloverfromPrintableStringtoUTF8StringCACert.pem @@ -1,61 +1,61 @@ Bag Attributes - localKeyID: E0 D4 12 A0 DC 4B 51 3E 01 68 B3 B7 0B E0 32 00 08 50 CE D5 + localKeyID: 0C 0E C1 9B 90 D2 60 B1 D6 2E 75 B6 8E 45 8D 0A 57 3E 9D 54 friendlyName: Rollover from PrintableString to UTF8String CA Cert -subject=/C=US/O=Test Certificates 2011/CN=Rollover from PrintableString to UTF8String CA -issuer=/C=US/O=Test Certificates 2011/CN=Rollover from PrintableString to UTF8String CA +subject=C = US, O = Test Certificates 2011, CN = Rollover from PrintableString to UTF8String CA +issuer=C = US, O = Test Certificates 2011, CN = Trust Anchor -----BEGIN CERTIFICATE----- -MIIDnjCCAoagAwIBAgIBADANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzEf -MB0GA1UECgwWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTE3MDUGA1UEAwwuUm9sbG92 -ZXIgZnJvbSBQcmludGFibGVTdHJpbmcgdG8gVVRGOFN0cmluZyBDQTAeFw0xMDAx -MDEwODMwMDBaFw0zMDEyMzEwODMwMDBaMGcxCzAJBgNVBAYTAlVTMR8wHQYDVQQK -DBZUZXN0IENlcnRpZmljYXRlcyAyMDExMTcwNQYDVQQDDC5Sb2xsb3ZlciBmcm9t -IFByaW50YWJsZVN0cmluZyB0byBVVEY4U3RyaW5nIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAuEETE+kVGfvnJPPJHUxpy7khkrkcBdQPlj2HTZ9i -LbYRvpIAC+Qa2lAVwzAwshljKfoGD6ZuL0sHATtKDC0/+iyDTOG7UJCGesmbO90Y -bgLR/j7fT9RNMND0BEycIOhBukZ4FkjKWU3+KFjQjMa9nUGECoNXyjYnKTAYj07X -sR+rsMgmzRm2TzALDArS6D+toFAs8DbNbtT882ZsE1h8O9VmN5GkWzrEVBzDGiKo -GUAt9P/ZmNVjx4gW5pB0MxacAvK+HxohxcF/y1gRZ3zp2dccZiirFK9GoCst0pDM -qqEgDRyTTK2a7hZkLtmVRNp2VIh7x5+hk41UnOELKoRErwIDAQABo1UwUzAJBgNV -HSMEAjAAMB0GA1UdDgQWBBS1bU8oP8e7sZikqaXQqFteSnSz5zAOBgNVHQ8BAf8E -BAMCBPAwFwYDVR0gBBAwDjAMBgpghkgBZQMCATABMA0GCSqGSIb3DQEBCwUAA4IB -AQA4KPELZ6+9+ZDvahZzIrH+QTAWJg50Y4xbi9Zhs739Q4F0TGrzwvXIpCcTY5iC -IrIBWHSqiE9cEEShxnY+sdGdAgtW7oJdRnVl3JfuNW9moIueVdvk5CbVGGdMzPIu -FfhNwLUHfpSrUKek+nWpWPIoMpQCmMVbIXVMRbjL7yFJZB4kNxo1650+Er4Kdjzq -TnedRp+n2+Lm1M4AxLUgJ/StrD6b1WkSjI3LgiqFLxdwOeH/Im99UEUyTulhSUCI -ZeoOali6JrtcsuMwtE0su8xLuEuHgCuHV3rh54ekfiEFmgUOuviiUSoYU8WoFk0O -ds/hkFuM1qLbRxFJU4h1AfKz +MIIDozCCAougAwIBAgIBYzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVUzEf +MB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgMjAxMTEVMBMGA1UEAxMMVHJ1c3Qg +QW5jaG9yMB4XDTEwMDEwMTA4MzAwMFoXDTMwMTIzMTA4MzAwMFowZzELMAkGA1UE +BhMCVVMxHzAdBgNVBAoTFlRlc3QgQ2VydGlmaWNhdGVzIDIwMTExNzA1BgNVBAMT +LlJvbGxvdmVyIGZyb20gUHJpbnRhYmxlU3RyaW5nIHRvIFVURjhTdHJpbmcgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4QRMT6RUZ++ck88kdTGnL +uSGSuRwF1A+WPYdNn2ItthG+kgAL5BraUBXDMDCyGWMp+gYPpm4vSwcBO0oMLT/6 +LINM4btQkIZ6yZs73RhuAtH+Pt9P1E0w0PQETJwg6EG6RngWSMpZTf4oWNCMxr2d +QYQKg1fKNicpMBiPTtexH6uwyCbNGbZPMAsMCtLoP62gUCzwNs1u1PzzZmwTWHw7 +1WY3kaRbOsRUHMMaIqgZQC30/9mY1WPHiBbmkHQzFpwC8r4fGiHFwX/LWBFnfOnZ +1xxmKKsUr0agKy3SkMyqoSANHJNMrZruFmQu2ZVE2nZUiHvHn6GTjVSc4QsqhESv +AgMBAAGjfDB6MB8GA1UdIwQYMBaAFOR9X9FclYYILAWuvnW2ZafZXahmMB0GA1Ud +DgQWBBS1bU8oP8e7sZikqaXQqFteSnSz5zAOBgNVHQ8BAf8EBAMCAQYwFwYDVR0g +BBAwDjAMBgpghkgBZQMCATABMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAEIpMIiOeUzWzRx5RExhSxK7MtakcVAbTjjlHWSlTuNWvkEpo6hbj5re +iUeRe3dt9mHKa2/rrTIfzd44IXmYGb/E+n7C1jzlxOTlUrHrVv+CHtANcON2lsNq +/ZtThy/HisC1FqEM2rQMfsSmHXzDwgsEFDCZU/wTbWZKig1oNpkUPLXa39IRqBIZ +WVu3HtxMAlFccm5Olp/gE0EvqFgzufYSllZU2khgkCaQjLlbqw9aSiNUZob+pY1v +asyGwpiBv9AqeYODTRd/2GCmkHTt2k8aEXoY2ICb6Wzqb9TDQG5Ea1h2y31C4UaY +HuU+qfxmwTT1sIiABlmkzTWaOWw5qmM= -----END CERTIFICATE----- Bag Attributes - localKeyID: E0 D4 12 A0 DC 4B 51 3E 01 68 B3 B7 0B E0 32 00 08 50 CE D5 + localKeyID: 0C 0E C1 9B 90 D2 60 B1 D6 2E 75 B6 8E 45 8D 0A 57 3E 9D 54 friendlyName: Rollover from PrintableString to UTF8String CA Cert Key Attributes: ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,9DDA760B90D3F5F4 - -odK0zz4yql9kRhptAZajKhjn8Z40phPXVyFw7Oa1H2W07aI8ebO7TFWG/woxEZC+ -AIx53YZA/Wqu4w+rSGokIXv7CMMmx0n1h3YGYE9nbS/Cvtqr02NF447J60Q8GGl1 -GRrOhSacfge3pKkdFZRZWgQwgcJgtZqLbPZI5rGkrqTc6h4AwRIhgNp9NdeSqKSn -T7abY80UwouSMjaefqARTomvPihqKnVA3SZlKXkxB2Gz8elW5UP5MfWuZZV0yBqq -NtegLaWeLKFKQOr99t21MUHFTD6vH5ELQr8XDHfYdDPTaMirhfySo+oUSa5ueE5M -x454cqPbxPJznKoQrAXtfLjRdoFPSN5G6s4paVP327cvHmtIOD1YYgwEtG77H35j -52lsSz4SOyBVWL0UfdnrlWmY3BaAg+HtfwkaacN+yFiPA/Eirgp8ImWn03GIbSwV -3Lx6ztmIuDs+ma0n+miGAtJrC5rmAW9tJdwE38q4K/tG5UBASK7D63zm5/z28Jkj -Wp8D6pmM4SnpTKJ4icARvIN2/BciEiuAUtlmqJel3YJhCDwcMbtdv1r2hyJSjwNx -d8YwX0HHvQrWU0/yxUcC/aZ/yonRZq3cCujcQlZTILFFHm2uqkJGwHPi+C3TTctw -Ct93ALYTDlq3YkIQwRY6jqluoDs4YgYlluE+cRv9a6+BnifwDeDnBikRFDhjEbqr -SpOYNG80P0e4ifuKgngQUuR71GkezCJ633lyerqeG2RsXDRwVpbK9279uEL8IooN -H8Ud4iQ4kXYUFDD7wRcUQy8Rz/4+DI6cixxhSmMR0/2ljEqDdtWpElnJQXoHgISP -kY5vj3BT4WyH6xhWbImRI4BKLHriPT8s3zzE4a0UhRsy1YTvoKBp3//JQxx9drb0 -U10OFHOQsU9+dpdGOWmdUhBDdPpOA/iE0CBjwgar6Z+kVmRgiA3YkFI7ezbc4G77 -2Ep4ZD5PLEqK/Lh8MjXY8ysok5Ki6hcclq7R2XyHld2K4RxHIxidQybjH+Rn0NEB -8RKF5ID5jTKaqe82ivCGpQ4NkbyqS5Vs9iml2yESOzQt8zKDbpoKO7WixBBWm0UJ -FdRKek9xZj8gBTDLnDgDaXXLy2ZAmuYHo+NNbjbkSaYx21LJ37pGqL00OqMNhKVQ -vLXaDHVrDVBqHKfnHlULNvR8tV1BH+BplyOebwawojgqSSwlIUCgkg54TC0TFBI+ -MpT71vFv9WzHQwGID5Lzxd0lC/I4osSCxERF2iZtyTdfWeSO8hbSKRea/jdt+DEc -BPMe/DZuV/QcvrLJhcJKD4Twp6LYyLp7OxcJBaHoBajIznIN97d1VTn6PFYdSIHg -exqDN/bULO6J/9gLrGlv3HgJzxmG9Zuk3xy81B3ua5Ke7/wkNIpmoInQxZuCH5ES -x/BdQv4XlakRy3Jw+26sZQKAkAV26YAgj1IUTUUa8WeHfTgXMYKLzcekPimWyu5E -JkeSjwaFBEf5978Tb3Fw9pM/OTB2dwt7XrZHbPVqdy9rZ3H38wUET42jTFX8QYpR -/ni1glyQZ2EVGAfyLMNp9w8YB2AKPiZ5y36ePJS6cawoSFZ+yIE1ZQ== ------END RSA PRIVATE KEY----- +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIWyW1PlYjVf4CAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAsNLFyz2zh0qbV6Y0JtPacBIIE +0HTGklhdBCHN9wb4WuGM+WE7nq9ovuEZRyCh8lYjEvjW7KbxP1D0hSuEeSyT9Iq7 +RRFeOHLGxLhrHWxz5lNDFb0STJUdUv7TbbU2HCTVVVUTp8WfRMobDcRSYeFOHIfa +vussU5FU0l/A86MOXzZkQD7MpTusIUeODaxeeDnOxCSbIpROCH9dduHt9O3wdnyT +2YRtK1rovm1ID0Zk/p0gbQLojkw0EQ+DDJhXW/yVYwAMoydwaOLO4zZSIbfKAv0v +6xhjpmpLme8x+bbI4Jt1syP6kakvaYeHjvF/TDiWm5+fZmMtTuFxwiWKfYGEf2LW +flxPQFdx66PjRfi4TCCQgLH/B77XdQ+Vdv7PKjltVZOgglP9Gt7+CfKw8pZhk9iU +Dtws8Vz9x1YDVCZg37c7IL3Vg9p0hwpXsyG1vey1Hz+7gNyqs09EfpyOvV/ZoeDc +p0Hf9O4ny0dEU6jncsLBKNVAMitXRDW6Rcxv8DNqy7Z7fJWZE6n+qlLiW//tApDa +zJD2TZSV2jeFQNiP9FAEtjoixFDKt20SpZVFGC5cblI0izXNaJhMAIIGR9pKeAh6 +GheX/MYxxUwTq0MunFmpJli4k3LjdrKXUrwN9ByK5jDjauL9l5EtGVJICwO6ybQV +OYlT5ZvKesd87S9TCK76VM5rcjQGNmpmalndw/dXsRI1M+qHrO/jORJcsHOSH8PT +ToLO6G1pNdWF4zeZY0hH5sMDjBBo2kcvagHzAK3iHd90orspowUcRq4ybW1+jrek +PbTLDYaUpW302kXlCYYvmDdu8fwRCHKGPOI6mqNCgRs01jmBV104DbXFydaXU9d4 +ibP328EYpGn+/fcpkajyVMQq9YaF9JqAlN8S3cFCv7wwSfrGrG4pxmxhravFI9Qq +t03Fn6iQLoQw8l/8zT4tz7KG77+k30ioLS4XcFshCyk+WwHQ2HE57RLyGwP7hc2W +zTmM198UYs/Zx+OYtzuYgTHkNARz+kmRdXfUuO25GPAhLTezk1xnVFX1eJLzIAtE +Bb8XYIkB17/gdSGsohmFg6T7N+l6whLd0XwmVZ8ruHsRHzf30UH6X9dM7Pl5ySlg +dmSI06eVsqpiiYcX2JhHhOrkVlYlyGRiO7Wi4YIocvPjAbbdpQga12OQcIkWUVYl +21+lJ7KCwjY5eXmu932RfkkGcZXRupLLg2QV3c0KP3io1lKzPrRjOlZjyzXXz2sk +gbg4g3jKTv8aM7DHxVa/leHIm0EDM3MNpu+ar4mbnkph9tbrFZLevruv+rNFMFNY +3a+7F0up3YTwngKtjoV/hq1A0wvqaF6H+6h5Ih80sgdW0iVr/6/OPXXgNNKfK3lV +HLvwrj/rNJ9IQcD2h/sbUIyj76ql+Yn3UNQfv1zMLQWijQhVO1ToZiIPn/j1dghZ +awadnvL9VnaFw+TqVft7QnM8SEf4+poVzWfgKKhdCgLbQiVtWXpHMHS1lahHzhON +PV4Pjha7VQsGFwZusqS/5EwqzRtQmSL69ESfzw1ohinmFozIhPCHuJ5qZ5XJcs14 +jWiwX6cryEvzcWDTAN26xoScFczn19Kc2CLPQlTN8R1olhYYNSzl0EnMLDIBMOVX +PCkZ7VIWTLWNOMBj/iv80EduPtOwzZ5+ibCRjDRyYbc+ +-----END ENCRYPTED PRIVATE KEY----- diff --git a/lib/public_key/test/pubkey_cert_SUITE.erl b/lib/public_key/test/pubkey_cert_SUITE.erl new file mode 100644 index 000000000000..7d51d5afda17 --- /dev/null +++ b/lib/public_key/test/pubkey_cert_SUITE.erl @@ -0,0 +1,178 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2023. 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(pubkey_cert_SUITE). + +-include_lib("common_test/include/ct.hrl"). +%% -include_lib("public_key/include/public_key.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +all() -> + [{group, time_str_2_gregorian_sec}]. + +groups() -> + [{time_str_2_gregorian_sec, [], time_str_two_gregorian()}]. + +time_str_two_gregorian() -> + [ time_str_2_gregorian_utc_post2000 + , time_str_2_gregorian_utc_limit_50_years_before_current_time + , time_str_2_gregorian_utc_limit_51_years_before_current_time + , time_str_2_gregorian_utc_limit_50_years_from_current_time + , time_str_2_gregorian_utc_limit_49_years_from_current_time + , time_str_2_gregorian_generaltime_50_years_before_current_time + , time_str_2_gregorian_generaltime_50_years_from_current_time + ]. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- +%%-------------------------------------------------------------------- +time_str_2_gregorian_utc_post2000() -> + [{doc, "Tests a valid gregorian Utc time"}]. +time_str_2_gregorian_utc_post2000(_) -> + YYMMDD = "450101", + HHMMSSZ = "000000Z", + ExpectedYear = 2045, + UtcTime = {utcTime, YYMMDD ++ HHMMSSZ}, + {ExpectedDate, _} = convert_to_datetime_format(UtcTime, ExpectedYear), + + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + {ExpectedDate, _} = calendar:gregorian_seconds_to_datetime(Result). + + +time_str_2_gregorian_utc_limit_50_years_before_current_time() -> + [{doc, "Tests limit of gregorian Utc time 50 years before current time"}]. +time_str_2_gregorian_utc_limit_50_years_before_current_time(_) -> + {ExpectedDate, UtcTime} = get_date(utcTime, -50), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + {ExpectedDate, _} = calendar:gregorian_seconds_to_datetime(Result). + +time_str_2_gregorian_utc_limit_51_years_before_current_time() -> + [{doc, "Tests limit of gregorian Utc time 51 years before current time"}]. +time_str_2_gregorian_utc_limit_51_years_before_current_time(_) -> + {{Y, M, D}, UtcTime} = get_date(utcTime, -51), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + %% the sliding window method from pubkey_cert reaches its limit and + %% reverses the year from 19XX to 20XX. Because of this, the expected + %% year is current_year + 50, or ExpectedYear + 100 (they are equivalent) + ExpectedYear = Y + 100, + {{ExpectedYear, M, D}, _} = calendar:gregorian_seconds_to_datetime(Result). + +time_str_2_gregorian_utc_limit_50_years_from_current_time() -> + [{doc, "Tests a valid gregorian Utc time 50 years from now"}]. +time_str_2_gregorian_utc_limit_50_years_from_current_time(_) -> + {{Y, M, D}, UtcTime} = get_date(utcTime, 50), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + %% the sliding window method from pubkey_cert reaches its limit and + %% reverses the year from 20XX to 19XX. Because of this, the expected + %% year is current_year - 50, or ExpectedYear - 100 (they are equivalent) + ExpectedYear = Y - 100, + {{ExpectedYear, M, D}, _} = calendar:gregorian_seconds_to_datetime(Result). + +time_str_2_gregorian_utc_limit_49_years_from_current_time() -> + [{doc, "Tests a valid gregorian Utc time 49 years from now"}]. +time_str_2_gregorian_utc_limit_49_years_from_current_time(_) -> + {ExpectedDate, UtcTime} = get_date(utcTime, 49), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + {ExpectedDate, _} = calendar:gregorian_seconds_to_datetime(Result). + + +time_str_2_gregorian_generaltime_50_years_before_current_time() -> + [{doc, "Tests a valid general time 50 years before current time"}]. +time_str_2_gregorian_generaltime_50_years_before_current_time(_) -> + {ExpectedDate, UtcTime} = get_date(generalTime, -50), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + {ExpectedDate, _} = calendar:gregorian_seconds_to_datetime(Result). + + +time_str_2_gregorian_generaltime_50_years_from_current_time() -> + [{doc, "Tests a valid general time 50 years from now"}]. +time_str_2_gregorian_generaltime_50_years_from_current_time(_) -> + {ExpectedDate, UtcTime} = get_date(generalTime, 50), + Result = pubkey_cert:time_str_2_gregorian_sec(UtcTime), + {ExpectedDate, _} = calendar:gregorian_seconds_to_datetime(Result). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Helper functions +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-spec convert_to_datetime_format({Format, Date}, ExpectedYear) -> Result when + Format :: generalTime | utcTime, + Date :: YYMMDDHHMMSS | YYYYMMDDHHMMSS, + YYMMDDHHMMSS :: string(), + YYYYMMDDHHMMSS :: string(), + ExpectedYear :: non_neg_integer(), + Result :: {{non_neg_integer(), 1..12, 1..31}, {0, 0, 0}}. +convert_to_datetime_format({Format, Date}, ExpectedYear) -> + YYMMDD = group_year(Format, Date), + [Y, M, D] = lists:map(fun (Str) -> erlang:list_to_integer(Str) end, YYMMDD), + %% assertions to test that the result is the expected one + case Format of + utcTime -> (ExpectedYear rem 100) =:= Y; + generalTime -> ExpectedYear =:= Y + end, + {{ExpectedYear, M, D}, {0, 0, 0}}. + +-spec get_date(Format, YearsFromNow) -> {{Year, Month, Day}, UtcDate} when + Format :: utcTime | generalTime, + YearsFromNow :: integer(), + Year :: non_neg_integer(), + Month :: 1..12, + Day :: 1..31, + UtcDate :: string(). +get_date(Format, Years) -> + {YYYY, MM0, DD0} = date(), + MM = io_lib:format("~2..0w", [MM0]), + DD = io_lib:format("~2..0w", [DD0]), + ExpectedYear = YYYY + Years, + YYMMDD = format_year(Format, ExpectedYear, {MM, DD}), + HHMMSSZ = "000000Z", + FormattedTime = {Format, YYMMDD ++ HHMMSSZ}, + {ExpectedDate, _} = convert_to_datetime_format(FormattedTime, ExpectedYear), + {ExpectedDate, FormattedTime}. + +-spec format_year(Format, ExpectedYear, {Month, Day}) -> YYMMDD | YYYYMMDD when + Format :: utcTime | generalTime, + ExpectedYear :: non_neg_integer(), + Month :: string(), + Day :: string(), + YYMMDD :: string(), + YYYYMMDD :: string(). +format_year(utcTime, ExpectedYear, {MM, DD}) -> + YY = erlang:integer_to_list((ExpectedYear) rem 100), + lists:flatten(YY++MM++DD); +format_year(generalTime, ExpectedYear, {MM, DD}) -> + YY = erlang:integer_to_list(ExpectedYear), + lists:flatten(YY++MM++DD). + +-spec group_year(Format, Date) -> [list()] when + Format :: utcTime | generalTime, + Date :: [non_neg_integer()]. +group_year(utcTime, [Y1, Y2, M1, M2, D1, D2 | _]) -> + [[Y1, Y2], [M1, M2], [D1, D2]]; +group_year(generalTime, [Y1, Y2, Y3, Y4, M1, M2, D1, D2 | _]) -> + [[Y1, Y2, Y3, Y4], [M1, M2], [D1, D2]]. diff --git a/lib/public_key/test/pubkey_ssh_SUITE.erl b/lib/public_key/test/pubkey_ssh_SUITE.erl deleted file mode 100644 index 4b7c2082ba0a..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE.erl +++ /dev/null @@ -1,457 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2021. 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(pubkey_ssh_SUITE). - -%% This test suite tests thoose functions until they are removed --compile([{nowarn_deprecated_function, - [{public_key,ssh_decode,2}, - {public_key,ssh_encode,2}, - {public_key,ssh_hostkey_fingerprint,1}, - {public_key,ssh_hostkey_fingerprint,2} - ]} - ]). - --include_lib("common_test/include/ct.hrl"). --include_lib("public_key/include/public_key.hrl"). - --export([ - suite/0, - all/0, - groups/0, - init_per_suite/1, - end_per_suite/1, - init_per_group/2, - end_per_group/2, - init_per_testcase/2, - end_per_testcase/2, - - ssh_rsa_public_key/1, - ssh_dsa_public_key/1, - ssh_ecdsa_public_key/1, - ssh_rfc4716_rsa_comment/1, - ssh_rfc4716_dsa_comment/1, - ssh_rfc4716_rsa_subject/1, - ssh_known_hosts/1, - ssh1_known_hosts/1, - ssh_auth_keys/1, - ssh1_auth_keys/1, - ssh_openssh_public_key_with_comment/1, - ssh_openssh_public_key_long_header/1, - - ssh_hostkey_fingerprint_md5_implicit/1, - ssh_hostkey_fingerprint_md5/1, - ssh_hostkey_fingerprint_sha/1, - ssh_hostkey_fingerprint_sha256/1, - ssh_hostkey_fingerprint_sha384/1, - ssh_hostkey_fingerprint_sha512/1, - ssh_hostkey_fingerprint_list/1 - ]). - - --define(TIMEOUT, 120000). % 2 min - - -%%-------------------------------------------------------------------- -%% Common Test interface functions ----------------------------------- -%%-------------------------------------------------------------------- - -suite() -> - []. - -all() -> - [{group, ssh_public_key_decode_encode}, - {group, ssh_hostkey_fingerprint} - ]. - -groups() -> - [{ssh_public_key_decode_encode, [], - [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key, - ssh_rfc4716_rsa_comment, ssh_rfc4716_dsa_comment, - ssh_rfc4716_rsa_subject, - ssh_known_hosts, - ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment, - ssh_openssh_public_key_long_header]}, - - {ssh_hostkey_fingerprint, [], - [ssh_hostkey_fingerprint_md5_implicit, - ssh_hostkey_fingerprint_md5, - ssh_hostkey_fingerprint_sha, - ssh_hostkey_fingerprint_sha256, - ssh_hostkey_fingerprint_sha384, - ssh_hostkey_fingerprint_sha512, - ssh_hostkey_fingerprint_list]} - ]. -%%------------------------------------------------------------------- -init_per_suite(Config) -> - application:stop(crypto), - try crypto:start() of - ok -> - application:start(asn1), - Config - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - application:stop(asn1), - application:stop(crypto). - -%%------------------------------------------------------------------- -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. -%%------------------------------------------------------------------- -init_per_testcase(ssh_hostkey_fingerprint_md5_implicit, Config) -> - init_fingerprint_testcase([md5], Config); - -init_per_testcase(ssh_hostkey_fingerprint_md5, Config) -> - init_fingerprint_testcase([md5], Config); - -init_per_testcase(ssh_hostkey_fingerprint_sha, Config) -> - init_fingerprint_testcase([sha], Config); - -init_per_testcase(ssh_hostkey_fingerprint_sha256, Config) -> - init_fingerprint_testcase([sha256], Config); - -init_per_testcase(ssh_hostkey_fingerprint_sha384, Config) -> - init_fingerprint_testcase([sha384], Config); - -init_per_testcase(ssh_hostkey_fingerprint_sha512, Config) -> - init_fingerprint_testcase([sha512], Config); - -init_per_testcase(ssh_hostkey_fingerprint_list , Config) -> - init_fingerprint_testcase([sha,md5], Config); - -init_per_testcase(_, Config) -> - init_common_per_testcase(Config). - - -init_fingerprint_testcase(Algs, Config) -> - Hashs = proplists:get_value(hashs, crypto:supports(), []), - case Algs -- Hashs of - [] -> init_common_per_testcase(Config); - UnsupportedAlgs -> {skip,{UnsupportedAlgs,not_supported}} - end. - -init_common_per_testcase(Config0) -> - Config = lists:keydelete(watchdog, 1, Config0), - Dog = ct:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. - - -end_per_testcase(_TestCase, _Config) -> - ok. - -%%-------------------------------------------------------------------- -%% Test Cases -------------------------------------------------------- -%%-------------------------------------------------------------------- -ssh_rsa_public_key(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")), - [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key), - [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key), - - {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")), - [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key), - [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key), - - %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh - %% = RSARawOpenSsh as line breakpoints may differ - - EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), - EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), - - [{PubKey, Attributes1}] = - public_key:ssh_decode(EncodedSSh, public_key), - [{PubKey, Attributes2}] = - public_key:ssh_decode(EncodedOpenSsh, public_key). - -%%-------------------------------------------------------------------- -ssh_dsa_public_key(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")), - [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key), - [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key), - - {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")), - [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key), - [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key), - - %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh - %% = DSARawOpenSsh as line breakpoints may differ - - EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), - EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), - - [{PubKey, Attributes1}] = - public_key:ssh_decode(EncodedSSh, public_key), - [{PubKey, Attributes2}] = - public_key:ssh_decode(EncodedOpenSsh, public_key). - -%%-------------------------------------------------------------------- -ssh_ecdsa_public_key(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, ECDSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_ecdsa_pub")), - [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, public_key), - [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, rfc4716_public_key), - - {ok, ECDSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_ecdsa_pub")), - [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, public_key), - [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, openssh_public_key), - - %% Can not check EncodedSSh == ECDSARawSsh2 and EncodedOpenSsh - %% = ECDSARawOpenSsh as line breakpoints may differ - - EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), - EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), - - [{PubKey, Attributes1}] = - public_key:ssh_decode(EncodedSSh, public_key), - [{PubKey, Attributes2}] = - public_key:ssh_decode(EncodedOpenSsh, public_key). - -%%-------------------------------------------------------------------- -ssh_rfc4716_rsa_comment(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")), - [{#'RSAPublicKey'{} = PubKey, Attributes}] = - public_key:ssh_decode(RSARawSsh2, public_key), - - Headers = proplists:get_value(headers, Attributes), - - Value = proplists:get_value("Comment", Headers, undefined), - true = Value =/= undefined, - RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key). - -%%-------------------------------------------------------------------- -ssh_rfc4716_dsa_comment(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")), - [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] = - public_key:ssh_decode(DSARawSsh2, public_key), - - Headers = proplists:get_value(headers, Attributes), - - Value = proplists:get_value("Comment", Headers, undefined), - true = Value =/= undefined, - - %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ - Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key), - [{PubKey, Attributes}] = - public_key:ssh_decode(Encoded, public_key). - -%%-------------------------------------------------------------------- -ssh_rfc4716_rsa_subject(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")), - [{#'RSAPublicKey'{} = PubKey, Attributes}] = - public_key:ssh_decode(RSARawSsh2, public_key), - - Headers = proplists:get_value(headers, Attributes), - - Value = proplists:get_value("Subject", Headers, undefined), - true = Value =/= undefined, - - %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ - Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key), - [{PubKey, Attributes}] = - public_key:ssh_decode(Encoded, public_key). - -%%-------------------------------------------------------------------- -ssh_known_hosts(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")), - [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}, - {#'RSAPublicKey'{}, Attributes3}, {#'RSAPublicKey'{}, Attributes4}] = Decoded = - public_key:ssh_decode(SshKnownHosts, known_hosts), - - Comment1 = undefined, - Comment2 = "foo@bar.com", - Comment3 = "Comment with whitespaces", - Comment4 = "foo@bar.com Comment with whitespaces", - - Comment1 = proplists:get_value(comment, Attributes1, undefined), - Comment2 = proplists:get_value(comment, Attributes2), - Comment3 = proplists:get_value(comment, Attributes3), - Comment4 = proplists:get_value(comment, Attributes4), - - Value1 = proplists:get_value(hostnames, Attributes1, undefined), - Value2 = proplists:get_value(hostnames, Attributes2, undefined), - true = (Value1 =/= undefined) and (Value2 =/= undefined), - - Encoded = public_key:ssh_encode(Decoded, known_hosts), - Decoded = public_key:ssh_decode(Encoded, known_hosts). - -%%-------------------------------------------------------------------- -ssh1_known_hosts(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")), - [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}] - = Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts), - - Value1 = proplists:get_value(hostnames, Attributes1, undefined), - Value2 = proplists:get_value(hostnames, Attributes2, undefined), - true = (Value1 =/= undefined) and (Value2 =/= undefined), - - Comment ="dhopson@VMUbuntu-DSH comment with whitespaces", - Comment = proplists:get_value(comment, Attributes3), - - Encoded = public_key:ssh_encode(Decoded, known_hosts), - Decoded = public_key:ssh_decode(Encoded, known_hosts). - -%%-------------------------------------------------------------------- -ssh_auth_keys(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")), - [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2}, - {#'RSAPublicKey'{}, Attributes3}, {{_, #'Dss-Parms'{}}, Attributes4} - ] = Decoded = - public_key:ssh_decode(SshAuthKeys, auth_keys), - - Value1 = proplists:get_value(options, Attributes1, undefined), - true = Value1 =/= undefined, - - Comment1 = Comment2 = "dhopson@VMUbuntu-DSH", - Comment3 = Comment4 ="dhopson@VMUbuntu-DSH comment with whitespaces", - - Comment1 = proplists:get_value(comment, Attributes1), - Comment2 = proplists:get_value(comment, Attributes2), - Comment3 = proplists:get_value(comment, Attributes3), - Comment4 = proplists:get_value(comment, Attributes4), - - Encoded = public_key:ssh_encode(Decoded, auth_keys), - Decoded = public_key:ssh_decode(Encoded, auth_keys). - -%%-------------------------------------------------------------------- -ssh1_auth_keys(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")), - [{#'RSAPublicKey'{}, Attributes1}, - {#'RSAPublicKey'{}, Attributes2}, {#'RSAPublicKey'{}, Attributes3}, - {#'RSAPublicKey'{}, Attributes4}, {#'RSAPublicKey'{}, Attributes5}] = Decoded = - public_key:ssh_decode(SshAuthKeys, auth_keys), - - Value1 = proplists:get_value(bits, Attributes2, undefined), - Value2 = proplists:get_value(bits, Attributes3, undefined), - true = (Value1 =/= undefined) and (Value2 =/= undefined), - - Comment2 = Comment3 = "dhopson@VMUbuntu-DSH", - Comment4 = Comment5 ="dhopson@VMUbuntu-DSH comment with whitespaces", - - undefined = proplists:get_value(comment, Attributes1, undefined), - Comment2 = proplists:get_value(comment, Attributes2), - Comment3 = proplists:get_value(comment, Attributes3), - Comment4 = proplists:get_value(comment, Attributes4), - Comment5 = proplists:get_value(comment, Attributes5), - - Encoded = public_key:ssh_encode(Decoded, auth_keys), - Decoded = public_key:ssh_decode(Encoded, auth_keys). - -%%-------------------------------------------------------------------- -ssh_openssh_public_key_with_comment(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")), - [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key). - -%%-------------------------------------------------------------------- -ssh_openssh_public_key_long_header(Config) when is_list(Config) -> - Datadir = proplists:get_value(data_dir, Config), - - {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")), - [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key), - - Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key), - Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key). - -%%-------------------------------------------------------------------- -%% Check of different host keys left to later -ssh_hostkey_fingerprint_md5_implicit(_Config) -> - Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a", - Expected = public_key:ssh_hostkey_fingerprint(ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Check of different host keys left to later -ssh_hostkey_fingerprint_md5(_Config) -> - Expected = "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a", - Expected = public_key:ssh_hostkey_fingerprint(md5, ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Since this kind of fingerprint is not available yet on standard -%% distros, we do like this instead. The Expected is generated with: -%% $ openssh-7.3p1/ssh-keygen -E sha1 -lf -%% 2048 SHA1:Soammnaqg06jrm2jivMSnzQGlmk none@example.org (RSA) -ssh_hostkey_fingerprint_sha(_Config) -> - Expected = "SHA1:Soammnaqg06jrm2jivMSnzQGlmk", - Expected = public_key:ssh_hostkey_fingerprint(sha, ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Since this kind of fingerprint is not available yet on standard -%% distros, we do like this instead. -ssh_hostkey_fingerprint_sha256(_Config) -> - Expected = "SHA256:T7F1BahkJWR7iJO8+rpzWOPbp7LZP4MlNrDExdNYOvY", - Expected = public_key:ssh_hostkey_fingerprint(sha256, ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Since this kind of fingerprint is not available yet on standard -%% distros, we do like this instead. -ssh_hostkey_fingerprint_sha384(_Config) -> - Expected = "SHA384:QhkLoGNI4KXdPvC//HxxSCP3uTQVADqxdajbgm+Gkx9zqz8N94HyP1JmH8C4/aEl", - Expected = public_key:ssh_hostkey_fingerprint(sha384, ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Since this kind of fingerprint is not available yet on standard -%% distros, we do like this instead. -ssh_hostkey_fingerprint_sha512(_Config) -> - Expected = "SHA512:ezUismvm3ADQQb6Nm0c1DwQ6ydInlJNfsnSQejFkXNmABg1Aenk9oi45CXeBOoTnlfTsGG8nFDm0smP10PBEeA", - Expected = public_key:ssh_hostkey_fingerprint(sha512, ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Since this kind of fingerprint is not available yet on standard -%% distros, we do like this instead. -ssh_hostkey_fingerprint_list(_Config) -> - Expected = ["SHA1:Soammnaqg06jrm2jivMSnzQGlmk", - "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a"], - Expected = public_key:ssh_hostkey_fingerprint([sha,md5], ssh_hostkey(rsa)). - -%%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ -%%-------------------------------------------------------------------- -ssh_hostkey(rsa) -> - [{PKdecoded,_}] = - public_key:ssh_decode( - <<"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYXcYmsyJBstl4EfFYzfQJmSiUE162zvSGSoMYybShYOI6rnnyvvihfw8Aml+2gZ716F2tqG48FQ/yPZEGWNPMrCejPpJctaPWhpNdNMJ8KFXSEgr5bY2mEpa19DHmuDeXKzeJJ+X7s3fVdYc4FMk5731KIW6Huf019ZnTxbx0VKG6b1KAJBg3vpNsDxEMwQ4LFMB0JHVklOTzbxmpaeULuIxvl65A+eGeFVeo2Q+YI9UnwY1vSgmc9Azwy8Ie9Z0HpQBN5I7Uc5xnknT8V6xDhgNfXEfzsgsRdDfZLECt1WO/1gP9wkosvAGZWt5oG8pbNQWiQdFq536ck8WQD9WD none@example.org">>, - public_key), - PKdecoded. - diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys b/lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys deleted file mode 100644 index 8be7357a061b..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys +++ /dev/null @@ -1,7 +0,0 @@ -command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH - -ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH - -command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH comment with whitespaces - -ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts b/lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts deleted file mode 100644 index 3c3af6817833..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts +++ /dev/null @@ -1,8 +0,0 @@ -hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= - -|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= foo@bar.com - -hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= Comment with whitespaces - -|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= foo@bar.com Comment with whitespaces - diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub deleted file mode 100644 index a765ba8189c9..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub deleted file mode 100644 index d5a34a3f78a3..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub +++ /dev/null @@ -1,3 +0,0 @@ -#This should be ignored!! - -ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub deleted file mode 100644 index a49b4264b840..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub +++ /dev/null @@ -1 +0,0 @@ -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIJrVlKYIT+MlxxRx5BFXisHHkcGMAAKv2dguUeOsutsYyzs9JAczvl6c+Sypra5+qOi2LHPXw6GGluuXcOssOM= uabhnil@elxadlj3q32 diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub deleted file mode 100644 index 0a0838db40f7..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys deleted file mode 100644 index ac3d61b4c791..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys +++ /dev/null @@ -1,9 +0,0 @@ -1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 - -1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH - -command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH - -1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces - -command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts deleted file mode 100644 index 835b16ab6765..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts +++ /dev/null @@ -1,3 +0,0 @@ -hostname.domain.com,192.168.0.1 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH -hostname2.domain.com,192.168.0.2 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 -hostname3.domain.com,192.168.0.3 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH comment with whitespaces diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub deleted file mode 100644 index ca5089dbd755..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub +++ /dev/null @@ -1,13 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: This is my public key for use on \ -servers which I don't like. -AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET -W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH -YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c -vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf -J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA -vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB -AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS -n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5 -sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub deleted file mode 100644 index a5e38be81ae5..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub +++ /dev/null @@ -1,12 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: DSA Public Key for use with MyIsp -AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET -W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH -YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c -vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf -J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA -vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB -AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS -n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5 -sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub deleted file mode 100644 index 702e5c4fdec7..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub +++ /dev/null @@ -1,6 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: "256-bit ECDSA, converted by uabhnil@elxadlj3q32 from OpenSSH" -AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIJrVlKYIT+MlxxRx5 -BFXisHHkcGMAAKv2dguUeOsutsYyzs9JAczvl6c+Sypra5+qOi2LHPXw6GGluuXcOssOM= - ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub deleted file mode 100644 index e4d446147cf0..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub +++ /dev/null @@ -1,7 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: "1024-bit RSA, converted from OpenSSH by me@example.com" -x-command: /home/me/bin/lock-in-guest.sh -AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb -YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ -5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub deleted file mode 100644 index 761088b51775..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub +++ /dev/null @@ -1,13 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o -39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS -7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmt -isaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2 -sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRu -LDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368 -+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNW -jeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4f -uKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV22 -5JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRM -IB+X+OTUUI8= ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub deleted file mode 100644 index 8b8ccda8baf5..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub +++ /dev/null @@ -1,8 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Subject: me -Comment: 1024-bit rsa, created by me@example.com Mon Jan 15 \ -08:31:24 2001 -AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 -596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 -soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub deleted file mode 100644 index 7b42ced93edd..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub +++ /dev/null @@ -1,9 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: This is an example of a very very very very looooooooooooo\ -ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ -commment -x-command: /home/me/bin/lock-in-guest.sh -AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb -YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ -5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub deleted file mode 100644 index 7b42ced93edd..000000000000 --- a/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub +++ /dev/null @@ -1,9 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Comment: This is an example of a very very very very looooooooooooo\ -ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ -commment -x-command: /home/me/bin/lock-in-guest.sh -AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb -YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ -5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= ----- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 80c76827c650..7cb8ceddd416 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -59,6 +59,7 @@ eddsa_priv_pkcs8/1, eddsa_priv_rfc5958/0, eddsa_priv_rfc5958/1, + eddsa_sign_verify_24_compat/1, init_ec_pem_encode_generated/1, ec_pem_encode_generated/0, ec_pem_encode_generated/1, @@ -88,6 +89,8 @@ pkix_countryname/1, pkix_emailaddress/0, pkix_emailaddress/1, + pkix_decode_cert/0, + pkix_decode_cert/1, pkix_path_validation/0, pkix_path_validation/1, pkix_path_validation_root_expired/0, @@ -96,6 +99,8 @@ pkix_verify_hostname_subjAltName/1, pkix_verify_hostname_options/1, pkix_verify_hostname_subjAltName_IP/1, + pkix_dist_point_uri/0, + pkix_dist_point_uri/1, pkix_iso_rsa_oid/0, pkix_iso_rsa_oid/1, pkix_iso_dsa_oid/0, @@ -112,6 +117,8 @@ pkix_test_data_all_default/1, pkix_test_data/0, pkix_test_data/1, + pkix_is_issuer/0, + pkix_is_issuer/1, short_cert_issuer_hash/0, short_cert_issuer_hash/1, short_crl_issuer_hash/0, @@ -119,9 +126,13 @@ gen_ec_param_prime_field/0, gen_ec_param_prime_field/1, gen_ec_param_char_2_field/0, - gen_ec_param_char_2_field/1 + gen_ec_param_char_2_field/1, + cacerts_load/0, cacerts_load/1 ]). +-export([list_cacerts/0]). % debug exports + + -define(TIMEOUT, 120000). % 2 min -define(PASSWORD1, "1234abcd"). -define(PASSWORD2, "4567efgh"). @@ -142,6 +153,7 @@ all() -> pkix, pkix_countryname, pkix_emailaddress, + pkix_decode_cert, pkix_path_validation, pkix_path_validation_root_expired, pkix_iso_rsa_oid, @@ -154,10 +166,13 @@ all() -> pkix_verify_hostname_subjAltName, pkix_verify_hostname_subjAltName_IP, pkix_verify_hostname_options, + pkix_dist_point_uri, pkix_test_data_all_default, pkix_test_data, + pkix_is_issuer, short_cert_issuer_hash, - short_crl_issuer_hash + short_crl_issuer_hash, + cacerts_load ]. groups() -> @@ -168,7 +183,8 @@ groups() -> eddsa_priv_pkcs8, eddsa_priv_rfc5958, ec_pem_encode_generated, gen_ec_param_prime_field, gen_ec_param_char_2_field]}, - {sign_verify, [], [rsa_sign_verify, rsa_pss_sign_verify, dsa_sign_verify]} + {sign_verify, [], [rsa_sign_verify, rsa_pss_sign_verify, dsa_sign_verify, + eddsa_sign_verify_24_compat]} ]. %%------------------------------------------------------------------- init_per_suite(Config) -> @@ -219,6 +235,15 @@ init_per_testcase(rsa_pss_sign_verify, Config) -> false -> {skip, not_supported_by_crypto} end; + +init_per_testcase(eddsa_sign_verify_24_compat, Config) -> + case lists:member(eddsa, crypto:supports(public_keys)) of + true -> + Config; + false -> + {skip, eddsa_not_supported_by_crypto} + end; + init_per_testcase(TestCase, Config) -> case TestCase of ec_pem_encode_generated -> @@ -435,6 +460,61 @@ eddsa_priv_rfc5958(Config) when is_list(Config) -> ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem), ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])). +eddsa_sign_verify_24_compat(_Config) -> + Key = + {'ECPrivateKey',1, + <<15,192,10,239,169,93,9,105,143,13,221,71,191,255,201, + 60,8,80,43,234,82,68,151,219,233,144,174,41,227,241, + 229,232>>, + {namedCurve,{1,3,101,112}}, + <<209,208,142,135,125,251,57,203,2,49,232,74,238,214,170, + 181,23,107,221,39,187,225,106,19,34,133,117,198,138, + 180,16,70>>, + asn1_NOVALUE}, + Body = + <<83,83,72,83,73,71,0,0,0,4,116,101,120,116,0,0,0,0,0,0,0,6,115,104,97, + 53,49,50,0,0,0,64,119,199,206,154,93,134,187,56,109,68,59,185,99,144, + 250,161,32,99,49,88,105,156,136,68,195,11,19,171,11,249,39,96,183,228, + 65,106,234,57,125,185,27,74,192,229,221,86,184,239,126,75,6,97,98,171, + 31,220,8,131,25,206,109,239,200,118>>, + ExpectedSignature = + <<203,148,171,54,165,4,216,251,189,124,35,227,88,183,187,225,142,10,132,163,98, + 48,167,195,67,12,49,148,85,146,41,14,58,0,198,68,103,114,90,61,31,38,200,198, + 64,179,135,138,31,172,236,105,0,71,50,195,168,247,216,110,210,61,159,5>>, + lists:foreach( + fun(Sha) -> + ct:log("Try Sha = ~p", [Sha]), + try + case public_key:sign(Body, Sha, Key) of + ExpectedSignature -> + ct:log("sign Sha ~p ok", [Sha]), + ExpectedSignature; + Others -> + ct:log("Sha: ~p~nGot: ~p~nExpect: ~p", [Sha,Others,ExpectedSignature]), + ct:fail("Bad sign result") + end + of + Sig -> + try + case public_key:verify(Body, Sha, Sig, Key) of + true -> + ct:log("verify Sha ~p ok", [Sha]); + false -> + ct:fail("Bad verify result for ~p",[Sha]) + end + catch + C:E -> + ct:log("Verify: ~p:~p Sha = ~p", [C,E,Sha]), + ct:fail("Bad verify",[]) + end + catch + C:E -> + ct:log("Sign: ~p:~p Sha = ~p", [C,E,Sha]), + ct:fail("Bad sign",[]) + end + end, [undefined, none | crypto:supports(hashs)]). + + init_ec_pem_encode_generated(Config) -> case catch true = lists:member('secp384r1', crypto:ec_curves()) of {'EXIT', _} -> {skip, {'secp384r1', not_supported}}; @@ -466,32 +546,46 @@ encrypted_pem_pwdfun(Config) when is_list(Config) -> encrypted_pem(Config, Password1, Password2) -> Datadir = proplists:get_value(data_dir, Config), - [{'RSAPrivateKey', DerRSAKey, not_encrypted}] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")), - RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey), - - Salt0 = crypto:strong_rand_bytes(8), - Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, - {{"DES-EDE3-CBC", Salt0}, ?PASSWORD1}), - RSAKey = public_key:pem_entry_decode(Entry0, Password1), + SupportedCiphers = crypto:supports(ciphers), + SupportedECB = lists:member(des_ecb, SupportedCiphers), + SupportedDES = lists:member(des_cbc, SupportedCiphers), + case SupportedECB of + true -> + encrypted_pem_des_ede(Datadir, RSAKey, Password1); + false -> + ct:comment("DES-EDE3-CBC not supported") + end, + case SupportedDES of + true -> + encrypted_pem_des_cbc(Datadir, RSAKey, Password2); + false -> + ct:comment("DES-CBC not supported") + end. +encrypted_pem_des_ede(Datadir, RSAKey, Password) -> + Salt = crypto:strong_rand_bytes(8), + Entry = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, + {{"DES-EDE3-CBC", Salt}, ?PASSWORD1}), + RSAKey = public_key:pem_entry_decode(Entry, Password), Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"), - erl_make_certs:der_to_pem(Des3KeyFile, [Entry0]), - [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = - erl_make_certs:pem_to_der(Des3KeyFile), - - Salt1 = crypto:strong_rand_bytes(8), - Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, - {{"DES-CBC", Salt1}, ?PASSWORD2}), + erl_make_certs:der_to_pem(Des3KeyFile, [Entry]), + [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt}}] = + erl_make_certs:pem_to_der(Des3KeyFile). + +encrypted_pem_des_cbc(Datadir, RSAKey, Password) -> + Salt = crypto:strong_rand_bytes(8), + Entry = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, + {{"DES-CBC", Salt}, ?PASSWORD2}), DesKeyFile = filename:join(Datadir, "des_client_key.pem"), - erl_make_certs:der_to_pem(DesKeyFile, [Entry1]), - [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} = Entry2] = + erl_make_certs:der_to_pem(DesKeyFile, [Entry]), + [{'RSAPrivateKey', _, {"DES-CBC", Salt}} = Entry] = erl_make_certs:pem_to_der(DesKeyFile), {ok, Pem} = file:read_file(DesKeyFile), check_encapsulated_header(Pem), - true = check_entry_type(public_key:pem_entry_decode(Entry2, Password2), - 'RSAPrivateKey'). + true = check_entry_type(public_key:pem_entry_decode(Entry, Password), + 'RSAPrivateKey'). %%-------------------------------------------------------------------- @@ -673,7 +767,7 @@ pkix(Config) when is_list(Config) -> true = lists:member(IssuerId, CaIds), - %% Should be normalized allready + %% Should be normalized already TestStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}], [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]}, @@ -707,6 +801,17 @@ pkix_emailaddress(Config) when is_list(Config) -> check_emailaddress(Issuer), check_emailaddress(Subj). + +%%-------------------------------------------------------------------- +pkix_decode_cert() -> + [{doc, "Test that extension IssuerDistributionPoint is not decoded in 'otp' decoding mode. We want to leave it for later " + "to increase interopability for sites that does not use this extension and will not care if it is properly encoded"}]. +pkix_decode_cert(Config) when is_list(Config) -> + Der = base64:decode( + <<"MIICXDCCAgKgAwIBAgIBATAKBggqhkjOPQQDAjApMRkwFwYDVQQFExBjOTY4NDI4OTMyNzUwOGRiMQwwCgYDVQQMDANURUUwHhcNMjIxMDI5MTczMTA3WhcNMjkwNDE2MjAzNDUzWjAfMR0wGwYDVQQDExRBbmRyb2lkIEtleXN0b3JlIEtleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFmIQDus/jIZ0cPnRCITCzUUuCjQBw8MetO6154mmTL8O/fFlGgYkZ6C8jSSntKC/lMwaZHxAgW1AGgoCrPuX5ejggEjMIIBHzALBgNVHQ8EBAMCB4AwCAYDVR0fBAEAMIIBBAYKKwYBBAHWeQIBEQSB9TCB8gIBAgoBAQIBAwoBAQQgyvsSa116xqleaXs6xA84wqpAPWFgaaTjCWBnZpHslmoEADBEv4VFQAQ+MDwxFjAUBAxjb20ud2hhdHNhcHACBA0+oAQxIgQgOYfQQ9EK769ahxCzZxQY/lfg4ZtlPJ34JVj+tf/OXUQweqEFMQMCAQKiAwIBA6MEAgIBAKUIMQYCAQYCAQSqAwIBAb+DdwIFAL+FPQgCBgGEJMweob+FPgMCAQC/hUAqMCgEIFNB5rJkaXmnDldlMAeh8xAWlCHsm92fGlZI91reAFrxAQH/CgEAv4VBBQIDAV+Qv4VCBQIDAxUYMAoGCCqGSM49BAMCA0gAMEUCIF0BwvRQipVoaz5SIhsYbIeK+FHbAjWPgOxWgQ6Juq64AiEA83ZLsK37DjZ/tZNRi271VHQqIU8mdqUIMboVUiy3DaM=">>), + + #'OTPCertificate'{} = public_key:pkix_decode_cert(Der, otp). + %%-------------------------------------------------------------------- pkix_path_validation() -> [{doc, "Test PKIX path validation"}]. @@ -734,8 +839,12 @@ pkix_path_validation(Config) when is_list(Config) -> {error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], []), - + {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1, Cert2], []), + + {error, {bad_cert, duplicate_cert_in_path}} = + public_key:pkix_path_validation(Trusted, [Cert1, Cert1, Cert2], []), + {error, issuer_not_found} = public_key:pkix_issuer_id(Cert2, other), CertK3 = {Cert3,_} = erl_make_certs:make_cert([{issuer, CertK1}, @@ -887,19 +996,19 @@ pkix_verify_hostname_subjAltName(Config) -> true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]), true = public_key:pkix_verify_hostname(Cert, [{dns_id,"KB.EXAMPLE.ORG"}]), - %% Check that a dns_id does not match a DNS subjAltName wiht wildcard + %% Check that a dns_id does not match a DNS subjAltName with wildcard false = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}]), - %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun + %% Check that a dns_id does match a DNS subjAltName with wildcard with matchfun MatchFun = {match_fun, public_key:pkix_verify_hostname_match_fun(https)}, true = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}], [MatchFun]), true = public_key:pkix_verify_hostname(Cert, [{dns_id,"OTHER.EXAMPLE.ORG"}], [MatchFun]), - %% Check that a uri_id does not match a DNS subjAltName wiht wildcard + %% Check that a uri_id does not match a DNS subjAltName with wildcard false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}]), false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://OTHER.EXAMPLE.ORG"}]), - %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun + %% Check that a dns_id does match a DNS subjAltName with wildcard with matchfun true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}], [MatchFun]), true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://OTHER.EXAMPLE.ORG"}], [MatchFun]), true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://OTHER.example.org"}], [MatchFun]), @@ -995,7 +1104,27 @@ pkix_verify_hostname_subjAltName_IP(Config) -> true = public_key:pkix_verify_hostname(Cert, [{ip, {10,67,16,75}}]), false = public_key:pkix_verify_hostname(Cert, [{ip, {1,2,3,4}}]), false = public_key:pkix_verify_hostname(Cert, [{ip, {10,11,12,13}}]). + + %%-------------------------------------------------------------------- + +pkix_dist_point_uri() -> + [{doc, "Disregard ldap URIs in code path handling HTTP URIs"}]. +pkix_dist_point_uri(Config) when is_list(Config) -> + Datadir = proplists:get_value(data_dir, Config), + {ok, PemCert} = file:read_file(filename:join(Datadir, "ldap_uri_cert.pem")), + [{_, Cert, _}] = public_key:pem_decode(PemCert), + #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp), + + Extensions = pubkey_cert:extensions_list(TBSCert#'OTPTBSCertificate'.extensions), + DpExt = pubkey_cert:select_extension(?'id-ce-cRLDistributionPoints', Extensions), + #'Extension'{extnValue = DPs} = DpExt, + [#'DistributionPoint'{distributionPoint = {fullName, DPNames}}|_] = DPs, + ct:pal("~p", [DPNames]), + true = pubkey_crl:match_one(DPNames, [{uniformResourceIdentifier, "http://ca.eait.uq.edu.au/crl/labs-LILY-CA"}]). + +%%-------------------------------------------------------------------- + pkix_iso_rsa_oid() -> [{doc, "Test workaround for supporting certs that use ISO oids" " 1.3.14.3.2.29 instead of PKIX/PKCS oid"}]. @@ -1123,6 +1252,7 @@ pkix_test_data_all_default(Config) when is_list(Config) -> check_conf_member(ServerConf1, [key, cert, cacerts]), check_conf_member(ClientConf1, [key, cert, cacerts]). +%%-------------------------------------------------------------------- pkix_test_data() -> [{doc, "Test API function pkix_test_data/1"}]. @@ -1167,6 +1297,23 @@ check_conf_member(Conf, [Member | Rest]) -> ct:fail({misssing_conf, Member}) end. +%%-------------------------------------------------------------------- +pkix_is_issuer() -> + [{doc, "Test pubkey_cert:pkix_is_issuer with cert that have diffent cases on countryname"}]. + +pkix_is_issuer(Config) when is_list(Config) -> + Upper = {rdnSequence, + [[{'AttributeTypeAndValue',{2,5,4,6},"GB"}], + [{'AttributeTypeAndValue',{2,5,4,10},{utf8String,<<"MYORG">>}}], + [{'AttributeTypeAndValue',{2,5,4,11},{utf8String,<<"INTERMEDIATE">>}}], + [{'AttributeTypeAndValue',{2,5,4,3},{utf8String,<<"INTERMEDIATE">>}}]]}, + Lower = {rdnSequence, + [[{'AttributeTypeAndValue',{2,5,4,6},"gb"}], + [{'AttributeTypeAndValue',{2,5,4,10},{utf8String,<<"MYORG">>}}], + [{'AttributeTypeAndValue',{2,5,4,11},{utf8String,<<"INTERMEDIATE">>}}], + [{'AttributeTypeAndValue',{2,5,4,3},{utf8String,<<"INTERMEDIATE">>}}]]}, + true = pubkey_cert:is_issuer(Upper, Lower). + %%-------------------------------------------------------------------- short_cert_issuer_hash() -> [{doc, "Test OpenSSL-style hash for certificate issuer"}]. @@ -1216,6 +1363,105 @@ gen_ec_param_char_2_field(Config) when is_list(Config) -> Datadir = proplists:get_value(data_dir, Config), do_gen_ec_param(filename:join(Datadir, "ec_key_param1.pem")). +%%-------------------------------------------------------------------- +cacerts_load() -> + [{doc, "Basic tests of cacerts functionality"}]. +cacerts_load(Config) -> + Datadir = proplists:get_value(data_dir, Config), + {error, enoent} = public_key:cacerts_load("/dummy.file"), + %% Load default OS certs + %% there is no default installed OS certs on netbsd + %% can be installed with 'pkgin install mozilla-rootcerts' + IsNetBsd = element(2, os:type()) =:= netbsd, + OsCerts = try + Certs = public_key:cacerts_get(), + true = public_key:cacerts_clear(), + Certs + catch _:{badmatch, {error, enoent}} when IsNetBsd -> netbsd + end, + + false = public_key:cacerts_clear(), + + %% Reload from file + ok = public_key:cacerts_load(filename:join(Datadir, "cacerts.pem")), + [_TestCert1, _TestCert2] = public_key:cacerts_get(), + + %% Re-Load default OS certs + try + process_flag(trap_exit, true), + flush(), + ok = public_key:cacerts_load(), + [] = flush(), + ct:log("~p: ~p~n", [os:type(), length(OsCerts)]), + OsCerts = public_key:cacerts_get(), + Ids = cert_info(OsCerts), + Check = fun(ShouldBeThere) -> + lists:any(fun(#{id:=Id}) -> lists:prefix(ShouldBeThere, Id) end, Ids) + end, + case lists:partition(Check, ["digicert", "globalsign"]) of + {_, []} -> ok; + {_, Fail} -> + cert_info(OsCerts), + [] = Fail + end, + ok + catch _:{badmatch, {error, enoent}} when IsNetBsd -> + ok + end. + +flush() -> + receive Msg -> [Msg|flush()] + after 500 -> [] + end. + +cert_info([#cert{der=Der, otp=#'OTPCertificate'{tbsCertificate = C0}=Cert}|Rest]) when is_binary(Der) -> + #'OTPTBSCertificate'{subject = Subject, serialNumber = _Nr, issuer = Issuer0} = C0, + C = case public_key:pkix_is_self_signed(Cert) of + true -> #{id => subject(Subject), ss => true}; + false -> + case public_key:pkix_issuer_id(Cert, other) of + {ok, {_IsNr, Issuer}} -> + #{id => subject(Subject), ss => false, issuer => subject(Issuer)}; + {error, _} -> + #{id => subject(Subject), ss => false, issuer => subject(Issuer0)} + end + end, + [C|cert_info(Rest)]; +cert_info([]) -> + []. + + +subject(S) -> + string:lowercase(subject(public_key:pkix_normalize_name(S), "unknown")). + +subject({rdnSequence, Seq}, Def) -> + subject(Seq, Def); +subject([[{'AttributeTypeAndValue', ?'id-at-commonName', Name0}]|_], _Def) -> + case Name0 of + {printableString, Name} -> Name; + {utf8String, Name} -> unicode:characters_to_list(Name); + Name -> Name + end; +subject([[{'AttributeTypeAndValue', ?'id-at-organizationName', Name0}]|Rest], _Def) -> + Name = case Name0 of + {printableString, Name1} -> Name1; + {utf8String, Name1} -> unicode:characters_to_list(Name1); + Name1 -> Name1 + end, + subject(Rest, Name); +subject([_|R], Def) -> + subject(R, Def); +subject([], Def) -> + Def. + +list_cacerts() -> + Certs = public_key:cacerts_get(), + %% io:format("~P~n",[Certs, 20]), + IO = fun(C, N) -> io:format("~.3w:~0p~n", [N,C]), N+1 end, + lists:foldl(IO, 0, lists:sort(cert_info(Certs))), + ok. + + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -1323,7 +1569,8 @@ crypto_supported_curve(Curve, _Curves) -> catch _:_-> false end. - + + incorrect_countryname_pkix_cert() -> <<48,130,5,186,48,130,4,162,160,3,2,1,2,2,7,7,250,61,63,6,140,137,48,13,6,9,42, 134,72,134,247,13,1,1,5,5,0,48,129,220,49,11,48,9,6,3,85,4,6,19,2,85,83,49, 16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19, 10,83,99,111,116,116,115,100,97,108,101,49,37,48,35,6,3,85,4,10,19,28,83,116, 97,114,102,105,101,108,100,32,84,101,99,104,110,111,108,111,103,105,101,115, 44,32,73,110,99,46,49,57,48,55,6,3,85,4,11,19,48,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 49,49,48,47,6,3,85,4,3,19,40,83,116,97,114,102,105,101,108,100,32,83,101,99, 117,114,101,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117, 116,104,111,114,105,116,121,49,17,48,15,6,3,85,4,5,19,8,49,48,54,56,56,52,51, 53,48,30,23,13,49,48,49,48,50,51,48,49,51,50,48,53,90,23,13,49,50,49,48,50, 51,48,49,51,50,48,53,90,48,122,49,11,48,9,6,3,85,4,6,12,2,85,83,49,11,48,9,6, 3,85,4,8,12,2,65,90,49,19,48,17,6,3,85,4,7,12,10,83,99,111,116,116,115,100, 97,108,101,49,38,48,36,6,3,85,4,10,12,29,83,112,101,99,105,97,108,32,68,111, 109,97,105,110,32,83,101,114,118,105,99,101,115,44,32,73,110,99,46,49,33,48, 31,6,3,85,4,3,12,24,42,46,108,111,103,105,110,46,115,101,99,117,114,101,115, 101,114,118,101,114,46,110,101,116,48,130,1,34,48,13,6,9,42,134,72,134,247, 13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,185,136,240,80,141,36,124, 245,182,130,73,19,188,74,166,117,72,228,185,209,43,129,244,40,44,193,231,11, 209,12,234,88,43,142,1,162,48,122,17,95,230,105,171,131,12,147,46,204,36,80, 250,171,33,253,35,62,83,22,71,212,186,141,14,198,89,89,121,204,224,122,246, 127,110,188,229,162,67,95,6,74,231,127,99,131,7,240,85,102,203,251,50,58,58, 104,245,103,181,183,134,32,203,121,232,54,32,188,139,136,112,166,126,14,91, 223,153,172,164,14,61,38,163,208,215,186,210,136,213,143,70,147,173,109,217, 250,169,108,31,211,104,238,103,93,182,59,165,43,196,189,218,241,30,148,240, 109,90,69,176,194,52,116,173,151,135,239,10,209,179,129,192,102,75,11,25,168, 223,32,174,84,223,134,70,167,55,172,143,27,130,123,226,226,7,34,142,166,39, 48,246,96,231,150,84,220,106,133,193,55,95,159,227,24,249,64,36,1,142,171,16, 202,55,126,7,156,15,194,22,116,53,113,174,104,239,203,120,45,131,57,87,84, 163,184,27,83,57,199,91,200,34,43,98,61,180,144,76,65,170,177,2,3,1,0,1,163, 130,1,224,48,130,1,220,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,0,48,29,6,3, 85,29,37,4,22,48,20,6,8,43,6,1,5,5,7,3,1,6,8,43,6,1,5,5,7,3,2,48,14,6,3,85, 29,15,1,1,255,4,4,3,2,5,160,48,56,6,3,85,29,31,4,49,48,47,48,45,160,43,160, 41,134,39,104,116,116,112,58,47,47,99,114,108,46,115,116,97,114,102,105,101, 108,100,116,101,99,104,46,99,111,109,47,115,102,115,50,45,48,46,99,114,108, 48,83,6,3,85,29,32,4,76,48,74,48,72,6,11,96,134,72,1,134,253,110,1,7,23,2,48, 57,48,55,6,8,43,6,1,5,5,7,2,1,22,43,104,116,116,112,115,58,47,47,99,101,114, 116,115,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99,111,109, 47,114,101,112,111,115,105,116,111,114,121,47,48,129,141,6,8,43,6,1,5,5,7,1, 1,4,129,128,48,126,48,42,6,8,43,6,1,5,5,7,48,1,134,30,104,116,116,112,58,47, 47,111,99,115,112,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99, 111,109,47,48,80,6,8,43,6,1,5,5,7,48,2,134,68,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 47,115,102,95,105,110,116,101,114,109,101,100,105,97,116,101,46,99,114,116, 48,31,6,3,85,29,35,4,24,48,22,128,20,73,75,82,39,209,27,188,242,161,33,106, 98,123,81,66,122,138,215,213,86,48,59,6,3,85,29,17,4,52,48,50,130,24,42,46, 108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118,101,114,46,110, 101,116,130,22,108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118, 101,114,46,110,101,116,48,29,6,3,85,29,14,4,22,4,20,138,233,191,208,157,203, 249,85,242,239,20,195,48,10,148,49,144,101,255,116,48,13,6,9,42,134,72,134, 247,13,1,1,5,5,0,3,130,1,1,0,82,31,121,162,49,50,143,26,167,202,143,61,71, 189,201,199,57,81,122,116,90,192,88,24,102,194,174,48,157,74,27,87,210,223, 253,93,3,91,150,109,120,1,110,27,11,200,198,141,222,246,14,200,71,105,41,138, 13,114,122,106,63,17,197,181,234,121,61,89,74,65,41,231,248,219,129,83,176, 219,55,107,55,211,112,98,38,49,69,77,96,221,108,123,152,12,210,159,157,141, 43,226,55,187,129,3,82,49,136,66,81,196,91,234,196,10,82,48,6,80,163,83,71, 127,102,177,93,209,129,26,104,2,84,24,255,248,161,3,244,169,234,92,122,110, 43,4,17,113,185,235,108,219,210,236,132,216,177,227,17,169,58,162,159,182, 162,93,160,229,200,9,163,229,110,121,240,168,232,14,91,214,188,196,109,210, 164,222,0,109,139,132,113,91,16,118,173,178,176,80,132,34,41,199,51,206,250, 224,132,60,115,192,94,107,163,219,212,226,225,65,169,148,108,213,46,174,173, 103,110,189,229,166,149,254,31,51,44,144,108,187,182,11,251,201,206,86,138, 208,59,51,86,132,235,81,225,88,34,190,8,184>>. @@ -1367,7 +1614,7 @@ hardcode_rsa_key(3) -> exponent2 = 137572620950115585809189662580789132500998007785886619351549079675566218169991569609420548245479957900898715184664311515467504676010484619686391036071176762179044243478326713135456833024206699951987873470661533079532774988581535389682358631768109586527575902839864474036157372334443583670210960715165278974609, coefficient = 15068630434698373319269196003209754243798959461311186548759287649485250508074064775263867418602372588394608558985183294561315208336731894947137343239541687540387209051236354318837334154993136528453613256169847839789803932725339395739618592522865156272771578671216082079933457043120923342632744996962853951612, otherPrimeInfos = asn1_NOVALUE}; -hardcode_rsa_key(4) -> +hardcode_rsa_key(4) -> #'RSAPrivateKey'{ version ='two-prime', modulus = 28617237755030755643854803617273584643843067580642149032833640135949799721163782522787597288521902619948688786051081993247908700824196122780349730169173433743054172191054872553484065655968335396052034378669869864779940355219732200954630251223541048434478476115391643898092650304645086338265930608997389611376417609043761464100338332976874588396803891301015812818307951159858145399281035705713082131199940309445719678087542976246147777388465712394062188801177717719764254900022006288880246925156931391594131839991579403409541227225173269459173129377291869028712271737734702830877034334838181789916127814298794576266389, @@ -1388,4 +1635,3 @@ pss_params(sha256) -> }, saltLength = 32, trailerField = 1}. - diff --git a/lib/public_key/test/public_key_SUITE_data/ldap_uri_cert.pem b/lib/public_key/test/public_key_SUITE_data/ldap_uri_cert.pem new file mode 100644 index 000000000000..2c6dbad9fa58 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ldap_uri_cert.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGIjCCBQqgAwIBAgITWwAAByiISJBWTJahTQAAAAAHKDANBgkqhkiG9w0BAQsF +ADCBgDESMBAGCgmSJomT8ixkARkWAmF1MRMwEQYKCZImiZPyLGQBGRYDZWR1MRIw +EAYKCZImiZPyLGQBGRYCdXExFDASBgoJkiaJk/IsZAEZFgRlYWl0MRQwEgYKCZIm +iZPyLGQBGRYEbGFiczEVMBMGA1UEAwwMbGFicy1MSUxZLUNBMB4XDTIyMTAxMjIz +MjgwNVoXDTIyMTEwOTIzMjgwNVowKTEnMCUGA1UEAxMeZ3M0MzItODEyNS5sYWJz +LmVhaXQudXEuZWR1LmF1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +wuWgx3RlNrtapvbXc5RBroyCbXGu1Zefmq70PUiHrxHQIhmExjN4sdBd7Q5biKY4 +lr++4I49Z8FbOLw+MypmK0SG6BqYtrL+1Y/GMqAmeox6RbWVkIfLTJHqxdvmTjEX +Kr9KbL7/5JOMSyDLv9ygqE5GS3IAjaDvwP6BeU3yJDkeSPotiCK2Pxm0Owo9g0a7 +C4UACCn2wzdo5g1xIeWoSejNC2ZMec8Ug1NWiuUq7FVw5+UzUkf4mqajndO6xJVi +EGOaW59197iqj/vz3Rl58Gr7pKQHyE3TtZI8Jt+PrRuUD68JEnpR7ZX3HEERnczD +2fejPM0v4AX725vuwCtkPQIDAQABo4IC6TCCAuUwHQYJKwYBBAGCNxQCBBAeDgBN +AGEAYwBoAGkAbgBlMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAOBgNV +HQ8BAf8EBAMCBaAwHQYDVR0OBBYEFNh+7KXQHE7Sxaze06Wna9IHRWIWMB8GA1Ud +IwQYMBaAFOoq6NmbC3CwMRapHGF6uqpJiKzvMIIBAwYDVR0fBIH7MIH4MIH1oIHy +oIHvhoHBbGRhcDovLy9DTj1sYWJzLUxJTFktQ0EsQ049bGlseSxDTj1DRFAsQ049 +UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJh +dGlvbixEQz1sYWJzLERDPWVhaXQsREM9dXEsREM9ZWR1LERDPWF1P2NlcnRpZmlj +YXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRp +b25Qb2ludIYpaHR0cDovL2NhLmVhaXQudXEuZWR1LmF1L2NybC9sYWJzLUxJTFkt +Q0Ewgc8GCCsGAQUFBwEBBIHCMIG/MIG8BggrBgEFBQcwAoaBr2xkYXA6Ly8vQ049 +bGFicy1MSUxZLUNBLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxD +Tj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWxhYnMsREM9ZWFpdCxEQz11 +cSxEQz1lZHUsREM9YXU/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNl +cnRpZmljYXRpb25BdXRob3JpdHkwKQYDVR0RBCIwIIIeZ3M0MzItODEyNS5sYWJz +LmVhaXQudXEuZWR1LmF1MFEGCSsGAQQBgjcZAgREMEKgQAYKKwYBBAGCNxkCAaAy +BDBTLTEtNS0yMS0xOTc2MTAwMzA2LTE3MzE1MDIwOTctMzk0MjQwMTc2Ni0xMjMy +MDcwDQYJKoZIhvcNAQELBQADggEBAMDVF3QK4Tgz2cu+UNbEnIQVDK9mx07kNDMO +X0SUD8SNEP5LWhpLZoltInJ0s3ID8T7Rjf0bFw+eykp4/prVqENuDNj6lYxY/2ho +WgJ7FKSqCNvkFzR2Bln20p6HFq8Jgz1R3uO3bVZ0RGUebUoT3PvF5t0d+xUg1Es9 +kYNxTRvNsFDvwpHg583R3bgO6Bqsi6ohTEW0/Xc3+d99dA+1F8So3DgXFnrb1wyT +/D+xxIqq/BTAO771oxiujzlBYUewkjf2+JMQTc/mCJHHwCZxC4kgxqS9T2vuk2Hv +CBsqnxGzixobGISmglAKAJvfckzWcF4iYwGPK9sSBkXSIAT5OOU= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index e987d4b3dfd9..90a474ba49dc 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 1.12.0.1 +PUBLIC_KEY_VSN = 1.14.1 diff --git a/lib/reltool/Makefile b/lib/reltool/Makefile index 94534ee2b7d4..50ac3b443ed1 100644 --- a/lib/reltool/Makefile +++ b/lib/reltool/Makefile @@ -37,5 +37,6 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk DIA_PLT_APPS=wx sasl +TEST_NEEDS_RELEASE=true include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml index d469c8d9a920..e9e128628532 100644 --- a/lib/reltool/doc/src/notes.xml +++ b/lib/reltool/doc/src/notes.xml @@ -5,7 +5,7 @@
    2009 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -38,7 +38,60 @@ thus constitutes one section in this document. The title of each section is the version number of Reltool.

    -
    Reltool 0.9 +
    Reltool 1.0 + +
    Improvements and New Features + + +

    + Add possibility to strip specific chunks from beam files + included in a release. Before this change it was only + possible to strip all chunks from the beam files.

    +

    + Own Id: OTP-18230 Aux Id: PR-5936

    +
    + +

    Runtime dependencies have been updated.

    +

    + Own Id: OTP-18350

    +
    + +

    Support for the experimental code archives feature has + been removed from reltool.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18488 Aux Id: PR-6836

    +
    + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    Reltool 0.9.1 + +
    Fixed Bugs and Malfunctions + + +

    Fixed a bug that would cause analysis to crash.

    +

    + Own Id: OTP-18372 Aux Id: GH-6580

    +
    +
    +
    + +
    + +
    Reltool 0.9
    Improvements and New Features @@ -404,7 +457,7 @@ reltool config does not contain all applications that are listed as {applications,Applications} in a .app file, then these applications are - autmatically added when creating the .rel file. + automatically added when creating the .rel file. For 'included_applications', the behaviour was not the same. I.e. if a rel spec in the reltool config did not contain all applications that are listed as @@ -455,10 +508,10 @@ A new sys level configuration parameter {excl_lib,otp_root} is added. When this is set, the target system will not contain anything from - $OTP_ROOT. It will only contain a releases + $OTPROOT. It will only contain a releases directory with rel, script and boot files, and a lib directory with applications found outside of - $OTP_ROOT (i.e. "your own" applications).

    + $OTPROOT (i.e. "your own" applications).

    Own Id: OTP-9743

    @@ -508,7 +561,7 @@ Status bar now indicates that reltool is working (Processing libraries...) for all configuration changes, and when generating target system. Title - of dependecies column in app and mod window is changed + of dependencies column in app and mod window is changed from "Modules used by others" to "Modules using this".

    @@ -668,7 +721,7 @@

    Allow the same module name in multiple applications visible to reltool, as long as all but one of the - applications/modules are explicitely excluded. (Thanks to + applications/modules are explicitly excluded. (Thanks to Andrew Gopienko and Jay Nelson)

    Own Id: OTP-9229

    diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml index 136ec2ed6991..b71c1a21995a 100644 --- a/lib/reltool/doc/src/reltool.xml +++ b/lib/reltool/doc/src/reltool.xml @@ -5,7 +5,7 @@
    2009 - 2018 + 2023 Ericsson AB, All Rights Reserved @@ -226,10 +226,10 @@ debug_info -

    The debug_info parameter controls whether the debug - information in the beam file should be kept (keep) or - stripped strip when the file is copied to the target - system.

    +

    The debug_info parameter controls what debug + information in the beam file should be kept or stripped. + keep keeps all debug info, strip strips all debug + info, and a list of chunkids keeps only those chunks.

    excl_lib @@ -237,11 +237,11 @@

    This option is experimental.

    If the excl_lib option is set to otp_root then reltool will not copy anything from the Erlang/OTP - installation ($OTP_ROOT) into the target structure. The goal + installation ($OTPROOT) into the target structure. The goal is to create a "slim" release which can be used together with an existing Erlang/OTP installation. The target structure will therefore only contain a lib directory with the - applications that were found outside of $OTP_ROOT (typically + applications that were found outside of $OTPROOT (typically your own applications), and a releases directory with the generated .rel, .script and .boot files.

    @@ -251,14 +251,14 @@ Which releases directory to use Tell the release handler to use the releases directory in our target structure instead of - $OTP_ROOT/releases. This is done by setting the SASL + $OTPROOT/releases. This is done by setting the SASL environment variable releases_dir, either from the command line (-sasl releases_dir <target-dir>/releases) or in sys.config. Which boot file to use - The default boot file is $OTP_ROOT/bin/start, + The default boot file is $OTPROOT/bin/start, but in this case we need to specify a boot file from our target structure, typically <target-dir>/releases/<vsn>/<RelName>. This @@ -325,40 +325,6 @@ [].

    - incl_archive_filters - -

    This parameter normally contains a list of regular - expressions that controls which top level directories in an - application should be included in an archive file (as - opposed to being included as a regular directory outside the - archive). Each top directory in the application must match at - least one of the listed regular expressions in order to be - included. Further the files may not match any filter in - excl_app_filters in order to be included. This - parameter defaults to [".*"].

    -
    - - excl_archive_filters - -

    This parameter normally contains a list of regular - expressions that controls which top level directories in an - application should not be included in an archive file. In - order to be included in the application archive, a top - directory must match some filter in incl_archive_filters - but not any filter in excl_archive_filters. This - parameter defaults to ["^include$","^priv$"].

    -
    - - archive_opts - -

    This parameter contains a list of options that are given to - zip:create/3 when application specific files are - packaged into an archive. Only a subset of the options are - supported. The most useful options in this context are the ones - that control which types of files should be compressed. This - parameter defaults to [].

    -
    -

    On application (escript) level, the following options are @@ -386,7 +352,7 @@ will be chosen.

    Note that in order for reltool to sort application versions and thereby be able to select the latest, it is required that - the version id for the application consits of integers and + the version id for the application consists of integers and dots only, for example 1, 2.0 or 3.17.1.

    @@ -402,7 +368,7 @@ will be chosen.

    Note that in order for reltool to sort application versions and thereby be able to select the latest, it is required that - the version id for the application consits of integers and + the version id for the application consists of integers and dots only, for example 1, 2.0 or 3.17.1.

    @@ -441,24 +407,6 @@

    The value of this parameter overrides the parameter with the same name on system level.

    - - incl_archive_filters - -

    The value of this parameter overrides the parameter with the - same name on system level.

    -
    - - excl_archive_filters - -

    The value of this parameter overrides the parameter with the - same name on system level.

    -
    - - archive_opts - -

    The value of this parameter overrides the parameter with the - same name on system level.

    -

    On module (mod) level, the following options are @@ -511,9 +459,6 @@ sys() = {root_dir, root_dir()} | {excl_sys_filters, excl_sys_filters()} | {incl_app_filters, incl_app_filters()} | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()} - | {archive_opts, [archive_opt()]} app() = {vsn, app_vsn()} | {lib_dir, lib_dir()} | {mod, mod_name(), [mod()]} @@ -526,9 +471,6 @@ app() = {vsn, app_vsn()} | {excl_sys_filters, excl_sys_filters()} | {incl_app_filters, incl_app_filters()} | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()} - | {archive_opts, [archive_opt()]} mod() = {incl_cond, incl_cond()} | {debug_info, debug_info()} rel_app() = app_name() @@ -539,21 +481,18 @@ rel_opt() = {load_dot_erlang, boolean()} app_name() = atom() app_type() = permanent | transient | temporary | load | none app_vsn() = string() -archive_opt = zip_create_opt() boot_rel() = rel_name() app_file() = keep | strip | all -debug_info() = keep | strip +debug_info() = keep | strip | [beam_lib:chunkid()] dir() = string() escript() = {incl_cond, incl_cond()} escript_file() = file() excl_app_filters() = regexps() -excl_archive_filters() = regexps() excl_lib() = otp_root excl_sys_filters() = regexps() file() = string() incl_app() = app_name() incl_app_filters() = regexps() -incl_archive_filters() = regexps() incl_cond() = include | exclude | derived incl_sys_filters() = regexps() lib_dir() = dir() @@ -582,7 +521,6 @@ top_file() = file() target_spec() = [target_spec()] | {create_dir, base_dir(), [target_spec()]} | {create_dir, base_dir(), top_dir(), [target_spec()]} - | {archive, base_file(), [archive_opt()], [target_spec()]} | {copy_file, base_file()} | {copy_file, base_file(), top_file()} | {write_file, base_file(), iolist()} @@ -632,7 +570,7 @@ target_spec() = [target_spec()] releases directory contains generated rel, script, and boot files. The lib directory contains the applications. Which applications are included - and if they should be customized (archived, stripped from debug + and if they should be customized (stripped from debug info etc.) is specified with various configuration parameters. The files in the bin directory are copied from the erts-vsn/bin directory, but only those files diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml index b77217dbf784..a29403da7800 100644 --- a/lib/reltool/doc/src/reltool_examples.xml +++ b/lib/reltool/doc/src/reltool_examples.xml @@ -5,7 +5,7 @@

    2009 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -136,9 +136,6 @@ Eshell V9.0 (abort with ^G) {excl_sys_filters,[]}, {incl_app_filters,[".*"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,[[...]|...]}, - {archive_opts,[]}, {rel_app_type,...}, {...}|...]}} 6> @@ -270,9 +267,6 @@ Eshell V9.0 (abort with ^G) "^erts.*/bin/.*(debug|pdb)"]}, {incl_app_filters,["^ebin","^include","^priv"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {embedded_app_type,load}, {app_file,keep}, @@ -296,9 +290,6 @@ Eshell V9.0 (abort with ^G) "^erts.*/bin/.*(debug|pdb)"]}, {incl_app_filters,["^ebin","^priv"]}, {excl_app_filters,["^ebin/.*\\.appup$"]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {app_file,keep}, {debug_info,keep}]}} @@ -432,16 +423,13 @@ Eshell V10.0 (abort with ^G) [{copy_file,"makewhatis"},{copy_file,"format_man_pages"}]}, {create_dir,"usr", [{create_dir,"lib", - [{copy_file,"liberts.a"}, - {copy_file,"liberl_interface_st.a"}, - {copy_file,"liberts_r.a"}, + [{copy_file,"liberl_interface_st.a"}, {copy_file,"libic.a"}, {copy_file,"liberl_interface.a"}, {copy_file,"libei_st.a"}, {copy_file,"libei.a"}]}, {create_dir,"include", - [{copy_file,"erl_memory_trace_parser.h"}, - {copy_file,"driver_int.h"}, + [{copy_file,"driver_int.h"}, {copy_file,"ei_connect.h"}, {copy_file,"ei.h"}, {copy_file,"erl_nif_api_funcs.h"}, @@ -476,8 +464,7 @@ Eshell V10.0 (abort with ^G) {copy_file,"liberts_internal_r.a"}, {copy_file,"libethread.a"}, {copy_file,"README"}]}, - {copy_file,"liberts.a"}, - {copy_file,"liberts_r.a"}]}, + ]}, {create_dir,"src",[{copy_file,"setuid_socket_wrap.c"}]}, {create_dir,"doc",[]}, {create_dir,"man",[]}, @@ -488,7 +475,6 @@ Eshell V10.0 (abort with ^G) {copy_file,[...]}, {copy_file,...}, {...}|...]}, - {copy_file,"erl_memory_trace_parser.h"}, {copy_file,"driver_int.h"}, {copy_file,"erl_nif_api_funcs.h"}, {copy_file,"erl_fixed_size_int_types.h"}, @@ -497,47 +483,41 @@ Eshell V10.0 (abort with ^G) {copy_file,...}, {...}]}]}, {create_dir,"lib", - [{archive,"compiler-7.0.4.ez",[], - [{create_dir,"compiler-7.0.4", - [{create_dir,"src", - [{copy_file,"beam_flatten.erl"}, - {copy_file,[...]}, - {copy_file,...}, - {...}|...]}, - {create_dir,"ebin", - [{copy_file,[...]},{copy_file,...},{...}|...]}]}]}, - {archive,"crypto-3.7.4.ez",[], - [{create_dir,"crypto-3.7.4", - [{create_dir,"src",[{copy_file,[...]},{copy_file,...}]}, - {create_dir,"ebin",[{copy_file,...},{...}|...]}]}]}, + [{create_dir,"compiler-7.0.4", + [{create_dir,"src", + [{copy_file,"beam_flatten.erl"}, + {copy_file,[...]}, + {copy_file,...}, + {...}|...]}, + {create_dir,"ebin", + [{copy_file,[...]},{copy_file,...},{...}|...]}]}, + {create_dir,"crypto-3.7.4", + [{create_dir,"src",[{copy_file,[...]},{copy_file,...}]}, + {create_dir,"ebin",[{copy_file,...},{...}|...]}]}, {create_dir,"crypto-3.7.4", [{create_dir,"priv", [{create_dir,"lib",[{copy_file,[...]},{copy_file,...}]}, {create_dir,"obj",[{copy_file,...},{...}|...]}]}]}, - {archive,"erts-10.0.ez",[], - [{create_dir,"erts-10.0", - [{create_dir,"src",[{...}|...]}, - {create_dir,"ebin",[...]}]}]}, - {archive,"hipe-3.15.4.ez",[], - [{create_dir,"hipe-3.15.4", - [{create_dir,"flow",[...]}, - {copy_file,[...]}, - {create_dir,...}, - {...}|...]}]}, - {archive,"inets-6.3.9.ez",[], - [{create_dir,"inets-6.3.9", - [{create_dir,[...],...},{create_dir,...},{...}]}]}, + {create_dir,"erts-10.0", + [{create_dir,"src",[{...}|...]}, + {create_dir,"ebin",[...]}]}, + {create_dir,"hipe-3.15.4", + [{create_dir,"flow",[...]}, + {copy_file,[...]}, + {create_dir,...}, + {...}|...]}, + {create_dir,"inets-6.3.9", + [{create_dir,[...],...},{create_dir,...},{...}]}, {create_dir,"inets-6.3.9", [{create_dir,"priv",[{create_dir,[...],...}]}, {create_dir,"include",[{copy_file,...},{...}]}]}, - {archive,"kernel-5.2.ez",[], - [{create_dir,"kernel-5.2",[{...}|...]}]}, + {create_dir,"kernel-5.2",[{...}|...]}, {create_dir,"kernel-5.2", [{create_dir,"include",[{...}|...]}]}, - {archive,"sasl-3.0.3.ez",[],[{create_dir,[...],...}]}, - {archive,"stdlib-3.3.ez",[],[{create_dir,...}]}, + {create_dir,[...],...}, + {create_dir,...}, {create_dir,"stdlib-3.3",[{create_dir,...}]}, - {archive,"tools-2.9.1.ez",[],[...]}]}]} + ...]}]} 3> 3> TargetDir = "/tmp/my_target_dir". "/tmp/my_target_dir" @@ -556,10 +536,10 @@ ok "releases"]} 8> 8> file:list_dir(filename:join([TargetDir,"lib"])). -{ok,["tools-2.9.1.ez","kernel-5.2.ez","inets-6.3.9.ez", - "kernel-5.2","sasl-3.0.3.ez","hipe-3.15.4.ez","inets-6.3.9", - "crypto-3.7.4","crypto-3.7.4.ez","stdlib-3.3.ez", - "erts-10.0.ez","stdlib-3.3","compiler-7.0.4.ez"]} +{ok,["tools-2.9.1","inets-6.3.9", + "kernel-5.2","sasl-3.0.3", + "crypto-3.7.4","erts-10.0", + "stdlib-3.3","compiler-7.0.4"]} 9> 9> file:make_dir("/tmp/yet_another_target_dir"). ok diff --git a/lib/reltool/doc/src/reltool_intro.xml b/lib/reltool/doc/src/reltool_intro.xml index 2980ad797711..695d2c21e5e6 100644 --- a/lib/reltool/doc/src/reltool_intro.xml +++ b/lib/reltool/doc/src/reltool_intro.xml @@ -5,7 +5,7 @@
    2009 - 2016 + 2023 Ericsson AB, All Rights Reserved @@ -50,7 +50,7 @@
    Prerequisites -

    The following prerequisites is required for understanding the material +

    The following prerequisites are required for understanding the material in the Reltool User's Guide:

    diff --git a/lib/reltool/doc/src/reltool_usage.xml b/lib/reltool/doc/src/reltool_usage.xml index 743d5fa366c5..c30684907a3d 100644 --- a/lib/reltool/doc/src/reltool_usage.xml +++ b/lib/reltool/doc/src/reltool_usage.xml @@ -5,7 +5,7 @@
    2009 - 2016 + 2022 Ericsson AB, All Rights Reserved @@ -261,7 +261,7 @@

    Note that in order for reltool to sort application versions and thereby be able to select the latest, it is required that the - version id for the application consits of integers and dots only, + version id for the application consists of integers and dots only, for example 1, 2.0 or 3.17.1.

    By default the Application inclusion policy on system diff --git a/lib/reltool/examples/Makefile b/lib/reltool/examples/Makefile index cc29c88ba310..b2e424b91a31 100644 --- a/lib/reltool/examples/Makefile +++ b/lib/reltool/examples/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -60,7 +60,7 @@ EBIN = . # ---------------------------------------------------- # Make Rules # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) *~ diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile index 4bddee466454..173a557d58c5 100644 --- a/lib/reltool/src/Makefile +++ b/lib/reltool/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -65,8 +65,8 @@ ERL_COMPILE_FLAGS += +'{parse_transform,sys_pre_attributes}' \ # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src index dc85464750e2..03d67ee5857e 100644 --- a/lib/reltool/src/reltool.app.src +++ b/lib/reltool/src/reltool.app.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2018. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -36,6 +36,8 @@ {registered, []}, {applications, [stdlib, kernel]}, {env, []}, - {runtime_dependencies, ["wx-1.2","tools-2.6.14","stdlib-3.4","sasl-2.4", - "kernel-3.0","erts-7.0"]} + {runtime_dependencies, + ["wx-2.3","tools-2.6.14", + "stdlib-5.0","stdlib-5.0","sasl-4.2.1", + "kernel-9.0","erts-14.0"]} ]}. diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index 844a3a880a7a..99f8ee8b3826 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -28,7 +28,7 @@ %% derived - Include only those modules that others are dependent on -type mod_cond() :: all | app | ebin | derived | none. -type incl_cond() :: include | exclude | derived. --type debug_info() :: keep | strip. +-type debug_info() :: keep | strip | [beam_lib:chunkid()]. -type app_file() :: keep | strip | all. -type re_regexp() :: string(). % re:regexp() -type regexps() :: [re_regexp()] | @@ -38,9 +38,6 @@ -type excl_sys_filters() :: regexps(). -type incl_app_filters() :: regexps(). -type excl_app_filters() :: regexps(). --type incl_archive_filters() :: regexps(). --type excl_archive_filters() :: regexps(). --type archive_opt() :: term(). % zip:create() -type root_dir() :: dir(). -type lib_dir() :: dir(). -type profile() :: development | embedded | standalone. @@ -72,9 +69,7 @@ | {app_file, app_file()} | {debug_info, debug_info()} | {incl_app_filters, incl_app_filters()} - | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()}. + | {excl_app_filters, excl_app_filters()}. -type escript() :: {incl_cond, incl_cond()}. -type sys() :: {mod_cond, mod_cond()} | {incl_cond, incl_cond()} @@ -86,9 +81,6 @@ | {excl_sys_filters, excl_sys_filters()} | {incl_app_filters, incl_app_filters()} | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()} - | {archive_opts, [archive_opt()]} | {root_dir, root_dir()} | {lib_dirs, [lib_dir()]} | {boot_rel, boot_rel()} @@ -119,7 +111,6 @@ -type target_spec() :: [target_spec()] | {create_dir, base_dir(), [target_spec()]} | {create_dir, base_dir(), top_dir(), [target_spec()]} - | {archive, base_file(), [archive_opt()], [target_spec()]} | {copy_file, base_file()} | {copy_file, base_file(), top_file()} | {write_file, base_file(), binary()} @@ -198,9 +189,6 @@ app_type :: '_' | app_type() | undefined, incl_app_filters :: '_' | [#regexp{}] | undefined, excl_app_filters :: '_' | [#regexp{}] | undefined, - incl_archive_filters :: '_' | [#regexp{}] | undefined, - excl_archive_filters :: '_' | [#regexp{}] | undefined, - archive_opts :: '_' | [archive_opt()] | undefined, %% Dynamic status :: '_' | status(), @@ -247,9 +235,6 @@ excl_sys_filters :: [#regexp{}], incl_app_filters :: [#regexp{}], excl_app_filters :: [#regexp{}], - incl_archive_filters :: [#regexp{}], - excl_archive_filters :: [#regexp{}], - archive_opts :: [archive_opt()], relocatable :: boolean(), rel_app_type :: app_type(), embedded_app_type :: app_type() | undefined, @@ -280,10 +265,6 @@ -define(DEFAULT_APP_FILE, keep). -define(DEFAULT_DEBUG_INFO, keep). --define(DEFAULT_INCL_ARCHIVE_FILTERS, [".*"]). --define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include\$", "^priv\$"]). --define(DEFAULT_ARCHIVE_OPTS, []). - -define(DEFAULT_INCL_SYS_FILTERS, [".*"]). -define(DEFAULT_EXCL_SYS_FILTERS, []). -define(DEFAULT_INCL_APP_FILTERS, [".*"]). diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl index c84c1562ee25..7d6e06246320 100644 --- a/lib/reltool/src/reltool_app_win.erl +++ b/lib/reltool/src/reltool_app_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2018. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -98,6 +98,7 @@ open_mod(Pid, ModName) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Server +-spec init(term(), term(), term(), term(), term()) -> no_return(). init(Parent, WxEnv, Xref, C, AppName) -> try do_init(Parent, WxEnv, Xref, C, AppName) diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 43e9d50b18f5..e14d171766ce 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -129,12 +129,13 @@ gen_spec(Pid) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Server +-spec init(_) -> no_return(). init([{parent,Parent}|_] = Options) -> try do_init(Options) catch throw:{error,Reason} -> - proc_lib:init_ack(Parent,{error,Reason}); + proc_lib:init_fail(Parent,{error,Reason},{exit,normal}); error:Reason:Stacktrace -> exit({Reason, Stacktrace}) end. @@ -196,13 +197,6 @@ default_sys() -> rel_app_type = ?DEFAULT_REL_APP_TYPE, embedded_app_type = ?DEFAULT_EMBEDDED_APP_TYPE, app_file = ?DEFAULT_APP_FILE, - incl_archive_filters = dec_re(incl_archive_filters, - ?DEFAULT_INCL_ARCHIVE_FILTERS, - []), - excl_archive_filters = dec_re(excl_archive_filters, - ?DEFAULT_EXCL_ARCHIVE_FILTERS, - []), - archive_opts = ?DEFAULT_ARCHIVE_OPTS, debug_info = ?DEFAULT_DEBUG_INFO}. dec_re(Key, Regexps, Old) -> @@ -450,9 +444,6 @@ app_set_config_only([],#app{name = Name, app_type = undefined, incl_app_filters = undefined, excl_app_filters = undefined, - incl_archive_filters = undefined, - excl_archive_filters = undefined, - archive_opts = undefined, is_escript = false})-> {delete,Name}; app_set_config_only(Mods,#app{name = Name, @@ -464,9 +455,6 @@ app_set_config_only(Mods,#app{name = Name, app_type = AppType, incl_app_filters = InclAppFilters, excl_app_filters = ExclAppFilters, - incl_archive_filters = InclArchiveFilters, - excl_archive_filters = ExclArchiveFilters, - archive_opts = ArchiveOpts, vsn = Vsn, is_escript = IsEscript, label = Label, @@ -481,9 +469,6 @@ app_set_config_only(Mods,#app{name = Name, app_type = AppType, incl_app_filters = InclAppFilters, excl_app_filters = ExclAppFilters, - incl_archive_filters = InclArchiveFilters, - excl_archive_filters = ExclArchiveFilters, - archive_opts = ArchiveOpts, vsn = Vsn, mods = Mods}, @@ -1012,7 +997,7 @@ mod_recap_dependencies(S, A, [#mod{name = ModName}=M1 | Mods], Acc, IsIncl) -> ets:insert(S#state.mod_tab, M3), mod_recap_dependencies(S, A, Mods, [M3 | Acc], IsIncl2); [_] when A#app.is_included==false; M1#mod.incl_cond==exclude -> - %% App is explicitely excluded so it is ok that the module + %% App is explicitly excluded so it is ok that the module %% record does not exist for this module in this %% application. mod_recap_dependencies(S, A, Mods, [M1 | Acc], IsIncl); @@ -1563,13 +1548,11 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals]) -> Sys#sys{excl_app_filters = dec_re(Key, Val, Sys#sys.excl_app_filters)}; incl_archive_filters -> - Sys#sys{incl_archive_filters = - dec_re(Key, Val, Sys#sys.incl_archive_filters)}; + io:format("incl_archive_filters is no longer supported in reltool"); excl_archive_filters -> - Sys#sys{excl_archive_filters = - dec_re(Key, Val, Sys#sys.excl_archive_filters)}; + io:format("excl_archive_filters is no longer supported in reltool"); archive_opts when is_list(Val) -> - Sys#sys{archive_opts = Val}; + io:format("archive_opts is no longer supported in reltool"); relocatable when Val =:= true; Val =:= false -> Sys#sys{relocatable = Val}; rel_app_type when Val =:= permanent; @@ -1587,7 +1570,7 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals]) -> Sys#sys{embedded_app_type = Val}; app_file when Val =:= keep; Val =:= strip; Val =:= all -> Sys#sys{app_file = Val}; - debug_info when Val =:= keep; Val =:= strip -> + debug_info when Val =:= keep; Val =:= strip; is_list(Val) -> Sys#sys{debug_info = Val}; _ -> reltool_utils:throw_error("Illegal option: ~tp", [{Key, Val}]) @@ -1608,7 +1591,8 @@ decode(#app{} = App, [{Key, Val} | KeyVals]) -> App#app{incl_cond = Val}; debug_info when Val =:= keep; - Val =:= strip -> + Val =:= strip; + is_list(Val) -> App#app{debug_info = Val}; app_file when Val =:= keep; Val =:= strip; @@ -1628,13 +1612,11 @@ decode(#app{} = App, [{Key, Val} | KeyVals]) -> App#app{excl_app_filters = dec_re(Key, Val, App#app.excl_app_filters)}; incl_archive_filters -> - App#app{incl_archive_filters = - dec_re(Key, Val, App#app.incl_archive_filters)}; + io:format("incl_archive_filters is no longer supported in reltool"); excl_archive_filters -> - App#app{excl_archive_filters = - dec_re(Key, Val, App#app.excl_archive_filters)}; + io:format("excl_archive_filters is no longer supported in reltool"); archive_opts when is_list(Val) -> - App#app{archive_opts = Val}; + io:format("archive_opts is no longer supported in reltool"); vsn when is_list(Val), App#app.use_selected_vsn=:=undefined -> App#app{use_selected_vsn = vsn, vsn = Val}; lib_dir when is_list(Val), App#app.use_selected_vsn=:=undefined -> @@ -1663,7 +1645,7 @@ decode(#mod{} = Mod, [{Key, Val} | KeyVals]) -> case Key of incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> Mod#mod{incl_cond = Val}; - debug_info when Val =:= keep; Val =:= strip -> + debug_info when Val =:= keep; Val =:= strip; is_list(Val) -> Mod#mod{debug_info = Val}; _ -> reltool_utils:throw_error("Illegal option: ~tp", [{Key, Val}]) diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl index e24f468f678e..7c446c079f9f 100644 --- a/lib/reltool/src/reltool_sys_win.erl +++ b/lib/reltool/src/reltool_sys_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2018. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -183,7 +183,7 @@ do_init([{safe_config, Safe}, {parent, Parent} | Options]) -> restart_server_safe_config(true,Parent,Reason) -> io:format("~w(~w): ~tp\n", [?MODULE, ?LINE, Reason]), - proc_lib:init_ack(Parent, {error,Reason}); + proc_lib:init_fail(Parent, {error,Reason}, {exit,normal}); restart_server_safe_config(false,Parent,Reason) -> wx:new(), Strings = @@ -200,7 +200,7 @@ restart_server_safe_config(false,Parent,Reason) -> do_init([{safe_config,true},{parent,Parent},?safe_config]); ?wxID_CANCEL -> io:format("~w(~w): ~tp\n", [?MODULE, ?LINE, Reason]), - proc_lib:init_ack(Parent,{error,Reason}) + proc_lib:init_fail(Parent, {error,Reason}, {exit,normal}) end. exit_dialog([]) -> diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl index 773e752ad491..b30edc5c368d 100644 --- a/lib/reltool/src/reltool_target.erl +++ b/lib/reltool/src/reltool_target.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -81,9 +81,6 @@ do_gen_config(#sys{root_dir = RootDir, excl_sys_filters = ExclSysFiles, incl_app_filters = InclAppFiles, excl_app_filters = ExclAppFiles, - incl_archive_filters = InclArchiveDirs, - excl_archive_filters = ExclArchiveDirs, - archive_opts = ArchiveOpts, relocatable = Relocatable, rel_app_type = RelAppType, embedded_app_type = InclAppType, @@ -133,9 +130,6 @@ do_gen_config(#sys{root_dir = RootDir, emit(excl_sys_filters, X(ExclSysFiles), reltool_utils:choose_default(excl_sys_filters, Profile, InclDefs), InclDefs) ++ emit(incl_app_filters, X(InclAppFiles), reltool_utils:choose_default(incl_app_filters, Profile, InclDefs), InclDefs) ++ emit(excl_app_filters, X(ExclAppFiles), reltool_utils:choose_default(excl_app_filters, Profile, InclDefs), InclDefs) ++ - emit(incl_archive_filters, X(InclArchiveDirs), ?DEFAULT_INCL_ARCHIVE_FILTERS, InclDefs) ++ - emit(excl_archive_filters, X(ExclArchiveDirs), ?DEFAULT_EXCL_ARCHIVE_FILTERS, InclDefs) ++ - emit(archive_opts, ArchiveOpts, ?DEFAULT_ARCHIVE_OPTS, InclDefs) ++ emit(rel_app_type, RelAppType, ?DEFAULT_REL_APP_TYPE, InclDefs) ++ emit(embedded_app_type, InclAppType, reltool_utils:choose_default(embedded_app_type, Profile, InclDefs), InclDefs) ++ emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefs) ++ @@ -147,9 +141,6 @@ do_gen_config(#app{name = Name, app_file = AppFile, incl_app_filters = InclAppFiles, excl_app_filters = ExclAppFiles, - incl_archive_filters = InclArchiveDirs, - excl_archive_filters = ExclArchiveDirs, - archive_opts = ArchiveOpts, use_selected_vsn = UseSelected, vsn = Vsn, active_dir = ActiveDir, @@ -164,9 +155,6 @@ do_gen_config(#app{name = Name, emit(app_file, AppFile, undefined, InclDefs), emit(incl_app_filters, InclAppFiles, undefined, InclDefs), emit(excl_app_filters, ExclAppFiles, undefined, InclDefs), - emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs), - emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs), - emit(archive_opts, ArchiveOpts, undefined, InclDefs), if IsIncl, InclDefs -> [{vsn, Vsn}, {lib_dir, ActiveDir}]; UseSelected =:= vsn -> [{vsn, Vsn}]; @@ -677,7 +665,7 @@ del_apps([], Apps) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create the load path used in the generated script. %% If PathFlag is true a script intended to be used as a complete -%% system (e.g. in an embbeded system), i.e. all applications are +%% system (e.g. in an embedded system), i.e. all applications are %% located under $ROOT/lib. %% Otherwise all paths are set according to dir per application. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -784,7 +772,7 @@ do_spec_rel_files(#rel{name = RelName} = Rel, Sys) -> case Sys#sys.excl_lib of otp_root -> %% All applications that are fetched from somewhere - %% other than $OTP_ROOT/lib will get $RELTOOL_EXT_LIB + %% other than $OTPROOT/lib will get $RELTOOL_EXT_LIB %% as path prefix in the .script file. [{"RELTOOL_EXT_LIB",LibDir} || LibDir <- Sys#sys.lib_dirs] ++ [{"RELTOOL_EXT_LIB",filename:dirname(AppLibDir)} || @@ -1075,12 +1063,14 @@ check_apps([Mandatory | Names], Apps) -> check_apps([], _) -> ok. -spec_app(#app{name = Name, +spec_app(#app{label = Label, + name = Name, mods = Mods, active_dir = SourceDir, incl_app_filters = AppInclRegexps, excl_app_filters = AppExclRegexps} = App, - #sys{incl_app_filters = SysInclRegexps, + #sys{root_dir = RootDir, + incl_app_filters = SysInclRegexps, excl_app_filters = SysExclRegexps, debug_info = SysDebugInfo} = Sys) -> %% List files recursively @@ -1104,47 +1094,7 @@ spec_app(#app{name = Name, ExclRegexps = reltool_utils:default_val(AppExclRegexps, SysExclRegexps), AppFiles3 = filter_spec(AppFiles2, InclRegexps, ExclRegexps), - %% Regular top directory and/or archive - spec_archive(App, Sys, AppFiles3). - -spec_archive(#app{label = Label, - active_dir = SourceDir, - incl_archive_filters = AppInclArchiveDirs, - excl_archive_filters = AppExclArchiveDirs, - archive_opts = AppArchiveOpts}, - #sys{root_dir = RootDir, - incl_archive_filters = SysInclArchiveDirs, - excl_archive_filters = SysExclArchiveDirs, - archive_opts = SysArchiveOpts}, - Files) -> - InclArchiveDirs = - reltool_utils:default_val(AppInclArchiveDirs, SysInclArchiveDirs), - ExclArchiveDirs = - reltool_utils:default_val(AppExclArchiveDirs, SysExclArchiveDirs), - ArchiveOpts = - reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), - Match = fun(F) -> match(element(2, F), InclArchiveDirs, ExclArchiveDirs) end, - case lists:filter(Match, Files) of - [] -> - %% Nothing to archive - [spec_create_dir(RootDir, SourceDir, Label, Files)]; - ArchiveFiles -> - OptDir = - case Files -- ArchiveFiles of - [] -> - []; - ExternalFiles -> - [spec_create_dir(RootDir, - SourceDir, - Label, - ExternalFiles)] - end, - ArchiveOpts = - reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), - ArchiveDir = - spec_create_dir(RootDir, SourceDir, Label, ArchiveFiles), - [{archive, Label ++ ".ez", ArchiveOpts, [ArchiveDir]} | OptDir] - end. + [spec_create_dir(RootDir, SourceDir, Label, AppFiles3)]. spec_dir(Dir) -> Base = filename:basename(Dir), @@ -1172,7 +1122,9 @@ spec_mod(Mod, DebugInfo) -> keep -> {copy_file, File}; strip -> - {strip_beam, File} + {strip_beam, File, []}; + ChunkIds -> + {strip_beam, File, ChunkIds} end. spec_app_file(#app{name = Name, @@ -1277,27 +1229,6 @@ do_eval_spec({create_dir, Dir, OldDir, Files}, TargetDir2 = filename:join([TargetDir, Dir]), reltool_utils:create_dir(TargetDir2), do_eval_spec(Files, SourceDir2, SourceDir2, TargetDir2); -do_eval_spec({archive, Archive, Options, Files}, - OrigSourceDir, - SourceDir, - TargetDir) -> - TmpSpec = {create_dir, "tmp", Files}, - TmpDir = filename:join([TargetDir, "tmp"]), - reltool_utils:create_dir(TmpDir), - do_eval_spec(Files, OrigSourceDir, SourceDir, TmpDir), - - ArchiveFile = filename:join([TargetDir, Archive]), - Files2 = [element(2, F) || F <- Files], - Res = zip:create(ArchiveFile, Files2, [{cwd, TmpDir} | Options]), - - cleanup_spec(TmpSpec, TargetDir), - case Res of - {ok, _} -> - ok; - {error, Reason} -> - reltool_utils:throw_error("create archive ~ts failed: ~tp", - [ArchiveFile, Reason]) - end; do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) -> SourceFile = filename:join([SourceDir, File]), TargetFile = filename:join([TargetDir, File]), @@ -1315,11 +1246,14 @@ do_eval_spec({write_file, File, Bin}, TargetDir) -> TargetFile = filename:join([TargetDir, File]), reltool_utils:write_file(TargetFile, Bin); -do_eval_spec({strip_beam, File}, _OrigSourceDir, SourceDir, TargetDir) -> +do_eval_spec({strip_beam, File, ChunkIds}, + _OrigSourceDir, + SourceDir, + TargetDir) -> SourceFile = filename:join([SourceDir, File]), TargetFile = filename:join([TargetDir, File]), BeamBin = reltool_utils:read_file(SourceFile), - {ok, {_, BeamBin2}} = beam_lib:strip(BeamBin), + {ok, {_, BeamBin2}} = beam_lib:strip(BeamBin, ChunkIds), reltool_utils:write_file(TargetFile, BeamBin2). cleanup_spec(List, TargetDir) when is_list(List) -> @@ -1334,12 +1268,6 @@ cleanup_spec({create_dir, Dir, _OldDir, Files}, TargetDir) -> TargetDir2 = filename:join([TargetDir, Dir]), cleanup_spec(Files, TargetDir2), file:del_dir(TargetDir2); -cleanup_spec({archive, Archive, _Options, Files}, TargetDir) -> - TargetFile = filename:join([TargetDir, Archive]), - file:delete(TargetFile), - TmpDir = filename:join([TargetDir, "tmp"]), - cleanup_spec(Files, TmpDir), - file:del_dir(TmpDir); cleanup_spec({copy_file, File}, TargetDir) -> TargetFile = filename:join([TargetDir, File]), file:delete(TargetFile); @@ -1349,7 +1277,7 @@ cleanup_spec({copy_file, NewFile, _OldFile}, TargetDir) -> cleanup_spec({write_file, File, _}, TargetDir) -> TargetFile = filename:join([TargetDir, File]), file:delete(TargetFile); -cleanup_spec({strip_beam, File}, TargetDir) -> +cleanup_spec({strip_beam, File, _ChunkIds}, TargetDir) -> TargetFile = filename:join([TargetDir, File]), file:delete(TargetFile). @@ -1392,21 +1320,6 @@ do_filter_spec(Path, Files2 when is_list(Files2) -> {true, {create_dir, NewDir, OldDir, Files2}} end; -do_filter_spec(Path, - {archive, Archive, Options, Files}, - InclRegexps, - ExclRegexps) -> - case do_filter_spec(Path, Files, InclRegexps, ExclRegexps) of - [] -> - case match(Path, InclRegexps, ExclRegexps) of - true -> - {true, {archive, Archive, Options, []}}; - false -> - false - end; - Files2 when is_list(Files2) -> - {true, {archive, Archive, Options, Files2}} - end; do_filter_spec(Path, {copy_file, File}, InclRegexps, ExclRegexps) -> Path2 = opt_join(Path, File), match(Path2, InclRegexps, ExclRegexps); @@ -1419,7 +1332,7 @@ do_filter_spec(Path, do_filter_spec(Path, {write_file, File, _}, InclRegexps, ExclRegexps) -> Path2 = opt_join(Path, File), match(Path2, InclRegexps, ExclRegexps); -do_filter_spec(Path, {strip_beam, File}, InclRegexps, ExclRegexps) -> +do_filter_spec(Path, {strip_beam, File, _ChunkIds}, InclRegexps, ExclRegexps) -> Path2 = opt_join(Path, File), match(Path2, InclRegexps, ExclRegexps). diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index 838e9a34f653..245c9c9f003a 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -51,6 +51,7 @@ RELSYSDIR = $(RELEASE_PATH)/reltool_test # FLAGS # ---------------------------------------------------- ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/reltool/ebin/ +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -58,7 +59,7 @@ EBIN = . # Targets # ---------------------------------------------------- -tests debug opt: $(TARGET_FILES) +tests $(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index c775aa122518..a7125aa7790b 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -281,9 +281,6 @@ get_config(_Config) -> {excl_sys_filters,[]}, {incl_app_filters,[".*"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {app_file,keep}, {debug_info,keep}]}}, @@ -312,9 +309,6 @@ get_config(_Config) -> {excl_sys_filters,[]}, {incl_app_filters,[".*"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {app_file,keep}, {debug_info,keep}]}}, @@ -1252,7 +1246,7 @@ create_slim(Config) -> TargetRelDir = filename:join(TargetDir,"releases"), TargetRelVsnDir = filename:join(TargetRelDir,RelVsn), - {ok,["a-1.0.ez"]} = file:list_dir(TargetLibDir), + {ok,["a-1.0"]} = file:list_dir(TargetLibDir), RootDir = code:root_dir(), Erl = filename:join([RootDir, "bin", "erl"]), @@ -1335,16 +1329,14 @@ otp_9229_dupl_mod_exclude_app(Config) -> {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), AbsTargetDir = filename:absname(TargetDir), - XArchive = "x-1.0.ez", - AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]), - XEbin = ["ebin","x-1.0",XArchive], - YArchive = "y-1.0.ez", - AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]), + AbsX = filename:join([AbsTargetDir,lib,"x-1.0"]), + XEbin = ["ebin","x-1.0"], + AbsY = filename:join([AbsTargetDir,lib,"y-1.0"]), - ?m(true, filelib:is_file(AbsXArchive)), + ?m(true, filelib:is_file(AbsX)), ?m(XEbin, mod_path(Node,x)), ?m(XEbin, mod_path(Node,mylib)), - ?m(false, filelib:is_file(AbsYArchive)), + ?m(false, filelib:is_file(AbsY)), ?m(non_existing, mod_path(Node,y)), ?msym(ok, stop_node(Node)), @@ -1382,17 +1374,15 @@ otp_9229_dupl_mod_exclude_mod(Config) -> {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)), AbsTargetDir = filename:absname(TargetDir), - XArchive = "x-1.0.ez", - AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]), - XEbin = ["ebin","x-1.0",XArchive], - YArchive = "y-1.0.ez", - AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]), - YEbin = ["ebin","y-1.0",YArchive], - - ?m(true, filelib:is_file(AbsXArchive)), + AbsX = filename:join([AbsTargetDir,lib,"x-1.0"]), + XEbin = ["ebin","x-1.0"], + AbsY = filename:join([AbsTargetDir,lib,"y-1.0"]), + YEbin = ["ebin","y-1.0"], + + ?m(true, filelib:is_file(AbsX)), ?m(XEbin, mod_path(Node,x)), ?m(XEbin, mod_path(Node,mylib)), - ?m(true, filelib:is_file(AbsYArchive)), + ?m(true, filelib:is_file(AbsY)), ?m(YEbin, mod_path(Node,y)), %% Remove path to XEbin and check that mylib is not located in YEbin @@ -2197,9 +2187,6 @@ save_config(Config) -> {excl_sys_filters,[]}, {incl_app_filters,[".*"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {app_file,keep}, {debug_info,keep}]}]}, @@ -2238,9 +2225,6 @@ save_config(Config) -> {excl_sys_filters,[]}, {incl_app_filters,[".*"]}, {excl_app_filters,[]}, - {incl_archive_filters,[".*"]}, - {excl_archive_filters,["^include$","^priv$"]}, - {archive_opts,[]}, {rel_app_type,permanent}, {app_file,keep}, {debug_info,keep}]}]}, @@ -2439,7 +2423,6 @@ dep_in_app_not_xref(Config) -> [ {lib_dirs,[filename:join(datadir(Config),"dep_in_app_not_xref")]}, {incl_cond,exclude}, - {incl_archive_filters,[]}, {erts,[{incl_cond,exclude}]}, {boot_rel, RelName}, {rel, RelName, RelVsn, [kernel, stdlib]}, @@ -2722,7 +2705,7 @@ os_cmd(Cmd) when is_list(Cmd) -> []-> {99, []}; Return-> - %% Find the position of the status code wich is last in the string + %% Find the position of the status code which is last in the string %% prepended with # case string:split(Return, "$#", trailing) of [_] -> %% This happens only if the sh command pipe is somehow interrupted diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk index 1bee6b4581ce..6a81d9b40cc0 100644 --- a/lib/reltool/vsn.mk +++ b/lib/reltool/vsn.mk @@ -1 +1 @@ -RELTOOL_VSN = 0.9 +RELTOOL_VSN = 1.0 diff --git a/lib/runtime_tools/Makefile b/lib/runtime_tools/Makefile index a76637dfeb42..c85d81922b82 100644 --- a/lib/runtime_tools/Makefile +++ b/lib/runtime_tools/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2022. 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. @@ -37,5 +37,6 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk DIA_PLT_APPS=mnesia +TEST_NEEDS_RELEASE=true include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c index e7fd5968c156..37a814977719 100644 --- a/lib/runtime_tools/c_src/trace_file_drv.c +++ b/lib/runtime_tools/c_src/trace_file_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2016. All Rights Reserved. + * Copyright Ericsson AB 1999-2022. 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. @@ -117,7 +117,7 @@ ** 0 = binary, 1 = drop ** If Op is 1, then Size reflects the number of dropped messages. The ** op 1 is never used in this driver. -** Size, a 32 bit interger in network byte order: +** Size, a 32 bit integer in network byte order: ** Either the size of the binary term, or the number of packet's dropped. ** Term, an array of bytes: ** An erlang term in the external format or simply empty if Op == 1, the diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 195558f95883..c6f42b3b5256 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2016. All Rights Reserved. + * Copyright Ericsson AB 1999-2022. 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. @@ -68,7 +68,7 @@ ** The number of messages to que up before dropping. ** Fl, ascii string representing a flag byte: ** 0x1 -> Drop oldest when que is full (instead of last arrived) -** 0x2 -> Fill the que even if noone is listening. +** 0x2 -> Fill the que even if no one is listening. ** ** The package sent over the network looks like this: ** +--+--------+-----------------------------------+ @@ -77,7 +77,7 @@ ** Op, a char: ** 0 = binary, 1 = drop ** If Op is 1, then Size reflects the number of dropped messages. -** Size, a 32 bit interger in network byte order: +** Size, a 32 bit integer in network byte order: ** Either the size of the binary term, or the number of packet's dropped. ** Term, an array of bytes: ** An erlang term in the external format or simply empty if Op == 1, the @@ -86,7 +86,7 @@ /* ** SO, most of the differences between WinDoze and Posixish OS'es -** is handeled here, but the multiplexing (driver_select) is also quite +** is handled here, but the multiplexing (driver_select) is also quite ** interesting, see my_driver_select further down in the file... */ @@ -677,7 +677,7 @@ static TraceIpMessage *make_buffer(int datasiz, unsigned char op, /* ** Add message to que, discarding in a politically correct way... -** The FLAG_DROP_OLDEST is currently ingored... +** The FLAG_DROP_OLDEST is currently ignored... */ static void enque_message(TraceIpData *data, char *buff, int bufflen, int byteswritten) diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml index 7567d4ba4359..00e153717652 100644 --- a/lib/runtime_tools/doc/src/LTTng.xml +++ b/lib/runtime_tools/doc/src/LTTng.xml @@ -521,7 +521,7 @@ Eshell V8.0 (abort with ^G)

    1> l(dyntrace).
     {module,dyntrace}
    -

    All tracepoints via dyntrace are now visibile and can be listed through lttng list -u.

    +

    All tracepoints via dyntrace are now visible and can be listed through lttng list -u.

    Enable the process_register LTTng tracepoint for Erlang.

    diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile index bed1358730fb..fb741bf733cb 100644 --- a/lib/runtime_tools/doc/src/Makefile +++ b/lib/runtime_tools/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2023. 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. @@ -39,14 +39,14 @@ XML_APPLICATION_FILES = ref_man.xml XML_REF3_FILES = \ dbg.xml \ dyntrace.xml \ - erts_alloc_config.xml \ + instrument.xml \ system_information.xml \ msacc.xml \ scheduler.xml XML_REF6_FILES = runtime_tools_app.xml XML_PART_FILES = part.xml -XML_CHAPTER_FILES = notes.xml LTTng.xml +XML_CHAPTER_FILES = notes.xml LTTng.xml erts_alloc_config.xml GENERATED_XML_FILES = DTRACE.xml SYSTEMTAP.xml diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml index 7532ec692dbe..5d9d7486d403 100644 --- a/lib/runtime_tools/doc/src/dbg.xml +++ b/lib/runtime_tools/doc/src/dbg.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962022 Ericsson AB. All Rights Reserved. @@ -821,7 +821,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ tracer(Type, Data) -> {ok, pid()} | {error, Error} Start a tracer server with additional parameters - Type = port | process | module + Type = port | process | module | file Data = PortGenerator | HandlerSpec | ModuleSpec PortGenerator = fun() (no arguments) Error = term() @@ -862,6 +862,9 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\ be either a tuple describing the erl_tracer module to be used for tracing and the state to be used for that tracer module or a fun returning the same tuple.

    +

    if Type is file, then the second parameter + should be a filename specifying a file where all the traces + are printed.

    If an error is returned, it can either be due to a tracer server already running ({error,already_started}) or due to the HandlerFun throwing an exception. @@ -1156,20 +1159,12 @@ hello stop() -> ok - Stop the dbgserver and the tracing of all processes. - -

    Stops the dbg server and clears all trace flags for - all processes and all local trace patterns for all functions. Also - shuts down all trace clients and closes all trace ports.

    -

    Note that no global trace patterns are affected by this - function.

    - - - - stop_clear() -> ok Stop the dbgserver and the tracing of all processes, and clears trace patterns. -

    Same as stop/0, but also clears all trace patterns on global functions calls.

    +

    Stops the dbg server, clears all trace flags for + all processes, clears all trace patterns for all functions, + clears trace patterns for send/receive, shuts down all trace clients, + and closes all trace ports.

    diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml index d3b348e85068..5971740b874a 100644 --- a/lib/runtime_tools/doc/src/dyntrace.xml +++ b/lib/runtime_tools/doc/src/dyntrace.xml @@ -171,7 +171,7 @@

    This function controls if user tags are to be spread to other processes with the next message. Spreading of user tags work like spreading of sequential trace tokens, so that a received user tag will be active in the process until the next message arrives (if that message does not also contain the user tag.

    This functionality is used when a client process communicates with a file i/o-server to spread the user tag to the I/O-server and then down to the efile_drv driver. By using spread_tag/1 and restore_tag/1, one can enable or disable spreading of user tags to other processes and then restore the previous state of the user tag. The TagData returned from this call contains all previous information so the state (including any previously spread user tags) will be completely restored by a later call to restore_tag/1.

    -

    The file module already spread's tags, so there is noo need to manually call these function to get user tags spread to the efile driver through that module.

    +

    The file module already spread's tags, so there is no need to manually call these function to get user tags spread to the efile driver through that module.

    The most use of this function would be if one for example uses the io module to communicate with an I/O-server for a regular file, like in the following example:

     f() ->
    diff --git a/lib/runtime_tools/doc/src/erts_alloc_config.xml b/lib/runtime_tools/doc/src/erts_alloc_config.xml
    index fb5d08be9db5..b5d5dfaff237 100644
    --- a/lib/runtime_tools/doc/src/erts_alloc_config.xml
    +++ b/lib/runtime_tools/doc/src/erts_alloc_config.xml
    @@ -1,10 +1,10 @@
     
    -
    +
     
    -
    +
       
    - 20072021 + 20072023 Ericsson AB. All Rights Reserved. @@ -25,188 +25,17 @@ erts_alloc_config Rickard Green 1 - 07-05-30 - 1 - erts_alloc_config.sgml + 23-04-06 + 2 + erts_alloc_config.xml
    - erts_alloc_config - Configuration tool for erts_alloc - - -

    erts_alloc_config is currently an experimental - tool and might be subject to backward incompatible - changes.

    -
    -

    erts_alloc(3) is an - Erlang Run-Time System internal memory allocator library. - erts_alloc_config is intended to be used to aid creation - of an erts_alloc(3) - configuration that is suitable for a limited number of runtime - scenarios. The configuration that erts_alloc_config - produce is intended as a suggestion, and may need to be - adjusted manually.

    -

    The configuration is created based on information about a number - of runtime scenarios. It is obviously impossible to foresee every - runtime scenario that can occur. The important scenarios are - those that cause maximum or minimum load on specific memory - allocators. Load in this context is total size of memory blocks - allocated.

    -

    The current implementation of erts_alloc_config concentrate - on configuration of multi-block carriers. Information gathered - when a runtime scenario is saved is mainly current and maximum use - of multi-block carriers. If a parameter that change the use of - multi-block carriers is changed, a previously generated - configuration is invalid and erts_alloc_config needs - to be run again. It is mainly the single block carrier threshold - that effects the use of multi-block carriers, but other - single-block carrier parameters might as well. If another value of - a single block carrier parameter than the default is desired, use - the desired value when running erts_alloc_config.

    -

    A configuration is created in the following way:

    - - -

    Pass the +Mea config - command-line flag to the Erlang runtime system you are going - to use for creation of the allocator configuration. It will - disable features that prevent erts_alloc_config from - doing its job. Note, you should not use this flag - when using the created configuration. Also note that it is - important that you use the same - amount of schedulers - when creating the configuration as you are going the use on - the system using the configuration.

    -
    - -

    Run your applications with different scenarios (the more - the better) and save information about each scenario by calling - save_scenario/0. - It may be hard to know when the applications are at an (for - erts_alloc_config) important runtime scenario. A good - approach may therefore be to call - save_scenario/0 - repeatedly, e.g. once every tenth second. Note that it is - important that your applications reach the runtime scenarios - that are important for erts_alloc_config when you are - saving scenarios; otherwise, the configuration may perform - bad.

    -
    - -

    When you have covered all scenarios, call - make_config/1 - in order to create a configuration. The configuration is - written to a file that you have chosen. This configuration - file can later be read by an Erlang runtime-system at - startup. Pass the command line argument - -args_file FileName - to the erl(1) command.

    -
    - -

    The configuration produced by erts_alloc_config may - need to be manually adjusted as already stated. Do not modify the - file produced by erts_alloc_config; instead, put your - modifications in another file and load this file after the - file produced by erts_alloc_config. That is, put the - -args_file FileName - argument that reads your modification file later on the - command-line than the - -args_file FileName - argument that reads the configuration file produced by - erts_alloc_config. If a memory allocation parameter - appear multiple times, the last version of will be used, i.e., - you can override parameters in the configuration file produced - by erts_alloc_config. Doing it this way simplifies - things when you want to rerun erts_alloc_config.

    -
    -
    - -

    The configuration created by erts_alloc_config may - perform bad, ever horrible, for runtime scenarios that are very - different from the ones saved when creating the - configuration. You are, therefore, advised to rerun - erts_alloc_config if the applications run when the - configuration was made are changed, or if the load on the - applications have changed since the configuration was made. You - are also advised to rerun erts_alloc_config if the Erlang - runtime system used is changed.

    -
    -

    erts_alloc_config saves information about runtime scenarios - and performs computations in a server that is automatically - started. The server register itself under the name - '__erts_alloc_config__'.

    -
    - - - save_scenario() -> ok | {error, Error} - Saves information about current runtime scenario - - Error = term() - - -

    save_scenario/0 saves information about the current - runtime scenario. This information will later be used when - make_config/0, - or make_config/1 - is called.

    -

    The first time save_scenario/0 is called a server - will be started. This server will save runtime scenarios. All - saved scenarios can be removed by calling - stop/0.

    -
    -
    - - make_config() -> ok | {error, Error} - Creates an erts_alloc configuration - - Error = term() - - -

    This is the same as calling - make_config(group_leader()).

    -
    -
    - - make_config(FileNameOrIODev) -> ok | {error, Error} - Creates an erts_alloc configuration - - FileNameOrIODev = string() | io_device() - Error = term() - - -

    make_config/1 uses the information previously saved by - save_scenario/0 - in order to produce an erts_alloc configuration. At - least one scenario have had to be saved. All scenarios - previously saved will be used when creating the - configuration.

    -

    If FileNameOrIODev is a string(), - make_config/1 will use FileNameOrIODev as a - filename. A file named FileNameOrIODev is created and - the configuration will be written to that file. If - FileNameOrIODev is an - io_device() (see the - documentation of the module - io), the configuration - will be written to the io device.

    -
    -
    - - stop() -> ok | {error, Error} - - - Error = term() - - -

    Stops the server that saves runtime scenarios.

    -
    -
    -
    - -
    - See Also -

    erts_alloc(3), - erl(1), - io(3)

    +
    Module Removed + +

    This (experimental) tool no longer produced good configurations and + cannot be fixed in a reasonably backwards compatible manner. It has + therefore as of OTP 26.0 been removed.

    +
    - + diff --git a/lib/tools/doc/src/instrument.xml b/lib/runtime_tools/doc/src/instrument.xml similarity index 82% rename from lib/tools/doc/src/instrument.xml rename to lib/runtime_tools/doc/src/instrument.xml index 4305bad5996d..5acdb13dd42e 100644 --- a/lib/tools/doc/src/instrument.xml +++ b/lib/runtime_tools/doc/src/instrument.xml @@ -4,7 +4,7 @@
    - 19982021 + 19982023 Ericsson AB. All Rights Reserved. @@ -36,11 +36,12 @@ Analysis and Utility Functions for Instrumentation

    The module instrument contains support for studying the resource - usage in an Erlang runtime system. Currently, only the allocation of memory can - be studied.

    + usage in an Erlang runtime system. Currently, only the allocation of + memory can be studied.

    -

    Note that this whole module is experimental, and the representations - used as well as the functionality is likely to change in the future.

    +

    Since this module inspects internal details of the runtime system it + may differ greatly from one version to another. We make no compatibility + guarantees in this module.

    @@ -52,6 +53,13 @@

    The upper bound of the first interval is provided by the function that returned the histogram, and the last interval has no upper bound.

    +

    For example, the histogram below has 40 (message) blocks + between 256-512 bytes in size, 78 blocks between 512-1024 bytes,2 + blocks between 1-2KB, and 2 blocks between 2-4KB.

    + instrument:allocations(#{ histogram_start => 128, histogram_width => 15 }). +{ok, {128, 0, #{ message => {0,40,78,2,2,0,0,0,0,0,0,0,0,0,0}, ... } }} + ]]> @@ -62,7 +70,10 @@

    Origin is generally which NIF or driver that allocated the blocks, or 'system' if it could not be determined.

    Type is the allocation category that the blocks - belong to, e.g. db_term, message or binary.

    + belong to, e.g. db_term, message or binary. The + categories correspond to those in + + erl_alloc.types.

    If one or more carriers could not be scanned in full without harming the responsiveness of the system, UnscannedSize is the number of bytes that had to be skipped.

    @@ -78,7 +89,10 @@

    TotalSize is the total size of the carrier, including its header.

    Allocations is a summary of the allocated blocks - in the carrier.

    + in the carrier. Note that carriers may contain multiple different + block types when carrier pools are shared between different allocator + types (see the erts_alloc + documentation for more details).

    FreeBlocks is a histogram of the free block sizes in the carrier.

    If the carrier could not be scanned in full without harming the @@ -115,11 +129,13 @@ allocator_types -

    The allocator types that will be searched. Note that blocks can - move freely between allocator types, so restricting the search to - certain allocators may return unexpected types (e.g. process - heaps when searching binary_alloc), or hide blocks that were - migrated out.

    +

    The allocator types that will be searched.

    +

    Specifying a specific allocator type may lead to strange results + when carrier migration between different allocator types has been + enabled: you may see unexpected types (e.g. process heaps when + searching binary_alloc), or fewer blocks than expected if the + carriers the blocks are on have been migrated out to an allocator + of a different type.

    Defaults to all alloc_util allocators.

    scheduler_ids @@ -217,10 +233,12 @@ instrument:carriers(#{ histogram_start => 512, histogram_width => 8 }). {ok,{512, - [{ll_alloc,1048576,0,1048344,71,false,{0,0,0,0,0,0,0,0}}, - {binary_alloc,1048576,0,324640,13,false,{3,0,0,1,0,0,0,2}}, - {eheap_alloc,2097152,0,1037200,45,false,{2,1,1,3,4,3,2,2}}, - {fix_alloc,32768,0,29544,82,false,{22,0,0,0,0,0,0,0}}, + [{driver_alloc,false,262144,0, + [{driver_alloc,1,32784}], + {0,0,0,0,0,0,0,1}}, + {binary_alloc,false,32768,0, + [{binary_alloc,15,4304}], + {3,0,0,0,1,0,0,0}}, {...}|...]}} ]]> diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml index 03e6a9af8cbd..7e25c3c5cc4d 100644 --- a/lib/runtime_tools/doc/src/notes.xml +++ b/lib/runtime_tools/doc/src/notes.xml @@ -32,6 +32,108 @@

    This document describes the changes made to the Runtime_Tools application.

    +
    Runtime_Tools 2.0 + +
    Fixed Bugs and Malfunctions + + +

    Fixed the type specification for + instrument:carriers/0,1

    +

    + Own Id: OTP-18499 Aux Id: PR-6946

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Add dbg:tracer(file, Filename) as a convenient way + to trace to a file in clean text.

    +

    + Own Id: OTP-18211 Aux Id: PR-6143

    +
    + +

    Handling of on_load modules during boot has + been improved by adding an extra step in the boot order + for embedded mode that runs all on_load handlers, + instead of relying on explicit invocation of them, later, + when the kernel supervision tree starts.

    This is + mostly a code improvement and OTP internal simplification + to avoid future bugs and to simplify code maintenance. +

    +

    + Own Id: OTP-18447

    +
    + +

    + Deprecates dbg:stop_clear/0 because it is simply a + function alias to dbg:stop/0

    +

    + Own Id: OTP-18478 Aux Id: GH-6903

    +
    + +

    The instrument module has been moved from + tools to runtime_tools.

    +

    + Own Id: OTP-18487 Aux Id: PR-6829

    +
    + +

    + Removed the experimental erts_alloc_config module. + It no longer produced good configurations and cannot be + fixed in a reasonably backwards compatible manner. It has + since OTP 25 been deprecated and scheduled for removal in + OTP 26.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18549 Aux Id: PR-7105

    +
    +
    +
    + +
    + +
    Runtime_Tools 1.19 + +
    Fixed Bugs and Malfunctions + + +

    + Reading port socket options on macOS and Windows "skips" + invalid options.

    +

    + Own Id: OTP-18012 Aux Id: #5798

    +
    +
    +
    + + +
    Improvements and New Features + + +

    dbg:stop/0 now behaves like + dbg:stop_clear/0, clearing all global trace + patterns for all functions.

    +

    + Own Id: OTP-17909 Aux Id: ERIERL-760

    +
    + +

    erts_alloc_config has been scheduled for + removal in OTP 26. It has not produced good + configurations for a very long time, and unfortunately it + cannot be fixed in a backwards compatible manner.

    +

    + Own Id: OTP-17939

    +
    +
    +
    + +
    +
    Runtime_Tools 1.18
    Fixed Bugs and Malfunctions diff --git a/lib/runtime_tools/doc/src/part.xml b/lib/runtime_tools/doc/src/part.xml index 34acf69fc8ab..9b92ab0bfd31 100644 --- a/lib/runtime_tools/doc/src/part.xml +++ b/lib/runtime_tools/doc/src/part.xml @@ -4,7 +4,7 @@
    - 20122016 + 20122023 Ericsson AB. All Rights Reserved. @@ -37,6 +37,7 @@ + diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml index fdca65422dda..7472956f2bf3 100644 --- a/lib/runtime_tools/doc/src/ref_man.xml +++ b/lib/runtime_tools/doc/src/ref_man.xml @@ -4,7 +4,7 @@
    - 19992018 + 19992023 Ericsson AB. All Rights Reserved. @@ -35,7 +35,7 @@ - + diff --git a/lib/runtime_tools/doc/src/specs.xml b/lib/runtime_tools/doc/src/specs.xml index 33fe7fa37051..f3152d0f0c1d 100644 --- a/lib/runtime_tools/doc/src/specs.xml +++ b/lib/runtime_tools/doc/src/specs.xml @@ -3,4 +3,5 @@ + diff --git a/lib/runtime_tools/doc/src/system_information.xml b/lib/runtime_tools/doc/src/system_information.xml index f52f461ddb49..b8ccc73418bf 100644 --- a/lib/runtime_tools/doc/src/system_information.xml +++ b/lib/runtime_tools/doc/src/system_information.xml @@ -74,7 +74,7 @@ versions of the same application installed in the system, but you do not use a boot - script identifing the correct application version.

    + script identifying the correct application version.

    Currently the sanity check is limited to verifying diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile index 76286c549912..9a80ca48f233 100644 --- a/lib/runtime_tools/src/Makefile +++ b/lib/runtime_tools/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2018. All Rights Reserved. +# Copyright Ericsson AB 1999-2023. 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. @@ -38,6 +38,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN) MODULES= \ appmon_info \ erts_alloc_config \ + instrument \ runtime_tools \ runtime_tools_sup \ dbg \ @@ -79,7 +80,7 @@ ERL_COMPILE_FLAGS += \ # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/runtime_tools/src/appmon_info.erl b/lib/runtime_tools/src/appmon_info.erl index ebff52664d6b..ad08a6c66f95 100644 --- a/lib/runtime_tools/src/appmon_info.erl +++ b/lib/runtime_tools/src/appmon_info.erl @@ -40,11 +40,11 @@ %% have a nice public interface function which should handle task %% administration. Tasks are identified by a "key" consisting of %% three items, the requesting pid, the name of the task and the -%% task auxillary parameter. The requesting pid is the pid of the +%% task auxiliary parameter. The requesting pid is the pid of the %% callee (in the appmon case it can be the node window for %% instance), the task name is whatever name the task is given %% (in the appmon case it can be app, app_ctrl or load). The task -%% name can be seen as the type of the task. The task auxillary +%% name can be seen as the type of the task. The task auxiliary %% parameter is an all purpose parameter that have a different %% meaning for each type of task so in appmon the Aux for app %% contains the root pid of the monitored application and in @@ -136,7 +136,7 @@ %%---------------------------------------------------------------------- %% Public interface %% -%% The Aux parameter is an auxillary parameter that can be used +%% The Aux parameter is an auxiliary parameter that can be used %% freely by the requesting process, it is included in the work %% task key. appmon uses it for storing the node name when %% requesting load and app_ctrl tasks, and appmon_a uses it for @@ -149,7 +149,7 @@ %% Do not use gen_server:start_link because we do not want the %% appmon_info to die when initiating process dies unless special %% conditions apply. -%% Uhu, we don't??? Made a fix so that this proces DOES indeed die +%% Uhu, we don't??? Made a fix so that this process DOES indeed die %% if it's starter dies. /Gunilla start_link(Node, Client, Opts) -> rpc:call(Node, ?MODULE, start_link2, [self(), Client, Opts]). @@ -473,7 +473,7 @@ get_pid(X) when is_tuple(X) -> element(2, X). %---------------------------------------------------------------------- %%--------------------------------------------------------------------- -%% Handling process trees of processses that are linked to each other +%% Handling process trees of processes that are linked to each other do_find_proc(Mode, DB, GL, Avoid) -> case get_next(DB) of diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index 7dd3c452e51a..ed274e2aa72f 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -41,6 +41,7 @@ match_front/2, match_rear/2, match_0_9/1]). +-deprecated([{stop_clear,0, "use dbg:stop/0 instead"}]). %%% Shell callable utility fun2ms(ShellFun) when is_function(ShellFun) -> @@ -317,8 +318,17 @@ tracer(process, {Handler,HandlerData}) -> tracer(module, Fun) when is_function(Fun) -> start(Fun); tracer(module, {Module, State}) -> - start(fun() -> {Module, State} end). - + start(fun() -> {Module, State} end); + +tracer(file, Filename) -> + tracer(process, + {fun F(E, undefined) -> + {ok, D} = file:open(Filename, [write]), + F(E, D); + F(E, D) -> + dhandler(E, D), + D + end, undefined}). remote_tracer(port, Fun) when is_function(Fun) -> remote_start(Fun); @@ -573,14 +583,14 @@ c(M, F, A, Flags) -> Mref = erlang:monitor(process, Pid), receive {'DOWN', Mref, _, _, Reason} -> - stop_clear(), + stop(), {error, Reason}; {Pid, Res} -> erlang:demonitor(Mref, [flush]), %% 'sleep' prevents the tracer (recv_all_traces) from %% receiving garbage {'EXIT',...} when dbg i stopped. timer:sleep(1), - stop_clear(), + stop(), Res end end. @@ -595,17 +605,23 @@ c(Parent, M, F, A, Flags) -> Parent ! {self(), Res}. stop() -> + {ok, _} = ctp(), + {ok, _} = ctpe('receive'), + {ok, _} = ctpe('send'), + Mref = erlang:monitor(process, dbg), catch dbg ! {self(),stop}, + receive - {'DOWN',Mref,_,_,_} -> - ok + {'DOWN',Mref,_,_,_} -> ok end. +%% This is a vestigial function that used to be documented as a variant of +%% `stop/0` that also clears global function traces. Since `stop/0` now clears +%% all tracing as the user would expect it to, we've removed this from the +%% documentation but keep it around for backwards compatibility, much like +%% `queue:lait`. stop_clear() -> - {ok, _} = ctp(), - {ok, _} = ctpe('receive'), - {ok, _} = ctpe('send'), stop(). %%% Calling the server. @@ -1593,14 +1609,14 @@ new_pattern_table() -> term_to_binary(x)}), ets:insert(PT, {c, - term_to_binary([{'_',[],[{message,{caller}}]}])}), + term_to_binary([{'_',[],[{message,{caller_line}}]}])}), ets:insert(PT, {caller_trace, term_to_binary(c)}), ets:insert(PT, {cx, term_to_binary([{'_',[],[{exception_trace}, - {message,{caller}}]}])}), + {message,{caller_line}}]}])}), ets:insert(PT, {caller_exception_trace, term_to_binary(cx)}), @@ -1938,6 +1954,6 @@ h(stop) -> h(stop_clear) -> help_display( ["stop_clear() -> ok", - " - Stops the dbg server and the tracing of all processes,", + " - Deprecated. Stops the dbg server and the tracing of all processes,", " and clears all trace patterns."]). diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl index 5fe62a46f6fe..65a85ddb0124 100644 --- a/lib/runtime_tools/src/dyntrace.erl +++ b/lib/runtime_tools/src/dyntrace.erl @@ -1,3 +1,23 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2023. 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(dyntrace). %%% @doc The Dynamic tracing interface module @@ -62,6 +82,18 @@ enabled/3]). -export([user_trace_i4s4/9]). % Know what you're doing! + +-nifs([available/0, user_trace_s1/1, user_trace_i4s4/9, user_trace_n/10, + + trace_procs/5, trace_ports/5, trace_running_procs/5, + trace_running_ports/5, trace_call/5, trace_send/5, + trace_receive/5, trace_garbage_collection/5, enabled_procs/3, + enabled_ports/3, enabled_running_procs/3, enabled_running_ports/3, + enabled_call/3, enabled_send/3, enabled_receive/3, + enabled_garbage_collection/3, + + enabled/3, trace/5]). + -compile(no_native). -on_load(on_load/0). @@ -88,7 +120,9 @@ on_load() -> filename:join([PrivDir, "lib", erlang:system_info(system_architecture)]), Candidate = - filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), + filelib:wildcard( + filename:join([ArchLibDir,LibName ++ "*" ]), + erl_prim_loader), case Candidate of [] -> Error1; _ -> diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl index ed36fe0589d4..e6ac47fa8f1a 100644 --- a/lib/runtime_tools/src/erts_alloc_config.erl +++ b/lib/runtime_tools/src/erts_alloc_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2021. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -20,732 +20,6 @@ %% %CopyrightEnd% %% -%%%------------------------------------------------------------------- -%%% File : erts_alloc_config.erl -%%% Author : Rickard Green -%%% Description : Generate an erts_alloc configuration suitable for -%%% a limited amount of runtime scenarios. -%%% -%%% Created : 9 May 2007 by Rickard Green -%%%------------------------------------------------------------------- - -module(erts_alloc_config). --record(state, {have_scenario = false, - alloc}). - - --record(alloc, {name, - enabled, - need_config_change, - alloc_util, - instances, - strategy, - acul, - low_mbc_blocks_size, - high_mbc_blocks_size, - sbct, - segments}). - --record(conf, - {segments, - format_to}). - --record(segment, {size,number}). - --define(PRINT_WITDH, 76). - --define(SERVER, '__erts_alloc_config__'). - --define(KB, 1024). --define(MB, 1048576). - --define(B2KB(B), ((((B) - 1) div ?KB) + 1)). --define(ROUNDUP(V, R), ((((V) - 1) div (R)) + 1)*(R)). - --define(LARGE_GROWTH_ABS_LIMIT, 20*?MB). --define(MBC_MSEG_LIMIT, 150). --define(FRAG_FACT, 1.25). --define(GROWTH_SEG_FACT, 2). --define(MIN_SEG_SIZE, 1*?MB). --define(SMALL_GROWTH_SEGS, 5). - --define(ALLOC_UTIL_ALLOCATOR(A), - A == binary_alloc; - A == std_alloc; - A == ets_alloc; - A == fix_alloc; - A == eheap_alloc; - A == ll_alloc; - A == sl_alloc; - A == temp_alloc; - A == driver_alloc). - --define(ALLOCATORS, - [binary_alloc, - ets_alloc, - eheap_alloc, - fix_alloc, - ll_alloc, - mseg_alloc, - sl_alloc, - std_alloc, - sys_alloc, - temp_alloc, - driver_alloc]). - --define(MMBCS_DEFAULTS, - [{binary_alloc, 131072}, - {std_alloc, 131072}, - {ets_alloc, 131072}, - {fix_alloc, 131072}, - {eheap_alloc, 524288}, - {ll_alloc, 131072}, - {sl_alloc, 131072}, - {temp_alloc, 131072}, - {driver_alloc, 131072}]). - -%%% -%%% Exported interface -%%% - --export([save_scenario/0, - make_config/0, - make_config/1, - stop/0]). - -%% Test and debug export --export([state/0]). - - -save_scenario() -> - req(save_scenario). - -make_config() -> - make_config(group_leader()). - -make_config(FileName) when is_list(FileName) -> - case file:open(FileName, [write]) of - {ok, IODev} -> - Res = req({make_config, IODev}), - ok = file:close(IODev), - Res; - Error -> - Error - end; -make_config(IODev) -> - req({make_config, IODev}). - -stop() -> - req(stop). - - -%% state() is intentionally undocumented, and is for testing -%% and debugging only... - -state() -> - req(state). - -%%% -%%% Server -%%% - -req(Req) -> - Ref = make_ref(), - ReqMsg = {request, self(), Ref, Req}, - req(ReqMsg, Ref, true). - -req(ReqMsg, Ref, TryStart) -> - req(ReqMsg, Ref, TryStart, erlang:monitor(process, ?SERVER)). - -req(ReqMsg, Ref, TryStart, Mon) -> - (catch ?SERVER ! ReqMsg), - receive - {response, Ref, Res} -> - erlang:demonitor(Mon, [flush]), - Res; - {'DOWN', Mon, _, _, noproc} -> - case TryStart of - true -> start_server(Ref, ReqMsg); - false -> {error, server_died} - end; - {'DOWN', Mon, _, _, Reason} -> - {error, Reason} - end. - -start_server(Ref, ReqMsg) -> - Starter = self(), - Pid = spawn(fun () -> - register(?SERVER, self()), - Starter ! {Ref, self(), started}, - server_loop(make_state()) - end), - Mon = erlang:monitor(process, Pid), - receive - {Ref, Pid, started} -> - req(ReqMsg, Ref, false, Mon); - {'DOWN', Mon, _, _, _} -> - req(ReqMsg, Ref, false) - end. - -server_loop(State) -> - NewState = receive - {request, From, Ref, save_scenario} -> - Alloc = save_scenario(State#state.alloc), - From ! {response, Ref, ok}, - State#state{alloc = Alloc, have_scenario = true}; - {request, From, Ref, {make_config, IODev}} -> - case State#state.have_scenario of - true -> - Conf = #conf{segments = ?MBC_MSEG_LIMIT, - format_to = IODev}, - Res = mk_config(Conf, State#state.alloc), - From ! {response, Ref, Res}, - ok; - _ -> - From ! {response, Ref, no_scenario_saved}, - ok - end, - State; - {request, From, Ref, stop} -> - From ! {response, Ref, ok}, - exit(normal); - {request, From, Ref, state} -> - From ! {response, Ref, State}, - State; - {request, From, Ref, Req} -> - From ! {response, Ref, {unknown_request, Req}}, - State; - _ -> - State - end, - server_loop(NewState). - -carrier_migration_support(aoff) -> - true; -carrier_migration_support(aoffcbf) -> - true; -carrier_migration_support(aoffcaobf) -> - true; -carrier_migration_support(_) -> - false. - -allocator_instances(ll_alloc, Strategy) -> - case carrier_migration_support(Strategy) of - true -> erlang:system_info(schedulers); - false -> 1 - end; -allocator_instances(_A, undefined) -> - 1; -allocator_instances(_A, _Strategy) -> - erlang:system_info(schedulers). - -strategy(temp_alloc, _AI) -> - af; -strategy(A, AI) -> - try - {A, OptList} = lists:keyfind(A, 1, AI), - {as, S} = lists:keyfind(as, 1, OptList), - S - catch - _ : _ -> - undefined - end. - -strategy_str(af) -> - "A fit"; -strategy_str(gf) -> - "Good fit"; -strategy_str(bf) -> - "Best fit"; -strategy_str(aobf) -> - "Address order best fit"; -strategy_str(aoff) -> - "Address order first fit"; -strategy_str(aoffcbf) -> - "Address order first fit carrier best fit"; -strategy_str(aoffcaobf) -> - "Address order first fit carrier adress order best fit"; -strategy_str(ageffcaoff) -> - "Age order first fit carrier address order first fit"; -strategy_str(ageffcbf) -> - "Age order first fit carrier best fit"; -strategy_str(ageffcaobf) -> - "Age order first fit carrier adress order best fit". - -default_acul(A, S) -> - case carrier_migration_support(S) of - false -> - 0; - true -> - case A of - ll_alloc -> 85; - eheap_alloc -> 45; - _ -> 60 - end - end. - -make_state() -> - {_, _, _, AI} = erlang:system_info(allocator), - #state{alloc = lists:map(fun (A) -> - S = strategy(A, AI), - #alloc{name = A, - strategy = S, - acul = default_acul(A, S), - instances = allocator_instances(A, S)} - end, - ?ALLOCATORS)}. - -%% -%% Save scenario -%% - -ai_value(Key1, Key2, AI) -> - case lists:keysearch(Key1, 1, AI) of - {value, {Key1, Value1}} -> - case lists:keysearch(Key2, 1, Value1) of - {value, Result} -> Result; - _ -> undefined - end; - _ -> undefined - end. - - -chk_mbcs_blocks_size(#alloc{low_mbc_blocks_size = undefined, - high_mbc_blocks_size = undefined} = Alc, - Min, - Max) -> - Alc#alloc{low_mbc_blocks_size = Min, - high_mbc_blocks_size = Max, - enabled = true}; -chk_mbcs_blocks_size(#alloc{low_mbc_blocks_size = LowBS, - high_mbc_blocks_size = HighBS} = Alc, - Min, - Max) -> - true = is_integer(LowBS), - true = is_integer(HighBS), - Alc1 = case Min < LowBS of - true -> Alc#alloc{low_mbc_blocks_size = Min}; - false -> Alc - end, - case Max > HighBS of - true -> Alc1#alloc{high_mbc_blocks_size = Max}; - false -> Alc1 - end. - -set_alloc_util(#alloc{alloc_util = AU} = Alc, AU) -> - Alc; -set_alloc_util(Alc, Val) -> - Alc#alloc{alloc_util = Val}. - -chk_sbct(#alloc{sbct = undefined} = Alc, AI) -> - case ai_value(options, sbct, AI) of - {sbct, Bytes} when is_integer(Bytes) -> Alc#alloc{sbct = b2kb(Bytes)}; - _ -> Alc - end; -chk_sbct(Alc, _AI) -> - Alc. - -save_scenario(AlcList) -> - %% The high priority is not really necessary. It is - %% used since it will make retrieval of allocator - %% information less spread out in time on a highly - %% loaded system. - OP = process_flag(priority, high), - Res = do_save_scenario(AlcList), - process_flag(priority, OP), - Res. - -save_ai2(#alloc{name=Name}=Alc0, AI) -> - Alc1 = chk_sbct(Alc0, AI), - - {Alc, IsAUtil} = - case ai_value(mbcs, blocks, AI) of - {blocks, Bs} -> - case ai_value(Name, size, Bs) of - {size, MinBS, _, MaxBS} -> - {chk_mbcs_blocks_size(Alc1, MinBS, MaxBS), true}; - _ -> - {Alc1, false} - end; - _ -> - {Alc1, false} - end, - - set_alloc_util(Alc, IsAUtil). - -save_ai(Alc, [{instance, 0, AI}]) -> - save_ai2(Alc, AI); -save_ai(Alc, [{instance, _, _}, {instance, _, _}| _]) -> - Alc#alloc{enabled = true, need_config_change = true}; -save_ai(Alc, AI) -> - save_ai2(Alc, AI). % Non erts_alloc_util allocator - -do_save_scenario(AlcList) -> - lists:map(fun (#alloc{enabled = false} = Alc) -> - Alc; - (#alloc{name = Name} = Alc) -> - case erlang:system_info({allocator, Name}) of - undefined -> - exit({bad_allocator_name, Name}); - false -> - Alc#alloc{enabled = false}; - AI when is_list(AI) -> - save_ai(Alc, AI) - end - end, - AlcList). - -%% -%% Make configuration -%% - -conf_size(Bytes) when is_integer(Bytes), Bytes < 0 -> - exit({bad_value, Bytes}); -conf_size(Bytes) when is_integer(Bytes), Bytes < 1*?MB -> - ?ROUNDUP(?B2KB(Bytes), 256); -conf_size(Bytes) when is_integer(Bytes), Bytes < 10*?MB -> - ?ROUNDUP(?B2KB(Bytes), ?B2KB(1*?MB)); -conf_size(Bytes) when is_integer(Bytes), Bytes < 100*?MB -> - ?ROUNDUP(?B2KB(Bytes), ?B2KB(2*?MB)); -conf_size(Bytes) when is_integer(Bytes), Bytes < 256*?MB -> - ?ROUNDUP(?B2KB(Bytes), ?B2KB(5*?MB)); -conf_size(Bytes) when is_integer(Bytes) -> - ?ROUNDUP(?B2KB(Bytes), ?B2KB(10*?MB)). - -sbct(#conf{format_to = FTO}, #alloc{name = A, sbct = SBCT}) -> - fc(FTO, "Sbc threshold size of ~p kilobytes.", [SBCT]), - format(FTO, " +M~csbct ~p~n", [alloc_char(A), SBCT]). - -default_mmbcs(temp_alloc = A, _Insts) -> - {value, {A, MMBCS_Default}} = lists:keysearch(A, 1, ?MMBCS_DEFAULTS), - MMBCS_Default; -default_mmbcs(A, Insts) -> - {value, {A, MMBCS_Default}} = lists:keysearch(A, 1, ?MMBCS_DEFAULTS), - I = case Insts > 4 of - true -> 4; - _ -> Insts - end, - ?ROUNDUP(MMBCS_Default div I, ?B2KB(1*?KB)). - -mmbcs(#conf{format_to = FTO}, - #alloc{name = A, instances = Insts, low_mbc_blocks_size = BlocksSize}) -> - BS = case A of - temp_alloc -> BlocksSize; - _ -> BlocksSize div Insts - end, - DefMMBCS = default_mmbcs(A, Insts), - case {Insts, BS > DefMMBCS} of - {1, true} -> - MMBCS = conf_size(BS), - fc(FTO, "Main mbc size of ~p kilobytes.", [MMBCS]), - format(FTO, " +M~cmmbcs ~p~n", [alloc_char(A), MMBCS]); - _ -> - MMBCS = ?B2KB(DefMMBCS), - fc(FTO, "Main mbc size of ~p kilobytes.", [MMBCS]), - format(FTO, " +M~cmmbcs ~p~n", [alloc_char(A), MMBCS]), - ok - end. - -smbcs_lmbcs(#conf{format_to = FTO}, - #alloc{name = A, segments = Segments}) -> - MBCS = Segments#segment.size, - AC = alloc_char(A), - fc(FTO, "Mseg mbc size of ~p kilobytes.", [MBCS]), - format(FTO, " +M~csmbcs ~p +M~clmbcs ~p~n", [AC, MBCS, AC, MBCS]), - ok. - -alloc_char(binary_alloc) -> $B; -alloc_char(std_alloc) -> $D; -alloc_char(ets_alloc) -> $E; -alloc_char(fix_alloc) -> $F; -alloc_char(eheap_alloc) -> $H; -alloc_char(ll_alloc) -> $L; -alloc_char(mseg_alloc) -> $M; -alloc_char(driver_alloc) -> $R; -alloc_char(sl_alloc) -> $S; -alloc_char(temp_alloc) -> $T; -alloc_char(sys_alloc) -> $Y; -alloc_char(Alloc) -> - exit({bad_allocator, Alloc}). - -conf_alloc(#conf{format_to = FTO}, - #alloc{name = A, enabled = false}) -> - fcl(FTO, A), - fcp(FTO, - "WARNING: ~p has been disabled. Consider enabling ~p by passing " - "the \"+M~ce true\" command line argument and rerun " - "erts_alloc_config.", - [A, A, alloc_char(A)]); -conf_alloc(#conf{format_to = FTO}, - #alloc{name = A, need_config_change = true}) -> - fcl(FTO, A), - fcp(FTO, - "WARNING: ~p has been configured in a way that prevents " - "erts_alloc_config from creating a configuration. The configuration " - "will be automatically adjusted to fit erts_alloc_config if you " - "use the \"+Mea config\" command line argument while running " - "erts_alloc_config.", - [A]); -conf_alloc(#conf{format_to = FTO} = Conf, - #alloc{name = A, alloc_util = true} = Alc) -> - fcl(FTO, A), - chk_xnote(Conf, Alc), - au_conf_alloc(Conf, Alc), - format(FTO, "#~n", []); -conf_alloc(#conf{format_to = FTO} = Conf, #alloc{name = A} = Alc) -> - fcl(FTO, A), - chk_xnote(Conf, Alc). - -chk_xnote(#conf{format_to = FTO}, - #alloc{name = sys_alloc}) -> - fcp(FTO, "Cannot be configured. Default malloc implementation used."); -chk_xnote(#conf{format_to = FTO}, - #alloc{name = mseg_alloc}) -> - fcp(FTO, "Default configuration used."); -chk_xnote(#conf{format_to = FTO}, - #alloc{name = ll_alloc}) -> - fcp(FTO, - "Note, blocks allocated with ll_alloc are very " - "seldom deallocated. Placing blocks in mseg " - "carriers is therefore very likely only a waste " - "of resources."); -chk_xnote(#conf{}, #alloc{}) -> - ok. - -au_conf_alloc(#conf{format_to = FTO} = Conf, - #alloc{name = A, - alloc_util = true, - instances = Insts, - acul = Acul, - strategy = Strategy, - low_mbc_blocks_size = Low, - high_mbc_blocks_size = High} = Alc) -> - fcp(FTO, "Usage of mbcs: ~p - ~p kilobytes", [?B2KB(Low), ?B2KB(High)]), - case Insts of - 1 -> - fc(FTO, "One instance used."), - format(FTO, " +M~ct false~n", [alloc_char(A)]); - _ -> - fc(FTO, "~p + 1 instances used.", - [Insts]), - format(FTO, " +M~ct true~n", [alloc_char(A)]), - case Strategy of - undefined -> - ok; - _ -> - fc(FTO, "Allocation strategy: ~s.", - [strategy_str(Strategy)]), - format(FTO, " +M~cas ~s~n", [alloc_char(A), - atom_to_list(Strategy)]) - end, - case carrier_migration_support(Strategy) of - false -> - ok; - true -> - fc(FTO, "Abandon carrier utilization limit of ~p%.", [Acul]), - format(FTO, " +M~cacul ~p~n", [alloc_char(A), Acul]) - end - end, - mmbcs(Conf, Alc), - smbcs_lmbcs(Conf, Alc), - sbct(Conf, Alc). - -calc_seg_size(Growth, Segs) -> - conf_size(round(Growth*?FRAG_FACT*?GROWTH_SEG_FACT) div Segs). - -calc_growth_segments(Conf, AlcList0) -> - CalcSmall = fun (#alloc{name = ll_alloc, instances = 1} = Alc, Acc) -> - {Alc#alloc{segments = #segment{size = conf_size(0), - number = 0}}, - Acc}; - (#alloc{alloc_util = true, - instances = Insts, - low_mbc_blocks_size = LowMBC, - high_mbc_blocks_size = High} = Alc, - {SL, AL}) -> - Low = case Insts of - 1 -> LowMBC; - _ -> 0 - end, - Growth = High - Low, - case Growth >= ?LARGE_GROWTH_ABS_LIMIT of - true -> - {Alc, {SL, AL+1}}; - false -> - Segs = ?SMALL_GROWTH_SEGS, - SegSize = calc_seg_size(Growth, Segs), - {Alc#alloc{segments - = #segment{size = SegSize, - number = Segs}}, - {SL - Segs, AL}} - - end; - (Alc, Acc) -> {Alc, Acc} - end, - {AlcList1, {SegsLeft, AllocsLeft}} - = lists:mapfoldl(CalcSmall, {Conf#conf.segments, 0}, AlcList0), - case AllocsLeft of - 0 -> - AlcList1; - _ -> - SegsPerAlloc = case (SegsLeft div AllocsLeft) + 1 of - SPA when SPA < ?SMALL_GROWTH_SEGS -> - ?SMALL_GROWTH_SEGS; - SPA -> - SPA - end, - CalcLarge = fun (#alloc{alloc_util = true, - segments = undefined, - instances = Insts, - low_mbc_blocks_size = LowMBC, - high_mbc_blocks_size = High} = Alc) -> - Low = case Insts of - 1 -> LowMBC; - _ -> 0 - end, - Growth = High - Low, - SegSize = calc_seg_size(Growth, - SegsPerAlloc), - Alc#alloc{segments - = #segment{size = SegSize, - number = SegsPerAlloc}}; - (Alc) -> - Alc - end, - lists:map(CalcLarge, AlcList1) - end. - -mk_config(#conf{format_to = FTO} = Conf, AlcList) -> - format_header(FTO), - Res = lists:foreach(fun (Alc) -> conf_alloc(Conf, Alc) end, - calc_growth_segments(Conf, AlcList)), - format_footer(FTO), - Res. - -format_header(FTO) -> - {Y,Mo,D} = erlang:date(), - {H,Mi,S} = erlang:time(), - fcl(FTO), - fcl(FTO, "erts_alloc configuration"), - fcl(FTO), - fcp(FTO, - "This erts_alloc configuration was automatically " - "generated at ~w-~2..0w-~2..0w ~2..0w:~2..0w.~2..0w by " - "erts_alloc_config.", - [Y, Mo, D, H, Mi, S]), - fcp(FTO, - "~s was used when generating the configuration.", - [string:trim(erlang:system_info(system_version), both, "$\n")]), - case erlang:system_info(schedulers) of - 1 -> ok; - Schdlrs -> - fcp(FTO, - "NOTE: This configuration was made for ~p schedulers. " - "It is very important that ~p schedulers are used.", - [Schdlrs, Schdlrs]) - end, - fcp(FTO, - "This configuration is intended as a suggestion and " - "may need to be adjusted manually. Instead of modifying " - "this file, you are advised to write another configuration " - "file and override values that you want to change. " - "Doing it this way simplifies things when you want to " - "rerun erts_alloc_config."), - fcp(FTO, - "This configuration is based on the actual use of " - "multi-block carriers (mbcs) for a set of different " - "runtime scenarios. Note that this configuration may " - "perform bad, ever horrible, for other runtime " - "scenarios."), - fcp(FTO, - "You are advised to rerun erts_alloc_config if the " - "applications run when the configuration was made " - "are changed, or if the load on the applications have " - "changed since the configuration was made. You are also " - "advised to rerun erts_alloc_config if the Erlang runtime " - "system used is changed."), - fcp(FTO, - "Note, that the singel-block carrier (sbc) parameters " - "very much effects the use of mbcs. Therefore, if you " - "change the sbc parameters, you are advised to rerun " - "erts_alloc_config."), - fcp(FTO, - "For more information see the erts_alloc_config(3) " - "documentation."), - ok. - -format_footer(FTO) -> - fcl(FTO). - -%%% -%%% Misc. -%%% - -b2kb(B) when is_integer(B) -> - MaxKB = (1 bsl erlang:system_info(wordsize)*8) div 1024, - case ?B2KB(B) of - KB when KB > MaxKB -> MaxKB; - KB -> KB - end. - -format(false, _Frmt) -> - ok; -format(IODev, Frmt) -> - io:format(IODev, Frmt, []). - -format(false, _Frmt, _Args) -> - ok; -format(IODev, Frmt, Args) -> - io:format(IODev, Frmt, Args). - -%% fcp: format comment paragraf -fcp(IODev, Frmt, Args) -> - fc(IODev, Frmt, Args), - format(IODev, "#~n"). - -fcp(IODev, Frmt) -> - fc(IODev, Frmt), - format(IODev, "#~n"). - -%% fc: format comment -fc(IODev, Frmt, Args) -> - fc(IODev, lists:flatten(io_lib:format(Frmt, Args))). - -fc(IODev, String) -> - fc_aux(IODev, string:lexemes(String, " "), 0). - -fc_aux(_IODev, [], 0) -> - ok; -fc_aux(IODev, [], _Len) -> - format(IODev, "~n"); -fc_aux(IODev, [T|Ts], 0) -> - Len = 2 + string:length(T), - format(IODev, "# ~s", [T]), - fc_aux(IODev, Ts, Len); -fc_aux(IODev, [T|Ts] = ATs, Len) -> - TLength = string:length(T), - case (TLength + Len) >= ?PRINT_WITDH of - true -> - format(IODev, "~n"), - fc_aux(IODev, ATs, 0); - false -> - NewLen = Len + 1 + TLength, - format(IODev, " ~s", [T]), - fc_aux(IODev, Ts, NewLen) - end. - -%% fcl: format comment line -fcl(FTO) -> - EndStr = "# ", - Precision = string:length(EndStr), - FieldWidth = -1*(?PRINT_WITDH), - format(FTO, "~*.*.*s~n", [FieldWidth, Precision, $-, EndStr]). - -fcl(FTO, A) when is_atom(A) -> - fcl(FTO, atom_to_list(A)); -fcl(FTO, Str) when is_list(Str) -> - Str2 = "# --- " ++ Str ++ " ", - Precision = string:length(Str2), - FieldWidth = -1*(?PRINT_WITDH), - format(FTO, "~*.*.*s~n", [FieldWidth, Precision, $-, Str2]). +-removed({'_','_', "this module has as of OTP 26.0 been removed"}). diff --git a/lib/tools/src/instrument.erl b/lib/runtime_tools/src/instrument.erl similarity index 96% rename from lib/tools/src/instrument.erl rename to lib/runtime_tools/src/instrument.erl index 6b2de541ec22..5941c4a8df3d 100644 --- a/lib/tools/src/instrument.erl +++ b/lib/runtime_tools/src/instrument.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -97,9 +97,9 @@ alloc_hist_merge_hist(Index, A, B) -> InPool :: boolean(), TotalSize :: non_neg_integer(), UnscannedSize :: non_neg_integer(), - Allocations :: {Type :: atom(), - Count :: non_neg_integer(), - Size :: non_neg_integer()}, + Allocations :: [{Type :: atom(), + Count :: non_neg_integer(), + Size :: non_neg_integer()}], FreeBlocks :: block_histogram()}]}. -spec carriers() -> {ok, Result} | {error, Reason} when diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl index ecbba3d0d8ca..ccd2240a99f8 100644 --- a/lib/runtime_tools/src/observer_backend.erl +++ b/lib/runtime_tools/src/observer_backend.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -63,7 +63,7 @@ vsn() -> socket_info() -> Info0 = socket:info(), {Counters, Info1} = maps:take(counters, Info0), - IovMax = maps:get(iov_max , Info1), + IovMax = maps:get(iov_max, Info1), NumMons = socket:number_of_monitors(), [{iov_max, IovMax}, {num_monitors, NumMons} | maps:to_list(Counters)]. @@ -205,22 +205,53 @@ inet_port_extra({_,Type},Port) when Type =:= "udp_inet"; [{local_address,LAddr}]; {error, _} -> [] end ++ - case inet:getopts(Port, - [active, broadcast, buffer, bind_to_device, - delay_send, deliver, dontroute, exit_on_close, - header, high_msgq_watermark, high_watermark, - ipv6_v6only, keepalive, linger, low_msgq_watermark, - low_watermark, mode, netns, nodelay, packet, - packet_size, priority, read_packets, recbuf, - reuseaddr, send_timeout, send_timeout_close, - show_econnreset, sndbuf, tos, tclass]) of - {ok, Opts} -> [{options, Opts}]; - {error, _} -> [] - end, + [{options, get_sock_opts(Port)}], [{inet,Data}]; inet_port_extra(_,_) -> []. +sock_opts() -> + [active, broadcast, buffer, bind_to_device, + delay_send, deliver, dontroute, exit_on_close, + header, high_msgq_watermark, high_watermark, + ipv6_v6only, keepalive, linger, low_msgq_watermark, + low_watermark, mode, netns, nodelay, packet, + packet_size, priority, read_packets, recbuf, + reuseaddr, send_timeout, send_timeout_close, + show_econnreset, sndbuf, tos, tclass]. + +get_sock_opts(Port) -> + get_sock_opts(Port, sock_opts()). + +get_sock_opts(Port, Opts) -> + get_sock_opts(Port, Opts, []). + +%% The reason we are doing it this way, is because if there +%% is an issue with one of the options, we should just skip +%% that option and continue with the next. +%% Better to have some options then none. +get_sock_opts(_Port, [], Acc) -> + lists:reverse(Acc); +get_sock_opts(Port, [Opt|Opts], Acc) -> + case inet:getopts(Port, [Opt]) of + {ok, [Res]} -> + get_sock_opts(Port, Opts, [Res|Acc]); + {ok, []} -> % No value? + Res = {Opt, "-"}, + get_sock_opts(Port, Opts, [Res|Acc]); + {error, einval} -> + Res = {Opt, "Not Supported"}, + get_sock_opts(Port, Opts, [Res|Acc]); + + %% If the option is "invalid", the reason would be 'einval', + %% so this error must be something else. + %% But if the option just vanish, we don't know what is + %% going on. So, do something similar to socket (see below). + {error, Reason} -> + Res = {Opt, f("error:~p", [Reason])}, + get_sock_opts(Port, Opts, [Res|Acc]) + end. + get_socket_list() -> GetOpt = fun(_Sock, {Opt, false}) -> diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index dfdd58015baa..6daa698cb841 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -23,7 +23,7 @@ {modules, [appmon_info, dbg,observer_backend,runtime_tools, runtime_tools_sup,erts_alloc_config, ttb_autostart,dyntrace,system_information, - scheduler, + scheduler, instrument, msacc]}, {registered, [runtime_tools_sup]}, {applications, [kernel, stdlib]}, diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl index 9bbb87dfb40b..3743b641d901 100644 --- a/lib/runtime_tools/src/system_information.erl +++ b/lib/runtime_tools/src/system_information.erl @@ -38,7 +38,6 @@ application/1, application/2, environment/0, environment/1, module/1, module/2, - modules/1, sanity_check/0]). %% gen_server callbacks @@ -124,10 +123,6 @@ module(M) when is_atom(M) -> module(M, []). module(M, Opts) when is_atom(M), is_list(Opts) -> gen_server:call(?SERVER, {module, M, Opts}, infinity). -modules(Opt) when is_atom(Opt) -> - gen_server:call(?SERVER, {modules, Opt}, infinity). - - -spec sanity_check() -> ok | {failed, Failures} when Application :: atom(), ApplicationVersion :: string(), @@ -190,12 +185,6 @@ handle_call({module, M, Opts}, _From, #state{ report = Report } = S) -> print_modules_from_code(M, Mods, Opts), {reply, ok, S}; -handle_call({modules, native}, _From, #state{ report = Report } = S) -> - Codes = get_native_modules_from_code(get_value([code],Report)), - io:format("~p~n", [Codes]), - {reply, ok, S}; - - handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -249,31 +238,6 @@ find_modules(M, [{M, _}=Info|Ms]) -> [Info|find_modules(M,Ms)]; find_modules(M, [_|Ms]) -> find_modules(M, Ms); find_modules(_, []) -> []. -get_native_modules_from_code([{application, {App, Info}}|Cs]) -> - case get_native_modules(get_value([modules], Info)) of - [] -> get_native_modules_from_code(Cs); - Mods -> - Path = get_value([path], Info), - Vsn = get_value([vsn], Info), - [{App, Vsn, Path, Mods}|get_native_modules_from_code(Cs)] - end; -get_native_modules_from_code([{code, Info}|Cs]) -> - case get_native_modules(get_value([modules], Info)) of - [] -> get_native_modules_from_code(Cs); - Mods -> - Path = get_value([path], Info), - [{Path, Mods}|get_native_modules_from_code(Cs)] - end; -get_native_modules_from_code([]) -> []. - -get_native_modules([]) -> []; -get_native_modules([{Mod, Info}|Ms]) -> - case proplists:get_value(native, Info) of - false -> get_native_modules(Ms); - _ -> [Mod|get_native_modules(Ms)] - end. - - %% print information print_applications([{application, App}|Apps], Opts) -> @@ -320,14 +284,12 @@ print_module_from_code(M, {Path, [{M,ModInfo}]}) -> io:format(" from path \"~ts\" (no application):~n", [Path]), io:format(" - compiler: ~s~n", [get_value([compiler], ModInfo)]), io:format(" - md5: ~s~n", [get_value([md5], ModInfo)]), - io:format(" - native: ~w~n", [get_value([native], ModInfo)]), io:format(" - loaded: ~w~n", [get_value([loaded], ModInfo)]), ok; print_module_from_code(M, {App,Vsn,Path,[{M,ModInfo}]}) -> io:format(" from path \"~ts\" (~w-~s):~n", [Path,App,Vsn]), io:format(" - compiler: ~s~n", [get_value([compiler], ModInfo)]), io:format(" - md5: ~s~n", [get_value([md5], ModInfo)]), - io:format(" - native: ~w~n", [get_value([native], ModInfo)]), io:format(" - loaded: ~w~n", [get_value([loaded], ModInfo)]), ok. @@ -335,7 +297,6 @@ print_module({Mod, ModInfo}) -> io:format(" - ~w:~n", [Mod]), io:format(" - compiler: ~s~n", [get_value([compiler], ModInfo)]), io:format(" - md5: ~s~n", [get_value([md5], ModInfo)]), - io:format(" - native: ~w~n", [get_value([native], ModInfo)]), io:format(" - loaded: ~w~n", [get_value([loaded], ModInfo)]), ok. @@ -387,7 +348,6 @@ os_getenv_erts_specific() -> os_getenv_erts_specific([ "BINDIR", "DIALYZER_EMULATOR", - "CERL_DETACHED_PROG", "EMU", "ERL_CONSOLE_MODE", "ERL_CRASH_DUMP", @@ -572,7 +532,6 @@ emit_module_info(EmitChunk, Beam) -> EmitChunk("{~w,[" "{loaded,~w}," - "{native,false}," "{compiler,~w}," "{md5,~w}" "]}", @@ -849,7 +808,7 @@ get_apps([Path|Paths], Apps) -> [AppFile] -> get_apps(Paths, [app_file_to_app(AppFile) | Apps]); [_AppFile| _] = AppFiles -> - %% Strange with multple .app files... Lets put them + %% Strange with multiple .app files... Lets put them %% all in the list and see what we get... lists:map(fun (AF) -> app_file_to_app(AF) diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile index e5a087f3ad57..a04e1ae97e59 100644 --- a/lib/runtime_tools/test/Makefile +++ b/lib/runtime_tools/test/Makefile @@ -5,10 +5,10 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk MODULES = \ dyntrace_SUITE \ dyntrace_lttng_SUITE \ + instrument_SUITE \ runtime_tools_SUITE \ system_information_SUITE \ dbg_SUITE \ - erts_alloc_config_SUITE \ scheduler_SUITE \ msacc_SUITE \ zzz_SUITE @@ -31,6 +31,7 @@ RELSYSDIR = $(RELEASE_PATH)/runtime_tools_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -Werror +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -42,7 +43,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: @@ -65,5 +66,6 @@ release_tests_spec: make_emakefile $(INSTALL_DATA) $(EMAKEFILE) runtime_tools.cover "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) + $(INSTALL_DATA) $(ERL_TOP)/make/otp_version_tickets "$(RELSYSDIR)/system_information_SUITE_data" release_docs_spec: diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index 44e9b7d00d4c..2d98284e2bfd 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -23,7 +23,7 @@ -export([all/0, suite/0, init_per_suite/1, end_per_suite/1, big/1, tiny/1, simple/1, message/1, distributed/1, port/1, send/1, recv/1, - ip_port/1, file_port/1, file_port2/1, + ip_port/1, file_port/1, file_port2/1, file_tracer/1, ip_port_busy/1, wrap_port/1, wrap_port_time/1, with_seq_trace/1, dead_suspend/1, local_trace/1, saved_patterns/1, tracer_exit_on_stop/1, @@ -41,7 +41,7 @@ suite() -> all() -> [big, tiny, simple, message, distributed, port, ip_port, send, recv, - file_port, file_port2, ip_port_busy, + file_port, file_port2, file_tracer, ip_port_busy, wrap_port, wrap_port_time, with_seq_trace, dead_suspend, local_trace, saved_patterns, tracer_exit_on_stop, erl_tracer, distributed_erl_tracer]. @@ -50,7 +50,7 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - dbg:stop_clear(), + dbg:stop(), ok. %% Rudimentary interface test @@ -89,7 +89,7 @@ big(Config) when is_list(Config) -> ok=file:set_cwd(OldCurDir) after - dbg:stop_clear() + dbg:stop() end, ok. @@ -120,7 +120,7 @@ tiny(Config) when is_list(Config) -> failure end after - dbg:stop_clear(), + dbg:stop(), ok = file:set_cwd(OldCurDir) end, ok. @@ -136,7 +136,7 @@ simple(Config) when is_list(Config) -> S = self(), [{trace,S,call,{dbg,ltp,[]}}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -152,7 +152,7 @@ message(Config) when is_list(Config) -> ok = dbg:ltp(), ok = dbg:ln() after - dbg:stop_clear() + dbg:stop() end, S = self(), [{trace,S,call,{dbg,ltp,[]},S}, @@ -161,9 +161,9 @@ message(Config) when is_list(Config) -> send(Config) when is_list(Config) -> {ok, _} = start(), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), rpc:call(Node, code, add_patha, - [filename:join(proplists:get_value(data_dir, Config), "..")]), + [filename:dirname(proplists:get_value(data_dir, Config))]), try Echo = fun F() -> receive {From, M} -> @@ -172,7 +172,7 @@ send(Config) when is_list(Config) -> end end, Rcvr = spawn_link(Echo), - RemoteRcvr = spawn_link(Node, Echo), + RemoteRcvr = spawn(Node, Echo), {ok, [{matched, _, 1}]} = dbg:p(Rcvr, send), @@ -222,7 +222,7 @@ send(Config) when is_list(Config) -> %% Test that distributed dbg works dbg:tracer(Node, process, {fun myhandler/2, self()}), Rcvr2 = spawn_link(Echo), - RemoteRcvr2 = spawn_link(Node, Echo), + RemoteRcvr2 = spawn(Node, Echo), dbg:p(Rcvr2, [send]), dbg:p(RemoteRcvr2, [send]), dbg:tpe(send, [{['_', hej],[],[]}]), @@ -235,7 +235,8 @@ send(Config) when is_list(Config) -> ok after - dbg:stop_clear() + dbg:stop(), + peer:stop(Peer) end. send_test(Pid, Pattern, Msg, TraceEvent) -> @@ -270,7 +271,7 @@ send_test_rcv(Pid, Msg, S, TraceEvent) -> recv(Config) when is_list(Config) -> {ok, _} = start(), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), rpc:call(Node, code, add_patha, [filename:join(proplists:get_value(data_dir, Config), "..")]), try @@ -281,7 +282,7 @@ recv(Config) when is_list(Config) -> end end, Rcvr = spawn_link(Echo), - RemoteRcvr = spawn_link(Node, Echo), + RemoteRcvr = spawn(Node, Echo), {ok, [{matched, _, 1}]} = dbg:p(Rcvr, 'receive'), @@ -333,7 +334,7 @@ recv(Config) when is_list(Config) -> %% Test that distributed dbg works dbg:tracer(Node, process, {fun myhandler/2, self()}), Rcvr2 = spawn_link(Echo), - RemoteRcvr2 = spawn_link(Node, Echo), + RemoteRcvr2 = spawn(Node, Echo), dbg:p(Rcvr2, ['receive']), dbg:p(RemoteRcvr2, ['receive']), dbg:tpe('receive', [{[node(), '_', '$1'],[{'==',{element,2,'$1'}, hej}],[]}]), @@ -346,7 +347,8 @@ recv(Config) when is_list(Config) -> ok after - dbg:stop_clear() + dbg:stop(), + peer:stop(Peer) end. recv_test(Pid, Pattern, Msg, TraceEvent) -> @@ -382,7 +384,7 @@ recv_test_rcv(Pid, Msg, TraceEvent) -> %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), try RexPid = rpc:call(Node, erlang, whereis, [rex]), RexPidList = pid_to_list(RexPid), @@ -410,8 +412,8 @@ distributed(Config) when is_list(Config) -> %% stop() after - dbg:stop_clear(), - stop_slave(Node) + dbg:stop(), + peer:stop(Peer) end, ok. @@ -461,7 +463,7 @@ local_trace(Config) when is_list(Config) -> {dbg_SUITE,not_exported,1}, {error,badarith}}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -486,7 +488,7 @@ port(Config) when is_list(Config) -> {trace,Port,getting_linked,S}, {trace,Port,closed,normal}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -512,7 +514,7 @@ saved_patterns(Config) when is_list(Config) -> S = self(), [{trace,S,call,{dbg,ltp,[]},blahonga}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -544,7 +546,7 @@ ip_port(Config) when is_list(Config) -> [{trace,S,call,{dbg,ltp,[]},S}, {trace,S,call,{dbg,ln,[]},hej}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -560,7 +562,7 @@ ip_port_busy(Config) when is_list(Config) -> io:format("Error reason = ~p~n", [Reason]), true = port_close(Port) after - dbg:stop_clear() + dbg:stop() end, ok. @@ -585,7 +587,7 @@ file_port(Config) when is_list(Config) -> {trace,S,call,{dbg,ln,[]},hej}, end_of_trace] = flush() after - dbg:stop_clear(), + dbg:stop(), file:delete(FName) end, ok. @@ -614,7 +616,32 @@ file_port2(Config) when is_list(Config) -> stop(), [] = flush() after - dbg:stop_clear(), + dbg:stop(), + file:delete(FName) + end, + ok. + +%% Test tracing to file +file_tracer(Config) when is_list(Config) -> + stop(), + FName = make_temp_name(Config), + %% Ok, lets try with flush and follow_file. + {ok, _} = dbg:tracer(file, FName), + try + {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + {ok, _} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), + {ok, _} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), + ok = dbg:ltp(), + timer:sleep(100), + {ok, LTP} = file:read_file(FName), + <<"dbg:ltp()",_/binary>> = string:find(LTP, "dbg:ltp() ("++pid_to_list(self())++")"), + ok = dbg:ln(), + timer:sleep(100), + {ok, LN} = file:read_file(FName), + <<"dbg:ln()",_/binary>> = string:find(LN, "dbg:ln() (hej)"), + stop() + after + dbg:stop(), file:delete(FName) end, ok. @@ -682,7 +709,7 @@ wrap_port(Config) when is_list(Config) -> %% lists:map(fun(F) -> file:delete(F) end, Files) after - dbg:stop_clear() + dbg:stop() end, ok. @@ -754,7 +781,7 @@ wrap_port_time(Config) when is_list(Config) -> end_of_trace] = flush(), lists:map(fun(F) -> file:delete(F) end, Files) after - dbg:stop_clear() + dbg:stop() end, ok. @@ -780,7 +807,7 @@ with_seq_trace(Config) when is_list(Config) -> {seq_trace,0,{send,_,Server,S,{dbg,{ok,Tracer}}}}] = flush() after - dbg:stop_clear() + dbg:stop() end, ok. @@ -791,7 +818,7 @@ dead_suspend(Config) when is_list(Config) -> try survived = run_dead_suspend() after - dbg:stop_clear() + dbg:stop() end. run_dead_suspend() -> @@ -870,7 +897,7 @@ distributed_erl_tracer(Config) -> ok = load_nif(Config), LNode = node(), - RNode = start_slave(), + {ok, Peer, RNode} = ?CT_PEER(), true = rpc:call(RNode, code, add_patha, [filename:join(proplists:get_value(data_dir, Config), "..")]), ok = rpc:call(RNode, ?MODULE, load_nif, [Config]), @@ -899,7 +926,7 @@ distributed_erl_tracer(Config) -> RCall = spawn_link(RNode, fun() -> ?MODULE:dummy() end), [{RCall, call, RNifProxy, RCall, {?MODULE, dummy, []}, #{}}] = flush(), - + peer:stop(Peer), ok. load_nif(Config) -> @@ -922,29 +949,6 @@ trace(_, _, _, _, _) -> %% Support functions %% -start_slave() -> - Name = "asdkxlkmd" ++ integer_to_list(erlang:unique_integer([positive])), - {ok, Node} = test_server:start_node(Name,slave,[]), - ok = wait_node(Node, 15), - Node. - -stop_slave(Node) -> - test_server:stop_node(Node). - -wait_node(_,0) -> - no; -wait_node(Node, N) -> - case net_adm:ping(Node) of - pong -> - ok; - pang -> - receive - after 1000 -> - ok - end, - wait_node(Node, N - 1) - end. - myhandler(Message, {wait_for_go,Pid}) -> receive {go,Pid} -> diff --git a/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl b/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl index 68ece5936e98..3e7c39f8ab3e 100644 --- a/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl +++ b/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -23,10 +23,10 @@ %%% This module implements a priority queue as defined in %%% "Priority Queues and the STL" by Mark Nelson in Dr.Dobb's Journal, Jan 1996 %%% see http://web2.airmail.net/markn/articles/pq_stl/priority.htm for more -%%% information. (A heap implementation is planned aswell) +%%% information. (A heap implementation is planned as well) %%%---------------------------------------------------------------------- %%% The items of the queue is kept priority sorted, and because of that, -%%% a push() operation costs more than a pop() operation (wich only +%%% a push() operation costs more than a pop() operation (which only %%% needs to return the top item of the queue(read: list)). %%%---------------------------------------------------------------------- %%% The priority queue can be deceptively nice to use when creating for diff --git a/lib/runtime_tools/test/erts_alloc_config_SUITE.erl b/lib/runtime_tools/test/erts_alloc_config_SUITE.erl deleted file mode 100644 index ed24cce0bf99..000000000000 --- a/lib/runtime_tools/test/erts_alloc_config_SUITE.erl +++ /dev/null @@ -1,214 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2010-2021. 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(erts_alloc_config_SUITE). - -%-define(line_trace, 1). - --include_lib("common_test/include/ct.hrl"). - -%-compile(export_all). --export([all/0, suite/0, - init_per_suite/1, end_per_suite/1, - init_per_testcase/2, end_per_testcase/2]). - -%% Testcases --export([basic/1]). - -%% internal export --export([make_basic_config/1]). - -suite() -> - [{ct_hooks,[ts_install_cth]}, - {timetrap, {minutes, 2}}]. - -all() -> - [basic]. - -init_per_suite(Config) -> - case test_server:is_asan() of - true -> - %% No point testing own allocators under address sanitizer. - {skip, "Address sanitizer"}; - false -> - Config - end. - -end_per_suite(_Config) -> - ok. - -init_per_testcase(Case, Config) when is_list(Config) -> - [{testcase, Case}, - {erl_flags_env, save_env()} | Config]. - -end_per_testcase(_Case, Config) when is_list(Config) -> - restore_env(proplists:get_value(erl_flags_env, Config)), - ok. - -%%% -%%% The test cases ------------------------------------------------------------ -%%% - -basic(Config) when is_list(Config) -> - ErtsAllocConfig = privfile("generated", Config), - - SbctMod = " +MBsbct 1024 +MHsbct 4096", - - %% Make sure we have enabled allocators - ZFlgs = os:getenv("ERL_ZFLAGS", "") ++ " +Mea max +Mea config", - - os:putenv("ERL_ZFLAGS", ZFlgs ++ SbctMod), - - {ok, Node1} = start_node(Config), - ok = rpc:call(Node1, ?MODULE, make_basic_config, [ErtsAllocConfig]), - stop_node(Node1), - - display_file(ErtsAllocConfig), - - ManualConfig = privfile("manual", Config), - {ok, IOD} = file:open(ManualConfig, [write]), - io:format(IOD, "~s", ["+MBsbct 2048"]), - file:close(IOD), - display_file(ManualConfig), - - os:putenv("ERL_ZFLAGS", ZFlgs), - - {ok, Node2} = start_node(Config, - "-args_file " ++ ErtsAllocConfig - ++ " -args_file " ++ ManualConfig), - - {_, _, _, Cfg} = rpc:call(Node2, erlang, system_info, [allocator]), - - stop_node(Node2), - - {value,{binary_alloc, BCfg}} = lists:keysearch(binary_alloc, 1, Cfg), - {value,{sbct, 2097152}} = lists:keysearch(sbct, 1, BCfg), - {value,{eheap_alloc, HCfg}} = lists:keysearch(eheap_alloc, 1, Cfg), - {value,{sbct, 4194304}} = lists:keysearch(sbct, 1, HCfg), - - ok. - -make_basic_config(ErtsAllocConfig) -> - %% Save some different scenarios - Tester = self(), - SSBegun = make_ref(), - SSDone = make_ref(), - SSFun = fun (F) -> - receive - SSDone -> - ok = erts_alloc_config:save_scenario(), - Tester ! SSDone - after 500 -> - ok = erts_alloc_config:save_scenario(), - F(F) - end - end, - SS = spawn_link(fun () -> - ok = erts_alloc_config:save_scenario(), - Tester ! SSBegun, - SSFun(SSFun) - end), - receive SSBegun -> ok end, - Ref = make_ref(), - Tab = ets:new(?MODULE, [bag, public]), - Ps = lists:map( - fun (_) -> - spawn_link( - fun () -> - ets:insert(Tab, - {self(), - lists:seq(1, 1000)}), - receive after 1000 -> ok end, - Tester ! {Ref, self()} - end) - end, - lists:seq(1, 10000)), - lists:foreach(fun (P) -> receive {Ref, P} -> ok end end, Ps), - ets:delete(Tab), - SS ! SSDone, - receive SSDone -> ok end, - - ok = erts_alloc_config:make_config(ErtsAllocConfig). - - - -%% -%% Utils ---------------------------------------------------------------------- -%% - -display_file(FileName) -> - io:format("filename: ~s~n", [FileName]), - {ok, Bin} = file:read_file(FileName), - io:format("~s", [binary_to_list(Bin)]), - io:format("eof: ~s~n", [FileName]), - ok. - -mk_name(Config) when is_list(Config) -> - {A, B, C} = erlang:timestamp(), - list_to_atom(atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ "-" ++ integer_to_list(A) - ++ "-" ++ integer_to_list(B) - ++ "-" ++ integer_to_list(C)). - -start_node(Config) -> - start_node(Config, ""). - -start_node(Config, Args) -> - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(mk_name(Config), - slave, - [{args, "-pa " ++ Pa ++ " " ++ Args}]). - -stop_node(Node) -> - true = test_server:stop_node(Node). - -privfile(Name, Config) -> - filename:join([proplists:get_value(priv_dir, Config), - atom_to_list(proplists:get_value(testcase, Config)) ++ "." ++ Name]). - -save_env() -> - {erl_flags, - os:getenv("ERL_AFLAGS"), - os:getenv("ERL_FLAGS"), - os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), - os:getenv("ERL_ZFLAGS")}. - -restore_env(EVar, false) when is_list(EVar) -> - restore_env(EVar, ""); -restore_env(EVar, "") when is_list(EVar) -> - case os:getenv(EVar) of - false -> ok; - "" -> ok; - " " -> ok; - _ -> os:putenv(EVar, " ") - end; -restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> - case os:getenv(EVar) of - Value -> ok; - _ -> os:putenv(EVar, Value) - end. - -restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> - restore_env("ERL_AFLAGS", AFlgs), - restore_env("ERL_FLAGS", Flgs), - restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), - restore_env("ERL_ZFLAGS", ZFlgs), - ok. diff --git a/lib/tools/test/instrument_SUITE.erl b/lib/runtime_tools/test/instrument_SUITE.erl similarity index 92% rename from lib/tools/test/instrument_SUITE.erl rename to lib/runtime_tools/test/instrument_SUITE.erl index 755739c94e00..8577794e5fb6 100644 --- a/lib/tools/test/instrument_SUITE.erl +++ b/lib/runtime_tools/test/instrument_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -73,17 +73,17 @@ allocations_test(Args, Plain, PerAlloc) -> end). allocations_enabled(Config) when is_list(Config) -> - allocations_test("+Meamax +Muatags true", + allocations_test(["+Meamax", "+Muatags", "true"], fun verify_allocations_enabled/1, fun verify_allocations_enabled/2). allocations_disabled(Config) when is_list(Config) -> - allocations_test("+Meamax +Muatags false", + allocations_test(["+Meamax", "+Muatags", "false"], fun verify_allocations_disabled/1, fun verify_allocations_disabled/2). allocations_ramv(Config) when is_list(Config) -> - allocations_test("+Meamax +Muatags true +Muramv true", + allocations_test(["+Meamax", "+Muatags","true", "+Muramv","true"], fun verify_allocations_enabled/1, fun verify_allocations_enabled/2). @@ -165,12 +165,12 @@ carriers_test(Args, Plain, PerAlloc) -> end). carriers_enabled(Config) when is_list(Config) -> - carriers_test("+Meamax", + carriers_test(["+Meamax"], fun verify_carriers_enabled/1, fun verify_carriers_enabled/2). carriers_disabled(Config) when is_list(Config) -> - carriers_test("+Meamin", + carriers_test(["+Meamin"], fun verify_carriers_disabled/1, fun verify_carriers_disabled/2). @@ -300,8 +300,8 @@ run_test(Args0, Test) -> %% %% We also set the abandon carrier threshold to 70% to provoke more %% activity in the carrier pool. - Args = Args0 ++ " +MBsbct 1 +Muacul 70", - Node = start_slave(Args), + Args = Args0 ++ ["+MBsbct", "1", "+Muacul", "70"], + {ok, Peer, Node} = ?CT_PEER(Args), ok = rpc:call(Node, ?MODULE, generate_test_blocks, []), ok = Test(Node), @@ -309,26 +309,7 @@ run_test(Args0, Test) -> ok = rpc:call(Node, ?MODULE, churn_memory, []), ok = Test(Node), - true = test_server:stop_node(Node). - -start_slave(Args) -> - MicroSecs = erlang:monotonic_time(), - Name = "instr" ++ integer_to_list(MicroSecs), - Pa = filename:dirname(code:which(?MODULE)), - - %% We pass arguments through ZFLAGS as the nightly tests rotate - %% +Meamax/+Meamin which breaks the _enabled and _disabled tests unless - %% overridden. - ZFlags = os:getenv("ERL_ZFLAGS", ""), - {ok, Node} = try - os:putenv("ERL_ZFLAGS", ZFlags ++ [" " | Args]), - test_server:start_node(list_to_atom(Name), - slave, - [{args, "-pa " ++ Pa}]) - after - os:putenv("ERL_ZFLAGS", ZFlags) - end, - Node. + peer:stop(Peer). generate_test_blocks() -> Runner = self(), diff --git a/lib/runtime_tools/test/system_information_SUITE.erl b/lib/runtime_tools/test/system_information_SUITE.erl index a5a025a1cf44..6870d95b4029 100644 --- a/lib/runtime_tools/test/system_information_SUITE.erl +++ b/lib/runtime_tools/test/system_information_SUITE.erl @@ -182,6 +182,19 @@ end_per_group(_GroupName, _Config) -> %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- +init_per_testcase(sanity_check, Config) -> + %% We check if the test results were released using a version + %% of Erlang/OTP that was a tagged version or not. On a non-tagged + %% version this testcase most likely will fail. + case file:read_file( + filename:join( + proplists:get_value(data_dir,Config), "otp_version_tickets")) of + {ok,<<"DEVELOPMENT",_/binary>>} -> + {skip, "This is a development version, test might fail " + "because of incorrect version numbers"}; + {ok,_S} -> + Config + end; init_per_testcase(_TestCase, Config) -> Config. @@ -280,7 +293,6 @@ validate_loaded_report() -> ok = system_information:application(kernel,[full]), ok = system_information:module(gen_server), ok = system_information:module(gen_server,[full]), - ok = system_information:modules(native), ok. diff --git a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat index 94120c0dc7fd..3c8f582086a8 100644 --- a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat +++ b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat @@ -9729,7 +9729,6 @@ [{"BINDIR", "/ldisk/daily_build/r16b02_opu_c_Muacul100.2013-07-10_20/otp/erts-5.10.3/bin"}, {"DIALYZER_EMULATOR",false}, - {"CERL_DETACHED_PROG",false}, {"EMU","beam"}, {"ERL_CONSOLE_MODE",false}, {"ERL_CRASH_DUMP",false}, diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk index 3e7545b8c545..6a374f92d477 100644 --- a/lib/runtime_tools/vsn.mk +++ b/lib/runtime_tools/vsn.mk @@ -1 +1 @@ -RUNTIME_TOOLS_VSN = 1.18 +RUNTIME_TOOLS_VSN = 2.0 diff --git a/lib/sasl/Makefile b/lib/sasl/Makefile index 4f32f0ec0cc4..4b04c1aee4ed 100644 --- a/lib/sasl/Makefile +++ b/lib/sasl/Makefile @@ -37,5 +37,6 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk DIA_PLT_APPS=tools +TEST_NEEDS_RELEASE=true include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 9ed8e1299edd..f30683db2a47 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -4,7 +4,7 @@

    - 19972021 + 19972023 Ericsson AB. All Rights Reserved. @@ -393,7 +393,7 @@ restart_new_emulator

    As stated earlier, instruction restart_new_emulator causes the emulator to be restarted with new versions of - ERTS>, Kernel, STDLIB, and SASL. + ERTS, Kernel, STDLIB, and SASL. However, all other applications do at startup run their old versions in this new emulator. This is usually no problem, but every now and then incompatible changes occur to the diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index f9162b67e757..2ba4c74362a6 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -31,6 +31,57 @@

    This document describes the changes made to the SASL application.

    +
    SASL 4.2.1 + +
    Fixed Bugs and Malfunctions + + +

    Improved error message from + systools:make_script, when .app parameters contain + duplicates. The parameters that will be checked are + modules, applications and registered.

    +

    + Own Id: OTP-18300 Aux Id: PR-6389

    +
    +
    +
    + +
    + +
    SASL 4.2 + +
    Fixed Bugs and Malfunctions + + +

    + Fix systools:make* to recursively search for source code + when doing a src_tests.

    +

    + Own Id: OTP-17752 Aux Id: PR-5302

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + An Erlang installation directory is now relocatable on + the file system given that the paths in the + installation's RELEASES file are paths that are + relative to the installations root directory. The + `release_handler:create_RELEASES/4 function can + generate a RELEASES file with relative paths if + its RootDir parameter is set to the empty string.

    +

    + Own Id: OTP-17304

    +
    +
    +
    + +
    +
    SASL 4.1.2
    Fixed Bugs and Malfunctions diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 55ec4cdb0fff..f5eb0ccbd17c 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962022 Ericsson AB. All Rights Reserved. @@ -202,6 +202,7 @@ + create_RELEASES(RelDir, RelFile, AppDirs) -> ok | {error, Reason} create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason} Creates an initial RELEASES file. @@ -215,12 +216,19 @@

    Creates an initial RELEASES file to be used by the release handler. This file must exist to install new releases.

    -

    Root is the root of the installation ($ROOT) as - described earlier. RelDir is the directory where - the RELEASES file is to be created (normally - $ROOT/releases). RelFile is the name - of the .rel file that describes the initial release, - including the extension .rel.

    +

    Root is the root of the installation ($ROOT) + as described earlier. RelDir is the directory where the + RELEASES file is to be created (normally + $ROOT/releases). RelFile is the name of the + .rel file that describes the initial release, including + the extension .rel. If Root is not given, + the RELEASES file will be location independent (i.e, it + will not contain absolute paths unless there are absolute + paths in AppDirs). A RELEASES file should be + made location independent if the installation's $ROOT + is unknown. The release_handler module will interpret + relative paths in a running system's RELEASES file as + being relative to $ROOT.

    AppDirs can be used to specify from where the modules for the specified applications are to be loaded. App is the name of an application, Vsn is the version, and diff --git a/lib/sasl/doc/src/sasl_app.xml b/lib/sasl/doc/src/sasl_app.xml index 039264ed1eee..7c661126269a 100644 --- a/lib/sasl/doc/src/sasl_app.xml +++ b/lib/sasl/doc/src/sasl_app.xml @@ -4,7 +4,7 @@

    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -54,7 +54,7 @@

    Specifies the program to be used when restarting the system during release installation. Default is - $OTP_ROOT/bin/start.

    + $OTPROOT/bin/start.

    @@ -84,7 +84,7 @@ The release handler writes all its files to this directory. If this parameter is not set, the OS environment parameter RELDIR is used. By default, this is - $OTP_ROOT/releases.

    + $OTPROOT/releases.

    diff --git a/lib/sasl/examples/src/Makefile b/lib/sasl/examples/src/Makefile index e8b903f252b8..6b6f872221b8 100644 --- a/lib/sasl/examples/src/Makefile +++ b/lib/sasl/examples/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2016. All Rights Reserved. +# Copyright Ericsson AB 2010-2022. 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. @@ -51,7 +51,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -fr $(TARGET_FILES) *~ *.beam diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl index b3d67483067d..8a68dd379dcb 100644 --- a/lib/sasl/examples/src/target_system.erl +++ b/lib/sasl/examples/src/target_system.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2016. All Rights Reserved. +%% Copyright Ericsson AB 2011-2022. 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. @@ -35,9 +35,9 @@ create(RelFileName,SystoolsOpts) -> Dir = filename:dirname(RelFileName), PlainRelFileName = filename:join(Dir,"plain"), PlainRelFile = PlainRelFileName ++ ".rel", - io:fwrite("Reading file: ~tp ...~n", [RelFile]), + io:fwrite("Reading file: ~ts ...~n", [RelFile]), {ok, [RelSpec]} = file:consult(RelFile), - io:fwrite("Creating file: ~tp from ~tp ...~n", + io:fwrite("Creating file: ~ts from ~ts ...~n", [PlainRelFile, RelFile]), {release, {RelName, RelVsn}, @@ -67,32 +67,32 @@ create(RelFileName,SystoolsOpts) -> make_script(RelFileName,SystoolsOpts), TarFileName = RelFileName ++ ".tar.gz", - io:fwrite("Creating tar file ~tp ...~n", [TarFileName]), + io:fwrite("Creating tar file ~ts ...~n", [TarFileName]), make_tar(RelFileName,SystoolsOpts), TmpDir = filename:join(Dir,"tmp"), io:fwrite("Creating directory ~tp ...~n",[TmpDir]), file:make_dir(TmpDir), - io:fwrite("Extracting ~tp into directory ~tp ...~n", [TarFileName,TmpDir]), + io:fwrite("Extracting ~ts into directory ~ts ...~n", [TarFileName,TmpDir]), extract_tar(TarFileName, TmpDir), TmpBinDir = filename:join([TmpDir, "bin"]), ErtsBinDir = filename:join([TmpDir, "erts-" ++ ErtsVsn, "bin"]), - io:fwrite("Deleting \"erl\" and \"start\" in directory ~tp ...~n", + io:fwrite("Deleting \"erl\" and \"start\" in directory ~ts ...~n", [ErtsBinDir]), file:delete(filename:join([ErtsBinDir, "erl"])), file:delete(filename:join([ErtsBinDir, "start"])), - io:fwrite("Creating temporary directory ~tp ...~n", [TmpBinDir]), + io:fwrite("Creating temporary directory ~ts ...~n", [TmpBinDir]), file:make_dir(TmpBinDir), - io:fwrite("Copying file \"~ts.boot\" to ~tp ...~n", + io:fwrite("Copying file \"~ts.boot\" to ~ts ...~n", [PlainRelFileName, filename:join([TmpBinDir, "start.boot"])]), copy_file(PlainRelFileName++".boot",filename:join([TmpBinDir, "start.boot"])), io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" - "~tp to ~tp ...~n", + "~ts to ~ts ...~n", [ErtsBinDir, TmpBinDir]), copy_file(filename:join([ErtsBinDir, "epmd"]), filename:join([TmpBinDir, "epmd"]), [preserve]), @@ -104,15 +104,15 @@ create(RelFileName,SystoolsOpts) -> %% This is needed if 'start' script created from 'start.src' shall %% be used as it points out this directory as log dir for 'run_erl' TmpLogDir = filename:join([TmpDir, "log"]), - io:fwrite("Creating temporary directory ~tp ...~n", [TmpLogDir]), + io:fwrite("Creating temporary directory ~ts ...~n", [TmpLogDir]), ok = file:make_dir(TmpLogDir), StartErlDataFile = filename:join([TmpDir, "releases", "start_erl.data"]), - io:fwrite("Creating ~tp ...~n", [StartErlDataFile]), + io:fwrite("Creating ~ts ...~n", [StartErlDataFile]), StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), write_file(StartErlDataFile, StartErlData), - io:fwrite("Recreating tar file ~tp from contents in directory ~tp ...~n", + io:fwrite("Recreating tar file ~ts from contents in directory ~ts ...~n", [TarFileName,TmpDir]), {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), %% {ok, Cwd} = file:get_cwd(), @@ -125,14 +125,14 @@ create(RelFileName,SystoolsOpts) -> erl_tar:add(Tar, filename:join(TmpDir,"log"), "log", []), erl_tar:close(Tar), %% file:set_cwd(Cwd), - io:fwrite("Removing directory ~tp ...~n",[TmpDir]), + io:fwrite("Removing directory ~ts ...~n",[TmpDir]), remove_dir_tree(TmpDir), ok. install(RelFileName, RootDir) -> TarFile = RelFileName ++ ".tar.gz", - io:fwrite("Extracting ~tp ...~n", [TarFile]), + io:fwrite("Extracting ~ts ...~n", [TarFile]), extract_tar(TarFile, RootDir), StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), {ok, StartErlData} = read_txt_file(StartErlDataFile), diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile index 16a42caf1101..490e03595d59 100644 --- a/lib/sasl/src/Makefile +++ b/lib/sasl/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -69,7 +69,7 @@ ERL_COMPILE_FLAGS += -I../../stdlib/include -Werror # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 48feac1a2136..7635b1ef78dc 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -24,7 +24,7 @@ %% External exports -export([start_link/0, - create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, + create_RELEASES/1, create_RELEASES/2, create_RELEASES/3, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, install_release/1, install_release/2, new_emulator_upgrade/2, @@ -43,7 +43,13 @@ -export([do_write_release/3, do_copy_file/2, do_copy_files/2, do_copy_files/1, do_rename_files/1, do_remove_files/1, remove_file/1, do_write_file/2, do_write_file/3, - do_ensure_RELEASES/1]). + do_ensure_RELEASES/1, + consult/2, + root_dir_relative_read_file_info/1, + root_dir_relative_read_file/1, + root_dir_relative_rename_file/2, + root_dir_relative_make_dir/1, + root_dir_relative_ensure_dir/1]). -record(state, {unpurged = [], root, @@ -134,9 +140,9 @@ %% %% It is configurable where the start file is located, and what it %% is called. -%% The paramater is {sasl, start_prg} = File +%% The parameter is {sasl, start_prg} = File %% It is also configurable where the releases directory is located. -%% Default is $ROOT/releases. $RELDIR overrids, and +%% Default is $ROOT/releases. $RELDIR overrides, and %% {sasl, releases_dir} overrides both. %%----------------------------------------------------------------- start_link() -> @@ -162,7 +168,7 @@ unpack_release(ReleaseName) -> %% Purpose: Checks the relup script for the specified version. %% The release must be unpacked. %% Options = [purge] - all old code that can be soft purged -%% will be purged if all checks succeeds. This can be usefull +%% will be purged if all checks succeeds. This can be useful %% in order to reduce time needed in the following call to %% install_release. %% Returns: {ok, FromVsn, Descr} | {error, Reason} @@ -298,7 +304,7 @@ remove_release(Vsn) -> %% .rel. %% The release dir will be created. The necessary files can %% be installed by calling install_file/2. -%% The release_handler remebers where all libs are located. +%% The release_handler remembers where all libs are located. %% If remove_release is called later, %% those libs are removed as well (if no other releases uses %% them). @@ -378,6 +384,8 @@ create_RELEASES([Root, RelFile | LibDirs]) -> create_RELEASES(Root, RelFile) -> create_RELEASES(Root, filename:join(Root, "releases"), RelFile, []). +create_RELEASES(RelDir, RelFile, LibDirs) -> + create_RELEASES("", RelDir, RelFile, LibDirs). create_RELEASES(Root, RelDir, RelFile, LibDirs) -> case catch check_rel(Root, RelFile, LibDirs, false) of {error, Reason } -> @@ -397,7 +405,8 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %% located under Dir/ebin %% Purpose: Upgrade to the version in Dir according to an appup file %%----------------------------------------------------------------- -upgrade_app(App, NewDir) -> +upgrade_app(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), try upgrade_script(App, NewDir) of {ok, NewVsn, Script} -> eval_appup_script(App, NewVsn, NewDir, Script) @@ -435,7 +444,8 @@ downgrade_app(App, OldVsn, OldDir) -> {error, Reason} end. -upgrade_script(App, NewDir) -> +upgrade_script(App, NewDir1) -> + NewDir = root_dir_relative_path(NewDir1), OldVsn = ensure_running(App), OldDir = code:lib_dir(App), {NewVsn, Script} = find_script(App, NewDir, OldVsn, up), @@ -489,7 +499,8 @@ ensure_running(App) -> end. find_script(App, Dir, OldVsn, UpOrDown) -> - Appup = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup1 = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), + Appup = root_dir_relative_path(Appup1), case file:consult(Appup) of {ok, [{NewVsn, UpFromScripts, DownToScripts}]} -> Scripts = case UpOrDown of @@ -522,7 +533,7 @@ read_app(App, Vsn, Dir) -> read_appspec(App, Dir) -> AppS = atom_to_list(App), - Path = [filename:join(Dir, "ebin")], + Path = [root_dir_relative_path(filename:join(Dir, "ebin"))], case file:path_consult(Path, AppS++".app") of {ok, AppSpecL, _File} -> AppSpecL; @@ -833,7 +844,9 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> Rel = ReleaseName ++ ".rel", _ = extract_rel_file(filename:join("releases", Rel), Tar, Root), RelFile = filename:join(RelDir, Rel), - Release = check_rel(Root, RelFile, false), + %% Send an empty string as Root as the library locations should + %% appear as paths relative to the root + Release = check_rel("", RelFile, false), #release{vsn = Vsn} = Release, case lists:keysearch(Vsn, #release.vsn, Releases) of {value, _} -> throw({error, {existing_release, Vsn}}); @@ -850,8 +863,8 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> copy_file(RelFile, Dir, false), %% Clean release - _ = file:delete(Tar), - _ = file:delete(RelFile), + _ = root_dir_relative_file_delete(Tar), + _ = root_dir_relative_file_delete(RelFile), {ok, NewReleases, Vsn}. @@ -883,7 +896,19 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs, check_path(Path, Masters), Path; _ -> - filename:join([Root, "lib", LibName]) + %% If Root is an empty string, + %% we assume that the path is + %% relative to code:root_dir() + %% and save a relative + %% path. This is done to make it + %% easy to create a relocatable + %% RELEASES file. + case string:length(Root) of + 0 -> + filename:join("lib", LibName); + _ -> + filename:join([Root, "lib", LibName]) + end end, {Lib, LibVsn, LibDir} end, @@ -894,7 +919,7 @@ check_rel_data(RelData, _Root, _LibDirs, _Masters) -> throw({error, {bad_rel_data, RelData}}). check_path(Path) -> - check_path_response(Path, file:read_file_info(Path)). + check_path_response(Path, root_dir_relative_read_file_info(Path)). check_path(Path, false) -> check_path(Path); check_path(Path, Masters) -> check_path_master(Masters, Path). @@ -904,7 +929,7 @@ check_path(Path, Masters) -> check_path_master(Masters, Path). %% at one node it should not exist at any other node either. %%----------------------------------------------------------------- check_path_master([Master|Ms], Path) -> - case rpc:call(Master, file, read_file_info, [Path]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [Path]) of {badrpc, _} -> consult_master(Ms, Path); Res -> check_path_response(Path, Res) end; @@ -1168,7 +1193,7 @@ new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn, new_emulator_rm_tmp_release(_,_,_,_,Releases,_) -> Releases. -%% Rename the tempoarary service (for erts ugprade) to the real ToVsn +%% Rename the temporary service (for erts ugprade) to the real ToVsn rename_tmp_service(EVsn,TmpVsn,NewVsn) -> FromName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn, ToName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ NewVsn, @@ -1573,14 +1598,14 @@ memlib(_Lib, []) -> false. %% recursively remove file or directory remove_file(File) -> - case file:read_link_info(File) of + case root_dir_relative_read_link_info(File) of {ok, Info} when Info#file_info.type==directory -> - case file:list_dir(File) of + case root_dir_relative_list_dir(File) of {ok, Files} -> lists:foreach(fun(File2) -> remove_file(filename:join(File,File2)) end, Files), - case file:del_dir(File) of + case root_dir_relative_dir_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1588,7 +1613,7 @@ remove_file(File) -> throw({error, Reason}) end; {ok, _Info} -> - case file:delete(File) of + case root_dir_relative_file_delete(File) of ok -> ok; {error, Reason} -> throw({error, Reason}) end; @@ -1599,7 +1624,8 @@ remove_file(File) -> do_write_file(File, Str) -> do_write_file(File, Str, []). -do_write_file(File, Str, FileOpts) -> +do_write_file(File1, Str, FileOpts) -> + File = root_dir_relative_path(File1), case file:open(File, [write | FileOpts]) of {ok, Fd} -> io:put_chars(Fd, Str), @@ -1822,13 +1848,13 @@ check_file_masters(_FileName, _Type, []) -> %% Type == regular | directory do_check_file(FileName, Type) -> - case file:read_file_info(FileName) of + case root_dir_relative_read_file_info(FileName) of {ok, Info} when Info#file_info.type==Type -> ok; {error, _Reason} -> throw({error, {no_such_file, FileName}}) end. do_check_file(Master, FileName, Type) -> - case rpc:call(Master, file, read_file_info, [FileName]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file_info, [FileName]) of {ok, Info} when Info#file_info.type==Type -> ok; _ -> throw({error, {no_such_file, {Master, FileName}}}) end. @@ -1871,7 +1897,8 @@ write_releases_1(Dir, NewReleases, Masters) -> write_releases_m(Dir, NewReleases, Masters). do_write_release(Dir, RELEASES, NewReleases) -> - case file:open(filename:join(Dir, RELEASES), [write,{encoding,utf8}]) of + ReleasesFile = root_dir_relative_path(filename:join(Dir, RELEASES)), + case file:open(ReleasesFile, [write,{encoding,utf8}]) of {ok, Fd} -> ok = io:format(Fd, "%% ~s~n~tp.~n", [epp:encoding_to_string(utf8),NewReleases]), @@ -1908,7 +1935,8 @@ write_releases_m(Dir, NewReleases, Masters) -> remove_files(all, [Backup, Change], Masters), ok; {error, {Master, R}} -> - takewhile(Master, Masters, file, rename, + takewhile(Master, Masters, ?MODULE, + root_dir_relative_rename_file, [Backup, RelFile]), remove_files(all, [Backup, Change], Masters), throw({error, {Master, R, move_releases}}) @@ -1959,9 +1987,9 @@ do_copy_file(File, Dir) -> do_copy_file1(File, File2). do_copy_file1(File, File2) -> - case file:read_file(File) of + case root_dir_relative_read_file(File) of {ok, Bin} -> - case file:write_file(File2, Bin) of + case root_dir_relative_write_file(File2, Bin) of ok -> ok; {error, Reason} -> {error, {Reason, File2}} @@ -1995,7 +2023,9 @@ do_copy_files([]) -> %%----------------------------------------------------------------- %% Rename each Src file to Dest file in the list of files. %%----------------------------------------------------------------- -do_rename_files([{Src, Dest}|Files]) -> +do_rename_files([{Src1, Dest1}|Files]) -> + Src = root_dir_relative_path(Src1), + Dest = root_dir_relative_path(Dest1), case file:rename(Src, Dest) of ok -> do_rename_files(Files); Error -> Error @@ -2007,7 +2037,7 @@ do_rename_files([]) -> %% Remove a list of files. Ignore failure. %%----------------------------------------------------------------- do_remove_files([File|Files]) -> - _ = file:delete(File), + _ = root_dir_relative_file_delete(File), do_remove_files(Files); do_remove_files([]) -> ok. @@ -2018,7 +2048,7 @@ do_remove_files([]) -> %% If not create an empty RELEASES file. %%----------------------------------------------------------------- do_ensure_RELEASES(RelFile) -> - case file:read_file_info(RelFile) of + case root_dir_relative_read_file_info(RelFile) of {ok, _} -> ok; _ -> do_write_file(RelFile, "[]. ") end. @@ -2026,11 +2056,16 @@ do_ensure_RELEASES(RelFile) -> %%----------------------------------------------------------------- %% Make a directory, ignore failures (captured later). %%----------------------------------------------------------------- -make_dir(Dir, false) -> +make_dir(Dir1, false) -> + Dir = root_dir_relative_path(Dir1), _ = file:make_dir(Dir), ok; make_dir(Dir, Masters) -> - lists:foreach(fun(Master) -> rpc:call(Master, file, make_dir, [Dir]) end, + lists:foreach(fun(Master) -> rpc:call(Master, + ?MODULE, + root_dir_relative_make_dir, + [Dir]) + end, Masters). %%----------------------------------------------------------------- @@ -2068,7 +2103,7 @@ takewhile(Master, Masters, M, F, A) -> end, Masters), ok. -consult(File, false) -> file:consult(File); +consult(File, false) -> file:consult(root_dir_relative_path(File)); consult(File, Masters) -> consult_master(Masters, File). %%----------------------------------------------------------------- @@ -2077,7 +2112,7 @@ consult(File, Masters) -> consult_master(Masters, File). %% not exist at any other node either. %%----------------------------------------------------------------- consult_master([Master|Ms], File) -> - case rpc:call(Master, file, consult, [File]) of + case rpc:call(Master, ?MODULE, consult, [File, false]) of {badrpc, _} -> consult_master(Ms, File); Res -> Res end; @@ -2085,12 +2120,12 @@ consult_master([], _File) -> {error, no_master}. read_file(File, false) -> - file:read_file(File); + root_dir_relative_read_file(File); read_file(File, Masters) -> read_master(Masters, File). write_file(File, Data, false) -> - case file:write_file(File, Data) of + case root_dir_relative_write_file(File, Data) of ok -> ok; Error -> throw(Error) end; @@ -2101,12 +2136,12 @@ write_file(File, Data, Masters) -> end. ensure_dir(File, false) -> - case filelib:ensure_dir(File) of + case root_dir_relative_ensure_dir(File) of ok -> ok; Error -> throw(Error) end; ensure_dir(File, Masters) -> - case at_all_masters(Masters,filelib,ensure_dir,[File]) of + case at_all_masters(Masters,?MODULE,root_dir_relative_ensure_dir,[File]) of ok -> ok; Error -> throw(Error) end. @@ -2130,7 +2165,7 @@ remove_files(Master, Files, Masters) -> %% not exist at any other node either. %%----------------------------------------------------------------- read_master([Master|Ms], File) -> - case rpc:call(Master, file, read_file, [File]) of + case rpc:call(Master, ?MODULE, root_dir_relative_read_file, [File]) of {badrpc, _} -> read_master(Ms, File); Res -> Res end; @@ -2275,7 +2310,7 @@ safe_write_file_m(File, Data, FileOpts, Masters) -> %% %% A different situation is when the same application version is used %% in old and new release, but the path has changed. This is not -%% handled here - instead it must be explicitely indicated by the +%% handled here - instead it must be explicitly indicated by the %% 'update_paths' option to release_handler:install_release/2 if the %% code path shall be updated then. %% ----------------------------------------------------------------- @@ -2299,3 +2334,47 @@ get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail], get_releases_with_status(Tail, Status, [Head | Acc]); get_releases_with_status([_ | Tail], Status, Acc) -> get_releases_with_status(Tail, Status, Acc). + +root_dir_relative_read_link_info(File) -> + file:read_link_info(root_dir_relative_path(File)). + +root_dir_relative_list_dir(File) -> + file:list_dir(root_dir_relative_path(File)). + +root_dir_relative_file_delete(File) -> + file:delete(root_dir_relative_path(File)). + +root_dir_relative_dir_delete(File) -> + file:del_dir(root_dir_relative_path(File)). + +root_dir_relative_path(Pathname) -> + case filename:pathtype(Pathname) of + relative -> + filename:join(code:root_dir(), Pathname); + _ -> + Pathname + end. + +root_dir_relative_write_file(File, Bin) -> + file:write_file(root_dir_relative_path(File), Bin). + +%% The root_dir_relative* functions below are exported so that they +%% can be called on other nodes with rpc + +root_dir_relative_read_file_info(Path) -> + file:read_file_info(root_dir_relative_path(Path)). + +root_dir_relative_read_file(File) -> + file:read_file(root_dir_relative_path(File)). + +root_dir_relative_rename_file(Source1, Destination1) -> + Source = root_dir_relative_path(Source1), + Destination = root_dir_relative_path(Destination1), + file:rename(Source, Destination). + +root_dir_relative_make_dir(Dir) -> + file:make_dir(root_dir_relative_path(Dir)). + +root_dir_relative_ensure_dir(Dir) -> + filelib:ensure_dir(root_dir_relative_path(Dir)). + diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index ede7df186b9c..3a5883dfb9d3 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -248,7 +248,7 @@ syntax_check_script([]) -> %% {load_object_code, [Mod1, Mod2]}, %% % delete old version %% {remove, {Mod1, brutal_purge}}, {remove, {Mod2, brutal_purge}}, -%% % now, some procs migth be running prev current (now old) version +%% % now, some procs might be running prev current (now old) version %% % kill them, and load new version %% {load, {Mod1, brutal_purge}}, {load, {Mod2, brutal_purge}} %% % now, there is one version of the code (new, current) @@ -279,7 +279,7 @@ syntax_check_script([]) -> %% If a process doesn't repsond - never mind. It will be killed %% later on (if a purge is performed). %% Hmm, we must do something smart here... we should probably kill it, -%% but we cant, because its supervisor will restart it directly! Maybe +%% but we can't, because its supervisor will restart it directly! Maybe %% we should keep a list of those, call supervisor:terminate_child() %% when all others are suspended, and call sup:restart_child() when the %% others are resumed. @@ -313,7 +313,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> {NewBins, NewVsns} = lists:foldl(fun(Mod, {Bins, Vsns}) -> File = lists:concat([Mod, Ext]), - FName = filename:join([LibDir, "ebin", File]), + FName = root_dir_relative_path(filename:join([LibDir, "ebin", File])), case erl_prim_loader:get_file(FName) of {ok, Bin, FName2} -> NVsns = add_vsns(Mod, Bin, Vsns), @@ -340,14 +340,15 @@ eval(point_of_no_return, EvalState) -> EvalState#eval_state.libdirs end, lists:foreach(fun({Lib, _LibVsn, LibDir}) -> - Ebin = filename:join(LibDir,"ebin"), + Ebin = root_dir_relative_path(filename:join(LibDir,"ebin")), code:replace_path(Lib, Ebin) end, Libs), EvalState; eval({load, {Mod, _PrePurgeMethod, PostPurgeMethod}}, EvalState) -> Bins = EvalState#eval_state.bins, - {value, {_Mod, Bin, File}} = lists:keysearch(Mod, 1, Bins), + {value, {_Mod, Bin, File1}} = lists:keysearch(Mod, 1, Bins), + File = root_dir_relative_path(File1), % load_binary kills all procs running old code % if soft_purge, we know that there are no such procs now {module,_} = code:load_binary(Mod, File, Bin), @@ -804,3 +805,12 @@ get_vsn(Bin) -> Vsn end end. + +root_dir_relative_path(Pathname) -> + case filename:pathtype(Pathname) of + relative -> + filename:join(code:root_dir(), Pathname); + _ -> + Pathname + end. + diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src index 293af504dfab..26e57119a75c 100644 --- a/lib/sasl/src/sasl.app.src +++ b/lib/sasl/src/sasl.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -42,6 +42,6 @@ {applications, [kernel, stdlib]}, {env, []}, {mod, {sasl, []}}, - {runtime_dependencies, ["tools-2.6.14","stdlib-3.4","kernel-5.3", + {runtime_dependencies, ["tools-2.6.14","stdlib-4.0","kernel-6.0", "erts-10.2"]}]}. diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index e2fc3e5b7fd0..644de8043839 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -19,34 +19,24 @@ %% %% We allow upgrade from, and downgrade to all previous %% versions from the following OTP releases: -%% - OTP 22 -%% - OTP 23 %% - OTP 24 +%% - OTP 25 +%% - OTP 26 %% %% We also allow upgrade from, and downgrade to all %% versions that have branched off from the above %% stated previous versions. %% {"%VSN%", - [{<<"^3\\.4$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.0$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.1$">>,[restart_new_emulator]}, + [{<<"^4\\.1$">>,[restart_new_emulator]}, {<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}], - [{<<"^3\\.4$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.0$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^4\\.1$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.2$">>,[restart_new_emulator]}, + {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], + [{<<"^4\\.1$">>,[restart_new_emulator]}, {<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}. + {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.2$">>,[restart_new_emulator]}, + {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. diff --git a/lib/sasl/src/systools.erl b/lib/sasl/src/systools.erl index a97db3a20e24..889cf924a374 100644 --- a/lib/sasl/src/systools.erl +++ b/lib/sasl/src/systools.erl @@ -43,7 +43,7 @@ %%----------------------------------------------------------------- %% Options is a list of {path, Path} | silent | local where path sets -%% the search path, silent supresses error message printing on console, +%% the search path, silent suppresses error message printing on console, %% local generates a script with references to the directories there %% the applications are found. %%----------------------------------------------------------------- @@ -57,7 +57,7 @@ make_script(RelName, Opt) -> %%----------------------------------------------------------------- %% Options is a list of {path, Path} | silent | %% {dirs, [src,include,examples,..]} | {erts, ErtsDir} where path -%% sets the search path, silent supresses error message printing on console, +%% sets the search path, silent suppresses error message printing on console, %% dirs includes the specified directories (per application) in the %% release package and erts specifies that the erts-Vsn/bin directory %% should be included in the release package and there it can be found. @@ -116,8 +116,8 @@ script2boot(File, Output0, _Opt) -> %%----------------------------------------------------------------- %% Options is a list of {path, Path} | silent | noexec where path sets -%% search path, silent supresses error message printing on console, -%% noexec supresses writing the output "relup" file +%% search path, silent suppresses error message printing on console, +%% noexec suppresses writing the output "relup" file %%----------------------------------------------------------------- make_relup(ReleaseName, UpNameList, DownNameList) -> systools_relup:mk_relup(ReleaseName, UpNameList, DownNameList, []). diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index ca4fb4300aab..671eaf774558 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -45,18 +45,13 @@ -compile({inline,[{badarg,2}]}). --ifdef(USE_ESOCK). -define(ESOCK_MODS, [prim_net,prim_socket,socket_registry]). --else. --define(ESOCK_MODS, []). --endif. - %%----------------------------------------------------------------- %% Create a boot script from a release file. %% Options is a list of {path, Path} | silent | local %% | warnings_as_errors -%% where path sets the search path, silent supresses error message +%% where path sets the search path, silent suppresses error message %% printing on console, local generates a script with references %% to the directories there the applications are found, %% and warnings_as_errors treats warnings as errors. @@ -195,7 +190,7 @@ do_make_hybrid_boot(TmpVsn, OldBoot, NewBoot, Args) -> {script,{_RelName1,_RelVsn1},OldScript} = binary_to_term(OldBoot), {script,{NewRelName,_RelVsn2},NewScript} = binary_to_term(NewBoot), - %% Everyting upto kernel_load_completed must come from the new script + %% Everything up to kernel_load_completed must come from the new script Fun1 = fun({progress,kernel_load_completed}) -> false; (_) -> true end, @@ -345,7 +340,7 @@ add_apply_upgrade(Script,Args) -> %% Create a release package from a release file. %% Options is a list of {path, Path} | silent | %% {dirs, [src,include,examples,..]} | {erts, ErtsDir} where path -%% sets the search path, silent supresses error message printing, +%% sets the search path, silent suppresses error message printing, %% dirs includes the specified directories (per application) in the %% release package and erts specifies that the erts-Vsn/bin directory %% should be included in the release package and there it can be found. @@ -674,7 +669,7 @@ parse_application({application, Name, Dict}, File, Vsn, Incls) parse_application(Other, _, _, _) -> {error, {badly_formatted_application, Other}}. -%% Test if all included applications specifed in the .rel file +%% Test if all included applications specified in the .rel file %% exists in the {included_applications,Incs} specified in the %% .app file. override_include(Name, Incs, Incls) -> @@ -701,7 +696,15 @@ specified([], _) -> []. get_items([H|T], Dict) -> - Item = check_item(keysearch(H, 1, Dict),H), + Item = case check_item(keysearch(H, 1, Dict),H) of + [Atom|_]=Atoms when is_atom(Atom), is_list(Atoms) -> + %% Check for duplicate entries in lists + case Atoms =/= lists:uniq(Atoms) of + true -> throw({dupl_entry, H, lists:subtract(Atoms, lists:uniq(Atoms))}); + false -> Atoms + end; + X -> X + end, [Item|get_items(T, Dict)]; get_items([], _Dict) -> []. @@ -1162,11 +1165,35 @@ smart_guess(Dir,IncPath) -> D1 = reverse(D), Dirs = [filename:join(D1 ++ ["src"]), filename:join(D1 ++ ["src", "e_src"])], - {Dirs,Dirs ++ IncPath}; + RecurseDirs = add_subdirs(Dirs), + {RecurseDirs,RecurseDirs ++ IncPath}; _ -> {[Dir],[Dir] ++ IncPath} end. +%%______________________________________________________________________ +%% add_subdirs([Dirs]) -> [Dirs] +%% Take the directories that were used for a guess, and search them +%% recursively. This is required for applications relying on varying +%% nested directories. One example within OTP is the `wx' application, +%% which has auto-generated modules in `src/gen/' and then fail any +%% systools check. + +add_subdirs([]) -> + []; +add_subdirs([Dir|Dirs]) -> + case filelib:is_dir(Dir) of + false -> + %% Keep the bad guess, but put it last in the search order + %% since we won't find anything there. Handling of errors + %% for unfound file is done in `locate_src/2' + add_subdirs(Dirs) ++ [Dir]; + true -> + SubDirs = [File || File <- filelib:wildcard(filename:join(Dir, "**")), + filelib:is_dir(File)], + [Dir|SubDirs] ++ add_subdirs(Dirs) + end. + %%______________________________________________________________________ %% generate_script(#release, %% [{{Name,Vsn},#application}], Flags) -> @@ -1346,7 +1373,7 @@ find_all(CheckingApp, [Name|T], L, Visited, Found, NotFound) -> case find_app(Name, L) of {value, App} -> {_A,R} = App, - %% It is OK to have a dependecy like + %% It is OK to have a dependency like %% X includes Y, Y uses X. case lists:member(CheckingApp, R#application.includes) of true -> @@ -1386,7 +1413,7 @@ del_apps([], L) -> %%______________________________________________________________________ %% Create the load path used in the generated script. %% If PathFlag is true a script intended to be used as a complete -%% system (e.g. in an embbeded system), i.e. all applications are +%% system (e.g. in an embedded system), i.e. all applications are %% located under $ROOT/lib. %% Otherwise all paths are set according to dir per application. @@ -1755,7 +1782,7 @@ add_system_files(Tar, RelName, Release, Path1) -> %% (well, actually the boot file was looked for in the same %% directory as RelName, which is not necessarily the same as cwd) %% -- - %% but also in the path specfied as an option to systools:make_tar + %% but also in the path specified as an option to systools:make_tar %% (but make sure to search the RelName directory and cwd first) Path = case filename:dirname(RelName) of "." -> @@ -2417,6 +2444,8 @@ form_reading({read,File}) -> io_lib:format("Cannot read ~tp~n",[File]); form_reading({{bad_param, P},_}) -> io_lib:format("Bad parameter in .app file: ~tp~n",[P]); +form_reading({{dupl_entry, P, DE},_}) -> + io_lib:format("~tp parameter contains duplicates of: ~tp~n", [P, DE]); form_reading({{missing_param,P},_}) -> io_lib:format("Missing parameter in .app file: ~p~n",[P]); form_reading({badly_formatted_application,_}) -> diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index c570ed00abbe..ead3c07dbb93 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -426,7 +426,7 @@ translate_dependent_instrs(Mode, Before, After, Appls) -> {Before ++ NBefore, NAfter}. translate_dep_loop(G, WCs, [I| Is], Appls, Before, After, Mode) - when is_tuple(I), size(I) > 1 -> + when tuple_size(I) > 1 -> IName = element(1, I), case lists:member(IName, ?DEP_INSTRS) of true -> @@ -465,7 +465,7 @@ make_dependency_graph(Instructions) -> {VDs, _} = lists:mapfoldl( fun(I, N) -> Mod = element(2, I), - Mods = element(size(I), I), + Mods = element(tuple_size(I), I), {{Mod, Mods, {N, I}}, N+1} end, 1, DepIs), G = digraph:new(), diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 2a782bcf613d..98c6cfb5bbc9 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2011-2016. All Rights Reserved. +# Copyright Ericsson AB 2011-2022. 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. @@ -35,10 +35,13 @@ MODULES= \ systools_rc_SUITE \ rb_SUITE \ rh_test_lib \ + otp_vsns ERL_FILES= $(MODULES:%=%.erl) -HRL_FILES= test_lib.hrl +EXTRA_FILES= $(ERL_TOP)/otp_versions.table + +HRL_FILES= TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) INSTALL_PROGS= $(TARGET_FILES) @@ -55,6 +58,7 @@ RELSYSDIR = $(RELEASE_PATH)/sasl_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/sasl/src +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -68,7 +72,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ >> $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: @@ -87,9 +91,11 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(EXTRA_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" @tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) + $(INSTALL_DIR) "$(RELSYSDIR)/sasl_SUITE_data" + $(INSTALL_DATA) $(ERL_TOP)/make/otp_version_tickets "$(RELSYSDIR)/sasl_SUITE_data" release_docs_spec: diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index 2c5c9d725aca..05b015657449 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2020. All Rights Reserved. +%% Copyright Ericsson AB 2011-2021. 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. @@ -20,8 +20,6 @@ -module(installer). --include("test_lib.hrl"). - %%-compile(export_all). -export([install_1/2]). -export([install_2/1]). @@ -330,7 +328,7 @@ install_11(TestNode) -> true = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), {ok, Dirs} = file:list_dir(code:root_dir()), - ErtsDir = "erts-"++?ertsvsn, + ErtsDir = "erts-"++rh_test_lib:old_app_vsn(erts), [ErtsDir] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), ?print(["install_11 file checks ok"]), ok. @@ -383,7 +381,7 @@ install_14(TestNode) -> %%%----------------------------------------------------------------- -%%% Ths test checks that an upgrade which both upgrades to a new +%%% The test checks that an upgrade which both upgrades to a new %%% emulator version, and had a restart_emulator option to %%% systools:make_relup will be restarted twice on upgrade. %%% (On downgrade it will happen only once.) @@ -413,7 +411,7 @@ upgrade_restart_2(TestNode) -> {"SASL-test","P2B"} -> upgrade_restart_2a(TestNode); {"SASL-test","__new_emulator__P1G"} -> - %% catched the node too early - give it another try + %% caught the node too early - give it another try {wait,whereis(init)} end. @@ -918,7 +916,9 @@ start_client_unix(TestNode,Sname,Node) -> start_client_win32(TestNode,Client,ClientSname) -> Name = atom_to_list(ClientSname) ++ "_P1G", RootDir = code:root_dir(), - ErtsBinDir = filename:join([RootDir,"erts-"++?ertsvsn,"bin"]), + ErtsBinDir = filename:join([RootDir, + "erts-"++rh_test_lib:old_app_vsn(erts), + "bin"]), {ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname, RootDir), diff --git a/lib/sasl/test/otp_vsns.erl b/lib/sasl/test/otp_vsns.erl new file mode 100644 index 000000000000..d88fb8a8159a --- /dev/null +++ b/lib/sasl/test/otp_vsns.erl @@ -0,0 +1,160 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021. 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(otp_vsns). + +-export([read_state/0, read_state/1, branch_latest/2, branch_vsns/2, app_vsn/3]). + +read_state() -> + File = "otp_versions.table", + Dir = filename:dirname(code:which(?MODULE)), + Alt0 = filename:join([Dir, File]), + case file:read_file_info(Alt0) of + {ok, _} -> + read_state(Alt0); + _ -> + Alt1 = filename:join([Dir, "..", "priv", File]), + case file:read_file_info(Alt1) of + {ok, _} -> + read_state(Alt1); + _ -> + error(no_otp_versions_table) + end + end. + +read_state(OtpVsnsTabFile) -> + {ok, OtpVsnsTabData} = file:read_file(OtpVsnsTabFile), + lists:foldl(fun (OtpAppVsnsBin, Acc0) -> + [OtpVsnBin + | AppVsnBins] = binary:split(OtpAppVsnsBin, + [<<" ">>, + <<":">>, + <<"#">>], + [global, trim_all]), + OtpVsn = mk_vsn(OtpVsnBin), + AppList = lists:map(fun (AppVsnBin) -> + AppVsn = mk_vsn(AppVsnBin), + {App, _} = AppVsn, + {App, AppVsn} + end, + AppVsnBins), + AppMap = maps:from_list(AppList), + Acc1 = maps:put(OtpVsn, AppMap, Acc0), + Acc2 = update_branch(OtpVsn, Acc1), + update_branch_versions(OtpVsn, Acc2) + end, + #{}, + binary:split(OtpVsnsTabData, <<"\n">>, [global, trim_all])). + +branch_latest(State, "maint-" ++ RelStr) -> + mk_vsn_str(maps:get({maint, list_to_integer(RelStr)}, State)). + +branch_vsns(State, "maint-" ++ RelStr) -> + Rel = list_to_integer(RelStr), + NrmlVsns = lists:map(fun (V) -> mk_vsn_str(V) end, + maps:get({normal_maint_vsns, Rel}, State)), + case maps:get({maint, Rel}, State) of + {'OTP', [_, _]} -> + NrmlVsns; + {'OTP', [_, _, _]} -> + NrmlVsns; + {'OTP', [_, _, _, _]} = Vsn -> + add_branched_vsns(1, Vsn, NrmlVsns) + end. + +add_branched_vsns(MinorPatch, + {'OTP', [_Major, _Minor, _Patch, MinorPatch]} = Vsn, + VsnStrs) -> + [mk_vsn_str(Vsn) | VsnStrs]; +add_branched_vsns(N, + {'OTP', [Major, Minor, Patch, _MinorPatch]} = Vsn, + VsnStrs) -> + VsnStr = mk_vsn_str({'OTP', [Major, Minor, Patch, N]}), + add_branched_vsns(N+1, Vsn, [VsnStr | VsnStrs]). + +app_vsn(State, "OTP-"++OtpVsn, App) -> + AppMap = maps:get({'OTP', vsnstr2vsnlist(OtpVsn)}, State), + mk_vsn_str(maps:get(list_to_atom(App), AppMap)). + +mk_vsn_str({App, Vsn}) -> + VsnStr = lists:flatten(lists:join($., lists:map(fun (V) -> + integer_to_list(V) + end, Vsn))), + atom_to_list(App) ++ "-" ++ VsnStr. + +mk_vsn(AppVsnBin) -> + [AppBin, VsnBin] = binary:split(AppVsnBin, <<"-">>), + {binary_to_atom(AppBin), vsnstr2vsnlist(VsnBin)}. + +vsnstr2vsnlist(VsnStr) -> + lists:map(fun (SV) when is_list(SV) -> + list_to_integer(SV); + (BV) when is_binary(BV) -> + binary_to_integer(BV) + end, string:lexemes(VsnStr, ".")). + +update_branch({'OTP', [Major, Minor | _] = Vsn} = OtpVsn, + VsnMap) when length(Vsn) =< 4 -> + Branch = {maint, Major}, + case maps:get(Branch, VsnMap, undefined) of + undefined -> + maps:put(Branch, OtpVsn, VsnMap); + {'OTP', [Major, OldMinor | _] = OldVsn} -> + if OldMinor < Minor -> + maps:put(Branch, OtpVsn, VsnMap); + OldMinor > Minor -> + VsnMap; + true -> + {Patch, MinorPatch} = get_patch_vsns(Vsn), + {OldPatch, OldMinorPatch} = get_patch_vsns(OldVsn), + if OldPatch < Patch -> + maps:put(Branch, OtpVsn, VsnMap); + OldPatch > Patch -> + VsnMap; + OldMinorPatch < MinorPatch -> + maps:put(Branch, OtpVsn, VsnMap); + true -> + VsnMap + end + end + end; +update_branch({'OTP', [_Major, _Minor | _]}, VsnMap) -> + VsnMap. + +update_branch_versions({'OTP', [Rel | _] = Vsn} = OtpVsn, + VsnMap) when length(Vsn) =< 3 -> + %% Save normal versions. Branched versions are added on request + %% since we do not know the right branch until all versions has + %% been parsed. + BranchVsnsKey = {normal_maint_vsns, Rel}, + OtherOtpVsns = case maps:get(BranchVsnsKey, VsnMap, undefined) of + undefined -> []; + Vsns -> Vsns + end, + maps:put(BranchVsnsKey, [OtpVsn|OtherOtpVsns], VsnMap); +update_branch_versions({'OTP', _}, VsnMap) -> + VsnMap. + +get_patch_vsns([_Major, _Minor]) -> + {0, 0}; +get_patch_vsns([_Major, _Minor, Patch]) -> + {Patch, 0}; +get_patch_vsns([_, _, Patch, MinorPatch | _]) -> + {Patch, MinorPatch}. diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index f545590247db..7e4c9df56f74 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2021. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -20,7 +20,8 @@ -module(release_handler_SUITE). -include_lib("common_test/include/ct.hrl"). --include("test_lib.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-include_lib("kernel/include/file.hrl"). -compile([export_all, nowarn_export_all]). -export([scheduler_wall_time/0, garbage_collect/0]). %% rpc'ed @@ -60,17 +61,16 @@ win32_cases() -> %% Cases that can be run on all platforms cases() -> - [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, - otp_9395_check_old_code, otp_9395_check_and_purge, - otp_9395_update_many_mods, otp_9395_rm_many_mods, + [otp_9395_check_old_code, instructions, eval_appup, eval_appup_with_restart, - supervisor_which_children_timeout, - release_handler_which_releases, install_release_syntax_check, - upgrade_supervisor, upgrade_supervisor_fail, otp_9864, - otp_10463_upgrade_script_regexp, no_dot_erlang, unicode_upgrade]. + install_release_syntax_check, + otp_10463_upgrade_script_regexp, no_dot_erlang, move_system, + {group, absolute}, {group, relative}]. groups() -> - [{release,[], + [{absolute,[],root_dir_cases()}, + {relative,[],root_dir_cases()}, + {release,[], [ {group,release_single}, {group,release_gg} @@ -87,6 +87,22 @@ groups() -> upgrade_gg ]}]. +%% Testcases that are to be run with and without an absolute root dir +root_dir_cases() -> + [supervisor_which_children_timeout, + release_handler_which_releases, + otp_2760, + otp_5761, + otp_9402, + otp_9417, + otp_9395_check_and_purge, + otp_9395_update_many_mods, + otp_9395_rm_many_mods, + otp_9864, + upgrade_supervisor, + upgrade_supervisor_fail, + unicode_upgrade]. + %% {group,release} %% Top group for all cases using run_erl init_per_group(release, Config) -> @@ -161,8 +177,10 @@ init_per_group(release_gg, Config0) -> Snames), test_server:timetrap_cancel(Dog), - [{snames,Snames}|Config]. - + [{snames,Snames}|Config]; +init_per_group(Group, Config) when Group =:= absolute; + Group =:= relative -> + [{root_dir, Group}|Config]. end_per_group(release, Config) -> Dog = test_server:timetrap(?default_timeout), @@ -244,6 +262,253 @@ gg_node_snames(Config) -> %%%----------------------------------------------------------------- %%% TEST CASES +%% Test that a release can be location independent (i.e., if all +%% paths related to the release are relative to the ROOTDIR of the +%% release, then one can move the release to a different directory and +%% it should still work). +move_system(Conf) when is_list(Conf) -> + + DataDir = ?config(data_dir, Conf), + TestRootDir = filename:join(priv_dir(Conf), ?FUNCTION_NAME), + ErtsBinDir = filename:join("erts-" ++ find_vsn_app(erts), "bin"), + + %% Remove old test data + file:del_dir_r(filename:join(TestRootDir,"system")), + file:del_dir_r(filename:join(TestRootDir,"system_moved")), + file:del_dir_r(filename:join(TestRootDir,"system_moved_again")), + + %% Create TAR file for release A + ReleaseATarFile = create_release_package(DataDir, "hello_server", "A"), + SystemPath = filename:join(TestRootDir, "system"), + ok = erl_tar:extract(ReleaseATarFile, [{cwd, SystemPath}, compressed]), + RelDir = filename:join(SystemPath, "releases"), + SystemRelFile = filename:join(RelDir, "hello_server-A.rel"), + + %% Create a location independent RELEASES file. Library paths in the releases + %% file are assumed to be relative to the RootDir. + ok = release_handler:create_RELEASES(RelDir, SystemRelFile, []), + + %% Create the bin directory with links (or copies on windows) to the erts directory + file:make_dir(filename:join(SystemPath,"bin")), + case os:type() of + {win32, _} -> + {ok,_} = file:copy( + filelib:wildcard(filename:join([SystemPath,ErtsBinDir,"erl.exe"])), + filename:join([SystemPath,"bin","erl.exe"])); + _ -> + ok = file:make_symlink( + filename:join(["..",ErtsBinDir,"erl"]), + filename:join([SystemPath,"bin","erl"])) + end, + + %% Test that the location independent system can start and run + {ok, Peer, Node} = start_remote_node(SystemPath, "A"), + hello = erpc:call(Node, app_callback_module, get_response, []), + peer:stop(Peer), + + %% Should still work after copying the system and corrupting the source + NewSystemPath = filename:join(TestRootDir, "system_moved"), + copy_r(SystemPath, NewSystemPath), + [file:del_dir_r(F) || F <- filelib:wildcard(filename:join([SystemPath,"lib","stdlib*"]))], + file:del_dir_r(filename:join(SystemPath,"releases")), + {ok, MovedPeer, MovedNode} = start_remote_node(NewSystemPath, "A"), + hello = erpc:call(MovedNode, app_callback_module, get_response, []), + peer:stop(MovedPeer), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Let us now try if a system upgrade also works with a location independent system % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ReleaseBTarFile = create_release_package(DataDir, "hello_server_new", "B"), + + BPackDest = filename:join([NewSystemPath, "releases", filename:basename(ReleaseBTarFile)]), + {ok, _ } = file:copy(ReleaseBTarFile, BPackDest), + BTarFileName = filename:basename(ReleaseBTarFile), + NameToUnpack = filename:rootname(BTarFileName, ".tar.gz"), + %% Start remote node with release A + {ok, PeerA, NodeA} = start_remote_node(NewSystemPath, "A"), + + %% Set current working directory to something irrelevant as the + %% current working directory should not affect if a system is + %% location independent or not + ok = erpc:call(NodeA, file, set_cwd, ["/"]), + %% Let us check our app + hello = erpc:call(NodeA, app_callback_module, get_response, []), + %% Install the next release + {ok, "B"} = erpc:call(NodeA, release_handler, unpack_release, [NameToUnpack]), + %% We can now create relup file + AppUpSrc = filename:join([DataDir, "relocatable_release", "hello_server_new", + "ebin", "hello_server.appup"]), + AppUpDest = filename:join([NewSystemPath, "lib", "hello_server-B", "ebin", "hello_server.appup"]), + {ok, _} = file:copy(AppUpSrc, AppUpDest), + %% Run command to create the relup file + ok = systools:make_relup( + filename:join([NewSystemPath, "releases", "B", "hello_server-B"]), + [filename:join([NewSystemPath, "releases", "A", "hello_server-A"])], + [filename:join([NewSystemPath, "releases", "A", "hello_server-A"])], + [{outdir,filename:join([NewSystemPath, "releases","B"])}, + {path,[NewSystemPath ++ "/lib/hello_server-A/ebin/", + NewSystemPath ++ "/lib/hello_server-B/ebin/"]}] + ), + %% Install the B version + {ok, "A", _} = erpc:call(NodeA, release_handler, install_release, ["B"]), + %% Check that the releases info looks ok + true = lists:any(fun({"hello_server", "B", _, current}) -> + true; + (_) -> + false + end, + erpc:call(NodeA, release_handler, which_releases, [])), + %% Make sure the old module gets replaced + ok = erpc:call(NodeA, app_callback_module, update, []), + %% Check that the upgrade worked + hej = erpc:call(NodeA, app_callback_module, get_response, []), + + case os:type() of + {win32, _} -> + %% We cannot make release permanent on windows due to + %% not having permissions to edit services. + %% And symlinks to do not on windows, so we don't test + %% anything more there. + peer:stop(PeerA); + _ -> + move_system_unix(NodeA, PeerA, TestRootDir, ErtsBinDir, NewSystemPath) + + end. + +move_system_unix(NodeA, PeerA, TestRootDir, ErtsBinDir, NewSystemPath) -> + %% Make the upgrade permanent + ok = erpc:call(NodeA, release_handler, make_permanent, ["B"]), + %% Check that it still works + hej = erpc:call(NodeA, app_callback_module, get_response, []), + true = lists:any(fun({"hello_server", "B", _, permanent}) -> + true; + (_) -> + false + end, + erpc:call(NodeA, release_handler, which_releases, [])), + ok = peer:stop(PeerA), + + %% We will now move the install and check that everything still seems to be working fine + NewSystemPath2 = filename:join(TestRootDir, "system_moved_again"), + ok = file:rename(NewSystemPath, NewSystemPath2), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Create a symlink to moved system and test that if we set the path to + %% contain the symlink it will work. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ok = file:make_symlink( + filename:join([NewSystemPath2, ErtsBinDir, "erl"]), + filename:join(TestRootDir, "erl")), + + Name = peer:random_name(), + LinkNode = list_to_atom(Name++"@"++lists:last(string:split(atom_to_list(node()),"@"))), + + %% We cannot use ?CT_PEER here because it uses spawn_executable and that + %% does not search the PATH for which program to run. + Port = open_port( + {spawn,"erl -sname " ++ Name ++ " -boot " ++ + filename:join([NewSystemPath2, "releases", "B", "start"])}, + [{env,[{"PATH",TestRootDir ++ ":" ++ os:getenv("PATH")}]}]), + + %% Wait for node to start + receive M1 -> ct:pal("~p",[M1]) end, + receive M2 -> ct:pal("~p",[M2]) end, + + hej = erpc:call(LinkNode, app_callback_module, get_response, []), + + true = catch port_close(Port), + ct:log("~p",[(fun F() -> receive M -> [M | F()] after 0 -> [] end end)()]), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Test that we can do a downgrade of the moved system + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + {ok, PeerB, NodeB} = start_remote_node(NewSystemPath2, "B"), + + %% Change current working directory to something irrelevant + ok = erpc:call(NodeB, file, set_cwd, ["/"]), + {ok, "/"} = erpc:call(NodeB, file, get_cwd, []), + %% Check that we are using version B + hej = erpc:call(NodeB, app_callback_module, get_response, []), + %% Downgrade to version A + {ok, "A", _} = erpc:call(NodeB, release_handler, install_release, ["A"]), + true = lists:any(fun({"hello_server", "A", _, current}) -> + true; + (_) -> + false + end, + erpc:call(NodeB, release_handler, which_releases, [])), + %% Make sure that the module is reloaded + ok = erpc:call(NodeB, app_callback_module, update, []), + %% Make sure that we are on version A + hello = erpc:call(NodeB, app_callback_module, get_response, []), + %% Make the downgrade permanent + ok = erpc:call(NodeB, release_handler, make_permanent, ["A"]), + %% Test that remove release works + ok = erpc:call(NodeB, release_handler, remove_release, ["B"]), + %% B should not exist anymore + false = lists:any(fun({"hello_server", "B", _, _}) -> + true; + (_) -> + false + end, + erpc:call(NodeB, release_handler, which_releases, [])), + ok = erpc:call(NodeB, app_callback_module, update, []), + %% We should still get hello + hello = erpc:call(NodeB, app_callback_module, get_response, []), + ok = peer:stop(PeerB), + + ok. + +start_remote_node(SystemPath, RelVsn) -> + SystemErlPath = filename:join([SystemPath, "bin", "erl"]), + ?CT_PEER(#{ exec => SystemErlPath, + args => ["-boot",filename:join([SystemPath,"releases", RelVsn, "start"])]}). + +create_release_package(DataDir, SourceDir, RelVsn) -> + ReleaseSource = filename:join(DataDir, "relocatable_release"), + AppSrc = filename:join(ReleaseSource, SourceDir), + OldCWD = file:get_cwd(), + file:set_cwd(AppSrc), + os:cmd("erl -make"), + file:set_cwd(OldCWD), + RelFileScr = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".rel.src"), + RelFileDst = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".rel"), + {ok, RelFileTxt1} = file:read_file(RelFileScr), + RelFileTxt = fix_rel_file_vsns(["erts", "kernel", "stdlib", "sasl"], + RelFileTxt1), + ok = file:write_file(RelFileDst, RelFileTxt), + AppPath = filename:join([ReleaseSource, SourceDir, "ebin"]), + RelFileWithoutEnding = filename:join(ReleaseSource, "hello_server-" ++ RelVsn), + ok = systools:make_script(RelFileWithoutEnding, [local, {path, [AppPath]}]), + ok = systools:make_tar(RelFileWithoutEnding, [{erts, code:root_dir()}, {path, [AppPath]}]), + SystemPath = filename:join(ReleaseSource, "system"), + file:make_dir(SystemPath), + InitialTarPath = filename:join(ReleaseSource, "hello_server-"++ RelVsn ++".tar.gz"), + InitialTarPath. + +fix_rel_file_vsns(Apps, Txt) -> + Res = + lists:foldl( + fun(App, TxtAcc) -> + string:replace(TxtAcc, + "%" ++ App ++ "_VSN" ++ "%" , + find_vsn_app(erlang:list_to_atom(App))) + end, + Txt, + Apps), + erlang:iolist_to_binary(lists:flatten(Res)). + +find_vsn_app(erts) -> + Str = erlang:system_info(system_version), + {match, [{Start, Len} | _]} = re:run(Str, "erts-(\\d\\.?)+"), + ErtsStr = string:substr(Str, Start+1, Len), + [_, Vsn] = string:split(ErtsStr, "-"), + Vsn; +find_vsn_app(App) -> + Apps = application:which_applications(), + [Vsn] = [Vsn || {AppX, _, Vsn} <- Apps, AppX =:= App], + Vsn. + %% Executed instead of release group when no run_erl program exists no_run_erl(Config) when is_list(Config) -> @@ -390,7 +655,7 @@ upgrade_restart(Conf) when is_list(Conf) -> ok -> ok; {wait,TestNodeInit2a} -> - %% We catched the node too early - it was supposed to + %% We caught the node too early - it was supposed to %% restart twice, so let's wait for one more restart. wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]), ok = rpc_inst(TestNode, upgrade_restart_2a, []) @@ -618,7 +883,7 @@ supervisor_which_children_timeout(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,release_handler_timeouts]), - Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{dummy,"0.1",LibDir}]), {ok, Node} = t_start_node(supervisor_which_children_timeout, Rel1, []), Proc = rpc:call(Node, erlang, whereis, [dummy_sup_2]), @@ -657,7 +922,7 @@ release_handler_which_releases(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,release_handler_timeouts]), - Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{dummy,"0.1",LibDir}]), {ok, Node} = t_start_node(release_handler_which_releases, Rel1, []), Releases0 = rpc:call(Node, release_handler, which_releases, []), @@ -713,7 +978,7 @@ otp_2760(Conf) -> DataDir = ?config(data_dir,Conf), LibDir = filename:join([DataDir,app1_app2,lib1]), - Rel1 = create_and_install_fake_first_release(Dir,[{app1,"1.0",LibDir}]), + Rel1 = create_and_install_fake_first_release(Conf,Dir,[{app1,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir,"after",[],{[Rel1],[Rel1],[LibDir]}), Rel2Dir = filename:dirname(Rel2), @@ -751,7 +1016,7 @@ otp_5761(Conf) when is_list(Conf) -> LibDir2 = filename:join(RelDir, "lib2"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{app1,"1.0",LibDir1}, {app2,"1.0",LibDir1}]), Rel2 = create_fake_upgrade_release(Dir, @@ -830,7 +1095,7 @@ otp_9402(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{a,"1.1",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -897,7 +1162,7 @@ otp_9417(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{b,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1010,7 +1275,7 @@ otp_9395_check_and_purge(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{b,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1076,7 +1341,7 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{many_mods,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1191,7 +1456,7 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) -> LibDir = filename:join(?config(data_dir, Conf), "lib"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{many_mods,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, "2", @@ -1303,7 +1568,7 @@ do_otp_9864(Conf) -> LibDir2 = filename:join(Dir, "lib2"), %% Create the releases - Rel1 = create_and_install_fake_first_release(Dir, + Rel1 = create_and_install_fake_first_release(Conf,Dir, [{app1,"1.0",LibDir1}, {app2,"1.0",LibDir1}]), Rel2 = create_fake_upgrade_release(Dir, @@ -1359,7 +1624,7 @@ upgrade_supervisor(Conf) when is_list(Conf) -> %% Create the releases Lib1 = [{a,"1.0",LibDir}], Lib2 = [{a,"9.0",LibDir}], - Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel1 = create_and_install_fake_first_release(Conf,Dir,Lib1), Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), Rel1Dir = filename:dirname(Rel1), Rel2Dir = filename:dirname(Rel2), @@ -1416,7 +1681,7 @@ upgrade_supervisor_fail(Conf) when is_list(Conf) -> %% Create the releases Lib1 = [{a,"1.0",LibDir}], Lib2 = [{a,"9.1",LibDir}], - Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel1 = create_and_install_fake_first_release(Conf,Dir,Lib1), Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), Rel1Dir = filename:dirname(Rel1), Rel2Dir = filename:dirname(Rel2), @@ -1814,15 +2079,34 @@ upgrade_gg(Conf) -> %% start gg2 and gg6 [Gg2,Gg6] = start_nodes(Conf,[Gg2Sname,Gg6Sname],"upgrade_gg start gg2/gg6"), + %% Watch dog pulling out some more information in case we hang... + Nodes3 = [Gg1,Gg2,Gg4,Gg5,Gg6], + Tester = self(), + WD = spawn_link(fun () -> + receive after 7*60*1000 -> ok end, + ct:pal("7 minutes passed...~n", []), + erlang:suspend_process(Tester), + load_suite(Nodes3), + dump_info([node()|Nodes3]), + exit(operation_hang) + end), + %% reg proc on each of the nodes ok = rpc:call(Gg2, installer, reg_proc, [reg2]), ok = rpc:call(Gg6, installer, reg_proc, [reg6]), - are_names_reg_gg(Gg1, [reg1, reg2, reg4, reg5, reg6]), %% Check global group info - Nodes3 = [Gg1,Gg2,Gg4,Gg5,Gg6], [check_gg_info(Node,Nodes3,[],Nodes3--[Node]) || Node <- Nodes3], + OkList = lists:map(fun (_) -> ok end, Nodes3), + {OkList,[]} = rpc:multicall(Nodes3, global, sync, []), + + are_names_reg_gg(Gg1, [reg1, reg2, reg4, reg5, reg6]), + + unlink(WD), + exit(WD, kill), + false = is_process_alive(WD), + ok. upgrade_gg(cleanup,Config) -> @@ -1830,6 +2114,53 @@ upgrade_gg(cleanup,Config) -> NodeNames = [node_name(Sname) || Sname <- Snames], ok = stop_nodes(NodeNames). +load_suite(Nodes) -> + {ok,Bin}=file:read_file(code:which(?MODULE)), + _ = rpc:multicall(Nodes, erlang, load_module, [?MODULE, Bin]), + ok. + +dump_info(Nodes) -> + GetLockerState = fun (TheLocker) -> + Mon = erlang:monitor(process, TheLocker), + TheLocker ! {get_state, self(), Mon}, + receive + Msg when element(1, Msg) =:= Mon -> + erlang:demonitor(Mon, [flush]), + RList = tl(erlang:tuple_to_list(Msg)), + erlang:list_to_tuple([state | RList]); + {'DOWN', Mon, process, TheLocker, Reason} -> + {error, Reason} + after 60*1000 -> + erlang:demonitor(Mon, [flush]), + {error, timeout} + end + end, + GI = rpc:multicall(Nodes, + erlang, + apply, + [fun () -> + GlobalLocker = global:get_locker(), + {node(), + #{global_state => global:info(), + global_dict => process_info(whereis(global_name_server), dictionary), + global_locks_tab => ets:tab2list(global_locks), + global_names_tab => ets:tab2list(global_names), + global_names_ext_tab => ets:tab2list(global_names_ext), + global_pid_names_tab => ets:tab2list(global_pid_names), + global_pid_ids_tab => ets:tab2list(global_pid_ids), + global_lost_connections_tab => ets:tab2list(global_lost_connections), + global_node_resources_tag => ets:tab2list(global_node_resources), + global_locker_state => GetLockerState(GlobalLocker), + global_locker_info => process_info(GlobalLocker, + [status, + current_stacktrace, + messages, + dictionary]), + global_group_info => global_group:info()}} + end, + []], + 2*60*1000), + ct:pal("GI: ~p~n", [GI]). %%%----------------------------------------------------------------- %%% OTP-10463, Bug - release_handler could not handle regexp in appup @@ -1926,7 +2257,7 @@ unicode_upgrade(Conf) -> %% Create the releases RelName = "unicode_rel_αβ", - Rel1 = create_and_install_fake_first_release(Dir,{RelName,"1"}, + Rel1 = create_and_install_fake_first_release(Conf,Dir,{RelName,"1"}, [{u,"1.0",LibDir}]), Rel2 = create_fake_upgrade_release(Dir, {RelName,"2"}, @@ -2241,7 +2572,7 @@ copy_tree(Conf, Src, NewName, DestDir) -> TempTarName = filename:join(PrivDir, "temp_tar_file.tar"), %% Not compressing tar file here since that would increase test %% suite time by almost 100%, and the tar file is deleted - %% imediately anyway. + %% immediately anyway. {ok,Tar} = erl_tar:open(TempTarName, [write]), ok = erl_tar:add(Tar, Src, NewName, []), ok = erl_tar:close(Tar), @@ -2405,6 +2736,17 @@ create_p1g(Conf,TargetDir) -> filename:join([DataDir,lib,"installer-1.0",ebin])), copy_file(filename:join(DataDir, "../rh_test_lib.beam"), filename:join([DataDir,lib,"installer-1.0",ebin])), + copy_file(filename:join(DataDir, "../otp_vsns.beam"), + filename:join([DataDir,lib,"installer-1.0",ebin])), + + InstPrivDir = filename:join([DataDir,lib,"installer-1.0","priv"]), + case file:read_file_info(InstPrivDir) of + {ok, _} -> + ok; + _ -> + ok = file:make_dir(InstPrivDir) + end, + copy_file(filename:join(DataDir, "../otp_versions.table"), InstPrivDir), %% Create .rel, .script and .boot files RelName = "rel0", @@ -2583,48 +2925,31 @@ check_gg_info(Node,OtherAlive,OtherDead,Synced) -> check_gg_info(Node,OtherAlive,OtherDead,Synced,N) -> GGI = rpc:call(Node, global_group, info, []), - GI = rpc:call(Node, global, info,[]), - try do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI) - catch _:E:Stacktrace when N==0 -> + try do_check_gg_info(OtherAlive,OtherDead,Synced,GGI) + catch _:E:Stacktrace -> test_server:format("~nERROR: check_gg_info failed for ~p:~n~p~n" - "when GGI was: ~p~nand GI was: ~p~n", - [Node,{E,Stacktrace},GGI,GI]), - ct:fail("check_gg_info failed"); - _:E:Stacktrace -> - test_server:format("~nWARNING: check_gg_info failed for ~p:~n~p~n" - "when GGI was: ~p~nand GI was: ~p~n", - [Node,{E,Stacktrace},GGI,GI]), - timer:sleep(1000), - check_gg_info(Node,OtherAlive,OtherDead,Synced,N-1) + "when GGI was: ~p~n", + [Node,{E,Stacktrace},GGI]), + if N == 0 -> + ct:fail("check_gg_info failed"); + true -> + ok = rpc:call(Node, global_group, sync, []), + timer:sleep(1000), + check_gg_info(Node,OtherAlive,OtherDead,Synced,N-1) + end end. -do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI) -> +do_check_gg_info(OtherAlive,OtherDead,Synced,GGI) -> {_,gg1} = lists:keyfind(own_group_name,1,GGI), {_,synced} = lists:keyfind(state,1,GGI), {_,AllNodes} = lists:keyfind(own_group_nodes,1,GGI), true = lists:sort(AllNodes) =:= lists:sort(OtherAlive++OtherDead), {_,[]} = lists:keyfind(sync_error,1,GGI), {_,[{gg2,[_,_]}]} = lists:keyfind(other_groups,1,GGI), - - %% There is a known bug in global_group (OTP-9177) which causes - %% the following to fail every now and then: - %% {_,SyncedNodes} = lists:keyfind(synced_nodes,1,GGI), - %% true = lists:sort(SyncedNodes) =:= lists:sort(Synced), - %% {_,NoContact} = lists:keyfind(no_contact,1,GGI), - %% true = lists:sort(NoContact) =:= lists:sort(OtherDead), - - %% Therefore we use global:info instead for this part - {state,_,_,SyncedNodes,_,_,_,_,_,_,_} = GI, + {_,SyncedNodes} = lists:keyfind(synced_nodes,1,GGI), true = lists:sort(SyncedNodes) =:= lists:sort(Synced), - - %% .. and we only check that all OtherDead are listed as - %% no_contact (due to th bug there might be more nodes in this - %% list) {_,NoContact} = lists:keyfind(no_contact,1,GGI), - true = - lists:sort(OtherDead) =:= - lists:sort([NC || NC <- NoContact,lists:member(NC,OtherDead)]), - + true = lists:sort(NoContact) =:= lists:sort(OtherDead), ok. %% Return the configuration (to be inserted in sys.config) for global group tests @@ -2650,7 +2975,7 @@ permanent_p1h(Node) -> ok = rpc_inst(Node, permanent_p1h, []). %% For each node in ToNodes, create a target installation which is -%% indentical to the target installation for FromNode. +%% identical to the target installation for FromNode. copy_installed(Conf,FromNode,ToNodes) -> PrivDir = priv_dir(Conf), DataDir = ?config(data_dir,Conf), @@ -2832,9 +3157,9 @@ cover_fun(Node,Func) -> %% current running OTP release. It includes kernel, stdlib and sasl, %% and possibly other applications if they are listed in AppDirs = %% [{App,Vsn,LibDir}] -create_and_install_fake_first_release(Dir,AppDirs) -> - create_and_install_fake_first_release(Dir,init:script_id(),AppDirs). -create_and_install_fake_first_release(Dir,{RelName,RelVsn},AppDirs) -> +create_and_install_fake_first_release(Conf,Dir,AppDirs) -> + create_and_install_fake_first_release(Conf,Dir,init:script_id(),AppDirs). +create_and_install_fake_first_release(Conf,Dir,{RelName,RelVsn},AppDirs) -> {Rel,_} = create_fake_release(Dir,RelName,RelVsn,AppDirs), ReleasesDir = filename:join(Dir, "releases"), RelDir = filename:dirname(Rel), @@ -2847,13 +3172,21 @@ create_and_install_fake_first_release(Dir,{RelName,RelVsn},AppDirs) -> ok = copy_file(Rel++".boot",filename:join(RelVsnDir, "start.boot")), ok = copy_file(filename:join(RelDir,"sys.config"),RelVsnDir), - ok = release_handler:create_RELEASES(code:root_dir(), - ReleasesDir, - Rel++".rel", - AppDirs), - + case proplists:get_value(root_dir, Conf, relative) of + relative -> + ok = release_handler:create_RELEASES( + ReleasesDir, + Rel++".rel", + AppDirs); + absolute -> + ok = release_handler:create_RELEASES( + code:root_dir(), + ReleasesDir, + Rel++".rel", + AppDirs) + end, Rel. - + %% This function create a new release, including a relup file. It can %% be upgraded to from the release created by %% create_and_install_fake_first_release/2. Unpack first by calls to @@ -2897,7 +3230,7 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> ok = copy_file(Rel++".boot", filename:join(RelDir,"start.boot")), %% Use an own 'releases' directory - we don't want to change the - %% contents of $OTP_ROOT/releases + %% contents of $OTPROOT/releases %% Inform SASL about this via sys.config ReleasesDir = filename:join(Dir, "releases"), Config = [{sasl,[{releases_dir,ReleasesDir}]}], @@ -2940,9 +3273,7 @@ modify_tar_win32(Conf, TarFileName) -> app_dir(App,Vsn) -> atom_to_list(App) ++ "-" ++ vsn(App,Vsn). -vsn(erts,old) -> ?ertsvsn; -vsn(kernel,old) -> ?kernelvsn; -vsn(stdlib,old) -> ?stdlibvsn; +vsn(App,old) -> rh_test_lib:old_app_vsn(App); vsn(erts,current) -> erlang:system_info(version); vsn(App,current) -> {ok,Vsn} = application:get_key(App,vsn), @@ -2950,3 +3281,20 @@ vsn(App,current) -> system_lib(PrivDir) -> filename:join(PrivDir,"system_lib"). + +copy_r(Src, Dst) -> + {ok,S} = file:read_file_info(Src), + case S#file_info.type of + directory -> + {ok,Names} = file:list_dir(Src), + ok = filelib:ensure_dir(Dst), + ok = file:make_dir(Dst), + lists:foreach( + fun(Name) -> + copy_r(filename:join(Src, Name), + filename:join(Dst, Name)) + end, Names); + _ -> + {ok,_NumBytesCopied} = file:copy(Src, Dst), + ok = file:write_file_info(Dst, S) + end. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app index e1391c06057c..b1622307bb78 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app +++ b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app @@ -1,6 +1,6 @@ {application, installer, [{description, "Installer application"}, {vsn, "1.0"}, - {modules, [installer,rh_test_lib]}, + {modules, [installer,rh_test_lib,otp_vsns]}, {registered, []}, {applications, [kernel, stdlib, sasl]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src new file mode 100644 index 000000000000..8b8ec2eff648 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-A.rel.src @@ -0,0 +1,8 @@ +{release, + {"hello_server", "A"}, + {erts, "%erts_VSN%"}, + [{kernel, "%kernel_VSN%"}, + {stdlib, "%stdlib_VSN%"}, + {sasl, "%sasl_VSN%"}, + {hello_server, "A"}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src new file mode 100644 index 000000000000..c966ad48ec47 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server-B.rel.src @@ -0,0 +1,8 @@ +{release, + {"hello_server", "B"}, + {erts, "%erts_VSN%"}, + [{kernel, "%kernel_VSN%"}, + {stdlib, "%stdlib_VSN%"}, + {sasl, "%sasl_VSN%"}, + {hello_server, "B"}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile new file mode 100644 index 000000000000..8e1f951aee61 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/Emakefile @@ -0,0 +1,2 @@ +{"src/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. +{"test/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore new file mode 100644 index 000000000000..1ef2775ff8f2 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/.gitignore @@ -0,0 +1 @@ +*.beam \ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app new file mode 100644 index 000000000000..697bd7add40c --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/ebin/hello_server.app @@ -0,0 +1,7 @@ +{application, hello_server, + [{description, "Simple server that sends back hello"}, + {vsn, "A"}, + {modules, [app_callback_module, hello_server]}, + {registered, [hello_server]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {app_callback_module,[]}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl new file mode 100644 index 000000000000..0d988ab8f685 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/app_callback_module.erl @@ -0,0 +1,26 @@ +-module(app_callback_module). + +-behaviour(application). + +-export([start/2, stop/1, get_response/0, update/0]). + +start(_Type, _Args) -> + Pid = hello_server:start_server(), + global:register_name(hello_server, Pid), + {ok, Pid}. + +update() -> + global:whereis_name(hello_server) ! update, + ok. + +get_response() -> + global:whereis_name(hello_server) ! self(), + receive + A -> + A + end. + +stop(_State) -> + Pid = global:whereis_name(hello_server), + hello_server:stop(Pid), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl new file mode 100644 index 000000000000..1008e1f4e2de --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server/src/hello_server.erl @@ -0,0 +1,20 @@ +-module(hello_server). + +-export([start_server/0, stop/1, loop/0]). + +start_server() -> + erlang:spawn_link(?MODULE, loop, []). + +stop(Pid) -> + Pid ! stop. + +loop() -> + receive + stop -> + ok; + update -> + ?MODULE:loop(); + Sender -> + Sender ! hello, + loop() + end. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile new file mode 100644 index 000000000000..8e1f951aee61 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/Emakefile @@ -0,0 +1,2 @@ +{"src/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. +{"test/*", [debug_info, {i,"include/"}, {outdir, "ebin/"}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore new file mode 100644 index 000000000000..1ef2775ff8f2 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/.gitignore @@ -0,0 +1 @@ +*.beam \ No newline at end of file diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app new file mode 100644 index 000000000000..1e1426344b93 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.app @@ -0,0 +1,7 @@ +{application, hello_server, + [{description, "Simple server that sends back hej"}, + {vsn, "B"}, + {modules, [app_callback_module, hello_server]}, + {registered, [hello_server]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {app_callback_module,[]}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup new file mode 100644 index 000000000000..1aa16cd39c73 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/ebin/hello_server.appup @@ -0,0 +1,3 @@ +{"B", + [{"A", [{load_module, hello_server}]}], + [{"A", [{load_module, hello_server}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl new file mode 100644 index 000000000000..0d988ab8f685 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/app_callback_module.erl @@ -0,0 +1,26 @@ +-module(app_callback_module). + +-behaviour(application). + +-export([start/2, stop/1, get_response/0, update/0]). + +start(_Type, _Args) -> + Pid = hello_server:start_server(), + global:register_name(hello_server, Pid), + {ok, Pid}. + +update() -> + global:whereis_name(hello_server) ! update, + ok. + +get_response() -> + global:whereis_name(hello_server) ! self(), + receive + A -> + A + end. + +stop(_State) -> + Pid = global:whereis_name(hello_server), + hello_server:stop(Pid), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl new file mode 100644 index 000000000000..d40309457a65 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/relocatable_release/hello_server_new/src/hello_server.erl @@ -0,0 +1,20 @@ +-module(hello_server). + +-export([start_server/0, stop/1, loop/0]). + +start_server() -> + erlang:spawn_link(?MODULE, loop, []). + +stop(Pid) -> + Pid ! stop. + +loop() -> + receive + stop -> + ok; + update -> + ?MODULE:loop(); + Sender -> + Sender ! hej, + loop() + end. diff --git a/lib/sasl/test/rh_test_lib.erl b/lib/sasl/test/rh_test_lib.erl index 6425fce7a760..dba45bece69f 100644 --- a/lib/sasl/test/rh_test_lib.erl +++ b/lib/sasl/test/rh_test_lib.erl @@ -12,13 +12,15 @@ -export([clean_dir/1, clean_dir/2]). +-export([old_app_vsn/1]). + -include_lib("kernel/include/file.hrl"). cmd(Cmd,Args,Env) -> case open_port({spawn_executable, Cmd}, [{args,Args},{env,Env}]) of Port when is_port(Port) -> unlink(Port), - catch erlang:port_close(Port), % migth already be closed, so catching + catch erlang:port_close(Port), % might already be closed, so catching ok; Error -> Error @@ -160,3 +162,23 @@ rm_rf([File|Files],Save) -> end; rm_rf([],_) -> ok. + +old_app_vsn(App) -> + %% Get oldest application version (erts, kernel, sasl, + %% stdlib) we support upgrade from, i.e., the first + %% application version in the release two releases + %% prior to current release... + State = case get('__otp_vsns_state__') of + undefined -> + S = otp_vsns:read_state(), + put('__otp_vsns_state__', S), + S; + S -> + S + end, + Rel = integer_to_list(list_to_integer(erlang:system_info(otp_release))-2), + AppVsn = otp_vsns:app_vsn(State, "OTP-"++Rel++".0", atom_to_list(App)), + [_, Vsn] = string:lexemes(AppVsn, "-"), + Vsn. + + diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 1b377db903e9..bbebce83ae57 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -32,7 +32,7 @@ log_file/1, utc_log/1]). --compile(r21). +-compile(r22). all() -> [log_mf_h_env, log_file, app_test, appup_test, utc_log]. @@ -60,6 +60,19 @@ end_per_group(_GroupName, Config) -> Config. +init_per_testcase(appup_test, Config) -> + %% We check if the test results were released using a version + %% of Erlang/OTP that was a tagged version or not. On a non-tagged + %% version this testcase most likely will fail. + case file:read_file( + filename:join( + proplists:get_value(data_dir,Config), "otp_version_tickets")) of + {ok,<<"DEVELOPMENT",_/binary>>} -> + {skip, "This is a development version, test might fail " + "because of incorrect version numbers"}; + {ok,S} -> + Config + end; init_per_testcase(_Case, Config) -> Config. end_per_testcase(_Case, _Config) -> @@ -74,8 +87,6 @@ app_test(Config) when is_list(Config) -> appup_test(_Config) -> appup_tests(sasl,create_test_vsns(sasl)). -appup_tests(_App,{[],[]}) -> - {skip,"no previous releases available"}; appup_tests(App,{OkVsns0,NokVsns}) -> application:load(App), {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()), @@ -88,8 +99,7 @@ appup_tests(App,{OkVsns0,NokVsns}) -> OkVsns0 -> OkVsns0; Ok -> - ct:log("Current version, ~p, is same as in previous release.~n" - "Removing this from the list of ok versions.", + ct:log("Removed current version ~p from the list of ok versions to test.", [Vsn]), Ok end, @@ -104,57 +114,46 @@ appup_tests(App,{OkVsns0,NokVsns}) -> ok. create_test_vsns(App) -> - ThisMajor = erlang:system_info(otp_release), - FirstMajor = previous_major(ThisMajor), - SecondMajor = previous_major(previous_major(FirstMajor)), - Ok = app_vsn(App,[ThisMajor,FirstMajor]), - Nok0 = app_vsn(App,[SecondMajor]), + S = otp_vsns:read_state(), + Rel = list_to_integer(erlang:system_info(otp_release)), + AppStr = atom_to_list(App), + Ok = ok_app_vsns(S, Rel, AppStr), + Nok0 = nok_app_vsns(S, Rel, AppStr, hd(Ok)), Nok = case Ok of - [Ok1|_] -> - [Ok1 ++ ",1" | Nok0]; % illegal - _ -> - Nok0 - end, - {Ok,Nok}. - -previous_major("17") -> - "r16b"; -previous_major("r16b") -> - "r15b"; -previous_major(Rel) -> - integer_to_list(list_to_integer(Rel)-1). - -app_vsn(App,[R|Rs]) -> - OldRel = - case test_server:is_release_available(R) of - true -> - {release,R}; - false -> - case ct:get_config({otp_releases,list_to_atom(R)}) of - undefined -> - false; - Prog0 -> - case os:find_executable(Prog0) of - false -> - false; - Prog -> - {prog,Prog} - end - end - end, - case OldRel of - false -> - app_vsn(App,Rs); - _ -> - {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]), - _ = rpc:call(N,application,load,[App]), - As = rpc:call(N,application,loaded_applications,[]), - {_,_,V} = lists:keyfind(App,1,As), - test_server:stop_node(N), - [V|app_vsn(App,Rs)] - end; -app_vsn(_App,[]) -> - []. + [Ok1|_] -> + [Ok1 ++ ",1" | Nok0]; % illegal + _ -> + Nok0 + end, + {Ok, Nok}. + +ok_app_vsns(S, Rel, AppStr) -> + AppVsns0 = get_rel_app_vsns(S, Rel-2, AppStr), + AppVsns1 = get_rel_app_vsns(S, Rel-1, AppStr), + AppVsns2 = try + get_rel_app_vsns(S, Rel, AppStr) + catch + _:_ -> [] + end, + lists:usort(AppVsns2 ++ AppVsns1 ++ AppVsns0). + +nok_app_vsns(S, Rel, AppStr, EarliestOkVsn) -> + AppVsns0 = get_rel_app_vsns(S, Rel-4, AppStr), + AppVsns1 = get_rel_app_vsns(S, Rel-3, AppStr), + %% Earliest OK version may exist in not OK versions + %% as well if there were no application version bump + %% between two releases, so we need to remove it + %% if that is the case... + lists:usort(AppVsns1 ++ AppVsns0) -- EarliestOkVsn. + +get_rel_app_vsns(S, Rel, App) -> + RelStr = integer_to_list(Rel), + OtpVsns = otp_vsns:branch_vsns(S, "maint-"++RelStr), + lists:map(fun (OtpVsn) -> + AppVsn = otp_vsns:app_vsn(S, OtpVsn, App), + [_, Vsn] = string:lexemes(AppVsn, "-"), + Vsn + end, OtpVsns). check_appup([Vsn|Vsns],Instrs,Expected) -> case systools_relup:appup_search_for_version(Vsn, Instrs) of diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl index 42672358c094..fb607d02cae8 100644 --- a/lib/sasl/test/sasl_report_SUITE.erl +++ b/lib/sasl/test/sasl_report_SUITE.erl @@ -95,12 +95,8 @@ gen_server_crash(Config, Encoding, FormatterOpts, Min, Max) -> ok = file:write_file(ConfigFileName ++ ".config", io_lib:format("[{kernel, ~p},~n{sasl, ~p}].", [KernelConfig,SaslConfig])), - {ok,Node} = - test_server:start_node( - TC, peer, - [{args, ["-pa ",filename:dirname(code:which(?MODULE)), - " -boot start_sasl -kernel start_timer true " - "-config ",ConfigFileName]}]), + {ok,Peer,Node} = ?CT_PEER(["-boot", "start_sasl", "-kernel", "start_timer", "true", + "-config", ConfigFileName]), %% Set depth or chars_limit. ok = rpc:call(Node,logger,update_formatter_config,[default,FormatterOpts]), @@ -126,7 +122,7 @@ gen_server_crash(Config, Encoding, FormatterOpts, Min, Max) -> ok = rpc:call(Node,logger_std_h,filesync,[default]), ok = rpc:call(Node,logger_std_h,filesync,[sasl]), - test_server:stop_node(Node), + peer:stop(Peer), ok = logger:remove_primary_filter(no_remote), check_file(KernelLog, utf8, Min, Max), diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index ef863581a5a3..534a1824b179 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2021. All Rights Reserved. +%% Copyright Ericsson AB 2012-2023. 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. @@ -63,7 +63,7 @@ groups() -> src_tests_script, crazy_script, optional_apps_script, included_script, included_override_script, included_fail_script, included_bug_script, exref_script, - duplicate_modules_script, + duplicate_modules_script, duplicate_entries_script, otp_3065_circular_dependenies, included_and_used_sort_script]}, {tar, [], [tar_options, relname_tar, normal_tar, no_mod_vsn_tar, system_files_tar, @@ -106,6 +106,9 @@ init_per_suite(Config) when is_list(Config) -> %% Compile source files in the copy directory. Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])), lists:foreach(fun compile_source/1, Sources), + %% Deal with subdirectories, if any + SubSources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*','*.erl'])), + lists:foreach(fun compile_subsource/1, SubSources), [{copy_dir, CopyDir}, {cwd,Cwd}, {path,Path} | Config]. @@ -122,6 +125,16 @@ compile_source(File) -> ok = file:write_file(OutFileTemp, Code), file:rename(OutFileTemp, OutFile). +compile_subsource(File) -> + %% Same as compile_source/1 but works a subdirectory lower + U = filename:dirname(filename:dirname(filename:dirname(File))), + Base = filename:rootname(filename:basename(File)), + OutFile = filename:join([U,"ebin",Base++".beam"]), + OutFileTemp = OutFile ++ "#", + {ok,_,Code} = compile:file(File, [binary]), + ok = file:write_file(OutFileTemp, Code), + file:rename(OutFileTemp, OutFile). + end_per_suite(Config) when is_list(Config) -> rh_test_lib:clean_dir(?privdir), Config. @@ -278,9 +291,7 @@ unicode_script(Config) when is_list(Config) -> %% Need to do this on a separate node to make sure it has unicode %% filename mode (+fnu*) - {ok,HostStr} = inet:gethostname(), - Host = list_to_atom(HostStr), - {ok,Node} = ct_slave:start(Host,unicode_script_node,[{erl_flags,"+fnui"}]), + {ok,Peer,Node} = ?CT_PEER(["+fnui"]), ok = rpc:call(Node,erl_tar,extract, [TarFile, [{cwd,UnicodeLibDir},compressed]]), @@ -313,10 +324,11 @@ unicode_script(Config) when is_list(Config) -> rpc:call(Node,code,add_pathz,[filename:dirname(code:which(?MODULE))]), rpc:call(Node,?MODULE,delete_tree,[UnicodeLibDir]), + peer:stop(Peer), + ok. unicode_script(cleanup,Config) -> - _ = ct_slave:stop(unicode_script_node), file:delete(fname(?privdir, "unicode_app.tgz")), ok. @@ -455,6 +467,18 @@ variable_script(Config) when is_list(Config) -> ok = file:set_cwd(OldDir), ok. +%% make_script: Duplicate entries in app file +duplicate_entries_script(Config) when is_list(Config) -> + DataDir = ?datadir, + create_apps_duplicate_entry(DataDir), + {LatestDir, LatestName} = create_script(latest_t21,Config), + error = systools:make_script(LatestName, + [{path, [DataDir, LatestDir]}]), + {LatestDir2, LatestName2} = create_script(latest_t22,Config), + ok = systools:make_script(LatestName2, + [{path, [DataDir, LatestDir2]}]), + ok. + %% make_script: Abnormal cases. abnormal_script(Config) when is_list(Config) -> {ok, OldDir} = file:get_cwd(), @@ -1097,9 +1121,9 @@ erts_tar(Config) -> {win32, _} -> {["beam.smp.pdb","erl.exe", "erl.pdb","erl_log.exe","erlexec.dll","erlsrv.exe","heart.exe", - "start_erl.exe","werl.exe","beam.smp.dll", + "start_erl.exe","beam.smp.dll", "epmd.exe","erl.ini","erl_call.exe", - "erlexec.pdb","escript.exe","inet_gethost.exe","werl.pdb"], + "erlexec.pdb","escript.exe","inet_gethost.exe"], ["dialyzer.exe","erlc.exe","yielding_c_fun.exe","ct_run.exe","typer.exe"]} end, @@ -1386,7 +1410,7 @@ src_tests_tar(Config) when is_list(Config) -> %% make_tar: Check that make_tar handles generation and placement of %% tar files for variables outside the main tar file. -%% Test the {var_tar, include | ownfile | omit} optio. +%% Test the {var_tar, include | ownfile | omit} option. var_tar(Config) when is_list(Config) -> {ok, OldDir} = file:get_cwd(), PSAVE = code:get_path(), % Save path @@ -2563,6 +2587,12 @@ create_script(latest_app_start_type2,Config) -> {xmerl,current,none}], Apps = core_apps(current) ++ OtherApps, do_create_script(latest_app_start_type2,Config,current,Apps); +create_script(latest_t21, Config) -> + Apps = core_apps(current) ++ [{t21, "1.0"}], + do_create_script(latest_t21, Config, "4.4", Apps); +create_script(latest_t22, Config) -> + Apps = core_apps(current) ++ [{t22, "1.0"}], + do_create_script(latest_t22, Config, "4.4", Apps); create_script(current_all_no_sasl,Config) -> Apps = [{kernel,current},{stdlib,current},{db,"2.1"},{fe,"3.1"}], do_create_script(current_all_no_sasl,Config,current,Apps); @@ -2894,7 +2924,6 @@ create_include_files(sort_apps_rev, Config) -> file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}. - create_apps(Dir) -> T1 = "{application, t1,\n" " [{vsn, \"1.0\"},\n" @@ -3013,8 +3042,6 @@ create_apps2(Dir) -> " {registered, []}]}.\n", file:write_file(fname(Dir, 't13.app'), list_to_binary(T13)). - - create_apps_3065(Dir) -> T11 = "{application, chTraffic,\n" " [{vsn, \"1.0\"},\n" @@ -3107,6 +3134,24 @@ create_sort_apps(Dir) -> " {registered, []}]}.\n", file:write_file(fname(Dir, 't20.app'), list_to_binary(T20)). +create_apps_duplicate_entry(Dir) -> + T21 = "{application, t21,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, [test, test]}]}.\n", + file:write_file(fname(Dir, 't21.app'), list_to_binary(T21)), + T22 = "{application, t22,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, [test]}]}.\n", + file:write_file(fname(Dir, 't22.app'), list_to_binary(T22)). + fname(N) -> filename:join(N). diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app index a1025c306a4c..28d0f80d34d0 100644 --- a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app +++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app @@ -1,7 +1,7 @@ {application, db, [{description, "ERICSSON NR FOR DB"}, {vsn, "2.1"}, - {modules, [db1, db2]}, + {modules, [db1, db2, db3]}, {registered, []}, {applications, []}, {env, []}, diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/sub/db3.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/sub/db3.erl new file mode 100644 index 000000000000..010249638f99 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/sub/db3.erl @@ -0,0 +1,3 @@ +-module(db3). +-vsn("1.0"). + diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl deleted file mode 100644 index 6f02666b875f..000000000000 --- a/lib/sasl/test/test_lib.hrl +++ /dev/null @@ -1,3 +0,0 @@ --define(ertsvsn,"10.4"). --define(kernelvsn,"6.4"). --define(stdlibvsn,"3.9"). diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index c38e64d0a9c9..569f493b684c 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 4.1.2 +SASL_VSN = 4.2.1 diff --git a/lib/snmp/.gitignore b/lib/snmp/.gitignore index aef73491a4f3..9f3a9a2331e0 100644 --- a/lib/snmp/.gitignore +++ b/lib/snmp/.gitignore @@ -6,3 +6,7 @@ doc/index.html mibs/.index + +# Agent +src/agent/Makefile + diff --git a/lib/snmp/bin/snmp-v2tov1.pl b/lib/snmp/bin/snmp-v2tov1.pl index f9ecfc9dd8bf..6f1e73087dcb 100644 --- a/lib/snmp/bin/snmp-v2tov1.pl +++ b/lib/snmp/bin/snmp-v2tov1.pl @@ -64,7 +64,7 @@ next line; } - # Translate TEXTUAL-CONVENTION into an ordinary type assignement. + # Translate TEXTUAL-CONVENTION into an ordinary type assignment. # Place comments around body. if (/TEXTUAL-CONVENTION/ && ($str == 0)) { $textual = 1; diff --git a/lib/snmp/configure b/lib/snmp/configure index 65d95918cc2c..a907ba26b2ad 100755 --- a/lib/snmp/configure +++ b/lib/snmp/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,41 +167,52 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -227,14 +220,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -252,18 +252,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -290,6 +291,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -307,6 +309,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -321,7 +331,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -330,7 +340,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -369,12 +379,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -386,18 +397,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -409,9 +429,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -438,7 +458,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -482,7 +502,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -496,6 +516,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -509,6 +533,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -574,17 +605,22 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= - -ac_unique_file="vsn.mk" +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="src/app/snmp.app.src" ac_subst_vars='LTLIBOBJS LIBOBJS +SNMP_EMPTY_PDU_SIZE_DEFAULT PERL +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -635,6 +671,7 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking +with_snmp_empty_pdu_size ' ac_precious_vars='build_alias host_alias @@ -707,8 +744,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -749,9 +784,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -775,9 +810,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -988,9 +1023,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1004,9 +1039,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1050,9 +1085,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1068,7 +1103,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1132,7 +1167,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1250,6 +1285,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1257,6 +1293,13 @@ if test -n "$ac_init_help"; then cat <<\_ACEOF +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-snmp-empty-pdu-size=SZ + Empty pdu size, in number of bytes >= 21; default is + 21 + Report bugs to the package provider. _ACEOF ac_status=$? @@ -1273,9 +1316,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1303,7 +1346,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1311,7 +1355,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1321,9 +1365,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1333,14 +1377,34 @@ fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -1373,8 +1437,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -1409,7 +1477,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -1444,11 +1512,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -1459,8 +1529,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -1484,7 +1554,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -1492,14 +1562,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -1507,15 +1577,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -1523,8 +1593,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -1538,69 +1608,152 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false @@ -1611,12 +1764,12 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -1625,24 +1778,24 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in @@ -1652,11 +1805,12 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -1670,57 +1824,126 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_aux_dir= -for ac_dir in ${ERL_TOP}/erts/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in ${ERL_TOP}/erts/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -1739,21 +1962,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -1772,20 +1996,116 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=win32 + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 +fi + fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 +fi + # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PERL+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PERL+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$PERL"; then ac_cv_prog_PERL="$PERL" # Let the user override the test. else @@ -1793,11 +2113,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PERL="perl" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -1809,11 +2133,11 @@ fi fi PERL=$ac_cv_prog_PERL if test -n "$PERL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 -$as_echo "$PERL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf "%s\n" "$PERL" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -1822,8 +2146,34 @@ if test "$PERL" = no_perl; then fi + + + +# Check whether --with-snmp-empty-pdu-size was given. +if test ${with_snmp_empty_pdu_size+y} +then : + withval=$with_snmp_empty_pdu_size; +else $as_nop + with_snmp_empty_pdu_size=21 +fi + + +if test $with_snmp_empty_pdu_size -lt 21; then + SNMP_EMPTY_PDU_SIZE_DEFAULT=21 + as_fn_error $? "Minimum size of 'empty pdu size' is 21" "$LINENO" 5 +else + SNMP_EMPTY_PDU_SIZE_DEFAULT=$with_snmp_empty_pdu_size + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Default (snmp) empty pdu size set to $with_snmp_empty_pdu_size" >&5 +printf "%s\n" "$as_me: Default (snmp) empty pdu size set to $with_snmp_empty_pdu_size" >&6;} +fi + + + + ac_config_files="$ac_config_files mibs/Makefile:mibs/Makefile.in" +ac_config_files="$ac_config_files src/agent/Makefile:src/agent/Makefile.in" + test "x$prefix" = xNONE && prefix=$ac_default_prefix @@ -1874,7 +2224,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -1890,8 +2240,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -1914,14 +2264,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -1931,46 +2283,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -1979,13 +2331,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -1994,8 +2339,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -2007,30 +2356,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -2043,13 +2372,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -2076,18 +2406,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -2099,12 +2431,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -2135,7 +2468,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -2157,6 +2490,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -2170,6 +2507,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -2211,7 +2554,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -2220,7 +2563,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -2283,7 +2626,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -2332,14 +2675,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -2376,21 +2721,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -2418,7 +2763,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -2432,7 +2777,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -2446,6 +2791,7 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in "mibs/Makefile") CONFIG_FILES="$CONFIG_FILES mibs/Makefile:mibs/Makefile.in" ;; + "src/agent/Makefile") CONFIG_FILES="$CONFIG_FILES src/agent/Makefile:src/agent/Makefile.in" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac @@ -2457,7 +2803,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -2685,7 +3031,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -2693,17 +3039,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -2720,7 +3066,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -2744,9 +3090,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -2799,8 +3145,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -2842,9 +3188,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -2891,8 +3237,9 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/lib/snmp/configure.ac b/lib/snmp/configure.ac new file mode 100644 index 000000000000..8f4c1fd83390 --- /dev/null +++ b/lib/snmp/configure.ac @@ -0,0 +1,71 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- +dnl +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 2021-2022. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% +dnl + + +define([AC_CACHE_LOAD], )dnl +define([AC_CACHE_SAVE], )dnl + +AC_INIT +AC_CONFIG_SRCDIR([src/app/snmp.app.src]) +AC_PREREQ([2.71]) + +m4_include([otp.m4]) + +AC_CONFIG_AUX_DIRS([${ERL_TOP}/make/autoconf]) + +dnl ---------------------------------------------------------------------- +dnl Checks for programs. +dnl ---------------------------------------------------------------------- + +ERL_CANONICAL_SYSTEM_TYPE + +AC_CHECK_PROG(PERL, perl, perl, no_perl) +if test "$PERL" = no_perl; then + AC_MSG_ERROR([Perl is required to generate v2 to v1 mib converter script]) +fi + + +dnl ---------------------------------------------------------------------- + +dnl *** SNMP_EMPTY_PDU_SIZE *** + +AC_ARG_WITH(snmp-empty-pdu-size, +AS_HELP_STRING([--with-snmp-empty-pdu-size=SZ], + [Empty pdu size, in number of bytes >= 21; default is 21]), +[], +[with_snmp_empty_pdu_size=21]) + +if test $with_snmp_empty_pdu_size -lt 21; then + SNMP_EMPTY_PDU_SIZE_DEFAULT=21 + AC_MSG_ERROR([Minimum size of 'empty pdu size' is 21]) +else + SNMP_EMPTY_PDU_SIZE_DEFAULT=$with_snmp_empty_pdu_size + AC_MSG_NOTICE([Default (snmp) empty pdu size set to $with_snmp_empty_pdu_size]) +fi + + +dnl ---------------------------------------------------------------------- + +AC_SUBST(SNMP_EMPTY_PDU_SIZE_DEFAULT) +AC_CONFIG_FILES([mibs/Makefile:mibs/Makefile.in]) +AC_CONFIG_FILES([src/agent/Makefile:src/agent/Makefile.in]) +AC_OUTPUT + diff --git a/lib/snmp/configure.in b/lib/snmp/configure.in deleted file mode 100644 index bac042ccca5b..000000000000 --- a/lib/snmp/configure.in +++ /dev/null @@ -1,28 +0,0 @@ - -define([AC_CACHE_LOAD], )dnl -define([AC_CACHE_SAVE], )dnl - -AC_INIT(vsn.mk) - -AC_CONFIG_AUX_DIRS(${ERL_TOP}/erts/autoconf) - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -else - host_os=win32 -fi - - -dnl ---------------------------------------------------------------------- -dnl Checks for programs. -dnl ---------------------------------------------------------------------- - - -AC_CHECK_PROG(PERL, perl, perl, no_perl) -if test "$PERL" = no_perl; then - AC_MSG_ERROR([Perl is required to generate v2 to v1 mib converter script]) -fi - - -AC_OUTPUT(mibs/Makefile:mibs/Makefile.in) - diff --git a/lib/snmp/doc/src/files.mk b/lib/snmp/doc/src/files.mk index 44db07230b2f..9670dfdca8a5 100644 --- a/lib/snmp/doc/src/files.mk +++ b/lib/snmp/doc/src/files.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2021. All Rights Reserved. +# Copyright Ericsson AB 2001-2022. 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. @@ -101,6 +101,7 @@ XML_CHAPTER_FILES = \ snmp_advanced_agent.xml \ snmp_app_a.xml \ snmp_app_b.xml \ + snmp_app_c.xml \ notes.xml BOOK_FILES = book.xml diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 262556c6d4ed..5c1c9a7444e5 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -34,6 +34,185 @@
    +
    SNMP 5.15 + +
    Improvements and New Features + + +

    + Make snmp handle gen_udp with socket backend on Windows + (completion).

    +

    + Own Id: OTP-18598 Aux Id: OTP-18029

    +
    +
    +
    + +
    + +
    SNMP 5.14 + +
    Improvements and New Features + + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    SNMP 5.13.5 + +
    Improvements and New Features + + +

    + Attempts to minimize the number of the error reports + during a failed agent init.

    +

    + Own Id: OTP-18422 Aux Id: ERIERL-873

    +
    +
    +
    + +
    + +
    SNMP 5.13.4 + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    SNMP 5.13.3 + +
    Fixed Bugs and Malfunctions + + +

    + Single threaded agent crash when vacm table not properly + initiated.

    +

    + Own Id: OTP-18379 Aux Id: ERIERL-904

    +
    +
    +
    + +
    + +
    SNMP 5.13.2 + +
    Fixed Bugs and Malfunctions + + +

    + Explicitly close the socket(s) when terminating + (default-) net-if process.

    +

    + Own Id: OTP-18352 Aux Id: ERIERL-881

    +
    +
    +
    + +
    + +
    SNMP 5.13.1.1 + +
    Fixed Bugs and Malfunctions + + +

    + Single threaded agent crash when vacm table not properly + initiated.

    +

    + Own Id: OTP-18379 Aux Id: ERIERL-904

    +
    +
    +
    + +
    + +
    SNMP 5.13.1 + +
    Fixed Bugs and Malfunctions + + +

    + Improved the get-bulk response max size calculation. Its + now possible to configure 'empty pdu size', see appendix + c for more info.

    +

    + Own Id: OTP-17115 Aux Id: ERIERL-456

    +
    + +

    + Fix various example dialyzer issues

    +

    + Own Id: OTP-18180 Aux Id: ERIERL-837

    +
    +
    +
    + +
    + +
    SNMP 5.13 + +
    Improvements and New Features + + +

    + Input for configure scripts adapted to + autoconf 2.71.

    +

    + Own Id: OTP-17414 Aux Id: PR-4967

    +
    + +

    + Removed deprecated functions slated for removal in + OTP-25. Also removed "dead" code, kept for backward + compatibility reasons.

    +

    + Own Id: OTP-17612

    +
    +
    +
    + +
    +
    SNMP 5.12.0.3
    Improvements and New Features @@ -50,7 +229,7 @@
    -
    SNMP 5.12.0.2 +
    SNMP 5.12.0.2
    Fixed Bugs and Malfunctions @@ -66,7 +245,7 @@
    -
    SNMP 5.12.0.1 +
    SNMP 5.12.0.1
    Fixed Bugs and Malfunctions @@ -262,7 +441,7 @@

    [manager] In a function handling snmp errors, an unused result (_Error) could result in matching issues and - therefor case clause runtime errors (crash). Note that + therefore case clause runtime errors (crash). Note that this would only happen in *very* unusual error cases.

    Own Id: OTP-17161

    @@ -1122,7 +1301,7 @@

    - Improved cryptocraphic capability.

    + Improved cryptographic capability.

    Own Id: OTP-12452

    @@ -1378,7 +1557,7 @@

    Add (atl) log conversion block option.

    It is now possible to request that the Audit Trail Log should be blocked during conversion (log_to_txt or log_to_io). - This could be usefull when coverting an entire large log (when + This could be useful when converting an entire large log (when there is a chance it may otherwise wrap during conversion).

    See agent @@ -1849,7 +2028,7 @@ -

    [agent] Sematic fixes to SNMP-USER-BASED-SM-MIB. +

    [agent] Semantic fixes to SNMP-USER-BASED-SM-MIB. The semantics allow the usmUserAuthKeyChange and usmUserPrivKeyChange objects to be written to in the same set requests that also creates and clones the user. @@ -1958,7 +2137,7 @@

    [manager] Introduced a new transport module, snmpm_net_if_mt, - which handles all incomming and outgoing + which handles all incoming and outgoing traffic in newly created processes. The message/request is processed and then the process exits.

    Own Id: OTP-9876

    @@ -1972,7 +2151,7 @@

    [agent] Improve error handling while reading agent config files. - Some files contain mandatory information and is therefor themself + Some files contain mandatory information and is therefore themself mandatory.

    Own Id: OTP-9943

    @@ -2159,8 +2338,8 @@ conflict. When dumping the vacm table to disk, a temoporary file with a fixed name was used. If the table dumping (snmpa_vacm:dump_table/0) was initiated from several different - processes in rapid succesion, the dumping could fail because the - different processes was simultaniously trying to write to the + processes in rapid succession, the dumping could fail because the + different processes was simultaneously trying to write to the same file. This problem has been eliminated by creating a unique name for the temporary file.

    Own Id: OTP-9851

    @@ -2623,7 +2802,7 @@

    See snmpa:send_notification2/3 for more info. - See also the incomming net-if messages when sending a + See also the incoming net-if messages when sending a trap (send_pdu message) and diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml index ed71a86e830f..cd65aec57da9 100644 --- a/lib/snmp/doc/src/notes_history.xml +++ b/lib/snmp/doc/src/notes_history.xml @@ -4,7 +4,7 @@

    - 20042020 + 20042022 Ericsson AB. All Rights Reserved. @@ -438,7 +438,7 @@

    [agent] The main agent type header file contained some miss-information regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.

    + unnecessary confusion.

    Own Id: OTP-8116

    Aux Id: Seq 11312

    @@ -490,7 +490,7 @@

    [agent] A manager could no longer use the SNMPv3 user "initial" - as this was interpretated as the first step of the discovery.

    + as this was interpreted as the first step of the discovery.

    Introduced a new terminating option, trigger_username to make it possible to configure the username the agent reacts to. Default is "".

    @@ -514,7 +514,7 @@

    [agent] The main agent type header file contained some miss-information regarding the type of the entrytype field of the me-record, causing - unneccessary confusion.

    + unnecessary confusion.

    Own Id: OTP-8116

    Aux Id: Seq 11312

    @@ -1397,7 +1397,7 @@

    [agent] Uninstalling MEs when unloading mibs incorrect and - therefor never done.

    + therefore never done.

    Own Id: OTP-7153

    @@ -2175,7 +2175,7 @@

    [manager] Improve handling of empty messages. Today when receiving an empty (size = 0) udp message, this - will result in a decode failure (a catched function + will result in a decode failure (a caught function clause), which in turn will be passed on to the user, via a call to the handle_error diff --git a/lib/snmp/doc/src/part.xml b/lib/snmp/doc/src/part.xml index 5ac6dc391798..4e5a33b6b2a4 100644 --- a/lib/snmp/doc/src/part.xml +++ b/lib/snmp/doc/src/part.xml @@ -4,7 +4,7 @@

    - 19962016 + 19962022 Ericsson AB. All Rights Reserved. @@ -51,5 +51,6 @@ + diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml index 9a4e123cb264..cc866b9f9931 100644 --- a/lib/snmp/doc/src/snmp.xml +++ b/lib/snmp/doc/src/snmp.xml @@ -381,7 +381,7 @@ Stop is the stop (last) date and time to which log events will be converted. The Block argument indicates if the log should be blocked - during conversion. This could be usefull when converting large + during conversion. This could be useful when converting large logs (when otherwise the log could wrap during conversion). Defaults to true.

    diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 9728b6e93a7d..9b0760ab5291 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -224,7 +224,7 @@ in the snmp_config file!

    Even with multi-threaded set to extended there is still a risk for 'reorder' when sending inform-requsts, - which require a response (and may therefor require resending).

    + which require a response (and may therefore require resending).

    Also, there is of course no way to guarantee order once the package is on the network.

    @@ -303,7 +303,7 @@ in the snmp_config file! {filter, agent_net_if_filter_options()} | {open_err_filters, agent_net_if_open_err_filters()} | {extra_sock_opts, extra_socket_options()} | - {inet_backend, inet | socket}

    + {inet_backend, inet_backend()}

    These options are actually specific to the used module. The ones shown here are applicable to the default agent_net_if_module().

    @@ -396,7 +396,7 @@ in the snmp_config file! behaviour.

    Several entities (mib-server via the its data module and the symbolic-store) of the snmp agent uses this for storage - of miscelaneous mib related data retrieved while loading a mib.

    + of miscellaneous mib related data retrieved while loading a mib.

    There are several implementations provided with the agent: snmpa_mib_storage_ets, snmpa_mib_storage_dets and snmpa_mib_storage_mnesia.

    @@ -406,7 +406,7 @@ in the snmp_config file! ]]> -

    This is implementattion depended. That is, it depends on the +

    This is implementation depended. That is, it depends on the module. For each module a specific set of options are valid. For the module provided with the app, these options are supported:

    @@ -824,8 +824,8 @@ in the snmp_config file! {recbuf, recbuf()} | {no_reuse, no_reuse()} | {filter, manager_net_if_filter_options()} | - {extra_sock_opts, extra_socket_options()} | - {inet_backend, inet | socket}

    + {extra_sock_opts, extra_socket_options()}} | + {inet_backend, inet_backend()}

    These options are actually specific to the used module. The ones shown here are applicable to the default manager_net_if_module().

    @@ -968,6 +968,15 @@ in the snmp_config file!

    Default is [].

    + + ]]> + +

    Choose the inet-backend.

    +

    This option make it possible to use net_if (gen_udp) with a + different inet-backend ('inet' or 'socket').

    +

    Default is inet.

    +
    + ]]> diff --git a/lib/snmp/doc/src/snmp_app_c.xml b/lib/snmp/doc/src/snmp_app_c.xml new file mode 100644 index 000000000000..8bf71800e53d --- /dev/null +++ b/lib/snmp/doc/src/snmp_app_c.xml @@ -0,0 +1,53 @@ + + + + +
    + + 20222022 + Ericsson AB. 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. + + + + SNMP Appendix C + + + + + + + + snmp_app_c.xml +
    + +
    + Appendix C + +
    + Compile time configuration +

    There is one compile/configure time option: + Defining the size of an "empty" PDU. This is used when processing + get-bulk requests. The default value for this is 21, + but can be increased in two ways:

    + + configure: --with-snmp-empty-pdu-size=SIZE + compile time: environment variable: SNMP_EMPTY_PDU_SIZE=SIZE" + +

    Where SIZE is a value greater or equal to 21.

    +
    +
    +
    + diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index c1c312a56ee3..c82236e87d27 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -209,7 +209,7 @@

    Even with multi-threaded set to extended there is still a risk for 'reorder' when sending inform-requsts, - which require a response (and may therefor require resending).

    + which require a response (and may therefore require resending).

    Also, there is of course no way to guarantee order once the package is on the network.

    @@ -287,9 +287,9 @@ {no_reuse, no_reuse()} | {req_limit, req_limit()} | {filter, agent_net_if_filter_options()} | - {extra_sock_opts, extra_socket_options()} | {open_err_filters, agent_net_if_open_err_filters()} | - {inet_backend, inet | socket}

    + {extra_sock_opts, extra_socket_options()} | + {inet_backend, inet_backend()}

    These options are actually specific to the used module. The ones shown here are applicable to the default agent_net_if_module().

    @@ -841,13 +841,13 @@ in so far as it will be converted to the new format if found. ]]>

    manager_net_if_option() = - {bind_to, bind_to()} | - {sndbuf, sndbuf()} | - {recbuf, recbuf()} | - {no_reuse, no_reuse()} | - {filter, manager_net_if_filter_options()} | - {extra_sock_opts, extra_socket_options()} | - {inet_backend, inet | socket}

    + {bind_to, bind_to()} | + {sndbuf, sndbuf()} | + {recbuf, recbuf()} | + {no_reuse, no_reuse()} | + {filter, manager_net_if_filter_options()} | + {extra_sock_opts, extra_socket_options()} | + {inet_backend, inet_backend()}

    These options are actually specific to the used module. The ones shown here are applicable to the default manager_net_if_module().

    @@ -990,6 +990,15 @@ in so far as it will be converted to the new format if found.

    Default is [].

    + + ]]> + +

    Choose the inet-backend.

    +

    This option make it possible to use net_if (gen_udp) with a + different inet-backend ('inet' or 'socket').

    +

    Default is inet.

    +
    + ]]> diff --git a/lib/snmp/doc/src/snmp_def_instr_functions.xml b/lib/snmp/doc/src/snmp_def_instr_functions.xml index 5fbcfaf2db48..5a59f1bae5da 100644 --- a/lib/snmp/doc/src/snmp_def_instr_functions.xml +++ b/lib/snmp/doc/src/snmp_def_instr_functions.xml @@ -99,7 +99,7 @@ genErr. Used if an error occurred. Note, this should be an internal processing error, e.g. a caused - by a programing fault somewhere. If the variable does not + by a programming fault somewhere. If the variable does not exist, use {noValue, noSuchName} or {noValue, noSuchInstance}. @@ -275,7 +275,7 @@
    genErr. Used if an error occurred. Note that this should be an internal processing error, e.g. a caused - by a programing fault somewhere. If some column does not + by a programming fault somewhere. If some column does not exist, use {noValue, noSuchName} or {noValue, noSuchInstance}. @@ -322,7 +322,7 @@ {NextOid, NextValue}, where NextOid is the lexicographic next OBJECT IDENTIFIER for the corresponding column. This should be specified as the - OBJECT IDENTIFER part following the table entry. This + OBJECT IDENTIFIER part following the table entry. This means that the first integer is the column number and the rest is a specification of the keys. NextValue is the value of this element. @@ -336,7 +336,7 @@ the column that caused the error. Column must be one of the columns in the Cols list. Note that this should be an internal processing error, e.g. a caused - by a programing fault somewhere. If some column does not + by a programming fault somewhere. If some column does not exist, you must return the next accessible element (or endOfTable). diff --git a/lib/snmp/doc/src/snmp_index.xml b/lib/snmp/doc/src/snmp_index.xml index 9c8e6b8b33c9..108266e608da 100644 --- a/lib/snmp/doc/src/snmp_index.xml +++ b/lib/snmp/doc/src/snmp_index.xml @@ -4,7 +4,7 @@
    - 19972020 + 19972022 Ericsson AB. All Rights Reserved. @@ -123,7 +123,7 @@ get_next_pid(Oid, SnmpIndex) ->

    For example, if the SNMP table has two INDEX columns, the first one an OCTET STRING with size 2, and the second one an OBJECT - IDENTIFER, the corresponding key_types parameter would be + IDENTIFIER, the corresponding key_types parameter would be {fix_string, string}.

    The key() type correlates to the key_types() diff --git a/lib/snmp/doc/src/snmp_intro.xml b/lib/snmp/doc/src/snmp_intro.xml index ec3f2af956a4..819a34fc9c95 100644 --- a/lib/snmp/doc/src/snmp_intro.xml +++ b/lib/snmp/doc/src/snmp_intro.xml @@ -4,7 +4,7 @@

    - 19972016 + 19972023 Ericsson AB. All Rights Reserved. @@ -81,7 +81,7 @@
    Prerequisites

    The following prerequisites - is required for understanding the material in the SNMP + are required for understanding the material in the SNMP User's Guide:

    diff --git a/lib/snmp/doc/src/snmp_manager_netif.xml b/lib/snmp/doc/src/snmp_manager_netif.xml index f6c9e642cf7e..a790a7e7f3b4 100644 --- a/lib/snmp/doc/src/snmp_manager_netif.xml +++ b/lib/snmp/doc/src/snmp_manager_netif.xml @@ -4,7 +4,7 @@
    - 20042020 + 20042022 Ericsson AB. All Rights Reserved. @@ -63,8 +63,8 @@ The (supervising) process simply sends a ping message and expects a pong message response - (withing a specific time). - The interval between each ping/pong exhange is user configurable. + (within a specific time). + The interval between each ping/pong exchange is user configurable. As is the time that is allowed for the pong message to arrive. diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index fb341f8f792d..c7ddd10d67a8 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -587,7 +587,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} LogName defaults to "snmpa_log". LogFile defaults to "snmpa.log".

    The Block option indicates if the log should be blocked - during conversion. This could be usefull when converting large + during conversion. This could be useful when converting large logs (when otherwise the log could wrap during conversion). Defaults to true.

    See snmp:log_to_txt @@ -628,7 +628,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} LogName defaults to "snmpa_log". LogFile defaults to "snmpa.log".

    The Block option indicates if the log should be blocked - during conversion. This could be usefull when converting large + during conversion. This could be useful when converting large logs (when otherwise the log could wrap during conversion). Defaults to true.

    See snmp:log_to_io @@ -772,7 +772,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} Agent = pid() | atom() -

    Retreive the size of the mib server cache.

    +

    Retrieve the size of the mib server cache.

    @@ -1104,7 +1104,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).

    The 'process oid' "tag" that can be provided with the - variable name / oids is indended to be used for oid post + variable name / oids is intended to be used for oid post processing. The value 'keep', which is the default, leaves the oid as is. The value 'truncate', will cause the oid to be "truncated". That is, any trailing ".0" will be removed.

    @@ -1126,8 +1126,8 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2). of this data, with one exception: Any tuple containing the atom snmpa_default_notification_extra_info - may be used by the agent and is therefor reserved.

    -

    See the net-if incomming messages for sending a + may be used by the agent and is therefore reserved.

    +

    See the net-if incoming messages for sending a trap and diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml index 1937e0f78079..3dcfdc5865b4 100644 --- a/lib/snmp/doc/src/snmpa_mib_data.xml +++ b/lib/snmp/doc/src/snmpa_mib_data.xml @@ -4,7 +4,7 @@

    - 20132020 + 20132022 Ericsson AB. All Rights Reserved. @@ -363,7 +363,7 @@

    Perform a backup of the mib-server data.

    -

    Note that its implementation dependant (and also +

    Note that its implementation dependent (and also dependent on mib-storage is used) if a backup is possible.

    diff --git a/lib/snmp/doc/src/snmpa_mpd.xml b/lib/snmp/doc/src/snmpa_mpd.xml index e9294430bd3b..323535260851 100644 --- a/lib/snmp/doc/src/snmpa_mpd.xml +++ b/lib/snmp/doc/src/snmpa_mpd.xml @@ -4,7 +4,7 @@
    - 19992020 + 19992022 Ericsson AB. All Rights Reserved. @@ -170,7 +170,7 @@ To is a list of destination addresses and their corresponding security parameters. This value is received in the same message from the agent and then transformed - trough process_taddrs + through process_taddrs before passed to this function.

    diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index bb0826f2cec4..880785151880 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -130,7 +130,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv

    During the start of a system, when a client application could start prior to the SNMP manager but is dependent - upon it, and therefor has to wait for it to start.

    + upon it, and therefore has to wait for it to start.

    When the SNMP manager has crashed, the dependent client @@ -558,59 +558,10 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1

    For SnmpInfo, see the user callback function handle_report.

    - - - async_get2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason} async_get2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason} @@ -649,49 +600,10 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 for this request, they override any configuration done when the agent was registered.

    -
    - - sync_get_next2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason} sync_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason} @@ -742,50 +654,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1

    For SnmpInfo, see the user callback function handle_report.

    - - - -
    - - async_get_next2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason} @@ -822,48 +693,10 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 for this request, they override any configuration done when the agent was registered.

    -
    - - sync_set2(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason} sync_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason} @@ -917,52 +750,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1

    For SnmpInfo, see the user callback function handle_report.

    - - - -
    - - async_set2(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason} @@ -1004,48 +794,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 for this request, they override any configuration done when the agent was registered.

    - - - -
    - - sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason} @@ -1099,52 +850,10 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1

    For SnmpInfo, see the user callback function handle_report.

    -
    - - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason} async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, ReqId} | {error, Reason} @@ -1182,49 +891,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 for this request, they override any configuration done when the agent was registered.

    - - - -
    - - cancel_async_request(UserId, ReqId) -> ok | {error, Reason} @@ -1274,7 +943,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 LogName defaults to "snmpm_log". LogFile defaults to "snmpm.log".

    The Block argument indicates if the log should be blocked - during conversion. This could be usefull when converting large + during conversion. This could be useful when converting large logs (when otherwise the log could wrap during conversion). Defaults to true.

    See snmp:log_to_txt @@ -1316,7 +985,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 LogName defaults to "snmpm_log". LogFile defaults to "snmpm.log".

    The Block argument indicates if the log should be blocked - during conversion. This could be usefull when converting large + during conversion. This could be useful when converting large logs (when otherwise the log could wrap during conversion). Defaults to true.

    See snmp:log_to_io @@ -1465,7 +1134,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 Reason = term() -

    Retreive the type (asn1 bertype) of an oid.

    +

    Retrieve the type (asn1 bertype) of an oid.

    @@ -1527,7 +1196,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1

    Restart the indicated process (Ref). Note that its not - without risk to restart a process, and should therefor be used + without risk to restart a process, and should therefore be used with care.

    @@ -1558,9 +1227,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1 handle_error user callback function.

    -

    Prefix should either be an indention string +

    Prefix should either be an indentation string (e.g. a list of spaces) or a positive integer (which will be used - to create the indention string of that length).

    + to create the indentation string of that length).

    diff --git a/lib/snmp/doc/src/structure.fig b/lib/snmp/doc/src/structure.fig index c7feff6f4789..c50a5b74b350 100644 --- a/lib/snmp/doc/src/structure.fig +++ b/lib/snmp/doc/src/structure.fig @@ -30,7 +30,7 @@ Inches 2400 900 8625 900 8625 6000 2400 6000 2400 900 2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 8625 6000 8625 6000 8625 6000 8625 6000 8625 6000 -4 0 -1 0 0 0 12 0.0000 4 135 1230 3525 3000 Assosiacition file\001 +4 0 -1 0 0 0 12 0.0000 4 135 1230 3525 3000 Association file\001 4 0 -1 0 0 0 12 0.0000 4 180 990 3750 1575 SNMP Agent\001 4 0 -1 0 0 0 12 0.0000 4 135 345 4050 1950 MIB\001 4 0 -1 0 0 0 12 0.0000 4 180 1080 3075 4275 snmp_local_db\001 diff --git a/lib/snmp/examples/ex1/Makefile b/lib/snmp/examples/ex1/Makefile index a3d02ea77826..b4e7c7f2dd95 100644 --- a/lib/snmp/examples/ex1/Makefile +++ b/lib/snmp/examples/ex1/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -67,7 +67,7 @@ TARGET_FILES= \ # Targets # ---------------------------------------------------- -debug opt: build +$(TYPES): build clean: rm -f $(TARGET_FILES) diff --git a/lib/snmp/examples/ex2/Makefile b/lib/snmp/examples/ex2/Makefile index 624a1df2eef6..f0f652af7416 100644 --- a/lib/snmp/examples/ex2/Makefile +++ b/lib/snmp/examples/ex2/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2006-2016. All Rights Reserved. +# Copyright Ericsson AB 2006-2022. 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. @@ -65,11 +65,25 @@ TARGET_FILES= \ $(ERL_FILES:%.erl=%.$(EMULATOR)) +DIA_PLT = snmp_example_ex2.plt +DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis +ifeq ($(DIAW_EH),true) +DIA_WARNINGS += -Werror_handling +endif +ifeq ($(DIAW_US),true) +DIA_WARNINGS += -Wunderspecs +endif +ifeq ($(DIAW_UR),true) +DIA_WARNINGS += -Wunmatched_returns +endif +DIA_PLT_APPS = erts kernel stdlib crypto mnesia runtime_tools compiler + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug opt: build +$(TYPES): build clean: rm -f $(TARGET_FILES) @@ -80,6 +94,28 @@ docs: build: $(TARGET_FILES) +dclean: + rm -f $(DIA_PLT) + rm -f $(DIA_ANALYSIS) + +dialyzer_plt: $(DIA_PLT) + +$(DIA_PLT): $(ERL_FILES) + @echo "Building ($(basename $(DIA_PLT))) plt file" + @dialyzer --build_plt \ + --output_plt $@ \ + --apps $(sort snmp $(DIA_PLT_APPS)) \ + --output $(DIA_ANALYSIS) \ + --verbose + +dialyzer: $(DIA_PLT) + @echo "Running dialyzer on snmp example ex2" + @dialyzer --plt $< \ + $(ERL_TOP)/lib/snmp/examples/ex2 \ + $(DIA_WARNINGS) \ + --verbose + + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/snmp/examples/ex2/snmp_ex2_manager.erl b/lib/snmp/examples/ex2/snmp_ex2_manager.erl index b3faa54a15dc..43f585f026cc 100644 --- a/lib/snmp/examples/ex2/snmp_ex2_manager.erl +++ b/lib/snmp/examples/ex2/snmp_ex2_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -133,12 +133,7 @@ write_config(Dir, Conf) -> end. start_manager(Opts) -> - case snmpm:start_link(Opts) of - ok -> - ok; - Error -> - error({failed_starting_manager, Error}) - end. + ok = snmpm:start_link(Opts). register_user() -> case snmpm:register_user(?USER, ?USER_MOD, self()) of @@ -397,16 +392,16 @@ handle_pdu(TargetName, ReqId, SnmpResponse, Server) when is_pid(Server) -> handle_trap(TargetName, SnmpTrap, Server) when is_pid(Server) -> report_callback(Server, handle_trap, {TargetName, SnmpTrap}), - ok. + ignore. handle_inform(TargetName, SnmpInform, Server) when is_pid(Server) -> report_callback(Server, handle_inform, {TargetName, SnmpInform}), - ok. + ignore. handle_report(TargetName, SnmpReport, Server) when is_pid(Server) -> report_callback(Server, handle_inform, {TargetName, SnmpReport}), - ok. + ignore. handle_invalid_result(In, Out, Server) when is_pid(Server) -> report_callback(Server, handle_invalid_result, {In, Out}), diff --git a/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl b/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl index e8f748c337fe..181a78952920 100644 --- a/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl +++ b/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2016. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -246,34 +246,32 @@ verify_vbs([Vb|T], NameAndTypes, Acc) -> Acc2 = lists:flatten(io_lib:format("~s~n ~s", [Acc, Val])), verify_vbs(T, NameAndTypes, Acc2). -verify_vb(#varbind{oid = Oid, variabletype = Type, value = Val} = Vb, - NameAndTypes) -> +verify_vb(#varbind{oid = Oid} = Vb, NameAndTypes) -> case lists:reverse(Oid) of [0|RevOid] -> - case snmp_ex2_manager:oid_to_name(lists:reverse(RevOid)) of - {ok, Name} -> - case lists:keysearch(Name, 1, NameAndTypes) of - {value, {Name, Type}} -> - Val; - {value, {Name, WrongType}} -> - error({wrong_type, {WrongType, Vb}}); - false -> - error({unexpected_name, {Name, Vb}}) - end; - {error, Reason} -> - error({unexpected_oid, {Reason, Vb}}) - end; + verify_vb_value(lists:reverse(RevOid), Vb, NameAndTypes); _ -> - case lists:keysearch(Oid, 1, NameAndTypes) of - {value, {Oid, Type}} -> - Val; - {value, {Oid, WrongType}} -> - error({wrong_type, {WrongType, Vb}}); - false -> - error({unexpected_oid, Vb}) - end + verify_vb_value(Oid, Vb, NameAndTypes) end. +verify_vb_value(Oid, + #varbind{variabletype = Type, value = Val} = Vb, + NameAndTypes) -> + case snmp_ex2_manager:oid_to_name(Oid) of + {ok, Name} -> + case lists:keysearch(Name, 1, NameAndTypes) of + {value, {Name, Type}} -> + Val; + {value, {Name, WrongType}} -> + error({wrong_type, {WrongType, Vb}}); + false -> + error({unexpected_name, {Name, Vb}}) + end; + {error, Reason} -> + error({unexpected_oid, {Reason, Vb}}) + end. + + std_mib(MibName) -> j(std_dir(), MibName). diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in index 6419009a6a82..428587617f96 100644 --- a/lib/snmp/mibs/Makefile.in +++ b/lib/snmp/mibs/Makefile.in @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -127,7 +127,7 @@ endif # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src $(gen_verbose)$(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@ diff --git a/lib/snmp/priv/conf/agent/Makefile b/lib/snmp/priv/conf/agent/Makefile index e905f55999d5..7e8f4ef6c63e 100644 --- a/lib/snmp/priv/conf/agent/Makefile +++ b/lib/snmp/priv/conf/agent/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -44,7 +44,7 @@ include files.mk # Targets # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/snmp/priv/conf/manager/Makefile b/lib/snmp/priv/conf/manager/Makefile index 27024c171fd8..0659b900eb45 100644 --- a/lib/snmp/priv/conf/manager/Makefile +++ b/lib/snmp/priv/conf/manager/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2016. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -44,7 +44,7 @@ include files.mk # Targets # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/snmp/src/agent/Makefile b/lib/snmp/src/agent/Makefile deleted file mode 100644 index 1da0f33c9d06..000000000000 --- a/lib/snmp/src/agent/Makefile +++ /dev/null @@ -1,163 +0,0 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode - -# %CopyrightBegin% -# -# Copyright Ericsson AB 1996-2021. 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% - -include $(ERL_TOP)/make/target.mk - -EBIN = ../../ebin - -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../../vsn.mk - -VSN = $(SNMP_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN) - - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- - -include modules.mk - -ERL_FILES = $(BEHAVIOUR_MODULES:%=%.erl) $(MODULES:%=%.erl) - -HRL_FILES = $(INTERNAL_HRL_FILES:%=%.hrl) - -BEHAVIOUR_TARGET_FILES = $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) -TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) - - -# ---------------------------------------------------- -# SNMP FLAGS -# ---------------------------------------------------- -ifeq ($(SNMP_DEFAULT_VERBOSITY),) - SNMP_FLAGS = -Ddefault_verbosity=silence -else - SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY) -endif - -# ifeq ($(SNMP_DEBUG),) -# SNMP_DEBUG = d -# endif - -ifeq ($(SNMP_DEBUG),d) - SNMP_FLAGS += -Dsnmp_debug -endif - -ifeq ($(SNMP_QC),true) - SNMP_FLAGS += -Dsnmp_qc -endif - -ifeq ($(SNMP_EXT_VERBOSITY),true) - SNMP_FLAGS += -Dsnmp_extended_verbosity -endif - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin - -ifeq ($(SNMP_WARNING_AS_ERROR),) - ERL_COMPILE_FLAGS += -Werror -else - ifeq ($(SNMP_WARNING_AS_ERROR),true) - ERL_COMPILE_FLAGS += -Werror - endif -endif - -ifeq ($(WARN_UNUSED_VARS),) - ERL_COMPILE_FLAGS += +warn_unused_vars -else - ifeq ($(WARN_UNUSED_VARS),true) - ERL_COMPILE_FLAGS += +warn_unused_vars - endif -endif - -ERL_COMPILE_FLAGS += -I../../include \ - -I../misc \ - -Dversion=\"$(VSN)$(PRE_VSN)\" \ - +'{parse_transform,sys_pre_attributes}' \ - +'{attribute,insert,app_vsn,$(APP_VSN)}' \ - -I$(ERL_TOP)/lib/stdlib \ - $(SNMP_FLAGS) - - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug: - @$(MAKE) TYPE=debug opt - -opt: - @$(MAKE) behaviour_targets - @$(MAKE) targets - -behaviour_targets: $(BEHAVIOUR_TARGET_FILES) - -targets: $(TARGET_FILES) - - -clean: - rm -f $(BEHAVIOUR_TARGET_FILES) - rm -f $(TARGET_FILES) - rm -f core *~ - -docs: - -info: - @echo "SNMP_FLAGS: $(SNMP_FLAGS)" - @echo "ERL_COMPILE_FLAGS: $(ERL_COMPILE_FLAGS)" - @echo "" - @echo "BEHAVIOUR_TARGET_FILES: $(BEHAVIOUR_TARGET_FILES)" - @echo "TARGET_FILES: $(TARGET_FILES)" - @echo "" - - -# ---------------------------------------------------- -# Special Build Targets -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) "$(RELSYSDIR)/src" - $(INSTALL_DIR) "$(RELSYSDIR)/src/agent" - $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/agent" - $(INSTALL_DIR) "$(RELSYSDIR)/ebin" - $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \ - "$(RELSYSDIR)/ebin" -# $(INSTALL_DIR) "$(RELSYSDIR)/include" -# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include" - -release_docs_spec: - -include depend.mk diff --git a/lib/snmp/src/agent/Makefile.in b/lib/snmp/src/agent/Makefile.in new file mode 100644 index 000000000000..6ab9ed437a3f --- /dev/null +++ b/lib/snmp/src/agent/Makefile.in @@ -0,0 +1,173 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2022. 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% + +include $(ERL_TOP)/make/target.mk + +EBIN = ../../ebin + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk + +VSN = $(SNMP_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN) + + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +ERL_FILES = $(BEHAVIOUR_MODULES:%=%.erl) $(MODULES:%=%.erl) + +HRL_FILES = $(INTERNAL_HRL_FILES:%=%.hrl) + +BEHAVIOUR_TARGET_FILES = $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR)) +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + + +# ---------------------------------------------------- +# SNMP FLAGS +# ---------------------------------------------------- +ifeq ($(SNMP_DEFAULT_VERBOSITY),) + SNMP_FLAGS = -Ddefault_verbosity=silence +else + SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY) +endif + +# ifeq ($(SNMP_DEBUG),) +# SNMP_DEBUG = d +# endif + +ifeq ($(SNMP_DEBUG),d) + SNMP_FLAGS += -Dsnmp_debug +endif + +ifeq ($(SNMP_QC),true) + SNMP_FLAGS += -Dsnmp_qc +endif + +ifeq ($(SNMP_EXT_VERBOSITY),true) + SNMP_FLAGS += -Dsnmp_extended_verbosity +endif + +SNMP_EMPTY_PDU_SIZE_DEFAULT = @SNMP_EMPTY_PDU_SIZE_DEFAULT@ + +# SNMP_EMPTY_PDU_SIZE=42 +ifneq ($(SNMP_EMPTY_PDU_SIZE),) + SNMP_FLAGS += -Dempty_pdu_size=$(SNMP_EMPTY_PDU_SIZE) +else + SNMP_FLAGS += -Dempty_pdu_size=$(SNMP_EMPTY_PDU_SIZE_DEFAULT) +endif + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin + +ifeq ($(SNMP_WARNING_AS_ERROR),) + ERL_COMPILE_FLAGS += -Werror +else + ifeq ($(SNMP_WARNING_AS_ERROR),true) + ERL_COMPILE_FLAGS += -Werror + endif +endif + +ifeq ($(WARN_UNUSED_VARS),) + ERL_COMPILE_FLAGS += +warn_unused_vars +else + ifeq ($(WARN_UNUSED_VARS),true) + ERL_COMPILE_FLAGS += +warn_unused_vars + endif +endif + +ERL_COMPILE_FLAGS += -I../../include \ + -I../misc \ + -Dversion=\"$(VSN)$(PRE_VSN)\" \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,$(APP_VSN)}' \ + -I$(ERL_TOP)/lib/stdlib \ + $(SNMP_FLAGS) + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt + +opt: + @$(MAKE) behaviour_targets + @$(MAKE) targets + +behaviour_targets: $(BEHAVIOUR_TARGET_FILES) + +targets: $(TARGET_FILES) + + +clean: + rm -f $(BEHAVIOUR_TARGET_FILES) + rm -f $(TARGET_FILES) + rm -f core *~ + +docs: + +info: + @echo "SNMP_FLAGS: $(SNMP_FLAGS)" + @echo "ERL_COMPILE_FLAGS: $(ERL_COMPILE_FLAGS)" + @echo "" + @echo "BEHAVIOUR_TARGET_FILES: $(BEHAVIOUR_TARGET_FILES)" + @echo "TARGET_FILES: $(TARGET_FILES)" + @echo "" + + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) "$(RELSYSDIR)/src" + $(INSTALL_DIR) "$(RELSYSDIR)/src/agent" + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src/agent" + $(INSTALL_DIR) "$(RELSYSDIR)/ebin" + $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \ + "$(RELSYSDIR)/ebin" +# $(INSTALL_DIR) "$(RELSYSDIR)/include" +# $(INSTALL_DATA) $(EXT_HRL_FILES) "$(RELSYSDIR)/include" + +release_docs_spec: + +include depend.mk diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk index 39c9aca1cd9d..32df6a9a9bb7 100644 --- a/lib/snmp/src/agent/modules.mk +++ b/lib/snmp/src/agent/modules.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2019. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -41,9 +41,9 @@ MIB_MODULES = \ snmp_view_based_acm_mib # snmpa is "plain" interface module but also defines some agent specific types -# and therefor must be compiled before the modules that use them, including +# and therefore must be compiled before the modules that use them, including # the behaviour modules... -# Some of the MIB modules also define types used elsewhere and therefor +# Some of the MIB modules also define types used elsewhere and therefore # has to be built before the other mods. # snmpa_mib_data_ttln MODULES = \ diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl index 5db686d29bb2..3f2179c11e09 100644 --- a/lib/snmp/src/agent/snmp_framework_mib.erl +++ b/lib/snmp/src/agent/snmp_framework_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -474,7 +474,7 @@ delete_context(Key) -> %%----------------------------------------------------------------- %% Instrumentation functions -%% Retreive functions are also used internally by the agent, so +%% Retrieve functions are also used internally by the agent, so %% don't change the interface without changing those functions. %% Note that if these functions implementations are changed, %% an error can make the agent crash, as no error detection is diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl index 429f78abd0e4..6419503322e0 100644 --- a/lib/snmp/src/agent/snmp_generic.erl +++ b/lib/snmp/src/agent/snmp_generic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2019. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -134,7 +134,7 @@ table_max_col(NameDb, Col) -> % ret largest element in Col %%------------------------------------------------------------------ -%% Theses functions could be in the MIB for simple +%% These functions could be in the MIB for simple %% variables or tables, i.e. vars without complex %% set-operations. If there are complex set op, an %% extra layer-function should be added, and that @@ -566,7 +566,7 @@ table_create_rest(Col, Max, StatusCol, Status, Cols, NoAccs) when Col =< Max-> %% Defs is a list of {Col, DefVal}, in Column order. %% Returns a new row (a list of values) with the same values as %% InitRow, except if InitRow has value noinit in a column, and -%% the corresponing Col has a DefVal in Defs, then the DefVal +%% the corresponding Col has a DefVal in Defs, then the DefVal %% will be the new value. %%------------------------------------------------------------------ table_defaults(InitRow, Defs) -> table_defaults(InitRow, 1, Defs). diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl index 131b9b0368c7..37bf23a5b6b8 100644 --- a/lib/snmp/src/agent/snmp_generic_mnesia.erl +++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -37,7 +37,7 @@ %%%----------------------------------------------------------------- %%------------------------------------------------------------------ -%% Theses functions could be in the MIB for simple +%% These functions could be in the MIB for simple %% variables or tables, i.e. vars without complex %% set-operations. If there are complex set op, an %% extra layer-function should be added, and that @@ -185,8 +185,8 @@ make_row2(RowList, 1) -> RowList; make_row2([_OtherIndex | RowList], N) -> make_row2(RowList, N-1). -make_row_list(Row) -> - make_row_list(size(Row), Row, []). +make_row_list(Row) when is_tuple(Row) -> + make_row_list(tuple_size(Row), Row, []). make_row_list(N, Row, Acc) when N > 2 -> make_row_list(N-1, Row, [element(N, Row) | Acc]); make_row_list(2, Row, Acc) -> diff --git a/lib/snmp/src/agent/snmp_index.erl b/lib/snmp/src/agent/snmp_index.erl index 38b39a9b7ea3..fd2f1c84159a 100644 --- a/lib/snmp/src/agent/snmp_index.erl +++ b/lib/snmp/src/agent/snmp_index.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -155,7 +155,7 @@ is_snmp_type(_) -> false. key_to_oid_i(Key, _Type) when is_integer(Key) -> [Key]; key_to_oid_i(Key, fix_string) -> Key; key_to_oid_i(Key, _Type) when is_list(Key) -> [length(Key) | Key]; -key_to_oid_i(Key, Types) -> keys_to_oid(size(Key), Key, [], Types). +key_to_oid_i(Key, Types) when is_tuple(Key) -> keys_to_oid(tuple_size(Key), Key, [], Types). keys_to_oid(0, _Key, Oid, _Types) -> Oid; keys_to_oid(N, Key, Oid, Types) -> diff --git a/lib/snmp/src/agent/snmp_shadow_table.erl b/lib/snmp/src/agent/snmp_shadow_table.erl index f9181f70a724..12aa65921354 100644 --- a/lib/snmp/src/agent/snmp_shadow_table.erl +++ b/lib/snmp/src/agent/snmp_shadow_table.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -93,9 +93,9 @@ update(Name, UpdateFunc, Interval) -> %% Args: Extra = {Name, SnmpKey, Attributes, Interval, UpdateFunc} %% Purpose: Instrumentation function for the table. %% Name is the name of the table -%% SnmpKey is the snmpkey as it should be specifed in order +%% SnmpKey is the snmpkey as it should be specified in order %% to create the Mnesia table as an SNMP table -%% Attributes is the attributes as it should be specifed in order +%% Attributes is the attributes as it should be specified in order %% to create the Mnesia table as an SNMP table %% Interval is the minimum time in milliseconds between two %% updates of the table diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index 22fd3acb84de..30a3f087494e 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2019. All Rights Reserved. +%% Copyright Ericsson AB 1998-2022. 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. @@ -595,7 +595,7 @@ get_target_addr({Tab, mnesia}, Key) -> snmpTargetAddrRowStatus = ?'RowStatus_active'}} -> case get_target_params(Params) of undefined -> - config_err("Failed retreiving target params [~p]" + config_err("Failed retrieving target params [~p]" "~n for ~p [~p]", [Params, Key, TAddress]), {error, {not_found, {target_params, Key, Params}}}; TargetParams -> @@ -612,7 +612,7 @@ get_target_addr(TabDb, Key) -> _Storage, ?'RowStatus_active', _TargetEngineId,_TMask,_MMS} -> case get_target_params(Params) of undefined -> - config_err("Failed retreiving target params [~p]" + config_err("Failed retrieving target params [~p]" "~n for target ~p [~p]", [Params, Key, TAddress]), {error, {not_found, {target_params, Key, Params}}}; diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl index 0b94f4604a6e..e75cb7c5ce37 100644 --- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl +++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl @@ -830,7 +830,7 @@ validate_set(Error, _RowIndex, _Cols) -> %%----------------------------------------------------------------- %% Here's the alg: If this is the first time the CloneFrom is written, %% we must check that the CloneFrom row exists, so we can invoke the -%% clone process in the set phase. Otherwise, the set succed, with +%% clone process in the set phase. Otherwise, the set succeed, with %% no further checks. %%----------------------------------------------------------------- validate_clone_from(RowIndex, Cols) -> @@ -902,7 +902,7 @@ validate_auth_protocol(RowIndex, Cols) -> %% now; set is ok if new protocol is usmNoAuthProtocol case AuthProtocol of ?usmNoAuthProtocol -> - %% Check that the Priv protocl is noPriv + %% Check that the Priv protocol is noPriv case get_priv_proto(RowIndex, Cols) of ?usmNoPrivProtocol -> ok; _ -> inconsistentValue(?usmUserAuthProtocol) @@ -928,7 +928,7 @@ validate_auth_protocol(RowIndex, Cols) -> %% hash function. case AuthProtocol of ?usmNoAuthProtocol -> - %% Check that the Priv protocl is noPriv + %% Check that the Priv protocol is noPriv case get_priv_proto(RowIndex, Cols) of ?usmNoPrivProtocol -> ok; _ -> inconsistentValue(?usmUserAuthProtocol) diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl index a5a65d9326a2..6fcd92bf03a1 100644 --- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl +++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2019. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -285,7 +285,7 @@ delete_sec2group(Key) -> {error, delete_failed} end. -%% NOTE: This function must be used in conjuction with +%% NOTE: This function must be used in conjunction with %% snmpa_vacm:dump_table. %% That is, when all access has been added, call %% snmpa_vacm:dump_table/0 @@ -357,7 +357,7 @@ init_vacm_mnesia() -> %% The 5 is intentional: It is a trick to get a tuple with the %% columns needed by the vacm ets-table (corresponding to the - %% tuple read from the config files). Therefor, 5 since it it + %% tuple read from the config files). Therefore, 5 since it it %% is not a real foi... snmp_generic:table_foreach({vacmAccessTable, mnesia}, F, 5). @@ -1048,7 +1048,7 @@ imask2emask(IMask) -> imask2emask([], EMask) -> lists:reverse(EMask); imask2emask(IMask, EMask) -> - %% Make sure we have atleast 8 bits + %% Make sure we have at least 8 bits %% (maybe extend with 1's) IMask2 = case length(IMask) of diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index 995e6d627da3..74205e5716f5 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -149,6 +149,11 @@ %% Options specific to the above module -type mib_storage_options() :: list(). +-type mib_module() :: atom(). +-type table_name() :: atom(). +-type variable_name() :: atom(). +-type mib_info() :: {mib_module(), [table_name()], [variable_name()]}. + %%----------------------------------------------------------------- %% This utility function is used to convert an old SNMP application @@ -340,11 +345,11 @@ unload_mib(Agent, Mib) -> end. unload_mibs(Mibs) -> - unload_mibs(snmp_master_agent, Mibs, false). + unload_mibs(snmp_master_agent, Mibs). unload_mibs(Agent, Mibs) when is_list(Mibs) -> - snmpa_agent:unload_mibs(Agent, Mibs); + unload_mibs(Agent, Mibs, false); unload_mibs(Mibs, Force) - when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + when is_list(Mibs) andalso is_boolean(Force) -> unload_mibs(snmp_master_agent, Mibs, Force). -spec unload_mibs(Agent :: pid() | atom(), @@ -353,7 +358,7 @@ unload_mibs(Mibs, Force) ok | {error, {'unload aborted at', MibName :: string(), InternalReason :: not_loaded | term()}}. unload_mibs(Agent, Mibs, Force) - when is_list(Mibs) andalso ((Force =:= true) orelse (Force =:= false)) -> + when is_list(Mibs) andalso is_boolean(Force) -> snmpa_agent:unload_mibs(Agent, Mibs, Force). @@ -369,6 +374,8 @@ whereis_mib(Agent, Mib) when is_atom(Mib) -> %% - +-spec mibs_info() -> [mib_info()]. + mibs_info() -> [ {snmp_standard_mib, diff --git a/lib/snmp/src/agent/snmpa_acm.erl b/lib/snmp/src/agent/snmpa_acm.erl index de67df8a06f0..74efae4ad53a 100644 --- a/lib/snmp/src/agent/snmpa_acm.erl +++ b/lib/snmp/src/agent/snmpa_acm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -234,7 +234,7 @@ invalidate_ca_cache() -> %%----------------------------------------------------------------- %% NOTE: The do_get MUST be executed in the Master agents's -%% context. Therefor, force master-agent to do a GET to +%% context. Therefore, force master-agent to do a GET to %% retrieve the value for snmpEnableAuthenTraps. %% A user may have another impl. than default for this %% variable. diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 3b73132906ca..8c24440efc59 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -65,18 +65,11 @@ -export([increment_counter/3]). -export([restart_worker/1, restart_set_worker/1, restart_notif_worker/1]). -%% For backward compatibillity --export([send_trap/6, send_trap/7]). - %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, tr_var/2, tr_varbind/1, handle_pdu/8, worker/4, worker_loop/2, do_send_trap/7, do_send_trap/8]). -%% --export([handle_pdu/7, - load_mibs/2, unload_mibs/2]). -%% -include("snmpa_internal.hrl"). @@ -84,8 +77,6 @@ -define(default_verbosity,silence). -endif. --define(empty_pdu_size, 21). - -ifdef(snmp_extended_verbosity). -define(vt(F,A), ?vtrace(F, A)). -else. @@ -510,29 +501,6 @@ start_mib_server(Prio, Ref, Mibs, Options) -> end. -%%----------------------------------------------------------------- -%% Purpose: We must calculate the length of an empty Pdu. This -%% length is used to calculate the max pdu size allowed -%% for each get-bulk-request. This size is -%% dependent on the varbinds. It is calculated -%% as EmptySize + 8. 8 comes from the fact that the -%% maximum pdu size needs 31 bits which needs 5 * 7 bits to be -%% expressed. One 7bit octet is already present in the -%% empty pdu, leaving 4 more 7bit octets. The length is -%% repeated twice, once for the varbinds, and once for the -%% entire pdu; 2 * 4 = 8. -%% Actually, this function is not used, we use a constant instead. -%%----------------------------------------------------------------- -%% Ret: 21 -%% empty_pdu() -> -%% Pdu = #pdu{type = 'get-response', -%% request_id = 1, -%% error_status = noError, -%% error_index = 0, -%% varbinds = []}, -%% length(snmp_pdus:enc_pdu(Pdu)) + 8. - - %%%-------------------------------------------------- %%% 1. Interface %%%-------------------------------------------------- @@ -578,21 +546,9 @@ subagent_set(SubAgent, Arguments) -> call(SubAgent, {subagent_set, Arguments, PduData}). -%% Called by administrator (not agent; deadlock would occur) -%% -load_mibs(Agent, Mibs) -> - load_mibs(Agent, Mibs, false). -%% - load_mibs(Agent, Mibs, Force) -> call(Agent, {load_mibs, Mibs, Force}). -%% Called by administrator (not agent; deadlock would occur) -%% -unload_mibs(Agent, Mibs) -> - unload_mibs(Agent, Mibs, false). -%% - unload_mibs(Agent, Mibs, Force) -> call(Agent, {unload_mibs, Mibs, Force}). @@ -641,51 +597,6 @@ send_notification(Agent, Notification, SendOpts) -> Msg = {send_notif, Notification, SendOpts}, maybe_call(Agent, Msg). -%% -send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) -> - ?d("send_trap -> entry with" - "~n self(): ~p" - "~n Agent: ~p [~p]" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n CtxName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p", - [self(), Agent, wis(Agent), - Trap, NotifyName, CtxName, Recv, Varbinds]), - SendOpts = [ - {receiver, Recv}, - {varbinds, Varbinds}, - {name, NotifyName}, - {context, CtxName}, - {extra, ?DEFAULT_NOTIF_EXTRA_INFO} - ], - send_notification(Agent, Trap, SendOpts). - -send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID) -> - ?d("send_trap -> entry with" - "~n self(): ~p" - "~n Agent: ~p [~p]" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n CtxName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p" - "~n LocalEngineID: ~p", - [self(), Agent, wis(Agent), - Trap, NotifyName, CtxName, Recv, Varbinds, LocalEngineID]), - SendOpts = [ - {receiver, Recv}, - {varbinds, Varbinds}, - {name, NotifyName}, - {context, CtxName}, - {extra, ?DEFAULT_NOTIF_EXTRA_INFO}, - {local_engine_id, LocalEngineID} - ], - send_notification(Agent, Trap, SendOpts). - -%% - %% -- Discovery functions -- @@ -882,51 +793,6 @@ handle_info({send_notif, Notification, SendOpts}, S) -> {noreply, S} end; -%% -handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, S) -> - ?vlog("[handle_info] send trap request:" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p", - [Trap, NotifyName, ContextName, Recv, Varbinds]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - LocalEngineID = local_engine_id(S), - case (catch handle_send_trap(S, Trap, NotifyName, ContextName, - Recv, Varbinds, LocalEngineID, ExtraInfo)) of - {ok, NewS} -> - {noreply, NewS}; - {'EXIT', R} -> - ?vinfo("Trap not sent:~n ~p", [R]), - {noreply, S}; - _ -> - {noreply, S} - end; - -handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds, - LocalEngineID}, S) -> - ?vlog("[handle_info] send trap request:" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p" - "~n LocalEngineID: ~p", - [Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - case (catch handle_send_trap(S, Trap, NotifyName, ContextName, - Recv, Varbinds, LocalEngineID, ExtraInfo)) of - {ok, NewS} -> - {noreply, NewS}; - {'EXIT', R} -> - ?vinfo("Trap not sent:~n ~p", [R]), - {noreply, S}; - _ -> - {noreply, S} - end; -%% - handle_info({forward_trap, TrapRecord, NotifyName, ContextName, Recv, Varbinds, ExtraInfo}, S) -> ?vlog("[handle_info] forward trap request:" @@ -948,30 +814,6 @@ handle_info({forward_trap, TrapRecord, NotifyName, ContextName, {noreply, S} end; -%% -handle_info({forward_trap, TrapRecord, NotifyName, ContextName, - Recv, Varbinds}, S) -> - ?vlog("[handle_info] forward trap request:" - "~n TrapRecord: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p", - [TrapRecord, NotifyName, ContextName, Recv, Varbinds]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - LocalEngineID = ?DEFAULT_LOCAL_ENGINE_ID, - case (catch maybe_send_trap(S, TrapRecord, NotifyName, ContextName, - Recv, Varbinds, LocalEngineID, ExtraInfo)) of - {ok, NewS} -> - {noreply, NewS}; - {'EXIT', R} -> - ?vinfo("Trap not sent:~n ~p", [R]), - {noreply, S}; - _ -> - {noreply, S} - end; -%% - handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) -> ?vlog("[handle_info] backup done:" "~n Reply: ~p", [Reply]), @@ -1094,55 +936,6 @@ handle_call({send_notif, Notification, SendOpts}, _From, S) -> {reply, {error, send_failed}, S} end; -%% -handle_call({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, - _From, S) -> - ?vlog("[handle_call] send trap request:" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p", - [Trap, NotifyName, ContextName, Recv, Varbinds]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - LocalEngineID = local_engine_id(S), - case (catch handle_send_trap(S, Trap, NotifyName, ContextName, - Recv, Varbinds, LocalEngineID, ExtraInfo)) of - {ok, NewS} -> - {reply, ok, NewS}; - {'EXIT', Reason} -> - ?vinfo("Trap not sent:~n ~p", [Reason]), - {reply, {error, {send_failed, Reason}}, S}; - _ -> - ?vinfo("Trap not sent", []), - {reply, {error, send_failed}, S} - end; - -handle_call({send_trap, Trap, NotifyName, - ContextName, Recv, Varbinds, LocalEngineID}, - _From, S) -> - ?vlog("[handle_call] send trap request:" - "~n Trap: ~p" - "~n NotifyName: ~p" - "~n ContextName: ~p" - "~n Recv: ~p" - "~n Varbinds: ~p" - "~n LocalEngineID: ~p", - [Trap, NotifyName, ContextName, Recv, Varbinds, LocalEngineID]), - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - case (catch handle_send_trap(S, Trap, NotifyName, ContextName, - Recv, Varbinds, LocalEngineID, ExtraInfo)) of - {ok, NewS} -> - {reply, ok, NewS}; - {'EXIT', Reason} -> - ?vinfo("Trap not sent:~n ~p", [Reason]), - {reply, {error, {send_failed, Reason}}, S}; - _ -> - ?vinfo("Trap not sent", []), - {reply, {error, send_failed}, S} - end; -%% - handle_call({discovery, TargetName, Notification, ContextName, Vbs, DiscoHandler, ExtraInfo}, @@ -1281,22 +1074,10 @@ handle_call({unregister_subagent, SubTreeOid}, _From, S) -> end, {reply, Reply, S}; -%% -handle_call({load_mibs, Mibs}, _From, S) -> - ?vlog("load mibs ~p", [Mibs]), - {reply, snmpa_mib:load_mibs(get(mibserver), Mibs), S}; -%% - handle_call({load_mibs, Mibs, Force}, _From, S) -> ?vlog("[~w] load mibs ~p", [Force, Mibs]), {reply, snmpa_mib:load_mibs(get(mibserver), Mibs, Force), S}; -%% -handle_call({unload_mibs, Mibs}, _From, S) -> - ?vlog("unload mibs ~p", [Mibs]), - {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs), S}; -%% - handle_call({unload_mibs, Mibs, Force}, _From, S) -> ?vlog("[~w] unload mibs ~p", [Force, Mibs]), {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs, Force), S}; @@ -1895,46 +1676,6 @@ worker_loop(Master, Report) -> exit(normal); - - - %% ************************************************************* - %% - %% Kept for backward compatibillity reasons - %% - %% ************************************************************* - - {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> - ?vtrace("worker_loop -> received request", []), - handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, - ?DEFAULT_GB_MAX_VBS, Extra), - Master ! worker_available; - - %% We don't trap exits! - {TrapRec, NotifyName, ContextName, Recv, Vbs} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, get(net_if)), - Master ! worker_available; - - %% We don't trap exits! - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, - ExtraInfo} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo, - get(net_if)), - Master ! worker_available; - - {verbosity, Verbosity} -> - put(verbosity, snmp_verbosity:validate(Verbosity)); - - terminate -> - exit(normal); - _X -> %% ignore ignore_unknown @@ -1991,12 +1732,6 @@ handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) -> S. -%% Called via the spawn_thread function -%% -handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) -> - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra, - Dict). -%% handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), put(sname, pdu_handler_short_name(get(sname))), @@ -2399,7 +2134,7 @@ handle_discovery_response(#state{disco = #disco{target = TargetName, "~n ManagerEngineId: ~p", [TargetName, ManagerEngineId]), %% This is end of stage 1. %% So, first we need to update the database with the EngineId of the - %% manager and then deside if we should continue with stage 2. E.g. + %% manager and then decide if we should continue with stage 2. E.g. %% establish authenticated communication. case snmp_target_mib:set_target_engine_id(TargetName, ManagerEngineId) of true when Disco#disco.sec_level =:= ?'SnmpSecurityLevel_noAuthNoPriv' -> @@ -2792,7 +2527,7 @@ validate_next_v1_2([], _MibView, Res) -> %% column, we'll try to find the next instance. This will be the %% next row in the table, which is a Counter64 value as well. This %% means that we will loop through the entire table, until we find -%% a column that isn't a Counter64 column. We can optimze this by +%% a column that isn't a Counter64 column. We can optimize this by %% adding 1 to the column-no in the oid of this instance. %% If the table is implemented by a subagent this does not help, %% we'll call that subagent many times. But it shouldn't be any diff --git a/lib/snmp/src/agent/snmpa_general_db.erl b/lib/snmp/src/agent/snmpa_general_db.erl index a1e91b2b3c15..306bb79769ad 100644 --- a/lib/snmp/src/agent/snmpa_general_db.erl +++ b/lib/snmp/src/agent/snmpa_general_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2020. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -56,7 +56,7 @@ %% Open or create a database table. In the mnesia/dets case, %% where the table is stored on disc, it could be of interest %% to clear the table. This is controlled by the Action parameter. -%% An empty node list ([]), is traslated into a list containing +%% An empty node list ([]), is translated into a list containing %% only the own node. %% --------------------------------------------------------------- open({mnesia,Nodes,clear}, Name, RecName, Attr, Type) when is_list(Nodes) -> diff --git a/lib/snmp/src/agent/snmpa_get.erl b/lib/snmp/src/agent/snmpa_get.erl index c4f4f4409536..dab90ff14e57 100644 --- a/lib/snmp/src/agent/snmpa_get.erl +++ b/lib/snmp/src/agent/snmpa_get.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2019-2019. All Rights Reserved. +%% Copyright Ericsson AB 2019-2022. 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. @@ -33,6 +33,13 @@ do_get_bulk/7 ]). +%% Debugging +-export([ + empty_pdu/0, empty_pdu/1, + empty_scoped_pdu/0, empty_scoped_pdu/1, + empty_pdu_size/0, empty_scoped_pdu_size/0 + ]). + -define(VMODULE,"GET"). -include("snmpa_internal.hrl"). -include("snmp_types.hrl"). @@ -43,7 +50,9 @@ -define(default_verbosity,silence). -endif. --define(empty_pdu_size, 21). +-ifndef(empty_pdu_size). +-define(empty_pdu_size, 21). % See below! +-endif. -ifdef(snmp_extended_verbosity). -define(vt(F,A), ?vtrace(F, A)). @@ -57,6 +66,80 @@ +%%----------------------------------------------------------------- +%% Purpose: We must calculate the length of an empty Pdu. This +%% length is used to calculate the max pdu size allowed +%% for each get-bulk-request. +%% This size is dependent on the varbinds. +%% It is calculated as EmptySize + 8. 8 comes from the +%% fact that the maximum pdu size needs 31 bits which needs +%% 5 * 7 bits to be expressed. One 7bit octet is already +%% present in the empty pdu, leaving 4 more 7bit octets. +%% The length is repeated twice, once for the varbinds, +%% and once for the entire pdu; 2 * 4 = 8. +%% +%% Actually, this function is not used, we use a constant instead. +%% +%%----------------------------------------------------------------- +%% +%% Some wierdness is going on since this seems to be insufficient, +%% atleast on version 3. +%% One of the issues is that the constant (21) is only correct if +%% request-id < 128 (as is the case in the example below). +%% But adding 8 to this solves the problem => 29 (atleast for the +%% customer reporting the issue). +%% Since it is version 3, should we use the scopedPDU for the +%% calculation? +%% +%%----------------------------------------------------------------- +%% Ret: 21 (see above) +%% empty_pdu_size() -> +%% Pdu = #pdu{type = 'get-response', +%% request_id = 1, +%% error_status = noError, +%% error_index = 0, +%% varbinds = []}, +%% length(snmp_pdus:enc_pdu(Pdu)) + 8. + +empty_pdu() -> + empty_pdu(1). +empty_pdu(RequestId) when is_integer(RequestId) andalso (RequestId > 0) -> + #pdu{type = 'get-response', + request_id = RequestId, + error_status = noError, + error_index = 0, + varbinds = []}. + +%% empty_pdu_size() -> +%% empty_pdu_size(1). +%% empty_pdu_size(RequestId) -> +%% length(snmp_pdus:enc_pdu(empty_pdu(RequestId))) + 8. + +empty_pdu_size() -> + ?empty_pdu_size. + + +%% This is used when calculating how many VBs to include in a pdu. +%% For "some reason" we need to add 8 to the size for version 3. +%% Could be the context EngineID and Name, which is actuall part +%% of the scoped PDU? + +empty_scoped_pdu() -> + empty_scoped_pdu(1). +empty_scoped_pdu(RequestId) -> + #scopedPdu{contextEngineID = "", + contextName = "", + data = empty_pdu(RequestId)}. + +%% empty_scoped_pdu_size() -> +%% empty_scoped_pdu_size(1). +%% empty_scoped_pdu_size(RequestId) -> +%% length(snmp_pdus:enc_scoped_pdu(empty_scoped_pdu(RequestId))) + 8. + +empty_scoped_pdu_size() -> + ?empty_pdu_size + 6. + + %%%----------------------------------------------------------------- %%% 3. GET REQUEST %%% -------------- @@ -143,7 +226,7 @@ do_get_local([], Res, _IsNotification) -> %%----------------------------------------------------------------- %% Func: do_get_subagents/2 %% Purpose: Loop the list of varbinds for different subagents. -%% For each of them, call sub_agent_get to retreive +%% For each of them, call sub_agent_get to retrieve %% the values for them. %% Returns: {noError, 0, ListOfNewVarbinds} | %% {ErrorStatus, ErrorIndex, []} @@ -928,7 +1011,7 @@ validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) -> %%----------------------------------------------------------------- %% Func: get_next_sa/4 %% Purpose: Loop the list of varbinds for the subagent. -%% Call subagent_get_next to retreive +%% Call subagent_get_next to retrieve %% the next varbinds. %% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} | %% {ErrorStatus, ErrorIndex} diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index c9093fcdb92a..2b6588b4124f 100644 --- a/lib/snmp/src/agent/snmpa_local_db.erl +++ b/lib/snmp/src/agent/snmpa_local_db.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2019. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -663,7 +663,7 @@ code_change(_Vsn, State, _Extra) -> %%---------------------------------------------------------- handle_backup(D, BackupDir) -> - %% First check that we do not wrote to the corrent db-dir... + %% First check that we do not wrote to the current db-dir... ?vtrace("handle_backup -> entry with" "~n D: ~p" "~n BackupDir: ~p", [D, BackupDir]), @@ -1031,7 +1031,7 @@ table_get_elements(NameDb, RowIndex, Cols, _FirstOwnIndex) -> get_elements(_Cols, undefined) -> undefined; -get_elements([Col | Cols], Row) when is_tuple(Row) and (size(Row) >= Col) -> +get_elements([Col | Cols], Row) when tuple_size(Row) >= Col -> [element(Col, Row) | get_elements(Cols, Row)]; get_elements([], _Row) -> []; @@ -1215,7 +1215,7 @@ cast(Msg) -> %% ---------------------------------------------------------------- %% DETS wrapper functions -%% The purpose of these fuctions is basically to hide the shadow +%% The purpose of these functions is basically to hide the shadow %% table. %% Changes are made both in dets and in the shadow table. %% Reads are made from the shadow table. diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl index fe98fc25852c..23d546889789 100644 --- a/lib/snmp/src/agent/snmpa_mib.erl +++ b/lib/snmp/src/agent/snmpa_mib.erl @@ -47,11 +47,6 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -%% --export([load_mibs/2, unload_mibs/2]). -%% - - -include_lib("kernel/include/file.hrl"). -include("snmpa_internal.hrl"). -include("snmp_types.hrl"). @@ -204,11 +199,6 @@ next(MibServer, Oid, MibView) -> %% Returns: ok | {error, Reason} %%---------------------------------------------------------------------- -%% -load_mibs(MibServer, Mibs) -> - load_mibs(MibServer, Mibs, false). -%% - load_mibs(MibServer, Mibs, Force) -> call(MibServer, {load_mibs, Mibs, Force}). @@ -219,10 +209,6 @@ load_mibs(MibServer, Mibs, Force) -> %% Force is a boolean %% Returns: ok | {error, Reason} %%---------------------------------------------------------------------- -%% -unload_mibs(MibServer, Mibs) -> - unload_mibs(MibServer, Mibs, false). -%% unload_mibs(MibServer, Mibs, Force) -> call(MibServer, {unload_mibs, Mibs, Force}). @@ -514,11 +500,6 @@ handle_call({next, Oid, MibView}, _From, ?vdebug("next -> Reply: ~p", [Reply]), {reply, Reply, NewState}; -%% -handle_call({load_mibs, Mibs}, From, State) -> - handle_call({load_mibs, Mibs, false}, From, State); -%% - handle_call({load_mibs, Mibs, Force}, _From, #state{data = Data, teo = TeOverride, @@ -540,11 +521,6 @@ handle_call({load_mibs, Mibs, Force}, _From, Mod:sync(NData), {reply, Reply, State#state{data = NData, cache = NewCache}}; -%% -handle_call({unload_mibs, Mibs}, From, State) -> - handle_call({unload_mibs, Mibs, false}, From, State); -%% - handle_call({unload_mibs, Mibs, Force}, _From, #state{data = Data, teo = TeOverride, diff --git a/lib/snmp/src/agent/snmpa_mib_data_ttln.erl b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl index 959230b1dd32..2b4493d527f7 100644 --- a/lib/snmp/src/agent/snmpa_mib_data_ttln.erl +++ b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -753,7 +753,7 @@ find_node(_D, Node, _RestOfOid, _RevOid) -> %% {subagent, SubAgentPid, SAOid} | %% {variable, MibEntry, VarOid} | %% {table, TableOid, TableRestOid, MibEntry} -%% If a variable is returnes, it is in the MibView. +%% If a variable is returns, it is in the MibView. %% If a table or subagent is returned, it *may* be in the MibView. %%----------------------------------------------------------------- next(#mib_data{tree = T} = D, Oid, MibView) -> @@ -777,10 +777,10 @@ next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) -> next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid], _RevOidSoFar, _MibView) - when Int+1 > size(Tree) -> - ?vtrace("next_node(tree,table_entry) -> entry when not found whith" + when Int+1 > tuple_size(Tree) -> + ?vtrace("next_node(tree,table_entry) -> entry when not found within" "~n Int: ~p" - "~n size(Tree): ~p", [Int, size(Tree)]), + "~n size(Tree): ~p", [Int, tuple_size(Tree)]), false; next_node(D, {tree, Tree, {table_entry, _MibName}}, Oid, RevOidSoFar, MibView) -> @@ -788,7 +788,7 @@ next_node(D, {tree, Tree, {table_entry, _MibName}}, "~n size(Tree): ~p" "~n Oid: ~p" "~n RevOidSoFar: ~p" - "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]), + "~n MibView: ~p", [tuple_size(Tree), Oid, RevOidSoFar, MibView]), OidSoFar = lists:reverse(RevOidSoFar), case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of true -> @@ -809,14 +809,14 @@ next_node(D, {tree, Tree, {table_entry, _MibName}}, end; next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView) - when (Int < size(Tree)) andalso (Int >= 0) -> + when (Int < tuple_size(Tree)) andalso (Int >= 0) -> ?vtrace("next_node(tree) -> entry when" "~n size(Tree): ~p" "~n Int: ~p" "~n RestOfOid: ~p" "~n RevOidSoFar: ~p" "~n MibView: ~p", - [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]), + [tuple_size(Tree), Int, RestOfOid, RevOidSoFar, MibView]), case next_node(D, element(Int+1,Tree), RestOfOid, [Int|RevOidSoFar], MibView) of false -> @@ -830,11 +830,11 @@ next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) -> "~n size(Tree): ~p" "~n RevOidSoFar: ~p" "~n MibView: ~p", - [size(Tree), RevOidSoFar, MibView]), + [tuple_size(Tree), RevOidSoFar, MibView]), find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView); next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) -> ?vtrace("next_node(tree) -> entry when" - "~n size(Tree): ~p", [size(Tree)]), + "~n size(Tree): ~p", [tuple_size(Tree)]), false; next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) -> @@ -896,7 +896,7 @@ next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) -> %% node. %%----------------------------------------------------------------- find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView) - when Idx < size(Tree) -> + when Idx < tuple_size(Tree) -> case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of false -> find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView); diff --git a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl index 9b4493a03f24..39ed23809ef8 100644 --- a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl +++ b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -780,7 +780,7 @@ find_node(_D, Node, _RestOfOid, _RevOid) -> %% {subagent, SubAgentPid, SAOid} | %% {variable, MibEntry, VarOid} | %% {table, TableOid, TableRestOid, MibEntry} -%% If a variable is returnes, it is in the MibView. +%% If a variable is returns, it is in the MibView. %% If a table or subagent is returned, it *may* be in the MibView. %%----------------------------------------------------------------- next(#mib_data{tree = T} = D, Oid, MibView) -> @@ -804,10 +804,10 @@ next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) -> next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid], _RevOidSoFar, _MibView) - when Int+1 > size(Tree) -> - ?vtrace("next_node(tree,table_entry) -> entry when not found whith" + when Int+1 > tuple_size(Tree) -> + ?vtrace("next_node(tree,table_entry) -> entry when not found within" "~n Int: ~p" - "~n size(Tree): ~p", [Int, size(Tree)]), + "~n size(Tree): ~p", [Int, tuple_size(Tree)]), false; next_node(D, {tree, Tree, {table_entry, _MibName}}, Oid, RevOidSoFar, MibView) -> @@ -815,7 +815,7 @@ next_node(D, {tree, Tree, {table_entry, _MibName}}, "~n size(Tree): ~p" "~n Oid: ~p" "~n RevOidSoFar: ~p" - "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]), + "~n MibView: ~p", [tuple_size(Tree), Oid, RevOidSoFar, MibView]), OidSoFar = lists:reverse(RevOidSoFar), case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of true -> @@ -836,14 +836,14 @@ next_node(D, {tree, Tree, {table_entry, _MibName}}, end; next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView) - when (Int < size(Tree)) andalso (Int >= 0) -> + when (Int < tuple_size(Tree)) andalso (Int >= 0) -> ?vtrace("next_node(tree) -> entry when" "~n size(Tree): ~p" "~n Int: ~p" "~n RestOfOid: ~p" "~n RevOidSoFar: ~p" "~n MibView: ~p", - [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]), + [tuple_size(Tree), Int, RestOfOid, RevOidSoFar, MibView]), case next_node(D, element(Int+1,Tree), RestOfOid, [Int|RevOidSoFar], MibView) of false -> @@ -857,11 +857,11 @@ next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) -> "~n size(Tree): ~p" "~n RevOidSoFar: ~p" "~n MibView: ~p", - [size(Tree), RevOidSoFar, MibView]), + [tuple_size(Tree), RevOidSoFar, MibView]), find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView); next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) -> ?vtrace("next_node(tree) -> entry when" - "~n size(Tree): ~p", [size(Tree)]), + "~n size(Tree): ~p", [tuple_size(Tree)]), false; next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) -> @@ -924,7 +924,7 @@ next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) -> %% node. %%----------------------------------------------------------------- find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView) - when Idx < size(Tree) -> + when Idx < tuple_size(Tree) -> case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of false -> find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView); diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl index ecdf968458cc..ad2840a33f9e 100644 --- a/lib/snmp/src/agent/snmpa_mib_lib.erl +++ b/lib/snmp/src/agent/snmpa_mib_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -56,7 +56,7 @@ table_del_row({Tab, Db} = TabDb, Key) -> %%%----------------------------------------------------------------- -%%% Retreives the entire table. Used for debugging +%%% Retrieves the entire table. Used for debugging %%%----------------------------------------------------------------- get_table(NameDb, FOI) -> diff --git a/lib/snmp/src/agent/snmpa_mib_storage.erl b/lib/snmp/src/agent/snmpa_mib_storage.erl index d46dab0be01f..508af51f18d4 100644 --- a/lib/snmp/src/agent/snmpa_mib_storage.erl +++ b/lib/snmp/src/agent/snmpa_mib_storage.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2019. All Rights Reserved. +%% Copyright Ericsson AB 2013-2022. 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. @@ -46,7 +46,7 @@ %% (of the behaviour), this is done using the *Options* argument. %% --------------------------------------------------------------- -%% Options is callback module dependant +%% Options is callback module dependent -callback open(Name :: atom(), RecName :: atom(), diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 0d40840d353e..9c520a707194 100644 --- a/lib/snmp/src/agent/snmpa_mpd.erl +++ b/lib/snmp/src/agent/snmpa_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -28,6 +28,13 @@ process_taddrs/1, generate_req_id/0]). +%% This is just for debugging and testing +-export([ + empty_msg/0, + empty_msg_size/0 + ]). + + -define(SNMP_USE_V3, true). -include("snmp_types.hrl"). -include("SNMP-MPD-MIB.hrl"). @@ -39,7 +46,11 @@ -include("snmp_verbosity.hrl"). -include("snmpa_internal.hrl"). +-ifdef(empty_pdu_size). +-define(empty_msg_size, ?empty_pdu_size + 3). +-else. -define(empty_msg_size, 24). +-endif. -record(state, {v1 = false, v2c = false, v3 = false}). -record(note, {sec_engine_id, @@ -51,9 +62,9 @@ disco = false, req_id}). - + %%%----------------------------------------------------------------- -%%% This module implemets the Message Processing and Dispatch part of +%%% This module implements the Message Processing and Dispatch part of %%% the multi-lingual SNMP agent. %%% %%% The MPD is responsible for: @@ -70,7 +81,7 @@ %%% the counters only, it does not provide instrumentation functions %%% for the counters. %%% -%%% With the terms defined in rfc2271, this module implememts part +%%% With the terms defined in rfc2271, this module implements part %%% of the Dispatcher and the Message Processing functionality. %%%----------------------------------------------------------------- init(Vsns) -> @@ -88,14 +99,13 @@ reset() -> ok. -%%----------------------------------------------------------------- -%% Purpose: We must calculate the length of a -%% message with an empty Pdu, and zero-length community -%% string. This length is used to calculate the max -%% pdu size allowed for each request. This size is -%% dependent on two dynamic fields, the community string -%% and the pdu (varbinds actually). It is calculated -%% as EmptySize + length(CommunityString) + 4. +%%-------------------------------------------------------------------------- +%% Purpose: We must calculate the length of a message with an empty Pdu +%% and zero-length community string. +%% This length is used to calculate the max pdu size allowed for +%% each request. This size is dependent on two dynamic fields; +%% the community string and the pdu (varbinds actually). +%% It is calculated as EmptySize + length(CommunityString) + 4. %% We assume that the length of the CommunityString is %% less than 128 (thus requiring just one octet for the %% length field (the same as the zero-length community @@ -104,13 +114,28 @@ reset() -> %% expressed. One 7bit octet is already present in the %% empty msg, leaving 4 more 7bit octets. %% Actually, this function is not used, we use a constant instead. -%%----------------------------------------------------------------- +%%-------------------------------------------------------------------------- %% Ret: 24 -%empty_msg() -> -% M = #message{version = 'version-1', community = "", data = -% #pdu{type = 'get-response', request_id = 1, -% error_status = noError, error_index = 0, varbinds = []}}, -% length(snmp_pdus:enc_message(M)) + 4. +%%empty_msg() -> +%% M = #message{version = 'version-1', community = "", data = +%% #pdu{type = 'get-response', request_id = 1, +%% error_status = noError, error_index = 0, varbinds = []}}, +%% length(snmp_pdus:enc_message(M)) + 4. + +-ifdef(SNMP_USE_V3). +empty_msg() -> + {message, 'version-1', "", snmpa_get:empty_pdu()}. +-else. +empty_msg() -> + #message{version = 'version-1', + community = "", + data = snmpa_get:empty_pdu()}. +-endif. + +empty_msg_size() -> + ?empty_msg_size. + + %%----------------------------------------------------------------- %% Func: process_packet(Packet, Domain, Address, State, Log) -> @@ -648,7 +673,7 @@ generate_response_msg(Vsn, RePdu, Type, {discarded, Reason}; Packet -> MMS = get_engine_max_message_size(LocalEngineID), - case size(Packet) of + case byte_size(Packet) of Len when Len =< MMS -> Log(Type, Packet), inc_snmp_cnt_vars(Type, RePdu), @@ -717,7 +742,7 @@ generate_response_msg(Vsn, RePdu, Type, %% because of the calculation we do when we %% receive the bulk-request. Packet = list_to_binary(OutMsg), - case size(Packet) of + case byte_size(Packet) of Len when Len =< AgentMS -> if SecLevel =:= 3 -> @@ -907,7 +932,7 @@ generate_msg(Vsn, _NoteStore, Pdu, {community, Community}, LocalEngineID, To) -> {discarded, Reason}; Packet -> AgentMax = get_engine_max_message_size(LocalEngineID), - case size(Packet) of + case byte_size(Packet) of Len when Len =< AgentMax -> {ok, mk_v1_v2_packet_list(To, Packet, Len, Pdu)}; Len -> @@ -1296,7 +1321,7 @@ mk_v3_packet_entry(NoteStore, Domain, Addr, %% Store in cache for 150 sec. Packet = list_to_binary(OutMsg), ?vdebug("mk_v3_packet_entry -> generated: ~w bytes", - [size(Packet)]), + [byte_size(Packet)]), Data = if SecLevel =:= 3 -> @@ -1535,3 +1560,4 @@ user_err(F, A) -> config_err(F, A) -> snmpa_error:config_err(F, A). + diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index 2c4ca5ce37b9..56d50403e5f8 100644 --- a/lib/snmp/src/agent/snmpa_net_if.erl +++ b/lib/snmp/src/agent/snmpa_net_if.erl @@ -52,7 +52,7 @@ %% Also, the request-reponder and trap-sender transport(s), %% has different needs. %% The trap-sender transport will send more data then it will receive. -%% Therefor, we should be able to specify; +%% Therefore, we should be able to specify; %% bind_to, no_reuse_address, recbuf and sndbuf individually: %% {intAgentTransports, %% [{transportDomainUdpIpv4, {{141,213,11,24}, PortInfo}, @@ -122,7 +122,7 @@ %% Note that since informs require confirmation, %% an ephemeral socket cannot be removed immediately %% when it has been "used up". -%% We need to keep it for some time to receive responces +%% We need to keep it for some time to receive responses %% and in case a resend is needed!. %% @@ -245,12 +245,12 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) -> info end, proc_lib:init_ack({error, {Class, udp_open, PortNo, Reason}}); - {error, Reason} -> - %% config_err("failed starting net-if: ~n~p", [Reason]), - proc_lib:init_ack({error, Reason}); + {error, Reason} -> + %% config_err("failed starting net-if: ~n~p", [Reason]), + proc_lib:init_fail({error, Reason}, {exit, normal}); Error -> %% config_err("failed starting net-if: ~n~p", [Error]), - proc_lib:init_ack({error, Error}) + proc_lib:init_fail({error, Error}, {exit, normal}) end. do_init(Prio, NoteStore, MasterAgent, Parent, Opts) -> @@ -583,7 +583,7 @@ loop(#state{transports = Transports, ?vdebug("loop(~p)", [S]), receive {udp, Socket, IpAddr, IpPort, Packet} = Msg -> - ?vlog("got paket from ~w:~w on ~w", [IpAddr, IpPort, Socket]), + ?vlog("got packet from ~w:~w on ~w", [IpAddr, IpPort, Socket]), case lists:keyfind(Socket, #transport.socket, Transports) of #transport{socket = Socket, domain = Domain} = Transport -> From = @@ -688,18 +688,6 @@ loop(#state{transports = Transports, S, Vsn, Pdu, MsgData, TDomAddrs, From), loop(NewS); - %% Discovery Inform - %% - {send_discovery, Pdu, MsgData, To, From} -> - ?vdebug("received send discovery request: " - "~n Pdu: ~p" - "~n To: ~p" - "~n From: ~p", - [Pdu, To, toname(From)]), - NewS = handle_send_discovery(S, Pdu, MsgData, To, From), - loop(NewS); - %% - %% Discovery Inform {send_discovery, Pdu, MsgData, To, From, ExtraInfo} -> ?vdebug("received send discovery request: " @@ -841,9 +829,12 @@ handle_udp_error(S, #transport{socket = Socket, try inet:sockname(Socket) of {ok, {IP, Port}} -> error_msg("UDP Error for transport: " - "~n Socket: ~p (~p, ~p)" + "~n Socket: ~s" + "~n Addr: ~p" + "~n Port: ~p" "~n Kind: ~p" - "~n Error: ~p", [Socket, IP, Port, Kind, Error]); + "~n Error: ~p", + [inet:socket_to_list(Socket), IP, Port, Kind, Error]); {error, _} -> error_msg("UDP Error for transport: " "~n Socket: ~p" @@ -1678,7 +1669,7 @@ udp_send(Socket, To, B) -> ok; ok -> %% For future use! Ephemeral ports! - {ok, size(B)} + {ok, byte_size(B)} catch error:ExitReason:StackTrace -> error_msg("[exit] cannot send message " @@ -1687,7 +1678,7 @@ udp_send(Socket, To, B) -> end. sz(L) when is_list(L) -> length(L); -sz(B) when is_binary(B) -> size(B); +sz(B) when is_binary(B) -> byte_size(B); sz(_) -> undefined. @@ -2029,6 +2020,21 @@ socket_opts(Domain, {IpAddr, PortInfo}, SocketOpts, DefaultOpts) -> "~n SocketOpts: ~p" "~n DefaultOpts: ~p", [Domain, IpAddr, PortInfo, SocketOpts, DefaultOpts]), + {RequireBind, InetBackend} = + case get_inet_backend(SocketOpts, DefaultOpts) of + use_default -> + {false, []}; + Backend when (Backend =:= inet) -> + {false, [{inet_backend, Backend}]}; + Backend when (Backend =:= socket) -> + {case os:type() of + {win32, nt} -> + true; + _ -> + false + end, + [{inet_backend, Backend}]} + end, Opts = [binary | case snmp_conf:tdomain_to_family(Domain) of @@ -2037,7 +2043,8 @@ socket_opts(Domain, {IpAddr, PortInfo}, SocketOpts, DefaultOpts) -> Family -> [Family] end ++ - case get_bind_to_ip_address(SocketOpts, DefaultOpts) of + case RequireBind orelse + get_bind_to_ip_address(SocketOpts, DefaultOpts) of true -> [{ip, IpAddr}]; _ -> @@ -2070,13 +2077,6 @@ socket_opts(Domain, {IpAddr, PortInfo}, SocketOpts, DefaultOpts) -> "~n ~p", [BadESO]), [] end, - InetBackend = - case get_inet_backend(SocketOpts, DefaultOpts) of - use_default -> - []; - Backend when (Backend =:= inet) orelse (Backend =:= socket) -> - [{inet_backend, Backend}] - end, %% %% Ephm = get_ephemeral(SocketOpts), %% {Ephm, PortInfo, Opts}. @@ -2152,7 +2152,7 @@ get_inet_backend(Opts, DefaultOpts) -> get_socket_opt(inet_backend, Opts, DefaultOpts, use_default). %% -%% This is not realy a socket option, but rather socket 'meta' +%% This is not really a socket option, but rather socket 'meta' %% information. Its still put together with the actual socket %% options. %% get_ephemeral(SocketOpts) -> diff --git a/lib/snmp/src/agent/snmpa_network_interface_filter.erl b/lib/snmp/src/agent/snmpa_network_interface_filter.erl index 1524a6447b62..d67d945b8a24 100644 --- a/lib/snmp/src/agent/snmpa_network_interface_filter.erl +++ b/lib/snmp/src/agent/snmpa_network_interface_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2016. All Rights Reserved. +%% Copyright Ericsson AB 2007-2022. 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. @@ -33,7 +33,7 @@ behaviour_info(_) -> %% accept_recv({domain(), address()}) -> boolean() -%% Called at the receiption of a message +%% Called at the reception of a message %% (before *any* processing has been done). %% %% accept_send({domain(), address()}) -> boolean() diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl index 89580ad8e100..5943b850bf10 100644 --- a/lib/snmp/src/agent/snmpa_set_lib.erl +++ b/lib/snmp/src/agent/snmpa_set_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -37,7 +37,7 @@ %% Input is a sorted Varbinds list. %% Output is either ok or {ErrIndex, ErrCode}. %%* 1) IF the variable is outside the mib view THEN noAccess. -%%* 2a) IF the varaible doesn't exist THEN notWritable. +%%* 2a) IF the variable doesn't exist THEN notWritable. %% 2b) IF mib isn't able to create instances of the variable (for %% example in a table) THEN noCreation. %%* 3) IF the new value provided is of the wrong ASN.1 type THEN wrongType. @@ -59,7 +59,7 @@ %% %% SNMPv1 (see rfc1157:4.1.5) %%* 1) IF variable not available for set in the mibview THEN noSuchName. -%%* 2) IF variable exists, but doesn't permit writeing THEN readOnly. +%%* 2) IF variable exists, but doesn't permit writing THEN readOnly. %%* 3) IF provided value doesn't match ASN.1 type THEN badValue. %% 4) IF any other error THEN genErr. %% 5) Otherwise ok! diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl index 3261411ec3e4..26c61579d5d9 100644 --- a/lib/snmp/src/agent/snmpa_supervisor.erl +++ b/lib/snmp/src/agent/snmpa_supervisor.erl @@ -280,7 +280,7 @@ init([AgentType, Opts]) -> %% -- mib storage -- %% MibStorage has only one mandatory part: module - %% Everything else is module dependent and therefor + %% Everything else is module dependent and therefore %% put in a special option: options MibStorage = case get_opt(mib_storage, Opts, [{module, snmpa_mib_storage_ets}]) of diff --git a/lib/snmp/src/agent/snmpa_svbl.erl b/lib/snmp/src/agent/snmpa_svbl.erl index 8955bed0f282..a42d16de3a0f 100644 --- a/lib/snmp/src/agent/snmpa_svbl.erl +++ b/lib/snmp/src/agent/snmpa_svbl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -91,7 +91,7 @@ insert_key(Key, Value, []) -> [{Key, [Value]}]. %%----------------------------------------------------------------- -%% Tranforms a list of {Oid, Vb} to a 2-tuple with all +%% Transforms a list of {Oid, Vb} to a 2-tuple with all %% Oids and all Vbs. These lists will be reversed. %%----------------------------------------------------------------- sa_split(Vbs) -> sa_split(Vbs, [], []). @@ -137,7 +137,7 @@ unpack(Rest, [Row | Rows], []) -> %% OrgIndex should not be present when we call the is_set_ok/set/undo %% table functions. They just see the list of cols, and if an error -%% occurs, they return the column nunber. +%% occurs, they return the column number. %% Also, delete duplicate columns. If a SET is performed with duplicate %% columns, it is undefined which column to use. We just pick one. delete_org_index([{RowIndex, Cols} | Rows]) -> diff --git a/lib/snmp/src/agent/snmpa_target_cache.erl b/lib/snmp/src/agent/snmpa_target_cache.erl index 72caf72b3389..dab6eacddcf2 100644 --- a/lib/snmp/src/agent/snmpa_target_cache.erl +++ b/lib/snmp/src/agent/snmpa_target_cache.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2016. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -200,7 +200,7 @@ do_init(Prio, Opts) -> %% %% (1) As long as there are no _waiting_ or active write locks, -%% read-locks will allways be granted +%% read-locks will always be granted %% (2) When there are no active readers, write-locks will be %% granted. %% (3) When there are active readers (clients with read-locks), @@ -490,7 +490,7 @@ handle_cast({unlock, Pid}, writer = Writer, waiting = StillWaiting}}; - %% If we have no active lockers, this may be a bug and therefor + %% If we have no active lockers, this may be a bug and therefore %% see if we can activate some of the waiting _ when (State#state.active_count == 0) -> ?vdebug("unlock -> could not find locker", []), @@ -661,7 +661,7 @@ handle_maybe_active_or_waiting_down(Pid, [#locker{state = active, type = read}] when (Cnt == 1) -> %% 1) This means that the writer must be waiting %% 2) The last reader terminated, - %% time to activate the wating writer + %% time to activate the waiting writer %% If this was the last one, then we must %% activate the waiting writer. ets:delete(?LOCKER_TAB, Pid), diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index 9ee854b67d8a..be1a2a2a85da 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -34,11 +34,6 @@ send_inform/6]). -export([init_discovery_inform/13, send_discovery_inform/5]). -%% --export([send_discovery/5, - init_discovery_inform/12]). -%% - -include_lib("snmp/include/snmp_types.hrl"). -include_lib("snmp/src/agent/snmpa_internal.hrl"). -include_lib("snmp/include/SNMPv2-MIB.hrl"). @@ -74,9 +69,9 @@ %% operation, and so on, until eventually the MA will receive the %% info. The MA then fills in the gaps, and at this point all %% oids and types must be known, otherwise an error is signalled, -%% and the opertaion is aborted. For the unknown values for some +%% and the operation is aborted. For the unknown values for some %% oids, a get-operation is performed by the MA. This will -%% retreive the missing values. +%% retrieve the missing values. %% At this point, all oid, types and values are known, so the MA %% can distribute the traps according to the information in the %% internal tables. @@ -128,7 +123,7 @@ %% Initialize as many variables as possible. %% Returns: {ok, TrapRecord, } | error %% where Var is returned from initiate_vars. -%% NOTE: Executed at the inital SA +%% NOTE: Executed at the initial SA %%----------------------------------------------------------------- construct_trap(Trap, Varbinds) -> ?vdebug("construct_trap -> entry with" @@ -218,7 +213,7 @@ alias2oid(Alias, Append) -> %% {{Process, VariableOid}, Value} | %% {{Process, VariableAtom}, Value} | %% {TableColAtom, RowIndex, Value} -%% NOTE: Executed at the inital SA +%% NOTE: Executed at the initial SA %%----------------------------------------------------------------- initiate_vars([{Oid, Asn1Type} | T], Varbinds) -> case delete_oid_from_varbinds(Oid, Varbinds) of @@ -410,7 +405,7 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) -> LocalEngineID, ExtraInfo, NetIf). %% The agent normally does not care about the result, -%% but since it can be usefull when debugging, add +%% but since it can be useful when debugging, add %% some info when we fail to send the trap(s). send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf) -> @@ -438,9 +433,6 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, send_trap_pdus(Dests, ContextName, {TrapRec, VarbindList}, [], [], [], Recv, LocalEngineID, ExtraInfo, NetIf). -send_discovery(TargetName, Record, ContextName, Vbs, NetIf) -> - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - send_discovery(TargetName, Record, ContextName, Vbs, NetIf, ExtraInfo). send_discovery(TargetName, Record, ContextName, Vbs, NetIf, ExtraInfo) -> case find_dest(TargetName) of {ok, Dest} -> @@ -715,16 +707,6 @@ send_discovery_pdu(Record, Dest, Vbs, ExtraInfo]), {ok, Sender, SecLevel}. -init_discovery_inform(Parent, - Dest, - SecModel, SecName, SecLevel, TargetName, - ContextName, Timeout, Retry, Vbs, NetIf, Verbosity) -> - ExtraInfo = ?DEFAULT_NOTIF_EXTRA_INFO, - init_discovery_inform(Parent, - Dest, - SecModel, SecName, SecLevel, TargetName, - ContextName, Timeout, Retry, Vbs, NetIf, - Verbosity, ExtraInfo). init_discovery_inform(Parent, Dest, SecModel, SecName, SecLevel, TargetName, diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl index c65fcf2f8c67..3417bb1aa9e0 100644 --- a/lib/snmp/src/agent/snmpa_usm.erl +++ b/lib/snmp/src/agent/snmpa_usm.erl @@ -62,7 +62,7 @@ %% Func: process_incoming_msg(Packet, Data, SecParams, SecLevel) -> %% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} | %% {error, Reason} | {error, Reason, ErrorInfo} -%% Return value may be throwed. +%% Return value may be thrown. %% Types: Reason -> term() %% Purpose: %%----------------------------------------------------------------- @@ -373,7 +373,7 @@ is_auth(AuthProtocol, AuthKey, AuthParams, Packet, SecName, (TermDiscoStage2 =:= plain)) -> %% 3.2.7a ?vtrace("is_auth -> terminating discovery stage 2 - plain",[]), %% This will *always* result in the manager *not* - %% beeing in timewindow + %% being in timewindow authoritative(SecName, MsgAuthEngineBoots, MsgAuthEngineTime, LocalEngineID); diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index 3a5aaa140b7d..a04d8bbdd83b 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -317,7 +317,7 @@ dump_table() -> %% time dumping the table. unique_table_name(Pre) -> %% We want something that is guaranteed to be unique, - %% therefor we use erlang:timestamp() instead of os:timestamp() + %% therefore we use erlang:timestamp() instead of os:timestamp() unique_table_name(Pre, erlang:timestamp()). unique_table_name(Pre, {_A, _B, C} = Now) -> @@ -389,7 +389,7 @@ get_access_row(Key, GroupKey, ContextName, SecModel, SecLevel, Score, Found) -> {ok, NScore} when NScore > Score -> get_access_row(NextKey, GroupKey, ContextName, SecModel, SecLevel, NScore, Row); - {ok, _} -> % e.g. a throwed {ok, 0} + {ok, _} -> % e.g. a thrown {ok, 0} get_access_row(NextKey, GroupKey, ContextName, SecModel, SecLevel, Score, Found); false -> diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile index 02800462a48f..f5a74aa78e4d 100644 --- a/lib/snmp/src/app/Makefile +++ b/lib/snmp/src/app/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2021. All Rights Reserved. +# Copyright Ericsson AB 2003-2022. 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. @@ -109,8 +109,8 @@ ERL_COMPILE_FLAGS += -I../misc \ # Targets # ---------------------------------------------------- -debug: - @$(MAKE) TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src index 2159fb5b4b9b..db82fe52ec54 100644 --- a/lib/snmp/src/app/snmp.app.src +++ b/lib/snmp/src/app/snmp.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -141,5 +141,6 @@ %% before snmp. {applications, [kernel, stdlib]}, {mod, {snmp_app, []}}, - {runtime_dependencies, ["stdlib-2.5","runtime_tools-1.8.14","mnesia-4.12", - "kernel-8.0","erts-12.0","crypto-3.3"]}]}. + {runtime_dependencies, + ["stdlib-5.0","runtime_tools-1.8.14","mnesia-4.12", + "kernel-8.0","erts-12.0","crypto-4.6"]}]}. diff --git a/lib/snmp/src/app/snmp.config b/lib/snmp/src/app/snmp.config index f35a6361577d..f5222245f186 100644 --- a/lib/snmp/src/app/snmp.config +++ b/lib/snmp/src/app/snmp.config @@ -36,8 +36,8 @@ %% {verbosity, verbosity()} | %% {options, net_if_options()} %% net_if_options() -> [net_if_option()] -%% net_if_option() -> Note that these are basically dependant on which net-if -%% module is beeing used, but the options described here +%% net_if_option() -> Note that these are basically dependent on which net-if +%% module is being used, but the options described here %% are the ones that snmp_net_if (the default value for %% the module option) handles: %% {bind_to, bool()} | @@ -77,8 +77,8 @@ %% {verbosity, verbosity()} | %% {options, mgr_net_if_options()} %% mgr_net_if_options() -> [mgr_net_if_option()] -%% mgr_net_if_option() -> Note that these are basically dependant on which -%% net-if module is beeing used, but the options +%% mgr_net_if_option() -> Note that these are basically dependent on which +%% net-if module is being used, but the options %% described here are the ones of the snmpm_net_if %% (the default value for the module option): %% {recbuf, integer()} | diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl index bc6a803eaa40..c1f1c12acd93 100644 --- a/lib/snmp/src/app/snmp.erl +++ b/lib/snmp/src/app/snmp.erl @@ -264,7 +264,7 @@ set_module_trace(Module, Opts) -> {value, {return_trace, false}} -> []; _ -> - %% Default is allways to include return values + %% Default is always to include return values [{return_trace}] end, TraceRes = @@ -665,7 +665,7 @@ short_time({{Y,M,D},{H,Mi,S}}) -> [y1(Y), y2(Y), M, D, H, Mi, S, 0]. %% This function will only be called if there has been some -%% validation error, and as it is strict, it allways returns +%% validation error, and as it is strict, it always returns %% false. strict_validation(_What, _Data) -> false. diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile index bbd7f99378dc..f255237a04f9 100644 --- a/lib/snmp/src/compile/Makefile +++ b/lib/snmp/src/compile/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -85,13 +85,17 @@ ERL_COMPILE_FLAGS += -I../../include \ YRL_FLAGS = -o . +ifeq ($(ERL_DETERMINISTIC),yes) + YRL_FLAGS += +deterministic +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug: - @${MAKE} TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl index 4249799195ad..4fcc6e2342c5 100644 --- a/lib/snmp/src/compile/snmpc.erl +++ b/lib/snmp/src/compile/snmpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2019. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -1322,7 +1322,7 @@ define_cols([{#mc_object_type{name = NameOfCol, entrytype = table_column, access = NewAccess, description = Description, - units = Units, %% Propably not usefull + units = Units, %% Probably not useful assocList = [{table_name,TableName} | Defval]}), define_cols(Rest,SubIndex+1,Fields,NameOfEntry,TableName, [ColumnME|ColMEs]); diff --git a/lib/snmp/src/compile/snmpc.src b/lib/snmp/src/compile/snmpc.src index e64b6607c42f..0f6831cc171c 100644 --- a/lib/snmp/src/compile/snmpc.src +++ b/lib/snmp/src/compile/snmpc.src @@ -3,7 +3,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -355,7 +355,7 @@ usage() -> "~n For example snmp/mibs/ " "~n The current workin dir and the " "~n /priv/mibs " - "~n are always listed last the includ path. " + "~n are always listed last the include path. " "~n --db - Database to used for the default instrumentation." "~n Defaults to volatile." "~n --sgc - This option (skip group check), if present, " diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl index 0cff8c545680..b04ab3af843e 100644 --- a/lib/snmp/src/compile/snmpc_lib.erl +++ b/lib/snmp/src/compile/snmpc_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -903,7 +903,7 @@ test_index_positions(Line, Indexes, ColMEs) -> TLI = lists:filter(IsTLI, Indexes), test_index_positions_impl(Line, TLI, ColMEs). -%% An table that augments another cannot conatin any index, +%% An table that augments another cannot contain any index, %% so the first non-index column is always the first column. augments_first_non_index_column([]) -> none; diff --git a/lib/snmp/src/compile/snmpc_mib_gram.yrl b/lib/snmp/src/compile/snmpc_mib_gram.yrl index 14a668127e3d..1a970b97ea21 100644 --- a/lib/snmp/src/compile/snmpc_mib_gram.yrl +++ b/lib/snmp/src/compile/snmpc_mib_gram.yrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -453,7 +453,7 @@ variables -> objectname : ['$1']. variables -> variables ',' objectname : ['$3' | '$1']. implies -> '::=' : '$1'. -implies -> ':' ':' '=' : w("Sloppy asignment on line ~p", [line_of('$1')]), '$1'. +implies -> ':' ':' '=' : w("Sloppy assignment on line ~p", [line_of('$1')]), '$1'. descriptionfield -> string : lreverse(descriptionfield, val('$1')). descriptionfield -> '$empty' : undefined. description -> 'DESCRIPTION' string : lreverse(description, val('$2')). @@ -1071,7 +1071,7 @@ bits_to_bytes([], 1, _Byte) -> % empty bitstring []; bits_to_bytes([], 256, _Byte) -> % correct; multiple of 8 []; -% If we are to support arbitrary length of bitstrings. This migth +% If we are to support arbitrary length of bitstrings. This might % be needed in the new SMI. %bits_to_bytes([], N, Byte) -> % [Byte]; diff --git a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl index c214bca93c0b..b041a6414b25 100644 --- a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl +++ b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl @@ -33,7 +33,7 @@ %% Args: MibName = string() without extension. %% Purpose: Produce a .hrl file with oid for tables and variables, %% column numbers for columns and values for enums. -%% Writes only the first occurence of a name. Prints a +%% Writes only the first occurrence of a name. Prints a %% warning if a duplicate name is found. %% Returns: ok | {error, Reason} %% Note: The Mib must be compiled. diff --git a/lib/snmp/src/compile/snmpc_tok.erl b/lib/snmp/src/compile/snmpc_tok.erl index 9114cc90de30..fa40dd323796 100644 --- a/lib/snmp/src/compile/snmpc_tok.erl +++ b/lib/snmp/src/compile/snmpc_tok.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -273,7 +273,7 @@ tokenise([10| T]) -> tokenise(T); tokenise([13| T]) -> tokenise(T); tokenise([32| T]) -> tokenise(T); -%% Handle singe characters like { } [ ] + = ... +%% Handle single characters like { } [ ] + = ... tokenise([Ch | T]) -> Atm = list_to_atom([Ch]), {{Atm, get(line)}, T}; diff --git a/lib/snmp/src/manager/Makefile b/lib/snmp/src/manager/Makefile index 6f5f5d01f965..693ef7546901 100644 --- a/lib/snmp/src/manager/Makefile +++ b/lib/snmp/src/manager/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2021. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -100,8 +100,8 @@ ERL_COMPILE_FLAGS += -I../../include \ # Targets # ---------------------------------------------------- -debug: - @$(MAKE) TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: @$(MAKE) behaviour_targets diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl index ffa6b0012c61..6c6a22e1f1bc 100644 --- a/lib/snmp/src/manager/snmpm.erl +++ b/lib/snmp/src/manager/snmpm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2021. 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. @@ -96,18 +96,6 @@ -export([format_reason/1, format_reason/2]). -%% Backward compatibility exports (API version "2") --export([ - sync_get/3, sync_get/4, sync_get/5, sync_get/6, - async_get/3, async_get/4, async_get/5, async_get/6, - sync_get_next/3, sync_get_next/4, sync_get_next/5, sync_get_next/6, - async_get_next/3, async_get_next/4, async_get_next/5, async_get_next/6, - sync_set/3, sync_set/4, sync_set/5, sync_set/6, - async_set/3, async_set/4, async_set/5, async_set/6, - sync_get_bulk/5, sync_get_bulk/6, sync_get_bulk/7, sync_get_bulk/8, - async_get_bulk/5, async_get_bulk/6, async_get_bulk/7, async_get_bulk/8 - ]). - %% Application internal export -export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]). -export([target_name/1, target_name/2]). @@ -119,49 +107,6 @@ ]). --deprecated( - [ - {sync_get, 3, "use snmpm:sync_get2/3 instead."}, - {sync_get, 4, "use snmpm:sync_get2/4 instead."}, - {sync_get, 5, "use snmpm:sync_get2/4 instead."}, - {sync_get, 6, "use snmpm:sync_get2/4 instead."}, - - {async_get, 3, "use snmpm:async_get2/3 instead."}, - {async_get, 4, "use snmpm:async_get2/4 instead."}, - {async_get, 5, "use snmpm:async_get2/4 instead."}, - {async_get, 6, "use snmpm:async_get2/4 instead."}, - - {sync_get_next, 3, "use snmpm:sync_get_next2/3 instead."}, - {sync_get_next, 4, "use snmpm:sync_get_next2/4 instead."}, - {sync_get_next, 5, "use snmpm:sync_get_next2/4 instead."}, - {sync_get_next, 6, "use snmpm:sync_get_next2/4 instead."}, - - {async_get_next, 3, "use snmpm:async_get_next2/3 instead."}, - {async_get_next, 4, "use snmpm:async_get_next2/4 instead."}, - {async_get_next, 5, "use snmpm:async_get_next2/4 instead."}, - {async_get_next, 6, "use snmpm:async_get_next2/4 instead."}, - - {sync_set, 3, "use snmpm:sync_set2/3 instead."}, - {sync_set, 4, "use snmpm:sync_set2/4 instead."}, - {sync_set, 5, "use snmpm:sync_set2/4 instead."}, - {sync_set, 6, "use snmpm:sync_set2/4 instead."}, - - {async_set, 3, "use snmpm:async_set2/3 instead."}, - {async_set, 4, "use snmpm:async_set2/4 instead."}, - {async_set, 5, "use snmpm:async_set2/4 instead."}, - {async_set, 6, "use snmpm:async_set2/4 instead."}, - - {sync_get_bulk, 5, "use snmpm:sync_get_bulk2/5 instead."}, - {sync_get_bulk, 6, "use snmpm:sync_get_bulk2/6 instead."}, - {sync_get_bulk, 7, "use snmpm:sync_get_bulk2/6 instead."}, - {sync_get_bulk, 8, "use snmpm:sync_get_bulk2/6 instead."}, - - {async_get_bulk, 5, "use snmpm:async_get_bulk2/5 instead."}, - {async_get_bulk, 6, "use snmpm:async_get_bulk2/6 instead."}, - {async_get_bulk, 7, "use snmpm:async_get_bulk2/6 instead."}, - {async_get_bulk, 8, "use snmpm:async_get_bulk2/6 instead."} - ]). - -include_lib("snmp/src/misc/snmp_debug.hrl"). -include_lib("snmp/include/snmp_types.hrl"). -include("snmpm_atl.hrl"). @@ -206,14 +151,14 @@ simple_conf() -> {ok, _} -> ok; _ -> - ok = snmp_config:write_manager_config(Cwd, "", + ok = snmp_config:write_manager_config(Cwd, "", [{port, 5000}, {engine_id, "mgrEngine"}, {max_message_size, 484}]) end, Conf = [{dir, Cwd}, {db_dir, Cwd}], [{versions, Vsns}, {config, Conf}]. - + %% Simple start. Start a manager with default values. start_link() -> start_link(simple_conf()). @@ -379,7 +324,7 @@ restart(net_if = What) -> %% The manager entity responsible for a specific agent. %% Module is the callback module (snmpm_user behaviour) which %% will be called whenever something happens (detected -%% agent, incomming reply or incomming trap/notification). +%% agent, incoming reply or incoming trap/notification). %% Note that this could have already been done as a %% consequence of the node config. register_user(Id, Module, Data) -> @@ -549,7 +494,7 @@ which_usm_users(EngineID) when is_list(EngineID) -> %% -- Requests -- -%% --- synchroneous get-request --- +%% --- synchronous get-request --- %% sync_get2(UserId, TargetName, Oids) -> @@ -559,29 +504,6 @@ sync_get2(UserId, TargetName, Oids, SendOpts) when is_list(Oids) andalso is_list(SendOpts) -> snmpm_server:sync_get(UserId, TargetName, Oids, SendOpts). -%% -sync_get(UserId, TargetName, Oids) -> - sync_get2(UserId, TargetName, Oids). - -sync_get(UserId, TargetName, Oids, Timeout) - when is_list(Oids) andalso is_integer(Timeout) -> - SendOpts = [{timeout, Timeout}], - sync_get2(UserId, TargetName, Oids, SendOpts); -sync_get(UserId, TargetName, Context, [OH|_] = Oids) - when is_list(Context) andalso is_list(OH) -> - SendOpts = [{context, Context}], - sync_get2(UserId, TargetName, Oids, SendOpts). - -sync_get(UserId, TargetName, Context, Oids, Timeout) -> - SendOpts = [{context, Context}, {timeout, Timeout}], - sync_get2(UserId, TargetName, Oids, SendOpts). - -sync_get(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) -> - SendOpts = [{context, Context}, {timeout, Timeout}, {extra, ExtraInfo}], - sync_get2(UserId, TargetName, Oids, SendOpts). -%% - - %% --- asynchronous get-request --- %% @@ -596,29 +518,8 @@ async_get2(UserId, TargetName, Oids, SendOpts) when is_list(Oids) andalso is_list(SendOpts) -> snmpm_server:async_get(UserId, TargetName, Oids, SendOpts). -%% -async_get(UserId, TargetName, Oids) -> - async_get2(UserId, TargetName, Oids). - -async_get(UserId, TargetName, Oids, Expire) when is_integer(Expire) -> - SendOpts = [{timeout, Expire}], - async_get2(UserId, TargetName, Oids, SendOpts); -async_get(UserId, TargetName, Context, Oids) - when is_list(Context) andalso is_list(Oids) -> - SendOpts = [{context, Context}], - async_get2(UserId, TargetName, Oids, SendOpts). - -async_get(UserId, TargetName, Context, Oids, Expire) -> - SendOpts = [{timeout, Expire}, {context, Context}], - async_get2(UserId, TargetName, Oids, SendOpts). -async_get(UserId, TargetName, Context, Oids, Expire, ExtraInfo) -> - SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}], - async_get2(UserId, TargetName, Oids, SendOpts). -%% - - -%% --- synchroneous get_next-request --- +%% --- synchronous get_next-request --- %% sync_get_next2(UserId, TargetName, Oids) -> @@ -628,28 +529,6 @@ sync_get_next2(UserId, TargetName, Oids, SendOpts) when is_list(Oids) andalso is_list(SendOpts) -> snmpm_server:sync_get_next(UserId, TargetName, Oids, SendOpts). -%% -sync_get_next(UserId, TargetName, Oids) -> - sync_get_next2(UserId, TargetName, Oids). - -sync_get_next(UserId, TargetName, Oids, Timeout) - when is_list(Oids) andalso is_integer(Timeout) -> - SendOpts = [{timeout, Timeout}], - sync_get_next2(UserId, TargetName, Oids, SendOpts); -sync_get_next(UserId, TargetName, Context, Oids) - when is_list(Context) andalso is_list(Oids) -> - SendOpts = [{context, Context}], - sync_get_next2(UserId, TargetName, Oids, SendOpts). - -sync_get_next(UserId, TargetName, Context, Oids, Timeout) -> - SendOpts = [{timeout, Timeout}, {context, Context}], - sync_get_next2(UserId, TargetName, Oids, SendOpts). - -sync_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) -> - SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}], - sync_get_next2(UserId, TargetName, Oids, SendOpts). -%% - %% --- asynchronous get_next-request --- %% @@ -661,30 +540,8 @@ async_get_next2(UserId, TargetName, Oids, SendOpts) when is_list(Oids) andalso is_list(SendOpts) -> snmpm_server:async_get_next(UserId, TargetName, Oids, SendOpts). -%% -async_get_next(UserId, TargetName, Oids) -> - async_get_next2(UserId, TargetName, Oids). -async_get_next(UserId, TargetName, Oids, Expire) - when is_list(Oids) andalso is_integer(Expire) -> - SendOpts = [{timeout, Expire}], - async_get_next2(UserId, TargetName, Oids, SendOpts); -async_get_next(UserId, TargetName, Context, Oids) - when is_list(Context) andalso is_list(Oids) -> - SendOpts = [{context, Context}], - async_get_next2(UserId, TargetName, Oids, SendOpts). - -async_get_next(UserId, TargetName, Context, Oids, Expire) -> - SendOpts = [{timeout, Expire}, {context, Context}], - async_get_next2(UserId, TargetName, Oids, SendOpts). - -async_get_next(UserId, TargetName, Context, Oids, Expire, ExtraInfo) -> - SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}], - async_get_next2(UserId, TargetName, Oids, SendOpts). -%% - - -%% --- synchroneous set-request --- +%% --- synchronous set-request --- %% sync_set2(UserId, TargetName, VarsAndVals) -> @@ -694,28 +551,6 @@ sync_set2(UserId, TargetName, VarsAndVals, SendOpts) when is_list(VarsAndVals) andalso is_list(SendOpts) -> snmpm_server:sync_set(UserId, TargetName, VarsAndVals, SendOpts). -%% -sync_set(UserId, TargetName, VarsAndVals) -> - sync_set2(UserId, TargetName, VarsAndVals). - -sync_set(UserId, TargetName, VarsAndVals, Timeout) - when is_list(VarsAndVals) andalso is_integer(Timeout) -> - SendOpts = [{timeout, Timeout}], - sync_set2(UserId, TargetName, VarsAndVals, SendOpts); -sync_set(UserId, TargetName, Context, VarsAndVals) - when is_list(Context) andalso is_list(VarsAndVals) -> - SendOpts = [{context, Context}], - sync_set2(UserId, TargetName, VarsAndVals, SendOpts). - -sync_set(UserId, TargetName, Context, VarsAndVals, Timeout) -> - SendOpts = [{timeout, Timeout}, {context, Context}], - sync_set2(UserId, TargetName, VarsAndVals, SendOpts). - -sync_set(UserId, TargetName, Context, VarsAndVals, Timeout, ExtraInfo) -> - SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}], - sync_set2(UserId, TargetName, VarsAndVals, SendOpts). -%% - %% --- asynchronous set-request --- %% @@ -727,30 +562,8 @@ async_set2(UserId, TargetName, VarsAndVals, SendOpts) when is_list(VarsAndVals) andalso is_list(SendOpts) -> snmpm_server:async_set(UserId, TargetName, VarsAndVals, SendOpts). -%% -async_set(UserId, TargetName, VarsAndVals) -> - async_set2(UserId, TargetName, VarsAndVals). - -async_set(UserId, TargetName, VarsAndVals, Expire) - when is_list(VarsAndVals) andalso is_integer(Expire) -> - SendOpts = [{timeout, Expire}], - async_set2(UserId, TargetName, VarsAndVals, SendOpts); -async_set(UserId, TargetName, Context, VarsAndVals) - when is_list(Context) andalso is_list(VarsAndVals) -> - SendOpts = [{context, Context}], - async_set2(UserId, TargetName, VarsAndVals, SendOpts). - -async_set(UserId, TargetName, Context, VarsAndVals, Expire) -> - SendOpts = [{timeout, Expire}, {context, Context}], - async_set2(UserId, TargetName, VarsAndVals, SendOpts). - -async_set(UserId, TargetName, Context, VarsAndVals, Expire, ExtraInfo) -> - SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}], - async_set2(UserId, TargetName, VarsAndVals, SendOpts). -%% - -%% --- synchroneous get-bulk --- +%% --- synchronous get-bulk --- %% sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> @@ -764,35 +577,6 @@ sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) snmpm_server:sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). -%% -sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> - sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids). - -sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Timeout) - when is_integer(NonRep) andalso - is_integer(MaxRep) andalso - is_list(Oids) andalso - is_integer(Timeout) -> - SendOpts = [{timeout, Timeout}], - sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts); -sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids) - when is_integer(NonRep) andalso - is_integer(MaxRep) andalso - is_list(Context) andalso - is_list(Oids) -> - SendOpts = [{context, Context}], - sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). - -sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout) -> - SendOpts = [{timeout, Timeout}, {context, Context}], - sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). - -sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout, - ExtraInfo) -> - SendOpts = [{timeout, Timeout}, {context, Context}, {extra, ExtraInfo}], - sync_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). -%% - %% --- asynchronous get-bulk --- %% @@ -808,35 +592,6 @@ async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) snmpm_server:async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). -%% -async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids). - -async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) - when is_integer(NonRep) andalso - is_integer(MaxRep) andalso - is_list(Oids) andalso - is_integer(Expire) -> - SendOpts = [{timeout, Expire}], - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts); -async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids) - when is_integer(NonRep) andalso - is_integer(MaxRep) andalso - is_list(Context) andalso - is_list(Oids) -> - SendOpts = [{context, Context}], - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). - -async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire) -> - SendOpts = [{timeout, Expire}, {context, Context}], - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). - -async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire, - ExtraInfo) -> - SendOpts = [{timeout, Expire}, {context, Context}, {extra, ExtraInfo}], - async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts). -%% - cancel_async_request(UserId, ReqId) -> @@ -1081,7 +836,7 @@ sys_up_time() -> %%% printable string of the error reason received from either: %%% %%% * If any of the sync/async get/get-next/set/get-bulk -%%% returnes {error, Reason} +%%% returns {error, Reason} %%% * The Reason parameter in the handle_error user callback %%% function %%% diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl index 8e3dc3be6e50..d5394d4298e7 100644 --- a/lib/snmp/src/manager/snmpm_config.erl +++ b/lib/snmp/src/manager/snmpm_config.erl @@ -38,7 +38,7 @@ register_agent/3, unregister_agent/2, agent_info/0, agent_info/2, agent_info/3, - update_agent_info/3, update_agent_info/4, + update_agent_info/3, which_agents/0, which_agents/1, is_known_engine_id/2, @@ -94,9 +94,7 @@ %% Backward compatibillity exports -export([ - register_user/3, unregister_agent/3, - update_agent_info/5, is_known_engine_id/3, get_agent_engine_id/2, get_agent_engine_max_message_size/2, @@ -109,12 +107,15 @@ check_manager_config/2, check_user_config/1, check_agent_config/1, - check_usm_user_config/1]). + check_usm_user_config/1 + ]). %% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - code_change/3, terminate/2]). +-export([ + init/1, handle_call/3, handle_cast/2, handle_info/2, + code_change/3, terminate/2 + ]). %% Includes: @@ -192,10 +193,6 @@ is_started() -> backup(BackupDir) when is_list(BackupDir) -> call({backup, BackupDir}). -%% Backward compatibillity -register_user(UserId, UserMod, UserData) -> - register_user(UserId, UserMod, UserData, []). - register_user(UserId, UserMod, UserData, DefaultAgentConfig) when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> case (catch verify_user_behaviour(UserMod)) of @@ -215,20 +212,6 @@ register_user(UserId, _UserMod, _UserData, DefaultAgentConfig) register_user(UserId, _, _, _) -> {error, {bad_user_id, UserId}}. -%% default_agent_config(DefaultAgentConfig) -> -%% {ok, SystemDefaultAgentConfig} = agent_info(), -%% default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig). - -%% default_agent_config([], DefaultAgentConfig) -> -%% DefaultAgentConfig; -%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) -> -%% case lists:keymember(Key, 1, DefaultAgentConfig) of -%% true -> -%% default_agent_config(T, DefaultAgentConfig); -%% false -> -%% default_agent_config(T, [Entry|DefaultAgentConfig]) -%% end. - verify_user_behaviour(UserMod) -> case snmp_misc:verify_behaviour(snmpm_user, UserMod) of @@ -547,23 +530,6 @@ which_agents(UserId) -> update_agent_info(UserId, TargetName, Info) -> call({update_agent_info, UserId, TargetName, Info}). -%% -%% This is wrapped in the interface module, so this function is -%% only here to catch code-upgrade problems. -update_agent_info(UserId, TargetName, Item, Val) -> - update_agent_info(UserId, TargetName, [{Item, Val}]). -%% - -%% -update_agent_info(UserId, Addr, Port, Item, Val) -> - case agent_info(Addr, Port, target_name) of - {ok, TargetName} -> - update_agent_info(UserId, TargetName, Item, Val); - Error -> - Error - end. -%% - is_known_engine_id(EngineID, TargetName) -> case agent_info(TargetName, engine_id) of {ok, EngineID} -> @@ -2531,18 +2497,6 @@ handle_call({update_agent_info, UserId, TargetName, Info}, Reply = handle_update_agent_info(UserId, TargetName, Info), {reply, Reply, State}; -%% -handle_call({update_agent_info, UserId, TargetName, Item, Val}, - _From, State) -> - ?vlog("received update_agent_info request: " - "~n UserId: ~p" - "~n TargetName: ~p" - "~n Item: ~p" - "~n Val: ~p", [UserId, TargetName, Item, Val]), - Reply = handle_update_agent_info(UserId, TargetName, Item, Val), - {reply, Reply, State}; -%% - handle_call({register_usm_user, User}, _From, State) -> ?vlog("received register_usm_user request: " "~n User: ~p", [User]), @@ -2793,7 +2747,7 @@ stop_backup_server({Pid, _}) when is_pid(Pid) -> %%---------------------------------------------------------- handle_backup(D, BackupDir) -> - %% First check that we do not wrote to the corrent db-dir... + %% First check that we do not wrote to the current db-dir... ?vtrace("handle_backup -> entry with" "~n D: ~p" "~n BackupDir: ~p", [D, BackupDir]), @@ -2915,6 +2869,7 @@ handle_register_agent(UserId, TargetName, Config) -> " FixedConfig: ~p", [FixedConfig]), do_handle_register_agent( TargetName, [{user_id, UserId}|FixedConfig]), + %% %% And now for some (backward compatibillity) %% dirty crossref stuff @@ -2928,25 +2883,6 @@ handle_register_agent(UserId, TargetName, Config) -> {{Domain, Address, target_name}, TargetName}), %% -%% %% First, insert this users default config -%% ?vtrace("handle_register_agent -> store default config", []), -%% do_handle_register_agent(TargetName, DefConfig), -%% %% Second, insert the config for this agent -%% ?vtrace("handle_register_agent -> store config", []), -%% do_handle_register_agent(TargetName, -%% [{user_id, UserId}|Config]), -%% %% -%% %% And now for some (backward compatibillity) -%% %% dirty crossref stuff -%% ?vtrace("handle_register_agent -> lookup taddress", []), -%% {ok, {Addr, Port} = TAddress} = -%% agent_info(TargetName, taddress), -%% ?vtrace("handle_register_agent -> taddress: ~p", -%% [TAddress]), -%% ?vtrace("handle_register_agent -> register cross-ref fix", []), -%% ets:insert(snmpm_agent_table, -%% {{Addr, Port, target_name}, TargetName}), -%% %% ok; _ -> {error, {not_found, UserId}} @@ -3051,14 +2987,6 @@ handle_update_agent_info(TargetName, Info) -> {error, {failed_info_verification, Info, T, E}} end. -handle_update_agent_info(UserId, TargetName, Item, Val) -> - ?vdebug("handle_update_agent_info -> entry with" - "~n UserId: ~p" - "~n TargetName: ~p" - "~n Item: ~p" - "~n Val: ~p", [UserId, TargetName, Item, Val]), - handle_update_agent_info(TargetName, [{Item, Val}]). - do_update_agent_info(TargetName, Info) -> ?vtrace("do_update_agent_info -> entry with~n" " TargetName: ~p~n" diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl index 85821ccb94c6..4d3733b2fd86 100644 --- a/lib/snmp/src/manager/snmpm_mpd.erl +++ b/lib/snmp/src/manager/snmpm_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -46,7 +46,7 @@ %%%----------------------------------------------------------------- -%%% This module implemets the Message Processing and Dispatch part of +%%% This module implements the Message Processing and Dispatch part of %%% the multi-lingual SNMP agent. %%% %%% The MPD is responsible for: @@ -63,7 +63,7 @@ %%% the counters only, it does not provide instrumentation functions %%% for the counters. %%% -%%% With the terms defined in rfc2271, this module implememts part +%%% With the terms defined in rfc2271, this module implements part %%% of the Dispatcher and the Message Processing functionality. %%%----------------------------------------------------------------- init(Vsns) -> @@ -324,7 +324,7 @@ process_v3_msg(NoteStore, Msg, Hdr, Data, Address, Log) -> CtxEngineID, CtxName, PDU#pdu.request_id}, Err = sec_error(Note, Recv), ACM = {invalid_sec_info, Err}, - ReqId = element(size(Note), Note), + ReqId = element(tuple_size(Note), Note), {ok, 'version-3', PDU, PduMMS, {error, ReqId, ACM}}; _NoFound -> ?vtrace("process_v3_msg -> _NoFound: " @@ -412,10 +412,10 @@ process_v3_msg(NoteStore, Msg, Hdr, Data, Address, Log) -> sec_error(T1, T2) - when is_tuple(T1) andalso is_tuple(T2) andalso (size(T1) =:= size(T2)) -> + when tuple_size(T1) =:= tuple_size(T2) -> Tags = {sec_engine_id, msg_sec_model, sec_name, sec_level, ctx_engine_id, ctx_name, request_id}, - sec_error(size(T1), T1, T2, Tags, []); + sec_error(tuple_size(T1), T1, T2, Tags, []); sec_error(T1, T2) -> [{internal_error, T1, T2}]. @@ -585,7 +585,7 @@ sec_module(?SEC_USM) -> %% securityEngineID is set to the value of the target entity's %% snmpEngineID. %% -%% As we never send traps, the SecEngineID is allways the +%% As we never send traps, the SecEngineID is always the %% snmpEngineID of the target entity! sec_engine_id(TargetName) -> case get_agent_engine_id(TargetName) of @@ -600,7 +600,7 @@ sec_engine_id(TargetName) -> %% BMK BMK BMK -%% This one looks very similar to lik generate_v1_v2c_response_msg! +%% This one looks very similar to link generate_v1_v2c_response_msg! %% Common/shared? Should there be differences? %% generate_v1_v2c_msg(Vsn, Pdu, Community, Log) -> @@ -622,7 +622,7 @@ generate_v1_v2c_msg(Vsn, Pdu, Community, Log) -> "(pdu: ~w, community: ~w): ~n~w", [Pdu, Community, Reason]), {discarded, Reason}; - {ok, Packet} when size(Packet) =< MMS -> + {ok, Packet} when byte_size(Packet) =< MMS -> Log(Packet), inc_snmp_out(Pdu), {ok, Packet}; @@ -630,7 +630,7 @@ generate_v1_v2c_msg(Vsn, Pdu, Community, Log) -> ?vlog("packet max size exceeded: " "~n MMS: ~p" "~n Len: ~p", - [MMS, size(Packet)]), + [MMS, byte_size(Packet)]), {discarded, tooBig} end end. @@ -683,7 +683,7 @@ generate_v3_response_msg(#pdu{type = Type} = Pdu, MsgID, %% if it's larger than the agent can handle - %% it will be dropped. Just check against the %% internal size. - {ok, Packet} when size(Packet) =< MMS -> + {ok, Packet} when byte_size(Packet) =< MMS -> if SecLevel == 3 -> %% encrypted - log decrypted pdu @@ -760,13 +760,13 @@ generate_v1_v2c_response_msg(Vsn, Pdu, Comm, Log) -> [Pdu, Comm, Reason]), {discarded, Reason}; - {ok, Packet} when size(Packet) =< MMS -> + {ok, Packet} when byte_size(Packet) =< MMS -> Log(Packet), inc_snmp_out(Pdu), {ok, Packet}; {ok, Packet} -> %% Too big - too_big(Vsn, Pdu, Comm, MMS, size(Packet), Log) + too_big(Vsn, Pdu, Comm, MMS, byte_size(Packet), Log) end end. @@ -870,7 +870,7 @@ get_max_message_size() -> {ok, MMS} -> MMS; E -> - user_err("failed retreiving engine max message size: ~w", [E]), + user_err("failed retrieving engine max message size: ~w", [E]), 484 end. diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl index bab5779ce31d..c55a2cfd2e5a 100644 --- a/lib/snmp/src/manager/snmpm_net_if.erl +++ b/lib/snmp/src/manager/snmpm_net_if.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2022. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -292,14 +292,26 @@ do_init(Server, NoteStore) -> ?vdebug("DomainAddresses: ~w", [DomainAddresses]), CommonSocketOpts = common_socket_opts(Opts), BindTo = get_opt(Opts, bind_to, false), - InetBackend = case get_opt(Opts, inet_backend, use_default) of - use_default -> []; - IB -> [{inet_backend, IB}] - end, + {RequireBind, InetBackend} = + case get_opt(Opts, inet_backend, use_default) of + use_default -> + {false, []}; + IB when (IB =:= inet) -> + {false, [{inet_backend, IB}]}; + IB when (IB =:= socket) -> + {case os:type() of + {win32, nt} -> + true; + _ -> + false + end, + [{inet_backend, IB}]} + end, case [begin {IpPort, SocketOpts} = - socket_params(Domain, Address, BindTo, CommonSocketOpts), + socket_params(Domain, Address, + RequireBind, BindTo, CommonSocketOpts), %% The 'inet-backend' option has to be first, %% so we might as well add it last. Socket = socket_open(IpPort, InetBackend ++ SocketOpts), @@ -356,7 +368,8 @@ socket_open(IpPort, SocketOpts) -> Socket end. -socket_params(Domain, {IpAddr, IpPort} = Addr, BindTo, CommonSocketOpts) -> +socket_params(Domain, {IpAddr, IpPort} = Addr, + RequireBind, BindTo, CommonSocketOpts) -> Family = snmp_conf:tdomain_to_family(Domain), SocketOpts = case Family of @@ -370,22 +383,22 @@ socket_params(Domain, {IpAddr, IpPort} = Addr, BindTo, CommonSocketOpts) -> case init:get_argument(snmpm_fd) of {ok, [[FdStr]]} -> Fd = list_to_integer(FdStr), - case BindTo of + case RequireBind orelse BindTo of true -> {IpPort, [{ip, IpAddr}, {fd, Fd} | SocketOpts]}; _ -> {0, [{fd, Fd} | SocketOpts]} end; error -> - socket_params(SocketOpts, Addr, BindTo) + socket_params(SocketOpts, Addr, RequireBind, BindTo) end; _ -> - socket_params(SocketOpts, Addr, BindTo) + socket_params(SocketOpts, Addr, RequireBind, BindTo) end. %% -socket_params(SocketOpts, {IpAddr, IpPort}, BindTo) -> - case BindTo of +socket_params(SocketOpts, {IpAddr, IpPort}, RequireBind, BindTo) -> + case RequireBind orelse BindTo of true -> {IpPort, [{ip, IpAddr} | SocketOpts]}; _ -> @@ -792,7 +805,7 @@ maybe_handle_recv_msg(Domain, Addr, Bytes, State) -> fun (Pid, Class, Reason, Stacktrace) -> warning_msg( "Worker process (~p) terminated " - "while processing (incomming) message from %s:~n" + "while processing (incoming) message from %s:~n" "~w:~w at ~p", [Pid, snmp_conf:mk_addr_string({Domain, Addr}), Class, Reason, Stacktrace]) @@ -814,7 +827,7 @@ maybe_handle_recv_msg_mt( handle_recv_msg(Domain, Addr, Bytes, #state{server = Pid}) - when is_binary(Bytes) andalso (size(Bytes) =:= 0) -> + when is_binary(Bytes) andalso (byte_size(Bytes) =:= 0) -> Pid ! {snmp_error, {empty_message, Domain, Addr}, Domain, Addr}; %% handle_recv_msg( diff --git a/lib/snmp/src/manager/snmpm_network_interface_filter.erl b/lib/snmp/src/manager/snmpm_network_interface_filter.erl index 35bec4e7e7d5..54fa8645df75 100644 --- a/lib/snmp/src/manager/snmpm_network_interface_filter.erl +++ b/lib/snmp/src/manager/snmpm_network_interface_filter.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -33,7 +33,7 @@ behaviour_info(_) -> %% accept_recv(address(), port()) -> boolean() -%% Called at the receiption of a message +%% Called at the reception of a message %% (before *any* processing has been done). %% %% accept_send(address(), port()) -> boolean() diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl index ca18637b8d45..0da35c9bb323 100644 --- a/lib/snmp/src/manager/snmpm_server.erl +++ b/lib/snmp/src/manager/snmpm_server.erl @@ -571,24 +571,6 @@ handle_call({sync_get, Pid, UserId, TargetName, Oids, SendOpts}, {reply, Error, State} end; -%% -%% The only case where this would be called is during code upgrade -handle_call({sync_get, - Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo}, - From, State) -> - ?vlog("[~p,~p,~p] received sync_get request for: " - "~n ~p", [UserId, TargetName, CtxName, Oids]), - case (catch handle_sync_get(Pid, - UserId, TargetName, CtxName, Oids, - Timeout, ExtraInfo, From, State)) of - ok -> - {noreply, State}; - Error -> - {reply, Error, State} - end; -%% - - handle_call({sync_get_next, Pid, UserId, TargetName, Oids, SendOpts}, From, State) -> ?vlog("[~p,~p] received sync_get_next request for: " @@ -603,24 +585,6 @@ handle_call({sync_get_next, Pid, UserId, TargetName, Oids, SendOpts}, end; -%% -%% The only case where this would be called is during code upgrade -handle_call({sync_get_next, - Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo}, - From, State) -> - ?vlog("[~p,~p,~p] received sync_get_next request for" - "~n ~p", [UserId, TargetName, CtxName, Oids]), - case (catch handle_sync_get_next(Pid, - UserId, TargetName, CtxName, Oids, - Timeout, ExtraInfo, From, State)) of - ok -> - {noreply, State}; - Error -> - {reply, Error, State} - end; -%% - - %% Check agent version? This op not in v1 handle_call({sync_get_bulk, Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts}, @@ -636,24 +600,6 @@ handle_call({sync_get_bulk, {reply, Error, State} end; -%% -%% The only case where this would be called is during code upgrade -handle_call({sync_get_bulk, Pid, UserId, TargetName, - NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo}, - From, State) -> - ?vlog("[~p,~p] received sync_get_bulk request for: ~p" - "~n ~p", [UserId, TargetName, CtxName, Oids]), - case (catch handle_sync_get_bulk(Pid, - UserId, TargetName, CtxName, - NonRep, MaxRep, Oids, - Timeout, ExtraInfo, From, State)) of - ok -> - {noreply, State}; - Error -> - {reply, Error, State} - end; -%% - handle_call({sync_set, Pid, UserId, TargetName, VarsAndVals, SendOpts}, @@ -670,24 +616,6 @@ handle_call({sync_set, end; -%% -%% The only case where this would be called is during code upgrade -handle_call({sync_set, Pid, UserId, TargetName, - CtxName, VarsAndVals, Timeout, ExtraInfo}, - From, State) -> - ?vlog("[~p,~p,~p] received sync_set request for: " - "~n ~p", [UserId, TargetName, CtxName, VarsAndVals]), - case (catch handle_sync_set(Pid, - UserId, TargetName, CtxName, VarsAndVals, - Timeout, ExtraInfo, From, State)) of - ok -> - {noreply, State}; - Error -> - {reply, Error, State} - end; -%% - - handle_call({async_get, Pid, UserId, TargetName, Oids, SendOpts}, _From, State) -> ?vlog("[~p,~p] received async_get request for: " @@ -698,19 +626,6 @@ handle_call({async_get, Pid, UserId, TargetName, Oids, SendOpts}, {reply, Reply, State}; -%% -%% The only case where this would be called is during code upgrade -handle_call({async_get, Pid, UserId, TargetName, - CtxName, Oids, Expire, ExtraInfo}, - _From, State) -> - ?vlog("[~p,~p,~p] received async_get request for: " - "~n ~p", [UserId, TargetName, CtxName, Oids]), - Reply = (catch handle_async_get(Pid, UserId, TargetName, CtxName, Oids, - Expire, ExtraInfo, State)), - {reply, Reply, State}; -%% - - handle_call({async_get_next, Pid, UserId, TargetName, Oids, SendOpts}, _From, State) -> ?vlog("[~p,~p] received async_get_next request for: " @@ -721,19 +636,6 @@ handle_call({async_get_next, Pid, UserId, TargetName, Oids, SendOpts}, {reply, Reply, State}; -%% -%% The only case where this would be called is during code upgrade -handle_call({async_get_next, Pid, UserId, TargetName, - CtxName, Oids, Expire, ExtraInfo}, - _From, State) -> - ?vlog("[~p,~p,~p] received async_get_next request for: ", - [UserId, TargetName, CtxName, Oids]), - Reply = (catch handle_async_get_next(Pid, UserId, TargetName, CtxName, - Oids, Expire, ExtraInfo, State)), - {reply, Reply, State}; -%% - - %% Check agent version? This op not in v1 handle_call({async_get_bulk, Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts}, @@ -747,21 +649,6 @@ handle_call({async_get_bulk, {reply, Reply, State}; -%% -%% The only case where this would be called is during code upgrade -handle_call({async_get_bulk, Pid, UserId, TargetName, - NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo}, - _From, State) -> - ?vlog("[~p,~p,~p] received async_get_bulk request for: " - "~n ~p", [UserId, TargetName, CtxName, Oids]), - Reply = (catch handle_async_get_bulk(Pid, - UserId, TargetName, CtxName, - NonRep, MaxRep, Oids, - Expire, ExtraInfo, State)), - {reply, Reply, State}; -%% - - handle_call({async_set, Pid, UserId, TargetName, VarsAndVals, SendOpts}, _From, State) -> @@ -773,19 +660,6 @@ handle_call({async_set, {reply, Reply, State}; -%% -%% The only case where this would be called is during code upgrade -handle_call({async_set, Pid, UserId, TargetName, - CtxName, VarsAndVals, Expire, ExtraInfo}, - _From, State) -> - ?vlog("[~p,~p,~p] received async_set request for: " - "~n ~p", [UserId, TargetName, CtxName, VarsAndVals]), - Reply = (catch handle_async_set(Pid, UserId, TargetName, CtxName, - VarsAndVals, Expire, ExtraInfo, State)), - {reply, Reply, State}; -%% - - handle_call({cancel_async_request, UserId, ReqId}, _From, State) -> ?vlog("received cancel_async_request request", []), Reply = (catch handle_cancel_async_request(UserId, ReqId, State)), @@ -1024,16 +898,6 @@ terminate(Reason, #state{nis_pid = NIS, gct = GCT, cbproxy = CBP}) -> %% %%---------------------------------------------------------------------- -handle_sync_get(Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo, - From, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Timeout}, - {extra, ExtraInfo} - ], - handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State). - handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) -> ?vtrace("handle_sync_get -> entry with" "~n Pid: ~p" @@ -1076,16 +940,6 @@ handle_sync_get(Pid, UserId, TargetName, Oids, SendOpts, From, State) -> Error end. -handle_sync_get_next(Pid, UserId, TargetName, CtxName, Oids, Timeout, - ExtraInfo, From, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Timeout}, - {extra, ExtraInfo} - ], - handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts, From, State). - handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts, From, State) -> ?vtrace("handle_sync_get_next -> entry with" @@ -1131,18 +985,6 @@ handle_sync_get_next(Pid, UserId, TargetName, Oids, SendOpts, end. -handle_sync_get_bulk(Pid, UserId, TargetName, CtxName, - NonRep, MaxRep, Oids, Timeout, - ExtraInfo, From, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Timeout}, - {extra, ExtraInfo} - ], - handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, - SendOpts, From, State). - handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, From, State) -> ?vtrace("handle_sync_get_bulk -> entry with" @@ -1190,17 +1032,6 @@ handle_sync_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, end. -handle_sync_set(Pid, UserId, TargetName, CtxName, VarsAndVals, Timeout, - ExtraInfo, From, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Timeout}, - {extra, ExtraInfo} - ], - handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, - From, State). - handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) -> ?vtrace("handle_sync_set -> entry with" "~n Pid: ~p" @@ -1245,16 +1076,6 @@ handle_sync_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, From, State) -> end. -handle_async_get(Pid, UserId, TargetName, CtxName, Oids, Expire, ExtraInfo, - State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Expire}, - {extra, ExtraInfo} - ], - handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State). - handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) -> ?vtrace("handle_async_get -> entry with" "~n Pid: ~p" @@ -1294,16 +1115,6 @@ handle_async_get(Pid, UserId, TargetName, Oids, SendOpts, State) -> end. -handle_async_get_next(Pid, UserId, TargetName, CtxName, Oids, Expire, - ExtraInfo, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Expire}, - {extra, ExtraInfo} - ], - handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State). - handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) -> ?vtrace("handle_async_get_next -> entry with" "~n Pid: ~p" @@ -1343,19 +1154,6 @@ handle_async_get_next(Pid, UserId, TargetName, Oids, SendOpts, State) -> end. -handle_async_get_bulk(Pid, UserId, TargetName, CtxName, - NonRep, MaxRep, Oids, Expire, - ExtraInfo, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Expire}, - {extra, ExtraInfo} - ], - handle_async_get_bulk(Pid, - UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, - State). - handle_async_get_bulk(Pid, UserId, TargetName, NonRep, MaxRep, Oids, SendOpts, State) -> @@ -1398,16 +1196,6 @@ handle_async_get_bulk(Pid, end. -handle_async_set(Pid, UserId, TargetName, CtxName, VarsAndVals, Expire, - ExtraInfo, State) -> - SendOpts = - [ - {context, CtxName}, - {timeout, Expire}, - {extra, ExtraInfo} - ], - handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State). - handle_async_set(Pid, UserId, TargetName, VarsAndVals, SendOpts, State) -> ?vtrace("handle_async_set -> entry with" "~n Pid: ~p" @@ -1549,14 +1337,14 @@ handle_snmp_error(#pdu{request_id = ReqId} = Pdu, Reason, State) -> _ -> %% reply to outstanding request, for which there is no %% longer any owner (the user has unregistered). - %% Therefor send it to the default user + %% Therefore send it to the default user case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State), maybe_delete(Disco, ReqId); _ -> - error_msg("failed retreiving the default user " + error_msg("failed retrieving the default user " "info handling error [~w]: " "~n~w", [ReqId, Reason]) end @@ -1604,7 +1392,7 @@ handle_snmp_error(#pdu{request_id = ReqId} = Pdu, Reason, State) -> handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); _ -> - error_msg("failed retreiving the default " + error_msg("failed retrieving the default " "user info handling error [~w]: " "~n~w",[ReqId, Reason]) end @@ -1636,7 +1424,7 @@ handle_snmp_error(Domain, Addr, ReqId, Reason, State) -> handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); _Error2 -> - error_msg("failed retreiving the default user " + error_msg("failed retrieving the default user " "info handling snmp error " "<~p,~p>: ~n~w~n~w", [Domain, Addr, ReqId, Reason]) @@ -1648,7 +1436,7 @@ handle_snmp_error(Domain, Addr, ReqId, Reason, State) -> handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); _Error4 -> - error_msg("failed retreiving the default user " + error_msg("failed retrieving the default user " "info handling snmp error " "<~p,~p>: ~n~w~n~w", [Domain, Addr, ReqId, Reason]) @@ -1721,7 +1509,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, _Error -> %% reply to outstanding request, for which there is no %% longer any owner (the user has unregistered). - %% Therefor send it to the default user + %% Therefore send it to the default user case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> handle_pdu( @@ -1730,7 +1518,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, ReqId, SnmpResponse, DefData, State), maybe_delete(Disco, ReqId); Error -> - error_msg("failed retreiving the default user " + error_msg("failed retrieving the default user " "info handling pdu from " "~p <~p,~p>: ~n~w~n~w", [Target, Domain, Addr, Error, Pdu]) @@ -1808,7 +1596,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); Error -> - error_msg("failed retreiving the default " + error_msg("failed retrieving the default " "user info handling (old) " "pdu from " "<~p,~p>: ~n~w~n~w", @@ -1835,7 +1623,7 @@ handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu, pdu, ignore, SnmpInfo, DefData, State); Error -> - error_msg("failed retreiving the default user " + error_msg("failed retrieving the default user " "info handling (old) pdu when no user " "found from " "<~p,~p>: ~n~w~n~w", @@ -2105,7 +1893,7 @@ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) -> Error1 -> %% User no longer exists, unregister agent - ?vlog("[trap] failed retreiving user info for " + ?vlog("[trap] failed retrieving user info for " "user ~p: " "~n ~p", [UserId, Error1]), case snmpm_config:unregister_agent(UserId, Target) of @@ -2120,7 +1908,7 @@ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) -> SnmpTrapInfo, DefData, State); Error2 -> error_msg( - "failed retreiving the default " + "failed retrieving the default " "user info handling report from " "~p <~p,~p>: ~n~w~n~w", [Target, Domain, Addr, @@ -2142,7 +1930,7 @@ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) -> Error4 -> %% Unknown agent, pass it on to the default user - ?vlog("[trap] failed retreiving user id for agent <~p,~p>: " + ?vlog("[trap] failed retrieving user id for agent <~p,~p>: " "~n Error: ~p" "~n when" "~n Users: ~p" @@ -2159,7 +1947,7 @@ do_handle_snmp_trap(SnmpTrapInfo, Domain, Addr, State) -> SnmpTrapInfo, DefData, State); Error5 -> error_msg( - "failed retreiving " + "failed retrieving " "the default user info, handling trap from <~p,~p>:" "~n Error: ~p" "~n Trap Info: ~p", @@ -2290,7 +2078,7 @@ handle_snmp_inform( case snmpm_config:unregister_agent(UserId, Target) of ok -> %% Try use the default user - ?vlog("[inform] failed retreiving user " + ?vlog("[inform] failed retrieving user " "info for user ~p:" "~n ~p", [UserId, Error1]), case snmpm_config:user_info() of @@ -2301,7 +2089,7 @@ handle_snmp_inform( inform, Ref, SnmpInform, DefData, State); Error2 -> - error_msg("failed retreiving the default " + error_msg("failed retrieving the default " "user info handling inform from " "~p <~p,~p>: ~n~w~n~w", [Target, Domain, Addr, @@ -2322,7 +2110,7 @@ handle_snmp_inform( Error4 -> %% Unknown agent, pass it on to the default user - ?vlog("[inform] failed retreiving user id for agent <~p,~p>: " + ?vlog("[inform] failed retrieving user id for agent <~p,~p>: " "~n ~p", [Domain, Addr, Error4]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> @@ -2332,7 +2120,7 @@ handle_snmp_inform( inform, Ref, SnmpInform, DefData, State); Error5 -> - error_msg("failed retreiving " + error_msg("failed retrieving " "the default user info handling inform from " "<~p,~p>: ~n~w~n~w", [Domain, Addr, Error5, Pdu]) @@ -2492,7 +2280,7 @@ handle_snmp_report( SnmpReport, Data, State); Error1 -> %% User no longer exists, unregister agent - ?vlog("[report] failed retreiving user info " + ?vlog("[report] failed retrieving user info " "for user ~p:" " ~n ~p", [UserId, Error1]), case snmpm_config:unregister_agent(UserId, Target) of @@ -2506,7 +2294,7 @@ handle_snmp_report( SnmpReport, DefData, State); Error2 -> - error_msg("failed retreiving the default " + error_msg("failed retrieving the default " "user info handling report from " "~p <~p,~p>: ~n~w~n~w", [Target, Domain, Addr, @@ -2527,7 +2315,7 @@ handle_snmp_report( Error4 -> %% Unknown agent, pass it on to the default user - ?vlog("[report] failed retreiving user id for agent <~p,~p>: " + ?vlog("[report] failed retrieving user id for agent <~p,~p>: " "~n ~p", [Domain, Addr, Error4]), case snmpm_config:user_info() of {ok, DefUserId, DefMod, DefData} -> @@ -2536,7 +2324,7 @@ handle_snmp_report( report, ignore, SnmpReport, DefData, State); Error5 -> - error_msg("failed retreiving " + error_msg("failed retrieving " "the default user info handling report from " "<~p,~p>: ~n~w~n~w", [Domain, Addr, Error5, Pdu]) @@ -2551,7 +2339,7 @@ handle_snmp_report(CrapReport, Domain, Addr, _State) -> %% This could be from a failed get-request, so we might have a user %% waiting for a reply here. If there is, we handle this as an failed -%% get-response (except for tha data which is different). Otherwise, +%% get-response (except for the data which is different). Otherwise, %% we handle it as an error (reported via the handle_error callback %% function). handle_snmp_report( @@ -2624,7 +2412,7 @@ handle_snmp_report( Data, State); Error -> %% Oh crap, use the default user - ?vlog("[report] failed retreiving user info for " + ?vlog("[report] failed retrieving user info for " "user ~p:" " ~n ~p", [UserId, Error]), case snmpm_config:user_info() of @@ -2632,7 +2420,7 @@ handle_snmp_report( handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); Error -> - error_msg("failed retreiving the " + error_msg("failed retrieving the " "default user " "info handling report from " "<~p,~p>: ~n~w~n~w~n~w", @@ -2642,7 +2430,7 @@ handle_snmp_report( end; Error -> %% Unknown agent, pass it on to the default user - ?vlog("[report] failed retreiving user id for " + ?vlog("[report] failed retrieving user id for " "agent <~p,~p>: " "~n ~p", [Domain, Addr, Error]), case snmpm_config:user_info() of @@ -2650,7 +2438,7 @@ handle_snmp_report( handle_error(DefUserId, DefMod, Reason, ReqId, DefData, State); Error -> - error_msg("failed retreiving " + error_msg("failed retrieving " "the default user info handling " "report from " "<~p,~p>: ~n~w~n~w~n~w", diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl index 7ba91b86e71f..08a70c6ca653 100644 --- a/lib/snmp/src/manager/snmpm_usm.erl +++ b/lib/snmp/src/manager/snmpm_usm.erl @@ -60,7 +60,7 @@ init() -> %% Func: process_incoming_msg(Packet, Data, SecParams, SecLevel) -> %% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} | %% {error, Reason} | {error, Reason, ErrorInfo} -%% Return value may be throwed. +%% Return value may be thrown. %% Types: Reason -> term() %% Purpose: %%----------------------------------------------------------------- @@ -331,7 +331,7 @@ try_decrypt(usmAesCfb128Protocol, %% SecData, SecLevel) -> %% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} | %% {error, Reason} | {error, Reason, ErrorInfo} -%% Return value may be throwed. +%% Return value may be thrown. %% Types: Reason -> term() %% Purpose: %%----------------------------------------------------------------- diff --git a/lib/snmp/src/misc/Makefile b/lib/snmp/src/misc/Makefile index eca2d949d25f..e92506e855b8 100644 --- a/lib/snmp/src/misc/Makefile +++ b/lib/snmp/src/misc/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2021. All Rights Reserved. +# Copyright Ericsson AB 2003-2022. 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. @@ -100,8 +100,8 @@ ERL_COMPILE_FLAGS += -I../../include \ # Targets # ---------------------------------------------------- -debug: - @$(MAKE) TYPE=debug opt +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt opt: $(TARGET_FILES) diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl index 39c18777c7e2..33db74e1e06f 100644 --- a/lib/snmp/src/misc/snmp_conf.erl +++ b/lib/snmp/src/misc/snmp_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -163,7 +163,7 @@ no_gen(_Dir, _R) -> []. no_order(_, _) -> true. no_filter(X) -> X. -%% Order tuples on element N with Keys first in appearence order. +%% Order tuples on element N with Keys first in appearance order. %% %% An ordering function (A, B) shall return true iff %% A is less than or equal to B i.e shall return @@ -924,7 +924,7 @@ check_transport_address(transportDomainUdpIpv4 = _Domain, when ?is_ipv4_addr(A0, A1, A2, A3) -> case PortInfo of system -> - %% The actual port number will be choosen + %% The actual port number will be chosen %% by the system (create with port = 0) %% when the socket is created. true; @@ -946,7 +946,7 @@ check_transport_address(transportDomainUdpIpv6 = _Domain, when ?is_ipv6_addr(A0, A1, A2, A3, A4, A5, A6, A7) -> case PortInfo of system -> - %% The actual port number will be choosen + %% The actual port number will be chosen %% by the system (create with port = 0) %% when the socket is created. true; diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl index 928b469c06b3..44a9044a2961 100644 --- a/lib/snmp/src/misc/snmp_config.erl +++ b/lib/snmp/src/misc/snmp_config.erl @@ -504,7 +504,7 @@ config_agent_transports(ID) -> config_agent_transports(ID, []). config_agent_transports(ID, []) -> - i(ID ++ ". Configure atleast one transport: "), + i(ID ++ ". Configure at least one transport: "), T = config_agent_transport(ID), config_agent_transports(ID, [T]); config_agent_transports(ID, Acc) -> @@ -1103,7 +1103,7 @@ verify_max_message_size(MMS) -> I when is_integer(I) andalso (I >= 484) -> {ok, I}; I when is_integer(I) -> - {error, "invalid max message size (must be atleast 484): " ++ MMS}; + {error, "invalid max message size (must be at least 484): " ++ MMS}; _ -> {error, "invalid max message size: " ++ MMS} end. @@ -1167,7 +1167,7 @@ verify_db_init_error(R) -> verify_notif_type("trap") -> {ok, trap}; verify_notif_type("inform") -> {ok, inform}; -verify_notif_type(NT) -> {error, "invalid notifcation type: " ++ NT}. +verify_notif_type(NT) -> {error, "invalid notification type: " ++ NT}. verify_sec_type("none") -> {ok, none}; @@ -2648,7 +2648,7 @@ write_sys_config_file_agent_config_opt(Fid, {verbosity, Verb}) -> ok = io:format(Fid, "{verbosity, ~w}", [Verb]). -%% This is only present if there is atleast one option +%% This is only present if there is at least one option write_sys_config_file_agent_atl_opts(Fid, [Opt]) -> write_sys_config_file_agent_atl_opt(Fid, Opt), ok = io:format(Fid, "]", []), @@ -2670,7 +2670,7 @@ write_sys_config_file_agent_atl_opt(Fid, {seqno, SeqNo}) -> ok = io:format(Fid, "{seqno, ~w}", [SeqNo]). -%% These options are allways there +%% These options are always there write_sys_config_file_agent_disco_opts(Fid, [Opt]) -> write_sys_config_file_agent_disco_opt(Fid, Opt), ok = io:format(Fid, "]", []), @@ -2776,7 +2776,7 @@ write_sys_config_file_manager_config_opt(Fid, {verbosity, Verb}) -> ok = io:format(Fid, "{verbosity, ~w}", [Verb]). -%% This is only present if there is atleast one option +%% This is only present if there is at least one option write_sys_config_file_manager_atl_opts(Fid, [Opt]) -> write_sys_config_file_manager_atl_opt(Fid, Opt), ok = io:format(Fid, "]", []), @@ -2807,7 +2807,7 @@ header() -> [?MODULE, ?version, Y, Mo, D, H, Mi, S]). -%% *If* these functions are successfull, they successfully return +%% *If* these functions are successful, they successfully return %% (value is ignored), but they fail preferably with %% throw({error, Reason}). Other exceptions are also handled. @@ -2862,7 +2862,7 @@ write_config_file(Dir, FileName, Order, Check, Write, Entries) end catch throw:E:S -> - d("File write of ~s throwed: " + d("File write of ~s thrown: " "~n ~p" "~n ~p" "~n", [FileName, E, S]), @@ -2881,7 +2881,7 @@ write_config_file(Dir, FileName, Write, Entries, Fd) -> close_config_file(Dir, FileName, Fd) catch throw:E:S -> - d("File write of ~s throwed: " + d("File write of ~s thrown: " "~n ~p" "~n ~p" "~n", [FileName, E, S]), @@ -2954,7 +2954,7 @@ append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) -> close_config_file(Dir, FileName, Fd) catch throw:E:S -> - d("File append of ~s throwed: " + d("File append of ~s thrown: " "~n ~p" "~n ~p" "~n", [FileName, E, S]), @@ -2997,7 +2997,7 @@ read_config_file(Dir, FileName, Order, Check) {ok, verify_lines(SortedLines, Check, undefined, [])} catch throw:E:S -> - d("File read of ~s throwed: " + d("File read of ~s thrown: " "~n ~p" "~n ~p" "~n", [FileName, E, S]), diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index 8a4dfa621b26..158883810fad 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2019. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -1068,7 +1068,7 @@ log_open2(Name, File, SeqNoGen, Size, Repair, Notify) -> end. -%% We need to make sure we do not end up in an infinit loop +%% We need to make sure we do not end up in an infinite loop %% Take the number of files of the wrap log and add 2 (for %% the index and size files). do_log_open(Name, File, {_, N} = Size, snmp_repair = _Repair, Notify) -> diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl index b02cf9d82e9f..18d5800651e6 100644 --- a/lib/snmp/src/misc/snmp_misc.erl +++ b/lib/snmp/src/misc/snmp_misc.erl @@ -492,7 +492,7 @@ format_pdu(PDU, MiniMib) when is_record(PDU, pdu) -> (T =:= 'get-bulk-request') -> ""; true -> - io_lib:format("*!*!* An error occured. *!*!* ~n" + io_lib:format("*!*!* An error occurred. *!*!* ~n" "Error status = ~w, index = ~w.~n", [ES, EI]) end, diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl index 606dd8ce4ffe..e842f3d3fab5 100644 --- a/lib/snmp/src/misc/snmp_note_store.erl +++ b/lib/snmp/src/misc/snmp_note_store.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -156,7 +156,7 @@ handle_call({set_note, Lifetime, Key, Value}, _From, {reply, Val, NState}; _Crap -> ?vinfo("handle_call(set_note) -> " - "failed retreiving system start time from ~w: " + "failed retrieving system start time from ~w: " "~n ~p", [Mod, _Crap]), {reply, {error, failed_retreive_system_start_time}, State} end; @@ -317,13 +317,13 @@ timer(Pid, passive, Timeout) -> ?MODULE:timer(Pid, passive, Timeout); activate -> - ?d("timer(deactive) -> activate request, send ack",[]), + ?d("timer(deactivate) -> activate request, send ack",[]), Pid ! activated, - ?d("timer(deactive) -> activate",[]), + ?d("timer(deactivate) -> activate",[]), ?MODULE:timer(Pid, active, Timeout) % code replacement after Timeout -> - ?d("timer(deactive) -> timeout",[]), + ?d("timer(deactivate) -> timeout",[]), ?MODULE:timer(Pid, passive, Timeout) end; timer(Pid, active, Timeout) -> diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl index 93f06749fd47..1967c7078d54 100644 --- a/lib/snmp/src/misc/snmp_pdus.erl +++ b/lib/snmp/src/misc/snmp_pdus.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -828,8 +828,8 @@ enint(N, Acc) -> enc_oct_str_tag(OStr) when is_list(OStr) -> lists:append([4|elength(length(OStr))],OStr); -enc_oct_str_tag(OBin) -> - [4 | elength(size(OBin))] ++ binary_to_list(OBin). +enc_oct_str_tag(OBin) when is_binary(OBin) -> + [4 | elength(byte_size(OBin))] ++ binary_to_list(OBin). enc_oct_str_notag(OStr) -> OStr. diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl index 9652e3a3ffc8..9c05c7d616f4 100644 --- a/lib/snmp/src/misc/snmp_usm.erl +++ b/lib/snmp/src/misc/snmp_usm.erl @@ -411,7 +411,7 @@ des_decrypt(PrivKey, MsgPrivParams, EncData) DesKey = [A,B,C,D,E,F,G,H], Salt = MsgPrivParams, IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)), - %% Whatabout errors here??? E.g. not a mulitple of 8! + %% Whatabout errors here??? E.g. not a multiple of 8! Data = binary_to_list(crypto:crypto_one_time(?BLOCK_CIPHER_DES, DesKey, IV, EncData, false)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), @@ -438,7 +438,7 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime) AesKey = PrivKey, Salt = MsgPrivParams, IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]), - %% Whatabout errors here??? E.g. not a mulitple of 8! + %% Whatabout errors here??? E.g. not a multiple of 8! Data = binary_to_list(crypto:crypto_one_time(?BLOCK_CIPHER_AES(AesKey), AesKey, IV, EncData, false)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile index e9bd50f6d875..8de1b1e80d8d 100644 --- a/lib/snmp/test/Makefile +++ b/lib/snmp/test/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2020. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -161,6 +161,7 @@ ERL_COMPILE_FLAGS += -I../../snmp/src/app \ +'{parse_transform,sys_pre_attributes}' \ +'{attribute,insert,app_vsn,$(APP_VSN)}' \ $(SNMP_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) ERL_SNMP_FLAGS = $(SNMP_MIB_FLAGS) \ -I../priv/mibs @@ -176,7 +177,7 @@ $(SNMP_BIN_TARGET_DIR)/%.hrl: $(SNMP_BIN_TARGET_DIR)/%.bin # Targets # ---------------------------------------------------- -tests debug opt: $(BUILDTARGET) +tests $(TYPES): $(BUILDTARGET) .PHONY: emakebuild diff --git a/lib/snmp/test/exp/snmp_agent_bl_test.erl b/lib/snmp/test/exp/snmp_agent_bl_test.erl deleted file mode 100644 index 943426d8c2cb..000000000000 --- a/lib/snmp/test/exp/snmp_agent_bl_test.erl +++ /dev/null @@ -1,5634 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_bl_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - -% -include_lib("kernel/include/file.hrl"). -% -include("test_server.hrl"). -% -include("snmp_test_lib.hrl"). -% -define(SNMP_USE_V3, true). -% -include_lib("snmp/include/snmp_types.hrl"). - -%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). - - -% -define(klas1, [1,3,6,1,2,1,7]). -% -define(klas2, [1,3,6,1,2,1,9]). -% -define(klas3, [1,3,6,1,2,1,8,1]). -% -define(klas4, [1,3,6,1,2,1,8,4]). -% -define(sa, [1,3,6,1,4,1,193,2]). -% -define(system, [1,3,6,1,2,1,1]). -% -define(snmp, [1,3,6,1,2,1,11]). -% -define(snmpTraps, [1,3,6,1,6,3,1,1,5]). -% -define(ericsson, [1,3,6,1,4,1,193]). -% -define(testTrap, [1,3,6,1,2,1,15,0]). -% -define(xDescr, [1,3,6,1,2,1,17,1]). -% -define(xDescr2, [1,3,6,1,2,1,17,2]). - -% -define(active, 1). -% -define(notInService, 2). -% -define(notReady, 3). -% -define(createAndGo, 4). -% -define(createAndWait, 5). -% -define(destroy, 6). - -% -define(TRAP_UDP, 5000). - -% -define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - --define(str(X), snmp_pdus:bits_to_str(X)). - --define(break(), begin io:format(user, "break at line ~w: pid: ~p\n", - [?LINE, self()]), - receive cont -> ok end - end). - - --import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]). --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all(suite) -> {req, - [mnesia, distribution, - {local_slave_nodes, 2}, {time, 360}], - [{conf, init_all, cases(), finish_all}]}. - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [ - app_info, - test_v1, test_v2, test_v1_v2, test_v3, - test_multi_threaded, - mib_storage, - tickets - ]. - - -%%%----------------------------------------------------------------- -%%% The test case structure is as follows: -%%% -%%% init_all - starts mnesia, -%%% -%%% init_v1 - starts agent -%%% simple -%%% big - e.g. starts/stops subagent, load/unloads mibs -%%% init_mul -%%% mul_get -%%% mul_set -%%% -%%% finish_mul -%%% -%%% finish_v1 -%%% -%%% init_v2 - starts agent -%%% finish_v2 -%%% -%%% init_bilingual - starts agent -%%% finish_bilingual -%%% -%%% finish_all -%%% -%%% There is still one problem with these testsuites. If one test -%%% fails, it may not be possible to run some other cases, as it -%%% may have e.g. created some row or loaded some table, that it -%%% didn't undo (since it failed). -%%%----------------------------------------------------------------- - -init_all(Config0) when list(Config0) -> - ?LOG("init_all -> entry with" - "~n Config0: ~p",[Config0]), - - %% -- - %% Fix config: - %% - - DataDir0 = ?config(data_dir, Config0), - DataDir1 = filename:split(filename:absname(DataDir0)), - [_|DataDir2] = lists:reverse(DataDir1), - DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), - Config1 = lists:keydelete(data_dir, 1, Config0), - Config = [{data_dir, DataDir3 ++ "/"}|Config1], - - %% -- - %% Start nodes - %% - - ?line {ok, SaNode} = start_node(snmp_sa), - ?line {ok, MgrNode} = start_node(snmp_mgr), - - - %% -- - %% Create necessary files - %% - - Dir = ?config(priv_dir, Config), - ?DBG("init_all -> Dir ~p", [Dir]), - - DataDir = ?config(data_dir, Config), - ?DBG("init_all -> DataDir ~p", [DataDir]), - - file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")), - ?DBG("init_all -> MgrDir ~p", [MgrDir]), - - file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")), - ?DBG("init_all -> AgentDir ~p", [AgentDir]), - - file:make_dir(SaDir = filename:join(Dir, "sa_dir/")), - ?DBG("init_all -> SaDir ~p", [SaDir]), - - - %% -- - %% Start and initiate mnesia - %% - - ?DBG("init_all -> load application mnesia", []), - ?line ok = application:load(mnesia), - - ?DBG("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), - - ?DBG("init_all -> application mnesia: set_env dir",[]), - ?line application_controller:set_env(mnesia, dir, - filename:join(Dir, "Mnesia1")), - - ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(Dir, "Mnesia2")]), - - ?DBG("init_all -> create mnesia schema",[]), - ?line ok = mnesia:create_schema([SaNode, node()]), - - ?DBG("init_all -> start application mnesia",[]), - ?line ok = application:start(mnesia), - - ?DBG("init_all -> start application mnesia on ~p",[SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), - Ip = ?LOCALHOST(), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, - {agent_dir, AgentDir ++ "/"}, - {mgr_dir, MgrDir ++ "/"}, - {sa_dir, SaDir ++ "/"}, - {mib_dir, DataDir}, - {ip, Ip} | - Config]. - -finish_all(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - stop_node(SaNode), - stop_node(MgrNode), - application:stop(mnesia). - -start_v1_agent(Config) when list(Config) -> - start_agent(Config, [v1]). - -start_v1_agent(Config,Opts) when list(Config), list(Opts) -> - start_agent(Config, [v1], Opts). - -start_v2_agent(Config) when list(Config) -> - start_agent(Config, [v2]). - -start_v3_agent(Config) when list(Config) -> - start_agent(Config, [v3]). - -start_bilingual_agent(Config) when list(Config) -> - start_agent(Config, [v1,v2]). - -start_multi_threaded_agent(Config) when list(Config) -> - start_agent(Config, [v2], [{snmp_multi_threaded, true}]). - -stop_agent(Config) when list(Config) -> - ?LOG("stop_agent -> entry with" - "~n Config: ~p",[Config]), - - {Sup, Par} = ?config(snmp_sup, Config), - ?DBG("stop_agent -> attempt to stop (sup) ~p" - "~n Sup: ~p" - "~n Par: ~p", - [Sup, - (catch process_info(Sup)), - (catch process_info(Par))]), - stop_sup(Sup, Par), - - {Sup2, Par2} = ?config(snmp_sub, Config), - ?DBG("stop_agent -> attempt to stop (sub) ~p" - "~n Sup2: ~p" - "~n Par2: ~p", - [Sup2, - (catch process_info(Sup2)), - (catch process_info(Par2))]), - stop_sup(Sup2, Par2), - - ?DBG("stop_agent -> done - now cleanup config", []), - C1 = lists:keydelete(snmp_sup, 1, Config), - lists:keydelete(snmp_sub, 1, C1). - - -stop_sup(Pid, _) when node(Pid) == node() -> - case (catch process_info(Pid)) of - PI when list(PI) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - exit(Pid, kill), - await_stopped(Pid, Ref); - {'EXIT', _Reason} -> - ?LOG("stop_sup -> ~p not running", [Pid]), - ok - end; -stop_sup(Pid, _) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - ?LOG("stop_sup -> Ref: ~p", [Ref]), - %% Pid ! {'EXIT', Parent, shutdown}, % usch - exit(Pid, kill), - await_stopped(Pid, Ref). - -await_stopped(Pid, Ref) -> - receive - {'DOWN', Ref, process, Pid, _Reason} -> - ?DBG("received down message for ~p", [Pid]), - ok - after 10000 -> - ?INF("await_stopped -> timeout for ~p",[Pid]), - erlang:demonitor(Ref), - ?FAIL({failed_stop,Pid}) - end. - - -start_agent(Config, Vsn) -> - start_agent(Config, Vsn, []). -start_agent(Config, Vsn, Opts) -> - ?LOG("start_agent -> entry (~p) with" - "~n Config: ~p" - "~n Vsn: ~p" - "~n Opts: ~p",[node(), Config, Vsn, Opts]), - - ?line AgentDir = ?config(agent_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - - snmp_app_env_init(vsn_init(Vsn) ++ - [{audit_trail_log, read_write_log}, - {audit_trail_log_dir, AgentDir}, - {audit_trail_log_size, {10240, 10}}, - {force_config_reload, false}, - {snmp_agent_type, master}, - {snmp_config_dir, AgentDir}, - {snmp_db_dir, AgentDir}, - {snmp_local_db_auto_repair, true}, - {snmp_master_agent_verbosity, trace}, - {snmp_supervisor_verbosity, trace}, - {snmp_mibserver_verbosity, trace}, - {snmp_symbolic_store_verbosity, trace}, - {snmp_note_store_verbosity, trace}, - {snmp_net_if_verbosity, trace}], - Opts), - - - process_flag(trap_exit,true), - - {ok, AppSup} = snmp_app_sup:start_link(), - unlink(AppSup), - ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]), - - ?DBG("start_agent -> start master agent (old style)",[]), - Sup = case (catch snmpa_app:start(normal)) of - {ok, S} -> - ?DBG("start_agent -> started, Sup: ~p",[S]), - S; - - Else -> - ?DBG("start_agent -> unknown result: ~n~p",[Else]), - %% Get info about the apps we depend on - MnesiaInfo = mnesia_running(), - ?FAIL({start_failed,Else,MnesiaInfo}) - end, - - ?DBG("start_agent -> unlink from supervisor",[]), - ?line unlink(Sup), - ?line SaDir = ?config(sa_dir, Config), - ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]), - ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]), - ?DBG("start_agent -> done",[]), - ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. - - -vsn_init(Vsn) -> - vsn_init([v1,v2,v3], Vsn, []). - -vsn_init([], _Vsn, Acc) -> - Acc; -vsn_init([V|Vsns], Vsn, Acc) -> - case lists:member(V, Vsn) of - true -> - vsn_init(Vsns, Vsn, [{V, true}|Acc]); - false -> - vsn_init(Vsns, Vsn, [{V, false}|Acc]) - end. - -snmp_app_env_init(Env0, Opts) -> - ?DBG("snmp_app_env_init -> unload snmp",[]), - ?line application:unload(snmp), - ?DBG("snmp_app_env_init -> load snmp",[]), - ?line application:load(snmp), - ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]), - F1 = fun({Key,Val} = New, Acc0) -> - ?DBG("snmp_app_env_init -> " - "updating setting ~p to ~p", [Key, Val]), - case lists:keyreplace(Key, 1, Acc0, New) of - Acc0 -> - [New|Acc0]; - Acc -> - Acc - end - end, - Env = lists:foldr(F1, Env0, Opts), - ?DBG("snmp_app_env_init -> Env: ~p",[Env]), - F2 = fun({Key,Val}) -> - ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]), - application_controller:set_env(snmp, Key, Val) - end, - lists:foreach(F2, Env). - - - - -%% Test if application is running -mnesia_running() -> ?IS_MNESIA_RUNNING(). -crypto_running() -> ?IS_CRYPTO_RUNNING(). - - -start_sub(Dir) -> - ?DBG("start_sub -> entry",[]), - Opts = [{db_dir, Dir}, - {supervisor, [{verbosity, trace}]}], - %% BMK BMK -% {ok, P} = snmp_supervisor:start_sub(Dir), - {ok, P} = snmpa_supervisor:start_sub_sup(Opts), - unlink(P), - {ok, {P, self()}}. - -create_tables(SaNode) -> - ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, - {attributes, [a1,a2]}]). - -delete_tables() -> - mnesia:delete_table(friendsTable2), - mnesia:delete_table(kompissTable2), - mnesia:delete_table(snmp_variables). - -%% Creation is done in runtime! -delete_mib_storage_mnesia_tables() -> - mnesia:delete_table(snmpa_mib_data), - mnesia:delete_table(snmpa_mib_tree), - mnesia:delete_table(snmpa_symbolic_store). - -%%----------------------------------------------------------------- -%% A test case is always one of: -%% - v1 specific case -%% - v2 specific case -%% - v1 and v2 case -%% All v1 specific cases are prefixed with v1_, and all v2 with -%% v2_. E.g. v1_trap/v2_trap. -%% -%% All other cases are shared. However, the testserver uses the name -%% of the case to generate a file for that case. The same case cannot -%% be used in different configurations in the same suite. Therefore -%% all these functions exists in two variants, the base function -%% , and a second version _2. There may be several -%% versions as well, _N. -%%----------------------------------------------------------------- -mib_storage(suite) -> [ - mib_storage_ets, - mib_storage_dets, - mib_storage_mnesia, - mib_storage_size_check_ets, - mib_storage_size_check_dets, - mib_storage_size_check_mnesia, - mib_storage_varm_dets, - mib_storage_varm_mnesia - ]. - -mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets, - mib_storage_ets_cases(), - finish_mib_storage_ets}}. - -mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets, - mib_storage_dets_cases(), - finish_mib_storage_dets}}. - -mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia, - mib_storage_mnesia_cases(), - finish_mib_storage_mnesia}}. - -mib_storage_size_check_ets(suite) -> - {req, [], {conf, - init_size_check_mse, - mse_size_check_cases(), - finish_size_check_mse}}. - -mib_storage_size_check_dets(suite) -> - {req, [], {conf, - init_size_check_msd, - msd_size_check_cases(), - finish_size_check_msd}}. - -mib_storage_size_check_mnesia(suite) -> - {req, [], {conf, - init_size_check_msm, - msm_size_check_cases(), - finish_size_check_msm}}. - -mib_storage_varm_dets(suite) -> - {req, [], {conf, - init_varm_mib_storage_dets, - varm_mib_storage_dets_cases(), - finish_varm_mib_storage_dets}}. - -mib_storage_varm_mnesia(suite) -> - {req, [], {conf, - init_varm_mib_storage_mnesia, - varm_mib_storage_mnesia_cases(), - finish_varm_mib_storage_mnesia}}. - -mib_storage_ets_cases() -> - [ - mse_simple, - mse_v1_processing, - mse_big, - mse_big2, - mse_loop_mib, - mse_api, - mse_sa_register, - mse_v1_trap, - mse_sa_error, - mse_next_across_sa, - mse_undo, - mse_standard_mib, - mse_community_mib, - mse_framework_mib, - mse_target_mib, - mse_notification_mib, - mse_view_based_acm_mib, - mse_sparse_table, - mse_me_of, - mse_mib_of]. - -mib_storage_dets_cases() -> - [ - msd_simple, - msd_v1_processing, - msd_big, - msd_big2, - msd_loop_mib, - msd_api, - msd_sa_register, - msd_v1_trap, - msd_sa_error, - msd_next_across_sa, - msd_undo, - msd_standard_mib, - msd_community_mib, - msd_framework_mib, - msd_target_mib, - msd_notification_mib, - msd_view_based_acm_mib, - msd_sparse_table, - msd_me_of, - msd_mib_of - ]. - -mib_storage_mnesia_cases() -> - [ - msm_simple, - msm_v1_processing, - msm_big, - msm_big2, - msm_loop_mib, - msm_api, - msm_sa_register, - msm_v1_trap, - msm_sa_error, - msm_next_across_sa, - msm_undo, - msm_standard_mib, - msm_community_mib, - msm_framework_mib, - msm_target_mib, - msm_notification_mib, - msm_view_based_acm_mib, - msm_sparse_table, - msm_me_of, - msm_mib_of - ]. - -mse_size_check_cases() -> - [mse_size_check]. - -msd_size_check_cases() -> - [msd_size_check]. - -msm_size_check_cases() -> - [msm_size_check]. - -varm_mib_storage_dets_cases() -> - [msd_varm_mib_start]. - -varm_mib_storage_mnesia_cases() -> - [msm_varm_mib_start]. - -init_mib_storage_ets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,ets}, - init_ms(Config, [MibStorage]). - -init_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - init_ms(Config, [MibStorage]). - -init_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - init_ms(Config, [MibStorage]). - -init_ms(Config, Opts) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts], - [{vsn, v1} | start_v1_agent(Config,Opts1)]. - -init_size_check_mse(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, ets}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msd(Config) when list(Config) -> - AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage, {dets, AgentDir}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msm(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, {mnesia,[]}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_ms(Config, Opts) when list(Config) -> - SaNode = ?GCONF(snmp_sa, Config), - %% We are using v3 here, so crypto must be supported or else... - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - create_tables(SaNode), - AgentDir = ?GCONF(agent_dir, Config), - MgrDir = ?GCONF(mgr_dir, Config), - Ip = ?GCONF(ip, Config), - ?line ok = - config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_agent(Config, [v3], Opts)]. - -init_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_dets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -init_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_mnesia -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -finish_mib_storage_ets(Config) when list(Config) -> - ?LOG("finish_mib_storage_ets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_mib_storage_dets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_dets -> entry", []), - delete_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_size_check_mse(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msd(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msm(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_ms(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%% These are just interface functions to fool the test server -mse_simple(X) -> simple(X). -mse_v1_processing(X) -> v1_processing(X). -mse_big(X) -> big(X). -mse_big2(X) -> big2(X). -mse_loop_mib(X) -> loop_mib(X). -mse_api(X) -> api(X). -mse_sa_register(X) -> sa_register(X). -mse_v1_trap(X) -> v1_trap(X). -mse_sa_error(X) -> sa_error(X). -mse_next_across_sa(X) -> next_across_sa(X). -mse_undo(X) -> undo(X). -mse_standard_mib(X) -> snmp_standard_mib(X). -mse_community_mib(X) -> snmp_community_mib(X). -mse_framework_mib(X) -> snmp_framework_mib(X). -mse_target_mib(X) -> snmp_target_mib(X). -mse_notification_mib(X) -> snmp_notification_mib(X). -mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -mse_sparse_table(X) -> sparse_table(X). -mse_me_of(X) -> ms_me_of(X). -mse_mib_of(X) -> ms_mib_of(X). - -msd_simple(X) -> simple(X). -msd_v1_processing(X) -> v1_processing(X). -msd_big(X) -> big(X). -msd_big2(X) -> big2(X). -msd_loop_mib(X) -> loop_mib(X). -msd_api(X) -> api(X). -msd_sa_register(X) -> sa_register(X). -msd_v1_trap(X) -> v1_trap(X). -msd_sa_error(X) -> sa_error(X). -msd_next_across_sa(X) -> next_across_sa(X). -msd_undo(X) -> undo(X). -msd_standard_mib(X) -> snmp_standard_mib(X). -msd_community_mib(X) -> snmp_community_mib(X). -msd_framework_mib(X) -> snmp_framework_mib(X). -msd_target_mib(X) -> snmp_target_mib(X). -msd_notification_mib(X) -> snmp_notification_mib(X). -msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msd_sparse_table(X) -> sparse_table(X). -msd_me_of(X) -> ms_me_of(X). -msd_mib_of(X) -> ms_mib_of(X). - -msm_simple(X) -> simple(X). -msm_v1_processing(X) -> v1_processing(X). -msm_big(X) -> big(X). -msm_big2(X) -> big2(X). -msm_loop_mib(X) -> loop_mib(X). -msm_api(X) -> api(X). -msm_sa_register(X) -> sa_register(X). -msm_v1_trap(X) -> v1_trap(X). -msm_sa_error(X) -> sa_error(X). -msm_next_across_sa(X) -> next_across_sa(X). -msm_undo(X) -> undo(X). -msm_standard_mib(X) -> snmp_standard_mib(X). -msm_community_mib(X) -> snmp_community_mib(X). -msm_framework_mib(X) -> snmp_framework_mib(X). -msm_target_mib(X) -> snmp_target_mib(X). -msm_notification_mib(X) -> snmp_notification_mib(X). -msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msm_sparse_table(X) -> sparse_table(X). -msm_me_of(X) -> ms_me_of(X). -msm_mib_of(X) -> ms_mib_of(X). - - -mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X). -msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X). -msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X). - -msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X). -msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X). - -ms_size_check(suite) -> []; -ms_size_check(Config) when list(Config) -> - p("ms_size_check..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?LOG("mib server size check...", []), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - - -varm_mib_start(suite) -> []; -varm_mib_start(Config) when list(Config) -> - p("varm_mib_start..."), - ?LOG("varm_mib_start -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - %% Start the agent - Opts = ?GCONF(agent_opts, Config), - Config1 = start_v1_agent(Config, Opts), - - %% Sleep some in order for the agent to start properly - ?DBG("varm_mib_start -> sleep some (before loading mobs)", []), - ?SLEEP(5000), - - %% Load all the mibs - HardwiredMibs = loaded_mibs(), - ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - - %% Unload the hardwired mibs - ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), - ?SLEEP(1000), - ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired - - ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), - ?SLEEP(1000), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - Config2 = stop_agent(Config1), - - %% Sleep some in order for the agent to stop properly - ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []), - ?SLEEP(5000), - - %% Start the agent (again) - ?DBG("varm_mib_start -> start the agent", []), - Config3 = start_v1_agent(Config2, Opts), - - ?DBG("varm_mib_start -> sleep some (before starting tests)", []), - ?SLEEP(5000), - - %% Perform the test(s) - ?DBG("varm_mib_start -> perform the tests", []), - try_test(snmp_community_mib), - try_test(snmp_framework_mib), - try_test(snmp_target_mib), - try_test(snmp_notification_mib), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - stop_agent(Config3), - ok. - - --define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]). --define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). --define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -ms_me_of(suite) -> []; -ms_me_of(Config) when list(Config) -> - p("ms_me_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -me_of(Oid) -> - case snmpa:me_of(Oid) of - {ok, #me{oid = Oid}} -> - ok; - {ok, #me{oid = OtherOid}} -> - case lists:reverse(Oid) of - [0|Rest] -> - case lists:reverse(Rest) of - OtherOid -> - ok; - AnotherOid -> - {error, {invalid_oid, Oid, AnotherOid}} - end; - _ -> - {error, {invalid_oid, Oid, OtherOid}} - end; - {error, Reason} -> - {error, Reason}; - Else -> - {error, Else} - end. - - -ms_mib_of(suite) -> []; -ms_mib_of(Config) when list(Config) -> - p("ms_mib_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, - 'SNMP-USER-BASED-SM-MIB'), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -mib_of(Oid, ExpectedMibName) -> - ?DBG("mib_of -> entry with" - "~n Oid: ~p" - "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]), - %% case snmpa:mib_of(Oid) of - MibOf = snmpa:mib_of(Oid), - ?DBG("mib_of -> MibOf: ~n~p", [MibOf]), - case MibOf of - {ok, ExpectedMibName} -> - ok; - {ok, OtherMibName} -> - {error, {invalid_mib, ExpectedMibName, OtherMibName}}; - {error, Reason} -> - {error, Reason}; - Else -> - ?DBG("mib_of -> Else: ~n~p", [Else]), - {error, Else} - end. - - -app_info(suite) -> []; -app_info(Config) when list(Config) -> - SnmpDir = app_dir(snmp), - SslDir = app_dir(ssl), - CryptoDir = app_dir(crypto), - Attr = snmp:module_info(attributes), - AppVsn = - case lists:keysearch(app_vsn, 1, Attr) of - {value, {app_vsn, V}} -> - V; - false -> - "undefined" - end, - io:format("Root dir: ~s~n" - "SNMP: Application dir: ~s~n" - " Application ver: ~s~n" - "SSL: Application dir: ~s~n" - "CRYPTO: Application dir: ~s~n", - [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]), - ok. - -app_dir(App) -> - case code:lib_dir(App) of - D when list(D) -> - filename:basename(D); - {error, _Reason} -> - "undefined" - end. - - -test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}. - -%v1_cases() -> [loop_mib]; -v1_cases() -> - [simple, - db_notify_client, - v1_processing, big, big2, loop_mib, - api, subagent, mnesia, multiple_reqs, - sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs, - standard_mibs, sparse_table, cnt_64, - opaque, - % opaque]. - - change_target_addr_config]. - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}. - -%v2_cases() -> [loop_mib_2]; -v2_cases() -> - [simple_2, v2_processing, big_2, big2_2, loop_mib_2, - api_2, subagent_2, mnesia_2, - multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2, - next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2, - v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps]. - -init_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_v2_agent(Config)]. - -finish_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}. - -v1_v2_cases() -> - [simple_bi]. - -init_v1_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, bilingual} | start_bilingual_agent(Config)]. - -finish_v1_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}. - -%v3_cases() -> [loop_mib_3]; -v3_cases() -> - [simple_3, v3_processing, - big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3, - multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3, - next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3, - v3_security, - v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3]. - -init_v3(Config) when list(Config) -> - %% Make sure crypto works, otherwise start_agent will fail - %% and we will be stuck with a bunch of mnesia tables for - %% the rest of this suite... - ?DBG("start_agent -> start crypto app",[]), - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. - -finish_v3(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}. - -mt_cases() -> - [multi_threaded, mt_trap]. - -init_mt(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. - -finish_mt(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -%% This one *must* be run first in each case. -init_case(Config) when list(Config) -> - ?DBG("init_case -> entry with" - "~n Config: ~p", [Config]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - MasterNode = node(), - - SaHost = ?HOSTNAME(SaNode), - MgrHost = ?HOSTNAME(MgrNode), - MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), - - - put(mgr_node, MgrNode), - put(sa_node, SaNode), - put(master_node, MasterNode), - put(sa_host, SaHost), - put(mgr_host, MgrHost), - put(master_host, MasterHost), - put(mip, tuple_to_list(MIP)), - put(masterip , tuple_to_list(MasterIP)), - put(sip, tuple_to_list(SIP)), - - MibDir = ?config(mib_dir, Config), - put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - put(std_mib_dir, StdM), - - MgrDir = ?config(mgr_dir, Config), - put(mgr_dir, MgrDir), - - put(vsn, ?config(vsn, Config)), - ?DBG("init_case -> exit with" - "~n MasterNode: ~p" - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]), - {SaNode, MgrNode, MibDir}. - -load_master(Mib) -> - ?DBG("load_master -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). - -load_master_std(Mib) -> - ?DBG("load_master_std -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). - -unload_master(Mib) -> - ?DBG("unload_master -> entry with" - "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). - -loaded_mibs() -> - ?DBG("loaded_mibs -> entry",[]), - Info = snmpa:info(snmp_master_agent), - {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info), - [atom_to_list(Mib) || {Mib,_,_} <- Mibs]. - -unload_mibs(Mibs) -> - ?DBG("unload_mibs -> entry with" - "~n Mibs: ~p", [Mibs]), - ok = snmpa:unload_mibs(snmp_master_agent, Mibs). - -start_subagent(SaNode, RegTree, Mib) -> - ?DBG("start_subagent -> entry with" - "~n SaNode: ~p" - "~n RegTree: ~p" - "~n Mib: ~p", [SaNode, RegTree, Mib]), - MA = whereis(snmp_master_agent), - ?DBG("start_subagent -> MA: ~p", [MA]), - MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), - %% BMK BMK -% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of - case rpc:call(SaNode, snmpa_supervisor, - start_sub_agent, [MA, RegTree, [Mib1]]) of - {ok, SA} -> - ?DBG("start_subagent -> SA: ~p", [SA]), - {ok, SA}; - Error -> - ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]}) - end. - -stop_subagent(SA) -> - ?DBG("stop_subagent -> entry with" - "~n SA: ~p", [SA]), - %% BNK BMK - %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]). - rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]). - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - - -simple(suite) -> []; -simple(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(simple_standard_test). - -simple_2(X) -> simple(X). - -simple_bi(suite) -> []; -simple_bi(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(vsn, v1), % First, try v1 manager - try_test(simple_standard_test), - - put(vsn, v2), % Then, try v2 manager - try_test(simple_standard_test). - -simple_3(X) -> - simple(X). - -big(suite) -> []; -big(Config) when list(Config) -> - ?DBG("big -> entry", []), - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -big_2(X) -> big(X). - -big_3(X) -> big(X). - - -big2(suite) -> []; -big2(Config) when list(Config) -> - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - -big2_2(X) -> big2(X). - -big2_3(X) -> big2(X). - - -multi_threaded(suite) -> []; -multi_threaded(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(multi_threaded_test), - ?line unload_master("Test1"). - -mt_trap(suite) -> []; -mt_trap(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). - -v2_types(suite) -> []; -v2_types(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(types_v2_test), - ?line unload_master("Test1"). - -v2_types_3(X) -> v2_types(X). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(implied_test,[MA]), - ?line unload_master("Test1"). - -implied_3(X) -> implied(X). - - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(sparse_table_test), - ?line unload_master("Test1"). - -sparse_table_2(X) -> sparse_table(X). - -sparse_table_3(X) -> sparse_table(X). - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -cnt_64_2(X) -> cnt_64(X). - -cnt_64_3(X) -> cnt_64(X). - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(opaque_test), - ?line unload_master("Test1"). - -opaque_2(X) -> opaque(X). - -opaque_3(X) -> opaque(X). - - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - try_test(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -api(suite) -> []; -api(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -api_2(X) -> api(X). - -api_3(X) -> api(X). - - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - try_test(load_test_sa), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - - p("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - try_test(load_test), - - p("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - try_test(unreg_test), - p("Testing register subagent..."), - rpc:call(SaNode, snmp, register_subagent, - [MA, ?klas1, SA]), - try_test(load_test_sa), - - ?line stop_subagent(SA), - try_test(unreg_test). - -subagent_2(X) -> subagent(X). - -subagent_3(X) -> subagent(X). - - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - try_test(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - -mnesia_2(X) -> mnesia(X). - -mnesia_3(X) -> mnesia(X). - - -multiple_reqs(suite) -> - {req, [], {conf, init_mul, mul_cases(), finish_mul}}. - -mul_cases() -> - [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err]. - -multiple_reqs_2(suite) -> - {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}. - -multiple_reqs_3(_X) -> - {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}. - - -mul_cases_2() -> - [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2]. - - -mul_cases_3() -> - [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3]. - - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - try_test(do_mul_get). - -mul_get_2(X) -> mul_get(X). - -mul_get_3(X) -> mul_get(X). - - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - try_test(do_mul_get_err). - -mul_get_err_2(X) -> mul_get_err(X). - -mul_get_err_3(X) -> mul_get_err(X). - - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next). - -mul_next_2(X) -> mul_next(X). - -mul_next_3(X) -> mul_next(X). - - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next_err). - -mul_next_err_2(X) -> mul_next_err(X). - -mul_next_err_3(X) -> mul_next_err(X). - - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set..."), - try_test(do_mul_set). - -mul_set_2(X) -> mul_set(X). - -mul_set_3(X) -> mul_set(X). - - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set with error..."), - try_test(do_mul_set_err). - -mul_set_err_2(X) -> mul_set_err(X). - -mul_set_err_3(X) -> mul_set_err(X). - - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?DBG("sa_register -> entry", []), - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - p("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - try_test(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -sa_register_2(X) -> sa_register(X). - -sa_register_3(X) -> sa_register(X). - - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_trap1, [MA]), - try_test(ma_trap2, [MA]), - try_test(ma_v2_2_v1_trap, [MA]), - try_test(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - try_test(sa_trap1, [SA]), - try_test(sa_trap2, [SA]), - try_test(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v2_trap(suite) -> []; -v2_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - - try_test(ma_v2_trap1, [MA]), - try_test(ma_v2_trap2, [MA]), - try_test(ma_v1_2_v2_trap, [MA]), - try_test(ma_v1_2_v2_trap2, [MA]), - - try_test(sa_mib), - p("Testing trap sending from subagent..."), - try_test(sa_v1_2_v2_trap1, [SA]), - try_test(sa_v1_2_v2_trap2, [SA]), - try_test(sa_v1_2_v2_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v3_trap(X) -> - v2_trap(X). - -v2_inform(suite) -> - {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}. - -v3_inform(_X) -> - %% v2_inform(X). - {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}. - -init_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -init_v3_inform(X) -> - init_v2_inform(X). - -finish_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -finish_v3_inform(X) -> - finish_v2_inform(X). - - - -v2_inform_i(suite) -> []; -v2_inform_i(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing inform sending from master agent... NOTE! This test\ntakes a " - "few minutes (5) to complete."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_v2_inform1, [MA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"). - -v3_inform_i(X) -> v2_inform_i(X). - - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - try_test(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - try_test(sa_errs_gen_err), - - p("Testing too big..."), - try_test(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -sa_error_2(X) -> sa_error(X). - -sa_error_3(X) -> sa_error(X). - - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - try_test(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - try_test(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - try_test(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -next_across_sa_2(X) -> next_across_sa(X). - -next_across_sa_3(X) -> next_across_sa(X). - - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - try_test(undo_test), - try_test(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - try_test(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - try_test(undo_test), - try_test(api_test3), - - p("Testing undo phase across master/subagents..."), - try_test(undo_test), - try_test(api_test3), - stop_subagent(SA). - -undo_2(X) -> undo(X). - -undo_3(X) -> undo(X). - -%% Req. Test2 -v1_processing(suite) -> []; -v1_processing(Config) when list(Config) -> - ?DBG("v1_processing -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v1_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v2_processing(suite) -> []; -v2_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v3_processing(suite) -> []; -v3_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), % same as v2! - ?line unload_master("Test2"). - - -%% We'll try get/set/trap and inform for all the auth & priv protocols. -%% For informs, the mgr is auth-engine. The agent has to sync. This is -%% accomplished by the first inform sent. That one will generate a -%% report, which makes it in sync. The notification-generating -%% application times out, and send again. This time it'll work. -v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv]. - -v3_crypto_basic(suite) -> []; -v3_crypto_basic(_Config) -> - EID = [0,0,0,0,0,0,0,0,0,0,0,2], - %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, - 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = - KMd5_1, - %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, - 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = - KSHA_1, - %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, - 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = - snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, - 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, - 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - KSHA_1t = lists:sublist(KSHA_1, 16), - KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, - 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - - %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), - ok. - - - -v3_md5_auth(suite) -> []; -v3_md5_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing MD5 authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authMD5"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_sha_auth(suite) -> []; -v3_sha_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing SHA authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authSHA"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_des_priv(suite) -> []; -v3_des_priv(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing DES encryption...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -%% Make sure mgr is in sync with agent -v3_sync(Funcs) -> - ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]), - g([[sysDescr, 0]]), - expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]), - g([[sysDescr, 0]]), - expect(433, [{[sysDescr,0], any}]), - lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs). - -v3_inform_sync(MA) -> - ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, - "standard inform", []), - %% Make sure agent is in sync with mgr... - ?DBG("v3_sync -> wait some time: ",[]), - sleep(20000), % more than 1500*10 in target_addr.conf - ?DBG("v3_sync -> await response",[]), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]). - - -v2_caps(suite) -> []; -v2_caps(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(v2_caps_i, [node()]). - -v2_caps_3(X) -> v2_caps(X). - - -v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]), - g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]}, - {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmp, del_agent_caps, [Idx]), - g([[sysORID, Idx]]), - ?line expect(2, [{[sysORID, Idx], noSuchInstance}]). - - -%% Req. Test2 -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - - -v1_get_p() -> - %% 4.1.2:1 - g([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - g([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - g([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - g([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - g([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - g([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - g([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - g([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - g([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - g([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - - -v1_get_next_p() -> - %% 4.1.3:1 - gn([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - gn([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - gn([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), -% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - gn([[tGenErr1]]), -% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - gn([[tGenErr2]]), -% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - gn([[sysDescr], [tGenErr3]]), -% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, -% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - s([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - s([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - s([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - s([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: -% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - s([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - -%% Req. Test2 -v2_proc() -> - %% According to RFC1905. - %% Template:
    : - ?DBG("v2_proc -> entry",[]), - v2_get_p(), - v2_get_next_p(), - v2_get_bulk_p(), - v2_set_p(). - -v2_get_p() -> - %% 4.2.1:2 - ?DBG("v2_get_p -> entry",[]), - g([[test2]]), - ?line expect(10, [{[test2], noSuchObject}]), - g([[tDescr]]), - ?line expect(11, [{[tDescr], noSuchObject}]), - g([[tDescr4,0]]), - ?line expect(12, [{[tDescr4,0], noSuchObject}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}, - {[tDescr,0], noSuchObject}]), - g([[tTable]]), - ?line expect(14, [{[tTable], noSuchObject}]), - g([[tEntry]]), - ?line expect(15, [{[tEntry], noSuchObject}]), - - %% 4.2.1:3 - g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line expect(20, [{[tDescr2,0], noSuchInstance}]), - g([[tDescr3,0]]), - ?line expect(21, [{[tDescr3,0], noSuchInstance}]), - g([[sysDescr,3]]), - ?line expect(22, [{[sysDescr, 3], noSuchInstance}]), - g([[tIndex,1]]), - ?line expect(23, [{[tIndex, 1], noSuchInstance}]), - - %% 4.2.1 - any other error: genErr - g([[tGenErr1, 0]]), - ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]), - - %% 4.2.1 - tooBig - g([[tTooBig, 0]]), - ?line expect(40, tooBig, 0, []). - - -v2_get_next_p() -> - %% 4.2.2:2 - ?DBG("v2_get_next_p -> entry",[]), - gn([[1,3,7,1]]), - ?line expect(10, [{[1,3,7,1], endOfMibView}]), - gn([[sysDescr], [1,3,7,1]]), - ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gn([[tCnt2, 1]]), - ?line expect(12, [{[tCnt2,2], 100}]), - gn([[tCnt2, 2]]), - ?line expect(12, [{[tCnt2,2], endOfMibView}]), - - %% 4.2.2 - any other error: genErr - gn([[tGenErr1]]), - ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]), - gn([[tGenErr2]]), - ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]), - gn([[sysDescr], [tGenErr3]]), - ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'}, - {[tGenErr3], 'NULL'}]), - - %% 4.2.2 - tooBig - gn([[tTooBig]]), - ?line expect(20, tooBig, 0, []). - -v2_get_bulk_p() -> - %% 4.2.3 - ?DBG("v2_get_bulk_p -> entry",[]), - gb(1, 1, []), - ?line expect(10, []), - gb(-1, 1, []), - ?line expect(11, []), - gb(-1, -1, []), - ?line expect(12, []), - gb(-1, -1, []), - ?line expect(13, []), - gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[sysDescr, 0], "Erlang SNMP agent"}]), - - gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line expect(19, []), - - gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'}, - {[sysObjectID], 'NULL'}, - {[tGenErr1], 'NULL'}, - {[sysDescr], 'NULL'}]), - gb(0, 2, [[tCnt2, 1]]), - ?line expect(21, [{[tCnt2,2], 100}, - {[tCnt2,2], endOfMibView}]). - - -v2_set_p() -> - %% 4.2.5:1 - ?DBG("v2_set_p -> entry",[]), - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]), - - %% 4.2.5:2 - s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), - - %% 4.2.5:3 - s([{[tDescr2, 0], i, 4}]), - ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.2.5:4 - s([{[tStr, 0], s, ""}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]), - s([{[tStr, 0], s, "12345"}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]), - - %% 4.2.5:5 - N/A - - %% 4.2.5:6 - s([{[tInt1, 0], i, 0}]), - ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]), - s([{[tInt1, 0], i, 5}]), - ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]), - s([{[tInt2, 0], i, 0}]), - ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]), - s([{[tInt2, 0], i, 5}]), - ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]), - s([{[tInt3, 0], i, 5}]), - ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]), - - %% 4.2.5:7 - s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), - - %% 4.2.5:8 - s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line expect(80, inconsistentName, 1, - [{[tDescrX, 1, 2], "inconsistentName"}]), - - %% 4.2.5:9 - s([{[tCnt, 1, 2], i, 5}]), - ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]), - - %% 4.2.5:10 - s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line expect(100, inconsistentValue, 1, - [{[tDescr2,0], "inconsistentValue"}]), - - %% 4.2.5:11 - s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line expect(110, resourceUnavailable, 1, - [{[tDescr2,0],"resourceUnavailable"}]), - - %% 4.2.5:12 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). - - %% commitFailed and undoFailed is tested by the 'undo' case. - - -%% Req. OLD-SNMPEA-MIB -table_test() -> - io:format("Testing simple get, next and set on communityTable...~n"), -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. - Key1c3 = [intCommunityViewIndex,get(mip),is("public")], - Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")], - Key1c4 = [intCommunityAccess,get(mip),is("public")], - EndKey = [intCommunityEntry,[9],get(mip),is("public")], - gn([[intCommunityEntry]]), - ?line expect(7, [{Key1c3, 2}]), - gn([[intCommunityTable]]), - ?line expect(71, [{Key1c3, 2}]), - gn([[community]]), - ?line expect(72, [{Key1c3, 2}]), - gn([[otpSnmpeaMIB]]), - ?line expect(73, [{Key1c3, 2}]), - gn([[ericsson]]), - ?line expect(74, [{Key1c3, 2}]), - gn([Key1c3]), - ?line expect(8, [{Key2c3, 2}]), - gn([Key2c3]), - ?line expect(9, [{Key1c4, 2}]), - gn([EndKey]), - AgentIp = [intAgentIpAddress,0], - ?line expect(10, [{AgentIp, any}]), - g([Key1c3]), - ?line expect(11, [{Key1c3, 2}]), - g([EndKey]), - ?line ?v1_2(expect(12, noSuchName, 1, any), - expect(12, [{EndKey, noSuchObject}])), - - io:format("Testing row creation/deletion on communityTable...~n"), - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - s([{NewKeyc5, ?createAndGo}]), - ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any), - s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), - g([NewKeyc4]), - ?line expect(16, [{NewKeyc4, 2}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(17, [{NewKeyc5, ?destroy}]), - s([{NewKeyc4, 2}]), - ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]), - s([{NewKeyc5, ?createAndWait}]), - ?line expect(19, [{NewKeyc5, ?createAndWait}]), - g([NewKeyc5]), - ?line expect(20, [{NewKeyc5, ?notReady}]), - s([{NewKeyc4, 2}]), - ?line expect(21, [{NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(22, [{NewKeyc5, ?notReady}]), - s([{NewKeyc3, 2}]), - ?line expect(23, [{NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(24, [{NewKeyc5, ?notInService}]), - s([{NewKeyc5, ?active}]), - ?line expect(25, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(26, [{NewKeyc5, ?destroy}]), - s([{NewKeyc3, 3}]), - ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]), - otp_1128(). - -%% Req. system group -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - gn([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - g([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - gn([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - g([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - io:format("Testing noSuchName and badValue...~n"), - s([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - s([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - try_test(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - gn([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - g([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - s([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - s([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - g([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - gn([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - s([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - gn([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - p("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - gn([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - g([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - s([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - g([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - p("Testing next from last object in master to subagent (2)..."), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - p("Adding one row in subagent table (2)"), - _FTab = [friendsEntry2], - s([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - g([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - p("Adding two rows in subagent table with special INDEX (2)"), - s([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - g([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - gn([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - s([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - gn([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - -%% Req. Test1 -multi_threaded_test() -> - p("Testing multi threaded agent..."), - g([[multiStr,0]]), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(1, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "pelle"}]), - ?line expect(2, [{[sysLocation, 0], "pelle"}]), - Pid ! continue, - ?line expect(3, [{[multiStr,0], "ok"}]), - - s([{[multiStr, 0], s, "block"}]), - Pid2 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(4, [{[sysUpTime,0], any}]), - g([[multiStr,0]]), - Pid3 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(5, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "kalle"}]), - Pid3 ! continue, - ?line expect(6, [{[multiStr,0], "ok"}]), - Pid2 ! continue, - ?line expect(7, [{[multiStr,0], "block"}]), - ?line expect(8, [{[sysLocation,0], "kalle"}]). - -%% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - snmpa:send_trap(MA, mtTrap, "standard trap"), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(2, [{[sysUpTime,0], any}]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - Pid ! continue, - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]). - - -get_multi_pid() -> - get_multi_pid(10). -get_multi_pid(0) -> - ?line ?FAIL(no_global_name); -get_multi_pid(N) -> - sleep(1000), - case global:whereis_name(snmp_multi_tester) of - Pid when pid(Pid) -> Pid; - _ -> get_multi_pid(N-1) - end. - -%% Req. Test1 -types_v2_test() -> - p("Testing v2 types..."), - - s([{[bits1,0], 2#10}]), - ?line expect(1, [{[bits1,0], ?str(2#10)}]), - g([[bits1,0]]), - ?line expect(2, [{[bits1,0], ?str(2#101)}]), - - s([{[bits2,0], 2#11000000110}]), - ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]), - g([[bits2,0]]), - ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]), - - g([[bits3,0]]), - ?line expect(50, genErr, 1, any), - - g([[bits4,0]]), - ?line expect(51, genErr, 1, any), - - s([{[bits1,0], s, [2#10]}]), - ?line expect(6, ?v1_2(badValue, wrongValue), 1, any), - - s([{[bits2,0], 2#11001001101010011}]), - ?line expect(7, ?v1_2(badValue, wrongValue), 1, any). - - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - p("Testing IMPLIED..."), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - gn([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - gn([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr2)",[]), - gn([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - gn([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, - oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, - int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - -%% Req. Klas3 -api_test2() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]), - g([[fname4,0]]), - ?line expect(2, [{[fname4,0], 1}]). - -api_test3() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]). - - -unreg_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - -%% Req. Klas1 -load_test_sa() -> - gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -%% Note: This test case takes a while... actually a couple of minutes. -ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform -> entry with MA = ~p => " - "send notification: testTrapv22",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag1, self()}, - "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag1, [_]} -> - ok; - {snmp_targets, tag1, Addrs1} -> - ?line ?FAIL({bad_addrs, Addrs1}) - after - 5000 -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag1, {got_response, _}} -> - ok; - {snmp_notification, tag1, {no_response, _}} -> - ?line ?FAIL(no_response) - after - 20000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - - %% - %% -- The rest is possibly erroneous... - %% - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag2, self()}, - "standard inform", []), - ?line expect(2, {inform, false}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag2, [_]} -> - ok; - {snmp_targets, tag2, Addrs2} -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]), - ?line ?FAIL({bad_addrs, Addrs2}) - after - 5000 -> - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag2, {got_response, _}} -> - ?line ?FAIL(got_response); - {snmp_notification, tag2, {no_response, _}} -> - ok - after - 240000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag2) timeout",[]), - ?line ?FAIL(nothing_at_all) - end. - - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. -% it depends on which order the agent traverses the varbind list. -% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- -standard_mibs(suite) -> - [snmp_standard_mib, snmp_community_mib, - snmp_framework_mib, - snmp_target_mib, snmp_notification_mib, - snmp_view_based_acm_mib]. - -standard_mibs_2(suite) -> - [snmpv2_mib_2, snmp_community_mib_2, - snmp_framework_mib_2, - snmp_target_mib_2, snmp_notification_mib_2, - snmp_view_based_acm_mib_2]. - -standard_mibs_3(suite) -> - [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3, - snmp_target_mib_3, snmp_notification_mib_3, - snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3]. - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - try_test(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = try_test(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - try_test(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = try_test(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - try_test(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - try_test(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - try_test(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - try_test(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - try_test(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - try_test(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - try_test(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]). - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v2 and v3. -%% o Test the counters and control objects in SNMPv2-MIB -%%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; -snmpv2_mib_2(Config) when list(Config) -> - ?LOG("snmpv2_mib_2 -> start",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?DBG("snmpv2_mib_2 -> standard mib init",[]), - try_test(std_mib_init), - - ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]), - InBadVsns = try_test(std_mib_a), - - ?DBG("snmpv2_mib_2 -> make a bad version read",[]), - put(vsn, v1), - try_test(std_mib_read), - - ?DBG("snmpv2_mib_2 -> bad version read",[]), - put(vsn, v2), - Bad = try_test(std_mib_b, [InBadVsns]), - - ?DBG("snmpv2_mib_2 -> read with bad community",[]), - try_test(std_mib_read, [], [{community, "bad community"}]), - - ?DBG("snmpv2_mib_2 -> write with public community",[]), - try_test(std_mib_write, [], [{community, "public"}]), - - ?DBG("snmpv2_mib_2 -> asn err",[]), - try_test(std_mib_asn_err), - - ?DBG("snmpv2_mib_2 -> check counters",[]), - try_test(std_mib_c, [Bad]), - - ?DBG("snmpv2_mib_2 -> get som counters",[]), - try_test(snmpv2_mib_a), - - ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), - try_test(std_mib_finish), - - ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, " - "then disable auth traps",[]), - try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]), - - ?LOG("snmpv2_mib_2 -> done",[]). - -%% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; -snmpv2_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - InBadVsns = try_test(std_mib_a), - put(vsn, v1), - try_test(std_mib_read), - put(vsn, v3), - _Bad = try_test(std_mib_b, [InBadVsns]), - try_test(snmpv2_mib_a), - - try_test(std_mib_finish). - --define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]). - -%% Req. SNMPv2-MIB -snmpv2_mib_test_finish() -> - %% force a authenticationFailure - ?DBG("ma_v2_inform -> write to std mib",[]), - std_mib_write(), - - %% check that we got a trap - ?DBG("ma_v2_inform -> await trap",[]), - ?line expect(2, v2trap, [{[sysUpTime,0], any}, - {[snmpTrapOID,0], ?authenticationFailure}]), - - %% and the the inform - ?DBG("ma_v2_inform -> await inform",[]), - ?line expect(2, {inform,true}, [{[sysUpTime,0], any}, - {[snmpTrapOID,0],?authenticationFailure}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - -%% Req. SNMPv2-MIB -snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), - s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), - s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, - [{[sysLocation, 0], "val3"}, - {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]). - - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - try_test(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - try_test(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -snmp_framework_mib_2(X) -> snmp_framework_mib(X). - -snmp_framework_mib_3(suite) -> []; -snmp_framework_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(snmp_framework_mib). - - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - -%%----------------------------------------------------------------- -%% o Test the counters -%%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; -snmp_mpd_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - UnknownPDUHs = try_test(snmp_mpd_mib_a), - try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]), - try_test(snmp_mpd_mib_c, [UnknownPDUHs]). - - -%% Req. SNMP-MPD-MIB -snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0]]), - Pdu = #pdu{type = 'get-request', - request_id = 23, - error_status = noError, - error_index = 0, - varbinds = []}, - SPdu = #scopedPdu{contextEngineID = "agentEngine", - contextName = "", - data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), - V3Hdr1 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [7], - msgSecurityModel = 23, % bad sec model - msgSecurityParameters = []}, - V3Hdr2 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [6], % bad flag combination - msgSecurityModel = 3, - msgSecurityParameters = []}, - Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1, - data = SPDUBytes}, - Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, - data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), - snmp_test_mgr:send_bytes(MsgBytes1), - snmp_test_mgr:send_bytes(MsgBytes2), - - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0], - [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, - UnknownPDUHs. - --define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). -snmp_mpd_mib_b() -> - g([[sysUpTime,0]]), - ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]). - - -snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1. - - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - try_test(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib_2(X) -> snmp_target_mib(X). - -snmp_target_mib_3(X) -> snmp_target_mib(X). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - try_test(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib_2(X) -> snmp_notification_mib(X). - -snmp_notification_mib_3(X) -> snmp_notification_mib(X). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line try_test(do_set, [ARow2]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [ARow2Status]), - - - %% Add valid row - ?line try_test(do_set, [ARow1]), - - ?line try_test(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), - - %% We should still have access... - ?line try_test(use_rights, [], Opts), - - %% Delete rows - ?line try_test(del_row, [GRow1Status]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), - - ?line try_test(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - -mk_ln(X) -> - [length(X) | X]. - -%%----------------------------------------------------------------- -%% o add/delete users and try them -%% o test all secLevels -%% o test all combinations of protocols -%% o try bad ops; check counters -%%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; -snmp_user_based_sm_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - _AgentDir = ?config(agent_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - - %% The newUser used here already has VACM access. - - %% Add a new user in the simplest way; just createAndGo - try_test(v3_sync, [[{usm_add_user1, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new user - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), - DesKey1 = lists:sublist(ShaKey1, 16), - - %% Change the new user's keys - 1 - try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), - DesKey2 = lists:sublist(ShaKey2, 16), - - %% Change the new user's keys - 2 - ?line try_test(v3_sync, - [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Change the new user's keys - 3 - ?line try_test(v3_sync, - [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("SNMP-USER-BASED-SM-MIB"). - --define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). - -usm_add_user1() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - -usm_use_user() -> - v2_proc(). - - -%% Change own public keys -usm_key_change1(ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_shaxxxxxxxxxx", - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_desxxxxxx", - DesKey), - Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change own private keys -usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change other's public keys -usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], - s(Vbs1), - ?line expect(1, noAccess, 1, any), - Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs2), - ?line expect(2, noAccess, 1, any), - - - Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs3), - ?line expect(1, Vbs3). - -usm_read() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], - [usmUserCloneFrom, NewRowIndex], - [usmUserAuthKeyChange, NewRowIndex], - [usmUserOwnAuthKeyChange, NewRowIndex], - [usmUserPrivKeyChange, NewRowIndex], - [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line expect(1, - [{[usmUserSecurityName, NewRowIndex], "newUser"}, - {[usmUserCloneFrom, NewRowIndex], [0,0]}, - {[usmUserAuthKeyChange, NewRowIndex], ""}, - {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, - {[usmUserPrivKeyChange, NewRowIndex], ""}, - {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]), - ok. - - - -usm_del_user() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - --define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). - --define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]). - --define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]). - --define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]). - --define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]). - --define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]). - -usm_bad() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, inconsistentName, 1, any), - - RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line expect(2, wrongValue, 1, any), - - RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line expect(3, Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line expect(4, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line expect(5, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line expect(6, wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line expect(7, wrongValue, 1, any), - - Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line expect(1, Vbs4), - - ok. - - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?LOG("loop_mib -> initiate case",[]), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - try_test(loop_mib_1), - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - - -loop_mib_2(suite) -> []; -loop_mib_2(Config) when list(Config) -> - ?LOG("loop_mib_2 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_2 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?LOG("loop_mib_2 -> done",[]). - - -loop_mib_3(suite) -> []; -loop_mib_3(Config) when list(Config) -> - ?LOG("loop_mib_3 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_3 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?LOG("loop_mib_3 -> done",[]). - - -%% Req. As many mibs all possible -loop_mib_1() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_1([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_1(Oid, N) -> - ?DBG("loop_it_1 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_1 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_1(NOid, N+1); - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it_1 -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - end. - -%% Req. As many mibs all possible -loop_mib_2() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_2([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_2(Oid, N) -> - ?DBG("loop_it_2 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid, value = endOfMibView}]} -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p",[NOid]), - N; - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_2 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_2(NOid, N+1) - end. - - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - -reported_bugs(suite) -> - [otp_1128, otp_1129, otp_1131, otp_1162, - otp_1222, otp_1298, otp_1331, otp_1338, - otp_1342, otp_2776, otp_2979, otp_3187, otp_3725]. - -reported_bugs_2(suite) -> - [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2, - otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2, - otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2]. - -reported_bugs_3(suite) -> - [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3, - otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3, - otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3, - otp_3542]. - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. -tickets(suite) -> - [otp_4394]. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128_2(X) -> otp_1128(X). - -otp_1128_3(X) -> otp_1128(X). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_2(X) -> otp_1129(X). - -otp_1129_3(X) -> otp_1129(X). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - try_test(otp_1131), - ?line unload_master("Klas1"). - -otp_1131_2(X) -> otp_1131(X). - -otp_1131_3(X) -> otp_1131(X). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - try_test(otp_1162), - stop_subagent(SA). - -otp_1162_2(X) -> otp_1162(X). - -otp_1162_3(X) -> otp_1162(X). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - try_test(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222_2(X) -> otp_1222(X). - -otp_1222_3(X) -> otp_1222(X). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1298), - ?line unload_master("Klas2"). - -otp_1298_2(X) -> otp_1298(X). - -otp_1298_3(X) -> otp_1298(X). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331_2(X) -> otp_1331(X). - -otp_1331_3(X) -> otp_1331(X). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1338), - ?line unload_master("Klas2"). - -otp_1338_2(X) -> otp_1338(X). - -otp_1338_3(X) -> otp_1338(X). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas4"), - try_test(otp_1342), - ?line unload_master("Klas4"). - -otp_1342_2(X) -> otp_1342(X). - -otp_1342_3(X) -> otp_1342(X). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366_2(X) -> otp_1366(X). - -otp_1366_3(X) -> otp_1366(X). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_2776). - -otp_2776_2(X) -> otp_2776(X). - -otp_2776_3(X) -> otp_2776(X). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Test1"), - ?line init_old(), - try_test(otp_2979), - ?line unload_master("Test1"). - -otp_2979_2(X) -> otp_2979(X). - -otp_2979_3(X) -> otp_2979(X). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187_2(X) -> otp_3187(X). - -otp_3187_3(X) -> otp_3187(X). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - - -otp_4394(suite) -> {req, [], {conf, - init_otp_4394, - [otp_4394_test], - finish_otp_4394}}. - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - - - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?DBG("otp_4394_test -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -%%%-------------------------------------------------- -%%% Used to test the standard mib with our -%%% configuration. -%%%-------------------------------------------------- -run(F, A, Opts) -> - M = get(mib_dir), - Dir = get(mgr_dir), - User = snmp_misc:get_option(user, Opts, "all-rights"), - SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv), - EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"), - CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), - Community = snmp_misc:get_option(community, Opts, "all-rights"), - ?DBG("run -> start crypto app",[]), - Crypto = ?CRYPTO_START(), - ?DBG("run -> Crypto: ~p",[Crypto]), - catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - ?DBG("run -> config:~n" - "\tM: ~p~n" - "\tDir: ~p~n" - "\tUser: ~p~n" - "\tSecLevel: ~p~n" - "\tEngineID: ~p~n" - "\tCtxEngineID: ~p~n" - "\tCommunity: ~p~n" - "\tStdM: ~p", - [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]), - case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()}, - {packet_server_debug,true}, - {debug,true}, - {agent, get(master_host)}, - {agent_udp, 4000}, - {trap_udp, 5000}, - {recbuf,65535}, - quiet, - get(vsn), - {community, Community}, - {user, User}, - {sec_level, SecLevel}, - {engine_id, EngineID}, - {context_engine_id, CtxEngineID}, - {dir, Dir}, - {mibs, mibs(StdM, M)}]) of - {ok, _Pid} -> - Res = apply(?MODULE, F, A), - catch snmp_test_mgr:stop(), - Res; - Err -> - io:format("Error starting manager: ~p\n", [Err]), - catch snmp_test_mgr:stop(), - ?line exit({mgr_start, Err}) - end. - - -mibs(StdMibDir,MibDir) -> - [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")), - join(MibDir, "OLD-SNMPEA-MIB.bin"), - join(StdMibDir, "SNMP-FRAMEWORK-MIB"), - join(StdMibDir, "SNMP-MPD-MIB"), - join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"), - join(StdMibDir, "SNMP-USER-BASED-SM-MIB"), - join(StdMibDir, "SNMP-TARGET-MIB"), - join(StdMibDir, "SNMP-NOTIFICATION-MIB"), - join(MibDir, "Klas1.bin"), - join(MibDir, "Klas2.bin"), - join(MibDir, "Klas3.bin"), - join(MibDir, "Klas4.bin"), - join(MibDir, "SA-MIB.bin"), - join(MibDir, "TestTrap.bin"), - join(MibDir, "Test1.bin"), - join(MibDir, "Test2.bin"), - join(MibDir, "TestTrapv2.bin")]. - -join(D,F) -> - filename:join(D,F). - -%% string used in index -is(S) -> [length(S) | S]. - -try_test(Func) -> - call(get(mgr_node), ?MODULE, run, [Func, [], []]). - -try_test(Func, A) -> - call(get(mgr_node), ?MODULE, run, [Func, A, []]). - -try_test(Func, A, Opts) -> - call(get(mgr_node), ?MODULE, run, [Func, A, Opts]). - -call(N,M,F,A) -> - ?DBG("call -> entry with~n" - " N: ~p~n" - " M: ~p~n" - " F: ~p~n" - " A: ~p~n" - " when~n" - " get(): ~p", - [N,M,F,A,get()]), - spawn(N, ?MODULE, wait, [self(),get(),M,F,A]), - receive - {done, {'EXIT', Rn}, Loc} -> - ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]), - put(test_server_loc, Loc), - exit(Rn); - {done, Ret, Zed} -> - ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]), - Ret - end. - -wait(From, Env, M, F, A) -> - ?DBG("wait -> entry with ~n" - "\tFrom: ~p~n" - "\tEnv: ~p",[From,Env]), - lists:foreach(fun({K,V}) -> put(K,V) end, Env), - Rn = (catch apply(M, F, A)), - ?DBG("wait -> Rn: ~n~p", [Rn]), - From ! {done, Rn, get(test_server_loc)}, - exit(Rn). - -expect(A,B) -> ok = snmp_test_mgr:expect(A,B). -expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C). -expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F). - -get_req(Id, Vars) -> - ?DBG("get_req -> entry with~n" - "\tId: ~p~n" - "\tVars: ~p",[Id,Vars]), - g(Vars), - ?DBG("get_req -> await response",[]), - {ok, Val} = snmp_test_mgr:get_response(Id, Vars), - ?DBG("get_req -> response: ~p",[Val]), - Val. - -get_next_req(Vars) -> - ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]), - gn(Vars), - ?DBG("get_next_req -> await response",[]), - Response = snmp_test_mgr:receive_response(), - ?DBG("get_next_req -> response: ~p",[Response]), - Response. - - - -start_node(Name) -> - ?LOG("start_node -> entry with Name: ~p",[Name]), - M = list_to_atom(?HOSTNAME(node())), - ?DBG("start_node -> M: ~p",[M]), - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p",[Pa]), - - Args = case init:get_argument('CC_TEST') of - {ok, [[]]} -> - " -pa /clearcase/otp/libraries/snmp/ebin "; - {ok, [[Path]]} -> - " -pa " ++ Path; - error -> - "" - end, - %% Do not use start_link!!! (the proc that calls this one is tmp) - ?DBG("start_node -> Args: ~p~n",[Args]), - A = Args ++ " -pa " ++ Pa, - case (catch ?START_NODE(Name, A)) of - {ok, Node} -> - %% Tell the test_server to not clean up things it never started. - ?DBG("start_node -> Node: ~p",[Node]), - {ok, Node}; - Else -> - ?ERR("start_node -> failed with(other): Else: ~p",[Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?LOG("stop_node -> Node: ~p",[Node]), - rpc:cast(Node, erlang, halt, []). - -p(X) -> - io:format(user, X++"\n", []). - -sleep(X) -> - receive - after - X -> ok - end. - -%%%----------------------------------------------------------------- -%%% Configuration -%%%----------------------------------------------------------------- -config(Vsns, MgrDir, AgentDir, MIp, AIp) -> - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp, - ?TRAP_UDP, AIp, 4000, - "test"), - ?line case update_usm(Vsns, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); - false -> - ?line ok - end, - ?line update_community(Vsns, AgentDir), - ?line update_vacm(Vsns, AgentDir), - ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns), - ?line write_target_params_conf(AgentDir, Vsns), - ?line write_notify_conf(AgentDir), - ok. - -delete_files(Config) -> - Dir = ?config(agent_dir, Config), - {ok, List} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, - List). - -update_usm(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -update_usm_mgr(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - file:close(Fid). - -reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). - - -update_community([v3], _Dir) -> ok; -update_community(_, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n", - []), - file:close(Fid). - - --define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). -update_vacm(_Vsn, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]), - ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", " - "~w, excluded, null}.\n", [?tDescr_instance]), - file:close(Fid). - - -vacm_ver(v1) -> v1; -vacm_ver(v2) -> v2c; -vacm_ver(v3) -> usm. - - -write_community_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write), - ok = write_community_conf1(Fid, Confs), - file:close(Fid). - -write_community_conf1(_, []) -> - ok; -write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) -> - ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [ComIdx, ComName, SecName, CtxName, TransTag]), - write_community_conf1(Fid, Confs). - - -write_target_addr_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - ok = write_target_addr_conf1(Fid, Confs), - file:close(Fid). - - -write_target_addr_conf1(_, []) -> - ok; -write_target_addr_conf1(Fid, - [{Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz}|Confs]) -> - ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz]), - write_target_addr_conf1(Fid, Confs). - -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - lists:foreach(fun(Vsn) -> - ok = io:format(Fid, - "{\"~s\", ~w, ~w, 1500, 3, " - "\"std_trap\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, mk_param(Vsn)]), - case Vsn of - v1 -> ok; - v2 -> - ok = io:format(Fid, - "{\"~s.2\",~w,~w,1500,3, " - "\"std_inform\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]); - v3 -> - ok = io:format(Fid, - "{\"~s.3\",~w,~w,1500,3, " - "\"std_inform\", \"~s\", " - "\"mgrEngine\", [], 1024}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]) - end - end, - Vsns), - file:close(Fid). - -mk_param(v1) -> "target_v1"; -mk_param(v2) -> "target_v2"; -mk_param(v3) -> "target_v3". - -mk_ip([A,B,C,D], Vsn) -> - io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]). - - -rewrite_target_addr_conf(Dir,NewPort) -> - TAFile = filename:join(Dir, "target_addr.conf"), - ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]), - case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok - end, - - ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end), - - ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), - - NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs], - - ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - - ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs), - - file:close(Fid). - -rewrite_target_addr_conf1(O) -> - {ok,O}. - -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> - ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), - {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; -rewrite_target_addr_conf2(_NewPort,O) -> - ?LOG("rewrite_target_addr_conf2 -> entry with " - "~n O: ~p",[O]), - O. - - -rewrite_target_addr_conf3(_,[]) -> ok; -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry, - ParamName,EngineId}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % ParamsName - "\"~s\"}.", % EngineId - [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]), - rewrite_target_addr_conf3(Fid,T); -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList, - ParamName,EngineId,TMask,MMS}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % TagList - "\"~s\", " % ParamsName - "\"~s\"," % EngineId - "~p, " % TMask - "~p}.", % MMS - [Name,Ip,Port,Timeout,Retry,TagList,ParamName, - EngineId,TMask,MMS]), - rewrite_target_addr_conf3(Fid,T). - -reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_addr.old"), - filename:join(Dir,"target_addr.conf")). - -write_target_params_conf(Dir, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - lists:foreach(fun(Vsn) -> - MP = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> v3 - end, - SM = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> usm - end, - ok = io:format(Fid, "{\"target_~w\", ~w, ~w, " - "\"all-rights\", noAuthNoPriv}.~n", - [Vsn, MP, SM]) - end, - Vsns), - file:close(Fid). - -rewrite_target_params_conf(Dir, SecName, SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n", - [SecName, SecLevel]), - file:close(Fid). - -reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). - -write_notify_conf(Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write), - ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []), - ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []), - file:close(Fid). - -ver_to_trap_str([v1]) -> "v1"; -ver_to_trap_str([v2]) -> "v2"; -% default is to use the latest snmp version -ver_to_trap_str([v1,v2]) -> "v2". - - - -write_view_conf(Dir) -> - {ok, Fid} = file:open(a(Dir,"view.conf"),write), - ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []), - ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]), - file:close(Fid). - -a(A,B) -> lists:append(A,B). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -copy_file(From, To) -> - {ok, Bin} = file:read_file(From), - ok = file:write_file(To, Bin). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_memory_usage() -> - Info = snmpa:info(snmp_master_agent), - TreeSize = lists_key1search(tree_size_bytes, Info), - ProcMem = lists_key1search(process_memory, Info), - MibDbSize = lists_key1search([db_memory,mib], Info), - NodeDbSize = lists_key1search([db_memory,node], Info), - TreeDbSize = lists_key1search([db_memory,tree], Info), - ?INF("Memory usage: " - "~n Tree size: ~p" - "~n Process memory size: ~p" - "~n Mib db size: ~p" - "~n Node db size: ~p" - "~n Tree db size: ~p", - [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]). - -lists_key1search([], Res) -> - Res; -lists_key1search([Key|Keys], List) when atom(Key), list(List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - lists_key1search(Keys, Val); - false -> - undefined - end; -lists_key1search(Key, List) when atom(Key) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - Val; - false -> - undefined - end. - - -regs() -> - lists:sort(registered()). diff --git a/lib/snmp/test/exp/snmp_agent_ms_test.erl b/lib/snmp/test/exp/snmp_agent_ms_test.erl deleted file mode 100644 index 7c8967d30264..000000000000 --- a/lib/snmp/test/exp/snmp_agent_ms_test.erl +++ /dev/null @@ -1,5636 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_ms_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - --compile(export_all). - --define(application, snmp). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). --include("snmp_test_lib.hrl"). --define(SNMP_USE_V3, true). --include_lib("snmp/include/snmp_types.hrl"). -%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). - - --define(klas1, [1,3,6,1,2,1,7]). --define(klas2, [1,3,6,1,2,1,9]). --define(klas3, [1,3,6,1,2,1,8,1]). --define(klas4, [1,3,6,1,2,1,8,4]). --define(sa, [1,3,6,1,4,1,193,2]). --define(system, [1,3,6,1,2,1,1]). --define(snmp, [1,3,6,1,2,1,11]). --define(snmpTraps, [1,3,6,1,6,3,1,1,5]). --define(ericsson, [1,3,6,1,4,1,193]). --define(testTrap, [1,3,6,1,2,1,15,0]). --define(xDescr, [1,3,6,1,2,1,17,1]). --define(xDescr2, [1,3,6,1,2,1,17,2]). - --define(active, 1). --define(notInService, 2). --define(notReady, 3). --define(createAndGo, 4). --define(createAndWait, 5). --define(destroy, 6). - --define(TRAP_UDP, 5000). - --define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - --define(str(X), snmp_pdus:bits_to_str(X)). - --define(break(), begin io:format(user, "break at line ~w: pid: ~p\n", - [?LINE, self()]), - receive cont -> ok end - end). - - --import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]). --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all() -> -[cases()]. - -groups() -> - [{mib_storage, [], - [{group, mib_storage_ets}, {group, mib_storage_dets}, - {group, mib_storage_mnesia}, - {group, mib_storage_size_check_ets}, - {group, mib_storage_size_check_dets}, - {group, mib_storage_size_check_mnesia}, - {group, mib_storage_varm_dets}, - {group, mib_storage_varm_mnesia}]}, - {mib_storage_ets, [], mib_storage_ets_cases()}, - {mib_storage_dets, [], mib_storage_dets_cases()}, - {mib_storage_mnesia, [], mib_storage_mnesia_cases()}, - {mib_storage_size_check_ets, [], - mse_size_check_cases()}, - {mib_storage_size_check_dets, [], - msd_size_check_cases()}, - {mib_storage_size_check_mnesia, [], - msm_size_check_cases()}, - {mib_storage_varm_dets, [], - varm_mib_storage_dets_cases()}, - {mib_storage_varm_mnesia, [], - varm_mib_storage_mnesia_cases()}, - {test_v1, [], v1_cases()}, {test_v2, [], v2_cases()}, - {test_v1_v2, [], v1_v2_cases()}, - {test_v3, [], v3_cases()}, - {test_multi_threaded, [], mt_cases()}, - {multiple_reqs, [], mul_cases()}, - {multiple_reqs_2, [], mul_cases_2()}, - {v2_inform, [], [v2_inform_i]}, - {v3_security, [], - [v3_crypto_basic, v3_md5_auth, v3_sha_auth, - v3_des_priv]}, - {standard_mibs, [], - [snmp_standard_mib, snmp_community_mib, - snmp_framework_mib, snmp_target_mib, - snmp_notification_mib, snmp_view_based_acm_mib]}, - {standard_mibs_2, [], - [snmpv2_mib_2, snmp_community_mib_2, - snmp_framework_mib_2, snmp_target_mib_2, - snmp_notification_mib_2, snmp_view_based_acm_mib_2]}, - {standard_mibs_3, [], - [snmpv2_mib_3, snmp_framework_mib_3, snmp_mpd_mib_3, - snmp_target_mib_3, snmp_notification_mib_3, - snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3]}, - {reported_bugs, [], - [otp_1128, otp_1129, otp_1131, otp_1162, otp_1222, - otp_1298, otp_1331, otp_1338, otp_1342, otp_2776, - otp_2979, otp_3187, otp_3725]}, - {reported_bugs_2, [], - [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2, - otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2, - otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2]}, - {reported_bugs_3, [], - [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3, - otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3, - otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3, - otp_3542]}, - {tickets, [], [{group, otp_4394}]}, - {otp_4394, [], [otp_4394_test]}]. - -init_per_group(otp_4394, Config) -> - init_otp_4394(Config); -init_per_group(v2_inform, Config) -> - init_v2_inform(Config); -init_per_group(multiple_reqs_2, Config) -> - init_mul(Config); -init_per_group(multiple_reqs, Config) -> - init_mul(Config); -init_per_group(test_multi_threaded, Config) -> - init_mt(Config); -init_per_group(test_v3, Config) -> - init_v3(Config); -init_per_group(test_v1_v2, Config) -> - init_v1_v2(Config); -init_per_group(test_v2, Config) -> - init_v2(Config); -init_per_group(test_v1, Config) -> - init_v1(Config); -init_per_group(mib_storage_varm_mnesia, Config) -> - init_varm_mib_storage_mnesia(Config); -init_per_group(mib_storage_varm_dets, Config) -> - init_varm_mib_storage_dets(Config); -init_per_group(mib_storage_size_check_mnesia, Config) -> - init_size_check_msm(Config); -init_per_group(mib_storage_size_check_dets, Config) -> - init_size_check_msd(Config); -init_per_group(mib_storage_size_check_ets, Config) -> - init_size_check_mse(Config); -init_per_group(mib_storage_mnesia, Config) -> - init_mib_storage_mnesia(Config); -init_per_group(mib_storage_dets, Config) -> - init_mib_storage_dets(Config); -init_per_group(mib_storage_ets, Config) -> - init_mib_storage_ets(Config); -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(otp_4394, Config) -> - finish_otp_4394(Config); -end_per_group(v2_inform, Config) -> - finish_v2_inform(Config); -end_per_group(multiple_reqs_2, Config) -> - finish_mul(Config); -end_per_group(multiple_reqs, Config) -> - finish_mul(Config); -end_per_group(test_multi_threaded, Config) -> - finish_mt(Config); -end_per_group(test_v3, Config) -> - finish_v3(Config); -end_per_group(test_v1_v2, Config) -> - finish_v1_v2(Config); -end_per_group(test_v2, Config) -> - finish_v2(Config); -end_per_group(test_v1, Config) -> - finish_v1(Config); -end_per_group(mib_storage_varm_mnesia, Config) -> - finish_varm_mib_storage_mnesia(Config); -end_per_group(mib_storage_varm_dets, Config) -> - finish_varm_mib_storage_dets(Config); -end_per_group(mib_storage_size_check_mnesia, Config) -> - finish_size_check_msm(Config); -end_per_group(mib_storage_size_check_dets, Config) -> - finish_size_check_msd(Config); -end_per_group(mib_storage_size_check_ets, Config) -> - finish_size_check_mse(Config); -end_per_group(mib_storage_mnesia, Config) -> - finish_mib_storage_mnesia(Config); -end_per_group(mib_storage_dets, Config) -> - finish_mib_storage_dets(Config); -end_per_group(mib_storage_ets, Config) -> - finish_mib_storage_ets(Config); -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [ - app_info, - {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets} - ]. - - -%%%----------------------------------------------------------------- -%%% The test case structure is as follows: -%%% -%%% init_all - starts mnesia, -%%% -%%% init_v1 - starts agent -%%% simple -%%% big - e.g. starts/stops subagent, load/unloads mibs -%%% init_mul -%%% mul_get -%%% mul_set -%%% -%%% finish_mul -%%% -%%% finish_v1 -%%% -%%% init_v2 - starts agent -%%% finish_v2 -%%% -%%% init_bilingual - starts agent -%%% finish_bilingual -%%% -%%% finish_all -%%% -%%% There is still one problem with these testsuites. If one test -%%% fails, it may not be possible to run some other cases, as it -%%% may have e.g. created some row or loaded some table, that it -%%% didn't undo (since it failed). -%%%----------------------------------------------------------------- - -init_all(Config0) when list(Config0) -> - ?LOG("init_all -> entry with" - "~n Config0: ~p",[Config0]), - - %% -- - %% Fix config: - %% - - DataDir0 = ?config(data_dir, Config0), - DataDir1 = filename:split(filename:absname(DataDir0)), - [_|DataDir2] = lists:reverse(DataDir1), - DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), - Config1 = lists:keydelete(data_dir, 1, Config0), - Config = [{data_dir, DataDir3 ++ "/"}|Config1], - - %% -- - %% Start nodes - %% - - ?line {ok, SaNode} = start_node(snmp_sa), - ?line {ok, MgrNode} = start_node(snmp_mgr), - - - %% -- - %% Create necessary files - %% - - Dir = ?config(priv_dir, Config), - ?DBG("init_all -> Dir ~p", [Dir]), - - DataDir = ?config(data_dir, Config), - ?DBG("init_all -> DataDir ~p", [DataDir]), - - file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")), - ?DBG("init_all -> MgrDir ~p", [MgrDir]), - - file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")), - ?DBG("init_all -> AgentDir ~p", [AgentDir]), - - file:make_dir(SaDir = filename:join(Dir, "sa_dir/")), - ?DBG("init_all -> SaDir ~p", [SaDir]), - - - %% -- - %% Start and initiate mnesia - %% - - ?DBG("init_all -> load application mnesia", []), - ?line ok = application:load(mnesia), - - ?DBG("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), - - ?DBG("init_all -> application mnesia: set_env dir",[]), - ?line application_controller:set_env(mnesia, dir, - filename:join(Dir, "Mnesia1")), - - ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(Dir, "Mnesia2")]), - - ?DBG("init_all -> create mnesia schema",[]), - ?line ok = mnesia:create_schema([SaNode, node()]), - - ?DBG("init_all -> start application mnesia",[]), - ?line ok = application:start(mnesia), - - ?DBG("init_all -> start application mnesia on ~p",[SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), - Ip = ?LOCALHOST(), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, - {agent_dir, AgentDir ++ "/"}, - {mgr_dir, MgrDir ++ "/"}, - {sa_dir, SaDir ++ "/"}, - {mib_dir, DataDir}, - {ip, Ip} | - Config]. - -finish_all(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - stop_node(SaNode), - stop_node(MgrNode), - application:stop(mnesia). - -start_v1_agent(Config) when list(Config) -> - start_agent(Config, [v1]). - -start_v1_agent(Config,Opts) when list(Config), list(Opts) -> - start_agent(Config, [v1], Opts). - -start_v2_agent(Config) when list(Config) -> - start_agent(Config, [v2]). - -start_v3_agent(Config) when list(Config) -> - start_agent(Config, [v3]). - -start_bilingual_agent(Config) when list(Config) -> - start_agent(Config, [v1,v2]). - -start_multi_threaded_agent(Config) when list(Config) -> - start_agent(Config, [v2], [{snmp_multi_threaded, true}]). - -stop_agent(Config) when list(Config) -> - ?LOG("stop_agent -> entry with" - "~n Config: ~p",[Config]), - - {Sup, Par} = ?config(snmp_sup, Config), - ?DBG("stop_agent -> attempt to stop (sup) ~p" - "~n Sup: ~p" - "~n Par: ~p", - [Sup, - (catch process_info(Sup)), - (catch process_info(Par))]), - stop_sup(Sup, Par), - - {Sup2, Par2} = ?config(snmp_sub, Config), - ?DBG("stop_agent -> attempt to stop (sub) ~p" - "~n Sup2: ~p" - "~n Par2: ~p", - [Sup2, - (catch process_info(Sup2)), - (catch process_info(Par2))]), - stop_sup(Sup2, Par2), - - ?DBG("stop_agent -> done - now cleanup config", []), - C1 = lists:keydelete(snmp_sup, 1, Config), - lists:keydelete(snmp_sub, 1, C1). - - -stop_sup(Pid, _) when node(Pid) == node() -> - case (catch process_info(Pid)) of - PI when list(PI) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - exit(Pid, kill), - await_stopped(Pid, Ref); - {'EXIT', _Reason} -> - ?LOG("stop_sup -> ~p not running", [Pid]), - ok - end; -stop_sup(Pid, _) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - ?LOG("stop_sup -> Ref: ~p", [Ref]), - %% Pid ! {'EXIT', Parent, shutdown}, % usch - exit(Pid, kill), - await_stopped(Pid, Ref). - -await_stopped(Pid, Ref) -> - receive - {'DOWN', Ref, process, Pid, _Reason} -> - ?DBG("received down message for ~p", [Pid]), - ok - after 10000 -> - ?INF("await_stopped -> timeout for ~p",[Pid]), - erlang:demonitor(Ref), - ?FAIL({failed_stop,Pid}) - end. - - -start_agent(Config, Vsn) -> - start_agent(Config, Vsn, []). -start_agent(Config, Vsn, Opts) -> - ?LOG("start_agent -> entry (~p) with" - "~n Config: ~p" - "~n Vsn: ~p" - "~n Opts: ~p",[node(), Config, Vsn, Opts]), - - ?line AgentDir = ?config(agent_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - - snmp_app_env_init(vsn_init(Vsn) ++ - [{audit_trail_log, read_write_log}, - {audit_trail_log_dir, AgentDir}, - {audit_trail_log_size, {10240, 10}}, - {force_config_reload, false}, - {snmp_agent_type, master}, - {snmp_config_dir, AgentDir}, - {snmp_db_dir, AgentDir}, - {snmp_local_db_auto_repair, true}, - {snmp_master_agent_verbosity, trace}, - {snmp_supervisor_verbosity, trace}, - {snmp_mibserver_verbosity, trace}, - {snmp_symbolic_store_verbosity, trace}, - {snmp_note_store_verbosity, trace}, - {snmp_net_if_verbosity, trace}], - Opts), - - - process_flag(trap_exit,true), - - {ok, AppSup} = snmp_app_sup:start_link(), - unlink(AppSup), - ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]), - - ?DBG("start_agent -> start master agent (old style)",[]), - Sup = case (catch snmpa_app:start(normal)) of - {ok, S} -> - ?DBG("start_agent -> started, Sup: ~p",[S]), - S; - - Else -> - ?DBG("start_agent -> unknown result: ~n~p",[Else]), - %% Get info about the apps we depend on - MnesiaInfo = mnesia_running(), - ?FAIL({start_failed,Else,MnesiaInfo}) - end, - - ?DBG("start_agent -> unlink from supervisor",[]), - ?line unlink(Sup), - ?line SaDir = ?config(sa_dir, Config), - ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]), - ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]), - ?DBG("start_agent -> done",[]), - ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. - - -vsn_init(Vsn) -> - vsn_init([v1,v2,v3], Vsn, []). - -vsn_init([], _Vsn, Acc) -> - Acc; -vsn_init([V|Vsns], Vsn, Acc) -> - case lists:member(V, Vsn) of - true -> - vsn_init(Vsns, Vsn, [{V, true}|Acc]); - false -> - vsn_init(Vsns, Vsn, [{V, false}|Acc]) - end. - -snmp_app_env_init(Env0, Opts) -> - ?DBG("snmp_app_env_init -> unload snmp",[]), - ?line application:unload(snmp), - ?DBG("snmp_app_env_init -> load snmp",[]), - ?line application:load(snmp), - ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]), - F1 = fun({Key,Val} = New, Acc0) -> - ?DBG("snmp_app_env_init -> " - "updating setting ~p to ~p", [Key, Val]), - case lists:keyreplace(Key, 1, Acc0, New) of - Acc0 -> - [New|Acc0]; - Acc -> - Acc - end - end, - Env = lists:foldr(F1, Env0, Opts), - ?DBG("snmp_app_env_init -> Env: ~p",[Env]), - F2 = fun({Key,Val}) -> - ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]), - application_controller:set_env(snmp, Key, Val) - end, - lists:foreach(F2, Env). - - - - -%% Test if application is running -mnesia_running() -> ?IS_MNESIA_RUNNING(). -crypto_running() -> ?IS_CRYPTO_RUNNING(). - - -start_sub(Dir) -> - ?DBG("start_sub -> entry",[]), - Opts = [{db_dir, Dir}, - {supervisor, [{verbosity, trace}]}], - %% BMK BMK -% {ok, P} = snmp_supervisor:start_sub(Dir), - {ok, P} = snmpa_supervisor:start_sub_sup(Opts), - unlink(P), - {ok, {P, self()}}. - -create_tables(SaNode) -> - ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, - {attributes, [a1,a2]}]). - -delete_tables() -> - mnesia:delete_table(friendsTable2), - mnesia:delete_table(kompissTable2), - mnesia:delete_table(snmp_variables). - -%% Creation is done in runtime! -delete_mib_storage_mnesia_tables() -> - mnesia:delete_table(snmpa_mib_data), - mnesia:delete_table(snmpa_mib_tree), - mnesia:delete_table(snmpa_symbolic_store). - -%%----------------------------------------------------------------- -%% A test case is always one of: -%% - v1 specific case -%% - v2 specific case -%% - v1 and v2 case -%% All v1 specific cases are prefixed with v1_, and all v2 with -%% v2_. E.g. v1_trap/v2_trap. -%% -%% All other cases are shared. However, the testserver uses the name -%% of the case to generate a file for that case. The same case cannot -%% be used in different configurations in the same suite. Therefore -%% all these functions exists in two variants, the base function -%% , and a second version _2. There may be several -%% versions as well, _N. -%%----------------------------------------------------------------- - - - - - - - - - -mib_storage_ets_cases() -> -[mse_simple, mse_v1_processing, mse_big, mse_big2, - mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap, - mse_sa_error, mse_next_across_sa, mse_undo, - mse_standard_mib, mse_community_mib, mse_framework_mib, - mse_target_mib, mse_notification_mib, - mse_view_based_acm_mib, mse_sparse_table, mse_me_of, - mse_mib_of]. - -mib_storage_dets_cases() -> -[msd_simple, msd_v1_processing, msd_big, msd_big2, - msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap, - msd_sa_error, msd_next_across_sa, msd_undo, - msd_standard_mib, msd_community_mib, msd_framework_mib, - msd_target_mib, msd_notification_mib, - msd_view_based_acm_mib, msd_sparse_table, msd_me_of, - msd_mib_of]. - -mib_storage_mnesia_cases() -> -[msm_simple, msm_v1_processing, msm_big, msm_big2, - msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap, - msm_sa_error, msm_next_across_sa, msm_undo, - msm_standard_mib, msm_community_mib, msm_framework_mib, - msm_target_mib, msm_notification_mib, - msm_view_based_acm_mib, msm_sparse_table, msm_me_of, - msm_mib_of]. - -mse_size_check_cases() -> -[mse_size_check]. - -msd_size_check_cases() -> -[msd_size_check]. - -msm_size_check_cases() -> -[msm_size_check]. - -varm_mib_storage_dets_cases() -> -[msd_varm_mib_start]. - -varm_mib_storage_mnesia_cases() -> -[msm_varm_mib_start]. - -init_mib_storage_ets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,ets}, - init_ms(Config, [MibStorage]). - -init_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - init_ms(Config, [MibStorage]). - -init_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - init_ms(Config, [MibStorage]). - -init_ms(Config, Opts) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts], - [{vsn, v1} | start_v1_agent(Config,Opts1)]. - -init_size_check_mse(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, ets}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msd(Config) when list(Config) -> - AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage, {dets, AgentDir}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msm(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, {mnesia,[]}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_ms(Config, Opts) when list(Config) -> - SaNode = ?GCONF(snmp_sa, Config), - %% We are using v3 here, so crypto must be supported or else... - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - create_tables(SaNode), - AgentDir = ?GCONF(agent_dir, Config), - MgrDir = ?GCONF(mgr_dir, Config), - Ip = ?GCONF(ip, Config), - ?line ok = - config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_agent(Config, [v3], Opts)]. - -init_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_dets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -init_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_mnesia -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -finish_mib_storage_ets(Config) when list(Config) -> - ?LOG("finish_mib_storage_ets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_mib_storage_dets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_dets -> entry", []), - delete_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_size_check_mse(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msd(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msm(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_ms(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%% These are just interface functions to fool the test server -mse_simple(X) -> simple(X). -mse_v1_processing(X) -> v1_processing(X). -mse_big(X) -> big(X). -mse_big2(X) -> big2(X). -mse_loop_mib(X) -> loop_mib(X). -mse_api(X) -> api(X). -mse_sa_register(X) -> sa_register(X). -mse_v1_trap(X) -> v1_trap(X). -mse_sa_error(X) -> sa_error(X). -mse_next_across_sa(X) -> next_across_sa(X). -mse_undo(X) -> undo(X). -mse_standard_mib(X) -> snmp_standard_mib(X). -mse_community_mib(X) -> snmp_community_mib(X). -mse_framework_mib(X) -> snmp_framework_mib(X). -mse_target_mib(X) -> snmp_target_mib(X). -mse_notification_mib(X) -> snmp_notification_mib(X). -mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -mse_sparse_table(X) -> sparse_table(X). -mse_me_of(X) -> ms_me_of(X). -mse_mib_of(X) -> ms_mib_of(X). - -msd_simple(X) -> simple(X). -msd_v1_processing(X) -> v1_processing(X). -msd_big(X) -> big(X). -msd_big2(X) -> big2(X). -msd_loop_mib(X) -> loop_mib(X). -msd_api(X) -> api(X). -msd_sa_register(X) -> sa_register(X). -msd_v1_trap(X) -> v1_trap(X). -msd_sa_error(X) -> sa_error(X). -msd_next_across_sa(X) -> next_across_sa(X). -msd_undo(X) -> undo(X). -msd_standard_mib(X) -> snmp_standard_mib(X). -msd_community_mib(X) -> snmp_community_mib(X). -msd_framework_mib(X) -> snmp_framework_mib(X). -msd_target_mib(X) -> snmp_target_mib(X). -msd_notification_mib(X) -> snmp_notification_mib(X). -msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msd_sparse_table(X) -> sparse_table(X). -msd_me_of(X) -> ms_me_of(X). -msd_mib_of(X) -> ms_mib_of(X). - -msm_simple(X) -> simple(X). -msm_v1_processing(X) -> v1_processing(X). -msm_big(X) -> big(X). -msm_big2(X) -> big2(X). -msm_loop_mib(X) -> loop_mib(X). -msm_api(X) -> api(X). -msm_sa_register(X) -> sa_register(X). -msm_v1_trap(X) -> v1_trap(X). -msm_sa_error(X) -> sa_error(X). -msm_next_across_sa(X) -> next_across_sa(X). -msm_undo(X) -> undo(X). -msm_standard_mib(X) -> snmp_standard_mib(X). -msm_community_mib(X) -> snmp_community_mib(X). -msm_framework_mib(X) -> snmp_framework_mib(X). -msm_target_mib(X) -> snmp_target_mib(X). -msm_notification_mib(X) -> snmp_notification_mib(X). -msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msm_sparse_table(X) -> sparse_table(X). -msm_me_of(X) -> ms_me_of(X). -msm_mib_of(X) -> ms_mib_of(X). - - -mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X). -msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X). -msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X). - -msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X). -msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X). - -ms_size_check(suite) -> []; -ms_size_check(Config) when list(Config) -> - p("ms_size_check..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?LOG("mib server size check...", []), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - - -varm_mib_start(suite) -> []; -varm_mib_start(Config) when list(Config) -> - p("varm_mib_start..."), - ?LOG("varm_mib_start -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - %% Start the agent - Opts = ?GCONF(agent_opts, Config), - Config1 = start_v1_agent(Config, Opts), - - %% Sleep some in order for the agent to start properly - ?DBG("varm_mib_start -> sleep some (before loading mobs)", []), - ?SLEEP(5000), - - %% Load all the mibs - HardwiredMibs = loaded_mibs(), - ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - - %% Unload the hardwired mibs - ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), - ?SLEEP(1000), - ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired - - ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), - ?SLEEP(1000), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - Config2 = stop_agent(Config1), - - %% Sleep some in order for the agent to stop properly - ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []), - ?SLEEP(5000), - - %% Start the agent (again) - ?DBG("varm_mib_start -> start the agent", []), - Config3 = start_v1_agent(Config2, Opts), - - ?DBG("varm_mib_start -> sleep some (before starting tests)", []), - ?SLEEP(5000), - - %% Perform the test(s) - ?DBG("varm_mib_start -> perform the tests", []), - try_test(snmp_community_mib), - try_test(snmp_framework_mib), - try_test(snmp_target_mib), - try_test(snmp_notification_mib), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - stop_agent(Config3), - ok. - - --define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]). --define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). --define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -ms_me_of(suite) -> []; -ms_me_of(Config) when list(Config) -> - p("ms_me_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -me_of(Oid) -> - case snmpa:me_of(Oid) of - {ok, #me{oid = Oid}} -> - ok; - {ok, #me{oid = OtherOid}} -> - case lists:reverse(Oid) of - [0|Rest] -> - case lists:reverse(Rest) of - OtherOid -> - ok; - AnotherOid -> - {error, {invalid_oid, Oid, AnotherOid}} - end; - _ -> - {error, {invalid_oid, Oid, OtherOid}} - end; - {error, Reason} -> - {error, Reason}; - Else -> - {error, Else} - end. - - -ms_mib_of(suite) -> []; -ms_mib_of(Config) when list(Config) -> - p("ms_mib_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, - 'SNMP-USER-BASED-SM-MIB'), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -mib_of(Oid, ExpectedMibName) -> - ?DBG("mib_of -> entry with" - "~n Oid: ~p" - "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]), - %% case snmpa:mib_of(Oid) of - MibOf = snmpa:mib_of(Oid), - ?DBG("mib_of -> MibOf: ~n~p", [MibOf]), - case MibOf of - {ok, ExpectedMibName} -> - ok; - {ok, OtherMibName} -> - {error, {invalid_mib, ExpectedMibName, OtherMibName}}; - {error, Reason} -> - {error, Reason}; - Else -> - ?DBG("mib_of -> Else: ~n~p", [Else]), - {error, Else} - end. - - -app_info(suite) -> []; -app_info(Config) when list(Config) -> - SnmpDir = app_dir(snmp), - SslDir = app_dir(ssl), - CryptoDir = app_dir(crypto), - Attr = snmp:module_info(attributes), - AppVsn = - case lists:keysearch(app_vsn, 1, Attr) of - {value, {app_vsn, V}} -> - V; - false -> - "undefined" - end, - io:format("Root dir: ~s~n" - "SNMP: Application dir: ~s~n" - " Application ver: ~s~n" - "SSL: Application dir: ~s~n" - "CRYPTO: Application dir: ~s~n", - [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]), - ok. - -app_dir(App) -> - case code:lib_dir(App) of - D when list(D) -> - filename:basename(D); - {error, _Reason} -> - "undefined" - end. - - - -%v1_cases() -> [loop_mib]; -v1_cases() -> -[simple, db_notify_client, v1_processing, big, big2, - loop_mib, api, subagent, mnesia, {group, multiple_reqs}, - sa_register, v1_trap, sa_error, next_across_sa, undo, - {group, reported_bugs}, {group, standard_mibs}, - sparse_table, cnt_64, opaque, change_target_addr_config]. - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v2_cases() -> [loop_mib_2]; -v2_cases() -> -[simple_2, v2_processing, big_2, big2_2, loop_mib_2, - api_2, subagent_2, mnesia_2, {group, multiple_reqs_2}, - sa_register_2, v2_trap, {group, v2_inform}, sa_error_2, - next_across_sa_2, undo_2, {group, reported_bugs_2}, - {group, standard_mibs_2}, v2_types, implied, - sparse_table_2, cnt_64_2, opaque_2, v2_caps]. - -init_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_v2_agent(Config)]. - -finish_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -v1_v2_cases() -> -[simple_bi]. - -init_v1_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, bilingual} | start_bilingual_agent(Config)]. - -finish_v1_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v3_cases() -> [loop_mib_3]; -v3_cases() -> -[simple_3, v3_processing, big_3, big2_3, api_3, - subagent_3, mnesia_3, loop_mib_3, multiple_reqs_3, - sa_register_3, v3_trap, v3_inform, sa_error_3, - next_across_sa_3, undo_3, {group, reported_bugs_3}, - {group, standard_mibs_3}, {group, v3_security}, - v2_types_3, implied_3, sparse_table_3, cnt_64_3, - opaque_3, v2_caps_3]. - -init_v3(Config) when list(Config) -> - %% Make sure crypto works, otherwise start_agent will fail - %% and we will be stuck with a bunch of mnesia tables for - %% the rest of this suite... - ?DBG("start_agent -> start crypto app",[]), - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. - -finish_v3(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -mt_cases() -> -[multi_threaded, mt_trap]. - -init_mt(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. - -finish_mt(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -%% This one *must* be run first in each case. -init_case(Config) when list(Config) -> - ?DBG("init_case -> entry with" - "~n Config: ~p", [Config]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - MasterNode = node(), - - SaHost = ?HOSTNAME(SaNode), - MgrHost = ?HOSTNAME(MgrNode), - MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), - - - put(mgr_node, MgrNode), - put(sa_node, SaNode), - put(master_node, MasterNode), - put(sa_host, SaHost), - put(mgr_host, MgrHost), - put(master_host, MasterHost), - put(mip, tuple_to_list(MIP)), - put(masterip , tuple_to_list(MasterIP)), - put(sip, tuple_to_list(SIP)), - - MibDir = ?config(mib_dir, Config), - put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - put(std_mib_dir, StdM), - - MgrDir = ?config(mgr_dir, Config), - put(mgr_dir, MgrDir), - - put(vsn, ?config(vsn, Config)), - ?DBG("init_case -> exit with" - "~n MasterNode: ~p" - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]), - {SaNode, MgrNode, MibDir}. - -load_master(Mib) -> - ?DBG("load_master -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). - -load_master_std(Mib) -> - ?DBG("load_master_std -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). - -unload_master(Mib) -> - ?DBG("unload_master -> entry with" - "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). - -loaded_mibs() -> - ?DBG("loaded_mibs -> entry",[]), - Info = snmpa:info(snmp_master_agent), - {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info), - [atom_to_list(Mib) || {Mib,_,_} <- Mibs]. - -unload_mibs(Mibs) -> - ?DBG("unload_mibs -> entry with" - "~n Mibs: ~p", [Mibs]), - ok = snmpa:unload_mibs(snmp_master_agent, Mibs). - -start_subagent(SaNode, RegTree, Mib) -> - ?DBG("start_subagent -> entry with" - "~n SaNode: ~p" - "~n RegTree: ~p" - "~n Mib: ~p", [SaNode, RegTree, Mib]), - MA = whereis(snmp_master_agent), - ?DBG("start_subagent -> MA: ~p", [MA]), - MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), - %% BMK BMK -% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of - case rpc:call(SaNode, snmpa_supervisor, - start_sub_agent, [MA, RegTree, [Mib1]]) of - {ok, SA} -> - ?DBG("start_subagent -> SA: ~p", [SA]), - {ok, SA}; - Error -> - ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]}) - end. - -stop_subagent(SA) -> - ?DBG("stop_subagent -> entry with" - "~n SA: ~p", [SA]), - %% BNK BMK - %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]). - rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]). - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - - -simple(suite) -> []; -simple(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(simple_standard_test). - -simple_2(X) -> simple(X). - -simple_bi(suite) -> []; -simple_bi(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(vsn, v1), % First, try v1 manager - try_test(simple_standard_test), - - put(vsn, v2), % Then, try v2 manager - try_test(simple_standard_test). - -simple_3(X) -> - simple(X). - -big(suite) -> []; -big(Config) when list(Config) -> - ?DBG("big -> entry", []), - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -big_2(X) -> big(X). - -big_3(X) -> big(X). - - -big2(suite) -> []; -big2(Config) when list(Config) -> - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - -big2_2(X) -> big2(X). - -big2_3(X) -> big2(X). - - -multi_threaded(suite) -> []; -multi_threaded(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(multi_threaded_test), - ?line unload_master("Test1"). - -mt_trap(suite) -> []; -mt_trap(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). - -v2_types(suite) -> []; -v2_types(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(types_v2_test), - ?line unload_master("Test1"). - -v2_types_3(X) -> v2_types(X). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(implied_test,[MA]), - ?line unload_master("Test1"). - -implied_3(X) -> implied(X). - - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(sparse_table_test), - ?line unload_master("Test1"). - -sparse_table_2(X) -> sparse_table(X). - -sparse_table_3(X) -> sparse_table(X). - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -cnt_64_2(X) -> cnt_64(X). - -cnt_64_3(X) -> cnt_64(X). - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(opaque_test), - ?line unload_master("Test1"). - -opaque_2(X) -> opaque(X). - -opaque_3(X) -> opaque(X). - - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - try_test(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -api(suite) -> []; -api(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -api_2(X) -> api(X). - -api_3(X) -> api(X). - - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - try_test(load_test_sa), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - - p("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - try_test(load_test), - - p("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - try_test(unreg_test), - p("Testing register subagent..."), - rpc:call(SaNode, snmp, register_subagent, - [MA, ?klas1, SA]), - try_test(load_test_sa), - - ?line stop_subagent(SA), - try_test(unreg_test). - -subagent_2(X) -> subagent(X). - -subagent_3(X) -> subagent(X). - - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - try_test(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - -mnesia_2(X) -> mnesia(X). - -mnesia_3(X) -> mnesia(X). - - - -mul_cases() -> -[mul_get, mul_get_err, mul_next, mul_next_err, - mul_set_err]. - - -multiple_reqs_3(_X) -> - {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}. - - -mul_cases_2() -> -[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, - mul_set_err_2]. - - -mul_cases_3() -> - [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3]. - - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - try_test(do_mul_get). - -mul_get_2(X) -> mul_get(X). - -mul_get_3(X) -> mul_get(X). - - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - try_test(do_mul_get_err). - -mul_get_err_2(X) -> mul_get_err(X). - -mul_get_err_3(X) -> mul_get_err(X). - - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next). - -mul_next_2(X) -> mul_next(X). - -mul_next_3(X) -> mul_next(X). - - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next_err). - -mul_next_err_2(X) -> mul_next_err(X). - -mul_next_err_3(X) -> mul_next_err(X). - - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set..."), - try_test(do_mul_set). - -mul_set_2(X) -> mul_set(X). - -mul_set_3(X) -> mul_set(X). - - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set with error..."), - try_test(do_mul_set_err). - -mul_set_err_2(X) -> mul_set_err(X). - -mul_set_err_3(X) -> mul_set_err(X). - - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?DBG("sa_register -> entry", []), - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - p("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - try_test(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -sa_register_2(X) -> sa_register(X). - -sa_register_3(X) -> sa_register(X). - - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_trap1, [MA]), - try_test(ma_trap2, [MA]), - try_test(ma_v2_2_v1_trap, [MA]), - try_test(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - try_test(sa_trap1, [SA]), - try_test(sa_trap2, [SA]), - try_test(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v2_trap(suite) -> []; -v2_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - - try_test(ma_v2_trap1, [MA]), - try_test(ma_v2_trap2, [MA]), - try_test(ma_v1_2_v2_trap, [MA]), - try_test(ma_v1_2_v2_trap2, [MA]), - - try_test(sa_mib), - p("Testing trap sending from subagent..."), - try_test(sa_v1_2_v2_trap1, [SA]), - try_test(sa_v1_2_v2_trap2, [SA]), - try_test(sa_v1_2_v2_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v3_trap(X) -> - v2_trap(X). - - -v3_inform(_X) -> - %% v2_inform(X). - {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}. - -init_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -init_v3_inform(X) -> - init_v2_inform(X). - -finish_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -finish_v3_inform(X) -> - finish_v2_inform(X). - - - -v2_inform_i(suite) -> []; -v2_inform_i(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing inform sending from master agent... NOTE! This test\ntakes a " - "few minutes (5) to complete."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_v2_inform1, [MA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"). - -v3_inform_i(X) -> v2_inform_i(X). - - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - try_test(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - try_test(sa_errs_gen_err), - - p("Testing too big..."), - try_test(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -sa_error_2(X) -> sa_error(X). - -sa_error_3(X) -> sa_error(X). - - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - try_test(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - try_test(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - try_test(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -next_across_sa_2(X) -> next_across_sa(X). - -next_across_sa_3(X) -> next_across_sa(X). - - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - try_test(undo_test), - try_test(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - try_test(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - try_test(undo_test), - try_test(api_test3), - - p("Testing undo phase across master/subagents..."), - try_test(undo_test), - try_test(api_test3), - stop_subagent(SA). - -undo_2(X) -> undo(X). - -undo_3(X) -> undo(X). - -%% Req. Test2 -v1_processing(suite) -> []; -v1_processing(Config) when list(Config) -> - ?DBG("v1_processing -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v1_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v2_processing(suite) -> []; -v2_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v3_processing(suite) -> []; -v3_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), % same as v2! - ?line unload_master("Test2"). - - -%% We'll try get/set/trap and inform for all the auth & priv protocols. -%% For informs, the mgr is auth-engine. The agent has to sync. This is -%% accomplished by the first inform sent. That one will generate a -%% report, which makes it in sync. The notification-generating -%% application times out, and send again. This time it'll work. - -v3_crypto_basic(suite) -> []; -v3_crypto_basic(_Config) -> - EID = [0,0,0,0,0,0,0,0,0,0,0,2], - %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, - 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = - KMd5_1, - %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, - 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = - KSHA_1, - %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, - 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = - snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, - 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, - 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - KSHA_1t = lists:sublist(KSHA_1, 16), - KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, - 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - - %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), - ok. - - - -v3_md5_auth(suite) -> []; -v3_md5_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing MD5 authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authMD5"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_sha_auth(suite) -> []; -v3_sha_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing SHA authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authSHA"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_des_priv(suite) -> []; -v3_des_priv(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing DES encryption...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -%% Make sure mgr is in sync with agent -v3_sync(Funcs) -> - ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]), - g([[sysDescr, 0]]), - expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]), - g([[sysDescr, 0]]), - expect(433, [{[sysDescr,0], any}]), - lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs). - -v3_inform_sync(MA) -> - ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, - "standard inform", []), - %% Make sure agent is in sync with mgr... - ?DBG("v3_sync -> wait some time: ",[]), - sleep(20000), % more than 1500*10 in target_addr.conf - ?DBG("v3_sync -> await response",[]), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]). - - -v2_caps(suite) -> []; -v2_caps(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(v2_caps_i, [node()]). - -v2_caps_3(X) -> v2_caps(X). - - -v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]), - g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]}, - {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmp, del_agent_caps, [Idx]), - g([[sysORID, Idx]]), - ?line expect(2, [{[sysORID, Idx], noSuchInstance}]). - - -%% Req. Test2 -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - - -v1_get_p() -> - %% 4.1.2:1 - g([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - g([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - g([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - g([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - g([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - g([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - g([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - g([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - g([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - g([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - - -v1_get_next_p() -> - %% 4.1.3:1 - gn([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - gn([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - gn([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), -% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - gn([[tGenErr1]]), -% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - gn([[tGenErr2]]), -% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - gn([[sysDescr], [tGenErr3]]), -% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, -% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - s([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - s([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - s([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - s([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: -% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - s([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - -%% Req. Test2 -v2_proc() -> - %% According to RFC1905. - %% Template:
    : - ?DBG("v2_proc -> entry",[]), - v2_get_p(), - v2_get_next_p(), - v2_get_bulk_p(), - v2_set_p(). - -v2_get_p() -> - %% 4.2.1:2 - ?DBG("v2_get_p -> entry",[]), - g([[test2]]), - ?line expect(10, [{[test2], noSuchObject}]), - g([[tDescr]]), - ?line expect(11, [{[tDescr], noSuchObject}]), - g([[tDescr4,0]]), - ?line expect(12, [{[tDescr4,0], noSuchObject}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}, - {[tDescr,0], noSuchObject}]), - g([[tTable]]), - ?line expect(14, [{[tTable], noSuchObject}]), - g([[tEntry]]), - ?line expect(15, [{[tEntry], noSuchObject}]), - - %% 4.2.1:3 - g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line expect(20, [{[tDescr2,0], noSuchInstance}]), - g([[tDescr3,0]]), - ?line expect(21, [{[tDescr3,0], noSuchInstance}]), - g([[sysDescr,3]]), - ?line expect(22, [{[sysDescr, 3], noSuchInstance}]), - g([[tIndex,1]]), - ?line expect(23, [{[tIndex, 1], noSuchInstance}]), - - %% 4.2.1 - any other error: genErr - g([[tGenErr1, 0]]), - ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]), - - %% 4.2.1 - tooBig - g([[tTooBig, 0]]), - ?line expect(40, tooBig, 0, []). - - -v2_get_next_p() -> - %% 4.2.2:2 - ?DBG("v2_get_next_p -> entry",[]), - gn([[1,3,7,1]]), - ?line expect(10, [{[1,3,7,1], endOfMibView}]), - gn([[sysDescr], [1,3,7,1]]), - ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gn([[tCnt2, 1]]), - ?line expect(12, [{[tCnt2,2], 100}]), - gn([[tCnt2, 2]]), - ?line expect(12, [{[tCnt2,2], endOfMibView}]), - - %% 4.2.2 - any other error: genErr - gn([[tGenErr1]]), - ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]), - gn([[tGenErr2]]), - ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]), - gn([[sysDescr], [tGenErr3]]), - ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'}, - {[tGenErr3], 'NULL'}]), - - %% 4.2.2 - tooBig - gn([[tTooBig]]), - ?line expect(20, tooBig, 0, []). - -v2_get_bulk_p() -> - %% 4.2.3 - ?DBG("v2_get_bulk_p -> entry",[]), - gb(1, 1, []), - ?line expect(10, []), - gb(-1, 1, []), - ?line expect(11, []), - gb(-1, -1, []), - ?line expect(12, []), - gb(-1, -1, []), - ?line expect(13, []), - gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[sysDescr, 0], "Erlang SNMP agent"}]), - - gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line expect(19, []), - - gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'}, - {[sysObjectID], 'NULL'}, - {[tGenErr1], 'NULL'}, - {[sysDescr], 'NULL'}]), - gb(0, 2, [[tCnt2, 1]]), - ?line expect(21, [{[tCnt2,2], 100}, - {[tCnt2,2], endOfMibView}]). - - -v2_set_p() -> - %% 4.2.5:1 - ?DBG("v2_set_p -> entry",[]), - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]), - - %% 4.2.5:2 - s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), - - %% 4.2.5:3 - s([{[tDescr2, 0], i, 4}]), - ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.2.5:4 - s([{[tStr, 0], s, ""}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]), - s([{[tStr, 0], s, "12345"}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]), - - %% 4.2.5:5 - N/A - - %% 4.2.5:6 - s([{[tInt1, 0], i, 0}]), - ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]), - s([{[tInt1, 0], i, 5}]), - ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]), - s([{[tInt2, 0], i, 0}]), - ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]), - s([{[tInt2, 0], i, 5}]), - ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]), - s([{[tInt3, 0], i, 5}]), - ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]), - - %% 4.2.5:7 - s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), - - %% 4.2.5:8 - s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line expect(80, inconsistentName, 1, - [{[tDescrX, 1, 2], "inconsistentName"}]), - - %% 4.2.5:9 - s([{[tCnt, 1, 2], i, 5}]), - ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]), - - %% 4.2.5:10 - s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line expect(100, inconsistentValue, 1, - [{[tDescr2,0], "inconsistentValue"}]), - - %% 4.2.5:11 - s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line expect(110, resourceUnavailable, 1, - [{[tDescr2,0],"resourceUnavailable"}]), - - %% 4.2.5:12 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). - - %% commitFailed and undoFailed is tested by the 'undo' case. - - -%% Req. OLD-SNMPEA-MIB -table_test() -> - io:format("Testing simple get, next and set on communityTable...~n"), -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. - Key1c3 = [intCommunityViewIndex,get(mip),is("public")], - Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")], - Key1c4 = [intCommunityAccess,get(mip),is("public")], - EndKey = [intCommunityEntry,[9],get(mip),is("public")], - gn([[intCommunityEntry]]), - ?line expect(7, [{Key1c3, 2}]), - gn([[intCommunityTable]]), - ?line expect(71, [{Key1c3, 2}]), - gn([[community]]), - ?line expect(72, [{Key1c3, 2}]), - gn([[otpSnmpeaMIB]]), - ?line expect(73, [{Key1c3, 2}]), - gn([[ericsson]]), - ?line expect(74, [{Key1c3, 2}]), - gn([Key1c3]), - ?line expect(8, [{Key2c3, 2}]), - gn([Key2c3]), - ?line expect(9, [{Key1c4, 2}]), - gn([EndKey]), - AgentIp = [intAgentIpAddress,0], - ?line expect(10, [{AgentIp, any}]), - g([Key1c3]), - ?line expect(11, [{Key1c3, 2}]), - g([EndKey]), - ?line ?v1_2(expect(12, noSuchName, 1, any), - expect(12, [{EndKey, noSuchObject}])), - - io:format("Testing row creation/deletion on communityTable...~n"), - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - s([{NewKeyc5, ?createAndGo}]), - ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any), - s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), - g([NewKeyc4]), - ?line expect(16, [{NewKeyc4, 2}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(17, [{NewKeyc5, ?destroy}]), - s([{NewKeyc4, 2}]), - ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]), - s([{NewKeyc5, ?createAndWait}]), - ?line expect(19, [{NewKeyc5, ?createAndWait}]), - g([NewKeyc5]), - ?line expect(20, [{NewKeyc5, ?notReady}]), - s([{NewKeyc4, 2}]), - ?line expect(21, [{NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(22, [{NewKeyc5, ?notReady}]), - s([{NewKeyc3, 2}]), - ?line expect(23, [{NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(24, [{NewKeyc5, ?notInService}]), - s([{NewKeyc5, ?active}]), - ?line expect(25, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(26, [{NewKeyc5, ?destroy}]), - s([{NewKeyc3, 3}]), - ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]), - otp_1128(). - -%% Req. system group -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - gn([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - g([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - gn([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - g([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - io:format("Testing noSuchName and badValue...~n"), - s([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - s([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - try_test(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - gn([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - g([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - s([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - s([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - g([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - gn([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - s([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - gn([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - p("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - gn([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - g([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - s([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - g([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - p("Testing next from last object in master to subagent (2)..."), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - p("Adding one row in subagent table (2)"), - _FTab = [friendsEntry2], - s([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - g([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - p("Adding two rows in subagent table with special INDEX (2)"), - s([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - g([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - gn([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - s([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - gn([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - -%% Req. Test1 -multi_threaded_test() -> - p("Testing multi threaded agent..."), - g([[multiStr,0]]), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(1, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "pelle"}]), - ?line expect(2, [{[sysLocation, 0], "pelle"}]), - Pid ! continue, - ?line expect(3, [{[multiStr,0], "ok"}]), - - s([{[multiStr, 0], s, "block"}]), - Pid2 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(4, [{[sysUpTime,0], any}]), - g([[multiStr,0]]), - Pid3 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(5, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "kalle"}]), - Pid3 ! continue, - ?line expect(6, [{[multiStr,0], "ok"}]), - Pid2 ! continue, - ?line expect(7, [{[multiStr,0], "block"}]), - ?line expect(8, [{[sysLocation,0], "kalle"}]). - -%% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - snmpa:send_trap(MA, mtTrap, "standard trap"), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(2, [{[sysUpTime,0], any}]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - Pid ! continue, - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]). - - -get_multi_pid() -> - get_multi_pid(10). -get_multi_pid(0) -> - ?line ?FAIL(no_global_name); -get_multi_pid(N) -> - sleep(1000), - case global:whereis_name(snmp_multi_tester) of - Pid when pid(Pid) -> Pid; - _ -> get_multi_pid(N-1) - end. - -%% Req. Test1 -types_v2_test() -> - p("Testing v2 types..."), - - s([{[bits1,0], 2#10}]), - ?line expect(1, [{[bits1,0], ?str(2#10)}]), - g([[bits1,0]]), - ?line expect(2, [{[bits1,0], ?str(2#101)}]), - - s([{[bits2,0], 2#11000000110}]), - ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]), - g([[bits2,0]]), - ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]), - - g([[bits3,0]]), - ?line expect(50, genErr, 1, any), - - g([[bits4,0]]), - ?line expect(51, genErr, 1, any), - - s([{[bits1,0], s, [2#10]}]), - ?line expect(6, ?v1_2(badValue, wrongValue), 1, any), - - s([{[bits2,0], 2#11001001101010011}]), - ?line expect(7, ?v1_2(badValue, wrongValue), 1, any). - - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - p("Testing IMPLIED..."), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - gn([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - gn([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr2)",[]), - gn([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - gn([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, - oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, - int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - -%% Req. Klas3 -api_test2() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]), - g([[fname4,0]]), - ?line expect(2, [{[fname4,0], 1}]). - -api_test3() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]). - - -unreg_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - -%% Req. Klas1 -load_test_sa() -> - gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -%% Note: This test case takes a while... actually a couple of minutes. -ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform -> entry with MA = ~p => " - "send notification: testTrapv22",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag1, self()}, - "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag1, [_]} -> - ok; - {snmp_targets, tag1, Addrs1} -> - ?line ?FAIL({bad_addrs, Addrs1}) - after - 5000 -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag1, {got_response, _}} -> - ok; - {snmp_notification, tag1, {no_response, _}} -> - ?line ?FAIL(no_response) - after - 20000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - - %% - %% -- The rest is possibly erroneous... - %% - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag2, self()}, - "standard inform", []), - ?line expect(2, {inform, false}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag2, [_]} -> - ok; - {snmp_targets, tag2, Addrs2} -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]), - ?line ?FAIL({bad_addrs, Addrs2}) - after - 5000 -> - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag2, {got_response, _}} -> - ?line ?FAIL(got_response); - {snmp_notification, tag2, {no_response, _}} -> - ok - after - 240000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag2) timeout",[]), - ?line ?FAIL(nothing_at_all) - end. - - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. -% it depends on which order the agent traverses the varbind list. -% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- - - - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - try_test(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = try_test(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - try_test(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = try_test(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - try_test(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - try_test(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - try_test(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - try_test(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - try_test(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - try_test(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - try_test(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]). - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v2 and v3. -%% o Test the counters and control objects in SNMPv2-MIB -%%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; -snmpv2_mib_2(Config) when list(Config) -> - ?LOG("snmpv2_mib_2 -> start",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?DBG("snmpv2_mib_2 -> standard mib init",[]), - try_test(std_mib_init), - - ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]), - InBadVsns = try_test(std_mib_a), - - ?DBG("snmpv2_mib_2 -> make a bad version read",[]), - put(vsn, v1), - try_test(std_mib_read), - - ?DBG("snmpv2_mib_2 -> bad version read",[]), - put(vsn, v2), - Bad = try_test(std_mib_b, [InBadVsns]), - - ?DBG("snmpv2_mib_2 -> read with bad community",[]), - try_test(std_mib_read, [], [{community, "bad community"}]), - - ?DBG("snmpv2_mib_2 -> write with public community",[]), - try_test(std_mib_write, [], [{community, "public"}]), - - ?DBG("snmpv2_mib_2 -> asn err",[]), - try_test(std_mib_asn_err), - - ?DBG("snmpv2_mib_2 -> check counters",[]), - try_test(std_mib_c, [Bad]), - - ?DBG("snmpv2_mib_2 -> get som counters",[]), - try_test(snmpv2_mib_a), - - ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), - try_test(std_mib_finish), - - ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, " - "then disable auth traps",[]), - try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]), - - ?LOG("snmpv2_mib_2 -> done",[]). - -%% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; -snmpv2_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - InBadVsns = try_test(std_mib_a), - put(vsn, v1), - try_test(std_mib_read), - put(vsn, v3), - _Bad = try_test(std_mib_b, [InBadVsns]), - try_test(snmpv2_mib_a), - - try_test(std_mib_finish). - --define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]). - -%% Req. SNMPv2-MIB -snmpv2_mib_test_finish() -> - %% force a authenticationFailure - ?DBG("ma_v2_inform -> write to std mib",[]), - std_mib_write(), - - %% check that we got a trap - ?DBG("ma_v2_inform -> await trap",[]), - ?line expect(2, v2trap, [{[sysUpTime,0], any}, - {[snmpTrapOID,0], ?authenticationFailure}]), - - %% and the the inform - ?DBG("ma_v2_inform -> await inform",[]), - ?line expect(2, {inform,true}, [{[sysUpTime,0], any}, - {[snmpTrapOID,0],?authenticationFailure}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - -%% Req. SNMPv2-MIB -snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), - s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), - s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, - [{[sysLocation, 0], "val3"}, - {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]). - - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - try_test(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - try_test(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -snmp_framework_mib_2(X) -> snmp_framework_mib(X). - -snmp_framework_mib_3(suite) -> []; -snmp_framework_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(snmp_framework_mib). - - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - -%%----------------------------------------------------------------- -%% o Test the counters -%%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; -snmp_mpd_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - UnknownPDUHs = try_test(snmp_mpd_mib_a), - try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]), - try_test(snmp_mpd_mib_c, [UnknownPDUHs]). - - -%% Req. SNMP-MPD-MIB -snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0]]), - Pdu = #pdu{type = 'get-request', - request_id = 23, - error_status = noError, - error_index = 0, - varbinds = []}, - SPdu = #scopedPdu{contextEngineID = "agentEngine", - contextName = "", - data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), - V3Hdr1 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [7], - msgSecurityModel = 23, % bad sec model - msgSecurityParameters = []}, - V3Hdr2 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [6], % bad flag combination - msgSecurityModel = 3, - msgSecurityParameters = []}, - Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1, - data = SPDUBytes}, - Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, - data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), - snmp_test_mgr:send_bytes(MsgBytes1), - snmp_test_mgr:send_bytes(MsgBytes2), - - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0], - [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, - UnknownPDUHs. - --define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). -snmp_mpd_mib_b() -> - g([[sysUpTime,0]]), - ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]). - - -snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1. - - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - try_test(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib_2(X) -> snmp_target_mib(X). - -snmp_target_mib_3(X) -> snmp_target_mib(X). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - try_test(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib_2(X) -> snmp_notification_mib(X). - -snmp_notification_mib_3(X) -> snmp_notification_mib(X). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line try_test(do_set, [ARow2]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [ARow2Status]), - - - %% Add valid row - ?line try_test(do_set, [ARow1]), - - ?line try_test(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), - - %% We should still have access... - ?line try_test(use_rights, [], Opts), - - %% Delete rows - ?line try_test(del_row, [GRow1Status]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), - - ?line try_test(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - -mk_ln(X) -> - [length(X) | X]. - -%%----------------------------------------------------------------- -%% o add/delete users and try them -%% o test all secLevels -%% o test all combinations of protocols -%% o try bad ops; check counters -%%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; -snmp_user_based_sm_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - _AgentDir = ?config(agent_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - - %% The newUser used here already has VACM access. - - %% Add a new user in the simplest way; just createAndGo - try_test(v3_sync, [[{usm_add_user1, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new user - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), - DesKey1 = lists:sublist(ShaKey1, 16), - - %% Change the new user's keys - 1 - try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), - DesKey2 = lists:sublist(ShaKey2, 16), - - %% Change the new user's keys - 2 - ?line try_test(v3_sync, - [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Change the new user's keys - 3 - ?line try_test(v3_sync, - [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("SNMP-USER-BASED-SM-MIB"). - --define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). - -usm_add_user1() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - -usm_use_user() -> - v2_proc(). - - -%% Change own public keys -usm_key_change1(ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_shaxxxxxxxxxx", - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_desxxxxxx", - DesKey), - Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change own private keys -usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change other's public keys -usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], - s(Vbs1), - ?line expect(1, noAccess, 1, any), - Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs2), - ?line expect(2, noAccess, 1, any), - - - Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs3), - ?line expect(1, Vbs3). - -usm_read() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], - [usmUserCloneFrom, NewRowIndex], - [usmUserAuthKeyChange, NewRowIndex], - [usmUserOwnAuthKeyChange, NewRowIndex], - [usmUserPrivKeyChange, NewRowIndex], - [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line expect(1, - [{[usmUserSecurityName, NewRowIndex], "newUser"}, - {[usmUserCloneFrom, NewRowIndex], [0,0]}, - {[usmUserAuthKeyChange, NewRowIndex], ""}, - {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, - {[usmUserPrivKeyChange, NewRowIndex], ""}, - {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]), - ok. - - - -usm_del_user() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - --define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). - --define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]). - --define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]). - --define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]). - --define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]). - --define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]). - -usm_bad() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, inconsistentName, 1, any), - - RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line expect(2, wrongValue, 1, any), - - RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line expect(3, Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line expect(4, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line expect(5, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line expect(6, wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line expect(7, wrongValue, 1, any), - - Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line expect(1, Vbs4), - - ok. - - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?LOG("loop_mib -> initiate case",[]), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - try_test(loop_mib_1), - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - - -loop_mib_2(suite) -> []; -loop_mib_2(Config) when list(Config) -> - ?LOG("loop_mib_2 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_2 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?LOG("loop_mib_2 -> done",[]). - - -loop_mib_3(suite) -> []; -loop_mib_3(Config) when list(Config) -> - ?LOG("loop_mib_3 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_3 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?LOG("loop_mib_3 -> done",[]). - - -%% Req. As many mibs all possible -loop_mib_1() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_1([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_1(Oid, N) -> - ?DBG("loop_it_1 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_1 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_1(NOid, N+1); - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it_1 -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - end. - -%% Req. As many mibs all possible -loop_mib_2() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_2([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_2(Oid, N) -> - ?DBG("loop_it_2 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid, value = endOfMibView}]} -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p",[NOid]), - N; - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_2 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_2(NOid, N+1) - end. - - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - - - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128_2(X) -> otp_1128(X). - -otp_1128_3(X) -> otp_1128(X). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_2(X) -> otp_1129(X). - -otp_1129_3(X) -> otp_1129(X). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - try_test(otp_1131), - ?line unload_master("Klas1"). - -otp_1131_2(X) -> otp_1131(X). - -otp_1131_3(X) -> otp_1131(X). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - try_test(otp_1162), - stop_subagent(SA). - -otp_1162_2(X) -> otp_1162(X). - -otp_1162_3(X) -> otp_1162(X). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - try_test(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222_2(X) -> otp_1222(X). - -otp_1222_3(X) -> otp_1222(X). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1298), - ?line unload_master("Klas2"). - -otp_1298_2(X) -> otp_1298(X). - -otp_1298_3(X) -> otp_1298(X). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331_2(X) -> otp_1331(X). - -otp_1331_3(X) -> otp_1331(X). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1338), - ?line unload_master("Klas2"). - -otp_1338_2(X) -> otp_1338(X). - -otp_1338_3(X) -> otp_1338(X). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas4"), - try_test(otp_1342), - ?line unload_master("Klas4"). - -otp_1342_2(X) -> otp_1342(X). - -otp_1342_3(X) -> otp_1342(X). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366_2(X) -> otp_1366(X). - -otp_1366_3(X) -> otp_1366(X). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_2776). - -otp_2776_2(X) -> otp_2776(X). - -otp_2776_3(X) -> otp_2776(X). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Test1"), - ?line init_old(), - try_test(otp_2979), - ?line unload_master("Test1"). - -otp_2979_2(X) -> otp_2979(X). - -otp_2979_3(X) -> otp_2979(X). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187_2(X) -> otp_3187(X). - -otp_3187_3(X) -> otp_3187(X). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - - - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - - - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?DBG("otp_4394_test -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -%%%-------------------------------------------------- -%%% Used to test the standard mib with our -%%% configuration. -%%%-------------------------------------------------- -run(F, A, Opts) -> - M = get(mib_dir), - Dir = get(mgr_dir), - User = snmp_misc:get_option(user, Opts, "all-rights"), - SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv), - EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"), - CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), - Community = snmp_misc:get_option(community, Opts, "all-rights"), - ?DBG("run -> start crypto app",[]), - Crypto = ?CRYPTO_START(), - ?DBG("run -> Crypto: ~p",[Crypto]), - catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - ?DBG("run -> config:~n" - "\tM: ~p~n" - "\tDir: ~p~n" - "\tUser: ~p~n" - "\tSecLevel: ~p~n" - "\tEngineID: ~p~n" - "\tCtxEngineID: ~p~n" - "\tCommunity: ~p~n" - "\tStdM: ~p", - [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]), - case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()}, - {packet_server_debug,true}, - {debug,true}, - {agent, get(master_host)}, - {agent_udp, 4000}, - {trap_udp, 5000}, - {recbuf,65535}, - quiet, - get(vsn), - {community, Community}, - {user, User}, - {sec_level, SecLevel}, - {engine_id, EngineID}, - {context_engine_id, CtxEngineID}, - {dir, Dir}, - {mibs, mibs(StdM, M)}]) of - {ok, _Pid} -> - Res = apply(?MODULE, F, A), - catch snmp_test_mgr:stop(), - Res; - Err -> - io:format("Error starting manager: ~p\n", [Err]), - catch snmp_test_mgr:stop(), - ?line exit({mgr_start, Err}) - end. - - -mibs(StdMibDir,MibDir) -> - [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")), - join(MibDir, "OLD-SNMPEA-MIB.bin"), - join(StdMibDir, "SNMP-FRAMEWORK-MIB"), - join(StdMibDir, "SNMP-MPD-MIB"), - join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"), - join(StdMibDir, "SNMP-USER-BASED-SM-MIB"), - join(StdMibDir, "SNMP-TARGET-MIB"), - join(StdMibDir, "SNMP-NOTIFICATION-MIB"), - join(MibDir, "Klas1.bin"), - join(MibDir, "Klas2.bin"), - join(MibDir, "Klas3.bin"), - join(MibDir, "Klas4.bin"), - join(MibDir, "SA-MIB.bin"), - join(MibDir, "TestTrap.bin"), - join(MibDir, "Test1.bin"), - join(MibDir, "Test2.bin"), - join(MibDir, "TestTrapv2.bin")]. - -join(D,F) -> - filename:join(D,F). - -%% string used in index -is(S) -> [length(S) | S]. - -try_test(Func) -> - call(get(mgr_node), ?MODULE, run, [Func, [], []]). - -try_test(Func, A) -> - call(get(mgr_node), ?MODULE, run, [Func, A, []]). - -try_test(Func, A, Opts) -> - call(get(mgr_node), ?MODULE, run, [Func, A, Opts]). - -call(N,M,F,A) -> - ?DBG("call -> entry with~n" - " N: ~p~n" - " M: ~p~n" - " F: ~p~n" - " A: ~p~n" - " when~n" - " get(): ~p", - [N,M,F,A,get()]), - spawn(N, ?MODULE, wait, [self(),get(),M,F,A]), - receive - {done, {'EXIT', Rn}, Loc} -> - ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]), - put(test_server_loc, Loc), - exit(Rn); - {done, Ret, Zed} -> - ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]), - Ret - end. - -wait(From, Env, M, F, A) -> - ?DBG("wait -> entry with ~n" - "\tFrom: ~p~n" - "\tEnv: ~p",[From,Env]), - lists:foreach(fun({K,V}) -> put(K,V) end, Env), - Rn = (catch apply(M, F, A)), - ?DBG("wait -> Rn: ~n~p", [Rn]), - From ! {done, Rn, get(test_server_loc)}, - exit(Rn). - -expect(A,B) -> ok = snmp_test_mgr:expect(A,B). -expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C). -expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F). - -get_req(Id, Vars) -> - ?DBG("get_req -> entry with~n" - "\tId: ~p~n" - "\tVars: ~p",[Id,Vars]), - g(Vars), - ?DBG("get_req -> await response",[]), - {ok, Val} = snmp_test_mgr:get_response(Id, Vars), - ?DBG("get_req -> response: ~p",[Val]), - Val. - -get_next_req(Vars) -> - ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]), - gn(Vars), - ?DBG("get_next_req -> await response",[]), - Response = snmp_test_mgr:receive_response(), - ?DBG("get_next_req -> response: ~p",[Response]), - Response. - - - -start_node(Name) -> - ?LOG("start_node -> entry with Name: ~p",[Name]), - M = list_to_atom(?HOSTNAME(node())), - ?DBG("start_node -> M: ~p",[M]), - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p",[Pa]), - - Args = case init:get_argument('CC_TEST') of - {ok, [[]]} -> - " -pa /clearcase/otp/libraries/snmp/ebin "; - {ok, [[Path]]} -> - " -pa " ++ Path; - error -> - "" - end, - %% Do not use start_link!!! (the proc that calls this one is tmp) - ?DBG("start_node -> Args: ~p~n",[Args]), - A = Args ++ " -pa " ++ Pa, - case (catch ?START_NODE(Name, A)) of - {ok, Node} -> - %% Tell the test_server to not clean up things it never started. - ?DBG("start_node -> Node: ~p",[Node]), - {ok, Node}; - Else -> - ?ERR("start_node -> failed with(other): Else: ~p",[Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?LOG("stop_node -> Node: ~p",[Node]), - rpc:cast(Node, erlang, halt, []). - -p(X) -> - io:format(user, X++"\n", []). - -sleep(X) -> - receive - after - X -> ok - end. - -%%%----------------------------------------------------------------- -%%% Configuration -%%%----------------------------------------------------------------- -config(Vsns, MgrDir, AgentDir, MIp, AIp) -> - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp, - ?TRAP_UDP, AIp, 4000, - "test"), - ?line case update_usm(Vsns, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); - false -> - ?line ok - end, - ?line update_community(Vsns, AgentDir), - ?line update_vacm(Vsns, AgentDir), - ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns), - ?line write_target_params_conf(AgentDir, Vsns), - ?line write_notify_conf(AgentDir), - ok. - -delete_files(Config) -> - Dir = ?config(agent_dir, Config), - {ok, List} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, - List). - -update_usm(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -update_usm_mgr(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - file:close(Fid). - -reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). - - -update_community([v3], _Dir) -> ok; -update_community(_, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n", - []), - file:close(Fid). - - --define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). -update_vacm(_Vsn, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]), - ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", " - "~w, excluded, null}.\n", [?tDescr_instance]), - file:close(Fid). - - -vacm_ver(v1) -> v1; -vacm_ver(v2) -> v2c; -vacm_ver(v3) -> usm. - - -write_community_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write), - ok = write_community_conf1(Fid, Confs), - file:close(Fid). - -write_community_conf1(_, []) -> - ok; -write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) -> - ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [ComIdx, ComName, SecName, CtxName, TransTag]), - write_community_conf1(Fid, Confs). - - -write_target_addr_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - ok = write_target_addr_conf1(Fid, Confs), - file:close(Fid). - - -write_target_addr_conf1(_, []) -> - ok; -write_target_addr_conf1(Fid, - [{Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz}|Confs]) -> - ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz]), - write_target_addr_conf1(Fid, Confs). - -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - lists:foreach(fun(Vsn) -> - ok = io:format(Fid, - "{\"~s\", ~w, ~w, 1500, 3, " - "\"std_trap\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, mk_param(Vsn)]), - case Vsn of - v1 -> ok; - v2 -> - ok = io:format(Fid, - "{\"~s.2\",~w,~w,1500,3, " - "\"std_inform\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]); - v3 -> - ok = io:format(Fid, - "{\"~s.3\",~w,~w,1500,3, " - "\"std_inform\", \"~s\", " - "\"mgrEngine\", [], 1024}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]) - end - end, - Vsns), - file:close(Fid). - -mk_param(v1) -> "target_v1"; -mk_param(v2) -> "target_v2"; -mk_param(v3) -> "target_v3". - -mk_ip([A,B,C,D], Vsn) -> - io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]). - - -rewrite_target_addr_conf(Dir,NewPort) -> - TAFile = filename:join(Dir, "target_addr.conf"), - ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]), - case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok - end, - - ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end), - - ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), - - NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs], - - ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - - ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs), - - file:close(Fid). - -rewrite_target_addr_conf1(O) -> - {ok,O}. - -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> - ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), - {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; -rewrite_target_addr_conf2(_NewPort,O) -> - ?LOG("rewrite_target_addr_conf2 -> entry with " - "~n O: ~p",[O]), - O. - - -rewrite_target_addr_conf3(_,[]) -> ok; -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry, - ParamName,EngineId}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % ParamsName - "\"~s\"}.", % EngineId - [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]), - rewrite_target_addr_conf3(Fid,T); -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList, - ParamName,EngineId,TMask,MMS}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % TagList - "\"~s\", " % ParamsName - "\"~s\"," % EngineId - "~p, " % TMask - "~p}.", % MMS - [Name,Ip,Port,Timeout,Retry,TagList,ParamName, - EngineId,TMask,MMS]), - rewrite_target_addr_conf3(Fid,T). - -reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_addr.old"), - filename:join(Dir,"target_addr.conf")). - -write_target_params_conf(Dir, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - lists:foreach(fun(Vsn) -> - MP = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> v3 - end, - SM = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> usm - end, - ok = io:format(Fid, "{\"target_~w\", ~w, ~w, " - "\"all-rights\", noAuthNoPriv}.~n", - [Vsn, MP, SM]) - end, - Vsns), - file:close(Fid). - -rewrite_target_params_conf(Dir, SecName, SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n", - [SecName, SecLevel]), - file:close(Fid). - -reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). - -write_notify_conf(Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write), - ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []), - ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []), - file:close(Fid). - -ver_to_trap_str([v1]) -> "v1"; -ver_to_trap_str([v2]) -> "v2"; -% default is to use the latest snmp version -ver_to_trap_str([v1,v2]) -> "v2". - - - -write_view_conf(Dir) -> - {ok, Fid} = file:open(a(Dir,"view.conf"),write), - ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []), - ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]), - file:close(Fid). - -a(A,B) -> lists:append(A,B). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -copy_file(From, To) -> - {ok, Bin} = file:read_file(From), - ok = file:write_file(To, Bin). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_memory_usage() -> - Info = snmpa:info(snmp_master_agent), - TreeSize = lists_key1search(tree_size_bytes, Info), - ProcMem = lists_key1search(process_memory, Info), - MibDbSize = lists_key1search([db_memory,mib], Info), - NodeDbSize = lists_key1search([db_memory,node], Info), - TreeDbSize = lists_key1search([db_memory,tree], Info), - ?INF("Memory usage: " - "~n Tree size: ~p" - "~n Process memory size: ~p" - "~n Mib db size: ~p" - "~n Node db size: ~p" - "~n Tree db size: ~p", - [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]). - -lists_key1search([], Res) -> - Res; -lists_key1search([Key|Keys], List) when atom(Key), list(List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - lists_key1search(Keys, Val); - false -> - undefined - end; -lists_key1search(Key, List) when atom(Key) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - Val; - false -> - undefined - end. - - -regs() -> - lists:sort(registered()). diff --git a/lib/snmp/test/exp/snmp_agent_mt_test.erl b/lib/snmp/test/exp/snmp_agent_mt_test.erl deleted file mode 100644 index bd9162fa6542..000000000000 --- a/lib/snmp/test/exp/snmp_agent_mt_test.erl +++ /dev/null @@ -1,5636 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_mt_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - --compile(export_all). - --define(application, snmp). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). --include("snmp_test_lib.hrl"). --define(SNMP_USE_V3, true). --include_lib("snmp/include/snmp_types.hrl"). -%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). - - --define(klas1, [1,3,6,1,2,1,7]). --define(klas2, [1,3,6,1,2,1,9]). --define(klas3, [1,3,6,1,2,1,8,1]). --define(klas4, [1,3,6,1,2,1,8,4]). --define(sa, [1,3,6,1,4,1,193,2]). --define(system, [1,3,6,1,2,1,1]). --define(snmp, [1,3,6,1,2,1,11]). --define(snmpTraps, [1,3,6,1,6,3,1,1,5]). --define(ericsson, [1,3,6,1,4,1,193]). --define(testTrap, [1,3,6,1,2,1,15,0]). --define(xDescr, [1,3,6,1,2,1,17,1]). --define(xDescr2, [1,3,6,1,2,1,17,2]). - --define(active, 1). --define(notInService, 2). --define(notReady, 3). --define(createAndGo, 4). --define(createAndWait, 5). --define(destroy, 6). - --define(TRAP_UDP, 5000). - --define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - --define(str(X), snmp_pdus:bits_to_str(X)). - --define(break(), begin io:format(user, "break at line ~w: pid: ~p\n", - [?LINE, self()]), - receive cont -> ok end - end). - - --import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]). --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all() -> -[cases()]. - -groups() -> - [{mib_storage, [], - [{group, mib_storage_ets}, {group, mib_storage_dets}, - {group, mib_storage_mnesia}, - {group, mib_storage_size_check_ets}, - {group, mib_storage_size_check_dets}, - {group, mib_storage_size_check_mnesia}, - {group, mib_storage_varm_dets}, - {group, mib_storage_varm_mnesia}]}, - {mib_storage_ets, [], mib_storage_ets_cases()}, - {mib_storage_dets, [], mib_storage_dets_cases()}, - {mib_storage_mnesia, [], mib_storage_mnesia_cases()}, - {mib_storage_size_check_ets, [], - mse_size_check_cases()}, - {mib_storage_size_check_dets, [], - msd_size_check_cases()}, - {mib_storage_size_check_mnesia, [], - msm_size_check_cases()}, - {mib_storage_varm_dets, [], - varm_mib_storage_dets_cases()}, - {mib_storage_varm_mnesia, [], - varm_mib_storage_mnesia_cases()}, - {test_v1, [], v1_cases()}, {test_v2, [], v2_cases()}, - {test_v1_v2, [], v1_v2_cases()}, - {test_v3, [], v3_cases()}, - {test_multi_threaded, [], mt_cases()}, - {multiple_reqs, [], mul_cases()}, - {multiple_reqs_2, [], mul_cases_2()}, - {v2_inform, [], [v2_inform_i]}, - {v3_security, [], - [v3_crypto_basic, v3_md5_auth, v3_sha_auth, - v3_des_priv]}, - {standard_mibs, [], - [snmp_standard_mib, snmp_community_mib, - snmp_framework_mib, snmp_target_mib, - snmp_notification_mib, snmp_view_based_acm_mib]}, - {standard_mibs_2, [], - [snmpv2_mib_2, snmp_community_mib_2, - snmp_framework_mib_2, snmp_target_mib_2, - snmp_notification_mib_2, snmp_view_based_acm_mib_2]}, - {standard_mibs_3, [], - [snmpv2_mib_3, snmp_framework_mib_3, snmp_mpd_mib_3, - snmp_target_mib_3, snmp_notification_mib_3, - snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3]}, - {reported_bugs, [], - [otp_1128, otp_1129, otp_1131, otp_1162, otp_1222, - otp_1298, otp_1331, otp_1338, otp_1342, otp_2776, - otp_2979, otp_3187, otp_3725]}, - {reported_bugs_2, [], - [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2, - otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2, - otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2]}, - {reported_bugs_3, [], - [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3, - otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3, - otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3, - otp_3542]}, - {tickets, [], [{group, otp_4394}]}, - {otp_4394, [], [otp_4394_test]}]. - -init_per_group(otp_4394, Config) -> - init_otp_4394(Config); -init_per_group(v2_inform, Config) -> - init_v2_inform(Config); -init_per_group(multiple_reqs_2, Config) -> - init_mul(Config); -init_per_group(multiple_reqs, Config) -> - init_mul(Config); -init_per_group(test_multi_threaded, Config) -> - init_mt(Config); -init_per_group(test_v3, Config) -> - init_v3(Config); -init_per_group(test_v1_v2, Config) -> - init_v1_v2(Config); -init_per_group(test_v2, Config) -> - init_v2(Config); -init_per_group(test_v1, Config) -> - init_v1(Config); -init_per_group(mib_storage_varm_mnesia, Config) -> - init_varm_mib_storage_mnesia(Config); -init_per_group(mib_storage_varm_dets, Config) -> - init_varm_mib_storage_dets(Config); -init_per_group(mib_storage_size_check_mnesia, Config) -> - init_size_check_msm(Config); -init_per_group(mib_storage_size_check_dets, Config) -> - init_size_check_msd(Config); -init_per_group(mib_storage_size_check_ets, Config) -> - init_size_check_mse(Config); -init_per_group(mib_storage_mnesia, Config) -> - init_mib_storage_mnesia(Config); -init_per_group(mib_storage_dets, Config) -> - init_mib_storage_dets(Config); -init_per_group(mib_storage_ets, Config) -> - init_mib_storage_ets(Config); -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(otp_4394, Config) -> - finish_otp_4394(Config); -end_per_group(v2_inform, Config) -> - finish_v2_inform(Config); -end_per_group(multiple_reqs_2, Config) -> - finish_mul(Config); -end_per_group(multiple_reqs, Config) -> - finish_mul(Config); -end_per_group(test_multi_threaded, Config) -> - finish_mt(Config); -end_per_group(test_v3, Config) -> - finish_v3(Config); -end_per_group(test_v1_v2, Config) -> - finish_v1_v2(Config); -end_per_group(test_v2, Config) -> - finish_v2(Config); -end_per_group(test_v1, Config) -> - finish_v1(Config); -end_per_group(mib_storage_varm_mnesia, Config) -> - finish_varm_mib_storage_mnesia(Config); -end_per_group(mib_storage_varm_dets, Config) -> - finish_varm_mib_storage_dets(Config); -end_per_group(mib_storage_size_check_mnesia, Config) -> - finish_size_check_msm(Config); -end_per_group(mib_storage_size_check_dets, Config) -> - finish_size_check_msd(Config); -end_per_group(mib_storage_size_check_ets, Config) -> - finish_size_check_mse(Config); -end_per_group(mib_storage_mnesia, Config) -> - finish_mib_storage_mnesia(Config); -end_per_group(mib_storage_dets, Config) -> - finish_mib_storage_dets(Config); -end_per_group(mib_storage_ets, Config) -> - finish_mib_storage_ets(Config); -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [ - app_info, - {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets} - ]. - - -%%%----------------------------------------------------------------- -%%% The test case structure is as follows: -%%% -%%% init_all - starts mnesia, -%%% -%%% init_v1 - starts agent -%%% simple -%%% big - e.g. starts/stops subagent, load/unloads mibs -%%% init_mul -%%% mul_get -%%% mul_set -%%% -%%% finish_mul -%%% -%%% finish_v1 -%%% -%%% init_v2 - starts agent -%%% finish_v2 -%%% -%%% init_bilingual - starts agent -%%% finish_bilingual -%%% -%%% finish_all -%%% -%%% There is still one problem with these testsuites. If one test -%%% fails, it may not be possible to run some other cases, as it -%%% may have e.g. created some row or loaded some table, that it -%%% didn't undo (since it failed). -%%%----------------------------------------------------------------- - -init_all(Config0) when list(Config0) -> - ?LOG("init_all -> entry with" - "~n Config0: ~p",[Config0]), - - %% -- - %% Fix config: - %% - - DataDir0 = ?config(data_dir, Config0), - DataDir1 = filename:split(filename:absname(DataDir0)), - [_|DataDir2] = lists:reverse(DataDir1), - DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), - Config1 = lists:keydelete(data_dir, 1, Config0), - Config = [{data_dir, DataDir3 ++ "/"}|Config1], - - %% -- - %% Start nodes - %% - - ?line {ok, SaNode} = start_node(snmp_sa), - ?line {ok, MgrNode} = start_node(snmp_mgr), - - - %% -- - %% Create necessary files - %% - - Dir = ?config(priv_dir, Config), - ?DBG("init_all -> Dir ~p", [Dir]), - - DataDir = ?config(data_dir, Config), - ?DBG("init_all -> DataDir ~p", [DataDir]), - - file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")), - ?DBG("init_all -> MgrDir ~p", [MgrDir]), - - file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")), - ?DBG("init_all -> AgentDir ~p", [AgentDir]), - - file:make_dir(SaDir = filename:join(Dir, "sa_dir/")), - ?DBG("init_all -> SaDir ~p", [SaDir]), - - - %% -- - %% Start and initiate mnesia - %% - - ?DBG("init_all -> load application mnesia", []), - ?line ok = application:load(mnesia), - - ?DBG("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), - - ?DBG("init_all -> application mnesia: set_env dir",[]), - ?line application_controller:set_env(mnesia, dir, - filename:join(Dir, "Mnesia1")), - - ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(Dir, "Mnesia2")]), - - ?DBG("init_all -> create mnesia schema",[]), - ?line ok = mnesia:create_schema([SaNode, node()]), - - ?DBG("init_all -> start application mnesia",[]), - ?line ok = application:start(mnesia), - - ?DBG("init_all -> start application mnesia on ~p",[SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), - Ip = ?LOCALHOST(), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, - {agent_dir, AgentDir ++ "/"}, - {mgr_dir, MgrDir ++ "/"}, - {sa_dir, SaDir ++ "/"}, - {mib_dir, DataDir}, - {ip, Ip} | - Config]. - -finish_all(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - stop_node(SaNode), - stop_node(MgrNode), - application:stop(mnesia). - -start_v1_agent(Config) when list(Config) -> - start_agent(Config, [v1]). - -start_v1_agent(Config,Opts) when list(Config), list(Opts) -> - start_agent(Config, [v1], Opts). - -start_v2_agent(Config) when list(Config) -> - start_agent(Config, [v2]). - -start_v3_agent(Config) when list(Config) -> - start_agent(Config, [v3]). - -start_bilingual_agent(Config) when list(Config) -> - start_agent(Config, [v1,v2]). - -start_multi_threaded_agent(Config) when list(Config) -> - start_agent(Config, [v2], [{snmp_multi_threaded, true}]). - -stop_agent(Config) when list(Config) -> - ?LOG("stop_agent -> entry with" - "~n Config: ~p",[Config]), - - {Sup, Par} = ?config(snmp_sup, Config), - ?DBG("stop_agent -> attempt to stop (sup) ~p" - "~n Sup: ~p" - "~n Par: ~p", - [Sup, - (catch process_info(Sup)), - (catch process_info(Par))]), - stop_sup(Sup, Par), - - {Sup2, Par2} = ?config(snmp_sub, Config), - ?DBG("stop_agent -> attempt to stop (sub) ~p" - "~n Sup2: ~p" - "~n Par2: ~p", - [Sup2, - (catch process_info(Sup2)), - (catch process_info(Par2))]), - stop_sup(Sup2, Par2), - - ?DBG("stop_agent -> done - now cleanup config", []), - C1 = lists:keydelete(snmp_sup, 1, Config), - lists:keydelete(snmp_sub, 1, C1). - - -stop_sup(Pid, _) when node(Pid) == node() -> - case (catch process_info(Pid)) of - PI when list(PI) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - exit(Pid, kill), - await_stopped(Pid, Ref); - {'EXIT', _Reason} -> - ?LOG("stop_sup -> ~p not running", [Pid]), - ok - end; -stop_sup(Pid, _) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - ?LOG("stop_sup -> Ref: ~p", [Ref]), - %% Pid ! {'EXIT', Parent, shutdown}, % usch - exit(Pid, kill), - await_stopped(Pid, Ref). - -await_stopped(Pid, Ref) -> - receive - {'DOWN', Ref, process, Pid, _Reason} -> - ?DBG("received down message for ~p", [Pid]), - ok - after 10000 -> - ?INF("await_stopped -> timeout for ~p",[Pid]), - erlang:demonitor(Ref), - ?FAIL({failed_stop,Pid}) - end. - - -start_agent(Config, Vsn) -> - start_agent(Config, Vsn, []). -start_agent(Config, Vsn, Opts) -> - ?LOG("start_agent -> entry (~p) with" - "~n Config: ~p" - "~n Vsn: ~p" - "~n Opts: ~p",[node(), Config, Vsn, Opts]), - - ?line AgentDir = ?config(agent_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - - snmp_app_env_init(vsn_init(Vsn) ++ - [{audit_trail_log, read_write_log}, - {audit_trail_log_dir, AgentDir}, - {audit_trail_log_size, {10240, 10}}, - {force_config_reload, false}, - {snmp_agent_type, master}, - {snmp_config_dir, AgentDir}, - {snmp_db_dir, AgentDir}, - {snmp_local_db_auto_repair, true}, - {snmp_master_agent_verbosity, trace}, - {snmp_supervisor_verbosity, trace}, - {snmp_mibserver_verbosity, trace}, - {snmp_symbolic_store_verbosity, trace}, - {snmp_note_store_verbosity, trace}, - {snmp_net_if_verbosity, trace}], - Opts), - - - process_flag(trap_exit,true), - - {ok, AppSup} = snmp_app_sup:start_link(), - unlink(AppSup), - ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]), - - ?DBG("start_agent -> start master agent (old style)",[]), - Sup = case (catch snmpa_app:start(normal)) of - {ok, S} -> - ?DBG("start_agent -> started, Sup: ~p",[S]), - S; - - Else -> - ?DBG("start_agent -> unknown result: ~n~p",[Else]), - %% Get info about the apps we depend on - MnesiaInfo = mnesia_running(), - ?FAIL({start_failed,Else,MnesiaInfo}) - end, - - ?DBG("start_agent -> unlink from supervisor",[]), - ?line unlink(Sup), - ?line SaDir = ?config(sa_dir, Config), - ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]), - ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]), - ?DBG("start_agent -> done",[]), - ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. - - -vsn_init(Vsn) -> - vsn_init([v1,v2,v3], Vsn, []). - -vsn_init([], _Vsn, Acc) -> - Acc; -vsn_init([V|Vsns], Vsn, Acc) -> - case lists:member(V, Vsn) of - true -> - vsn_init(Vsns, Vsn, [{V, true}|Acc]); - false -> - vsn_init(Vsns, Vsn, [{V, false}|Acc]) - end. - -snmp_app_env_init(Env0, Opts) -> - ?DBG("snmp_app_env_init -> unload snmp",[]), - ?line application:unload(snmp), - ?DBG("snmp_app_env_init -> load snmp",[]), - ?line application:load(snmp), - ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]), - F1 = fun({Key,Val} = New, Acc0) -> - ?DBG("snmp_app_env_init -> " - "updating setting ~p to ~p", [Key, Val]), - case lists:keyreplace(Key, 1, Acc0, New) of - Acc0 -> - [New|Acc0]; - Acc -> - Acc - end - end, - Env = lists:foldr(F1, Env0, Opts), - ?DBG("snmp_app_env_init -> Env: ~p",[Env]), - F2 = fun({Key,Val}) -> - ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]), - application_controller:set_env(snmp, Key, Val) - end, - lists:foreach(F2, Env). - - - - -%% Test if application is running -mnesia_running() -> ?IS_MNESIA_RUNNING(). -crypto_running() -> ?IS_CRYPTO_RUNNING(). - - -start_sub(Dir) -> - ?DBG("start_sub -> entry",[]), - Opts = [{db_dir, Dir}, - {supervisor, [{verbosity, trace}]}], - %% BMK BMK -% {ok, P} = snmp_supervisor:start_sub(Dir), - {ok, P} = snmpa_supervisor:start_sub_sup(Opts), - unlink(P), - {ok, {P, self()}}. - -create_tables(SaNode) -> - ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, - {attributes, [a1,a2]}]). - -delete_tables() -> - mnesia:delete_table(friendsTable2), - mnesia:delete_table(kompissTable2), - mnesia:delete_table(snmp_variables). - -%% Creation is done in runtime! -delete_mib_storage_mnesia_tables() -> - mnesia:delete_table(snmpa_mib_data), - mnesia:delete_table(snmpa_mib_tree), - mnesia:delete_table(snmpa_symbolic_store). - -%%----------------------------------------------------------------- -%% A test case is always one of: -%% - v1 specific case -%% - v2 specific case -%% - v1 and v2 case -%% All v1 specific cases are prefixed with v1_, and all v2 with -%% v2_. E.g. v1_trap/v2_trap. -%% -%% All other cases are shared. However, the testserver uses the name -%% of the case to generate a file for that case. The same case cannot -%% be used in different configurations in the same suite. Therefore -%% all these functions exists in two variants, the base function -%% , and a second version _2. There may be several -%% versions as well, _N. -%%----------------------------------------------------------------- - - - - - - - - - -mib_storage_ets_cases() -> -[mse_simple, mse_v1_processing, mse_big, mse_big2, - mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap, - mse_sa_error, mse_next_across_sa, mse_undo, - mse_standard_mib, mse_community_mib, mse_framework_mib, - mse_target_mib, mse_notification_mib, - mse_view_based_acm_mib, mse_sparse_table, mse_me_of, - mse_mib_of]. - -mib_storage_dets_cases() -> -[msd_simple, msd_v1_processing, msd_big, msd_big2, - msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap, - msd_sa_error, msd_next_across_sa, msd_undo, - msd_standard_mib, msd_community_mib, msd_framework_mib, - msd_target_mib, msd_notification_mib, - msd_view_based_acm_mib, msd_sparse_table, msd_me_of, - msd_mib_of]. - -mib_storage_mnesia_cases() -> -[msm_simple, msm_v1_processing, msm_big, msm_big2, - msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap, - msm_sa_error, msm_next_across_sa, msm_undo, - msm_standard_mib, msm_community_mib, msm_framework_mib, - msm_target_mib, msm_notification_mib, - msm_view_based_acm_mib, msm_sparse_table, msm_me_of, - msm_mib_of]. - -mse_size_check_cases() -> -[mse_size_check]. - -msd_size_check_cases() -> -[msd_size_check]. - -msm_size_check_cases() -> -[msm_size_check]. - -varm_mib_storage_dets_cases() -> -[msd_varm_mib_start]. - -varm_mib_storage_mnesia_cases() -> -[msm_varm_mib_start]. - -init_mib_storage_ets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,ets}, - init_ms(Config, [MibStorage]). - -init_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - init_ms(Config, [MibStorage]). - -init_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - init_ms(Config, [MibStorage]). - -init_ms(Config, Opts) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts], - [{vsn, v1} | start_v1_agent(Config,Opts1)]. - -init_size_check_mse(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, ets}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msd(Config) when list(Config) -> - AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage, {dets, AgentDir}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msm(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, {mnesia,[]}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_ms(Config, Opts) when list(Config) -> - SaNode = ?GCONF(snmp_sa, Config), - %% We are using v3 here, so crypto must be supported or else... - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - create_tables(SaNode), - AgentDir = ?GCONF(agent_dir, Config), - MgrDir = ?GCONF(mgr_dir, Config), - Ip = ?GCONF(ip, Config), - ?line ok = - config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_agent(Config, [v3], Opts)]. - -init_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_dets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -init_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_mnesia -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -finish_mib_storage_ets(Config) when list(Config) -> - ?LOG("finish_mib_storage_ets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_mib_storage_dets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_dets -> entry", []), - delete_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_size_check_mse(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msd(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msm(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_ms(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%% These are just interface functions to fool the test server -mse_simple(X) -> simple(X). -mse_v1_processing(X) -> v1_processing(X). -mse_big(X) -> big(X). -mse_big2(X) -> big2(X). -mse_loop_mib(X) -> loop_mib(X). -mse_api(X) -> api(X). -mse_sa_register(X) -> sa_register(X). -mse_v1_trap(X) -> v1_trap(X). -mse_sa_error(X) -> sa_error(X). -mse_next_across_sa(X) -> next_across_sa(X). -mse_undo(X) -> undo(X). -mse_standard_mib(X) -> snmp_standard_mib(X). -mse_community_mib(X) -> snmp_community_mib(X). -mse_framework_mib(X) -> snmp_framework_mib(X). -mse_target_mib(X) -> snmp_target_mib(X). -mse_notification_mib(X) -> snmp_notification_mib(X). -mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -mse_sparse_table(X) -> sparse_table(X). -mse_me_of(X) -> ms_me_of(X). -mse_mib_of(X) -> ms_mib_of(X). - -msd_simple(X) -> simple(X). -msd_v1_processing(X) -> v1_processing(X). -msd_big(X) -> big(X). -msd_big2(X) -> big2(X). -msd_loop_mib(X) -> loop_mib(X). -msd_api(X) -> api(X). -msd_sa_register(X) -> sa_register(X). -msd_v1_trap(X) -> v1_trap(X). -msd_sa_error(X) -> sa_error(X). -msd_next_across_sa(X) -> next_across_sa(X). -msd_undo(X) -> undo(X). -msd_standard_mib(X) -> snmp_standard_mib(X). -msd_community_mib(X) -> snmp_community_mib(X). -msd_framework_mib(X) -> snmp_framework_mib(X). -msd_target_mib(X) -> snmp_target_mib(X). -msd_notification_mib(X) -> snmp_notification_mib(X). -msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msd_sparse_table(X) -> sparse_table(X). -msd_me_of(X) -> ms_me_of(X). -msd_mib_of(X) -> ms_mib_of(X). - -msm_simple(X) -> simple(X). -msm_v1_processing(X) -> v1_processing(X). -msm_big(X) -> big(X). -msm_big2(X) -> big2(X). -msm_loop_mib(X) -> loop_mib(X). -msm_api(X) -> api(X). -msm_sa_register(X) -> sa_register(X). -msm_v1_trap(X) -> v1_trap(X). -msm_sa_error(X) -> sa_error(X). -msm_next_across_sa(X) -> next_across_sa(X). -msm_undo(X) -> undo(X). -msm_standard_mib(X) -> snmp_standard_mib(X). -msm_community_mib(X) -> snmp_community_mib(X). -msm_framework_mib(X) -> snmp_framework_mib(X). -msm_target_mib(X) -> snmp_target_mib(X). -msm_notification_mib(X) -> snmp_notification_mib(X). -msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msm_sparse_table(X) -> sparse_table(X). -msm_me_of(X) -> ms_me_of(X). -msm_mib_of(X) -> ms_mib_of(X). - - -mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X). -msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X). -msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X). - -msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X). -msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X). - -ms_size_check(suite) -> []; -ms_size_check(Config) when list(Config) -> - p("ms_size_check..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?LOG("mib server size check...", []), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - - -varm_mib_start(suite) -> []; -varm_mib_start(Config) when list(Config) -> - p("varm_mib_start..."), - ?LOG("varm_mib_start -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - %% Start the agent - Opts = ?GCONF(agent_opts, Config), - Config1 = start_v1_agent(Config, Opts), - - %% Sleep some in order for the agent to start properly - ?DBG("varm_mib_start -> sleep some (before loading mobs)", []), - ?SLEEP(5000), - - %% Load all the mibs - HardwiredMibs = loaded_mibs(), - ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - - %% Unload the hardwired mibs - ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), - ?SLEEP(1000), - ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired - - ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), - ?SLEEP(1000), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - Config2 = stop_agent(Config1), - - %% Sleep some in order for the agent to stop properly - ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []), - ?SLEEP(5000), - - %% Start the agent (again) - ?DBG("varm_mib_start -> start the agent", []), - Config3 = start_v1_agent(Config2, Opts), - - ?DBG("varm_mib_start -> sleep some (before starting tests)", []), - ?SLEEP(5000), - - %% Perform the test(s) - ?DBG("varm_mib_start -> perform the tests", []), - try_test(snmp_community_mib), - try_test(snmp_framework_mib), - try_test(snmp_target_mib), - try_test(snmp_notification_mib), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - stop_agent(Config3), - ok. - - --define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]). --define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). --define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -ms_me_of(suite) -> []; -ms_me_of(Config) when list(Config) -> - p("ms_me_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -me_of(Oid) -> - case snmpa:me_of(Oid) of - {ok, #me{oid = Oid}} -> - ok; - {ok, #me{oid = OtherOid}} -> - case lists:reverse(Oid) of - [0|Rest] -> - case lists:reverse(Rest) of - OtherOid -> - ok; - AnotherOid -> - {error, {invalid_oid, Oid, AnotherOid}} - end; - _ -> - {error, {invalid_oid, Oid, OtherOid}} - end; - {error, Reason} -> - {error, Reason}; - Else -> - {error, Else} - end. - - -ms_mib_of(suite) -> []; -ms_mib_of(Config) when list(Config) -> - p("ms_mib_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, - 'SNMP-USER-BASED-SM-MIB'), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -mib_of(Oid, ExpectedMibName) -> - ?DBG("mib_of -> entry with" - "~n Oid: ~p" - "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]), - %% case snmpa:mib_of(Oid) of - MibOf = snmpa:mib_of(Oid), - ?DBG("mib_of -> MibOf: ~n~p", [MibOf]), - case MibOf of - {ok, ExpectedMibName} -> - ok; - {ok, OtherMibName} -> - {error, {invalid_mib, ExpectedMibName, OtherMibName}}; - {error, Reason} -> - {error, Reason}; - Else -> - ?DBG("mib_of -> Else: ~n~p", [Else]), - {error, Else} - end. - - -app_info(suite) -> []; -app_info(Config) when list(Config) -> - SnmpDir = app_dir(snmp), - SslDir = app_dir(ssl), - CryptoDir = app_dir(crypto), - Attr = snmp:module_info(attributes), - AppVsn = - case lists:keysearch(app_vsn, 1, Attr) of - {value, {app_vsn, V}} -> - V; - false -> - "undefined" - end, - io:format("Root dir: ~s~n" - "SNMP: Application dir: ~s~n" - " Application ver: ~s~n" - "SSL: Application dir: ~s~n" - "CRYPTO: Application dir: ~s~n", - [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]), - ok. - -app_dir(App) -> - case code:lib_dir(App) of - D when list(D) -> - filename:basename(D); - {error, _Reason} -> - "undefined" - end. - - - -%v1_cases() -> [loop_mib]; -v1_cases() -> -[simple, db_notify_client, v1_processing, big, big2, - loop_mib, api, subagent, mnesia, {group, multiple_reqs}, - sa_register, v1_trap, sa_error, next_across_sa, undo, - {group, reported_bugs}, {group, standard_mibs}, - sparse_table, cnt_64, opaque, change_target_addr_config]. - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v2_cases() -> [loop_mib_2]; -v2_cases() -> -[simple_2, v2_processing, big_2, big2_2, loop_mib_2, - api_2, subagent_2, mnesia_2, {group, multiple_reqs_2}, - sa_register_2, v2_trap, {group, v2_inform}, sa_error_2, - next_across_sa_2, undo_2, {group, reported_bugs_2}, - {group, standard_mibs_2}, v2_types, implied, - sparse_table_2, cnt_64_2, opaque_2, v2_caps]. - -init_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_v2_agent(Config)]. - -finish_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -v1_v2_cases() -> -[simple_bi]. - -init_v1_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, bilingual} | start_bilingual_agent(Config)]. - -finish_v1_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v3_cases() -> [loop_mib_3]; -v3_cases() -> -[simple_3, v3_processing, big_3, big2_3, api_3, - subagent_3, mnesia_3, loop_mib_3, multiple_reqs_3, - sa_register_3, v3_trap, v3_inform, sa_error_3, - next_across_sa_3, undo_3, {group, reported_bugs_3}, - {group, standard_mibs_3}, {group, v3_security}, - v2_types_3, implied_3, sparse_table_3, cnt_64_3, - opaque_3, v2_caps_3]. - -init_v3(Config) when list(Config) -> - %% Make sure crypto works, otherwise start_agent will fail - %% and we will be stuck with a bunch of mnesia tables for - %% the rest of this suite... - ?DBG("start_agent -> start crypto app",[]), - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. - -finish_v3(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -mt_cases() -> -[multi_threaded, mt_trap]. - -init_mt(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. - -finish_mt(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -%% This one *must* be run first in each case. -init_case(Config) when list(Config) -> - ?DBG("init_case -> entry with" - "~n Config: ~p", [Config]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - MasterNode = node(), - - SaHost = ?HOSTNAME(SaNode), - MgrHost = ?HOSTNAME(MgrNode), - MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), - - - put(mgr_node, MgrNode), - put(sa_node, SaNode), - put(master_node, MasterNode), - put(sa_host, SaHost), - put(mgr_host, MgrHost), - put(master_host, MasterHost), - put(mip, tuple_to_list(MIP)), - put(masterip , tuple_to_list(MasterIP)), - put(sip, tuple_to_list(SIP)), - - MibDir = ?config(mib_dir, Config), - put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - put(std_mib_dir, StdM), - - MgrDir = ?config(mgr_dir, Config), - put(mgr_dir, MgrDir), - - put(vsn, ?config(vsn, Config)), - ?DBG("init_case -> exit with" - "~n MasterNode: ~p" - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]), - {SaNode, MgrNode, MibDir}. - -load_master(Mib) -> - ?DBG("load_master -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). - -load_master_std(Mib) -> - ?DBG("load_master_std -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). - -unload_master(Mib) -> - ?DBG("unload_master -> entry with" - "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). - -loaded_mibs() -> - ?DBG("loaded_mibs -> entry",[]), - Info = snmpa:info(snmp_master_agent), - {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info), - [atom_to_list(Mib) || {Mib,_,_} <- Mibs]. - -unload_mibs(Mibs) -> - ?DBG("unload_mibs -> entry with" - "~n Mibs: ~p", [Mibs]), - ok = snmpa:unload_mibs(snmp_master_agent, Mibs). - -start_subagent(SaNode, RegTree, Mib) -> - ?DBG("start_subagent -> entry with" - "~n SaNode: ~p" - "~n RegTree: ~p" - "~n Mib: ~p", [SaNode, RegTree, Mib]), - MA = whereis(snmp_master_agent), - ?DBG("start_subagent -> MA: ~p", [MA]), - MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), - %% BMK BMK -% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of - case rpc:call(SaNode, snmpa_supervisor, - start_sub_agent, [MA, RegTree, [Mib1]]) of - {ok, SA} -> - ?DBG("start_subagent -> SA: ~p", [SA]), - {ok, SA}; - Error -> - ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]}) - end. - -stop_subagent(SA) -> - ?DBG("stop_subagent -> entry with" - "~n SA: ~p", [SA]), - %% BNK BMK - %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]). - rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]). - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - - -simple(suite) -> []; -simple(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(simple_standard_test). - -simple_2(X) -> simple(X). - -simple_bi(suite) -> []; -simple_bi(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(vsn, v1), % First, try v1 manager - try_test(simple_standard_test), - - put(vsn, v2), % Then, try v2 manager - try_test(simple_standard_test). - -simple_3(X) -> - simple(X). - -big(suite) -> []; -big(Config) when list(Config) -> - ?DBG("big -> entry", []), - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -big_2(X) -> big(X). - -big_3(X) -> big(X). - - -big2(suite) -> []; -big2(Config) when list(Config) -> - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - -big2_2(X) -> big2(X). - -big2_3(X) -> big2(X). - - -multi_threaded(suite) -> []; -multi_threaded(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(multi_threaded_test), - ?line unload_master("Test1"). - -mt_trap(suite) -> []; -mt_trap(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). - -v2_types(suite) -> []; -v2_types(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(types_v2_test), - ?line unload_master("Test1"). - -v2_types_3(X) -> v2_types(X). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(implied_test,[MA]), - ?line unload_master("Test1"). - -implied_3(X) -> implied(X). - - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(sparse_table_test), - ?line unload_master("Test1"). - -sparse_table_2(X) -> sparse_table(X). - -sparse_table_3(X) -> sparse_table(X). - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -cnt_64_2(X) -> cnt_64(X). - -cnt_64_3(X) -> cnt_64(X). - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(opaque_test), - ?line unload_master("Test1"). - -opaque_2(X) -> opaque(X). - -opaque_3(X) -> opaque(X). - - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - try_test(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -api(suite) -> []; -api(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -api_2(X) -> api(X). - -api_3(X) -> api(X). - - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - try_test(load_test_sa), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - - p("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - try_test(load_test), - - p("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - try_test(unreg_test), - p("Testing register subagent..."), - rpc:call(SaNode, snmp, register_subagent, - [MA, ?klas1, SA]), - try_test(load_test_sa), - - ?line stop_subagent(SA), - try_test(unreg_test). - -subagent_2(X) -> subagent(X). - -subagent_3(X) -> subagent(X). - - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - try_test(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - -mnesia_2(X) -> mnesia(X). - -mnesia_3(X) -> mnesia(X). - - - -mul_cases() -> -[mul_get, mul_get_err, mul_next, mul_next_err, - mul_set_err]. - - -multiple_reqs_3(_X) -> - {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}. - - -mul_cases_2() -> -[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, - mul_set_err_2]. - - -mul_cases_3() -> - [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3]. - - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - try_test(do_mul_get). - -mul_get_2(X) -> mul_get(X). - -mul_get_3(X) -> mul_get(X). - - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - try_test(do_mul_get_err). - -mul_get_err_2(X) -> mul_get_err(X). - -mul_get_err_3(X) -> mul_get_err(X). - - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next). - -mul_next_2(X) -> mul_next(X). - -mul_next_3(X) -> mul_next(X). - - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next_err). - -mul_next_err_2(X) -> mul_next_err(X). - -mul_next_err_3(X) -> mul_next_err(X). - - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set..."), - try_test(do_mul_set). - -mul_set_2(X) -> mul_set(X). - -mul_set_3(X) -> mul_set(X). - - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set with error..."), - try_test(do_mul_set_err). - -mul_set_err_2(X) -> mul_set_err(X). - -mul_set_err_3(X) -> mul_set_err(X). - - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?DBG("sa_register -> entry", []), - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - p("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - try_test(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -sa_register_2(X) -> sa_register(X). - -sa_register_3(X) -> sa_register(X). - - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_trap1, [MA]), - try_test(ma_trap2, [MA]), - try_test(ma_v2_2_v1_trap, [MA]), - try_test(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - try_test(sa_trap1, [SA]), - try_test(sa_trap2, [SA]), - try_test(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v2_trap(suite) -> []; -v2_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - - try_test(ma_v2_trap1, [MA]), - try_test(ma_v2_trap2, [MA]), - try_test(ma_v1_2_v2_trap, [MA]), - try_test(ma_v1_2_v2_trap2, [MA]), - - try_test(sa_mib), - p("Testing trap sending from subagent..."), - try_test(sa_v1_2_v2_trap1, [SA]), - try_test(sa_v1_2_v2_trap2, [SA]), - try_test(sa_v1_2_v2_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v3_trap(X) -> - v2_trap(X). - - -v3_inform(_X) -> - %% v2_inform(X). - {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}. - -init_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -init_v3_inform(X) -> - init_v2_inform(X). - -finish_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -finish_v3_inform(X) -> - finish_v2_inform(X). - - - -v2_inform_i(suite) -> []; -v2_inform_i(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing inform sending from master agent... NOTE! This test\ntakes a " - "few minutes (5) to complete."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_v2_inform1, [MA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"). - -v3_inform_i(X) -> v2_inform_i(X). - - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - try_test(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - try_test(sa_errs_gen_err), - - p("Testing too big..."), - try_test(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -sa_error_2(X) -> sa_error(X). - -sa_error_3(X) -> sa_error(X). - - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - try_test(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - try_test(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - try_test(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -next_across_sa_2(X) -> next_across_sa(X). - -next_across_sa_3(X) -> next_across_sa(X). - - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - try_test(undo_test), - try_test(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - try_test(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - try_test(undo_test), - try_test(api_test3), - - p("Testing undo phase across master/subagents..."), - try_test(undo_test), - try_test(api_test3), - stop_subagent(SA). - -undo_2(X) -> undo(X). - -undo_3(X) -> undo(X). - -%% Req. Test2 -v1_processing(suite) -> []; -v1_processing(Config) when list(Config) -> - ?DBG("v1_processing -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v1_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v2_processing(suite) -> []; -v2_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v3_processing(suite) -> []; -v3_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), % same as v2! - ?line unload_master("Test2"). - - -%% We'll try get/set/trap and inform for all the auth & priv protocols. -%% For informs, the mgr is auth-engine. The agent has to sync. This is -%% accomplished by the first inform sent. That one will generate a -%% report, which makes it in sync. The notification-generating -%% application times out, and send again. This time it'll work. - -v3_crypto_basic(suite) -> []; -v3_crypto_basic(_Config) -> - EID = [0,0,0,0,0,0,0,0,0,0,0,2], - %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, - 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = - KMd5_1, - %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, - 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = - KSHA_1, - %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, - 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = - snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, - 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, - 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - KSHA_1t = lists:sublist(KSHA_1, 16), - KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, - 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - - %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), - ok. - - - -v3_md5_auth(suite) -> []; -v3_md5_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing MD5 authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authMD5"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_sha_auth(suite) -> []; -v3_sha_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing SHA authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authSHA"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_des_priv(suite) -> []; -v3_des_priv(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing DES encryption...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -%% Make sure mgr is in sync with agent -v3_sync(Funcs) -> - ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]), - g([[sysDescr, 0]]), - expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]), - g([[sysDescr, 0]]), - expect(433, [{[sysDescr,0], any}]), - lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs). - -v3_inform_sync(MA) -> - ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, - "standard inform", []), - %% Make sure agent is in sync with mgr... - ?DBG("v3_sync -> wait some time: ",[]), - sleep(20000), % more than 1500*10 in target_addr.conf - ?DBG("v3_sync -> await response",[]), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]). - - -v2_caps(suite) -> []; -v2_caps(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(v2_caps_i, [node()]). - -v2_caps_3(X) -> v2_caps(X). - - -v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]), - g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]}, - {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmp, del_agent_caps, [Idx]), - g([[sysORID, Idx]]), - ?line expect(2, [{[sysORID, Idx], noSuchInstance}]). - - -%% Req. Test2 -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - - -v1_get_p() -> - %% 4.1.2:1 - g([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - g([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - g([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - g([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - g([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - g([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - g([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - g([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - g([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - g([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - - -v1_get_next_p() -> - %% 4.1.3:1 - gn([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - gn([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - gn([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), -% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - gn([[tGenErr1]]), -% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - gn([[tGenErr2]]), -% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - gn([[sysDescr], [tGenErr3]]), -% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, -% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - s([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - s([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - s([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - s([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: -% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - s([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - -%% Req. Test2 -v2_proc() -> - %% According to RFC1905. - %% Template:
    : - ?DBG("v2_proc -> entry",[]), - v2_get_p(), - v2_get_next_p(), - v2_get_bulk_p(), - v2_set_p(). - -v2_get_p() -> - %% 4.2.1:2 - ?DBG("v2_get_p -> entry",[]), - g([[test2]]), - ?line expect(10, [{[test2], noSuchObject}]), - g([[tDescr]]), - ?line expect(11, [{[tDescr], noSuchObject}]), - g([[tDescr4,0]]), - ?line expect(12, [{[tDescr4,0], noSuchObject}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}, - {[tDescr,0], noSuchObject}]), - g([[tTable]]), - ?line expect(14, [{[tTable], noSuchObject}]), - g([[tEntry]]), - ?line expect(15, [{[tEntry], noSuchObject}]), - - %% 4.2.1:3 - g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line expect(20, [{[tDescr2,0], noSuchInstance}]), - g([[tDescr3,0]]), - ?line expect(21, [{[tDescr3,0], noSuchInstance}]), - g([[sysDescr,3]]), - ?line expect(22, [{[sysDescr, 3], noSuchInstance}]), - g([[tIndex,1]]), - ?line expect(23, [{[tIndex, 1], noSuchInstance}]), - - %% 4.2.1 - any other error: genErr - g([[tGenErr1, 0]]), - ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]), - - %% 4.2.1 - tooBig - g([[tTooBig, 0]]), - ?line expect(40, tooBig, 0, []). - - -v2_get_next_p() -> - %% 4.2.2:2 - ?DBG("v2_get_next_p -> entry",[]), - gn([[1,3,7,1]]), - ?line expect(10, [{[1,3,7,1], endOfMibView}]), - gn([[sysDescr], [1,3,7,1]]), - ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gn([[tCnt2, 1]]), - ?line expect(12, [{[tCnt2,2], 100}]), - gn([[tCnt2, 2]]), - ?line expect(12, [{[tCnt2,2], endOfMibView}]), - - %% 4.2.2 - any other error: genErr - gn([[tGenErr1]]), - ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]), - gn([[tGenErr2]]), - ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]), - gn([[sysDescr], [tGenErr3]]), - ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'}, - {[tGenErr3], 'NULL'}]), - - %% 4.2.2 - tooBig - gn([[tTooBig]]), - ?line expect(20, tooBig, 0, []). - -v2_get_bulk_p() -> - %% 4.2.3 - ?DBG("v2_get_bulk_p -> entry",[]), - gb(1, 1, []), - ?line expect(10, []), - gb(-1, 1, []), - ?line expect(11, []), - gb(-1, -1, []), - ?line expect(12, []), - gb(-1, -1, []), - ?line expect(13, []), - gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[sysDescr, 0], "Erlang SNMP agent"}]), - - gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line expect(19, []), - - gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'}, - {[sysObjectID], 'NULL'}, - {[tGenErr1], 'NULL'}, - {[sysDescr], 'NULL'}]), - gb(0, 2, [[tCnt2, 1]]), - ?line expect(21, [{[tCnt2,2], 100}, - {[tCnt2,2], endOfMibView}]). - - -v2_set_p() -> - %% 4.2.5:1 - ?DBG("v2_set_p -> entry",[]), - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]), - - %% 4.2.5:2 - s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), - - %% 4.2.5:3 - s([{[tDescr2, 0], i, 4}]), - ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.2.5:4 - s([{[tStr, 0], s, ""}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]), - s([{[tStr, 0], s, "12345"}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]), - - %% 4.2.5:5 - N/A - - %% 4.2.5:6 - s([{[tInt1, 0], i, 0}]), - ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]), - s([{[tInt1, 0], i, 5}]), - ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]), - s([{[tInt2, 0], i, 0}]), - ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]), - s([{[tInt2, 0], i, 5}]), - ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]), - s([{[tInt3, 0], i, 5}]), - ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]), - - %% 4.2.5:7 - s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), - - %% 4.2.5:8 - s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line expect(80, inconsistentName, 1, - [{[tDescrX, 1, 2], "inconsistentName"}]), - - %% 4.2.5:9 - s([{[tCnt, 1, 2], i, 5}]), - ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]), - - %% 4.2.5:10 - s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line expect(100, inconsistentValue, 1, - [{[tDescr2,0], "inconsistentValue"}]), - - %% 4.2.5:11 - s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line expect(110, resourceUnavailable, 1, - [{[tDescr2,0],"resourceUnavailable"}]), - - %% 4.2.5:12 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). - - %% commitFailed and undoFailed is tested by the 'undo' case. - - -%% Req. OLD-SNMPEA-MIB -table_test() -> - io:format("Testing simple get, next and set on communityTable...~n"), -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. - Key1c3 = [intCommunityViewIndex,get(mip),is("public")], - Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")], - Key1c4 = [intCommunityAccess,get(mip),is("public")], - EndKey = [intCommunityEntry,[9],get(mip),is("public")], - gn([[intCommunityEntry]]), - ?line expect(7, [{Key1c3, 2}]), - gn([[intCommunityTable]]), - ?line expect(71, [{Key1c3, 2}]), - gn([[community]]), - ?line expect(72, [{Key1c3, 2}]), - gn([[otpSnmpeaMIB]]), - ?line expect(73, [{Key1c3, 2}]), - gn([[ericsson]]), - ?line expect(74, [{Key1c3, 2}]), - gn([Key1c3]), - ?line expect(8, [{Key2c3, 2}]), - gn([Key2c3]), - ?line expect(9, [{Key1c4, 2}]), - gn([EndKey]), - AgentIp = [intAgentIpAddress,0], - ?line expect(10, [{AgentIp, any}]), - g([Key1c3]), - ?line expect(11, [{Key1c3, 2}]), - g([EndKey]), - ?line ?v1_2(expect(12, noSuchName, 1, any), - expect(12, [{EndKey, noSuchObject}])), - - io:format("Testing row creation/deletion on communityTable...~n"), - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - s([{NewKeyc5, ?createAndGo}]), - ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any), - s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), - g([NewKeyc4]), - ?line expect(16, [{NewKeyc4, 2}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(17, [{NewKeyc5, ?destroy}]), - s([{NewKeyc4, 2}]), - ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]), - s([{NewKeyc5, ?createAndWait}]), - ?line expect(19, [{NewKeyc5, ?createAndWait}]), - g([NewKeyc5]), - ?line expect(20, [{NewKeyc5, ?notReady}]), - s([{NewKeyc4, 2}]), - ?line expect(21, [{NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(22, [{NewKeyc5, ?notReady}]), - s([{NewKeyc3, 2}]), - ?line expect(23, [{NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(24, [{NewKeyc5, ?notInService}]), - s([{NewKeyc5, ?active}]), - ?line expect(25, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(26, [{NewKeyc5, ?destroy}]), - s([{NewKeyc3, 3}]), - ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]), - otp_1128(). - -%% Req. system group -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - gn([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - g([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - gn([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - g([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - io:format("Testing noSuchName and badValue...~n"), - s([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - s([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - try_test(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - gn([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - g([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - s([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - s([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - g([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - gn([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - s([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - gn([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - p("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - gn([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - g([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - s([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - g([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - p("Testing next from last object in master to subagent (2)..."), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - p("Adding one row in subagent table (2)"), - _FTab = [friendsEntry2], - s([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - g([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - p("Adding two rows in subagent table with special INDEX (2)"), - s([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - g([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - gn([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - s([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - gn([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - -%% Req. Test1 -multi_threaded_test() -> - p("Testing multi threaded agent..."), - g([[multiStr,0]]), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(1, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "pelle"}]), - ?line expect(2, [{[sysLocation, 0], "pelle"}]), - Pid ! continue, - ?line expect(3, [{[multiStr,0], "ok"}]), - - s([{[multiStr, 0], s, "block"}]), - Pid2 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(4, [{[sysUpTime,0], any}]), - g([[multiStr,0]]), - Pid3 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(5, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "kalle"}]), - Pid3 ! continue, - ?line expect(6, [{[multiStr,0], "ok"}]), - Pid2 ! continue, - ?line expect(7, [{[multiStr,0], "block"}]), - ?line expect(8, [{[sysLocation,0], "kalle"}]). - -%% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - snmpa:send_trap(MA, mtTrap, "standard trap"), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(2, [{[sysUpTime,0], any}]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - Pid ! continue, - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]). - - -get_multi_pid() -> - get_multi_pid(10). -get_multi_pid(0) -> - ?line ?FAIL(no_global_name); -get_multi_pid(N) -> - sleep(1000), - case global:whereis_name(snmp_multi_tester) of - Pid when pid(Pid) -> Pid; - _ -> get_multi_pid(N-1) - end. - -%% Req. Test1 -types_v2_test() -> - p("Testing v2 types..."), - - s([{[bits1,0], 2#10}]), - ?line expect(1, [{[bits1,0], ?str(2#10)}]), - g([[bits1,0]]), - ?line expect(2, [{[bits1,0], ?str(2#101)}]), - - s([{[bits2,0], 2#11000000110}]), - ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]), - g([[bits2,0]]), - ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]), - - g([[bits3,0]]), - ?line expect(50, genErr, 1, any), - - g([[bits4,0]]), - ?line expect(51, genErr, 1, any), - - s([{[bits1,0], s, [2#10]}]), - ?line expect(6, ?v1_2(badValue, wrongValue), 1, any), - - s([{[bits2,0], 2#11001001101010011}]), - ?line expect(7, ?v1_2(badValue, wrongValue), 1, any). - - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - p("Testing IMPLIED..."), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - gn([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - gn([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr2)",[]), - gn([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - gn([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, - oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, - int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - -%% Req. Klas3 -api_test2() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]), - g([[fname4,0]]), - ?line expect(2, [{[fname4,0], 1}]). - -api_test3() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]). - - -unreg_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - -%% Req. Klas1 -load_test_sa() -> - gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -%% Note: This test case takes a while... actually a couple of minutes. -ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform -> entry with MA = ~p => " - "send notification: testTrapv22",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag1, self()}, - "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag1, [_]} -> - ok; - {snmp_targets, tag1, Addrs1} -> - ?line ?FAIL({bad_addrs, Addrs1}) - after - 5000 -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag1, {got_response, _}} -> - ok; - {snmp_notification, tag1, {no_response, _}} -> - ?line ?FAIL(no_response) - after - 20000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - - %% - %% -- The rest is possibly erroneous... - %% - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag2, self()}, - "standard inform", []), - ?line expect(2, {inform, false}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag2, [_]} -> - ok; - {snmp_targets, tag2, Addrs2} -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]), - ?line ?FAIL({bad_addrs, Addrs2}) - after - 5000 -> - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag2, {got_response, _}} -> - ?line ?FAIL(got_response); - {snmp_notification, tag2, {no_response, _}} -> - ok - after - 240000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag2) timeout",[]), - ?line ?FAIL(nothing_at_all) - end. - - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. -% it depends on which order the agent traverses the varbind list. -% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- - - - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - try_test(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = try_test(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - try_test(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = try_test(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - try_test(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - try_test(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - try_test(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - try_test(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - try_test(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - try_test(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - try_test(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]). - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v2 and v3. -%% o Test the counters and control objects in SNMPv2-MIB -%%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; -snmpv2_mib_2(Config) when list(Config) -> - ?LOG("snmpv2_mib_2 -> start",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?DBG("snmpv2_mib_2 -> standard mib init",[]), - try_test(std_mib_init), - - ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]), - InBadVsns = try_test(std_mib_a), - - ?DBG("snmpv2_mib_2 -> make a bad version read",[]), - put(vsn, v1), - try_test(std_mib_read), - - ?DBG("snmpv2_mib_2 -> bad version read",[]), - put(vsn, v2), - Bad = try_test(std_mib_b, [InBadVsns]), - - ?DBG("snmpv2_mib_2 -> read with bad community",[]), - try_test(std_mib_read, [], [{community, "bad community"}]), - - ?DBG("snmpv2_mib_2 -> write with public community",[]), - try_test(std_mib_write, [], [{community, "public"}]), - - ?DBG("snmpv2_mib_2 -> asn err",[]), - try_test(std_mib_asn_err), - - ?DBG("snmpv2_mib_2 -> check counters",[]), - try_test(std_mib_c, [Bad]), - - ?DBG("snmpv2_mib_2 -> get som counters",[]), - try_test(snmpv2_mib_a), - - ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), - try_test(std_mib_finish), - - ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, " - "then disable auth traps",[]), - try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]), - - ?LOG("snmpv2_mib_2 -> done",[]). - -%% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; -snmpv2_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - InBadVsns = try_test(std_mib_a), - put(vsn, v1), - try_test(std_mib_read), - put(vsn, v3), - _Bad = try_test(std_mib_b, [InBadVsns]), - try_test(snmpv2_mib_a), - - try_test(std_mib_finish). - --define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]). - -%% Req. SNMPv2-MIB -snmpv2_mib_test_finish() -> - %% force a authenticationFailure - ?DBG("ma_v2_inform -> write to std mib",[]), - std_mib_write(), - - %% check that we got a trap - ?DBG("ma_v2_inform -> await trap",[]), - ?line expect(2, v2trap, [{[sysUpTime,0], any}, - {[snmpTrapOID,0], ?authenticationFailure}]), - - %% and the the inform - ?DBG("ma_v2_inform -> await inform",[]), - ?line expect(2, {inform,true}, [{[sysUpTime,0], any}, - {[snmpTrapOID,0],?authenticationFailure}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - -%% Req. SNMPv2-MIB -snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), - s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), - s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, - [{[sysLocation, 0], "val3"}, - {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]). - - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - try_test(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - try_test(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -snmp_framework_mib_2(X) -> snmp_framework_mib(X). - -snmp_framework_mib_3(suite) -> []; -snmp_framework_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(snmp_framework_mib). - - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - -%%----------------------------------------------------------------- -%% o Test the counters -%%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; -snmp_mpd_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - UnknownPDUHs = try_test(snmp_mpd_mib_a), - try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]), - try_test(snmp_mpd_mib_c, [UnknownPDUHs]). - - -%% Req. SNMP-MPD-MIB -snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0]]), - Pdu = #pdu{type = 'get-request', - request_id = 23, - error_status = noError, - error_index = 0, - varbinds = []}, - SPdu = #scopedPdu{contextEngineID = "agentEngine", - contextName = "", - data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), - V3Hdr1 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [7], - msgSecurityModel = 23, % bad sec model - msgSecurityParameters = []}, - V3Hdr2 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [6], % bad flag combination - msgSecurityModel = 3, - msgSecurityParameters = []}, - Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1, - data = SPDUBytes}, - Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, - data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), - snmp_test_mgr:send_bytes(MsgBytes1), - snmp_test_mgr:send_bytes(MsgBytes2), - - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0], - [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, - UnknownPDUHs. - --define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). -snmp_mpd_mib_b() -> - g([[sysUpTime,0]]), - ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]). - - -snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1. - - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - try_test(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib_2(X) -> snmp_target_mib(X). - -snmp_target_mib_3(X) -> snmp_target_mib(X). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - try_test(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib_2(X) -> snmp_notification_mib(X). - -snmp_notification_mib_3(X) -> snmp_notification_mib(X). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line try_test(do_set, [ARow2]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [ARow2Status]), - - - %% Add valid row - ?line try_test(do_set, [ARow1]), - - ?line try_test(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), - - %% We should still have access... - ?line try_test(use_rights, [], Opts), - - %% Delete rows - ?line try_test(del_row, [GRow1Status]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), - - ?line try_test(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - -mk_ln(X) -> - [length(X) | X]. - -%%----------------------------------------------------------------- -%% o add/delete users and try them -%% o test all secLevels -%% o test all combinations of protocols -%% o try bad ops; check counters -%%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; -snmp_user_based_sm_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - _AgentDir = ?config(agent_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - - %% The newUser used here already has VACM access. - - %% Add a new user in the simplest way; just createAndGo - try_test(v3_sync, [[{usm_add_user1, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new user - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), - DesKey1 = lists:sublist(ShaKey1, 16), - - %% Change the new user's keys - 1 - try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), - DesKey2 = lists:sublist(ShaKey2, 16), - - %% Change the new user's keys - 2 - ?line try_test(v3_sync, - [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Change the new user's keys - 3 - ?line try_test(v3_sync, - [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("SNMP-USER-BASED-SM-MIB"). - --define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). - -usm_add_user1() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - -usm_use_user() -> - v2_proc(). - - -%% Change own public keys -usm_key_change1(ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_shaxxxxxxxxxx", - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_desxxxxxx", - DesKey), - Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change own private keys -usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change other's public keys -usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], - s(Vbs1), - ?line expect(1, noAccess, 1, any), - Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs2), - ?line expect(2, noAccess, 1, any), - - - Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs3), - ?line expect(1, Vbs3). - -usm_read() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], - [usmUserCloneFrom, NewRowIndex], - [usmUserAuthKeyChange, NewRowIndex], - [usmUserOwnAuthKeyChange, NewRowIndex], - [usmUserPrivKeyChange, NewRowIndex], - [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line expect(1, - [{[usmUserSecurityName, NewRowIndex], "newUser"}, - {[usmUserCloneFrom, NewRowIndex], [0,0]}, - {[usmUserAuthKeyChange, NewRowIndex], ""}, - {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, - {[usmUserPrivKeyChange, NewRowIndex], ""}, - {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]), - ok. - - - -usm_del_user() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - --define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). - --define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]). - --define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]). - --define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]). - --define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]). - --define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]). - -usm_bad() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, inconsistentName, 1, any), - - RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line expect(2, wrongValue, 1, any), - - RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line expect(3, Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line expect(4, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line expect(5, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line expect(6, wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line expect(7, wrongValue, 1, any), - - Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line expect(1, Vbs4), - - ok. - - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?LOG("loop_mib -> initiate case",[]), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - try_test(loop_mib_1), - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - - -loop_mib_2(suite) -> []; -loop_mib_2(Config) when list(Config) -> - ?LOG("loop_mib_2 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_2 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?LOG("loop_mib_2 -> done",[]). - - -loop_mib_3(suite) -> []; -loop_mib_3(Config) when list(Config) -> - ?LOG("loop_mib_3 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_3 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?LOG("loop_mib_3 -> done",[]). - - -%% Req. As many mibs all possible -loop_mib_1() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_1([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_1(Oid, N) -> - ?DBG("loop_it_1 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_1 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_1(NOid, N+1); - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it_1 -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - end. - -%% Req. As many mibs all possible -loop_mib_2() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_2([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_2(Oid, N) -> - ?DBG("loop_it_2 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid, value = endOfMibView}]} -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p",[NOid]), - N; - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_2 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_2(NOid, N+1) - end. - - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - - - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128_2(X) -> otp_1128(X). - -otp_1128_3(X) -> otp_1128(X). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_2(X) -> otp_1129(X). - -otp_1129_3(X) -> otp_1129(X). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - try_test(otp_1131), - ?line unload_master("Klas1"). - -otp_1131_2(X) -> otp_1131(X). - -otp_1131_3(X) -> otp_1131(X). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - try_test(otp_1162), - stop_subagent(SA). - -otp_1162_2(X) -> otp_1162(X). - -otp_1162_3(X) -> otp_1162(X). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - try_test(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222_2(X) -> otp_1222(X). - -otp_1222_3(X) -> otp_1222(X). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1298), - ?line unload_master("Klas2"). - -otp_1298_2(X) -> otp_1298(X). - -otp_1298_3(X) -> otp_1298(X). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331_2(X) -> otp_1331(X). - -otp_1331_3(X) -> otp_1331(X). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1338), - ?line unload_master("Klas2"). - -otp_1338_2(X) -> otp_1338(X). - -otp_1338_3(X) -> otp_1338(X). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas4"), - try_test(otp_1342), - ?line unload_master("Klas4"). - -otp_1342_2(X) -> otp_1342(X). - -otp_1342_3(X) -> otp_1342(X). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366_2(X) -> otp_1366(X). - -otp_1366_3(X) -> otp_1366(X). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_2776). - -otp_2776_2(X) -> otp_2776(X). - -otp_2776_3(X) -> otp_2776(X). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Test1"), - ?line init_old(), - try_test(otp_2979), - ?line unload_master("Test1"). - -otp_2979_2(X) -> otp_2979(X). - -otp_2979_3(X) -> otp_2979(X). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187_2(X) -> otp_3187(X). - -otp_3187_3(X) -> otp_3187(X). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - - - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - - - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?DBG("otp_4394_test -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -%%%-------------------------------------------------- -%%% Used to test the standard mib with our -%%% configuration. -%%%-------------------------------------------------- -run(F, A, Opts) -> - M = get(mib_dir), - Dir = get(mgr_dir), - User = snmp_misc:get_option(user, Opts, "all-rights"), - SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv), - EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"), - CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), - Community = snmp_misc:get_option(community, Opts, "all-rights"), - ?DBG("run -> start crypto app",[]), - Crypto = ?CRYPTO_START(), - ?DBG("run -> Crypto: ~p",[Crypto]), - catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - ?DBG("run -> config:~n" - "\tM: ~p~n" - "\tDir: ~p~n" - "\tUser: ~p~n" - "\tSecLevel: ~p~n" - "\tEngineID: ~p~n" - "\tCtxEngineID: ~p~n" - "\tCommunity: ~p~n" - "\tStdM: ~p", - [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]), - case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()}, - {packet_server_debug,true}, - {debug,true}, - {agent, get(master_host)}, - {agent_udp, 4000}, - {trap_udp, 5000}, - {recbuf,65535}, - quiet, - get(vsn), - {community, Community}, - {user, User}, - {sec_level, SecLevel}, - {engine_id, EngineID}, - {context_engine_id, CtxEngineID}, - {dir, Dir}, - {mibs, mibs(StdM, M)}]) of - {ok, _Pid} -> - Res = apply(?MODULE, F, A), - catch snmp_test_mgr:stop(), - Res; - Err -> - io:format("Error starting manager: ~p\n", [Err]), - catch snmp_test_mgr:stop(), - ?line exit({mgr_start, Err}) - end. - - -mibs(StdMibDir,MibDir) -> - [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")), - join(MibDir, "OLD-SNMPEA-MIB.bin"), - join(StdMibDir, "SNMP-FRAMEWORK-MIB"), - join(StdMibDir, "SNMP-MPD-MIB"), - join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"), - join(StdMibDir, "SNMP-USER-BASED-SM-MIB"), - join(StdMibDir, "SNMP-TARGET-MIB"), - join(StdMibDir, "SNMP-NOTIFICATION-MIB"), - join(MibDir, "Klas1.bin"), - join(MibDir, "Klas2.bin"), - join(MibDir, "Klas3.bin"), - join(MibDir, "Klas4.bin"), - join(MibDir, "SA-MIB.bin"), - join(MibDir, "TestTrap.bin"), - join(MibDir, "Test1.bin"), - join(MibDir, "Test2.bin"), - join(MibDir, "TestTrapv2.bin")]. - -join(D,F) -> - filename:join(D,F). - -%% string used in index -is(S) -> [length(S) | S]. - -try_test(Func) -> - call(get(mgr_node), ?MODULE, run, [Func, [], []]). - -try_test(Func, A) -> - call(get(mgr_node), ?MODULE, run, [Func, A, []]). - -try_test(Func, A, Opts) -> - call(get(mgr_node), ?MODULE, run, [Func, A, Opts]). - -call(N,M,F,A) -> - ?DBG("call -> entry with~n" - " N: ~p~n" - " M: ~p~n" - " F: ~p~n" - " A: ~p~n" - " when~n" - " get(): ~p", - [N,M,F,A,get()]), - spawn(N, ?MODULE, wait, [self(),get(),M,F,A]), - receive - {done, {'EXIT', Rn}, Loc} -> - ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]), - put(test_server_loc, Loc), - exit(Rn); - {done, Ret, Zed} -> - ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]), - Ret - end. - -wait(From, Env, M, F, A) -> - ?DBG("wait -> entry with ~n" - "\tFrom: ~p~n" - "\tEnv: ~p",[From,Env]), - lists:foreach(fun({K,V}) -> put(K,V) end, Env), - Rn = (catch apply(M, F, A)), - ?DBG("wait -> Rn: ~n~p", [Rn]), - From ! {done, Rn, get(test_server_loc)}, - exit(Rn). - -expect(A,B) -> ok = snmp_test_mgr:expect(A,B). -expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C). -expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F). - -get_req(Id, Vars) -> - ?DBG("get_req -> entry with~n" - "\tId: ~p~n" - "\tVars: ~p",[Id,Vars]), - g(Vars), - ?DBG("get_req -> await response",[]), - {ok, Val} = snmp_test_mgr:get_response(Id, Vars), - ?DBG("get_req -> response: ~p",[Val]), - Val. - -get_next_req(Vars) -> - ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]), - gn(Vars), - ?DBG("get_next_req -> await response",[]), - Response = snmp_test_mgr:receive_response(), - ?DBG("get_next_req -> response: ~p",[Response]), - Response. - - - -start_node(Name) -> - ?LOG("start_node -> entry with Name: ~p",[Name]), - M = list_to_atom(?HOSTNAME(node())), - ?DBG("start_node -> M: ~p",[M]), - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p",[Pa]), - - Args = case init:get_argument('CC_TEST') of - {ok, [[]]} -> - " -pa /clearcase/otp/libraries/snmp/ebin "; - {ok, [[Path]]} -> - " -pa " ++ Path; - error -> - "" - end, - %% Do not use start_link!!! (the proc that calls this one is tmp) - ?DBG("start_node -> Args: ~p~n",[Args]), - A = Args ++ " -pa " ++ Pa, - case (catch ?START_NODE(Name, A)) of - {ok, Node} -> - %% Tell the test_server to not clean up things it never started. - ?DBG("start_node -> Node: ~p",[Node]), - {ok, Node}; - Else -> - ?ERR("start_node -> failed with(other): Else: ~p",[Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?LOG("stop_node -> Node: ~p",[Node]), - rpc:cast(Node, erlang, halt, []). - -p(X) -> - io:format(user, X++"\n", []). - -sleep(X) -> - receive - after - X -> ok - end. - -%%%----------------------------------------------------------------- -%%% Configuration -%%%----------------------------------------------------------------- -config(Vsns, MgrDir, AgentDir, MIp, AIp) -> - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp, - ?TRAP_UDP, AIp, 4000, - "test"), - ?line case update_usm(Vsns, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); - false -> - ?line ok - end, - ?line update_community(Vsns, AgentDir), - ?line update_vacm(Vsns, AgentDir), - ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns), - ?line write_target_params_conf(AgentDir, Vsns), - ?line write_notify_conf(AgentDir), - ok. - -delete_files(Config) -> - Dir = ?config(agent_dir, Config), - {ok, List} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, - List). - -update_usm(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -update_usm_mgr(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - file:close(Fid). - -reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). - - -update_community([v3], _Dir) -> ok; -update_community(_, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n", - []), - file:close(Fid). - - --define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). -update_vacm(_Vsn, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]), - ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", " - "~w, excluded, null}.\n", [?tDescr_instance]), - file:close(Fid). - - -vacm_ver(v1) -> v1; -vacm_ver(v2) -> v2c; -vacm_ver(v3) -> usm. - - -write_community_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write), - ok = write_community_conf1(Fid, Confs), - file:close(Fid). - -write_community_conf1(_, []) -> - ok; -write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) -> - ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [ComIdx, ComName, SecName, CtxName, TransTag]), - write_community_conf1(Fid, Confs). - - -write_target_addr_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - ok = write_target_addr_conf1(Fid, Confs), - file:close(Fid). - - -write_target_addr_conf1(_, []) -> - ok; -write_target_addr_conf1(Fid, - [{Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz}|Confs]) -> - ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz]), - write_target_addr_conf1(Fid, Confs). - -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - lists:foreach(fun(Vsn) -> - ok = io:format(Fid, - "{\"~s\", ~w, ~w, 1500, 3, " - "\"std_trap\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, mk_param(Vsn)]), - case Vsn of - v1 -> ok; - v2 -> - ok = io:format(Fid, - "{\"~s.2\",~w,~w,1500,3, " - "\"std_inform\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]); - v3 -> - ok = io:format(Fid, - "{\"~s.3\",~w,~w,1500,3, " - "\"std_inform\", \"~s\", " - "\"mgrEngine\", [], 1024}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]) - end - end, - Vsns), - file:close(Fid). - -mk_param(v1) -> "target_v1"; -mk_param(v2) -> "target_v2"; -mk_param(v3) -> "target_v3". - -mk_ip([A,B,C,D], Vsn) -> - io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]). - - -rewrite_target_addr_conf(Dir,NewPort) -> - TAFile = filename:join(Dir, "target_addr.conf"), - ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]), - case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok - end, - - ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end), - - ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), - - NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs], - - ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - - ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs), - - file:close(Fid). - -rewrite_target_addr_conf1(O) -> - {ok,O}. - -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> - ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), - {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; -rewrite_target_addr_conf2(_NewPort,O) -> - ?LOG("rewrite_target_addr_conf2 -> entry with " - "~n O: ~p",[O]), - O. - - -rewrite_target_addr_conf3(_,[]) -> ok; -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry, - ParamName,EngineId}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % ParamsName - "\"~s\"}.", % EngineId - [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]), - rewrite_target_addr_conf3(Fid,T); -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList, - ParamName,EngineId,TMask,MMS}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % TagList - "\"~s\", " % ParamsName - "\"~s\"," % EngineId - "~p, " % TMask - "~p}.", % MMS - [Name,Ip,Port,Timeout,Retry,TagList,ParamName, - EngineId,TMask,MMS]), - rewrite_target_addr_conf3(Fid,T). - -reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_addr.old"), - filename:join(Dir,"target_addr.conf")). - -write_target_params_conf(Dir, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - lists:foreach(fun(Vsn) -> - MP = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> v3 - end, - SM = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> usm - end, - ok = io:format(Fid, "{\"target_~w\", ~w, ~w, " - "\"all-rights\", noAuthNoPriv}.~n", - [Vsn, MP, SM]) - end, - Vsns), - file:close(Fid). - -rewrite_target_params_conf(Dir, SecName, SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n", - [SecName, SecLevel]), - file:close(Fid). - -reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). - -write_notify_conf(Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write), - ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []), - ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []), - file:close(Fid). - -ver_to_trap_str([v1]) -> "v1"; -ver_to_trap_str([v2]) -> "v2"; -% default is to use the latest snmp version -ver_to_trap_str([v1,v2]) -> "v2". - - - -write_view_conf(Dir) -> - {ok, Fid} = file:open(a(Dir,"view.conf"),write), - ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []), - ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]), - file:close(Fid). - -a(A,B) -> lists:append(A,B). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -copy_file(From, To) -> - {ok, Bin} = file:read_file(From), - ok = file:write_file(To, Bin). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_memory_usage() -> - Info = snmpa:info(snmp_master_agent), - TreeSize = lists_key1search(tree_size_bytes, Info), - ProcMem = lists_key1search(process_memory, Info), - MibDbSize = lists_key1search([db_memory,mib], Info), - NodeDbSize = lists_key1search([db_memory,node], Info), - TreeDbSize = lists_key1search([db_memory,tree], Info), - ?INF("Memory usage: " - "~n Tree size: ~p" - "~n Process memory size: ~p" - "~n Mib db size: ~p" - "~n Node db size: ~p" - "~n Tree db size: ~p", - [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]). - -lists_key1search([], Res) -> - Res; -lists_key1search([Key|Keys], List) when atom(Key), list(List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - lists_key1search(Keys, Val); - false -> - undefined - end; -lists_key1search(Key, List) when atom(Key) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - Val; - false -> - undefined - end. - - -regs() -> - lists:sort(registered()). diff --git a/lib/snmp/test/exp/snmp_agent_v1_test.erl b/lib/snmp/test/exp/snmp_agent_v1_test.erl deleted file mode 100644 index f3b49f3bfd29..000000000000 --- a/lib/snmp/test/exp/snmp_agent_v1_test.erl +++ /dev/null @@ -1,2674 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_v1_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - --export([]). - --define(application, snmp). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). --include("snmp_test_lib.hrl"). --define(SNMP_USE_V3, true). --include_lib("snmp/include/snmp_types.hrl"). - - --define(klas1, [1,3,6,1,2,1,7]). --define(klas2, [1,3,6,1,2,1,9]). --define(klas3, [1,3,6,1,2,1,8,1]). --define(klas4, [1,3,6,1,2,1,8,4]). --define(sa, [1,3,6,1,4,1,193,2]). --define(system, [1,3,6,1,2,1,1]). --define(snmp, [1,3,6,1,2,1,11]). --define(snmpTraps, [1,3,6,1,6,3,1,1,5]). --define(ericsson, [1,3,6,1,4,1,193]). --define(testTrap, [1,3,6,1,2,1,15,0]). --define(xDescr, [1,3,6,1,2,1,17,1]). --define(xDescr2, [1,3,6,1,2,1,17,2]). - --define(active, 1). --define(notInService, 2). --define(notReady, 3). --define(createAndGo, 4). --define(createAndWait, 5). --define(destroy, 6). - --define(TRAP_UDP, 5000). - --define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - - -%% -- test manager defines -- --define(MGR, snmp_test_mgr). --define(GN(X), ?MGR:gn(X)). --define(G(X), ?MGR:g(X)). --define(S(X), ?MGR:s(X)). --define(GB(X), ?MGR:gb(X)). --define(SEND_BYTES(X), ?MGR:send_bytes(X)). - -%% -- agent test lib defines -- --define(LIB, snmp_agent_test_lib). --define(INIT_CASE(X), ?LIB:init_case(X)). --define(TRY_TEST1(A), ?LIB:try_test(A)). --define(TRY_TEST2(A, B), ?LIB:try_test(A, B)). --define(TRY_TEST3(A, B, C), ?LIB:try_test(A, B, C)). --define(START_SA(A, B, C), ?LIB:start_subagent(A, B, C)). --define(STOP_SA(A), ?LIB:stop_subagent(A)). --define(P1(C), ?LIB:p(C)). --define(P2(F), ?LIB:p(F,[])). --define(P3(F,A), ?LIB:p(F,A)). --define(RPC(N, F, A), ?LIB:rpc(N, F, A)). - - --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all(suite) -> {req, - [mnesia, distribution, - {local_slave_nodes, 2}, {time, 360}], - [{conf, init, cases(), finish}]}. - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [simple, - db_notify_client, - processing, - big, - big2, - %% implied, - loop_mib, - api, - subagent, - mnesia, - multiple_reqs, - sa_register, - v1_trap, - sa_error, - next_across_sa, - undo, - standard_mibs, - sparse_table, - cnt_64, - opaque, - %% opaque]. - - change_target_addr_config, - - reported_bugs, - tickets - ]. - - -init(Config) -> - init_all(Config), - init_v1(Config). - -finish(Config) -> - finish_v1(Config), - finish_all(Config). - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - -%% ========================================================================= -%% -%% C A S E S -%% -%% ========================================================================= - -%% -- simple -- - -simple(suite) -> []; -simple(Config) when list(Config) -> - ?P1(simple), - ?INIT_CASE(Config), - - ?TRY_TEST1(simple_standard_test). - -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - ?GN([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?GN([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?G([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - - ?G([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - - ?G([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - - ?GN([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - - ?S([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?G([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - - io:format("Testing noSuchName and badValue...~n"), - ?S([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - - ?S([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - - -%% -- db_notify_client -- - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - ?P1(db_notify_client), - {SaNode, MgrNode, MibDir} = ?INIT_CASE(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - ?TRY_TEST1(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - ?S([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - ?S([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% -- processing -- - -%% Req. Test2 -processing(suite) -> []; -processing(Config) when list(Config) -> - ?P1(processing), - ?INIT_CASE(Config), - - ?line load_master("Test2"), - ?TRY_TEST1(v1_proc), - ?line unload_master("Test2"). - -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - -v1_get_p() -> - %% 4.1.2:1 - ?G([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - ?G([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - ?G([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - ?G([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - ?G([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - ?G([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - ?G([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - ?G([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - ?G([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - ?G([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - ?G([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - ?G([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - ?G([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - -v1_get_next_p() -> - %% 4.1.3:1 - ?GN([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - - ?GN([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - ?GN([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), - %% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - ?GN([[tGenErr1]]), - %% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - - ?GN([[tGenErr2]]), - %% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - - ?GN([[sysDescr], [tGenErr3]]), - %% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, - %% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - ?S([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - - ?S([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - - ?S([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - - ?S([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - - ?S([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - - ?S([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - ?S([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - - ?S([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - ?S([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: - %% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - ?S([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - - ?S([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - - -%% -- big -- - -big(suite) -> []; -big(Config) when list(Config) -> - ?P1(big), - {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - ?TRY_TEST1(big_test), - - ?line ?STOP_SA(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - ?GN([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - - ?G([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - - ?S([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - - ?G([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - ?GN([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - - ?GN([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - ?S([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - ?S([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - - ?G([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - - ?S([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - ?S([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - - ?G([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - - ?GN([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - - ?S([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - - ?GN([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - - ?S([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - - ?S([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - ?P1(big_test_2), - - ?P2("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - ?GN([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - - ?G([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - - ?S([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - - ?G([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - ?P2("Testing next from last object in master to subagent (2)..."), - ?GN([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - - ?GN([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - ?P2("Adding one row in subagent table (2)"), - ?S([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - - ?G([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - - ?S([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - ?P2("Adding two rows in subagent table with special INDEX (2)"), - ?S([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - ?G([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - ?GN([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - - ?S([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - - ?GN([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - - ?S([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - - ?S([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - - -%% -- bug2 -- - -big2(suite) -> []; -big2(Config) when list(Config) -> - ?P1(big2), - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - - ?P2("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - - ?TRY_TEST1(big_test), - - ?line ?STOP_SUBAGENT(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - ?P1(implied), - ?INIT_CASE(Config), - - ?line load_master("Test1"), - - ?TRY_TEST2(implied_test,[whereis(snmp_master_agent)]), - - ?line unload_master("Test1"). - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - ?S([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - - ?S([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - - ?GN([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - - ?GN([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - ?S([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - ?S([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - ?S([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - ?S([{[testStatus2, Idx4], i, ?createAndGo}, - {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - - ?DBG("implied_test -> get-next(testDescr2)",[]), - ?GN([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - - ?GN([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - ?S([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - ?S([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - -%% -- loop_mib -- - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?P1(loop_mib), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = ?INIT_CASE(Config), - ?DBG("loop_mib -> " - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [SaNode, MgrNode, MibDir]), - - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - - ?TRY_TEST1(loop_mib), - - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - -%% Req. As many mibs all possible -loop_mib() -> - ?DBG("loop_mib -> entry",[]), - N = loop_it([1,1], 0), - ?P3("found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - -loop_it(Oid, N) -> - ?DBG("loop_it -> entry with" - "~n Oid: ~p" - "~n N: ~p", [Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it -> " - "~n NOid: ~p" - "~n Value: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> " - "~n Value2: ~p",[Value2]), - loop_it(NOid, N+1); - - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - - end. - - -%% -- api -- - -api(suite) -> []; -api(Config) when list(Config) -> - ?P1(api), - ?INIY_CASE(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - ?TRY_TEST2(api_test, [node()]), - - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = ?RPC(MaNode, name_to_oid, [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = ?RPC(MaNode, oid_to_name, [OID]), - ?line false = ?RPC(MaNode, name_to_oid, [intAgentIpAddres]), - ?line false = ?RPC(MaNode, oid_to_name, [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = ?RPC(MaNode, enum_to_int, [intViewType, excluded]), - ?line {value, excluded} = ?RPC(MaNode, int_to_enum, [intViewType, 2]), - ?line false = ?RPC(MaNode, enum_to_int, [intViewType, exclude]), - ?line false = ?RPC(MaNode, enum_to_int, [intAgentIpAddress, exclude]), - ?line false = ?RPC(MaNode, enum_to_int, [intAgentIpAddre, exclude]), - ?line false = ?RPC(MaNode, int_to_enum, [intViewType, 3]), - ?line false = ?RPC(MaNode, int_to_enum, [intAgentIpAddress, 2]), - ?line false = ?RPC(MaNode, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = ?RPC(MaNode, int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = - ?RPC(MaNode, enum_to_int, ['RowStatus', destroy]), - ?line false = ?RPC(MaNode, enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = ?RPC(MaNode, enum_to_int, ['xxRowStatus', destroy]), - ?line false = ?RPC(MaNode, int_to_enum, ['RowStatus', 25]), - ?line false = ?RPC(MaNode, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - - -%% -- subagent -- - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - ?P1(subagent), - {SaNode, _MgrNode, MibDir} = ?INIT_CASE(Config), - - ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1"), - - ?TRY_TEST1(load_test_sa), - - ?P2("Testing unregister subagent [~w]...", [SA]), - MA = whereis(snmp_master_agent), - ?RPC(SaNode, unregister_subagent, [MA, SA]), - ?TRY_TEST1(unreg_test), - - ?P2("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - ?TRY_TEST1(load_test), - - ?P2("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - - ?TRY_TEST1(unreg_test), - - ?P2("Testing register subagent..."), - ?RPC(SaNode, register_subagent, [MA, ?klas1, SA]), - ?TRY_TEST1(load_test_sa), - - ?line ?STOP_SA(SA), - ?TRY_TEST1(unreg_test). - -%% Req. Klas1 -load_test_sa() -> - ?GN([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -unreg_test() -> - ?GN([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - ?GN([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - - -%% -- mnesia -- - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - ?TRY_TEST1(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - ?TRY_TEST1(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - - -%% -- multiple_reqs -- - -multiple_reqs(suite) -> - {req, [], {conf, init_mul, mul_cases(), finish_mul}}. - -mul_cases() -> - [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err]. - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - - -%% -- mul_get -- - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - ?TRY_TEST1(do_mul_get). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - - -%% -- mul_get_err -- - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - ?TRY_TEST1(do_mul_get_err). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% -- mul_next -- - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - ?TRY_TEST1(do_mul_next). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - - -%% -- mul_next_err -- - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - ?TRY_TEST1(do_mul_next_err). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% -- mul_set -- - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - ?P(mul_set), - ?INIT_CASE(Config), - - ?TRY_TEST1(do_mul_set). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - - -%% -- mul_set_err -- - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - ?P(mul_set_err), - ?INIT_CASE(Config), - - ?TRY_TEST1(do_mul_set_err). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - - -%% -- sa_register -- - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?P1(sa_register), - {SaNode, _MgrNode, MibDir} = ?INIT_CASE(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - ?P2("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - ?TRY_TEST1(unreg_test), - - ?P2("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - ?TRY_TEST1(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - - -%% -- v1_trap -- - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - ?TRY_TEST2(ma_trap1, [MA]), - ?TRY_TEST2(ma_trap2, [MA]), - ?TRY_TEST2(ma_v2_2_v1_trap, [MA]), - ?TRY_TEST2(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - ?TRY_TEST2(sa_trap1, [SA]), - ?TRY_TEST2(sa_trap2, [SA]), - ?TRY_TEST2(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% -- sa_error -- - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - ?TRY_TEST1(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - ?TRY_TEST1(sa_errs_gen_err), - - p("Testing too big..."), - ?TRY_TEST1(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - - -%% -- next_across_sa -- - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - ?TRY_TEST1(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - ?TRY_TEST1(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - ?TRY_TEST1(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - ?TRY_TEST1(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - - -%% -- undo -- - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - ?TRY_TEST1(undo_test), - ?TRY_TEST1(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - ?TRY_TEST1(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - ?TRY_TEST1(undo_test), - ?TRY_TEST1(api_test3), - - p("Testing undo phase across master/subagents..."), - ?TRY_TEST1(undo_test), - ?TRY_TEST1(api_test3), - stop_subagent(SA). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), - %% unfortunatly we don't know if we'll get undoFailed or commitFailed. - %% it depends on which order the agent traverses the varbind list. - %% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), - %% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%% -- standard_mibs -- - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- -standard_mibs(suite) -> - [snmp_standard_mib, - snmp_community_mib, - snmp_framework_mib, - snmp_target_mib, - snmp_notification_mib, - snmp_view_based_acm_mib]. - - -%% -- snmp_standard_mib -- - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - ?TRY_TEST1(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = ?TRY_TEST1(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - ?TRY_TEST1(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = ?TRY_TEST2(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - ?TRY_TEST3(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - ?TRY_TEST3(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - ?TRY_TEST1(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - ?TRY_TEST2(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - ?TRY_TEST1(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - ?TRY_TEST1(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - ?TRY_TEST3(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - ?SEND_BYTES([48,99,67,12,0,0,0,0,0,0,5]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - - -%% -- snmp_community_mib -- - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?TRY_TEST1(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - - -%% -- snmp_framework_mib -- - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?TRY_TEST1(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - - -%% -- snmp_target_mib -- - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - ?TRY_TEST1(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - - -%% -- snmp_notification_mib -- - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?TRY_TEST1(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - - -%% -- snmp_view_based_acm_mib -- - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line ?TRY_TEST2(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line ?TRY_TEST2(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Delete that row - ?line ?TRY_TEST2(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line ?TRY_TEST2(do_set, [ARow2]), - - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Delete that row - ?line ?TRY_TEST2(del_row, [ARow2Status]), - - - %% Add valid row - ?line ?TRY_TEST2(do_set, [ARow1]), - - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line ?TRY_TEST2(add_row, [VRow1Status]), - ?line ?TRY_TEST2(add_row, [VRow2Status]), - ?line ?TRY_TEST2(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line ?TRY_TEST3(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line ?TRY_TEST2(del_row, [VRow3Status]), - ?line ?TRY_TEST2(add_row, [VRow4Status]), - - %% We should still have access... - ?line ?TRY_TEST3(use_rights, [], Opts), - - %% Delete rows - ?line ?TRY_TEST2(del_row, [GRow1Status]), - - ?line ?TRY_TEST3(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line ?TRY_TEST2(del_row, [ARow1Status]), - ?line ?TRY_TEST2(del_row, [VRow1Status]), - ?line ?TRY_TEST2(del_row, [VRow2Status]), - ?line ?TRY_TEST2(del_row, [VRow4Status]), - - ?line ?TRY_TEST3(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - - -%% -- sparse_table -- - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - - ?line load_master("Test1"), - ?TRY_TEST1(sparse_table_test), - ?line unload_master("Test1"). - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% -- cnt_64 -- - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?TRY_TEST2(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - - -%% -- opaque -- - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - - ?line load_master("Test1"), - ?TRY_TEST1(opaque_test), - ?line unload_master("Test1"). - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - - -%% -- change_target_addr_config -- - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - ?TRY_TEST2(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -%% -- reported_bugs -- - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - -reported_bugs(suite) -> - [otp_1128, otp_1129, otp_1131, otp_1162, - otp_1222, otp_1298, otp_1331, otp_1338, - otp_1342, otp_2776, otp_2979, otp_3187, otp_3725]. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?TRY_TEST1(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?TRY_TEST2(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - ?TRY_TEST1(otp_1131), - ?line unload_master("Klas1"). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - ?P1(otp_1162), - {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config), - ?line {ok, SA} = ?START_SA(SaNode, ?sa, "SA-MIB"), - ?TRY_TEST1(otp_1162), - ?STOP_SA(SA). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - ?P1(otp_1222), - ?INIT_CASE(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - ?TRY_TEST1(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - ?P1(otp_1298), - ?INIT_CASE(Config), - ?line load_master("Klas2"), - ?TRY_TEST1(otp_1298), - ?line unload_master("Klas2"). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - ?P1(otp_1331), - ?INIT_CASE(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?TRY_TEST1(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - ?P1(otp_1338), - ?INIT_CASE(Config), - ?line load_master("Klas2"), - ?TRY_TEST1(otp_1338), - ?line unload_master("Klas2"). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - ?P1(otp_1342), - ?INIT_CASE(Config), - ?line load_master("Klas4"), - ?TRY_TEST1(otp_1342), - ?line unload_master("Klas4"). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - ?P1(otp_1366), - ?INIT_CASE(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?TRY_TEST1(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - ?P1(otp_2776), - ?INIT_CASE(Config), - ?TRY_TEST1(otp_2776). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - ?P1(otp_2979), - ?INIT_CASE(Config), - ?line load_master("Test1"), - ?line init_old(), - ?TRY_TEST1(otp_2979), - ?line unload_master("Test1"). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - ?P1(otp_3187), - ?INIT_CASE(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - ?P1(otp_3542), - ?INIT_CASE(Config), - ?TRY_TEST1(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - ?P1(otp_3725), - ?INIT_CASE(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?TRY_TEST2(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%% -- tickets -- - -%% These are (ticket) test cases where the initiation has to be done -%% individually. -tickets(suite) -> - [otp_4394]. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - -otp_4394(suite) -> {req, [], {conf, - init_otp_4394, - [otp_4394_test], - finish_otp_4394}}. - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?P1(otp_4394_test), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?TRY_TEST1(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -mk_ln(X) -> - [length(X) | X]. - - - -%% string used in index -is(S) -> [length(S) | S]. - -expect(A,B) -> ok = ?MGR:expect(A,B). -expect(A,B,C) -> ok = ?MGR:expect(A,B,C). -expect(A,B,C,D) -> ok = ?MGR:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = ?MGR:expect(A,B,C,D,E,F). - diff --git a/lib/snmp/test/exp/snmp_agent_v2_test.erl b/lib/snmp/test/exp/snmp_agent_v2_test.erl deleted file mode 100644 index 07ff1ed42248..000000000000 --- a/lib/snmp/test/exp/snmp_agent_v2_test.erl +++ /dev/null @@ -1,5636 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_v2_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - --compile(export_all). - --define(application, snmp). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). --include("snmp_test_lib.hrl"). --define(SNMP_USE_V3, true). --include_lib("snmp/include/snmp_types.hrl"). -%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). - - --define(klas1, [1,3,6,1,2,1,7]). --define(klas2, [1,3,6,1,2,1,9]). --define(klas3, [1,3,6,1,2,1,8,1]). --define(klas4, [1,3,6,1,2,1,8,4]). --define(sa, [1,3,6,1,4,1,193,2]). --define(system, [1,3,6,1,2,1,1]). --define(snmp, [1,3,6,1,2,1,11]). --define(snmpTraps, [1,3,6,1,6,3,1,1,5]). --define(ericsson, [1,3,6,1,4,1,193]). --define(testTrap, [1,3,6,1,2,1,15,0]). --define(xDescr, [1,3,6,1,2,1,17,1]). --define(xDescr2, [1,3,6,1,2,1,17,2]). - --define(active, 1). --define(notInService, 2). --define(notReady, 3). --define(createAndGo, 4). --define(createAndWait, 5). --define(destroy, 6). - --define(TRAP_UDP, 5000). - --define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - --define(str(X), snmp_pdus:bits_to_str(X)). - --define(break(), begin io:format(user, "break at line ~w: pid: ~p\n", - [?LINE, self()]), - receive cont -> ok end - end). - - --import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]). --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all() -> -[cases()]. - -groups() -> - [{mib_storage, [], - [{group, mib_storage_ets}, {group, mib_storage_dets}, - {group, mib_storage_mnesia}, - {group, mib_storage_size_check_ets}, - {group, mib_storage_size_check_dets}, - {group, mib_storage_size_check_mnesia}, - {group, mib_storage_varm_dets}, - {group, mib_storage_varm_mnesia}]}, - {mib_storage_ets, [], mib_storage_ets_cases()}, - {mib_storage_dets, [], mib_storage_dets_cases()}, - {mib_storage_mnesia, [], mib_storage_mnesia_cases()}, - {mib_storage_size_check_ets, [], - mse_size_check_cases()}, - {mib_storage_size_check_dets, [], - msd_size_check_cases()}, - {mib_storage_size_check_mnesia, [], - msm_size_check_cases()}, - {mib_storage_varm_dets, [], - varm_mib_storage_dets_cases()}, - {mib_storage_varm_mnesia, [], - varm_mib_storage_mnesia_cases()}, - {test_v1, [], v1_cases()}, {test_v2, [], v2_cases()}, - {test_v1_v2, [], v1_v2_cases()}, - {test_v3, [], v3_cases()}, - {test_multi_threaded, [], mt_cases()}, - {multiple_reqs, [], mul_cases()}, - {multiple_reqs_2, [], mul_cases_2()}, - {v2_inform, [], [v2_inform_i]}, - {v3_security, [], - [v3_crypto_basic, v3_md5_auth, v3_sha_auth, - v3_des_priv]}, - {standard_mibs, [], - [snmp_standard_mib, snmp_community_mib, - snmp_framework_mib, snmp_target_mib, - snmp_notification_mib, snmp_view_based_acm_mib]}, - {standard_mibs_2, [], - [snmpv2_mib_2, snmp_community_mib_2, - snmp_framework_mib_2, snmp_target_mib_2, - snmp_notification_mib_2, snmp_view_based_acm_mib_2]}, - {standard_mibs_3, [], - [snmpv2_mib_3, snmp_framework_mib_3, snmp_mpd_mib_3, - snmp_target_mib_3, snmp_notification_mib_3, - snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3]}, - {reported_bugs, [], - [otp_1128, otp_1129, otp_1131, otp_1162, otp_1222, - otp_1298, otp_1331, otp_1338, otp_1342, otp_2776, - otp_2979, otp_3187, otp_3725]}, - {reported_bugs_2, [], - [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2, - otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2, - otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2]}, - {reported_bugs_3, [], - [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3, - otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3, - otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3, - otp_3542]}, - {tickets, [], [{group, otp_4394}]}, - {otp_4394, [], [otp_4394_test]}]. - -init_per_group(otp_4394, Config) -> - init_otp_4394(Config); -init_per_group(v2_inform, Config) -> - init_v2_inform(Config); -init_per_group(multiple_reqs_2, Config) -> - init_mul(Config); -init_per_group(multiple_reqs, Config) -> - init_mul(Config); -init_per_group(test_multi_threaded, Config) -> - init_mt(Config); -init_per_group(test_v3, Config) -> - init_v3(Config); -init_per_group(test_v1_v2, Config) -> - init_v1_v2(Config); -init_per_group(test_v2, Config) -> - init_v2(Config); -init_per_group(test_v1, Config) -> - init_v1(Config); -init_per_group(mib_storage_varm_mnesia, Config) -> - init_varm_mib_storage_mnesia(Config); -init_per_group(mib_storage_varm_dets, Config) -> - init_varm_mib_storage_dets(Config); -init_per_group(mib_storage_size_check_mnesia, Config) -> - init_size_check_msm(Config); -init_per_group(mib_storage_size_check_dets, Config) -> - init_size_check_msd(Config); -init_per_group(mib_storage_size_check_ets, Config) -> - init_size_check_mse(Config); -init_per_group(mib_storage_mnesia, Config) -> - init_mib_storage_mnesia(Config); -init_per_group(mib_storage_dets, Config) -> - init_mib_storage_dets(Config); -init_per_group(mib_storage_ets, Config) -> - init_mib_storage_ets(Config); -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(otp_4394, Config) -> - finish_otp_4394(Config); -end_per_group(v2_inform, Config) -> - finish_v2_inform(Config); -end_per_group(multiple_reqs_2, Config) -> - finish_mul(Config); -end_per_group(multiple_reqs, Config) -> - finish_mul(Config); -end_per_group(test_multi_threaded, Config) -> - finish_mt(Config); -end_per_group(test_v3, Config) -> - finish_v3(Config); -end_per_group(test_v1_v2, Config) -> - finish_v1_v2(Config); -end_per_group(test_v2, Config) -> - finish_v2(Config); -end_per_group(test_v1, Config) -> - finish_v1(Config); -end_per_group(mib_storage_varm_mnesia, Config) -> - finish_varm_mib_storage_mnesia(Config); -end_per_group(mib_storage_varm_dets, Config) -> - finish_varm_mib_storage_dets(Config); -end_per_group(mib_storage_size_check_mnesia, Config) -> - finish_size_check_msm(Config); -end_per_group(mib_storage_size_check_dets, Config) -> - finish_size_check_msd(Config); -end_per_group(mib_storage_size_check_ets, Config) -> - finish_size_check_mse(Config); -end_per_group(mib_storage_mnesia, Config) -> - finish_mib_storage_mnesia(Config); -end_per_group(mib_storage_dets, Config) -> - finish_mib_storage_dets(Config); -end_per_group(mib_storage_ets, Config) -> - finish_mib_storage_ets(Config); -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [ - app_info, - {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets} - ]. - - -%%%----------------------------------------------------------------- -%%% The test case structure is as follows: -%%% -%%% init_all - starts mnesia, -%%% -%%% init_v1 - starts agent -%%% simple -%%% big - e.g. starts/stops subagent, load/unloads mibs -%%% init_mul -%%% mul_get -%%% mul_set -%%% -%%% finish_mul -%%% -%%% finish_v1 -%%% -%%% init_v2 - starts agent -%%% finish_v2 -%%% -%%% init_bilingual - starts agent -%%% finish_bilingual -%%% -%%% finish_all -%%% -%%% There is still one problem with these testsuites. If one test -%%% fails, it may not be possible to run some other cases, as it -%%% may have e.g. created some row or loaded some table, that it -%%% didn't undo (since it failed). -%%%----------------------------------------------------------------- - -init_all(Config0) when list(Config0) -> - ?LOG("init_all -> entry with" - "~n Config0: ~p",[Config0]), - - %% -- - %% Fix config: - %% - - DataDir0 = ?config(data_dir, Config0), - DataDir1 = filename:split(filename:absname(DataDir0)), - [_|DataDir2] = lists:reverse(DataDir1), - DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), - Config1 = lists:keydelete(data_dir, 1, Config0), - Config = [{data_dir, DataDir3 ++ "/"}|Config1], - - %% -- - %% Start nodes - %% - - ?line {ok, SaNode} = start_node(snmp_sa), - ?line {ok, MgrNode} = start_node(snmp_mgr), - - - %% -- - %% Create necessary files - %% - - Dir = ?config(priv_dir, Config), - ?DBG("init_all -> Dir ~p", [Dir]), - - DataDir = ?config(data_dir, Config), - ?DBG("init_all -> DataDir ~p", [DataDir]), - - file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")), - ?DBG("init_all -> MgrDir ~p", [MgrDir]), - - file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")), - ?DBG("init_all -> AgentDir ~p", [AgentDir]), - - file:make_dir(SaDir = filename:join(Dir, "sa_dir/")), - ?DBG("init_all -> SaDir ~p", [SaDir]), - - - %% -- - %% Start and initiate mnesia - %% - - ?DBG("init_all -> load application mnesia", []), - ?line ok = application:load(mnesia), - - ?DBG("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), - - ?DBG("init_all -> application mnesia: set_env dir",[]), - ?line application_controller:set_env(mnesia, dir, - filename:join(Dir, "Mnesia1")), - - ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(Dir, "Mnesia2")]), - - ?DBG("init_all -> create mnesia schema",[]), - ?line ok = mnesia:create_schema([SaNode, node()]), - - ?DBG("init_all -> start application mnesia",[]), - ?line ok = application:start(mnesia), - - ?DBG("init_all -> start application mnesia on ~p",[SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), - Ip = ?LOCALHOST(), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, - {agent_dir, AgentDir ++ "/"}, - {mgr_dir, MgrDir ++ "/"}, - {sa_dir, SaDir ++ "/"}, - {mib_dir, DataDir}, - {ip, Ip} | - Config]. - -finish_all(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - stop_node(SaNode), - stop_node(MgrNode), - application:stop(mnesia). - -start_v1_agent(Config) when list(Config) -> - start_agent(Config, [v1]). - -start_v1_agent(Config,Opts) when list(Config), list(Opts) -> - start_agent(Config, [v1], Opts). - -start_v2_agent(Config) when list(Config) -> - start_agent(Config, [v2]). - -start_v3_agent(Config) when list(Config) -> - start_agent(Config, [v3]). - -start_bilingual_agent(Config) when list(Config) -> - start_agent(Config, [v1,v2]). - -start_multi_threaded_agent(Config) when list(Config) -> - start_agent(Config, [v2], [{snmp_multi_threaded, true}]). - -stop_agent(Config) when list(Config) -> - ?LOG("stop_agent -> entry with" - "~n Config: ~p",[Config]), - - {Sup, Par} = ?config(snmp_sup, Config), - ?DBG("stop_agent -> attempt to stop (sup) ~p" - "~n Sup: ~p" - "~n Par: ~p", - [Sup, - (catch process_info(Sup)), - (catch process_info(Par))]), - stop_sup(Sup, Par), - - {Sup2, Par2} = ?config(snmp_sub, Config), - ?DBG("stop_agent -> attempt to stop (sub) ~p" - "~n Sup2: ~p" - "~n Par2: ~p", - [Sup2, - (catch process_info(Sup2)), - (catch process_info(Par2))]), - stop_sup(Sup2, Par2), - - ?DBG("stop_agent -> done - now cleanup config", []), - C1 = lists:keydelete(snmp_sup, 1, Config), - lists:keydelete(snmp_sub, 1, C1). - - -stop_sup(Pid, _) when node(Pid) == node() -> - case (catch process_info(Pid)) of - PI when list(PI) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - exit(Pid, kill), - await_stopped(Pid, Ref); - {'EXIT', _Reason} -> - ?LOG("stop_sup -> ~p not running", [Pid]), - ok - end; -stop_sup(Pid, _) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - ?LOG("stop_sup -> Ref: ~p", [Ref]), - %% Pid ! {'EXIT', Parent, shutdown}, % usch - exit(Pid, kill), - await_stopped(Pid, Ref). - -await_stopped(Pid, Ref) -> - receive - {'DOWN', Ref, process, Pid, _Reason} -> - ?DBG("received down message for ~p", [Pid]), - ok - after 10000 -> - ?INF("await_stopped -> timeout for ~p",[Pid]), - erlang:demonitor(Ref), - ?FAIL({failed_stop,Pid}) - end. - - -start_agent(Config, Vsn) -> - start_agent(Config, Vsn, []). -start_agent(Config, Vsn, Opts) -> - ?LOG("start_agent -> entry (~p) with" - "~n Config: ~p" - "~n Vsn: ~p" - "~n Opts: ~p",[node(), Config, Vsn, Opts]), - - ?line AgentDir = ?config(agent_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - - snmp_app_env_init(vsn_init(Vsn) ++ - [{audit_trail_log, read_write_log}, - {audit_trail_log_dir, AgentDir}, - {audit_trail_log_size, {10240, 10}}, - {force_config_reload, false}, - {snmp_agent_type, master}, - {snmp_config_dir, AgentDir}, - {snmp_db_dir, AgentDir}, - {snmp_local_db_auto_repair, true}, - {snmp_master_agent_verbosity, trace}, - {snmp_supervisor_verbosity, trace}, - {snmp_mibserver_verbosity, trace}, - {snmp_symbolic_store_verbosity, trace}, - {snmp_note_store_verbosity, trace}, - {snmp_net_if_verbosity, trace}], - Opts), - - - process_flag(trap_exit,true), - - {ok, AppSup} = snmp_app_sup:start_link(), - unlink(AppSup), - ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]), - - ?DBG("start_agent -> start master agent (old style)",[]), - Sup = case (catch snmpa_app:start(normal)) of - {ok, S} -> - ?DBG("start_agent -> started, Sup: ~p",[S]), - S; - - Else -> - ?DBG("start_agent -> unknown result: ~n~p",[Else]), - %% Get info about the apps we depend on - MnesiaInfo = mnesia_running(), - ?FAIL({start_failed,Else,MnesiaInfo}) - end, - - ?DBG("start_agent -> unlink from supervisor",[]), - ?line unlink(Sup), - ?line SaDir = ?config(sa_dir, Config), - ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]), - ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]), - ?DBG("start_agent -> done",[]), - ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. - - -vsn_init(Vsn) -> - vsn_init([v1,v2,v3], Vsn, []). - -vsn_init([], _Vsn, Acc) -> - Acc; -vsn_init([V|Vsns], Vsn, Acc) -> - case lists:member(V, Vsn) of - true -> - vsn_init(Vsns, Vsn, [{V, true}|Acc]); - false -> - vsn_init(Vsns, Vsn, [{V, false}|Acc]) - end. - -snmp_app_env_init(Env0, Opts) -> - ?DBG("snmp_app_env_init -> unload snmp",[]), - ?line application:unload(snmp), - ?DBG("snmp_app_env_init -> load snmp",[]), - ?line application:load(snmp), - ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]), - F1 = fun({Key,Val} = New, Acc0) -> - ?DBG("snmp_app_env_init -> " - "updating setting ~p to ~p", [Key, Val]), - case lists:keyreplace(Key, 1, Acc0, New) of - Acc0 -> - [New|Acc0]; - Acc -> - Acc - end - end, - Env = lists:foldr(F1, Env0, Opts), - ?DBG("snmp_app_env_init -> Env: ~p",[Env]), - F2 = fun({Key,Val}) -> - ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]), - application_controller:set_env(snmp, Key, Val) - end, - lists:foreach(F2, Env). - - - - -%% Test if application is running -mnesia_running() -> ?IS_MNESIA_RUNNING(). -crypto_running() -> ?IS_CRYPTO_RUNNING(). - - -start_sub(Dir) -> - ?DBG("start_sub -> entry",[]), - Opts = [{db_dir, Dir}, - {supervisor, [{verbosity, trace}]}], - %% BMK BMK -% {ok, P} = snmp_supervisor:start_sub(Dir), - {ok, P} = snmpa_supervisor:start_sub_sup(Opts), - unlink(P), - {ok, {P, self()}}. - -create_tables(SaNode) -> - ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, - {attributes, [a1,a2]}]). - -delete_tables() -> - mnesia:delete_table(friendsTable2), - mnesia:delete_table(kompissTable2), - mnesia:delete_table(snmp_variables). - -%% Creation is done in runtime! -delete_mib_storage_mnesia_tables() -> - mnesia:delete_table(snmpa_mib_data), - mnesia:delete_table(snmpa_mib_tree), - mnesia:delete_table(snmpa_symbolic_store). - -%%----------------------------------------------------------------- -%% A test case is always one of: -%% - v1 specific case -%% - v2 specific case -%% - v1 and v2 case -%% All v1 specific cases are prefixed with v1_, and all v2 with -%% v2_. E.g. v1_trap/v2_trap. -%% -%% All other cases are shared. However, the testserver uses the name -%% of the case to generate a file for that case. The same case cannot -%% be used in different configurations in the same suite. Therefore -%% all these functions exists in two variants, the base function -%% , and a second version _2. There may be several -%% versions as well, _N. -%%----------------------------------------------------------------- - - - - - - - - - -mib_storage_ets_cases() -> -[mse_simple, mse_v1_processing, mse_big, mse_big2, - mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap, - mse_sa_error, mse_next_across_sa, mse_undo, - mse_standard_mib, mse_community_mib, mse_framework_mib, - mse_target_mib, mse_notification_mib, - mse_view_based_acm_mib, mse_sparse_table, mse_me_of, - mse_mib_of]. - -mib_storage_dets_cases() -> -[msd_simple, msd_v1_processing, msd_big, msd_big2, - msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap, - msd_sa_error, msd_next_across_sa, msd_undo, - msd_standard_mib, msd_community_mib, msd_framework_mib, - msd_target_mib, msd_notification_mib, - msd_view_based_acm_mib, msd_sparse_table, msd_me_of, - msd_mib_of]. - -mib_storage_mnesia_cases() -> -[msm_simple, msm_v1_processing, msm_big, msm_big2, - msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap, - msm_sa_error, msm_next_across_sa, msm_undo, - msm_standard_mib, msm_community_mib, msm_framework_mib, - msm_target_mib, msm_notification_mib, - msm_view_based_acm_mib, msm_sparse_table, msm_me_of, - msm_mib_of]. - -mse_size_check_cases() -> -[mse_size_check]. - -msd_size_check_cases() -> -[msd_size_check]. - -msm_size_check_cases() -> -[msm_size_check]. - -varm_mib_storage_dets_cases() -> -[msd_varm_mib_start]. - -varm_mib_storage_mnesia_cases() -> -[msm_varm_mib_start]. - -init_mib_storage_ets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,ets}, - init_ms(Config, [MibStorage]). - -init_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - init_ms(Config, [MibStorage]). - -init_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - init_ms(Config, [MibStorage]). - -init_ms(Config, Opts) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts], - [{vsn, v1} | start_v1_agent(Config,Opts1)]. - -init_size_check_mse(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, ets}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msd(Config) when list(Config) -> - AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage, {dets, AgentDir}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msm(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, {mnesia,[]}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_ms(Config, Opts) when list(Config) -> - SaNode = ?GCONF(snmp_sa, Config), - %% We are using v3 here, so crypto must be supported or else... - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - create_tables(SaNode), - AgentDir = ?GCONF(agent_dir, Config), - MgrDir = ?GCONF(mgr_dir, Config), - Ip = ?GCONF(ip, Config), - ?line ok = - config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_agent(Config, [v3], Opts)]. - -init_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_dets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -init_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_mnesia -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -finish_mib_storage_ets(Config) when list(Config) -> - ?LOG("finish_mib_storage_ets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_mib_storage_dets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_dets -> entry", []), - delete_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_size_check_mse(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msd(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msm(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_ms(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%% These are just interface functions to fool the test server -mse_simple(X) -> simple(X). -mse_v1_processing(X) -> v1_processing(X). -mse_big(X) -> big(X). -mse_big2(X) -> big2(X). -mse_loop_mib(X) -> loop_mib(X). -mse_api(X) -> api(X). -mse_sa_register(X) -> sa_register(X). -mse_v1_trap(X) -> v1_trap(X). -mse_sa_error(X) -> sa_error(X). -mse_next_across_sa(X) -> next_across_sa(X). -mse_undo(X) -> undo(X). -mse_standard_mib(X) -> snmp_standard_mib(X). -mse_community_mib(X) -> snmp_community_mib(X). -mse_framework_mib(X) -> snmp_framework_mib(X). -mse_target_mib(X) -> snmp_target_mib(X). -mse_notification_mib(X) -> snmp_notification_mib(X). -mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -mse_sparse_table(X) -> sparse_table(X). -mse_me_of(X) -> ms_me_of(X). -mse_mib_of(X) -> ms_mib_of(X). - -msd_simple(X) -> simple(X). -msd_v1_processing(X) -> v1_processing(X). -msd_big(X) -> big(X). -msd_big2(X) -> big2(X). -msd_loop_mib(X) -> loop_mib(X). -msd_api(X) -> api(X). -msd_sa_register(X) -> sa_register(X). -msd_v1_trap(X) -> v1_trap(X). -msd_sa_error(X) -> sa_error(X). -msd_next_across_sa(X) -> next_across_sa(X). -msd_undo(X) -> undo(X). -msd_standard_mib(X) -> snmp_standard_mib(X). -msd_community_mib(X) -> snmp_community_mib(X). -msd_framework_mib(X) -> snmp_framework_mib(X). -msd_target_mib(X) -> snmp_target_mib(X). -msd_notification_mib(X) -> snmp_notification_mib(X). -msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msd_sparse_table(X) -> sparse_table(X). -msd_me_of(X) -> ms_me_of(X). -msd_mib_of(X) -> ms_mib_of(X). - -msm_simple(X) -> simple(X). -msm_v1_processing(X) -> v1_processing(X). -msm_big(X) -> big(X). -msm_big2(X) -> big2(X). -msm_loop_mib(X) -> loop_mib(X). -msm_api(X) -> api(X). -msm_sa_register(X) -> sa_register(X). -msm_v1_trap(X) -> v1_trap(X). -msm_sa_error(X) -> sa_error(X). -msm_next_across_sa(X) -> next_across_sa(X). -msm_undo(X) -> undo(X). -msm_standard_mib(X) -> snmp_standard_mib(X). -msm_community_mib(X) -> snmp_community_mib(X). -msm_framework_mib(X) -> snmp_framework_mib(X). -msm_target_mib(X) -> snmp_target_mib(X). -msm_notification_mib(X) -> snmp_notification_mib(X). -msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msm_sparse_table(X) -> sparse_table(X). -msm_me_of(X) -> ms_me_of(X). -msm_mib_of(X) -> ms_mib_of(X). - - -mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X). -msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X). -msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X). - -msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X). -msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X). - -ms_size_check(suite) -> []; -ms_size_check(Config) when list(Config) -> - p("ms_size_check..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?LOG("mib server size check...", []), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - - -varm_mib_start(suite) -> []; -varm_mib_start(Config) when list(Config) -> - p("varm_mib_start..."), - ?LOG("varm_mib_start -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - %% Start the agent - Opts = ?GCONF(agent_opts, Config), - Config1 = start_v1_agent(Config, Opts), - - %% Sleep some in order for the agent to start properly - ?DBG("varm_mib_start -> sleep some (before loading mobs)", []), - ?SLEEP(5000), - - %% Load all the mibs - HardwiredMibs = loaded_mibs(), - ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - - %% Unload the hardwired mibs - ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), - ?SLEEP(1000), - ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired - - ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), - ?SLEEP(1000), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - Config2 = stop_agent(Config1), - - %% Sleep some in order for the agent to stop properly - ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []), - ?SLEEP(5000), - - %% Start the agent (again) - ?DBG("varm_mib_start -> start the agent", []), - Config3 = start_v1_agent(Config2, Opts), - - ?DBG("varm_mib_start -> sleep some (before starting tests)", []), - ?SLEEP(5000), - - %% Perform the test(s) - ?DBG("varm_mib_start -> perform the tests", []), - try_test(snmp_community_mib), - try_test(snmp_framework_mib), - try_test(snmp_target_mib), - try_test(snmp_notification_mib), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - stop_agent(Config3), - ok. - - --define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]). --define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). --define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -ms_me_of(suite) -> []; -ms_me_of(Config) when list(Config) -> - p("ms_me_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -me_of(Oid) -> - case snmpa:me_of(Oid) of - {ok, #me{oid = Oid}} -> - ok; - {ok, #me{oid = OtherOid}} -> - case lists:reverse(Oid) of - [0|Rest] -> - case lists:reverse(Rest) of - OtherOid -> - ok; - AnotherOid -> - {error, {invalid_oid, Oid, AnotherOid}} - end; - _ -> - {error, {invalid_oid, Oid, OtherOid}} - end; - {error, Reason} -> - {error, Reason}; - Else -> - {error, Else} - end. - - -ms_mib_of(suite) -> []; -ms_mib_of(Config) when list(Config) -> - p("ms_mib_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, - 'SNMP-USER-BASED-SM-MIB'), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -mib_of(Oid, ExpectedMibName) -> - ?DBG("mib_of -> entry with" - "~n Oid: ~p" - "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]), - %% case snmpa:mib_of(Oid) of - MibOf = snmpa:mib_of(Oid), - ?DBG("mib_of -> MibOf: ~n~p", [MibOf]), - case MibOf of - {ok, ExpectedMibName} -> - ok; - {ok, OtherMibName} -> - {error, {invalid_mib, ExpectedMibName, OtherMibName}}; - {error, Reason} -> - {error, Reason}; - Else -> - ?DBG("mib_of -> Else: ~n~p", [Else]), - {error, Else} - end. - - -app_info(suite) -> []; -app_info(Config) when list(Config) -> - SnmpDir = app_dir(snmp), - SslDir = app_dir(ssl), - CryptoDir = app_dir(crypto), - Attr = snmp:module_info(attributes), - AppVsn = - case lists:keysearch(app_vsn, 1, Attr) of - {value, {app_vsn, V}} -> - V; - false -> - "undefined" - end, - io:format("Root dir: ~s~n" - "SNMP: Application dir: ~s~n" - " Application ver: ~s~n" - "SSL: Application dir: ~s~n" - "CRYPTO: Application dir: ~s~n", - [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]), - ok. - -app_dir(App) -> - case code:lib_dir(App) of - D when list(D) -> - filename:basename(D); - {error, _Reason} -> - "undefined" - end. - - - -%v1_cases() -> [loop_mib]; -v1_cases() -> -[simple, db_notify_client, v1_processing, big, big2, - loop_mib, api, subagent, mnesia, {group, multiple_reqs}, - sa_register, v1_trap, sa_error, next_across_sa, undo, - {group, reported_bugs}, {group, standard_mibs}, - sparse_table, cnt_64, opaque, change_target_addr_config]. - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v2_cases() -> [loop_mib_2]; -v2_cases() -> -[simple_2, v2_processing, big_2, big2_2, loop_mib_2, - api_2, subagent_2, mnesia_2, {group, multiple_reqs_2}, - sa_register_2, v2_trap, {group, v2_inform}, sa_error_2, - next_across_sa_2, undo_2, {group, reported_bugs_2}, - {group, standard_mibs_2}, v2_types, implied, - sparse_table_2, cnt_64_2, opaque_2, v2_caps]. - -init_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_v2_agent(Config)]. - -finish_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -v1_v2_cases() -> -[simple_bi]. - -init_v1_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, bilingual} | start_bilingual_agent(Config)]. - -finish_v1_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v3_cases() -> [loop_mib_3]; -v3_cases() -> -[simple_3, v3_processing, big_3, big2_3, api_3, - subagent_3, mnesia_3, loop_mib_3, multiple_reqs_3, - sa_register_3, v3_trap, v3_inform, sa_error_3, - next_across_sa_3, undo_3, {group, reported_bugs_3}, - {group, standard_mibs_3}, {group, v3_security}, - v2_types_3, implied_3, sparse_table_3, cnt_64_3, - opaque_3, v2_caps_3]. - -init_v3(Config) when list(Config) -> - %% Make sure crypto works, otherwise start_agent will fail - %% and we will be stuck with a bunch of mnesia tables for - %% the rest of this suite... - ?DBG("start_agent -> start crypto app",[]), - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. - -finish_v3(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -mt_cases() -> -[multi_threaded, mt_trap]. - -init_mt(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. - -finish_mt(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -%% This one *must* be run first in each case. -init_case(Config) when list(Config) -> - ?DBG("init_case -> entry with" - "~n Config: ~p", [Config]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - MasterNode = node(), - - SaHost = ?HOSTNAME(SaNode), - MgrHost = ?HOSTNAME(MgrNode), - MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), - - - put(mgr_node, MgrNode), - put(sa_node, SaNode), - put(master_node, MasterNode), - put(sa_host, SaHost), - put(mgr_host, MgrHost), - put(master_host, MasterHost), - put(mip, tuple_to_list(MIP)), - put(masterip , tuple_to_list(MasterIP)), - put(sip, tuple_to_list(SIP)), - - MibDir = ?config(mib_dir, Config), - put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - put(std_mib_dir, StdM), - - MgrDir = ?config(mgr_dir, Config), - put(mgr_dir, MgrDir), - - put(vsn, ?config(vsn, Config)), - ?DBG("init_case -> exit with" - "~n MasterNode: ~p" - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]), - {SaNode, MgrNode, MibDir}. - -load_master(Mib) -> - ?DBG("load_master -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). - -load_master_std(Mib) -> - ?DBG("load_master_std -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). - -unload_master(Mib) -> - ?DBG("unload_master -> entry with" - "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). - -loaded_mibs() -> - ?DBG("loaded_mibs -> entry",[]), - Info = snmpa:info(snmp_master_agent), - {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info), - [atom_to_list(Mib) || {Mib,_,_} <- Mibs]. - -unload_mibs(Mibs) -> - ?DBG("unload_mibs -> entry with" - "~n Mibs: ~p", [Mibs]), - ok = snmpa:unload_mibs(snmp_master_agent, Mibs). - -start_subagent(SaNode, RegTree, Mib) -> - ?DBG("start_subagent -> entry with" - "~n SaNode: ~p" - "~n RegTree: ~p" - "~n Mib: ~p", [SaNode, RegTree, Mib]), - MA = whereis(snmp_master_agent), - ?DBG("start_subagent -> MA: ~p", [MA]), - MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), - %% BMK BMK -% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of - case rpc:call(SaNode, snmpa_supervisor, - start_sub_agent, [MA, RegTree, [Mib1]]) of - {ok, SA} -> - ?DBG("start_subagent -> SA: ~p", [SA]), - {ok, SA}; - Error -> - ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]}) - end. - -stop_subagent(SA) -> - ?DBG("stop_subagent -> entry with" - "~n SA: ~p", [SA]), - %% BNK BMK - %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]). - rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]). - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - - -simple(suite) -> []; -simple(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(simple_standard_test). - -simple_2(X) -> simple(X). - -simple_bi(suite) -> []; -simple_bi(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(vsn, v1), % First, try v1 manager - try_test(simple_standard_test), - - put(vsn, v2), % Then, try v2 manager - try_test(simple_standard_test). - -simple_3(X) -> - simple(X). - -big(suite) -> []; -big(Config) when list(Config) -> - ?DBG("big -> entry", []), - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -big_2(X) -> big(X). - -big_3(X) -> big(X). - - -big2(suite) -> []; -big2(Config) when list(Config) -> - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - -big2_2(X) -> big2(X). - -big2_3(X) -> big2(X). - - -multi_threaded(suite) -> []; -multi_threaded(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(multi_threaded_test), - ?line unload_master("Test1"). - -mt_trap(suite) -> []; -mt_trap(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). - -v2_types(suite) -> []; -v2_types(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(types_v2_test), - ?line unload_master("Test1"). - -v2_types_3(X) -> v2_types(X). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(implied_test,[MA]), - ?line unload_master("Test1"). - -implied_3(X) -> implied(X). - - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(sparse_table_test), - ?line unload_master("Test1"). - -sparse_table_2(X) -> sparse_table(X). - -sparse_table_3(X) -> sparse_table(X). - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -cnt_64_2(X) -> cnt_64(X). - -cnt_64_3(X) -> cnt_64(X). - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(opaque_test), - ?line unload_master("Test1"). - -opaque_2(X) -> opaque(X). - -opaque_3(X) -> opaque(X). - - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - try_test(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -api(suite) -> []; -api(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -api_2(X) -> api(X). - -api_3(X) -> api(X). - - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - try_test(load_test_sa), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - - p("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - try_test(load_test), - - p("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - try_test(unreg_test), - p("Testing register subagent..."), - rpc:call(SaNode, snmp, register_subagent, - [MA, ?klas1, SA]), - try_test(load_test_sa), - - ?line stop_subagent(SA), - try_test(unreg_test). - -subagent_2(X) -> subagent(X). - -subagent_3(X) -> subagent(X). - - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - try_test(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - -mnesia_2(X) -> mnesia(X). - -mnesia_3(X) -> mnesia(X). - - - -mul_cases() -> -[mul_get, mul_get_err, mul_next, mul_next_err, - mul_set_err]. - - -multiple_reqs_3(_X) -> - {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}. - - -mul_cases_2() -> -[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, - mul_set_err_2]. - - -mul_cases_3() -> - [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3]. - - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - try_test(do_mul_get). - -mul_get_2(X) -> mul_get(X). - -mul_get_3(X) -> mul_get(X). - - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - try_test(do_mul_get_err). - -mul_get_err_2(X) -> mul_get_err(X). - -mul_get_err_3(X) -> mul_get_err(X). - - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next). - -mul_next_2(X) -> mul_next(X). - -mul_next_3(X) -> mul_next(X). - - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next_err). - -mul_next_err_2(X) -> mul_next_err(X). - -mul_next_err_3(X) -> mul_next_err(X). - - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set..."), - try_test(do_mul_set). - -mul_set_2(X) -> mul_set(X). - -mul_set_3(X) -> mul_set(X). - - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set with error..."), - try_test(do_mul_set_err). - -mul_set_err_2(X) -> mul_set_err(X). - -mul_set_err_3(X) -> mul_set_err(X). - - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?DBG("sa_register -> entry", []), - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - p("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - try_test(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -sa_register_2(X) -> sa_register(X). - -sa_register_3(X) -> sa_register(X). - - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_trap1, [MA]), - try_test(ma_trap2, [MA]), - try_test(ma_v2_2_v1_trap, [MA]), - try_test(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - try_test(sa_trap1, [SA]), - try_test(sa_trap2, [SA]), - try_test(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v2_trap(suite) -> []; -v2_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - - try_test(ma_v2_trap1, [MA]), - try_test(ma_v2_trap2, [MA]), - try_test(ma_v1_2_v2_trap, [MA]), - try_test(ma_v1_2_v2_trap2, [MA]), - - try_test(sa_mib), - p("Testing trap sending from subagent..."), - try_test(sa_v1_2_v2_trap1, [SA]), - try_test(sa_v1_2_v2_trap2, [SA]), - try_test(sa_v1_2_v2_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v3_trap(X) -> - v2_trap(X). - - -v3_inform(_X) -> - %% v2_inform(X). - {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}. - -init_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -init_v3_inform(X) -> - init_v2_inform(X). - -finish_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -finish_v3_inform(X) -> - finish_v2_inform(X). - - - -v2_inform_i(suite) -> []; -v2_inform_i(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing inform sending from master agent... NOTE! This test\ntakes a " - "few minutes (5) to complete."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_v2_inform1, [MA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"). - -v3_inform_i(X) -> v2_inform_i(X). - - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - try_test(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - try_test(sa_errs_gen_err), - - p("Testing too big..."), - try_test(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -sa_error_2(X) -> sa_error(X). - -sa_error_3(X) -> sa_error(X). - - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - try_test(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - try_test(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - try_test(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -next_across_sa_2(X) -> next_across_sa(X). - -next_across_sa_3(X) -> next_across_sa(X). - - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - try_test(undo_test), - try_test(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - try_test(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - try_test(undo_test), - try_test(api_test3), - - p("Testing undo phase across master/subagents..."), - try_test(undo_test), - try_test(api_test3), - stop_subagent(SA). - -undo_2(X) -> undo(X). - -undo_3(X) -> undo(X). - -%% Req. Test2 -v1_processing(suite) -> []; -v1_processing(Config) when list(Config) -> - ?DBG("v1_processing -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v1_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v2_processing(suite) -> []; -v2_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v3_processing(suite) -> []; -v3_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), % same as v2! - ?line unload_master("Test2"). - - -%% We'll try get/set/trap and inform for all the auth & priv protocols. -%% For informs, the mgr is auth-engine. The agent has to sync. This is -%% accomplished by the first inform sent. That one will generate a -%% report, which makes it in sync. The notification-generating -%% application times out, and send again. This time it'll work. - -v3_crypto_basic(suite) -> []; -v3_crypto_basic(_Config) -> - EID = [0,0,0,0,0,0,0,0,0,0,0,2], - %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, - 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = - KMd5_1, - %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, - 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = - KSHA_1, - %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, - 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = - snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, - 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, - 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - KSHA_1t = lists:sublist(KSHA_1, 16), - KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, - 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - - %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), - ok. - - - -v3_md5_auth(suite) -> []; -v3_md5_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing MD5 authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authMD5"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_sha_auth(suite) -> []; -v3_sha_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing SHA authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authSHA"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_des_priv(suite) -> []; -v3_des_priv(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing DES encryption...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -%% Make sure mgr is in sync with agent -v3_sync(Funcs) -> - ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]), - g([[sysDescr, 0]]), - expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]), - g([[sysDescr, 0]]), - expect(433, [{[sysDescr,0], any}]), - lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs). - -v3_inform_sync(MA) -> - ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, - "standard inform", []), - %% Make sure agent is in sync with mgr... - ?DBG("v3_sync -> wait some time: ",[]), - sleep(20000), % more than 1500*10 in target_addr.conf - ?DBG("v3_sync -> await response",[]), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]). - - -v2_caps(suite) -> []; -v2_caps(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(v2_caps_i, [node()]). - -v2_caps_3(X) -> v2_caps(X). - - -v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]), - g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]}, - {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmp, del_agent_caps, [Idx]), - g([[sysORID, Idx]]), - ?line expect(2, [{[sysORID, Idx], noSuchInstance}]). - - -%% Req. Test2 -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - - -v1_get_p() -> - %% 4.1.2:1 - g([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - g([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - g([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - g([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - g([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - g([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - g([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - g([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - g([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - g([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - - -v1_get_next_p() -> - %% 4.1.3:1 - gn([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - gn([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - gn([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), -% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - gn([[tGenErr1]]), -% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - gn([[tGenErr2]]), -% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - gn([[sysDescr], [tGenErr3]]), -% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, -% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - s([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - s([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - s([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - s([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: -% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - s([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - -%% Req. Test2 -v2_proc() -> - %% According to RFC1905. - %% Template:
    : - ?DBG("v2_proc -> entry",[]), - v2_get_p(), - v2_get_next_p(), - v2_get_bulk_p(), - v2_set_p(). - -v2_get_p() -> - %% 4.2.1:2 - ?DBG("v2_get_p -> entry",[]), - g([[test2]]), - ?line expect(10, [{[test2], noSuchObject}]), - g([[tDescr]]), - ?line expect(11, [{[tDescr], noSuchObject}]), - g([[tDescr4,0]]), - ?line expect(12, [{[tDescr4,0], noSuchObject}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}, - {[tDescr,0], noSuchObject}]), - g([[tTable]]), - ?line expect(14, [{[tTable], noSuchObject}]), - g([[tEntry]]), - ?line expect(15, [{[tEntry], noSuchObject}]), - - %% 4.2.1:3 - g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line expect(20, [{[tDescr2,0], noSuchInstance}]), - g([[tDescr3,0]]), - ?line expect(21, [{[tDescr3,0], noSuchInstance}]), - g([[sysDescr,3]]), - ?line expect(22, [{[sysDescr, 3], noSuchInstance}]), - g([[tIndex,1]]), - ?line expect(23, [{[tIndex, 1], noSuchInstance}]), - - %% 4.2.1 - any other error: genErr - g([[tGenErr1, 0]]), - ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]), - - %% 4.2.1 - tooBig - g([[tTooBig, 0]]), - ?line expect(40, tooBig, 0, []). - - -v2_get_next_p() -> - %% 4.2.2:2 - ?DBG("v2_get_next_p -> entry",[]), - gn([[1,3,7,1]]), - ?line expect(10, [{[1,3,7,1], endOfMibView}]), - gn([[sysDescr], [1,3,7,1]]), - ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gn([[tCnt2, 1]]), - ?line expect(12, [{[tCnt2,2], 100}]), - gn([[tCnt2, 2]]), - ?line expect(12, [{[tCnt2,2], endOfMibView}]), - - %% 4.2.2 - any other error: genErr - gn([[tGenErr1]]), - ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]), - gn([[tGenErr2]]), - ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]), - gn([[sysDescr], [tGenErr3]]), - ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'}, - {[tGenErr3], 'NULL'}]), - - %% 4.2.2 - tooBig - gn([[tTooBig]]), - ?line expect(20, tooBig, 0, []). - -v2_get_bulk_p() -> - %% 4.2.3 - ?DBG("v2_get_bulk_p -> entry",[]), - gb(1, 1, []), - ?line expect(10, []), - gb(-1, 1, []), - ?line expect(11, []), - gb(-1, -1, []), - ?line expect(12, []), - gb(-1, -1, []), - ?line expect(13, []), - gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[sysDescr, 0], "Erlang SNMP agent"}]), - - gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line expect(19, []), - - gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'}, - {[sysObjectID], 'NULL'}, - {[tGenErr1], 'NULL'}, - {[sysDescr], 'NULL'}]), - gb(0, 2, [[tCnt2, 1]]), - ?line expect(21, [{[tCnt2,2], 100}, - {[tCnt2,2], endOfMibView}]). - - -v2_set_p() -> - %% 4.2.5:1 - ?DBG("v2_set_p -> entry",[]), - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]), - - %% 4.2.5:2 - s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), - - %% 4.2.5:3 - s([{[tDescr2, 0], i, 4}]), - ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.2.5:4 - s([{[tStr, 0], s, ""}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]), - s([{[tStr, 0], s, "12345"}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]), - - %% 4.2.5:5 - N/A - - %% 4.2.5:6 - s([{[tInt1, 0], i, 0}]), - ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]), - s([{[tInt1, 0], i, 5}]), - ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]), - s([{[tInt2, 0], i, 0}]), - ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]), - s([{[tInt2, 0], i, 5}]), - ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]), - s([{[tInt3, 0], i, 5}]), - ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]), - - %% 4.2.5:7 - s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), - - %% 4.2.5:8 - s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line expect(80, inconsistentName, 1, - [{[tDescrX, 1, 2], "inconsistentName"}]), - - %% 4.2.5:9 - s([{[tCnt, 1, 2], i, 5}]), - ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]), - - %% 4.2.5:10 - s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line expect(100, inconsistentValue, 1, - [{[tDescr2,0], "inconsistentValue"}]), - - %% 4.2.5:11 - s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line expect(110, resourceUnavailable, 1, - [{[tDescr2,0],"resourceUnavailable"}]), - - %% 4.2.5:12 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). - - %% commitFailed and undoFailed is tested by the 'undo' case. - - -%% Req. OLD-SNMPEA-MIB -table_test() -> - io:format("Testing simple get, next and set on communityTable...~n"), -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. - Key1c3 = [intCommunityViewIndex,get(mip),is("public")], - Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")], - Key1c4 = [intCommunityAccess,get(mip),is("public")], - EndKey = [intCommunityEntry,[9],get(mip),is("public")], - gn([[intCommunityEntry]]), - ?line expect(7, [{Key1c3, 2}]), - gn([[intCommunityTable]]), - ?line expect(71, [{Key1c3, 2}]), - gn([[community]]), - ?line expect(72, [{Key1c3, 2}]), - gn([[otpSnmpeaMIB]]), - ?line expect(73, [{Key1c3, 2}]), - gn([[ericsson]]), - ?line expect(74, [{Key1c3, 2}]), - gn([Key1c3]), - ?line expect(8, [{Key2c3, 2}]), - gn([Key2c3]), - ?line expect(9, [{Key1c4, 2}]), - gn([EndKey]), - AgentIp = [intAgentIpAddress,0], - ?line expect(10, [{AgentIp, any}]), - g([Key1c3]), - ?line expect(11, [{Key1c3, 2}]), - g([EndKey]), - ?line ?v1_2(expect(12, noSuchName, 1, any), - expect(12, [{EndKey, noSuchObject}])), - - io:format("Testing row creation/deletion on communityTable...~n"), - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - s([{NewKeyc5, ?createAndGo}]), - ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any), - s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), - g([NewKeyc4]), - ?line expect(16, [{NewKeyc4, 2}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(17, [{NewKeyc5, ?destroy}]), - s([{NewKeyc4, 2}]), - ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]), - s([{NewKeyc5, ?createAndWait}]), - ?line expect(19, [{NewKeyc5, ?createAndWait}]), - g([NewKeyc5]), - ?line expect(20, [{NewKeyc5, ?notReady}]), - s([{NewKeyc4, 2}]), - ?line expect(21, [{NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(22, [{NewKeyc5, ?notReady}]), - s([{NewKeyc3, 2}]), - ?line expect(23, [{NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(24, [{NewKeyc5, ?notInService}]), - s([{NewKeyc5, ?active}]), - ?line expect(25, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(26, [{NewKeyc5, ?destroy}]), - s([{NewKeyc3, 3}]), - ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]), - otp_1128(). - -%% Req. system group -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - gn([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - g([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - gn([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - g([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - io:format("Testing noSuchName and badValue...~n"), - s([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - s([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - try_test(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - gn([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - g([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - s([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - s([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - g([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - gn([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - s([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - gn([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - p("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - gn([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - g([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - s([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - g([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - p("Testing next from last object in master to subagent (2)..."), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - p("Adding one row in subagent table (2)"), - _FTab = [friendsEntry2], - s([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - g([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - p("Adding two rows in subagent table with special INDEX (2)"), - s([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - g([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - gn([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - s([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - gn([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - -%% Req. Test1 -multi_threaded_test() -> - p("Testing multi threaded agent..."), - g([[multiStr,0]]), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(1, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "pelle"}]), - ?line expect(2, [{[sysLocation, 0], "pelle"}]), - Pid ! continue, - ?line expect(3, [{[multiStr,0], "ok"}]), - - s([{[multiStr, 0], s, "block"}]), - Pid2 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(4, [{[sysUpTime,0], any}]), - g([[multiStr,0]]), - Pid3 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(5, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "kalle"}]), - Pid3 ! continue, - ?line expect(6, [{[multiStr,0], "ok"}]), - Pid2 ! continue, - ?line expect(7, [{[multiStr,0], "block"}]), - ?line expect(8, [{[sysLocation,0], "kalle"}]). - -%% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - snmpa:send_trap(MA, mtTrap, "standard trap"), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(2, [{[sysUpTime,0], any}]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - Pid ! continue, - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]). - - -get_multi_pid() -> - get_multi_pid(10). -get_multi_pid(0) -> - ?line ?FAIL(no_global_name); -get_multi_pid(N) -> - sleep(1000), - case global:whereis_name(snmp_multi_tester) of - Pid when pid(Pid) -> Pid; - _ -> get_multi_pid(N-1) - end. - -%% Req. Test1 -types_v2_test() -> - p("Testing v2 types..."), - - s([{[bits1,0], 2#10}]), - ?line expect(1, [{[bits1,0], ?str(2#10)}]), - g([[bits1,0]]), - ?line expect(2, [{[bits1,0], ?str(2#101)}]), - - s([{[bits2,0], 2#11000000110}]), - ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]), - g([[bits2,0]]), - ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]), - - g([[bits3,0]]), - ?line expect(50, genErr, 1, any), - - g([[bits4,0]]), - ?line expect(51, genErr, 1, any), - - s([{[bits1,0], s, [2#10]}]), - ?line expect(6, ?v1_2(badValue, wrongValue), 1, any), - - s([{[bits2,0], 2#11001001101010011}]), - ?line expect(7, ?v1_2(badValue, wrongValue), 1, any). - - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - p("Testing IMPLIED..."), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - gn([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - gn([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr2)",[]), - gn([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - gn([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, - oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, - int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - -%% Req. Klas3 -api_test2() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]), - g([[fname4,0]]), - ?line expect(2, [{[fname4,0], 1}]). - -api_test3() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]). - - -unreg_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - -%% Req. Klas1 -load_test_sa() -> - gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -%% Note: This test case takes a while... actually a couple of minutes. -ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform -> entry with MA = ~p => " - "send notification: testTrapv22",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag1, self()}, - "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag1, [_]} -> - ok; - {snmp_targets, tag1, Addrs1} -> - ?line ?FAIL({bad_addrs, Addrs1}) - after - 5000 -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag1, {got_response, _}} -> - ok; - {snmp_notification, tag1, {no_response, _}} -> - ?line ?FAIL(no_response) - after - 20000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - - %% - %% -- The rest is possibly erroneous... - %% - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag2, self()}, - "standard inform", []), - ?line expect(2, {inform, false}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag2, [_]} -> - ok; - {snmp_targets, tag2, Addrs2} -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]), - ?line ?FAIL({bad_addrs, Addrs2}) - after - 5000 -> - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag2, {got_response, _}} -> - ?line ?FAIL(got_response); - {snmp_notification, tag2, {no_response, _}} -> - ok - after - 240000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag2) timeout",[]), - ?line ?FAIL(nothing_at_all) - end. - - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. -% it depends on which order the agent traverses the varbind list. -% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- - - - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - try_test(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = try_test(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - try_test(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = try_test(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - try_test(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - try_test(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - try_test(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - try_test(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - try_test(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - try_test(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - try_test(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]). - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v2 and v3. -%% o Test the counters and control objects in SNMPv2-MIB -%%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; -snmpv2_mib_2(Config) when list(Config) -> - ?LOG("snmpv2_mib_2 -> start",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?DBG("snmpv2_mib_2 -> standard mib init",[]), - try_test(std_mib_init), - - ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]), - InBadVsns = try_test(std_mib_a), - - ?DBG("snmpv2_mib_2 -> make a bad version read",[]), - put(vsn, v1), - try_test(std_mib_read), - - ?DBG("snmpv2_mib_2 -> bad version read",[]), - put(vsn, v2), - Bad = try_test(std_mib_b, [InBadVsns]), - - ?DBG("snmpv2_mib_2 -> read with bad community",[]), - try_test(std_mib_read, [], [{community, "bad community"}]), - - ?DBG("snmpv2_mib_2 -> write with public community",[]), - try_test(std_mib_write, [], [{community, "public"}]), - - ?DBG("snmpv2_mib_2 -> asn err",[]), - try_test(std_mib_asn_err), - - ?DBG("snmpv2_mib_2 -> check counters",[]), - try_test(std_mib_c, [Bad]), - - ?DBG("snmpv2_mib_2 -> get som counters",[]), - try_test(snmpv2_mib_a), - - ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), - try_test(std_mib_finish), - - ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, " - "then disable auth traps",[]), - try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]), - - ?LOG("snmpv2_mib_2 -> done",[]). - -%% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; -snmpv2_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - InBadVsns = try_test(std_mib_a), - put(vsn, v1), - try_test(std_mib_read), - put(vsn, v3), - _Bad = try_test(std_mib_b, [InBadVsns]), - try_test(snmpv2_mib_a), - - try_test(std_mib_finish). - --define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]). - -%% Req. SNMPv2-MIB -snmpv2_mib_test_finish() -> - %% force a authenticationFailure - ?DBG("ma_v2_inform -> write to std mib",[]), - std_mib_write(), - - %% check that we got a trap - ?DBG("ma_v2_inform -> await trap",[]), - ?line expect(2, v2trap, [{[sysUpTime,0], any}, - {[snmpTrapOID,0], ?authenticationFailure}]), - - %% and the the inform - ?DBG("ma_v2_inform -> await inform",[]), - ?line expect(2, {inform,true}, [{[sysUpTime,0], any}, - {[snmpTrapOID,0],?authenticationFailure}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - -%% Req. SNMPv2-MIB -snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), - s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), - s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, - [{[sysLocation, 0], "val3"}, - {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]). - - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - try_test(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - try_test(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -snmp_framework_mib_2(X) -> snmp_framework_mib(X). - -snmp_framework_mib_3(suite) -> []; -snmp_framework_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(snmp_framework_mib). - - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - -%%----------------------------------------------------------------- -%% o Test the counters -%%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; -snmp_mpd_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - UnknownPDUHs = try_test(snmp_mpd_mib_a), - try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]), - try_test(snmp_mpd_mib_c, [UnknownPDUHs]). - - -%% Req. SNMP-MPD-MIB -snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0]]), - Pdu = #pdu{type = 'get-request', - request_id = 23, - error_status = noError, - error_index = 0, - varbinds = []}, - SPdu = #scopedPdu{contextEngineID = "agentEngine", - contextName = "", - data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), - V3Hdr1 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [7], - msgSecurityModel = 23, % bad sec model - msgSecurityParameters = []}, - V3Hdr2 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [6], % bad flag combination - msgSecurityModel = 3, - msgSecurityParameters = []}, - Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1, - data = SPDUBytes}, - Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, - data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), - snmp_test_mgr:send_bytes(MsgBytes1), - snmp_test_mgr:send_bytes(MsgBytes2), - - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0], - [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, - UnknownPDUHs. - --define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). -snmp_mpd_mib_b() -> - g([[sysUpTime,0]]), - ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]). - - -snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1. - - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - try_test(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib_2(X) -> snmp_target_mib(X). - -snmp_target_mib_3(X) -> snmp_target_mib(X). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - try_test(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib_2(X) -> snmp_notification_mib(X). - -snmp_notification_mib_3(X) -> snmp_notification_mib(X). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line try_test(do_set, [ARow2]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [ARow2Status]), - - - %% Add valid row - ?line try_test(do_set, [ARow1]), - - ?line try_test(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), - - %% We should still have access... - ?line try_test(use_rights, [], Opts), - - %% Delete rows - ?line try_test(del_row, [GRow1Status]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), - - ?line try_test(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - -mk_ln(X) -> - [length(X) | X]. - -%%----------------------------------------------------------------- -%% o add/delete users and try them -%% o test all secLevels -%% o test all combinations of protocols -%% o try bad ops; check counters -%%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; -snmp_user_based_sm_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - _AgentDir = ?config(agent_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - - %% The newUser used here already has VACM access. - - %% Add a new user in the simplest way; just createAndGo - try_test(v3_sync, [[{usm_add_user1, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new user - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), - DesKey1 = lists:sublist(ShaKey1, 16), - - %% Change the new user's keys - 1 - try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), - DesKey2 = lists:sublist(ShaKey2, 16), - - %% Change the new user's keys - 2 - ?line try_test(v3_sync, - [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Change the new user's keys - 3 - ?line try_test(v3_sync, - [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("SNMP-USER-BASED-SM-MIB"). - --define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). - -usm_add_user1() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - -usm_use_user() -> - v2_proc(). - - -%% Change own public keys -usm_key_change1(ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_shaxxxxxxxxxx", - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_desxxxxxx", - DesKey), - Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change own private keys -usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change other's public keys -usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], - s(Vbs1), - ?line expect(1, noAccess, 1, any), - Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs2), - ?line expect(2, noAccess, 1, any), - - - Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs3), - ?line expect(1, Vbs3). - -usm_read() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], - [usmUserCloneFrom, NewRowIndex], - [usmUserAuthKeyChange, NewRowIndex], - [usmUserOwnAuthKeyChange, NewRowIndex], - [usmUserPrivKeyChange, NewRowIndex], - [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line expect(1, - [{[usmUserSecurityName, NewRowIndex], "newUser"}, - {[usmUserCloneFrom, NewRowIndex], [0,0]}, - {[usmUserAuthKeyChange, NewRowIndex], ""}, - {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, - {[usmUserPrivKeyChange, NewRowIndex], ""}, - {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]), - ok. - - - -usm_del_user() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - --define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). - --define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]). - --define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]). - --define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]). - --define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]). - --define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]). - -usm_bad() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, inconsistentName, 1, any), - - RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line expect(2, wrongValue, 1, any), - - RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line expect(3, Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line expect(4, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line expect(5, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line expect(6, wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line expect(7, wrongValue, 1, any), - - Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line expect(1, Vbs4), - - ok. - - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?LOG("loop_mib -> initiate case",[]), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - try_test(loop_mib_1), - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - - -loop_mib_2(suite) -> []; -loop_mib_2(Config) when list(Config) -> - ?LOG("loop_mib_2 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_2 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?LOG("loop_mib_2 -> done",[]). - - -loop_mib_3(suite) -> []; -loop_mib_3(Config) when list(Config) -> - ?LOG("loop_mib_3 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_3 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?LOG("loop_mib_3 -> done",[]). - - -%% Req. As many mibs all possible -loop_mib_1() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_1([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_1(Oid, N) -> - ?DBG("loop_it_1 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_1 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_1(NOid, N+1); - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it_1 -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - end. - -%% Req. As many mibs all possible -loop_mib_2() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_2([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_2(Oid, N) -> - ?DBG("loop_it_2 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid, value = endOfMibView}]} -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p",[NOid]), - N; - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_2 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_2(NOid, N+1) - end. - - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - - - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128_2(X) -> otp_1128(X). - -otp_1128_3(X) -> otp_1128(X). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_2(X) -> otp_1129(X). - -otp_1129_3(X) -> otp_1129(X). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - try_test(otp_1131), - ?line unload_master("Klas1"). - -otp_1131_2(X) -> otp_1131(X). - -otp_1131_3(X) -> otp_1131(X). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - try_test(otp_1162), - stop_subagent(SA). - -otp_1162_2(X) -> otp_1162(X). - -otp_1162_3(X) -> otp_1162(X). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - try_test(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222_2(X) -> otp_1222(X). - -otp_1222_3(X) -> otp_1222(X). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1298), - ?line unload_master("Klas2"). - -otp_1298_2(X) -> otp_1298(X). - -otp_1298_3(X) -> otp_1298(X). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331_2(X) -> otp_1331(X). - -otp_1331_3(X) -> otp_1331(X). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1338), - ?line unload_master("Klas2"). - -otp_1338_2(X) -> otp_1338(X). - -otp_1338_3(X) -> otp_1338(X). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas4"), - try_test(otp_1342), - ?line unload_master("Klas4"). - -otp_1342_2(X) -> otp_1342(X). - -otp_1342_3(X) -> otp_1342(X). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366_2(X) -> otp_1366(X). - -otp_1366_3(X) -> otp_1366(X). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_2776). - -otp_2776_2(X) -> otp_2776(X). - -otp_2776_3(X) -> otp_2776(X). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Test1"), - ?line init_old(), - try_test(otp_2979), - ?line unload_master("Test1"). - -otp_2979_2(X) -> otp_2979(X). - -otp_2979_3(X) -> otp_2979(X). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187_2(X) -> otp_3187(X). - -otp_3187_3(X) -> otp_3187(X). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - - - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - - - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?DBG("otp_4394_test -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -%%%-------------------------------------------------- -%%% Used to test the standard mib with our -%%% configuration. -%%%-------------------------------------------------- -run(F, A, Opts) -> - M = get(mib_dir), - Dir = get(mgr_dir), - User = snmp_misc:get_option(user, Opts, "all-rights"), - SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv), - EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"), - CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), - Community = snmp_misc:get_option(community, Opts, "all-rights"), - ?DBG("run -> start crypto app",[]), - Crypto = ?CRYPTO_START(), - ?DBG("run -> Crypto: ~p",[Crypto]), - catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - ?DBG("run -> config:~n" - "\tM: ~p~n" - "\tDir: ~p~n" - "\tUser: ~p~n" - "\tSecLevel: ~p~n" - "\tEngineID: ~p~n" - "\tCtxEngineID: ~p~n" - "\tCommunity: ~p~n" - "\tStdM: ~p", - [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]), - case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()}, - {packet_server_debug,true}, - {debug,true}, - {agent, get(master_host)}, - {agent_udp, 4000}, - {trap_udp, 5000}, - {recbuf,65535}, - quiet, - get(vsn), - {community, Community}, - {user, User}, - {sec_level, SecLevel}, - {engine_id, EngineID}, - {context_engine_id, CtxEngineID}, - {dir, Dir}, - {mibs, mibs(StdM, M)}]) of - {ok, _Pid} -> - Res = apply(?MODULE, F, A), - catch snmp_test_mgr:stop(), - Res; - Err -> - io:format("Error starting manager: ~p\n", [Err]), - catch snmp_test_mgr:stop(), - ?line exit({mgr_start, Err}) - end. - - -mibs(StdMibDir,MibDir) -> - [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")), - join(MibDir, "OLD-SNMPEA-MIB.bin"), - join(StdMibDir, "SNMP-FRAMEWORK-MIB"), - join(StdMibDir, "SNMP-MPD-MIB"), - join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"), - join(StdMibDir, "SNMP-USER-BASED-SM-MIB"), - join(StdMibDir, "SNMP-TARGET-MIB"), - join(StdMibDir, "SNMP-NOTIFICATION-MIB"), - join(MibDir, "Klas1.bin"), - join(MibDir, "Klas2.bin"), - join(MibDir, "Klas3.bin"), - join(MibDir, "Klas4.bin"), - join(MibDir, "SA-MIB.bin"), - join(MibDir, "TestTrap.bin"), - join(MibDir, "Test1.bin"), - join(MibDir, "Test2.bin"), - join(MibDir, "TestTrapv2.bin")]. - -join(D,F) -> - filename:join(D,F). - -%% string used in index -is(S) -> [length(S) | S]. - -try_test(Func) -> - call(get(mgr_node), ?MODULE, run, [Func, [], []]). - -try_test(Func, A) -> - call(get(mgr_node), ?MODULE, run, [Func, A, []]). - -try_test(Func, A, Opts) -> - call(get(mgr_node), ?MODULE, run, [Func, A, Opts]). - -call(N,M,F,A) -> - ?DBG("call -> entry with~n" - " N: ~p~n" - " M: ~p~n" - " F: ~p~n" - " A: ~p~n" - " when~n" - " get(): ~p", - [N,M,F,A,get()]), - spawn(N, ?MODULE, wait, [self(),get(),M,F,A]), - receive - {done, {'EXIT', Rn}, Loc} -> - ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]), - put(test_server_loc, Loc), - exit(Rn); - {done, Ret, Zed} -> - ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]), - Ret - end. - -wait(From, Env, M, F, A) -> - ?DBG("wait -> entry with ~n" - "\tFrom: ~p~n" - "\tEnv: ~p",[From,Env]), - lists:foreach(fun({K,V}) -> put(K,V) end, Env), - Rn = (catch apply(M, F, A)), - ?DBG("wait -> Rn: ~n~p", [Rn]), - From ! {done, Rn, get(test_server_loc)}, - exit(Rn). - -expect(A,B) -> ok = snmp_test_mgr:expect(A,B). -expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C). -expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F). - -get_req(Id, Vars) -> - ?DBG("get_req -> entry with~n" - "\tId: ~p~n" - "\tVars: ~p",[Id,Vars]), - g(Vars), - ?DBG("get_req -> await response",[]), - {ok, Val} = snmp_test_mgr:get_response(Id, Vars), - ?DBG("get_req -> response: ~p",[Val]), - Val. - -get_next_req(Vars) -> - ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]), - gn(Vars), - ?DBG("get_next_req -> await response",[]), - Response = snmp_test_mgr:receive_response(), - ?DBG("get_next_req -> response: ~p",[Response]), - Response. - - - -start_node(Name) -> - ?LOG("start_node -> entry with Name: ~p",[Name]), - M = list_to_atom(?HOSTNAME(node())), - ?DBG("start_node -> M: ~p",[M]), - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p",[Pa]), - - Args = case init:get_argument('CC_TEST') of - {ok, [[]]} -> - " -pa /clearcase/otp/libraries/snmp/ebin "; - {ok, [[Path]]} -> - " -pa " ++ Path; - error -> - "" - end, - %% Do not use start_link!!! (the proc that calls this one is tmp) - ?DBG("start_node -> Args: ~p~n",[Args]), - A = Args ++ " -pa " ++ Pa, - case (catch ?START_NODE(Name, A)) of - {ok, Node} -> - %% Tell the test_server to not clean up things it never started. - ?DBG("start_node -> Node: ~p",[Node]), - {ok, Node}; - Else -> - ?ERR("start_node -> failed with(other): Else: ~p",[Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?LOG("stop_node -> Node: ~p",[Node]), - rpc:cast(Node, erlang, halt, []). - -p(X) -> - io:format(user, X++"\n", []). - -sleep(X) -> - receive - after - X -> ok - end. - -%%%----------------------------------------------------------------- -%%% Configuration -%%%----------------------------------------------------------------- -config(Vsns, MgrDir, AgentDir, MIp, AIp) -> - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp, - ?TRAP_UDP, AIp, 4000, - "test"), - ?line case update_usm(Vsns, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); - false -> - ?line ok - end, - ?line update_community(Vsns, AgentDir), - ?line update_vacm(Vsns, AgentDir), - ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns), - ?line write_target_params_conf(AgentDir, Vsns), - ?line write_notify_conf(AgentDir), - ok. - -delete_files(Config) -> - Dir = ?config(agent_dir, Config), - {ok, List} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, - List). - -update_usm(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -update_usm_mgr(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - file:close(Fid). - -reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). - - -update_community([v3], _Dir) -> ok; -update_community(_, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n", - []), - file:close(Fid). - - --define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). -update_vacm(_Vsn, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]), - ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", " - "~w, excluded, null}.\n", [?tDescr_instance]), - file:close(Fid). - - -vacm_ver(v1) -> v1; -vacm_ver(v2) -> v2c; -vacm_ver(v3) -> usm. - - -write_community_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write), - ok = write_community_conf1(Fid, Confs), - file:close(Fid). - -write_community_conf1(_, []) -> - ok; -write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) -> - ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [ComIdx, ComName, SecName, CtxName, TransTag]), - write_community_conf1(Fid, Confs). - - -write_target_addr_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - ok = write_target_addr_conf1(Fid, Confs), - file:close(Fid). - - -write_target_addr_conf1(_, []) -> - ok; -write_target_addr_conf1(Fid, - [{Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz}|Confs]) -> - ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz]), - write_target_addr_conf1(Fid, Confs). - -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - lists:foreach(fun(Vsn) -> - ok = io:format(Fid, - "{\"~s\", ~w, ~w, 1500, 3, " - "\"std_trap\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, mk_param(Vsn)]), - case Vsn of - v1 -> ok; - v2 -> - ok = io:format(Fid, - "{\"~s.2\",~w,~w,1500,3, " - "\"std_inform\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]); - v3 -> - ok = io:format(Fid, - "{\"~s.3\",~w,~w,1500,3, " - "\"std_inform\", \"~s\", " - "\"mgrEngine\", [], 1024}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]) - end - end, - Vsns), - file:close(Fid). - -mk_param(v1) -> "target_v1"; -mk_param(v2) -> "target_v2"; -mk_param(v3) -> "target_v3". - -mk_ip([A,B,C,D], Vsn) -> - io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]). - - -rewrite_target_addr_conf(Dir,NewPort) -> - TAFile = filename:join(Dir, "target_addr.conf"), - ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]), - case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok - end, - - ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end), - - ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), - - NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs], - - ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - - ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs), - - file:close(Fid). - -rewrite_target_addr_conf1(O) -> - {ok,O}. - -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> - ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), - {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; -rewrite_target_addr_conf2(_NewPort,O) -> - ?LOG("rewrite_target_addr_conf2 -> entry with " - "~n O: ~p",[O]), - O. - - -rewrite_target_addr_conf3(_,[]) -> ok; -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry, - ParamName,EngineId}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % ParamsName - "\"~s\"}.", % EngineId - [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]), - rewrite_target_addr_conf3(Fid,T); -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList, - ParamName,EngineId,TMask,MMS}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % TagList - "\"~s\", " % ParamsName - "\"~s\"," % EngineId - "~p, " % TMask - "~p}.", % MMS - [Name,Ip,Port,Timeout,Retry,TagList,ParamName, - EngineId,TMask,MMS]), - rewrite_target_addr_conf3(Fid,T). - -reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_addr.old"), - filename:join(Dir,"target_addr.conf")). - -write_target_params_conf(Dir, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - lists:foreach(fun(Vsn) -> - MP = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> v3 - end, - SM = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> usm - end, - ok = io:format(Fid, "{\"target_~w\", ~w, ~w, " - "\"all-rights\", noAuthNoPriv}.~n", - [Vsn, MP, SM]) - end, - Vsns), - file:close(Fid). - -rewrite_target_params_conf(Dir, SecName, SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n", - [SecName, SecLevel]), - file:close(Fid). - -reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). - -write_notify_conf(Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write), - ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []), - ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []), - file:close(Fid). - -ver_to_trap_str([v1]) -> "v1"; -ver_to_trap_str([v2]) -> "v2"; -% default is to use the latest snmp version -ver_to_trap_str([v1,v2]) -> "v2". - - - -write_view_conf(Dir) -> - {ok, Fid} = file:open(a(Dir,"view.conf"),write), - ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []), - ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]), - file:close(Fid). - -a(A,B) -> lists:append(A,B). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -copy_file(From, To) -> - {ok, Bin} = file:read_file(From), - ok = file:write_file(To, Bin). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_memory_usage() -> - Info = snmpa:info(snmp_master_agent), - TreeSize = lists_key1search(tree_size_bytes, Info), - ProcMem = lists_key1search(process_memory, Info), - MibDbSize = lists_key1search([db_memory,mib], Info), - NodeDbSize = lists_key1search([db_memory,node], Info), - TreeDbSize = lists_key1search([db_memory,tree], Info), - ?INF("Memory usage: " - "~n Tree size: ~p" - "~n Process memory size: ~p" - "~n Mib db size: ~p" - "~n Node db size: ~p" - "~n Tree db size: ~p", - [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]). - -lists_key1search([], Res) -> - Res; -lists_key1search([Key|Keys], List) when atom(Key), list(List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - lists_key1search(Keys, Val); - false -> - undefined - end; -lists_key1search(Key, List) when atom(Key) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - Val; - false -> - undefined - end. - - -regs() -> - lists:sort(registered()). diff --git a/lib/snmp/test/exp/snmp_agent_v3_test.erl b/lib/snmp/test/exp/snmp_agent_v3_test.erl deleted file mode 100644 index 49f98b517875..000000000000 --- a/lib/snmp/test/exp/snmp_agent_v3_test.erl +++ /dev/null @@ -1,5635 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(snmp_agent_v3_test). - -%% TODO -%% * Test fault-tolerance (kill master etc) -%% - --compile(export_all). - --define(application, snmp). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). --include("snmp_test_lib.hrl"). --define(SNMP_USE_V3, true). --include_lib("snmp/include/snmp_types.hrl"). -%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl"). -%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl"). - - --define(klas1, [1,3,6,1,2,1,7]). --define(klas2, [1,3,6,1,2,1,9]). --define(klas3, [1,3,6,1,2,1,8,1]). --define(klas4, [1,3,6,1,2,1,8,4]). --define(sa, [1,3,6,1,4,1,193,2]). --define(system, [1,3,6,1,2,1,1]). --define(snmp, [1,3,6,1,2,1,11]). --define(snmpTraps, [1,3,6,1,6,3,1,1,5]). --define(ericsson, [1,3,6,1,4,1,193]). --define(testTrap, [1,3,6,1,2,1,15,0]). --define(xDescr, [1,3,6,1,2,1,17,1]). --define(xDescr2, [1,3,6,1,2,1,17,2]). - --define(active, 1). --define(notInService, 2). --define(notReady, 3). --define(createAndGo, 4). --define(createAndWait, 5). --define(destroy, 6). - --define(TRAP_UDP, 5000). - --define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"). - --define(str(X), snmp_pdus:bits_to_str(X)). - --define(break(), begin io:format(user, "break at line ~w: pid: ~p\n", - [?LINE, self()]), - receive cont -> ok end - end). - - --import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]). --define(v1_2(V1,V2), - case get(vsn) of - v1 -> V1; - _ -> V2 - end). - --define(v1_2_3(V1,V2,V3), - case get(vsn) of - v1 -> V1; - v2 -> V2; - _ -> V3 - end). - -all() -> -[cases()]. - -groups() -> - [{mib_storage, [], - [{group, mib_storage_ets}, {group, mib_storage_dets}, - {group, mib_storage_mnesia}, - {group, mib_storage_size_check_ets}, - {group, mib_storage_size_check_dets}, - {group, mib_storage_size_check_mnesia}, - {group, mib_storage_varm_dets}, - {group, mib_storage_varm_mnesia}]}, - {mib_storage_ets, [], mib_storage_ets_cases()}, - {mib_storage_dets, [], mib_storage_dets_cases()}, - {mib_storage_mnesia, [], mib_storage_mnesia_cases()}, - {mib_storage_size_check_ets, [], - mse_size_check_cases()}, - {mib_storage_size_check_dets, [], - msd_size_check_cases()}, - {mib_storage_size_check_mnesia, [], - msm_size_check_cases()}, - {mib_storage_varm_dets, [], - varm_mib_storage_dets_cases()}, - {mib_storage_varm_mnesia, [], - varm_mib_storage_mnesia_cases()}, - {test_v1, [], v1_cases()}, {test_v2, [], v2_cases()}, - {test_v1_v2, [], v1_v2_cases()}, - {test_v3, [], v3_cases()}, - {test_multi_threaded, [], mt_cases()}, - {multiple_reqs, [], mul_cases()}, - {multiple_reqs_2, [], mul_cases_2()}, - {v2_inform, [], [v2_inform_i]}, - {v3_security, [], - [v3_crypto_basic, v3_md5_auth, v3_sha_auth, - v3_des_priv]}, - {standard_mibs, [], - [snmp_standard_mib, snmp_community_mib, - snmp_framework_mib, snmp_target_mib, - snmp_notification_mib, snmp_view_based_acm_mib]}, - {standard_mibs_2, [], - [snmpv2_mib_2, snmp_community_mib_2, - snmp_framework_mib_2, snmp_target_mib_2, - snmp_notification_mib_2, snmp_view_based_acm_mib_2]}, - {standard_mibs_3, [], - [snmpv2_mib_3, snmp_framework_mib_3, snmp_mpd_mib_3, - snmp_target_mib_3, snmp_notification_mib_3, - snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3]}, - {reported_bugs, [], - [otp_1128, otp_1129, otp_1131, otp_1162, otp_1222, - otp_1298, otp_1331, otp_1338, otp_1342, otp_2776, - otp_2979, otp_3187, otp_3725]}, - {reported_bugs_2, [], - [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2, - otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2, - otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2]}, - {reported_bugs_3, [], - [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3, - otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3, - otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3, - otp_3542]}, - {tickets, [], [{group, otp_4394}]}, - {otp_4394, [], [otp_4394_test]}]. - -init_per_group(otp_4394, Config) -> - init_otp_4394(Config); -init_per_group(v2_inform, Config) -> - init_v2_inform(Config); -init_per_group(multiple_reqs_2, Config) -> - init_mul(Config); -init_per_group(multiple_reqs, Config) -> - init_mul(Config); -init_per_group(test_multi_threaded, Config) -> - init_mt(Config); -init_per_group(test_v3, Config) -> - init_v3(Config); -init_per_group(test_v1_v2, Config) -> - init_v1_v2(Config); -init_per_group(test_v2, Config) -> - init_v2(Config); -init_per_group(test_v1, Config) -> - init_v1(Config); -init_per_group(mib_storage_varm_mnesia, Config) -> - init_varm_mib_storage_mnesia(Config); -init_per_group(mib_storage_varm_dets, Config) -> - init_varm_mib_storage_dets(Config); -init_per_group(mib_storage_size_check_mnesia, Config) -> - init_size_check_msm(Config); -init_per_group(mib_storage_size_check_dets, Config) -> - init_size_check_msd(Config); -init_per_group(mib_storage_size_check_ets, Config) -> - init_size_check_mse(Config); -init_per_group(mib_storage_mnesia, Config) -> - init_mib_storage_mnesia(Config); -init_per_group(mib_storage_dets, Config) -> - init_mib_storage_dets(Config); -init_per_group(mib_storage_ets, Config) -> - init_mib_storage_ets(Config); -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(otp_4394, Config) -> - finish_otp_4394(Config); -end_per_group(v2_inform, Config) -> - finish_v2_inform(Config); -end_per_group(multiple_reqs_2, Config) -> - finish_mul(Config); -end_per_group(multiple_reqs, Config) -> - finish_mul(Config); -end_per_group(test_multi_threaded, Config) -> - finish_mt(Config); -end_per_group(test_v3, Config) -> - finish_v3(Config); -end_per_group(test_v1_v2, Config) -> - finish_v1_v2(Config); -end_per_group(test_v2, Config) -> - finish_v2(Config); -end_per_group(test_v1, Config) -> - finish_v1(Config); -end_per_group(mib_storage_varm_mnesia, Config) -> - finish_varm_mib_storage_mnesia(Config); -end_per_group(mib_storage_varm_dets, Config) -> - finish_varm_mib_storage_dets(Config); -end_per_group(mib_storage_size_check_mnesia, Config) -> - finish_size_check_msm(Config); -end_per_group(mib_storage_size_check_dets, Config) -> - finish_size_check_msd(Config); -end_per_group(mib_storage_size_check_ets, Config) -> - finish_size_check_mse(Config); -end_per_group(mib_storage_mnesia, Config) -> - finish_mib_storage_mnesia(Config); -end_per_group(mib_storage_dets, Config) -> - finish_mib_storage_dets(Config); -end_per_group(mib_storage_ets, Config) -> - finish_mib_storage_ets(Config); -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) when list(Config) -> - Dog = test_server:timetrap(test_server:minutes(6)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) when list(Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - Config. - -cases() -> - [ - app_info, {group, test_v1}, {group, test_v2}, - {group, test_v1_v2}, {group, test_v3}, - {group, test_multi_threaded}, {group, mib_storage}, - {group, tickets} - ]. - - -%%%----------------------------------------------------------------- -%%% The test case structure is as follows: -%%% -%%% init_all - starts mnesia, -%%% -%%% init_v1 - starts agent -%%% simple -%%% big - e.g. starts/stops subagent, load/unloads mibs -%%% init_mul -%%% mul_get -%%% mul_set -%%% -%%% finish_mul -%%% -%%% finish_v1 -%%% -%%% init_v2 - starts agent -%%% finish_v2 -%%% -%%% init_bilingual - starts agent -%%% finish_bilingual -%%% -%%% finish_all -%%% -%%% There is still one problem with these testsuites. If one test -%%% fails, it may not be possible to run some other cases, as it -%%% may have e.g. created some row or loaded some table, that it -%%% didn't undo (since it failed). -%%%----------------------------------------------------------------- - -init_all(Config0) when list(Config0) -> - ?LOG("init_all -> entry with" - "~n Config0: ~p",[Config0]), - - %% -- - %% Fix config: - %% - - DataDir0 = ?config(data_dir, Config0), - DataDir1 = filename:split(filename:absname(DataDir0)), - [_|DataDir2] = lists:reverse(DataDir1), - DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]), - Config1 = lists:keydelete(data_dir, 1, Config0), - Config = [{data_dir, DataDir3 ++ "/"}|Config1], - - %% -- - %% Start nodes - %% - - ?line {ok, SaNode} = start_node(snmp_sa), - ?line {ok, MgrNode} = start_node(snmp_mgr), - - - %% -- - %% Create necessary files - %% - - Dir = ?config(priv_dir, Config), - ?DBG("init_all -> Dir ~p", [Dir]), - - DataDir = ?config(data_dir, Config), - ?DBG("init_all -> DataDir ~p", [DataDir]), - - file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")), - ?DBG("init_all -> MgrDir ~p", [MgrDir]), - - file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")), - ?DBG("init_all -> AgentDir ~p", [AgentDir]), - - file:make_dir(SaDir = filename:join(Dir, "sa_dir/")), - ?DBG("init_all -> SaDir ~p", [SaDir]), - - - %% -- - %% Start and initiate mnesia - %% - - ?DBG("init_all -> load application mnesia", []), - ?line ok = application:load(mnesia), - - ?DBG("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), - - ?DBG("init_all -> application mnesia: set_env dir",[]), - ?line application_controller:set_env(mnesia, dir, - filename:join(Dir, "Mnesia1")), - - ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, - [mnesia, dir, filename:join(Dir, "Mnesia2")]), - - ?DBG("init_all -> create mnesia schema",[]), - ?line ok = mnesia:create_schema([SaNode, node()]), - - ?DBG("init_all -> start application mnesia",[]), - ?line ok = application:start(mnesia), - - ?DBG("init_all -> start application mnesia on ~p",[SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), - Ip = ?LOCALHOST(), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, - {agent_dir, AgentDir ++ "/"}, - {mgr_dir, MgrDir ++ "/"}, - {sa_dir, SaDir ++ "/"}, - {mib_dir, DataDir}, - {ip, Ip} | - Config]. - -finish_all(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - stop_node(SaNode), - stop_node(MgrNode), - application:stop(mnesia). - -start_v1_agent(Config) when list(Config) -> - start_agent(Config, [v1]). - -start_v1_agent(Config,Opts) when list(Config), list(Opts) -> - start_agent(Config, [v1], Opts). - -start_v2_agent(Config) when list(Config) -> - start_agent(Config, [v2]). - -start_v3_agent(Config) when list(Config) -> - start_agent(Config, [v3]). - -start_bilingual_agent(Config) when list(Config) -> - start_agent(Config, [v1,v2]). - -start_multi_threaded_agent(Config) when list(Config) -> - start_agent(Config, [v2], [{snmp_multi_threaded, true}]). - -stop_agent(Config) when list(Config) -> - ?LOG("stop_agent -> entry with" - "~n Config: ~p",[Config]), - - {Sup, Par} = ?config(snmp_sup, Config), - ?DBG("stop_agent -> attempt to stop (sup) ~p" - "~n Sup: ~p" - "~n Par: ~p", - [Sup, - (catch process_info(Sup)), - (catch process_info(Par))]), - stop_sup(Sup, Par), - - {Sup2, Par2} = ?config(snmp_sub, Config), - ?DBG("stop_agent -> attempt to stop (sub) ~p" - "~n Sup2: ~p" - "~n Par2: ~p", - [Sup2, - (catch process_info(Sup2)), - (catch process_info(Par2))]), - stop_sup(Sup2, Par2), - - ?DBG("stop_agent -> done - now cleanup config", []), - C1 = lists:keydelete(snmp_sup, 1, Config), - lists:keydelete(snmp_sub, 1, C1). - - -stop_sup(Pid, _) when node(Pid) == node() -> - case (catch process_info(Pid)) of - PI when list(PI) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - exit(Pid, kill), - await_stopped(Pid, Ref); - {'EXIT', _Reason} -> - ?LOG("stop_sup -> ~p not running", [Pid]), - ok - end; -stop_sup(Pid, _) -> - ?LOG("stop_sup -> attempt to stop ~p", [Pid]), - Ref = erlang:monitor(process, Pid), - ?LOG("stop_sup -> Ref: ~p", [Ref]), - %% Pid ! {'EXIT', Parent, shutdown}, % usch - exit(Pid, kill), - await_stopped(Pid, Ref). - -await_stopped(Pid, Ref) -> - receive - {'DOWN', Ref, process, Pid, _Reason} -> - ?DBG("received down message for ~p", [Pid]), - ok - after 10000 -> - ?INF("await_stopped -> timeout for ~p",[Pid]), - erlang:demonitor(Ref), - ?FAIL({failed_stop,Pid}) - end. - - -start_agent(Config, Vsn) -> - start_agent(Config, Vsn, []). -start_agent(Config, Vsn, Opts) -> - ?LOG("start_agent -> entry (~p) with" - "~n Config: ~p" - "~n Vsn: ~p" - "~n Opts: ~p",[node(), Config, Vsn, Opts]), - - ?line AgentDir = ?config(agent_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - - snmp_app_env_init(vsn_init(Vsn) ++ - [{audit_trail_log, read_write_log}, - {audit_trail_log_dir, AgentDir}, - {audit_trail_log_size, {10240, 10}}, - {force_config_reload, false}, - {snmp_agent_type, master}, - {snmp_config_dir, AgentDir}, - {snmp_db_dir, AgentDir}, - {snmp_local_db_auto_repair, true}, - {snmp_master_agent_verbosity, trace}, - {snmp_supervisor_verbosity, trace}, - {snmp_mibserver_verbosity, trace}, - {snmp_symbolic_store_verbosity, trace}, - {snmp_note_store_verbosity, trace}, - {snmp_net_if_verbosity, trace}], - Opts), - - - process_flag(trap_exit,true), - - {ok, AppSup} = snmp_app_sup:start_link(), - unlink(AppSup), - ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]), - - ?DBG("start_agent -> start master agent (old style)",[]), - Sup = case (catch snmpa_app:start(normal)) of - {ok, S} -> - ?DBG("start_agent -> started, Sup: ~p",[S]), - S; - - Else -> - ?DBG("start_agent -> unknown result: ~n~p",[Else]), - %% Get info about the apps we depend on - MnesiaInfo = mnesia_running(), - ?FAIL({start_failed,Else,MnesiaInfo}) - end, - - ?DBG("start_agent -> unlink from supervisor",[]), - ?line unlink(Sup), - ?line SaDir = ?config(sa_dir, Config), - ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]), - ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]), - ?DBG("start_agent -> done",[]), - ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. - - -vsn_init(Vsn) -> - vsn_init([v1,v2,v3], Vsn, []). - -vsn_init([], _Vsn, Acc) -> - Acc; -vsn_init([V|Vsns], Vsn, Acc) -> - case lists:member(V, Vsn) of - true -> - vsn_init(Vsns, Vsn, [{V, true}|Acc]); - false -> - vsn_init(Vsns, Vsn, [{V, false}|Acc]) - end. - -snmp_app_env_init(Env0, Opts) -> - ?DBG("snmp_app_env_init -> unload snmp",[]), - ?line application:unload(snmp), - ?DBG("snmp_app_env_init -> load snmp",[]), - ?line application:load(snmp), - ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]), - F1 = fun({Key,Val} = New, Acc0) -> - ?DBG("snmp_app_env_init -> " - "updating setting ~p to ~p", [Key, Val]), - case lists:keyreplace(Key, 1, Acc0, New) of - Acc0 -> - [New|Acc0]; - Acc -> - Acc - end - end, - Env = lists:foldr(F1, Env0, Opts), - ?DBG("snmp_app_env_init -> Env: ~p",[Env]), - F2 = fun({Key,Val}) -> - ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]), - application_controller:set_env(snmp, Key, Val) - end, - lists:foreach(F2, Env). - - - - -%% Test if application is running -mnesia_running() -> ?IS_MNESIA_RUNNING(). -crypto_running() -> ?IS_CRYPTO_RUNNING(). - - -start_sub(Dir) -> - ?DBG("start_sub -> entry",[]), - Opts = [{db_dir, Dir}, - {supervisor, [{verbosity, trace}]}], - %% BMK BMK -% {ok, P} = snmp_supervisor:start_sub(Dir), - {ok, P} = snmpa_supervisor:start_sub_sup(Opts), - unlink(P), - {ok, {P, self()}}. - -create_tables(SaNode) -> - ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, - {ram_copies, [SaNode]}, - {snmp, [{key, integer}]}, - {attributes, [a1,a2,a3]}]), - ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, - {attributes, [a1,a2]}]). - -delete_tables() -> - mnesia:delete_table(friendsTable2), - mnesia:delete_table(kompissTable2), - mnesia:delete_table(snmp_variables). - -%% Creation is done in runtime! -delete_mib_storage_mnesia_tables() -> - mnesia:delete_table(snmpa_mib_data), - mnesia:delete_table(snmpa_mib_tree), - mnesia:delete_table(snmpa_symbolic_store). - -%%----------------------------------------------------------------- -%% A test case is always one of: -%% - v1 specific case -%% - v2 specific case -%% - v1 and v2 case -%% All v1 specific cases are prefixed with v1_, and all v2 with -%% v2_. E.g. v1_trap/v2_trap. -%% -%% All other cases are shared. However, the testserver uses the name -%% of the case to generate a file for that case. The same case cannot -%% be used in different configurations in the same suite. Therefore -%% all these functions exists in two variants, the base function -%% , and a second version _2. There may be several -%% versions as well, _N. -%%----------------------------------------------------------------- - - - - - - - - - -mib_storage_ets_cases() -> -[mse_simple, mse_v1_processing, mse_big, mse_big2, - mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap, - mse_sa_error, mse_next_across_sa, mse_undo, - mse_standard_mib, mse_community_mib, mse_framework_mib, - mse_target_mib, mse_notification_mib, - mse_view_based_acm_mib, mse_sparse_table, mse_me_of, - mse_mib_of]. - -mib_storage_dets_cases() -> -[msd_simple, msd_v1_processing, msd_big, msd_big2, - msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap, - msd_sa_error, msd_next_across_sa, msd_undo, - msd_standard_mib, msd_community_mib, msd_framework_mib, - msd_target_mib, msd_notification_mib, - msd_view_based_acm_mib, msd_sparse_table, msd_me_of, - msd_mib_of]. - -mib_storage_mnesia_cases() -> -[msm_simple, msm_v1_processing, msm_big, msm_big2, - msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap, - msm_sa_error, msm_next_across_sa, msm_undo, - msm_standard_mib, msm_community_mib, msm_framework_mib, - msm_target_mib, msm_notification_mib, - msm_view_based_acm_mib, msm_sparse_table, msm_me_of, - msm_mib_of]. - -mse_size_check_cases() -> -[mse_size_check]. - -msd_size_check_cases() -> -[msd_size_check]. - -msm_size_check_cases() -> -[msm_size_check]. - -varm_mib_storage_dets_cases() -> -[msd_varm_mib_start]. - -varm_mib_storage_mnesia_cases() -> -[msm_varm_mib_start]. - -init_mib_storage_ets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,ets}, - init_ms(Config, [MibStorage]). - -init_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - init_ms(Config, [MibStorage]). - -init_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - init_ms(Config, [MibStorage]). - -init_ms(Config, Opts) when list(Config) -> - ?LOG("init_mib_storage_ets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts], - [{vsn, v1} | start_v1_agent(Config,Opts1)]. - -init_size_check_mse(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, ets}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msd(Config) when list(Config) -> - AgentDir = ?GCONF(agent_dir, Config), - MibStorage = {snmp_mib_storage, {dets, AgentDir}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_msm(Config) when list(Config) -> - MibStorage = {snmp_mib_storage, {mnesia,[]}}, - init_size_check_ms(Config, [MibStorage]). - -init_size_check_ms(Config, Opts) when list(Config) -> - SaNode = ?GCONF(snmp_sa, Config), - %% We are using v3 here, so crypto must be supported or else... - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - create_tables(SaNode), - AgentDir = ?GCONF(agent_dir, Config), - MgrDir = ?GCONF(mgr_dir, Config), - Ip = ?GCONF(ip, Config), - ?line ok = - config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_agent(Config, [v3], Opts)]. - -init_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_dets -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{dets,AgentDir}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -init_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("init_varm_mib_storage_mnesia -> entry", []), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?GCONF(agent_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - MibStorage = {snmp_mib_storage,{mnesia,[]}}, - MasterAgentVerbosity = {snmp_master_agent_verbosity, trace}, - MibsVerbosity = {snmp_mibserver_verbosity, trace}, - SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace}, - Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity], - [{vsn, v1}, {agent_opts,Opts} | Config]. - -finish_mib_storage_ets(Config) when list(Config) -> - ?LOG("finish_mib_storage_ets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_mib_storage_dets -> entry", []), - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - C1 = stop_agent(Config), - delete_files(C1), - C2 = lists:keydelete(vsn, 1, C1), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_dets(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_dets -> entry", []), - delete_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_varm_mib_storage_mnesia(Config) when list(Config) -> - ?LOG("finish_varm_mib_storage_mnesia -> entry", []), - delete_tables(), - delete_mib_storage_mnesia_tables(), - %% C1 = stop_agent(Config), % In case something went wrong... - delete_files(Config), - C2 = lists:keydelete(vsn, 1, Config), - lists:keydelete(agent_opts, 1, C2). - -finish_size_check_mse(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msd(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_msm(Config) when list(Config) -> - finish_size_check_ms(Config). - -finish_size_check_ms(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%% These are just interface functions to fool the test server -mse_simple(X) -> simple(X). -mse_v1_processing(X) -> v1_processing(X). -mse_big(X) -> big(X). -mse_big2(X) -> big2(X). -mse_loop_mib(X) -> loop_mib(X). -mse_api(X) -> api(X). -mse_sa_register(X) -> sa_register(X). -mse_v1_trap(X) -> v1_trap(X). -mse_sa_error(X) -> sa_error(X). -mse_next_across_sa(X) -> next_across_sa(X). -mse_undo(X) -> undo(X). -mse_standard_mib(X) -> snmp_standard_mib(X). -mse_community_mib(X) -> snmp_community_mib(X). -mse_framework_mib(X) -> snmp_framework_mib(X). -mse_target_mib(X) -> snmp_target_mib(X). -mse_notification_mib(X) -> snmp_notification_mib(X). -mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -mse_sparse_table(X) -> sparse_table(X). -mse_me_of(X) -> ms_me_of(X). -mse_mib_of(X) -> ms_mib_of(X). - -msd_simple(X) -> simple(X). -msd_v1_processing(X) -> v1_processing(X). -msd_big(X) -> big(X). -msd_big2(X) -> big2(X). -msd_loop_mib(X) -> loop_mib(X). -msd_api(X) -> api(X). -msd_sa_register(X) -> sa_register(X). -msd_v1_trap(X) -> v1_trap(X). -msd_sa_error(X) -> sa_error(X). -msd_next_across_sa(X) -> next_across_sa(X). -msd_undo(X) -> undo(X). -msd_standard_mib(X) -> snmp_standard_mib(X). -msd_community_mib(X) -> snmp_community_mib(X). -msd_framework_mib(X) -> snmp_framework_mib(X). -msd_target_mib(X) -> snmp_target_mib(X). -msd_notification_mib(X) -> snmp_notification_mib(X). -msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msd_sparse_table(X) -> sparse_table(X). -msd_me_of(X) -> ms_me_of(X). -msd_mib_of(X) -> ms_mib_of(X). - -msm_simple(X) -> simple(X). -msm_v1_processing(X) -> v1_processing(X). -msm_big(X) -> big(X). -msm_big2(X) -> big2(X). -msm_loop_mib(X) -> loop_mib(X). -msm_api(X) -> api(X). -msm_sa_register(X) -> sa_register(X). -msm_v1_trap(X) -> v1_trap(X). -msm_sa_error(X) -> sa_error(X). -msm_next_across_sa(X) -> next_across_sa(X). -msm_undo(X) -> undo(X). -msm_standard_mib(X) -> snmp_standard_mib(X). -msm_community_mib(X) -> snmp_community_mib(X). -msm_framework_mib(X) -> snmp_framework_mib(X). -msm_target_mib(X) -> snmp_target_mib(X). -msm_notification_mib(X) -> snmp_notification_mib(X). -msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X). -msm_sparse_table(X) -> sparse_table(X). -msm_me_of(X) -> ms_me_of(X). -msm_mib_of(X) -> ms_mib_of(X). - - -mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X). -msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X). -msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X). - -msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X). -msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X). - -ms_size_check(suite) -> []; -ms_size_check(Config) when list(Config) -> - p("ms_size_check..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?LOG("mib server size check...", []), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - - -varm_mib_start(suite) -> []; -varm_mib_start(Config) when list(Config) -> - p("varm_mib_start..."), - ?LOG("varm_mib_start -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - %% Start the agent - Opts = ?GCONF(agent_opts, Config), - Config1 = start_v1_agent(Config, Opts), - - %% Sleep some in order for the agent to start properly - ?DBG("varm_mib_start -> sleep some (before loading mobs)", []), - ?SLEEP(5000), - - %% Load all the mibs - HardwiredMibs = loaded_mibs(), - ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - - %% Unload the hardwired mibs - ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), - ?SLEEP(1000), - ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired - - ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), - ?SLEEP(1000), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - Config2 = stop_agent(Config1), - - %% Sleep some in order for the agent to stop properly - ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []), - ?SLEEP(5000), - - %% Start the agent (again) - ?DBG("varm_mib_start -> start the agent", []), - Config3 = start_v1_agent(Config2, Opts), - - ?DBG("varm_mib_start -> sleep some (before starting tests)", []), - ?SLEEP(5000), - - %% Perform the test(s) - ?DBG("varm_mib_start -> perform the tests", []), - try_test(snmp_community_mib), - try_test(snmp_framework_mib), - try_test(snmp_target_mib), - try_test(snmp_notification_mib), - - %% Stop the agent (without deleting the stored files) - ?DBG("varm_mib_start -> stop the agent", []), - stop_agent(Config3), - ok. - - --define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]). --define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). --define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -ms_me_of(suite) -> []; -ms_me_of(Config) when list(Config) -> - p("ms_me_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), - - ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -me_of(Oid) -> - case snmpa:me_of(Oid) of - {ok, #me{oid = Oid}} -> - ok; - {ok, #me{oid = OtherOid}} -> - case lists:reverse(Oid) of - [0|Rest] -> - case lists:reverse(Rest) of - OtherOid -> - ok; - AnotherOid -> - {error, {invalid_oid, Oid, AnotherOid}} - end; - _ -> - {error, {invalid_oid, Oid, OtherOid}} - end; - {error, Reason} -> - {error, Reason}; - Else -> - {error, Else} - end. - - -ms_mib_of(suite) -> []; -ms_mib_of(Config) when list(Config) -> - p("ms_mib_of..."), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - - ?SLEEP(2000), - - ?line display_memory_usage(), - - - ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", - [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", - [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), - - ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", - [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, - 'SNMP-USER-BASED-SM-MIB'), - - - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - - ok. - -mib_of(Oid, ExpectedMibName) -> - ?DBG("mib_of -> entry with" - "~n Oid: ~p" - "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]), - %% case snmpa:mib_of(Oid) of - MibOf = snmpa:mib_of(Oid), - ?DBG("mib_of -> MibOf: ~n~p", [MibOf]), - case MibOf of - {ok, ExpectedMibName} -> - ok; - {ok, OtherMibName} -> - {error, {invalid_mib, ExpectedMibName, OtherMibName}}; - {error, Reason} -> - {error, Reason}; - Else -> - ?DBG("mib_of -> Else: ~n~p", [Else]), - {error, Else} - end. - - -app_info(suite) -> []; -app_info(Config) when list(Config) -> - SnmpDir = app_dir(snmp), - SslDir = app_dir(ssl), - CryptoDir = app_dir(crypto), - Attr = snmp:module_info(attributes), - AppVsn = - case lists:keysearch(app_vsn, 1, Attr) of - {value, {app_vsn, V}} -> - V; - false -> - "undefined" - end, - io:format("Root dir: ~s~n" - "SNMP: Application dir: ~s~n" - " Application ver: ~s~n" - "SSL: Application dir: ~s~n" - "CRYPTO: Application dir: ~s~n", - [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]), - ok. - -app_dir(App) -> - case code:lib_dir(App) of - D when list(D) -> - filename:basename(D); - {error, _Reason} -> - "undefined" - end. - - - -%v1_cases() -> [loop_mib]; -v1_cases() -> -[simple, db_notify_client, v1_processing, big, big2, - loop_mib, api, subagent, mnesia, {group, multiple_reqs}, - sa_register, v1_trap, sa_error, next_across_sa, undo, - {group, reported_bugs}, {group, standard_mibs}, - sparse_table, cnt_64, opaque, change_target_addr_config]. - -init_v1(Config) when list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v1} | start_v1_agent(Config)]. - -finish_v1(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v2_cases() -> [loop_mib_2]; -v2_cases() -> -[simple_2, v2_processing, big_2, big2_2, loop_mib_2, - api_2, subagent_2, mnesia_2, {group, multiple_reqs_2}, - sa_register_2, v2_trap, {group, v2_inform}, sa_error_2, - next_across_sa_2, undo_2, {group, reported_bugs_2}, - {group, standard_mibs_2}, v2_types, implied, - sparse_table_2, cnt_64_2, opaque_2, v2_caps]. - -init_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_v2_agent(Config)]. - -finish_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -v1_v2_cases() -> -[simple_bi]. - -init_v1_v2(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, bilingual} | start_bilingual_agent(Config)]. - -finish_v1_v2(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -%v3_cases() -> [loop_mib_3]; -v3_cases() -> -[simple_3, v3_processing, big_3, big2_3, api_3, - subagent_3, mnesia_3, loop_mib_3, multiple_reqs_3, - sa_register_3, v3_trap, v3_inform, sa_error_3, - next_across_sa_3, undo_3, {group, reported_bugs_3}, - {group, standard_mibs_3}, {group, v3_security}, - v2_types_3, implied_3, sparse_table_3, cnt_64_3, - opaque_3, v2_caps_3]. - -init_v3(Config) when list(Config) -> - %% Make sure crypto works, otherwise start_agent will fail - %% and we will be stuck with a bunch of mnesia tables for - %% the rest of this suite... - ?DBG("start_agent -> start crypto app",[]), - case ?CRYPTO_START() of - ok -> - case ?CRYPTO_SUPPORT() of - {no, Reason} -> - ?SKIP({unsupported_encryption, Reason}); - yes -> - ok - end; - {error, Reason} -> - ?SKIP({failed_starting_crypto, Reason}) - end, - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v3], MgrDir, AgentDir, - tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v3} | start_v3_agent(Config)]. - -finish_v3(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - - -mt_cases() -> -[multi_threaded, mt_trap]. - -init_mt(Config) when list(Config) -> - SaNode = ?config(snmp_sa, Config), - create_tables(SaNode), - AgentDir = ?config(agent_dir, Config), - MgrDir = ?config(mgr_dir, Config), - Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. - -finish_mt(Config) when list(Config) -> - delete_tables(), - C1 = stop_agent(Config), - delete_files(C1), - lists:keydelete(vsn, 1, C1). - -%% This one *must* be run first in each case. -init_case(Config) when list(Config) -> - ?DBG("init_case -> entry with" - "~n Config: ~p", [Config]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), - MasterNode = node(), - - SaHost = ?HOSTNAME(SaNode), - MgrHost = ?HOSTNAME(MgrNode), - MasterHost = ?HOSTNAME(MasterNode), - {ok, MasterIP} = snmp_misc:ip(MasterHost), - {ok, MIP} = snmp_misc:ip(MgrHost), - {ok, SIP} = snmp_misc:ip(SaHost), - - - put(mgr_node, MgrNode), - put(sa_node, SaNode), - put(master_node, MasterNode), - put(sa_host, SaHost), - put(mgr_host, MgrHost), - put(master_host, MasterHost), - put(mip, tuple_to_list(MIP)), - put(masterip , tuple_to_list(MasterIP)), - put(sip, tuple_to_list(SIP)), - - MibDir = ?config(mib_dir, Config), - put(mib_dir, MibDir), - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - put(std_mib_dir, StdM), - - MgrDir = ?config(mgr_dir, Config), - put(mgr_dir, MgrDir), - - put(vsn, ?config(vsn, Config)), - ?DBG("init_case -> exit with" - "~n MasterNode: ~p" - "~n SaNode: ~p" - "~n MgrNode: ~p" - "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]), - {SaNode, MgrNode, MibDir}. - -load_master(Mib) -> - ?DBG("load_master -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]). - -load_master_std(Mib) -> - ?DBG("load_master_std -> entry with" - "~n Mib: ~p", [Mib]), - snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety - ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]). - -unload_master(Mib) -> - ?DBG("unload_master -> entry with" - "~n Mib: ~p", [Mib]), - ok = snmpa:unload_mibs(snmp_master_agent, [Mib]). - -loaded_mibs() -> - ?DBG("loaded_mibs -> entry",[]), - Info = snmpa:info(snmp_master_agent), - {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info), - [atom_to_list(Mib) || {Mib,_,_} <- Mibs]. - -unload_mibs(Mibs) -> - ?DBG("unload_mibs -> entry with" - "~n Mibs: ~p", [Mibs]), - ok = snmpa:unload_mibs(snmp_master_agent, Mibs). - -start_subagent(SaNode, RegTree, Mib) -> - ?DBG("start_subagent -> entry with" - "~n SaNode: ~p" - "~n RegTree: ~p" - "~n Mib: ~p", [SaNode, RegTree, Mib]), - MA = whereis(snmp_master_agent), - ?DBG("start_subagent -> MA: ~p", [MA]), - MibDir = get(mib_dir), - Mib1 = join(MibDir,Mib), - %% BMK BMK -% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of - case rpc:call(SaNode, snmpa_supervisor, - start_sub_agent, [MA, RegTree, [Mib1]]) of - {ok, SA} -> - ?DBG("start_subagent -> SA: ~p", [SA]), - {ok, SA}; - Error -> - ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]}) - end. - -stop_subagent(SA) -> - ?DBG("stop_subagent -> entry with" - "~n SA: ~p", [SA]), - %% BNK BMK - %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]). - rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]). - -%%----------------------------------------------------------------- -%% This function takes care of the old OTP-SNMPEA-MIB. -%% Unfortunately, the testcases were written to use the data in the -%% internal tables, and these table are now obsolete and not used -%% by the agent. Therefore, we emulate them by using -%% OLD-SNMPEA-MIB, which uses the default impl. of all tables. -%% -%% These two rows must exist in intCommunityTable -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. -%% (But with the manager's IP address) -%% -%%----------------------------------------------------------------- -init_old() -> - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [6 | "public"], - {get(mip), "public", 2, 2}), - snmpa_local_db:table_create_row(intCommunityTable, - get(mip) ++ [13 | "standard trap"], - {get(mip), "standard trap", 2, 1}), - snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]). - - - -simple(suite) -> []; -simple(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(simple_standard_test). - -simple_2(X) -> simple(X). - -simple_bi(suite) -> []; -simple_bi(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(vsn, v1), % First, try v1 manager - try_test(simple_standard_test), - - put(vsn, v2), % Then, try v2 manager - try_test(simple_standard_test). - -simple_3(X) -> - simple(X). - -big(suite) -> []; -big(Config) when list(Config) -> - ?DBG("big -> entry", []), - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). - -big_2(X) -> big(X). - -big_3(X) -> big(X). - - -big2(suite) -> []; -big2(Config) when list(Config) -> - %% This is exactly the same tests as 'big', but with the - %% v2 equivalent of the mibs. - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), - try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). - -big2_2(X) -> big2(X). - -big2_3(X) -> big2(X). - - -multi_threaded(suite) -> []; -multi_threaded(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(multi_threaded_test), - ?line unload_master("Test1"). - -mt_trap(suite) -> []; -mt_trap(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"). - -v2_types(suite) -> []; -v2_types(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(types_v2_test), - ?line unload_master("Test1"). - -v2_types_3(X) -> v2_types(X). - - -implied(suite) -> []; -implied(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(implied_test,[MA]), - ?line unload_master("Test1"). - -implied_3(X) -> implied(X). - - -sparse_table(suite) -> []; -sparse_table(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(sparse_table_test), - ?line unload_master("Test1"). - -sparse_table_2(X) -> sparse_table(X). - -sparse_table_3(X) -> sparse_table(X). - -cnt_64(suite) -> []; -cnt_64(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line load_master("Test1"), - try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). - -cnt_64_2(X) -> cnt_64(X). - -cnt_64_3(X) -> cnt_64(X). - -opaque(suite) -> []; -opaque(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test1"), - try_test(opaque_test), - ?line unload_master("Test1"). - -opaque_2(X) -> opaque(X). - -opaque_3(X) -> opaque(X). - - -change_target_addr_config(suite) -> []; -change_target_addr_config(Config) when list(Config) -> - p("Testing changing target address config..."), - ?LOG("change_target_addr_config -> entry",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - put(sname,snmp_suite), - put(verbosity,trace), - - MA = whereis(snmp_master_agent), - - ?LOG("change_target_addr_config -> load TestTrap",[]), - ?line load_master("TestTrap"), - - ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,trace), - - %% First send some traps that will arive att the original manager - ?LOG("change_target_addr_config -> send trap",[]), - try_test(ma_trap1, [MA]), - - ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]), - ?line snmpa:verbosity(local_db,silence), - - %% Start new dummy listener - ?LOG("change_target_addr_config -> start dummy manager",[]), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), - - %% Reconfigure - ?LOG("change_target_addr_config -> reconfigure",[]), - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_addr_conf(AgentDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentDir), - - %% Send the trap again - ?LOG("change_target_addr_config -> send trap again",[]), - catch dummy_manager_send_trap2(Pid), - - ?LOG("change_target_addr_config -> await trap ack",[]), - catch dummy_manager_await_trap2_ack(), - - ?LOG("change_target_addr_config -> stop dummy manager",[]), - ?line ok = dummy_manager_stop(Pid), - - ?LOG("change_target_addr_config -> reset target address config",[]), - ?line reset_target_addr_conf(AgentDir), - - ?LOG("change_target_addr_config -> unload TestTrap",[]), - ?line unload_master("TestTrap"). - - -dummy_manager_start(MA) -> - ?DBG("dummy_manager_start -> entry",[]), - Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]), - ?DBG("dummy_manager_start -> Pid: ~p",[Pid]), - await_dummy_manager_started(Pid). - -await_dummy_manager_started(Pid) -> - receive - {dummy_manager_started,Pid,Port} -> - ?DBG("dummy_manager_start -> acknowledge received with" - "~n Port: ~p",[Port]), - {ok,Pid,Port}; - {'EXIT', Pid, Reason} -> - {error, Pid, Reason}; - O -> - ?LOG("dummy_manager_start -> received unknown message:" - "~n ~p",[O]), - await_dummy_manager_started(Pid) - end. - -dummy_manager_stop(Pid) -> - ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]), - Pid ! stop, - receive - {dummy_manager_stopping, Pid} -> - ?DBG("dummy_manager_stop -> acknowledge received",[]), - ok - after 10000 -> - ?ERR("dummy_manager_stop -> timeout",[]), - timeout - end. - -dummy_manager_send_trap2(Pid) -> - ?DBG("dummy_manager_send_trap2 -> entry",[]), - Pid ! {send_trap,testTrap2}. - -dummy_manager_await_trap2_ack() -> - ?DBG("dummy_manager_await_trap2 -> entry",[]), - receive - {received_trap,Trap} -> - ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]), - %% Note: - %% Without this sleep the v2_inform_i testcase failes! There - %% is no relation between these two test cases as far as I - %% able to figure out... - sleep(60000), - ok; - O -> - ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]), - ok - after 10000 -> - ?ERR("dummy_manager_await_trap2 -> timeout",[]), - timeout - end. - -dummy_manager_init(Parent,MA) -> - ?DBG("dummy_manager_init -> entry with" - "~n Parent: ~p" - "~n MA: ~p",[Parent,MA]), - {ok,S} = gen_udp:open(0,[{recbuf,65535}]), - ?DBG("dummy_manager_init -> S: ~p",[S]), - {ok,Port} = inet:port(S), - ?DBG("dummy_manager_init -> Port: ~p",[Port]), - Parent ! {dummy_manager_started,self(),Port}, - dummy_manager_loop(Parent,S,MA). - -dummy_manager_loop(P,S,MA) -> - ?LOG("dummy_manager_loop -> ready for receive",[]), - receive - {send_trap,Trap} -> - ?LOG("dummy_manager_loop -> received trap send request" - "~n Trap: ~p",[Trap]), - snmpa:send_trap(MA, Trap, "standard trap"), - dummy_manager_loop(P,S,MA); - {udp, _UdpId, Ip, UdpPort, Bytes} -> - ?LOG("dummy_manager_loop -> received upd message" - "~n from: ~p:~p" - "~n size: ~p", - [Ip, UdpPort, dummy_manager_message_sz(Bytes)]), - R = dummy_manager_handle_message(Bytes), - ?DBG("dummy_manager_loop -> R: ~p",[R]), - P ! R, - dummy_manager_loop(P,S,MA); - stop -> - ?DBG("dummy_manager_loop -> received stop request",[]), - P ! {dummy_manager_stopping, self()}, - gen_udp:close(S), - exit(normal); - O -> - ?LOG("dummy_manager_loop -> received unknown message:" - "~n ~p",[O]), - dummy_manager_loop(P,S,MA) - end. - -dummy_manager_message_sz(B) when binary(B) -> - size(B); -dummy_manager_message_sz(L) when list(L) -> - length(L); -dummy_manager_message_sz(_) -> - undefined. - -dummy_manager_handle_message(Bytes) -> - case (catch snmp_pdus:dec_message(Bytes)) of - {'EXIT',Reason} -> - ?ERR("dummy_manager_handle_message -> " - "failed decoding message only:~n ~p",[Reason]), - {error,Reason}; - M -> - ?DBG("dummy_manager_handle_message -> decoded message:" - "~n ~p",[M]), - {received_trap,M} - end. - - -api(suite) -> []; -api(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -api_2(X) -> api(X). - -api_3(X) -> api(X). - - -subagent(suite) -> []; -subagent(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - try_test(load_test_sa), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - - p("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]), - try_test(load_test), - - p("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]), - try_test(unreg_test), - p("Testing register subagent..."), - rpc:call(SaNode, snmp, register_subagent, - [MA, ?klas1, SA]), - try_test(load_test_sa), - - ?line stop_subagent(SA), - try_test(unreg_test). - -subagent_2(X) -> subagent(X). - -subagent_3(X) -> subagent(X). - - -mnesia(suite) -> []; -mnesia(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Starting subagent with mnesia impl..."), - {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - - try_test(big_test_2), - - p("Testing unregister subagent..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]), - try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). - -mnesia_2(X) -> mnesia(X). - -mnesia_3(X) -> mnesia(X). - - - -mul_cases() -> -[mul_get, mul_get_err, mul_next, mul_next_err, - mul_set_err]. - - -multiple_reqs_3(_X) -> - {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}. - - -mul_cases_2() -> -[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, - mul_set_err_2]. - - -mul_cases_3() -> - [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3]. - - -init_mul(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - [{mul_sub, SA} | Config]. - -finish_mul(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - SA = ?config(mul_sub, Config), - - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), - lists:keydelete(mul_sub, 1, Config). - -mul_get(suite) -> []; -mul_get(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get..."), - try_test(do_mul_get). - -mul_get_2(X) -> mul_get(X). - -mul_get_3(X) -> mul_get(X). - - -mul_get_err(suite) -> []; -mul_get_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple get with error..."), - try_test(do_mul_get_err). - -mul_get_err_2(X) -> mul_get_err(X). - -mul_get_err_3(X) -> mul_get_err(X). - - -mul_next(suite) -> []; -mul_next(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next). - -mul_next_2(X) -> mul_next(X). - -mul_next_3(X) -> mul_next(X). - - -mul_next_err(suite) -> []; -mul_next_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple next..."), - try_test(do_mul_next_err). - -mul_next_err_2(X) -> mul_next_err(X). - -mul_next_err_3(X) -> mul_next_err(X). - - -mul_set(suite) -> []; -mul_set(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set..."), - try_test(do_mul_set). - -mul_set_2(X) -> mul_set(X). - -mul_set_3(X) -> mul_set(X). - - -mul_set_err(suite) -> []; -mul_set_err(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing multiple set with error..."), - try_test(do_mul_set_err). - -mul_set_err_2(X) -> mul_set_err(X). - -mul_set_err_3(X) -> mul_set_err(X). - - -sa_register(suite) -> []; -sa_register(Config) when list(Config) -> - ?DBG("sa_register -> entry", []), - {SaNode, _MgrNode, MibDir} = init_case(Config), - - ?DBG("sa_register -> start subagent", []), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - - ?DBG("sa_register -> unregister subagent", []), - p("Testing unregister subagent (2)..."), - MA = whereis(snmp_master_agent), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Loading SA-MIB..."), - ?DBG("sa_register -> unload mibs", []), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - ?DBG("sa_register -> unload mibs", []), - snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]), - ?DBG("sa_register -> register subagent", []), - rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]), - try_test(sa_mib), - - ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). - -sa_register_2(X) -> sa_register(X). - -sa_register_3(X) -> sa_register(X). - - -v1_trap(suite) -> []; -v1_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_trap1, [MA]), - try_test(ma_trap2, [MA]), - try_test(ma_v2_2_v1_trap, [MA]), - try_test(ma_v2_2_v1_trap2, [MA]), - - p("Testing trap sending from subagent..."), - try_test(sa_trap1, [SA]), - try_test(sa_trap2, [SA]), - try_test(sa_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v2_trap(suite) -> []; -v2_trap(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing trap sending from master agent..."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - - try_test(ma_v2_trap1, [MA]), - try_test(ma_v2_trap2, [MA]), - try_test(ma_v1_2_v2_trap, [MA]), - try_test(ma_v1_2_v2_trap2, [MA]), - - try_test(sa_mib), - p("Testing trap sending from subagent..."), - try_test(sa_v1_2_v2_trap1, [SA]), - try_test(sa_v1_2_v2_trap2, [SA]), - try_test(sa_v1_2_v2_trap3, [SA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), - - ?line stop_subagent(SA). - -v3_trap(X) -> - v2_trap(X). - - -v3_inform(_X) -> - %% v2_inform(X). - {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}. - -init_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -init_v3_inform(X) -> - init_v2_inform(X). - -finish_v2_inform(Config) when list(Config) -> - _Dir = ?config(agent_dir, Config), -% snmp_internal_mib:configure(Dir), - Config. - -finish_v3_inform(X) -> - finish_v2_inform(X). - - - -v2_inform_i(suite) -> []; -v2_inform_i(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - p("Testing inform sending from master agent... NOTE! This test\ntakes a " - "few minutes (5) to complete."), - MA = whereis(snmp_master_agent), - - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(ma_v2_inform1, [MA]), - - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"). - -v3_inform_i(X) -> v2_inform_i(X). - - -sa_error(suite) -> []; -sa_error(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing sa bad value (is_set_ok)..."), - try_test(sa_errs_bad_value), - - p("Testing sa gen err (set)..."), - try_test(sa_errs_gen_err), - - p("Testing too big..."), - try_test(sa_too_big), - - ?line unload_master("OLD-SNMPEA-MIB"), - stop_subagent(SA). - -sa_error_2(X) -> sa_error(X). - -sa_error_3(X) -> sa_error(X). - - -next_across_sa(suite) -> []; -next_across_sa(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Loading another subagent mib..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]), - - rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]), - try_test(load_test_sa), - - p("Testing next across subagent (endOfMibView from SA)..."), - try_test(next_across_sa), - - p("Unloading mib"), - snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]), - rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]), - try_test(unreg_test), - - p("Starting another subagent"), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), - p("Testing next across subagent (wrong prefix from SA)..."), - try_test(next_across_sa), - - stop_subagent(SA), - stop_subagent(SA2). - -next_across_sa_2(X) -> next_across_sa(X). - -next_across_sa_3(X) -> next_across_sa(X). - - -undo(suite) -> []; -undo(Config) when list(Config) -> - {SaNode, _MgrNode, MibDir} = init_case(Config), - MA = whereis(snmp_master_agent), - - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - - p("Testing undo phase at master agent..."), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]), - try_test(undo_test), - try_test(api_test2), - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]), - - p("Testing bad return values from instrum. funcs..."), - try_test(bad_return), - - ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]), - - p("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]), - ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), - try_test(undo_test), - try_test(api_test3), - - p("Testing undo phase across master/subagents..."), - try_test(undo_test), - try_test(api_test3), - stop_subagent(SA). - -undo_2(X) -> undo(X). - -undo_3(X) -> undo(X). - -%% Req. Test2 -v1_processing(suite) -> []; -v1_processing(Config) when list(Config) -> - ?DBG("v1_processing -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v1_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v2_processing(suite) -> []; -v2_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), - ?line unload_master("Test2"). - -%% Req. Test2 -v3_processing(suite) -> []; -v3_processing(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("Test2"), - try_test(v2_proc), % same as v2! - ?line unload_master("Test2"). - - -%% We'll try get/set/trap and inform for all the auth & priv protocols. -%% For informs, the mgr is auth-engine. The agent has to sync. This is -%% accomplished by the first inform sent. That one will generate a -%% report, which makes it in sync. The notification-generating -%% application times out, and send again. This time it'll work. - -v3_crypto_basic(suite) -> []; -v3_crypto_basic(_Config) -> - EID = [0,0,0,0,0,0,0,0,0,0,0,2], - %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, - 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = - KMd5_1, - %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, - 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = - KSHA_1, - %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, - 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = - snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, - 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, - 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - KSHA_1t = lists:sublist(KSHA_1, 16), - KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, - 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, - 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = - snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16, - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), - - %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), - ok. - - - -v3_md5_auth(suite) -> []; -v3_md5_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing MD5 authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authMD5"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_sha_auth(suite) -> []; -v3_sha_auth(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing SHA authentication...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authNoPriv}, {user, "authSHA"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -v3_des_priv(suite) -> []; -v3_des_priv(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - p("Testing DES encryption...takes a few seconds..."), - - AgentDir = ?config(agent_dir, Config), - ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentDir), - - MA = whereis(snmp_master_agent), - - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - - try_test(v3_sync, [[{v2_proc, []}, - {ma_v2_trap1, [MA]}, - {v3_inform_sync, [MA]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentDir). - -%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). - -%% Make sure mgr is in sync with agent -v3_sync(Funcs) -> - ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]), - g([[sysDescr, 0]]), - expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]), - g([[sysDescr, 0]]), - expect(433, [{[sysDescr,0], any}]), - lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs). - -v3_inform_sync(MA) -> - ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, - "standard inform", []), - %% Make sure agent is in sync with mgr... - ?DBG("v3_sync -> wait some time: ",[]), - sleep(20000), % more than 1500*10 in target_addr.conf - ?DBG("v3_sync -> await response",[]), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]). - - -v2_caps(suite) -> []; -v2_caps(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - try_test(v2_caps_i, [node()]). - -v2_caps_3(X) -> v2_caps(X). - - -v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]), - g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]}, - {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmp, del_agent_caps, [Idx]), - g([[sysORID, Idx]]), - ?line expect(2, [{[sysORID, Idx], noSuchInstance}]). - - -%% Req. Test2 -v1_proc() -> - ?DBG("v1_proc -> entry", []), - %% According to RFC1157. - %% Template:
    : - v1_get_p(), - v1_get_next_p(), - v1_set_p(). - - -v1_get_p() -> - %% 4.1.2:1 - g([[test2]]), - ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]), - g([[tDescr]]), - ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]), - g([[tDescr2,0]]), - ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]), - g([[tDescr3,0]]), - ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]), - g([[tDescr4,0]]), - ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'}, - {[tDescr,0], 'NULL'}]), - g([[sysDescr,3]]), - ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), - - %% 4.1.2:2 - g([[tTable]]), - ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]), - g([[tEntry]]), - ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]), - - %% 4.1.2:3 - g([[tTooBig, 0]]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.2:4 - g([[tGenErr1, 0]]), - ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]). - - -v1_get_next_p() -> - %% 4.1.3:1 - gn([[1,3,7,1]]), - ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]), - gn([[tDescr2]]), - ?line expect(11, tooBig, 0, any), - - %% 4.1.3:2 - gn([[tTooBig]]), - io:format("We currently don't handle tooBig correct!!!\n"), -% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]), - ?line expect(20, tooBig, 0, any), - - %% 4.1.3:3 - gn([[tGenErr1]]), -% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]), - ?line expect(40, genErr, 1, any), - gn([[tGenErr2]]), -% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]), - ?line expect(41, genErr, 1, any), - gn([[sysDescr], [tGenErr3]]), -% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'}, -% {[tGenErr3], 'NULL'}]). - ?line expect(42, genErr, 2, any). - -v1_set_p() -> - %% 4.1.5:1 - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]), - s([{[tDescr3], s, "noSuchObject"}]), - ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]), - s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), - s([{[tDescr2,0], s, "inconsistentName"}]), - ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), - - %% 4.1.5:2 - s([{[tDescr2, 0], i, 4}]), - ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.1.5:3 - %% The standard is quite incorrect here. The resp pdu was too big. In - %% the resp pdu, we have the original vbs. In the tooBig pdu we still - %% have to original vbs => the tooBig pdu is too big as well!!! It - %% may not get it to the manager, unless the agent uses 'NULL' instead - %% of the std-like original value. - s([{[tTooBig, 0], s, ?tooBigStr}]), - %% according to std: -% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]), - - %% 4.1.5:4 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), - s([{[tDescr2, 0], s, "commit_fail"}]), - ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]). - -%% Req. Test2 -v2_proc() -> - %% According to RFC1905. - %% Template:
    : - ?DBG("v2_proc -> entry",[]), - v2_get_p(), - v2_get_next_p(), - v2_get_bulk_p(), - v2_set_p(). - -v2_get_p() -> - %% 4.2.1:2 - ?DBG("v2_get_p -> entry",[]), - g([[test2]]), - ?line expect(10, [{[test2], noSuchObject}]), - g([[tDescr]]), - ?line expect(11, [{[tDescr], noSuchObject}]), - g([[tDescr4,0]]), - ?line expect(12, [{[tDescr4,0], noSuchObject}]), - g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}, - {[tDescr,0], noSuchObject}]), - g([[tTable]]), - ?line expect(14, [{[tTable], noSuchObject}]), - g([[tEntry]]), - ?line expect(15, [{[tEntry], noSuchObject}]), - - %% 4.2.1:3 - g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line expect(20, [{[tDescr2,0], noSuchInstance}]), - g([[tDescr3,0]]), - ?line expect(21, [{[tDescr3,0], noSuchInstance}]), - g([[sysDescr,3]]), - ?line expect(22, [{[sysDescr, 3], noSuchInstance}]), - g([[tIndex,1]]), - ?line expect(23, [{[tIndex, 1], noSuchInstance}]), - - %% 4.2.1 - any other error: genErr - g([[tGenErr1, 0]]), - ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]), - g([[tGenErr2, 0]]), - ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]), - g([[sysDescr, 0], [tGenErr3, 0]]), - ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'}, - {[tGenErr3, 0], 'NULL'}]), - - %% 4.2.1 - tooBig - g([[tTooBig, 0]]), - ?line expect(40, tooBig, 0, []). - - -v2_get_next_p() -> - %% 4.2.2:2 - ?DBG("v2_get_next_p -> entry",[]), - gn([[1,3,7,1]]), - ?line expect(10, [{[1,3,7,1], endOfMibView}]), - gn([[sysDescr], [1,3,7,1]]), - ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gn([[tCnt2, 1]]), - ?line expect(12, [{[tCnt2,2], 100}]), - gn([[tCnt2, 2]]), - ?line expect(12, [{[tCnt2,2], endOfMibView}]), - - %% 4.2.2 - any other error: genErr - gn([[tGenErr1]]), - ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]), - gn([[tGenErr2]]), - ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]), - gn([[sysDescr], [tGenErr3]]), - ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'}, - {[tGenErr3], 'NULL'}]), - - %% 4.2.2 - tooBig - gn([[tTooBig]]), - ?line expect(20, tooBig, 0, []). - -v2_get_bulk_p() -> - %% 4.2.3 - ?DBG("v2_get_bulk_p -> entry",[]), - gb(1, 1, []), - ?line expect(10, []), - gb(-1, 1, []), - ?line expect(11, []), - gb(-1, -1, []), - ?line expect(12, []), - gb(-1, -1, []), - ?line expect(13, []), - gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}]), - gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysDescr, 0], "Erlang SNMP agent"}, - {[1,3,7,1], endOfMibView}, - {[sysObjectID, 0], [1,2,3]}, - {[1,3,7,1], endOfMibView}]), - - gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"}, - {[sysDescr, 0], "Erlang SNMP agent"}]), - - gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line expect(19, []), - - gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'}, - {[sysObjectID], 'NULL'}, - {[tGenErr1], 'NULL'}, - {[sysDescr], 'NULL'}]), - gb(0, 2, [[tCnt2, 1]]), - ?line expect(21, [{[tCnt2,2], 100}, - {[tCnt2,2], endOfMibView}]). - - -v2_set_p() -> - %% 4.2.5:1 - ?DBG("v2_set_p -> entry",[]), - s([{[1,3,7,0], i, 4}]), - ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]), - s([{[tDescr,0], s, "outside mibview"}]), - ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]), - - %% 4.2.5:2 - s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), - - %% 4.2.5:3 - s([{[tDescr2, 0], i, 4}]), - ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]), - s([{[tDescr2, 0], s, "badValue"}]), - ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]), - - %% 4.2.5:4 - s([{[tStr, 0], s, ""}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]), - s([{[tStr, 0], s, "12345"}]), - ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]), - - %% 4.2.5:5 - N/A - - %% 4.2.5:6 - s([{[tInt1, 0], i, 0}]), - ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]), - s([{[tInt1, 0], i, 5}]), - ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]), - s([{[tInt2, 0], i, 0}]), - ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]), - s([{[tInt2, 0], i, 5}]), - ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]), - s([{[tInt3, 0], i, 5}]), - ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]), - - %% 4.2.5:7 - s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), - - %% 4.2.5:8 - s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line expect(80, inconsistentName, 1, - [{[tDescrX, 1, 2], "inconsistentName"}]), - - %% 4.2.5:9 - s([{[tCnt, 1, 2], i, 5}]), - ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]), - s([{[tDescr3,0], s, "read-only"}]), - ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]), - - %% 4.2.5:10 - s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line expect(100, inconsistentValue, 1, - [{[tDescr2,0], "inconsistentValue"}]), - - %% 4.2.5:11 - s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line expect(110, resourceUnavailable, 1, - [{[tDescr2,0],"resourceUnavailable"}]), - - %% 4.2.5:12 - s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). - - %% commitFailed and undoFailed is tested by the 'undo' case. - - -%% Req. OLD-SNMPEA-MIB -table_test() -> - io:format("Testing simple get, next and set on communityTable...~n"), -%% {[147,214,36,45], "public", 2, readWrite}. -%% {[147,214,36,45], "standard trap", 2, read}. - Key1c3 = [intCommunityViewIndex,get(mip),is("public")], - Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")], - Key1c4 = [intCommunityAccess,get(mip),is("public")], - EndKey = [intCommunityEntry,[9],get(mip),is("public")], - gn([[intCommunityEntry]]), - ?line expect(7, [{Key1c3, 2}]), - gn([[intCommunityTable]]), - ?line expect(71, [{Key1c3, 2}]), - gn([[community]]), - ?line expect(72, [{Key1c3, 2}]), - gn([[otpSnmpeaMIB]]), - ?line expect(73, [{Key1c3, 2}]), - gn([[ericsson]]), - ?line expect(74, [{Key1c3, 2}]), - gn([Key1c3]), - ?line expect(8, [{Key2c3, 2}]), - gn([Key2c3]), - ?line expect(9, [{Key1c4, 2}]), - gn([EndKey]), - AgentIp = [intAgentIpAddress,0], - ?line expect(10, [{AgentIp, any}]), - g([Key1c3]), - ?line expect(11, [{Key1c3, 2}]), - g([EndKey]), - ?line ?v1_2(expect(12, noSuchName, 1, any), - expect(12, [{EndKey, noSuchObject}])), - - io:format("Testing row creation/deletion on communityTable...~n"), - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - s([{NewKeyc5, ?createAndGo}]), - ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any), - s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), - g([NewKeyc4]), - ?line expect(16, [{NewKeyc4, 2}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(17, [{NewKeyc5, ?destroy}]), - s([{NewKeyc4, 2}]), - ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]), - s([{NewKeyc5, ?createAndWait}]), - ?line expect(19, [{NewKeyc5, ?createAndWait}]), - g([NewKeyc5]), - ?line expect(20, [{NewKeyc5, ?notReady}]), - s([{NewKeyc4, 2}]), - ?line expect(21, [{NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(22, [{NewKeyc5, ?notReady}]), - s([{NewKeyc3, 2}]), - ?line expect(23, [{NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(24, [{NewKeyc5, ?notInService}]), - s([{NewKeyc5, ?active}]), - ?line expect(25, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(26, [{NewKeyc5, ?destroy}]), - s([{NewKeyc3, 3}]), - ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]), - otp_1128(). - -%% Req. system group -simple_standard_test() -> - ?DBG("simple_standard_test -> entry",[]), - gn([[1,1]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3]]), - ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6]]), - ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1]]), - ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2]]), - ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1]]), - ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[1,3,6,1,2,1,1]]), - ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]), - gn([[sysDescr]]), - ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr,0]]), - ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]), - g([[sysDescr]]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{[sysDescr], noSuchObject}])), - g([[1,6,7,0]]), - ?line ?v1_2(expect(41, noSuchName, 1, any), - expect(3, [{[1,6,7,0], noSuchObject}])), - gn([[1,13]]), - ?line ?v1_2(expect(4, noSuchName,1, any), - expect(4, [{[1,13], endOfMibView}])), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - g([[sysLocation, 0]]), - ?line expect(6, [{[sysLocation, 0], "new_value"}]), - io:format("Testing noSuchName and badValue...~n"), - s([{[sysServices,0], 3}]), - ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any), - s([{[sysLocation, 0], i, 3}]), - ?line expect(62, ?v1_2(badValue, wrongType), 1, any), - ?DBG("simple_standard_test -> done",[]), - ok. - -%% This is run in the agent node -db_notify_client(suite) -> []; -db_notify_client(Config) when list(Config) -> - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p", - [SaNode,MgrNode,MibDir]), - snmpa_local_db:register_notify_client(self(),?MODULE), - - %% This call (the manager) will issue to set operations, so - %% we expect to receive to notify(insert) calls. - try_test(db_notify_client_test), - - ?DBG("await first notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok - end, - - ?DBG("await second notify",[]), - receive - {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok - end, - - snmpa_local_db:unregister_notify_client(self()). - - -%% This is run in the manager node -db_notify_client_test() -> - ?DBG("set first new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]), - - ?DBG("set second new sysLocation",[]), - s([{[sysLocation, 0], "new_value"}]), - ?line expect(5, [{[sysLocation, 0], "new_value"}]). - -notify(Pid,What) -> - ?DBG("notify(~p,~p) -> called",[Pid,What]), - Pid ! {db_notify_test_reply,What}. - - -%% Req: system group, OLD-SNMPEA-MIB, Klas1 -big_test() -> - ?DBG("big_test -> testing simple next/get/set @ master agent...",[]), - simple_standard_test(), - - ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), - gn([[klas1]]), - ?line expect(1, [{[fname,0], ""}]), - g([[fname,0]]), - ?line expect(2, [{[fname,0], ""}]), - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[fname,0]]), - ?line expect(4, [{[fname,0], "test set"}]), - - ?DBG("big_test -> " - "testing next from last instance in master to subagent...",[]), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname,0], "test set"}]), - s([{[fname,0], s, ""}]), - ?line expect(52, [{[fname,0], ""}]), - - table_test(), - - ?DBG("big_test -> adding one row in subagent table",[]), - _FTab = [friendsEntry], - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [friendsEntry, [3, 3]]]), - ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"}, - {[friendsEntry, [3, 3]], ?active}]), - s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]), - - otp_1131(), - - ?DBG("big_test -> adding two rows in subagent table with special INDEX", - []), - s([{[kompissEntry, [1, 3]], s, "kompis3"}, - {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?createAndGo}]), - g([[kompissEntry, [1, 3]], - [kompissEntry, [2, 3]]]), - ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - gn([[kompissEntry, [1]], - [kompissEntry, [2]]]), - ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"}, - {[kompissEntry, [2, 3]], ?active}]), - s([{[kompissEntry, [1, 2]], s, "kompis3"}, - {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?createAndGo}]), - gn([[kompissEntry, [1, 1]], - [kompissEntry, [2, 1]]]), - ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"}, - {[kompissEntry, [2, 2]], ?active}]), - s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]), - s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]), - ?DBG("big_test -> done",[]), - ok. - -%% Req. system group, Klas2, OLD-SNMPEA-MIB -big_test_2() -> - p("Testing simple next/get/set @ master agent (2)..."), - simple_standard_test(), - - p("Testing simple next/get/set @ subagent (2)..."), - gn([[klas2]]), - ?line expect(1, [{[fname2,0], ""}]), - g([[fname2,0]]), - ?line expect(2, [{[fname2,0], ""}]), - s([{[fname2,0], s, "test set"}]), - ?line expect(3, [{[fname2,0], "test set"}]), - g([[fname2,0]]), - ?line expect(4, [{[fname2,0], "test set"}]), - - otp_1298(), - - p("Testing next from last object in master to subagent (2)..."), - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(5, [{[fname2,0], "test set"}]), - gn([[1,1], - [?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"}, - {[fname2,0], "test set"}]), - - table_test(), - - p("Adding one row in subagent table (2)"), - _FTab = [friendsEntry2], - s([{[friendsEntry2, [2, 3]], s, "kompis3"}, - {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?createAndGo}]), - g([[friendsEntry2, [2, 3]], - [friendsEntry2, [3, 3]]]), - ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"}, - {[friendsEntry2, [3, 3]], ?active}]), - s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]), - - p("Adding two rows in subagent table with special INDEX (2)"), - s([{[kompissEntry2, [1, 3]], s, "kompis3"}, - {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?createAndGo}]), - g([[kompissEntry2, [1, 3]], - [kompissEntry2, [2, 3]]]), - ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - gn([[kompissEntry2, [1]], - [kompissEntry2, [2]]]), - ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"}, - {[kompissEntry2, [2, 3]], ?active}]), - s([{[kompissEntry2, [1, 2]], s, "kompis3"}, - {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?createAndGo}]), - gn([[kompissEntry2, [1, 1]], - [kompissEntry2, [2, 1]]]), - ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"}, - {[kompissEntry2, [2, 2]], ?active}]), - s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]), - s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]), - ok. - -%% Req. Test1 -multi_threaded_test() -> - p("Testing multi threaded agent..."), - g([[multiStr,0]]), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(1, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "pelle"}]), - ?line expect(2, [{[sysLocation, 0], "pelle"}]), - Pid ! continue, - ?line expect(3, [{[multiStr,0], "ok"}]), - - s([{[multiStr, 0], s, "block"}]), - Pid2 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(4, [{[sysUpTime,0], any}]), - g([[multiStr,0]]), - Pid3 = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(5, [{[sysUpTime,0], any}]), - s([{[sysLocation, 0], s, "kalle"}]), - Pid3 ! continue, - ?line expect(6, [{[multiStr,0], "ok"}]), - Pid2 ! continue, - ?line expect(7, [{[multiStr,0], "block"}]), - ?line expect(8, [{[sysLocation,0], "kalle"}]). - -%% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - snmpa:send_trap(MA, mtTrap, "standard trap"), - Pid = get_multi_pid(), - g([[sysUpTime,0]]), - ?line expect(2, [{[sysUpTime,0], any}]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - Pid ! continue, - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [2]}, - {[multiStr,0], "ok"}]). - - -get_multi_pid() -> - get_multi_pid(10). -get_multi_pid(0) -> - ?line ?FAIL(no_global_name); -get_multi_pid(N) -> - sleep(1000), - case global:whereis_name(snmp_multi_tester) of - Pid when pid(Pid) -> Pid; - _ -> get_multi_pid(N-1) - end. - -%% Req. Test1 -types_v2_test() -> - p("Testing v2 types..."), - - s([{[bits1,0], 2#10}]), - ?line expect(1, [{[bits1,0], ?str(2#10)}]), - g([[bits1,0]]), - ?line expect(2, [{[bits1,0], ?str(2#101)}]), - - s([{[bits2,0], 2#11000000110}]), - ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]), - g([[bits2,0]]), - ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]), - - g([[bits3,0]]), - ?line expect(50, genErr, 1, any), - - g([[bits4,0]]), - ?line expect(51, genErr, 1, any), - - s([{[bits1,0], s, [2#10]}]), - ?line expect(6, ?v1_2(badValue, wrongValue), 1, any), - - s([{[bits2,0], 2#11001001101010011}]), - ?line expect(7, ?v1_2(badValue, wrongValue), 1, any). - - -%% Req. Test1 -implied_test(MA) -> - ?LOG("implied_test -> start",[]), - p("Testing IMPLIED..."), - - snmpa:verbosity(MA,trace), - snmpa:verbosity(MA,trace), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = "apa", - Idx2 = "qq", - ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line expect(1, [{[testStatus, Idx1], ?createAndGo}, - {[testDescr, Idx1], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line expect(2, [{[testStatus, Idx2], ?createAndGo}, - {[testDescr, Idx2], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr)",[]), - gn([[testDescr]]), - ?line expect(3, [{[testDescr,Idx1], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr) of row 1",[]), - gn([[testDescr,Idx1]]), - ?line expect(4, [{[testDescr,Idx2], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), - s([{[testStatus, Idx1], i, ?destroy}]), - ?line expect(5, [{[testStatus, Idx1], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), - s([{[testStatus, Idx2], i, ?destroy}]), - ?line expect(6, [{[testStatus, Idx2], ?destroy}]), - - %% Try the same in other table - Idx3 = [1, "apa"], - Idx4 = [1, "qq"], - ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line expect(1, [{[testStatus2, Idx3], ?createAndGo}, - {[testDescr2, Idx3], "row 1"}]), - ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line expect(2, [{[testStatus2, Idx4], ?createAndGo}, - {[testDescr2, Idx4], "row 2"}]), - ?DBG("implied_test -> get-next(testDescr2)",[]), - gn([[testDescr2]]), - ?line expect(3, [{[testDescr2,Idx3], "row 1"}]), - ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), - gn([[testDescr2,Idx3]]), - ?line expect(4, [{[testDescr2,Idx4], "row 2"}]), - - % Delete the rows - ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), - s([{[testStatus2, Idx3], i, ?destroy}]), - ?line expect(5, [{[testStatus2, Idx3], ?destroy}]), - ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), - s([{[testStatus2, Idx4], i, ?destroy}]), - ?line expect(6, [{[testStatus2, Idx4], ?destroy}]), - - snmpa:verbosity(MA,log), - - ?LOG("implied_test -> done",[]). - - - -%% Req. Test1 -sparse_table_test() -> - p("Testing sparse table..."), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - s([{[sparseStatus, Idx1], i, ?createAndGo}, - {[sparseDescr, Idx1], s, "row 1"}]), - ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo}, - {[sparseDescr, Idx1], "row 1"}]), - s([{[sparseStatus, Idx2], i, ?createAndGo}, - {[sparseDescr, Idx2], s, "row 2"}]), - ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo}, - {[sparseDescr, Idx2], "row 2"}]), - ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], - [sparseStatus,Idx1], [sparseStatus,Idx2]]), - gb(0,5,[[sparseIndex]])), - ?line expect(3, [{[sparseDescr,Idx1], "row 1"}, - {[sparseDescr,Idx2], "row 2"}, - {[sparseStatus,Idx1], ?active}, - {[sparseStatus,Idx2], ?active}, - {[sparseStr,0], "slut"}]), - % Delete the rows - s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]), - s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]). - - -%% Req. Test1 -cnt_64_test(MA) -> - ?LOG("start cnt64 test (~p)",[MA]), - snmpa:verbosity(MA,trace), - ?LOG("start cnt64 test",[]), - p("Testing Counter64, and at the same time, RowStatus is not last column"), - - ?DBG("get cnt64",[]), - g([[cnt64,0]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(1, noSuchName, 1, any), - expect(1, [{[cnt64,0],18446744073709551615}])), - ?DBG("get-next cnt64",[]), - gn([[cnt64]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]), - expect(2, [{[cnt64,0],18446744073709551615}])), - ?DBG("send cntTrap",[]), - snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"}, - {cnt64, 10}, - {sysLocation, "here"}]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"}, - {[sysLocation,0], "here"}]), - expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?testTrap ++ [1]}, - {[sysContact,0], "pelle"}, - {[cnt64,0], 10}, - {[sysLocation,0], "here"}])), - - %% Create two rows, check that they are get-nexted in correct order. - Idx1 = 1, - Idx2 = 2, - ?DBG("create row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]), - ?DBG("create row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?createAndGo}]), - ?DBG("await response",[]), - ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]), - - ?DBG("get-next (cntIndex)",[]), - gn([[cntIndex]]), - ?DBG("await response",[]), - ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]), - expect(3, [{[cntCnt,Idx1], 0}])), - % Delete the rows - ?DBG("delete row (cntStatus): ~p",[Idx1]), - s([{[cntStatus, Idx1], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(4, [{[cntStatus, Idx1], ?destroy}]), - ?DBG("delete row (cntStatus): ~p",[Idx2]), - s([{[cntStatus, Idx2], i, ?destroy}]), - ?DBG("await response",[]), - ?line expect(5, [{[cntStatus, Idx2], ?destroy}]), - catch snmpa:verbosity(MA,log), - ?DBG("done",[]), - ok. - -%% Req. Test1 -opaque_test() -> - p("Testing Opaque datatype..."), - g([[opaqueObj,0]]), - ?line expect(1, [{[opaqueObj,0], "opaque-data"}]). - -%% Req. OLD-SNMPEA-MIB -api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, - oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, - int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, - enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of - List when list(List), length(List) == 8 -> ok; - List when list(List), length(List) == 11 -> ok - end. - -%% Req. Klas3 -api_test2() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]), - g([[fname4,0]]), - ?line expect(2, [{[fname4,0], 1}]). - -api_test3() -> - g([[fname3,0]]), - ?line expect(1, [{[fname3,0], "ok"}]). - - -unreg_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[snmpInPkts, 0], any}]). - -load_test() -> - gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line expect(1, [{[fname,0], ""}]). - -%% Req. Klas1 -load_test_sa() -> - gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line expect(1, [{[fname,0], any}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_get() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0], Key1c4, [fname,0],Key1c3, - [sysName,0]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,0], "test"}]), - g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(expect(2, noSuchName, [1,4], any), - expect(2, [{[1,3,7,1], noSuchObject}, - {Key1c4, 2}, - {[sysDescr,0], "Erlang SNMP agent"}, - {[1,3,7,2], noSuchObject}, - {Key1c3, 2}, - {[sysDescr,0], "Erlang SNMP agent"}])). - -%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3. -do_mul_get_err() -> - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(expect(1, noSuchName, 5, any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname,0], "test set"}, - {Key1c3, 2}, - {[sysName,2], noSuchInstance}])), - g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[fname3,0], noSuchObject}, - {Key1c3, 2}, - {[sysName,1], noSuchInstance}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, {[fname,0], "test set"}, - {Key1c3, 2}, {[sysName,0], "test"}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_next_err() -> - Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")], - Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")], - Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], - Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], - s([{[fname,0], s, "test set"}]), - ?line expect(3, [{[fname,0], "test set"}]), - gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(expect(1, noSuchName, [3,5], any), - expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {Key1c4, 2}, - {[1,3,6,999], endOfMibView}, - {[fname,0], "test set"}, - {[1,3,90], endOfMibView}, - {Key1c3, 2}, - {[sysName,0], "test"}])). - - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set() -> - p("Adding one row in subagent table, and one in master table"), - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"}, - {NewKeyc3, 2}, - {[sysLocation,0], "new_value"}, - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - g([[friendsEntry, [2, 3]], - [sysLocation,0], - [friendsEntry, [3, 3]]]), - ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"}, - {[sysLocation,0], "new_value"}, - {[friendsEntry, [3, 3]], ?active}]), - g([NewKeyc4]), - ?line expect(3, [{NewKeyc4, 2}]), - s([{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]), - ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy}, - {NewKeyc5, ?destroy}]). - -%% Req. system group, Klas1, OLD-SNMPEA-MIB -do_mul_set_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - p("Adding one row in subagent table, and one in master table"), - s([{[friendsEntry, [2, 3]], s, "kompis3"}, - {NewKeyc3, 2}, - {[sysUpTime,0], 45}, % sysUpTime (readOnly) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}, - {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any), - g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])), - g([NewKeyc4]), - ?line ?v1_2(expect(3, noSuchName, 1, any), - expect(3, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB -sa_mib() -> - g([[sa, [2,0]]]), - ?line expect(1, [{[sa, [2,0]], 3}]), - s([{[sa, [1,0]], s, "sa_test"}]), - ?line expect(2, [{[sa, [1,0]], "sa_test"}]). - -ma_trap1(MA) -> - snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]), - snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}]). - -ma_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]). - -ma_v2_2_v1_trap2(MA) -> - snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, - {ifAdminStatus, [1], 1}, - {ifOperStatus, [1], 2}]), - ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, - {[ifAdminStatus, 1], 1}, - {[ifOperStatus, 1], 2}]). - -sa_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]], - "pelle"}, - {[sa, [1,0]], "sa_test"}]). - -sa_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}]). - -ma_v2_trap1(MA) -> - ?DBG("ma_v2_traps -> entry with MA = ~p => " - "send standard trap: testTrapv22",[MA]), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line expect(1, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), - snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmp ++ [1]}]). - -ma_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). - -%% Note: This test case takes a while... actually a couple of minutes. -ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform -> entry with MA = ~p => " - "send notification: testTrapv22",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag1, self()}, - "standard inform", []), - ?line expect(1, {inform, true}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag1, [_]} -> - ok; - {snmp_targets, tag1, Addrs1} -> - ?line ?FAIL({bad_addrs, Addrs1}) - after - 5000 -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag1, {got_response, _}} -> - ok; - {snmp_notification, tag1, {no_response, _}} -> - ?line ?FAIL(no_response) - after - 20000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag1) timeout",[]), - ?line ?FAIL(nothing_at_all) - end, - - %% - %% -- The rest is possibly erroneous... - %% - - ?DBG("ma_v2_inform -> send notification: testTrapv22",[]), - snmpa:send_notification(MA, testTrapv22, {tag2, self()}, - "standard inform", []), - ?line expect(2, {inform, false}, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("ma_v2_inform -> await targets",[]), - receive - {snmp_targets, tag2, [_]} -> - ok; - {snmp_targets, tag2, Addrs2} -> - ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]), - ?line ?FAIL({bad_addrs, Addrs2}) - after - 5000 -> - ?line ?FAIL(nothing_at_all) - end, - ?DBG("ma_v2_inform -> await notification",[]), - receive - {snmp_notification, tag2, {got_response, _}} -> - ?line ?FAIL(got_response); - {snmp_notification, tag2, {no_response, _}} -> - ok - after - 240000 -> - ?ERR("ma_v2_inform1 -> " - "awaiting snmp_notification(tag2) timeout",[]), - ?line ?FAIL(nothing_at_all) - end. - - -ma_v1_2_v2_trap(MA) -> - snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line expect(2, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, - {[ifIndex, 1], 1}, - {[snmpTrapEnterprise, 0], [1,2,3]}]). - - -ma_v1_2_v2_trap2(MA) -> - snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line expect(3, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}, - {[snmpTrapEnterprise, 0], ?system}]). - - -sa_v1_2_v2_trap1(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap"), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - -sa_v1_2_v2_trap2(SA) -> - snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, - {[system, [4,0]], "pelle"}, - {[sa, [1,0]], "sa_test"}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -sa_v1_2_v2_trap3(SA) -> - snmpa:send_trap(SA, saTrap2, "standard trap", - [{intViewSubtree, [4], [1,2,3,4]}]), - ?line expect(4, v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, - {[system, [4,0]], - "{mbj,eklas}@erlang.ericsson.se"}, - {[sa, [1,0]], "sa_test"}, - {[intViewSubtree,4],[1,2,3,4]}, - {[snmpTrapEnterprise, 0], ?ericsson}]). - - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_bad_value() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2}, - {[sa, [2,0]], 5}, % badValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, badValue, 2, any), - s([{NewKeyc3, 2}, - {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) - {NewKeyc5, ?createAndGo}, - {NewKeyc4, 2}]), - ?line expect(1, ?v1_2(badValue, wrongValue), 2, any), - g([NewKeyc4]), - ?line ?v1_2(expect(2, noSuchName, 1, any), - expect(2, [{NewKeyc4, noSuchInstance}])). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_errs_gen_err() -> - NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")], - NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")], - NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], - s([{NewKeyc3, 2},{NewKeyc4, 2}, - {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line expect(1, genErr, 4, any), -% The row might have been added; we don't know. -% (as a matter of fact we do - it is added, because the agent -% first sets its own vars, and then th SAs. Lets destroy it. - s([{NewKeyc5, ?destroy}]), - ?line expect(2, [{NewKeyc5, ?destroy}]). - -%% Req. SA-MIB, OLD-SNMPEA-MIB -sa_too_big() -> - g([[sa, [4,0]]]), - ?line expect(1, tooBig). - -%% Req. Klas1, system group, snmp group (v1/v2) -next_across_sa() -> - gn([[sysDescr],[klas1,5]]), - ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}, - {[snmpInPkts, 0], any}]). - -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2} -%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1} -%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2} -%% Req. Klas3, Klas4 -undo_test() -> - s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any), - s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line expect(3, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line expect(4, ?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. -% it depends on which order the agent traverses the varbind list. -% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), - s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line expect(6, genErr, 2, any). - -%% Req. Klas3, Klas4 -bad_return() -> - g([[fStatus4,4], - [fName4,4]]), - ?line expect(4, genErr, 2, any), - g([[fStatus4,5], - [fName4,5]]), - ?line expect(5, genErr, 1, any), - g([[fStatus4,6], - [fName4,6]]), - ?line expect(6, genErr, 2, any), - gn([[fStatus4,7], - [fName4,7]]), - ?line expect(7, genErr, 2, any), - gn([[fStatus4,8], - [fName4,8]]), - ?line expect(8, genErr, 1, any), - gn([[fStatus4,9], - [fName4,9]]), - ?line expect(9, genErr, 2, any). - - -%%%----------------------------------------------------------------- -%%% Test the implementation of standard mibs. -%%% We should *at least* try to GET all variables, just to make -%%% sure the instrumentation functions work. -%%% Note that many of the functions in the standard mib is -%%% already tested by the normal tests. -%%%----------------------------------------------------------------- - - - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v1. -%% o Test the counters and control objects in SNMP-STANDARD-MIB -%%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; -snmp_standard_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?DBG("snmp_standard_mib -> std_mib_init", []), - try_test(std_mib_init), - - ?DBG("snmp_standard_mib -> std_mib_a", []), - InBadVsns = try_test(std_mib_a), - put(vsn, v2), - ?DBG("snmp_standard_mib -> std_mib_read", []), - try_test(std_mib_read), - put(vsn, v1), - - ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]), - Bad = try_test(std_mib_b, [InBadVsns]), - ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []), - try_test(std_mib_read, [], [{community, "bad community"}]), - ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []), - try_test(std_mib_write, [], [{community, "public"}]), - ?DBG("snmp_standard_mib -> std_mib_asn_err", []), - try_test(std_mib_asn_err), - ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]), - try_test(std_mib_c, [Bad]), - ?DBG("snmp_standard_mib -> std_mib_a", []), - try_test(standard_mib_a), - - ?DBG("snmp_standard_mib -> std_mib_finish", []), - try_test(std_mib_finish), - ?DBG("snmp_standard_mib -> std_mib_test_finish", []), - try_test(standard_mib_test_finish, [], [{community, "bad community"}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, - %% There are some more counters we could test here, but it's not that - %% important, since they are removed from SNMPv2-MIB. - ok. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_init() -> - %% disable authentication failure traps. (otherwise w'd get many of - %% them - this is also a test to see that it works). - s([{[snmpEnableAuthenTraps,0], 2}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_finish() -> - %% enable again - s([{[snmpEnableAuthenTraps,0], 1}]), - ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]). - -%% Req. SNMP-STANDARD-MIB -standard_mib_test_finish() -> - %% force a authenticationFailure - std_mib_write(), - %% check that we got a trap - ?line expect(2, trap, [1,2,3], 4, 0, []). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_read() -> - ?DBG("std_mib_read -> entry", []), - g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply - ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line expect(1, timeout). % make sure we don't get a trap! - - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_write() -> - ?DBG("std_mib_write -> entry", []), - s([{[sysLocation, 0], "new_value"}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_asn_err() -> - snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]). - -%%----------------------------------------------------------------- -%% For this test, the agent is configured for v2 and v3. -%% o Test the counters and control objects in SNMPv2-MIB -%%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; -snmpv2_mib_2(Config) when list(Config) -> - ?LOG("snmpv2_mib_2 -> start",[]), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?DBG("snmpv2_mib_2 -> standard mib init",[]), - try_test(std_mib_init), - - ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]), - InBadVsns = try_test(std_mib_a), - - ?DBG("snmpv2_mib_2 -> make a bad version read",[]), - put(vsn, v1), - try_test(std_mib_read), - - ?DBG("snmpv2_mib_2 -> bad version read",[]), - put(vsn, v2), - Bad = try_test(std_mib_b, [InBadVsns]), - - ?DBG("snmpv2_mib_2 -> read with bad community",[]), - try_test(std_mib_read, [], [{community, "bad community"}]), - - ?DBG("snmpv2_mib_2 -> write with public community",[]), - try_test(std_mib_write, [], [{community, "public"}]), - - ?DBG("snmpv2_mib_2 -> asn err",[]), - try_test(std_mib_asn_err), - - ?DBG("snmpv2_mib_2 -> check counters",[]), - try_test(std_mib_c, [Bad]), - - ?DBG("snmpv2_mib_2 -> get som counters",[]), - try_test(snmpv2_mib_a), - - ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), - try_test(std_mib_finish), - - ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, " - "then disable auth traps",[]), - try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]), - - ?LOG("snmpv2_mib_2 -> done",[]). - -%% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; -snmpv2_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - InBadVsns = try_test(std_mib_a), - put(vsn, v1), - try_test(std_mib_read), - put(vsn, v3), - _Bad = try_test(std_mib_b, [InBadVsns]), - try_test(snmpv2_mib_a), - - try_test(std_mib_finish). - --define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]). - -%% Req. SNMPv2-MIB -snmpv2_mib_test_finish() -> - %% force a authenticationFailure - ?DBG("ma_v2_inform -> write to std mib",[]), - std_mib_write(), - - %% check that we got a trap - ?DBG("ma_v2_inform -> await trap",[]), - ?line expect(2, v2trap, [{[sysUpTime,0], any}, - {[snmpTrapOID,0], ?authenticationFailure}]), - - %% and the the inform - ?DBG("ma_v2_inform -> await inform",[]), - ?line expect(2, {inform,true}, [{[sysUpTime,0], any}, - {[snmpTrapOID,0],?authenticationFailure}]). - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), - InBadVsns. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = - get_req(4, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - {InBadCommunityNames, InBadCommunityUses, InASNErrs}. - -%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB -std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = - get_req(1, [[snmpInBadCommunityNames,0], - [snmpInBadCommunityUses,0], - [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. - -%% Req. SNMPv2-MIB -snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), - s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line expect(3, [{[snmpSetSerialNo,0], SetSerial}, - {[sysLocation, 0], "val2"}]), - s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line expect(4, inconsistentValue, 2, - [{[sysLocation, 0], "val3"}, - {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]). - - -%%----------------------------------------------------------------- -%% o Bad community uses/name is tested already -%% in SNMPv2-MIB and STANDARD-MIB. -%% o Test add/deletion of rows. -%%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; -snmp_community_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - try_test(snmp_community_mib), - ?line unload_master("SNMP-COMMUNITY-MIB"). - -snmp_community_mib_2(X) -> snmp_community_mib(X). - -%% Req. SNMP-COMMUNITY-MIB -snmp_community_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o Test engine boots / time -%%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; -snmp_framework_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - try_test(snmp_framework_mib), - ?line unload_master("SNMP-FRAMEWORK-MIB"). - -snmp_framework_mib_2(X) -> snmp_framework_mib(X). - -snmp_framework_mib_3(suite) -> []; -snmp_framework_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(snmp_framework_mib). - - -%% Req. SNMP-FRAMEWORK-MIB -snmp_framework_mib() -> - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), - sleep(5000), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), - if - EngineTime+7 < EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - EngineTime+4 > EngineTime2 -> - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); - true -> ok - end, - ?line case get_req(4, [[snmpEngineBoots,0]]) of - [Boots] when integer(Boots) -> ok; - Else -> ?FAIL(Else) - end, - ok. - -%%----------------------------------------------------------------- -%% o Test the counters -%%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; -snmp_mpd_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - UnknownPDUHs = try_test(snmp_mpd_mib_a), - try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]), - try_test(snmp_mpd_mib_c, [UnknownPDUHs]). - - -%% Req. SNMP-MPD-MIB -snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0]]), - Pdu = #pdu{type = 'get-request', - request_id = 23, - error_status = noError, - error_index = 0, - varbinds = []}, - SPdu = #scopedPdu{contextEngineID = "agentEngine", - contextName = "", - data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), - V3Hdr1 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [7], - msgSecurityModel = 23, % bad sec model - msgSecurityParameters = []}, - V3Hdr2 = #v3_hdr{msgID = 21, - msgMaxSize = 484, - msgFlags = [6], % bad flag combination - msgSecurityModel = 3, - msgSecurityParameters = []}, - Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1, - data = SPDUBytes}, - Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, - data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), - snmp_test_mgr:send_bytes(MsgBytes1), - snmp_test_mgr:send_bytes(MsgBytes2), - - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = - get_req(1, [[snmpUnknownSecurityModels,0], - [snmpInvalidMsgs,0], - [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, - UnknownPDUHs. - --define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). -snmp_mpd_mib_b() -> - g([[sysUpTime,0]]), - ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]). - - -snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1. - - -snmp_target_mib(suite) -> []; -snmp_target_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), - try_test(snmp_target_mib), - ?line unload_master("SNMP-TARGET-MIB"). - -snmp_target_mib_2(X) -> snmp_target_mib(X). - -snmp_target_mib_3(X) -> snmp_target_mib(X). - -snmp_target_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -snmp_notification_mib(suite) -> []; -snmp_notification_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - try_test(snmp_notification_mib), - ?line unload_master("SNMP-NOTIFICATION-MIB"). - -snmp_notification_mib_2(X) -> snmp_notification_mib(X). - -snmp_notification_mib_3(X) -> snmp_notification_mib(X). - -snmp_notification_mib() -> - ?INF("NOT YET IMPLEMENTED", []), - nyi. - -%%----------------------------------------------------------------- -%% o add/delete views and try them -%% o try boundaries -%%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; -snmp_view_based_acm_mib(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), - snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X). - -snmp_view_based_acm_mib() -> - snmpa:verbosity(net_if,trace), - snmpa:verbosity(master_agent,trace), - ?LOG("start snmp_view_based_acm_mib test",[]), - %% The user "no-rights" is present in USM, and is mapped to security - %% name 'no-rights", which is not present in VACM. - %% So, we'll add rights for it, try them and delete them. - %% We'll give "no-rights" write access to tDescr.0 and read access - %% to tDescr2.0 - %% These are the options we'll use to the mgr - Opts = [{user, "no-rights"}, {community, "no-rights"}], - %% Find the valid secmodel, and one invalid secmodel. - {SecMod, InvSecMod} = - case get(vsn) of - v1 -> {?SEC_V1, ?SEC_V2C}; - v2 -> {?SEC_V2C, ?SEC_USM}; - v3 -> {?SEC_USM, ?SEC_V1} - end, - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Now, add a mapping from "no-rights" -> "no-rights-group" - GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], - GRow1 = - [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, - {GRow1Status, ?createAndGo}], - ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Create a mapping for another sec model, and make sure it dosn't - %% give us access - GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], - GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, - {GRow2Status, ?createAndGo}], - - ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), - - ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [GRow2Status]), - - RVName = "rv_name", - WVName = "wv_name", - - %% Access row - ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1], - ARow1Status = [vacmAccessStatus, ARow1Idx], - ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1}, - {[vacmAccessReadViewName, ARow1Idx], RVName}, - {[vacmAccessWriteViewName, ARow1Idx], WVName}, - {ARow1Status, ?createAndGo}], - - %% This access row would give acces, if InvSecMod was valid. - ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], - ARow2Status = [vacmAccessStatus, ARow2Idx], - ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, - {[vacmAccessReadViewName, ARow2Idx], "internet"}, - {[vacmAccessWriteViewName, ARow2Idx], "internet"}, - {ARow2Status, ?createAndGo}], - - ?line try_test(do_set, [ARow2]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete that row - ?line try_test(del_row, [ARow2Status]), - - - %% Add valid row - ?line try_test(do_set, [ARow1]), - - ?line try_test(use_no_rights, [], Opts), - - %% Create the view family - VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access - VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access - VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access - VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access - VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx], - VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx], - VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], - VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), - - %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), - - %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), - - %% We should still have access... - ?line try_test(use_rights, [], Opts), - - %% Delete rows - ?line try_test(del_row, [GRow1Status]), - - ?line try_test(use_no_rights, [], Opts), - - %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), - - ?line try_test(use_no_rights, [], Opts), - snmpa:verbosity(master_agent,log). - -do_set(Row) -> - s(Row), - expect(1, Row). - -add_row(RowStatus) -> - s([{RowStatus, ?createAndGo}]), - expect(1, [{RowStatus, ?createAndGo}]). - -del_row(RowStatus) -> - s([{RowStatus, ?destroy}]), - expect(1, [{RowStatus, ?destroy}]). - - - -use_no_rights() -> - g([[xDescr,0]]), - ?v1_2_3(expect(11, noSuchName, 1, any), - expect(12, [{[xDescr,0], noSuchObject}]), - expect(13, authorizationError, 1, any)), - g([[xDescr2,0]]), - ?v1_2_3(expect(21, noSuchName, 1, any), - expect(22, [{[xDescr2,0], noSuchObject}]), - expect(23, authorizationError, 1, any)), - gn([[xDescr]]), - ?v1_2_3(expect(31, noSuchName, 1, any), - expect(32, [{[xDescr], endOfMibView}]), - expect(33, authorizationError, 1, any)), - s([{[xDescr,0], "tryit"}]), - ?v1_2_3(expect(41, noSuchName, 1, any), - expect(42, noAccess, 1, any), - expect(43, authorizationError, 1, any)). - - -use_rights() -> - g([[xDescr,0]]), - expect(1, [{[xDescr,0], any}]), - g([[xDescr2,0]]), - expect(2, [{[xDescr2,0], any}]), - s([{[xDescr,0], "tryit"}]), - expect(3, noError, 0, any), - g([[xDescr,0]]), - expect(4, [{[xDescr,0], "tryit"}]). - -mk_ln(X) -> - [length(X) | X]. - -%%----------------------------------------------------------------- -%% o add/delete users and try them -%% o test all secLevels -%% o test all combinations of protocols -%% o try bad ops; check counters -%%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; -snmp_user_based_sm_mib_3(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - _AgentDir = ?config(agent_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - - %% The newUser used here already has VACM access. - - %% Add a new user in the simplest way; just createAndGo - try_test(v3_sync, [[{usm_add_user1, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new user - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), - DesKey1 = lists:sublist(ShaKey1, 16), - - %% Change the new user's keys - 1 - try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - - ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), - DesKey2 = lists:sublist(ShaKey2, 16), - - %% Change the new user's keys - 2 - ?line try_test(v3_sync, - [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], - [{sec_level, authPriv}, {user, "newUser"}]), - - %% Try to use the new keys - reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Change the new user's keys - 3 - ?line try_test(v3_sync, - [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), - try_test(v3_sync, [[{usm_use_user, []}]], - [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), - reset_usm_mgr(MgrDir), - - %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], - [{sec_level, authPriv}, {user, "privDES"}]), - - ?line unload_master("SNMP-USER-BASED-SM-MIB"). - --define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). - -usm_add_user1() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - -usm_use_user() -> - v2_proc(). - - -%% Change own public keys -usm_key_change1(ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_shaxxxxxxxxxx", - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - "passwd_desxxxxxx", - DesKey), - Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change own private keys -usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs1), - ?line expect(1, Vbs1). - -%% Change other's public keys -usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldShaKey, - ShaKey), - DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha, - OldDesKey, - DesKey), - Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], - s(Vbs1), - ?line expect(1, noAccess, 1, any), - Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs2), - ?line expect(2, noAccess, 1, any), - - - Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, - {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], - s(Vbs3), - ?line expect(1, Vbs3). - -usm_read() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], - [usmUserCloneFrom, NewRowIndex], - [usmUserAuthKeyChange, NewRowIndex], - [usmUserOwnAuthKeyChange, NewRowIndex], - [usmUserPrivKeyChange, NewRowIndex], - [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line expect(1, - [{[usmUserSecurityName, NewRowIndex], "newUser"}, - {[usmUserCloneFrom, NewRowIndex], [0,0]}, - {[usmUserAuthKeyChange, NewRowIndex], ""}, - {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, - {[usmUserPrivKeyChange, NewRowIndex], ""}, - {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]), - ok. - - - -usm_del_user() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line expect(1, Vbs1), - ok. - --define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). - --define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]). - --define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]). - --define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]). - --define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]). - --define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]). - -usm_bad() -> - NewRowIndex = [11,"agentEngine", 7, "newUser"], - RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], - Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line expect(1, inconsistentName, 1, any), - - RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line expect(2, wrongValue, 1, any), - - RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], - Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, - {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line expect(3, Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line expect(4, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line expect(5, inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line expect(6, wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line expect(7, wrongValue, 1, any), - - Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line expect(1, Vbs4), - - ok. - - -%%----------------------------------------------------------------- -%% Loop through entire MIB, to make sure that all instrum. funcs -%% works. -%% Load all std mibs that are not loaded by default. -%%----------------------------------------------------------------- -loop_mib(suite) -> []; -loop_mib(Config) when list(Config) -> - ?LOG("loop_mib -> initiate case",[]), - %% snmpa:verbosity(master_agent,debug), - %% snmpa:verbosity(mib_server,info), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), - ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?DBG("loop_mib -> try",[]), - try_test(loop_mib_1), - ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), - ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - %% snmpa:verbosity(master_agent,log), - %% snmpa:verbosity(mib_server,silence), - ?LOG("loop_mib -> done",[]). - - -loop_mib_2(suite) -> []; -loop_mib_2(Config) when list(Config) -> - ?LOG("loop_mib_2 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_2 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?LOG("loop_mib_2 -> done",[]). - - -loop_mib_3(suite) -> []; -loop_mib_3(Config) when list(Config) -> - ?LOG("loop_mib_3 -> initiate case",[]), - {SaNode, MgrNode, MibDir} = init_case(Config), - ?DBG("loop_mib_3 -> ~n" - "\tSaNode: ~p~n" - "\tMgrNode: ~p~n" - "\tMibDir: ~p",[SaNode, MgrNode, MibDir]), - ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - try_test(loop_mib_2), - ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?LOG("loop_mib_3 -> done",[]). - - -%% Req. As many mibs all possible -loop_mib_1() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_1([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_1(Oid, N) -> - ?DBG("loop_it_1 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_1 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_1 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_1(NOid, N+1); - #pdu{type='get-response', error_status=noSuchName, error_index=1, - varbinds=[_]} -> - ?DBG("loop_it_1 -> done",[]), - N; - - #pdu{type = Type, error_status = Err, error_index = Idx, - varbinds = Vbs} -> - exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs}) - end. - -%% Req. As many mibs all possible -loop_mib_2() -> - ?DBG("loop_mib_1 -> entry",[]), - N = loop_it_2([1,1], 0), - io:format(user, "found ~w varibles\n", [N]), - ?line N = if N < 100 -> 100; - true -> N - end. - - -loop_it_2(Oid, N) -> - ?DBG("loop_it_2 -> entry with~n" - "\tOid: ~p~n" - "\tN: ~p",[Oid,N]), - case get_next_req([Oid]) of - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid, value = endOfMibView}]} -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p",[NOid]), - N; - #pdu{type='get-response', error_status=noError, error_index=0, - varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid -> - ?DBG("loop_it_2 -> ~n" - "\tNOid: ~p~n" - "\tValue: ~p",[NOid,Value]), - ?line [Value2] = get_req(1, [NOid]), % must not be same - ?DBG("loop_it_2 -> ~n" - "\tValue2: ~p",[Value2]), - loop_it_2(NOid, N+1) - end. - - -%%%----------------------------------------------------------------- -%%% Testing of reported bugs and other tickets. -%%%----------------------------------------------------------------- - - - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - -%%----------------------------------------------------------------- -%% Ticket: OTP-1128 -%% Slogan: Bug in handling of createAndWait set-requests. -%%----------------------------------------------------------------- -otp_1128(suite) -> []; -otp_1128(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1128), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1128_2(X) -> otp_1128(X). - -otp_1128_3(X) -> otp_1128(X). - -otp_1128() -> - io:format("Testing bug reported in ticket OTP-1128...~n"), - - NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")], - NewKeyc4 = [intCommunityAccess,get(mip),is("test")], - NewKeyc5 = [intCommunityStatus,get(mip),is("test")], - - s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - g([NewKeyc5]), - ?line expect(29, [{NewKeyc5, ?notReady}]), - s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]), - g([NewKeyc5]), - ?line expect(31, [{NewKeyc5, ?active}]), - s([{NewKeyc5, ?destroy}]), - ?line expect(32, [{NewKeyc5, ?destroy}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1129, OTP-1169 -%% Slogan: snmpa:int_to_enum crashes on bad oids -%%----------------------------------------------------------------- -otp_1129(suite) -> []; -otp_1129(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"). - -otp_1129_2(X) -> otp_1129(X). - -otp_1129_3(X) -> otp_1129(X). - -otp_1129_i(MaNode) -> - io:format("Testing bug reported in ticket OTP-1129...~n"), - false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]), - false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1131 -%% Slogan: Agent crashes / erlang node halts if RowIndex in a -%% setrequest is of bad type, e.g. an INDEX {INTEGER}, -%% and RowIdenx [3,2]. -%%----------------------------------------------------------------- -otp_1131(suite) -> []; -otp_1131(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas1"), - try_test(otp_1131), - ?line unload_master("Klas1"). - -otp_1131_2(X) -> otp_1131(X). - -otp_1131_3(X) -> otp_1131(X). - -otp_1131() -> - io:format("Testing bug reported in ticket OTP-1131...~n"), - s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, - {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1162 -%% Slogan: snmp_agent can't handle wrongValue from instrum.func -%%----------------------------------------------------------------- -otp_1162(suite) -> []; -otp_1162(Config) when list(Config) -> - {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), - try_test(otp_1162), - stop_subagent(SA). - -otp_1162_2(X) -> otp_1162(X). - -otp_1162_3(X) -> otp_1162(X). - -otp_1162() -> - s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line expect(1, ?v1_2(badValue, wrongValue), 1, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1222 -%% Slogan: snmp agent crash if faulty index is returned from instrum -%%----------------------------------------------------------------- -otp_1222(suite) -> []; -otp_1222(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), - try_test(otp_1222), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"). - -otp_1222_2(X) -> otp_1222(X). - -otp_1222_3(X) -> otp_1222(X). - -otp_1222() -> - io:format("Testing bug reported in ticket OTP-1222...~n"), - s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line expect(1, genErr, 0, any), - s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line expect(2, genErr, 0, any). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1298 -%% Slogan: Negative INTEGER values are treated as positive. -%%----------------------------------------------------------------- -otp_1298(suite) -> []; -otp_1298(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1298), - ?line unload_master("Klas2"). - -otp_1298_2(X) -> otp_1298(X). - -otp_1298_3(X) -> otp_1298(X). - -otp_1298() -> - io:format("Testing bug reported in ticket OTP-1298...~n"), - s([{[fint,0], -1}]), - ?line expect(1298, [{[fint,0], -1}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1331 -%% Slogan: snmp_generic should return noError when deleting non-ex row -%%----------------------------------------------------------------- -otp_1331(suite) -> []; -otp_1331(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1331), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1331_2(X) -> otp_1331(X). - -otp_1331_3(X) -> otp_1331(X). - -otp_1331() -> - NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], - s([{NewKeyc5, ?destroy}]), - ?line expect(1, [{NewKeyc5, ?destroy}]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1338 -%% Slogan: snmp bug in initialisation of default values for mnesia tabs -%%----------------------------------------------------------------- -otp_1338(suite) -> []; -otp_1338(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas2"), - try_test(otp_1338), - ?line unload_master("Klas2"). - -otp_1338_2(X) -> otp_1338(X). - -otp_1338_3(X) -> otp_1338(X). - -otp_1338() -> - s([{[kStatus2, 7], i, ?createAndGo}]), - ?line expect(1, [{[kStatus2, 7], ?createAndGo}]), - g([[kName2, 7]]), - ?line expect(2, [{[kName2, 7], "JJJ"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-1342 -%% Slogan: default impl of snmp table can't handle bad index access, -%% Set when INDEX is read-write gets into an infinite loop! -%%----------------------------------------------------------------- -otp_1342(suite) -> []; -otp_1342(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Klas4"), - try_test(otp_1342), - ?line unload_master("Klas4"). - -otp_1342_2(X) -> otp_1342(X). - -otp_1342_3(X) -> otp_1342(X). - -otp_1342() -> - s([{[fIndex5, 1], i, 1}, - {[fName5, 1], i, 3}, - {[fStatus5, 1], i, ?createAndGo}]), - ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-1366 -%% Slogan: snmp traps not sent to all managers -%% Note: NYI! We need a way to tell the test server that we need -%% mgrs on two different machines. -%%----------------------------------------------------------------- -otp_1366(suite) -> []; -otp_1366(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_1366), - ?line unload_master("OLD-SNMPEA-MIB"). - -otp_1366_2(X) -> otp_1366(X). - -otp_1366_3(X) -> otp_1366(X). - -otp_1366() -> - ?INF("NOT YET IMPLEMENTED", []), - 'NYI'. - -%%----------------------------------------------------------------- -%% Ticket: OTP-2776 -%% Slogan: snmp:validate_date_and_time() fails when time is 00:00 -%%----------------------------------------------------------------- -otp_2776(suite) -> []; -otp_2776(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_2776). - -otp_2776_2(X) -> otp_2776(X). - -otp_2776_3(X) -> otp_2776(X). - -otp_2776() -> - io:format("Testing bug reported in ticket OTP-2776...~n"), - - Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0], - Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00 - Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0], - Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0], - Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0], - Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0], - Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2 - Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0], - Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4 - Dt10_invalid = [], - Dt11_invalid = [kalle,hobbe], - L = [{ 1, true, Dt01_valid}, - { 2, true, Dt02_valid}, - { 3, true, Dt03_valid}, - { 4, false, Dt04_invalid}, - { 5, true, Dt05_valid}, - { 6, true, Dt06_valid}, - { 7, false, Dt07_invalid}, - { 8, true, Dt08_valid}, - { 9, false, Dt09_invalid}, - {10, false, Dt10_invalid}, - {11, false, Dt11_invalid}], - - ?line ok = validate_dat(L). - - -validate_dat(L) -> validate_dat(L,[]). - -validate_dat([],V) -> - Fun = fun({_,X}) -> case X of - ok -> false; - _ -> true - end - end, - validate_dat1( lists:reverse( lists:filter(Fun,V) ) ); -validate_dat([{Id,E,Dat}|T],V) -> - validate_dat(T,[validate_dat2(Id,E,Dat) | V]). - -validate_dat1([]) -> ok; -validate_dat1(L) -> {error,L}. - -validate_dat2(Id, E, Dat) -> - Res = case {E,snmp:validate_date_and_time(Dat)} of - {E,E} -> ok; - {E,A} -> {E,A} - end, - {Id, Res}. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-2979 -%% Slogan: get-next on more than 1 column in an empty table -%% returns bad response. -%%----------------------------------------------------------------- -otp_2979(suite) -> []; -otp_2979(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master("Test1"), - ?line init_old(), - try_test(otp_2979), - ?line unload_master("Test1"). - -otp_2979_2(X) -> otp_2979(X). - -otp_2979_3(X) -> otp_2979(X). - -otp_2979() -> - gn([[sparseDescr], [sparseStatus]]), - ?line expect(1, [{[sparseStr,0], "slut"}, - {[sparseStr,0], "slut"}]). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns -%% endOfTable - should return value. -%%----------------------------------------------------------------- -otp_3187(suite) -> []; -otp_3187(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - otp_3187(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). - -otp_3187_2(X) -> otp_3187(X). - -otp_3187_3(X) -> otp_3187(X). - -otp_3187() -> - ?line Elements = - snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), - lists:foreach(fun(E) -> - ?line if E == endOfTable -> - ?FAIL(endOfTable); - true -> ok - end - end, Elements). - -%%----------------------------------------------------------------- -%% Ticket: OTP-3542 -%% Slogan: -%%----------------------------------------------------------------- -otp_3542(suite) -> []; -otp_3542(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_3542). - -otp_3542() -> - io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), - io:format("SNMP v3 discovery result: ~p~n",[Res]). - - -%%----------------------------------------------------------------- -%% Ticket: OTP-3725 -%% Slogan: Slow response time on snmpa:int_to_enum -%%----------------------------------------------------------------- -otp_3725(suite) -> []; -otp_3725(Config) when list(Config) -> - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), - try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). - -%% Req. OLD-SNMPEA-MIB -otp_3725_test(MaNode) -> - io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]), - ?DBG("otp_3725_test -> Db = ~p",[Db]), - - ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid, - [Db, intAgentIpAddress]), - ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name, - [Db,OID]), - ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmp, oid_to_name, - [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum, - [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, - [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum, - [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmp, enum_to_int, - [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]), - ok. - - -%%----------------------------------------------------------------- -%% Ticket: OTP-4394 -%% Slogan: Target mib tag list check invalid -%%----------------------------------------------------------------- - - - -init_otp_4394(Config) when list(Config) -> - ?DBG("init_otp_4394 -> entry with" - "~n Config: ~p", [Config]), - ?line AgentDir = ?config(agent_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentDir, MgrDir, Ip), - MasterAgentVerbosity = {master_agent_verbosity, trace}, - NetIfVerbosity = {net_if_verbosity, trace}, - Opts = [MasterAgentVerbosity,NetIfVerbosity], - [{vsn, v1} | start_v1_agent(Config,Opts)]. - -otp_4394_config(AgentDir, MgrDir, Ip0) -> - ?DBG("otp_4394_config -> entry with" - "~n AgentDir: ~p" - "~n MgrDir: ~p" - "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]), - Vsn = [v1], - Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip, - ?TRAP_UDP, Ip, 4000, - "OTP-4394 test"), - ?line case update_usm(Vsn, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); - false -> - ?line ok - end, - C1 = {"a", "all-rights", "initial", "", "pc"}, - C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentDir, [C1, C2]), - ?line update_vacm(Vsn, AgentDir), - Ta1 = {"shelob v1", - [134,138,177,177], 5000, 1500, 3, %% Anvnd Ip och modda - "pc1", - "target_v1", "", - %% [255,255,255,255,0,0], - [], - 2048}, - Ta2 = {"bifur v1", - [134,138,177,75], 5000, 1500, 3, %% Anvnd Ip - "pc2", - "target_v1", "", - %% [255,255,255,255,0,0], - [], 2048}, - ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentDir, Vsn), - ?line write_notify_conf(AgentDir), - ok. - - - -finish_otp_4394(Config) when list(Config) -> - ?DBG("finish_otp_4394 -> entry", []), - C1 = stop_agent(Config), - delete_files(C1), - erase(mgr_node), - lists:keydelete(vsn, 1, C1). - -otp_4394_test(suite) -> []; -otp_4394_test(Config) -> - ?DBG("otp_4394_test -> entry", []), - {_SaNode, _MgrNode, _MibDir} = init_case(Config), - try_test(otp_4394_test1), - ?DBG("otp_4394_test -> done", []), - ok. - -otp_4394_test1() -> - ?DBG("otp_4394_test1 -> entry", []), - gn([[1,1]]), - Res = - case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of - %% {error, 1, {"?",[]}, {"~w",[timeout]}} - {error, 1, _, {_, [timeout]}} -> - ?DBG("otp_4394_test1 -> expected result: timeout", []), - ok; - Else -> - Else - end, - ?DBG("otp_4394_test1 -> done with: ~p", [Res]), - Res. - - -%%%-------------------------------------------------- -%%% Used to test the standard mib with our -%%% configuration. -%%%-------------------------------------------------- -run(F, A, Opts) -> - M = get(mib_dir), - Dir = get(mgr_dir), - User = snmp_misc:get_option(user, Opts, "all-rights"), - SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv), - EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"), - CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID), - Community = snmp_misc:get_option(community, Opts, "all-rights"), - ?DBG("run -> start crypto app",[]), - Crypto = ?CRYPTO_START(), - ?DBG("run -> Crypto: ~p",[Crypto]), - catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case - StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/", - ?DBG("run -> config:~n" - "\tM: ~p~n" - "\tDir: ~p~n" - "\tUser: ~p~n" - "\tSecLevel: ~p~n" - "\tEngineID: ~p~n" - "\tCtxEngineID: ~p~n" - "\tCommunity: ~p~n" - "\tStdM: ~p", - [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]), - case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()}, - {packet_server_debug,true}, - {debug,true}, - {agent, get(master_host)}, - {agent_udp, 4000}, - {trap_udp, 5000}, - {recbuf,65535}, - quiet, - get(vsn), - {community, Community}, - {user, User}, - {sec_level, SecLevel}, - {engine_id, EngineID}, - {context_engine_id, CtxEngineID}, - {dir, Dir}, - {mibs, mibs(StdM, M)}]) of - {ok, _Pid} -> - Res = apply(?MODULE, F, A), - catch snmp_test_mgr:stop(), - Res; - Err -> - io:format("Error starting manager: ~p\n", [Err]), - catch snmp_test_mgr:stop(), - ?line exit({mgr_start, Err}) - end. - - -mibs(StdMibDir,MibDir) -> - [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")), - join(MibDir, "OLD-SNMPEA-MIB.bin"), - join(StdMibDir, "SNMP-FRAMEWORK-MIB"), - join(StdMibDir, "SNMP-MPD-MIB"), - join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"), - join(StdMibDir, "SNMP-USER-BASED-SM-MIB"), - join(StdMibDir, "SNMP-TARGET-MIB"), - join(StdMibDir, "SNMP-NOTIFICATION-MIB"), - join(MibDir, "Klas1.bin"), - join(MibDir, "Klas2.bin"), - join(MibDir, "Klas3.bin"), - join(MibDir, "Klas4.bin"), - join(MibDir, "SA-MIB.bin"), - join(MibDir, "TestTrap.bin"), - join(MibDir, "Test1.bin"), - join(MibDir, "Test2.bin"), - join(MibDir, "TestTrapv2.bin")]. - -join(D,F) -> - filename:join(D,F). - -%% string used in index -is(S) -> [length(S) | S]. - -try_test(Func) -> - call(get(mgr_node), ?MODULE, run, [Func, [], []]). - -try_test(Func, A) -> - call(get(mgr_node), ?MODULE, run, [Func, A, []]). - -try_test(Func, A, Opts) -> - call(get(mgr_node), ?MODULE, run, [Func, A, Opts]). - -call(N,M,F,A) -> - ?DBG("call -> entry with~n" - " N: ~p~n" - " M: ~p~n" - " F: ~p~n" - " A: ~p~n" - " when~n" - " get(): ~p", - [N,M,F,A,get()]), - spawn(N, ?MODULE, wait, [self(),get(),M,F,A]), - receive - {done, {'EXIT', Rn}, Loc} -> - ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]), - put(test_server_loc, Loc), - exit(Rn); - {done, Ret, Zed} -> - ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]), - Ret - end. - -wait(From, Env, M, F, A) -> - ?DBG("wait -> entry with ~n" - "\tFrom: ~p~n" - "\tEnv: ~p",[From,Env]), - lists:foreach(fun({K,V}) -> put(K,V) end, Env), - Rn = (catch apply(M, F, A)), - ?DBG("wait -> Rn: ~n~p", [Rn]), - From ! {done, Rn, get(test_server_loc)}, - exit(Rn). - -expect(A,B) -> ok = snmp_test_mgr:expect(A,B). -expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C). -expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D). -expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F). - -get_req(Id, Vars) -> - ?DBG("get_req -> entry with~n" - "\tId: ~p~n" - "\tVars: ~p",[Id,Vars]), - g(Vars), - ?DBG("get_req -> await response",[]), - {ok, Val} = snmp_test_mgr:get_response(Id, Vars), - ?DBG("get_req -> response: ~p",[Val]), - Val. - -get_next_req(Vars) -> - ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]), - gn(Vars), - ?DBG("get_next_req -> await response",[]), - Response = snmp_test_mgr:receive_response(), - ?DBG("get_next_req -> response: ~p",[Response]), - Response. - - - -start_node(Name) -> - ?LOG("start_node -> entry with Name: ~p",[Name]), - M = list_to_atom(?HOSTNAME(node())), - ?DBG("start_node -> M: ~p",[M]), - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p",[Pa]), - - Args = case init:get_argument('CC_TEST') of - {ok, [[]]} -> - " -pa /clearcase/otp/libraries/snmp/ebin "; - {ok, [[Path]]} -> - " -pa " ++ Path; - error -> - "" - end, - %% Do not use start_link!!! (the proc that calls this one is tmp) - ?DBG("start_node -> Args: ~p~n",[Args]), - A = Args ++ " -pa " ++ Pa, - case (catch ?START_NODE(Name, A)) of - {ok, Node} -> - %% Tell the test_server to not clean up things it never started. - ?DBG("start_node -> Node: ~p",[Node]), - {ok, Node}; - Else -> - ?ERR("start_node -> failed with(other): Else: ~p",[Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?LOG("stop_node -> Node: ~p",[Node]), - rpc:cast(Node, erlang, halt, []). - -p(X) -> - io:format(user, X++"\n", []). - -sleep(X) -> - receive - after - X -> ok - end. - -%%%----------------------------------------------------------------- -%%% Configuration -%%%----------------------------------------------------------------- -config(Vsns, MgrDir, AgentDir, MIp, AIp) -> - ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp, - ?TRAP_UDP, AIp, 4000, - "test"), - ?line case update_usm(Vsns, AgentDir) of - true -> - ?line copy_file(filename:join(AgentDir, "usm.conf"), - filename:join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); - false -> - ?line ok - end, - ?line update_community(Vsns, AgentDir), - ?line update_vacm(Vsns, AgentDir), - ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns), - ?line write_target_params_conf(AgentDir, Vsns), - ?line write_notify_conf(AgentDir), - ok. - -delete_files(Config) -> - Dir = ?config(agent_dir, Config), - {ok, List} = file:list_dir(Dir), - lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end, - List). - -update_usm(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"agentEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", " - "\"all-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", " - "\"no-rights\", zeroDotZero, " - "usmNoAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", " - "\"authMD5\", zeroDotZero, " - "usmHMACMD5AuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_md5xxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", " - "\"authSHA\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmNoPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []), - ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", " - "\"privDES\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -update_usm_mgr(Vsns, Dir) -> - case lists:member(v3, Vsns) of - true -> - {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]), - file:position(Fid, eof), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n", - []), - file:close(Fid), - true; - false -> - false - end. - -rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(filename:join(Dir,"usm.conf"), - filename:join(Dir,"usm.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write), - ok = io:format(Fid, "{\"agentEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", " - "\"newUser\", zeroDotZero, " - "usmHMACSHAAuthProtocol, \"\", \"\", " - "usmDESPrivProtocol, \"\", \"\", \"\", " - "\"~s\", \"~s\"}.\n", - [ShaKey, DesKey]), - file:close(Fid). - -reset_usm_mgr(Dir) -> - ?line ok = file:rename(filename:join(Dir,"usm.old"), - filename:join(Dir,"usm.conf")). - - -update_community([v3], _Dir) -> ok; -update_community(_, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n", - []), - file:close(Fid). - - --define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). -update_vacm(_Vsn, Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]), - file:position(Fid, eof), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]), - ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]), - ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", " - "~w, excluded, null}.\n", [?tDescr_instance]), - file:close(Fid). - - -vacm_ver(v1) -> v1; -vacm_ver(v2) -> v2c; -vacm_ver(v3) -> usm. - - -write_community_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write), - ok = write_community_conf1(Fid, Confs), - file:close(Fid). - -write_community_conf1(_, []) -> - ok; -write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) -> - ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n", - [ComIdx, ComName, SecName, CtxName, TransTag]), - write_community_conf1(Fid, Confs). - - -write_target_addr_conf(Dir, Confs) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - ok = write_target_addr_conf1(Fid, Confs), - file:close(Fid). - - -write_target_addr_conf1(_, []) -> - ok; -write_target_addr_conf1(Fid, - [{Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz}|Confs]) -> - ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n", - [Name, Ip, Port, Timeout, Retry, TagList, ParamName, - EngineId, TMask, MaxMsgSz]), - write_target_addr_conf1(Fid, Confs). - -write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - lists:foreach(fun(Vsn) -> - ok = io:format(Fid, - "{\"~s\", ~w, ~w, 1500, 3, " - "\"std_trap\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, mk_param(Vsn)]), - case Vsn of - v1 -> ok; - v2 -> - ok = io:format(Fid, - "{\"~s.2\",~w,~w,1500,3, " - "\"std_inform\", \"~s\"}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]); - v3 -> - ok = io:format(Fid, - "{\"~s.3\",~w,~w,1500,3, " - "\"std_inform\", \"~s\", " - "\"mgrEngine\", [], 1024}.~n", - [mk_ip(ManagerIp, Vsn), - ManagerIp, UDP, - mk_param(Vsn)]) - end - end, - Vsns), - file:close(Fid). - -mk_param(v1) -> "target_v1"; -mk_param(v2) -> "target_v2"; -mk_param(v3) -> "target_v3". - -mk_ip([A,B,C,D], Vsn) -> - io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]). - - -rewrite_target_addr_conf(Dir,NewPort) -> - TAFile = filename:join(Dir, "target_addr.conf"), - ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]), - case file:read_file_info(TAFile) of - {ok, _} -> ok; - {error, R} -> ?ERR("failure reading file info of " - "target address config file: ~p",[R]), - ok - end, - - ?line [TrapAddr|Addrs] = - snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end), - - ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), - - NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs], - - ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - - ?line ok = file:rename(filename:join(Dir,"target_addr.conf"), - filename:join(Dir,"target_addr.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write), - - ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs), - - file:close(Fid). - -rewrite_target_addr_conf1(O) -> - {ok,O}. - -rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry, - "std_trap",EngineId}) -> - ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]), - {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId}; -rewrite_target_addr_conf2(_NewPort,O) -> - ?LOG("rewrite_target_addr_conf2 -> entry with " - "~n O: ~p",[O]), - O. - - -rewrite_target_addr_conf3(_,[]) -> ok; -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry, - ParamName,EngineId}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % ParamsName - "\"~s\"}.", % EngineId - [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]), - rewrite_target_addr_conf3(Fid,T); -rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList, - ParamName,EngineId,TMask,MMS}|T]) -> - ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]), - io:format(Fid, - "{\"~s\", " % Name - "~p, " % Ip - "~p, " % Port - "~p, " % Timeout - "~p, " % Retry - "\"~s\", " % TagList - "\"~s\", " % ParamsName - "\"~s\"," % EngineId - "~p, " % TMask - "~p}.", % MMS - [Name,Ip,Port,Timeout,Retry,TagList,ParamName, - EngineId,TMask,MMS]), - rewrite_target_addr_conf3(Fid,T). - -reset_target_addr_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_addr.old"), - filename:join(Dir,"target_addr.conf")). - -write_target_params_conf(Dir, Vsns) -> - {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - lists:foreach(fun(Vsn) -> - MP = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> v3 - end, - SM = if Vsn == v1 -> v1; - Vsn == v2 -> v2c; - Vsn == v3 -> usm - end, - ok = io:format(Fid, "{\"target_~w\", ~w, ~w, " - "\"all-rights\", noAuthNoPriv}.~n", - [Vsn, MP, SM]) - end, - Vsns), - file:close(Fid). - -rewrite_target_params_conf(Dir, SecName, SecLevel) -> - ?line ok = file:rename(filename:join(Dir,"target_params.conf"), - filename:join(Dir,"target_params.old")), - ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write), - ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n", - [SecName, SecLevel]), - file:close(Fid). - -reset_target_params_conf(Dir) -> - ?line ok = file:rename(filename:join(Dir,"target_params.old"), - filename:join(Dir,"target_params.conf")). - -write_notify_conf(Dir) -> - {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write), - ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []), - ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []), - file:close(Fid). - -ver_to_trap_str([v1]) -> "v1"; -ver_to_trap_str([v2]) -> "v2"; -% default is to use the latest snmp version -ver_to_trap_str([v1,v2]) -> "v2". - - - -write_view_conf(Dir) -> - {ok, Fid} = file:open(a(Dir,"view.conf"),write), - ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []), - ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]), - file:close(Fid). - -a(A,B) -> lists:append(A,B). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -copy_file(From, To) -> - {ok, Bin} = file:read_file(From), - ok = file:write_file(To, Bin). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -display_memory_usage() -> - Info = snmpa:info(snmp_master_agent), - TreeSize = lists_key1search(tree_size_bytes, Info), - ProcMem = lists_key1search(process_memory, Info), - MibDbSize = lists_key1search([db_memory,mib], Info), - NodeDbSize = lists_key1search([db_memory,node], Info), - TreeDbSize = lists_key1search([db_memory,tree], Info), - ?INF("Memory usage: " - "~n Tree size: ~p" - "~n Process memory size: ~p" - "~n Mib db size: ~p" - "~n Node db size: ~p" - "~n Tree db size: ~p", - [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]). - -lists_key1search([], Res) -> - Res; -lists_key1search([Key|Keys], List) when atom(Key), list(List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - lists_key1search(Keys, Val); - false -> - undefined - end; -lists_key1search(Key, List) when atom(Key) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Val}} -> - Val; - false -> - undefined - end. - - -regs() -> - lists:sort(registered()). diff --git a/lib/snmp/test/klas3.erl b/lib/snmp/test/klas3.erl index 9a5c388170ae..40002e84135f 100644 --- a/lib/snmp/test/klas3.erl +++ b/lib/snmp/test/klas3.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -131,7 +131,7 @@ ftab2(set, [2], _Cols) -> ftab2(set, _, _Cols) -> {noError, 0}; -%% Unfortunatly we can't force the undo - we don't know which var +%% Unfortunately we can't force the undo - we don't know which var %% is tried first. %ftab2(undo, [3], Cols) -> % % bad column - In: col 2 & 3 diff --git a/lib/snmp/test/snmp_agent_SUITE.erl b/lib/snmp/test/snmp_agent_SUITE.erl index bf942715cd97..36c47f00f198 100644 --- a/lib/snmp/test/snmp_agent_SUITE.erl +++ b/lib/snmp/test/snmp_agent_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2022. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -524,10 +524,11 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. all() -> - %% This is a temporary messure to ensure that we can + %% This is a temporary measure to ensure that we can %% test the socket backend without effecting *all* %% applications on *all* machines. %% This flag is set only for *one* host. + %% case ?TEST_INET_BACKENDS() of case ?TEST_INET_BACKENDS() of true -> [ @@ -679,8 +680,8 @@ otp16649_gen_cases() -> init_per_suite(Config0) when is_list(Config0) -> ?IPRINT("init_per_suite -> entry with" - "~n Config: ~p" - "~n Nodes: ~p" + "~n Config: ~p" + "~n Nodes: ~p" "~n explicit inet backend: ~p" "~n test inet backends: ~p", [Config0, erlang:nodes(), @@ -709,7 +710,7 @@ init_per_suite(Config0) when is_list(Config0) -> ?IPRINT("init_per_suite -> end when" "~n Config: ~p" "~n Nodes: ~p", [Config4, erlang:nodes()]), - + Config4 end. @@ -721,7 +722,7 @@ end_per_suite(Config0) when is_list(Config0) -> case snmp_test_mgr_counter_server:stop() of {ok, Counters} -> - ?IPRINT("end_per_suite -> sucessfully stopped counter server" + ?IPRINT("end_per_suite -> successfully stopped counter server" "~n Counters: ~p", [Counters]); {error, Reason} -> @@ -761,25 +762,56 @@ init_per_group(GroupName, Config0) -> Config1. -init_per_group2(inet_backend_default = _GroupName, Config) -> - snmp_test_lib:init_group_top_dir(default, [{socket_create_opts, []} | Config]); -init_per_group2(inet_backend_inet = _GroupName, Config) -> +init_per_group2(inet_backend_default = _GroupName, Config0) -> + Config1 = [{socket_create_opts, []} | Config0], + case ?EXPLICIT_INET_BACKEND() of + true -> + ?LIB:init_group_top_dir(default, Config1); + false -> + %% For a "standard" test (that is if we do not run the "extended" + %% inet backends test) then we should always run this group! + %% So, if we have an extended test, *then* (and only then) + %% check the factor. + case ?TEST_INET_BACKENDS() of + true -> + case lists:keysearch(snmp_factor, 1, Config0) of + {value, {snmp_factor, Factor}} when (Factor < 3) -> + ?LIB:init_group_top_dir(default, Config1); + _ -> + {skip, "Machine too slow"} + end; + _ -> + ?LIB:init_group_top_dir(default, Config1) + end + end; +init_per_group2(inet_backend_inet = _GroupName, Config0) -> case ?EXPLICIT_INET_BACKEND() of true -> %% The environment trumps us, %% so only the default group should be run! {skip, "explicit inet backend"}; false -> - snmp_test_lib:init_group_top_dir(inet, [{socket_create_opts, [{inet_backend, inet}]} | Config]) + case lists:keysearch(snmp_factor, 1, Config0) of + {value, {snmp_factor, Factor}} when (Factor < 5) -> + Config1 = [{socket_create_opts, [{inet_backend, inet}]} | + Config0], + ?LIB:init_group_top_dir(inet, Config1); + _ -> + {skip, "Machine too slow"} + end end; -init_per_group2(inet_backend_socket = _GroupName, Config) -> +init_per_group2(inet_backend_socket = _GroupName, Config0) -> case ?EXPLICIT_INET_BACKEND() of true -> %% The environment trumps us, - %% so only the default group should be run! + %% so only the *default* group should be run! {skip, "explicit inet backend"}; false -> - snmp_test_lib:init_group_top_dir(socket, [{socket_create_opts, [{inet_backend, socket}]} | Config]) + %% Always run this unless a backend has been explicitly + %% configured (since this is really what we want to test). + Config1 = [{socket_create_opts, [{inet_backend, socket}]} | + Config0], + ?LIB:init_group_top_dir(socket, Config1) end; init_per_group2(major_tcs = GroupName, Config) -> init_all(snmp_test_lib:init_group_top_dir(GroupName, Config)); @@ -873,7 +905,7 @@ init_per_group2(GroupName, Config) -> init_per_group_ipv6(GroupName, Config, Init) -> %% - %% This is a higly questionable test. + %% This is a highly questionable test. %% But until we have time to figure out what IPv6 issues %% are actually causing the failures... OSSkipable = [{unix, @@ -1330,7 +1362,7 @@ stop_agent(Config) -> create_tables(SaNode) -> - %% ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2}, + %% {atomic, ok} = mnesia:create_table([{name, friendsTable2}, %% {ram_copies, [SaNode]}, %% {snmp, [{key, integer}]}, %% {attributes, [a1,a2,a3]}]), @@ -1338,7 +1370,7 @@ create_tables(SaNode) -> {ram_copies, [SaNode]}, {snmp, [{key, integer}]}, {attributes, [a1,a2,a3]}]), - %% ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2}, + %% {atomic, ok} = mnesia:create_table([{name, kompissTable2}, %% {ram_copies, [SaNode]}, %% {snmp, [{key, integer}]}, %% {attributes, [a1,a2,a3]}]), @@ -1346,7 +1378,7 @@ create_tables(SaNode) -> {ram_copies, [SaNode]}, {snmp, [{key, integer}]}, {attributes, [a1,a2,a3]}]), - %% ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables}, + %% {atomic, ok} = mnesia:create_table([{name, snmp_variables}, %% {attributes, [a1,a2]}]), mnesia_create_table_or_fail([{name, snmp_variables}, {attributes, [a1,a2]}]), @@ -1526,14 +1558,14 @@ init_mib_storage_ets(Config) when is_list(Config) -> init_mib_storage_dets(Config) when is_list(Config) -> ?IPRINT("init_mib_storage_dets -> entry"), - ?line AgentDbDir = ?GCONF(agent_db_dir, Config), + AgentDbDir = ?GCONF(agent_db_dir, Config), MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets}, {options, [{dir, AgentDbDir}]}]}, init_ms(Config, [MibStorage]). init_mib_storage_mnesia(Config) when is_list(Config) -> ?IPRINT("init_mib_storage_mnesia -> entry"), - ?line AgentNode = ?GCONF(snmp_master, Config), + AgentNode = ?GCONF(snmp_master, Config), MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia}, {options, [{nodes, [AgentNode]}]}]}, init_ms(Config, [MibStorage]). @@ -1542,12 +1574,12 @@ init_ms(Config, Opts) when is_list(Config) -> ?IPRINT("init_ms -> entry with" "~n Config: ~p" "~n Opts: ~p", [Config, Opts]), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentConfDir = ?GCONF(agent_conf_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentConfDir, + SaNode = ?GCONF(snmp_sa, Config), + create_tables(SaNode), + AgentConfDir = ?GCONF(agent_conf_dir, Config), + MgrDir = ?GCONF(mgr_dir, Config), + Ip = ?GCONF(ip, Config), + config([v1], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), MasterAgentVerbosity = {agent_verbosity, trace}, MibsVerbosity = {mib_server, [{verbosity, trace}]}, @@ -1566,7 +1598,7 @@ init_ms(Config, Opts) when is_list(Config) -> %% init_size_check_ms(Config, [MibStorage]). init_size_check_msm(Config) when is_list(Config) -> - ?line AgentNode = ?GCONF(snmp_master, Config), + AgentNode = ?GCONF(snmp_master, Config), MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia}, {options, [{nodes, [AgentNode]}]}]}, init_size_check_ms(Config, [MibStorage]). @@ -1594,19 +1626,19 @@ init_size_check_ms(Config, Opts) when is_list(Config) -> AgentConfDir = ?GCONF(agent_conf_dir, Config), MgrDir = ?GCONF(mgr_dir, Config), Ip = ?GCONF(ip, Config), - ?line ok = config([v3], MgrDir, AgentConfDir, + ok = config([v3], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), [{vsn, v3} | start_v3_agent(Config, Opts)]. init_varm_mib_storage_dets(Config) when is_list(Config) -> ?IPRINT("init_varm_mib_storage_dets -> entry"), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentDbDir = ?GCONF(agent_db_dir, Config), - ?line AgentConfDir = ?GCONF(agent_conf_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentConfDir, + SaNode = ?GCONF(snmp_sa, Config), + create_tables(SaNode), + AgentDbDir = ?GCONF(agent_db_dir, Config), + AgentConfDir = ?GCONF(agent_conf_dir, Config), + MgrDir = ?GCONF(mgr_dir, Config), + Ip = ?GCONF(ip, Config), + config([v1], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets}, {options, [{dir, AgentDbDir}]}]}, @@ -1621,14 +1653,14 @@ init_varm_mib_storage_dets(Config) when is_list(Config) -> init_varm_mib_storage_mnesia(Config) when is_list(Config) -> ?IPRINT("init_varm_mib_storage_mnesia -> entry"), - ?line SaNode = ?GCONF(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentConfDir = ?GCONF(agent_conf_dir, Config), - ?line MgrDir = ?GCONF(mgr_dir, Config), - ?line Ip = ?GCONF(ip, Config), - ?line config([v1], MgrDir, AgentConfDir, + SaNode = ?GCONF(snmp_sa, Config), + create_tables(SaNode), + AgentConfDir = ?GCONF(agent_conf_dir, Config), + MgrDir = ?GCONF(mgr_dir, Config), + Ip = ?GCONF(ip, Config), + config([v1], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), - ?line AgentNode = ?GCONF(snmp_master, Config), + AgentNode = ?GCONF(snmp_master, Config), MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia}, {options, [{nodes, [AgentNode]}]}]}, MasterAgentVerbosity = {agent_verbosity, trace}, @@ -1803,49 +1835,47 @@ msm_varm_mib_start(X) -> ?P(msm_varm_mib_start), varm_mib_start(X). -ms_size_check(suite) -> []; ms_size_check(Config) when is_list(Config) -> ?P(ms_size_check), init_case(Config), ?IPRINT("mib server size check..."), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMPv2-MIB"), - ?line load_master_std("SNMPv2-TM"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), + load_master_std("OTP-SNMPEA-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-MPD-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-USER-BASED-SM-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master_std("SNMPv2-MIB"), + load_master_std("SNMPv2-TM"), ?SLEEP(2000), - ?line display_memory_usage(), + display_memory_usage(), - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMPv2-MIB"), - ?line unload_master("SNMPv2-TM"), + unload_master("OTP-SNMPEA-MIB"), + unload_master("SNMP-COMMUNITY-MIB"), + unload_master("SNMP-FRAMEWORK-MIB"), + unload_master("SNMP-MPD-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-USER-BASED-SM-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("SNMPv2-MIB"), + unload_master("SNMPv2-TM"), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), ok. -varm_mib_start(suite) -> []; varm_mib_start(Config) when is_list(Config) -> ?P(varm_mib_start), ?IPRINT("varm_mib_start -> entry"), @@ -1862,16 +1892,16 @@ varm_mib_start(Config) when is_list(Config) -> %% Load all the mibs HardwiredMibs = loaded_mibs(), ?DBG("varm_mib_start -> load all mibs", []), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), %% Unload the hardwired mibs ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []), ?SLEEP(1000), ?DBG("varm_mib_start -> unload (hardwired) mibs", []), - ?line unload_mibs(HardwiredMibs), %% unload hardwired + unload_mibs(HardwiredMibs), %% unload hardwired ?DBG("varm_mib_start -> sleep some (before stopping agent)", []), ?SLEEP(1000), @@ -1908,51 +1938,50 @@ varm_mib_start(Config) when is_list(Config) -> -define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]). -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). -ms_me_of(suite) -> []; ms_me_of(Config) when is_list(Config) -> ?P(ms_me_of), init_case(Config), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), + load_master_std("OTP-SNMPEA-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-MPD-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), ?SLEEP(2000), - ?line display_memory_usage(), + display_memory_usage(), ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB", [?snmpTrapCommunity_instance]), - ?line ok = me_of(?snmpTrapCommunity_instance), + ok = me_of(?snmpTrapCommunity_instance), ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", [?vacmViewSpinLock_instance]), - ?line ok = me_of(?vacmViewSpinLock_instance), + ok = me_of(?vacmViewSpinLock_instance), ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB", [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance), + {error, _} = me_of(?usmStatsNotInTimeWindows_instance), - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("OTP-SNMPEA-MIB"), + unload_master("SNMP-COMMUNITY-MIB"), + unload_master("SNMP-FRAMEWORK-MIB"), + unload_master("SNMP-MPD-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), ok. @@ -1979,52 +2008,51 @@ me_of(Oid) -> end. -ms_mib_of(suite) -> []; ms_mib_of(Config) when is_list(Config) -> ?P(ms_mib_of), init_case(Config), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), - ?line load_master_std("OTP-SNMPEA-MIB"), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), + load_master_std("OTP-SNMPEA-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-MPD-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), ?SLEEP(2000), - ?line display_memory_usage(), + display_memory_usage(), ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB", [?snmpTrapCommunity_instance]), - ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), + ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'), ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB", [?vacmViewSpinLock_instance]), - ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), + ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'), ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB", [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, + {error, _} = mib_of(?usmStatsNotInTimeWindows_instance, 'SNMP-USER-BASED-SM-MIB'), - ?line unload_master("OTP-SNMPEA-MIB"), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("OTP-SNMPEA-MIB"), + unload_master("SNMP-COMMUNITY-MIB"), + unload_master("SNMP-FRAMEWORK-MIB"), + unload_master("SNMP-MPD-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), ok. @@ -2062,7 +2090,6 @@ misc_cases() -> create_local_db_dir ]. -app_info(suite) -> []; app_info(Config) when is_list(Config) -> ?P(app_info), SnmpDir = app_dir(snmp), @@ -2100,8 +2127,6 @@ create_local_db_dir(Config) when is_list(Config) -> erlang:unique_integer([positive])}, [As,Bs,Cs] = [integer_to_list(I) || I <- tuple_to_list(T)], DbDir = filename:join([DataDir, As, Bs, Cs]), - Name = list_to_atom(atom_to_list(create_local_db_dir) - ++"_"++As++"_"++Bs++"_"++Cs), ?IPRINT("try ensuring db-dir does not exist"), try del_dir(DbDir, 3) of ok -> @@ -2114,20 +2139,13 @@ create_local_db_dir(Config) when is_list(Config) -> "~n Stack: ~p", [C, E, S]), throw({skip, "Failed pre db-dir cleanup"}) end, - ?IPRINT("try start node ~p", [Name]), - case ?ALIB:start_node(Name) of - {ok, Node} -> - {DbDir, Node}; - {error, Reason} -> - ?WPRINT("Failed starting node ~p:" - "~n ~p", [Reason]), - throw({skip, ?F("Failed starting node ~p", [Name])}) - end + {ok, Peer, Node} = ?START_PEER(""), + {DbDir, Peer, Node} end, Case = fun do_create_local_db_dir/1, - Post = fun({DbDir, Node}) -> + Post = fun({DbDir, Peer, Node}) -> ?IPRINT("try stop node ~p", [Node]), - ?ALIB:stop_node(Node), + peer:stop(Peer), ?IPRINT("try delete db-dir"), try del_dir(DbDir, 3) catch @@ -2142,7 +2160,7 @@ create_local_db_dir(Config) when is_list(Config) -> end, ?TC_TRY(create_local_db_dir, Pre, Case, Post). -do_create_local_db_dir({DbDir, Node}) -> +do_create_local_db_dir({DbDir, _Peer, Node}) -> ?P(create_local_db_dir), %% first start with a nonexisting DbDir Fun1 = fun() -> @@ -2254,13 +2272,13 @@ v1_cases_ipv6() -> ]. init_v1(Config) when is_list(Config) -> - ?line SaNode = ?config(snmp_sa, Config), - ?line create_tables(SaNode), - ?line AgentConfDir = ?config(agent_conf_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line IpFamily = config_ipfamily(Config), - ?line config( + SaNode = ?config(snmp_sa, Config), + create_tables(SaNode), + AgentConfDir = ?config(agent_conf_dir, Config), + MgrDir = ?config(mgr_dir, Config), + Ip = ?config(ip, Config), + IpFamily = config_ipfamily(Config), + config( [v1], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), [{vsn, v1} | start_v1_agent(Config)]. @@ -2462,7 +2480,7 @@ init_v3(Config) when is_list(Config) -> MgrDir = ?config(mgr_dir, Config), Ip = ?config(ip, Config), IpFamily = config_ipfamily(Config), - ?line ok = + ok = config( [v3], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip), IpFamily), @@ -2495,7 +2513,7 @@ init_mt(Config, MT) when is_list(Config) -> AgentConfDir = ?config(agent_conf_dir, Config), MgrDir = ?config(mgr_dir, Config), Ip = ?config(ip, Config), - ?line ok = config([v2], MgrDir, AgentConfDir, + ok = config([v2], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), [{vsn, v2} | start_multi_threaded_agent(Config, MT)]. @@ -2574,7 +2592,6 @@ init_old() -> -simple(suite) -> []; simple(Config) when is_list(Config) -> ?P(simple), init_case(Config), @@ -2586,7 +2603,6 @@ simple(Config) when is_list(Config) -> simple_2(X) -> ?P(simple_2), simple(X). -simple_bi(suite) -> []; simple_bi(Config) when is_list(Config) -> ?P(simple_bi), init_case(Config), @@ -2600,7 +2616,6 @@ simple_bi(Config) when is_list(Config) -> simple_3(X) -> ?P(simple_3), simple(X). -big(suite) -> []; big(Config) when is_list(Config) -> ?P(big), %% put(sname, {?MODULE, big}), @@ -2609,12 +2624,12 @@ big(Config) when is_list(Config) -> {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), + pong = net_adm:ping(SaNode), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), + {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), ?DBG("big -> SA: ~p", [SA]), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), snmpa:dump_mibs(), snmpa:dump_mibs("dumped_mibs.txt"), @@ -2622,15 +2637,14 @@ big(Config) when is_list(Config) -> try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB"). + stop_subagent(SA), + unload_master("OLD-SNMPEA-MIB"). big_2(X) -> ?P(big_2), big(X). big_3(X) -> ?P(big_3), big(X). -big2(suite) -> []; big2(Config) when is_list(Config) -> ?P(big2), %% This is exactly the same tests as 'big', but with the @@ -2638,110 +2652,102 @@ big2(Config) when is_list(Config) -> {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("Starting subagent..."), - ?line pong = net_adm:ping(SaNode), + pong = net_adm:ping(SaNode), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), - ?line load_master("OLD-SNMPEA-MIB-v2"), - ?line init_old(), + {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"), + load_master("OLD-SNMPEA-MIB-v2"), + init_old(), try_test(big_test), - ?line stop_subagent(SA), - ?line unload_master("OLD-SNMPEA-MIB-v2"). + stop_subagent(SA), + unload_master("OLD-SNMPEA-MIB-v2"). big2_2(X) -> ?P(big2_2), big2(X). big2_3(X) -> ?P(big2_3), big2(X). -multi_threaded(suite) -> []; multi_threaded(Config) when is_list(Config) -> ?P(multi_threaded), init_case(Config), - ?line load_master("Test1"), + load_master("Test1"), try_test(multi_threaded_test), - ?line unload_master("Test1"). + unload_master("Test1"). -mt_trap(suite) -> []; mt_trap(Config) when is_list(Config) -> ?P(mt_trap), init_case(Config), MA = whereis(snmp_master_agent), MT = ?config(multi_threaded, Config), - ?line load_master("Test1"), - ?line load_master("TestTrapv2"), + load_master("Test1"), + load_master("TestTrapv2"), try_test(mt_trap_test, [MA, MT]), - ?line unload_master("TestTrapv2"), - ?line unload_master("Test1"), + unload_master("TestTrapv2"), + unload_master("Test1"), ok. -v2_types(suite) -> []; v2_types(Config) when is_list(Config) -> ?P(v2_types), init_case(Config), - ?line load_master("Test1"), + load_master("Test1"), try_test(types_v2_test), - ?line unload_master("Test1"). + unload_master("Test1"). v2_types_3(X) -> ?P(v2_types_3), v2_types(X). -implied(suite) -> []; implied(Config) when is_list(Config) -> ?P(implied), init_case(Config), MA = whereis(snmp_master_agent), - ?line load_master("Test1"), + load_master("Test1"), try_test(implied_test,[MA]), - ?line unload_master("Test1"). + unload_master("Test1"). implied_3(X) -> ?P(implied_3), implied(X). -sparse_table(suite) -> []; sparse_table(Config) when is_list(Config) -> ?P(sparse_table), init_case(Config), - ?line load_master("Test1"), + load_master("Test1"), try_test(sparse_table_test), - ?line unload_master("Test1"). + unload_master("Test1"). sparse_table_2(X) -> ?P(sparse_table_2), sparse_table(X). sparse_table_3(X) -> ?P(sparse_table_3), sparse_table(X). -cnt_64(suite) -> []; cnt_64(Config) when is_list(Config) -> ?P(cnt_64), init_case(Config), MA = whereis(snmp_master_agent), - ?line load_master("Test1"), + load_master("Test1"), try_test(cnt_64_test, [MA]), - ?line unload_master("Test1"). + unload_master("Test1"). cnt_64_2(X) -> ?P(cnt_64_2), cnt_64(X). cnt_64_3(X) -> ?P(cnt_64_3), cnt_64(X). -opaque(suite) -> []; opaque(Config) when is_list(Config) -> ?P(opaque), init_case(Config), - ?line load_master("Test1"), + load_master("Test1"), try_test(opaque_test), - ?line unload_master("Test1"). + unload_master("Test1"). opaque_2(X) -> ?P(opaque_2), opaque(X). opaque_3(X) -> ?P(opaque_2), opaque(X). -change_target_addr_config(suite) -> []; change_target_addr_config(Config) when is_list(Config) -> ?P(change_target_addr_config), ?IPRINT("change_target_addr_config -> entry"), @@ -2753,27 +2759,27 @@ change_target_addr_config(Config) when is_list(Config) -> MA = whereis(snmp_master_agent), ?IPRINT("change_target_addr_config -> load TestTrap"), - ?line load_master("TestTrap"), + load_master("TestTrap"), ?IPRINT("change_target_addr_config -> set trace verbosity for local_db"), - ?line snmpa:verbosity(local_db,trace), + snmpa:verbosity(local_db,trace), - %% First send some traps that will arive att the original manager + %% First send some traps that will arrive att the original manager ?IPRINT("change_target_addr_config -> send trap"), try_test(ma_trap1, [MA]), ?IPRINT("change_target_addr_config -> set silence verbosity for local_db"), - ?line snmpa:verbosity(local_db, silence), + snmpa:verbosity(local_db, silence), %% Start new dummy listener ?IPRINT("change_target_addr_config -> start dummy manager"), - ?line {ok,Pid,NewPort} = dummy_manager_start(MA), + {ok,Pid,NewPort} = dummy_manager_start(MA), %% Reconfigure ?IPRINT("change_target_addr_config -> reconfigure"), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_addr_conf(AgentConfDir, NewPort), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_addr_conf(AgentConfDir, NewPort), + snmp_target_mib:reconfigure(AgentConfDir), %% Send the trap again ?IPRINT("change_target_addr_config -> send trap again"), @@ -2783,13 +2789,13 @@ change_target_addr_config(Config) when is_list(Config) -> catch dummy_manager_await_trap2_ack(), ?IPRINT("change_target_addr_config -> stop dummy manager"), - ?line ok = dummy_manager_stop(Pid), + ok = dummy_manager_stop(Pid), ?IPRINT("change_target_addr_config -> reset target address config"), - ?line reset_target_addr_conf(AgentConfDir), + reset_target_addr_conf(AgentConfDir), ?IPRINT("change_target_addr_config -> unload TestTrap"), - ?line unload_master("TestTrap"). + unload_master("TestTrap"). dummy_manager_start(MA) -> @@ -2838,7 +2844,7 @@ dummy_manager_await_trap2_ack() -> {received_trap, _Trap} -> ?IPRINT("dummy_manager_await_trap2 -> received trap: ~p", [_Trap]), %% Note: - %% Without this sleep the v2_inform_i testcase failes! There + %% Without this sleep the v2_inform_i testcase fails! There %% is no relation between these two test cases as far as I %% able to figure out... ?SLEEP(60000), @@ -2892,7 +2898,7 @@ dummy_manager_loop(P,S,MA) -> %% -ifdef(snmp_log). dummy_manager_message_sz(B) when is_binary(B) -> - size(B); + byte_size(B); dummy_manager_message_sz(L) when is_list(L) -> length(L); dummy_manager_message_sz(_) -> @@ -2913,49 +2919,57 @@ dummy_manager_handle_message(Bytes) -> end. -api(suite) -> []; api(Config) when is_list(Config) -> ?P(api), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(api_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). + unload_master("OLD-SNMPEA-MIB"). api_2(X) -> ?P(api_2), api(X). api_3(X) -> ?P(api_3), api(X). -subagent(suite) -> []; subagent(Config) when is_list(Config) -> ?P(subagent), {SaNode, _MgrNode, MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), + ?NPRINT("try start subagent..."), + {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), + ?NPRINT("try test case load_test_sa..."), try_test(load_test_sa), ?NPRINT("Testing unregister subagent..."), MA = whereis(snmp_master_agent), rpc:call(SaNode, snmpa, unregister_subagent, [MA, SA]), + ?NPRINT("try test case unreg_test..."), try_test(unreg_test), ?NPRINT("Loading previous subagent mib in master and testing..."), - ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas1")), + ok = snmpa:load_mib(MA, join(MibDir, "Klas1")), + ?NPRINT("try test case load_test..."), try_test(load_test), ?NPRINT("Unloading previous subagent mib in master and testing..."), - ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas1")), + ok = snmpa:unload_mib(MA, join(MibDir, "Klas1")), + ?NPRINT("try test case unreg_test..."), try_test(unreg_test), ?NPRINT("Testing register subagent..."), - rpc:call(SaNode, snmpa, register_subagent, - [MA, ?klas1, SA]), + rpc:call(SaNode, snmpa, register_subagent, [MA, ?klas1, SA]), + ?NPRINT("try test case load_test_sa..."), try_test(load_test_sa), - ?line stop_subagent(SA), - try_test(unreg_test). + ?NPRINT("try stop subagent..."), + stop_subagent(SA), + ?NPRINT("try test case unreg_test..."), + try_test(unreg_test), + + ?NPRINT("done"), + ok. subagent_2(X) -> ?P(subagent_2), subagent(X). @@ -2970,15 +2984,14 @@ subagent_3(X) -> subagent(X). -mnesia(suite) -> []; mnesia(Config) when is_list(Config) -> ?P(mnesia), {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("Starting subagent with mnesia impl..."), {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(big_test_2), @@ -2986,8 +2999,8 @@ mnesia(Config) when is_list(Config) -> MA = whereis(snmp_master_agent), rpc:call(SaNode, snmpa, unregister_subagent, [MA, SA]), try_test(unreg_test), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA). + unload_master("OLD-SNMPEA-MIB"), + stop_subagent(SA). mnesia_2(X) -> ?P(mnesia_2), mnesia(X). @@ -3030,9 +3043,9 @@ mul_cases_3() -> init_mul(Config) when is_list(Config) -> {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), + load_master("OLD-SNMPEA-MIB"), + init_old(), [{mul_sub, SA} | Config]. finish_mul(Config) when is_list(Config) -> @@ -3040,11 +3053,10 @@ finish_mul(Config) when is_list(Config) -> SA = ?config(mul_sub, Config), - ?line unload_master("OLD-SNMPEA-MIB"), - ?line stop_subagent(SA), + unload_master("OLD-SNMPEA-MIB"), + stop_subagent(SA), lists:keydelete(mul_sub, 1, Config). -mul_get(suite) -> []; mul_get(Config) when is_list(Config) -> ?P(mul_get), init_case(Config), @@ -3057,7 +3069,6 @@ mul_get_2(X) -> ?P(mul_get_2), mul_get(X). mul_get_3(X) -> ?P(mul_get_3), mul_get(X). -mul_get_err(suite) -> []; mul_get_err(Config) when is_list(Config) -> ?P(mul_get_err), init_case(Config), @@ -3070,7 +3081,6 @@ mul_get_err_2(X) -> ?P(mul_get_err_2), mul_get_err(X). mul_get_err_3(X) -> ?P(mul_get_err_3), mul_get_err(X). -mul_next(suite) -> []; mul_next(Config) when is_list(Config) -> ?P(mul_next), init_case(Config), @@ -3083,7 +3093,6 @@ mul_next_2(X) -> ?P(mul_next_2), mul_next(X). mul_next_3(X) -> ?P(mul_next_3), mul_next(X). -mul_next_err(suite) -> []; mul_next_err(Config) when is_list(Config) -> ?P(mul_next_err), init_case(Config), @@ -3096,7 +3105,6 @@ mul_next_err_2(X) -> ?P(mul_next_err_2), mul_next_err(X). mul_next_err_3(X) -> ?P(mul_next_err_3), mul_next_err(X). -mul_set(suite) -> []; mul_set(Config) when is_list(Config) -> ?P(mul_set), init_case(Config), @@ -3109,7 +3117,6 @@ mul_set_2(X) -> ?P(mul_set_2), mul_set(X). mul_set_3(X) -> ?P(mul_set_3), mul_set(X). -mul_set_err(suite) -> []; mul_set_err(Config) when is_list(Config) -> ?P(mul_set_err), init_case(Config), @@ -3122,14 +3129,13 @@ mul_set_err_2(X) -> ?P(mul_set_err_2), mul_set_err(X). mul_set_err_3(X) -> ?P(mul_set_err_3), mul_set_err(X). -sa_register(suite) -> []; sa_register(Config) when is_list(Config) -> ?P(sa_register), {SaNode, _MgrNode, MibDir} = init_case(Config), ?DBG("sa_register -> start subagent", []), ?NPRINT("start subagent..."), - ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), + {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"), ?DBG("sa_register -> unregister subagent", []), ?NPRINT("Testing unregister subagent (2)..."), @@ -3153,14 +3159,13 @@ sa_register(Config) when is_list(Config) -> ?NPRINT("stop subagent..."), ?DBG("sa_register -> stop subagent", []), - ?line stop_subagent(SA). + stop_subagent(SA). sa_register_2(X) -> ?P(sa_register_2), sa_register(X). sa_register_3(X) -> ?P(sa_register_3), sa_register(X). -v1_trap(suite) -> []; v1_trap(Config) when is_list(Config) -> ?P(v1_trap), trap1(Config). @@ -3169,14 +3174,14 @@ trap1(Config) -> {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("start subagent..."), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?NPRINT("Testing trap sending from master agent..."), MA = whereis(snmp_master_agent), ?NPRINT("load TestTrap & TestTrapv2..."), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("TestTrap"), + load_master("TestTrapv2"), ?NPRINT("Testing trap sending from master-agent..."), try_test(ma_trap1, [MA]), @@ -3190,13 +3195,12 @@ trap1(Config) -> try_test(sa_trap3, [SA]), ?NPRINT("unload TestTrap & TestTrapv2..."), - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("TestTrapv2"), ?NPRINT("stop subagent..."), - ?line stop_subagent(SA). + stop_subagent(SA). -v2_trap(suite) -> []; v2_trap(Config) when is_list(Config) -> ?P(v2_trap), trap2(Config). @@ -3205,14 +3209,14 @@ trap2(Config) -> {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("start subagent..."), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?NPRINT("Testing trap sending from master agent..."), MA = whereis(snmp_master_agent), ?NPRINT("load TestTrap & TestTrapv2..."), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("TestTrap"), + load_master("TestTrapv2"), ?NPRINT("Testing trap sending from master-agent..."), try_test(ma_v2_trap1, [MA]), @@ -3228,13 +3232,12 @@ trap2(Config) -> try_test(sa_v1_2_v2_trap3, [SA]), ?NPRINT("unload TestTrap & TestTrapv2..."), - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("TestTrapv2"), ?NPRINT("stop subagent..."), - ?line stop_subagent(SA). + stop_subagent(SA). -v3_trap(suite) -> []; v3_trap(Config) when is_list(Config) -> %% Skippable = [{unix, [darwin]}], @@ -3273,7 +3276,6 @@ v2_inform_cases() -> v2_inform_i ]. -v2_inform_i(suite) -> []; v2_inform_i(Config) when is_list(Config) -> ?P(v2_inform_i), inform_i(Config). @@ -3284,19 +3286,19 @@ inform_i(Config) -> MA = whereis(snmp_master_agent), ?NPRINT("load TestTrap & TestTrapv2..."), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("TestTrap"), + load_master("TestTrapv2"), ?NPRINT("Testing inform sending from master agent... " - "~nNOTE! This test takes a few minutes (10) to complete."), + "~n NOTE! This test takes a few minutes (10) to complete."), try_test(ma_v2_inform1, [MA]), try_test(ma_v2_inform2, [MA]), try_test(ma_v2_inform3, [MA]), ?NPRINT("unload TestTrap & TestTrapv2..."), - ?line unload_master("TestTrap"), - ?line unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("TestTrapv2"), ok. v3_inform_i(X) -> @@ -3310,17 +3312,16 @@ v3_inform_i(X) -> inform_i(X). -sa_error(suite) -> []; sa_error(Config) when is_list(Config) -> ?P(sa_error), {SaNode, _MgrNode, _MibDir} = init_case(Config), ?NPRINT("load OLD-SNMPEA-MIB..."), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), ?NPRINT("start subagent..."), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?NPRINT("Testing sa bad value (is_set_ok)..."), try_test(sa_errs_bad_value), @@ -3332,7 +3333,7 @@ sa_error(Config) when is_list(Config) -> try_test(sa_too_big), ?NPRINT("unload OLD-SNMPEA-MIB..."), - ?line unload_master("OLD-SNMPEA-MIB"), + unload_master("OLD-SNMPEA-MIB"), ?NPRINT("stop subagent..."), stop_subagent(SA). @@ -3352,17 +3353,16 @@ sa_error_3(X) -> sa_error(X). -next_across_sa(suite) -> []; next_across_sa(Config) when is_list(Config) -> ?P(next_across_sa), {SaNode, _MgrNode, MibDir} = init_case(Config), MA = whereis(snmp_master_agent), ?NPRINT("start subagent (1)..."), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?NPRINT("Loading another subagent mib (Klas1)..."), - ?line ok = snmpa:load_mib(SA, MibDir ++ "Klas1"), + ok = snmpa:load_mib(SA, MibDir ++ "Klas1"), ?NPRINT("register subagent..."), rpc:call(SaNode, snmpa, register_subagent, [MA, ?klas1, SA]), @@ -3379,7 +3379,7 @@ next_across_sa(Config) when is_list(Config) -> try_test(unreg_test), ?NPRINT("Starting another subagent (2) "), - ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), + {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"), ?NPRINT("Testing next across subagent (wrong prefix from SA)..."), try_test(next_across_sa_test), @@ -3404,7 +3404,6 @@ next_across_sa_3(X) -> next_across_sa(X). -undo(suite) -> []; undo(Config) when is_list(Config) -> ?P(undo), {SaNode, _MgrNode, MibDir} = init_case(Config), @@ -3412,30 +3411,30 @@ undo(Config) when is_list(Config) -> MA = whereis(snmp_master_agent), ?NPRINT("start subagent (1)..."), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), ?NPRINT("Load Klas3 & Klas4..."), - ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas3")), - ?line ok = snmpa:load_mib(MA, join(MibDir, "Klas4")), + ok = snmpa:load_mib(MA, join(MibDir, "Klas3")), + ok = snmpa:load_mib(MA, join(MibDir, "Klas4")), ?NPRINT("Testing undo phase at master agent..."), try_test(undo_test), try_test(api_test2), ?NPRINT("Unload Klas3..."), - ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas3")), + ok = snmpa:unload_mib(MA, join(MibDir, "Klas3")), ?NPRINT("Testing bad return values from instrum. funcs..."), try_test(bad_return), ?NPRINT("Unload Klas4..."), - ?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas4")), + ok = snmpa:unload_mib(MA, join(MibDir, "Klas4")), ?NPRINT("Testing undo phase at subagent..."), - ?line ok = snmpa:load_mib(SA, join(MibDir, "Klas3")), - ?line ok = snmpa:load_mib(SA, join(MibDir, "Klas4")), - ?line ok = snmpa:register_subagent(MA, ?klas3, SA), - ?line ok = snmpa:register_subagent(MA, ?klas4, SA), + ok = snmpa:load_mib(SA, join(MibDir, "Klas3")), + ok = snmpa:load_mib(SA, join(MibDir, "Klas4")), + ok = snmpa:register_subagent(MA, ?klas3, SA), + ok = snmpa:register_subagent(MA, ?klas4, SA), try_test(undo_test), try_test(api_test3), @@ -3461,47 +3460,44 @@ undo_3(X) -> undo(X). %% Req. Test2 -v1_processing(suite) -> []; v1_processing(Config) when is_list(Config) -> ?P(v1_processing), ?DBG("v1_processing -> entry", []), init_case(Config), ?NPRINT("Load Test2..."), - ?line load_master("Test2"), + load_master("Test2"), try_test(v1_proc), ?NPRINT("Unload Test2..."), - ?line unload_master("Test2"). + unload_master("Test2"). %% Req. Test2 -v2_processing(suite) -> []; v2_processing(Config) when is_list(Config) -> ?P(v2_processing), init_case(Config), ?NPRINT("Load Test2..."), - ?line load_master("Test2"), + load_master("Test2"), try_test(v2_proc), ?NPRINT("Unload Test2..."), - ?line unload_master("Test2"). + unload_master("Test2"). %% Req. Test2 -v3_processing(suite) -> []; v3_processing(Config) when is_list(Config) -> ?P(v3_processing), init_case(Config), ?NPRINT("Load Test2..."), - ?line load_master("Test2"), + load_master("Test2"), try_test(v2_proc), % same as v2! ?NPRINT("Unload Test2..."), - ?line unload_master("Test2"). + unload_master("Test2"). %% We'll try get/set/trap and inform for all the auth & priv protocols. @@ -3523,31 +3519,30 @@ v3_security_cases() -> ]. -v3_crypto_basic(suite) -> []; v3_crypto_basic(_Config) -> ?P(v3_crypto_basic), EID = [0,0,0,0,0,0,0,0,0,0,0,2], %% From rfc2274 appendix A.3.1 - ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), - ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, + KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID), + [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f, 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] = KMd5_1, %% From rfc2274 appendix A.3.2 - ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), - ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, + KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID), + [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23, 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] = KSHA_1, %% From rfc2274, appendix A.5.1 - ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, + KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID), + [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9, 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), %% From rfc2274, appendix A.5.2 - ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, + KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID), + [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4, 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db, @@ -3556,7 +3551,7 @@ v3_crypto_basic(_Config) -> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), KSHA_1t = lists:sublist(KSHA_1, 16), KSHA_2t = lists:sublist(KSHA_2, 16), - ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, + [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b, 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] = @@ -3564,15 +3559,14 @@ v3_crypto_basic(_Config) -> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]), %% Try with correct random - ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), - ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), - ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), - ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), + Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2), + KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1), + Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2), + KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2), ok. -v3_md5_auth(suite) -> []; v3_md5_auth(Config) when is_list(Config) -> ?P(v3_md5_auth), init_case(Config), @@ -3580,26 +3574,25 @@ v3_md5_auth(Config) when is_list(Config) -> ?NPRINT("Testing MD5 authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authMD5", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authMD5", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authMD5"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_sha_auth(suite) -> []; v3_sha_auth(Config) when is_list(Config) -> ?P(v3_sha_auth), init_case(Config), @@ -3607,28 +3600,27 @@ v3_sha_auth(Config) when is_list(Config) -> ?NPRINT("Testing SHA authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authSHA", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authSHA", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authSHA"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_sha224_auth(suite) -> []; v3_sha224_auth(Config) when is_list(Config) -> ?P(v3_sha224_auth), init_case(Config), @@ -3636,28 +3628,27 @@ v3_sha224_auth(Config) when is_list(Config) -> ?NPRINT("Testing SHA224 authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authSHA224", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authSHA224", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authSHA224"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_sha256_auth(suite) -> []; v3_sha256_auth(Config) when is_list(Config) -> ?P(v3_sha256_auth), init_case(Config), @@ -3665,28 +3656,27 @@ v3_sha256_auth(Config) when is_list(Config) -> ?NPRINT("Testing SHA256 authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authSHA256", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authSHA256", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authSHA256"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_sha384_auth(suite) -> []; v3_sha384_auth(Config) when is_list(Config) -> ?P(v3_sha384_auth), init_case(Config), @@ -3694,28 +3684,27 @@ v3_sha384_auth(Config) when is_list(Config) -> ?NPRINT("Testing SHA authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authSHA384", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authSHA384", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authSHA384"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_sha512_auth(suite) -> []; v3_sha512_auth(Config) when is_list(Config) -> ?P(v3_sha512_auth), init_case(Config), @@ -3723,28 +3712,27 @@ v3_sha512_auth(Config) when is_list(Config) -> ?NPRINT("Testing SHA512 authentication...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "authSHA512", authNoPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "authSHA512", authNoPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authNoPriv}, {user, "authSHA512"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). -v3_des_priv(suite) -> []; v3_des_priv(Config) when is_list(Config) -> ?P(v3_des_priv), init_case(Config), @@ -3752,26 +3740,26 @@ v3_des_priv(Config) when is_list(Config) -> ?NPRINT("Testing DES encryption...takes a few seconds..."), AgentConfDir = ?config(agent_conf_dir, Config), - ?line rewrite_target_params_conf(AgentConfDir, "privDES", authPriv), - ?line snmp_target_mib:reconfigure(AgentConfDir), + rewrite_target_params_conf(AgentConfDir, "privDES", authPriv), + snmp_target_mib:reconfigure(AgentConfDir), MA = whereis(snmp_master_agent), snmp_user_based_sm_mib:usmUserTable(print), - ?line load_master("Test2"), - ?line load_master("TestTrap"), - ?line load_master("TestTrapv2"), + load_master("Test2"), + load_master("TestTrap"), + load_master("TestTrapv2"), try_test(v3_sync, [[{v2_proc, []}, {ma_v2_trap1, [MA]}, {v3_inform_sync, [MA]}]], [{sec_level, authPriv}, {user, "privDES"}]), - ?line unload_master("TestTrapv2"), - ?line unload_master("TestTrap"), - ?line unload_master("Test2"), - ?line reset_target_params_conf(AgentConfDir). + unload_master("TestTrapv2"), + unload_master("TestTrap"), + unload_master("Test2"), + reset_target_params_conf(AgentConfDir). %% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]). @@ -3786,18 +3774,17 @@ v3_sync(Funcs) -> v3_inform_sync(MA) -> ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]), - ?line snmpa:send_notification(MA, testTrapv22, no_receiver, + snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []), %% Make sure agent is in sync with mgr... ?DBG("v3_sync -> wait some time: ",[]), ?SLEEP(20000), % more than 1500*10 in target_addr.conf ?DBG("v3_sync -> await response",[]), - ?line ?expect2({inform, true}, + ?expect2({inform, true}, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}]). -v2_caps(suite) -> []; v2_caps(Config) when is_list(Config) -> ?P(v2_caps), init_case(Config), @@ -3808,13 +3795,13 @@ v2_caps_3(X) -> ?P(v2_caps_3), v2_caps(X). v2_caps_i(Node) -> - ?line Idx = rpc:call(Node, snmpa, add_agent_caps, [[1,2,3,4,5], "test cap"]), + Idx = rpc:call(Node, snmpa, add_agent_caps, [[1,2,3,4,5], "test cap"]), g([[sysORID, Idx], [sysORDescr, Idx]]), - ?line ?expect1([{[sysORID, Idx], [1,2,3,4,5]}, + ?expect1([{[sysORID, Idx], [1,2,3,4,5]}, {[sysORDescr, Idx], "test cap"}]), - ?line rpc:call(Node, snmpa, del_agent_caps, [Idx]), + rpc:call(Node, snmpa, del_agent_caps, [Idx]), g([[sysORID, Idx]]), - ?line ?expect1([{[sysORID, Idx], noSuchInstance}]). + ?expect1([{[sysORID, Idx], noSuchInstance}]). %% Req. Test2 @@ -3830,85 +3817,85 @@ v1_proc() -> v1_get_p() -> %% 4.1.2:1 g([[test2]]), - ?line ?expect3(noSuchName, 1, [{[test2], 'NULL'}]), + ?expect3(noSuchName, 1, [{[test2], 'NULL'}]), g([[tDescr]]), - ?line ?expect3(noSuchName, 1, [{[tDescr], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tDescr], 'NULL'}]), g([[tDescr2,0]]), - ?line ?expect3(noSuchName, 1, [{[tDescr2,0], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tDescr2,0], 'NULL'}]), g([[tDescr3,0]]), - ?line ?expect3(noSuchName, 1, [{[tDescr3,0], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tDescr3,0], 'NULL'}]), g([[tDescr4,0]]), - ?line ?expect3(noSuchName, 1, [{[tDescr4,0], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tDescr4,0], 'NULL'}]), g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line ?expect3(noSuchName, 2, [{[sysDescr, 0], 'NULL'}, + ?expect3(noSuchName, 2, [{[sysDescr, 0], 'NULL'}, {[tDescr,0], 'NULL'}]), g([[sysDescr,3]]), - ?line ?expect3(noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), + ?expect3(noSuchName, 1, [{[sysDescr, 3], 'NULL'}]), %% 4.1.2:2 g([[tTable]]), - ?line ?expect3(noSuchName, 1, [{[tTable], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tTable], 'NULL'}]), g([[tEntry]]), - ?line ?expect3(noSuchName, 1, [{[tEntry], 'NULL'}]), + ?expect3(noSuchName, 1, [{[tEntry], 'NULL'}]), %% 4.1.2:3 g([[tTooBig, 0]]), - ?line ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]), + ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]), %% 4.1.2:4 g([[tGenErr1, 0]]), - ?line ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]), g([[tGenErr2, 0]]), - ?line ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]), g([[sysDescr, 0], [tGenErr3, 0]]), - ?line ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'}, + ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'}, {[tGenErr3, 0], 'NULL'}]). v1_get_next_p() -> %% 4.1.3:1 gn([[1,3,7,1]]), - ?line ?expect3(noSuchName, 1, [{[1,3,7,1], 'NULL'}]), + ?expect3(noSuchName, 1, [{[1,3,7,1], 'NULL'}]), gn([[tDescr2]]), - ?line ?expect3(tooBig, 0, any), + ?expect3(tooBig, 0, any), %% 4.1.3:2 gn([[tTooBig]]), io:format("We currently don't handle tooBig correct!!!\n"), - ?line ?expect3(tooBig, 0, any), + ?expect3(tooBig, 0, any), %% 4.1.3:3 gn([[tGenErr1]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), gn([[tGenErr2]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), gn([[sysDescr], [tGenErr3]]), - ?line ?expect3(genErr, 2, any). + ?expect3(genErr, 2, any). v1_set_p() -> %% 4.1.5:1 s([{[1,3,7,0], i, 4}]), - ?line ?expect3(noSuchName, 1, [{[1,3,7,0], 4}]), + ?expect3(noSuchName, 1, [{[1,3,7,0], 4}]), s([{[tDescr,0], s, "outside mibview"}]), - ?line ?expect3(noSuchName, 1, [{[tDescr,0], "outside mibview"}]), + ?expect3(noSuchName, 1, [{[tDescr,0], "outside mibview"}]), s([{[tDescr3,0], s, "read-only"}]), - ?line ?expect3(noSuchName, 1, [{[tDescr3,0], "read-only"}]), + ?expect3(noSuchName, 1, [{[tDescr3,0], "read-only"}]), s([{[tDescr3], s, "noSuchObject"}]), - ?line ?expect3(noSuchName, 1, [{[tDescr3], "noSuchObject"}]), + ?expect3(noSuchName, 1, [{[tDescr3], "noSuchObject"}]), s([{[tDescr3,1], s, "noSuchInstance"}]), - ?line ?expect3(noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), + ?expect3(noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]), s([{[tDescr2,0], s, "inconsistentName"}]), - ?line ?expect3(noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), + ?expect3(noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]), %% 4.1.5:2 s([{[tDescr2, 0], i, 4}]), - ?line ?expect3(badValue, 1, [{[tDescr2, 0], 4}]), + ?expect3(badValue, 1, [{[tDescr2, 0], 4}]), s([{[tDescr2, 0], s, "badValue"}]), - ?line ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]), + ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]), %% 4.1.5:3 %% The standard is quite incorrect here. The resp pdu was too big. In @@ -3918,14 +3905,14 @@ v1_set_p() -> %% of the std-like original value. s([{[tTooBig, 0], s, ?tooBigStr}]), %% according to std: -% ?line ?expect3(tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), - ?line ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]), +% ?expect3(tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]), + ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]), %% 4.1.5:4 s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), + ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]), s([{[tDescr2, 0], s, "commit_fail"}]), - ?line ?expect3(genErr, 1, [{[tDescr2, 0], "commit_fail"}]). + ?expect3(genErr, 1, [{[tDescr2, 0], "commit_fail"}]). %% Req. Test2 v2_proc() -> @@ -3941,94 +3928,94 @@ v2_get_p() -> %% 4.2.1:2 ?DBG("v2_get_p -> entry",[]), g([[test2]]), - ?line ?expect1([{[test2], noSuchObject}]), + ?expect1([{[test2], noSuchObject}]), g([[tDescr]]), - ?line ?expect1([{[tDescr], noSuchObject}]), + ?expect1([{[tDescr], noSuchObject}]), g([[tDescr4,0]]), - ?line ?expect1([{[tDescr4,0], noSuchObject}]), + ?expect1([{[tDescr4,0], noSuchObject}]), g([[sysDescr, 0], [tDescr,0]]), % Outside mibview - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {[tDescr,0], noSuchObject}]), g([[tTable]]), - ?line ?expect1([{[tTable], noSuchObject}]), + ?expect1([{[tTable], noSuchObject}]), g([[tEntry]]), - ?line ?expect1([{[tEntry], noSuchObject}]), + ?expect1([{[tEntry], noSuchObject}]), %% 4.2.1:3 g([[tDescr2,0]]), %% instrum ret noSuchName!!! - ?line ?expect1([{[tDescr2,0], noSuchInstance}]), + ?expect1([{[tDescr2,0], noSuchInstance}]), g([[tDescr3,0]]), - ?line ?expect1([{[tDescr3,0], noSuchInstance}]), + ?expect1([{[tDescr3,0], noSuchInstance}]), g([[sysDescr,3]]), - ?line ?expect1([{[sysDescr, 3], noSuchInstance}]), + ?expect1([{[sysDescr, 3], noSuchInstance}]), g([[tIndex,1]]), - ?line ?expect1([{[tIndex, 1], noSuchInstance}]), + ?expect1([{[tIndex, 1], noSuchInstance}]), %% 4.2.1 - any other error: genErr g([[tGenErr1, 0]]), - ?line ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]), g([[tGenErr2, 0]]), - ?line ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]), g([[sysDescr, 0], [tGenErr3, 0]]), - ?line ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'}, + ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'}, {[tGenErr3, 0], 'NULL'}]), %% 4.2.1 - tooBig g([[tTooBig, 0]]), - ?line ?expect3(tooBig, 0, []). + ?expect3(tooBig, 0, []). v2_get_next_p() -> %% 4.2.2:2 ?DBG("v2_get_next_p -> entry",[]), gn([[1,3,7,1]]), - ?line ?expect1([{[1,3,7,1], endOfMibView}]), + ?expect1([{[1,3,7,1], endOfMibView}]), gn([[sysDescr], [1,3,7,1]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}]), gn([[tCnt2, 1]]), - ?line ?expect1([{[tCnt2,2], 100}]), + ?expect1([{[tCnt2,2], 100}]), gn([[tCnt2, 2]]), - ?line ?expect1([{[tCnt2,2], endOfMibView}]), + ?expect1([{[tCnt2,2], endOfMibView}]), %% 4.2.2 - any other error: genErr gn([[tGenErr1]]), - ?line ?expect3(genErr, 1, [{[tGenErr1], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr1], 'NULL'}]), gn([[tGenErr2]]), - ?line ?expect3(genErr, 1, [{[tGenErr2], 'NULL'}]), + ?expect3(genErr, 1, [{[tGenErr2], 'NULL'}]), gn([[sysDescr], [tGenErr3]]), - ?line ?expect3(genErr, 2, [{[sysDescr], 'NULL'}, + ?expect3(genErr, 2, [{[sysDescr], 'NULL'}, {[tGenErr3], 'NULL'}]), %% 4.2.2 - tooBig gn([[tTooBig]]), - ?line ?expect3(tooBig, 0, []). + ?expect3(tooBig, 0, []). v2_get_bulk_p() -> %% 4.2.3 ?DBG("v2_get_bulk_p -> entry",[]), gb(1, 1, []), - ?line ?expect1([]), + ?expect1([]), gb(-1, 1, []), - ?line ?expect1([]), + ?expect1([]), gb(-1, -1, []), - ?line ?expect1([]), + ?expect1([]), gb(-1, -1, []), - ?line ?expect1([]), + ?expect1([]), gb(2, 0, [[sysDescr], [1,3,7,1]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}]), gb(1, 2, [[sysDescr], [1,3,7,1]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}]), gb(0, 2, [[sysDescr], [1,3,7,1]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}, {[sysObjectID, 0], [1,2,3]}, {[1,3,7,1], endOfMibView}]), gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}, {[sysDescr, 0], "Erlang SNMP agent"}, {[1,3,7,1], endOfMibView}, @@ -4036,19 +4023,19 @@ v2_get_bulk_p() -> {[1,3,7,1], endOfMibView}]), gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]), - ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr, 0], "Erlang SNMP agent"}, {[sysDescr, 0], "Erlang SNMP agent"}]), gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig. - ?line ?expect1([]), + ?expect1([]), gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]), - ?line ?expect3(genErr, 3, [{[sysDescr], 'NULL'}, + ?expect3(genErr, 3, [{[sysDescr], 'NULL'}, {[sysObjectID], 'NULL'}, {[tGenErr1], 'NULL'}, {[sysDescr], 'NULL'}]), gb(0, 2, [[tCnt2, 1]]), - ?line ?expect1([{[tCnt2,2], 100}, + ?expect1([{[tCnt2,2], 100}, {[tCnt2,2], endOfMibView}]). @@ -4056,68 +4043,68 @@ v2_set_p() -> %% 4.2.5:1 ?DBG("v2_set_p -> entry",[]), s([{[1,3,7,0], i, 4}]), - ?line ?expect3(noAccess, 1, [{[1,3,7,0], 4}]), + ?expect3(noAccess, 1, [{[1,3,7,0], 4}]), s([{[tDescr,0], s, "outside mibview"}]), - ?line ?expect3(noAccess, 1, [{[tDescr,0], "outside mibview"}]), + ?expect3(noAccess, 1, [{[tDescr,0], "outside mibview"}]), %% 4.2.5:2 s([{[1,3,6,1,0], s, "noSuchObject"}]), - ?line ?expect3(notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), + ?expect3(notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]), %% 4.2.5:3 s([{[tDescr2, 0], i, 4}]), - ?line ?expect3(wrongType, 1, [{[tDescr2, 0], 4}]), + ?expect3(wrongType, 1, [{[tDescr2, 0], 4}]), s([{[tDescr2, 0], s, "badValue"}]), - ?line ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]), + ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]), %% 4.2.5:4 s([{[tStr, 0], s, ""}]), - ?line ?expect3(wrongLength, 1, [{[tStr, 0], ""}]), + ?expect3(wrongLength, 1, [{[tStr, 0], ""}]), s([{[tStr, 0], s, "12345"}]), - ?line ?expect3(wrongLength, 1, [{[tStr, 0], "12345"}]), + ?expect3(wrongLength, 1, [{[tStr, 0], "12345"}]), %% 4.2.5:5 - N/A %% 4.2.5:6 s([{[tInt1, 0], i, 0}]), - ?line ?expect3(wrongValue, 1, [{[tInt1, 0], 0}]), + ?expect3(wrongValue, 1, [{[tInt1, 0], 0}]), s([{[tInt1, 0], i, 5}]), - ?line ?expect3(wrongValue, 1, [{[tInt1, 0], 5}]), + ?expect3(wrongValue, 1, [{[tInt1, 0], 5}]), s([{[tInt2, 0], i, 0}]), - ?line ?expect3(wrongValue, 1, [{[tInt2, 0], 0}]), + ?expect3(wrongValue, 1, [{[tInt2, 0], 0}]), s([{[tInt2, 0], i, 5}]), - ?line ?expect3(wrongValue, 1, [{[tInt2, 0], 5}]), + ?expect3(wrongValue, 1, [{[tInt2, 0], 5}]), s([{[tInt3, 0], i, 5}]), - ?line ?expect3(wrongValue, 1, [{[tInt3, 0], 5}]), + ?expect3(wrongValue, 1, [{[tInt3, 0], 5}]), %% 4.2.5:7 s([{[tDescrX, 1, 1], s, "noCreation"}]), - ?line ?expect3(noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), + ?expect3(noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]), %% 4.2.5:8 s([{[tDescrX, 1, 2], s, "inconsistentName"}]), - ?line ?expect3(inconsistentName, 1, + ?expect3(inconsistentName, 1, [{[tDescrX, 1, 2], "inconsistentName"}]), %% 4.2.5:9 s([{[tCnt, 1, 2], i, 5}]), - ?line ?expect3(notWritable, 1, [{[tCnt, 1, 2], 5}]), + ?expect3(notWritable, 1, [{[tCnt, 1, 2], 5}]), s([{[tDescr3,0], s, "read-only"}]), - ?line ?expect3(notWritable, 1, [{[tDescr3,0], "read-only"}]), + ?expect3(notWritable, 1, [{[tDescr3,0], "read-only"}]), %% 4.2.5:10 s([{[tDescr2,0], s, "inconsistentValue"}]), - ?line ?expect3(inconsistentValue, 1, + ?expect3(inconsistentValue, 1, [{[tDescr2,0], "inconsistentValue"}]), %% 4.2.5:11 s([{[tDescr2,0], s, "resourceUnavailable"}]), - ?line ?expect3(resourceUnavailable, 1, + ?expect3(resourceUnavailable, 1, [{[tDescr2,0],"resourceUnavailable"}]), %% 4.2.5:12 s([{[tDescr2, 0], s, "is_set_ok_fail"}]), - ?line ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). + ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]). %% commitFailed and undoFailed is tested by the 'undo' case. @@ -4131,26 +4118,26 @@ table_test() -> Key1c4 = [intCommunityAccess,get(mip),is("public")], EndKey = [intCommunityEntry,[9],get(mip),is("public")], gn([[intCommunityEntry]]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), gn([[intCommunityTable]]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), gn([[community]]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), gn([[otpSnmpeaMIB]]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), gn([[ericsson]]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), gn([Key1c3]), - ?line ?expect1([{Key2c3, 2}]), + ?expect1([{Key2c3, 2}]), gn([Key2c3]), - ?line ?expect1([{Key1c4, 2}]), + ?expect1([{Key1c4, 2}]), gn([EndKey]), AgentIp = [intAgentIpAddress,0], - ?line ?expect1([{AgentIp, any}]), + ?expect1([{AgentIp, any}]), g([Key1c3]), - ?line ?expect1([{Key1c3, 2}]), + ?expect1([{Key1c3, 2}]), g([EndKey]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{EndKey, noSuchObject}])), io:format("Testing row creation/deletion on communityTable...~n"), @@ -4158,33 +4145,33 @@ table_test() -> NewKeyc4 = [intCommunityAccess,get(mip),is("test")], NewKeyc5 = [intCommunityStatus,get(mip),is("test")], s([{NewKeyc5, ?createAndGo}]), - ?line ?expect3(?v1_2(badValue, inconsistentValue), 1, any), + ?expect3(?v1_2(badValue, inconsistentValue), 1, any), s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]), - ?line ?expect1([{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), + ?expect1([{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]), g([NewKeyc4]), - ?line ?expect1([{NewKeyc4, 2}]), + ?expect1([{NewKeyc4, 2}]), s([{NewKeyc5, ?destroy}]), - ?line ?expect1([{NewKeyc5, ?destroy}]), + ?expect1([{NewKeyc5, ?destroy}]), s([{NewKeyc4, 2}]), - ?line ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc4, 2}]), + ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc4, 2}]), s([{NewKeyc5, ?createAndWait}]), - ?line ?expect1([{NewKeyc5, ?createAndWait}]), + ?expect1([{NewKeyc5, ?createAndWait}]), g([NewKeyc5]), - ?line ?expect1([{NewKeyc5, ?notReady}]), + ?expect1([{NewKeyc5, ?notReady}]), s([{NewKeyc4, 2}]), - ?line ?expect1([{NewKeyc4, 2}]), + ?expect1([{NewKeyc4, 2}]), g([NewKeyc5]), - ?line ?expect1([{NewKeyc5, ?notReady}]), + ?expect1([{NewKeyc5, ?notReady}]), s([{NewKeyc3, 2}]), - ?line ?expect1([{NewKeyc3, 2}]), + ?expect1([{NewKeyc3, 2}]), g([NewKeyc5]), - ?line ?expect1([{NewKeyc5, ?notInService}]), + ?expect1([{NewKeyc5, ?notInService}]), s([{NewKeyc5, ?active}]), - ?line ?expect1([{NewKeyc5, ?active}]), + ?expect1([{NewKeyc5, ?active}]), s([{NewKeyc5, ?destroy}]), - ?line ?expect1([{NewKeyc5, ?destroy}]), + ?expect1([{NewKeyc5, ?destroy}]), s([{NewKeyc3, 3}]), - ?line ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc3, 3}]), + ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc3, 3}]), otp_1128_test(), ok. @@ -4192,46 +4179,45 @@ table_test() -> simple_standard_test() -> ?DBG("simple_standard_test -> entry",[]), gn([[1,1]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3,6]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3,6,1]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3,6,1,2]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3,6,1,2,1]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[1,3,6,1,2,1,1]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), gn([[sysDescr]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), g([[sysDescr,0]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]), g([[sysDescr]]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{[sysDescr], noSuchObject}])), g([[1,6,7,0]]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{[1,6,7,0], noSuchObject}])), gn([[1,13]]), - ?line ?v1_2(?expect3(noSuchName,1, any), + ?v1_2(?expect3(noSuchName,1, any), ?expect1([{[1,13], endOfMibView}])), s([{[sysLocation, 0], "new_value"}]), - ?line ?expect1([{[sysLocation, 0], "new_value"}]), + ?expect1([{[sysLocation, 0], "new_value"}]), g([[sysLocation, 0]]), - ?line ?expect1([{[sysLocation, 0], "new_value"}]), + ?expect1([{[sysLocation, 0], "new_value"}]), io:format("Testing noSuchName and badValue...~n"), s([{[sysServices,0], 3}]), - ?line ?expect3(?v1_2(noSuchName, notWritable), 1, any), + ?expect3(?v1_2(noSuchName, notWritable), 1, any), s([{[sysLocation, 0], i, 3}]), - ?line ?expect3(?v1_2(badValue, wrongType), 1, any), + ?expect3(?v1_2(badValue, wrongType), 1, any), ?DBG("simple_standard_test -> done",[]), ok. %% This is run in the agent node -db_notify_client(suite) -> []; db_notify_client(Config) when is_list(Config) -> ?P(db_notify_client), {_SaNode, _MgrNode, _MibDir} = init_case(Config), @@ -4280,11 +4266,11 @@ db_notify_client(Config) when is_list(Config) -> db_notify_client_test() -> ?DBG("set first new sysLocation",[]), s([{[sysLocation, 0], "new_value"}]), - ?line ?expect1([{[sysLocation, 0], "new_value"}]), + ?expect1([{[sysLocation, 0], "new_value"}]), ?DBG("set second new sysLocation",[]), s([{[sysLocation, 0], "new_value"}]), - ?line ?expect1([{[sysLocation, 0], "new_value"}]). + ?expect1([{[sysLocation, 0], "new_value"}]). %% Callback function notify(Pid, What) -> @@ -4300,23 +4286,23 @@ big_test() -> ?DBG("big_test -> testing simple next/get/set @ subagent...",[]), gn([[klas1]]), - ?line ?expect1([{[fname,0], ""}]), + ?expect1([{[fname,0], ""}]), g([[fname,0]]), - ?line ?expect1([{[fname,0], ""}]), + ?expect1([{[fname,0], ""}]), s([{[fname,0], s, "test set"}]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), g([[fname,0]]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), ?DBG("big_test -> " "testing next from last instance in master to subagent...",[]), gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), gn([[1,1], [?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {[fname,0], "test set"}]), s([{[fname,0], s, ""}]), - ?line ?expect1([{[fname,0], ""}]), + ?expect1([{[fname,0], ""}]), table_test(), @@ -4324,14 +4310,14 @@ big_test() -> _FTab = [friendsEntry], s([{[friendsEntry, [2, 3]], s, "kompis3"}, {[friendsEntry, [3, 3]], i, ?createAndGo}]), - ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, {[friendsEntry, [3, 3]], ?createAndGo}]), g([[friendsEntry, [2, 3]], [friendsEntry, [3, 3]]]), - ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, {[friendsEntry, [3, 3]], ?active}]), s([{[friendsEntry, [3, 3]], i, ?destroy}]), - ?line ?expect1([{[friendsEntry, [3, 3]], ?destroy}]), + ?expect1([{[friendsEntry, [3, 3]], ?destroy}]), otp_1131_test(), @@ -4339,28 +4325,28 @@ big_test() -> []), s([{[kompissEntry, [1, 3]], s, "kompis3"}, {[kompissEntry, [2, 3]], i, ?createAndGo}]), - ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, {[kompissEntry, [2, 3]], ?createAndGo}]), g([[kompissEntry, [1, 3]], [kompissEntry, [2, 3]]]), - ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, {[kompissEntry, [2, 3]], ?active}]), gn([[kompissEntry, [1]], [kompissEntry, [2]]]), - ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry, [1, 3]], "kompis3"}, {[kompissEntry, [2, 3]], ?active}]), s([{[kompissEntry, [1, 2]], s, "kompis3"}, {[kompissEntry, [2, 2]], i, ?createAndGo}]), - ?line ?expect1([{[kompissEntry, [1, 2]], "kompis3"}, + ?expect1([{[kompissEntry, [1, 2]], "kompis3"}, {[kompissEntry, [2, 2]], ?createAndGo}]), gn([[kompissEntry, [1, 1]], [kompissEntry, [2, 1]]]), - ?line ?expect1([{[kompissEntry, [1, 2]], "kompis3"}, + ?expect1([{[kompissEntry, [1, 2]], "kompis3"}, {[kompissEntry, [2, 2]], ?active}]), s([{[kompissEntry, [2, 3]], i, ?destroy}]), - ?line ?expect1([{[kompissEntry, [2, 3]], ?destroy}]), + ?expect1([{[kompissEntry, [2, 3]], ?destroy}]), s([{[kompissEntry, [2, 2]], i, ?destroy}]), - ?line ?expect1([{[kompissEntry, [2, 2]], ?destroy}]), + ?expect1([{[kompissEntry, [2, 2]], ?destroy}]), ?DBG("big_test -> done",[]), ok. @@ -4371,21 +4357,21 @@ big_test_2() -> ?NPRINT("Testing simple next/get/set @ subagent (2)..."), gn([[klas2]]), - ?line ?expect1([{[fname2,0], ""}]), + ?expect1([{[fname2,0], ""}]), g([[fname2,0]]), - ?line ?expect1([{[fname2,0], ""}]), + ?expect1([{[fname2,0], ""}]), s([{[fname2,0], s, "test set"}]), - ?line ?expect1([{[fname2,0], "test set"}]), + ?expect1([{[fname2,0], "test set"}]), g([[fname2,0]]), - ?line ?expect1([{[fname2,0], "test set"}]), + ?expect1([{[fname2,0], "test set"}]), otp_1298_test(), ?NPRINT("Testing next from last object in master to subagent (2)..."), gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[fname2,0], "test set"}]), + ?expect1([{[fname2,0], "test set"}]), gn([[1,1], [?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {[fname2,0], "test set"}]), table_test(), @@ -4394,40 +4380,40 @@ big_test_2() -> _FTab = [friendsEntry2], s([{[friendsEntry2, [2, 3]], s, "kompis3"}, {[friendsEntry2, [3, 3]], i, ?createAndGo}]), - ?line ?expect1([{[friendsEntry2, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry2, [2, 3]], "kompis3"}, {[friendsEntry2, [3, 3]], ?createAndGo}]), g([[friendsEntry2, [2, 3]], [friendsEntry2, [3, 3]]]), - ?line ?expect1([{[friendsEntry2, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry2, [2, 3]], "kompis3"}, {[friendsEntry2, [3, 3]], ?active}]), s([{[friendsEntry2, [3, 3]], i, ?destroy}]), - ?line ?expect1([{[friendsEntry2, [3, 3]], ?destroy}]), + ?expect1([{[friendsEntry2, [3, 3]], ?destroy}]), ?NPRINT("Adding two rows in subagent table with special INDEX (2)"), s([{[kompissEntry2, [1, 3]], s, "kompis3"}, {[kompissEntry2, [2, 3]], i, ?createAndGo}]), - ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, {[kompissEntry2, [2, 3]], ?createAndGo}]), g([[kompissEntry2, [1, 3]], [kompissEntry2, [2, 3]]]), - ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, {[kompissEntry2, [2, 3]], ?active}]), gn([[kompissEntry2, [1]], [kompissEntry2, [2]]]), - ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, + ?expect1([{[kompissEntry2, [1, 3]], "kompis3"}, {[kompissEntry2, [2, 3]], ?active}]), s([{[kompissEntry2, [1, 2]], s, "kompis3"}, {[kompissEntry2, [2, 2]], i, ?createAndGo}]), - ?line ?expect1([{[kompissEntry2, [1, 2]], "kompis3"}, + ?expect1([{[kompissEntry2, [1, 2]], "kompis3"}, {[kompissEntry2, [2, 2]], ?createAndGo}]), gn([[kompissEntry2, [1, 1]], [kompissEntry2, [2, 1]]]), - ?line ?expect1([{[kompissEntry2, [1, 2]], "kompis3"}, + ?expect1([{[kompissEntry2, [1, 2]], "kompis3"}, {[kompissEntry2, [2, 2]], ?active}]), s([{[kompissEntry2, [2, 3]], i, ?destroy}]), - ?line ?expect1([{[kompissEntry2, [2, 3]], ?destroy}]), + ?expect1([{[kompissEntry2, [2, 3]], ?destroy}]), s([{[kompissEntry2, [2, 2]], i, ?destroy}]), - ?line ?expect1([{[kompissEntry2, [2, 2]], ?destroy}]), + ?expect1([{[kompissEntry2, [2, 2]], ?destroy}]), ok. %% Req. Test1 @@ -4436,26 +4422,26 @@ multi_threaded_test() -> g([[multiStr,0]]), Pid = get_multi_pid(), g([[sysUpTime,0]]), - ?line ?expect1([{[sysUpTime,0], any}]), + ?expect1([{[sysUpTime,0], any}]), s([{[sysLocation, 0], s, "pelle"}]), - ?line ?expect1([{[sysLocation, 0], "pelle"}]), + ?expect1([{[sysLocation, 0], "pelle"}]), Pid ! continue, - ?line ?expect1([{[multiStr,0], "ok"}]), + ?expect1([{[multiStr,0], "ok"}]), s([{[multiStr, 0], s, "block"}]), Pid2 = get_multi_pid(), g([[sysUpTime,0]]), - ?line ?expect1([{[sysUpTime,0], any}]), + ?expect1([{[sysUpTime,0], any}]), g([[multiStr,0]]), Pid3 = get_multi_pid(), g([[sysUpTime,0]]), - ?line ?expect1([{[sysUpTime,0], any}]), + ?expect1([{[sysUpTime,0], any}]), s([{[sysLocation, 0], s, "kalle"}]), Pid3 ! continue, - ?line ?expect1([{[multiStr,0], "ok"}]), + ?expect1([{[multiStr,0], "ok"}]), Pid2 ! continue, - ?line ?expect1([{[multiStr,0], "block"}]), - ?line ?expect1([{[sysLocation,0], "kalle"}]). + ?expect1([{[multiStr,0], "block"}]), + ?expect1([{[sysLocation,0], "kalle"}]). %% Req. Test1, TestTrapv2 mt_trap_test(MA, MT) -> @@ -4463,12 +4449,12 @@ mt_trap_test(MA, MT) -> ?IPRINT("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?IPRINT("mt_trap_test(02) -> await v2trap", []), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}]), %% multi-threaded = true %% This will *lock* the 'main thread' of a multi-threaded agent, - %% the worker state will be 'busy'. Therefor when a new request + %% the worker state will be 'busy'. Therefore when a new request %% arrives a new *temporary* worker will be spawned. ?IPRINT("mt_trap_test(03) -> issue mtTrap (standard trap)", []), snmpa:send_trap(MA, mtTrap, "standard trap"), @@ -4477,7 +4463,7 @@ mt_trap_test(MA, MT) -> g([[sysUpTime,0]]), ?IPRINT("mt_trap_test(06) -> await sysUpTime", []), - ?line ?expect1([{[sysUpTime,0], any}]), + ?expect1([{[sysUpTime,0], any}]), %% This will *only* work if multi-threaded is 'true', not 'extended' %% since in the latter case all notifications are serialized through @@ -4488,7 +4474,7 @@ mt_trap_test(MA, MT) -> ?IPRINT("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), ?IPRINT("mt_trap_test(08) -> await v2trap", []), - ?line ?expect2(v2trap, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}]); true -> @@ -4499,7 +4485,7 @@ mt_trap_test(MA, MT) -> Pid ! continue, ?IPRINT("mt_trap_test(10) -> await v2trap", []), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?testTrap ++ [2]}, {[multiStr,0], "ok"}]), ?IPRINT("mt_trap_test(11) -> done", []), @@ -4509,7 +4495,7 @@ mt_trap_test(MA, MT) -> get_multi_pid() -> get_multi_pid(10). get_multi_pid(0) -> - ?line ?FAIL(no_global_name); + ?FAIL(no_global_name); get_multi_pid(N) -> ?SLEEP(1000), case global:whereis_name(snmp_multi_tester) of @@ -4522,26 +4508,26 @@ types_v2_test() -> ?NPRINT("Testing v2 types..."), s([{[bits1,0], 2#10}]), - ?line ?expect1([{[bits1,0], ?str(2#10)}]), + ?expect1([{[bits1,0], ?str(2#10)}]), g([[bits1,0]]), - ?line ?expect1([{[bits1,0], ?str(2#101)}]), + ?expect1([{[bits1,0], ?str(2#101)}]), s([{[bits2,0], 2#11000000110}]), - ?line ?expect1([{[bits2,0], ?str(2#11000000110)}]), + ?expect1([{[bits2,0], ?str(2#11000000110)}]), g([[bits2,0]]), - ?line ?expect1([{[bits2,0], ?str(2#11000000110)}]), + ?expect1([{[bits2,0], ?str(2#11000000110)}]), g([[bits3,0]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), g([[bits4,0]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), s([{[bits1,0], s, [2#10]}]), - ?line ?expect3(?v1_2(badValue, wrongValue), 1, any), + ?expect3(?v1_2(badValue, wrongValue), 1, any), s([{[bits2,0], 2#11001001101010011}]), - ?line ?expect3(?v1_2(badValue, wrongValue), 1, any). + ?expect3(?v1_2(badValue, wrongValue), 1, any). %% Req. Test1 @@ -4557,52 +4543,52 @@ implied_test(MA) -> Idx2 = "qq", ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]), s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]), - ?line ?expect1([{[testStatus, Idx1], ?createAndGo}, + ?expect1([{[testStatus, Idx1], ?createAndGo}, {[testDescr, Idx1], "row 1"}]), ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]), s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]), - ?line ?expect1([{[testStatus, Idx2], ?createAndGo}, + ?expect1([{[testStatus, Idx2], ?createAndGo}, {[testDescr, Idx2], "row 2"}]), ?DBG("implied_test -> get-next(testDescr)",[]), gn([[testDescr]]), - ?line ?expect1([{[testDescr,Idx1], "row 1"}]), + ?expect1([{[testDescr,Idx1], "row 1"}]), ?DBG("implied_test -> get-next(testDescr) of row 1",[]), gn([[testDescr,Idx1]]), - ?line ?expect1([{[testDescr,Idx2], "row 2"}]), + ?expect1([{[testDescr,Idx2], "row 2"}]), % Delete the rows ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]), s([{[testStatus, Idx1], i, ?destroy}]), - ?line ?expect1([{[testStatus, Idx1], ?destroy}]), + ?expect1([{[testStatus, Idx1], ?destroy}]), ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]), s([{[testStatus, Idx2], i, ?destroy}]), - ?line ?expect1([{[testStatus, Idx2], ?destroy}]), + ?expect1([{[testStatus, Idx2], ?destroy}]), %% Try the same in other table Idx3 = [1, "apa"], Idx4 = [1, "qq"], ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]), s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]), - ?line ?expect1([{[testStatus2, Idx3], ?createAndGo}, + ?expect1([{[testStatus2, Idx3], ?createAndGo}, {[testDescr2, Idx3], "row 1"}]), ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]), s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]), - ?line ?expect1([{[testStatus2, Idx4], ?createAndGo}, + ?expect1([{[testStatus2, Idx4], ?createAndGo}, {[testDescr2, Idx4], "row 2"}]), ?DBG("implied_test -> get-next(testDescr2)",[]), gn([[testDescr2]]), - ?line ?expect1([{[testDescr2,Idx3], "row 1"}]), + ?expect1([{[testDescr2,Idx3], "row 1"}]), ?DBG("implied_test -> get-next(testDescr2) of row 1",[]), gn([[testDescr2,Idx3]]), - ?line ?expect1([{[testDescr2,Idx4], "row 2"}]), + ?expect1([{[testDescr2,Idx4], "row 2"}]), % Delete the rows ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]), s([{[testStatus2, Idx3], i, ?destroy}]), - ?line ?expect1([{[testStatus2, Idx3], ?destroy}]), + ?expect1([{[testStatus2, Idx3], ?destroy}]), ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]), s([{[testStatus2, Idx4], i, ?destroy}]), - ?line ?expect1([{[testStatus2, Idx4], ?destroy}]), + ?expect1([{[testStatus2, Idx4], ?destroy}]), snmpa:verbosity(MA, log), @@ -4620,25 +4606,25 @@ sparse_table_test() -> Idx2 = 2, s([{[sparseStatus, Idx1], i, ?createAndGo}, {[sparseDescr, Idx1], s, "row 1"}]), - ?line ?expect1([{[sparseStatus, Idx1], ?createAndGo}, + ?expect1([{[sparseStatus, Idx1], ?createAndGo}, {[sparseDescr, Idx1], "row 1"}]), s([{[sparseStatus, Idx2], i, ?createAndGo}, {[sparseDescr, Idx2], s, "row 2"}]), - ?line ?expect1([{[sparseStatus, Idx2], ?createAndGo}, + ?expect1([{[sparseStatus, Idx2], ?createAndGo}, {[sparseDescr, Idx2], "row 2"}]), ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2], [sparseStatus,Idx1], [sparseStatus,Idx2]]), gb(0,5,[[sparseIndex]])), - ?line ?expect1([{[sparseDescr,Idx1], "row 1"}, + ?expect1([{[sparseDescr,Idx1], "row 1"}, {[sparseDescr,Idx2], "row 2"}, {[sparseStatus,Idx1], ?active}, {[sparseStatus,Idx2], ?active}, {[sparseStr,0], "slut"}]), %% Delete the rows s([{[sparseStatus, Idx1], i, ?destroy}]), - ?line ?expect1([{[sparseStatus, Idx1], ?destroy}]), + ?expect1([{[sparseStatus, Idx1], ?destroy}]), s([{[sparseStatus, Idx2], i, ?destroy}]), - ?line ?expect1([{[sparseStatus, Idx2], ?destroy}]). + ?expect1([{[sparseStatus, Idx2], ?destroy}]). %% Req. Test1 @@ -4653,12 +4639,12 @@ cnt_64_test(MA) -> ?DBG("get cnt64",[]), g([[cnt64,0]]), ?DBG("await response",[]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{[cnt64,0],18446744073709551615}])), ?DBG("get-next cnt64",[]), gn([[cnt64]]), ?DBG("await response",[]), - ?line ?v1_2(?expect1([{[cnt64Str,0], "after cnt64"}]), + ?v1_2(?expect1([{[cnt64Str,0], "after cnt64"}]), ?expect1([{[cnt64,0],18446744073709551615}])), ?DBG("send cntTrap",[]), snmpa:send_trap(MA,cntTrap,"standard trap",[ @@ -4667,7 +4653,7 @@ cnt_64_test(MA) -> {sysLocation, "here"} ]), ?DBG("await response",[]), - ?line ?v1_2(?expect5(trap, [test], 6, 1, [{[sysContact,0], "pelle"}, + ?v1_2(?expect5(trap, [test], 6, 1, [{[sysContact,0], "pelle"}, {[sysLocation,0], "here"}]), ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?testTrap ++ [1]}, @@ -4681,26 +4667,26 @@ cnt_64_test(MA) -> ?DBG("create row (cntStatus): ~p",[Idx1]), s([{[cntStatus, Idx1], i, ?createAndGo}]), ?DBG("await response",[]), - ?line ?expect1([{[cntStatus, Idx1], ?createAndGo}]), + ?expect1([{[cntStatus, Idx1], ?createAndGo}]), ?DBG("create row (cntStatus): ~p",[Idx2]), s([{[cntStatus, Idx2], i, ?createAndGo}]), ?DBG("await response",[]), - ?line ?expect1([{[cntStatus, Idx2], ?createAndGo}]), + ?expect1([{[cntStatus, Idx2], ?createAndGo}]), ?DBG("get-next (cntIndex)",[]), gn([[cntIndex]]), ?DBG("await response",[]), - ?line ?v1_2(?expect1([{[cntStatus,Idx1], ?active}]), + ?v1_2(?expect1([{[cntStatus,Idx1], ?active}]), ?expect1([{[cntCnt,Idx1], 0}])), % Delete the rows ?DBG("delete row (cntStatus): ~p",[Idx1]), s([{[cntStatus, Idx1], i, ?destroy}]), ?DBG("await response",[]), - ?line ?expect1([{[cntStatus, Idx1], ?destroy}]), + ?expect1([{[cntStatus, Idx1], ?destroy}]), ?DBG("delete row (cntStatus): ~p",[Idx2]), s([{[cntStatus, Idx2], i, ?destroy}]), ?DBG("await response",[]), - ?line ?expect1([{[cntStatus, Idx2], ?destroy}]), + ?expect1([{[cntStatus, Idx2], ?destroy}]), catch snmpa:verbosity(MA, log), ?DBG("done",[]), ok. @@ -4709,40 +4695,40 @@ cnt_64_test(MA) -> opaque_test() -> ?NPRINT("Testing Opaque datatype..."), g([[opaqueObj,0]]), - ?line ?expect1([{[opaqueObj,0], "opaque-data"}]). + ?expect1([{[opaqueObj,0], "opaque-data"}]). %% Req. OLD-SNMPEA-MIB api_test(MaNode) -> - ?line {value, OID} = rpc:call(MaNode, snmpa, name_to_oid, + {value, OID} = rpc:call(MaNode, snmpa, name_to_oid, [intAgentIpAddress]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmpa, + {value, intAgentIpAddress} = rpc:call(MaNode, snmpa, oid_to_name, [OID]), - ?line false = rpc:call(MaNode, snmpa, name_to_oid, [intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmpa, oid_to_name, + false = rpc:call(MaNode, snmpa, name_to_oid, [intAgentIpAddres]), + false = rpc:call(MaNode, snmpa, oid_to_name, [[1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmpa, enum_to_int, + {value, 2} = rpc:call(MaNode, snmpa, enum_to_int, [intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmpa, int_to_enum, + {value, excluded} = rpc:call(MaNode, snmpa, int_to_enum, [intViewType, 2]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, [intViewType, exclude]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [intViewType, exclude]), + false = rpc:call(MaNode, snmpa, enum_to_int, [intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [intViewType, 3]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmpa, + false = rpc:call(MaNode, snmpa, int_to_enum, [intViewType, 3]), + false = rpc:call(MaNode, snmpa, int_to_enum, [intAgentIpAddress, 2]), + false = rpc:call(MaNode, snmpa, int_to_enum, [intAgentIpAddre, 2]), + {value, active} = rpc:call(MaNode, snmpa, int_to_enum, ['RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmpa, + {value, ?destroy} = rpc:call(MaNode, snmpa, enum_to_int, ['RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmpa, + false = rpc:call(MaNode, snmpa, enum_to_int, ['RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmpa, + false = rpc:call(MaNode, snmpa, enum_to_int, ['xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, ['RowStatus', 25]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, ['xxRowStatus', 1]), - ?line case snmp:date_and_time() of + false = rpc:call(MaNode, snmpa, int_to_enum, ['RowStatus', 25]), + false = rpc:call(MaNode, snmpa, int_to_enum, ['xxRowStatus', 1]), + case snmp:date_and_time() of List when is_list(List), length(List) == 8 -> ok; List when is_list(List), length(List) == 11 -> ok end. @@ -4750,42 +4736,42 @@ api_test(MaNode) -> %% Req. Klas3 api_test2() -> g([[fname3,0]]), - ?line ?expect1([{[fname3,0], "ok"}]), + ?expect1([{[fname3,0], "ok"}]), g([[fname4,0]]), - ?line ?expect1([{[fname4,0], 1}]). + ?expect1([{[fname4,0], 1}]). api_test3() -> g([[fname3,0]]), - ?line ?expect1([{[fname3,0], "ok"}]). + ?expect1([{[fname3,0], "ok"}]). unreg_test() -> gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[snmpInPkts, 0], any}]). + ?expect1([{[snmpInPkts, 0], any}]). load_test() -> gn([[?v1_2(sysServices, sysORLastChange),0]]), - ?line ?expect1([{[fname,0], ""}]). + ?expect1([{[fname,0], ""}]). %% Req. Klas1 load_test_sa() -> gn([[?v1_2(sysServices,sysORLastChange), 0]]), - ?line ?expect1([{[fname,0], any}]). + ?expect1([{[fname,0], any}]). %% Req. system group, Klas1, OLD-SNMPEA-MIB do_mul_get() -> Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], s([{[fname,0], s, "test set"}]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), g([[sysDescr,0], Key1c4, [fname,0],Key1c3,[sysName,0]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {Key1c4, 2}, {[fname,0], "test set"}, {Key1c3, 2}, {[sysName,0], "test"}]), g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]), - ?line ?v1_2(?expect3(noSuchName, [1,4], any), + ?v1_2(?expect3(noSuchName, [1,4], any), ?expect1([{[1,3,7,1], noSuchObject}, {Key1c4, 2}, {[sysDescr,0], "Erlang SNMP agent"}, @@ -4798,16 +4784,16 @@ do_mul_get_err() -> Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], s([{[fname,0], s, "test set"}]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]), - ?line ?v1_2(?expect3(noSuchName, 5, any), + ?v1_2(?expect3(noSuchName, 5, any), ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {Key1c4, 2}, {[fname,0], "test set"}, {Key1c3, 2}, {[sysName,2], noSuchInstance}])), g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]), - ?line ?v1_2(?expect3(noSuchName, [3,5], any), + ?v1_2(?expect3(noSuchName, [3,5], any), ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {Key1c4, 2}, {[fname3,0], noSuchObject}, @@ -4822,9 +4808,9 @@ do_mul_next() -> Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], s([{[fname,0], s, "test set"}]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {Key1c4, 2}, {[fname,0], "test set"}, {Key1c3, 2}, {[sysName,0], "test"}]). @@ -4835,9 +4821,9 @@ do_mul_next_err() -> Key1c3 = [intCommunityEntry,[3],get(mip),is("public")], Key1c4 = [intCommunityEntry,[4],get(mip),is("public")], s([{[fname,0], s, "test set"}]), - ?line ?expect1([{[fname,0], "test set"}]), + ?expect1([{[fname,0], "test set"}]), gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]), - ?line ?v1_2(?expect3(noSuchName, [3,5], any), + ?v1_2(?expect3(noSuchName, [3,5], any), ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {Key1c4, 2}, {[1,3,6,999], endOfMibView}, @@ -4859,7 +4845,7 @@ do_mul_set() -> {NewKeyc5, ?createAndGo}, {NewKeyc4, 2}, {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, {NewKeyc3, 2}, {[sysLocation,0], "new_value"}, {NewKeyc5, ?createAndGo}, @@ -4868,14 +4854,14 @@ do_mul_set() -> g([[friendsEntry, [2, 3]], [sysLocation,0], [friendsEntry, [3, 3]]]), - ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, + ?expect1([{[friendsEntry, [2, 3]], "kompis3"}, {[sysLocation,0], "new_value"}, {[friendsEntry, [3, 3]], ?active}]), g([NewKeyc4]), - ?line ?expect1([{NewKeyc4, 2}]), + ?expect1([{NewKeyc4, 2}]), s([{[friendsEntry, [3, 3]], ?destroy}, {NewKeyc5, ?destroy}]), - ?line ?expect1([{[friendsEntry, [3, 3]], ?destroy}, + ?expect1([{[friendsEntry, [3, 3]], ?destroy}, {NewKeyc5, ?destroy}]). %% Req. system group, Klas1, OLD-SNMPEA-MIB @@ -4890,46 +4876,46 @@ do_mul_set_err() -> {NewKeyc5, ?createAndGo}, {NewKeyc4, 2}, {[friendsEntry, [3, 3]], ?createAndGo}]), - ?line ?expect3(?v1_2(noSuchName, notWritable), 3, any), + ?expect3(?v1_2(noSuchName, notWritable), 3, any), g([[friendsEntry, [2, 3]]]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{[friendsEntry, [2,3]], noSuchInstance}])), g([NewKeyc4]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{NewKeyc4, noSuchInstance}])). %% Req. SA-MIB sa_mib() -> g([[sa, [2,0]]]), - ?line ?expect1([{[sa, [2,0]], 3}]), + ?expect1([{[sa, [2,0]], 3}]), s([{[sa, [1,0]], s, "sa_test"}]), - ?line ?expect1([{[sa, [1,0]], "sa_test"}]), + ?expect1([{[sa, [1,0]], "sa_test"}]), ok. ma_trap1(MA) -> ok = snmpa:send_trap(MA, testTrap2, "standard trap"), - ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]], + ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}]), ok = snmpa:send_trap(MA, testTrap1, "standard trap"), - ?line ?expect5(trap, [1,2,3] , 1, 0, [{[system, [4,0]], + ?expect5(trap, [1,2,3] , 1, 0, [{[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}]), ok. ma_trap2(MA) -> snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), + ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), ok. ma_v2_2_v1_trap(MA) -> snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), + ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]), ok. ma_v2_2_v1_trap2(MA) -> snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1}, {ifAdminStatus, [1], 1}, {ifOperStatus, [1], 2}]), - ?line ?expect5(trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, + ?expect5(trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1}, {[ifAdminStatus, 1], 1}, {[ifOperStatus, 1], 2}]), ok. @@ -4949,7 +4935,7 @@ sa_trap1(SA) -> %% io:format("sa_trap1 -> SA trap send: " %% "~n TSRes: ~p" %% "~n", [TSRes]), - ?line ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]], + ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}, {[sa, [1,0]], "sa_test"}]), snmpa:verbosity(SA, {subagents, silence}), @@ -4957,14 +4943,14 @@ sa_trap1(SA) -> sa_trap2(SA) -> snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]], "pelle"}, + ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]], "pelle"}, {[sa, [1,0]], "sa_test"}]), ok. sa_trap3(SA) -> snmpa:send_trap(SA, saTrap2, "standard trap", [{intViewSubtree, [4], [1,2,3,4]}]), - ?line ?expect5(trap, [ericsson], 6, 2, [{[system, [4,0]], + ?expect5(trap, [ericsson], 6, 2, [{[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}, {[sa, [1,0]], "sa_test"}, {[intViewSubtree,4],[1,2,3,4]}]), @@ -4974,25 +4960,23 @@ ma_v2_trap1(MA) -> ?DBG("ma_v2_traps -> entry with MA = ~p => " "send standard trap: testTrapv22",[MA]), snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}]), ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]), snmpa:send_trap(MA, testTrapv21, "standard trap"), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?snmp ++ [1]}]), ok. ma_v2_trap2(MA) -> snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}, - {[system, [4,0]], "pelle"}]). + ?expect2(v2trap, [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}, + {[system, [4,0]], "pelle"}]). %% Note: This test case takes a while... actually a couple of minutes. ma_v2_inform1(MA) -> - ?DBG("ma_v2_inform1 -> entry with" - "~n MA = ~p => " - "~n send notification: testTrapv22", [MA]), + ?IPRINT("begin ma_v2_inform1 (MA: ~p)", [MA]), CmdExpectInform = fun(_No, Response) -> @@ -5145,9 +5129,7 @@ ma_v2_inform1(MA) -> %% Note: This test case takes a while... actually a couple of minutes. ma_v2_inform2(MA) -> - ?DBG("ma_v2_inform2 -> entry with" - "~n MA = ~p => " - "~n send notification: testTrapv22", [MA]), + ?IPRINT("begin ma_v2_inform2 (MA: ~p)", [MA]), CmdExpectInform = fun(_No, Response) -> @@ -5244,9 +5226,7 @@ ma_v2_inform2(MA) -> %% Note: This test case takes a while... actually a couple of minutes. ma_v2_inform3(MA) -> - ?DBG("ma_v2_inform3 -> entry with" - "~n MA = ~p => " - "~n send notification: testTrapv22", [MA]), + ?IPRINT("begin ma_v2_inform3 (MA: ~p)", [MA]), CmdExpectInform = fun(_No, Response) -> @@ -5389,10 +5369,10 @@ command_handler([{_No, _Desc, Cmd}|Rest]) -> %% command_handler(Rest); %% {error, Reason} -> %% ?EPRINT("command_handler -> ~w error: ~n~p", [_No, Reason]), - %% ?line ?FAIL(Reason); + %% ?FAIL(Reason); %% Error -> %% ?EPRINT("command_handler -> ~w unexpected: ~n~p", [_No, Error]), - %% ?line ?FAIL({unexpected_command_result, Error}) + %% ?FAIL({unexpected_command_result, Error}) %% end. try Cmd() of ok -> @@ -5404,7 +5384,7 @@ command_handler([{_No, _Desc, Cmd}|Rest]) -> if (SysEvs =:= []) -> ?EPRINT("command_handler -> ~w error: ~n~p", [_No, Reason]), - ?line ?FAIL(Reason); + ?FAIL(Reason); true -> ?WPRINT("command_handler -> " "failed when we got system events: " @@ -5420,7 +5400,7 @@ command_handler([{_No, _Desc, Cmd}|Rest]) -> (SysEvs =:= []) -> ?EPRINT("command_handler -> " "~w unexpected: ~n~p", [_No, Error]), - ?line ?FAIL({unexpected_command_result, Error}); + ?FAIL({unexpected_command_result, Error}); true -> ?WPRINT("command_handler -> " "unexpected when we got system events: " @@ -5431,32 +5411,32 @@ command_handler([{_No, _Desc, Cmd}|Rest]) -> end catch C:E:S -> - ?IPRINT("command_handler -> command ~w catched", [_No]), + ?IPRINT("command_handler -> command ~w caught", [_No]), SysEvs = snmp_test_global_sys_monitor:events(), if (SysEvs =:= []) -> - ?EPRINT("command_handler -> ~w catched: " + ?EPRINT("command_handler -> ~w caught: " "~n Class: ~p" "~n Error: ~p" "~n Stack: ~p", [_No, C, E, S]), - ?line ?FAIL({catched_command_result, {C, E, S}}); + ?FAIL({catched_command_result, {C, E, S}}); true -> ?WPRINT("command_handler -> " - "catched when we got system events: " - "~n Catched: " + "caught when we got system events: " + "~n Caught: " "~n Class: ~p" "~n Error: ~p" "~n Stack: ~p" "~n Sys Events: ~p" "~n", [C, E, S, SysEvs]), - ?SKIP([{catched, {C, E, S}}, {system_events, SysEvs}]) + ?SKIP([{caught, {C, E, S}}, {system_events, SysEvs}]) end end. ma_v1_2_v2_trap(MA) -> snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?snmpTraps ++ [3]}, {[ifIndex, 1], 1}, {[snmpTrapEnterprise, 0], [1,2,3]}]). @@ -5464,7 +5444,7 @@ ma_v1_2_v2_trap(MA) -> ma_v1_2_v2_trap2(MA) -> snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}, {[system, [4,0]], "pelle"}, {[snmpTrapEnterprise, 0], ?system}]). @@ -5473,7 +5453,7 @@ ma_v1_2_v2_trap2(MA) -> sa_v1_2_v2_trap1(SA) -> snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap, "standard trap"), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, {[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}, @@ -5485,7 +5465,7 @@ sa_v1_2_v2_trap1(SA) -> sa_v1_2_v2_trap2(SA) -> snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?ericsson ++ [0, 1]}, {[system, [4,0]], "pelle"}, {[sa, [1,0]], "sa_test"}, @@ -5498,7 +5478,7 @@ sa_v1_2_v2_trap3(SA) -> snmpa:verbosity(SA, {subagents, trace}), snmpa:send_trap(SA, saTrap2, "standard trap", [{intViewSubtree, [4], [1,2,3,4]}]), - ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, + ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?ericsson ++ [0, 2]}, {[system, [4,0]], "{mbj,eklas}@erlang.ericsson.se"}, @@ -5518,14 +5498,14 @@ sa_errs_bad_value() -> {[sa, [2,0]], 5}, % badValue (i is_set_ok) {NewKeyc5, ?createAndGo}, {NewKeyc4, 2}]), - ?line ?expect3(badValue, 2, any), + ?expect3(badValue, 2, any), s([{NewKeyc3, 2}, {[sa, [2,0]], 6}, % wrongValue (i is_set_ok) {NewKeyc5, ?createAndGo}, {NewKeyc4, 2}]), - ?line ?expect3(?v1_2(badValue, wrongValue), 2, any), + ?expect3(?v1_2(badValue, wrongValue), 2, any), g([NewKeyc4]), - ?line ?v1_2(?expect3(noSuchName, 1, any), + ?v1_2(?expect3(noSuchName, 1, any), ?expect1([{NewKeyc4, noSuchInstance}])). %% Req. SA-MIB, OLD-SNMPEA-MIB @@ -5535,22 +5515,22 @@ sa_errs_gen_err() -> NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")], s([{NewKeyc3, 2},{NewKeyc4, 2}, {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]), - ?line ?expect3(genErr, 4, any), + ?expect3(genErr, 4, any), % The row might have been added; we don't know. % (as a matter of fact we do - it is added, because the agent % first sets its own vars, and then th SAs. Lets destroy it. s([{NewKeyc5, ?destroy}]), - ?line ?expect1([{NewKeyc5, ?destroy}]). + ?expect1([{NewKeyc5, ?destroy}]). %% Req. SA-MIB, OLD-SNMPEA-MIB sa_too_big() -> g([[sa, [4,0]]]), - ?line ?expect1(tooBig). + ?expect1(tooBig). %% Req. Klas1, system group, snmp group (v1/v2) next_across_sa_test() -> gn([[sysDescr],[klas1,5]]), - ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, + ?expect1([{[sysDescr,0], "Erlang SNMP agent"}, {[snmpInPkts, 0], any}]). %% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError @@ -5562,40 +5542,40 @@ next_across_sa_test() -> %% Req. Klas3, Klas4 undo_test() -> s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), - ?line ?expect1([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), + ?expect1([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]), s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]), - ?line ?expect3(?v1_2(badValue, inconsistentValue), 2, any), + ?expect3(?v1_2(badValue, inconsistentValue), 2, any), s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]), - ?line ?expect3(?v1_2(genErr, undoFailed), 1, any), + ?expect3(?v1_2(genErr, undoFailed), 1, any), s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]), - ?line ?expect3(?v1_2(genErr, commitFailed), 1, any), -% unfortunatly we don't know if we'll get undoFailed or commitFailed. + ?expect3(?v1_2(genErr, commitFailed), 1, any), +% unfortunately we don't know if we'll get undoFailed or commitFailed. % it depends on which order the agent traverses the varbind list. % s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]), -% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any), +% expect(5, ?v1_2(genErr, undoFailed), 1, any), s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]), - ?line ?expect3(genErr, 2, any). + ?expect3(genErr, 2, any). %% Req. Klas3, Klas4 bad_return() -> g([[fStatus4,4], [fName4,4]]), - ?line ?expect3(genErr, 2, any), + ?expect3(genErr, 2, any), g([[fStatus4,5], [fName4,5]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), g([[fStatus4,6], [fName4,6]]), - ?line ?expect3(genErr, 2, any), + ?expect3(genErr, 2, any), gn([[fStatus4,7], [fName4,7]]), - ?line ?expect3(genErr, 2, any), + ?expect3(genErr, 2, any), gn([[fStatus4,8], [fName4,8]]), - ?line ?expect3(genErr, 1, any), + ?expect3(genErr, 1, any), gn([[fStatus4,9], [fName4,9]]), - ?line ?expect3(genErr, 2, any). + ?expect3(genErr, 2, any). %%%----------------------------------------------------------------- @@ -5630,7 +5610,6 @@ standard_mibs_cases_ipv6() -> %% For this test, the agent is configured for v1. %% o Test the counters and control objects in SNMP-STANDARD-MIB %%----------------------------------------------------------------- -snmp_standard_mib(suite) -> []; snmp_standard_mib(Config) when is_list(Config) -> ?P(snmp_standard_mib), init_case(Config), @@ -5671,9 +5650,9 @@ snmp_standard_mib(Config) when is_list(Config) -> %% Req. SNMP-STANDARD-MIB standard_mib_a() -> - ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]), - ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), - ?line OutPkts2 = OutPkts + 1, + [OutPkts] = get_req(2, [[snmpOutPkts,0]]), + [OutPkts2] = get_req(3, [[snmpOutPkts,0]]), + OutPkts2 = OutPkts + 1, %% There are some more counters we could test here, but it's not that %% important, since they are removed from SNMPv2-MIB. ok. @@ -5683,27 +5662,27 @@ std_mib_init() -> %% disable authentication failure traps. (otherwise w'd get many of %% them - this is also a test to see that it works). s([{[snmpEnableAuthenTraps,0], 2}]), - ?line ?expect1([{[snmpEnableAuthenTraps, 0], 2}]). + ?expect1([{[snmpEnableAuthenTraps, 0], 2}]). %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_finish() -> %% enable again s([{[snmpEnableAuthenTraps,0], 1}]), - ?line ?expect1([{[snmpEnableAuthenTraps, 0], 1}]). + ?expect1([{[snmpEnableAuthenTraps, 0], 1}]). %% Req. SNMP-STANDARD-MIB standard_mib_test_finish() -> %% force a authenticationFailure (should result in a trap) std_mib_write(), %% check that we got a trap - ?line ?expect5(trap, [1,2,3], 4, 0, []). + ?expect5(trap, [1,2,3], 4, 0, []). %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_read() -> ?DBG("std_mib_read -> entry", []), g([[sysUpTime,0]]), % try a bad ; msg dropped, no reply ?DBG("std_mib_read -> await timeout (i.e. no reply)", []), - ?line ?expect1(timeout). % make sure we don't get a trap! + ?expect1(timeout). % make sure we don't get a trap! %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB @@ -5731,7 +5710,6 @@ standard_mibs2_cases() -> %% For this test, the agent is configured for v2 and v3. %% o Test the counters and control objects in SNMPv2-MIB %%----------------------------------------------------------------- -snmpv2_mib_2(suite) -> []; snmpv2_mib_2(Config) when is_list(Config) -> ?P(snmpv2_mib_2), ?IPRINT("snmpv2_mib_2 -> start"), @@ -5763,7 +5741,7 @@ snmpv2_mib_2(Config) when is_list(Config) -> ?DBG("snmpv2_mib_2 -> check counters",[]), try_test(std_mib_c, [Bad]), - ?DBG("snmpv2_mib_2 -> get som counters",[]), + ?DBG("snmpv2_mib_2 -> get some counters",[]), try_test(snmpv2_mib_a), ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]), @@ -5790,7 +5768,6 @@ standard_mibs3_cases() -> %% Req. SNMPv2-MIB -snmpv2_mib_3(suite) -> []; snmpv2_mib_3(Config) when is_list(Config) -> %% Skippable = [{unix, [darwin]}], @@ -5820,31 +5797,31 @@ snmpv2_mib_test_finish() -> %% check that we got a trap ?DBG("ma_v2_inform -> await trap",[]), - ?line ?expect2(v2trap, [{[sysUpTime,0], any}, + ?expect2(v2trap, [{[sysUpTime,0], any}, {[snmpTrapOID,0], ?authenticationFailure}]), %% and the the inform ?DBG("ma_v2_inform -> await inform",[]), - ?line ?expect2({inform,true}, [{[sysUpTime,0], any}, + ?expect2({inform,true}, [{[sysUpTime,0], any}, {[snmpTrapOID,0],?authenticationFailure}]). %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_a() -> - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, + [InPkts] = get_req(2, [[snmpInPkts,0]]), + [InPkts2] = get_req(3, [[snmpInPkts,0]]), + InPkts2 = InPkts + 1, - ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), + [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]), InBadVsns. %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_b(InBadVsns) -> - ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), - ?line InBadVsns2 = InBadVsns + 1, - ?line [InPkts] = get_req(2, [[snmpInPkts,0]]), - ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]), - ?line InPkts2 = InPkts + 1, - ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] = + [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]), + InBadVsns2 = InBadVsns + 1, + [InPkts] = get_req(2, [[snmpInPkts,0]]), + [InPkts2] = get_req(3, [[snmpInPkts,0]]), + InPkts2 = InPkts + 1, + [InBadCommunityNames, InBadCommunityUses, InASNErrs] = get_req(4, [[snmpInBadCommunityNames,0], [snmpInBadCommunityUses,0], [snmpInASNParseErrs, 0]]), @@ -5852,25 +5829,25 @@ std_mib_b(InBadVsns) -> %% Req. SNMP-STANDARD-MIB | SNMPv2-MIB std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) -> - ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = + [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] = get_req(1, [[snmpInBadCommunityNames,0], [snmpInBadCommunityUses,0], [snmpInASNParseErrs, 0]]), - ?line InBadCommunityNames2 = InBadCommunityNames + 1, - ?line InBadCommunityUses2 = InBadCommunityUses + 1, - ?line InASNErrs2 = InASNErrs + 1. + InBadCommunityNames2 = InBadCommunityNames + 1, + InBadCommunityUses2 = InBadCommunityUses + 1, + InASNErrs2 = InASNErrs + 1. %% Req. SNMPv2-MIB snmpv2_mib_a() -> - ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), + [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]), s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), - ?line ?expect1([{[snmpSetSerialNo,0], SetSerial}, + ?expect1([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]), s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line ?expect3(inconsistentValue, 2, + ?expect3(inconsistentValue, 2, [{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]), - ?line ["val2"] = get_req(5, [[sysLocation,0]]), + ["val2"] = get_req(5, [[sysLocation,0]]), ok. @@ -5879,13 +5856,12 @@ snmpv2_mib_a() -> %% in SNMPv2-MIB and STANDARD-MIB. %% o Test add/deletion of rows. %%----------------------------------------------------------------- -snmp_community_mib(suite) -> []; snmp_community_mib(Config) when is_list(Config) -> ?P(snmp_community_mib), init_case(Config), - ?line load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), try_test(snmp_community_mib_test), - ?line unload_master("SNMP-COMMUNITY-MIB"). + unload_master("SNMP-COMMUNITY-MIB"). snmp_community_mib_2(X) -> ?P(snmp_community_mib_2), snmp_community_mib(X). @@ -5898,17 +5874,15 @@ snmp_community_mib_test() -> %%----------------------------------------------------------------- %% o Test engine boots / time %%----------------------------------------------------------------- -snmp_framework_mib(suite) -> []; snmp_framework_mib(Config) when is_list(Config) -> ?P(snmp_framework_mib), init_case(Config), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), try_test(snmp_framework_mib_test), - ?line unload_master("SNMP-FRAMEWORK-MIB"). + unload_master("SNMP-FRAMEWORK-MIB"). snmp_framework_mib_2(X) -> ?P(snmp_framework_mib_2), snmp_framework_mib(X). -snmp_framework_mib_3(suite) -> []; snmp_framework_mib_3(Config) when is_list(Config) -> ?P(snmp_framework_mib_3), init_case(Config), @@ -5921,7 +5895,7 @@ snmp_framework_mib_3(Config) when is_list(Config) -> %% the same as the number of seconds we sleep (5 in this case). %% But because, on some (slow or/and high loaded) hosts, the actual %% time we sleep could be a lot larger (due to, for instance, scheduling). -%% Therefor we must take that into account when we check if the +%% Therefore we must take that into account when we check if the %% Engine Time diff (between the two checks) is acceptably. snmp_framework_mib_test() -> @@ -5935,13 +5909,13 @@ snmp_framework_mib_test() -> ]), Sleep = 5, - ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), + ["agentEngine"] = get_req(1, [[snmpEngineID,0]]), T1 = snmp_misc:now(ms), - ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]), + [EngineTime] = get_req(2, [[snmpEngineTime,0]]), T2 = snmp_misc:now(ms), ?SLEEP(?SECS(Sleep)), T3 = snmp_misc:now(ms), - ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), + [EngineTime2] = get_req(3, [[snmpEngineTime,0]]), T4 = snmp_misc:now(ms), %% Ok, we tried to sleep 5 seconds, but how long did we actually sleep @@ -5988,18 +5962,18 @@ snmp_framework_mib_test() -> ?EPRINT("snmp_framework_mib -> (High) Engine Time diff (~w) too large: " "~n ~w < ~w", [EngineTimeDiff, HighEngineTime, EngineTime2]), - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); + ?FAIL({too_large_diff, EngineTime, EngineTime2}); (LowEngineTime > EngineTime2) -> ?EPRINT("snmp_framework_mib -> (Low) Engine Time diff (~w) too large: " "~n ~w > ~w", [EngineTimeDiff, LowEngineTime, EngineTime2]), - ?line ?FAIL({too_large_diff, EngineTime, EngineTime2}); + ?FAIL({too_large_diff, EngineTime, EngineTime2}); true -> ok end, T5 = snmp_misc:now(ms), - ?line case get_req(4, [[snmpEngineBoots,0]]) of + case get_req(4, [[snmpEngineBoots,0]]) of [Boots] when is_integer(Boots) -> T6 = snmp_misc:now(ms), ?IPRINT("snmp_framework_mib -> " @@ -6016,7 +5990,6 @@ snmp_framework_mib_test() -> %%----------------------------------------------------------------- %% o Test the counters %%----------------------------------------------------------------- -snmp_mpd_mib_3(suite) -> []; snmp_mpd_mib_3(Config) when is_list(Config) -> %% Skippable = [{unix, [darwin]}], @@ -6033,7 +6006,7 @@ snmp_mpd_mib_3(Config) when is_list(Config) -> %% Req. SNMP-MPD-MIB snmp_mpd_mib_a() -> - ?line [UnknownSecs, InvalidMsgs] = + [UnknownSecs, InvalidMsgs] = get_req(1, [[snmpUnknownSecurityModels,0], [snmpInvalidMsgs,0]]), Pdu = #pdu{type = 'get-request', @@ -6044,7 +6017,7 @@ snmp_mpd_mib_a() -> SPdu = #scopedPdu{contextEngineID = "agentEngine", contextName = "", data = Pdu}, - ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), + SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu), V3Hdr1 = #v3_hdr{msgID = 21, msgMaxSize = 484, msgFlags = [7], @@ -6059,38 +6032,37 @@ snmp_mpd_mib_a() -> data = SPDUBytes}, Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2, data = SPDUBytes}, - ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1), - ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2), + MsgBytes1 = snmp_pdus:enc_message_only(Message1), + MsgBytes2 = snmp_pdus:enc_message_only(Message2), snmp_test_mgr:send_bytes(MsgBytes1), snmp_test_mgr:send_bytes(MsgBytes2), - ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = + [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] = get_req(1, [[snmpUnknownSecurityModels,0], [snmpInvalidMsgs,0], [snmpUnknownPDUHandlers, 0]]), - ?line UnknownSecs2 = UnknownSecs + 1, - ?line InvalidMsgs2 = InvalidMsgs + 1, + UnknownSecs2 = UnknownSecs + 1, + InvalidMsgs2 = InvalidMsgs + 1, UnknownPDUHs. -define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]). snmp_mpd_mib_b() -> g([[sysUpTime,0]]), - ?line ?expect2(report, [{?snmpUnknownPDUHandlers_instance, any}]). + ?expect2(report, [{?snmpUnknownPDUHandlers_instance, any}]). snmp_mpd_mib_c(UnknownPDUHs) -> - ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), - ?line UnknownPDUHs2 = UnknownPDUHs + 1, + [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]), + UnknownPDUHs2 = UnknownPDUHs + 1, ok. -snmp_target_mib(suite) -> []; snmp_target_mib(Config) when is_list(Config) -> ?P(snmp_target_mib), init_case(Config), - ?line load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-TARGET-MIB"), try_test(snmp_target_mib_test), - ?line unload_master("SNMP-TARGET-MIB"). + unload_master("SNMP-TARGET-MIB"). snmp_target_mib_2(X) -> ?P(snmp_target_mib_2), snmp_target_mib(X). @@ -6100,13 +6072,12 @@ snmp_target_mib_test() -> ?NPRINT("NOT YET IMPLEMENTED"), nyi. -snmp_notification_mib(suite) -> []; snmp_notification_mib(Config) when is_list(Config) -> ?P(snmp_notification_mib), init_case(Config), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), try_test(snmp_notification_mib_test), - ?line unload_master("SNMP-NOTIFICATION-MIB"). + unload_master("SNMP-NOTIFICATION-MIB"). snmp_notification_mib_2(X) -> ?P(snmp_notification_mib_2), snmp_notification_mib(X). @@ -6123,16 +6094,15 @@ snmp_notification_mib_test() -> %% o add/delete views and try them %% o try boundaries %%----------------------------------------------------------------- -snmp_view_based_acm_mib(suite) -> []; snmp_view_based_acm_mib(Config) when is_list(Config) -> ?P(snmp_view_based_acm_mib), init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master("Test2"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master("Test2"), snmp_view_based_acm_mib(), - ?line unload_master("Test2"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). + unload_master("Test2"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"). snmp_view_based_acm_mib_2(X) -> ?P(snmp_view_based_acm_mib_2), @@ -6167,7 +6137,7 @@ snmp_view_based_acm_mib() -> v3 -> {?SEC_USM, ?SEC_V1} end, ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), %% Now, add a mapping from "no-rights" -> "no-rights-group" GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]], @@ -6175,25 +6145,25 @@ snmp_view_based_acm_mib() -> [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"}, {GRow1Status, ?createAndGo}], ?DBG("set '~p'",[GRow1]), - ?line try_test(do_set, [GRow1]), + try_test(do_set, [GRow1]), ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), - %% Create a mapping for another sec model, and make sure it dosn't + %% Create a mapping for another sec model, and make sure it doesn't %% give us access GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]], GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"}, {GRow2Status, ?createAndGo}], ?DBG("set '~p'",[GRow2]), - ?line try_test(do_set, [GRow2]), + try_test(do_set, [GRow2]), ?DBG("assign rights for 'no-rights'",[]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), %% Delete that row - ?line try_test(del_row, [GRow2Status]), + try_test(del_row, [GRow2Status]), RVName = "rv_name", WVName = "wv_name", @@ -6206,7 +6176,7 @@ snmp_view_based_acm_mib() -> {[vacmAccessWriteViewName, ARow1Idx], WVName}, {ARow1Status, ?createAndGo}], - %% This access row would give acces, if InvSecMod was valid. + %% This access row would give access, if InvSecMod was valid. ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1], ARow2Status = [vacmAccessStatus, ARow2Idx], ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1}, @@ -6214,18 +6184,18 @@ snmp_view_based_acm_mib() -> {[vacmAccessWriteViewName, ARow2Idx], "internet"}, {ARow2Status, ?createAndGo}], - ?line try_test(do_set, [ARow2]), + try_test(do_set, [ARow2]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), %% Delete that row - ?line try_test(del_row, [ARow2Status]), + try_test(del_row, [ARow2Status]), %% Add valid row - ?line try_test(do_set, [ARow1]), + try_test(do_set, [ARow1]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), %% Create the view family VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access @@ -6237,32 +6207,32 @@ snmp_view_based_acm_mib() -> VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx], VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx], - ?line try_test(add_row, [VRow1Status]), - ?line try_test(add_row, [VRow2Status]), - ?line try_test(add_row, [VRow3Status]), + try_test(add_row, [VRow1Status]), + try_test(add_row, [VRow2Status]), + try_test(add_row, [VRow3Status]), %% We're supposed to have access now... - ?line try_test(use_rights, [], Opts), + try_test(use_rights, [], Opts), %% Change Row3 to Row4 - ?line try_test(del_row, [VRow3Status]), - ?line try_test(add_row, [VRow4Status]), + try_test(del_row, [VRow3Status]), + try_test(add_row, [VRow4Status]), %% We should still have access... - ?line try_test(use_rights, [], Opts), + try_test(use_rights, [], Opts), %% Delete rows - ?line try_test(del_row, [GRow1Status]), + try_test(del_row, [GRow1Status]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), %% Delete rest of rows - ?line try_test(del_row, [ARow1Status]), - ?line try_test(del_row, [VRow1Status]), - ?line try_test(del_row, [VRow2Status]), - ?line try_test(del_row, [VRow4Status]), + try_test(del_row, [ARow1Status]), + try_test(del_row, [VRow1Status]), + try_test(del_row, [VRow2Status]), + try_test(del_row, [VRow4Status]), - ?line try_test(use_no_rights, [], Opts), + try_test(use_no_rights, [], Opts), snmpa:verbosity(master_agent,log). do_set(Row) -> @@ -6318,7 +6288,6 @@ mk_ln(X) -> %% o test all combinations of protocols %% o try bad ops; check counters %%----------------------------------------------------------------- -snmp_user_based_sm_mib_3(suite) -> []; snmp_user_based_sm_mib_3(Config) when is_list(Config) -> %% Skippable = [{unix, [darwin]}], @@ -6330,7 +6299,7 @@ snmp_user_based_sm_mib_3(Config) when is_list(Config) -> init_case(Config), _AgentDir = ?config(agent_conf_dir, Config), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), + load_master_std("SNMP-USER-BASED-SM-MIB"), %% The newUser used here already has VACM access. @@ -6339,10 +6308,10 @@ snmp_user_based_sm_mib_3(Config) when is_list(Config) -> [{sec_level, authPriv}, {user, "privDES"}]), %% Try to use the new user - ?line load_master("Test2"), + load_master("Test2"), try_test(v3_sync, [[{usm_use_user, []}]], [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), + unload_master("Test2"), ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"), DesKey1 = lists:sublist(ShaKey1, 16), @@ -6353,55 +6322,55 @@ snmp_user_based_sm_mib_3(Config) when is_list(Config) -> %% Try to use the new keys MgrDir = ?config(mgr_dir, Config), - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), + rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), + load_master("Test2"), try_test(v3_sync, [[{usm_use_user, []}]], [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), + unload_master("Test2"), ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"), DesKey2 = lists:sublist(ShaKey2, 16), %% Change the new user's keys - 2 - ?line try_test(v3_sync, + try_test(v3_sync, [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]], [{sec_level, authPriv}, {user, "newUser"}]), %% Try to use the new keys reset_usm_mgr(MgrDir), - ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), - ?line load_master("Test2"), - ?line try_test(v3_sync, [[{usm_use_user, []}]], + rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2), + load_master("Test2"), + try_test(v3_sync, [[{usm_use_user, []}]], [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), + unload_master("Test2"), reset_usm_mgr(MgrDir), %% Change the new user's keys - 3 - ?line try_test(v3_sync, + try_test(v3_sync, [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]], [{sec_level, authPriv}, {user, "privDES"}]), %% Try to use the new keys - ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), - ?line load_master("Test2"), + rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1), + load_master("Test2"), try_test(v3_sync, [[{usm_use_user, []}]], [{sec_level, authPriv}, {user, "newUser"}]), - ?line unload_master("Test2"), + unload_master("Test2"), reset_usm_mgr(MgrDir), %% Try some read requests - ?line try_test(v3_sync, [[{usm_read, []}]], + try_test(v3_sync, [[{usm_read, []}]], [{sec_level, authPriv}, {user, "privDES"}]), %% Delete the new user - ?line try_test(v3_sync, [[{usm_del_user, []}]], + try_test(v3_sync, [[{usm_del_user, []}]], [{sec_level, authPriv}, {user, "privDES"}]), %% Try some bad requests - ?line try_test(v3_sync, [[{usm_bad, []}]], + try_test(v3_sync, [[{usm_bad, []}]], [{sec_level, authPriv}, {user, "privDES"}]), - ?line unload_master("SNMP-USER-BASED-SM-MIB"). + unload_master("SNMP-USER-BASED-SM-MIB"). -define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]). @@ -6410,8 +6379,8 @@ usm_add_user1() -> RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer}, {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line ?expect1(Vbs1), + s(Vbs1), + ?expect1(Vbs1), ok. usm_use_user() -> @@ -6430,7 +6399,7 @@ usm_key_change1(ShaKey, DesKey) -> Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], s(Vbs1), - ?line ?expect1(Vbs1). + ?expect1(Vbs1). %% Change own private keys usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> @@ -6444,7 +6413,7 @@ usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) -> Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}, {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], s(Vbs1), - ?line ?expect1(Vbs1). + ?expect1(Vbs1). %% Change other's public keys usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> @@ -6457,27 +6426,27 @@ usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) -> DesKey), Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}], s(Vbs1), - ?line ?expect3(noAccess, 1, any), + ?expect3(noAccess, 1, any), Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}], s(Vbs2), - ?line ?expect3(noAccess, 1, any), + ?expect3(noAccess, 1, any), Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange}, {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}], s(Vbs3), - ?line ?expect1(Vbs3), + ?expect1(Vbs3), ok. usm_read() -> NewRowIndex = [11,"agentEngine", 7, "newUser"], - ?line g([[usmUserSecurityName, NewRowIndex], + g([[usmUserSecurityName, NewRowIndex], [usmUserCloneFrom, NewRowIndex], [usmUserAuthKeyChange, NewRowIndex], [usmUserOwnAuthKeyChange, NewRowIndex], [usmUserPrivKeyChange, NewRowIndex], [usmUserOwnPrivKeyChange, NewRowIndex]]), - ?line ?expect1([{[usmUserSecurityName, NewRowIndex], "newUser"}, + ?expect1([{[usmUserSecurityName, NewRowIndex], "newUser"}, {[usmUserCloneFrom, NewRowIndex], [0,0]}, {[usmUserAuthKeyChange, NewRowIndex], ""}, {[usmUserOwnAuthKeyChange, NewRowIndex], ""}, @@ -6490,8 +6459,8 @@ usm_read() -> usm_del_user() -> NewRowIndex = [11,"agentEngine", 7, "newUser"], Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs1), - ?line ?expect1(Vbs1), + s(Vbs1), + ?expect1(Vbs1), ok. -define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]). @@ -6511,32 +6480,32 @@ usm_bad() -> RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"], Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1}, {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs1), - ?line ?expect3(inconsistentName, 1, any), + s(Vbs1), + ?expect3(inconsistentName, 1, any), RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"], Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2}, {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs2), - ?line ?expect3(wrongValue, 1, any), + s(Vbs2), + ?expect3(wrongValue, 1, any), RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"], Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3}, {[usmUserStatus, NewRowIndex], ?createAndGo}], - ?line s(Vbs3), - ?line ?expect1(Vbs3), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), - ?line ?expect3(inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), - ?line ?expect3(inconsistentValue, 1, any), - ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), - ?line ?expect3(wrongValue, 1, any), - ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), - ?line ?expect3(wrongValue, 1, any), + s(Vbs3), + ?expect1(Vbs3), + s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]), + ?expect3(inconsistentValue, 1, any), + s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]), + ?expect3(inconsistentValue, 1, any), + s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]), + ?expect3(wrongValue, 1, any), + s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]), + ?expect3(wrongValue, 1, any), Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}], - ?line s(Vbs4), - ?line ?expect1(Vbs4), + s(Vbs4), + ?expect1(Vbs4), ok. @@ -6545,7 +6514,6 @@ usm_bad() -> %% works. %% Load all std mibs that are not loaded by default. %%----------------------------------------------------------------- -loop_mib_1(suite) -> []; loop_mib_1(Config) when is_list(Config) -> ?P(loop_mib_1), ?IPRINT("loop_mib_1 -> initiate case"), @@ -6556,40 +6524,39 @@ loop_mib_1(Config) when is_list(Config) -> "\tMgrNode: ~p~n" "\tMibDir: ~p",[_SaNode, _MgrNode, _MibDir]), ?DBG("loop_mib_1 -> load mib SNMP-COMMUNITY-MIB",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-MPD-MIB",[]), - ?line load_master_std("SNMP-MPD-MIB"), + load_master_std("SNMP-MPD-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-TARGET-MIB",[]), - ?line load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-TARGET-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-NOTIFICATION-MIB",[]), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-FRAMEWORK-MIB",[]), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), ?DBG("loop_mib_1 -> load mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), ?DBG("loop_mib_1 -> try",[]), try_test(loop_mib_1_test), ?DBG("loop_mib_1 -> unload mib SNMP-COMMUNITY-MIB",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), + unload_master("SNMP-COMMUNITY-MIB"), ?DBG("loop_mib_1 -> unload mib SNMP-MPD-MIB",[]), - ?line unload_master("SNMP-MPD-MIB"), + unload_master("SNMP-MPD-MIB"), ?DBG("loop_mib_1 -> unload mib SNMP-TARGET-MIB",[]), - ?line unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-TARGET-MIB"), ?DBG("loop_mib_1 -> unload mib SNMP-NOTIFICATION-MIB",[]), - ?line unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), ?DBG("loop_mib_1 -> unload mib SNMP-FRAMEWORK-MIB",[]), - ?line unload_master("SNMP-FRAMEWORK-MIB"), + unload_master("SNMP-FRAMEWORK-MIB"), ?DBG("loop_mib_1 -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), %% snmpa:verbosity(master_agent,log), %% snmpa:verbosity(mib_server,silence), ?IPRINT("loop_mib_1 -> done"), ok. -loop_mib_2(suite) -> []; loop_mib_2(Config) when is_list(Config) -> ?P(loop_mib_2), ?IPRINT("loop_mib_2 -> initiate case"), @@ -6599,27 +6566,26 @@ loop_mib_2(Config) when is_list(Config) -> "\tMgrNode: ~p~n" "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]), ?DBG("loop_mib_2 -> load mibs",[]), - ?line load_master_std("SNMP-COMMUNITY-MIB"), - ?line load_master_std("SNMP-MPD-MIB"), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-FRAMEWORK-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master_std("SNMP-COMMUNITY-MIB"), + load_master_std("SNMP-MPD-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-FRAMEWORK-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), try_test(loop_mib_2_test), ?DBG("loop_mib_2 -> unload mibs",[]), - ?line unload_master("SNMP-COMMUNITY-MIB"), - ?line unload_master("SNMP-MPD-MIB"), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-FRAMEWORK-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("SNMP-COMMUNITY-MIB"), + unload_master("SNMP-MPD-MIB"), + unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-FRAMEWORK-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), ?IPRINT("loop_mib_2 -> done"), ok. -loop_mib_3(suite) -> []; loop_mib_3(Config) when is_list(Config) -> ?P(loop_mib_3), ?IPRINT("loop_mib_3 -> initiate case"), @@ -6629,18 +6595,18 @@ loop_mib_3(Config) when is_list(Config) -> "\tMgrNode: ~p~n" "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]), ?DBG("loop_mib_3 -> load mibs",[]), - ?line load_master_std("SNMP-TARGET-MIB"), - ?line load_master_std("SNMP-NOTIFICATION-MIB"), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), - ?line load_master_std("SNMP-USER-BASED-SM-MIB"), + load_master_std("SNMP-TARGET-MIB"), + load_master_std("SNMP-NOTIFICATION-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master_std("SNMP-USER-BASED-SM-MIB"), try_test(loop_mib_3_test), ?DBG("loop_mib_3 -> unload mibs",[]), - ?line unload_master("SNMP-TARGET-MIB"), - ?line unload_master("SNMP-NOTIFICATION-MIB"), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"), - ?line unload_master("SNMP-USER-BASED-SM-MIB"), + unload_master("SNMP-TARGET-MIB"), + unload_master("SNMP-NOTIFICATION-MIB"), + unload_master("SNMP-VIEW-BASED-ACM-MIB"), + unload_master("SNMP-USER-BASED-SM-MIB"), ?IPRINT("loop_mib_3 -> done"), ok. @@ -6649,8 +6615,8 @@ loop_mib_3(Config) when is_list(Config) -> loop_mib_1_test() -> ?IPRINT("loop_mib_1_test -> entry"), N = loop_it_1([1,1], 0), - ?IPRINT("found ~w varibles", [N]), - ?line N = if N < 100 -> 100; + ?IPRINT("found ~w variables", [N]), + N = if N < 100 -> 100; true -> N end. @@ -6668,7 +6634,7 @@ loop_it_1(Oid, N) -> "expected intermediate (get-next) result: " "~n NOid: ~p" "~n Value: ~p", [NOid, _Value]), - ?line [_Value2] = get_req(1, [NOid]), % must not be same + [_Value2] = get_req(1, [NOid]), % must not be same ?IPRINT("loop_it_1_test -> expected intermediate (get) result: " "~n Value2: ~p", [_Value2]), loop_it_1(NOid, N+1); @@ -6679,7 +6645,7 @@ loop_it_1(Oid, N) -> varbinds = Vbs} -> ?EPRINT("loop_it_1_test -> unexpected (get-response) vbs: " "~n Vbs: ~p", [Vbs]), - ?line ?FAIL({unexpected_vbs, + ?FAIL({unexpected_vbs, [{get_next_oid, Oid}, {counter, N}, {varbinds, Vbs}]}); @@ -6699,7 +6665,7 @@ loop_it_1(Oid, N) -> "~n Err: ~p" "~n Idx: ~p" "~n Vbs: ~p", [Err, Idx, Vbs]), - ?line ?FAIL({unexpected_pdu, + ?FAIL({unexpected_pdu, [{get_next_oid, Oid}, {counter, N}, {error_status, Err}, @@ -6715,7 +6681,7 @@ loop_it_1(Oid, N) -> "~n Err: ~p" "~n Idx: ~p" "~n Vbs: ~p", [Type, Err, Idx, Vbs]), - ?line ?FAIL({unexpected_pdu, + ?FAIL({unexpected_pdu, [{get_next_oid, Oid}, {counter, N}, {type, Type}, @@ -6735,7 +6701,7 @@ loop_it_1(Oid, N) -> (SysEvs =:= []) -> ?EPRINT("loop_it_1_test -> error: " "~n ~p", [Reason]), - ?line ?FAIL([{get_next_oid, Oid}, + ?FAIL([{get_next_oid, Oid}, {counter, N}, {reason, Reason}]); @@ -6750,12 +6716,12 @@ loop_it_1(Oid, N) -> end. -%% Req. As many mibs all possible +%% Req. As many mibs as possible loop_mib_2_test() -> ?IPRINT("loop_mib_2_test -> entry"), N = loop_it_2([1,1], 0), - ?IPRINT("found ~w varibles", [N]), - ?line N = if N < 100 -> 100; + ?IPRINT("found ~w variables", [N]), + N = if N < 100 -> 100; true -> N end. @@ -6781,7 +6747,7 @@ loop_it_2(Oid, N) -> "expected intermediate (get-next) result: " "~n NOid: ~p" "~n Value: ~p", [NOid, _Value]), - ?line [_Value2] = get_req(1, [NOid]), % must not be same + [_Value2] = get_req(1, [NOid]), % must not be same ?IPRINT("loop_it_2 -> expected intermediate (get) result: " "~n Value2: ~p", [_Value2]), loop_it_2(NOid, N+1); @@ -6792,7 +6758,7 @@ loop_it_2(Oid, N) -> varbinds = Vbs} -> ?EPRINT("loop_it_2 -> unexpected (get-response) vbs: " "~n Vbs: ~p", [Vbs]), - ?line ?FAIL({unexpected_vbs, + ?FAIL({unexpected_vbs, [{get_next_oid, Oid}, {counter, N}, {varbinds, Vbs}]}); @@ -6805,7 +6771,7 @@ loop_it_2(Oid, N) -> "~n ES: ~p" "~n EI: ~p" "~n Vbs: ~p", [ES, EI, Vbs]), - ?line ?FAIL({unexpected_pdu, + ?FAIL({unexpected_pdu, [{get_next_oid, Oid}, {counter, N}, {error_status, ES}, @@ -6821,7 +6787,7 @@ loop_it_2(Oid, N) -> "~n ES: ~p" "~n EI: ~p" "~n Vbs: ~p", [Type, ES, EI, Vbs]), - ?line ?FAIL({unexpected_pdu, + ?FAIL({unexpected_pdu, [{get_next_oid, Oid}, {counter, N}, {type, Type}, @@ -6839,18 +6805,22 @@ loop_it_2(Oid, N) -> SysEvs = snmp_test_global_sys_monitor:events(), if (SysEvs =:= []) -> - ?EPRINT("loop_it_2 -> error: " - "~n ~p", [Reason]), - ?line ?FAIL([{get_next_oid, Oid}, - {counter, N}, - {reason, Reason}]); + ?EPRINT("loop_it_2 -> error *without* system events: " + "~n Oid: ~p" + "~n N: ~p" + "~n Reason: ~p", [Oid, N,Reason]), + ?FAIL([{get_next_oid, Oid}, + {counter, N}, + {reason, Reason}]); - true -> + true -> ?WPRINT("loop_it_2 -> " - "error when we got system events: " + "error *with* system events: " + "~n Oid: ~p" + "~n N: ~p" "~n Reason: ~p" "~n Sys Events: ~p" - "~n", [Reason, SysEvs]), + "~n", [Oid, N, Reason, SysEvs]), ?SKIP([{reason, Reason}, {system_events, SysEvs}]) end end. @@ -6922,15 +6892,14 @@ reported_bugs3_cases() -> %% Ticket: OTP-1128 %% Slogan: Bug in handling of createAndWait set-requests. %%----------------------------------------------------------------- -otp_1128(suite) -> []; otp_1128(Config) when is_list(Config) -> ?P(otp_1128), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(otp_1128_test), - ?line unload_master("OLD-SNMPEA-MIB"), + unload_master("OLD-SNMPEA-MIB"), ok. otp_1128_2(X) -> ?P(otp_1128_2), otp_1128(X). @@ -6945,15 +6914,15 @@ otp_1128_test() -> NewKeyc5 = [intCommunityStatus,get(mip),is("test")], s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), - ?line ?expect1([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), + ?expect1([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]), g([NewKeyc5]), - ?line ?expect1([{NewKeyc5, ?notReady}]), + ?expect1([{NewKeyc5, ?notReady}]), s([{NewKeyc5, ?active}, {NewKeyc3, 2}]), - ?line ?expect1([{NewKeyc5, ?active}, {NewKeyc3, 2}]), + ?expect1([{NewKeyc5, ?active}, {NewKeyc3, 2}]), g([NewKeyc5]), - ?line ?expect1([{NewKeyc5, ?active}]), + ?expect1([{NewKeyc5, ?active}]), s([{NewKeyc5, ?destroy}]), - ?line ?expect1([{NewKeyc5, ?destroy}]), + ?expect1([{NewKeyc5, ?destroy}]), ok. @@ -6961,13 +6930,12 @@ otp_1128_test() -> %% Ticket: OTP-1129, OTP-1169 %% Slogan: snmpa:int_to_enum crashes on bad oids %%----------------------------------------------------------------- -otp_1129(suite) -> []; otp_1129(Config) when is_list(Config) -> ?P(otp_1129), init_case(Config), - ?line load_master("Klas3"), + load_master("Klas3"), try_test(otp_1129_i, [node()]), - ?line unload_master("Klas3"), + unload_master("Klas3"), ok. otp_1129_2(X) -> ?P(otp_1129_2), otp_1129(X). @@ -6986,14 +6954,13 @@ otp_1129_i(MaNode) -> %% setrequest is of bad type, e.g. an INDEX {INTEGER}, %% and RowIdenx [3,2]. %%----------------------------------------------------------------- -otp_1131(suite) -> []; otp_1131(Config) when is_list(Config) -> ?P(otp_1131), init_case(Config), - ?line load_master("Klas1"), + load_master("Klas1"), try_test(otp_1131_test), - ?line unload_master("Klas1"). + unload_master("Klas1"). otp_1131_2(X) -> ?P(otp_1131_2), otp_1131(X). @@ -7046,7 +7013,7 @@ otp_1131_test() -> io:format("Testing bug reported in ticket OTP-1131...~n"), s([{[friendsEntry, [2, 3, 1]], s, "kompis3"}, {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]), - ?line ?expect3(?v1_2(noSuchName, noCreation), 2, any), + ?expect3(?v1_2(noSuchName, noCreation), 2, any), ok. @@ -7054,11 +7021,10 @@ otp_1131_test() -> %% Ticket: OTP-1162 %% Slogan: snmp_agent can't handle wrongValue from instrum.func %%----------------------------------------------------------------- -otp_1162(suite) -> []; otp_1162(Config) when is_list(Config) -> ?P(otp_1162), {SaNode, _MgrNode, _MibDir} = init_case(Config), - ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), + {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"), try_test(otp_1162_test), stop_subagent(SA). @@ -7068,7 +7034,7 @@ otp_1162_3(X) -> ?P(otp_1162_3), otp_1162(X). otp_1162_test() -> s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok) - ?line ?expect3(?v1_2(badValue, wrongValue), 1, any), + ?expect3(?v1_2(badValue, wrongValue), 1, any), ok. @@ -7076,15 +7042,14 @@ otp_1162_test() -> %% Ticket: OTP-1222 %% Slogan: snmp agent crash if faulty index is returned from instrum %%----------------------------------------------------------------- -otp_1222(suite) -> []; otp_1222(Config) when is_list(Config) -> ?P(otp_1222), init_case(Config), - ?line load_master("Klas3"), - ?line load_master("Klas4"), + load_master("Klas3"), + load_master("Klas4"), try_test(otp_1222_test), - ?line unload_master("Klas3"), - ?line unload_master("Klas4"), + unload_master("Klas3"), + unload_master("Klas4"), ok. otp_1222_2(X) -> ?P(otp_1222_2), otp_1222(X). @@ -7094,9 +7059,9 @@ otp_1222_3(X) -> ?P(otp_1222_3), otp_1222(X). otp_1222_test() -> io:format("Testing bug reported in ticket OTP-1222...~n"), s([{[fStatus4,1], 4}, {[fName4,1], 1}]), - ?line ?expect3(genErr, 0, any), + ?expect3(genErr, 0, any), s([{[fStatus4,2], 4}, {[fName4,2], 1}]), - ?line ?expect3(genErr, 0, any), + ?expect3(genErr, 0, any), ok. @@ -7104,14 +7069,13 @@ otp_1222_test() -> %% Ticket: OTP-1298 %% Slogan: Negative INTEGER values are treated as positive. %%----------------------------------------------------------------- -otp_1298(suite) -> []; otp_1298(Config) when is_list(Config) -> ?P(otp_1298), init_case(Config), - ?line load_master("Klas2"), + load_master("Klas2"), try_test(otp_1298_test), - ?line unload_master("Klas2"), + unload_master("Klas2"), ok. otp_1298_2(X) -> ?P(otp_1298_2), otp_1298(X). @@ -7121,7 +7085,7 @@ otp_1298_3(X) -> ?P(otp_1298_3), otp_1298(X). otp_1298_test() -> io:format("Testing bug reported in ticket OTP-1298...~n"), s([{[fint,0], -1}]), - ?line ?expect1([{[fint,0], -1}]), + ?expect1([{[fint,0], -1}]), ok. @@ -7129,14 +7093,13 @@ otp_1298_test() -> %% Ticket: OTP-1331 %% Slogan: snmp_generic should return noError when deleting non-ex row %%----------------------------------------------------------------- -otp_1331(suite) -> []; otp_1331(Config) when is_list(Config) -> ?P(otp_1331), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(otp_1331_test), - ?line unload_master("OLD-SNMPEA-MIB"), + unload_master("OLD-SNMPEA-MIB"), ok. otp_1331_2(X) -> ?P(otp_1331_2), otp_1331(X). @@ -7146,7 +7109,7 @@ otp_1331_3(X) -> ?P(otp_1331_3), otp_1331(X). otp_1331_test() -> NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")], s([{NewKeyc5, ?destroy}]), - ?line ?expect1([{NewKeyc5, ?destroy}]), + ?expect1([{NewKeyc5, ?destroy}]), ok. @@ -7154,14 +7117,13 @@ otp_1331_test() -> %% Ticket: OTP-1338 %% Slogan: snmp bug in initialisation of default values for mnesia tabs %%----------------------------------------------------------------- -otp_1338(suite) -> []; otp_1338(Config) when is_list(Config) -> ?P(otp_1338), init_case(Config), - ?line load_master("Klas2"), + load_master("Klas2"), try_test(otp_1338_test), - ?line unload_master("Klas2"). + unload_master("Klas2"). otp_1338_2(X) -> ?P(otp_1338_2), otp_1338(X). @@ -7169,9 +7131,9 @@ otp_1338_3(X) -> ?P(otp_1338_3), otp_1338(X). otp_1338_test() -> s([{[kStatus2, 7], i, ?createAndGo}]), - ?line ?expect1([{[kStatus2, 7], ?createAndGo}]), + ?expect1([{[kStatus2, 7], ?createAndGo}]), g([[kName2, 7]]), - ?line ?expect1([{[kName2, 7], "JJJ"}]). + ?expect1([{[kName2, 7], "JJJ"}]). %%----------------------------------------------------------------- @@ -7179,13 +7141,12 @@ otp_1338_test() -> %% Slogan: default impl of snmp table can't handle bad index access, %% Set when INDEX is read-write gets into an infinite loop! %%----------------------------------------------------------------- -otp_1342(suite) -> []; otp_1342(Config) when is_list(Config) -> ?P(otp_1342), init_case(Config), - ?line load_master("Klas4"), + load_master("Klas4"), try_test(otp_1342_test), - ?line unload_master("Klas4"), + unload_master("Klas4"), ok. otp_1342_2(X) -> ?P(otp_1342_2), otp_1342(X). @@ -7196,7 +7157,7 @@ otp_1342_test() -> s([{[fIndex5, 1], i, 1}, {[fName5, 1], i, 3}, {[fStatus5, 1], i, ?createAndGo}]), - ?line ?expect3(?v1_2(noSuchName, noCreation), 3, any), + ?expect3(?v1_2(noSuchName, noCreation), 3, any), ok. @@ -7206,14 +7167,13 @@ otp_1342_test() -> %% Note: NYI! We need a way to tell the test server that we need %% mgrs on two different machines. %%----------------------------------------------------------------- -otp_1366(suite) -> []; otp_1366(Config) when is_list(Config) -> ?P(otp_1366), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(otp_1366_test), - ?line unload_master("OLD-SNMPEA-MIB"), + unload_master("OLD-SNMPEA-MIB"), ok. otp_1366_2(X) -> ?P(otp_1366_2), otp_1366(X). @@ -7229,7 +7189,6 @@ otp_1366_test() -> %% Ticket: OTP-2776 %% Slogan: snmp:validate_date_and_time() fails when time is 00:00 %%----------------------------------------------------------------- -otp_2776(suite) -> []; otp_2776(Config) when is_list(Config) -> ?P(otp_2776), init_case(Config), @@ -7265,7 +7224,7 @@ otp_2776_test() -> {10, false, Dt10_invalid}, {11, false, Dt11_invalid}], - ?line ok = validate_dat(L). + ok = validate_dat(L). validate_dat(L) -> validate_dat(L,[]). @@ -7296,14 +7255,13 @@ validate_dat2(Id, E, Dat) -> %% Slogan: get-next on more than 1 column in an empty table %% returns bad response. %%----------------------------------------------------------------- -otp_2979(suite) -> []; otp_2979(Config) when is_list(Config) -> ?P(otp_2979), init_case(Config), - ?line load_master("Test1"), - ?line init_old(), + load_master("Test1"), + init_old(), try_test(otp_2979_test), - ?line unload_master("Test1"). + unload_master("Test1"). otp_2979_2(X) -> ?P(otp_2979_2), otp_2979(X). @@ -7311,33 +7269,32 @@ otp_2979_3(X) -> ?P(otp_2979_3), otp_2979(X). otp_2979_test() -> gn([[sparseDescr], [sparseStatus]]), - ?line ?expect1([{[sparseStr,0], "slut"}, + ?expect1([{[sparseStr,0], "slut"}, {[sparseStr,0], "slut"}]), ok. %%----------------------------------------------------------------- %% Ticket: OTP-3187 -%% Slogan: get-next on vacmAccessTable for colums > 5 returns +%% Slogan: get-next on vacmAccessTable for columns > 5 returns %% endOfTable - should return value. %%----------------------------------------------------------------- -otp_3187(suite) -> []; otp_3187(Config) when is_list(Config) -> ?P(otp_3187), init_case(Config), - ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"), + load_master_std("SNMP-VIEW-BASED-ACM-MIB"), otp_3187_test(), - ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"). + unload_master("SNMP-VIEW-BASED-ACM-MIB"). otp_3187_2(X) -> ?P(otp_3187_2), otp_3187(X). otp_3187_3(X) -> ?P(otp_3187_3), otp_3187(X). otp_3187_test() -> - ?line Elements = + Elements = snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]), lists:foreach(fun(E) -> - ?line if E == endOfTable -> + if E == endOfTable -> ?FAIL(endOfTable); true -> ok end @@ -7347,7 +7304,6 @@ otp_3187_test() -> %% Ticket: OTP-3542 %% Slogan: %%----------------------------------------------------------------- -otp_3542(suite) -> []; otp_3542(Config) when is_list(Config) -> ?P(otp_3542), init_case(Config), @@ -7355,7 +7311,7 @@ otp_3542(Config) when is_list(Config) -> otp_3542_test() -> io:format("SNMP v3 discovery...~n"), - ?line Res = snmp_test_mgr:d(), + Res = snmp_test_mgr:d(), io:format("SNMP v3 discovery result: ~p~n",[Res]). @@ -7363,57 +7319,56 @@ otp_3542_test() -> %% Ticket: OTP-3725 %% Slogan: Slow response time on snmpa:int_to_enum %%----------------------------------------------------------------- -otp_3725(suite) -> []; otp_3725(Config) when is_list(Config) -> ?P(otp_3725), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(otp_3725_test, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). + unload_master("OLD-SNMPEA-MIB"). %% Req. OLD-SNMPEA-MIB otp_3725_test(MaNode) -> io:format("Testing feature requested in ticket OTP-3725...~n"), - ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), - ?line Db = rpc:call(MaNode, snmpa, get_symbolic_store_db, []), + rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]), + Db = rpc:call(MaNode, snmpa, get_symbolic_store_db, []), ?DBG("otp_3725_test -> Db = ~p", [Db]), - ?line {value, OID} = rpc:call(MaNode, snmpa, name_to_oid, + {value, OID} = rpc:call(MaNode, snmpa, name_to_oid, [Db, intAgentIpAddress]), ?DBG("otp_3725_test -> name_to_oid for ~p: ~p", [intAgentIpAddress,OID]), - ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmpa, oid_to_name, + {value, intAgentIpAddress} = rpc:call(MaNode, snmpa, oid_to_name, [Db,OID]), ?DBG("otp_3725_test -> oid_to_name for ~p: ~p", [OID, intAgentIpAddress]), - ?line false = rpc:call(MaNode, snmpa, name_to_oid, [Db, intAgentIpAddres]), - ?line false = rpc:call(MaNode, snmpa, oid_to_name, + false = rpc:call(MaNode, snmpa, name_to_oid, [Db, intAgentIpAddres]), + false = rpc:call(MaNode, snmpa, oid_to_name, [Db, [1,5,32,3,54,3,3,34,4]]), - ?line {value, 2} = rpc:call(MaNode, snmpa, enum_to_int, + {value, 2} = rpc:call(MaNode, snmpa, enum_to_int, [Db, intViewType, excluded]), - ?line {value, excluded} = rpc:call(MaNode, snmpa, int_to_enum, + {value, excluded} = rpc:call(MaNode, snmpa, int_to_enum, [Db, intViewType, 2]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [Db, intViewType, exclude]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [Db, intAgentIpAddress, exclude]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [Db, intAgentIpAddre, exclude]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [Db, intViewType, 3]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, + false = rpc:call(MaNode, snmpa, int_to_enum, [Db, intViewType, 3]), + false = rpc:call(MaNode, snmpa, int_to_enum, [Db, intAgentIpAddress, 2]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, + false = rpc:call(MaNode, snmpa, int_to_enum, [Db, intAgentIpAddre, 2]), - ?line {value, active} = rpc:call(MaNode, snmpa, int_to_enum, + {value, active} = rpc:call(MaNode, snmpa, int_to_enum, [Db, 'RowStatus', ?active]), - ?line {value, ?destroy} = rpc:call(MaNode, snmpa, enum_to_int, + {value, ?destroy} = rpc:call(MaNode, snmpa, enum_to_int, [Db, 'RowStatus', destroy]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [Db, 'RowStatus', xxxdestroy]), - ?line false = rpc:call(MaNode, snmpa, enum_to_int, + false = rpc:call(MaNode, snmpa, enum_to_int, [Db, 'xxRowStatus', destroy]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [Db, 'RowStatus', 25]), - ?line false = rpc:call(MaNode, snmpa, int_to_enum, [Db, 'xxRowStatus', 1]), + false = rpc:call(MaNode, snmpa, int_to_enum, [Db, 'RowStatus', 25]), + false = rpc:call(MaNode, snmpa, int_to_enum, [Db, 'xxRowStatus', 1]), ok. @@ -7425,10 +7380,10 @@ otp_3725_test(MaNode) -> otp_4394_init(Config) when is_list(Config) -> ?DBG("otp_4394_init -> entry with" "~n Config: ~p", [Config]), - ?line AgentConfDir = ?config(agent_conf_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line otp_4394_config(AgentConfDir, MgrDir, Ip), + AgentConfDir = ?config(agent_conf_dir, Config), + MgrDir = ?config(mgr_dir, Config), + Ip = ?config(ip, Config), + otp_4394_config(AgentConfDir, MgrDir, Ip), MasterAgentVerbosity = {master_agent_verbosity, trace}, NetIfVerbosity = {net_if_verbosity, trace}, Opts = [MasterAgentVerbosity, NetIfVerbosity], @@ -7441,21 +7396,21 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) -> "~n Ip0: ~p", [AgentConfDir, MgrDir, Ip0]), Vsn = [v1], Ip = tuple_to_list(Ip0), - ?line snmp_config:write_agent_snmp_files(AgentConfDir, Vsn, Ip, + snmp_config:write_agent_snmp_files(AgentConfDir, Vsn, Ip, ?TRAP_UDP, Ip, 4000, "OTP-4394 test"), - ?line case update_usm(Vsn, AgentConfDir) of + case update_usm(Vsn, AgentConfDir) of true -> - ?line copy_file(join(AgentConfDir, "usm.conf"), + copy_file(join(AgentConfDir, "usm.conf"), join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsn, MgrDir); + update_usm_mgr(Vsn, MgrDir); false -> - ?line ok + ok end, C1 = {"a", "all-rights", "initial", "", "pc"}, C2 = {"c", "secret", "secret_name", "", "secret_tag"}, - ?line write_community_conf(AgentConfDir, [C1, C2]), - ?line update_vacm(Vsn, AgentConfDir), + write_community_conf(AgentConfDir, [C1, C2]), + update_vacm(Vsn, AgentConfDir), Ta1 = {"shelob v1", [134,138,177,177], 5000, 1500, 3, %% Use Ip and modify "pc1", @@ -7469,9 +7424,9 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) -> "target_v1", "", %% [255,255,255,255,0,0], [], 2048}, - ?line write_target_addr_conf(AgentConfDir, [Ta1, Ta2]), - ?line write_target_params_conf(AgentConfDir, Vsn), - ?line write_notify_conf(AgentConfDir), + write_target_addr_conf(AgentConfDir, [Ta1, Ta2]), + write_target_params_conf(AgentConfDir, Vsn), + write_notify_conf(AgentConfDir), ok. otp_4394_finish(Config) when is_list(Config) -> @@ -7481,7 +7436,6 @@ otp_4394_finish(Config) when is_list(Config) -> erase(mgr_node), lists:keydelete(vsn, 1, C1). -otp_4394(suite) -> []; otp_4394(Config) -> ?P(otp_4394), ?DBG("otp_4394 -> entry", []), @@ -7519,10 +7473,10 @@ otp_7157_init(Config) when is_list(Config) -> ?DBG("init_otp_7157 -> entry with" "~n Config: ~p", [Config]), - ?line AgentConfDir = ?config(agent_conf_dir, Config), - ?line MgrDir = ?config(mgr_dir, Config), - ?line Ip = ?config(ip, Config), - ?line config([v2], MgrDir, AgentConfDir, + AgentConfDir = ?config(agent_conf_dir, Config), + MgrDir = ?config(mgr_dir, Config), + Ip = ?config(ip, Config), + config([v2], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), MasterAgentVerbosity = {master_agent_verbosity, trace}, NetIfVerbosity = {net_if_verbosity, trace}, @@ -7537,15 +7491,14 @@ otp_7157_finish(Config) when is_list(Config) -> erase(mgr_node), lists:keydelete(vsn, 1, C1). -otp_7157(suite) -> []; otp_7157(Config) -> ?P(otp_7157), ?DBG("otp_7157 -> entry", []), init_case(Config), MA = whereis(snmp_master_agent), - ?line load_master("Test1"), + load_master("Test1"), try_test(otp_7157_test, [MA]), - ?line unload_master("Test1"), + unload_master("Test1"), ?DBG("otp_7157 -> done", []), ok. @@ -7562,7 +7515,7 @@ otp_7157_test(MA) -> ?DBG("await response",[]), %% We don't really care about the values, just the vb order. - ?line ok = ?expect2(v2trap, [{[sysUpTime, 0], any}, + ok = ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], any}, {[sysContact, 0], any}, {[cnt64, 0], any}, @@ -7588,108 +7541,80 @@ otp16092_cases() -> otp_16092_simple_start_and_stop4 % invalid content ]. -otp_16092_simple_start_and_stop1(suite) -> []; otp_16092_simple_start_and_stop1(Config) -> - ?P(otp_16092_simple_start_and_stop1), - ?DBG("otp_16092_simple_start_and_stop1 -> entry", []), - - TC = fun() -> - otp_16092_simple_start_and_stop(Config, default, success) - end, + otp_16092_simple_start_and_stop(?FUNCTION_NAME, + Config, default, success). - Result = otp_16092_try(TC), - ?DBG("otp_16092_simple_start_and_stop1 -> done: " - "~n ~p", [Result]), - - Result. - - -otp_16092_simple_start_and_stop2(suite) -> []; otp_16092_simple_start_and_stop2(Config) -> - ?P(otp_16092_simple_start_and_stop2), - ?DBG("otp_16092_simple_start_and_stop2 -> entry", []), - - TC = fun() -> - otp_16092_simple_start_and_stop(Config, [], success) - end, + otp_16092_simple_start_and_stop(?FUNCTION_NAME, + Config, [], success). - Result = otp_16092_try(TC), - ?DBG("otp_16092_simple_start_and_stop2 -> done: " - "~n ~p", [Result]), - - Result. - - -otp_16092_simple_start_and_stop3(suite) -> []; otp_16092_simple_start_and_stop3(Config) -> - ?P(otp_16092_simple_start_and_stop3), - ?DBG("otp_16092_simple_start_and_stop3 -> entry", []), - - TC = fun() -> - otp_16092_simple_start_and_stop(Config, - 'this-should-be-ignored', - success) - end, - - Result = otp_16092_try(TC), - - ?DBG("otp_16092_simple_start_and_stop3 -> done: " - "~n ~p", [Result]), - - Result. + otp_16092_simple_start_and_stop(?FUNCTION_NAME, + Config, + 'this-should-be-ignored', + success). -otp_16092_simple_start_and_stop4(suite) -> []; otp_16092_simple_start_and_stop4(Config) -> - ?P(otp_16092_simple_start_and_stop4), - ?DBG("otp_16092_simple_start_and_stop4 -> entry", []), - - TC = fun() -> - otp_16092_simple_start_and_stop(Config, - ['this-should-fail'], - failure) - end, - - Result = otp_16092_try(TC), - - ?DBG("otp_16092_simple_start_and_stop4 -> done: " - "~n ", [Result]), - - Result. - - -otp_16092_try(TC) -> - try TC() of - Any -> - Any - catch - _:{skip, _} = SKIP -> - SKIP - end. - -otp_16092_simple_start_and_stop(Config, ESO, Expected) -> - ?line ConfDir = ?config(agent_conf_dir, Config), - ?line DbDir = ?config(agent_db_dir, Config), - - ?NPRINT("try start agent node"), - {ok, Node} = ?ALIB:start_node(agent_16092), - - Vsns = [v1], - IP = tuple_to_list(?config(ip, Config)), - ManagerIP = IP, - TrapPort = ?TRAP_UDP, - AgentIP = IP, - AgentPort = 4000, - SysName = "test", - ok = snmp_config:write_agent_snmp_files( - ConfDir, Vsns, ManagerIP, TrapPort, AgentIP, AgentPort, SysName), - - ConfOpts = [{dir, ConfDir}, - {force_load, false}, - {verbosity, trace}], - NiOpts = + otp_16092_simple_start_and_stop(?FUNCTION_NAME, + Config, + ['this-should-fail'], + failure). + +otp_16092_simple_start_and_stop(CaseName, Config, ESO, Expected) + when is_atom(CaseName) -> + Pre = fun() -> + [D|_] = lists:reverse(atom_to_list(CaseName)), + Digit = [D], + + ?NPRINT("try start agent node"), + {ok, Peer, Node} = ?START_PEER(Digit ++ "-agent"), + + ?NPRINT("try write config to file"), + ConfDir = ?config(agent_conf_dir, Config), + DbDir = ?config(agent_db_dir, Config), + Vsns = [v1], + IP = tuple_to_list(?config(ip, Config)), + ManagerIP = IP, + TrapPort = ?TRAP_UDP, + AgentIP = IP, + AgentPort = 4000, + SysName = "test", + ok = snmp_config:write_agent_snmp_files(ConfDir, Vsns, + ManagerIP, TrapPort, + AgentIP, AgentPort, + SysName), + + #{eso => ESO, + vsns => Vsns, + db_dir => DbDir, + conf_opts => [{dir, ConfDir}, + {force_load, false}, + {verbosity, trace}], + node => Node, + peer => Peer, + expected => Expected} + end, + Case = fun(State) -> + do_otp_16092_simple_start_and_stop(State) + end, + Post = fun(#{node := Node, + peer := Peer}) -> + ?NPRINT("try stop agent node ~p", [Node]), + ?STOP_PEER(Peer) + end, + ?TC_TRY(CaseName, Pre, Case, Post). + +do_otp_16092_simple_start_and_stop(#{eso := ESO, + vsns := Vsns, + db_dir := DbDir, + conf_opts := ConfOpts, + node := Node, + expected := Expected} = _State) -> + NiOpts = case ESO of default -> [{verbosity, trace}]; @@ -7705,15 +7630,9 @@ otp_16092_simple_start_and_stop(Config, ESO, Expected) -> otp16092_try_start_and_stop_agent(Node, Opts, Expected), - ?NPRINT("try stop agent node ~p", [Node]), - ?ALIB:stop_node(Node), - - ?SLEEP(1000), - ?NPRINT("done"), ok. - otp16092_try_start_and_stop_agent(Node, Opts, Expected) -> ?IPRINT("try start snmp (agent) supervisor (on ~p) - expect ~p", [Node, Expected]), @@ -7794,9 +7713,8 @@ otp8395({init, Config}) when is_list(Config) -> %% -- %% Start nodes %% - FName = ?FUNCTION_NAME, - {ok, AgentNode} = start_node(mk_node_name(FName, agent)), - {ok, ManagerNode} = start_node(mk_node_name(FName, manager)), + {ok, AgentPeer, AgentNode} = ?START_PEER("-agent"), + {ok, ManagerPeer, ManagerNode} = ?START_PEER("-manager"), %% -- %% Mnesia init @@ -7846,12 +7764,14 @@ otp8395({init, Config}) when is_list(Config) -> Config2 = start_agent([{host, Host}, {ip, Ip}, {ipfamily, IpFamily}, + {agent_peer, AgentPeer}, {agent_node, AgentNode}, {agent_host, AgentHost}, {agent_ip, AgentIP}, %% {sub_agent_node, SubAgentNode}, %% {sub_agent_host, SubAgentHost}, - %% {sub_agent_ip, SubAgentIP}, + %% {sub_agent_ip, SubAgentIP}, + {manager_peer, ManagerPeer}, {manager_node, ManagerNode}, {manager_host, ManagerHost}, {manager_ip, ManagerIP}|Config]), @@ -7867,7 +7787,6 @@ otp8395({fin, Config}) when is_list(Config) -> "~n Config: ~p", [Config]), AgentNode = ?config(agent_node, Config), - ManagerNode = ?config(manager_node, Config), %% - %% Stop agent (this is the nice way to do it, @@ -7890,14 +7809,14 @@ otp8395({fin, Config}) when is_list(Config) -> %% ?DBG("otp8395(fin) -> stop agent node", []), - stop_node(AgentNode), + ?STOP_PEER(?config(agent_peer, Config)), %% - %% Stop the manager node %% ?DBG("otp8395(fin) -> stop manager node", []), - stop_node(ManagerNode), + ?STOP_PEER(?config(manager_peer, Config)), wd_stop(Config); @@ -8156,7 +8075,7 @@ otp16649(N, Config) -> AgentNode = ?config(agent_node, Config), ManagerNode = ?config(manager_node, Config), - ?line AInfo = rpc:call(AgentNode, snmpa, info, []), + AInfo = rpc:call(AgentNode, snmpa, info, []), ?IPRINT("Agent Info: " "~n ~p", [AInfo]), @@ -8189,25 +8108,25 @@ otp16649(N, Config) -> AgentTrapPortNo = otp16649_which_trap_port_no(TIs), ?IPRINT("(mgr) register user"), - ?line ok = otp16649_mgr_reg_user(ManagerNode), + ok = otp16649_mgr_reg_user(ManagerNode), ?IPRINT("(mgr) register agent"), TargetBase = "otp16649-agent-", ReqTarget = TargetBase ++ "req", TrapTarget = TargetBase ++ "trap", - ?line ok = otp16649_mgr_reg_agent(ManagerNode, + ok = otp16649_mgr_reg_agent(ManagerNode, ?config(ipfamily, Config), ?config(tdomain, Config), ReqTarget, AgentReqPortNo), - ?line ok = otp16649_mgr_reg_agent(ManagerNode, + ok = otp16649_mgr_reg_agent(ManagerNode, ?config(ipfamily, Config), ?config(tdomain, Config), TrapTarget, AgentTrapPortNo), ?IPRINT("(mgr) simple (sync) get request"), Oids = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance], - ?line ok = case otp16649_mgr_get_req(ManagerNode, Oids) of + ok = case otp16649_mgr_get_req(ManagerNode, Oids) of {ok, {noError, 0, ReplyOids}, _} -> ?IPRINT("(mgr) simple (sync) successful reply: " "~n ~p", [ReplyOids]), @@ -8224,10 +8143,10 @@ otp16649(N, Config) -> ?IPRINT("load TestTrap..."), MibDir = ?config(mib_dir, Config), - ?line ok = otp16649_agent_load_mib(AgentNode, MibDir, "TestTrap"), + ok = otp16649_agent_load_mib(AgentNode, MibDir, "TestTrap"), ?IPRINT("(agent) send trap (testTrap2)"), - ?line ok = otp16649_agent_send_trap(AgentNode, testTrap2), + ok = otp16649_agent_send_trap(AgentNode, testTrap2), TDomain = ?config(tdomain, Config), @@ -8245,7 +8164,7 @@ otp16649(N, Config) -> case TDomain of transportDomainUdpIpv4 -> ?IPRINT("TIMEOUT"), - ?line exit(timeout); + exit(timeout); transportDomainUdpIpv6 -> ?IPRINT("expected timeout - " "v1 trap's can only be sent on IPv4 domains"), @@ -8255,10 +8174,10 @@ otp16649(N, Config) -> ?IPRINT("load TestTrapv2..."), - ?line ok = otp16649_agent_load_mib(AgentNode, MibDir, "TestTrapv2"), + ok = otp16649_agent_load_mib(AgentNode, MibDir, "TestTrapv2"), ?IPRINT("(agent) send trap (testTrapv22)"), - ?line ok = otp16649_agent_send_trap(AgentNode, testTrapv22), + ok = otp16649_agent_send_trap(AgentNode, testTrapv22), receive {handle_trap, From_v2, TrapTarget, @@ -8270,7 +8189,7 @@ otp16649(N, Config) -> after 5000 -> ?IPRINT("TIMEOUT"), - ?line exit(timeout) + exit(timeout) end, ?IPRINT("done"), @@ -8287,10 +8206,8 @@ otp16649_init(N, AgentPreTransports, Config) -> %% Start nodes %% - ?IPRINT("start (agent and mansger) nodes"), - - {ok, AgentNode} = start_node(otp16649_mk_name(N, agent)), - {ok, ManagerNode} = start_node(otp16649_mk_name(N, manager)), + {ok, AgentPeer, AgentNode} = ?START_PEER("-agent"), + {ok, ManagerPeer, ManagerNode} = ?START_PEER("-manager"), %% -- %% Misc @@ -8340,16 +8257,18 @@ otp16649_init(N, AgentPreTransports, Config) -> AgentPreTransports2 = [F(T) || T <- AgentPreTransports], ?IPRINT("write agent config files"), - ?line ok = snmp_config:write_agent_snmp_files( + ok = snmp_config:write_agent_snmp_files( AgentConfDir, Vsns, TransportDomain, {ManagerIP, ?MGR_PORT}, AgentPreTransports2, "test"), ?IPRINT("start agent"), Config2 = start_agent([{host, Host}, + {agent_peer, AgentPeer}, {agent_node, AgentNode}, {agent_host, AgentHost}, {agent_ip, AgentIP}, + {manager_peer, ManagerPeer}, {manager_node, ManagerNode}, {manager_host, ManagerHost}, {manager_ip, ManagerIP}|Config]), @@ -8364,15 +8283,15 @@ otp16649_init(N, AgentPreTransports, Config) -> MgrTopDir = ?config(manager_top_dir, Config), MgrDbDir = filename:join(MgrTopDir, "db/"), MgrConfDir = filename:join(MgrTopDir, "conf/"), - ?line ok = file:make_dir(MgrConfDir), + ok = file:make_dir(MgrConfDir), MgrDbDir = filename:join(MgrTopDir, "db/"), - ?line ok = file:make_dir(MgrDbDir), + ok = file:make_dir(MgrDbDir), MgrLogDir = filename:join(MgrTopDir, "log/"), - ?line ok = file:make_dir(MgrLogDir), + ok = file:make_dir(MgrLogDir), ?IPRINT("write manager config files"), MgrTransports = [{TransportDomain, {ManagerIP0, ?MGR_PORT}}], - ?line ok = snmp_config:write_manager_snmp_files( + ok = snmp_config:write_manager_snmp_files( MgrConfDir, MgrTransports, ?MGR_MMS, ?MGR_ENGINE_ID), @@ -8382,19 +8301,12 @@ otp16649_init(N, AgentPreTransports, Config) -> {manager_log_dir, MgrLogDir} | Config2], ?IPRINT("start manager"), - ?line ok = start_manager(Config3), + ok = start_manager(Config3), ?DBG("otp16649_init -> done when" "~n Config2: ~p", [Config3]), [{agent_raw_transports, AgentPreTransports} | Config3]. -mk_node_name(FName, Post) when is_atom(FName) andalso is_atom(Post) -> - list_to_atom(?F("~w_~w", [FName, Post])). - -otp16649_mk_name(N, Post) when is_integer(N) andalso is_atom(Post) -> - mk_node_name(otp16649, list_to_atom(?F("~w_~w", [N, Post]))). -%% list_to_atom(?F("otp16649_~w_~w", [N, Post])). - otp16649_fin(N, Config) when is_integer(N) -> ?IPRINT("otp16649_fin -> entry with" @@ -8402,14 +8314,13 @@ otp16649_fin(N, Config) when is_integer(N) -> "~n Config: ~p", [N, Config]), ManagerNode = ?config(manager_node, Config), - AgentNode = ?config(agent_node, Config), %% - %% Stop agent (this is the nice way to do it, %% so logs and files can be closed in the proper way). %% - ?line AgentTopSup = ?config(agent_sup, Config), + AgentTopSup = ?config(agent_sup, Config), stop_standalone_agent(AgentTopSup), @@ -8425,7 +8336,7 @@ otp16649_fin(N, Config) when is_integer(N) -> %% ?DBG("otp16649_fin -> stop manager node", []), - stop_node(ManagerNode), + peer:stop(?config(manager_peer, Config)), %% @@ -8433,7 +8344,7 @@ otp16649_fin(N, Config) when is_integer(N) -> %% ?DBG("otp16649_fin -> stop agent node", []), - stop_node(AgentNode), + peer:stop(?config(agent_peer, Config)), ?DBG("otp16649_fin -> done", []), Config1 = lists:keydelete(manager_node, 1, Config), @@ -8624,7 +8535,7 @@ start_agent(Config, Opts) -> process_flag(trap_exit, true), - ?line {ok, AgentTopSup} = start_standalone_agent(AgentNode, AgentConfig), + {ok, AgentTopSup} = start_standalone_agent(AgentNode, AgentConfig), [{agent_sup, AgentTopSup} | Config]. @@ -8719,7 +8630,7 @@ start_manager(Config) -> {net_if, [{verbosity, trace}]}, {note_store, [{verbosity, trace}]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], - ?line ok = start_standalone_manager(Node, Opts). + ok = start_standalone_manager(Node, Opts). start_standalone_manager(Node, Config) -> @@ -8756,18 +8667,17 @@ nkill(Pid, Reason, N) when N > 0 -> %% Slogan: info test %%----------------------------------------------------------------- -info_test(suite) -> []; info_test(Config) when is_list(Config) -> ?P(info_test), init_case(Config), - ?line load_master("OLD-SNMPEA-MIB"), - ?line init_old(), + load_master("OLD-SNMPEA-MIB"), + init_old(), try_test(do_info, [node()]), - ?line unload_master("OLD-SNMPEA-MIB"). + unload_master("OLD-SNMPEA-MIB"). do_info(MaNode) -> - ?line Info = rpc:call(MaNode, snmpa, info, []), + Info = rpc:call(MaNode, snmpa, info, []), ?DBG("info_test1 -> Info: ~n~p", [Info]), Keys = [vsns, stats_counters, @@ -8854,15 +8764,6 @@ get_next_req(Vars) -> ?ALIB:get_next_req(Vars). -start_node(Name) -> - ?ALIB:start_node(Name). - -stop_node(undefined) -> - ok; -stop_node(Node) -> - ?ALIB:stop_node(Node). - - %%%----------------------------------------------------------------- %%% Configuration %%%----------------------------------------------------------------- @@ -9075,14 +8976,12 @@ lists_key1search(Key, List) when is_atom(Key) -> init_v1_agent(Config) -> %% -- %% Start nodes - %% - - FName = ?config(fname, Config), - {ok, AgentNode} = start_node(mk_node_name(FName, agent)), + %% + {ok, AgentPeer, AgentNode} = ?START_PEER("-agent"), %% We don't use a manager in this test but the (common) config %% function takes an argument that is derived from this - {ok, ManagerNode} = start_node(mk_node_name(FName, manager)), + {ok, ManagerPeer, ManagerNode} = ?START_PEER("-manager"), %% -- %% Mnesia init @@ -9134,6 +9033,7 @@ init_v1_agent(Config) -> Config2 = start_agent([{host, Host}, {ip, Ip}, + {agent_peer, AgentPeer}, {agent_node, AgentNode}, {agent_host, AgentHost}, {agent_ip, AgentIP}, @@ -9141,6 +9041,7 @@ init_v1_agent(Config) -> %% We need this here since without it %% fin_v1_agent will not be able to stop! + {manager_peer, ManagerPeer}, {manager_node, ManagerNode}|Config]), %% -- @@ -9151,7 +9052,6 @@ init_v1_agent(Config) -> fin_v1_agent(Config) -> AgentNode = ?config(agent_node, Config), - ManagerNode = ?config(manager_node, Config), %% - %% Stop agent (this is the nice way to do it, @@ -9170,7 +9070,7 @@ fin_v1_agent(Config) -> %% - %% Stop the agent node %% - stop_node(AgentNode), + peer:stop(?config(agent_peer, Config)), %% SubAgentNode = ?config(sub_agent_node, Config), @@ -9180,7 +9080,7 @@ fin_v1_agent(Config) -> %% - %% Stop the manager node %% - stop_node(ManagerNode), + peer:stop(?config(manager_peer, Config)), wd_stop(Config). diff --git a/lib/snmp/test/snmp_agent_mibs_SUITE.erl b/lib/snmp/test/snmp_agent_mibs_SUITE.erl index f4130aed653b..3fc9f55371fe 100644 --- a/lib/snmp/test/snmp_agent_mibs_SUITE.erl +++ b/lib/snmp/test/snmp_agent_mibs_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -163,7 +163,7 @@ init_per_testcase(Case, Config0) when is_list(Config0) -> Config1 = ?LIB:fix_data_dir(Config0), CaseTopDir = ?LIB:init_testcase_top_dir(Case, Config1), DbDir = join(CaseTopDir, "db_dir/"), - ?line ok = file:make_dir(DbDir), + ok = file:make_dir(DbDir), init_per_testcase2(Case, [{db_dir, DbDir}, {case_top_dir, CaseTopDir} | Config1]). @@ -215,7 +215,6 @@ end_per_testcase1(_Case, Config) when is_list(Config) -> %% Test functions %%====================================================================== -start_and_stop(suite) -> []; start_and_stop(Config) when is_list(Config) -> tc_try(start_and_start, fun() -> do_start_and_stop(Config) end). @@ -224,20 +223,19 @@ do_start_and_stop(_Config) -> Prio = normal, Verbosity = trace, - ?line sym_start(Prio, Verbosity), - ?line MibsPid = mibs_start(Prio, Verbosity), + sym_start(Prio, Verbosity), + MibsPid = mibs_start(Prio, Verbosity), - ?line mibs_info(MibsPid), + mibs_info(MibsPid), - ?line mibs_stop(MibsPid), - ?line sym_stop(), + mibs_stop(MibsPid), + sym_stop(), ok. %% --------------------------------------------------------------------- -load_unload(suite) -> []; load_unload(Config) when is_list(Config) -> tc_try(load_unload, fun() -> do_load_unload(Config) end). @@ -250,44 +248,44 @@ do_load_unload(Config) -> MibDir = ?config(data_dir, Config), ?DBG("load_unload -> start symbolic store", []), - ?line sym_start(Prio, Verbosity), + sym_start(Prio, Verbosity), ?DBG("load_unload -> start mib server", []), - ?line MibsPid = mibs_start(Prio, Verbosity), + MibsPid = mibs_start(Prio, Verbosity), ?DBG("load_unload -> load one not already loaded mib", []), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, []), - ?line ok = load_mibs(MibsPid, MibDir, ["Test2"]), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["Test2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, []), + ok = load_mibs(MibsPid, MibDir, ["Test2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, ["Test2"]), ?DBG("load_unload -> try load one *already loaded* mib", []), EMib = join(MibDir, "Test2"), - ?line {error, {'load aborted at', EMib, already_loaded}} = + {error, {'load aborted at', EMib, already_loaded}} = load_mibs(MibsPid, MibDir, ["Test2"]), ?DBG("load_unload -> load 2 not already loaded mibs", []), - ?line ok = load_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, + ok = load_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, ["Test2", "TestTrap", "TestTrapv2"]), ?DBG("load_unload -> unload one loaded mib", []), - ?line ok = unload_mibs(MibsPid, ["Test2"]), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), + ok = unload_mibs(MibsPid, ["Test2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]), ?DBG("load_unload -> try unload two loaded mibs and one not loaded", []), - ?line {error, {'unload aborted at', "Test2", not_loaded}} = + {error, {'unload aborted at', "Test2", not_loaded}} = unload_mibs(MibsPid, ["TestTrap","Test2","TestTrapv2"]), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrapv2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrapv2"]), ?DBG("load_unload -> unload the remaining loaded mib", []), - ?line ok = unload_mibs(MibsPid, ["TestTrapv2"]), - ?line ok = verify_loaded_mibs(MibsPid, MibDir, []), + ok = unload_mibs(MibsPid, ["TestTrapv2"]), + ok = verify_loaded_mibs(MibsPid, MibDir, []), ?DBG("load_unload -> stop mib server", []), - ?line mibs_stop(MibsPid), + mibs_stop(MibsPid), ?DBG("load_unload -> stop symbolic store", []), - ?line sym_stop(), + sym_stop(), ?DBG("load_unload -> done", []), ok. @@ -296,15 +294,11 @@ do_load_unload(Config) -> %% --------------------------------------------------------------------- -size_check_ets1(suite) -> - []; size_check_ets1(Config) when is_list(Config) -> MibStorage = [{module, snmpa_mib_storage_ets}], do_size_check(size_check_ets1, [{mib_storage, MibStorage}|Config]). -size_check_ets2(suite) -> - []; size_check_ets2(Config) when is_list(Config) -> Dir = ?config(db_dir, Config), MibStorage = [{module, snmpa_mib_storage_ets}, @@ -312,8 +306,6 @@ size_check_ets2(Config) when is_list(Config) -> do_size_check(size_check_ets2, [{mib_storage, MibStorage}|Config]). -size_check_ets2_bad_file1(suite) -> - []; size_check_ets2_bad_file1(Config) when is_list(Config) -> Dir = ?config(db_dir, Config), %% Ensure that the bad file does not cause any problems (action = clear) @@ -323,8 +315,6 @@ size_check_ets2_bad_file1(Config) when is_list(Config) -> do_size_check(size_check_ets2_bad_file1, [{mib_storage, MibStorage}|Config]). -size_check_ets3(suite) -> - []; size_check_ets3(Config) when is_list(Config) -> Dir = ?config(db_dir, Config), MibStorage = [{module, snmpa_mib_storage_ets}, @@ -333,8 +323,6 @@ size_check_ets3(Config) when is_list(Config) -> do_size_check(size_check_ets3, [{mib_storage, MibStorage}|Config]). -size_check_ets3_bad_file1(suite) -> - []; size_check_ets3_bad_file1(Config) when is_list(Config) -> Dir = ?config(db_dir, Config), %% Ensure that the bad file does not cause any problems (action = clear) @@ -345,8 +333,6 @@ size_check_ets3_bad_file1(Config) when is_list(Config) -> do_size_check(size_check_ets3_bad_file1, [{mib_storage, MibStorage}|Config]). -size_check_dets(suite) -> - []; size_check_dets(Config) when is_list(Config) -> Dir = ?config(db_dir, Config), MibStorage = [{module, snmpa_mib_storage_dets}, @@ -354,8 +340,6 @@ size_check_dets(Config) when is_list(Config) -> do_size_check(size_check_dets, [{mib_storage, MibStorage}|Config]). -size_check_mnesia(suite) -> - []; size_check_mnesia(Config) when is_list(Config) -> MibStorage = [{module, snmpa_mib_storage_mnesia}, {options, [{nodes, []}]}], @@ -385,9 +369,9 @@ do_size_check(Config) -> StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/", ?IPRINT("do_size_check -> start symbolic store", []), - ?line sym_start(Prio, MibStorage, Verbosity), + sym_start(Prio, MibStorage, Verbosity), ?IPRINT("do_size_check -> start mib server", []), - ?line MibsPid = mibs_start(Prio, MibStorage, Verbosity), + MibsPid = mibs_start(Prio, MibStorage, Verbosity), Mibs = ["Test2", "TestTrap", "TestTrapv2"], StdMibs = ["OTP-SNMPEA-MIB", @@ -403,23 +387,23 @@ do_size_check(Config) -> "SNMPv2-TM"], ?IPRINT("do_size_check -> load std mibs", []), - ?line load_mibs(MibsPid, StdMibDir, StdMibs), + load_mibs(MibsPid, StdMibDir, StdMibs), ?IPRINT("do_size_check -> load (own) mibs", []), - ?line load_mibs(MibsPid, MibDir, Mibs), + load_mibs(MibsPid, MibDir, Mibs), ?SLEEP(2000), ?IPRINT("do_size_check -> display mem usage", []), - ?line display_memory_usage(MibsPid), + display_memory_usage(MibsPid), ?IPRINT("do_size_check -> unload (own) mibs", []), - ?line unload_mibs(MibsPid, Mibs), + unload_mibs(MibsPid, Mibs), ?IPRINT("do_size_check -> unload std mibs", []), - ?line unload_mibs(MibsPid, StdMibs), + unload_mibs(MibsPid, StdMibs), ?IPRINT("do_size_check -> stop mib server", []), - ?line mibs_stop(MibsPid), + mibs_stop(MibsPid), ?IPRINT("do_size_check -> stop symbolic store", []), - ?line sym_stop(), + sym_stop(), ?IPRINT("do_size_check -> done", []), ok. @@ -427,7 +411,6 @@ do_size_check(Config) -> %% --------------------------------------------------------------------- -me_lookup(suite) -> []; me_lookup(Config) when is_list(Config) -> tc_try(me_lookup, fun() -> do_me_lookup(Config) end). @@ -451,40 +434,39 @@ do_me_lookup(Config) -> "SNMPv2-TM"], ?DBG("me_lookup -> start symbolic store", []), - ?line sym_start(Prio, Verbosity), + sym_start(Prio, Verbosity), ?DBG("me_lookup -> start mib server", []), - ?line MibsPid = mibs_start(Prio, Verbosity), + MibsPid = mibs_start(Prio, Verbosity), ?DBG("me_lookup -> load mibs", []), - ?line load_mibs(MibsPid, MibDir, Mibs), + load_mibs(MibsPid, MibDir, Mibs), ?DBG("me_lookup -> load std mibs", []), - ?line load_mibs(MibsPid, StdMibDir, StdMibs), + load_mibs(MibsPid, StdMibDir, StdMibs), ?DBG("me_lookup -> find ~w from SNMP-COMMUNITY-MIB", [?snmpTrapCommunity_instance]), - ?line ok = me_lookup(MibsPid, ?snmpTrapCommunity_instance), + ok = me_lookup(MibsPid, ?snmpTrapCommunity_instance), ?DBG("me_lookup -> find ~w from SNMP-VIEW-BASED-ACM-MIB", [?vacmViewSpinLock_instance]), - ?line ok = me_lookup(MibsPid, ?vacmViewSpinLock_instance), + ok = me_lookup(MibsPid, ?vacmViewSpinLock_instance), ?DBG("me_lookup -> find ~w from SNMP-USER-BASED-SM-MIB", [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = me_lookup(MibsPid, ?usmStatsNotInTimeWindows_instance), + {error, _} = me_lookup(MibsPid, ?usmStatsNotInTimeWindows_instance), ?DBG("me_lookup -> stop mib server", []), - ?line mibs_stop(MibsPid), + mibs_stop(MibsPid), ?DBG("me_lookup -> stop symbolic store", []), - ?line sym_stop(), + sym_stop(), ok. %% --------------------------------------------------------------------- -which_mib(suite) -> []; which_mib(Config) when is_list(Config) -> tc_try(which_mib, fun() -> do_which_mib(Config) end). @@ -508,43 +490,42 @@ do_which_mib(Config) -> "SNMPv2-TM"], ?DBG("which_mib -> start symbolic store", []), - ?line sym_start(Prio, Verbosity), + sym_start(Prio, Verbosity), ?DBG("which_mib -> start mib server", []), - ?line MibsPid = mibs_start(Prio, Verbosity), + MibsPid = mibs_start(Prio, Verbosity), ?DBG("which_mib -> load mibs", []), - ?line load_mibs(MibsPid, MibDir, Mibs), + load_mibs(MibsPid, MibDir, Mibs), ?DBG("which_mib -> load std mibs", []), - ?line load_mibs(MibsPid, StdMibDir, StdMibs), + load_mibs(MibsPid, StdMibDir, StdMibs), ?DBG("which_mib -> find ~w from SNMP-COMMUNITY-MIB", [?snmpTrapCommunity_instance]), - ?line ok = which_mib(MibsPid, ?snmpTrapCommunity_instance, + ok = which_mib(MibsPid, ?snmpTrapCommunity_instance, "SNMP-COMMUNITY-MIB"), ?DBG("which_mib -> find ~w from SNMP-VIEW-BASED-ACM-MIB", [?vacmViewSpinLock_instance]), - ?line ok = which_mib(MibsPid, ?vacmViewSpinLock_instance, + ok = which_mib(MibsPid, ?vacmViewSpinLock_instance, "SNMP-VIEW-BASED-ACM-MIB"), ?DBG("which_mib -> find ~w from SNMP-USER-BASED-SM-MIB (not loaded)", [?usmStatsNotInTimeWindows_instance]), - ?line {error, _} = which_mib(MibsPid, ?usmStatsNotInTimeWindows_instance, + {error, _} = which_mib(MibsPid, ?usmStatsNotInTimeWindows_instance, "SNMP-USER-BASED-SM-MIB"), ?DBG("which_mib -> stop mib server", []), - ?line mibs_stop(MibsPid), + mibs_stop(MibsPid), ?DBG("which_mib -> stop symbolic store", []), - ?line sym_stop(), + sym_stop(), ok. %% --------------------------------------------------------------------- -cache_test(suite) -> []; cache_test(Config) when is_list(Config) -> tc_try(cache_test, fun() -> do_cache_test(Config) end). @@ -571,7 +552,7 @@ do_cache_test(Config) -> "SNMPv2-TM"], ?IPRINT("cache_test -> start symbolic store"), - ?line sym_start(Prio, MibStorage, silence), % Verbosity), + sym_start(Prio, MibStorage, silence), % Verbosity), ?IPRINT("cache_test -> start mib server"), GcLimit = 3, @@ -580,25 +561,25 @@ do_cache_test(Config) -> {age, Age}, {gclimit, GcLimit}, {gcverbose, true}], - ?line MibsPid = mibs_start(Prio, MibStorage, [], Verbosity, CacheOpts), + MibsPid = mibs_start(Prio, MibStorage, [], Verbosity, CacheOpts), ?NPRINT("Info before load mibs: " "~n ~p", [snmpa_mib:info(MibsPid)]), ?IPRINT("cache_test -> load mibs"), - ?line load_mibs(MibsPid, MibDir, Mibs), + load_mibs(MibsPid, MibDir, Mibs), ?NPRINT("Info before load std mibs: " "~n ~p", [snmpa_mib:info(MibsPid)]), ?IPRINT("cache_test -> load std mibs"), - ?line load_mibs(MibsPid, StdMibDir, StdMibs), + load_mibs(MibsPid, StdMibDir, StdMibs), ?NPRINT("Info (after mibs load but) before populate: " "~n ~p", [snmpa_mib:info(MibsPid)]), ?IPRINT("cache_test -> populate the cache"), - ?line ok = populate(MibsPid), + ok = populate(MibsPid), ?NPRINT("Info after populate: " "~n ~p", [snmpa_mib:info(MibsPid)]), @@ -625,10 +606,10 @@ do_cache_test(Config) -> ?IPRINT("cache_test -> subscribe to GC events"), - ?line ok = snmpa_mib:subscribe_gc_events(MibsPid), + ok = snmpa_mib:subscribe_gc_events(MibsPid), ?IPRINT("cache_test -> enable cache autogc"), - ?line ok = snmpa_mib:enable_cache_autogc(MibsPid), + ok = snmpa_mib:enable_cache_autogc(MibsPid), ?IPRINT("cache_test -> wait 65 seconds to allow gc to happen"), ?SLEEP(timer:seconds(65)), @@ -738,10 +719,10 @@ do_cache_test(Config) -> ?IPRINT("cache_test -> stop mib server"), - ?line mibs_stop(MibsPid), + mibs_stop(MibsPid), ?IPRINT("cache_test -> stop symbolic store"), - ?line sym_stop(), + sym_stop(), ?IPRINT("cache_test -> end"), ok. @@ -873,13 +854,13 @@ mnesia_start(Opts) -> mnesia_start(Opts, [node()]). mnesia_start(Opts, Nodes) -> - %% We can accept mnesia beeing loaded but *not* started. + %% We can accept mnesia being loaded but *not* started. %% If its started it *may* contain data that will invalidate %% this test case. ?IPRINT("mnesia_start -> try load mnesia when:" "~n Loaded: ~p" "~n Running: ~p", [apps_loaded(), apps_running()]), - ?line ok = case application:load(mnesia) of + ok = case application:load(mnesia) of ok -> ok; {error, {already_loaded, mnesia}} -> @@ -890,11 +871,11 @@ mnesia_start(Opts, Nodes) -> F = fun({Key, Val}) -> ?IPRINT("mnesia_start -> try set mnesia env: " "~n ~p -> ~p", [Key, Val]), - ?line application_controller:set_env(mnesia, Key, Val) + application_controller:set_env(mnesia, Key, Val) end, lists:foreach(F, Opts), ?IPRINT("mnesia_start -> create mnesia schema on ~p", [Nodes]), - ?line case mnesia:create_schema(Nodes) of + case mnesia:create_schema(Nodes) of ok -> ok; {error, {_, {already_exist, _}}} -> @@ -904,7 +885,7 @@ mnesia_start(Opts, Nodes) -> ?F("Failed create mnesia schema: ~p", [SchemaReason])}) end, ?IPRINT("mnesia_start -> start mnesia", []), - ?line case application:start(mnesia) of + case application:start(mnesia) of ok -> ok; {error, {already_started, mnesia}} -> @@ -988,13 +969,13 @@ mibs_info(Pid) -> load_mibs(Pid, Dir, Mibs0) -> Mibs = [join(Dir, Mib) || Mib <- Mibs0], - Res = snmpa_mib:load_mibs(Pid, Mibs), + Res = snmpa_mib:load_mibs(Pid, Mibs, false), %% ?DBG("load_mibs -> " %% "~n Res: ~p", [Res]), Res. unload_mibs(Pid, Mibs) -> - Res = snmpa_mib:unload_mibs(Pid, Mibs), + Res = snmpa_mib:unload_mibs(Pid, Mibs, false), %% ?DBG("unload_mibs -> " %% "~n Res: ~p", [Res]), Res. @@ -1093,11 +1074,11 @@ tc_try(Name, TC) -> tc_try(Name, Init, TC) when is_atom(Name) andalso is_function(Init, 0) andalso is_function(TC, 0) -> Pre = fun() -> - {ok, Node} = ?ALIB:start_node(unique(Name)), + {ok, Peer, Node} = ?START_PEER(atom_to_list(Name)), ok = run_on(Node, Init), - Node + {Peer, Node} end, - Case = fun(Node) -> + Case = fun({_Peer, Node}) -> monitor_node(Node, true), Pid = spawn_link(Node, TC), receive @@ -1125,7 +1106,7 @@ tc_try(Name, Init, TC) exit(Reason) end end, - Post = fun(Node) -> + Post = fun({Peer, Node}) -> receive {nodedown, Node} -> ?NPRINT("node ~p (already) stopped", [Node]), @@ -1133,7 +1114,7 @@ tc_try(Name, Init, TC) after 0 -> monitor_node(Node, true), ?NPRINT("try stop node ~p", [Node]), - ?STOP_NODE(Node), + peer:stop(Peer), receive {nodedown, Node} -> ?NPRINT("node ~p stopped", [Node]), @@ -1156,9 +1137,6 @@ run_on(Node, F) when is_atom(Node) andalso is_function(F, 0) -> monitor_node(Node, false), Reason end. - -unique(PreName) -> - list_to_atom(?F("~w_~w", [PreName, erlang:system_time(millisecond)])). %% -- diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 199296593f7e..3877123b370b 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -33,8 +33,6 @@ start_subagent/3, stop_subagent/1, start_sub_sup/1, start_sub_sup/2, - start_node/1, stop_node/1, - load_master/1, load_master_std/1, unload_master/1, loaded_mibs/0, unload_mibs/1, @@ -131,11 +129,16 @@ init_all(Config) when is_list(Config) -> %% ?IPRINT("init_all -> start sub-agent node"), - ?line {ok, SaNode} = start_node(snmp_sa), + Args = ["-s", "snmp_test_sys_monitor", "start", "-s", "global", "sync"], + + {ok, SaPeer, SaNode} = ?CT_PEER(#{name => ?CT_PEER_NAME(snmp_sa), args => Args}), + unlink(SaPeer), %% must unlink, otherwise peer will exit before test case ?IPRINT("init_all -> start manager node"), - ?line {ok, MgrNode} = start_node(snmp_mgr), + {ok, MgrPeer, MgrNode} = ?CT_PEER(#{name => ?CT_PEER_NAME(snmp_mgr), args => Args}), + unlink(MgrPeer), %% must unlink, otherwise peer will exit before test case + global:sync(), %% -- %% Create necessary files ( and dirs ) @@ -147,37 +150,37 @@ init_all(Config) when is_list(Config) -> ?IPRINT("init_all -> create agent dir"), AgentDir = join(GroupTopDir, "agent/"), - ?line ok = file:make_dir(AgentDir), + ok = file:make_dir(AgentDir), ?DBG("init_all -> AgentDir ~p", [AgentDir]), ?IPRINT("init_all -> create agent db dir"), AgentDbDir = join(AgentDir, "db/"), - ?line ok = file:make_dir(AgentDbDir), + ok = file:make_dir(AgentDbDir), ?DBG("init_all -> AgentDbDir ~p", [AgentDbDir]), ?IPRINT("init_all -> create agent log dir"), AgentLogDir = join(AgentDir, "log/"), - ?line ok = file:make_dir(AgentLogDir), + ok = file:make_dir(AgentLogDir), ?DBG("init_all -> AgentLogDir ~p", [AgentLogDir]), ?IPRINT("init_all -> create agent config dir"), AgentConfDir = join(AgentDir, "conf/"), - ?line ok = file:make_dir(AgentConfDir), + ok = file:make_dir(AgentConfDir), ?DBG("init_all -> AgentConfDir ~p", [AgentConfDir]), ?IPRINT("init_all -> create manager dir"), MgrDir = join(GroupTopDir, "mgr/"), - ?line ok = file:make_dir(MgrDir), + ok = file:make_dir(MgrDir), ?DBG("init_all -> MgrDir ~p", [MgrDir]), ?IPRINT("init_all -> create sub-agent dir"), SaDir = join(GroupTopDir, "sa/"), - ?line ok = file:make_dir(SaDir), + ok = file:make_dir(SaDir), ?DBG("init_all -> SaDir ~p", [SaDir]), ?IPRINT("init_all -> create sub-agent db dir"), SaDbDir = join(SaDir, "db/"), - ?line ok = file:make_dir(SaDbDir), + ok = file:make_dir(SaDbDir), ?DBG("init_all -> SaDbDir ~p", [SaDbDir]), %% MibDir = ?config(mib_dir, Config), @@ -189,35 +192,37 @@ init_all(Config) when is_list(Config) -> %% ?IPRINT("init_all -> load mnesia application (local)"), - ?line ok = application:load(mnesia), + ok = application:load(mnesia), ?IPRINT("init_all -> load application mnesia on node ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, load, [mnesia]), + ok = rpc:call(SaNode, application, load, [mnesia]), ?IPRINT("init_all -> application mnesia (local): set_env dir"), - ?line application_controller:set_env(mnesia, dir, + application_controller:set_env(mnesia, dir, join(AgentDbDir, "Mnesia1")), ?IPRINT("init_all -> application mnesia: set_env dir on node ~p", [SaNode]), - ?line rpc:call(SaNode, application_controller, set_env, + rpc:call(SaNode, application_controller, set_env, [mnesia, dir, join(SaDir, "Mnesia2")]), ?IPRINT("init_all -> create mnesia schema"), - ?line ok = mnesia:create_schema([SaNode, node()]), + ok = mnesia:create_schema([SaNode, node()]), ?IPRINT("init_all -> start application mnesia (local)"), - ?line ok = application:start(mnesia), + ok = application:start(mnesia), ?IPRINT("init_all -> start application mnesia on ~p", [SaNode]), - ?line ok = rpc:call(SaNode, application, start, [mnesia]), + ok = rpc:call(SaNode, application, start, [mnesia]), ?IPRINT("init_all -> get localhost"), Ip = ?LOCALHOST(), ?IPRINT("init_all -> done when" "~n Nodes: ~p", [nodes()]), - [{snmp_sa, SaNode}, - {snmp_mgr, MgrNode}, + [{snmp_sa, SaNode}, + {snmp_sa_peer, SaPeer}, + {snmp_mgr, MgrNode}, + {snmp_mgr_peer, MgrPeer}, {snmp_master, node()}, {agent_dir, AgentDir ++ "/"}, {agent_db_dir, AgentDbDir ++ "/"}, @@ -237,14 +242,12 @@ finish_all(Config) when is_list(Config) -> "~n Config: ~p" "~n Nodes: ~p", [Config, nodes()]), - SaNode = ?config(snmp_sa, Config), - MgrNode = ?config(snmp_mgr, Config), + SaPeer = ?config(snmp_sa_peer, Config), + MgrPeer = ?config(snmp_mgr_peer, Config), - ?IPRINT("finish_all -> stop sub-agent node ~p", [SaNode]), - stop_node(SaNode), + peer:stop(SaPeer), - ?IPRINT("finish_all -> stop manager node ~p", [MgrNode]), - stop_node(MgrNode), + peer:stop(MgrPeer), ?IPRINT("finish_all -> stop mnesia application"), application:stop(mnesia), @@ -296,6 +299,8 @@ init_case(Config) when is_list(Config) -> put(masterip, tuple_to_list(MasterIP)), put(sip, tuple_to_list(SIP)), put(ipfamily, IpFamily), + + put(receive_response_timeout, receive_response_timeout(Config)), MibDir = ?config(mib_dir, Config), put(mib_dir, MibDir), @@ -316,6 +321,20 @@ init_case(Config) when is_list(Config) -> {SaNode, MgrNode, MibDir}. +receive_response_timeout(Config) -> + case lists:keysearch(snmp_factor, 1, Config) of + {value, {snmp_factor, F}} when (F < 4) -> + ?SECS(5); + {value, {snmp_factor, F}} when (F < 6) -> + ?SECS(10); + {value, {snmp_factor, F}} when (F < 8) -> + ?SECS(15); + {value, {snmp_factor, _}} -> + ?SECS(20); + _ -> + ?SECS(10) + end. + %%%-------------------------------------------------- %%% Used to test the standard mib with our %%% configuration. @@ -579,13 +598,13 @@ tc_run(Mod, Func, Args, Opts) -> ?EPRINT("Failed starting (test) manager: " "~n ~p", [Reason]), (catch snmp_test_mgr:stop()), - ?line ?FAIL({mgr_start_error, Reason}); + ?FAIL({mgr_start_error, Reason}); Err -> ?EPRINT("Failed starting (test) manager: " "~n ~p", [Err]), (catch snmp_test_mgr:stop()), - ?line ?FAIL({mgr_start_failure, Err}) + ?FAIL({mgr_start_failure, Err}) end. %% We have some crap machines that generate this every now and then @@ -597,7 +616,7 @@ tc_run_skip_check(_Mod, _Func, _Args, ?SKIP([{reason, Reason}]); %% We have hosts (mostly *very* slooow VMs) that %% can timeout anything. Since we are basically -%% testing communication, we therefor must check +%% testing communication, we therefore must check %% for system events at every failure. Grrr! tc_run_skip_check(Mod, Func, Args, Reason, Cat) -> SysEvs = snmp_test_global_sys_monitor:events(), @@ -608,7 +627,7 @@ tc_run_skip_check(Mod, Func, Args, Reason, Cat) -> "~n ~p~n", [Cat, Reason]), ?FAIL({apply_failed, {Mod, Func, Args}, Reason}); true -> - ?WPRINT("apply (~w) catched " + ?WPRINT("apply (~w) caught " "when we got system events: " "~n Reason: ~p" "~n Sys Events: ~p" @@ -670,11 +689,11 @@ start_agent(Config, Vsns, Opts) -> "~n Vsns: ~p" "~n Opts: ~p", [node(), Config, Vsns, Opts]), - ?line AgentLogDir = ?config(agent_log_dir, Config), - ?line AgentConfDir = ?config(agent_conf_dir, Config), - ?line AgentDbDir = ?config(agent_db_dir, Config), - ?line SaNode = ?config(snmp_sa, Config), - ?line InetBackend = ?config(socket_create_opts, Config), + AgentLogDir = ?config(agent_log_dir, Config), + AgentConfDir = ?config(agent_conf_dir, Config), + AgentDbDir = ?config(agent_db_dir, Config), + SaNode = ?config(snmp_sa, Config), + InetBackend = ?config(socket_create_opts, Config), Env = app_agent_env_init( [{versions, Vsns}, @@ -706,26 +725,26 @@ start_agent(Config, Vsns, Opts) -> ?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]), ?IPRINT("start_agent -> try start master agent",[]), - ?line Sup = start_sup(Env), - ?line unlink(Sup), + Sup = start_sup(Env), + unlink(Sup), ?DBG("start_agent -> snmp supervisor: ~p", [Sup]), ?IPRINT("start_agent -> try (rpc) start sub agent on ~p", [SaNode]), - ?line SaDir = ?config(sa_dir, Config), - ?line {ok, Sub} = start_sub_sup(SaNode, SaDir), + SaDir = ?config(sa_dir, Config), + {ok, Sub} = start_sub_sup(SaNode, SaDir), ?DBG("start_agent -> done", []), - ?line [{snmp_app_sup, AppSup}, + [{snmp_app_sup, AppSup}, {snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config]. app_agent_env_init(Env0, Opts) -> ?DBG("app_agent_env_init -> unload snmp",[]), - ?line application:unload(snmp), + application:unload(snmp), ?DBG("app_agent_env_init -> load snmp",[]), - ?line application:load(snmp), + application:load(snmp), ?DBG("app_agent_env_init -> " "merge or maybe replace (snmp agent) app env",[]), @@ -1306,7 +1325,7 @@ do_expect(Err, Idx, ExpVBs, To) when is_atom(Err) andalso (is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) -> Check = fun(_, R) -> R end, - io_format_expect("'get-response' withing ~w ms with" + io_format_expect("'get-response' within ~w ms with" "~n Error: ~p" "~n Index: ~p" "~n Varbinds: ~p", [To, Err, Idx, ExpVBs]), @@ -1639,41 +1658,6 @@ get_next_req(Vars) -> Response. -%% --- start and stop nodes --- - -start_node(Name) -> - ?IPRINT("start_node -> entry with" - "~n Name: ~p" - "~n when" - "~n hostname of this node: ~p", - [Name, list_to_atom(?HOSTNAME(node()))]), - - Pa = filename:dirname(code:which(?MODULE)), - ?DBG("start_node -> Pa: ~p", [Pa]), - - A = " -pa " ++ Pa ++ - " -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++ - " -s global sync", - case ?START_NODE(Name, A) of - {ok, Node} -> - ?DBG("start_node -> Node: ~p", [Node]), - global:sync(), - {ok, Node}; - {error, Reason} -> - ?WPRINT("start_node -> failed starting node ~p:" - "~n Reason: ~p", [Name, Reason]), - ?line ?SKIP({failed_start_node, Reason}); - Else -> - ?EPRINT("start_node -> failed starting node ~p:" - "~n ~p", [Name, Else]), - ?line ?FAIL(Else) - end. - - -stop_node(Node) -> - ?IPRINT("stop_node -> Node: ~p", [Node]), - ?STOP_NODE(Node). - %%%----------------------------------------------------------------- %%% Configuration @@ -1691,13 +1675,13 @@ config(Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily) -> "~n AIp: ~p" "~n IpFamily: ~p", [Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily]), - ?line {Domain, ManagerAddr} = + {Domain, ManagerAddr} = case IpFamily of inet6 -> TransportDomain6 = transportDomainUdpIpv6, AgentAddr6 = {AIp, 4000}, ManagerAddr6 = {MIp, ?TRAP_UDP}, - ?line ok = + ok = snmp_config:write_agent_snmp_files( AgentConfDir, Vsns, TransportDomain6, ManagerAddr6, AgentAddr6, "test"), @@ -1710,32 +1694,32 @@ config(Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily) -> %% [#{addr => {AIp2, 4000}, kind => req_responder}, %% #{addr => {AIp2, 4001}, kind => trap_sender}], AgentPreTransport = [#{addr => {AIp2, 4000}}], - ?line ok = + ok = snmp_config:write_agent_snmp_files( AgentConfDir, Vsns, TransportDomain4, ManagerAddr4, AgentPreTransport, "test"), {TransportDomain4, ManagerAddr4}; _ -> - ?line ok = + ok = snmp_config:write_agent_snmp_files( AgentConfDir, Vsns, MIp, ?TRAP_UDP, AIp, 4000, "test"), {snmpUDPDomain, {MIp, ?TRAP_UDP}} end, - ?line case update_usm(Vsns, AgentConfDir) of + case update_usm(Vsns, AgentConfDir) of true -> - ?line copy_file(join(AgentConfDir, "usm.conf"), + copy_file(join(AgentConfDir, "usm.conf"), join(MgrDir, "usm.conf")), - ?line update_usm_mgr(Vsns, MgrDir); + update_usm_mgr(Vsns, MgrDir); false -> - ?line ok + ok end, - ?line update_community(Vsns, AgentConfDir), - ?line update_vacm(Vsns, AgentConfDir), - ?line write_target_addr_conf(AgentConfDir, Domain, ManagerAddr, Vsns), - ?line write_target_params_conf(AgentConfDir, Vsns), - ?line write_notify_conf(AgentConfDir), + update_community(Vsns, AgentConfDir), + update_vacm(Vsns, AgentConfDir), + write_target_addr_conf(AgentConfDir, Domain, ManagerAddr, Vsns), + write_target_params_conf(AgentConfDir, Vsns), + write_notify_conf(AgentConfDir), ok. maybe_fix_addr(Addr) when is_list(Addr) -> @@ -1843,7 +1827,7 @@ update_usm(Vsns, Dir) -> usmHMACSHAAuthProtocol, "", "", usmDESPrivProtocol, "", "", "", "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}], - ?line ok = snmp_config:update_agent_usm_config(Dir, Conf), + ok = snmp_config:update_agent_usm_config(Dir, Conf), true; false -> false @@ -1862,14 +1846,14 @@ update_usm_mgr(Vsns, Dir) -> usmDESPrivProtocol, "", "", "", "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}], - ?line ok = snmp_config:update_agent_usm_config(Dir, Conf), + ok = snmp_config:update_agent_usm_config(Dir, Conf), true; false -> false end. rewrite_usm_mgr(Dir, ShaKey, DesKey) -> - ?line ok = file:rename(join(Dir,"usm.conf"), + ok = file:rename(join(Dir,"usm.conf"), join(Dir,"usm.old")), Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero, usmHMACSHAAuthProtocol, "", "", @@ -1877,10 +1861,10 @@ rewrite_usm_mgr(Dir, ShaKey, DesKey) -> {"mgrEngine", "newUser", "newUser", zeroDotZero, usmHMACSHAAuthProtocol, "", "", usmDESPrivProtocol, "", "", "", ShaKey, DesKey}], - ?line ok = snmp_config:write_agent_usm_config(Dir, "", Conf). + ok = snmp_config:write_agent_usm_config(Dir, "", Conf). reset_usm_mgr(Dir) -> - ?line ok = file:rename(join(Dir,"usm.old"), + ok = file:rename(join(Dir,"usm.old"), join(Dir,"usm.conf")). @@ -1888,7 +1872,7 @@ update_community([v3], _Dir) -> ok; update_community(_, Dir) -> Conf = [{"no-rights", "no-rights", "no-rights", "", ""}], - ?line ok = snmp_config:update_agent_community_config(Dir, Conf). + ok = snmp_config:update_agent_community_config(Dir, Conf). -define(tDescr_instance, [1,3,6,1,2,1,16,1,0]). @@ -1903,17 +1887,17 @@ update_vacm(_Vsn, Dir) -> {vacmSecurityToGroup, usm, "newUser", "initial"}, {vacmViewTreeFamily, "internet", ?tDescr_instance, excluded, null}], - ?line ok = snmp_config:update_agent_vacm_config(Dir, Conf). + ok = snmp_config:update_agent_vacm_config(Dir, Conf). write_community_conf(Dir, Conf) -> - ?line ok = snmp_config:write_agent_community_config(Dir, "", Conf). + ok = snmp_config:write_agent_community_config(Dir, "", Conf). write_target_addr_conf(Dir, Conf) -> - ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", Conf). + ok = snmp_config:write_agent_target_addr_config(Dir, "", Conf). write_target_addr_conf(Dir, Ip_or_Domain, Port_or_Addr, Vsns) -> - ?line ok = + ok = snmp_config:write_agent_snmp_target_addr_conf( Dir, Ip_or_Domain, Port_or_Addr, Vsns). @@ -1930,7 +1914,7 @@ rewrite_target_addr_conf(Dir, NewPort) -> ok end, - ?line [TrapAddr|Addrs] = + [TrapAddr|Addrs] = snmp_conf:read(TAFile, fun rewrite_target_addr_conf_check/1), ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]), @@ -1939,10 +1923,10 @@ rewrite_target_addr_conf(Dir, NewPort) -> ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]), - ?line ok = file:rename(join(Dir,"target_addr.conf"), + ok = file:rename(join(Dir,"target_addr.conf"), join(Dir,"target_addr.old")), - ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", NewAddrs). + ok = snmp_config:write_agent_target_addr_config(Dir, "", NewAddrs). rewrite_target_addr_conf_check(O) -> {ok,O}. @@ -1958,7 +1942,7 @@ rewrite_target_addr_conf2(_NewPort,O) -> O. reset_target_addr_conf(Dir) -> - ?line ok = file:rename(join(Dir, "target_addr.old"), + ok = file:rename(join(Dir, "target_addr.old"), join(Dir, "target_addr.conf")). write_target_params_conf(Dir, Vsns) -> @@ -1967,28 +1951,28 @@ write_target_params_conf(Dir, Vsns) -> (v3) -> {"target_v3", v3, usm, "all-rights", noAuthNoPriv} end, Conf = [F(Vsn) || Vsn <- Vsns], - ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). + ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). rewrite_target_params_conf(Dir, SecName, SecLevel) when is_list(SecName) andalso is_atom(SecLevel) -> - ?line ok = file:rename(join(Dir,"target_params.conf"), + ok = file:rename(join(Dir,"target_params.conf"), join(Dir,"target_params.old")), Conf = [{"target_v3", v3, usm, SecName, SecLevel}], - ?line ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). + ok = snmp_config:write_agent_target_params_config(Dir, "", Conf). reset_target_params_conf(Dir) -> - ?line ok = file:rename(join(Dir,"target_params.old"), + ok = file:rename(join(Dir,"target_params.old"), join(Dir,"target_params.conf")). write_notify_conf(Dir) -> Conf = [{"standard trap", "std_trap", trap}, {"standard inform", "std_inform", inform}], - ?line ok = snmp_config:write_agent_notify_config(Dir, "", Conf). + ok = snmp_config:write_agent_notify_config(Dir, "", Conf). write_view_conf(Dir) -> Conf = [{2, [1,3,6], included, null}, {2, ?tDescr_instance, excluded, null}], - ?line ok = snmp_config:write_agent_view_config(Dir, "", Conf). + ok = snmp_config:write_agent_view_config(Dir, "", Conf). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/snmp/test/snmp_compiler_SUITE.erl b/lib/snmp/test/snmp_compiler_SUITE.erl index f4ba914919b4..9cc47397a828 100644 --- a/lib/snmp/test/snmp_compiler_SUITE.erl +++ b/lib/snmp/test/snmp_compiler_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2020. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -197,14 +197,14 @@ description(Config) when is_list(Config) -> Desctext = "This is a test description", Oid = [1,3,6,1,2,1,15,1], write_mib(MibSrcName,Desctext), - ?line {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir}, + {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir}, {group_check, false}, {warnings, false}, {description, false}]), MIB1 = read_mib(MibBinName), %% ?IPRINT("description -> MIB1: ~n~p~n", [MIB1]), check_mib(MIB1#mib.mes, Oid, undefined), - ?line {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir}, + {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir}, {group_check, false}, {warnings, false}, {description, true}]), @@ -228,8 +228,8 @@ oid_conflicts(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), Mib = join(Dir,"TESTv2.mib"), - ?line ok = write_oid_conflict_mib(Mib), - ?line {error,compilation_failed} = + ok = write_oid_conflict_mib(Mib), + {error,compilation_failed} = snmpc:compile(Mib,[{outdir, Dir},{verbosity,trace}]), ok. @@ -263,21 +263,21 @@ agent_capabilities(Config) when is_list(Config) -> SnmpMibsDir = join(SnmpPrivDir, "mibs"), Dir = ?config(mib_dir, Config), AcMib = join(Dir,"AC-TEST-MIB.mib"), - ?line {ok, MibFile1} = snmpc:compile(AcMib, [options, + {ok, MibFile1} = snmpc:compile(AcMib, [options, version, {i, [SnmpMibsDir]}, {outdir, Dir}, {verbosity, trace}]), - ?line {ok, Mib1} = snmp_misc:read_mib(MibFile1), - ?line {ok, MibFile2} = snmpc:compile(AcMib, [options, + {ok, Mib1} = snmp_misc:read_mib(MibFile1), + {ok, MibFile2} = snmpc:compile(AcMib, [options, version, agent_capabilities, {i, [SnmpMibsDir]}, {outdir, Dir}, {verbosity, trace}]), - ?line {ok, Mib2} = snmp_misc:read_mib(MibFile2), + {ok, Mib2} = snmp_misc:read_mib(MibFile2), MEDiff = Mib2#mib.mes -- Mib1#mib.mes, - %% This is a rather pathetic test, but it is somthing... + %% This is a rather pathetic test, but it is something... ?IPRINT("agent_capabilities -> " "~n MEDiff: ~p" "~n Mib1: ~p" @@ -304,21 +304,21 @@ module_compliance(Config) when is_list(Config) -> SnmpMibsDir = join(SnmpPrivDir, "mibs"), Dir = ?config(mib_dir, Config), AcMib = join(Dir,"MC-TEST-MIB.mib"), - ?line {ok, MibFile1} = snmpc:compile(AcMib, [options, + {ok, MibFile1} = snmpc:compile(AcMib, [options, version, {i, [SnmpMibsDir]}, {outdir, Dir}, {verbosity, trace}]), - ?line {ok, Mib1} = snmp_misc:read_mib(MibFile1), - ?line {ok, MibFile2} = snmpc:compile(AcMib, [options, + {ok, Mib1} = snmp_misc:read_mib(MibFile1), + {ok, MibFile2} = snmpc:compile(AcMib, [options, version, module_compliance, {i, [SnmpMibsDir]}, {outdir, Dir}, {verbosity, trace}]), - ?line {ok, Mib2} = snmp_misc:read_mib(MibFile2), + {ok, Mib2} = snmp_misc:read_mib(MibFile2), MEDiff = Mib2#mib.mes -- Mib1#mib.mes, - %% This is a rather pathetic test, but it is somthing... + %% This is a rather pathetic test, but it is something... ?IPRINT("module_compliance -> " "~n MEDiff: ~p" "~n Mib1: ~p" @@ -369,7 +369,7 @@ otp_6150(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "ERICSSON-TOP-MIB.mib"), - ?line {ok, Mib} = + {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]), ?IPRINT("otp_6150 -> Mib: " "~n ~p", [Mib]), @@ -422,7 +422,7 @@ otp_8595(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "OTP8595-MIB.mib"), - ?line {ok, Mib} = + {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}, {group_check, false}]), @@ -442,7 +442,7 @@ otp_10799(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "OTP10799-MIB.mib"), - ?line {ok, Mib} = + {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]), ?IPRINT("Mib: " "~n ~p", [Mib]), @@ -461,7 +461,7 @@ otp_10808(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "OTP10808-MIB.mib"), - ?line {ok, Mib} = + {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}, {group_check, false}]), @@ -483,7 +483,7 @@ otp_14145(Config) when is_list(Config) -> MibDir = ?config(mib_dir, Config), MibName = "OTP14145-MIB", MibFile = join(MibDir, MibName++".mib"), - ?line {ok, MibBin} = + {ok, MibBin} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}, {group_check, false}, @@ -509,7 +509,7 @@ otp_13014(Config) when is_list(Config) -> MibDir = ?config(mib_dir, Config), MibName = "Test-LLDP-MIB", MibFile = join(MibDir, MibName++".mib"), - ?line {ok, MibBin} = + {ok, MibBin} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, log}, {group_check, false}, @@ -544,7 +544,7 @@ otp_14196(Config) when is_list(Config) -> Dir = ?config(case_top_dir, Config), MibDir = ?config(mib_dir, Config), MibFile = join(MibDir, "OTP14196-MIB.mib"), - ?line {ok, Mib} = + {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]), ?IPRINT("Mib: " "~n ~p", [Mib]), @@ -564,13 +564,13 @@ augments_extra_info(Config) when is_list(Config) -> MibDir = ?config(mib_dir, Config), Test2File = join(MibDir, "Test2.mib"), Test3File = join(MibDir, "Test3.mib"), - ?line {ok, Test2BinFile} = + {ok, Test2BinFile} = snmpc:compile(Test2File, [{outdir, Dir}, {verbosity, silence}, {group_check, false}]), ?IPRINT("Test2BinFile: " "~n ~p", [Test2BinFile]), - ?line {ok, Test3BinFile} = + {ok, Test3BinFile} = snmpc:compile(Test3File, [{i, [MibDir]}, {outdir, Dir}, {verbosity, silence}, diff --git a/lib/snmp/test/snmp_conf_SUITE.erl b/lib/snmp/test/snmp_conf_SUITE.erl index 698cf2d6f35a..ae5cbc9c5a79 100644 --- a/lib/snmp/test/snmp_conf_SUITE.erl +++ b/lib/snmp/test/snmp_conf_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2020. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -181,7 +181,7 @@ init_per_testcase(fd_leak_check = _Case, Config) when is_list(Config) -> %% Something strange happens when we use pfiles from within erlang, %% so skip the test for now - %% For some reason even though 'which' exists (atleast in + %% For some reason even though 'which' exists (at least in %% a tcsh shell), it hangs when called via os:cmd/1. %% And type produces results that is not so easy to %% "analyze". So, we 'try it' and know that it starts @@ -239,14 +239,14 @@ check_mandatory(Config) when is_list(Config) -> {b, mandatory}, {d, {value, 20202}}, {e, {value, "kalle"}}], - ?line {ok, _L1} = verify_mandatory(A1, B1), + {ok, _L1} = verify_mandatory(A1, B1), ?DBG("check_mandatory -> L1: ~p", [L1]), A2 = [{a, hej}, {c, 10}, {d, 10101}, {f, 10.88}], B2 = [{a, {value, hejsan}}, {b, mandatory}, {d, {value, 20202}}, {e, {value, "kalle"}}], - ?line ok = verify_not_mandatory(A2, B2), + ok = verify_not_mandatory(A2, B2), ok. verify_mandatory(A, B) -> @@ -283,16 +283,16 @@ verify_not_mandatory(A, B) -> check_integer1(suite) -> []; check_integer1(Config) when is_list(Config) -> ?P(check_integer1), - ?line ok = verify_int(0), - ?line ok = verify_int(16#FF), - ?line ok = verify_int(16#FFFF), - ?line ok = verify_int(16#FFFFFFFF), - ?line ok = verify_int(-1), - ?line ok = verify_int(-333), + ok = verify_int(0), + ok = verify_int(16#FF), + ok = verify_int(16#FFFF), + ok = verify_int(16#FFFFFFFF), + ok = verify_int(-1), + ok = verify_int(-333), - ?line ok = verify_not_int("kalle & hobbe"), - ?line ok = verify_not_int(kalle_och_hobbe), - ?line ok = verify_not_int(1.5), + ok = verify_not_int("kalle & hobbe"), + ok = verify_not_int(kalle_och_hobbe), + ok = verify_not_int(1.5), ok. @@ -318,49 +318,49 @@ check_integer2(suite) -> []; check_integer2(Config) when is_list(Config) -> ?P(check_integer2), - ?line ok = verify_int(0, any), - ?line ok = verify_int(-22222, any), - ?line ok = verify_int(33333, any), - ?line ok = verify_int(1, pos), - ?line ok = verify_int(9999, pos), - ?line ok = verify_int(-1, neg), - ?line ok = verify_int(-9999, neg), - ?line ok = verify_int(1, {gt, 0}), - ?line ok = verify_int(88888, {gt, -255}), - ?line ok = verify_int(88888, {gte, -255}), - ?line ok = verify_int(88888, {gte, 88888}), - ?line ok = verify_int(88888, {lt, 88889}), - ?line ok = verify_int(88888, {lte, 88888}), - ?line ok = verify_int(88888, {eq, 88888}), - ?line ok = verify_int(88888, {range, 88887,88889}), - - ?line ok = verify_not_int("kalle & hobbe", any), - ?line ok = verify_not_int(kalle_och_hobbe, any), - ?line ok = verify_not_int(1.5, any), - - ?line ok = verify_not_int(0, pos), - ?line ok = verify_not_int(-22222, pos), - ?line ok = verify_not_int(33333, neg), - ?line ok = verify_not_int(0, {gt, 0}), - ?line ok = verify_not_int(33333, {gt, 99999}), - ?line ok = verify_not_int(33333, {gt, 33333}), - ?line ok = verify_not_int(33333, {gte, 33334}), - ?line ok = verify_not_int(33333, {lt, 33333}), - ?line ok = verify_not_int(33333, {lte, 33332}), - ?line ok = verify_not_int(33333, {eq, 33332}), - ?line ok = verify_not_int(33333, {eq, -33333}), - ?line ok = verify_not_int(33333, {range, 33334, 33338}), - ?line ok = verify_not_int(33339, {range, 33334, 33338}), - ?line ok = verify_not_int(33333, {gt, kalle}), - ?line ok = verify_not_int(33333, {gt, 1.55}), - ?line ok = verify_not_int(33333, {gte, "hejsan"}), - ?line ok = verify_not_int(33333, {lt, hobbe}), - ?line ok = verify_not_int(33333, {lte, 1.7666}), - ?line ok = verify_not_int(33333, {eq, 33333.0}), - ?line ok = verify_not_int(33333, {eq, -33333.0}), - ?line ok = verify_not_int(33333, {range, kalle, 33338}), - ?line ok = verify_not_int(33339, {range, 33334, kalle}), - ?line ok = verify_not_int(33339, {kalle, 33334, kalle}), + ok = verify_int(0, any), + ok = verify_int(-22222, any), + ok = verify_int(33333, any), + ok = verify_int(1, pos), + ok = verify_int(9999, pos), + ok = verify_int(-1, neg), + ok = verify_int(-9999, neg), + ok = verify_int(1, {gt, 0}), + ok = verify_int(88888, {gt, -255}), + ok = verify_int(88888, {gte, -255}), + ok = verify_int(88888, {gte, 88888}), + ok = verify_int(88888, {lt, 88889}), + ok = verify_int(88888, {lte, 88888}), + ok = verify_int(88888, {eq, 88888}), + ok = verify_int(88888, {range, 88887,88889}), + + ok = verify_not_int("kalle & hobbe", any), + ok = verify_not_int(kalle_och_hobbe, any), + ok = verify_not_int(1.5, any), + + ok = verify_not_int(0, pos), + ok = verify_not_int(-22222, pos), + ok = verify_not_int(33333, neg), + ok = verify_not_int(0, {gt, 0}), + ok = verify_not_int(33333, {gt, 99999}), + ok = verify_not_int(33333, {gt, 33333}), + ok = verify_not_int(33333, {gte, 33334}), + ok = verify_not_int(33333, {lt, 33333}), + ok = verify_not_int(33333, {lte, 33332}), + ok = verify_not_int(33333, {eq, 33332}), + ok = verify_not_int(33333, {eq, -33333}), + ok = verify_not_int(33333, {range, 33334, 33338}), + ok = verify_not_int(33339, {range, 33334, 33338}), + ok = verify_not_int(33333, {gt, kalle}), + ok = verify_not_int(33333, {gt, 1.55}), + ok = verify_not_int(33333, {gte, "hejsan"}), + ok = verify_not_int(33333, {lt, hobbe}), + ok = verify_not_int(33333, {lte, 1.7666}), + ok = verify_not_int(33333, {eq, 33333.0}), + ok = verify_not_int(33333, {eq, -33333.0}), + ok = verify_not_int(33333, {range, kalle, 33338}), + ok = verify_not_int(33339, {range, 33334, kalle}), + ok = verify_not_int(33339, {kalle, 33334, kalle}), ok. @@ -385,10 +385,10 @@ verify_not_int(Val, Cond) -> check_string1(suite) -> []; check_string1(Config) when is_list(Config) -> ?P(check_string1), - ?line ok = verify_string("kalle & hobbe"), - ?line ok = verify_not_string(kalle_hobbe), - ?line ok = verify_not_string(1000), - ?line ok = verify_not_string(1.0), + ok = verify_string("kalle & hobbe"), + ok = verify_not_string(kalle_hobbe), + ok = verify_not_string(1000), + ok = verify_not_string(1.0), ok. verify_string(Val) -> @@ -414,21 +414,21 @@ check_string2(suite) -> []; check_string2(Config) when is_list(Config) -> ?P(check_string2), Str = "kalle & hobbe", - ?line ok = verify_string(Str, any), - ?line ok = verify_string(Str, {gt, length(Str) - 1}), - ?line ok = verify_string(Str, {gte, length(Str)}), - ?line ok = verify_string(Str, {lt, length(Str) + 1}), - ?line ok = verify_string(Str, {lte, length(Str)}), - ?line ok = verify_string(Str, length(Str)), - - ?line ok = verify_not_string(kalle_hobbe, any), - ?line ok = verify_not_string(1000, any), - ?line ok = verify_not_string(1.0, any), - ?line ok = verify_not_string(Str, {gt, length(Str)}), - ?line ok = verify_not_string(Str, {gte, length(Str) + 1}), - ?line ok = verify_not_string(Str, {lt, length(Str)}), - ?line ok = verify_not_string(Str, {lte, length(Str) - 1}), - ?line ok = verify_not_string(Str, length(Str) + 1), + ok = verify_string(Str, any), + ok = verify_string(Str, {gt, length(Str) - 1}), + ok = verify_string(Str, {gte, length(Str)}), + ok = verify_string(Str, {lt, length(Str) + 1}), + ok = verify_string(Str, {lte, length(Str)}), + ok = verify_string(Str, length(Str)), + + ok = verify_not_string(kalle_hobbe, any), + ok = verify_not_string(1000, any), + ok = verify_not_string(1.0, any), + ok = verify_not_string(Str, {gt, length(Str)}), + ok = verify_not_string(Str, {gte, length(Str) + 1}), + ok = verify_not_string(Str, {lt, length(Str)}), + ok = verify_not_string(Str, {lte, length(Str) - 1}), + ok = verify_not_string(Str, length(Str) + 1), ok. verify_string(Val, Limit) -> @@ -454,10 +454,10 @@ check_atom(suite) -> []; check_atom(Config) when is_list(Config) -> ?P(check_atom), Atoms = [{kalle, "kalle"}, {hobbe, "hobbe"}, {dummy, "dummy"}], - ?line ok = verify_atom(kalle, Atoms), - ?line ok = verify_not_atom(anka, Atoms), - ?line ok = verify_not_atom("kalle", Atoms), - ?line ok = verify_not_atom(1000, Atoms), + ok = verify_atom(kalle, Atoms), + ok = verify_not_atom(anka, Atoms), + ok = verify_not_atom("kalle", Atoms), + ok = verify_not_atom(1000, Atoms), ok. verify_atom(Val, Atoms) -> @@ -482,13 +482,13 @@ verify_not_atom(Val, Atoms) -> check_ip(suite) -> []; check_ip(Config) when is_list(Config) -> ?P(check_ip), - ?line ok = verify_ip([1,2,3,4]), - ?line ok = verify_not_ip([1,2,3]), - ?line ok = verify_not_ip([1,2,3,4,5]), - ?line ok = verify_not_ip(kalle), - ?line ok = verify_not_ip(1000), - ?line ok = verify_not_ip([1,2,3.0,4]), - ?line ok = verify_not_ip([1,two,3,4]), + ok = verify_ip([1,2,3,4]), + ok = verify_not_ip([1,2,3]), + ok = verify_not_ip([1,2,3,4,5]), + ok = verify_not_ip(kalle), + ok = verify_not_ip(1000), + ok = verify_not_ip([1,2,3.0,4]), + ok = verify_not_ip([1,two,3,4]), ok. verify_ip(Val) -> @@ -515,13 +515,13 @@ verify_not_ip(Val) -> check_taddress(suite) -> []; check_taddress(Config) when is_list(Config) -> ?P(check_taddress), - ?line ok = verify_taddress([1,2,3,4,5,6]), - ?line ok = verify_not_taddress([1,2,3,4,5]), - ?line ok = verify_not_taddress([1,2,3,4,5,6,7]), - ?line ok = verify_not_taddress(kalle), - ?line ok = verify_not_taddress(1000), - ?line ok = verify_not_taddress([1,2,3.0,4,5,6]), - ?line ok = verify_not_taddress([1,two,3,4,5,6]), + ok = verify_taddress([1,2,3,4,5,6]), + ok = verify_not_taddress([1,2,3,4,5]), + ok = verify_not_taddress([1,2,3,4,5,6,7]), + ok = verify_not_taddress(kalle), + ok = verify_not_taddress(1000), + ok = verify_not_taddress([1,2,3.0,4,5,6]), + ok = verify_not_taddress([1,two,3,4,5,6]), ok. verify_taddress(Val) -> @@ -548,15 +548,15 @@ check_packet_size(Config) when is_list(Config) -> ?P(check_packet_size), Min = 484, Max = 2147483647, - ?line ok = verify_packet_size(Min), - ?line ok = verify_packet_size(2*Min), - ?line ok = verify_packet_size(Max), - ?line ok = verify_not_packet_size(Min-1), - ?line ok = verify_not_packet_size(Max+1), - ?line ok = verify_not_packet_size(kalle), - ?line ok = verify_not_packet_size("kalle"), - ?line ok = verify_not_packet_size(1.0), - ?line ok = verify_not_packet_size(1.0*Max), + ok = verify_packet_size(Min), + ok = verify_packet_size(2*Min), + ok = verify_packet_size(Max), + ok = verify_not_packet_size(Min-1), + ok = verify_not_packet_size(Max+1), + ok = verify_not_packet_size(kalle), + ok = verify_not_packet_size("kalle"), + ok = verify_not_packet_size(1.0), + ok = verify_not_packet_size(1.0*Max), ok. verify_packet_size(Val) -> @@ -583,14 +583,14 @@ check_oid(Config) when is_list(Config) -> ?P(check_oid), [_,_|Rest] = ?otpSnmpeaModule, ErrOid = [6,16|Rest], - ?line ok = verify_oid(?system), - ?line ok = verify_oid(?sysDescr_instance), - ?line ok = verify_oid(?otpSnmpeaModule), - ?line ok = verify_not_oid(kalle), - ?line ok = verify_not_oid("kalle"), - ?line ok = verify_not_oid(1000), - ?line ok = verify_not_oid(1.0), - ?line ok = verify_not_oid(ErrOid), + ok = verify_oid(?system), + ok = verify_oid(?sysDescr_instance), + ok = verify_oid(?otpSnmpeaModule), + ok = verify_not_oid(kalle), + ok = verify_not_oid("kalle"), + ok = verify_not_oid(1000), + ok = verify_not_oid(1.0), + ok = verify_not_oid(ErrOid), ok. verify_oid(Val) -> @@ -618,15 +618,15 @@ check_sec_model1(Config) when is_list(Config) -> Exclude1 = [], Exclude2 = [v1], Exclude3 = [v1,usm], - ?line ok = verify_sec_model(any, Exclude1), - ?line ok = verify_sec_model(v1, Exclude1), - ?line ok = verify_sec_model(v2c, Exclude1), - ?line ok = verify_sec_model(usm, Exclude1), - ?line ok = verify_sec_model(any, Exclude2), - ?line ok = verify_sec_model(v2c, Exclude2), - ?line ok = verify_not_sec_model(v1, Exclude2), - ?line ok = verify_not_sec_model(v1, Exclude3), - ?line ok = verify_not_sec_model(usm, Exclude3), + ok = verify_sec_model(any, Exclude1), + ok = verify_sec_model(v1, Exclude1), + ok = verify_sec_model(v2c, Exclude1), + ok = verify_sec_model(usm, Exclude1), + ok = verify_sec_model(any, Exclude2), + ok = verify_sec_model(v2c, Exclude2), + ok = verify_not_sec_model(v1, Exclude2), + ok = verify_not_sec_model(v1, Exclude3), + ok = verify_not_sec_model(usm, Exclude3), ok. verify_sec_model(Val, Exclude) -> @@ -651,24 +651,24 @@ verify_not_sec_model(Val, Exclude) -> check_sec_model2(suite) -> []; check_sec_model2(Config) when is_list(Config) -> ?P(check_sec_model2), - ?line ok = verify_sec_model(v1, v1, []), - ?line ok = verify_sec_model(v1, v1, [v2c]), - ?line ok = verify_sec_model(v2c, v2c, []), - ?line ok = verify_sec_model(v2c, v2c, [v1]), - ?line ok = verify_sec_model(v3, usm, []), - ?line ok = verify_sec_model(v3, usm, [v2c]), - ?line ok = verify_not_sec_model(v1, v2c, []), - ?line ok = verify_not_sec_model(v1, v3, [v2c]), - ?line ok = verify_not_sec_model(v1, v1, [v1]), - ?line ok = verify_not_sec_model(v2c, v1, []), - ?line ok = verify_not_sec_model(v2c, v3, [v3]), - ?line ok = verify_not_sec_model(v2c, v2c, [v2c]), - ?line ok = verify_not_sec_model(v3, v1, []), - ?line ok = verify_not_sec_model(v3, v2c, [v1]), - ?line ok = verify_not_sec_model(v3, v3, [v2c]), - ?line ok = verify_not_sec_model(kalle, v3, []), - ?line ok = verify_not_sec_model(1000, v3, []), - ?line ok = verify_not_sec_model(1.0, v3, []), + ok = verify_sec_model(v1, v1, []), + ok = verify_sec_model(v1, v1, [v2c]), + ok = verify_sec_model(v2c, v2c, []), + ok = verify_sec_model(v2c, v2c, [v1]), + ok = verify_sec_model(v3, usm, []), + ok = verify_sec_model(v3, usm, [v2c]), + ok = verify_not_sec_model(v1, v2c, []), + ok = verify_not_sec_model(v1, v3, [v2c]), + ok = verify_not_sec_model(v1, v1, [v1]), + ok = verify_not_sec_model(v2c, v1, []), + ok = verify_not_sec_model(v2c, v3, [v3]), + ok = verify_not_sec_model(v2c, v2c, [v2c]), + ok = verify_not_sec_model(v3, v1, []), + ok = verify_not_sec_model(v3, v2c, [v1]), + ok = verify_not_sec_model(v3, v3, [v2c]), + ok = verify_not_sec_model(kalle, v3, []), + ok = verify_not_sec_model(1000, v3, []), + ok = verify_not_sec_model(1.0, v3, []), ok. @@ -694,13 +694,13 @@ verify_not_sec_model(M1, M2, Exclude) -> check_sec_level(suite) -> []; check_sec_level(Config) when is_list(Config) -> ?P(check_sec_level), - ?line ok = verify_sec_level(noAuthNoPriv), - ?line ok = verify_sec_level(authNoPriv), - ?line ok = verify_sec_level(authPriv), - ?line ok = verify_not_sec_level(kalle), - ?line ok = verify_not_sec_level("noAuthNoPriv"), - ?line ok = verify_not_sec_level(1000), - ?line ok = verify_not_sec_level(1.0), + ok = verify_sec_level(noAuthNoPriv), + ok = verify_sec_level(authNoPriv), + ok = verify_sec_level(authPriv), + ok = verify_not_sec_level(kalle), + ok = verify_not_sec_level("noAuthNoPriv"), + ok = verify_not_sec_level(1000), + ok = verify_not_sec_level(1.0), ok. @@ -730,30 +730,30 @@ verify_not_sec_level(Val) -> check_timer(suite) -> []; check_timer(Config) when is_list(Config) -> ?P(check_timer), - ?line ok = verify_timer(infinity), - ?line ok = verify_timer(1), - ?line ok = verify_timer(10), - ?line ok = verify_timer(2147483647), - ?line ok = verify_timer(2*2147483647), - ?line ok = verify_timer({1,1,0,0}), - ?line ok = verify_timer({10,10,10,10}), - ?line ok = verify_timer({2147483647,2147483647,2147483647,2147483647}), - ?line ok = verify_not_timer(ytinifni), - ?line ok = verify_not_timer("ytinifni"), - ?line ok = verify_not_timer(0), - ?line ok = verify_not_timer(-10), - ?line ok = verify_not_timer({0,1,0,0}), - ?line ok = verify_not_timer({1,0,0,0}), - ?line ok = verify_not_timer({1,1,-1,0}), - ?line ok = verify_not_timer({1,1,0,-1}), - ?line ok = verify_not_timer({1.0,1,0,0}), - ?line ok = verify_not_timer({1,1.0,0,0}), - ?line ok = verify_not_timer({1,1,1.0,0}), - ?line ok = verify_not_timer({1,1,0,1.0}), - ?line ok = verify_not_timer({"1",1,0,0}), - ?line ok = verify_not_timer({1,"1",0,0}), - ?line ok = verify_not_timer({1,1,"0",0}), - ?line ok = verify_not_timer({1,1,0,"0"}), + ok = verify_timer(infinity), + ok = verify_timer(1), + ok = verify_timer(10), + ok = verify_timer(2147483647), + ok = verify_timer(2*2147483647), + ok = verify_timer({1,1,0,0}), + ok = verify_timer({10,10,10,10}), + ok = verify_timer({2147483647,2147483647,2147483647,2147483647}), + ok = verify_not_timer(ytinifni), + ok = verify_not_timer("ytinifni"), + ok = verify_not_timer(0), + ok = verify_not_timer(-10), + ok = verify_not_timer({0,1,0,0}), + ok = verify_not_timer({1,0,0,0}), + ok = verify_not_timer({1,1,-1,0}), + ok = verify_not_timer({1,1,0,-1}), + ok = verify_not_timer({1.0,1,0,0}), + ok = verify_not_timer({1,1.0,0,0}), + ok = verify_not_timer({1,1,1.0,0}), + ok = verify_not_timer({1,1,0,1.0}), + ok = verify_not_timer({"1",1,0,0}), + ok = verify_not_timer({1,"1",0,0}), + ok = verify_not_timer({1,1,"0",0}), + ok = verify_not_timer({1,1,0,"0"}), ok. verify_timer(Val) -> diff --git a/lib/snmp/test/snmp_log_SUITE.erl b/lib/snmp/test/snmp_log_SUITE.erl index caa7a1007698..e4d841450624 100644 --- a/lib/snmp/test/snmp_log_SUITE.erl +++ b/lib/snmp/test/snmp_log_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -169,7 +169,7 @@ init_per_testcase(Case, Config) when is_list(Config) -> Error -> ?FAIL({failed_creating_subsuite_top_dir, Error}) end, - ?line ok = file:make_dir(CaseDir), + ok = file:make_dir(CaseDir), Dog = ?WD_START(?MINS(5)), [{log_dir, CaseDir}, {watchdog, Dog}|Config]. @@ -199,11 +199,11 @@ open_and_close(Config) when is_list(Config) -> File = join(Dir, "snmp_test.log"), Size = {1024, 10}, Repair = true, - ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair), - ?line ok = snmp_log:sync(Log), - ?line {ok, Info} = snmp_log:info(Log), + {ok, Log} = snmp_log:create(Name, File, Size, Repair), + ok = snmp_log:sync(Log), + {ok, Info} = snmp_log:info(Log), display_info(Info), - ?line ok = snmp_log:close(Log). + ok = snmp_log:close(Log). %%====================================================================== @@ -219,7 +219,7 @@ open_write_and_close1(Config) when is_list(Config) -> ?DBG("open_write_and_close1 -> start", []), SeqNoGen = none, - ?line ok = open_write_and_close(SeqNoGen, Config), + ok = open_write_and_close(SeqNoGen, Config), ?DBG("open_write_and_close1 -> done", []), ok. @@ -238,7 +238,7 @@ open_write_and_close2(Config) when is_list(Config) -> ?DBG("open_write_and_close2 -> start", []), SeqNoGen = disabled, - ?line ok = open_write_and_close(SeqNoGen, Config), + ok = open_write_and_close(SeqNoGen, Config), ?DBG("open_write_and_close2 -> done", []), ok. @@ -258,7 +258,7 @@ open_write_and_close3(Config) when is_list(Config) -> seqno_init(), SeqNoGen = {?MODULE, next_seqno, [10, 100]}, - ?line ok = open_write_and_close(SeqNoGen, Config), + ok = open_write_and_close(SeqNoGen, Config), seqno_finish(), ?DBG("open_write_and_close2 -> done", []), @@ -279,7 +279,7 @@ open_write_and_close4(Config) when is_list(Config) -> seqno_init(), SeqNoGen = fun() -> next_seqno(10, 100) end, - ?line ok = open_write_and_close(SeqNoGen, Config), + ok = open_write_and_close(SeqNoGen, Config), seqno_finish(), ?DBG("open_write_and_close2 -> done", []), @@ -319,7 +319,7 @@ open_write_and_close(SeqNoGen, Config) -> Repair = true, ?DBG("open_write_and_close -> create log", []), - ?line {ok, Log} = + {ok, Log} = case SeqNoGen of none -> snmp_log:create(Name, File, Size, Repair); @@ -332,10 +332,10 @@ open_write_and_close(SeqNoGen, Config) -> ?DBG("open_write_and_close1 -> create messages to log", []), %% A request - ?line Req = get_next_request(Vsn, Community, [1,1], 1, 235779012), + Req = get_next_request(Vsn, Community, [1,1], 1, 235779012), %% A reply - ?line Rep = get_response(Vsn, Community, + Rep = get_response(Vsn, Community, [1,3,6,1,2,1,1,1,0], 'OCTET STRING', "Erlang SNMP agent", 1, 235779012), @@ -348,17 +348,17 @@ open_write_and_close(SeqNoGen, Config) -> Addr = ?LOCALHOST(), Port = 162, Logger = fun(Packet) -> - ?line ok = snmp_log:log(Log, Packet, Addr, Port) + ok = snmp_log:log(Log, Packet, Addr, Port) end, lists:foreach(Logger, Msgs), check_notify(), ?DBG("open_write_and_close1 -> display info", []), - ?line {ok, Info} = snmp_log:info(Log), + {ok, Info} = snmp_log:info(Log), display_info(Info), ?DBG("open_write_and_close1 -> close log", []), - ?line ok = snmp_log:close(Log), + ok = snmp_log:close(Log), ?DBG("open_write_and_close -> done", []), ok. @@ -381,7 +381,7 @@ log_to_io1(Config) when is_list(Config) -> Size = {1024, 10}, Repair = true, ?DBG("log_to_io1 -> create log", []), - ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair), + {ok, Log} = snmp_log:create(Name, File, Size, Repair), ?DBG("log_to_io1 -> create messages to log", []), Msgs = messages(), @@ -390,7 +390,7 @@ log_to_io1(Config) when is_list(Config) -> Addr = ?LOCALHOST(), Port = 162, Logger = fun(Packet) -> - ?line ok = snmp_log:log(Log, Packet, Addr, Port) + ok = snmp_log:log(Log, Packet, Addr, Port) end, BatchLogger = fun(Time) -> lists:foreach(Logger, Msgs), @@ -403,14 +403,14 @@ log_to_io1(Config) when is_list(Config) -> lists:foreach(BatchLogger, To), ?DBG("log_to_io1 -> display info", []), - ?line {ok, Info} = snmp_log:info(Log), + {ok, Info} = snmp_log:info(Log), display_info(Info), ?DBG("log_to_io1 -> do the convert to io (stdout)", []), ? line ok = snmp:log_to_io(Dir, [], Name, File, false), ?DBG("log_to_io1 -> close log", []), - ?line ok = snmp_log:close(Log), + ok = snmp_log:close(Log), ?DBG("log_to_io1 -> done", []), ok. @@ -438,20 +438,20 @@ log_to_io2(Config) when is_list(Config) -> Repair = true, ?DBG("log_to_io2 -> create log writer process", []), - ?line {ok, Log, Logger} = + {ok, Log, Logger} = log_writer_start(Name, File, Size, Repair, Factor), ?DBG("log_to_io2 -> create log reader process", []), - ?line {ok, Reader} = log_reader_start(), + {ok, Reader} = log_reader_start(), ?DBG("log_to_io2 -> wait some time", []), ?SLEEP(5000), ?DBG("log_to_io2 -> display log info", []), - ?line log_writer_info(Logger), + log_writer_info(Logger), ?DBG("log_to_io2 -> instruct the log writer to sleep some", []), - ?line ok = log_writer_sleep(Logger, 5000), + ok = log_writer_sleep(Logger, 5000), ?DBG("log_to_io2 -> instruct the log reader to log to io", []), Res = @@ -470,14 +470,14 @@ log_to_io2(Config) when is_list(Config) -> ?DBG("log_to_io2 -> log to io failed: " "~n Error: ~p" "~n Info: ~p", [Error, Info]), - ?line ?FAIL({log_lo_io_failed, Error, Info}) + ?FAIL({log_lo_io_failed, Error, Info}) end, ?DBG("log_to_io2 -> instruct the log writer to stop", []), - ?line log_writer_stop(Logger), + log_writer_stop(Logger), ?DBG("log_to_io2 -> instruct the log reader to stop", []), - ?line log_reader_stop(Reader), + log_reader_stop(Reader), ?DBG("log_to_io2 -> done", []), ok. @@ -494,7 +494,7 @@ log_to_txt1(Config) when is_list(Config) -> Name = "snmp_test_l2t1", SeqNoGen = disabled, - ?line ok = log_to_txt(Name, SeqNoGen, Config), + ok = log_to_txt(Name, SeqNoGen, Config), ?DBG("log_to_txt1 -> done", []), ok. @@ -513,7 +513,7 @@ log_to_txt2(Config) when is_list(Config) -> Name = "snmp_test_l2t2", seqno_init(), SeqNoGen = {?MODULE, next_seqno, [1, 100]}, - ?line ok = log_to_txt(Name, SeqNoGen, Config), + ok = log_to_txt(Name, SeqNoGen, Config), seqno_finish(), ?DBG("log_to_txt2 -> done", []), @@ -531,7 +531,7 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> Repair = true, ?DBG("log_to_txt -> create log", []), - ?line {ok, Log} = + {ok, Log} = case SeqNoGen of none -> snmp_log:create(Name, File, Size, Repair); @@ -546,7 +546,7 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> Addr = ?LOCALHOST(), Port = 162, Logger = fun(Packet) -> - ?line ok = snmp_log:log(Log, Packet, Addr, Port) + ok = snmp_log:log(Log, Packet, Addr, Port) end, BatchLogger = fun(Time) -> lists:foreach(Logger, Msgs), @@ -561,22 +561,22 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> Stop = calendar:local_time(), ?DBG("log_to_txt -> display info", []), - ?line {ok, Info} = snmp_log:info(Log), + {ok, Info} = snmp_log:info(Log), display_info(Info), Out1a = join(Dir, "snmp_text-1-unblocked.txt"), ?DBG("log_to_txt -> do the convert to a text file (~s) unblocked", [Out1a]), - ?line ok = snmp:log_to_txt(Dir, [], Out1a, Log, File, false), + ok = snmp:log_to_txt(Dir, [], Out1a, Log, File, false), - ?line {ok, #file_info{size = Size1a}} = file:read_file_info(Out1a), + {ok, #file_info{size = Size1a}} = file:read_file_info(Out1a), ?DBG("log_to_txt -> text file size: ~p", [Size1a]), validate_size(Size1a), Out1b = join(Dir, "snmp_text-1-blocked.txt"), ?DBG("log_to_txt -> do the convert to a text file (~s) blocked", [Out1b]), - ?line ok = snmp:log_to_txt(Dir, [], Out1b, Log, File, true), + ok = snmp:log_to_txt(Dir, [], Out1b, Log, File, true), - ?line {ok, #file_info{size = Size1b}} = file:read_file_info(Out1b), + {ok, #file_info{size = Size1b}} = file:read_file_info(Out1b), ?DBG("log_to_txt -> text file size: ~p", [Size1b]), validate_size(Size1b, {eq, Size1a}), @@ -585,9 +585,9 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> "~n Start: ~p" "~n Stop: ~p" "~n Out2: ~p", [Start, Stop, Out2]), - ?line ok = snmp:log_to_txt(Dir, [], Out2, Log, File, Start, Stop), + ok = snmp:log_to_txt(Dir, [], Out2, Log, File, Start, Stop), - ?line {ok, #file_info{size = Size2}} = file:read_file_info(Out2), + {ok, #file_info{size = Size2}} = file:read_file_info(Out2), ?DBG("log_to_txt -> text file size: ~p", [Size2]), validate_size(Size2, {le, Size1a}), @@ -615,14 +615,14 @@ log_to_txt(Name, SeqNoGen, Config) when is_list(Config) -> "~n Start2: ~p" "~n Stop2: ~p" "~n Out3: ~p", [Start2, Stop2, Out3]), - ?line ok = snmp:log_to_txt(Dir, [], Out3, Log, File, Start2, Stop2), + ok = snmp:log_to_txt(Dir, [], Out3, Log, File, Start2, Stop2), - ?line {ok, #file_info{size = Size3}} = file:read_file_info(Out3), + {ok, #file_info{size = Size3}} = file:read_file_info(Out3), ?DBG("log_to_txt -> text file size: ~p", [Size3]), validate_size(Size3, {l, Size1a}), ?DBG("log_to_txt -> close log", []), - ?line ok = snmp_log:close(Log), + ok = snmp_log:close(Log), ?DBG("log_to_txt -> done", []), ok. @@ -659,20 +659,20 @@ log_to_txt3(Config) when is_list(Config) -> Mibs = [join(StdMibDir, "SNMPv2-MIB")], ?DBG("log_to_txt3 -> create log writer process", []), - ?line {ok, Log, Logger} = + {ok, Log, Logger} = log_writer_start(Name, LogFile, Size, Repair, Factor), ?DBG("log_to_txt3 -> create log reader process", []), - ?line {ok, Reader} = log_reader_start(), + {ok, Reader} = log_reader_start(), ?DBG("log_to_txt3 -> wait some time", []), ?SLEEP(5000), ?DBG("log_to_txt3 -> display log info", []), - ?line log_writer_info(Logger), + log_writer_info(Logger), ?DBG("log_to_txt3 -> instruct the log writer to sleep some", []), - ?line ok = log_writer_sleep(Logger, 5000), + ok = log_writer_sleep(Logger, 5000), ?DBG("log_to_txt3 -> instruct the log reader to log to txt", []), Res = @@ -690,7 +690,7 @@ log_to_txt3(Config) when is_list(Config) -> case Res of {ok, _Info} -> ?DBG("log_to_txt3 -> ~n Info: ~p", [_Info]), - ?line {ok, #file_info{size = FileSize}} = + {ok, #file_info{size = FileSize}} = file:read_file_info(TxtFile), ?DBG("log_to_txt3 -> text file size: ~p", [FileSize]), validate_size(FileSize); @@ -698,14 +698,14 @@ log_to_txt3(Config) when is_list(Config) -> ?EPRINT("log to txt failed: " "~n Error: ~p" "~n Info: ~p", [Error, Info]), - ?line ?FAIL({log_lo_txt_failed, Error, Info}) + ?FAIL({log_lo_txt_failed, Error, Info}) end, ?DBG("log_to_txt3 -> instruct the log writer to stop", []), - ?line log_writer_stop(Logger), + log_writer_stop(Logger), ?DBG("log_to_txt3 -> instruct the log reader to stop", []), - ?line log_reader_stop(Reader), + log_reader_stop(Reader), ?IPRINT("log_to_txt3 -> done", []), ok. @@ -801,7 +801,7 @@ log_writer_main(Name, File, Size, Repair, P, Factor) -> Addr = ?LOCALHOST(), Port = 162, Logger = fun(Packet) -> - ?line ok = snmp_log:log(Log, Packet, Addr, Port) + ok = snmp_log:log(Log, Packet, Addr, Port) end, BatchLogger = fun(Time) -> lists:foreach(Logger, Msgs), diff --git a/lib/snmp/test/snmp_manager_SUITE.erl b/lib/snmp/test/snmp_manager_SUITE.erl index fc4d73ac7f54..d45a4157762b 100644 --- a/lib/snmp/test/snmp_manager_SUITE.erl +++ b/lib/snmp/test/snmp_manager_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -62,9 +62,9 @@ register_user1/1, - register_agent_old/1, - register_agent2/1, - register_agent3/1, + register_agent_old/0, register_agent_old/1, + register_agent2/0, register_agent2/1, + register_agent3/0, register_agent3/1, info/1, usm_priv_aes/1, @@ -73,30 +73,30 @@ usm_sha384_priv_aes/1, usm_sha512_priv_aes/1, - simple_sync_get3/1, - simple_async_get3/1, + simple_sync_get3/0, simple_sync_get3/1, + simple_async_get3/0, simple_async_get3/1, - simple_sync_get_next3/1, - simple_async_get_next3_cbp_def/1, - simple_async_get_next3_cbp_temp/1, - simple_async_get_next3_cbp_perm/1, + simple_sync_get_next3/0, simple_sync_get_next3/1, + simple_async_get_next3_cbp_def/0, simple_async_get_next3_cbp_def/1, + simple_async_get_next3_cbp_temp/0, simple_async_get_next3_cbp_temp/1, + simple_async_get_next3_cbp_perm/0, simple_async_get_next3_cbp_perm/1, - simple_sync_set3/1, - simple_async_set3_cbp_def/1, - simple_async_set3_cbp_temp/1, - simple_async_set3_cbp_perm/1, + simple_sync_set3/0, simple_sync_set3/1, + simple_async_set3_cbp_def/0, simple_async_set3_cbp_def/1, + simple_async_set3_cbp_temp/0, simple_async_set3_cbp_temp/1, + simple_async_set3_cbp_perm/0, simple_async_set3_cbp_perm/1, - simple_sync_get_bulk3/1, - simple_async_get_bulk3_cbp_def/1, - simple_async_get_bulk3_cbp_temp/1, - simple_async_get_bulk3_cbp_perm/1, - - simple_v3_exchange_md5/1, - simple_v3_exchange_sha/1, - simple_v3_exchange_sha224/1, - simple_v3_exchange_sha256/1, - simple_v3_exchange_sha384/1, - simple_v3_exchange_sha512/1, + simple_sync_get_bulk3/0, simple_sync_get_bulk3/1, + simple_async_get_bulk3_cbp_def/0, simple_async_get_bulk3_cbp_def/1, + simple_async_get_bulk3_cbp_temp/0, simple_async_get_bulk3_cbp_temp/1, + simple_async_get_bulk3_cbp_perm/0, simple_async_get_bulk3_cbp_perm/1, + + simple_v3_exchange_md5/0, simple_v3_exchange_md5/1, + simple_v3_exchange_sha/0, simple_v3_exchange_sha/1, + simple_v3_exchange_sha224/0, simple_v3_exchange_sha224/1, + simple_v3_exchange_sha256/0, simple_v3_exchange_sha256/1, + simple_v3_exchange_sha384/0, simple_v3_exchange_sha384/1, + simple_v3_exchange_sha512/0, simple_v3_exchange_sha512/1, discovery/1, @@ -113,9 +113,9 @@ report/1, - otp8015_1/1, + otp8015_1/0, otp8015_1/1, - otp8395_1/1 + otp8395_1/0, otp8395_1/1 ]). @@ -156,7 +156,7 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. all() -> - %% This is a temporary messure to ensure that we can + %% This is a temporary measure to ensure that we can %% test the socket backend without effecting *all* %% applications on *all* machines. %% This flag is set only for *one* host. @@ -440,25 +440,56 @@ init_per_group(GroupName, Config0) -> Config1. -init_per_group2(inet_backend_default = _GroupName, Config) -> - ?LIB:init_group_top_dir(default, [{socket_create_opts, []} | Config]); -init_per_group2(inet_backend_inet = _GroupName, Config) -> +init_per_group2(inet_backend_default = _GroupName, Config0) -> + Config1 = [{socket_create_opts, []} | Config0], + case ?EXPLICIT_INET_BACKEND() of + true -> + ?LIB:init_group_top_dir(default, Config1); + false -> + %% For a "standard" test (that is if we do not run the "extended" + %% inet backends test) then we should always run this group! + %% So, if we have an extended test, *then* (and only then) + %% check the factor. + case ?TEST_INET_BACKENDS() of + true -> + case lists:keysearch(snmp_factor, 1, Config0) of + {value, {snmp_factor, Factor}} when (Factor < 3) -> + ?LIB:init_group_top_dir(default, Config1); + _ -> + {skip, "Machine too slow"} + end; + _ -> + ?LIB:init_group_top_dir(default, Config1) + end + end; +init_per_group2(inet_backend_inet = _GroupName, Config0) -> case ?EXPLICIT_INET_BACKEND() of true -> %% The environment trumps us, %% so only the default group should be run! {skip, "explicit inet backend"}; false -> - ?LIB:init_group_top_dir(inet, [{socket_create_opts, [{inet_backend, inet}]} | Config]) + case lists:keysearch(snmp_factor, 1, Config0) of + {value, {snmp_factor, Factor}} when (Factor < 5) -> + Config1 = [{socket_create_opts, [{inet_backend, inet}]} | + Config0], + ?LIB:init_group_top_dir(inet, Config1); + _ -> + {skip, "Machine too slow"} + end end; -init_per_group2(inet_backend_socket = _GroupName, Config) -> +init_per_group2(inet_backend_socket = _GroupName, Config0) -> case ?EXPLICIT_INET_BACKEND() of true -> %% The environment trumps us, %% so only the default group should be run! {skip, "explicit inet backend"}; false -> - ?LIB:init_group_top_dir(socket, [{socket_create_opts, [{inet_backend, socket}]} | Config]) + %% Always run this unless a backend has been explicitly + %% configured (since this is really what we want to test). + Config1 = [{socket_create_opts, [{inet_backend, socket}]} | + Config0], + ?LIB:init_group_top_dir(socket, Config1) end; init_per_group2(all = GroupName, Config) -> ?LIB:init_group_top_dir(GroupName, Config); @@ -577,7 +608,7 @@ init_per_testcase(Case, Config) when is_list(Config) -> {skip, {Reason, Mod, Line}}; C:E:_ when ((C =:= throw) orelse (C =:= exit)) -> - {skip, {catched, C, E}} + {skip, {caught, C, E}} end end, ?IPRINT("init_per_testcase end when" @@ -598,29 +629,29 @@ init_per_testcase2(Case, Config) -> MgrTopDir = filename:join(CaseTopDir, "manager/"), ?DBG("init_per_testcase2 -> try create manager top dir: ~n~p", [MgrTopDir]), - ?line ok = file:make_dir(MgrTopDir), + ok = file:make_dir(MgrTopDir), MgrConfDir = filename:join(MgrTopDir, "conf/"), - ?line ok = file:make_dir(MgrConfDir), + ok = file:make_dir(MgrConfDir), MgrDbDir = filename:join(MgrTopDir, "db/"), - ?line ok = file:make_dir(MgrDbDir), + ok = file:make_dir(MgrDbDir), MgrLogDir = filename:join(MgrTopDir, "log/"), - ?line ok = file:make_dir(MgrLogDir), + ok = file:make_dir(MgrLogDir), %% -- Agent dirs -- AgTopDir = filename:join(CaseTopDir, "agent/"), - ?line ok = file:make_dir(AgTopDir), + ok = file:make_dir(AgTopDir), AgConfDir = filename:join(AgTopDir, "conf/"), - ?line ok = file:make_dir(AgConfDir), + ok = file:make_dir(AgConfDir), AgDbDir = filename:join(AgTopDir, "db/"), - ?line ok = file:make_dir(AgDbDir), + ok = file:make_dir(AgDbDir), AgLogDir = filename:join(AgTopDir, "log/"), - ?line ok = file:make_dir(AgLogDir), + ok = file:make_dir(AgLogDir), Family = proplists:get_value(ipfamily, Config, inet), @@ -654,18 +685,18 @@ init_per_testcase2(Case, Config) -> ?DBG("init [~w] Nodes [2]: ~p", [Case, erlang:nodes()]), Conf2. -init_per_testcase3(simple_v3_exchange_md5 = _Case, Config) -> - init_v3_testcase([{auth_alg, md5} | Config]); -init_per_testcase3(simple_v3_exchange_sha = _Case, Config) -> - init_v3_testcase([{auth_alg, sha} | Config]); -init_per_testcase3(simple_v3_exchange_sha224 = _Case, Config) -> - init_v3_testcase([{auth_alg, sha224} | Config]); -init_per_testcase3(simple_v3_exchange_sha256 = _Case, Config) -> - init_v3_testcase([{auth_alg, sha256} | Config]); -init_per_testcase3(simple_v3_exchange_sha384 = _Case, Config) -> - init_v3_testcase([{auth_alg, sha384} | Config]); -init_per_testcase3(simple_v3_exchange_sha512 = _Case, Config) -> - init_v3_testcase([{auth_alg, sha512} | Config]); +init_per_testcase3(simple_v3_exchange_md5 = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, md5} | Config]); +init_per_testcase3(simple_v3_exchange_sha = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, sha} | Config]); +init_per_testcase3(simple_v3_exchange_sha224 = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, sha224} | Config]); +init_per_testcase3(simple_v3_exchange_sha256 = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, sha256} | Config]); +init_per_testcase3(simple_v3_exchange_sha384 = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, sha384} | Config]); +init_per_testcase3(simple_v3_exchange_sha512 = Case, Config) -> + init_v3_testcase(Case, [{auth_alg, sha512} | Config]); init_per_testcase3(Case, Config) -> ApiCases02 = [ @@ -744,8 +775,8 @@ init_per_testcase3(Case, Config) -> end, %% We don't need to try catch this (init_agent) %% since we have a try catch "higher up"... - Conf3 = init_agent(Conf2), - Conf4 = try init_manager(AutoInform, Conf3) + Conf3 = init_agent(Case, Conf2), + Conf4 = try init_manager(Case, AutoInform, Conf3) catch AC:AE:_ -> %% Ouch we need to clean up: %% The init_agent starts an agent node! @@ -771,9 +802,9 @@ init_per_testcase3(Case, Config) -> Config end. -init_v3_testcase(Conf) -> - Conf2 = init_v3_agent(Conf), - Conf3 = try init_v3_manager(Conf2) +init_v3_testcase(Case, Conf) -> + Conf2 = init_v3_agent(Case, Conf), + Conf3 = try init_v3_manager(Case, Conf2) catch AC:AE:AS -> %% Ouch we need to clean up: %% The init_agent starts an agent node! @@ -896,7 +927,6 @@ end_per_testcase2(Case, Config) -> %% Test functions %%====================================================================== -simple_start_and_stop1(suite) -> []; simple_start_and_stop1(Config) when is_list(Config) -> ?TC_TRY(simple_start_and_stop1, fun() -> do_simple_start_and_stop1(Config) end). @@ -930,17 +960,16 @@ do_simple_start_and_stop1(Config) -> %%====================================================================== -simple_start_and_stop2(suite) -> []; simple_start_and_stop2(Config) when is_list(Config) -> Pre = fun() -> - ManagerNode = start_manager_node(), + ManagerNode = start_node(simple_start_and_stop2), [ManagerNode] end, Case = fun(State) -> do_simple_start_and_stop2(State, Config) end, - Post = fun([ManagerNode]) -> stop_node(ManagerNode) end, + Post = fun([{ManagerPeer, _ManagerNode}]) -> peer:stop(ManagerPeer) end, ?TC_TRY(simple_start_and_stop2, Pre, Case, Post). -do_simple_start_and_stop2([ManagerNode], Config) -> +do_simple_start_and_stop2([{_ManagerPeer, ManagerNode}], Config) -> ?IPRINT("starting with Config: " "~n ~p" "~n", [Config]), @@ -958,20 +987,20 @@ do_simple_start_and_stop2([ManagerNode], Config) -> ?IPRINT("try load snmp application"), - ?line ok = load_snmp(ManagerNode), + ok = load_snmp(ManagerNode), ?IPRINT("try set manager env for the snmp application"), - ?line ok = set_mgr_env(ManagerNode, Opts), + ok = set_mgr_env(ManagerNode, Opts), ?IPRINT("try starting snmp application (with only manager)"), - ?line ok = start_snmp(ManagerNode), + ok = start_snmp(ManagerNode), ?IPRINT("started"), ?SLEEP(1000), ?IPRINT("try stopping snmp application (with only manager)"), - ?line ok = stop_snmp(ManagerNode), + ok = stop_snmp(ManagerNode), ?SLEEP(1000), ?IPRINT("end"), @@ -981,7 +1010,6 @@ do_simple_start_and_stop2([ManagerNode], Config) -> %%====================================================================== -simple_start_and_stop3(suite) -> []; simple_start_and_stop3(Config) when is_list(Config) -> ?TC_TRY(simple_start_and_stop3, fun() -> do_simple_start_and_stop3(Config) end). @@ -1021,7 +1049,6 @@ do_simple_start_and_stop3(Config) -> %%====================================================================== -simple_start_and_monitor_crash1(suite) -> []; simple_start_and_monitor_crash1(Config) when is_list(Config) -> ?TC_TRY(simple_start_and_monitor_crash1, fun() -> do_simple_start_and_monitor_crash1(Config) end). @@ -1085,7 +1112,6 @@ do_simple_start_and_monitor_crash1(Config) -> %%====================================================================== -simple_start_and_monitor_crash2(suite) -> []; simple_start_and_monitor_crash2(Config) when is_list(Config) -> Cond = fun() -> case os:type() of {unix, netbsd} -> @@ -1191,7 +1217,6 @@ simulate_crash(NumKills, _) -> %%====================================================================== -notify_started01(suite) -> []; notify_started01(Config) when is_list(Config) -> ?TC_TRY(notify_started01, fun() -> do_notify_started01(Config) end). @@ -1283,7 +1308,6 @@ snmpm_starter(Opts, To) -> %%====================================================================== -notify_started02(suite) -> []; notify_started02(Config) when is_list(Config) -> ?TC_TRY(notify_started02, fun() -> notify_started02_cond(Config) end, @@ -1509,7 +1533,6 @@ ns02_ctrl_loop(Opts, N) -> %%====================================================================== -info(suite) -> []; info(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1612,7 +1635,6 @@ verify_info([{Key, SubKeys}|Keys], Info) -> %% USM privacy fails with AES in OTP 22.2.3. Test to prevent %% regression in future releases. %% -usm_priv_aes(suite) -> []; usm_priv_aes(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1645,7 +1667,6 @@ usm_priv_aes(Config) when is_list(Config) -> %%====================================================================== -usm_sha224_priv_aes(suite) -> []; usm_sha224_priv_aes(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1678,7 +1699,6 @@ usm_sha224_priv_aes(Config) when is_list(Config) -> %%====================================================================== -usm_sha256_priv_aes(suite) -> []; usm_sha256_priv_aes(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1711,7 +1731,6 @@ usm_sha256_priv_aes(Config) when is_list(Config) -> %%====================================================================== -usm_sha384_priv_aes(suite) -> []; usm_sha384_priv_aes(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1744,7 +1763,6 @@ usm_sha384_priv_aes(Config) when is_list(Config) -> %%====================================================================== -usm_sha512_priv_aes(suite) -> []; usm_sha512_priv_aes(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -1921,17 +1939,16 @@ do_usm_priv_aes(AuthAlg, Config) -> %%====================================================================== -register_user1(suite) -> []; register_user1(Config) when is_list(Config) -> Pre = fun() -> - ManagerNode = start_manager_node(), + ManagerNode = start_node(register_user1), [ManagerNode] end, Case = fun(State) -> do_register_user1(State, Config) end, - Post = fun([ManagerNode]) -> stop_node(ManagerNode) end, + Post = fun([{ManagerPeer, _ManagerNode}]) -> peer:stop(ManagerPeer) end, ?TC_TRY(register_user1, Pre, Case, Post). -do_register_user1([ManagerNode], Config) -> +do_register_user1([{_ManagerPeer, ManagerNode}], Config) -> ?IPRINT("starting with Config: " "~n ~p" "~n", [Config]), @@ -1949,13 +1966,13 @@ do_register_user1([ManagerNode], Config) -> ?IPRINT("load snmp application"), - ?line ok = load_snmp(ManagerNode), + ok = load_snmp(ManagerNode), ?IPRINT("set manager env for the snmp application"), - ?line ok = set_mgr_env(ManagerNode, Opts), + ok = set_mgr_env(ManagerNode, Opts), ?IPRINT("starting snmp application (with only manager)"), - ?line ok = start_snmp(ManagerNode), + ok = start_snmp(ManagerNode), ?IPRINT("started"), @@ -1964,41 +1981,41 @@ do_register_user1([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("try register user(s)"), - ?line ok = mgr_register_user(ManagerNode, calvin, snmpm_user_default, + ok = mgr_register_user(ManagerNode, calvin, snmpm_user_default, [self(), "various misc info"]), Users1 = mgr_which_users(ManagerNode), ?IPRINT("users: ~p~n", [Users1]), - ?line ok = verify_users(Users1, [calvin]), + ok = verify_users(Users1, [calvin]), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), - ?line ok = mgr_register_user(ManagerNode, hobbe, snmpm_user_default, + ok = mgr_register_user(ManagerNode, hobbe, snmpm_user_default, {"misc info", self()}), Users2 = mgr_which_users(ManagerNode), ?IPRINT("users: ~p~n", [Users2]), - ?line ok = verify_users(Users2, [calvin, hobbe]), + ok = verify_users(Users2, [calvin, hobbe]), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("try unregister user(s)"), - ?line ok = mgr_unregister_user(ManagerNode, calvin), + ok = mgr_unregister_user(ManagerNode, calvin), Users3 = mgr_which_users(ManagerNode), ?IPRINT("users: ~p~n", [Users3]), - ?line ok = verify_users(Users3, [hobbe]), + ok = verify_users(Users3, [hobbe]), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), - ?line ok = mgr_unregister_user(ManagerNode, hobbe), + ok = mgr_unregister_user(ManagerNode, hobbe), Users4 = mgr_which_users(ManagerNode), ?IPRINT("users: ~p~n", [Users4]), - ?line ok = verify_users(Users4, []), + ok = verify_users(Users4, []), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?SLEEP(1000), ?IPRINT("stop snmp application (with only manager)"), - ?line ok = stop_snmp(ManagerNode), + ok = stop_snmp(ManagerNode), ?SLEEP(1000), @@ -2019,20 +2036,19 @@ verify_users(ActualUsers0, [User|RegUsers]) -> %%====================================================================== -register_agent_old(doc) -> - ["Test registration of agents with the OLD interface functions"]; -register_agent_old(suite) -> - []; +register_agent_old() -> + [{doc, "Test registration of agents with the OLD interface functions"}]. + register_agent_old(Config) when is_list(Config) -> Pre = fun() -> - ManagerNode = start_manager_node(), + ManagerNode = start_node(register_agent_old), [ManagerNode] end, Case = fun(State) -> do_register_agent_old(State, Config) end, - Post = fun([ManagerNode]) -> stop_node(ManagerNode) end, + Post = fun([{ManagerPeer, _ManagerNode}]) -> peer:stop(ManagerPeer) end, ?TC_TRY(register_agent_old, Pre, Case, Post). -do_register_agent_old([ManagerNode], Config) -> +do_register_agent_old([{_ManagerPeer, ManagerNode}], Config) -> ?IPRINT("starting with Config: " "~n ~p" "~n", [Config]), @@ -2050,13 +2066,13 @@ do_register_agent_old([ManagerNode], Config) -> ?IPRINT("load snmp application"), - ?line ok = load_snmp(ManagerNode), + ok = load_snmp(ManagerNode), ?IPRINT("set manager env for the snmp application"), - ?line ok = set_mgr_env(ManagerNode, Opts), + ok = set_mgr_env(ManagerNode, Opts), ?IPRINT("starting snmp application (with only manager)"), - ?line ok = start_snmp(ManagerNode), + ok = start_snmp(ManagerNode), ?IPRINT("started"), @@ -2065,15 +2081,15 @@ do_register_agent_old([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register user(s) user_alfa & user_beta"), - ?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), - ?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register agent(s)"), - ?line ok = mgr_register_agent(ManagerNode, user_alfa, 5000, []), - ?line ok = mgr_register_agent(ManagerNode, user_alfa, 5001, []), - ?line ok = mgr_register_agent(ManagerNode, user_beta, 5002, []), - ?line ok = mgr_register_agent(ManagerNode, user_beta, 5003, []), + ok = mgr_register_agent(ManagerNode, user_alfa, 5000, []), + ok = mgr_register_agent(ManagerNode, user_alfa, 5001, []), + ok = mgr_register_agent(ManagerNode, user_beta, 5002, []), + ok = mgr_register_agent(ManagerNode, user_beta, 5003, []), ?IPRINT("verify all agent(s): expect 4"), case mgr_which_agents(ManagerNode) of @@ -2106,7 +2122,7 @@ do_register_agent_old([ManagerNode], Config) -> "~n ~p", [mgr_info(ManagerNode)]), ?IPRINT("unregister user user_alfa"), - ?line ok = mgr_unregister_user(ManagerNode, user_alfa), + ok = mgr_unregister_user(ManagerNode, user_alfa), ?IPRINT("verify all agent(s): expect 2"), case mgr_which_agents(ManagerNode) of @@ -2120,8 +2136,8 @@ do_register_agent_old([ManagerNode], Config) -> "~n ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user_beta agents"), - ?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5002), - ?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5003), + ok = mgr_unregister_agent(ManagerNode, user_beta, 5002), + ok = mgr_unregister_agent(ManagerNode, user_beta, 5003), ?IPRINT("verify all agent(s): expect 0"), case mgr_which_agents(ManagerNode) of @@ -2136,7 +2152,7 @@ do_register_agent_old([ManagerNode], Config) -> "~n ~p", [mgr_info(ManagerNode)]), ?IPRINT("unregister user hobbe"), - ?line ok = mgr_unregister_user(ManagerNode, user_beta), + ok = mgr_unregister_user(ManagerNode, user_beta), ?IPRINT("manager info: " "~n ~p", [mgr_info(ManagerNode)]), @@ -2144,7 +2160,7 @@ do_register_agent_old([ManagerNode], Config) -> ?SLEEP(1000), ?IPRINT("stop snmp application (with only manager)"), - ?line ok = stop_snmp(ManagerNode), + ok = stop_snmp(ManagerNode), ?SLEEP(1000), ?IPRINT("end"), @@ -2154,20 +2170,19 @@ do_register_agent_old([ManagerNode], Config) -> %%====================================================================== -register_agent2(doc) -> - ["Test registration of agents with the NEW interface functions"]; -register_agent2(suite) -> - []; +register_agent2() -> + [{doc, "Test registration of agents with the NEW interface functions"}]. + register_agent2(Config) when is_list(Config) -> Pre = fun() -> - ManagerNode = start_manager_node(), + ManagerNode = start_node(register_agent2), [ManagerNode] end, Case = fun(State) -> do_register_agent2(State, Config) end, - Post = fun([ManagerNode]) -> stop_node(ManagerNode) end, + Post = fun([{ManagerPeer, _ManagerNode}]) -> peer:stop(ManagerPeer) end, ?TC_TRY(register_agent2, Pre, Case, Post). -do_register_agent2([ManagerNode], Config) -> +do_register_agent2([{_ManagerPeer, ManagerNode}], Config) -> ?IPRINT("starting with Config: " "~n ~p", [Config]), @@ -2184,13 +2199,13 @@ do_register_agent2([ManagerNode], Config) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("load snmp application"), - ?line ok = load_snmp(ManagerNode), + ok = load_snmp(ManagerNode), ?IPRINT("set manager env for the snmp application"), - ?line ok = set_mgr_env(ManagerNode, Opts), + ok = set_mgr_env(ManagerNode, Opts), ?IPRINT("starting snmp application (with only manager)"), - ?line ok = start_snmp(ManagerNode), + ok = start_snmp(ManagerNode), ?IPRINT("started"), @@ -2199,28 +2214,28 @@ do_register_agent2([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register user(s) user_alfa & user_beta"), - ?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), - ?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register agent(s)"), TargetName1 = "agent1", - ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1, + ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1, [{address, LocalHost}, {port, 5001}, {engine_id, "agentEngineId-1"}]), TargetName2 = "agent2", - ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2, + ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2, [{address, LocalHost}, {port, 5002}, {engine_id, "agentEngineId-2"}]), TargetName3 = "agent3", - ?line ok = mgr_register_agent(ManagerNode, user_beta, TargetName3, + ok = mgr_register_agent(ManagerNode, user_beta, TargetName3, [{address, LocalHost}, {port, 5003}, {engine_id, "agentEngineId-3"}]), TargetName4 = "agent4", - ?line ok = mgr_register_agent(ManagerNode, user_beta, TargetName4, + ok = mgr_register_agent(ManagerNode, user_beta, TargetName4, [{address, LocalHost}, {port, 5004}, {engine_id, "agentEngineId-4"}]), @@ -2255,7 +2270,7 @@ do_register_agent2([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user user_alfa"), - ?line ok = mgr_unregister_user(ManagerNode, user_alfa), + ok = mgr_unregister_user(ManagerNode, user_alfa), ?IPRINT("verify all agent(s): expect 2"), case mgr_which_agents(ManagerNode) of @@ -2268,8 +2283,8 @@ do_register_agent2([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user_beta agents"), - ?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName3), - ?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName4), + ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName3), + ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName4), ?IPRINT("verify all agent(s): expect 0"), case mgr_which_agents(ManagerNode) of @@ -2283,14 +2298,14 @@ do_register_agent2([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user user_beta"), - ?line ok = mgr_unregister_user(ManagerNode, user_beta), + ok = mgr_unregister_user(ManagerNode, user_beta), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?SLEEP(1000), ?IPRINT("stop snmp application (with only manager)"), - ?line ok = stop_snmp(ManagerNode), + ok = stop_snmp(ManagerNode), ?SLEEP(1000), @@ -2299,21 +2314,20 @@ do_register_agent2([ManagerNode], Config) -> %%====================================================================== -register_agent3(doc) -> - ["Test registration of agents with the NEW interface functions " - "and specifying transport domain"]; -register_agent3(suite) -> - []; +register_agent3() -> + [{doc, "Test registration of agents with the NEW interface functions " + "and specifying transport domain"}]. + register_agent3(Config) when is_list(Config) -> Pre = fun() -> - ManagerNode = start_manager_node(), + ManagerNode = start_node(register_agent3), [ManagerNode] end, Case = fun(State) -> do_register_agent3(State, Config) end, - Post = fun([ManagerNode]) -> stop_node(ManagerNode) end, + Post = fun([{ManagerPeer, _ManagerNode}]) -> peer:stop(ManagerPeer) end, ?TC_TRY(register_agent3, Pre, Case, Post). -do_register_agent3([ManagerNode], Config) -> +do_register_agent3([{_ManagerPeer, ManagerNode}], Config) -> ?IPRINT("starting with Config: " "~n ~p", [Config]), @@ -2332,13 +2346,13 @@ do_register_agent3([ManagerNode], Config) -> ?IPRINT("load snmp application"), - ?line ok = load_snmp(ManagerNode), + ok = load_snmp(ManagerNode), ?IPRINT("set manager env for the snmp application"), - ?line ok = set_mgr_env(ManagerNode, Opts), + ok = set_mgr_env(ManagerNode, Opts), ?IPRINT("starting snmp application (with only manager)"), - ?line ok = start_snmp(ManagerNode), + ok = start_snmp(ManagerNode), ?IPRINT("started"), @@ -2347,25 +2361,25 @@ do_register_agent3([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register user(s) user_alfa & user_beta"), - ?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), - ?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []), + ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("register agent(s)"), TargetName1 = "agent2", - ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1, + ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1, [{tdomain, transportDomainUdpIpv4}, {address, LocalHost}, {port, 5001}, {engine_id, "agentEngineId-1"}]), TargetName2 = "agent3", - ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2, + ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2, [{tdomain, transportDomainUdpIpv6}, {address, {0,0,0,0,0,0,0,1}}, {port, 5002}, {engine_id, "agentEngineId-2"}]), TargetName3 = "agent4", - ?line {error, {unsupported_domain, _} = Reason4} = + {error, {unsupported_domain, _} = Reason4} = mgr_register_agent(ManagerNode, user_beta, TargetName3, [{tdomain, transportDomainTcpIpv4}, {address, LocalHost}, @@ -2373,7 +2387,7 @@ do_register_agent3([ManagerNode], Config) -> {engine_id, "agentEngineId-3"}]), ?IPRINT("Expected registration failure: ~p", [Reason4]), TargetName4 = "agent5", - ?line {error, {unknown_domain, _} = Reason5} = + {error, {unknown_domain, _} = Reason5} = mgr_register_agent(ManagerNode, user_beta, TargetName4, [{tdomain, transportDomainUdpIpv4_bad}, {address, LocalHost}, @@ -2411,7 +2425,7 @@ do_register_agent3([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user user_alfa"), - ?line ok = mgr_unregister_user(ManagerNode, user_alfa), + ok = mgr_unregister_user(ManagerNode, user_alfa), ?IPRINT("verify all agent(s): expect 0"), case mgr_which_agents(ManagerNode) of @@ -2435,14 +2449,14 @@ do_register_agent3([ManagerNode], Config) -> ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?IPRINT("unregister user user_beta"), - ?line ok = mgr_unregister_user(ManagerNode, user_beta), + ok = mgr_unregister_user(ManagerNode, user_beta), ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]), ?SLEEP(1000), ?IPRINT("stop snmp application (with only manager)"), - ?line ok = stop_snmp(ManagerNode), + ok = stop_snmp(ManagerNode), ?SLEEP(1000), @@ -2451,9 +2465,9 @@ do_register_agent3([ManagerNode], Config) -> %%====================================================================== -simple_sync_get3(doc) -> - ["Simple sync get-request - Version 3 API (TargetName and send-opts)"]; -simple_sync_get3(suite) -> []; +simple_sync_get3() -> + [{doc, "Simple sync get-request - Version 3 API (TargetName and send-opts)"}]. + simple_sync_get3(Config) when is_list(Config) -> ?TC_TRY(simple_sync_get3, fun() -> do_simple_sync_get3(Config) end). @@ -2493,12 +2507,12 @@ do_simple_sync_get3(Config, Get, PostVerify) -> ?IPRINT("issue get-request without loading the mib"), Oids1 = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance], - ?line ok = do_simple_sync_get3(Node, TargetName, Oids1, Get, PostVerify), + ok = do_simple_sync_get3(Node, TargetName, Oids1, Get, PostVerify), ?IPRINT("issue get-request after first loading the mibs"), - ?line ok = mgr_user_load_mib(Node, std_mib()), + ok = mgr_user_load_mib(Node, std_mib()), Oids2 = [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]], - ?line ok = do_simple_sync_get3(Node, TargetName, Oids2, Get, PostVerify), + ok = do_simple_sync_get3(Node, TargetName, Oids2, Get, PostVerify), ok. do_simple_sync_get3(Node, TargetName, Oids, Get, PostVerify) @@ -2506,7 +2520,7 @@ do_simple_sync_get3(Node, TargetName, Oids, Get, PostVerify) ?IPRINT("try get for ~p (on ~p):" "~n Oids: ~p", [TargetName, Node, Oids]), - ?line Reply = + Reply = case Get(Node, TargetName, Oids) of {ok, R, _Rem} -> ?IPRINT("get reply: " @@ -2522,7 +2536,7 @@ do_simple_sync_get3(Node, TargetName, Oids, Get, PostVerify) %% verify that the operation actually worked: %% The order should be the same, so no need to search - ?line ok = case Reply of + ok = case Reply of {noError, 0, [#varbind{oid = ?sysObjectID_instance, value = SysObjectID}, #varbind{oid = ?sysDescr_instance, @@ -2582,9 +2596,9 @@ sag_verify_vbs([Vb|_], [E|_]) -> %%====================================================================== -simple_async_get3(doc) -> - ["Simple (async) get-request - Version 3 API (TargetName and send-opts)"]; -simple_async_get3(suite) -> []; +simple_async_get3() -> + [{doc, "Simple (async) get-request - Version 3 API (TargetName and send-opts)"}]. + simple_async_get3(Config) when is_list(Config) -> ?TC_TRY(simple_async_get3, fun() -> do_simple_async_get3(Config) end). @@ -2613,10 +2627,10 @@ do_simple_async_get3(Config) -> Res. do_simple_async_sync_get3(Config, MgrNode, AgentNode, Get, PostVerify) -> - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), do_simple_async_sync_get3(fun() -> mgr_info(MgrNode) end, fun() -> agent_info(AgentNode) end, Get, PostVerify). @@ -2666,7 +2680,7 @@ do_simple_async_sync_get3(MgrInfo, AgentInfo, Get, PostVerify) ?IPRINT("agent info when starting test: " "~n ~p", [AgentInfo()]), - ?line ok = async_exec(Requests, []), + ok = async_exec(Requests, []), ?IPRINT("manager info when ending test: " "~n ~p", [MgrInfo()]), @@ -2715,10 +2729,10 @@ check_ssgn_vbs([Vb|_], [E|_]) -> %%====================================================================== -simple_sync_get_next3(doc) -> - ["Simple (sync) get_next-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_sync_get_next3(suite) -> []; +simple_sync_get_next3() -> + [{doc, "Simple (sync) get_next-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_sync_get_next3(Config) when is_list(Config) -> process_flag(trap_exit, true), put(tname, ssgn3), @@ -2753,32 +2767,32 @@ do_simple_sync_get_next3(Config, GetNext, PostVerify) %% -- 1 -- Oids01 = [[1,3,7,1]], VF01 = fun(X) -> verify_ssgn_reply1(X, [{[1,3,7,1],endOfMibView}]) end, - ?line ok = do_simple_get_next(1, + ok = do_simple_get_next(1, MgrNode, TargetName, Oids01, VF01, GetNext, PostVerify), - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), %% -- 2 -- Oids02 = [[sysDescr], [1,3,7,1]], VF02 = fun(X) -> verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView]) end, - ?line ok = do_simple_get_next(2, + ok = do_simple_get_next(2, MgrNode, TargetName, Oids02, VF02, GetNext, PostVerify), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), %% -- 3 -- - ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), + {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), Oids03 = [[TCnt2, 1]], VF03 = fun(X) -> verify_ssgn_reply1(X, [{fl([TCnt2,2]), 100}]) end, - ?line ok = do_simple_get_next(3, + ok = do_simple_get_next(3, MgrNode, TargetName, Oids03, VF03, GetNext, PostVerify), @@ -2787,48 +2801,48 @@ do_simple_sync_get_next3(Config, GetNext, PostVerify) VF04 = fun(X) -> verify_ssgn_reply1(X, [{fl([TCnt2,2]), endOfMibView}]) end, - ?line ok = do_simple_get_next(4, + ok = do_simple_get_next(4, MgrNode, TargetName, Oids04, VF04, GetNext, PostVerify), %% -- 5 -- - ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1), + {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1), Oids05 = [TGenErr1], VF05 = fun(X) -> verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]}) end, - ?line ok = do_simple_get_next(5, + ok = do_simple_get_next(5, MgrNode, TargetName, Oids05, VF05, GetNext, PostVerify), %% -- 6 -- - ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2), + {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2), Oids06 = [TGenErr2], VF06 = fun(X) -> verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]}) end, - ?line ok = do_simple_get_next(6, + ok = do_simple_get_next(6, MgrNode, TargetName, Oids06, VF06, GetNext, PostVerify), %% -- 7 -- - ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3), + {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3), Oids07 = [[sysDescr], TGenErr3], VF07 = fun(X) -> verify_ssgn_reply2(X, {genErr, 2, [?sysDescr, TGenErr3]}) end, - ?line ok = do_simple_get_next(7, + ok = do_simple_get_next(7, MgrNode, TargetName, Oids07, VF07, GetNext, PostVerify), %% -- 8 -- - ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig), + {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig), Oids08 = [TTooBig], VF08 = fun(X) -> verify_ssgn_reply2(X, {tooBig, 0, []}) end, - ?line ok = do_simple_get_next(8, + ok = do_simple_get_next(8, MgrNode, TargetName, Oids08, VF08, GetNext, PostVerify), ok. @@ -2850,24 +2864,24 @@ do_simple_get_next(N, Node, TargetName, Oids, Verify, GetNext, PostVerify) -> %%====================================================================== -simple_async_get_next3_cbp_def(doc) -> - ["Simple (async) get_next-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_next3_cbp_def(suite) -> []; +simple_async_get_next3_cbp_def() -> + [{doc, "Simple (async) get_next-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_next3_cbp_def(Config) when is_list(Config) -> simple_async_get_next3(ssgn2_cbp_def, Config). -simple_async_get_next3_cbp_temp(doc) -> - ["Simple (async) get_next-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_next3_cbp_temp(suite) -> []; +simple_async_get_next3_cbp_temp() -> + [{doc, "Simple (async) get_next-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_next3_cbp_temp(Config) when is_list(Config) -> simple_async_get_next3(ssgn2_cbp_temp, Config). -simple_async_get_next3_cbp_perm(doc) -> - ["Simple (async) get_next-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_next3_cbp_perm(suite) -> []; +simple_async_get_next3_cbp_perm() -> + [{doc, "Simple (async) get_next-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_next3_cbp_perm(Config) when is_list(Config) -> simple_async_get_next3(ssgn2_cbp_perm, Config). @@ -2884,10 +2898,10 @@ do_simple_async_get_next3(Config) -> AgentNode = ?config(agent_node, Config), TargetName = ?config(manager_agent_target_name, Config), - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), Self = self(), Msg = simple_async_get_next3, @@ -2911,11 +2925,11 @@ do_simple_async_get_next3(Config) -> do_simple_async_get_next3(MgrNode, AgentNode, GetNext, PostVerify) when is_function(GetNext, 1) andalso is_function(PostVerify, 1) -> - ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), - ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1), - ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2), - ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3), - ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig), + {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), + {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1), + {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2), + {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3), + {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig), Requests = [ @@ -2983,7 +2997,7 @@ do_simple_async_get_next3(MgrNode, AgentNode, GetNext, PostVerify) ?IPRINT("agent info when starting test: " "~n ~p", [agent_info(AgentNode)]), - ?line ok = async_exec(Requests, []), + ok = async_exec(Requests, []), ?IPRINT("manager info when ending test: " "~n ~p", [mgr_info(MgrNode)]), @@ -3012,9 +3026,9 @@ value_of_vavs([{_Oid, Val}|VAVs], Acc) -> %%====================================================================== -simple_sync_set3(doc) -> - ["Simple (sync) set-request - Version 3 API (TargetName with send-opts)"]; -simple_sync_set3(suite) -> []; +simple_sync_set3() -> + [{doc, "Simple (sync) set-request - Version 3 API (TargetName with send-opts)"}]. + simple_sync_set3(Config) when is_list(Config) -> ?TC_TRY(simple_sync_set3, fun() -> do_simple_sync_set3(Config) end). @@ -3054,22 +3068,22 @@ do_simple_sync_set3(Config, Set, PostVerify) {?sysName_instance, s, Val11}, {?sysLocation_instance, s, Val12} ], - ?line ok = do_simple_set3(Node, TargetName, VAVs1, Set, PostVerify), + ok = do_simple_set3(Node, TargetName, VAVs1, Set, PostVerify), ?IPRINT("issue set-request after first loading the mibs"), - ?line ok = mgr_user_load_mib(Node, std_mib()), + ok = mgr_user_load_mib(Node, std_mib()), Val21 = "Sune Anka", Val22 = "Gothenburg", VAVs2 = [ {[sysName, 0], Val21}, {[sysLocation, 0], Val22} ], - ?line ok = do_simple_set3(Node, TargetName, VAVs2, Set, PostVerify), + ok = do_simple_set3(Node, TargetName, VAVs2, Set, PostVerify), ok. do_simple_set3(Node, TargetName, VAVs, Set, PostVerify) -> [SysName, SysLoc] = value_of_vavs(VAVs), - ?line {ok, Reply, _Rem} = Set(Node, TargetName, VAVs), + {ok, Reply, _Rem} = Set(Node, TargetName, VAVs), ?DBG("~n Reply: ~p" "~n Rem: ~w", [Reply, _Rem]), @@ -3077,7 +3091,7 @@ do_simple_set3(Node, TargetName, VAVs, Set, PostVerify) -> %% verify that the operation actually worked: %% The order should be the same, so no need to search %% The value we get should be exactly the same as we sent - ?line ok = case Reply of + ok = case Reply of {noError, 0, [#varbind{oid = ?sysName_instance, value = SysName}, #varbind{oid = ?sysLocation_instance, @@ -3127,21 +3141,21 @@ sas_verify_vbs([Vb|_], [E|_]) -> %%====================================================================== -simple_async_set3_cbp_def(doc) -> - ["Simple (async) set-request - Version 3 API (TargetName with send-opts)"]; -simple_async_set3_cbp_def(suite) -> []; +simple_async_set3_cbp_def() -> + [{doc, "Simple (async) set-request - Version 3 API (TargetName with send-opts)"}]. + simple_async_set3_cbp_def(Config) when is_list(Config) -> simple_async_set3(sas3_cbp_def, Config). -simple_async_set3_cbp_temp(doc) -> - ["Simple (async) set-request - Version 3 API (TargetName with send-opts)"]; -simple_async_set3_cbp_temp(suite) -> []; +simple_async_set3_cbp_temp() -> + [{doc, "Simple (async) set-request - Version 3 API (TargetName with send-opts)"}]. + simple_async_set3_cbp_temp(Config) when is_list(Config) -> simple_async_set3(sas3_cbp_temp, Config). -simple_async_set3_cbp_perm(doc) -> - ["Simple (async) set-request - Version 3 API (TargetName with send-opts)"]; -simple_async_set3_cbp_perm(suite) -> []; +simple_async_set3_cbp_perm() -> + [{doc, "Simple (async) set-request - Version 3 API (TargetName with send-opts)"}]. + simple_async_set3_cbp_perm(Config) when is_list(Config) -> simple_async_set3(sas3_cbp_perm, Config). @@ -3157,10 +3171,10 @@ do_simple_async_set3(Config) -> AgentNode = ?config(agent_node, Config), TargetName = ?config(manager_agent_target_name, Config), - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), Self = self(), Msg = simple_async_set3, @@ -3217,7 +3231,7 @@ do_simple_async_set3(MgrNode, AgentNode, Set, PostVerify) -> ?IPRINT("agent info when starting test: " "~n ~p", [agent_info(AgentNode)]), - ?line ok = async_exec(Requests, []), + ok = async_exec(Requests, []), ?IPRINT("manager info when ending test: " "~n ~p", [mgr_info(MgrNode)]), @@ -3270,10 +3284,10 @@ check_ssgb_vbs([R|_], [E|_]) -> %%====================================================================== -simple_sync_get_bulk3(doc) -> - ["Simple (sync) get_bulk-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_sync_get_bulk3(suite) -> []; +simple_sync_get_bulk3() -> + [{doc, "Simple (sync) get_bulk-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_sync_get_bulk3(Config) when is_list(Config) -> ?TC_TRY(simple_sync_get_bulk3, fun() -> do_simple_sync_get_bulk3(Config) end). @@ -3310,34 +3324,34 @@ do_simple_sync_get_bulk3(Config) -> do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> %% -- 1 -- - ?line ok = do_simple_get_bulk3(1, + ok = do_simple_get_bulk3(1, 1, 1, [], fun verify_ssgb_reply1/1, GetBulk, PostVerify), %% -- 2 -- - ?line ok = do_simple_get_bulk3(2, + ok = do_simple_get_bulk3(2, -1, 1, [], fun verify_ssgb_reply1/1, GetBulk, PostVerify), %% -- 3 -- - ?line ok = do_simple_get_bulk3(3, + ok = do_simple_get_bulk3(3, -1, -1, [], fun verify_ssgb_reply1/1, GetBulk, PostVerify), - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), %% -- 4 -- VF04 = fun(X) -> verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView]) end, - ?line ok = do_simple_get_bulk3(4, + ok = do_simple_get_bulk3(4, 2, 0, [[sysDescr],[1,3,7,1]], VF04, GetBulk, PostVerify), %% -- 5 -- - ?line ok = do_simple_get_bulk3(5, + ok = do_simple_get_bulk3(5, 1, 2, [[sysDescr],[1,3,7,1]], VF04, GetBulk, PostVerify), @@ -3347,7 +3361,7 @@ do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> [?sysDescr_instance, endOfMibView, ?sysObjectID_instance, endOfMibView]) end, - ?line ok = do_simple_get_bulk3(6, + ok = do_simple_get_bulk3(6, 0, 2, [[sysDescr],[1,3,7,1]], VF06, GetBulk, PostVerify), @@ -3358,15 +3372,15 @@ do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> ?sysDescr_instance, endOfMibView, ?sysObjectID_instance, endOfMibView]) end, - ?line ok = do_simple_get_bulk3(7, + ok = do_simple_get_bulk3(7, 2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]], VF07, GetBulk, PostVerify), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), %% -- 8 -- VF08 = fun(X) -> @@ -3374,14 +3388,14 @@ do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> [?sysDescr_instance, ?sysDescr_instance]) end, - ?line ok = do_simple_get_bulk3(8, + ok = do_simple_get_bulk3(8, 1, 2, [[sysDescr],[sysDescr],[tTooBig]], VF08, GetBulk, PostVerify), %% -- 9 -- - ?line ok = do_simple_get_bulk3(9, + ok = do_simple_get_bulk3(9, 1, 12, [[tDescr2], [sysDescr]], fun verify_ssgb_reply1/1, @@ -3395,7 +3409,7 @@ do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> {?tGenErr1, 'NULL'}, {?sysDescr, 'NULL'}]) end, - ?line ok = do_simple_get_bulk3(10, + ok = do_simple_get_bulk3(10, 2, 2, [[sysDescr], [sysObjectID], @@ -3405,14 +3419,14 @@ do_simple_sync_get_bulk3(Config, MgrNode, AgentNode, GetBulk, PostVerify) -> GetBulk, PostVerify), %% -- 11 -- - ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), + {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), ?IPRINT("TCnt2: ~p", [TCnt2]), VF11 = fun(X) -> verify_ssgb_reply2(X, [{fl([TCnt2,2]), 100}, {fl([TCnt2,2]), endOfMibView}]) end, - ?line ok = do_simple_get_bulk3(11, + ok = do_simple_get_bulk3(11, 0, 2, [[TCnt2, 1]], VF11, GetBulk, PostVerify), @@ -3440,10 +3454,10 @@ do_simple_get_bulk3(N, %%====================================================================== -simple_async_get_bulk3_cbp_def(doc) -> - ["Simple (async) get_bulk-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_bulk3_cbp_def(suite) -> []; +simple_async_get_bulk3_cbp_def() -> + [{doc, "Simple (async) get_bulk-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_bulk3_cbp_def(Config) when is_list(Config) -> simple_async_get_bulk3(sagb3_cbp_def, Config). @@ -3460,10 +3474,10 @@ do_simple_async_get_bulk3(Config) -> AgentNode = ?config(agent_node, Config), TargetName = ?config(manager_agent_target_name, Config), - ?line ok = mgr_user_load_mib(MgrNode, std_mib()), + ok = mgr_user_load_mib(MgrNode, std_mib()), Test2Mib = test2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), Self = self(), Msg = simple_async_get_bulk3, @@ -3519,7 +3533,7 @@ do_simple_async_get_bulk3(MgrNode, AgentNode, GetBulk, PostVerify) -> {?tGenErr1, 'NULL'}, {?sysDescr, 'NULL'}])) end, - ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), + {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2), VF11 = fun(X) -> PostVerify( verify_ssgb_reply2(X, @@ -3602,7 +3616,7 @@ do_simple_async_get_bulk3(MgrNode, AgentNode, GetBulk, PostVerify) -> ?IPRINT("agent info when starting test: " "~n ~p", [agent_info(AgentNode)]), - ?line ok = async_exec(Requests, []), + ok = async_exec(Requests, []), ?IPRINT("manager info when ending test: " "~n ~p", [mgr_info(MgrNode)]), @@ -3618,59 +3632,59 @@ async_gb_exec3(Node, TargetName, {NR, MR, Oids}, SendOpts) -> %%====================================================================== -simple_async_get_bulk3_cbp_temp(doc) -> - ["Simple (async) get_bulk-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_bulk3_cbp_temp(suite) -> []; +simple_async_get_bulk3_cbp_temp() -> + [{doc, "Simple (async) get_bulk-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_bulk3_cbp_temp(Config) when is_list(Config) -> simple_async_get_bulk3(sagb3_cbp_temp, Config). %%====================================================================== -simple_async_get_bulk3_cbp_perm(doc) -> - ["Simple (async) get_bulk-request - " - "Version 3 API (TargetName with send-opts)"]; -simple_async_get_bulk3_cbp_perm(suite) -> []; +simple_async_get_bulk3_cbp_perm() -> + [{doc, "Simple (async) get_bulk-request - " + "Version 3 API (TargetName with send-opts)"}]. + simple_async_get_bulk3_cbp_perm(Config) when is_list(Config) -> simple_async_get_bulk3(sagb3_cbp_perm, Config). %%====================================================================== -simple_v3_exchange_md5(doc) -> - ["Simple message exchange using v3 (MD5) messages"]; -simple_v3_exchange_md5(suite) -> []; +simple_v3_exchange_md5() -> + [{doc, "Simple message exchange using v3 (MD5) messages"}]. + simple_v3_exchange_md5(Config) when is_list(Config) -> simple_v3_exchange(Config). -simple_v3_exchange_sha(doc) -> - ["Simple message exchange using v3 (SHA) messages"]; -simple_v3_exchange_sha(suite) -> []; +simple_v3_exchange_sha() -> + [{doc, "Simple message exchange using v3 (SHA) messages"}]. + simple_v3_exchange_sha(Config) when is_list(Config) -> simple_v3_exchange(Config). -simple_v3_exchange_sha224(doc) -> - ["Simple message exchange using v3 (SHA224) messages"]; -simple_v3_exchange_sha224(suite) -> []; +simple_v3_exchange_sha224() -> + [{doc, "Simple message exchange using v3 (SHA224) messages"}]. + simple_v3_exchange_sha224(Config) when is_list(Config) -> simple_v3_exchange(Config). -simple_v3_exchange_sha256(doc) -> - ["Simple message exchange using v3 (SHA256) messages"]; -simple_v3_exchange_sha256(suite) -> []; +simple_v3_exchange_sha256() -> + [{doc, "Simple message exchange using v3 (SHA256) messages"}]. + simple_v3_exchange_sha256(Config) when is_list(Config) -> simple_v3_exchange(Config). -simple_v3_exchange_sha384(doc) -> - ["Simple message exchange using v3 (SHA384) messages"]; -simple_v3_exchange_sha384(suite) -> []; +simple_v3_exchange_sha384() -> + [{doc, "Simple message exchange using v3 (SHA384) messages"}]. + simple_v3_exchange_sha384(Config) when is_list(Config) -> simple_v3_exchange(Config). -simple_v3_exchange_sha512(doc) -> - ["Simple message exchange using v3 (SHA512) messages"]; -simple_v3_exchange_sha512(suite) -> []; +simple_v3_exchange_sha512() -> + [{doc, "Simple message exchange using v3 (SHA512) messages"}]. + simple_v3_exchange_sha512(Config) when is_list(Config) -> simple_v3_exchange(Config). @@ -3707,7 +3721,6 @@ simple_v3_exchange(Config) when is_list(Config) -> %%====================================================================== -discovery(suite) -> []; discovery(Config) when is_list(Config) -> ?SKIP(not_yet_implemented). @@ -3772,7 +3785,6 @@ verify_trap(Trap, [{Id, Verifier}|Verifiers]) -> %%====================================================================== -trap1(suite) -> []; trap1(Config) when is_list(Config) -> ?TC_TRY(trap1, fun() -> do_trap1(Config) end). @@ -3785,16 +3797,16 @@ do_trap1(Config) -> MgrNode = ?config(manager_node, Config), AgentNode = ?config(agent_node, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), %% Version 1 trap verification function: VerifyTrap_v1 = @@ -3933,7 +3945,6 @@ do_trap1(Config) -> %%====================================================================== -trap2(suite) -> []; trap2(Config) when is_list(Config) -> ?TC_TRY(trap2, fun() -> do_trap2(Config) end). @@ -3946,16 +3957,16 @@ do_trap2(Config) -> MgrNode = ?config(manager_node, Config), AgentNode = ?config(agent_node, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), %% Version 1 trap verification function: VerifyTrap_v1 = @@ -4132,7 +4143,6 @@ do_trap2(Config) -> %%====================================================================== -inform1(suite) -> []; inform1(Config) when is_list(Config) -> ?TC_TRY(inform1, fun() -> do_inform1(Config) end). @@ -4145,16 +4155,16 @@ do_inform1(Config) -> MgrNode = ?config(manager_node, Config), AgentNode = ?config(agent_node, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), Cmd1 = @@ -4252,7 +4262,7 @@ do_inform1(Config) -> Commands = [ {1, "Manager and agent info at start of test", Cmd1}, - {2, "Send notifcation [no receiver] from agent", Cmd2}, + {2, "Send notification [no receiver] from agent", Cmd2}, {3, "Await first inform to manager - do not reply", Cmd3}, {4, "Await second inform to manager - reply", Cmd4}, {5, "Sleep some time (5 sec)", Cmd5}, @@ -4266,7 +4276,6 @@ do_inform1(Config) -> %%====================================================================== -inform2(suite) -> []; inform2(Config) when is_list(Config) -> ?TC_TRY(inform2, fun() -> do_inform2(Config) end). @@ -4281,16 +4290,16 @@ do_inform2(Config) -> %% Addr = ?config(ip, Config), %% Port = ?AGENT_PORT, - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), Cmd1 = fun() -> @@ -4428,7 +4437,7 @@ do_inform2(Config) -> Commands = [ {1, "Manager and agent info at start of test", Cmd1}, - {2, "Send notifcation [no receiver] from agent", Cmd2}, + {2, "Send notification [no receiver] from agent", Cmd2}, {3, "Await inform-sent acknowledge from agent", Cmd3}, {4, "Await first inform to manager - do not reply", Cmd4}, {5, "Await second inform to manager - reply", Cmd5}, @@ -4444,7 +4453,6 @@ do_inform2(Config) -> %%====================================================================== -inform3(suite) -> []; inform3(Config) when is_list(Config) -> ?TC_TRY(inform3, fun() -> do_inform3(Config) end). @@ -4456,16 +4464,16 @@ do_inform3(Config) -> MgrNode = ?config(manager_node, Config), AgentNode = ?config(agent_node, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), Cmd1 = fun() -> @@ -4567,7 +4575,7 @@ do_inform3(Config) -> Commands = [ {1, "Manager and agent info at start of test", Cmd1}, - {2, "Send notifcation from agent", Cmd2}, + {2, "Send notification from agent", Cmd2}, {3, "await inform-sent acknowledge from agent", Cmd3}, {4, "Await first inform to manager - do not reply", Cmd4}, {5, "Await first inform to manager - do not reply", Cmd4}, @@ -4584,7 +4592,6 @@ do_inform3(Config) -> %%====================================================================== -inform4(suite) -> []; inform4(Config) when is_list(Config) -> ?TC_TRY(inform4, fun() -> do_inform4(Config) end). @@ -4596,16 +4603,16 @@ do_inform4(Config) -> MgrNode = ?config(manager_node, Config), AgentNode = ?config(agent_node, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), Cmd1 = fun() -> @@ -4693,7 +4700,7 @@ do_inform4(Config) -> Commands = [ {1, "Manager and agent info at start of test", Cmd1}, - {2, "Send notifcation [no receiver] from agent", Cmd2}, + {2, "Send notification [no receiver] from agent", Cmd2}, {3, "Await inform to manager", Cmd3}, %% {4, "Await error info (because of erroneous config)", Cmd4}, {5, "Sleep some time (1 sec)", Cmd5}, @@ -4709,15 +4716,12 @@ do_inform4(Config) -> %% %% Test: ts:run(snmp, snmp_manager_test, inform_swarm_cbp_def, [batch]). -inform_swarm_cbp_def(suite) -> []; inform_swarm_cbp_def(Config) when is_list(Config) -> inform_swarm(is_cbp_def, 1500, Config). -inform_swarm_cbp_temp(suite) -> []; inform_swarm_cbp_temp(Config) when is_list(Config) -> inform_swarm(is_cbp_temp, 1500, Config). -inform_swarm_cbp_perm(suite) -> []; inform_swarm_cbp_perm(Config) when is_list(Config) -> inform_swarm(is_cbp_perm, 1800, Config). @@ -4736,16 +4740,16 @@ do_inform_swarm(NumI, Config) -> AgentNode = ?config(agent_node, Config), Factor = ?config(snmp_factor, Config), - ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), + ok = mgr_user_load_mib(MgrNode, snmpv2_mib()), Test2Mib = test2_mib(Config), TestTrapMib = test_trap_mib(Config), TestTrapv2Mib = test_trap_v2_mib(Config), - ?line ok = mgr_user_load_mib(MgrNode, Test2Mib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib), - ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), - ?line ok = agent_load_mib(AgentNode, Test2Mib), - ?line ok = agent_load_mib(AgentNode, TestTrapMib), - ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib), + ok = mgr_user_load_mib(MgrNode, Test2Mib), + ok = mgr_user_load_mib(MgrNode, TestTrapMib), + ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib), + ok = agent_load_mib(AgentNode, Test2Mib), + ok = agent_load_mib(AgentNode, TestTrapMib), + ok = agent_load_mib(AgentNode, TestTrapv2Mib), NumInforms = NumI div Factor, Collector = self(), @@ -4807,7 +4811,7 @@ do_inform_swarm(NumI, Config) -> Commands = [ {1, "Manager and agent info at start of test", Cmd1}, - {2, ?F("Send ~p notifcation(s) from agent", [NumInforms]), Cmd2}, + {2, ?F("Send ~p notification(s) from agent", [NumInforms]), Cmd2}, {3, "Await send-ack(s)/inform(s)/response(s)", Cmd3}, {4, "Sleep some time (1 sec)", Cmd4}, {5, "Manager and agent info after test completion", Cmd1} @@ -4823,7 +4827,7 @@ inform_swarm_collector(N) -> %% Note that we need to deal with re-transmissions! %% That is, the agent did not receive the ack in time, -%% and therefor did a re-transmit. This means that we +%% and therefore did a re-transmit. This means that we %% expect to receive more inform's then we actually %% sent. So for success we assume: %% @@ -4900,7 +4904,6 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) -> %%====================================================================== -report(suite) -> []; report(Config) when is_list(Config) -> ?SKIP(not_yet_implemented). @@ -4908,8 +4911,9 @@ report(Config) when is_list(Config) -> %%====================================================================== -otp8015_1(doc) -> ["OTP-8015:1 - testing the new api-function."]; -otp8015_1(suite) -> []; +otp8015_1() -> + [{doc, "OTP-8015:1 - testing the new api-function."}]. + otp8015_1(Config) when is_list(Config) -> Pre = fun() -> SCO = ?config(socket_create_opts, Config), @@ -4965,8 +4969,9 @@ do_otp8015_1(Config) -> %%====================================================================== -otp8395_1(doc) -> ["OTP-8395:1 - simple get with ATL sequence numbering."]; -otp8395_1(suite) -> []; +otp8395_1() -> + [{doc, "OTP-8395:1 - simple get with ATL sequence numbering."}]. + otp8395_1(Config) when is_list(Config) -> ?TC_TRY(otp8395_1, fun() -> do_otp8395_1(Config) end). @@ -4984,7 +4989,7 @@ async_exec([], Acc) -> async_verify(async_collector(Acc, [])); async_exec([{Id, Data, Exec, Ver}|Reqs], Acc) -> ?IPRINT("issue async request ~w", [Id]), - ?line {ok, ReqId} = Exec(Data), + {ok, ReqId} = Exec(Data), async_exec(Reqs, [{ReqId, Id, Ver}|Acc]). async_collector([], Acc) -> @@ -5079,17 +5084,17 @@ command_handler([{No, Desc, Cmd}|Cmds]) -> {error, Reason} -> ?EPRINT("Command_handler -> ~w error: " "~n ~p", [No, Reason]), - ?line ?FAIL({command_failed, No, Reason}); + ?FAIL({command_failed, No, Reason}); Error -> ?EPRINT("Command_handler -> ~w unexpected: " "~n ~p", [No, Error]), - ?line ?FAIL({unexpected_command_result, No, Error}) + ?FAIL({unexpected_command_result, No, Error}) end. %% -- Misc manager functions -- -init_manager(AutoInform, Config) -> +init_manager(Case, AutoInform, Config) -> ?IPRINT("init_manager -> entry with" "~n AutoInform: ~p" @@ -5099,7 +5104,7 @@ init_manager(AutoInform, Config) -> %% Start node %% - ?line Node = start_manager_node(), + {Peer, Node} = start_node(lists:concat([Case, "-mgr"])), %% The point with this (try catch block) is to be %% able to do some cleanup in case we fail to @@ -5114,13 +5119,13 @@ init_manager(AutoInform, Config) -> %% Start and initiate crypto on manager node %% - ?line ok = init_crypto(Node), + ok = init_crypto(Node), %% %% Write manager config %% - ?line ok = write_manager_config(Config), + ok = write_manager_config(Config), IRB = case AutoInform of true -> @@ -5128,7 +5133,7 @@ init_manager(AutoInform, Config) -> _ -> user end, - Conf = [{manager_node, Node}, {irb, IRB} | Config], + Conf = [{manager_node, Node}, {manager_peer, Peer}, {irb, IRB} | Config], Vsns = [v1,v2,v3], start_manager(Node, Vsns, Conf) end @@ -5138,7 +5143,7 @@ init_manager(AutoInform, Config) -> "~n Reason: ~p" "~n StackTrace: ~p", [Reason, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), erlang:raise(C, E, S); C:E:S -> ?EPRINT("Failure during manager start: " @@ -5146,11 +5151,11 @@ init_manager(AutoInform, Config) -> "~n Error: ~p" "~n StackTrace: ~p", [C, E, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), ?FAIL({failed_starting_manager, C, E, S}) end. -init_v3_manager(Config) -> +init_v3_manager(Case, Config) -> ?IPRINT("init_v3_manager -> entry with" "~n Config: ~p", [Config]), @@ -5159,8 +5164,7 @@ init_v3_manager(Config) -> %% Start node %% - %% ?line Node = self(), - ?line Node = start_unique_manager_node(), + {Peer, Node} = start_node(lists:concat([Case, "-v3mgr"])), %% The point with this (try catch block) is to be %% able to do some cleanup in case we fail to @@ -5175,7 +5179,7 @@ init_v3_manager(Config) -> %% Start and initiate crypto on manager node %% - ?line ok = init_crypto(Node), + ok = init_crypto(Node), %% %% Write manager config @@ -5183,10 +5187,10 @@ init_v3_manager(Config) -> %% DomainType is just a "dummy" arg to make the %% function choose transportDomainUdpIpv4 as transport domain. - ?line ok = write_manager_config(transport, Config), + ok = write_manager_config(transport, Config), IRB = auto, - Conf = [{manager_node, Node}, {irb, IRB} | Config], + Conf = [{manager_node, Node}, {manager_peer, Peer}, {irb, IRB} | Config], Vsns = [v3], start_manager(Node, Vsns, Conf) end @@ -5196,7 +5200,7 @@ init_v3_manager(Config) -> "~n Reason: ~p" "~n StackTrace: ~p", [Reason, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), erlang:raise(C, E, S); C:E:S -> ?EPRINT("Failure during manager start: " @@ -5204,7 +5208,7 @@ init_v3_manager(Config) -> "~n Error: ~p" "~n StackTrace: ~p", [C, E, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), ?FAIL({failed_starting_manager, C, E, S}) end. @@ -5215,7 +5219,7 @@ fin_manager(Config) -> Node = ?config(manager_node, Config), StopMgrRes = stop_manager(Node), StopCryptoRes = fin_crypto(Node), - StopNode = stop_node(Node), + StopNode = peer:stop(?config(manager_peer, Config)), ?IPRINT("fin_manager -> stop apps and (mgr node ~p) node results: " "~n SNMP Mgr: ~p" "~n Crypto: ~p" @@ -5226,7 +5230,7 @@ fin_manager(Config) -> %% -- Misc agent functions -- -init_agent(Config) -> +init_agent(Case, Config) -> ?IPRINT("init_agent -> entry with" "~n Config: ~p", [Config]), @@ -5240,7 +5244,7 @@ init_agent(Config) -> %% Start node %% - ?line Node = start_agent_node(), + {Peer, Node} = start_node(lists:concat([Case, "-agent"])), %% The point with this (try catch block) is to be %% able to do some cleanup in case we fail to @@ -5255,14 +5259,14 @@ init_agent(Config) -> %% Start and initiate mnesia on agent node %% - ?line ok = init_mnesia(Node, Dir, ?config(mnesia_debug, Config)), + ok = init_mnesia(Node, Dir, ?config(mnesia_debug, Config)), %% -- %% Start and initiate crypto on agent node %% - ?line ok = init_crypto(Node), + ok = init_crypto(Node), %% @@ -5270,9 +5274,9 @@ init_agent(Config) -> %% Vsns = [v1,v2], - ?line ok = write_agent_config(Vsns, Config), + ok = write_agent_config(Vsns, Config), - Conf = [{agent_node, Node}, + Conf = [{agent_node, Node}, {agent_peer, Peer}, {mib_dir, MibDir} | Config], %% @@ -5287,7 +5291,7 @@ init_agent(Config) -> "~n Reason: ~p" "~n StackTrace: ~p", [Reason, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), erlang:raise(C, E, S); C:E:S -> ?EPRINT("Failure during agent start: " @@ -5295,12 +5299,12 @@ init_agent(Config) -> "~n Error: ~p" "~n StackTrace: ~p", [C, E, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), ?FAIL({failed_starting_agent, C, E, S}) end. -init_v3_agent(Config) -> +init_v3_agent(Case, Config) -> ?IPRINT("init_v3_agent -> entry with" "~n Config: ~p", [Config]), @@ -5315,7 +5319,7 @@ init_v3_agent(Config) -> %% %% ?line Node = self(), - ?line Node = start_unique_agent_node(), + ?line {Peer, Node} = start_node(lists:concat([Case, "-v3agent"])), %% The point with this (try catch block) is to be %% able to do some cleanup in case we fail to @@ -5330,7 +5334,7 @@ init_v3_agent(Config) -> %% Start and initiate crypto on agent node %% - ?line ok = init_crypto(Node), + ok = init_crypto(Node), %% @@ -5338,9 +5342,9 @@ init_v3_agent(Config) -> %% Vsns = [v3], - ?line ok = write_agent_config(Vsns, Config), + ok = write_agent_config(Vsns, Config), - Conf = [{agent_node, Node}, + Conf = [{agent_node, Node}, {agent_peer, Peer}, {mib_dir, MibDir} | Config], %% @@ -5355,7 +5359,7 @@ init_v3_agent(Config) -> "~n Reason: ~p" "~n StackTrace: ~p", [Reason, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), erlang:raise(C, E, S); C:E:S -> ?EPRINT("Failure during agent start: " @@ -5363,7 +5367,7 @@ init_v3_agent(Config) -> "~n Error: ~p" "~n StackTrace: ~p", [C, E, S]), %% And now, *try* to cleanup - (catch stop_node(Node)), + (catch peer:stop(Peer)), ?FAIL({failed_starting_agent, C, E, S}) end. @@ -5373,7 +5377,7 @@ fin_agent(Config) -> StopAgentRes = stop_agent(Node), StopCryptoRes = fin_crypto(Node), StopMnesiaRes = fin_mnesia(Node), - StopNode = stop_node(Node), + StopNode = peer:stop(?config(agent_peer, Config)), ?IPRINT("fin_agent -> stop apps and (agent node ~p) node results: " "~n SNMP Agent: ~p" "~n Crypto: ~p" @@ -5386,7 +5390,7 @@ fin_v3_agent(Config) -> Node = ?config(agent_node, Config), StopAgentRes = stop_agent(Node), StopCryptoRes = fin_crypto(Node), - StopNode = stop_node(Node), + StopNode = peer:stop(?config(agent_peer, Config)), ?IPRINT("fin_agent -> stop apps and (agent node ~p) node results: " "~n SNMP Agent: ~p" "~n Crypto: ~p" @@ -5400,52 +5404,52 @@ init_mnesia(Node, Dir, MnesiaDebug) init_mnesia(Node, Dir, ?DEFAULT_MNESIA_DEBUG); init_mnesia(Node, Dir, MnesiaDebug) -> ?DBG("init_mnesia -> load application mnesia", []), - ?line ok = load_mnesia(Node), + ok = load_mnesia(Node), ?DBG("init_mnesia -> application mnesia: set_env dir: ~n~p",[Dir]), - ?line ok = set_mnesia_env(Node, dir, filename:join(Dir, "mnesia")), + ok = set_mnesia_env(Node, dir, filename:join(Dir, "mnesia")), %% Just in case, only set (known to be) valid values for debug if ((MnesiaDebug =:= debug) orelse (MnesiaDebug =:= trace)) -> ?DBG("init_mnesia -> application mnesia: set_env debug: ~w", [MnesiaDebug]), - ?line ok = set_mnesia_env(Node, debug, MnesiaDebug); + ok = set_mnesia_env(Node, debug, MnesiaDebug); true -> ok end, ?DBG("init_mnesia -> create mnesia schema",[]), - ?line case create_schema(Node) of + case create_schema(Node) of ok -> ok; {error, {Node, {already_exists, Node}}} -> - ?line ok = delete_schema(Node), - ?line ok = create_schema(Node); + ok = delete_schema(Node), + ok = create_schema(Node); Error -> ?FAIL({failed_creating_mnesia_schema, Error}) end, ?DBG("init_mnesia -> start application mnesia",[]), - ?line ok = start_mnesia(Node), + ok = start_mnesia(Node), ?DBG("init_mnesia -> create tables",[]), - ?line ok = create_tables(Node), + ok = create_tables(Node), ok. fin_mnesia(Node) -> - ?line ok = delete_tables(Node), - ?line ok = stop_mnesia(Node), + ok = delete_tables(Node), + ok = stop_mnesia(Node), ok. init_crypto(Node) -> - ?line ok = load_crypto(Node), - ?line ok = start_crypto(Node), + ok = load_crypto(Node), + ok = start_crypto(Node), ok. fin_crypto(Node) -> - ?line ok = stop_crypto(Node), + ok = stop_crypto(Node), ok. @@ -5662,7 +5666,7 @@ init_mgr_user(Conf) -> Node = ?config(manager_node, Conf), %% UserId = ?config(user_id, Conf), - ?line {ok, User} = mgr_user_start(Node), + {ok, User} = mgr_user_start(Node), ?DBG("start_mgr_user -> User: ~p", [User]), link(User), @@ -5675,7 +5679,7 @@ init_mgr_v3_user(Conf) -> Node = ?config(manager_node, Conf), %% UserId = ?config(user_id, Conf), - ?line {ok, User} = mgr_user_start(Node), + {ok, User} = mgr_user_start(Node), ?IPRINT("start_mgr_v3_user -> User: ~p", [User]), link(User), @@ -5687,7 +5691,7 @@ init_mgr_v3_user(Conf) -> [ {auth, select_auth_proto(AuthAlg)}, {auth_key, AuthKey} ], - ?line ok = mgr_register_usm_user(Node, EngineID, SecName, Credentials), + ok = mgr_register_usm_user(Node, EngineID, SecName, Credentials), ?IPRINT("start_mgr_v3_user -> done"), [{user_pid, User} | Conf]. @@ -5723,7 +5727,7 @@ fin_mgr_user(Conf) -> User = ?config(user_pid, Conf), unlink(User), Node = ?config(manager_node, Conf), - ?line ok = mgr_user_stop(Node), + ok = mgr_user_stop(Node), Conf. init_mgr_user_data1(Conf) -> @@ -5732,7 +5736,7 @@ init_mgr_user_data1(Conf) -> IpFamily = ?config(ipfamily, Conf), Ip = ?config(ip, Conf), Port = ?AGENT_PORT, - ?line ok = + ok = case IpFamily of inet -> mgr_user_register_agent( @@ -5750,19 +5754,19 @@ init_mgr_user_data1(Conf) -> _Agents = mgr_user_which_own_agents(Node), ?DBG("Own agents: ~p", [_Agents]), - ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), ?DBG("Default agent config: ~n~p", [_DefAgentConf]), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, community, "all-rights"), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, sec_name, "all-rights"), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, engine_id, "agentEngine"), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, max_message_size, 1024), - ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), ?DBG("Updated agent config: ~n~p", [_AgentConf]), Conf. @@ -5774,7 +5778,7 @@ init_mgr_user_data2(Conf) -> IpFamily = ?config(ipfamily, Conf), Ip = ?config(ip, Conf), Port = ?AGENT_PORT, - ?line ok = + ok = case IpFamily of inet -> mgr_user_register_agent( @@ -5792,17 +5796,17 @@ init_mgr_user_data2(Conf) -> _Agents = mgr_user_which_own_agents(Node), ?DBG("Own agents: ~p", [_Agents]), - ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), ?DBG("Default agent config: ~n~p", [_DefAgentConf]), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, community, "all-rights"), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, sec_name, "all-rights"), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, max_message_size, 1024), - ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), ?DBG("Updated agent config: ~n~p", [_AgentConf]), Conf. @@ -5814,7 +5818,7 @@ init_mgr_v3_user_data(Conf) -> IpFamily = ?config(ipfamily, Conf), Ip = ?config(ip, Conf), Port = ?AGENT_PORT, - ?line ok = + ok = case IpFamily of inet -> mgr_user_register_agent( @@ -5834,22 +5838,22 @@ init_mgr_v3_user_data(Conf) -> _Agents = mgr_user_which_own_agents(Node), ?IPRINT("Own agents: ~p", [_Agents]), - ?line {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _DefAgentConf} = mgr_user_agent_info(Node, TargetName, all), ?IPRINT("Default agent config: ~n~p", [_DefAgentConf]), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, community, "all-rights"), SecName = select_secname_from_authalg(?config(auth_alg, Conf)), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, sec_name, SecName), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, sec_level, authNoPriv), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, sec_model, usm), - ?line ok = mgr_user_update_agent_info(Node, TargetName, + ok = mgr_user_update_agent_info(Node, TargetName, max_message_size, 1024), - ?line {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), + {ok, _AgentConf} = mgr_user_agent_info(Node, TargetName, all), ?IPRINT("Updated agent config: ~n~p", [_AgentConf]), Conf. @@ -5992,9 +5996,9 @@ start_manager(Node, Vsns, Conf0, _Opts) -> {cbproxy, CBP}, {netif_sup, NIS}]}, {net_if, NetIfConf}], - ?line ok = set_mgr_env(Node, Env), + ok = set_mgr_env(Node, Env), - ?line ok = try start_snmp(Node) of + ok = try start_snmp(Node) of ok -> ok; {error, Reason} -> @@ -6059,9 +6063,9 @@ start_agent(Node, Vsns, Conf0, _Opts) -> %% (which will cause problems for some test cases). {options, [{bind_to, true}]}]}, {multi_threaded, true}], - ?line ok = set_agent_env(Node, Env), + ok = set_agent_env(Node, Env), - ?line try start_snmp(Node) of + try start_snmp(Node) of ok -> ok; {error, Reason} -> @@ -6100,87 +6104,12 @@ agent_info(Node) -> %% -- Misc node operation wrapper functions -- -unique(PreName) -> - list_to_atom(?F("~w_~w", [PreName, erlang:system_time(millisecond)])). - -start_agent_node() -> - start_node(snmp_agent). - -start_unique_agent_node() -> - start_unique_node(snmp_agent). - -start_manager_node() -> - start_node(snmp_manager). - -start_unique_manager_node() -> - start_unique_node(snmp_manager). - -%% Generate a "unique" (node-) name and start a node with this name. -start_unique_node(BaseName) when is_atom(BaseName) -> - start_node(unique(BaseName), false). - -start_node(Name) -> - start_node(Name, true). -start_node(Name, Retry) -> - - ?IPRINT("start_node -> entry with" - "~n Name: ~p" - "~n when" - "~n hostname of this node: ~p", - [Name, list_to_atom(?HOSTNAME(node()))]), - - Pa = filename:dirname(code:which(?MODULE)), - - A = " -pa " ++ Pa ++ - " -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++ - " -s global sync", - try ?START_NODE(Name, A) of - {ok, Node} -> - global:sync(), - Node; - {error, timeout} -> - ?EPRINT("Failed starting node ~p: timeout", [Name]), - ?line ?FAIL({error_starting_node, Name, timeout}); - {error, {already_running, Node}} when (Retry =:= true) -> - %% Ouch - %% Either we previously failed to (properly) stop the node - %% or it was a failed start, that reported failure (for instance - %% timeout) but actually succeeded. Regardless, we don't know - %% the state of this node, so (try) stop it and then (re-) try - %% start again. - ?WPRINT("Failed starting node ~p: Already Running - try stop", [Node]), - case ?STOP_NODE(Node) of - true -> - ?IPRINT("Successfully stopped old node ~p", [Node]), - start_node(Name, false); - false -> - ?EPRINT("Failed stop old node ~p", [Node]), - ?line ?FAIL({error_starting_node, Node, Retry, already_running}) - end; - {error, {already_running, Node}} -> - ?EPRINT("Failed starting node ~p: Already Running", [Node]), - ?line ?FAIL({error_starting_node, Node, Retry, already_running}); - {error, Reason} -> - ?EPRINT("Failed starting node ~p: ~p", [Name, Reason]), - ?line ?FAIL({error_starting_node, Name, Reason}) - catch - exit:{suite_failed, Reason} -> - ?EPRINT("(suite) Failed starting node ~p: ~p", [Name, Reason]), - ?line ?FAIL({failed_starting_node, Name, Reason}) - end. - - -stop_node(Node) when (Node =:= self()) -> - ok;%?line ?FAIL({stop_own_node, Node}); -stop_node(Node) -> - case ?STOP_NODE(Node) of - true -> - ok; - false -> - ?line ?FAIL({failed_stop_node, Node}) - end. - - +start_node(Case) -> + Args = ["-s", "snmp_test_sys_monitor", "start", "-s", "global", "sync"], + Name = peer:random_name(lists:concat([?MODULE, "-", Case])), + {ok, Peer, Node} = ?CT_PEER(#{name => Name, args => Args}), + global:sync(), + {Peer, Node}. %% -- Misc config wrapper functions -- @@ -6224,21 +6153,21 @@ write_manager_conf(Dir, Str) -> write_agent_config(Vsns, Conf) -> Dir = ?config(agent_conf_dir, Conf), - ?line Ip = tuple_to_list(?config(ip, Conf)), - ?line Domain = + Ip = tuple_to_list(?config(ip, Conf)), + Domain = case ?config(ipfamily, Conf) of inet -> transportDomainUdpIpv4; inet6 -> transportDomainUdpIpv6 end, - ?line ok = write_agent_config_files(Dir, Vsns, Domain, Ip), - ?line ok = update_agent_usm(Vsns, Dir), - ?line ok = update_agent_community(Vsns, Dir), - ?line ok = update_agent_vacm(Vsns, Dir), - ?line ok = write_agent_target_addr_conf(Dir, Domain, Ip, Vsns), - ?line ok = write_agent_target_params_conf(Dir, Vsns), - ?line ok = write_agent_notify_conf(Dir), + ok = write_agent_config_files(Dir, Vsns, Domain, Ip), + ok = update_agent_usm(Vsns, Dir), + ok = update_agent_community(Vsns, Dir), + ok = update_agent_vacm(Vsns, Dir), + ok = write_agent_target_addr_conf(Dir, Domain, Ip, Vsns), + ok = write_agent_target_params_conf(Dir, Vsns), + ok = write_agent_notify_conf(Dir), ok. write_agent_config_files(Dir, Vsns, Domain, Ip) -> @@ -6381,8 +6310,8 @@ write_agent_notify_conf(Dir) -> write_conf_file(Dir, File, Str) -> - ?line {ok, Fd} = file:open(filename:join(Dir, File), write), - ?line ok = io:format(Fd, "~s", [Str]), + {ok, Fd} = file:open(filename:join(Dir, File), write), + ok = io:format(Fd, "~s", [Str]), file:close(Fd). diff --git a/lib/snmp/test/snmp_manager_config_SUITE.erl b/lib/snmp/test/snmp_manager_config_SUITE.erl index f70f506fb01e..933be4e01625 100644 --- a/lib/snmp/test/snmp_manager_config_SUITE.erl +++ b/lib/snmp/test/snmp_manager_config_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -272,22 +272,22 @@ init_per_testcase(Case, Config) when is_list(Config) -> SuiteTopDir = ?config(snmp_suite_top_dir, Config), CaseTopDir = filename:join(SuiteTopDir, atom_to_list(Case)), - ?line ok = file:make_dir(CaseTopDir), + ok = file:make_dir(CaseTopDir), ?IPRINT("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]), MgrTopDir = filename:join(CaseTopDir, "manager/"), - ?line ok = file:make_dir(MgrTopDir), + ok = file:make_dir(MgrTopDir), MgrConfDir = filename:join(MgrTopDir, "conf/"), - ?line ok = file:make_dir(MgrConfDir), + ok = file:make_dir(MgrConfDir), MgrDbDir = filename:join(MgrTopDir, "db/"), case Case of start_with_create_db_and_dir_opt -> ok; _ -> - ?line ok = file:make_dir(MgrDbDir) + ok = file:make_dir(MgrDbDir) end, MgrLogDir = filename:join(MgrTopDir, "log/"), - ?line ok = file:make_dir(MgrLogDir), + ok = file:make_dir(MgrLogDir), Config1 = [{case_top_dir, CaseTopDir}, {manager_dir, MgrTopDir}, {manager_conf_dir, MgrConfDir}, @@ -308,7 +308,7 @@ end_per_testcase(_Case, Config) when is_list(Config) -> ?IPRINT("system events during test: " "~n ~p", [snmp_test_global_sys_monitor:events()]), - %% The cleanup is removed due to some really discusting NFS behaviour... + %% The cleanup is removed due to some really disgusting NFS behaviour... %% Also, it can always be useful to retain "all the stuff" after %% the test case in case of debugging... Config. @@ -338,8 +338,8 @@ simple_start_and_stop(Conf) when is_list(Conf) -> Opts = [{versions, [v1]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], - ?line {ok, _Pid} = snmpm_config:start_link(Opts), - ?line ok = snmpm_config:stop(), + {ok, _Pid} = snmpm_config:start_link(Opts), + ok = snmpm_config:stop(), ok. @@ -367,7 +367,7 @@ start_without_mandatory_opts1(Conf) when is_list(Conf) -> ?IPRINT("config option, but no dir"), Opts = [{priority, normal}, {config, [{verbosity, trace}, {db_dir, DbDir}]}, {mibs, []}], - ?line {error, {missing_mandatory,dir}} = config_start(Opts), + {error, {missing_mandatory,dir}} = config_start(Opts), ?IPRINT("done"), ok. @@ -395,7 +395,7 @@ start_without_mandatory_opts2(Conf) when is_list(Conf) -> ?IPRINT("no config option"), Opts = [{priority, normal}, {mibs, []}], - ?line {error, {missing_mandatory,config,[dir, db_dir]}} = + {error, {missing_mandatory,config,[dir, db_dir]}} = config_start(Opts), ?IPRINT("done"), @@ -456,8 +456,8 @@ start_with_all_valid_opts(Conf) when is_list(Conf) -> {priority, Prio}, {mibs, Mibs}, {versions, Vsns}], - ?line {ok, _Pid} = config_start(Opts), - ?line ok = config_stop(), + {ok, _Pid} = config_start(Opts), + ok = config_stop(), ?IPRINT("done"), ok. @@ -510,10 +510,10 @@ start_with_unknown_opts(Conf) when is_list(Conf) -> {priority, Prio}, {mibs, Mibs}, {versions, Vsns}], - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), ?IPRINT("(config) started - now stop"), - ?line ok = config_stop(), + ok = config_stop(), ?IPRINT("done"), ok. @@ -544,35 +544,35 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> NetIfOpts1 = [{module, snmpm_user}], %% Behaviour check will fail Opts01 = [{config, ConfigOpts}, {versions, [v1]}, {net_if, NetIfOpts1}], - ?line {error, Reason01} = config_start(Opts01), + {error, Reason01} = config_start(Opts01), ?IPRINT("net-if (module) res: ~p", [Reason01]), ?IPRINT("net-if - incorrect verbosity"), NetIfOpts2 = [{verbosity, invalid_verbosity}], Opts02 = [{config, ConfigOpts}, {versions, [v1]}, {net_if, NetIfOpts2}], - ?line {error, Reason02} = config_start(Opts02), + {error, Reason02} = config_start(Opts02), ?IPRINT("net-if (verbosity) res: ~p", [Reason02]), ?IPRINT("net-if - incorrect options"), NetIfOpts3 = [{options, invalid_options}], Opts03 = [{config, ConfigOpts}, {versions, [v1]}, {net_if, NetIfOpts3}], - ?line {error, Reason03} = config_start(Opts03), + {error, Reason03} = config_start(Opts03), ?IPRINT("net-if (options) res: ~p", [Reason03]), ?IPRINT("server - incorrect timeout (1)"), ServerOpts1 = [{timeout, invalid_timeout}], Opts08 = [{config, ConfigOpts}, {versions, [v1]}, {server, ServerOpts1}], - ?line {error, Reason08} = config_start(Opts08), + {error, Reason08} = config_start(Opts08), ?IPRINT("server (timeout) res: ~p", [Reason08]), ?IPRINT("server - incorrect timeout (2)"), ServerOpts2 = [{timeout, 0}], Opts09 = [{config, ConfigOpts}, {versions, [v1]}, {server, ServerOpts2}], - ?line {error, Reason09} = config_start(Opts09), + {error, Reason09} = config_start(Opts09), ?IPRINT("server (timeout) res: ~p", [Reason09]), ?IPRINT("server - incorrect timeout (3)"), @@ -580,7 +580,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts10 = [{config, ConfigOpts}, {versions, [v1]}, {server, ServerOpts3}], - ?line {error, Reason10} = config_start(Opts10), + {error, Reason10} = config_start(Opts10), ?IPRINT("server (timeout) res: ~p", [Reason10]), ?IPRINT("server - incorrect verbosity"), @@ -588,7 +588,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts11 = [{config, ConfigOpts}, {versions, [v1]}, {server, ServerOpts4}], - ?line {error, Reason11} = config_start(Opts11), + {error, Reason11} = config_start(Opts11), ?IPRINT("server (verbosity) res: ~p", [Reason11]), ?IPRINT("note-store - incorrect timeout (1)"), @@ -596,7 +596,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts12 = [{config, ConfigOpts}, {versions, [v1]}, {note_store, NoteStoreOpts1}], - ?line {error, Reason12} = config_start(Opts12), + {error, Reason12} = config_start(Opts12), ?IPRINT("note-store (timeout) res: ~p", [Reason12]), ?IPRINT("note-store - incorrect timeout (2)"), @@ -604,7 +604,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts13 = [{config, ConfigOpts}, {versions, [v1]}, {note_store, NoteStoreOpts2}], - ?line {error, Reason13} = config_start(Opts13), + {error, Reason13} = config_start(Opts13), ?IPRINT("note-store (timeout) res: ~p", [Reason13]), ?IPRINT("note-store - incorrect timeout (3)"), @@ -612,7 +612,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts14 = [{config, ConfigOpts}, {versions, [v1]}, {note_store, NoteStoreOpts3}], - ?line {error, Reason14} = config_start(Opts14), + {error, Reason14} = config_start(Opts14), ?IPRINT("note-store (timeout) res: ~p", [Reason14]), ?IPRINT("note-store - incorrect verbosity"), @@ -620,28 +620,28 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts15 = [{config, ConfigOpts}, {versions, [v1]}, {note_store, NoteStoreOpts4}], - ?line {error, Reason15} = config_start(Opts15), + {error, Reason15} = config_start(Opts15), ?IPRINT("note-store (verbosity) res: ~p", [Reason15]), ?IPRINT("config - incorrect dir (1)"), ConfigOpts1 = [{dir, invalid_dir}], Opts16 = [{config, ConfigOpts1}, {versions, [v1]}], - ?line {error, Reason16} = config_start(Opts16), + {error, Reason16} = config_start(Opts16), ?IPRINT("config (dir) res: ~p", [Reason16]), ?IPRINT("config - incorrect dir (2)"), ConfigOpts2 = [{dir, "/invalid/dir"}], Opts17 = [{config, ConfigOpts2}, {versions, [v1]}], - ?line {error, Reason17} = config_start(Opts17), + {error, Reason17} = config_start(Opts17), ?IPRINT("config (dir) res: ~p", [Reason17]), ?IPRINT("config - incorrect verbosity"), ConfigOpts3 = [{dir, ConfDir}, {verbosity, invalid_verbosity}], Opts18 = [{config, ConfigOpts3}, {versions, [v1]}], - ?line {error, Reason18} = config_start(Opts18), + {error, Reason18} = config_start(Opts18), ?IPRINT("config (verbosity) res: ~p", [Reason18]), ?IPRINT("mibs - incorrect mibs (1)"), @@ -649,7 +649,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts19 = [{config, ConfigOpts}, {versions, [v1]}, {mibs, Mibs1}], - ?line {error, Reason19} = config_start(Opts19), + {error, Reason19} = config_start(Opts19), ?IPRINT("mibs (mibs) res: ~p", [Reason19]), ?IPRINT("mibs - incorrect mibs (2)"), @@ -657,7 +657,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts20 = [{config, ConfigOpts}, {versions, [v1]}, {mibs, Mibs2}], - ?line {error, Reason20} = config_start(Opts20), + {error, Reason20} = config_start(Opts20), ?IPRINT("mibs (mibs) res: ~p", [Reason20]), ?IPRINT("prio - incorrect prio"), @@ -665,7 +665,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts21 = [{config, ConfigOpts}, {versions, [v1]}, {priority, Prio1}], - ?line {error, Reason21} = config_start(Opts21), + {error, Reason21} = config_start(Opts21), ?IPRINT("prio (prio) res: ~p", [Reason21]), ?IPRINT("atl - incorrect type"), @@ -676,7 +676,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts22 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL1}], - ?line {error, Reason22} = config_start(Opts22), + {error, Reason22} = config_start(Opts22), ?IPRINT("atl (type) res: ~p", [Reason22]), ?IPRINT("atl - incorrect dir (1)"), @@ -687,7 +687,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts23 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL2}], - ?line {error, Reason23} = config_start(Opts23), + {error, Reason23} = config_start(Opts23), ?IPRINT("atl (dir) res: ~p", [Reason23]), ?IPRINT("atl - incorrect dir (2)"), @@ -698,7 +698,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts24 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL3}], - ?line {error, Reason24} = config_start(Opts24), + {error, Reason24} = config_start(Opts24), ?IPRINT("atl (dir) res: ~p", [Reason24]), ?IPRINT("atl - incorrect size (1)"), @@ -709,7 +709,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts25 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL4}], - ?line {error, Reason25} = config_start(Opts25), + {error, Reason25} = config_start(Opts25), ?IPRINT("atl (size) res: ~p", [Reason25]), ?IPRINT("atl - incorrect size (2)"), @@ -720,7 +720,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts26 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL5}], - ?line {error, Reason26} = config_start(Opts26), + {error, Reason26} = config_start(Opts26), ?IPRINT("atl (size) res: ~p", [Reason26]), ?IPRINT("atl - incorrect size (3)"), @@ -731,7 +731,7 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts27 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL6}], - ?line {error, Reason27} = config_start(Opts27), + {error, Reason27} = config_start(Opts27), ?IPRINT("atl (size) res: ~p", [Reason27]), ?IPRINT("atl - incorrect repair"), @@ -742,21 +742,21 @@ start_with_incorrect_opts(Conf) when is_list(Conf) -> Opts28 = [{config, ConfigOpts}, {versions, [v1]}, {audit_trail_log, ATL7}], - ?line {error, Reason28} = config_start(Opts28), + {error, Reason28} = config_start(Opts28), ?IPRINT("atl (repair) res: ~p", [Reason28]), ?IPRINT("version - incorrect versions (1)"), Vsns1 = invalid_vsns, Opts29 = [{config, ConfigOpts}, {versions, Vsns1}], - ?line {error, Reason29} = config_start(Opts29), + {error, Reason29} = config_start(Opts29), ?IPRINT("versions (versions) res: ~p", [Reason29]), ?IPRINT("version - incorrect versions (2)"), Vsns2 = [v1,v2,v3,v9], Opts30 = [{config, ConfigOpts}, {versions, Vsns2}], - ?line {error, Reason30} = config_start(Opts30), + {error, Reason30} = config_start(Opts30), ?IPRINT("versions (versions) res: ~p", [Reason30]), ?IPRINT("done"), @@ -784,136 +784,136 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("write manager config file with invalid IP address (1)"), write_manager_conf(ConfDir, "arne-anka", "4001", "500", "\"bmkEngine\""), - ?line {error, Reason11} = config_start(Opts), + {error, Reason11} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason11]), - ?line {failed_reading, _, _, 1, {parse_error, _}} = Reason11, + {failed_reading, _, _, 1, {parse_error, _}} = Reason11, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid IP address (2)"), write_manager_conf(ConfDir, "arne_anka", "4001", "500", "\"bmkEngine\""), - ?line {error, Reason12} = config_start(Opts), + {error, Reason12} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason12]), - ?line {failed_check, _, _, 2, {bad_address, _}} = Reason12, + {failed_check, _, _, 2, {bad_address, _}} = Reason12, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid IP address (3)"), write_manager_conf(ConfDir, "9999", "4001", "500", "\"bmkEngine\""), - ?line {error, Reason13} = config_start(Opts), + {error, Reason13} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason13]), - ?line {failed_check, _, _, 2, {bad_address, _}} = Reason13, + {failed_check, _, _, 2, {bad_address, _}} = Reason13, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid port (2)"), write_manager_conf(ConfDir, "[134,138,177,189]", "kalle-anka", "500", "\"bmkEngine\""), - ?line {error, Reason21} = config_start(Opts), + {error, Reason21} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason21]), - ?line {failed_reading, _, _, 2, {parse_error, _}} = Reason21, + {failed_reading, _, _, 2, {parse_error, _}} = Reason21, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid port (1)"), write_manager_conf(ConfDir, "[134,138,177,189]", "-1", "500", "\"bmkEngine\""), - ?line {error, Reason22} = config_start(Opts), + {error, Reason22} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason22]), io:format("Reason22: ~p~n", [Reason22]), - ?line {failed_check, _, _, 3, {bad_port, _}} = Reason22, + {failed_check, _, _, 3, {bad_port, _}} = Reason22, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid port (3)"), write_manager_conf(ConfDir, "[134,138,177,189]", "\"kalle-anka\"", "500", "\"bmkEngine\""), - ?line {error, Reason23} = config_start(Opts), + {error, Reason23} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason23]), - ?line {failed_check, _, _, 3, {bad_port, _}} = Reason23, + {failed_check, _, _, 3, {bad_port, _}} = Reason23, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid EngineID (1)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "500", "bmkEngine"), - ?line {error, Reason31} = config_start(Opts), + {error, Reason31} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason31]), - ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason31, + {failed_check, _, _, 5, {invalid_string, _}} = Reason31, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid EngineID (2)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "500", "{1,2,3}"), - ?line {error, Reason32} = config_start(Opts), + {error, Reason32} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason32]), - ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason32, + {failed_check, _, _, 5, {invalid_string, _}} = Reason32, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid EngineID (3)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "500", "10101"), - ?line {error, Reason33} = config_start(Opts), + {error, Reason33} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason33]), - ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason33, + {failed_check, _, _, 5, {invalid_string, _}} = Reason33, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid MMS (1)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "483", "\"bmkEngine\""), - ?line {error, Reason41} = config_start(Opts), + {error, Reason41} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason41]), - ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason41, + {failed_check, _, _, 4, {invalid_integer, _}} = Reason41, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid MMS (2)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "-1", "\"bmkEngine\""), - ?line {error, Reason42} = config_start(Opts), + {error, Reason42} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason42]), - ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason42, + {failed_check, _, _, 4, {invalid_integer, _}} = Reason42, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid MMS (3)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "\"kalle-anka\"", "\"bmkEngine\""), - ?line {error, Reason43} = config_start(Opts), + {error, Reason43} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason43]), - ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason43, + {failed_check, _, _, 4, {invalid_integer, _}} = Reason43, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with invalid MMS (4)"), write_manager_conf(ConfDir, "[134,138,177,189]", "4001", "kalle_anka", "\"bmkEngine\""), - ?line {error, Reason44} = config_start(Opts), + {error, Reason44} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason44]), - ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason44, + {failed_check, _, _, 4, {invalid_integer, _}} = Reason44, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with unknown option"), write_manager_conf(ConfDir, "{kalle, anka}."), - ?line {error, Reason51} = config_start(Opts), + {error, Reason51} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51]), - ?line {failed_check, _, _, 1, {unknown_config, _}} = Reason51, + {failed_check, _, _, 1, {unknown_config, _}} = Reason51, config_ensure_not_running(), %% -- ?IPRINT("write manager config file with unknown option"), write_manager_conf(ConfDir, "kalle_anka."), - ?line {error, Reason52} = config_start(Opts), + {error, Reason52} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason52]), - ?line {failed_check, _, _, 1, {unknown_config, _}} = Reason52, + {failed_check, _, _, 1, {unknown_config, _}} = Reason52, config_ensure_not_running(), ?IPRINT("done"), @@ -945,73 +945,73 @@ start_with_invalid_users_conf_file1(Conf) when is_list(Conf) -> %% -- ?IPRINT("write users config file with invalid module (1)"), write_users_conf(ConfDir, [{"kalle", "kalle", "dummy"}]), - ?line {error, Reason11} = config_start(Opts), + {error, Reason11} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason11]), - ?line {failed_check, _, _, _, {bad_module, kalle}} = Reason11, + {failed_check, _, _, _, {bad_module, kalle}} = Reason11, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid module (1)"), write_users_conf(ConfDir, [{"kalle", "snmpm", "dummy"}]), - ?line {error, Reason12} = config_start(Opts), + {error, Reason12} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason12]), - ?line {failed_check, _, _, _, {bad_module, _}} = Reason12, + {failed_check, _, _, _, {bad_module, _}} = Reason12, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid module (2)"), write_users_conf(ConfDir, [{"kalle1", "10101", "dummy"}]), - ?line {error, Reason13} = config_start(Opts), + {error, Reason13} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason13]), - ?line {failed_check, _, _, _, {bad_module, _}} = Reason13, + {failed_check, _, _, _, {bad_module, _}} = Reason13, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user tuple (1)"), write_users_conf2(ConfDir, "{kalle, snmpm_user_default}."), - ?line {error, Reason21} = config_start(Opts), + {error, Reason21} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason21]), - ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason21, + {failed_check, _, _, _, {bad_user_config, _}} = Reason21, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user tuple (2)"), write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [], olle}."), - ?line {error, Reason22} = config_start(Opts), + {error, Reason22} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason22]), - ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason22, + {failed_check, _, _, _, {bad_user_config, _}} = Reason22, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user tuple (3)"), write_users_conf2(ConfDir, "snmpm_user_default."), - ?line {error, Reason23} = config_start(Opts), + {error, Reason23} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason23]), - ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason23, + {failed_check, _, _, _, {bad_user_config, _}} = Reason23, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user tuple (4)"), write_users_conf2(ConfDir, "[kalle, snmpm_user_default, kalle]."), - ?line {error, Reason24} = config_start(Opts), + {error, Reason24} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason24]), - ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason24, + {failed_check, _, _, _, {bad_user_config, _}} = Reason24, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user agent default config (1)"), write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, olle}."), - ?line {error, Reason31} = config_start(Opts), + {error, Reason31} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason31]), - ?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason31, + {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason31, config_ensure_not_running(), %% -- ?IPRINT("write users config file with invalid user agent default config (2)"), write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [olle]}."), - ?line {error, Reason32} = config_start(Opts), + {error, Reason32} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason32]), - %% ?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason32, + %% {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason32, case Reason32 of {failed_check, _, _, _, {bad_default_agent_config, _}} -> ok; @@ -1059,7 +1059,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason11} -> ?IPRINT("start failed (as expected): ~p", [Reason11]), - ?line {failed_reading, _, _, _, {parse_error, _}} = Reason11, + {failed_reading, _, _, _, {parse_error, _}} = Reason11, config_ensure_not_running(); OK_11 -> config_ensure_not_running(), @@ -1073,7 +1073,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason21} -> ?IPRINT("start failed (as expected): ~p", [Reason21]), - ?line {failed_reading, _, _, _, {parse_error, _}} = Reason21, + {failed_reading, _, _, _, {parse_error, _}} = Reason21, config_ensure_not_running(); OK_21 -> config_ensure_not_running(), @@ -1087,7 +1087,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason22} -> ?IPRINT("start failed (as expected): ~p", [Reason22]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason22, + {failed_check, _, _, _, {invalid_string, _}} = Reason22, config_ensure_not_running(); OK_22 -> config_ensure_not_running(), @@ -1101,7 +1101,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason23} -> ?IPRINT("start failed (as expected): ~p", [Reason23]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason23, + {failed_check, _, _, _, {invalid_string, _}} = Reason23, config_ensure_not_running(); OK_23 -> config_ensure_not_running(), @@ -1115,7 +1115,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason31} -> ?IPRINT("start failed (as expected): ~p", [Reason31]), - ?line {failed_reading, _, _, _, {parse_error, _}} = Reason31, + {failed_reading, _, _, _, {parse_error, _}} = Reason31, config_ensure_not_running(); OK_31 -> config_ensure_not_running(), @@ -1129,7 +1129,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason32} -> ?IPRINT("start failed (as expected): ~p", [Reason32]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason32, + {failed_check, _, _, _, {invalid_string, _}} = Reason32, config_ensure_not_running(); OK_32 -> config_ensure_not_running(), @@ -1143,7 +1143,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason33} -> ?IPRINT("start failed (as expected): ~p", [Reason33]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason33, + {failed_check, _, _, _, {invalid_string, _}} = Reason33, config_ensure_not_running(); OK_33 -> config_ensure_not_running(), @@ -1157,7 +1157,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason51} -> ?IPRINT("start failed (as expected): ~p", [Reason51]), - ?line {failed_check, _, _, _, {bad_domain, _}} = Reason51, + {failed_check, _, _, _, {bad_domain, _}} = Reason51, config_ensure_not_running(); OK_51 -> config_ensure_not_running(), @@ -1171,7 +1171,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason52} -> ?IPRINT("start failed (as expected): ~p", [Reason52]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason52, + {failed_check, _, _, _, {bad_address, _}} = Reason52, config_ensure_not_running(); OK_52 -> config_ensure_not_running(), @@ -1185,7 +1185,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason53} -> ?IPRINT("start failed (as expected): ~p", [Reason53]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason53, + {failed_check, _, _, _, {bad_address, _}} = Reason53, config_ensure_not_running(); OK_53 -> config_ensure_not_running(), @@ -1199,7 +1199,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, Reason54} -> ?IPRINT("start failed (as expected): ~p", [Reason54]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason54, + {failed_check, _, _, _, {bad_address, _}} = Reason54, config_ensure_not_running(); OK_54 -> config_ensure_not_running(), @@ -1210,162 +1210,162 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 55] write agents config file with invalid ip (5)"), Agent55 = setelement(4, Agent0, "[192,168,0,arne]"), write_agents_conf(ConfDir, [Agent55]), - ?line {error, Reason55} = config_start(Opts), + {error, Reason55} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason55]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason55, + {failed_check, _, _, _, {bad_address, _}} = Reason55, config_ensure_not_running(), %% -- ?IPRINT("[test 61] write agents config file with invalid port (1)"), Agent61 = setelement(5, Agent0, "kalle_anka"), write_agents_conf(ConfDir, [Agent61]), - ?line {error, Reason61} = config_start(Opts), + {error, Reason61} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason61]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason61, + {failed_check, _, _, _, {bad_address, _}} = Reason61, config_ensure_not_running(), %% -- ?IPRINT("[test 62] write agents config file with invalid port (2)"), Agent62 = setelement(5, Agent0, "-1"), write_agents_conf(ConfDir, [Agent62]), - ?line {error, Reason62} = config_start(Opts), + {error, Reason62} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason62]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason62, + {failed_check, _, _, _, {bad_address, _}} = Reason62, config_ensure_not_running(), %% -- ?IPRINT("[test 63] write agents config file with invalid port (3)"), Agent63 = setelement(5, Agent0, "\"100\""), write_agents_conf(ConfDir, [Agent63]), - ?line {error, Reason63} = config_start(Opts), + {error, Reason63} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason63]), - ?line {failed_check, _, _, _, {bad_address, _}} = Reason63, + {failed_check, _, _, _, {bad_address, _}} = Reason63, config_ensure_not_running(), %% -- ?IPRINT("[test 71] write agents config file with invalid engine-id (1)"), Agent71 = setelement(6, Agent0, "kalle_anka"), write_agents_conf(ConfDir, [Agent71]), - ?line {error, Reason71} = config_start(Opts), + {error, Reason71} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason71]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason71, + {failed_check, _, _, _, {invalid_string, _}} = Reason71, config_ensure_not_running(), %% -- ?IPRINT("[test 72] write agents config file with invalid engine-id (2)"), Agent72 = setelement(6, Agent0, "10101"), write_agents_conf(ConfDir, [Agent72]), - ?line {error, Reason72} = config_start(Opts), + {error, Reason72} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason72]), - ?line {failed_check, _, _, _, {invalid_string, _}} = Reason72, + {failed_check, _, _, _, {invalid_string, _}} = Reason72, config_ensure_not_running(), %% -- ?IPRINT("[test 81] write agents config file with invalid timeout (1)"), Agent81 = setelement(7, Agent0, "kalle_anka"), write_agents_conf(ConfDir, [Agent81]), - ?line {error, Reason81} = config_start(Opts), + {error, Reason81} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason81]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason81, + {failed_check, _, _, _, {invalid_timer, _}} = Reason81, config_ensure_not_running(), %% -- ?IPRINT("[test 82] write agents config file with invalid timeout (2)"), Agent82 = setelement(7, Agent0, "-1"), write_agents_conf(ConfDir, [Agent82]), - ?line {error, Reason82} = config_start(Opts), + {error, Reason82} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason82]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason82, + {failed_check, _, _, _, {invalid_timer, _}} = Reason82, config_ensure_not_running(), %% -- ?IPRINT("[test 83] write agents config file with invalid timeout (3)"), Agent83 = setelement(7, Agent0, "{1000, 1, 10, kalle}"), write_agents_conf(ConfDir, [Agent83]), - ?line {error, Reason83} = config_start(Opts), + {error, Reason83} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason83]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason83, + {failed_check, _, _, _, {invalid_timer, _}} = Reason83, config_ensure_not_running(), %% -- ?IPRINT("[test 84] write agents config file with invalid timeout (4)"), Agent84 = setelement(7, Agent0, "{1000, -1, 10, 10}"), write_agents_conf(ConfDir, [Agent84]), - ?line {error, Reason84} = config_start(Opts), + {error, Reason84} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason84]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason84, + {failed_check, _, _, _, {invalid_timer, _}} = Reason84, config_ensure_not_running(), %% -- ?IPRINT("[test 85] write agents config file with invalid timeout (5)"), Agent85 = setelement(7, Agent0, "{1000, 1, -100, 10}"), write_agents_conf(ConfDir, [Agent85]), - ?line {error, Reason85} = config_start(Opts), + {error, Reason85} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason85]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason85, + {failed_check, _, _, _, {invalid_timer, _}} = Reason85, config_ensure_not_running(), %% -- ?IPRINT("[test 86] write agents config file with invalid timeout (6)"), Agent86 = setelement(7, Agent0, "{1000, 1, 100, -1}"), write_agents_conf(ConfDir, [Agent86]), - ?line {error, Reason86} = config_start(Opts), + {error, Reason86} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason86]), - ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason86, + {failed_check, _, _, _, {invalid_timer, _}} = Reason86, config_ensure_not_running(), %% -- ?IPRINT("[test 91] write agents config file with invalid max-message-size (1)"), Agent91 = setelement(8, Agent0, "483"), write_agents_conf(ConfDir, [Agent91]), - ?line {error, Reason91} = config_start(Opts), + {error, Reason91} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason91]), - ?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason91, + {failed_check, _, _, _, {invalid_packet_size, _}} = Reason91, config_ensure_not_running(), %% -- ?IPRINT("[test 92] write agents config file with invalid max-message-size (2)"), Agent92 = setelement(8, Agent0, "kalle_anka"), write_agents_conf(ConfDir, [Agent92]), - ?line {error, Reason92} = config_start(Opts), + {error, Reason92} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason92]), - ?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason92, + {failed_check, _, _, _, {invalid_packet_size, _}} = Reason92, config_ensure_not_running(), %% -- ?IPRINT("[test A1] write agents config file with invalid version (1)"), AgentA1 = setelement(9, Agent0, "1"), write_agents_conf(ConfDir, [AgentA1]), - ?line {error, ReasonA1} = config_start(Opts), + {error, ReasonA1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [ReasonA1]), - ?line {failed_check, _, _, _, {bad_version, _}} = ReasonA1, + {failed_check, _, _, _, {bad_version, _}} = ReasonA1, config_ensure_not_running(), %% -- ?IPRINT("[test A2] write agents config file with invalid version (2)"), AgentA2 = setelement(9, Agent0, "v30"), write_agents_conf(ConfDir, [AgentA2]), - ?line {error, ReasonA2} = config_start(Opts), + {error, ReasonA2} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [ReasonA2]), - ?line {failed_check, _, _, _, {bad_version, _}} = ReasonA2, + {failed_check, _, _, _, {bad_version, _}} = ReasonA2, config_ensure_not_running(), %% -- ?IPRINT("[test B1] write agents config file with invalid sec-model (1)"), AgentB1 = setelement(10, Agent0, "\"any\""), write_agents_conf(ConfDir, [AgentB1]), - ?line {error, ReasonB1} = config_start(Opts), + {error, ReasonB1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [ReasonB1]), - ?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB1, + {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB1, config_ensure_not_running(), %% -- ?IPRINT("[test B2] write agents config file with invalid sec-model (2)"), AgentB2 = setelement(10, Agent0, "v3"), write_agents_conf(ConfDir, [AgentB2]), - ?line {error, ReasonB2} = config_start(Opts), + {error, ReasonB2} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [ReasonB2]), - ?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB2, + {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB2, config_ensure_not_running(), %% -- @@ -1375,7 +1375,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, ReasonC1} -> ?IPRINT("start failed (as expected): ~p", [ReasonC1]), - ?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC1, + {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC1, config_ensure_not_running(); OK_C1 -> config_ensure_not_running(), @@ -1389,7 +1389,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, ReasonC2} -> ?IPRINT("start failed (as expected): ~p", [ReasonC2]), - ?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC2, + {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC2, config_ensure_not_running(); OK_C2 -> config_ensure_not_running(), @@ -1403,7 +1403,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, ReasonD1} -> ?IPRINT("start failed (as expected): ~p", [ReasonD1]), - ?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD1, + {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD1, config_ensure_not_running(); OK_D1 -> config_ensure_not_running(), @@ -1417,7 +1417,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, ReasonD2} -> ?IPRINT("start failed (as expected): ~p", [ReasonD2]), - ?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD2, + {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD2, config_ensure_not_running(); OK_D2 -> config_ensure_not_running(), @@ -1430,7 +1430,7 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) -> case config_start(Opts) of {error, ReasonE1} -> ?IPRINT("start failed (as expected): ~p", [ReasonE1]), - ?line {failed_check, _, _, _, {bad_agent_config, _}} = ReasonE1, + {failed_check, _, _, _, {bad_agent_config, _}} = ReasonE1, config_ensure_not_running(); OK_E1 -> config_ensure_not_running(), @@ -1487,146 +1487,146 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 11] write usm config file with invalid engine-id (1)"), Usm11 = setelement(1, Usm0, "kalle-anka"), write_usm_conf(ConfDir, [Usm11]), - ?line {error, Reason11} = config_start(Opts), + {error, Reason11} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason11]), - ?line {failed_reading, _, _, _, {parse_error, _}} = Reason11, + {failed_reading, _, _, _, {parse_error, _}} = Reason11, config_ensure_not_running(), %% -- ?IPRINT("[test 12] write usm config file with invalid engine-id (2)"), Usm12 = setelement(1, Usm0, "kalle_anka"), write_usm_conf(ConfDir, [Usm12]), - ?line {error, Reason12} = config_start(Opts), + {error, Reason12} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason12]), - ?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason12, + {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason12, config_ensure_not_running(), %% -- ?IPRINT("[test 13] write usm config file with invalid engine-id (3)"), Usm13 = setelement(1, Usm1, "10101"), write_usm_conf(ConfDir, [Usm13]), - ?line {error, Reason13} = config_start(Opts), + {error, Reason13} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason13]), - ?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason13, + {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason13, config_ensure_not_running(), %% -- ?IPRINT("[test 21] write usm config file with invalid user-name (1)"), Usm21 = setelement(2, Usm0, "kalle_anka"), write_usm_conf(ConfDir, [Usm21]), - ?line {error, Reason21} = config_start(Opts), + {error, Reason21} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason21]), - ?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason21, + {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason21, config_ensure_not_running(), %% -- ?IPRINT("[test 22] write usm config file with invalid user-name (1)"), Usm22 = setelement(2, Usm1, "10101"), write_usm_conf(ConfDir, [Usm22]), - ?line {error, Reason22} = config_start(Opts), + {error, Reason22} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason22]), - ?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason22, + {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason22, config_ensure_not_running(), %% -- ?IPRINT("[test 31] write usm config file with invalid sec-name (1)"), Usm31 = setelement(3, Usm1, "kalle_anka"), write_usm_conf(ConfDir, [Usm31]), - ?line {error, Reason31} = config_start(Opts), + {error, Reason31} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason31]), - ?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason31, + {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason31, config_ensure_not_running(), %% -- ?IPRINT("[test 32] write usm config file with invalid sec-name (2)"), Usm32 = setelement(3, Usm1, "10101"), write_usm_conf(ConfDir, [Usm32]), - ?line {error, Reason32} = config_start(Opts), + {error, Reason32} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason32]), - ?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason32, + {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason32, config_ensure_not_running(), %% -- ?IPRINT("[test 41] write usm config file with invalid auth-protocol (1)"), Usm41 = setelement(3, Usm0, "\"usmNoAuthProtocol\""), write_usm_conf(ConfDir, [Usm41]), - ?line {error, Reason41} = config_start(Opts), + {error, Reason41} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason41]), - ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason41, + {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason41, config_ensure_not_running(), %% -- ?IPRINT("[test 42] write usm config file with invalid auth-protocol (2)"), Usm42 = setelement(3, Usm0, "kalle"), write_usm_conf(ConfDir, [Usm42]), - ?line {error, Reason42} = config_start(Opts), + {error, Reason42} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason42]), - ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason42, + {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason42, config_ensure_not_running(), %% -- ?IPRINT("[test 43] write usm config file with invalid auth-protocol (3)"), Usm43 = setelement(3, Usm0, "10101"), write_usm_conf(ConfDir, [Usm43]), - ?line {error, Reason43} = config_start(Opts), + {error, Reason43} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason43]), - ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason43, + {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason43, config_ensure_not_running(), %% -- ?IPRINT("[test 51.1] write (auth md5) usm config file with invalid auth-key (1)"), Usm51_1 = setelement(3, Usm0, "usmHMACMD5AuthProtocol"), write_usm_conf(ConfDir, [Usm51_1]), - ?line {error, Reason51_1} = config_start(Opts), + {error, Reason51_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason51_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason51_1, config_ensure_not_running(), %% -- ?IPRINT("[test 51.2] write (auth md5) usm config file with invalid auth-key (2)"), Usm51_2 = setelement(4, Usm51_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"), write_usm_conf(ConfDir, [Usm51_2]), - ?line {error, Reason51_2} = config_start(Opts), + {error, Reason51_2} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51_2]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 15}} = Reason51_2, + {failed_check, _, _, _, {invalid_auth_key, _, 15}} = Reason51_2, config_ensure_not_running(), %% -- ?IPRINT("[test 51.3] write (auth md5) usm config file with invalid auth-key (3)"), Usm51_3 = setelement(4, Usm51_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"), write_usm_conf(ConfDir, [Usm51_3]), - ?line {error, Reason51_3} = config_start(Opts), + {error, Reason51_3} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 17}} = Reason51_3, + {failed_check, _, _, _, {invalid_auth_key, _, 17}} = Reason51_3, config_ensure_not_running(), %% -- ?IPRINT("[test 51.4] write (auth md5) usm config file with invalid auth-key (4)"), Usm51_4 = setelement(4, Usm51_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"), write_usm_conf(ConfDir, [Usm51_4]), - ?line maybe_start_crypto(), %% Make sure it's started... - ?line {error, Reason51_4} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + maybe_start_crypto(), %% Make sure it's started... + {error, Reason51_4} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason51_4]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_4, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_4, config_ensure_not_running(), %% -- ?IPRINT("[test 51.5] write (auth md5) usm config file with invalid auth-key (5)"), Usm51_5 = setelement(4, Usm51_1, "arne_anka"), write_usm_conf(ConfDir, [Usm51_5]), - ?line {error, Reason51_5} = config_start(Opts), + {error, Reason51_5} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51_5]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_5, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_5, config_ensure_not_running(), %% -- ?IPRINT("[test 51.6] write (auth md5) usm config file with invalid auth-key (6)"), Usm51_6 = setelement(4, Usm51_1, "10101"), write_usm_conf(ConfDir, [Usm51_6]), - ?line {error, Reason51_6} = config_start(Opts), + {error, Reason51_6} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason51_6]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_6, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason51_6, config_ensure_not_running(), @@ -1635,29 +1635,29 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 52.1] write (auth sha) usm config file with invalid auth-key (1)"), Usm52_1 = setelement(3, Usm0, "usmHMACSHAAuthProtocol"), write_usm_conf(ConfDir, [Usm52_1]), - ?line {error, Reason52_1} = config_start(Opts), + {error, Reason52_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason52_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason52_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason52_1, config_ensure_not_running(), %% -- ?IPRINT("[test 52.2] write (auth sha) usm config file with invalid auth-key (2)"), Usm52_2 = setelement(4, Usm52_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"), write_usm_conf(ConfDir, [Usm52_2]), - ?line {error, Reason52_2} = config_start(Opts), + {error, Reason52_2} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason52_2]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 16}} = Reason52_2, + {failed_check, _, _, _, {invalid_auth_key, _, 16}} = Reason52_2, config_ensure_not_running(), %% -- ?IPRINT("[test 52.3] write (auth sha) usm config file with invalid auth-key (3)"), Usm52_3 = setelement(4, Usm52_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,ka]"), write_usm_conf(ConfDir, [Usm52_3]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason52_3} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason52_3} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason52_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason52_3, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason52_3, config_ensure_not_running(), @@ -1666,9 +1666,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 53.1] write (auth sha224) usm config file with invalid auth-key (1)"), Usm53_1 = setelement(3, Usm0, "usmHMAC128SHA224AuthProtocol"), write_usm_conf(ConfDir, [Usm53_1]), - ?line {error, Reason53_1} = config_start(Opts), + {error, Reason53_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason53_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason53_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason53_1, config_ensure_not_running(), %% -- @@ -1676,7 +1676,7 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm53_2 = setelement(4, Usm53_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8]"), write_usm_conf(ConfDir, [Usm53_2]), - ?line {ok, _} = config_start(Opts), + {ok, _} = config_start(Opts), ?IPRINT("expected start success"), config_ensure_not_running(), @@ -1685,9 +1685,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm53_3 = setelement(4, Usm53_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"), write_usm_conf(ConfDir, [Usm53_3]), - ?line {error, Reason53_3} = config_start(Opts), + {error, Reason53_3} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason53_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 27}} = Reason53_3, + {failed_check, _, _, _, {invalid_auth_key, _, 27}} = Reason53_3, config_ensure_not_running(), %% -- @@ -1695,11 +1695,11 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm53_4 = setelement(4, Usm53_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,ka]"), write_usm_conf(ConfDir, [Usm53_4]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason53_4} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason53_4} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason53_4]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason53_4, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason53_4, config_ensure_not_running(), @@ -1707,9 +1707,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 54.1] write (auth sha256) usm config file with invalid auth-key (1)"), Usm54_1 = setelement(3, Usm0, "usmHMAC192SHA256AuthProtocol"), write_usm_conf(ConfDir, [Usm54_1]), - ?line {error, Reason54_1} = config_start(Opts), + {error, Reason54_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason54_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason54_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason54_1, config_ensure_not_running(), %% -- @@ -1717,7 +1717,7 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm54_2 = setelement(4, Usm54_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]"), write_usm_conf(ConfDir, [Usm54_2]), - ?line {ok, _} = config_start(Opts), + {ok, _} = config_start(Opts), ?IPRINT("expected start success"), config_ensure_not_running(), @@ -1726,9 +1726,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm54_3 = setelement(4, Usm54_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1]"), write_usm_conf(ConfDir, [Usm54_3]), - ?line {error, Reason54_3} = config_start(Opts), + {error, Reason54_3} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason54_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 31}} = Reason54_3, + {failed_check, _, _, _, {invalid_auth_key, _, 31}} = Reason54_3, config_ensure_not_running(), %% -- @@ -1736,11 +1736,11 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm54_4 = setelement(4, Usm54_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,ka]"), write_usm_conf(ConfDir, [Usm54_4]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason54_4} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason54_4} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason54_4]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason54_4, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason54_4, config_ensure_not_running(), @@ -1748,9 +1748,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 55.1] write (auth sha384) usm config file with invalid auth-key (1)"), Usm55_1 = setelement(3, Usm0, "usmHMAC256SHA384AuthProtocol"), write_usm_conf(ConfDir, [Usm55_1]), - ?line {error, Reason55_1} = config_start(Opts), + {error, Reason55_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason55_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason55_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason55_1, config_ensure_not_running(), %% -- @@ -1758,7 +1758,7 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm55_2 = setelement(4, Usm55_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8]"), write_usm_conf(ConfDir, [Usm55_2]), - ?line {ok, _} = config_start(Opts), + {ok, _} = config_start(Opts), ?IPRINT("expected start success"), config_ensure_not_running(), @@ -1767,9 +1767,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm55_3 = setelement(4, Usm55_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"), write_usm_conf(ConfDir, [Usm55_3]), - ?line {error, Reason55_3} = config_start(Opts), + {error, Reason55_3} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason55_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 47}} = Reason55_3, + {failed_check, _, _, _, {invalid_auth_key, _, 47}} = Reason55_3, config_ensure_not_running(), %% -- @@ -1777,11 +1777,11 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm55_4 = setelement(4, Usm55_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,ka]"), write_usm_conf(ConfDir, [Usm55_4]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason55_4} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason55_4} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason55_4]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason55_4, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason55_4, config_ensure_not_running(), @@ -1789,9 +1789,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 56.1] write (auth sha512) usm config file with invalid auth-key (1)"), Usm56_1 = setelement(3, Usm0, "usmHMAC384SHA512AuthProtocol"), write_usm_conf(ConfDir, [Usm56_1]), - ?line {error, Reason56_1} = config_start(Opts), + {error, Reason56_1} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason56_1]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason56_1, + {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason56_1, config_ensure_not_running(), %% -- @@ -1799,7 +1799,7 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm56_2 = setelement(4, Usm56_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4]"), write_usm_conf(ConfDir, [Usm56_2]), - ?line {ok, _} = config_start(Opts), + {ok, _} = config_start(Opts), ?IPRINT("expected start success"), config_ensure_not_running(), @@ -1808,9 +1808,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm56_3 = setelement(4, Usm56_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3]"), write_usm_conf(ConfDir, [Usm56_3]), - ?line {error, Reason56_3} = config_start(Opts), + {error, Reason56_3} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason56_3]), - ?line {failed_check, _, _, _, {invalid_auth_key, _, 63}} = Reason56_3, + {failed_check, _, _, _, {invalid_auth_key, _, 63}} = Reason56_3, config_ensure_not_running(), %% -- @@ -1818,11 +1818,11 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> Usm56_4 = setelement(4, Usm56_1, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,ka]"), write_usm_conf(ConfDir, [Usm56_4]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason56_4} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason56_4} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason56_4]), - ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason56_4, + {failed_check, _, _, _, {invalid_auth_key, _}} = Reason56_4, config_ensure_not_running(), @@ -1830,83 +1830,83 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> ?IPRINT("[test 61] write usm config file with invalid priv-protocol (1)"), Usm61 = setelement(5, Usm0, "\"usmNoPrivProtocol\""), write_usm_conf(ConfDir, [Usm61]), - ?line {error, Reason61} = config_start(Opts), + {error, Reason61} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason61]), - ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason61, + {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason61, config_ensure_not_running(), %% -- ?IPRINT("[test 62] write usm config file with invalid priv-protocol (2)"), Usm62 = setelement(5, Usm0, "kalle"), write_usm_conf(ConfDir, [Usm62]), - ?line {error, Reason62} = config_start(Opts), + {error, Reason62} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason62]), - ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason62, + {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason62, config_ensure_not_running(), %% -- ?IPRINT("[test 63] write usm config file with invalid priv-protocol (3)"), Usm63 = setelement(5, Usm0, "10101"), write_usm_conf(ConfDir, [Usm63]), - ?line {error, Reason63} = config_start(Opts), + {error, Reason63} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason63]), - ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason63, + {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason63, config_ensure_not_running(), %% -- ?IPRINT("[test 71] write usm config file with invalid priv-key (1)"), Usm71 = setelement(5, Usm0, "usmDESPrivProtocol"), write_usm_conf(ConfDir, [Usm71]), - ?line {error, Reason71} = config_start(Opts), + {error, Reason71} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason71]), - ?line {failed_check, _, _, _, {invalid_priv_key, _, _}} = Reason71, + {failed_check, _, _, _, {invalid_priv_key, _, _}} = Reason71, config_ensure_not_running(), %% -- ?IPRINT("[test 72] write usm config file with invalid priv-key (2)"), Usm72 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"), write_usm_conf(ConfDir, [Usm72]), - ?line {error, Reason72} = config_start(Opts), + {error, Reason72} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason72]), - ?line {failed_check, _, _, _, {invalid_priv_key, _, 15}} = Reason72, + {failed_check, _, _, _, {invalid_priv_key, _, 15}} = Reason72, config_ensure_not_running(), %% -- ?IPRINT("[test 73] write usm config file with invalid priv-key (3)"), Usm73 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"), write_usm_conf(ConfDir, [Usm73]), - ?line {error, Reason73} = config_start(Opts), + {error, Reason73} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason73]), - ?line {failed_check, _, _, _, {invalid_priv_key, _, 17}} = Reason73, + {failed_check, _, _, _, {invalid_priv_key, _, 17}} = Reason73, config_ensure_not_running(), %% -- ?IPRINT("[test 74] write usm config file with invalid priv-key (4)"), Usm74 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"), write_usm_conf(ConfDir, [Usm74]), - ?line ok = maybe_start_crypto(), - ?line {error, Reason74} = config_start(Opts), - ?line ok = maybe_stop_crypto(), + ok = maybe_start_crypto(), + {error, Reason74} = config_start(Opts), + ok = maybe_stop_crypto(), ?IPRINT("start failed (as expected): ~p", [Reason74]), - ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason74, + {failed_check, _, _, _, {invalid_priv_key, _}} = Reason74, config_ensure_not_running(), %% -- ?IPRINT("[test 75] write usm config file with invalid priv-key (5)"), Usm75 = setelement(6, Usm71, "arne_anka"), write_usm_conf(ConfDir, [Usm75]), - ?line {error, Reason75} = config_start(Opts), + {error, Reason75} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason75]), - ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason75, + {failed_check, _, _, _, {invalid_priv_key, _}} = Reason75, config_ensure_not_running(), %% -- ?IPRINT("[test 76] write usm config file with invalid priv-key (6)"), Usm76 = setelement(6, Usm71, "10101"), write_usm_conf(ConfDir, [Usm76]), - ?line {error, Reason76} = config_start(Opts), + {error, Reason76} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason76]), - ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason76, + {failed_check, _, _, _, {invalid_priv_key, _}} = Reason76, config_ensure_not_running(), %% -- @@ -1919,9 +1919,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> "when crypto not started (7)"), Usm77 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"), write_usm_conf(ConfDir, [Usm77]), - ?line {error, Reason77} = config_start(Opts), + {error, Reason77} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason77]), - ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77, + {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77, config_ensure_not_running(); _ -> %% This function is only present in version 2.0 or greater. @@ -1933,9 +1933,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> %% -- ?IPRINT("[test 78] write usm config file with invalid usm (1)"), write_usm_conf2(ConfDir, "{\"bmkEngine\", \"swiusmcf\"}."), - ?line {error, Reason81} = config_start(Opts), + {error, Reason81} = config_start(Opts), ?IPRINT("start failed (as expected): ~p", [Reason81]), - ?line {failed_check, _, _, _, {bad_usm_config, _}} = Reason81, + {failed_check, _, _, _, {bad_usm_config, _}} = Reason81, config_ensure_not_running(), ?IPRINT("done"), @@ -1996,17 +1996,17 @@ simple_system_op(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("start config"), - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), - ?IPRINT("retreive various configs"), - ?line {ok, _Time} = snmpm_config:system_start_time(), - ?line {ok, _EngineId} = snmpm_config:get_engine_id(), - ?line {ok, _MMS} = snmpm_config:get_engine_max_message_size(), + ?IPRINT("retrieve various configs"), + {ok, _Time} = snmpm_config:system_start_time(), + {ok, _EngineId} = snmpm_config:get_engine_id(), + {ok, _MMS} = snmpm_config:get_engine_max_message_size(), - ?IPRINT("attempt to retreive nonexisting"), - ?line {error, not_found} = snmpm_config:system_info(kalle), + ?IPRINT("attempt to retrieve nonexisting"), + {error, not_found} = snmpm_config:system_info(kalle), - ?line ok = config_stop(), + ok = config_stop(), config_ensure_not_running(), ?IPRINT("done"), @@ -2092,7 +2092,7 @@ register_agent_using_file(Conf) when is_list(Conf) -> Case = fun(_) -> do_register_agent_using_file(Conf) end, Post = fun(_) -> ?IPRINT("stop config process"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), ok end, @@ -2151,49 +2151,49 @@ do_register_agent_using_file(Conf) -> %% -- ?IPRINT("start the config process"), - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), %% -- ?IPRINT("which agents"), - ?line [_, _] = All = snmpm_config:which_agents(), + [_, _] = All = snmpm_config:which_agents(), ?IPRINT("all agents: ~n ~p", [All]), - ?line [A1] = snmpm_config:which_agents(UserId1), + [A1] = snmpm_config:which_agents(UserId1), ?IPRINT("agents belonging to ~w: ~n ~p", [UserId1, A1]), - ?line [A2] = snmpm_config:which_agents(UserId2), + [A2] = snmpm_config:which_agents(UserId2), ?IPRINT("agents belonging to ~w: ~n ~p", [UserId2, A2]), %% -- ?IPRINT("All info for agent <~w,~w>", [AgentAddr1, AgentPort1]), - ?line {ok, AllInfo1} = + {ok, AllInfo1} = snmpm_config:agent_info(AgentAddr1, AgentPort1, all), ?IPRINT("all agent info for agent: ~n ~p", [AllInfo1]), %% -- ?IPRINT("EngineID (~p) for agent <~w,~w>", [EngineID1, AgentAddr1, AgentPort1]), - ?line {ok, EngineID1} = + {ok, EngineID1} = snmpm_config:agent_info(AgentAddr1, AgentPort1, engine_id), %% -- ?IPRINT("All info for agent <~w,~w>", [AgentAddr2, AgentPort2]), - ?line {ok, AllInfo2} = + {ok, AllInfo2} = snmpm_config:agent_info(AgentAddr2, AgentPort2, all), ?IPRINT("all agent info for agent: ~n ~p", [AllInfo2]), %% -- ?IPRINT("EngineID (~p) for agent <~w,~w>", [EngineID2, AgentAddr2, AgentPort2]), - ?line {ok, EngineID2} = + {ok, EngineID2} = snmpm_config:agent_info(AgentAddr2, AgentPort2, engine_id), %% -- - ?line {ok, MMS2} = + {ok, MMS2} = snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size), NewMMS21 = 2048, ?IPRINT("try update agent info max-message-size to ~w for agent <~w,~w>", [NewMMS21, AgentAddr2, AgentPort2]), - ?line ok = snmpm_config:update_agent_info(UserId2, AgentAddr2, AgentPort2, - max_message_size, NewMMS21), - ?line {ok, NewMMS21} = + ok = update_agent_info(UserId2, AgentAddr2, AgentPort2, + max_message_size, NewMMS21), + {ok, NewMMS21} = snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size), %% -- @@ -2201,11 +2201,11 @@ do_register_agent_using_file(Conf) -> "for agent <~w,~w> " "with user ~w (not owner)", [NewMMS21, AgentAddr2, AgentPort2, UserId1]), - ?line {error, Reason01} = - snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2, - max_message_size, NewMMS21), + {error, Reason01} = + update_agent_info(UserId1, AgentAddr2, AgentPort2, + max_message_size, NewMMS21), ?IPRINT("expected failure. Reason01: ~p", [Reason01]), - ?line {ok, NewMMS21} = + {ok, NewMMS21} = snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size), %% -- @@ -2213,9 +2213,9 @@ do_register_agent_using_file(Conf) -> ?IPRINT("try (and fail) to update agent info max-message-size to ~w " "for agent <~w,~w>", [NewMMS22, AgentAddr2, AgentPort2]), - ?line {error, Reason02} = - snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2, - max_message_size, NewMMS22), + {error, Reason02} = + update_agent_info(UserId1, AgentAddr2, AgentPort2, + max_message_size, NewMMS22), ?IPRINT("expected failure. Reason02: ~p", [Reason02]), %% -- @@ -2245,7 +2245,7 @@ register_agent_using_function(Conf) when is_list(Conf) -> register_agent_failed_using_function1(suite) -> []; register_agent_failed_using_function1(doc) -> - "Register agents failng using the API (function) with incorrect " + "Register agents failing using the API (function) with incorrect " "config (1)."; register_agent_failed_using_function1(Conf) when is_list(Conf) -> put(tname, "REG-AG-FAIL-USING-FUNC-1"), @@ -2318,26 +2318,26 @@ register_usm_user_using_file(Conf) when is_list(Conf) -> %% -- ?IPRINT("start the config process"), - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), %% -- ?IPRINT("lookup 1 (ok)"), - ?line {ok, #usm_user{name = UserName1} = User1} = + {ok, #usm_user{name = UserName1} = User1} = snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName1), ?IPRINT("User: ~p", [User1]), ?IPRINT("lookup 2 (ok)"), - ?line {ok, #usm_user{name = UserName2} = User2} = + {ok, #usm_user{name = UserName2} = User2} = snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2), ?IPRINT("User: ~p", [User2]), ?IPRINT("lookup 3 (error)"), - ?line {error, not_found} = + {error, not_found} = snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2 ++ "_1"), %% -- ?IPRINT("stop config process"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), %% -- @@ -2386,7 +2386,7 @@ register_usm_user_using_function(Conf) when is_list(Conf) -> %% -- ?IPRINT("start the config process"), - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), %% -- ?IPRINT("register usm user's"), @@ -2400,9 +2400,9 @@ register_usm_user_using_function(Conf) when is_list(Conf) -> {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]}, {priv, usmNoPrivProtocol}], - ?line ok = snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1), + ok = snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1), ?IPRINT("try register user 1 again (error)"), - ?line {error, {already_registered, EngineID, UserName1}} = + {error, {already_registered, EngineID, UserName1}} = snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1), ?IPRINT("register user 2 (ok)"), @@ -2411,7 +2411,7 @@ register_usm_user_using_function(Conf) when is_list(Conf) -> UsmConfig2 = [{auth, usmHMACMD5AuthProtocol}, {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]}, {priv, usmNoPrivProtocol}], - ?line ok = snmpm_config:register_usm_user(EngineID, UserName2, UsmConfig2), + ok = snmpm_config:register_usm_user(EngineID, UserName2, UsmConfig2), ?IPRINT("register user 3 (ok)"), UserName3 = "samu3", @@ -2420,7 +2420,7 @@ register_usm_user_using_function(Conf) when is_list(Conf) -> {auth, usmHMACMD5AuthProtocol}, {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]}, {priv, usmNoPrivProtocol}], - ?line ok = snmpm_config:register_usm_user(EngineID, UserName3, UsmConfig3), + ok = snmpm_config:register_usm_user(EngineID, UserName3, UsmConfig3), ?IPRINT("register user 4 (ok)"), UserName4 = "samu4", @@ -2430,35 +2430,35 @@ register_usm_user_using_function(Conf) when is_list(Conf) -> {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]}, {priv, usmAesCfb128Protocol}, {priv_key, [190,54,66,227,33,171,152,0,133,223,204,155,109,111,77,44]}], - ?line ok = snmpm_config:register_usm_user(EngineID, UserName4, UsmConfig4), + ok = snmpm_config:register_usm_user(EngineID, UserName4, UsmConfig4), ?IPRINT("lookup 1 (ok)"), - ?line {ok, #usm_user{name = UserName1} = User1} = + {ok, #usm_user{name = UserName1} = User1} = snmpm_config:get_usm_user_from_sec_name(EngineID, SecName1), ?IPRINT("User: ~p", [User1]), ?IPRINT("lookup 2 (ok)"), - ?line {ok, #usm_user{name = UserName2} = User2} = + {ok, #usm_user{name = UserName2} = User2} = snmpm_config:get_usm_user_from_sec_name(EngineID, SecName2), ?IPRINT("User: ~p", [User2]), ?IPRINT("lookup 3 (ok)"), - ?line {ok, #usm_user{name = UserName3} = User3} = + {ok, #usm_user{name = UserName3} = User3} = snmpm_config:get_usm_user_from_sec_name(EngineID, SecName3), ?IPRINT("User: ~p", [User3]), ?IPRINT("lookup 4 (ok)"), - ?line {ok, #usm_user{name = UserName4} = User4} = + {ok, #usm_user{name = UserName4} = User4} = snmpm_config:get_usm_user_from_sec_name(EngineID, SecName4), ?IPRINT("User: ~p", [User4]), ?IPRINT("lookup 5 (error)"), - ?line {error, not_found} = + {error, not_found} = snmpm_config:get_usm_user_from_sec_name(EngineID, SecName4 ++ "_1"), %% -- ?IPRINT("stop config process"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), %% -- @@ -2535,7 +2535,7 @@ update_usm_user_info(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("Start config server"), - ?line {ok, _Pid} = snmpm_config:start_link(Opts), + {ok, _Pid} = snmpm_config:start_link(Opts), ?IPRINT("Register usm user"), EngineID = "engine", @@ -2551,9 +2551,9 @@ update_usm_user_info(Conf) when is_list(Conf) -> ok = snmpm_config:register_usm_user(EngineID, UsmUser, UsmConfig), ?IPRINT("verify user user config"), - ?line {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), - ?line {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), - ?line {ok, PrivProto1} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), + {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), + {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), + {ok, PrivProto1} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), ?IPRINT("usm user update 1"), PrivProto2 = usmAesCfb128Protocol, @@ -2562,22 +2562,22 @@ update_usm_user_info(Conf) when is_list(Conf) -> ok = snmpm_config:update_usm_user_info(EngineID, UsmUser, priv_key, PrivKey2), ?IPRINT("verify updated user user config after update 1"), - ?line {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), - ?line {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), - ?line {ok, PrivProto2} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), - ?line {ok, PrivKey2} = snmpm_config:usm_user_info(EngineID, UsmUser, priv_key), + {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), + {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), + {ok, PrivProto2} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), + {ok, PrivKey2} = snmpm_config:usm_user_info(EngineID, UsmUser, priv_key), ?IPRINT("usm user update 2"), PrivProto3 = PrivProto1, ok = snmpm_config:update_usm_user_info(EngineID, UsmUser, priv, PrivProto3), ?IPRINT("verify updated user user config after update 2"), - ?line {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), - ?line {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), - ?line {ok, PrivProto3} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), + {ok, AuthProto} = snmpm_config:usm_user_info(EngineID, UsmUser, auth), + {ok, AuthKey} = snmpm_config:usm_user_info(EngineID, UsmUser, auth_key), + {ok, PrivProto3} = snmpm_config:usm_user_info(EngineID, UsmUser, priv), ?IPRINT("Stop config server"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), ?IPRINT("done"), ok. @@ -2595,7 +2595,7 @@ update_usm_user_info(Conf) when is_list(Conf) -> create_and_increment(suite) -> []; create_and_increment(doc) -> - "Craete and increment counters."; + "Create and increment counters."; create_and_increment(Conf) when is_list(Conf) -> put(tname, "CRE-AND-INC"), ?IPRINT("start"), @@ -2609,7 +2609,7 @@ create_and_increment(Conf) when is_list(Conf) -> Opts = [{versions, [v1]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], - ?line {ok, _Pid} = snmpm_config:start_link(Opts), + {ok, _Pid} = snmpm_config:start_link(Opts), %% Random init ?SNMP_RAND_SEED(), @@ -2618,10 +2618,10 @@ create_and_increment(Conf) when is_list(Conf) -> IncVal = 42, EndVal = StartVal + IncVal, - ?line StartVal = snmpm_config:cre_counter(test_id, StartVal), - ?line EndVal = snmpm_config:incr_counter(test_id, IncVal), + StartVal = snmpm_config:cre_counter(test_id, StartVal), + EndVal = snmpm_config:incr_counter(test_id, IncVal), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), ok. @@ -2652,27 +2652,27 @@ stats_create_and_increment(Conf) when is_list(Conf) -> Opts = [{versions, [v1]}, {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], - ?line {ok, _Pid} = snmpm_config:start_link(Opts), + {ok, _Pid} = snmpm_config:start_link(Opts), ?IPRINT("stats table (1): ~p", [ets:tab2list(snmpm_stats_table)]), - ?line 0 = snmpm_config:maybe_cre_stats_counter(stats1, 0), + 0 = snmpm_config:maybe_cre_stats_counter(stats1, 0), ?IPRINT("stats table (2): ~p", [ets:tab2list(snmpm_stats_table)]), - ?line ok = snmpm_config:maybe_cre_stats_counter(stats1, 0), + ok = snmpm_config:maybe_cre_stats_counter(stats1, 0), ?IPRINT("stats table (3): ~p", [ets:tab2list(snmpm_stats_table)]), - ?line 1 = snmpm_config:maybe_cre_stats_counter(stats2, 1), + 1 = snmpm_config:maybe_cre_stats_counter(stats2, 1), ?IPRINT("stats table (4): ~p", [ets:tab2list(snmpm_stats_table)]), - ?line 10 = snmpm_config:cre_stats_counter(stats3, 10), + 10 = snmpm_config:cre_stats_counter(stats3, 10), ?IPRINT("stats table (5): ~p", [ets:tab2list(snmpm_stats_table)]), Stats1Inc = fun() -> snmpm_config:incr_stats_counter(stats1, 1) end, - ?line 10 = loop(10, -1, Stats1Inc), + 10 = loop(10, -1, Stats1Inc), ?IPRINT("stats table (6): ~p", [ets:tab2list(snmpm_stats_table)]), - ?line ok = snmpm_config:reset_stats_counter(stats1), + ok = snmpm_config:reset_stats_counter(stats1), - ?line 10 = loop(10, -1, Stats1Inc), + 10 = loop(10, -1, Stats1Inc), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), ok. @@ -2710,13 +2710,13 @@ otp_7219(Config) when is_list(Config) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("start manager config"), - ?line {ok, _Pid1} = snmpm_config:start_link(Opts1), + {ok, _Pid1} = snmpm_config:start_link(Opts1), ?IPRINT("get some manager config"), {ok, {user, _}} = snmpm_config:system_info(net_if_irb), ?IPRINT("stop manager config"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), IRB_TO = 15322, @@ -2725,13 +2725,13 @@ otp_7219(Config) when is_list(Config) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("start manager config"), - ?line {ok, _Pid2} = snmpm_config:start_link(Opts2), + {ok, _Pid2} = snmpm_config:start_link(Opts2), ?IPRINT("get some manager config"), {ok, {user, IRB_TO}} = snmpm_config:system_info(net_if_irb), ?IPRINT("stop manager config"), - ?line ok = snmpm_config:stop(), + ok = snmpm_config:stop(), config_ensure_not_running(), ?IPRINT("done"), @@ -2808,7 +2808,7 @@ otp8395(Conf, SeqNoVal, Expect) -> case config_start(Opts) of {ok, _Pid} when (Expect =:= ok) -> - ?line ok = config_stop(), + ok = config_stop(), ok; {ok, _Pid} when (Expect =/= ok) -> config_stop(), @@ -2867,7 +2867,7 @@ otp_8395_4(Conf) when is_list(Conf) -> {mibs, Mibs}, {versions, Vsns}], - ?line {ok, _Pid} = config_start(Opts), + {ok, _Pid} = config_start(Opts), Counter = otp_8395_4, Initial = 10, @@ -2885,7 +2885,7 @@ otp_8395_4(Conf) when is_list(Conf) -> Val2 = Initial + Increment, Val2 = otp8395_incr_counter(Counter, Initial, Increment, Max), - ?line ok = config_stop(), + ok = config_stop(), ?IPRINT("done"), ok. @@ -2899,6 +2899,14 @@ otp8395_incr_counter(Counter, Initial, Increment, Max) -> %% Internal functions %%====================================================================== +update_agent_info(UserId, Addr, Port, Item, Val) -> + case snmpm_config:agent_info(Addr, Port, target_name) of + {ok, TargetName} -> + snmpm_config:update_agent_info(UserId, TargetName, [{Item, Val}]); + Error -> + Error + end. + config_start(Opts) -> (catch snmpm_config:start_link(Opts)). @@ -3016,7 +3024,7 @@ write_usm_conf2(Dir, Str) -> write_conf_file(Dir, File, Str) -> case file:open(filename:join(Dir, File), write) of {ok, Fd} -> - ?line ok = io:format(Fd, "~s", [Str]), + ok = io:format(Fd, "~s", [Str]), file:close(Fd); {error, Reason} -> Info = diff --git a/lib/snmp/test/snmp_manager_user_SUITE.erl b/lib/snmp/test/snmp_manager_user_SUITE.erl index 04a75232b7fb..b4789bfe89b4 100644 --- a/lib/snmp/test/snmp_manager_user_SUITE.erl +++ b/lib/snmp/test/snmp_manager_user_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -202,16 +202,16 @@ init_per_testcase(Case, Config) when is_list(Config) -> SuiteTopDir = ?config(snmp_suite_top_dir, Config), CaseTopDir = filename:join(SuiteTopDir, atom_to_list(Case)), - ?line ok = file:make_dir(CaseTopDir), + ok = file:make_dir(CaseTopDir), ?IPRINT("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]), MgrTopDir = filename:join(CaseTopDir, "manager/"), - ?line ok = file:make_dir(MgrTopDir), + ok = file:make_dir(MgrTopDir), MgrConfDir = filename:join(MgrTopDir, "conf/"), - ?line ok = file:make_dir(MgrConfDir), + ok = file:make_dir(MgrConfDir), MgrDbDir = filename:join(MgrTopDir, "db/"), - ?line ok = file:make_dir(MgrDbDir), + ok = file:make_dir(MgrDbDir), MgrLogDir = filename:join(MgrTopDir, "log/"), - ?line ok = file:make_dir(MgrLogDir), + ok = file:make_dir(MgrLogDir), Config1 = [{case_top_dir, CaseTopDir}, {manager_dir, MgrTopDir}, @@ -267,24 +267,24 @@ simple_register_and_unregister1(Conf) when is_list(Conf) -> Id = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id), + ok = register_user(Pid, Id), - ?line [Id] = Users2 = which_users(), + [Id] = Users2 = which_users(), ?IPRINT("Users2: ~p", [Users2]), - ?line ok = unregister_user(Pid), + ok = unregister_user(Pid), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid), + stop_user(Pid), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -319,15 +319,15 @@ simple_register_and_unregister2(Conf) when is_list(Conf) -> Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id1), - ?line ok = register_user(Pid, Id2), + ok = register_user(Pid, Id1), + ok = register_user(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -338,15 +338,15 @@ simple_register_and_unregister2(Conf) when is_list(Conf) -> ?IPRINT("Users2: ~p", [Users2]), - ?line ok = unregister_user(Pid, Id1), - ?line ok = unregister_user(Pid, Id2), + ok = unregister_user(Pid, Id1), + ok = unregister_user(Pid, Id2), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid), + stop_user(Pid), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -381,16 +381,16 @@ simple_register_and_unregister3(Conf) when is_list(Conf) -> Id1 = make_ref(), Id2 = make_ref(), - ?line Pid1 = start_user(), - ?line Pid2 = start_user(), + Pid1 = start_user(), + Pid2 = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid1, Id1), - ?line ok = register_user(Pid2, Id2), + ok = register_user(Pid1, Id1), + ok = register_user(Pid2, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -401,16 +401,16 @@ simple_register_and_unregister3(Conf) when is_list(Conf) -> ?IPRINT("Users2: ~p", [Users2]), - ?line ok = unregister_user(Pid1, Id1), - ?line ok = unregister_user(Pid2, Id2), + ok = unregister_user(Pid1, Id1), + ok = unregister_user(Pid2, Id2), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid1), - ?line stop_user(Pid2), + stop_user(Pid1), + stop_user(Pid2), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -437,29 +437,29 @@ register_and_crash1(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("try starting manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), Id = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id), + ok = register_user(Pid, Id), - ?line [Id] = Users2 = which_users(), + [Id] = Users2 = which_users(), ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid), + ok = simulate_crash(Pid), - ?line [Id] = Users3 = which_users(), + [Id] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -487,22 +487,22 @@ register_and_crash2(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("try starting manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id1), - ?line ok = register_user(Pid, Id2), + ok = register_user(Pid, Id1), + ok = register_user(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -512,9 +512,9 @@ register_and_crash2(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid), + ok = simulate_crash(Pid), - ?line Users3 = case which_users() of + Users3 = case which_users() of [Id1, Id2] = U3 -> U3; [Id2, Id1] = U4 -> @@ -525,7 +525,7 @@ register_and_crash2(Conf) when is_list(Conf) -> ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -614,31 +614,31 @@ simple_register_monitor_and_unregister1(Conf) when is_list(Conf) -> Id = make_ref(), ?IPRINT("start user"), - ?line Pid = start_user(), + Pid = start_user(), ?IPRINT("get users (=0)"), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), ?IPRINT("register monitored user"), - ?line ok = register_user_monitor(Pid, Id), + ok = register_user_monitor(Pid, Id), ?IPRINT("get users (=1)"), - ?line [Id] = Users2 = which_users(), + [Id] = Users2 = which_users(), ?IPRINT("Users2: ~p", [Users2]), ?IPRINT("unregister monitored user"), - ?line unregister_user(Pid), + unregister_user(Pid), ?IPRINT("get users (=0)"), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("start user"), - ?line stop_user(Pid), + stop_user(Pid), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -674,15 +674,15 @@ simple_register_monitor_and_unregister2(Conf) when is_list(Conf) -> Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user_monitor(Pid, Id1), - ?line ok = register_user_monitor(Pid, Id2), + ok = register_user_monitor(Pid, Id1), + ok = register_user_monitor(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -692,15 +692,15 @@ simple_register_monitor_and_unregister2(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line ok = unregister_user(Pid, Id1), - ?line ok = unregister_user(Pid, Id2), + ok = unregister_user(Pid, Id1), + ok = unregister_user(Pid, Id2), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid), + stop_user(Pid), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -737,15 +737,15 @@ simple_register_monitor_and_unregister3(Conf) when is_list(Conf) -> Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id1), - ?line ok = register_user_monitor(Pid, Id2), + ok = register_user(Pid, Id1), + ok = register_user_monitor(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -755,14 +755,14 @@ simple_register_monitor_and_unregister3(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line unregister_user(Pid), + unregister_user(Pid), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid), + stop_user(Pid), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -789,31 +789,31 @@ register_monitor_and_crash1(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("try starting manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), Id = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user_monitor(Pid, Id), + ok = register_user_monitor(Pid, Id), - ?line [Id] = Users2 = which_users(), + [Id] = Users2 = which_users(), ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid), + ok = simulate_crash(Pid), ?SLEEP(1000), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -842,22 +842,22 @@ register_monitor_and_crash2(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("try starting manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user_monitor(Pid, Id1), - ?line ok = register_user_monitor(Pid, Id2), + ok = register_user_monitor(Pid, Id1), + ok = register_user_monitor(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -867,15 +867,15 @@ register_monitor_and_crash2(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid), + ok = simulate_crash(Pid), ?SLEEP(1000), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -924,22 +924,22 @@ register_monitor_and_crash3(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("try starting manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), Id1 = make_ref(), Id2 = make_ref(), - ?line Pid = start_user(), + Pid = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user(Pid, Id1), - ?line ok = register_user_monitor(Pid, Id2), + ok = register_user(Pid, Id1), + ok = register_user_monitor(Pid, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -949,15 +949,15 @@ register_monitor_and_crash3(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid), + ok = simulate_crash(Pid), ?SLEEP(1000), - ?line [Id1] = Users3 = which_users(), + [Id1] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -986,7 +986,7 @@ register_monitor_and_crash4(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("start manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), @@ -994,16 +994,16 @@ register_monitor_and_crash4(Conf) when is_list(Conf) -> Id2 = make_ref(), ?IPRINT("start user processes"), - ?line Pid1 = start_user(), - ?line Pid2 = start_user(), + Pid1 = start_user(), + Pid2 = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user_monitor(Pid1, Id1), - ?line ok = register_user_monitor(Pid2, Id2), + ok = register_user_monitor(Pid1, Id1), + ok = register_user_monitor(Pid2, Id2), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -1013,17 +1013,17 @@ register_monitor_and_crash4(Conf) when is_list(Conf) -> end, ?IPRINT("Users2: ~p", [Users2]), - ?line ok = simulate_crash(Pid1), + ok = simulate_crash(Pid1), ?SLEEP(1000), - ?line [Id2] = Users3 = which_users(), + [Id2] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line stop_user(Pid2), + stop_user(Pid2), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -1054,7 +1054,7 @@ register_monitor_and_crash5(Conf) when is_list(Conf) -> {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}], ?IPRINT("start manager"), - ?line ok = snmpm:start_link(Opts), + ok = snmpm:start_link(Opts), ?SLEEP(1000), @@ -1062,14 +1062,14 @@ register_monitor_and_crash5(Conf) when is_list(Conf) -> Id2 = tomat, %% make_ref(), ?IPRINT("start user processes"), - ?line Pid1 = start_user(), - ?line Pid2 = start_user(), + Pid1 = start_user(), + Pid2 = start_user(), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = register_user_monitor(Pid1, Id1), - ?line ok = register_user_monitor(Pid2, Id2), + ok = register_user_monitor(Pid1, Id1), + ok = register_user_monitor(Pid2, Id2), LocalHost = snmp_test_lib:localhost(), @@ -1083,16 +1083,16 @@ register_monitor_and_crash5(Conf) when is_list(Conf) -> Port2 = 5002, EngineId2 = "agentEngineId-2", - ?line ok = register_agent(Pid1, + ok = register_agent(Pid1, Id1, TargetName1, [{address, Address1}, {port, Port1}, {engine_id, EngineId1}]), - ?line ok = register_agent(Pid2, + ok = register_agent(Pid2, Id2, TargetName2, [{address, Address2}, {port, Port2}, {engine_id, EngineId2}]), - ?line Users2 = case which_users() of + Users2 = case which_users() of [Id1, Id2] = U1 -> U1; [Id2, Id1] = U2 -> @@ -1103,7 +1103,7 @@ register_monitor_and_crash5(Conf) when is_list(Conf) -> ?IPRINT("Users2: ~p", [Users2]), ?IPRINT("verify all agent(s): expect 2"), - ?line Agents1 = case which_agents() of + Agents1 = case which_agents() of [TargetName1, TargetName2] = A1 -> A1; [TargetName2, TargetName1] = A2 -> @@ -1113,21 +1113,21 @@ register_monitor_and_crash5(Conf) when is_list(Conf) -> end, ?IPRINT("Agents1: ~p", [Agents1]), - ?line ok = simulate_crash(Pid1), + ok = simulate_crash(Pid1), ?IPRINT("wait some time"), ?SLEEP(1000), - ?line [Id2] = Users3 = which_users(), + [Id2] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line [TargetName2] = Agents2 = which_agents(), + [TargetName2] = Agents2 = which_agents(), ?IPRINT("Agents2: ~p", [Agents2]), - ?line stop_user(Pid2), + stop_user(Pid2), ?IPRINT("stop manager"), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -1217,20 +1217,20 @@ otp7902(Conf) when is_list(Conf) -> ?SLEEP(1000), - ?line [] = Users1 = which_users(), + [] = Users1 = which_users(), ?IPRINT("Users1: ~p", [Users1]), - ?line ok = snmp_manager_user_old:start(), + ok = snmp_manager_user_old:start(), - ?line [_] = Users2 = which_users(), + [_] = Users2 = which_users(), ?IPRINT("Users2: ~p", [Users2]), - ?line ok = snmp_manager_user_old:stop(), + ok = snmp_manager_user_old:stop(), - ?line [] = Users3 = which_users(), + [] = Users3 = which_users(), ?IPRINT("Users3: ~p", [Users3]), - ?line ok = snmpm:stop(), + ok = snmpm:stop(), ?IPRINT("end"), ok. @@ -1312,7 +1312,7 @@ write_manager_conf(Dir, Str) -> write_conf_file(Dir, File, Str) -> - ?line {ok, Fd} = file:open(filename:join(Dir, File), write), - ?line ok = io:format(Fd, "~s", [Str]), + {ok, Fd} = file:open(filename:join(Dir, File), write), + ok = io:format(Fd, "~s", [Str]), file:close(Fd). diff --git a/lib/snmp/test/snmp_note_store_SUITE.erl b/lib/snmp/test/snmp_note_store_SUITE.erl index 3b6d9f9fcd63..469178c37279 100644 --- a/lib/snmp/test/snmp_note_store_SUITE.erl +++ b/lib/snmp/test/snmp_note_store_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -239,7 +239,7 @@ do_notes({_, Pid}, _Config) -> info(suite) -> []; info(doc) -> - ["Testing that we can retreive process info."]; + ["Testing that we can retrieve process info."]; info(Config) when is_list(Config) -> Pre = fun() -> ?IPRINT("try start note-store"), diff --git a/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib b/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib index 0421e64d628d..eeb2535d7d06 100644 --- a/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib +++ b/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib @@ -684,7 +684,7 @@ Setting this object to a null string (one of zero length) has the effect of invaliding the corresponding entry in the atTable object. That - is, it effectively dissasociates the interface + is, it effectively disassociates the interface identified with said entry from the mapping identified with said entry. It is an implementation-specific matter as to whether the @@ -1256,7 +1256,7 @@ Setting this object to the value invalid(2) has the effect of invalidating the corresponding entry in the ipRouteTable object. That is, it - effectively dissasociates the destination + effectively disassociates the destination identified with said entry from the route identified with said entry. It is an implementation-specific matter as to whether the @@ -1475,7 +1475,7 @@ Setting this object to the value invalid(2) has the effect of invalidating the corresponding entry in the ipNetToMediaTable. That is, it effectively - dissasociates the interface identified with said + disassociates the interface identified with said entry from the mapping identified with said entry. It is an implementation-specific matter as to whether the agent removes an invalidated entry diff --git a/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib index e45d9d91da4c..995be37f8091 100644 --- a/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib +++ b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib @@ -221,7 +221,7 @@ sysORUpTime OBJECT-TYPE STATUS current DESCRIPTION "The value of sysUpTime at the time this conceptual row was - last instanciated." + last instantiated." ::= { sysOREntry 4 } diff --git a/lib/snmp/test/snmp_test_data/Test-LLDP-MIB.mib b/lib/snmp/test/snmp_test_data/Test-LLDP-MIB.mib index 40a9fc79e12c..41b8057223ae 100644 --- a/lib/snmp/test/snmp_test_data/Test-LLDP-MIB.mib +++ b/lib/snmp/test/snmp_test_data/Test-LLDP-MIB.mib @@ -30,7 +30,7 @@ t-lldpMIB MODULE-IDENTITY "This is the ripped out bits and pieces of LLDP-MIB that triggered a compilation problem for Erlang/OTP's MIB compiler due to an AUGMENTS in lldpConfigManAddrEntry - refering to a not yet defined OBJECT-TYPE lldpLocManAddrEntry. + referring to a not yet defined OBJECT-TYPE lldpLocManAddrEntry. Rip and rewrite done 2017. Management Information Base module for LLDP configuration, @@ -199,7 +199,7 @@ lldpLocManAddrLen OBJECT-TYPE The management address length field is needed so that the receiving systems that do not implement SNMP will not be required to implement an iana family numbers/address length - equivalency table in order to decode the management adress." + equivalency table in order to decode the management address." REFERENCE "IEEE 802.1AB-2005 9.5.9.2" ::= { lldpLocManAddrEntry 2 } diff --git a/lib/snmp/test/snmp_test_data/TestTrapv2.mib b/lib/snmp/test/snmp_test_data/TestTrapv2.mib index 679ddc14b0fd..2ba59451f5c7 100644 --- a/lib/snmp/test/snmp_test_data/TestTrapv2.mib +++ b/lib/snmp/test/snmp_test_data/TestTrapv2.mib @@ -44,14 +44,14 @@ tst OBJECT IDENTIFIER ::= { system 0 } testTrapv21 NOTIFICATION-TYPE STATUS current DESCRIPTION - "This trap is exactly the v2 correspondance of testTrap1 in + "This trap is exactly the v2 correspondence of testTrap1 in TestTrap mib." ::= { snmp 1 } testTrapv22 NOTIFICATION-TYPE STATUS current DESCRIPTION - "This trap is exactly the v2 correspondance of testTrap2 in + "This trap is exactly the v2 correspondence of testTrap2 in TestTrap mib." ::= { system 0 1 } diff --git a/lib/snmp/test/snmp_test_global_sys_monitor.erl b/lib/snmp/test/snmp_test_global_sys_monitor.erl index 1c90fff68652..e3f59c05e483 100644 --- a/lib/snmp/test/snmp_test_global_sys_monitor.erl +++ b/lib/snmp/test/snmp_test_global_sys_monitor.erl @@ -199,7 +199,7 @@ cast(Msg) -> ok catch C:E:_ -> - {error, {catched, C, E}} + {error, {caught, C, E}} end. %% call(Req) -> @@ -217,7 +217,7 @@ cast(Msg) -> %% end %% catch %% C:E:_ -> -%% {error, {catched, C, E}} +%% {error, {caught, C, E}} %% end. call(Req, Timeout) when (Timeout =:= infinity) -> @@ -229,7 +229,7 @@ call(Req, Timeout) when is_integer(Timeout) andalso (Timeout > 1000) -> call(Req, Timeout) when is_integer(Timeout) -> call(Req, Timeout, Timeout div 2). -%% This peace of wierdness is because on some machines this call has +%% This peace of weirdness is because on some machines this call has %% hung (in a call during end_per_testcase, which had a 1 min timeout, %% or if that was the total time for the test case). %% But because it hung there, we don't really know where it got stuck. @@ -249,7 +249,7 @@ call(Req, Timeout1, Timeout2) -> end catch C:E:_ -> - exit({error, {catched, C, E}}) + exit({error, {caught, C, E}}) end end, {Pid, Mon} = spawn_monitor(F), diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl index 95aab43debc3..97b69dcfa5a9 100644 --- a/lib/snmp/test/snmp_test_lib.erl +++ b/lib/snmp/test/snmp_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2022. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -26,7 +26,7 @@ -export([tc_try/2, tc_try/3, tc_try/4, tc_try/5]). -export([proxy_call/3]). --export([hostname/0, hostname/1, localhost/0, localhost/1, os_type/0, sz/1, +-export([hostname/0, hostname/1, localhost/0, localhost/1, sz/1, display_suite_info/1]). -export([non_pc_tc_maybe_skip/4, os_based_skip/1, @@ -41,8 +41,7 @@ -export([hours/1, minutes/1, seconds/1, sleep/1]). -export([flush_mqueue/0, mqueue/0, mqueue/1, trap_exit/0, trap_exit/1]). -export([ping/1, local_nodes/0, nodes_on/1]). --export([start_node/2, stop_node/1]). --export([is_app_running/1, +-export([is_app_running/1, is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0, ensure_not_running/3]). -export([crypto_start/0, crypto_support/0]). @@ -54,6 +53,8 @@ -export([explicit_inet_backend/0, test_inet_backends/0]). -export([which_host_ip/2]). +%% Convenient exports... +-export([analyze_and_print_host_info/0]). -define(SKIP(R), skip(R, ?MODULE, ?LINE)). @@ -71,7 +72,7 @@ %% conditions. %% Pre: A fun that is nominally part of the test case %% but is an initiation that must be "undone". This is -%% done by the Post fun (regardless if the TC is successfull +%% done by the Post fun (regardless if the TC is successful %% or not). Example: Starts a couple of nodes, %% TC: The test case fun %% Post: A fun that undo what was done by the Pre fun. @@ -119,7 +120,7 @@ tc_try(Case, TCCond, Pre, TC, Post) (C =:= exit) -> tc_print("test case (~w) skip: try post", [C]), (catch Post(State)), - tc_end( f("skipping(catched,~w,tc)", [C]) ), + tc_end( f("skipping(caught,~w,tc)", [C]) ), SKIP; C:E:S -> %% We always check the system events @@ -130,7 +131,7 @@ tc_try(Case, TCCond, Pre, TC, Post) [] -> tc_print("test case failed: try post"), (catch Post(State)), - tc_end( f("failed(catched,~w,tc)", [C]) ), + tc_end( f("failed(caught,~w,tc)", [C]) ), erlang:raise(C, E, S); SysEvs -> tc_print("System Events received during tc: " @@ -150,7 +151,7 @@ tc_try(Case, TCCond, Pre, TC, Post) catch C:{skip, _} = SKIP when (C =:= throw) orelse (C =:= exit) -> - tc_end( f("skipping(catched,~w,tc-pre)", [C]) ), + tc_end( f("skipping(caught,~w,tc-pre)", [C]) ), SKIP; C:E:S -> %% We always check the system events @@ -162,7 +163,7 @@ tc_try(Case, TCCond, Pre, TC, Post) "~n E: ~p" "~n S: ~p", [C, E, S]), - tc_end( f("auto-skip(catched,~w,tc-pre)", [C]) ), + tc_end( f("auto-skip(caught,~w,tc-pre)", [C]) ), SKIP = {skip, f("TC-Pre failure (~w)", [C])}, SKIP; SysEvs -> @@ -186,13 +187,13 @@ tc_try(Case, TCCond, Pre, TC, Post) exit({tc_cond_failed, Reason}) catch C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) -> - tc_end( f("skipping(catched,~w,cond)", [C]) ), + tc_end( f("skipping(caught,~w,cond)", [C]) ), SKIP; C:E:S -> %% We always check the system events before we accept a failure case snmp_test_global_sys_monitor:events() of [] -> - tc_end( f("failed(catched,~w,cond)", [C]) ), + tc_end( f("failed(caught,~w,cond)", [C]) ), erlang:raise(C, E, S); SysEvs -> tc_print("System Events received: " @@ -278,24 +279,17 @@ explicit_inet_backend() -> end. test_inet_backends() -> - case init:get_argument(snmp) of - {ok, SnmpArgs} when is_list(SnmpArgs) -> - test_inet_backends(SnmpArgs, atom_to_list(?FUNCTION_NAME)); - error -> - false - end. - -test_inet_backends([], _) -> - false; -test_inet_backends([[Key, Val] | _], Key) -> - case list_to_atom(string:to_lower(Val)) of - Bool when is_boolean(Bool) -> - Bool; + case application:get_all_env(snmp) of + Env when is_list(Env) -> + case lists:keysearch(test_inet_backends, 1, Env) of + {value, {test_inet_backends, true}} -> + true; + _ -> + false + end; _ -> - false - end; -test_inet_backends([_|Args], Key) -> - test_inet_backends(Args, Key). + false + end. @@ -396,10 +390,10 @@ which_addr(Family, [{_Name, IfOpts} | IfList]) -> which_addr2(_Family, []) -> {error, not_found}; which_addr2(Family, [{addr, Addr}|_]) - when (Family =:= inet) andalso (size(Addr) =:= 4) -> + when (Family =:= inet) andalso (tuple_size(Addr) =:= 4) -> {ok, Addr}; which_addr2(Family, [{addr, Addr}|_]) - when (Family =:= inet6) andalso (size(Addr) =:= 8) -> + when (Family =:= inet6) andalso (tuple_size(Addr) =:= 8) -> {ok, Addr}; which_addr2(Family, [_|IfOpts]) -> which_addr2(Family, IfOpts). @@ -408,20 +402,10 @@ which_addr2(Family, [_|IfOpts]) -> sz(L) when is_list(L) -> length(L); sz(B) when is_binary(B) -> - size(B); + byte_size(B); sz(O) -> {unknown_size,O}. - -os_type() -> - case (catch test_server:os_type()) of - {'EXIT', _} -> - %% Pre-R10 test server does not have this function - os:type(); - OsType -> - OsType - end. - display_suite_info(SUITE) when is_atom(SUITE) -> (catch do_display_suite_info(SUITE)). @@ -692,7 +676,7 @@ old_has_support_ipv6() -> old_has_support_ipv6(Hostname) -> case inet:getaddr(Hostname, inet6) of - {ok, Addr} when (size(Addr) =:= 8) andalso + {ok, Addr} when (tuple_size(Addr) =:= 8) andalso (element(1, Addr) =/= 0) andalso (element(1, Addr) =/= 16#fe80) -> true; @@ -968,7 +952,7 @@ skip(Reason, Module, Line) -> exit({skip, String}). -%% This function prints various host info, which might be usefull +%% This function prints various host info, which might be useful %% when analyzing the test suite (results). %% It also returns a "factor" that can be used when deciding %% the load for some test cases. Such as run time or number of @@ -1009,82 +993,426 @@ analyze_and_print_host_info() -> "~n Num Online Schedulers: ~s" "~n TS Extra Platform Label: ~s" "~n", [OsFam, OsName, Version, str_num_schedulers(), - ts_extra_flatform_label()]), + ts_extra_platform_label()]), {num_schedulers_to_factor(), []} end. -ts_extra_flatform_label() -> +ts_extra_platform_label() -> case os:getenv("TS_EXTRA_PLATFORM_LABEL") of false -> "-"; Val -> Val end. -simplify_label(Label) -> - case string:to_lower(Label) of - "docker" ++ _ -> - docker; +ts_scale_factor() -> + case timetrap_scale_factor() of + N when is_integer(N) andalso (N > 0) -> + N - 1; _ -> - host + 0 end. - linux_which_distro(Version) -> - Label = ts_extra_flatform_label(), - case file:read_file_info("/etc/issue") of + Label = ts_extra_platform_label(), + Checks = + [fun() -> do_linux_which_distro_os_release(Version, Label) end, + fun() -> do_linux_which_distro_suse_release(Version, Label) end, + fun() -> do_linux_which_distro_fedora_release(Version, Label) end, + fun() -> do_linux_which_distro_issue(Version, Label) end], + try linux_which_distro("", Version, Label, Checks) + catch + throw:{distro, Distro} -> + Distro + end. + +linux_which_distro("", Version, Label, []) -> + io:format("Linux: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", [Version, Label, + linux_product_name()]), + {other, simplify_label(Label)}; +linux_which_distro(DestroStr, Version, Label, []) -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", [Version, DestroStr, Label, + linux_product_name()]), + {other, simplify_label(Label)}; +linux_which_distro(Default, Version, Label, [Check|Checks]) -> + try Check() of + DistroStr when is_list(DistroStr) -> + linux_which_distro(DistroStr, Version, Label, Checks); + retry -> + linux_which_distro(Default, Version, Label, Checks); + {error, _Reason} -> + linux_which_distro(Default, Version, Label, Checks) + catch + throw:{error, _Reason} -> + linux_which_distro(Default, Version, Label, Checks) + end. + +do_linux_which_distro_os_release(Version, Label) -> + case file:read_file_info("/etc/os-release") of + {ok, _} -> + %% We want to 'catch' if our processing is wrong, + %% that's why we catch and re-throw the distro. + %% Actual errors will be returned as 'ignore'. + try + begin + Info = linux_process_os_release(), + {value, {_, DistroStr}} = lists:keysearch(name, 1, Info), + {value, {_, VersionNo}} = lists:keysearch(version, 1, Info), + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, VersionNo, Label, + linux_product_name()]), + throw({distro, + {linux_distro_str_to_distro_id(DistroStr), + simplify_label(Label)}}) + end + catch + throw:{distro, _} = DISTRO -> + throw(DISTRO); + _:_ -> + retry + end; + _ -> + retry + end. + + +linux_process_os_release() -> + %% Read the "raw" file + Raw = os:cmd("cat /etc/os-release"), + %% Split it into lines + Lines1 = string:tokens(Raw, [$\n]), + %% Just in case, skip any lines starting with '#'. + Lines2 = linux_process_os_release1(Lines1), + %% Each (remaining) line *should* be: = + %% Both sides will be strings, the value side will be a quoted string... + %% Convert those into a 2-tuple list: [{Tag, Value}] + linux_process_os_release2(Lines2). + +linux_process_os_release1(Lines) -> + linux_process_os_release1(Lines, []). + +linux_process_os_release1([], Acc) -> + lists:reverse(Acc); +linux_process_os_release1([H|T], Acc) -> + case H of + "#" ++ _ -> + linux_process_os_release1(T, Acc); + _ -> + linux_process_os_release1(T, [H|Acc]) + end. + +linux_process_os_release2(Lines) -> + linux_process_os_release2(Lines, []). + +linux_process_os_release2([], Acc) -> + lists:reverse(Acc); +linux_process_os_release2([H|T], Acc) -> + case linux_process_os_release3(H) of + {value, Value} -> + linux_process_os_release2(T, [Value|Acc]); + false -> + linux_process_os_release2(T, Acc) + end. + +linux_process_os_release3(H) -> + case [string:strip(S) || S <- string:tokens(H, [$=])] of + [Tag, Value] -> + Tag2 = list_to_atom(string:to_lower(Tag)), + Value2 = string:strip(Value, both, $"), + linux_process_os_release4(Tag2, Value2); + _ -> + false + end. + +linux_process_os_release4(name = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(version = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(version_id = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(id = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(pretty_name = Tag, Value) -> + {value, {Tag, Value}}; +linux_process_os_release4(_Tag, _Value) -> + false. + + +linux_distro_str_to_distro_id("Debian" ++ _) -> + debian; +linux_distro_str_to_distro_id("Fedora" ++ _) -> + fedora; +linux_distro_str_to_distro_id("Linux Mint" ++ _) -> + linux_mint; +linux_distro_str_to_distro_id("MontaVista" ++ _) -> + montavista; +linux_distro_str_to_distro_id("openSUSE" ++ _) -> + suse; +linux_distro_str_to_distro_id("SLES" ++ _) -> + sles; +linux_distro_str_to_distro_id("Ubuntu" ++ _) -> + ubuntu; +linux_distro_str_to_distro_id("Wind River Linux" ++ _) -> + wind_river; +linux_distro_str_to_distro_id("Yellow Dog" ++ _) -> + yellow_dog; +linux_distro_str_to_distro_id(X) -> + X. + + +do_linux_which_distro_fedora_release(Version, Label) -> + %% Check if fedora + case file:read_file_info("/etc/fedora-release") of {ok, _} -> case [string:trim(S) || - S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of - [DistroStr|_] -> + S <- string:tokens(os:cmd("cat /etc/fedora-release"), + [$\n])] of + [DistroStr | _] -> io:format("Linux: ~s" "~n Distro: ~s" "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" "~n", - [Version, DistroStr, Label]), - {case DistroStr of - "Wind River Linux" ++ _ -> - wind_river; - "MontaVista" ++ _ -> - montavista; - "Yellow Dog" ++ _ -> - yellow_dog; - "Debian" ++ _ -> - debian; - _ -> - other - end, - simplify_label(Label)}; - X -> + [Version, DistroStr, Label, + linux_product_name()]); + _ -> io:format("Linux: ~s" - "~n Distro: ~p" + "~n Distro: ~s" "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" "~n", - [Version, X, Label]), - {other, simplify_label(Label)} + [Version, "Fedora", Label, + linux_product_name()]) + end, + throw({distro, {fedora, simplify_label(Label)}}); + _ -> + throw({error, not_found}) + end. + +do_linux_which_distro_suse_release(Version, Label) -> + %% Check if its a SuSE + case file:read_file_info("/etc/SUSE-brand") of + {ok, _} -> + case file:read_file_info("/etc/SuSE-release") of + {ok, _} -> + case [string:trim(S) || + S <- string:tokens(os:cmd("cat /etc/SuSE-release"), + [$\n])] of + ["SUSE Linux Enterprise Server" ++ _ = DistroStr | _] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, {sles, simplify_label(Label)}}); + [DistroStr | _] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, "SuSE", Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}) + end; + _ -> + case string:tokens(os:cmd("cat /etc/SUSE-brand"), [$\n]) of + ["SLE" = DistroStr, VERSION | _] -> + case [string:strip(S) || + S <- string:tokens(VERSION, [$=])] of + ["VERSION", VersionNo] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, + DistroStr, VersionNo, + Label, + linux_product_name()]), + throw({distro, + {sles, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {sles, simplify_label(Label)}}) + end; + ["openSUSE" = DistroStr, VERSION | _] -> + case [string:strip(S) || + S <- string:tokens(VERSION, [$=])] of + ["VERSION", VersionNo] -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n Distro Version: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, + DistroStr, VersionNo, + Label, + linux_product_name()]), + throw({distro, + {suse, simplify_label(Label)}}); + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {suse, simplify_label(Label)}}) + end; + _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, "Unknown SUSE", Label, + linux_product_name()]), + throw({distro, {suse, simplify_label(Label)}}) + end end; _ -> - io:format("Linux: ~s" - "~n TS Extra Platform Label: ~s" - "~n", [Version, Label]), - {other, simplify_label(Label)} + throw({error, not_found}) + end. + +do_linux_which_distro_issue(Version, Label) -> + case file:read_file_info("/etc/issue") of + {ok, _} -> + case [string:trim(S) || + S <- string:tokens(os:cmd("cat /etc/issue"), [$\n])] of + [DistroStr | _] -> + case DistroStr of + "Wind River Linux" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {wind_river, simplify_label(Label)}}); + "MontaVista" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {montavista, simplify_label(Label)}}); + "Yellow Dog" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {yellow_dog, simplify_label(Label)}}); + "Debian" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {debian, simplify_label(Label)}}); + "Ubuntu" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {ubuntu, simplify_label(Label)}}); + "Linux Mint" ++ _ -> + io:format("Linux: ~s" + "~n Distro: ~s" + "~n TS Extra Platform Label: ~s" + "~n Product Name: ~s" + "~n", + [Version, DistroStr, Label, + linux_product_name()]), + throw({distro, + {linux_mint, simplify_label(Label)}}); + _ -> + DistroStr + end; + X -> + X + end; + _ -> + throw({error, not_found}) + end. + + +simplify_label("Systemtap" ++ _) -> + {host, systemtap}; +simplify_label("Meamax" ++ _) -> + {host, meamax}; +simplify_label("Cover" ++ _) -> + {host, cover}; +simplify_label(Label) -> + case string:find(string:to_lower(Label), "docker") of + "docker" ++ _ -> + docker; + _ -> + {host, undefined} end. label2factor(docker) -> 4; -label2factor(host) -> +label2factor({host, meamax}) -> + 2; +label2factor({host, cover}) -> + 6; +label2factor({host, _}) -> 0. + analyze_and_print_linux_host_info(Version) -> - {Distro, Label} = - case file:read_file_info("/etc/issue") of - {ok, _} -> - linux_which_distro(Version); - _ -> - L = ts_extra_flatform_label(), - io:format("Linux: ~s" - "~n TS Extra Platform Label: ~s" - "~n", [Version, L]), - {other, simplify_label(L)} - end, + {Distro, Label} = linux_which_distro(Version), + %% 'VirtFactor' will be 0 unless virtual + VirtFactor = linux_virt_factor(), Factor = case (catch linux_which_cpuinfo(Distro)) of {ok, {CPU, BogoMIPS}} -> @@ -1094,31 +1422,49 @@ analyze_and_print_linux_host_info(Version) -> "~n Num Online Schedulers: ~s" "~n", [CPU, BogoMIPS, str_num_schedulers()]), if - (BogoMIPS > 20000) -> + (BogoMIPS > 50000) -> 1; - (BogoMIPS > 10000) -> + (BogoMIPS > 40000) -> 2; - (BogoMIPS > 5000) -> + (BogoMIPS > 30000) -> 3; - (BogoMIPS > 2000) -> + (BogoMIPS > 20000) -> + 4; + (BogoMIPS > 10000) -> 5; - (BogoMIPS > 1000) -> + (BogoMIPS > 5000) -> 8; + (BogoMIPS > 3000) -> + 12; true -> 10 end; + {ok, "POWER9" ++ _ = CPU} -> + %% For some reason this host is really slow + %% Consider the CPU, it really should not be... + %% But, to not fail a bunch of test cases, we add 5 + case linux_cpuinfo_clock() of + Clock when is_integer(Clock) andalso (Clock > 0) -> + io:format("CPU: " + "~n Model: ~s" + "~n CPU Speed: ~w" + "~n Num Online Schedulers: ~s" + "~n", [CPU, Clock, str_num_schedulers()]), + if + (Clock > 2000) -> + 5 + num_schedulers_to_factor(); + true -> + 10 + num_schedulers_to_factor() + end; + _ -> + num_schedulers_to_factor() + end; {ok, CPU} -> io:format("CPU: " "~n Model: ~s" "~n Num Online Schedulers: ~s" "~n", [CPU, str_num_schedulers()]), - NumChed = erlang:system_info(schedulers), - if - (NumChed > 2) -> - 2; - true -> - 5 - end; + num_schedulers_to_factor(); _ -> 5 end, @@ -1137,9 +1483,12 @@ analyze_and_print_linux_host_info(Version) -> "~n Base Factor: ~w" "~n Label Factor: ~w" "~n Mem Factor: ~w" + "~n Virtual Factor: ~w" "~n TS Scale Factor: ~w" - "~n", [Factor, AddLabelFactor, AddMemFactor, TSScaleFactor]), - {Factor + AddLabelFactor + AddMemFactor + TSScaleFactor, [{label, Label}]}. + "~n", [Factor, AddLabelFactor, AddMemFactor, VirtFactor, + TSScaleFactor]), + {Factor + AddLabelFactor + AddMemFactor + VirtFactor + TSScaleFactor, + [{label, Label}]}. linux_cpuinfo_lookup(Key) when is_list(Key) -> @@ -1162,19 +1511,17 @@ linux_cpuinfo_motherboard() -> end. linux_cpuinfo_bogomips() -> - case linux_cpuinfo_lookup("bogomips") of - BMips when is_list(BMips) -> - try lists:sum([bogomips_to_int(BM) || BM <- BMips]) - catch - _:_:_ -> - "-" - end; - _ -> - "-" + case linux_cpuinfo_bogomips("bogomips") of + "-" -> + linux_cpuinfo_bogomips("BogoMIPS"); + Res -> + Res end. -linux_cpuinfo_BogoMIPS() -> - case linux_cpuinfo_lookup("BogoMIPS") of +linux_cpuinfo_bogomips(Key) -> + case linux_cpuinfo_lookup(Key) of + [] -> + "-"; BMips when is_list(BMips) -> try lists:sum([bogomips_to_int(BM) || BM <- BMips]) catch @@ -1303,7 +1650,7 @@ linux_which_cpuinfo(wind_river) -> end, case linux_cpuinfo_total_bogomips() of "-" -> - case linux_cpuinfo_BogoMIPS() of + case linux_cpuinfo_bogomips() of "-" -> {ok, CPU}; BMips -> @@ -1313,43 +1660,44 @@ linux_which_cpuinfo(wind_river) -> {ok, {CPU, BMips}} end; -%% Check for x86 (Intel, AMD, Raspberry (ARM)) -linux_which_cpuinfo(debian) -> - CPU = - case linux_cpuinfo_model() of - "-" -> - %% ARM (at least some distros...) - case linux_cpuinfo_processor() of - "-" -> - %% Ok, we give up - throw(noinfo); - Proc -> - Proc - end; - ModelName -> - ModelName - end, - case linux_cpuinfo_bogomips() of - "-" -> - {ok, CPU}; - BMips -> - {ok, {CPU, BMips}} - end; - %% Check for x86 (Intel or AMD) -linux_which_cpuinfo(other) -> +linux_which_cpuinfo(Distro) when (Distro =:= debian) orelse + (Distro =:= fedora) orelse + (Distro =:= linux_mint) orelse + (Distro =:= sles) orelse + (Distro =:= suse) orelse + (Distro =:= ubuntu) orelse + (Distro =:= other) -> CPU = case linux_cpuinfo_model_name() of "-" -> - %% ARM (at least some distros...) - case linux_cpuinfo_processor() of - "-" -> - %% Ok, we give up - throw(noinfo); - Proc -> - Proc - end; - ModelName -> + %% This is for POWER9 + case linux_cpuinfo_cpu() of + "POWER9" ++ _ = PowerCPU -> + Machine = + case linux_cpuinfo_machine() of + "-" -> + ""; + M -> + " (" ++ M ++ ")" + end, + PowerCPU ++ Machine; + _X -> + %% ARM (at least some distros...) + case linux_cpuinfo_processor() of + "-" -> + case linux_cpuinfo_model() of + "-" -> + %% Ok, we give up + throw(noinfo); + Model -> + Model + end; + Proc -> + Proc + end + end; + ModelName -> ModelName end, case linux_cpuinfo_bogomips() of @@ -1409,6 +1757,87 @@ linux_which_meminfo() -> end. +linux_product_name() -> + ProductNameFile = "/sys/devices/virtual/dmi/id/product_name", + case file:read_file_info(ProductNameFile) of + {ok, _} -> + case os:cmd("cat " ++ ProductNameFile) of + false -> + "-"; + Info -> + string:trim(Info) + end; + _ -> + "-" + end. + + +linux_info_lookup(Key, File) -> + try [string:trim(S) || S <- string:tokens(os:cmd("grep " ++ "\"" ++ Key ++ "\"" ++ " " ++ File), [$:,$\n])] of + Info -> + linux_info_lookup_collect(Key, Info, []) + catch + _:_:_ -> + "-" + end. + +linux_info_lookup_collect(_Key, [], Values) -> + lists:reverse(Values); +linux_info_lookup_collect(Key, [Key, Value|Rest], Values) -> + linux_info_lookup_collect(Key, Rest, [Value|Values]); +linux_info_lookup_collect(_, _, Values) -> + lists:reverse(Values). + + +linux_virt_factor() -> + linux_virt_factor(linux_product_name()). + +linux_virt_factor("VMware" ++ _) -> + 2; +linux_virt_factor("VirtualBox" ++ _) -> + 4; +linux_virt_factor(_) -> + 0. + + +linux_cpuinfo_machine() -> + case linux_cpuinfo_lookup("machine") of + [M] -> + M; + _ -> + "-" + end. + +linux_cpuinfo_clock() -> + %% This is written as: "3783.000000MHz" + %% So, check unit MHz (handle nothing else). + %% Also, check for both float and integer + %% Also, the freq is per core, and can vary... + case linux_cpuinfo_lookup("clock") of + [C|_] when is_list(C) -> + case lists:reverse(string:to_lower(C)) of + "zhm" ++ CRev -> + try trunc(list_to_float(lists:reverse(CRev))) of + I -> + I + catch + _:_:_ -> + try list_to_integer(lists:reverse(CRev)) of + I -> + I + catch + _:_:_ -> + 0 + end + end; + _ -> + 0 + end; + _ -> + 0 + end. + + %% Just to be clear: This is ***not*** scientific... analyze_and_print_openbsd_host_info(Version) -> io:format("OpenBSD:" @@ -1458,39 +1887,71 @@ analyze_and_print_openbsd_host_info(Version) -> io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), CPUFactor = if - (CPUSpeed =:= -1) -> - 1; - (CPUSpeed >= 2000) -> + (CPUSpeed >= 3000) -> if - (NCPU >= 4) -> + (NCPU >= 8) -> 1; + (NCPU >= 6) -> + 2; + (NCPU >= 4) -> + 3; (NCPU >= 2) -> + 4; + true -> + 10 + end; + (CPUSpeed >= 2000) -> + if + (NCPU >= 8) -> 2; + (NCPU >= 6) -> + 3; + (NCPU >= 4) -> + 4; + (NCPU >= 2) -> + 5; true -> - 3 + 12 + end; + (CPUSpeed >= 1000) -> + if + (NCPU >= 8) -> + 3; + (NCPU >= 6) -> + 4; + (NCPU >= 4) -> + 5; + (NCPU >= 2) -> + 6; + true -> + 14 end; true -> if + (NCPU >= 8) -> + 4; + (NCPU >= 6) -> + 6; (NCPU >= 4) -> - 2; + 8; (NCPU >= 2) -> - 3; + 10; true -> - 4 + 20 end end, MemAddFactor = if - (Memory =:= -1) -> + (Memory >= 16777216) -> 0; (Memory >= 8388608) -> - 0; - (Memory >= 4194304) -> 1; + (Memory >= 4194304) -> + 3; (Memory >= 2097152) -> - 2; + 5; true -> - 3 + 10 end, {CPUFactor + MemAddFactor, []} end @@ -1790,47 +2251,58 @@ analyze_and_print_darwin_host_info(Version) -> %% we need to find some other way to find some info... %% Also, I suppose its possible that we for some other %% reason *fail* to get the info... - case analyze_darwin_software_info() of - [] -> - io:format("Darwin:" - "~n Version: ~s" - "~n Num Online Schedulers: ~s" - "~n", [Version, str_num_schedulers()]), - {num_schedulers_to_factor(), []}; - SwInfo when is_list(SwInfo) -> - SystemVersion = analyze_darwin_sw_system_version(SwInfo), - KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), - HwInfo = analyze_darwin_hardware_info(), - ModelName = analyze_darwin_hw_model_name(HwInfo), - ModelId = analyze_darwin_hw_model_identifier(HwInfo), - ProcName = analyze_darwin_hw_processor_name(HwInfo), - ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), - NumProc = analyze_darwin_hw_number_of_processors(HwInfo), - NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), - Memory = analyze_darwin_hw_memory(HwInfo), - io:format("Darwin:" - "~n System Version: ~s" - "~n Kernel Version: ~s" - "~n Model: ~s (~s)" - "~n Processor: ~s (~s, ~s, ~s)" - "~n Memory: ~s" - "~n Num Online Schedulers: ~s" - "~n", [SystemVersion, KernelVersion, - ModelName, ModelId, - ProcName, ProcSpeed, NumProc, NumCores, - Memory, - str_num_schedulers()]), - CPUFactor = analyze_darwin_cpu_to_factor(ProcName, - ProcSpeed, - NumProc, - NumCores), - MemFactor = analyze_darwin_memory_to_factor(Memory), - if (MemFactor =:= 1) -> - {CPUFactor, []}; - true -> - {CPUFactor + MemFactor, []} - end - end. + Label = ts_extra_platform_label(), + {BaseFactor, MemFactor} = + case analyze_darwin_software_info() of + [] -> + io:format("Darwin:" + "~n Version: ~s" + "~n Num Online Schedulers: ~s" + "~n TS Extra Platform Label: ~s" + "~n", [Version, str_num_schedulers(), Label]), + {num_schedulers_to_factor(), 1}; + SwInfo when is_list(SwInfo) -> + SystemVersion = analyze_darwin_sw_system_version(SwInfo), + KernelVersion = analyze_darwin_sw_kernel_version(SwInfo), + HwInfo = analyze_darwin_hardware_info(), + ModelName = analyze_darwin_hw_model_name(HwInfo), + ModelId = analyze_darwin_hw_model_identifier(HwInfo), + {Processor, CPUFactor} = analyze_darwin_hw_processor(HwInfo), + Memory = analyze_darwin_hw_memory(HwInfo), + io:format("Darwin:" + "~n System Version: ~s" + "~n Kernel Version: ~s" + "~n Model: ~s (~s)" + "~n Processor: ~s" + "~n Memory: ~s" + "~n Num Online Schedulers: ~s" + "~n TS Extra Platform Label: ~s" + "~n~n", + [SystemVersion, KernelVersion, + ModelName, ModelId, + Processor, + Memory, + str_num_schedulers(), Label]), + {CPUFactor, analyze_darwin_memory_to_factor(Memory)} + end, + AddLabelFactor = label2factor(simplify_label(Label)), + AddMemFactor = if + (MemFactor > 0) -> + MemFactor - 1; + true -> + 0 + end, + TSScaleFactor = ts_scale_factor(), + io:format("Factor calc:" + "~n Base Factor: ~w" + "~n Label Factor: ~w" + "~n Mem Factor: ~w" + "~n TS Scale Factor: ~w" + "~n~n", + [BaseFactor, AddLabelFactor, AddMemFactor, TSScaleFactor]), + {BaseFactor + AddLabelFactor + AddMemFactor + TSScaleFactor, + [{label, Label}]}. + analyze_darwin_sw_system_version(SwInfo) -> proplists:get_value("system version", SwInfo, "-"). @@ -1847,6 +2319,32 @@ analyze_darwin_hw_model_name(HwInfo) -> analyze_darwin_hw_model_identifier(HwInfo) -> proplists:get_value("model identifier", HwInfo, "-"). +analyze_darwin_hw_processor(HwInfo) -> + case analyze_darwin_hw_processor_name(HwInfo) of + "-" -> % Maybe Apple Chip + case analyze_darwin_hw_chip(HwInfo) of + "-" -> + "-"; + Chip -> + NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), + CPUFactor = analyze_darwin_cpu_to_factor(Chip, NumCores), + {f("~s [~s]", [Chip, NumCores]), CPUFactor} + end; + ProcName -> + ProcSpeed = analyze_darwin_hw_processor_speed(HwInfo), + NumProc = analyze_darwin_hw_number_of_processors(HwInfo), + NumCores = analyze_darwin_hw_total_number_of_cores(HwInfo), + CPUFactor = analyze_darwin_cpu_to_factor(ProcName, + ProcSpeed, + NumProc, + NumCores), + {f("~s [~s, ~s, ~s]", + [ProcName, ProcSpeed, NumProc, NumCores]), CPUFactor} + end. + +analyze_darwin_hw_chip(HwInfo) -> + proplists:get_value("chip", HwInfo, "-"). + analyze_darwin_hw_processor_name(HwInfo) -> proplists:get_value("processor name", HwInfo, "-"). @@ -1871,17 +2369,25 @@ analyze_darwin_hardware_info() -> %% "Key: Value1:Value2" analyze_darwin_system_profiler(DataType) -> %% First, make sure the program actually exist: - case os:cmd("which system_profiler") of + case string:trim(os:cmd("which system_profiler")) of [] -> - []; - _ -> - D0 = os:cmd("system_profiler " ++ DataType), - D1 = string:tokens(D0, [$\n]), - D2 = [string:trim(S1) || S1 <- D1], - D3 = [string:tokens(S2, [$:]) || S2 <- D2], - analyze_darwin_system_profiler2(D3) + case string:trim(os:cmd("which /usr/sbin/system_profiler")) of + [] -> + []; + Cmd1 -> + analyze_darwin_system_profiler(Cmd1, DataType) + end; + Cmd2 -> + analyze_darwin_system_profiler(Cmd2, DataType) end. +analyze_darwin_system_profiler(Cmd, DataType) -> + D0 = os:cmd(Cmd ++ " " ++ DataType), + D1 = string:tokens(D0, [$\n]), + D2 = [string:trim(S1) || S1 <- D1], + D3 = [string:tokens(S2, [$:]) || S2 <- D2], + analyze_darwin_system_profiler2(D3). + analyze_darwin_system_profiler2(L) -> analyze_darwin_system_profiler2(L, []). @@ -1931,6 +2437,12 @@ analyze_darwin_memory_to_factor(Mem) -> end. +analyze_darwin_cpu_to_factor("Apple" ++ _ = _Chip, _NumCores) -> + 1; +analyze_darwin_cpu_to_factor(_Chip, _NumCores) -> + 8. + + %% The speed is a string: " " %% the speed may be a float, which we transforms into an integer of MHz. %% To calculate a factor based on processor speed, number of procs @@ -2199,66 +2711,118 @@ analyze_and_print_solaris_host_info(Version) -> analyze_and_print_win_host_info(Version) -> + Label = ts_extra_platform_label(), + AddLabelFactor = label2factor(simplify_label(Label)), + SysInfo = which_win_system_info(), OsName = win_sys_info_lookup(os_name, SysInfo), OsVersion = win_sys_info_lookup(os_version, SysInfo), SysMan = win_sys_info_lookup(system_manufacturer, SysInfo), SysMod = win_sys_info_lookup(system_model, SysInfo), + SysType = win_sys_info_lookup(system_type, SysInfo), NumProcs = win_sys_info_lookup(num_processors, SysInfo), TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo), io:format("Windows: ~s" "~n OS Version: ~s (~p)" "~n System Manufacturer: ~s" "~n System Model: ~s" + "~n System Type: ~s" "~n Number of Processor(s): ~s" "~n Total Physical Memory: ~s" + "~n (Erlang) WordSize: ~w" "~n Num Online Schedulers: ~s" "~n~n", [OsName, OsVersion, Version, - SysMan, SysMod, NumProcs, TotPhysMem, + SysMan, SysMod, SysType, + NumProcs, TotPhysMem, + erlang:system_info(wordsize), str_num_schedulers()]), - io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]), + + io:format("TS: " + "~n TimeTrap Factor: ~w" + "~n Extra Platform Label: ~s" + "~n~n", + [timetrap_scale_factor(), Label]), + + %% 'VirtFactor' will be 0 unless virtual + VirtFactor = win_virt_factor(SysMod), + + %% On some machines this is a badly formated string + %% (contains a char of 255), so we need to do some nasty stuff... MemFactor = try begin - [MStr, MUnit|_] = - string:tokens(lists:delete($,, TotPhysMem), [$\ ]), + %% "Normally" this looks like this: "16,123 MB" + %% But sometimes the "," is replaced by a + %% 255 or 160 char, which I assume must be some + %% unicode screwup... + %% Anyway, filter out both of them! + TotPhysMem1 = lists:delete($,, TotPhysMem), + TotPhysMem2 = lists:delete(255, TotPhysMem1), + TotPhysMem3 = lists:delete(160, TotPhysMem2), + [MStr, MUnit|_] = string:tokens(TotPhysMem3, [$\ ]), case string:to_lower(MUnit) of "gb" -> try list_to_integer(MStr) of - M when M > 8 -> + M when M >= 16 -> 0; - M when M > 4 -> + M when M >= 8 -> 1; - M when M > 2 -> - 2; + M when M >= 4 -> + 3; + M when M >= 2 -> + 6; _ -> - 5 + 10 catch _:_:_ -> + %% For some reason the string contains + %% "unusual" characters... + %% ...so print the string as a list... + io:format("Bad memory string: " + "~n [gb] ~w" + "~n", [MStr]), 10 end; "mb" -> try list_to_integer(MStr) of - M when M > 8192 -> + M when M >= 16384 -> 0; - M when M > 4096 -> + M when M >= 8192 -> 1; - M when M > 2048 -> - 2; + M when M >= 4096 -> + 3; + M when M >= 2048 -> + 6; _ -> - 5 + 10 catch _:_:_ -> + %% For some reason the string contains + %% "unusual" characters... + %% ...so print the string as a list... + io:format("Bad memory string: " + "~n [mb] ~w" + "~n", [MStr]), 10 end; _ -> + io:format("Bad memory string: " + "~n ~w" + "~n", [MStr]), 10 end end catch _:_:_ -> + %% For some reason the string contains + %% "unusual" characters... + %% ...so print the string as a list... + io:format("Bad memory string: " + "~n (y) ~w" + "~n", [TotPhysMem]), 10 end, + CPUFactor = case erlang:system_info(schedulers) of 1 -> @@ -2268,7 +2832,19 @@ analyze_and_print_win_host_info(Version) -> _ -> 2 end, - {CPUFactor + MemFactor, SysInfo}. + io:format("Factor calc:" + "~n CPU Factor: ~w" + "~n Mem Factor: ~w" + "~n Label Factor: ~w" + "~n Virtual Factor: ~w" + "~n~n", + [CPUFactor, MemFactor, AddLabelFactor, VirtFactor]), + {CPUFactor + MemFactor + AddLabelFactor + VirtFactor, SysInfo}. + +win_virt_factor("VMware" ++ _) -> + 2; +win_virt_factor(_) -> + 0. win_sys_info_lookup(Key, SysInfo) -> win_sys_info_lookup(Key, SysInfo, "-"). @@ -2349,8 +2925,12 @@ num_schedulers_to_factor() -> 1 -> 10; 2 -> - 5; - N when (N =< 6) -> + 8; + 3 -> + 6; + 4 -> + 4; + N when (N =< 5) -> 2; _ -> 1 @@ -2360,38 +2940,6 @@ num_schedulers_to_factor() -> end. -linux_info_lookup(Key, File) -> - %% try - %% begin - %% GREP = os:cmd("grep " ++ "\"" ++ Key ++ "\"" ++ " " ++ File), - %% io:format("linux_info_lookup() -> GREP: ~p~n", [GREP]), - %% TOKENS = string:tokens(GREP, [$:,$\n]), - %% io:format("linux_info_lookup() -> TOKENS: ~p~n", [TOKENS]), - %% INFO = [string:trim(S) || S <- TOKENS], - %% io:format("linux_info_lookup() -> INFO: ~p~n", [INFO]), - %% linux_info_lookup_collect(Key, INFO, []) - %% end - %% catch - %% _:_:_ -> - %% "-" - %% end. - try [string:trim(S) || S <- string:tokens(os:cmd("grep " ++ "\"" ++ Key ++ "\"" ++ " " ++ File), [$:,$\n])] of - Info -> - linux_info_lookup_collect(Key, Info, []) - catch - _:_:_ -> - "-" - end. - -linux_info_lookup_collect(_Key, [], Values) -> - lists:reverse(Values); -linux_info_lookup_collect(Key, [Key, Value|Rest], Values) -> - linux_info_lookup_collect(Key, Rest, [Value|Values]); -linux_info_lookup_collect(_, _, Values) -> - lists:reverse(Values). - - - %% ---------------------------------------------------------------- %% Time related function %% @@ -2468,15 +3016,6 @@ nodes_on(Host) when is_list(Host) -> net_adm:world_list([list_to_atom(Host)]). -start_node(Name, Args) -> - Opts = [{cleanup, false}, {args, Args}], - test_server:start_node(Name, peer, Opts). - - -stop_node(Node) -> - test_server:stop_node(Node). - - %% ---------------------------------------------------------------- %% Application and Crypto utility functions %% diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl index ea7732eba89d..f57f2b0e35c5 100644 --- a/lib/snmp/test/snmp_test_lib.hrl +++ b/lib/snmp/test/snmp_test_lib.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2022. 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. @@ -103,9 +103,6 @@ -define(PING(N), ?LIB:ping(N)). -define(LNODES(), ?LIB:local_nodes()). -define(NODES(H), ?LIB:nodes_on(H)). --define(START_NODE(N,A), ?LIB:start_node(N,A)). --define(STOP_NODE(N), ?LIB:stop_node(N)). - %% - Application and Crypto utility macros - @@ -158,3 +155,9 @@ -define(FTS(), snmp_misc:formated_timestamp()). -define(FTS(TS), snmp_misc:format_timestamp(TS)). +%% This needs to be a macro-definition to capture ?FUNCTION_NAME and ?MODULE. +-define (START_PEER(Kind), ?CT_PEER(#{ + name => ?CT_PEER_NAME(atom_to_list(?FUNCTION_NAME) ++ Kind), + args => ["-s", "snmp_test_sys_monitor", "start", "-s", "global", "sync"] +})). +-define(STOP_PEER(__P__), peer:stop(__P__)). diff --git a/lib/snmp/test/snmp_test_manager.erl b/lib/snmp/test/snmp_test_manager.erl index 38ec1d9ce336..1bd1351a76af 100644 --- a/lib/snmp/test/snmp_test_manager.erl +++ b/lib/snmp/test/snmp_test_manager.erl @@ -155,7 +155,7 @@ parse_opts(Opts) -> MgrDir = get_opt(dir, get_opt(config, MgrOpts, [])), - %% Retreive the agent configuration + %% Retrieve the agent configuration AgentConf = get_opt(agent_config, Opts), AgentTarget = get_opt(agent_target, Opts), {MgrDir, MgrConf, MgrOpts, AgentTarget, AgentConf}. diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index d9caa15cdb02..9621bb2e7d6f 100644 --- a/lib/snmp/test/snmp_test_mgr.erl +++ b/lib/snmp/test/snmp_test_mgr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -147,7 +147,7 @@ receive_response() -> receive_response(get_timeout()). receive_response(Timeout) -> - d("await response within ~w ms",[Timeout]), + d("await response within ~w ms", [Timeout]), receive {snmp_pdu, PDU} when is_record(PDU, pdu) -> d("[await response] received PDU: " @@ -158,7 +158,8 @@ receive_response(Timeout) -> "~n ~p", [Reason]), ERROR after Timeout -> - ?EPRINT("[await response] unexpected timeout"), + ?EPRINT("[await response] unexpected timeout: " + "~n ~p", [process_info(self(), messages)]), {error, timeout} end. @@ -255,14 +256,12 @@ init({Options, CallerPid}) -> IpFamily = get_value(ipfamily, Options, inet), ?IPRINT("init -> IpFamily: ~p", [IpFamily]), AgIp = case snmp_misc:assq(agent, Options) of - {value, Addr} when is_tuple(Addr) andalso - (size(Addr) =:= 4) andalso - (IpFamily =:= inet) -> + {value, Addr} when (tuple_size(Addr) =:= 4) andalso + (IpFamily =:= inet) -> ?IPRINT("init -> Addr: ~p", [Addr]), Addr; - {value, Addr} when is_tuple(Addr) andalso - (size(Addr) =:= 8) andalso - (IpFamily =:= inet6) -> + {value, Addr} when (tuple_size(Addr) =:= 8) andalso + (IpFamily =:= inet6) -> ?IPRINT("init -> Addr: ~p", [Addr]), Addr; {value, Host} when is_list(Host) -> @@ -1303,7 +1302,7 @@ cast(Msg) -> sizeOf(L) when is_list(L) -> length(lists:flatten(L)); sizeOf(B) when is_binary(B) -> - size(B). + byte_size(B). d(F) -> d(F, []). d(F, A) -> d(get(debug), F, A). diff --git a/lib/snmp/test/snmp_test_mgr_counter_server.erl b/lib/snmp/test/snmp_test_mgr_counter_server.erl index 697afdf7994d..49f273e04a18 100644 --- a/lib/snmp/test/snmp_test_mgr_counter_server.erl +++ b/lib/snmp/test/snmp_test_mgr_counter_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2016. All Rights Reserved. +%% Copyright Ericsson AB 2014-2022. 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. @@ -23,7 +23,7 @@ %% agent test suite is implemented in such a way that the %% agent is started once and then used for several test cases. %% Each request is given a request id which *was* generated using -%% random! It is therefor possible, although unlikely, that a +%% random! It is therefore possible, although unlikely, that a %% request may get a request id that has recently been used, %% which will cause the agent to silently reject the request. %% For this reason, we start this server at the start of the diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl index 506ceb6a5e1b..ed3785d0199c 100644 --- a/lib/snmp/test/snmp_test_mgr_misc.erl +++ b/lib/snmp/test/snmp_test_mgr_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -394,7 +394,7 @@ handle_v1_or_v2_message(Mgr, _UdpId, Ip, UdpPort, _AgentIp, end. -%% This function assumes that the agent and the manager (thats us) +%% This function assumes that the agent and the manager (that's us) %% has the same version. check_discovery_result('version-3', DiscoReqMsg, DiscoRspMsg) -> ReqMsgID = getMsgID(DiscoReqMsg), @@ -776,7 +776,7 @@ ensure_dead_kill(Pid, MRef, Timeout) -> display_incomming_message(M) -> - display_message("Incomming",M). + display_message("Incoming",M). display_outgoing_message(M) -> display_message("Outgoing", M). @@ -961,7 +961,7 @@ display_prop_hdr(S) -> sz(L) when is_list(L) -> iolist_size(L); sz(B) when is_binary(B) -> - size(B); + byte_size(B); sz(O) -> {unknown_size, O}. diff --git a/lib/snmp/test/snmp_test_server.erl b/lib/snmp/test/snmp_test_server.erl index ac874e47beb5..0eb7065b8519 100644 --- a/lib/snmp/test/snmp_test_server.erl +++ b/lib/snmp/test/snmp_test_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2020. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -322,7 +322,7 @@ display_failed(Failed) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Verify that the actual result of a test case matches the exected one +%% Verify that the actual result of a test case matches the expected one %% Returns the actual result %% Stores the result in the process dictionary if mismatch diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl index 1152c8ec49d2..6a659e6aeda0 100644 --- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl @@ -411,7 +411,7 @@ erlang_agent_netsnmp_get(Config) when is_list(Config) -> "~n ~s", [Rest]), throw({skip, Rest}); Any -> - ct:pal("Received unexpected reponse: " + ct:pal("Received unexpected response: " "~n ~p", [Any]), exit({unexpected, Any}) end || Transport <- Transports], diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib index 679ddc14b0fd..2ba59451f5c7 100644 --- a/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib +++ b/lib/snmp/test/snmp_to_snmpnet_SUITE_data/TestTrapv2.mib @@ -44,14 +44,14 @@ tst OBJECT IDENTIFIER ::= { system 0 } testTrapv21 NOTIFICATION-TYPE STATUS current DESCRIPTION - "This trap is exactly the v2 correspondance of testTrap1 in + "This trap is exactly the v2 correspondence of testTrap1 in TestTrap mib." ::= { snmp 1 } testTrapv22 NOTIFICATION-TYPE STATUS current DESCRIPTION - "This trap is exactly the v2 correspondance of testTrap2 in + "This trap is exactly the v2 correspondence of testTrap2 in TestTrap mib." ::= { system 0 1 } diff --git a/lib/snmp/test/test-mibs/RFC1213-MIB.mib b/lib/snmp/test/test-mibs/RFC1213-MIB.mib index 0421e64d628d..eeb2535d7d06 100644 --- a/lib/snmp/test/test-mibs/RFC1213-MIB.mib +++ b/lib/snmp/test/test-mibs/RFC1213-MIB.mib @@ -684,7 +684,7 @@ Setting this object to a null string (one of zero length) has the effect of invaliding the corresponding entry in the atTable object. That - is, it effectively dissasociates the interface + is, it effectively disassociates the interface identified with said entry from the mapping identified with said entry. It is an implementation-specific matter as to whether the @@ -1256,7 +1256,7 @@ Setting this object to the value invalid(2) has the effect of invalidating the corresponding entry in the ipRouteTable object. That is, it - effectively dissasociates the destination + effectively disassociates the destination identified with said entry from the route identified with said entry. It is an implementation-specific matter as to whether the @@ -1475,7 +1475,7 @@ Setting this object to the value invalid(2) has the effect of invalidating the corresponding entry in the ipNetToMediaTable. That is, it effectively - dissasociates the interface identified with said + disassociates the interface identified with said entry from the mapping identified with said entry. It is an implementation-specific matter as to whether the agent removes an invalidated entry diff --git a/lib/snmp/test/test-mibs/SNMPv2-MIB.mib b/lib/snmp/test/test-mibs/SNMPv2-MIB.mib index 0c5418b9ce4c..e07e5ae16b47 100644 --- a/lib/snmp/test/test-mibs/SNMPv2-MIB.mib +++ b/lib/snmp/test/test-mibs/SNMPv2-MIB.mib @@ -221,7 +221,7 @@ sysORUpTime OBJECT-TYPE STATUS current DESCRIPTION "The value of sysUpTime at the time this conceptual row was - last instanciated." + last instantiated." ::= { sysOREntry 4 } @@ -375,7 +375,7 @@ tst OBJECT IDENTIFIER ::= { system 0 } testTrapv22 NOTIFICATION-TYPE STATUS current DESCRIPTION - "This trap is exactly the v2 correspondance of testTrap2 in + "This trap is exactly the v2 correspondence of testTrap2 in TestTrap mib." ::= { system 0 1 } diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib index 1d75c4bbd8d5..f6051f7a7177 100644 --- a/lib/snmp/test/test-mibs/SNMPv2-TC.mib +++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib @@ -629,7 +629,7 @@ value | | see 1| ->C| ->D time should be long enough to allow for human response time (including `think time') between the creation of the conceptual row and the setting of the status to `active'. - In the absense of such information in the DESCRIPTION + In the absence of such information in the DESCRIPTION clause, it is suggested that this period be approximately 5 minutes in length. This removal action applies not only to newly-created rows, but also to previously active rows which diff --git a/lib/snmp/test/test-mibs/SNMPv2-test.mib b/lib/snmp/test/test-mibs/SNMPv2-test.mib index b02be091383f..f435660b2c04 100644 --- a/lib/snmp/test/test-mibs/SNMPv2-test.mib +++ b/lib/snmp/test/test-mibs/SNMPv2-test.mib @@ -163,7 +163,7 @@ sysQ OBJECT-TYPE MAX-ACCESS read-write STATUS current DESCRIPTION - "The auxiliar the SYNTAX." + "The auxiliary the SYNTAX." DEFVAL { { a, b } } ::= { system 11 } @@ -231,7 +231,7 @@ sysORUpTime OBJECT-TYPE STATUS current DESCRIPTION "The value of sysUpTime at the time this conceptual row was - last instanciated." + last instantiated." ::= { sysOREntry 4 } diff --git a/lib/snmp/test/test_config/Makefile b/lib/snmp/test/test_config/Makefile index 1e53f51b830d..af765cfa5a7d 100644 --- a/lib/snmp/test/test_config/Makefile +++ b/lib/snmp/test/test_config/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2016. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -117,7 +117,7 @@ endif # Targets # ---------------------------------------------------- -tests debug opt: $(TARGETS) +tests $(TYPES): $(TARGETS) clean: rm -f $(CONFIG_FILES) diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 72175ec5d20d..226bf3e50c8f 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 5.12.0.3 +SNMP_VSN = 5.15 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile index a4a25f8eed4f..3835866fcc3f 100644 --- a/lib/ssh/doc/src/Makefile +++ b/lib/ssh/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2021. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -63,7 +63,7 @@ BOOK_FILES = book.xml XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES)\ $(XML_PART_FILES) $(XML_CHAPTER_FILES) -IMAGE_FILES = SSH_protocols.png +IMAGE_FILES = SSH_protocols.png ssh_timeouts.jpg TOP_SPECS_FILE = specs.xml diff --git a/lib/ssh/doc/src/SSH_app.xml b/lib/ssh/doc/src/SSH_app.xml index 8f3b5fc80b54..4d12669c1e04 100644 --- a/lib/ssh/doc/src/SSH_app.xml +++ b/lib/ssh/doc/src/SSH_app.xml @@ -282,7 +282,7 @@
    Unicode support -

    Unicode filenames are supported if the emulator and the underlaying OS support it. See section DESCRIPTION in the +

    Unicode filenames are supported if the emulator and the underlying OS support it. See section DESCRIPTION in the file manual page in Kernel for information about this subject.

    The shell and the cli both support unicode. diff --git a/lib/ssh/doc/src/configurations.xml b/lib/ssh/doc/src/configurations.xml index cd55e8702705..56dc84e7e01b 100644 --- a/lib/ssh/doc/src/configurations.xml +++ b/lib/ssh/doc/src/configurations.xml @@ -4,7 +4,7 @@

    - 2020 + 20202022 Ericsson AB. All Rights Reserved. @@ -105,7 +105,7 @@

    There is an ordering, which is:

    - Level 0: Hard-coded default values in the source code + Level 0: Hard-coded default values in the OTP SSH source code Level 1: OTP Configuration Parameters Level 2: Options in the OTP Configuration Parameters server_options or client_options @@ -116,7 +116,7 @@

    The only exception is the modify_algorithms common option. They are all applied in ascending level order on the set of algorithms. So a - modify_algorithms on level zero is applied before one of level one and so on. + modify_algorithms on level one is applied before one of level two and so on.

    If there is an preferred_algorithms @@ -250,7 +250,7 @@ ok ]). {ok,>0.118.0>} -

    We check which algoritms are negotiated by the client and the server, and note that +

    We check which algorithms are negotiated by the client and the server, and note that the (only) kex algorithm 'curve25519-sha256@libssh.org' was selected:

    diff --git a/lib/ssh/doc/src/configure_algos.xml b/lib/ssh/doc/src/configure_algos.xml index acc6269da533..bbfbdb5e61dd 100644 --- a/lib/ssh/doc/src/configure_algos.xml +++ b/lib/ssh/doc/src/configure_algos.xml @@ -5,7 +5,7 @@
    2017 - 2021 + 2023 Ericsson AB. All Rights Reserved. @@ -75,15 +75,15 @@ public_key

    Server host key

    -

    The asymetric encryption algorithm used in the server's private-public host key pair. +

    The asymmetric encryption algorithm used in the server's private-public host key pair. Examples include the well-known RSA 'ssh-rsa' and elliptic curve 'ecdsa-sha2-nistp521'.

    cipher -

    Symetric cipher algorithm used for the payload encryption. This algorithm will use the key calculated - in the kex phase (together with other info) to genereate the actual key used. Examples are +

    Symmetric cipher algorithm used for the payload encryption. This algorithm will use the key calculated + in the kex phase (together with other info) to generate the actual key used. Examples are tripple-DES '3des-cbc' and one of many AES variants 'aes192-ctr'.

    This list is actually two - one for each direction server-to-client and client-to-server. Therefore it @@ -110,13 +110,13 @@

    The SSH app's mechanism -

    The set of algorithms that the SSH app uses by default depends on the algoritms supported by the:

    +

    The set of algorithms that the SSH app uses by default depends on the algorithms supported by the:

    crypto app,

    -

    The cryptolib OTP is linked with, usally the one the OS uses, probably OpenSSL,

    +

    The cryptolib OTP is linked with, usually the one the OS uses, probably OpenSSL,

    -

    and finaly what the SSH app implements

    +

    and finally what the SSH app implements

    Due to this, it impossible to list in documentation what algorithms that are available in a certain installation.

    @@ -170,7 +170,7 @@

    To forsee the effect of an option there is an experimental function ssh:chk_algos_opts(Opts). It mangles the options preferred_algorithms - and modify_algorithms in the same way as ssh:dameon, ssh:connect and their friends does.

    + and modify_algorithms in the same way as ssh:daemon, ssh:connect and their friends does.

    Example 1 @@ -322,7 +322,7 @@
    Example 5

    As an example let's add the Diffie-Hellman Group1 first in the kex list. It is supported according to - Supported algoritms.

    + Supported algorithms.

    5> ssh:chk_algos_opts( [{modify_algorithms, @@ -432,7 +432,7 @@
    Example 8

    In this example, we need to use a diffie-hellman-group1-sha1 key exchange algorithm - although it is unsage and disabled by default. + although it is unsafe and disabled by default.

    We use the modify_algorithms diff --git a/lib/ssh/doc/src/hardening.xml b/lib/ssh/doc/src/hardening.xml index c1d3f7669cab..cc530ace0e10 100644 --- a/lib/ssh/doc/src/hardening.xml +++ b/lib/ssh/doc/src/hardening.xml @@ -5,14 +5,14 @@

    2017 - 2020 + 2022 Ericsson AB. 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 @@ -59,43 +59,64 @@ However, some measures could be taken in the configuration of the SSH server to increase the resilence. The options to use are:

    - - hello_timeout - - If the client fails to send the first ssh message after a tcp connection setup - within this time (in milliseconds), the connection is closed. - The default value is 30 seconds. This is actualy a generous time, so it can lowered - to make the daemon less prone to DoS attacks. - - negotiation_timeout - - Maximum time in milliseconds for the authentication negotiation. - If the client fails to log in within this time, the connection is closed. - The default value is 2 minutes. It is quite a long time, but can lowered if the client is - supposed to be fast like if it is a program logging in. - - max_sessions - - The maximum number of simultaneous sessions that are accepted at any time for this daemon. - This includes sessions that are being authorized. The default is that an unlimited number of - simultaneous sessions are allowed. It is a good candidate to set if the capacity of the server - is low or a capacity margin is needed. - - max_channels - - The maximum number of channels that are accepted for each connection. The default is unlimited. - - parallel_login - - If set to false (the default value), only one login is handled at a time. - If set to true, the number of simultaneous login attempts are limited by the value of - max_sessions option. - - idle_time - - Sets a time-out on a connection when no channels are open. Defaults to infinity. - - +
    + Counters and parallelism + + max_sessions + + The maximum number of simultaneous sessions that are accepted at any time for this daemon. + This includes sessions that are being authorized. The default is that an unlimited number of + simultaneous sessions are allowed. It is a good candidate to set if the capacity of the server + is low or a capacity margin is needed. + + max_channels + + The maximum number of channels that are accepted for each connection. The default is unlimited. + + parallel_login + + If set to false (the default value), only one login is handled at a time. + If set to true, the number of simultaneous login attempts are limited by the value of the + max_sessions option. + + +
    + +
    + Timeouts + + hello_timeout + + If the client fails to send the first ssh message after a tcp connection setup + within this time (in milliseconds), the connection is closed. + The default value is 30 seconds. This is actually a generous time, so it can lowered + to make the daemon less prone to DoS attacks. + + negotiation_timeout + + Maximum time in milliseconds for the authentication negotiation counted from the TCP connection establishment. + If the client fails to log in within this time the connection is closed. + The default value is 2 minutes. It is quite a long time, but can lowered if the client is + supposed to be fast like if it is a program logging in. + + idle_time + + Sets a time-out on a connection when no channels are left after closing the final one. + It defaults to infinity. + + max_initial_idle_time + + Sets a time-out on a connection that will expire if no channel is opened on the connection. + The timeout is started when the authentication phase is completed. + It defaults to infinity. + + +

    A figure clarifies when a timeout is started and when it triggers: +

    + + SSH server timeouts + +
    @@ -170,7 +191,7 @@ fun(User, Password, _PeerAddress, State) -> end.

    If a public key is used for logging in, there is normally no checking of the user name. It - could be enabled by setting the option + could be enabled by setting the option pk_check_user to true. In that case the pwdfun will get the atom pubkey in the password argument. @@ -251,7 +272,7 @@ end. ssh:daemon(1234, [{id_string,"hi there"}, ... ]). -

    and the deamon will present itself as:

    +

    and the daemon will present itself as:

    SSH-2.0-hi there

    It is possible to replace the string with one randomly generated for each connection attempt. See the reference manual for id_string. diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index f462e912318d..1e9ea82fb60b 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -4,7 +4,7 @@

    - 20042022 + 20042023 Ericsson AB. All Rights Reserved. @@ -30,6 +30,262 @@ notes.xml
    +
    Ssh 5.0.1 + +
    Fixed Bugs and Malfunctions + + +

    + Added multiline editing support to ssh clients connected + through OTP ssh daemon.

    +

    + Own Id: OTP-18653 Aux Id: PR-7242

    +
    +
    +
    + +
    + +
    Ssh 5.0 + +
    Improvements and New Features + + +

    + The ssh_cli has been updated to work with the changes + introduced in the new Erlang shell implementation.

    +

    + Own Id: OTP-18231 Aux Id: OTP-17932 PR-6144

    +
    + +

    + Typing Ctrl+L in a shell now clears the screen and + redraws the current line instead of only redrawing the + current line. To only redraw the current line, you must + now type Alt+L. This brings the behaviour of + Ctrl+L closer to how bash and other shells work.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18285 Aux Id: PR-6262

    +
    + +

    + Deprecates dbg:stop_clear/0 because it is simply a + function alias to dbg:stop/0

    +

    + Own Id: OTP-18478 Aux Id: GH-6903

    +
    + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    Ssh 4.15.3 + +
    Fixed Bugs and Malfunctions + + +

    + With this change, PKCS8 formatted private key file is + properly decoded and SSH daemon with such key can be + started.

    +

    + Own Id: OTP-18446 Aux Id: GH-6475

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Ssh 4.15.2 + +
    Fixed Bugs and Malfunctions + + +

    + With this change, ssh application does not crash when + formatting some of info reports for unsuccessful + connections.

    +

    + Own Id: OTP-18386 Aux Id: PR-6611

    +
    + +

    + With this change, ssh does not log extensively long + messages.

    +

    + Own Id: OTP-18417 Aux Id: DAFH-1349,ERIERL-888,IA18357

    +
    +
    +
    + +
    + +
    Ssh 4.15.1 + +
    Fixed Bugs and Malfunctions + + +

    + graceful shutdown of ssh_conection_handler when + connection is closed by peer

    +

    + Own Id: OTP-18326 Aux Id: ERIERL-865

    +
    +
    +
    + +
    + +
    Ssh 4.15 + +
    Fixed Bugs and Malfunctions + + +

    + Handling rare race condition at channel close.

    +

    + Own Id: OTP-18220 Aux Id: ERIERL-666, ERIERL-661

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + New ssh option no_auth_needed to skip the ssh + authentication. Use with caution!

    +

    + Own Id: OTP-18134 Aux Id: GH-6021

    +
    + +

    + This change fixes dialyzer warnings generated for + inets/httpd examples (includes needed adjustment of spec + for ssh_sftp module).

    +

    + Own Id: OTP-18178 Aux Id: ERIERL-833, ERIERL-834, + ERIERL-835

    +
    + +

    + The new function ssh:daemon_replace_options/2 + makes it possible to change the Options in a + running SSH server.

    +

    + Established connections are not affected, only those + created after the call to this new function.

    +

    + Own Id: OTP-18196

    +
    + +

    + Add a timeout as option max_initial_idle_time. It + closes a connection that does not allocate a channel + within the timeout time.

    +

    + For more information about timeouts, see the Timeouts section + in the User's Guide Hardening chapter.

    +

    + Own Id: OTP-18207 Aux Id: PR-6231

    +
    +
    +
    + +
    + +
    Ssh 4.14.1 + +
    Fixed Bugs and Malfunctions + + +

    + Binaries can be limited in logs with the parameter + max_log_item_len. The default value is 500 bytes.

    +

    + Own Id: OTP-18094

    +
    +
    +
    + +
    + +
    Ssh 4.14 + +
    Improvements and New Features + + +

    + The representation of Edward curves (ed25519 and ed448) + inside ssh had a temporary representation (ed_pri and + ed_pub).

    +

    + That is now changed to the public_key form. See the + manual for more information.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17920

    +
    + +

    + Former internal function + ssh_file:extract_public_key/1 documented publicly.

    +

    + Internally it was previously in ssh_transport.

    +

    + Own Id: OTP-18079 Aux Id: GH-5767

    +
    +
    +
    + +
    +
    Ssh 4.13.2.3
    Fixed Bugs and Malfunctions @@ -396,6 +652,22 @@
    +
    Ssh 4.11.1.6 + +
    Fixed Bugs and Malfunctions + + +

    + Binaries can be limited in logs with the parameter + max_log_item_len. The default value is 500 bytes.

    +

    + Own Id: OTP-18094

    +
    +
    +
    + +
    +
    Ssh 4.11.1.5
    Fixed Bugs and Malfunctions @@ -1181,7 +1453,7 @@ input/output, the I/O was erroneously handled by the *server's* group leader, so the I/O turned up in the the server's Erlang shell (if any). The user at the client - side did therefor not see that I/O.

    + side did therefore not see that I/O.

    This is corrected now, so the client - for example the ssh OS shell command - handles the I/O. The user could @@ -1726,7 +1998,7 @@

    - The type specifications in SSH are completly reworked and + The type specifications in SSH are completely reworked and the following types are renamed:

    ssh:ssh_connection_ref() is changed to @@ -1991,7 +2263,7 @@

    - Fix rare spurios shutdowns of ssh servers when receiveing + Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

    Own Id: OTP-15018

    @@ -2442,7 +2714,7 @@

    - Fix rare spurios shutdowns of ssh servers when receiveing + Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

    Own Id: OTP-15018

    @@ -2674,7 +2946,7 @@

    If a client illegaly sends an info-line and then - immediatly closes the TCP-connection, a badmatch + immediately closes the TCP-connection, a badmatch exception was raised.

    Own Id: OTP-13966

    @@ -2887,7 +3159,7 @@

    - Fix rare spurios shutdowns of ssh servers when receiveing + Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

    Own Id: OTP-15018

    @@ -3509,7 +3781,7 @@

    The possible values are: {id_string,string()} and {id_string,random}. The latter will make ssh - generate a random nonsence id-string for each new + generate a random nonsense id-string for each new connection.

    Own Id: OTP-12659

    @@ -3635,7 +3907,7 @@

    The possible values are: {id_string,string()} and {id_string,random}. The latter will make ssh - generate a random nonsence id-string for each new + generate a random nonsense id-string for each new connection.

    Own Id: OTP-12659

    @@ -4298,7 +4570,7 @@

    - ssh:daemon will get feeded with an argument even if it is + ssh:daemon will get fed with an argument even if it is not a valid expression.

    Own Id: OTP-10975

    @@ -4646,7 +4918,7 @@

    - All keys in authorized_keys are considerd, wrongly only + All keys in authorized_keys are considered, wrongly only the first one was before.

    Own Id: OTP-7235

    @@ -5020,7 +5292,7 @@

    - Now clear all processes when a connnection is terminated.

    + Now clear all processes when a connection is terminated.

    Own Id: OTP-8121 Aux Id:

    @@ -5118,13 +5390,13 @@

    - ssh_sftp:start_channel/3 did not handle timout correctly.

    + ssh_sftp:start_channel/3 did not handle timeout correctly.

    Own Id: OTP-8159 Aux Id: seq11386

    - If a progress message was not recieved after invoking ssh:connect/3 + If a progress message was not received after invoking ssh:connect/3 the call could hang for ever. A timeout option has also been added.

    Own Id: OTP-8160 Aux Id: seq11386

    diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 8491eb61f66f..d58166711a12 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -11,7 +11,7 @@ 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 @@ -21,7 +21,7 @@ limitations under the License. - + ssh @@ -40,8 +40,8 @@

    With the SSH application it is possible to start clients and to start daemons (servers).

    Clients are started with - connect/2, - connect/3 or + connect/2, + connect/3 or connect/4. They open an encrypted connection on top of TCP/IP. In that encrypted connection one or more channels could be opened with ssh_connection:session_channel/2,4. @@ -52,32 +52,32 @@ the user is not necessarily a human but probably a system interfacing the SSH app.

    A server-side subssystem (channel) server is requested by the client with - ssh_connection:subsystem/4. + ssh_connection:subsystem/4.

    -

    A server (daemon) is started with +

    A server (daemon) is started with daemon/1, daemon/2 or daemon/3. Possible channel handlers (subsystems) are declared with the subsystem option when the daemon is started.

    -

    To just run a shell on a remote machine, there are functions that bundles the needed +

    To just run a shell on a remote machine, there are functions that bundles the needed three steps needed into one: shell/1,2,3. - Similarily, to just open an sftp (file transfer) connection to a remote machine, the simplest way is to use + Similarly, to just open an sftp (file transfer) connection to a remote machine, the simplest way is to use ssh_sftp:start_channel/1,2,3.

    -

    To write your own client channel handler, use the behaviour - ssh_client_channel. For server channel handlers use +

    To write your own client channel handler, use the behaviour + ssh_client_channel. For server channel handlers use ssh_server_channel behaviour (replaces ssh_daemon_channel).

    Both clients and daemons accepts options that controls the exact behaviour. Some options are common to both. - The three sets are called - Client Options, + The three sets are called + Client Options, Daemon Options and Common Options.

    -

    The descriptions of the options uses the +

    The descriptions of the options uses the Erlang Type Language with explaining text.

    @@ -90,7 +90,7 @@
    Keys and files -

    A number of objects must be present for the SSH application to work. +

    A number of objects must be present for the SSH application to work. Those objects are per default stored in files. The default names, paths and file formats are the same as for OpenSSH. Keys could be generated with the ssh-keygen @@ -102,7 +102,7 @@ user_dir and system_dir.

    -

    A completly different storage could be interfaced by writing call-back modules +

    A completely different storage could be interfaced by writing call-back modules using the behaviours ssh_client_key_api and/or ssh_server_key_api. @@ -122,12 +122,12 @@ ssh_host_rsa_key and ssh_host_rsa_key.pub ssh_host_ecdsa_key and ssh_host_ecdsa_key.pub -

    The host keys directory could be changed with the option +

    The host keys directory could be changed with the option system_dir.

    Optional: one or more User's public key in case of publickey authorization. Default is to store them concatenated in the file .ssh/authorized_keys in the user's home directory. -

    The user keys directory could be changed with the option +

    The user keys directory could be changed with the option user_dir.

    @@ -137,14 +137,14 @@ Clients

    The keys and some other data are by default stored in files in the directory .ssh in the user's home directory.

    -

    The directory could be changed with the option +

    The directory could be changed with the option user_dir.

    Optional: a list of Host public key(s) for previously connected hosts. This list is handled by the SSH application without any need of user assistance. The default is to store them in the file known_hosts. -

    The +

    The host_accepting_client_options() are associated with this list of keys.

    @@ -206,12 +206,12 @@ silently_accept_hosts -

    This option guides the connect function on how to act when the connected server presents a Host +

    This option guides the connect function on how to act when the connected server presents a Host Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to accept or reject the new Host Key. See the option user_dir for specifying the path to the file known_hosts where previously accepted Host Keys are recorded. - See also the option + See also the option key_cb for the general way to handle keys.

    @@ -228,7 +228,7 @@ result the connection will be closed. The arguments to the fun are: PeerName - a string with the name or address of the remote host. - FingerPrint - the fingerprint of the Host Key as + FingerPrint - the fingerprint of the Host Key as hostkey_fingerprint/1 calculates it. @@ -241,12 +241,12 @@ is either an atom or a list of atoms as the first argument in hostkey_fingerprint/2. If it is a list of hash algorithm names, the FingerPrint argument in the - accept_callback() will be + accept_callback() will be a list of fingerprints in the same order as the corresponding name in the HashAlgoSpec list.
    - + user_interaction

    If false, disables the client to connect to the server @@ -322,7 +322,7 @@

    Sets a timeout on the transport layer connect time. - For gen_tcp the time is in milli-seconds and the default + For gen_tcp the time is in milli-seconds and the default value is infinity.

    See the parameter Timeout in connect/4 for @@ -335,7 +335,7 @@

    Make the client tell the server that the client accepts extension negotiation, that is, - include ext-info-c in the kexinit message sent. See + include ext-info-c in the kexinit message sent. See RFC 8308 for details and ssh(6) for a list of currently implemented extensions. @@ -370,7 +370,7 @@ - + @@ -382,7 +382,7 @@

    The channel_callback is the module that implements the ssh_server_channel (replaces ssh_daemon_channel) - behaviour in the daemon. See the section + behaviour in the daemon. See the section Creating a Subsystem in the User's Guide for more information and an example.

    @@ -440,8 +440,8 @@

    In case of the {direct, exec_fun()} variant or no exec-option at all, all reads from standard_input will be from the received data-events of type 0. - Those are sent by the client. Similarily all writes to standard_output - will be sent as data-events to the client. An OS shell client like the command 'ssh' will usally use + Those are sent by the client. Similarly all writes to standard_output + will be sent as data-events to the client. An OS shell client like the command 'ssh' will usually use stdin and stdout for the user interface.

    The option cooperates with the daemon-option shell @@ -473,7 +473,7 @@ shell_spec's value.

    - + 4. If the exec-option is absent, and the shell-option is present with the default Erlang shell as the @@ -483,7 +483,7 @@

    The default Erlang evaluator is used both for exec and shell requests. The result is returned to the client.

    - + 5. If the exec-option is absent, and the shell-option is present with a value that is neither the default Erlang shell nor the value disabled: @@ -492,7 +492,7 @@ are executed according to the value of the shell_spec.

    - + 6. If the exec-option is absent, and the shell_spec's value is disabled: @@ -601,11 +601,11 @@ - pwdfun with + pwdfun with pwdfun_4() -

    Provides a function for password validation. This could used for calling an external system or handeling +

    Provides a function for password validation. This could used for calling an external system or handling passwords stored as hash values.

    This fun can also be used to make delays in authentication tries for example by calling @@ -618,13 +618,13 @@

    true if the user and password is valid - false if the user or password is invalid + false if the user or password is invalid disconnect if a SSH_MSG_DISCONNECT message should be sent immediately. It will be followed by a close of the underlying tcp connection. {true, NewState:any()} if the user and password is valid - {false, NewState:any()} if the user or password is invalid + {false, NewState:any()} if the user or password is invalid -

    A third usage is to block login attempts from a missbehaving peer. The State described above +

    A third usage is to block login attempts from a missbehaving peer. The State described above can be used for this. The return value disconnect is useful for this.

    In case of the pk_check_user is set, the atom pubkey is put in the password argument when validating a public key login. The @@ -640,7 +640,7 @@ as strings, and returns:

    true if the user and password is valid - false if the user or password is invalid + false if the user or password is invalid

    In case of the pk_check_user is set, the atom pubkey is put in the password argument when validating a public key login. The @@ -648,6 +648,19 @@

    This variant is kept for compatibility.

    + + no_auth_needed + +

    If true, a client is authenticated without any need of + providing any password or key. +

    +

    This option is only intended for very special applications due + to the high risk of accepting any connecting client. +

    +

    The default value is false. +

    +
    + @@ -662,7 +675,7 @@ dh_gex_groups

    Defines the groups the server may choose among when diffie-hellman-group-exchange is negotiated. - See + See RFC 4419 for details. The three variants of this option are:

    @@ -672,7 +685,7 @@ In such a case, the server will choose one randomly in the negotiated Size.
    {file,filename()} - The file must have one or more three-tuples {Size=integer(),G=integer(),P=integer()} + The file must have one or more three-tuples {Size=integer(),G=integer(),P=integer()} terminated by a dot. The file is read when the daemon starts. {ssh_moduli_file,filename()} @@ -681,7 +694,7 @@ The file is read when the daemon starts. -

    The default list is fetched from the +

    The default list is fetched from the public_key application.

    @@ -690,14 +703,14 @@

    Limits what a client can ask for in diffie-hellman-group-exchange. The limits will be - {MaxUsed = min(MaxClient,Max), MinUsed = max(MinClient,Min)} where MaxClient and + {MaxUsed = min(MaxClient,Max), MinUsed = max(MinClient,Min)} where MaxClient and MinClient are the values proposed by a connecting client.

    The default value is {0,infinity}.

    If MaxUsed < MinUsed in a key exchange, it will fail with a disconnect.

    -

    See +

    See RFC 4419 for the function of the Max and Min values.

    @@ -712,6 +725,10 @@ Defaults to 30000 ms (30 seconds). If the client fails to send the first message within this time, the connection is closed.

    +

    For more information about timeouts, see the + Timeouts section + in the User's Guide Hardening chapter. +

    @@ -722,12 +739,33 @@ Defaults to 120000 ms (2 minutes). If the client fails to log in within this time, the connection is closed.

    +

    For more information about timeouts, see the + Timeouts section + in the User's Guide Hardening chapter. +

    + + + + + + +

    Maximum time in milliseconds for the first channel start after + completion of the authentication negotiation. + Defaults to infinity. +

    +

    For more information about timeouts, see the + Timeouts section + in the User's Guide Hardening chapter. +

    +

    For more information about hardening, see the + Hardening section in the User's Guide chapter. +

    @@ -751,7 +789,7 @@

    By default, this option is not set. This means that the number is not limited.

    - + max_channels @@ -792,11 +830,11 @@ The default value is 0.

    - +
    - + @@ -880,6 +918,10 @@

    The timeout is not active until channels are started, so it does not limit the time from the connection creation to the first channel opening.

    +

    For more information about timeouts, see the + Timeouts section + in the User's Guide Hardening chapter. +

    @@ -934,10 +976,10 @@ Module:F(..., [{key_cb_private,Opts}|UserOptions]) -

    where ... are arguments to F as in +

    where ... are arguments to F as in ssh_client_key_api and/or ssh_server_key_api. - The UserOptions are the options given to + The UserOptions are the options given to ssh:connect, ssh:shell or ssh:daemon. @@ -982,7 +1024,7 @@

    Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. - The last three parameters are from the message, see + The last three parameters are from the message, see RFC 4253, section 11.3. The connection_ref() is the reference to the connection on which the message arrived. @@ -1027,7 +1069,7 @@

    If an alg_entry() is missing in the algs_list(), the default value is used for that entry.

    Here is an example of this option:

    - {preferred_algorithms, + {preferred_algorithms, [{public_key,['ssh-rsa','ssh-dss']}, {cipher,[{client2server,['aes128-ctr']}, {server2client,['aes128-cbc','3des-cbc']}]}, @@ -1060,7 +1102,7 @@

    Modifies the list of algorithms to use in the algorithm negotiation. The modifications are applied after the option preferred_algorithms (if existing) is applied.

    -

    The algoritm for modifications works like this:

    +

    The algorithm for modifications works like this:

    Input is the modify_algs_list() and a set of algorithms A @@ -1094,7 +1136,7 @@

    If there are more than one modify_algorithms options, the result is undefined.

    Here is an example of this option:

    - {modify_algorithms, + {modify_algorithms, [{prepend, [{kex, ['diffie-hellman-group1-sha1']}], {rm, [{compression, [none]}]} ] @@ -1140,7 +1182,7 @@ Other data types - + @@ -1158,13 +1200,13 @@ - + - + @@ -1231,7 +1273,7 @@

    In the option info tuple are only the options included that differs from the default values.

    -
    + opaque_client_options() @@ -1257,7 +1299,7 @@ Closes an SSH connection.

    Closes an SSH connection.

    - + connect(Host, Port, Options) -> Result @@ -1327,7 +1369,7 @@

    are allowed. The excluded options are reserved by the SSH application.

    -

    This is an extremly dangerous function. You use it on your own risk.

    +

    This is an extremely dangerous function. You use it on your own risk.

    Some options are OS and OS version dependent. Do not use it unless you know what effect your option values will have on an TCP stream.

    @@ -1349,7 +1391,7 @@
    - + daemon(Port | TcpSocket) -> Result daemon(Port | TcpSocket, Options) -> Result @@ -1383,7 +1425,7 @@ An 'ip'-option will be discarded if present. if HostAddress is the atom loopback, the listening address - is loopback and an loopback address will be choosen by the underlying layers. + is loopback and an loopback address will be chosen by the underlying layers. An 'ip'-option will be discarded if present. if HostAddress is the atom any and no 'ip'-option is present, the listening address is @@ -1395,7 +1437,32 @@ - + + + + Change options in a running daemon + +

    + Replaces the options in a running daemon with the options in + NewUserOptions. Only connections established after this call + are affected, already established connections are not. +

    + +

    In the final phase of this function, the listening process is restarted. + Therfore a connection attempt to the daemon in this final phase could fail. +

    +
    +

    + The handling of Erlang configurations is described in the User's Guide; + see chapters + Configuration in SSH + and + Configuring algorithms in SSH. +

    +
    +
    + + @@ -1411,7 +1478,6 @@ - @@ -1442,7 +1508,7 @@ interactive shell on that remote host.

    As an alternative, an already open TCP socket could be passed to the function in TcpSocket. - The SSH initiation and negotiation will be initiated on that one and finaly a shell will be started + The SSH initiation and negotiation will be initiated on that one and finally a shell will be started on the host at the other end of the TCP socket.

    For a description of the options, see Client Options.

    @@ -1473,7 +1539,7 @@ manual page in Kernel.

    - + @@ -1515,7 +1581,7 @@

    - + @@ -1553,7 +1619,7 @@ in uppercase as in newer ssh-keygen commands.

    Examples:

    - 2> ssh:hostkey_fingerprint(Key). + 2> ssh:hostkey_fingerprint(Key). "f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84" 3> ssh:hostkey_fingerprint(md5,Key). @@ -1575,5 +1641,5 @@ - + diff --git a/lib/ssh/doc/src/ssh_agent.xml b/lib/ssh/doc/src/ssh_agent.xml index a6ff511f2f29..ceada7237100 100644 --- a/lib/ssh/doc/src/ssh_agent.xml +++ b/lib/ssh/doc/src/ssh_agent.xml @@ -52,7 +52,7 @@

    The agent communication is established through a UNIX domain socket. By default, the socket path - will be fetched from the SSH_AUTH_SOCK enviroment variable, which is the default socket path in the agent + will be fetched from the SSH_AUTH_SOCK environment variable, which is the default socket path in the agent implementation of OpenSSH.

    diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml index a81d0d3274d2..cb20724496da 100644 --- a/lib/ssh/doc/src/ssh_client_key_api.xml +++ b/lib/ssh/doc/src/ssh_client_key_api.xml @@ -69,7 +69,7 @@ ConnectOptions = client_key_cb_options() -

    This function is retired in favour for Module:add_host_key/4 which is the prefered API function. +

    This function is retired in favour for Module:add_host_key/4 which is the preferred API function. The calling SSH application will still try the add_host_key/3 if the call to add_host_key/4 failed.

    Adds a host key to the set of trusted host keys.

    @@ -96,10 +96,10 @@

    Adds a host key to the set of trusted host keys.

    -

    This function is prefered to the old Module:add_host_key/3 since it also uses +

    This function is preferred to the old Module:add_host_key/3 since it also uses the peer host port number and may return an error message.

    The OTP/SSH application first calls this function in the callback module, and then - the old Module:add_host_key/3 for compatibilty.

    + the old Module:add_host_key/3 for compatibility.

    @@ -121,7 +121,7 @@ Result = boolean() -

    This function is retired in favour for Module:is_host_key/5 which is the prefered API function. +

    This function is retired in favour for Module:is_host_key/5 which is the preferred API function. The calling SSH application will still try the is_host_key/4 if the call to is_host_key/5 failed.

    Checks if a host key is trusted.

    @@ -155,10 +155,10 @@

    Checks if a host key is trusted.

    -

    This function is prefered to the old Module:is_host_key/4 since it also uses +

    This function is preferred to the old Module:is_host_key/4 since it also uses the peer host port number and may return an error message.

    The OTP/SSH application first calls this function in the callback module, and then - the old Module:is_host_key/4 for compatibilty.

    + the old Module:is_host_key/4 for compatibility.

    diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index cd4b9c0f8501..899bd0c2b73d 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -5,7 +5,7 @@
    2008 - 2020 + 2022 Ericsson AB, All Rights Reserved @@ -85,7 +85,7 @@

    The status of a request. - Coresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in + Corresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in RFC 4254, Section 5.4.

    diff --git a/lib/ssh/doc/src/ssh_file.xml b/lib/ssh/doc/src/ssh_file.xml index e97bb5b37fa5..29db36481aa7 100644 --- a/lib/ssh/doc/src/ssh_file.xml +++ b/lib/ssh/doc/src/ssh_file.xml @@ -4,7 +4,7 @@
    - 20182022 + 20182023 Ericsson AB. All Rights Reserved. @@ -66,7 +66,7 @@ Daemons

    Daemons uses all files stored in the SYSDIR directory.

    -

    Optionaly, in case of publickey authorization, one or more of the remote user's public keys +

    Optionally, in case of publickey authorization, one or more of the remote user's public keys in the USERDIR directory are used. See the files USERDIR/authorized_keys and @@ -223,7 +223,7 @@ key :: % encoded key from eg ssh_host_*.pub -

    The key representation.

    +

    The key representation

    @@ -232,8 +232,6 @@ key :: % encoded key from eg ssh_host_*.pub

    Types for the experimental implementaition of the openssh_key_v1 format. - The #ECPoint{} and ECPrivateKey{} are not used for Edwards curves - (ed25519 and ed448), but will be in next major release.

    @@ -262,7 +260,7 @@ key :: % encoded key from eg ssh_host_*.pub SYSDIR/ssh_host_dsa_key SYSDIR/ssh_host_ecdsa_key SYSDIR/ssh_host_ed25519_key - SYSDIR/ssh_host_ed448_keyc> + SYSDIR/ssh_host_ed448_key @@ -285,7 +283,7 @@ key :: % encoded key from eg ssh_host_*.pub USERDIR/authorized_keys USERDIR/authorized_keys2 -

    This functions discards all options in the begining of the lines of thoose files when reading them. +

    This functions discards all options in the beginning of the lines of thoose files when reading them.

    @@ -375,7 +373,7 @@ key :: % encoded key from eg ssh_host_*.pub an RFC4716 public key or an OpenSSH public key.

    The following key types have been renamed from the deprecated - public_key:ssh_decode/2:

    + public_key:ssh_decode/2:

    rfc4716_public_key -> rfc4716_key openssh_public_key -> openssh_key @@ -391,8 +389,7 @@ key :: % encoded key from eg ssh_host_*.pub

    Encodes a list of SSH file entries (public keys and attributes) to a binary.

    -

    The following key types have been renamed from the deprecated - public_key:ssh_encode/2:

    +

    The following key types have been renamed from the removed public_key:ssh_encode/2:

    rfc4716_public_key -> rfc4716_key openssh_public_key -> openssh_key @@ -402,6 +399,15 @@ key :: % encoded key from eg ssh_host_*.pub
    + + + + + +

    Fetches the public key from a private key.

    +
    +
    + diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index 6e30c1e20dba..c035f74b3a26 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -4,7 +4,7 @@
    - 20052020 + 20052022 Ericsson AB. All Rights Reserved. @@ -96,7 +96,7 @@ crypto:crypto_init/4 or similar. The crypto_state() is the state such a function may return.

    -

    If the selected cipher needs to have the input data partioned into +

    If the selected cipher needs to have the input data partitioned into blocks of a certain size, the init_fun() should return the second form of return value with the chunk_size() set to the block size. If the chunk_size() is undefined, the size of the PlainBins varies, diff --git a/lib/ssh/doc/src/ssh_timeouts.jpg b/lib/ssh/doc/src/ssh_timeouts.jpg new file mode 100644 index 000000000000..da2f0914fc58 Binary files /dev/null and b/lib/ssh/doc/src/ssh_timeouts.jpg differ diff --git a/lib/ssh/doc/src/ssh_timeouts.odp b/lib/ssh/doc/src/ssh_timeouts.odp new file mode 100644 index 000000000000..ba2d072e9f7e Binary files /dev/null and b/lib/ssh/doc/src/ssh_timeouts.odp differ diff --git a/lib/ssh/doc/src/terminology.xml b/lib/ssh/doc/src/terminology.xml index 97662761923a..78a24f1618c7 100644 --- a/lib/ssh/doc/src/terminology.xml +++ b/lib/ssh/doc/src/terminology.xml @@ -44,7 +44,7 @@ cause confusion.

    The term is used differently in OpenSSH and SSH in Erlang/OTP. - The reason is the different environments and use cases that are not immediatly obvious. + The reason is the different environments and use cases that are not immediately obvious.

    This chapter aims at explaining the differences and giving a rationale for why Erlang/OTP handles "user" as it does. @@ -95,8 +95,8 @@

    - The SSH server on UNIX/Linux/etc after a succesful authentication -

    After a succesful incoming authentication, a new process runs as the just authenticated user.

    + The SSH server on UNIX/Linux/etc after a successful authentication +

    After a successful incoming authentication, a new process runs as the just authenticated user.

    Next step is to start a service according to the ssh request. In case of a request of a shell, a new one is started which handles the OS-commands that arrives from the client (that's "you").

    @@ -166,7 +166,7 @@
    - The Erlang/OTP SSH server after a succesful authentication + The Erlang/OTP SSH server after a successful authentication

    After a successful authentication an Erlang process is handling the service request from the remote ssh client. The rights of that process are those of the user of the OS process running the Erlang emulator.

    diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index a127b66607ed..648b59ab232e 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -5,7 +5,7 @@
    2012 - 2020 + 2022 Ericsson AB. All Rights Reserved. @@ -201,7 +201,7 @@ ok

    To close the connection, call the function ssh:close(ConnectionRef). As an alternative, set the option {idle_time, 1} - when opening the connection. This will cause the connection to be closed automaticaly when there are + when opening the connection. This will cause the connection to be closed automatically when there are no channels open for the specified time period, in this case 1 ms.

    diff --git a/lib/ssh/examples/Makefile b/lib/ssh/examples/Makefile index d7d47eb3ae01..1b05d65cb539 100644 --- a/lib/ssh/examples/Makefile +++ b/lib/ssh/examples/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2015. All Rights Reserved. +# Copyright Ericsson AB 2005-2022. 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. @@ -56,7 +56,7 @@ EBIN = . # ---------------------------------------------------- # Make Rules # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) debug: ERLC_FLAGS += -Ddebug diff --git a/lib/ssh/src/.gitignore b/lib/ssh/src/.gitignore new file mode 100644 index 000000000000..3f9cfafd3378 --- /dev/null +++ b/lib/ssh/src/.gitignore @@ -0,0 +1 @@ +deps diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index cc3cfe9e965d..2fcb1643013b 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -159,7 +159,7 @@ $(DEP_FILE): $(ERL_FILES) | sed 's@^sshd_@$$(EBIN)/sshd_@' \ > $(DEP_FILE) -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(DEP_FILE) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(DEP_FILE) clean: rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(BEHAVIOUR_TARGET_FILES) diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index c7ad417bef26..fedd05e350f4 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -59,9 +59,9 @@ {mod, {ssh_app, []}}, {runtime_dependencies, [ "crypto-5.0", - "erts-9.0", - "kernel-5.3", + "erts-14.0", + "kernel-9.0", "public_key-1.6.1", - "stdlib-3.15", + "stdlib-5.0","stdlib-5.0", "runtime_tools-1.15.1" ]}]}. diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index f655f0db4571..f856d3d88787 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -1,7 +1,7 @@ % %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -35,6 +35,7 @@ channel_info/3, daemon/1, daemon/2, daemon/3, daemon_info/1, daemon_info/2, + daemon_replace_options/2, set_sock_opts/2, get_sock_opts/2, default_algorithms/0, chk_algos_opts/1, @@ -108,7 +109,7 @@ start(Type) -> {ok, _} -> %% Clear cached default_algorithms (if exists) ... ssh_transport:clear_default_algorithms_env(), - %% ... and rebuld them taking configure options in account + %% ... and rebuild them taking configure options in account ssh_transport:default_algorithms(), ok; Other -> @@ -442,6 +443,17 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535, daemon(_, _, _) -> {error, badarg}. +%%-------------------------------------------------------------------- +-spec daemon_replace_options(DaemonRef, NewUserOptions) -> {ok,daemon_ref()} + | {error,term()} when + DaemonRef :: daemon_ref(), + NewUserOptions :: daemon_options(). + +daemon_replace_options(DaemonRef, NewUserOptions) -> + {ok,Os0} = ssh_system_sup:get_acceptor_options(DaemonRef), + Os1 = ssh_options:merge_options(server, NewUserOptions, Os0), + ssh_system_sup:replace_acceptor_options(DaemonRef, Os1). + %%-------------------------------------------------------------------- -type daemon_info_tuple() :: {port, inet:port_number()} @@ -836,7 +848,7 @@ fp_fmt(b64, Bin) -> %% [C || C<-base64:encode_to_string(Bin), C =/= $=] %% but I am not sure. Must be checked. B64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - BitsInLast = 8*size(Bin) rem 6, + BitsInLast = 8*byte_size(Bin) rem 6, Padding = (6-BitsInLast) rem 6, % Want BitsInLast = [1:5] to map to padding [5:1] and 0 -> 0 [lists:nth(C+1,B64Chars) || <> <= <> ]. @@ -931,10 +943,10 @@ is_host(X, Opts) -> is_host1(L) when is_list(L) -> true; %% "string()" -is_host1(T) when is_tuple(T), size(T)==4 -> lists:all(fun(I) -> 0= lists:all(fun(I) -> 0= lists:all(fun(I) -> 0= lists:all(fun(I) -> 0= true. %%%---------------------------------------------------------------- diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl index 206c5feb9b9c..aecce6c1efea 100644 --- a/lib/ssh/src/ssh.hrl +++ b/lib/ssh/src/ssh.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2022. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -50,7 +50,7 @@ -define(UINT16(X), (X):16/unsigned-big-integer). -define(UINT32(X), (X):32/unsigned-big-integer). -define(UINT64(X), (X):64/unsigned-big-integer). --define(STRING(X), ?UINT32((size(X))), (X)/binary). +-define(STRING(X), ?UINT32((byte_size(X))), (X)/binary). -define(DEC_BIN(X,Len), ?UINT32(Len), X:Len/binary ). -define(DEC_INT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ). @@ -322,6 +322,7 @@ | tcpip_tunnel_in_daemon_option() | authentication_daemon_options() | diffie_hellman_group_exchange_daemon_option() + | max_initial_idle_time_daemon_option() | negotiation_timeout_daemon_option() | hello_timeout_daemon_option() | hardening_daemon_options() @@ -362,7 +363,9 @@ | {user_passwords, [{UserName::string(),Pwd::string()}]} | {pk_check_user, boolean()} | {password, string()} - | {pwdfun, pwdfun_2() | pwdfun_4()} . + | {pwdfun, pwdfun_2() | pwdfun_4()} + | {no_auth_needed, boolean()} + . -type prompt_texts() :: kb_int_tuple() @@ -390,6 +393,7 @@ -type explicit_group_file() :: {file,string()} . -type ssh_moduli_file() :: {ssh_moduli_file,string()}. +-type max_initial_idle_time_daemon_option() :: {max_initial_idle_time, timeout()} . -type negotiation_timeout_daemon_option() :: {negotiation_timeout, timeout()} . -type hello_timeout_daemon_option() :: {hello_timeout, timeout()} . diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl index 00587eecbae1..7952574de78c 100644 --- a/lib/ssh/src/ssh_acceptor.erl +++ b/lib/ssh/src/ssh_acceptor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -93,7 +93,7 @@ acceptor_init(Parent, SystemSup, Opts1 = ?DELETE_INTERNAL_OPT(lsocket, Opts), acceptor_loop(Port, Address, Opts1, NewLSock, AcceptTimeout, SystemSup); {error,Error} -> - proc_lib:init_ack(Parent, {error,Error}) + proc_lib:init_fail(Parent, {error,Error}, {exit, normal}) end end; @@ -104,7 +104,7 @@ acceptor_init(Parent, SystemSup, proc_lib:init_ack(Parent, {ok, self()}), acceptor_loop(Port, Address, Opts, LSock, AcceptTimeout, SystemSup); {error,Error} -> - proc_lib:init_ack(Parent, {error,Error}) + proc_lib:init_fail(Parent, {error,Error}, {exit, normal}) end end. diff --git a/lib/ssh/src/ssh_agent.erl b/lib/ssh/src/ssh_agent.erl index ffb46df4ea42..25e6beed0e4c 100644 --- a/lib/ssh/src/ssh_agent.erl +++ b/lib/ssh/src/ssh_agent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2019-2021. All Rights Reserved. +%% Copyright Ericsson AB 2019-2023. 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. @@ -173,7 +173,7 @@ send(Request, Opts) -> %% Message packing pack(Data) -> - <<(size(Data)):32/unsigned-big-integer, Data/binary>>. + <<(byte_size(Data)):32/unsigned-big-integer, Data/binary>>. %% SSH Agent message encoding diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 818489c1d0ec..efd1bbbabde2 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -149,7 +149,7 @@ get_public_key(SigAlg, #ssh{opts = Opts}) -> try %% Check the key - the KeyCb may be a buggy plugin true = ssh_transport:valid_key_sha_alg(private, PrivKey, KeyAlg), - Key = ssh_transport:extract_public_key(PrivKey), + Key = ssh_file:extract_public_key(PrivKey), ssh_message:ssh2_pubkey_encode(Key) of PubKeyBlob -> {ok, {PrivKey, PubKeyBlob}} @@ -272,11 +272,21 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, handle_userauth_request(#ssh_msg_userauth_request{user = User, service = "ssh-connection", method = "none"}, _, - #ssh{userauth_supported_methods = Methods} = Ssh) -> - {not_authorized, {User, undefined}, - {#ssh_msg_userauth_failure{authentications = Methods, - partial_success = false}, Ssh} - }; + #ssh{userauth_supported_methods = Methods, + opts = Opts} = Ssh) -> + case ?GET_OPT(no_auth_needed, Opts) of + false -> + %% The normal case + {not_authorized, {User, undefined}, + {#ssh_msg_userauth_failure{authentications = Methods, + partial_success = false}, Ssh} + }; + true -> + %% RFC 4252 5.2 + {authorized, User, + {#ssh_msg_userauth_success{}, Ssh} + } + end; handle_userauth_request(#ssh_msg_userauth_request{user = User, service = "ssh-connection", diff --git a/lib/ssh/src/ssh_auth.hrl b/lib/ssh/src/ssh_auth.hrl index 56314ca6d904..842beb518602 100644 --- a/lib/ssh/src/ssh_auth.hrl +++ b/lib/ssh/src/ssh_auth.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -59,7 +59,7 @@ -record(ssh_msg_userauth_passwd_changereq, { prompt, %% string - languge %% string + language %% string }). -record(ssh_msg_userauth_pk_ok, diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 3ce775844762..882154c006de 100644 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2016. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -40,20 +40,20 @@ mpint(I) when I>0 -> <> = binary:encode_unsigned(I), case B1 band 16#80 of 16#80 -> - <<(size(V)+2):32/unsigned-big-integer, 0,B1,V/binary >>; + <<(byte_size(V)+2):32/unsigned-big-integer, 0,B1,V/binary >>; _ -> - <<(size(V)+1):32/unsigned-big-integer, B1,V/binary >> + <<(byte_size(V)+1):32/unsigned-big-integer, B1,V/binary >> end; mpint(N) when N<0 -> - Sxn = 8*size(binary:encode_unsigned(-N)), + Sxn = bit_size(binary:encode_unsigned(-N)), Sxn1 = Sxn+8, <> = <<1, 0:Sxn>>, <> = binary:encode_unsigned(W+N), case B1 band 16#80 of 16#80 -> - <<(size(V)+1):32/unsigned-big-integer, B1,V/binary >>; + <<(byte_size(V)+1):32/unsigned-big-integer, B1,V/binary >>; _ -> - <<(size(V)+2):32/unsigned-big-integer, 255,B1,V/binary >> + <<(byte_size(V)+2):32/unsigned-big-integer, 255,B1,V/binary >> end. %%%---------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index 13a44beea3c8..9f6d3be21d91 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -281,6 +281,10 @@ handle_msg({Group, get_unicode_state}, State) -> Group ! {self(), get_unicode_state, false}, {ok, State}; +handle_msg({Group, get_terminal_state}, State) -> + Group ! {self(), get_terminal_state, true}, + {ok, State}; + handle_msg({Group, tty_geometry}, #state{group = Group, pty = Pty } = State) -> @@ -426,8 +430,36 @@ io_request({insert_chars, unicode, Cs}, Buf, Tty, _Group) -> insert_chars(unicode:characters_to_list(Cs,unicode), Buf, Tty); io_request({move_rel, N}, Buf, Tty, _Group) -> move_rel(N, Buf, Tty); +io_request({move_line, N}, Buf, Tty, _Group) -> + move_line(N, Buf, Tty); +io_request({move_combo, L, V, R}, Buf, Tty, _Group) -> + {ML, Buf1} = move_rel(L, Buf, Tty), + {MV, Buf2} = move_line(V, Buf1, Tty), + {MR, Buf3} = move_rel(R, Buf2, Tty), + {[ML,MV,MR], Buf3}; +io_request(new_prompt, _Buf, _Tty, _Group) -> + {[], {[], {[],[]}, [], 0 }}; +io_request(delete_line, {_, {_, _}, _, Col}, Tty, _Group) -> + MoveToBeg = move_cursor(Col, 0, Tty), + {[MoveToBeg, "\e[J"], + {[],{[],[]},[],0}}; +io_request({redraw_prompt, Pbs, Pbs2, {LB, {Bef, Aft}, LA}}, Buf, Tty, _Group) -> + {ClearLine, Cleared} = io_request(delete_line, Buf, Tty, _Group), + CL = lists:reverse(Bef,Aft), + Text = Pbs ++ lists:flatten(lists:join("\n"++Pbs2, lists:reverse(LB)++[CL|LA])), + Moves = if LA /= [] -> + [Last|_] = lists:reverse(LA), + {move_combo, -length(Last), -length(LA), length(Bef)}; + true -> + {move_rel, -length(Aft)} + end, + {T, InsertedText} = io_request({insert_chars, unicode:characters_to_binary(Text)}, Cleared, Tty, _Group), + {M, Moved} = io_request(Moves, InsertedText, Tty, _Group), + {[ClearLine, T, M], Moved}; io_request({delete_chars,N}, Buf, Tty, _Group) -> delete_chars(N, Buf, Tty); +io_request(clear, Buf, _Tty, _Group) -> + {"\e[H\e[2J", Buf}; io_request(beep, Buf, _Tty, _Group) -> {[7], Buf}; @@ -441,13 +473,12 @@ io_request({requests,Rs}, Buf, Tty, Group) -> io_request(tty_geometry, Buf, Tty, Group) -> io_requests([{move_rel, 0}, {put_chars, unicode, [10]}], Buf, Tty, [], Group); - %{[], Buf}; %% New in 18 io_request({put_chars_sync, Class, Cs, Reply}, Buf, Tty, Group) -> %% We handle these asynchronous for now, if we need output guarantees %% we have to handle these synchronously - Group ! {reply, Reply}, + Group ! {reply, Reply, ok}, io_request({put_chars, Class, Cs}, Buf, Tty, Group); io_request(_R, Buf, _Tty, _Group) -> @@ -480,55 +511,58 @@ get_tty_command(left, N, _TerminalType) -> %% convert input characters to buffer and to writeout %% Note that the buf is reversed but the buftail is not %% (this is handy; the head is always next to the cursor) -conv_buf([], AccBuf, AccBufTail, AccWrite, Col, _Tty) -> - {AccBuf, AccBufTail, lists:reverse(AccWrite), Col}; -conv_buf([13, 10 | Rest], _AccBuf, AccBufTail, AccWrite, _Col, Tty) -> - conv_buf(Rest, [], tl2(AccBufTail), [10, 13 | AccWrite], 0, Tty); -conv_buf([13 | Rest], _AccBuf, AccBufTail, AccWrite, _Col, Tty) -> - conv_buf(Rest, [], tl1(AccBufTail), [13 | AccWrite], 0, Tty); -conv_buf([10 | Rest], _AccBuf, AccBufTail, AccWrite0, _Col, Tty) -> +conv_buf([], {LB, {Bef, Aft}, LA, Col}, AccWrite, _Tty) -> + {{LB, {Bef, Aft}, LA}, lists:reverse(AccWrite), Col}; +conv_buf([13, 10 | Rest], {LB, {Bef, Aft}, LA, Col}, AccWrite, Tty = #ssh_pty{width = W}) -> + conv_buf(Rest, {[lists:reverse(Bef)|LB], {[], tl2(Aft)}, LA, Col+(W-(Col rem W))}, [10, 13 | AccWrite], Tty); +conv_buf([13 | Rest], {LB, {Bef, Aft}, LA, Col}, AccWrite, Tty = #ssh_pty{width = W}) -> + conv_buf(Rest, {[lists:reverse(Bef)|LB], {[], tl1(Aft)}, LA, Col+(W-(Col rem W))}, [13 | AccWrite], Tty); +conv_buf([10 | Rest],{LB, {Bef, Aft}, LA, Col}, AccWrite0, Tty = #ssh_pty{width = W}) -> AccWrite = case pty_opt(onlcr,Tty) of 0 -> [10 | AccWrite0]; 1 -> [10,13 | AccWrite0]; undefined -> [10 | AccWrite0] end, - conv_buf(Rest, [], tl1(AccBufTail), AccWrite, 0, Tty); -conv_buf([C | Rest], AccBuf, AccBufTail, AccWrite, Col, Tty) -> - conv_buf(Rest, [C | AccBuf], tl1(AccBufTail), [C | AccWrite], Col + 1, Tty). - - -%%% put characters at current position (possibly overwriting -%%% characters after current position in buffer) -put_chars(Chars, {Buf, BufTail, Col}, Tty) -> - {NewBuf, NewBufTail, WriteBuf, NewCol} = - conv_buf(Chars, Buf, BufTail, [], Col, Tty), - {WriteBuf, {NewBuf, NewBufTail, NewCol}}. + conv_buf(Rest, {[lists:reverse(Bef)|LB], {[], tl1(Aft)}, LA, Col+(W - (Col rem W))}, AccWrite, Tty); +conv_buf([C | Rest], {LB, {Bef, Aft}, LA, Col}, AccWrite, Tty) -> + conv_buf(Rest, {LB, {[C|Bef], tl1(Aft)}, LA, Col+1}, [C | AccWrite], Tty). + +%%% put characters before the prompt +put_chars(Chars, Buf, Tty) -> + case Buf of + {[],{[],[]},[],_} -> {_, WriteBuf, _} = conv_buf(Chars, Buf, [], Tty), + {WriteBuf, Buf}; + _ -> + {Delete, DeletedState} = io_request(delete_line, Buf, Tty, []), + {_, PutBuffer, _} = conv_buf(Chars, DeletedState, [], Tty), + {Redraw, _} = io_request(redraw_prompt_pre_deleted, Buf, Tty, []), + {[Delete, PutBuffer, Redraw], Buf} + end. %%% insert character at current position -insert_chars([], {Buf, BufTail, Col}, _Tty) -> - {[], {Buf, BufTail, Col}}; -insert_chars(Chars, {Buf, BufTail, Col}, Tty) -> - {NewBuf, _NewBufTail, WriteBuf, NewCol} = - conv_buf(Chars, Buf, [], [], Col, Tty), - M = move_cursor(special_at_width(NewCol+length(BufTail), Tty), NewCol, Tty), - {[WriteBuf, BufTail | M], {NewBuf, BufTail, NewCol}}. +insert_chars([], Buf, _Tty) -> + {[], Buf}; +insert_chars(Chars, {_LB,{_Bef, Aft},LA, _Col}=Buf, Tty) -> + {{NewLB, {NewBef, _NewAft}, _NewLA}, WriteBuf, NewCol} = conv_buf(Chars, Buf, [], Tty), + M = move_cursor(special_at_width(NewCol+length(Aft), Tty), NewCol, Tty), + {[WriteBuf, Aft | M], {NewLB,{NewBef, Aft},LA, NewCol}}. %%% delete characters at current position, (backwards if negative argument) -delete_chars(0, {Buf, BufTail, Col}, _Tty) -> - {[], {Buf, BufTail, Col}}; -delete_chars(N, {Buf, BufTail, Col}, Tty) when N > 0 -> - NewBufTail = nthtail(N, BufTail), - M = move_cursor(Col + length(NewBufTail) + N, Col, Tty), - {[NewBufTail, lists:duplicate(N, $ ) | M], - {Buf, NewBufTail, Col}}; -delete_chars(N, {Buf, BufTail, Col}, Tty) -> % N < 0 - NewBuf = nthtail(-N, Buf), +delete_chars(0, {LB,{Bef, Aft},LA, Col}, _Tty) -> + {[], {LB,{Bef, Aft},LA, Col}}; +delete_chars(N, {LB,{Bef, Aft},LA, Col}, Tty) when N > 0 -> + NewAft = nthtail(N, Aft), + M = move_cursor(Col + length(NewAft) + N, Col, Tty), + {[NewAft, lists:duplicate(N, $ ) | M], + {LB,{Bef, NewAft},LA, Col}}; +delete_chars(N, {LB,{Bef, Aft},LA, Col}, Tty) -> % N < 0 + NewBef = nthtail(-N, Bef), NewCol = case Col + N of V when V >= 0 -> V; _ -> 0 end, M1 = move_cursor(Col, NewCol, Tty), - M2 = move_cursor(special_at_width(NewCol+length(BufTail)-N, Tty), NewCol, Tty), - {[M1, BufTail, lists:duplicate(-N, $ ) | M2], - {NewBuf, BufTail, NewCol}}. + M2 = move_cursor(special_at_width(NewCol+length(Aft)-N, Tty), NewCol, Tty), + {[M1, Aft, lists:duplicate(-N, $ ) | M2], + {LB,{NewBef, Aft},LA, NewCol}}. %%% Window change, redraw the current line (and clear out after it %%% if current window is wider than previous) @@ -536,52 +570,74 @@ window_change(Tty, OldTty, Buf) when OldTty#ssh_pty.width == Tty#ssh_pty.width -> %% No line width change {[], Buf}; -window_change(Tty, OldTty, {Buf, BufTail, Col}) -> +window_change(Tty, OldTty, {LB, {Bef, Aft}, LA, Col}) -> case OldTty#ssh_pty.width - Tty#ssh_pty.width of 0 -> %% No line width change - {[], {Buf,BufTail,Col}}; + {[], {LB, {Bef, Aft}, LA, Col}}; DeltaW0 when DeltaW0 < 0, - BufTail == [] -> + Aft == [] -> % Line width is decreased, cursor is at end of input - {[], {Buf,BufTail,Col}}; + {[], {LB, {Bef, Aft}, LA, Col}}; DeltaW0 when DeltaW0 < 0, - BufTail =/= [] -> + Aft =/= [] -> % Line width is decreased, cursor is not at end of input - {[], {Buf,BufTail,Col}}; + {[], {LB, {Bef, Aft}, LA, Col}}; DeltaW0 when DeltaW0 > 0 -> % Line width is increased - {[], {Buf,BufTail,Col}} + {[], {LB, {Bef, Aft}, LA, Col}} end. %% move around in buffer, respecting pad characters -step_over(0, Buf, [?PAD | BufTail], Col) -> - {[?PAD | Buf], BufTail, Col+1}; -step_over(0, Buf, BufTail, Col) -> - {Buf, BufTail, Col}; -step_over(N, [C | Buf], BufTail, Col) when N < 0 -> +step_over(0, {LB, {Bef, [?PAD |Aft]}, LA, Col}) -> + {LB, {[?PAD | Bef], Aft}, LA, Col+1}; +step_over(0, {LB, {Bef, Aft}, LA, Col}) -> + {LB, {Bef, Aft}, LA, Col}; +step_over(N, {LB, {[C | Bef], Aft}, LA, Col}) when N < 0 -> N1 = ifelse(C == ?PAD, N, N+1), - step_over(N1, Buf, [C | BufTail], Col-1); -step_over(N, Buf, [C | BufTail], Col) when N > 0 -> + step_over(N1, {LB, {Bef, [C | Aft]}, LA, Col-1}); +step_over(N, {LB, {Bef, [C | Aft]}, LA, Col}) when N > 0 -> N1 = ifelse(C == ?PAD, N, N-1), - step_over(N1, [C | Buf], BufTail, Col+1). + step_over(N1, {LB, {[C | Bef], Aft}, LA, Col+1}). %%% an empty line buffer -empty_buf() -> {[], [], 0}. +empty_buf() -> {[], {[], []}, [], 0}. %%% col and row from position with given width col(N, W) -> N rem W. row(N, W) -> N div W. %%% move relative N characters -move_rel(N, {Buf, BufTail, Col}, Tty) -> - {NewBuf, NewBufTail, NewCol} = step_over(N, Buf, BufTail, Col), +move_rel(N, {_LB, {_Bef, _Aft}, _LA, Col}=Buf, Tty) -> + {NewLB, {NewBef, NewAft}, NewLA, NewCol} = step_over(N, Buf), M = move_cursor(Col, NewCol, Tty), - {M, {NewBuf, NewBufTail, NewCol}}. - + {M, {NewLB, {NewBef, NewAft}, NewLA, NewCol}}. + +move_line(V, {_LB, {_Bef, _Aft}, _LA, Col}, Tty = #ssh_pty{width=W}) + when V < 0, length(_LB) >= -V -> + {LinesJumped, [B|NewLB]} = lists:split(-V -1, _LB), + CL = lists:reverse(_Bef,_Aft), + NewLA = lists:reverse([CL|LinesJumped], _LA), + {NewBB, NewAft} = lists:split(min(length(_Bef),length(B)), B), + NewBef = lists:reverse(NewBB), + NewCol = Col - length(_Bef) - lists:sum([((length(L)-1) div W)*W + W || L <- [B|LinesJumped]]) + length(NewBB), + M = move_cursor(Col, NewCol, Tty), + {M, {NewLB, {NewBef, NewAft}, NewLA, NewCol}}; +move_line(V, {_LB, {_Bef, _Aft}, _LA, Col}, Tty = #ssh_pty{width=W}) + when V > 0, length(_LA) >= V -> + {LinesJumped, [A|NewLA]} = lists:split(V -1, _LA), + CL = lists:reverse(_Bef,_Aft), + NewLB = lists:reverse([CL|LinesJumped],_LB), + {NewBB, NewAft} = lists:split(min(length(_Bef),length(A)), A), + NewBef = lists:reverse(NewBB), + NewCol = Col - length(_Bef) + lists:sum([((length(L)-1) div W)*W + W || L <- [CL|LinesJumped]]) + length(NewBB), + M = move_cursor(Col, NewCol, Tty), + {M, {NewLB, {NewBef, NewAft}, NewLA, NewCol}}; +move_line(_, Buf, _) -> + {"", Buf}. %%% give move command for tty move_cursor(A, A, _Tty) -> []; @@ -666,7 +722,9 @@ start_shell(ConnectionHandler, State) -> {_,_,_} = Shell -> Shell end, - State#state{group = group:start(self(), ShellSpawner, [{echo, get_echo(State#state.pty)}]), + State#state{group = group:start(self(), ShellSpawner, + [{expand_below, false}, + {echo, get_echo(State#state.pty)}]), buf = empty_buf()}. %%-------------------------------------------------------------------- @@ -687,7 +745,8 @@ start_exec_shell(ConnectionHandler, Cmd, State) -> {M,F,A} -> {M, F, A++[Cmd]} end, - State#state{group = group:start(self(), ExecShellSpawner, [{echo,false}]), + State#state{group = group:start(self(), ExecShellSpawner, [{expand_below, false}, + {echo,false}]), buf = empty_buf()}. %%-------------------------------------------------------------------- @@ -771,7 +830,8 @@ exec_in_self_group(ConnectionHandler, ChannelId, WantReply, State, Fun) -> end end) end, - {ok, State#state{group = group:start(self(), Exec, [{echo,false}]), + {ok, State#state{group = group:start(self(), Exec, [{expand_below, false}, + {echo,false}]), buf = empty_buf()}}. diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl index 7132e32fe5d9..6b6623945f90 100644 --- a/lib/ssh/src/ssh_client_channel.erl +++ b/lib/ssh/src/ssh_client_channel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -261,10 +261,9 @@ handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}}, (catch ssh_connection:close(ConnectionManager, ChannelId)), {stop, normal, State#state{close_sent = true}}; -handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, - channel_cb = Module, - channel_state = ChannelState0} = State) -> - case Module:handle_ssh_msg(Msg, ChannelState0) of +handle_info({ssh_cm, _, _} = Msg, #state{channel_cb = Module, + channel_state = ChannelState0} = State) -> + try Module:handle_ssh_msg(Msg, ChannelState0) of {ok, ChannelState} -> adjust_window(Msg), {noreply, State#state{channel_state = ChannelState}}; @@ -272,9 +271,10 @@ handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, adjust_window(Msg), {noreply, State#state{channel_state = ChannelState}, Timeout}; {stop, ChannelId, ChannelState} -> - catch ssh_connection:close(ConnectionManager, ChannelId), - {stop, normal, State#state{close_sent = true, - channel_state = ChannelState}} + do_the_close(Msg, ChannelId, State#state{channel_state = ChannelState}) + catch + error:_ -> + do_the_close(Msg, State#state.channel_id, State) end; handle_info(Msg, #state{channel_cb = Module, @@ -288,7 +288,7 @@ handle_info(Msg, #state{channel_cb = Module, {stop, ChannelId, ChannelState} -> do_the_close(Msg, ChannelId, State#state{channel_state = ChannelState}) catch - error:function_clause when size(Msg) == 3, + error:function_clause when tuple_size(Msg) == 3, element(1,Msg) == 'EXIT' -> do_the_close(Msg, State#state.channel_id, State) end. @@ -390,7 +390,7 @@ handle_cb_result({stop, Reason, ChannelState}, State) -> adjust_window({ssh_cm, ConnectionManager, {data, ChannelId, _, Data}}) -> - ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data)); + ssh_connection:adjust_window(ConnectionManager, ChannelId, byte_size(Data)); adjust_window(_) -> ok. diff --git a/lib/ssh/src/ssh_client_key_api.erl b/lib/ssh/src/ssh_client_key_api.erl index 367d78bf22fc..1cc153904f03 100644 --- a/lib/ssh/src/ssh_client_key_api.erl +++ b/lib/ssh/src/ssh_client_key_api.erl @@ -82,7 +82,7 @@ %%% in the argument Host with the port Port. %%% %%% Due to compatibility reasons, the OTP/SSH application first -%%% trys add_host_key/4 and then the old add_host_key/3 +%%% tries add_host_key/4 and then the old add_host_key/3 -callback add_host_key(Host :: inet:ip_address() | inet:hostname() | [inet:ip_address() | inet:hostname()], diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index f504cd581395..34e97ba6ca1f 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -177,7 +177,7 @@ Command :: string() } . -%%% This function is soley to convince all +%%% This function is solely to convince all %%% checks that the type event() exists... -export([dummy/1]). -spec dummy(event()) -> false. @@ -404,7 +404,7 @@ ptty_alloc(ConnectionHandler, Channel, Options0, TimeOut) -> ). %%-------------------------------------------------------------------- -%% Not yet officialy supported! The following functions are part of the +%% Not yet officially supported! The following functions are part of the %% initial contributed ssh application. They are untested. Do we want them? %% Should they be documented and tested? %%-------------------------------------------------------------------- @@ -1200,7 +1200,7 @@ get_window(#channel{send_buf = Buffer, } = Channel, Acc0) -> case queue:out(Buffer) of {{value, {_, Data} = Msg}, NewBuffer} -> - case handle_send_window(Msg, size(Data), PacketSize, WindowSize0, Acc0) of + case handle_send_window(Msg, byte_size(Data), PacketSize, WindowSize0, Acc0) of {WindowSize, Acc, {_, <<>>}} -> {lists:reverse(Acc), Channel#channel{send_window_size = WindowSize, send_buf = NewBuffer}}; @@ -1520,7 +1520,7 @@ handle_cli_msg(C0, ChId, Reply0) -> channel_data_reply_msg(ChannelId, Connection, DataType, Data) -> case ssh_client_channel:cache_lookup(Connection#connection.channel_cache, ChannelId) of #channel{recv_window_size = Size} = Channel -> - WantedSize = Size - size(Data), + WantedSize = Size - byte_size(Data), ssh_client_channel:cache_update(Connection#connection.channel_cache, Channel#channel{recv_window_size = WantedSize}), reply_msg(Channel, Connection, {data, ChannelId, DataType, Data}); diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 57d47bddcbad..4ef45516ca23 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -421,11 +421,11 @@ init([Role, Socket, Opts]) when Role==client ; Role==server -> end; {error,Error} -> - {stop, {error,Error}} + {stop, {shutdown,Error}} end. %%%---------------------------------------------------------------- -%%% Connection start and initalization helpers +%%% Connection start and initialization helpers init_connection_record(Role, Socket, Opts) -> {WinSz, PktSz} = init_inet_buffers_window(Socket), @@ -625,7 +625,7 @@ handle_event(internal, {version_exchange,Version}, {hello,Role}, D0) -> {NumVsn, StrVsn} = ssh_transport:handle_hello_version(Version), case handle_version(NumVsn, StrVsn, D0#data.ssh_params) of {ok, Ssh1} -> - %% Since the hello part is finnished correctly, we set the + %% Since the hello part is finished correctly, we set the %% socket to the packet handling mode (including recbuf size): inet:setopts(D0#data.socket, [{packet,0}, {mode,binary}, @@ -651,7 +651,7 @@ handle_event(state_timeout, no_hello_received, {hello,_Role}=StateName, D0 = #da Time = ?GET_OPT(hello_timeout, Ssh0#ssh.opts), {Shutdown, D} = ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR, - lists:concat(["No HELLO recieved within ",ssh_lib:format_time_ms(Time)]), + lists:concat(["No HELLO received within ",ssh_lib:format_time_ms(Time)]), StateName, D0), {stop, Shutdown, D}; @@ -939,7 +939,7 @@ handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, {error,Error} -> {keep_state, D0, {reply,From,{error,Error}}}; D -> - %% Note reply to channel will happen later when reply is recived from peer on the socket + %% Note reply to channel will happen later when reply is received from peer on the socket start_channel_request_timer(ChannelId, From, Timeout), {keep_state, D, cond_set_idle_timer(D)} end; @@ -950,7 +950,7 @@ handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, {error,Error} -> {keep_state, D0, {reply,From,{error,Error}}}; D -> - %% Note reply to channel will happen later when reply is recived from peer on the socket + %% Note reply to channel will happen later when reply is received from peer on the socket start_channel_request_timer(ChannelId, From, Timeout), {keep_state, D, cond_set_idle_timer(D)} end; @@ -1120,7 +1120,10 @@ handle_event(info, {Proto, Sock, NewData}, StateName, #ssh_msg_global_request{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; #ssh_msg_request_success{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; #ssh_msg_request_failure{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; - #ssh_msg_channel_open{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; + #ssh_msg_channel_open{} = Msg -> {keep_state, D1, + [{{timeout, max_initial_idle_time}, cancel} | + ?CONNECTION_MSG(Msg) + ]}; #ssh_msg_channel_open_confirmation{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; #ssh_msg_channel_open_failure{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; #ssh_msg_channel_window_adjust{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)}; @@ -1186,7 +1189,7 @@ handle_event(info, {Proto, Sock, NewData}, StateName, %%%==== handle_event(internal, prepare_next_packet, _StateName, D) -> Enough = erlang:max(8, D#data.ssh_params#ssh.decrypt_block_size), - case size(D#data.encrypted_data_buffer) of + case byte_size(D#data.encrypted_data_buffer) of Sz when Sz >= Enough -> self() ! {D#data.transport_protocol, D#data.socket, <<>>}; _ -> @@ -1237,6 +1240,9 @@ handle_event({timeout,idle_time}, _Data, _StateName, D) -> keep_state_and_data end; +handle_event({timeout,max_initial_idle_time}, _Data, _StateName, _D) -> + {stop, {shutdown, "Timeout"}}; + %%% So that terminate will be run when supervisor is shutdown handle_event(info, {'EXIT', _Sup, Reason}, StateName, _D) -> Role = ?role(StateName), @@ -1247,7 +1253,7 @@ handle_event(info, {'EXIT', _Sup, Reason}, StateName, _D) -> {stop, {shutdown, Reason}}; Reason == normal -> - %% An exit normal should not cause a server to crash. This has happend... + %% An exit normal should not cause a server to crash. This has happened... keep_state_and_data; true -> @@ -1588,7 +1594,7 @@ handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) -> ext_info({"server-sig-algs",SigAlgsStr}, D0 = #data{ssh_params=#ssh{role=client, userauth_pubkeys=ClientSigAlgs}=Ssh0}) -> - %% ClientSigAlgs are the pub_key algortithms that: + %% ClientSigAlgs are the pub_key algorithms that: %% 1) is usable, that is, the user has such a public key and %% 2) is either the default list or set by the caller %% with the client option 'pref_public_key_algs' @@ -2082,7 +2088,7 @@ ssh_dbg_off(disconnect) -> dbg:ctpl(?MODULE, send_disconnect, 7); ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 3); ssh_dbg_off(tcp) -> dbg:ctpg(?MODULE, handle_event, 4), % How to avoid cancelling 'connection_events' ? dbg:ctpl(?MODULE, send_bytes, 2), - dbg:ctpg(?MODULE, close_transport, 1); + dbg:ctpl(?MODULE, close_transport, 1); ssh_dbg_off(renegotiation) -> dbg:ctpl(?MODULE, init_renegotiate_timers, 3), dbg:ctpl(?MODULE, pause_renegotiate_timers, 3), dbg:ctpl(?MODULE, check_data_rekeying_dbg, 2), diff --git a/lib/ssh/src/ssh_daemon_channel.erl b/lib/ssh/src/ssh_daemon_channel.erl index 30c4773a7a73..899c99d61091 100644 --- a/lib/ssh/src/ssh_daemon_channel.erl +++ b/lib/ssh/src/ssh_daemon_channel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2018. All Rights Reserved. +%% Copyright Ericsson AB 2013-2022. 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. @@ -25,7 +25,7 @@ -module(ssh_daemon_channel). -%% API to server side channel that can be pluged into the erlang ssh daemeon +%% API to server side channel that can be plugged into the erlang ssh daemeon -callback init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | {stop, Reason :: term()} | ignore. diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl index 54a88a479ffb..7ef69630fecf 100644 --- a/lib/ssh/src/ssh_dbg.erl +++ b/lib/ssh/src/ssh_dbg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -113,7 +113,7 @@ start(IoFmtFun) when is_function(IoFmtFun,2) ; is_function(IoFmtFun,3) -> stop() -> try - dbg:stop_clear(), + dbg:stop(), gen_server:stop(?SERVER) catch _:_ -> ok @@ -156,26 +156,26 @@ go_on() -> on(IsOn). %%%---------------------------------------------------------------- -shrink_bin(B) when is_binary(B), size(B)>256 -> {'*** SHRINKED BIN', - size(B), - element(1,split_binary(B,64)), - '...', - element(2,split_binary(B,size(B)-64)) - }; +shrink_bin(B) when is_binary(B), byte_size(B)>256 -> {'*** SHRUNK BIN', + byte_size(B), + element(1,split_binary(B,64)), + '...', + element(2,split_binary(B,byte_size(B)-64)) + }; shrink_bin(L) when is_list(L) -> lists:map(fun shrink_bin/1, L); shrink_bin(T) when is_tuple(T) -> list_to_tuple(shrink_bin(tuple_to_list(T))); shrink_bin(X) -> X. %%%---------------------------------------------------------------- -%% Replace any occurence of {Name,...}, with "#Name{}" +%% Replace any occurrence of {Name,...}, with "#Name{}" reduce_state(T, RecordExample) -> Name = element(1, RecordExample), - Arity = size(RecordExample), + Arity = tuple_size(RecordExample), reduce_state(T, Name, Arity). -%% Replace any occurence of {Name,...}, with "#Name{}" +%% Replace any occurrence of {Name,...}, with "#Name{}" reduce_state(T, Name, Arity) when element(1,T) == Name, - size(T) == Arity -> + tuple_size(T) == Arity -> lists:concat(['#',Name,'{}']); reduce_state(L, Name, Arity) when is_list(L) -> [reduce_state(E,Name,Arity) || E <- L]; @@ -353,7 +353,7 @@ trace_pid(T) when element(1,T)==trace %% Pick last element, the Time Stamp, and format it trace_ts(T) when element(1,T)==trace_ts -> - ts( element(size(T), T) ). + ts( element(tuple_size(T), T) ). %% Make a tuple of all elements but the 1st, 2nd and last trace_info(T) -> @@ -400,7 +400,7 @@ try_all_types_in_all_modules(TypesOn, Arg, WriteFun, Acc0) -> catch _:_ -> %% and finally, signal for special formatting - %% if noone else formats it + %% if no one else formats it Acc end end diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl index 5a1b4def87b4..c44b649e87dd 100644 --- a/lib/ssh/src/ssh_file.erl +++ b/lib/ssh/src/ssh_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2022. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -51,6 +51,7 @@ %%%--------------------- utility exports --------------------------- -export([decode/2, encode/2]). +-export([extract_public_key/1]). -define(ENCODED_LINE_LENGTH, 68). @@ -66,10 +67,7 @@ -type optimize_key_lookup() :: {optimize, time|space} . -type key() :: public_key:public_key() | public_key:private_key() . --type experimental_openssh_key_v1() :: [{key() - | {ed_pri, ed25519|ed448, Pub::binary(), Priv::binary()} - | {ed_pub, ed25519|ed448, Key::binary()}, - openssh_key_v1_attributes()}]. +-type experimental_openssh_key_v1() :: [{key(), openssh_key_v1_attributes()}]. -type openssh_key_v1_attributes() :: [{atom(),term()}]. %%%================================================================ @@ -291,7 +289,7 @@ decode(Bin, auth_keys) when is_binary(Bin) -> [ [[] | binary:split(L,<<" ">>,[global,trim_all])] ]; {Pos,Len} when is_integer(Pos), is_integer(Len) -> [ [binary:split(binary:part(L,0,Pos-1), <<",">>,[global,trim_all]) | - binary:split(binary:part(L,Pos,size(L)-Pos), <<" ">>, [global,trim_all])] + binary:split(binary:part(L,Pos,byte_size(L)-Pos), <<" ">>, [global,trim_all])] ] end ]; @@ -386,6 +384,40 @@ encode(KeyAttrs, Type) when Type == known_hosts; encode(_KeyBin, _Type) -> error(badarg). +%%%---------------------------------------------------------------- + +-spec extract_public_key(PrivKey) -> PubKey + when PrivKey :: public_key:private_key(), + PubKey :: public_key:public_key(). + +extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) -> + #'RSAPublicKey'{modulus = N, publicExponent = E}; +extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) -> + {Y, #'Dss-Parms'{p=P, q=Q, g=G}}; +extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID}, + publicKey = Pub0, privateKey = Priv}) when + OID == ?'id-Ed25519' orelse + OID == ?'id-Ed448' -> + case {pubkey_cert_records:namedCurves(OID), Pub0} of + {Alg, asn1_NOVALUE} -> + %% If we're missing the public key, we can create it with + %% the private key. + {Pub, Priv} = crypto:generate_key(eddsa, Alg, Priv), + {#'ECPoint'{point=Pub}, {namedCurve,OID}}; + {_Alg, Pub} -> + {#'ECPoint'{point=Pub}, {namedCurve,OID}} + end; +extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID}, + publicKey = Q}) when is_tuple(OID) -> + {#'ECPoint'{point=Q}, {namedCurve,OID}}; +extract_public_key(#{engine:=_, key_id:=_, algorithm:=Alg} = M) -> + case {Alg, crypto:privkey_to_pubkey(Alg, M)} of + {rsa, [E,N]} -> + #'RSAPublicKey'{modulus = N, publicExponent = E}; + {dss, [P,Q,G,Y]} -> + {Y, #'Dss-Parms'{p=P, q=Q, g=G}} + end. + %%%================================================================ %%% %%% Local functions @@ -604,7 +636,7 @@ find_host_key(_, _, _, []) -> revoked_key(Hosts, KeyType, EncKey, [<<"@revoked ",RestLine/binary>> | Lines]) -> case binary:split(RestLine, <<" ">>, [global,trim_all]) of [Patterns, KeyType, EncKey|_Comment] -> - %% Very likeley to be a revoked key, + %% Very likely to be a revoked key, %% but does any of the hosts match the pattern? case host_match(Hosts, Patterns) of true -> @@ -698,12 +730,12 @@ pos_match(H, P) -> {[Hh], [Ph,<<"*">>]} -> %% host [host]:* - Sz = size(Hh), + Sz = byte_size(Hh), Ph == <<"[", Hh:Sz/binary, "]">>; {[Hh], [Ph,<<"22">>]} -> %% host [host]:22 - Sz = size(Hh), + Sz = byte_size(Hh), Ph == <<"[", Hh:Sz/binary, "]">>; _ -> @@ -1020,6 +1052,7 @@ asn1_type(<<"RSA PUBLIC">>) -> 'RSAPublicKey'; asn1_type(<<"DSA PRIVATE">>) -> 'DSAPrivateKey'; asn1_type(<<"EC PRIVATE">>) -> 'ECPrivateKey'; asn1_type(<<"OPENSSH PRIVATE">>) -> 'openssh-key-v1'; +asn1_type(<<"PRIVATE">>) -> 'PrivateKeyInfo'; asn1_type(_) -> undefined. %%%================================================================ @@ -1101,7 +1134,7 @@ check_padding(Bin, BlockSize) -> end. %%%---------------------------------------------------------------- -%% KeyPairs :: [ {Pub,Priv,Comment} | {ed_pri{_,_,_},Comment} ] +%% KeyPairs :: [ {Pub,Priv,Comment} ] openssh_key_v1_encode(KeyPairs) -> CipherName = <<"none">>, BlockSize = ?NON_CRYPT_BLOCKSIZE, % Cipher dependent @@ -1113,7 +1146,7 @@ openssh_key_v1_encode(KeyPairs) -> CheckInt/binary, (openssh_key_v1_encode_priv_keys_cmnts(KeyPairs))/binary>>, UnEncrypted = <>, + (pad(byte_size(UnEncrypted0), BlockSize))/binary>>, Encrypted = encrypt_openssh_key_v1(UnEncrypted, KdfName, KdfOptions, CipherName, ignore), <<"openssh-key-v1",0, ?STRING(CipherName), @@ -1127,8 +1160,9 @@ openssh_key_v1_encode(KeyPairs) -> openssh_key_v1_encode_pub_keys(KeyPairs) -> openssh_key_v1_encode_pub_keys(KeyPairs, []). -openssh_key_v1_encode_pub_keys([{{ed_pri,Alg,PubKey,_},_C}|Ks], Acc) -> - Bk = ssh_message:ssh2_pubkey_encode({ed_pub,Alg,PubKey}), +openssh_key_v1_encode_pub_keys([{Priv = #'ECPrivateKey'{}, _Cmnt} | Ks], Acc) -> + Pub = extract_public_key(Priv), + Bk = ssh_message:ssh2_pubkey_encode(Pub), openssh_key_v1_encode_pub_keys(Ks, [<>|Acc]); openssh_key_v1_encode_pub_keys([{K,_,_C}|Ks], Acc) -> Bk = ssh_message:ssh2_pubkey_encode(K), @@ -1136,11 +1170,12 @@ openssh_key_v1_encode_pub_keys([{K,_,_C}|Ks], Acc) -> openssh_key_v1_encode_pub_keys([], Acc) -> list_to_binary(lists:reverse(Acc)). + %%%---- openssh_key_v1_encode_priv_keys_cmnts(KeyPairs) -> openssh_key_v1_encode_priv_keys_cmnts(KeyPairs, []). -openssh_key_v1_encode_priv_keys_cmnts([{K={ed_pri,_,_,_},C} | Ks], Acc) -> +openssh_key_v1_encode_priv_keys_cmnts([{K = #'ECPrivateKey'{}, C} | Ks], Acc) -> Bk = ssh_message:ssh2_privkey_encode(K), openssh_key_v1_encode_priv_keys_cmnts(Ks, [<>|Acc]); openssh_key_v1_encode_priv_keys_cmnts([{_,K,C}|Ks], Acc) -> diff --git a/lib/ssh/src/ssh_fsm_userauth_client.erl b/lib/ssh/src/ssh_fsm_userauth_client.erl index e24e0e2f9a0a..73c8446639d4 100644 --- a/lib/ssh/src/ssh_fsm_userauth_client.erl +++ b/lib/ssh/src/ssh_fsm_userauth_client.erl @@ -55,13 +55,13 @@ callback_mode() -> %%% ######## {userauth, client} #### -%%---- #ssh_msg_ext_info could follow after the key exchange, both the intial and the re-negotiation +%%---- #ssh_msg_ext_info could follow after the key exchange, both the initial and the re-negotiation handle_event(internal, #ssh_msg_ext_info{}=Msg, {userauth,client}, D0) -> %% FIXME: need new state to receive this msg! D = ssh_connection_handler:handle_ssh_msg_ext_info(Msg, D0), {keep_state, D}; -%%---- recevied userauth success from the server +%%---- received userauth success from the server handle_event(internal, #ssh_msg_userauth_success{}, {userauth,client}, D0=#data{ssh_params = Ssh}) -> ssh_auth:ssh_msg_userauth_result(success), ssh_connection_handler:handshake(ssh_connected, D0), @@ -80,7 +80,7 @@ handle_event(internal, #ssh_msg_userauth_failure{}, {userauth,client}=StateName, handle_event(internal, #ssh_msg_userauth_failure{authentications = Methods}, StateName={userauth,client}, D0 = #data{ssh_params = Ssh0}) -> - %% The prefered authentication method failed, try next method + %% The preferred authentication method failed, try next method Ssh1 = case Ssh0#ssh.userauth_methods of none -> %% Server tells us which authentication methods that are allowed diff --git a/lib/ssh/src/ssh_fsm_userauth_server.erl b/lib/ssh/src/ssh_fsm_userauth_server.erl index 77657b4d829d..fc1750ce2c48 100644 --- a/lib/ssh/src/ssh_fsm_userauth_server.erl +++ b/lib/ssh/src/ssh_fsm_userauth_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -64,10 +64,20 @@ handle_event(internal, case {ServiceName, Ssh0#ssh.service, Method} of {"ssh-connection", "ssh-connection", "none"} -> %% Probably the very first userauth_request but we deny unauthorized login - {not_authorized, _, {Reply,Ssh}} = - ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0), - D = ssh_connection_handler:send_msg(Reply, D0#data{ssh_params = Ssh}), - {keep_state, D}; + %% However, we *may* accept unauthorized login if instructed so + case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of + {not_authorized, _, {Reply,Ssh}} -> + D = ssh_connection_handler:send_msg(Reply, D0#data{ssh_params = Ssh}), + {keep_state, D}; + {authorized, User, {Reply, Ssh1}} -> + D = connected_state(Reply, Ssh1, User, Method, D0), + {next_state, {connected,server}, D, + [set_max_initial_idle_timeout(D), + {change_callback_module,ssh_connection_handler} + ] + } + + end; {"ssh-connection", "ssh-connection", Method} -> %% Userauth request with a method like "password" or so @@ -77,7 +87,10 @@ handle_event(internal, case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of {authorized, User, {Reply, Ssh1}} -> D = connected_state(Reply, Ssh1, User, Method, D0), - {next_state, {connected,server}, D, {change_callback_module,ssh_connection_handler}}; + {next_state, {connected,server}, D, + [set_max_initial_idle_timeout(D), + {change_callback_module,ssh_connection_handler} + ]}; {not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" -> retry_fun(User, Reason, D0), D = ssh_connection_handler:send_msg(Reply, D0#data{ssh_params = Ssh}), @@ -110,7 +123,10 @@ handle_event(internal, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboa case ssh_auth:handle_userauth_info_response(Msg, D0#data.ssh_params) of {authorized, User, {Reply, Ssh1}} -> D = connected_state(Reply, Ssh1, User, "keyboard-interactive", D0), - {next_state, {connected,server}, D, {change_callback_module,ssh_connection_handler}}; + {next_state, {connected,server}, D, + [set_max_initial_idle_timeout(D), + {change_callback_module,ssh_connection_handler} + ]}; {not_authorized, {User, Reason}, {Reply, Ssh}} -> retry_fun(User, Reason, D0), D = ssh_connection_handler:send_msg(Reply, D0#data{ssh_params = Ssh}), @@ -125,7 +141,11 @@ handle_event(internal, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboa {authorized, User, {Reply, Ssh1}} = ssh_auth:handle_userauth_info_response({extra,Msg}, D0#data.ssh_params), D = connected_state(Reply, Ssh1, User, "keyboard-interactive", D0), - {next_state, {connected,server}, D, {change_callback_module,ssh_connection_handler}}; + {next_state, {connected,server}, D, + [set_max_initial_idle_timeout(D), + {change_callback_module,ssh_connection_handler} + ] + }; %%% ######## UNHANDLED EVENT! @@ -159,6 +179,9 @@ connected_state(Reply, Ssh1, User, Method, D0) -> ssh_params = Ssh#ssh{authenticated = true}}. +set_max_initial_idle_timeout(#data{ssh_params = #ssh{opts=Opts}}) -> + {{timeout,max_initial_idle_time}, ?GET_OPT(max_initial_idle_time,Opts), none}. + connected_fun(User, Method, #data{ssh_params = #ssh{peer = {_,Peer}}} = D) -> ?CALL_FUN(connectfun,D)(User, Peer, Method). diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl index b1b4d0ea56e8..aa7324b58805 100644 --- a/lib/ssh/src/ssh_info.erl +++ b/lib/ssh/src/ssh_info.erl @@ -20,7 +20,7 @@ %% %%---------------------------------------------------------------------- -%% Purpose: Print some info of a running ssh aplication. +%% Purpose: Print some info of a running ssh application. %%---------------------------------------------------------------------- -module(ssh_info). diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index 8ed662b3de74..3c1ea65038df 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -34,6 +34,8 @@ -export([ssh2_pubkey_decode/1, ssh2_pubkey_encode/1, ssh2_privkey_decode2/1, + oid2ssh_curvename/1, + ssh_curvename2oid/1, %% experimental: ssh2_privkey_encode/1 ]). @@ -172,7 +174,7 @@ encode(#ssh_msg_userauth_pk_ok{ <>; encode(#ssh_msg_userauth_passwd_changereq{prompt = Prompt, - languge = Lang + language = Lang })-> <>; @@ -438,7 +440,7 @@ decode(<>) -> #ssh_msg_userauth_passwd_changereq{ prompt = Prompt, - languge = Lang + language = Lang }; %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST: @@ -571,20 +573,29 @@ decode(< <>), ?Empint(E), ?Empint(N)>>; + ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> <>), ?Empint(P), ?Empint(Q), ?Empint(G), ?Empint(Y)>>; + +ssh2_pubkey_encode({#'ECPoint'{point = Q}, {namedCurve,OID}}) when OID == ?'id-Ed25519' orelse + OID == ?'id-Ed448' -> + {KeyType, _} = oid2ssh_curvename(OID), + <>; + +ssh2_pubkey_encode(#'ECPrivateKey'{parameters = {namedCurve,OID}, + publicKey = Key}) when OID == ?'id-Ed25519' orelse + OID == ?'id-Ed448' -> + {KeyType, _} = oid2ssh_curvename(OID), + <>; + +ssh2_pubkey_encode(#'ECPrivateKey'{parameters = {namedCurve,OID}, + publicKey = Key}) -> + {KeyType,Curve} = oid2ssh_curvename(OID), + <>; + ssh2_pubkey_encode({#'ECPoint'{point = Q}, {namedCurve,OID}}) -> - Curve = public_key:oid2ssh_curvename(OID), - KeyType = <<"ecdsa-sha2-", Curve/binary>>, - <>; -ssh2_pubkey_encode({ed_pub, ed25519, Key}) -> - <>), ?Estring(Key)>>; -ssh2_pubkey_encode({ed_pub, ed448, Key}) -> - <>), ?Estring(Key)>>; -ssh2_pubkey_encode({ed_pri, ed25519, Key, _}) -> - <>), ?Estring(Key)>>; -ssh2_pubkey_encode({ed_pri, ed448, Key, _}) -> - <>), ?Estring(Key)>>. + {KeyType,Curve} = oid2ssh_curvename(OID), + <>. %%%-------- ssh2_pubkey_decode(KeyBlob) -> @@ -608,26 +619,23 @@ ssh2_pubkey_decode2(<>) -> - Sz = TL-11, - <<_Curve:Sz/binary, - ?DEC_BIN(SshName, _IL), - ?DEC_BIN(Q, _QL), - Rest/binary>> = KeyRest, - OID = public_key:ssh_curvename2oid(SshName), - {{#'ECPoint'{point = Q}, {namedCurve,OID} - }, Rest}; -ssh2_pubkey_decode2(<>) -> - {{ed_pub, ed25519, Key}, - Rest}; -ssh2_pubkey_decode2(<>) -> - {{ed_pub, ed448, Key}, + +ssh2_pubkey_decode2(<>) -> + {Pub, Rest} = + case {SshCurveName, Rest0} of + {<<"ecdsa-sha2-", _/binary>>, + <>} -> {Q, Rest1}; + + {<<"ssh-ed",_/binary>>, + <>} -> {Key, Rest1} + end, + OID = ssh_curvename2oid(SshCurveName), + {{#'ECPoint'{point = Pub}, {namedCurve,OID}}, Rest}. - + %%%-------- private key -------- %% dialyser... ssh2_privkey_decode(KeyBlob) -> @@ -670,24 +678,30 @@ ssh2_privkey_encode(#'DSAPrivateKey' ?Empint(X) % Priv key >>; +ssh2_privkey_encode(#'ECPrivateKey' + {version = 1, + parameters = {namedCurve,OID}, + privateKey = Priv, + publicKey = Pub + }) when OID == ?'id-Ed25519' orelse + OID == ?'id-Ed448' -> + {CurveName,_} = oid2ssh_curvename(OID), + <>; + ssh2_privkey_encode(#'ECPrivateKey' {version = 1, parameters = {namedCurve,OID}, privateKey = Priv, publicKey = Q }) -> - CurveName = public_key:oid2ssh_curvename(OID), - <>), - ?STRING(<<"ecdsa-sha2-",CurveName/binary>>), % Yes + {CurveName,_} = oid2ssh_curvename(OID), + <>; + ?STRING(Priv)>>. -ssh2_privkey_encode({ed_pri, Alg, Pub, Priv}) -> - Name = atom_to_binary(Alg), - <>), - ?STRING(Pub), - ?STRING(<>)>>. - %%%-------- ssh2_privkey_decode2(<>) -> - Sz = TL-11, - <<_Curve:Sz/binary, - ?DEC_BIN(CurveName, _SNN), - ?DEC_BIN(Q, _QL), - ?DEC_BIN(Priv, _PrivL), - Rest/binary>> = KeyRest, - OID = public_key:ssh_curvename2oid(CurveName), + +ssh2_privkey_decode2(<>) -> + {Pub, Priv, Rest} = + case {SshCurveName, Rest0} of + {<<"ecdsa-sha2-",_/binary>>, + <>} -> + {Pub1, Priv1, Rest1}; + + {<<"ssh-ed",_/binary>>, + <>} -> + PL = PPL div 2, + <> = PrivPub, + {Pub1, Priv1, Rest1} + end, + OID = ssh_curvename2oid(SshCurveName), {#'ECPrivateKey'{version = 1, parameters = {namedCurve,OID}, privateKey = Priv, - publicKey = Q - }, Rest}; -ssh2_privkey_decode2(<>) -> - {{ed_pri, ed25519, Pub, Priv}, Rest}; -ssh2_privkey_decode2(<>) -> - {{ed_pri, ed448, Pub, Priv}, Rest}. - + publicKey = Pub + }, Rest}. + + +%% Description: Converts from the ssh name of elliptic curves to +%% the OIDs. +%%-------------------------------------------------------------------- +ssh_curvename2oid(<<"ssh-ed25519">>) -> ?'id-Ed25519'; +ssh_curvename2oid(<<"ssh-ed448">> ) -> ?'id-Ed448'; +ssh_curvename2oid(<<"ecdsa-sha2-nistp256">>) -> ?'secp256r1'; +ssh_curvename2oid(<<"ecdsa-sha2-nistp384">>) -> ?'secp384r1'; +ssh_curvename2oid(<<"ecdsa-sha2-nistp521">>) -> ?'secp521r1'. + +%% Description: Converts from elliptic curve OIDs to the ssh name. +%%-------------------------------------------------------------------- +oid2ssh_curvename(?'id-Ed25519')-> {<<"ssh-ed25519">>, 'n/a'}; +oid2ssh_curvename(?'id-Ed448') -> {<<"ssh-ed448">>, 'n/a'}; +oid2ssh_curvename(?'secp256r1') -> {<<"ecdsa-sha2-nistp256">>, <<"nistp256">>}; +oid2ssh_curvename(?'secp384r1') -> {<<"ecdsa-sha2-nistp384">>, <<"nistp384">>}; +oid2ssh_curvename(?'secp521r1') -> {<<"ecdsa-sha2-nistp521">>, <<"nistp521">>}. %%%================================================================ %%% @@ -810,13 +839,8 @@ encode_signature(#'RSAPublicKey'{}, SigAlg, Signature) -> encode_signature({_, #'Dss-Parms'{}}, _SigAlg, Signature) -> <>), ?Ebinary(Signature)>>; encode_signature({#'ECPoint'{}, {namedCurve,OID}}, _SigAlg, Signature) -> - Curve = public_key:oid2ssh_curvename(OID), - <>), ?Ebinary(Signature)>>; -encode_signature({ed_pub, ed25519,_}, _SigAlg, Signature) -> - <>), ?Ebinary(Signature)>>; -encode_signature({ed_pub, ed448,_}, _SigAlg, Signature) -> - <>), ?Ebinary(Signature)>>. - + {SshCurveName,_} = oid2ssh_curvename(OID), + <>), ?Ebinary(Signature)>>. %%%################################################################ diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl index b5ad545ecdc1..53cc69dc861a 100644 --- a/lib/ssh/src/ssh_options.erl +++ b/lib/ssh/src/ssh_options.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2022. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -34,7 +34,8 @@ keep_set_options/2, no_sensitive/2, initial_default_algorithms/2, - check_preferred_algorithms/1 + check_preferred_algorithms/1, + merge_options/3 ]). -export_type([private_options/0 @@ -151,6 +152,14 @@ delete_key(internal_options, Key, Opts, _CallerMod, _CallerLine) when is_map(Opt Opts#{internal_options := maps:remove(Key, InternalOpts)}. +%%%================================================================ +%%% +%%% Replace 0 or more options in an options map +%%% +merge_options(Role, NewPropList, Opts0) when is_list(NewPropList), + is_map(Opts0) -> + check_and_save(NewPropList, default(Role), Opts0). + %%%================================================================ %%% %%% Initialize the options @@ -167,8 +176,7 @@ handle_options(Role, PropList0) -> handle_options(Role, OptsList0, Opts0) when is_map(Opts0), is_list(OptsList0) -> OptsList1 = proplists:unfold( - lists:foldr(fun(T,Acc) when is_tuple(T), - size(T) =/= 2-> [{special_trpt_args,T} | Acc]; + lists:foldr(fun(T,Acc) when tuple_size(T) =/= 2 -> [{special_trpt_args,T} | Acc]; (X,Acc) -> [X|Acc] end, [], OptsList0)), @@ -219,10 +227,8 @@ handle_options(Role, OptsList0, Opts0) when is_map(Opts0), %% Enter the user's values into the map; unknown keys are %% treated as socket options - final_preferred_algorithms( - lists:foldl(fun(KV, Vals) -> - save(KV, OptionDefinitions, Vals) - end, InitialMap, OptsList2)) + check_and_save(OptsList2, OptionDefinitions, InitialMap) + catch error:{EO, KV, Reason} when EO == eoptions ; EO == eerl_env -> if @@ -235,6 +241,13 @@ handle_options(Role, OptsList0, Opts0) when is_map(Opts0), end end. +check_and_save(OptsList, OptionDefinitions, InitialMap) -> + final_preferred_algorithms( + lists:foldl(fun(KV, Vals) -> + save(KV, OptionDefinitions, Vals) + end, InitialMap, OptsList)). + + cnf_key(server) -> server_options; cnf_key(client) -> client_options. @@ -295,7 +308,7 @@ save({Inet,false}, _Defs, OptMap) when Inet==inet ; Inet==inet6 -> OptMap; save({special_trpt_args,T}, _Defs, OptMap) when is_map(OptMap) -> OptMap#{socket_options := [T | maps:get(socket_options,OptMap)]}; -%% and finaly the 'real stuff': +%% and finally the 'real stuff': save({Key,Value}, Defs, OptMap) when is_map(OptMap) -> try (check_fun(Key,Defs))(Value) of @@ -477,6 +490,12 @@ default(server) -> class => user_option }, + no_auth_needed => + #{default => false, + chk => fun(V) -> erlang:is_boolean(V) end, + class => user_option + }, + pk_check_user => #{default => false, chk => fun(V) -> erlang:is_boolean(V) end, @@ -513,6 +532,12 @@ default(server) -> class => user_option }, + max_initial_idle_time => + #{default => infinity, %% To not break compatibility + chk => fun(V) -> check_timeout(V) end, + class => user_option + }, + negotiation_timeout => #{default => 2*60*1000, chk => fun(V) -> check_timeout(V) end, @@ -1053,7 +1078,7 @@ check_modify_algorithms(M) when is_list(M) -> [error_in_check(Op_KVs, "Bad modify_algorithms") || Op_KVs <- M, not is_tuple(Op_KVs) - orelse (size(Op_KVs) =/= 2) + orelse (tuple_size(Op_KVs) =/= 2) orelse (not lists:member(element(1,Op_KVs), [append,prepend,rm]))], {true, [{Op,normalize_mod_algs(KVs,false)} || {Op,KVs} <- M]}; check_modify_algorithms(_) -> @@ -1078,11 +1103,11 @@ normalize_mod_algs([K|Ks], KVs0, Acc, UseDefaultAlgs) -> normalize_mod_algs(Ks, KVs, [{K,Vs} | Acc], UseDefaultAlgs); normalize_mod_algs([], [], Acc, _) -> %% No values left in the key-value list after removing the expected entries - %% (thats good) + %% (that's good) lists:reverse(Acc); normalize_mod_algs([], [{K,_}|_], _, _) -> %% Some values left in the key-value list after removing the expected entries - %% (thats bad) + %% (that's bad) case ssh_transport:algo_class(K) of true -> error_in_check(K, "Duplicate key"); false -> error_in_check(K, "Unknown key") @@ -1165,7 +1190,7 @@ check_input_ok(Algs) -> [error_in_check(KVs, "Bad preferred_algorithms") || KVs <- Algs, not is_tuple(KVs) - orelse (size(KVs) =/= 2)]. + orelse (tuple_size(KVs) =/= 2)]. %%%---------------------------------------------------------------- final_preferred_algorithms(Options0) -> diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl index 6339f13cadaf..87d32ccfb0d1 100644 --- a/lib/ssh/src/ssh_server_channel.erl +++ b/lib/ssh/src/ssh_server_channel.erl @@ -25,7 +25,7 @@ -module(ssh_server_channel). -%% API to server side channel that can be pluged into the erlang ssh daemeon +%% API to server side channel that can be plugged into the erlang ssh daemeon -callback init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | {stop, Reason :: term()} | ignore. diff --git a/lib/ssh/src/ssh_server_key_api.erl b/lib/ssh/src/ssh_server_key_api.erl index addf46ef78e1..d668c8f61b61 100644 --- a/lib/ssh/src/ssh_server_key_api.erl +++ b/lib/ssh/src/ssh_server_key_api.erl @@ -29,7 +29,7 @@ %%% The option key_cb_private is to pass options needed by other %%% callback modules than the default ssh_file.erl %%% -%%% If ssh:deamon(n, [ {key_cb_private, {hi,{there}}} ] +%%% If ssh:daemon(n, [ {key_cb_private, {hi,{there}}} ] %%% is called, the term() will be {hi,{there}} -type daemon_key_cb_options(T) :: [{key_cb_private,[T]} | ssh:daemon_option()]. diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index c91f9d67ee6f..bd3111965469 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -58,9 +58,9 @@ -record(state, { xf, - rep_buf = <<>>, + rep_buf = <<>> :: binary(), req_id, - req_list = [], %% {ReqId, Fun} + req_list = [], %% {ReqId, Fun} inf, %% list of fileinf, opts }). @@ -75,14 +75,14 @@ -record(bufinf, { - mode, % read | write (=from or to buffer by user) - crypto_state, + mode :: read | write, % read | write (=from or to buffer by user) + crypto_state :: term() | undefined, crypto_fun, % For encode or decode depending on the mode field - size = 0, % # bytes "before" the current buffer for the postion call + size = 0 :: non_neg_integer() | undefined, % # bytes "before" the current buffer for the position call - chunksize, % The size of the chunks to be sent or received - enc_text_buf = <<>>, % Encrypted text - plain_text_buf = <<>> % Decrypted text + chunksize :: non_neg_integer() | undefined, % The size of the chunks to be sent or received + enc_text_buf = <<>> :: binary() | undefined, % Encrypted text + plain_text_buf = <<>> :: binary() | undefined % Decrypted text }). -define(FILEOP_TIMEOUT, infinity). @@ -121,7 +121,7 @@ start_channel(Dest) -> %%% function clauses. -spec start_channel(ssh:open_socket(), - [ssh:client_options() | sftp_option()] + [ssh:client_option() | sftp_option()] ) -> {ok,pid(),ssh:connection_ref()} | {error,reason()}; @@ -131,7 +131,7 @@ start_channel(Dest) -> -> {ok,pid()} | {ok,pid(),ssh:connection_ref()} | {error,reason()}; (ssh:host(), - [ssh:client_options() | sftp_option()] + [ssh:client_option() | sftp_option()] ) -> {ok,pid(),ssh:connection_ref()} | {error,reason()} . @@ -816,7 +816,7 @@ write_file(Pid, Name, Bin, FileOpTimeout) -> case open(Pid, Name, [write, binary], FileOpTimeout) of {ok, Handle} -> {ok,{_Window,Packet}} = send_window(Pid, FileOpTimeout), - Res = write_file_loop(Pid, Handle, 0, Bin, size(Bin), Packet, + Res = write_file_loop(Pid, Handle, 0, Bin, byte_size(Bin), Packet, FileOpTimeout), close(Pid, Handle, FileOpTimeout), Res; @@ -1017,7 +1017,7 @@ do_handle_call({pwrite,Async,Handle,At,Data0}, From, State) -> {ok,Offset} -> Data = to_bin(Data0), ReqID = State#state.req_id, - Size = size(Data), + Size = byte_size(Data), ssh_xfer:write(?XF(State),ReqID,Handle,Offset,Data), State1 = update_size(Handle, Offset+Size, State), make_reply(ReqID, Async, From, State1); @@ -1030,7 +1030,7 @@ do_handle_call({write,Async,Handle,Data0}, From, State) -> {ok,Offset} -> Data = to_bin(Data0), ReqID = State#state.req_id, - Size = size(Data), + Size = byte_size(Data), ssh_xfer:write(?XF(State),ReqID,Handle,Offset,Data), State1 = update_offset(Handle, Offset+Size, State), make_reply(ReqID, Async, From, State1); @@ -1224,7 +1224,7 @@ terminate(_Reason, State) -> %% Internal functions %%==================================================================== legacy_timeout(UserOptions) -> - %% Make both connect_timeout and timeout defined if exaclty one of them is defined: + %% Make both connect_timeout and timeout defined if exactly one of them is defined: case {proplists:get_value(connect_timeout, UserOptions), proplists:get_value(timeout, UserOptions)} of {undefined, undefined} -> @@ -1582,7 +1582,7 @@ erase_handle(Handle, State) -> State#state{inf = FI}. %% -%% Caluclate a integer offset +%% Calculate a integer offset %% lseek_position(Handle, Pos, State) -> case maps:find(Handle, State#state.inf) of @@ -1640,7 +1640,7 @@ read_repeat(Pid, Handle, Len, FileOpTimeout) -> read_rpt(Pid, Handle, WantedLen, PacketSz, FileOpTimeout, Acc) when WantedLen > 0 -> case read(Pid, Handle, min(WantedLen,PacketSz), FileOpTimeout) of {ok, Data} -> - read_rpt(Pid, Handle, WantedLen-size(Data), PacketSz, FileOpTimeout, <>); + read_rpt(Pid, Handle, WantedLen-byte_size(Data), PacketSz, FileOpTimeout, <>); eof -> {ok, Acc}; Error -> @@ -1654,7 +1654,7 @@ write_to_remote_tar(_Pid, _SftpHandle, <<>>, _FileOpTimeout) -> ok; write_to_remote_tar(Pid, SftpHandle, Bin, FileOpTimeout) -> {ok,{_Window,Packet}} = send_window(Pid, FileOpTimeout), - write_file_loop(Pid, SftpHandle, 0, Bin, size(Bin), Packet, FileOpTimeout). + write_file_loop(Pid, SftpHandle, 0, Bin, byte_size(Bin), Packet, FileOpTimeout). position_buf(Pid, SftpHandle, BufHandle, Pos, FileOpTimeout) -> {ok,#bufinf{mode = Mode, @@ -1662,7 +1662,7 @@ position_buf(Pid, SftpHandle, BufHandle, Pos, FileOpTimeout) -> size = Size}} = call(Pid, {get_bufinf,BufHandle}, FileOpTimeout), case Pos of {cur,0} when Mode==write -> - {ok,Size+size(Buf0)}; + {ok,Size+byte_size(Buf0)}; {cur,0} when Mode==read -> {ok,Size}; @@ -1707,7 +1707,7 @@ read_buf(Pid, SftpHandle, BufHandle, WantedLen, FileOpTimeout) -> do_the_read_buf(_Pid, _SftpHandle, WantedLen, _Packet, _FileOpTimeout, B=#bufinf{plain_text_buf=PlainBuf0, size = Size}) - when size(PlainBuf0) >= WantedLen -> + when byte_size(PlainBuf0) >= WantedLen -> %% We already have the wanted number of bytes decoded and ready! <> = PlainBuf0, {ok,ResultBin,B#bufinf{plain_text_buf=PlainBuf, @@ -1718,8 +1718,8 @@ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, enc_text_buf = EncBuf0, chunksize = undefined }) - when size(EncBuf0) > 0 -> - %% We have (at least) one decodable byte waiting for decodeing. + when byte_size(EncBuf0) > 0 -> + %% We have (at least) one decodable byte waiting for decoding. {ok,DecodedBin,B} = apply_crypto(EncBuf0, B0), do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, B#bufinf{plain_text_buf = <>, @@ -1731,8 +1731,8 @@ do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, enc_text_buf = EncBuf0, chunksize = ChunkSize0 }) - when size(EncBuf0) >= ChunkSize0 -> - %% We have (at least) one chunk of decodable bytes waiting for decodeing. + when byte_size(EncBuf0) >= ChunkSize0 -> + %% We have (at least) one chunk of decodable bytes waiting for decoding. <> = EncBuf0, {ok,DecodedBin,B} = apply_crypto(ToDecode, B0), do_the_read_buf(Pid, SftpHandle, WantedLen, Packet, FileOpTimeout, @@ -1768,7 +1768,7 @@ write_buf(Pid, SftpHandle, BufHandle, PlainBin, FileOpTimeout) -> do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout, B=#bufinf{enc_text_buf = EncBuf0, size = Size}) - when size(EncBuf0) >= Packet -> + when byte_size(EncBuf0) >= Packet -> <> = EncBuf0, case write(Pid, SftpHandle, BinToWrite, FileOpTimeout) of ok -> @@ -1783,7 +1783,7 @@ do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout, B0=#bufinf{plain_text_buf = PlainBuf0, enc_text_buf = EncBuf0, chunksize = undefined}) - when size(PlainBuf0) > 0 -> + when byte_size(PlainBuf0) > 0 -> {ok,EncodedBin,B} = apply_crypto(PlainBuf0, B0), do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout, B#bufinf{plain_text_buf = <<>>, @@ -1794,7 +1794,7 @@ do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout, enc_text_buf = EncBuf0, chunksize = ChunkSize0 }) - when size(PlainBuf0) >= ChunkSize0 -> + when byte_size(PlainBuf0) >= ChunkSize0 -> <> = PlainBuf0, {ok,EncodedBin,B} = apply_crypto(ToEncode, B0), do_the_write_buf(Pid, SftpHandle, Packet, FileOpTimeout, diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index 27b97716ebde..c86ed2cb8199 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -102,7 +102,7 @@ init(Options) -> %% Get the root of the file system (symlinks must be followed, %% otherwise the realpath call won't work). But since symbolic links - %% isn't supported on all plattforms we have to use the root property + %% isn't supported on all platforms we have to use the root property %% supplied by the user. {Root, State} = case resolve_symlinks(Root0, diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl index bd11afa080cb..4ab11487a913 100644 --- a/lib/ssh/src/ssh_shell.erl +++ b/lib/ssh/src/ssh_shell.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2020. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -26,7 +26,7 @@ -include("ssh_connect.hrl"). %%% As this is an user interactive client it behaves like a daemon -%%% channel inspite of it being a client. +%%% channel in spite of it being a client. -behaviour(ssh_server_channel). %% ssh_server_channel callbacks diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl index 728a10974c9e..ed27dc52b2d9 100644 --- a/lib/ssh/src/ssh_system_sup.erl +++ b/lib/ssh/src/ssh_system_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -39,7 +39,9 @@ get_daemon_listen_address/1, addresses/1, addresses/2, - get_options/2 + get_options/2, + get_acceptor_options/1, + replace_acceptor_options/2 ]). %% Supervisor callback @@ -122,7 +124,7 @@ start_subsystem(Role, Address=#address{}, Socket, Options0) -> {error,Error}; error:timeout -> %% The connection was started, but the takover procedure timed out, - %% therefor it exists a subtree, but it is not quite ready and + %% therefore it exists a subtree, but it is not quite ready and %% must be removed (by the supervisor above): supervisor:terminate_child(SysPid, Id), {error, connection_start_timeout} @@ -151,6 +153,32 @@ addresses(Role, #address{address=Address, port=Port, profile=Profile}) -> Port == any orelse A#address.port == Port, Profile == any orelse A#address.profile == Profile]. +%%%---------------------------------------------------------------- +%% SysPid is the DaemonRef + +get_acceptor_options(SysPid) -> + case get_daemon_listen_address(SysPid) of + {ok,Address} -> + get_options(SysPid, Address); + {error,Error} -> + {error,Error} + end. + +replace_acceptor_options(SysPid, NewOpts) -> + case get_daemon_listen_address(SysPid) of + {ok,Address} -> + try stop_listener(SysPid) + of + ok -> + restart_acceptor(SysPid, Address, NewOpts) + catch + error:_ -> + restart_acceptor(SysPid, Address, NewOpts) + end; + {error,Error} -> + {error,Error} + end. + %%%========================================================================= %%% Supervisor callback %%%========================================================================= @@ -219,7 +247,7 @@ find_system_sup(Role, Address0) -> case addresses(Role, Address0) of [{SysSupPid,Address}] -> {ok,{SysSupPid,Address}}; [] -> {error,not_found}; - [_,_|_] -> {error,ambigous} + [_,_|_] -> {error,ambiguous} end. sup(client) -> sshc_sup; diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index 836993c27820..c0b46b338bed 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -49,7 +49,6 @@ handle_kex_ecdh_init/2, handle_kex_ecdh_reply/2, parallell_gen_key/1, - extract_public_key/1, ssh_packet/2, pack/2, valid_key_sha_alg/3, sign/3, sign/4, @@ -62,6 +61,8 @@ -behaviour(ssh_dbg). -export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]). +-define(MIN_DH_KEY_SIZE, 400). + %%% For test suites -export([pack/3, adjust_algs_for_peer_version/2]). @@ -558,7 +559,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, {Public, Private} = generate_key(dh, [P,G,2*Sz]), K = compute_key(dh, E, Private, [P,G]), MyPrivHostKey = get_host_key(SignAlg, Opts), - MyPubHostKey = extract_public_key(MyPrivHostKey), + MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey), H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {E,Public,K}), case sign(H, SignAlg, MyPrivHostKey, Ssh0) of {ok,H_SIG} -> @@ -710,7 +711,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E}, if 1 MyPrivHostKey = get_host_key(SignAlg, Opts), - MyPubHostKey = extract_public_key(MyPrivHostKey), + MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey), H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}), case sign(H, SignAlg, MyPrivHostKey, Ssh0) of {ok,H_SIG} -> @@ -793,7 +794,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic}, of K -> MyPrivHostKey = get_host_key(SignAlg, Opts), - MyPubHostKey = extract_public_key(MyPrivHostKey), + MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey), H = kex_hash(Ssh0, MyPubHostKey, sha(Curve), {PeerPublic, MyPublic, K}), case sign(H, SignAlg, MyPrivHostKey, Ssh0) of {ok,H_SIG} -> @@ -931,37 +932,6 @@ call_KeyCb(F, Args, Opts) -> UserOpts = ?GET_OPT(key_cb_options, Opts), apply(KeyCb, F, Args ++ [[{key_cb_private,KeyCbOpts}|UserOpts]]). -extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) -> - #'RSAPublicKey'{modulus = N, publicExponent = E}; -extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) -> - {Y, #'Dss-Parms'{p=P, q=Q, g=G}}; -extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID}, - publicKey = Pub0, privateKey = Priv}) when - OID == ?'id-Ed25519'orelse - OID == ?'id-Ed448' -> - case {pubkey_cert_records:namedCurves(OID), Pub0} of - {Alg, asn1_NOVALUE} -> - %% If we're missing the public key, we can create it with - %% the private key. - {Pub, Priv} = crypto:generate_key(eddsa, Alg, Priv), - {ed_pub, Alg, Pub}; - {Alg, Pub} -> - {ed_pub, Alg, Pub} - end; -extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID}, - publicKey = Q}) when is_tuple(OID) -> - {#'ECPoint'{point=Q}, {namedCurve,OID}}; -extract_public_key({ed_pri, Alg, Pub, _Priv}) -> - {ed_pub, Alg, Pub}; -extract_public_key(#{engine:=_, key_id:=_, algorithm:=Alg} = M) -> - case {Alg, crypto:privkey_to_pubkey(Alg, M)} of - {rsa, [E,N]} -> - #'RSAPublicKey'{modulus = N, publicExponent = E}; - {dss, [P,Q,G,Y]} -> - {Y, #'Dss-Parms'{p=P, q=Q, g=G}} - end. - - verify_host_key(#ssh{algorithms=Alg}=SSH, PublicKey, Digest, {AlgStr,Signature}) -> case atom_to_list(Alg#alg.hkey) of @@ -1279,8 +1249,8 @@ alg_final(rcv, SSH0) -> select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS -> - %% algortihms only used by client - %% NOTE: an algorithm occuring more than once in CL will still be present + %% algorithms only used by client + %% NOTE: an algorithm occurring more than once in CL will still be present %% in CLonly. This is not a problem for nice clients. CLonly = CL -- SL, @@ -1340,9 +1310,9 @@ pack(common, rfc4253, PlainText, DeltaLenTst, #ssh{send_sequence = SeqNum, send_mac = MacAlg, send_mac_key = MacKey} = Ssh0) -> - PadLen = padding_length(4+1+size(PlainText), Ssh0), + PadLen = padding_length(4+1+byte_size(PlainText), Ssh0), Pad = ssh_bits:random(PadLen), - TextLen = 1 + size(PlainText) + PadLen + DeltaLenTst, + TextLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst, PlainPkt = <>, {Ssh1, CipherPkt} = encrypt(Ssh0, PlainPkt), MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPkt), @@ -1353,9 +1323,9 @@ pack(common, enc_then_mac, PlainText, DeltaLenTst, #ssh{send_sequence = SeqNum, send_mac = MacAlg, send_mac_key = MacKey} = Ssh0) -> - PadLen = padding_length(1+size(PlainText), Ssh0), + PadLen = padding_length(1+byte_size(PlainText), Ssh0), Pad = ssh_bits:random(PadLen), - PlainLen = 1 + size(PlainText) + PadLen + DeltaLenTst, + PlainLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst, PlainPkt = <>, {Ssh1, CipherPkt} = encrypt(Ssh0, PlainPkt), EncPacketPkt = <>, @@ -1363,9 +1333,9 @@ pack(common, enc_then_mac, PlainText, DeltaLenTst, {<>, Ssh1}; pack(aead, _, PlainText, DeltaLenTst, Ssh0) -> - PadLen = padding_length(1+size(PlainText), Ssh0), + PadLen = padding_length(1+byte_size(PlainText), Ssh0), Pad = ssh_bits:random(PadLen), - PlainLen = 1 + size(PlainText) + PadLen + DeltaLenTst, + PlainLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst, PlainPkt = <>, {Ssh1, {CipherPkt,MAC0}} = encrypt(Ssh0, <>), {<>, Ssh1}. @@ -1392,7 +1362,7 @@ handle_packet_part(<<>>, Encrypted0, AEAD0, undefined, #ssh{decrypt = CryptoAlg, end; handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0) - when (size(DecryptedPfx)+size(EncryptedBuffer)) < TotalNeeded -> + when (byte_size(DecryptedPfx)+byte_size(EncryptedBuffer)) < TotalNeeded -> %% need more bytes to finalize the packet {get_more, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0}; @@ -1411,7 +1381,7 @@ handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, #ssh{decryp %%%---------------- unpack(common, rfc4253, DecryptedPfx, EncryptedBuffer, _AEAD, TotalNeeded, #ssh{recv_mac_size = MacSize} = Ssh0) -> - MoreNeeded = TotalNeeded - size(DecryptedPfx) - MacSize, + MoreNeeded = TotalNeeded - byte_size(DecryptedPfx) - MacSize, <> = EncryptedBuffer, {Ssh1, DecryptedSfx} = decrypt(Ssh0, EncryptedSfx), PlainPkt = <>, @@ -1428,7 +1398,7 @@ unpack(common, enc_then_mac, <>, EncryptedBuffer, _AEAD, _Tot case is_valid_mac(MAC0, <>, Ssh0) of true -> {Ssh1, <>} = decrypt(Ssh0, Payload), - CompressedPlainTextLen = size(PlainRest) - PaddingLen, + CompressedPlainTextLen = byte_size(PlainRest) - PaddingLen, <> = PlainRest, {ok, CompressedPlainText, NextPacketBytes, Ssh1}; false -> @@ -1438,7 +1408,7 @@ unpack(common, enc_then_mac, <>, EncryptedBuffer, _AEAD, _Tot unpack(aead, _, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, #ssh{recv_mac_size = MacSize} = Ssh0) -> %% enough bytes to decode the packet. - MoreNeeded = TotalNeeded - size(DecryptedPfx) - MacSize, + MoreNeeded = TotalNeeded - byte_size(DecryptedPfx) - MacSize, <> = EncryptedBuffer, case decrypt(Ssh0, {AEAD,EncryptedSfx,Mac}) of {Ssh1, error} -> @@ -1450,7 +1420,7 @@ unpack(aead, _, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, %%%---------------------------------------------------------------- get_length(common, rfc4253, EncryptedBuffer, #ssh{decrypt_block_size = BlockSize} = Ssh0) -> - case size(EncryptedBuffer) >= erlang:max(8, BlockSize) of + case byte_size(EncryptedBuffer) >= erlang:max(8, BlockSize) of true -> <> = EncryptedBuffer, {Ssh, @@ -1470,7 +1440,7 @@ get_length(common, enc_then_mac, EncryptedBuffer, Ssh) -> end; get_length(aead, _, EncryptedBuffer, Ssh) -> - case {size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of + case {byte_size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of {true, 'chacha20-poly1305@openssh.com'} -> <> = EncryptedBuffer, {Ssh1, PacketLenBin} = decrypt(Ssh, {length,EncryptedLen}), @@ -1551,7 +1521,7 @@ do_verify(PlainText, HashAlg, Sig, {_, #'Dss-Parms'{}} = Key, _) -> _ -> false end; -do_verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key, _) -> +do_verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key, _) when HashAlg =/= undefined -> case Sig of <> -> @@ -2066,40 +2036,27 @@ valid_key_sha_alg(private, #'RSAPrivateKey'{}, 'ssh-rsa' ) -> true; valid_key_sha_alg(public, {_, #'Dss-Parms'{}}, 'ssh-dss') -> true; valid_key_sha_alg(private, #'DSAPrivateKey'{}, 'ssh-dss') -> true; -valid_key_sha_alg(public, {ed_pub, ed25519,_}, 'ssh-ed25519') -> true; -valid_key_sha_alg(private, {ed_pri, ed25519,_,_},'ssh-ed25519') -> true; -valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}},'ssh-ed25519') when OID == ?'id-Ed25519' -> true; -valid_key_sha_alg(public, {ed_pub, ed448,_}, 'ssh-ed448') -> true; -valid_key_sha_alg(private, {ed_pri, ed448,_,_}, 'ssh-ed448') -> true; -valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}},'ssh-ed448') when OID == ?'id-Ed448' -> true; - -valid_key_sha_alg(public, {#'ECPoint'{},{namedCurve,OID}}, Alg) when is_tuple(OID) -> +valid_key_sha_alg(public, {#'ECPoint'{},{namedCurve,OID}}, Alg) -> valid_key_sha_alg_ec(OID, Alg); -valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) when is_tuple(OID) -> +valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) -> valid_key_sha_alg_ec(OID, Alg); valid_key_sha_alg(_, _, _) -> false. - -valid_key_sha_alg_ec(OID, Alg) -> - try - Curve = public_key:oid2ssh_curvename(OID), - Alg == list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(Curve)) - catch - _:_ -> false - end. + + +valid_key_sha_alg_ec(OID, Alg) when is_tuple(OID) -> + {SshCurveType, _} = ssh_message:oid2ssh_curvename(OID), + Alg == binary_to_atom(SshCurveType); +valid_key_sha_alg_ec(_, _) -> false. + -dialyzer({no_match, public_algo/1}). public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa'; % FIXME: Not right with draft-curdle-rsa-sha2 public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss'; -public_algo({ed_pub, ed25519,_}) -> 'ssh-ed25519'; -public_algo({ed_pub, ed448,_}) -> 'ssh-ed448'; public_algo({#'ECPoint'{},{namedCurve,OID}}) when is_tuple(OID) -> - SshName = public_key:oid2ssh_curvename(OID), - try list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(SshName)) - catch - _:_ -> undefined - end. + {SshCurveType, _} = ssh_message:oid2ssh_curvename(OID), + binary_to_atom(SshCurveType). sha('ssh-rsa') -> sha; @@ -2184,10 +2141,10 @@ parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}}, Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}. -generate_key(ecdh = Algorithm, Args) -> - crypto:generate_key(Algorithm, Args); -generate_key(Algorithm, Args) -> - {Public,Private} = crypto:generate_key(Algorithm, Args), +generate_key(ecdh, Args) -> + crypto:generate_key(ecdh, Args); +generate_key(dh, [P,G,Sz2]) -> + {Public,Private} = crypto:generate_key(dh, [P, G, max(Sz2,?MIN_DH_KEY_SIZE)] ), {crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}. diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl index f424a4ff63c3..009d85cb79e4 100644 --- a/lib/ssh/src/ssh_transport.hrl +++ b/lib/ssh/src/ssh_transport.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2018. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -20,7 +20,7 @@ %% %%---------------------------------------------------------------------- -%% Purpose: Record and constant defenitions for the SSH-tansport layer +%% Purpose: Record and constant definitions for the SSH-tansport layer %% protocol see RFC 4253 %%---------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl index 212798f2d7f4..4656ab5219e2 100644 --- a/lib/ssh/src/ssh_xfer.erl +++ b/lib/ssh/src/ssh_xfer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -242,7 +242,7 @@ xf_request(XF, Op, Arg) -> is_list(Arg) -> ?to_binary(Arg) end, - Size = 1+size(Data), + Size = 1+byte_size(Data), ssh_connection:send(CM, Channel, [<>]). xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) -> @@ -252,7 +252,7 @@ xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) -> is_list(Arg) -> ?to_binary(Arg) end, - Size = 1 + size(Data), + Size = 1 + byte_size(Data), ssh_connection:send(CM, Channel, [<>]). xf_send_name(XF, ReqId, Name, Attr) -> @@ -290,7 +290,7 @@ xf_send_status(#ssh_xfer{cm = CM, channel = Channel}, LangTag = "en", ELen = length(ErrorMsg), TLen = 2, %% length(LangTag), - Size = 1 + 4 + 4 + 4+ELen + 4+TLen + size(Data), + Size = 1 + 4 + 4 + 4+ELen + 4+TLen + byte_size(Data), ToSend = [<>, <>, ErrorMsg, @@ -300,13 +300,13 @@ xf_send_status(#ssh_xfer{cm = CM, channel = Channel}, xf_send_attr(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn}, ReqId, Attr) -> EncAttr = encode_ATTR(Vsn, Attr), - ALen = size(EncAttr), + ALen = byte_size(EncAttr), Size = 1 + 4 + ALen, ToSend = [<>, EncAttr], ssh_connection:send(CM, Channel, ToSend). xf_send_data(#ssh_xfer{cm = CM, channel = Channel}, ReqId, Data) -> - DLen = size(Data), + DLen = byte_size(Data), Size = 1 + 4 + 4+DLen, ToSend = [<>, Data], @@ -815,21 +815,21 @@ encode_name(Vsn, {{NameUC,LongNameUC},Attr}, Len) when Vsn =< 3 -> LongName = binary_to_list(unicode:characters_to_binary(LongNameUC)), LNLen = length(LongName), EncAttr = encode_ATTR(Vsn, Attr), - ALen = size(EncAttr), + ALen = byte_size(EncAttr), NewLen = Len + NLen + LNLen + 4 + 4 + ALen, {[<>, Name, <>, LongName, EncAttr], NewLen}; encode_name(Vsn, {NameUC,Attr}, Len) when Vsn =< 3 -> Name = binary_to_list(unicode:characters_to_binary(NameUC)), NLen = length(Name), EncAttr = encode_ATTR(Vsn, Attr), - ALen = size(EncAttr), + ALen = byte_size(EncAttr), NewLen = Len + NLen*2 + 4 + 4 + ALen, {[<>, Name, <>, Name, EncAttr], NewLen}; encode_name(Vsn, {NameUC,Attr}, Len) when Vsn >= 4 -> Name = binary_to_list(unicode:characters_to_binary(NameUC)), NLen = length(Name), EncAttr = encode_ATTR(Vsn, Attr), - ALen = size(EncAttr), + ALen = byte_size(EncAttr), {[<>, Name, EncAttr], Len + 4 + NLen + ALen}. diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl index 07467c474b33..bc2e1fa20ce1 100644 --- a/lib/ssh/src/ssh_xfer.hrl +++ b/lib/ssh/src/ssh_xfer.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -226,7 +226,7 @@ -record(ssh_xfer_attr, { - type, %% regular, dirctory, symlink, ... + type, %% regular, directory, symlink, ... size, owner, group, diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile index 54d20cf8dbea..1e33d0151df7 100644 --- a/lib/ssh/test/Makefile +++ b/lib/ssh/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2021. All Rights Reserved. +# Copyright Ericsson AB 2004-2023. 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. @@ -32,6 +32,7 @@ MODULES= \ ssh_basic_SUITE \ ssh_bench_SUITE \ ssh_chan_behaviours_SUITE \ + ssh_collect_labmachine_info_SUITE \ ssh_compat_SUITE \ ssh_connection_SUITE \ ssh_agent_mock_server \ @@ -98,6 +99,7 @@ RELSYSDIR = $(RELEASE_PATH)/ssh_test INCLUDES = -I$(ERL_TOP)/lib/ssh/src ERL_COMPILE_FLAGS += $(INCLUDES) -pa ../ebin +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -105,7 +107,7 @@ EBIN = . # Targets # ---------------------------------------------------- -tests debug opt: emakebuild $(TARGET_FILES) +tests $(TYPES): emakebuild $(TARGET_FILES) .PHONY: emakebuild diff --git a/lib/ssh/test/property_test/ssh_eqc_client_server.erl b/lib/ssh/test/property_test/ssh_eqc_client_server.erl index 4bfc23d5ff30..432fc87900c0 100644 --- a/lib/ssh/test/property_test/ssh_eqc_client_server.erl +++ b/lib/ssh/test/property_test/ssh_eqc_client_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -299,7 +299,7 @@ do(Pid, Fun, Timeout) when is_function(Fun,0) -> %%%---------------- %%% Start a new connection -%%% Precondition: deamon exists +%%% Precondition: daemon exists ssh_open_connection_pre(S) -> S#state.servers /= []. diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl index 843a2b5a3ca8..b34d36dfdb2d 100644 --- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl +++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -250,7 +250,7 @@ msg_code(Num) -> Name -include_lib("ssh/src/ssh_connect.hrl"). -include_lib("ssh/src/ssh_transport.hrl"). -%%% Encoding and decodeing is asymetric so out=binary in=string. Sometimes. :( +%%% Encoding and decoding is asymmetric so out=binary in=string. Sometimes. :( -define(fix_asym_Xdh_reply(S), fix_asym(#S{public_host_key = Key, h_sig = {Alg,Sig}} = M) -> M#S{public_host_key = {Key, list_to_atom(Alg)}, h_sig = Sig} diff --git a/lib/ssh/test/ssh_agent_mock_server.erl b/lib/ssh/test/ssh_agent_mock_server.erl index 026bc30812c3..f68239325223 100644 --- a/lib/ssh/test/ssh_agent_mock_server.erl +++ b/lib/ssh/test/ssh_agent_mock_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -149,7 +149,7 @@ check_mktemp(Config) -> end. extract_pubkey(PrivKey) -> - PubKey = ssh_transport:extract_public_key(PrivKey), + PubKey = ssh_file:extract_public_key(PrivKey), ssh_message:ssh2_pubkey_encode(PubKey). sig_format('ssh-rsa') -> <<"ssh-rsa">>; diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 0c6bb4365fe1..bcf4c7f859e1 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -22,6 +22,7 @@ -module(ssh_basic_SUITE). +-include_lib("public_key/include/public_key.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/file.hrl"). @@ -73,6 +74,7 @@ login_bad_pwd_no_retry3/1, login_bad_pwd_no_retry4/1, login_bad_pwd_no_retry5/1, + max_initial_idle_time/1, misc_ssh_options/1, multi_daemon_opt_fd/1, openssh_zlib_basic_test/1, @@ -154,7 +156,9 @@ groups() -> exec, exec_compressed, exec_with_io_out, exec_with_io_in, cli, cli_exit_normal, cli_exit_status, - idle_time_client, idle_time_server, openssh_zlib_basic_test, + idle_time_client, idle_time_server, + max_initial_idle_time, + openssh_zlib_basic_test, misc_ssh_options, inet_option, inet6_option, shell, shell_socket, shell_ssh_conn, shell_no_unicode, shell_unicode_string, close @@ -251,7 +255,7 @@ appup_test(Config) when is_list(Config) -> %%-------------------------------------------------------------------- %%% Test that we can set some misc options not tested elsewhere %%% some options not yet present are not decided if we should support or -%%% if they need thier own test case. +%%% if they need their own test case. misc_ssh_options(Config) when is_list(Config) -> SystemDir = filename:join(proplists:get_value(priv_dir, Config), system), UserDir = proplists:get_value(priv_dir, Config), @@ -470,6 +474,25 @@ idle_time_common(DaemonExtraOpts, ClientExtraOpts, Config) -> end, ssh:stop_daemon(Pid). +%%-------------------------------------------------------------------- +max_initial_idle_time(Config) -> + SystemDir = filename:join(proplists:get_value(priv_dir, Config), system), + UserDir = proplists:get_value(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}, + {max_initial_idle_time, 2000} + ]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false} + ]), + timer:sleep(8000), + {error, closed} = ssh_connection:session_channel(ConnectionRef, 1000), + ssh:stop_daemon(Pid). + %%-------------------------------------------------------------------- %%% Test that ssh:shell/2 works shell(Config) when is_list(Config) -> @@ -520,7 +543,7 @@ shell_socket(Config) when is_list(Config) -> ct:log("~p:~p udp socket failed ok", [?MODULE,?LINE]), gen_udp:close(BadSock), - %% And finaly test with passive mode (which should work): + %% And finally test with passive mode (which should work): IO = ssh_test_lib:start_io_server(), {ok,Sock} = gen_tcp:connect(Host, Port, [{active,false}]), Shell = ssh_test_lib:start_shell(Sock, IO, [{user_dir,UserDir}]), @@ -659,7 +682,7 @@ cli_exit_status(Config) when is_list(Config) -> %%-------------------------------------------------------------------- %%% Test that get correct error message if you try to start a daemon -%%% on an adress that already runs a daemon see also seq10667 +%%% on an address that already runs a daemon see also seq10667 daemon_already_started(Config) when is_list(Config) -> SystemDir = proplists:get_value(data_dir, Config), UserDir = proplists:get_value(priv_dir, Config), @@ -783,12 +806,14 @@ ssh_file_is_host_key(Config) -> ct:log("Dir = ~p", [Dir]), KnownHosts = filename:join(Dir, "known_hosts"), - Key1 = {ed_pub,ed25519,<<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, - 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, - Key2 = {ed_pub,ed448,<<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, - 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, - 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, - 190,175,232,37,97,128>>}, + Key1 = {#'ECPoint'{point = <<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, + 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, + {namedCurve,?'id-Ed25519'}}, + Key2 = {#'ECPoint'{point = <<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, + 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, + 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, + 190,175,232,37,97,128>>}, + {namedCurve,?'id-Ed448'}}, Key3 = {'RSAPublicKey',26565213557098441060571713941539431805641814292761836797158846333985276408616038302348064841541244792430014595960643885863857366044141899534486816837416587694213836843799730043696945690516841209754307951050689906601353687467659852190777927968674989320642319504162787468947018505175948989102544757855693228490011564030927714896252701919941617689227585365348356580525802093985552564228730275431222515673065363441446158870936027338182083252824862151536327733046243804704721201548991176621134884093279416695997338124856506800535228380202243308550318880784741179703553922258881924287662178348044420509921666661119986374777, 65537}, @@ -831,13 +856,14 @@ ssh_file_is_host_key_misc(Config) -> ct:log("Dir = ~p", [Dir]), KnownHosts = filename:join(Dir, "known_hosts"), - Key1 = {ed_pub,ed25519,<<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, - 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, - Key2 = {ed_pub,ed448,<<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, - 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, - 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, - 190,175,232,37,97,128>>}, - + Key1 = {#'ECPoint'{point = <<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, + 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, + {namedCurve,?'id-Ed25519'}}, + Key2 = {#'ECPoint'{point = <<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, + 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, + 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, + 190,175,232,37,97,128>>}, + {namedCurve,?'id-Ed448'}}, FileContents = <<"h11,h12,!h12 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElI66JgZZo72XJ7wGBp+h3WTDw/pxXddvaomAIHrIl9\n", %% Key revoked later in file: "h22 ssh-ed448 AAAACXNzaC1lZDQ0OAAAADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh" @@ -871,13 +897,14 @@ ssh_file_is_auth_key(Config) -> ct:log("Dir = ~p", [Dir]), AuthKeys = filename:join(Dir, "authorized_keys"), - Key1 = {ed_pub,ed25519,<<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, - 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, - Key2 = {ed_pub,ed448,<<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, - 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, - 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, - 190,175,232,37,97,128>>}, - + Key1 = {#'ECPoint'{point = <<73,72,235,162,96,101,154,59,217,114,123,192,96,105,250,29, + 214,76,60,63,167,21,221,118,246,168,152,2,7,172,137,125>>}, + {namedCurve,?'id-Ed25519'}}, + Key2 = {#'ECPoint'{point = <<95,215,68,155,89,180,97,253,44,231,135,236,97,106,212,106,29, + 161,52,36,133,167,14,31,138,14,167,93,128,233,103,120,237,241, + 36,118,155,70,199,6,27,214,120,61,241,229,15,108,209,250,26, + 190,175,232,37,97,128>>}, + {namedCurve,?'id-Ed448'}}, FileContents = <<" \n", "# A test file\n", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElI66JgZZo72XJ7wGBp+h3WTDw/pxXddvaomAIHrIl9 foo@example.com\n", @@ -1204,7 +1231,7 @@ packet_size(Config) -> rec(Server, Conn, Ch, MaxSz) -> receive - {ssh_cm,Conn,{data,Ch,_,M}} when size(M) =< MaxSz -> + {ssh_cm,Conn,{data,Ch,_,M}} when byte_size(M) =< MaxSz -> ct:log("~p: ~p",[MaxSz,M]), rec(Server, Conn, Ch, MaxSz); {ssh_cm,Conn,{data,Ch,_,_}} = M -> @@ -1393,7 +1420,7 @@ login_bad_pwd_no_retry(Config, AuthMethods) -> {ok,Conn} -> ssh:close(Conn), ssh:stop_daemon(DaemonRef), - {fail, "Connect erroneosly succeded"} + {fail, "Connect erroneosly succeeded"} end end. @@ -1465,7 +1492,7 @@ setopts_getopts(Config) -> %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- %% Due to timing the error message may or may not be delivered to -%% the "tcp-application" before the socket closed message is recived +%% the "tcp-application" before the socket closed message is received check_error("Invalid state") -> ok; check_error("Connection closed") -> ok; check_error("Selection of key exchange algorithm failed"++_) -> ok; @@ -1515,7 +1542,7 @@ new_do_shell(IO, N, [new_prompt|More]) -> new_do_shell(IO, N, Ops=[{Order,Arg}|More]) -> Pfx = prompt_prefix(), - PfxSize = size(Pfx), + PfxSize = byte_size(Pfx), receive _X = <<"\r\n">> -> ct:log("Skip newline ~p",[_X]), @@ -1557,7 +1584,8 @@ new_do_shell(IO, N, Ops=[{Order,Arg}|More]) -> ct:log("Matched echo ~ts",[RecStr]), new_do_shell(IO, N, More); false -> - ct:fail("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr]) + ct:log("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr]), + new_do_shell(IO, N, Ops) end after 30000 -> ct:log("Message queue of ~p:~n~p", @@ -1582,7 +1610,7 @@ prompt_prefix() -> new_do_shell_prompt(IO, N, type, Str, More) -> ct:log("Matched prompt ~p to trigger sending of next line to server",[N]), IO ! {input, self(), Str++"\r\n"}, - ct:log("Promt '~p> ', Sent ~ts",[N,Str++"\r\n"]), + ct:log("Prompt '~p> ', Sent ~ts",[N,Str++"\r\n"]), new_do_shell(IO, N, More); new_do_shell_prompt(IO, N, Op, Str, More) -> ct:log("Matched prompt ~p",[N]), diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE.erl b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl index df3791822839..c0ab32512612 100644 --- a/lib/ssh/test/ssh_chan_behaviours_SUITE.erl +++ b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl @@ -104,7 +104,7 @@ end_per_testcase(_TC, Config) -> %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- -%% Try start a subsystem whos name is not known by the server +%% Try start a subsystem whose name is not known by the server noexist_subsystem(Config) -> C = proplists:get_value(connref, Config), {ok, Ch} = ssh_connection:session_channel(C, infinity), @@ -135,7 +135,7 @@ defined_subsystem(Config) -> ?EXPECT({ssh_cm, C, {closed,Ch1}}, []), % self() is instead of a proper channel handler ok. -%% Try to start and stop a subsystem from a ssh_client_channel behviour +%% Try to start and stop a subsystem from a ssh_client_channel behaviour subsystem_client(Config) -> C = proplists:get_value(connref, Config), diff --git a/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl b/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl new file mode 100644 index 000000000000..02b11bde1dca --- /dev/null +++ b/lib/ssh/test/ssh_collect_labmachine_info_SUITE.erl @@ -0,0 +1,250 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2021. 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(ssh_collect_labmachine_info_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-export([save_ssh_data/3]). + +-export([ + suite/0, + all/0, + init_per_suite/1, + end_per_suite/1, + ssh_info_lib/1 + ]). + + +-define(DAYS_TO_KEEP, 5). + +save_ssh_data(Host, Data, Config0) -> + case init_data_transfer(Host, Config0) of + Config1 when is_list(Config1) -> + Config = + case Data of + [[_|_]|_] -> + lists:foldl(fun save_data/2, Config1, Data); + _ -> + save_data(Data, Config1) + end, + end_data_transfer(Config); + + Skip -> + Skip + end. + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +suite() -> [{timetrap,{seconds,40}}]. + +all() -> [ssh_info_lib]. + +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case os:find_executable("ssh") of + false -> + {skip, "No ssh found"}; + + _Path -> + init_data_transfer(hostname(), Config) + end. + +end_per_suite(Config) -> + end_data_transfer(Config). + +%%-------------------------------------------------------------------- +ssh_info_lib(Config) -> + NewEntry = new_entry(), + ct:pal("New entry:~n~p",[NewEntry]), + save_data(NewEntry, Config). + +new_entry() -> + [{hostname, hostname()}, + {type, host}, + {date, date()}, + {time, time()}, + {os_type, os:type()}, + {os_version, os:version()}, + {full_ssh_version, ssh_info()} + ]. + +ssh_info() -> + try os:cmd("ssh -V") of + Version when is_list(Version) -> Version--"\n"; + _ -> "?" + catch + _:_ -> "??" + end. + +%%-------------------------------------------------------------------- +hostname() -> + case inet:gethostname() of + {ok,Name} -> string:to_lower(Name); + _ -> "undefined" + end. + +priv_dir(Config) -> proplists:get_value(priv_dir, Config). + +priv_file(Config, Name) -> filename:join(priv_dir(Config), Name). + +remove_drive_letter(FileName) -> + ssh_test_lib:winpath_to_linuxpath(FileName). + +usable_file(FileName) -> + case file:open(FileName, [append]) of + {ok,D} -> + ok == file:close(D); + _ -> + false + end. + +%%%---------------------------------------------------------------- +wsl_ify(Cmnd) -> + case os:getenv("WSLENV") of + false -> Cmnd; + _ -> "wsl " ++ Cmnd + end. + +%%%================================================================ +save_data(NewEntry, Config) -> + LocalFile = proplists:get_value(local_file, Config), + + YoungEntries = + case file:consult(LocalFile) of + {ok, Consulted} when is_list(Consulted) -> + lists:filter(fun(E) -> is_young(E) end, + Consulted); + Other -> + ct:log("Strange result of consult:~n~p", [Other]), + ct:fail("Consult failed") + end, + + {ok,D} = file:open(LocalFile, [write]), + lists:foreach(fun(E) -> + io:format(D, '~p.~n', [E]) + end, lists:usort([NewEntry|YoungEntries])), + file:close(D), + Config. + + +is_young(E) -> + try + Days = days_ago(proplists:get_value(date, E)), + Days >= 0 andalso Days =< ?DAYS_TO_KEEP + catch + _:_ -> false % No or illegal date property + end. + + +days_ago(D={_,_,_})-> + calendar:date_to_gregorian_days(date()) - calendar:date_to_gregorian_days(D). + +%%%---------------------------------------------------------------- +init_data_transfer(Host, Config) -> + case ct:get_config(collect_host_info) of + undefined -> + {skip, "No 'collect_host_info' path configured"}; + + Root when is_list(Root) -> + RemoteFile = filename:join([Root, "ssh_info", Host++".data"]), + init_data_transfer_cont(Host, Config, RemoteFile) + end. + +init_data_transfer_cont(Host, Config, RemoteFile) -> + LocalFile = priv_file(Config, Host++".sshdata"), + + case usable_file(LocalFile) of + false -> ct:fail(no_local_file); + true -> ok + end, + + TransferType = + case {path_type(RemoteFile), os:type()} of + {local, {unix,_}} -> + case usable_file(RemoteFile) of + true -> filesystem; + false -> ssh + end; + _ -> + ssh + end, + + case TransferType of + filesystem -> + %% 'filesystem' was concluded since it was possible + %% to open the file in append mode + {ok,B} = file:read_file(RemoteFile), + ok = file:write_file(LocalFile, B); + ssh -> + SCP = wsl_ify("scp "++RemoteFile++" "++remove_drive_letter(LocalFile)), + ct:pal("Run command: \"~s\"", [SCP]), + Result = os:cmd(SCP), + ct:pal("Command result: \"~s\"",[Result]) + end, + + [{transfer_type, TransferType}, + {local_file,LocalFile}, + {remote_file,RemoteFile} | Config]. + +%%%---------------------------------------------------------------- +end_data_transfer(Config) -> + LocalFile = proplists:get_value(local_file,Config), + RemoteFile = proplists:get_value(remote_file,Config), + case proplists:get_value(transfer_type,Config) of + filesystem -> + {ok,B} = file:read_file(LocalFile), + ok = file:write_file(RemoteFile, B); + ssh -> + SCP = wsl_ify("scp "++remove_drive_letter(LocalFile)++" "++RemoteFile), + ct:pal("Run command: \"~s\"", [SCP]), + Result = os:cmd(SCP), + ct:pal("Command result: \"~s\"",[Result]) + end, + file:delete(LocalFile). + +path_type(Path) -> + case string:lexemes(Path, ":") of + [_] -> + local; + [Host | _] -> + case string:find(Host, "/") of + nomatch -> remote; + _ -> local + end + end. + + + + + + + + + + + + + + diff --git a/lib/ssh/test/ssh_compat_SUITE.erl b/lib/ssh/test/ssh_compat_SUITE.erl index 56127e98e262..5af304b5b188 100644 --- a/lib/ssh/test/ssh_compat_SUITE.erl +++ b/lib/ssh/test/ssh_compat_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -80,7 +80,7 @@ groups() -> ssh_image_versions() -> try %% Find all useful containers in such a way that undefined command, too low - %% priviliges, no containers and containers found give meaningful result: + %% privileges, no containers and containers found give meaningful result: L0 = ["REPOSITORY"++_|_] = string:tokens(os:cmd("docker images"), "\r\n"), [["REPOSITORY","TAG"|_]|L1] = [string:tokens(E, " ") || E<-L0], [list_to_atom(V) || [?DOCKER_PFX,V|_] <- L1] @@ -100,6 +100,7 @@ init_per_suite(Config) -> {skip, "No docker"}; _ -> ssh:start(), + log_image_versions(ssh_image_versions(), Config), ct:log("Crypto info: ~p",[crypto:info_lib()]), ct:log("ssh image versions: ~p",[ssh_image_versions()]), Config @@ -151,7 +152,7 @@ init_per_group(G, Config0) -> ct:comment("~s",[NewCmnt]) end, AuthMethods = - %% This should be obtained by quering the peer, but that + %% This should be obtained by querying the peer, but that %% is a bit hard. It is possible with ssh_protocol_SUITE %% techniques, but it can wait. case Vssh of @@ -409,7 +410,7 @@ send_recv_big_with_renegotiate_otp_is_client(Config) -> Data = << <> || X <- lists:seq(1, HalfSizeBytes div 4)>>, %% Send the data. Must spawn a process to avoid deadlock. The client will block - %% until all is sent through the send window. But the server will stop receiveing + %% until all is sent through the send window. But the server will stop receiving %% when the servers send-window towards the client is full. %% Since the client can't receive before the server has received all but 655k from the client %% ssh_connection:send/4 is blocking... @@ -875,7 +876,7 @@ new_dir(Config) -> %%-------------------------------------------------------------------- %% -%% Find the intersection of algoritms for otp ssh and the docker ssh. +%% Find the intersection of algorithms for otp ssh and the docker ssh. %% Returns {ok, ServerHello, Server, ClientHello, Client} where Server are the algorithms common %% with the docker server and analogous for Client. %% @@ -1097,7 +1098,7 @@ receive_hello(S, Ack) -> receive_kexinit(_S, <>) - when PacketLen < 5000, % heuristic max len to stop huge attempts if packet decodeing get out of sync + when PacketLen < 5000, % heuristic max len to stop huge attempts if packet decoding get out of sync size(PayloadAndPadding) >= (PacketLen-1) % Need more bytes? -> ct:log("Has all ~p packet bytes",[PacketLen]), @@ -1486,3 +1487,50 @@ renegotiate_test(Kex1, ConnectionRef) -> %% ct:log("Renegotiate test passed!",[]), ok end. + +%%%---------------------------------------------------------------- +%% ImageVersions = ['dropbearv2016.72', +%% 'openssh4.4p1-openssl0.9.8c', +%% ... +%% 'openssh8.8p1-openssl1.1.1l'] + +log_image_versions(ImageVersions, Config) -> + case true == (catch + lists:member({save_ssh_data,3}, + ssh_collect_labmachine_info_SUITE:module_info(exports))) + of + true -> + HostPfx = hostname()++"_docker", + {_Imax, Entries} = lists:foldl(fix_entry(HostPfx), {0,[]}, ImageVersions), + ssh_collect_labmachine_info_SUITE:save_ssh_data(HostPfx, Entries, Config); + false -> + Config + end. + + +fix_entry(HostPfx) -> + fun(E, {I,Acc}) -> + Entry = + [{hostname, lists:flatten(io_lib:format("~s:~2..0w",[HostPfx,I]))}, + {type, compat_test}, + {date, date()}, + {time, time()}, + {os_type, os:type()}, + {os_version, os:version()}, + {full_ssh_version, fix_version(E)} + ], + {I+1, [Entry|Acc]} + end. + +fix_version(E) -> + case string:tokens(atom_to_list(E), "-") of + ["openssh"++Vs, "openssl"++Vc ] -> lists:concat(["OpenSSH_",Vs," OpenSSL ",Vc]); + ["openssh"++Vs, "libressl"++Vc] -> lists:concat(["OpenSSH_",Vs," LibreSSL ",Vc]); + _ -> atom_to_list(E) + end. + +hostname() -> + case inet:gethostname() of + {ok,Name} -> string:to_lower(Name); + _ -> "undefined" + end. diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl index 1e79f0a622b9..06d90cc036a6 100644 --- a/lib/ssh/test/ssh_connection_SUITE.erl +++ b/lib/ssh/test/ssh_connection_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -209,7 +209,7 @@ end_per_suite(_Config) -> init_per_group(openssh, Config) -> case ssh_test_lib:gen_tcp_connect(?SSH_DEFAULT_PORT, []) of {error,econnrefused} -> - {skip,"No openssh deamon (econnrefused)"}; + {skip,"No openssh daemon (econnrefused)"}; {ok, Socket} -> gen_tcp:close(Socket), ssh_test_lib:openssh_sanity_check(Config) @@ -368,7 +368,7 @@ connect4_invalid_two_1(Config) -> ssh:stop_daemon(Pid). connect4_invalid_two_2(Config) -> - {Pid, Host, Port, _UserDir} = daemon_start(Config), + {Pid, Host, _Port, _UserDir} = daemon_start(Config), %% Actual error implementation dependent {error, _} = @@ -380,7 +380,7 @@ connect4_invalid_two_2(Config) -> %% All three args incorrect connect4_invalid_three(Config) -> - {Pid, Host, Port, _UserDir} = daemon_start(Config), + {Pid, Host, _Port, _UserDir} = daemon_start(Config), %% Actual error implementation dependent {error, _} = @@ -679,7 +679,7 @@ do_interrupted_send(Config, SendSize, EchoSize) -> ct:log("~p:~p got expected data",[?MODULE,?LINE]), ok; Other -> - ct:log("~p:~p unexpect: ~p", [?MODULE,?LINE,Other]), + ct:log("~p:~p unexpected: ~p", [?MODULE,?LINE,Other]), {fail,"unexpected result in listener"} catch Class:Exception -> @@ -1236,7 +1236,7 @@ start_shell_sock_daemon_exec_multi(Config) -> receive {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"echo testing\n">>}} -> Parent ! {answer_received,self()}, - ct:log("~p:~p: recevied result on connection ~p", [?MODULE,?LINE,ConnectionRef]) + ct:log("~p:~p: received result on connection ~p", [?MODULE,?LINE,ConnectionRef]) after 5000 -> ct:fail("Exec Timeout") end diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl index 968e6a0fdaef..c02b20d6a256 100644 --- a/lib/ssh/test/ssh_options_SUITE.erl +++ b/lib/ssh/test/ssh_options_SUITE.erl @@ -34,6 +34,7 @@ auth_method_kb_interactive_data_tuple/1, auth_method_kb_interactive_data_fun3/1, auth_method_kb_interactive_data_fun4/1, + auth_none/1, connectfun_disconnectfun_client/1, disconnectfun_option_client/1, disconnectfun_option_server/1, @@ -83,7 +84,11 @@ save_accepted_host_option/1, raw_option/1, config_file/1, - config_file_modify_algorithms_order/1 + config_file_modify_algorithms_order/1, + daemon_replace_options_simple/1, + daemon_replace_options_algs/1, + daemon_replace_options_algs_connect/1, + daemon_replace_options_algs_conf_file/1 ]). %%% Common test callbacks @@ -93,6 +98,10 @@ init_per_testcase/2, end_per_testcase/2 ]). +%%% For test nodes +-export([get_preferred_algorithms/2 + ]). + -define(NEWLINE, <<"\r\n">>). %%-------------------------------------------------------------------- @@ -115,6 +124,7 @@ all() -> auth_method_kb_interactive_data_tuple, auth_method_kb_interactive_data_fun3, auth_method_kb_interactive_data_fun4, + auth_none, {group, dir_options}, ssh_connect_timeout, ssh_connect_arg4_timeout, @@ -145,6 +155,10 @@ all() -> raw_option, config_file, config_file_modify_algorithms_order, + daemon_replace_options_simple, + daemon_replace_options_algs, + daemon_replace_options_algs_connect, + daemon_replace_options_algs_conf_file, {group, hardening_tests} ]. @@ -575,6 +589,30 @@ amkid(Config, {ExpectName,ExpectInstr,ExpectPrompts,ExpectEcho}, OptVal) -> {"Bad again",1}, {"bar",2}]). +%%-------------------------------------------------------------------- +auth_none(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = proplists:get_value(data_dir, Config), + {DaemonRef, Host, Port} = + ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {auth_methods, "password"}, % to make even more sure we don't use public-key-auth + {user_passwords, [{"foo","somepwd"}]}, % Not to be used + {no_auth_needed, true} % we test this + ]), + ClientConnRef1 = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "some-other-user"}, + {password, "wrong-pwd"}, + {user_dir, UserDir}, + {user_interaction, false}]), + "some-other-user" = + proplists:get_value(user, ssh:connection_info(ClientConnRef1, [user])), + ok = ssh:close(ClientConnRef1), + ok = ssh:stop_daemon(DaemonRef). + %%-------------------------------------------------------------------- system_dir_option(Config) -> DirUnread = proplists:get_value(unreadable_dir,Config), @@ -1391,12 +1429,14 @@ max_log_item_len(Config) -> {ok, Reports} = ssh_eqc_event_handler:get_reports(ReportHandlerPid), ct:log("~p:~p ssh:connect -> ~p~n~p", [?MODULE,?LINE,R,Reports]), - [ok,ok] = - [check_skip_part( - string:tokens( - lists:flatten(io_lib:format(Fmt,Args)), - " \n")) - || {info_msg,_,{_,Fmt,Args}} <- Reports]. + [ok] = + lists:usort( + [check_skip_part( + string:tokens( + lists:flatten(io_lib:format(Fmt,Args)), + " \n")) + || {info_msg,_,{_,Fmt,Args}} <- Reports] + ). check_skip_part(["Disconnect","...","("++_NumSkipped, "bytes","skipped)"]) -> @@ -1473,7 +1513,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) -> ct:log("Connections up: ~p",[Connections]), [_|_] = Connections, - %% N w try one more than alowed: + %% N w try one more than allowed: ct:pal("Info Report expected here (if not disabled) ...",[]), try Connect(Host,Port) of @@ -1503,7 +1543,7 @@ try_to_connect(Connect, Host, Port, Pid, Tref, N) -> of _ConnectionRef1 -> timer:cancel(Tref), - ct:log("Step 3 ok: could set up one more connection after killing one. Thats good.",[]), + ct:log("Step 3 ok: could set up one more connection after killing one. That's good.",[]), ssh:stop_daemon(Pid), receive % flush. timeout_no_connection -> ok @@ -1672,30 +1712,24 @@ config_file(Config) -> [{_,[Ch1|_]}|_] = proplists:get_value(cipher, CommonAlgs), %% Make config file: - Contents = - [{ssh, [{preferred_algorithms, - [{cipher, [Ch1]}, - {kex, [K1a]} - ] ++ AdjustClient}, - {client_options, - [{modify_algorithms, - [{rm, [{kex, [K1a]}]}, - {append, [{kex, [K1b]}]} + {ok,ConfFile} = + make_config_file_in_privdir( + "c2.config", Config, + [{ssh, [{preferred_algorithms, + [{cipher, [Ch1]}, + {kex, [K1a]} + ] ++ AdjustClient}, + {client_options, + [{modify_algorithms, + [{rm, [{kex, [K1a]}]}, + {append, [{kex, [K1b]}]} + ]} ]} ]} - ]} - ], - %% write the file: - PrivDir = proplists:get_value(priv_dir, Config), - ConfFile = filename:join(PrivDir,"c2.config"), - {ok,D} = file:open(ConfFile, [write]), - io:format(D, "~p.~n", [Contents]), - file:close(D), - {ok,Cnfs} = file:read_file(ConfFile), - ct:log("c2.config:~n~s", [Cnfs]), + ]), %% Start the slave node with the configuration just made: - {ok,Node} = start_node(random_node_name(?MODULE), ConfFile), + {ok, Peer, Node} = ?CT_PEER(["-config", ConfFile]), R0 = rpc:call(Node, ssh, default_algorithms, []), ct:log("R0 = ~p",[R0]), @@ -1740,7 +1774,7 @@ config_file(Config) -> {options,Os2} = rpc:call(Node, ssh, connection_info, [C2, options]), ct:log("C2 opts:~n~p~n~nalgorithms:~n~p~n~noptions:~n~p", [C2_Opts,As2,Os2]), - stop_node_nice(Node) + peer:stop(Peer) end. %%%---------------------------------------------------------------- @@ -1764,36 +1798,30 @@ config_file_modify_algorithms_order(Config) -> [{_,[Ch1|_]}|_] = proplists:get_value(cipher, CommonAlgs), %% Make config file: - Contents = - [{ssh, [{preferred_algorithms, - [{cipher, [Ch1]}, - {kex, [K1]} - ]}, - {server_options, - [{modify_algorithms, - [{rm, [{kex, [K1]}]}, - {append, [{kex, [K2]}]} - ]} - ]}, - {client_options, - [{modify_algorithms, - [{rm, [{kex, [K1]}]}, - {append, [{kex, [K3]}]} + {ok, ConfFile} = + make_config_file_in_privdir( + "c3.config", Config, + [{ssh, [{preferred_algorithms, + [{cipher, [Ch1]}, + {kex, [K1]} + ]}, + {server_options, + [{modify_algorithms, + [{rm, [{kex, [K1]}]}, + {append, [{kex, [K2]}]} + ]} + ]}, + {client_options, + [{modify_algorithms, + [{rm, [{kex, [K1]}]}, + {append, [{kex, [K3]}]} + ]} ]} ]} - ]} - ], - %% write the file: - PrivDir = proplists:get_value(priv_dir, Config), - ConfFile = filename:join(PrivDir,"c3.config"), - {ok,D} = file:open(ConfFile, [write]), - io:format(D, "~p.~n", [Contents]), - file:close(D), - {ok,Cnfs} = file:read_file(ConfFile), - ct:log("c3.config:~n~s", [Cnfs]), + ]), %% Start the slave node with the configuration just made: - {ok,Node} = start_node(random_node_name(?MODULE), ConfFile), + {ok, Peer, Node} = ?CT_PEER(["-config", ConfFile]), R0 = rpc:call(Node, ssh, default_algorithms, []), ct:log("R0 = ~p",[R0]), @@ -1830,32 +1858,184 @@ config_file_modify_algorithms_order(Config) -> ConnOptions = proplists:get_value(options, ConnInfo), ConnPrefAlgs = proplists:get_value(preferred_algorithms, ConnOptions), - %% And now, are all levels appied in right order: + %% And now, are all levels applied in right order: [K3,K2] = proplists:get_value(kex, ConnPrefAlgs), - stop_node_nice(Node) + peer:stop(Peer) end. %%-------------------------------------------------------------------- -%% Internal functions ------------------------------------------------ +daemon_replace_options_simple(Config) -> + SysDir = proplists:get_value(data_dir, Config), + + UserDir1 = proplists:get_value(user_dir, Config), + UserDir2 = filename:join(UserDir1, "foo"), + file:make_dir(UserDir2), + + {Pid, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir1} + ]), + {ok,Opts1} = ssh:daemon_info(Pid), + UserDir1 = proplists:get_value(user_dir, proplists:get_value(options,Opts1,[])), + + {ok, Pid} = ssh:daemon_replace_options(Pid, [{user_dir,UserDir2}]), + {ok,Opts2} = ssh:daemon_info(Pid), + case proplists:get_value(user_dir, proplists:get_value(options,Opts2,[])) of + UserDir2 -> + ok; + UserDir1 -> + ct:log("~p:~p Got old value ~p~nExpected ~p", [?MODULE,?LINE,UserDir1,UserDir2]), + {fail, "Not changed"}; + Other -> + ct:log("~p:~p Got ~p~nExpected ~p", [?MODULE,?LINE,Other,UserDir2]), + {fail, "Strange value"} + end. + %%-------------------------------------------------------------------- +daemon_replace_options_algs(Config) -> + SysDir = proplists:get_value(data_dir, Config), + UserDir = proplists:get_value(user_dir, Config), -start_node(Name, ConfigFile) -> - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, slave, [{args, - " -pa " ++ Pa ++ - " -config " ++ ConfigFile}]). + DefaultKex = + ssh_transport:default_algorithms(kex), + NonDefaultKex = + ssh_transport:supported_algorithms(kex) -- DefaultKex, + + case NonDefaultKex of + [A1|_] -> + [A2,A3|_] = DefaultKex, + {Pid, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, + {preferred_algorithms,[{kex,[A1]}]} + ]), + [A1] = get_preferred_algorithms(Pid, kex), + {ok, Pid} = + ssh:daemon_replace_options(Pid, [{modify_algorithms, + [{prepend,[{kex,[A2]}]}] + } + ]), + [A2,A1] = get_preferred_algorithms(Pid, kex), + + {ok, Pid} = + ssh:daemon_replace_options(Pid, [{preferred_algorithms,[{kex,[A3]}] + } + ]), + [A2,A3] = get_preferred_algorithms(Pid, kex) + ; + [] -> + {skip, "No non-default kex"} + end. -stop_node_nice(Node) when is_atom(Node) -> - test_server:stop_node(Node). +%%-------------------------------------------------------------------- +daemon_replace_options_algs_connect(Config) -> + [A1,A2|_] = + ssh_transport:default_algorithms(kex), + + {Pid, Host, Port} = + ssh_test_lib:std_daemon(Config, + [{preferred_algorithms,[{kex,[A1]}]} + ]), + [A1] = get_preferred_algorithms(Pid, kex), + + %% Open a connection with A1 as kex and test it + C1 = + ssh_test_lib:std_connect(Config, Host, Port, + [{preferred_algorithms,[{kex,[A1]}]} + ]), + ok = test_connection(C1), + ok = test_not_connect(Config, Host, Port, + [{preferred_algorithms,[{kex,[A2]}]} + ]), + + %% Change kex to A2 + {ok, Pid} = + ssh:daemon_replace_options(Pid, + [{preferred_algorithms,[{kex,[A2]}]}]), + [A2] = get_preferred_algorithms(Pid, kex), + + %% and open the second connection with this kex, and test it + C2 = + ssh_test_lib:std_connect(Config, Host, Port, + [{preferred_algorithms,[{kex,[A2]}]} + ]), + ok = test_connection(C2), + ok = test_not_connect(Config, Host, Port, + [{preferred_algorithms,[{kex,[A1]}]} + ]), + + %% Test that the first connection is still alive: + ok = test_connection(C1), + + ssh:close(C1), + ssh:close(C2), + ssh:stop_daemon(Pid). -random_node_name(BaseName) -> - L = integer_to_list(erlang:unique_integer([positive])), - lists:concat([BaseName,"___",L]). +%%-------------------------------------------------------------------- +daemon_replace_options_algs_conf_file(Config) -> + SysDir = proplists:get_value(data_dir, Config), + UserDir = proplists:get_value(user_dir, Config), + + DefaultKex = + ssh_transport:default_algorithms(kex), + NonDefaultKex = + ssh_transport:supported_algorithms(kex) -- DefaultKex, + + case NonDefaultKex of + [A0,A1|_] -> + %% Make config file: + {ok,ConfFile} = + make_config_file_in_privdir( + "c4.config", Config, + [{ssh, [{modify_algorithms, + %% Whatever happens, always put A0 first in the kex list: + [{prepend, [{kex, [A0]}]} + ]} + ]} + ]), + + [A2|_] = DefaultKex, + ct:log("[A0, A1, A2] = ~p", [[A0, A1, A2]]), + + %% Start the slave node with the configuration just made: + {ok, Peer, Node} = ?CT_PEER(["-config", ConfFile]), + + %% Start ssh on the slave. This should apply the ConfFile: + rpc:call(Node, ssh, start, []), + + {Pid, _Host, _Port} = + rpc:call(Node, ssh_test_lib, daemon, + [ + [{system_dir, SysDir}, + {user_dir, UserDir}, + {preferred_algorithms,[{kex,[A1]}]} + ] + ]), + + [A0,A1] = + rpc:call(Node, ?MODULE, get_preferred_algorithms, [Pid, kex]), + {ok, Pid} = + rpc:call(Node, ssh, daemon_replace_options, + [Pid, + [{modify_algorithms, + [{prepend,[{kex,[A2]}]}] + } + ] + ]), + + %% Check that the precedens order is fulfilled: + [A2,A0,A1] = + rpc:call(Node, ?MODULE, get_preferred_algorithms, [Pid, kex]), + + peer:stop(Peer); + [] -> + {skip, "No non-default kex"} + end. + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- -%%%---- - expected_ssh_vsn(Str) -> try {ok,L} = application:get_all_key(ssh), @@ -1865,7 +2045,7 @@ expected_ssh_vsn(Str) -> "\r\n" -> true; _ -> false catch - _:_ -> true %% ssh not started so we dont't know + _:_ -> true %% ssh not started so we don't know end. @@ -1892,3 +2072,42 @@ fake_daemon(_Config) -> after 10000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. + + +make_config_file_in_privdir(FileName, Config, Contents) -> + %% write the file: + PrivDir = proplists:get_value(priv_dir, Config), + ConfFile = filename:join(PrivDir, FileName), + {ok,D} = file:open(ConfFile, [write]), + io:format(D, "~p.~n", [Contents]), + file:close(D), + {ok,Cnfs} = file:read_file(ConfFile), + ct:log("Config file ~p :~n~s", [ConfFile,Cnfs]), + {ok,ConfFile}. + + +get_preferred_algorithms(Pid, Type) -> + {ok,#{preferred_algorithms:=As}} = ssh_system_sup:get_acceptor_options(Pid), + proplists:get_value(Type, As). + +test_connection(C) -> + {ok, Ch} = ssh_connection:session_channel(C, infinity), + A = rand:uniform(100), + B = rand:uniform(100), + A_plus_B = lists:concat([A,"+",B,"."]), + Sum = integer_to_binary(A+B), + success = ssh_connection:exec(C, Ch, A_plus_B, infinity), + expected = ssh_test_lib:receive_exec_result( + {ssh_cm, C, {data, Ch, 0, Sum}} ), + ssh_test_lib:receive_exec_end(C, Ch), + ok. + +test_not_connect(Config, Host, Port, Opts) -> + try + ssh_test_lib:std_connect(Config, Host, Port, Opts) + of + Cx when is_pid(Cx) -> {error, connected} + catch + error:{badmatch, {error,_}} -> ok + end. + diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl index 7e94bf60c718..666ac76f6334 100644 --- a/lib/ssh/test/ssh_protocol_SUITE.erl +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -717,7 +717,7 @@ client_info_line(Config) -> %%% The server does not send the extension because %%% the client does not tell the server to send it no_ext_info_s1(Config) -> - %% Start the dameon + %% Start the daemon Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,true}, {system_dir, system_dir(Config)}]), {ok,AfterKexState} = connect_and_kex([{server,Server}|Config]), @@ -732,7 +732,7 @@ no_ext_info_s1(Config) -> %%% The server does not send the extension because %%% the server is not configured to send it no_ext_info_s2(Config) -> - %% Start the dameon + %% Start the daemon Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,false}, {system_dir, system_dir(Config)}]), {ok,AfterKexState} = connect_and_kex([{extra_options,[{recv_ext_info,true}]}, @@ -748,7 +748,7 @@ no_ext_info_s2(Config) -> %%%-------------------------------------------------------------------- %%% The server sends the extension ext_info_s(Config) -> - %% Start the dameon + %% Start the daemon Server = {Pid,_,_} = ssh_test_lib:daemon([{send_ext_info,true}, {system_dir, system_dir(Config)}]), {ok,AfterKexState} = connect_and_kex([{extra_options,[{recv_ext_info,true}]}, @@ -903,8 +903,6 @@ modify_combo(Config) -> %%%---------------------------------------------------------------- %%% -client_close_after_hello() -> [{timetrap,{seconds,80}}]. - client_close_after_hello(Config0) -> MaxSessions = 20, SleepSec = 15, @@ -913,7 +911,7 @@ client_close_after_hello(Config0) -> {negotiation_timeout,SleepSec*1000} ]), - {Parents0, Conns0, []} = find_handshake_parent(server_port(Config)), + {_Parents0, Conns0, []} = find_handshake_parent(server_port(Config)), Cs = [ssh_trpt_test_lib:exec( @@ -984,7 +982,7 @@ chk_pref_algs(Config, ExpectedKex, ExpectedCiphers, ServerPrefOpts) -> - %% Start the dameon + %% Start the daemon case ssh_test_lib:daemon( [{send_ext_info,false}, {recv_ext_info,false}, @@ -1103,7 +1101,7 @@ std_connect({Host,Port}, Config, Opts) -> std_connect(Host, Port, Config, Opts) -> {User,Pwd} = server_user_password(Config), ssh:connect(Host, Port, - %% Prefere User's Opts to the default opts + %% Prefer User's Opts to the default opts [O || O = {Tag,_} <- [{user,User},{password,Pwd}, {silently_accept_hosts, true}, {save_accepted_host, false}, diff --git a/lib/ssh/test/ssh_pubkey_SUITE.erl b/lib/ssh/test/ssh_pubkey_SUITE.erl index 81c32e019769..7eca2619db0b 100644 --- a/lib/ssh/test/ssh_pubkey_SUITE.erl +++ b/lib/ssh/test/ssh_pubkey_SUITE.erl @@ -85,7 +85,8 @@ ssh_hostkey_fingerprint_sha512/1, ssh_hostkey_fingerprint_list/1, - chk_known_hosts/1 + chk_known_hosts/1, + ssh_hostkey_pkcs8/1 ]). -include_lib("common_test/include/ct.hrl"). @@ -106,6 +107,7 @@ all() -> {group, option_space}, {group, ssh_hostkey_fingerprint}, {group, ssh_public_key_decode_encode}, + {group, pkcs8}, chk_known_hosts ]. @@ -146,6 +148,7 @@ groups() -> {old_format, [], [check_dsa_disabled, check_rsa_sha1_disabled | ?tests_old++[{group,passphrase}] ]}, {passphrase, [], ?tests_old}, {option_space,[], [{group,new_format}]}, + {pkcs8, [], [ssh_hostkey_pkcs8]}, {ssh_hostkey_fingerprint, [], [ssh_hostkey_fingerprint_md5_implicit, @@ -192,6 +195,11 @@ init_per_group(old_format, Config) -> [{fmt,old_format}, {key_src_dir,Dir} | Config]; +init_per_group(pkcs8, Config) -> + Dir = filename:join(proplists:get_value(data_dir,Config), "pkcs8"), + [{fmt,pkcs8}, + {key_src_dir,Dir} | Config]; + init_per_group(option_space, Config) -> extend_optsL([client_opts,daemon_opts], [{key_cb, {ssh_file, [{optimize, space}]}}], @@ -237,6 +245,8 @@ end_per_group(_, Config) -> Config. %%%---------------------------------------------------------------- +init_per_testcase(ssh_hostkey_pkcs8, Config0) -> + setup_user_system_dir(rsa_sha2, rsa_sha2, Config0); init_per_testcase(connect_rsa_sha2_to_rsa_sha2, Config0) -> setup_user_system_dir(rsa_sha2, rsa_sha2, Config0); init_per_testcase(connect_rsa_sha1_to_dsa, Config0) -> @@ -426,6 +436,12 @@ check_rsa_sha1_disabled(Config) -> %%%---------------------------------------------------------------- +%% Check of different host keys left to later +ssh_hostkey_pkcs8(Config) -> + try_connect(Config). + +%%%---------------------------------------------------------------- + %% Check of different host keys left to later ssh_hostkey_fingerprint_md5_implicit(_Config) -> Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a", @@ -836,8 +852,8 @@ chk_known_hosts(Config) -> %%%---------------------------------------------------------------- -try_connect({skip,Reson}) -> - {skip,Reson}; +try_connect({skip,Reason}) -> + {skip,Reason}; try_connect(Config) -> SystemDir = proplists:get_value(system_dir, Config), UserDir = proplists:get_value(user_dir, Config), diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa new file mode 100644 index 000000000000..b0453eb4e23e --- /dev/null +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2d3XMIA8GTEQc +UFCOm31M5jt6lGjN61ZYGnXBVBjEcyJynB7Y3C437cDpjmvbSWF1oSVVDTwMERwn +XzixLG//7w8K7i6aJLKpHKtS91qnrQidmrUWDnQ4kx8AZxaN46nhSsf+cZ0nKp03 +ZjjR5WxeDimiDLsSUbdDmFE6ZsL2+k5OStvcqu/skUVfPe+FGTGJgIw3DyErxM7J +72jUkLJXMiZkYbB1QD05k3g2LOiPqJ73QoJVGgj7YagTSA3Lgy3s/6U7IMHMV4ls +aXShv1Lk/eCfIJVSaVXQRjV9KKM3wgg6PmWqwGkAO36w3eJiW1kmYKfnAM/+I5Gf +o/TiNZTXAgMBAAECggEAeWdwfDmUZZdW9hPGFayFKSZCyuN1/BSqZYJteQ2QUR1d +/S29JIMTSWkqovt87fGcI9ztbvKYUlsMBXJI0TGE75/KvXYOkcb7DKQjpdcofUoW +4m4uMJe7Ym0ZAnaUviGNRXYxLS3A529mHZcpFRb2DHqV3tljmuO98P6mhRocfKCc +3p/T4+LIGlRlov5lOP/oKkeILF1m04J/SjptTtNo81xne9/dCGTiOTXjS8QMslCc +8Xyy0Go9Zr0d+YzsI2NYF2aFBce0fDwK0Xpptr0FEL8UxjHjeK0T2GSDqncmtKoA +3+BnpEJcuiDqZBi20lX7LygtNe9uVPZjdz1iOeKAaQKBgQDZjj6yOwbDeXkedD0I +25RC8lmCWhV381PDz9RdeRXVC50jq3OYwmdcDEIK23YNWU8GoUnvi7B1aljSfAUm +yUSnixXpU+/ZOkGYA48MHpC1DxJeEVZDu+MFWHmTCXctQNUj40gAKhozJm5Lo33s +Wnhr+Yq2CP65w6R+vXn4gXsv9QKBgQDWtd0BMEVCUug+6/dWCVTUsuBouz/erOgE +f0PPA8/IQV1ZhBQK4wewv14R8Nkywb8Z5lsVyH8JHRHZC35mVzFxGJyGAzDfJ3Mg +GoK8t7jjiUHPF0tYWpLmAKdKHmJqB7ZBGzT7pAP07XockRHoeYHBHoO3Ck/c3h0f +EtclGMOuGwKBgQCXf8z9RMmS+lZz9LJEJtT6QdY/RghJPbOJWoMijJ29fJbzLgQT +zt03ZnnfIbD13sl/bnYUUIyTV3l/KkpUFjivC9Y4Y/FUrpLbDy9gWzCeRV6fDyep +h3+yS0huMltBsjI7CZ0sMCWKlSqdlb6tBttxJZeI6H6qUimM8NmtSk3EuQKBgAw+ +OIjt0LU0dwvHdsYQKCcswAEY1E6FO4GuJBa01+9KUuFc16u7QGACuYF6Y1gylgwL +B5yZXy0M3EytDBsX07joN1yo5+uBm130RQovy7olxHvjjydNmtzEosVmMCRtpiXW +QFItCxC3TeQ9HXFNJGn3rHkOfHlSrQRtlZkG7XmLAoGACVKIJSoI2Kvd913TATb4 +whzNqbdiyFCadLf9cST7sGZ+ZvtHF3CT3iU/9JpBhndu4IqgFPPk694GXhoR2LK8 +SoGR4mhRvPAUgvKjRE2dypQtytgA8gm1soofSjSdoJlSBQkaxfT8N0mwQTbsoyWN +zUDUWl3epDaqpUsV8NOuy4E= +-----END PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa.pub b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa.pub new file mode 100644 index 000000000000..f7b1180aad0f --- /dev/null +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2d3XMIA8GTEQcUFCOm31M5jt6lGjN61ZYGnXBVBjEcyJynB7Y3C437cDpjmvbSWF1oSVVDTwMERwnXzixLG//7w8K7i6aJLKpHKtS91qnrQidmrUWDnQ4kx8AZxaN46nhSsf+cZ0nKp03ZjjR5WxeDimiDLsSUbdDmFE6ZsL2+k5OStvcqu/skUVfPe+FGTGJgIw3DyErxM7J72jUkLJXMiZkYbB1QD05k3g2LOiPqJ73QoJVGgj7YagTSA3Lgy3s/6U7IMHMV4lsaXShv1Lk/eCfIJVSaVXQRjV9KKM3wgg6PmWqwGkAO36w3eJiW1kmYKfnAM/+I5Gfo/TiNZTX uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key new file mode 100644 index 000000000000..0c01831fa665 --- /dev/null +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCuvOQFQAxi8Cyj +iFHv2+Y1vE1sti3tChy6RuIJY6rb0dC+ptLOP85ITVCDoL9pNuCG92m/FtoW3dqp +1augXQ+FVWgSwljvpsjtGyhsh73Mj9nd2RBGZbcjKMe+lUHDLzh8pnTkDwF3XSRx +rUZ+tBeLsuQVnkVGPFqsXMyiMZV6xZxktqBOE8bRACNLDawb6iqXhigh5qBJ1/e3 +M44X7Ti9ymCoJG6CyxzDXuUjVHCrScze2FQGBJYNFuPOaRaj2Llalz1kpLXPgA0R +P4jaEZbs8QDpcBckoLqchZ1UiJ7QY3TYL+aLjk3JM+fnYj9MkoUC0ihnx9uscR6l +ftX8O3sNAgMBAAECggEADXIlja3fBiH7HV5ZB78BGPNzdcETCaF0knTv4c8Uj7O2 +f2Uw5YQNaIzifC57bCo33srdDUJB5+6Ma/MwMLfYgOcQihkAZPiNj4k+dBOB7GLJ +XgPc973N+NujeyvbEpzomNbqOb5Z24iETGcL/KX5BdvvJya1p/Du/UJq0LRGD1tS +0TycwcphU9rOffTCUd0+XpPJO0RehkIoyDY5PGu9rzTHkluhSotldfjVWpWaqqhq +QQ7c04aWGsjMg4HzrqnLx35/rCKU3+tRwZ4wnAHxpOtg/EuQJiX08Z4wMwsBG+GM +ybnd/pRAUOkvatjRemdqqtmpL0qtsmhNANaUyPc6IQKBgQDgUvd9trgVgbN/tP+b +bFFILmqumvSA2fWZknmhRYaIcHCMAcLsRVZqlyOyRpztavOcgEmJXajPPFA6AjKa +5g70tf3kbpveeuRaFVepSLIKSl0xIT9hV8CIxzdnRA3P4j9xsQ9Qpnuiwo9mbgFG +lQ28nCPhW+3mNfBNmU+ZWak0dQKBgQDHaXGroc74attrQDODvChuedny5lm91n5C +nGAaEfVHH3zrYoz65VisnvERSU1Nh8G12moldCcaWnOMY97OJmMnG/sCBZskDzRp +e1Mf+gT0TQoyYZHMTZtA1HyRRkdTlLZ7S77HUNTK8qrIpJEHLFSnzCPlBkY84fgw ++8IdVkX5OQKBgCDnapARFi1paffoh7m3iLCqxlE4P3cLAYB2QMsMFLC8tXWD6KCZ +hxR5eO30d55HmtYw5xh0GYfUU/w+SEf6SOVSMJyqMMjQg+BG0yXsmNjzkXncY5yW +r5IgjpriG5iLmjzF+PYehXIZUcl3h05gHLS2vniW8G1dKhNn0oou4aflAoGAFTLh +caR+8yuw7cLidxOunKf5gnf4fFTsETq8gKj+ETSIvCE66YUuGxO+ft7zB9XxwtpY +RGkHqyaIeBk522J7UfIIiht8daXkJX6FxLV4h1wVRGvY6wYpBghQwcTd2kXJ7GuN ++XRfWr/XZgMQo9mTmk76VeOH3fsLvnFVHndIcwkCgYBLntA0osVpZm6egw26+80C +PtnSrUmsW4sTB+eQbbyDn6i/fAgGKc+2WuvcdorqyfLSEcs+hE/59roFVFpCEPN5 +4oO7o+o0SQ2ehxY+Lv2XF+TnfUQlAc6BCBfK3tG6rROUFiznAaua1hcsoAa9x/LH +0SgWzYqbWI0qq7pv91tBdw== +-----END PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key.pub new file mode 100644 index 000000000000..8e62458395a1 --- /dev/null +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/pkcs8/ssh_host_rsa_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuvOQFQAxi8CyjiFHv2+Y1vE1sti3tChy6RuIJY6rb0dC+ptLOP85ITVCDoL9pNuCG92m/FtoW3dqp1augXQ+FVWgSwljvpsjtGyhsh73Mj9nd2RBGZbcjKMe+lUHDLzh8pnTkDwF3XSRxrUZ+tBeLsuQVnkVGPFqsXMyiMZV6xZxktqBOE8bRACNLDawb6iqXhigh5qBJ1/e3M44X7Ti9ymCoJG6CyxzDXuUjVHCrScze2FQGBJYNFuPOaRaj2Llalz1kpLXPgA0RP4jaEZbs8QDpcBckoLqchZ1UiJ7QY3TYL+aLjk3JM+fnYj9MkoUC0ihnx9uscR6lftX8O3sN uabhnil@elxadlj3q32 diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_comment_pub b/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_comment_pub index 7b42ced93edd..bca5a375ca62 100644 --- a/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_comment_pub +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_comment_pub @@ -1,7 +1,7 @@ ---- BEGIN SSH2 PUBLIC KEY ---- Comment: This is an example of a very very very very looooooooooooo\ ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ -commment +comment x-command: /home/me/bin/lock-in-guest.sh AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ diff --git a/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_header_pub b/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_header_pub index 7b42ced93edd..bca5a375ca62 100644 --- a/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_header_pub +++ b/lib/ssh/test/ssh_pubkey_SUITE_data/public_key/ssh_rsa_long_header_pub @@ -1,7 +1,7 @@ ---- BEGIN SSH2 PUBLIC KEY ---- Comment: This is an example of a very very very very looooooooooooo\ ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ -commment +comment x-command: /home/me/bin/lock-in-guest.sh AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl index 3bb4cb2071c2..f7aac11c7cea 100644 --- a/lib/ssh/test/ssh_relay.erl +++ b/lib/ssh/test/ssh_relay.erl @@ -313,7 +313,7 @@ listen(Parent, LSock) -> do_listen(Parent, LSock). do_listen(Parent, LSock) -> - %% So annoying there is no select-like sematic for this + %% So annoying there is no select-like semantics for this case gen_tcp:accept(LSock, ?ACCEPT_TMO) of {ok, Sock} -> Parent ! {accept, Sock}, diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index 70a004973046..42677b761376 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2020. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -405,7 +405,7 @@ rename_file(Config) when is_list(Config) -> NewReqId1 = NewReqId + 1, file:copy(FileName, NewFileName), - %% No owerwrite + %% No overwrite {ok, <>, _} = rename(FileName, NewFileName, Cm, Channel, NewReqId1, 6, @@ -685,7 +685,7 @@ access_outside_root(Config) when is_list(Config) -> BadFilePath = filename:join([BaseDir, bad]), ok = file:write_file(BadFilePath, <<>>), {Cm, Channel} = proplists:get_value(sftp, Config), - %% Try to access a file parallell to the RootDir: + %% Try to access a file parallel to the RootDir: try_access("/../bad", Cm, Channel, 0), %% Try to access the same file via the CWD which is /b relative to the RootDir: try_access("../../bad", Cm, Channel, 1). @@ -717,7 +717,7 @@ try_access(Path, Cm, Channel, ReqId) -> end end; _ -> - ct:fail("Completly unexpected return: ~p", [Return]) + ct:fail("Completely unexpected return: ~p", [Return]) end. %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index acabb66a4805..faa350423dca 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -484,7 +484,7 @@ receive_exec_result(Msgs) when is_list(Msgs) -> receive_exec_result(Msgs); Other -> ct:log("~p:~p unexpected Other ~p", [?MODULE,?FUNCTION_NAME,Other]), - {unexpected_msg, Other} + receive_exec_result(Msgs) end end after @@ -627,14 +627,14 @@ default_algorithms(sshc, DaemonOptions) -> {hostport,Srvr,{_Host,Port}} -> spawn(fun()-> os:cmd(lists:concat(["ssh -o \"StrictHostKeyChecking no\" -p ",Port," localhost"])) end) after ?TIMEOUT -> - ct:fail("No server respons (timeout) 1") + ct:fail("No server response (timeout) 1") end, receive {result,Srvr,L} -> L after ?TIMEOUT -> - ct:fail("No server respons (timeout) 2") + ct:fail("No server response (timeout) 2") end. run_fake_ssh({ok,InitialState}) -> @@ -940,7 +940,7 @@ create_random_dir(Config) -> Name; {error,eexist} -> %% The Name already denotes an existing file system object, try again. - %% The likelyhood of always generating an existing file name is low + %% The likelihood of always generating an existing file name is low create_random_dir(Config) end. diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index a36b4036a527..c61907ec288b 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -91,7 +91,7 @@ init_per_suite(Config) -> ?CHECK_CRYPTO( case gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, []) of {error,econnrefused} -> - {skip,"No openssh deamon (econnrefused)"}; + {skip,"No openssh daemon (econnrefused)"}; _ -> ssh_test_lib:openssh_sanity_check( [{ptty_supported, ssh_test_lib:ptty_supported()} diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl index eea392bd352a..6d3f4544ce43 100644 --- a/lib/ssh/test/ssh_trpt_test_lib.erl +++ b/lib/ssh/test/ssh_trpt_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2020. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -47,7 +47,7 @@ prints = [], return_value, - %% Packet retrival and decryption + %% Packet retrieval and decryption decrypted_data_buffer = <<>>, encrypted_data_buffer = <<>>, aead_data = <<>>, @@ -343,7 +343,7 @@ send(S0=#s{alg_neg={undefined,PeerMsg}}, Msg=#ssh_msg_kexinit{}) -> S1#s{alg = Cx#ssh.algorithms} catch Class:Exc -> - save_prints({"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", + save_prints({"Algorithm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(Msg)]}, S1) end; @@ -361,8 +361,8 @@ send(S0, ssh_msg_kexdh_init) when ?role(S0) == client -> try ssh_transport:handle_kexinit_msg(PeerMsg, OwnMsg, S0#s.ssh) catch Class:Exc -> - fail("Algoritm negotiation failed!", - {"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s", + fail("Algorithm negotiation failed!", + {"Algorithm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s", [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(OwnMsg)]}, S0) end, @@ -429,7 +429,7 @@ recv(S0 = #s{}) -> %% Must see hello before binary messages try_find_crlf(<<>>, S1); true -> - %% Has seen hello, therefore no more crlf-messages are alowed. + %% Has seen hello, therefore no more crlf-messages are allowed. S = receive_binary_msg(S1), case PeerMsg = S#s.return_value of #ssh_msg_kexinit{} -> @@ -451,7 +451,7 @@ recv(S0 = #s{}) -> alg = C#ssh.algorithms} catch Class:Exc -> - save_prints({"Algoritm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", + save_prints({"Algorithm negotiation failed at line ~p:~p~n~p:~s~nPeer: ~s~n Own: ~s~n", [?MODULE,?LINE,Class,format_msg(Exc),format_msg(PeerMsg),format_msg(OwnMsg)]}, S#s{alg_neg = {OwnMsg, PeerMsg}}) end @@ -650,7 +650,7 @@ ok({error,E}) -> erlang:error(E). %%%================================================================ %%% -%%% Formating of records +%%% Formatting of records %%% format_msg(M) -> format_msg(M, 0). diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl index 7c7c93e04be9..b96fa896bb58 100644 --- a/lib/ssh/test/ssh_upgrade_SUITE.erl +++ b/lib/ssh/test/ssh_upgrade_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2014-2020. All Rights Reserved. +%% Copyright Ericsson AB 2014-2022. 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. @@ -98,7 +98,7 @@ minor_upgrade(Config) when is_list(Config) -> %%% %%%---------------------------------------------------------------- -%%% Initialyze system before upgrade test starts. +%%% Initialize system before upgrade test starts. %%% Called by ct_release_test:upgrade/4 upgrade_init(CTData, State) -> {ok, AppUp={_, _, Up, _Down}} = ct_release_test:get_appup(CTData, ssh), diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 110239529a66..50757ade5b5d 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,4 +1,4 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 4.13.2.3 +SSH_VSN = 5.0.1 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile index 5cc111ec1455..40f97eff5c22 100644 --- a/lib/ssl/Makefile +++ b/lib/ssl/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2023. 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. @@ -40,4 +40,6 @@ include $(ERL_TOP)/make/otp_subdir.mk DIA_PLT_APPS=crypto runtime_tools inets public_key +TEST_NEEDS_RELEASE=true + include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 1f32267e3572..d8c74d915ebb 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 19992022 + 19992023 Ericsson AB. All Rights Reserved. @@ -27,6 +27,820 @@

    This document describes the changes made to the SSL application.

    +
    SSL 11.0.3 + +
    Fixed Bugs and Malfunctions + + +

    + Avoid function clause error in ssl:getopts/2 by handling + that inet:getopts may return an empty list during some + circumstances, such as the socket being in a closing + state.

    +

    + Own Id: OTP-18697 Aux Id: GH-7506

    +
    + +

    + The API function `ssl:recv/3` has been tightened to + disallow negative length, which has never been documented + to work, but was passed through and caused strange + errors.

    +

    + Own Id: OTP-18700 Aux Id: GH-7507

    +
    + +

    + When a client initiated renegotiation was rejected and + the client socket was in active mode the expected error + message to the controlling process was not sent.

    +

    + Own Id: OTP-18712 Aux Id: GH-7431

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Add some guidance for signature algorithms configuration + in ssl applications users guide.

    +

    + Own Id: OTP-18631

    +
    +
    +
    + +
    + +
    SSL 11.0.2 + +
    Fixed Bugs and Malfunctions + + +

    + Added keylog information to all protocol versions in + ssl:connection_information/2.

    +

    + Own Id: OTP-18643 Aux Id: ERIERL-932

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Add RFC-6083 considerations for DTLS to enable gen_sctp + based callback for the transport.

    +

    + Own Id: OTP-18618 Aux Id: ERIERL-932

    +
    +
    +
    + +
    + +
    SSL 11.0.1 + +
    Fixed Bugs and Malfunctions + + +

    + Make sure that selection of client certificates handle + both TLS-1.3 and TLS-1.2 names correctly. Could cause + valid client certificate to not be selected, and an empty + client certificate message to be sent to server.

    +

    + Own Id: OTP-18588 Aux Id: GH-7264, PR-7277

    +
    + +

    + Improved ssl:format_error/1 to handle more error + tuples.

    +

    + Own Id: OTP-18596 Aux Id: GH-7247

    +
    + +

    + Fixed hanging ssl:connect when ssl application is + not started.

    +

    + Own Id: OTP-18603 Aux Id: GH-7297

    +
    + +

    + Correct handling of retransmission timers, current + behavior could cause unwanted delays.

    +

    + Own Id: OTP-18632 Aux Id: PR-7300, GH-7301

    +
    +
    +
    + +
    + +
    SSL 11.0 + +
    Improvements and New Features + + +

    + Remove less that 256 bit ECC from default supported ECC + pre TLS-1.3

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-14771

    +
    + +

    + Improved error checking and handling of ssl options.

    +

    + Own Id: OTP-15903

    +
    + +

    + With this change, stateless tickets generated by server + with anti_replay option enabled can be used for creating + ClientHello throughout ticket lifetime. Without this + change, usability was limited to WindowSize number of + seconds configured for anti_replay option.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18168 Aux Id: PR-6019, GH-6014

    +
    + +

    Support for Kernel TLS (kTLS), has been added to the + SSL application, for TLS distribution (-proto_dist + inet_tls), the SSL option {ktls, true}. Using + this for general SSL sockets is uncomfortable, + undocumented and not recommended since it requires very + platform dependent raw options.

    This, for now, + only works for some not too old Linux distributions. + Roughly, a kernel 5.2.0 or later with support for + UserLand Protocols and the kernel module tls is + required.

    +

    + Own Id: OTP-18235 Aux Id: PR-6104, PR-5840

    +
    + +

    + With this change, TLS 1.3 server can be configured to + include client certificate in session ticket.

    +

    + Own Id: OTP-18253

    +
    + +

    + With this change, it is possible to configure encryption + seed to be used with TLS1.3 stateless tickets. This + enables using tickets on different server instances.

    +

    + Own Id: OTP-18254 Aux Id: PR-5982

    +
    + +

    + Debugging enhancements.

    +

    + Own Id: OTP-18312

    +
    + +

    + With this change, maybe keyword atom is not used as + function name in ssl code.

    +

    + Own Id: OTP-18335

    +
    + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18405 Aux Id: + GH-6672,PR-6702,PR-6768,PR-6700,PR-6769,PR-6812,PR-6814

    +
    + +

    + For security reasons remove support for SHA1 and DSA + algorithms from default values.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18438 Aux Id: GH-6679

    +
    + +

    + Mitigate memory usage from large certificate chains by + lowering the maximum handshake size. This should not + effect the common cases, if needed it can be configured + to a higher value.

    +

    + Own Id: OTP-18453

    +
    + +

    + Change the client default verify option to verify_peer. + Note that this makes it mandatory to also supply trusted + CA certificates or explicitly set verify to verify_none. + This also applies when using the so called anonymous test + cipher suites defined in TLS versions pre TLS-1.3.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18455 Aux Id: GH-5899

    +
    + +

    + Erlang distribution code in Kernel and SSL has been + refactored a bit to facilitate debugging and + re-usability, which shouldn't have any noticeable effects + on behaviour or performance.

    +

    + Own Id: OTP-18456

    +
    + +

    + Add encoding and decoding of use_srtp hello extension to + facilitate for DTLS users to implement SRTP + functionality.

    +

    + Own Id: OTP-18459

    +
    + +

    + Refactors the (ssl application to use macros for + TLS and DTLS versions instead of hard-coded tuple + numbers. This change improves the maintainability of + ssl

    +

    + Own Id: OTP-18465 Aux Id: GH-7065

    +
    + +

    + If the function ssl:renegotiate/1 is called on connection + that is running TLS-1.3 return an error instead of + hanging or timing out.

    +

    + Own Id: OTP-18507

    +
    + +

    + If a user cancel alert with level warning is received + during handshake make it be handled the same regardless + of TLS version. If it is received in connection in + TLS-1.3 regard it as an error as it is inappropriate.

    +

    + In TLS-1.3 all error alerts are considered FATAL + regardless of legacy alert type. But make sure legacy + type is printed in logs to not confuse users that are + expecting the same legacy type as sent by peer.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18531

    +
    + +

    + Make fail_if_no_peer_cert default true if + verify_peer is set on the server, otherwise the server + will accept the connection if verify_peer is set and the + user have forgot to set the fail_if_no_peer_cert and the + client did not send a certificate.

    +

    + Own Id: OTP-18567

    +
    + +

    + To make it easier to configure signature algorithms with + algorithms that are moved from the default add the API + function signature_algs/2 that lists possible values. + Also make sha224 a non default value.

    +

    + Own Id: OTP-18572

    +
    +
    +
    + +
    + +
    SSL 10.9.1.2 + +
    Fixed Bugs and Malfunctions + + +

    + The API function `ssl:recv/3` has been tightened to + disallow negative length, which has never been documented + to work, but was passed through and caused strange + errors.

    +

    + Own Id: OTP-18700 Aux Id: GH-7507

    +
    + +

    + When a client initiated renegotiation was rejected and + the client socket was in active mode the expected error + message to the controlling process was not sent.

    +

    + Own Id: OTP-18712 Aux Id: GH-7431

    +
    +
    +
    + +
    + +
    SSL 10.9.1.1 + +
    Fixed Bugs and Malfunctions + + +

    + Added keylog information to all protocol versions in + ssl:connection_information/2.

    +

    + Own Id: OTP-18643 Aux Id: ERIERL-932

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Add RFC-6083 considerations for DTLS to enable gen_sctp + based callback for the transport.

    +

    + Own Id: OTP-18618 Aux Id: ERIERL-932

    +
    +
    +
    + +
    + +
    SSL 10.9.1 + +
    Fixed Bugs and Malfunctions + + +

    + With this change, ssl:connection_information/2 returns + correct keylog data after TLS1.3 key update.

    +

    + Own Id: OTP-18489

    +
    + +

    + Client signature algorithm list input order is now + honored again , it was accidently reversed by a previous + fix.

    +

    + Own Id: OTP-18550

    +
    +
    +
    + +
    + +
    SSL 10.9 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed that new dtls connections from the same + client ip port combination works. If there is a process + waiting for accept the new connection will connect to + that, otherwise it will try to re-connect to the old + server connection.

    +

    + Own Id: OTP-18371 Aux Id: GH-6160

    +
    + +

    + When shutting down a node that uses SSL distribution + (-proto_dist inet_tls), a confusing error message + about an unexpected process exit was printed. This + particular message is no longer generated.

    +

    + Own Id: OTP-18443 Aux Id: PR-6810

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + fixes the type spec for ssl:format_error/1

    +

    + Own Id: OTP-18366 Aux Id: PR-6565, GH-6506

    +
    + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    SSL 10.8.7 + +
    Improvements and New Features + + +

    + Maximize compatibility by ignoring change_cipher_spec + during handshake even if middle_box_mode is not + negotiated (mandated by client)

    +

    + Own Id: OTP-18433 Aux Id: GH-6772

    +
    + +

    + Move assert of middlebox message after an + hello_retry_request to maximize interoperability. Does + not changes semantics of the protocol only allows + unexpected message delay from server.

    +

    + Own Id: OTP-18467 Aux Id: GH-6807

    +
    +
    +
    + +
    + +
    SSL 10.8.6 + +
    Fixed Bugs and Malfunctions + + +

    + With this change, tls_sender process is hibernated after + sufficient inactivity.

    +

    + Own Id: OTP-18314 Aux Id: GH-6373

    +
    + +

    + Correct handling of legacy schemes so that ECDSA certs + using sha1 may be used for some TLS-1.3 configurations.

    +

    + Own Id: OTP-18332 Aux Id: GH-6435, PR-6435, ERL-6435

    +
    + +

    + With this change, tls_sender does not cause logger crash + upon key update.

    +

    + Own Id: OTP-18349

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Enhance warning message

    +

    + Own Id: OTP-18257 Aux Id: GH-6307

    +
    + +

    + Provide server option to make certificate_authorities + extension in the TLS-1.3 servers certificate request + optional. This will allow clients to send incomplete + chains that may be reconstructable and thereby verifiable + by the server, but that would not adhere to the + certificate_authorities extension.

    +

    + Own Id: OTP-18267 Aux Id: PR-6228, GH-6106

    +
    + +

    + If the verify_fun handles four arguments the DER + cert will be supplied as one of the arguments.

    +

    + Own Id: OTP-18302 Aux Id: ERIERL-867

    +
    +
    +
    + +
    + +
    SSL 10.8.5 + +
    Fixed Bugs and Malfunctions + + +

    + Fixes handling of symlinks in cacertfile option.

    +

    + Own Id: OTP-18266 Aux Id: GH-6328

    +
    +
    +
    + +
    + +
    SSL 10.8.4 + +
    Fixed Bugs and Malfunctions + + +

    + Reject unexpected application data in all relevant places + for all TLS versions. Also, handle TLS-1.3 middlebox + compatibility with more care. This will make malicious + connections fail early and further, mitigate possible DoS + attacks, that would be caught by the handshake timeout.

    +

    + Thanks to Aina Toky Rasoamanana and Olivier Levillain + from Télécom SudParis for alerting us of the issues in + our implementation.

    +

    + Own Id: OTP-18044

    +
    + +

    + With this change, value of cacertfile option will be + adjusted before loading certs from the file. Adjustments + include converting relative paths to absolute and + converting symlinks to actual file path.

    +

    + Thanks to Marcus Johansson

    +

    + Own Id: OTP-18099 Aux Id: PR-6287

    +
    + +

    + In TLS-1.3, if chain certs are missing (so server auth + domain adherence can not be determined) send peer cert + and hope the server is able to recreate a chain in its + auth domain.

    +

    + Own Id: OTP-18191 Aux Id: GH-6105

    +
    + +

    + Make sure periodical refresh of CA certificate files + repopulates cache properly.

    +

    + Own Id: OTP-18195

    +
    + +

    + Correct internal CRL cache functions to use internal + format consistently.

    +

    + Own Id: OTP-18203 Aux Id: PR-5996

    +
    + +

    + Incorrect handling of client middlebox negotiation for + TLS-1.3 could result in that a TLS-1.3 server would not + use middlebox mode although the client was expecting it + too and failing the negotiation with unexpected message.

    +

    + Own Id: OTP-18219 Aux Id: GH-6241, PR-6249

    +
    + +

    + If the "User" process, the process starting the TLS + connection, gets killed in the middle of spawning the + dynamic connection tree make sure we do not leave any + processes behind.

    +

    + Own Id: OTP-18233 Aux Id: GH-6244, PR-6270

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + A vulnerability has been discovered and corrected. It is + registered as CVE-2022-37026 "Client Authentication + Bypass". Corrections have been released on the supported + tracks with patches 23.3.4.15, 24.3.4.2, and 25.0.2. The + vulnerability might also exist in older OTP versions. We + recommend that impacted users upgrade to one of these + versions or later on the respective tracks. OTP 25.1 + would be an even better choice. Impacted are those who + are running an ssl/tls/dtls server using the ssl + application either directly or indirectly via other + applications. For example via inets (httpd), cowboy, etc. + Note that the vulnerability only affects servers that + request client certification, that is sets the option + {verify, verify_peer}.

    +

    + Own Id: OTP-18241

    +
    +
    +
    + +
    + +
    SSL 10.8.3 + +
    Fixed Bugs and Malfunctions + + +

    The link to crypto:engine_load refered the function + with wrong arity.

    +

    + Own Id: OTP-18173

    +
    +
    +
    + +
    + +
    SSL 10.8.2 + +
    Fixed Bugs and Malfunctions + + +

    + Improved handling of unexpected messages during the + handshake, taking the right action for unexpected + messages.

    +

    + Own Id: OTP-18145

    +
    +
    +
    + +
    + +
    SSL 10.8.1 + +
    Fixed Bugs and Malfunctions + + +

    + When a TLS-1.3 enabled client tried to talk to a TLS-1.2 + server that coalesces TLS-1.2 handshake message over one + TLS record, the connection could fail due to some message + being handled in the wrong state, this has been fixed.

    +

    + Own Id: OTP-18087 Aux Id: GH-5961

    +
    + +

    + Correctly handles supported protocol version change from + default to something else by sni_fun supplied to + ssl:handshake/[2,3] together with a TCP-socket (so called + upgrade).

    +

    + Own Id: OTP-18100 Aux Id: GH-5985

    +
    + +

    + Also, TLS-1.3 should respond with a protocol version + alert if previous versions, that are supported but not + configured, are attempted.

    +

    + Own Id: OTP-18129 Aux Id: GH-5950

    +
    +
    +
    + +
    + +
    SSL 10.8 + +
    Fixed Bugs and Malfunctions + + +

    + When a TLS-1.3 enabled client tried to talk to a TLS-1.2 + server that coalesces TLS-1.2 handshake message over one + TLS record, the connection could fail due to some message + being handled in the wrong state, this has been fixed.

    +

    + Own Id: OTP-18087 Aux Id: GH-5961

    +
    + +

    + Fixed tls-1.3 session ticket lifetime which was discarded + to quickly before.

    +

    + Own Id: OTP-18092 Aux Id: PR-5959

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + With this change, it is possible to provide several + certificates. Most appropriate will be selected based on + negotiated properties.

    +

    + Own Id: OTP-15993 Aux Id: GH-4143

    +
    + +

    + Add options for users to be able to set spawn_opts for + TLS processes (sender and receiver) this may be useful + for tuning trade-offs between CPU and Memory usage.

    +

    + Own Id: OTP-17855 Aux Id: PR-5328

    +
    + +

    + Allow key file passwords to be input as a single binary, + that is we change the data type to be the more for the + purpose logical data type iodata() instead of string().

    +

    + Own Id: OTP-17890

    +
    + +

    + Logging enhancement, add location information to the + warning log message.

    +

    + Own Id: OTP-18000 Aux Id: PR-5790

    +
    + +

    + Now also accepts the signature_algs_cert option in + TLS-1.2 configuration.

    +

    + Own Id: OTP-18014

    +
    + +

    + Handle certificate selection correctly for server + fallback and certificate authorities considerations.

    +

    + Own Id: OTP-18045 Aux Id: ERIERL-792, OTP-15993

    +
    + +

    + Enhance handling of handshake decoding errors, especially + for certificate authorities extension to ensure graceful + termination.

    +

    + Own Id: OTP-18085

    +
    +
    +
    + +
    +
    SSL 10.7.3.8
    Fixed Bugs and Malfunctions @@ -793,6 +1607,56 @@
    +
    SSL 10.3.1.5 + +
    Fixed Bugs and Malfunctions + + +

    + Correct corner case of unexpected message handling for + pre TLS-1.3 versions, could cause "late failure" and make + the server dependent on its handshake timeout to prevent + possible DoS attacks.

    +

    + Own Id: OTP-18224

    +
    +
    +
    + +
    + +
    SSL 10.3.1.4 + +
    Fixed Bugs and Malfunctions + + +

    The link to crypto:engine_load refered the function + with wrong arity.

    +

    + Own Id: OTP-18173

    +
    +
    +
    + +
    + +
    SSL 10.3.1.3 + +
    Fixed Bugs and Malfunctions + + +

    + Improved handling of unexpected messages during the + handshake, taking the right action for unexpected + messages.

    +

    + Own Id: OTP-18145

    +
    +
    +
    + +
    +
    SSL 10.3.1.2
    Fixed Bugs and Malfunctions @@ -936,6 +1800,23 @@
    +
    SSL 10.2.4.4 + +
    Fixed Bugs and Malfunctions + + +

    + Improved handling of unexpected messages during the + handshake, taking the right action for unexpected + messages.

    +

    + Own Id: OTP-18145

    +
    +
    +
    + +
    +
    SSL 10.2.4.3
    Fixed Bugs and Malfunctions diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 6e4456d95e62..57fb68ab5f78 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -4,7 +4,7 @@
    - 19992022 + 19992023 Ericsson AB. All Rights Reserved. @@ -228,6 +228,10 @@ + + + + @@ -340,7 +344,7 @@

    The DER-encoded user's private key or a map referring to a crypto engine and its key reference that optionally can be password protected, see also crypto:engine_load/3 - and Crypto's Users Guide. If this option + and Crypto's Users Guide. If this option is supplied, it overrides option keyfile.

    @@ -356,13 +360,53 @@ - +

    String containing the user's password or a function returning same type. Only used if the private keyfile is password-protected.

    + + + +

    A list of a certificate (or possible a certificate and its + chain) and the associated key of the certificate, that may be + used to authenticate the client or the server. The + certificate key pair that is considered best and matches + negotiated parameters for the connection will be selected. + Different signature algorithms are prioritized in the order + eddsa, ecdsa, rsa_pss_pss, rsa and dsa . If more than + one key is supplied for the same signing algorithm (which is + probably an unusual use case) they will prioritized by + strength unless it is a so called engine key that will + be favoured over other keys. As engine keys cannot be + inspected, supplying more than one engine key will make no + sense. This offers flexibility to for instance configure a + newer certificate that is expected to be used in most cases + and an older but acceptable certificate that will only be used + to communicate with legacy systems. Note that there is a trade + off between the induced overhead and the flexibility so + alternatives should be chosen for good reasons. If the certs_keys option is specified it + overrides all single certificate and key options. For examples see the Users Guide +

    + +

    eddsa certificates are only supported by TLS-1.3 that does not support dsa certificates. + rsa_pss_pss (RSA certificates using Probabilistic Signature Scheme) are supported in TLS-1.2 and TLS-1.3, but some + TLS-1.2 implementations may not support rsa_pss_pss. +

    +
    +
    + + + + +

    A certificate (or possibly a certificate and its chain) and its associated key on one of the + possible formats. For the PEM file format there may also be a password associated with the file containg the key. +

    +
    +
    + @@ -422,7 +466,8 @@

    Signature algorithms used for certificates may be overridden by the signature schemes (algorithms) supplied by the signature_algs_cert option.

    -

    TLS-1.2 default is

    +

    TLS-1.2 default is Default_TLS_12_Alg_Pairs interleaved with rsa_pss_schemes since ssl-11.0 (OTP-25) + pss_pss is prefered over pss_rsae that is prefered over rsa

    Default_TLS_12_Alg_Pairs =

    [ @@ -432,53 +477,52 @@ {sha384, ecdsa}, {sha384, rsa}, {sha256, ecdsa}, -{sha256, rsa}, -{sha224, ecdsa}, -{sha224, rsa}, -%% SHA -{sha, ecdsa}, -{sha, rsa}, -{sha, dsa} -] - +{sha256, rsa} +]
    -

    Support for {md5, rsa} was removed from the the TLS-1.2 default in ssl-8.0 (OTP-22)

    +

    Support for {md5, rsa} was removed from the the TLS-1.2 default in ssl-8.0 (OTP-22) and support for SHA1 {sha, _} and SHA224 {sha224, _} was removed in ssl-11.0 (OTP-26)

    +

    rsa_pss_schemes =

    + +[rsa_pss_pss_sha512, +rsa_pss_pss_sha384, +rsa_pss_pss_sha256, +rsa_pss_rsae_sha512, +rsa_pss_rsae_sha384, +rsa_pss_rsae_sha256] + -

    TLS_13 _Legacy_Schemes =

    +

    TLS_13_Legacy_Schemes =

    [ %% Legacy algorithms only applicable to certificate signatures rsa_pkcs1_sha512, %% Corresponds to {sha512, rsa} rsa_pkcs1_sha384, %% Corresponds to {sha384, rsa} rsa_pkcs1_sha256, %% Corresponds to {sha256, rsa} -ecdsa_sha1, %% Corresponds to {sha, ecdsa} -rsa_pkcs1_sha1 %% Corresponds to {sha, rsa} ]

    Default_TLS_13_Schemes =

    [ + %% EDDSA +eddsa_ed25519, +eddsa_ed448 + %% ECDSA ecdsa_secp521r1_sha512, ecdsa_secp384r1_sha384, -ecdsa_secp256r1_sha256, +ecdsa_secp256r1_sha256] ++ + %% RSASSA-PSS -rsa_pss_pss_sha512, -rsa_pss_pss_sha384, -rsa_pss_pss_sha256, -rsa_pss_rsae_sha512, -rsa_pss_rsae_sha384, -rsa_pss_rsae_sha256, -%% EDDSA -eddsa_ed25519, -eddsa_ed448] - +rsa_pss_schemes() +
    + +

    EDDSA was made highest priority in ssl-10.8 (OTP-25)

    TLS-1.3 default is

    -Default_TLS_13_Schemes ++ Legacy_TLS_13_Schemes +Default_TLS_13_Schemes

    If both TLS-1.3 and TLS-1.2 are supported the default will be

    -Default_TLS_13_Schemes ++ Default_TLS_12_Alg_Pairs +Default_TLS_13_Schemes ++ TLS_13_Legacy_Schemes ++ Default_TLS_12_Alg_Pairs (not represented in TLS_13_Legacy_Schemes)

    so appropriate algorithms can be chosen for the negotiated version. @@ -577,11 +621,22 @@ version.

    The verification fun is to be defined as follows:

    -fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | - {revoked, atom()}} | - {extension, #'Extension'{}} | valid | valid_peer, InitialUserState :: term()) -> +fun(OtpCert :: #'OTPCertificate'{}, + Event, InitialUserState :: term()) -> + {valid, UserState :: term()} | + {fail, Reason :: term()} | {unknown, UserState :: term()}. + +fun(OtpCert :: #'OTPCertificate'{}, DerCert :: public_key:der_encoded(), + Event, InitialUserState :: term()) -> {valid, UserState :: term()} | {fail, Reason :: term()} | {unknown, UserState :: term()}. + +Types: + Event = {bad_cert, Reason :: atom() | + {revoked, atom()}} | + {extension, #'Extension'{}} | + valid | + valid_peer

    The verification fun is called during the X509-path @@ -591,8 +646,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | allow access to each certificate in the path to the user application. It differentiates between the peer certificate and the CA certificates by using valid_peer or - valid as second argument to the verification fun. See - the public_key + valid as Event argument to the verification fun. + See the public_key User's Guide for definition of #'OTPCertificate'{} and #'Extension'{}.

    @@ -762,7 +817,7 @@ marker="public_key:public_key#pkix_path_validation/3">public_key:pkix_path_valid fun(Chain::[public_key:der_encoded()]) -> - {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca} + {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca.

    Claim an intermediate CA in the chain as trusted. TLS then performs + + +

    Configures spawn options of TLS sender and receiver processes.

    +

    Setting up garbage collection options can be helpful for trade-offs between + CPU usage and Memory usage. + See erlang:spawn_opt/2.

    +

    For dist connections, default sender option is [...{priority, max}], this priority + option cannot be changed. For all connections, ...link is added to receiver and cannot + be changed.

    +
    + +

    Configures a TLS 1.3 connection for keylogging

    @@ -936,9 +1003,14 @@ fun(srp, Username :: binary(), UserState :: term()) -> -

    In mode verify_none the default behavior is to allow - all x509-path validation errors. See also option verify_fun.

    -
    + +

    Defaults to verify_none as additional options are needed to be able to perform the certificate verification. + A warning will be emitted unless verify_none is explicitly configured. Usually the applications will want to configure + verify_peer together with an appropriate cacert or cacertfile option. For example an HTTPS client would normally + use the option {cacerts, public_key:cacerts_get()} (available since OTP-25) to access the CA certificates + provided by the OS. Using verify_none means that all x509-certificate path validation errors will be ignored. + See also option verify_fun.

    +
    @@ -949,7 +1021,7 @@ fun(srp, Username :: binary(), UserState :: term()) -> explicitly specified by its session id and associated data since OTP-22.3. See also - SSL's Users Guide, Session Reuse pre TLS 1.3 + SSL's Users Guide, Session Reuse pre TLS 1.3.

    @@ -963,17 +1035,17 @@ fun(srp, Username :: binary(), UserState :: term()) -> and used with the client option reuse_session The boolean value true specifies that if possible, automated session reuse will be performed. If a new session is created, and is unique in regard - to previous stored sessions, it will be saved for possible later reuse. Since OTP-21.3

    + to previous stored sessions, it will be saved for possible later reuse. Since OTP-21.3.

    - +

    If set to true, sends the certificate authorities extension in TLS-1.3 client hello. The default is false. Note that setting it to true may result in a big overhead if you have many trusted CA certificates. - Since OTP-24.3

    + Since OTP-24.3.

    @@ -989,8 +1061,15 @@ fun(srp, Username :: binary(), UserState :: term()) ->

    Path to a file containing PEM-encoded CA certificates. The CA - certificates are used during server authentication and when building the - client certificate chain.

    + certificates are used during server authentication and when building the + client certificate chain.

    +

    When PEM caching is enabled, files provided with + this option will be checked for updates at fixed time intervals specified by the + ssl_pem_cache_clean environment parameter.

    +
    +

    Alternatively, CA certificates can be provided as a DER-encoded + binary with client_cacerts + option.

    @@ -1077,7 +1156,10 @@ fun(srp, Username :: binary(), UserState :: term()) ->

    Customizes the hostname verification of the peer certificate, as different protocols that use - TLS such as HTTP or LDAP may want to do it differently, for possible options see + TLS such as HTTP or LDAP may want to do it differently. For example the get standard HTTPS handling + provide the already implememnted fun from the public_key application for HTTPS. + {customize_hostname_check, [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}]} + For futher description of customize options see public_key:pkix_verify_hostname/3

    @@ -1148,6 +1230,34 @@ fun(srp, Username :: binary(), UserState :: term()) -> + + + +

    Configures the use_srtp DTLS hello extension.

    +

    In order to negotiate the use of SRTP data protection, clients + include an extension of type "use_srtp" in the DTLS extended client + hello. This extension MUST only be used when the data being + transported is RTP or RTCP.

    +

    The value is a map with a mandatory protection_profiles and + an optional mki parameters.

    +

    protection_profiles configures the list of the client's acceptable + SRTP Protection Profiles. Each profile is a 2-byte binary. Example: + #{protection_profiles => [<<0,2>>, <<0,5>>]}

    +

    mki configures the SRTP Master Key Identifier chosen by the client.

    +

    The srtp_mki field contains the value of the SRTP MKI which is associated + with the SRTP master keys derived from this handshake. Each SRTP + session MUST have exactly one master key that is used to protect + packets at any given time. The client MUST choose the MKI value so + that it is distinct from the last MKI value that was used, and it + SHOULD make these values unique for the duration of the TLS session.

    +

    This extension MUST only be used with DTLS, and not with TLS.

    +

    OTP does not handle SRTP, so an external implementations of SRTP + encoder/decoder and a packet demultiplexer are needed to make use + of the use_srtp extension. See also + cb_info option.

    +
    +
    + @@ -1183,6 +1293,21 @@ fun(srp, Username :: binary(), UserState :: term()) -> is supplied it overrides option cacertfile.

    + + + + +

    Determines if a TLS-1.3 server should include the authorities + extension in its certificate request message that will be sent if the + option verify is set to verify_peer. Defaults to true.

    + +

    A reason to exclude the extension would be if the server wants to communicate with clients + incapable of sending complete certificate chains that adhere to the + extension, but the server still has the capability to recreate a chain that it can verify.

    + +
    + +
    @@ -1193,6 +1318,12 @@ fun(srp, Username :: binary(), UserState :: term()) -> client when a certificate is requested. Can be omitted if there is no need to verify the client and if there are no intermediate CAs for the server certificate.

    +

    When PEM caching is enabled, files provided with + this option will be checked for updates at fixed time intervals specified by the + ssl_pem_cache_clean environment parameter.

    +
    +

    Alternatively, CA certificates can be provided as a DER-encoded + binary with server_cacerts option.

    @@ -1218,12 +1349,14 @@ fun(srp, Username :: binary(), UserState :: term()) -> -

    A server only does x509-path validation in mode - verify_peer, as it then sends a certificate request to - the client (this message is not sent if the verify option is - verify_none). You can then also want to specify option - fail_if_no_peer_cert.

    -
    +

    Client certificates are an optional part of the TLS protocol. + A server only does x509-certificate path validation in mode + verify_peer. By default the server is in verify_none mode + an hence will not send an certificate request to the client. + When using verify_peer you may also want to specify the options + fail_if_no_peer_cert and + certificate_authorities.

    +
    @@ -1242,7 +1375,7 @@ fun(srp, Username :: binary(), UserState :: term()) ->

    The boolean value true specifies that the server will agree to reuse sessions. Setting it to false will result in an empty session table, that is no sessions will be reused. - See also option reuse_session + See also option reuse_session.

    @@ -1366,15 +1499,34 @@ fun(srp, Username :: binary(), UserState :: term()) -> -

    Configures the session ticket functionality. Allowed values are disabled, - stateful and stateless.

    -

    If it is set to stateful or - stateless, session resumption with pre-shared keys is enabled and the server will - send stateful or stateless session tickets to the client after successful connections.

    +

    Configures the session ticket functionality. Allowed values are disabled, + stateful, stateless, stateful_with_cert, stateless_with_cert.

    +

    If it is not set to disabled, + session resumption with pre-shared keys is enabled and the server will + send stateful or stateless session tickets to the client after successful connections.

    + +

    + Pre-shared key session ticket resumption does not include any certificate exchange, + hence the function ssl:peercert/1 will not + be able to return the peer certificate as it is only communicated in the initial handshake. + The server options stateful_with_cert or stateless_with_cert may be used + to make a server associate the client certificate from the original handshake + with the tickets it issues. +

    +

    A stateful session ticket is a database reference to internal state information. A stateless session ticket is a self-encrypted binary that contains both cryptographic keying material and state data.

    + +

    + If it is set to stateful_with_cert the client certificate + is stored with the internal state information, increasing memory consumption. + If it is set to stateless_with_cert the client certificate is + encoded in the self-encrypted binary that is sent to the client, + increasing the payload size. +

    +

    This option is supported by TLS 1.3 and above. See also SSL's Users Guide, Session Tickets and Session Resumption in TLS 1.3 @@ -1382,6 +1534,26 @@ fun(srp, Username :: binary(), UserState :: term()) -> + + + +

    Configures the seed used for the encryption of stateless session tickets. + Allowed values are any randomly generated binary(). If this option is not + configured, an encryption seed will be randomly generated.

    + +

    Reusing the ticket encryption seed between multiple server + instances enables stateless session tickets to work across multiple server + instances, but it breaks anti-replay protection across instances.

    + +

    Inaccurate time synchronization between server instances can also + affect session ticket freshness checks, potentially causing false negatives as + well as false positives.

    + +

    This option is supported by TLS 1.3 and above and only with stateless + session tickets.

    +
    +
    + @@ -1390,7 +1562,7 @@ fun(srp, Username :: binary(), UserState :: term()) ->

    Allowed values are the pre-defined '10k', '100k' or a custom 3-tuple that defines the properties of the bloom filters: {WindowSize, HashFunctions, Bits}. WindowSize is the number of seconds after the current Bloom filter is rotated - and also the window size used for freshness checks. HashFunctions is the number + and also the window size used for freshness checks of ClientHello. HashFunctions is the number hash functions and Bits is the number of bits in the bit vector. '10k' and '100k' are simple defaults with the following properties:

    @@ -1437,6 +1609,40 @@ fun(srp, Username :: binary(), UserState :: term()) ->
    + + + +

    Configures the use_srtp DTLS hello extension.

    +

    Servers that receive an extended hello containing a "use_srtp" + extension can agree to use SRTP by including an extension of type + "use_srtp", with the chosen protection profile in the extended server + hello. This extension MUST only be used when the data being + transported is RTP or RTCP.

    +

    The value is a map with a mandatory protection_profiles and + an optional mki parameters.

    + +

    protection_profiles configures the list of the server's chosen + SRTP Protection Profile as a list of a single 2-byte binary. Example: + #{protection_profiles => [<<0,5>>]}

    +

    mki configures the server's SRTP Master Key Identifier.

    +

    Upon receipt of a "use_srtp" extension containing a "srtp_mki" field, + the server MUST either (assuming it accepts the extension at all):

    + +

    include a matching "srtp_mki" value in its "use_srtp" extension + to indicate that it will make use of the MKI, or

    +

    return an empty "srtp_mki" value to indicate that it cannot + make use of the MKI (default).

    +
    +
    +
    +

    This extension MUST only be used with DTLS, and not with TLS.

    +

    OTP does not handle SRTP, so an external implementations of SRTP + encoder/decoder and a packet demultiplexer are needed to make use + of the use_srtp extension. See also + cb_info option.

    +
    +
    + @@ -1544,12 +1750,13 @@ fun(srp, Username :: binary(), UserState :: term()) -> - Clears the pem cache -

    PEM files, used by ssl API-functions, are cached. The - cache is regularly checked to see if any cache entries should be - invalidated, however this function provides a way to - unconditionally clear the whole cache. -

    + Clears the pem cache + +

    PEM files, used by ssl API-functions, are cached for + performance reasons. The cache is automatically checked at + regular intervals to see if any cache entries should be invalidated.

    +

    This function provides a way to unconditionally clear the entire + cache, thereby forcing a reload of previously cached PEM files.

    @@ -1912,6 +2119,12 @@ fun(srp, Username :: binary(), UserState :: term()) -> {error, renegotiation_rejected} indicating that the peer refused to go through with the renegotiation, but the connection is still active using the previously negotiated session.

    +

    TLS-1.3 has removed the renegotiate feature of earlier TLS versions + and instead adds a new feature called key update that replaces the most + important part of renegotiate, that is the refreshing of session keys. + This is triggered automatically after reaching a plaintext limit and + can be configured by option key_update_at. +

    @@ -1960,6 +2173,61 @@ fun(srp, Username :: binary(), UserState :: term()) -> is useful.

    + + + + Returns a list of signature algorithms/schemes + +

    Lists all possible signature algorithms corresponding to + Description that are available. The + exclusive option will exclusively list + algorithms/schemes for that protocol version, whereas the + default and all options lists the combined list to support the + range of protocols from (D)TLS-1.2, the first version to support + configuration of the signature algorithms, to Version.

    + +

    Example:

    + + + 1> ssl:signature_algs(default, 'tlsv1.3'). + [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512, + ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256, + rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256, + rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256, + rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256, + {sha512,ecdsa}, + {sha384,ecdsa}, + {sha256,ecdsa}] + + 2>ssl:signature_algs(all, 'tlsv1.3'). + [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512, + ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256, + rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256, + rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256, + rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256, + {sha512,ecdsa}, + {sha384,ecdsa}, + {sha256,ecdsa}, + {sha224,ecdsa}, + {sha224,rsa}, + {sha,rsa}, + {sha,dsa}] + + 3> ssl:signature_algs(exclusive, 'tlsv1.3'). + [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512, + ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256, + rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256, + rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256] + + +

    Some TLS-1-3 scheme names overlap with TLS-1.2 + algorithm-tuple-pair-names and then TLS-1.3 names will be + used, for example rsa_pkcs1_sha256 instead of + {sha256, rsa} these are legacy algorithms in TLS-1.3 + that apply only to certificate signatures in this version of + the protocol.

    +
    +
    diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml index 0f660cc420c6..dbb1fc166e62 100644 --- a/lib/ssl/doc/src/ssl_app.xml +++ b/lib/ssl/doc/src/ssl_app.xml @@ -4,7 +4,7 @@
    - 19992021 + 19992022 Ericsson AB. All Rights Reserved. @@ -139,9 +139,9 @@

    Number of milliseconds between PEM cache validations. Defaults to 2 minutes.

    +

    Note: The cache can be reloaded by calling ssl:clear_pem_cache/0 - + marker="ssl#clear_pem_cache/0">ssl:clear_pem_cache/0.

    ]]> diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml index 03111749788a..725c219f1316 100644 --- a/lib/ssl/doc/src/standards_compliance.xml +++ b/lib/ssl/doc/src/standards_compliance.xml @@ -5,7 +5,7 @@
    2015 - 2022 + 2023 Ericsson AB, All Rights Reserved @@ -327,8 +327,8 @@ use_srtp (RFC5764) - NC - + C + 26.0 @@ -466,8 +466,8 @@ use_srtp (RFC5764) - NC - + C + 26.0 @@ -594,6 +594,12 @@ C 22.1 + + + use_srtp (RFC5764) + C + 26.0 + @@ -625,6 +631,12 @@ C 22 + + + use_srtp (RFC5764) + C + 26.0 + @@ -910,14 +922,14 @@ Client - NC - + C + 24.3 Server - NC - + C + 24.3 @@ -1254,8 +1266,8 @@ application_layer_protocol_negotiation (RFC7301) - NC - + C + 23.0 @@ -1275,13 +1287,6 @@ C 23.3 - - - supported_versions (RFC8446) - NC - - - Server @@ -1321,8 +1326,8 @@ application_layer_protocol_negotiation (RFC7301) - NC - + C + 23.0 @@ -1342,13 +1347,6 @@ C 23.3 - - - supported_versions (RFC8446) - NC - - - diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml index ae082b98dbd8..25e63e1b634e 100644 --- a/lib/ssl/doc/src/using_ssl.xml +++ b/lib/ssl/doc/src/using_ssl.xml @@ -4,7 +4,7 @@
    - 20032022 + 20032023 Ericsson AB. All Rights Reserved. @@ -36,39 +36,60 @@ ssl:versions/0 .

    -

    To see all supported cipher suites, call - ssl:cipher_suites(all, 'tlsv1.3') . - The available cipher suites for a connection depend on the TLS version and pre TLS-1.3 also - on the certificate. To see the default cipher suite list change all to default. - Note that TLS 1.3 and previous versions does not have any cipher suites in common, - for listing cipher suites for a specific version use - ssl:cipher_suites(exclusive, 'tlsv1.3') . - Specific cipher suites that you want your connection to use can also be - specified. Default is to use the strongest available.

    - +

    To see all supported cipher suites, call ssl:cipher_suites(all, + 'tlsv1.3') . The available cipher suites for a + connection depend on the TLS version and pre TLS-1.3 also on the + certificate. To see the default cipher suite list change all + to default. Note that TLS 1.3 and previous versions do not + have any cipher suites in common, for listing cipher suites for a + specific version use ssl:cipher_suites(exclusive, + 'tlsv1.3') . Specific cipher suites that you want your + connection to use can also be specified. Default is to use the + strongest available.

    + + +

    The following sections shows small examples of how to set up + client/server connections using the Erlang shell. The returned + value of the sslsocket is abbreviated with [...] as + it can be fairly large and is opaque to the user except for the + purpose of pattern matching.

    + + +

    Note that client certificate verification is optional for the server and needs additional conguration + on both sides to work. The Certificate and keys, in the examples, are provided using the certs_keys option + introduced in OTP-25. +

    +
    +
    - Setting up Connections - -

    This section shows a small example of how to set up client/server connections - using the Erlang shell. The returned value of the sslsocket is abbreviated - with [...] as it can be fairly large and is opaque.

    - -
    - Minimal Example - -

    The minimal setup is not the most secure setup of TLS/DTLS.

    -
    + Basic Client + 1 > ssl:start(), ssl:connect("google.com", 443, [{verify, verify_peer}, + {cacerts, public_key:cacerts_get()}]). + {ok,{sslsocket, [...]}} +
    -

    To set up client/server connections:

    +
    + Basic Connection -

    Step 1: Start the server side:

    - 1 server> ssl:start(). +

    Step 1: Start the server side:

    + 1 server> ssl:start(). ok - -

    Step 2: Create a TLS listen socket: (To run DTLS add the option {protocol, dtls})

    + +

    Step 2: with alternative certificates, + in this example the EDDSA certificate will be preferred if TLS-1.3 + is negotiated and the RSA certificate will always be used for TLS-1.2 + as it does not support the EDDSA algorithm:

    2 server> {ok, ListenSocket} = -ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}]). +ssl:listen(9999, [{certs_keys, [#{certfile => "eddsacert.pem", + keyfile => "eddsakey.pem"}, + #{certfile => "rsacert.pem", + keyfile => "rsakey.pem", + password => "foobar"} + ]},{reuseaddr, true}]). {ok,{sslsocket, [...]}} +

    Step 3: Do a transport accept on the TLS listen socket:

    3 server> {ok, TLSTransportSocket} = ssl:transport_accept(ListenSocket). @@ -83,8 +104,10 @@ connection

    Step 4: Start the client side:

    1 client> ssl:start(). ok -

    To run DTLS add the option {protocol, dtls} to third argument.

    - 2 client> {ok, Socket} = ssl:connect("localhost", 9999, [], infinity). +

    Be sure to configure trusted certificates to use for server certificate verification.

    + 2 client> {ok, Socket} = ssl:connect("localhost", 9999, + [{verify, verify_peer}, + {cacertfile, "cacerts.pem"}, {active, once}], infinity). {ok,{sslsocket, [...]}}

    Step 5: Do the TLS handshake:

    @@ -100,79 +123,90 @@ to avoid DoS attacks. In the example the timeout defaults to infinty.

    ok

    Step 7: Flush the shell message queue to see that the message - was sent on the server side:

    + sent on the server side is recived by the client side:

    3 client> flush(). Shell got {ssl,{sslsocket,[...]},"foo"} ok -
    - -
    - Upgrade Example - TLS only - -

    To upgrade a TCP/IP connection to a TLS connection, the - client and server must agree to do so. The agreement - can be accomplished by using a protocol, for example, the one used by HTTP - specified in RFC 2817.

    +
    -

    To upgrade to a TLS connection:

    - -

    Step 1: Start the server side:

    - 1 server> ssl:start(). -ok - -

    Step 2: Create a normal TCP listen socket:

    - 2 server> {ok, ListenSocket} = gen_tcp:listen(9999, [{reuseaddr, true}]). -{ok, #Port<0.475>} - -

    Step 3: Accept client connection:

    - 3 server> {ok, Socket} = gen_tcp:accept(ListenSocket). -{ok, #Port<0.476>} - -

    Step 4: Start the client side:

    - 1 client> ssl:start(). -ok - - 2 client> {ok, Socket} = gen_tcp:connect("localhost", 9999, [], infinity). + +
    + Upgrade Example - TLS only + +

    Upgrading a a TCP/IP connection to a TLS connections is mostly + used when there is a desire have unencrypted communication first and + then later secure the communication channel by using TLS. Note that + the client and server need to agree to do the upgrade in the + protocol doing the communication. This is concept is often + referenced as STARTLS and used in many protocols such as + SMTP, FTPS and HTTPS via a proxy. +

    + +

    Maximum security recommendations are however moving away from such solutions.

    -

    Step 5: Ensure active is set to false before trying - to upgrade a connection to a TLS connection, otherwise - TLS handshake messages can be delivered to the wrong process:

    - 4 server> inet:setopts(Socket, [{active, false}]). -ok +

    To upgrade to a TLS connection:

    + +

    Step 1: Start the server side:

    + 1 server> ssl:start(). + ok + +

    Step 2: Create a normal TCP listen socket and ensure + active is set to false and not set to any active mode + otherwise TLS handshake messages can be delivered to the + wrong process. +

    + 2 server> {ok, ListenSocket} = gen_tcp:listen(9999, [{reuseaddr, true}, + {active, false}]). + {ok, #Port<0.475>} + +

    Step 3: Accept client connection:

    + 3 server> {ok, Socket} = gen_tcp:accept(ListenSocket). + {ok, #Port<0.476>} + +

    Step 4: Start the client side:

    + 1 client> ssl:start(). + ok + + 2 client> {ok, Socket} = gen_tcp:connect("localhost", 9999, [], infinity). + +

    Step 5: Do the TLS handshake:

    + 4 server> {ok, TLSSocket} = ssl:handshake(Socket, [{verify, verify_peer}, + {fail_if_no_peer_cert, true}, + {cacertfile, "cacerts.pem"}, + {certs_keys, [#{certfile => "cert.pem", keyfile => "key.pem"}]}]). + {ok,{sslsocket,[...]}} -

    Step 6: Do the TLS handshake:

    - 5 server> {ok, TLSSocket} = ssl:handshake(Socket, [{cacertfile, "cacerts.pem"}, -{certfile, "cert.pem"}, {keyfile, "key.pem"}]). -{ok,{sslsocket,[...]}} - -

    Step 7: Upgrade to a TLS connection. The client and server - must agree upon the upgrade. The server must call - ssl:handshake/2 before the client calls ssl:connect/3.

    - 3 client>{ok, TLSSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"}, -{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity). +

    Step 6: Upgrade to a TLS connection. The client and + server must agree upon the upgrade. The server must be prepared to be a TLS server before the client + can do a successful connect.

    + + 3 client>{ok, TLSSocket} = ssl:connect(Socket, [{verify, verify_peer}, + {cacertfile, "cacerts.pem"}, + {certs_keys, [#{certfile => "cert.pem", keyfile => "key.pem"}]}], infinity). {ok,{sslsocket,[...]}} - -

    Step 8: Send a message over TLS:

    + +

    Step 7: Send a message over TLS:

    4 client> ssl:send(TLSSocket, "foo"). -ok + ok
    -

    Step 9: Set active true on the TLS socket:

    - 4 server> ssl:setopts(TLSSocket, [{active, true}]). -ok +

    Step 8: Set active once on the TLS socket:

    + 5 server> ssl:setopts(TLSSocket, [{active, once}]). + ok -

    Step 10: Flush the shell message queue to see that the message - was sent on the client side:

    +

    Step 9: Flush the shell message queue to see that + the message sent on the client side is recived by the server side:

    + 5 server> flush(). -Shell got {ssl,{sslsocket,[...]},"foo"} -ok -
    -
    + Shell got {ssl,{sslsocket,[...]},"foo"} + ok +
    Customizing cipher suites

    Fetch default cipher suite list for a TLS/DTLS version. Change default to all to get all possible cipher suites.

    + 1> Default = ssl:cipher_suites(default, 'tlsv1.2'). [#{cipher => aes_256_gcm,key_exchange => ecdhe_ecdsa, mac => aead,prf => sha384}, ....] @@ -183,7 +217,8 @@ ok 2> NoRSA = ssl:filter_cipher_suites(Default, [{key_exchange, fun(rsa) -> false; - (_) -> true end}]). + (_) -> true + end}]). [...] @@ -191,9 +226,11 @@ ok 3> Suites = ssl:filter_cipher_suites(Default, [{key_exchange, fun(ecdh_ecdsa) -> true; - (_) -> false end}, - {cipher, fun(aes_128_cbc) ->true; - (_) ->false end}]). + (_) -> false + end}, + {cipher, fun(aes_128_cbc) -> true; + (_) ->false + end}]). [#{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa, mac => sha256,prf => sha256}, #{cipher => aes_128_cbc,key_exchange => ecdh_ecdsa,mac => sha, @@ -210,7 +247,63 @@ ok #{cipher => aes_256_cbc,key_exchange => ecdhe_ecdsa, mac => sha384,prf => sha384}, ...] -
    +
    + +
    + Customizing signature algorithms(TLS-1.2)/schemes(TLS-1.3) + +

    Starting from TLS-1.2 signature algorithms (called signature + schemes in TLS-1.3) is something that can be negotiated and hence + also configured. These algorithms/schemes will be used for digital + signatures in protocol messages and in certificates.

    + +

    TLS-1.3 schemes have atom names whereas TLS-1.2 + configuration is two element tuples composed by one hash algorithm + and one signature algorithm. When both versions are supported the + configuration can be a mix of these as both versions might be + negotiated. All rsa_pss based schemes are back ported to + TLS-1.2 and can be used also in a TLS-1.2 configuration. In + TLS-1.2 the signature algorithms chosen by the server will also + be affected by the chiper suite that is chosen, which is not the + case in TLS-1.3.

    + +

    Using the function ssl:signature_algs/2 + will let you inspect diffrent aspects of possible configurations + for your system. For example if TLS-1.3 and TLS-1.2 is supported the + default signature_algorithm list in OTP-26 and cryptolib from + OpenSSL 3.0.2 would look like: +

    + + 1> ssl:signature_algs(default, 'tlsv1.3'). + %% TLS-1.3 schemes + [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512, + ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256, + rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256, + rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256, + %% Legacy schemes only valid for certificate signatures in TLS-1.3 + %% (would have a tuple name in TLS-1.2 only configuration) + rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256 + %% TLS 1.2 algorithms + {sha512,ecdsa}, + {sha384,ecdsa}, + {sha256,ecdsa}] + + +

    If you want to add support for non default supported + algorithms you should append them to the default list as the + configuration is in prefered order, something like this:

    + + + MySignatureAlgs = ssl:signature_algs(default, 'tlsv1.3') ++ [{sha, rsa}, {sha, dsa}], + ssl:connect(Host,Port,[{signature_algs, MySignatureAlgs,...]}), + ... + + +

    See also ssl:signature_algs/2 + and sign_algo()

    +
    Using an Engine Stored Key @@ -226,7 +319,8 @@ ok

    2> {ok, EngineRef} = crypto:engine_load(<<"dynamic">>, - [{<<"SO_PATH">>, "/tmp/user/engines/MyEngine"},<<"LOAD">>],[]). +[{<<"SO_PATH">>, "/tmp/user/engines/MyEngine"},<<"LOAD">>], +[]). {ok,#Ref<0.2399045421.3028942852.173962>} @@ -240,35 +334,61 @@ crypto:engine_load(<<"dynamic">>, 4> {ok, SSLSocket} = ssl:connect("localhost", 9999, [{cacertfile, "cacerts.pem"}, - {certfile, "cert.pem"}, - {key, PrivKey}], infinity). + {certs_keys, [#{certfile => "cert.pem", key => PrivKey}]} + ], infinity).

    See also crypto documentation

    +
    + NSS keylog +

    The NSS keylog debug feature can be used by authorized users + to for instance enable wireshark to decrypt TLS packets.

    + +

    Server (with NSS key logging)

    + + server() -> + application:load(ssl), + {ok, _} = application:ensure_all_started(ssl), + Port = 11029, + LOpts = [{certs_keys, [#{certfile => "cert.pem", keyfile => "key.pem"}]}, + {reuseaddr, true}, + {versions, ['tlsv1.2','tlsv1.3']}, + {keep_secrets, true} %% Enable NSS key log (debug option) + ], + {ok, LSock} = ssl:listen(Port, LOpts), + {ok, ASock} = ssl:transport_accept(LSock), + {ok, CSock} = ssl:handshake(ASock). + +

    Exporting the secrets

    + + {ok, [{keylog, KeylogItems}]} = ssl:connection_information(CSock, [keylog]). + file:write_file("key.log", [[KeylogItem,$\n] || KeylogItem <- KeylogItems]). + +
    Session Reuse pre TLS 1.3 -

    Clients can request to reuse a session established - by a previous full handshake between that client and server by - sending the id of the session in the initial handshake - message. The server may or may not agree to reuse it. If agreed - the server will send back the id and if not it will send a new - id. The ssl application has several options for handling session - reuse.

    + +

    Clients can request to reuse a session established by a + previous full handshake between that client and server by sending + the id of the session in the initial handshake message. The server + may or may not agree to reuse it. If agreed the server will send + back the id and if not it will send a new id. The ssl application + has several options for handling session reuse.

    On the client side the ssl application will save session data to try to automate session reuse on behalf of the client processes - on the Erlang node. Note that only verified sessions will be - saved for security reasons, that is session resumption relies on - the certificate validation to have been run in the original + on the Erlang node. Note that only verified sessions will be saved + for security reasons, that is session resumption relies on the + certificate validation to have been run in the original handshake. To minimize memory consumption only unique sessions will be saved unless the special save value is specified for the following option {reuse_sessions, boolean() | - save} in which case a full handshake will be performed and that - specific session will have been saved before the handshake + save} in which case a full handshake will be performed and + that specific session will have been saved before the handshake returns. The session id and even an opaque binary containing the session data can be retrieved using ssl:connection_information/1 function. A saved session @@ -320,7 +440,8 @@ ok

    Step 2- Using save Option

    -%% We want save this particular session for reuse although it has the same basis as C1 +%% We want save this particular session for +%% reuse although it has the same basis as C1 6> {ok, C3} = ssl:connect("localhost", 9999, [{verify, verify_peer}, {versions, ['tlsv1.2']}, {cacertfile, "cacerts.pem"}, @@ -365,11 +486,12 @@ ok %% Perform a full handshake and the session will not be saved for reuse -12> {ok, C9} = ssl:connect("localhost", 9999, [{verify, verify_peer}, - {versions, ['tlsv1.2']}, - {cacertfile, "cacerts.pem"}, - {reuse_sessions, false}, - {server_name_indication, disable}]). +12> {ok, C9} = +ssl:connect("localhost", 9999, [{verify, verify_peer}, + {versions, ['tlsv1.2']}, + {cacertfile, "cacerts.pem"}, + {reuse_sessions, false}, + {server_name_indication, disable}]). {ok,{sslsocket,{gen_tcp,#Port<0.14>,tls_connection, ...}} %% Fetch session ID and data for C9 connection @@ -451,15 +573,14 @@ ok

    An example with automatic and manual session resumption:

    -

    Step 1 (server): Start the server:

    {ok, _} = application:ensure_all_started(ssl). - LOpts = [{certfile, "cert.pem"}, - {keyfile, "key.pem"}, + LOpts = [{certs_keys, [#{certfile => "cert.pem", + keyfile => "key.pem"}]}, {versions, ['tlsv1.2','tlsv1.3']}, {session_tickets, stateless}]. {ok, LSock} = ssl:listen(8001, LOpts). - {ok, CSock} = ssl:transport_accept(LSock). + {ok, ASock} = ssl:transport_accept(LSock).

    Step 2 (client): Start the client and connect to server:

    @@ -474,7 +595,7 @@ ok

    Step 3 (server): Start the TLS handshake:

    - ssl:handshake(CSock). + {ok, CSocket} = ssl:handshake(ASock).

    A connection is established using a full handshake. @@ -490,12 +611,13 @@ ok Post-Handshake, NewSessionTicket ... -

    At this point the client has stored the received session tickets and ready to use them when - establishing new connections to the same server.

    +

    At this point the client has stored the received session + tickets and ready to use them when establishing new connections to + the same server.

    Step 4 (server): Accept a new connection on the server:

    - {ok, CSock2} = ssl:transport_accept(LSock). + {ok, ASock2} = ssl:transport_accept(LSock).

    Step 5 (client): Make a new connection:

    @@ -505,7 +627,7 @@ ok

    Step 6 (server): Start the handshake:

    - ssl:handshake(CSock2). + {ok, CSock2} =ssl:handshake(ASock2).

    The second connection is a session resumption using keying material @@ -524,13 +646,13 @@ ok

    Step 7 (server): Accept a new connection on the server:

    - {ok, CSock3} = ssl:transport_accept(LSock). + {ok, ASock3} = ssl:transport_accept(LSock).

    Step 8 (client): Make a new connection to server:

    {ok, _} = application:ensure_all_started(ssl). - COpts2 = [{cacertfile, "cert.pem"}, + COpts2 = [{cacertfile, "cacerts.pem"}, {versions, ['tlsv1.2','tlsv1.3']}, {log_level, debug}, {session_tickets, manual}]. @@ -539,11 +661,11 @@ ok

    Step 9 (server): Start the handshake:

    - ssl:handshake(CSock3). + {ok, CSock3} = ssl:handshake(ASock3). -

    After the handshake is performed, the user process receives messages with the tickets - sent by the server.

    +

    After the handshake is performed, the user process receivess + messages with the tickets sent by the server.

    Step 10 (client): Receive a new session ticket:

    @@ -552,7 +674,7 @@ ok

    Step 11 (server): Accept a new connection on the server:

    - {ok, CSock4} = ssl:transport_accept(LSock). + {ok, ASock4} = ssl:transport_accept(LSock).

    Step 12 (client): Initiate a new connection to the server with the session ticket @@ -569,12 +691,13 @@ ok

    Step 13 (server): Start the handshake:

    - ssl:handshake(CSock3). + {ok, CSock4} = ssl:handshake(ASock4). -
    +
    +
    - Early Data in TLS 1.3 + Early Data in TLS-1.3

    TLS 1.3 allows clients to send data on the first flight if the endpoints have a shared crypographic secret (pre-shared key). This means that clients can send early data if they have a valid session ticket received in a previous @@ -593,39 +716,29 @@ ok GET, can usually be regarded as safe but even they can be exploited by a large number of replays causing resource limit exhaustion and other similar problems.

    An example of sending early data with automatic and manual session ticket handling:

    - -

    The Early Data feature is experimental in this version of OTP. -

    -
    -

    Server (with NSS key logging)

    +

    Server

    early_data_server() -> application:load(ssl), {ok, _} = application:ensure_all_started(ssl), Port = 11029, - LOpts = [{certfile, ?SERVER_CERT}, - {keyfile, ?SERVER_KEY}, - {reuseaddr, true}, - {versions, ['tlsv1.2','tlsv1.3']}, - {session_tickets, stateless}, - {early_data, enabled}, - {keep_secrets, true} %% Enable NSS key log (debug option) - ], + LOpts = [{certs_keys, [#{certfile => "cert.pem", keyfile => "key.pem"}]}, + {reuseaddr, true}, + {versions, ['tlsv1.2','tlsv1.3']}, + {session_tickets, stateless}, + {early_data, enabled}, + ], {ok, LSock} = ssl:listen(Port, LOpts), %% Accept first connection - {ok, CSock0} = ssl:transport_accept(LSock), - {ok, _} = ssl:handshake(CSock0), + {ok, ASock0} = ssl:transport_accept(LSock), + {ok, CSock0} = ssl:handshake(ASock0), %% Accept second connection - {ok, CSock1} = ssl:transport_accept(LSock), - {ok, Sock} = ssl:handshake(CSock1), + {ok, ASock1} = ssl:transport_accept(LSock), + {ok, CSock1} = ssl:handshake(ASock1), Sock. -

    Exporting the secrets (optional)

    - - {ok, [{keylog, KeylogItems}]} = ssl:connection_information(Sock, [keylog]). - file:write_file("key.log", [[KeylogItem,$\n] || KeylogItem <- KeylogItems]). - +

    Client (automatic ticket handling):

    early_data_auto() -> @@ -634,18 +747,19 @@ ok {ok, _} = application:ensure_all_started(ssl), Port = 11029, Data = <<"HEAD / HTTP/1.1\r\nHost: \r\nConnection: close\r\n">>, - COpts0 = [{cacertfile, ?CA_CERT}, + COpts0 = [{cacertfile, "cacerts.pem"}, {versions, ['tlsv1.2', 'tlsv1.3']}, {session_tickets, auto}], {ok, Sock0} = ssl:connect("localhost", Port, COpts0), %% Wait for session tickets timer:sleep(500), - %% Close socket if server cannot handle multiple connections e.g. openssl s_server + %% Close socket if server cannot handle multiple + %% connections e.g. openssl s_server ssl:close(Sock0), %% Second handshake 0-RTT - COpts1 = [{cacertfile, ?CA_CERT}, + COpts1 = [{cacertfile, "cacerts.pem"}, {versions, ['tlsv1.2', 'tlsv1.3']}, {session_tickets, auto}, {early_data, Data}], @@ -660,7 +774,7 @@ ok {ok, _} = application:ensure_all_started(ssl), Port = 11029, Data = <<"HEAD / HTTP/1.1\r\nHost: \r\nConnection: close\r\n">>, - COpts0 = [{cacertfile, ?CA_CERT}, + COpts0 = [{cacertfile, "cacerts.pem"}, {versions, ['tlsv1.2', 'tlsv1.3']}, {session_tickets, manual}], {ok, Sock0} = ssl:connect("localhost", Port, COpts0), @@ -677,7 +791,7 @@ ok ssl:close(Sock0), %% Second handshake 0-RTT - COpts1 = [{cacertfile, ?CA_CERT}, + COpts1 = [{cacertfile, "cacerts.pem"}, {versions, ['tlsv1.2', 'tlsv1.3']}, {session_tickets, manual}, {use_ticket, [Ticket]}, @@ -736,7 +850,7 @@ ok less than ticket lifetime.

    Actual ticket age shall be less than the ticket lifetime (stateless session tickets contain the servers timestamp when the ticket was issued).

    -

    Ticket shall be used within specified time window (freshness checks).

    +

    ClientHello created with the ticket shall be sent relatively recently (freshness checks).

    If all above checks passed both current and old Bloom filters are checked to detect if binder was already seen. Being a probabilistic data structure, false positives can occur and they trigger a full handshake.

    @@ -745,4 +859,14 @@ ok
    + +
    + Using DTLS + +

    Using DTLS has basically the same API as TLS. You need to add the option {protocol, dtls} to the connect and listen functions. For example

    + + client> {ok, Socket} = ssl:connect("localhost", 9999, [{protocol, dtls}, +{verify, verify_peer},{cacertfile, "cacerts.pem"}], infinity). +{ok,{sslsocket, [...]}} +
    diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile index 5c456c6a1a27..817ff2b00d77 100644 --- a/lib/ssl/examples/certs/Makefile +++ b/lib/ssl/examples/certs/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2016. All Rights Reserved. +# Copyright Ericsson AB 2003-2022. 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. @@ -42,7 +42,7 @@ TARGET_FILES= # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -fr $(TARGET_FILES) *~ *.beam diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile index 7335bb2bb828..8b0435bfc419 100644 --- a/lib/ssl/examples/src/Makefile +++ b/lib/ssl/examples/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2016. All Rights Reserved. +# Copyright Ericsson AB 2003-2022. 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. @@ -51,7 +51,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -fr $(TARGET_FILES) *~ *.beam diff --git a/lib/ssl/internal_doc/pem_and_cert_cache.md b/lib/ssl/internal_doc/pem_and_cert_cache.md new file mode 100644 index 000000000000..52fac1e6fef9 --- /dev/null +++ b/lib/ssl/internal_doc/pem_and_cert_cache.md @@ -0,0 +1,39 @@ +# Notes on the PEM and cert caches +## Data relations + + |---------------| |------------------------| + | PemCache | | CertDb | + |---------------| * |------------------------| + | FilePath (PK) | +---- | {Ref, SN, Issuer} (PK) | + | FileContent | | | Cert (Subject) | + |---------------| | |------------------------| + |0,1 | + | +-----------+ + |0,1 |1 + |-----------------| |------------| + | FileMapDb | | RefDb | + |-----------------|1 1 |------------| + | CaCertFile (PK) |---------------| Ref (PK) | + | Ref (FK) | | Counter | + |-----------------| |------------| + +### PemCache +1. stores a copy of file content in memory +2. includes files from cacertfile, certfile, keyfile options +3. content is added unless FileMapDb table contains entry with specified path + +### FileMapDb +1. holds relation between specific path (PEM file with CA certificates) and a ref +2. ref is generated when file from path is added for 1st time +3. ref is used as path identifier in CertDb and RefDb tables + +### RefDb +1. holds an active connections counter for a specific ref +2. when counter reaches zero - related data in CertDb, FileMapDb, RefDb is deleted + +### CertDb +1. holds decoded CA ceritificates (only those taken from cacertfile option) +2. used for building certificate chains +3. it is an ETS set table - when iterating in search of Issuer certificate, + processing order is not guaranted +4. Table key is: {Ref, SerialNumber, Issuer} diff --git a/lib/ssl/src/.gitignore b/lib/ssl/src/.gitignore new file mode 100644 index 000000000000..3f9cfafd3378 --- /dev/null +++ b/lib/ssl/src/.gitignore @@ -0,0 +1 @@ +deps diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index 1e55bb497df9..6395834fe92b 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -39,6 +39,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) # ---------------------------------------------------- BEHAVIOUR_MODULES= \ + ssl_trace \ ssl_crl_cache_api \ ssl_session_cache_api @@ -94,8 +95,10 @@ MODULES= \ tls_dtls_connection \ tls_connection \ tls_connection_sup \ - tls_connection_1_3 \ - tls_gen_connection \ + tls_server_connection_1_3 \ + tls_client_connection_1_3 \ + tls_gen_connection_1_3 \ + tls_gen_connection \ tls_handshake \ tls_handshake_1_3 \ tls_record \ @@ -173,7 +176,7 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \ # Targets # ---------------------------------------------------- -opt debug: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(DEP_FILE) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(DEP_FILE) deps: $(DEP_FILE) diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl index 1bd33c0ff2e5..aa93b5482abc 100644 --- a/lib/ssl/src/dtls_connection.erl +++ b/lib/ssl/src/dtls_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -88,7 +88,7 @@ %% | Abbrev Flight 1 to Abbrev Flight 2 part 1 %% | %% New session | Resumed session -%% WAIT_OCSP_STAPELING CERTIFY <----------------------------------> ABBRIVIATED +%% WAIT_OCSP_STAPLING CERTIFY <----------------------------------> ABBREVIATED %% %% <- Possibly Receive -- | | %% OCSP Stapel ------> | Send/ Recv Flight 5 | @@ -155,29 +155,31 @@ code_change/4, format_status/2]). +%% Tracing +-export([handle_trace/3]). + %%==================================================================== %% Internal application API -%%==================================================================== +%%==================================================================== %%==================================================================== %% Setup -%%==================================================================== +%%==================================================================== init([Role, Host, Port, Socket, Options, User, CbInfo]) -> process_flag(trap_exit, true), - State0 = #state{protocol_specific = Map} = - initial_state(Role, Host, Port, Socket, Options, User, CbInfo), + State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo), try - State = ssl_gen_statem:ssl_config(State0#state.ssl_options, + State = ssl_gen_statem:init_ssl_config(State0#state.ssl_options, Role, State0), gen_statem:enter_loop(?MODULE, [], initial_hello, State) catch throw:Error -> - EState = State0#state{protocol_specific = - Map#{error => Error}}, + #state{protocol_specific = Map} = State0, + EState = State0#state{protocol_specific = Map#{error => Error}}, gen_statem:enter_loop(?MODULE, [], config_error, EState) end. %%==================================================================== -%% Handshake -%%==================================================================== +%% Handshake +%%==================================================================== renegotiate(#state{static_env = #static_env{role = client}} = State0, Actions) -> %% Handle same way as if server requested %% the renegotiation @@ -192,7 +194,7 @@ renegotiate(#state{static_env = #static_env{role = server}} = State0, Actions) - dtls_gen_connection:next_event(hello, no_record, State, Actions ++ MoreActions). %%-------------------------------------------------------------------- -%% State functions +%% State functions %%-------------------------------------------------------------------- %%-------------------------------------------------------------------- -spec initial_hello(gen_statem:event_type(), @@ -200,7 +202,7 @@ renegotiate(#state{static_env = #static_env{role = server}} = State0, Actions) - gen_statem:state_function_result(). %%-------------------------------------------------------------------- initial_hello(enter, _, State) -> - {keep_state, State}; + {keep_state, State}; initial_hello({call, From}, {start, Timeout}, #state{static_env = #static_env{host = Host, port = Port, @@ -211,13 +213,14 @@ initial_hello({call, From}, {start, Timeout}, session_cache_cb = CacheCb}, protocol_specific = PS, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, ssl_options = #{versions := Versions} = SslOpts, session = Session0, connection_states = ConnectionStates0 } = State0) -> Packages = maps:get(active_n, PS), dtls_socket:setopts(Transport, Socket, [{active,Packages}]), + CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts), Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs), Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation), @@ -297,34 +300,32 @@ hello(internal, #client_hello{cookie = <<>>, catch throw:#alert{} = Alert -> alert_or_reset_connection(Alert, ?FUNCTION_NAME, State0) end; -hello(internal, #hello_verify_request{cookie = Cookie}, +hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #static_env{role = client, host = Host, port = Port}, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}, ocsp_stapling_state = OcspState0} = HsEnv, connection_env = CEnv, - ssl_options = #{ocsp_stapling := OcspStaplingOpt, - ocsp_nonce := OcspNonceOpt} = SslOpts, + ssl_options = SslOpts, session = #session{session_id = Id}, connection_states = ConnectionStates0, protocol_specific = PS } = State0) -> - OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt), + OcspNonce = tls_handshake:ocsp_nonce(SslOpts), Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts, Id, Renegotiation, OcspNonce), Version = Hello#client_hello.client_version, - State1 = prepare_flight(State0#state{handshake_env = - HsEnv#handshake_env{tls_handshake_history - = ssl_handshake:init_handshake_history(), - ocsp_stapling_state = - OcspState0#{ocsp_nonce => OcspNonce}}}), - - {State2, Actions} = dtls_gen_connection:send_handshake(Hello, State1), - - State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, % RequestedVersion - protocol_specific = PS#{current_cookie_secret => Cookie} - }, + State1 = + prepare_flight( + State0#state{handshake_env = + HsEnv#handshake_env{ + tls_handshake_history = ssl_handshake:init_handshake_history(), + ocsp_stapling_state = OcspState0#{ocsp_nonce => OcspNonce}}}), + {State2, Actions} = dtls_gen_connection:send_handshake(Hello, State1), + State = State2#state{connection_env = + CEnv#connection_env{negotiated_version = Version}, % RequestedVersion + protocol_specific = PS#{current_cookie_secret => Cookie}}, dtls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, Actions); hello(internal, #client_hello{extensions = Extensions} = Hello, #state{handshake_env = #handshake_env{continue_status = pause}, @@ -372,11 +373,11 @@ hello(internal, #server_hello{} = Hello, try {Version, NewId, ConnectionStates, ProtoExt, Protocol, OcspState} = dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation, OldId), - tls_dtls_connection:handle_session(Hello, - Version, NewId, ConnectionStates, ProtoExt, Protocol, - State#state{handshake_env = - HsEnv#handshake_env{ - ocsp_stapling_state = maps:merge(OcspState0,OcspState)}}) + tls_dtls_connection:handle_session( + Hello, Version, NewId, ConnectionStates, ProtoExt, Protocol, + State#state{handshake_env = + HsEnv#handshake_env{ + ocsp_stapling_state = maps:merge(OcspState0,OcspState)}}) catch throw:#alert{} = Alert -> ssl_gen_statem:handle_own_alert(Alert, ?FUNCTION_NAME, State) end; @@ -478,10 +479,7 @@ wait_cert_verify(info, Event, State) -> wait_cert_verify(state_timeout, Event, State) -> handle_state_timeout(Event, ?FUNCTION_NAME, State); wait_cert_verify(Type, Event, State) -> - try tls_dtls_connection:gen_handshake(?FUNCTION_NAME, Type, Event, State) - catch throw:#alert{} = Alert -> - ssl_gen_statem:handle_own_alert(Alert, ?FUNCTION_NAME, State) - end. + gen_handshake(?FUNCTION_NAME, Type, Event, State). %%-------------------------------------------------------------------- -spec cipher(gen_statem:event_type(), term(), #state{}) -> @@ -505,20 +503,27 @@ cipher(internal = Type, #finished{} = Event, #state{connection_states = Connecti cipher(state_timeout, Event, State) -> handle_state_timeout(Event, ?FUNCTION_NAME, State); cipher(Type, Event, State) -> - gen_handshake(?FUNCTION_NAME, Type, Event, State). + gen_handshake(?FUNCTION_NAME, Type, Event, State). %%-------------------------------------------------------------------- -spec connection(gen_statem:event_type(), #hello_request{} | #client_hello{}| term(), #state{}) -> gen_statem:state_function_result(). %%-------------------------------------------------------------------- -connection(enter, _, #state{connection_states = Cs0} = State0) -> - State = case maps:is_key(previous_cs, Cs0) of - false -> - State0; - true -> - Cs = maps:remove(previous_cs, Cs0), - State0#state{connection_states = Cs} +connection(enter, _, #state{connection_states = Cs0, + static_env = Env} = State0) -> + State = case Env of + #static_env{socket = {Listener, {Client, _}}} -> + dtls_packet_demux:connection_setup(Listener, Client), + case maps:is_key(previous_cs, Cs0) of + false -> + State0; + true -> + Cs = maps:remove(previous_cs, Cs0), + State0#state{connection_states = Cs} + end; + _ -> %% client + State0 end, {keep_state, State}; connection(info, Event, State) -> @@ -530,13 +535,14 @@ connection(internal, #hello_request{}, #state{static_env = #static_env{host = Ho session_cache_cb = CacheCb }, handshake_env = #handshake_env{renegotiation = {Renegotiation, _}}, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, session = Session0, ssl_options = #{versions := Versions} = SslOpts, connection_states = ConnectionStates0, protocol_specific = PS } = State0) -> #{current_cookie_secret := Cookie} = PS, + CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts), Session = ssl_session:client_select_session({Host, Port, SslOpts}, Cache, CacheCb, Session0, CertKeyPairs), Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation, undefined), @@ -571,14 +577,20 @@ connection(internal, #client_hello{}, #state{static_env = #static_env{role = ser dtls_gen_connection:next_event(?FUNCTION_NAME, Record, State); connection(internal, new_connection, #state{ssl_options=SSLOptions, handshake_env=HsEnv, + static_env = #static_env{socket = {Listener, {Client, _}}}, connection_states = OldCs} = State) -> case maps:get(previous_cs, OldCs, undefined) of undefined -> - BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), - ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation), - ConnectionStates = ConnectionStates0#{previous_cs => OldCs}, - {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}}, - connection_states = ConnectionStates}}; + case dtls_packet_demux:new_connection(Listener, Client) of + true -> + {keep_state, State}; + false -> + BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), + ConnectionStates0 = dtls_record:init_connection_states(server, BeastMitigation), + ConnectionStates = ConnectionStates0#{previous_cs => OldCs}, + {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {false, first}}, + connection_states = ConnectionStates}} + end; _ -> %% Someone spamming new_connection, just drop them {keep_state, State} @@ -640,8 +652,9 @@ format_status(Type, Data) -> %%% Internal functions %%-------------------------------------------------------------------- initial_state(Role, Host, Port, Socket, - {#{client_renegotiation := ClientRenegotiation} = SSLOptions, SocketOptions, Trackers}, User, + {SSLOptions, SocketOptions, Trackers}, User, {CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) -> + put(log_level, maps:get(log_level, SSLOptions)), BeastMitigation = maps:get(beast_mitigation, SSLOptions, disabled), ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation), #{session_cb := SessionCacheCb} = ssl_config:pre_1_3_session_opts(Role), @@ -666,13 +679,11 @@ initial_state(Role, Host, Port, Socket, handshake_env = #handshake_env{ tls_handshake_history = ssl_handshake:init_handshake_history(), renegotiation = {false, first}, - allow_renegotiate = ClientRenegotiation + allow_renegotiate = maps:get(client_renegotiation, SSLOptions, undefined) }, connection_env = #connection_env{user_application = {Monitor, User}}, socket_options = SocketOptions, - %% We do not want to save the password in the state so that - %% could be written in the clear into error logs. - ssl_options = SSLOptions#{password => undefined}, + ssl_options = SSLOptions, session = #session{is_resumable = false}, connection_states = ConnectionStates, protocol_buffers = #protocol_buffers{}, @@ -695,14 +706,14 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State handshake_env = #handshake_env{kex_algorithm = KeyExAlg, renegotiation = {Renegotiation, _}, negotiated_protocol = CurrentProtocol} = HsEnv, - connection_env = #connection_env{cert_key_pairs = CertKeyPairs} = CEnv, + connection_env = #connection_env{cert_key_alts = CertKeyAlts} = CEnv, session = Session0, ssl_options = SslOpts} = tls_dtls_connection:handle_sni_extension(State0, Hello), SessionTracker = proplists:get_value(session_id_tracker, Trackers), {Version, {Type, Session}, ConnectionStates, Protocol0, ServerHelloExt, HashSign} = dtls_handshake:hello(Hello, SslOpts, {SessionTracker, Session0, - ConnectionStates0, CertKeyPairs, KeyExAlg}, Renegotiation), + ConnectionStates0, CertKeyAlts, KeyExAlg}, Renegotiation), Protocol = case Protocol0 of undefined -> CurrentProtocol; _ -> Protocol0 @@ -723,11 +734,12 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello, State handle_state_timeout(flight_retransmission_timeout, StateName, #state{protocol_specific = - #{flight_state := {retransmit, _NextTimeout}}} = State0) -> + #{flight_state := {retransmit, CurrentTimeout}}} = State0) -> {State1, Actions0} = dtls_gen_connection:send_handshake_flight(State0, retransmit_epoch(StateName, State0)), - {next_state, StateName, State, Actions} = + {next_state, StateName, #state{protocol_specific = PS} = State2, Actions} = dtls_gen_connection:next_event(StateName, no_record, State1, Actions0), + State = State2#state{protocol_specific = PS#{flight_state => {retransmit, new_timeout(CurrentTimeout)}}}, %% This will reset the retransmission timer by repeating the enter state event {repeat_state, State, Actions}. @@ -747,25 +759,30 @@ alert_or_reset_connection(Alert, StateName, #state{connection_states = Cs} = Sta {next_state, connection, NewState} end. +gen_handshake(_, {call, _From}, {application_data, _Data}, _State) -> + {keep_state_and_data, [postpone]}; gen_handshake(StateName, Type, Event, State) -> try tls_dtls_connection:StateName(Type, Event, State) catch throw:#alert{}=Alert -> alert_or_reset_connection(Alert, StateName, State); - error:_ -> + error:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data), alert_or_reset_connection(Alert, StateName, State) end. gen_info(Event, connection = StateName, State) -> try dtls_gen_connection:handle_info(Event, StateName, State) - catch error:_ -> + catch error:Reason:ST -> + ?SSL_LOG(info, internal_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, malformed_data), alert_or_reset_connection(Alert, StateName, State) end; gen_info(Event, StateName, State) -> try dtls_gen_connection:handle_info(Event, StateName, State) - catch error:_ -> + catch error:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), Alert = ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,malformed_handshake_data), alert_or_reset_connection(Alert, StateName, State) end. @@ -797,7 +814,7 @@ handle_flight_timer(#state{protocol_specific = #{flight_state := reliable}} = St {State, []}. start_retransmision_timer(Timeout, #state{protocol_specific = PS} = State) -> - {State#state{protocol_specific = PS#{flight_state => {retransmit, new_timeout(Timeout)}}}, + {State#state{protocol_specific = PS#{flight_state => {retransmit, Timeout}}}, [{state_timeout, Timeout, flight_retransmission_timeout}]}. new_timeout(N) when N =< 30000 -> @@ -859,3 +876,12 @@ is_time_to_renegotiate(N, M) when N < M-> is_time_to_renegotiate(_,_) -> true. +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(hbn, + {call, {?MODULE, connection, + [_Type = info, Event, _State]}}, + Stack) -> + {io_lib:format("Type = info Event = ~W ", [Event, 10]), Stack}. diff --git a/lib/ssl/src/dtls_gen_connection.erl b/lib/ssl/src/dtls_gen_connection.erl index ce8caa65b8d8..95b0302b7418 100644 --- a/lib/ssl/src/dtls_gen_connection.erl +++ b/lib/ssl/src/dtls_gen_connection.erl @@ -81,10 +81,10 @@ %%==================================================================== %% Setup %%==================================================================== -start_fsm(Role, Host, Port, Socket, {#{erl_dist := false},_, Tracker} = Opts, +start_fsm(Role, Host, Port, Socket, {_,_, Tracker} = Opts, User, {CbModule, _, _, _, _} = CbInfo, - Timeout) -> - try + Timeout) -> + try {ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket, Opts, User, CbInfo]), {ok, SslSocket} = ssl_gen_statem:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker), @@ -565,10 +565,9 @@ handle_info({CloseTag, Socket}, StateName, %% with widespread implementation practice. case (Active == false) andalso (CTs =/= []) of false -> - case Version of - {254, N} when N =< 253 -> + if (?DTLS_GTE(Version, ?DTLS_1_2)) -> ok; - _ -> + true -> %% As invalidate_sessions here causes performance issues, %% we will conform to the widespread implementation %% practice and go against the spec @@ -592,6 +591,12 @@ handle_info(new_cookie_secret, StateName, {next_state, StateName, State#state{protocol_specific = CookieInfo#{current_cookie_secret => dtls_v1:cookie_secret(), previous_cookie_secret => Secret}}}; +handle_info({socket_reused, Client}, StateName, + #state{static_env = #static_env{socket = {_, {Client, _}}}} = State) -> + Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed), + ssl_gen_statem:handle_normal_shutdown(Alert#alert{role = server}, StateName, State), + {stop, {shutdown, transport_closed}, State}; + handle_info(Msg, StateName, State) -> ssl_gen_statem:handle_info(Msg, StateName, State). @@ -648,7 +653,7 @@ next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{ ssl_options = SslOpts} = State0) -> case dtls_record:get_dtls_records(Data, {DataTag, StateName, Version, - [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]}, + [dtls_record:protocol_version_name(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]}, Buf0, SslOpts) of {Records, Buf1} -> CT1 = CT0 ++ Records, diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl index 10258dcc508b..85faad11b686 100644 --- a/lib/ssl/src/dtls_handshake.erl +++ b/lib/ssl/src/dtls_handshake.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -118,11 +118,12 @@ hello(#client_hello{client_version = ClientVersion} = Hello, Version = ssl_handshake:select_version(dtls_record, ClientVersion, Versions), handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation). -cookie(Key, Address, Port, #client_hello{client_version = {Major, Minor}, +cookie(Key, Address, Port, #client_hello{client_version = Version, random = Random, session_id = SessionId, cipher_suites = CipherSuites, compression_methods = CompressionMethods}) -> + {Major, Minor} = Version, CookieData = [address_to_bin(Address, Port), <>, Random, SessionId, CipherSuites, CompressionMethods], @@ -189,7 +190,7 @@ handle_client_hello(Version, TLSVersion = dtls_v1:corresponding_tls_version(Version), AvailableHashSigns = ssl_handshake:available_signature_algs( ClientHashSigns, SupportedHashSigns, TLSVersion), - ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, TLSVersion, ECCOrder), + ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder), {Type, #session{cipher_suite = CipherSuite, own_certificates = [OwnCert |_]} = Session1} = ssl_handshake:select_session(SugesstedId, CipherSuites, @@ -219,32 +220,35 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites, HelloExt, SslOpts, Session0, ConnectionStates0, Renegotiation, HashSign) -> {Session, ConnectionStates, Protocol, ServerHelloExt} = ssl_handshake:handle_client_hello_extensions(dtls_record, Random, CipherSuites, - HelloExt, dtls_v1:corresponding_tls_version(Version), - SslOpts, Session0, + HelloExt, + dtls_v1:corresponding_tls_version(Version), + SslOpts, Session0, ConnectionStates0, Renegotiation, Session0#session.is_resumable), {Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt, HashSign}. handle_server_hello_extensions(Version, SessionId, Random, CipherSuite, - Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation, IsNew) -> + Compression, HelloExt, SslOpt, ConnectionStates0, + Renegotiation, IsNew) -> {ConnectionStates, ProtoExt, Protocol, OcspState} = - ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite, - Compression, HelloExt, - dtls_v1:corresponding_tls_version(Version), - SslOpt, ConnectionStates0, Renegotiation, IsNew), + ssl_handshake:handle_server_hello_extensions( + dtls_record, Random, CipherSuite, Compression, HelloExt, + dtls_v1:corresponding_tls_version(Version), SslOpt, ConnectionStates0, + Renegotiation, IsNew), {Version, SessionId, ConnectionStates, ProtoExt, Protocol, OcspState}. %%-------------------------------------------------------------------- -enc_handshake(#hello_verify_request{protocol_version = {Major, Minor}, +enc_handshake(#hello_verify_request{protocol_version = Version, cookie = Cookie}, _Version) -> CookieLength = byte_size(Cookie), + {Major,Minor} = Version, {?HELLO_VERIFY_REQUEST, <>}; enc_handshake(#hello_request{}, _Version) -> {?HELLO_REQUEST, <<>>}; -enc_handshake(#client_hello{client_version = {Major, Minor}, +enc_handshake(#client_hello{client_version = ClientVersion, random = Random, session_id = SessionID, cookie = Cookie, @@ -257,8 +261,8 @@ enc_handshake(#client_hello{client_version = {Major, Minor}, CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), - ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions, - dtls_v1:corresponding_tls_version({Major, Minor})), + ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions), + {Major,Minor} = ClientVersion, {?CLIENT_HELLO, <>) -> - #hello_verify_request{protocol_version = {Major, Minor}, - cookie = Cookie}; + #hello_verify_request{protocol_version = {Major,Minor}, + cookie = Cookie}; decode_handshake(Version, Tag, <>) -> %% DTLS specifics stripped @@ -388,9 +392,9 @@ decode_handshake_fragments(< + dtls_handshake_next_fragments = Fragments0, + dtls_handshake_later_fragments = LaterFragments0} = + Buffers0)-> case reassemble_fragments(Fragment, Fragments0) of {more_data, Fragments} -> {more_data, Buffers0#protocol_buffers{dtls_handshake_next_fragments = Fragments}}; diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl index 2c89ce15d55c..ea7a1d72a070 100644 --- a/lib/ssl/src/dtls_handshake.hrl +++ b/lib/ssl/src/dtls_handshake.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -29,9 +29,10 @@ -include("tls_handshake.hrl"). %% Common TLS and DTLS records and Constantes -include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes -include("ssl_api.hrl"). +-include("ssl_record.hrl"). -define(HELLO_VERIFY_REQUEST, 3). --define(HELLO_VERIFY_REQUEST_VERSION, {254, 255}). +-define(HELLO_VERIFY_REQUEST_VERSION, ?DTLS_1_0). -record(hello_verify_request, { protocol_version, @@ -48,10 +49,9 @@ }). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% RFC 7764 Datagram Transport Layer Security (DTLS) Extension to Establish Keys +%% RFC 5764 Datagram Transport Layer Security (DTLS) Extension to Establish Keys %% for the Secure Real-time Transport Protocol (SRTP) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Not supported --define(USE_SRTP, 14). +%% Defined in ssl_handshake.hrl because extension parsing code is in ssl_handshake.erl -endif. % -ifdef(dtls_handshake). diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl index 19f1d2359cf4..c4cdb2eb01e6 100644 --- a/lib/ssl/src/dtls_packet_demux.erl +++ b/lib/ssl/src/dtls_packet_demux.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2016-2022. All Rights Reserved. +%% Copyright Ericsson AB 2016-2023. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,6 +33,8 @@ sockname/1, close/1, new_owner/1, + new_connection/2, + connection_setup/2, get_all_opts/1, set_all_opts/2, get_sock_opts/2, @@ -55,7 +57,6 @@ dtls_options, emulated_options, dtls_msq_queues = kv_new(), - clients = set_new(), dtls_processes = kv_new(), accepters = queue:new(), first, @@ -85,6 +86,12 @@ close(PacketSocket) -> new_owner(PacketSocket) -> call(PacketSocket, new_owner). +new_connection(PacketSocket, Client) -> + call(PacketSocket, {new_connection, Client, self()}). + +connection_setup(PacketSocket, Client) -> + gen_server:cast(PacketSocket, {connection_setup, Client}). + get_sock_opts(PacketSocket, SplitSockOpts) -> call(PacketSocket, {get_sock_opts, SplitSockOpts}). get_all_opts(PacketSocket) -> @@ -146,6 +153,18 @@ handle_call(close, _, #state{dtls_processes = Processes, end; handle_call(new_owner, _, State) -> {reply, ok, State#state{close = false, first = true}}; +handle_call({new_connection, Old, _Pid}, _, + #state{accepters = Accepters, dtls_msq_queues = MsgQs0} = State) -> + case queue:is_empty(Accepters) of + false -> + OldQueue = kv_get(Old, MsgQs0), + MsgQs1 = kv_delete(Old, MsgQs0), + MsgQs = kv_insert({old,Old}, OldQueue, MsgQs1), + {reply, true, State#state{dtls_msq_queues = MsgQs}}; + true -> + {reply, false, State} + end; + handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listener = Socket, emulated_options = EmOpts} = State) -> case get_socket_opts(Socket, SocketOptNames) of @@ -170,7 +189,16 @@ handle_call({getstat, Options}, _, #state{listener = Socket, transport = {Tran handle_cast({active_once, Client, Pid}, State0) -> State = handle_active_once(Client, Pid, State0), - {noreply, State}. + {noreply, State}; +handle_cast({connection_setup, Client}, #state{dtls_msq_queues = MsgQueues} = State) -> + case kv_lookup({old, Client}, MsgQueues) of + none -> + {noreply, State}; + {value, {Pid, _}} -> + Pid ! {socket_reused, Client}, + %% Will be deleted when handling DOWN message + {noreply, State} + end. handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket, transport = {_,Transport,_,_,_}} = State0) -> State = handle_datagram({IP, InPortNo}, Msg, State0), @@ -190,24 +218,40 @@ handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket, t ?LOG_NOTICE(Report), {noreply, State}; handle_info({ErrorTag, Socket, Error}, #state{listener = Socket, transport = {_,_,_, ErrorTag,_}} = State) -> - Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]), + Report = io_lib:format("SSL Packet muliplexer shutdown: Socket error: ~p ~n", [Error]), ?LOG_NOTICE(Report), {noreply, State#state{close=true}}; -handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients, - dtls_processes = Processes0, - dtls_msq_queues = MsgQueues0, - close = ListenClosed} = State) -> +handle_info({'DOWN', _, process, Pid, _}, + #state{dtls_processes = Processes0, + dtls_msq_queues = MsgQueues0, + close = ListenClosed} = State0) -> Client = kv_get(Pid, Processes0), Processes = kv_delete(Pid, Processes0), - MsgQueues = kv_delete(Client, MsgQueues0), + State = case kv_lookup(Client, MsgQueues0) of + none -> + MsgQueues1 = kv_delete({old, Client}, MsgQueues0), + State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1}; + {value, {Pid, _}} -> + MsgQueues1 = kv_delete(Client, MsgQueues0), + %% Restore old process if exists + case kv_lookup({old, Client}, MsgQueues1) of + none -> + State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1}; + {value, Old} -> + MsgQueues2 = kv_delete({old, Client}, MsgQueues1), + MsgQueues = kv_insert(Client, Old, MsgQueues2), + State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues} + end; + {value, _} -> %% Old process died (just delete its queue) + MsgQueues1 = kv_delete({old, Client}, MsgQueues0), + State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1} + end, case ListenClosed andalso kv_empty(Processes) of true -> {stop, normal, State}; false -> - {noreply, State#state{clients = set_delete(Client, Clients), - dtls_processes = Processes, - dtls_msq_queues = MsgQueues}} + {noreply, State} end. terminate(_Reason, _State) -> @@ -219,55 +263,57 @@ code_change(_OldVsn, State, _Extra) -> %%%=================================================================== %%% Internal functions %%%=================================================================== -handle_datagram(Client, Msg, #state{clients = Clients, - accepters = AcceptorsQueue0} = State) -> - case set_is_member(Client, Clients) of - false -> +handle_datagram(Client, Msg, #state{dtls_msq_queues = MsgQueues, accepters = AcceptorsQueue0} = State) -> + case kv_lookup(Client, MsgQueues) of + none -> case queue:out(AcceptorsQueue0) of - {{value, {UserPid, From}}, AcceptorsQueue} -> - setup_new_connection(UserPid, From, Client, Msg, + {{value, {UserPid, From}}, AcceptorsQueue} -> + setup_new_connection(UserPid, From, Client, Msg, State#state{accepters = AcceptorsQueue}); {empty, _} -> %% Drop packet client will resend State end; - true -> - dispatch(Client, Msg, State) + {value, Queue} -> + dispatch(Queue, Client, Msg, State) end. -dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) -> - case kv_lookup(Client, MsgQueues) of - {value, Queue0} -> - case queue:out(Queue0) of - {{value, Pid}, Queue} when is_pid(Pid) -> - Pid ! Msg, - State#state{dtls_msq_queues = - kv_update(Client, Queue, MsgQueues)}; - {{value, _UDP}, _Queue} -> - State#state{dtls_msq_queues = - kv_update(Client, queue:in(Msg, Queue0), MsgQueues)}; - {empty, Queue} -> - State#state{dtls_msq_queues = - kv_update(Client, queue:in(Msg, Queue), MsgQueues)} - end +dispatch({Pid, Queue0}, Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) -> + case queue:out(Queue0) of + {{value, Pid}, Queue} when is_pid(Pid) -> + Pid ! Msg, + State#state{dtls_msq_queues = + kv_update(Client, {Pid, Queue}, MsgQueues)}; + {{value, _UDP}, _Queue} -> + State#state{dtls_msq_queues = + kv_update(Client, {Pid, queue:in(Msg, Queue0)}, MsgQueues)}; + {empty, Queue} -> + State#state{dtls_msq_queues = + kv_update(Client, {Pid, queue:in(Msg, Queue)}, MsgQueues)} end. + next_datagram(Socket, N) -> inet:setopts(Socket, [{active, N}]). handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) -> - Queue0 = kv_get(Client, MsgQueues), + {Key, Queue0} = case kv_lookup(Client, MsgQueues) of + {value, {Pid, Q0}} -> {Client, Q0}; + _ -> + OldKey = {old, Client}, + {Pid, Q0} = kv_get(OldKey, MsgQueues), + {OldKey, Q0} + end, case queue:out(Queue0) of - {{value, Pid}, _} when is_pid(Pid) -> - State0; - {{value, Msg}, Queue} -> - Pid ! Msg, - State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)}; - {empty, Queue0} -> - State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)} + {{value, Pid}, _} when is_pid(Pid) -> + State0; + {{value, Msg}, Queue} -> + Pid ! Msg, + State0#state{dtls_msq_queues = kv_update(Key, {Pid, Queue}, MsgQueues)}; + {empty, Queue0} -> + State0#state{dtls_msq_queues = kv_update(Key, {Pid, queue:in(Pid, Queue0)}, MsgQueues)} end. setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes, - clients = Clients, dtls_msq_queues = MsgQueues, dtls_options = DTLSOpts, port = Port, @@ -281,8 +327,7 @@ setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes, erlang:monitor(process, Pid), gen_server:reply(From, {ok, Pid, {Client, Socket}}), Pid ! Msg, - State#state{clients = set_insert(Client, Clients), - dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues), + State#state{dtls_msq_queues = kv_insert(Client, {Pid, queue:new()}, MsgQueues), dtls_processes = kv_insert(Pid, Client, Processes)}; {error, Reason} -> gen_server:reply(From, {error, Reason}), @@ -295,7 +340,7 @@ kv_lookup(Key, Store) -> gb_trees:lookup(Key, Store). kv_insert(Key, Value, Store) -> gb_trees:insert(Key, Value, Store). -kv_get(Key, Store) -> +kv_get(Key, Store) -> gb_trees:get(Key, Store). kv_delete(Key, Store) -> gb_trees:delete(Key, Store). @@ -304,15 +349,6 @@ kv_new() -> kv_empty(Store) -> gb_trees:is_empty(Store). -set_new() -> - gb_sets:empty(). -set_insert(Item, Set) -> - gb_sets:insert(Item, Set). -set_delete(Item, Set) -> - gb_sets:delete(Item, Set). -set_is_member(Item, Set) -> - gb_sets:is_member(Item, Set). - call(Server, Msg) -> try gen_server:call(Server, Msg, infinity) diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl index 6efc2dc8be88..c0030fe1dc06 100644 --- a/lib/ssl/src/dtls_record.erl +++ b/lib/ssl/src/dtls_record.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2021. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -43,7 +43,7 @@ -export([decode_cipher_text/2]). %% Protocol version handling --export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2, +-export([protocol_version/1, protocol_version_name/1, lowest_protocol_version/1, lowest_protocol_version/2, highest_protocol_version/1, highest_protocol_version/2, is_higher/2, supported_protocol_versions/0, is_acceptable_version/2, hello_version/2]). @@ -141,14 +141,14 @@ set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch %%-------------------------------------------------------------------- -spec init_connection_state_seq(ssl_record:ssl_version(), ssl_record:connection_states()) -> - ssl_record:connection_state(). + ssl_record:connection_state(). %% %% Description: Copy the read sequence number to the write sequence number %% This is only valid for DTLS in the first client_hello %%-------------------------------------------------------------------- -init_connection_state_seq({254, _}, +init_connection_state_seq(Version, #{current_read := #{epoch := 0, sequence_number := Seq}, - current_write := #{epoch := 0} = Write} = ConnnectionStates0) -> + current_write := #{epoch := 0} = Write} = ConnnectionStates0) when ?DTLS_1_X(Version)-> ConnnectionStates0#{current_write => Write#{sequence_number => Seq}}; init_connection_state_seq(_, ConnnectionStates) -> ConnnectionStates. @@ -175,9 +175,9 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}}, %% and returns it as a list of tls_compressed binaries also returns leftover %% data %%-------------------------------------------------------------------- -get_dtls_records(Data, Vinfo, Buffer, SslOpts) -> +get_dtls_records(Data, Vinfo, Buffer, #{log_level := LogLevel}) -> BinData = list_to_binary([Buffer, Data]), - get_dtls_records_aux(Vinfo, BinData, [], SslOpts). + get_dtls_records_aux(Vinfo, BinData, [], LogLevel). %%==================================================================== %% Encoding DTLS records @@ -263,85 +263,83 @@ decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) -> %% Protocol version handling %%==================================================================== + %%-------------------------------------------------------------------- --spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) -> - ssl_record:ssl_version() | dtls_atom_version(). +-spec protocol_version_name(dtls_atom_version()) -> ssl_record:ssl_version(). %% %% Description: Creates a protocol version record from a version atom %% or vice versa. %%-------------------------------------------------------------------- -protocol_version('dtlsv1.2') -> - {254, 253}; -protocol_version(dtlsv1) -> - {254, 255}; -protocol_version({254, 253}) -> + +protocol_version_name('dtlsv1.2') -> + ?DTLS_1_2; +protocol_version_name(dtlsv1) -> + ?DTLS_1_0. + +%%-------------------------------------------------------------------- +-spec protocol_version(ssl_record:ssl_version()) -> dtls_atom_version(). + +%% +%% Description: Creates a protocol version record from a version atom +%% or vice versa. +%%-------------------------------------------------------------------- + +protocol_version(?DTLS_1_2) -> 'dtlsv1.2'; -protocol_version({254, 255}) -> +protocol_version(?DTLS_1_0) -> dtlsv1. %%-------------------------------------------------------------------- -spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). %% %% Description: Lowes protocol version of two given versions %%-------------------------------------------------------------------- -lowest_protocol_version(Version = {M, N}, {M, O}) when N > O -> - Version; -lowest_protocol_version({M, _}, Version = {M, _}) -> - Version; -lowest_protocol_version(Version = {M,_}, {N, _}) when M > N -> - Version; -lowest_protocol_version(_,Version) -> - Version. +lowest_protocol_version(Version1, Version2) when ?DTLS_LT(Version1, Version2) -> + Version1; +lowest_protocol_version(_, Version2) -> + Version2. %%-------------------------------------------------------------------- -spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). %% %% Description: Lowest protocol version present in a list %%-------------------------------------------------------------------- -lowest_protocol_version([]) -> - lowest_protocol_version(); lowest_protocol_version(Versions) -> - [Ver | Vers] = Versions, - lowest_list_protocol_version(Ver, Vers). + check_protocol_version(Versions, fun lowest_protocol_version/2). %%-------------------------------------------------------------------- -spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version(). %% %% Description: Highest protocol version present in a list %%-------------------------------------------------------------------- -highest_protocol_version([]) -> - highest_protocol_version(); highest_protocol_version(Versions) -> - [Ver | Vers] = Versions, - highest_list_protocol_version(Ver, Vers). + check_protocol_version(Versions, fun highest_protocol_version/2). + + +check_protocol_version([], Fun) -> check_protocol_version(supported_protocol_versions(), Fun); +check_protocol_version([Ver | Versions], Fun) -> lists:foldl(Fun, Ver, Versions). %%-------------------------------------------------------------------- -spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version(). %% %% Description: Highest protocol version of two given versions %%-------------------------------------------------------------------- -highest_protocol_version(Version = {M, N}, {M, O}) when N < O -> - Version; -highest_protocol_version({M, _}, - Version = {M, _}) -> - Version; -highest_protocol_version(Version = {M,_}, - {N, _}) when M < N -> - Version; -highest_protocol_version(_,Version) -> - Version. + +highest_protocol_version(Version1, Version2) when ?DTLS_GT(Version1, Version2) -> + Version1; +highest_protocol_version(_, Version2) -> + Version2. %%-------------------------------------------------------------------- -spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean(). %% %% Description: Is V1 > V2 %%-------------------------------------------------------------------- -is_higher({M, N}, {M, O}) when N < O -> - true; -is_higher({M, _}, {N, _}) when M < N -> +is_higher(V1, V2) when ?DTLS_GT(V1, V2) -> true; is_higher(_, _) -> false. + %%-------------------------------------------------------------------- -spec supported_protocol_versions() -> [ssl_record:ssl_version()]. %% @@ -349,7 +347,7 @@ is_higher(_, _) -> %%-------------------------------------------------------------------- supported_protocol_versions() -> Fun = fun(Version) -> - protocol_version(Version) + protocol_version_name(Version) end, case application:get_env(ssl, dtls_protocol_version) of undefined -> @@ -397,7 +395,7 @@ is_acceptable_version(Version, Versions) -> -spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version(). hello_version(Version, Versions) -> case dtls_v1:corresponding_tls_version(Version) of - TLSVersion when TLSVersion >= {3, 3} -> + TLSVersion when ?TLS_GTE(TLSVersion, ?TLS_1_2) -> Version; _ -> lowest_protocol_version(Versions) @@ -423,40 +421,50 @@ initial_connection_state(ConnectionEnd, BeastMitigation) -> max_fragment_length => undefined }. -get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, <> = RawDTLSRecord, - Acc, #{log_level := LogLevel} = SslOpts) +get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, + <> = RawDTLSRecord, + Acc0, LogLevel) when ((StateName == hello) orelse ((StateName == certify) andalso (DataTag == udp)) - orelse ((StateName == abbreviated) andalso (DataTag == udp))) andalso ((Type == ?HANDSHAKE) - orelse - (Type == ?ALERT)) -> + orelse ((StateName == abbreviated) andalso (DataTag == udp))) + andalso ((Type == ?HANDSHAKE) orelse (Type == ?ALERT)) -> ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]), - case is_acceptable_version({MajVer, MinVer}, Versions) of + Version = {MajVer,MinVer}, + Acc = [#ssl_tls{type = Type, version = Version, + epoch = Epoch, sequence_number = SequenceNumber, + fragment = Data} | Acc0], + case is_acceptable_version(Version, Versions) of true -> - get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type, - version = {MajVer, MinVer}, - epoch = Epoch, sequence_number = SequenceNumber, - fragment = Data} | Acc], SslOpts); + get_dtls_records_aux(Vinfo, Rest, Acc, LogLevel); false -> - ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) - end; -get_dtls_records_aux({_, _, Version, _} = Vinfo, <> = RawDTLSRecord, - Acc, #{log_level := LogLevel} = SslOpts) when (Type == ?APPLICATION_DATA) orelse - (Type == ?HANDSHAKE) orelse - (Type == ?ALERT) orelse - (Type == ?CHANGE_CIPHER_SPEC) -> + Acc0, LogLevel) + when (Type == ?APPLICATION_DATA) orelse + (Type == ?HANDSHAKE) orelse + (Type == ?ALERT) orelse + (Type == ?CHANGE_CIPHER_SPEC) -> ssl_logger:debug(LogLevel, inbound, 'record', [RawDTLSRecord]), - case {MajVer, MinVer} of - Version -> - get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type, - version = {MajVer, MinVer}, - epoch = Epoch, sequence_number = SequenceNumber, - fragment = Data} | Acc], SslOpts); - _ -> + Version1 = {MajVer,MinVer}, + Acc = [#ssl_tls{type = Type, version = Version, + epoch = Epoch, sequence_number = SequenceNumber, + fragment = Data} | Acc0], + if Version1 =:= Version -> + get_dtls_records_aux(Vinfo, Rest, Acc, LogLevel); + Type == ?HANDSHAKE -> + case is_acceptable_version(Version1, Versions) of + true -> + get_dtls_records_aux(Vinfo, Rest, Acc, LogLevel); + false -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end; + true -> ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) end; get_dtls_records_aux(_, < Length = erlang:iolist_size(Fragment), + {MajVer,MinVer} = Version, {[<>, Fragment], WriteState#{sequence_number => Seq + 1}}. @@ -624,32 +633,19 @@ calc_mac_hash(Type, Version, #{mac_secret := MacSecret, mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment). -mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) -> +mac_hash(Version, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment) -> + {Major,Minor} = Version, Value = [<>, Fragment], dtls_v1:hmac_hash(MacAlg, MacSecret, Value). -start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) -> +start_additional_data(Type, Version, Epoch, SeqNo) -> + {MajVer,MinVer} = Version, <>. %%-------------------------------------------------------------------- -lowest_list_protocol_version(Ver, []) -> - Ver; -lowest_list_protocol_version(Ver1, [Ver2 | Rest]) -> - lowest_list_protocol_version(lowest_protocol_version(Ver1, Ver2), Rest). - -highest_list_protocol_version(Ver, []) -> - Ver; -highest_list_protocol_version(Ver1, [Ver2 | Rest]) -> - highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest). - -highest_protocol_version() -> - highest_protocol_version(supported_protocol_versions()). - -lowest_protocol_version() -> - lowest_protocol_version(supported_protocol_versions()). sufficient_dtlsv1_2_crypto_support() -> CryptoSupport = crypto:supports(), diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl index 3ac6d8226e26..851de7896368 100644 --- a/lib/ssl/src/dtls_v1.erl +++ b/lib/ssl/src/dtls_v1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2021. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -20,6 +20,7 @@ -module(dtls_v1). -include("ssl_cipher.hrl"). +-include("ssl_record.hrl"). -export([suites/1, all_suites/1, @@ -35,13 +36,13 @@ -define(COOKIE_BASE_TIMEOUT, 30000). --spec suites(Minor:: 253|255) -> [ssl_cipher_format:cipher_suite()]. +-spec suites(ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()]. -suites(Minor) -> +suites(Version) -> lists:filter(fun(Cipher) -> is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher)) end, - tls_v1:suites(corresponding_minor_tls_version(Minor))). + tls_v1:suites(corresponding_tls_version(Version))). all_suites(Version) -> lists:filter(fun(Cipher) -> is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher)) @@ -54,27 +55,30 @@ anonymous_suites(Version) -> end, ssl_cipher:anonymous_suites(corresponding_tls_version(Version))). -exclusive_suites(Minor) -> +exclusive_suites(Version) -> lists:filter(fun(Cipher) -> is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher)) end, - tls_v1:exclusive_suites(corresponding_minor_tls_version(Minor))). + tls_v1:exclusive_suites(corresponding_tls_version(Version))). -exclusive_anonymous_suites(Minor) -> +exclusive_anonymous_suites(Version) -> lists:filter(fun(Cipher) -> is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher)) end, - tls_v1:exclusive_anonymous_suites(corresponding_minor_tls_version(Minor))). + tls_v1:exclusive_anonymous_suites(corresponding_tls_version(Version))). hmac_hash(MacAlg, MacSecret, Value) -> tls_v1:hmac_hash(MacAlg, MacSecret, Value). -ecc_curves({_Major, Minor}) -> - tls_v1:ecc_curves(corresponding_minor_tls_version(Minor)). +ecc_curves(Version) -> + tls_v1:ecc_curves(corresponding_tls_version(Version)). -corresponding_tls_version({254, Minor}) -> - {3, corresponding_minor_tls_version(Minor)}. + +corresponding_tls_version(?DTLS_1_0) -> + ?TLS_1_1; +corresponding_tls_version(?DTLS_1_2) -> + ?TLS_1_2. cookie_secret() -> crypto:strong_rand_bytes(32). @@ -82,18 +86,12 @@ cookie_secret() -> cookie_timeout() -> %% Cookie will live for two timeouts periods round(rand:uniform() * ?COOKIE_BASE_TIMEOUT/2). - -corresponding_minor_tls_version(255) -> - 2; -corresponding_minor_tls_version(253) -> - 3. - -corresponding_dtls_version({3, Minor}) -> - {254, corresponding_minor_dtls_version(Minor)}. - -corresponding_minor_dtls_version(2) -> - 255; -corresponding_minor_dtls_version(3) -> - 253. + + +corresponding_dtls_version(?TLS_1_1) -> + ?DTLS_1_0; +corresponding_dtls_version(?TLS_1_2) -> + ?DTLS_1_2. + is_acceptable_cipher(Suite) -> not ssl_cipher:is_stream_ciphersuite(Suite). diff --git a/lib/ssl/src/inet6_tls_dist.erl b/lib/ssl/src/inet6_tls_dist.erl index 5ca0cd6904f3..0e51f9a1900a 100644 --- a/lib/ssl/src/inet6_tls_dist.erl +++ b/lib/ssl/src/inet6_tls_dist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015-2020. All Rights Reserved. +%% Copyright Ericsson AB 2015-2023. 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. @@ -25,26 +25,30 @@ -export([listen/2, accept/1, accept_connection/5, setup/5, close/1, select/1, address/0]). +-define(FAMILY, inet6). + childspecs() -> inet_tls_dist:childspecs(). select(Node) -> - inet_tls_dist:gen_select(inet6_tcp, Node). + inet_tls_dist:fam_select(?FAMILY, Node). address() -> - inet_tls_dist:gen_address(inet6_tcp). + inet_tls_dist:fam_address(?FAMILY). listen(Name, Host) -> - inet_tls_dist:gen_listen(inet6_tcp, Name, Host). + inet_tls_dist:fam_listen(?FAMILY, Name, Host). accept(Listen) -> - inet_tls_dist:gen_accept(inet6_tcp, Listen). + inet_tls_dist:fam_accept(?FAMILY, Listen). accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> - inet_tls_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + inet_tls_dist:fam_accept_connection( + ?FAMILY, AcceptPid, Socket, MyNode, Allowed, SetupTime). setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> - inet_tls_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime). + inet_tls_dist:fam_setup( + ?FAMILY, Node, Type, MyNode, LongOrShortNames,SetupTime). close(Socket) -> - inet_tls_dist:gen_close(inet6_tcp, Socket). + inet_tls_dist:close(Socket). diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index c234bf81beac..c93bb2759634 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2022. All Rights Reserved. +%% Copyright Ericsson AB 2011-2023. 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. @@ -20,19 +20,24 @@ %% -module(inet_tls_dist). +-feature(maybe_expr, enable). -export([childspecs/0]). --export([listen/2, accept/1, accept_connection/5, - setup/5, close/1, select/1, address/0, is_node_name/1]). +-export([select/1, address/0, is_node_name/1, + listen/2, accept/1, accept_connection/5, + setup/5, close/1]). %% Generalized dist API --export([gen_listen/3, gen_accept/2, gen_accept_connection/6, - gen_setup/6, gen_close/2, gen_select/2, gen_address/1]). - --export([nodelay/0]). +-export([fam_select/2, fam_address/1, fam_listen/3, fam_accept/2, + fam_accept_connection/6, fam_setup/6]). -export([verify_client/3, cert_nodes/1]). +%% kTLS helpers +-export([inet_ktls_setopt/3, inet_ktls_getopt/3, + set_ktls/1, set_ktls_ulp/2, set_ktls_cipher/5, + ktls_os/0, ktls_opt_ulp/1, ktls_opt_cipher/6]). + -export([dbg/0]). % Debug -include_lib("kernel/include/net_address.hrl"). @@ -41,37 +46,68 @@ -include_lib("public_key/include/public_key.hrl"). -include("ssl_api.hrl"). +-include("ssl_cipher.hrl"). +-include("ssl_internal.hrl"). +-include("ssl_record.hrl"). -include_lib("kernel/include/logger.hrl"). +-define(FAMILY, inet). +-define(DRIVER, inet_tcp). % Implies ?FAMILY = inet through inet_drv.c +-define(PROTOCOL, tls). + %% ------------------------------------------------------------------------- childspecs() -> {ok, [{ssl_dist_sup,{ssl_dist_sup, start_link, []}, permanent, infinity, supervisor, [ssl_dist_sup]}]}. +%% ------------------------------------------------------------------------- +%% Select this protocol based on node name select(Node) -> - gen_select(inet_tcp, Node). - -gen_select(Driver, Node) -> - inet_tcp_dist:gen_select(Driver, Node). - -%% ------------------------------------------------------------ -%% Get the address family that this distribution uses -%% ------------------------------------------------------------ + fam_select(?FAMILY, Node). +fam_select(Family, Node) -> + inet_tcp_dist:fam_select(Family, Node). +%% ------------------------------------------------------------------------- +%% Get the #net_address this distribution uses address() -> - gen_address(inet_tcp). -gen_address(Driver) -> - inet_tcp_dist:gen_address(Driver). - + fam_address(?FAMILY). +fam_address(Family) -> + NetAddress = inet_tcp_dist:fam_address(Family), + NetAddress#net_address{ protocol = ?PROTOCOL }. %% ------------------------------------------------------------------------- - +%% Is this one really needed?? is_node_name(Node) -> dist_util:is_node_name(Node). - %% ------------------------------------------------------------------------- -hs_data_common(#sslsocket{pid = [_, DistCtrl|_]} = SslSocket) -> +hs_data_inet_tcp(Driver, Socket) -> + Family = Driver:family(), + {ok, Peername} = + maybe + {error, einval} ?= inet:peername(Socket), + ?shutdown({Driver, closed}) + end, + (inet_tcp_dist:gen_hs_data(Driver, Socket)) + #hs_data{ + f_address = + fun(_, Node) -> + {node, _, Host} = dist_util:split_node(Node), + #net_address{ + address = Peername, + host = Host, + protocol = ?PROTOCOL, + family = Family + } + end}. + +hs_data_ssl(Family, #sslsocket{pid = [_, DistCtrl|_]} = SslSocket) -> + {ok, Address} = + maybe + {error, einval} ?= ssl:peername(SslSocket), + ?shutdown({sslsocket, closed}) + end, #hs_data{ + socket = DistCtrl, f_send = fun (_Ctrl, Packet) -> f_send(SslSocket, Packet) @@ -95,7 +131,7 @@ hs_data_common(#sslsocket{pid = [_, DistCtrl|_]} = SslSocket) -> end, f_address = fun (Ctrl, Node) when Ctrl == DistCtrl -> - f_address(SslSocket, Node) + f_address(Family, Address, Node) end, mf_tick = fun (Ctrl) when Ctrl == DistCtrl -> @@ -133,22 +169,21 @@ f_setopts_pre_nodeup(_SslSocket) -> ok. f_setopts_post_nodeup(SslSocket) -> - ssl:setopts(SslSocket, [nodelay()]). + ssl:setopts(SslSocket, [inet_tcp_dist:nodelay()]). f_getll(DistCtrl) -> {ok, DistCtrl}. -f_address(SslSocket, Node) -> - case ssl:peername(SslSocket) of - {ok, Address} -> - case dist_util:split_node(Node) of - {node,_,Host} -> - #net_address{ - address=Address, host=Host, - protocol=tls, family=inet}; - _ -> - {error, no_node} - end +f_address(Family, Address, Node) -> + case dist_util:split_node(Node) of + {node,_,Host} -> + #net_address{ + address = Address, + host = Host, + protocol = ?PROTOCOL, + family = Family}; + _ -> + {error, no_node} end. mf_tick(DistCtrl) -> @@ -194,71 +229,102 @@ split_stat([], R, W, P) -> %% ------------------------------------------------------------------------- listen(Name, Host) -> - gen_listen(inet_tcp, Name, Host). - -gen_listen(Driver, Name, Host) -> - case inet_tcp_dist:gen_listen(Driver, Name, Host) of - {ok, {Socket, Address, Creation}} -> - inet:setopts(Socket, [{packet, 4}, {nodelay, true}]), - {ok, {Socket, Address#net_address{protocol=tls}, Creation}}; - Other -> - Other + fam_listen(?FAMILY, Name, Host). + +fam_listen(Family, Name, Host) -> + ForcedOptions = + [Family, {active, false}, {packet, 4}, {nodelay, true}], + ListenFun = + fun (First, Last, ListenOptions) -> + listen_loop( + First, Last, + inet_tcp_dist:merge_options(ListenOptions, ForcedOptions)) + end, + maybe + %% + {ok, {ListenSocket, Address, Creation}} ?= + inet_tcp_dist:fam_listen(Family, Name, Host, ListenFun), + NetAddress = + #net_address{ + host = Host, + protocol = ?PROTOCOL, + family = Family, + address = Address}, + {ok, {ListenSocket, NetAddress, Creation}} end. +listen_loop(First, Last, ListenOptions) when First =< Last -> + case gen_tcp:listen(First, ListenOptions) of + {error, eaddrinuse} -> + listen_loop(First + 1, Last, ListenOptions); + Result -> + Result + end; +listen_loop(_, _, _) -> + {error, eaddrinuse}. + %% ------------------------------------------------------------------------- -accept(Listen) -> - gen_accept(inet_tcp, Listen). +accept(ListenSocket) -> + fam_accept(?FAMILY, ListenSocket). -gen_accept(Driver, Listen) -> - Kernel = self(), +fam_accept(Family, ListenSocket) -> + NetKernel = self(), monitor_pid( spawn_opt( fun () -> - process_flag(trap_exit, true), - LOpts = application:get_env(kernel, inet_dist_listen_options, []), - MaxPending = - case lists:keyfind(backlog, 1, LOpts) of - {backlog, Backlog} -> Backlog; - false -> 128 - end, - DLK = {Driver, Listen, Kernel}, - accept_loop(DLK, spawn_accept(DLK), MaxPending, #{}) + process_flag(trap_exit, true), + MaxPending = erlang:system_info(schedulers_online), + Continue = make_ref(), + FLNC = {Family, ListenSocket, NetKernel, Continue}, + Pending = #{}, + accept_loop( + FLNC, Continue, spawn_accept(FLNC), MaxPending, + Pending) end, - [link, {priority, max}])). + dist_util:net_ticker_spawn_options())). %% Concurrent accept loop will spawn a new HandshakePid when %% there is no HandshakePid already running, and Pending map is %% smaller than MaxPending -accept_loop(DLK, undefined, MaxPending, Pending) when map_size(Pending) < MaxPending -> - accept_loop(DLK, spawn_accept(DLK), MaxPending, Pending); -accept_loop(DLK, HandshakePid, MaxPending, Pending) -> +accept_loop(FLNC, Continue, undefined, MaxPending, Pending) + when map_size(Pending) < MaxPending -> + accept_loop(FLNC, Continue, spawn_accept(FLNC), MaxPending, Pending); +accept_loop({_, _, NetKernelPid, _} = FLNC, Continue, HandshakePid, MaxPending, Pending) -> receive - {continue, HandshakePid} when is_pid(HandshakePid) -> - accept_loop(DLK, undefined, MaxPending, Pending#{HandshakePid => true}); + {Continue, HandshakePid} when is_pid(HandshakePid) -> + accept_loop( + FLNC, Continue, undefined, MaxPending, + Pending#{HandshakePid => true}); {'EXIT', Pid, Reason} when is_map_key(Pid, Pending) -> Reason =/= normal andalso ?LOG_ERROR("TLS distribution handshake failed: ~p~n", [Reason]), - accept_loop(DLK, HandshakePid, MaxPending, maps:remove(Pid, Pending)); + accept_loop( + FLNC, Continue, HandshakePid, MaxPending, + maps:remove(Pid, Pending)); {'EXIT', HandshakePid, Reason} when is_pid(HandshakePid) -> %% HandshakePid crashed before turning into Pending, which means %% error happened in accept. Need to restart the listener. exit(Reason); + {'EXIT', NetKernelPid, Reason} -> + %% Since we're trapping exits, need to manually propagate this signal + exit(Reason); Unexpected -> - ?LOG_WARNING("TLS distribution: unexpected message: ~p~n" ,[Unexpected]), - accept_loop(DLK, HandshakePid, MaxPending, Pending) + ?LOG_WARNING( + "TLS distribution: unexpected message: ~p~n", [Unexpected]), + accept_loop(FLNC, Continue, HandshakePid, MaxPending, Pending) end. -spawn_accept({Driver, Listen, Kernel}) -> +spawn_accept({Family, ListenSocket, NetKernel, Continue}) -> AcceptLoop = self(), spawn_link( fun () -> - case Driver:accept(Listen) of + case gen_tcp:accept(ListenSocket) of {ok, Socket} -> - AcceptLoop ! {continue, self()}, - case check_ip(Driver, Socket) of + AcceptLoop ! {Continue, self()}, + case check_ip(Socket) of true -> - accept_one(Driver, Kernel, Socket); + accept_one(Family, Socket, NetKernel); {false,IP} -> ?LOG_ERROR( "** Connection attempt from " @@ -270,33 +336,37 @@ spawn_accept({Driver, Listen, Kernel}) -> end end). -accept_one(Driver, Kernel, Socket) -> +accept_one(Family, Socket, NetKernel) -> Opts = setup_verify_client(Socket, get_ssl_options(server)), - wait_for_code_server(), + KTLS = proplists:get_value(ktls, Opts, false), case ssl:handshake( Socket, trace([{active, false},{packet, 4}|Opts]), net_kernel:connecttime()) of - {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} -> - trace( - Kernel ! - {accept, self(), DistCtrl, - Driver:family(), tls}), - receive - {Kernel, controller, Pid} -> - case ssl:controlling_process(SslSocket, Pid) of + {ok, SslSocket} -> + Receiver = hd(SslSocket#sslsocket.pid), + case KTLS of + true -> + {ok, KtlsInfo} = ssl_gen_statem:ktls_handover(Receiver), + case inet_set_ktls(KtlsInfo) of ok -> - trace(Pid ! {self(), controller}); - Error -> - trace(Pid ! {self(), exit}), + accept_one( + Family, maps:get(socket, KtlsInfo), NetKernel, + fun gen_tcp:controlling_process/2); + {error, KtlsReason} -> ?LOG_ERROR( - "Cannot control TLS distribution connection: ~p~n", - [Error]) + [{slogan, set_ktls_failed}, + {reason, KtlsReason}, + {pid, self()}]), + close(Socket), + trace({ktls_error, KtlsReason}) end; - {Kernel, unsupported_protocol} -> - trace(unsupported_protocol) + false -> + accept_one( + Family, SslSocket, NetKernel, + fun ssl:controlling_process/2) end; {error, {options, _}} = Error -> %% Bad options: that's probably our fault. @@ -304,12 +374,31 @@ accept_one(Driver, Kernel, Socket) -> ?LOG_ERROR( "Cannot accept TLS distribution connection: ~s~n", [ssl:format_error(Error)]), - gen_tcp:close(Socket), + close(Socket), trace(Error); Other -> - gen_tcp:close(Socket), + close(Socket), trace(Other) end. +%% +accept_one( + Family, DistSocket, NetKernel, ControllingProcessFun) -> + trace(NetKernel ! {accept, self(), DistSocket, Family, ?PROTOCOL}), + receive + {NetKernel, controller, Pid} -> + case ControllingProcessFun(DistSocket, Pid) of + ok -> + trace(Pid ! {self(), controller}); + {error, Reason} -> + trace(Pid ! {self(), exit}), + ?LOG_ERROR( + [{slogan, controlling_process_failed}, + {reason, Reason}, + {pid, self()}]) + end; + {NetKernel, unsupported_protocol} -> + trace(unsupported_protocol) + end. %% {verify_fun,{fun ?MODULE:verify_client/3,_}} is used @@ -395,72 +484,50 @@ verify_client(PeerCert, valid_peer, {AllowedHosts,PeerIP} = S) -> end. -wait_for_code_server() -> - %% This is an ugly hack. Upgrading a socket to TLS requires the - %% crypto module to be loaded. Loading the crypto module triggers - %% its on_load function, which calls code:priv_dir/1 to find the - %% directory where its NIF library is. However, distribution is - %% started earlier than the code server, so the code server is not - %% necessarily started yet, and code:priv_dir/1 might fail because - %% of that, if we receive an incoming connection on the - %% distribution port early enough. - %% - %% If the on_load function of a module fails, the module is - %% unloaded, and the function call that triggered loading it fails - %% with 'undef', which is rather confusing. - %% - %% Thus, the accept process will terminate, and be - %% restarted by ssl_dist_sup. However, it won't have any memory - %% of being asked by net_kernel to listen for incoming - %% connections. Hence, the node will believe that it's open for - %% distribution, but it actually isn't. - %% - %% So let's avoid that by waiting for the code server to start. - case whereis(code_server) of - undefined -> - timer:sleep(10), - wait_for_code_server(); - Pid when is_pid(Pid) -> - ok - end. - %% ------------------------------------------------------------------------- -accept_connection(AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) -> - gen_accept_connection( - inet_tcp, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime). +accept_connection(AcceptPid, DistSocket, MyNode, Allowed, SetupTime) -> + fam_accept_connection( + ?FAMILY, AcceptPid, DistSocket, MyNode, Allowed, SetupTime). -gen_accept_connection( - Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) -> +fam_accept_connection( + Family, AcceptPid, DistSocket, MyNode, Allowed, SetupTime) -> Kernel = self(), monitor_pid( spawn_opt( fun() -> do_accept( - Driver, AcceptPid, DistCtrl, + Family, AcceptPid, DistSocket, MyNode, Allowed, SetupTime, Kernel) end, - [link, {priority, max}])). + dist_util:net_ticker_spawn_options())). do_accept( - _Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime, Kernel) -> + Family, AcceptPid, DistSocket, MyNode, Allowed, SetupTime, Kernel) -> MRef = erlang:monitor(process, AcceptPid), receive {AcceptPid, controller} -> erlang:demonitor(MRef, [flush]), - {ok, SslSocket} = tls_sender:dist_tls_socket(DistCtrl), - Timer = dist_util:start_timer(SetupTime), - NewAllowed = allowed_nodes(SslSocket, Allowed), - HSData0 = hs_data_common(SslSocket), + Timer = dist_util:start_timer(SetupTime), + {HSData0, NewAllowed} = + case DistSocket of + SslSocket = #sslsocket{pid = [_Receiver, Sender| _]} -> + link(Sender), + {hs_data_ssl(Family, SslSocket), + allowed_nodes(SslSocket, Allowed)}; + PortSocket when is_port(DistSocket) -> + %%% XXX Breaking abstraction barrier + Driver = erlang:port_get_data(PortSocket), + {hs_data_inet_tcp(Driver, PortSocket), + Allowed} + end, HSData = HSData0#hs_data{ kernel_pid = Kernel, this_node = MyNode, - socket = DistCtrl, timer = Timer, this_flags = 0, allowed = NewAllowed}, - link(DistCtrl), dist_util:handshake_other_started(trace(HSData)); {AcceptPid, exit} -> %% this can happen when connection was initiated, but dropped @@ -532,138 +599,147 @@ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host) -> allowed_nodes(PeerCert, Allowed, PeerIP) end. + +%% ------------------------------------------------------------------------- + setup(Node, Type, MyNode, LongOrShortNames, SetupTime) -> - gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime). + fam_setup(?FAMILY, Node, Type, MyNode, LongOrShortNames, SetupTime). -gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) -> - Kernel = self(), +fam_setup(Family, Node, Type, MyNode, LongOrShortNames, SetupTime) -> + NetKernel = self(), monitor_pid( - spawn_opt(setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime), - [link, {priority, max}])). + spawn_opt( + setup_fun( + Family, Node, Type, MyNode, LongOrShortNames, SetupTime, + NetKernel), + dist_util:net_ticker_spawn_options())). -spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()). -setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> +setup_fun( + Family, Node, Type, MyNode, LongOrShortNames, SetupTime, NetKernel) -> fun() -> do_setup( - Driver, Kernel, Node, Type, - MyNode, LongOrShortNames, SetupTime) + Family, Node, Type, MyNode, LongOrShortNames, SetupTime, + NetKernel) end. - -spec do_setup(_,_,_,_,_,_,_) -> no_return(). -do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> - {Name, Address} = split_node(Driver, Node, LongOrShortNames), - ErlEpmd = net_kernel:epmd_module(), - {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver), +do_setup( + Family, Node, Type, MyNode, LongOrShortNames, SetupTime, NetKernel) -> Timer = trace(dist_util:start_timer(SetupTime)), - case ARMod:ARFun(Name,Address,Driver:family()) of - {ok, Ip, TcpPort, Version} -> - do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer); - {ok, Ip} -> - case ErlEpmd:port_please(Name, Ip) of - {port, TcpPort, Version} -> - do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer); - Other -> - ?shutdown2( - Node, - trace( - {port_please_failed, ErlEpmd, Name, Ip, Other})) - end; - Other -> - ?shutdown2( - Node, - trace({getaddr_failed, Driver, Address, Other})) - end. - --spec do_setup_connect(_,_,_,_,_,_,_,_,_,_) -> no_return(). - -do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer) -> - Opts = trace(connect_options(get_ssl_options(client))), + ParseAddress = fun (A) -> inet:parse_strict_address(A, Family) end, + {#net_address{ + host = Host, + address = {Ip, PortNum}}, + ConnectOptions, + Version} = + trace(inet_tcp_dist:fam_setup( + Family, Node, LongOrShortNames, ParseAddress)), + Opts = + inet_tcp_dist:merge_options( + inet_tcp_dist:merge_options( + ConnectOptions, + get_ssl_options(client)), + [Family, binary, {active, false}, {packet, 4}, {nodelay, true}], + [{server_name_indication, Host}]), + KTLS = proplists:get_value(ktls, Opts, false), dist_util:reset_timer(Timer), - case ssl:connect( - Ip, TcpPort, - [binary, {active, false}, {packet, 4}, {server_name_indication, Address}, - Driver:family(), {nodelay, true}] ++ Opts, - net_kernel:connecttime()) of - {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} -> - _ = monitor_pid(DistCtrl), - ok = ssl:controlling_process(SslSocket, self()), - HSData0 = hs_data_common(SslSocket), + maybe + {ok, #sslsocket{pid = [Receiver, Sender| _]} = SslSocket} ?= + ssl:connect(Ip, PortNum, Opts, net_kernel:connecttime()), HSData = - HSData0#hs_data{ - kernel_pid = Kernel, - other_node = Node, - this_node = MyNode, - socket = DistCtrl, - timer = Timer, - this_flags = 0, - other_version = Version, - request_type = Type}, - link(DistCtrl), - dist_util:handshake_we_started(trace(HSData)); - Other -> - %% Other Node may have closed since - %% port_please ! - ?shutdown2( - Node, - trace( - {ssl_connect_failed, Ip, TcpPort, Other})) + case KTLS of + true -> + {ok, KtlsInfo} = + ssl_gen_statem:ktls_handover(Receiver), + Socket = maps:get(socket, KtlsInfo), + case inet_set_ktls(KtlsInfo) of + ok when is_port(Socket) -> + %% XXX Breaking abstraction barrier + Driver = erlang:port_get_data(Socket), + hs_data_inet_tcp(Driver, Socket); + {error, KtlsReason} -> + ?shutdown2( + Node, + trace({set_ktls_failed, KtlsReason})) + end; + false -> + _ = monitor_pid(Sender), + ok = ssl:controlling_process(SslSocket, self()), + link(Sender), + hs_data_ssl(Family, SslSocket) + end + #hs_data{ + kernel_pid = NetKernel, + other_node = Node, + this_node = MyNode, + timer = Timer, + this_flags = 0, + other_version = Version, + request_type = Type}, + dist_util:handshake_we_started(trace(HSData)) + else + Other -> + %% Other Node may have closed since + %% port_please ! + ?shutdown2( + Node, + trace({ssl_connect_failed, Ip, PortNum, Other})) end. -close(Socket) -> - gen_close(inet, Socket). - -gen_close(Driver, Socket) -> - trace(Driver:close(Socket)). +close(Socket) -> + gen_tcp:close(Socket). -%% ------------------------------------------------------------ -%% Determine if EPMD module supports address resolving. Default -%% is to use inet_tcp:getaddr/2. -%% ------------------------------------------------------------ -get_address_resolver(EpmdModule, _Driver) -> - case erlang:function_exported(EpmdModule, address_please, 3) of - true -> {EpmdModule, address_please}; - _ -> {erl_epmd, address_please} - end. %% ------------------------------------------------------------ %% Do only accept new connection attempts from nodes at our %% own LAN, if the check_ip environment parameter is true. %% ------------------------------------------------------------ -check_ip(Driver, Socket) -> +check_ip(Socket) -> case application:get_env(check_ip) of {ok, true} -> - case get_ifs(Socket) of - {ok, IFs, IP} -> - check_ip(Driver, IFs, IP); - Other -> - ?shutdown2( - no_node, trace({check_ip_failed, Socket, Other})) - end; + maybe + {ok, {IP, _}} ?= inet:sockname(Socket), + ok ?= if is_tuple(IP) -> ok; + true -> {error, {no_ip_address, IP}} + end, + {ok, Ifaddrs} ?= inet:getifaddrs(), + {ok, Netmask} ?= find_netmask(IP, Ifaddrs), + {ok, {PeerIP, _}} ?= inet:sockname(Socket), + ok ?= if is_tuple(PeerIP) -> ok; + true -> {error, {no_ip_address, PeerIP}} + end, + mask(IP, Netmask) =:= mask(PeerIP, Netmask) + orelse {false, PeerIP} + else + Other -> + exit({check_ip, Other}) + end; _ -> true end. -check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of - {M, M} -> true; - _ -> check_ip(IFs, PeerIP) - end; -check_ip(_Driver, [], PeerIP) -> - {false, PeerIP}. - -get_ifs(Socket) -> - case inet:peername(Socket) of - {ok, {IP, _}} -> - %% XXX this is seriously broken for IPv6 - case inet:getif(Socket) of - {ok, IFs} -> {ok, IFs, IP}; - Error -> Error - end; - Error -> - Error - end. +find_netmask(IP, [{_Name,Items} | Ifaddrs]) -> + find_netmask(IP, Ifaddrs, Items); +find_netmask(_, []) -> + {error, no_netmask}. +%% +find_netmask(IP, _Ifaddrs, [{addr, IP}, {netmask, Netmask} | _]) -> + {ok, Netmask}; +find_netmask(IP, Ifaddrs, [_ | Items]) -> + find_netmask(IP, Ifaddrs, Items); +find_netmask(IP, Ifaddrs, []) -> + find_netmask(IP, Ifaddrs). + +mask(Addr, Mask) -> + list_to_tuple(mask(Addr, Mask, 1)). +%% +mask(Addr, Mask, N) when N =< tuple_size(Addr) -> + [element(N, Addr) band element(N, Mask) | mask(Addr, Mask, N + 1)]; +mask(_, _, _) -> + []. + %% Look in Extensions, in all subjectAltName:s @@ -741,90 +817,32 @@ parse_rdn([_|Rdn]) -> parse_rdn(Rdn). -%% If Node is illegal terminate the connection setup!! -split_node(Driver, Node, LongOrShortNames) -> - case dist_util:split_node(Node) of - {node, Name, Host} -> - check_node(Driver, Node, Name, Host, LongOrShortNames); - {host, _} -> - ?LOG_ERROR( - "** Nodename ~p illegal, no '@' character **~n", - [Node]), - ?shutdown2(Node, trace({illegal_node_n@me, Node})); - _ -> - ?LOG_ERROR( - "** Nodename ~p illegal **~n", [Node]), - ?shutdown2(Node, trace({illegal_node_name, Node})) - end. - -check_node(Driver, Node, Name, Host, LongOrShortNames) -> - case string:split(Host, ".", all) of - [_] when LongOrShortNames =:= longnames -> - case Driver:parse_address(Host) of - {ok, _} -> - {Name, Host}; - _ -> - ?LOG_ERROR( - "** System running to use " - "fully qualified hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown2(Node, trace({not_longnames, Host})) - end; - [_,_|_] when LongOrShortNames =:= shortnames -> - ?LOG_ERROR( - "** System NOT running to use " - "fully qualified hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown2(Node, trace({not_shortnames, Host})); - _ -> - {Name, Host} - end. - %% ------------------------------------------------------------------------- - -connect_options(Opts) -> - case application:get_env(kernel, inet_dist_connect_options) of - {ok,ConnectOpts} -> - lists:ukeysort(1, ConnectOpts ++ Opts); - _ -> - Opts - end. - -%% we may not always want the nodelay behaviour -%% for performance reasons -nodelay() -> - case application:get_env(kernel, dist_nodelay) of - undefined -> - {nodelay, true}; - {ok, true} -> - {nodelay, true}; - {ok, false} -> - {nodelay, false}; - _ -> - {nodelay, true} - end. - - get_ssl_options(Type) -> - try ets:lookup(ssl_dist_opts, Type) of - [{Type, Opts0}] -> - [{erl_dist, true} | dist_defaults(Opts0)]; - _ -> - get_ssl_dist_arguments(Type) - catch - error:badarg -> - get_ssl_dist_arguments(Type) - end. - -get_ssl_dist_arguments(Type) -> - case init:get_argument(ssl_dist_opt) of - {ok, Args} -> - [{erl_dist, true} | dist_defaults(ssl_options(Type, lists:append(Args)))]; - _ -> - [{erl_dist, true}] - end. + [{erl_dist, true} | + case + case init:get_argument(ssl_dist_opt) of + {ok, Args} -> + ssl_options(Type, lists:append(Args)); + _ -> + [] + end + ++ + try ets:lookup(ssl_dist_opts, Type) of + [{Type, Opts0}] -> + Opts0; + _ -> + [] + catch + error:badarg -> + [] + end + of + [] -> + []; + Opts1 -> + dist_defaults(Opts1) + end]. dist_defaults(Opts) -> case proplists:get_value(versions, Opts, undefined) of @@ -871,7 +889,13 @@ ssl_option(client, Opt) -> "secure_renegotiate" -> fun atomize/1; "depth" -> fun erlang:list_to_integer/1; "hibernate_after" -> fun erlang:list_to_integer/1; - "ciphers" -> fun listify/1; + "ciphers" -> + %% Allows just one cipher, for now (could be , separated) + fun (Val) -> [listify(Val)] end; + "versions" -> + %% Allows just one version, for now (could be , separated) + fun (Val) -> [atomize(Val)] end; + "ktls" -> fun atomize/1; _ -> error end. @@ -897,6 +921,174 @@ verify_fun(Value) -> error(malformed_ssl_dist_opt, [Value]) end. + +inet_set_ktls( + #{ socket := Socket, socket_options := SocketOptions } = KtlsInfo) -> + %% + maybe + ok ?= + set_ktls( + KtlsInfo + #{ setopt_fun => fun ?MODULE:inet_ktls_setopt/3, + getopt_fun => fun ?MODULE:inet_ktls_getopt/3 }), + %% + #socket_options{ + mode = _Mode, + packet = Packet, + packet_size = PacketSize, + header = Header, + active = Active + } = SocketOptions, + case + inet:setopts( + Socket, + [list, {packet, Packet}, {packet_size, PacketSize}, + {header, Header}, {active, Active}]) + of + ok -> + ok; + {error, SetoptError} -> + {error, {ktls_setopt_failed, SetoptError}} + end + end. + +inet_ktls_setopt(Socket, {Level, Opt}, Value) + when is_integer(Level), is_integer(Opt), is_binary(Value) -> + inet:setopts(Socket, [{raw, Level, Opt, Value}]). + +inet_ktls_getopt(Socket, {Level, Opt}, Size) + when is_integer(Level), is_integer(Opt), is_integer(Size) -> + case inet:getopts(Socket, [{raw, Level, Opt, Size}]) of + {ok, [{raw, Level, Opt, Value}]} -> + {ok, Value}; + {ok, _} = Error -> + {error, Error}; + {error, _} = Error -> + Error + end. + + +set_ktls(KtlsInfo) -> + maybe + {ok, OS} ?= ktls_os(), + ok ?= set_ktls_ulp(KtlsInfo, OS), + #{ write_state := WriteState, + write_seq := WriteSeq, + read_state := ReadState, + read_seq := ReadSeq } = KtlsInfo, + ok ?= set_ktls_cipher(KtlsInfo, OS, WriteState, WriteSeq, tx), + set_ktls_cipher(KtlsInfo, OS, ReadState, ReadSeq, rx) + end. + +set_ktls_ulp( + #{ socket := Socket, + setopt_fun := SetoptFun, + getopt_fun := GetoptFun }, + OS) -> + %% + {Option, Value} = ktls_opt_ulp(OS), + Size = byte_size(Value), + _ = SetoptFun(Socket, Option, Value), + %% + %% Check if kernel module loaded, + %% i.e if getopts Level, Opt returns Value + %% + case GetoptFun(Socket, Option, Size + 1) of + {ok, <>} -> + ok; + Other -> + {error, {ktls_set_ulp_failed, Option, Value, Other}} + end. + +%% Set kTLS cipher +%% +set_ktls_cipher( + _KtlsInfo = + #{ tls_version := TLS_version, + cipher_suite := CipherSuite, + %% + socket := Socket, + setopt_fun := SetoptFun, + getopt_fun := GetoptFun }, + OS, CipherState, CipherSeq, TxRx) -> + maybe + {ok, {Option, Value}} ?= + ktls_opt_cipher( + OS, TLS_version, CipherSuite, CipherState, CipherSeq, TxRx), + _ = SetoptFun(Socket, Option, Value), + case TxRx of + tx -> + Size = byte_size(Value), + case GetoptFun(Socket, Option, Size) of + {ok, Value} -> + ok; + Other -> + {error, {ktls_set_cipher_failed, Other}} + end; + rx -> + ok + end + end. + +ktls_os() -> + OS = {os:type(), os:version()}, + case OS of + {{unix,linux}, OsVersion} when {5,2,0} =< OsVersion -> + {ok, OS}; + _ -> + {error, {ktls_notsup, {os,OS}}} + end. + +ktls_opt_ulp(_OS) -> + %% + %% See https://www.kernel.org/doc/html/latest/networking/tls.html + %% and include/netinet/tcp.h + %% + SOL_TCP = 6, TCP_ULP = 31, + KtlsMod = <<"tls">>, + {{SOL_TCP,TCP_ULP}, KtlsMod}. + +ktls_opt_cipher( + _OS, + _TLS_version = ?TLS_1_3, % 'tlsv1.3' + _CipherSpec = ?TLS_AES_256_GCM_SHA384, + #cipher_state{ + key = <>, + iv = <> }, + CipherSeq, + TxRx) when is_integer(CipherSeq) -> + %% + %% See include/linux/tls.h + %% + TLS_1_3_VERSION_MAJOR = 3, + TLS_1_3_VERSION_MINOR = 4, + TLS_1_3_VERSION = + (TLS_1_3_VERSION_MAJOR bsl 8) bor TLS_1_3_VERSION_MINOR, + TLS_CIPHER_AES_GCM_256 = 52, + SOL_TLS = 282, + TLS_TX = 1, + TLS_RX = 2, + Value = + <>, + %% + SOL_TLS = 282, + TLS_TX = 1, + TLS_RX = 2, + TLS_TxRx = + case TxRx of + tx -> TLS_TX; + rx -> TLS_RX + end, + {ok, {{SOL_TLS,TLS_TxRx}, Value}}; +ktls_opt_cipher( + _OS, TLS_version, CipherSpec, _CipherState, _CipherSeq, _TxRx) -> + {error, + {ktls_notsup, {cipher, TLS_version, CipherSpec, _CipherState}}}. + + %% ------------------------------------------------------------------------- %% Trace point diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index c381e3643c65..b9f69af6a3bb 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -4,7 +4,9 @@ {modules, [ %% TLS/SSL tls_connection, - tls_connection_1_3, + tls_client_connection_1_3, + tls_server_connection_1_3, + tls_gen_connection_1_3, tls_handshake, tls_handshake_1_3, tls_record, @@ -75,6 +77,7 @@ ssl_crl_hash_dir, %% Logging ssl_logger, + ssl_trace, %% App structure ssl_app, ssl_sup, @@ -85,6 +88,6 @@ {applications, [crypto, public_key, kernel, stdlib]}, {env, []}, {mod, {ssl_app, []}}, - {runtime_dependencies, ["stdlib-3.17.2.1","public_key-1.11.3","kernel-8.0", - "erts-10.0","crypto-5.0", "inets-5.10.7", + {runtime_dependencies, ["stdlib-4.1","public_key-1.11.3","kernel-9.0", + "erts-14.0","crypto-5.0", "inets-5.10.7", "runtime_tools-1.15.1"]}]}. diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index b0faa738d31f..6c8cb7ae9907 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {<<"11\\..*">>, [{restart_application, ssl}]}, {<<"10\\..*">>, [{restart_application, ssl}]}, {<<"9\\..*">>, [{restart_application, ssl}]}, {<<"8\\..*">>, [{restart_application, ssl}]}, @@ -11,6 +12,7 @@ {<<"3\\..*">>, [{restart_application, ssl}]} ], [ + {<<"11\\..*">>, [{restart_application, ssl}]}, {<<"10\\..*">>, [{restart_application, ssl}]}, {<<"9\\..*">>, [{restart_application, ssl}]}, {<<"8\\..*">>, [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 30a04a9a361b..2069c9912646 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -26,6 +26,7 @@ -module(ssl). -include_lib("public_key/include/public_key.hrl"). +-include_lib("kernel/include/logger.hrl"). -include("ssl_internal.hrl"). -include("ssl_api.hrl"). @@ -80,6 +81,7 @@ filter_cipher_suites/2, prepend_cipher_suites/2, append_cipher_suites/2, + signature_algs/2, eccs/0, eccs/1, versions/0, @@ -93,12 +95,14 @@ connection_information/1, connection_information/2]). %% Misc --export([handle_options/2, - handle_options/3, - tls_version/1, +-export([handle_options/3, + update_options/3, + tls_version/1, suite_to_str/1, suite_to_openssl_str/1, str_to_suite/1]). +%% Tracing +-export([handle_trace/3]). -removed({ssl_accept, '_', "use ssl_handshake/1,2,3 instead"}). @@ -177,16 +181,14 @@ des_cbc | '3des_ede_cbc'. --type hash() :: sha | - sha2() | +-type hash() :: sha2() | legacy_hash(). % exported --type sha2() :: sha224 | - sha256 | - sha384 | - sha512. +-type sha2() :: sha256 | + sha384 | + sha512. --type legacy_hash() :: md5. +-type legacy_hash() :: sha224 | sha | md5. -type sign_algo() :: rsa | dsa | ecdsa | eddsa. % exported @@ -244,7 +246,9 @@ brainpoolP256r1 | secp256k1 | secp256r1 | - sect239k1 | + legacy_named_curve(). % exported + +-type legacy_named_curve() :: sect239k1 | sect233k1 | sect233r1 | secp224k1 | @@ -258,9 +262,9 @@ sect163r2 | secp160k1 | secp160r1 | - secp160r2. % exported + secp160r2. --type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 | +-type group() :: x25519 | x448 | secp256r1 | secp384r1 | secp521r1 | ffdhe2048 | ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192. % exported -type srp_param_type() :: srp_1024 | @@ -310,7 +314,8 @@ {certfile, cert_pem()} | {key, key()} | {keyfile, key_pem()} | - {password, key_password()} | + {password, key_pem_password()} | + {certs_keys, certs_keys()} | {ciphers, cipher_suites()} | {eccs, [named_curve()]} | {signature_algs, signature_algs()} | @@ -333,7 +338,9 @@ {beast_mitigation, beast_mitigation()} | {ssl_imp, ssl_imp()} | {session_tickets, session_tickets()} | - {key_update_at, key_update_at()}. + {key_update_at, key_update_at()} | + {receiver_spawn_opts, spawn_opts()} | + {sender_spawn_opts, spawn_opts()}. -type protocol() :: tls | dtls. -type handshake_completion() :: hello | full. @@ -346,8 +353,14 @@ key_id := crypto:key_id(), password => crypto:password()}. % exported -type key_pem() :: file:filename(). --type key_password() :: string() | fun(() -> string()). --type cipher_suites() :: ciphers(). +-type key_pem_password() :: iodata() | fun(() -> iodata()). +-type certs_keys() :: [cert_key_conf()]. +-type cert_key_conf() :: #{cert => cert(), + key => key(), + certfile => cert_pem(), + keyfile => key_pem(), + password => key_pem_password()}. +-type cipher_suites() :: ciphers(). -type ciphers() :: [erl_cipher_suite()] | string(). % (according to old API) exported -type cipher_filters() :: list({key_exchange | cipher | mac | prf, @@ -376,7 +389,7 @@ -type log_alert() :: boolean(). -type logging_level() :: logger:level() | none | all. -type client_session_tickets() :: disabled | manual | auto. --type server_session_tickets() :: disabled | stateful | stateless. +-type server_session_tickets() :: disabled | stateful | stateless | stateful_with_cert | stateless_with_cert. -type session_tickets() :: client_session_tickets() | server_session_tickets(). -type key_update_at() :: pos_integer(). -type bloom_filter_window_size() :: integer(). @@ -390,6 +403,8 @@ -type middlebox_comp_mode() :: boolean(). -type client_early_data() :: binary(). -type server_early_data() :: disabled | enabled. +-type use_srtp() :: #{protection_profiles := [binary()], mki => binary()}. +-type spawn_opts() :: [erlang:spawn_opt_option()]. %% ------------------------------------------------------------------------------------------------------- @@ -407,10 +422,11 @@ {customize_hostname_check, customize_hostname_check()} | {fallback, fallback()} | {middlebox_comp_mode, middlebox_comp_mode()} | - {certificate_authorities, certificate_authorities()} | + {certificate_authorities, client_certificate_authorities()} | {session_tickets, client_session_tickets()} | {use_ticket, use_ticket()} | - {early_data, client_early_data()}. + {early_data, client_early_data()} | + {use_srtp, use_srtp()}. %% {ocsp_stapling, ocsp_stapling()} | %% {ocsp_responder_certs, ocsp_responder_certs()} | %% {ocsp_nonce, ocsp_nonce()}. @@ -418,8 +434,8 @@ -type client_verify_type() :: verify_type(). -type client_reuse_session() :: session_id() | {session_id(), SessionData::binary()}. -type client_reuse_sessions() :: boolean() | save. --type certificate_authorities() :: boolean(). --type client_cacerts() :: [public_key:der_encoded()]. +-type client_certificate_authorities() :: boolean(). +-type client_cacerts() :: [public_key:der_encoded()] | [public_key:combined_cert()]. -type client_cafile() :: file:filename(). -type app_level_protocol() :: binary(). -type client_alpn() :: [app_level_protocol()]. @@ -447,6 +463,7 @@ {dhfile, dh_file()} | {verify, server_verify_type()} | {fail_if_no_peer_cert, fail_if_no_peer_cert()} | + {certificate_authorities, server_certificate_authorities()} | {reuse_sessions, server_reuse_sessions()} | {reuse_session, server_reuse_session()} | {alpn_preferred_protocols, server_alpn()} | @@ -458,11 +475,13 @@ {honor_ecc_order, honor_ecc_order()} | {client_renegotiation, client_renegotiation()}| {session_tickets, server_session_tickets()} | + {stateless_tickets_seed, stateless_tickets_seed()} | {anti_replay, anti_replay()} | {cookie, cookie()} | - {early_data, server_early_data()}. + {early_data, server_early_data()} | + {use_srtp, use_srtp()}. --type server_cacerts() :: [public_key:der_encoded()]. +-type server_cacerts() :: [public_key:der_encoded()] | [public_key:combined_cert()]. -type server_cafile() :: file:filename(). -type server_alpn() :: [app_level_protocol()]. -type server_next_protocol() :: [app_level_protocol()]. @@ -474,11 +493,13 @@ -type server_reuse_session() :: fun(). -type server_reuse_sessions() :: boolean(). -type sni_hosts() :: [{hostname(), [server_option() | common_option()]}]. --type sni_fun() :: fun(). +-type sni_fun() :: fun((string()) -> [] | undefined). -type honor_cipher_order() :: boolean(). -type honor_ecc_order() :: boolean(). -type client_renegotiation() :: boolean(). +-type stateless_tickets_seed() :: binary(). -type cookie() :: boolean(). +-type server_certificate_authorities() :: boolean(). %% ------------------------------------------------------------------------------------------------------- -type prf_random() :: client_random | server_random. % exported -type protocol_extensions() :: #{renegotiation_info => binary(), @@ -580,11 +601,11 @@ connect(Socket, SslOptions) -> connect(Socket, SslOptions0, Timeout) when is_list(SslOptions0) andalso (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> - CbInfo = handle_option_cb_info(SslOptions0, tls), - Transport = element(1, CbInfo), - try handle_options(Transport, Socket, SslOptions0, client, undefined) of - {ok, Config} -> - tls_socket:upgrade(Socket, Config, Timeout) + try + CbInfo = handle_option_cb_info(SslOptions0, tls), + Transport = element(1, CbInfo), + {ok, Config} = handle_options(Transport, Socket, SslOptions0, client, undefined), + tls_socket:upgrade(Socket, Config, Timeout) catch _:{error, Reason} -> {error, Reason} @@ -629,7 +650,7 @@ listen(_Port, []) -> {error, nooptions}; listen(Port, Options0) -> try - {ok, Config} = handle_options(Options0, server), + {ok, Config} = handle_options(Options0, server, undefined), do_listen(Port, Config, Config#config.connection_cb) catch Error = {error, _} -> @@ -716,7 +737,7 @@ handshake(ListenSocket, SslOptions) -> Reason :: closed | timeout | {options, any()} | error_alert(). handshake(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or - (Timeout == infinity)-> + (Timeout == infinity)-> handshake(Socket, Timeout); handshake(#sslsocket{fd = {_, _, _, Trackers}} = Socket, SslOpts, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> @@ -738,19 +759,20 @@ handshake(#sslsocket{pid = [Pid|_], fd = {_, _, _}} = Socket, SslOpts, Timeout) Error = {error, _Reason} -> Error end; handshake(Socket, SslOptions, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) -> - CbInfo = handle_option_cb_info(SslOptions, tls), - Transport = element(1, CbInfo), - ConnetionCb = connection_cb(SslOptions), - try handle_options(Transport, Socket, SslOptions, server, undefined) of - {ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} -> - ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()), - {ok, Port} = tls_socket:port(Transport, Socket), - {ok, SessionIdHandle} = tls_socket:session_id_tracker(ssl_unknown_listener, SslOpts), - ssl_gen_statem:handshake(ConnetionCb, Port, Socket, - {SslOpts, - tls_socket:emulated_socket_options(EmOpts, #socket_options{}), - [{session_id_tracker, SessionIdHandle}]}, - self(), CbInfo, Timeout) + try + CbInfo = handle_option_cb_info(SslOptions, tls), + Transport = element(1, CbInfo), + ConnetionCb = connection_cb(SslOptions), + {ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} = + handle_options(Transport, Socket, SslOptions, server, undefined), + ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()), + {ok, Port} = tls_socket:port(Transport, Socket), + {ok, SessionIdHandle} = tls_socket:session_id_tracker(ssl_unknown_listener, SslOpts), + ssl_gen_statem:handshake(ConnetionCb, Port, Socket, + {SslOpts, + tls_socket:emulated_socket_options(EmOpts, #socket_options{}), + [{session_id_tracker, SessionIdHandle}]}, + self(), CbInfo, Timeout) catch Error = {error, _Reason} -> Error end. @@ -857,7 +879,7 @@ send(#sslsocket{pid = {ListenSocket, #config{transport_info = Info}}}, Data) -> %%-------------------------------------------------------------------- -spec recv(SslSocket, Length) -> {ok, Data} | {error, reason()} when SslSocket :: sslsocket(), - Length :: integer(), + Length :: non_neg_integer(), Data :: binary() | list() | HttpPacket, HttpPacket :: any(). @@ -866,13 +888,15 @@ recv(Socket, Length) -> -spec recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, reason()} when SslSocket :: sslsocket(), - Length :: integer(), + Length :: non_neg_integer(), Data :: binary() | list() | HttpPacket, Timeout :: timeout(), HttpPacket :: any(). -recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid), - (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)-> +recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) + when is_pid(Pid) andalso + (is_integer(Length) andalso Length >= 0) andalso + ((is_integer(Timeout) andalso Timeout >= 0) orelse Timeout == infinity) -> ssl_gen_statem:recv(Pid, Length, Timeout); recv(#sslsocket{pid = {dtls,_}}, _, _) -> {error,enotconn}; @@ -977,7 +1001,7 @@ peercert(#sslsocket{pid = {_Listen, #config{}}}) -> -spec negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, Reason} when SslSocket :: sslsocket(), Protocol :: binary(), - Reason :: protocol_not_negotiated. + Reason :: protocol_not_negotiated | closed. %% %% Description: Returns the protocol that has been negotiated. If no %% protocol has been negotiated will return {error, protocol_not_negotiated} @@ -988,7 +1012,7 @@ negotiated_protocol(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) -> %%-------------------------------------------------------------------- -spec cipher_suites(Description, Version) -> ciphers() when Description :: default | all | exclusive | anonymous | exclusive_anonymous, - Version :: protocol_version(). + Version :: protocol_version() | ssl_record:ssl_version(). %% Description: Returns all default and all supported cipher suites for a %% TLS/DTLS version @@ -997,17 +1021,17 @@ cipher_suites(Description, Version) when Version == 'tlsv1.3'; Version == 'tlsv1.2'; Version == 'tlsv1.1'; Version == tlsv1 -> - cipher_suites(Description, tls_record:protocol_version(Version)); + cipher_suites(Description, tls_record:protocol_version_name(Version)); cipher_suites(Description, Version) when Version == 'dtlsv1.2'; Version == 'dtlsv1'-> - cipher_suites(Description, dtls_record:protocol_version(Version)); + cipher_suites(Description, dtls_record:protocol_version_name(Version)); cipher_suites(Description, Version) -> [ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- supported_suites(Description, Version)]. %%-------------------------------------------------------------------- -spec cipher_suites(Description, Version, rfc | openssl) -> [string()] when Description :: default | all | exclusive | anonymous, - Version :: protocol_version(). + Version :: protocol_version() | ssl_record:ssl_version(). %% Description: Returns all default and all supported cipher suites for a %% TLS/DTLS version @@ -1016,10 +1040,10 @@ cipher_suites(Description, Version, StringType) when Version == 'tlsv1.3'; Version == 'tlsv1.2'; Version == 'tlsv1.1'; Version == tlsv1 -> - cipher_suites(Description, tls_record:protocol_version(Version), StringType); + cipher_suites(Description, tls_record:protocol_version_name(Version), StringType); cipher_suites(Description, Version, StringType) when Version == 'dtlsv1.2'; Version == 'dtlsv1'-> - cipher_suites(Description, dtls_record:protocol_version(Version), StringType); + cipher_suites(Description, dtls_record:protocol_version_name(Version), StringType); cipher_suites(Description, Version, rfc) -> [ssl_cipher_format:suite_map_to_str(ssl_cipher_format:suite_bin_to_map(Suite)) || Suite <- supported_suites(Description, Version)]; @@ -1083,6 +1107,41 @@ append_cipher_suites(Filters, Suites) -> Deferred = filter_cipher_suites(Suites, Filters), (Suites -- Deferred) ++ Deferred. +%%-------------------------------------------------------------------- +-spec signature_algs(Description, Version) -> [signature_algs()] when + Description :: default | all | exclusive, + Version :: protocol_version(). + +%% Description: Returns possible signature algorithms/schemes +%% for TLS/DTLS version +%%-------------------------------------------------------------------- + +signature_algs(default, 'tlsv1.3') -> + tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3'), + tls_record:protocol_version_name('tlsv1.2')]); +signature_algs(default, 'tlsv1.2') -> + tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]); +signature_algs(all, 'tlsv1.3') -> + tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3'), + tls_record:protocol_version_name('tlsv1.2')]) ++ + tls_v1:legacy_signature_algs_pre_13(); +signature_algs(all, 'tlsv1.2') -> + tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]) ++ + tls_v1:legacy_signature_algs_pre_13(); +signature_algs(exclusive, 'tlsv1.3') -> + tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3')]); +signature_algs(exclusive, 'tlsv1.2') -> + Algs = tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]), + Algs ++ tls_v1:legacy_signature_algs_pre_13(); +signature_algs(Description, 'dtlsv1.2') -> + signature_algs(Description, 'tlsv1.2'); +signature_algs(Description, Version) when Description == default; + Description == all; + Description == exclusive-> + {error, {signature_algs_not_supported_in_protocol_version, Version}}; +signature_algs(Description,_) -> + {error, {badarg, Description}}. + %%-------------------------------------------------------------------- -spec eccs() -> NamedCurves when NamedCurves :: [named_curve()]. @@ -1121,14 +1180,14 @@ eccs_filter_supported(Curves) -> %% Description: returns all supported groups (TLS 1.3 and later) %%-------------------------------------------------------------------- groups() -> - tls_v1:groups(4). + tls_v1:groups(). %%-------------------------------------------------------------------- -spec groups(default) -> [group()]. %% Description: returns the default groups (TLS 1.3 and later) %%-------------------------------------------------------------------- groups(default) -> - tls_v1:default_groups(4). + tls_v1:default_groups(). %%-------------------------------------------------------------------- -spec getopts(SslSocket, OptionNames) -> @@ -1328,8 +1387,8 @@ versions() -> SupportedTLSVsns = [tls_record:protocol_version(Vsn) || Vsn <- ConfTLSVsns, TLSCryptoSupported(Vsn)], SupportedDTLSVsns = [dtls_record:protocol_version(Vsn) || Vsn <- ConfDTLSVsns, DTLSCryptoSupported(Vsn)], - AvailableTLSVsns = [Vsn || Vsn <- ImplementedTLSVsns, TLSCryptoSupported(tls_record:protocol_version(Vsn))], - AvailableDTLSVsns = [Vsn || Vsn <- ImplementedDTLSVsns, DTLSCryptoSupported(dtls_record:protocol_version(Vsn))], + AvailableTLSVsns = [Vsn || Vsn <- ImplementedTLSVsns, TLSCryptoSupported(tls_record:protocol_version_name(Vsn))], + AvailableDTLSVsns = [Vsn || Vsn <- ImplementedDTLSVsns, DTLSCryptoSupported(dtls_record:protocol_version_name(Vsn))], [{ssl_app, ?VSN}, {supported, SupportedTLSVsns}, @@ -1346,13 +1405,18 @@ versions() -> %% %% Description: Initiates a renegotiation. %%-------------------------------------------------------------------- -renegotiate(#sslsocket{pid = [Pid, Sender |_]}) when is_pid(Pid), +renegotiate(#sslsocket{pid = [Pid, Sender |_]} = Socket) when is_pid(Pid), is_pid(Sender) -> - case tls_sender:renegotiate(Sender) of - {ok, Write} -> - tls_dtls_connection:renegotiation(Pid, Write); - Error -> - Error + case ssl:connection_information(Socket, [protocol]) of + {ok, [{protocol, 'tlsv1.3'}]} -> + {error, notsup}; + _ -> + case tls_sender:renegotiate(Sender) of + {ok, Write} -> + tls_dtls_connection:renegotiation(Pid, Write); + Error -> + Error + end end; renegotiate(#sslsocket{pid = [Pid |_]}) when is_pid(Pid) -> tls_dtls_connection:renegotiation(Pid); @@ -1378,7 +1442,7 @@ update_keys(#sslsocket{pid = [Pid, Sender |_]}, Type0) when is_pid(Pid) andalso read_write -> update_requested end, - tls_connection_1_3:send_key_update(Sender, Type); + tls_gen_connection_1_3:send_key_update(Sender, Type); update_keys(_, Type) -> {error, {illegal_parameter, Type}}. @@ -1408,43 +1472,19 @@ clear_pem_cache() -> ssl_pem_cache:clear(). %%--------------------------------------------------------------- --spec format_error({error, Reason}) -> string() when +-spec format_error(Reason | {error, Reason}) -> string() when Reason :: any(). %% %% Description: Creates error string. %%-------------------------------------------------------------------- format_error({error, Reason}) -> - format_error(Reason); -format_error(Reason) when is_list(Reason) -> - Reason; -format_error(closed) -> - "TLS connection is closed"; -format_error({tls_alert, {_, Description}}) -> - Description; -format_error({options,{FileType, File, Reason}}) when FileType == cacertfile; - FileType == certfile; - FileType == keyfile; - FileType == dhfile -> - Error = file_error_format(Reason), - file_desc(FileType) ++ File ++ ": " ++ Error; -format_error({options, {socket_options, Option, Error}}) -> - lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, format_error(Error)])); -format_error({options, {socket_options, Option}}) -> - lists:flatten(io_lib:format("Invalid socket option: ~p", [Option])); -format_error({options, Options}) -> - lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options])); - -format_error(Error) -> - case inet:format_error(Error) of - "unknown POSIX" ++ _ -> - unexpected_format(Error); - Other -> - Other - end. + do_format_error(Reason); +format_error(Reason) -> + do_format_error(Reason). -tls_version({3, _} = Version) -> +tls_version(Version) when ?TLS_1_X(Version) -> Version; -tls_version({254, _} = Version) -> +tls_version(Version) when ?DTLS_1_X(Version) -> dtls_v1:corresponding_tls_version(Version). %%-------------------------------------------------------------------- @@ -1494,57 +1534,132 @@ str_to_suite(CipherSuiteName) -> %%%-------------------------------------------------------------- %%% Internal functions %%%-------------------------------------------------------------------- -supported_suites(exclusive, {3,Minor}) -> - tls_v1:exclusive_suites(Minor); -supported_suites(exclusive, {254, Minor}) -> - dtls_v1:exclusive_suites(Minor); +supported_suites(exclusive, Version) when ?TLS_1_X(Version) -> + tls_v1:exclusive_suites(Version); +supported_suites(exclusive, Version) when ?DTLS_1_X(Version) -> + dtls_v1:exclusive_suites(Version); supported_suites(default, Version) -> ssl_cipher:suites(Version); supported_suites(all, Version) -> ssl_cipher:all_suites(Version); supported_suites(anonymous, Version) -> ssl_cipher:anonymous_suites(Version); -supported_suites(exclusive_anonymous, {3, Minor}) -> - tls_v1:exclusive_anonymous_suites(Minor); -supported_suites(exclusive_anonymous, {254, Minor}) -> - dtls_v1:exclusive_anonymous_suites(Minor). +supported_suites(exclusive_anonymous, Version) when ?TLS_1_X(Version) -> + tls_v1:exclusive_anonymous_suites(Version); +supported_suites(exclusive_anonymous, Version) when ?DTLS_1_X(Version) -> + dtls_v1:exclusive_anonymous_suites(Version). do_listen(Port, #config{transport_info = {Transport, _, _, _,_}} = Config, tls_gen_connection) -> tls_socket:listen(Transport, Port, Config); do_listen(Port, Config, dtls_gen_connection) -> dtls_socket:listen(Port, Config). - --spec handle_options([any()], client | server) -> {ok, #config{}}; - ([any()], ssl_options()) -> ssl_options(). -handle_options(Opts, Role) -> - handle_options(undefined, undefined, Opts, Role, undefined). - -handle_options(Opts, Role, InheritedSslOpts) -> - handle_options(undefined, undefined, Opts, Role, InheritedSslOpts). +ssl_options() -> + [ + alpn_advertised_protocols, alpn_preferred_protocols, + anti_replay, + beast_mitigation, + cacertfile, cacerts, + cert, certs_keys,certfile, + certificate_authorities, + ciphers, + client_renegotiation, + cookie, + crl_cache, crl_check, + customize_hostname_check, + depth, + dh, dhfile, + + early_data, + eccs, + erl_dist, + fail_if_no_peer_cert, + fallback, + handshake, + hibernate_after, + honor_cipher_order, honor_ecc_order, + keep_secrets, + key, keyfile, + key_update_at, + ktls, + + log_level, + max_handshake_size, + middlebox_comp_mode, + max_fragment_length, + next_protocol_selector, next_protocols_advertised, + ocsp_stapling, ocsp_responder_certs, ocsp_nonce, + padding_check, + partial_chain, + password, + protocol, + psk_identity, + receiver_spawn_opts, + renegotiate_at, + reuse_session, reuse_sessions, + + secure_renegotiate, + sender_spawn_opts, + server_name_indication, + session_tickets, + stateless_tickets_seed, + signature_algs, signature_algs_cert, + sni_fun, + sni_hosts, + srp_identity, + supported_groups, + use_ticket, + use_srtp, + user_lookup_fun, + verify, verify_fun, + versions + ]. %% Handle ssl options at handshake, handshake_continue -handle_options(_, _, Opts0, Role, InheritedSslOpts) when is_map(InheritedSslOpts) -> - {SslOpts, _} = expand_options(Opts0, ?RULES), - process_options(SslOpts, InheritedSslOpts, #{role => Role, - rules => ?RULES}); +-spec update_options([any()], client | server, map()) -> map(). +update_options(Opts, Role, InheritedSslOpts) when is_map(InheritedSslOpts) -> + {UserSslOpts, _} = split_options(Opts, ssl_options()), + process_options(UserSslOpts, InheritedSslOpts, #{role => Role}). + +process_options(UserSslOpts, SslOpts0, Env) -> + %% Reverse option list so we get the last set option if set twice, + %% users depend on it. + UserSslOptsMap = proplists:to_map(lists:reverse(UserSslOpts)), + SslOpts1 = opt_protocol_versions(UserSslOptsMap, SslOpts0, Env), + SslOpts2 = opt_verification(UserSslOptsMap, SslOpts1, Env), + SslOpts3 = opt_certs(UserSslOptsMap, SslOpts2, Env), + SslOpts4 = opt_tickets(UserSslOptsMap, SslOpts3, Env), + SslOpts5 = opt_ocsp(UserSslOptsMap, SslOpts4, Env), + SslOpts6 = opt_sni(UserSslOptsMap, SslOpts5, Env), + SslOpts7 = opt_signature_algs(UserSslOptsMap, SslOpts6, Env), + SslOpts8 = opt_alpn(UserSslOptsMap, SslOpts7, Env), + SslOpts9 = opt_mitigation(UserSslOptsMap, SslOpts8, Env), + SslOpts10 = opt_server(UserSslOptsMap, SslOpts9, Env), + SslOpts11 = opt_client(UserSslOptsMap, SslOpts10, Env), + SslOpts12 = opt_renegotiate(UserSslOptsMap, SslOpts11, Env), + SslOpts13 = opt_reuse_sessions(UserSslOptsMap, SslOpts12, Env), + SslOpts14 = opt_identity(UserSslOptsMap, SslOpts13, Env), + SslOpts15 = opt_supported_groups(UserSslOptsMap, SslOpts14, Env), + SslOpts16 = opt_crl(UserSslOptsMap, SslOpts15, Env), + SslOpts17 = opt_handshake(UserSslOptsMap, SslOpts16, Env), + SslOpts18 = opt_use_srtp(UserSslOptsMap, SslOpts17, Env), + SslOpts = opt_process(UserSslOptsMap, SslOpts18, Env), + SslOpts. + +-spec handle_options([any()], client | server, undefined|host()) -> {ok, #config{}}. +handle_options(Opts, Role, Host) -> + handle_options(undefined, undefined, Opts, Role, Host). + %% Handle all options in listen, connect and handshake handle_options(Transport, Socket, Opts0, Role, Host) -> - {SslOpts0, SockOpts0} = expand_options(Opts0, ?RULES), - - %% Ensure all options are evaluated at startup - SslOpts1 = add_missing_options(SslOpts0, ?RULES), - SslOpts2 = #{protocol := Protocol} - = process_options(SslOpts1, - #{}, - #{role => Role, - host => Host, - rules => ?RULES}), - - maybe_client_warn_no_verify(SslOpts2, Role), - SslOpts = maps:without([warn_verify_none], SslOpts2), + {UserSslOptsList, SockOpts0} = split_options(Opts0, ssl_options()), + + Env = #{role => Role, host => Host}, + SslOpts = process_options(UserSslOptsList, #{}, Env), + %% Handle special options + #{protocol := Protocol} = SslOpts, {Sock, Emulated} = emulated_options(Transport, Socket, Protocol, SockOpts0), ConnetionCb = connection_cb(Protocol), CbInfo = handle_option_cb_info(Opts0, Protocol), @@ -1559,791 +1674,367 @@ handle_options(Transport, Socket, Opts0, Role, Host) -> }}. -%% process_options(SSLOptions, OptionsMap, Env) where -%% SSLOptions is the following tuple: -%% {InOptions, SkippedOptions, Counter} -%% -%% The list of options is processed in multiple passes. When -%% processing an option all dependencies must already be resolved. -%% If there are unresolved dependencies the option will be -%% skipped and processed in a subsequent pass. -%% Counter is equal to the number of unprocessed options at -%% the beginning of a pass. Its value must monotonically decrease -%% after each successful pass. -%% If the value of the counter is unchanged at the end of a pass, -%% the processing stops due to faulty input data. -process_options({[], [], _}, OptionsMap, _Env) -> - OptionsMap; -process_options({[], [_|_] = Skipped, Counter}, OptionsMap, Env) - when length(Skipped) < Counter -> - %% Continue handling options if current pass was successful - process_options({Skipped, [], length(Skipped)}, OptionsMap, Env); -process_options({[], [_|_], _Counter}, _OptionsMap, _Env) -> - throw({error, faulty_configuration}); -process_options({[{K0,V} = E|T], S, Counter}, OptionsMap0, Env) -> - K = maybe_map_key_internal(K0), - case check_dependencies(K, OptionsMap0, Env) of - true -> - OptionsMap = handle_option(K, V, OptionsMap0, Env), - process_options({T, S, Counter}, OptionsMap, Env); - false -> - %% Skip option for next pass - process_options({T, [E|S], Counter}, OptionsMap0, Env) - end. - -handle_option(anti_replay = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(anti_replay = Option, Value0, - #{session_tickets := SessionTickets, - versions := Versions} = OptionsMap, #{rules := Rules}) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - assert_option_dependency(Option, session_tickets, [SessionTickets], [stateless]), - case SessionTickets of - stateless -> - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; - _ -> - OptionsMap#{Option => default_value(Option, Rules)} - end; -handle_option(beast_mitigation = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(beast_mitigation = Option, Value0, #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(cacertfile = Option, unbound, #{cacerts := CaCerts, - verify := Verify, - verify_fun := VerifyFun} = OptionsMap, _Env) - when Verify =:= verify_none orelse - Verify =:= 0 -> - Value = validate_option(Option, ca_cert_default(verify_none, VerifyFun, CaCerts)), - OptionsMap#{Option => Value}; -handle_option(cacertfile = Option, unbound, #{cacerts := CaCerts, - verify := Verify, - verify_fun := VerifyFun} = OptionsMap, _Env) - when Verify =:= verify_peer orelse - Verify =:= 1 orelse - Verify =:= 2 -> - Value = validate_option(Option, ca_cert_default(verify_peer, VerifyFun, CaCerts)), - OptionsMap#{Option => Value}; -handle_option(cacertfile = Option, Value0, OptionsMap, _Env) -> - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(ciphers = Option, unbound, #{versions := Versions} = OptionsMap, #{rules := Rules}) -> - Value = handle_cipher_option(default_value(Option, Rules), Versions), - OptionsMap#{Option => Value}; -handle_option(ciphers = Option, Value0, #{versions := Versions} = OptionsMap, _Env) -> - Value = handle_cipher_option(Value0, Versions), - OptionsMap#{Option => Value}; -handle_option(client_renegotiation = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(server, true, Role), - OptionsMap#{Option => Value}; -handle_option(client_renegotiation = Option, Value0, - #{versions := Versions} = OptionsMap, #{role := Role}) -> - assert_role(server_only, Role, Option, Value0), - assert_option_dependency(Option, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(early_data = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(early_data = Option, Value0, #{session_tickets := SessionTickets, - versions := Versions} = OptionsMap, - #{role := server = Role}) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - assert_option_dependency(Option, session_tickets, [SessionTickets], - [stateful, stateless]), - Value = validate_option(Option, Value0, Role), - OptionsMap#{Option => Value}; -handle_option(early_data = Option, Value0, #{session_tickets := SessionTickets, - use_ticket := UseTicket, - versions := Versions} = OptionsMap, - #{role := client = Role}) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - assert_option_dependency(Option, session_tickets, [SessionTickets], - [manual, auto]), - case UseTicket of - undefined when SessionTickets =/= auto -> - throw({error, {options, dependency, {Option, use_ticket}}}); - _ -> - ok - end, - Value = validate_option(Option, Value0, Role), - OptionsMap#{Option => Value}; -handle_option(eccs = Option, unbound, #{versions := [HighestVersion|_]} = OptionsMap, #{rules := _Rules}) -> - Value = handle_eccs_option(eccs(), HighestVersion), - OptionsMap#{Option => Value}; -handle_option(eccs = Option, Value0, #{versions := [HighestVersion|_]} = OptionsMap, _Env) -> - Value = handle_eccs_option(Value0, HighestVersion), - OptionsMap#{Option => Value}; -handle_option(fallback = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(client, false, Role), - OptionsMap#{Option => Value}; -handle_option(fallback = Option, Value0, OptionsMap, #{role := Role}) -> - assert_role(client_only, Role, Option, Value0), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(certificate_authorities = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(client, false, Role), - OptionsMap#{Option => Value}; -handle_option(certificate_authorities = Option, Value0, #{versions := Versions} = OptionsMap, #{role := Role}) -> - assert_role(client_only, Role, Option, Value0), - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(cookie = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(server, true, Role), - OptionsMap#{Option => Value}; -handle_option(cookie = Option, Value0, #{versions := Versions} = OptionsMap, #{role := Role}) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - assert_role(server_only, Role, Option, Value0), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(honor_cipher_order = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(server, false, Role), - OptionsMap#{Option => Value}; -handle_option(honor_cipher_order = Option, Value0, OptionsMap, #{role := Role}) -> - assert_role(server_only, Role, Option, Value0), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(honor_ecc_order = Option, unbound, OptionsMap, #{role := Role}) -> - Value = default_option_role(server, false, Role), - OptionsMap#{Option => Value}; -handle_option(honor_ecc_order = Option, Value0, OptionsMap, #{role := Role}) -> - assert_role(server_only, Role, Option, Value0), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(keyfile = Option, unbound, #{certfile := CertFile} = OptionsMap, _Env) -> - Value = validate_option(Option, CertFile), - OptionsMap#{Option => Value}; -handle_option(key_update_at = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(key_update_at = Option, Value0, #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(next_protocols_advertised = Option, unbound, OptionsMap, - #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(next_protocols_advertised = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(next_protocols_advertised, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(next_protocol_selector = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = default_value(Option, Rules), - OptionsMap#{Option => Value}; -handle_option(next_protocol_selector = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(client_preferred_next_protocols, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = make_next_protocol_selector( - validate_option(client_preferred_next_protocols, Value0)), - OptionsMap#{Option => Value}; -handle_option(padding_check = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(padding_check = Option, Value0, #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(password = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{password => Value}; -handle_option(password = Option, Value0, OptionsMap, _Env) -> - Value = validate_option(Option, Value0), - OptionsMap#{password => Value}; -handle_option(psk_identity = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(psk_identity = Option, Value0, #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(secure_renegotiate = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(secure_renegotiate= Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(secure_renegotiate, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(reuse_session = Option, unbound, OptionsMap, #{role := Role}) -> - Value = - case Role of - client -> - undefined; - server -> - fun(_, _, _, _) -> true end +opt_protocol_versions(UserOpts, Opts, Env) -> + {_, PRC} = get_opt_of(protocol, [tls, dtls], tls, UserOpts, Opts), + + LogLevels = [none, all, emergency, alert, critical, error, + warning, notice, info, debug], + + DefaultLevel = case logger:get_module_level(?MODULE) of + [] -> notice; + [{ssl,Level}] -> Level + end, + + {_, LL} = get_opt_of(log_level, LogLevels, DefaultLevel, UserOpts, Opts), + + Opts1 = set_opt_bool(keep_secrets, false, UserOpts, Opts), + + {DistW, Dist} = get_opt_bool(erl_dist, false, UserOpts, Opts1), + option_incompatible(PRC =:= dtls andalso Dist, [{protocol, PRC}, {erl_dist, Dist}]), + Opts2 = set_opt_new(DistW, erl_dist, false, Dist, Opts1), + + {KtlsW, Ktls} = get_opt_bool(ktls, false, UserOpts, Opts1), + option_incompatible(PRC =:= dtls andalso Ktls, [{protocol, PRC}, {ktls, Ktls}]), + Opts3 = set_opt_new(KtlsW, ktls, false, Ktls, Opts2), + + opt_versions(UserOpts, Opts3#{protocol => PRC, log_level => LL}, Env). + +opt_versions(UserOpts, #{protocol := Protocol} = Opts, _Env) -> + Versions = case get_opt(versions, unbound, UserOpts, Opts) of + {default, unbound} -> default_versions(Protocol); + {new, Vs} -> validate_versions(Protocol, Vs); + {old, Vs} -> Vs + end, + + {Where, MCM} = get_opt_bool(middlebox_comp_mode, true, UserOpts, Opts), + assert_version_dep(Where =:= new, middlebox_comp_mode, Versions, ['tlsv1.3']), + Opts1 = set_opt_new(Where, middlebox_comp_mode, true, MCM, Opts), + Opts1#{versions => Versions}. + +default_versions(tls) -> + Vsns0 = tls_record:supported_protocol_versions(), + lists:sort(fun tls_record:is_higher/2, Vsns0); +default_versions(dtls) -> + Vsns0 = dtls_record:supported_protocol_versions(), + lists:sort(fun dtls_record:is_higher/2, Vsns0). + +validate_versions(tls, Vsns0) -> + Validate = + fun(Version) -> + try tls_record:sufficient_crypto_support(Version) of + true -> tls_record:protocol_version_name(Version); + false -> option_error(insufficient_crypto_support, + {Version, {versions, Vsns0}}) + catch error:function_clause -> + option_error(Version, {versions, Vsns0}) + end end, - OptionsMap#{Option => Value}; -handle_option(reuse_session = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(reuse_session, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -%% TODO: validate based on role -handle_option(reuse_sessions = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(reuse_sessions = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(reuse_sessions, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(server_name_indication = Option, unbound, OptionsMap, #{host := Host, - role := Role}) -> - Value = default_option_role(client, server_name_indication_default(Host), Role), - OptionsMap#{Option => Value}; -handle_option(server_name_indication = Option, Value0, OptionsMap, _Env) -> - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(session_tickets = Option, unbound, OptionsMap, #{role := Role, - rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules), Role), - OptionsMap#{Option => Value}; -handle_option(session_tickets = Option, Value0, #{versions := Versions} = OptionsMap, #{role := Role}) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - Value = validate_option(Option, Value0, Role), - OptionsMap#{Option => Value}; -handle_option(signature_algs = Option, unbound, #{versions := [HighestVersion | _] = Versions} = OptionsMap, #{role := Role}) -> - Value = - handle_hashsigns_option( - default_option_role_sign_algs( - server, - tls_v1:default_signature_algs(Versions), - Role, - HighestVersion), - tls_version(HighestVersion)), - OptionsMap#{Option => Value}; -handle_option(signature_algs = Option, Value0, #{versions := [HighestVersion|_]} = OptionsMap, _Env) -> - Value = handle_hashsigns_option(Value0, tls_version(HighestVersion)), - OptionsMap#{Option => Value}; -handle_option(signature_algs_cert = Option, unbound, #{versions := [HighestVersion|_]} = OptionsMap, _Env) -> - %% Do not send by default - Value = handle_signature_algorithms_option(undefined, tls_version(HighestVersion)), - OptionsMap#{Option => Value}; -handle_option(signature_algs_cert = Option, Value0, #{versions := [HighestVersion|_]} = OptionsMap, _Env) -> - Value = handle_signature_algorithms_option(Value0, tls_version(HighestVersion)), - OptionsMap#{Option => Value}; -handle_option(sni_fun = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = default_value(Option, Rules), - OptionsMap#{Option => Value}; -handle_option(sni_fun = Option, Value0, OptionsMap, _Env) -> - validate_option(Option, Value0), - OptHosts = maps:get(sni_hosts, OptionsMap, undefined), - Value = - case {Value0, OptHosts} of - {undefined, _} -> - Value0; - {_, []} -> - Value0; - _ -> - throw({error, {conflict_options, [sni_fun, sni_hosts]}}) + Vsns = [Validate(V) || V <- Vsns0], + tls_validate_version_gap(Vsns0), + option_error([] =:= Vsns, versions, Vsns0), + lists:sort(fun tls_record:is_higher/2, Vsns); +validate_versions(dtls, Vsns0) -> + Validate = + fun(Version) -> + try tls_record:sufficient_crypto_support( + dtls_v1:corresponding_tls_version( + dtls_record:protocol_version_name(Version))) of + true -> dtls_record:protocol_version_name(Version); + false-> option_error(insufficient_crypto_support, + {Version, {versions, Vsns0}}) + catch error:function_clause -> + option_error(Version, {versions, Vsns0}) + end end, - OptionsMap#{Option => Value}; -handle_option(srp_identity = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(srp_identity = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(srp_identity, versions, Versions, - ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(supported_groups = Option, unbound, #{versions := [HighestVersion|_]} = OptionsMap, #{rules := _Rules}) -> - Value = handle_supported_groups_option(groups(default), HighestVersion), - OptionsMap#{Option => Value}; -handle_option(supported_groups = Option, Value0, - #{versions := [HighestVersion|_] = Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - Value = handle_supported_groups_option(Value0, HighestVersion), - OptionsMap#{Option => Value}; -handle_option(use_ticket = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(use_ticket = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1.3']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(user_lookup_fun = Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(user_lookup_fun = Option, Value0, - #{versions := Versions} = OptionsMap, _Env) -> - assert_option_dependency(Option, versions, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(verify = Option, unbound, OptionsMap, #{rules := Rules}) -> - handle_verify_option(default_value(Option, Rules), OptionsMap#{warn_verify_none => true}); -handle_option(verify = _Option, Value, OptionsMap, _Env) -> - handle_verify_option(Value, OptionsMap); -handle_option(verify_fun = Option, unbound, #{verify := Verify} = OptionsMap, #{rules := Rules}) - when Verify =:= verify_none -> - OptionsMap#{Option => default_value(Option, Rules)}; -handle_option(verify_fun = Option, unbound, #{verify := Verify} = OptionsMap, _Env) - when Verify =:= verify_peer -> - OptionsMap#{Option => undefined}; -handle_option(verify_fun = Option, Value0, OptionsMap, _Env) -> - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}; -handle_option(versions = Option, unbound, #{protocol := Protocol} = OptionsMap, _Env) -> - RecordCb = record_cb(Protocol), - Vsns0 = RecordCb:supported_protocol_versions(), - Value = lists:sort(fun RecordCb:is_higher/2, Vsns0), - OptionsMap#{Option => Value}; -handle_option(versions = Option, Vsns0, #{protocol := Protocol} = OptionsMap, _Env) -> - validate_option(versions, Vsns0), - RecordCb = record_cb(Protocol), - Vsns1 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns0], - Value = lists:sort(fun RecordCb:is_higher/2, Vsns1), - OptionsMap#{Option => Value}; -%% Special options -handle_option(cb_info = Option, unbound, #{protocol := Protocol} = OptionsMap, _Env) -> - Default = default_cb_info(Protocol), - validate_option(Option, Default), - Value = handle_cb_info(Default), - OptionsMap#{Option => Value}; -handle_option(cb_info = Option, Value0, OptionsMap, _Env) -> - validate_option(Option, Value0), - Value = handle_cb_info(Value0), - OptionsMap#{Option => Value}; -%% Generic case -handle_option(Option, unbound, OptionsMap, #{rules := Rules}) -> - Value = validate_option(Option, default_value(Option, Rules)), - OptionsMap#{Option => Value}; -handle_option(Option, Value0, OptionsMap, _Env) -> - Value = validate_option(Option, Value0), - OptionsMap#{Option => Value}. - -handle_option_cb_info(Options, Protocol) -> - Value = proplists:get_value(cb_info, Options, default_cb_info(Protocol)), - #{cb_info := CbInfo} = handle_option(cb_info, Value, #{protocol => Protocol}, #{}), - CbInfo. - - -maybe_map_key_internal(client_preferred_next_protocols) -> - next_protocol_selector; -maybe_map_key_internal(K) -> - K. - -maybe_map_key_external(next_protocol_selector) -> - client_preferred_next_protocols; -maybe_map_key_external(K) -> - K. - -check_dependencies(K, OptionsMap, Env) -> - Rules = maps:get(rules, Env), - Deps = get_dependencies(K, Rules), - case Deps of - [] -> - true; - L -> - option_already_defined(K,OptionsMap) orelse - dependecies_already_defined(L, OptionsMap) + Vsns = [Validate(V) || V <- Vsns0], + option_error([] =:= Vsns, versions, Vsns0), + lists:sort(fun dtls_record:is_higher/2, Vsns). + +opt_verification(UserOpts, Opts0, #{role := Role} = Env) -> + {Verify, Opts1} = + case get_opt_of(verify, [verify_none, verify_peer], default_verify(Role), UserOpts, Opts0) of + {old, Val} -> + {Val, Opts0}; + {_, verify_none} -> + {verify_none, Opts0#{verify => verify_none, verify_fun => {none_verify_fun(), []}}}; + {_, verify_peer} -> + %% If 'verify' is changed from verify_none to verify_peer, (via update_options/3) + %% the 'verify_fun' must also be changed to undefined. + %% i.e remove verify_none fun + Temp = Opts0#{verify => verify_peer, verify_fun => undefined}, + {verify_peer, maps:remove(fail_if_no_peer_cert, Temp)} + end, + Opts2 = opt_cacerts(UserOpts, Opts1, Env), + {_, PartialChain} = get_opt_fun(partial_chain, 1, fun(_) -> unknown_ca end, UserOpts, Opts2), + + DefFailNoPeer = Role =:= server andalso Verify =:= verify_peer, + {_, FailNoPeerCert} = get_opt_bool(fail_if_no_peer_cert, DefFailNoPeer, UserOpts, Opts2), + assert_server_only(Role, FailNoPeerCert, fail_if_no_peer_cert), + option_incompatible(FailNoPeerCert andalso Verify =:= verify_none, + [{verify, verify_none}, {fail_if_no_peer_cert, true}]), + + Opts = set_opt_int(depth, 0, 255, ?DEFAULT_DEPTH, UserOpts, Opts2), + + case Role of + client -> + opt_verify_fun(UserOpts, Opts#{partial_chain => PartialChain}, + Env); + server -> + opt_verify_fun(UserOpts, Opts#{partial_chain => PartialChain, + fail_if_no_peer_cert => FailNoPeerCert}, + Env) end. +default_verify(client) -> + %% Server authenication is by default requiered + verify_peer; +default_verify(server) -> + %% Client certification is an optional part of the protocol + verify_none. + +opt_verify_fun(UserOpts, Opts, _Env) -> + %%DefVerifyNoneFun = {default_verify_fun(), []}, + VerifyFun = case get_opt(verify_fun, undefined, UserOpts, Opts) of + {_, {F,_} = FA} when is_function(F, 3); is_function(F, 4) -> + FA; + {_, UserFun} when is_function(UserFun, 1) -> + {convert_verify_fun(), UserFun}; + {_, undefined} -> + undefined; + {_, Value} -> + option_error(verify_fun, Value) + end, + Opts#{verify_fun => VerifyFun}. + +none_verify_fun() -> + fun(_, {bad_cert, _}, UserState) -> + {valid, UserState}; + (_, {extension, #'Extension'{critical = true}}, UserState) -> + %% This extension is marked as critical, so + %% certificate verification should fail if we don't + %% understand the extension. However, this is + %% `verify_none', so let's accept it anyway. + {valid, UserState}; + (_, {extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end. + +convert_verify_fun() -> + fun(_,{bad_cert, _} = Reason, OldFun) -> + case OldFun([Reason]) of + true -> {valid, OldFun}; + false -> {fail, Reason} + end; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> + {valid, UserState} + end. -%% Handle options that are not present in the map -get_dependencies(K, _) when K =:= cb_info orelse K =:= log_alert-> - []; -get_dependencies(K, Rules) -> - {_, Deps} = maps:get(K, Rules), - Deps. - - -option_already_defined(K, Map) -> - maps:get(K, Map, unbound) =/= unbound. - - -dependecies_already_defined(L, OptionsMap) -> - Fun = fun (E) -> option_already_defined(E, OptionsMap) end, - lists:all(Fun, L). +opt_certs(UserOpts, #{log_level := LogLevel} = Opts0, Env) -> + case get_opt_list(certs_keys, [], UserOpts, Opts0) of + {Where, []} when Where =/= new -> + opt_old_certs(UserOpts, #{}, Opts0, Env); + {old, [CertKey]} -> + opt_old_certs(UserOpts, CertKey, Opts0, Env); + {Where, CKs} when is_list(CKs) -> + warn_override(Where, UserOpts, certs_keys, [cert,certfile,key,keyfile,password], LogLevel), + Opts0#{certs_keys => [check_cert_key(CK, #{}, LogLevel) || CK <- CKs]} + end. +opt_old_certs(UserOpts, CertKeys, #{log_level := LogLevel}=SSLOpts, _Env) -> + CK = check_cert_key(UserOpts, CertKeys, LogLevel), + case maps:keys(CK) =:= [] of + true -> + SSLOpts#{certs_keys => []}; + false -> + SSLOpts#{certs_keys => [CK]} + end. -expand_options(Opts0, Rules) -> - Opts1 = proplists:expand([{binary, [{mode, binary}]}, - {list, [{mode, list}]}], Opts0), - Opts2 = handle_option_format(Opts1, []), +check_cert_key(UserOpts, CertKeys, LogLevel) -> + CertKeys0 = case get_opt(cert, undefined, UserOpts, CertKeys) of + {Where, Cert} when is_binary(Cert) -> + warn_override(Where, UserOpts, cert, [certfile], LogLevel), + CertKeys#{cert => [Cert]}; + {Where, [C0|_] = Certs} when is_binary(C0) -> + warn_override(Where, UserOpts, cert, [certfile], LogLevel), + CertKeys#{cert => Certs}; + {new, Err0} -> + option_error(cert, Err0); + {_, undefined} -> + case get_opt_file(certfile, unbound, UserOpts, CertKeys) of + {default, unbound} -> CertKeys; + {_, CertFile} -> CertKeys#{certfile => CertFile} + end + end, - %% Remove deprecated ssl_imp option - Opts = proplists:delete(ssl_imp, Opts2), - AllOpts = maps:keys(Rules), - SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) end, - Opts, - AllOpts ++ - [ssl_imp, %% TODO: remove ssl_imp - cb_info, - client_preferred_next_protocols, %% next_protocol_selector - log_alert]), %% obsoleted by log_level - - SslOpts0 = Opts -- SockOpts, - SslOpts = {SslOpts0, [], length(SslOpts0)}, - {SslOpts, SockOpts}. - - -add_missing_options({L0, S, _C}, Rules) -> - Fun = fun(K0, Acc) -> - K = maybe_map_key_external(K0), - case proplists:is_defined(K, Acc) of - true -> - Acc; - false -> - Default = unbound, - [{K, Default}|Acc] - end - end, - AllOpts = maps:keys(Rules), - L = lists:foldl(Fun, L0, AllOpts), - {L, S, length(L)}. + CertKeys1 = case get_opt(key, undefined, UserOpts, CertKeys) of + {_, undefined} -> + case get_opt_file(keyfile, <<>>, UserOpts, CertKeys) of + {new, KeyFile} -> + CertKeys0#{keyfile => KeyFile}; + {_, <<>>} -> + case maps:get(certfile, CertKeys0, unbound) of + unbound -> CertKeys0; + CF -> CertKeys0#{keyfile => CF} + end; + {old, _} -> + CertKeys0 + end; + {_, {KF, K0} = Key} + when is_binary(K0), KF =:= rsa; KF =:= dsa; + KF == 'RSAPrivateKey'; KF == 'DSAPrivateKey'; + KF == 'ECPrivateKey'; KF == 'PrivateKeyInfo' -> + CertKeys0#{key => Key}; + {_, #{engine := _, key_id := _, algorithm := _} = Key} -> + CertKeys0#{key => Key}; + {new, Err1} -> + option_error(key, Err1) + end, -default_value(Key, Rules) -> - {Default, _} = maps:get(Key, Rules, {undefined, []}), - Default. + CertKeys2 = case get_opt(password, unbound, UserOpts,CertKeys) of + {default, _} -> CertKeys1; + {_, Pwd} when is_binary(Pwd); is_list(Pwd) -> + CertKeys1#{password => fun() -> Pwd end}; + {_, Pwd} when is_function(Pwd, 0) -> + CertKeys1#{password => Pwd}; + {_, Err2} -> + option_error(password, Err2) + end, + CertKeys2. + +opt_cacerts(UserOpts, #{verify := Verify, log_level := LogLevel, versions := Versions} = Opts, + #{role := Role}) -> + {_, CaCerts} = get_opt_list(cacerts, undefined, UserOpts, Opts), + + CaCertFile = case get_opt_file(cacertfile, <<>>, UserOpts, Opts) of + {Where1, _FileName} when CaCerts =/= undefined -> + warn_override(Where1, UserOpts, cacerts, [cacertfile], LogLevel), + <<>>; + {new, FileName} -> unambiguous_path(FileName); + {_, FileName} -> FileName + end, + option_incompatible(CaCertFile =:= <<>> andalso CaCerts =:= undefined andalso Verify =:= verify_peer, + [{verify, verify_peer}, {cacerts, undefined}]), + + {Where2, CA} = get_opt_bool(certificate_authorities, Role =:= server, UserOpts, Opts), + assert_version_dep(Where2 =:= new, certificate_authorities, Versions, ['tlsv1.3']), + + Opts1 = set_opt_new(new, cacertfile, <<>>, CaCertFile, Opts), + Opts2 = set_opt_new(Where2, certificate_authorities, Role =:= server, CA, Opts1), + Opts2#{cacerts => CaCerts}. + +opt_tickets(UserOpts, #{versions := Versions} = Opts, #{role := client}) -> + {_, SessionTickets} = get_opt_of(session_tickets, [disabled,manual,auto], disabled, UserOpts, Opts), + assert_version_dep(SessionTickets =/= disabled, session_tickets, Versions, ['tlsv1.3']), + + {_, UseTicket} = get_opt_list(use_ticket, undefined, UserOpts, Opts), + option_error(UseTicket =:= [], use_ticket, UseTicket), + option_incompatible(UseTicket =/= undefined andalso SessionTickets =/= manual, + [{use_ticket, UseTicket}, {session_tickets, SessionTickets}]), + + {_, EarlyData} = get_opt_bin(early_data, undefined, UserOpts, Opts), + option_incompatible(is_binary(EarlyData) andalso SessionTickets =:= disabled, + [early_data, {session_tickets, disabled}]), + option_incompatible(is_binary(EarlyData) andalso SessionTickets =:= manual andalso UseTicket =:= undefined, + [early_data, {session_tickets, manual}, {use_ticket, undefined}]), + + assert_server_only(anti_replay, UserOpts), + assert_server_only(stateless_tickets_seed, UserOpts), + Opts#{session_tickets => SessionTickets, use_ticket => UseTicket, early_data => EarlyData}; +opt_tickets(UserOpts, #{versions := Versions} = Opts, #{role := server}) -> + {_, SessionTickets} = + get_opt_of(session_tickets, + [disabled, stateful, stateless, stateful_with_cert, stateless_with_cert], + disabled, + UserOpts, + Opts), + assert_version_dep(SessionTickets =/= disabled, session_tickets, Versions, ['tlsv1.3']), + + {_, EarlyData} = get_opt_of(early_data, [enabled, disabled], disabled, UserOpts, Opts), + option_incompatible(SessionTickets =:= disabled andalso EarlyData =:= enabled, + [early_data, {session_tickets, disabled}]), + + Stateless = lists:member(SessionTickets, [stateless, stateless_with_cert]), + + AntiReplay = + case get_opt(anti_replay, undefined, UserOpts, Opts) of + {_, undefined} -> undefined; + {_,AR} when not Stateless -> + option_incompatible([{anti_replay, AR}, {session_tickets, SessionTickets}]); + {_,'10k'} -> {10, 5, 72985}; %% n = 10000 p = 0.030003564 (1 in 33) m = 72985 (8.91KiB) k = 5 + {_,'100k'} -> {10, 5, 729845}; %% n = 10000 p = 0.03000428 (1 in 33) m = 729845 (89.09KiB) k = 5 + {_, {_,_,_} = AR} -> AR; + {_, AR} -> option_error(anti_replay, AR) + end, + {_, STS} = get_opt_bin(stateless_tickets_seed, undefined, UserOpts, Opts), + option_incompatible(STS =/= undefined andalso not Stateless, + [stateless_tickets_seed, {session_tickets, SessionTickets}]), -assert_role(client_only, client, _, _) -> - ok; -assert_role(server_only, server, _, _) -> - ok; -assert_role(client_only, _, _, undefined) -> - ok; -assert_role(server_only, _, _, undefined) -> - ok; -assert_role(Type, _, Key, _) -> - throw({error, {option, Type, Key}}). + assert_client_only(use_ticket, UserOpts), + Opts#{session_tickets => SessionTickets, early_data => EarlyData, + anti_replay => AntiReplay, stateless_tickets_seed => STS}. -assert_option_dependency(Option, OptionDep, Values0, AllowedValues) -> - case is_dtls_configured(Values0) of +opt_ocsp(UserOpts, #{versions := _Versions} = Opts, #{role := Role}) -> + {Stapling, SMap} = + case get_opt(ocsp_stapling, ?DEFAULT_OCSP_STAPLING, UserOpts, Opts) of + {old, Map} when is_map(Map) -> {true, Map}; + {_, Bool} when is_boolean(Bool) -> {Bool, #{}}; + {_, Value} -> option_error(ocsp_stapling, Value) + end, + assert_client_only(Role, Stapling, ocsp_stapling), + {_, Nonce} = get_opt_bool(ocsp_nonce, ?DEFAULT_OCSP_NONCE, UserOpts, SMap), + option_incompatible(Stapling =:= false andalso Nonce =:= false, + [{ocsp_nonce, false}, {ocsp_stapling, false}]), + {_, ORC} = get_opt_list(ocsp_responder_certs, ?DEFAULT_OCSP_RESPONDER_CERTS, + UserOpts, SMap), + CheckBinary = fun(Cert) when is_binary(Cert) -> ok; + (_Cert) -> option_error(ocsp_responder_certs, ORC) + end, + [CheckBinary(C) || C <- ORC], + option_incompatible(Stapling =:= false andalso ORC =/= [], + [ocsp_responder_certs, {ocsp_stapling, false}]), + case Stapling of true -> - %% TODO: Check option dependency for DTLS - ok; + Opts#{ocsp_stapling => + #{ocsp_nonce => Nonce, + ocsp_responder_certs => ORC}}; false -> - %% special handling for version - Values = - case OptionDep of - versions -> - lists:map(fun tls_record:protocol_version/1, Values0); - _ -> - Values0 - end, - Set1 = sets:from_list(Values), - Set2 = sets:from_list(AllowedValues), - case sets:size(sets:intersection(Set1, Set2)) > 0 of - true -> - ok; - false -> - throw({error, {options, dependency, - {Option, {OptionDep, AllowedValues}}}}) - end + Opts end. -is_dtls_configured(Versions) -> - Fun = fun (Version) when Version =:= {254, 253} orelse - Version =:= {254, 255} -> - true; - (_) -> - false - end, - lists:any(Fun, Versions). - -validate_option(Option, Value) -> - validate_option(Option, Value, undefined). -%% -validate_option(Opt, Value, _) - when Opt =:= alpn_advertised_protocols orelse - Opt =:= alpn_preferred_protocols, - is_list(Value) -> - validate_binary_list(Opt, Value), - Value; -validate_option(Opt, Value, _) - when Opt =:= alpn_advertised_protocols orelse - Opt =:= alpn_preferred_protocols, - Value =:= undefined -> - undefined; -validate_option(anti_replay, '10k', _) -> - %% n = 10000 - %% p = 0.030003564 (1 in 33) - %% m = 72985 (8.91KiB) - %% k = 5 - {10, 5, 72985}; -validate_option(anti_replay, '100k', _) -> - %% n = 100000 - %% p = 0.03000428 (1 in 33) - %% m = 729845 (89.09KiB) - %% k = 5 - {10, 5, 729845}; -validate_option(anti_replay, Value, _) - when (is_tuple(Value) andalso - tuple_size(Value) =:= 3) -> - Value; -validate_option(beast_mitigation, Value, _) - when Value == one_n_minus_one orelse - Value == zero_n orelse - Value == disabled -> - Value; -%% certfile must be present in some cases otherwise it can be set -%% to the empty string. -validate_option(cacertfile, undefined, _) -> - <<>>; -validate_option(cacertfile, Value, _) - when is_binary(Value) -> - unambiguous_path(Value); -validate_option(cacertfile, Value, _) - when is_list(Value), Value =/= ""-> - binary_filename(unambiguous_path(Value)); -validate_option(cacerts, Value, _) - when Value == undefined; - is_list(Value) -> - Value; -validate_option(cb_info, {V1, V2, V3, V4} = Value, _) - when is_atom(V1), - is_atom(V2), - is_atom(V3), - is_atom(V4) -> - Value; -validate_option(cb_info, {V1, V2, V3, V4, V5} = Value, _) - when is_atom(V1), - is_atom(V2), - is_atom(V3), - is_atom(V4), - is_atom(V5) -> - Value; -validate_option(cert, Value, _) when Value == undefined; - is_list(Value)-> - Value; -validate_option(cert, Value, _) when Value == undefined; - is_binary(Value)-> - [Value]; -validate_option(certificate_authorities, Value, _) when is_boolean(Value)-> - Value; -validate_option(certfile, undefined = Value, _) -> - Value; -validate_option(certfile, Value, _) - when is_binary(Value) -> - Value; -validate_option(certfile, Value, _) - when is_list(Value) -> - binary_filename(Value); -validate_option(client_preferred_next_protocols, {Precedence, PreferredProtocols}, _) - when is_list(PreferredProtocols) -> - validate_binary_list(client_preferred_next_protocols, PreferredProtocols), - validate_npn_ordering(Precedence), - {Precedence, PreferredProtocols, ?NO_PROTOCOL}; -validate_option(client_preferred_next_protocols, - {Precedence, PreferredProtocols, Default} = Value, _) - when is_list(PreferredProtocols), is_binary(Default), - byte_size(Default) > 0, byte_size(Default) < 256 -> - validate_binary_list(client_preferred_next_protocols, PreferredProtocols), - validate_npn_ordering(Precedence), - Value; -validate_option(client_preferred_next_protocols, undefined, _) -> - undefined; -validate_option(client_renegotiation, Value, _) - when is_boolean(Value) -> - Value; -validate_option(cookie, Value, _) - when is_boolean(Value) -> - Value; -validate_option(crl_cache, {Cb, {_Handle, Options}} = Value, _) - when is_atom(Cb) and is_list(Options) -> - Value; -validate_option(crl_check, Value, _) - when is_boolean(Value) -> - Value; -validate_option(crl_check, Value, _) - when (Value == best_effort) or - (Value == peer) -> - Value; -validate_option(customize_hostname_check, Value, _) - when is_list(Value) -> - Value; -validate_option(depth, Value, _) - when is_integer(Value), - Value >= 0, Value =< 255-> - Value; -validate_option(dh, Value, _) - when Value == undefined; - is_binary(Value) -> - Value; -validate_option(dhfile, undefined = Value, _) -> - Value; -validate_option(dhfile, Value, _) - when is_binary(Value) -> - Value; -validate_option(dhfile, Value, _) - when is_list(Value), Value =/= "" -> - binary_filename(Value); -validate_option(early_data, Value, server) - when Value =:= disabled orelse - Value =:= enabled -> - Value; -validate_option(early_data = Option, Value, server) -> - throw({error, - {options, role, {Option, {Value, {server, [disabled, enabled]}}}}}); -validate_option(early_data, Value, client) - when is_binary(Value) -> - Value; -validate_option(early_data = Option, Value, client) -> - throw({error, - {options, type, {Option, {Value, not_binary}}}}); -validate_option(erl_dist, Value, _) - when is_boolean(Value) -> - Value; -validate_option(fail_if_no_peer_cert, Value, _) - when is_boolean(Value) -> - Value; -validate_option(fallback, Value, _) - when is_boolean(Value) -> - Value; -validate_option(handshake, hello = Value, _) -> - Value; -validate_option(handshake, full = Value, _) -> - Value; -validate_option(hibernate_after, undefined, _) -> %% Backwards compatibility - infinity; -validate_option(hibernate_after, infinity, _) -> - infinity; -validate_option(hibernate_after, Value, _) - when is_integer(Value), Value >= 0 -> - Value; -validate_option(honor_cipher_order, Value, _) - when is_boolean(Value) -> - Value; -validate_option(honor_ecc_order, Value, _) - when is_boolean(Value) -> - Value; -validate_option(keep_secrets, Value, _) when is_boolean(Value) -> - Value; -validate_option(key, undefined, _) -> - undefined; -validate_option(key, {KeyType, Value}, _) - when is_binary(Value), - KeyType == rsa; %% Backwards compatibility - KeyType == dsa; %% Backwards compatibility - KeyType == 'RSAPrivateKey'; - KeyType == 'DSAPrivateKey'; - KeyType == 'ECPrivateKey'; - KeyType == 'PrivateKeyInfo' -> - {KeyType, Value}; -validate_option(key, #{algorithm := _} = Value, _) -> - Value; -validate_option(keyfile, undefined, _) -> - <<>>; -validate_option(keyfile, Value, _) - when is_binary(Value) -> - Value; -validate_option(keyfile, Value, _) - when is_list(Value), Value =/= "" -> - binary_filename(Value); -validate_option(key_update_at, Value, _) - when is_integer(Value) andalso - Value > 0 -> - Value; -validate_option(log_level, Value, _) when - is_atom(Value) andalso - (Value =:= none orelse - Value =:= all orelse - Value =:= emergency orelse - Value =:= alert orelse - Value =:= critical orelse - Value =:= error orelse - Value =:= warning orelse - Value =:= notice orelse - Value =:= info orelse - Value =:= debug) -> - Value; -%% RFC 6066, Section 4 -validate_option(max_fragment_length, I, _) - when I == ?MAX_FRAGMENT_LENGTH_BYTES_1; - I == ?MAX_FRAGMENT_LENGTH_BYTES_2; - I == ?MAX_FRAGMENT_LENGTH_BYTES_3; - I == ?MAX_FRAGMENT_LENGTH_BYTES_4 -> - I; -validate_option(max_fragment_length, undefined, _) -> - undefined; -validate_option(max_handshake_size, Value, _) - when is_integer(Value) andalso - Value =< ?MAX_UNIT24 -> - Value; -validate_option(middlebox_comp_mode, Value, _) - when is_boolean(Value) -> - Value; -validate_option(next_protocols_advertised, Value, _) when is_list(Value) -> - validate_binary_list(next_protocols_advertised, Value), - Value; -validate_option(next_protocols_advertised, undefined, _) -> - undefined; -validate_option(ocsp_nonce, Value, _) - when Value =:= true orelse - Value =:= false -> - Value; -%% The OCSP responders' certificates can be given as a suggestion and -%% will be used to verify the OCSP response. -validate_option(ocsp_responder_certs, Value, _) - when is_list(Value) -> - [public_key:pkix_decode_cert(CertDer, plain) || CertDer <- Value, - is_binary(CertDer)]; -validate_option(ocsp_stapling, Value, _) - when Value =:= true orelse - Value =:= false -> - Value; -validate_option(padding_check, Value, _) - when is_boolean(Value) -> - Value; -validate_option(partial_chain, Value, _) - when is_function(Value) -> - Value; -validate_option(password, Value, _) - when is_list(Value) -> - Value; -validate_option(password, Value, _) - when is_function(Value, 0) -> - Value; -validate_option(protocol, Value = tls, _) -> - Value; -validate_option(protocol, Value = dtls, _) -> - Value; -validate_option(psk_identity, undefined, _) -> - undefined; -validate_option(psk_identity, Identity, _) - when is_list(Identity), Identity =/= "", length(Identity) =< 65535 -> - binary_filename(Identity); -validate_option(renegotiate_at, Value, _) when is_integer(Value) -> - erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT); -validate_option(reuse_session, undefined, _) -> - undefined; -validate_option(reuse_session, Value, _) - when is_function(Value) -> - Value; -validate_option(reuse_session, Value, _) - when is_binary(Value) -> - Value; -validate_option(reuse_session, {Id, Data} = Value, _) - when is_binary(Id) andalso - is_binary(Data) -> - Value; -validate_option(reuse_sessions, Value, _) - when is_boolean(Value) -> - Value; -validate_option(reuse_sessions, save = Value, _) -> - Value; -validate_option(secure_renegotiate, Value, _) - when is_boolean(Value) -> - Value; -validate_option(server_name_indication, Value, _) - when is_list(Value) -> +opt_sni(UserOpts, #{versions := _Versions} = Opts, #{role := server}) -> + {_, SniHosts} = get_opt_list(sni_hosts, [], UserOpts, Opts), + %% Postpone option checking until all other options are checked FIXME + Check = fun({[_|_], SO}) when is_list(SO) -> + case proplists:get_value(sni_hosts, SO, undefined) of + undefined -> ok; + Recursive -> option_error(sni_hosts, Recursive) + end; + (HostOpts) -> option_error(sni_hosts, HostOpts) + end, + [Check(E) || E <- SniHosts], + + {Where, SniFun0} = get_opt_fun(sni_fun, 1, undefined, UserOpts, Opts), + + option_incompatible(is_function(SniFun0) andalso SniHosts =/= [] andalso Where =:= new, + [sni_fun, sni_hosts]), + assert_client_only(server_name_indication, UserOpts), + + SniFun = case SniFun0 =:= undefined of + true -> fun(Host) -> proplists:get_value(Host, SniHosts) end; + false -> SniFun0 + end, + + Opts#{sni_fun => SniFun}; +opt_sni(UserOpts, #{versions := _Versions} = Opts, #{role := client} = Env) -> %% RFC 6066, Section 3: Currently, the only server names supported are %% DNS hostnames %% case inet_parse:domain(Value) of @@ -2355,195 +2046,572 @@ validate_option(server_name_indication, Value, _) %% %% But the definition seems very diffuse, so let all strings through %% and leave it up to public_key to decide... - Value; -validate_option(server_name_indication, undefined, _) -> - undefined; -validate_option(server_name_indication, disable, _) -> - disable; -validate_option(session_tickets, Value, server) - when Value =:= disabled orelse - Value =:= stateful orelse - Value =:= stateless -> - Value; -validate_option(session_tickets, Value, server) -> - throw({error, - {options, role, - {session_tickets, - {Value, {server, [disabled, stateful, stateless]}}}}}); -validate_option(session_tickets, Value, client) - when Value =:= disabled orelse - Value =:= manual orelse - Value =:= auto -> - Value; -validate_option(session_tickets, Value, client) -> - throw({error, - {options, role, - {session_tickets, - {Value, {client, [disabled, manual, auto]}}}}}); -validate_option(sni_fun, undefined, _) -> - undefined; -validate_option(sni_fun, Fun, _) - when is_function(Fun) -> - Fun; -validate_option(sni_hosts, [], _) -> - []; -validate_option(sni_hosts, [{Hostname, SSLOptions} | Tail], _) - when is_list(Hostname) -> - RecursiveSNIOptions = proplists:get_value(sni_hosts, SSLOptions, undefined), - case RecursiveSNIOptions of - undefined -> - [{Hostname, validate_options(SSLOptions)} | - validate_option(sni_hosts, Tail)]; - _ -> - throw({error, {options, {sni_hosts, RecursiveSNIOptions}}}) - end; -validate_option(srp_identity, undefined, _) -> - undefined; -validate_option(srp_identity, {Username, Password}, _) - when is_list(Username), - is_list(Password), Username =/= "", - length(Username) =< 255 -> - {unicode:characters_to_binary(Username), - unicode:characters_to_binary(Password)}; -validate_option(user_lookup_fun, undefined, _) -> - undefined; -validate_option(user_lookup_fun, {Fun, _} = Value, _) - when is_function(Fun, 3) -> - Value; -validate_option(use_ticket, Value, _) - when is_list(Value) -> - Value; -validate_option(verify, Value, _) - when Value == verify_none; Value == verify_peer -> - Value; -validate_option(verify_fun, undefined, _) -> - undefined; -%% Backwards compatibility -validate_option(verify_fun, Fun, _) when is_function(Fun) -> - {fun(_,{bad_cert, _} = Reason, OldFun) -> - case OldFun([Reason]) of - true -> - {valid, OldFun}; - false -> - {fail, Reason} - end; - (_,{extension, _}, UserState) -> - {unknown, UserState}; - (_, valid, UserState) -> - {valid, UserState}; - (_, valid_peer, UserState) -> - {valid, UserState} - end, Fun}; -validate_option(verify_fun, {Fun, _} = Value, _) when is_function(Fun) -> - Value; -validate_option(versions, Versions, _) -> - validate_versions(Versions, Versions); -validate_option(Opt, undefined = Value, _) -> - AllOpts = maps:keys(?RULES), - case lists:member(Opt, AllOpts) of - true -> - Value; - false -> - throw({error, {options, {Opt, Value}}}) + SNI = case get_opt(server_name_indication, unbound, UserOpts, Opts) of + {_, unbound} -> server_name_indication_default(maps:get(host, Env, undefined)); + {_, [_|_] = SN} -> SN; + {_, disable} -> disable; + {_, SN} -> option_error(server_name_indication, SN) + end, + assert_server_only(sni_fun, UserOpts), + assert_server_only(sni_hosts, UserOpts), + Opts#{server_name_indication => SNI}. + +server_name_indication_default(Host) when is_list(Host) -> + %% SNI should not contain a trailing dot that a hostname may + string:strip(Host, right, $.); +server_name_indication_default(_) -> + undefined. + +opt_signature_algs(UserOpts, #{versions := Versions} = Opts, _Env) -> + [TlsVersion|_] = TlsVsns = [tls_version(V) || V <- Versions], + SA = case get_opt_list(signature_algs, undefined, UserOpts, Opts) of + {default, undefined} when ?TLS_GTE(TlsVersion, ?TLS_1_2) -> + DefAlgs = tls_v1:default_signature_algs(TlsVsns), + handle_hashsigns_option(DefAlgs, TlsVersion); + {new, Algs} -> + assert_version_dep(signature_algs, Versions, ['tlsv1.2', 'tlsv1.3']), + SA0 = handle_hashsigns_option(Algs, TlsVersion), + option_error(SA0 =:= [], no_supported_algorithms, {signature_algs, Algs}), + SA0; + {_, Algs} -> + Algs + end, + SAC = case get_opt_list(signature_algs_cert, undefined, UserOpts, Opts) of + {new, Schemes} -> + %% Do not send by default + assert_version_dep(signature_algs_cert, Versions, ['tlsv1.2', 'tlsv1.3']), + SAC0 = handle_signature_algorithms_option(Schemes, TlsVersion), + option_error(SAC0 =:= [], no_supported_signature_schemes, {signature_algs_cert, Schemes}), + SAC0; + {_, Schemes} -> + Schemes + end, + Opts#{signature_algs => SA, signature_algs_cert => SAC}. + +opt_alpn(UserOpts, #{versions := Versions} = Opts, #{role := server}) -> + {_, APP} = get_opt_list(alpn_preferred_protocols, undefined, UserOpts, Opts), + validate_protocols(is_list(APP), alpn_preferred_protocols, APP), + + {Where, NPA} = get_opt_list(next_protocols_advertised, undefined, UserOpts, Opts), + validate_protocols(is_list(NPA), next_protocols_advertised, NPA), + assert_version_dep(is_list(NPA), next_protocols_advertised, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + + assert_client_only(alpn_advertised_protocols, UserOpts), + assert_client_only(client_preferred_next_protocols, UserOpts), + + Opts1 = set_opt_new(Where, next_protocols_advertised, undefined, NPA, Opts), + Opts1#{alpn_preferred_protocols => APP}; +opt_alpn(UserOpts, #{versions := Versions} = Opts, #{role := client}) -> + {_, AAP} = get_opt_list(alpn_advertised_protocols, undefined, UserOpts, Opts), + validate_protocols(is_list(AAP), alpn_advertised_protocols, AAP), + + {Where, NPS} = case get_opt(client_preferred_next_protocols, undefined, UserOpts, Opts) of + {new, CPNP} -> + assert_version_dep(client_preferred_next_protocols, + Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + {new, make_next_protocol_selector(CPNP)}; + CPNP -> + CPNP + end, + + validate_protocols(is_list(NPS), client_preferred_next_protocols, NPS), + + assert_server_only(alpn_preferred_protocols, UserOpts), + assert_server_only(next_protocols_advertised, UserOpts), + + Opts1 = set_opt_new(Where, next_protocol_selector, undefined, NPS, Opts), + Opts1#{alpn_advertised_protocols => AAP}. + +validate_protocols(false, _Opt, _List) -> ok; +validate_protocols(true, Opt, List) -> + Check = fun(Bin) -> + IsOK = is_binary(Bin) andalso byte_size(Bin) > 0 andalso byte_size(Bin) < 256, + option_error(not IsOK, Opt, {invalid_protocol, Bin}) + end, + lists:foreach(Check, List). + +opt_mitigation(UserOpts, #{versions := Versions} = Opts, _Env) -> + DefBeast = case ?TLS_GT(lists:last(Versions), ?TLS_1_0) of + true -> disabled; + false -> one_n_minus_one + end, + {Where1, BM} = get_opt_of(beast_mitigation, [disabled, one_n_minus_one, zero_n], DefBeast, UserOpts, Opts), + assert_version_dep(Where1 =:= new, beast_mitigation, Versions, ['tlsv1']), + + {Where2, PC} = get_opt_bool(padding_check, true, UserOpts, Opts), + assert_version_dep(Where2 =:= new, padding_check, Versions, ['tlsv1']), + + %% Use 'new' we need to check for non default 'one_n_minus_one' + Opts1 = set_opt_new(new, beast_mitigation, disabled, BM, Opts), + set_opt_new(Where2, padding_check, true, PC, Opts1). + +opt_server(UserOpts, #{versions := Versions, log_level := LogLevel} = Opts, #{role := server}) -> + {_, ECC} = get_opt_bool(honor_ecc_order, false, UserOpts, Opts), + + {_, Cipher} = get_opt_bool(honor_cipher_order, false, UserOpts, Opts), + + {Where1, Cookie} = get_opt_bool(cookie, true, UserOpts, Opts), + assert_version_dep(Where1 =:= new, cookie, Versions, ['tlsv1.3']), + + {Where2, ReNeg} = get_opt_bool(client_renegotiation, true, UserOpts, Opts), + assert_version_dep(Where2 =:= new, client_renegotiation, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + + Opts1 = case get_opt(dh, undefined, UserOpts, Opts) of + {Where, DH} when is_binary(DH) -> + warn_override(Where, UserOpts, dh, [dhfile], LogLevel), + Opts#{dh => DH}; + {new, DH} -> + option_error(dh, DH); + {_, undefined} -> + case get_opt_file(dhfile, unbound, UserOpts, Opts) of + {default, unbound} -> Opts; + {_, DHFile} -> Opts#{dhfile => DHFile} + end + end, + + Opts1#{honor_ecc_order => ECC, honor_cipher_order => Cipher, + cookie => Cookie, client_renegotiation => ReNeg}; +opt_server(UserOpts, Opts, #{role := client}) -> + assert_server_only(honor_ecc_order, UserOpts), + assert_server_only(honor_cipher_order, UserOpts), + assert_server_only(cookie, UserOpts), + assert_server_only(client_renegotiation, UserOpts), + assert_server_only(dh, UserOpts), + assert_server_only(dhfile, UserOpts), + Opts. + +opt_client(UserOpts, #{versions := Versions} = Opts, #{role := client}) -> + {Where, FB} = get_opt_bool(fallback, false, UserOpts, Opts), + assert_version_dep(Where =:= new, fallback, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + + {_, CHC} = get_opt_list(customize_hostname_check, [], UserOpts, Opts), + + ValidMFL = [undefined, ?MAX_FRAGMENT_LENGTH_BYTES_1, ?MAX_FRAGMENT_LENGTH_BYTES_2, %% RFC 6066, Section 4 + ?MAX_FRAGMENT_LENGTH_BYTES_3, ?MAX_FRAGMENT_LENGTH_BYTES_4], + {_, MFL} = get_opt_of(max_fragment_length, ValidMFL, undefined, UserOpts, Opts), + + Opts#{fallback => FB, customize_hostname_check => CHC, max_fragment_length => MFL}; +opt_client(UserOpts, Opts, #{role := server}) -> + assert_client_only(fallback, UserOpts), + assert_client_only(customize_hostname_check, UserOpts), + assert_client_only(max_fragment_length, UserOpts), + Opts#{customize_hostname_check => []}. + +opt_renegotiate(UserOpts, #{versions := Versions} = Opts, _Env) -> + {Where1, KUA} = get_opt_pos_int(key_update_at, ?KEY_USAGE_LIMIT_AES_GCM, UserOpts, Opts), + assert_version_dep(Where1 =:= new, key_update_at, Versions, ['tlsv1.3']), + + %% Undocumented, old ? + {_, RA0} = get_opt_pos_int(renegotiate_at, ?DEFAULT_RENEGOTIATE_AT, UserOpts, Opts), + RA = min(RA0, ?DEFAULT_RENEGOTIATE_AT), %% Override users choice without notifying ?? + + {Where3, SR} = get_opt_bool(secure_renegotiate, true, UserOpts, Opts), + assert_version_dep(Where3 =:= new, secure_renegotiate, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + + Opts#{secure_renegotiate => SR, key_update_at => KUA, renegotiate_at => RA}. + +opt_reuse_sessions(UserOpts, #{versions := Versions} = Opts, #{role := client}) -> + {Where1, RUSS} = get_opt_of(reuse_sessions, [true, false, save], true, UserOpts, Opts), + + {Where2, RS} = RST = get_opt(reuse_session, undefined, UserOpts, Opts), + case RST of + {new, Bin} when is_binary(Bin) -> ok; + {new, {B1,B2}} when is_binary(B1), is_binary(B2) -> ok; + {new, Bad} -> option_error(reuse_session, Bad); + {_, _} -> ok + end, + + assert_version_dep(Where1 =:= new, reuse_sessions, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + assert_version_dep(Where2 =:= new, reuse_session, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + Opts#{reuse_sessions => RUSS, reuse_session => RS}; +opt_reuse_sessions(UserOpts, #{versions := Versions} = Opts, #{role := server}) -> + {Where1, RUSS} = get_opt_bool(reuse_sessions, true, UserOpts, Opts), + + DefRS = fun(_, _, _, _) -> true end, + {Where2, RS} = get_opt_fun(reuse_session, 4, DefRS, UserOpts, Opts), + + assert_version_dep(Where1 =:= new, reuse_sessions, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + assert_version_dep(Where2 =:= new, reuse_session, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + Opts#{reuse_sessions => RUSS, reuse_session => RS}. + +opt_identity(UserOpts, #{versions := Versions} = Opts, _Env) -> + PSK = case get_opt_list(psk_identity, undefined, UserOpts, Opts) of + {new, PSK0} -> + PSK1 = unicode:characters_to_binary(PSK0), + PSKSize = byte_size(PSK1), + assert_version_dep(psk_identity, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + option_error(not (0 < PSKSize andalso PSKSize < 65536), + psk_identity, {psk_identity, PSK0}), + PSK1; + {_, PSK0} -> + PSK0 + end, + + SRP = case get_opt(srp_identity, undefined, UserOpts, Opts) of + {new, {S1, S2}} when is_list(S1), is_list(S2) -> + User = unicode:characters_to_binary(S1), + UserSize = byte_size(User), + assert_version_dep(srp_identity, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + option_error(not (0 < UserSize andalso UserSize < 65536), + srp_identity, {srp_identity, PSK0}), + {User, unicode:characters_to_binary(S2)}; + {new, Err} -> + option_error(srp_identity, Err); + {_, SRP0} -> + SRP0 + end, + + ULF = case get_opt(user_lookup_fun, undefined, UserOpts, Opts) of + {new, {Fun, _} = ULF0} when is_function(Fun, 3) -> + assert_version_dep(user_lookup_fun, Versions, ['tlsv1','tlsv1.1','tlsv1.2']), + ULF0; + {new, ULF0} -> + option_error(user_lookup_fun, ULF0); + {_, ULF0} -> + ULF0 + end, + + Opts#{psk_identity => PSK, srp_identity => SRP, user_lookup_fun => ULF}. + +opt_supported_groups(UserOpts, #{versions := Versions} = Opts, _Env) -> + [TlsVersion|_] = TlsVsns = [tls_version(V) || V <- Versions], + SG = case get_opt_list(supported_groups, undefined, UserOpts, Opts) of + {default, undefined} -> + handle_supported_groups_option(groups(default), TlsVersion); + {new, SG0} -> + assert_version_dep(supported_groups, TlsVsns, ['tlsv1.3']), + handle_supported_groups_option(SG0, TlsVersion); + {old, SG0} -> + SG0 + end, + + CPHS = case get_opt_list(ciphers, [], UserOpts, Opts) of + {old, CPS0} -> CPS0; + {_, CPS0} -> handle_cipher_option(CPS0, Versions) + end, + + ECCS = case get_opt_list(eccs, undefined, UserOpts, Opts) of + {old, ECCS0} -> ECCS0; + {default, _} -> handle_eccs_option(tls_v1:ecc_curves(all), TlsVersion); + {new, ECCS0} -> handle_eccs_option(ECCS0, TlsVersion) + end, + + Opts#{ciphers => CPHS, eccs => ECCS, supported_groups => SG}. + +opt_crl(UserOpts, Opts, _Env) -> + {_, Check} = get_opt_of(crl_check, [best_effort, peer, true, false], false, UserOpts, Opts), + Cache = case get_opt(crl_cache, {ssl_crl_cache, {internal, []}}, UserOpts, Opts) of + {_, {Cb, {_Handle, Options}} = Value} when is_atom(Cb), is_list(Options) -> + Value; + {_, Err} -> + option_error(crl_cache, Err) + end, + Opts#{crl_check => Check, crl_cache => Cache}. + +opt_handshake(UserOpts, Opts, _Env) -> + {_, HS} = get_opt_of(handshake, [hello, full], full, UserOpts, Opts), + + {_, MHSS} = get_opt_int(max_handshake_size, 1, ?MAX_UNIT24, ?DEFAULT_MAX_HANDSHAKE_SIZE, + UserOpts, Opts), + + Opts#{handshake => HS, max_handshake_size => MHSS}. + +opt_use_srtp(UserOpts, #{protocol := Protocol} = Opts, _Env) -> + UseSRTP = case get_opt_map(use_srtp, undefined, UserOpts, Opts) of + {old, UseSRTP0} -> + UseSRTP0; + {default, undefined} -> + undefined; + {new, UseSRTP1} -> + assert_protocol_dep(use_srtp, Protocol, [dtls]), + validate_use_srtp(UseSRTP1) + end, + case UseSRTP of + #{} -> Opts#{use_srtp => UseSRTP}; + _ -> Opts + end. + +validate_use_srtp(#{protection_profiles := [_|_] = PPs} = UseSRTP) -> + case maps:keys(UseSRTP) -- [protection_profiles, mki] of + [] -> ok; + Extra -> option_error(use_srtp, {unknown_parameters, Extra}) + end, + IsValidProfile = fun(<<_, _>>) -> true; (_) -> false end, + case lists:all(IsValidProfile, PPs) of + true -> ok; + false -> option_error(use_srtp, {invalid_protection_profiles, PPs}) + end, + case UseSRTP of + #{mki := MKI} when not is_binary(MKI) -> + option_error(use_srtp, {invalid_mki, MKI}); + #{mki := _} -> + UseSRTP; + #{} -> + UseSRTP#{mki => <<>>} end; -validate_option(Opt, Value, _) -> - throw({error, {options, {Opt, Value}}}). + +validate_use_srtp(#{} = UseSRTP) -> + option_error(use_srtp, {no_protection_profiles, UseSRTP}). + + +opt_process(UserOpts, Opts0, _Env) -> + Opts1 = set_opt_list(receiver_spawn_opts, [], UserOpts, Opts0), + Opts2 = set_opt_list(sender_spawn_opts, [], UserOpts, Opts1), + %% {_, SSO} = get_opt_list(sender_spawn_opts, [], UserOpts, Opts), + %% Opts = Opts1#{receiver_spawn_opts => RSO, sender_spawn_opts => SSO}, + set_opt_int(hibernate_after, 0, infinity, infinity, UserOpts, Opts2). + +%%%% + +get_opt(Opt, Default, UserOpts, Opts) -> + case maps:get(Opt, UserOpts, unbound) of + unbound -> + case maps:get(maybe_map_key_internal(Opt), Opts, unbound) of + unbound -> %% Uses default value + {default, Default}; + Value -> %% Uses already set value (merge) + {old, Value} + end; + Value -> %% Uses new user option + {new, Value} + end. + +get_opt_of(Opt, Valid, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {new, Value} = Res -> + case lists:member(Value, Valid) of + true -> Res; + false -> option_error(Opt, Value) + end; + Res -> + Res + end. + +get_opt_bool(Opt, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {_, Value} = Res when is_boolean(Value) -> Res; + {_, Value} -> option_error(Opt, Value) + end. + +get_opt_pos_int(Opt, Default, UserOpts, Opts) -> + get_opt_int(Opt, 1, infinity, Default, UserOpts, Opts). + +get_opt_int(Opt, Min, Max, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {_, Value} = Res when is_integer(Value), Min =< Value, Value =< Max -> + Res; + {_, Value} = Res when Value =:= infinity, Max =:= infinity -> + Res; + {_, Value} -> + option_error(Opt, Value) + end. + +get_opt_fun(Opt, Arity, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {_, Fun} = Res when is_function(Fun, Arity) -> Res; + {new, Err} -> option_error(Opt, Err); + Res -> Res + end. + +get_opt_list(Opt, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {new, Err} when not is_list(Err) -> option_error(Opt, Err); + Res -> Res + end. + +get_opt_bin(Opt, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {new, Err} when not is_binary(Err) -> option_error(Opt, Err); + Res -> Res + end. + +get_opt_file(Opt, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {new, File} -> {new, validate_filename(File, Opt)}; + Res -> Res + end. + +set_opt_bool(Opt, Default, UserOpts, Opts) -> + case maps:get(Opt, UserOpts, Default) of + Default -> Opts; + Value when is_boolean(Value) -> Opts#{Opt => Value}; + Value -> option_error(Opt, Value) + end. + +get_opt_map(Opt, Default, UserOpts, Opts) -> + case get_opt(Opt, Default, UserOpts, Opts) of + {new, Err} when not is_map(Err) -> option_error(Opt, Err); + Res -> Res + end. + +set_opt_int(Opt, Min, Max, Default, UserOpts, Opts) -> + case maps:get(Opt, UserOpts, Default) of + Default -> + Opts; + Value when is_integer(Value), Min =< Value, Value =< Max -> + Opts#{Opt => Value}; + Value when Value =:= infinity, Max =:= infinity -> + Opts#{Opt => Value}; + Value -> + option_error(Opt, Value) + end. + +set_opt_list(Opt, Default, UserOpts, Opts) -> + case maps:get(Opt, UserOpts, []) of + Default -> + Opts; + List when is_list(List) -> + Opts#{Opt => List}; + Value -> + option_error(Opt, Value) + end. + +set_opt_new(new, Opt, Default, Value, Opts) + when Default =/= Value -> + Opts#{Opt => Value}; +set_opt_new(_, _, _, _, Opts) -> + Opts. + +%%%% + +default_cb_info(tls) -> + {gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive}; +default_cb_info(dtls) -> + {gen_udp, udp, udp_closed, udp_error, udp_passive}. handle_cb_info({V1, V2, V3, V4}) -> {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "_passive")}; +handle_cb_info(CbInfo) when tuple_size(CbInfo) =:= 5 -> + CbInfo; handle_cb_info(CbInfo) -> - CbInfo. + option_error(cb_info, CbInfo). -handle_hashsigns_option(Value, Version) when is_list(Value) - andalso Version >= {3, 4} -> - case tls_v1:signature_schemes(Version, Value) of - [] -> - throw({error, {options, - no_supported_signature_schemes, - {signature_algs, Value}}}); - _ -> - Value - end; -handle_hashsigns_option(Value, Version) when is_list(Value) - andalso Version =:= {3, 3} -> - case tls_v1:signature_algs(Version, Value) of - [] -> - throw({error, {options, no_supported_algorithms, {signature_algs, Value}}}); - _ -> - Value - end; -handle_hashsigns_option(_, Version) when Version =:= {3, 3} -> - handle_hashsigns_option(tls_v1:default_signature_algs([Version]), Version); -handle_hashsigns_option(_, _Version) -> - undefined. +handle_option_cb_info(Options, Protocol) -> + CbInfo = proplists:get_value(cb_info, Options, default_cb_info(Protocol)), + handle_cb_info(CbInfo). -handle_signature_algorithms_option(Value, Version) when is_list(Value) - andalso Version >= {3, 4} -> - case tls_v1:signature_schemes(Version, Value) of - [] -> - throw({error, {options, - no_supported_signature_schemes, - {signature_algs_cert, Value}}}); - _ -> - Value - end; -handle_signature_algorithms_option(_, _Version) -> - undefined. +maybe_map_key_internal(client_preferred_next_protocols) -> + next_protocol_selector; +maybe_map_key_internal(K) -> + K. -validate_options([]) -> - []; -validate_options([{Opt, Value} | Tail]) -> - [{Opt, validate_option(Opt, Value)} | validate_options(Tail)]. +split_options(Opts0, AllOptions) -> + Opts1 = proplists:expand([{binary, [{mode, binary}]}, + {list, [{mode, list}]}], Opts0), + Opts2 = handle_option_format(Opts1, []), + %% Remove deprecated ssl_imp option + Opts = proplists:delete(ssl_imp, Opts2), -validate_npn_ordering(client) -> - ok; -validate_npn_ordering(server) -> + DeleteUserOpts = fun(Key, PropList) -> proplists:delete(Key, PropList) end, + AllOpts = [cb_info, client_preferred_next_protocols] ++ AllOptions, + SockOpts = lists:foldl(DeleteUserOpts, Opts, AllOpts), + {Opts -- SockOpts, SockOpts}. + +assert_server_only(Option, Opts) -> + Value = maps:get(Option, Opts, undefined), + role_error(Value =/= undefined, server_only, Option). +assert_client_only(Option, Opts) -> + Value = maps:get(Option, Opts, undefined), + role_error(Value =/= undefined, client_only, Option). + +assert_server_only(client, Bool, Option) -> + role_error(Bool, server_only, Option); +assert_server_only(_, _, _) -> + ok. +assert_client_only(server, Bool, Option) -> + role_error(Bool, client_only, Option); +assert_client_only(_, _, _) -> + ok. + +role_error(false, _ErrorDesc, _Option) -> ok; -validate_npn_ordering(Value) -> - throw({error, {options, {client_preferred_next_protocols, {invalid_precedence, Value}}}}). - -validate_binary_list(Opt, List) -> - lists:foreach( - fun(Bin) when is_binary(Bin), - byte_size(Bin) > 0, - byte_size(Bin) < 256 -> - ok; - (Bin) -> - throw({error, {options, {Opt, {invalid_protocol, Bin}}}}) - end, List). -validate_versions([], Versions) -> - Versions; -validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3'; - Version == 'tlsv1.2'; - Version == 'tlsv1.1'; - Version == tlsv1 -> - case tls_record:sufficient_crypto_support(Version) of - true -> - tls_validate_versions(Rest, Versions); - false -> - throw({error, {options, {insufficient_crypto_support, {Version, {versions, Versions}}}}}) - end; -validate_versions([Version | Rest], Versions) when Version == 'dtlsv1'; - Version == 'dtlsv1.2'-> - DTLSVer = dtls_record:protocol_version(Version), - case tls_record:sufficient_crypto_support(dtls_v1:corresponding_tls_version(DTLSVer)) of - true -> - dtls_validate_versions(Rest, Versions); +role_error(true, ErrorDesc, Option) + when ErrorDesc =:= client_only; ErrorDesc =:= server_only -> + throw_error({option, ErrorDesc, Option}). + +option_incompatible(false, _Options) -> ok; +option_incompatible(true, Options) -> option_incompatible(Options). + +-spec option_incompatible(_) -> no_return(). +option_incompatible(Options) -> + throw_error({options, incompatible, Options}). + +option_error(false, _, _What) -> true; +option_error(true, Tag, What) -> option_error(Tag,What). + +-spec option_error(_,_) -> no_return(). +option_error(Tag, What) -> + throw_error({options, {Tag, What}}). + +-spec throw_error(_) -> no_return(). +throw_error(Err) -> + throw({error, Err}). + +assert_protocol_dep(Option, Protocol, AllowedProtos) -> + case lists:member(Protocol, AllowedProtos) of + true -> ok; + false -> option_incompatible([Option, {protocol, Protocol}]) + end. + +assert_version_dep(Option, Vsns, AllowedVsn) -> + assert_version_dep(true, Option, Vsns, AllowedVsn). + +assert_version_dep(false, _, _, _) -> true; +assert_version_dep(true, Option, SSLVsns, AllowedVsn) -> + case is_dtls_configured(SSLVsns) of + true -> %% TODO: Check option dependency for DTLS + true; false -> - throw({error, {options, {insufficient_crypto_support, {Version, {versions, Versions}}}}}) - end; -validate_versions([Version| _], Versions) -> - throw({error, {options, {Version, {versions, Versions}}}}). - -tls_validate_versions([], Versions) -> - tls_validate_version_gap(Versions); -tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3'; - Version == 'tlsv1.2'; - Version == 'tlsv1.1'; - Version == tlsv1 -> - tls_validate_versions(Rest, Versions); -tls_validate_versions([Version| _], Versions) -> - throw({error, {options, {Version, {versions, Versions}}}}). + APIVsns = lists:map(fun tls_record:protocol_version/1, SSLVsns), + Set1 = sets:from_list(APIVsns), + Set2 = sets:from_list(AllowedVsn), + case sets:size(sets:intersection(Set1, Set2)) > 0 of + true -> ok; + false -> option_incompatible([Option, {versions, APIVsns}]) + end + end. + +warn_override(new, UserOpts, NewOpt, OldOpts, LogLevel) -> + Check = fun(Key) -> maps:is_key(Key,UserOpts) end, + case lists:filter(Check, OldOpts) of + [] -> ok; + Ignored -> + Desc = lists:flatten(io_lib:format("Options ~w are ignored", [Ignored])), + Reas = lists:flatten(io_lib:format("Option ~w is set", [NewOpt])), + ssl_logger:log(notice, LogLevel, #{description => Desc, reason => Reas}, ?LOCATION) + end; +warn_override(_, _UserOpts, _NewOpt, _OldOpts, _LogLevel) -> + ok. + +is_dtls_configured(Versions) -> + lists:any(fun (Ver) -> ?DTLS_1_X(Ver) end, Versions). + +handle_hashsigns_option(Value, Version) -> + try + if ?TLS_GTE(Version, ?TLS_1_3) -> + tls_v1:signature_schemes(Version, Value); + (Version =:= ?TLS_1_2) -> + tls_v1:signature_algs(Version, Value); + true -> + undefined + end + catch error:function_clause -> + option_error(signature_algs, Value) + end. + +handle_signature_algorithms_option(Value, Version) -> + try tls_v1:signature_schemes(Version, Value) + catch error:function_clause -> + option_error(signature_algs_cert, Value) + end. + +validate_filename(FN, _Option) when is_binary(FN), FN =/= <<>> -> + FN; +validate_filename([_|_] = FN, _Option) -> + Enc = file:native_name_encoding(), + unicode:characters_to_binary(FN, unicode, Enc); +validate_filename(FN, Option) -> + option_error(Option, FN). %% Do not allow configuration of TLS 1.3 with a gap where TLS 1.2 is not supported %% as that configuration can trigger the built in version downgrade protection @@ -2560,25 +2628,7 @@ tls_validate_version_gap(Versions) -> _ -> Versions end. -dtls_validate_versions([], Versions) -> - Versions; -dtls_validate_versions([Version | Rest], Versions) when Version == 'dtlsv1'; - Version == 'dtlsv1.2'-> - dtls_validate_versions(Rest, Versions); -dtls_validate_versions([Ver| _], Versions) -> - throw({error, {options, {Ver, {versions, Versions}}}}). - -%% The option cacerts overrides cacertfile -ca_cert_default(_,_, [_|_]) -> - undefined; -ca_cert_default(verify_none, _, _) -> - undefined; -ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) -> - undefined; -%% Server that wants to verify_peer and has no verify_fun must have -%% some trusted certs. -ca_cert_default(verify_peer, undefined, _) -> - "". + emulated_options(undefined, undefined, Protocol, Opts) -> case Protocol of tls -> @@ -2598,16 +2648,16 @@ handle_cipher_option(Value, Versions) when is_list(Value) -> Suites catch exit:_ -> - throw({error, {options, {ciphers, Value}}}); + option_error(ciphers, Value); error:_-> - throw({error, {options, {ciphers, Value}}}) + option_error(ciphers, Value) end. -binary_cipher_suites([{3,4} = Version], []) -> +binary_cipher_suites([?TLS_1_3], []) -> %% Defaults to all supported suites that does %% not require explicit configuration TLS-1.3 %% only mode. - default_binary_suites(exclusive, Version); + default_binary_suites(exclusive, ?TLS_1_3); binary_cipher_suites([Version| _], []) -> %% Defaults to all supported suites that does %% not require explicit configuration @@ -2637,15 +2687,15 @@ binary_cipher_suites(Versions, Ciphers0) -> Ciphers = [ssl_cipher_format:suite_openssl_str_to_map(C) || C <- string:lexemes(Ciphers0, ":")], binary_cipher_suites(Versions, Ciphers). -default_binary_suites(exclusive, {_, Minor}) -> - ssl_cipher:filter_suites(tls_v1:exclusive_suites(Minor)); +default_binary_suites(exclusive, Version) -> + ssl_cipher:filter_suites(tls_v1:exclusive_suites(Version)); default_binary_suites(default, Version) -> ssl_cipher:filter_suites(ssl_cipher:suites(Version)). -all_suites([{3, 4 = Minor}]) -> - tls_v1:exclusive_suites(Minor); -all_suites([{3, 4} = Version0, Version1 |_]) -> - all_suites([Version0]) ++ +all_suites([?TLS_1_3]) -> + tls_v1:exclusive_suites(?TLS_1_3); +all_suites([?TLS_1_3, Version1 |_]) -> + all_suites([?TLS_1_3]) ++ ssl_cipher:all_suites(Version1) ++ ssl_cipher:anonymous_suites(Version1); all_suites([Version|_]) -> @@ -2673,31 +2723,95 @@ tuple_to_map_mac(chacha20_poly1305, _) -> tuple_to_map_mac(_, MAC) -> MAC. -handle_eccs_option(Value, Version) when is_list(Value) -> - {_Major, Minor} = tls_version(Version), - try tls_v1:ecc_curves(Minor, Value) of - Curves -> #elliptic_curves{elliptic_curve_list = Curves} +%% TODO: remove Version +handle_eccs_option(Value, _Version0) when is_list(Value) -> + try tls_v1:ecc_curves(Value) of + Curves -> + option_error(Curves =:= [], eccs, none_valid), + #elliptic_curves{elliptic_curve_list = Curves} catch - exit:_ -> throw({error, {options, {eccs, Value}}}); - error:_ -> throw({error, {options, {eccs, Value}}}) + exit:_ -> option_error(eccs, Value); + error:_ -> option_error(eccs, Value) end. -handle_supported_groups_option(Value, Version) when is_list(Value) -> - {_Major, Minor} = tls_version(Version), - try tls_v1:groups(Minor, Value) of - Groups -> #supported_groups{supported_groups = Groups} +%% TODO: remove Version +handle_supported_groups_option(Value, _Version0) when is_list(Value) -> + try tls_v1:groups(Value) of + Groups -> + option_error(Groups =:= [], supported_groups, none_valid), + #supported_groups{supported_groups = Groups} catch - exit:_ -> throw({error, {options, {supported_groups, Value}}}); - error:_ -> throw({error, {options, {supported_groups, Value}}}) + exit:_ -> option_error(supported_groups, Value); + error:_ -> option_error(supported_groups, Value) end. +-spec do_format_error( string() + | closed + | {tls_alert, {_, Description :: string()}} + | {options, Options :: term()} + | {options, {socket_options, Option :: term()}} + | {options, {socket_options, Option :: term(), Error}} + | {options, {FileType, File :: string(), Error}} + | InetError + | OtherReason) -> string() + when + FileType :: cacertfile | certfile | keyfile | dhfile, + OtherReason :: term(), + Error :: term(), + InetError :: inet:posix() | system_limit. + +do_format_error(Reason) when is_list(Reason) -> + Reason; +do_format_error(closed) -> + "TLS connection is closed"; +do_format_error({tls_alert, {_, Description}}) -> + Description; +do_format_error({options,{FileType, File, Reason}}) + when FileType == cacertfile; + FileType == certfile; + FileType == keyfile; + FileType == dhfile -> + Error = file_error_format(Reason), + file_desc(FileType) ++ File ++ ": " ++ Error; +do_format_error ({options, {socket_options, Option, Error}}) -> + lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, do_format_error(Error)])); +do_format_error({options, {socket_options, Option}}) -> + lists:flatten(io_lib:format("Invalid socket option: ~p", [Option])); +do_format_error({options, incompatible, Opts}) -> + lists:flatten(io_lib:format("Options (or their values) can not be combined: ~p", [Opts])); +do_format_error({option, Reason, Opts}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, Reason])); +do_format_error({options, Reason, Opts}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, Reason])); +do_format_error({options, {missing_version=R, Opts}}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, R])); +do_format_error({options, {option_not_a_key_value_tuple=R, Opts}}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, R])); +do_format_error({options, {no_supported_algorithms=R, Opts}}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, R])); +do_format_error({options, {no_supported_signature_schemes=R, Opts}}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, R])); +do_format_error({options, {insufficient_crypto_support=R, Opts}}) -> + lists:flatten(io_lib:format("Invalid option ~w ~w", [Opts, R])); + +do_format_error({options, Options}) -> + lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options])); + +do_format_error(Error) -> + case inet:format_error(Error) of + "unknown POSIX" ++ _ -> + unexpected_format(Error); + Other -> + Other + end. + unexpected_format(Error) -> lists:flatten(io_lib:format("Unexpected error: ~p", [Error])). file_error_format({error, Error})-> case file:format_error(Error) of - "unknown POSIX error" -> + "unknown POSIX error" ++ _ -> "decoding error"; Str -> Str @@ -2714,42 +2828,37 @@ file_desc(keyfile) -> file_desc(dhfile) -> "Invalid DH params file ". -detect(_Pred, []) -> - undefined; -detect(Pred, [H|T]) -> - case Pred(H) of - true -> - H; - _ -> - detect(Pred, T) - end. - make_next_protocol_selector(undefined) -> undefined; -make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) -> - fun(AdvertisedProtocols) -> - case detect(fun(PreferredProtocol) -> - lists:member(PreferredProtocol, AdvertisedProtocols) - end, AllProtocols) of - undefined -> - DefaultProtocol; - PreferredProtocol -> - PreferredProtocol - end +make_next_protocol_selector({Precedence, PrefProtcol} = V) -> + option_error(not is_list(PrefProtcol), client_preferred_next_protocols, V), + make_next_protocol_selector({Precedence, PrefProtcol, ?NO_PROTOCOL}); +make_next_protocol_selector({Precedence, AllProtocols, DefP} = V) -> + option_error(not is_list(AllProtocols), client_preferred_next_protocols, V), + option_error(not (is_binary(DefP) andalso byte_size(DefP) < 256), client_preferred_next_protocols, V), + validate_protocols(true, client_preferred_next_protocols, AllProtocols), + case Precedence of + client -> + fun(Advertised) -> + Search = fun(P) -> lists:member(P, Advertised) end, + case lists:search(Search, AllProtocols) of + false -> DefP; + {value, Preferred} -> Preferred + end + end; + server -> + fun(Advertised) -> + Search = fun(P) -> lists:member(P, AllProtocols) end, + case lists:search(Search, Advertised) of + false -> DefP; + {value, Preferred} -> Preferred + end + end; + Value -> + option_error(client_preferred_next_protocols, {invalid_precedence, Value}) end; - -make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) -> - fun(AdvertisedProtocols) -> - case detect(fun(PreferredProtocol) -> - lists:member(PreferredProtocol, AllProtocols) - end, - AdvertisedProtocols) of - undefined -> - DefaultProtocol; - PreferredProtocol -> - PreferredProtocol - end - end. +make_next_protocol_selector(What) -> + option_error(client_preferred_next_protocols, What). connection_cb(tls) -> tls_gen_connection; @@ -2758,16 +2867,6 @@ connection_cb(dtls) -> connection_cb(Opts) -> connection_cb(proplists:get_value(protocol, Opts, tls)). -record_cb(tls) -> - tls_record; -record_cb(dtls) -> - dtls_record; -record_cb(Opts) -> - record_cb(proplists:get_value(protocol, Opts, tls)). - -binary_filename(FileName) -> - Enc = file:native_name_encoding(), - unicode:characters_to_binary(FileName, unicode, Enc). %% Assert that basic options are on the format {Key, Value} %% with a few exceptions and phase out log_alert @@ -2775,12 +2874,12 @@ handle_option_format([], Acc) -> lists:reverse(Acc); handle_option_format([{log_alert, Bool} | Rest], Acc) when is_boolean(Bool) -> case proplists:get_value(log_level, Acc ++ Rest, undefined) of - undefined -> + undefined -> handle_option_format(Rest, [{log_level, map_log_level(Bool)} | Acc]); - _ -> + _ -> handle_option_format(Rest, Acc) - end; + end; handle_option_format([{Key,_} = Opt | Rest], Acc) when is_atom(Key) -> handle_option_format(Rest, [Opt | Acc]); %% Handle exceptions @@ -2791,53 +2890,13 @@ handle_option_format([inet = Opt | Rest], Acc) -> handle_option_format([inet6 = Opt | Rest], Acc) -> handle_option_format(Rest, [Opt | Acc]); handle_option_format([Value | _], _) -> - throw({option_not_a_key_value_tuple, Value}). + option_error(option_not_a_key_value_tuple, Value). map_log_level(true) -> notice; map_log_level(false) -> none. -handle_verify_option(verify_none, #{fail_if_no_peer_cert := false} = OptionsMap) -> - OptionsMap#{verify => verify_none}; -handle_verify_option(verify_none, #{fail_if_no_peer_cert := true}) -> - throw({error, {options, incompatible, - {verify, verify_none}, - {fail_if_no_peer_cert, true}}}); -%% The option 'verify' is simulated by the configured 'verify_fun' that is mostly -%% hidden from the end user. When 'verify' is set to verify_none, the option -%% 'verify_fun' is also set to a default verify-none-verify_fun when processing -%% the configuration. If 'verify' is later changed from verify_none to verify_peer, -%% the 'verify_fun' must also be changed to undefined. When 'verify_fun' is set to -%% undefined, public_key's default verify_fun will be used that performs a full -%% verification. -handle_verify_option(verify_peer, #{verify := verify_none} = OptionsMap) -> - OptionsMap#{verify => verify_peer, - verify_fun => undefined}; -handle_verify_option(verify_peer, OptionsMap) -> - OptionsMap#{verify => verify_peer}; -handle_verify_option(Value, _) -> - throw({error, {options, {verify, Value}}}). - -%% Added to handle default values for signature_algs in TLS 1.3 -default_option_role_sign_algs(_, Value, _, Version) when Version >= {3,4} -> - Value; -default_option_role_sign_algs(Role, Value, Role, _) -> - Value; -default_option_role_sign_algs(_, _, _, _) -> - undefined. - -default_option_role(Role, Value, Role) -> - Value; -default_option_role(_,_,_) -> - undefined. - - -default_cb_info(tls) -> - {gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive}; -default_cb_info(dtls) -> - {gen_udp, udp, udp_closed, udp_error, udp_passive}. - include_security_info([]) -> false; include_security_info([Item | Items]) -> @@ -2848,37 +2907,46 @@ include_security_info([Item | Items]) -> include_security_info(Items) end. -server_name_indication_default(Host) when is_list(Host) -> - %% SNI should not contain a trailing dot that a hostname may - string:strip(Host, right, $.); -server_name_indication_default(_) -> - undefined. add_filter(undefined, Filters) -> Filters; add_filter(Filter, Filters) -> [Filter | Filters]. -maybe_client_warn_no_verify(#{verify := verify_none, - warn_verify_none := true, - log_level := LogLevel}, client) -> - ssl_logger:log(warning, LogLevel, #{description => "Authenticity is not established by certificate path validation", - reason => "Option {verify, verify_peer} and cacertfile/cacerts is missing"}, #{}); -maybe_client_warn_no_verify(_,_) -> - %% Warning not needed. Note client certificate validation is optional in TLS - ok. - unambiguous_path(Value) -> AbsName = filename:absname(Value), - case file:read_link(AbsName) of - {ok, PathWithNoLink} -> - case filename:pathtype(PathWithNoLink) of - relative -> - Dirname = filename:dirname(AbsName), - filename:join([Dirname, PathWithNoLink]); - _ -> - PathWithNoLink - end; - _ -> - AbsName - end. + UP = case file:read_link(AbsName) of + {ok, PathWithNoLink} -> + case filename:pathtype(PathWithNoLink) of + relative -> + Dirname = filename:dirname(AbsName), + filename:join([Dirname, PathWithNoLink]); + _ -> + PathWithNoLink + end; + _ -> + AbsName + end, + validate_filename(UP, cacertfile). + +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(csp, {call, {?MODULE, opt_ocsp, [UserOpts | _]}}, Stack) -> + {format_ocsp_params(UserOpts), Stack}; +handle_trace(csp, {return_from, {?MODULE, opt_ocsp, 3}, Return}, Stack) -> + {format_ocsp_params(Return), Stack}; +handle_trace(rle, {call, {?MODULE, listen, Args}}, Stack0) -> + Role = server, + {io_lib:format("(*~w) Args = ~W", [Role, Args, 10]), [{role, Role} | Stack0]}; +handle_trace(rle, {call, {?MODULE, connect, Args}}, Stack0) -> + Role = client, + {io_lib:format("(*~w) Args = ~W", [Role, Args, 10]), [{role, Role} | Stack0]}. + +format_ocsp_params(Map) -> + Stapling = maps:get(ocsp_stapling, Map, '?'), + Nonce = maps:get(ocsp_nonce, Map, '?'), + Certs = maps:get(ocsp_responder_certs, Map, '?'), + io_lib:format("Stapling = ~W Nonce = ~W Certs = ~W", + [Stapling, 5, Nonce, 5, Certs, 5]). diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 08210985adde..ec1816fdde79 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2022 All Rights Reserved. +%% Copyright Ericsson AB 2007-2023 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. @@ -65,6 +65,7 @@ -include("ssl_handshake.hrl"). -include("ssl_alert.hrl"). -include("ssl_internal.hrl"). +-include("ssl_record.hrl"). -include_lib("public_key/include/public_key.hrl"). -export([trusted_cert_and_paths/4, @@ -80,9 +81,14 @@ public_key_type/1, foldl_db/3, find_cross_sign_root_paths/4, - handle_cert_auths/4 + handle_cert_auths/4, + available_cert_key_pairs/1, + available_cert_key_pairs/2 ]). +%% Tracing +-export([handle_trace/3]). + %%==================================================================== %% Internal application API %%==================================================================== @@ -307,25 +313,61 @@ find_cross_sign_root_paths([_ | Rest] = Path, CertDbHandle, CertDbRef, Invalidat end. handle_cert_auths(Chain, [], _, _) -> - %% If we have no authorities extension to check we just accept - %% first choice + %% If we have no authorities extension (or corresponding + %% 'certificate_authorities' in the certificate request message in + %% TLS-1.2 is empty) to check we just accept first choice. {ok, Chain}; handle_cert_auths([Cert], CertAuths, CertDbHandle, CertDbRef) -> - {ok, {_, [Cert | _] = EChain}, {_, [_ | DCerts]}} = certificate_chain(Cert, CertDbHandle, CertDbRef, [], both), - case cert_auth_member(cert_subjects(DCerts), CertAuths) of - true -> - {ok, EChain}; - false -> - {error, EChain, not_in_auth_domain} + case certificate_chain(Cert, CertDbHandle, CertDbRef, [], both) of + {ok, {_, [Cert | _] = EChain}, {_, [_ | DCerts]}} -> + case cert_auth_member(cert_issuers(DCerts), CertAuths) of + true -> + {ok, EChain}; + false -> + {error, EChain, not_in_auth_domain} + end; + _ -> + {ok, [Cert]} end; handle_cert_auths([_ | Certs] = EChain, CertAuths, _, _) -> - case cert_auth_member(cert_subjects(Certs), CertAuths) of + case cert_auth_member(cert_issuers(Certs), CertAuths) of true -> {ok, EChain}; false -> {error, EChain, not_in_auth_domain} end. +available_cert_key_pairs(CertKeyGroups) -> + %% To be able to find possible TLS session pre TLS-1.3 + %% that may be reused. At this point the version is + %% not negotiated. + RevAlgos = [dsa, rsa, rsa_pss_pss, ecdsa], + cert_key_group_to_list(RevAlgos, CertKeyGroups, []). + +%% Create the prioritized list of cert key pairs that +%% are availble for use in the negotiated version +available_cert_key_pairs(CertKeyGroups, ?TLS_1_3) -> + RevAlgos = [rsa, rsa_pss_pss, ecdsa, eddsa], + cert_key_group_to_list(RevAlgos, CertKeyGroups, []); +available_cert_key_pairs(CertKeyGroups, ?TLS_1_2) -> + RevAlgos = [dsa, rsa, rsa_pss_pss, ecdsa], + cert_key_group_to_list(RevAlgos, CertKeyGroups, []); +available_cert_key_pairs(CertKeyGroups, Version) + when ?TLS_LT(Version, ?TLS_1_2) -> + RevAlgos = [dsa, rsa, ecdsa], + cert_key_group_to_list(RevAlgos, CertKeyGroups, []). + +cert_key_group_to_list([], _, Acc) -> + final_group_list(Acc); +cert_key_group_to_list([Algo| Rest], CertKeyGroups, Acc) -> + CertKeyPairs = maps:get(Algo, CertKeyGroups, []), + cert_key_group_to_list(Rest, CertKeyGroups, CertKeyPairs ++ Acc). + +final_group_list([]) -> + [#{certs => [[]], private_key => #{}}]; +final_group_list(List) -> + List. + %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -541,10 +583,12 @@ verify_cert_extensions(Cert, UserState, [], _) -> {valid, UserState#{issuer => Cert}}; verify_cert_extensions(Cert, #{ocsp_responder_certs := ResponderCerts, ocsp_state := OscpState, - issuer := Issuer} = UserState, - [#certificate_status{response = OcspResponsDer} | Exts], Context) -> + issuer := Issuer} = UserState, + [#certificate_status{response = OcspResponsDer} | Exts], + Context) -> #{ocsp_nonce := Nonce} = OscpState, - case public_key:pkix_ocsp_validate(Cert, Issuer, OcspResponsDer, ResponderCerts, Nonce) of + case public_key:pkix_ocsp_validate(Cert, Issuer, OcspResponsDer, + ResponderCerts, Nonce) of valid -> verify_cert_extensions(Cert, UserState, Exts, Context); {bad_cert, _} = Status -> @@ -554,21 +598,22 @@ verify_cert_extensions(Cert, UserState, [_|Exts], Context) -> %% Skip unknown extensions! verify_cert_extensions(Cert, UserState, Exts, Context). -verify_sign(_, #{version := {_, Minor}}) when Minor < 3 -> +verify_sign(_, #{version := Version}) + when ?TLS_LT(Version, ?TLS_1_2) -> %% This verification is not applicable pre TLS-1.2 true; -verify_sign(Cert, #{version := {3, 3}, +verify_sign(Cert, #{version := ?TLS_1_2, signature_algs := SignAlgs, signature_algs_cert := undefined}) -> is_supported_signature_algorithm_1_2(Cert, SignAlgs); -verify_sign(Cert, #{version := {3, 3}, +verify_sign(Cert, #{version := ?TLS_1_2, signature_algs_cert := SignAlgs}) -> is_supported_signature_algorithm_1_2(Cert, SignAlgs); -verify_sign(Cert, #{version := {3, 4}, +verify_sign(Cert, #{version := ?TLS_1_3, signature_algs := SignAlgs, signature_algs_cert := undefined}) -> is_supported_signature_algorithm_1_3(Cert, SignAlgs); -verify_sign(Cert, #{version := {3, 4}, +verify_sign(Cert, #{version := ?TLS_1_3, signature_algs_cert := SignAlgs}) -> is_supported_signature_algorithm_1_3(Cert, SignAlgs). @@ -583,7 +628,7 @@ is_supported_signature_algorithm_1_2(#'OTPCertificate'{signatureAlgorithm = is_supported_signature_algorithm_1_2(#'OTPCertificate'{signatureAlgorithm = SignAlg}, SignAlgs) -> Scheme = ssl_cipher:signature_algorithm_to_scheme(SignAlg), {Hash, Sign, _ } = ssl_cipher:scheme_to_components(Scheme), - ssl_cipher:is_supported_sign({pre_1_3_hash(Hash), pre_1_3_sign(Sign)}, ssl_cipher:signature_schemes_1_2(SignAlgs)). + ssl_cipher:is_supported_sign({Hash, pre_1_3_sign(Sign)}, ssl_cipher:signature_schemes_1_2(SignAlgs)). is_supported_signature_algorithm_1_3(#'OTPCertificate'{signatureAlgorithm = SignAlg}, SignAlgs) -> Scheme = ssl_cipher:signature_algorithm_to_scheme(SignAlg), ssl_cipher:is_supported_sign(Scheme, SignAlgs). @@ -592,10 +637,6 @@ pre_1_3_sign(rsa_pkcs1) -> rsa; pre_1_3_sign(Other) -> Other. -pre_1_3_hash(sha1) -> - sha; -pre_1_3_hash(Hash) -> - Hash. paths(Chain, CertDbHandle) -> paths(Chain, Chain, CertDbHandle, []). @@ -671,18 +712,18 @@ maybe_shorten_path(Path, PartialChainHandler, Default) -> DerCerts = [Der || #cert{der=Der} <- Path], try PartialChainHandler(DerCerts) of {trusted_ca, Root} -> - new_trusteded_path(Root, Path, Default); + new_trusted_path(Root, Path, Default); unknown_ca -> Default catch _:_ -> Default end. -new_trusteded_path(DerCert, [#cert{der=DerCert}=Cert | Chain], _) -> - {Cert, Chain}; -new_trusteded_path(DerCert, [_ | Rest], Default) -> - new_trusteded_path(DerCert, Rest, Default); -new_trusteded_path(_, [], Default) -> +new_trusted_path(DerCert, [#cert{der=DerCert}=Cert | Path], _) -> + {Cert, Path}; +new_trusted_path(DerCert, [_ | Rest], Default) -> + new_trusted_path(DerCert, Rest, Default); +new_trusted_path(_, [], Default) -> %% User did not pick a cert present %% in the cert chain so ignore Default. @@ -762,14 +803,63 @@ subject(Cert) -> {_Serial,Subject} = public_key:pkix_subject_id(Cert), Subject. -cert_subjects([], Acc) -> +issuer(Cert) -> + case public_key:pkix_is_self_signed(Cert) of + true -> + subject(Cert); + false -> + case is_binary(Cert) of + true -> + #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp), + public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.issuer); + false -> + #'OTPCertificate'{tbsCertificate = TBSCert} = Cert, + public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.issuer) + end + end. + +cert_issuers([], Acc) -> Acc; -cert_subjects([Cert | Rest], Acc) -> - cert_subjects(Rest, [subject(Cert) | Acc]). +cert_issuers([Cert | Rest], Acc) -> + cert_issuers(Rest, [issuer(Cert) | Acc]). -cert_subjects(OTPCerts) -> - cert_subjects(OTPCerts, []). +cert_issuers(OTPCerts) -> + cert_issuers(OTPCerts, []). cert_auth_member(ChainSubjects, CertAuths) -> CommonAuthorities = sets:intersection(sets:from_list(ChainSubjects), sets:from_list(CertAuths)), not sets:is_empty(CommonAuthorities). + +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(crt, + {call, {?MODULE, validate, [Cert, StatusOrExt| _]}}, Stack) -> + {io_lib:format("[~W] StatusOrExt = ~W", [Cert, 3, StatusOrExt, 10]), Stack}; + %% {io_lib:format("(~s) StatusOrExt = ~W", + %% [ssl_test_lib:format_cert(Cert), StatusOrExt, 10]), Stack}; +handle_trace(crt, {call, {?MODULE, verify_cert_extensions, + [Cert, + _UserState, + [], _Context]}}, Stack) -> + {io_lib:format(" no more extensions [~W]", [Cert, 3]), Stack}; + %% {io_lib:format(" no more extensions (~s)", [ssl_test_lib:format_cert(Cert)]), Stack}; +handle_trace(crt, {call, {?MODULE, verify_cert_extensions, + [Cert, + #{ocsp_responder_certs := _ResponderCerts, + ocsp_state := OcspState, + issuer := Issuer} = _UserState, + [#certificate_status{response = OcspResponsDer} | + _Exts], _Context]}}, Stack) -> + {io_lib:format("#2 OcspState = ~W Issuer = [~W] OcspResponsDer = ~W [~W]", + [OcspState, 10, Issuer, 3, OcspResponsDer, 2, Cert, 3]), + Stack}; + %% {io_lib:format("#2 OcspState = ~W Issuer = (~s) OcspResponsDer = ~W (~s)", + %% [OcspState, 10, ssl_test_lib:format_cert(Issuer), + %% OcspResponsDer, 2, ssl_test_lib:format_cert(Cert)]), +handle_trace(crt, {return_from, + {ssl_certificate, verify_cert_extensions, 4}, + {valid, #{issuer := Issuer}}}, Stack) -> + {io_lib:format(" extensions valid Issuer = ~W", [Issuer, 3]), Stack}. + %% {io_lib:format(" extensions valid Issuer = ~s", [ssl_test_lib:format_cert(Issuer)]), Stack}. diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 0e65e937d3db..8d982f7fa205 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -183,10 +183,10 @@ cipher(?AES_CBC, CipherState, Mac, Fragment, Version) -> end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version). aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData, TagLen) -> - crypto:crypto_one_time_aead(aead_type(Type,size(Key)), Key, Nonce, Fragment, AdditionalData, TagLen, true). + crypto:crypto_one_time_aead(aead_type(Type,byte_size(Key)), Key, Nonce, Fragment, AdditionalData, TagLen, true). aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AdditionalData) -> - crypto:crypto_one_time_aead(aead_type(Type,size(Key)), Key, Nonce, CipherText, AdditionalData, CipherTag, false). + crypto:crypto_one_time_aead(aead_type(Type,byte_size(Key)), Key, Nonce, CipherText, AdditionalData, CipherTag, false). aead_type(?AES_GCM, 16) -> aes_128_gcm; @@ -214,16 +214,15 @@ build_cipher_block(BlockSz, Mac, Fragment) -> [Fragment, Mac, padding_with_len(TotSz, BlockSz)]. block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, - Mac, Fragment, {3, N}) - when N == 0; N == 1 -> + Mac, Fragment, ?TLS_1_0) -> L = build_cipher_block(BlockSz, Mac, Fragment), T = Fun(Key, IV, L), NextIV = next_iv(T, IV), {T, CS0#cipher_state{iv=NextIV}}; block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV, state = IV_Cache0} = CS0, - Mac, Fragment, {3, N}) - when N == 2; N == 3; N == 4 -> + Mac, Fragment, Version) + when ?TLS_GT(Version, ?TLS_1_0)-> IV_Size = byte_size(IV), <> = case IV_Cache0 of @@ -260,12 +259,13 @@ decipher(?RC4, HashSz, CipherState = #cipher_state{state = State}, Fragment, _, #generic_stream_cipher{content = Content, mac = Mac} = GSC, {Content, Mac, CipherState} catch - _:_ -> + _:Reason:ST -> %% This is a DECRYPTION_FAILED but %% "differentiating between bad_record_mac and decryption_failed %% alerts may permit certain attacks against CBC mode as used in %% TLS [CBCATT]. It is preferable to uniformly use the %% bad_record_mac alert to hide the specific type of the error." + ?SSL_LOG(debug, decrypt_error, [{reason,Reason}, {stacktrace, ST}]), ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed) end; @@ -305,12 +305,13 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, {<<16#F0, Content/binary>>, Mac, CipherState1} end catch - _:_ -> + _:Reason:ST -> %% This is a DECRYPTION_FAILED but %% "differentiating between bad_record_mac and decryption_failed %% alerts may permit certain attacks against CBC mode as used in %% TLS [CBCATT]. It is preferable to uniformly use the %% bad_record_mac alert to hide the specific type of the error." + ?SSL_LOG(debug, decrypt_error, [{reason,Reason}, {stacktrace, ST}]), ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed) end. @@ -319,45 +320,42 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, %% %% Description: Returns a list of supported cipher suites. %%-------------------------------------------------------------------- -suites({3, Minor}) -> - tls_v1:suites(Minor); -suites({_, Minor}) -> - dtls_v1:suites(Minor). -all_suites({3, 4} = Version) -> - suites(Version) - ++ tls_v1:psk_suites({3,3}) - ++ tls_v1:srp_suites({3,3}) - ++ tls_v1:rsa_suites({3,3}) - ++ tls_v1:des_suites({3,3}) - ++ tls_v1:rc4_suites({3,3}); -all_suites({3, _} = Version) -> - suites(Version) - ++ tls_v1:psk_suites(Version) - ++ tls_v1:srp_suites(Version) - ++ tls_v1:rsa_suites(Version) - ++ tls_v1:des_suites(Version) - ++ tls_v1:rc4_suites(Version); +suites(Version) when ?TLS_1_X(Version) -> + tls_v1:suites(Version); +suites(Version) when ?DTLS_1_X(Version) -> + dtls_v1:suites(Version). +all_suites(?TLS_1_3 = Version) -> + suites(Version) ++ tls_legacy_suites(?TLS_1_2); +all_suites(Version) when ?TLS_1_X(Version) -> + suites(Version) ++ tls_legacy_suites(Version); all_suites(Version) -> dtls_v1:all_suites(Version). +tls_legacy_suites(Version) -> + Tests = [fun tls_v1:psk_suites/1, + fun tls_v1:srp_suites/1, + fun tls_v1:rsa_suites/1, + fun tls_v1:des_suites/1, + fun tls_v1:rc4_suites/1], + lists:flatmap(fun (Fun) -> Fun(Version) end, Tests). + %%-------------------------------------------------------------------- --spec anonymous_suites(ssl_record:ssl_version() | integer()) -> - [ssl_cipher_format:cipher_suite()]. +-spec anonymous_suites(ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()]. %% %% Description: Returns a list of the anonymous cipher suites, only supported %% if explicitly set by user. Intended only for testing. %%-------------------------------------------------------------------- -anonymous_suites({3, N}) -> - anonymous_suites(N); -anonymous_suites({254, _} = Version) -> - dtls_v1:anonymous_suites(Version); - -anonymous_suites(1 = N) -> - tls_v1:exclusive_anonymous_suites(N); -anonymous_suites(4 = N) -> - tls_v1:exclusive_anonymous_suites(N); -anonymous_suites(N) when N > 1-> - tls_v1:exclusive_anonymous_suites(N) ++ anonymous_suites(N-1). + +anonymous_suites(Version) when ?TLS_1_X(Version) -> + SuitesToTest = anonymous_suite_to_test(Version), + lists:flatmap(fun tls_v1:exclusive_anonymous_suites/1, SuitesToTest); +anonymous_suites(Version) when ?DTLS_1_X(Version) -> + dtls_v1:anonymous_suites(Version). + +anonymous_suite_to_test(?TLS_1_0) -> [?TLS_1_0]; +anonymous_suite_to_test(?TLS_1_1) -> [?TLS_1_1, ?TLS_1_0]; +anonymous_suite_to_test(?TLS_1_2) -> [?TLS_1_2, ?TLS_1_1, ?TLS_1_0]; +anonymous_suite_to_test(?TLS_1_3) -> [?TLS_1_3]. %%-------------------------------------------------------------------- -spec filter(undefined | binary(), [ssl_cipher_format:cipher_suite()], @@ -391,11 +389,11 @@ filter(DerCert, Ciphers0, Version) -> %% Description: Filter suites using supplied filter funs %%------------------------------------------------------------------- filter_suites(Suites, Filters) -> - ApplyFilters = fun(Suite) -> - filter_suite(Suite, Filters) - end, - lists:filter(ApplyFilters, Suites). - + Fn = fun (Suite) when is_map_key(key_exchange, Suite) -> Suite; + (Suite) -> ssl_cipher_format:suite_bin_to_map(Suite) + end, + lists:filter(fun(Suite) -> filter_suite(Fn(Suite), Filters) end, Suites). + filter_suite(#{key_exchange := KeyExchange, cipher := Cipher, mac := Hash, @@ -404,12 +402,10 @@ filter_suite(#{key_exchange := KeyExchange, cipher_filters := CipherFilters, mac_filters := HashFilters, prf_filters := PrfFilters}) -> - all_filters(KeyExchange, KeyFilters) andalso - all_filters(Cipher, CipherFilters) andalso - all_filters(Hash, HashFilters) andalso - all_filters(Prf, PrfFilters); -filter_suite(Suite, Filters) -> - filter_suite(ssl_cipher_format:suite_bin_to_map(Suite), Filters). + KeyPairs = [{KeyExchange, KeyFilters}, {Cipher, CipherFilters}, + {Hash, HashFilters}, {Prf, PrfFilters}], + lists:all(fun all_filters/1, KeyPairs). + %%-------------------------------------------------------------------- -spec filter_suites([ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]) -> @@ -421,15 +417,9 @@ filter_suites(Suites) -> Filters = crypto_support_filters(), filter_suites(Suites, Filters). -all_filters(_, []) -> - true; -all_filters(Value, [Filter| Rest]) -> - case Filter(Value) of - true -> - all_filters(Value, Rest); - false -> - false - end. +all_filters({Value, Filters}) -> + lists:all(fun (FilterFn) -> FilterFn(Value) end, Filters). + crypto_support_filters() -> Algos = crypto:supports(), Hashs = proplists:get_value(hashs, Algos), @@ -566,20 +556,17 @@ hash_size(sha384) -> hash_size(sha512) -> 64. -is_supported_sign({Hash, rsa} = SignAlgo, HashSigns) -> %% PRE TLS-1.3 - lists:member(SignAlgo, HashSigns) orelse - lists:member({Hash, rsa_pss_rsae}, HashSigns); -is_supported_sign(rsa_pkcs1_sha256 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy - lists:member(SignAlgo, HashSigns) orelse - lists:member(rsa_pss_rsae_sha256, HashSigns); -is_supported_sign(rsa_pkcs1_sha384 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy - lists:member(SignAlgo, HashSigns) orelse - lists:member(rsa_pss_rsae_sha384, HashSigns); -is_supported_sign(rsa_pkcs1_sha512 = SignAlgo, HashSigns) -> %% TLS-1.3 legacy - lists:member(SignAlgo, HashSigns) orelse - lists:member(rsa_pss_rsae_sha512, HashSigns); -is_supported_sign(SignAlgo, HashSigns) -> %% PRE TLS-1.3 SignAlgo::tuple() TLS-1.3 SignAlgo::atom() - lists:member(SignAlgo, HashSigns). +is_supported_sign(SignAlgo, HashSigns) -> + lists:any(fun (SignAlgo0) -> lists:member(SignAlgo0, HashSigns) end, + [SignAlgo, supported_signalgo(SignAlgo)]). + +supported_signalgo({Hash, rsa}) -> {Hash,rsa_pss_rsae}; %% PRE TLS-1.3 %% PRE TLS-1.3 +supported_signalgo(rsa_pkcs1_sha256) -> rsa_pss_rsae_sha256; %% TLS-1.3 legacy +supported_signalgo(rsa_pkcs1_sha384) -> rsa_pss_rsae_sha384; %% TLS-1.3 legacy +supported_signalgo(rsa_pkcs1_sha512) -> rsa_pss_rsae_sha512; %% TLS-1.3 legacy +supported_signalgo(_) -> skip_test. %% made up atom, PRE TLS-1.3 SignAlgo::tuple() TLS-1.3 SignAlgo::atom() + + signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256; signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384; @@ -674,8 +661,8 @@ scheme_to_components(eddsa_ed448) -> {none, eddsa, ed448}; scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined}; scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined}; scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined}; -scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined}; -scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}; +scheme_to_components(rsa_pkcs1_sha1) -> {sha, rsa_pkcs1, undefined}; +scheme_to_components(ecdsa_sha1) -> {sha, ecdsa, undefined}; %% Handling legacy signature algorithms scheme_to_components({Hash,Sign}) -> {Hash, Sign, undefined}. @@ -685,8 +672,8 @@ scheme_to_components({Hash,Sign}) -> {Hash, Sign, undefined}. mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, _Length, _Fragment) -> <<>>; -mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) - when N =:= 1; N =:= 2; N =:= 3; N =:= 4 -> +mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) + when ?TLS_LTE(Version, ?TLS_1_2), Version =/= ?SSL_3_0 -> tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version, Length, Fragment). @@ -826,9 +813,9 @@ block_size(Cipher) when Cipher == aes_128_cbc; Cipher == chacha20_poly1305 -> 16. -prf_algorithm(default_prf, {3, N}) when N >= 3 -> +prf_algorithm(default_prf, ?TLS_1_2) -> ?SHA256; -prf_algorithm(default_prf, {3, _}) -> +prf_algorithm(default_prf, Version) when ?TLS_1_X(Version) -> ?MD5SHA; prf_algorithm(Algo, _) -> hash_algorithm(Algo). @@ -931,8 +918,7 @@ signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?'id-RSASSA-PSS' %% We return the original (possibly invalid) PadLength in any case. %% An invalid PadLength will be caught by is_correct_padding/2 %% -generic_block_cipher_from_bin({3, N}, T, IV, HashSize) - when N == 0; N == 1 -> +generic_block_cipher_from_bin(?TLS_1_0, T, IV, HashSize)-> Sz1 = byte_size(T) - 1, <<_:Sz1/binary, ?BYTE(PadLength0)>> = T, PadLength = if @@ -946,8 +932,8 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize) padding=Padding, padding_length=PadLength0, next_iv = IV}; -generic_block_cipher_from_bin({3, N}, T, IV, HashSize) - when N == 2; N == 3; N == 4 -> +generic_block_cipher_from_bin(Version, T, IV, HashSize) + when Version == ?TLS_1_1; Version == ?TLS_1_2 -> Sz1 = byte_size(T) - 1, <<_:Sz1/binary, ?BYTE(PadLength)>> = T, IVLength = byte_size(IV), @@ -966,14 +952,14 @@ generic_stream_cipher_from_bin(T, HashSz) -> mac=Mac}. is_correct_padding(#generic_block_cipher{padding_length = Len, - padding = Padding}, {3, 0}, _) -> + padding = Padding}, ?SSL_3_0, _) -> Len == byte_size(Padding); %% Only length check is done in SSL 3.0 spec %% For interoperability reasons it is possible to disable -%% the padding check when using TLS 1.0, as it is not strictly required +%% the padding check when using TLS 1.0 (mimicking SSL-3.0), as it is not strictly required %% in the spec (only recommended), however this makes TLS 1.0 vunrable to the Poodle attack %% so by default this clause will not match -is_correct_padding(GenBlockCipher, {3, 1}, false) -> - is_correct_padding(GenBlockCipher, {3, 0}, false); +is_correct_padding(GenBlockCipher, ?TLS_1_0, false) -> + is_correct_padding(GenBlockCipher, ?SSL_3_0, false); %% Padding must be checked in TLS 1.1 and after is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _, _) -> @@ -1051,14 +1037,14 @@ filter_suites_pubkey(ecdsa, Ciphers, _, OtpCert) -> ec_ecdhe_suites(Ciphers)), filter_keyuse_suites(keyAgreement, Uses, CiphersSuites, ec_ecdh_suites(Ciphers)). -filter_suites_signature(_, Ciphers, {3, N}) when N >= 3 -> +filter_suites_signature(_, Ciphers, Version) when ?TLS_GTE(Version, ?TLS_1_2) -> Ciphers; filter_suites_signature(rsa, Ciphers, Version) -> - (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version); + (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers); filter_suites_signature(dsa, Ciphers, Version) -> (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- rsa_signed_suites(Ciphers, Version); filter_suites_signature(ecdsa, Ciphers, Version) -> - (Ciphers -- rsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version). + (Ciphers -- rsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers). %% From RFC 5246 - Section 7.4.2. Server Certificate @@ -1077,7 +1063,7 @@ filter_suites_signature(ecdsa, Ciphers, Version) -> %% extension. The names DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are %% historical. %% Note: DH_DSS and DH_RSA is not supported -rsa_signed({3,N}) when N >= 3 -> +rsa_signed(?TLS_1_2) -> fun(rsa) -> true; (dhe_rsa) -> true; (ecdhe_rsa) -> true; @@ -1096,11 +1082,9 @@ rsa_signed(_) -> end. %% Cert should be signed by RSA rsa_signed_suites(Ciphers, Version) -> - filter_suites(Ciphers, #{key_exchange_filters => [rsa_signed(Version)], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). -ecdsa_signed({3,N}) when N >= 3 -> + filter_kex(Ciphers, rsa_signed(Version)). + +ecdsa_signed(Version) when ?TLS_GTE(Version, ?TLS_1_2) -> fun(ecdhe_ecdsa) -> true; (_) -> false end; @@ -1112,10 +1096,7 @@ ecdsa_signed(_) -> %% Cert should be signed by ECDSA ecdsa_signed_suites(Ciphers, Version) -> - filter_suites(Ciphers, #{key_exchange_filters => [ecdsa_signed(Version)], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, ecdsa_signed(Version)). rsa_keyed(dhe_rsa) -> true; @@ -1132,98 +1113,67 @@ rsa_keyed(_) -> %% Certs key is an RSA key rsa_keyed_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> rsa_keyed(Kex) end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun rsa_keyed/1). %% RSA Certs key can be used for encipherment rsa_suites_encipher(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(rsa) -> true; - (rsa_psk) -> true; - (_) -> false - end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun(rsa) -> true; + (rsa_psk) -> true; + (_) -> false + end). -dss_keyed(dhe_dss) -> - true; -dss_keyed(spr_dss) -> - true; -dss_keyed(_) -> - false. %% Cert should be have DSS key (DSA) dss_keyed_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> dss_keyed(Kex) end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun (dhe_dss) -> true; + (spr_dss) -> true; + (_) -> false + end). %% Cert should be signed by DSS (DSA) -dsa_signed_suites(Ciphers, Version) -> - filter_suites(Ciphers, #{key_exchange_filters => [dsa_signed(Version)], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). -dsa_signed(_) -> - fun(dhe_dss) -> true; - (_) -> false - end. +dsa_signed_suites(Ciphers) -> + filter_kex(Ciphers, fun(dhe_dss) -> true; + (_) -> false + end). dss_dhe_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_dss) -> true; - (_) -> false - end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). - -ec_keyed(ecdh_ecdsa) -> - true; -ec_keyed(ecdh_rsa) -> - true; -ec_keyed(ecdhe_ecdsa) -> - true; -ec_keyed(_) -> - false. - + filter_kex(Ciphers, fun(dhe_dss) -> true; + (_) -> false + end). %% Certs key is an ECC key ec_keyed_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> ec_keyed(Kex) end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun (ecdh_ecdsa) -> true; + (ecdh_rsa) -> true; + (ecdhe_ecdsa) -> true; + (_) -> false + end). %% EC Certs key usage keyAgreement ec_ecdh_suites(Ciphers)-> - filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdh_ecdsa) -> true; - (_) -> false - end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun(ecdh_ecdsa) -> true; + (_) -> false + end). %% EC Certs key usage digitalSignature ec_ecdhe_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdhe_ecdsa) -> true; - (ecdhe_rsa) -> true; - (_) -> false - end], - cipher_filters => [], - mac_filters => [], - prf_filters => []}). + filter_kex(Ciphers, fun(ecdhe_ecdsa) -> true; + (ecdhe_rsa) -> true; + (_) -> false + end). %% RSA Certs key usage digitalSignature rsa_ecdhe_dhe_suites(Ciphers) -> - filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_rsa) -> true; - (ecdhe_rsa) -> true; - (_) -> false - end], + filter_kex(Ciphers, fun(dhe_rsa) -> true; + (ecdhe_rsa) -> true; + (_) -> false + end). + +filter_kex(Ciphers, Fn) -> + filter_suites(Ciphers, #{key_exchange_filters => [Fn], cipher_filters => [], mac_filters => [], prf_filters => []}). + key_uses(OtpCert) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions, @@ -1254,21 +1204,12 @@ generate_server_share(Group) -> key_exchange = Key }}. -generate_client_shares([]) -> - #key_share_client_hello{client_shares = []}; generate_client_shares(Groups) -> - generate_client_shares(Groups, []). -%% -generate_client_shares([], Acc) -> - #key_share_client_hello{client_shares = lists:reverse(Acc)}; -generate_client_shares([Group|Groups], Acc) -> - Key = generate_key_exchange(Group), - KeyShareEntry = #key_share_entry{ - group = Group, - key_exchange = Key - }, - generate_client_shares(Groups, [KeyShareEntry|Acc]). - + KeyShareEntry = fun (Group) -> + #key_share_entry{group = Group, key_exchange = generate_key_exchange(Group)} + end, + ClientShares = lists:map(KeyShareEntry, Groups), + #key_share_client_hello{client_shares = ClientShares}. generate_key_exchange(secp256r1) -> public_key:generate_key({namedCurve, secp256r1}); @@ -1306,10 +1247,22 @@ encrypt_ticket(#stateless_ticket{ pre_shared_key = PSK, ticket_age_add = TicketAgeAdd, lifetime = Lifetime, - timestamp = Timestamp + timestamp = Timestamp, + certificate = Certificate }, Shard, IV) -> - Plaintext = <<(ssl_cipher:hash_algorithm(Hash)):8,PSK/binary, + Plaintext1 = <<(ssl_cipher:hash_algorithm(Hash)):8,PSK/binary, ?UINT64(TicketAgeAdd),?UINT32(Lifetime),?UINT32(Timestamp)>>, + CertificateLength = case Certificate of + undefined -> 0; + _ -> byte_size(Certificate) + end, + Plaintext = case CertificateLength of + 0 -> + <>; + _ -> + <> + end, encrypt_ticket_data(Plaintext, Shard, IV). @@ -1321,13 +1274,19 @@ decrypt_ticket(CipherFragment, Shard, IV) -> <> = Plaintext, Hash = hash_algorithm(HKDF), HashSize = hash_size(Hash), - <> = T, + <> = T, + Certificate = case CertificateLength of + 0 -> undefined; + _ -> Certificate1 + end, #stateless_ticket{ hash = Hash, pre_shared_key = PSK, ticket_age_add = TicketAgeAdd, lifetime = Lifetime, - timestamp = Timestamp + timestamp = Timestamp, + certificate = Certificate } end. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 77305c1e77ba..cf5bd06a35c9 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -34,7 +34,8 @@ pre_shared_key, ticket_age_add, lifetime, - timestamp + timestamp, + certificate }). %%% SSL cipher protocol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl index 91bd03decf95..761a4f431561 100644 --- a/lib/ssl/src/ssl_config.erl +++ b/lib/ssl/src/ssl_config.erl @@ -40,21 +40,130 @@ %%==================================================================== %% Internal application API %%==================================================================== -init(#{erl_dist := ErlDist, - key := Key, - keyfile := KeyFile, - password := Password, %% Can be fun() or string() - dh := DH, - dhfile := DHFile} = SslOpts, Role) -> - - init_manager_name(ErlDist), - - {ok, #{pem_cache := PemCache} = Config, Certs} - = init_certificates(SslOpts, Role), - PrivateKey = - init_private_key(PemCache, Key, KeyFile, Password, Role), - DHParams = init_diffie_hellman(PemCache, DH, DHFile, Role), - {ok, Config#{cert_key_pairs => [#{private_key => PrivateKey, certs => Certs}], dh_params => DHParams}}. +init(SslOpts, Role) -> + init_manager_name(maps:get(erl_dist, SslOpts, false)), + #{pem_cache := PemCache} = Config = init_cacerts(SslOpts, Role), + DHParams = init_diffie_hellman(PemCache, SslOpts, Role), + CertKeyAlts = init_certs_keys(SslOpts, Role, PemCache), + {ok, Config#{cert_key_alts => CertKeyAlts, dh_params => DHParams}}. + +init_certs_keys(#{certs_keys := CertsKeys}, Role, PemCache) -> + Pairs = lists:map(fun(CertKey) -> init_cert_key_pair(CertKey, Role, PemCache) end, CertsKeys), + CertKeyGroups = group_pairs(Pairs), + prioritize_groups(CertKeyGroups). + +init_cert_key_pair(CertKey, Role, PemCache) -> + Certs = init_certificates(CertKey, PemCache, Role), + PrivateKey = init_private_key(maps:get(key, CertKey, undefined), CertKey, PemCache), + #{private_key => PrivateKey, certs => Certs}. + +group_pairs([#{certs := []}]) -> + #{eddsa => [], + ecdsa => [], + rsa_pss_pss => [], + rsa => [], + dsa => [] + }; +group_pairs(Pairs) -> + group_pairs(Pairs, #{eddsa => [], + ecdsa => [], + rsa_pss_pss => [], + rsa => [], + dsa => [] + }). + +group_pairs([#{private_key := #'ECPrivateKey'{parameters = {namedCurve, ?'id-Ed25519'}}} = Pair | Rest], #{eddsa := EDDSA} = Group) -> + group_pairs(Rest, Group#{eddsa => [Pair | EDDSA]}); +group_pairs([#{private_key := #'ECPrivateKey'{parameters = {namedCurve, ?'id-Ed448'}}} = Pair | Rest], #{eddsa := EDDSA} = Group) -> + group_pairs(Rest, Group#{eddsa => [Pair | EDDSA]}); +group_pairs([#{private_key := #'ECPrivateKey'{}} = Pair | Rest], #{ecdsa := ECDSA} = Group) -> + group_pairs(Rest, Group#{ecdsa => [Pair | ECDSA]}); +group_pairs([#{private_key := {#'RSAPrivateKey'{}, #'RSASSA-PSS-params'{}}} = Pair | Rest], #{rsa_pss_pss := RSAPSS} = Group) -> + group_pairs(Rest, Group#{rsa_pss_pss => [Pair | RSAPSS]}); +group_pairs([#{private_key := #'RSAPrivateKey'{}} = Pair | Rest], #{rsa := RSA} = Group) -> + group_pairs(Rest, Group#{rsa => [Pair | RSA]}); +group_pairs([#{private_key := #'DSAPrivateKey'{}} = Pair | Rest], #{dsa := DSA} = Group) -> + group_pairs(Rest, Group#{dsa => [Pair | DSA]}); +group_pairs([#{private_key := #{algorithm := dss, engine := _}} = Pair | Rest], Group) -> + Pairs = maps:get(dsa, Group), + group_pairs(Rest, Group#{dsa => [Pair | Pairs]}); +group_pairs([#{private_key := #{algorithm := Alg, engine := _}} = Pair | Rest], Group) -> + Pairs = maps:get(Alg, Group), + group_pairs(Rest, Group#{Alg => [Pair | Pairs]}); +group_pairs([], Group) -> + Group. + + +prioritize_groups(#{eddsa := EDDSA, + ecdsa := ECDSA, + rsa_pss_pss := RSAPSS, + rsa := RSA, + dsa := DSA} = CertKeyGroups) -> + CertKeyGroups#{eddsa => prio_eddsa(EDDSA), + ecdsa => prio_ecdsa(ECDSA), + rsa_pss_pss => prio_rsa_pss(RSAPSS), + rsa => prio_rsa(RSA), + dsa => prio_dsa(DSA)}. + +prio_eddsa(EDDSA) -> + %% Engine not supported yet + using_curve({namedCurve, ?'id-Ed25519'}, EDDSA, []) ++ using_curve({namedCurve, ?'id-Ed448'}, EDDSA, []). + +prio_ecdsa(ECDSA) -> + EnginePairs = [Pair || Pair = #{private_key := #{engine := _}} <- ECDSA], + Curves = tls_v1:ecc_curves(all), + EnginePairs ++ lists:foldr(fun(Curve, AccIn) -> + CurveOid = pubkey_cert_records:namedCurves(Curve), + Pairs = using_curve({namedCurve, CurveOid}, ECDSA -- EnginePairs, []), + Pairs ++ AccIn + end, [], Curves). +using_curve(_, [], Acc) -> + lists:reverse(Acc); +using_curve(Curve, [#{private_key := #'ECPrivateKey'{parameters = Curve}} = Pair | Rest], Acc) -> + using_curve(Curve, Rest, [Pair | Acc]); +using_curve(Curve, [_ | Rest], Acc) -> + using_curve(Curve, Rest, Acc). + +prio_rsa_pss(RSAPSS) -> + Order = fun(#{privat_key := {#'RSAPrivateKey'{modulus = N}, Params1}}, + #{private_key := {#'RSAPrivateKey'{modulus = N}, Params2}}) -> + prio_params_1(Params1, Params2); + (#{private_key := {#'RSAPrivateKey'{modulus = N}, _}}, + #{private_key := {#'RSAPrivateKey'{modulus = M}, _}}) when M > N -> + true; + (#{private_key := #{engine := _}}, _) -> + true; + (_,_) -> + false + end, + lists:sort(Order, RSAPSS). + +prio_params_1(#'RSASSA-PSS-params'{hashAlgorithm = #'HashAlgorithm'{algorithm = Oid1}}, + #'RSASSA-PSS-params'{hashAlgorithm = #'HashAlgorithm'{algorithm = Oid2}}) -> + public_key:pkix_hash_type(Oid1) > public_key:pkix_hash_type(Oid2). + +prio_rsa(RSA) -> + Order = fun(#{key := #'RSAPrivateKey'{modulus = N}}, + #{key := #'RSAPrivateKey'{modulus = M}}) when M > N -> + true; + (#{private_key := #{engine := _}}, _) -> + true; + (_,_) -> + false + end, + lists:sort(Order, RSA). + +prio_dsa(DSA) -> + Order = fun(#{key := #'DSAPrivateKey'{q = N}}, + #{key := #'DSAPrivateKey'{q = M}}) when M > N -> + true; + (#{private_key := #{engine := _}}, _) -> + true; + (_,_) -> + false + end, + lists:sort(Order, DSA). + pre_1_3_session_opts(Role) -> {Cb, InitArgs} = session_cb_opts(Role), @@ -119,81 +228,71 @@ init_manager_name(true) -> put(ssl_manager, ssl_manager:name(dist)), put(ssl_pem_cache, ssl_pem_cache:name(dist)). -init_certificates(#{cacerts := CaCerts, - cacertfile := CACertFile, - certfile := CertFile, - cert := OwnCerts, - crl_cache := CRLCache - }, Role) -> +init_cacerts(#{cacerts := CaCerts, crl_cache := CRLCache} = Opts, Role) -> + CACertFile = maps:get(cacertfile, Opts, <<>>), {ok, Config} = - try + try Certs = case CaCerts of - undefined -> - CACertFile; - _ -> - {der, CaCerts} + undefined -> CACertFile; + _ -> {der, CaCerts} end, {ok,_} = ssl_manager:connection_init(Certs, Role, CRLCache) catch _:Reason -> file_error(CACertFile, {cacertfile, Reason}) end, - init_certificates(OwnCerts, Config, CertFile, Role). - -init_certificates(undefined, Config, <<>>, _) -> - {ok, Config, [[]]}; + Config. -init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, client) -> - try - %% OwnCert | [OwnCert | Chain] - OwnCerts = ssl_certificate:file_to_certificats(CertFile, PemCache), - {ok, Config, OwnCerts} - catch _Error:_Reason -> - {ok, Config, [[]]} - end; +init_certificates(CertKey, PemCache, Role) -> + case maps:get(cert, CertKey, undefined) of + undefined -> + init_certificate_file(maps:get(certfile, CertKey, <<>>), PemCache, Role); + Bin when is_binary(Bin) -> + [Bin]; + Certs when is_list(Certs) -> + Certs + end. -init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server) -> - try - %% OwnCert | [OwnCert | Chain] - OwnCerts = ssl_certificate:file_to_certificats(CertFile, PemCache), - {ok, Config, OwnCerts} +init_certificate_file(<<>>, _PemCache, _Role) -> + []; +init_certificate_file(CertFile, PemCache, Role) -> + try %% OwnCert | [OwnCert | Chain] + ssl_certificate:file_to_certificats(CertFile, PemCache) catch - _:Reason -> - file_error(CertFile, {certfile, Reason}) - end; -init_certificates(OwnCerts, Config, _, _) -> - {ok, Config, OwnCerts}. -init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg == ecdsa; - Alg == rsa; - Alg == dss -> + _Error:_Reason when Role =:= client -> + []; + _Error:Reason -> + file_error(CertFile, {certfile, Reason}) + end. + +init_private_key(#{algorithm := Alg} = Key, _, _PemCache) + when Alg =:= ecdsa; Alg =:= rsa; Alg =:= dss -> case maps:is_key(engine, Key) andalso maps:is_key(key_id, Key) of - true -> - Key; - false -> - throw({key, {invalid_key_id, Key}}) - end; -init_private_key(_, undefined, <<>>, _Password, _Client) -> - #{}; -init_private_key(DbHandle, undefined, KeyFile, Password, _) -> - try - {ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle), - [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, - PKey =:= 'RSAPrivateKey' orelse - PKey =:= 'DSAPrivateKey' orelse - PKey =:= 'ECPrivateKey' orelse - PKey =:= 'PrivateKeyInfo' - ], - private_key(public_key:pem_entry_decode(PemEntry, Password)) - catch - _:Reason -> - file_error(KeyFile, {keyfile, Reason}) + true -> Key; + false -> throw({key, {invalid_key_id, Key}}) end; - -init_private_key(_,{Asn1Type, PrivateKey},_,_,_) -> - private_key(init_private_key(Asn1Type, PrivateKey)). - -init_private_key(Asn1Type, PrivateKey) -> - public_key:der_decode(Asn1Type, PrivateKey). +init_private_key({Asn1Type, PrivateKey},_,_) -> + private_key(public_key:der_decode(Asn1Type, PrivateKey)); +init_private_key(undefined, CertKey, DbHandle) -> + case maps:get(keyfile, CertKey, undefined) of + undefined -> + #{}; + KeyFile -> + Password = maps:get(password, CertKey, undefined), + try + {ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle), + [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, + PKey =:= 'RSAPrivateKey' orelse + PKey =:= 'DSAPrivateKey' orelse + PKey =:= 'ECPrivateKey' orelse + PKey =:= 'PrivateKeyInfo' + ], + private_key(public_key:pem_entry_decode(PemEntry, Password)) + catch + _:Reason -> + file_error(KeyFile, {keyfile, Reason}) + end + end. private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'rsaEncryption'}, @@ -225,27 +324,35 @@ file_error(File, Throw) -> throw(Throw) end. -init_diffie_hellman(_,Params, _,_) when is_binary(Params)-> - public_key:der_decode('DHParameter', Params); -init_diffie_hellman(_,_,_, client) -> +init_diffie_hellman(_, _, client) -> undefined; -init_diffie_hellman(_,_,undefined, _) -> - ?DEFAULT_DIFFIE_HELLMAN_PARAMS; -init_diffie_hellman(DbHandle,_, DHParamFile, server) -> +init_diffie_hellman(DbHandle, Opts, server) -> + case maps:get(dh, Opts, undefined) of + Bin when is_binary(Bin) -> + public_key:der_decode('DHParameter', Bin); + _ -> + case maps:get(dh, Opts, undefined) of + undefined -> + ?DEFAULT_DIFFIE_HELLMAN_PARAMS; + DHParamFile -> + dh_file(DbHandle, DHParamFile) + end + end. + +dh_file(DbHandle, DHParamFile) -> try - {ok, List} = ssl_manager:cache_pem_file(DHParamFile,DbHandle), - case [Entry || Entry = {'DHParameter', _ , _} <- List] of - [Entry] -> - public_key:pem_entry_decode(Entry); - [] -> - ?DEFAULT_DIFFIE_HELLMAN_PARAMS - end + {ok, List} = ssl_manager:cache_pem_file(DHParamFile,DbHandle), + case [Entry || Entry = {'DHParameter', _ , _} <- List] of + [Entry] -> + public_key:pem_entry_decode(Entry); + [] -> + ?DEFAULT_DIFFIE_HELLMAN_PARAMS + end catch - _:Reason -> - file_error(DHParamFile, {dhfile, Reason}) + _:Reason -> + file_error(DHParamFile, {dhfile, Reason}) end. - session_cb_init_args(client) -> case application:get_env(ssl, client_session_cb_init_args) of undefined -> diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl index 3de0dc79918b..c8295f339fbd 100644 --- a/lib/ssl/src/ssl_connection.hrl +++ b/lib/ssl/src/ssl_connection.hrl @@ -99,9 +99,12 @@ socket_tls_closed = false ::boolean(), negotiated_version :: ssl_record:ssl_version() | 'undefined', erl_dist_handle = undefined :: erlang:dist_handle() | 'undefined', - cert_key_pairs = undefined :: [#{private_key => public_key:private_key(), - certs => [public_key:der_encoded()]}] - | secret_printout() | 'undefined' + cert_key_alts = undefined :: #{eddsa => list(), + ecdsa => list(), + rsa_pss_pss => list(), + rsa => list(), + dsa => list() + } | secret_printout() | 'undefined' }). -record(state, { diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl index 095e3e8b4487..c12d829470cc 100644 --- a/lib/ssl/src/ssl_crl_cache.erl +++ b/lib/ssl/src/ssl_crl_cache.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015-2020. All Rights Reserved. +%% Copyright Ericsson AB 2015-2022. 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. @@ -64,7 +64,7 @@ fresh_crl(#'DistributionPoint'{distributionPoint = {fullName, Names}}, CRL) -> case get_crls(Names, undefined) of not_available -> CRL; - [NewCRL] -> + NewCRL -> NewCRL end. @@ -175,7 +175,7 @@ cache_lookup(URL, {{Cache, _}, _}) -> case ssl_pkix_db:lookup(string:trim(Path, leading, "/"), Cache) of undefined -> []; - CRLs -> + [CRLs] -> CRLs end. diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl index 521555789ca9..348abe6125d5 100644 --- a/lib/ssl/src/ssl_gen_statem.erl +++ b/lib/ssl/src/ssl_gen_statem.erl @@ -25,8 +25,6 @@ -module(ssl_gen_statem). --include_lib("kernel/include/logger.hrl"). - -include("ssl_api.hrl"). -include("ssl_internal.hrl"). -include("ssl_connection.hrl"). @@ -40,7 +38,8 @@ init/1]). %% TLS connection setup --export([ssl_config/3, +-export([init_ssl_config/3, + ssl_config/3, connect/8, handshake/7, handshake/2, @@ -62,7 +61,8 @@ set_opts/2, peer_certificate/1, negotiated_protocol/1, - connection_information/2 + connection_information/2, + ktls_handover/1 ]). %% Erlang Distribution export @@ -98,58 +98,88 @@ %% Log handling -export([format_status/2]). +%% Tracing +-export([handle_trace/3]). + %%-------------------------------------------------------------------- %%% Initial Erlang process setup %%-------------------------------------------------------------------- %%-------------------------------------------------------------------- --spec start_link(client| server, pid(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(client| server, pid(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a process which calls Module:init/1 to %% choose appropriat gen_statem and initialize. %%-------------------------------------------------------------------- -start_link(Role, Sender, Host, Port, Socket, Options, User, CbInfo) -> - {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]])}. +start_link(Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) -> + ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []), + Opts = [link | proplists:delete(link, ReceiverOpts)], + Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]], Opts), + {ok, Pid}. %%-------------------------------------------------------------------- --spec start_link(atom(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) -> +-spec start_link(atom(), ssl:host(), inet:port_number(), port(), tuple(), pid(), tuple()) -> {ok, pid()} | ignore | {error, reason()}. %% %% Description: Creates a gen_statem process which calls Module:init/1 to %% initialize. %%-------------------------------------------------------------------- -start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> - {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}. +start_link(Role, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo) -> + ReceiverOpts = maps:get(receiver_spawn_opts, SslOpts, []), + Opts = [link | proplists:delete(link, ReceiverOpts)], + Pid = proc_lib:spawn_opt(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]], Opts), + {ok, Pid}. %%-------------------------------------------------------------------- -spec init(list()) -> no_return(). %% Description: Initialization %%-------------------------------------------------------------------- -init([_Role, _Sender, _Host, _Port, _Socket, {#{erl_dist := ErlDist} = TLSOpts, _, _}, _User, _CbInfo] = InitArgs) -> +init([Role, _Sender, _Host, _Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs) -> process_flag(trap_exit, true), - case ErlDist of + case maps:get(erl_dist, TLSOpts, false) of true -> process_flag(priority, max); _ -> ok end, - ConnectionFsm = tls_connection_fsm(TLSOpts), - ConnectionFsm:init(InitArgs); -init([_Role, _Host, _Port, _Socket, {TLSOpts, _, _}, _User, _CbInfo] = InitArgs) -> + case {Role, TLSOpts} of + {?CLIENT_ROLE, #{versions := [?TLS_1_3]}} -> + tls_client_connection_1_3:init(InitArgs); + {?SERVER_ROLE, #{versions := [?TLS_1_3]}} -> + tls_server_connection_1_3:init(InitArgs); + {_,_} -> + tls_connection:init(InitArgs) + end; +init([_Role, _Host, _Port, _Socket, _TLSOpts, _User, _CbInfo] = InitArgs) -> process_flag(trap_exit, true), - ConnectionFsm = dtls_connection_fsm(TLSOpts), - ConnectionFsm:init(InitArgs). + dtls_connection:init(InitArgs). %%==================================================================== %% TLS connection setup %%==================================================================== +%%-------------------------------------------------------------------- +-spec init_ssl_config(ssl_options(), client | server, #state{}) -> #state{}. +%%-------------------------------------------------------------------- +init_ssl_config(Opts, Role, #state{ssl_options = #{handshake := Handshake}, + handshake_env = HsEnv} = State0) -> + ContinueStatus = case Handshake of + hello -> + %% Will pause handshake after hello message to + %% enable user to react to hello extensions + pause; + full -> + Handshake + end, + ssl_config(Opts, Role, + State0#state{handshake_env = + HsEnv#handshake_env{continue_status = ContinueStatus}}). + %%-------------------------------------------------------------------- -spec ssl_config(ssl_options(), client | server, #state{}) -> #state{}. %%-------------------------------------------------------------------- ssl_config(Opts, Role, #state{static_env = InitStatEnv0, - ssl_options = #{handshake := Handshake}, handshake_env = HsEnv, connection_env = CEnv} = State0) -> {ok, #{cert_db_ref := Ref, @@ -157,21 +187,12 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, fileref_db_handle := FileRefHandle, session_cache := CacheHandle, crl_db_info := CRLDbHandle, - cert_key_pairs := CertKeyPairs, + cert_key_alts := CertKeyAlts, dh_params := DHParams}} = ssl_config:init(Opts, Role), TimeStamp = erlang:monotonic_time(), Session = State0#state.session, - ContinueStatus = case Handshake of - hello -> - %% Will pause handshake after hello message to - %% enable user to react to hello extensions - pause; - full -> - Handshake - end, - State0#state{session = Session#session{time_stamp = TimeStamp}, static_env = InitStatEnv0#static_env{ file_ref_db = FileRefHandle, @@ -180,9 +201,9 @@ ssl_config(Opts, Role, #state{static_env = InitStatEnv0, crl_db = CRLDbHandle, session_cache = CacheHandle }, - handshake_env = HsEnv#handshake_env{diffie_hellman_params = DHParams, - continue_status = ContinueStatus}, - connection_env = CEnv#connection_env{cert_key_pairs = CertKeyPairs}, + handshake_env = + HsEnv#handshake_env{diffie_hellman_params = DHParams}, + connection_env = CEnv#connection_env{cert_key_alts = CertKeyAlts}, ssl_options = Opts}. %%-------------------------------------------------------------------- @@ -290,21 +311,23 @@ socket_control(Connection, Socket, Pid, Transport) -> -spec socket_control(tls_gen_connection | dtls_gen_connection, port(), [pid()], atom(), [pid()] | atom()) -> {ok, #sslsocket{}} | {error, reason()}. %%-------------------------------------------------------------------- -socket_control(dtls_gen_connection = Connection, Socket, Pids, Transport, udp_listener) -> +socket_control(dtls_gen_connection, Socket, Pids, Transport, udp_listener) -> %% dtls listener process must have the socket control - {ok, Connection:socket(Pids, Transport, Socket, undefined)}; + {ok, dtls_gen_connection:socket(Pids, Transport, Socket, undefined)}; -socket_control(tls_gen_connection = Connection, Socket, [Pid|_] = Pids, Transport, Trackers) -> +socket_control(tls_gen_connection, Socket, [Pid|_] = Pids, Transport, Trackers) -> case Transport:controlling_process(Socket, Pid) of ok -> - {ok, Connection:socket(Pids, Transport, Socket, Trackers)}; + {ok, tls_gen_connection:socket(Pids, Transport, Socket, Trackers)}; {error, Reason} -> {error, Reason} end; -socket_control(dtls_gen_connection = Connection, {PeerAddrPort, Socket}, [Pid|_] = Pids, Transport, Trackers) -> +socket_control(dtls_gen_connection, {PeerAddrPort, Socket}, + [Pid|_] = Pids, Transport, Trackers) -> case Transport:controlling_process(Socket, Pid) of ok -> - {ok, Connection:socket(Pids, Transport, {PeerAddrPort, Socket}, Trackers)}; + {ok, dtls_gen_connection:socket(Pids, Transport, {PeerAddrPort, Socket}, + Trackers)}; {error, Reason} -> {error, Reason} end. @@ -418,6 +441,14 @@ peer_certificate(ConnectionPid) -> negotiated_protocol(ConnectionPid) -> call(ConnectionPid, negotiated_protocol). +%%-------------------------------------------------------------------- +-spec ktls_handover(pid()) -> {ok, map()} | {error, reason()}. +%% +%% Description: Returns the negotiated protocol +%%-------------------------------------------------------------------- +ktls_handover(ConnectionPid) -> + call(ConnectionPid, ktls_handover). + dist_handshake_complete(ConnectionPid, DHandle) -> gen_statem:cast(ConnectionPid, {dist_handshake_complete, DHandle}). @@ -458,8 +489,6 @@ initial_hello({call, From}, {start, Timeout}, %% Versions is a descending list of supported versions. versions := [HelloVersion|_] = Versions, session_tickets := SessionTickets, - ocsp_stapling := OcspStaplingOpt, - ocsp_nonce := OcspNonceOpt, early_data := EarlyData} = SslOpts, session = Session, connection_states = ConnectionStates0 @@ -469,9 +498,9 @@ initial_hello({call, From}, {start, Timeout}, %% Update UseTicket in case of automatic session resumption. The automatic ticket handling %% also takes it into account if the ticket is suitable for sending early data not exceeding %% the max_early_data_size or if it can only be used for session resumption. - {UseTicket, State1} = tls_handshake_1_3:maybe_automatic_session_resumption(State0), + {UseTicket, State1} = tls_client_connection_1_3:maybe_automatic_session_resumption(State0), TicketData = tls_handshake_1_3:get_ticket_data(self(), SessionTickets, UseTicket), - OcspNonce = tls_handshake:ocsp_nonce(OcspNonceOpt, OcspStaplingOpt), + OcspNonce = tls_handshake:ocsp_nonce(SslOpts), Hello0 = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Session#session.session_id, Renegotiation, @@ -505,21 +534,24 @@ initial_hello({call, From}, {start, Timeout}, %% ServerHello is processed. RequestedVersion = tls_record:hello_version(Versions), - {Ref,Maybe} = tls_handshake_1_3:maybe(), + {Ref,Maybe} = tls_gen_connection_1_3:do_maybe(), try %% Send Early Data - State4 = Maybe(tls_handshake_1_3:maybe_send_early_data(State3)), + State4 = Maybe(tls_client_connection_1_3:maybe_send_early_data(State3)), {#state{handshake_env = HsEnv1} = State5, _} = Connection:send_handshake_flight(State4), + OcspStaplingKeyPresent = maps:is_key(ocsp_stapling, SslOpts), State = State5#state{ connection_env = CEnv#connection_env{ negotiated_version = RequestedVersion}, session = Session, - handshake_env = HsEnv1#handshake_env{ - ocsp_stapling_state = OcspState0#{ocsp_nonce => OcspNonce, - ocsp_stapling => OcspStaplingOpt}}, + handshake_env = + HsEnv1#handshake_env{ + ocsp_stapling_state = + OcspState0#{ocsp_nonce => OcspNonce, + ocsp_stapling => OcspStaplingKeyPresent}}, start_or_recv_from = From, key_share = KeyShare}, NextState = next_statem_state(Versions, Role), @@ -532,17 +564,17 @@ initial_hello({call, From}, {start, Timeout}, initial_hello({call, From}, {start, Timeout}, #state{static_env = #static_env{role = Role, protocol_cb = Connection}, ssl_options = #{versions := Versions}} = State0) -> - - NextState = next_statem_state(Versions, Role), + + NextState = next_statem_state(Versions, Role), Connection:next_event(NextState, no_record, State0#state{start_or_recv_from = From}, [{{timeout, handshake}, Timeout, close}]); - + initial_hello({call, From}, {start, {Opts, EmOpts}, Timeout}, #state{static_env = #static_env{role = Role}, ssl_options = OrigSSLOptions, socket_options = SockOpts} = State0) -> try - SslOpts = ssl:handle_options(Opts, Role, OrigSSLOptions), + SslOpts = ssl:update_options(Opts, Role, OrigSSLOptions), State = ssl_config(SslOpts, Role, State0), initial_hello({call, From}, {start, Timeout}, State#state{ssl_options = SslOpts, @@ -644,6 +676,45 @@ connection({call, From}, {error, timeout} -> {stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]} end; +connection({call, From}, ktls_handover, #state{ + static_env = #static_env{ + transport_cb = Transport, + socket = Socket + }, + connection_env = #connection_env{ + user_application = {_Mon, Pid}, + negotiated_version = TlsVersion + }, + ssl_options = #{ktls := true}, + socket_options = SocketOpts, + connection_states = #{ + current_write := #{ + security_parameters := #security_parameters{cipher_suite = CipherSuite}, + cipher_state := WriteState, + sequence_number := WriteSeq + }, + current_read := #{ + cipher_state := ReadState, + sequence_number := ReadSeq + } + } +}) -> + Reply = case Transport:controlling_process(Socket, Pid) of + ok -> + {ok, #{ + socket => Socket, + tls_version => TlsVersion, + cipher_suite => CipherSuite, + socket_options => SocketOpts, + write_state => WriteState, + write_seq => WriteSeq, + read_state => ReadState, + read_seq => ReadSeq + }}; + {error, Reason} -> + {error, Reason} + end, + {stop_and_reply, {shutdown, ktls}, [{reply, From, Reply}]}; connection({call, From}, Msg, State) -> handle_call(Msg, From, ?FUNCTION_NAME, State); connection(cast, {dist_handshake_complete, DHandle}, @@ -852,10 +923,9 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName, handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{ role = Role, socket = Socket, - error_tag = ErrorTag}, - ssl_options = #{log_level := Level}} = State) -> - ssl_logger:log(info, Level, #{description => "Socket error", - reason => [{error_tag, ErrorTag}, {description, Reason}]}, ?LOCATION), + error_tag = ErrorTag} + } = State) -> + ?SSL_LOG(info, "Socket error", [{error_tag, ErrorTag}, {description, Reason}]), Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, {transport_error, Reason}), handle_normal_shutdown(Alert#alert{role = Role}, StateName, State), {stop, {shutdown,normal}, State}; @@ -882,11 +952,9 @@ handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_en {stop,{shutdown, Reason}, State}; handle_info(allow_renegotiate, StateName, #state{handshake_env = HsEnv} = State) -> %% PRE TLS-1.3 {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{allow_renegotiate = true}}}; -handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = ErrorTag}, - ssl_options = #{log_level := Level}} = State) -> - ssl_logger:log(notice, Level, #{description => "Unexpected INFO message", - reason => [{message, Msg}, {socket, Socket}, - {error_tag, ErrorTag}]}, ?LOCATION), +handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = ErrorTag}} = State) -> + ?SSL_LOG(notice, "Unexpected INFO message", + [{message, Msg}, {socket, Socket}, {error_tag, ErrorTag}]), {next_state, StateName, State}. %%==================================================================== @@ -908,9 +976,25 @@ read_application_data(Data, try read_application_dist_data(DHandle, Front, BufferSize, Rear) of Buffer -> {no_record, State#state{user_data_buffer = Buffer}} - catch error:_ -> - {stop,disconnect, - State#state{user_data_buffer = {Front,BufferSize,Rear}}} + catch + error:notsup -> + %% Distribution controller has shut down + %% so we are no longer input handler and therefore + %% erlang:dist_ctrl_put_data/2 raises this exception + {stop, {shutdown, dist_closed}, + %% This buffers known data, but we might have delivered + %% some of it to the VM, which makes buffering all + %% incorrect, as would be wasting all. + %% But we are stopping the server so + %% user_data_buffer is not important at all... + State#state{ + user_data_buffer = {Front,BufferSize,Rear}}}; + error:Reason:Stacktrace -> + %% Unforeseen exception in parsing application data + {stop, + {disconnect,{error,Reason,Stacktrace}}, + State#state{ + user_data_buffer = {Front,BufferSize,Rear}}} end end. passive_receive(#state{user_data_buffer = {Front,BufferSize,Rear}, @@ -941,8 +1025,9 @@ passive_receive(#state{user_data_buffer = {Front,BufferSize,Rear}, %%==================================================================== hibernate_after(connection = StateName, - #state{ssl_options= #{hibernate_after := HibernateAfter}} = State, + #state{ssl_options= SslOpts} = State, Actions) -> + HibernateAfter = maps:get(hibernate_after, SslOpts, infinity), {next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]}; hibernate_after(StateName, State, Actions) -> {next_state, StateName, State, Actions}. @@ -989,31 +1074,14 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = protocol_cb = Connection, trackers = Trackers}, connection_env = #connection_env{user_application = {_Mon, Pid}}, + handshake_env = #handshake_env{renegotiation = Type}, socket_options = Opts, start_or_recv_from = RecvFrom} = State) -> Pids = Connection:pids(State), - alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection). + alert_user(Pids, Transport, Trackers, Socket, Type, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection). -handle_alert(#alert{level = ?FATAL} = Alert0, StateName, - #state{static_env = #static_env{role = Role, - socket = Socket, - host = Host, - port = Port, - trackers = Trackers, - transport_cb = Transport, - protocol_cb = Connection}, - connection_env = #connection_env{user_application = {_Mon, Pid}}, - ssl_options = #{log_level := LogLevel}, - start_or_recv_from = From, - session = Session, - socket_options = Opts} = State) -> - invalidate_session(Role, Host, Port, Session), - Alert = Alert0#alert{role = opposite_role(Role)}, - log_alert(LogLevel, Role, Connection:protocol_name(), - StateName, Alert), - Pids = Connection:pids(State), - alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection), - {stop, {shutdown, normal}, State}; +handle_alert(#alert{level = ?FATAL} = Alert, StateName, State) -> + handle_fatal_alert(Alert, StateName, State); handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, downgrade= StateName, State) -> {next_state, StateName, State, [{next_event, internal, Alert}]}; @@ -1080,27 +1148,61 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, %% Go back to connection! State = Connection:reinit(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}), Connection:next_event(connection, no_record, State); +handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, StateName, + #state{static_env = #static_env{role = Role, + protocol_cb = Connection}, + ssl_options = #{log_level := LogLevel}} = State) when StateName =/= connection -> + log_alert(LogLevel, Role, + Connection:protocol_name(), StateName, + Alert#alert{role = opposite_role(Role)}), + %% Wait for close alert that should follow or handshake timeout + Connection:next_event(StateName, no_record, State); %% Gracefully log and ignore all other warning alerts pre TLS-1.3 handle_alert(#alert{level = ?WARNING} = Alert, StateName, #state{static_env = #static_env{role = Role, protocol_cb = Connection}, connection_env = #connection_env{negotiated_version = Version}, - ssl_options = #{log_level := LogLevel}} = State) when Version < {3,4} -> + ssl_options = #{log_level := LogLevel}} = State) when ?TLS_LT(Version, ?TLS_1_3) -> log_alert(LogLevel, Role, Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), Connection:next_event(StateName, no_record, State); -handle_alert(Alert0, StateName, State) -> +handle_alert(Alert, StateName, State) -> %% In TLS-1.3 all error alerts are fatal not matter of legacy level - handle_alert(Alert0#alert{level = ?FATAL}, StateName, State). + %% but keep the level for the log so that users looking at what is + %% sent and what is logged are not confused! Or if some one sends + %% user cancel alert in connection which is inappropriate! + handle_fatal_alert(Alert, StateName, State). + +handle_fatal_alert(Alert0, StateName, + #state{static_env = #static_env{role = Role, + socket = Socket, + host = Host, + port = Port, + trackers = Trackers, + transport_cb = Transport, + protocol_cb = Connection}, + connection_env = #connection_env{user_application = {_Mon, Pid}}, + ssl_options = #{log_level := LogLevel}, + start_or_recv_from = From, + session = Session, + socket_options = Opts} = State) -> + invalidate_session(Role, Host, Port, Session), + Alert = Alert0#alert{role = opposite_role(Role)}, + log_alert(LogLevel, Role, Connection:protocol_name(), + StateName, Alert), + Pids = Connection:pids(State), + alert_user(Pids, Transport, Trackers, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection), + {stop, {shutdown, normal}, State}. -handle_trusted_certs_db(#state{ssl_options = - #{cacertfile := <<>>, cacerts := []}}) -> +handle_trusted_certs_db(#state{ssl_options =#{cacerts := []} = Opts}) + when not is_map_key(cacertfile, Opts) -> %% No trusted certs specified ok; handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref, cert_db = CertDb}, - ssl_options = #{cacertfile := <<>>}}) when CertDb =/= undefined -> + ssl_options = Opts}) + when CertDb =/= undefined, not is_map_key(cacertfile, Opts) -> %% Certs provided as DER directly can not be shared %% with other connections and it is safe to delete them when the connection ends. ssl_pkix_db:remove_trusted_certs(Ref, CertDb); @@ -1118,9 +1220,9 @@ handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref, ok end. -maybe_invalidate_session({3, 4},_, _, _, _, _) -> +maybe_invalidate_session(?TLS_1_3,_, _, _, _, _) -> ok; -maybe_invalidate_session({3, N}, Type, Role, Host, Port, Session) when N < 4 -> +maybe_invalidate_session(Version, Type, Role, Host, Port, Session) when ?TLS_LT(Version, ?TLS_1_3) -> maybe_invalidate_session(Type, Role, Host, Port, Session). maybe_invalidate_session({false, first}, server = Role, Host, Port, Session) -> @@ -1128,6 +1230,9 @@ maybe_invalidate_session({false, first}, server = Role, Host, Port, Session) -> maybe_invalidate_session(_, _, _, _, _) -> ok. +terminate({shutdown, ktls}, connection, State) -> + %% Socket shall not be closed as it should be returned to user + handle_trusted_certs_db(State); terminate({shutdown, downgrade}, downgrade, State) -> %% Socket shall not be closed as it should be returned to user handle_trusted_certs_db(State); @@ -1163,7 +1268,7 @@ terminate(Reason, connection, #state{static_env = #static_env{ handle_trusted_certs_db(State), Alert = terminate_alert(Reason), %% Send the termination ALERT if possible - catch (ok = Connection:send_alert_in_connection(Alert, State)), + catch Connection:send_alert_in_connection(Alert, State), Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, ConnectionStates); terminate(Reason, _StateName, #state{static_env = #static_env{transport_cb = Transport, protocol_cb = Connection, @@ -1179,10 +1284,9 @@ format_status(normal, [_, StateName, State]) -> [{data, [{"State", {StateName, State}}]}]; format_status(terminate, [_, StateName, State]) -> SslOptions = (State#state.ssl_options), - NewOptions = SslOptions#{password => ?SECRET_PRINTOUT, - cert => ?SECRET_PRINTOUT, + NewOptions = SslOptions#{ + certs_keys => ?SECRET_PRINTOUT, cacerts => ?SECRET_PRINTOUT, - key => ?SECRET_PRINTOUT, dh => ?SECRET_PRINTOUT, psk_identity => ?SECRET_PRINTOUT, srp_identity => ?SECRET_PRINTOUT}, @@ -1198,24 +1302,16 @@ format_status(terminate, [_, StateName, State]) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -tls_connection_fsm(#{versions := [{3,4}]}) -> - tls_connection_1_3; -tls_connection_fsm(_) -> - tls_connection. - -dtls_connection_fsm(_) -> - dtls_connection. - next_statem_state([Version], client) -> case ssl:tls_version(Version) of - {3,4} -> + ?TLS_1_3 -> wait_sh; _ -> hello end; next_statem_state([Version], server) -> case ssl:tls_version(Version) of - {3,4} -> + ?TLS_1_3 -> start; _ -> hello @@ -1264,11 +1360,8 @@ is_sni_value(Hostname) -> true end. -is_hostname_recognized(#{sni_fun := undefined, - sni_hosts := SNIHosts}, Hostname) -> - proplists:is_defined(Hostname, SNIHosts); -is_hostname_recognized(_, _) -> - true. +is_hostname_recognized(#{sni_fun := Fun}, Hostname) -> + Fun(Hostname) =:= undefined. handle_sni_hostname(Hostname, #state{static_env = #static_env{role = Role} = InitStatEnv0, @@ -1278,7 +1371,7 @@ handle_sni_hostname(Hostname, NewOptions = update_ssl_options_from_sni(Opts, Hostname), case NewOptions of undefined -> - case maps:get(server_name_indication, Opts) of + case maps:get(server_name_indication, Opts, undefined) of disable when Role == client-> State0; _ -> @@ -1290,7 +1383,7 @@ handle_sni_hostname(Hostname, fileref_db_handle := FileRefHandle, session_cache := CacheHandle, crl_db_info := CRLDbHandle, - cert_key_pairs := CertKeyPairs, + cert_key_alts := CertKeyAlts, dh_params := DHParams}} = ssl_config:init(NewOptions, Role), State0#state{ @@ -1301,30 +1394,21 @@ handle_sni_hostname(Hostname, crl_db = CRLDbHandle, session_cache = CacheHandle }, - connection_env = CEnv#connection_env{cert_key_pairs = CertKeyPairs}, + connection_env = CEnv#connection_env{cert_key_alts = CertKeyAlts}, ssl_options = NewOptions, handshake_env = HsEnv#handshake_env{sni_hostname = Hostname, diffie_hellman_params = DHParams} } end. -update_ssl_options_from_sni(#{sni_fun := SNIFun, - sni_hosts := SNIHosts} = OrigSSLOptions, SNIHostname) -> - SSLOptions = - case SNIFun of - undefined -> - proplists:get_value(SNIHostname, - SNIHosts); - SNIFun -> - SNIFun(SNIHostname) - end, - case SSLOptions of +update_ssl_options_from_sni(#{sni_fun := SNIFun} = OrigSSLOptions, SNIHostname) -> + case SNIFun(SNIHostname) of undefined -> undefined; - _ -> + SSLOptions -> VersionsOpt = proplists:get_value(versions, SSLOptions, []), FallBackOptions = filter_for_versions(VersionsOpt, OrigSSLOptions), - ssl:handle_options(SSLOptions, server, FallBackOptions) + ssl:update_options(SSLOptions, server, FallBackOptions) end. filter_for_versions([], OrigSSLOptions) -> @@ -1796,9 +1880,11 @@ send_user(Pid, Msg) -> Pid ! Msg, ok. -alert_user(Pids, Transport, Trackers, Socket, connection, Opts, Pid, From, Alert, Role, StateName, Connection) -> +alert_user(Pids, Transport, Trackers, Socket, _, Opts, Pid, From, Alert, Role, connection = StateName, Connection) -> alert_user(Pids, Transport, Trackers, Socket, Opts#socket_options.active, Pid, From, Alert, Role, StateName, Connection); -alert_user(Pids, Transport, Trackers, Socket,_, _, _, From, Alert, Role, StateName, Connection) -> +alert_user(Pids, Transport, Trackers, Socket, {true, internal}, Opts, Pid, From, Alert, Role, StateName, Connection) -> + alert_user(Pids, Transport, Trackers, Socket, Opts#socket_options.active, Pid, From, Alert, Role, StateName, Connection); +alert_user(Pids, Transport, Trackers, Socket, _, _, _, From, Alert, Role, StateName, Connection) -> alert_user(Pids, Transport, Trackers, Socket, From, Alert, Role, StateName, Connection). alert_user(Pids, Transport, Trackers, Socket, From, Alert, Role, StateName, Connection) -> @@ -1885,7 +1971,8 @@ connection_info(#state{handshake_env = #handshake_env{sni_hostname = SNIHostname security_info(#state{connection_states = ConnectionStates, static_env = #static_env{role = Role}, - ssl_options = #{keep_secrets := KeepSecrets}}) -> + ssl_options = Opts, + protocol_specific = ProtocolSpecific}) -> ReadState = ssl_record:current_connection_state(ConnectionStates, read), #{security_parameters := #security_parameters{client_random = ClientRand, @@ -1895,14 +1982,18 @@ security_info(#state{connection_states = ConnectionStates, client_early_data_secret = ServerEarlyData }} = ReadState, BaseSecurityInfo = [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}], + + KeepSecrets = maps:get(keep_secrets, Opts, false), if KeepSecrets =/= true -> BaseSecurityInfo; true -> #{security_parameters := - #security_parameters{application_traffic_secret = AppTrafSecretWrite, - client_early_data_secret = ClientEarlyData - }} = + #security_parameters{ + application_traffic_secret = AppTrafSecretWrite0, + client_early_data_secret = ClientEarlyData}} = ssl_record:current_connection_state(ConnectionStates, write), + Sender = maps:get(sender, ProtocolSpecific, undefined), + AppTrafSecretWrite = {Sender, AppTrafSecretWrite0}, if Role == server -> if ServerEarlyData =/= undefined -> [{server_traffic_secret_0, AppTrafSecretWrite}, @@ -1962,6 +2053,8 @@ get_socket_opts(Connection, Transport, Socket, [Tag | Tags], SockOpts, Acc) -> case Connection:getopts(Transport, Socket, [Tag]) of {ok, [Opt]} -> get_socket_opts(Connection, Transport, Socket, Tags, SockOpts, [Opt | Acc]); + {ok, []} -> + get_socket_opts(Connection, Transport, Socket, Tags, SockOpts, Acc); {error, Reason} -> {error, {options, {socket_options, Tag, Reason}}} end; @@ -2094,8 +2187,25 @@ maybe_add_keylog(Info) -> maybe_add_keylog({_, 'tlsv1.3'}, Info) -> try {client_random, ClientRandomBin} = lists:keyfind(client_random, 1, Info), - {client_traffic_secret_0, ClientTrafficSecret0Bin} = lists:keyfind(client_traffic_secret_0, 1, Info), - {server_traffic_secret_0, ServerTrafficSecret0Bin} = lists:keyfind(server_traffic_secret_0, 1, Info), + %% after traffic key update current traffic secret + %% is stored in tls_sender process state + MaybeUpdateTrafficSecret = + fun({Direction, {Sender, TrafficSecret0}}) -> + TrafficSecret = + case call(Sender, get_application_traffic_secret) of + {ok, SenderAppTrafSecretWrite} -> + SenderAppTrafSecretWrite; + _ -> + TrafficSecret0 + end, + {Direction, TrafficSecret}; + (TrafficSecret0) -> + TrafficSecret0 + end, + {client_traffic_secret_0, ClientTrafficSecret0Bin} = + MaybeUpdateTrafficSecret(lists:keyfind(client_traffic_secret_0, 1, Info)), + {server_traffic_secret_0, ServerTrafficSecret0Bin} = + MaybeUpdateTrafficSecret(lists:keyfind(server_traffic_secret_0, 1, Info)), {client_handshake_traffic_secret, ClientHSecretBin} = lists:keyfind(client_handshake_traffic_secret, 1, Info), {server_handshake_traffic_secret, ServerHSecretBin} = lists:keyfind(server_handshake_traffic_secret, 1, Info), {selected_cipher_suite, #{prf := Prf}} = lists:keyfind(selected_cipher_suite, 1, Info), @@ -2143,12 +2253,37 @@ keylog_secret(SecretBin, sha384) -> keylog_secret(SecretBin, sha512) -> io_lib:format("~128.16.0B", [binary:decode_unsigned(SecretBin)]). -maybe_generate_client_shares(#{versions := [Version|_], +maybe_generate_client_shares(#{versions := [?TLS_1_3|_], supported_groups := #supported_groups{ - supported_groups = [Group|_]}}) - when Version =:= {3,4} -> + supported_groups = [Group|_]}}) -> %% Generate only key_share entry for the most preferred group ssl_cipher:generate_client_shares([Group]); maybe_generate_client_shares(_) -> undefined. + +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(api, + {call, {?MODULE, connect, [Connection | _]}}, Stack0) -> + {io_lib:format("Connection = ~w", [Connection]), Stack0}; +handle_trace(rle, + {call, {?MODULE, init, Args = [[Role | _]]}}, Stack0) -> + {io_lib:format("(*~w) Args = ~W", [Role, Args, 3]), [{role, Role} | Stack0]}; +handle_trace(hbn, + {call, {?MODULE, hibernate_after, + [_StateName = connection, State, Actions]}}, + Stack) -> + #state{ssl_options= #{hibernate_after := HibernateAfter}} = State, + {io_lib:format("* * * maybe hibernating in ~w ms * * * Actions = ~W ", + [HibernateAfter, Actions, 10]), Stack}; +handle_trace(hbn, + {return_from, {?MODULE, hibernate_after, 3}, + {Cmd, Arg,_State, Actions}}, + Stack) -> + {io_lib:format("Cmd = ~w Arg = ~w Actions = ~W", [Cmd, Arg, Actions, 10]), Stack}; +handle_trace(hbn, + {call, {?MODULE, handle_common_event, [timeout, hibernate, connection | _]}}, Stack) -> + {io_lib:format("* * * hibernating * * *", []), Stack}. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 94626071939b..dbbf0a44967d 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2022. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -23,6 +23,7 @@ %%---------------------------------------------------------------------- -module(ssl_handshake). +-feature(maybe_expr,enable). -include("ssl_handshake.hrl"). -include("ssl_record.hrl"). @@ -59,7 +60,7 @@ ]). %% Encode --export([encode_handshake/2, encode_hello_extensions/2, encode_extensions/1, encode_extensions/2, +-export([encode_handshake/2, encode_hello_extensions/1, encode_extensions/1, encode_extensions/2, encode_client_protocol_negotiation/2, encode_protocols_advertised_on_server/1]). %% Decode -export([decode_handshake/3, decode_vector/1, decode_hello_extensions/4, decode_extensions/3, @@ -69,13 +70,13 @@ %% Cipher suites handling -export([available_suites/2, available_signature_algs/2, available_signature_algs/3, - cipher_suites/3, prf/6, select_session/9, supported_ecc/1, + cipher_suites/3, prf/6, select_session/9, premaster_secret/2, premaster_secret/3, premaster_secret/4]). %% Extensions handling -export([client_hello_extensions/10, handle_client_hello_extensions/10, %% Returns server hello extensions - handle_server_hello_extensions/10, select_curve/3, select_curve/4, + handle_server_hello_extensions/10, select_curve/2, select_curve/3, select_hashsign/4, select_hashsign/5, select_hashsign_algs/3, empty_extensions/2, add_server_share/3, add_alpn/2, add_selected_version/1, decode_alpn/1, max_frag_enum/1 @@ -84,11 +85,12 @@ -export([get_cert_params/1, select_own_cert/1, server_name/3, - path_validate/9, path_validation/10, validation_fun_and_state/4, path_validation_alert/1]). +%% Tracing +-export([handle_trace/3]). %%==================================================================== %% Create handshake messages %%==================================================================== @@ -337,10 +339,9 @@ next_protocol(SelectedProtocol) -> %% Description: Handles a certificate handshake message %%-------------------------------------------------------------------- certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef, - #{server_name_indication := ServerNameIndication, - partial_chain := PartialChain} = SSlOptions, + #{partial_chain := PartialChain} = SSlOptions, CRLDbHandle, Role, Host, Version, CertExt) -> - ServerName = server_name(ServerNameIndication, Host, Role), + ServerName = server_name(SSlOptions, Host, Role), [PeerCert | _ChainCerts ] = ASN1Certs, try PathsAndAnchors = @@ -358,7 +359,8 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef, error:{_,{error, {asn1, Asn1Reason}}} -> %% ASN-1 decode of certificate somehow failed ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, {failed_to_decode_certificate, Asn1Reason}); - error:OtherReason -> + error:OtherReason:ST -> + ?SSL_LOG(info, internal_error, [{error, OtherReason}, {stacktrace, ST}]), ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {unexpected_error, OtherReason}) end. %%-------------------------------------------------------------------- @@ -390,26 +392,29 @@ verify_signature(_, Msg, {HashAlgo, SignAlgo}, Signature, SignAlgo == rsa_pss_pss -> Options = verify_options(SignAlgo, HashAlgo, PubKeyParams), public_key:verify(Msg, HashAlgo, Signature, PubKey, Options); -verify_signature({3, Minor}, Msg, {HashAlgo, SignAlgo}, Signature, {?rsaEncryption, PubKey, PubKeyParams}) - when Minor >= 3 -> +verify_signature(Version, Msg, {HashAlgo, SignAlgo}, Signature, {?rsaEncryption, PubKey, PubKeyParams}) + when ?TLS_GTE(Version, ?TLS_1_2) -> Options = verify_options(SignAlgo, HashAlgo, PubKeyParams), public_key:verify(Msg, HashAlgo, Signature, PubKey, Options); -verify_signature({3, Minor}, {digest, Digest}, _HashAlgo, Signature, {?rsaEncryption, PubKey, _PubKeyParams}) when Minor =< 2 -> +verify_signature(Version, {digest, Digest}, _HashAlgo, Signature, {?rsaEncryption, PubKey, _PubKeyParams}) + when ?TLS_LTE(Version, ?TLS_1_1) -> case public_key:decrypt_public(Signature, PubKey, [{rsa_pad, rsa_pkcs1_padding}]) of Digest -> true; _ -> false end; -verify_signature({3, 4}, Msg, {_, eddsa}, Signature, {?'id-Ed25519', PubKey, PubKeyParams}) -> +verify_signature(?TLS_1_3, Msg, {_, eddsa}, Signature, {?'id-Ed25519', PubKey, PubKeyParams}) -> public_key:verify(Msg, none, Signature, {PubKey, PubKeyParams}); -verify_signature({3, 4}, Msg, {_, eddsa}, Signature, {?'id-Ed448', PubKey, PubKeyParams}) -> +verify_signature(?TLS_1_3, Msg, {_, eddsa}, Signature, {?'id-Ed448', PubKey, PubKeyParams}) -> public_key:verify(Msg, none, Signature, {PubKey, PubKeyParams}); verify_signature(_, Msg, {HashAlgo, _SignAlg}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) -> public_key:verify(Msg, HashAlgo, Signature, {PublicKey, PublicKeyParams}); -verify_signature({3, Minor}, _Msg, {_HashAlgo, anon}, _Signature, _) when Minor =< 3 -> +verify_signature(Version, _Msg, {_HashAlgo, anon}, _Signature, _) + when ?TLS_1_X(Version), ?TLS_LTE(Version, ?TLS_1_2) -> true; -verify_signature({3, Minor}, Msg, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) when Minor =< 3-> +verify_signature(Version, Msg, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) + when ?TLS_1_X(Version), ?TLS_LTE(Version, ?TLS_1_2) -> public_key:verify(Msg, HashAlgo, Signature, {PublicKey, PublicKeyParams}). %%-------------------------------------------------------------------- @@ -427,7 +432,8 @@ master_secret(Version, #session{master_secret = Mastersecret}, try master_secret(Version, Mastersecret, SecParams, ConnectionStates, Role) catch - exit:_ -> + exit:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, key_calculation_failure) end; @@ -443,7 +449,8 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> ClientRandom, ServerRandom), SecParams, ConnectionStates, Role) catch - exit:_ -> + exit:Reason:ST -> + ?SSL_LOG(info, handshake_error, [{error, Reason}, {stacktrace, ST}]), ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, master_secret_calculation_failure) end. @@ -518,17 +525,13 @@ select_version(RecordCB, ClientVersion, Versions) -> %% Called by TLS 1.2/1.3 Server when "supported_versions" is present %% in ClientHello. %% Input lists are ordered (highest first) -select_supported_version([], _ServerVersions) -> - undefined; -select_supported_version([ClientVersion|T], ServerVersions) -> - case lists:member(ClientVersion, ServerVersions) of - true -> - ClientVersion; - false -> - select_supported_version(T, ServerVersions) +select_supported_version(ClientVersions, ServerVersions) -> + Fn = fun (ClientVersion) -> lists:member(ClientVersion, ServerVersions) end, + case lists:search(Fn, ClientVersions) of + {value, ClientVersion} -> ClientVersion; + false -> undefined end. - %%==================================================================== %% Encode handshake %%==================================================================== @@ -537,14 +540,15 @@ encode_handshake(#next_protocol{selected_protocol = SelectedProtocol}, _Version) PaddingLength = 32 - ((byte_size(SelectedProtocol) + 2) rem 32), {?NEXT_PROTOCOL, <>}; -encode_handshake(#server_hello{server_version = {Major, Minor} = Version, +encode_handshake(#server_hello{server_version = ServerVersion, random = Random, session_id = Session_ID, cipher_suite = CipherSuite, compression_method = Comp_method, extensions = Extensions}, _Version) -> SID_length = byte_size(Session_ID), - ExtensionsBin = encode_hello_extensions(Extensions, Version), + {Major,Minor} = ServerVersion, + ExtensionsBin = encode_hello_extensions(Extensions), {?SERVER_HELLO, <>}; @@ -561,7 +565,7 @@ encode_handshake(#server_key_params{params_bin = Keys, hashsign = HashSign, encode_handshake(#certificate_request{certificate_types = CertTypes, hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSignAlgos}, certificate_authorities = CertAuths}, - {3,3}) -> + ?TLS_1_2) -> HashSigns = << <<(ssl_cipher:signature_scheme(SignatureScheme)):16 >> || SignatureScheme <- HashSignAlgos >>, EncCertAuths = encode_cert_auths(CertAuths), @@ -585,17 +589,15 @@ encode_handshake(#certificate_request{certificate_types = CertTypes, }; encode_handshake(#server_hello_done{}, _Version) -> {?SERVER_HELLO_DONE, <<>>}; -encode_handshake(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) -> - {?CLIENT_KEY_EXCHANGE, encode_client_key(ExchangeKeys, Version)}; +encode_handshake(#client_key_exchange{exchange_keys = ExchangeKeys}, _Version) -> + {?CLIENT_KEY_EXCHANGE, encode_client_key(ExchangeKeys)}; encode_handshake(#certificate_verify{signature = BinSig, hashsign_algorithm = HashSign}, Version) -> EncSig = enc_sign(HashSign, BinSig, Version), {?CERTIFICATE_VERIFY, EncSig}; encode_handshake(#finished{verify_data = VerifyData}, _Version) -> {?FINISHED, VerifyData}. -encode_hello_extensions(_, {3, 0}) -> - <<>>; -encode_hello_extensions(Extensions, _) -> +encode_hello_extensions(Extensions) -> encode_extensions(hello_extensions_list(Extensions), <<>>). encode_extensions(Exts) -> @@ -692,6 +694,15 @@ encode_extensions([#sni{hostname = Hostname} | Rest], Acc) -> ?BYTE(?SNI_NAMETYPE_HOST_NAME), ?UINT16(HostLen), HostnameBin/binary, Acc/binary>>); +encode_extensions([#use_srtp{protection_profiles = Profiles, mki = MKI} | Rest], Acc) -> + ProfilesBin = iolist_to_binary(Profiles), + ProfilesLength = byte_size(ProfilesBin), + MKILength = byte_size(MKI), + ExtLength = ProfilesLength + 2 + MKILength + 1, + encode_extensions(Rest, <>); encode_extensions([#max_frag_enum{enum = MaxFragEnum} | Rest], Acc) -> ExtLength = 1, encode_extensions(Rest, < extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}. encode_cert_auths(Auths) -> - encode_cert_auths(Auths, []). - -encode_cert_auths([], Acc) -> - list_to_binary(lists:reverse(Acc)); -encode_cert_auths([Auth | Auths], Acc) -> - DNEncodedBin = public_key:pkix_encode('Name', Auth, otp), - DNEncodedLen = byte_size(DNEncodedBin), - encode_cert_auths(Auths, [<> | Acc]). + DNEncode = fun (Auth) -> + DNEncodedBin = public_key:pkix_encode('Name', Auth, otp), + DNEncodedLen = byte_size(DNEncodedBin), + <> + end, + list_to_binary(lists:map(DNEncode, Auths)). %%==================================================================== %% Decode handshake @@ -876,7 +885,7 @@ decode_handshake(_Version, ?CERTIFICATE_STATUS, < #server_key_exchange{exchange_keys = Keys}; -decode_handshake({3, 3} = Version, ?CERTIFICATE_REQUEST, +decode_handshake(?TLS_1_2 = Version, ?CERTIFICATE_REQUEST, <>) -> @@ -891,9 +900,8 @@ decode_handshake(_Version, ?CERTIFICATE_REQUEST, certificate_authorities = decode_cert_auths(EncCertAuths, [])}; decode_handshake(_Version, ?SERVER_HELLO_DONE, <<>>) -> #server_hello_done{}; -decode_handshake({Major, Minor}, ?CERTIFICATE_VERIFY,<>) - when Major == 3, Minor >= 3 -> +decode_handshake(?TLS_1_2, ?CERTIFICATE_VERIFY,<>) -> #certificate_verify{hashsign_algorithm = dec_hashsign(HashSign), signature = Signature}; decode_handshake(_Version, ?CERTIFICATE_VERIFY,<>)-> #certificate_verify{signature = Signature}; @@ -983,6 +991,7 @@ decode_suites('2_bytes', Dec) -> decode_suites('3_bytes', Dec) -> from_3bytes(Dec). + %%==================================================================== %% Cipher suite handling %%==================================================================== @@ -996,16 +1005,15 @@ available_suites(ServerCert, UserSuites, Version, undefined, Curve) -> filter_unavailable_ecc_suites(Curve, Suites); available_suites(ServerCert, UserSuites, Version, HashSigns, Curve) -> Suites = available_suites(ServerCert, UserSuites, Version, undefined, Curve), - filter_hashsigns(Suites, [ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- Suites], HashSigns, - Version, []). + filter_hashsigns(Suites, [ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- Suites], HashSigns, Version). available_signature_algs(undefined, _) -> undefined; -available_signature_algs(SupportedHashSigns, Version) when Version >= {3, 3} -> +available_signature_algs(SupportedHashSigns, Version) when ?TLS_GTE(Version, ?TLS_1_2) -> case contains_scheme(SupportedHashSigns) of true -> case Version of - {3,3} -> + ?TLS_1_2 -> #hash_sign_algos{hash_sign_algos = ssl_cipher:signature_schemes_1_2(SupportedHashSigns)}; _ -> #signature_algorithms{signature_scheme_list = SupportedHashSigns} @@ -1017,12 +1025,12 @@ available_signature_algs(_, _) -> undefined. available_signature_algs(undefined, SupportedHashSigns, Version) when - Version >= {3,3} -> + ?TLS_GTE(Version, ?TLS_1_2) -> SupportedHashSigns; available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns0, - Version) when Version >= {3,3} -> + Version) when ?TLS_GTE(Version, ?TLS_1_2) -> SupportedHashSigns = - case (Version == {3,3}) andalso contains_scheme(SupportedHashSigns0) of + case (Version == ?TLS_1_2) andalso contains_scheme(SupportedHashSigns0) of true -> ssl_cipher:signature_schemes_1_2(SupportedHashSigns0); false -> @@ -1033,18 +1041,15 @@ available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, Su available_signature_algs(_, _, _) -> undefined. -contains_scheme([]) -> - false; -contains_scheme([Scheme | _]) when is_atom(Scheme) -> - true; -contains_scheme([_| Rest]) -> - contains_scheme(Rest). +contains_scheme(Schemes) -> + lists:any(fun erlang:is_atom/1, Schemes). cipher_suites(Suites, Renegotiation, true) -> %% TLS_FALLBACK_SCSV should be placed last -RFC7507 cipher_suites(Suites, Renegotiation) ++ [?TLS_FALLBACK_SCSV]; cipher_suites(Suites, Renegotiation, false) -> cipher_suites(Suites, Renegotiation). + cipher_suites(Suites, false) -> [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites]; cipher_suites(Suites, true) -> @@ -1055,10 +1060,12 @@ cipher_suites(Suites, true) -> %% %% Description: use the TLS PRF to generate key material %%-------------------------------------------------------------------- -prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) -> +prf(Version, PRFAlgo, Secret, Label, Seed, WantedLength) + when ?TLS_1_X(Version)-> {ok, tls_v1:prf(PRFAlgo, Secret, Label, Seed, WantedLength)}. -select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, SessIdTracker, Session0, Version, SslOpts, CertKeyPairs) -> +select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, SessIdTracker, Session0, Version, SslOpts, CertKeyAlts) -> + CertKeyPairs = ssl_certificate:available_cert_key_pairs(CertKeyAlts, Version), {SessionId, Resumed} = ssl_session:server_select_session(Version, SessIdTracker, SuggestedSessionId, SslOpts, CertKeyPairs), case Resumed of @@ -1076,7 +1083,7 @@ select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, SessId new_session_parameters(SessionId, #session{ecc = ECCCurve0} = Session, CipherSuites, SslOpts, Version, Compressions, HashSigns, CertKeyPairs) -> Compression = select_compression(Compressions), - {Certs, Key, {ECCCurve, CipherSuite}} = select_cert_key_pair_and_params(CipherSuites, CertKeyPairs, HashSigns, + {Certs, Key, {ECCCurve, CipherSuite}} = server_select_cert_key_pair_and_params(CipherSuites, CertKeyPairs, HashSigns, ECCCurve0, SslOpts, Version), Session#session{session_id = SessionId, ecc = ECCCurve, @@ -1087,57 +1094,67 @@ new_session_parameters(SessionId, #session{ecc = ECCCurve0} = Session, CipherSui %% Possibly support part of "trusted_ca_keys" extension that corresponds to TLS-1.3 certificate_authorities?! -select_cert_key_pair_and_params(CipherSuites, [#{private_key := NoKey, certs := [[]] = NoCerts}], HashSigns, ECCCurve0, +server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := NoKey, certs := [[]] = NoCerts}], HashSigns, ECCCurve0, #{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder}, Version) -> %% This can happen if anonymous cipher suites are enabled Suites = available_suites(undefined, UserSuites, Version, HashSigns, ECCCurve0), CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder), CurveAndSuite = cert_curve(undefined, ECCCurve0, CipherSuite0), {NoCerts, NoKey, CurveAndSuite}; -select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs}], HashSigns, ECCCurve0, +server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs}], HashSigns, ECCCurve0, #{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder}, Version) -> Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0), CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder), CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0), {Certs, Key, CurveAndSuite}; -select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs} | Rest], HashSigns, ECCCurve0, +server_select_cert_key_pair_and_params(CipherSuites, [#{private_key := Key, certs := [Cert | _] = Certs} | Rest], HashSigns, ECCCurve0, #{ciphers := UserSuites, honor_cipher_order := HonorCipherOrder} = Opts, Version) -> Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0), case select_cipher_suite(CipherSuites, Suites, HonorCipherOrder) of no_suite -> - select_cert_key_pair_and_params(CipherSuites, Rest, HashSigns, ECCCurve0, Opts, Version); + server_select_cert_key_pair_and_params(CipherSuites, Rest, HashSigns, ECCCurve0, Opts, Version); CipherSuite0 -> - CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0), - {Certs, Key, CurveAndSuite} + case is_acceptable_cert(Cert, HashSigns, ssl:tls_version(Version)) of + true -> + CurveAndSuite = cert_curve(Cert, ECCCurve0, CipherSuite0), + {Certs, Key, CurveAndSuite}; + false -> + server_select_cert_key_pair_and_params(CipherSuites, Rest, HashSigns, ECCCurve0, Opts, Version) + end end. -supported_ecc({Major, Minor}) when ((Major == 3) and (Minor >= 1)) orelse (Major > 3) -> - Curves = tls_v1:ecc_curves(Minor), - #elliptic_curves{elliptic_curve_list = Curves}; -supported_ecc(_) -> - #elliptic_curves{elliptic_curve_list = []}. +is_acceptable_cert(Cert, HashSigns, Version) + when ?TLS_1_X(Version), + ?TLS_GTE(Version, ?TLS_1_2) -> + {SignAlgo0, Param, _, _, _} = get_cert_params(Cert), + SignAlgo = sign_algo(SignAlgo0, Param), + is_acceptable_hash_sign(SignAlgo, HashSigns); +is_acceptable_cert(_,_,_) -> + %% Not negotiable pre TLS-1.2. So if cert is available for version it is acceptable + true. premaster_secret(OtherPublicDhKey, MyPrivateKey, #'DHParameter'{} = Params) -> - try - public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params) - catch - error:computation_failed -> + try + public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params) + catch + error:Reason:ST -> + ?SSL_LOG(debug, crypto_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) - end; + end; premaster_secret(PublicDhKey, PrivateDhKey, #server_dh_params{dh_p = Prime, dh_g = Base}) -> - try + try crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]) - catch - error:computation_failed -> + catch + error:Reason:ST -> + ?SSL_LOG(debug, crypto_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end; premaster_secret(#client_srp_public{srp_a = ClientPublicKey}, ServerKey, #srp_user{prime = Prime, verifier = Verifier}) -> - try crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) of - PremasterSecret -> - PremasterSecret + try crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) catch - error:_ -> + error:Reason:ST -> + ?SSL_LOG(debug, crypto_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end; premaster_secret(#server_srp_params{srp_n = Prime, srp_g = Generator, srp_s = Salt, srp_b = Public}, @@ -1145,14 +1162,13 @@ premaster_secret(#server_srp_params{srp_n = Prime, srp_g = Generator, srp_s = Sa case ssl_srp_primes:check_srp_params(Generator, Prime) of ok -> DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]), - try crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of - PremasterSecret -> - PremasterSecret + try crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) catch - error -> + error:Reason:ST -> + ?SSL_LOG(debug, crypto_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end; - _ -> + not_accepted -> throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end; premaster_secret(#client_rsa_psk_identity{ @@ -1198,14 +1214,16 @@ premaster_secret(EncSecret, #'RSAPrivateKey'{} = RSAPrivateKey) -> try public_key:decrypt_private(EncSecret, RSAPrivateKey, [{rsa_pad, rsa_pkcs1_padding}]) catch - _:_ -> + _:Reason:ST -> + ?SSL_LOG(debug, decrypt_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR)) end; premaster_secret(EncSecret, #{algorithm := rsa} = Engine) -> try crypto:private_decrypt(rsa, EncSecret, maps:remove(algorithm, Engine), [{rsa_pad, rsa_pkcs1_padding}]) catch - _:_ -> + _:Reason:ST -> + ?SSL_LOG(debug, decrypt_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR)) end. %%==================================================================== @@ -1221,12 +1239,11 @@ client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renego add_tls12_extensions(_Version, #{alpn_advertised_protocols := AlpnAdvertisedProtocols, - next_protocol_selector := NextProtocolSelector, - server_name_indication := ServerNameIndication, - max_fragment_length := MaxFragmentLength} = SslOpts, + max_fragment_length := MaxFragmentLength} = SslOpts, ConnectionStates, Renegotiation) -> SRP = srp_user(SslOpts), + NextProtocolSelector = maps:get(next_protocol_selector, SslOpts, undefined), #{renegotiation_info => renegotiation_info(tls_record, client, ConnectionStates, Renegotiation), srp => SRP, @@ -1234,12 +1251,13 @@ add_tls12_extensions(_Version, next_protocol_negotiation => encode_client_protocol_negotiation(NextProtocolSelector, Renegotiation), - sni => sni(ServerNameIndication), + sni => sni(SslOpts), + use_srtp => use_srtp_ext(SslOpts), max_frag_enum => max_frag_enum(MaxFragmentLength) }. -add_common_extensions({3,4}, +add_common_extensions(?TLS_1_3, HelloExtensions, _CipherSuites, #{eccs := SupportedECCs, @@ -1276,10 +1294,9 @@ add_common_extensions(Version, signature_algs_cert => signature_algs_cert(SignatureCertSchemes)}. -maybe_add_tls13_extensions({3,4}, +maybe_add_tls13_extensions(?TLS_1_3, HelloExtensions0, - #{versions := SupportedVersions, - certificate_authorities := Bool}, + #{versions := SupportedVersions} = Opts, KeyShare, TicketData, CertDbHandle, CertDbRef) -> HelloExtensions1 = @@ -1287,18 +1304,15 @@ maybe_add_tls13_extensions({3,4}, #client_hello_versions{versions = SupportedVersions}}, HelloExtensions2 = maybe_add_key_share(HelloExtensions1, KeyShare), HelloExtensions = maybe_add_pre_shared_key(HelloExtensions2, TicketData), - maybe_add_certificate_auths(HelloExtensions, CertDbHandle, CertDbRef, Bool); + AddCA = maps:get(certificate_authorities, Opts, false), + maybe_add_certificate_auths(HelloExtensions, CertDbHandle, CertDbRef, AddCA); maybe_add_tls13_extensions(_, HelloExtensions, _, _, _, _,_) -> HelloExtensions. -maybe_add_certificate_status_request( - _Version, #{ocsp_stapling := false}, _OcspNonce, HelloExtensions) -> - HelloExtensions; -maybe_add_certificate_status_request( - _Version, #{ocsp_stapling := true, - ocsp_responder_certs := OcspResponderCerts}, - OcspNonce, HelloExtensions) -> +maybe_add_certificate_status_request(_Version, #{ocsp_stapling := OcspStapling}, + OcspNonce, HelloExtensions) -> + OcspResponderCerts = maps:get(ocsp_responder_certs, OcspStapling), OcspResponderList = get_ocsp_responder_list(OcspResponderCerts), OcspRequestExtns = public_key:ocsp_extensions(OcspNonce), Req = #ocsp_status_request{responder_id_list = OcspResponderList, @@ -1307,16 +1321,13 @@ maybe_add_certificate_status_request( status_type = ?CERTIFICATE_STATUS_TYPE_OCSP, request = Req }, - HelloExtensions#{status_request => CertStatusReqExtn}. + HelloExtensions#{status_request => CertStatusReqExtn}; +maybe_add_certificate_status_request(_Version, _SslOpts, _OcspNonce, + HelloExtensions) -> + HelloExtensions. get_ocsp_responder_list(ResponderCerts) -> - get_ocsp_responder_list(ResponderCerts, []). - -get_ocsp_responder_list([], Acc) -> - Acc; -get_ocsp_responder_list([ResponderCert | T], Acc) -> - get_ocsp_responder_list( - T, [public_key:ocsp_responder_id(ResponderCert) | Acc]). + lists:map(fun public_key:ocsp_responder_id/1, ResponderCerts). %% TODO: Add support for PSK key establishment @@ -1420,7 +1431,7 @@ add_alpn(Extensions, ALPN0) -> Extensions#{alpn => ALPN}. add_selected_version(Extensions) -> - SupportedVersions = #server_hello_selected_version{selected_version = {3,4}}, + SupportedVersions = #server_hello_selected_version{selected_version = ?TLS_1_3}, Extensions#{server_hello_selected_version => SupportedVersions}. kse_remove_private_key(#key_share_entry{ @@ -1451,6 +1462,13 @@ signature_algs_cert(undefined) -> signature_algs_cert(SignatureSchemes) -> #signature_algorithms_cert{signature_scheme_list = SignatureSchemes}. + +use_srtp_ext(#{use_srtp := #{protection_profiles := Profiles, mki := MKI}}) -> + #use_srtp{protection_profiles = Profiles, mki = MKI}; +use_srtp_ext(#{}) -> + undefined. + + handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites, Exts, Version, #{secure_renegotiate := SecureRenegotation, @@ -1477,6 +1495,7 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites, ConnectionStates, Renegotiation), ec_point_formats => server_ecc_extension(Version, maps:get(ec_point_formats, Exts, undefined)), + use_srtp => use_srtp_ext(Opts), max_frag_enum => ServerMaxFragEnum }, @@ -1498,9 +1517,8 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites, handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, Exts, Version, - #{secure_renegotiate := SecureRenegotation, - next_protocol_selector := NextProtoSelector, - ocsp_stapling := Stapling}, + #{secure_renegotiate := SecureRenegotation} = + SslOpts, ConnectionStates0, Renegotiation, IsNew) -> ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, maps:get(renegotiation_info, Exts, undefined), Random, @@ -1523,7 +1541,7 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, ok end, - case handle_ocsp_extension(Stapling, Exts) of + case handle_ocsp_extension(SslOpts, Exts) of #alert{} = Alert -> Alert; OcspState -> @@ -1539,7 +1557,8 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, {ConnectionStates, alpn, undefined, OcspState}; undefined -> NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined), - Protocol = handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation), + NextProtocolSelector = maps:get(next_protocol_selector, SslOpts, undefined), + Protocol = handle_next_protocol(NextProtocolNegotiation, NextProtocolSelector, Renegotiation), {ConnectionStates, npn, Protocol, OcspState}; {error, Reason} -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason); @@ -1550,12 +1569,11 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression, end end. -select_curve(Client, Server, Version) -> - select_curve(Client, Server, Version, false). +select_curve(Client, Server) -> + select_curve(Client, Server, false). select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves}, #elliptic_curves{elliptic_curve_list = ServerCurves}, - _, ServerOrder) -> case ServerOrder of false -> @@ -1563,25 +1581,25 @@ select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves}, true -> select_shared_curve(ServerCurves, ClientCurves) end; -select_curve(undefined, _, {_,Minor}, _) -> +select_curve(undefined, _, _) -> %% Client did not send ECC extension use default curve if %% ECC cipher is negotiated - case tls_v1:ecc_curves(Minor, [secp256r1]) of + case tls_v1:ecc_curves([secp256r1]) of [] -> %% Curve not supported by cryptolib ECC algorithms can not be negotiated no_curve; [CurveOid] -> {namedCurve, CurveOid} end; -select_curve({supported_groups, Groups}, Server,{_, Minor} = Version, HonorServerOrder) -> +select_curve({supported_groups, Groups}, Server, HonorServerOrder) -> %% TLS-1.3 hello but lesser version chosen TLSCommonCurves = [secp256r1,secp384r1,secp521r1], Curves = [tls_v1:enum_to_oid(tls_v1:group_to_enum(Name)) || Name <- Groups, lists:member(Name, TLSCommonCurves)], - case tls_v1:ecc_curves(Minor, Curves) of + case tls_v1:ecc_curves(Curves) of [] -> - select_curve(undefined, Server, Version, HonorServerOrder); + select_curve(undefined, Server, HonorServerOrder); [_|_] = ClientCurves -> - select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves}, Server, Version, HonorServerOrder) + select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves}, Server, HonorServerOrder) end. %%-------------------------------------------------------------------- @@ -1602,13 +1620,13 @@ select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon; %% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have %% negotiated a lower version. select_hashsign({ClientHashSigns, ClientSignatureSchemes}, - Cert, KeyExAlgo, undefined, {3, 3} = Version) -> + Cert, KeyExAlgo, undefined, ?TLS_1_2 = Version) -> select_hashsign({ClientHashSigns, ClientSignatureSchemes}, Cert, KeyExAlgo, tls_v1:default_signature_algs([Version]), Version); select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns}, ClientSignatureSchemes0}, - Cert, KeyExAlgo, SupportedHashSigns, {3, 3}) -> - ClientSignatureSchemes = get_signature_scheme(ClientSignatureSchemes0), + Cert, KeyExAlgo, SupportedHashSigns, ?TLS_1_2) -> + ClientSignatureSchemes = client_signature_schemes(ClientHashSigns, ClientSignatureSchemes0), {SignAlgo0, Param, PublicKeyAlgo0, _, _} = get_cert_params(Cert), SignAlgo = sign_algo(SignAlgo0, Param), PublicKeyAlgo = ssl_certificate:public_key_type(PublicKeyAlgo0), @@ -1629,7 +1647,7 @@ select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns}, %% If no "signature_algorithms_cert" extension is %% present, then the "signature_algorithms" extension also applies to %% signatures appearing in certificates. - case is_supported_sign(SignAlgo, Param, ClientHashSigns, ClientSignatureSchemes) of + case is_supported_sign(SignAlgo, ClientSignatureSchemes) of true -> case (KeyExAlgo == psk) orelse @@ -1639,9 +1657,9 @@ select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns}, (KeyExAlgo == dh_anon) orelse (KeyExAlgo == ecdhe_anon) of true -> - ClientHashSigns; + ClientSignatureSchemes; false -> - do_select_hashsign(ClientHashSigns, PublicKeyAlgo, SupportedHashSigns) + do_select_hashsign(ClientSignatureSchemes, PublicKeyAlgo, SupportedHashSigns) end; false -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm) @@ -1664,13 +1682,12 @@ select_hashsign(#certificate_request{ certificate_types = Types}, Cert, SupportedHashSigns, - {3, 3}) -> + ?TLS_1_2) -> {SignAlgo0, Param, PublicKeyAlgo0, _, _} = get_cert_params(Cert), - SignAlgo = {_, KeyType} = sign_algo(SignAlgo0, Param), + SignAlgo = sign_algo(SignAlgo0, Param), PublicKeyAlgo = ssl_certificate:public_key_type(PublicKeyAlgo0), - SignatureSchemes = [Scheme || Scheme <- HashSigns, is_atom(Scheme), (KeyType == rsa_pss_pss) or (KeyType == rsa)], case is_acceptable_cert_type(PublicKeyAlgo, Types) andalso - is_supported_sign(SignAlgo, Param, HashSigns, SignatureSchemes) of + is_supported_sign(SignAlgo, HashSigns) of true -> do_select_hashsign(HashSigns, PublicKeyAlgo, SupportedHashSigns); false -> @@ -1688,26 +1705,56 @@ select_hashsign(#certificate_request{certificate_types = Types}, Cert, _, Versio ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm) end. - do_select_hashsign(HashSigns, PublicKeyAlgo, SupportedHashSigns) -> - case lists:filter(fun({H, rsa_pss_pss = S} = Algos) when S == PublicKeyAlgo -> - is_acceptable_hash_sign(list_to_existing_atom(atom_to_list(S) ++ "_" ++ atom_to_list(H)), SupportedHashSigns) orelse - is_acceptable_hash_sign(Algos, SupportedHashSigns); - ({H, rsa_pss_rsae = S} = Algos) when PublicKeyAlgo == rsa -> - is_acceptable_hash_sign(list_to_existing_atom(atom_to_list(S) ++ "_" ++ atom_to_list(H)), SupportedHashSigns) orelse - is_acceptable_hash_sign(Algos, SupportedHashSigns); - ({_, S} = Algos) when S == PublicKeyAlgo -> - is_acceptable_hash_sign(Algos, SupportedHashSigns); - (_A) -> - false - end, HashSigns) of + TLS12Scheme = + fun(Scheme) -> + {H, S, _} = ssl_cipher:scheme_to_components(Scheme), + case S of + rsa_pkcs1 when PublicKeyAlgo == rsa -> + is_acceptable_hash_sign({H, rsa}, SupportedHashSigns) %% TLS-1.2 name + orelse is_acceptable_hash_sign(Scheme, SupportedHashSigns); %% TLS-1.3 legacy name + rsa_pss_rsae when PublicKeyAlgo == rsa -> %% Backported + is_acceptable_hash_sign(Scheme, SupportedHashSigns); + rsa_pss_pss when PublicKeyAlgo == rsa_pss_pss -> %% Backported + is_acceptable_hash_sign(Scheme, SupportedHashSigns); + ecdsa when (PublicKeyAlgo == ecdsa) andalso (H == sha) -> + is_acceptable_hash_sign({H, S}, SupportedHashSigns) orelse %% TLS-1.2 name + is_acceptable_hash_sign(Scheme, SupportedHashSigns); %% TLS-1.3 legacy name + _ -> + false + end + end, + + case lists:filter( + fun({H, rsa_pss_pss = S} = Algos) when S == PublicKeyAlgo -> + %% Backported from TLS-1.3, but only TLS-1.2 configured + is_acceptable_hash_sign(list_to_existing_atom(atom_to_list(S) ++ "_" ++ atom_to_list(H)), + SupportedHashSigns) orelse + is_acceptable_hash_sign(Algos, SupportedHashSigns); + ({H, rsa_pss_rsae = S} = Algos) when PublicKeyAlgo == rsa -> + %% Backported from TLS-1.3, but only TLS-1.2 configured + is_acceptable_hash_sign(list_to_existing_atom(atom_to_list(S) ++ "_" ++ atom_to_list(H)), + SupportedHashSigns) orelse + is_acceptable_hash_sign(Algos, SupportedHashSigns); + ({_, S} = Algos) when S == PublicKeyAlgo -> + is_acceptable_hash_sign(Algos, SupportedHashSigns); + %% Backported or legacy schemes from TLS-1.3 (TLS-1.2 negotiated when TLS-1.3 supported) + (Scheme) when is_atom(Scheme) -> + TLS12Scheme(Scheme); + (_) -> + false + end, HashSigns) of [] -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm); [HashSign | _] -> - HashSign + case ssl_cipher:scheme_to_components(HashSign) of + {Hash, rsa_pkcs1, _} -> + {Hash, rsa}; + {Hash, Sign, _} -> + {Hash, Sign} + end end. - %% Gets the relevant parameters of a certificate: %% - signature algorithm %% - parameters of the signature algorithm @@ -1827,10 +1874,10 @@ select_own_cert([OwnCert| _]) -> select_own_cert(undefined) -> undefined. -get_signature_scheme(undefined) -> - []; -get_signature_scheme(#signature_algorithms_cert{ - signature_scheme_list = ClientSignatureSchemes}) -> +client_signature_schemes(ClientHashSigns, undefined) -> + ClientHashSigns; +client_signature_schemes(_, #signature_algorithms_cert{ + signature_scheme_list = ClientSignatureSchemes}) -> ClientSignatureSchemes. @@ -1856,9 +1903,9 @@ get_signature_scheme(#signature_algorithms_cert{ %% ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}. %%-------------------------------------------------------------------- -select_hashsign_algs(HashSign, _, {3, 3}) when HashSign =/= undefined -> +select_hashsign_algs(HashSign, _, ?TLS_1_2) when HashSign =/= undefined -> HashSign; -select_hashsign_algs(undefined, ?rsaEncryption, {3,3}) -> +select_hashsign_algs(undefined, ?rsaEncryption, ?TLS_1_2) -> {sha, rsa}; select_hashsign_algs(undefined,?'id-ecPublicKey', _) -> {sha, ecdsa}; @@ -1876,6 +1923,8 @@ extension_value(undefined) -> undefined; extension_value(#sni{hostname = HostName}) -> HostName; +extension_value(#use_srtp{protection_profiles = ProtectionProfiles, mki = MKI}) -> + #{protection_profiles => ProtectionProfiles, mki => MKI}; extension_value(#ec_point_formats{ec_point_format_list = List}) -> List; extension_value(#elliptic_curves{elliptic_curve_list = List}) -> @@ -1915,21 +1964,21 @@ extension_value(#psk_key_exchange_modes{ke_modes = Modes}) -> extension_value(#cookie{cookie = Cookie}) -> Cookie. -handle_ocsp_extension(true = Stapling, Extensions) -> +handle_ocsp_extension(#{ocsp_stapling := _OcspStapling}, Extensions) -> case maps:get(status_request, Extensions, false) of undefined -> %% status_request in server hello is empty - #{ocsp_stapling => Stapling, + #{ocsp_stapling => true, ocsp_expect => staple}; false -> %% status_request is missing (not negotiated) - #{ocsp_stapling => Stapling, + #{ocsp_stapling => true, ocsp_expect => no_staple}; _Else -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, status_request_not_empty) end; -handle_ocsp_extension(false = Stapling, Extensions) -> +handle_ocsp_extension(_SslOpts, Extensions) -> case maps:get(status_request, Extensions, false) of false -> %% status_request is missing (not negotiated) - #{ocsp_stapling => Stapling, + #{ocsp_stapling => false, ocsp_expect => no_staple}; _Else -> %% unsolicited status_request ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_status_request) @@ -1952,7 +2001,7 @@ int_to_bin(I) -> %% The end-entity certificate provided by the client MUST contain a %% key that is compatible with certificate_types. -certificate_types(Version) when Version =< {3,3} -> +certificate_types(Version) when ?TLS_LTE(Version, ?TLS_1_2) -> ECDSA = supported_cert_type_or_empty(ecdsa, ?ECDSA_SIGN), RSA = supported_cert_type_or_empty(rsa, ?RSA_SIGN), DSS = supported_cert_type_or_empty(dss, ?DSS_SIGN), @@ -2029,8 +2078,8 @@ validation_fun_and_state(undefined, VerifyState, CertPath, LogLevel) -> apply_user_fun(Fun, OtpCert, VerifyResult0, UserState0, SslState, CertPath, LogLevel) when (VerifyResult0 == valid) or (VerifyResult0 == valid_peer) -> VerifyResult = maybe_check_hostname(OtpCert, VerifyResult0, SslState), - case Fun(OtpCert, VerifyResult, UserState0) of - {Valid, UserState} when (Valid == valid) or (Valid == valid_peer) -> + case apply_fun(Fun, OtpCert, VerifyResult, UserState0, CertPath) of + {Valid, UserState} when (Valid == valid) orelse (Valid == valid_peer) -> case cert_status_check(OtpCert, SslState, VerifyResult, CertPath, LogLevel) of valid -> {Valid, {SslState, UserState}}; @@ -2040,9 +2089,9 @@ apply_user_fun(Fun, OtpCert, VerifyResult0, UserState0, SslState, CertPath, LogL {fail, _} = Fail -> Fail end; -apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath, _LogLevel) -> - case Fun(OtpCert, ExtensionOrError, UserState0) of - {Valid, UserState} when (Valid == valid) or (Valid == valid_peer)-> +apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, CertPath, _LogLevel) -> + case apply_fun(Fun, OtpCert, ExtensionOrError, UserState0, CertPath) of + {Valid, UserState} when (Valid == valid) orelse (Valid == valid_peer)-> {Valid, {SslState, UserState}}; {fail, _} = Fail -> Fail; @@ -2050,6 +2099,14 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath, {unknown, {SslState, UserState}} end. +apply_fun(Fun, OtpCert, ExtensionOrError, UserState, CertPath) -> + if is_function(Fun, 4) -> + #cert{der=DerCert} = lists:keyfind(OtpCert, #cert.otp, CertPath), + Fun(OtpCert, DerCert, ExtensionOrError, UserState); + is_function(Fun, 3) -> + Fun(OtpCert, ExtensionOrError, UserState) + end. + maybe_check_hostname(OtpCert, valid_peer, SslState) -> case ssl_certificate:validate(OtpCert, valid_peer, SslState) of {valid, _} -> @@ -2074,8 +2131,7 @@ path_validation_alert({bad_cert, unknown_critical_extension}) -> path_validation_alert({bad_cert, {revoked, _}}) -> ?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED); path_validation_alert({bad_cert, {revocation_status_undetermined, Details}}) -> - Alert = ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE), - Alert#alert{reason = Details}; + ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, Details); path_validation_alert({bad_cert, selfsigned_peer}) -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE); path_validation_alert({bad_cert, unknown_ca}) -> @@ -2085,29 +2141,28 @@ path_validation_alert(Reason) -> digitally_signed(Version, Msg, HashAlgo, PrivateKey, SignAlgo) -> - try do_digitally_signed(Version, Msg, HashAlgo, PrivateKey, SignAlgo) of - Signature -> - Signature + try do_digitally_signed(Version, Msg, HashAlgo, PrivateKey, SignAlgo) catch - error:badkey-> + error:Reason:ST -> + ?SSL_LOG(info, sign_error, [{error, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, bad_key(PrivateKey))) end. -do_digitally_signed({3, Minor}, Msg, HashAlgo, {#'RSAPrivateKey'{} = Key, - #'RSASSA-PSS-params'{}}, SignAlgo) when Minor >= 3 -> +do_digitally_signed(Version, Msg, HashAlgo, {#'RSAPrivateKey'{} = Key, + #'RSASSA-PSS-params'{}}, SignAlgo) when ?TLS_GTE(Version, ?TLS_1_2) -> Options = signature_options(SignAlgo, HashAlgo), public_key:sign(Msg, HashAlgo, Key, Options); -do_digitally_signed({3, Minor}, {digest, Digest}, _HashAlgo, #'RSAPrivateKey'{} = Key, rsa) when Minor =< 2 -> +do_digitally_signed(Version, {digest, Digest}, _HashAlgo, #'RSAPrivateKey'{} = Key, rsa) when ?TLS_LTE(Version, ?TLS_1_1) -> public_key:encrypt_private(Digest, Key, [{rsa_pad, rsa_pkcs1_padding}]); -do_digitally_signed({3, Minor}, {digest, Digest}, _, - #{algorithm := rsa} = Engine, rsa) when Minor =< 2-> +do_digitally_signed(Version, {digest, Digest}, _, + #{algorithm := rsa} = Engine, rsa) when ?TLS_LTE(Version, ?TLS_1_1) -> crypto:private_encrypt(rsa, Digest, maps:remove(algorithm, Engine), rsa_pkcs1_padding); do_digitally_signed(_, Msg, HashAlgo, #{algorithm := Alg} = Engine, SignAlgo) -> Options = signature_options(SignAlgo, HashAlgo), crypto:sign(Alg, HashAlgo, Msg, maps:remove(algorithm, Engine), Options); -do_digitally_signed({3, Minor}, {digest, _} = Msg , HashAlgo, Key, _) when Minor =< 2 -> +do_digitally_signed(Version, {digest, _} = Msg , HashAlgo, Key, _) when ?TLS_LTE(Version,?TLS_1_1) -> public_key:sign(Msg, HashAlgo, Key); do_digitally_signed(_, Msg, HashAlgo, Key, SignAlgo) -> Options = signature_options(SignAlgo, HashAlgo), @@ -2144,21 +2199,25 @@ bad_key(#{algorithm := rsa}) -> bad_key(#{algorithm := ecdsa}) -> unacceptable_ecdsa_key. -cert_status_check(_, #{ocsp_state := #{ocsp_stapling := true, - ocsp_expect := stapled}}, _VerifyResult, _, _) -> - valid; %% OCSP staple will now be checked by ssl_certifcate:verify_cert_extensions/2 in ssl_certifcate:validate -cert_status_check(OtpCert, #{ocsp_state := #{ocsp_stapling := false}} = SslState, VerifyResult, CertPath, LogLevel) -> +cert_status_check(_, + #{ocsp_state := #{ocsp_stapling := true, + ocsp_expect := stapled}}, + _VerifyResult, _, _) -> + %% OCSP staple will now be checked by + %% ssl_certificate:verify_cert_extensions/2 in ssl_certificate:validate + valid; +cert_status_check(OtpCert, + #{ocsp_state := #{ocsp_stapling := false}} = SslState, + VerifyResult, CertPath, LogLevel) -> maybe_check_crl(OtpCert, SslState, VerifyResult, CertPath, LogLevel); -cert_status_check(_OtpCert, #{ocsp_state := #{ocsp_stapling := true, - ocsp_expect := undetermined}}, +cert_status_check(_OtpCert, + #{ocsp_state := #{ocsp_stapling := true, + ocsp_expect := undetermined}}, _VerifyResult, _CertPath, _LogLevel) -> {bad_cert, {revocation_status_undetermined, not_stapled}}; -cert_status_check(OtpCert, #{ocsp_state := #{ocsp_stapling := best_effort, %% TODO support this ? - ocsp_expect := undetermined}} = SslState, - VerifyResult, CertPath, LogLevel) -> - maybe_check_crl(OtpCert, SslState, VerifyResult, CertPath, LogLevel); -cert_status_check(_OtpCert, #{ocsp_state := #{ocsp_stapling := true, - ocsp_expect := no_staple}}, +cert_status_check(_OtpCert, + #{ocsp_state := #{ocsp_stapling := true, + ocsp_expect := no_staple}}, _VerifyResult, _CertPath, _LogLevel) -> {bad_cert, {revocation_status_undetermined, not_stapled}}. @@ -2214,12 +2273,12 @@ crl_check_same_issuer(OtpCert, _, Dps, Options) -> dps_and_crls(OtpCert, Callback, CRLDbHandle, ext, LogLevel) -> case public_key:pkix_dist_points(OtpCert) of - [] -> - no_dps; - DistPoints -> - Issuer = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer, - CRLs = distpoints_lookup(DistPoints, Issuer, Callback, CRLDbHandle, LogLevel), - dps_and_crls(DistPoints, CRLs, []) + [] -> + no_dps; + DistPoints -> + Issuer = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer, + CRLs = distpoints_lookup(DistPoints, Issuer, Callback, CRLDbHandle, LogLevel), + [{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} || DP <- DistPoints, CRL <- CRLs] end; dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer, LogLevel) -> @@ -2238,12 +2297,7 @@ dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer, LogLevel) -> end, GenNames), [{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs]. -dps_and_crls([], _, Acc) -> - Acc; -dps_and_crls([DP | Rest], CRLs, Acc) -> - DpCRL = [{DP, {CRL, public_key:der_decode('CertificateList', CRL)}} || CRL <- CRLs], - dps_and_crls(Rest, CRLs, DpCRL ++ Acc). - + distpoints_lookup([],_, _, _, _) -> []; distpoints_lookup([DistPoint | Rest], Issuer, Callback, CRLDbHandle, LogLevel) -> @@ -2272,14 +2326,17 @@ encrypted_premaster_secret(Secret, RSAPublicKey) -> rsa_pkcs1_padding}]), #encrypted_premaster_secret{premaster_secret = PreMasterSecret} catch - _:_-> + _:Reason:ST-> + ?SSL_LOG(debug, encrypt_error, [{reason, Reason}, {stacktrace, ST}]), throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, premaster_encryption_failed)) end. -calc_certificate_verify({3, N}, HashAlgo, _MasterSecret, Handshake) -> - tls_v1:certificate_verify(HashAlgo, N, lists:reverse(Handshake)). -calc_finished({3, N}, Role, PrfAlgo, MasterSecret, Handshake) -> - tls_v1:finished(Role, N, PrfAlgo, MasterSecret, lists:reverse(Handshake)). +-spec calc_certificate_verify(ssl_record:ssl_version(), md5sha | ssl:hash(), _, [binary()]) -> binary(). +calc_certificate_verify(Version, HashAlgo, _MasterSecret, Handshake) when ?TLS_1_X(Version) -> + tls_v1:certificate_verify(HashAlgo, lists:reverse(Handshake)). + +calc_finished(Version, Role, PrfAlgo, MasterSecret, Handshake) when ?TLS_1_X(Version) -> + tls_v1:finished(Role, Version, PrfAlgo, MasterSecret, lists:reverse(Handshake)). master_secret(Version, MasterSecret, #security_parameters{ @@ -2307,11 +2364,12 @@ master_secret(Version, MasterSecret, {MasterSecret, ssl_record:set_pending_cipher_state(ConnStates2, ClientCipherState, ServerCipherState, Role)}. -setup_keys({3,N}, PrfAlgo, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) -> - tls_v1:setup_keys(N, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, +setup_keys(Version, PrfAlgo, MasterSecret, + ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) when ?TLS_1_X(Version)-> + tls_v1:setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, IVS). -calc_master_secret({3,_}, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> +calc_master_secret(Version, PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) + when ?TLS_LT(Version, ?TLS_1_3) -> tls_v1:master_secret(PrfAlgo, PremasterSecret, ClientRandom, ServerRandom). %% Update pending connection states with parameters exchanged via @@ -2435,50 +2493,48 @@ encode_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B} <>. -encode_client_key(#encrypted_premaster_secret{premaster_secret = PKEPMS},{3, 0}) -> - PKEPMS; -encode_client_key(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) -> +encode_client_key(#encrypted_premaster_secret{premaster_secret = PKEPMS}) -> PKEPMSLen = byte_size(PKEPMS), <>; -encode_client_key(#client_diffie_hellman_public{dh_public = DHPublic}, _) -> +encode_client_key(#client_diffie_hellman_public{dh_public = DHPublic}) -> Len = byte_size(DHPublic), <>; -encode_client_key(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) -> +encode_client_key(#client_ec_diffie_hellman_public{dh_public = DHPublic}) -> Len = byte_size(DHPublic), <>; -encode_client_key(#client_psk_identity{identity = undefined}, _) -> +encode_client_key(#client_psk_identity{identity = undefined}) -> Id = <<"psk_identity">>, Len = byte_size(Id), <>; -encode_client_key(#client_psk_identity{identity = Id}, _) -> +encode_client_key(#client_psk_identity{identity = Id}) -> Len = byte_size(Id), <>; -encode_client_key(Identity = #client_dhe_psk_identity{identity = undefined}, Version) -> - encode_client_key(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version); -encode_client_key(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) -> +encode_client_key(Identity = #client_dhe_psk_identity{identity = undefined}) -> + encode_client_key(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}); +encode_client_key(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}) -> Len = byte_size(Id), DHLen = byte_size(DHPublic), <>; -encode_client_key(Identity = #client_ecdhe_psk_identity{identity = undefined}, Version) -> - encode_client_key(Identity#client_ecdhe_psk_identity{identity = <<"psk_identity">>}, Version); -encode_client_key(#client_ecdhe_psk_identity{identity = Id, dh_public = DHPublic}, _) -> +encode_client_key(Identity = #client_ecdhe_psk_identity{identity = undefined}) -> + encode_client_key(Identity#client_ecdhe_psk_identity{identity = <<"psk_identity">>}); +encode_client_key(#client_ecdhe_psk_identity{identity = Id, dh_public = DHPublic}) -> Len = byte_size(Id), DHLen = byte_size(DHPublic), <>; -encode_client_key(Identity = #client_rsa_psk_identity{identity = undefined}, Version) -> - encode_client_key(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version); -encode_client_key(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) -> - EncPMS = encode_client_key(ExchangeKeys, Version), +encode_client_key(Identity = #client_rsa_psk_identity{identity = undefined}) -> + encode_client_key(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}); +encode_client_key(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}) -> + EncPMS = encode_client_key(ExchangeKeys), Len = byte_size(Id), <>; -encode_client_key(#client_srp_public{srp_a = A}, _) -> +encode_client_key(#client_srp_public{srp_a = A}) -> Len = byte_size(A), <>. enc_sign({_, anon}, _Sign, _Version) -> <<>>; -enc_sign({HashAlg, SignAlg}, Signature, _Version = {Major, Minor}) - when Major == 3, Minor >= 3-> +enc_sign({HashAlg, SignAlg}, Signature, Version) + when ?TLS_GTE(Version, ?TLS_1_2)-> SignLen = byte_size(Signature), HashSign = enc_hashsign(HashAlg, SignAlg), <>; @@ -2532,61 +2588,32 @@ encode_alpn(Protocols, _) -> encode_versions(Versions) -> - encode_versions(lists:reverse(Versions), <<>>). -%% -encode_versions([], Acc) -> - Acc; -encode_versions([{M,N}|T], Acc) -> - encode_versions(T, <>). + << <> || {M,N} <- Versions>>. encode_client_shares(ClientShares) -> - encode_client_shares(ClientShares, <<>>). -%% -encode_client_shares([], Acc) -> - Acc; -encode_client_shares([KeyShareEntry0|T], Acc) -> - KeyShareEntry = encode_key_share_entry(KeyShareEntry0), - encode_client_shares(T, <>). + << << (encode_key_share_entry(KeyShareEntry0))/binary >> || KeyShareEntry0 <- ClientShares >>. -encode_key_share_entry(#key_share_entry{ - group = Group, - key_exchange = KeyExchange}) -> +encode_key_share_entry(#key_share_entry{group = Group, + key_exchange = KeyExchange}) -> Len = byte_size(KeyExchange), <>. encode_psk_key_exchange_modes(KEModes) -> - encode_psk_key_exchange_modes(lists:reverse(KEModes), <<>>). -%% -encode_psk_key_exchange_modes([], Acc) -> - Acc; -encode_psk_key_exchange_modes([psk_ke|T], Acc) -> - encode_psk_key_exchange_modes(T, <>); -encode_psk_key_exchange_modes([psk_dhe_ke|T], Acc) -> - encode_psk_key_exchange_modes(T, <>). - + << <> || PskKey <- KEModes>>. +% +choose_psk_key(psk_ke) -> ?PSK_KE; +choose_psk_key(psk_dhe_ke) -> ?PSK_DHE_KE. encode_psk_identities(Identities) -> - encode_psk_identities(Identities, <<>>). -%% -encode_psk_identities([], Acc) -> - Len = byte_size(Acc), - <>; -encode_psk_identities([#psk_identity{ - identity = Identity, - obfuscated_ticket_age = Age}|T], Acc) -> - IdLen = byte_size(Identity), - encode_psk_identities(T, <>). - + Result = << << ?UINT16((byte_size(Identity))), Identity/binary,?UINT32(Age) >> + || #psk_identity{ identity = Identity, obfuscated_ticket_age = Age} <- Identities >>, + Len = byte_size(Result), + <>. encode_psk_binders(Binders) -> - encode_psk_binders(Binders, <<>>). -%% -encode_psk_binders([], Acc) -> - Len = byte_size(Acc), - <>; -encode_psk_binders([Binder|T], Acc) -> - Len = byte_size(Binder), - encode_psk_binders(T, <>). + Result = << << ?BYTE((byte_size(Binder))),Binder/binary >> || Binder <- Binders >>, + Len = byte_size(Result), + <>. hello_extensions_list(HelloExtensions) -> @@ -2670,8 +2697,6 @@ dec_server_key(< throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {unknown_or_malformed_key_exchange, KeyExchange})). -dec_client_key(PKEPMS, ?KEY_EXCHANGE_RSA, {3, 0}) -> - #encrypted_premaster_secret{premaster_secret = PKEPMS}; dec_client_key(<>, ?KEY_EXCHANGE_RSA, _) -> #encrypted_premaster_secret{premaster_secret = PKEPMS}; dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> @@ -2695,10 +2720,6 @@ dec_client_key(<>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN_PSK, _) -> #client_ecdhe_psk_identity{identity = Id, dh_public = DH_Y}; -dec_client_key(<>, - ?KEY_EXCHANGE_RSA_PSK, {3, 0}) -> - #client_rsa_psk_identity{identity = Id, - exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}}; dec_client_key(<>, ?KEY_EXCHANGE_RSA_PSK, _) -> #client_rsa_psk_identity{identity = Id, @@ -2712,27 +2733,27 @@ dec_server_key_params(Len, Keys, Version) -> dec_server_key_signature(Params, Signature, Version). dec_server_key_signature(Params, <>, {Major, Minor}) - when Major == 3, Minor >= 3 -> + ?UINT16(0)>>, Version) + when ?TLS_GTE(Version, ?TLS_1_2) -> <> = <>, Scheme = ssl_cipher:signature_scheme(Scheme0), {Hash, Sign, _} = ssl_cipher:scheme_to_components(Scheme), {Params, {Hash, Sign}, <<>>}; dec_server_key_signature(Params, <>, {Major, Minor}) - when Major == 3, Minor >= 3 -> + ?UINT16(Len), Signature:Len/binary>>, Version) + when ?TLS_GTE(Version, ?TLS_1_2) -> <> = <>, Scheme = ssl_cipher:signature_scheme(Scheme0), {Hash, Sign, _} = ssl_cipher:scheme_to_components(Scheme), {Params, {Hash, Sign}, Signature}; dec_server_key_signature(Params, <>, {Major, Minor}) - when Major == 3, Minor >= 3 -> + ?UINT16(0)>>, Version) + when ?TLS_GTE(Version, ?TLS_1_2) -> HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}, {Params, HashSign, <<>>}; dec_server_key_signature(Params, <>, {Major, Minor}) - when Major == 3, Minor >= 3 -> + ?UINT16(Len), Signature:Len/binary>>, Version) + when ?TLS_GTE(Version, ?TLS_1_2) -> HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)}, {Params, HashSign, Signature}; dec_server_key_signature(Params, <<>>, _) -> @@ -2818,7 +2839,7 @@ decode_extensions(<>, Version, MessageType, Acc) - when Version < {3,3} -> + when ?TLS_LT(Version, ?TLS_1_2) -> SignAlgoListLen = Len - 2, <> = ExtData, HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} || @@ -2828,8 +2849,7 @@ decode_extensions(<>, Version, MessageType, Acc) - when Version =:= {3,3} -> + ExtData:Len/binary, Rest/binary>>, ?TLS_1_2=Version, MessageType, Acc) -> SignSchemeListLen = Len - 2, <> = ExtData, HashSigns = decode_sign_alg(Version, SignSchemeList), @@ -2838,8 +2858,7 @@ decode_extensions(<>, Version, MessageType, Acc) - when Version =:= {3,4} -> + ExtData:Len/binary, Rest/binary>>, ?TLS_1_3=Version, MessageType, Acc) -> SignSchemeListLen = Len - 2, <> = ExtData, SignSchemes = decode_sign_alg(Version, SignSchemeList), @@ -2849,8 +2868,7 @@ decode_extensions(<>, Version, MessageType, Acc) - when Version =:= {3,4} -> + ExtData:Len/binary, Rest/binary>>, ?TLS_1_3=Version, MessageType, Acc) -> SignSchemeListLen = Len - 2, <> = ExtData, %% Ignore unknown signature algorithms @@ -2889,9 +2907,19 @@ decode_extensions(<>, Version, MessageType, Acc) -> + <> = ExtData, + Profiles = [P || <> <= ProfilesBin], + decode_extensions(Rest, Version, MessageType, + Acc#{use_srtp => + #use_srtp{ + protection_profiles = Profiles, + mki = MKI}}); + decode_extensions(<>, Version, MessageType, Acc) - when Version < {3,4} -> + when ?TLS_LT(Version, ?TLS_1_3) -> <> = ExtData, %% Ignore unknown curves Pick = fun(Enum) -> @@ -2909,8 +2937,7 @@ decode_extensions(<>, Version, MessageType, Acc) - when Version =:= {3,4} -> + ExtData:Len/binary, Rest/binary>>, ?TLS_1_3=Version, MessageType, Acc) -> <> = ExtData, %% Ignore unknown curves Pick = fun(Enum) -> @@ -2964,8 +2991,7 @@ decode_extensions(< decode_extensions(Rest, Version, MessageType, Acc#{server_hello_selected_version => - #server_hello_selected_version{selected_version = - {3,4}}}); + #server_hello_selected_version{selected_version = ?TLS_1_3}}); decode_extensions(<>, @@ -3084,7 +3110,7 @@ decode_extensions(<> decode_extensions(_, _, _, Acc) -> Acc. -decode_sign_alg({3,3}, SignSchemeList) -> +decode_sign_alg(?TLS_1_2, SignSchemeList) -> %% Ignore unknown signature algorithms Fun = fun(Elem) -> case ssl_cipher:signature_scheme(Elem) of @@ -3096,18 +3122,10 @@ decode_sign_alg({3,3}, SignSchemeList) -> {true, {Hash, Sign}}; {Hash, rsa_pss_pss = Sign, _} -> {true,{Hash, Sign}}; - {sha1, rsa_pkcs1, _} -> - {true,{sha, rsa}}; {Hash, rsa_pkcs1, _} -> {true,{Hash, rsa}}; - {sha1, ecdsa, _} -> - {true,{sha, ecdsa}}; - {sha512,ecdsa, _} -> - {true,{sha512, ecdsa}}; - {sha384,ecdsa, _} -> - {true,{sha384, ecdsa}}; - {sha256,ecdsa, _}-> - {true,{sha256, ecdsa}}; + {Hash, ecdsa, _} -> + {true,{Hash, ecdsa}}; _ -> false end; @@ -3117,7 +3135,7 @@ decode_sign_alg({3,3}, SignSchemeList) -> end, lists:filtermap(Fun, [SignScheme || <> <= SignSchemeList]); -decode_sign_alg({3,4}, SignSchemeList) -> +decode_sign_alg(?TLS_1_3, SignSchemeList) -> %% Ignore unknown signature algorithms Fun = fun(Elem) -> case ssl_cipher:signature_scheme(Elem) of @@ -3131,7 +3149,7 @@ decode_sign_alg({3,4}, SignSchemeList) -> <> <= SignSchemeList]). dec_hashsign(Value) -> - [HashSign] = decode_sign_alg({3,3}, Value), + [HashSign] = decode_sign_alg(?TLS_1_2, Value), HashSign. @@ -3287,14 +3305,11 @@ select_cipher_suite(CipherSuites, Suites, false) -> select_cipher_suite(CipherSuites, Suites, true) -> select_cipher_suite(Suites, CipherSuites). -select_cipher_suite([], _) -> - no_suite; -select_cipher_suite([Suite | ClientSuites], SupportedSuites) -> - case is_member(Suite, SupportedSuites) of - true -> - Suite; - false -> - select_cipher_suite(ClientSuites, SupportedSuites) +select_cipher_suite(ClientSuites, SupportedSuites) -> + F = fun(Suite) -> is_member(Suite, SupportedSuites) end, + case lists:search(F, ClientSuites) of + {value, Suite} -> Suite; + false -> no_suite end. is_member(Suite, SupportedSuites) -> @@ -3329,25 +3344,41 @@ handle_psk_identity(_PSKIdentity, LookupFun) handle_psk_identity(PSKIdentity, {Fun, UserState}) -> Fun(psk, PSKIdentity, UserState). -filter_hashsigns([], [], _, _, Acc) -> - lists:reverse(Acc); -filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, - Acc) when KeyExchange == dhe_ecdsa; - KeyExchange == ecdhe_ecdsa -> - do_filter_hashsigns(ecdsa, Suite, Suites, Algos, HashSigns, Version, Acc); -filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, - Acc) when KeyExchange == rsa; + +filter_hashsigns(Suites, Algos, HashSigns, Version) -> + %% HashSigns, and Version never change + ZipperF = fun (Suite, #{key_exchange := KeyExchange}) -> {Suite, KeyExchange} end, + SuiteAlgoPairs = lists:zipwith(ZipperF, Suites, Algos), + FilterHashSign = fun ({Suite, Kex}) -> + maybe true ?= filter_hashsigns_helper(Kex, HashSigns, Version), + {true, Suite} + end + end, + lists:filtermap(FilterHashSign, SuiteAlgoPairs). + +filter_hashsigns_helper(KeyExchange, HashSigns, _Version) + when KeyExchange == dhe_ecdsa; + KeyExchange == ecdhe_ecdsa -> + lists:keymember(ecdsa, 2, HashSigns); +filter_hashsigns_helper(KeyExchange, HashSigns, ?TLS_1_2) when KeyExchange == rsa; + KeyExchange == dhe_rsa; + KeyExchange == ecdhe_rsa; + KeyExchange == srp_rsa; + KeyExchange == rsa_psk -> + lists:any(fun (H) -> lists:keymember(H, 2, HashSigns) end, + [rsa, rsa_pss_rsae, rsa_pss_pss]); +filter_hashsigns_helper(KeyExchange, HashSigns, _Version) when KeyExchange == rsa; KeyExchange == dhe_rsa; KeyExchange == ecdhe_rsa; KeyExchange == srp_rsa; KeyExchange == rsa_psk -> - do_filter_hashsigns(rsa, Suite, Suites, Algos, HashSigns, Version, Acc); -filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, Acc) when + lists:keymember(rsa, 2, HashSigns); +filter_hashsigns_helper(KeyExchange, HashSigns, _Version) when KeyExchange == dhe_dss; - KeyExchange == srp_dss -> - do_filter_hashsigns(dsa, Suite, Suites, Algos, HashSigns, Version, Acc); -filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, - Acc) when + KeyExchange == srp_dss -> + lists:keymember(dsa, 2, HashSigns); + +filter_hashsigns_helper(KeyExchange, _HashSigns, _Version) when KeyExchange == dh_dss; KeyExchange == dh_rsa; KeyExchange == dh_ecdsa; @@ -3356,9 +3387,8 @@ filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], Has %% Fixed DH certificates MAY be signed with any hash/signature %% algorithm pair appearing in the hash_sign extension. The names %% DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are historical. - filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]); -filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, - Acc) when + true; +filter_hashsigns_helper(KeyExchange, _HashSigns, _Version) when KeyExchange == dh_anon; KeyExchange == ecdh_anon; KeyExchange == srp_anon; @@ -3366,24 +3396,7 @@ filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], Has KeyExchange == dhe_psk; KeyExchange == ecdhe_psk -> %% In this case hashsigns is not used as the kexchange is anonaymous - filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]). - -do_filter_hashsigns(rsa = SignAlgo, Suite, Suites, Algos, HashSigns, {3,3} = Version, Acc) -> - case (lists:keymember(SignAlgo, 2, HashSigns) orelse - lists:keymember(rsa_pss_rsae, 2, HashSigns) orelse - lists:keymember(rsa_pss_pss, 2, HashSigns)) of - true -> - filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]); - false -> - filter_hashsigns(Suites, Algos, HashSigns, Version, Acc) - end; -do_filter_hashsigns(SignAlgo, Suite, Suites, Algos, HashSigns, Version, Acc) -> - case lists:keymember(SignAlgo, 2, HashSigns) of - true -> - filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]); - false -> - filter_hashsigns(Suites, Algos, HashSigns, Version, Acc) - end. + true. filter_unavailable_ecc_suites(no_curve, Suites) -> ECCSuites = ssl_cipher:filter_suites(Suites, #{key_exchange_filters => [fun(ecdh_ecdsa) -> true; @@ -3455,10 +3468,9 @@ handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, SslOpts)- handle_next_protocol_on_server(undefined, _Renegotiation, _SslOpts) -> undefined; - handle_next_protocol_on_server(#next_protocol_negotiation{extension_data = <<>>}, - false, #{next_protocols_advertised := Protocols}) -> - Protocols; + false, SslOpts) -> + maps:get(next_protocols_advertised, SslOpts, undefined); handle_next_protocol_on_server(_Hello, _Renegotiation, _SSLOpts) -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension). @@ -3487,25 +3499,7 @@ is_acceptable_hash_sign(Algos, SupportedHashSigns) -> is_acceptable_cert_type(Sign, Types) -> lists:member(sign_type(Sign), binary_to_list(Types)). -%% signature_algorithms_cert = undefined -is_supported_sign(SignAlgo, _, HashSigns, []) -> - ssl_cipher:is_supported_sign(SignAlgo, HashSigns); %% {'SignatureAlgorithm',{1,2,840,113549,1,1,11},'NULL'} -is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) -> - Fun = fun (Scheme, Acc) -> - {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme), - S1 = case S0 of - rsa_pkcs1 -> rsa; - S -> S - end, - H1 = case H0 of - sha1 -> sha; - H -> H - end, - Acc orelse (Sign =:= S1 andalso - Hash =:= H1) - end, - lists:foldl(Fun, false, SignatureSchemes); %% TODO: Implement validation for the curve used in the signature %% RFC 3279 - 2.2.3 ECDSA Signature Algorithm %% When the ecdsa-with-SHA1 algorithm identifier appears as the @@ -3516,21 +3510,20 @@ is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) -> %% The elliptic curve parameters in the subjectPublicKeyInfo field of %% the certificate of the issuer SHALL apply to the verification of the %% signature. -is_supported_sign({Hash, Sign}, _Param, _, SignatureSchemes) -> - Fun = fun (Scheme, Acc) -> - {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme), +is_supported_sign({Hash, Sign}, SignatureSchemes) -> + Fun = fun (Scheme) -> + {H, S0, _} = ssl_cipher:scheme_to_components(Scheme), S1 = case S0 of - rsa_pkcs1 -> rsa; - S -> S - end, - H1 = case H0 of - sha1 -> sha; - H -> H - end, - Acc orelse (Sign =:= S1 andalso - Hash =:= H1) + rsa_pkcs1 -> + rsa; + rsa_pss_rsae -> + rsa; + S -> + S + end, + (Sign =:= S1) andalso (Hash =:= H) end, - lists:foldl(Fun, false, SignatureSchemes). + lists:any(Fun, SignatureSchemes). %% SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= { @@ -3563,10 +3556,13 @@ sign_type(ecdsa) -> server_name(_, _, server) -> undefined; %% Not interesting to check your own name. -server_name(undefined, Host, client) -> - {fallback, Host}; %% Fallback to Host argument to connect -server_name(SNI, _, client) -> - SNI. %% If Server Name Indication is available +server_name(SSLOpts, Host, client) -> + case maps:get(server_name_indication, SSLOpts, undefined) of + undefined -> + {fallback, Host}; %% Fallback to Host argument to connect + SNI -> + SNI %% If Server Name Indication is available + end. client_ecc_extensions(SupportedECCs) -> CryptoSupport = proplists:get_value(public_keys, crypto:supports()), @@ -3598,39 +3594,25 @@ handle_ecc_point_fmt_extension(undefined) -> handle_ecc_point_fmt_extension(_) -> #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}. -advertises_ec_ciphers([]) -> - false; -advertises_ec_ciphers([#{key_exchange := ecdh_ecdsa} | _]) -> - true; -advertises_ec_ciphers([#{key_exchange := ecdhe_ecdsa} | _]) -> - true; -advertises_ec_ciphers([#{key_exchange := ecdh_rsa} | _]) -> - true; -advertises_ec_ciphers([#{key_exchange := ecdhe_rsa} | _]) -> - true; -advertises_ec_ciphers([#{key_exchange := ecdh_anon} | _]) -> - true; -advertises_ec_ciphers([{ecdhe_psk, _,_,_} | _]) -> - true; -advertises_ec_ciphers([_| Rest]) -> - advertises_ec_ciphers(Rest). +advertises_ec_ciphers(ListKex) -> + KeyExchanges = [ecdh_ecdsa, ecdhe_ecdsa, ecdh_rsa, ecdhe_rsa, ecdh_anon], + F = fun (#{key_exchange := Kex}) -> lists:member(Kex, KeyExchanges); + ({ecdhe_psk, _,_,_}) -> true + end, + lists:any(F, ListKex). -select_shared_curve([], _) -> - no_curve; -select_shared_curve([Curve | Rest], Curves) -> - case lists:member(Curve, Curves) of - true -> - {namedCurve, Curve}; - false -> - select_shared_curve(Rest, Curves) +select_shared_curve(SharedCurves, Curves) -> + case lists:search(fun (Curve) -> lists:member(Curve, Curves) end, SharedCurves) of + {value, SharedCurve} -> {namedCurve, SharedCurve}; + false -> no_curve end. -sni(undefined) -> - undefined; -sni(disable) -> - undefined; -sni(Hostname) -> - #sni{hostname = Hostname}. +sni(SslOpts) -> + case maps:get(server_name_indication, SslOpts, undefined) of + undefined -> undefined; + disable -> undefined; + Hostname -> #sni{hostname = Hostname} + end. %% convert max_fragment_length (in bytes) to the RFC 6066 ENUM max_frag_enum(?MAX_FRAGMENT_LENGTH_BYTES_1) -> @@ -3758,14 +3740,14 @@ cert_curve(Cert, ECCCurve0, CipherSuite) -> empty_extensions() -> #{}. -empty_extensions({3,4}, client_hello) -> +empty_extensions(?TLS_1_3, client_hello) -> #{ sni => undefined, %% max_frag_enum => undefined, %% status_request => undefined, elliptic_curves => undefined, signature_algs => undefined, - %% use_srtp => undefined, + use_srtp => undefined, %% heartbeat => undefined, alpn => undefined, %% signed_cert_timestamp => undefined, @@ -3782,8 +3764,8 @@ empty_extensions({3,4}, client_hello) -> %% post_handshake_auth => undefined, signature_algs_cert => undefined }; -empty_extensions({3, 3}, client_hello) -> - Ext = empty_extensions({3,2}, client_hello), +empty_extensions(?TLS_1_2, client_hello) -> + Ext = empty_extensions(?TLS_1_1, client_hello), Ext#{signature_algs => undefined}; empty_extensions(_, client_hello) -> #{renegotiation_info => undefined, @@ -3793,12 +3775,12 @@ empty_extensions(_, client_hello) -> ec_point_formats => undefined, elliptic_curves => undefined, sni => undefined}; -empty_extensions({3,4}, server_hello) -> +empty_extensions(?TLS_1_3, server_hello) -> #{server_hello_selected_version => undefined, key_share => undefined, pre_shared_key => undefined }; -empty_extensions({3,4}, hello_retry_request) -> +empty_extensions(?TLS_1_3, hello_retry_request) -> #{server_hello_selected_version => undefined, key_share => undefined, pre_shared_key => undefined, %% TODO remove! @@ -3856,8 +3838,7 @@ path_validation(TrustedCert, Path, ServerName, Role, CertDbHandle, CertDbRef, CR #{verify_fun := VerifyFun, customize_hostname_check := CustomizeHostnameCheck, crl_check := CrlCheck, - log_level := Level, - depth := Depth} = Opts, + log_level := Level} = Opts, #{cert_ext := CertExt, ocsp_responder_certs := OcspResponderCerts, ocsp_state := OcspState}) -> @@ -3880,7 +3861,7 @@ path_validation(TrustedCert, Path, ServerName, Role, CertDbHandle, CertDbRef, CR ocsp_responder_certs => OcspResponderCerts, ocsp_state => OcspState}, Path, Level), - Options = [{max_path_length, Depth}, + Options = [{max_path_length, maps:get(depth, Opts, ?DEFAULT_DEPTH)}, {verify_fun, ValidationFunAndState}], public_key:pkix_path_validation(TrustedCert, Path, Options). @@ -3889,7 +3870,20 @@ error_to_propagate({error, {bad_cert, root_cert_expired}} = Error, _) -> error_to_propagate(_, Error) -> Error. -path_validation_cb({3,4}) -> +path_validation_cb(?TLS_1_3) -> tls_handshake_1_3; path_validation_cb(_) -> ?MODULE. + +%%%################################################################ +%%%# +%%%# Tracing +%%%# +handle_trace(csp, + {call, {?MODULE, maybe_add_certificate_status_request, + [_Version, SslOpts, + _OcspNonce, _HelloExtensions]}}, + Stack) -> + OcspStapling = maps:get(ocsp_stapling, SslOpts, false), + {io_lib:format("#1 ADD crt status request / OcspStapling option = ~W", + [OcspStapling, 10]), Stack}. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index b375a5322eb1..ada0c774d56a 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2022. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -55,7 +55,6 @@ }). -define(EMPTY_ID, <<>>). - -define(NUM_OF_SESSION_ID_BYTES, 32). % TSL 1.1 & SSL 3 -define(NUM_OF_PREMASTERSECRET_BYTES, 48). -define(DEFAULT_DIFFIE_HELLMAN_GENERATOR, ssl_dh_groups:modp2048_generator()). @@ -84,9 +83,14 @@ -define(CERTIFICATE_VERIFY, 15). -define(CLIENT_KEY_EXCHANGE, 16). -define(FINISHED, 20). - -define(MAX_UNIT24, 8388607). --define(DEFAULT_MAX_HANDSHAKE_SIZE, (256*1024)). + +%% Usually the biggest handshake message will be the message conveying the +%% certificate chain. This size should be sufficient for usual certificate +%% chains, certificates without special extensions have a typical size of +%% 1-2kB. By dividing the old default value by 2 we still have a slightly +%% bigger margin than OpenSSL +-define(DEFAULT_MAX_HANDSHAKE_SIZE, ((256*1024) div 2)). -record(random, { gmt_unix_time, % uint32 @@ -371,6 +375,17 @@ -define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1). -define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% RFC 5764 section 4 Datagram Transport Layer Security (DTLS) Extensions +%% for SRTP (Secure Real-time Transport Protocol) Key Establishment +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(USE_SRTP_EXT, 14). + +-record(use_srtp, { + protection_profiles, + mki + }). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% ECC RFC 4492 Handshake Messages, Section 5 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index a611f237d049..f98be277bfe5 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2022. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -23,7 +23,11 @@ -ifndef(ssl_internal). -define(ssl_internal, true). --include_lib("public_key/include/public_key.hrl"). +-include_lib("kernel/include/logger.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +-define(CLIENT_ROLE, client). +-define(SERVER_ROLE, server). -define(SECRET_PRINTOUT, "***"). @@ -117,110 +121,30 @@ -define(DEFAULT_MAX_EARLY_DATA_SIZE, 16384). -%% This map stores all supported options with default values and -%% list of dependencies: -%% #{
    - 20072021 + 20072023 Ericsson AB. All Rights Reserved. @@ -40,7 +40,27 @@ -

    Base 64 Encoding alphabet, see RFC 4648.

    +

    Base 64 Encoding alphabet, see + RFC 4648.

    +
    +
    + + + +

    Selector for the Base 64 Encoding alphabet used for + encoding and + decoding. + See RFC 4648 + Sections 4 + and 5.

    +
    +
    + + + +

    Customises the behaviour of the encode and decode functions. + Default value if omitted entirely or partially is + #{mode => standard, padding => true}.

    @@ -67,15 +87,62 @@ Decode a base64 encoded string to data. - + -

    Decodes a base64-encoded string to plain ASCII. See - RFC 4648.

    +

    Decodes a base64 string encoded using the standard alphabet according + to RFC 4648 + Section 4 to plain ASCII.

    mime_decode/1 and mime_decode_to_string/1 strip away illegal characters, while decode/1 and decode_to_string/1 only strip away whitespace characters.

    +

    Checks the correct number of = padding characters + at the end of the encoded string.

    +
    + + + + + + + + Decode a base64 encoded string to data. + + + + + +

    Decodes a base64 string encoded using the alphabet indicated by the + mode option to plain ASCII.

    +

    mime_decode/2 and mime_decode_to_string/2 strip away + illegal characters, while decode/2 and + decode_to_string/2 only strip away whitespace characters.

    +

    The mode option can be one of the following:

    + + standard + Default. Decode the given string using the standard base64 alphabet according + to RFC 4648 + Section 4, that is "+" and "/" are representing bytes 62 + and 63 respectively, while "-" and "_" are illegal + characters. + urlsafe + Decode the given string using the alternative "URL and Filename safe" base64 + alphabet according to + RFC 4648 + Section 5, that is "-" and "_" are representing bytes 62 + and 63 respectively, while "+" and "/" are illegal + characters. + +

    The padding option can be one of the following:

    + + true + Default. Checks the correct number of = padding characters + at the end of the encoded string. + false + Accepts an encoded string with missing = padding characters + at the end. +
    @@ -87,10 +154,46 @@ -

    Encodes a plain ASCII string into base64. The result is 33% larger - than the data.

    +

    Encodes a plain ASCII string into base64 using the standard alphabet + according to RFC 4648 + Section 4. The result is 33% larger than the data.

    +

    Always appends correct number of = padding characters + to the encoded string.

    +
    + + + + + + Encode data into base64. + + + + + +

    Encodes a plain ASCII string into base64 using the alphabet indicated by + the mode option. The result is 33% larger than the data.

    +

    The mode option can be one of the following:

    + + standard + Default. Encode the given string using the standard base64 alphabet according + to RFC 4648 + Section 4. + urlsafe + Encode the given string using the alternative "URL and Filename safe" base64 + alphabet according to + RFC 4648 + Section 5. + +

    The padding option can be one of the following:

    + + true + Default. Appends correct number of = padding characters + to the encoded string. + false + Skips appending = padding characters to the encoded string. +
    - diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml index bc550c1494e7..e743741ea89a 100644 --- a/lib/stdlib/doc/src/beam_lib.xml +++ b/lib/stdlib/doc/src/beam_lib.xml @@ -4,7 +4,7 @@
    - 20002021 + 20002022 Ericsson AB. All Rights Reserved. @@ -138,8 +138,11 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
    .erlang.crypt

    beam_lib searches for .erlang.crypt in the current - directory and then the home directory for the current user. If - the file is found and contains a key, beam_lib + directory, then the + user's home directory and then + + filename:basedir(user_config, "erlang"). + If the file is found and contains a key, beam_lib implicitly creates a crypto key fun and registers it.

    File .erlang.crypt is to contain a single list of tuples:

    @@ -459,11 +462,11 @@ CryptoKeyFun(clear) -> term()
    - Remove chunks not needed by the loader from a BEAM file. + Remove chunks not used by the loader from a BEAM file.

    Removes all chunks from a BEAM - file except those needed by the loader. In particular, + file except those used by the loader. In particular, the debug information (chunk debug_info and abstract_code) is removed.

    @@ -471,23 +474,23 @@ CryptoKeyFun(clear) -> term() - Remove chunks not needed by the loader from a BEAM file. + Remove chunks not used by the loader from a BEAM file. -

    Removes all chunks from a BEAM - file except those needed by the loader or passed in. In particular, - the debug information (chunk debug_info and abstract_code) - is removed.

    +

    Removes all chunks from a BEAM file except those used by + the loader or mentioned in AdditionalChunks. In + particular, the debug information (chunk debug_info and + abstract_code) is removed.

    - Removes chunks not needed by the loader from BEAM files. + Removes chunks not used by the loader from BEAM files.

    Removes all chunks except - those needed by the loader from BEAM files. In particular, + those used by the loader from BEAM files. In particular, the debug information (chunk debug_info and abstract_code) is removed. The returned list contains one element for each specified filename, in the same order as in Files.

    @@ -496,24 +499,25 @@ CryptoKeyFun(clear) -> term() - Removes chunks not needed by the loader from BEAM files. + Removes chunks not used by the loader from BEAM files. -

    Removes all chunks except - those needed by the loader or passed in from BEAM files. In particular, - the debug information (chunk debug_info and abstract_code) - is removed. The returned list contains one element for each - specified filename, in the same order as in Files.

    +

    Removes all chunks except those used by the loader or + mentioned in AdditionalChunks. In + particular, the debug information (chunk debug_info and + abstract_code) is removed. The returned list contains + one element for each specified filename, in the same order as + in Files.

    - Remove chunks not needed by the loader from all BEAM files of + Remove chunks not used by the loader from all BEAM files of a release.

    Removes all chunks - except those needed by the loader from the BEAM files of a + except those used by the loader from the BEAM files of a release. Dir is to be the installation root directory. For example, the current OTP release can be stripped with the call @@ -526,12 +530,12 @@ CryptoKeyFun(clear) -> term() Remove chunks not needed by the loader from all BEAM files of a release. -

    Removes all chunks - except those needed by the loader or passed in from the BEAM files of a - release. Dir is to be the installation root - directory. For example, the current OTP release can be - stripped with the call - beam_lib:strip_release(code:root_dir()).

    +

    Removes all chunks except those used by the loader or + mentioned in AdditionalChunks. + Dir is to be the installation + root directory. For example, the current OTP release can be + stripped with the call + beam_lib:strip_release(code:root_dir()).

    diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 220caaaaee82..6f55d6d327f0 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -5,7 +5,7 @@
    2009 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -244,15 +244,23 @@ - Encodes a binary into a hex encoded binary. + + Encodes a binary into a hex encoded binary with specified case -

    Encodes a binary into a hex encoded binary.

    +

    Encodes a binary into a hex encoded binary using the specified case for the hexadecimal digits "a" to "f".

    +

    The default case is uppercase.

    +

    Example:

    -

    Example:

    - - + 1> binary:encode_hex(<<"f">>). -<<"66">> +<<"66">> +2> binary:encode_hex(<<"/">>). +<<"2F">> +3> binary:encode_hex(<<"/">>, lowercase). +<<"2f">> +4> binary:encode_hex(<<"/">>, uppercase). +<<"2F">> +
    diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml index 9d6199904306..343c384cb624 100644 --- a/lib/stdlib/doc/src/c.xml +++ b/lib/stdlib/doc/src/c.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962022 Ericsson AB. All Rights Reserved. @@ -197,6 +197,35 @@ + + + Module help information + + +

    Print the callback documentation for Module

    +
    +
    + + + + Function help information + + + +

    Print the callback documentation for all Module:Callbacks (regardless of arity).

    +
    +
    + + + + Function help information + + + +

    Print the callback documentation for Module:Callback/Arity.

    +
    +
    + Type help information diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml index 213bca365d44..228c0808d3a8 100644 --- a/lib/stdlib/doc/src/calendar.xml +++ b/lib/stdlib/doc/src/calendar.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962022 Ericsson AB. All Rights Reserved. @@ -124,6 +124,13 @@ + + +

    + The native time unit was added to rfc3339_time_unit() + in OTP 25.0.

    +
    +
    @@ -321,11 +328,11 @@ Convert from RFC 3339 timestamp to system time. -

    Converts an RFC 3339 timestamp into system time. The data format of RFC 3339 timestamps is described by - RFC 3339.

    + RFC 3339. + Starting from OTP 25.1, the minutes part of the time zone is optional.

    Valid option:

    {unit, Unit} @@ -378,7 +385,6 @@ Convert from system to RFC 3339 timestamp. -

    Converts a system time into an RFC 3339 timestamp. The data format of RFC 3339 timestamps is described by @@ -401,12 +407,13 @@ {unit, Unit}

    The time unit of Time. The default is second. If some other unit is given - (millisecond, microsecond, or - nanosecond), the formatted string includes a + (millisecond, microsecond, nanosecond, or + native), the formatted string includes a fraction of a second. The number of fractional second digits is three, six, or nine depending on what time unit - is chosen. Notice that trailing zeros are not removed from - the fraction. + is chosen. For native three fractional digits are + included. Notice that trailing zeros are not removed from the + fraction.

    diff --git a/lib/stdlib/doc/src/edlin.xml b/lib/stdlib/doc/src/edlin.xml new file mode 100644 index 000000000000..fbd1c50df87b --- /dev/null +++ b/lib/stdlib/doc/src/edlin.xml @@ -0,0 +1,247 @@ + + + + +
    + + 19962023 + Ericsson AB. 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. + + + + edlin + + + + +
    + edlin + Line and input interpretter for the erlang shell. + +

    This module reads input, handles any escape sequences that have been configured via edlin_key + and outputs action requests. The action requests are handled either by modules group or the user_drv. +

    +
    +
    + Key configuration +

    You can setup a custom key configuration that overrides the default key configuration. + This is done by setting the stdlib application parameter shell_keymap before Erlang is started. + If you want to have the same keymap in all Erlang shells you can do so by putting a + config file in your user's home directory and then set + ERL_FLAGS to load it at startup. + For example: +

    +
    +$ cat $HOME/.erlang_keymap.config
    +[{stdlib,
    +  [{shell_keymap,
    +    #{ normal => #{ "\^[A" => clear } }
    +  }]
    +}].
    +$ ERL_FLAGS="-config $HOME/.erlang_keymap" erl
    +
    +

    The current keymap configuration can be fetched through edlin:keymap(). + If a custom keymap or keymap file is specified, then it will be merged with the default keymap.

    +

    The keymap is a map of maps where the keys in the parent map corresponds to different + editing modes in the shell. The valid modes currently supported are normal and search.

    +

    The keys in the child maps are the escape sequences that are sent from the terminal when a key is + pressed and each value is a valid action as seen below.

    +

    The default atom is used to specify that an action should happen when a key is pressed that does not + have any mapping. Typically used to exit a mode.

    +

    See tty - A Command-Line Interface for more information about the default keymap.

    +
    +
    + Actions +

    The commands below are the built-in action requests for switching input modes on the normal + shell or navigating, or manipulating the line feed. The line feed supports multiple lines. +

    + + + auto_blink + +

    Automatically close the closest matching opening parenthesis.

    +
    + backward_char + +

    Move backward one character.

    +
    + backward_delete_char + +

    Delete the character behind the cursor.

    +
    + backward_delete_word + +

    Delete the word behind the cursor.

    +
    + backward_kill_line + +

    Delete all characters from the cursor to the beginning of the line and save them in the kill buffer.

    +
    + backward_kill_word + +

    Delete the word behind the cursor and save it in the kill buffer.

    +
    + backward_line + +

    Move backward one line.

    +
    + backward_word + +

    Move backward one word.

    +
    + beginning_of_expression + +

    Move to the beginning of the expression.

    +
    + beginning_of_line + +

    Move to the beginning of the line.

    +
    + clear + +

    Clear the screen.

    +
    + clear_line + +

    Clear the current expression.

    +
    + end_of_expression + +

    Move to the end of the expression.

    +
    + end_of_line + +

    Move to the end of the line.

    +
    + forward_char + +

    Move forward one character.

    +
    + forward_delete_char + +

    Delete the character under the cursor.

    +
    + forward_line + +

    Move forward one line.

    +
    + forward_word + +

    Move forward one word.

    +
    + history_down + +

    Move to the next item in the history.

    +
    + history_up + +

    Move to the previous item in the history.

    +
    + kill_line + +

    Delete all characters from the cursor to the end of the line and save them in the kill buffer.

    +
    + kill_word + +

    Delete the word under the cursor and save it in the kill buffer.

    +
    + new_line_finish + +

    Add a newline at the end of the line and try to evaluate the current expression.

    +
    + newline + +

    Add a newline at the cursor position.

    +
    + open_editor + +

    Open the current line in an editor e.g. EDITOR="code -w" opens a buffer in vs code. + Note that you need to pass a flag to the editor so that it signals the shell when you close + the buffer.

    +
    + redraw_line + +

    Redraw the current line.

    +
    + search_cancel + +

    Cancel the current search.

    +
    + search_found + +

    Accept the current search result and submit it.

    +
    + search_quit + +

    Accept the current search result, but edit it before submitting.

    +
    + search + +

    Enter search mode, search the history.

    +
    + search_down + +

    Skip to the next line in the history that matches the current search expression.

    +
    + search_up + +

    Skip to the previous line in the history that matches the current search expression.

    +
    + tab_expand_full + +

    Output all possible tab completions.

    +
    + tab_expand_quit + +

    Go back to normal mode.

    +
    + tab_expand + +

    Autocomplete the current word, or show 5 lines of possible completions.

    +
    + transpose_char + +

    Swap the character behind the cursor with the one in front of it.

    +
    + transpose_word + +

    Swap the word behind the cursor with the one in front of it.

    +
    + yank + +

    Insert the contents of the kill buffer at the cursor position.

    +
    +
    +
    + + + +

    A map of maps for each shell mode containing key, action pairs.

    +
    +
    + + + + Get current keymap for the shell. + + +

    Get the current keymap used in the shell. Each key in the parent map represents a shell mode e.g. normal or search. + Each map associated with the shell modes contains key sequences represented as strings, paired with an action, + which is one of the valid actions mentioned above.

    +
    +
    +
    +
    \ No newline at end of file diff --git a/lib/stdlib/doc/src/edlin_expand.xml b/lib/stdlib/doc/src/edlin_expand.xml new file mode 100644 index 000000000000..d95d0bf0e4e2 --- /dev/null +++ b/lib/stdlib/doc/src/edlin_expand.xml @@ -0,0 +1,117 @@ + + + + +
    + + 19962023 + Ericsson AB. 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. + + + + edlin_expand + + + + +
    + edlin_expand + Shell expansion and formatting of expansion suggestions. + +

    This module provides an expand_fun for the erlang shell + expand/1,2. + It is possible to override this expand_fun + io:setopts/1,2.

    +
    + + + + + Standard expanion function for the erl shell. + +

    The standard expansion function is able to expand strings to + valid erlang terms. This includes module names:

    +
    +1> erla
    +modules
    +erlang:
    +        
    +

    function names:

    +
    +1> is_ato
    +functions
    +is_atom(
    +2> erlang:is_ato
    +functions
    +is_atom(
    +    
    +

    + function types: +

    +
    +1> erlang:is_atom(
    +typespecs
    +erlang:is_atom(Term)
    +any()
    +
    +

    + and automatically add , or closing parenthesis when no other + valid expansion is possible. The expand function also completes: + shell bindings, record names, record fields and map keys. +

    +

    + As seen below, function headers are grouped together if they've got the same + expansion suggestion, in this case all had the same suggestions, that is '}'. + There is also limited support for filtering out function typespecs that that does + not match the types on the terms on the prompt. Only 4 suggestions are shown below + but there exists plenty more typespecs for erlang:system_info. +

    +
    +1> erlang:system_info({allocator, my_allocator
    +typespecs
    +erlang:system_info(wordsize | {wordsize, ...} | {wordsize, ...})
    +erlang:system_info({allocator, ...})
    +erlang:system_info({allocator_sizes, ...})
    +erlang:system_info({cpu_topology, ...})
    +}
    +
    +

    The return type of expand function specifies either a list of Element + tuples or a list of Section maps. The section concept was introduced to enable + more formatting options for the expansion results. For example, the shell expansion has + support to highlight text and hide suggestions. + There are also a {highlight, Text} that highlights all occurances of + Text in the title, and a highlight_all for simplicity which + highlights the whole title, as can be seen above for functions and typespecs.

    + +

    By setting the {hide, result} or {hide, title} options you may hide + suggestions. Sometimes the title isn't useful and just produces text noise, in the example + above the any() result is part of a section with title Types. Hiding results + is currently not in use, but the idea is that a section can be selected in the expand area + and all the other section entries should be collapsed. +

    + +

    Its possible to set a custom separator between the title and the results. This can be + done with {separator, Separator}. + By default its set to be \n, some results display a type_name() :: + followed by all types that define type_name(). +

    + +

    The {ending, Text} ElementOption just appends Text to the Element. +

    +
    +
    +
    +
    diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml index 6cd715c55c51..45c0f241d2c5 100644 --- a/lib/stdlib/doc/src/epp.xml +++ b/lib/stdlib/doc/src/epp.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -131,6 +131,10 @@ attributes inserted during preprocessing, you can do with {source_name, SourceName}. If unset it will default to the name of the opened file.

    +

    Setting {deterministic, Enabled} will + additionally reduce the file name of the implicit -file() + attributes inserted during preprocessing to only the basename + of the path.

    If extra is specified in Options, the return value is {ok, Epp, Extra} instead @@ -138,6 +142,10 @@

    The option location is forwarded to the Erlang token scanner, see erl_scan:tokens/3,4.

    +

    The {compiler_internal,term()} option is forwarded + to the Erlang token scanner, see + + {compiler_internal,term()}.

    @@ -189,6 +197,10 @@

    The option location is forwarded to the Erlang token scanner, see erl_scan:tokens/3,4.

    +

    The {compiler_internal,term()} option is forwarded + to the Erlang token scanner, see + + {compiler_internal,term()}.

    diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml index 41566d9aec5c..45d9a150ea7b 100644 --- a/lib/stdlib/doc/src/erl_eval.xml +++ b/lib/stdlib/doc/src/erl_eval.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962022 Ericsson AB. All Rights Reserved. @@ -273,10 +273,13 @@ Func(Name, Arguments, Bindings) {value,Func} -

    This defines a non-local function handler that is called with:

    - -Func(FuncSpec, Arguments) -

    FuncSpec is the name of the function on the form +

    This defines a non-local function handler. The function + may be called with two arguments:

    + Func(FuncSpec, Arguments) +

    or three arguments:

    + Func(Anno, FuncSpec, Arguments) +

    Anno is the erl_anno:anno() of the node, + FuncSpec is the name of the function on the form {Module,Function} or a fun, and Arguments is a list of the evaluated arguments. The function handler returns the value of the function. To diff --git a/lib/stdlib/doc/src/erl_features.xml b/lib/stdlib/doc/src/erl_features.xml new file mode 100644 index 000000000000..cf85b4ccd6ac --- /dev/null +++ b/lib/stdlib/doc/src/erl_features.xml @@ -0,0 +1,114 @@ + + + + +

    + + 20222022 + Ericsson AB. 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. + + + + erl_features + Cons T Åhs + + 1 + + + 2022-05-02 + B + erl_features.xml +
    + erl_features + Feature support. + +

    This module contains functions for supporting features that can + be enabled/disabled in Erlang. It should be considered as mostly + for internal use, although there are some functions that might be + useful when writing tools. + +

    +
    + + + + + + + + + + + + + + + + + + + + Return all known features. + +

    Return a list of all known features. This list will + include features that have been removed (status + rejected) and features that are no longer configurable + (status permanent).

    +
    +
    + + + + Return all configurable features. + +

    Return a list of all configurable features, that is, features + with status experimental or approved. These are + the features that can be enabled or disabled.

    +
    +
    + + + + Return information about the given feature. + +

    Return a map containing information about the given feature.

    +
    +
    + + + + Return list of currently enabled features. + +

    Return a list of the features that are currently enabled. + Note that the set of enabled is set during startup and can + then not be changed.

    +
    +
    + + + + Return features used by a module or beam file. + +

    Return the list of features enabled when compiling the + module. The module need not be loaded, but is found if it + exists in the loadpath. If not all features used by the + module are enabled in the runtime, loading the module is not + allowed.

    +
    +
    +
    + + diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml index 79b85eb06aaf..7a0506744391 100644 --- a/lib/stdlib/doc/src/erl_pp.xml +++ b/lib/stdlib/doc/src/erl_pp.xml @@ -5,7 +5,7 @@
    1996 - 2021 + 2022 Ericsson AB, All Rights Reserved @@ -45,6 +45,14 @@

    All functions can have an optional argument, which specifies a hook that is called if an attempt is made to print an unknown form.

    + +

    Note that if the functions in this module are used to convert + abstract code back to Erlang source code, the enclosing function + should first be processed by legalize_vars/1 in order + to ensure that the output is semantically equivalent to the + abstract code.

    + @@ -146,6 +154,29 @@ but only for the guard test Guard.

    + + + + Ensure all variable names are valid. + +

    The Erlang compiler will, when expanding records to tuples, + introduce new variables in the abstract representation. As the + expansion is done on the abstract representation, the compiler + can safely name the new variables with names that are not + syntactically valid in Erlang source code (the name starts + with a lowercase letter), thus ensuring the uniqueness of the + new names.

    + +

    The above strategy leads to problems if a user wants to + convert the abstract representation, using the functions of + this module back to Erlang source code. Typically, pattern + variables are output as atoms thus changing the sematics of + the program. To solve this problem legalize_vars/1, + when run on the abstract representation of a function, will + return an equivalent function where all variables will have + syntactically valid names.

    +
    +
    diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml index 4cfad284e7fd..1f0a4b2cb842 100644 --- a/lib/stdlib/doc/src/erl_scan.xml +++ b/lib/stdlib/doc/src/erl_scan.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -70,6 +70,9 @@ + + + @@ -220,9 +223,35 @@ return

    Short for [return_comments, return_white_spaces].

    - text + text

    Include the token text in the token annotation. The - text is the part of the input corresponding to the token.

    + text is the part of the input corresponding to the token. + See also text_fun.

    +
    + {text_fun, text_fun()} +

    A callback function used to determine whether the + full text for the token shall be included in the token + annotation. Arguments of the function are the category of + the token and the full token string. This is only used when + text is not present. + If neither are present the text will not be saved in the + token annotation.

    +
    + + {compiler_internal, term()} + +

    Pass compiler-internal options to the scanner. The + set of internal options understood by the scanner should + be considered experimental and can thus be changed at any time + without prior warning.

    +

    The following options are currently understood:

    + + ssa_checks + +

    Tokenizes source code annotations used for encoding + tests on the BEAM SSA code produced by the compiler.

    +
    +
    diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index 8f4c013145ad..855f38d2ae66 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -48,7 +48,26 @@ A set or ordered_set table can only have one object associated with each key. A bag or duplicate_bag table can have many objects associated with each key.

    - +

    + Insert and lookup times in tables of type set are constant, + regardless of the table size. For table types bag and + duplicate_bag time is proportional to the number of objects with the + same key. Even seemingly unrelated keys may inflict linear search to be + skipped past while looking for the key of interest (due to hash collision). +

    + +

    + For tables of type bag and duplicate_bag, avoid inserting + an extensive amount of objects with the same key. It will hurt insert and + lookup performance as well as real time characteristics of the runtime + environment (hash bucket linear search do not yield). +

    +
    +

    + The ordered_set table type uses a binary search tree. Insert and + lookup times are proportional to the logarithm of the number of objects in + the table. +

    @@ -283,7 +302,7 @@ true - + continuation() @@ -297,17 +316,17 @@ true -

    A match specification, see above.

    +

    A match specification, see Match Specifications.

    - +

    A compiled match specification.

    - + @@ -315,7 +334,7 @@ true new/2.

    - + @@ -339,7 +358,7 @@ true Delete an entire ETS table. -

    Deletes the entire table Tab.

    +

    Deletes the entire table Table.

    @@ -349,7 +368,8 @@ true table.

    Deletes all objects with key Key from table - Tab.

    + Table. This function succeeds even if + no objects with key Key exist.

    @@ -357,7 +377,7 @@ true Delete all objects in an ETS table. -

    Delete all objects in the ETS table Tab. +

    Delete all objects in the ETS table Table. The operation is guaranteed to be atomic and isolated.

    @@ -382,7 +402,7 @@ true

    Reads a file produced by tab2file/2 or tab2file/3 and - creates the corresponding table Tab.

    + creates the corresponding table Table.

    Equivalent to file2tab(Filename, []).

    @@ -394,7 +414,7 @@ true

    Reads a file produced by tab2file/2 or tab2file/3 and creates the - corresponding table Tab.

    + corresponding table Table.

    The only supported option is {verify,boolean()}. If verification is turned on (by specifying {verify,true}), the function uses whatever information is present in the file to @@ -424,7 +444,7 @@ true Return the first key in an ETS table.

    Returns the first key Key in table - Tab. For an ordered_set table, the first + Table. For an ordered_set table, the first key in Erlang term order is returned. For other table types, the first key according to the internal order of the table is returned. If the table is empty, @@ -554,8 +574,8 @@ Error: fun containing local Erlang function calls Change owner of a table.

    Make process Pid the new owner of table - Tab. If successful, message - {'ETS-TRANSFER',Tab,FromPid,GiftData} + Table. If successful, message + {'ETS-TRANSFER',Table,FromPid,GiftData} is sent to the new owner.

    The process Pid must be alive, local, and not already the owner of the table. @@ -580,7 +600,7 @@ Error: fun containing local Erlang function calls Browse an ETS table on a terminal. -

    Browses table Tab on a terminal.

    +

    Browses table Table on a terminal.

    @@ -588,10 +608,10 @@ Error: fun containing local Erlang function calls Return information about an table. -

    Returns information about table Tab as a list of - tuples. If Tab has the correct type +

    Returns information about table Table as a list of + tuples. If Table has the correct type for a table identifier, but does not refer to an existing ETS - table, undefined is returned. If Tab is + table, undefined is returned. If Table is not of the correct type, a badarg exception is raised.

    {compressed, boolean()} @@ -616,7 +636,7 @@ Error: fun containing local Erlang function calls

    The key position.

    - {memory, integer() >= 0 + {memory, integer() >= 0}

    The number of words allocated to the table.

    @@ -637,16 +657,16 @@ Error: fun containing local Erlang function calls

    The pid of the owner of the table.

    - {protection, + {protection, access()}

    The table access rights.

    - {size, integer() >= 0 + {size, integer() >= 0}

    The number of objects inserted in the table.

    - {type, + {type, type()}

    The table type.

    @@ -656,9 +676,9 @@ Error: fun containing local Erlang function calls

    Indicates whether the table uses read_concurrency or not.

    - {write_concurrency, boolean()} + {write_concurrency, WriteConcurrencyAlternative} -

    Indicates whether the table uses write_concurrency.

    +

    Indicates which write_concurrency option the table uses.

    The execution time of this function is affected by @@ -677,9 +697,9 @@ Error: fun containing local Erlang function calls an ETS table.

    Returns the information associated with Item for table - Tab, or returns undefined if Tab + Table, or returns undefined if Table does not refer an existing ETS table. If - Tab is + Table is not of the correct type, or if Item is not one of the allowed values, a badarg exception is raised.

    In addition to the {Item,Value} @@ -769,7 +789,7 @@ Error: fun containing local Erlang function calls Replace all objects of an ETS table. -

    Replaces the existing objects of table Tab with +

    Replaces the existing objects of table Table with objects created by calling the input function InitFun, see below. This function is provided for compatibility with @@ -801,7 +821,7 @@ Error: fun containing local Erlang function calls

    Inserts the object or all of the objects in list ObjectOrObjects into table - Tab.

    + Table.

    If the table type is set and the key of the inserted @@ -813,6 +833,12 @@ Error: fun containing local Erlang function calls inserted object compares equal to the key of any object in the table, the old object is replaced.

    + +

    + If the table type is bag and the object matches + any whole object in the table, the object is not inserted. +

    +

    If the list contains more than one object with matching keys and the table type is set, one is @@ -824,6 +850,27 @@ Error: fun containing local Erlang function calls

    The entire operation is guaranteed to be atomic and isolated, even when a list of objects is inserted.

    + +

    + For bag and duplicate_bag, objects in the list with + identical keys will be inserted in list order (from head to tail). That + is, a subsequent call to lookup(T,Key) + will return them in that inserted order. +

    + +

    + For bag the insertion order of indentical keys described above was + accidentally reverted in OTP 23.0 and later fixed in OTP 25.3. That + is, from OTP 23.0 up until OTP 25.3 the objects in a list are + inserted in reverse order (from tail to head). +

    +

    + For duplicate_bag the same faulty reverse insertion exist + from OTP 23.0 until OTP 25.3. However, it is unpredictable and may + or may not happen. A longer list will increase the probabiliy of the + insertion being done in reverse. +

    +
    @@ -853,7 +900,7 @@ Error: fun containing local Erlang function calls

    Checks if a term represent a valid compiled match specification. - A compiled match specifications is only valid on the Erlang node where + A compiled match specification is only valid on the Erlang node where it was compiled by calling match_spec_compile/1.

    @@ -880,7 +927,7 @@ Error: fun containing local Erlang function calls ordered_set.

    Returns the last key Key according to Erlang - term order in table Tab of type ordered_set. For + term order in table Table of type ordered_set. For other table types, the function is synonymous to first/1. If the table is empty, '$end_of_table' is returned.

    @@ -895,7 +942,7 @@ Error: fun containing local Erlang function calls

    Returns a list of all objects with key Key in - table Tab.

    + table Table.

    For tables of type set, bag, or @@ -918,14 +965,11 @@ Error: fun containing local Erlang function calls element, as there cannot be more than one object with the same key. For tables of type bag or duplicate_bag, the function returns a list of arbitrary length.

    -

    Notice that the time order of object insertions is preserved; +

    Notice that the sequential order of object insertions is preserved; the first object inserted with the specified key is the first - in the resulting list, and so on.

    -

    Insert and lookup times in tables of type set, - bag, and duplicate_bag are constant, regardless - of the table size. For the ordered_set - datatype, time is proportional to the (binary) logarithm of - the number of objects.

    + in the resulting list, and so on. See also the note about + list insertion order. +

    @@ -934,7 +978,7 @@ Error: fun containing local Erlang function calls Return the Pos:th element of all objects with a specified key in an ETS table. -

    For a table Tab of type set or +

    For a table Table of type set or ordered_set, the function returns the Pos:th element of the object with key Key.

    @@ -943,6 +987,8 @@ Error: fun containing local Erlang function calls element of every object with key Key.

    If no object with key Key exists, the function exits with reason badarg.

    +

    If Pos is larger than the size of the tuple, + the function exits with reason badarg.

    The difference between set, bag, and duplicate_bag on one hand, and ordered_set on the other, regarding the fact that ordered_set @@ -952,6 +998,32 @@ Error: fun containing local Erlang function calls + + + Return the Pos:th element of all objects with a + specified key in an ETS table, or Default if there is no such object. + +

    For a table Table of type set or + ordered_set, the function returns the + Pos:th + element of the object with key Key.

    +

    For tables of type bag or duplicate_bag, + the functions returns a list with the Pos:th + element of every object with key Key.

    +

    If no object with key Key exists, the + function returns Default.

    +

    If Pos is larger than the size of + any tuple with a matching key, the function exits with + reason badarg.

    +

    The difference between set, bag, and + duplicate_bag on one hand, and ordered_set on + the other, regarding the fact that ordered_set + view keys as equal when they compare equal + whereas the other table types regard them equal only when + they match, holds for lookup_element/4.

    +
    + + Continues matching objects in an ETS table. @@ -971,7 +1043,7 @@ Error: fun containing local Erlang function calls Match the objects in an ETS table against a pattern. -

    Matches the objects in table Tab against +

    Matches the objects in table Table against pattern Pattern.

    A pattern is a term that can contain:

    @@ -1026,7 +1098,7 @@ Error: fun containing local Erlang function calls ETS table.

    Deletes all objects that match pattern Pattern - from table Tab. For a description of patterns, + from table Table. For a description of patterns, see match/2.

    @@ -1051,7 +1123,7 @@ Error: fun containing local Erlang function calls Match the objects in an ETS table against a pattern. -

    Matches the objects in table Tab against +

    Matches the objects in table Table against pattern Pattern. For a description of patterns, see match/2. The function returns a list of all objects that @@ -1193,8 +1265,8 @@ ets:select(Table, MatchSpec), means that to an ordered_set table, integer() 1 and float() 1.0 are regarded as equal. This also means that the - key used to lookup an element not necessarily - matches the key in the returned elements, if + key used to lookup an element does not necessarily + match the key in the returned elements, if float()'s and integer()'s are mixed in keys of a table.

    @@ -1258,17 +1330,24 @@ ets:select(Table, MatchSpec), when the owner terminates.

    - {write_concurrency,boolean()} + {write_concurrency,WriteConcurrencyAlternative}

    Performance tuning. Defaults to false, in which case an operation that mutates (writes to) the table obtains exclusive access, blocking any concurrent access of the same table until finished. - If set to true, the table is optimized to concurrent + If set to true, the table is optimized for concurrent write access. Different objects of the same table can be mutated (and read) by concurrent processes. This is achieved to some degree at the expense of memory consumption and the performance of sequential access and concurrent reading.

    +

    The auto alternative for the + write_concurrency option is similar to the + true option but automatically adjusts the + synchronization granularity during runtime depending on how the + table is used. This is the recommended + write_concurrency option when using Erlang/OTP 25 + and above as it performs well in most scenarios.

    The write_concurrency option can be combined with the options read_concurrency and @@ -1278,12 +1357,9 @@ ets:select(Table, MatchSpec), concurrent read bursts and large concurrent write bursts are common; for more information, see option - read_concurrency. The decentralized_counters - option is turned on by default for tables of type ordered_set - with the write_concurrency option enabled, and the - decentralized_counters option is turned off by default for - all other table types. - For more information, see the documentation for the + read_concurrency. It is almost always a + good idea to combine the write_concurrency option + with the decentralized_counters option.

    Notice that this option does not change any guarantees about @@ -1291,20 +1367,27 @@ ets:select(Table, MatchSpec), Functions that makes such promises over many objects (like insert/2) gain less (or nothing) from this option.

    -

    The memory consumption inflicted by both write_concurrency - and read_concurrency is a constant overhead per table for - set, bag and duplicate_bag. For - ordered_set the memory overhead depends on the number - of inserted objects and the amount of actual detected - concurrency in runtime. The memory overhead can be especially - large when both options are combined.

    +

    The memory consumption inflicted by both + write_concurrency and read_concurrency is a + constant overhead per table for set, bag and + duplicate_bag when the true alternative for + the write_concurrency option is not used. For + all tables with the auto alternative and ordered_set + tables with true alternative the + memory overhead depends on the amount of actual detected concurrency during + runtime. The memory overhead can be especially large when + both write_concurrency and read_concurrency are combined.

    Prior to stdlib-3.7 (OTP-22.0) write_concurrency had no effect on ordered_set.

    + +

    The auto alternative for the write_concurrency + option is only available in OTP-25.0 and above.

    +
    - {read_concurrency,boolean()} + {read_concurrency,boolean()}

    Performance tuning. Defaults to false. When set to true, the table is optimized for concurrent read @@ -1329,15 +1412,18 @@ ets:select(Table, MatchSpec), read bursts and large concurrent write bursts are common.

    - {decentralized_counters,boolean()} + {decentralized_counters,boolean()}

    - Performance tuning. Defaults to true for tables - of type ordered_set with the - - write_concurrency option enabled, and defaults to - false for all other table types. This option has no effect if - the write_concurrency option is set to false.

    + Performance tuning. Defaults to true for all + tables with the write_concurrency option set + to auto. For + tables of type ordered_set the option also + defaults to true when the write_concurrency option + is set to true. The option defaults to + false for all other configurations. This option + has no effect if the write_concurrency option is + set to false.

    When this option is set to true, the table is optimized for frequent concurrent calls to operations that modify the tables @@ -1361,7 +1447,7 @@ ets:select(Table, MatchSpec),

    - compressed + compressed

    If this option is present, the table data is stored in a more compact format to consume less memory. However, it will make @@ -1378,7 +1464,7 @@ ets:select(Table, MatchSpec), Return the next key in an ETS table.

    Returns the next key Key2, following key - Key1 in table Tab. For table + Key1 in table Table. For table type ordered_set, the next key in Erlang term order is returned. For other table types, the next key according to the internal order of the table is returned. If no @@ -1403,7 +1489,7 @@ ets:select(Table, MatchSpec),

    Returns the previous key Key2, preceding key Key1 according to Erlang term order in table - Tab of type ordered_set. For other + Table of type ordered_set. For other table types, the function is synonymous to next/2. If no previous key exists, '$end_of_table' is returned.

    @@ -1416,7 +1502,7 @@ ets:select(Table, MatchSpec), Rename a named ETS table. -

    Renames the named table Tab to the new name +

    Renames the named table Table to the new name Name. Afterwards, the old name cannot be used to access the table. Renaming an unnamed table has no effect.

    @@ -1488,9 +1574,9 @@ ets:select(ets:repair_continuation(MaybeBroken,MS)). select/3 & select/1.

    A process fixes a table by calling - safe_fixtable(Tab, true). The table remains + safe_fixtable(Table, true). The table remains fixed until the process releases it by calling - safe_fixtable(Tab, false), or until the process + safe_fixtable(Table, false), or until the process terminates.

    If many processes fix a table, the table remains fixed until all processes have released it (or terminated). @@ -1506,21 +1592,21 @@ ets:select(ets:repair_continuation(MaybeBroken,MS)). next/2 is called.

    Example:

    -clean_all_with_value(Tab,X) -> - safe_fixtable(Tab,true), - clean_all_with_value(Tab,X,ets:first(Tab)), - safe_fixtable(Tab,false). +clean_all_with_value(Table,X) -> + safe_fixtable(Table,true), + clean_all_with_value(Table,X,ets:first(Table)), + safe_fixtable(Table,false). -clean_all_with_value(Tab,X,'$end_of_table') -> +clean_all_with_value(Table,X,'$end_of_table') -> true; -clean_all_with_value(Tab,X,Key) -> - case ets:lookup(Tab,Key) of +clean_all_with_value(Table,X,Key) -> + case ets:lookup(Table,Key) of [{Key,X}] -> - ets:delete(Tab,Key); + ets:delete(Table,Key); _ -> true end, - clean_all_with_value(Tab,X,ets:next(Tab,Key)). + clean_all_with_value(Table,X,ets:next(Table,Key)).

    Notice that deleted objects are not freed from a fixed table until it has been released. If a process fixes a table but never releases it, the memory used by the deleted @@ -1528,7 +1614,7 @@ clean_all_with_value(Tab,X,Key) -> the table also degrades significantly.

    To retrieve information about which processes have fixed which tables, use - info(Tab, safe_fixed_monotonic_time). A system with + info(Table, safe_fixed_monotonic_time). A system with many processes fixing tables can need a monitor that sends alarms when tables have been fixed for too long.

    Notice that safe_fixtable/2 is not necessary for table type @@ -1556,7 +1642,7 @@ clean_all_with_value(Tab,X,Key) -> Match the objects in an ETS table against a match specification. -

    Matches the objects in table Tab using a +

    Matches the objects in table Table using a match specification. This is a more general call than match/2 and @@ -1585,23 +1671,23 @@ Result = "Term construct" match variables in a list), so that the following match/2 expression:

    -ets:match(Tab,{'$1','$2','$3'}) +ets:match(Table,{'$1','$2','$3'})

    is exactly equivalent to:

    -ets:select(Tab,[{{'$1','$2','$3'},[],['$$']}]) +ets:select(Table,[{{'$1','$2','$3'},[],['$$']}])

    And that the following match_object/2 call:

    -ets:match_object(Tab,{'$1','$2','$1'}) +ets:match_object(Table,{'$1','$2','$1'})

    is exactly equivalent to

    -ets:select(Tab,[{{'$1','$2','$1'},[],['$_']}]) +ets:select(Table,[{{'$1','$2','$1'},[],['$_']}])

    Composite terms can be constructed in the Result part either by simply writing a list, so that the following code:

    -ets:select(Tab,[{{'$1','$2','$3'},[],['$$']}]) +ets:select(Table,[{{'$1','$2','$3'},[],['$$']}])

    gives the same output as:

    -ets:select(Tab,[{{'$1','$2','$3'},[],[['$1','$2','$3']]}]) +ets:select(Table,[{{'$1','$2','$3'},[],[['$1','$2','$3']]}])

    That is, all the bound variables in the match head as a list. If tuples are to be constructed, one has to write a tuple of arity 1 where the single element in the tuple is the tuple @@ -1609,10 +1695,10 @@ ets:select(Tab,[{{'$1','$2','$3'},[],[['$1','$2','$3']]}]) for a Guard).

    Therefore the following call:

    -ets:select(Tab,[{{'$1','$2','$1'},[],['$_']}]) +ets:select(Table,[{{'$1','$2','$1'},[],['$_']}])

    gives the same output as:

    -ets:select(Tab,[{{'$1','$2','$1'},[],[{{'$1','$2','$3'}}]}]) +ets:select(Table,[{{'$1','$2','$1'},[],[{{'$1','$2','$3'}}]}])

    This syntax is equivalent to the syntax used in the trace patterns (see the @@ -1674,7 +1760,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]> specification and return the number of objects for which the match specification returned true. -

    Matches the objects in table Tab using a +

    Matches the objects in table Table using a match specification. If the match specification returns true for an object, that object considered a match and is counted. For any other result from @@ -1693,7 +1779,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]> specification and delete objects where the match specification returns true. -

    Matches the objects in table Tab using a +

    Matches the objects in table Table using a match specification. If the match specification returns true for an object, that object is removed from the table. For any other result from the match @@ -1715,7 +1801,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]> Match and replace objects atomically in an ETS table -

    Matches the objects in the table Tab using a +

    Matches the objects in the table Table using a match specification. For each matched object, the existing object is replaced with the match specification result.

    @@ -1723,7 +1809,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]> atomic and isolated. The select_replace table traversal as a whole, like all other select functions, does not give such guarantees.

    -

    The match specifiction must be guaranteed to retain the key +

    The match specification must be guaranteed to retain the key of any matched object. If not, select_replace will fail with badarg without updating any objects.

    For the moment, due to performance and semantic constraints, @@ -1833,7 +1919,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), first/next or last/prev are to be used instead.

    Returns all objects in slot I of table - Tab. A table can be traversed by repeatedly + Table. A table can be traversed by repeatedly calling the function, starting with the first slot I=0 and ending when '$end_of_table' is returned. @@ -1853,10 +1939,10 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), Dump an ETS table to a file. -

    Dumps table Tab to file +

    Dumps table Table to file Filename.

    Equivalent to - tab2file(Tab, Filename,[])

    + tab2file(Table, Filename,[])

    @@ -1864,7 +1950,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), Dump an ETS table to a file. -

    Dumps table Tab to file +

    Dumps table Table to file Filename.

    When dumping the table, some information about the table is dumped to a header at the beginning of the dump. This @@ -1911,7 +1997,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), Return a list of all objects in an ETS table. -

    Returns a list of all objects in table Tab.

    +

    Returns a list of all objects in table Table.

    @@ -2005,7 +2091,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])), tables, Dets tables, and lists are also recognized by QLC as sources of data. Calling table/1,2 is the means to make the - ETS table Tab usable to QLC.

    + ETS table Table usable to QLC.

    When there are only simple restrictions on the key position, QLC uses lookup/2 to look up the keys. When @@ -2053,12 +2139,12 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),

    An explicit match specification is here used to traverse the table:

    -9> true = ets:insert(Tab = ets:new(t, []), [{1,a},{2,b},{3,c},{4,d}]),
    +9> true = ets:insert(Table = ets:new(t, []), [{1,a},{2,b},{3,c},{4,d}]),
     MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} end),
    -QH1 = ets:table(Tab, [{traverse, {select, MS}}]).
    +QH1 = ets:table(Table, [{traverse, {select, MS}}]).

    An example with an implicit match specification:

    -10> QH2 = qlc:q([{Y} || {X,Y} <- ets:table(Tab), (X > 1) or (X < 5)]).
    +10> QH2 = qlc:q([{Y} || {X,Y} <- ets:table(Table), (X > 1) or (X < 5)]).

    The latter example is equivalent to the former, which can be verified using function qlc:info/1:

    @@ -2076,7 +2162,7 @@ true
    ETS table.

    Returns and removes a list of all objects with key - Key in table Tab.

    + Key in table Table.

    The specified Key is used to identify the object by either comparing equal the key of an object in an ordered_set table, or matching in other types of @@ -2118,7 +2204,7 @@ true

    Fills an already created/opened Dets table with the objects - in the already opened ETS table named Tab. + in the already opened ETS table named Table. The Dets table is emptied before the objects are inserted.

    @@ -2131,7 +2217,7 @@ true Update a counter object in an ETS table. - + @@ -2144,8 +2230,8 @@ true the object by incrementing an element, and insert the resulting object into the table again. The operation is guaranteed to be atomic and isolated.

    -

    This function destructively update the object with key - Key in table Tab by adding +

    This function destructively updates the object with key + Key in table Table by adding Incr to the element at position Pos. The new counter value is returned. If no position is specified, the element directly @@ -2211,7 +2297,7 @@ true Update the Pos:th element of the object with a specified key in an ETS table. - + @@ -2220,7 +2306,7 @@ true elements within an object, without the trouble of having to look up, update, and write back the entire object.

    This function destructively updates the object with key - Key in table Tab. + Key in table Table. The element at position Pos is given the value Value.

    A list of {Pos,Value} can be diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml index 815eb23931a7..f07d87811029 100644 --- a/lib/stdlib/doc/src/filelib.xml +++ b/lib/stdlib/doc/src/filelib.xml @@ -4,7 +4,7 @@

    - 20032021 + 20032022 Ericsson AB. All Rights Reserved. @@ -107,6 +107,23 @@ + + + Ensure that all parent directories for a target directory exist. + +

    Ensures that all parent directories for the specified path + Path exist, trying to create them if + necessary.

    +

    Unlike ensure_dir/1, this + function will attempt to create all path segments as a + directory, including the last segment.

    +

    Returns ok if all parent directories already exist + or can be created. Returns {error, Reason} if + some parent directory does not exist and cannot be created.

    +
    +
    + Return the size in bytes of a file. @@ -120,7 +137,8 @@ Fold over all files matching a regular expression.

    Folds function Fun over all (regular) files - F in directory Dir that match + F in directory Dir whose basename + (for example, just "baz.erl" in "foo/bar/baz.erl") matches the regular expression RegExp (for a description of the allowed regular expressions, see the re module). diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml index 46e2b2378fff..cb9010ed536e 100644 --- a/lib/stdlib/doc/src/filename.xml +++ b/lib/stdlib/doc/src/filename.xml @@ -136,7 +136,7 @@

    Joins an absolute directory with a relative filename. Similar to join/2, but on platforms with tight restrictions on raw filename length and no support for - symbolic links (read: VxWorks), leading parent directory components + symbolic links, leading parent directory components in Filename are matched against trailing directory components in Dir so they can be removed from the result - minimizing its length.

    @@ -188,7 +188,7 @@ basedir(PathsType, Application, #{}). The options 'author' and 'version' are only used with 'windows' option mode.

    - user_cache + user_cache

    The path location is intended for transient data files on a local machine.

    On Linux: @@ -212,7 +212,7 @@ basedir(PathsType, Application, #{}). 5> filename:basedir(user_cache, "My App", #{author=>"Erlang",version=>"1.2"}). "c:/Users/otptest/AppData/Local/Erlang/My App/1.2/Cache" - user_config + user_config

    The path location is intended for persistent configuration files.

    @@ -232,7 +232,7 @@ basedir(PathsType, Application, #{}). 2> filename:basedir(user_config, "My App", #{author=>"Erlang", version=>"1.2"}). "c:/Users/otptest/AppData/Roaming/Erlang/My App/1.2"
    - user_data + user_data

    The path location is intended for persistent data files.

    @@ -252,7 +252,7 @@ basedir(PathsType, Application, #{}). 9> filename:basedir(user_data, "My App",#{author=>"Erlang",version=>"1.2"}). "c:/Users/otptest/AppData/Local/Erlang/My App/1.2"
    - user_log + user_log

    The path location is intended for transient log files on a local machine.

    On Linux: @@ -269,11 +269,11 @@ basedir(PathsType, Application, #{}). 13> filename:basedir(user_log, "My App",#{author=>"Erlang",version=>"1.2"}). "c:/Users/otptest/AppData/Local/Erlang/My App/1.2/Logs" - site_config

    + site_config

    On Linux: Respects the os environment variable XDG_CONFIG_DIRS.

    -5> filename:basedir(site_data, "my_application", #{os=>linux}).
    +5> filename:basedir(site_config, "my_application", #{os=>linux}).
     ["/usr/local/share/my_application",
      "/usr/share/my_application"]
     6> os:getenv("XDG_CONFIG_DIRS").
    @@ -290,7 +290,7 @@ true
     5> filename:basedir(site_config, "my_application", #{os=>darwin}).
     ["/Library/Application Support/my_application"]
    - site_data

    + site_data

    On Linux: Respects the os environment variable XDG_DATA_DIRS.

    @@ -508,37 +508,6 @@ true
           
         
     
    -    
    -      
    -      Sanitize a relative path to avoid directory traversal attacks.
    -      
    -        

    Sanitizes the relative path by eliminating ".." and "." - components to protect against directory traversal attacks. - Either returns the sanitized path name, or the atom - unsafe if the path is unsafe. - The path is considered unsafe in the following circumstances:

    - -

    The path is not relative.

    -

    A ".." component would climb up above the root of - the relative path.

    -
    - -

    This function is deprecated. Use - filelib:safe_relative_path/2 instead for sanitizing paths.

    -
    -

    Examples:

    -
    -1> filename:safe_relative_path("dir/sub_dir/..").
    -"dir"
    -2> filename:safe_relative_path("dir/..").
    -[]
    -3> filename:safe_relative_path("dir/../..").
    -unsafe
    -4> filename:safe_relative_path("/abs/path").
    -unsafe
    -
    -
    - Split a filename into its path components. diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml index 9aafca90c30f..c1162f0dba47 100644 --- a/lib/stdlib/doc/src/gb_sets.xml +++ b/lib/stdlib/doc/src/gb_sets.xml @@ -4,7 +4,7 @@
    - 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -29,13 +29,21 @@
    gb_sets - General balanced trees. + Sets represented by general balanced trees.

    This module provides ordered sets using Prof. Arne Andersson's General Balanced Trees. Ordered sets can be much more efficient than using ordered lists, for larger sets, but depends on the application.

    +

    The data representing a set as used by this module is to be + regarded as opaque by other modules. In abstract terms, the + representation is a composite type of existing Erlang terms. See + note on data + types. Any code assuming knowledge of the format is + running on thin ice.

    +

    This module considers two elements as different if and only if they do not compare equal (==).

    @@ -60,48 +68,10 @@
    Compatibility -

    The following functions in this module also exist and provides - the same functionality in the - sets(3) and - ordsets(3) - modules. That is, by only changing the module name for each call, - you can try out different set representations.

    - - add_element/2 - - del_element/2 - - filter/2 - - fold/3 - - from_list/1 - - intersection/1 - - intersection/2 - - is_element/2 - - is_empty/1 - - is_set/1 - - is_subset/2 - - new/0 - - size/1 - - subtract/2 - - to_list/1 - - union/1 - - union/2 - - +

    See the Compatibility Section + in the sets(3) module for information about + the compatibility of the different implementations of sets in the + Standard Library.

    @@ -304,8 +274,14 @@ Test for a set. -

    Returns true if Term appears to be a set, - otherwise false.

    +

    Returns true if Term appears to + be a set, otherwise false. This function will return + true for any term that coincides with the + representation of a gb_set, while not really being a + gb_set, thus it might return false positive results. + See also note on data + types.

    diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml index 44682e91e2e5..99333e284fbe 100644 --- a/lib/stdlib/doc/src/gen_event.xml +++ b/lib/stdlib/doc/src/gen_event.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -113,30 +113,129 @@ gen_event:stop -----> Module:terminate/2

    Unless otherwise stated, all functions in this module fail if the specified event manager does not exist or if bad arguments are specified.

    + +

    + For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + Blocking signaling can, for example, cause call timeouts in + gen_event to be significantly delayed. +

    + + + + + + + +

    - A request handle, see send_request/3 + An opaque request identifier. See + send_request/3 for details.

    + + + + +

    + An opaque collection of request identifiers + (request_id()) + where each request identifier can be associated with a label + chosen by the user. For more information see + reqids_new/0. +

    +
    +
    + + + + +

    + Used to set a time limit on how long to wait for a response using + either + receive_response/2, + receive_response/3, + wait_response/2, + or + wait_response/3. + The time unit used is millisecond. Currently valid values: +

    + + 0..4294967295 +

    + Timeout relative to current time in milliseconds. +

    + infinity +

    + Infinite timeout. That is, the operation will never time out. +

    + {abs, Timeout} +

    + An absolute + Erlang monotonic time + timeout in milliseconds. That is, the operation will time out when + erlang:monotonic_time(millisecond) + returns a value larger than or equal to Timeout. Timeout + is not allowed to identify a time further into the future than 4294967295 + milliseconds. Identifying the timeout using an absolute timeout value + is especially handy when you have a deadline for responses corresponding + to a complete collection of requests + (request_id_collection()) +, + since you do not have to recalculate the relative time until the deadline + over and over again. +

    +
    +
    +
    + + + + +

    + A map that describes the gen_event process status. + The keys are: +

    + + state + The internal state of the event handler. + message + The message that caused the event handler to terminate. + reason + The reason that caused the event handler to terminate. + log + + The sys log of the server. + + +

    + New associations may be added into the status map + without prior notice. +

    +
    +
    @@ -207,14 +306,17 @@ gen_event:stop -----> Module:terminate/2

    Adds a new event handler in the same way as add_handler/3, - but also supervises the connection between the event handler + but also supervises the connection by linking the event handler and the calling process.

    If the calling process later terminates with Reason, - the event manager deletes the event handler by calling + the event manager deletes any supervised event handlers by calling - Module:terminate/2 - with {stop,Reason} as argument. + Module:terminate/2, + then calls + + Module:handle_info/2 + for each remaining handler.

    If the event handler is deleted later, the event manager @@ -292,31 +394,41 @@ gen_event:stop -----> Module:terminate/2 unexpected value Term, this function returns {error,{'EXIT',Reason}} or {error,Term}, respectively.

    +

    + When this call fails it + exits + the calling process. + The exit term is on the form + {Reason, Location} where + Location = {gen_event,call,ArgList}. + See + + gen_server:call/3 + + that has a description of relevant + values for the Reason in the exit term. +

    - - check_response(Msg, RequestId) -> Result - Check if a message is a reply from a server. - - Msg = term() - RequestId = request_id() - Result = {reply, Reply} | no_reply | {error, Error} - Reply = Error = term() - + + Check if a message is a response to an asynchronous call request + to a generic event manager.

    - This function is used to check if a previously received - message, for example by receive or - handle_info/2, is a result of a request made with + Check if Msg is a response corresponding + to the request identifier ReqId. The request + must have been made by send_request/3. - If Msg is a reply to the handle RequestId - the result of the request is returned in Reply. - Otherwise returns no_reply and no cleanup is done, and - thus the function shall be invoked repeatedly until a reply - is returned.

    +

    + If Msg is a response corresponding to + ReqId the response is returned; otherwise, + no_reply is returned and no cleanup is done, and + thus the function must be invoked repeatedly until a response + is returned. +

    If the specified event handler is not installed, the function returns {error,bad_module}. If @@ -329,6 +441,74 @@ gen_event:stop -----> Module:terminate/2 + + + Check if a message is a response to an asynchronous call request + to a generic event manager. + +

    + Check if Msg is a response corresponding + to a request identifier saved in ReqIdCollection. + All request identifiers of ReqIdCollection + must correspond to requests that have been made using + send_request/3 or + send_request/5, + and all requests must have been made by the process calling this + function. +

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id + in a request identifier collection, or when sending the request using + send_request/5. +

    +

    + Compared to + check_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by check_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. If Msg + does not correspond to any of the request identifiers in + ReqIdCollection, the atom + no_reply is returned. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + check_response/3, + receive_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to check_response/3, it will always + return no_reply. +

    +
    +
    + delete_handler(EventMgrRef, Handler, Args) -> Result Delete an event handler from a generic event manager. @@ -392,34 +572,29 @@ gen_event:stop -----> Module:terminate/2 does not exist, unless it is specified as Name.

    - + - receive_response(RequestId, Timeout) -> Result - Receive for a reply from a server. - - RequestId = request_id() - Reply = term() - Timeout = timeout() - Result = {reply, Reply} | timeout | {error, Error} - Reply = Error = term() - + + Receive a response to an asynchronous call request + to a generic event manager.

    - This function is used to receive for a reply of a request made with - send_request/3 - to the event manager. This function must be called from the same - process from which send_request/3 - was made. + Receive a response corresponding to the request identifier + ReqId- The request must have been made by + send_request/3 + to the gen_statem process. This function must be called + from the same process from which + send_request/3 + was made.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. - If no reply is received within the specified - time, the function returns timeout. Assuming that the + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the server executes on a node supporting aliases (introduced in - OTP 24) no response will be received after a timeout. Otherwise, - a garbage response might be received at a later time. + OTP 24) the request will also be abandoned. That is, no + response will be received after a timeout. Otherwise, a + stray response might be received at a later time.

    The return value Reply is defined in the return value @@ -436,44 +611,197 @@ gen_event:stop -----> Module:terminate/2

    The difference between - wait_response() - and receive_response() is that receive_response() + wait_response/2 + and receive_response/2 is that receive_response/2 abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + response is ignored, while wait_response/2 does not.

    - send_request(EventMgrRef, Handler, Request) -> RequestId - Send a request to a generic event manager. - - EventMgrRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - Handler = Module | {Module,Id} -  Module = atom() -  Id = term() - Request = term() - RequestId = request_id() - + + Receive a response to an asynchronous call request + to a generic event manager. +

    + Receive a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/3 or + send_request/5, + and all requests must have been made by the process calling this + function. +

    - Sends a request to event handler Handler installed in - event manager EventMgrRef and returns a handle - RequestId. The return value RequestId shall - later be used with - receive_response/2, - wait_response/2, or - check_response/2 in the same process to - fetch the actual result of the request. + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + adding the request id + in a request identifier collection, or when sending the request using + send_request/5. +

    +

    + Compared to + receive_response/2, + the returned result associated with a specific request identifier + will be wrapped in a 3-tuple. The first element of this tuple equals + the value that would have been produced by receive_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. +

    +

    + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) all requests identified by ReqIdCollection + will also be abandoned. That is, no responses will be received + after a timeout. Otherwise, stray responses might be received + at a later time.

    - The call gen_event:wait_response(gen_event:send_request(EventMgrRef,Handler,Request), Timeout) + The difference between receive_response/3 and + wait_response/3 + is that receive_response/3 abandons the requests at timeout + so that potential future responses are ignored, while + wait_response/3 does not. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + receive_response/3, + check_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to receive_response/3, it will always block + until a timeout determined by Timeout is + triggered. +

    +
    +
    + + + + Save a request identifier. + +

    + Saves ReqId and associates a Label + with the request identifier by adding this information to + ReqIdCollection and returning the + resulting request identifier collection. +

    +
    +
    + + + + Create a new empty request identifier collection. + +

    + Returns a new empty request identifier collection. A + request identifier collection can be utilized in order + the handle multiple outstanding requests. +

    +

    + Request identifiers of requests made by + send_request/3 + can be saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    +

    + reqids_size/1 + can be used to determine the amount of request identifiers in a + request identifier collection. +

    +
    +
    + + + + Get size of a request identifier collection. + +

    + Returns the amount of request identifiers saved in + ReqIdCollection. +

    +
    +
    + + + + List a request identifiers. + +

    + Returns a list of {ReqId, Label} + tuples which corresponds to all request identifiers with their + associated labels present in the ReqIdCollection + collection. +

    +
    +
    + + + + Send an asyncronous call request to a generic event manager. + +

    + Sends an asynchronous call request Request to + event handler Handler installed in the event manager + identified by EventMgrRef and returns a request + identifier ReqId. The return value ReqId + shall later be used with + receive_response/2, + wait_response/2, or + check_response/2 + to fetch the actual result of the request. Besides passing + the request identifier directly to these functions, it can also be + saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, or + check_response/3. + If you are about to save the request identifier in a request identifier + collection, you may want to consider using + send_request/5 + instead. +

    +

    + The call gen_event:receive_response(gen_event:send_request(EventMgrRef, + Handler, Request), Timeout) can be seen as equivalent to - gen_event:call(EventMgrRef,Handler,Request,Timeout), + gen_event:call(EventMgrRef, + Handler, Request, Timeout), ignoring the error handling.

    @@ -487,6 +815,38 @@ gen_event:stop -----> Module:terminate/2 + + + + Sends a request to a generic server. + +

    + Sends an asynchronous call request Request to + event handler Handler installed in the event manager + identified by EventMgrRef. + The Label will be associated with the request + identifier of the operation and added to the returned request + identifier collection NewReqIdCollection. + The collection can later be used in order to get one response + corresponding to a request in the collection by passing the + collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    + +

    + The same as calling + gen_event:reqids_add(gen_event:send_request(EventMgrRef, + Handler, Request), Label, + ReqIdCollection), but calling send_request/5 + is slightly more efficient. +

    +
    +
    + start() -> Result start(EventMgrName | Options) -> Result @@ -501,8 +861,8 @@ gen_event:stop -----> Module:terminate/2   Dbgs = [Dbg]    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}   SOpts = [term()] - Result = {ok,Pid} | {error,{already_started,Pid}} -  Pid = pid() + Result = {ok,Pid} | {error,{already_started,OtherPid}} | {error,timeout} +  Pid = OtherPid = pid()

    Creates a stand-alone event manager process, that is, an event @@ -528,14 +888,14 @@ gen_event:stop -----> Module:terminate/2   Dbgs = [Dbg]    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}   SOpts = [term()] - Result = {ok,Pid} | {error,{already_started,Pid}} -  Pid = pid() + Result = {ok,Pid} | {error,{already_started,OtherPid}} | {error,timeout} +  Pid = OtherPid = pid()

    Creates an event manager process as part of a supervision tree. The function is to be called, directly or indirectly, by the supervisor. For example, it ensures that - the event manager is linked to the supervisor.

    + the event manager is linked to the caller (supervisor).

    If EventMgrName={local,Name}, the event manager is @@ -567,10 +927,50 @@ gen_event:stop -----> Module:terminate/2

    If the event manager is successfully created, the function returns {ok,Pid}, where Pid is the pid of - the event manager. If a process with the specified + the event manager.

    +

    If a process with the specified EventMgrName exists already, the function returns - {error,{already_started,Pid}}, where Pid is - the pid of that process.

    + {error,{already_started,OtherPid}}, where OtherPid is + the pid of that process, and the event manager process + exits with reason normal.

    +

    + If the event manager fails to start within the specified + start timeout {timeout,Time}, which is very unlikely + since the start does not interact with other processes, + the function returns {error,timeout} and the + failed event manager is killed with + exit(_, kill). +

    +

    + If start_link/1,2 returns {error,_}, + the started event manager process has terminated. + If an 'EXIT' message was delivered to the calling process + (due to the process link), that message has been consumed. +

    + +

    + Before OTP 26.0, if the started event manager + failed to register its name, this founction could return + {error,{already_started,OtherPid}} + before the started event manager process + had terminated so starting again might fail + because the registered name was not yet unregistered, + and an 'EXIT' message could arrive later + to the process calling this function. +

    +

    + But if the start timed out, this function killed + the started event manager process and returned + {error,timeout}, and then the process link + {'EXIT',Pid,killed} message was consumed. +

    +

    + The start was made synchronous in OTP 26.0 + and the guarantee was implemented + that no process link 'EXIT' message from a failed start + will linger in the caller's inbox. +

    +
    @@ -588,8 +988,8 @@ gen_event:stop -----> Module:terminate/2   Dbgs = [Dbg]    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}   SOpts = [term()] - Result = {ok,{Pid,Mon}} | {error,{already_started,Pid}} -  Pid = pid() + Result = {ok,{Pid,Mon}} | {error,{already_started,OtherPid}} | {error,timeout} +  Pid = OtherPid = pid()

    Creates a stand-alone event manager process, that is, an event @@ -637,10 +1037,16 @@ gen_event:stop -----> Module:terminate/2 specifies how many milliseconds to wait for the event manager to terminate, or the atom infinity to wait indefinitely. Defaults to infinity. If the - event manager has not terminated within the specified time, a - timeout exception is raised.

    -

    If the process does not exist, a noproc exception - is raised.

    + event manager has not terminated within the specified time, + the call exits the calling process + with reason timeout.

    +

    + If the process does not exist, the call exits + the calling process with reason noproc, + and with reason {nodedown,Node} + if the connection fails to the remote Node + where the server runs. +

    For a description of EventMgrRef, see add_handler/3.

    @@ -719,30 +1125,24 @@ gen_event:stop -----> Module:terminate/2 - wait_response(RequestId, Timeout) -> Result - Wait for a reply from a server. - - RequestId = request_id() - Reply = term() - Timeout = timeout() - Result = {reply, Reply} | timeout | {error, Error} - Reply = Error = term() - + + Wait or poll for a response to an asynchronous call request + to a generic event manager.

    - This function is used to wait for a reply of a request made with - send_request/3 - to the event manager. This function must be called from the same - process from which send_request/3 - was made. + Wait for a response corresponding to the request identifier + ReqId. The request must have been made by + send_request/3 + to the gen_statem process. This function must be called + from the same process from which + send_request/3 + was made.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. - If no reply is received within the specified + WaitTime specifies how long to wait for + a response. If no response is received within the specified time, the function returns timeout and no cleanup is - done, and thus the function must be invoked repeatedly until a + done, and thus the function can be invoked repeatedly until a reply is returned.

    @@ -760,11 +1160,89 @@ gen_event:stop -----> Module:terminate/2

    The difference between - receive_response() - and wait_response() is that receive_response() + receive_response/2 + and wait_response/2 is that receive_response/2 abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + response is ignored, while wait_response/2 does not. +

    +
    +
    + + + + Wait or poll for a response to an asynchronous call request + to a generic event manager. + +

    + Wait for a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/3 or + send_request/5, + and all requests must have been made by the process calling this + function.

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id in + a request identifier collection, or when sending the request using + send_request/5. +

    +

    + Compared to + wait_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by wait_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, no_request + will be returned. If no response is received before the + WaitTime timeout has triggered, the atom + timeout is returned. It is valid to continue waiting for a + response as many times as needed up until a response has been received + and completed by check_response(), receive_response(), + or wait_response(). +

    +

    + The difference between + receive_response/3 + and wait_response/3 is that receive_response/3 + abandons requests at timeout so that potential future + responses are ignored, while wait_response/3 does not. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + wait_response/3, + check_response/3, + and + receive_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to wait_response/3, it will always block + until a timeout determined by WaitTime is + triggered and then return no_reply. +

    @@ -834,6 +1312,67 @@ gen_event:stop -----> Module:terminate/2 + + Module:format_status(Status) -> NewStatus + Optional function for providing a term describing the + current event handler state. + + Status = format_status() + NewStatus = format_status() + + + +

    This callback is optional, so event handler modules need + not export it. If a handler does not export this function, + the gen_event module uses the handler state directly for + the purposes described below.

    +

    + If this callback is exported but fails, to hide possibly sensitive + data, the default function will instead return the fact that + format_status/1 has crashed.

    +
    +

    This function is called by a gen_event process in the + following situations:

    + + One of + sys:get_status/1,2 + is invoked to get the gen_event status. + The event handler terminates abnormally and gen_event + logs an error. + +

    + This callback is used to limit the status of the event handler + returned by + sys:get_status/1,2 + or sent to logger. +

    +

    + The callback gets a map Status + describing the current status and shall return a map + NewStatus with the same keys, + but it may transform some values. +

    +

    + Two possible use cases for this callback is to + remove sensitive information from the state + to prevent it from being printed in log files, + or to compact large irrelevant status items + that would only clutter the logs. +

    + + maps:map( + fun(state,State) -> + maps:remove(private_key, State); + (message,{password, _Pass}) -> + {password, removed}; + (_,Value) -> + Value + end, Status). +]]> +
    +
    + Module:format_status(Opt, [PDict, State]) -> Status Optional function for providing a term describing the @@ -845,6 +1384,11 @@ gen_event:stop -----> Module:terminate/2 Status = term() + +

    This callback is deprecated, in new code use + format_status/1. If a format_status/1 + callback exists, then this function will never be called.

    +

    This callback is optional, so event handler modules need not export it. If a handler does not export this function, @@ -1005,6 +1549,14 @@ gen_event:stop -----> Module:terminate/2 an event manager receives any other message than an event or a synchronous request (or a system message).

    Info is the received message.

    +

    In particular, this callback will be made when a process terminated + after calling + + add_sup_handler/3. Any event handler + attached to an event manager which in turn has a supervised handler + should expect callbacks of the shape + + Module:handle_info({'EXIT', Pid, Reason}, State).

    For a description of State and possible return values, see Module:handle_event/2.

    diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index c0c806c309a1..788197ac46c0 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -107,632 +107,1443 @@ gen_server:abcast -----> Module:handle_cast/2 Processes in the Reference Manual for details regarding error handling using exit signals.

    +

    + For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + Blocking signaling can, for example, cause call timeouts in + gen_server to be significantly delayed. +

    + + + + + + + +

    + Name specification to use when starting a gen_server. + See functions + start/3,4, + start_link/3,4, + start_monitor/3,4, + enter_loop/3,4,5, + and the type + server_ref() + below. +

    + + {local,LocalName} + +

    + Register the gen_server locally + as LocalName using + + register/2. +

    +
    + {global,GlobalName} + +

    + Register the gen_server process id + globally as GlobalName using + + global:register_name/2. +

    +
    + {via,RegMod,ViaName} + +

    + Register the gen_server process with the registry + represented by RegMod. + The RegMod callback is to export + the functions register_name/2, unregister_name/1, + whereis_name/1, and send/2, which are to behave + like the corresponding functions in + global. + Thus, {via,global,GlobalName} + is a valid reference equivalent to + {global,GlobalName}. +

    +
    +
    +
    +
    + + + + +

    + Server specification to use when addressing + a gen_server. + See call/2,3, + cast/2, + send_request/2, + check_response/2, + wait_response/2, + stop/2,3 + and the type + server_name() + above. +

    +

    It can be:

    + + pid() + +

    + The gen_server's process identifier. +

    +
    + LocalName + +

    + The gen_server is locally registered + as LocalName with + + register/2. +

    +
    + {Name,Node} + +

    + The gen_server is locally registered + on another node. +

    +
    + {global,GlobalName} + +

    + The gen_server is globally registered in + global. +

    +
    + {via,RegMod,ViaName} + +

    + The gen_server is registered in + an alternative process registry. + The registry callback module RegMod + is to export functions + register_name/2, unregister_name/1, + whereis_name/1, and send/2, + which are to behave like the corresponding functions in + global. + Thus, {via,global,GlobalName} + is the same as {global,GlobalName}. +

    +
    +
    +
    +
    + + + + +

    + Options that can be used when starting + a gen_server server through, for example, + start_link/3,4. +

    + + {timeout,Timeout} + +

    + How many milliseconds the gen_server process is allowed + to spend initializing or it is terminated and the + start function returns {error,timeout}. +

    +
    + + {spawn_opt,SpawnOptions} + + +

    + The SpawnOptions option list + is passed to the function used to spawn + the gen_server; see + + spawn_opt/2. +

    + +

    + Using spawn option monitor is not + allowed, it causes a badarg failure. +

    +
    +
    + enter_loop_opt() + +

    + See the type + enter_loop_opt() + below for more start options that are also allowed by + enter_loop/3,4,5. +

    +
    +
    +
    +
    + + + + +

    + Options that can be used when starting + a gen_server server through + enter_loop/3-5 + or the start functions such as + start_link/3,4. +

    + + {hibernate_after,HibernateAfterTimeout} + +

    + Specifies that the gen_server process awaits + any message for HibernateAfterTimeout milliseconds and + if no message is received, the process goes into hibernation + automatically (by calling + + proc_lib:hibernate/3). +

    +
    + {debug,Dbgs} + +

    + For every entry in Dbgs, + the corresponding function in + sys(3) is called. +

    +
    +
    +
    +
    + + + + +

    + Return value from the + start/3,4 + and + start_link/3,4 + functions. +

    + + {ok,Pid} + +

    + The gen_server process was succesfully created + and initialized, with the process identifier + Pid. +

    +
    + {error,{already_started,OtherPid}} + +

    + A process with the specified ServerName exists already + with the process identifier OtherPid. + This gen_server was not started, + or rather exited with reason normal before + calling + Module:init/1. +

    +
    + {error,timeout} + +

    + The gen_server process failed to initialize since + Module:init/1 + did not return within the + start timeout. + The gen_server process was killed with + exit(_, kill). +

    +
    + ignore + +

    + The gen_server process failed to initialize since + Module:init/1 + returned ignore. +

    +
    + {error,Reason} + +

    + The gen_server process failed to initialize since + Module:init/1 + returned {stop,Reason}, + {error,Reason}, + or it failed with reason Reason. +

    +
    +
    +

    + See + Module:init/1 + about the exit reason for the gen_server process + when it fails to initialize. +

    +
    +
    + + + + +

    + Return value from the + start_monitor/3,4 + functions. + The same as type + start_ret() + except that for a succesful start it returns both + the process identifier Pid and a + monitor/2,3 + reference() MonRef. +

    +
    +
    + + + + +

    + Destination, given to the gen_server + as the first argument to the callback function + Module:handle_call/3, + to be used by the when replying through + reply/2 + (instead of through the callback function's return value) + to the process Client + that has called the gen_server using + call/2,3. + Tag is a term that is unique + for this call/request instance. +

    +
    +
    + + + + +

    + A handle that associates a reply to the corresponding request. +

    +
    +
    + + + + +

    + An opaque request identifier. See + send_request/2 + for details. +

    +
    +
    + + + + +

    + An opaque collection of request identifiers + (request_id()) + where each request identifier can be associated with a label + chosen by the user. For more information see + reqids_new/0. +

    +
    +
    + + + + +

    + Used to set a time limit on how long to wait for a response using + either + receive_response/2, + receive_response/3, + wait_response/2, + or + wait_response/3. + The time unit used is millisecond. Currently valid values: +

    + + 0..4294967295 +

    + Timeout relative to current time in milliseconds. +

    + infinity +

    + Infinite timeout. That is, the operation will never time out. +

    + {abs, Timeout} +

    + An absolute + Erlang monotonic time + timeout in milliseconds. That is, the operation will time out when + erlang:monotonic_time(millisecond) + returns a value larger than or equal to Timeout. Timeout + is not allowed to identify a time further into the future than 4294967295 + milliseconds. Identifying the timeout using an absolute timeout value + is especially handy when you have a deadline for responses corresponding + to a complete collection of requests + (request_id_collection()) +, + since you do not have to recalculate the relative time until the deadline + over and over again. +

    +
    +
    +
    + + + + +

    + A map that describes the gen_server status. + The keys are: +

    + + state + The internal state of the gen_server process. + message + The message that caused the server to terminate. + reason + The reason that caused the server to terminate. + log + + The sys log of the server. + + +

    + New associations may be added to the status map + without prior notice. +

    +
    +
    +
    + + + - abcast(Name, Request) -> abcast - abcast(Nodes, Name, Request) -> abcast - Send an asynchronous request to many generic servers. - - Nodes = [Node] -  Node = atom() - Name = atom() - Request = term() - + + + + Send an asynchronous request to many generic servers. + -

    Sends an asynchronous request to the gen_server processes - locally registered as Name at the specified nodes. The function +

    + Sends an asynchronous request to the gen_server processes + locally registered as Name + at the specified nodes. The function returns immediately and ignores nodes that do not exist, or - where the gen_server Name does not exist. + where the gen_server + Name does not exist. The gen_server processes call - Module:handle_cast/2 to handle the request.

    -

    For a description of the arguments, see - multi_call/2,3,4.

    + Module:handle_cast/2 + to handle the request. +

    +

    + For a description of the arguments, see + multi_call/2,3,4. +

    - call(ServerRef, Request) -> Reply - call(ServerRef, Request, Timeout) -> Reply + + Make a synchronous call to a generic server. - - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - Request = term() - Timeout = int()>0 | infinity - Reply = term() - -

    Makes a synchronous call to the ServerRef of the - gen_server process +

    + Makes a synchronous call to the + ServerRef of the gen_server process by sending a request and waiting until a reply arrives or a time-out occurs. The gen_server process calls - Module:handle_call/3 to handle the request.

    -

    ServerRef can be any of the following:

    - - The pid - Name, if the gen_server process is locally - registered - {Name,Node}, if the gen_server process is locally - registered at another node - {global,GlobalName}, if the gen_server process is - globally registered - {via,Module,ViaName}, if the gen_server process is - registered through an alternative process registry - -

    Request is any term that is passed as the - first argument to Module:handle_call/3.

    -

    Timeout is an integer greater than zero that + Module:handle_call/3 + + to handle the request. +

    +

    + See also ServerRef's type + server_ref(). +

    +

    + Request is any term that is passed as the + first argument to Module:handle_call/3. +

    +

    + Timeout is an integer that specifies how many milliseconds to wait for a reply, or - the atom infinity to wait indefinitely. Defaults to - 5000. If no reply is received within the specified time, - the function call fails. If the caller catches the failure - and continues running, and the server is just late with the reply, - it can arrive at any time later into the message queue of the caller. - The caller must in this case be prepared for this - and discard any such garbage messages that are two element - tuples with a reference as the first element.

    -

    The return value Reply is defined in the return value - of Module:handle_call/3.

    -

    The call can fail for many reasons, including time-out and the - called gen_server process dying before or during the call.

    + the atom infinity to wait indefinitely. + Defaults to 5000. + If no reply is received within the specified time, + this function exits the calling process with an exit term + containing Reason = timeout as described below. +

    + +

    + Before OTP 24, if the caller uses (try...)catch + to avoid process exit, + and the server happens to just be late with the reply, + it may arrive to the process message queue any time later. + The calling process must therefore after catching a time-out exit + be prepared to receive garbage message(s) + on the form {reference(), _} + and deal with them appropriately (discard them) + so they do not clog the process message queue + or gets mistaken for other messages. +

    +

    + Starting with OTP 24, gen_server:call uses process aliases, + so late replies will not be received. +

    +
    +

    + The return value Reply + is passed from the return value of Module:handle_call/3. +

    +

    + This call may exit the calling process + with an exit term on the form + {Reason, Location} where + Location = {gen_server,call,ArgList} + and Reason can be (at least) one of: +

    + + timeout + +

    + The call was aborted after waiting + Timeout milliseconds for a reply, + as described above. +

    +
    + noproc + +

    + The ServerRef refers to + a server by name (it is not a pid()) + and looking up the server process failed, + or the pid() was already terminated. +

    +
    + {nodedown,Node} + +

    + The ServerRef refers to a server + on the remote node Node and the connection + to that node failed. +

    +
    + calling_self + +

    A call to self() would hang indefinitely.

    +
    + + shutdown
    +
    + +

    + The server was stopped during the call + by its supervisor. See also + stop/3. +

    +
    + + normal
    + {shutdown,Term}
    +
    + +

    + The server stopped during the call by returning + {stop,Reason,_} from one of its callbacks + without replying to this call. See also + stop/3. +

    +
    + _OtherTerm + +

    + The server process exited during the call, + with reason Reason. Either by returning + {stop,Reason,_} from one of its callbacks + (without replying to this call), by raising an + exception, or due to getting an exit signal it + did not trap. +

    +
    +
    - cast(ServerRef, Request) -> ok + Send an asynchronous request to a generic server. - - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - Request = term() - -

    Sends an asynchronous request to the ServerRef of the - gen_server process - and returns ok immediately, ignoring - if the destination node or gen_server process does not exist. +

    + Sends an asynchronous request to the + ServerRef of the + gen_server process and returns ok immediately, + ignoring if the destination node or gen_server process + does not exist. The gen_server process calls - Module:handle_cast/2 to handle the request.

    -

    For a description of ServerRef, see - call/2,3.

    -

    Request is any term that is passed as one - of the arguments to Module:handle_cast/2.

    + Module:handle_cast/2 + + to handle the request. +

    +

    + See also ServerRef's type + server_ref(). +

    +

    + Request is any term that is passed as + the first argument to Module:handle_cast/2. +

    - check_response(Msg, RequestId) -> Result - Check if a message is a reply from a server. - - RequestId = term() - Result = {reply, Reply} | no_reply | {error, {Reason, ServerRef}} - Msg = Reply = term() - Timeout = timeout() - Reason = term() - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - + + Check if a message is a response from a server.

    - This function is used to check if a previously received - message, for example by receive or - handle_info/2, is a result of a request made with - send_request/2. - If Msg is a reply to the handle RequestId - the result of the request is returned in Reply. - Otherwise returns no_reply and no cleanup is done, and - thus the function must be invoked repeatedly until a reply - is returned. + Check if Msg is a response corresponding + to the request identifier ReqId. The request + must have been made by + send_request/2, + and it must have been made by the same process calling + this function.

    +

    + If Msg is a response corresponding to + ReqId the response is returned; otherwise, + no_reply is returned and no cleanup is done, and + thus the function must be invoked repeatedly until a response + is returned. +

    - The return value Reply is defined in the return value - of Module:handle_call/3. + The return value Reply is passed from the + return value of Module:handle_call/3.

    The function returns an error if the gen_server - dies before or during this request. + died before a reply was sent. +

    +
    +
    + + + + Check if a message is a response from a server. + +

    + Check if Msg is a response corresponding + to a request identifier saved in ReqIdCollection. + All request identifiers of ReqIdCollection + must correspond to requests that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function.

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id + in a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + check_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by check_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. If Msg + does not correspond to any of the request identifiers in + ReqIdCollection, the atom + no_reply is returned. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + check_response/3, + receive_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to check_response/3, it will always + return no_reply. +

    - enter_loop(Module, Options, State) - enter_loop(Module, Options, State, ServerName) - enter_loop(Module, Options, State, Timeout) - enter_loop(Module, Options, State, ServerName, Timeout) + + + + + + + + Enter the gen_server receive loop. - - Module = atom() - Options = [Option] -  Option = {debug,Dbgs} | {hibernate_after,HibernateAfterTimeout} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics -     | {log_to_file,FileName} | {install,{Func,FuncState}} - State = term() - ServerName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Timeout = int() | infinity - -

    Makes an existing process into a gen_server process. Does not - return, instead the calling process enters the gen_server - process receive - loop and becomes a gen_server process. The process - must have been started using one of the start functions in - proc_lib(3). The user is - responsible for any initialization of the process, including - registering a name for it.

    -

    This function is useful when a more complex initialization procedure - is needed than the gen_server process behavior provides.

    -

    Module, Options, and ServerName have +

    + Makes an existing process a gen_server process. + Does not return, instead the calling process enters + the gen_server process receive loop + and becomes a gen_server process. + The process must have been started using + one of the start functions in + proc_lib(3). + The user is responsible for any initialization of the process, + including registering a name for it. +

    +

    + This function is useful when a more complex + initialization procedure is needed + than the gen_server process behavior provides. +

    +

    + Module, Options, + and ServerName have the same meanings as when calling - start[_link|_monitor]/3,4. - However, if ServerName is specified, the process must - have been registered accordingly before this function - is called.

    -

    State and Timeout have the same meanings as in + + start[_link|_monitor]/3,4 + + or it can be self() for an anonymous server, + which is the same as calling an enter_loop/3,4 function + without a ServerName argument. + However, if ServerName is specified + (and not as self()), + the process must have been registered accordingly + before this function is called. +

    +

    + State, Timeout, + Hibernate and Cont have the same meanings as in the return value of - Module:init/1. - The callback module Module does not need to - export an init/1 function.

    -

    The function fails if the calling process was not started by a + Module:init/1, + which is not called when enter_loop/3,4,5 is used. + Note that to adhere to the + + gen_server Behaviour + + such a callback function needs to be defined, + and it might as well be the one used when starting + the gen_server process through proc_lib, + and then be the one that calls enter_loop/3,4,5. + But if such a Module:init/1 function + in for example error cases cannot call + enter_loop/3,4,5, it should return a value + that follows the type specification for + Module:init/1 such as ignore, + although that value will be lost + when returning to the spawning function. +

    +

    + This function fails if the calling process was not started by a proc_lib start function, or if it is not registered - according to ServerName.

    + according to ServerName. +

    - multi_call(Name, Request) -> Result - multi_call(Nodes, Name, Request) -> Result - multi_call(Nodes, Name, Request, Timeout) -> Result + + + Make a synchronous call to many generic servers. - - Nodes = [Node] -  Node = atom() - Name = atom() - Request = term() - Timeout = int()>=0 | infinity - Result = {Replies,BadNodes} -  Replies = [{Node,Reply}] -   Reply = term() - BadNodes = [Node] - -

    Makes a synchronous call to all gen_server processes locally - registered as Name at the specified nodes by first - sending a request to every node and then waits for - the replies. The gen_server process calls +

    + Makes a synchronous call to all gen_server processes + locally registered as Name + at the specified nodes, + by first sending the request to the nodes, + and then waiting for the replies. + The gen_server processes on the nodes call - Module:handle_call/3 to handle the request.

    -

    The function returns a tuple {Replies,BadNodes}, where - Replies is a list of {Node,Reply} and - BadNodes is a list of node that either did not exist, - or where the gen_server Name did not exist or did not - reply.

    -

    Nodes is a list of node names to which the request - is to be sent. Default value is the list of all known nodes - [node()|nodes()].

    -

    Name is the locally registered name of each - gen_server process.

    -

    Request is any term that is passed as the first - argument to Module:handle_call/3.

    -

    Timeout is an integer greater than zero that - specifies how many milliseconds to wait for each reply, or - the atom infinity to wait indefinitely. Defaults - to infinity. If no reply is received from a node within - the specified time, the node is added to BadNodes.

    -

    When a reply Reply is received from the gen_server - process at a node Node, {Node,Reply} is added to - Replies. Reply is defined in the return value of - Module:handle_call/3.

    + Module:handle_call/3 + + to handle the request. +

    +

    + The function returns a tuple + {Replies,BadNodes}, + where Replies is a list of + {Node,Reply} tuples, + and BadNodes is a list of nodes + that either did not exist, + where Name + was not a registered gen_server, + or where it did not reply. +

    +

    + Nodes is a list of node names + to which the request is to be sent. + Default value is the list of all known nodes + [node()|nodes()]. +

    +

    + Name is the locally registered name + for each gen_server process. +

    +

    + Request is any term that is passed + as the first argument to Module:handle_call/3. +

    +

    + Timeout is an integer that + specifies how many milliseconds to wait for all replies, + or the atom infinity to wait indefinitely, + which is the default. + If no reply is received from a node within the specified time, + the node is added to BadNodes. +

    +

    + When a reply Reply is received + from the gen_server process + at a node Node, + {Node,Reply} is added to + Replies. + Reply is passed from the return value of + Module:handle_call/3. +

    -

    If one of the nodes cannot process monitors, for example, +

    + If one of the nodes cannot process monitors, for example, C or Java nodes, and the gen_server process is not started when the requests are sent, but starts within 2 seconds, this function waits the whole Timeout, - which may be infinity.

    + which may be infinity. +

    This problem does not exist if all nodes are Erlang nodes.

    -

    To prevent late answers (after the time-out) from polluting - the message queue of the caller, a middleman process is used to - do the calls. Late answers are then discarded - when they arrive to a terminated process.

    +

    + To prevent late answers (after the time-out) from polluting + the message queue of the caller, a middleman process is used + to do the calls. Late answers are then discarded + when they arrive to a terminated process. +

    - receive_response(RequestId, Timeout) -> Result - Receive for a reply from a server. - - RequestId = term() - Result = {reply, Reply} | timeout | {error, {Reason, ServerRef}} - Reply = term() - Timeout = timeout() - Reason = term() - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - + + Receive a response from a server.

    - This function is used to receive a reply of a request made with - send_request/2 - to a gen_server process. This function must be called - from the same process from which - send_request/2 - was made. + Receive a response corresponding to the request identifier + ReqId. The request must have been made by + send_request/2, + and it must have been made by the same process calling + this function.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. - If no reply is received within the specified - time, the function returns timeout. Assuming that the + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the server executes on a node supporting aliases (introduced in - OTP 24) no response will be received after a timeout. Otherwise, - a garbage response might be received at a later time. + OTP 24) the request will also be abandoned. That is, no + response will be received after a timeout. Otherwise, a + stray response might be received at a later time.

    - The return value Reply is defined in the return value - of Module:handle_call/3. + The return value Reply is passed from the + return value of Module:handle_call/3.

    The function returns an error if the gen_server - dies before or during this request. + died before a reply was sent.

    - The difference between - wait_response() - and receive_response() is that receive_response() - abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + The difference between receive_response/2 and + wait_response/2 + is that receive_response/2 abandons the request at + timeout so that a potential future response is ignored, while + wait_response/2 does not.

    - reply(Client, Reply) -> ok + + Receive a response from a server. + +

    + Receive a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function. +

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + adding the request id + in a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + receive_response/2, + the returned result associated with a specific request identifier + will be wrapped in a 3-tuple. The first element of this tuple equals + the value that would have been produced by receive_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. +

    +

    + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) all requests identified by ReqIdCollection + will also be abandoned. That is, no responses will be received + after a timeout. Otherwise, stray responses might be received + at a later time. +

    +

    + The difference between receive_response/3 and + wait_response/3 + is that receive_response/3 abandons the requests at timeout + so that potential future responses are ignored, while + wait_response/3 does not. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + receive_response/3, + check_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to receive_response/3, it will always block + until a timeout determined by Timeout is + triggered. +

    +
    +
    + + + Send a reply to a client. - - Client - see below - Reply = term() - -

    This function can be used by a gen_server process to +

    + This function can be used by a gen_server process to explicitly send a reply to a client that called call/2,3 or multi_call/2,3,4, - when the reply cannot be defined in the return value of + when the reply cannot be passed in the return value of - Module:handle_call/3.

    -

    Client must be the From argument provided to - the callback function. Reply is any term - given back to the client as the return value of - call/2,3 or multi_call/2,3,4.

    + Module:handle_call/3. +

    +

    + Client must be the From argument + provided to the handle_call callback function. + Reply is any term + passed back to the client as the return value of + call/2,3 or multi_call/2,3,4. +

    - send_request(ServerRef, Request) -> RequestId + + Save a request identifier. + +

    + Saves ReqId and associates a Label + with the request identifier by adding this information to + ReqIdCollection and returning the + resulting request identifier collection. +

    +
    +
    + + + + Create a new empty request identifier collection. + +

    + Returns a new empty request identifier collection. A + request identifier collection can be utilized in order + the handle multiple outstanding requests. +

    +

    + Request identifiers of requests made by + send_request/2 + can be saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    +

    + reqids_size/1 + can be used to determine the amount of request identifiers in a + request identifier collection. +

    +
    +
    + + + + Get size of a request identifier collection. + +

    + Returns the amount of request identifiers saved in + ReqIdCollection. +

    +
    +
    + + + + List a request identifiers. + +

    + Returns a list of {ReqId, Label} + tuples which corresponds to all request identifiers with their + associated labels present in the ReqIdCollection + collection. +

    +
    +
    + + + Sends a request to a generic server. - - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - RequestId = term() - Timeout = int()>0 | infinity - Request = term() -

    - Sends a request to the ServerRef of the - gen_server process and returns a handle RequestId. - The return value RequestId shall later be used with + Sends an asynchronous call request Request + to the gen_server process identified by ServerRef + and returns a request identifier ReqId. The return + value ReqId shall later be used with receive_response/2, wait_response/2, or check_response/2 - to fetch the actual result of the request. + to fetch the actual result of the request. Besides passing + the request identifier directly to these functions, it can also be + saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, or + check_response/3. + If you are about to save the request identifier in a request identifier + collection, you may want to consider using + send_request/4 + instead.

    - The call gen_server:wait_response(gen_server:send_request(ServerRef,Request), Timeout) - can be seen as equivalent to - gen_server:call(Server,Request,Timeout), - ignoring the error handling. + The call gen_server:receive_response(gen_server:send_request(ServerRef, + Request), Timeout) can be seen as equivalent to + gen_server:call(ServerRef, Request, + Timeout), ignoring the error handling.

    The gen_server process calls - Module:handle_call/3 + + Module:handle_call/3 + to handle the request.

    -

    ServerRef can be any of the following:

    - - The pid - Name, if the gen_server process is locally - registered - {Name,Node}, if the gen_server process is locally - registered at another node - {global,GlobalName}, if the gen_server process is - globally registered - {via,Module,ViaName}, if the gen_server process is - registered through an alternative process registry - -

    Request is any term that is passed as the first - argument to Module:handle_call/3.

    +

    + See the type + server_ref() + for the possible values for ServerRef. +

    +

    + Request is any term that is passed + as the first argument to Module:handle_call/3. +

    +
    +
    + + + + Sends a request to a generic server. + +

    + Sends an asynchronous call request Request + to the gen_server process identified by ServerRef. + The Label will be associated with the request + identifier of the operation and added to the returned request + identifier collection NewReqIdCollection. + The collection can later be used in order to get one response + corresponding to a request in the collection by passing the + collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    + +

    + The same as calling + gen_server:reqids_add(gen_server:send_request(ServerRef, + Request), Label, + ReqIdCollection), but calling send_request/4 + is slightly more efficient. +

    - start(Module, Args, Options) -> Result - start(ServerName, Module, Args, Options) -> Result + + Create a standalone gen_server process. - - ServerName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Module = atom() - Args = term() - Options = [Option] -  Option = {debug,Dbgs} | {timeout,Time} | {hibernate_after,HibernateAfterTimeout} | {spawn_opt,SOpts} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}} -   SOpts = [term()] - Result = {ok,Pid} | ignore | {error,Error} -  Pid = pid() -  Error = {already_started,Pid} | term() - -

    Creates a standalone gen_server process, that is, a +

    + Creates a standalone gen_server process, that is, a gen_server process that is not part of a supervision tree and thus has no supervisor.

    -

    For a description of arguments and return values, see - start_link/3,4.

    +

    + Other than that see + start_link/3,4. +

    - start_link(Module, Args, Options) -> Result - start_link(ServerName, Module, Args, Options) -> Result - Create a gen_server process in a supervision tree. + + + + Create a gen_server process in a supervision tree. - - ServerName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Module = atom() - Args = term() - Options = [Option] -  Option = {debug,Dbgs} | {timeout,Time} | {hibernate_after,HibernateAfterTimeout} | {spawn_opt,SOpts} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}} -   SOpts = [term()] - Result = {ok,Pid} | ignore | {error,Error} -  Pid = pid() -  Error = {already_started,Pid} | term() - -

    Creates a gen_server process as part of a supervision tree. +

    + Creates a gen_server process as part of a supervision tree. This function is to be called, directly or indirectly, by the supervisor. For example, it ensures that - the gen_server process is linked to the supervisor.

    -

    The gen_server process calls - Module:init/1 to - initialize. To ensure a synchronized startup procedure, + the gen_server process is spawned as linked + to the caller (supervisor). +

    +

    + The gen_server process calls + Module:init/1 + to initialize. + To ensure a synchronized startup procedure, start_link/3,4 does not return until - Module:init/1 has returned.

    - - -

    If ServerName={local,Name}, the gen_server process - is registered locally as Name using register/2.

    -
    - -

    If ServerName={global,GlobalName}, the gen_server - process id registered globally as GlobalName using - - global:register_name/2 If no name is - provided, the gen_server process is not registered.

    -
    - -

    If ServerName={via,Module,ViaName}, the gen_server - process registers with the registry represented by Module. - The Module callback is to export the functions - register_name/2, unregister_name/1, - whereis_name/1, and send/2, which are to behave - like the corresponding functions in - global. - Thus, {via,global,GlobalName} is a valid reference.

    -
    -
    -

    Module is the name of the callback module.

    -

    Args is any term that is passed as + Module:init/1 has returned or failed. +

    +

    + Using the argument ServerName + creates a gen_server with a registered name. + See type + server_name() + for different name registrations. + If no ServerName is provided, + the gen_server process is not registered. +

    +

    + Module is the name of the callback module. +

    +

    + Args is any term that is passed as the argument to - Module:init/1.

    - - -

    If option {timeout,Time} is present, the gen_server - process is allowed to spend Time milliseconds - initializing or it is terminated and the start function - returns {error,timeout}.

    -
    - -

    If option {hibernate_after,HibernateAfterTimeout} is present, the gen_server - process awaits any message for HibernateAfterTimeout milliseconds and - if no message is received, the process goes into hibernation automatically - (by calling proc_lib:hibernate/3).

    -
    - -

    If option {debug,Dbgs} is present, - the corresponding sys function is called for each - item in Dbgs; see - sys(3).

    -
    - -

    If option {spawn_opt,SOpts} is present, - SOpts is passed as option list to - the spawn_opt BIF, which is used to spawn - the gen_server process; see - - spawn_opt/2.

    -
    -
    - -

    Using spawn option monitor is not - allowed, it causes the function to fail with reason - badarg.

    -
    -

    If the gen_server process is successfully created and - initialized, the function returns {ok,Pid}, where Pid - is the pid of the gen_server process. If a process with the - specified ServerName exists already, the function returns - {error,{already_started,Pid}}, where Pid is - the pid of that process.

    -

    If Module:init/1 fails with Reason, - the function returns {error,Reason}. If - Module:init/1 returns {stop,Reason} or - ignore, the process is terminated and the function - returns {error,Reason} or ignore, respectively. - An exit signal with the same Reason (or normal if - Module:init/1 returns ignore) is sent to linked - processes and ports.

    + Module:init/1. +

    +

    + See type + start_opt() + for Options when starting + the gen_server process. +

    +

    + See type + start_ret() + for a description this function's return values. +

    +

    + If start_link/3,4 returns ignore or {error,_}, + the started gen_server process has terminated. + If an 'EXIT' message was delivered to the calling process + (due to the process link), that message has been consumed. +

    + +

    + Before OTP 26.0, if the started gen_server process + returned e.g. {stop,Reason} from + Module:init/1, + this function could return {error,Reason} + before the started gen_statem process + had terminated so starting again might fail + because VM resources such as the registered name + was not yet unregistered. An 'EXIT' message + could arrive later to the process calling this function. +

    +

    + But if the started gen_server process instead + failed during + Module:init/1, + a process link {'EXIT',Pid,Reason} message + caused this function to return {error,Reason} + so the 'EXIT' message had been consumed + and the started gen_statem process had terminated. +

    +

    + Since it was impossible to tell the difference + between these two cases from + start_link/3,4's return value, + this inconsistency was cleaned up in OTP 26.0. +

    +
    +

    + The difference between returning + {stop,_} and {error,_} from + Module:init/1, + is that {error,_} results in a graceful ("silent") + termination since the gen_server process + exits with reason normal. +

    - start_monitor(Module, Args, Options) -> Result - start_monitor(ServerName, Module, Args, Options) -> Result + + Create a standalone gen_server process. - - ServerName = {local,Name} | {global,GlobalName} -   | {via,Module,ViaName} -  Name = atom() -  GlobalName = ViaName = term() - Module = atom() - Args = term() - Options = [Option] -  Option = {debug,Dbgs} | {timeout,Time} | {hibernate_after,HibernateAfterTimeout} | {spawn_opt,SOpts} -   Dbgs = [Dbg] -    Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}} -   SOpts = [term()] - Result = {ok,{Pid,Mon}} | ignore | {error,Error} -  Pid = pid() -  Error = {already_started,Pid} | term() - -

    Creates a standalone gen_server process, that is, a +

    + Creates a standalone gen_server process, that is, a gen_server process that is not part of a supervision tree (and thus has no supervisor) and atomically sets up a monitor to - the newly created server.

    -

    For a description of arguments and return values, see - start_link/3,4. - Note that the return value on successful start differs from - start_link/3,4. start_monitor/3,4 will return - {ok,{Pid,Mon}} where Pid is the process identifier - of the server, and Mon is a reference to the monitor - set up to monitor the server. If the start is not successful, - the caller will be blocked until the DOWN message has - been received and removed from the message queue.

    + the newly created server. +

    +

    + Other than that see + start_link/3,4. + Note that the return value for a successful start differs + in that it returns a monitor reference. + See type + start_mon_ret(). +

    +

    + If the start is not successful, + the caller will be blocked until the monitor's + 'DOWN' message has been received + and removed from the message queue. +

    - stop(ServerRef) -> ok - stop(ServerRef, Reason, Timeout) -> ok + + Synchronously stop a generic server. - - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - Reason = term() - Timeout = int()>0 | infinity - -

    Orders a generic server to exit with the specified Reason - and waits for it to terminate. The gen_server process calls +

    + Orders the generic server specified by + ServerRef to exit + with the specified Reason, + default 'normal', and waits for it to terminate. + The gen_server process calls - Module:terminate/2 before exiting.

    -

    The function returns ok if the server terminates + Module:terminate/2 + + before exiting. +

    +

    + The function returns ok if the server terminates with the expected reason. Any other reason than normal, shutdown, or {shutdown,Term} causes an error report to be issued using logger(3). - An exit signal with the same reason is sent to linked processes - and ports. - The default Reason is normal.

    -

    Timeout is an integer greater than zero that + An exit signal with the same reason + is sent to linked processes and ports. +

    +

    + Timeout is an integer that specifies how many milliseconds to wait for the server to terminate, or the atom infinity to wait - indefinitely. Defaults to infinity. If the - server has not terminated within the specified time, a - timeout exception is raised.

    -

    If the process does not exist, a noproc exception - is raised.

    + indefinitely, which is the default. If the + server has not terminated within the specified time, + the call exits the calling process + with reason timeout. +

    +

    + If the process does not exist, the call exits + the calling process with reason noproc, + and with reason {nodedown,Node} + if the connection fails to the remote Node + where the server runs. +

    - wait_response(RequestId, Timeout) -> Result - Wait for a reply from a server. - - RequestId = term() - Result = {reply, Reply} | timeout | {error, {Reason, ServerRef}} - Reply = term() - Timeout = timeout() - Reason = term() - ServerRef = Name | {Name,Node} | {global,GlobalName} -   | {via,Module,ViaName} | pid() -  Node = atom() -  GlobalName = ViaName = term() - + + Wait or poll for a response from a server.

    - This function is used to wait for a reply of a request made with - send_request/2 - from the gen_server process. This function must be called - from the same process from which - send_request/2 - was made. + Wait for a response corresponding to the request identifier + ReqId. The request must have been made by + send_request/2, + and it must have been made by the same process calling + this function.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. - If no reply is received within the specified + WaitTime specifies how long to wait for + a reply. If no reply is received within the specified time, the function returns timeout and no cleanup is done, and thus the function can be invoked repeatedly until a reply is returned.

    - The return value Reply is defined in the return value - of Module:handle_call/3. + The return value Reply is passed from the + return value of Module:handle_call/3.

    The function returns an error if the gen_server - dies before or during this request. + died before a reply was sent. +

    +

    + The difference between + receive_response/2 + and wait_response/2 is that receive_response/2 + abandons the request at time-out so that a potential future + response is ignored, while wait_response/2 does not.

    +
    +
    + + + + Wait or poll for a response from a server. + +

    + Wait for a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function. +

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id in + a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + wait_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by wait_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, no_request + will be returned. If no response is received before the + WaitTime timeout has triggered, the atom + timeout is returned. It is valid to continue waiting for a + response as many times as needed up until a response has been received + and completed by check_response(), receive_response(), + or wait_response(). +

    The difference between - receive_response() - and wait_response() is that receive_response() - abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + receive_response/3 + and wait_response/3 is that receive_response/3 + abandons requests at timeout so that potential future + responses are ignored, while wait_response/3 does not.

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + wait_response/3, + check_response/3, + and + receive_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to wait_response/3, it will always block + until a timeout determined by WaitTime is + triggered and then return no_reply. +

    @@ -787,6 +1598,69 @@ gen_server:abcast -----> Module:handle_cast/2 + + Module:format_status(Status) -> NewStatus + Optional function for providing a term describing the + current gen_server status. + + Status = format_status() + NewStatus = format_status() + + + +

    This callback is optional, so callback modules need not + export it. The gen_server module provides a default + implementation of this function that returns the callback + module state.

    +

    + If this callback is exported but fails, to hide possibly sensitive + data, the default function will instead return the fact that + format_status/1 has crashed.

    +
    +

    This function is called by a gen_server process in the following situations:

    + + +

    sys:get_status/1,2 + is invoked to get the gen_server status.

    +
    + +

    The gen_server process terminates abnormally and logs an error.

    +
    +
    +

    + This callback is used to limit the status of the process + returned by + sys:get_status/1,2 + or sent to logger. +

    +

    + The callback gets a map Status + describing the current status and shall return a map + NewStatus with the same keys, + but it may transform some values. +

    +

    + Two possible use cases for this callback is to + remove sensitive information from the state + to prevent it from being printed in log files, + or to compact large irrelevant status items + that would only clutter the logs. +

    +

    Example:

    + + maps:map( + fun(state,State) -> + maps:remove(private_key, State); + (message,{password, _Pass}) -> + {password, removed}; + (_,Value) -> + Value + end, Status). +]]> +
    +
    + Module:format_status(Opt, [PDict, State]) -> Status Optional function for providing a term describing the @@ -798,6 +1672,11 @@ gen_server:abcast -----> Module:handle_cast/2 Status = term() + +

    This callback is deprecated, in new code use + format_status/1. If a format_status/1 + callback exists, then this function will never be called.

    +

    This callback is optional, so callback modules need not export it. The gen_server module provides a default @@ -852,18 +1731,24 @@ gen_server:abcast -----> Module:handle_cast/2 Handle a synchronous request. Request = term() - From = {pid(),Tag} + From = from() State = term() - Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} + Result = {reply,Reply,NewState} +   | {reply,Reply,NewState,Timeout}   | {reply,Reply,NewState,hibernate}   | {reply,Reply,NewState,{continue,Continue}} -   | {noreply,NewState} | {noreply,NewState,Timeout} +   | {noreply,NewState} +   | {noreply,NewState,Timeout}   | {noreply,NewState,hibernate}   | {noreply,NewState,{continue,Continue}} -   | {stop,Reason,Reply,NewState} | {stop,Reason,NewState} +   | {stop,Reason,Reply,NewState} +   | {stop,Reason,NewState}  Reply = term()  NewState = term() -  Timeout = int()>=0 | infinity + +  Timeout = + timeout() +  Continue = term()  Reason = term() @@ -872,45 +1757,109 @@ gen_server:abcast -----> Module:handle_cast/2 call/2,3 or multi_call/2,3,4, this function is called to handle the request.

    -

    Request is the Request argument provided - to call or multi_call.

    -

    From is a tuple {Pid,Tag}, where Pid is - the pid of the client and Tag is a unique tag.

    State is the internal state of the gen_server - process.

    - + process, and NewState a possibly updated one.

    +

    Request is passed from the same argument provided + to call or multi_call.

    +

    The return value Result is interpreted as follows:

    + + + {reply,Reply,NewState}
    + {reply,Reply,NewState,_} +
    -

    If {reply,Reply,NewState} is returned, - {reply,Reply,NewState,Timeout} or - {reply,Reply,NewState,hibernate}, Reply is - given back to From as the return value of - call/2,3 or included in the return value of - multi_call/2,3,4. The gen_server process then - continues executing with the possibly updated internal state - NewState.

    -

    For a description of Timeout and hibernate, see - Module:init/1.

    +

    + The Reply value is sent back to the client request + and there becomes its return value. +

    +

    + The gen_server process continues executing + with the possibly updated internal state NewState. +

    + + {noreply,NewState}
    + {noreply,NewState,_} +
    -

    If {noreply,NewState} is returned, - {noreply,NewState,Timeout}, or - {noreply,NewState,hibernate}, the gen_server - process continues executing with NewState. Any reply to - From must be specified explicitly using - reply/2.

    +

    + The gen_server process continues executing + with the possibly updated internal state NewState. +

    +

    + A reply to the client request has to be created by calling + reply(From, Reply), + either in this or in a later callback. +

    + + {reply,_,_,Timeout}
    + {noreply,_,Timeout} +
    -

    If {stop,Reason,Reply,NewState} is returned, - Reply is given back to From.

    +

    + If an integer Timeout is provided, a time-out occurs + unless a request or a message is received within + that many milliseconds. A time-out is represented by + the atom timeout to be handled by the + + Module:handle_info/2 + + callback function. + Timeout =:= infinity + can be used to wait indefinitely, which is the same as + returning a value without a Timeout member. +

    + + {reply,_,_,hibernate}
    + {noreply,_,hibernate} +
    -

    If {stop,Reason,NewState} is returned, any reply - to From must be specified explicitly using - reply/2. - The gen_server process then calls - Module:terminate(Reason,NewState) and terminates.

    +

    + The process goes into hibernation waiting for + the next message to arrive (by calling + + proc_lib:hibernate/3). +

    -
    + + {reply,_,_,{continue,Continue}}
    + {noreply,_,{continue,Continue}} +
    + +

    + The process will execute the + + Module:handle_continue/2 + + callback function, with Continue as the first argument. +

    +
    + + {stop,Reason,NewState}
    + {stop,Reason,Reply,NewState} +
    + +

    + The gen_server process will call + + Module:terminate(Reason,NewState) + + and then terminate. +

    +

    + {stop,_,Reply,_} will create + a reply to the client request just as + {reply,Reply,...} while + {stop,_,_} will not, + so just as for {noreply,NewState,...} + a reply has to be created by calling + reply(From, Reply) + before returning {stop,_,_}. +

    +
    +
    @@ -920,12 +1869,16 @@ gen_server:abcast -----> Module:handle_cast/2 Request = term() State = term() - Result = {noreply,NewState} | {noreply,NewState,Timeout} + Result = {noreply,NewState} +   | {noreply,NewState,Timeout}   | {noreply,NewState,hibernate}   | {noreply,NewState,{continue,Continue}}   | {stop,Reason,NewState}  NewState = term() -  Timeout = int()>=0 | infinity + +  Timeout = + timeout() +  Continue = term()  Reason = term() @@ -946,25 +1899,31 @@ gen_server:abcast -----> Module:handle_cast/2 Continue = term() State = term() - Result = {noreply,NewState} | {noreply,NewState,Timeout} + Result = {noreply,NewState} +   | {noreply,NewState,Timeout}   | {noreply,NewState,hibernate}   | {noreply,NewState,{continue,Continue}}   | {stop,Reason,NewState}  NewState = term() -  Timeout = int()>=0 | infinity + +  Timeout = + timeout() +  Continue = term()  Reason = normal | term()

    This callback is optional, so callback modules need to - export it only if they return {continue,Continue} - from another callback. If continue is used and the callback - is not implemented, the process will exit with undef - error.

    + export it only if they return one of the tuples containing + {continue,Continue} + from another callback. If such a {continue,_} tuple + is used and the callback is not implemented, + the process will exit with undef error.

    -

    This function is called by a gen_server process whenever - a previous callback returns {continue, Continue}. +

    This function is called by a gen_server process + whenever a previous callback returns + one of the tuples containing {continue, Continue}. handle_continue/2 is invoked immediately after the previous callback, which makes it useful for performing work after initialization or for splitting the work in a callback in @@ -981,12 +1940,16 @@ gen_server:abcast -----> Module:handle_cast/2 Info = timeout | term() State = term() - Result = {noreply,NewState} | {noreply,NewState,Timeout} + Result = {noreply,NewState} +   | {noreply,NewState,Timeout}   | {noreply,NewState,hibernate}   | {noreply,NewState,{continue,Continue}}   | {stop,Reason,NewState}  NewState = term() -  Timeout = int()>=0 | infinity + +  Timeout = + timeout() +  Reason = normal | term() @@ -1012,10 +1975,18 @@ gen_server:abcast -----> Module:handle_cast/2 Initialize process and internal state. Args = term() - Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} -  | {ok,State,{continue,Continue}} | {stop,Reason} | ignore + Result = {ok,State} +   | {ok,State,Timeout} +   | {ok,State,hibernate} +   | {ok,State,{continue,Continue}} +   | {stop,Reason} +   | {error,Reason} +   | ignore  State = term() -  Timeout = int()>=0 | infinity + +  Timeout = + timeout() +  Reason = term() @@ -1026,35 +1997,62 @@ gen_server:abcast -----> Module:handle_cast/2 this function is called by the new process to initialize.

    Args is the Args argument provided to the start function.

    -

    If the initialization is successful, the function is to - return {ok,State}, {ok,State,Timeout}, - {ok,State,hibernate}, or {ok,State,{continue,Continue}} - where State is the internal state of the gen_server - process.

    -

    If an integer time-out value is provided, a time-out occurs - unless a request or a message is received within - Timeout milliseconds. A time-out is represented by - the atom timeout, which is to be handled by the - - Module:handle_info/2 callback function. The atom - infinity can be used to wait indefinitely, this is - the default value.

    -

    If hibernate is specified instead of a time-out value, - the process goes into - hibernation when waiting for the next message to arrive (by calling - - proc_lib:hibernate/3).

    -

    If {continue,Continue} is specified, the process will - execute the - Module:handle_continue/2 callback function, with - Continue as the first argument.

    -

    If the initialization fails, the function is to return - {stop,Reason}, where Reason is any term, or - ignore. An exit signal with this Reason (or with reason - normal if ignore is returned) is sent to linked - processes and ports, notably to the process starting the gen_server - when start_link/3,4 - is used.

    +

    The return value Result is interpreted as follows:

    + + + {ok,State}
    + {ok,State,_} +
    + +

    + Initialization was succesful and State + is the internal state of the gen_server process. +

    +
    + + {ok,_,Timeout}
    + {ok,_,hibernate}
    + {ok,_,{continue,Continue}} +
    + +

    + See the corresponding return values from + + Module:handle_call/3 + + for a description of this tuple member. +

    +
    + + {stop,Reason}
    +
    + +

    + Initialization failed. The gen_server process + exits with reason Reason. +

    +
    + + {error,Reason}
    + ignore +
    + +

    + Initialization failed. The gen_server process + exits with reason normal. +

    +

    + {error,Reason} was introduced in OTP 26.0. +

    +
    +
    +

    + See function + start_link/3,4's + return value + start_ret() + in these different cases. +

    @@ -1104,11 +2102,14 @@ gen_server:abcast -----> Module:handle_cast/2 'EXIT' message from its parent. Reason is the same as in the 'EXIT' message.

    Otherwise, the gen_server process terminates immediately.

    -

    Notice that for any other reason than normal, - shutdown, or {shutdown,Term}, the gen_server - process is assumed to terminate because of an error and - an error report is issued using - logger(3).

    +

    + Notice that for any other reason than normal, + shutdown, or {shutdown,Term}, see + stop/3, + the gen_server process is assumed to terminate + because of an error, and an error report is issued using + logger(3). +

    When the gen_server process exits, an exit signal with the same reason is sent to linked processes and ports.

    diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index fd3d11bbcff3..e9c09a2c4a1b 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -4,7 +4,7 @@
    - 20162021 + 20162023 Ericsson AB. All Rights Reserved. @@ -381,6 +381,14 @@ erlang:'!' -----> Module:StateName/3 Processes in the Reference Manual for details regarding error handling using exit signals.

    +

    + For some important information about distributed signals, see the + + Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + Blocking signaling can, for example, cause call timeouts in + gen_statem to be significantly delayed. +

    @@ -580,8 +588,10 @@ handle_event(_, _, State, Data) ->

    - Return value from the start() and start_link() functions, - for example, start_link/3. + Return value from the + start/3,4 and + start_link/3,4 + functions.

    @@ -590,7 +600,7 @@ handle_event(_, _, State, Data) ->

    Return value from the - start_monitor() + start_monitor/3,4 functions.

    @@ -638,6 +648,14 @@ handle_event(_, _, State, Data) ->

    + + + +

    + A handle that associates a reply to the corresponding request. +

    +
    +
    @@ -725,6 +743,19 @@ handle_event(_, _, State, Data) ->

    + + + +

    + Any event's content can be any term. +

    +

    + See event_type + that describes the origins of the different event types, + which is also where the event content comes from. +

    +
    +
    @@ -1008,7 +1039,7 @@ handle_event(_, _, State, Data) ->

    If there are enqueued events to process - when hibrnation is requested, + when hibernation is requested, this is optimized by not hibernating but instead calling erlang:garbage_collect/0 @@ -1246,8 +1277,8 @@ handle_event(_, _, State, Data) -> such as the state callback, NewModule:code_change/4, - - NewModule:format_status/2 + + NewModule:format_status/1 and @@ -1473,10 +1504,14 @@ handle_event(_, _, State, Data) ->

    For an unsuccesful initialization, - {stop,Reason} + {stop,Reason}, + {error,Reason} or ignore should be used; see start_link/3,4.

    +

    + {error,Reason} was introduced in OTP 26.0. +

    @@ -1616,11 +1651,106 @@ handle_event(_, _, State, Data) ->

    - A request handle, see send_request/2 + An opaque request identifier. See + send_request/2 for details.

    + + + + +

    + An opaque collection of request identifiers + (request_id()) + where each request identifier can be associated with a label + chosen by the user. For more information see + reqids_new/0. +

    +
    +
    + + + + +

    + Used to set a time limit on how long to wait for a response using + either + receive_response/2, + receive_response/3, + wait_response/2, + or + wait_response/3. + The time unit used is millisecond. Currently valid values: +

    + + 0..4294967295 +

    + Timeout relative to current time in milliseconds. +

    + infinity +

    + Infinite timeout. That is, the operation will never time out. +

    + {abs, Timeout} +

    + An absolute + Erlang monotonic time + timeout in milliseconds. That is, the operation will time out when + erlang:monotonic_time(millisecond) + returns a value larger than or equal to Timeout. Timeout + is not allowed to identify a time further into the future than 4294967295 + milliseconds. Identifying the timeout using an absolute timeout value + is especially handy when you have a deadline for responses corresponding + to a complete collection of requests + (request_id_collection()) +, + since you do not have to recalculate the relative time until the deadline + over and over again. +

    +
    +
    +
    + + + + +

    + A map that describes the gen_statem status. + The keys are: +

    + + state + The current state of the gen_statem process. + data + The state data of the the gen_statem process. + reason + The reason that caused the state machine to terminate. + queue + The event queue of the gen_statem process. + postponed + + The postponed + events queue of the gen_statem process. + + timeouts + + The active + time-outs + of the gen_statem process. + + log + + The sys log of the server. + + +

    + New associations may be added to the status map + without prior notice. +

    +
    +
    @@ -1657,47 +1787,35 @@ handle_event(_, _, State, Data) -> which is the default. If no reply is received within the specified time, the function call fails.

    - -

    - For Timeout < infinity, - to avoid getting a late reply in the caller's - inbox if the caller should catch exceptions, - this function spawns a proxy process that - does the call. A late reply gets delivered to the - dead proxy process, hence gets discarded. This is - less efficient than using - Timeout == infinity. -

    -

    - Timeout can also be a tuple - {clean_timeout,T} or - {dirty_timeout,T}, where - T is the time-out time. - {clean_timeout,T} works like - just T described in the note above - and uses a proxy process - while {dirty_timeout,T} - bypasses the proxy process which is more lightweight. + Previous issue with late replies that could occur when having + network issues or using dirty_timeout is now prevented + by use of + process + aliases. {clean_timeout, T} + and {dirty_timeout, T} therefore no longer + serves any purpose and will work the same as + Timeout while all of them also being + equally efficient.

    - -

    - If you combine catching exceptions from this function - with {dirty_timeout,T} - to avoid that the calling process dies when the call - times out, you will have to be prepared to handle - a late reply. Note that there is an odd chance - to get a late reply even with - {dirty_timeout,infinity} or infinity - for example in the event of network problems. - So why not just let the calling process die - by not catching the exception? -

    -

    The call can also fail, for example, if the gen_statem dies before or during this function call.

    +

    + When this call fails it + exits + the calling process. + The exit term is on the form + {Reason, Location} where + Location = {gen_statem,call,ArgList}. + See + + gen_server:call/3 + + that has a description of relevant + values for the Reason in the exit term. +

    @@ -1722,15 +1840,15 @@ handle_event(_, _, State, Data) -> - + Check if a message is a reply from a server.

    - This function is used to check if a previously received - message, for example by receive or - handle_info/2, is a result of a request made with + Check if Msg is a response corresponding + to the request identifier ReqId. The request + must have been made by send_request/2. - If Msg is a reply to the handle RequestId + If Msg is a reply to the handle ReqId the result of the request is returned in Reply. Otherwise returns no_reply and no cleanup is done, and thus the function shall be invoked repeatedly until a reply @@ -1752,6 +1870,73 @@ handle_event(_, _, State, Data) -> + + + Check if a message is a reply from a server. + +

    + Check if Msg is a response corresponding + to a request identifier saved in ReqIdCollection. + All request identifiers of ReqIdCollection + must correspond to requests that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function. +

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id + in a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + check_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by check_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. If Msg + does not correspond to any of the request identifiers in + ReqIdCollection, the atom + no_reply is returned. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + check_response/3, + receive_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to check_response/3, it will always + return no_reply. +

    +
    +
    + Enter the gen_statem receive loop. @@ -1849,11 +2034,23 @@ handle_event(_, _, State, Data) -> - Receive for a reply from a server.

    - This function is used to receive for a reply of a request made with + The same as calling + gen_statem:receive_response(ReqId, + infinity). +

    +
    +
    + + + + Receive for a reply from a server. + +

    + Receive a response corresponding to the request identifier + ReqId- The request must have been made by send_request/2 to the gen_statem process. This function must be called from the same process from which @@ -1861,15 +2058,13 @@ handle_event(_, _, State, Data) -> was made.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. Defaults to - infinity. - If no reply is received within the specified - time, the function returns timeout. Assuming that the + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the server executes on a node supporting aliases (introduced in - OTP 24) no response will be received after a timeout. Otherwise, - a garbage response might be received at a later time. + OTP 24) the request will also be abandoned. That is, no + response will be received after a timeout. Otherwise, a + stray response might be received at a later time.

    The return value Reply is generated when a @@ -1886,11 +2081,92 @@ handle_event(_, _, State, Data) ->

    The difference between - wait_response() - and receive_response() is that receive_response() + wait_response/2 + and receive_response/2 is that receive_response/2 abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + response is ignored, while wait_response/2 does not. +

    +
    +
    + + + + Receive a response from a server. + +

    + Receive a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function.

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + adding the request id + in a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + receive_response/2, + the returned result associated with a specific request identifier + will be wrapped in a 3-tuple. The first element of this tuple equals + the value that would have been produced by receive_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, the atom + no_request will be returned. +

    +

    + Timeout specifies how long to wait for + a response. If no response is received within the specified time, + the function returns timeout. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) all requests identified by ReqIdCollection + will also be abandoned. That is, no responses will be received + after a timeout. Otherwise, stray responses might be received + at a later time. +

    +

    + The difference between receive_response/3 and + wait_response/3 + is that receive_response/3 abandons the requests at timeout + so that potential future responses are ignored, while + wait_response/3 does not. +

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + receive_response/3, + check_response/3, + and + wait_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to receive_response/3, it will always block + until a timeout determined by Timeout is + triggered. +

    @@ -1928,20 +2204,98 @@ handle_event(_, _, State, Data) ->
    - - Send a request to a gen_statem. + + Save a request identifier. +

    + Saves ReqId and associates a Label + with the request identifier by adding this information to + ReqIdCollection and returning the + resulting request identifier collection. +

    +
    +
    + + + + Create a new empty request identifier collection. + +

    + Returns a new empty request identifier collection. A + request identifier collection can be utilized in order + the handle multiple outstanding requests. +

    - Sends a request to the gen_statem - ServerRef - and returns a handle RequestId. -

    + Request identifiers of requests made by + send_request/2 + can be saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    +

    + reqids_size/1 + can be used to determine the amount of request identifiers in a + request identifier collection. +

    +
    +
    + + + + Get size of a request identifier collection. + +

    + Returns the amount of request identifiers saved in + ReqIdCollection. +

    +
    +
    + + + + List a request identifiers. +

    - The return value RequestId shall later be used with - receive_response/1,2, - wait_response/1,2, or + Returns a list of {ReqId, Label} + tuples which corresponds to all request identifiers with their + associated labels present in the ReqIdCollection + collection. +

    +
    +
    + + + + Send a request to a gen_statem. + +

    + Sends an asynchronous call request Request + to the gen_statem process identified by ServerRef + and returns a request identifier ReqId. The return + value ReqId shall later be used with + receive_response/2, + wait_response/2, or check_response/2 - to fetch the actual result of the request. + to fetch the actual result of the request. Besides passing + the request identifier directly to these functions, it can also be + saved in a request identifier collection using + reqids_add/3. + Such a collection of request identifiers can later be used in + order to get one response corresponding to a request in the + collection by passing the collection as argument to + receive_response/3, + wait_response/3, or + check_response/3. + If you are about to save the request identifier in a request identifier + collection, you may want to consider using + send_request/4 + instead.

    The call gen_statem:wait_response(gen_statem:send_request(ServerRef,Request), Timeout) @@ -1971,6 +2325,36 @@ handle_event(_, _, State, Data) -> + + + Sends a request to a generic server. + +

    + Sends an asynchronous call request Request + to the gen_statem process identified by ServerRef. + The Label will be associated with the request + identifier of the operation and added to the returned request + identifier collection NewReqIdCollection. + The collection can later be used in order to get one response + corresponding to a request in the collection by passing the + collection as argument to + receive_response/3, + wait_response/3, + or, + check_response/3. +

    + +

    + The same as calling + gen_statem:reqids_add(statem:send_request(ServerRef, + Request), Label, + ReqIdCollection), but calling send_request/4 + is slightly more efficient. +

    +
    +
    + @@ -2003,7 +2387,7 @@ handle_event(_, _, State, Data) -> (using proc_lib primitives) - that is linked to the calling process. + that is spawned as linked to the calling process. This is essential when the gen_statem must be part of a supervision tree so it gets linked to its supervisor.

    @@ -2013,15 +2397,15 @@ handle_event(_, _, State, Data) -> to initialize the server. To ensure a synchronized startup procedure, start_link/3,4 does not return until Module:init/1 - has returned. + has returned or failed.

    ServerName specifies the server_name() - to register for the gen_statem. - If the gen_statem is started with start_link/3, - no ServerName is provided and - the gen_statem is not registered. + to register for the gen_statem process. + If the gen_statem process is started with start_link/3, + no ServerName is provided and + the gen_statem process is not registered.

    Module is the name of the callback module.

    @@ -2037,9 +2421,9 @@ handle_event(_, _, State, Data) -> {timeout,Time} is present in - Opts, the gen_statem + Opts, the gen_statem process is allowed to spend Time milliseconds initializing - or it terminates and the start function returns + or it is terminated and the start function returns {error,timeout}.

    @@ -2049,9 +2433,11 @@ handle_event(_, _, State, Data) -> {hibernate_after,HibernateAfterTimeout} is present, the gen_statem - process awaits any message for HibernateAfterTimeout milliseconds and - if no message is received, the process goes into hibernation automatically - (by calling proc_lib:hibernate/3). + process awaits any message for HibernateAfterTimeout + milliseconds and if no message is received, + the process goes into hibernation automatically + (by calling + proc_lib:hibernate/3).

    @@ -2086,34 +2472,88 @@ handle_event(_, _, State, Data) ->

    - If the gen_statem is successfully created + If the gen_statem process is successfully created and initialized, this function returns {ok,Pid}, where Pid is the pid() - of the gen_statem. + of the gen_statem process. If a process with the specified ServerName exists already, this function returns - {error,{already_started,Pid}}, - where Pid is the pid() of that process. + {error,{already_started,OtherPid}}, + where OtherPid is the pid() of that process, + and the gen_statem process exits with reason normal + before calling + Module:init/1.

    +

    + If Module:init/1 + does not return within the + start timeout, + the gen_statem process is killed with + exit(_, kill), + and this function returns + {error,timeout}. +

    - If Module:init/1 fails with Reason, - this function returns - {error,Reason}. - If Module:init/1 returns - {stop,Reason} - or - ignore, - the process is terminated and this function - returns - {error,Reason} - or - ignore, - respectively. - An exit signal with the same Reason (or normal if - Module:init/1 returns ignore) is set to linked processes - and ports, including the process calling start_link/3,4. + This function returns + {error,Reason} if + Module:init/1 + returns + {stop,Reason} or + {error,Reason}, + or fails with reason Reason. + This function returns + ignore if + Module:init/1 + returns + ignore. + In these cases the gen_statem process exits + with reason Reason, except when Module:init/1 + returns ignore or {error,_}; + then the gen_statem process exits with reason normal. +

    +

    + If start_link/3,4 returns ignore or {error,_}, + the started gen_statem process has terminated. + If an 'EXIT' message was delivered to the calling process + (due to the process link), that message has been consumed.

    + +

    + Before OTP 26.0, if the started gen_statem process + returned e.g. {stop,Reason} from + Module:init/1, + this function could return {error,Reason} + before the started gen_statem process + had terminated so starting again might fail + because VM resources such as the registered name + was not yet unregistered, and an 'EXIT' message + could arrive later to the process calling this function. +

    +

    + But if the started gen_statem process instead + failed during + Module:init/1, + a process link {'EXIT',Pid,Reason} message + caused this function to return {error,Reason} + so the 'EXIT' message had been consumed + and the started gen_statem process had terminated. +

    +

    + Since it was impossible to tell the difference + between these two cases from + start_link/3,4's return value, + this inconsistency was cleaned up in OTP 26.0. +

    +
    +

    + The difference between returning + {stop,_} and {error,_} from + Module:init/1, + is that {error,_} results in a graceful ("silent") + termination since the gen_statem process + exits with reason normal. +

    @@ -2148,7 +2588,7 @@ handle_event(_, _, State, Data) -> - Synchronously stop a generic server. + Synchronously stop a gen_statem process.

    The same as @@ -2159,7 +2599,7 @@ handle_event(_, _, State, Data) -> - Synchronously stop a generic server. + Synchronously stop a gen_statem process.

    Orders the gen_statem @@ -2186,22 +2626,38 @@ handle_event(_, _, State, Data) -> terminate, or the atom infinity to wait indefinitely. Defaults to infinity. If the server does not terminate within the specified time, - a timeout exception is raised. -

    -

    - If the process does not exist, a noproc exception - is raised. + the call exits the calling process + with reason timeout.

    +

    + If the process does not exist, the call exits + the calling process with reason noproc, + and with reason {nodedown,Node} + if the connection fails to the remote Node + where the server runs. +

    - - + Wait for a reply from a server.

    - This function is used to wait for a reply of a request made with + The same as calling + gen_statem:receive_response(ReqId, + infinity). +

    +
    +
    + + + + Wait or poll for a reply from a server. + +

    + Wait for a response corresponding to the request identifier + ReqId. The request must have been made by send_request/2 to the gen_statem process. This function must be called from the same process from which @@ -2209,11 +2665,8 @@ handle_event(_, _, State, Data) -> was made.

    - Timeout is an integer greater then or equal to zero - that specifies how many milliseconds to wait for an reply, or - the atom infinity to wait indefinitely. Defaults to - infinity. - If no reply is received within the specified + WaitTime specifies how long to wait for + a reply. If no reply is received within the specified time, the function returns timeout and no cleanup is done, and thus the function can be invoked repeatedly until a reply is returned. @@ -2233,11 +2686,88 @@ handle_event(_, _, State, Data) ->

    The difference between - receive_response() - and wait_response() is that receive_response() + receive_response/2 + and wait_response/2 is that receive_response/2 abandons the request at timeout so that a potential future - response is ignored, while wait_response() does not. + response is ignored, while wait_response/2 does not. +

    +
    +
    + + + + Wait or poll for a response from a server. + +

    + Wait for a response corresponding to a request identifier saved + in ReqIdCollection. All request identifiers + of ReqIdCollection must correspond to requests + that have been made using + send_request/2 or + send_request/4, + and all requests must have been made by the process calling this + function. +

    +

    + The Label in the response equals the + Label associated with the request identifier + that the response corresponds to. The Label + of a request identifier is associated when + saving the request id in + a request identifier collection, or when sending the request using + send_request/4. +

    +

    + Compared to + wait_response/2, + the returned result associated with a specific request identifier + or an exception associated with a specific request identifier will + be wrapped in a 3-tuple. The first element of this tuple equals the + value that would have been produced by wait_response/2, + the second element equals the Label associated + with the specific request identifier, and the third element + NewReqIdCollection is a possibly modified + request identifier collection. +

    +

    + If ReqIdCollection is empty, no_request + will be returned. If no response is received before the + WaitTime timeout has triggered, the atom + timeout is returned. It is valid to continue waiting for a + response as many times as needed up until a response has been received + and completed by check_response(), receive_response(), + or wait_response(). +

    +

    + The difference between + receive_response/3 + and wait_response/3 is that receive_response/3 + abandons requests at timeout so that potential future + responses are ignored, while wait_response/3 does not.

    +

    + If Delete equals true, the association + with Label will have been deleted from + ReqIdCollection in the resulting + NewReqIdCollection. If + Delete equals false, + NewReqIdCollection will equal + ReqIdCollection. Note that deleting an + association is not for free and that a collection containing + already handled requests can still be used by subsequent calls to + wait_response/3, + check_response/3, + and + receive_response/3. + However, without deleting handled associations, the above calls will + not be able to detect when there are no more outstanding requests to + handle, so you will have to keep track of this some other way than + relying on a no_request return. Note that if you pass a + collection only containing associations of already handled or + abandoned requests to wait_response/3, it will always block + until a timeout determined by WaitTime is + triggered and then return no_reply. +

    @@ -2479,6 +3009,76 @@ init(Args) -> erlang:error(not_implemented, [Args]).
    + + Module:format_status(Status) -> NewStatus + Optional function for providing a term describing the + current gen_statem status. + + Status = format_status() + NewStatus = format_status() + + + +

    + This callback is optional, so a callback module does not need + to export it. The gen_statem module provides a default + implementation of this function that returns + {State,Data}. +

    +

    + If this callback is exported but fails, + to hide possibly sensitive data, + the default function will instead return {State,Info}, + where Info says nothing but the fact that + format_status/2 has crashed. +

    +
    +

    This function is called by a gen_statem process when + any of the following apply:

    + + +

    sys:get_status/1,2 + is invoked to get the gen_statem status.

    +
    + +

    The gen_statem process terminates abnormally and logs an error.

    +
    +
    +

    + This function is useful for changing the form and + appearance of the gen_statem status for these cases. A + callback module wishing to change the + sys:get_status/1,2 + return value and how + its status appears in termination error logs exports + an instance of format_status/1, + which will get a map Status that describes + the current states of the gen_statem, + and shall return a map NewStatus + containing the same keys as the input map, + but it may transform some values. +

    +

    + One use case for this function is to return compact alternative + state representations to avoid having large state terms + printed in log files. Another is to hide sensitive data from + being written to the error log. +

    +

    Example:

    + + maps:map( + fun(state,State) -> + maps:remove(private_key, State); + (message,{password, _Pass}) -> + {password, removed}; + (_,Value) -> + Value + end, Status). +]]> +
    +
    + Module:format_status(Opt, [PDict,State,Data]) -> Status @@ -2502,6 +3102,11 @@ init(Args) -> erlang:error(not_implemented, [Args]). Status = term() + +

    This callback is deprecated, in new code use + format_status/1. If a format_status/1 + callback exists, then this function will never be called.

    +

    This callback is optional, so a callback module does not need diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index a400d2af2334..c2215c821ed1 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -4,7 +4,7 @@

    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -41,7 +41,7 @@ protocols. Normally, it is a IoDevice returned by file:open/2. If no IoDevice is given, - standard_io is used.

    + standard_io is used.

    For a description of the I/O protocols, see section The Erlang I/O Protocol @@ -71,17 +71,82 @@ -

    An I/O device, either standard_io, standard_error, a - registered name, or a pid handling I/O protocols (returned from +

    An I/O device, either standard_io, standard_error, user, + a registered name, or a pid handling I/O protocols (returned from file:open/2).

    -

    For more information about the built-in devices see - Standard Input/Output - and Standard Error. + + + + + +

    All Erlang processes have a default standard I/O device. This + device is used when no IoDevice argument is specified in + the function calls in this module. However, it is sometimes desirable to + use an explicit IoDevice argument that refers to the + default I/O device. This is the case with functions that can + access either a file or the default I/O device. The atom + standard_io has this special meaning. The following example + illustrates this: +

    + +
    +27> io:read('enter>').
    +enter>foo.
    +{ok,foo}
    +28> io:read(standard_io, 'enter>').
    +enter>bar.
    +{ok,bar}
    + +

    By default all I/O sent to standard_io will en up in the + user I/O device of the node + that spawned the calling process. +

    + +

    standard_io is an alias for + group_leader/0, so in order to change where the default input/output + requests are sent you can change the group leader for the current process using + + group_leader(NewGroupLeader, self()). +

    + + + + + + +

    The I/O device standard_error can be used to direct + output to whatever the current operating system considers a suitable + I/O device for error output. This can be useful when standard output is + redirected. Example on a Unix-like operating system: +

    + +
    +$ erl -noinput -eval 'io:format(standard_error,"Error: ~s~n",["error 11"]),'\
    +'init:stop().' > /dev/null
    +Error: error 11
    +
    +
    + + + +

    An I/O device that can be used to interact with the node local + stdout and stdin. This can be either a terminal, + a pipe, a file, or a combination. You can use + getopts/0 to get more information about the + I/O device. +

    +

    See The Interactive Shell + and Escripts and non-interactive I/O + in the Using Unicode In Erlang User's Guide for details on how Unicode + is handled by user.

    + + + @@ -174,9 +239,38 @@ ok

    Mod is the control sequence modifier. This is one or more characters that change the interpretation of - Data. The current modifiers are t, for Unicode - translation, and l, for stopping p and P - from detecting printable characters.

    + Data.

    +

    The current modifiers are:

    + + t + +

    For Unicode translation.

    +
    + l + +

    For stopping p and P from detecting + printable characters.

    +
    + k + +

    For use with p, P, w, and W + to format maps in map-key ordered order (see + maps:iterator_order()).

    +
    + K + +

    Similar to k, for formatting maps in map-key order, + but takes an extra argument that specifies the + maps:iterator_order().

    +

    For example:

    +
    +> M = #{ a => 1, b => 2 }.
    +#{a => 1,b => 2}
    +> 
    +#{b => 2,a => 1}
    +ok
    +
    +

    If F, P, or Pad is a * character, @@ -711,7 +805,10 @@ enter>: alan : joelatin1 range). If the I/O server is set to deliver binaries, they are encoded in UTF-8 (regardless of whether - the I/O device supports Unicode).

    + the I/O device supports Unicode). If you want the data to + be returned as a latin1 encoded binary you should use + file:read/2 + instead.

    eof @@ -743,7 +840,10 @@ enter>: alan : joelatin1 range). If the I/O server is set to deliver binaries, they are encoded in UTF-8 (regardless of if - the I/O device supports Unicode).

    + the I/O device supports Unicode). If you want the data to + be returned as a latin1 encoded binary you should use + file:read_line/1 + instead.

    eof @@ -779,9 +879,17 @@ enter>: alan : joe + {encoding,unicode}, + {terminal,true}]

    This example is, as can be seen, run in an environment where the terminal supports Unicode input and output.

    +

    The terminal option is read only and indicates whether + the output stream is a terminal or not. When it is a terminal, + most systems that Erlang runs on allows the use of + ANSI escape codes + to control what the terminal outputs.

    +

    See setopts/1 for a description + of the other options.

    @@ -928,7 +1036,10 @@ enter>abc("hey". Write a list of characters.

    Writes the characters of CharData to the I/O - server (IoDevice).

    + server (IoDevice). If you want to write latin1 encoded + bytes to the I/O server you should use + file:write/2 + instead.

    @@ -1135,13 +1246,18 @@ enter>1.0er. get_line/1,2.

    The function is called with the current line, up to the cursor, as a reversed string. It is to return a - three-tuple: {yes|no, string(), [string(), ...]}. The + three-tuple: {yes|no, string(), list()}. The first element gives a beep if no, otherwise the expansion is silent; the second is a string that will be entered at the cursor position; the third is a list of possible expansions. If this list is not empty, - it is printed and the current input line is written - once again.

    + it is printed below the current input line. + The list of possible expansions can be formatted in + different ways to make more advanced expansion suggestions + more readable to the user, see + + edlin_expand:expand/2 for + documentation of that.

    Trivial example (beep on anything except empty line, which is expanded to "quit"):

    @@ -1169,13 +1285,23 @@ fun("") -> {yes, "quit", []}; is in {encoding, unicode} mode if the I/O device supports it. The mode can be changed, if the assumption of the runtime system is wrong, by setting this option.

    -

    The I/O device used when Erlang is started with the "-oldshell" - or "-noshell" flags is by default set to latin1 encoding, - meaning that any characters > codepoint 255 are escaped - and that input is expected to be plain 8-bit ISO Latin-1. - If the encoding is changed to Unicode, input and output from - the standard file descriptors are in UTF-8 (regardless of - operating system).

    +

    + Prior to OTP 26.0, when Erlang was started with the + -oldshell or -noshell flags (for example, in an + escript), the default encoding for + standard_io was set to latin1, meaning + that any characters > codepoint 255 were escaped and that input + was expected to be plain 8-bit ISO Latin-1. As of OTP 26.0, + standard_io always defaults + to unicode if its supported, otherwise latin1. +

    + If you want to send raw bytes on standard_io, + you now always need to explicitly set the encoding to latin1; + otherwise, code points 128-255 will be converted to UTF-8. + This is best done by setting the kernel configuration parameter + standard_io_encoding + to latin1. +

    Files can also be set in {encoding, unicode}, meaning that data is written and read as UTF-8. More encodings are possible for files, see below.

    @@ -1213,49 +1339,6 @@ fun("") -> {yes, "quit", []}; -
    - Standard Input/Output -

    All Erlang processes have a default standard I/O device. This - device is used when no IoDevice argument is specified in - the function calls in this module. However, it is sometimes desirable to - use an explicit IoDevice argument that refers to the - default I/O device. This is the case with functions that can - access either a file or the default I/O device. The atom - standard_io has this special meaning. The following example - illustrates this:

    - -
    -27> io:read('enter>').
    -enter>foo.
    -{ok,foo}
    -28> io:read(standard_io, 'enter>').
    -enter>bar.
    -{ok,bar}
    - -

    standard_io is an alias for - group_leader/0, so in order to change where the default input/output - requests are sent you can change the group leader for the current process using - - group_leader(NewGroupLeader, self()).

    - -

    There is always a process registered under the name of - user. This can be used for sending output to the user.

    -
    - -
    - Standard Error -

    In certain situations, especially when the standard output is - redirected, access to an I/O server specific for error messages can be - convenient. The I/O device standard_error can be used to direct - output to whatever the current operating system considers a suitable - I/O device for error output. Example on a Unix-like operating system:

    - -
    -$ erl -noshell -noinput -eval 'io:format(standard_error,"Error: ~s~n",["error 11"]),'\
    -'init:stop().' > /dev/null
    -Error: error 11
    -
    -
    Error Information

    The ErrorInfo mentioned in this module is the standard diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml index 3b7aea529e0b..f882e632bdd8 100644 --- a/lib/stdlib/doc/src/io_lib.xml +++ b/lib/stdlib/doc/src/io_lib.xml @@ -4,7 +4,7 @@

    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -92,6 +92,10 @@

    strings is set to false if modifier l is present.

    +

    maps_order is set to undefined by default, + ordered if modifier k is present, or reversed + or CmpFun if modifier K is present.

    +
    diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml index 67352543ec1d..1a7be2fdc590 100644 --- a/lib/stdlib/doc/src/io_protocol.xml +++ b/lib/stdlib/doc/src/io_protocol.xml @@ -5,7 +5,7 @@
    1999 - 2021 + 2023 Ericsson AB. All Rights Reserved. @@ -87,7 +87,7 @@

    ReplyAs can be any datum and is returned in the corresponding io_reply. The io module monitors the - the I/O server and uses the monitor reference as the ReplyAs + I/O server and uses the monitor reference as the ReplyAs datum. A more complicated client can have many outstanding I/O requests to the same I/O server and can use different references (or something else) to differentiate among the incoming I/O replies. @@ -449,10 +449,10 @@ ok columns. -

    The I/O server is to send the Reply as:

    +

    The I/O server is to send one of the following as Reply:

    -{ok, N}
    +N
     {error, Error}
    diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index f7b4506f14e8..8bf10b71b5ed 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -174,6 +174,38 @@ + + + + + Annotates elements with their index. + +

    Returns List1 with each element + H replaced by a tuple of form {I, H} where + I is the position of H in + List1. The enumeration starts with + Index and increases by Step + in each step.

    +

    That is, enumerate/3 behaves as if it had been defined as follows:

    + +enumerate(I, S, List) -> + {List1, _ } = lists:mapfoldl(fun(T, Acc) -> {{Acc, T}, Acc+S} end, I, List), + List1. +

    The default values for Index and + Step are both 1.

    +

    Examples:

    +
    +> lists:enumerate([a,b,c]).
    +[{1,a},{2,b},{3,c}]
    +
    +> lists:enumerate(10, [a,b,c]).
    +[{10,a},{11,b},{12,c}]
    +
    +> lists:enumerate(0, -2, [a,b,c]).
    +[{0,a},{-2,b},{-4,c}]
    +
    +
    + Select elements that satisfy a predicate. @@ -1027,35 +1059,69 @@ splitwith(Pred, List) -> + Zip two lists into a list of two-tuples. -

    "Zips" two lists of equal length into one list of two-tuples, +

    "Zips" two lists into one list of two-tuples, where the first element of each tuple is taken from the first list and the second element is taken from the corresponding element in the second list.

    +

    The How parameter specifies the behavior + if the given lists are of different lengths.

    + + fail + The call will fail if the given lists are not of equal + length. This is the default. + trim + Surplus elements from the longer list will be ignored. +

    Examples:

    +
    +> lists:zip([a, b], [1, 2, 3], trim).
    +[{a,1},{b,2}]
    +> lists:zip([a, b, c], [1, 2], trim).
    +[{a,1},{b,2}]
    +
    + {pad, Defaults} + The shorter list will be padded to the length of the + longer list, using the respective elements from the given + Defaults tuple. +

    Examples:

    +
    +> lists:zip([a, b], [1, 2, 3], {pad, {x, 0}}).
    +[{a,1},{b,2},{x,3}]
    +> lists:zip([a, b, c], [1, 2], {pad, {x, 0}}).
    +[{a,1},{b,2},{c,0}]
    +
    +
    + Zip three lists into a list of three-tuples. -

    "Zips" three lists of equal length into one list of +

    "Zips" three lists into one list of three-tuples, where the first element of each tuple is taken from the first list, the second element is taken from the corresponding element in the second list, and the third element is taken from the corresponding element in the third list.

    +

    For a description of the How parameter, see + zip/3.

    + Zip two lists into one list according to a fun. -

    Combines the elements of two lists of equal length into one list. +

    Combines the elements of two lists into one list. For each pair X, Y of list elements from the two lists, the element in the result list is Combine(X, Y).

    +

    For a description of the How parameter, see + zip/3.

    zipwith(fun(X, Y) -> {X,Y} end, List1, List2) is equivalent to zip(List1, List2).

    Example:

    @@ -1067,13 +1133,16 @@ splitwith(Pred, List) -> + Zip three lists into one list according to a fun. -

    Combines the elements of three lists of equal length into one +

    Combines the elements of three lists into one list. For each triple X, Y, Z of list elements from the three lists, the element in the result list is Combine(X, Y, Z).

    +

    For a description of the How parameter, see + zip/3.

    zipwith3(fun(X, Y, Z) -> {X,Y,Z} end, List1, List2, List3) is equivalent to zip3(List1, List2, List3).

    Examples:

    @@ -1084,6 +1153,43 @@ splitwith(Pred, List) -> [[a,x,1],[b,y,2],[c,z,3]]
    + + + + Removes duplicate elements of a list preserving the order. + +

    Returns a list containing the elements of + List1 with duplicated elements removed + (preserving the order of the elements). The first occurrence of + each element is kept.

    +

    Examples:

    +
    +> lists:uniq([3,3,1,2,1,2,3]).
    +[3,1,2]
    +> lists:uniq([a, a, 1, b, 2, a, 3]).
    +[a, 1, b, 2, 3]
    +
    +
    + + + + + Removes duplicate elements of a list using + a fun as a key preserving the order. + + +

    Returns a list containing the elements of + List1 without the elements for which + Fun returned duplicate values + (preserving the order of the elements). The first occurrence + of each element is kept.

    +

    Examples:

    +
    +> lists:uniq(fun({X, _}) -> X end, [{b, 2}, {a, 1}, {c, 3}, {a, 2}]).
    +[{b, 2}, {a, 1}, {c, 3}]
    +
    +
    + diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml index ea0f16eec91d..9113276aaf15 100644 --- a/lib/stdlib/doc/src/maps.xml +++ b/lib/stdlib/doc/src/maps.xml @@ -4,7 +4,7 @@
    - 20132021 + 20132023 Ericsson AB. All Rights Reserved. @@ -42,17 +42,43 @@

    An iterator representing the associations in a map with keys of type Key and values of type Value.

    -

    Created using maps:iterator/1.

    -

    Consumed by maps:next/1, - maps:filter/2, - maps:fold/3 and - maps:map/2.

    +

    Created using maps:iterator/1 or + maps:iterator/2.

    +

    Consumed by:

    + + maps:next/1 + maps:filter/2 + maps:filtermap/2 + maps:fold/3 + maps:foreach/2 + maps:map/2 + maps:to_list/1 +
    + + + + +

    Key-based iterator order option that can be one of undefined + (default for maps:iterator/1), + ordered (sorted in map-key order), reversed, + or a custom sorting function.

    +

    Used by maps:iterator/2.

    +

    The + + Expressions section contains descriptions of how terms are ordered.

    +
    +
    + + + + @@ -87,8 +113,7 @@ returns true, the association is copied to the result map. If it returns false, the association is not copied. If it returns {true, NewValue}, the value for Key is - replaced with NewValueat this position is replaced in the - result map.

    + replaced with NewValue in the result map.

    The call fails with a {badmap,Map} exception if MapOrIter is not a map or valid iterator, or with badarg if Fun is not a @@ -230,6 +255,51 @@ val1 + + + Partitions a list into groups using a function as discriminator. + +

    Partitions the given List into a map of groups.

    +

    The result is a map where each key is given by KeyFun + and each value is a list of elements from the given List + for which KeyFun returned the same key.

    +

    The order of elements within each group list is preserved from the original + list.

    +

    Examples:

    +
    +> EvenOdd = fun(X) -> case X rem 2 of 0 -> even; 1 -> odd end end,
    +maps:groups_from_list(EvenOdd, [1, 2, 3]).
    +#{even => [2], odd => [1, 3]}
    +> maps:groups_from_list(fun erlang:length/1, ["ant", "buffalo", "cat", "dingo"]).
    +#{3 => ["ant", "cat"], 5 => ["dingo"], 7 => ["buffalo"]}
    + + + + + + Partitions a list into groups using a function as discriminator. + +

    Partitions the given List into a map of groups.

    +

    The result is a map where each key is given by KeyFun + and each value is a list of elements from the given List, + mapped via ValueFun, for which KeyFun + returned the same key.

    +

    The order of elements within each group list is preserved from the + original list.

    +

    Examples:

    +
    +> EvenOdd = fun(X) -> case X rem 2 of 0 -> even; 1 -> odd end end,
    +> Square = fun(X) -> X * X end,
    +> maps:groups_from_list(EvenOdd, Square, [1, 2, 3]).
    +#{even => [4], odd => [1, 9]}
    +> maps:groups_from_list(
    +    fun erlang:length/1,
    +    fun lists:reverse/1,
    +    ["ant", "buffalo", "cat", "dingo"]).
    +#{3 => ["tna", "tac"],5 => ["ognid"],7 => ["olaffub"]}
    +
    +
    + @@ -323,6 +393,59 @@ none
    + + + Create a map iterator. + +

    Returns a map iterator Iterator that can + be used by maps:next/1 + to traverse the key-value associations in a map sorted by key using + the given Order.

    +

    The call fails with a {badmap,Map} exception if + Map is not a map or if Order + is invalid.

    +

    Example (when Order is ordered):

    + M = #{ a => 1, b => 2 }. +#{a => 1,b => 2} +> OrdI = maps:iterator(M, ordered), ok. +ok +> {K1, V1, OrdI2} = maps:next(OrdI), {K1, V1}. +{a,1} +> {K2, V2, OrdI3} = maps:next(OrdI2),{K2, V2}. +{b,2} +> maps:next(OrdI3). +none + ]]> +

    Example (when Order is reversed):

    + M = #{ a => 1, b => 2 }. +#{a => 1,b => 2} +> RevI = maps:iterator(M, reversed), ok. +ok +> {K2, V2, RevI2} = maps:next(RevI), {K2, V2}. +{b,2} +> {K1, V1, RevI3} = maps:next(RevI2),{K1, V1}. +{a,1} +> maps:next(RevI3). +none + ]]> +

    Example (when Order is an arithmetic sorting function):

    + M = #{ -1 => a, -1.0 => b, 0 => c, 0.0 => d }. +#{-1 => a,0 => c,-1.0 => b,0.0 => d} +> ArithOrdI = maps:iterator(M, fun(A, B) -> A =< B end), ok. +ok +> maps:to_list(ArithOrdI). +[{-1,a},{-1.0,b},{0,c},{0.0,d}] +> ArithRevI = maps:iterator(M, fun(A, B) -> B < A end), ok. +ok +> maps:to_list(ArithRevI). +[{0.0,d},{0,c},{-1.0,b},{-1,a}] + ]]> +
    +
    + @@ -537,15 +660,24 @@ error

    Returns a list of pairs representing the key-value associations of - Map, where the pairs + MapOrIterator, where the pairs [{K1,V1}, ..., {Kn,Vn}] are returned in arbitrary order.

    The call fails with a {badmap,Map} exception if - Map is not a map.

    + MapOrIterator is not a map or an iterator obtained + by a call to iterator/1 or + iterator/2.

    Example:

    > Map = #{42 => value_three,1337 => "value two","a" => 1}, maps:to_list(Map). [{42,value_three},{1337,"value two"},{"a",1}] +

    Example (using iterator/2):

    + Map = #{ z => 1, y => 2, x => 3 }. +#{x => 3,y => 2,z => 1} +> maps:to_list(maps:iterator(Map, ordered)). +[{x,3},{y,2},{z,1}] + ]]>
    @@ -606,7 +738,7 @@ error maps:update_with("new counter",Fun,42,Map). #{"counter" => 1,"new counter" => 42} - + @@ -657,5 +789,6 @@ error #{1337 => "value two"} + diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index 59a05a4e5a4b..c0b0d60f61f8 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -5,7 +5,7 @@
    1996 - 2020 + 2023 Ericsson AB, All Rights Reserved @@ -102,9 +102,20 @@ erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt. - A useful number. + Ratio of the circumference of a circle to its diameter. -

    A useful number.

    +

    Ratio of the circumference of a circle to its diameter.

    +

    Floating point approximation of mathematical constant pi.

    +
    +
    + + + + Ratio of the circumference of a circle to its radius. + +

    Ratio of the circumference of a circle to its radius.

    +

    This constant is equivalent to a full turn when described in radians.

    +

    The same as 2 * pi().

    diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml index bde9223eb02c..2df25805f056 100644 --- a/lib/stdlib/doc/src/ms_transform.xml +++ b/lib/stdlib/doc/src/ms_transform.xml @@ -4,7 +4,7 @@
    - 20022020 + 20022021 Ericsson AB. All Rights Reserved. @@ -389,8 +389,8 @@ ets:select(emp_tab, ets:fun2ms(

    The guard BIFs: abs, element, hd, length, - node, round, size, tl, trunc, - self

    + node, round, size, byte_size, tl, + trunc, binary_part, self

    diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index f5cdacc21952..b8d86e6745f8 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 20042021 + 20042023 Ericsson AB. All Rights Reserved. @@ -31,6 +31,1418 @@

    This document describes the changes made to the STDLIB application.

    +
    STDLIB 5.1.1 + +
    Improvements and New Features + + +

    + Garbage collect the shell process when reducing the + amount of saved history and results.

    +

    + Own Id: OTP-18773 Aux Id: PR-7691

    +
    +
    +
    + +
    + +
    STDLIB 5.1 + +
    Fixed Bugs and Malfunctions + + +

    The compiler could run forever when compiling a call + to is_record/3 with a huge positive tuple size. + The call is_record(A, a, 0) would crash the + compiler when used in a function body. When used in a + guard the compiler would emit incorrect code that would + accept {a> as a record.

    +

    + Own Id: OTP-18605 Aux Id: GH-7298, GH-7317

    +
    + +

    + Fix bug in ets:tab2file that could make it fail if + another Erlang process created the same file at the same + time.

    +

    + Own Id: OTP-18614 Aux Id: GH-7162, PR-7237

    +
    + +

    An {else_clause,Value} exception will now be + reported nicely in the shell.

    +

    + Own Id: OTP-18616 Aux Id: GH-7258

    +
    + +

    + Correct return value for error case, so that it matches + the documented and intended return value {error, + {already_started, pid()} when local registered names are + used.

    +

    + Own Id: OTP-18627 Aux Id: PR-7072

    +
    + +

    sys:get_state/1,2 and + sys:replace_state/2,3 has been corrected to handle + a state named error as a state name, not as a + failed system callback.

    For the standard server + behaviours this was an issue only for gen_statem + (and gen_fsm) when the state name was + error, and for gen_server if the complete + state was {error,_}.

    +

    + Own Id: OTP-18633

    +
    + +

    Multiple problems were fixed in + filelib:safe_relative_path/2. If its second + argument was a path that contained symbolic links, an + incorrect result patch could be returned. Also, paths + were sometimes falsely considered unsafe.

    +

    + Own Id: OTP-18655 Aux Id: GH-6460, PR-7208

    +
    + +

    + Fix deadlock when erl.exe is used as part of a + pipe on Windows and trying to set the encoding of the + standard_io device.

    +

    + Own Id: OTP-18675 Aux Id: PR-7473 GH-7459

    +
    + +

    + Expanded the documentation about how to use the + standard_io, standard_error and user + I/O devices.

    +

    + Added the types io:standard_io/0, + io:standard:error/0 and io:user/0.

    +

    + Own Id: OTP-18676 Aux Id: PR-7473 GH-7459

    +
    + +

    + Fix h/2,3 to properly render multi-clause + documentation.

    +

    + Own Id: OTP-18683 Aux Id: PR-7502

    +
    + +

    Timers created by timer:apply_after/4, + apply_interval/4, and apply_repeatedly/4 + would silently fail to do the apply if it was not + possible to spawn a process when the timer expired. This + has now been corrected, and if the spawn fails, the + system will be taken down producing a crash dump.

    +

    + Own Id: OTP-18759 Aux Id: GH-7606

    +
    + +

    When an Erlang source file lacked a module definition, + there would be a spurious "module name must not be empty" + diagnostic for each spec in the file.

    +

    + Own Id: OTP-18763 Aux Id: GH-7655

    +
    +
    +
    + + +
    Improvements and New Features + + +

    The argument descriptions for option types in + argparse have been made less ambiguous.

    +

    + Own Id: OTP-18679 Aux Id: ERIERL-965

    +
    + +

    Clarified the documentation of normal shutdown reason + on gen_server:call/2,3

    +

    + Own Id: OTP-18690 Aux Id: PR-7511, GH-7510

    +
    + +

    Pattern matching and equivalence (=:=, + =/=) comparisons on 0.0 will now raise a + warning, as it will no longer be considered equivalent to + -0.0 in OTP 27.

    If a match on 0.0 + specifically is desired (distinct from -0.0), the + warning can be suppressed by writing +0.0 + instead.

    The arithmetic comparison operators are + unaffected, including arithmetic equality + (==).

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18696

    +
    + +

    + The semantics of the gen_{server,statem,event} + behaviour's synchronous start behaviour introduced in + OTP-26.0 with OTP-18471, has been clarified in the + documentation.

    +

    + Own Id: OTP-18705 Aux Id: GH-7524, OTP-18471, GH-6339, + PR-6843

    +
    + +

    + Added functionality to set a custom multiline prompt.

    +

    + Own Id: OTP-18736 Aux Id: PR-7564

    +
    + +

    + A warning for (accidental use of) Triple-Quoted Strings + has been implemented as per EEP + 64.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18746 Aux Id: PR-7313, PR-7456

    +
    + +

    + The keyboard shortcuts for the shell are now + configurable.

    +

    + Own Id: OTP-18754 Aux Id: PR-7604 PR-7647

    +
    +
    +
    + +
    + +
    STDLIB 5.0.2 + +
    Fixed Bugs and Malfunctions + + +

    + Fix bug where when you entered Alt+Enter in the terminal, + the cursor would move to the last line, instead of moving + to the next line.

    +

    + Own Id: OTP-18580 Aux Id: PR-7242

    +
    + +

    + Fix eof handling when reading from stdin when erlang is + started using -noshell.

    +

    + Own Id: OTP-18640 Aux Id: PR-7384 GH-7368 GH-7286 GH-6881

    +
    + +

    + Fixed problem where output would disappear if it was + received after a prompt was written in the shell.

    +

    + Own Id: OTP-18652 Aux Id: PR-7242

    +
    + +

    The following functions are now much faster when given + a long list or binary:

    + erlang:list_to_integer/1 + erlang:binary_to_integer/1 + erlang:binary_to_integer/2 + erlang:list_to_integer/2 + string:to_integer/1 +

    + Own Id: OTP-18659 Aux Id: PR-7426

    +
    +
    +
    + +
    + +
    STDLIB 5.0.1 + +
    Fixed Bugs and Malfunctions + + +

    The POSIX error exdev was sometimes incorrectly + described as "cross domain link" in some error + messages.

    +

    + Own Id: OTP-18578 Aux Id: GH-7213

    +
    +
    +
    + +
    + +
    STDLIB 5.0 + +
    Fixed Bugs and Malfunctions + + +

    + All process calls in dets have been updated to use + the receive queue optimizations.

    +

    + Own Id: OTP-18275 Aux Id: PR-6045

    +
    + +

    proc_lib:start*/* has become synchronous when + the started process fails. This requires that a failing + process use a new function proc_lib:init_fail/2,3, + or exits, to indicate failure. All OTP behaviours have + been fixed to do this.

    All these start functions + now consume the 'EXIT' message from a process link + for all error returns. Previously it was only the + start_link/* functions that did this, and only + when the started function exited, not when it used + init_ack/1,2 or init_fail/2,3 to create the + return value.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18471 Aux Id: GH-6339, PR-6843

    +
    + +

    Fixed a bug where file:read(standard_io, ...) + unexpectedly returned eof in binary mode.

    +

    + Own Id: OTP-18486 Aux Id: PR-6881

    +
    + +

    In the shell, v(N) would fail to retrieve the + command if the command's return value was + undefined.

    +

    + Own Id: OTP-18548 Aux Id: PR-6967

    +
    +
    +
    + + +
    Improvements and New Features + + +

    The Erlang shell has been improved to support the + following features:

    Auto-complete + variables, record names, record field names, map keys, + function parameter types and filenames. Open + external editor in the shell (with C-o) to edit the + current expression in an editor. Support + defining records (with types), functions and function + typespecs, and custom types in the shell. Do + not save pager commands, and input to io:getline in + history. +

    + Own Id: OTP-14835 Aux Id: PR-5924

    +
    + +

    + Gen_server now caches external functions for use in + handle_call, handle_cast and handle_info.

    +

    + Own Id: OTP-15597 Aux Id: PR-5831

    +
    + +

    The TTY/terminal subsystem has been rewritten by + moving more code to Erlang from the old linked-in driver + and implementing all the I/O primitives needed in a NIF + instead.

    On Unix platforms the user should not + notice a lot of difference, besides better handling of + unicode characters and fixing of some long standing bugs. +

    Windows users will notice that erl.exe has the + same functionality as a normal Unix shell and that + werl.exe has been removed and replaced with a symlink to + erl.exe. This makes the Windows Erlang terminal + experience identical to that of Unix.

    The + re-write brings with it a number of bug fixes and feature + additions:

    The TTY is now reset when + Erlang exits, fixing zsh to not break when terminating an + Erlang session. standard_error now + uses the same unicode mode as standard_io. + Hitting backspace when searching the shell history + with an empty search string no longer breaks the + shell. Tab expansion now works on remote + nodes started using the JCL interface. It is + now possible to configure the shell slogan and the + session slogans (that is the texts that appear when you + start an Erlang shell). See the kernel documentation for + more details. Added shell:start_interactive + for starting the interactive shell from a non-interactive + Erlang session (for example an escript). On + Windows, when starting in detached mode the standard + handler are now set to nul devices instead of + being unset. Standard I/O now always + defaults to unicode mode if supported. Previously + the default was latin1 if the runtime system had + been started with -oldshell or -noshell + (for example in an escript). To send raw bytes + over standard out, one now explicitly has to specify + io:setopts(standard_io, [{encoding, latin1}]). + +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17932 Aux Id: PR-6144 GH-3150 GH-3390 GH-4343 + GH-4225

    +
    + +

    Added the zip:zip_get_crc32/2 function to + retrieve the CRC32 checksum from an opened ZIP + archive.

    +

    + Own Id: OTP-18159 Aux Id: PR-6904

    +
    + +

    + Added the options post_process_args and + detached to the peer:start function.

    +

    + Own Id: OTP-18176 Aux Id: PR-6118

    +
    + +

    The re:replace/3,4 functions now accept a fun + as the replacement argument.

    +

    + Own Id: OTP-18221 Aux Id: PR-6197

    +
    + +

    The performance of the base64 module has been + significantly improved. For example, on an x86_64 system + with the JIT both encode and decode are more than three + times faster than in Erlang/OTP 25.

    +

    + Own Id: OTP-18228 Aux Id: GH-5639

    +
    + +

    + Improved implementation of timer:apply_interval/4 + reducing load on the timer server, and introduction of + the new function timer:apply_repeatedly/4. + timer:apply_repeatedly/4 is similar to + timer:apply_interval/4, but + timer:apply_repeatedly/4 prevents parallel + execution of triggered apply operations which + timer:apply_interval/4 does not.

    +

    + Own Id: OTP-18236 Aux Id: PR-6256

    +
    + +

    The base64 module now supports encoding and + decoding with an alternate URL safe alphabet, and an + option for accepting or adding missing = padding + characters.

    +

    + Own Id: OTP-18247 Aux Id: PR-6280, PR-6711

    +
    + +

    + Add shell:whereis/0 which can be used to locate + the current shell process.

    +

    + Own Id: OTP-18272 Aux Id: PR-6279

    +
    + +

    + The Erlang shell's auto-completion when typing tab + has been changed to happen after the editing current line + instead of before it.

    +

    + This behaviour can be configured using a the + shell_expand_location STDLIB configuration + parameter.

    +

    + Own Id: OTP-18278 Aux Id: PR-6260

    +
    + +

    + New function ets:lookup_element/4 with a + Default argument returned if the key did not exist + in the table. The old ets:lookup_element/3 raises + a badarg exception which can be both inconvenient + and slower.

    +

    + Own Id: OTP-18279 Aux Id: PR-6234

    +
    + +

    + Typing Ctrl+L in a shell now clears the screen and + redraws the current line instead of only redrawing the + current line. To only redraw the current line, you must + now type Alt+L. This brings the behaviour of + Ctrl+L closer to how bash and other shells work.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18285 Aux Id: PR-6262

    +
    + +

    + peer nodes using standard_io connections + now include standard error from the node in the io stream + from the started node.

    +

    + Own Id: OTP-18287 Aux Id: PR-5955

    +
    + +

    A limitation in the binary syntax has been removed. It + is now possible to match binary patterns in parallel. + Example: <<A:8>> = <<B:4,C:4>> + = Bin

    +

    + Own Id: OTP-18297 Aux Id: GH-6348

    +
    + +

    + Improve type specification of + unicode:characters_to_list().

    +

    + Own Id: OTP-18301 Aux Id: PR-6350

    +
    + +

    In the lists module, the zip family of + functions now takes options to allow handling lists of + different lengths.

    +

    + Own Id: OTP-18318 Aux Id: PR-6347

    +
    + +

    It is documented that $\^X is the ASCII code + for Control X, where X is an uppercase or lowercase + letter. However, this notation would work for any + character X, even then it didn't make sense.

    +

    In Erlang/OTP 26, it is now documented that the + following characters are also allowed to follow the + \^ characters: @, [, \, + ], ^, _, and ?. Attempt to + use other characters will be rejected with a compiler + error.

    +

    The value for $\^? is now 127 (instead of 31 as + in earlier releases).

    +

    + Own Id: OTP-18337 Aux Id: GH-6477, PR-6503

    +
    + +

    The binary:encode_hex/2 function has been added + to allow the encoded hexadecimal digits to be in either + lower or upper case.

    +

    + Own Id: OTP-18354 Aux Id: PR-6297

    +
    + +

    + Variants of timer:tc() with user specified time + unit have been introduced.

    +

    + Own Id: OTP-18355 Aux Id: PR-6507

    +
    + +

    + New function math:tau/0. Returns + 2*math:pi().

    +

    + Own Id: OTP-18361 Aux Id: PR-6536

    +
    + +

    The BIFs min/2 and max/2 are now allowed + to be used in guards and match specs.

    +

    + Own Id: OTP-18367 Aux Id: GH-6544

    +
    + +

    + Optimized gen_server:multi_call().

    +

    + Own Id: OTP-18385 Aux Id: PR-6698

    +
    + +

    Map comprehensions as suggested in EEP 58 has now been + implemented.

    +

    + Own Id: OTP-18413 Aux Id: EEP-58, PR-6727

    +
    + +

    Some map operations have been optimized by changing + the internal sort order of atom keys. This changes the + (undocumented) order of how atom keys in small maps are + printed and returned by maps:to_list/1 and + maps:next/1. The new order is unpredictable and + may change between different invocations of the Erlang + VM.

    +

    For applications where order is important, there is a + new function maps:iterator/2 for creating + iterators that return the map elements in a deterministic + order. There are also new modifiers k and K + for the format string for io:format() to support + printing map elements ordered.

    +

    + Own Id: OTP-18414 Aux Id: PR-6151

    +
    + +

    + Make gen_server fail "silently" with a new return value + for init/1.

    +

    + Own Id: OTP-18423 Aux Id: + https://github.com/erlang/backlog/issues/142

    +
    + +

    Improved the selective receive optimization, which can + now be enabled for references returned from other + functions.

    +

    This greatly improves the performance of + gen_server:send_request/3, + gen_server:wait_response/2, and similar + functions.

    +

    + Own Id: OTP-18431 Aux Id: PR-6739

    +
    + +

    It is no longer necessary to enable a feature in the + runtime system in order to load modules that are using + it. It is sufficient to enable the feature in the + compiler when compiling it.

    +

    That means that to use feature maybe_expr in + Erlang/OTP 26, it is sufficient to enable it during + compilation.

    +

    In Erlang/OTP 27, feature maybe_expr will be + enabled by default, but it will be possible to disable + it.

    +

    + Own Id: OTP-18445

    +
    + +

    + Static supervisors are very idle processes after they + have started so they will now be hibernated after start + to improve resource management.

    +

    + Own Id: OTP-18474 Aux Id: PR-6895

    +
    + +

    + Deprecates dbg:stop_clear/0 because it is simply a + function alias to dbg:stop/0

    +

    + Own Id: OTP-18478 Aux Id: GH-6903

    +
    + +

    Support has been added in ms_transform for the + actions caller_line/0, + current_stacktrace/0, and + current_stacktrace/1.

    +

    + Own Id: OTP-18494 Aux Id: PR-6924

    +
    + +

    The family of enumeration functions in module + lists has been extended with enumerate/3 + that allows a step value to be supplied.

    +

    + Own Id: OTP-18495 Aux Id: PR-6943

    +
    + +

    + Update Unicode to version 15.0.0.

    +

    + Own Id: OTP-18500

    +
    + +

    The regular expression library powering the re + module is likely to be changed in Erlang/OTP 27. See + Upcoming + Potential Incompatibilities.

    +

    + Own Id: OTP-18511 Aux Id: PR-7017

    +
    + +

    Improved the performance of sets:subtract/2 + when subtracting a small number of elements.

    +

    + Own Id: OTP-18515 Aux Id: GH-6990

    +
    + +

    The linter will no longer raise warnings for + underspecified opaque types.

    +

    + Own Id: OTP-18518 Aux Id: GH-7015

    +
    + +

    Added the new built-in type dynamic() + introduced in EEP-61, improving support for gradual type + checkers.

    +

    + Own Id: OTP-18522

    +
    + +

    + The by gen_statem previously used call proxy + process that was used for preventing late replies from + reaching the client at timeout or connection loss has + been removed. It is no longer needed since process + aliases take care of this, are used, and supported by + all Erlang nodes that an OTP 26 Erlang node can + communicate with.

    +

    + Own Id: OTP-18537 Aux Id: PR-7081

    +
    + +

    Added the argparse module for simplified + argument handling in escripts and similar.

    +

    + Own Id: OTP-18558 Aux Id: PR-6852

    +
    + +

    Added support for multiple line expressions and + navigation in the shell. Added new keybindings:

    + navigate up (ctrl+up)/(alt+up) + navigate down (ctrl+down)/(alt+down) + insert newline in middle of line (alt+enter) + navigate top (alt+<)/(alt+shift+up) + navigate bottom + (alt+>)/(alt+shift+down) clear current + expression (alt+c) cancel search (alt+c) + opening editor on mac (option+o)/(alt+o) +

    Modifies the prompt for new lines to + make it clearer that the prompt has entered multi-line + mode. Supports terminal with small window size, recommend + not go lower than 7 rows and 40 columns. Modifies the + search prompt to support multi-line statements. Redraw + the prompt after continuing from JCL menu.

    +

    + Own Id: OTP-18575 Aux Id: PR-7169

    +
    +
    +
    + +
    + +
    STDLIB 4.3.1.2 + +
    Fixed Bugs and Malfunctions + + +

    The following functions are now much faster when given + a long list or binary:

    + erlang:list_to_integer/1 + erlang:binary_to_integer/1 + erlang:binary_to_integer/2 + erlang:list_to_integer/2 + string:to_integer/1 +

    + Own Id: OTP-18659 Aux Id: PR-7426

    +
    +
    +
    + +
    + +
    STDLIB 4.3.1.1 + +
    Improvements and New Features + + +

    + Static supervisors are very idle processes after they + have started so they will now be hibernated after start + to improve resource management.

    +

    + Own Id: OTP-18556

    +
    +
    +
    + +
    + +
    STDLIB 4.3.1 + +
    Fixed Bugs and Malfunctions + + +

    The type specs in the erl_parse module has been + updated to include the maybe construct and the + ! operator.

    +

    + Own Id: OTP-18506 Aux Id: GH-6956

    +
    +
    +
    + +
    + +
    STDLIB 4.3 + +
    Fixed Bugs and Malfunctions + + +

    Fixed a bug that would cause analysis to crash.

    +

    + Own Id: OTP-18372 Aux Id: GH-6580

    +
    + +

    Fixed a crash when formatting stack traces for error + reports.

    +

    + Own Id: OTP-18375 Aux Id: GH-6591

    +
    + +

    Instead of crashing, the list_to_integer/1 and + list_to_integer/2 BIFs now raise the + system_limit exception for overlong lists that + can't be converted to integers. Similarly, the + string:to_integer/1 BIF now returns + {error,system_limit} for overlong lists.

    +

    + Own Id: OTP-18475 Aux Id: PR-6897

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Removal of non-necessary undefined types added to + the state's supervisor record.

    +

    + Own Id: OTP-18393 Aux Id: PR-6666

    +
    +
    +
    + +
    + +
    STDLIB 4.2 + +
    Fixed Bugs and Malfunctions + + +

    erl_tar can now read gzip-compressed tar files + that are padded. There is a new option + compressed_one for file:open/2 that will + read a single member from a gzip file,

    +

    + Own Id: OTP-18289 Aux Id: PR-6343

    +
    + +

    + A concurrent call to ets:rename could cause + ets:delete_all_objects to fail halfway through + with badarg.

    +

    + Own Id: OTP-18292 Aux Id: PR-6366

    +
    + +

    It is not allowed to call functions from guards. The + compiler failed to reject a call in a guard when done by + constructing a record with a default initialization + expression that called a function.

    +

    + Own Id: OTP-18325 Aux Id: GH-6465, GH-6466

    +
    + +

    The compiler could crash when using a record with + complex field initialization expression as a filter in a + list comprehension.

    +

    + Own Id: OTP-18336 Aux Id: GH-6501, PR-6502

    +
    + +

    + unicode:characters_to_binary() could build + unnecessarily large call stack.

    +

    + Own Id: OTP-18351 Aux Id: ERIERL-885, PR-6529

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Improve error message for ets:new/2 name clash. Say "name + already exists" instead of less specific "invalid + options".

    +

    + Own Id: OTP-18283 Aux Id: PR-6338

    +
    +
    +
    + +
    + +
    STDLIB 4.1.1 + +
    Fixed Bugs and Malfunctions + + +

    + peer nodes + failed to halt when the process supervising the control + connection crashed. When an alternative control + connection was used, this supervision process also quite + frequently crashed when the peer node was stopped + by the node that started it which caused the peer + node to linger without ever halting.

    +

    + Own Id: OTP-18249 Aux Id: PR-6301

    +
    +
    +
    + +
    + +
    STDLIB 4.1 + +
    Fixed Bugs and Malfunctions + + +

    + Fixed inconsistency bugs in global due to + nodeup/nodedown messages not being + delivered before/after traffic over connections. Also + fixed various other inconsistency bugs and deadlocks in + both global_group + and global.

    +

    + As building blocks for these fixes, a new BIF erlang:nodes/2 + has been introduced and net_kernel:monitor_nodes/2 + has been extended.

    +

    + The -hidden and + -connect_all + command line arguments did not work if multiple instances + were present on the command line which has been fixed. + The new kernel parameter connect_all + has also been introduced in order to replace the + -connect_all command line argument.

    +

    + Own Id: OTP-17934 Aux Id: PR-6007

    +
    + +

    + Fix the public_key:ssh* functions to be listed + under the correct release in the Removed Functionality + User's Guide.

    +

    + Own Id: OTP-18139 Aux Id: PR-6060

    +
    + +

    + The type spec for format_status/1 in + gen_statem, gen_server and gen_event + has been corrected to state that the return value is of + the same type as the argument (instead of the same value + as the argument).

    +

    + Own Id: OTP-18142 Aux Id: PR-6078

    +
    + +

    + If the timer server child spec was already present + in kernel_sup but it was not started, the + timer server would fail to start with an + {error, already_present} error instead of + restarting the server.

    +

    + Own Id: OTP-18146 Aux Id: PR-5983

    +
    + +

    When changing callback module in gen_statem the + state_enter calls flag from the old module was used in + for the first event in the new module, which could + confuse the new module and cause malfunction. This bug + has been corrected.

    With this change some + sys debug message formats have been modified, + which can be a problem for debug code relying on the + format.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18239

    +
    +
    +
    + + +
    Improvements and New Features + + +

    There is a new configure option, + --enable-deterministic-build, which will apply the + deterministic compiler option when building + Erlang/OTP. The deterministic option has been + improved to eliminate more sources of non-determinism in + several applications.

    +

    + Own Id: OTP-18165 Aux Id: PR-5965

    +
    + +

    The rfc339_to_system_time/1,2 functions now + allows the minutes part to be omitted from the time + zone.

    +

    + Own Id: OTP-18166 Aux Id: PR-6108

    +
    + +

    + The receive statement in gen_event has been + optimized to not use selective receive (which was never + needed, and could cause severe performance degradation + under heavy load).

    +

    + Own Id: OTP-18194 Aux Id: PR-6199

    +
    + +

    + Add new API function erl_features:configurable/0

    +

    + Own Id: OTP-18199 Aux Id: PR-5790

    +
    +
    +
    + +
    + +
    STDLIB 4.0.1 + +
    Fixed Bugs and Malfunctions + + +

    + In the initial release of Erlang/OTP 25, the expression + bound to the _ pseudo-field in a record + initialization would always be evaluated once, even if + all other fields in the record were explicitly + initialized. That would break the use case of binding the + expression error(...) to _ in order to get + an exception if not all fields were initialized.

    +

    + The behavior of binding to _ has been reverted to + the pre-OTP 25 behavior, that is, to not evaluate the + expression if all fields have been bound to explicit + values.

    +

    + Own Id: OTP-18110 Aux Id: GH-6000

    +
    +
    +
    + +
    + +
    STDLIB 4.0 + +
    Fixed Bugs and Malfunctions + + +

    + Improve the Erlang code linter's check of unused types.

    +

    + Own Id: OTP-17370 Aux Id: GH-4784

    +
    + +

    + Fix race condition in proc_lib:stop/3 + where the process is not stopped when the timeout given + is very short.

    +

    + Own Id: OTP-17480 Aux Id: GH-4853 PR-4872

    +
    + +

    Maps are now fully supported in by + ms_transform.

    +

    + Own Id: OTP-17518 Aux Id: GH-4915

    +
    + +

    + Fix gen_server:call with the first argument as self() to + throw an error instead of failing with a timeout.

    +

    + The same fix has also been done for gen_statem:call/3, + gen_event:sync_notify/2 and any other functionality + relying on the internal gen:call/3 function.

    +

    + A similar fix was also done when using io:format/2 and + the current group_leader was set to the current process.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17544 Aux Id: PR-5008

    +
    + +

    + erl_pp printed unary - and + operators with a space + between the operator and the operand. This is fixed by + not having any space in between.

    +

    + Own Id: OTP-17566 Aux Id: PR-5095, GH-5093

    +
    + +

    + Adjust uri_string:normalize behavior for URIs with + undefined port (URI string with a port colon but no port + value or URI map with port => undefined).

    +

    + Remove redundant normalization from http_request module.

    +

    + Before this change, normalize would not remove port + subcomponent in such cases and could for example return + "http://localhost:" URI.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17627

    +
    + +

    + Fix reduction counting bug in re:run that caused + the function to yield too frequently when doing + global matches.

    +

    + Own Id: OTP-17661 Aux Id: PR-5165

    +
    + +

    + Fix the memory value returned from + ets:info(Tid,memory) when the + read_concurrency option is used.

    +

    + Before this fix the memory used by the scheduler specific + lock cache lines was not counted towards the total. This + caused the returned memory usage to be very incorrect on + systems with many schedulers for tables with man locks.

    +

    + Own Id: OTP-17832 Aux Id: PR-5494

    +
    + +

    + Avoid confusion by correcting the argument order in the + gen_event crash log printout.

    +

    + Own Id: OTP-17878

    +
    + +

    + Fixed string:next_grapheme/1 to return an empty + binary in the tail for binary input for the last grapheme + cluster.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18009 Aux Id: PR-5785

    +
    + +

    + Fixed type specifications of the + supervisor:sup_name/0 and + supervisor:sup_ref/0 types.

    +

    + Own Id: OTP-18034 Aux Id: PR-4661, GH-4622

    +
    + +

    + If a default record field initialization (_ = + Expr) was used even though all records fields were + explicitly initialized, Expr would not be + evaluated. That would not be a problem, except when + Expr would bind a variable subsequently used, in + which case the compiler would crash.

    +

    + As an example, if record #r{} is defined to have + only one field a, the following code would crash + the compiler:

    +

    + #r{a=[],_=V=42}, V

    +

    + To fix that problem, the compiler will make sure that + Expr is always evaluated at least once. The + compiler will now rewrite the example to essentially:

    +

    + V=42, #r{a=[]}, V

    +

    + Own Id: OTP-18083

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Users can now configure ETS tables with the + {write_concurrency, auto} option. This option + forces tables to automatically change the number of locks + that are used at run-time depending on how much + concurrency is detected. The {decentralized_counters, + true} option is enabled by default when + {write_concurrency, auto} is active.

    +

    + Benchmark results comparing this option with the other + ETS optimization options are available here:

    +

    + https://erlang.org/bench/ets_bench_result_lock_config.html

    +

    + Own Id: OTP-15991 Aux Id: PR-5208

    +
    + +

    + The format_status/2 callback for + gen_server, gen_statem and gen_event + has been deprecated in favor of the new + format_status/1 callback.

    +

    + The new callback adds the possibility to limit and change + many more things than the just the state, such as the + last received message, the reason for terminating and + more events specific to each type of behavior. See the + respective modules documentation for more details.

    +

    + Own Id: OTP-17351 Aux Id: GH-4673 PR-4952

    +
    + +

    The timer module has been modernized and made + more efficient, which makes the timer server less + susceptible to being overloaded. The timer:sleep/1 + function now accepts an arbitrarily large integer.

    +

    + Own Id: OTP-17481 Aux Id: PR-4811

    +
    + +

    + Add lists:enumerate/[1,2].

    +

    + Own Id: OTP-17523 Aux Id: PR-4928

    +
    + +

    + The configuration files .erlang, .erlang.cookie + and .erlang.crypt + can now be located in the XDG Config Home directory.

    +

    + See the documentation for each file and + filename:basedir/2 for more details.

    +

    + Own Id: OTP-17554 Aux Id: GH-5016 PR-5408 OTP-17821

    +
    + +

    + Support native time unit in calendar + functions system_time_to_rfc3339/2 and + rfc3339_to_system_time.

    +

    + Own Id: OTP-17592 Aux Id: ERIERL-663, PR-5243

    +
    + +

    + The tagged tuple tests and fun-calls have been optimized + and are now a little bit cheaper than previously.

    +

    + These optimizations become possible after making sure + that all boxed terms have at least one word allocated + after the arity word. This has been accomplished by + letting all empty tuples refer to the same empty tuple + literal which also reduces memory usage for empty tuples.

    +

    + Own Id: OTP-17608

    +
    + +

    + The signal queue benchmark in parallel_messages_SUITE and + the ETS benchmark in ets_SUITE have benchmark result + visualization HTML pages with "fill-screen" buttons to + make the graphs bigger. This button did not work as + intended before. When pressing the button for a graph, + the last graph got replaced with a bigger version and not + the one over the button. This is now fixed.

    +

    + Own Id: OTP-17630

    +
    + +

    + The new module peer supersedes the slave + module. The slave module is now deprecated and + will be removed in OTP 27.

    +

    + peer contains an extended and more robust API for + starting erlang nodes.

    +

    + Own Id: OTP-17720 Aux Id: PR-5162

    +
    + +

    + This change introduces quote and unquote functions in + uri_string module - a replacement for deprecated encode + and decode functions from http_uri.

    +

    + Own Id: OTP-17778 Aux Id: GH-5368

    +
    + +

    + In order to make it easier for the user to manage + multiple outstanding asynchronous call requests, + new functionality utilizing request identifier + collections have been introduced in erpc, + gen_server, + gen_statem, + and gen_event.

    +

    + Own Id: OTP-17784 Aux Id: PR-5792

    +
    + +

    + Update to the Unicode 14.0 specification.

    +

    + Own Id: OTP-17869 Aux Id: PR-5595

    +
    + +

    + The following ets types have been renamed to a clearer + name: tab/0 to table/0 and + comp_match_spec/0 to compiled_match_spec/0.

    +

    + The types table_access/0 and table_type/0 + have been exported.

    +

    + Own Id: OTP-17901 Aux Id: GH-4968 PR-5649

    +
    + +

    + Add support for locating .asn1 files to the + default search rules of filelib:find_file/1 and + filelib:find_source/1.

    +

    + Own Id: OTP-17908 Aux Id: GH-5655 PR-5669

    +
    + +

    Type specifications have been added to the + gen_server, and the documentation has been updated + to utilize this.

    This surfaced a few type + violations that has been corrected in global, + logger_olp and rpc.

    +

    + Own Id: OTP-17915 Aux Id: PR-5751, GH-2375, GH-2690

    +
    + +

    The non-local function handler for the erl_eval + can now be called with either two or three arguments. + When called with three arguments, the first argument is + the annotation for the node in the abstract format.

    +

    All errors during evaluation will now be passed + through erlang:raise/3. If the restricted shell is + active and it does not let erlang:raise/3 through, + evaluation errors will be printed in less clear way. See + the documentation for restricted shell in + shell.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17925 Aux Id: PR-5631

    +
    + +

    Added filelib:ensure_path/1 that ensures that + all directories for the given path exists (unlike + filelib:ensure_dir/1, which will not create the + last segment of the path).

    +

    + Own Id: OTP-17953 Aux Id: PR-5621

    +
    + +

    The functions groups_from_list/2 and + groups_from_list/3 have been added to the + maps module.

    +

    + Own Id: OTP-17969 Aux Id: PR-5588

    +
    + +

    + gen_server has been refactored to throw more + readable exceptions when a callback returns bad values in + the Timeout field (timeout() | 'hibernate' | + {'continue,_}), and also to verify that argument in + the gen_server:enter_loop/3,4,5 API function.

    +

    + Own Id: OTP-17974 Aux Id: GH-5683

    +
    + +

    The functions uniq/1 and uniq/2 for + removing duplicates have been added to the lists + module.

    +

    + Own Id: OTP-17977 Aux Id: GH-5606, PR-5766

    +
    + +

    + Added support for configurable features as described in + EEP-60. Features can be enabled/disabled during + compilation with options (-enable-feature Feature, + -disable-feature Feature and +{feature, + Feature, enable|disable}) to erlc as well as + with directives (-feature(Feature, + enable|disable).) in the file. Similar options can be + used to erl for enabling/disabling features + allowed at runtime. The new maybe expression + (EEP-49) is fully supported as the feature + maybe_expr. The features support is documented in + the reference manual.

    +

    + Own Id: OTP-17988

    +
    + +

    The function filename:safe_relative_path/1, + which has been deprecated since OTP 25, has been removed. + Use filelib:safe_relative_path/2 instead.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17991

    +
    + +

    A new PRNG have been added to the rand module: + mwc59 which has been developed in collaboration + with Sebastiano Vigna. It is intended for applications + that need really fast pseudo-random numbers, and it comes + with two output value scramblers, one fast and one + thorough.

    Two internal functions for the + exsp generator have also been exported so they can + be used outside the rand plug-in framework to + shave off some overhead.

    The internal + splitmix64 generator has also been exported which + can be useful for seeding other kinds of PRNG:s than its + own.

    +

    + Own Id: OTP-18011

    +
    +
    +
    + +
    +
    STDLIB 3.17.2.4
    Fixed Bugs and Malfunctions @@ -857,6 +2269,23 @@
    +
    STDLIB 3.14.2.3 + +
    Fixed Bugs and Malfunctions + + +

    It is not allowed to call functions from guards. The + compiler failed to reject a call in a guard when done by + constructing a record with a default initialization + expression that called a function.

    +

    + Own Id: OTP-18325 Aux Id: GH-6465, GH-6466

    +
    +
    +
    + +
    +
    STDLIB 3.14.2.2
    Fixed Bugs and Malfunctions diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml index 796cb42ede61..2ebe7566bfb7 100644 --- a/lib/stdlib/doc/src/orddict.xml +++ b/lib/stdlib/doc/src/orddict.xml @@ -4,7 +4,7 @@
    - 20002020 + 20002023 Ericsson AB. All Rights Reserved. @@ -38,7 +38,7 @@

    This module provides a Key-Value dictionary. An orddict is a representation of a dictionary, where a list of pairs is used to store the keys and values. The list is - ordered after the keys in the Erlang term order.

    + ordered after the keys in the Erlang term order.

    This module provides the same interface as the dict(3) module @@ -69,6 +69,24 @@ generated if the initial value associated with Key is not a list of values.

    See also section Notes.

    +

    Example 1:

    +
    +1> OrdDict1 = orddict:from_list([{x, []}]).
    +[{x,[]}]
    +2> OrdDict2 = orddict:append(x, 1, OrdDict1).
    +[{x,[1]}]
    +3> OrdDict3 = orddict:append(x, 2, OrdDict2).
    +[{x,[1,2]}]
    +4> orddict:append(y, 3, OrdDict3).
    +[{x,[1,2]},{y,[3]}]
    +

    Example 2:

    +
    +1> OrdDict1 = orddict:from_list([{a, no_list}]).
    +[{a,no_list}]
    +2> orddict:append(a, 1, OrdDict1).
    +** exception error: bad argument
    +     in operator  ++/2
    +        called as no_list ++ [1]
    @@ -81,6 +99,14 @@ An exception is generated if the initial value associated with Key is not a list of values.

    See also section Notes.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{x, []}]).
    +[{x,[]}]
    +2> OrdDict2 = orddict:append_list(x, [1,2], OrdDict1).
    +[{x,[1,2]}]
    +3> OrdDict3 = orddict:append_list(y, [3,4], OrdDict2).
    +[{x,[1,2]},{y,[3,4]}]
    @@ -89,6 +115,12 @@ Erase a key from a dictionary.

    Erases all items with a specified key from a dictionary.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:erase(a, OrdDict1).
    +[{b,2}]
    @@ -101,6 +133,14 @@ the Key is present in the dictionary. An exception is generated if Key is not in the dictionary.

    See also section Notes.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:fetch(a, OrdDict1).
    +1
    +3> orddict:fetch(missing, OrdDict1).
    +** exception error: no function clause matching orddict:fetch(missing,[])
    @@ -109,6 +149,12 @@ Return all keys in a dictionary.

    Returns a list of all keys in a dictionary.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:fetch_keys(OrdDict1).
    +[a,b]
    @@ -118,6 +164,14 @@

    This function returns value from dictionary and new dictionary without this value. Returns error if the key is not present in the dictionary.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:take(a, OrdDict1).
    +{1, [{b,2}]}
    +3> orddict:take(missing, OrdDict1).
    +error
    @@ -129,6 +183,12 @@ in Orddict1 for which Pred(Key, Value) is true.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:filter(fun (K, V) -> V > 1 end, OrdDict1).
    +[{b,2}]
    @@ -141,6 +201,14 @@ the value associated with Key, or error if the key is not present in the dictionary.

    See also section Notes.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:find(a, OrdDict1).
    +{ok,1}
    +3> orddict:find(c, OrdDict1).
    +error
    @@ -153,6 +221,12 @@ (short for accumulator). Fun must return a new accumulator that is passed to the next call. Acc0 is returned if the list is empty.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:fold(fun (K, V, Acc) -> [{K, V+100} | Acc] end, [], OrdDict1).
    +[{b,102},{a,101}]
    @@ -188,7 +262,13 @@ Map a function over a dictionary.

    Calls Fun on successive keys and values of - Orddict1 tvo return a new value for each key.

    + Orddict1 to return a new value for each key.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:map(fun (_K, V) -> V + 100 end, OrdDict1).
    +[{a,101},{b,102}]
    @@ -208,6 +288,14 @@ merge(Fun, D1, D2) -> fold(fun (K, V1, D) -> update(K, fun (V2) -> Fun(K, V1, V2) end, V1, D) end, D2, D1). +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> OrdDict2 = orddict:from_list([{b, 7}, {c, 8}]).
    +[{b,7},{c,8}]
    +3> orddict:merge(fun (K, V1, V2) -> V1 * V2 end, OrdDict1, OrdDict2).
    +[{a, 1},{b, 14},{c,8}]
    @@ -236,6 +324,14 @@ merge(Fun, D1, D2) -> dictionary. If the Key already exists in Orddict1, the associated value is replaced by Value.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:store(a, 99, OrdDict1).
    +[{a,99},{b,2}]
    +3> orddict:store(c, 100, OrdDict1).
    +[{a,1},{b,2},{c,100}]
    @@ -254,6 +350,12 @@ merge(Fun, D1, D2) ->

    Updates a value in a dictionary by calling Fun on the value to get a new value. An exception is generated if Key is not present in the dictionary.

    +

    Example:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:update(a, fun (V) -> V1 + 100 end, OrdDict1).
    +[{a, 101}, {b, 102}]
    @@ -269,6 +371,18 @@ merge(Fun, D1, D2) -> append(Key, Val, D) -> update(Key, fun (Old) -> Old ++ [Val] end, [Val], D). +

    Example 1:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:update(c, fun (V) -> V1 + 100 end, 99, OrdDict1).
    +[{a,1},{b,2},{c,99}]
    +

    Example 2:

    +
    +1> OrdDict1 = orddict:from_list([{a, 1}, {b, 2}]).
    +[{a,1},{b,2}]
    +2> orddict:update(a, fun (V) -> V1 + 100 end, 99, OrdDict1).
    +[{a,101},{b,2}]
    diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml index e4540e92176e..b3efde76b458 100644 --- a/lib/stdlib/doc/src/ordsets.xml +++ b/lib/stdlib/doc/src/ordsets.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -48,6 +48,11 @@ that while sets considers two elements as different if they do not match (=:=), this module considers two elements as different if and only if they do not compare equal (==).

    + +

    See the Compatibility Section + in the sets(3) module for more information about + the compatibility of the different implementations of sets in the + Standard Library.

    @@ -155,7 +160,9 @@ Test for an Ordset.

    Returns true if Ordset is an ordered set - of elements, otherwise false.

    + of elements, otherwise false. This function will + return true for any ordered list, even when not + constructed by the functions in this module.

    diff --git a/lib/stdlib/doc/src/peer.xml b/lib/stdlib/doc/src/peer.xml new file mode 100644 index 000000000000..e28dd7814669 --- /dev/null +++ b/lib/stdlib/doc/src/peer.xml @@ -0,0 +1,637 @@ + + + + + + +
    + + 20212021 + Maxim Fedorov, WhatsApp Inc. + + + 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. + + + + peer + maximfca@gmail.com + + + + peer.xml +
    + peer + Start and control linked Erlang nodes. + + +

    + This module provides functions for starting linked Erlang nodes. + The node spawning new nodes is called origin, and newly started + nodes are peer nodes, or peers. A peer node automatically + terminates when it loses the control connection to the origin. This + connection could be an Erlang distribution connection, or an alternative - + TCP or standard I/O. The alternative connection provides a way to execute + remote procedure calls even when Erlang Distribution is not available, + allowing to test the distribution itself. +

    + +

    + Peer node terminal input/output is relayed through the origin. + If a standard I/O alternative connection is requested, console output + also goes via the origin, allowing debugging of node startup and boot + script execution (see + -init_debug). File I/O is not redirected, contrary to + slave(3) behaviour. +

    + +

    + The peer node can start on the same or a different host (via ssh) + or in a separate container (for example Docker). + When the peer starts on the same host as the origin, it inherits + the current directory and environment variables from the origin. +

    + + +

    + This module is designed to facilitate multi-node testing with Common Test. + Use the ?CT_PEER() macro to start a linked peer node according to + Common Test conventions: crash dumps written to specific location, node + name prefixed with module name, calling function, and origin OS process + ID). Use random_name/1 to + create sufficiently unique node names if you need more control. +

    +

    + A peer node started without alternative connection behaves similarly + to slave(3). When an alternative + connection is requested, the behaviour is similar to + test_server:start_node(Name, peer, Args). +

    + +
    + +
    + Example +

    + The following example implements a test suite starting extra Erlang nodes. + It employs a number of techniques to speed up testing and reliably shut + down peer nodes: +

    + + peers start linked to test runner process. If the test case fails, + the peer node is stopped automatically, leaving no rogue nodes running in + the background + arguments used to start the peer are saved in the control process + state for manual analysis. If the test case fails, the CRASH REPORT contains + these arguments + multiple test cases can run concurrently speeding up overall testing + process, peer node names are unique even when there are multiple instances + of the same test suite running in parallel + + +-module(my_SUITE). +-behaviour(ct_suite). +-export([all/0, groups/0]). +-export([basic/1, args/1, named/1, restart_node/1, multi_node/1]). + +-include_lib("common_test/include/ct.hrl"). + +groups() -> + [{quick, [parallel], + [basic, args, named, restart_node, multi_node]}]. + +all() -> + [{group, quick}]. + +basic(Config) when is_list(Config) -> + {ok, Peer, _Node} = ?CT_PEER(), + peer:stop(Peer). + +args(Config) when is_list(Config) -> + %% specify additional arguments to the new node + {ok, Peer, _Node} = ?CT_PEER(["-emu_flavor", "smp"]), + peer:stop(Peer). + +named(Config) when is_list(Config) -> + %% pass test case name down to function starting nodes + Peer = start_node_impl(named_test), + peer:stop(Peer). + +start_node_impl(ActualTestCase) -> + {ok, Peer, Node} = ?CT_PEER(#{name => ?CT_PEER_NAME(ActualTestCase)}), + %% extra setup needed for multiple test cases + ok = rpc:call(Node, application, set_env, [kernel, key, value]), + Peer. + +restart_node(Config) when is_list(Config) -> + Name = ?CT_PEER_NAME(), + {ok, Peer, Node} = ?CT_PEER(#{name => Name}), + peer:stop(Peer), + %% restart the node with the same name as before + {ok, Peer2, Node} = ?CT_PEER(#{name => Name, args => ["+fnl"]}), + peer:stop(Peer2). + + +

    + The next example demonstrates how to start multiple nodes concurrently: +

    + +multi_node(Config) when is_list(Config) -> + Peers = [?CT_PEER(#{wait_boot => {self(), tag}}) + || _ <- lists:seq(1, 4)], + %% wait for all nodes to complete boot process, get their names: + _Nodes = [receive {tag, {started, Node, Peer}} -> Node end + || {ok, Peer} <- Peers], + [peer:stop(Peer) || {ok, Peer} <- Peers]. + + +

    + Start a peer on a different host. Requires ssh key-based + authentication set up, allowing "another_host" connection without password + prompt. +

    + +Ssh = os:find_executable("ssh"), +peer:start_link(#{exec => {Ssh, ["another_host", "erl"]}, + connection => standard_io}), + + +

    + The following Common Test case demonstrates Docker integration, starting two + containers with hostnames "one" and "two". In this example Erlang nodes + running inside containers form an Erlang cluster. +

    + +docker(Config) when is_list(Config) -> + Docker = os:find_executable("docker"), + PrivDir = proplists:get_value(priv_dir, Config), + build_release(PrivDir), + build_image(PrivDir), + + %% start two Docker containers + {ok, Peer, Node} = peer:start_link(#{name => lambda, + connection => standard_io, + exec => {Docker, ["run", "-h", "one", "-i", "lambda"]}}), + {ok, Peer2, Node2} = peer:start_link(#{name => lambda, + connection => standard_io, + exec => {Docker, ["run", "-h", "two", "-i", "lambda"]}}), + + %% find IP address of the second node using alternative connection RPC + {ok, Ips} = peer:call(Peer2, inet, getifaddrs, []), + {"eth0", Eth0} = lists:keyfind("eth0", 1, Ips), + {addr, Ip} = lists:keyfind(addr, 1, Eth0), + + %% make first node to discover second one + ok = peer:call(Peer, inet_db, set_lookup, [[file]]), + ok = peer:call(Peer, inet_db, add_host, [Ip, ["two"]]), + + %% join a cluster + true = peer:call(Peer, net_kernel, connect_node, [Node2]), + %% verify that second peer node has only the first node visible + [Node] = peer:call(Peer2, erlang, nodes, []), + + %% stop peers, causing containers to also stop + peer:stop(Peer2), + peer:stop(Peer). + +build_release(Dir) -> + %% load sasl.app file, otherwise application:get_key will fail + application:load(sasl), + %% create *.rel - release file + RelFile = filename:join(Dir, "lambda.rel"), + Release = {release, {"lambda", "1.0.0"}, + {erts, erlang:system_info(version)}, + [{App, begin {ok, Vsn} = application:get_key(App, vsn), Vsn end} + || App <- [kernel, stdlib, sasl]]}, + ok = file:write_file(RelFile, list_to_binary(lists:flatten( + io_lib:format("~tp.", [Release])))), + RelFileNoExt = filename:join(Dir, "lambda"), + + %% create boot script + {ok, systools_make, []} = systools:make_script(RelFileNoExt, + [silent, {outdir, Dir}]), + %% package release into *.tar.gz + ok = systools:make_tar(RelFileNoExt, [{erts, code:root_dir()}]). + +build_image(Dir) -> + %% Create Dockerfile example, working only for Ubuntu 20.04 + %% Expose port 4445, and make Erlang distribution to listen + %% on this port, and connect to it without EPMD + %% Set cookie on both nodes to be the same. + BuildScript = filename:join(Dir, "Dockerfile"), + Dockerfile = + "FROM ubuntu:20.04 as runner\n" + "EXPOSE 4445\n" + "WORKDIR /opt/lambda\n" + "COPY lambda.tar.gz /tmp\n" + "RUN tar -zxvf /tmp/lambda.tar.gz -C /opt/lambda\n" + "ENTRYPOINT [\"/opt/lambda/erts-" ++ erlang:system_info(version) ++ + "/bin/dyn_erl\", \"-boot\", \"/opt/lambda/releases/1.0.0/start\"," + " \"-kernel\", \"inet_dist_listen_min\", \"4445\"," + " \"-erl_epmd_port\", \"4445\"," + " \"-setcookie\", \"secret\"]\n", + ok = file:write_file(BuildScript, Dockerfile), + os:cmd("docker build -t lambda " ++ Dir). + +
    + + + + + +

    + Identifies the controlling process of a peer node. +

    +
    +
    + + + +

    + Options that can be used when starting + a peer node through start/1 + and start_link/0,1. +

    + + name + +

    + Node name (the part before "@"). When name is not specified, but host + is, peer follows compatibility behaviour and uses the origin node name. +

    +
    + longnames + +

    + Use long names to start a node. Default is taken from the origin + using net_kernel:longnames(). If the origin is not distributed, + short names is the default. +

    +
    + host + +

    + Enforces a specific host name. Can be used to override the default + behaviour and start "node@localhost" instead of "node@realhostname". +

    +
    + peer_down + +

    + Defines the peer control process behaviour when the control connection is + closed from the peer node side (for example when the peer crashes or dumps core). + When set to stop (default), a lost control connection causes + the control process to exit normally. Setting peer_down to continue + keeps the control process running, and crash will cause + the controlling process to exit abnormally. +

    +
    + connection + +

    Alternative connection specification. See the + connection datatype.

    +
    + exec + +

    + Alternative mechanism to start peer nodes with, for example, ssh instead of the + default bash. +

    +
    + detached + +

    Defines whether to pass the -detached flag to the started peer. + This option cannot be set to false using the standard_io alternative + connection type. Default is true. +

    +
    + args + +

    Extra command line arguments to append to the "erl" command. Arguments are + passed as is, no escaping or quoting is needed or accepted.

    +
    + post_process_args + +

    Allows the user to change the arguments passed to exec before the + peer is started. This can for example be useful when the exec program + wants the arguments to "erl" as a single argument. Example: +

    + +peer:start(#{ name => peer:random_name(), + exec => {os:find_executable("bash"),["-c","erl"]}, + post_process_args => + fun(["-c"|Args]) -> ["-c", lists:flatten(lists:join($\s, Args))] end + }). + +
    + env + +

    + List of environment variables with their values. This list is applied + to a locally started executable. If you need to change the environment of + the remote peer, adjust args to contain + -env ENV_KEY ENV_VALUE. +

    +
    + wait_boot + +

    Specifies the start/start_link timeout. + See wait_boot datatype. +

    +
    + shutdown + +

    Specifies the peer node stopping behaviour. See + stop().

    +
    +
    +
    +
    + + +

    Peer node state.

    +
    + + +

    Alternative connection between the origin and the peer. When the + connection closes, the peer node terminates automatically. If + the peer_down startup flag is set to crash, the controlling + process on the origin node exits with corresponding reason, effectively + providing a two-way link.

    +

    When connection is set to a port number, the origin starts listening on + the requested TCP port, and the peer node connects to the port. When it is set to + an {IP, Port} tuple, the origin listens only on the specified IP. The port + number can be set to 0 for automatic selection. +

    +

    Using the standard_io alternative connection starts the peer attached to + the origin (other connections use -detached flag to erl). In this mode + peer and origin communicate via stdin/stdout. +

    +
    +
    + + + +

    + Overrides executable to start peer nodes with. By default it is + the path to "erl", taken from init:get_argument(progname). + If progname is not known, peer makes best guess given the current + ERTS version. +

    +

    + When a tuple is passed, the first element is the path to executable, + and the second element is prepended to the final command line. This can be used + to start peers on a remote host or in a Docker container. See the examples + above. +

    +

    + This option is useful for testing backwards compatibility with previous releases, + installed at specific paths, or when the Erlang installation location + is missing from the PATH. +

    +
    +
    + + +

    Specifies start/start_link timeout in milliseconds. Can be set to + false, allowing the peer to start asynchronously. If {Pid, Tag} + is specified instead of a timeout, the peer will send Tag to the + requested process.

    +
    + + +

    Disconnect timeout. See + stop().

    +
    +
    + + + + + + + Evaluates a function call on a peer node. + +

    + Uses the alternative connection to + evaluate apply(Module, Function, + Args) on the peer node and returns + the corresponding value Result. + Timeout is an integer representing + the timeout in milliseconds or the atom infinity + which prevents the operation from ever timing out. +

    +

    + When an alternative connection is not requested, this + function will raise exit signal with the noconnection + reason. Use erpc module + to communicate over Erlang distribution. +

    +
    +
    + + + + Evaluates a function call on a peer node ignoring the result. + +

    + Uses the alternative connection to + evaluate apply(Module, Function, + Args) on the peer node. No response is delivered to the + calling process. +

    +

    + peer:cast/4 fails silently when the alternative connection is not + configured. Use erpc module + to communicate over Erlang distribution. +

    +
    +
    + + + + Sends a message to a process on the peer node. + +

    + Uses the alternative connection to send Message to a process on the + the peer node. Silently fails if no alternative connection is configured. + The process can be referenced by process ID or registered name. +

    +
    +
    + + + + Returns peer node state. + +

    Returns the peer node state. Th initial state is booting; the node stays in that + state until then boot script is complete, and then the node progresses to running. + If the node stops (gracefully or not), the state changes to down. +

    +
    +
    + + + + Creates a sufficiently unique node name. + +

    + The same as random_name(peer). +

    +
    +
    + + + + Creates a sufficiently unique node name given a prefix. + +

    + Creates a sufficiently unique node name for the current host, + combining a prefix, a unique number, and the current OS process ID. +

    + +

    + Use the ?CT_PEER(["erl_arg1"]) macro provided by Common Test + -include_lib("common_test/include/ct.hrl") for convenience. + It starts a new peer using Erlang distribution as the control channel, + supplies thes calling module's code path to the peer, and uses the calling + function name for the name prefix. +

    +
    +
    +
    + + + + Starts a peer node. + +

    + Starts a peer node with the specified + start_options(). + Returns the controlling process and the full peer node name, unless + wait_boot is not requested and the host name is not known in advance. +

    +
    +
    + + + + Starts a peer node, and links controlling process to caller process. + +

    + The same as + start_link(#{name => random_name()}). +

    +
    +
    + + + + Starts a peer node, and links controlling process to caller process. + +

    Starts a peer node in the same way as start/1, + except that the peer node is linked to the currently + executing process. If that process terminates, the peer node + also terminates.

    +

    + Accepts start_options(). + Returns the controlling process and the full peer node name, unless wait_boot is not + requested and host name is not known in advance. +

    +

    + When the standard_io alternative connection is requested, and wait_boot is + not set to false, a failed peer boot sequence causes the caller to exit with + the {boot_failed, {exit_status, ExitCode}} reason. +

    +
    +
    + + + + Stop controlling process and terminate peer node. + + +

    + Stops a peer node. How the node is stopped depends on the + shutdown + option passed when starting the peer node. Currently the + following shutdown options are supported: +

    + + halt +

    + This is the default shutdown behavior. It behaves as shutdown + option {halt, DefaultTimeout} where DefaultTimeout + currently equals 5000. +

    + {halt, Timeout :: disconnect_timeout()} +

    + Triggers a call to + erlang:halt() + on the peer node and then waits for the Erlang distribution + connection to the peer node to be taken down. If this connection + has not been taken down after Timeout milliseconds, it will + forcefully be taken down by peer:stop/1. See the + warning below for + more info about this. +

    + Timeout :: disconnect_timeout() +

    + Triggers a call to + init:stop() + on the peer node and then waits for the Erlang distribution + connection to the peer node to be taken down. If this connection + has not been taken down after Timeout milliseconds, it will + forcefully be taken down by peer:stop/1. See the + warning below for + more info about this. +

    + close +

    + Close the control connection to the peer node and + return. This is the fastest way for the caller of + peer:stop/1 to stop a peer node. +

    +

    + Note that if the Erlang distribution connection is not used as + control connection it might not have been taken down when + peer:stop/1 returns. Also note that the + warning below + applies when the Erlang distribution connection is used as control + connection. +

    +
    +
    + + + +

    + In the cases where the Erlang distribution connection is taken + down by peer:stop/1, other code independent of the peer + code might react to the connection loss before the peer node is + stopped which might cause undesirable effects. For example, + global + might trigger even more Erlang distribution connections to other + nodes to be taken down. The potential undesirable effects are, + however, not limited to this. It is hard to say what the effects + will be since these effects can be caused by any code with links + or monitors to something on the origin node, or code monitoring + the connection to the origin node. +

    +
    +
    +
    + +
    +
    + diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml index aa649a280a6f..a064c8341e22 100644 --- a/lib/stdlib/doc/src/proc_lib.xml +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -178,16 +178,34 @@ Used by a process when it has started. -

    This function must be used by a process that has been started by - a start[_link]/3,4,5 +

    + This function must only be used by a process + that has been started by a + start[_link|_monitor]/3,4,5 function. It tells Parent that the process has - initialized itself, has started, or has failed to initialize - itself.

    + initialized itself and started. +

    Function init_ack/1 uses the parent value previously stored by the start function used.

    -

    If this function is not called, the start function - returns an error tuple (if a link and/or a time-out is used) or - hang otherwise.

    +

    + If neither this function nor + init_fail/2,3 + is called by the started process, the start function + returns an error tuple when the started process exits, + or when the start function time-out (if used) has passed, + see start/3,4,5. +

    + +

    + Do not use this function to return an error indicating + that the process start failed. When doing so + the start function can return before the failing + process has exited, which may block VM resources + required for a new start attempt to succeed. Use + init_fail/2,3 + for that purpose. +

    +

    The following example illustrates how this function and proc_lib:start_link/3 are used:

    @@ -207,6 +225,76 @@ init(Parent) -> end, loop(). +... +
    + + + + init_fail(Ret, Exception) -> no_return() + init_fail(Parent, Ret, Exception) -> no_return() + Used by a process that fails to start. + + Parent = pid() + Ret = term() + Exception = {Class, Reason} | {Class, Reason, Stacktrace} + + +

    + This function must only be used by a process + that has been started by a + start[_link|_monitor]/3,4,5 + function. It tells Parent that the process has failed to + initialize, and immediately raises an exception + according to Exception. + The start function then returns Ret. +

    +

    + See + erlang:raise/3 + for a description of Class, Reason + and Stacktrace. +

    +

    + Function init_fail/2 uses the parent value + previously stored by the start function used. +

    + +

    + Do not consider catching the exception from this function. + That would defeat its purpose. A process started by a + start[_link|_monitor]/3,4,5 + function should end in a value (that will be ignored) + or an exception that will be handled by this module. + See Description. +

    +
    +

    + If neither this function nor + init_ack/1,2 + is called by the started process, the start function + returns an error tuple when the started process exits, + or when the start function time-out (if used) has passed, + see start/3,4,5. +

    +

    The following example illustrates how this function and + proc_lib:start_link/3 can be used:

    + +-module(my_proc). +-export([start_link/0]). +-export([init/1]). + +start_link() -> + proc_lib:start_link(my_proc, init, [self()]). + +init(Parent) -> + case do_initialization() of + ok -> + proc_lib:init_ack(Parent, {ok, self()}); + {error, Reason} = Error -> + proc_lib:init_fail(Parent, Error, {exit, normal}) + end, + loop(). + ...
    @@ -304,17 +392,42 @@ init(Parent) -> Start a new process synchronously. -

    Starts a new process synchronously. Spawns the process and - waits for it to start. When the process has started, it - must call +

    + Starts a new process synchronously. Spawns the process and + waits for it to start. +

    +

    + To indicate a succesful start, + the started process must call init_ack(Parent, Ret) - or init_ack(Ret), - where Parent is the process that evaluates this - function. At this time, Ret is returned.

    + where Parent is the process that evaluates this function, + or init_ack(Ret). + Ret is then returned by this function. +

    +

    + If the process fails to start, it must fail; + preferably by calling + + init_fail(Parent, Ret, Exception) + + where Parent is the process that evaluates this function, + or init_fail(Ret, Exception). + Ret is then returned by this function, + and the started process fails with Exception. +

    +

    + If the process instead fails before calling + init_ack/1,2 or init_fail/2,3, + this function returns {error, Reason} + where Reason depends a bit on the exception + just like for a process link {'EXIT',Pid,Reason} + message. +

    If Time is specified as an integer, this function waits for Time milliseconds for the - new process to call init_ack, or Ret = {error, timeout} - will be returned, and the process is killed.

    + new process to call init_ack/1,2 or init_fail/2,3, + otherwise the process gets killed + and Ret = {error, timeout} is returned.

    Argument SpawnOpts, if specified, is passed as the last argument to the spawn_opt/2,3,4,5 BIF.

    @@ -322,6 +435,11 @@ init(Parent) ->

    Using spawn option monitor is not allowed. It causes the function to fail with reason badarg.

    +

    + Using spawn option link will set a link to + the spawned process, just like + start_link/3,4,5. +

    @@ -335,22 +453,31 @@ init(Parent) ->

    Starts a new process synchronously. Spawns the process and waits for it to start. A link is atomically set on the - newly spawned process. When the process has started, it - must call - init_ack(Parent, Ret) - or init_ack(Ret), - where Parent is the process that evaluates this - function. At this time, Ret is returned.

    -

    If Time is specified as an integer, this - function waits for Time milliseconds for the - new process to call init_ack, or Ret = {error, timeout} - will be returned, and the process is killed.

    -

    If the process crashes before it has called init_ack/1,2, - Ret = {error, Reason} will be returned if - the calling process traps exits.

    -

    Argument SpawnOpts, if specified, is passed - as the last argument to the - spawn_opt/2,3,4,5 BIF.

    + newly spawned process. +

    + +

    + If the started process gets killed or crashes with a reason + that is not `normal`, the process link will kill the calling + process so this function does not return, + unless the calling process traps exits. + For example, if this function times out it will kill + the spawned process, and then the link might kill + the calling process. +

    +
    +

    + Besides setting a link on the spawned process + this function behaves like + start/3,4,5. +

    +

    + When the calling process traps exits; + if this function returns due to the spawned process exiting + (any error return), this function receives (consumes) + the 'EXIT' message, also when this function times out + and kills the spawned process. +

    Using spawn option monitor is not allowed. It causes the function to fail with reason @@ -368,34 +495,36 @@ init(Parent) ->

    Starts a new process synchronously. Spawns the process and waits for it to start. A monitor is atomically set on the - newly spawned process. When the process has started, it - must call - init_ack(Parent, Ret) - or init_ack(Ret), - where Parent is the process that evaluates this - function. At this time, Ret is returned.

    -

    If Time is specified as an integer, this - function waits for Time milliseconds for the - new process to call init_ack, or Ret = {error, timeout} - will be returned, and the process is killed.

    + newly spawned process. +

    +

    + Besides setting a monitor on the spawned process + this function behaves like + start/3,4,5. +

    The return value is {Ret, Mon} where Ret corresponds - to the Ret argument in the call to init_ack(), and - Mon is the monitor reference of the monitor that has been - set up. + to the Ret argument in the call to init_ack/1,2 + or init_fail/2,3, and Mon is the monitor reference + of the monitor that has been set up.

    - A 'DOWN' message will be delivered to the caller if - this function returns, and the spawned process terminates. This is - true also in the case when the operation times out. + If this function returns due to the spawned process exiting, + that is returns any error value, + a 'DOWN' message will be delivered to the calling process, + also when this function times out and kills the spawned process.

    -

    Argument SpawnOpts, if specified, is passed - as the last argument to the - spawn_opt/2,3,4,5 BIF.

    -

    Using spawn option monitor is not +

    + Using spawn option monitor is not allowed. It causes the function to fail with reason - badarg.

    + badarg. +

    +

    + Using spawn option link will set a link to + the spawned process, just like + start_link/3,4,5. +

    diff --git a/lib/stdlib/doc/src/qlc.xml b/lib/stdlib/doc/src/qlc.xml index 18f2bcfb108c..51a94fea285c 100644 --- a/lib/stdlib/doc/src/qlc.xml +++ b/lib/stdlib/doc/src/qlc.xml @@ -4,7 +4,7 @@
    - 20042021 + 20042023 Ericsson AB. All Rights Reserved. @@ -1247,6 +1247,11 @@ ets:match_spec_run( Options, erl_eval:new_bindings()).

    This function is probably mainly useful when called from outside of Erlang, for example from a driver written in C.

    + +

    Query handles created this way may have worse + performance than when created directly via + q/1,2.

    +
    diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml index e2ffffd2f753..480ca89963a1 100644 --- a/lib/stdlib/doc/src/queue.xml +++ b/lib/stdlib/doc/src/queue.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -44,13 +44,16 @@ not lists. Improper lists cause internal crashes. An index out of range for a queue also causes a failure with reason badarg.

    -

    Some functions, where noted, fail with reason empty for an empty queue.

    -

    The data representing a queue as used by this module - is to be regarded as opaque by other modules. Any code - assuming knowledge of the format is running on thin ice.

    +

    The data representing a queue as used by this module is to be + regarded as opaque by other modules. In abstract terms, the + representation is a composite type of existing Erlang terms. See + note on data + types. Any code assuming knowledge of the format is + running on thin ice.

    All operations have an amortized O(1) running time, except all/2, @@ -85,7 +88,7 @@ are reverse operations on the queue.

    This module has three sets of interface functions: the - "Original API", the "Extended API", and the "Okasaki API".

    + "Original API", the "Extended API", and the "Okasaki API".

    The "Original API" and the "Extended API" both use the mental picture of a waiting line of items. Both @@ -129,6 +132,13 @@

    Returns true if Pred(Item) returns true for all items Item in Q, otherwise false.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +2> queue:all(fun (E) -> E > 3 end, Queue).
    +false
    +3> queue:all(fun (E) -> E > 0 end, Queue).
    +true
    @@ -140,6 +150,13 @@

    Returns true if Pred(Item) returns true for at least one item Item in Q, otherwise false.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +2> queue:any(fun (E) -> E > 10 end, Queue).
    +false
    +3> queue:any(fun (E) -> E > 3 end, Queue).
    +true
    @@ -150,6 +167,12 @@

    Returns a copy of Q1 where the first item matching Item is deleted, if there is such an item.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +2> Queue1 = queue:delete(3, Queue).
    +3> queue:member(3, Queue1).
    +false
    @@ -160,6 +183,12 @@

    Returns a copy of Q1 where the last item matching Item is deleted, if there is such an item.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,3,5]).
    +2> Queue1 = queue:delete_r(3, Queue).
    +3> queue:to_list(Queue1).
    +[1,2,3,4,5]
    @@ -171,6 +200,12 @@

    Returns a copy of Q1 where the first item for which Pred returns true is deleted, if there is such an item.

    +

    Example:

    +
    +1> Queue = queue:from_list([100,1,2,3,4,5]).
    +2> Queue1 = queue:delete_with(fun (E) -> E > 0, Queue).
    +3> queue:to_list(Queue1).
    +[1,2,3,4,5]
    @@ -182,6 +217,12 @@

    Returns a copy of Q1 where the last item for which Pred returns true is deleted, if there is such an item.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5,100]).
    +2> Queue1 = queue:delete_with(fun (E) -> E > 10, Queue).
    +3> queue:to_list(Queue1).
    +[1,2,3,4,5]
    @@ -197,12 +238,28 @@ Item is not copied. If it returns a list, the list elements are inserted instead of Item in the result queue.

    +

    Example 1:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue1 = queue:filter(fun (E) -> E > 2 end, Queue).
    +{[5],[3,4]}
    +3> queue:to_list(Queue1).
    +[3,4,5]

    So, Fun(Item) returning [Item] is thereby semantically equivalent to returning true, just as returning [] is semantically equivalent to returning false. But returning a list builds more garbage than returning an atom.

    +

    Example 2:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue1 = queue:filter(fun (E) -> [E, E+1] end, Queue).
    +{[6,5,5,4,4,3],[1,2,2,3]}
    +3> queue:to_list(Queue1).
    +[1,2,2,3,3,4,4,5,5,6]
    @@ -218,6 +275,18 @@ Item is not copied. If it returns {true, NewItem}, the queue element at this position is replaced with NewItem in the result queue.

    +

    Example 1:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue1 = queue:filtermap(fun (E) -> E > 2 end, Queue).
    +{[5],[3,4]}
    +3> queue:to_list(Queue1).
    +[3,4,5]
    +4> Queue1 = queue:filtermap(fun (E) -> {true, E+100} end, Queue).
    +{"ihg","ef"}
    +5> queue:to_list(Queue1).
    +"efghi
    @@ -235,9 +304,9 @@ empty.

    Example:

    -> queue:fold(fun(X, Sum) -> X + Sum end, 0, queue:from_list([1,2,3,4,5])).
    +1> queue:fold(fun(X, Sum) -> X + Sum end, 0, queue:from_list([1,2,3,4,5])).
     15
    -> queue:fold(fun(X, Prod) -> X * Prod end, 1, queue:from_list([1,2,3,4,5])).
    +2> queue:fold(fun(X, Prod) -> X * Prod end, 1, queue:from_list([1,2,3,4,5])).
     120
    @@ -259,6 +328,14 @@

    Inserts Item at the rear of queue Q1. Returns the resulting queue Q2.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue1 = queue:in(100, Queue).
    +{[100,5,4,3],[1,2]}
    +3> queue:to_list(Queue1).
    +[1,2,3,4,5,100]
    @@ -269,6 +346,14 @@

    Inserts Item at the front of queue Q1. Returns the resulting queue Q2.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue1 = queue:in_r(100, Queue).
    +{[5,4,3],[100,1,2]}
    +3> queue:to_list(Queue1).
    +[100,1,2,3,4,5]
    @@ -285,8 +370,13 @@ Test if a term is a queue. -

    Tests if Term is a queue and returns true - if so, otherwise false.

    +

    Tests if Term is a queue and returns + true if so, otherwise false. Note that the test + will return true for a term coinciding with the + representation of a queue, even when not constructed by thus + module. See also note on data + types.

    @@ -297,6 +387,14 @@

    Returns a queue Q3 that is the result of joining Q1 and Q2 with Q1 in front of Q2.

    +

    Example:

    +
    +1> Queue1 = queue:from_list([1,3]).
    +{[3],[1]}
    +2> Queue2 = queue:from_list([2,4]).
    +{[4],[2]}
    +3> queue:to_list(queue:join(Queue1, Queue2)).
    +[1,3,2,4]
    @@ -335,6 +433,14 @@ Q2 is the resulting queue. If Q1 is empty, tuple {empty, Q1} is returned.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> {{value, 1=Item}, Queue1} = queue:out(Queue).
    +{{value,1},{[5,4,3],[2]}}
    +3> queue:to_list(Queue1).
    +[2,3,4,5]
    @@ -347,6 +453,14 @@ where Item is the item removed and Q2 is the new queue. If Q1 is empty, tuple {empty, Q1} is returned.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> {{value, 5=Item}, Queue1} = queue:out_r(Queue).
    +{{value,5},{[4,3],[1,2]}}
    +3> queue:to_list(Queue1).
    +[1,2,3,4]
    @@ -375,6 +489,12 @@

    Returns a list of the items in the queue in the same order; the front item of the queue becomes the head of the list.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> List == queue:to_list(Queue).
    +true
    @@ -392,6 +512,14 @@

    Returns a queue Q2 that is the result of removing the front item from Q1.

    Fails with reason empty if Q1 is empty.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue = queue:drop(Queue).
    +{[5,4,3],[2]}
    +3> queue:to_list(Queue1).
    +[2,3,4,5]
    @@ -402,6 +530,14 @@

    Returns a queue Q2 that is the result of removing the rear item from Q1.

    Fails with reason empty if Q1 is empty.

    +

    Example:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> Queue = queue:drop_r(Queue).
    +{[4,3],[1,2]}
    +3> queue:to_list(Queue1).
    +[1,2,3,4]
    @@ -412,6 +548,12 @@

    Returns Item at the front of queue Q.

    Fails with reason empty if Q is empty.

    +

    Example 1:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> 1 == queue:get(Queue).
    +true
    @@ -422,6 +564,12 @@

    Returns Item at the rear of queue Q.

    Fails with reason empty if Q is empty.

    +

    Example 1:

    +
    +1> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +2> 5 == queue:get_r(Queue).
    +true
    @@ -432,6 +580,14 @@

    Returns tuple {value, Item}, where Item is the front item of Q, or empty if Q is empty.

    +

    Example 1:

    +
    +1> queue:peek(queue:new()).
    +empty
    +2> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +3> queue:peek(Queue).
    +{value, 1}
    @@ -442,12 +598,18 @@

    Returns tuple {value, Item}, where Item is the rear item of Q, or empty if Q is empty.

    +

    Example 1:

    +
    +1> queue:peek_r(queue:new()).
    +empty
    +2> Queue = queue:from_list([1,2,3,4,5]).
    +{[5,4,3],[1,2]}
    +3> queue:peek_r(Queue).
    +{value, 5}
    - - Okasaki API @@ -459,6 +621,12 @@

    Inserts Item at the head of queue Q1. Returns the new queue Q2.

    +

    Example:

    +
    +1> Queue = queue:cons(0, queue:from_list([1,2,3])).
    +{[3,2],[0,1]}
    +2> queue:to_list(Queue).
    +[0,1,2,3]
    @@ -468,6 +636,10 @@

    Returns the tail item of queue Q.

    Fails with reason empty if Q is empty.

    +

    Example 1:

    +
    +1> queue:daeh(queue:from_list([1,2,3])).
    +3
    @@ -478,6 +650,10 @@

    Returns Item from the head of queue Q.

    Fails with reason empty if Q is empty.

    +

    Example 1:

    +
    +1> queue:head(queue:from_list([1,2,3])).
    +1
    @@ -488,6 +664,12 @@

    Returns a queue Q2 that is the result of removing the tail item from Q1.

    Fails with reason empty if Q1 is empty.

    +

    Example:

    +
    +1> Queue = queue:init(queue:from_list([1,2,3])).
    +{[2],[1]}
    +2> queue:to_list(Queue).
    +[1,2]
    @@ -508,6 +690,10 @@

    Returns the tail item of queue Q.

    Fails with reason empty if Q is empty.

    +

    Example:

    +
    +1> queue:last(queue:from_list([1,2,3])).
    +3
    @@ -518,6 +704,12 @@

    Returns a queue Q2 that is the result of removing the tail item from Q1.

    Fails with reason empty if Q1 is empty.

    +

    Example:

    +
    +1> Queue = queue:liat(queue:from_list([1,2,3])).
    +{[2],[1]}
    +2> queue:to_list(Queue).
    +[1,2]
    @@ -528,6 +720,12 @@

    Inserts Item as the tail item of queue Q1. Returns the new queue Q2.

    +

    Example:

    +
    +1> Queue = queue:snoc(queue:from_list([1,2,3]), 4).
    +{[4,3,2],[1]}
    +2> queue:to_list(Queue).
    +[1,2,3,4]
    diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index e7a2823bc0e4..fb8075cb3219 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -4,7 +4,7 @@
    - 20152021 + 20152023 Ericsson AB. All Rights Reserved. @@ -54,7 +54,22 @@ non-overlapping sequences for parallel computations. The jump functions perform calculations equivalent to perform a large number of repeated calls - for calculating new states. + for calculating new states, but execute in a time + roughly equivalent to one regular iteration per generator bit. +

    + +

    + At the end of this module documentation there are also some + + niche algorithms + + to be used without this module's normal + + plug-in framework API + + that may be useful for special purposes like + short generation time when quality is not essential, + for seeding other generators, and such.

    @@ -63,7 +78,7 @@

    - exsss + exsss

    Xorshift116**, 58 bits precision and period of 2^116-1

    Jump function: equivalent to 2^64 calls

    @@ -89,7 +104,7 @@ thanks to its statistical qualities.

    - exro928ss + exro928ss

    Xoroshiro928**, 58 bits precision and a period of 2^928-1

    Jump function: equivalent to 2^512 calls

    @@ -112,17 +127,17 @@ the 58 bit adaption.

    - exrop + exrop

    Xoroshiro116+, 58 bits precision and period of 2^116-1

    Jump function: equivalent to 2^64 calls

    - exs1024s + exs1024s

    Xorshift1024*, 64 bits precision and a period of 2^1024-1

    Jump function: equivalent to 2^512 calls

    - exsp + exsp

    Xorshift116+, 58 bits precision and period of 2^116-1

    Jump function: equivalent to 2^64 calls

    @@ -290,9 +305,10 @@ tests. We suggest to use a sign test to extract a random Boolean value. If this is a problem; to generate a boolean with these algorithms use something like this:

    -
    (rand:uniform(16) > 8)
    +
    (rand:uniform(256) > 128) % -> boolean()
    +
    ((rand:uniform(256) - 1) bsr 7) % -> 0 | 1

    - And for a general range, with N = 1 for exrop, + For a general range, with N = 1 for exrop, and N = 3 for exs1024s:

    (((rand:uniform(Range bsl N) - 1) bsr N) + 1)
    @@ -376,13 +392,38 @@ tests. We suggest to use a sign test to extract a random Boolean value.

    Algorithm specific internal state

    + + +

    Algorithm specific internal state

    +
    + + +

    Algorithm specific state

    +
    + + +

    0 .. (2^58 - 1)

    +
    + + +

    0 .. (2^64 - 1)

    +
    + + +

    1 .. ((16#1ffb072 * 2^29 - 1) - 1)

    +
    + + + + Plug-in framework API + Return a random binary. - +

    Returns, for a specified integer N >= 0, a binary() with that number of random bytes. @@ -396,7 +437,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Return a random binary. - +

    Returns, for a specified integer N >= 0 and a state, a binary() with that number of random bytes, @@ -411,7 +452,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Export the random number generation state. - +

    Returns the random number state in an external format. To be used with seed/1.

    @@ -420,7 +461,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Export the random number generation state. - +

    Returns the random number generator state in an external format. To be used with seed/1.

    @@ -430,7 +471,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Return the seed after performing jump calculation to the state in the process dictionary. - +

    Returns the state after performing jump calculation to the state in the process dictionary.

    @@ -444,7 +485,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Return the seed after performing jump calculation. - +

    Returns the state after performing jump calculation to the given state.

    This function generates a not_implemented error exception @@ -496,7 +537,6 @@ tests. We suggest to use a sign test to extract a random Boolean value. Seed random number generator. -

    Seeds random number generation with the specifed algorithm and time-dependent data if AlgOrStateOrExpState @@ -571,7 +611,7 @@ tests. We suggest to use a sign test to extract a random Boolean value. Return a random float. - +

    Returns a random float uniformly distributed in the value range 0.0 =< X < 1.0 and @@ -607,7 +647,7 @@ end. Return a random float. - +

    Returns a random float uniformly distributed in the value range @@ -628,7 +668,7 @@ end. uniform/0 because all bits in the mantissa are random. This property, in combination with the fact that exactly zero - is never returned is useful for algoritms doing for example + is never returned is useful for algorithms doing for example 1.0 / X or math:log(X).

    @@ -643,7 +683,7 @@ end. Return a random integer. - +

    Returns, for a specified integer N >= 1, a random integer uniformly distributed in the value range 1 =< X =< N and @@ -711,7 +751,7 @@ end. uniform_s/1 because all bits in the mantissa are random. This property, in combination with the fact that exactly zero - is never returned is useful for algoritms doing for example + is never returned is useful for algorithms doing for example 1.0 / X or math:log(X).

    @@ -760,4 +800,472 @@ end.
    + + + + + + Niche algorithms API +

    + This section contains special purpose algorithms + that does not use the + plug-in framework API, + for example for speed reasons. +

    +

    + Since these algorithms lack the plug-in framework support, + generating numbers in a range other than the + generator's own generated range may become a problem. +

    +

    + There are at least 3 ways to do this, assuming that + the range is less than the generator's range: +

    + + Modulo + +

    + To generate a number V in the range 0..Range-1: +

    + + Generate a number X. + + Use V = X rem Range as your value. + + +

    + This method uses rem, that is, the remainder of + an integer division, which is a slow operation. +

    +

    + Low bits from the generator propagate straight through + to the generated value, so if the generator has got + weaknesses in the low bits this method propagates + them too. +

    +

    + If Range is not a divisor of the generator range, + the generated numbers have a bias. + Example: +

    +

    + Say the generator generates a byte, that is, + the generator range is 0..255, + and the desired range is 0..99 (Range=100). + Then there are 3 generator outputs that produce the value 0, + that is; 0, 100 and 200. But there are only + 2 generator outputs that produce the value 99, + which are; 99 and 199. So the probability for + a value V in 0..55 is 3/2 times + the probability for the other values 56..99. +

    +

    + If Range is much smaller than the generator range, + then this bias gets hard to detect. The rule of thumb is + that if Range is smaller than the square root + of the generator range, the bias is small enough. + Example: +

    +

    + A byte generator when Range=20. + There are 12 (256 div 20) + possibilities to generate the highest numbers + and one more to generate a number + V < 16 (256 rem 20). + So the probability is 13/12 for a low number + versus a high. To detect that difference + with some confidence you would need to generate + a lot more numbers than the generator range, + 256 in this small example. +

    +
    + Truncated multiplication + +

    + To generate a number V in the range 0..Range-1, + when you have a generator with the range + 0..2^Bits-1: +

    + + Generate a number X. + + Use V = X*Range bsr Bits + as your value. + + +

    + If the multiplication X*Range creates a bignum + this method becomes very slow. +

    +

    + High bits from the generator propagate through + to the generated value, so if the generator has got + weaknesses in the high bits this method propagates + them too. +

    +

    + If Range is not a divisor of the generator range, + the generated numbers have a bias, + pretty much as for the Modulo method above. +

    +
    + Shift or mask + +

    + To generate a number in the range 0..2^RBits-1, + when you have a generator with the range 0..2^Bits: +

    + + Generate a number X. + + Use V = X band ((1 bsl RBits)-1) + or V = X bsr (Bits-RBits) + as your value. + + +

    + Masking with band preserves the low bits, + and right shifting with bsr preserves the high, + so if the generator has got weaknesses in high or low + bits; choose the right operator. +

    +

    + If the generator has got a range that is not a power of 2 + and this method is used anyway, it introduces bias + in the same way as for the Modulo method above. +

    +
    + Rejection + + + Generate a number X. + + If X is in the range, use V = X + as your value, otherwise reject it and repeat. + + +

    + In theory it is not certain that this method + will ever complete, but in practice you ensure + that the probability of rejection is low. + Then the probability for yet another iteration + decreases exponentially so the expected mean + number of iterations will often be between 1 and 2. + Also, since the base generator is a full length generator, + a value that will break the loop must eventually + be generated. +

    +
    +
    +

    + Chese methods can be combined, such as using the Modulo + method and only if the generator value would create bias + use Rejection. Or using Shift or mask + to reduce the size of a generator value so that + Truncated multiplication will not create a bignum. +

    +

    + The recommended way to generate a floating point number + (IEEE 745 double, that has got a 53-bit mantissa) + in the range 0..1, that is + 0.0 =< V <1.0 + is to generate a 53-bit number X and then use + V = X * (1.0/((1 bsl 53))) + as your value. This will create a value on the form + N*2^-53 with equal probability for every + possible N for the range. +

    +
    + + + Return a random integer and new state. + +

    + Returns a random 64-bit integer X + and a new generator state NewAlgState, + according to the SplitMix64 algorithm. +

    +

    + This generator is used internally in the rand + module for seeding other generators since it is of a + quite different breed which reduces the probability for + creating an accidentally bad seed. +

    +
    +
    + + + Return a random integer and new state. + +

    + Returns a random 58-bit integer X + and a new generator state NewAlgState, + according to the Xorshift116+ algorithm. +

    +

    + This is an API function into the internal implementation of the + exsp + algorithm that enables using it without the overhead + of the plug-in framework, which might be useful + for time critial applications. + On a typical 64 bit Erlang VM this approach executes + in just above 30% (1/3) of the time + for the default algorithm through + this module's normal plug-in framework. +

    +

    + To seed this generator use + + {_, AlgState} = rand:seed_s(exsp) + + or + + {_, AlgState} = rand:seed_s(exsp, Seed) + + with a specific Seed. +

    + +

    + This function offers no help in generating a number + on a selected range, nor in generating a floating point number. + It is easy to accidentally mess up the fairly good + statistical properties of this generator when doing either. + See the recepies at the start of this + + Niche algorithms API + + description. + Note also the caveat about weak low bits that + this generator suffers from. + The generator is exported in this form + primarily for performance. +

    +
    +
    +
    + + + Return the new state as from 2^64 iterations. + +

    + Returns a new generator state equivalent of the state + after iterating over + exsp_next/1 + 2^64 times. +

    +

    + See the description of jump functions + at the top of this module description. +

    +
    +
    + + + Return a new generator state. + +

    + Returns a new generator state CX1, + according to a Multiply With Carry generator, + which is an efficient implementation of a + Multiplicative Congruential Generator with + a power of 2 multiplier and a prime modulus. +

    +

    + This generator uses the multiplier 2^32 and the modulus + 16#7fa6502 * 2^32 - 1, + which have been selected, + in collaboration with Sebastiano Vigna, + to avoid bignum operations + and still get good statistical quality. + It can be written as:
    + C = CX0 bsr 32
    + X = CX0 band ((1 bsl 32)-1))
    + CX1 = 16#7fa6502 * X + C +

    +

    + Because the generator uses a multiplier that is + a power of 2 it gets statistical flaws for collision tests + and birthday spacings tests in 2 and 3 dimensions, + and even these caveats apply only to the MWC "digit", + that is the low 32 bits (due to the multiplier) of + the generator state. +

    +

    + The quality of the output value improves much by using + a scrambler instead of just taking the low bits. + Function + + mwc59_value32 + + is a fast scrambler that returns a decent 32-bit number. + The slightly slower + + mwc59_value + + scrambler returns 59 bits of very good quality, and + mwc59_float + returns a float() of very good quality. +

    +

    + The low bits of the base generator are surprisingly good, + so the lowest 16 bits actually pass fairly strict PRNG tests, + despite the generator's weaknesses that lie in the high + bits of the 32-bit MWC "digit". It is recommended + to use rem on the the generator state, + or bit mask extracting the lowest bits to produce numbers + in a range 16 bits or less. + See the recepies at the start of this + + Niche algorithms API + + description. +

    +

    + On a typical 64 bit Erlang VM this generator executes + in below 8% (1/13) of the time + for the default algorithm in the + + plug-in framework API + + of this module. With the + + mwc59_value32 + + scrambler the total time becomes 16% (1/6), + and with + + mwc59_value + + it becomes 20% (1/5) of the time for the default algorithm. + With + mwc59_float + the total time is 60% of the time for the default + algorithm generating a float(). +

    + +

    + This generator is a niche generator for high speed + applications. It has a much shorter period + than the default generator, which in itself + is a quality concern, although when used with the + value scramblers it passes strict PRNG tests. + The generator is much faster than + exsp_next/1 + but with a bit lower quality. +

    +
    +
    +
    + + + Return the generator value. + +

    + Returns a 32-bit value V + from a generator state CX. + The generator state is scrambled using + an 8-bit xorshift which masks + the statistical imperfecions of the base generator + mwc59 + enough to produce numbers of decent quality. + Still some problems in 2- and 3-dimensional + birthday spacing and collision tests show through. +

    +

    + When using this scrambler it is in general better to use + the high bits of the value than the low. + The lowest 8 bits are of good quality and pass right through + from the base generator. They are combined with the next 8 + in the xorshift making the low 16 good quality, + but in the range 16..31 bits there are weaker bits + that you do not want to have as the high bits + of your generated values. + Therefore it is in general safer to shift out low bits. + See the recepies at the start of this + + Niche algorithms API + + description. +

    +

    + For a non power of 2 range less than about 16 bits + (to not get too much bias and to avoid bignums) + truncated multiplication can be used, + which is much faster than using rem: + (Range*V) bsr 32. +

    +
    +
    + + + Return the generator value. + +

    + Returns a 59-bit value V + from a generator state CX. + The generator state is scrambled using + an 4-bit followed by a 27-bit xorshift, which masks + the statistical imperfecions of the base generator + mwc59 + enough that all 59 bits are of very good quality. +

    +

    + Be careful to not accidentaly create a bignum + when handling the value V. +

    +

    + It is in general general better to use the high bits + from this scrambler than the low. + See the recepies at the start of this + + Niche algorithms API + + description. +

    +

    + For a non power of 2 range less than about 29 bits + (to not get too much bias and to avoid bignums) + truncated multiplication can be used, + which is much faster than using rem. + Example for range 1'000'000'000; + the range is 30 bits, we use 29 bits from the generator, + adding up to 59 bits, which is not a bignum: + (1000000000 * (V bsr (59-29))) bsr 29. +

    +
    +
    + + + Return a generated float. + +

    + Returns the generator value V + from a generator state CX, + as a float(). + The generator state is scrambled as with + + mwc59_value/1 + + before converted to a float(). +

    +
    +
    + + + + Create a generator state. + +

    + Returns a generator state CX. + S is hashed to create the generator state, + to avoid that similar seeds create similar sequences. +

    +

    + Without S, + the generator state is created as for + seed_s(atom()). +

    +
    +
    +
    diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index e16ef12f16a3..d18b976d6568 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -5,7 +5,7 @@
    2007 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -75,6 +75,9 @@ + + + @@ -363,7 +366,7 @@ elements with Replacement.

    Replaces the matched part of the Subject string - with the contents of Replacement.

    + with Replacement.

    The permissible options are the same as for run/3, except that option capture is not allowed. Instead a {return, @@ -378,8 +381,8 @@ unicode compilation option is specified to this function, both the regular expression and Subject are to specified as valid Unicode charlist()s.

    -

    The replacement string can contain the special character - &, which inserts the whole matching expression in the +

    If the replacement is given as a string, it can contain the special + character &, which inserts the whole matching expression in the result, and the special sequence \N (where N is an integer > 0), \gN, or \g{N}, resulting in the subexpression number N, is inserted in the result. If no subexpression with that @@ -401,6 +404,35 @@ re:replace("abcd","c","[\\&]",[{return,list}]).

    gives

    "ab[&]d" +

    If the replacement is given as a fun, it will be called with the + whole matching expression as the first argument and a list of subexpression + matches in the order in which they appear in the regular expression. + The returned value will be inserted in the result.

    +

    Example:

    + +re:replace("abcd", ".(.)", fun(Whole, [<<C>>]) -> <<$#, Whole/binary, $-, (C - $a + $A), $#>> end, [{return, list}]). +

    gives

    + +"#ab-B#cd" + +

    Non-matching optional subexpressions will not be included in the list + of subexpression matches if they are the last subexpressions in the + regular expression.

    +

    Example:

    +

    The regular expression "(a)(b)?(c)?" ("a", optionally followed + by "b", optionally followed by "c") will create the following subexpression + lists:

    + + [<<"a">>, <<"b">>, <<"c">>] + when applied to the string "abc" + [<<"a">>, <<>>, <<"c">>] + when applied to the string "acx" + [<<"a">>, <<"b">>] + when applied to the string "abx" + [<<"a">>] + when applied to the string "axx" + +

    As with run/3, compilation errors raise the badarg exception. compile/2 can be used to get more information about the error.

    @@ -972,7 +1004,7 @@ re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]).

    Here the empty binary (<<>>) represents the unassigned subpattern. In the binary case, some information about the matching is therefore lost, as - <<>> can + <<>> can also be an empty string captured.

    If differentiation between empty matches and non-existing subpatterns is necessary, use the type index and do diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml index e404b1a3c843..428647f6cf1d 100644 --- a/lib/stdlib/doc/src/ref_man.xml +++ b/lib/stdlib/doc/src/ref_man.xml @@ -4,7 +4,7 @@

    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -32,6 +32,7 @@ + @@ -43,11 +44,14 @@ + + + @@ -74,6 +78,7 @@ + diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml index 5d81ca4f0d41..4b70fe4add21 100644 --- a/lib/stdlib/doc/src/sets.xml +++ b/lib/stdlib/doc/src/sets.xml @@ -4,7 +4,7 @@
    - 20002021 + 20002023 Ericsson AB. All Rights Reserved. @@ -35,8 +35,17 @@ sets Functions for set manipulation. -

    Sets are collections of elements with no duplicate elements. - The representation of a set is undefined.

    +

    Sets are collections of elements with no duplicate + elements.

    + +

    The data representing a set as used by this module is to be + regarded as opaque by other modules. In abstract terms, the + representation is a composite type of existing Erlang terms. See + note on data + types. Any code assuming knowledge of the format is + running on thin ice.

    +

    This module provides the same interface as the ordsets(3) module @@ -60,6 +69,71 @@ +

    + Compatibility +

    The following functions in this module also exist and provide + the same functionality in the + gb_sets(3) and + ordsets(3) + modules. That is, by only changing the module name for each call, + you can try out different set representations.

    + + add_element/2 + + del_element/2 + + filter/2 + + fold/3 + + from_list/1 + + intersection/1 + + intersection/2 + + is_element/2 + + is_empty/1 + + is_set/1 + + is_subset/2 + + new/0 + + size/1 + + subtract/2 + + to_list/1 + + union/1 + + union/2 + + + +

    + While the three set implementations offer the same functionality + with respect to the aforementioned functions, their overall behavior + may differ. As mentioned, this module considers elements as different if + and only if they do not match (=:=), while both + ordsets and + gb_sets consider elements as + different if and only if they do not compare equal (==). +

    +

    Example:

    +
    +1> sets:is_element(1.0, sets:from_list([1])).
    +false
    +2> ordsets:is_element(1.0, ordsets:from_list([1])).
    +true
    +2> gb_sets:is_element(1.0, gb_sets:from_list([1])).
    +true
    +
    +
    + @@ -174,8 +248,13 @@ Test for a Set. -

    Returns true if Set is a set of - elements, otherwise false.

    +

    Returns true if Set appears to + be a set of elements, otherwise false. Note that the + test is shallow and will return true for any term that + coincides with the possible representations of a set. See + also note on data + types.

    diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml index dc68af432894..9f3849b0c3c2 100644 --- a/lib/stdlib/doc/src/shell.xml +++ b/lib/stdlib/doc/src/shell.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -39,16 +39,28 @@

    The shell is a user interface program for entering expression sequences. The expressions are - evaluated and a value is returned. - A history mechanism saves previous commands and their + evaluated and a value is returned. The shell provides an Emacs like set of + shortcuts for editing the text of the current line. See + tty - A Command-Line Interface in the ERTS User's Guide + for a list of all available shortcuts. + You may also change the shortcuts to suit your preferences more, see + edlin - line editor in the shell.

    + +

    A history mechanism saves previous commands and their values, which can then be incorporated in later commands. How many commands and results to save can be determined by the user, either interactively, by calling history/1 and results/1, or by setting the application configuration - parameters shell_history_length and - shell_saved_results for the STDLIB application.

    + parameters + shell_history_length and + shell_saved_results + for the STDLIB application. The shell history can be saved to disk by + setting the application configuration parameter + shell_history + for the Kernel application. +

    The shell uses a helper process for evaluating commands to protect the history mechanism from exceptions. By @@ -134,6 +146,8 @@ f(X)

    Removes the binding of variable X.

    +

    If a huge value is stored in a variable binding, you have to both call f(X) and + call history(0) or results(0) to free up that memory.

    h() @@ -168,6 +182,21 @@

    Evaluates shell_default:help().

    + h(Module, Function) + +

    Print the documentation for Module:Function in the shell + if available.

    +
    + ht(Module, Type) + +

    Print the documentation for Module:Type in the shell + if available.

    +
    + hcb(Module, Callback) + +

    Print the documentation for Module:Callback in the shell + if available.

    +
    c(Mod)

    Evaluates shell_default:c(Mod). This compiles and @@ -789,6 +818,14 @@ q - quit erlang manual page. (Arguments in ArgList are evaluated before the callback functions are called.)

    +

    From OTP 25.0, if there are errors evaluating Erlang constructs, + such as badmatch during pattern matching or bad_generator + in a comprehension, the evaluator will dispatch to + erlang:raise(error, Reason, Stacktrace). This call will be + checked against the non_local_allowed/3 callback function. + You can either forbid it, allow it, or redirect to another call of + your choice.

    +

    Argument State is a tuple {ShellState,ExprState}. The return value NewState has the same form. This can be used to carry a state between calls @@ -923,6 +960,85 @@ q - quit erlang + + + Start the interactive shell + +

    Starts the interactive shell if it has not already been started. + It can be used to programatically start the shell from an escript + or when erl is started with the -noinput or -noshell flags.

    + + + + + + + + Start the interactive shell + +

    Starts the interactive shell if it has not already been started. + It can be used to programatically start the shell from an + escript or when + erl is started with the + -noinput or + -noshell flags. + The following options are allowed:

    + + noshell + +

    Starts the interactive shell as if + -noshell was given to erl. + This is only useful when erl is started with + -noinput and the + system want to read input data. +

    +
    + mfa() + +

    Starts the interactive shell using + mfa() + as the default shell.

    +
    + {node(), + mfa()} + +

    Starts the interactive shell using + mfa() on + node() as the default shell.

    +
    + {remote, string()} + +

    Starts the interactive shell using as if + -remsh + was given to erl.

    +
    + {remote, + string(), + mfa()} + +

    Starts the interactive shell using as if + -remsh + was given to erl + but with an alternative shell implementation.

    +
    +
    +

    On error this function will return:

    + + already_started + if an interactive shell is already started. + noconnection + if a remote shell was requested but it could not be connected to. + badfile | nofile | on_load_failure + if a remote shell was requested with a custom + mfa(), + but the module could not be loaded. See + Error Reasons for Code-Loading Functions + for a description of the error reasons. + + +
    +
    + Exit a normal shell and starts a restricted shell. @@ -961,6 +1077,17 @@ q - quit erlang string syntax.

    + + + + Return the current shell process. + +

    Returns the current shell process on the node where the + calling process' group_leader is located. If that node + has no shell this function will return undefined.

    +
    +
    + diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml index 9b96c4d39aa3..6d47054cb83e 100644 --- a/lib/stdlib/doc/src/sofs.xml +++ b/lib/stdlib/doc/src/sofs.xml @@ -4,7 +4,7 @@
    - 20012020 + 20012022 Ericsson AB. All Rights Reserved. @@ -40,6 +40,14 @@ collection of elements; every element belongs to the set, and the set contains every element.

    +

    The data representing sofs as used by this module is to + be regarded as opaque by other modules. In abstract terms, the + representation is a composite type of existing Erlang terms. See + note on data + types. Any code assuming knowledge of the format is + running on thin ice.

    +

    Given a set A and a sentence S(x), where x is a free variable, a new set B whose elements are exactly those elements of A for which S(x) holds can be formed, this is denoted B = @@ -1167,20 +1175,31 @@ true Test for an unordered set. -

    Returns true if AnySet is - an unordered set, and - false if AnySet is an ordered set or an - atomic set.

    +

    Returns true if AnySet appears + to be an unordered + set, and false if AnySet + is an ordered set or an atomic set or any other term. Note + that the test is shallow and this function will return + true for any term that coincides with the + representation of an unordered set. See also note on + data + types.

    - Test for an unordered set. - -

    Returns true if Term is - an unordered set, an - ordered set, or an atomic set, otherwise false.

    + Test for a sofs set. + +

    Returns true if Term appears to + be an unordered + set, an ordered set, or an atomic set, otherwise + false. Note that this function will return true + for any term that coincides with the representation of a + sofs set. See also note on data + types.

    diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml index 75266530f278..4484dd4e8af5 100644 --- a/lib/stdlib/doc/src/specs.xml +++ b/lib/stdlib/doc/src/specs.xml @@ -1,5 +1,6 @@ + @@ -10,11 +11,14 @@ + + + @@ -41,6 +45,7 @@ + diff --git a/lib/stdlib/doc/src/stdlib_app.xml b/lib/stdlib/doc/src/stdlib_app.xml index 298fbb4b9136..e12bc8b17f65 100644 --- a/lib/stdlib/doc/src/stdlib_app.xml +++ b/lib/stdlib/doc/src/stdlib_app.xml @@ -4,7 +4,7 @@
    - 20052021 + 20052023 Ericsson AB. All Rights Reserved. @@ -43,26 +43,35 @@ app(4) module in Kernel.

    - shell_esc = icl | abort + shell_esc = icl | abort

    Can be used to change the behavior of the Erlang shell when ^G is pressed.

    - restricted_shell = module() + restricted_shell = module()

    Can be used to run the Erlang shell in restricted mode.

    - shell_catch_exception = boolean() + shell_catch_exception = boolean()

    Can be used to set the exception handling of the evaluator process of Erlang shell.

    - shell_history_length = integer() >= 0 + shell_expand_location = above | below + +

    Sets where the tab expansion text should appear in the shell. + The default is below.

    +
    + shell_history_length = integer() >= 0

    Can be used to determine how many commands are saved by the Erlang - shell.

    + shell. See edlin for more.

    +
    + shell_keymap = #{} + +

    Can be used to override the default keymap configuration for the shell.

    - shell_prompt_func = {Mod, Func} | default + shell_prompt_func = {Mod, Func} | default

    where

    @@ -71,12 +80,35 @@

    Can be used to set a customized Erlang shell prompt function.

    - shell_saved_results = integer() >= 0 + shell_saved_results = integer() >= 0

    Can be used to determine how many results are saved by the Erlang shell.

    - shell_strings = boolean() + shell_session_slogan = string() | fun() -> string()) + +

    The slogan printed when starting an Erlang shell. Example:

    + +$ erl -stdlib shell_session_slogan '"Test slogan"' +Erlang/OTP 26 [DEVELOPMENT] [erts-13.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns] + +Test slogan +1> + +
    + shell_slogan = string() | fun(() -> string()) + +

    The slogan printed when starting the Erlang shell subsystem. Example:

    + +$ erl -stdlib shell_slogan '"Test slogan"' +Test slogan +Eshell V13.0.2 (abort with ^G) +1> + +

    The default is the return value of + erlang:system_info(system_version).

    +
    + shell_strings = boolean()

    Can be used to determine how the Erlang shell outputs lists of integers.

    diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml index 3c8e7250df05..5176f6de6004 100644 --- a/lib/stdlib/doc/src/string.xml +++ b/lib/stdlib/doc/src/string.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -69,7 +69,7 @@ find/3, replace/3, split/2, - split/2 and + split/3 and trim/3.

    diff --git a/lib/stdlib/doc/src/supervisor_bridge.xml b/lib/stdlib/doc/src/supervisor_bridge.xml index eb21f06b1661..3e8b5a7da9b0 100644 --- a/lib/stdlib/doc/src/supervisor_bridge.xml +++ b/lib/stdlib/doc/src/supervisor_bridge.xml @@ -5,7 +5,7 @@

    1996 - 2021 + 2022 Ericsson AB, All Rights Reserved @@ -115,7 +115,7 @@

    If Module:init/1 fails or returns an error tuple or an incorrect value, this function returns - {error,Errorr}, where + {error,Error}, where Error is a term with information about the error, and the supervisor bridge terminates with reason Error.

    diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index 6c1973f7621c..1aea4ba0dcde 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -4,7 +4,7 @@
    - 19962022 + 19962023 Ericsson AB. All Rights Reserved. @@ -470,7 +470,7 @@

    If Flag is get, a list of all logged events is returned.

    If Flag is print, the logged events - are printed to standard_io.

    + are printed to standard_io.

    The events are formatted with a function that is defined by the process that generated the event (with a call to @@ -675,9 +675,9 @@ Print all system events on standard_io. -

    Prints all system events on standard_io. The events are - formatted with a function that is defined by the process that - generated the event (with a call to +

    Prints all system events on standard_io. + The events are formatted with a function that is defined by + the process that generated the event (with a call to handle_debug/4).

    diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml index 2ff124885d07..75706f7b2dff 100644 --- a/lib/stdlib/doc/src/timer.xml +++ b/lib/stdlib/doc/src/timer.xml @@ -4,7 +4,7 @@
    - 19962021 + 19962023 Ericsson AB. All Rights Reserved. @@ -50,7 +50,9 @@

    Creating timers using erlang:send_after/3 and erlang:start_timer/3 - is much more efficient than using the timers provided by this module. See + is more efficient than using the timers provided by this module. However, + the timer module has been improved in OTP 25, making it more efficient and + less susceptible to being overloaded. See the Timer Module section in the Efficiency Guide.

    @@ -69,10 +71,10 @@ - Apply Module:Function(Arguments) after a specified - Time. + Spawn a process evaluating Module:Function(Arguments) + after a specified Time. -

    Evaluates apply(Module, Function, +

    Evaluates spawn(Module, Function, Arguments) after Time milliseconds.

    Returns {ok, TRef} or @@ -82,12 +84,53 @@ - Evaluate Module:Function(Arguments) repeatedly at - intervals of Time. + Spawn a process evaluating Module:Function(Arguments) + repeatedly at intervals of Time. + +

    Evaluates spawn(Module, Function, + Arguments) repeatedly at intervals of + Time, irrespective of whether a previously + spawned process has finished or not.

    + +

    If the execution time of the spawned process is, on average, + greater than the given Time, multiple such + processes will run at the same time. With long execution times, + short intervals, and many interval timers running, this may even + lead to exceeding the number of allowed processes. As an extreme + example, consider + [timer:apply_interval(1, timer, sleep, [1000]) || _ <- lists:seq(1, 1000)], + that is, 1,000 interval timers executing a process that takes 1s + to complete, started in intervals of 1ms, which would result in + 1,000,000 processes running at the same time, far more than a node + started with default settings allows (see the + System + Limits section in the Effiency Guide).

    +
    +

    Returns {ok, TRef} or + {error, Reason}.

    +
    +
    + + + + Spawn a process evaluating Module:Function(Arguments) + repeatedly at intervals of Time. -

    Evaluates apply(Module, Function, +

    Evaluates spawn(Module, Function, Arguments) repeatedly at intervals of - Time.

    + Time, waiting for the spawned process to + finish before starting the next.

    +

    If the execution time of the spawned process is greater than the + given Time, the next process is spawned immediately + after the one currently running has finished. Assuming that execution + times of the spawned processes performing the applies on average + are smaller than Time, the amount of applies + made over a large amount of time will be the same even if some + individual execution times are larger than + Time. The system will try to catch up as soon + as possible. For example, if one apply takes + 2.5*Time, the following two applies will be + made immediately one after the other in sequence.

    Returns {ok, TRef} or {error, Reason}.

    @@ -116,8 +159,9 @@ exit_after(Time, self(), Reason1).

    exit_after/3 sends an exit signal with reason - Reason1 to - pid Pid. Returns {ok, TRef} + Reason1 to Target, + which can be a local process identifier or an atom of a registered + name. Returns {ok, TRef} or {error, Reason2}.

    @@ -149,7 +193,7 @@

    kill_after/1 is the same as exit_after(Time, self(), kill).

    kill_after/2 is the same as - exit_after(Time, Pid, kill).

    + exit_after(Time, Target, kill).

    @@ -190,15 +234,16 @@ - Send Message to Pid after a specified + Send Message to Destination after a specified Time. send_after/3 -

    Evaluates Pid ! Message after - Time milliseconds. (Pid - can also be an atom of a registered name.)

    +

    Evaluates Destination ! Message after + Time milliseconds. (Destination can + be a remote or local process identifier, an atom of a registered name or + a tuple {RegName, Node} for a registered name at another node.)

    Returns {ok, TRef} or {error, Reason}.

    See also @@ -223,10 +268,11 @@ send_interval/3 -

    Evaluates Pid ! Message +

    Evaluates Destination ! Message repeatedly after Time milliseconds. - (Pid can also be - an atom of a registered name.)

    + (Destination can be a remote or local process + identifier, an atom of a registered name or a tuple {RegName, Node} + for a registered name at another node.)

    Returns {ok, TRef} or {error, Reason}.

    @@ -249,6 +295,11 @@ or suspends the process forever if Time is the atom infinity. Naturally, this function does not return immediately.

    + +

    Before OTP 25, timer:sleep/1 did not accept integer + timeout values greater than 16#ffffffff, that is, 2^32-1. + Since OTP 25, arbitrarily high integer values are accepted.

    +
    @@ -268,14 +319,37 @@ - - + + + Measure the real time it takes to evaluate Fun. + + + tc/3 + +

    Calls function timer:tc(Module, Function, Arguments, microsecond).

    +
    + tc/2 + +

    Calls function timer:tc(Fun, Arguments, microsecond).

    +
    + tc/1 + +

    Calls function timer:tc(Fun, microsecond).

    +
    +
    +
    +
    + + + + + Measure the real time it takes to evaluate apply(Module, Function, Arguments) or apply(Fun, Arguments). - In microseconds + In the specified TimeUnit - tc/3 + tc/4

    Evaluates apply(Module, Function, Arguments) and measures the elapsed real time as @@ -283,18 +357,18 @@ erlang:monotonic_time/0.

    Returns {Time, Value}, where Time is the elapsed real time in - microseconds, and Value is what is + the specified TimeUnit, and Value is what is returned from the apply.

    - tc/2 + tc/3

    Evaluates apply(Fun, Arguments). - Otherwise the same as tc/3.

    + Otherwise the same as tc/4.

    - tc/1 + tc/2

    Evaluates Fun(). Otherwise the same as - tc/2.

    + tc/3.

    @@ -350,4 +424,3 @@ timer:cancel(R), cancel/1.

    - diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index 1f0133de674e..5008f13075f9 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -5,7 +5,7 @@
    1996 - 2020 + 2023 Ericsson AB, All Rights Reserved @@ -37,7 +37,7 @@ representations. It converts between ISO Latin-1 characters and Unicode characters, but it can also convert between different Unicode encodings (like UTF-8, UTF-16, and UTF-32).

    -

    The default Unicode encoding in Erlang is in binaries UTF-8, which is also +

    The default Unicode encoding in Erlang binaries is UTF-8, which is also the format in which built-in functions and libraries in OTP expect to find binary Unicode data. In lists, Unicode data is encoded as integers, each integer representing one character and encoded simply as the Unicode code diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml index c73dc73667c1..6f915346651b 100644 --- a/lib/stdlib/doc/src/unicode_usage.xml +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -5,7 +5,7 @@

    1999 - 2020 + 2023 Ericsson AB. All Rights Reserved. @@ -611,9 +611,7 @@ ok
    The Interactive Shell -

    The interactive Erlang shell, when started to a terminal or started - using command werl on Windows, can support Unicode input and - output.

    +

    The interactive Erlang shell can support Unicode input and output.

    On Windows, proper operation requires that a suitable font is installed and selected for the Erlang application to use. If no suitable @@ -716,7 +714,50 @@ Eshell V5.10.1 (abort with ^G) 2> Юникод. * 1: illegal character 2> -

    +
    + +
    + Escripts and non-interactive I/O +

    When Erlang is started without an interactive shell (-noshell, + -noinput or as an escript) the unicode support is identified using + environment variables just as for + interactive shells. Working with unicode in non-interactive + sessions works just the same as for interactive sessions. +

    +

    In some situations you may need to be able to read and write raw bytes + from standard_io. + If that is the case, then you want to set + the standard_io_encoding + configuration parameter to latin1 and use the file + API to read and write data (as explained in Unicode Data in Files). +

    +

    In the example below we first read the character ξ from standard_io + and then print the charlist() + represented by it. +

    +
    +#!/usr/bin/env escript
    +%%! -kernel standard_io_encoding latin1
    +
    +main(_) ->
    +  {ok, Char} = file:read_line(standard_io),
    +  ok = file:write(standard_io, string:trim(Char)),
    +  ok = file:write(standard_io, io_lib:format(": ~w~n",[string:trim(Char)])),
    +  ok.
    +
    +
    +$ escript test.es
    +ξ
    +ξ: [206,190]
    +
    +

    ξ would normally be represented as the integer 958, but since we are + using bytewise encoding (latin1), it is represented by 206 and 190, + which is the utf-8 bytes representing ξ. When we echo those bytes back + to standard_io, + the terminal will see the bytes as utf-8 and show the + correct value even though in Erlang we never knew that it was indeed a unicode + string.

    +
    @@ -1214,19 +1255,27 @@ ok

    io:setopts/1,2 - and flags -oldshell/-noshell + and + standard_io_encoding -

    When Erlang is started with -oldshell or -noshell, the - I/O server for standard_io is by default set to bytewise - encoding, while an interactive shell defaults to what the - environment variables says.

    +

    When Erlang is started the encoding for standard_io is by + default set to what the locale settings indicate. + You can override the default by setting the kernel configuration parameter + + standard_io_encoding to the desired encoding.

    You can set the encoding of a file or other I/O server with function io:setopts/2. This can also be set when opening a file. Setting the terminal (or - other standard_io server) unconditionally to option - {encoding,utf8} implies that UTF-8 encoded characters are - written to the device, regardless of how Erlang was started or the - user's environment.

    + other standard_io server) + unconditionally to option {encoding,utf8} implies that UTF-8 + encoded characters are written to the device, regardless of how Erlang + was started or the user's environment.

    +

    If you use io:setopts/2 + to change the encoding of standard_io + the I/O server may already have + read some data using the default encoding. To avoid this you should set + the encoding using + standard_io_encoding.

    Opening files with option encoding is convenient when writing or reading text files in a known encoding.

    You can retrieve the encoding setting for an I/O server with @@ -1357,7 +1406,8 @@ ok terminal: "oldshell" or "noshell") or whatever is suitable to show the character properly (for an interactive terminal: the regular shell).

    -

    So, you can always send Unicode data to the standard_io device. +

    So, you can always send Unicode data to the + standard_io device. Files, however, accept only Unicode code points beyond ISO Latin-1 if encoding is set to something else than latin1.

    diff --git a/lib/stdlib/doc/src/uri_string.xml b/lib/stdlib/doc/src/uri_string.xml index 4fe24e656fd9..08fc09e15045 100644 --- a/lib/stdlib/doc/src/uri_string.xml +++ b/lib/stdlib/doc/src/uri_string.xml @@ -4,7 +4,7 @@
    - 20172020 + 20172022 Ericsson AB. All Rights Reserved. @@ -84,9 +84,14 @@ Dissecting form-urlencoded query strings into a list of key-value pairs

    dissect_query/1
    - Decoding percent-encoded triplets

    + Decoding percent-encoded triplets in URI map or a specific component of URI

    percent_decode/1
    + Preparing and retrieving application specific data included in URI components

    + quote/1 + quote/2 + unquote/1 +

    There are four different encodings present during the handling of URIs:

    @@ -110,6 +115,15 @@ character encoding and it is usually defined by the protocol or surrounding text. This library takes the same assumption, binary and percent-encoding are handled as one configuration unit, they cannot be set to different values.

    +

    Quoting functions are intended to be used by URI producing application + during component preparation or retrieval phase to avoid conflicts between + data and characters used in URI syntax. Quoting functions use percent + encoding, but with different rules than for example during execution of + recompose/1. It is user responsibility to provide quoting + functions with application data only and using their output to combine an + URI component.

    Quoting functions can for instance be used for constructing a path + component with a segment containing '/' character which should not collide with + '/' used as general delimiter in path component.

    @@ -357,6 +371,48 @@ + + + Percent encode characters out of unreserved set. + +

    Replaces characters out of unreserved set with their percent encoded equivalents.

    +

    Unreserved characters defined in + RFC 3986 are not quoted.

    +

    Example:

    +
    +1> 
    +
    +2> >).]]>
    +>]]>
    +	
    + +

    Function is not aware about any URI component context and + should not be used on whole URI. If applied more than once on the same + data, might produce unexpected results.

    +
    +
    + + + + Percent encode characters out of unreserved set and user defined + safe list. + +

    Same as quote/1, but Safe allows user to + provide a list of characters to be protected from encoding.

    +

    Example:

    +
    +1> 
    +
    +2> >, "/").]]>
    +>]]>
    +	
    + +

    Function is not aware about any URI component context and + should not be used on whole URI. If applied more than once on the same + data, might produce unexpected results.

    +
    +
    + Recompose URI. @@ -445,5 +501,24 @@ + + + Percent decode characters. + +

    Percent decode characters.

    + +

    Example:

    +
    +1> 
    +
    +2> >).]]>
    +>]]>
    +	
    + +

    Function is not aware about any URI component context and + should not be used on whole URI. If applied more than once on the same + data, might produce unexpected results.

    +
    +
    diff --git a/lib/stdlib/doc/src/uri_string_usage.xml b/lib/stdlib/doc/src/uri_string_usage.xml index 72851096b793..31e2c23c4581 100644 --- a/lib/stdlib/doc/src/uri_string_usage.xml +++ b/lib/stdlib/doc/src/uri_string_usage.xml @@ -4,8 +4,7 @@
    - 2020 - 2020 + 2022 Ericsson AB. All Rights Reserved. @@ -294,12 +293,14 @@ and it happens when converting a uri_map() into a uri_string(). - There is no equivalent to a raw percent-encoding function as percent-encoding - shall be applied on the component level using different sets of allowed characters. - Applying percent-encoding directly on an input URI would not be safe just as in + Applying any percent-encoding directly on an input URI would not be safe just as in the case of uri_string:percent_decode/1, the output could be an invalid URI. + Quoting functions allow users to perform raw percent encoding and decoding + on application data which cannot be handled automatically by + uri_string:recompose/1. For example in scenario when user would + need to use '/' or sub-delimeter as data rather than delimeter in a path component.

    diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml index a056621ca12a..5d5d83d270ca 100644 --- a/lib/stdlib/doc/src/zip.xml +++ b/lib/stdlib/doc/src/zip.xml @@ -4,7 +4,7 @@
    - 20062020 + 20062023 Ericsson AB. All Rights Reserved. @@ -506,6 +506,14 @@ + + + Extracts a crc32 checksum from an open archive. + +

    Extracts one crc32 checksum from an open archive.

    +
    +
    + Return a table of files in open zip archive. diff --git a/lib/stdlib/examples/Makefile b/lib/stdlib/examples/Makefile index 743ea871799e..cbef03850011 100644 --- a/lib/stdlib/examples/Makefile +++ b/lib/stdlib/examples/Makefile @@ -29,7 +29,7 @@ include ../vsn.mk # Targets # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index 292c06506af8..792f944d365c 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -409,13 +409,17 @@ expr({cons,Anno,H0,T0}) -> T1 = expr(T0), %They see the same variables {cons,Anno,H1,T1}; expr({lc,Anno,E0,Qs0}) -> - Qs1 = lc_bc_quals(Qs0), + Qs1 = comprehension_quals(Qs0), E1 = expr(E0), {lc,Anno,E1,Qs1}; expr({bc,Anno,E0,Qs0}) -> - Qs1 = lc_bc_quals(Qs0), + Qs1 = comprehension_quals(Qs0), E1 = expr(E0), {bc,Anno,E1,Qs1}; +expr({mc,Anno,E0,Qs0}) -> + Qs1 = comprehension_quals(Qs0), + E1 = expr(E0), + {mc,Anno,E1,Qs1}; expr({tuple,Anno,Es0}) -> Es1 = expr_list(Es0), {tuple,Anno,Es1}; @@ -502,6 +506,17 @@ expr({'catch',Anno,E0}) -> %% No new variables added. E1 = expr(E0), {'catch',Anno,E1}; +expr({'maybe',MaybeAnno,Es0}) -> + Es = exprs(Es0), + {'maybe',MaybeAnno,Es}; +expr({'maybe',MaybeAnno,Es0,{'else',ElseAnno,Cs0}}) -> + Es = exprs(Es0), + Cs = clauses(Cs0), + {'maybe',MaybeAnno,Es,{'else',ElseAnno,Cs}}; +expr({maybe_match,Anno,P0,E0}) -> + E = expr(E0), + P = pattern(P0), + {maybe_match,Anno,P,E}; expr({match,Anno,P0,E0}) -> E1 = expr(E0), P1 = pattern(P0), @@ -559,21 +574,25 @@ icr_clauses([C0|Cs]) -> [C1|icr_clauses(Cs)]; icr_clauses([]) -> []. -%% -type lc_bc_quals([Qualifier]) -> [Qualifier]. +%% -type comprehension_quals([Qualifier]) -> [Qualifier]. %% Allow filters to be both guard tests and general expressions. -lc_bc_quals([{generate,Anno,P0,E0}|Qs]) -> +comprehension_quals([{generate,Anno,P0,E0}|Qs]) -> + E1 = expr(E0), + P1 = pattern(P0), + [{generate,Anno,P1,E1}|comprehension_quals(Qs)]; +comprehension_quals([{b_generate,Anno,P0,E0}|Qs]) -> E1 = expr(E0), P1 = pattern(P0), - [{generate,Anno,P1,E1}|lc_bc_quals(Qs)]; -lc_bc_quals([{b_generate,Anno,P0,E0}|Qs]) -> + [{b_generate,Anno,P1,E1}|comprehension_quals(Qs)]; +comprehension_quals([{m_generate,Anno,P0,E0}|Qs]) -> E1 = expr(E0), P1 = pattern(P0), - [{b_generate,Anno,P1,E1}|lc_bc_quals(Qs)]; -lc_bc_quals([E0|Qs]) -> + [{m_generate,Anno,P1,E1}|comprehension_quals(Qs)]; +comprehension_quals([E0|Qs]) -> E1 = expr(E0), - [E1|lc_bc_quals(Qs)]; -lc_bc_quals([]) -> []. + [E1|comprehension_quals(Qs)]; +comprehension_quals([]) -> []. %% -type fun_clauses([Clause]) -> [Clause]. diff --git a/lib/stdlib/scripts/generate_ryu_table.escript b/lib/stdlib/scripts/generate_ryu_table.escript deleted file mode 100755 index dce203401c44..000000000000 --- a/lib/stdlib/scripts/generate_ryu_table.escript +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env escript -%% -*- erlang -*- -%%! +A0 -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2017-2021. 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% -%% - --mode(compile). - --define(MOD, "io_lib_format_ryu_table"). - --define(TABLE_SIZE, 326). --define(INV_TABLE_SIZE, 342). - --define(POW5_BITCOUNT, 125). --define(POW5_INV_BITCOUNT, 125). - -main(_) -> - Values = [ values(X) || X <- lists:seq(0, ?TABLE_SIZE - 1)], - InvValues = [ inv_values(X) || X <- lists:seq(0, ?INV_TABLE_SIZE - 1)], - - %% Make module - {ok, Out} = file:open("../src/" ++ ?MOD ++ ".erl", [write]), - gen_file(Out, Values, InvValues), - ok = file:close(Out), - ok. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -inv_values(X) -> - Pow = pow5(X), - Pow5len = log2floor(Pow), - J = Pow5len + ?POW5_INV_BITCOUNT - 1, - Inv = ((1 bsl J) div Pow) + 1, - {X, Inv}. - -values(X) -> - Pow = pow5(X), - Pow5len = log2floor(Pow), - Pow5 = Pow bsr (Pow5len - ?POW5_BITCOUNT), - {X, Pow5}. - -pow5(0) -> - 1; -pow5(1) -> - 5; -pow5(X) -> - 5 * pow5(X - 1). - -log2floor(Int) when is_integer(Int), Int > 0 -> - log2floor(Int, 0). - -log2floor(0, N) -> - N; -log2floor(Int, N) -> - log2floor(Int bsr 1, 1 + N). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -gen_file(Fd, Values, InvValues) -> - gen_header(Fd), - gen_pow5_static(Fd), - gen_table(Fd, Values), - gen_inv_table(Fd, InvValues), - ok. - -gen_header(Fd) -> - io:put_chars(Fd, "%%\n%% this file is generated do not modify\n"), - io:put_chars(Fd, "%% see ../script/generate_ryu_table.escript\n\n"), - io:put_chars(Fd, "-module(" ++ ?MOD ++").\n"), - io:put_chars(Fd, "-export([pow5_bitcount/0, pow5_inv_bitcount/0, value/1, inv_value/1]).\n\n"), - ok. - -gen_pow5_static(Fd) -> - io:put_chars(Fd, "-spec pow5_bitcount() -> integer().\n"), - io:format(Fd, "pow5_bitcount() -> ~p.~n~n", [?POW5_BITCOUNT]), - io:put_chars(Fd, "-spec pow5_inv_bitcount() -> integer().\n"), - io:format(Fd, "pow5_inv_bitcount() -> ~p.~n~n", [?POW5_INV_BITCOUNT]), - ok. - -gen_table(Fd, Values) -> - io:put_chars(Fd, "-spec value(integer()) -> integer().\n"), - [io:format(Fd, "value(~p) -> ~p;~n", [Key, Val]) || {Key,Val} <- Values], - io:put_chars(Fd, "value(_) -> error(function_clause).\n\n"), - ok. - -gen_inv_table(Fd, Values) -> - io:put_chars(Fd, "-spec inv_value(integer()) -> integer().\n"), - [io:format(Fd, "inv_value(~p) -> ~p;~n", [Key, Val]) || {Key,Val} <- Values], - io:put_chars(Fd, "inv_value(_) -> error(function_clause).\n"), - ok. - diff --git a/lib/stdlib/scripts/update_deprecations b/lib/stdlib/scripts/update_deprecations index ef6be3b5af77..ba34392c363d 100755 --- a/lib/stdlib/scripts/update_deprecations +++ b/lib/stdlib/scripts/update_deprecations @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2020-2021. All Rights Reserved. +%% Copyright Ericsson AB 2020-2022. 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. @@ -237,13 +237,32 @@ make_xml(Top, Type, OutFile, InfoText0) -> InfoTextMap = maps:from_list(make_xml_info(InfoText0, AttrTag)), Collected = make_xml_collect(Depr, RelKey, InfoTextMap, []), - All = make_xml_gen(lists:reverse(Collected), Type, OutDir), - file:write_file(OutFile, All), + case Type of + "removed" -> + {ok, Vsn} = file:read_file(filename:join(Top,"OTP_VERSION")), + [Release|_] = string:split(Vsn,"."), + lists:foreach( + fun({Rel, Functions}) -> + case Rel > binary_to_integer(Release) of + true -> + io:format(standard_error, + "Some functions have been marked " + "as removed in the future: ~n~p~n", + [Functions]), + halt(1); + false -> + ok + end + end, Collected); + _ -> + ok + end, - ok. + All = make_xml_gen(lists:reverse(Collected), Type, OutDir), + ok = file:write_file(OutFile, All). make_xml_info([{Tag,M,F,A,Text} | Attributes], Tag) -> - [{{M,F,A}, Text} | make_xml_info(Attributes, Tag)]; + [{{M,F,A}, info_string(Text)} | make_xml_info(Attributes, Tag)]; make_xml_info([_ | Attributes], Tag) -> make_xml_info(Attributes, Tag); make_xml_info([], _Tag) -> diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 509648cb2bcb..25606600ee55 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -42,6 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/stdlib-$(VSN) # ---------------------------------------------------- MODULES= \ array \ + argparse \ base64 \ beam_lib \ binary \ @@ -56,7 +57,10 @@ MODULES= \ digraph \ digraph_utils \ edlin \ + edlin_key \ + edlin_context \ edlin_expand \ + edlin_type_suggestion \ epp \ erl_abstract_code \ erl_anno \ @@ -65,6 +69,7 @@ MODULES= \ erl_error \ erl_eval \ erl_expand_records \ + erl_features \ erl_internal \ erl_lint \ erl_parse \ @@ -91,7 +96,6 @@ MODULES= \ io \ io_lib \ io_lib_format \ - io_lib_format_ryu_table \ io_lib_fread \ io_lib_pretty \ lists \ @@ -103,6 +107,7 @@ MODULES= \ orddict \ ordsets \ re \ + peer \ pool \ proc_lib \ proplists \ @@ -165,11 +170,17 @@ endif ERL_COMPILE_FLAGS += -Werror ERL_COMPILE_FLAGS += -I../include -I../../kernel/include +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif + # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) clean: rm -f $(TARGET_FILES) @@ -184,22 +195,25 @@ primary_bootstrap_compiler: \ $(BOOTSTRAP_COMPILER)/ebin/epp.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_anno.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_error.beam \ + $(BOOTSTRAP_COMPILER)/ebin/erl_features.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \ $(BOOTSTRAP_COMPILER)/ebin/io.beam \ - $(BOOTSTRAP_COMPILER)/ebin/otp_internal.beam + $(BOOTSTRAP_COMPILER)/ebin/otp_internal.beam \ + $(BOOTSTRAP_COMPILER)/ebin/erl_internal.beam + $(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam: erl_parse.yrl $(gen_verbose) - $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/egen erl_parse.yrl - $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl + $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/egen $(DETERMINISM_FLAG) erl_parse.yrl + $(V_at)$(ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG) $(BOOTSTRAP_COMPILER)/egen/erl_parse.erl $(BOOTSTRAP_TOP)/lib/stdlib/egen/erl_parse.erl: erl_parse.yrl $(yecc_verbose)$(ERLC) $(YRL_FLAGS) -o$(BOOTSTRAP_TOP)/lib/stdlib/egen erl_parse.yrl $(BOOTSTRAP_COMPILER)/ebin/%.beam: %.erl - $(V_ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $< + $(V_ERLC) -o $(BOOTSTRAP_COMPILER)/ebin $(DETERMINISM_FLAG) $< # ---------------------------------------------------- # Special Build Targets diff --git a/lib/stdlib/src/argparse.erl b/lib/stdlib/src/argparse.erl new file mode 100644 index 000000000000..69b734a126f5 --- /dev/null +++ b/lib/stdlib/src/argparse.erl @@ -0,0 +1,1361 @@ +%% +%% +%% Copyright Maxim Fedorov +%% +%% +%% 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. + +-module(argparse). +-author("maximfca@gmail.com"). + +%% API Exports +-export([ + run/3, + parse/2, parse/3, + help/1, help/2, + format_error/1 +]). + +%% Internal exports for validation and error reporting. +-export([validate/1, validate/2, format_error/2]). + +%%-------------------------------------------------------------------- +%% API + +-type arg_type() :: + boolean | + float | + {float, Choice :: [float()]} | + {float, [{min, float()} | {max, float()}]} | + integer | + {integer, Choices :: [integer()]} | + {integer, [{min, integer()} | {max, integer()}]} | + string | + {string, Choices :: [string()]} | + {string, Re :: string()} | + {string, Re :: string(), ReOptions :: [term()]} | + binary | + {binary, Choices :: [binary()]} | + {binary, Re :: binary()} | + {binary, Re :: binary(), ReOptions :: [term()]} | + atom | + {atom, Choices :: [atom()]} | + {atom, unsafe} | + {custom, fun((string()) -> term())}. +%% Built-in types include basic validation abilities +%% String and binary validation may use regex match (ignoring captured value). +%% For float, integer, string, binary and atom type, it is possible to specify +%% available choices instead of regex/min/max. + +-type argument_help() :: { + unicode:chardata(), %% short form, printed in command usage, e.g. "[--dir ]", developer is + %% responsible for proper formatting (e.g. adding <>, dots... and so on) + [unicode:chardata() | type | default] | fun(() -> unicode:chardata()) +}. +%% Help template definition for argument. Short and long forms exist for every argument. +%% Short form is printed together with command definition, e.g. "usage: rm [--force]", +%% while long description is printed in detailed section below: "--force forcefully remove". + +-type argument_name() :: atom() | string() | binary(). + +-type argument() :: #{ + %% Argument name, and a destination to store value too + %% It is allowed to have several arguments named the same, setting or appending to the same variable. + name := argument_name(), + + %% short, single-character variant of command line option, omitting dash (example: $b, meaning -b), + %% when present, the argument is considered optional + short => char(), + + %% long command line option, omitting first dash (example: "kernel" means "-kernel" in the command line) + %% long command always wins over short abbreviation (e.g. -kernel is considered before -k -e -r -n -e -l) + %% when present, the argument is considered optional + long => string(), + + %% makes parser to return an error if the argument is not present in the command line + required => boolean(), + + %% default value, produced if the argument is not present in the command line + %% parser also accepts a global default + default => term(), + + %% parameter type (string by default) + type => arg_type(), + + %% action to take when argument is matched + action => store | %% default: store argument consumed (last stored wins) + {store, term()} | %% does not consume argument, stores term() instead + append | %% appends consumed argument to a list + {append, term()} | %% does not consume an argument, appends term() to a list + count | %% does not consume argument, bumps counter + extend, %% uses when nargs is list/nonempty_list/all - appends every element to the list + + %% how many positional arguments to consume + nargs => + pos_integer() | %% consume exactly this amount, e.g. '-kernel key value' #{long => "-kernel", args => 2} + %% returns #{kernel => ["key", "value"]} + 'maybe' | %% if the next argument is positional, consume it, otherwise produce default + {'maybe', term()} | %% if the next argument is positional, consume it, otherwise produce term() + list | %% consume zero or more positional arguments, until next optional + nonempty_list | %% consume at least one positional argument, until next optional + all, %% fold remaining command line into this argument + + %% help string printed in usage, hidden help is not printed at all + help => hidden | unicode:chardata() | argument_help() +}. +%% Command line argument specification. +%% Argument can be optional - starting with - (dash), and positional. + +-type arg_map() :: #{argument_name() => term()}. +%% Arguments map: argument name to a term, produced by parser. Supplied to the command handler + +-type handler() :: + optional | %% valid for commands with sub-commands, suppresses parser error when no + %% sub-command is selected + fun((arg_map()) -> term()) | %% handler accepting arg_map + {module(), Fn :: atom()} | %% handler, accepting arg_map, Fn exported from module() + {fun(() -> term()), term()} | %% handler, positional form (term() is supplied for omitted args) + {module(), atom(), term()}. %% handler, positional form, exported from module() +%% Command handler. May produce some output. Can accept a map, or be +%% arbitrary mfa() for handlers accepting positional list. +%% Special value 'optional' may be used to suppress an error that +%% otherwise raised when command contains sub-commands, but arguments +%% supplied via command line do not select any. + +-type command_help() :: [unicode:chardata() | usage | commands | arguments | options]. +%% Template for the command help/usage message. + +%% Command descriptor +-type command() :: #{ + %% Sub-commands are arranged into maps. Command name must not start with prefix. + commands => #{string() => command()}, + %% accepted arguments list. Order is important! + arguments => [argument()], + %% help line + help => hidden | unicode:chardata() | command_help(), + %% recommended handler function + handler => handler() +}. + +-type cmd_path() :: [string()]. +%% Command path, for nested commands + +-export_type([arg_type/0, argument_help/0, argument/0, + command/0, handler/0, cmd_path/0, arg_map/0]). + +-type parser_error() :: {Path :: cmd_path(), + Expected :: argument() | undefined, + Actual :: string() | undefined, + Details :: unicode:chardata()}. +%% Returned from `parse/2,3' when command spec is valid, but the command line +%% cannot be parsed using the spec. +%% When `Expected' is undefined, but `Actual' is not, it means that the input contains +%% an unexpected argument which cannot be parsed according to command spec. +%% When `Expected' is an argument, and `Actual' is undefined, it means that a mandatory +%% argument is not provided in the command line. +%% When both `Expected' and `Actual' are defined, it means that the supplied argument +%% is failing validation. +%% When both are `undefined', there is some logical issue (e.g. a sub-command is required, +%% but was not selected). + +-type parser_options() :: #{ + %% allowed prefixes (default is [$-]). + prefixes => [char()], + %% default value for all missing optional arguments + default => term(), + %% root command name (program name) + progname => string() | atom(), + %% considered by `help/2' only + command => cmd_path(), %% command to print the help for + columns => pos_integer() %% viewport width, in characters +}. +%% Parser options + +-type parse_result() :: + {ok, arg_map(), Path :: cmd_path(), command()} | + {error, parser_error()}. +%% Parser result: argument map, path leading to successfully +%% matching command (contains only ["progname"] if there were +%% no subcommands matched), and a matching command. + +%% @equiv validate(Command, #{}) +-spec validate(command()) -> Progname :: string(). +validate(Command) -> + validate(Command, #{}). + +%% @doc Validate command specification, taking Options into account. +%% Raises an error if the command specification is invalid. +-spec validate(command(), parser_options()) -> Progname :: string(). +validate(Command, Options) -> + Prog = executable(Options), + is_list(Prog) orelse erlang:error(badarg, [Command, Options], + [{error_info, #{cause => #{2 => <<"progname is not valid">>}}}]), + Prefixes = maps:from_list([{P, true} || P <- maps:get(prefixes, Options, [$-])]), + _ = validate_command([{Prog, Command}], Prefixes), + Prog. + +%% @equiv parse(Args, Command, #{}) +-spec parse(Args :: [string()], command()) -> parse_result(). +parse(Args, Command) -> + parse(Args, Command, #{}). + +%% @doc Parses supplied arguments according to expected command specification. +%% @param Args command line arguments (e.g. `init:get_plain_arguments()') +%% @returns argument map, or argument map with deepest matched command +%% definition. +-spec parse(Args :: [string()], command(), Options :: parser_options()) -> parse_result(). +parse(Args, Command, Options) -> + Prog = validate(Command, Options), + %% use maps and not sets v2, because sets:is_element/2 cannot be used in guards (unlike is_map_key) + Prefixes = maps:from_list([{P, true} || P <- maps:get(prefixes, Options, [$-])]), + try + parse_impl(Args, merge_arguments(Prog, Command, init_parser(Prefixes, Command, Options))) + catch + %% Parser error may happen at any depth, and bubbling the error is really + %% cumbersome. Use exceptions and catch it before returning from `parse/2,3' instead. + throw:Reason -> + {error, Reason} + end. + +%% @equiv help(Command, #{}) +-spec help(command()) -> string(). +help(Command) -> + help(Command, #{}). + +%% @doc Returns help for Command formatted according to Options specified +-spec help(command(), parser_options()) -> unicode:chardata(). +help(Command, Options) -> + Prog = validate(Command, Options), + format_help({Prog, Command}, Options). + +%% @doc +-spec run(Args :: [string()], command(), parser_options()) -> term(). +run(Args, Command, Options) -> + try parse(Args, Command, Options) of + {ok, ArgMap, Path, SubCmd} -> + handle(Command, ArgMap, tl(Path), SubCmd); + {error, Reason} -> + io:format("error: ~ts~n", [argparse:format_error(Reason)]), + io:format("~ts", [argparse:help(Command, Options#{command => tl(element(1, Reason))})]), + erlang:halt(1) + catch + error:Reason:Stack -> + io:format(erl_error:format_exception(error, Reason, Stack)), + erlang:halt(1) + end. + +%% @doc Basic formatter for the parser error reason. +-spec format_error(Reason :: parser_error()) -> unicode:chardata(). +format_error({Path, undefined, undefined, Details}) -> + io_lib:format("~ts: ~ts", [format_path(Path), Details]); +format_error({Path, undefined, Actual, Details}) -> + io_lib:format("~ts: unknown argument: ~ts~ts", [format_path(Path), Actual, Details]); +format_error({Path, #{name := Name}, undefined, Details}) -> + io_lib:format("~ts: required argument missing: ~ts~ts", [format_path(Path), Name, Details]); +format_error({Path, #{name := Name}, Value, Details}) -> + io_lib:format("~ts: invalid argument for ~ts: ~ts ~ts", [format_path(Path), Name, Value, Details]). + +-type validator_error() :: + {?MODULE, command | argument, cmd_path(), Field :: atom(), Detail :: unicode:chardata()}. + +%% @doc Transforms exception thrown by `validate/1,2' according to EEP54. +%% Use `erl_error:format_exception/3,4' to get the shell-like output. +-spec format_error(Reason :: validator_error(), erlang:stacktrace()) -> map(). +format_error({?MODULE, command, Path, Field, Reason}, [{_M, _F, [Cmd], Info} | _]) -> + #{cause := Cause} = proplists:get_value(error_info, Info, #{}), + Cause#{general => <<"command specification is invalid">>, 1 => io_lib:format("~tp", [Cmd]), + reason => io_lib:format("command \"~ts\": invalid field '~ts', reason: ~ts", [format_path(Path), Field, Reason])}; +format_error({?MODULE, argument, Path, Field, Reason}, [{_M, _F, [Arg], Info} | _]) -> + #{cause := Cause} = proplists:get_value(error_info, Info, #{}), + ArgName = maps:get(name, Arg, ""), + Cause#{general => "argument specification is invalid", 1 => io_lib:format("~tp", [Arg]), + reason => io_lib:format("command \"~ts\", argument '~ts', invalid field '~ts': ~ts", + [format_path(Path), ArgName, Field, Reason])}. + +%%-------------------------------------------------------------------- +%% Parser implementation + +%% Parser state (not available via API) +-record(eos, { + %% prefix character map, by default, only - + prefixes :: #{char() => true}, + %% argument map to be returned + argmap = #{} :: arg_map(), + %% sub-commands, in reversed orders, allowing to recover the path taken + commands = [] :: cmd_path(), + %% command being matched + current :: command(), + %% unmatched positional arguments, in the expected match order + pos = [] :: [argument()], + %% expected optional arguments, mapping between short/long form and an argument + short = #{} :: #{integer() => argument()}, + long = #{} :: #{string() => argument()}, + %% flag, whether there are no options that can be confused with negative numbers + no_digits = true :: boolean(), + %% global default for not required arguments + default :: error | {ok, term()} +}). + +init_parser(Prefixes, Cmd, Options) -> + #eos{prefixes = Prefixes, current = Cmd, default = maps:find(default, Options)}. + +%% Optional or positional argument? +-define(IS_OPTION(Arg), is_map_key(short, Arg) orelse is_map_key(long, Arg)). + +%% helper function to match either a long form of "--arg=value", or just "--arg" +match_long(Arg, LongOpts) -> + case maps:find(Arg, LongOpts) of + {ok, Option} -> + {ok, Option}; + error -> + %% see if there is '=' equals sign in the Arg + case string:split(Arg, "=") of + [MaybeLong, Value] -> + case maps:find(MaybeLong, LongOpts) of + {ok, Option} -> + {ok, Option, Value}; + error -> + nomatch + end; + _ -> + nomatch + end + end. + +%% parse_impl implements entire internal parse logic. + +%% Clause: option starting with any prefix +%% No separate clause for single-character short form, because there could be a single-character +%% long form taking precedence. +parse_impl([[Prefix | Name] | Tail], #eos{prefixes = Pref} = Eos) when is_map_key(Prefix, Pref) -> + %% match "long" option from the list of currently known + case match_long(Name, Eos#eos.long) of + {ok, Option} -> + consume(Tail, Option, Eos); + {ok, Option, Value} -> + consume([Value | Tail], Option, Eos); + nomatch -> + %% try to match single-character flag + case Name of + [Flag] when is_map_key(Flag, Eos#eos.short) -> + %% found a flag + consume(Tail, maps:get(Flag, Eos#eos.short), Eos); + [Flag | Rest] when is_map_key(Flag, Eos#eos.short) -> + %% can be a combination of flags, or flag with value, + %% but can never be a negative integer, because otherwise + %% it will be reflected in no_digits + case abbreviated(Name, [], Eos#eos.short) of + false -> + %% short option with Rest being an argument + consume([Rest | Tail], maps:get(Flag, Eos#eos.short), Eos); + Expanded -> + %% expand multiple flags into actual list, adding prefix + parse_impl([[Prefix,E] || E <- Expanded] ++ Tail, Eos) + end; + MaybeNegative when Prefix =:= $-, Eos#eos.no_digits -> + case is_digits(MaybeNegative) of + true -> + %% found a negative number + parse_positional([Prefix|Name], Tail, Eos); + false -> + catch_all_positional([[Prefix|Name] | Tail], Eos) + end; + _Unknown -> + catch_all_positional([[Prefix|Name] | Tail], Eos) + end + end; + +%% Arguments not starting with Prefix: attempt to match sub-command, if available +parse_impl([Positional | Tail], #eos{current = #{commands := SubCommands}} = Eos) -> + case maps:find(Positional, SubCommands) of + error -> + %% sub-command not found, try positional argument + parse_positional(Positional, Tail, Eos); + {ok, SubCmd} -> + %% found matching sub-command with arguments, descend into it + parse_impl(Tail, merge_arguments(Positional, SubCmd, Eos)) + end; + +%% Clause for arguments that don't have sub-commands (therefore check for +%% positional argument). +parse_impl([Positional | Tail], Eos) -> + parse_positional(Positional, Tail, Eos); + +%% Entire command line has been matched, go over missing arguments, +%% add defaults etc +parse_impl([], #eos{argmap = ArgMap0, commands = Commands, current = Current, pos = Pos, default = Def} = Eos) -> + %% error if stopped at sub-command with no handler + map_size(maps:get(commands, Current, #{})) >0 andalso + (not is_map_key(handler, Current)) andalso + throw({Commands, undefined, undefined, <<"subcommand expected">>}), + + %% go over remaining positional, verify they are all not required + ArgMap1 = fold_args_map(Commands, true, ArgMap0, Pos, Def), + %% go over optionals, and either raise an error, or set default + ArgMap2 = fold_args_map(Commands, false, ArgMap1, maps:values(Eos#eos.short), Def), + ArgMap3 = fold_args_map(Commands, false, ArgMap2, maps:values(Eos#eos.long), Def), + + %% return argument map, command path taken, and the deepest + %% last command matched (usually it contains a handler to run) + {ok, ArgMap3, Eos#eos.commands, Eos#eos.current}. + +%% Generate error for missing required argument, and supply defaults for +%% missing optional arguments that have defaults. +fold_args_map(Commands, Req, ArgMap, Args, GlobalDefault) -> + lists:foldl( + fun (#{name := Name}, Acc) when is_map_key(Name, Acc) -> + %% argument present + Acc; + (#{required := true} = Opt, _Acc) -> + %% missing, and required explicitly + throw({Commands, Opt, undefined, <<>>}); + (#{name := Name, required := false, default := Default}, Acc) -> + %% explicitly not required argument with default + Acc#{Name => Default}; + (#{name := Name, required := false}, Acc) -> + %% explicitly not required with no local default, try global one + try_global_default(Name, Acc, GlobalDefault); + (#{name := Name, default := Default}, Acc) when Req =:= true -> + %% positional argument with default + Acc#{Name => Default}; + (Opt, _Acc) when Req =:= true -> + %% missing, for positional argument, implicitly required + throw({Commands, Opt, undefined, <<>>}); + (#{name := Name, default := Default}, Acc) -> + %% missing, optional, and there is a default + Acc#{Name => Default}; + (#{name := Name}, Acc) -> + %% missing, optional, no local default, try global default + try_global_default(Name, Acc, GlobalDefault) + end, ArgMap, Args). + +try_global_default(_Name, Acc, error) -> + Acc; +try_global_default(Name, Acc, {ok, Term}) -> + Acc#{Name => Term}. + +%%-------------------------------------------------------------------- +%% argument consumption (nargs) handling + +catch_all_positional(Tail, #eos{pos = [#{nargs := all} = Opt]} = Eos) -> + action([], Tail, Opt#{type => {list, maps:get(type, Opt, string)}}, Eos); +%% it is possible that some positional arguments are not required, +%% and therefore it is possible to catch all skipping those +catch_all_positional(Tail, #eos{argmap = Args, pos = [#{name := Name, default := Default, required := false} | Pos]} = Eos) -> + catch_all_positional(Tail, Eos#eos{argmap = Args#{Name => Default}, pos = Pos}); +%% same as above, but no default specified +catch_all_positional(Tail, #eos{pos = [#{required := false} | Pos]} = Eos) -> + catch_all_positional(Tail, Eos#eos{pos = Pos}); +catch_all_positional([Arg | _Tail], #eos{commands = Commands}) -> + throw({Commands, undefined, Arg, <<>>}). + +parse_positional(Arg, _Tail, #eos{pos = [], commands = Commands}) -> + throw({Commands, undefined, Arg, <<>>}); +parse_positional(Arg, Tail, #eos{pos = Pos} = Eos) -> + %% positional argument itself is a value + consume([Arg | Tail], hd(Pos), Eos). + +%% Adds CmdName to path, and includes any arguments found there +merge_arguments(CmdName, #{arguments := Args} = SubCmd, Eos) -> + add_args(Args, Eos#eos{current = SubCmd, commands = Eos#eos.commands ++ [CmdName]}); +merge_arguments(CmdName, SubCmd, Eos) -> + Eos#eos{current = SubCmd, commands = Eos#eos.commands ++ [CmdName]}. + +%% adds arguments into current set of discovered pos/opts +add_args([], Eos) -> + Eos; +add_args([#{short := S, long := L} = Option | Tail], #eos{short = Short, long = Long} = Eos) -> + %% remember if this option can be confused with negative number + NoDigits = no_digits(Eos#eos.no_digits, Eos#eos.prefixes, S, L), + add_args(Tail, Eos#eos{short = Short#{S => Option}, long = Long#{L => Option}, no_digits = NoDigits}); +add_args([#{short := S} = Option | Tail], #eos{short = Short} = Eos) -> + %% remember if this option can be confused with negative number + NoDigits = no_digits(Eos#eos.no_digits, Eos#eos.prefixes, S, 0), + add_args(Tail, Eos#eos{short = Short#{S => Option}, no_digits = NoDigits}); +add_args([#{long := L} = Option | Tail], #eos{long = Long} = Eos) -> + %% remember if this option can be confused with negative number + NoDigits = no_digits(Eos#eos.no_digits, Eos#eos.prefixes, 0, L), + add_args(Tail, Eos#eos{long = Long#{L => Option}, no_digits = NoDigits}); +add_args([PosOpt | Tail], #eos{pos = Pos} = Eos) -> + add_args(Tail, Eos#eos{pos = Pos ++ [PosOpt]}). + +%% If no_digits is still true, try to find out whether it should turn false, +%% because added options look like negative numbers, and prefixes include - +no_digits(false, _, _, _) -> + false; +no_digits(true, Prefixes, _, _) when not is_map_key($-, Prefixes) -> + true; +no_digits(true, _, Short, _) when Short >= $0, Short =< $9 -> + false; +no_digits(true, _, _, Long) -> + not is_digits(Long). + +%%-------------------------------------------------------------------- +%% additional functions for optional arguments processing + +%% Returns true when option (!) description passed requires a positional argument, +%% hence cannot be treated as a flag. +requires_argument(#{nargs := {'maybe', _Term}}) -> + false; +requires_argument(#{nargs := 'maybe'}) -> + false; +requires_argument(#{nargs := _Any}) -> + true; +requires_argument(Opt) -> + case maps:get(action, Opt, store) of + store -> + maps:get(type, Opt, string) =/= boolean; + append -> + maps:get(type, Opt, string) =/= boolean; + _ -> + false + end. + +%% Attempts to find if passed list of flags can be expanded +abbreviated([Last], Acc, AllShort) when is_map_key(Last, AllShort) -> + lists:reverse([Last | Acc]); +abbreviated([_], _Acc, _Eos) -> + false; +abbreviated([Flag | Tail], Acc, AllShort) -> + case maps:find(Flag, AllShort) of + error -> + false; + {ok, Opt} -> + case requires_argument(Opt) of + true -> + false; + false -> + abbreviated(Tail, [Flag | Acc], AllShort) + end + end. + +%%-------------------------------------------------------------------- +%% argument consumption (nargs) handling + +%% consume predefined amount (none of which can be an option?) +consume(Tail, #{nargs := Count} = Opt, Eos) when is_integer(Count) -> + {Consumed, Remain} = split_to_option(Tail, Count, Eos, []), + length(Consumed) < Count andalso + throw({Eos#eos.commands, Opt, Tail, + io_lib:format("expected ~b, found ~b argument(s)", [Count, length(Consumed)])}), + action(Remain, Consumed, Opt#{type => {list, maps:get(type, Opt, string)}}, Eos); + +%% handle 'reminder' by just dumping everything in +consume(Tail, #{nargs := all} = Opt, Eos) -> + action([], Tail, Opt#{type => {list, maps:get(type, Opt, string)}}, Eos); + +%% require at least one argument +consume(Tail, #{nargs := nonempty_list} = Opt, Eos) -> + {Consumed, Remains} = split_to_option(Tail, -1, Eos, []), + Consumed =:= [] andalso throw({Eos#eos.commands, Opt, Tail, <<"expected argument">>}), + action(Remains, Consumed, Opt#{type => {list, maps:get(type, Opt, string)}}, Eos); + +%% consume all until next option +consume(Tail, #{nargs := list} = Opt, Eos) -> + {Consumed, Remains} = split_to_option(Tail, -1, Eos, []), + action(Remains, Consumed, Opt#{type => {list, maps:get(type, Opt, string)}}, Eos); + +%% maybe consume one, maybe not... +%% special cases for 'boolean maybe', only consume 'true' and 'false' +consume(["true" | Tail], #{type := boolean} = Opt, Eos) -> + action(Tail, true, Opt#{type => raw}, Eos); +consume(["false" | Tail], #{type := boolean} = Opt, Eos) -> + action(Tail, false, Opt#{type => raw}, Eos); +consume(Tail, #{type := boolean} = Opt, Eos) -> + %% neither true nor false means 'undefined' (with the default for boolean being true) + action(Tail, undefined, Opt, Eos); + +%% maybe behaviour, as '?' +consume(Tail, #{nargs := 'maybe'} = Opt, Eos) -> + case split_to_option(Tail, 1, Eos, []) of + {[], _} -> + %% no argument given, produce default argument (if not present, + %% then produce default value of the specified type) + action(Tail, default(Opt), Opt#{type => raw}, Eos); + {[Consumed], Remains} -> + action(Remains, Consumed, Opt, Eos) + end; + +%% maybe consume one, maybe not... +consume(Tail, #{nargs := {'maybe', Const}} = Opt, Eos) -> + case split_to_option(Tail, 1, Eos, []) of + {[], _} -> + action(Tail, Const, Opt, Eos); + {[Consumed], Remains} -> + action(Remains, Consumed, Opt, Eos) + end; + +%% default case, which depends on action +consume(Tail, #{action := count} = Opt, Eos) -> + action(Tail, undefined, Opt, Eos); + +%% for {store, ...} and {append, ...} don't take argument out +consume(Tail, #{action := {Act, _Const}} = Opt, Eos) when Act =:= store; Act =:= append -> + action(Tail, undefined, Opt, Eos); + +%% optional: ensure not to consume another option start +consume([[Prefix | _] = ArgValue | Tail], Opt, Eos) when ?IS_OPTION(Opt), is_map_key(Prefix, Eos#eos.prefixes) -> + case Eos#eos.no_digits andalso is_digits(ArgValue) of + true -> + action(Tail, ArgValue, Opt, Eos); + false -> + throw({Eos#eos.commands, Opt, undefined, <<"expected argument">>}) + end; + +consume([ArgValue | Tail], Opt, Eos) -> + action(Tail, ArgValue, Opt, Eos); + +%% we can only be here if it's optional argument, but there is no value supplied, +%% and type is not 'boolean' - this is an error! +consume([], Opt, Eos) -> + throw({Eos#eos.commands, Opt, undefined, <<"expected argument">>}). + +%% no more arguments for consumption, but last optional may still be action-ed +%%consume([], Current, Opt, Eos) -> +%% action([], Current, undefined, Opt, Eos). + +%% smart split: ignore arguments that can be parsed as negative numbers, +%% unless there are arguments that look like negative numbers +split_to_option([], _, _Eos, Acc) -> + {lists:reverse(Acc), []}; +split_to_option(Tail, 0, _Eos, Acc) -> + {lists:reverse(Acc), Tail}; +split_to_option([[Prefix | _] = MaybeNumber | Tail] = All, Left, + #eos{no_digits = true, prefixes = Prefixes} = Eos, Acc) when is_map_key(Prefix, Prefixes) -> + case is_digits(MaybeNumber) of + true -> + split_to_option(Tail, Left - 1, Eos, [MaybeNumber | Acc]); + false -> + {lists:reverse(Acc), All} + end; +split_to_option([[Prefix | _] | _] = All, _Left, + #eos{no_digits = false, prefixes = Prefixes}, Acc) when is_map_key(Prefix, Prefixes) -> + {lists:reverse(Acc), All}; +split_to_option([Head | Tail], Left, Opts, Acc) -> + split_to_option(Tail, Left - 1, Opts, [Head | Acc]). + +%%-------------------------------------------------------------------- +%% Action handling + +action(Tail, ArgValue, #{name := ArgName, action := store} = Opt, #eos{argmap = ArgMap} = Eos) -> + Value = convert_type(maps:get(type, Opt, string), ArgValue, Opt, Eos), + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => Value}}); + +action(Tail, undefined, #{name := ArgName, action := {store, Value}} = Opt, #eos{argmap = ArgMap} = Eos) -> + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => Value}}); + +action(Tail, ArgValue, #{name := ArgName, action := append} = Opt, #eos{argmap = ArgMap} = Eos) -> + Value = convert_type(maps:get(type, Opt, string), ArgValue, Opt, Eos), + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => maps:get(ArgName, ArgMap, []) ++ [Value]}}); + +action(Tail, undefined, #{name := ArgName, action := {append, Value}} = Opt, #eos{argmap = ArgMap} = Eos) -> + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => maps:get(ArgName, ArgMap, []) ++ [Value]}}); + +action(Tail, ArgValue, #{name := ArgName, action := extend} = Opt, #eos{argmap = ArgMap} = Eos) -> + Value = convert_type(maps:get(type, Opt, string), ArgValue, Opt, Eos), + Extended = maps:get(ArgName, ArgMap, []) ++ Value, + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => Extended}}); + +action(Tail, _, #{name := ArgName, action := count} = Opt, #eos{argmap = ArgMap} = Eos) -> + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => maps:get(ArgName, ArgMap, 0) + 1}}); + +%% default action is `store' (important to sync the code with the first clause above) +action(Tail, ArgValue, #{name := ArgName} = Opt, #eos{argmap = ArgMap} = Eos) -> + Value = convert_type(maps:get(type, Opt, string), ArgValue, Opt, Eos), + continue_parser(Tail, Opt, Eos#eos{argmap = ArgMap#{ArgName => Value}}). + +%% pop last positional, unless nargs is list/nonempty_list +continue_parser(Tail, Opt, Eos) when ?IS_OPTION(Opt) -> + parse_impl(Tail, Eos); +continue_parser(Tail, #{nargs := List}, Eos) when List =:= list; List =:= nonempty_list -> + parse_impl(Tail, Eos); +continue_parser(Tail, _Opt, Eos) -> + parse_impl(Tail, Eos#eos{pos = tl(Eos#eos.pos)}). + +%%-------------------------------------------------------------------- +%% Type conversion + +%% Handle "list" variant for nargs returning list +convert_type({list, Type}, Arg, Opt, Eos) -> + [convert_type(Type, Var, Opt, Eos) || Var <- Arg]; + +%% raw - no conversion applied (most likely default) +convert_type(raw, Arg, _Opt, _Eos) -> + Arg; + +%% Handle actual types +convert_type(string, Arg, _Opt, _Eos) -> + Arg; +convert_type({string, Choices}, Arg, Opt, Eos) when is_list(Choices), is_list(hd(Choices)) -> + lists:member(Arg, Choices) orelse + throw({Eos#eos.commands, Opt, Arg, <<"is not one of the choices">>}), + Arg; +convert_type({string, Re}, Arg, Opt, Eos) -> + case re:run(Arg, Re) of + {match, _X} -> Arg; + _ -> throw({Eos#eos.commands, Opt, Arg, <<"does not match">>}) + end; +convert_type({string, Re, ReOpt}, Arg, Opt, Eos) -> + case re:run(Arg, Re, ReOpt) of + match -> Arg; + {match, _} -> Arg; + _ -> throw({Eos#eos.commands, Opt, Arg, <<"does not match">>}) + end; +convert_type(integer, Arg, Opt, Eos) -> + get_int(Arg, Opt, Eos); +convert_type({integer, Opts}, Arg, Opt, Eos) -> + minimax(get_int(Arg, Opt, Eos), Opts, Eos, Opt, Arg); +convert_type(boolean, "true", _Opt, _Eos) -> + true; +convert_type(boolean, undefined, _Opt, _Eos) -> + true; +convert_type(boolean, "false", _Opt, _Eos) -> + false; +convert_type(boolean, Arg, Opt, Eos) -> + throw({Eos#eos.commands, Opt, Arg, <<"is not a boolean">>}); +convert_type(binary, Arg, _Opt, _Eos) -> + unicode:characters_to_binary(Arg); +convert_type({binary, Choices}, Arg, Opt, Eos) when is_list(Choices), is_binary(hd(Choices)) -> + Conv = unicode:characters_to_binary(Arg), + lists:member(Conv, Choices) orelse + throw({Eos#eos.commands, Opt, Arg, <<"is not one of the choices">>}), + Conv; +convert_type({binary, Re}, Arg, Opt, Eos) -> + case re:run(Arg, Re) of + {match, _X} -> unicode:characters_to_binary(Arg); + _ -> throw({Eos#eos.commands, Opt, Arg, <<"does not match">>}) + end; +convert_type({binary, Re, ReOpt}, Arg, Opt, Eos) -> + case re:run(Arg, Re, ReOpt) of + match -> unicode:characters_to_binary(Arg); + {match, _} -> unicode:characters_to_binary(Arg); + _ -> throw({Eos#eos.commands, Opt, Arg, <<"does not match">>}) + end; +convert_type(float, Arg, Opt, Eos) -> + get_float(Arg, Opt, Eos); +convert_type({float, Opts}, Arg, Opt, Eos) -> + minimax(get_float(Arg, Opt, Eos), Opts, Eos, Opt, Arg); +convert_type(atom, Arg, Opt, Eos) -> + try list_to_existing_atom(Arg) + catch error:badarg -> + throw({Eos#eos.commands, Opt, Arg, <<"is not an existing atom">>}) + end; +convert_type({atom, unsafe}, Arg, _Opt, _Eos) -> + list_to_atom(Arg); +convert_type({atom, Choices}, Arg, Opt, Eos) -> + try + Atom = list_to_existing_atom(Arg), + lists:member(Atom, Choices) orelse throw({Eos#eos.commands, Opt, Arg, <<"is not one of the choices">>}), + Atom + catch error:badarg -> + throw({Eos#eos.commands, Opt, Arg, <<"is not an existing atom">>}) + end; +convert_type({custom, Fun}, Arg, Opt, Eos) -> + try Fun(Arg) + catch error:badarg -> + throw({Eos#eos.commands, Opt, Arg, <<"failed faildation">>}) + end. + +%% Given Var, and list of {min, X}, {max, Y}, ensure that +%% value falls within defined limits. +minimax(Var, [], _Eos, _Opt, _Orig) -> + Var; +minimax(Var, [{min, Min} | _], Eos, Opt, Orig) when Var < Min -> + throw({Eos#eos.commands, Opt, Orig, <<"is less than accepted minimum">>}); +minimax(Var, [{max, Max} | _], Eos, Opt, Orig) when Var > Max -> + throw({Eos#eos.commands, Opt, Orig, <<"is greater than accepted maximum">>}); +minimax(Var, [Num | Tail], Eos, Opt, Orig) when is_number(Num) -> + lists:member(Var, [Num|Tail]) orelse + throw({Eos#eos.commands, Opt, Orig, <<"is not one of the choices">>}), + Var; +minimax(Var, [_ | Tail], Eos, Opt, Orig) -> + minimax(Var, Tail, Eos, Opt, Orig). + +%% returns integer from string, or errors out with debugging info +get_int(Arg, Opt, Eos) -> + case string:to_integer(Arg) of + {Int, []} -> + Int; + _ -> + throw({Eos#eos.commands, Opt, Arg, <<"is not an integer">>}) + end. + +%% returns float from string, that is floating-point, or integer +get_float(Arg, Opt, Eos) -> + case string:to_float(Arg) of + {Float, []} -> + Float; + _ -> + %% possibly in disguise + case string:to_integer(Arg) of + {Int, []} -> + Int; + _ -> + throw({Eos#eos.commands, Opt, Arg, <<"is not a number">>}) + end + end. + +%% Returns 'true' if String can be converted to a number +is_digits(String) -> + case string:to_integer(String) of + {_Int, []} -> + true; + {_, _} -> + case string:to_float(String) of + {_Float, []} -> + true; + {_, _} -> + false + end + end. + +%% 'maybe' nargs for an option that does not have default set still have +%% to produce something, let's call it hardcoded default. +default(#{default := Default}) -> + Default; +default(#{type := boolean}) -> + true; +default(#{type := integer}) -> + 0; +default(#{type := float}) -> + 0.0; +default(#{type := string}) -> + ""; +default(#{type := binary}) -> + <<"">>; +default(#{type := atom}) -> + undefined; +%% no type given, consider it 'undefined' atom +default(_) -> + undefined. + +%% command path is now in direct order +format_path(Commands) -> + lists:join(" ", Commands). + +%%-------------------------------------------------------------------- +%% Validation and preprocessing +%% Theoretically, Dialyzer should do that too. +%% Practically, so many people ignore Dialyzer and then spend hours +%% trying to understand why things don't work, that is makes sense +%% to provide a mini-Dialyzer here. + +%% to simplify throwing errors with the right reason +-define (INVALID(Kind, Entity, Path, Field, Text), + erlang:error({?MODULE, Kind, clean_path(Path), Field, Text}, [Entity], [{error_info, #{cause => #{}}}])). + +executable(#{progname := Prog}) when is_atom(Prog) -> + atom_to_list(Prog); +executable(#{progname := Prog}) when is_binary(Prog) -> + binary_to_list(Prog); +executable(#{progname := Prog}) -> + Prog; +executable(_) -> + {ok, [[Prog]]} = init:get_argument(progname), + Prog. + +%% Recursive command validator +validate_command([{Name, Cmd} | _] = Path, Prefixes) -> + (is_list(Name) andalso (not is_map_key(hd(Name), Prefixes))) orelse + ?INVALID(command, Cmd, tl(Path), commands, + <<"command name must be a string not starting with option prefix">>), + is_map(Cmd) orelse + ?INVALID(command, Cmd, Path, commands, <<"expected command()">>), + is_valid_command_help(maps:get(help, Cmd, [])) orelse + ?INVALID(command, Cmd, Path, help, <<"must be a printable unicode list, or a command help template">>), + is_map(maps:get(commands, Cmd, #{})) orelse + ?INVALID(command, Cmd, Path, commands, <<"expected map of #{string() => command()}">>), + case maps:get(handler, Cmd, optional) of + optional -> ok; + {Mod, ModFun} when is_atom(Mod), is_atom(ModFun) -> ok; %% map form + {Mod, ModFun, _} when is_atom(Mod), is_atom(ModFun) -> ok; %% positional form + {Fun, _} when is_function(Fun) -> ok; %% positional form + Fun when is_function(Fun, 1) -> ok; + _ -> ?INVALID(command, Cmd, Path, handler, <<"handler must be a valid callback, or an atom 'optional'">>) + end, + Cmd1 = + case maps:find(arguments, Cmd) of + error -> + Cmd; + {ok, Opts} when not is_list(Opts) -> + ?INVALID(command, Cmd, Path, arguments, <<"expected a list, [argument()]">>); + {ok, Opts} -> + Cmd#{arguments => [validate_option(Path, Opt) || Opt <- Opts]} + end, + %% collect all short & long option identifiers - to figure out any conflicts + lists:foldl( + fun ({_, #{arguments := Opts}}, Acc) -> + lists:foldl( + fun (#{short := Short, name := OName} = Arg, {AllS, AllL}) -> + is_map_key(Short, AllS) andalso + ?INVALID(argument, Arg, Path, short, + "short conflicting with previously defined short for " + ++ atom_to_list(maps:get(Short, AllS))), + {AllS#{Short => OName}, AllL}; + (#{long := Long, name := OName} = Arg, {AllS, AllL}) -> + is_map_key(Long, AllL) andalso + ?INVALID(argument, Arg, Path, long, + "long conflicting with previously defined long for " + ++ atom_to_list(maps:get(Long, AllL))), + {AllS, AllL#{Long => OName}}; + (_, AccIn) -> + AccIn + end, Acc, Opts); + (_, Acc) -> + Acc + end, {#{}, #{}}, Path), + %% verify all sub-commands + case maps:find(commands, Cmd1) of + error -> + {Name, Cmd1}; + {ok, Sub} -> + {Name, Cmd1#{commands => maps:map( + fun (K, V) -> + {K, Updated} = validate_command([{K, V} | Path], Prefixes), + Updated + end, Sub)}} + end. + +%% validates option spec +validate_option(Path, #{name := Name} = Arg) when is_atom(Name); is_list(Name); is_binary(Name) -> + %% verify specific arguments + %% help: string, 'hidden', or a tuple of {string(), ...} + is_valid_option_help(maps:get(help, Arg, [])) orelse + ?INVALID(argument, Arg, Path, help, <<"must be a string or valid help template">>), + io_lib:printable_unicode_list(maps:get(long, Arg, [])) orelse + ?INVALID(argument, Arg, Path, long, <<"must be a printable string">>), + is_boolean(maps:get(required, Arg, true)) orelse + ?INVALID(argument, Arg, Path, required, <<"must be a boolean">>), + io_lib:printable_unicode_list([maps:get(short, Arg, $a)]) orelse + ?INVALID(argument, Arg, Path, short, <<"must be a printable character">>), + Opt1 = maybe_validate(action, Arg, fun validate_action/3, Path), + Opt2 = maybe_validate(type, Opt1, fun validate_type/3, Path), + maybe_validate(nargs, Opt2, fun validate_args/3, Path); +validate_option(Path, Arg) -> + ?INVALID(argument, Arg, Path, name, <<"argument must be a map containing 'name' field">>). + +maybe_validate(Key, Map, Fun, Path) when is_map_key(Key, Map) -> + maps:put(Key, Fun(maps:get(Key, Map), Path, Map), Map); +maybe_validate(_Key, Map, _Fun, _Path) -> + Map. + +%% validate action field +validate_action(store, _Path, _Opt) -> + store; +validate_action({store, Term}, _Path, _Opt) -> + {store, Term}; +validate_action(append, _Path, _Opt) -> + append; +validate_action({append, Term}, _Path, _Opt) -> + {append, Term}; +validate_action(count, _Path, _Opt) -> + count; +validate_action(extend, _Path, #{nargs := Nargs}) when + Nargs =:= list; Nargs =:= nonempty_list; Nargs =:= all; is_integer(Nargs) -> + extend; +validate_action(extend, _Path, #{type := {custom, _}}) -> + extend; +validate_action(extend, Path, Arg) -> + ?INVALID(argument, Arg, Path, action, <<"extend action works only with lists">>); +validate_action(_Action, Path, Arg) -> + ?INVALID(argument, Arg, Path, action, <<"unsupported">>). + +%% validate type field +validate_type(Simple, _Path, _Opt) when Simple =:= boolean; Simple =:= integer; Simple =:= float; + Simple =:= string; Simple =:= binary; Simple =:= atom; Simple =:= {atom, unsafe} -> + Simple; +validate_type({custom, Fun}, _Path, _Opt) when is_function(Fun, 1) -> + {custom, Fun}; +validate_type({float, Opts}, Path, Arg) -> + [?INVALID(argument, Arg, Path, type, <<"invalid validator">>) + || {Kind, Val} <- Opts, (Kind =/= min andalso Kind =/= max) orelse (not is_float(Val))], + {float, Opts}; +validate_type({integer, Opts}, Path, Arg) -> + [?INVALID(argument, Arg, Path, type, <<"invalid validator">>) + || {Kind, Val} <- Opts, (Kind =/= min andalso Kind =/= max) orelse (not is_integer(Val))], + {integer, Opts}; +validate_type({atom, Choices} = Valid, Path, Arg) when is_list(Choices) -> + [?INVALID(argument, Arg, Path, type, <<"unsupported">>) || C <- Choices, not is_atom(C)], + Valid; +validate_type({string, Re} = Valid, _Path, _Opt) when is_list(Re) -> + Valid; +validate_type({string, Re, L} = Valid, _Path, _Opt) when is_list(Re), is_list(L) -> + Valid; +validate_type({binary, Re} = Valid, _Path, _Opt) when is_binary(Re) -> + Valid; +validate_type({binary, Choices} = Valid, _Path, _Opt) when is_list(Choices), is_binary(hd(Choices)) -> + Valid; +validate_type({binary, Re, L} = Valid, _Path, _Opt) when is_binary(Re), is_list(L) -> + Valid; +validate_type(_Type, Path, Arg) -> + ?INVALID(argument, Arg, Path, type, <<"unsupported">>). + +validate_args(N, _Path, _Opt) when is_integer(N), N >= 1 -> N; +validate_args(Simple, _Path, _Opt) when Simple =:= all; Simple =:= list; Simple =:= 'maybe'; Simple =:= nonempty_list -> + Simple; +validate_args({'maybe', Term}, _Path, _Opt) -> {'maybe', Term}; +validate_args(_Nargs, Path, Arg) -> + ?INVALID(argument, Arg, Path, nargs, <<"unsupported">>). + +%% used to throw an error - strips command component out of path +clean_path(Path) -> + {Cmds, _} = lists:unzip(Path), + lists:reverse(Cmds). + +is_valid_option_help(hidden) -> + true; +is_valid_option_help(Help) when is_list(Help); is_binary(Help) -> + true; +is_valid_option_help({Short, Desc}) when is_list(Short) orelse is_binary(Short), is_list(Desc) -> + %% verify that Desc is a list of string/type/default + lists:all(fun(type) -> true; + (default) -> true; + (S) when is_list(S); is_binary(S) -> true; + (_) -> false + end, Desc); +is_valid_option_help({Short, Desc}) when is_list(Short) orelse is_binary(Short), is_function(Desc, 0) -> + true; +is_valid_option_help(_) -> + false. + +is_valid_command_help(hidden) -> + true; +is_valid_command_help(Help) when is_binary(Help) -> + true; +is_valid_command_help(Help) when is_list(Help) -> + %% allow printable lists + case io_lib:printable_unicode_list(Help) of + true -> + true; + false -> + %% ... or a command help template + lists:all( + fun (Atom) when Atom =:= usage; Atom =:= commands; Atom =:= arguments; Atom =:= options -> true; + (Bin) when is_binary(Bin) -> true; + (Str) -> io_lib:printable_unicode_list(Str) + end, Help) + end; +is_valid_command_help(_) -> + false. + +%%-------------------------------------------------------------------- +%% Built-in Help formatter + +format_help({ProgName, Root}, Format) -> + Prefix = hd(maps:get(prefixes, Format, [$-])), + Nested = maps:get(command, Format, []), + %% descent into commands collecting all options on the way + {_CmdName, Cmd, AllArgs} = collect_options(ProgName, Root, Nested, []), + %% split arguments into Flags, Options, Positional, and create help lines + {_, Longest, Flags, Opts, Args, OptL, PosL} = lists:foldl(fun format_opt_help/2, + {Prefix, 0, "", [], [], [], []}, AllArgs), + %% collect and format sub-commands + Immediate = maps:get(commands, Cmd, #{}), + {Long, Subs} = maps:fold( + fun (_Name, #{help := hidden}, {Long, SubAcc}) -> + {Long, SubAcc}; + (Name, Sub, {Long, SubAcc}) -> + Help = maps:get(help, Sub, ""), + {max(Long, string:length(Name)), [{Name, Help}|SubAcc]} + end, {Longest, []}, maps:iterator(Immediate, ordered)), + %% format sub-commands + ShortCmd0 = + case map_size(Immediate) of + 0 -> + []; + Small when Small < 4 -> + Keys = lists:sort(maps:keys(Immediate)), + ["{" ++ lists:append(lists:join("|", Keys)) ++ "}"]; + _Largs -> + [""] + end, + %% was it nested command? + ShortCmd = if Nested =:= [] -> ShortCmd0; true -> [lists:append(lists:join(" ", Nested)) | ShortCmd0] end, + %% format flags + FlagsForm = if Flags =:= [] -> []; + true -> [unicode:characters_to_list(io_lib:format("[~tc~ts]", [Prefix, Flags]))] + end, + %% format extended view + %% usage line has hardcoded format for now + Usage = [ProgName, ShortCmd, FlagsForm, Opts, Args], + %% format usage according to help template + Template0 = maps:get(help, Root, ""), + %% when there is no help defined for the command, or help is a string, + %% use the default format (original argparse behaviour) + Template = + case Template0 =:= "" orelse io_lib:printable_unicode_list(Template0) of + true -> + %% classic/compatibility format + NL = [io_lib:nl()], + Template1 = ["Usage:" ++ NL, usage, NL], + Template2 = maybe_add("~n", Template0, Template0 ++ NL, Template1), + Template3 = maybe_add("~nSubcommands:~n", Subs, commands, Template2), + Template4 = maybe_add("~nArguments:~n", PosL, arguments, Template3), + maybe_add("~nOptional arguments:~n", OptL, options, Template4); + false -> + Template0 + end, + + %% produce formatted output, taking viewport width into account + Parts = #{usage => Usage, commands => {Long, Subs}, + arguments => {Longest, PosL}, options => {Longest, OptL}}, + Width = maps:get(columns, Format, 80), %% might also use io:columns() here + lists:append([format_width(maps:find(Part, Parts), Part, Width) || Part <- Template]). + +%% collects options on the Path, and returns found Command +collect_options(CmdName, Command, [], Args) -> + {CmdName, Command, maps:get(arguments, Command, []) ++ Args}; +collect_options(CmdName, Command, [Cmd|Tail], Args) -> + Sub = maps:get(commands, Command), + SubCmd = maps:get(Cmd, Sub), + collect_options(CmdName ++ " " ++ Cmd, SubCmd, Tail, maps:get(arguments, Command, []) ++ Args). + +%% conditionally adds text and empty lines +maybe_add(_ToAdd, [], _Element, Template) -> + Template; +maybe_add(ToAdd, _List, Element, Template) -> + Template ++ [io_lib:format(ToAdd, []), Element]. + +format_width(error, Part, Width) -> + wrap_text(Part, 0, Width); +format_width({ok, [ProgName, ShortCmd, FlagsForm, Opts, Args]}, usage, Width) -> + %% make every separate command/option to be a "word", and then + %% wordwrap it indented by the ProgName length + 3 + Words = ShortCmd ++ FlagsForm ++ Opts ++ Args, + if Words =:= [] -> io_lib:format(" ~ts", [ProgName]); + true -> + Indent = string:length(ProgName), + Wrapped = wordwrap(Words, Width - Indent, 0, [], []), + Pad = lists:append(lists:duplicate(Indent + 3, " ")), + ArgLines = lists:join([io_lib:nl() | Pad], Wrapped), + io_lib:format(" ~ts~ts", [ProgName, ArgLines]) + end; +format_width({ok, {Len, Texts}}, _Part, Width) -> + SubFormat = io_lib:format(" ~~-~bts ~~ts~n", [Len]), + [io_lib:format(SubFormat, [N, wrap_text(D, Len + 3, Width)]) || {N, D} <- lists:reverse(Texts)]. + +wrap_text(Text, Indent, Width) -> + %% split text into separate lines (paragraphs) + NL = io_lib:nl(), + Lines = string:split(Text, NL, all), + %% wordwrap every paragraph + Paragraphs = lists:append([wrap_line(L, Width, Indent) || L <- Lines]), + Pad = lists:append(lists:duplicate(Indent, " ")), + lists:join([NL | Pad], Paragraphs). + +wrap_line([], _Width, _Indent) -> + [[]]; +wrap_line(Line, Width, Indent) -> + [First | Tail] = string:split(Line, " ", all), + wordwrap(Tail, Width - Indent, string:length(First), First, []). + +wordwrap([], _Max, _Len, [], Lines) -> + lists:reverse(Lines); +wordwrap([], _Max, _Len, Line, Lines) -> + lists:reverse([Line | Lines]); +wordwrap([Word | Tail], Max, Len, Line, Lines) -> + WordLen = string:length(Word), + case Len + 1 + WordLen > Max of + true -> + wordwrap(Tail, Max, WordLen, Word, [Line | Lines]); + false -> + wordwrap(Tail, Max, WordLen + 1 + Len, [Line, <<" ">>, Word], Lines) + end. + +%% create help line for every option, collecting together all flags, short options, +%% long options, and positional arguments + +%% format optional argument +format_opt_help(#{help := hidden}, Acc) -> + Acc; +format_opt_help(Opt, {Prefix, Longest, Flags, Opts, Args, OptL, PosL}) when ?IS_OPTION(Opt) -> + Desc = format_description(Opt), + %% does it need an argument? look for nargs and action + RequiresArg = requires_argument(Opt), + %% long form always added to Opts + NonOption = maps:get(required, Opt, false) =:= true, + {Name0, MaybeOpt0} = + case maps:find(long, Opt) of + error -> + {"", []}; + {ok, Long} when NonOption, RequiresArg -> + FN = [Prefix | Long], + {FN, [format_required(true, [FN, " "], Opt)]}; + {ok, Long} when RequiresArg -> + FN = [Prefix | Long], + {FN, [format_required(false, [FN, " "], Opt)]}; + {ok, Long} when NonOption -> + FN = [Prefix | Long], + {FN, [FN]}; + {ok, Long} -> + FN = [Prefix | Long], + {FN, [io_lib:format("[~ts]", [FN])]} + end, + %% short may go to flags, or Opts + {Name, MaybeFlag, MaybeOpt1} = + case maps:find(short, Opt) of + error -> + {Name0, [], MaybeOpt0}; + {ok, Short} when RequiresArg -> + SN = [Prefix, Short], + {maybe_concat(SN, Name0), [], + [format_required(NonOption, [SN, " "], Opt) | MaybeOpt0]}; + {ok, Short} -> + {maybe_concat([Prefix, Short], Name0), [Short], MaybeOpt0} + end, + %% apply override for non-default usage (in form of {Quick, Advanced} tuple + MaybeOpt2 = + case maps:find(help, Opt) of + {ok, {Str, _}} -> + [Str]; + _ -> + MaybeOpt1 + end, + %% name length, capped at 24 + NameLen = string:length(Name), + Capped = min(24, NameLen), + {Prefix, max(Capped, Longest), Flags ++ MaybeFlag, Opts ++ MaybeOpt2, Args, [{Name, Desc} | OptL], PosL}; + +%% format positional argument +format_opt_help(#{name := Name} = Opt, {Prefix, Longest, Flags, Opts, Args, OptL, PosL}) -> + Desc = format_description(Opt), + %% positional, hence required + LName = io_lib:format("~ts", [Name]), + LPos = case maps:find(help, Opt) of + {ok, {Str, _}} -> + Str; + _ -> + format_required(maps:get(required, Opt, true), "", Opt) + end, + {Prefix, max(Longest, string:length(LName)), Flags, Opts, Args ++ [LPos], OptL, [{LName, Desc} | PosL]}. + +%% custom format +format_description(#{help := {_Short, Fun}}) when is_function(Fun, 0) -> + Fun(); +format_description(#{help := {_Short, Desc}} = Opt) -> + lists:map( + fun (type) -> + format_type(Opt); + (default) -> + format_default(Opt); + (String) -> + String + end, Desc + ); +%% default format: +%% "desc" +%% "desc (type)" +%% "desc, default: abc" +%% "desc (type), default: abc" +format_description(#{name := Name} = Opt) -> + NameStr = maps:get(help, Opt, io_lib:format("~ts", [Name])), + case {NameStr, format_type(Opt), format_default(Opt)} of + {"", "", Type} -> Type; + {"", Default, ""} -> Default; + {Desc, "", ""} -> Desc; + {Desc, "", Default} -> [Desc, " , default: ", Default]; + {Desc, Type, ""} -> [Desc, " (", Type, ")"]; + {"", Type, Default} -> [Type, ", default: ", Default]; + {Desc, Type, Default} -> [Desc, " (", Type, "), default: ", Default] + end. + +%% option formatting helpers +maybe_concat(No, []) -> No; +maybe_concat(No, L) -> [No, ", ", L]. + +format_required(true, Extra, #{name := Name} = Opt) -> + io_lib:format("~ts<~ts>~ts", [Extra, Name, format_nargs(Opt)]); +format_required(false, Extra, #{name := Name} = Opt) -> + io_lib:format("[~ts<~ts>~ts]", [Extra, Name, format_nargs(Opt)]). + +format_nargs(#{nargs := Dots}) when Dots =:= list; Dots =:= all; Dots =:= nonempty_list -> + "..."; +format_nargs(_) -> + "". + +format_type(#{type := {integer, Choices}}) when is_list(Choices), is_integer(hd(Choices)) -> + io_lib:format("choice: ~s", [lists:join(", ", [integer_to_list(C) || C <- Choices])]); +format_type(#{type := {float, Choices}}) when is_list(Choices), is_number(hd(Choices)) -> + io_lib:format("choice: ~s", [lists:join(", ", [io_lib:format("~g", [C]) || C <- Choices])]); +format_type(#{type := {Num, Valid}}) when Num =:= integer; Num =:= float -> + case {proplists:get_value(min, Valid), proplists:get_value(max, Valid)} of + {undefined, undefined} -> + io_lib:format("~s", [format_type(#{type => Num})]); + {Min, undefined} -> + io_lib:format("~s >= ~tp", [format_type(#{type => Num}), Min]); + {undefined, Max} -> + io_lib:format("~s <= ~tp", [format_type(#{type => Num}), Max]); + {Min, Max} -> + io_lib:format("~tp <= ~s <= ~tp", [Min, format_type(#{type => Num}), Max]) + end; +format_type(#{type := {string, Re, _}}) when is_list(Re), not is_list(hd(Re)) -> + io_lib:format("string re: ~ts", [Re]); +format_type(#{type := {string, Re}}) when is_list(Re), not is_list(hd(Re)) -> + io_lib:format("string re: ~ts", [Re]); +format_type(#{type := {binary, Re}}) when is_binary(Re) -> + io_lib:format("binary re: ~ts", [Re]); +format_type(#{type := {binary, Re, _}}) when is_binary(Re) -> + io_lib:format("binary re: ~ts", [Re]); +format_type(#{type := {StrBin, Choices}}) when StrBin =:= string orelse StrBin =:= binary, is_list(Choices) -> + io_lib:format("choice: ~ts", [lists:join(", ", Choices)]); +format_type(#{type := atom}) -> + "existing atom"; +format_type(#{type := {atom, unsafe}}) -> + "atom"; +format_type(#{type := {atom, Choices}}) -> + io_lib:format("choice: ~ts", [lists:join(", ", [atom_to_list(C) || C <- Choices])]); +format_type(#{type := boolean}) -> + ""; +format_type(#{type := integer}) -> + "int"; +format_type(#{type := Type}) when is_atom(Type) -> + io_lib:format("~ts", [Type]); +format_type(_Opt) -> + "". + +format_default(#{default := Def}) when is_list(Def); is_binary(Def); is_atom(Def) -> + io_lib:format("~ts", [Def]); +format_default(#{default := Def}) -> + io_lib:format("~tp", [Def]); +format_default(_) -> + "". + +%%-------------------------------------------------------------------- +%% Basic handler execution +handle(CmdMap, ArgMap, Path, #{handler := {Mod, ModFun, Default}}) -> + ArgList = arg_map_to_arg_list(CmdMap, Path, ArgMap, Default), + %% if argument count may not match, better error can be produced + erlang:apply(Mod, ModFun, ArgList); +handle(_CmdMap, ArgMap, _Path, #{handler := {Mod, ModFun}}) when is_atom(Mod), is_atom(ModFun) -> + Mod:ModFun(ArgMap); +handle(CmdMap, ArgMap, Path, #{handler := {Fun, Default}}) when is_function(Fun) -> + ArgList = arg_map_to_arg_list(CmdMap, Path, ArgMap, Default), + %% if argument count may not match, better error can be produced + erlang:apply(Fun, ArgList); +handle(_CmdMap, ArgMap, _Path, #{handler := Handler}) when is_function(Handler, 1) -> + Handler(ArgMap). + +%% Given command map, path to reach a specific command, and a parsed argument +%% map, returns a list of arguments (effectively used to transform map-based +%% callback handler into positional). +arg_map_to_arg_list(Command, Path, ArgMap, Default) -> + AllArgs = collect_arguments(Command, Path, []), + [maps:get(Arg, ArgMap, Default) || #{name := Arg} <- AllArgs]. + +%% recursively descend into Path, ignoring arguments with duplicate names +collect_arguments(Command, [], Acc) -> + Acc ++ maps:get(arguments, Command, []); +collect_arguments(Command, [H|Tail], Acc) -> + Args = maps:get(arguments, Command, []), + Next = maps:get(H, maps:get(commands, Command, H)), + collect_arguments(Next, Tail, Acc ++ Args). diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl index 1504326c612b..03dedabd5528 100644 --- a/lib/stdlib/src/array.erl +++ b/lib/stdlib/src/array.erl @@ -462,7 +462,7 @@ fix_test_() -> -spec relax(Array :: array(Type)) -> array(Type). -relax(#array{size = N}=A) -> +relax(#array{size = N}=A) when is_integer(N), N >= 0 -> A#array{max = find_max(N-1, ?LEAFSIZE)}. @@ -489,7 +489,9 @@ relax_test_() -> array(Type). resize(Size, #array{size = N, max = M, elements = E}=A) - when is_integer(Size), Size >= 0 -> + when is_integer(Size), Size >= 0, + is_integer(N), N >= 0, + is_integer(M), M >= 0 -> if Size > N -> {E1, M1} = grow(Size-1, E, if M > 0 -> M; @@ -570,7 +572,7 @@ resize_test_() -> -spec set(I :: array_indx(), Value :: Type, Array :: array(Type)) -> array(Type). set(I, Value, #array{size = N, max = M, default = D, elements = E}=A) - when is_integer(I), I >= 0 -> + when is_integer(I), I >= 0, is_integer(N), is_integer(M) -> if I < N -> A#array{elements = set_1(I, E, Value, D)}; I < M -> @@ -599,7 +601,7 @@ set_1(I, E, X, _D) -> %% Enlarging the array upwards to accommodate an index `I' -grow(I, E, _M) when is_integer(E) -> +grow(I, E, _M) when is_integer(I), is_integer(E) -> M1 = find_max(I, E), {M1, M1}; grow(I, E, M) -> @@ -633,7 +635,7 @@ expand(I, _S, X, D) -> -spec get(I :: array_indx(), Array :: array(Type)) -> Value :: Type. get(I, #array{size = N, max = M, elements = E, default = D}) - when is_integer(I), I >= 0 -> + when is_integer(I), I >= 0, is_integer(N), is_integer(M) -> if I < N -> get_1(I, E, D); M > 0 -> @@ -673,7 +675,7 @@ get_1(I, E, _D) -> -spec reset(I :: array_indx(), Array :: array(Type)) -> array(Type). reset(I, #array{size = N, max = M, default = D, elements = E}=A) - when is_integer(I), I >= 0 -> + when is_integer(I), I >= 0, is_integer(N), is_integer(M) -> if I < N -> try A#array{elements = reset_1(I, E, D)} catch throw:default -> A @@ -760,7 +762,7 @@ set_get_test_() -> to_list(#array{size = 0}) -> []; -to_list(#array{size = N, elements = E, default = D}) -> +to_list(#array{size = N, elements = E, default = D}) when is_integer(N) -> to_list_1(E, D, N - 1); to_list(_) -> erlang:error(badarg). @@ -833,7 +835,7 @@ to_list_test_() -> sparse_to_list(#array{size = 0}) -> []; -sparse_to_list(#array{size = N, elements = E, default = D}) -> +sparse_to_list(#array{size = N, elements = E, default = D}) when is_integer(N) -> sparse_to_list_1(E, D, N - 1); sparse_to_list(_) -> erlang:error(badarg). @@ -1011,7 +1013,7 @@ from_list_test_() -> to_orddict(#array{size = 0}) -> []; -to_orddict(#array{size = N, elements = E, default = D}) -> +to_orddict(#array{size = N, elements = E, default = D}) when is_integer(N) -> I = N - 1, to_orddict_1(E, I, D, I); to_orddict(_) -> @@ -1030,7 +1032,7 @@ to_orddict_1(E, R, D, I) when is_integer(E) -> to_orddict_1(E, R, _D, I) -> push_tuple_pairs(I+1, R, E, []). -to_orddict_2(E=?NODEPATTERN(S), R, D, L) -> +to_orddict_2(E=?NODEPATTERN(S), R, D, L) when is_integer(S) -> to_orddict_3(?NODESIZE, R, D, L, E, S); to_orddict_2(E, R, D, L) when is_integer(E) -> push_pairs(E, R, D, L); @@ -1103,7 +1105,8 @@ to_orddict_test_() -> sparse_to_orddict(#array{size = 0}) -> []; -sparse_to_orddict(#array{size = N, elements = E, default = D}) -> +sparse_to_orddict(#array{size = N, elements = E, default = D}) + when is_integer(N) -> I = N - 1, sparse_to_orddict_1(E, I, D, I); sparse_to_orddict(_) -> @@ -1122,7 +1125,7 @@ sparse_to_orddict_1(E, _R, _D, _I) when is_integer(E) -> sparse_to_orddict_1(E, R, D, I) -> sparse_push_tuple_pairs(I+1, R, D, E, []). -sparse_to_orddict_2(E=?NODEPATTERN(S), R, D, L) -> +sparse_to_orddict_2(E=?NODEPATTERN(S), R, D, L) when is_integer(S) -> sparse_to_orddict_3(?NODESIZE, R, D, L, E, S); sparse_to_orddict_2(E, _R, _D, L) when is_integer(E) -> L; @@ -1223,7 +1226,7 @@ from_orddict_0([], N, _Max, _D, Es) -> end; from_orddict_0(Xs=[{Ix1, _}|_], Ix, Max0, D, Es0) - when Ix1 > Max0, is_integer(Ix1) -> + when is_integer(Ix1), Ix1 > Max0 -> %% We have a hole larger than a leaf Hole = Ix1-Ix, Step = Hole - (Hole rem ?LEAFSIZE), @@ -1393,7 +1396,7 @@ from_orddict_test_() -> Function :: fun((Index :: array_indx(), Type1) -> Type2). map(Function, Array=#array{size = N, elements = E, default = D}) - when is_function(Function, 2) -> + when is_function(Function, 2), is_integer(N) -> if N > 0 -> A = Array#array{elements = []}, % kill reference, for GC A#array{elements = map_1(N-1, E, 0, Function, D)}; @@ -1485,7 +1488,7 @@ map_test_() -> Function :: fun((Index :: array_indx(), Type1) -> Type2). sparse_map(Function, Array=#array{size = N, elements = E, default = D}) - when is_function(Function, 2) -> + when is_function(Function, 2), is_integer(N) -> if N > 0 -> A = Array#array{elements = []}, % kill reference, for GC A#array{elements = sparse_map_1(N-1, E, 0, Function, D)}; @@ -1581,7 +1584,7 @@ sparse_map_test_() -> Function :: fun((Index :: array_indx(), Value :: Type, Acc :: A) -> B). foldl(Function, A, #array{size = N, elements = E, default = D}) - when is_function(Function, 3) -> + when is_function(Function, 3), is_integer(N) -> if N > 0 -> foldl_1(N-1, E, A, 0, Function, D); true -> @@ -1653,7 +1656,7 @@ foldl_test_() -> Function :: fun((Index :: array_indx(), Value :: Type, Acc :: A) -> B). sparse_foldl(Function, A, #array{size = N, elements = E, default = D}) - when is_function(Function, 3) -> + when is_function(Function, 3), is_integer(N) -> if N > 0 -> sparse_foldl_1(N-1, E, A, 0, Function, D); true -> @@ -1730,7 +1733,7 @@ sparse_foldl_test_() -> Function :: fun((Index :: array_indx(), Value :: Type, Acc :: A) -> B). foldr(Function, A, #array{size = N, elements = E, default = D}) - when is_function(Function, 3) -> + when is_function(Function, 3), is_integer(N) -> if N > 0 -> I = N - 1, foldr_1(I, E, I, A, Function, D); @@ -1808,7 +1811,7 @@ foldr_test_() -> Function :: fun((Index :: array_indx(), Value :: Type, Acc :: A) -> B). sparse_foldr(Function, A, #array{size = N, elements = E, default = D}) - when is_function(Function, 3) -> + when is_function(Function, 3), is_integer(N) -> if N > 0 -> I = N - 1, sparse_foldr_1(I, E, I, A, Function, D); @@ -1862,7 +1865,7 @@ sparse_size(A) -> try sparse_foldr(F, [], A) of [] -> 0 catch - {value, I} -> + {value, I} when is_integer(I) -> I + 1 end. diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl index be4d9d42b45d..62bcd0d24fb2 100644 --- a/lib/stdlib/src/base64.erl +++ b/lib/stdlib/src/base64.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2021. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -21,12 +21,22 @@ -module(base64). --export([encode/1, decode/1, mime_decode/1, - encode_to_string/1, decode_to_string/1, mime_decode_to_string/1]). - +-export([encode/1, encode/2, + decode/1, decode/2, + mime_decode/1, mime_decode/2, + encode_to_string/1, encode_to_string/2, + decode_to_string/1, decode_to_string/2, + mime_decode_to_string/1, mime_decode_to_string/2, + format_error/2]). %% RFC 4648: Base 64 Encoding alphabet --type base64_alphabet() :: $A..$Z | $a..$z | $0..$9 | $+ | $/ | $=. +-type base64_alphabet() :: $A..$Z | $a..$z | $0..$9 | $+ | $/ | $- | $_ | $=. + +%% Selector for the Base 64 alphabet, `standard' for RFC 4648 +%% Section 4, `urlsafe' for RFC 4648 Section 5. +-type base64_mode() :: 'standard' | 'urlsafe'. + +-type options() :: #{padding => boolean(), mode => base64_mode()}. %% The following type is a subtype of string() for return values %% of encoding functions. @@ -40,67 +50,126 @@ Data :: byte_string() | binary(), Base64String :: base64_string(). -encode_to_string(Bin) when is_binary(Bin) -> - encode_to_string(binary_to_list(Bin)); -encode_to_string(List) when is_list(List) -> - encode_list_to_string(List). +encode_to_string(Data) -> + encode_to_string(Data, #{}). + +-spec encode_to_string(Data, Options) -> Base64String when + Data :: byte_string() | binary(), + Options :: options(), + Base64String :: base64_string(). + +encode_to_string(Bin, Options) when is_binary(Bin), is_map(Options) -> + encode_to_string(binary_to_list(Bin), Options); +encode_to_string(List, Options) when is_list(List), is_map(Options) -> + encode_list_to_string(get_encoding_offset(Options), get_padding(Options), List). -spec encode(Data) -> Base64 when Data :: byte_string() | binary(), Base64 :: base64_binary(). -encode(Bin) when is_binary(Bin) -> - encode_binary(Bin, <<>>); -encode(List) when is_list(List) -> - encode_list(List, <<>>). +encode(Data) -> + encode(Data, #{}). + +-spec encode(Data, Options) -> Base64 when + Data :: byte_string() | binary(), + Options :: options(), + Base64 :: base64_binary(). -encode_list_to_string([]) -> +encode(Bin, Options) when is_binary(Bin), is_map(Options) -> + encode_binary(get_encoding_offset(Options), get_padding(Options), Bin, <<>>); +encode(List, Options) when is_list(List) -> + encode_list(get_encoding_offset(Options), get_padding(Options), List, <<>>). + +encode_list_to_string(_ModeOffset, _Padding, []) -> []; -encode_list_to_string([B1]) -> - [b64e(B1 bsr 2), - b64e((B1 band 3) bsl 4), $=, $=]; -encode_list_to_string([B1,B2]) -> - [b64e(B1 bsr 2), - b64e(((B1 band 3) bsl 4) bor (B2 bsr 4)), - b64e((B2 band 15) bsl 2), $=]; -encode_list_to_string([B1,B2,B3|Ls]) -> +encode_list_to_string(ModeOffset, Padding, [B1]) -> + [b64e(B1 bsr 2, ModeOffset), + b64e((B1 band 3) bsl 4, ModeOffset) | + case Padding of + true -> "=="; + false -> "" + end]; +encode_list_to_string(ModeOffset, Padding, [B1,B2]) -> + [b64e(B1 bsr 2, ModeOffset), + b64e(((B1 band 3) bsl 4) bor (B2 bsr 4), ModeOffset), + b64e((B2 band 15) bsl 2, ModeOffset) | + case Padding of + true -> "="; + false -> "" + end]; +encode_list_to_string(ModeOffset, Padding, [B1,B2,B3|Ls]) -> BB = (B1 bsl 16) bor (B2 bsl 8) bor B3, - [b64e(BB bsr 18), - b64e((BB bsr 12) band 63), - b64e((BB bsr 6) band 63), - b64e(BB band 63) | encode_list_to_string(Ls)]. - -encode_binary(<<>>, A) -> + [b64e(BB bsr 18, ModeOffset), + b64e((BB bsr 12) band 63, ModeOffset), + b64e((BB bsr 6) band 63, ModeOffset), + b64e(BB band 63, ModeOffset) | encode_list_to_string(ModeOffset, Padding, Ls)]. + +encode_binary(ModeOffset, Padding, <>, A) -> + encode_binary(ModeOffset, + Padding, + Ls, + <>); +encode_binary(_ModeOffset, _Padding, <<>>, A) -> A; -encode_binary(<>, A) -> - <>; -encode_binary(<>, A) -> - <>; -encode_binary(<>, A) -> - BB = (B1 bsl 16) bor (B2 bsl 8) bor B3, - encode_binary(Ls, - <>). +encode_binary(ModeOffset, Padding, <>, A) -> + encode_binary(ModeOffset, + Padding, + Ls, + <>); +encode_binary(ModeOffset, Padding, <>, A) -> + E1 = b64e(B1, ModeOffset), + E2 = b64e(B2 bsl 4, ModeOffset), + case Padding of + true -> <>; + _ -> <> + end; +encode_binary(ModeOffset, Padding, <>, A) -> + E1 = b64e(B1, ModeOffset), + E2 = b64e(B2, ModeOffset), + E3 = b64e(B3 bsl 2, ModeOffset), + case Padding of + true -> <>; + _ -> <> + end. -encode_list([], A) -> +encode_list(_ModeOffset, _Padding, [], A) -> A; -encode_list([B1], A) -> - <>; -encode_list([B1,B2], A) -> - <>; -encode_list([B1,B2,B3|Ls], A) -> +encode_list(ModeOffset, Padding, [B1], A) -> + E1 = b64e(B1 bsr 2, ModeOffset), + E2 = b64e((B1 band 3) bsl 4, ModeOffset), + case Padding of + true -> <>; + false -> <> + end; +encode_list(ModeOffset, Padding, [B1,B2], A) -> + E1 = b64e(B1 bsr 2, ModeOffset), + E2 = b64e(((B1 band 3) bsl 4) bor (B2 bsr 4), ModeOffset), + E3 = b64e((B2 band 15) bsl 2, ModeOffset), + case Padding of + true -> <>; + false -> <> + end; +encode_list(ModeOffset, Padding, [B1,B2,B3|Ls], A) -> BB = (B1 bsl 16) bor (B2 bsl 8) bor B3, - encode_list(Ls, - <>). + encode_list(ModeOffset, + Padding, + Ls, + <>). %% mime_decode strips away all characters not Base64 before %% converting, whereas decode crashes if an illegal character is found @@ -109,19 +178,35 @@ encode_list([B1,B2,B3|Ls], A) -> Base64 :: base64_string() | base64_binary(), Data :: binary(). -decode(Bin) when is_binary(Bin) -> - decode_binary(Bin, <<>>); -decode(List) when is_list(List) -> - decode_list(List, <<>>). +decode(Base64) -> + decode(Base64, #{}). + +-spec decode(Base64, Options) -> Data when + Base64 :: base64_string() | base64_binary(), + Options :: options(), + Data :: binary(). + +decode(Bin, Options) when is_binary(Bin) -> + decode_binary(get_decoding_offset(Options), get_padding(Options), Bin, <<>>); +decode(List, Options) when is_list(List) -> + decode_list(get_decoding_offset(Options), get_padding(Options), List, <<>>). -spec mime_decode(Base64) -> Data when Base64 :: base64_string() | base64_binary(), Data :: binary(). -mime_decode(Bin) when is_binary(Bin) -> - mime_decode_binary(Bin, <<>>); -mime_decode(List) when is_list(List) -> - mime_decode_list(List, <<>>). +mime_decode(Base64) -> + mime_decode(Base64, #{}). + +-spec mime_decode(Base64, Options) -> Data when + Base64 :: base64_string() | base64_binary(), + Options :: options(), + Data :: binary(). + +mime_decode(Bin, Options) when is_binary(Bin) -> + mime_decode_binary(get_decoding_offset(Options), get_padding(Options), Bin, <<>>); +mime_decode(List, Options) when is_list(List) -> + mime_decode_list(get_decoding_offset(Options), get_padding(Options), List, <<>>). %% mime_decode_to_string strips away all characters not Base64 before %% converting, whereas decode_to_string crashes if an illegal @@ -131,324 +216,439 @@ mime_decode(List) when is_list(List) -> Base64 :: base64_string() | base64_binary(), DataString :: byte_string(). -decode_to_string(Bin) when is_binary(Bin) -> - decode_to_string(binary_to_list(Bin)); -decode_to_string(List) when is_list(List) -> - decode_list_to_string(List). +decode_to_string(Base64) -> + decode_to_string(Base64, #{}). + +-spec decode_to_string(Base64, Options) -> DataString when + Base64 :: base64_string() | base64_binary(), + Options :: options(), + DataString :: byte_string(). + +decode_to_string(Bin, Options) when is_binary(Bin) -> + decode_to_string(binary_to_list(Bin), Options); +decode_to_string(List, Options) when is_list(List) -> + decode_list_to_string(get_decoding_offset(Options), get_padding(Options), List). -spec mime_decode_to_string(Base64) -> DataString when Base64 :: base64_string() | base64_binary(), DataString :: byte_string(). -mime_decode_to_string(Bin) when is_binary(Bin) -> - mime_decode_to_string(binary_to_list(Bin)); -mime_decode_to_string(List) when is_list(List) -> - mime_decode_list_to_string(List). +mime_decode_to_string(Base64) -> + mime_decode_to_string(Base64, #{}). + +-spec mime_decode_to_string(Base64, Options) -> DataString when + Base64 :: base64_string() | base64_binary(), + Options :: options(), + DataString :: byte_string(). + +mime_decode_to_string(Bin, Options) when is_binary(Bin) -> + mime_decode_to_string(binary_to_list(Bin), Options); +mime_decode_to_string(List, Options) when is_list(List) -> + mime_decode_list_to_string(get_decoding_offset(Options), get_padding(Options), List). %% Skipping pad character if not at end of string. Also liberal about %% excess padding and skipping of other illegal (non-base64 alphabet) %% characters. See section 3.3 of RFC4648 -mime_decode_list([0 | Cs], A) -> - mime_decode_list(Cs, A); -mime_decode_list([C1 | Cs], A) -> - case b64d(C1) of - B1 when is_integer(B1) -> mime_decode_list(Cs, A, B1); - _ -> mime_decode_list(Cs, A) % eq is padding +mime_decode_list(ModeOffset, Padding, [C1 | Cs], A) -> + case b64d(C1, ModeOffset) of + B1 when is_integer(B1) -> mime_decode_list(ModeOffset, Padding, Cs, A, B1); + _ -> mime_decode_list(ModeOffset, Padding, Cs, A) % eq is padding end; -mime_decode_list([], A) -> +mime_decode_list(_ModeOffset, _Padding, [], A) -> A. -mime_decode_list([0 | Cs], A, B1) -> - mime_decode_list(Cs, A, B1); -mime_decode_list([C2 | Cs], A, B1) -> - case b64d(C2) of +mime_decode_list(ModeOffset, Padding, [C2 | Cs], A, B1) -> + case b64d(C2, ModeOffset) of B2 when is_integer(B2) -> - mime_decode_list(Cs, A, B1, B2); - _ -> mime_decode_list(Cs, A, B1) % eq is padding + mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2); + _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1) % eq is padding end. -mime_decode_list([0 | Cs], A, B1, B2) -> - mime_decode_list(Cs, A, B1, B2); -mime_decode_list([C3 | Cs], A, B1, B2) -> - case b64d(C3) of +mime_decode_list(ModeOffset, Padding, [C3 | Cs], A, B1, B2) -> + case b64d(C3, ModeOffset) of B3 when is_integer(B3) -> - mime_decode_list(Cs, A, B1, B2, B3); + mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3); eq=B3 -> - mime_decode_list_after_eq(Cs, A, B1, B2, B3); - _ -> mime_decode_list(Cs, A, B1, B2) + mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3); + _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2) + end; +mime_decode_list(ModeOffset, Padding, [], A, B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_list_after_eq(ModeOffset, Padding, [], A, B1, B2, eq) end. -mime_decode_list([0 | Cs], A, B1, B2, B3) -> - mime_decode_list(Cs, A, B1, B2, B3); -mime_decode_list([C4 | Cs], A, B1, B2, B3) -> - case b64d(C4) of +mime_decode_list(ModeOffset, Padding, [C4 | Cs], A, B1, B2, B3) -> + case b64d(C4, ModeOffset) of B4 when is_integer(B4) -> - mime_decode_list(Cs, <>); + mime_decode_list(ModeOffset, Padding, Cs, <>); eq -> - mime_decode_list_after_eq(Cs, A, B1, B2, B3); - _ -> mime_decode_list(Cs, A, B1, B2, B3) + mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3); + _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3) + end; +mime_decode_list(ModeOffset, Padding, [], A, B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_list_after_eq(ModeOffset, Padding, [], A, B1, B2, B3) end. -mime_decode_list_after_eq([0 | Cs], A, B1, B2, B3) -> - mime_decode_list_after_eq(Cs, A, B1, B2, B3); -mime_decode_list_after_eq([C | Cs], A, B1, B2, B3) -> - case b64d(C) of +mime_decode_list_after_eq(ModeOffset, Padding, [C | Cs], A, B1, B2, B3) -> + case b64d(C, ModeOffset) of B when is_integer(B) -> %% More valid data, skip the eq as invalid case B3 of - eq -> mime_decode_list(Cs, A, B1, B2, B); - _ -> mime_decode_list(Cs, <>) + eq -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B); + _ -> mime_decode_list(ModeOffset, Padding, Cs, <>) end; - _ -> mime_decode_list_after_eq(Cs, A, B1, B2, B3) + _ -> mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3) end; -mime_decode_list_after_eq([], A, B1, B2, eq) -> +mime_decode_list_after_eq(_ModeOffset, _Padding, [], A, B1, B2, eq) -> <>; -mime_decode_list_after_eq([], A, B1, B2, B3) -> +mime_decode_list_after_eq(_ModeOffset, _Padding, [], A, B1, B2, B3) -> <>. -mime_decode_binary(<<0:8, Cs/bits>>, A) -> - mime_decode_binary(Cs, A); -mime_decode_binary(<>, A) -> - case b64d(C1) of - B1 when is_integer(B1) -> mime_decode_binary(Cs, A, B1); - _ -> mime_decode_binary(Cs, A) % eq is padding +mime_decode_binary(ModeOffset, Padding, <>, A) -> + case b64d(C1, ModeOffset) of + B1 when is_integer(B1) -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1); + _ -> mime_decode_binary(ModeOffset, Padding, Cs, A) % eq is padding end; -mime_decode_binary(<<>>, A) -> +mime_decode_binary(_ModeOffset, _Padding, <<>>, A) -> A. -mime_decode_binary(<<0:8, Cs/bits>>, A, B1) -> - mime_decode_binary(Cs, A, B1); -mime_decode_binary(<>, A, B1) -> - case b64d(C2) of +mime_decode_binary(ModeOffset, Padding, <>, A, B1) -> + case b64d(C2, ModeOffset) of B2 when is_integer(B2) -> - mime_decode_binary(Cs, A, B1, B2); - _ -> mime_decode_binary(Cs, A, B1) % eq is padding + mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2); + _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1) % eq is padding end. -mime_decode_binary(<<0:8, Cs/bits>>, A, B1, B2) -> - mime_decode_binary(Cs, A, B1, B2); -mime_decode_binary(<>, A, B1, B2) -> - case b64d(C3) of +mime_decode_binary(ModeOffset, Padding, <>, A, B1, B2) -> + case b64d(C3, ModeOffset) of B3 when is_integer(B3) -> - mime_decode_binary(Cs, A, B1, B2, B3); + mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3); eq=B3 -> - mime_decode_binary_after_eq(Cs, A, B1, B2, B3); - _ -> mime_decode_binary(Cs, A, B1, B2) + mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3); + _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2) + end; +mime_decode_binary(ModeOffset, Padding, <>, A, B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, eq) end. -mime_decode_binary(<<0:8, Cs/bits>>, A, B1, B2, B3) -> - mime_decode_binary(Cs, A, B1, B2, B3); -mime_decode_binary(<>, A, B1, B2, B3) -> - case b64d(C4) of +mime_decode_binary(ModeOffset, Padding, <>, A, B1, B2, B3) -> + case b64d(C4, ModeOffset) of B4 when is_integer(B4) -> - mime_decode_binary(Cs, <>); + mime_decode_binary(ModeOffset, Padding, Cs, <>); eq -> - mime_decode_binary_after_eq(Cs, A, B1, B2, B3); - _ -> mime_decode_binary(Cs, A, B1, B2, B3) + mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3); + _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3) + end; +mime_decode_binary(ModeOffset, Padding, <>, A, B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3) end. -mime_decode_binary_after_eq(<<0:8, Cs/bits>>, A, B1, B2, B3) -> - mime_decode_binary_after_eq(Cs, A, B1, B2, B3); -mime_decode_binary_after_eq(<>, A, B1, B2, B3) -> - case b64d(C) of +mime_decode_binary_after_eq(ModeOffset, Padding, <>, A, B1, B2, B3) -> + case b64d(C, ModeOffset) of B when is_integer(B) -> %% More valid data, skip the eq as invalid case B3 of - eq -> mime_decode_binary(Cs, A, B1, B2, B); - _ -> mime_decode_binary(Cs, <>) + eq -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B); + _ -> mime_decode_binary(ModeOffset, Padding, Cs, <>) end; - _ -> mime_decode_binary_after_eq(Cs, A, B1, B2, B3) + _ -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3) end; -mime_decode_binary_after_eq(<<>>, A, B1, B2, eq) -> +mime_decode_binary_after_eq(_ModeOffset, _Padding, <<>>, A, B1, B2, eq) -> <>; -mime_decode_binary_after_eq(<<>>, A, B1, B2, B3) -> +mime_decode_binary_after_eq(_ModeOffset, _Padding, <<>>, A, B1, B2, B3) -> <>. -mime_decode_list_to_string([0 | Cs]) -> - mime_decode_list_to_string(Cs); -mime_decode_list_to_string([C1 | Cs]) -> - case b64d(C1) of - B1 when is_integer(B1) -> mime_decode_list_to_string(Cs, B1); - _ -> mime_decode_list_to_string(Cs) % eq is padding +mime_decode_list_to_string(ModeOffset, Padding, [C1 | Cs]) -> + case b64d(C1, ModeOffset) of + B1 when is_integer(B1) -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1); + _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs) % eq is padding end; -mime_decode_list_to_string([]) -> +mime_decode_list_to_string(_ModeOffset, _Padding, []) -> []. -mime_decode_list_to_string([0 | Cs], B1) -> - mime_decode_list_to_string(Cs, B1); -mime_decode_list_to_string([C2 | Cs], B1) -> - case b64d(C2) of +mime_decode_list_to_string(ModeOffset, Padding, [C2 | Cs], B1) -> + case b64d(C2, ModeOffset) of B2 when is_integer(B2) -> - mime_decode_list_to_string(Cs, B1, B2); - _ -> mime_decode_list_to_string(Cs, B1) % eq is padding + mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2); + _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1) % eq is padding end. -mime_decode_list_to_string([0 | Cs], B1, B2) -> - mime_decode_list_to_string(Cs, B1, B2); -mime_decode_list_to_string([C3 | Cs], B1, B2) -> - case b64d(C3) of +mime_decode_list_to_string(ModeOffset, Padding, [C3 | Cs], B1, B2) -> + case b64d(C3, ModeOffset) of B3 when is_integer(B3) -> - mime_decode_list_to_string(Cs, B1, B2, B3); - eq=B3 -> mime_decode_list_to_string_after_eq(Cs, B1, B2, B3); - _ -> mime_decode_list_to_string(Cs, B1, B2) + mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3); + eq=B3 -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3); + _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2) + end; +mime_decode_list_to_string(ModeOffset, Padding, [], B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, [], B1, B2, eq) end. -mime_decode_list_to_string([0 | Cs], B1, B2, B3) -> - mime_decode_list_to_string(Cs, B1, B2, B3); -mime_decode_list_to_string([C4 | Cs], B1, B2, B3) -> - case b64d(C4) of +mime_decode_list_to_string(ModeOffset, Padding, [C4 | Cs], B1, B2, B3) -> + case b64d(C4, ModeOffset) of B4 when is_integer(B4) -> Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4, Octet1 = Bits4x6 bsr 16, Octet2 = (Bits4x6 bsr 8) band 16#ff, Octet3 = Bits4x6 band 16#ff, - [Octet1, Octet2, Octet3 | mime_decode_list_to_string(Cs)]; + [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Padding, Cs)]; eq -> - mime_decode_list_to_string_after_eq(Cs, B1, B2, B3); - _ -> mime_decode_list_to_string(Cs, B1, B2, B3) + mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3); + _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3) + end; +mime_decode_list_to_string(ModeOffset, Padding, [], B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, [], B1, B2, B3) end. -mime_decode_list_to_string_after_eq([0 | Cs], B1, B2, B3) -> - mime_decode_list_to_string_after_eq(Cs, B1, B2, B3); -mime_decode_list_to_string_after_eq([C | Cs], B1, B2, B3) -> - case b64d(C) of +mime_decode_list_to_string_after_eq(ModeOffset, Padding, [C | Cs], B1, B2, B3) -> + case b64d(C, ModeOffset) of B when is_integer(B) -> %% More valid data, skip the eq as invalid case B3 of - eq -> mime_decode_list_to_string(Cs, B1, B2, B); + eq -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B); _ -> Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B, Octet1 = Bits4x6 bsr 16, Octet2 = (Bits4x6 bsr 8) band 16#ff, Octet3 = Bits4x6 band 16#ff, - [Octet1, Octet2, Octet3 | mime_decode_list_to_string(Cs)] + [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Padding, Cs)] end; - _ -> mime_decode_list_to_string_after_eq(Cs, B1, B2, B3) + _ -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3) end; -mime_decode_list_to_string_after_eq([], B1, B2, eq) -> +mime_decode_list_to_string_after_eq(_ModeOffset, _Padding, [], B1, B2, eq) -> binary_to_list(<>); -mime_decode_list_to_string_after_eq([], B1, B2, B3) -> +mime_decode_list_to_string_after_eq(_ModeOffset, _Padding, [], B1, B2, B3) -> binary_to_list(<>). -decode_list([C1 | Cs], A) -> - case b64d(C1) of - ws -> decode_list(Cs, A); - B1 -> decode_list(Cs, A, B1) +decode_list(ModeOffset, Padding, [C1 | Cs], A) -> + case b64d(C1, ModeOffset) of + ws -> decode_list(ModeOffset, Padding, Cs, A); + B1 -> decode_list(ModeOffset, Padding, Cs, A, B1) end; -decode_list([], A) -> +decode_list(_ModeOffset, _Padding, [], A) -> A. -decode_list([C2 | Cs], A, B1) -> - case b64d(C2) of - ws -> decode_list(Cs, A, B1); - B2 -> decode_list(Cs, A, B1, B2) +decode_list(ModeOffset, Padding, [C2 | Cs], A, B1) -> + case b64d(C2, ModeOffset) of + ws -> decode_list(ModeOffset, Padding, Cs, A, B1); + B2 -> decode_list(ModeOffset, Padding, Cs, A, B1, B2) end. -decode_list([C3 | Cs], A, B1, B2) -> - case b64d(C3) of - ws -> decode_list(Cs, A, B1, B2); - B3 -> decode_list(Cs, A, B1, B2, B3) +decode_list(ModeOffset, Padding, [C3 | Cs], A, B1, B2) -> + case b64d(C3, ModeOffset) of + ws -> decode_list(ModeOffset, Padding, Cs, A, B1, B2); + B3 -> decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3) + end; +decode_list(ModeOffset, Padding, [], A, B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> decode_list(ModeOffset, Padding, [], A, B1, B2, eq) end. -decode_list([C4 | Cs], A, B1, B2, B3) -> - case b64d(C4) of - ws -> decode_list(Cs, A, B1, B2, B3); - eq when B3 =:= eq -> only_ws(Cs, <>); - eq -> only_ws(Cs, <>); - B4 -> decode_list(Cs, <>) +decode_list(ModeOffset, Padding, [C4 | Cs], A, B1, B2, B3) -> + case b64d(C4, ModeOffset) of + ws -> decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3); + eq when B3 =:= eq -> only_ws(ModeOffset, Padding, Cs, <>); + eq -> only_ws(ModeOffset, Padding, Cs, <>); + B4 -> decode_list(ModeOffset, Padding, Cs, <>) + end; +decode_list(_ModeOffset, Padding, [], A, B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false when B3 == eq -> <>; + false -> <> end. -decode_binary(<>, A) -> - case b64d(C1) of - ws -> decode_binary(Cs, A); - B1 -> decode_binary(Cs, A, B1) +decode_binary(ModeOffset, Padding, <>, A) -> + case {b64d(C1, ModeOffset), b64d(C2, ModeOffset), b64d(C3, ModeOffset), b64d(C4, ModeOffset)} of + {B1, B2, B3, B4} when is_integer(B1), is_integer(B2), + is_integer(B3), is_integer(B4) -> + decode_binary(ModeOffset, Padding, Cs, <>); + {B1, B2, B3, B4} -> + dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, B4, A) end; -decode_binary(<<>>, A) -> - A. +decode_binary(_ModeOffset, _Padding, <<>>, A) -> + A; +decode_binary(ModeOffset, Padding, <>, A) -> + case b64d(C1, ModeOffset) of + ws -> decode_binary(ModeOffset, Padding, Cs, A); + B1 -> decode_binary(ModeOffset, Padding, Cs, A, B1) + end. -decode_binary(<>, A, B1) -> - case b64d(C2) of - ws -> decode_binary(Cs, A, B1); - B2 -> decode_binary(Cs, A, B1, B2) +dec_bin(ModeOffset, Padding, Cs, ws, B2, B3, B4, A) -> + dec_bin(ModeOffset, Padding, Cs, B2, B3, B4, A); +dec_bin(ModeOffset, Padding, Cs, B1, ws, B3, B4, A) -> + dec_bin(ModeOffset, Padding, Cs, B1, B3, B4, A); +dec_bin(ModeOffset, Padding, Cs, B1, B2, ws, B4, A) -> + dec_bin(ModeOffset, Padding, Cs, B1, B2, B4, A); +dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, B4, A) -> + case B4 of + ws -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3); + eq when B3 =:= eq -> only_ws_binary(ModeOffset, Padding, Cs, <>); + eq -> only_ws_binary(ModeOffset, Padding, Cs, <>); + B4 -> decode_binary(ModeOffset, Padding, Cs, <>) end. -decode_binary(<>, A, B1, B2) -> - case b64d(C3) of - ws -> decode_binary(Cs, A, B1, B2); - B3 -> decode_binary(Cs, A, B1, B2, B3) +dec_bin(ModeOffset, Padding, Cs, ws, B2, B3, A) -> + dec_bin(ModeOffset, Padding, Cs, B2, B3, A); +dec_bin(ModeOffset, Padding, Cs, B1, ws, B3, A) -> + dec_bin(ModeOffset, Padding, Cs, B1, B3, A); +dec_bin(ModeOffset, Padding, Cs, B1, B2, ws, A) -> + dec_bin(ModeOffset, Padding, Cs, B1, B2, A); +dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, A) -> + decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3). + +dec_bin(ModeOffset, Padding, Cs, ws, B2, A) -> + dec_bin(ModeOffset, Padding, Cs, B2, A); +dec_bin(ModeOffset, Padding, Cs, B1, ws, A) -> + dec_bin(ModeOffset, Padding, Cs, B1, A); +dec_bin(ModeOffset, Padding, Cs, B1, B2, A) -> + decode_binary(ModeOffset, Padding, Cs, A, B1, B2). + +dec_bin(ModeOffset, Padding, Cs, ws, A) -> + decode_binary(ModeOffset, Padding, Cs, A); +dec_bin(ModeOffset, Padding, Cs, B1, A) -> + decode_binary(ModeOffset, Padding,Cs, A, B1). + +decode_binary(ModeOffset, Padding, <>, A, B1) -> + case b64d(C2, ModeOffset) of + ws -> decode_binary(ModeOffset, Padding, Cs, A, B1); + B2 -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2) end. -decode_binary(<>, A, B1, B2, B3) -> - case b64d(C4) of - ws -> decode_binary(Cs, A, B1, B2, B3); - eq when B3 =:= eq -> only_ws_binary(Cs, <>); - eq -> only_ws_binary(Cs, <>); - B4 -> decode_binary(Cs, <>) +decode_binary(ModeOffset, Padding, <>, A, B1, B2) -> + case b64d(C3, ModeOffset) of + ws -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2); + B3 -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3) + end; +decode_binary(ModeOffset, Padding, <>, A, B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, eq) + end. + +decode_binary(ModeOffset, Padding, <>, A, B1, B2, B3) -> + case b64d(C4, ModeOffset) of + ws -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3); + eq when B3 =:= eq -> only_ws_binary(ModeOffset, Padding, Cs, <>); + eq -> only_ws_binary(ModeOffset, Padding, Cs, <>); + B4 -> decode_binary(ModeOffset, Padding, Cs, <>) + end; +decode_binary(_ModeOffset, Padding, <<>>, A, B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false when B3 =:= eq -> <>; + false -> <> end. -only_ws_binary(<<>>, A) -> +only_ws_binary(_ModeOffset, _Padding, <<>>, A) -> A; -only_ws_binary(<>, A) -> - case b64d(C) of - ws -> only_ws_binary(Cs, A) +only_ws_binary(ModeOffset, Padding, <>, A) -> + case b64d(C, ModeOffset) of + ws -> only_ws_binary(ModeOffset, Padding, Cs, A) end. -decode_list_to_string([C1 | Cs]) -> - case b64d(C1) of - ws -> decode_list_to_string(Cs); - B1 -> decode_list_to_string(Cs, B1) +decode_list_to_string(ModeOffset, Padding, [C1 | Cs]) -> + case b64d(C1, ModeOffset) of + ws -> decode_list_to_string(ModeOffset, Padding, Cs); + B1 -> decode_list_to_string(ModeOffset, Padding, Cs, B1) end; -decode_list_to_string([]) -> +decode_list_to_string(_ModeOffset, _Padding, []) -> []. -decode_list_to_string([C2 | Cs], B1) -> - case b64d(C2) of - ws -> decode_list_to_string(Cs, B1); - B2 -> decode_list_to_string(Cs, B1, B2) +decode_list_to_string(ModeOffset, Padding, [C2 | Cs], B1) -> + case b64d(C2, ModeOffset) of + ws -> decode_list_to_string(ModeOffset, Padding, Cs, B1); + B2 -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2) end. -decode_list_to_string([C3 | Cs], B1, B2) -> - case b64d(C3) of - ws -> decode_list_to_string(Cs, B1, B2); - B3 -> decode_list_to_string(Cs, B1, B2, B3) +decode_list_to_string(ModeOffset, Padding, [C3 | Cs], B1, B2) -> + case b64d(C3, ModeOffset) of + ws -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2); + B3 -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3) + end; +decode_list_to_string(ModeOffset, Padding, [], B1, B2) -> + case Padding of + true -> missing_padding_error(); + false -> decode_list_to_string(ModeOffset, Padding, [], B1, B2, eq) end. -decode_list_to_string([C4 | Cs], B1, B2, B3) -> - case b64d(C4) of +decode_list_to_string(ModeOffset, Padding, [C4 | Cs], B1, B2, B3) -> + case b64d(C4, ModeOffset) of ws -> - decode_list_to_string(Cs, B1, B2, B3); + decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3); eq when B3 =:= eq -> - only_ws(Cs, binary_to_list(<>)); + only_ws(ModeOffset, Padding, Cs, binary_to_list(<>)); eq -> - only_ws(Cs, binary_to_list(<>)); + only_ws(ModeOffset, Padding, Cs, binary_to_list(<>)); B4 -> Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4, Octet1 = Bits4x6 bsr 16, Octet2 = (Bits4x6 bsr 8) band 16#ff, Octet3 = Bits4x6 band 16#ff, - [Octet1, Octet2, Octet3 | decode_list_to_string(Cs)] + [Octet1, Octet2, Octet3 | decode_list_to_string(ModeOffset, Padding, Cs)] + end; +decode_list_to_string(_ModeOffset, Padding, [], B1, B2, B3) -> + case Padding of + true -> missing_padding_error(); + false when B3 =:= eq -> binary_to_list(<>); + false -> binary_to_list(<>) end. -only_ws([], A) -> +only_ws(_ModeOffset, _Padding, [], A) -> A; -only_ws([C | Cs], A) -> - case b64d(C) of - ws -> only_ws(Cs, A) +only_ws(ModeOffset, Padding, [C | Cs], A) -> + case b64d(C, ModeOffset) of + ws -> only_ws(ModeOffset, Padding, Cs, A) end. +%%%======================================================================== +%%% Error handling functions +%%%======================================================================== + +% always inlined for useful stacktraces when called in tail position +-compile({inline, missing_padding_error/0}). +missing_padding_error() -> + error(missing_padding, none, [{error_info, #{}}]). + +format_error(missing_padding, _) -> + #{general => "data to decode is missing final = padding characters, if this is intended, use the `padding => false` option"}; +format_error(_, _) -> + #{}. + %%%======================================================================== %%% Internal functions %%%======================================================================== -%% accessors --compile({inline, [{b64d, 1}]}). -%% One-based decode map. -b64d(X) -> - element(X, - {bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %1-15 +%% accessors + +get_padding(#{padding := Bool}) when is_boolean(Bool) -> Bool; +get_padding(#{}) -> true. + +get_decoding_offset(#{mode := standard}) -> 1; +get_decoding_offset(#{mode := urlsafe}) -> 257; +get_decoding_offset(#{}) -> 1. + +-compile({inline, [{b64d, 2}]}). +b64d(X, Off) -> + element(X + Off, + { + %% standard base64 alphabet (RFC 4648 Section 4) + bad,bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %0-15 bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, %16-31 ws,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,62,bad,bad,bad,63, %32-47 - 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,eq,bad,bad, %48-63 + 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,eq,bad,bad, %48-61 bad,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,bad,bad,bad,bad,bad, bad,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, @@ -460,13 +660,44 @@ b64d(X) -> bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + + %% alternative base64url alphabet (RFC 4648 Section 5) + bad,bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %0-15 + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, %16-31 + ws,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,62,bad,bad, %32-47 + 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,eq,bad,bad, %48-61 + bad,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,bad,bad,bad,bad,63, + bad,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad}). --compile({inline, [{b64e, 1}]}). -b64e(X) -> - element(X+1, - {$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, +get_encoding_offset(#{mode := standard}) -> 1; +get_encoding_offset(#{mode := urlsafe}) -> 65; +get_encoding_offset(#{}) -> 1. + +-compile({inline, [{b64e, 2}]}). +b64e(X, Off) -> + element(X + Off, + { + %% standard base64 alphabet (RFC 4648 Section 4) + $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, + $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, + $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, + $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $+, $/, + + %% alternative base64url alphabet (RFC 4648 Section 5) + $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, - $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $+, $/}). + $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $-, $_}). diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl index 438d76e47f74..14c6d76430e4 100644 --- a/lib/stdlib/src/beam_lib.erl +++ b/lib/stdlib/src/beam_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -51,6 +51,7 @@ -export([make_crypto_key/2, get_crypto_key/1]). %Utilities used by compiler -export_type([attrib_entry/0, compinfo_entry/0, labeled_entry/0, label/0]). +-export_type([chunkid/0]). -export_type([chnk_rsn/0]). -import(lists, [append/1, delete/2, foreach/2, keysort/2, @@ -155,7 +156,7 @@ chunks(File, Chunks, Options) -> catch Error -> Error end. -spec all_chunks(beam()) -> - {'ok', 'beam_lib', [{chunkid(), dataB()}]} | {'error', 'beam_lib', info_rsn()}. + {'ok', module(), [{chunkid(), dataB()}]} | {'error', 'beam_lib', info_rsn()}. all_chunks(File) -> read_all_chunks(File). @@ -831,8 +832,7 @@ symbol(_, AT, I1, I2, _I3, _Cnt) -> {atm(AT, I1), I2}. atm(AT, N) -> - [{_N, S}] = ets:lookup(AT, N), - S. + ets:lookup_element(AT, N, 2). %% AT is updated. ensure_atoms({empty, AT}, Cs) -> @@ -953,13 +953,13 @@ error(Reason) -> %% The following chunks must be kept when stripping a BEAM file. significant_chunks() -> - ["Line" | md5_chunks()]. + ["Line", "Type" | md5_chunks()]. %% The following chunks are significant when calculating the MD5 %% for a module. They are listed in the order that they should be MD5:ed. md5_chunks() -> - ["Atom", "AtU8", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT"]. + ["Atom", "AtU8", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT", "Meta"]. %% The following chunks are mandatory in every Beam file. @@ -1150,11 +1150,12 @@ terminate(_Reason, _State) -> ok. crypto_key_fun_from_file() -> + UserConfig = filename:basedir(user_config,"erlang"), case init:get_argument(home) of {ok,[[Home]]} -> - crypto_key_fun_from_file_1([".",Home]); + crypto_key_fun_from_file_1([".", Home, UserConfig]); _ -> - crypto_key_fun_from_file_1(["."]) + crypto_key_fun_from_file_1([".", UserConfig]) end. crypto_key_fun_from_file_1(Path) -> diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index f3e2f5421557..e587cfe98d30 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -20,8 +20,8 @@ -module(binary). %% %% Implemented in this module: --export([replace/3,replace/4, - encode_hex/1, decode_hex/1]). +-export([replace/3, replace/4, + encode_hex/1, encode_hex/2, decode_hex/1]). -export_type([cp/0]). @@ -365,127 +365,112 @@ get_opts_replace(_,_) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Hex encoding functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --define(HEX(X), (hex(X)):16). --compile({inline,[hex/1]}). +-compile({inline, [hex/2]}). -spec encode_hex(Bin) -> Bin2 when Bin :: binary(), Bin2 :: <<_:_*16>>. -encode_hex(Data) when byte_size(Data) rem 8 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 7 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 6 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 5 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 4 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 3 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when byte_size(Data) rem 2 =:= 0 -> - << <> || <> <= Data >>; -encode_hex(Data) when is_binary(Data) -> - << <> || <> <= Data >>; +encode_hex(Bin) when is_binary(Bin) -> + encode_hex(Bin, uppercase); encode_hex(Bin) -> - badarg_with_info([Bin]). + error_with_info(badarg, [Bin]). -hex(X) -> +-spec encode_hex(Bin, Case) -> Bin2 when + Bin :: binary(), + Case :: lowercase | uppercase, + Bin2 :: <<_:_*16>>. +encode_hex(Bin, uppercase) when is_binary(Bin) -> + encode_hex1(Bin, 1); +encode_hex(Bin, lowercase) when is_binary(Bin) -> + encode_hex1(Bin, 257); +encode_hex(Bin, Case) -> + error_with_info(badarg, [Bin, Case]). + +encode_hex1(Data, Offset) -> + <> = Data, + Hex = << <<(hex(A, Offset)):16, (hex(B, Offset)):16, (hex(C, Offset)):16, (hex(D, Offset)):16, + (hex(E, Offset)):16, (hex(F, Offset)):16, (hex(G, Offset)):16, (hex(H, Offset)):16>> || + <> <= First >>, + encode_hex2(Rest, Offset, Hex). + +encode_hex2(<>, Offset, Acc) -> + encode_hex2(Data, Offset, <>); +encode_hex2(<<>>, _Offset, Acc) -> + Acc. + +hex(X, Offset) -> element( - X+1, {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044, 16#3045, 16#3046, - 16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142, 16#3143, 16#3144, 16#3145, 16#3146, - 16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246, - 16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 16#3346, - 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443, 16#3444, 16#3445, 16#3446, - 16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541, 16#3542, 16#3543, 16#3544, 16#3545, 16#3546, - 16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646, - 16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 16#3745, 16#3746, - 16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842, 16#3843, 16#3844, 16#3845, 16#3846, - 16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946, - 16#4130, 16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145, 16#4146, - 16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235, 16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 16#4244, 16#4245, 16#4246, - 16#4330, 16#4331, 16#4332, 16#4333, 16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341, 16#4342, 16#4343, 16#4344, 16#4345, 16#4346, - 16#4430, 16#4431, 16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438, 16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446, - 16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544, 16#4545, 16#4546, - 16#4630, 16#4631, 16#4632, 16#4633, 16#4634, 16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 16#4643, 16#4644, 16#4645, 16#4646}). - + X + Offset, { + %% Used for Uppercase + 16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044, 16#3045, 16#3046, + 16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142, 16#3143, 16#3144, 16#3145, 16#3146, + 16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246, + 16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 16#3346, + 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443, 16#3444, 16#3445, 16#3446, + 16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541, 16#3542, 16#3543, 16#3544, 16#3545, 16#3546, + 16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646, + 16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 16#3745, 16#3746, + 16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842, 16#3843, 16#3844, 16#3845, 16#3846, + 16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946, + 16#4130, 16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145, 16#4146, + 16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235, 16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 16#4244, 16#4245, 16#4246, + 16#4330, 16#4331, 16#4332, 16#4333, 16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341, 16#4342, 16#4343, 16#4344, 16#4345, 16#4346, + 16#4430, 16#4431, 16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438, 16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446, + 16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544, 16#4545, 16#4546, + 16#4630, 16#4631, 16#4632, 16#4633, 16#4634, 16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 16#4643, 16#4644, 16#4645, 16#4646, + %% Used for Lowercase + 16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3061, 16#3062, 16#3063, 16#3064, 16#3065, 16#3066, + 16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3161, 16#3162, 16#3163, 16#3164, 16#3165, 16#3166, + 16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3261, 16#3262, 16#3263, 16#3264, 16#3265, 16#3266, + 16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3361, 16#3362, 16#3363, 16#3364, 16#3365, 16#3366, + 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437, 16#3438, 16#3439, 16#3461, 16#3462, 16#3463, 16#3464, 16#3465, 16#3466, + 16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3561, 16#3562, 16#3563, 16#3564, 16#3565, 16#3566, + 16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3661, 16#3662, 16#3663, 16#3664, 16#3665, 16#3666, + 16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737, 16#3738, 16#3739, 16#3761, 16#3762, 16#3763, 16#3764, 16#3765, 16#3766, + 16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3861, 16#3862, 16#3863, 16#3864, 16#3865, 16#3866, + 16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3961, 16#3962, 16#3963, 16#3964, 16#3965, 16#3966, + 16#6130, 16#6131, 16#6132, 16#6133, 16#6134, 16#6135, 16#6136, 16#6137, 16#6138, 16#6139, 16#6161, 16#6162, 16#6163, 16#6164, 16#6165, 16#6166, + 16#6230, 16#6231, 16#6232, 16#6233, 16#6234, 16#6235, 16#6236, 16#6237, 16#6238, 16#6239, 16#6261, 16#6262, 16#6263, 16#6264, 16#6265, 16#6266, + 16#6330, 16#6331, 16#6332, 16#6333, 16#6334, 16#6335, 16#6336, 16#6337, 16#6338, 16#6339, 16#6361, 16#6362, 16#6363, 16#6364, 16#6365, 16#6366, + 16#6430, 16#6431, 16#6432, 16#6433, 16#6434, 16#6435, 16#6436, 16#6437, 16#6438, 16#6439, 16#6461, 16#6462, 16#6463, 16#6464, 16#6465, 16#6466, + 16#6530, 16#6531, 16#6532, 16#6533, 16#6534, 16#6535, 16#6536, 16#6537, 16#6538, 16#6539, 16#6561, 16#6562, 16#6563, 16#6564, 16#6565, 16#6566, + 16#6630, 16#6631, 16#6632, 16#6633, 16#6634, 16#6635, 16#6636, 16#6637, 16#6638, 16#6639, 16#6661, 16#6662, 16#6663, 16#6664, 16#6665, 16#6666}). + +-compile({inline, [unhex/1]}). -spec decode_hex(Bin) -> Bin2 when Bin :: <<_:_*16>>, Bin2 :: binary(). -decode_hex(Bin) when byte_size(Bin) rem 2 =:= 0 -> - << <<(unhex(Int))>> || <> <= Bin >>; -decode_hex(Bin) -> - badarg_with_info([Bin]). - -%% This function pattern-matches on the hexadecimal representation of a pair of characters -%% for example, 16#3030 is matching on the integers <<48, 48>>, which is ascii for <<"00">> -unhex(16#3030) -> 0; unhex(16#3031) -> 1; unhex(16#3032) -> 2; unhex(16#3033) -> 3; unhex(16#3034) -> 4; unhex(16#3035) -> 5; unhex(16#3036) -> 6; unhex(16#3037) -> 7; unhex(16#3038) -> 8; unhex(16#3039) -> 9; -unhex(16#3041) -> 10; unhex(16#3042) -> 11; unhex(16#3043) -> 12; unhex(16#3044) -> 13; unhex(16#3045) -> 14; unhex(16#3046) -> 15; -unhex(16#3061) -> 10; unhex(16#3062) -> 11; unhex(16#3063) -> 12; unhex(16#3064) -> 13; unhex(16#3065) -> 14; unhex(16#3066) -> 15; -unhex(16#3130) -> 16; unhex(16#3131) -> 17; unhex(16#3132) -> 18; unhex(16#3133) -> 19; unhex(16#3134) -> 20; unhex(16#3135) -> 21; unhex(16#3136) -> 22; unhex(16#3137) -> 23; unhex(16#3138) -> 24; unhex(16#3139) -> 25; -unhex(16#3141) -> 26; unhex(16#3142) -> 27; unhex(16#3143) -> 28; unhex(16#3144) -> 29; unhex(16#3145) -> 30; unhex(16#3146) -> 31; -unhex(16#3161) -> 26; unhex(16#3162) -> 27; unhex(16#3163) -> 28; unhex(16#3164) -> 29; unhex(16#3165) -> 30; unhex(16#3166) -> 31; -unhex(16#3230) -> 32; unhex(16#3231) -> 33; unhex(16#3232) -> 34; unhex(16#3233) -> 35; unhex(16#3234) -> 36; unhex(16#3235) -> 37; unhex(16#3236) -> 38; unhex(16#3237) -> 39; unhex(16#3238) -> 40; unhex(16#3239) -> 41; -unhex(16#3241) -> 42; unhex(16#3242) -> 43; unhex(16#3243) -> 44; unhex(16#3244) -> 45; unhex(16#3245) -> 46; unhex(16#3246) -> 47; -unhex(16#3261) -> 42; unhex(16#3262) -> 43; unhex(16#3263) -> 44; unhex(16#3264) -> 45; unhex(16#3265) -> 46; unhex(16#3266) -> 47; -unhex(16#3330) -> 48; unhex(16#3331) -> 49; unhex(16#3332) -> 50; unhex(16#3333) -> 51; unhex(16#3334) -> 52; unhex(16#3335) -> 53; unhex(16#3336) -> 54; unhex(16#3337) -> 55; unhex(16#3338) -> 56; unhex(16#3339) -> 57; -unhex(16#3341) -> 58; unhex(16#3342) -> 59; unhex(16#3343) -> 60; unhex(16#3344) -> 61; unhex(16#3345) -> 62; unhex(16#3346) -> 63; -unhex(16#3361) -> 58; unhex(16#3362) -> 59; unhex(16#3363) -> 60; unhex(16#3364) -> 61; unhex(16#3365) -> 62; unhex(16#3366) -> 63; -unhex(16#3430) -> 64; unhex(16#3431) -> 65; unhex(16#3432) -> 66; unhex(16#3433) -> 67; unhex(16#3434) -> 68; unhex(16#3435) -> 69; unhex(16#3436) -> 70; unhex(16#3437) -> 71; unhex(16#3438) -> 72; unhex(16#3439) -> 73; -unhex(16#3441) -> 74; unhex(16#3442) -> 75; unhex(16#3443) -> 76; unhex(16#3444) -> 77; unhex(16#3445) -> 78; unhex(16#3446) -> 79; -unhex(16#3461) -> 74; unhex(16#3462) -> 75; unhex(16#3463) -> 76; unhex(16#3464) -> 77; unhex(16#3465) -> 78; unhex(16#3466) -> 79; -unhex(16#3530) -> 80; unhex(16#3531) -> 81; unhex(16#3532) -> 82; unhex(16#3533) -> 83; unhex(16#3534) -> 84; unhex(16#3535) -> 85; unhex(16#3536) -> 86; unhex(16#3537) -> 87; unhex(16#3538) -> 88; unhex(16#3539) -> 89; -unhex(16#3541) -> 90; unhex(16#3542) -> 91; unhex(16#3543) -> 92; unhex(16#3544) -> 93; unhex(16#3545) -> 94; unhex(16#3546) -> 95; -unhex(16#3561) -> 90; unhex(16#3562) -> 91; unhex(16#3563) -> 92; unhex(16#3564) -> 93; unhex(16#3565) -> 94; unhex(16#3566) -> 95; -unhex(16#3630) -> 96; unhex(16#3631) -> 97; unhex(16#3632) -> 98; unhex(16#3633) -> 99; unhex(16#3634) -> 100; unhex(16#3635) -> 101; unhex(16#3636) -> 102; unhex(16#3637) -> 103; unhex(16#3638) -> 104; unhex(16#3639) -> 105; -unhex(16#3641) -> 106; unhex(16#3642) -> 107; unhex(16#3643) -> 108; unhex(16#3644) -> 109; unhex(16#3645) -> 110; unhex(16#3646) -> 111; -unhex(16#3661) -> 106; unhex(16#3662) -> 107; unhex(16#3663) -> 108; unhex(16#3664) -> 109; unhex(16#3665) -> 110; unhex(16#3666) -> 111; -unhex(16#3730) -> 112; unhex(16#3731) -> 113; unhex(16#3732) -> 114; unhex(16#3733) -> 115; unhex(16#3734) -> 116; unhex(16#3735) -> 117; unhex(16#3736) -> 118; unhex(16#3737) -> 119; unhex(16#3738) -> 120; unhex(16#3739) -> 121; -unhex(16#3741) -> 122; unhex(16#3742) -> 123; unhex(16#3743) -> 124; unhex(16#3744) -> 125; unhex(16#3745) -> 126; unhex(16#3746) -> 127; -unhex(16#3761) -> 122; unhex(16#3762) -> 123; unhex(16#3763) -> 124; unhex(16#3764) -> 125; unhex(16#3765) -> 126; unhex(16#3766) -> 127; -unhex(16#3830) -> 128; unhex(16#3831) -> 129; unhex(16#3832) -> 130; unhex(16#3833) -> 131; unhex(16#3834) -> 132; unhex(16#3835) -> 133; unhex(16#3836) -> 134; unhex(16#3837) -> 135; unhex(16#3838) -> 136; unhex(16#3839) -> 137; -unhex(16#3841) -> 138; unhex(16#3842) -> 139; unhex(16#3843) -> 140; unhex(16#3844) -> 141; unhex(16#3845) -> 142; unhex(16#3846) -> 143; -unhex(16#3861) -> 138; unhex(16#3862) -> 139; unhex(16#3863) -> 140; unhex(16#3864) -> 141; unhex(16#3865) -> 142; unhex(16#3866) -> 143; -unhex(16#3930) -> 144; unhex(16#3931) -> 145; unhex(16#3932) -> 146; unhex(16#3933) -> 147; unhex(16#3934) -> 148; unhex(16#3935) -> 149; unhex(16#3936) -> 150; unhex(16#3937) -> 151; unhex(16#3938) -> 152; unhex(16#3939) -> 153; -unhex(16#3941) -> 154; unhex(16#3942) -> 155; unhex(16#3943) -> 156; unhex(16#3944) -> 157; unhex(16#3945) -> 158; unhex(16#3946) -> 159; -unhex(16#3961) -> 154; unhex(16#3962) -> 155; unhex(16#3963) -> 156; unhex(16#3964) -> 157; unhex(16#3965) -> 158; unhex(16#3966) -> 159; -unhex(16#4130) -> 160; unhex(16#4131) -> 161; unhex(16#4132) -> 162; unhex(16#4133) -> 163; unhex(16#4134) -> 164; unhex(16#4135) -> 165; unhex(16#4136) -> 166; unhex(16#4137) -> 167; unhex(16#4138) -> 168; unhex(16#4139) -> 169; -unhex(16#4141) -> 170; unhex(16#4142) -> 171; unhex(16#4143) -> 172; unhex(16#4144) -> 173; unhex(16#4145) -> 174; unhex(16#4146) -> 175; -unhex(16#4161) -> 170; unhex(16#4162) -> 171; unhex(16#4163) -> 172; unhex(16#4164) -> 173; unhex(16#4165) -> 174; unhex(16#4166) -> 175; -unhex(16#4230) -> 176; unhex(16#4231) -> 177; unhex(16#4232) -> 178; unhex(16#4233) -> 179; unhex(16#4234) -> 180; unhex(16#4235) -> 181; unhex(16#4236) -> 182; unhex(16#4237) -> 183; unhex(16#4238) -> 184; unhex(16#4239) -> 185; -unhex(16#4241) -> 186; unhex(16#4242) -> 187; unhex(16#4243) -> 188; unhex(16#4244) -> 189; unhex(16#4245) -> 190; unhex(16#4246) -> 191; -unhex(16#4261) -> 186; unhex(16#4262) -> 187; unhex(16#4263) -> 188; unhex(16#4264) -> 189; unhex(16#4265) -> 190; unhex(16#4266) -> 191; -unhex(16#4330) -> 192; unhex(16#4331) -> 193; unhex(16#4332) -> 194; unhex(16#4333) -> 195; unhex(16#4334) -> 196; unhex(16#4335) -> 197; unhex(16#4336) -> 198; unhex(16#4337) -> 199; unhex(16#4338) -> 200; unhex(16#4339) -> 201; -unhex(16#4341) -> 202; unhex(16#4342) -> 203; unhex(16#4343) -> 204; unhex(16#4344) -> 205; unhex(16#4345) -> 206; unhex(16#4346) -> 207; -unhex(16#4361) -> 202; unhex(16#4362) -> 203; unhex(16#4363) -> 204; unhex(16#4364) -> 205; unhex(16#4365) -> 206; unhex(16#4366) -> 207; -unhex(16#4430) -> 208; unhex(16#4431) -> 209; unhex(16#4432) -> 210; unhex(16#4433) -> 211; unhex(16#4434) -> 212; unhex(16#4435) -> 213; unhex(16#4436) -> 214; unhex(16#4437) -> 215; unhex(16#4438) -> 216; unhex(16#4439) -> 217; -unhex(16#4441) -> 218; unhex(16#4442) -> 219; unhex(16#4443) -> 220; unhex(16#4444) -> 221; unhex(16#4445) -> 222; unhex(16#4446) -> 223; -unhex(16#4461) -> 218; unhex(16#4462) -> 219; unhex(16#4463) -> 220; unhex(16#4464) -> 221; unhex(16#4465) -> 222; unhex(16#4466) -> 223; -unhex(16#4530) -> 224; unhex(16#4531) -> 225; unhex(16#4532) -> 226; unhex(16#4533) -> 227; unhex(16#4534) -> 228; unhex(16#4535) -> 229; unhex(16#4536) -> 230; unhex(16#4537) -> 231; unhex(16#4538) -> 232; unhex(16#4539) -> 233; -unhex(16#4541) -> 234; unhex(16#4542) -> 235; unhex(16#4543) -> 236; unhex(16#4544) -> 237; unhex(16#4545) -> 238; unhex(16#4546) -> 239; -unhex(16#4561) -> 234; unhex(16#4562) -> 235; unhex(16#4563) -> 236; unhex(16#4564) -> 237; unhex(16#4565) -> 238; unhex(16#4566) -> 239; -unhex(16#4630) -> 240; unhex(16#4631) -> 241; unhex(16#4632) -> 242; unhex(16#4633) -> 243; unhex(16#4634) -> 244; unhex(16#4635) -> 245; unhex(16#4636) -> 246; unhex(16#4637) -> 247; unhex(16#4638) -> 248; unhex(16#4639) -> 249; -unhex(16#4641) -> 250; unhex(16#4642) -> 251; unhex(16#4643) -> 252; unhex(16#4644) -> 253; unhex(16#4645) -> 254; unhex(16#4646) -> 255; -unhex(16#4661) -> 250; unhex(16#4662) -> 251; unhex(16#4663) -> 252; unhex(16#4664) -> 253; unhex(16#4665) -> 254; unhex(16#4666) -> 255; -unhex(16#6130) -> 160; unhex(16#6131) -> 161; unhex(16#6132) -> 162; unhex(16#6133) -> 163; unhex(16#6134) -> 164; unhex(16#6135) -> 165; unhex(16#6136) -> 166; unhex(16#6137) -> 167; unhex(16#6138) -> 168; unhex(16#6139) -> 169; -unhex(16#6141) -> 170; unhex(16#6142) -> 171; unhex(16#6143) -> 172; unhex(16#6144) -> 173; unhex(16#6145) -> 174; unhex(16#6146) -> 175; -unhex(16#6161) -> 170; unhex(16#6162) -> 171; unhex(16#6163) -> 172; unhex(16#6164) -> 173; unhex(16#6165) -> 174; unhex(16#6166) -> 175; -unhex(16#6230) -> 176; unhex(16#6231) -> 177; unhex(16#6232) -> 178; unhex(16#6233) -> 179; unhex(16#6234) -> 180; unhex(16#6235) -> 181; unhex(16#6236) -> 182; unhex(16#6237) -> 183; unhex(16#6238) -> 184; unhex(16#6239) -> 185; -unhex(16#6241) -> 186; unhex(16#6242) -> 187; unhex(16#6243) -> 188; unhex(16#6244) -> 189; unhex(16#6245) -> 190; unhex(16#6246) -> 191; -unhex(16#6261) -> 186; unhex(16#6262) -> 187; unhex(16#6263) -> 188; unhex(16#6264) -> 189; unhex(16#6265) -> 190; unhex(16#6266) -> 191; -unhex(16#6330) -> 192; unhex(16#6331) -> 193; unhex(16#6332) -> 194; unhex(16#6333) -> 195; unhex(16#6334) -> 196; unhex(16#6335) -> 197; unhex(16#6336) -> 198; unhex(16#6337) -> 199; unhex(16#6338) -> 200; unhex(16#6339) -> 201; -unhex(16#6341) -> 202; unhex(16#6342) -> 203; unhex(16#6343) -> 204; unhex(16#6344) -> 205; unhex(16#6345) -> 206; unhex(16#6346) -> 207; -unhex(16#6361) -> 202; unhex(16#6362) -> 203; unhex(16#6363) -> 204; unhex(16#6364) -> 205; unhex(16#6365) -> 206; unhex(16#6366) -> 207; -unhex(16#6430) -> 208; unhex(16#6431) -> 209; unhex(16#6432) -> 210; unhex(16#6433) -> 211; unhex(16#6434) -> 212; unhex(16#6435) -> 213; unhex(16#6436) -> 214; unhex(16#6437) -> 215; unhex(16#6438) -> 216; unhex(16#6439) -> 217; -unhex(16#6441) -> 218; unhex(16#6442) -> 219; unhex(16#6443) -> 220; unhex(16#6444) -> 221; unhex(16#6445) -> 222; unhex(16#6446) -> 223; -unhex(16#6461) -> 218; unhex(16#6462) -> 219; unhex(16#6463) -> 220; unhex(16#6464) -> 221; unhex(16#6465) -> 222; unhex(16#6466) -> 223; -unhex(16#6530) -> 224; unhex(16#6531) -> 225; unhex(16#6532) -> 226; unhex(16#6533) -> 227; unhex(16#6534) -> 228; unhex(16#6535) -> 229; unhex(16#6536) -> 230; unhex(16#6537) -> 231; unhex(16#6538) -> 232; unhex(16#6539) -> 233; -unhex(16#6541) -> 234; unhex(16#6542) -> 235; unhex(16#6543) -> 236; unhex(16#6544) -> 237; unhex(16#6545) -> 238; unhex(16#6546) -> 239; -unhex(16#6561) -> 234; unhex(16#6562) -> 235; unhex(16#6563) -> 236; unhex(16#6564) -> 237; unhex(16#6565) -> 238; unhex(16#6566) -> 239; -unhex(16#6630) -> 240; unhex(16#6631) -> 241; unhex(16#6632) -> 242; unhex(16#6633) -> 243; unhex(16#6634) -> 244; unhex(16#6635) -> 245; unhex(16#6636) -> 246; unhex(16#6637) -> 247; unhex(16#6638) -> 248; unhex(16#6639) -> 249; -unhex(16#6641) -> 250; unhex(16#6642) -> 251; unhex(16#6643) -> 252; unhex(16#6644) -> 253; unhex(16#6645) -> 254; unhex(16#6646) -> 255; -unhex(16#6661) -> 250; unhex(16#6662) -> 251; unhex(16#6663) -> 252; unhex(16#6664) -> 253; unhex(16#6665) -> 254; unhex(16#6666) -> 255; -unhex(Char) -> - badarg_with_info([<>]). +decode_hex(Data) when byte_size(Data) rem 2 =:= 0 -> + try + decode_hex1(Data) + catch + error:badarg -> + badarg_with_info([Data]) + end; +decode_hex(Data) -> + badarg_with_info([Data]). + +decode_hex1(Data) -> + <> = Data, + Bin = << <<(unhex(A)):4, (unhex(B)):4, (unhex(C)):4, (unhex(D)):4, + (unhex(E)):4, (unhex(F)):4, (unhex(G)):4, (unhex(H)):4>> || + <> <= First >>, + decode_hex2(Rest, Bin). + +decode_hex2(<>, Acc) -> + decode_hex2(Data, <>); +decode_hex2(<<>>, Acc) -> + Acc. + +unhex(X) -> + element(X, + {nonono, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %1 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %16 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %32 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, no, no, no, no, no, no, %48 + no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no, %64 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %80 + no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no %96 + }). badarg_with_cause(Args, Cause) -> erlang:error(badarg, Args, [{error_info, #{module => erl_stdlib_errors, diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl index 01b70f7f6a38..88573d1df11b 100644 --- a/lib/stdlib/src/c.erl +++ b/lib/stdlib/src/c.erl @@ -793,9 +793,10 @@ lm() -> erlangrc() -> case init:get_argument(home) of - {ok,[[Home]]} -> - erlangrc([Home]); - _ -> + {ok,[[Home]]} -> + UserConfig = filename:basedir(user_config,"erlang"), + erlangrc([Home, UserConfig]); + _ -> {error, enoent} end. diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl index 2f95f54312e5..788444a66494 100644 --- a/lib/stdlib/src/calendar.erl +++ b/lib/stdlib/src/calendar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -94,11 +94,11 @@ -type yearweeknum() :: {year(),weeknum()}. -type rfc3339_string() :: [byte(), ...]. -%% By design 'native' is not supported: -type rfc3339_time_unit() :: 'microsecond' | 'millisecond' | 'nanosecond' - | 'second'. + | 'second' + | 'native'. %%---------------------------------------------------------------------- @@ -326,7 +326,7 @@ local_time_to_universal_time_dst(DateTime) -> -spec now_to_datetime(Now) -> datetime1970() when Now :: erlang:timestamp(). now_to_datetime({MSec, Sec, _uSec}) -> - system_time_to_datetime(MSec*1000000 + Sec). + system_time_to_datetime(MSec*1_000_000 + Sec). -spec now_to_universal_time(Now) -> datetime1970() when Now :: erlang:timestamp(). @@ -444,7 +444,23 @@ system_time_to_rfc3339(Time) -> system_time_to_rfc3339(Time, Options) -> Unit = proplists:get_value(unit, Options, second), - OffsetOption = proplists:get_value(offset, Options, ""), + OffsetOpt0 = proplists:get_value(offset, Options, ""), + case Unit of + native -> + TimeMS = erlang:convert_time_unit(Time, native, millisecond), + OffsetOpt1 = + if is_integer(OffsetOpt0) -> + erlang:convert_time_unit(OffsetOpt0, native, + millisecond); + true -> + OffsetOpt0 + end, + system_time_to_rfc3339_do(TimeMS, Options, millisecond, OffsetOpt1); + _ -> + system_time_to_rfc3339_do(Time, Options, Unit, OffsetOpt0) + end. + +system_time_to_rfc3339_do(Time, Options, Unit, OffsetOption) -> T = proplists:get_value(time_designator, Options, $T), AdjustmentSecs = offset_adjustment(Time, Unit, OffsetOption), Offset = offset(OffsetOption, AdjustmentSecs), @@ -702,9 +718,14 @@ offset_string_adjustment(_Time, _Unit, "Z") -> offset_string_adjustment(_Time, _Unit, "z") -> 0; offset_string_adjustment(_Time, _Unit, Tz) -> - [Sign, H1, H2, $:, M1, M2] = Tz, + [Sign, H1, H2 | MinutesDiff] = Tz, Hour = list_to_integer([H1, H2]), - Min = list_to_integer([M1, M2]), + Min = case MinutesDiff of + [$:, M1, M2] -> + list_to_integer([M1, M2]); + [] -> + 0 + end, Adjustment = 3600 * Hour + 60 * Min, case Sign of $- -> -Adjustment; @@ -738,12 +759,13 @@ copy_sign(N1, _N2) -> N1. factor(second) -> 1; factor(millisecond) -> 1000; -factor(microsecond) -> 1000000; -factor(nanosecond) -> 1000000000. +factor(microsecond) -> 1_000_000; +factor(nanosecond) -> 1_000_000_000; +factor(native) -> erlang:convert_time_unit(1, second, native). log10(1000) -> 3; -log10(1000000) -> 6; -log10(1000000000) -> 9. +log10(1_000_000) -> 6; +log10(1_000_000_000) -> 9. pad(0, S) -> S; diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 0488c2bef2ad..133d209ae15a 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -93,7 +93,8 @@ tab_name/0]). -compile({inline, [{einval,2},{badarg,2},{undefined,1}, - {badarg_exit,2},{lookup_reply,2}]}). + {badarg_exit,2},{lookup_reply,2}, + {pidof,1},{resp,2}]}). -include_lib("kernel/include/file.hrl"). @@ -149,7 +150,7 @@ proc :: 'undefined' | pid(), % the pid of the Dets process match_program :: 'true' | 'undefined' - | {'match_spec', ets:comp_match_spec()} + | {'match_spec', ets:compiled_match_spec()} }). -record(open_args, { @@ -321,7 +322,7 @@ foldl(Fun, Acc, Tab) -> -spec from_ets(Name, EtsTab) -> 'ok' | {'error', Reason} when Name :: tab_name(), - EtsTab :: ets:tab(), + EtsTab :: ets:table(), Reason :: term(). from_ets(DTab, ETab) -> @@ -861,7 +862,7 @@ table_info(_Tab, _) -> -spec to_ets(Name, EtsTab) -> EtsTab | {'error', Reason} when Name :: tab_name(), - EtsTab :: ets:tab(), + EtsTab :: ets:table(), Reason :: term(). to_ets(DTab, ETab) -> @@ -1237,15 +1238,24 @@ treq(Tab, R) -> req(Proc, R) -> Ref = erlang:monitor(process, Proc), - Proc ! ?DETS_CALL(self(), R), + Proc ! ?DETS_CALL({self(), Ref}, R), receive {'DOWN', Ref, process, Proc, _Info} -> badarg; - {Proc, Reply} -> + {Ref, Reply} -> erlang:demonitor(Ref, [flush]), Reply end. +%% Inlined. +pidof({Pid, _Tag}) -> + Pid. + +%% Inlined. +resp({Pid, Tag} = _From, Message) -> + Pid ! {Tag, Message}, + ok. + %% Inlined. einval({error, {file_error, _, einval}}, A) -> erlang:error(badarg, A); @@ -1398,7 +1408,7 @@ apply_op(Op, From, Head, N) -> true -> err({error, incompatible_arguments}) end, - From ! {self(), Res}, + resp(From, Res), ok; auto_save -> case Head#head.update_mode of @@ -1419,7 +1429,7 @@ apply_op(Op, From, Head, N) -> {0, Head} end; close -> - From ! {self(), fclose(Head)}, + resp(From, fclose(Head)), _NewHead = unlink_fixing_procs(Head), ?PROFILE(ep:done()), exit(normal); @@ -1427,25 +1437,25 @@ apply_op(Op, From, Head, N) -> %% Used from dets_server when Pid has closed the table, %% but the table is still opened by some process. NewHead = remove_fix(Head, Pid, close), - From ! {self(), status(NewHead)}, + resp(From, status(NewHead)), NewHead; {corrupt, Reason} -> {H2, Error} = dets_utils:corrupt_reason(Head, Reason), - From ! {self(), Error}, + resp(From, Error), H2; {delayed_write, WrTime} -> delayed_write(Head, WrTime); info -> {H2, Res} = finfo(Head), - From ! {self(), Res}, + resp(From, Res), H2; {info, Tag} -> {H2, Res} = finfo(Head, Tag), - From ! {self(), Res}, + resp(From, Res), H2; {is_compatible_bchunk_format, Term} -> Res = test_bchunk_format(Head, Term), - From ! {self(), Res}, + resp(From, Res), ok; {internal_open, Ref, Args} -> do_internal_open(Head#head.parent, Head#head.server, From, @@ -1462,27 +1472,27 @@ apply_op(Op, From, Head, N) -> end; {set_verbose, What} -> set_verbose(What), - From ! {self(), ok}, + resp(From, ok), ok; {where, Object} -> {H2, Res} = where_is_object(Head, Object), - From ! {self(), Res}, + resp(From, Res), H2; _Message when element(1, Head#head.update_mode) =:= error -> - From ! {self(), status(Head)}, + resp(From, status(Head)), ok; %% The following messages assume that the status of the table is OK. {bchunk_init, Tab} -> {H2, Res} = do_bchunk_init(Head, Tab), - From ! {self(), Res}, + resp(From, Res), H2; {bchunk, State} -> {H2, Res} = do_bchunk(Head, State), - From ! {self(), Res}, + resp(From, Res), H2; delete_all_objects -> {H2, Res} = fdelete_all_objects(Head), - From ! {self(), Res}, + resp(From, Res), erlang:garbage_collect(), {0, H2}; {delete_key, _Keys} when Head#head.update_mode =:= dirty -> @@ -1492,16 +1502,16 @@ apply_op(Op, From, Head, N) -> true -> stream_op(Op, From, [], Head, N); false -> - From ! {self(), badarg}, + resp(From, badarg), ok end; first -> {H2, Res} = ffirst(Head), - From ! {self(), Res}, + resp(From, Res), H2; {initialize, InitFun, Format, MinNoSlots} -> {H2, Res} = finit(Head, InitFun, Format, MinNoSlots), - From ! {self(), Res}, + resp(From, Res), erlang:garbage_collect(), H2; {insert, Objs} when Head#head.update_mode =:= dirty -> @@ -1509,12 +1519,12 @@ apply_op(Op, From, Head, N) -> true -> stream_op(Op, From, [], Head, N); false -> - From ! {self(), badarg}, + resp(From, badarg), ok end; {insert_new, Objs} when Head#head.update_mode =:= dirty -> {H2, Res} = finsert_new(Head, Objs), - From ! {self(), Res}, + resp(From, Res), {N + 1, H2}; {lookup_keys, _Keys} -> stream_op(Op, From, [], Head, N); @@ -1523,48 +1533,48 @@ apply_op(Op, From, Head, N) -> H2 = case Res of {cont,_} -> H1; _ when Safe =:= no_safe-> H1; - _ when Safe =:= safe -> do_safe_fixtable(H1, From, false) + _ when Safe =:= safe -> do_safe_fixtable(H1, pidof(From), false) end, - From ! {self(), Res}, + resp(From, Res), H2; {match, MP, Spec, NObjs, Safe} -> {H2, Res} = fmatch(Head, MP, Spec, NObjs, Safe, From), - From ! {self(), Res}, + resp(From, Res), H2; {member, _Key} = Op -> stream_op(Op, From, [], Head, N); {next, Key} -> {H2, Res} = fnext(Head, Key), - From ! {self(), Res}, + resp(From, Res), H2; {match_delete, State} when Head#head.update_mode =:= dirty -> {H1, Res} = fmatch_delete(Head, State), H2 = case Res of {cont,_S,_N} -> H1; - _ -> do_safe_fixtable(H1, From, false) + _ -> do_safe_fixtable(H1, pidof(From), false) end, - From ! {self(), Res}, + resp(From, Res), {N + 1, H2}; {match_delete_init, MP, Spec} when Head#head.update_mode =:= dirty -> {H2, Res} = fmatch_delete_init(Head, MP, Spec, From), - From ! {self(), Res}, + resp(From, Res), {N + 1, H2}; {safe_fixtable, Bool} -> - NewHead = do_safe_fixtable(Head, From, Bool), - From ! {self(), ok}, + NewHead = do_safe_fixtable(Head, pidof(From), Bool), + resp(From, ok), NewHead; {slot, Slot} -> {H2, Res} = fslot(Head, Slot), - From ! {self(), Res}, + resp(From, Res), H2; sync -> {NewHead, Res} = perform_save(Head, true), - From ! {self(), Res}, + resp(From, Res), erlang:garbage_collect(), {0, NewHead}; {update_counter, Key, Incr} when Head#head.update_mode =:= dirty -> {NewHead, Res} = do_update_counter(Head, Key, Incr), - From ! {self(), Res}, + resp(From, Res), {N + 1, NewHead}; WriteOp when Head#head.update_mode =:= new_dirty -> H2 = Head#head{update_mode = dirty}, @@ -1577,12 +1587,12 @@ apply_op(Op, From, Head, N) -> H2 = Head#head{update_mode = dirty}, apply_op(WriteOp, From, H2, 0); {NewHead, Error} when is_record(NewHead, head) -> - From ! {self(), Error}, + resp(From, Error), NewHead end; WriteOp when is_tuple(WriteOp), Head#head.access =:= read -> Reason = {access_mode, Head#head.filename}, - From ! {self(), err({error, Reason})}, + resp(From, err({error, Reason})), ok end. @@ -1603,7 +1613,7 @@ bug_found(Name, Op, Bad, Stacktrace, From) -> end, if From =/= self() -> - From ! {self(), {error, {dets_bug, Name, Op, Bad}}}, + resp(From, {error, {dets_bug, Name, Op, Bad}}), ok; true -> % auto_save | may_grow | {delayed_write, _} ok @@ -1613,10 +1623,10 @@ do_internal_open(Parent, Server, From, Ref, Args) -> ?PROFILE(ep:do()), case do_open_file(Args, Parent, Server, Ref) of {ok, Head} -> - From ! {self(), ok}, + resp(From, ok), Head; Error -> - From ! {self(), Error}, + resp(From, Error), exit(normal) end. @@ -1698,7 +1708,7 @@ stream_end1(Pids, Next, N, C, Head, PwriteList) -> stream_end2(Pids, Pids, Next, N, C, Head1, PR). stream_end2([Pid | Pids], Ps, Next, N, C, Head, Reply) -> - Pid ! {self(), Reply}, + resp(Pid, Reply), stream_end2(Pids, Ps, Next, N+1, C, Head, Reply); stream_end2([], Ps, no_more, N, C, Head, _Reply) -> penalty(Head, Ps, C), @@ -1710,7 +1720,7 @@ penalty(H, _Ps, _C) when H#head.fixed =:= false -> ok; penalty(_H, _Ps, [{{lookup,_Pids},_Keys}]) -> ok; -penalty(#head{fixed = {_,[{Pid,_}]}}, [Pid], _C) -> +penalty(#head{fixed = {_,[{Pid, _}]}}, [{Pid, _Tag} = _From], _C) -> ok; penalty(_H, _Ps, _C) -> timer:sleep(1). @@ -1729,9 +1739,9 @@ lookup_replies(P, O, [{P2,O2} | L]) -> %% If a list of Pid then op was {member, Key}. Inlined. lookup_reply([P], O) -> - P ! {self(), O =/= []}; + resp(P, O =/= []); lookup_reply(P, O) -> - P ! {self(), O}. + resp(P, O). %%----------------------------------------------------------------- %% Callback functions for system messages handling. @@ -2253,7 +2263,7 @@ fmatch(Head, MP, Spec, N, Safe, From) -> {Head1, []} -> NewHead = case Safe of - safe -> do_safe_fixtable(Head1, From, true); + safe -> do_safe_fixtable(Head1, pidof(From), true); no_safe -> Head1 end, C0 = init_scan(NewHead, N), @@ -2370,7 +2380,7 @@ do_fmatch_delete_var_keys(Head, _MP, ?PATTERN_TO_TRUE_MATCH_SPEC('_'), _From) Reply end; do_fmatch_delete_var_keys(Head, MP, _Spec, From) -> - Head1 = do_safe_fixtable(Head, From, true), + Head1 = do_safe_fixtable(Head, pidof(From), true), {NewHead, []} = write_cache(Head1), C0 = init_scan(NewHead, default), {NewHead, {cont, C0#dets_cont{match_program = MP}, 0}}. diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl index 6f9bbcd2bde5..797839ac4e97 100644 --- a/lib/stdlib/src/digraph.erl +++ b/lib/stdlib/src/digraph.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -39,9 +39,9 @@ -export_type([graph/0, d_type/0, vertex/0, edge/0, label/0]). --record(digraph, {vtab = notable :: ets:tab(), - etab = notable :: ets:tab(), - ntab = notable :: ets:tab(), +-record(digraph, {vtab = notable :: ets:table(), + etab = notable :: ets:table(), + ntab = notable :: ets:table(), cyclic = true :: boolean()}). -opaque graph() :: #digraph{}. diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl index 6078c5e67bd1..431a3dc0ba06 100644 --- a/lib/stdlib/src/edlin.erl +++ b/lib/stdlib/src/edlin.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2019. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -22,41 +22,44 @@ %% A simple Emacs-like line editor. %% About Latin-1 characters: see the beginning of erl_scan.erl. --export([init/0,init/1,start/1,start/2,edit_line/2,prefix_arg/1]). --export([erase_line/1,erase_inp/1,redraw_line/1]). +-export([init/0,init/1,start/1,start/2,edit_line/2]). +-export([erase_line/0,erase_inp/1,redraw_line/1]). -export([length_before/1,length_after/1,prompt/1]). -export([current_line/1, current_chars/1]). -%%-export([expand/1]). -export([edit_line1/2]). - +-export([inverted_space_prompt/1]). +-export([keymap/0]). -import(lists, [reverse/1, reverse/2]). -export([over_word/3]). +-type keymap() :: #{atom() => #{string()|default => atom()}}. %% A Continuation has the structure: -%% {line,Prompt,CurrentLine,EditPrefix} +%% {line,Prompt,{LinesBefore,{ColumnsBefore, ColumnsAfter},LinesAfter},{ShellMode, EscapePrefix}} %% init() %% Initialise the line editor. This must be done once per process using %% the editor. init() -> + put(key_map, edlin_key:get_key_map()), put(kill_buffer, []). init(Pid) -> + init(), %% copy the kill_buffer from the process Pid CopiedKillBuf = - case erlang:process_info(Pid, dictionary) of - {dictionary,Dict} -> - case proplists:get_value(kill_buffer, Dict) of - undefined -> []; - Buf -> Buf - end; - undefined -> - [] - end, + case erlang:process_info(Pid, dictionary) of + {dictionary,Dict} -> + case proplists:get_value(kill_buffer, Dict) of + undefined -> []; + Buf -> Buf + end; + undefined -> + [] + end, put(kill_buffer, CopiedKillBuf). %% start(Prompt) @@ -65,234 +68,170 @@ init(Pid) -> %% {done,Line,Rest,Requests} %% {more_chars,Cont,Requests} %% {blink,Cont,Requests} -%% {undefined,Char,Rest,Cont,Requests} start(Pbs) -> - start(Pbs, none). + start(Pbs, {normal,none}). %% Only two modes used: 'none' and 'search'. Other modes can be %% handled inline through specific character handling. -start(Pbs, Mode) -> - {more_chars,{line,Pbs,{[],[]},Mode},[{put_chars,unicode,Pbs}]}. +start(Pbs, {_,{_,_},[]}=Cont) -> + %% Skip redraw if the cursor is at the end. + {more_chars,{line,Pbs,Cont,{normal,none}},[{insert_chars,unicode,multi_line_prompt(Pbs)}]}; + +start(Pbs, {_,{_,_},_}=Cont) -> + {more_chars,{line,Pbs,Cont,{normal,none}},redraw(Pbs, Cont, [])}; + +start(Pbs, EditState) -> + {more_chars,{line,Pbs,{[],{[],[]},[]},EditState},[new_prompt, {insert_chars,unicode,Pbs}]}. + +-spec keymap() -> keymap(). +keymap() -> + get(key_map). -edit_line(Cs, {line,P,L,{blink,N}}) -> - edit(Cs, P, L, none, [{move_rel,N}]); +edit_line(Cs, {line,P,L,{blink,N_Rs}}) -> + edit(Cs, P, L, {normal, none}, N_Rs); edit_line(Cs, {line,P,L,M}) -> edit(Cs, P, L, M, []). -edit_line1(Cs, {line,P,L,{blink,N}}) -> - edit(Cs, P, L, none, [{move_rel,N}]); -edit_line1(Cs, {line,P,{[],[]},none}) -> - {more_chars, {line,P,{string:reverse(Cs),[]},none},[{put_chars, unicode, Cs}]}; +edit_line1(Cs, {line,P,L,{blink,N_Rs}}) -> + edit(Cs, P, L, {normal, none}, N_Rs); +edit_line1(Cs, {line,P,{B,{[],[]},A},{normal,none}}) -> + [CurrentLine|Lines] = [string:to_graphemes(Line) || Line <- reverse(string:split(Cs, "\n",all))], + Cont = {Lines ++ B,{reverse(CurrentLine),[]},A}, + Rs = redraw(P, Cont, []), + {more_chars, {line,P,Cont,{normal,none}},[delete_line|Rs]}; edit_line1(Cs, {line,P,L,M}) -> edit(Cs, P, L, M, []). edit([C|Cs], P, Line, {blink,_}, [_|Rs]) -> %Remove blink here - edit([C|Cs], P, Line, none, Rs); -edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> - case key_map(C, Prefix) of - meta -> - edit(Cs, P, {Bef,Aft}, meta, Rs0); - meta_o -> - edit(Cs, P, {Bef,Aft}, meta_o, Rs0); - meta_csi -> - edit(Cs, P, {Bef,Aft}, meta_csi, Rs0); - meta_meta -> - edit(Cs, P, {Bef,Aft}, meta_meta, Rs0); - {csi, _} = Csi -> - edit(Cs, P, {Bef,Aft}, Csi, Rs0); - meta_left_sq_bracket -> - edit(Cs, P, {Bef,Aft}, meta_left_sq_bracket, Rs0); - search_meta -> - edit(Cs, P, {Bef,Aft}, search_meta, Rs0); - search_meta_left_sq_bracket -> - edit(Cs, P, {Bef,Aft}, search_meta_left_sq_bracket, Rs0); - ctlx -> - edit(Cs, P, {Bef,Aft}, ctlx, Rs0); - new_line -> - {done, get_line(Bef, Aft ++ "\n"), Cs, - reverse(Rs0, [{move_rel,cp_len(Aft)},{put_chars,unicode,"\n"}])}; - redraw_line -> - Rs1 = erase(P, Bef, Aft, Rs0), - Rs = redraw(P, Bef, Aft, Rs1), - edit(Cs, P, {Bef,Aft}, none, Rs); - tab_expand -> - {expand, Bef, Cs, - {line, P, {Bef, Aft}, none}, - reverse(Rs0)}; - -%% tab -> -%% %% Always redraw the line since expand/1 might have printed -%% %% possible expansions. -%% case expand(Bef) of -%% {yes,Str} -> -%% edit([redraw_line| -%% (Str ++ Cs)], P, {Bef,Aft}, none, Rs0); -%% no -> -%% %% don't beep if there's only whitespace before -%% %% us - user may have pasted in a lot of indented stuff. -%% case whitespace_only(Bef) of -%% false -> -%% edit([redraw_line|Cs], P, {Bef,Aft}, none, -%% [beep|Rs0]); -%% true -> -%% edit([redraw_line|Cs], P, {Bef,Aft}, none, [Rs0]) -%% end -%% end; - {undefined,C} -> - {undefined,{none,Prefix,C},Cs,{line,P,{Bef,Aft},none}, - reverse(Rs0)}; - Op -> - case do_op(Op, Bef, Aft, Rs0) of - {blink,N,Line,Rs} -> - edit(Cs, P, Line, {blink,N}, Rs); - {Line, Rs, Mode} -> % allow custom modes from do_op - edit(Cs, P, Line, Mode, Rs); - {Line,Rs} -> - edit(Cs, P, Line, none, Rs) - end - end; + edit([C|Cs], P, Line, {normal,none}, Rs); edit([], P, L, {blink,N}, Rs) -> - {blink,{line,P,L,{blink,N}},reverse(Rs)}; -edit([], P, L, Prefix, Rs) -> - {more_chars,{line,P,L,Prefix},reverse(Rs)}; -edit(eof, _, {Bef,Aft}, _, Rs) -> - {done,get_line(Bef, Aft),[],reverse(Rs, [{move_rel,cp_len(Aft)}])}. - -%% %% Assumes that arg is a string -%% %% Horizontal whitespace only. -%% whitespace_only([]) -> -%% true; -%% whitespace_only([C|Rest]) -> -%% case C of -%% $\s -> -%% whitespace_only(Rest); -%% $\t -> -%% whitespace_only(Rest); -%% _ -> -%% false -%% end. - -%% prefix_arg(Argument) -%% Take a prefix argument and return its numeric value. - -prefix_arg(none) -> 1; -prefix_arg({ctlu,N}) -> N; -prefix_arg(N) -> N. - -%% key_map(Char, Prefix) -%% Map a character and a prefix to an action. - -key_map(A, _) when is_atom(A) -> A; % so we can push keywords -key_map($\^A, none) -> beginning_of_line; -key_map($\^B, none) -> backward_char; -key_map($\^D, none) -> forward_delete_char; -key_map($\^E, none) -> end_of_line; -key_map($\^F, none) -> forward_char; -key_map($\^H, none) -> backward_delete_char; -key_map($\t, none) -> tab_expand; -key_map($\^L, none) -> redraw_line; -key_map($\n, none) -> new_line; -key_map($\^K, none) -> kill_line; -key_map($\r, none) -> new_line; -key_map($\^T, none) -> transpose_char; -key_map($\^U, none) -> ctlu; -key_map($\^], none) -> auto_blink; -key_map($\^X, none) -> ctlx; -key_map($\^Y, none) -> yank; -key_map($\^W, none) -> backward_kill_word; -key_map($\e, none) -> meta; -key_map($), Prefix) when Prefix =/= meta, - Prefix =/= search, - Prefix =/= search_meta -> {blink,$),$(}; -key_map($}, Prefix) when Prefix =/= meta, - Prefix =/= search, - Prefix =/= search_meta -> {blink,$},${}; -key_map($], Prefix) when Prefix =/= meta, - Prefix =/= search, - Prefix =/= search_meta -> {blink,$],$[}; -key_map($B, meta) -> backward_word; -key_map($D, meta) -> kill_word; -key_map($F, meta) -> forward_word; -key_map($T, meta) -> transpose_word; -key_map($Y, meta) -> yank_pop; -key_map($b, meta) -> backward_word; -key_map($d, meta) -> kill_word; -key_map($f, meta) -> forward_word; -key_map($t, meta) -> transpose_word; -key_map($y, meta) -> yank_pop; -key_map($O, meta) -> meta_o; -key_map($H, meta_o) -> beginning_of_line; -key_map($F, meta_o) -> end_of_line; -key_map($\177, none) -> backward_delete_char; -key_map($\177, meta) -> backward_kill_word; -key_map($[, meta) -> meta_left_sq_bracket; -key_map($H, meta_left_sq_bracket) -> beginning_of_line; -key_map($F, meta_left_sq_bracket) -> end_of_line; -key_map($D, meta_left_sq_bracket) -> backward_char; -key_map($C, meta_left_sq_bracket) -> forward_char; -% support a few + combinations... -% - forward: \e\e[C, \e[5C, \e[1;5C -% - backward: \e\e[D, \e[5D, \e[1;5D -key_map($\e, meta) -> meta_meta; -key_map($[, meta_meta) -> meta_csi; -key_map($C, meta_csi) -> forward_word; -key_map($D, meta_csi) -> backward_word; -key_map($1, meta_left_sq_bracket) -> {csi, "1"}; -key_map($3, meta_left_sq_bracket) -> {csi, "3"}; -key_map($5, meta_left_sq_bracket) -> {csi, "5"}; -key_map($5, {csi, "1;"}) -> {csi, "1;5"}; -key_map($~, {csi, "3"}) -> forward_delete_char; -key_map($C, {csi, "5"}) -> forward_word; -key_map($C, {csi, "1;5"}) -> forward_word; -key_map($D, {csi, "5"}) -> backward_word; -key_map($D, {csi, "1;5"}) -> backward_word; -key_map($;, {csi, "1"}) -> {csi, "1;"}; -key_map(C, none) when C >= $\s -> - {insert,C}; -%% for search, we need smarter line handling and so -%% we cheat a bit on the dispatching, and allow to -%% return a mode. -key_map($\^H, search) -> {search, backward_delete_char}; -key_map($\177, search) -> {search, backward_delete_char}; -key_map($\^R, search) -> {search, skip_up}; -key_map($\^S, search) -> {search, skip_down}; -key_map($\n, search) -> {search, search_found}; -key_map($\r, search) -> {search, search_found}; -key_map($\^A, search) -> {search, search_quit}; -key_map($\^B, search) -> {search, search_quit}; -key_map($\^D, search) -> {search, search_quit}; -key_map($\^E, search) -> {search, search_quit}; -key_map($\^F, search) -> {search, search_quit}; -key_map($\t, search) -> {search, search_quit}; -key_map($\^L, search) -> {search, search_quit}; -key_map($\^T, search) -> {search, search_quit}; -key_map($\^U, search) -> {search, search_quit}; -key_map($\^], search) -> {search, search_quit}; -key_map($\^X, search) -> {search, search_quit}; -key_map($\^Y, search) -> {search, search_quit}; -key_map($\e, search) -> search_meta; -key_map($[, search_meta) -> search_meta_left_sq_bracket; -key_map(_, search_meta) -> {search, search_quit}; -key_map(_C, search_meta_left_sq_bracket) -> {search, search_quit}; -key_map(C, search) -> {insert_search,C}; -key_map(C, _) -> {undefined,C}. + {blink,{line,P,L, {blink,N}},reverse(Rs)}; +edit([], P, L, EditState, Rs) -> + {more_chars,{line,P,L,EditState},reverse(Rs)}; +edit(eof, _, {_,{Bef,Aft0},LA} = L, _, Rs) -> + Aft1 = case LA of + [Last|_] -> Last; + _ -> Aft0 + end, + {done,L,[],reverse(Rs, [{move_combo,-cp_len(Bef), length(LA), cp_len(Aft1)}])}; +edit(Buf, P, {LB, {Bef,Aft}, LA}=MultiLine, {ShellMode, EscapePrefix}, Rs0) -> + case edlin_key:get_valid_escape_key(Buf, EscapePrefix) of + {escape_prefix, EscapePrefix1} -> + case ShellMode of + tab_expand -> edit(Buf, P, MultiLine, {normal, none}, Rs0); + _ -> edit([], P, MultiLine, {ShellMode, EscapePrefix1}, Rs0) + end; + {invalid, _I, Rest} -> + edit(Rest, P, MultiLine, {ShellMode, none}, Rs0); + {insert, C1, Cs2} -> + %% If its a printable character + %% we could in theory override it in the keymap, + %% but lets not for now. + Op = case ShellMode of + normal when C1 =:= $) -> + {blink,$),$(}; + normal when C1 =:= $] -> + {blink,$],$[}; + normal when C1 =:= $} -> + {blink,$},${}; + normal -> {insert, C1}; + search when $\s =< C1 ->{insert_search, C1}; + search -> search_quit; + tab_expand -> tab_expand_quit + end, + case Op of + tab_expand_quit -> + edit(Buf, P, MultiLine, {normal,none}, Rs0); + search_quit -> + {search_quit,Cs2,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + _ -> + case do_op(Op, MultiLine, Rs0) of + {blink,N,MultiLine1,Rs} -> + edit(Cs2, P, MultiLine1, {blink,N}, Rs); + {redraw, MultiLine1, Rs} -> + edit(Cs2, P, MultiLine1, {ShellMode, none}, redraw(P, MultiLine1, Rs)); + {MultiLine1,Rs} -> + edit(Cs2, P, MultiLine1, {ShellMode, none}, Rs) + end + end; + {key, Key, Cs} -> + KeyMap = get(key_map), + Value = case maps:find(Key, maps:get(ShellMode, KeyMap)) of + error -> + %% Default handling for shell modes + case maps:find(default, maps:get(ShellMode, KeyMap)) of + error -> none; + {ok, Value0} -> Value0 + end; + {ok, Value0} -> Value0 + end, + case Value of + none -> edit(Cs, P, MultiLine, {normal,none}, Rs0); + search -> {search,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + search_found -> {search_found,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + search_cancel -> {search_cancel,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + search_quit -> {search_quit,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + open_editor -> {open_editor,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + history_up -> {history_up,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + history_down -> {history_down,Cs,{line,P,MultiLine,{normal, none}},reverse(Rs0)}; + new_line -> + MultiLine1 = {[lists:reverse(Bef)|LB],{[],Aft},LA}, + edit(Cs, P, MultiLine1, {normal, none}, reverse(redraw(P, MultiLine1, Rs0))); + new_line_finish -> + % Move to end + {{LB1,{Bef1,[]},[]}, Rs1} = do_op(end_of_expression, MultiLine, Rs0), + {done, {[lists:reverse(Bef1)|LB1],{[],[]},[]}, Cs, reverse(Rs1, [{insert_chars, unicode, "\n"}])}; + redraw_line -> + Rs1 = erase_line(Rs0), + Rs = redraw(P, MultiLine, Rs1), + edit(Cs, P, MultiLine, {normal, none}, Rs); + clear -> + Rs = redraw(P, MultiLine, [clear|Rs0]), + edit(Cs, P, MultiLine, {normal, none}, Rs); + tab_expand -> + {expand, chars_before(MultiLine), Cs, + {line, P, MultiLine, {tab_expand, none}}, + reverse(Rs0)}; + tab_expand_full -> + {expand_full, chars_before(MultiLine), Cs, + {line, P, MultiLine, {tab_expand, none}}, + reverse(Rs0)}; + tab_expand_quit -> + %% When exiting tab expand mode, we want to evaluate the key in normal mode + edit(Buf, P, MultiLine, {normal,none}, Rs0); + Op -> + Op1 = case ShellMode of + search -> + {search, Op}; + _ -> Op + end, + case do_op(Op1, MultiLine, Rs0) of + {blink,N,MultiLine1,Rs} -> + edit(Cs, P, MultiLine1, {blink,N}, Rs); + {redraw, MultiLine1, Rs} -> + edit(Cs, P, MultiLine1, {normal, none}, redraw(P, MultiLine1, Rs)); + {MultiLine1,Rs} -> + edit(Cs, P, MultiLine1, {ShellMode, none}, Rs) + end + end + end. %% do_op(Action, Before, After, Requests) %% Before and After are of lists of type string:grapheme_cluster() -do_op({insert,C}, [], [], Rs) -> - {{[C],[]},[{put_chars, unicode,[C]}|Rs]}; -do_op({insert,C}, [Bef|Bef0], [], Rs) -> +do_op({insert,C}, {LB,{[],[]},LA}, Rs) -> + {{LB,{[C],[]},LA},[{insert_chars, unicode,[C]}|Rs]}; +do_op({insert,C}, {LB,{[Bef|Bef0], []},LA}, Rs) -> case string:to_graphemes([Bef,C]) of - [GC] -> {{[GC|Bef0],[]},[{put_chars, unicode,[C]}|Rs]}; - _ -> {{[C,Bef|Bef0],[]},[{put_chars, unicode,[C]}|Rs]} + [GC] -> {{LB,{[GC|Bef0],[]},LA},[{insert_chars, unicode,[C]}|Rs]}; + _ -> {{LB,{[C,Bef|Bef0],[]},LA},[{insert_chars, unicode,[C]}|Rs]} end; -do_op({insert,C}, [], Aft, Rs) -> - {{[C],Aft},[{insert_chars, unicode,[C]}|Rs]}; -do_op({insert,C}, [Bef|Bef0], Aft, Rs) -> +do_op({insert,C}, {LB,{[], Aft},LA}, Rs) -> + {{LB,{[C],Aft},LA},[{insert_chars, unicode,[C]}|Rs]}; +do_op({insert,C}, {LB,{[Bef|Bef0], Aft},LA}, Rs) -> case string:to_graphemes([Bef,C]) of - [GC] -> {{[GC|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]}; - _ -> {{[C,Bef|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]} + [GC] -> {{LB,{[GC|Bef0],Aft},LA},[{insert_chars, unicode,[C]}|Rs]}; + _ -> {{LB,{[C,Bef|Bef0],Aft},LA},[{insert_chars, unicode,[C]}|Rs]} end; %% Search mode prompt always looks like (search)`$TERMS': $RESULT. %% the {insert_search, _} handlings allow to share this implementation @@ -303,127 +242,206 @@ do_op({insert,C}, [Bef|Bef0], Aft, Rs) -> %% search mode), we can use the Bef and Aft variables to hold each %% part of the line. Bef takes charge of "(search)`$TERMS" and Aft %% takes charge of "': $RESULT". -do_op({insert_search, C}, Bef, [], Rs) -> - Aft="': ", - {{[C|Bef],Aft}, - [{insert_chars, unicode, [C]++Aft}, {delete_chars,-3} | Rs], - search}; -do_op({insert_search, C}, Bef, Aft, Rs) -> - Offset= cp_len(Aft), - NAft = "': ", - {{[C|Bef],NAft}, - [{insert_chars, unicode, [C]++NAft}, {delete_chars,-Offset} | Rs], +%% +%% Since multiline support the search mode prompt always looks like: +%% search: $TERMS +%% $ResultLine1 +%% $ResultLine2 +do_op({insert_search, C}, {LB,{Bef, []},LA}, Rs) -> + {{LB, {[C|Bef],[]}, LA}, + [{insert_chars, unicode, [C]}, delete_after_cursor | Rs]}; +do_op({insert_search, C}, {LB,{Bef, _Aft},LA}, Rs) -> + {{LB, {[C|Bef],[]}, LA}, + [{insert_chars, unicode, [C]}, delete_after_cursor | Rs], search}; -do_op({search, backward_delete_char}, [_|Bef], Aft, Rs) -> +do_op({search, backward_delete_char}, {LB,{[_|Bef], Aft},LA}, Rs) -> Offset= cp_len(Aft)+1, - NAft = "': ", - {{Bef,NAft}, - [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], - search}; -do_op({search, backward_delete_char}, [], _Aft, Rs) -> - Aft="': ", - {{[],Aft}, Rs, search}; -do_op({search, skip_up}, Bef, Aft, Rs) -> + {{LB, {Bef,Aft}, LA}, + [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs]}; +do_op({search, backward_delete_char}, {LB,{[], Aft},LA}, Rs) -> + {{LB, {[],Aft}, LA}, [{insert_chars, unicode, Aft}, {delete_chars,-cp_len(Aft)}|Rs]}; +do_op({search, skip_up}, {_,{Bef, Aft},_}, Rs) -> Offset= cp_len(Aft), - NAft = "': ", - {{[$\^R|Bef],NAft}, % we insert ^R as a flag to whoever called us - [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], - search}; -do_op({search, skip_down}, Bef, Aft, Rs) -> + {{[],{[$\^R|Bef],Aft},[]}, % we insert ^R as a flag to whoever called us + [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs]}; +do_op({search, skip_down}, {_,{Bef, Aft},_LA}, Rs) -> Offset= cp_len(Aft), - NAft = "': ", - {{[$\^S|Bef],NAft}, % we insert ^S as a flag to whoever called us - [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], - search}; -do_op({search, search_found}, _Bef, Aft, Rs) -> - "': "++NAft = Aft, - {{[],NAft}, - [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], - search_found}; -do_op({search, search_quit}, _Bef, Aft, Rs) -> - "': "++NAft = Aft, - {{[],NAft}, - [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], - search_quit}; + {{[],{[$\^S|Bef],Aft},[]}, % we insert ^S as a flag to whoever called us + [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs]}; %% do blink after $$ -do_op({blink,C,M}, Bef=[$$,$$|_], Aft, Rs) -> - N = over_paren(Bef, C, M), - {blink,N+1,{[C|Bef],Aft},[{move_rel,-(N+1)},{insert_chars, unicode,[C]}|Rs]}; +do_op({blink,C,M}, {_,{[$$,$$|_], _},_} = MultiLine, Rs) -> + blink(over_paren(chars_before(MultiLine), C, M), C, MultiLine, Rs); %% don't blink after a $ -do_op({blink,C,_}, Bef=[$$|_], Aft, Rs) -> - do_op({insert,C}, Bef, Aft, Rs); -do_op({blink,C,M}, Bef, Aft, Rs) -> - case over_paren(Bef, C, M) of - beep -> - {{[C|Bef], Aft}, [beep,{insert_chars, unicode, [C]}|Rs]}; - N -> {blink,N+1,{[C|Bef],Aft}, - [{move_rel,-(N+1)},{insert_chars, unicode,[C]}|Rs]} - end; -do_op(auto_blink, Bef, Aft, Rs) -> - case over_paren_auto(Bef) of - {N, Paren} -> - {blink,N+1, - {[Paren|Bef], Aft},[{move_rel,-(N+1)},{insert_chars, unicode,[Paren]}|Rs]}; - % N is likely 0 - N -> {blink,N+1,{Bef,Aft}, - [{move_rel,-(N+1)}|Rs]} - end; -do_op(forward_delete_char, Bef, [GC|Aft], Rs) -> - {{Bef,Aft},[{delete_chars,gc_len(GC)}|Rs]}; -do_op(backward_delete_char, [GC|Bef], Aft, Rs) -> - {{Bef,Aft},[{delete_chars,-gc_len(GC)}|Rs]}; -do_op(transpose_char, [C1,C2|Bef], [], Rs) -> +do_op({blink,C,_}, {_,{[$$|_], _},_} = MultiLine, Rs) -> + do_op({insert,C}, MultiLine, Rs); +do_op({blink,C,M}, MultiLine, Rs) -> + blink(over_paren(chars_before(MultiLine), C, M), C, MultiLine, Rs); +do_op(auto_blink, MultiLine, Rs) -> + blink(over_paren_auto(chars_before(MultiLine)), MultiLine, Rs); +do_op(forward_delete_char, {LB,{Bef, []},[NextLine|LA]}, Rs) -> + NewLine = {LB, {Bef, NextLine}, LA}, + {redraw, NewLine, Rs}; +do_op(forward_delete_char, {LB,{Bef, [GC|Aft]},LA}, Rs) -> + {{LB, {Bef,Aft}, LA},[{delete_chars,gc_len(GC)}|Rs]}; +do_op(backward_delete_char, {[PrevLine|LB],{[], Aft},LA}, Rs) -> + NewLine = {LB, {lists:reverse(PrevLine), Aft}, LA}, + {redraw, NewLine,Rs}; +do_op(backward_delete_char, {LB,{[GC|Bef], Aft},LA}, Rs) -> + {{LB, {Bef,Aft}, LA},[{delete_chars,-gc_len(GC)}|Rs]}; +do_op(forward_delete_word, {LB,{Bef, []},[NextLine|LA]}, Rs) -> + NewLine = {LB, {Bef, NextLine}, LA}, + {redraw, NewLine, Rs}; +do_op(forward_delete_word, {LB,{Bef, Aft0},LA}, Rs) -> + {Aft1,Kill0,N0} = over_non_word(Aft0, [], 0), + {Aft,Kill,N} = over_word(Aft1, Kill0, N0), + put(kill_buffer, reverse(Kill)), + {{LB, {Bef,Aft}, LA},[{delete_chars,N}|Rs]}; +do_op(backward_delete_word, {[PrevLine|LB],{[], Aft},LA}, Rs) -> + NewLine = {LB, {lists:reverse(PrevLine), Aft}, LA}, + {redraw, NewLine,Rs}; +do_op(backward_delete_word, {LB,{Bef0, Aft},LA}, Rs) -> + {Bef1,Kill0,N0} = over_non_word(Bef0, [], 0), + {Bef,Kill,N} = over_word(Bef1, Kill0, N0), + put(kill_buffer, Kill), + {{LB,{Bef,Aft},LA},[{delete_chars,-N}|Rs]}; +do_op(transpose_char, {LB,{[C1,C2|Bef], []},LA}, Rs) -> Len = gc_len(C1)+gc_len(C2), - {{[C2,C1|Bef],[]},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -do_op(transpose_char, [C2|Bef], [C1|Aft], Rs) -> + {{LB, {[C2,C1|Bef],[]}, LA},[{insert_chars_over, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; +do_op(transpose_char, {LB,{[C2|Bef], [C1|Aft]},LA}, Rs) -> Len = gc_len(C2), - {{[C2,C1|Bef],Aft},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -do_op(kill_word, Bef, Aft0, Rs) -> + {{LB, {[C2,C1|Bef],Aft}, LA},[{insert_chars_over, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; +do_op(transpose_word, {LB,{Bef0, Aft0},LA}, Rs) -> + {Aft1,Word2A,N0} = over_word(Aft0, [], 0), + {Bef, TransposedWords, Aft, N} = case N0 of + 0 -> {Aft2,NonWord,N1} = over_non_word(Aft1, [], 0), + case N1 of + 0 -> + {Bef1,Word2B,B0} = over_word(Bef0, [], 0), + {Bef2,NonWordB,B1} = over_non_word(Bef1, [], B0), + {Bef3,Word1,B2} = over_word(Bef2, [], B1), + {Bef3, Word2B++NonWordB++Word1, Aft0, B2}; + _ -> + {Aft3,Word2,N2} = over_word(Aft2, [], N1), + case N2 of + 0 -> + {Bef1,Word2B,B0} = over_word(Bef0, [], 0), + {Bef2,NonWordB,B1} = over_non_word(Bef1, [], B0), + {Bef3,Word1,B2} = over_word(Bef2, [], B1), + {Bef3, Word2B++NonWordB++Word1, Aft0, B2}; + _ -> + {Bef1, NonWord2, B0} = over_non_word(Bef0, [], 0), + {Bef2, Word1, B1} = over_word(Bef1, [], B0), + {Bef2, reverse(Word2) ++NonWord2 ++ reverse(NonWord) ++Word1, Aft3, B1} + end + end; + _ -> + {Bef1,Word2B,B0} = over_word(Bef0, [], 0), + {Bef2,NonWord,B1} = over_non_word(Bef1, [], B0), + {Bef3,Word1,B2} = over_word(Bef2, [], B1), + {Bef3, Word2B++reverse(Word2A)++NonWord++Word1, Aft1, B2} + end, + {{LB, {reverse(TransposedWords)++Bef, Aft}, LA},[{insert_chars_over, unicode, TransposedWords}, {move_rel, -N}|Rs]}; +do_op(kill_word, {LB,{Bef, Aft0},LA}, Rs) -> {Aft1,Kill0,N0} = over_non_word(Aft0, [], 0), {Aft,Kill,N} = over_word(Aft1, Kill0, N0), put(kill_buffer, reverse(Kill)), - {{Bef,Aft},[{delete_chars,N}|Rs]}; -do_op(backward_kill_word, Bef0, Aft, Rs) -> + {{LB, {Bef,Aft}, LA},[{delete_chars,N}|Rs]}; +do_op(backward_kill_word, {LB,{Bef0, Aft},LA}, Rs) -> {Bef1,Kill0,N0} = over_non_word(Bef0, [], 0), {Bef,Kill,N} = over_word(Bef1, Kill0, N0), put(kill_buffer, Kill), - {{Bef,Aft},[{delete_chars,-N}|Rs]}; -do_op(kill_line, Bef, Aft, Rs) -> + {{LB,{Bef,Aft},LA},[{delete_chars,-N}|Rs]}; +do_op(kill_line, {LB, {Bef, Aft}, LA}, Rs) -> put(kill_buffer, Aft), - {{Bef,[]},[{delete_chars,cp_len(Aft)}|Rs]}; -do_op(yank, Bef, [], Rs) -> + {{LB, {Bef,[]}, LA},[{delete_chars,cp_len(Aft)}|Rs]}; +do_op(clear_line, _, Rs) -> + {redraw, {[], {[],[]},[]}, Rs}; +do_op(yank, {LB,{Bef, []},LA}, Rs) -> Kill = get(kill_buffer), - {{reverse(Kill, Bef),[]},[{put_chars, unicode,Kill}|Rs]}; -do_op(yank, Bef, Aft, Rs) -> + {{LB, {reverse(Kill, Bef),[]}, LA},[{insert_chars, unicode,Kill}|Rs]}; +do_op(yank, {LB,{Bef, Aft},LA}, Rs) -> Kill = get(kill_buffer), - {{reverse(Kill, Bef),Aft},[{insert_chars, unicode,Kill}|Rs]}; -do_op(forward_char, Bef, [C|Aft], Rs) -> - {{[C|Bef],Aft},[{move_rel,gc_len(C)}|Rs]}; -do_op(backward_char, [C|Bef], Aft, Rs) -> - {{Bef,[C|Aft]},[{move_rel,-gc_len(C)}|Rs]}; -do_op(forward_word, Bef0, Aft0, Rs) -> + {{LB, {reverse(Kill, Bef),Aft}, LA},[{insert_chars, unicode,Kill}|Rs]}; +do_op(forward_line, {_,_,[]} = MultiLine, Rs) -> + {MultiLine, Rs}; +do_op(forward_line, {LB,{Bef, Aft},[AL|LA]}, Rs) -> + CL = lists:reverse(Bef, Aft), + CursorPos = min(length(Bef), length(AL)), + {Bef1, Aft1} = lists:split(CursorPos, AL), + {{[CL|LB], {lists:reverse(Bef1), Aft1}, LA}, [{move_combo, -cp_len(Bef), 1, cp_len(Bef1)}|Rs]}; +do_op(backward_line, {[], _, _} = MultiLine, Rs) -> + {MultiLine, Rs}; +do_op(backward_line, {[BL|LB],{Bef, Aft},LA}, Rs) -> + CL = lists:reverse(Bef, Aft), + CursorPos = min(length(Bef), length(BL)), + {Bef1, Aft1} = lists:split(CursorPos, BL), + {{LB, {lists:reverse(Bef1), Aft1}, [CL|LA]},[{move_combo, -cp_len(Bef), -1, cp_len(Bef1)}|Rs]}; +do_op(forward_char, {LB,{Bef, []}, [AL|LA]}, Rs) -> + {{[lists:reverse(Bef)|LB],{[], string:to_graphemes(AL)}, LA}, [{move_combo, -cp_len(Bef), 1, 0}|Rs]}; +do_op(forward_char, {LB,{Bef, [C|Aft]},LA}, Rs) -> + {{LB,{[C|Bef],Aft},LA},[{move_rel,gc_len(C)}|Rs]}; +do_op(backward_char, {[BL|LB],{[], Aft},LA}, Rs) -> + {{LB,{lists:reverse(string:to_graphemes(BL)), []}, [Aft|LA]}, [{move_combo, 0, -1, cp_len(BL)}|Rs]}; +do_op(backward_char, {LB,{[C|Bef], Aft},LA}, Rs) -> + {{LB, {Bef,[C|Aft]}, LA},[{move_rel,-gc_len(C)}|Rs]}; +do_op(forward_word, {LB,{Bef0, []},[NextLine|LA]}, Rs) -> + {{[reverse(Bef0)|LB], {[], NextLine}, LA},[{move_combo, -cp_len(Bef0), 1, 0}|Rs]}; +do_op(forward_word, {LB,{Bef0, Aft0},LA}, Rs) -> {Aft1,Bef1,N0} = over_non_word(Aft0, Bef0, 0), - {Aft,Bef,N} = over_word(Aft1, Bef1, N0), - {{Bef,Aft},[{move_rel,N}|Rs]}; -do_op(backward_word, Bef0, Aft0, Rs) -> + {Aft, Bef, N} = over_word(Aft1, Bef1, N0), + {{LB, {Bef,Aft}, LA},[{move_rel,N}|Rs]}; +do_op(backward_word, {[PrevLine|LB],{[], Aft0},LA}, Rs) -> + {{LB, {reverse(PrevLine), []}, [Aft0|LA]},[{move_combo, 0, -1, cp_len(PrevLine)}|Rs]}; +do_op(backward_word, {LB,{Bef0, Aft0},LA}, Rs) -> {Bef1,Aft1,N0} = over_non_word(Bef0, Aft0, 0), {Bef,Aft,N} = over_word(Bef1, Aft1, N0), - {{Bef,Aft},[{move_rel,-N}|Rs]}; -do_op(beginning_of_line, [_|_]=Bef, Aft, Rs) -> - {{[],reverse(Bef, Aft)},[{move_rel,-(cp_len(Bef))}|Rs]}; -do_op(beginning_of_line, [], Aft, Rs) -> - {{[],Aft},Rs}; -do_op(end_of_line, Bef, [_|_]=Aft, Rs) -> - {{reverse(Aft, Bef),[]},[{move_rel,cp_len(Aft)}|Rs]}; -do_op(end_of_line, Bef, [], Rs) -> - {{Bef,[]},Rs}; -do_op(ctlu, Bef, Aft, Rs) -> + {{LB, {Bef,Aft}, LA},[{move_rel,-N}|Rs]}; +do_op(beginning_of_expression, {[],{[], Aft},LA}, Rs) -> + {{[], {[],Aft}, LA},Rs}; +do_op(beginning_of_expression, {LB,{Bef, Aft},LA}, Rs) -> + [First|Rest] = lists:reverse(LB) ++ [lists:reverse(Bef, Aft)], + {{[], {[],First}, Rest ++ LA},[{move_combo, -cp_len(Bef), -length(LB), 0}|Rs]}; +do_op(end_of_expression, {LB,{Bef, []},[]}, Rs) -> + {{LB, {Bef,[]}, []},Rs}; +do_op(end_of_expression, {LB,{Bef, Aft},LA}, Rs) -> + [Last|Rest] = lists:reverse(LA) ++ [lists:reverse(Bef, Aft)], + {{Rest ++ LB, {lists:reverse(Last),[]}, []},[{move_combo, -cp_len(Bef), length(LA), cp_len(Last)}|Rs]}; +do_op(beginning_of_line, {LB,{[_|_]=Bef, Aft},LA}, Rs) -> + {{LB, {[],reverse(Bef, Aft)}, LA},[{move_rel,-(cp_len(Bef))}|Rs]}; +do_op(beginning_of_line, {LB,{[], Aft},LA}, Rs) -> + {{LB, {[],Aft}, LA},Rs}; +do_op(end_of_line, {LB,{Bef, [_|_]=Aft},LA}, Rs) -> + {{LB, {reverse(Aft, Bef),[]}, LA},[{move_rel,cp_len(Aft)}|Rs]}; +do_op(end_of_line, {LB,{Bef, []},LA}, Rs) -> + {{LB, {Bef,[]}, LA},Rs}; +do_op(backward_kill_line, {LB,{Bef, Aft},LA}, Rs) -> put(kill_buffer, reverse(Bef)), - {{[], Aft}, [{delete_chars, -cp_len(Bef)} | Rs]}; -do_op(beep, Bef, Aft, Rs) -> - {{Bef,Aft},[beep|Rs]}; -do_op(_, Bef, Aft, Rs) -> - {{Bef,Aft},[beep|Rs]}. + {{LB, {[], Aft}, LA}, [{delete_chars, -cp_len(Bef)} | Rs]}; +do_op(beep, {LB,{Bef, Aft},LA}, Rs) -> + {{LB,{Bef,Aft},LA},[beep|Rs]}; +do_op(_, {LB,{Bef, Aft},LA}, Rs) -> + {{LB,{Bef,Aft},LA},[beep|Rs]}. + +blink(beep, C, {LB, {Bef, Aft}, LA}, Rs) -> + {{LB,{[C|Bef], Aft},LA}, [beep,{insert_chars, unicode, [C]}|Rs]}; +blink({N, R}, C, MultiLine, Rs) -> + blink({N, R, C}, MultiLine, Rs). +%% same line +blink(beep, {LB,{Bef, Aft},LA}, Rs) -> + {{LB,{Bef, Aft},LA}, [beep|Rs]}; +blink({N, 0, Paren}, {LB, {Bef, Aft}, LA}, Rs) -> + MoveBackToParen = {move_rel,-N-1}, + MoveForwardToParen = {move_rel, N+1}, + {blink,[MoveForwardToParen],{LB,{[Paren|Bef],Aft},LA}, + [MoveBackToParen,{insert_chars, unicode,[Paren]}|Rs]}; +%% multiline +blink({N, R, Paren}, {LB,{Bef, Aft},LA}, Rs) -> + LengthToClosingParen = cp_len([Paren|Bef]), + LengthOpeningParen = cp_len(lists:nth(R,LB)) - N - 1, + MoveToOpeningParen = {move_combo, -LengthToClosingParen, -R, LengthOpeningParen}, + MoveToClosingParen = {move_combo, -LengthOpeningParen, R, LengthToClosingParen+1}, + {blink,[MoveToClosingParen],{LB,{[Paren|Bef],Aft},LA}, + [MoveToOpeningParen,{insert_chars, unicode,[Paren]}|Rs]}. %% over_word(Chars, InitialStack, InitialCount) -> %% {RemainingChars,CharStack,Count} @@ -431,8 +449,6 @@ do_op(_, Bef, Aft, Rs) -> %% {RemainingChars,CharStack,Count} %% Step over word/non-word characters pushing the stepped over ones on %% the stack. - - over_word(Cs, Stack, N) -> L = length([1 || $\' <- Cs]), case L rem 2 of @@ -493,80 +509,84 @@ word_char(_) -> false. %% do proper parentheses matching check. Paren has NOT been added. over_paren(Chars, Paren, Match) -> - over_paren(Chars, Paren, Match, 1, 1, []). - - -over_paren([C,$$,$$|Cs], Paren, Match, D, N, L) -> - over_paren([C|Cs], Paren, Match, D, N+2, L); -over_paren([GC,$$|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+1+gc_len(GC), L); -over_paren([Match|_], _Paren, Match, 1, N, _) -> - N; -over_paren([Match|Cs], Paren, Match, D, N, [Match|L]) -> - over_paren(Cs, Paren, Match, D-1, N+1, L); -over_paren([Paren|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D+1, N+1, [Match|L]); - -over_paren([$)|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+1, [$(|L]); -over_paren([$]|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+1, [$[|L]); -over_paren([$}|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+1, [${|L]); - -over_paren([$(|Cs], Paren, Match, D, N, [$(|L]) -> - over_paren(Cs, Paren, Match, D, N+1, L); -over_paren([$[|Cs], Paren, Match, D, N, [$[|L]) -> - over_paren(Cs, Paren, Match, D, N+1, L); -over_paren([${|Cs], Paren, Match, D, N, [${|L]) -> - over_paren(Cs, Paren, Match, D, N+1, L); - -over_paren([$(|_], _, _, _, _, _) -> + over_paren(Chars, Paren, Match, 1, 1, 0, []). + + +over_paren([C,$$,$$|Cs], Paren, Match, D, N, R, L) -> + over_paren([C|Cs], Paren, Match, D, N+2, R, L); +over_paren([GC,$$|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D, N+1+gc_len(GC), R, L); +over_paren([$\n|Cs], Paren, Match, D, _N, R, L) -> + over_paren(Cs, Paren, Match, D, 0, R+1, L); +over_paren([Match|_], _Paren, Match, 1, N, R, _) -> + {N, R}; +over_paren([Match|Cs], Paren, Match, D, N, R, [Match|L]) -> + over_paren(Cs, Paren, Match, D-1, N+1, R, L); +over_paren([Paren|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D+1, N+1, R, [Match|L]); + +over_paren([$)|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D, N+1, R, [$(|L]); +over_paren([$]|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D, N+1, R, [$[|L]); +over_paren([$}|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D, N+1, R, [${|L]); + +over_paren([$(|Cs], Paren, Match, D, N, R, [$(|L]) -> + over_paren(Cs, Paren, Match, D, N+1, R, L); +over_paren([$[|Cs], Paren, Match, D, N, R, [$[|L]) -> + over_paren(Cs, Paren, Match, D, N+1, R, L); +over_paren([${|Cs], Paren, Match, D, N, R, [${|L]) -> + over_paren(Cs, Paren, Match, D, N+1, R, L); + +over_paren([$(|_], _, _, _, _, _, _) -> beep; -over_paren([$[|_], _, _, _, _, _) -> +over_paren([$[|_], _, _, _, _, _, _) -> beep; -over_paren([${|_], _, _, _, _, _) -> +over_paren([${|_], _, _, _, _, _, _) -> beep; -over_paren([GC|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+gc_len(GC), L); -over_paren([], _, _, _, _, _) -> - 0. +over_paren([GC|Cs], Paren, Match, D, N, R, L) -> + over_paren(Cs, Paren, Match, D, N+gc_len(GC), R, L); +over_paren([], _, _, _, _, _, _) -> + beep. over_paren_auto(Chars) -> - over_paren_auto(Chars, 1, 1, []). - - -over_paren_auto([C,$$,$$|Cs], D, N, L) -> - over_paren_auto([C|Cs], D, N+2, L); -over_paren_auto([GC,$$|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+1+gc_len(GC), L); - -over_paren_auto([$(|_], _, N, []) -> - {N, $)}; -over_paren_auto([$[|_], _, N, []) -> - {N, $]}; -over_paren_auto([${|_], _, N, []) -> - {N, $}}; - -over_paren_auto([$)|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+1, [$(|L]); -over_paren_auto([$]|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+1, [$[|L]); -over_paren_auto([$}|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+1, [${|L]); - -over_paren_auto([$(|Cs], D, N, [$(|L]) -> - over_paren_auto(Cs, D, N+1, L); -over_paren_auto([$[|Cs], D, N, [$[|L]) -> - over_paren_auto(Cs, D, N+1, L); -over_paren_auto([${|Cs], D, N, [${|L]) -> - over_paren_auto(Cs, D, N+1, L); - -over_paren_auto([GC|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+gc_len(GC), L); -over_paren_auto([], _, _, _) -> - 0. + over_paren_auto(Chars, 1, 1, 0, []). + + +over_paren_auto([C,$$,$$|Cs], D, N, R, L) -> + over_paren_auto([C|Cs], D, N+2, R, L); +over_paren_auto([GC,$$|Cs], D, N, R, L) -> + over_paren_auto(Cs, D, N+1+gc_len(GC), R, L); +over_paren_auto([$\n|Cs], D, _N, R, L) -> + over_paren_auto(Cs, D, 0, R+1, L); + +over_paren_auto([$(|_], _, N, R, []) -> + {N, R, $)}; +over_paren_auto([$[|_], _, N, R, []) -> + {N, R, $]}; +over_paren_auto([${|_], _, N, R, []) -> + {N, R, $}}; + +over_paren_auto([$)|Cs], D, N, R, L) -> + over_paren_auto(Cs, D, N+1, R, [$(|L]); +over_paren_auto([$]|Cs], D, N, R, L) -> + over_paren_auto(Cs, D, N+1, R, [$[|L]); +over_paren_auto([$}|Cs], D, N, R, L) -> + over_paren_auto(Cs, D, N+1, R, [${|L]); + +over_paren_auto([$(|Cs], D, N, R, [$(|L]) -> + over_paren_auto(Cs, D, N+1, R, L); +over_paren_auto([$[|Cs], D, N, R, [$[|L]) -> + over_paren_auto(Cs, D, N+1, R, L); +over_paren_auto([${|Cs], D, N, R, [${|L]) -> + over_paren_auto(Cs, D, N+1, R, L); + +over_paren_auto([GC|Cs], D, N, R, L) -> + over_paren_auto(Cs, D, N+gc_len(GC), R, L); +over_paren_auto([], _, _, _, _) -> + beep. %% erase_line(Line) %% erase_inp(Line) @@ -575,40 +595,79 @@ over_paren_auto([], _, _, _) -> %% length_after(Line) %% prompt(Line) %% current_line(Line) +%% current_chars(Line) %% Various functions for accessing bits of a line. -erase_line({line,Pbs,{Bef,Aft},_}) -> - reverse(erase(Pbs, Bef, Aft, [])). +erase_line() -> + [delete_line]. -erase_inp({line,_,{Bef,Aft},_}) -> - reverse(erase([], Bef, Aft, [])). +erase_inp({line,_, L,_}) -> + reverse(erase([], L, [])). -erase(Pbs, Bef, Aft, Rs) -> +erase_line(Rs) -> + [delete_line|Rs]. + +erase(Pbs, {_,{Bef, Aft},_}, Rs) -> [{delete_chars,-cp_len(Pbs)-cp_len(Bef)},{delete_chars,cp_len(Aft)}|Rs]. -redraw_line({line,Pbs,{Bef,Aft},_}) -> - reverse(redraw(Pbs, Bef, Aft, [])). +redraw_line({line, Pbs, L,_}) -> + redraw(Pbs, L, []). + +multi_line_prompt(Pbs) -> + case application:get_env(stdlib, shell_multiline_prompt, default) of + default -> %% Default multiline prompt + default_multiline_prompt(Pbs); + {M,F} when is_atom(M), is_atom(F) -> + case catch apply(M,F,[Pbs]) of + Prompt when is_list(Prompt) -> Prompt; + _ -> + application:set_env(stdlib, shell_multiline_prompt, default), + io:format("Invalid call: ~p:~p/1~n", [M,F]), + default_multiline_prompt(Pbs) + end; + Prompt when is_list(Prompt) -> + lists:duplicate(max(0,prim_tty:npwcwidthstring(Pbs) - prim_tty:npwcwidthstring(Prompt)), $\s) ++ Prompt; + Prompt -> + application:set_env(stdlib, shell_multiline_prompt, default), + io:format("Invalid multiline prompt: ~p~n", [Prompt]), + default_multiline_prompt(Pbs) + end. + +default_multiline_prompt(Pbs) -> + lists:duplicate(max(0,prim_tty:npwcwidthstring(Pbs) - 3), $\s) ++ ".. ". +inverted_space_prompt(Pbs) -> + "\e[7m" ++ lists:duplicate(prim_tty:npwcwidthstring(Pbs) - 1, $\s) ++ "\e[27m ". + +redraw(Pbs, {_,{_,_},_}=L, Rs) -> + [{redraw_prompt, Pbs, multi_line_prompt(Pbs), L} |Rs]. -redraw(Pbs, Bef, Aft, Rs) -> - [{move_rel,-cp_len(Aft)},{put_chars, unicode,reverse(Bef, Aft)},{put_chars, unicode,Pbs}|Rs]. +chars_before({[],{Bef,_},_}) -> + Bef; +chars_before({LB,{Bef,_},_}) -> + lists:flatten(lists:join($\n, [Bef| [reverse(Line)|| Line <- LB]])). -length_before({line,Pbs,{Bef,_Aft},_}) -> +length_before({line,Pbs,{_,{Bef,_Aft},_},_}) -> cp_len(Pbs) + cp_len(Bef). -length_after({line,_,{_Bef,Aft},_}) -> +length_after({line,_,{_,{_Bef,Aft},_},_}) -> cp_len(Aft). prompt({line,Pbs,_,_}) -> Pbs. -current_line({line,_,{Bef, Aft},_}) -> - get_line(Bef, Aft ++ "\n"). - -current_chars({line,_,{Bef,Aft},_}) -> - get_line(Bef, Aft). - -get_line(Bef, Aft) -> - unicode:characters_to_list(reverse(Bef, Aft)). +current_chars({line,_,MultiLine,_}) -> + current_line(MultiLine). +current_line({line,_,MultiLine,_}) -> + current_line(MultiLine) ++ "\n"; +%% Convert a multiline tuple into a string with new lines +current_line({LinesBefore, {Before, After}, LinesAfter}) -> + CurrentLine = lists:reverse(Before, After), + unicode:characters_to_list(lists:flatten( + lists:filter( + fun (X) -> + X /= [] + end, + lists:join($\n, lists:reverse(LinesBefore) ++ [CurrentLine] ++ LinesAfter)))). %% Grapheme length in codepoints gc_len(CP) when is_integer(CP) -> 1; @@ -621,148 +680,3 @@ cp_len(Str) -> cp_len([GC|R], Len) -> cp_len(R, Len + gc_len(GC)); cp_len([], Len) -> Len. - -%% %% expand(CurrentBefore) -> -%% %% {yes,Expansion} | no -%% %% Try to expand the word before as either a module name or a function -%% %% name. We can handle white space around the seperating ':' but the -%% %% function name must be on the same line. CurrentBefore is reversed -%% %% and over_word/3 reverses the characters it finds. In certain cases -%% %% possible expansions are printed. - -%% expand(Bef0) -> -%% {Bef1,Word,_} = over_word(Bef0, [], 0), -%% case over_white(Bef1, [], 0) of -%% {[$:|Bef2],_White,_Nwh} -> -%% {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), -%% {_,Mod,_Nm} = over_word(Bef3, [], 0), -%% expand_function_name(Mod, Word); -%% {_,_,_} -> -%% expand_module_name(Word) -%% end. - -%% expand_module_name(Prefix) -> -%% match(Prefix, code:all_loaded(), ":"). - -%% expand_function_name(ModStr, FuncPrefix) -> -%% Mod = list_to_atom(ModStr), -%% case erlang:module_loaded(Mod) of -%% true -> -%% L = apply(Mod, module_info, []), -%% case lists:keyfind(exports, 1, L) of -%% {_, Exports} -> -%% match(FuncPrefix, Exports, "("); -%% _ -> -%% no -%% end; -%% false -> -%% no -%% end. - -%% match(Prefix, Alts, Extra) -> -%% Matches = match1(Prefix, Alts), -%% case longest_common_head([N || {N,_} <- Matches]) of -%% {partial, []} -> -%% print_matches(Matches), -%% no; -%% {partial, Str} -> -%% case lists:nthtail(length(Prefix), Str) of -%% [] -> -%% print_matches(Matches), -%% {yes, []}; -%% Remain -> -%% {yes, Remain} -%% end; -%% {complete, Str} -> -%% {yes, lists:nthtail(length(Prefix), Str) ++ Extra}; -%% no -> -%% no -%% end. - -%% %% Print the list of names L in multiple columns. -%% print_matches(L) -> -%% io:nl(), -%% col_print(lists:sort(L)), -%% ok. - -%% col_print([]) -> ok; -%% col_print(L) -> col_print(L, field_width(L), 0). - -%% col_print(X, Width, Len) when Width + Len > 79 -> -%% io:nl(), -%% col_print(X, Width, 0); -%% col_print([{H0,A}|T], Width, Len) -> -%% H = if -%% %% If the second element is an integer, we assume it's an -%% %% arity, and meant to be printed. -%% integer(A) -> -%% H0 ++ "/" ++ integer_to_list(A); -%% true -> -%% H0 -%% end, -%% io:format("~-*s",[Width,H]), -%% col_print(T, Width, Len+Width); -%% col_print([], _, _) -> -%% io:nl(). - -%% field_width([{H,_}|T]) -> field_width(T, length(H)). - -%% field_width([{H,_}|T], W) -> -%% case length(H) of -%% L when L > W -> field_width(T, L); -%% _ -> field_width(T, W) -%% end; -%% field_width([], W) when W < 40 -> -%% W + 4; -%% field_width([], _) -> -%% 40. - -%% match1(Prefix, Alts) -> -%% match1(Prefix, Alts, []). - -%% match1(Prefix, [{H,A}|T], L) -> -%% case prefix(Prefix, Str = atom_to_list(H)) of -%% true -> -%% match1(Prefix, T, [{Str,A}|L]); -%% false -> -%% match1(Prefix, T, L) -%% end; -%% match1(_, [], L) -> -%% L. - -%% longest_common_head([]) -> -%% no; -%% longest_common_head(LL) -> -%% longest_common_head(LL, []). - -%% longest_common_head([[]|_], L) -> -%% {partial, reverse(L)}; -%% longest_common_head(LL, L) -> -%% case same_head(LL) of -%% true -> -%% [[H|_]|_] = LL, -%% LL1 = all_tails(LL), -%% case all_nil(LL1) of -%% false -> -%% longest_common_head(LL1, [H|L]); -%% true -> -%% {complete, reverse([H|L])} -%% end; -%% false -> -%% {partial, reverse(L)} -%% end. - -%% same_head([[H|_]|T1]) -> same_head(H, T1). - -%% same_head(H, [[H|_]|T]) -> same_head(H, T); -%% same_head(_, []) -> true; -%% same_head(_, _) -> false. - -%% all_tails(LL) -> all_tails(LL, []). - -%% all_tails([[_|T]|T1], L) -> all_tails(T1, [T|L]); -%% all_tails([], L) -> L. - -%% all_nil([]) -> true; -%% all_nil([[] | Rest]) -> all_nil(Rest); -%% all_nil(_) -> false. diff --git a/lib/stdlib/src/edlin_context.erl b/lib/stdlib/src/edlin_context.erl new file mode 100644 index 000000000000..589bac4a02e1 --- /dev/null +++ b/lib/stdlib/src/edlin_context.erl @@ -0,0 +1,649 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2023. 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(edlin_context). +%% description +%% +-export([get_context/1, get_context/2, odd_quotes/2]). +%% The context record is a structure that helps with viewing a nested expression +%% Typically we do not know the types of a tuple or a map in isolation, but if +%% we make use of the type information available for a function or a record +%% then we are able to extract more information. +%% A nesting can be either be a tuple a list or a map, more types of nestings could +%% be supported in the future. But it is for these types that we have type information. +%% We do not need to care about nested records or nested functions since the type information +%% is available for the deepest nested one. +%% The context record stores the top most nesting so far, while the nesting field contains +%% a list of nestings we found, the last element being the deepest nesting. +-type nesting() :: {'tuple', [{atom(), string()}], {atom(), string()} | []} + | {'list', [{atom(), string()}], {atom(), string()} | []} + | {'map', [string()], string(), [{atom(), string()}], {atom(), string()} | []}. +-record(context,{ + arguments = [] :: [any()], + fields = [] :: [string()], %% The Field or Keys in this nesting + parameter_count = 0 :: non_neg_integer(), %% Number of parameters in this nesting + current_field = [] :: string(), %% field of a record or key of a map field= %% should be the last element in this context + nestings = [] :: [nesting()]}). +%% get_context - basically get the context to be able to deduce how we should complete the word +%% If the word is empty, then we do not want to complete with anything if we just closed +%% a bracket, ended a quote (user has to enter , or . themselves) +%% but maybe we can help to add ',',},] depending on context in the future +-spec get_context(Line) -> Context when + Line :: string(), %% The whole line in reverse excluding Word + Mod :: string(), + Fun :: string(), + Args :: list(any()), + Unfinished :: any(), + Binding :: string(), %% map variable + Keys :: [string()], %% list of keys in the map MapBind + Record :: string(), + Fields :: [string()], %% list of keys in the record + FieldToComplete :: string(), + Nesting :: [nesting()] | [], + Context :: {string} %% cursor is inside a string "_ + | {binding} %% cursor is inside a Binding statement + | {term} %% cursor is at a free position, where any value is expected + | {term, Args, Unfinished} + | {fun_} %% cursor is in a fun statement (either a NewVar, '(' or mfa() is expected) + | {fun_, Mod} %% cursor is in a fun mod: statement (mfa) + | {fun_, Mod, Fun} %% cursor is in a fun mod:fun statement + | {new_fun, Unfinished} + | {function} + | {function, Mod, Fun, Args, Unfinished, Nesting} + | {map, Binding, Keys} + | {map_or_record} + | {record} + | {record, Record, Fields, FieldToComplete, Args, Unfinished, Nesting} + | {error, integer()}. +get_context(Line) -> + {Bef0, Word} = edlin_expand:over_word(Line), + case {{Bef0, Word}, odd_quotes($", Bef0)} of + {_, true} -> {string}; + {{[$#|_], []}, _} -> {map_or_record}; + {{_Bef1, Word}, _} -> + case is_binding(Word) of + true -> {binding}; + false -> get_context(Bef0, Word) + end + end. +get_context(">-" ++ _, L) when is_list(L) -> {term}; +get_context([$?|_], _) -> + {macro}; +get_context(Bef0, Word) when is_list(Word) -> + get_context(lists:reverse(Word) ++ Bef0, #context{}); +get_context([], #context{arguments = Args, parameter_count = Count, nestings = Nestings} = _CR) -> + case Count+1 == length(Args) of + true -> {term, lists:droplast(Args), lists:last(Args)}; + _ -> + %% Nestings will not end up as an argument + case Nestings of + [] -> case Count of + 0 when length(Args) > 0 -> {term, lists:droplast(Args), lists:last(Args)}; + _ -> {term, Args, []} + end; + [{list, Args1, Arg}] -> {term, Args1, Arg}; + [{tuple, Args1, Arg}] -> {term, Args1, Arg}; + [{map, _, _, Args1, Arg}] -> {term, Args1, Arg} + end + end; +get_context([$(|Bef], CR) -> + %% We have an unclosed opening parenthesis + %% Check if we have a function call + %% We can deduce the minimum arity based on how many terms we trimmed + %% We can check the type of the following Term and suggest those in special cases + %% shell_default and erlang are imported, make sure we can do expansion for those + {Bef1, Fun} = edlin_expand:over_word(Bef), + case Fun of + [] -> {term}; % parenthesis + _ -> + {_, Mod} = over_module(Bef1, Fun), + case Mod of + "shell" -> {term}; + "shell_default" -> {term}; + _ -> + case CR#context.parameter_count+1 == length(CR#context.arguments) of + true -> + %% N arguments N-1 commas, this means that we have an argument + %% still being worked on. + {function, Mod, Fun, lists:droplast(CR#context.arguments), + lists:last(CR#context.arguments),CR#context.nestings}; + _ -> + {function, Mod, Fun, CR#context.arguments, + [], CR#context.nestings} + end + end + end; +get_context([${|Bef], #context{ fields=Fields, + current_field=FieldToComplete, + arguments = Arguments, + parameter_count = Count, + nestings=Nestings}) -> + {Args, Unfinished} = case Count+1 == length(Arguments) of + true -> {lists:droplast(Arguments), lists:last(Arguments)}; + _ -> {Arguments, []} + end, + case edlin_expand:over_word(Bef) of + {[$#|Bef1], []} -> %% Map + {Bef2, Map} = edlin_expand:over_word(Bef1), + case Map of + [] -> get_context(Bef2, #context{ + %% We finished a nesting lets reset and read the next nesting + nestings = [{'map', Fields, FieldToComplete, Args, Unfinished}|Nestings]}); + _ -> {map, Map, Fields} + end; + {_, []} -> + get_context(Bef, #context{ + %% We finished a nesting lets reset and read the next nesting + nestings = [{'tuple', Args, Unfinished}|Nestings]}); + {[$#|_Bef3], Record} -> %% Record + {record, Record, Fields, FieldToComplete, Args, Unfinished, Nestings} + end; +get_context([$[|Bef1], #context{arguments = Arguments, parameter_count = Count, nestings=Nestings}) -> + {Args, Unfinished} = case Count+1 == length(Arguments) of + true -> {lists:droplast(Arguments), lists:last(Arguments)}; + _ -> {Arguments, []} + end, + get_context(Bef1, #context{ + %% We finished a nesting lets reset and read the next nesting + nestings = [{'list', Args, Unfinished}|Nestings]}); +get_context([$,|Bef1], #context{parameter_count=Count}=CR) -> + get_context(Bef1, CR#context{ + parameter_count = Count+1}); +get_context([$>,$=|Bef1], #context{ parameter_count=Count, + fields=Fields}=CR) -> + {Bef2, Field}=edlin_expand:over_word(Bef1), + case Count of + 0 -> %% If count is 0, then we know its a value we may want to complete. + get_context(Bef2, CR#context{fields = [Field|Fields], + current_field = Field}); + _ -> get_context(Bef2, CR#context{fields = [Field|Fields]}) + end; +get_context([$=,$:|Bef1], #context{ parameter_count=Count, + fields=Fields}=CR) -> + {Bef2, Field}=edlin_expand:over_word(Bef1), + case Count of + 0 -> %% If count is 0, then we know its a value we may want to complete. + get_context(Bef2, CR#context{fields = [Field|Fields], + current_field = Field}); + _ -> get_context(Bef2, CR#context{fields = [Field|Fields]}) + end; +get_context([$=|Bef1], #context{ + parameter_count=Count, + fields=Fields}=CR) -> + {Bef2, Field}=edlin_expand:over_word(Bef1), + % if we are here, its always going to be + case Count of + 0 -> %%[$=|_], + get_context(Bef2, CR#context{fields = [Field|Fields], + current_field = Field}); + _ -> get_context(Bef2, CR#context{fields = [Field|Fields]}) + end; +get_context([$.|Bef2], CR) -> + Arguments = CR#context.arguments, + Count = CR#context.parameter_count, + {Args, Unfinished} = case Count+1 == length(Arguments) of + true -> {lists:droplast(Arguments), lists:last(Arguments)}; + _ -> {Arguments, []} + end, + case edlin_expand:over_word(Bef2) of + {[$#|_Bef3], Record} -> %% Record + {record, Record, CR#context.fields, CR#context.current_field, Args, Unfinished, CR#context.nestings}; + _ -> {'end'} + end; +get_context([$:|Bef2], _) -> + %% look backwards to see if its a fun + {Bef3, Mod} = edlin_expand:over_word(Bef2), + case edlin_expand:over_word(Bef3) of + {_, "fun"} -> {fun_, Mod}; + _ -> {function} + end; +get_context([$/|Bef1], _) -> + {Bef2, Fun} = edlin_expand:over_word(Bef1), + {_, Mod} = over_module(Bef2, Fun), + {fun_, Mod, Fun}; +get_context([$>,$-|_Bef2], #context{arguments = Args} = CR) -> + %% Inside a function + case CR#context.parameter_count+1 == length(Args) of + true -> + {term, lists:droplast(Args), lists:last(Args)}; + _ -> {term, Args, []} + end; +get_context("nehw " ++ _Bef2, #context{arguments = Args} = CR) -> + %% Inside a guard + case CR#context.parameter_count+1 == length(Args) of + true -> + {term, lists:droplast(Args), lists:last(Args)}; + _ -> {term, Args, []} + end; +get_context([$\ |Bef],CR) -> get_context(Bef, CR); %% matching space here simplifies the other clauses +get_context(Bef0, #context{arguments=Args, parameter_count=Count} = CR) -> + case over_to_opening(Bef0) of + {_,[]} -> {term}; + {error, _}=E -> E; + {record} -> {record}; + {fun_} -> {fun_}; + {new_fun, _}=F -> F; + {Bef1, {fun_, Str}=Arg} -> + case Count of + 0 -> + [_, Mod, Fun| _] = string:tokens(Str, " :/"), + {fun_, Mod, Fun}; + _ -> get_context(Bef1, CR#context{arguments=[Arg|Args]}) + end; + {Bef1, Arg} -> get_context(Bef1, CR#context{arguments=[Arg|Args]}) + end. + +read_operator(Bef) -> + read_operator1(Bef). + +operator_string() -> "-=><:+*/|&^~". +read_operator1([$\ |Bef]) -> read_operator1(Bef); +read_operator1("mer " ++ Bef) -> {Bef, "rem"}; +read_operator1("osladna " ++ Bef) -> {Bef, "andalso"}; +read_operator1("dna " ++ Bef) -> {Bef, "and"}; +read_operator1("eslero " ++ Bef) -> {Bef, "orelse"}; +read_operator1("ro " ++ Bef) -> {Bef, "or"}; +read_operator1([$>,$>,$>|Bef1]) -> {[$>,$>|Bef1], [$>]}; %% comparison with a binary or typo +read_operator1([$>,$>|Bef1]) -> {[$>|Bef1], [$>]}; %% comparison with a pid, or binary +read_operator1([$>,$-, C|Bef1]=Bef) -> + case lists:member(C, operator_string()) of + true -> {Bef1, [C,$-,$>]}; + false -> {Bef, []} + end; +read_operator1([$>,$=, C|Bef1]=Bef) -> + case lists:member(C, operator_string()) of + true -> {Bef1, [C,$=,$>]}; + false -> {Bef, []} + end; +read_operator1([$=,$:, C|Bef1]=Bef) -> + case lists:member(C, operator_string()) of + true -> {Bef1, [C,$:,$=]}; + false -> {Bef, []} + end; +read_operator1([$:|_]=Bef) -> {Bef, []}; %% this operator does not count +read_operator1([Op1,Op2,Op3|Bef])-> + case {lists:member(Op1, operator_string()), + lists:member(Op2, operator_string()), + lists:member(Op3, operator_string())} of + {true, true, true} -> {Bef, [Op3, Op2, Op1]}; + {true, true, false} -> {[Op3|Bef], [Op2, Op1]}; + {true, false, _} -> {[Op2,Op3|Bef], [Op1]}; + _ -> {[Op1,Op2,Op3|Bef], []} + end; +read_operator1([Op1, Op2]) -> + case {lists:member(Op1, operator_string()), + lists:member(Op2, operator_string())} of + {true, true} -> {[], [Op2, Op1]}; + {true, false} -> {[Op2], [Op1]}; + _ -> {[Op1,Op2], []} + end; +read_operator1([Op1]) -> + case lists:member(Op1, operator_string()) of + true -> {[], [Op1]}; + _ -> {[Op1], []} + end; +read_operator1(Bef) -> {Bef, []}. + +read_opening_char("nehw "++Bef) -> + {Bef, "when"}; +read_opening_char([OC|Bef]) when OC =:= $(; OC =:= $[; OC =:= ${; OC =:= $,; OC =:= $. -> + {Bef, [OC]}; +read_opening_char([$>,$-|_]=Bef) -> + case read_operator(Bef) of + {_, []} -> {Bef, "->"}; + _ -> {Bef, []} + end; +read_opening_char([$\ |Bef]) -> read_opening_char(Bef); +read_opening_char(Bef) -> {Bef, []}. + +over_to_opening(Bef) -> try + over_to_opening1(Bef,#{args => []}) + catch + throw:E -> E + end. +over_to_opening1([], #{'args' := Args}) -> + over_to_opening_return([], Args); +over_to_opening1(Bef, Acc = #{args := Args}) -> + case edlin_expand:over_word(Bef) of + {_, []} -> %% removed spaces + case read_opening_char(Bef) of + {Bef1, []} -> %% not an opening + case extract_argument2(Bef1) of + {stop} -> over_to_opening_return(Bef1, Args); + {Bef2, []} -> over_to_opening_return(Bef2, Args); + {Bef2, Arg} -> over_to_opening1(Bef2, Acc#{args => [Arg | Args]}) + end; + {_Bef1, _Opening} -> over_to_opening_return(Bef, Args) + end; + _ -> case extract_argument2(Bef) of + {stop} -> over_to_opening_return(Bef, Args); + {Bef2, []} -> over_to_opening_return(Bef2, Args); + {Bef2, Arg} -> over_to_opening1(Bef2, Acc#{args => [Arg | Args]}) + end + end. +over_to_opening_return(Bef, Args) -> + case Args of + [] -> {Bef, []}; + [Arg] -> {Bef, Arg}; + [{operator, "-"}, {integer, I}] -> {Bef, {integer, "-" ++ I}}; + [{operator, "-"}, {float, F}] -> {Bef, {float, "-" ++ F}}; + [{atom, "fun"}, {atom, _}] -> throw({fun_}); + _ -> + case look_for_non_operator_separator(Args) of + true -> {Bef, {operation, lists:flatten(lists:join(" ", lists:map(fun({_, Arg}) -> Arg end, Args)))}}; + false -> {error, length(Bef)} + end + end. +look_for_non_operator_separator([{string, _},{string, _}=A|Args]) -> + look_for_non_operator_separator([A|Args]); +look_for_non_operator_separator([{operator, _}, {operator, _}|_]) -> false; + +look_for_non_operator_separator([_, {operator, _}=B|Args]) -> + look_for_non_operator_separator([B|Args]); +look_for_non_operator_separator([{operator, _}, B|Args]) -> + look_for_non_operator_separator([B|Args]); +look_for_non_operator_separator([_]) -> true; +look_for_non_operator_separator(_) -> false. + +over_map_record_or_tuple(Bef0) -> + case over_to_opening_paren($},Bef0) of + {_, []} -> %% no matching { + throw({error, length(Bef0)}); + {Bef3, Clause} -> + {Bef4, MaybeRecord} = edlin_expand:over_word(Bef3), + case MaybeRecord of + [] -> case Bef4 of + [$#|Bef5] -> %% Map + {Bef6, _Var} = edlin_expand:over_word(Bef5), + {Bef6, {map, _Var++"#"++Clause}}; + _ -> %% Tuple + {Bef4, {tuple, Clause}} + end; + _Record -> %% Record + [$#|Bef5] = Bef4, + {Bef6, _Var} = edlin_expand:over_word(Bef5), + {Bef6, {record, _Var++"#"++_Record++Clause}} + end + end. +over_pid_port_or_ref(Bef2) -> + %% Extracts argument or part of an operation + %% Consume Pid, Ref, FunRef or Binary + case over_to_opening_paren($>,Bef2) of + {_, []} -> %% no matching <, maybe a '>' operator + throw({soft_error, length(Bef2)}); + {Bef3, Clause} -> + case Bef3 of + "feR#" ++ Bef4 -> + {Bef4, {ref, "#Ref" ++ Clause}}; + "nuF#" ++ Bef4 -> + {Bef4, {'funref', "#Fun" ++ Clause}}; + "troP#" ++ Bef4 -> + {Bef4, {port, "#Port" ++ Clause}}; + _ -> case edlin_expand:over_word(Bef3) of + {Bef3, []} -> + case Bef2 of + [$>|_] -> %% binary + {Bef3, {binary, Clause}}; + _ -> %% pid + %% match + {Bef3, {pid, Clause}} + end; + _ -> + throw({error, length(Bef3)}) + end + end + end. +over_list(Bef2) -> + case over_to_opening_paren($],Bef2) of + {_, []} -> %% no matching [ + throw({error, length(Bef2)}); + {Bef3, Clause} -> + {Bef3, {list, Clause}} + end. +over_parenthesis_or_call(Bef2) -> + case over_to_opening_paren($),Bef2) of + {_, []} -> %% no matching ( + throw({error, length(Bef2)}); + {Bef3, Clause} -> + {Bef4, Fun} = edlin_expand:over_word(Bef3), + {Bef5, ModFun} = case Bef4 of + [$:|Bef41] -> + {Bef42, Mod} = edlin_expand:over_word(Bef41), + {Bef42, Mod++[$:|Fun]}; + _ -> {Bef4, Fun} + end, + case ModFun of + [] -> {Bef5, {parenthesis, Clause}}; + "fun" -> throw({new_fun, Clause}); + _ -> {Bef5, {call, ModFun++Clause}} + end + end. +over_keyword_or_fun(Bef1) -> + case over_keyword_expression(Bef1) of + {Bef2, KeywordExpression} -> {Bef2, {keyword, KeywordExpression ++ " end"}}; + _ -> throw({error, length(Bef1)}) + end. +extract_argument2([$>|Bef0]=Bef)-> + case read_operator(Bef) of + {[$>|_]=Bef1, ">"=Operator} -> + try over_pid_port_or_ref(Bef0) + catch + %% not a pid, port, ref or binary + throw:{error, _}=E -> throw(E); + throw:{soft_error, _Col} -> {Bef1, {operator, Operator}} + end; + {Bef1, ">"=Operator} -> + try over_pid_port_or_ref(Bef1) + catch + %% not a pid, port or ref + throw:{error, _}=E -> throw(E); + throw:{soft_error, _Col} -> {Bef1, {operator, Operator}} + end; + {_Bef1, []} -> {stop}; + {Bef1, Operator} -> {Bef1, {operator, Operator}} + end; +extract_argument2(Bef0) -> + case read_operator(Bef0) of + {[$}|Bef1], []} -> over_map_record_or_tuple(Bef1); + {[$)|Bef1], []} -> over_parenthesis_or_call(Bef1); + {[$]|Bef1], []} -> over_list(Bef1); + {[$"|Bef2], []} -> {Bef3, _Quote} = over_to_opening_quote($", Bef2), + {Bef3, {string, _Quote}}; + {"dne "++Bef1, []} -> over_keyword_or_fun(Bef1); + {[$=,$:|_], []} -> {stop}; + {[$:|_], []} -> {stop}; + {"nehw" ++ _Bef1,[]} -> {stop}; + {_, []} -> extract_argument(Bef0); + {Bef1, Operator} -> + {Bef1, {operator, Operator}} + end. + +extract_argument(Bef0) -> + %% TODO: We probably need to be able to extract Terms with operators... + case edlin_expand:over_word(Bef0) of + {_Bef1, []} -> + case read_char(_Bef1) of + {_, []} -> {_Bef1, []}; + {Bef2, Char} -> {Bef2, {char, Char}} + end; + {Bef2, Var} -> + try list_to_integer(Var) of + _ -> %% there is an integer + case over_fun_function(Bef0) of + {Bef3, "fun " ++ _ModFunArr} -> {Bef3, {fun_, "fun "++_ModFunArr}}; + _ -> case over_number(Bef0) of + {Bef3, []} -> {Bef3, []}; %% how to deal with operators + {Bef3, Number} -> {Bef3, Number} + + end + end + catch + _:_ -> + case is_binding(Var) of + true -> {Bef2,{var, Var}}; + false -> case Bef2 of + [$#|_] -> throw({record}); + _ -> {Bef2, {atom, Var}} + end + end + end + end. +over_number(Bef) -> + case edlin_expand:over_word(Bef) of + {_, []} -> {Bef, []}; + {Bef2, Var} -> + try list_to_integer(Var) of + _ -> + {Bef6, {NumberType, Number}}=Res = case edlin_expand:over_word(Bef2) of + {[$.|Bef3],[]} -> %% float + {Bef4, Integer} = edlin_expand:over_word(Bef3), + {Bef4, {float, Integer ++ "." ++ Var}}; + {[$#|Bef3],[]} -> %% integer base + {Bef4, Base} = edlin_expand:over_word(Bef3), + {Bef4, {integer, Base ++ "#" ++ Var}}; + _ -> + {Bef2, {integer, Var}} + %% otherwise its an operation that can be very complicated we should read everything up to the closest CC + %% and return an {operation, Clause} + end, + case edlin_expand:over_word(Bef6) of + {[$-|Bef5], []} -> + case read_opening_char(Bef5) of + {_, []} -> Res; + _ -> {Bef5, {NumberType, "-" ++Number}} + end; + _ -> Res + end + catch + _:_ -> {Bef, []} + end + end. +read_char([C,$$|Line]) -> + {Line, [$$,C]}; +read_char([$$|Line]) -> + {Line, "$ "}; +read_char(Line) -> + {Line, []}. + +over_fun_function(Bef) -> + over_fun_function(Bef, []). +over_fun_function(Bef, Acc) -> + case edlin_expand:over_word(Bef) of + {[$/|Bef1], Arity} -> over_fun_function(Bef1, [$/|Arity]++Acc); + {[$:|Bef1], Fun} -> over_fun_function(Bef1, [$:|Fun]++Acc); + {" nuf"++Bef1, ModOrFun} -> over_fun_function(Bef1, "fun "++ModOrFun ++ Acc); + _ -> {Bef,Acc} + end. + +%% Extracts everything within the quote +over_to_opening_quote(Q, Bef) when Q == $'; Q == $" -> + over_to_opening_quote([Q], Bef, [Q]); +over_to_opening_quote(_, Bef) -> {Bef, []}. +over_to_opening_quote([], Bef, Word) -> {Bef, Word}; +over_to_opening_quote([Q|Stack], [Q|Bef], Word) -> + over_to_opening_quote(Stack, Bef, [Q| Word]); +over_to_opening_quote([Q|Stack], [Q,EC|Bef], Word) when EC=:=$\\; EC=:=$$ -> + over_to_opening_quote([Q|Stack], Bef, [EC,Q| Word]); +over_to_opening_quote([Stack], [C|Bef], Word) -> + over_to_opening_quote([Stack], Bef, [C| Word]); +over_to_opening_quote(_,_,Word) -> {lists:reverse(Word), []}. + +matching_paren($(,$)) -> true; +matching_paren($[,$]) -> true; +matching_paren(${,$}) -> true; +matching_paren($<,$>) -> true; +matching_paren(_,_) -> false. + +%% Extracts everything within the brackets +%% Recursively extracts nested bracket expressions. +over_to_opening_paren(CC, Bef) when CC == $); CC == $]; + CC == $}; CC == $> -> + over_to_opening_paren([CC], Bef, [CC]); +over_to_opening_paren(_, Bef) -> {Bef, []}. %% Not a closing parenthesis +over_to_opening_paren([], Bef, Word) -> {Bef, Word}; +over_to_opening_paren(_, [], Word) -> {lists:reverse(Word), []}; %% Not a closing parenthesis +over_to_opening_paren([CC|Stack], [CC,$$|Bef], Word) -> + over_to_opening_paren([CC|Stack], Bef, [$$,CC|Word]); +over_to_opening_paren([CC|Stack], [OC|Bef], Word) when OC==$(; OC==$[; OC==${; OC==$< -> + case matching_paren(OC, CC) of + true -> over_to_opening_paren(Stack, Bef, [OC|Word]); + false -> over_to_opening_paren([CC|Stack], Bef, [OC|Word]) + end; +over_to_opening_paren([CC|Stack], [CC|Bef], Word) -> %% Nested parenthesis of same type + over_to_opening_paren([CC,CC|Stack], Bef, [CC|Word]); +over_to_opening_paren(Stack, [Q,NEC|Bef], Word) when Q == $"; Q == $', NEC /= $$, NEC /= $\\ -> + %% Consume the whole quoted text, it may contain parenthesis which + %% would have confused us. + {Bef1, QuotedWord} = over_to_opening_quote(Q, Bef), + over_to_opening_paren(Stack, Bef1, QuotedWord ++ Word); +over_to_opening_paren(CC, [C|Bef], Word) -> over_to_opening_paren(CC, Bef, [C|Word]). + +%% Extract a whole keyword expression +%% Keywordend +%% Function expects a string of erlang code in reverse, and extracts everything +%% including a keyword being one of if, fun, case, maybe, receiver (need to add all here) +%% Recursively extracts nested keyword expressions +%% Note: In the future we could autocomplete case expressions by looking at the +%% return type of the expression. +over_keyword_expression(Bef) -> + over_keyword_expression(Bef, []). +over_keyword_expression("dne"++Bef, Expr)-> + %% Nested expression + {Bef1, KWE}=over_keyword_expression(Bef), + over_keyword_expression(Bef1, KWE++"end"++Expr); +over_keyword_expression("fi"++Bef, Expr) -> {Bef, "if" ++ Expr}; +over_keyword_expression("nuf"++Bef, Expr) -> {Bef, "fun" ++ Expr}; +over_keyword_expression("yrt"++Bef, Expr) -> {Bef, "try" ++ Expr}; +over_keyword_expression("esac"++Bef, Expr) -> {Bef, "case" ++ Expr}; +over_keyword_expression("hctac"++Bef, Expr) -> + case over_keyword_expression(Bef, []) of + {Bef1, "try" ++ Expr1} -> {Bef1, "try" ++ Expr1 ++ "catch" ++ Expr}; + _ -> {Bef, "catch" ++ Expr} + end; +over_keyword_expression("nigeb"++Bef, Expr) -> {Bef, "begin" ++ Expr}; +over_keyword_expression("ebyam"++Bef, Expr) -> {Bef, "maybe" ++ Expr}; +over_keyword_expression("eviecer"++Bef, Expr) -> {Bef, "receive" ++ Expr}; +over_keyword_expression([], _) -> {no, [], []}; +over_keyword_expression([C|Bef], Expr) -> over_keyword_expression(Bef, [C|Expr]). + +odd_quotes(Q, [Q,C|Line], Acc) when C == $\\; C == $$ -> + odd_quotes(Q, Line, Acc); +odd_quotes(Q, [Q|Line], Acc) -> + odd_quotes(Q, Line, Acc+1); +odd_quotes(Q, [_|Line], Acc) -> + odd_quotes(Q, Line, Acc); +odd_quotes(_, [], Acc) -> Acc band 1 == 1. +odd_quotes(Q, Line) -> + odd_quotes(Q, Line, 0). + +over_module(Bef, Fun)-> + case edlin_expand:over_word(Bef) of + {[$:|Bef1], _} -> + edlin_expand:over_word(Bef1); + {[], _} -> {Bef, edlin_expand:shell_default_or_bif(Fun)}; + _ -> {Bef, edlin_expand:bif(Fun)} + end. + +%% Check that the given string starts with a capital letter, or an underscore +%% followed by an alphanumeric grapheme. +is_binding(Word) -> + Normalized = unicode:characters_to_nfc_list(Word), + nomatch =/= re:run(Normalized, + "^[_[:upper:]][[:alpha:]]*$", + [unicode, ucp]). diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl index bc3de137508b..9823534e9b94 100644 --- a/lib/stdlib/src/edlin_expand.erl +++ b/lib/stdlib/src/edlin_expand.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -18,47 +18,784 @@ %% %CopyrightEnd% %% -module(edlin_expand). +%% a default expand function for edlin, expanding modules, functions +%% filepaths, variable binding, record names, function parameter values, +%% record fields and map keys and record field values. +-include_lib("kernel/include/eep48.hrl"). +-export([expand/1, expand/2, expand/3, format_matches/2, number_matches/1, get_exports/1, + shell_default_or_bif/1, bif/1, over_word/1]). +-export([is_type/3, match_arguments1/3]). +-record(shell_state,{ + bindings = [], + records = [], + functions = [] + }). -%% a default expand function for edlin, expanding modules and functions +-spec expand(Bef0) -> {Res, Completion, Matches} when + Bef0 :: string(), %% a line of erlang expressions in reverse + Res :: 'yes' | 'no', + Completion :: string(), + Matches :: [Element] | [Section], + Element :: {string(), [ElementOption]}, + ElementOption :: {ending, string()}, + Section :: #{title:=string(), elems:=Matches, options:=SectionOption}, + SectionOption :: {highlight_all} %% highlight the whole title + | {highlight, string()} %% highlight this part of the title + | {highlight_param, integer()} %% highlight this parameter + | {hide, title} %% hide the title + | {hide, result} %% hide the results + | {separator, string()}. %% specify another separator between title and result +expand(Bef0) -> + expand(Bef0, [{legacy_output, true}]). + +-spec expand(Bef0, Opts) -> {Res, Completion, Matches} when + Bef0 :: string(), %% a line of erlang expressions in reverse + Opts :: [Option], + Option :: {legacy_output, boolean()}, + Res :: 'yes' | 'no', + Completion :: string(), + Matches :: [Element] | [Section], + Element :: {string(), [ElementOption]}, + ElementOption :: {ending, string()}, + Section :: #{title:=string(), elems:=Matches, options:=SectionOption}, + SectionOption :: {highlight_all} %% highlight the whole title + | {highlight, string()} %% highlight this part of the title + | {highlight_param, integer()} %% highlight this parameter + | {hide, title} %% hide the title + | {hide, result} %% hide the results + | {separator, string()}. %% specify another separator between title and result +expand(Bef0, Opts) -> + ShellState = try + shell:get_state() + catch + _:_ -> + %% Running on a shell that does not support get_state() + #shell_state{bindings=[],records=[],functions=[]} + end, + expand(Bef0, Opts, ShellState). + +%% Only used for testing +expand(Bef0, Opts, #shell_state{bindings = Bs, records = RT, functions = FT}) -> + LegacyOutput = proplists:get_value(legacy_output, Opts, false), + {_Bef1, Word} = over_word(Bef0), + {Res, Expansion, Matches} = case edlin_context:get_context(Bef0) of + + {string} -> expand_string(Bef0); + + {binding} -> expand_binding(Word, Bs); + + {term} -> expand_module_function(Bef0, FT); + {term, _, {_, Unfinished}} -> expand_module_function(lists:reverse(Unfinished), FT); + {error, _Column} -> + {no, [], []}; + {function} -> expand_module_function(Bef0, FT); + {fun_} -> expand_module_function(Bef0, FT); + + {fun_, Mod} -> expand_function_name(Mod, Word, "/", FT); + + %% Complete with arity in a 'fun mod:fun/' expression + {fun_, Mod, Fun} -> + Arities = [integer_to_list(A) || A <- get_arities(Mod, Fun)], + match(Word, Arities, ""); + {new_fun, _ArgsString} -> {no, [], []}; + %% Suggest type of function parameter + %% Complete an unfinished list, tuple or map using type of function parameter + {function, Mod, Fun, Args, Unfinished, Nesting} -> + Mod2 = case Mod of + "user_defined" -> "shell_default"; + _ -> Mod + end, + FunExpansion = expand_function_type(Mod2, Fun, Args, Unfinished, Nesting, FT), + case Word of + [] -> FunExpansion; + _ -> + ModuleOrBifs = expand_helper(FT, module, Word, ":"), + Functions = case Args =/= [] andalso lists:last(Args) of + {atom, MaybeMod} -> expand_function_name(MaybeMod, Word, "", FT); + _ -> {no, [], []} + end, + fold_results([FunExpansion] ++ ModuleOrBifs ++ [Functions]) + end; + + %% Complete an unfinished key or suggest valid keys of a map binding + {map, Binding, Keys} -> expand_map(Word, Bs, Binding, Keys); + + {map_or_record} -> + {[$#|Bef2], _} = over_word(Bef0), + {_, Var} = over_word(Bef2), + case Bs of + [] -> expand_record(Word, RT); + _ -> + case proplists:get_value(list_to_atom(Var), Bs) of + undefined -> + expand_record(Word, RT); + Map when is_map(Map) -> {yes, "{", []}; + RecordTuple when is_tuple(RecordTuple), tuple_size(RecordTuple) > 0 -> + Atom = erlang:element(1, RecordTuple), + case (is_atom(Atom) andalso lists:keysearch(Atom, 1, RT)) of + {value, {Atom, _}} -> match(Word, [Atom], "{"); + _ -> {no, [], []} + end; + _ -> {no, [], []} + end + end; + + {record} -> expand_record(Word, RT); + + {record, Record, Fields, FieldToComplete, Args, Unfinished, Nestings} -> + RecordExpansion = expand_record_fields(FieldToComplete, Unfinished, Record, Fields, RT, Args, Nestings, FT), + case Word of + [] -> RecordExpansion; + _ -> + ModuleOrBifs = expand_helper(FT, module,Word,":"), + fold_results([RecordExpansion] ++ ModuleOrBifs) + end; + _ -> {no, [], []} + + end, + Matches1 = case {Res,number_matches(Matches)} of + {yes, 1} -> []; + _ -> Matches + end, + case LegacyOutput of + true -> {Res, Expansion, to_legacy_format(Matches1)}; + false -> {Res, Expansion, Matches1} + end. +expand_map(_, [], _, _) -> + {no, [], []}; +expand_map(Word, Bs, Binding, Keys) -> + case proplists:get_value(list_to_atom(Binding), Bs) of + Map when is_map(Map) -> + K1 = sets:from_list(maps:keys(Map)), + K2 = sets:subtract(K1, sets:from_list([list_to_atom(K) || K <- Keys])), + match(Word, sets:to_list(K2), "=>"); + _ -> {no, [], []} + end. + +over_word(Bef) -> + {Bef1,_,_} = over_white(Bef, [], 0), + {Bef2, Word, _} = edlin:over_word(Bef1, [], 0), + {Bef2, Word}. + + +expand_binding(Prefix, Bindings) -> + Alts = [strip_quotes(K) || {K,_} <- Bindings], + case match(Prefix, Alts, "") of + {_Res,_Expansion,[]}=M -> M; + {Res, Expansion, Matches} -> {Res,Expansion,[#{title=>"bindings", elems=>Matches, options=>[highlight_all]}]} + end. + +expand_record(Prefix, RT) -> + Alts = [Name || {Name, _} <- RT], + case match(Prefix, Alts, "{") of + {_Res,_Expansion,[]}=M -> M; + {Res, Expansion, Matches} -> {Res,Expansion,[#{title=>"records", elems=>Matches, options=>[highlight_all]}]} + end. + +expand_record_fields(FieldToComplete, Word, Record, Fields, RT, _Args, Nestings, FT) -> + Record2 = list_to_atom(Record), + FieldSet2 = sets:from_list([list_to_atom(F) || F <- Fields]), + FieldToComplete2 = list_to_atom(FieldToComplete), + Word1 = case Word of + {_, Word2} -> Word2; + [] -> [] + end, + case [RecordSpec || {Record3, RecordSpec} <- RT, Record2 =:= Record3] of + [RecordType|_] -> + case sets:is_element(FieldToComplete2, FieldSet2) of + true -> + expand_record_field_content(FieldToComplete2, RecordType, Word1, Nestings, FT); + false -> + expand_record_field_name(Record2, FieldSet2, RecordType, Word1) + end; + _ -> + {no, [], []} + end. + +expand_record_field_name(Record, Fields, RecordType, Word) -> + RecordFieldsList = extract_record_fields(Record, RecordType), + RecordFieldsSet = sets:from_list(RecordFieldsList), + RecordFields = sets:subtract(RecordFieldsSet, Fields), + Alts = sets:to_list(RecordFields), + case match(Word, Alts, "=") of + {_Res,_Expansion,[]}=M -> M; + {Res, Expansion, Matches} -> {Res,Expansion,[#{title=>"fields", elems=>Matches, options=>[highlight_all]}]} + end. --export([expand/1, format_matches/1]). +expand_record_field_content(Field, + {attribute, _, record, + {_Record, FieldTypes}}, Word, Nestings, FT) -> + FieldTypesFiltered = [Type1 || {typed_record_field, {record_field, _, {_,_, F}}, Type1} <- FieldTypes, F == Field] ++ + [Type1 || {typed_record_field, {record_field, _, {_,_, F}, _}, Type1} <- FieldTypes, F == Field], + case FieldTypesFiltered of + [] -> {no, [], []}; + [Type] -> + T = edlin_type_suggestion:type_tree(erlang, Type, Nestings, FT), + Types = edlin_type_suggestion:get_types([], T, Nestings), + case Nestings of + [] -> + Atoms = edlin_type_suggestion:get_atoms([], T, Nestings), + case {Word, match(Word, Atoms, ", ")} of + {[],{_Res,_Expansion,_}} -> {_Res, _Expansion, [#{title=>"types", elems=>Types, options=>[{hide, title}]}]}; + {_,{_Res,_Expansion,[]}=M} -> M; + {_,{Res,Expansion,Matches}} -> {Res, Expansion, [#{title=>"matches", elems=>Matches, options=>[highlight_all]}]} + end; + _ -> + expand_nesting_content(T, [], Nestings, #{title=>"types", elems=>Types, options=>[{hide, title}]}) + end + end. + +%% Check that the actual type on previous arguments +%% matches with the expected types +%% Since we are not doing any evaluations at this point we +%% don't know if a parenthesis, keyword, var, call or fun returns +%% a value with the wrong type. +match_arguments({function, {{parameters, Ps}, _}, Cs}, As) -> + match_arguments1(Ps, Cs, As); +match_arguments({{parameters, Ps}, _}, As) -> + match_arguments1(Ps, [], As). +match_arguments1(_,_,[]) -> true; +%% Just assume that it will evaluate to the correct type. +match_arguments1([_|Ps], Cs, [{parenthesis, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([_|Ps], Cs, [{operation, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([_|Ps], Cs, [{keyword, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([_|Ps], Cs, [{var, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([_|Ps], Cs, [{call, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([_|Ps], Cs, [{fun_, _}|As]) -> + match_arguments1(Ps, Cs, As); +match_arguments1([P|Ps], Cs, [{atom, [$'|_]=String}|As]) -> + case edlin_context:odd_quotes($', lists:reverse(String)) of + true -> false; % we know that the atom is unfinished, and thus cannot match any valid atom + _ -> case is_type(P, Cs, String) of + true -> match_arguments1(Ps, Cs, As); + false -> false + end + end; +match_arguments1([P|Ps], Cs, [{_, String}|As]) -> + case is_type(P, Cs, String) of + true -> match_arguments1(Ps, Cs, As); + false -> false + end. + +is_type(Type, Cs, String) -> + {ok, A, _} = erl_scan:string(String++"."), + Types = [T || T <- edlin_type_suggestion:get_types(Cs, Type, [], [no_print]) ], + try + {ok, Term} = erl_parse:parse_term(A), + case Term of + Atom when is_atom(Atom) -> + Atoms = edlin_type_suggestion:get_atoms(Cs, Type, []), + lists:member(to_list(Atom), Atoms) orelse + lists:member(atom_to_list(Atom), Atoms) orelse + find_type(Types, [atom, node, module, 'fun']); + Tuple when is_tuple(Tuple) -> find_type(Types, [tuple]); + Map when is_map(Map) -> find_type(Types, [map]); + Binary when is_binary(Binary) -> find_type(Types, [binary]); + Float when is_float(Float) -> find_type(Types, [float]); + Integer when is_integer(Integer) -> check_integer_type(Types, Integer); + List when is_list(List), length(List) > 0 -> + find_type(Types, [list, string, nonempty_list,maybe_improper_list, nonempty_improper_list]); + List when is_list(List) -> find_type(Types, [list, string, maybe_improper_list]) + end + catch + _:_ -> + %% Types not possible to deduce with erl_parse + % If string contains variables, erl_parse:parse_term will fail, but we + % consider them valid sooo.. lets replace them with the atom var + B = [(fun({var, Anno, _}) -> {atom, Anno, var}; (Token) -> Token end)(X) || X <- A], + try + {ok, Term2} = erl_parse:parse_term(B), + case Term2 of + Tuple2 when is_tuple(Tuple2) -> find_type(Types, [tuple]); + Map2 when is_map(Map2) -> find_type(Types, [map]); + Binary2 when is_binary(Binary2) -> find_type(Types, [binary]); + List2 when is_list(List2), length(List2) > 0 -> + find_type(Types, [list, string, nonempty_list,maybe_improper_list, nonempty_improper_list]); + List2 when is_list(List2) -> find_type(Types, [list, string, maybe_improper_list]) + end + catch + _:_ -> + case A of + [{'#',_},{var,_,'Port'},{'<',_},{float,_,_},{'>',_},{dot,_}] -> find_type(Types, [port]); + [{'#',_},{var,_,'Ref'},{'<',_},{float,_,_},{'.',_},{float,_,_},{'>',_},{dot,_}] -> find_type(Types, [reference]); + [{'fun',_},{'(',_} | _] -> find_type(Types, [parameters, function, 'fun']); + [{'#',_},{var,_,'Fun'},{'<',_},{atom,_,erl_eval},{'.',_},{float,_,_},{'>',_}] -> find_type(Types, [parameters, function, 'fun']); + [{'<', _}, {float, _, _}, {'.', _}, {integer, _, _}, {'>', _}, {dot, _}] -> find_type(Types, [pid]); + [{'#', _}, {atom, _, RecordName},{'{', _}| _] -> find_type(Types, [{record, RecordName}]); + _ -> false + end + end + end. + +find_type([],_) -> false; +find_type([any|_], _) -> true; % If we find any then every type is valid +find_type([{type, any, []}|_], _) -> true; +find_type([{{parameters, _},_}|Types], ValidTypes) -> + case lists:member(parameters, ValidTypes) of + true -> true; + false -> find_type(Types, ValidTypes) + end; +find_type([{record, _}=Type|Types], ValidTypes) -> + case lists:member(Type, ValidTypes) of + true -> true; + false -> find_type(Types, ValidTypes) + end; +find_type([{Type, _}|Types], ValidTypes) -> + case lists:member(Type, ValidTypes) of + true -> true; + false -> find_type(Types, ValidTypes) + end; +find_type([{type, Type, _}|Types], ValidTypes) -> + case lists:member(Type, ValidTypes) of + true -> true; + false -> find_type(Types, ValidTypes) + end; +find_type([{type, Type, _, any}|Types], ValidTypes) -> + case lists:member(Type, ValidTypes) of + true -> true; + false -> find_type(Types, ValidTypes) + end; +find_type([_|Types], ValidTypes) -> find_type(Types, ValidTypes). + +in_range(_, []) -> false; +in_range(Integer, [{type, range, [{integer, Start}, {integer, End}]}|_]) when Start =< Integer, Integer =< End -> true; +in_range(Integer, [_|Types]) -> in_range(Integer, Types). + +check_integer_type(Types, Integer) when Integer == 0 -> find_type(Types, [integer, non_neg_integer, arity]) orelse in_range(Integer, Types); +check_integer_type(Types, Integer) when Integer < 0 -> find_type(Types, [integer, neg_integer]) orelse in_range(Integer, Types); +check_integer_type(Types, Integer) when Integer > 0 -> find_type(Types, [integer, non_neg_integer, pos_integer]) orelse in_range(Integer, Types). --import(lists, [reverse/1, prefix/2]). +add_to_last_nesting(Term, Nesting) -> + Last = lists:last(Nesting), + List = lists:droplast(Nesting), + case Last of + {tuple, Args, U} -> + List ++ [{tuple, Args ++ [Term], U}]; + {list, Args, U} -> + List ++ [{list, Args ++ [Term], U}]; + {map, F, Fs, Args, U} -> + List ++ [{map, F, Fs, Args ++ [Term], U}] + end. + +close_nesting(Nesting) -> + Last = lists:last(Nesting), + case Last of + {tuple, _Args, _} -> + "}"; + {list, _Args, _} -> + "]"; + {map, _F, _Fs, _Args, _} -> + "}" + end. +expand_function_parameter_type(Mod, MFA, FunType, Args, Unfinished, Nestings, FT) -> + TypeTree = edlin_type_suggestion:type_tree(Mod, FunType, Nestings, FT), + + {Parameters, Constraints1} = case TypeTree of + {function, {{parameters, Parameters1},_}, Constraints} -> + {Parameters1, Constraints}; + {{parameters, Parameters1},_}=_F -> + {Parameters1, []} + end, + case match_arguments(TypeTree, Args) of + false -> {no, [], []}; + true when Parameters == [] -> {yes, ")", [#{title=>MFA, elems=>[")"], options=>[]}]}; + true -> + Parameter = lists:nth(length(Args)+1, Parameters), + {T, _Name} = case Parameter of + Atom when is_atom(Atom) -> {Atom, atom_to_list(Atom)}; + {var, Name1}=T1 -> {T1, atom_to_list(Name1)}; + {ann_type, {var, Name1}, T1} -> {T1, atom_to_list(Name1)}; + T1 -> {T1, edlin_type_suggestion:print_type(T1, [], [{first_only, true}])} + end, + Ts = edlin_type_suggestion:get_types(Constraints1, T, Nestings), + Types = case Ts of + [] -> []; + _ -> + SectionTypes = [S || #{}=S <- Ts], + Types1 = case [E || {_, _}=E<-Ts] of + [] -> SectionTypes; + Elems -> + case SectionTypes of + [] -> Elems; + ST -> [#{title=>"simple types", elems=>Elems, options=>[{hide, title}]}|ST] + end + end, + + [#{title=>"types", elems=>(Types1), options=>[{hide, title}]}] + end, + case Nestings of + [] -> %% Expand function type + case Unfinished of + [] -> + case T of + Atom1 when is_atom(Atom1) -> + CC = case length(Args)+1 < length(Parameters) of + true -> ", "; + false ->")" + end, + {Res, Expansion, Matches} = match([], [Atom1], CC), + case Matches of + [] -> {no, [], []}; + _ -> {Res, Expansion, [#{title=>MFA, elems=>[], options=>[{highlight_param, length(Args)+1}]}]} + end; + _ when Types == [] -> + {no, [], []}; + _ -> + {no, [], [#{title=>MFA, elems=>Types, options=>[{highlight_param, length(Args)+1}]}]} + end; + {_, Word} when is_atom(T) -> + CC = case length(Args)+1 < length(Parameters) of + true -> ", "; + false ->")" + end, + {Res, Expansion, Matches} = match(Word, [T], CC), + case Matches of + [] -> {no, [], []}; + _ -> {Res, Expansion, [#{title=>MFA, elems=>[], options=>[{highlight_param, length(Args)+1}]}]} + end; + {_, Word} -> + {Res, Expansion, Matches} = begin + CC = case length(Args)+1 < length(Parameters) of + true -> ", "; + false ->")" + end, + Atoms1 = edlin_type_suggestion:get_atoms(Constraints1, T, Nestings), + {Res1, Expansion1, Matches1} = match(Word, Atoms1, CC), + case Matches1 of + [] -> + case match_arguments(TypeTree, Args ++ [Unfinished]) of + false -> {Res1, Expansion1, Matches1}; + true -> + {yes, CC, [{CC, []}]} + end; + _ -> + {Res1, Expansion1, Matches1} + end + end, + Match1 = case Matches of + [] -> []; + _ -> Atoms = [#{title=>"atoms", elems=>Matches, options=>[{hide, title}]}], + [#{title=>MFA, elems=>Atoms, options=>[{highlight_param, length(Args)+1}]}] + end, + {Res, Expansion,Match1} + end; + _ -> %% Expand last nesting types + expand_nesting_content(T, Constraints1, Nestings, #{title=>MFA, elems=>Types, options=>[{highlight_param, length(Args)+1}]}) + end + end. +expand_nesting_content(T, Constraints, Nestings, Section) -> + {NestingType, UnfinishedNestingArg, NestingArgs} = case lists:last(Nestings) of + {tuple, NestingArgs1, Unfinished1} -> {tuple, Unfinished1, NestingArgs1}; + {list, NestingArgs1, Unfinished1} -> {list, Unfinished1, NestingArgs1}; + {map, _, _, NestingArgs1, Unfinished1} -> {map, Unfinished1, NestingArgs1} + end, + %% in the case of + %% erlang:system_info({allocator, ) + %% we have a tuple nesting with an atom + %% this should give us "allocator" in the nestingsargs, and empty unfinished part + %% but we also know that we have a nesting, if we expect something other than a tuple, we shouldnt print that function + %% lets call it NestingType + %% now when that is fixed, how do we filter {allocator_sizes, ...} and others + Types = [Ts || Ts <- edlin_type_suggestion:get_types(Constraints, T, lists:droplast(Nestings), [no_print]) ], + case UnfinishedNestingArg of + [] -> + case find_type(Types, [NestingType]) of + true -> + %% if we know had a tuple, {allocator_sizes, } will be allowed + %% probably get_arity will return none + Nestings2 = add_to_last_nesting({var, "Var"}, Nestings), + NestingArities = edlin_type_suggestion:get_arity(Constraints, T, Nestings2), + + fold_results([begin + case NestingArity of + none -> {no, [], []}; + _ -> {no, [], [Section]} + end + end || NestingArity <- NestingArities]); + false -> {no, [], []} + end; + {_, Word} -> + Atoms1 = edlin_type_suggestion:get_atoms(Constraints, T, Nestings), + {Res1, Expansion1, Matches1} = match(Word, Atoms1, ""), + {Res, Expansion, Matches} = case Matches1 of + [] -> + Nestings2 = add_to_last_nesting(UnfinishedNestingArg, Nestings), + NestingArities = edlin_type_suggestion:get_arity(Constraints, T, Nestings2), + fold_results([begin + case NestingArity of + none -> {no, [], []}; + _ when NestingType =:= tuple -> + CC = case length(NestingArgs)+1 < NestingArity of + true -> ", "; + false -> close_nesting(Nestings) + end, + {yes, CC, [{CC, []}]}; + _ when NestingType =:= list -> + {no, [], [{", ", []}, {"]", []}]}; + _ when NestingType =:= map -> + {no, [], [{", ",[]},{"}", []}]}; + _ -> + {no, [], []} + end + end || NestingArity <- NestingArities]); + [{Word2,_}] -> + Nestings2 = add_to_last_nesting({atom, Word2}, Nestings), + NestingArities = edlin_type_suggestion:get_arity(Constraints, T, Nestings2), + fold_results([begin + case NestingArity of + none -> {no, [], []}; + _ when NestingType =:= tuple -> + CC = case length(NestingArgs)+1 < NestingArity of + true -> ", "; + false -> close_nesting(Nestings) + end, + {yes, Expansion1++CC, [{Word2, [{ending, CC}]}]}; + _ -> + {Res1, Expansion1, Matches1} + end + end || NestingArity <- NestingArities]); + _ -> {Res1, Expansion1, Matches1} + end, + Match1 = case Matches of + [] -> []; + _ -> Atoms = [#{title=>"atoms", elems=>Matches, options=>[{hide, title}]}], + [Section#{elems:=Atoms}] + end, + {Res, Expansion, Match1} + end. + +extract_record_fields(Record, {attribute,_,record,{Record, Fields}})-> + [X || X <- [extract_record_field(F) || F <- Fields], X /= []]; +extract_record_fields(_, _)-> error. +extract_record_field({typed_record_field, {_, _,{atom, _, Field}},_})-> + Field; +extract_record_field({typed_record_field, {_, _,{atom, _, Field}, _},_})-> + Field; +extract_record_field({record_field, _,{atom, _, Field},_})-> + Field; +extract_record_field({record_field, _,{atom, _, Field}})-> + Field; +extract_record_field(_) -> []. + +fold_results([]) -> {no, [], []}; +fold_results([R|Results]) -> + lists:foldl(fun fold_completion_result/2, R, Results). + +fold_completion_result({yes, Cmp1, Matches1}, {yes, Cmp2, Matches2}) -> + {_, Cmp} = longest_common_head([Cmp1,Cmp2]), + case Cmp of + [] -> {no, [], ordsets:union([Matches1,Matches2])}; + _ -> {yes, Cmp, ordsets:union([Matches1,Matches2])} + end; +fold_completion_result({yes, Cmp, Matches}, {no, [], []}) -> + {yes, Cmp, Matches}; +fold_completion_result({no, [], []},{yes, Cmp, Matches}) -> + {yes, Cmp, Matches}; +fold_completion_result({_, _, Matches1}, {_, [], Matches2}) -> + {no, [], ordsets:union([Matches1,Matches2])}; +fold_completion_result(A, B) -> + fold_completion_result(B,A). + +expand_function_type(ModStr, FunStr, Args, Unfinished, Nestings, FT) -> + Mod = list_to_atom(ModStr), + Fun = list_to_atom(FunStr), + MinArity = if Unfinished =:= [], length(Args) =:= 0 -> 0; + true -> length(Args)+1 + end, + case [A || A <- get_arities(ModStr, FunStr, FT), A >= MinArity] of + [] -> {no, [], []}; + Arities -> + {Res, Expansion, Matches} = fold_results([begin + FunTypes = edlin_type_suggestion:get_function_type(Mod, Fun, Arity, FT), + case FunTypes of + [] -> MFA = print_function_head(ModStr, FunStr, Arity), + case Unfinished of + [] -> {no, [], [#{title=>MFA, elems=>[], options=>[]}]}; + _ -> {no, [], []} + end; + _ -> + fold_results([begin + MFA = print_function_head(ModStr, FunStr, FunType, FT), + expand_function_parameter_type(Mod, MFA, FunType, Args, Unfinished, Nestings, FT) + end || FunType <- FunTypes]) + end + end || Arity <- Arities]), + case Matches of + [] -> {Res, Expansion, Matches}; + _ -> {Res, Expansion, [#{title=>"typespecs", elems=>Matches, options=>[highlight_all]}]} + end + end. -%% expand(CurrentBefore) -> -%% {yes, Expansion, Matches} | {no, Matches} +%% Behaves like zsh +%% filters all files starting with . unless Word starts with . +%% outputs / on end of folders +expand_filepath(PathPrefix, Word) -> + Path = case PathPrefix of + [$/|_] -> PathPrefix; + _ -> + {ok, Cwd} = file:get_cwd(), + Cwd ++ "/" ++ PathPrefix + end, + ShowHidden = case Word of + "." ++ _ -> true; + _ -> false + end, + Entries = case file:list_dir(Path) of + {ok, E} -> lists:map( + fun(X)-> + case filelib:is_dir(Path ++ "/" ++ X) of + true -> X ++ "/"; + false -> X + end + end, [".."|E]); + _ -> [] + end, + EntriesFiltered = [File || File <- Entries, + case File of + [$.|_] -> ShowHidden; + _ -> true + end], + case match(Word, EntriesFiltered, []) of + {yes, Cmp, [Match]} -> + case filelib:is_dir(Path ++ "/" ++ Word ++ Cmp) of + true -> {yes, Cmp, [Match]}; + false -> {yes, Cmp ++ "\"", [Match]} + end; + X -> X + end. + +shell(Fun) -> + case shell:local_func(list_to_atom(Fun)) of + true -> "shell"; + false -> "user_defined" + end. + +shell_default_or_bif(Fun) -> + case lists:member(list_to_atom(Fun), [E || {E,_}<-get_exports(shell_default)]) of + true -> "shell_default"; + _ -> bif(Fun) + end. +bif(Fun) -> + case lists:member(list_to_atom(Fun), [E || {E,A}<-get_exports(erlang), erl_internal:bif(E,A)]) of + true -> "erlang"; + _ -> shell(Fun) + end. + +expand_string(Bef0) -> + case over_filepath(Bef0, []) of + {_, Filepath} -> + {Path, File} = split_at_last_slash(Filepath), + expand_filepath(Path, File); + _ -> {no, [], []} + end. +%% Extract a whole filepath +%% Stops as soon as we hit a double quote (") +%% and returns everything it found before stopping. +%% assumes the string is not a filepath if it contains unescaped spaces +over_filepath([],_) -> none; +over_filepath([$", $\\|Bef1], Filepath) -> over_filepath(Bef1, [$" | Filepath]); +over_filepath([$"|Bef1], Filepath) -> {Bef1, Filepath}; +over_filepath([$\ ,$\\|Bef1], Filepath) -> over_filepath(Bef1, [$\ |Filepath]); +over_filepath([$\ |_], _) -> none; +over_filepath([C|Bef1], Filepath) -> + over_filepath(Bef1, [C|Filepath]). +split_at_last_slash(Filepath) -> + {File, Path} = lists:splitwith(fun(X)->X/=$/ end, lists:reverse(Filepath)), + {lists:reverse(Path), lists:reverse(File)}. + +print_function_head(ModStr, FunStr, Arity) -> + lists:flatten(ModStr ++ ":" ++ FunStr ++ "/" ++ integer_to_list(Arity)). +print_function_head(ModStr, FunStr, FunType, FT) -> + lists:flatten(print_function_head_from_type(ModStr, FunStr, FunType, FT)). + +print_function_head1(Mod, Fun, Par, _Ret) -> + Mod++":"++Fun++"("++lists:join(", ", + [case P of + Atom when is_atom(Atom) -> atom_to_list(Atom); + {var, V} -> atom_to_list(V); + {ann_type, {var, V}, _T} -> atom_to_list(V); + T -> edlin_type_suggestion:print_type(T, [], [{first_only, true}]) + end || {_N,P} <- lists:enumerate(Par)])++")". +print_function_head_from_type(Mod, Fun, FunType, FT) -> + case edlin_type_suggestion:type_tree(list_to_atom(Mod), FunType, [], FT) of + {function, {{parameters, Parameters},{return, Return}}, _} -> + print_function_head1(Mod, Fun, Parameters, Return); + {{parameters, Parameters},{return, Return}} -> + print_function_head1(Mod, Fun, Parameters, Return) + end. + +%% expand_module_function(CurrentBefore, FT) -> {yes, Expansion, Matches} | {no, [], Matches} %% Try to expand the word before as either a module name or a function %% name. We can handle white space around the seperating ':' but the %% function name must be on the same line. CurrentBefore is reversed %% and over_word/3 reverses the characters it finds. In certain cases -%% possible expansions are printed. +%% possible expansions are printed.´´´ %% -%% The function also handles expansion with "h(" for module and functions. -expand(Bef0) -> +%% The function also handles expansion with "h(" and "ht("" for module and functions. +expand_module_function(Bef0, FT) -> {Bef1,Word,_} = edlin:over_word(Bef0, [], 0), case over_white(Bef1, [], 0) of {[$,|Bef2],_White,_Nwh} -> - {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), - {Bef4,Mod,_Nm} = edlin:over_word(Bef3, [], 0), + {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), + {Bef4,Mod,_Nm} = edlin:over_word(Bef3, [], 0), case expand_function(Bef4) of help -> - expand_function_name(Mod, Word, ","); + expand_function_name(Mod, Word, ", ", FT); + help_type -> + expand_type_name(Mod, Word, ", "); _ -> - expand_module_name(Word, ",") + fold_results(expand_helper(FT, module, Word, ":")) end; {[$:|Bef2],_White,_Nwh} -> - {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), - {_,Mod,_Nm} = edlin:over_word(Bef3, [], 0), - expand_function_name(Mod, Word, "("); - {_,_,_} -> + {Bef3,_White1,_Nwh1} = over_white(Bef2, [], 0), + {_,Mod,_Nm} = edlin:over_word(Bef3, [], 0), + expand_function_name(Mod, Word, "(", FT); + {[CC, N_Esc|_], _White, _Nwh} when (CC =:= $] orelse CC =:= $) orelse CC =:= $> orelse CC =:= $} + orelse CC =:= $" orelse CC =:= $'), + N_Esc =/= $$, N_Esc =/= $- -> + {no, [], []}; + {[], _, _} -> + case Word of + [] -> {no, [], []}; %fold_results([expand_shell_default(Word), expand_user_defined_functions(FT, Word)]); + _ -> fold_results(expand_helper(FT, all, Word, ":")) + end; + {_,_,_} -> + case Word of + [] -> {no, [], []}; + _ -> + TypeOfExpand = expand_function(Bef1), CompleteChar - = case expand_function(Bef1) of - help -> ","; + = case TypeOfExpand of + help -> ", "; + help_type -> ", "; _ -> ":" end, - expand_module_name(Word, CompleteChar) + fold_results(expand_helper(FT, TypeOfExpand, Word, CompleteChar)) + end end. - +expand_keyword(Word) -> + Keywords = ["begin", "case", "of", "receive", "after", "maybe", "try", "catch", "throw", "if", "fun", "when", "end"], + {Res, Expansion, Matches} = match(Word, Keywords, ""), + case Matches of + [] -> {no, [], []}; + [{Word, _}] -> {no, [], []}; %% exact match + _ -> {Res,Expansion,[#{title=>"keywords", elems=>Matches, options=>[highlight_all]}]} + end. +expand_helper(_, help, Word, CompleteChar) -> + [expand_module_name(Word, CompleteChar)]; +expand_helper(_, help_type, Word, CompleteChar) -> + [expand_module_name(Word, CompleteChar)]; +expand_helper(FT, all, Word, CompleteChar) -> + [expand_module_name(Word, CompleteChar), expand_bifs(Word), expand_shell_default(Word), + expand_user_defined_functions(FT, Word), expand_keyword(Word)]; +expand_helper(FT, _, Word, CompleteChar) -> + [expand_module_name(Word, CompleteChar), expand_bifs(Word), + expand_user_defined_functions(FT, Word), expand_keyword(Word)]. expand_function("("++Str) -> case edlin:over_word(Str, [], 0) of {_,"h",_} -> @@ -71,68 +808,157 @@ expand_function("("++Str) -> expand_function(_) -> module. +expand_bifs(Prefix) -> + Alts = [EA || {E,A}=EA <- get_exports(erlang), erl_internal:bif(E,A)], + CC = "(", + case match(Prefix, Alts, CC) of + {_Res,_Expansion,[]}=M -> M; + {Res,Expansion, Matches} -> {Res,Expansion,[#{title=>"bifs", elems=>Matches, options=>[highlight_all]}]} + end. + +expand_shell_default(Prefix) -> + Alts = get_exports(shell_default) ++ shell:local_func(), + CC = "(", + case match(Prefix, Alts, CC) of + {_Res,_Expansion,[]}=M -> M; + {Res,Expansion, Matches} -> {Res,Expansion,[#{title=>"commands",elems=>Matches, options=>[highlight_all]}]} + end. + +expand_user_defined_functions(FT, Prefix) -> + Alts = [{Name, Arity}||{{function, {_, Name, Arity}}, _} <- FT], + CC = "(", + case match(Prefix, Alts, CC) of + {_Res,_Expansion,[]}=M -> M; + {Res,Expansion, Matches} -> {Res,Expansion,[#{title=>"user_defined", elems=>Matches, options=>[highlight_all]}]} + end. + expand_module_name("",_) -> {no, [], []}; -expand_module_name(Prefix,CompleteChar) -> - match(Prefix, [{list_to_atom(M),P} || {M,P,_} <- code:all_available()], CompleteChar). +expand_module_name(Prefix,CC) -> + Alts = [{list_to_atom(M),""} || {M,_,_} <- code:all_available()], + case match(Prefix, Alts, CC) of + {_Res,_Expansion,[]}=M -> M; + {Res,Expansion, Matches} -> {Res,Expansion,[#{title=>"modules", elems=>Matches, options=>[highlight_all]}]} + end. -expand_function_name(ModStr, FuncPrefix, CompleteChar) -> +get_arities("shell_default"=ModStr, FuncStr, FT) -> + case [A || {{function, {_, Fun, A}}, _} <- FT, Fun =:= list_to_atom(FuncStr)] of + [] -> get_arities(ModStr, FuncStr); + Arities -> Arities + end; +get_arities(ModStr, FuncStr, _) -> + get_arities(ModStr, FuncStr). +get_arities(ModStr, FuncStr) -> case to_atom(ModStr) of - {ok, Mod} -> - Exports = - case erlang:module_loaded(Mod) of - true -> - Mod:module_info(exports); - false -> - case beam_lib:chunks(code:which(Mod), [exports]) of - {ok, {Mod, [{exports,E}]}} -> - E; - _ -> - {no, [], []} - end - end, - case Exports of + {ok, Mod} -> + Exports = get_exports(Mod), + lists:sort( + [A || {H, A} <- Exports, string:equal(FuncStr, flat_write(H))]); + error -> + {no, [], []} + end. + +get_exports(Mod) -> + case erlang:module_loaded(Mod) of + true -> + Mod:module_info(exports); + false -> + case beam_lib:chunks(code:which(Mod), [exports]) of + {ok, {Mod, [{exports,E}]}} -> + E; + _ -> + [] + end + end. + +expand_function_name(ModStr, FuncPrefix, CompleteChar, FT) -> + case to_atom(ModStr) of + {ok, Mod} -> + Extra = case Mod of + shell_default -> [{Name, Arity}||{{function, {_, Name, Arity}}, _} <- FT]; + _ -> [] + end, + Exports = get_exports(Mod) ++ Extra, + {Res, Expansion, Matches}=Result = match(FuncPrefix, Exports, CompleteChar), + case Matches of + [] -> Result; + _ -> {Res, Expansion, [#{title=>"functions", elems=>Matches, options=>[highlight_all]}]} + end; + error -> + {no, [], []} + end. + +get_module_types(Mod) -> + case code:get_doc(Mod, #{sources => [debug_info]}) of + {ok, #docs_v1{ docs = Docs } } -> + [{T, A} || {{type, T, A},_Anno,_Sig,_Doc,_Meta} <- Docs]; + _ -> {no, [], []} + end. + +expand_type_name(ModStr, TypePrefix, CompleteChar) -> + case to_atom(ModStr) of + {ok, Mod} -> + case get_module_types(Mod) of {no, [], []} -> {no, [], []}; - Exports -> - match(FuncPrefix, Exports, CompleteChar) + Types -> + {Res, Expansion, Matches}=Result = match(TypePrefix, Types, CompleteChar), + case Matches of + [] -> Result; + _ -> {Res, Expansion, [#{title=>"types", elems=>Matches, options=>[highlight_all]}]} + end end; - error -> - {no, [], []} + error -> + {no, [], []} end. -%% if it's a quoted atom, atom_to_list/1 will do the wrong thing. to_atom(Str) -> case erl_scan:string(Str) of - {ok, [{atom,_,A}], _} -> - {ok, A}; - _ -> - error + {ok, [{atom,_,A}], _} -> + {ok, A}; + _ -> + error end. +to_list(Atom) -> + io_lib:write_atom(Atom). + +strip_quotes(Atom) -> + [C || C<-atom_to_list(Atom), C/=$']. + +match_preprocess_alt({_,_}=Alt) -> Alt; +match_preprocess_alt(X) -> {X, ""}. + match(Prefix, Alts, Extra0) -> + Alts2 = [match_preprocess_alt(A) || A <- Alts], Len = string:length(Prefix), Matches = lists:sort( - [{S, A} || {H, A} <- Alts, - prefix(Prefix, S=flat_write(H))]), + [{S, A} || {H, A} <- Alts2, + lists:prefix(Prefix, S=flat_write(H))]), + Matches2 = lists:usort( + case Extra0 of + [] -> [{S,[]} || {S,_} <- Matches]; + _ -> [{S,[{ending, Extra0}]} || {S,_} <- Matches] + end), case longest_common_head([N || {N, _} <- Matches]) of - {partial, []} -> - {no, [], Matches}; % format_matches(Matches)}; - {partial, Str} -> + {partial, []} -> + {no, [], Matches2}; + {partial, Str} -> case string:slice(Str, Len) of - [] -> - {yes, [], Matches}; % format_matches(Matches)}; - Remain -> - {yes, Remain, []} - end; - {complete, Str} -> - Extra = case {Extra0,Matches} of - {"(",[{Str,0}]} -> "()"; - {_,_} -> Extra0 - end, - {yes, string:slice(Str, Len) ++ Extra, []}; - no -> - {no, [], []} + [] -> + {yes, [], Matches2}; + Remain -> + {yes, Remain, Matches2} + end; + {complete, Str} -> + Extra = case {Extra0,Matches} of + {"/",[{Str,N}]} when is_integer(N) -> "/"++integer_to_list(N); + {"(",[{Str,0}]} -> "()"; + {_,_} -> Extra0 + end, + {yes, string:slice(Str, Len) ++ Extra, ordsets:from_list(Matches2)}; + no -> + {no, [], []} end. flat_write(T) when is_atom(T) -> @@ -140,79 +966,198 @@ flat_write(T) when is_atom(T) -> flat_write(S) -> S. -%% Return the list of names L in multiple columns. -format_matches(L) -> - {S1, Dots} = format_col(lists:sort(L), []), - S = case Dots of - true -> - {_, Prefix} = longest_common_head(vals(L)), - PrefixLen = string:length(Prefix), - case PrefixLen =< 3 of - true -> S1; % Do not replace the prefix with "...". - false -> - LeadingDotsL = leading_dots(L, PrefixLen), - {S2, _} = format_col(lists:sort(LeadingDotsL), []), - S2 - end; - false -> S1 +special_sort1([C|A], B) when C == ${ ; C == $. ; C == $# -> + special_sort1(A, B); +special_sort1(A, [C|B]) when C == ${ ; C == $. ; C == $# -> + special_sort1(A,B); +special_sort1(A,B) -> + string:lowercase(A) =< string:lowercase(B). +special_sort(#{title:=A}, #{title:=B}) -> + special_sort1(A,B); +%% Sections and elemts should not be in the same list +special_sort(#{}, {}) -> + error; +special_sort({}, #{}) -> + error; +special_sort({A,_},{B,_}) -> + special_sort1(A,B); +special_sort(A,B) -> + special_sort1(A,B). + +to_legacy_format([]) -> []; +to_legacy_format([#{title:=Title}|Rest]) when Title =:= "commands"; Title =:= "bifs" -> + to_legacy_format(Rest); +to_legacy_format([#{title:=Title, elems:=Elems}|Rest]) + when Title =:= "modules"; Title =:= "functions"; Title =:= "bindings"; + Title =:= "user_defined", Title =:= "records"; Title =:= "fields"; + Title =:= "types"; Title =:= "atoms"; Title =:= "matches"; + Title =:= "keywords"; Title =:= "typespecs" -> + Elems1 = to_legacy_format(Elems), + Elems1 ++ to_legacy_format(Rest); +to_legacy_format([#{title:=Title, elems:=_Elems}|Rest]) -> + [Title] ++ to_legacy_format(Rest); +to_legacy_format([{Val, _}|Rest]) -> + [{Val, ""}] ++ to_legacy_format(Rest). + +format_matches([], _LineWidth) -> []; +format_matches([#{}|_]=FF, LineWidth) -> + %% Group function head that have the exact same Type suggestion + Groups = maps:groups_from_list( + fun(#{title:=Title, elems:=T, options:=Opts}) -> + Separator = proplists:get_value(separator, Opts, "\n"), + case lists:last(string:split(Title++Separator, "\n", all)) of + [] -> format_section_matches(T, LineWidth); + Chars -> %% we have chars that compete with the results on the first line + Len = length(Chars), + format_section_matches(T, LineWidth, Len) + end + end, + fun(F) -> + format_title(F, LineWidth) + end, FF), + S = lists:flatten( + [lists:join("", F)++Matches || + {Matches, F}<-lists:sort(fun({_,A},{_,B}) -> A =< B end, maps:to_list(Groups))]), + lists:flatten(string:trim(S, trailing)++"\n"); +format_matches(Elems, LineWidth) -> + S = format_section_matches1(Elems, LineWidth, 0), + lists:flatten(string:trim(S, trailing)++"\n"). +format_title(#{title:=MFA, options:=Options}, _LineWidth) -> + case proplists:get_value(hide, Options) of + title -> ""; + _ -> + Separator = proplists:get_value(separator, Options, "\n"), + HighlightAll = proplists:is_defined(highlight_all, Options), + case HighlightAll of + true -> "\033[;1;4m"++MFA++"\033[0m"++Separator; + _ -> + HighlightParam = proplists:get_value(highlight_param, Options, false), + + MFA2 = case HighlightParam of + false -> MFA; + _ -> + PreviousParams = HighlightParam -1, + TuplePattern = "(?:\\{[^\\}]+\\})", + AtomVarPattern = "(?:\\w+)", + TypePattern="(?:(?:"++AtomVarPattern++":)?(?:"++AtomVarPattern++"\\(\\))(?:\\s[><=]+\\s\\d+)?)", + SimplePatterns = "(?:"++TuplePattern++"|"++TypePattern++"|"++AtomVarPattern++")", + UnionPattern = "(?:"++SimplePatterns++"(?:\\s\\|\\s"++SimplePatterns++")*)", + FunPattern="(?:fun\\(\\(" ++ UnionPattern ++ "\\)\\s*->\\s*" ++ UnionPattern ++ "\\))", + ArgPattern3 = "(?:"++FunPattern++"|"++UnionPattern++")", + PrevArgs="(?:"++ArgPattern3++",\\s){"++integer_to_list(PreviousParams) ++ "}", + FunctionHeadStart="^([^\\(]+\\("++PrevArgs++")", %% \\1 + + HighlightArg="("++ArgPattern3++")", %\\2 + NextArgs="(?:,\\s"++ArgPattern3++")*", + FunctionHeadEnd="("++NextArgs++"\\)(?:.*))$", % \\3 + + re:replace(MFA, + FunctionHeadStart ++ HighlightArg ++ FunctionHeadEnd, + "\\1\033[;1;4m\\2\033[0m\\3", + [global, {return, list}, unicode]) + end, + Highlight = proplists:get_value(highlight, Options, false), + case Highlight of + false -> MFA2; + _ -> re:replace(MFA2, "(\\Q"++Highlight++"\\E)", "\033[;1;4m\\1\033[0m", [global, {return, list}, unicode]) + end ++ Separator + end + end; +format_title(_Elems, _LineWidth) -> + %% not a section, old interface + %% output empty list + "". + +format_section_matches(LS, LineWidth) -> format_section_matches(LS, LineWidth, 0). +format_section_matches([], _, _) -> "\n"; +format_section_matches([#{}|_]=FF, LineWidth, Acc) -> + Groups = maps:groups_from_list( + fun(#{title:=Title, elems:=T, options:=Opts}) -> + Separator = proplists:get_value(separator, Opts, "\n"), + case lists:last(string:split(Title++Separator, "\n", trailing)) of + [] -> format_section_matches(T, LineWidth); + Chars -> %% we have chars that compete with the results on the first line + Len = string:length(Chars), + format_section_matches(T, LineWidth, Len+Acc) + end end, - ["\n" | S]. + fun(F) -> + format_title(F, LineWidth) + end, FF), + lists:flatten( + [lists:join("", F)++Matches || + {Matches, F}<-lists:sort(fun({_,A},{_,B}) -> A =< B end, maps:to_list(Groups))]); +format_section_matches(Elems, LineWidth, Acc) -> + format_section_matches1(Elems, LineWidth, Acc). -format_col([], _) -> []; -format_col(L, Acc) -> - LL = 79, - format_col(L, field_width(L, LL), 0, Acc, LL, false). +format_section_matches1([], _, _) -> []; +format_section_matches1(LS, LineWidth, Len) -> + L = lists:usort(fun special_sort/2, ordsets:to_list(LS)), + Opt = case Len == 0 of + true -> []; + false -> [{title, Len}] + end, + S1 = format_col(Opt ++ L, field_width(Opt ++ L, LineWidth), Len, [], LineWidth, Opt), + S2 = lists:map( + fun(Line) -> + case string:length(Line) of + Len1 when Len1 > LineWidth -> + string:sub_string(Line, 1, LineWidth-4) ++ "...\n"; + _ -> Line + end + end,S1), + lists:flatten(string:trim(S2, trailing)++"\n"). -format_col(X, Width, Len, Acc, LL, Dots) when Width + Len > LL -> - format_col(X, Width, 0, ["\n" | Acc], LL, Dots); -format_col([A|T], Width, Len, Acc0, LL, Dots) -> +format_col(X, Width, Len, Acc, LL, Opt) when Width + Len > LL -> + format_col(X, Width, 0, ["\n" | Acc], LL, Opt); +format_col([{title,TitleLen}|T], Width, Len, Acc0, LL, Opt) -> + Acc = [io_lib:format("~-*ts", [Width-TitleLen, ""])|Acc0], + format_col(T, Width, Len+Width, Acc, LL, Opt); +format_col([A|T], Width, Len, Acc0, LL, _Opt) -> {H0, R} = format_val(A), - Hmax = LL - length(R), - {H, NewDots} = + Hmax = LL - string:length(R), + {H, _} = case string:length(H0) > Hmax of true -> {io_lib:format("~-*ts", [Hmax - 3, H0]) ++ "...", true}; - false -> {H0, Dots} + false -> {H0, false} end, Acc = [io_lib:format("~-*ts", [Width, H ++ R]) | Acc0], - format_col(T, Width, Len+Width, Acc, LL, NewDots); -format_col([], _, _, Acc, _LL, Dots) -> - {lists:reverse(Acc, "\n"), Dots}. + format_col(T, Width, Len+Width, Acc, LL, []); +format_col([], _, _, Acc, _LL, _Opt) -> + lists:reverse(Acc). +format_val({H, L}) when is_list(L) -> + {H, proplists:get_value(ending, L, "")}; format_val({H, I}) when is_integer(I) -> - %% If it's a tuple {string(), integer()}, we assume it's an - %% arity, and meant to be printed. - {H, "/" ++ integer_to_list(I)}; + {H, "/"++integer_to_list(I)}; format_val({H, _}) -> {H, ""}; format_val(H) -> {H, ""}. field_width(L, LL) -> field_width(L, 0, LL). - -field_width([{H,_}|T], W, LL) -> - case string:length(H) of +field_width([{title, Len}|T], W, LL) -> + case Len of L when L > W -> field_width(T, L, LL); _ -> field_width(T, W, LL) end; field_width([H|T], W, LL) -> - case string:length(H) of + {H1, Ending} = format_val(H), + case string:length(H1++Ending) of L when L > W -> field_width(T, L, LL); _ -> field_width(T, W, LL) end; -field_width([], W, LL) when W < LL - 3 -> +field_width([], W, LL) when W < LL -> W + 4; field_width([], _, LL) -> LL. -vals([]) -> []; -vals([{S, _}|L]) -> [S|vals(L)]; -vals([S|L]) -> [S|vals(L)]. - -leading_dots([], _Len) -> []; -leading_dots([{H, I}|L], Len) -> - [{"..." ++ string:slice(H, Len), I}|leading_dots(L, Len)]; -leading_dots([H|L], Len) -> - ["..." ++ string:slice(H, Len)|leading_dots(L, Len)]. +number_matches([#{ elems := Matches }|T]) -> + number_matches(Matches) + number_matches(T); +number_matches([_|T]) -> + 1 + number_matches(T); +number_matches([]) -> + 0. %% Strings are handled naively, but it should be OK here. longest_common_head([]) -> @@ -221,24 +1166,23 @@ longest_common_head(LL) -> longest_common_head(LL, []). longest_common_head([[]|_], L) -> - {partial, reverse(L)}; + {partial, lists:reverse(L)}; longest_common_head(LL, L) -> case same_head(LL) of - true -> - [[H|_]|_] = LL, - LL1 = all_tails(LL), - case all_nil(LL1) of - false -> - longest_common_head(LL1, [H|L]); - true -> - {complete, reverse([H|L])} - end; - false -> - {partial, reverse(L)} + true -> + [[H|_]|_] = LL, + LL1 = all_tails(LL), + case all_nil(LL1) of + false -> + longest_common_head(LL1, [H|L]); + true -> + {complete, lists:reverse([H|L])} + end; + false -> + {partial, lists:reverse(L)} end. same_head([[H|_]|T1]) -> same_head(H, T1). - same_head(H, [[H|_]|T]) -> same_head(H, T); same_head(_, []) -> true; same_head(_, _) -> false. diff --git a/lib/stdlib/src/edlin_key.erl b/lib/stdlib/src/edlin_key.erl new file mode 100644 index 000000000000..7a9b0eaa2748 --- /dev/null +++ b/lib/stdlib/src/edlin_key.erl @@ -0,0 +1,358 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017-2023. 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(edlin_key). +-export([get_key_map/0, get_valid_escape_key/2]). +-import(lists, [reverse/1, reverse/2]). +get_key_map() -> + KeyMap = application:get_env(stdlib, shell_keymap, none), + case KeyMap of + none -> key_map(); + _ -> merge(KeyMap) + end. + +%% Incase we are receiving partial input, we need to wait for the rest of the input. +%% We return a mode whenever we are waiting for more input. +get_valid_escape_key([], {csi, [_]=Acc}=_Mode) -> + %% we allow \e[1, \e[2... to be a valid escape sequences + %% note that this blocks [1;... inputed one character at a time + {key, "\e["++Acc, []}; +get_valid_escape_key([], Res) -> + case Res of + {Atom, Acc, Rest} -> + case Atom of + finished -> {key, Acc, Rest}; + invalid -> {invalid, Acc, Rest} + end; + {Atom, Acc} -> + case Atom of + finished -> {key, Acc, []}; + invalid -> {invalid, Acc, []}; + csi -> {mode, {csi, Acc}} + end; + meta -> {escape_prefix, meta}; + meta_o -> {key,"\eO", []}; + meta_meta -> {escape_prefix, meta_meta}; + meta_csi -> {escape_prefix, meta_csi}; + meta_left_sq_bracket -> {escape_prefix, meta_left_sq_bracket} + end; +get_valid_escape_key([C|Rest], none) -> + case C of + $\e -> get_valid_escape_key(Rest,meta); + C when $\^@ =< C, C =< $\^_; C =:= $\^? -> {key, [C], Rest}; + _ -> {insert, C, Rest} + end; +get_valid_escape_key([C|Rest], meta) -> + case C of + $\e -> get_valid_escape_key(Rest, meta_meta); + $O -> get_valid_escape_key(Rest, meta_o); + $[ -> get_valid_escape_key(Rest, meta_left_sq_bracket); + _ when $! =< C, C =< $~ -> get_valid_escape_key(Rest, {finished, "\e"++[C]}); + _ when $\^@ =< C, C =< $\^_; C=:= $\^? -> get_valid_escape_key(Rest, {finished, "\e"++[C]}); + _ -> get_valid_escape_key(Rest, {invalid, "\e"++[C]}) + end; +get_valid_escape_key([C|Rest], meta_meta) -> + case C of + $[ -> get_valid_escape_key(Rest, meta_csi); + _ when $! =< C, C =< $~ -> get_valid_escape_key(Rest, {finished, "\e\e"++[C]}); + _ -> get_valid_escape_key(Rest, {invalid, "\e\e"++[C]}) + end; +get_valid_escape_key([C|Rest], meta_o) -> + case C of + _ when $! =< C, C =< $~ -> get_valid_escape_key(Rest, {finished, "\eO"++[C]}); + _ -> get_valid_escape_key(Rest, {invalid, "\eO"++[C]}) + end; +get_valid_escape_key([C|Rest], meta_csi) -> + case C of + _ when $! =< C, C =< $~ -> get_valid_escape_key(Rest, {finished, "\e\e["++[C]}); + _ -> get_valid_escape_key(Rest, {invalid, "\e["++[C]}) + end; +get_valid_escape_key([C|Rest], meta_left_sq_bracket) -> + case C of + _ when $0 =< C, C =< $9 -> get_valid_escape_key(Rest, {csi, [C]}); + _ when $a =< C, C =< $z; $A =< C, C =< $Z -> get_valid_escape_key(Rest, {finished, "\e["++[C]}); + _ -> get_valid_escape_key(Rest, {invalid, "\e["++[C]}) + end; +get_valid_escape_key([C|Rest], {csi, [$;|Acc]}) -> + case C of + _ when $0 =< C, C =< $9 -> get_valid_escape_key(Rest, {csi, [C,$;|Acc]}); + _ -> get_valid_escape_key(Rest, {invalid, "\e["++reverse([$;|Acc])++[C]}) + end; +get_valid_escape_key([C|Rest], {csi, Acc}) -> + case C of + $~ -> get_valid_escape_key(Rest, {finished, "\e["++reverse([$~|Acc])}); + $; -> get_valid_escape_key(Rest, {csi, [$;|Acc]}); + _ when $0 =< C, C =< $9 -> get_valid_escape_key(Rest, {csi, [C|Acc]}); + $m -> {invalid, "\e["++reverse([$m|Acc]), [$m|Rest]}; + _ when $! =< C, C =< $~ -> get_valid_escape_key(Rest, {finished, "\e["++reverse([C|Acc])}) + end; +get_valid_escape_key([C|Rest], {finished, Acc}) -> + case C of + $~ -> get_valid_escape_key([], {finished, Acc++[C], Rest}); + _ -> get_valid_escape_key([], {finished, Acc, [C|Rest]}) + end; +get_valid_escape_key(Rest, {invalid, Acc}) -> + {invalid, Acc, Rest}; +get_valid_escape_key(Rest, Acc) -> + {invalid, Acc, Rest}. + +merge(KeyMap) -> + merge(KeyMap, [normal, search, tab_expand], key_map()). +merge(_, [], KeyMap) -> + KeyMap; +merge(InputKeyMap, [Mode|ShellModes], KeyMap) -> + InputKeyMapModeValidated = #{}, + maps:foreach(fun(Key, Value) when is_list(Key), is_atom(Value) -> + try + {key, Key, []} = get_valid_escape_key(Key, none), + case lists:member(Value,valid_functions()) of + true -> InputKeyMapModeValidated#{Key => Value}; + false -> io:format(standard_error, "Invalid function ~p in entry {~p,~p}~n", [Value, Key, Value]) + end + catch + _:_ -> + io:format(standard_error, "Invalid key ~p in entry {~p,~p}~n", [Key,Key,Value]) + end; + (default, Value) -> + case lists:member(Value,valid_functions()) of + true -> InputKeyMapModeValidated#{default => Value}; + false -> io:format(standard_error, "Invalid function ~p in entry {default,~p}~n", [Value, Value]) + end; + (Key,Value) -> + io:format(standard_error, "Invalid entry {~p,~p}~n", [Key, Value]) + end, maps:get(Mode, InputKeyMap, #{})), + KeyMap1 = KeyMap#{Mode => maps:merge(maps:get(Mode, KeyMap), InputKeyMapModeValidated)}, + + merge(InputKeyMap, ShellModes, KeyMap1). + +%% Default Keymap for erl shell. +%% This is a keymap that corresponds to what was previously +%% configured in edlin.erl. +%% They are now in a map of maps that supports multiple shell modes, +%% normal, search, expand. +%% +%% See below for unused keys. +%% +key_map() -> #{ + normal => normal_map(), + search => #{ + "\^R" => skip_up, + "\^S" => skip_down, + "\^[C" => search_cancel, + "\^[c" => search_cancel, + "\n" => search_found, + "\r" => search_found, + "\^H" => backward_delete_char, + "\^?" => backward_delete_char, + default => search_quit + %% # everything else should exit search mode and edit the search result (search_quit), + }, + tab_expand => #{ + "\t" => tab_expand_full, + default => tab_expand_quit %% go to normal mode and evaluate key input again + } + }. + +normal_map() -> + #{ + %% Enter + "\n" => new_line_finish, + "\r" => new_line_finish, + %%% Alt-Enter or Esc + Enter + "\^[\n" => new_line, + "\^[\r" => new_line, + %% Tab ^I + "\t" => tab_expand, + + %% Ctrl-alpha_key, can not distinguish case + "\^A" => beginning_of_line, + "\^B" => backward_char, + %%"\^C" => sig_term_menu, currently handled by user_drv.erl + "\^D" => forward_delete_char, + "\^E" => end_of_line, + "\^F" => forward_char, + %%"\^G" => jcl_menu, currently handled by user_drv.erl + "\^H" => backward_delete_word, + %%"\^I" => tab_expand, same as \t + %%"\^J" => new_line_finish, same as \n + "\^K" => kill_line, + "\^L" => clear, + %%"\^M" => new_line_finish, same as \r + "\^N" => history_down, + "\^O" => open_editor, + "\^P" => history_up, + "\^R" => search, + "\^T" => transpose_char, + "\^U" => backward_kill_line, + "\^W" => backward_kill_word, + %%"\^X" => , + "\^Y" => yank, + %%"\^Z" => sig_stop, currently not handled by edlin.erl + "\^]" => auto_blink, % ctrl+5 seems to do the same thing, + + %%# Alt-alpha_key or Esc + alpha_key, can distinguish case, + "\^[B" => backward_word, + "\^[b" => backward_word, + "\^[c" => clear_line, + "\^[D" => kill_word, + "\^[d" => kill_word, + "\^[F" => forward_word, + "\^[f" => forward_word, + "\^[L" => redraw_line, + "\^[l" => redraw_line, + "\^[o" => open_editor, + "\^[T" => transpose_word, + "\^[t" => transpose_word, + "\^[<" => beginning_of_expression, + "\^[>" => end_of_expression, + + %% # Deletion keys + %% ## Backspace + "\^?" => backward_delete_char, + %% ## Ctrl+Backspace + "\^[\^?" => backward_kill_word, + %% ## Del + "\^[[3~" => forward_delete_char, + "\^[[3;5~" => forward_delete_word, + + %% # Navigation keys + %% ## Home + "\^[[H" => beginning_of_line, + "\^[OH" => beginning_of_line, + + %% ## End + "\^[[F" => end_of_line, + "\^[OF" => end_of_line, + + %% # Arrow keys + %% ## Up + "\^[OA" => history_up, + "\^[[A" => history_up, + "\^[[1;3A" => backward_line, + "\^[[1;5A" => backward_line, + "\^[[1;4A" => beginning_of_expression, + + %% ## Down + "\^[OB" => history_down, + "\^[[B" => history_down, + "\^[[1;3B" => forward_line, + "\^[[1;5B" => forward_line, + "\^[[1;4B" => end_of_expression, + + %% ## Left + "\^[OD" => backward_char, + "\^[[D" => backward_char, + "\^[[3D" => backward_word, + "\^[[1;3D" => backward_word, + "\^[[5D" => backward_word, + "\^[[1;5D" => backward_word, + + %% ## Right + "\^[OC" => forward_char, + "\^[[C" => forward_char, + "\^[[3C" => forward_word, + "\^[[1;3C" => forward_word, + "\^[[5C" => forward_word, + "\^[[1;5C" => forward_word, + default => none + }. +valid_functions() -> + [auto_blink, %% Automatically close the closest matching opening parenthesis + backward_char, %% Move backward one character + backward_delete_char, %% Delete the character behind the cursor + backward_delete_word, %% Delete the word behind the cursor + backward_kill_line, %% Delete all characters from the cursor to the beginning of the line and save them in the kill buffer + backward_kill_word, %% Delete the word behind the cursor and save it in the kill buffer + backward_line, %% Move backward one line + backward_word, %% Move backward one word + beginning_of_expression,%% Move to the beginning of the expression + beginning_of_line, %% Move to the beginning of the line + clear, %% Clear the screen + clear_line, %% Clear the current expression + end_of_expression, %% Move to the end of the expression + end_of_line, %% Move to the end of the line + forward_char, %% Move forward one character + forward_delete_char, %% Delete the character under the cursor + forward_delete_word, %% Delete the characters until the closest non-word character + forward_line, %% Move forward one line + forward_word, %% Move forward one word + history_down, %% Move to the next item in the history + history_up, %% Move to the previous item in the history + %%jcl_menu, + kill_line, %% Delete all characters from the cursor to the end of the line and save them in the kill buffer + kill_word, %% Delete the word behind the cursor and save it in the kill buffer + new_line_finish, %% Add a newline at the end of the line and try to evaluate the current expression + new_line, %% Add a newline at the cursor position + none, %% Do nothing + open_editor, %% Open the current line in an editor i.e. EDITOR=code -w + redraw_line, %% Redraw the current line + search_cancel, %% Cancel the current search + search_found, %% Accept the current search result and submit it + search_quit, %% Accept the current search result, but edit it before submitting + search, %% Enter search mode, search the history + %%sig_stop, + %%sig_term_menu, + skip_down, %% Skip to the next line in the history that matches the current search expression + skip_up, %% Skip to the previous line in the history that matches the current search expression + tab_expand_full, %% Output all possible tab completions + tab_expand_quit, %% Go back to normal mode + tab_expand, %% Autocomplete the current word, or show 5 lines of possible completions + transpose_char, %% Swap the character behind the cursor with the one in front of it + transpose_word, %% Swap the word behind the cursor with the one in front of it + yank]. %% Insert the contents of the kill buffer at the cursor position + +%% Unused keys in normal mode: +%% Ctrl+char +%% ^Q +%% ^S +%% ^V +%% ^@, ^\, ^], ^^, ^_ %% not straightforward how to type these +%% +%% Alt-Shift-char, Alt-char or Esc + Shift-char, Esc + char +%% ^[A, a +%% ^[C +%% ^[E, e +%% ^[G, g +%% ^[H, h +%% ^[I, i +%% ^[J, j +%% ^[K, k +%% ^[M, m +%% ^[N, n +%% ^[O, o +%% ^[P, p +%% ^[Q, q +%% ^[R, r +%% ^[S, s +%% ^[U, u +%% ^[V, v +%% ^[W, w +%% ^[X, x +%% ^[Z, z +%% ^[1, ^[2, ^[3, ^[4, ^[5, ^[6, ^[7, ^[8, ^[9, ^[0 +%% Any symbol that is typable while holding alt key, or esc key followed by a symbol: +%% e.g. ^[!, ^[@, ^[#, ^[$, ^[%, ^[^, ^[&, ^[*, ^[(, ^[), +%% (F1-F4) +%% ^[OP, ^[OQ, ^[OR, ^[OS +%% ^[[1;2P, ^[[1;2Q, ^[[1;2R, ^[[1;2S (Shift-F1-F4) +%% ^[[1;5P, ^[[1;5Q, ^[[1;5R, ^[[1;5S (Ctrl-F1-F4) +%% (F5-F12) +%% ^[15~, ^[17~, ^[18~, ^[19~, ^[20~, ^[21~, ^[23~, ^[24~ +%% ^[[15;2~, ^[[17;2~, ^[[18;2~, ^[[19;2~, ^[[20;2~, ^[[21;2~, ^[[23;2~, ^[[24;2~ (Shift-F5-F12) +%% ^[[15;5~, ^[[17;5~, ^[[18;5~, ^[[19;5~, ^[[20;5~, ^[[21;5~, ^[[23;5~, ^[[24;5~ (Ctrl-F5-F12) diff --git a/lib/stdlib/src/edlin_type_suggestion.erl b/lib/stdlib/src/edlin_type_suggestion.erl new file mode 100644 index 000000000000..5b148ab99838 --- /dev/null +++ b/lib/stdlib/src/edlin_type_suggestion.erl @@ -0,0 +1,487 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2023. 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(edlin_type_suggestion). +-include_lib("kernel/include/eep48.hrl"). +-export([type_tree/4, get_arity/3, get_atoms/3, get_types/3, get_types/4, get_function_type/4, print_type/3]). + + +%% type_tree/4 returns a unwrapped and trimmed type specification containing +%% all the valid 'types' that are valid in each function parameter of a function or +%% each record field of a record. +%% +%% Translates the spec AST to a structure that resembles the AST but trimmed of unneeded data. +%% User types and remote types are fetched and embedded in the structure depending on requested +%% level of unnestling. +%% Unions are flattened. +%% Visited is used to prevent infinite loops when looking up a recursive / cyclic type +%% FT is a map of type {{type, Type}, {attribute,_,type,{_,TypeAST,_}}}) +type_tree(Mod, FunType, Nestings, FT) -> + %% TODO when FT is updated we would be getting incorrect results because of cache + %% we should probably store a "dirty bit" in the table to make this aware that + %% a new result should be calculated. Preferably only types that depend on the table + %% would be invalidated, but it may turn advanced. + %% TODO look this over to make sure we don't do unnecessary work, + case get({type_traverser, Mod, FunType, Nestings}) of + undefined -> Res = type_traverser_cache(Mod, FunType, #{}, length(Nestings)+1, FT), + put({type_traverser, Mod, FunType, Nestings}, Res), + Res; + Res -> Res + end. +type_traverser_cache(Mod, T, Visited, Level, FT) -> + case get({Mod, T, Level}) of + undefined -> + Res = type_traverser(Mod, T, Visited, Level, FT), + put({Mod, T, Level}, Res), + Res; + Res -> Res + end. + +type_traverser(Mod, {type, _, bounded_fun, [Fun, Constraints]}, Visited, Level, FT) -> + Cl = [type_traverser(Mod,X,Visited, Level, FT) || X <- Constraints], + F = type_traverser(Mod, Fun, Visited, Level, FT), + {function, F, Cl}; +type_traverser(Mod, {type, _, 'fun', [Product, Return]}, Visited, Level, FT) -> + P = type_traverser(Mod, Product, Visited, Level, FT), + R = type_traverser(Mod, Return, Visited, Level, FT), + {P, {return, R}}; +type_traverser(Mod, {type, _, product, Childs}, Visited, Level, FT) -> + Cl = [type_traverser(Mod, X, Visited, Level, FT) || X <- Childs], + {parameters, Cl}; +type_traverser(Mod, {type, _, constraint, [{atom, _, is_subtype}, [Type1, Type2]]}, Visited, Level, FT) -> + {constraint, type_traverser(Mod, Type1, Visited, Level, FT), type_traverser(Mod, Type2, Visited, Level, FT)}; +type_traverser(_, {var, _, Name}, _Visited, _Level, _FT) -> + {var, Name}; +type_traverser(_Mod,{type, _, map, any}, _Visited, _Level, _FT) -> + {type, map, []}; +type_traverser(Mod, {type, _, map, Params}, Visited, Level, FT) -> + {map, [type_traverser(Mod, X, Visited, Level-1, FT) || X <- Params]}; +type_traverser(Mod, {type, _, map_field_exact, [Type1, Type2]}, Visited, Level, FT) -> + {map_field_exact, type_traverser(Mod,Type1, Visited, Level, FT), type_traverser(Mod,Type2, Visited, Level, FT)}; +type_traverser(Mod, {type, _, map_field_assoc, [Type1, Type2]}, Visited, Level, FT) -> + {map_field_assoc, type_traverser(Mod,Type1, Visited, Level, FT), type_traverser(Mod,Type2, Visited, Level, FT)}; +type_traverser(_Mod, {atom, _, Atom}, _Visited, _Level, _FT) when is_atom(Atom) -> + Atom; +type_traverser(Mod, {op, _, Op, Type}, Visited, Level, FT) -> + {op, Op, type_traverser(Mod, Type, Visited, Level, FT)}; +type_traverser(Mod, {op, _, Op, Type1, Type2}, Visited, Level, FT) -> + {op, Op, type_traverser(Mod, Type1, Visited, Level, FT), type_traverser(Mod, Type2, Visited, Level, FT)}; +type_traverser(_Mod, {integer, _, Int}, _Visited, _Level, _FT) -> + {integer, Int}; +type_traverser(Mod, {type, _, list, [ChildType]}, Visited, Level, FT) -> + {list, type_traverser(Mod, ChildType, Visited, Level-1, FT)}; +type_traverser(_Mod, {type, _, tuple, any}, _Visited, _Level, _FT) -> + {type, tuple, []}; +type_traverser(Mod, {type, _, tuple, ChildTypes}, Visited, Level, FT) -> + {tuple, [type_traverser(Mod, X, Visited, Level-1, FT) || X <- ChildTypes]}; +type_traverser(Mod, {type, _, union, ChildTypes}, Visited, Level, FT) -> + Childs = [type_traverser(Mod, X, Visited, Level, FT) || X <- ChildTypes], + ChildsFiltered = [X || X <- Childs, X/=undefined], + {UnionChilds, NonUnionChilds} = lists:partition( + fun(X) -> + case X of + {union, _} -> true; + _ -> false + end + end, ChildsFiltered), + ChildsFlattened = lists:flatten([T || {union, T} <- UnionChilds]) ++ NonUnionChilds, + {union, ChildsFlattened}; +type_traverser(Mod, {ann_type,_,[T1,T2]}, Visited, Level, FT) -> + {ann_type, type_traverser(Mod, T1, Visited, Level, FT), type_traverser(Mod, T2, Visited, Level, FT)}; +type_traverser(Mod, {user_type,_,Name,Params}=T, Visited, Level, FT) when 0 >= Level -> + %% when we have level 0, do not traverse the type further, just print it + case maps:is_key(strip_anno(T), Visited) of + false -> + {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, 0, FT) || P <- Params]}; + true -> {type, Mod, Name, []} + end; +type_traverser(_, {remote_type,_,[{_,_,Mod},{_,_,Name}, Params]}=T, Visited, Level, FT) when 0 >= Level -> + case maps:is_key(strip_anno(T), Visited) of + false -> + {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, 0, FT) || P <- Params]}; + true -> {type, Mod, Name, []} + end; +type_traverser(Mod, {user_type,_,Name,Params}=T, Visited, 1=Level, FT) -> + case maps:is_key(strip_anno(T), Visited) of + false -> + case get({strip_anno(T), 1}) of + undefined -> + Res = case lookup_type(Mod, Name, length(Params), FT) of + hidden -> {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params]}; + Type -> {user_type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params], type_traverser(Mod, Type, Visited#{ strip_anno(T) => true }, Level, FT)} + end, + put({strip_anno(T), 1}, Res), + Res; + Res -> Res + end; + true -> {type, Mod, Name, []} + end; +type_traverser(_, {remote_type,_,[{_,_,Mod},{_,_,Name}, Params]}=T, Visited, 1=Level, FT) -> + case maps:is_key(strip_anno(T), Visited) of + false -> + case get({strip_anno(T), 1}) of + undefined -> + Res = case lookup_type(Mod, Name, length(Params), FT) of + hidden -> {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params]}; + Type -> {user_type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params], type_traverser(Mod, Type, Visited#{ strip_anno(T) => true }, Level, FT)} + end, + put({strip_anno(T), 1}, Res), + Res; + Res -> Res + end; + true -> {type, Mod, Name, []} + end; +type_traverser(Mod, {user_type,_,Name,Params}=T, Visited, Level, FT) -> + case maps:is_key(strip_anno(T), Visited) of + false -> + case get({strip_anno(T), Level}) of + undefined -> + Res = case lookup_type(Mod, Name, length(Params), FT) of + hidden -> {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params]}; + Type -> type_traverser(Mod, Type, Visited#{ strip_anno(T) => true }, Level, FT) + end, + put({strip_anno(T), Level}, Res), + Res; + Res -> Res + end; + true -> {type, Mod, Name, []} + end; +type_traverser(_, {remote_type, _, [{_,_,Mod},{_,_,Name}, Params]}=T, Visited, Level, FT) -> + case maps:is_key(strip_anno(T), Visited) of + false -> + case get({strip_anno(T), Level}) of + undefined -> + Res = case lookup_type(Mod, Name, length(Params), FT) of + hidden -> {type, Mod, Name, [type_traverser(Mod, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params]}; + Type -> type_traverser(Mod, Type, Visited#{ strip_anno(T) => true }, Level, FT) + end, + put({strip_anno(T), Level}, Res), + Res; + Res -> Res + end; + true -> {type, Mod, Name, []} + end; +type_traverser(_, {type, _, record, [{atom, _, Record}]}, _Visited, _Level, _FT) -> + {record, Record}; +type_traverser(_, {type, _, Name, any}, _, _, _) -> + {type, Name, []}; +type_traverser(_, {type, _, term}, _, _, _) -> + {type, any, []}; +type_traverser(_, {type, _, Name}, _, _, _) -> + {type, Name, []}; +type_traverser(_, {type, _, term, _}, _, _, _) -> + {type, any, []}; +type_traverser(_, {type, _, Name, Params}=T, Visited, Level, FT) -> + case maps:is_key(strip_anno(T), Visited) of + false -> + case get({strip_anno(T), 1}) of + undefined -> + Res = case lookup_type(erlang, Name, length(Params), FT) of + hidden -> {type, Name, [type_traverser(erlang, P, Visited#{ strip_anno(T) => true }, Level, FT) || P <- Params]}; + Type -> type_traverser(erlang, Type, Visited#{ strip_anno(T) => true}, Level, FT) + end, + put({strip_anno(T), 1}, Res), + Res; + Res -> Res + end; + true -> {type, Name, []} + end. + +strip_anno({A, _, B}) -> {A, B}; +strip_anno({A, _, B, C}) -> {A, B, C}. + +simplified_type(erlang, binary, 0) -> {type, undefined, binary, []}; +simplified_type(erlang, char, 0) -> {type, undefined, char, []}; +simplified_type(erlang, iolist, 0) -> {type, undefined, iolist, []}; +simplified_type(erlang, string, 0) -> {type, undefined, string, []}; +simplified_type(unicode, chardata, 0) -> {type, erlang, string, []}; +simplified_type(file, filename_all, 0) -> {type, erlang, string, []}; +simplified_type(file, filename, 0) -> {type, erlang, string, []}; +simplified_type(file, name_all, 0) -> {type, erlang, string, []}; +simplified_type(file, name, 0) -> {type, erlang, string, []}; +simplified_type(_Module, _TypeName, _Arity) -> none. + +lookup_type(Mod, Type, Arity, FT) -> + case simplified_type(Mod, Type, Arity) of + none -> + case code:get_doc(Mod, #{sources => [debug_info]}) of + {ok, #docs_v1{ docs = Docs } } -> + FnFunctions = + lists:filter(fun({{type, T, A},_Anno,_Sig,_Doc,_Meta}) -> + T =:= Type andalso A =:= Arity; + (_) -> + false + end, Docs), + case FnFunctions of + [] -> + case [TypeAST || {{type, Type2}, {attribute,_,type,{_,TypeAST,_}}} <- FT, Type2 =:= Type] of + [] -> hidden; %% can be an opaque type or missing type + [SingleTypeAST] -> SingleTypeAST + end; + [{_,_,_,_,#{signature := [{attribute,_,type,{_,TypeAST,_}}]}}] -> TypeAST + end; + _ -> + case [TypeAST || {{type, Type2}, {attribute,_,type,{_,TypeAST,_}}} <- FT, Type2 =:= Type] of + [] -> hidden; %% can be an opaque type or missing type + [SingleTypeAST] -> SingleTypeAST + end + end; + T -> T + end. +get_function_type(Mod, Fun, Arity, FT) -> + case code:get_doc(Mod, #{sources => [debug_info]}) of + {ok, #docs_v1{ docs = Docs } } -> + R = lists:flatten([FunTypes || + {{function, F, A},_Anno,_Sig,_Doc, #{ signature := [{attribute,_,spec,{_,FunTypes}}]}} <- Docs, + F =:= Fun, A =:= Arity]), + case {Mod, R} of + {shell_default, []} -> + lists:flatten([FunTypes || + {{function_type, {shell_default, F, A}},{attribute,_,spec,{_,FunTypes}}} <- FT, + F =:= Fun, A =:= Arity]); + _ -> R + end; + _ when Mod =:= shell_default -> + lists:flatten([FunTypes || {{function_type, {shell_default, F, A}},{attribute,_,spec,{_,FunTypes}}} <- FT, + F =:= Fun, A =:= Arity]); + _ -> [] + end. +get_arity(Constraints, Type, Nestings) -> + case get_arity1(Type, Constraints, Nestings) of + List when is_list(List) -> List; + Val -> [Val] + end. +get_arity1({var, _Var}=C, Constraints, Nestings) -> + case get_constraint(C, Constraints) of + {constraint, _, T} -> get_arity1(T, Constraints, Nestings); + _ -> none + end; +get_arity1({list, _T}, _Constraints, [{'list', _, _}]) -> + 99; %% Can be higher, but probably do not need completion for that +get_arity1({list, T}, Constraints, [{'list', _, _}|Nestings]) -> + get_arity1(T, Constraints, Nestings); +get_arity1({tuple, LT}, Constraints, [{'tuple', Args, _}]) when length(LT) >= length(Args) -> + case edlin_expand:match_arguments1(LT, Constraints, Args) of + true -> length(LT); + false -> + none + end; +get_arity1({tuple, LT}, Constraints, [{'tuple', Args, _}|Nestings]) when length(LT) >= length(Args)+1 -> + case edlin_expand:match_arguments1(LT, Constraints, Args) of + true -> get_arity1(lists:nth(length(Args)+1, LT), Constraints, Nestings); + false -> none + end; +get_arity1({map, Types}, _Constraints, [{'map', _Keys, [], _, _}]) -> + length(Types); +get_arity1({map, Types}, _Constraints, [{'map', _Keys, _Key, _, _}]) -> + length(Types); +get_arity1({map, Types}, Constraints, [{'map', Keys, [], _, _}|Nestings]) -> + lists:flatten([get_arity1(T, Constraints, Nestings) || {_, Key, _}=T <- Types, not lists:member(atom_to_list(Key), Keys)]); +get_arity1({map, Types}, Constraints, [{'map', _Keys, Key, _, _}|Nestings]) -> + case [V || {_, K, V} <- Types, K =:= list_to_atom(Key)] of + [] -> none; + [Type] -> get_arity1(Type, Constraints, Nestings) + end; +get_arity1({map_field_assoc, K, _V}, C, Nestings) -> + get_arity1(K, C, Nestings); +get_arity1({map_field_exact, K, _V}, C, Nestings) -> + get_arity1(K, C, Nestings); +get_arity1({union, Types}, Constraints, Nestings) -> + Arities = [get_arity1(T, Constraints, Nestings) || T <- Types], + [X || X <- lists:flatten(Arities), X/=none]; +get_arity1({ann_type, _Var, Type}, Constraints, Nestings) -> + get_arity1(Type, Constraints, Nestings); +get_arity1({user_type, _, _, _, Type}, Constraints, Nestings) -> + get_arity1(Type, Constraints, Nestings); +get_arity1(_, _, _) -> + none. + +%% get_atoms returns the valid atoms in the current context as a list +get_atoms(Constraints, Type, Nestings) -> + case get_atoms1(Type, Constraints, Nestings) of + List when is_list(List) -> [io_lib:write_atom(Atom) || Atom <- List]; + Atom when is_atom(Atom) -> [io_lib:write_atom(Atom)] + end. +get_atoms1({var, _Var}=C, Constraints, Nestings) -> + case get_constraint(C, Constraints) of + {constraint, _, T} -> get_atoms1(T, Constraints, Nestings); + _ -> [] + end; +get_atoms1({list, T}, Constraints, [{'list', _, _}|Nestings]) -> + get_atoms1(T, Constraints, Nestings); +get_atoms1({tuple, LT}, Constraints, [{'tuple', Args, _}|Nestings]) when length(LT) >= length(Args)+1 -> + case edlin_expand:match_arguments1(LT, Constraints, Args) of + true -> get_atoms1(lists:nth(length(Args)+1, LT), Constraints, Nestings); + false -> [] + end; +get_atoms1({map, Types}, Constraints, [{'map', Keys, [], _, _}|Nestings]) -> + lists:flatten([get_atoms1(T, Constraints, Nestings) || {_, Key, _}=T <- Types, not lists:member(atom_to_list(Key), Keys)]); +get_atoms1({map, Types}, Constraints, [{'map', _Keys, Key, _, _}|Nestings]) -> + case [V || {_, K, V} <- Types, K =:= list_to_atom(Key)] of + [] -> []; + [Type] -> get_atoms1(Type, Constraints, Nestings) + end; +get_atoms1({map_field_assoc, K, _V}, C, Nestings) -> + get_atoms1(K, C, Nestings); +get_atoms1({map_field_exact, K, _V}, C, Nestings) -> + get_atoms1(K, C, Nestings); +get_atoms1( {union, Types}, Constraints, Nestings) -> + Atoms = [get_atoms1(T, Constraints, Nestings) || T <- Types], + [X || X <- lists:flatten(Atoms), X/=[]]; +get_atoms1(Atom, _Constraints, []) when is_atom(Atom) -> + Atom; +get_atoms1({user_type, _, _, _, Type}, Constraints, Nestings) -> + get_atoms1(Type, Constraints, Nestings); +get_atoms1(_, _, _) -> + []. + +get_types(Constraints, T, Nestings) -> + get_types(Constraints, T, Nestings,[]). +get_types(Constraints, T, Nestings, Options) -> + MaxUserTypeExpansions = 1, + case get_types1(T, Constraints, Nestings, MaxUserTypeExpansions, Options) of + [] -> []; + [_|_]=Types -> [Type || Type <- Types, Type /= []]; + Type -> [Type] + end. +get_types1({var, _Var}=C, Constraints, Nestings, MaxUserTypeExpansions, Options) -> + case get_constraint(C, Constraints) of + {constraint, _, T} -> get_types1(T, Constraints, Nestings, MaxUserTypeExpansions, Options); + _ -> [] + end; +get_types1({union, Types}, Cs, Nestings, MaxUserTypeExpansions, Options) -> + lists:flatten([get_types1(T, Cs, Nestings, MaxUserTypeExpansions, Options) || T <- Types]); + +get_types1({list, T}, Cs, [{list, _Args, _}|Nestings], MaxUserTypeExpansions, Options) -> + get_types1(T, Cs, Nestings, MaxUserTypeExpansions, Options); +get_types1({tuple, LT}, Cs, [{tuple, Args, _}|Nestings], MaxUserTypeExpansions, Options) when length(LT) >= length(Args)+1 -> + case edlin_expand:match_arguments1(LT, Cs, Args) of + true -> get_types1(lists:nth(length(Args)+1, LT), Cs, Nestings, MaxUserTypeExpansions, Options); + false -> [] + end; +get_types1({'map', Types}, Cs, [{'map', Keys, [], _Args, _}|Nestings], MaxUserTypeExpansions, Options) -> + lists:flatten([get_types1(T, Cs, Nestings, MaxUserTypeExpansions, Options) || {_, Key, _}=T <- Types, not lists:member(atom_to_list(Key), Keys)]); +get_types1({'map', Types}, Cs, [{'map', _, Key, _Args, _}|Nestings], MaxUserTypeExpansions, Options) -> + case [V || {_, K, V} <- Types, K =:= list_to_atom(Key)] of + [] -> []; + [Type] -> get_types1(Type, Cs, Nestings, MaxUserTypeExpansions, Options) + end; +get_types1({user_type, _Mod, _Name, _Params, Type}, Cs, Nestings, MaxUserTypeExpansions, [no_print]=Options) when MaxUserTypeExpansions > 0 -> + lists:flatten([get_types1(Type, Cs, Nestings, MaxUserTypeExpansions-1, Options)]); +get_types1({user_type, _, _, _, Type}, Cs, Nestings, 0, [no_print]=Options) -> + get_types1(Type, Cs, Nestings, 0, Options); +get_types1({ann_type, _Var, T}, Cs, Nestings, MaxUserTypeExpansions, [no_print]) -> + get_types1(T, Cs, Nestings, MaxUserTypeExpansions, [no_print]); +get_types1({ann_type, _Var, _T}=Type, Cs, [], _MaxUserTypeExpansions, []) -> + {print_type(Type, Cs), ""}; +get_types1({ann_type, _Var, T}, Cs, Nestings, MaxUserTypeExpansions, []) -> + get_types1(T, Cs, Nestings, MaxUserTypeExpansions, []); +get_types1(Type, _Cs, [], _, [no_print]) -> + Type; +get_types1({user_type, Mod, Name, Params, Type}, Cs, Nestings, MaxUserTypeExpansions, []) when MaxUserTypeExpansions > 0 -> + Title = print_type({type, Mod, Name, Params}, Cs, []), + Elems = lists:flatten([get_types1(Type, Cs, Nestings, MaxUserTypeExpansions-1, [])]), + #{title=>Title, elems=>Elems, options=>[{separator, " :: "}, {highlight_all}]}; +get_types1({user_type, _, _, _, Type}, Cs, Nestings, 0, []) -> + get_types1(Type, Cs, Nestings, 0, []); +get_types1(Type, Cs, [],_, []) -> + {print_type(Type, Cs), ""}; +get_types1(_, _, _, _, _) -> []. + +get_constraint(Type, Constraints) -> + case [ X || {constraint, T, _}=X <- Constraints, T == Type] of + [C|_] -> C; + [] -> [] + end. + +print_type(Type, Constraints) -> + lists:flatten(print_type(Type, Constraints, [], [])). +print_type(Type, Constraints, Options) -> + lists:flatten(print_type(Type, Constraints, [], Options)). +print_type({var, Name}=Var, Constraints, Visited, Options) -> + case lists:member(Var, Visited) of + true -> atom_to_list(Name); + false -> + case get_constraint(Var, Constraints) of + {constraint, _, T2} -> print_type(T2, Constraints, [Var| Visited], Options); + _ -> atom_to_list(Name) + end + end; +print_type(Atom, _Cs, _V, _) when is_atom(Atom) -> io_lib:write_atom(Atom); +print_type({{parameters, Ps}, {return, R}}, Cs, V, Options) -> + "fun(("++lists:join(", ", [print_type(X, Cs, V, Options) || X <- Ps]) ++ ") -> " ++ print_type(R, Cs, V, Options) ++ ")"; +print_type({list, Type}, Cs, V, Options)-> + "[" ++ print_type(Type, Cs, V, Options) ++ "]"; +print_type({tuple, Types}, Cs, V, Options) when is_list(Types) -> + Types1 = [print_type(X, Cs, V, Options) || X <- Types], + case Types1 of + [] -> "{}"; + _ -> "{"++ lists:nth(1, Types1) ++ ", ...}" + end; +print_type({ann_type, Var, Type}, Cs, V, Options) -> + print_type(Var, Cs, V, Options) ++ " :: " ++ print_type(Type, Cs, V, Options); +print_type({map, Types}, Cs, V, Options) -> + Types1 = [print_type(X, Cs, V, Options) || X <- Types], + "#{"++lists:join(", ", Types1) ++ "}"; +print_type({map_field_assoc, Type1, Type2}, Cs, V, Options) -> + print_type(Type1, Cs, V, Options) ++ "=>" ++ print_type(Type2, Cs, V, Options); +print_type({map_field_exact, Type1, Type2}, Cs, V, Options) -> + print_type(Type1, Cs, V, Options) ++ ":=" ++ print_type(Type2, Cs, V, Options); +print_type({integer, Int}, _Cs, _V, _) -> + integer_to_list(Int); +print_type({op, Op, Type}, Cs, V, Options) -> + "op ("++atom_to_list(Op)++" "++print_type(Type, Cs, V, Options)++")"; +print_type({op, Op, Type1, Type2}, Cs, V, Options) -> + "op ("++print_type(Type1, Cs, V, Options)++" "++atom_to_list(Op)++" "++print_type(Type2, Cs, V, Options)++")"; +print_type({record, Record}, _Cs, _V, _) -> + "#" ++ atom_to_list(Record); +print_type({type, range, [{integer, Int1},{integer, Int2}]}, _Cs, _V, _) -> + integer_to_list(Int1) ++ ".." ++ integer_to_list(Int2); +print_type({type, non_neg_integer, []}, _Cs, _V, _) -> + "integer() >= 0"; +print_type({type, neg_integer, []}, _Cs, _V, _) -> + "integer() < 0"; +print_type({type, pos_integer, []}, _Cs, _V, _) -> + "integer() > 0"; +print_type({type, Name, []}, _Cs, _V, _) -> + atom_to_list(Name)++"()"; +print_type({type, Name, Params}, _Cs, _V, _) -> + atom_to_list(Name) ++ "(" ++ lists:join(", ",[ extract_param(P) || P <- Params]) ++ ")"; +print_type({union, Types}, Cs, V, Options) -> + lists:join(" | ", [print_type(X, Cs, V, Options) || X <- Types]); +print_type({type, Mod, Name, Params}, _Cs, _V, _) -> + atom_to_list(Mod) ++ ":" ++ atom_to_list(Name) ++ + "(" ++ lists:join(", ", [extract_param(P) || P <- Params]) ++ ")"; +print_type({user_type, Mod, Name, Params, Type}, Cs, V, Options) -> + First = proplists:get_value(first_only, Options, false), + case First of + true -> print_type({type, Mod, Name, Params}, Cs, V, Options); + _ -> print_type({type, Mod, Name, Params}, Cs, V, Options) ++ " :: " ++ print_type(Type, Cs, V, Options) + end; +print_type(_,_,_,_) -> atom_to_list(unknown). + + +extract_param({var, Var}) -> + atom_to_list(Var); +extract_param({integer, Value}) -> + io_lib:format("~p",[Value]); +extract_param({type, Type,_}) -> + io_lib:format("~p", [Type]); +extract_param(T)-> + print_type(T, []). diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 53b91530c57c..55f328ea1cf8 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -72,8 +72,13 @@ uses = #{} %Macro use structure :: #{name() => [{argspec(), [used()]}]}, default_encoding = ?DEFAULT_ENCODING :: source_encoding(), - pre_opened = false :: boolean(), - fname = [] :: function_name_type() + pre_opened = false :: boolean(), + in_prefix = true :: boolean(), + erl_scan_opts = [] :: [_], + features = [] :: [atom()], + else_reserved = false :: boolean(), + fname = [] :: function_name_type(), + deterministic = false :: boolean() }). %% open(Options) @@ -115,11 +120,13 @@ open(Name, Path, Pdm) -> Options :: [{'default_encoding', DefEncoding :: source_encoding()} | {'includes', IncludePath :: [DirectoryName :: file:name()]} | {'source_name', SourceName :: file:name()} | + {'deterministic', Enabled :: boolean()} | {'macros', PredefMacros :: macros()} | {'name',FileName :: file:name()} | {'location',StartLocation :: erl_anno:location()} | {'fd',FileDescriptor :: file:io_device()} | - 'extra'], + 'extra' | + {'compiler_internal', [term()]}], Epp :: epp_handle(), Extra :: [{'encoding', source_encoding() | 'none'}], ErrorDescriptor :: term(). @@ -131,12 +138,14 @@ open(Options) -> Name -> Self = self(), Epp = spawn(fun() -> server(Self, Name, Options) end), + Extra = proplists:get_bool(extra, Options), case epp_request(Epp) of - {ok, Pid, Encoding} -> - case proplists:get_bool(extra, Options) of - true -> {ok, Pid, [{encoding, Encoding}]}; - false -> {ok, Pid} - end; + {ok, Pid, Encoding} when Extra -> + {ok, Pid, [{encoding, Encoding}]}; + {ok, Pid, _} -> + {ok, Pid}; + {ok, Pid} when Extra -> + {ok, Pid, []}; Other -> Other end @@ -239,6 +248,10 @@ format_error({error,Term}) -> io_lib:format("-error(~tp).", [Term]); format_error({warning,Term}) -> io_lib:format("-warning(~tp).", [Term]); +format_error(ftr_after_prefix) -> + "feature directive not allowed after exports or record definitions"; +format_error(tqstring) -> + "Triple-quoted (or more) strings will change meaning in OTP-27.0"; format_error(E) -> file:format_error(E). -spec scan_file(FileName, Options) -> @@ -297,7 +310,10 @@ parse_file(Ifile, Path, Predefs) -> {'macros', PredefMacros :: macros()} | {'default_encoding', DefEncoding :: source_encoding()} | {'location',StartLocation :: erl_anno:location()} | - 'extra'], + {'reserved_word_fun', Fun :: fun((atom()) -> boolean())} | + {'features', [Feature :: atom()]} | + 'extra' | + {'compiler_internal', [term()]}], Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Location}, @@ -311,11 +327,13 @@ parse_file(Ifile, Options) -> {ok,Epp} -> Forms = parse_file(Epp), close(Epp), - {ok,Forms}; + {ok, Forms}; {ok,Epp,Extra} -> Forms = parse_file(Epp), + Epp ! {get_features, self()}, + Ftrs = receive {features, X} -> X end, close(Epp), - {ok,Forms,Extra}; + {ok, Forms, [{features, Ftrs} | Extra]}; {error,E} -> {error,E} end. @@ -329,15 +347,32 @@ parse_file(Ifile, Options) -> WarningInfo :: warning_info(). parse_file(Epp) -> - case parse_erl_form(Epp) of - {ok,Form} -> - [Form|parse_file(Epp)]; + %% Code duplicated from parse_erl_form(Epp), but with + %% added search for tokens to warn for + case epp_request(Epp, scan_erl_form) of + {ok,Toks} -> + Warnings = + [{warning, {erl_anno:location(Anno),?MODULE,tqstring}} + %% Warn about using 3 or more double qoutes + || {tqstring,Anno,_} <- Toks], + case erl_parse:parse_form(Toks) of + {ok, Form} -> + [Form|Warnings] ++ parse_file(Epp); + Problem2 -> + parse_file_problem(Epp, Problem2, Warnings) + end; + Problem1 -> + parse_file_problem(Epp, Problem1, []) + end. + +parse_file_problem(Epp, Problem, Warnings) -> + case Problem of {error,E} -> - [{error,E}|parse_file(Epp)]; + [{error,E}|Warnings] ++ parse_file(Epp); {warning,W} -> - [{warning,W}|parse_file(Epp)]; + [{warning,W}|Warnings] ++ parse_file(Epp); {eof,Location} -> - [{eof,Location}] + [{eof,Location}|Warnings] end. -spec default_encoding() -> source_encoding(). @@ -593,7 +628,10 @@ server(Pid, Name, Options) -> init_server(Pid, FileName, Options, St0) -> SourceName = proplists:get_value(source_name, Options, FileName), Pdm = proplists:get_value(macros, Options, []), - Ms0 = predef_macros(SourceName), + Features = proplists:get_value(features, Options, []), + Internal = proplists:get_value(compiler_internal, Options, []), + ParseChecks = proplists:get_bool(ssa_checks, Internal), + Ms0 = predef_macros(SourceName, Features), case user_predef(Pdm, Ms0) of {ok,Ms1} -> DefEncoding = proplists:get_value(default_encoding, Options, @@ -604,28 +642,62 @@ init_server(Pid, FileName, Options, St0) -> %% first in path Path = [filename:dirname(FileName) | proplists:get_value(includes, Options, [])], + ResWordFun = + proplists:get_value(reserved_word_fun, Options, + fun erl_scan:f_reserved_word/1), %% the default location is 1 for backwards compatibility, not {1,1} AtLocation = proplists:get_value(location, Options, 1), + + Deterministic = proplists:get_value(deterministic, Options, false), St = St0#epp{delta=0, name=SourceName, name2=SourceName, path=Path, location=AtLocation, macs=Ms1, - default_encoding=DefEncoding}, + default_encoding=DefEncoding, + erl_scan_opts = + [{text_fun, keep_ftr_keywords()}, + {reserved_word_fun, ResWordFun}] + ++ if ParseChecks -> + [{compiler_internal,[ssa_checks]}]; + true -> [] + end, + features = Features, + else_reserved = ResWordFun('else'), + deterministic = Deterministic}, From = wait_request(St), Anno = erl_anno:new(AtLocation), enter_file_reply(From, file_name(SourceName), Anno, - AtLocation, code), + AtLocation, code, Deterministic), wait_req_scan(St); {error,E} -> epp_reply(Pid, {error,E}) end. +%% Return a function that keeps quoted atoms that are keywords in +%% configurable features. Need in erl_lint to avoid warning about +%% them. +keep_ftr_keywords() -> + Features = erl_features:configurable(), + Keywords = lists:flatmap(fun erl_features:keywords/1, Features), + F = fun(Atom) -> atom_to_list(Atom) ++ "'" end, + Strings = lists:map(F, Keywords), + fun(atom, [$'|S]) -> lists:member(S, Strings); + (_, _) -> false + end. + %% predef_macros(FileName) -> Macrodict %% Initialise the macro dictionary with the default predefined macros, %% FILE, LINE, MODULE as undefined, MACHINE and MACHINE value. -predef_macros(File) -> +predef_macros(File, EnabledFeatures0) -> Machine = list_to_atom(erlang:system_info(machine)), Anno = line1(), OtpVersion = list_to_integer(erlang:system_info(otp_release)), + AvailableFeatures = + [Ftr || Ftr <- erl_features:all(), + maps:get(status, erl_features:info(Ftr)) /= rejected], + PermanentFeatures = + [Ftr || Ftr <- erl_features:all(), + maps:get(status, erl_features:info(Ftr)) == permanent], + EnabledFeatures = EnabledFeatures0 ++ PermanentFeatures, Defs = [{'FILE', {none,[{string,Anno,File}]}}, {'FUNCTION_NAME', undefined}, {'FUNCTION_ARITY', undefined}, @@ -636,10 +708,36 @@ predef_macros(File) -> {'BASE_MODULE_STRING', undefined}, {'MACHINE', {none,[{atom,Anno,Machine}]}}, {Machine, {none,[{atom,Anno,true}]}}, - {'OTP_RELEASE', {none,[{integer,Anno,OtpVersion}]}} + {'OTP_RELEASE', {none,[{integer,Anno,OtpVersion}]}}, + {'FEATURE_AVAILABLE', [ftr_macro(AvailableFeatures)]}, + {'FEATURE_ENABLED', [ftr_macro(EnabledFeatures)]} ], maps:from_list(Defs). +%% Make macro definition from a list of features. The macro takes one +%% argument and returns true when argument is available as a feature. +ftr_macro(Features) -> + Anno = line1(), + Arg = 'X', + Fexp = fun(Ftr) -> [{'(', Anno}, + {var, Anno, Arg}, + {')', Anno}, + {'==', Anno}, + {atom, Anno, Ftr}] + end, + Body = + case Features of + [] -> [{atom, Anno, false}]; + [Ftr| Ftrs] -> + [{'(', Anno}| + lists:foldl(fun(F, Expr) -> + Fexp(F) ++ [{'orelse', Anno} | Expr] + end, + Fexp(Ftr) ++ [{')', Anno}], + Ftrs)] + end, + {1, {[Arg], Body}}. + %% user_predef(PreDefMacros, Macros) -> %% {ok,MacroDict} | {error,E} %% Add the predefined macros to the macros dictionary. A macro without a @@ -674,9 +772,12 @@ user_predef([], Ms) -> {ok,Ms}. wait_request(St) -> receive {epp_request,From,scan_erl_form} -> From; + {get_features, From} -> + From ! {features, St#epp.features}, + wait_request(St); {epp_request,From,macro_defs} -> %% Return the old format to avoid any incompability issues. - Defs = [{{atom,K},V} || {K,V} <- maps:to_list(St#epp.macs)], + Defs = [{{atom,K},V} || K := V <- St#epp.macs], epp_reply(From, Defs), wait_request(St); {epp_request,From,close} -> @@ -728,10 +829,15 @@ enter_file(NewName, Inc, From, St) -> enter_file2(NewF, Pname, From, St0, AtLocation) -> Anno = erl_anno:new(AtLocation), - enter_file_reply(From, Pname, Anno, AtLocation, code), + enter_file_reply(From, Pname, Anno, AtLocation, code, St0#epp.deterministic), #epp{macs = Ms0, - default_encoding = DefEncoding} = St0, - Ms = Ms0#{'FILE':={none,[{string,Anno,Pname}]}}, + default_encoding = DefEncoding, + in_prefix = InPrefix, + erl_scan_opts = ScanOpts, + else_reserved = ElseReserved, + features = Ftrs, + deterministic = Deterministic} = St0, + Ms = Ms0#{'FILE':={none,[{string,Anno,source_name(St0,Pname)}]}}, %% update the head of the include path to be the directory of the new %% source file, so that an included file can always include other files %% relative to its current location (this is also how C does it); note @@ -742,16 +848,21 @@ enter_file2(NewF, Pname, From, St0, AtLocation) -> _ = set_encoding(NewF, DefEncoding), #epp{file=NewF,location=AtLocation,name=Pname,name2=Pname,delta=0, sstk=[St0|St0#epp.sstk],path=Path,macs=Ms, - default_encoding=DefEncoding}. - -enter_file_reply(From, Name, LocationAnno, AtLocation, Where) -> + in_prefix = InPrefix, + features = Ftrs, + erl_scan_opts = ScanOpts, + else_reserved = ElseReserved, + default_encoding=DefEncoding, + deterministic=Deterministic}. + +enter_file_reply(From, Name, LocationAnno, AtLocation, Where, Deterministic) -> Anno0 = erl_anno:new(AtLocation), Anno = case Where of code -> Anno0; generated -> erl_anno:set_generated(true, Anno0) end, Rep = {ok, [{'-',Anno},{atom,Anno,file},{'(',Anno}, - {string,Anno,Name},{',',Anno}, + {string,Anno,source_name(Deterministic,Name)},{',',Anno}, {integer,Anno,get_line(LocationAnno)},{')',LocationAnno}, {dot,Anno}]}, epp_reply(From, Rep). @@ -783,9 +894,17 @@ leave_file(From, St) -> CurrLoc = add_line(OldLoc, Delta), Anno = erl_anno:new(CurrLoc), Ms0 = St#epp.macs, - Ms = Ms0#{'FILE':={none,[{string,Anno,OldName2}]}}, - NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses}, - enter_file_reply(From, OldName, Anno, CurrLoc, code), + InPrefix = St#epp.in_prefix, + Ftrs = St#epp.features, + ElseReserved = St#epp.else_reserved, + ScanOpts = St#epp.erl_scan_opts, + Ms = Ms0#{'FILE':={none,[{string,Anno,source_name(St,OldName2)}]}}, + NextSt = OldSt#epp{sstk=Sts,macs=Ms,uses=St#epp.uses, + in_prefix = InPrefix, + features = Ftrs, + else_reserved = ElseReserved, + erl_scan_opts = ScanOpts}, + enter_file_reply(From, OldName, Anno, CurrLoc, code, St#epp.deterministic), case OldName2 =:= OldName of true -> ok; @@ -793,7 +912,7 @@ leave_file(From, St) -> NFrom = wait_request(NextSt), OldAnno = erl_anno:new(OldLoc), enter_file_reply(NFrom, OldName2, OldAnno, - CurrLoc, generated) + CurrLoc, generated, St#epp.deterministic) end, wait_req_scan(NextSt); [] -> @@ -806,27 +925,30 @@ leave_file(From, St) -> %% scan_toks(Tokens, From, EppState) scan_toks(From, St) -> - case io:scan_erl_form(St#epp.file, '', St#epp.location) of - {ok,Toks,Cl} -> - scan_toks(Toks, From, St#epp{location=Cl}); - {error,E,Cl} -> - epp_reply(From, {error,E}), - wait_req_scan(St#epp{location=Cl}); - {eof,Cl} -> - leave_file(From, St#epp{location=Cl}); - {error,_E} -> + #epp{file = File, location = Loc, erl_scan_opts = ScanOpts} = St, + case io:scan_erl_form(File, '', Loc, ScanOpts) of + {ok,Toks,Cl} -> + scan_toks(Toks, From, St#epp{location=Cl}); + {error,E,Cl} -> + epp_reply(From, {error,E}), + wait_req_scan(St#epp{location=Cl}); + {eof,Cl} -> + leave_file(From, St#epp{location=Cl}); + {error,_E} -> epp_reply(From, {error,{St#epp.location,epp,cannot_parse}}), - leave_file(wait_request(St), St) %This serious, just exit! + leave_file(wait_request(St), St) %This serious, just exit! end. +scan_toks([{'-',_Lh},{atom,_Ld,feature}=Feature|Toks], From, St) -> + scan_feature(Toks, Feature, From, St); scan_toks([{'-',_Lh},{atom,_Ld,define}=Define|Toks], From, St) -> scan_define(Toks, Define, From, St); scan_toks([{'-',_Lh},{atom,_Ld,undef}=Undef|Toks], From, St) -> - scan_undef(Toks, Undef, From, St); + scan_undef(Toks, Undef, From, leave_prefix(St)); scan_toks([{'-',_Lh},{atom,_Ld,error}=Error|Toks], From, St) -> - scan_err_warn(Toks, Error, From, St); + scan_err_warn(Toks, Error, From, leave_prefix(St)); scan_toks([{'-',_Lh},{atom,_Ld,warning}=Warn|Toks], From, St) -> - scan_err_warn(Toks, Warn, From, St); + scan_err_warn(Toks, Warn, From, leave_prefix(St)); scan_toks([{'-',_Lh},{atom,_Li,include}=Inc|Toks], From, St) -> scan_include(Toks, Inc, From, St); scan_toks([{'-',_Lh},{atom,_Li,include_lib}=IncLib|Toks], From, St) -> @@ -837,6 +959,10 @@ scan_toks([{'-',_Lh},{atom,_Li,ifndef}=IfnDef|Toks], From, St) -> scan_ifndef(Toks, IfnDef, From, St); scan_toks([{'-',_Lh},{atom,_Le,'else'}=Else|Toks], From, St) -> scan_else(Toks, Else, From, St); +%% conditionally allow else as a keyword +scan_toks([{'-',_Lh},{'else',_Le}=Else|Toks], From, St) + when St#epp.else_reserved -> + scan_else(Toks, Else, From, St); scan_toks([{'-',_Lh},{'if',_Le}=If|Toks], From, St) -> scan_if(Toks, If, From, St); scan_toks([{'-',_Lh},{atom,_Le,elif}=Elif|Toks], From, St) -> @@ -854,13 +980,37 @@ scan_toks([{'-',_Lh},{atom,_Lf,file}=FileToken|Toks0], From, St) -> scan_toks(Toks0, From, St) -> case catch expand_macros(Toks0, St#epp{fname=Toks0}) of Toks1 when is_list(Toks1) -> + InPrefix = + St#epp.in_prefix + andalso case Toks1 of + [] -> true; + [{'-', _Loc}, Tok | _] -> + in_prefix(Tok); + _ -> + false + end, epp_reply(From, {ok,Toks1}), - wait_req_scan(St#epp{macs=scan_module(Toks1, St#epp.macs)}); + wait_req_scan(St#epp{in_prefix = InPrefix, + macs=scan_module(Toks1, St#epp.macs)}); {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), wait_req_scan(St) end. +%% Determine whether we have passed the prefix where a -feature +%% directive is allowed. +in_prefix({atom, _, Atom}) -> + %% These directives are allowed inside the prefix + lists:member(Atom, ['module', 'feature', + 'if', 'else', 'elif', 'endif', 'ifdef', 'ifndef', + 'define', 'undef', + 'include', 'include_lib']); +in_prefix(_T) -> + false. + +leave_prefix(#epp{} = St) -> + St#epp{in_prefix = false}. + scan_module([{'-',_Ah},{atom,_Am,module},{'(',_Al}|Ts], Ms) -> scan_module_1(Ts, Ms); scan_module([{'-',_Ah},{atom,_Am,extends},{'(',_Al}|Ts], Ms) -> @@ -901,6 +1051,54 @@ scan_err_warn(Toks, {atom,_,Tag}=Token, From, St) -> epp_reply(From, {error,{loc(T),epp,{bad,Tag}}}), wait_req_scan(St). +%% scan a feature directive +scan_feature([{'(', _Ap}, {atom, _Am, Ftr}, + {',', _}, {atom, _, Ind}, {')', _}, {dot, _}], + Feature, From, St) + when St#epp.in_prefix, + (Ind =:= enable + orelse Ind =:= disable) -> + case update_features(St, Ind, Ftr, loc(Feature)) of + {ok, St1} -> + scan_toks(From, St1); + {error, {{Mod, Reason}, ErrLoc}} -> + epp_reply(From, {error, {ErrLoc, Mod, Reason}}), + wait_req_scan(St) + end; +scan_feature([{'(', _Ap}, {atom, _Am, _Ind}, + {',', _}, {atom, _, _Ftr}, {')', _}, {dot, _}| _Toks], + Feature, From, St) when not St#epp.in_prefix -> + epp_reply(From, {error, {loc(Feature), epp, + ftr_after_prefix}}), + wait_req_scan(St); +scan_feature(Toks, {atom, _, Tag} = Token, From, St) -> + T = no_match(Toks, Token), + epp_reply(From, {error,{loc(T),epp,{bad,Tag}}}), + wait_req_scan(St). + +update_features(St0, Ind, Ftr, Loc) -> + Ftrs0 = St0#epp.features, + ScanOpts0 = St0#epp.erl_scan_opts, + KeywordFun = + case proplists:get_value(reserved_word_fun, ScanOpts0) of + undefined -> fun erl_scan:f_reserved_word/1; + Fun -> Fun + end, + case erl_features:keyword_fun(Ind, Ftr, Ftrs0, KeywordFun) of + {error, Reason} -> + {error, {Reason, Loc}}; + {ok, {Ftrs1, ResWordFun1}} -> + Macs0 = St0#epp.macs, + Macs1 = Macs0#{'FEATURE_ENABLED' => [ftr_macro(Ftrs1)]}, + ScanOpts1 = proplists:delete(reserved_word_fun, ScanOpts0), + St = St0#epp{erl_scan_opts = + [{reserved_word_fun, ResWordFun1}| ScanOpts1], + features = Ftrs1, + else_reserved = ResWordFun1('else'), + macs = Macs1}, + {ok, St} + end. + %% scan_define(Tokens, DefineToken, From, EppState) scan_define([{'(',_Ap},{Type,_Am,_}=Mac|Toks], Def, From, St) @@ -1298,9 +1496,9 @@ scan_file(Tokens0, Tf, From, St) -> scan_file1([{'(',_Alp},{string,_As,Name},{',',_Ac},{integer,_Ai,Ln},{')',_Arp}, {dot,_Ad}], Tf, From, St) -> Anno = erl_anno:new(Ln), - enter_file_reply(From, Name, Anno, loc(Tf), generated), + enter_file_reply(From, Name, Anno, loc(Tf), generated, St#epp.deterministic), Ms0 = St#epp.macs, - Ms = Ms0#{'FILE':={none,[{string,line1(),Name}]}}, + Ms = Ms0#{'FILE':={none,[{string,line1(),source_name(St,Name)}]}}, Locf = loc(Tf), NewLoc = new_location(Ln, St#epp.location, Locf), Delta = get_line(element(2, Tf))-Ln + St#epp.delta, @@ -1320,7 +1518,8 @@ new_location(Ln, {Le,_}, {Lf,_}) -> %% nested conditionals and repeated 'else's. skip_toks(From, St, [I|Sis]) -> - case io:scan_erl_form(St#epp.file, '', St#epp.location) of + ElseReserved = St#epp.else_reserved, + case io:scan_erl_form(St#epp.file, '', St#epp.location, St#epp.erl_scan_opts) of {ok,[{'-',_Ah},{atom,_Ai,ifdef}|_Toks],Cl} -> skip_toks(From, St#epp{location=Cl}, [ifdef,I|Sis]); {ok,[{'-',_Ah},{atom,_Ai,ifndef}|_Toks],Cl} -> @@ -1329,6 +1528,9 @@ skip_toks(From, St, [I|Sis]) -> skip_toks(From, St#epp{location=Cl}, ['if',I|Sis]); {ok,[{'-',_Ah},{atom,_Ae,'else'}=Else|_Toks],Cl}-> skip_else(Else, From, St#epp{location=Cl}, [I|Sis]); + %% conditionally allow else as reserved word + {ok,[{'-',_Ah},{'else',_Ae}=Else|_Toks],Cl} when ElseReserved -> + skip_else(Else, From, St#epp{location=Cl}, [I|Sis]); {ok,[{'-',_Ah},{atom,_Ae,'elif'}=Elif|Toks],Cl}-> skip_elif(Toks, Elif, From, St#epp{location=Cl}, [I|Sis]); {ok,[{'-',_Ah},{atom,_Ae,endif}|_Toks],Cl} -> @@ -1915,3 +2117,12 @@ interpret_file_attr([Form0 | Forms], Delta, Fs) -> [Form | interpret_file_attr(Forms, Delta, Fs)]; interpret_file_attr([], _Delta, _Fs) -> []. + +-spec source_name(#epp{} | boolean(), file:filename_all()) -> file:filename_all(). +source_name(Deterministic, Name) when is_boolean(Deterministic) -> + case Deterministic of + true -> filename:basename(Name); + false -> Name + end; +source_name(St, Name) -> + source_name(St#epp.deterministic, Name). diff --git a/lib/stdlib/src/erl_anno.erl b/lib/stdlib/src/erl_anno.erl index d0310f52e2c8..356417aa72f7 100644 --- a/lib/stdlib/src/erl_anno.erl +++ b/lib/stdlib/src/erl_anno.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -361,7 +361,7 @@ anno_info(Anno, Item, Default) -> Value catch _:_ -> - erlang:error(badarg, [Anno]) + erlang:error(badarg, [Anno, Item, Default]) end. anno_info(Anno, Item) -> @@ -372,7 +372,7 @@ anno_info(Anno, Item) -> undefined catch _:_ -> - erlang:error(badarg, [Anno]) + erlang:error(badarg, [Anno, Item]) end. end_location("", Line, Column) -> diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl index 9701f772927e..991efd444218 100644 --- a/lib/stdlib/src/erl_compile.erl +++ b/lib/stdlib/src/erl_compile.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -55,7 +55,8 @@ compile_cmdline() -> compile_cmdline1(List). %% Run a compilation. Meant to be used by the compilation server. --spec compile(list(), file:filename()) -> 'ok' | {'error', binary()}. +-spec compile(list(), file:filename()) -> + 'ok' | {'error', binary()} | {'crash', {atom(), term(), term()}}. compile(Args, Cwd) -> try compile1(Args, #options{outdir=Cwd,cwd=Cwd}) of ok -> @@ -101,13 +102,16 @@ compile1(["-"++Option|T], Opts) -> compile1(["+"++Option|Rest], Opts) -> Term = make_term(Option), Specific = Opts#options.specific, - compile1(Rest, Opts#options{specific=[Term|Specific]}); + compile1(Rest, Opts#options{specific=Specific++[Term]}); compile1(Files, Opts) -> compile2(Files, Opts). parse_generic_option("b"++Opt, T0, Opts) -> {OutputType,T} = get_option("b", Opt, T0), compile1(T, Opts#options{output_type=list_to_atom(OutputType)}); +%% parse_generic_option("c"++Opt, T0, Opts) -> +%% {InputType,T} = get_option("c", Opt, T0), +%% compile1(T, Opts#options{input_type=[$.| InputType]}); parse_generic_option("D"++Opt, T0, #options{defines=Defs}=Opts) -> {Val0,T} = get_option("D", Opt, T0), {Key0,Val1} = split_at_equals(Val0, []), @@ -170,6 +174,25 @@ parse_generic_option("P", T, #options{specific=Spec}=Opts) -> compile1(T, Opts#options{specific=['P'|Spec]}); parse_generic_option("S", T, #options{specific=Spec}=Opts) -> compile1(T, Opts#options{specific=['S'|Spec]}); +parse_generic_option("enable-feature" ++ Str, T0, + #options{specific = Spec} = Opts) -> + {FtrStr, T} = get_option("enable-feature", Str, T0), + Feature = list_to_atom(FtrStr), + compile1(T, Opts#options{ + specific = Spec ++ [{feature, Feature, enable}]}); +parse_generic_option("disable-feature" ++ Str, T0, + #options{specific = Spec} = Opts) -> + {FtrStr, T} = get_option("disable-feature", Str, T0), + Feature = list_to_atom(FtrStr), + compile1(T, Opts#options{specific = Spec ++ [{feature, Feature, disable}]}); +parse_generic_option("describe-feature" ++ Str, T0, + #options{specific = Spec} = Opts) -> + {FtrStr, T} = get_option("disable-feature", Str, T0), + Feature = list_to_atom(FtrStr), + compile1(T, Opts#options{specific =[{describe_feature, Feature}| Spec]}); +parse_generic_option("list-features", T, + #options{specific = Spec} = Opts) -> + compile1(T, Opts#options{specific =[{list_features, true}| Spec]}); parse_generic_option(Option, _T, _Opts) -> usage(io_lib:format("Unknown option: -~ts\n", [Option])). @@ -229,11 +252,24 @@ usage(Error) -> {"-E","generate listing of expanded code (Erlang compiler)"}, {"-S","generate assembly listing (Erlang compiler)"}, {"-P","generate listing of preprocessed code (Erlang compiler)"}, + {"-enable-feature ", + "enable when compiling (Erlang compiler)"}, + {"-disable-feature ", + "disable when compiling (Erlang compiler)"}, + {"-list-features", + "list short descriptions of available features (Erlang compiler)"}, + {"-describe-feature ", + "show long description of "}, {"+term","pass the Erlang term unchanged to the compiler"}], + Fmt = fun(K, D) when length(K) < 15 -> + io_lib:format("~-14s ~s\n", [K, D]); + (K, D) -> + io_lib:format("~s\n~-14s ~s\n", [K, "", D]) + end, Msg = [Error, "Usage: erlc [Options] file.ext ...\n", "Options:\n", - [io_lib:format("~-14s ~s\n", [K,D]) || {K,D} <- H]], + [Fmt(K, D) || {K,D} <- H]], throw({error, Msg}). get_option(_Name, [], [[C|_]=Option|T]) when C =/= $- -> @@ -251,14 +287,19 @@ split_at_equals([], Acc) -> {lists:reverse(Acc),[]}. compile2(Files, #options{cwd=Cwd,includes=Incl,outfile=Outfile}=Opts0) -> - Opts = Opts0#options{includes=lists:reverse(Incl)}, - case {Outfile,length(Files)} of - {"", _} -> - compile3(Files, Cwd, Opts); - {[_|_], 1} -> - compile3(Files, Cwd, Opts); - {[_|_], _N} -> - throw({error, "Output file name given, but more than one input file.\n"}) + case show_info(Opts0) of + {ok, Msg} -> + throw({error, Msg}); + false -> + Opts = Opts0#options{includes=lists:reverse(Incl)}, + case {Outfile,length(Files)} of + {"", _} -> + compile3(Files, Cwd, Opts); + {[_|_], 1} -> + compile3(Files, Cwd, Opts); + {[_|_], _N} -> + throw({error, "Output file name given, but more than one input file.\n"}) + end end. %% Compile the list of files, until done or compilation fails. @@ -277,6 +318,35 @@ compile3([File|Rest], Cwd, Options) -> compile3(Rest, Cwd, Options); compile3([], _Cwd, _Options) -> ok. +show_info(#options{specific = Spec}) -> + G = fun G0([]) -> undefined; + G0([E|Es]) -> + case proplists:get_value(E, Spec) of + undefined -> G0(Es); + V -> {E, V} + end + end, + + case G([list_features, describe_feature]) of + {list_features, true} -> + Features = erl_features:configurable(), + Msg = ["Available features:\n", + [io_lib:format(" ~-18s ~s\n", [Ftr, erl_features:short(Ftr)]) + || Ftr <- Features]], + {ok, Msg}; + {describe_feature, Ftr} -> + Description = + try + erl_features:long(Ftr) + catch + error:invalid_feature -> + io_lib:format("Unknown feature: ~p\n", [Ftr]) + end, + {ok, Description}; + _ -> + false + end. + %% Invoke the appropriate compiler, depending on the file extension. compile_file("", Input, _Output, _Options) -> throw({error, io_lib:format("File has no extension: ~ts~n", [Input])}); diff --git a/lib/stdlib/src/erl_error.erl b/lib/stdlib/src/erl_error.erl index 7d5d9d8ae730..cd8a8b737b68 100644 --- a/lib/stdlib/src/erl_error.erl +++ b/lib/stdlib/src/erl_error.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -216,6 +216,8 @@ explain_reason({case_clause,V}, error=Cl, [], PF, S, _Enc, CL) -> %% "there is no case clause with a true guard sequence and a %% pattern matching..." format_value(V, <<"no case clause matching ">>, Cl, PF, S, CL); +explain_reason({else_clause,V}, error=Cl, [], PF, S, _Enc, CL) -> + format_value(V, <<"no else clause matching ">>, Cl, PF, S, CL); explain_reason(function_clause, error, [{F,A}], _PF, _S, _Enc, _CL) -> %% Shell commands FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]), @@ -269,6 +271,8 @@ explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc, _CL) -> <<"restricted shell starts now">>; explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc, _CL) -> <<"restricted shell stopped">>; +explain_reason(calling_self, exit, [], _PF, _S, _Enc, _CL) -> + <<"the current process attempted to call itself">>; %% Other exit code: explain_reason(Reason, Class, [], PF, S, _Enc, CL) -> {L, _} = PF(Reason, (iolist_size(S)+1) + exited_size(Class), CL), @@ -319,7 +323,7 @@ format_stacktrace2(S, [{M,F,As,_Info}|Fs], N, PF, Enc, CL, Reason, ErrorMap) [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A, Enc), CalledAs, C, FormattedError]), - CL1 = sub(CL, Enc, Cs), + CL1 = sub(CL, Cs, Enc), [Cs | format_stacktrace2(S, Fs, N + 1, PF, Enc, CL1, Reason, #{})]; format_stacktrace2(_S, [], _N, _PF, _Enc, _CL, _Reason, _ErrorMap) -> "". diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index df2e6a25a196..f88cba1ba3da 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -24,8 +24,7 @@ -export([exprs/2,exprs/3,exprs/4,expr/2,expr/3,expr/4,expr/5, expr_list/2,expr_list/3,expr_list/4]). -export([new_bindings/0,bindings/1,binding/2,add_binding/3,del_binding/2]). --export([extended_parse_exprs/1, extended_parse_term/1, - subst_values_for_vars/2]). +-export([extended_parse_exprs/1, extended_parse_term/1]). -export([is_constant_expr/1, partial_eval/1, eval_str/1]). %% Is used by standalone Erlang (escript). @@ -62,14 +61,17 @@ -type(func_spec() :: {Module :: module(), Function :: atom()} | function()). -type(nlfun_handler() :: fun((FuncSpec :: func_spec(), - Arguments :: [term()]) -> - term())). + Arguments :: [term()]) -> term()) + | fun((Anno :: erl_anno:anno(), FuncSpec :: func_spec(), + Arguments :: [term()]) -> term())). -type(non_local_function_handler() :: {value, nlfun_handler()} | none). -define(STACKTRACE, element(2, erlang:process_info(self(), current_stacktrace))). +empty_fun_used_vars() -> #{}. + %% exprs(ExpressionSeq, Bindings) %% exprs(ExpressionSeq, Bindings, LocalFuncHandler) %% exprs(ExpressionSeq, Bindings, LocalFuncHandler, ExternalFuncHandler) @@ -88,8 +90,8 @@ NewBindings :: binding_struct()). exprs(Exprs, Bs) -> case check_command(Exprs, Bs) of - ok -> - exprs(Exprs, Bs, none, none, none); + ok -> + exprs(Exprs, Bs, none, none, none, empty_fun_used_vars()); {error,{_Location,_Mod,Error}} -> erlang:raise(error, Error, ?STACKTRACE) end. @@ -102,7 +104,7 @@ exprs(Exprs, Bs) -> Value :: value(), NewBindings :: binding_struct()). exprs(Exprs, Bs, Lf) -> - exprs(Exprs, Bs, Lf, none, none). + exprs(Exprs, Bs, Lf, none, none, empty_fun_used_vars()). -spec(exprs(Expressions, Bindings, LocalFunctionHandler, NonLocalFunctionHandler) -> @@ -114,14 +116,51 @@ exprs(Exprs, Bs, Lf) -> Value :: value(), NewBindings :: binding_struct()). exprs(Exprs, Bs, Lf, Ef) -> - exprs(Exprs, Bs, Lf, Ef, none). + exprs(Exprs, Bs, Lf, Ef, none, empty_fun_used_vars()). -exprs([E], Bs0, Lf, Ef, RBs) -> - expr(E, Bs0, Lf, Ef, RBs); -exprs([E|Es], Bs0, Lf, Ef, RBs) -> +-spec(exprs(Expressions, Bindings, LocalFunctionHandler, + NonLocalFunctionHandler, ReturnFormat, FunUsedVars) -> + {value, Value, NewBindings} when + Expressions :: expressions(), + Bindings :: binding_struct(), + LocalFunctionHandler :: local_function_handler(), + NonLocalFunctionHandler :: non_local_function_handler(), + ReturnFormat :: none | value, + FunUsedVars :: erl_lint:fun_used_vars(), + Value :: value(), + NewBindings :: binding_struct()). +exprs([E], Bs0, Lf, Ef, RBs, FUVs) -> + expr(E, Bs0, Lf, Ef, RBs, FUVs); +exprs([E|Es], Bs0, Lf, Ef, RBs, FUVs) -> RBs1 = none, - {value,_V,Bs} = expr(E, Bs0, Lf, Ef, RBs1), - exprs(Es, Bs, Lf, Ef, RBs). + {value,_V,Bs} = expr(E, Bs0, Lf, Ef, RBs1, FUVs), + exprs(Es, Bs, Lf, Ef, RBs, FUVs). + +%% maybe_match_exprs(Expression, Bindings, LocalFuncHandler, ExternalFuncHandler) +%% Returns one of: +%% {success,Value} +%% {failure,Value} +%% or raises an exception. + +maybe_match_exprs([{maybe_match,Anno,Lhs,Rhs0}|Es], Bs0, Lf, Ef) -> + {value,Rhs,Bs1} = expr(Rhs0, Bs0, Lf, Ef, none), + case match(Lhs, Rhs, Anno, Bs1, Bs1, Ef) of + {match,Bs} -> + case Es of + [] -> + {success,Rhs}; + [_|_] -> + maybe_match_exprs(Es, Bs, Lf, Ef) + end; + nomatch -> + {failure,Rhs} + end; +maybe_match_exprs([E], Bs0, Lf, Ef) -> + {value,V,_Bs} = expr(E, Bs0, Lf, Ef, none), + {success,V}; +maybe_match_exprs([E|Es], Bs0, Lf, Ef) -> + {value,_V,Bs} = expr(E, Bs0, Lf, Ef, none), + maybe_match_exprs(Es, Bs, Lf, Ef). %% expr(Expression, Bindings) %% expr(Expression, Bindings, LocalFuncHandler) @@ -139,7 +178,7 @@ exprs([E|Es], Bs0, Lf, Ef, RBs) -> NewBindings :: binding_struct()). expr(E, Bs) -> case check_command([E], Bs) of - ok -> + ok -> expr(E, Bs, none, none, none); {error,{_Location,_Mod,Error}} -> erlang:raise(error, Error, ?STACKTRACE) @@ -185,9 +224,9 @@ fun_data(F) when is_function(F) -> case erlang:fun_info(F, module) of {module,?MODULE} -> case erlang:fun_info(F, env) of - {env,[{FBs,_FLf,_FEf,FCs}]} -> + {env,[{_FAnno,FBs,_FLf,_FEf,_FUVs,FCs}]} -> {fun_data,FBs,FCs}; - {env,[{FBs,_FLf,_FEf,FCs,FName}]} -> + {env,[{_FAnno,FBs,_FLf,_FEf,_FUVs,FCs,FName}]} -> {named_fun_data,FBs,FName,FCs} end; _ -> @@ -206,92 +245,105 @@ fun_data(_T) -> ReturnFormat :: none | value, Value :: value(), NewBindings :: binding_struct()). -expr({var,_,V}, Bs, _Lf, _Ef, RBs) -> +expr(Expr, Bs, Lf, Ef, Rbs) -> + expr(Expr, Bs, Lf, Ef, Rbs, empty_fun_used_vars()). + +-spec(expr(Expression, Bindings, LocalFunctionHandler, + NonLocalFunctionHandler, ReturnFormat, FunUsedVars) -> + {value, Value, NewBindings} | Value when + Expression :: expression(), + Bindings :: binding_struct(), + LocalFunctionHandler :: local_function_handler(), + NonLocalFunctionHandler :: non_local_function_handler(), + ReturnFormat :: none | value, + FunUsedVars :: erl_lint:fun_used_vars(), + Value :: value(), + NewBindings :: binding_struct()). +expr({var,Anno,V}, Bs, _Lf, Ef, RBs, _FUVs) -> case binding(V, Bs) of {value,Val} -> ret_expr(Val, Bs, RBs); unbound -> % Cannot not happen if checked by erl_lint - erlang:raise(error, {unbound,V}, ?STACKTRACE) + apply_error({unbound,V}, ?STACKTRACE, Anno, Bs, Ef, RBs) end; -expr({char,_,C}, Bs, _Lf, _Ef, RBs) -> +expr({char,_,C}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr(C, Bs, RBs); -expr({integer,_,I}, Bs, _Lf, _Ef, RBs) -> +expr({integer,_,I}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr(I, Bs, RBs); -expr({float,_,F}, Bs, _Lf, _Ef, RBs) -> +expr({float,_,F}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr(F, Bs, RBs); -expr({atom,_,A}, Bs, _Lf, _Ef, RBs) -> +expr({atom,_,A}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr(A, Bs, RBs); -expr({string,_,S}, Bs, _Lf, _Ef, RBs) -> +expr({string,_,S}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr(S, Bs, RBs); -expr({nil, _}, Bs, _Lf, _Ef, RBs) -> +expr({nil, _}, Bs, _Lf, _Ef, RBs, _FUVs) -> ret_expr([], Bs, RBs); -expr({cons,_,H0,T0}, Bs0, Lf, Ef, RBs) -> - {value,H,Bs1} = expr(H0, Bs0, Lf, Ef, none), - {value,T,Bs2} = expr(T0, Bs0, Lf, Ef, none), - ret_expr([H|T], merge_bindings(Bs1, Bs2), RBs); -expr({lc,_,E,Qs}, Bs, Lf, Ef, RBs) -> - eval_lc(E, Qs, Bs, Lf, Ef, RBs); -expr({bc,_,E,Qs}, Bs, Lf, Ef, RBs) -> - eval_bc(E, Qs, Bs, Lf, Ef, RBs); -expr({tuple,_,Es}, Bs0, Lf, Ef, RBs) -> - {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef), +expr({cons,Anno,H0,T0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,H,Bs1} = expr(H0, Bs0, Lf, Ef, none, FUVs), + {value,T,Bs2} = expr(T0, Bs0, Lf, Ef, none, FUVs), + ret_expr([H|T], merge_bindings(Bs1, Bs2, Anno, Ef), RBs); +expr({lc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) -> + eval_lc(E, Qs, Bs, Lf, Ef, RBs, FUVs); +expr({bc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) -> + eval_bc(E, Qs, Bs, Lf, Ef, RBs, FUVs); +expr({mc,_,E,Qs}, Bs, Lf, Ef, RBs, FUVs) -> + eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs); +expr({tuple,_,Es}, Bs0, Lf, Ef, RBs, FUVs) -> + {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef, FUVs), ret_expr(list_to_tuple(Vs), Bs, RBs); -expr({record_field,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, {undef_record,Name}, ?STACKTRACE); -expr({record_index,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, {undef_record,Name}, ?STACKTRACE); -expr({record,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, {undef_record,Name}, ?STACKTRACE); -expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, {undef_record,Name}, ?STACKTRACE); +expr({record_field,Anno,_,Name,_}, Bs, _Lf, Ef, RBs, _FUVs) -> + apply_error({undef_record,Name}, ?STACKTRACE, Anno, Bs, Ef, RBs); +expr({record_index,Anno,Name,_}, Bs, _Lf, Ef, RBs, _FUVs) -> + apply_error({undef_record,Name}, ?STACKTRACE, Anno, Bs, Ef, RBs); +expr({record,Anno,Name,_}, Bs, _Lf, Ef, RBs, _FUVs) -> + apply_error({undef_record,Name}, ?STACKTRACE, Anno, Bs, Ef, RBs); +expr({record,Anno,_,Name,_}, Bs, _Lf, Ef, RBs, _FUVs) -> + apply_error({undef_record,Name}, ?STACKTRACE, Anno, Bs, Ef, RBs); %% map -expr({map,_,Binding,Es}, Bs0, Lf, Ef, RBs) -> - {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, none), - {Vs,Bs2} = eval_map_fields(Es, Bs0, Lf, Ef), +expr({map,Anno,Binding,Es}, Bs0, Lf, Ef, RBs, FUVs) -> + {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, none, FUVs), + {Vs,Bs2} = eval_map_fields(Es, Bs0, Lf, Ef, FUVs), _ = maps:put(k, v, Map0), %Validate map. Map1 = lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K, V, Mi); ({map_exact,K,V}, Mi) -> maps:update(K, V, Mi) end, Map0, Vs), - ret_expr(Map1, merge_bindings(Bs2, Bs1), RBs); -expr({map,_,Es}, Bs0, Lf, Ef, RBs) -> - {Vs,Bs} = eval_map_fields(Es, Bs0, Lf, Ef), + ret_expr(Map1, merge_bindings(Bs2, Bs1, Anno, Ef), RBs); +expr({map,_,Es}, Bs0, Lf, Ef, RBs, FUVs) -> + {Vs,Bs} = eval_map_fields(Es, Bs0, Lf, Ef, FUVs), ret_expr(lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi) end, maps:new(), Vs), Bs, RBs); -expr({block,_,Es}, Bs, Lf, Ef, RBs) -> - exprs(Es, Bs, Lf, Ef, RBs); -expr({'if',_,Cs}, Bs, Lf, Ef, RBs) -> - if_clauses(Cs, Bs, Lf, Ef, RBs); -expr({'case',_,E,Cs}, Bs0, Lf, Ef, RBs) -> - {value,Val,Bs} = expr(E, Bs0, Lf, Ef, none), - case_clauses(Val, Cs, Bs, Lf, Ef, RBs); -expr({'try',_,B,Cases,Catches,AB}, Bs, Lf, Ef, RBs) -> - try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs); -expr({'receive',_,Cs}, Bs, Lf, Ef, RBs) -> - receive_clauses(Cs, Bs, Lf, Ef, RBs); -expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs) -> - {value,T,Bs} = expr(E, Bs0, Lf, Ef, none), - receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, RBs); -expr({'fun',_Anno,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) -> - {[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef), +expr({block,_,Es}, Bs, Lf, Ef, RBs, FUVs) -> + exprs(Es, Bs, Lf, Ef, RBs, FUVs); +expr({'if',Anno,Cs}, Bs, Lf, Ef, RBs, FUVs) -> + if_clauses(Cs, Anno, Bs, Lf, Ef, RBs, FUVs); +expr({'case',Anno,E,Cs}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,Val,Bs} = expr(E, Bs0, Lf, Ef, none, FUVs), + case_clauses(Val, Cs, Anno, Bs, Lf, Ef, RBs, FUVs); +expr({'try',Anno,B,Cases,Catches,AB}, Bs, Lf, Ef, RBs, FUVs) -> + try_clauses(B, Cases, Catches, AB, Anno, Bs, Lf, Ef, RBs, FUVs); +expr({'receive',_,Cs}, Bs, Lf, Ef, RBs, FUVs) -> + receive_clauses(Cs, Bs, Lf, Ef, RBs, FUVs); +expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,T,Bs} = expr(E, Bs0, Lf, Ef, none, FUVs), + receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, RBs, FUVs); +expr({'fun',_Anno,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs, FUVs) -> + {[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef, FUVs), F = erlang:make_fun(Mod, Name, Arity), - ret_expr(F, Bs, RBs); -expr({'fun',_Anno,{function,Name,Arity}}, _Bs0, _Lf, _Ef, _RBs) -> % R8 + ret_expr(F, Bs, RBs); +expr({'fun',Anno,{function,Name,Arity}}, Bs0, _Lf, Ef, RBs, _FUVs) -> % R8 %% Don't know what to do... - erlang:raise(error, undef, [{?MODULE,Name,Arity}|?STACKTRACE]); -expr({'fun',Anno,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) -> - %% Save only used variables in the function environment. - %% {value,L,V} are hidden while lint finds used variables. - {Ex1, _} = hide_calls(Ex, 0), - {ok,Used} = erl_lint:used_vars([Ex1], bindings(Bs)), - En = filter_bindings(fun(K,_V) -> member(K,Used) end, Bs), - Info = {En,Lf,Ef,Cs}, + apply_error(undef, [{?MODULE,Name,Arity}|?STACKTRACE], Anno, Bs0, Ef, RBs); +expr({'fun',Anno,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs, FUVs) -> + {En,NewFUVs} = fun_used_bindings(Ex, Cs, Bs, FUVs), + Info = {Anno,En,Lf,Ef,NewFUVs,Cs}, + %% This is a really ugly hack! - F = + F = case length(element(3,hd(Cs))) of 0 -> fun () -> eval_fun([], Info) end; 1 -> fun (A) -> eval_fun([A], Info) end; @@ -327,17 +379,14 @@ expr({'fun',Anno,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) -> eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T], Info) end; _Other -> L = erl_anno:location(Anno), - erlang:raise(error, {'argument_limit',{'fun',L,to_terms(Cs)}}, - ?STACKTRACE) + Reason = {'argument_limit',{'fun',L,to_terms(Cs)}}, + apply_error(Reason, ?STACKTRACE, Anno, Bs, Ef, RBs) end, ret_expr(F, Bs, RBs); -expr({named_fun,Anno,Name,Cs} = Ex, Bs, Lf, Ef, RBs) -> - %% Save only used variables in the function environment. - %% {value,L,V} are hidden while lint finds used variables. - {Ex1, _} = hide_calls(Ex, 0), - {ok,Used} = erl_lint:used_vars([Ex1], bindings(Bs)), - En = filter_bindings(fun(K,_V) -> member(K,Used) end, Bs), - Info = {En,Lf,Ef,Cs,Name}, +expr({named_fun,Anno,Name,Cs} = Ex, Bs, Lf, Ef, RBs, FUVs) -> + {En,NewFUVs} = fun_used_bindings(Ex, Cs, Bs, FUVs), + Info = {Anno,En,Lf,Ef,NewFUVs,Cs,Name}, + %% This is a really ugly hack! F = case length(element(3,hd(Cs))) of @@ -380,58 +429,57 @@ expr({named_fun,Anno,Name,Cs} = Ex, Bs, Lf, Ef, RBs) -> RF, Info) end; _Other -> L = erl_anno:location(Anno), - erlang:raise(error, {'argument_limit', - {named_fun,L,Name,to_terms(Cs)}}, - ?STACKTRACE) + Reason = {'argument_limit',{named_fun,L,Name,to_terms(Cs)}}, + apply_error(Reason, ?STACKTRACE, Anno, Bs, Ef, RBs) end, ret_expr(F, Bs, RBs); -expr({call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[{lc,_,_E,_Qs}=LC | As0]}, - Bs0, Lf, Ef, RBs) when length(As0) =< 1 -> +expr({call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[{lc,_,_E,_Qs}=LC | As0]}, + Bs0, Lf, Ef, RBs, FUVs) when length(As0) =< 1 -> %% No expansion or evaluation of module name or function name. MaxLine = find_maxline(LC), {LC1, D} = hide_calls(LC, MaxLine), case qlc:transform_from_evaluator(LC1, Bs0) of {ok,{call,A,Remote,[QLC]}} -> QLC1 = unhide_calls(QLC, MaxLine, D), - expr({call,A,Remote,[QLC1 | As0]}, Bs0, Lf, Ef, RBs); + expr({call,A,Remote,[QLC1 | As0]}, Bs0, Lf, Ef, RBs, FUVs); {not_ok,Error} -> ret_expr(Error, Bs0, RBs) end; expr({call,A1,{remote,A2,{record_field,_,{atom,_,''},{atom,_,qlc}=Mod}, {atom,_,q}=Func}, - [{lc,_,_E,_Qs} | As0]=As}, - Bs, Lf, Ef, RBs) when length(As0) =< 1 -> - expr({call,A1,{remote,A2,Mod,Func},As}, Bs, Lf, Ef, RBs); -expr({call,_,{remote,_,Mod,Func},As0}, Bs0, Lf, Ef, RBs) -> - {value,M,Bs1} = expr(Mod, Bs0, Lf, Ef, none), - {value,F,Bs2} = expr(Func, Bs0, Lf, Ef, none), - {As,Bs3} = expr_list(As0, merge_bindings(Bs1, Bs2), Lf, Ef), + [{lc,_,_E,_Qs} | As0]=As}, + Bs, Lf, Ef, RBs, FUVs) when length(As0) =< 1 -> + expr({call,A1,{remote,A2,Mod,Func},As}, Bs, Lf, Ef, RBs, FUVs); +expr({call,Anno,{remote,_,Mod,Func},As0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,M,Bs1} = expr(Mod, Bs0, Lf, Ef, none, FUVs), + {value,F,Bs2} = expr(Func, Bs0, Lf, Ef, none, FUVs), + {As,Bs3} = expr_list(As0, merge_bindings(Bs1, Bs2, Anno, Ef), Lf, Ef, FUVs), %% M could be a parameterized module (not an atom). case is_atom(M) andalso erl_internal:bif(M, F, length(As)) of true -> - bif(F, As, Bs3, Ef, RBs); + bif(F, As, Anno, Bs3, Ef, RBs); false -> - do_apply(M, F, As, Bs3, Ef, RBs) + do_apply(M, F, As, Anno, Bs3, Ef, RBs) end; -expr({call,_,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs) -> +expr({call,Anno,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs, FUVs) -> case erl_internal:bif(Func, length(As0)) of true -> {As,Bs} = expr_list(As0, Bs0, Lf, Ef), - bif(Func, As, Bs, Ef, RBs); + bif(Func, As, Anno, Bs, Ef, RBs); false -> - local_func(Func, As0, Bs0, Lf, Ef, RBs) + local_func(Func, As0, Anno, Bs0, Lf, Ef, RBs, FUVs) end; -expr({call,_,Func0,As0}, Bs0, Lf, Ef, RBs) -> % function or {Mod,Fun} - {value,Func,Bs1} = expr(Func0, Bs0, Lf, Ef, none), - {As,Bs2} = expr_list(As0, Bs1, Lf, Ef), +expr({call,Anno,Func0,As0}, Bs0, Lf, Ef, RBs, FUVs) -> % function or {Mod,Fun} + {value,Func,Bs1} = expr(Func0, Bs0, Lf, Ef, none, FUVs), + {As,Bs2} = expr_list(As0, Bs1, Lf, Ef, FUVs), case Func of {M,F} when is_atom(M), is_atom(F) -> - erlang:raise(error, {badfun,Func}, ?STACKTRACE); + apply_error({badfun,Func}, ?STACKTRACE, Anno, Bs0, Ef, RBs); _ -> - do_apply(Func, As, Bs2, Ef, RBs) + do_apply(Func, As, Anno, Bs2, Ef, RBs) end; -expr({'catch',_,Expr}, Bs0, Lf, Ef, RBs) -> - try expr(Expr, Bs0, Lf, Ef, none) of +expr({'catch',_,Expr}, Bs0, Lf, Ef, RBs, FUVs) -> + try expr(Expr, Bs0, Lf, Ef, none, FUVs) of {value,V,Bs} -> ret_expr(V, Bs, RBs) catch @@ -442,48 +490,65 @@ expr({'catch',_,Expr}, Bs0, Lf, Ef, RBs) -> error:Reason:Stacktrace -> ret_expr({'EXIT',{Reason,Stacktrace}}, Bs0, RBs) end; -expr({match,_,Lhs,Rhs0}, Bs0, Lf, Ef, RBs) -> - {value,Rhs,Bs1} = expr(Rhs0, Bs0, Lf, Ef, none), - case match(Lhs, Rhs, Bs1) of +expr({match,Anno,Lhs,Rhs0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,Rhs,Bs1} = expr(Rhs0, Bs0, Lf, Ef, none, FUVs), + case match(Lhs, Rhs, Anno, Bs1, Bs1, Ef) of {match,Bs} -> ret_expr(Rhs, Bs, RBs); - nomatch -> erlang:raise(error, {badmatch,Rhs}, ?STACKTRACE) + nomatch -> apply_error({badmatch,Rhs}, ?STACKTRACE, Anno, Bs0, Ef, RBs) + end; +expr({'maybe',_,Es}, Bs, Lf, Ef, RBs, _FUVs) -> + {_,Val} = maybe_match_exprs(Es, Bs, Lf, Ef), + ret_expr(Val, Bs, RBs); +expr({'maybe',Anno,Es,{'else',_,Cs}}, Bs0, Lf, Ef, RBs, FUVs) -> + case maybe_match_exprs(Es, Bs0, Lf, Ef) of + {success,Val} -> + ret_expr(Val, Bs0, RBs); + {failure,Val} -> + case match_clause(Cs, [Val], Bs0, Lf, Ef) of + {B, Bs} -> + exprs(B, Bs, Lf, Ef, RBs, FUVs); + nomatch -> + apply_error({else_clause,Val}, ?STACKTRACE, Anno, Bs0, Ef, RBs) + end end; -expr({op,_,Op,A0}, Bs0, Lf, Ef, RBs) -> - {value,A,Bs} = expr(A0, Bs0, Lf, Ef, none), - eval_op(Op, A, Bs, Ef, RBs); -expr({op,_,'andalso',L0,R0}, Bs0, Lf, Ef, RBs) -> - {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none), +expr({op,Anno,Op,A0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,A,Bs} = expr(A0, Bs0, Lf, Ef, none, FUVs), + eval_op(Op, A, Anno, Bs, Ef, RBs); +expr({op,Anno,'andalso',L0,R0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs), V = case L of true -> - {value,R,_} = expr(R0, Bs1, Lf, Ef, none), + {value,R,_} = expr(R0, Bs1, Lf, Ef, none, FUVs), R; false -> false; - _ -> erlang:raise(error, {badarg,L}, ?STACKTRACE) + _ -> apply_error({badarg,L}, ?STACKTRACE, Anno, Bs0, Ef, RBs) end, ret_expr(V, Bs1, RBs); -expr({op,_,'orelse',L0,R0}, Bs0, Lf, Ef, RBs) -> - {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none), +expr({op,Anno,'orelse',L0,R0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs), V = case L of true -> true; false -> - {value,R,_} = expr(R0, Bs1, Lf, Ef, none), + {value,R,_} = expr(R0, Bs1, Lf, Ef, none, FUVs), R; - _ -> erlang:raise(error, {badarg,L}, ?STACKTRACE) + _ -> apply_error({badarg,L}, ?STACKTRACE, Anno, Bs0, Ef, RBs) end, ret_expr(V, Bs1, RBs); -expr({op,_,Op,L0,R0}, Bs0, Lf, Ef, RBs) -> - {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none), - {value,R,Bs2} = expr(R0, Bs0, Lf, Ef, none), - eval_op(Op, L, R, merge_bindings(Bs1, Bs2), Ef, RBs); -expr({bin,_,Fs}, Bs0, Lf, Ef, RBs) -> - EvalFun = fun(E, B) -> expr(E, B, Lf, Ef, none) end, - {value,V,Bs} = eval_bits:expr_grp(Fs, Bs0, EvalFun), +expr({op,Anno,Op,L0,R0}, Bs0, Lf, Ef, RBs, FUVs) -> + {value,L,Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs), + {value,R,Bs2} = expr(R0, Bs0, Lf, Ef, none, FUVs), + eval_op(Op, L, R, Anno, merge_bindings(Bs1, Bs2, Anno, Ef), Ef, RBs); +expr({bin,_,Fs}, Bs0, Lf, Ef, RBs, FUVs) -> + EvalFun = fun(E, B) -> expr(E, B, Lf, Ef, none, FUVs) end, + ErrorFun = fun(A, R, S) -> apply_error(R, S, A, Bs0, Ef, RBs) end, + {value,V,Bs} = eval_bits:expr_grp(Fs, Bs0, EvalFun, ErrorFun), ret_expr(V, Bs, RBs); -expr({remote,_,_,_}, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, {badexpr,':'}, ?STACKTRACE); -expr({value,_,Val}, Bs, _Lf, _Ef, RBs) -> % Special case straight values. - ret_expr(Val, Bs, RBs). +expr({remote,Anno,_,_}, Bs0, _Lf, Ef, RBs, _FUVs) -> + apply_error({badexpr,':'}, ?STACKTRACE, Anno, Bs0, Ef, RBs). + +apply_error(Reason, Stack, Anno, Bs0, Ef, RBs) -> + do_apply(erlang, raise, [error, Reason, Stack], Anno, Bs0, Ef, RBs). find_maxline(LC) -> put('$erl_eval_max_line', 0), @@ -503,43 +568,52 @@ find_maxline(LC) -> _ = erl_parse:map_anno(F, LC), erase('$erl_eval_max_line'). +fun_used_bindings(Fun, Cs, Bs, FUVs) -> + {Used,InnerFUVs} = + case FUVs of + %% If this clause is in our fun used vars tree, + %% then we do not need to compute to traverse it again. + #{Cs := UsedAndFUVs} -> + UsedAndFUVs; + + #{} -> + %% Save only used variables in the function environment. + AllUsedVars = erl_lint:used_vars([Fun], bindings(Bs)), + + %% At the root we should see only a single function, + %% so we extract its used vars and its tree out. + [{_,UsedAndFUVs}] = maps:to_list(AllUsedVars), + UsedAndFUVs + end, + + {filter_bindings(fun(K,_V) -> member(K,Used) end, Bs),InnerFUVs}. + hide_calls(LC, MaxLine) -> LineId0 = MaxLine + 1, {NLC, _, D} = hide(LC, LineId0, maps:new()), {NLC, D}. -%% v/1 and local calls are hidden. -hide({value,L,V}, Id, D) -> - A = erl_anno:new(Id), - {{atom,A,ok}, Id+1, maps:put(Id, {value,L,V}, D)}; +%% Local calls are hidden from qlc so they are not expanded. hide({call,A,{atom,_,N}=Atom,Args}, Id0, D0) -> {NArgs, Id, D} = hide(Args, Id0, D0), C = case erl_internal:bif(N, length(Args)) of true -> {call,A,Atom,NArgs}; - false -> + false -> Anno = erl_anno:new(Id), {call,Anno,{remote,A,{atom,A,m},{atom,A,f}},NArgs} end, {C, Id+1, maps:put(Id, {call,Atom}, D)}; -hide(T0, Id0, D0) when is_tuple(T0) -> +hide(T0, Id0, D0) when is_tuple(T0) -> {L, Id, D} = hide(tuple_to_list(T0), Id0, D0), {list_to_tuple(L), Id, D}; -hide([E0 | Es0], Id0, D0) -> +hide([E0 | Es0], Id0, D0) -> {E, Id1, D1} = hide(E0, Id0, D0), {Es, Id, D} = hide(Es0, Id1, D1), {[E | Es], Id, D}; -hide(E, Id, D) -> +hide(E, Id, D) -> {E, Id, D}. -unhide_calls({atom,A,ok}=E, MaxLine, D) -> - L = erl_anno:line(A), - if - L > MaxLine -> - map_get(L, D); - true -> - E - end; unhide_calls({call,Anno,{remote,A,{atom,A,m},{atom,A,f}}=F,Args}, MaxLine, D) -> Line = erl_anno:line(Anno), @@ -550,84 +624,71 @@ unhide_calls({call,Anno,{remote,A,{atom,A,m},{atom,A,f}}=F,Args}, true -> {call,Anno,F,unhide_calls(Args, MaxLine, D)} end; -unhide_calls(T, MaxLine, D) when is_tuple(T) -> +unhide_calls(T, MaxLine, D) when is_tuple(T) -> list_to_tuple(unhide_calls(tuple_to_list(T), MaxLine, D)); -unhide_calls([E | Es], MaxLine, D) -> +unhide_calls([E | Es], MaxLine, D) -> [unhide_calls(E, MaxLine, D) | unhide_calls(Es, MaxLine, D)]; -unhide_calls(E, _MaxLine, _D) -> +unhide_calls(E, _MaxLine, _D) -> E. -%% local_func(Function, Arguments, Bindings, LocalFuncHandler, -%% ExternalFuncHandler, RBs) -> +%% local_func(Function, Arguments, Anno, Bindings, LocalFuncHandler, +%% ExternalFuncHandler, RBs, FunUsedVars) -> %% {value,Value,Bindings} | Value when %% LocalFuncHandler = {value,F} | {value,F,Eas} | %% {eval,F} | {eval,F,Eas} | none. -local_func(Func, As0, Bs0, {value,F}, Ef, value) -> - {As1,_Bs1} = expr_list(As0, Bs0, {value,F}, Ef), +local_func(Func, As0, _Anno, Bs0, {value,F}, Ef, value, FUVs) -> + {As1,_Bs1} = expr_list(As0, Bs0, {value,F}, Ef, FUVs), %% Make tail recursive calls when possible. F(Func, As1); -local_func(Func, As0, Bs0, {value,F}, Ef, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {value,F}, Ef), +local_func(Func, As0, _Anno, Bs0, {value,F}, Ef, RBs, FUVs) -> + {As1,Bs1} = expr_list(As0, Bs0, {value,F}, Ef, FUVs), ret_expr(F(Func, As1), Bs1, RBs); -local_func(Func, As0, Bs0, {value,F,Eas}, Ef, RBs) -> +local_func(Func, As0, Anno, Bs0, {value,F,Eas}, Ef, RBs, FUVs) -> Fun = fun(Name, Args) -> apply(F, [Name,Args|Eas]) end, - local_func(Func, As0, Bs0, {value, Fun}, Ef, RBs); -local_func(Func, As, Bs, {eval,F}, _Ef, RBs) -> - local_func2(F(Func, As, Bs), RBs); -local_func(Func, As, Bs, {eval,F,Eas}, _Ef, RBs) -> - local_func2(apply(F, [Func,As,Bs|Eas]), RBs); + local_func(Func, As0, Anno, Bs0, {value, Fun}, Ef, RBs, FUVs); +local_func(Func, As, Anno, Bs, {eval,F}, _Ef, RBs, _FUVs) -> + local_func2(F(Func, As, Bs), Anno, RBs); +local_func(Func, As, Anno, Bs, {eval,F,Eas}, _Ef, RBs, _FUVs) -> + local_func2(apply(F, [Func,As,Bs|Eas]), Anno, RBs); %% These two clauses are for backwards compatibility. -local_func(Func, As0, Bs0, {M,F}, Ef, RBs) -> - {As1,Bs1} = expr_list(As0, Bs0, {M,F}, Ef), +local_func(Func, As0, _Anno, Bs0, {M,F}, Ef, RBs, FUVs) -> + {As1,Bs1} = expr_list(As0, Bs0, {M,F}, Ef, FUVs), ret_expr(M:F(Func,As1), Bs1, RBs); -local_func(Func, As, _Bs, {M,F,Eas}, _Ef, RBs) -> - local_func2(apply(M, F, [Func,As|Eas]), RBs); +local_func(Func, As, Anno, _Bs, {M,F,Eas}, _Ef, RBs, _FUVs) -> + local_func2(apply(M, F, [Func,As|Eas]), Anno, RBs); %% Default unknown function handler to undefined function. -local_func(Func, As0, _Bs0, none, _Ef, _RBs) -> - erlang:raise(error, undef, [{?MODULE,Func,length(As0)}|?STACKTRACE]). +local_func(Func, As0, Anno, Bs0, none, Ef, RBs, _FUVs) -> + apply_error(undef, [{?MODULE,Func,length(As0)}|?STACKTRACE], Anno, Bs0, Ef, RBs). -local_func2({value,V,Bs}, RBs) -> +local_func2({value,V,Bs}, _Anno, RBs) -> ret_expr(V, Bs, RBs); -local_func2({eval,F,As,Bs}, RBs) -> % This reply is not documented. +local_func2({eval,F,As,Bs}, Anno, RBs) -> % This reply is not documented. %% The shell found F. erl_eval tries to do a tail recursive call, %% something the shell cannot do. Do not use Ef here. - do_apply(F, As, Bs, none, RBs). + do_apply(F, As, Anno, Bs, none, RBs). %% bif(Name, Arguments, RBs) %% Evaluate the Erlang auto-imported function Name. erlang:apply/2,3 %% are "hidden" from the external function handler. -bif(apply, [erlang,apply,As], Bs, Ef, RBs) -> - bif(apply, As, Bs, Ef, RBs); -bif(apply, [M,F,As], Bs, Ef, RBs) -> - do_apply(M, F, As, Bs, Ef, RBs); -bif(apply, [F,As], Bs, Ef, RBs) -> - do_apply(F, As, Bs, Ef, RBs); -bif(Name, As, Bs, Ef, RBs) -> - do_apply(erlang, Name, As, Bs, Ef, RBs). +bif(apply, [erlang,apply,As], Anno, Bs, Ef, RBs) -> + bif(apply, As, Anno, Bs, Ef, RBs); +bif(apply, [M,F,As], Anno, Bs, Ef, RBs) -> + do_apply(M, F, As, Anno, Bs, Ef, RBs); +bif(apply, [F,As], Anno, Bs, Ef, RBs) -> + do_apply(F, As, Anno, Bs, Ef, RBs); +bif(Name, As, Anno, Bs, Ef, RBs) -> + do_apply(erlang, Name, As, Anno, Bs, Ef, RBs). -%% do_apply(MF, Arguments, Bindings, ExternalFuncHandler, RBs) -> +%% do_apply(Func, Arguments, Bindings, ExternalFuncHandler, RBs) -> %% {value,Value,Bindings} | Value when -%% ExternalFuncHandler = {value,F} | none. -%% MF is a tuple {Module,Function} or a fun. +%% ExternalFuncHandler = {value,F} | none, +%% Func = fun() -do_apply({M,F}=Func, As, Bs0, Ef, RBs) - when tuple_size(M) >= 1, is_atom(element(1, M)), is_atom(F) -> - case Ef of - none when RBs =:= value -> - %% Make tail recursive calls when possible. - apply(M, F, As); - none -> - ret_expr(apply(M, F, As), Bs0, RBs); - {value,Fun} when RBs =:= value -> - Fun(Func, As); - {value,Fun} -> - ret_expr(Fun(Func, As), Bs0, RBs) - end; -do_apply(Func, As, Bs0, Ef, RBs) -> +do_apply(Func, As, Anno, Bs0, Ef, RBs) -> Env = if - is_function(Func) -> + is_function(Func) -> case {erlang:fun_info(Func, module), erlang:fun_info(Func, env)} of {{module,?MODULE},{env,Env1}} when Env1 =/= [] -> @@ -635,12 +696,12 @@ do_apply(Func, As, Bs0, Ef, RBs) -> _ -> no_env end; - true -> + true -> no_env end, case {Env,Ef} of - {{env,[{FBs,FLf,FEf,FCs}]},_} -> - %% If we are evaluting within another function body + {{env,[{FAnno,FBs,FLf,FEf,FFUVs,FCs}]},_} -> + %% If we are evaluting within another function body %% (RBs =/= none), we return RBs when this function body %% has been evalutated, otherwise we return Bs0, the %% bindings when evalution of this function body started. @@ -650,20 +711,20 @@ do_apply(Func, As, Bs0, Ef, RBs) -> end, case {erlang:fun_info(Func, arity), length(As)} of {{arity, Arity}, Arity} -> - eval_fun(FCs, As, FBs, FLf, FEf, NRBs); + eval_fun(FCs, As, FAnno, FBs, FLf, FEf, NRBs, FFUVs); _ -> - erlang:raise(error, {badarity,{Func,As}},?STACKTRACE) + apply_error({badarity,{Func,As}}, ?STACKTRACE, Anno, Bs0, Ef, RBs) end; - {{env,[{FBs,FLf,FEf,FCs,FName}]},_} -> + {{env,[{FAnno,FBs,FLf,FEf,FFUVs,FCs,FName}]},_} -> NRBs = if RBs =:= none -> Bs0; true -> RBs end, case {erlang:fun_info(Func, arity), length(As)} of {{arity, Arity}, Arity} -> - eval_named_fun(FCs, As, FBs, FLf, FEf, FName, Func, NRBs); + eval_named_fun(FCs, As, FAnno, FBs, FLf, FEf, FName, Func, NRBs, FFUVs); _ -> - erlang:raise(error, {badarity,{Func,As}},?STACKTRACE) + apply_error({badarity,{Func,As}}, ?STACKTRACE, Anno, Bs0, Ef, RBs) end; {no_env,none} when RBs =:= value -> %% Make tail recursive calls when possible. @@ -671,12 +732,12 @@ do_apply(Func, As, Bs0, Ef, RBs) -> {no_env,none} -> ret_expr(apply(Func, As), Bs0, RBs); {no_env,{value,F}} when RBs =:= value -> - F(Func,As); + do_apply(F, Anno, Func, As); {no_env,{value,F}} -> - ret_expr(F(Func, As), Bs0, RBs) + ret_expr(do_apply(F, Anno, Func, As), Bs0, RBs) end. -do_apply(Mod, Func, As, Bs0, Ef, RBs) -> +do_apply(Mod, Func, As, Anno, Bs0, Ef, RBs) -> case Ef of none when RBs =:= value -> %% Make tail recursive calls when possible. @@ -684,86 +745,150 @@ do_apply(Mod, Func, As, Bs0, Ef, RBs) -> none -> ret_expr(apply(Mod, Func, As), Bs0, RBs); {value,F} when RBs =:= value -> - F({Mod,Func}, As); + do_apply(F, Anno, {Mod,Func}, As); {value,F} -> - ret_expr(F({Mod,Func}, As), Bs0, RBs) + ret_expr(do_apply(F, Anno, {Mod,Func}, As), Bs0, RBs) end. -%% eval_lc(Expr, [Qualifier], Bindings, LocalFunctionHandler, +do_apply(F, Anno, FunOrModFun, Args) when is_function(F, 3) -> + F(Anno, FunOrModFun, Args); +do_apply(F, _Anno, FunOrModFun, Args) when is_function(F, 2) -> + F(FunOrModFun, Args). + +%% eval_lc(Expr, [Qualifier], Bindings, LocalFunctionHandler, %% ExternalFuncHandler, RetBindings) -> %% {value,Value,Bindings} | Value -eval_lc(E, Qs, Bs, Lf, Ef, RBs) -> - ret_expr(lists:reverse(eval_lc1(E, Qs, Bs, Lf, Ef, [])), Bs, RBs). - -eval_lc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> - {value,L1,_Bs1} = expr(L0, Bs0, Lf, Ef, none), - CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_generate(L1, P, Bs0, Lf, Ef, CompFun, Acc0); -eval_lc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> - {value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none), - CompFun = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0); -eval_lc1(E, [F|Qs], Bs0, Lf, Ef, Acc) -> - CompFun = fun(Bs) -> eval_lc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_filter(F, Bs0, Lf, Ef, CompFun, Acc); -eval_lc1(E, [], Bs, Lf, Ef, Acc) -> - {value,V,_} = expr(E, Bs, Lf, Ef, none), +eval_lc(E, Qs, Bs, Lf, Ef, RBs, FUVs) -> + ret_expr(lists:reverse(eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, [])), Bs, RBs). + +eval_lc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> + case is_generator(Q) of + true -> + CF = fun(Bs, Acc) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end, + eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF); + false -> + CF = fun(Bs) -> eval_lc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end, + eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0) + end; +eval_lc1(E, [], Bs, Lf, Ef, FUVs, Acc) -> + {value,V,_} = expr(E, Bs, Lf, Ef, none, FUVs), [V|Acc]. -%% eval_bc(Expr, [Qualifier], Bindings, LocalFunctionHandler, +%% eval_bc(Expr, [Qualifier], Bindings, LocalFunctionHandler, %% ExternalFuncHandler, RetBindings) -> %% {value,Value,Bindings} | Value -eval_bc(E, Qs, Bs, Lf, Ef, RBs) -> - ret_expr(eval_bc1(E, Qs, Bs, Lf, Ef, <<>>), Bs, RBs). - -eval_bc1(E, [{b_generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> - {value,Bin,_Bs1} = expr(L0, Bs0, Lf, Ef, none), - CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_b_generate(Bin, P, Bs0, Lf, Ef, CompFun, Acc0); -eval_bc1(E, [{generate,_,P,L0}|Qs], Bs0, Lf, Ef, Acc0) -> - {value,List,_Bs1} = expr(L0, Bs0, Lf, Ef, none), - CompFun = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_generate(List, P, Bs0, Lf, Ef, CompFun, Acc0); -eval_bc1(E, [F|Qs], Bs0, Lf, Ef, Acc) -> - CompFun = fun(Bs) -> eval_bc1(E, Qs, Bs, Lf, Ef, Acc) end, - eval_filter(F, Bs0, Lf, Ef, CompFun, Acc); -eval_bc1(E, [], Bs, Lf, Ef, Acc) -> - {value,V,_} = expr(E, Bs, Lf, Ef, none), +eval_bc(E, Qs, Bs, Lf, Ef, RBs, FUVs) -> + ret_expr(eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, <<>>), Bs, RBs). + +eval_bc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> + case is_generator(Q) of + true -> + CF = fun(Bs, Acc) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end, + eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF); + false -> + CF = fun(Bs) -> eval_bc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end, + eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0) + end; +eval_bc1(E, [], Bs, Lf, Ef, FUVs, Acc) -> + {value,V,_} = expr(E, Bs, Lf, Ef, none, FUVs), <>. -eval_generate([V|Rest], P, Bs0, Lf, Ef, CompFun, Acc) -> - case match(P, V, new_bindings(Bs0), Bs0) of +%% eval_mc(Expr, [Qualifier], Bindings, LocalFunctionHandler, +%% ExternalFuncHandler, RetBindings) -> +%% {value,Value,Bindings} | Value + +eval_mc(E, Qs, Bs, Lf, Ef, RBs, FUVs) -> + L = eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, []), + Map = maps:from_list(L), + ret_expr(Map, Bs, RBs). + +eval_mc1(E, [Q|Qs], Bs0, Lf, Ef, FUVs, Acc0) -> + case is_generator(Q) of + true -> + CF = fun(Bs, Acc) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc) end, + eval_generator(Q, Bs0, Lf, Ef, FUVs, Acc0, CF); + false -> + CF = fun(Bs) -> eval_mc1(E, Qs, Bs, Lf, Ef, FUVs, Acc0) end, + eval_filter(Q, Bs0, Lf, Ef, CF, FUVs, Acc0) + end; +eval_mc1({map_field_assoc,Lfa,K0,V0}, [], Bs, Lf, Ef, FUVs, Acc) -> + {value,KV,_} = expr({tuple,Lfa,[K0,V0]}, Bs, Lf, Ef, none, FUVs), + [KV|Acc]. + +eval_generator({generate,Anno,P,L0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) -> + {value,L1,_Bs1} = expr(L0, Bs0, Lf, Ef, none, FUVs), + eval_generate(L1, P, Anno, Bs0, Lf, Ef, CompFun, Acc0); +eval_generator({b_generate,Anno,P,Bin0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) -> + {value,Bin,_Bs1} = expr(Bin0, Bs0, Lf, Ef, none, FUVs), + eval_b_generate(Bin, P, Anno, Bs0, Lf, Ef, CompFun, Acc0); +eval_generator({m_generate,Anno,P,Map0}, Bs0, Lf, Ef, FUVs, Acc0, CompFun) -> + {map_field_exact,_,K,V} = P, + {value,Map,_Bs1} = expr(Map0, Bs0, Lf, Ef, none, FUVs), + Iter = case is_map(Map) of + true -> + maps:iterator(Map); + false -> + %% Validate iterator. + try maps:foreach(fun(_, _) -> ok end, Map) of + _ -> + Map + catch + _:_ -> + apply_error({bad_generator,Map}, ?STACKTRACE, + Anno, Bs0, Ef, none) + end + end, + eval_m_generate(Iter, {tuple,Anno,[K,V]}, Anno, Bs0, Lf, Ef, CompFun, Acc0). + +eval_generate([V|Rest], P, Anno, Bs0, Lf, Ef, CompFun, Acc) -> + case match(P, V, Anno, new_bindings(Bs0), Bs0, Ef) of {match,Bsn} -> Bs2 = add_bindings(Bsn, Bs0), NewAcc = CompFun(Bs2, Acc), - eval_generate(Rest, P, Bs0, Lf, Ef, CompFun, NewAcc); - nomatch -> - eval_generate(Rest, P, Bs0, Lf, Ef, CompFun, Acc) + eval_generate(Rest, P, Anno, Bs0, Lf, Ef, CompFun, NewAcc); + nomatch -> + eval_generate(Rest, P, Anno, Bs0, Lf, Ef, CompFun, Acc) end; -eval_generate([], _P, _Bs0, _Lf, _Ef, _CompFun, Acc) -> +eval_generate([], _P, _Anno, _Bs0, _Lf, _Ef, _CompFun, Acc) -> Acc; -eval_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) -> - erlang:raise(error, {bad_generator,Term}, ?STACKTRACE). +eval_generate(Term, _P, Anno, Bs0, _Lf, Ef, _CompFun, _Acc) -> + apply_error({bad_generator,Term}, ?STACKTRACE, Anno, Bs0, Ef, none). -eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) -> - Mfun = match_fun(Bs0), +eval_b_generate(<<_/bitstring>>=Bin, P, Anno, Bs0, Lf, Ef, CompFun, Acc) -> + Mfun = match_fun(Bs0, Ef), Efun = fun(Exp, Bs) -> expr(Exp, Bs, Lf, Ef, none) end, - case eval_bits:bin_gen(P, Bin, new_bindings(Bs0), Bs0, Mfun, Efun) of + ErrorFun = fun(A, R, S) -> apply_error(R, S, A, Bs0, Ef, none) end, + case eval_bits:bin_gen(P, Bin, new_bindings(Bs0), Bs0, Mfun, Efun, ErrorFun) of {match, Rest, Bs1} -> Bs2 = add_bindings(Bs1, Bs0), NewAcc = CompFun(Bs2, Acc), - eval_b_generate(Rest, P, Bs0, Lf, Ef, CompFun, NewAcc); + eval_b_generate(Rest, P, Anno, Bs0, Lf, Ef, CompFun, NewAcc); {nomatch, Rest} -> - eval_b_generate(Rest, P, Bs0, Lf, Ef, CompFun, Acc); + eval_b_generate(Rest, P, Anno, Bs0, Lf, Ef, CompFun, Acc); done -> Acc end; -eval_b_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) -> - erlang:raise(error, {bad_generator,Term}, ?STACKTRACE). +eval_b_generate(Term, _P, Anno, Bs0, _Lf, Ef, _CompFun, _Acc) -> + apply_error({bad_generator,Term}, ?STACKTRACE, Anno, Bs0, Ef, none). + +eval_m_generate(Iter0, P, Anno, Bs0, Lf, Ef, CompFun, Acc0) -> + case maps:next(Iter0) of + {K,V,Iter} -> + case match(P, {K,V}, Anno, new_bindings(Bs0), Bs0, Ef) of + {match,Bsn} -> + Bs2 = add_bindings(Bsn, Bs0), + Acc = CompFun(Bs2, Acc0), + eval_m_generate(Iter, P, Anno, Bs0, Lf, Ef, CompFun, Acc); + nomatch -> + eval_m_generate(Iter, P, Anno, Bs0, Lf, Ef, CompFun, Acc0) + end; + none -> + Acc0 + end. -eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) -> +eval_filter(F, Bs0, Lf, Ef, CompFun, FUVs, Acc) -> case erl_lint:is_guard_test(F) of true -> case guard_test(F, Bs0, Lf, Ef) of @@ -771,30 +896,35 @@ eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) -> {value,false,_} -> Acc end; false -> - case expr(F, Bs0, Lf, Ef, none) of + case expr(F, Bs0, Lf, Ef, none, FUVs) of {value,true,Bs1} -> CompFun(Bs1); {value,false,_} -> Acc; - {value,V,_} -> - erlang:raise(error, {bad_filter,V}, ?STACKTRACE) + {value,V,_} -> + apply_error({bad_filter,V}, ?STACKTRACE, element(2, F), Bs0, Ef, none) end end. +is_generator({generate,_,_,_}) -> true; +is_generator({b_generate,_,_,_}) -> true; +is_generator({m_generate,_,_,_}) -> true; +is_generator(_) -> false. + %% eval_map_fields([Field], Bindings, LocalFunctionHandler, %% ExternalFuncHandler) -> %% {[{map_assoc | map_exact,Key,Value}],Bindings} -eval_map_fields(Fs, Bs, Lf, Ef) -> - eval_map_fields(Fs, Bs, Lf, Ef, []). - -eval_map_fields([{map_field_assoc,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) -> - {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none), - {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none), - eval_map_fields(Fs, Bs2, Lf, Ef, [{map_assoc,K1,V1}|Acc]); -eval_map_fields([{map_field_exact,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) -> - {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none), - {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none), - eval_map_fields(Fs, Bs2, Lf, Ef, [{map_exact,K1,V1}|Acc]); -eval_map_fields([], Bs, _Lf, _Ef, Acc) -> +eval_map_fields(Fs, Bs, Lf, Ef, FUVs) -> + eval_map_fields(Fs, Bs, Lf, Ef, FUVs, []). + +eval_map_fields([{map_field_assoc,_,K0,V0}|Fs], Bs0, Lf, Ef, FUVs, Acc) -> + {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none, FUVs), + {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none, FUVs), + eval_map_fields(Fs, Bs2, Lf, Ef, FUVs, [{map_assoc,K1,V1}|Acc]); +eval_map_fields([{map_field_exact,_,K0,V0}|Fs], Bs0, Lf, Ef, FUVs, Acc) -> + {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none, FUVs), + {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none, FUVs), + eval_map_fields(Fs, Bs2, Lf, Ef, FUVs, [{map_exact,K1,V1}|Acc]); +eval_map_fields([], Bs, _Lf, _Ef, _FUVs, Acc) -> {lists:reverse(Acc),Bs}. @@ -810,48 +940,48 @@ ret_expr(V, Bs, none) -> ret_expr(V, _Bs, RBs) when is_list(RBs); is_map(RBs) -> {value,V,RBs}. -%% eval_fun(Arguments, {Bindings,LocalFunctionHandler, -%% ExternalFunctionHandler,Clauses}) -> Value +%% eval_fun(Arguments, {Anno,Bindings,LocalFunctionHandler, +%% ExternalFunctionHandler,FunUsedVars,Clauses}) -> Value %% This function is called when the fun is called from compiled code %% or from apply. -eval_fun(As, {Bs0,Lf,Ef,Cs}) -> - eval_fun(Cs, As, Bs0, Lf, Ef, value). +eval_fun(As, {Anno,Bs0,Lf,Ef,FUVs,Cs}) -> + eval_fun(Cs, As, Anno, Bs0, Lf, Ef, value, FUVs). -eval_fun([{clause,_,H,G,B}|Cs], As, Bs0, Lf, Ef, RBs) -> - case match_list(H, As, new_bindings(Bs0), Bs0) of +eval_fun([{clause,_,H,G,B}|Cs], As, Anno, Bs0, Lf, Ef, RBs, FUVs) -> + case match_list(H, As, Anno, new_bindings(Bs0), Bs0, Ef) of {match,Bsn} -> % The new bindings for the head Bs1 = add_bindings(Bsn, Bs0), % which then shadow! case guard(G, Bs1, Lf, Ef) of - true -> exprs(B, Bs1, Lf, Ef, RBs); - false -> eval_fun(Cs, As, Bs0, Lf, Ef, RBs) + true -> exprs(B, Bs1, Lf, Ef, RBs, FUVs); + false -> eval_fun(Cs, As, Anno, Bs0, Lf, Ef, RBs, FUVs) end; nomatch -> - eval_fun(Cs, As, Bs0, Lf, Ef, RBs) + eval_fun(Cs, As, Anno, Bs0, Lf, Ef, RBs, FUVs) end; -eval_fun([], As, _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, function_clause, - [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE]). +eval_fun([], As, Anno, Bs, _Lf, Ef, RBs, _FUVs) -> + Stack = [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE], + apply_error(function_clause, Stack, Anno, Bs, Ef, RBs). -eval_named_fun(As, Fun, {Bs0,Lf,Ef,Cs,Name}) -> - eval_named_fun(Cs, As, Bs0, Lf, Ef, Name, Fun, value). +eval_named_fun(As, Fun, {Anno,Bs0,Lf,Ef,FUVs,Cs,Name}) -> + eval_named_fun(Cs, As, Anno, Bs0, Lf, Ef, Name, Fun, value, FUVs). -eval_named_fun([{clause,_,H,G,B}|Cs], As, Bs0, Lf, Ef, Name, Fun, RBs) -> +eval_named_fun([{clause,_,H,G,B}|Cs], As, Anno, Bs0, Lf, Ef, Name, Fun, RBs, FUVs) -> Bs1 = add_binding(Name, Fun, Bs0), - case match_list(H, As, new_bindings(Bs0), Bs1) of + case match_list(H, As, Anno, new_bindings(Bs0), Bs1, Ef) of {match,Bsn} -> % The new bindings for the head Bs2 = add_bindings(Bsn, Bs1), % which then shadow! case guard(G, Bs2, Lf, Ef) of - true -> exprs(B, Bs2, Lf, Ef, RBs); - false -> eval_named_fun(Cs, As, Bs0, Lf, Ef, Name, Fun, RBs) + true -> exprs(B, Bs2, Lf, Ef, RBs, FUVs); + false -> eval_named_fun(Cs, As, Anno, Bs0, Lf, Ef, Name, Fun, RBs, FUVs) end; nomatch -> - eval_named_fun(Cs, As, Bs0, Lf, Ef, Name, Fun, RBs) + eval_named_fun(Cs, As, Anno, Bs0, Lf, Ef, Name, Fun, RBs, FUVs) end; -eval_named_fun([], As, _Bs, _Lf, _Ef, _Name, _Fun, _RBs) -> - erlang:raise(error, function_clause, - [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE]). +eval_named_fun([], As, Anno, Bs, _Lf, Ef, _Name, _Fun, RBs, _FUVs) -> + Stack = [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE], + apply_error(function_clause, Stack, Anno, Bs, Ef, RBs). %% expr_list(ExpressionList, Bindings) @@ -865,7 +995,7 @@ eval_named_fun([], As, _Bs, _Lf, _Ef, _Name, _Fun, _RBs) -> ValueList :: [value()], NewBindings :: binding_struct()). expr_list(Es, Bs) -> - expr_list(Es, Bs, none, none). + expr_list(Es, Bs, none, none, empty_fun_used_vars()). -spec(expr_list(ExpressionList, Bindings, LocalFunctionHandler) -> {ValueList, NewBindings} when @@ -875,7 +1005,7 @@ expr_list(Es, Bs) -> ValueList :: [value()], NewBindings :: binding_struct()). expr_list(Es, Bs, Lf) -> - expr_list(Es, Bs, Lf, none). + expr_list(Es, Bs, Lf, none, empty_fun_used_vars()). -spec(expr_list(ExpressionList, Bindings, LocalFunctionHandler, NonLocalFunctionHandler) -> @@ -887,44 +1017,47 @@ expr_list(Es, Bs, Lf) -> ValueList :: [value()], NewBindings :: binding_struct()). expr_list(Es, Bs, Lf, Ef) -> - expr_list(Es, [], Bs, Bs, Lf, Ef). + expr_list(Es, Bs, Lf, Ef, empty_fun_used_vars()). + +expr_list(Es, Bs, Lf, Ef, FUVs) -> + expr_list(Es, [], Bs, Bs, Lf, Ef, FUVs). -expr_list([E|Es], Vs, BsOrig, Bs0, Lf, Ef) -> - {value,V,Bs1} = expr(E, BsOrig, Lf, Ef, none), - expr_list(Es, [V|Vs], BsOrig, merge_bindings(Bs1, Bs0), Lf, Ef); -expr_list([], Vs, _, Bs, _Lf, _Ef) -> +expr_list([E|Es], Vs, BsOrig, Bs0, Lf, Ef, FUVs) -> + {value,V,Bs1} = expr(E, BsOrig, Lf, Ef, none, FUVs), + expr_list(Es, [V|Vs], BsOrig, merge_bindings(Bs1, Bs0, element(2, E), Ef), Lf, Ef, FUVs); +expr_list([], Vs, _, Bs, _Lf, _Ef, _FUVs) -> {reverse(Vs),Bs}. -eval_op(Op, Arg1, Arg2, Bs, Ef, RBs) -> - do_apply(erlang, Op, [Arg1,Arg2], Bs, Ef, RBs). +eval_op(Op, Arg1, Arg2, Anno, Bs, Ef, RBs) -> + do_apply(erlang, Op, [Arg1,Arg2], Anno, Bs, Ef, RBs). -eval_op(Op, Arg, Bs, Ef, RBs) -> - do_apply(erlang, Op, [Arg], Bs, Ef, RBs). +eval_op(Op, Arg, Anno, Bs, Ef, RBs) -> + do_apply(erlang, Op, [Arg], Anno, Bs, Ef, RBs). -%% if_clauses(Clauses, Bindings, LocalFuncHandler, ExtFuncHandler, RBs) +%% if_clauses(Clauses, Anno, Bindings, LocalFuncHandler, ExtFuncHandler, RBs) -if_clauses([{clause,_,[],G,B}|Cs], Bs, Lf, Ef, RBs) -> +if_clauses([{clause,_,[],G,B}|Cs], Anno, Bs, Lf, Ef, RBs, FUVs) -> case guard(G, Bs, Lf, Ef) of - true -> exprs(B, Bs, Lf, Ef, RBs); - false -> if_clauses(Cs, Bs, Lf, Ef, RBs) + true -> exprs(B, Bs, Lf, Ef, RBs, FUVs); + false -> if_clauses(Cs, Anno, Bs, Lf, Ef, RBs, FUVs) end; -if_clauses([], _Bs, _Lf, _Ef, _RBs) -> - erlang:raise(error, if_clause, ?STACKTRACE). +if_clauses([], Anno, Bs, _Lf, Ef, RBs, _FUVs) -> + apply_error(if_clause, ?STACKTRACE, Anno, Bs, Ef, RBs). -%% try_clauses(Body, CaseClauses, CatchClauses, AfterBody, Bindings, +%% try_clauses(Body, CaseClauses, CatchClauses, AfterBody, Anno, Bindings, %% LocalFuncHandler, ExtFuncHandler, RBs) -try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) -> - check_stacktrace_vars(Catches, Bs), - try exprs(B, Bs, Lf, Ef, none) of +try_clauses(B, Cases, Catches, AB, Anno, Bs, Lf, Ef, RBs, FUVs) -> + check_stacktrace_vars(Catches, Anno, Bs, Ef, RBs), + try exprs(B, Bs, Lf, Ef, none, FUVs) of {value,V,Bs1} when Cases =:= [] -> ret_expr(V, Bs1, RBs); {value,V,Bs1} -> case match_clause(Cases, [V], Bs1, Lf, Ef) of {B2,Bs2} -> - exprs(B2, Bs2, Lf, Ef, RBs); + exprs(B2, Bs2, Lf, Ef, RBs, FUVs); nomatch -> - erlang:raise(error, {try_clause,V}, ?STACKTRACE) + apply_error({try_clause, V}, ?STACKTRACE, Anno, Bs, Ef, RBs) end catch Class:Reason:Stacktrace when Catches =:= [] -> @@ -933,63 +1066,63 @@ try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) -> V = {Class,Reason,Stacktrace}, case match_clause(Catches, [V], Bs, Lf, Ef) of {B2,Bs2} -> - exprs(B2, Bs2, Lf, Ef, RBs); + exprs(B2, Bs2, Lf, Ef, RBs, FUVs); nomatch -> erlang:raise(Class, Reason, Stacktrace) end after - if AB =:= [] -> + if AB =:= [] -> Bs; % any true -> - exprs(AB, Bs, Lf, Ef, none) + exprs(AB, Bs, Lf, Ef, none, FUVs) end end. -check_stacktrace_vars([{clause,_,[{tuple,_,[_,_,STV]}],_,_}|Cs], Bs) -> + +check_stacktrace_vars([{clause,_,[{tuple,_,[_,_,STV]}],_,_}|Cs], Anno, Bs, Ef, RBs) -> case STV of {var,_,V} -> case binding(V, Bs) of {value, _} -> - erlang:raise(error, stacktrace_bound, ?STACKTRACE); + apply_error(stacktrace_bound, ?STACKTRACE, Anno, Bs, Ef, RBs); unbound -> - check_stacktrace_vars(Cs, Bs) + check_stacktrace_vars(Cs, Anno, Bs, Ef, RBs) end; _ -> - erlang:raise(error, - {illegal_stacktrace_variable,STV}, - ?STACKTRACE) + Reason = {illegal_stacktrace_variable,STV}, + apply_error(Reason, ?STACKTRACE, Anno, Bs, Ef, RBs) end; -check_stacktrace_vars([], _Bs) -> +check_stacktrace_vars([], _Anno, _Bs, _Ef, _RBs) -> ok. -%% case_clauses(Value, Clauses, Bindings, LocalFuncHandler, ExtFuncHandler, -%% RBs) +%% case_clauses(Value, Clauses, Anno, Bindings, LocalFuncHandler, +%% ExtFuncHandler, RBs) -case_clauses(Val, Cs, Bs, Lf, Ef, RBs) -> +case_clauses(Val, Cs, Anno, Bs, Lf, Ef, RBs, FUVs) -> case match_clause(Cs, [Val], Bs, Lf, Ef) of {B, Bs1} -> - exprs(B, Bs1, Lf, Ef, RBs); + exprs(B, Bs1, Lf, Ef, RBs, FUVs); nomatch -> - erlang:raise(error, {case_clause,Val}, ?STACKTRACE) + apply_error({case_clause,Val}, ?STACKTRACE, Anno, Bs, Ef, RBs) end. %% -%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, RBs) +%% receive_clauses(Clauses, Bindings, LocalFuncHnd, ExtFuncHnd, RBs) %% -receive_clauses(Cs, Bs, Lf, Ef, RBs) -> - receive_clauses(infinity, Cs, unused, Bs, Lf, Ef, RBs). +receive_clauses(Cs, Bs, Lf, Ef, RBs, FUVs) -> + receive_clauses(infinity, Cs, unused, Bs, Lf, Ef, RBs, FUVs). %% -%% receive_clauses(TimeOut, Clauses, TimeoutBody, Bindings, +%% receive_clauses(TimeOut, Clauses, TimeoutBody, Bindings, %% ExternalFuncHandler, LocalFuncHandler, RBs) %% -receive_clauses(T, Cs, TB, Bs, Lf, Ef, RBs) -> +receive_clauses(T, Cs, TB, Bs, Lf, Ef, RBs, FUVs) -> F = fun (M) -> match_clause(Cs, [M], Bs, Lf, Ef) end, case prim_eval:'receive'(F, T) of {B, Bs1} -> - exprs(B, Bs1, Lf, Ef, RBs); + exprs(B, Bs1, Lf, Ef, RBs, FUVs); timeout -> {B, Bs1} = TB, - exprs(B, Bs1, Lf, Ef, RBs) + exprs(B, Bs1, Lf, Ef, RBs, FUVs) end. %% match_clause -> {Body, Bindings} or nomatch @@ -1006,8 +1139,8 @@ receive_clauses(T, Cs, TB, Bs, Lf, Ef, RBs) -> match_clause(Cs, Vs, Bs, Lf) -> match_clause(Cs, Vs, Bs, Lf, none). -match_clause([{clause,_,H,G,B}|Cs], Vals, Bs, Lf, Ef) -> - case match_list(H, Vals, Bs) of +match_clause([{clause,Anno,H,G,B}|Cs], Vals, Bs, Lf, Ef) -> + case match_list(H, Vals, Anno, Bs, Bs, Ef) of {match, Bs1} -> case guard(G, Bs1, Lf, Ef) of true -> {B, Bs1}; @@ -1045,7 +1178,7 @@ guard0([G|Gs], Bs0, Lf, Ef) -> {value,false,_} -> false end; false -> - erlang:raise(error, guard_expr, ?STACKTRACE) + apply_error(guard_expr, ?STACKTRACE, element(2, G), Bs0, Ef, none) end; guard0([], _Bs, _Lf, _Ef) -> true. @@ -1068,7 +1201,7 @@ guard_test(G, Bs0, Lf, Ef) -> expr_guard_test(G, Bs0, Lf, Ef) -> try {value,true,_} = expr(G, Bs0, Lf, Ef, none) catch error:_ -> {value,false,Bs0} end. - + type_test(integer) -> is_integer; type_test(float) -> is_float; type_test(number) -> is_number; @@ -1084,23 +1217,19 @@ type_test(record) -> is_record; type_test(map) -> is_map; type_test(Test) -> Test. - -%% match(Pattern, Term, Bindings) -> -%% {match,NewBindings} | nomatch +%% match(Pattern, Term, Anno, NewBindings, Bindings, ExternalFunHnd) -> +%% {match,NewBindings} | nomatch %% or erlang:error({illegal_pattern, Pattern}). -%% Try to match Pattern against Term with the current bindings. - -match(Pat, Term, Bs) -> - match(Pat, Term, Bs, Bs). - +%% +%% Try to match Pattern against Term with the current bindings. %% Bs are the bindings that are augmented with new bindings. BBs are %% the bindings used for "binsize" variables (in <>, Y is a %% binsize variable). -match(Pat, Term, Bs, BBs) -> - case catch match1(Pat, Term, Bs, BBs) of +match(Pat, Term, Anno, Bs, BBs, Ef) -> + case catch match1(Pat, Term, Bs, BBs, Ef) of invalid -> - erlang:raise(error, {illegal_pattern,to_term(Pat)}, ?STACKTRACE); + apply_error({illegal_pattern,to_term(Pat)}, ?STACKTRACE, Anno, Bs, Ef, none); Other -> Other end. @@ -1109,29 +1238,29 @@ string_to_conses([], _, Tail) -> Tail; string_to_conses([E|Rest], Anno, Tail) -> {cons, Anno, {integer, Anno, E}, string_to_conses(Rest, Anno, Tail)}. -match1({atom,_,A0}, A, Bs, _BBs) -> +match1({atom,_,A0}, A, Bs, _BBs, _Ef) -> case A of A0 -> {match,Bs}; _ -> throw(nomatch) end; -match1({integer,_,I0}, I, Bs, _BBs) -> +match1({integer,_,I0}, I, Bs, _BBs, _Ef) -> case I of I0 -> {match,Bs}; _ -> throw(nomatch) end; -match1({float,_,F0}, F, Bs, _BBs) -> +match1({float,_,F0}, F, Bs, _BBs, _Ef) -> case F of F0 -> {match,Bs}; _ -> throw(nomatch) end; -match1({char,_,C0}, C, Bs, _BBs) -> +match1({char,_,C0}, C, Bs, _BBs, _Ef) -> case C of C0 -> {match,Bs}; _ -> throw(nomatch) end; -match1({var,_,'_'}, _, Bs, _BBs) -> %Anonymous variable matches +match1({var,_,'_'}, _, Bs, _BBs, _Ef) -> %Anonymous variable matches {match,Bs}; % everything, no new bindings -match1({var,_,Name}, Term, Bs, _BBs) -> +match1({var,_,Name}, Term, Bs, _BBs, _Ef) -> case binding(Name, Bs) of {value,Term} -> {match,Bs}; @@ -1140,34 +1269,34 @@ match1({var,_,Name}, Term, Bs, _BBs) -> unbound -> {match,add_binding(Name, Term, Bs)} end; -match1({match,_,Pat1,Pat2}, Term, Bs0, BBs) -> - {match, Bs1} = match1(Pat1, Term, Bs0, BBs), - match1(Pat2, Term, Bs1, BBs); -match1({string,_,S0}, S, Bs, _BBs) -> +match1({match,_,Pat1,Pat2}, Term, Bs0, BBs, Ef) -> + {match, Bs1} = match1(Pat1, Term, Bs0, BBs, Ef), + match1(Pat2, Term, Bs1, BBs, Ef); +match1({string,_,S0}, S, Bs, _BBs, _Ef) -> case S of S0 -> {match,Bs}; _ -> throw(nomatch) end; -match1({nil,_}, Nil, Bs, _BBs) -> +match1({nil,_}, Nil, Bs, _BBs, _Ef) -> case Nil of [] -> {match,Bs}; _ -> throw(nomatch) end; -match1({cons,_,H,T}, [H1|T1], Bs0, BBs) -> - {match,Bs} = match1(H, H1, Bs0, BBs), - match1(T, T1, Bs, BBs); -match1({cons,_,_,_}, _, _Bs, _BBs) -> +match1({cons,_,H,T}, [H1|T1], Bs0, BBs, Ef) -> + {match,Bs} = match1(H, H1, Bs0, BBs, Ef), + match1(T, T1, Bs, BBs, Ef); +match1({cons,_,_,_}, _, _Bs, _BBs, _Ef) -> throw(nomatch); -match1({tuple,_,Elts}, Tuple, Bs, BBs) +match1({tuple,_,Elts}, Tuple, Bs, BBs, Ef) when length(Elts) =:= tuple_size(Tuple) -> - match_tuple(Elts, Tuple, 1, Bs, BBs); -match1({tuple,_,_}, _, _Bs, _BBs) -> + match_tuple(Elts, Tuple, 1, Bs, BBs, Ef); +match1({tuple,_,_}, _, _Bs, _BBs, _Ef) -> throw(nomatch); -match1({map,_,Fs}, #{}=Map, Bs, BBs) -> - match_map(Fs, Map, Bs, BBs); -match1({map,_,_}, _, _Bs, _BBs) -> +match1({map,_,Fs}, #{}=Map, Bs, BBs, Ef) -> + match_map(Fs, Map, Bs, BBs, Ef); +match1({map,_,_}, _, _Bs, _BBs, _Ef) -> throw(nomatch); -match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) -> +match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs, Ef) -> EvalFun = fun(E, Bs) -> case erl_lint:is_guard_expr(E) of true -> ok; @@ -1180,74 +1309,72 @@ match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) -> throw(invalid) end end, - eval_bits:match_bits(Fs, B, Bs0, BBs, match_fun(BBs), EvalFun); -match1({bin,_,_}, _, _Bs, _BBs) -> + ErrorFun = fun(A, R, S) -> apply_error(R, S, A, Bs0, Ef, none) end, + eval_bits:match_bits(Fs, B, Bs0, BBs, match_fun(BBs, Ef), EvalFun, ErrorFun); +match1({bin,_,_}, _, _Bs, _BBs, _Ef) -> throw(nomatch); -match1({op,_,'++',{nil,_},R}, Term, Bs, BBs) -> - match1(R, Term, Bs, BBs); -match1({op,_,'++',{cons,Ai,{integer,A2,I},T},R}, Term, Bs, BBs) -> - match1({cons,Ai,{integer,A2,I},{op,Ai,'++',T,R}}, Term, Bs, BBs); -match1({op,_,'++',{cons,Ai,{char,A2,C},T},R}, Term, Bs, BBs) -> - match1({cons,Ai,{char,A2,C},{op,Ai,'++',T,R}}, Term, Bs, BBs); -match1({op,_,'++',{string,Ai,L},R}, Term, Bs, BBs) -> - match1(string_to_conses(L, Ai, R), Term, Bs, BBs); -match1({op,Anno,Op,A}, Term, Bs, BBs) -> +match1({op,_,'++',{nil,_},R}, Term, Bs, BBs, Ef) -> + match1(R, Term, Bs, BBs, Ef); +match1({op,_,'++',{cons,Ai,{integer,A2,I},T},R}, Term, Bs, BBs, Ef) -> + match1({cons,Ai,{integer,A2,I},{op,Ai,'++',T,R}}, Term, Bs, BBs, Ef); +match1({op,_,'++',{cons,Ai,{char,A2,C},T},R}, Term, Bs, BBs, Ef) -> + match1({cons,Ai,{char,A2,C},{op,Ai,'++',T,R}}, Term, Bs, BBs, Ef); +match1({op,_,'++',{string,Ai,L},R}, Term, Bs, BBs, Ef) -> + match1(string_to_conses(L, Ai, R), Term, Bs, BBs, Ef); +match1({op,Anno,Op,A}, Term, Bs, BBs, Ef) -> case partial_eval({op,Anno,Op,A}) of {op,Anno,Op,A} -> throw(invalid); X -> - match1(X, Term, Bs, BBs) + match1(X, Term, Bs, BBs, Ef) end; -match1({op,Anno,Op,L,R}, Term, Bs, BBs) -> +match1({op,Anno,Op,L,R}, Term, Bs, BBs, Ef) -> case partial_eval({op,Anno,Op,L,R}) of {op,Anno,Op,L,R} -> throw(invalid); X -> - match1(X, Term, Bs, BBs) + match1(X, Term, Bs, BBs, Ef) end; -match1(_, _, _Bs, _BBs) -> +match1(_, _, _Bs, _BBs, _Ef) -> throw(invalid). -match_fun(BBs) -> - fun(match, {L,R,Bs}) -> match1(L, R, Bs, BBs); +match_fun(BBs, Ef) -> + fun(match, {L,R,Bs}) -> match1(L, R, Bs, BBs, Ef); (binding, {Name,Bs}) -> binding(Name, Bs); (add_binding, {Name,Val,Bs}) -> add_binding(Name, Val, Bs) end. -match_tuple([E|Es], Tuple, I, Bs0, BBs) -> - {match,Bs} = match1(E, element(I, Tuple), Bs0, BBs), - match_tuple(Es, Tuple, I+1, Bs, BBs); -match_tuple([], _, _, Bs, _BBs) -> +match_tuple([E|Es], Tuple, I, Bs0, BBs, Ef) -> + {match,Bs} = match1(E, element(I, Tuple), Bs0, BBs, Ef), + match_tuple(Es, Tuple, I+1, Bs, BBs, Ef); +match_tuple([], _, _, Bs, _BBs, _Ef) -> {match,Bs}. -match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) -> +match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs, Ef) -> Vm = try {value, Ke, _} = expr(K, BBs), maps:get(Ke,Map) catch error:_ -> throw(nomatch) end, - {match, Bs} = match1(V, Vm, Bs0, BBs), - match_map(Fs, Map, Bs, BBs); -match_map([], _, Bs, _) -> + {match, Bs} = match1(V, Vm, Bs0, BBs, Ef), + match_map(Fs, Map, Bs, BBs, Ef); +match_map([], _, Bs, _, _) -> {match, Bs}. -%% match_list(PatternList, TermList, Bindings) -> +%% match_list(PatternList, TermList, Anno, NewBindings, Bindings, ExternalFunHnd) -> %% {match,NewBindings} | nomatch %% Try to match a list of patterns against a list of terms with the %% current bindings. -match_list(Ps, Ts, Bs) -> - match_list(Ps, Ts, Bs, Bs). - -match_list([P|Ps], [T|Ts], Bs0, BBs) -> - case match(P, T, Bs0, BBs) of - {match,Bs1} -> match_list(Ps, Ts, Bs1, BBs); +match_list([P|Ps], [T|Ts], Anno, Bs0, BBs, Ef) -> + case match(P, T, Anno, Bs0, BBs, Ef) of + {match,Bs1} -> match_list(Ps, Ts, Anno, Bs1, BBs, Ef); nomatch -> nomatch end; -match_list([], [], Bs, _BBs) -> +match_list([], [], _Anno, Bs, _BBs, _Ef) -> {match,Bs}; -match_list(_, _, _Bs, _BBs) -> +match_list(_, _, _Anno, _Bs, _BBs, _Ef) -> nomatch. %% new_bindings() @@ -1296,17 +1423,17 @@ add_bindings(Bs1, Bs2) -> foldl(fun ({Name,Val}, Bs) -> orddict:store(Name, Val, Bs) end, Bs2, orddict:to_list(Bs1)). -merge_bindings(Bs1, Bs2) when is_map(Bs1), is_map(Bs2) -> +merge_bindings(Bs1, Bs2, Anno, Ef) when is_map(Bs1), is_map(Bs2) -> maps:merge_with(fun (_K, V, V) -> V; - (_K, _, V) -> erlang:raise(error, {badmatch,V}, ?STACKTRACE) + (_K, _, V) -> apply_error({badmatch,V}, ?STACKTRACE, Anno, Bs1, Ef, none) end, Bs2, Bs1); -merge_bindings(Bs1, Bs2) -> +merge_bindings(Bs1, Bs2, Anno, Ef) -> foldl(fun ({Name,Val}, Bs) -> case orddict:find(Name, Bs) of {ok,Val} -> Bs; %Already with SAME value - {ok,V1} -> - erlang:raise(error, {badmatch,V1}, ?STACKTRACE); + {ok,V1} -> + apply_error({badmatch,V1}, ?STACKTRACE, Anno, Bs1, Ef, none); error -> orddict:store(Name, Val, Bs) end end, Bs2, orddict:to_list(Bs1)). @@ -1323,28 +1450,6 @@ to_terms(Abstrs) -> to_term(Abstr) -> erl_parse:anno_to_term(Abstr). -%% Substitute {value, A, Item} for {var, A, Var}, preserving A. -%% {value, A, Item} is a shell/erl_eval convention, and for example -%% the linter cannot handle it. - --spec subst_values_for_vars(ExprList, Bindings) -> [term()] when - ExprList :: [erl_parse:abstract_expr()], - Bindings :: binding_struct(). - -subst_values_for_vars({var, A, V}=Var, Bs) -> - case erl_eval:binding(V, Bs) of - {value, Value} -> - {value, A, Value}; - unbound -> - Var - end; -subst_values_for_vars(L, Bs) when is_list(L) -> - [subst_values_for_vars(E, Bs) || E <- L]; -subst_values_for_vars(T, Bs) when is_tuple(T) -> - list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs)); -subst_values_for_vars(T, _Bs) -> - T. - %% `Tokens' is assumed to have been scanned with the 'text' option. %% The annotations of the returned expressions are locations. %% @@ -1353,18 +1458,17 @@ subst_values_for_vars(T, _Bs) -> %% the items themselves are stored in the returned bindings. -spec extended_parse_exprs(Tokens) -> - {'ok', ExprList, Bindings} | {'error', ErrorInfo} when + {'ok', ExprList} | {'error', ErrorInfo} when Tokens :: [erl_scan:token()], ExprList :: [erl_parse:abstract_expr()], - Bindings :: erl_eval:binding_struct(), ErrorInfo :: erl_parse:error_info(). extended_parse_exprs(Tokens) -> Ts = tokens_fixup(Tokens), case erl_parse:parse_exprs(Ts) of {ok, Exprs0} -> - {Exprs, Bs} = expr_fixup(Exprs0), - {ok, reset_expr_anno(Exprs), Bs}; + Exprs = expr_fixup(Exprs0), + {ok, reset_expr_anno(Exprs)}; _ErrorInfo -> erl_parse:parse_exprs(reset_token_anno(Ts)) end. @@ -1382,7 +1486,7 @@ tokens_fixup([T|Ts]=Ts0) -> token_fixup(Ts) -> {AnnoL, NewTs, FixupTag} = unscannable(Ts), String = lists:append([erl_anno:text(A) || A <- AnnoL]), - _ = (fixup_fun(FixupTag))(String), + _ = validate_tag(FixupTag, String), NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)), {{string, NewAnno, String}, NewTs}. @@ -1403,37 +1507,26 @@ unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _}, {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) -> {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}. -expr_fixup(Expr0) -> - {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1), - {Expr, Bs}. - -expr_fixup({string,A,S}=T, Bs0, I) -> - try string_fixup(A, S) of - Value -> - Var = new_var(I), - Bs = erl_eval:add_binding(Var, Value, Bs0), - {{var, A, Var}, Bs, I+1} +expr_fixup({string,A,S}=T) -> + try string_fixup(A, S, T) of + Expr -> Expr catch - _:_ -> - {T, Bs0, I} + _:_ -> T end; -expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) -> - {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0), - {list_to_tuple(L), Bs, I}; -expr_fixup([E0|Es0], Bs0, I0) -> - {E, Bs1, I1} = expr_fixup(E0, Bs0, I0), - {Es, Bs, I} = expr_fixup(Es0, Bs1, I1), - {[E|Es], Bs, I}; -expr_fixup(T, Bs, I) -> - {T, Bs, I}. - -string_fixup(A, S) -> - Text = erl_anno:text(A), - FixupTag = fixup_tag(Text, S), - (fixup_fun(FixupTag))(S). - -new_var(I) -> - list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])). +expr_fixup(Tuple) when is_tuple(Tuple) -> + L = expr_fixup(tuple_to_list(Tuple)), + list_to_tuple(L); +expr_fixup([E0|Es0]) -> + E = expr_fixup(E0), + Es = expr_fixup(Es0), + [E|Es]; +expr_fixup(T) -> + T. + +string_fixup(Anno, String, Token) -> + Text = erl_anno:text(Anno), + FixupTag = fixup_tag(Text, String), + fixup_ast(FixupTag, Anno, String, Token). reset_token_anno(Tokens) -> [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens]. @@ -1444,18 +1537,15 @@ reset_expr_anno(Exprs) -> reset_anno() -> fun(A) -> erl_anno:new(erl_anno:location(A)) end. -fixup_fun(function) -> fun function/1; -fixup_fun(pid) -> fun erlang:list_to_pid/1; -fixup_fun(port) -> fun erlang:list_to_port/1; -fixup_fun(reference) -> fun erlang:list_to_ref/1. - -function(S) -> - %% External function. - {ok, [_, _, _, - {atom, _, Module}, _, - {atom, _, Function}, _, - {integer, _, Arity}|_], _} = erl_scan:string(S), - erlang:make_fun(Module, Function, Arity). +fixup_ast(pid, A, _S, T) -> + {call,A,{remote,A,{atom,A,erlang},{atom,A,list_to_pid}},[T]}; +fixup_ast(port, A, _S, T) -> + {call,A,{remote,A,{atom,A,erlang},{atom,A,list_to_port}},[T]}; +fixup_ast(reference, A, _S, T) -> + {call,A,{remote,A,{atom,A,erlang},{atom,A,list_to_ref}},[T]}; +fixup_ast(function, A, S, _T) -> + {Module, Function, Arity} = fixup_mfa(S), + {'fun',A,{function,{atom,A,Module},{atom,A,Function},{integer,A,Arity}}}. fixup_text(function) -> "function"; fixup_text(pid) -> "pid"; @@ -1467,6 +1557,20 @@ fixup_tag("pid", "<"++_) -> pid; fixup_tag("port", "#"++_) -> port; fixup_tag("reference", "#"++_) -> reference. +fixup_mfa(S) -> + {ok, [_, _, _, + {atom, _, Module}, _, + {atom, _, Function}, _, + {integer, _, Arity}|_], _} = erl_scan:string(S), + {Module, Function, Arity}. + +validate_tag(pid, String) -> erlang:list_to_pid(String); +validate_tag(port, String) -> erlang:list_to_port(String); +validate_tag(reference, String) -> erlang:list_to_ref(String); +validate_tag(function, String) -> + {Module, Function, Arity} = fixup_mfa(String), + erlang:make_fun(Module, Function, Arity). + %%% End of extended_parse_exprs. %% `Tokens' is assumed to have been scanned with the 'text' option. @@ -1481,8 +1585,8 @@ fixup_tag("reference", "#"++_) -> reference. extended_parse_term(Tokens) -> case extended_parse_exprs(Tokens) of - {ok, [Expr], Bindings} -> - try normalise(Expr, Bindings) of + {ok, [Expr]} -> + try normalise(Expr) of Term -> {ok, Term} catch @@ -1490,7 +1594,7 @@ extended_parse_term(Tokens) -> Loc = erl_anno:location(element(2, Expr)), {error,{Loc,?MODULE,"bad term"}} end; - {ok, [_,Expr|_], _Bindings} -> + {ok, [_,Expr|_]} -> Loc = erl_anno:location(element(2, Expr)), {error,{Loc,?MODULE,"bad term"}}; {error, _} = Error -> @@ -1498,46 +1602,47 @@ extended_parse_term(Tokens) -> end. %% From erl_parse. -normalise({var, _, V}, Bs) -> - {value, Value} = erl_eval:binding(V, Bs), - Value; -normalise({char,_,C}, _Bs) -> C; -normalise({integer,_,I}, _Bs) -> I; -normalise({float,_,F}, _Bs) -> F; -normalise({atom,_,A}, _Bs) -> A; -normalise({string,_,S}, _Bs) -> S; -normalise({nil,_}, _Bs) -> []; -normalise({bin,_,Fs}, Bs) -> +normalise({char,_,C}) -> C; +normalise({integer,_,I}) -> I; +normalise({float,_,F}) -> F; +normalise({atom,_,A}) -> A; +normalise({string,_,S}) -> S; +normalise({nil,_}) -> []; +normalise({bin,_,Fs}) -> {value, B, _} = eval_bits:expr_grp(Fs, [], fun(E, _) -> - {value, normalise(E, Bs), []} - end, [], true), + {value, normalise(E), []} + end), B; -normalise({cons,_,Head,Tail}, Bs) -> - [normalise(Head, Bs)|normalise(Tail, Bs)]; -normalise({tuple,_,Args}, Bs) -> - list_to_tuple(normalise_list(Args, Bs)); -normalise({map,_,Pairs}, Bs) -> +normalise({cons,_,Head,Tail}) -> + [normalise(Head)|normalise(Tail)]; +normalise({tuple,_,Args}) -> + list_to_tuple(normalise_list(Args)); +normalise({map,_,Pairs}) -> maps:from_list(lists:map(fun %% only allow '=>' ({map_field_assoc,_,K,V}) -> - {normalise(K, Bs),normalise(V, Bs)} + {normalise(K),normalise(V)} end, Pairs)); %% Special case for unary +/-. -normalise({op,_,'+',{char,_,I}}, _Bs) -> I; -normalise({op,_,'+',{integer,_,I}}, _Bs) -> I; -normalise({op,_,'+',{float,_,F}}, _Bs) -> F; -normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible! -normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I; -normalise({op,_,'-',{float,_,F}}, _Bs) -> -F; -normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) -> +normalise({op,_,'+',{char,_,I}}) -> I; +normalise({op,_,'+',{integer,_,I}}) -> I; +normalise({op,_,'+',{float,_,F}}) -> F; +normalise({op,_,'-',{char,_,I}}) -> -I; %Weird, but compatible! +normalise({op,_,'-',{integer,_,I}}) -> -I; +normalise({op,_,'-',{float,_,F}}) -> -F; +%% Special case for #...<> +normalise({call,_,{remote,_,{atom,_,erlang},{atom,_,Fun}},[{string,_,S}]}) when + Fun =:= list_to_ref; Fun =:= list_to_port; Fun =:= list_to_pid -> + erlang:Fun(S); +normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}) -> %% Since "#Fun" is recognized, "fun M:F/A" should be too. fun M:F/A. -normalise_list([H|T], Bs) -> - [normalise(H, Bs)|normalise_list(T, Bs)]; -normalise_list([], _Bs) -> +normalise_list([H|T]) -> + [normalise(H)|normalise_list(T)]; +normalise_list([]) -> []. %%---------------------------------------------------------------------------- diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index 4c8ba0578b19..706b5fec6eda 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -30,6 +30,7 @@ vcount=0, % Variable counter calltype=#{}, % Call types records=#{}, % Record definitions + raw_records=[],% Raw record forms strict_ra=[], % strict record accesses checked_ra=[], % successfully accessed records dialyzer=false % Cached value of compile flag 'dialyzer' @@ -54,8 +55,7 @@ compiler_options(Forms) -> lists:flatten([C || {attribute,_,compile,C} <- Forms]). init_calltype(Forms) -> - Locals = [{{Name,Arity},local} || {function,_,Name,Arity,_} <- Forms], - Ctype = maps:from_list(Locals), + Ctype = #{{Name,Arity} => local || {function,_,Name,Arity,_} <- Forms}, init_calltype_imports(Forms, Ctype). init_calltype_imports([{attribute,_,import,{Mod,Fs}}|T], Ctype0) -> @@ -70,7 +70,8 @@ init_calltype_imports([], Ctype) -> Ctype. forms([{attribute,_,record,{Name,Defs}}=Attr | Fs], St0) -> NDefs = normalise_fields(Defs), - St = St0#exprec{records=maps:put(Name, NDefs, St0#exprec.records)}, + St = St0#exprec{records=maps:put(Name, NDefs, St0#exprec.records), + raw_records=[Attr | St0#exprec.raw_records]}, {Fs1, St1} = forms(Fs, St), {[Attr | Fs1], St1}; forms([{function,Anno,N,A,Cs0} | Fs0], St0) -> @@ -287,6 +288,10 @@ expr({bc,Anno,E0,Qs0}, St0) -> {Qs1,St1} = lc_tq(Anno, Qs0, St0), {E1,St2} = expr(E0, St1), {{bc,Anno,E1,Qs1},St2}; +expr({mc,Anno,E0,Qs0}, St0) -> + {Qs1,St1} = lc_tq(Anno, Qs0, St0), + {E1,St2} = expr(E0, St1), + {{mc,Anno,E1,Qs1},St2}; expr({tuple,Anno,Es0}, St0) -> {Es1,St1} = expr_list(Es0, St0), {{tuple,Anno,Es1},St1}; @@ -366,6 +371,12 @@ expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,is_record}}, expr({call,Anno,{tuple,_,[{atom,_,erlang},{atom,_,is_record}]}, [A,{atom,_,Name}]}, St) -> record_test(Anno, A, Name, St); +expr({call,Anno,{atom,_,is_record},[_,_,{integer,_,Sz}]}, St) + when is_integer(Sz), Sz =< 0 -> + {{atom,Anno,false},St}; +expr({call,Anno,{remote,_,{atom,_,erlang},{atom,_,is_record}}, + [_,_,{integer,_,Sz}]}, St) when is_integer(Sz), Sz =< 0 -> + {{atom,Anno,false},St}; expr({call,Anno,{atom,_AnnoA,record_info},[_,_]=As0}, St0) -> {As,St1} = expr_list(As0, St0), record_info_call(Anno, As, St1); @@ -406,6 +417,17 @@ expr({'try',Anno,Es0,Scs0,Ccs0,As0}, St0) -> expr({'catch',Anno,E0}, St0) -> {E,St1} = expr(E0, St0), {{'catch',Anno,E},St1}; +expr({'maybe',MaybeAnno,Es0}, St0) -> + {Es,St1} = exprs(Es0, St0), + {{'maybe',MaybeAnno,Es},St1}; +expr({'maybe',MaybeAnno,Es0,{'else',ElseAnno,Cs0}}, St0) -> + {Es,St1} = exprs(Es0, St0), + {Cs,St2} = clauses(Cs0, St1), + {{'maybe',MaybeAnno,Es,{'else',ElseAnno,Cs}},St2}; +expr({maybe_match,Anno,P0,E0}, St0) -> + {E,St1} = expr(E0, St0), + {P,St2} = pattern(P0, St1), + {{maybe_match,Anno,P,E},St2}; expr({match,Anno,P0,E0}, St0) -> {E,St1} = expr(E0, St0), {P,St2} = pattern(P0, St1), @@ -429,7 +451,9 @@ expr({op,Anno,Op,L0,R0}, St0) when Op =:= 'andalso'; expr({op,Anno,Op,L0,R0}, St0) -> {L,St1} = expr(L0, St0), {R,St2} = expr(R0, St1), - {{op,Anno,Op,L,R},St2}. + {{op,Anno,Op,L,R},St2}; +expr(E={ssa_check_when,_,_,_,_,_}, St) -> + {E, St}. expr_list([E0 | Es0], St0) -> {E,St1} = expr(E0, St0), @@ -500,7 +524,12 @@ lc_tq(Anno, [{b_generate,AnnoG,P0,G0} | Qs0], St0) -> {P1,St2} = pattern(P0, St1), {Qs1,St3} = lc_tq(Anno, Qs0, St2), {[{b_generate,AnnoG,P1,G1} | Qs1],St3}; -lc_tq(Anno, [F0 | Qs0], #exprec{calltype=Calltype}=St0) -> +lc_tq(Anno, [{m_generate,AnnoG,P0,G0} | Qs0], St0) -> + {G1,St1} = expr(G0, St0), + {P1,St2} = pattern(P0, St1), + {Qs1,St3} = lc_tq(Anno, Qs0, St2), + {[{m_generate,AnnoG,P1,G1} | Qs1],St3}; +lc_tq(Anno, [F0 | Qs0], #exprec{calltype=Calltype,raw_records=Records}=St0) -> %% Allow record/2 and expand out as guard test. IsOverriden = fun(FA) -> case Calltype of @@ -509,7 +538,7 @@ lc_tq(Anno, [F0 | Qs0], #exprec{calltype=Calltype}=St0) -> _ -> false end end, - case erl_lint:is_guard_test(F0, [], IsOverriden) of + case erl_lint:is_guard_test(F0, Records, IsOverriden) of true -> {F1,St1} = guard_test(F0, St0), {Qs1,St2} = lc_tq(Anno, Qs0, St1), @@ -595,11 +624,11 @@ strict_get_record_field(Anno, R, {atom,_,F}=Index, Name, St0) -> RAnno = mark_record(NAnno, St), E = {'case',Anno,R, [{clause,NAnno,[{tuple,RAnno,P}],[],[Var]}, - {clause,NAnno,[{var,NAnno,'_'}],[], + {clause,NAnno,[Var],[], [{call,NAnno,{remote,NAnno, {atom,NAnno,erlang}, {atom,NAnno,error}}, - [{tuple,NAnno,[{atom,NAnno,badrecord},{atom,NAnno,Name}]}]}]}]}, + [{tuple,NAnno,[{atom,NAnno,badrecord},Var]}]}]}]}, expr(E, St); true -> %In a guard. Fs = record_fields(Name, Anno, St0), @@ -681,24 +710,20 @@ record_wildcard_init([]) -> none. record_update(R, Name, Fs, Us0, St0) -> Anno = element(2, R), {Pre,Us,St1} = record_exprs(Us0, St0), - Nf = length(Fs), %# of record fields - Nu = length(Us), %# of update fields - Nc = Nf - Nu, %# of copy fields %% We need a new variable for the record expression %% to guarantee that it is only evaluated once. {Var,St2} = new_var(Anno, St1), + %% Honor the `strict_record_updates` option needed by `dialyzer`, otherwise + %% expand everything to chains of `setelement/3` as that's far more + %% efficient in the JIT. StrictUpdates = strict_record_updates(St2#exprec.compile), - - %% Try to be intelligent about which method of updating record to use. {Update,St} = if - Nu =:= 0 -> - record_match(Var, Name, Anno, Fs, Us, St2); - Nu =< Nc, not StrictUpdates -> %Few fields updated + not StrictUpdates, Us =/= [] -> {record_setel(Var, Name, Fs, Us), St2}; - true -> %The wide area inbetween + true -> record_match(Var, Name, Anno, Fs, Us, St2) end, {{block,Anno,Pre ++ [{match,Anno,Var,R},Update]},St}. @@ -714,7 +739,7 @@ record_match(R, Name, AnnoR, Fs, Us, St0) -> [{clause,AnnoR,[{tuple,RAnno,[{atom,AnnoR,Name} | Ps]}],[], [{tuple,RAnno,[{atom,AnnoR,Name} | News]}]}, {clause,NAnnoR,[{var,NAnnoR,'_'}],[], - [call_error(NAnnoR, {tuple,NAnnoR,[{atom,NAnnoR,badrecord},{atom,NAnnoR,Name}]})]} + [call_error(NAnnoR, {tuple,NAnnoR,[{atom,NAnnoR,badrecord},R]})]} ]}, St1}. @@ -752,7 +777,7 @@ record_setel(R, Name, Fs, Us0) -> {atom,Anno,setelement}},[I,Acc,Val]} end, R, Us)]}, {clause,NAnnoR,[{var,NAnnoR,'_'}],[], - [call_error(NAnnoR, {tuple,NAnnoR,[{atom,NAnnoR,badrecord},{atom,NAnnoR,Name}]})]}]}. + [call_error(NAnnoR, {tuple,NAnnoR,[{atom,NAnnoR,badrecord},R]})]}]}. %% Expand a call to record_info/2. We have checked that it is not %% shadowed by an import. @@ -900,11 +925,13 @@ opt_rec_vars_2({op,_,'orelse',Arg,{atom,_,fail}}, Rs) -> %% Since the second argument guarantees failure, %% it is safe to inspect the first argument. opt_rec_vars_2(Arg, Rs); -opt_rec_vars_2({call,_,{remote,_,{atom,_,erlang},{atom,_,is_record}}, - [{var,_,V},{atom,_,Tag},{integer,_,Sz}]}, Rs) -> - orddict:store(V, {Tag,Sz}, Rs); +opt_rec_vars_2({call,Anno, + {remote,_,{atom,_,erlang},{atom,_,is_record}=IsRecord}, + Args}, Rs) -> + opt_rec_vars_2({call,Anno,IsRecord,Args}, Rs); opt_rec_vars_2({call,_,{atom,_,is_record}, - [{var,_,V},{atom,_,Tag},{integer,_,Sz}]}, Rs) -> + [{var,_,V},{atom,_,Tag},{integer,_,Sz}]}, Rs) + when is_integer(Sz), 0 < Sz, Sz < 100 -> orddict:store(V, {Tag,Sz}, Rs); opt_rec_vars_2(_, Rs) -> Rs. diff --git a/lib/stdlib/src/erl_features.erl b/lib/stdlib/src/erl_features.erl new file mode 100644 index 000000000000..44056a27b0e6 --- /dev/null +++ b/lib/stdlib/src/erl_features.erl @@ -0,0 +1,545 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2023. 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(erl_features). +-feature(maybe_expr, enable). + +-export([all/0, + configurable/0, + info/1, + short/1, + long/1, + enabled/0, + keywords/0, + keywords/1, + keyword_fun/2, + keyword_fun/4, + used/1, + format_error/1, + format_error/2]). + +-type type() :: 'extension' | 'backwards_incompatible_change'. +-type status() :: 'experimental' + | 'approved' + | 'permanent' + | 'rejected'. +-type release() :: non_neg_integer(). +-type feature() :: atom(). +-type error() :: {?MODULE, + {'invalid_features', [atom()]} + | {'incorrect_features', [atom()]} + | {'not_configurable', [atom()]}}. + +-define(VALID_FEATURE(Feature), + (case is_valid(Feature) of + false -> + error(invalid_feature, [Feature], + [{error_info, + #{module => ?MODULE, + cause => #{1 => "unknown feature"}}}]); + true -> ok + end)). + +%% Specification about currently known features. +feature_specs() -> + #{maybe_expr => + #{short => "Value based error handling (EEP49)", + description => + "Implementation of the maybe expression proposed in EEP49 -- " + "Value based error handling.", + status => experimental, + experimental => 25, + keywords => ['maybe', 'else'], + type => extension}}. + +%% Return all currently known features. +-spec all() -> [feature()]. +all() -> + Map = case persistent_term:get({?MODULE, feature_specs}, none) of + none -> init_specs(); + M -> M + end, + lists:sort(maps:keys(Map)). + +-spec configurable() -> [feature()]. +configurable() -> + [Ftr || Ftr <- all(), + lists:member(maps:get(status, info(Ftr)), + [experimental, approved])]. + +is_valid(Ftr) -> + lists:member(Ftr, all()). + +is_configurable(Ftr) -> + lists:member(Ftr, configurable()). + +-spec short(feature()) -> iolist() | no_return(). +short(Feature) -> + #{short := Short, + status := Status} = Info = info(Feature), + #{Status := Release} = Info, + io_lib:format("~-40s ~-12s (~p)", [Short, Status, Release]). + +-spec long(feature()) -> iolist() | no_return(). +long(Feature) -> + #{short := Short, + description := Description, + status := Status, + keywords := Keywords, + type := Type} = Info = info(Feature), + StatusFmt = " ~-10s ~-12s (~p)\n", + History = [io_lib:format(StatusFmt, [T, S, R]) + || {T, S, R} <- history(Status, Info)], + KeywordsStrs = + if Keywords == [] -> ""; + true -> + io_lib:format(" ~-10s ~p\n", ["Keywords", Keywords]) + end, + Lines = [{"~s - ~s\n", [Feature, Short]}, + {" ~-10s ~s\n", ["Type", Type]}, + {"~s", [History]}, + {"~s", [KeywordsStrs]}, + {"\n~s\n", [nqTeX(Description)]}], + [io_lib:format(FStr, Args) || {FStr, Args} <- Lines]. + +history(Current, Info) -> + G = fun(Key, S) -> + case maps:find(Key, Info) of + error -> []; + {ok, R} -> [{S, Key, R}] + end + end, + F = fun(Key) -> G(Key, "") end, + History = + case Current of + experimental -> []; + rejected -> F(experimental); + approved -> F(experimental); + permanent -> F(approved) ++ F(experimental) + end, + G(Current, "Status") ++ History. + +%% Dead simple line breaking for better presentation. +nqTeX(String) -> + Words = string:tokens(String, " "), + WithLens = lists:map(fun(W) -> {W, length(W)} end, Words), + adjust(WithLens). + +adjust(WLs) -> + adjust(0, WLs, []). + +adjust(_, [], Ws) -> + lists:reverse(tl(Ws)); +adjust(Col, [{W, L}| WLs], Ws) -> + case Col + L > 72 of + true -> + lists:reverse(["\n"| tl(Ws)]) + ++ adjust(L+1, WLs, [" ", W]); + false -> + adjust(Col + L + 1, WLs, [" ", W| Ws]) + end. + + +-spec info(feature()) -> FeatureInfoMap | no_return() + when + Description :: string(), + FeatureInfoMap :: + #{description := Description, + short := Description, + type := type(), + keywords := [atom()], + status := status(), + experimental => release(), + approved => release(), + permanent => release(), + rejected => release() + }. +info(Feature) -> + ?VALID_FEATURE(Feature), + + Map = persistent_term:get({?MODULE, feature_specs}), + maps:get(Feature, Map). + +%% New keywords introduced by a feature. +-spec keywords(feature()) -> [atom()] | no_return(). +keywords(Ftr) -> + ?VALID_FEATURE(Ftr), + + #{keywords := Keywords} = info(Ftr), + Keywords. + +%% Internal - Ftr is valid +keywords(Ftr, Map) -> + maps:get(keywords, maps:get(Ftr, Map)). + +%% Utilities +%% Returns list of enabled features and a new keywords function +-spec keyword_fun([term()], fun((atom()) -> boolean())) -> + {'ok', {[feature()], fun((atom()) -> boolean())}} + | {'error', error()}. +keyword_fun(Opts, KeywordFun) -> + %% Get items enabling or disabling features, preserving order. + IsFtr = fun({feature, _, enable}) -> true; + ({feature, _, disable}) -> true; + (_) -> false + end, + FeatureOps = lists:filter(IsFtr, Opts), + {AddFeatures, DelFeatures, RawFtrs} = collect_features(FeatureOps), + + case configurable_features(RawFtrs) of + ok -> + {ok, Fun} = add_features_fun(AddFeatures, KeywordFun), + {ok, FunX} = remove_features_fun(DelFeatures, Fun), + {ok, {AddFeatures -- DelFeatures, FunX}}; + {error, _} = Error -> + Error + end. + +-spec keyword_fun('enable' | 'disable', feature(), [feature()], + fun((atom()) -> boolean())) -> + {'ok', {[feature()], fun((atom()) -> boolean())}} + | {'error', error()}. +keyword_fun(Ind, Feature, Ftrs, KeywordFun) -> + case is_configurable(Feature) of + true -> + case Ind of + enable -> + NewFtrs = case lists:member(Feature, Ftrs) of + true -> Ftrs; + false -> [Feature | Ftrs] + end, + {ok, {NewFtrs, + add_feature_fun(Feature, KeywordFun)}}; + disable -> + {ok, {Ftrs -- [Feature], + remove_feature_fun(Feature, KeywordFun)}} + end; + false -> + Error = + case is_valid(Feature) of + true -> not_configurable; + false -> invalid_features + end, + {error, {?MODULE, {Error, [Feature]}}} + end. + +add_feature_fun(Feature, F) -> + Words = keywords(Feature), + fun(Word) -> + lists:member(Word, Words) + orelse F(Word) + end. + +remove_feature_fun(Feature, F) -> + Words = keywords(Feature), + fun(Word) -> + case lists:member(Word, Words) of + true -> false; + false -> F(Word) + end + end. + +-spec add_features_fun([feature()], fun((atom()) -> boolean())) -> + {'ok', fun((atom()) -> boolean())}. +add_features_fun(Features, F) -> + {ok, lists:foldl(fun add_feature_fun/2, F, Features)}. + +-spec remove_features_fun([feature()], fun((atom()) -> boolean())) -> + {'ok', fun((atom()) -> boolean())}. +remove_features_fun(Features, F) -> + {ok, lists:foldl(fun remove_feature_fun/2, F, Features)}. + +configurable_features(Features) -> + case lists:all(fun is_configurable/1, Features) of + true -> + ok; + false -> + feature_error(Features) + end. + +feature_error(Features) -> + IsInvalid = fun(Ftr) -> not is_valid(Ftr) end, + IsNonConfig = fun(Ftr) -> + is_valid(Ftr) + andalso + (not is_configurable(Ftr)) + end, + Invalid = lists:filter(IsInvalid, Features), + NonConfig = lists:filter(IsNonConfig, Features), + {Error, Culprits} = + case {Invalid, NonConfig} of + {[], NC} -> {not_configurable, NC}; + {NV, []} -> {invalid_features, NV}; + {NV, NC} -> {incorrect_features, NV ++ NC} + end, + {error, {?MODULE, {Error, Culprits}}}. + +-spec format_error(Reason, StackTrace) -> ErrorDescription + when Reason :: term(), + StackTrace :: erlang:stacktrace(), + ArgumentPosition :: pos_integer(), + ErrorDescription :: #{ArgumentPosition => unicode:chardata(), + general => unicode:chardata(), + reason => unicode:chardata()}. +format_error(Reason, [{_M, _F, _Args, Info}| _St]) -> + ErrorInfo = proplists:get_value(error_info, Info, #{}), + ErrorMap = maps:get(cause, ErrorInfo), + ErrorMap#{reason => io_lib:format("~p: ~p", [?MODULE, Reason])}. + +-spec format_error(Reason) -> iolist() + when Reason :: term(). +format_error({Error, Features}) -> + Fmt = fun F([Ftr]) -> io_lib:fwrite("'~p'", [Ftr]); + F([Ftr1, Ftr2]) -> + io_lib:fwrite("'~p' and '~p'", [Ftr1, Ftr2]); + F([Ftr| Ftrs]) -> + io_lib:fwrite("'~p', ~s", [Ftr, F(Ftrs)]) + end, + FmtStr = + case {Error, Features} of + {invalid_features, [_]} -> + "the feature ~s does not exist."; + {invalid_features, _} -> + "the features ~s do not exist."; + {not_configurable, [_]} -> + "the feature ~s is not configurable."; + {not_configurable, _} -> + "the features ~s are not configurable."; + {incorrect_features, _} -> + "the features ~s do not exist or are not configurable." + end, + + io_lib:fwrite(FmtStr, [Fmt(Features)]). + +%% Hold the state of which features are currently enabled. +%% This is almost static, so we go for an almost permanent state, +%% i.e., use persistent_term. +init_features() -> + Map = init_specs(), + + persistent_term:put({?MODULE, enabled_features}, []), + persistent_term:put({?MODULE, keywords}, []), + + RawOps = lists:filter(fun({Tag, _}) -> + Tag == 'enable-feature' + orelse Tag == 'disable-feature'; + (_) -> false + end, + init:get_arguments()), + + Cnv = fun('enable-feature') -> enable; + ('disable-feature') -> disable + end, + + FeatureOps = lists:append(lists:map(fun({Tag, Strings}) -> + lists:map(fun(S) -> + {Tag, S} end, + Strings) + end, + RawOps)), + + %% Convert failure, e.g., too long string for atom, to not + %% being a valid feature. + F = fun({Tag, String}) -> + try + Atom = list_to_atom(String), + case is_configurable(Atom) of + true -> {true, {feature, Atom, Cnv(Tag)}}; + false when Atom == all -> + {true, {feature, Atom, Cnv(Tag)}}; + false -> false + end + catch + _ -> false + end + end, + FOps = lists:filtermap(F, FeatureOps), + {Features, _, _} = collect_features(FOps), + {Enabled0, Keywords} = + lists:foldl(fun(Ftr, {Ftrs, Keys}) -> + case lists:member(Ftr, Ftrs) of + true -> + {Ftrs, Keys}; + false -> + {[Ftr| Ftrs], + keywords(Ftr, Map) ++ Keys} + end + end, + {[], []}, + Features), + + %% Save state + Enabled = lists:uniq(Enabled0), + enabled_features(Enabled), + set_keywords(Keywords), + persistent_term:put({?MODULE, init_done}, true), + ok. + +init_specs() -> + Specs = case os:getenv("OTP_TEST_FEATURES") of + "true" -> test_features(); + _ -> feature_specs() + end, + persistent_term:put({?MODULE, feature_specs}, Specs), + Specs. + +ensure_init() -> + case persistent_term:get({?MODULE, init_done}, false) of + true -> ok; + false -> + init_features() + end. + +%% Return list of currently enabled features +-spec enabled() -> [feature()]. +enabled() -> + ensure_init(), + persistent_term:get({?MODULE, enabled_features}). + +enabled_features(Ftrs) -> + persistent_term:put({?MODULE, enabled_features}, Ftrs). + +%% Return list of keywords activated by enabled features +-spec keywords() -> [atom()]. +keywords() -> + ensure_init(), + persistent_term:get({?MODULE, keywords}). + +set_keywords(Words) -> + persistent_term:put({?MODULE, keywords}, Words). + +%% Return features used by module or beam file +-spec used(module() | file:filename()) -> [feature()]. +used(Module) when is_atom(Module) -> + case code:get_object_code(Module) of + error -> + not_found; + {_Mod, Bin, _Fname} -> + features_in(Bin) + end; +used(FName) when is_list(FName) -> + features_in(FName). + +features_in(NameOrBin) -> + case beam_lib:chunks(NameOrBin, ["Meta"], [allow_missing_chunks]) of + {ok, {_, [{_, missing_chunk}]}} -> + []; + {ok, {_, [{_, Meta}]}} -> + MetaData = erlang:binary_to_term(Meta), + proplists:get_value(enabled_features, MetaData, []); + _ -> + not_found + end. + +%% Interpret feature ops (enable or disable) to build the full set of +%% features. The meta feature 'all' is expanded to all known +%% features. +collect_features(FOps) -> + %% Features enabled by default + Enabled = [Ftr || Ftr <- all(), + maps:get(status, info(Ftr)) == approved], + collect_features(FOps, Enabled, [], []). + +collect_features([], Add, Del, Raw) -> + {Add, Del, Raw}; +collect_features([{feature, all, enable}| FOps], Add, _Del, Raw) -> + All = configurable(), + Add1 = lists:foldl(fun add_ftr/2, Add, All), + collect_features(FOps, Add1, [], Raw); +collect_features([{feature, Feature, enable}| FOps], Add, Del, Raw) -> + collect_features(FOps, add_ftr(Feature, Add), Del -- [Feature], + Raw ++ [Feature]); +collect_features([{feature, all, disable}| FOps], _Add, Del, Raw) -> + %% Start over + All = configurable(), + collect_features(FOps, [], Del -- All, Raw); +collect_features([{feature, Feature, disable}| FOps], Add, Del, Raw) -> + collect_features(FOps, Add -- [Feature], + add_ftr(Feature, Del), + Raw ++ [Feature]). + +add_ftr(F, []) -> + [F]; +add_ftr(F, [F| _] = Fs) -> + Fs; +add_ftr(F, [F0| Fs]) -> + [F0| add_ftr(F, Fs)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Test features - not present in a release +test_features() -> + #{experimental_ftr_1 => + #{short => "Experimental test feature #1", + description => + "Test feature in the experimental state. " + "It is disabled by default, but can be enabled.", + status => experimental, + experimental => 24, + keywords => ['ifn'], + type => extension}, + experimental_ftr_2 => + #{short => "Experimental test features #2", + description => + "Test feature in experimental state. " + "It is disabled by default, but can be enabled.", + status => experimental, + experimental => 25, + keywords => ['while', 'until'], + type => extension}, + approved_ftr_1 => + #{short => "Approved test feature #1", + description => "Test feature in the approved state. " + "It is on by default and can be disabled.", + status => approved, + experimental => 24, + approved => 25, + keywords => [], + type => extension}, + approved_ftr_2 => + #{short => "Approved test feature #2", + description => + "Test feature in the approved state. " + "It is enabled by default, but can still be disabled.", + status => approved, + experimental => 24, + approved => 25, + keywords => ['unless'], + type => extension}, + permanent_ftr => + #{short => "Permanent test feature", + description => "Test feature in the permanent state. " + "This means it is on by default and cannot be disabled. " + "It is now a permanent part of Erlang/OTP.", + status => permanent, + experimental => 17, + approved => 18, + permanent => 19, + keywords => [], + type => extension}, + rejected_ftr => + #{short => "Rejected test feature.", + description => + "Test feature existing only to end up as rejected. " + "It is not available and cannot be enabled. " + "This should be the only trace of it", + status => rejected, + experimental => 24, + rejected => 25, + keywords => ['inline', 'return', 'set'], + type => extension}}. diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index 52fbe470bd82..8f0b1e43ee10 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -78,6 +78,8 @@ guard_bif(is_map_key, 2) -> true; guard_bif(length, 1) -> true; guard_bif(map_size, 1) -> true; guard_bif(map_get, 2) -> true; +guard_bif(max, 2) -> true; +guard_bif(min, 2) -> true; guard_bif(node, 0) -> true; guard_bif(node, 1) -> true; guard_bif(round, 1) -> true; @@ -356,6 +358,7 @@ bif(node, 0) -> true; bif(node, 1) -> true; bif(nodes, 0) -> true; bif(nodes, 1) -> true; +bif(nodes, 2) -> true; bif(now, 0) -> true; bif(open_port, 2) -> true; bif(pid_to_list, 1) -> true; @@ -563,6 +566,7 @@ is_type(bool, 0) -> true; is_type(boolean, 0) -> true; is_type(byte, 0) -> true; is_type(char, 0) -> true; +is_type(dynamic, 0) -> true; is_type(float, 0) -> true; is_type(function, 0) -> true; is_type(identifier, 0) -> true; diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index d05c98f54f42..107b0970cfab 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -21,6 +21,7 @@ %% Do necessary checking of Erlang code. -module(erl_lint). +-feature(maybe_expr, enable). -export([module/1,module/2,module/3,format_error/1]). -export([exprs/2,exprs_opt/3,used_vars/2]). % Used from erl_eval.erl. @@ -31,6 +32,7 @@ -export([check_format_string/1]). -export_type([error_info/0, error_description/0]). +-export_type([fun_used_vars/0]). % Used from erl_eval.erl. -import(lists, [all/2,any/2, foldl/3,foldr/3, @@ -93,6 +95,18 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> -record(typeinfo, {attr, anno}). +-type type_id() :: {'export', []} + | {'record', atom()} + | {'spec', mfa()} + | {'type', ta()}. + +-record(used_type, {anno :: erl_anno:anno(), + at = {export, []} :: type_id()}). + +-type used_type() :: #used_type{}. + +-type fun_used_vars() :: #{erl_parse:abstract_expr() => {[atom()], fun_used_vars()}}. + %% Usage of records, functions, and imports. The variable table, which %% is passed on as an argument, holds the usage of variables. -record(usage, { @@ -101,7 +115,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> used_records = gb_sets:new() %Used record definitions :: gb_sets:set(atom()), used_types = maps:new() %Used type definitions - :: #{ta() := anno()} + :: #{ta() := [used_type()]} }). @@ -130,6 +144,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> not_removed=gb_sets:empty() %Not considered removed :: gb_sets:set(module_or_mfa()), func=[], %Current function + type_id=[], %Current type id warn_format=0, %Warn format calls enabled_warnings=[], %All enabled warnings (ordset). nowarn_bif_clash=[], %All no warn bif clashes (ordset). @@ -140,6 +155,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> %outside any fun or lc xqlc= false :: boolean(), %true if qlc.hrl included called= [] :: [{fa(),anno()}], %Called functions + fun_used_vars = undefined %Funs used vars + :: fun_used_vars() | undefined, usage = #usage{} :: #usage{}, specs = maps:new() %Type specifications :: #{mfa() => anno()}, @@ -151,9 +168,13 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) -> :: #{ta() => #typeinfo{}}, exp_types=gb_sets:empty() %Exported types :: gb_sets:set(ta()), + feature_keywords = %Keywords in + %configurable features + feature_keywords() :: #{atom() => atom()}, bvt = none :: 'none' | [any()], %Variables in binary pattern gexpr_context = guard %Context of guard expression - :: gexpr_context() + :: gexpr_context(), + load_nif=false :: boolean() %true if calls erlang:load_nif/2 }). -type lint_state() :: #lint{}. @@ -176,12 +197,21 @@ format_error(pmod_unsupported) -> %% io_lib:format("module '~s' already imported from package '~s'", [M, P]); format_error(non_latin1_module_unsupported) -> "module names with non-latin1 characters are not supported"; +format_error(empty_module_name) -> + "the module name must not be empty"; +format_error(blank_module_name) -> + "the module name must contain at least one visible character"; +format_error(ctrl_chars_in_module_name) -> + "the module name must not contain control characters"; format_error(invalid_call) -> "invalid function call"; format_error(invalid_record) -> "invalid record expression"; +format_error({future_feature, Ftr, Atom}) -> + io_lib:format("atom '~p' is reserved in the experimental feature '~p'", + [Atom, Ftr]); format_error({attribute,A}) -> io_lib:format("attribute ~tw after function definitions", [A]); format_error({missing_qlc_hrl,A}) -> @@ -190,6 +220,10 @@ format_error({redefine_import,{{F,A},M}}) -> io_lib:format("function ~tw/~w already imported from ~w", [F,A,M]); format_error({bad_inline,{F,A}}) -> io_lib:format("inlined function ~tw/~w undefined", [F,A]); +format_error({undefined_nif,{F,A}}) -> + io_lib:format("nif ~tw/~w undefined", [F,A]); +format_error(no_load_nif) -> + io_lib:format("nifs defined, but no call to erlang:load_nif/2", []); format_error({invalid_deprecated,D}) -> io_lib:format("badly formed deprecated attribute ~tw", [D]); format_error({bad_deprecated,{F,A}}) -> @@ -281,13 +315,14 @@ format_error({too_many_arguments,Arity}) -> %% --- patterns and guards --- format_error(illegal_pattern) -> "illegal pattern"; format_error(illegal_map_key) -> "illegal map key in pattern"; -format_error(illegal_bin_pattern) -> - "binary patterns cannot be matched in parallel using '='"; format_error(illegal_expr) -> "illegal expression"; format_error({illegal_guard_local_call, {F,A}}) -> io_lib:format("call to local/imported function ~tw/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; +format_error(match_float_zero) -> + "matching on the float 0.0 will no longer also match -0.0 in OTP 27. If " + "you specifically intend to match 0.0 alone, write +0.0 instead."; %% --- maps --- format_error(illegal_map_construction) -> "only association operators '=>' are allowed in map construction"; @@ -403,12 +438,8 @@ format_error({undefined_type, {TypeName, Arity}}) -> io_lib:format("type ~tw~s undefined", [TypeName, gen_type_paren(Arity)]); format_error({unused_type, {TypeName, Arity}}) -> io_lib:format("type ~tw~s is unused", [TypeName, gen_type_paren(Arity)]); -format_error({new_builtin_type, {TypeName, Arity}}) -> - io_lib:format("type ~w~s is a new builtin type; " - "its (re)definition is allowed only until the next release", - [TypeName, gen_type_paren(Arity)]); -format_error({builtin_type, {TypeName, Arity}}) -> - io_lib:format("type ~w~s is a builtin type; it cannot be redefined", +format_error({redefine_builtin_type, {TypeName, Arity}}) -> + io_lib:format("local redefinition of built-in type: ~w~s", [TypeName, gen_type_paren(Arity)]); format_error({renamed_type, OldName, NewName}) -> io_lib:format("type ~w() is now called ~w(); " @@ -456,9 +487,6 @@ format_error({deprecated_builtin_type, {Name, Arity}, format_error({not_exported_opaque, {TypeName, Arity}}) -> io_lib:format("opaque type ~tw~s is not exported", [TypeName, gen_type_paren(Arity)]); -format_error({underspecified_opaque, {TypeName, Arity}}) -> - io_lib:format("opaque type ~tw~s is underspecified and therefore meaningless", - [TypeName, gen_type_paren(Arity)]); format_error({bad_dialyzer_attribute,Term}) -> io_lib:format("badly formed dialyzer attribute: ~tw", [Term]); format_error({bad_dialyzer_option,Term}) -> @@ -518,10 +546,9 @@ used_vars(Exprs, BindingsList) -> ({V,_Val}, Vs0) -> [{V,{bound,unused,[]}} | Vs0] end, [], BindingsList), Vt = orddict:from_list(Vs), - {Evt,_St} = exprs(set_file(Exprs, "nofile"), Vt, start()), - {ok, foldl(fun({V,{_,used,_}}, L) -> [V | L]; - (_, L) -> L - end, [], Evt)}. + St0 = (start())#lint{fun_used_vars=maps:new()}, + {_Evt,St1} = exprs(Exprs, Vt, St0), + St1#lint.fun_used_vars. %% module([Form]) -> %% module([Form], FileName) -> @@ -568,6 +595,7 @@ module(Forms, FileName) -> ErrorInfo :: error_info()). module(Forms, FileName, Opts0) -> + %% FIXME Hmm, this is not coherent with the semantics of features %% We want the options given on the command line to take %% precedence over options in the module. Opts = compiler_options(Forms) ++ Opts0, @@ -638,13 +666,25 @@ start(File, Opts) -> true, Opts)}, {nif_inline, bool_option(warn_nif_inline, nowarn_nif_inline, + true, Opts)}, + {keyword_warning, + bool_option(warn_keywords, nowarn_keywords, + false, Opts)}, + {redefined_builtin_type, + bool_option(warn_redefined_builtin_type, nowarn_redefined_builtin_type, + true, Opts)}, + {singleton_typevar, + bool_option(warn_singleton_typevar, nowarn_singleton_typevar, + true, Opts)}, + {match_float_zero, + bool_option(warn_match_float_zero, nowarn_match_float_zero, true, Opts)} ], Enabled1 = [Category || {Category,true} <- Enabled0], Enabled = ordsets:from_list(Enabled1), Calls = case ordsets:is_element(unused_function, Enabled) of true -> - maps:from_list([{{module_info,1},pseudolocals()}]); + #{{module_info,1} => pseudolocals()}; false -> undefined end, @@ -979,7 +1019,8 @@ post_traversal_check(Forms, St0) -> StF = check_local_opaque_types(StE), StG = check_dialyzer_attribute(Forms, StF), StH = check_callback_information(StG), - check_removed(Forms, StH). + StI = check_nifs(Forms, StH), + check_removed(Forms, StI). %% check_behaviour(State0) -> State %% Check that the behaviour attribute is valid. @@ -1288,8 +1329,10 @@ check_undefined_types(#lint{usage=Usage,types=Def}=St0) -> TA <- UTAs, not is_map_key(TA, Def), not is_default_type(TA)], - foldl(fun ({TA,Anno}, St) -> - add_error(Anno, {undefined_type,TA}, St) + foldl(fun ({TA,UsedTypeList}, St) -> + foldl( fun(#used_type{anno = Anno}, St1) -> + add_error(Anno, {undefined_type,TA}, St1) + end, St, UsedTypeList) end, St0, Undef). %% check_bif_clashes(Forms, State0) -> State @@ -1310,6 +1353,19 @@ check_option_functions(Forms, Tag0, Type, St0) -> Bad = [{FA,Anno} || {FA,Anno} <- FAsAnno, not member(FA, DefFunctions)], func_location_error(Type, Bad, St0). +check_nifs(Forms, St0) -> + FAsAnno = [{FA,Anno} || {attribute, Anno, nifs, Args} <- Forms, + FA <- Args], + St1 = case {FAsAnno, St0#lint.load_nif} of + {[{_,Anno1}|_], false} -> + add_warning(Anno1, no_load_nif, St0); + _ -> + St0 + end, + DefFunctions = gb_sets:subtract(St1#lint.defined, gb_sets:from_list(pseudolocals())), + Bad = [{FA,Anno} || {FA,Anno} <- FAsAnno, not gb_sets:is_element(FA, DefFunctions)], + func_location_error(undefined_nif, Bad, St1). + nowarn_function(Tag, Opts) -> ordsets:from_list([FA || {Tag1,FAs} <- Opts, Tag1 =:= Tag, @@ -1364,7 +1420,7 @@ check_unused_records(Forms, St0) -> maps:remove(Used, Recs) end, St1#lint.records, UsedRecords), Unused = [{Name,Anno} || - {Name,{Anno,_Fields}} <- maps:to_list(URecs), + Name := {Anno,_Fields} <- URecs, element(1, loc(Anno, St1)) =:= FirstFile], foldl(fun ({N,Anno}, St) -> add_warning(Anno, {unused_record, N}, St) @@ -1423,21 +1479,21 @@ export(Anno, Es, #lint{exports = Es0, called = Called} = St0) -> -spec export_type(anno(), [ta()], lint_state()) -> lint_state(). %% Mark types as exported; also mark them as used from the export line. -export_type(Anno, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) -> - UTs0 = Usage#usage.used_types, - try foldl(fun ({T,A}=TA, {E,U,St2}) when is_atom(T), is_integer(A) -> +export_type(Anno, ETs, #lint{exp_types = ETs0} = St0) -> + try foldl(fun ({T,A}=TA, {E,St2}) when is_atom(T), is_integer(A) -> St = case gb_sets:is_element(TA, E) of true -> Warn = {duplicated_export_type,TA}, add_warning(Anno, Warn, St2); false -> - St2 + St3 = St2#lint{type_id = {export, []}}, + used_type(TA, Anno, St3) end, - {gb_sets:add_element(TA, E), maps:put(TA, Anno, U), St} + {gb_sets:add_element(TA, E), St} end, - {ETs0,UTs0,St0}, ETs) of - {ETs1,UTs1,St1} -> - St1#lint{usage = Usage#usage{used_types = UTs1}, exp_types = ETs1} + {ETs0,St0}, ETs) of + {ETs1,St1} -> + St1#lint{exp_types = ETs1} catch error:_ -> add_error(Anno, {bad_export_type, ETs}, St0) @@ -1654,7 +1710,12 @@ pattern({var,Anno,V}, _Vt, Old, St) -> pat_var(V, Anno, Old, [], St); pattern({char,_Anno,_C}, _Vt, _Old, St) -> {[],[],St}; pattern({integer,_Anno,_I}, _Vt, _Old, St) -> {[],[],St}; -pattern({float,_Anno,_F}, _Vt, _Old, St) -> {[],[],St}; +pattern({float,Anno,F}, _Vt, _Old, St0) -> + St = case F == 0 andalso is_warn_enabled(match_float_zero, St0) of + true -> add_warning(Anno, match_float_zero, St0); + false -> St0 + end, + {[], [], St}; pattern({atom,Anno,A}, _Vt, _Old, St) -> {[],[],keyword_warning(Anno, A, St)}; pattern({string,_Anno,_S}, _Vt, _Old, St) -> {[],[],St}; @@ -1697,10 +1758,9 @@ pattern({op,_Anno,'++',{string,_Ai,_S},R}, Vt, Old, St) -> pattern({match,_Anno,Pat1,Pat2}, Vt0, Old, St0) -> {Lvt, Lnew, St1} = pattern(Pat1, Vt0, Old, St0), {Rvt, Rnew, St2} = pattern(Pat2, Vt0, Old, St1), - St3 = reject_invalid_alias(Pat1, Pat2, Vt0, St2), - {Vt1, St4} = vtmerge_pat(Lvt, Rvt, St3), - {New, St5} = vtmerge_pat(Lnew, Rnew, St4), - {Vt1, New, St5}; + {Vt1, St3} = vtmerge_pat(Lvt, Rvt, St2), + {New, St4} = vtmerge_pat(Lnew, Rnew, St3), + {Vt1, New, St4}; %% Catch legal constant expressions, including unary +,-. pattern(Pat, _Vt, _Old, St) -> case is_pattern_expr(Pat) of @@ -1727,101 +1787,6 @@ check_multi_field_init(Fs, Anno, Fields, St) -> false -> St end. -%% reject_invalid_alias(Pat, Expr, Vt, St) -> St' -%% Reject aliases for binary patterns at the top level. -%% Reject aliases for maps patterns at the top level. -%% The variables table (Vt) are for maps checkking. - -reject_invalid_alias_expr({bin,_,_}=P, {match,_,P0,E}, Vt, St0) -> - St = reject_invalid_alias(P, P0, Vt, St0), - reject_invalid_alias_expr(P, E, Vt, St); -reject_invalid_alias_expr({map,_,_}=P, {match,_,P0,E}, Vt, St0) -> - St = reject_invalid_alias(P, P0, Vt, St0), - reject_invalid_alias_expr(P, E, Vt, St); -reject_invalid_alias_expr({match,_,_,_}=P, {match,_,P0,E}, Vt, St0) -> - St = reject_invalid_alias(P, P0, Vt, St0), - reject_invalid_alias_expr(P, E, Vt, St); -reject_invalid_alias_expr(_, _, _, St) -> St. - - - -%% reject_invalid_alias(Pat1, Pat2, St) -> St' -%% Aliases of binary patterns, such as <> = <> or even -%% <> = <>, are not allowed. Traverse the patterns in parallel -%% and generate an error if any binary aliases are found. -%% We generate an error even if is obvious that the overall pattern can't -%% possibly match, for instance, {a,<>,c}={x,<>} WILL generate an -%% error. -%% Maps should reject unbound variables here. - -reject_invalid_alias({bin,Anno,_}, {bin,_,_}, _, St) -> - add_error(Anno, illegal_bin_pattern, St); -reject_invalid_alias({map,_Anno,Ps1}, {map,_,Ps2}, Vt, St0) -> - Fun = fun ({map_field_exact,_,{var,A,K},_V}, Sti) -> - case is_var_bound(K,Vt) of - true -> - Sti; - false -> - add_error(A, {unbound_var,K}, Sti) - end; - ({map_field_exact,_A,_K,_V}, Sti) -> - Sti - end, - foldl(Fun, foldl(Fun, St0, Ps1), Ps2); -reject_invalid_alias({cons,_,H1,T1}, {cons,_,H2,T2}, Vt, St0) -> - St = reject_invalid_alias(H1, H2, Vt, St0), - reject_invalid_alias(T1, T2, Vt, St); -reject_invalid_alias({tuple,_,Es1}, {tuple,_,Es2}, Vt, St) -> - reject_invalid_alias_list(Es1, Es2, Vt, St); -reject_invalid_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2}, Vt, - #lint{records=Recs}=St) -> - case Recs of - #{Name1 := {_Anno1,Fields1}, Name2 := {_Anno2,Fields2}} -> - reject_invalid_alias_rec(Pfs1, Pfs2, Fields1, Fields2, Vt, St); - #{} -> - %% One or more non-existing records. (An error messages has - %% already been generated, so we are done here.) - St - end; -reject_invalid_alias({match,_,P1,P2}, P, Vt, St0) -> - St = reject_invalid_alias(P1, P, Vt, St0), - reject_invalid_alias(P2, P, Vt, St); -reject_invalid_alias(P, {match,_,_,_}=M, Vt, St) -> - reject_invalid_alias(M, P, Vt, St); -reject_invalid_alias(_P1, _P2, _Vt, St) -> St. - -reject_invalid_alias_list([E1|Es1], [E2|Es2], Vt, St0) -> - St = reject_invalid_alias(E1, E2, Vt, St0), - reject_invalid_alias_list(Es1, Es2, Vt, St); -reject_invalid_alias_list(_, _, _, St) -> St. - -reject_invalid_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, Vt, St) -> - %% We treat records as if they have been converted to tuples. - PfsA1 = rbia_field_vars(PfsA0), - PfsB1 = rbia_field_vars(PfsB0), - FieldsA1 = rbia_fields(lists:reverse(FieldsA0), 0, []), - FieldsB1 = rbia_fields(lists:reverse(FieldsB0), 0, []), - FieldsA = sofs:relation(FieldsA1), - PfsA = sofs:relation(PfsA1), - A = sofs:join(FieldsA, 1, PfsA, 1), - FieldsB = sofs:relation(FieldsB1), - PfsB = sofs:relation(PfsB1), - B = sofs:join(FieldsB, 1, PfsB, 1), - C = sofs:join(A, 2, B, 2), - D = sofs:projection({external,fun({_,_,P1,_,P2}) -> {P1,P2} end}, C), - E = sofs:to_external(D), - {Ps1,Ps2} = lists:unzip(E), - reject_invalid_alias_list(Ps1, Ps2, Vt, St). - -rbia_field_vars(Fs) -> - [{Name,Pat} || {record_field,_,{atom,_,Name},Pat} <- Fs]. - -rbia_fields([{record_field,_,{atom,_,Name},_}|Fs], I, Acc) -> - rbia_fields(Fs, I+1, [{Name,I}|Acc]); -rbia_fields([_|Fs], I, Acc) -> - rbia_fields(Fs, I+1, Acc); -rbia_fields([], _, Acc) -> Acc. - %% is_pattern_expr(Expression) -> boolean(). %% Test if a general expression is a valid pattern expression. @@ -1845,14 +1810,14 @@ is_pattern_expr_1({integer,_Anno,_I}) -> true; is_pattern_expr_1({float,_Anno,_F}) -> true; is_pattern_expr_1({atom,_Anno,_A}) -> true; is_pattern_expr_1({tuple,_Anno,Es}) -> - all(fun is_pattern_expr/1, Es); + all(fun is_pattern_expr_1/1, Es); is_pattern_expr_1({nil,_Anno}) -> true; is_pattern_expr_1({cons,_Anno,H,T}) -> is_pattern_expr_1(H) andalso is_pattern_expr_1(T); is_pattern_expr_1({op,_Anno,Op,A}) -> erl_internal:arith_op(Op, 1) andalso is_pattern_expr_1(A); is_pattern_expr_1({op,_Anno,Op,A1,A2}) -> - erl_internal:arith_op(Op, 2) andalso all(fun is_pattern_expr/1, [A1,A2]); + erl_internal:arith_op(Op, 2) andalso all(fun is_pattern_expr_1/1, [A1,A2]); is_pattern_expr_1(_Other) -> false. pattern_map(Ps, Vt0, Old, St0) -> @@ -2032,7 +1997,8 @@ bit_size_check(Anno, all, #bittype{type=Type}, St) -> binary -> {all,St}; _ -> {unknown,add_error(Anno, illegal_bitsize, St)} end; -bit_size_check(Anno, Size, #bittype{type=Type,unit=Unit}, St) -> +bit_size_check(Anno, Size, #bittype{type=Type,unit=Unit}, St) + when is_integer(Size), is_integer(Unit) -> Sz = Unit * Size, %Total number of bits! St2 = elemtype_check(Anno, Type, Sz, St), {Sz,St2}. @@ -2194,6 +2160,9 @@ gexpr({op,_,'andalso',L,R}, Vt, St) -> gexpr_list([L,R], Vt, St); gexpr({op,_,'orelse',L,R}, Vt, St) -> gexpr_list([L,R], Vt, St); +gexpr({op,_Anno,EqOp,L,R}, Vt, St0) when EqOp =:= '=:='; EqOp =:= '=/=' -> + St1 = expr_check_match_zero(R, expr_check_match_zero(L, St0)), + gexpr_list([L,R], Vt, St1); gexpr({op,Anno,Op,L,R}, Vt, St0) -> {Avt,St1} = gexpr_list([L,R], Vt, St0), case is_gexpr_op(Op, 2) of @@ -2247,13 +2216,24 @@ is_guard_test(Expression, Forms) -> IsOverridden :: fun((fa()) -> boolean()). is_guard_test(Expression, Forms, IsOverridden) -> - RecordAttributes = [A || A = {attribute, _, record, _D} <- Forms], - St0 = foldl(fun(Attr0, St1) -> - Attr = set_file(Attr0, "none"), - attribute_state(Attr, St1) - end, start(), RecordAttributes), - is_guard_test2(set_file(Expression, "nofile"), - {St0#lint.records,IsOverridden}). + NoFileExpression = set_file(Expression, "nofile"), + + %% Unless the expression constructs a record, the record + %% definitions are not needed. Therefore, because there can be a + %% huge number of record definitions in the forms, delay + %% processing the forms until we'll know that the record + %% definitions are truly needed. + F = fun() -> + St = foldl(fun({attribute, _, record, _}=Attr0, St0) -> + Attr = set_file(Attr0, "none"), + attribute_state(Attr, St0); + (_, St0) -> + St0 + end, start(), Forms), + St#lint.records + end, + + is_guard_test2(NoFileExpression, {F,IsOverridden}). %% is_guard_test2(Expression, RecordDefs :: dict:dict()) -> boolean(). is_guard_test2({call,Anno,{atom,Ar,record},[E,A]}, Info) -> @@ -2291,7 +2271,13 @@ is_gexpr({record_index,_A,_Name,Field}, Info) -> is_gexpr(Field, Info); is_gexpr({record_field,_A,Rec,_Name,Field}, Info) -> is_gexpr_list([Rec,Field], Info); -is_gexpr({record,A,Name,Inits}, Info) -> +is_gexpr({record,A,Name,Inits}, Info0) -> + Info = case Info0 of + {#{},_} -> + Info0; + {F,IsOverridden} when is_function(F, 0) -> + {F(),IsOverridden} + end, is_gexpr_fields(Inits, A, Name, Info); is_gexpr({bin,_A,Fs}, Info) -> all(fun ({bin_element,_Anno,E,Sz,_Ts}) -> @@ -2376,6 +2362,8 @@ expr({lc,_Anno,E,Qs}, Vt, St) -> handle_comprehension(E, Qs, Vt, St); expr({bc,_Anno,E,Qs}, Vt, St) -> handle_comprehension(E, Qs, Vt, St); +expr({mc,_Anno,E,Qs}, Vt, St) -> + handle_comprehension(E, Qs, Vt, St); expr({tuple,_Anno,Es}, Vt, St) -> expr_list(Es, Vt, St); expr({map,_Anno,Es}, Vt, St) -> @@ -2563,9 +2551,25 @@ expr({'catch',Anno,E}, Vt, St0) -> {vtupdate(vtunsafe({'catch',Anno}, Evt, Vt), Evt),St}; expr({match,_Anno,P,E}, Vt, St0) -> {Evt,St1} = expr(E, Vt, St0), - {Pvt,Pnew,St2} = pattern(P, vtupdate(Evt, Vt), St1), - St = reject_invalid_alias_expr(P, E, Vt, St2), + {Pvt,Pnew,St} = pattern(P, vtupdate(Evt, Vt), St1), {vtupdate(Pnew, vtmerge(Evt, Pvt)),St}; +expr({maybe_match,Anno,P,E}, Vt, St0) -> + expr({match,Anno,P,E}, Vt, St0); +expr({'maybe',Anno,Es}, Vt, St) -> + %% No variables are exported. + {Evt0, St1} = exprs(Es, Vt, St), + Evt1 = vtupdate(vtunsafe({'maybe',Anno}, Evt0, Vt), Vt), + Evt2 = vtmerge(Evt0, Evt1), + {Evt2,St1}; +expr({'maybe',MaybeAnno,Es,{'else',ElseAnno,Cs}}, Vt, St) -> + %% No variables are exported. + {Evt0, St1} = exprs(Es, Vt, St), + Evt1 = vtupdate(vtunsafe({'maybe',MaybeAnno}, Evt0, Vt), Vt), + {Cvt0, St2} = icrt_clauses(Cs, {'else',ElseAnno}, Evt1, St1), + Cvt1 = vtupdate(vtunsafe({'else',ElseAnno}, Cvt0, Vt), Vt), + Evt2 = vtmerge(Evt0, Evt1), + Cvt2 = vtmerge(Cvt0, Cvt1), + {vtmerge(Evt2, Cvt2),St2}; %% No comparison or boolean operators yet. expr({op,_Anno,_Op,A}, Vt, St) -> expr(A, Vt, St); @@ -2575,11 +2579,31 @@ expr({op,Anno,Op,L,R}, Vt, St0) when Op =:= 'orelse'; Op =:= 'andalso' -> {Evt2,St2} = expr(R, Vt1, St1), Evt3 = vtupdate(vtunsafe({Op,Anno}, Evt2, Vt1), Evt2), {vtmerge(Evt1, Evt3),St2}; +expr({op,_Anno,EqOp,L,R}, Vt, St0) when EqOp =:= '=:='; EqOp =:= '=/=' -> + St = expr_check_match_zero(R, expr_check_match_zero(L, St0)), + expr_list([L,R], Vt, St); %They see the same variables expr({op,_Anno,_Op,L,R}, Vt, St) -> expr_list([L,R], Vt, St); %They see the same variables %% The following are not allowed to occur anywhere! expr({remote,_Anno,M,_F}, _Vt, St) -> - {[],add_error(erl_parse:first_anno(M), illegal_expr, St)}. + {[],add_error(erl_parse:first_anno(M), illegal_expr, St)}; +expr({ssa_check_when,_Anno,_WantedResult,_Args,_Tag,_Exprs}, _Vt, St) -> + {[], St}. + +%% Checks whether 0.0 occurs naked in the LHS or RHS of an equality check. Note +%% that we do not warn when it's being used as arguments for expressions in +%% in general: `A =:= abs(0.0)` is fine. +expr_check_match_zero({float,Anno,F}, St) -> + case F == 0 andalso is_warn_enabled(match_float_zero, St) of + true -> add_warning(Anno, match_float_zero, St); + false -> St + end; +expr_check_match_zero({cons,_Anno,H,T}, St) -> + expr_check_match_zero(H, expr_check_match_zero(T, St)); +expr_check_match_zero({tuple,_Anno,Es}, St) -> + foldl(fun expr_check_match_zero/2, St, Es); +expr_check_match_zero(_Expr, St) -> + St. %% expr_list(Expressions, Variables, State) -> %% {UsedVarTable,State} @@ -2673,7 +2697,8 @@ record_def(Anno, Name, Fs0, St0) -> St2 = St1#lint{records=maps:put(Name, {Anno,Fs1}, St1#lint.records)}, Types = [T || {typed_record_field, _, T} <- Fs0], - check_type({type, nowarn(), product, Types}, St2) + St3 = St2#lint{type_id = {record, Name}}, + check_type({type, nowarn(), product, Types}, St3) end. %% def_fields([RecDef], RecordName, State) -> {[DefField],State}. @@ -2892,110 +2917,137 @@ type_def(Attr, Anno, TypeName, ProtoType, Args, St0) -> fun(St) -> NewDefs = maps:put(TypePair, Info, TypeDefs), CheckType = {type, nowarn(), product, [ProtoType|Args]}, - check_type(CheckType, St#lint{types=NewDefs}) + St1 = St#lint{types=NewDefs, type_id={type, TypePair}}, + check_type(CheckType, St1) end, case is_default_type(TypePair) andalso not member(no_auto_import_types, St0#lint.compile) of true -> case is_obsolete_builtin_type(TypePair) of - true -> StoreType(St0); + true -> + StoreType(St0); false -> - case is_newly_introduced_builtin_type(TypePair) of - %% allow some types just for bootstrapping - true -> - Warn = {new_builtin_type, TypePair}, - St1 = add_warning(Anno, Warn, St0), - StoreType(St1); - false -> - add_error(Anno, {builtin_type, TypePair}, St0) - end + %% Starting from OTP 26, redefining built-in types + %% is allowed. + St1 = StoreType(St0), + warn_redefined_builtin_type(Anno, TypePair, St1) end; false -> case is_map_key(TypePair, TypeDefs) of true -> add_error(Anno, {redefine_type, TypePair}, St0); false -> - St1 = case - Attr =:= opaque andalso - is_underspecified(ProtoType, Arity) - of - true -> - Warn = {underspecified_opaque, TypePair}, - add_warning(Anno, Warn, St0); - false -> St0 - end, - StoreType(St1) + StoreType(St0) end end. -is_underspecified({type,_,term,[]}, 0) -> true; -is_underspecified({type,_,any,[]}, 0) -> true; -is_underspecified(_ProtType, _Arity) -> false. +warn_redefined_builtin_type(Anno, TypePair, #lint{compile=Opts}=St) -> + case is_warn_enabled(redefined_builtin_type, St) of + true -> + NoWarn = [Type || + {nowarn_redefined_builtin_type, Type0} <- Opts, + Type <- lists:flatten([Type0])], + case lists:member(TypePair, NoWarn) of + true -> + St; + false -> + Warn = {redefine_builtin_type, TypePair}, + add_warning(Anno, Warn, St) + end; + false -> + St + end. check_type(Types, St) -> - {SeenVars, St1} = check_type(Types, maps:new(), St), + {SeenVars, St1} = check_type_1(Types, maps:new(), St), maps:fold(fun(Var, {seen_once, Anno}, AccSt) -> case atom_to_list(Var) of "_"++_ -> AccSt; _ -> add_error(Anno, {singleton_typevar, Var}, AccSt) end; + (Var, {seen_once_union, Anno}, AccSt) -> + case is_warn_enabled(singleton_typevar, AccSt) of + true -> + case atom_to_list(Var) of + "_"++_ -> AccSt; + _ -> add_warning(Anno, {singleton_typevar, Var}, AccSt) + end; + false -> + AccSt + end; (_Var, seen_multiple, AccSt) -> AccSt end, St1, SeenVars). -check_type({ann_type, _A, [_Var, Type]}, SeenVars, St) -> - check_type(Type, SeenVars, St); -check_type({remote_type, A, [{atom, _, Mod}, {atom, _, Name}, Args]}, +check_type_1({type, Anno, TypeName, Args}=Type, SeenVars, #lint{types=Types}=St) -> + TypePair = {TypeName, + if + is_list(Args) -> length(Args); + true -> 0 + end}, + case is_map_key(TypePair, Types) of + true -> + check_type_2(Type, SeenVars, used_type(TypePair, Anno, St)); + false -> + check_type_2(Type, SeenVars, St) + end; +check_type_1(Types, SeenVars, St) -> + check_type_2(Types, SeenVars, St). + +check_type_2({ann_type, _A, [_Var, Type]}, SeenVars, St) -> + check_type_1(Type, SeenVars, St); +check_type_2({remote_type, A, [{atom, _, Mod}, {atom, _, Name}, Args]}, SeenVars, St00) -> St0 = check_module_name(Mod, A, St00), St = deprecated_type(A, Mod, Name, Args, St0), CurrentMod = St#lint.module, case Mod =:= CurrentMod of - true -> check_type({user_type, A, Name, Args}, SeenVars, St); + true -> check_type_2({user_type, A, Name, Args}, SeenVars, St); false -> lists:foldl(fun(T, {AccSeenVars, AccSt}) -> - check_type(T, AccSeenVars, AccSt) + check_type_1(T, AccSeenVars, AccSt) end, {SeenVars, St}, Args) end; -check_type({integer, _A, _}, SeenVars, St) -> {SeenVars, St}; -check_type({atom, _A, _}, SeenVars, St) -> {SeenVars, St}; -check_type({var, _A, '_'}, SeenVars, St) -> {SeenVars, St}; -check_type({var, A, Name}, SeenVars, St) -> +check_type_2({integer, _A, _}, SeenVars, St) -> {SeenVars, St}; +check_type_2({atom, _A, _}, SeenVars, St) -> {SeenVars, St}; +check_type_2({var, _A, '_'}, SeenVars, St) -> {SeenVars, St}; +check_type_2({var, A, Name}, SeenVars, St) -> NewSeenVars = case maps:find(Name, SeenVars) of {ok, {seen_once, _}} -> maps:put(Name, seen_multiple, SeenVars); + {ok, {seen_once_union, _}} -> maps:put(Name, seen_multiple, SeenVars); {ok, seen_multiple} -> SeenVars; error -> maps:put(Name, {seen_once, A}, SeenVars) end, {NewSeenVars, St}; -check_type({type, A, bool, []}, SeenVars, St) -> +check_type_2({type, A, bool, []}, SeenVars, St) -> {SeenVars, add_warning(A, {renamed_type, bool, boolean}, St)}; -check_type({type, A, 'fun', [Dom, Range]}, SeenVars, St) -> +check_type_2({type, A, 'fun', [Dom, Range]}, SeenVars, St) -> St1 = case Dom of {type, _, product, _} -> St; {type, _, any} -> St; _ -> add_error(A, {type_syntax, 'fun'}, St) end, - check_type({type, nowarn(), product, [Dom, Range]}, SeenVars, St1); -check_type({type, A, range, [From, To]}, SeenVars, St) -> + check_type_2({type, nowarn(), product, [Dom, Range]}, SeenVars, St1); +check_type_2({type, A, range, [From, To]}, SeenVars, St) -> St1 = case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of {{integer, _, X}, {integer, _, Y}} when X < Y -> St; _ -> add_error(A, {type_syntax, range}, St) end, {SeenVars, St1}; -check_type({type, _A, map, any}, SeenVars, St) -> +check_type_2({type, _A, map, any}, SeenVars, St) -> {SeenVars, St}; -check_type({type, _A, map, Pairs}, SeenVars, St) -> +check_type_2({type, _A, map, Pairs}, SeenVars, St) -> lists:foldl(fun(Pair, {AccSeenVars, AccSt}) -> - check_type(Pair, AccSeenVars, AccSt) + check_type_2(Pair, AccSeenVars, AccSt) end, {SeenVars, St}, Pairs); -check_type({type, _A, map_field_assoc, [Dom, Range]}, SeenVars, St) -> - check_type({type, nowarn(), product, [Dom, Range]}, SeenVars, St); -check_type({type, _A, tuple, any}, SeenVars, St) -> {SeenVars, St}; -check_type({type, _A, any}, SeenVars, St) -> {SeenVars, St}; -check_type({type, A, binary, [Base, Unit]}, SeenVars, St) -> +check_type_2({type, _A, map_field_assoc, [Dom, Range]}, SeenVars, St) -> + check_type_2({type, nowarn(), product, [Dom, Range]}, SeenVars, St); +check_type_2({type, _A, tuple, any}, SeenVars, St) -> {SeenVars, St}; +check_type_2({type, _A, any}, SeenVars, St) -> {SeenVars, St}; +check_type_2({type, A, binary, [Base, Unit]}, SeenVars, St) -> St1 = case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of {{integer, _, BaseVal}, @@ -3003,20 +3055,43 @@ check_type({type, A, binary, [Base, Unit]}, SeenVars, St) -> _ -> add_error(A, {type_syntax, binary}, St) end, {SeenVars, St1}; -check_type({type, A, record, [Name|Fields]}, SeenVars, St) -> +check_type_2({type, A, record, [Name|Fields]}, SeenVars, St) -> case Name of {atom, _, Atom} -> St1 = used_record(Atom, St), check_record_types(A, Atom, Fields, SeenVars, St1); _ -> {SeenVars, add_error(A, {type_syntax, record}, St)} end; -check_type({type, _A, Tag, Args}, SeenVars, St) when Tag =:= product; - Tag =:= union; - Tag =:= tuple -> +check_type_2({type, _A, Tag, Args}=_F, SeenVars, St) when Tag =:= product; + Tag =:= tuple -> lists:foldl(fun(T, {AccSeenVars, AccSt}) -> - check_type(T, AccSeenVars, AccSt) - end, {SeenVars, St}, Args); -check_type({type, Anno, TypeName, Args}, SeenVars, St) -> + check_type_1(T, AccSeenVars, AccSt) + end, {SeenVars, St}, Args); +check_type_2({type, _A, union, Args}=_F, SeenVars0, St) -> + lists:foldl(fun(T, {AccSeenVars0, AccSt}) -> + {SeenVars1, St0} = check_type_1(T, SeenVars0, AccSt), + AccSeenVars = maps:merge_with( + fun (K, {seen_once, Anno}, {seen_once, _}) -> + case SeenVars0 of + #{K := _} -> + %% Unused outside of this union. + {seen_once, Anno}; + #{} -> + {seen_once_union, Anno} + end; + (_K, {seen_once, Anno}, {seen_once_union, _}) -> + {seen_once_union, Anno}; + (_K, {seen_once_union, _}=R, {seen_once, _}) -> R; + (_K, {seen_once_union, _}=R, {seen_once_union, _}) -> R; + (_K, {seen_once_union, _}, Else) -> Else; + (_K, {seen_once, _}, Else) -> Else; + (_K, Else, {seen_once_union, _}) -> Else; + (_K, Else, {seen_once, _}) -> Else; + (_K, Else1, _Else2) -> Else1 + end, AccSeenVars0, SeenVars1), + {AccSeenVars, St0} + end, {SeenVars0, St}, Args); +check_type_2({type, Anno, TypeName, Args}, SeenVars, St) -> #lint{module = Module, types=Types} = St, Arity = length(Args), TypePair = {TypeName, Arity}, @@ -3032,20 +3107,26 @@ check_type({type, Anno, TypeName, Args}, SeenVars, St) -> Tag = deprecated_builtin_type, W = {Tag, TypePair, Replacement, Rel}, add_warning(Anno, W, St) - end; - _ -> St - end, - check_type({type, nowarn(), product, Args}, SeenVars, St1); -check_type({user_type, A, TypeName, Args}, SeenVars, St) -> + end; + _ -> + case is_default_type(TypePair) of + true -> + used_type(TypePair, Anno, St); + false -> + St + end + end, + check_type_2({type, nowarn(), product, Args}, SeenVars, St1); +check_type_2({user_type, A, TypeName, Args}, SeenVars, St) -> Arity = length(Args), TypePair = {TypeName, Arity}, St1 = used_type(TypePair, A, St), lists:foldl(fun(T, {AccSeenVars, AccSt}) -> - check_type(T, AccSeenVars, AccSt) + check_type_1(T, AccSeenVars, AccSt) end, {SeenVars, St1}, Args); -check_type([{typed_record_field,Field,_T}|_], SeenVars, St) -> +check_type_2([{typed_record_field,Field,_T}|_], SeenVars, St) -> {SeenVars, add_error(element(2, Field), old_abstract_code, St)}; -check_type(I, SeenVars, St) -> +check_type_2(I, SeenVars, St) -> case erl_eval:partial_eval(I) of {integer,_A,_Integer} -> {SeenVars, St}; _Other -> @@ -3080,25 +3161,22 @@ check_record_types([{type, _, field_type, [{atom, Anno, FName}, Type]}|Left], false -> St1 end, %% Check Type - {NewSeenVars, St3} = check_type(Type, SeenVars, St2), + {NewSeenVars, St3} = check_type_2(Type, SeenVars, St2), NewSeenFields = ordsets:add_element(FName, SeenFields), check_record_types(Left, Name, DefFields, NewSeenVars, St3, NewSeenFields); check_record_types([], _Name, _DefFields, SeenVars, St, _SeenFields) -> {SeenVars, St}. used_type(TypePair, Anno, #lint{usage = Usage, file = File} = St) -> - OldUsed = Usage#usage.used_types, - UsedTypes = maps:put(TypePair, erl_anno:set_file(File, Anno), OldUsed), - St#lint{usage=Usage#usage{used_types=UsedTypes}}. + Used = Usage#usage.used_types, + UsedType = #used_type{anno = erl_anno:set_file(File, Anno), + at = St#lint.type_id}, + NewUsed = maps_prepend(TypePair, UsedType, Used), + St#lint{usage=Usage#usage{used_types=NewUsed}}. is_default_type({Name, NumberOfTypeVariables}) -> erl_internal:is_type(Name, NumberOfTypeVariables). -%% OTP 24.0 -is_newly_introduced_builtin_type({nonempty_binary, 0}) -> true; -is_newly_introduced_builtin_type({nonempty_bitstring, 0}) -> true; -is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false. - is_obsolete_builtin_type(TypePair) -> obsolete_builtin_type(TypePair) =/= no. @@ -3109,22 +3187,29 @@ obsolete_builtin_type({Name, A}) when is_atom(Name), is_integer(A) -> no. %% spec_decl(Anno, Fun, Types, State) -> State. -spec_decl(Anno, MFA0, TypeSpecs, St00 = #lint{specs = Specs, module = Mod}) -> +spec_decl(Anno, MFA0, TypeSpecs, #lint{specs = Specs, module = Mod} = St0) -> MFA = case MFA0 of {F, Arity} -> {Mod, F, Arity}; {_M, _F, Arity} -> MFA0 end, - St0 = check_module_name(element(1, MFA), Anno, St00), St1 = St0#lint{specs = maps:put(MFA, Anno, Specs)}, case is_map_key(MFA, Specs) of true -> add_error(Anno, {redefine_spec, MFA0}, St1); false -> - case MFA of - {Mod, _, _} -> - check_specs(TypeSpecs, spec_wrong_arity, Arity, St1); - _ -> - add_error(Anno, {bad_module, MFA}, St1) - end + St2 = case MFA of + {Mod, _, _} -> + St1; + _ -> + St1int = case MFA0 of + {M, _, _} -> + check_module_name(M, Anno, St1); + _ -> + St1 + end, + add_error(Anno, {bad_module, MFA}, St1int) + end, + St3 = St2#lint{type_id = {spec, MFA}}, + check_specs(TypeSpecs, spec_wrong_arity, Arity, St3) end. %% callback_decl(Anno, Fun, Types, State) -> State. @@ -3140,8 +3225,9 @@ callback_decl(Anno, MFA0, TypeSpecs, St1 = St0#lint{callbacks = maps:put(MFA, Anno, Callbacks)}, case is_map_key(MFA, Callbacks) of true -> add_error(Anno, {redefine_callback, MFA0}, St1); - false -> check_specs(TypeSpecs, callback_wrong_arity, - Arity, St1) + false -> + St2 = St1#lint{type_id = {spec, MFA}}, + check_specs(TypeSpecs, callback_wrong_arity, Arity, St2) end end. @@ -3178,15 +3264,42 @@ is_fa({FuncName, Arity}) when is_atom(FuncName), is_integer(Arity), Arity >= 0 -> true; is_fa(_) -> false. -check_module_name(M, Anno, St) -> - case is_latin1_name(M) of - true -> St; - false -> - add_error(Anno, non_latin1_module_unsupported, St) +check_module_name(M, Anno, St0) -> + AllChars = atom_to_list(M), + VisibleChars = remove_non_visible(AllChars), + case {AllChars, VisibleChars} of + {[], []} -> + add_error(Anno, empty_module_name, St0); + {[_|_], []} -> + add_error(Anno, blank_module_name, St0); + {Cs,[_|_]} -> + St1 = case io_lib:latin1_char_list(Cs) of + true -> + St0; + false -> + add_error(Anno, + non_latin1_module_unsupported, + St0) + end, + case any_control_characters(Cs) of + true -> + add_error(Anno, ctrl_chars_in_module_name, St1); + false -> + St1 + end end. -is_latin1_name(Name) -> - io_lib:latin1_char_list(atom_to_list(Name)). +remove_non_visible(Cs) -> + SP = $\s, %Plain space. + NBSP = 16#A0, %Non-breaking space. + SHY = 16#AD, %Soft hyphen. + [C || C <- Cs, C =/= SP, C =/= NBSP, C =/= SHY]. + +any_control_characters(Cs) -> + any(fun(C) when is_integer(C), 0 =< C, C < 16#20; + is_integer(C), 16#7F =< C, C < 16#A0 -> true; + (_) -> false + end, Cs). check_specs([FunType|Left], ETag, Arity, St0) -> {FunType1, CTypes} = @@ -3262,11 +3375,10 @@ check_unused_types(Forms, St) -> false -> St end. -check_unused_types_1(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) -> +check_unused_types_1(Forms, #lint{types=Ts}=St) -> case [File || {attribute,_A,file,{File,_Anno}} <- Forms] of [FirstFile|_] -> - D = Usage#usage.used_types, - L = gb_sets:to_list(ExpTs) ++ maps:keys(D), + L = reached_types(St), UsedTypes = gb_sets:from_list(L), FoldFun = fun({{record, _}=_Type, 0}, _, AccSt) -> @@ -3290,6 +3402,19 @@ check_unused_types_1(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) -> St end. +reached_types(#lint{usage = Usage}) -> + Es = [{From, {type, To}} || + To := UsedTs <- Usage#usage.used_types, + #used_type{at = From} <- UsedTs], + Initial = initially_reached_types(Es), + G = sofs:family_to_digraph(sofs:rel2fam(sofs:relation(Es))), + R = digraph_utils:reachable(Initial, G), + true = digraph:delete(G), + [T || {type, T} <- R]. + +initially_reached_types(Es) -> + [FromTypeId || {{T, _}=FromTypeId, _} <- Es, T =/= type]. + check_local_opaque_types(St) -> #lint{types=Ts, exp_types=ExpTs} = St, FoldFun = @@ -3353,11 +3478,12 @@ is_function_dialyzer_option(Option) -> is_module_dialyzer_option(Option) -> lists:member(Option, [no_return,no_unused,no_improper_lists,no_fun_app, - no_match,no_opaque,no_fail_call,no_contracts, + no_match,no_opaque,no_fail_call,no_contracts,no_unknown, no_behaviours,no_undefined_callbacks,unmatched_returns, error_handling,race_conditions,no_missing_calls, specdiffs,overspecs,underspecs,unknown, - no_underspecs + no_underspecs,extra_return,no_extra_return, + missing_return,no_missing_return,overlapping_contract ]). %% try_catch_clauses(Scs, Ccs, In, ImportVarTable, State) -> @@ -3484,7 +3610,7 @@ icrt_export([], _, _, _, Acc) -> handle_comprehension(E, Qs, Vt0, St0) -> {Vt1, Uvt, St1} = lc_quals(Qs, Vt0, St0), - {Evt,St2} = expr(E, Vt1, St1), + {Evt,St2} = comprehension_expr(E, Vt1, St1), Vt2 = vtupdate(Evt, Vt1), %% Shadowed global variables. {_,St3} = check_old_unused_vars(Vt2, Uvt, St2), @@ -3501,6 +3627,11 @@ handle_comprehension(E, Qs, Vt0, St0) -> Vt = vt_no_unsafe(vt_no_unused(Vt4)), {Vt, St}. +comprehension_expr({map_field_assoc,_,K,V}, Vt0, St0) -> + expr_list([K,V], Vt0, St0); +comprehension_expr(E, Vt, St) -> + expr(E, Vt, St). + %% lc_quals(Qualifiers, ImportVarTable, State) -> %% {VarTable,ShadowedVarTable,State} %% Test list comprehension qualifiers, return all variables. Allow @@ -3524,6 +3655,9 @@ lc_quals([{b_generate,_Anno,P,E} | Qs], Vt0, Uvt0, St0) -> St1 = handle_bitstring_gen_pat(P,St0), {Vt,Uvt,St} = handle_generator(P,E,Vt0,Uvt0,St1), lc_quals(Qs, Vt, Uvt, St); +lc_quals([{m_generate,_Anno,P,E} | Qs], Vt0, Uvt0, St0) -> + {Vt,Uvt,St} = handle_generator(P,E,Vt0,Uvt0,St0), + lc_quals(Qs, Vt, Uvt, St); lc_quals([F|Qs], Vt, Uvt, St0) -> Info = is_guard_test2_info(St0), {Fvt,St1} = case is_guard_test2(F, Info) of @@ -3545,7 +3679,7 @@ handle_generator(P,E,Vt,Uvt,St0) -> %% Forget variables local to E immediately. Vt1 = vtupdate(vtold(Evt, Vt), Vt), {_, St2} = check_unused_vars(Evt, Vt, St1), - {Pvt,Pnew,St3} = pattern(P, Vt1, [], St2), + {Pvt,Pnew,St3} = comprehension_pattern(P, Vt1, St2), %% Have to keep fresh variables separated from used variables somehow %% in order to handle for example X = foo(), [X || <> <- bar()]. %% 1 2 2 1 @@ -3557,6 +3691,11 @@ handle_generator(P,E,Vt,Uvt,St0) -> Vt3 = vtupdate(vtsubtract(Vt2, Pnew), Pnew), {Vt3,NUvt,St5}. +comprehension_pattern({map_field_exact,_,K,V}, Vt, St) -> + pattern_list([K,V], Vt, [], St); +comprehension_pattern(P, Vt, St) -> + pattern(P, Vt, [], St). + handle_bitstring_gen_pat({bin,_,Segments=[_|_]},St) -> case lists:last(Segments) of {bin_element,Anno,_,default,Flags} when is_list(Flags) -> @@ -3581,7 +3720,20 @@ handle_bitstring_gen_pat(_,St) -> %% unless it was introduced in a fun or an lc. Only if pat_var finds %% such variables can the correct line number be given. +%% If fun_used_vars is set, we want to compute the tree of used +%% vars across functions. This is by erl_eval to compute used vars +%% without having to traverse the tree multiple times. + +fun_clauses(Cs, Vt, #lint{fun_used_vars=(#{}=FUV)} = St) -> + {Uvt, St0} = fun_clauses1(Cs, Vt, St#lint{fun_used_vars=maps:new()}), + #lint{fun_used_vars=InnerFUV} = St0, + UsedVars = [V || {V, {_, used, _}} <- Uvt], + OuterFUV = maps:put(Cs, {UsedVars, InnerFUV}, FUV), + {Uvt, St0#lint{fun_used_vars=OuterFUV}}; fun_clauses(Cs, Vt, St) -> + fun_clauses1(Cs, Vt, St). + +fun_clauses1(Cs, Vt, St) -> OldRecDef = St#lint.recdef_top, {Bvt,St2} = foldl(fun (C, {Bvt0, St0}) -> {Cvt,St1} = fun_clause(C, Vt, St0), @@ -3816,14 +3968,6 @@ warn_unused_vars(U, Vt, St0) -> UVt = map(fun ({V,{State,_,As}}) -> {V,{State,used,As}} end, U), {vtmerge(Vt, UVt), St1}. - -is_var_bound(V, Vt) -> - case orddict:find(V, Vt) of - {ok,{bound,_Usage,_}} -> true; - _ -> false - end. - - %% vtupdate(UpdVarTable, VarTable) -> VarTable. %% Add the variables in the updated vartable to VarTable. The variables %% will be updated with their property in UpdVarTable. The state of @@ -3956,7 +4100,8 @@ check_remote_function(Anno, M, F, As, St0) -> %% check_load_nif(Anno, ModName, FuncName, [Arg], State) -> State %% Add warning if erlang:load_nif/2 is called when any kind of inlining has %% been enabled. -check_load_nif(Anno, erlang, load_nif, [_, _], St) -> +check_load_nif(Anno, erlang, load_nif, [_, _], St0) -> + St = St0#lint{load_nif = true}, case is_warn_enabled(nif_inline, St) of true -> check_nif_inline(Anno, St); false -> St @@ -4075,28 +4220,53 @@ test_overriden_by_local(Anno, OldTest, Arity, St) -> St end. +feature_keywords() -> + Features = erl_features:configurable(), + G = fun(Ftr, Map) -> + Keywords = erl_features:keywords(Ftr), + Add = fun(Keyword, M) -> maps:put(Keyword, Ftr, M) end, + lists:foldl(Add, Map, Keywords) + end, + lists:foldl(G, #{}, Features). + %% keyword_warning(Anno, Atom, State) -> State. %% Add warning for atoms that will be reserved keywords in the future. %% (Currently, no such keywords to warn for.) -keyword_warning(_Anno, _A, St) -> St. +keyword_warning(Anno, Atom, St) -> + case is_warn_enabled(keyword_warning, St) of + true -> + case erl_anno:text(Anno) of + [$'| _] -> + %% Don't warn for quoted atoms + St; + _ -> + Keywords = St#lint.feature_keywords, + case maps:find(Atom, Keywords) of + error -> St; + {ok, Ftr} -> + add_warning(Anno, {future_feature, Ftr, Atom}, St) + end + end; + false -> + St + end. %% format_function(Anno, ModName, FuncName, [Arg], State) -> State. %% Add warning for bad calls to io:fwrite/format functions. format_function(DefAnno, M, F, As, St) -> - case is_format_function(M, F) of - true -> - case St#lint.warn_format of - Lev when Lev > 0 -> - case check_format_1(As) of - {warn,Level,Fmt,Fas} when Level =< Lev -> - add_warning(DefAnno, {format_error,{Fmt,Fas}}, St); - {warn,Level,Anno,Fmt,Fas} when Level =< Lev -> - add_warning(Anno, {format_error,{Fmt,Fas}}, St); - _ -> St - end; - _Lev -> St - end; + maybe + true ?= is_format_function(M, F), + Lev = St#lint.warn_format, + true ?= Lev > 0, + case check_format_1(As) of + {warn,Level,Fmt,Fas} when Level =< Lev -> + add_warning(DefAnno, {format_error,{Fmt,Fas}}, St); + {warn,Level,Anno,Fmt,Fas} when Level =< Lev -> + add_warning(Anno, {format_error,{Fmt,Fas}}, St); + _ -> St + end + else false -> St end. @@ -4142,7 +4312,7 @@ check_format_2a(Fmt, FmtAnno, As) -> false -> Anno = element(2, As), {warn,1,Anno,"format arguments not a list",[]}; - maybe -> + 'maybe' -> Anno = erl_parse:first_anno(As), {warn,2,Anno,"format arguments perhaps not a list",[]} end. @@ -4188,12 +4358,12 @@ arguments(N) -> args_list({cons,_A,_H,T}) -> args_list(T); %% Strange case: user has written something like [a | "bcd"]; pretend %% we don't know: -args_list({string,_A,_Cs}) -> maybe; +args_list({string,_A,_Cs}) -> 'maybe'; args_list({nil,_A}) -> true; args_list({atom,_,_}) -> false; args_list({integer,_,_}) -> false; args_list({float,_,_}) -> false; -args_list(_Other) -> maybe. +args_list(_Other) -> 'maybe'. args_length({cons,_A,_H,T}) -> 1 + args_length(T); args_length({nil,_A}) -> 0. @@ -4215,9 +4385,11 @@ extract_sequences(Fmt, Need0) -> end end. -extract_sequence(1, [$-,C|Fmt], Need) when C >= $0, C =< $9 -> +extract_sequence(1, [$-,C|Fmt], Need) + when is_integer(C), C >= $0, C =< $9 -> extract_sequence_digits(1, Fmt, Need); -extract_sequence(1, [C|Fmt], Need) when C >= $0, C =< $9 -> +extract_sequence(1, [C|Fmt], Need) + when is_integer(C), C >= $0, C =< $9 -> extract_sequence_digits(1, Fmt, Need); extract_sequence(1, [$-,$*|Fmt], Need) -> extract_sequence(2, Fmt, [int|Need]); @@ -4226,7 +4398,8 @@ extract_sequence(1, [$*|Fmt], Need) -> extract_sequence(1, Fmt, Need) -> extract_sequence(2, Fmt, Need); -extract_sequence(2, [$.,C|Fmt], Need) when C >= $0, C =< $9 -> +extract_sequence(2, [$.,C|Fmt], Need) + when is_integer(C), C >= $0, C =< $9 -> extract_sequence_digits(2, Fmt, Need); extract_sequence(2, [$.,$*|Fmt], Need) -> extract_sequence(3, Fmt, [int|Need]); @@ -4242,36 +4415,23 @@ extract_sequence(3, [$.,_|Fmt], Need) -> extract_sequence(3, Fmt, Need) -> extract_sequence(4, Fmt, Need); -extract_sequence(4, [$t, $l | Fmt], Need) -> - extract_sequence(4, [$l, $t | Fmt], Need); -extract_sequence(4, [$t, $c | Fmt], Need) -> - extract_sequence(5, [$c|Fmt], Need); -extract_sequence(4, [$t, $s | Fmt], Need) -> - extract_sequence(5, [$s|Fmt], Need); -extract_sequence(4, [$t, $p | Fmt], Need) -> - extract_sequence(5, [$p|Fmt], Need); -extract_sequence(4, [$t, $P | Fmt], Need) -> - extract_sequence(5, [$P|Fmt], Need); -extract_sequence(4, [$t, $w | Fmt], Need) -> - extract_sequence(5, [$w|Fmt], Need); -extract_sequence(4, [$t, $W | Fmt], Need) -> - extract_sequence(5, [$W|Fmt], Need); -extract_sequence(4, [$t, C | _Fmt], _Need) -> - {error,"invalid control ~t" ++ [C]}; -extract_sequence(4, [$l, $p | Fmt], Need) -> - extract_sequence(5, [$p|Fmt], Need); -extract_sequence(4, [$l, $t, $p | Fmt], Need) -> - extract_sequence(5, [$p|Fmt], Need); -extract_sequence(4, [$l, $P | Fmt], Need) -> - extract_sequence(5, [$P|Fmt], Need); -extract_sequence(4, [$l, $t, $P | Fmt], Need) -> - extract_sequence(5, [$P|Fmt], Need); -extract_sequence(4, [$l, $t, C | _Fmt], _Need) -> - {error,"invalid control ~lt" ++ [C]}; -extract_sequence(4, [$l, C | _Fmt], _Need) -> - {error,"invalid control ~l" ++ [C]}; -extract_sequence(4, Fmt, Need) -> - extract_sequence(5, Fmt, Need); +extract_sequence(4, Fmt0, Need) -> + case extract_modifiers(Fmt0, []) of + {error, _} = Error -> + Error; + {[C|Fmt], Modifiers} -> + maybe + ok ?= check_modifiers(C, Modifiers), + case ordsets:is_element($K, Modifiers) of + true -> + extract_sequence(5, [C|Fmt], ['fun'|Need]); + false -> + extract_sequence(5, [C|Fmt], Need) + end + end; + {[], _} -> + extract_sequence(5, [], Need) + end; extract_sequence(5, [C|Fmt], Need0) -> case control_type(C, Need0) of @@ -4280,11 +4440,56 @@ extract_sequence(5, [C|Fmt], Need0) -> end; extract_sequence(_, [], _Need) -> {error,"truncated"}. -extract_sequence_digits(Fld, [C|Fmt], Need) when C >= $0, C =< $9 -> +extract_sequence_digits(Fld, [C|Fmt], Need) + when is_integer(C), C >= $0, C =< $9 -> extract_sequence_digits(Fld, Fmt, Need); extract_sequence_digits(Fld, Fmt, Need) -> extract_sequence(Fld+1, Fmt, Need). +extract_modifiers([C|Fmt], Modifiers0) -> + case is_modifier(C) of + true -> + case ordsets:add_element(C, Modifiers0) of + Modifiers0 -> + {error, "repeated modifier " ++ [C]}; + Modifiers -> + extract_modifiers(Fmt, Modifiers) + end; + false -> + {[C|Fmt], Modifiers0} + end; +extract_modifiers([], Modifiers) -> + {[], Modifiers}. + +check_modifiers(C, Modifiers) -> + maybe + ok ?= check_modifiers_1("l", Modifiers, C, "Pp"), + ok ?= check_modifiers_1("lt", Modifiers, C, "cPpsWw"), + ok ?= check_modifiers_1("Kk", Modifiers, C, "PpWw") + end. + +check_modifiers_1(M, Modifiers, C, Cs) -> + case ordsets:intersection(ordsets:from_list(M), Modifiers) of + [_]=Mod -> + case lists:member(C, Cs) of + true -> + ok; + false -> + {error, "invalid modifier/control combination ~" ++ + Mod ++ [C]} + end; + [] -> + ok; + [_,_]=M -> + {error, "conflicting modifiers ~" ++ M ++ [C]} + end. + +is_modifier($k) -> true; +is_modifier($K) -> true; +is_modifier($l) -> true; +is_modifier($t) -> true; +is_modifier(_) -> false. + control_type($~, Need) -> Need; control_type($c, Need) -> [int|Need]; control_type($f, Need) -> [float|Need]; diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 33569d4a8deb..709476005ae5 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -31,6 +31,7 @@ pat_expr pat_expr_max map_pat_expr record_pat_expr pat_argument_list pat_exprs list tail list_comprehension lc_expr lc_exprs +map_comprehension binary_comprehension tuple record_expr record_tuple record_field record_fields @@ -48,13 +49,39 @@ top_type top_types type typed_expr typed_attr_val type_sig type_sigs type_guard type_guards fun_type binary_type type_spec spec_fun typed_exprs typed_record_fields field_types field_type map_pair_types map_pair_type -bin_base_type bin_unit_type. +bin_base_type bin_unit_type +maybe_expr maybe_match_exprs maybe_match +clause_body_exprs +ssa_check_anno +ssa_check_anno_clause +ssa_check_anno_clauses +ssa_check_args +ssa_check_binary_lit +ssa_check_binary_lit_bytes_ls +ssa_check_binary_lit_rest +ssa_check_clause_args +ssa_check_clause_args_ls +ssa_check_expr +ssa_check_exprs +ssa_check_fun_ref +ssa_check_list_lit +ssa_check_list_lit_ls +ssa_check_map_key +ssa_check_map_key_element +ssa_check_map_key_elements +ssa_check_map_key_list +ssa_check_map_key_tuple_elements +ssa_check_pat +ssa_check_pats +ssa_check_when_clause +ssa_check_when_clauses. Terminals -char integer float atom string var +char integer float atom tqstring string var '(' ')' ',' '->' '{' '}' '[' ']' '|' '||' '<-' ';' ':' '#' '.' 'after' 'begin' 'case' 'try' 'catch' 'end' 'fun' 'if' 'of' 'receive' 'when' +'maybe' 'else' 'andalso' 'orelse' 'bnot' 'not' '*' '/' 'div' 'rem' 'band' 'and' @@ -63,8 +90,10 @@ char integer float atom string var '==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' '=>' ':=' '<<' '>>' '!' '=' '::' '..' '...' +'?=' 'spec' 'callback' % helper -dot. +dot +'%ssa%'. Expect 0. @@ -83,6 +112,7 @@ Left 500 mult_op. Unary 600 prefix_op. Nonassoc 700 '#'. Nonassoc 800 ':'. +Nonassoc 900 clause_body_exprs. %% Types @@ -222,8 +252,7 @@ clause_args -> pat_argument_list : element(1, '$1'). clause_guard -> 'when' guard : '$2'. clause_guard -> '$empty' : []. -clause_body -> '->' exprs: '$2'. - +clause_body -> '->' clause_body_exprs: '$2'. expr -> 'catch' expr : {'catch',?anno('$1'),'$2'}. expr -> expr '=' expr : {match,first_anno('$1'),'$1','$3'}. @@ -248,6 +277,7 @@ expr_max -> atomic : '$1'. expr_max -> list : '$1'. expr_max -> binary : '$1'. expr_max -> list_comprehension : '$1'. +expr_max -> map_comprehension : '$1'. expr_max -> binary_comprehension : '$1'. expr_max -> tuple : '$1'. expr_max -> '(' expr ')' : '$2'. @@ -257,6 +287,7 @@ expr_max -> case_expr : '$1'. expr_max -> receive_expr : '$1'. expr_max -> fun_expr : '$1'. expr_max -> try_expr : '$1'. +expr_max -> maybe_expr : '$1'. pat_expr -> pat_expr '=' pat_expr : {match,first_anno('$1'),'$1','$3'}. pat_expr -> pat_expr comp_op pat_expr : ?mkop2('$1', '$2', '$3'). @@ -277,10 +308,6 @@ pat_expr_max -> '(' pat_expr ')' : '$2'. map_pat_expr -> '#' map_tuple : {map, ?anno('$1'),'$2'}. -map_pat_expr -> pat_expr_max '#' map_tuple : - {map, ?anno('$2'),'$1','$3'}. -map_pat_expr -> map_pat_expr '#' map_tuple : - {map, ?anno('$2'),'$1','$3'}. record_pat_expr -> '#' atom '.' atom : {record_index,?anno('$1'),element(3, '$2'),'$4'}. @@ -324,12 +351,15 @@ bit_size_expr -> expr_max : '$1'. list_comprehension -> '[' expr '||' lc_exprs ']' : {lc,?anno('$1'),'$2','$4'}. +map_comprehension -> '#' '{' map_field_assoc '||' lc_exprs '}' : + {mc,?anno('$1'),'$3','$5'}. binary_comprehension -> '<<' expr_max '||' lc_exprs '>>' : {bc,?anno('$1'),'$2','$4'}. lc_exprs -> lc_expr : ['$1']. lc_exprs -> lc_expr ',' lc_exprs : ['$1'|'$3']. lc_expr -> expr : '$1'. +lc_expr -> map_field_exact '<-' expr : {m_generate,?anno('$2'),'$1','$3'}. lc_expr -> expr '<-' expr : {generate,?anno('$2'),'$1','$3'}. lc_expr -> binary '<=' expr : {b_generate,?anno('$2'),'$1','$3'}. @@ -401,7 +431,6 @@ if_clauses -> if_clause ';' if_clauses : ['$1' | '$3']. if_clause -> guard clause_body : {clause,first_anno(hd(hd('$1'))),[],'$1','$2'}. - case_expr -> 'case' expr 'of' cr_clauses 'end' : {'case',?anno('$1'),'$2','$4'}. @@ -477,6 +506,21 @@ try_clause -> var ':' pat_expr try_opt_stacktrace clause_guard clause_body : try_opt_stacktrace -> ':' var : '$2'. try_opt_stacktrace -> '$empty' : '_'. + +maybe_expr -> 'maybe' maybe_match_exprs 'end' : + {'maybe',?anno('$1'),'$2'}. +maybe_expr -> 'maybe' maybe_match_exprs 'else' cr_clauses 'end' : + %% `erl_lint` can produce a better warning when the position + %% of the `else` keyword is known. + {'maybe',?anno('$1'),'$2',{'else',?anno('$3'),'$4'}}. + +maybe_match_exprs -> maybe_match : ['$1']. +maybe_match_exprs -> maybe_match ',' maybe_match_exprs : ['$1' | '$3']. +maybe_match_exprs -> expr : ['$1']. +maybe_match_exprs -> expr ',' maybe_match_exprs : ['$1' | '$3']. + +maybe_match -> expr '?=' expr : {maybe_match,?anno('$2'),'$1','$3'}. + argument_list -> '(' ')' : {[],?anno('$1')}. argument_list -> '(' exprs ')' : {'$2',?anno('$1')}. @@ -486,6 +530,9 @@ pat_argument_list -> '(' pat_exprs ')' : {'$2',?anno('$1')}. exprs -> expr : ['$1']. exprs -> expr ',' exprs : ['$1' | '$3']. +clause_body_exprs -> ssa_check_when_clauses exprs : '$1' ++ '$2'. +clause_body_exprs -> exprs : '$1'. + pat_exprs -> pat_expr : ['$1']. pat_exprs -> pat_expr ',' pat_exprs : ['$1' | '$3']. @@ -499,8 +546,11 @@ atomic -> atom : '$1'. atomic -> strings : '$1'. strings -> string : '$1'. +strings -> tqstring : {string,?anno('$1'),element(3, '$1')}. strings -> string strings : {string,?anno('$1'),element(3, '$1') ++ element(3, '$2')}. +strings -> tqstring strings : + {string,?anno('$1'),element(3, '$1') ++ element(3, '$2')}. prefix_op -> '+' : '$1'. prefix_op -> '-' : '$1'. @@ -535,6 +585,132 @@ comp_op -> '>' : '$1'. comp_op -> '=:=' : '$1'. comp_op -> '=/=' : '$1'. +ssa_check_when_clauses -> ssa_check_when_clause : ['$1']. +ssa_check_when_clauses -> ssa_check_when_clause ssa_check_when_clauses : + ['$1'|'$2']. + +ssa_check_when_clause -> '%ssa%' atom ssa_check_clause_args_ls 'when' atom '->' + ssa_check_exprs '.' : + {ssa_check_when, ?anno('$1'), '$2', '$3', '$5', '$7'}. + +ssa_check_when_clause -> '%ssa%' ssa_check_clause_args_ls 'when' atom '->' + ssa_check_exprs '.' : + {ssa_check_when, ?anno('$1'), {atom,?anno('$1'),pass}, '$2', '$4', '$6'}. + +ssa_check_exprs -> ssa_check_expr : [add_anno_check('$1', [])]. +ssa_check_exprs -> ssa_check_expr ssa_check_anno : [add_anno_check('$1', '$2')]. +ssa_check_exprs -> ssa_check_expr ',' ssa_check_exprs : + [add_anno_check('$1', [])|'$3']. +ssa_check_exprs -> ssa_check_expr ssa_check_anno ',' ssa_check_exprs : + [add_anno_check('$1', '$2')|'$4']. + +ssa_check_anno -> '{' ssa_check_anno_clauses '}' : '$2'. + +ssa_check_anno_clauses -> ssa_check_anno_clause : ['$1']. +ssa_check_anno_clauses -> ssa_check_anno_clause ',' ssa_check_anno_clauses : + ['$1'|'$3']. + +ssa_check_anno_clause -> atom '=>' ssa_check_pat : {term, '$1', '$3'}. + +ssa_check_expr -> var '=' atom ssa_check_args : + {check_expr, ?anno('$1'), [set, '$1', '$3'|'$4']}. +ssa_check_expr -> atom ssa_check_args : + {check_expr, ?anno('$1'), [none, '$1'|'$2']}. +ssa_check_expr -> var '=' atom ':' atom ssa_check_args : + {check_expr, ?anno('$1'), [set, '$1', {'$3', '$5'}|'$6']}. +ssa_check_expr -> atom integer : + {check_expr, ?anno('$1'), build_ssa_check_label('$1', '$2')}. +ssa_check_expr -> atom var : + {check_expr, ?anno('$1'), build_ssa_check_label('$1', '$2')}. + +ssa_check_clause_args_ls -> '(' ')' : []. +ssa_check_clause_args_ls -> '(' ssa_check_clause_args ')' : '$2'. +ssa_check_clause_args_ls -> '(' '...' ')' : ['$2']. + +ssa_check_clause_args -> var : ['$1']. +ssa_check_clause_args -> var ',' ssa_check_clause_args : ['$1'|'$3']. +ssa_check_clause_args -> var ',' '...' : ['$1', '$3']. + +ssa_check_args -> '(' ')' : {[], ?anno('$1')}. +ssa_check_args -> '(' ssa_check_pats ')' : '$2'. +ssa_check_args -> '(' '...' ')' : ['$2']. + +ssa_check_pats -> ssa_check_pat : ['$1']. +ssa_check_pats -> ssa_check_pat ',' ssa_check_pats : ['$1'|'$3']. +ssa_check_pats -> ssa_check_pat ',' '...' : ['$1', '$3']. + +ssa_check_pat -> var : '$1'. +ssa_check_pat -> atom : '$1'. +ssa_check_pat -> integer : '$1'. +ssa_check_pat -> float : '$1'. +ssa_check_pat -> float '(' float ')': {float_epsilon, '$1', '$3'}. +ssa_check_pat -> ssa_check_fun_ref : '$1'. +ssa_check_pat -> '{' '}' : {tuple, ?anno('$1'), []}. +ssa_check_pat -> '{' ssa_check_pats '}' : {tuple, ?anno('$1'), '$2'}. +ssa_check_pat -> '{' '...' '}' : {tuple, ?anno('$1'), ['$2']}. +ssa_check_pat -> ssa_check_binary_lit : '$1'. +ssa_check_pat -> ssa_check_list_lit : '$1'. +ssa_check_pat -> '#' '{' '}' : {map, ?anno('$1'), []}. +ssa_check_pat -> '#' '{' ssa_check_map_key_elements '}' : {map, ?anno('$1'), '$3'}. + +ssa_check_fun_ref -> 'fun' atom '/' integer : {local_fun, '$2', '$4'}. +ssa_check_fun_ref -> 'fun' atom ':' atom '/' integer : {external_fun, '$2', '$4', '$6'}. + +ssa_check_binary_lit -> '<<' '>>' : {binary, ?anno('$1'), []}. +ssa_check_binary_lit -> '<<' ssa_check_binary_lit_bytes_ls '>>' : + {binary, ?anno('$1'), '$2'}. +ssa_check_binary_lit -> '<<' ssa_check_binary_lit_rest '>>' : + {binary, ?anno('$1'), ['$2']}. + +ssa_check_binary_lit_bytes_ls -> integer : ['$1']. +ssa_check_binary_lit_bytes_ls -> integer ',' ssa_check_binary_lit_bytes_ls : + ['$1'|'$3']. +ssa_check_binary_lit_bytes_ls -> integer ',' ssa_check_binary_lit_rest : + ['$1', '$3']. + +ssa_check_binary_lit_rest -> integer ':' integer : {'$1', '$3'}. + +ssa_check_list_lit -> '[' ']' : {list, ?anno('$1'), []}. +ssa_check_list_lit -> '[' ssa_check_list_lit_ls ']' : + {list, ?anno('$1'), '$2'}. + +ssa_check_list_lit_ls -> ssa_check_pat : ['$1']. +ssa_check_list_lit_ls -> ssa_check_pat ',' ssa_check_list_lit_ls : ['$1'|'$3']. +ssa_check_list_lit_ls -> ssa_check_pat ',' '...' : ['$1', '$3']. +ssa_check_list_lit_ls -> ssa_check_pat '|' ssa_check_pat : ['$1'|'$3']. + +ssa_check_map_key -> atom : '$1'. +ssa_check_map_key -> integer : '$1'. +ssa_check_map_key -> float : '$1'. +ssa_check_map_key -> '{' ssa_check_map_key_tuple_elements '}' : + {tuple, ?anno('$1'), '$2'}. +ssa_check_map_key -> '{' '}' : {tuple, ?anno('$1'), []}. +ssa_check_map_key -> ssa_check_binary_lit : '$1'. +ssa_check_map_key -> '[' ssa_check_map_key_list ']' : + {list, ?anno('$1'), '$2'}. +ssa_check_map_key -> '[' ']' : {list, ?anno('$1'), []}. +ssa_check_map_key -> '#' '{' '}' : {map, ?anno('$1'), []}. +ssa_check_map_key -> '#' '{' ssa_check_map_key_elements '}' : '$3'. + +ssa_check_map_key_list -> ssa_check_map_key : ['$1']. +ssa_check_map_key_list -> ssa_check_map_key ',' ssa_check_map_key_list : + ['$1'|'$3']. +ssa_check_map_key_list -> ssa_check_map_key '|' ssa_check_map_key : + ['$1'|'$3']. + +ssa_check_map_key_elements -> ssa_check_map_key_element : ['$1']. +ssa_check_map_key_elements -> ssa_check_map_key_element ',' ssa_check_map_key_elements : + ['$1'|'$3']. + +ssa_check_map_key_element -> ssa_check_map_key '=>' ssa_check_map_key: + {'$1', '$3'}. +%% ssa_check_map_key_element -> ssa_check_map_key '::' top_type: +%% {type, '$1', '$3'}. + +ssa_check_map_key_tuple_elements -> ssa_check_map_key : ['$1']. +ssa_check_map_key_tuple_elements -> ssa_check_map_key ',' ssa_check_map_key_tuple_elements: + ['$1'|'$3']. + Header "%% This file was automatically generated from the file \"erl_parse.yrl\"." "%%" @@ -647,6 +823,7 @@ Erlang code. -type abstract_expr() :: af_literal() | af_match(abstract_expr()) + | af_maybe_match() | af_variable() | af_tuple(abstract_expr()) | af_nil() @@ -664,6 +841,7 @@ Erlang code. | af_local_call() | af_remote_call() | af_list_comprehension() + | af_map_comprehension() | af_binary_comprehension() | af_block() | af_if() @@ -673,7 +851,9 @@ Erlang code. | af_local_fun() | af_remote_fun() | af_fun() - | af_named_fun(). + | af_named_fun() + | af_maybe() + | af_maybe_else(). -type af_record_update(T) :: {'record', anno(), @@ -697,6 +877,9 @@ Erlang code. -type af_list_comprehension() :: {'lc', anno(), af_template(), af_qualifier_seq()}. +-type af_map_comprehension() :: + {'mc', anno(), af_assoc(abstract_expr()), af_qualifier_seq()}. + -type af_binary_comprehension() :: {'bc', anno(), af_template(), af_qualifier_seq()}. @@ -707,6 +890,7 @@ Erlang code. -type af_qualifier() :: af_generator() | af_filter(). -type af_generator() :: {'generate', anno(), af_pattern(), abstract_expr()} + | {'m_generate', anno(), af_assoc_exact(af_pattern()), abstract_expr()} | {'b_generate', anno(), af_pattern(), abstract_expr()}. -type af_filter() :: abstract_expr(). @@ -816,6 +1000,9 @@ Erlang code. -type af_map_pattern() :: {'map', anno(), [af_assoc_exact(af_pattern())]}. +-type af_maybe() :: {'maybe', anno(), af_body()}. +-type af_maybe_else() :: {'maybe', anno(), af_body(), {'else', anno(), af_clause_seq()}}. + -type abstract_type() :: af_annotated_type() | af_atom() | af_bitstring_type() @@ -926,6 +1113,8 @@ Erlang code. -type af_match(T) :: {'match', anno(), af_pattern(), T}. +-type af_maybe_match() :: {'maybe_match', anno(), af_pattern(), abstract_expr()}. + -type af_variable() :: {'var', anno(), atom()}. % | af_anon_variable() %-type af_anon_variable() :: {'var', anno(), '_'}. @@ -951,7 +1140,7 @@ Erlang code. -type binary_op() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-' | 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++' | '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:=' - | '=/='. + | '=/=' | '!'. -type af_unary_op(T) :: {'op', anno(), unary_op(), T}. @@ -1397,7 +1586,7 @@ normalise({bin,_,Fs}) -> eval_bits:expr_grp(Fs, [], fun(E, _) -> {value, normalise(E), []} - end, [], true), + end), B; normalise({cons,_,Head,Tail}) -> [normalise(Head)|normalise(Tail)]; @@ -1507,16 +1696,16 @@ abstract_list([H|T], String, A, E) -> abstract_list(T, [H|String], A, E); false -> AbstrList = {cons,A,abstract(H, A, E),abstract(T, A, E)}, - not_string(String, AbstrList, A, E) + not_string(String, AbstrList, A) end; abstract_list([], String, A, _E) -> {string, A, lists:reverse(String)}; abstract_list(T, String, A, E) -> - not_string(String, abstract(T, A, E), A, E). + not_string(String, abstract(T, A, E), A). -not_string([C|T], Result, A, E) -> - not_string(T, {cons, A, {integer, A, C}, Result}, A, E); -not_string([], Result, _A, _E) -> +not_string([C|T], Result, A) -> + not_string(T, {cons, A, {integer, A, C}, Result}, A); +not_string([], Result, _A) -> Result. abstract_tuple_list([H|T], A, E) -> @@ -1819,4 +2008,12 @@ modify_anno1([H|T], Ac, Mf) -> modify_anno1([], Ac, _Mf) -> {[],Ac}; modify_anno1(E, Ac, _Mf) when not is_tuple(E), not is_list(E) -> {E,Ac}. +build_ssa_check_label({atom,_,label}, Lbl) -> + [label, Lbl]; +build_ssa_check_label({atom,L,_}, _) -> + return_error(L, "expected 'label'"). + +add_anno_check({check_expr,Loc,Args}, AnnoCheck) -> + {check_expr,Loc,Args,AnnoCheck}. + %% vim: ft=erlang diff --git a/lib/stdlib/src/erl_posix_msg.erl b/lib/stdlib/src/erl_posix_msg.erl index b9ed4a3a9d21..4161cf6644a4 100644 --- a/lib/stdlib/src/erl_posix_msg.erl +++ b/lib/stdlib/src/erl_posix_msg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2018. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -139,7 +139,7 @@ message_1(eprocunavail) -> <<"bad procedure for program">>; message_1(eprogmismatch) -> <<"program version wrong">>; message_1(eprogunavail) -> <<"RPC program not available">>; message_1(eproto) -> <<"protocol error">>; -message_1(eprotonosupport) -> <<"protocol not suppored">>; +message_1(eprotonosupport) -> <<"protocol not supported">>; message_1(eprototype) -> <<"protocol wrong type for socket">>; message_1(erange) -> <<"math result unrepresentable">>; message_1(erefused) -> <<"EREFUSED">>; @@ -167,9 +167,9 @@ message_1(eunatch) -> <<"protocol driver not attached">>; message_1(eusers) -> <<"too many users">>; message_1(eversion) -> <<"version mismatch">>; message_1(ewouldblock) -> <<"operation would block">>; -message_1(exdev) -> <<"cross-domain link">>; +message_1(exdev) -> <<"cross-device link">>; message_1(exfull) -> <<"message tables full">>; message_1(nxdomain) -> <<"non-existing domain">>; message_1(exbadport) -> <<"inet_drv bad port state">>; message_1(exbadseq) -> <<"inet_drv bad request sequence">>; -message_1(_) -> <<"unknown POSIX error">>. +message_1(Other) -> <<"unknown POSIX error: ", (atom_to_binary(Other))/binary>>. diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index 74b42a3b4037..50ff87643cd7 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -24,7 +24,8 @@ -export([form/1,form/2, attribute/1,attribute/2,function/1,function/2, - guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4]). + guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4, + legalize_vars/1]). -import(lists, [append/1,foldr/3,map/2,mapfoldl/3,reverse/1,reverse/2]). -import(io_lib, [write/1,format/2]). @@ -199,6 +200,34 @@ expr(E, I, P, Options) -> ?TEST(E), frmt(lexpr(E, P, options(Options)), I, state(Options)). +-spec(legalize_vars(Function) -> erl_parse:abstract_form() when + Function :: erl_parse:abstract_form()). + +legalize_vars({function,ANNO,Name0,Arity,Clauses0}) -> + ?TEST(F), + %% Collect all used variables in this function and classify them + %% as either syntactically valid or not. + F = fun({var,_Anno,Name}, {Valid, Invalid}) -> + Str = [First|_] = atom_to_list(Name), + case First of + X when X >= $a, X =< $z -> + {Valid,Invalid#{Name => Str}}; + _ -> + {Valid#{Name => Name},Invalid} + end + end, + {Valid, Invalid} = fold_vars(F, {#{}, #{}}, Clauses0), + %% Make up an unique variable name for each key in Invalid, then + %% replace all invalid names. + Mapping = maps:fold(fun legalize_name/3, Valid, Invalid), + Subs = fun({var,Anno,Name}) -> + {var,Anno,map_get(Name, Mapping)} + end, + Clauses = map_vars(Subs, Clauses0), + {function,ANNO,Name0,Arity,Clauses}; +legalize_vars(Form) -> + erlang:error(badarg, [Form]). + %%% %%% Local functions %%% @@ -551,12 +580,13 @@ lexpr({cons,_,H,T}, _, Opts) -> lexpr({lc,_,E,Qs}, _Prec, Opts) -> Lcl = {list,[{step,[lexpr(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]}, {list,[{seq,$[,[],[[]],[{force_nl,leaf(" "),[Lcl]}]},$]]}; - %% {list,[{step,$[,Lcl},$]]}; lexpr({bc,_,E,Qs}, _Prec, Opts) -> P = max_prec(), Lcl = {list,[{step,[lexpr(E, P, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]}, {list,[{seq,'<<',[],[[]],[{force_nl,leaf(" "),[Lcl]}]},'>>']}; - %% {list,[{step,'<<',Lcl},'>>']}; +lexpr({mc,_,E,Qs}, _Prec, Opts) -> + Lcl = {list,[{step,[map_field(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]}, + {list,[{seq,'#{',[],[[]],[{force_nl,leaf(" "),[Lcl]}]},$}]}; lexpr({tuple,_,Elts}, _, Opts) -> tuple(Elts, Opts); lexpr({record_index, _, Name, F}, Prec, Opts) -> @@ -675,12 +705,26 @@ lexpr({'catch',_,Expr}, Prec, Opts) -> {P,R} = preop_prec('catch'), El = {list,[{step,'catch',lexpr(Expr, R, Opts)}]}, maybe_paren(P, Prec, El); +lexpr({'maybe',_,Es}, _, Opts) -> + {list,[{step,'maybe',body(Es, Opts)},{reserved,'end'}]}; +lexpr({'maybe',_,Es,{'else',_,Cs}}, _, Opts) -> + {list,[{step,'maybe',body(Es, Opts)},{step,'else',cr_clauses(Cs, Opts)},{reserved,'end'}]}; +lexpr({maybe_match,_,Lhs,Rhs}, _, Opts) -> + Pl = lexpr(Lhs, 0, Opts), + Rl = lexpr(Rhs, 0, Opts), + {list,[{cstep,[Pl,leaf(" ?=")],Rl}]}; lexpr({match,_,Lhs,Rhs}, Prec, Opts) -> {L,P,R} = inop_prec('='), Pl = lexpr(Lhs, L, Opts), Rl = lexpr(Rhs, R, Opts), El = {list,[{cstep,[Pl,' ='],Rl}]}, maybe_paren(P, Prec, El); +lexpr({op,_,Op,Arg}, Prec, Opts) when Op =:= '+'; + Op =:= '-' -> + {P,R} = preop_prec(Op), + Ol = {reserved, leaf(atom_to_list(Op))}, + El = [Ol,lexpr(Arg, R, Opts)], + maybe_paren(P, Prec, El); lexpr({op,_,Op,Arg}, Prec, Opts) -> {P,R} = preop_prec(Op), Ol = {reserved, leaf(format("~s ", [Op]))}, @@ -913,6 +957,9 @@ clauses(Type, Opts, Cs) -> lc_quals(Qs, Opts) -> {prefer_nl,[$,],lexprs(Qs, fun lc_qual/2, Opts)}. +lc_qual({m_generate,_,Pat,E}, Opts) -> + Pl = map_field(Pat, Opts), + {list,[{step,[Pl,leaf(" <-")],lexpr(E, 0, Opts)}]}; lc_qual({b_generate,_,Pat,E}, Opts) -> Pl = lexpr(Pat, 0, Opts), {list,[{step,[Pl,leaf(" <=")],lexpr(E, 0, Opts)}]}; @@ -1324,7 +1371,7 @@ wordtable() -> L = [begin {leaf,Sz,S} = leaf(W), {S,Sz} end || W <- [" ->"," =","<<",">>","[]","after","begin","case","catch", "end","fun","if","of","receive","try","when"," ::","..", - " |"]], + " |","maybe","else","#{"]], list_to_tuple(L). word(' ->', WT) -> element(1, WT); @@ -1345,4 +1392,40 @@ word('try', WT) -> element(15, WT); word('when', WT) -> element(16, WT); word(' ::', WT) -> element(17, WT); word('..', WT) -> element(18, WT); -word(' |', WT) -> element(19, WT). +word(' |', WT) -> element(19, WT); +word('maybe', WT) -> element(20, WT); +word('else', WT) -> element(21, WT); +word('#{', WT) -> element(22, WT). + +%% Make up an unique variable name for Name that won't clash with any +%% name in Used. We first try by converting the name to uppercase and +%% if that fails we start prepending 'X'es until we find an unused +%% name. +legalize_name(InvalidName, StringName, Used) -> + Upper = string:to_upper(StringName), + NewName = list_to_atom(Upper), + case Used of + #{ NewName := _ } -> + legalize_name(InvalidName, [$X|StringName], Used); + #{} -> + Used#{ InvalidName => NewName } + end. + +fold_vars(F, Acc0, Forms) when is_list(Forms) -> + lists:foldl(fun(Elem, Acc) -> fold_vars(F, Acc, Elem) end, Acc0, Forms); +fold_vars(F, Acc0, V={var,_,_}) -> + F(V, Acc0); +fold_vars(F, Acc0, Form) when is_tuple(Form) -> + lists:foldl(fun(Elem, Acc) -> fold_vars(F, Acc, Elem) end, + Acc0, tuple_to_list(Form)); +fold_vars(_, Acc, _) -> + Acc. + +map_vars(F, Forms) when is_list(Forms) -> + [map_vars(F, Form) || Form <- Forms]; +map_vars(F, V={var,_,_}) -> + F(V); +map_vars(F, Form) when is_tuple(Form) -> + list_to_tuple([map_vars(F, Elem) || Elem <- tuple_to_list(Form)]); +map_vars(_, Form) -> + Form. diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index 5d988e743866..24c1660da1c3 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -52,7 +52,8 @@ %%% External exports -export([string/1,string/2,string/3,tokens/3,tokens/4, - format_error/1,reserved_word/1]). + format_error/1,reserved_word/1, + f_reserved_word/1]). -export([column/1,end_location/1,line/1,location/1,text/1, category/1,symbol/1]). @@ -89,8 +90,10 @@ -type category() :: atom(). -type resword_fun() :: fun((atom()) -> boolean()). +-type text_fun() :: fun((atom(), string()) -> boolean()). -type option() :: 'return' | 'return_white_spaces' | 'return_comments' - | 'text' | {'reserved_word_fun', resword_fun()}. + | 'text' | {'reserved_word_fun', resword_fun()} + | {'text_fun', text_fun()} | {'compiler_internal', [term()]}. -type options() :: option() | [option()]. -type symbol() :: atom() | float() | integer() | string(). -type token() :: {category(), Anno :: erl_anno:anno(), symbol()} @@ -101,10 +104,15 @@ %%% Local record. -record(erl_scan, - {resword_fun = fun reserved_word/1 :: resword_fun(), - ws = false :: boolean(), - comment = false :: boolean(), - text = false :: boolean()}). + {resword_fun = fun reserved_word/1 :: resword_fun(), + text_fun = fun(_, _) -> false end :: text_fun(), + ws = false :: boolean(), + comment = false :: boolean(), + has_fun = false :: boolean(), + %% True if requested to parse %ssa%-check comments + checks = false :: boolean(), + %% True if we're scanning inside a %ssa%-check comment + in_check = false :: boolean()}). %%---------------------------------------------------------------------------- @@ -260,15 +268,15 @@ string_thing(_) -> "string". -define(WHITE_SPACE(C), is_integer(C) andalso (C >= $\000 andalso C =< $\s orelse C >= $\200 andalso C =< $\240)). --define(DIGIT(C), C >= $0 andalso C =< $9). --define(CHAR(C), is_integer(C), C >= 0). +-define(DIGIT(C), (is_integer(C) andalso $0 =< C andalso C =< $9)). +-define(CHAR(C), (is_integer(C) andalso 0 =< C andalso C < 16#110000)). -define(UNICODE(C), - is_integer(C) andalso + (is_integer(C) andalso (C >= 0 andalso C < 16#D800 orelse C > 16#DFFF andalso C < 16#FFFE orelse - C > 16#FFFF andalso C =< 16#10FFFF)). + C > 16#FFFF andalso C =< 16#10FFFF))). --define(UNI255(C), C >= 0, C =< 16#ff). +-define(UNI255(C), (is_integer(C) andalso 0 =< C andalso C =< 16#ff)). options(Opts0) when is_list(Opts0) -> Opts = lists:foldr(fun expand_opt/2, [], Opts0), @@ -282,10 +290,22 @@ options(Opts0) when is_list(Opts0) -> Comment = proplists:get_bool(return_comments, Opts), WS = proplists:get_bool(return_white_spaces, Opts), Txt = proplists:get_bool(text, Opts), + TxtFunOpt = proplists:get_value(text_fun, Opts, none), + Internal = proplists:get_value(compiler_internal, Opts, []), + Checks = proplists:get_bool(ssa_checks, Internal), + DefTxtFun = fun(_, _) -> Txt end, + {HasFun, TxtFun} = + if + Txt -> {Txt, DefTxtFun}; + TxtFunOpt == none -> {Txt, DefTxtFun}; + true -> {true, TxtFunOpt} + end, #erl_scan{resword_fun = RW_fun, comment = Comment, ws = WS, - text = Txt}; + text_fun = TxtFun, + has_fun = HasFun, + checks = Checks}; options(Opt) -> options([Opt]). @@ -317,8 +337,8 @@ expand_opt(O, Os) -> tokens1(Cs, St, Line, Col, Toks, Fun, Any) when ?STRING(Cs); Cs =:= eof -> case Fun(Cs, St, Line, Col, Toks, Any) of - {more,{Cs0,Ncol,Ntoks,Nline,Nany,Nfun}} -> - {more,{erl_scan_continuation,Cs0,Ncol,Ntoks,Nline,St,Nany,Nfun}}; + {more,{Cs0,Nst,Ncol,Ntoks,Nline,Nany,Nfun}} -> + {more,{erl_scan_continuation,Cs0,Ncol,Ntoks,Nline,Nst,Nany,Nfun}}; {ok,Toks0,eof,Nline,Ncol} -> Res = case Toks0 of [] -> @@ -335,8 +355,8 @@ tokens1(Cs, St, Line, Col, Toks, Fun, Any) when ?STRING(Cs); Cs =:= eof -> string1(Cs, St, Line, Col, Toks) -> case scan1(Cs, St, Line, Col, Toks) of - {more,{Cs0,Ncol,Ntoks,Nline,Any,Fun}} -> - case Fun(Cs0++eof, St, Nline, Ncol, Ntoks, Any) of + {more,{Cs0,Nst,Ncol,Ntoks,Nline,Any,Fun}} -> + case Fun(Cs0++eof, Nst, Nline, Ncol, Ntoks, Any) of {ok,Toks1,_Rest,Line2,Col2} -> {ok,lists:reverse(Toks1),location(Line2, Col2)}; {{error,_,_}=Error,_Rest} -> @@ -350,7 +370,7 @@ string1(Cs, St, Line, Col, Toks) -> Error end. -scan(Cs, St, Line, Col, Toks, _) -> +scan(Cs, #erl_scan{}=St, Line, Col, Toks, _) -> scan1(Cs, St, Line, Col, Toks). scan1([$\s|Cs], St, Line, Col, Toks) when St#erl_scan.ws -> @@ -361,10 +381,6 @@ scan1([$\n|Cs], St, Line, Col, Toks) when St#erl_scan.ws -> scan_newline(Cs, St, Line, Col, Toks); scan1([$\n|Cs], St, Line, Col, Toks) -> skip_white_space(Cs, St, Line+1, new_column(Col, 1), Toks, 0); -scan1([C|Cs], St, Line, Col, Toks) when C >= $A, C =< $Z -> - scan_variable(Cs, St, Line, Col, Toks, [C]); -scan1([C|Cs], St, Line, Col, Toks) when C >= $a, C =< $z -> - scan_atom(Cs, St, Line, Col, Toks, [C]); %% Optimization: some very common punctuation characters: scan1([$,|Cs], St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ",", ',', 1); @@ -384,23 +400,37 @@ scan1([$;|Cs], St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ";", ';', 1); scan1([$_=C|Cs], St, Line, Col, Toks) -> scan_variable(Cs, St, Line, Col, Toks, [C]); -%% More punctuation characters below. +scan1([$\%=C|Cs], St, Line, Col, Toks) when St#erl_scan.checks -> + scan_check(Cs, St, Line, Col, Toks, [C]); scan1([$\%|Cs], St, Line, Col, Toks) when not St#erl_scan.comment -> skip_comment(Cs, St, Line, Col, Toks, 1); scan1([$\%=C|Cs], St, Line, Col, Toks) -> scan_comment(Cs, St, Line, Col, Toks, [C]); +%% More punctuation characters below. +scan1([C|_], _St, _Line, _Col0, _Toks) when not ?CHAR(C) -> + error({not_character,C}); +scan1([C|Cs], St, Line, Col, Toks) when C >= $A, C =< $Z -> + scan_variable(Cs, St, Line, Col, Toks, [C]); +scan1([C|Cs], St, Line, Col, Toks) when C >= $a, C =< $z -> + scan_atom(Cs, St, Line, Col, Toks, [C]); scan1([C|Cs], St, Line, Col, Toks) when ?DIGIT(C) -> scan_number(Cs, St, Line, Col, Toks, [C], no_underscore); scan1("..."++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "...", '...', 3); -scan1(".."=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1(".."=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1(".."++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "..", '..', 2); -scan1("."=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("."=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1([$.=C|Cs], St, Line, Col, Toks) -> scan_dot(Cs, St, Line, Col, Toks, [C]); +scan1([$",$",$"|Cs], St, Line, Col, Toks) -> %" Emacs + scan_tqstring(Cs, St, Line, Col, Toks, 3); % Number of quote chars +scan1([$",$"]=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; +scan1([$"]=Cs, St, Line, Col, Toks) -> %" Emacs + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1([$"|Cs], St, Line, Col, Toks) -> %" Emacs State0 = {[],[],Line,Col}, scan_string(Cs, St, Line, incr_column(Col, 1), Toks, State0); @@ -427,6 +457,11 @@ scan1([C|Cs], St, Line, Col, Toks) when ?WHITE_SPACE(C) -> skip_white_space(Cs, St, Line, Col, Toks, 1) end; %% Punctuation characters and operators, first recognise multiples. +%% ?= for the maybe ... else ... end construct +scan1("?="++Cs, St, Line, Col, Toks) -> + tok2(Cs, St, Line, Col, Toks, "?=", '?=', 2); +scan1("?"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% << <- <= scan1("<<"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "<<", '<<', 2); @@ -434,62 +469,62 @@ scan1("<-"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "<-", '<-', 2); scan1("<="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "<=", '<=', 2); -scan1("<"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("<"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% >> >= scan1(">>"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ">>", '>>', 2); scan1(">="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ">=", '>=', 2); -scan1(">"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1(">"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% -> -- scan1("->"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "->", '->', 2); scan1("--"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "--", '--', 2); -scan1("-"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("-"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% ++ scan1("++"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "++", '++', 2); -scan1("+"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("+"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% =:= =/= =< == => scan1("=:="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=:=", '=:=', 3); -scan1("=:"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("=:"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1("=/="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=/=", '=/=', 3); -scan1("=/"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("=/"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1("=<"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=<", '=<', 2); scan1("=>"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=>", '=>', 2); scan1("=="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "==", '==', 2); -scan1("="=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("="=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% /= scan1("/="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "/=", '/=', 2); -scan1("/"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("/"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% || scan1("||"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "||", '||', 2); -scan1("|"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1("|"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% := scan1(":="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ":=", ':=', 2); %% :: for typed records scan1("::"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "::", '::', 2); -scan1(":"=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1(":"=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; %% Optimization: punctuation characters less than 127: scan1([$=|Cs], St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=", '=', 1); @@ -534,44 +569,54 @@ scan1([C|Cs], St, Line, Col, Toks) when ?UNI255(C) -> scan1([C|Cs], _St, Line, Col, _Toks) when ?CHAR(C) -> Ncol = incr_column(Col, 1), scan_error({illegal,character}, Line, Col, Line, Ncol, Cs); -scan1([]=Cs, _St, Line, Col, Toks) -> - {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +scan1([]=Cs, St, Line, Col, Toks) -> + {more,{Cs,St,Col,Toks,Line,[],fun scan/6}}; scan1(eof=Cs, _St, Line, Col, Toks) -> {ok,Toks,Cs,Line,Col}. +scan_atom_fun(Cs, #erl_scan{}=St, Line, Col, Toks, Ncs) -> + scan_atom(Cs, St, Line, Col, Toks, Ncs). + scan_atom(Cs0, St, Line, Col, Toks, Ncs0) -> case scan_name(Cs0, Ncs0) of {more,Ncs} -> - {more,{[],Col,Toks,Line,Ncs,fun scan_atom/6}}; + {more,{[],St,Col,Toks,Line,Ncs,fun scan_atom_fun/6}}; {Wcs,Cs} -> - case catch list_to_atom(Wcs) of - Name when is_atom(Name) -> + try list_to_atom(Wcs) of + Name -> case (St#erl_scan.resword_fun)(Name) of true -> tok2(Cs, St, Line, Col, Toks, Wcs, Name); false -> tok3(Cs, St, Line, Col, Toks, atom, Wcs, Name) - end; - _Error -> + end + catch + _:_ -> Ncol = incr_column(Col, length(Wcs)), scan_error({illegal,atom}, Line, Col, Line, Ncol, Cs) end end. +scan_variable_fun(Cs, #erl_scan{}=St, Line, Col, Toks, Ncs) -> + scan_variable(Cs, St, Line, Col, Toks, Ncs). + scan_variable(Cs0, St, Line, Col, Toks, Ncs0) -> case scan_name(Cs0, Ncs0) of {more,Ncs} -> - {more,{[],Col,Toks,Line,Ncs,fun scan_variable/6}}; + {more,{[],St,Col,Toks,Line,Ncs,fun scan_variable_fun/6}}; {Wcs,Cs} -> - case catch list_to_atom(Wcs) of - Name when is_atom(Name) -> - tok3(Cs, St, Line, Col, Toks, var, Wcs, Name); - _Error -> + try list_to_atom(Wcs) of + Name -> + tok3(Cs, St, Line, Col, Toks, var, Wcs, Name) + catch + _:_ -> Ncol = incr_column(Col, length(Wcs)), scan_error({illegal,var}, Line, Col, Line, Ncol, Cs) end end. +scan_name([C|_]=Cs, Ncs) when not ?CHAR(C) -> + {lists:reverse(Ncs),Cs}; scan_name([C|Cs], Ncs) when C >= $a, C =< $z -> scan_name(Cs, [C|Ncs]); scan_name([C|Cs], Ncs) when C >= $A, C =< $Z -> @@ -591,19 +636,27 @@ scan_name([], Ncs) -> scan_name(Cs, Ncs) -> {lists:reverse(Ncs),Cs}. --define(STR(St, S), if St#erl_scan.text -> S; true -> [] end). +-define(STR(Cl, St, S), + case (St#erl_scan.has_fun) + andalso (St#erl_scan.text_fun)(Cl, S) of + true -> S; + false -> [] + end). +scan_dot([C|_]=Cs, St, Line, Col, Toks, Ncs) + when St#erl_scan.in_check, C =/= $. -> + tok2(Cs, St#erl_scan{in_check=false}, Line, Col, Toks, Ncs, '.', 1); scan_dot([$%|_]=Cs, St, Line, Col, Toks, Ncs) -> - Anno = anno(Line, Col, St, Ncs), + Anno = anno(Line, Col, St, ?STR(dot, St, Ncs)), {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 1)}; scan_dot([$\n=C|Cs], St, Line, Col, Toks, Ncs) -> - Anno = anno(Line, Col, St, ?STR(St, Ncs++[C])), + Anno = anno(Line, Col, St, ?STR(dot, St, Ncs++[C])), {ok,[{dot,Anno}|Toks],Cs,Line+1,new_column(Col, 1)}; scan_dot([C|Cs], St, Line, Col, Toks, Ncs) when ?WHITE_SPACE(C) -> - Anno = anno(Line, Col, St, ?STR(St, Ncs++[C])), + Anno = anno(Line, Col, St, ?STR(dot, St, Ncs++[C])), {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 2)}; scan_dot(eof=Cs, St, Line, Col, Toks, Ncs) -> - Anno = anno(Line, Col, St, Ncs), + Anno = anno(Line, Col, St, ?STR(dot, St, Ncs)), {ok,[{dot,Anno}|Toks],Cs,Line,incr_column(Col, 1)}; scan_dot(Cs, St, Line, Col, Toks, Ncs) -> tok2(Cs, St, Line, Col, Toks, Ncs, '.', 1). @@ -635,88 +688,114 @@ scan_newline([$\r|Cs], St, Line, Col, Toks) -> newline_end(Cs, St, Line, Col, Toks, 2, "\n\r"); scan_newline([$\f|Cs], St, Line, Col, Toks) -> newline_end(Cs, St, Line, Col, Toks, 2, "\n\f"); -scan_newline([], _St, Line, Col, Toks) -> - {more,{[$\n],Col,Toks,Line,[],fun scan/6}}; +scan_newline([], St, Line, Col, Toks) -> + {more,{[$\n],St,Col,Toks,Line,[],fun scan/6}}; scan_newline(Cs, St, Line, Col, Toks) -> scan_nl_white_space(Cs, St, Line, Col, Toks, "\n"). +scan_nl_spcs_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) + when is_integer(N) -> + scan_nl_spcs(Cs, St, Line, Col, Toks, N). + scan_nl_spcs([$\s|Cs], St, Line, Col, Toks, N) when N < 17 -> scan_nl_spcs(Cs, St, Line, Col, Toks, N+1); -scan_nl_spcs([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun scan_nl_spcs/6}}; +scan_nl_spcs([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun scan_nl_spcs_fun/6}}; scan_nl_spcs(Cs, St, Line, Col, Toks, N) -> newline_end(Cs, St, Line, Col, Toks, N, nl_spcs(N)). +scan_nl_tabs_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) + when is_integer(N) -> + scan_nl_tabs(Cs, St, Line, Col, Toks, N). + scan_nl_tabs([$\t|Cs], St, Line, Col, Toks, N) when N < 11 -> scan_nl_tabs(Cs, St, Line, Col, Toks, N+1); -scan_nl_tabs([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun scan_nl_tabs/6}}; +scan_nl_tabs([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun scan_nl_tabs_fun/6}}; scan_nl_tabs(Cs, St, Line, Col, Toks, N) -> newline_end(Cs, St, Line, Col, Toks, N, nl_tabs(N)). +scan_nl_white_space_fun(Cs, #erl_scan{}=St, Line, Col, Toks, Ncs) -> + scan_nl_white_space(Cs, St, Line, Col, Toks, Ncs). + %% Note: returning {more,Cont} is meaningless here; one could just as %% well return several tokens. But since tokens() scans up to a full %% stop anyway, nothing is gained by not collecting all white spaces. -scan_nl_white_space([$\n|Cs], #erl_scan{text = false}=St, Line, no_col=Col, +scan_nl_white_space([$\n|Cs], #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks0, Ncs) -> Toks = [{white_space,anno(Line),lists:reverse(Ncs)}|Toks0], scan_newline(Cs, St, Line+1, Col, Toks); scan_nl_white_space([$\n|Cs], St, Line, Col, Toks, Ncs0) -> Ncs = lists:reverse(Ncs0), - Anno = anno(Line, Col, St, Ncs), + Anno = anno(Line, Col, St, ?STR(white_space, St, Ncs)), Token = {white_space,Anno,Ncs}, scan_newline(Cs, St, Line+1, new_column(Col, length(Ncs)), [Token|Toks]); -scan_nl_white_space([C|Cs], St, Line, Col, Toks, Ncs) when ?WHITE_SPACE(C) -> +scan_nl_white_space([C|Cs], St, Line, Col, Toks, Ncs) + when ?WHITE_SPACE(C) -> scan_nl_white_space(Cs, St, Line, Col, Toks, [C|Ncs]); -scan_nl_white_space([]=Cs, _St, Line, Col, Toks, Ncs) -> - {more,{Cs,Col,Toks,Line,Ncs,fun scan_nl_white_space/6}}; -scan_nl_white_space(Cs, #erl_scan{text = false}=St, Line, no_col=Col, +scan_nl_white_space([]=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_nl_white_space_fun/6}}; +scan_nl_white_space(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, Ncs) -> Anno = anno(Line), scan1(Cs, St, Line+1, Col, [{white_space,Anno,lists:reverse(Ncs)}|Toks]); scan_nl_white_space(Cs, St, Line, Col, Toks, Ncs0) -> Ncs = lists:reverse(Ncs0), - Anno = anno(Line, Col, St, Ncs), + Anno = anno(Line, Col, St, ?STR(white_space, St, Ncs)), Token = {white_space,Anno,Ncs}, scan1(Cs, St, Line+1, new_column(Col, length(Ncs)), [Token|Toks]). -newline_end(Cs, #erl_scan{text = false}=St, Line, no_col=Col, +newline_end(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, _N, Ncs) -> scan1(Cs, St, Line+1, Col, [{white_space,anno(Line),Ncs}|Toks]); -newline_end(Cs, St, Line, Col, Toks, N, Ncs) -> - Anno = anno(Line, Col, St, Ncs), +newline_end(Cs, #erl_scan{}=St, Line, Col, Toks, N, Ncs) -> + Anno = anno(Line, Col, St, ?STR(white_space, St, Ncs)), scan1(Cs, St, Line+1, new_column(Col, N), [{white_space,Anno,Ncs}|Toks]). +scan_spcs_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) + when is_integer(N), N >= 1 -> + scan_spcs(Cs, St, Line, Col, Toks, N). + scan_spcs([$\s|Cs], St, Line, Col, Toks, N) when N < 16 -> scan_spcs(Cs, St, Line, Col, Toks, N+1); -scan_spcs([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun scan_spcs/6}}; +scan_spcs([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun scan_spcs_fun/6}}; scan_spcs(Cs, St, Line, Col, Toks, N) -> white_space_end(Cs, St, Line, Col, Toks, N, spcs(N)). +scan_tabs_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) + when is_integer(N), N >= 1 -> + scan_tabs(Cs, St, Line, Col, Toks, N). + scan_tabs([$\t|Cs], St, Line, Col, Toks, N) when N < 10 -> scan_tabs(Cs, St, Line, Col, Toks, N+1); -scan_tabs([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun scan_tabs/6}}; +scan_tabs([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun scan_tabs_fun/6}}; scan_tabs(Cs, St, Line, Col, Toks, N) -> white_space_end(Cs, St, Line, Col, Toks, N, tabs(N)). +skip_white_space_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) -> + skip_white_space(Cs, St, Line, Col, Toks, N). + skip_white_space([$\n|Cs], St, Line, Col, Toks, _N) -> skip_white_space(Cs, St, Line+1, new_column(Col, 1), Toks, 0); skip_white_space([C|Cs], St, Line, Col, Toks, N) when ?WHITE_SPACE(C) -> skip_white_space(Cs, St, Line, Col, Toks, N+1); -skip_white_space([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun skip_white_space/6}}; +skip_white_space([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun skip_white_space_fun/6}}; skip_white_space(Cs, St, Line, Col, Toks, N) -> scan1(Cs, St, Line, incr_column(Col, N), Toks). +scan_white_space_fun(Cs, #erl_scan{}=St, Line, Col, Toks, Ncs) -> + scan_white_space(Cs, St, Line, Col, Toks, Ncs). + %% Maybe \t and \s should break the loop. scan_white_space([$\n|_]=Cs, St, Line, Col, Toks, Ncs) -> white_space_end(Cs, St, Line, Col, Toks, length(Ncs), lists:reverse(Ncs)); scan_white_space([C|Cs], St, Line, Col, Toks, Ncs) when ?WHITE_SPACE(C) -> scan_white_space(Cs, St, Line, Col, Toks, [C|Ncs]); -scan_white_space([]=Cs, _St, Line, Col, Toks, Ncs) -> - {more,{Cs,Col,Toks,Line,Ncs,fun scan_white_space/6}}; +scan_white_space([]=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_white_space_fun/6}}; scan_white_space(Cs, St, Line, Col, Toks, Ncs) -> white_space_end(Cs, St, Line, Col, Toks, length(Ncs), lists:reverse(Ncs)). @@ -728,71 +807,97 @@ white_space_end(Cs, St, Line, Col, Toks, N, Ncs) -> scan_char([$\\|Cs]=Cs0, St, Line, Col, Toks) -> case scan_escape(Cs, incr_column(Col, 2)) of more -> - {more,{[$$|Cs0],Col,Toks,Line,[],fun scan/6}}; + {more,{[$$|Cs0],St,Col,Toks,Line,[],fun scan/6}}; {error,Ncs,Error,Ncol} -> scan_error(Error, Line, Col, Line, Ncol, Ncs); {eof,Ncol} -> scan_error(char, Line, Col, Line, Ncol, eof); {nl,Val,Str,Ncs,Ncol} -> - Anno = anno(Line, Col, St, ?STR(St, "$\\"++Str)), %" + Anno = anno(Line, Col, St, ?STR(char, St, "$\\"++Str)), %" Ntoks = [{char,Anno,Val}|Toks], scan1(Ncs, St, Line+1, Ncol, Ntoks); {Val,Str,Ncs,Ncol} -> - Anno = anno(Line, Col, St, ?STR(St, "$\\"++Str)), %" + Anno = anno(Line, Col, St, ?STR(char, St, "$\\"++Str)), %" Ntoks = [{char,Anno,Val}|Toks], scan1(Ncs, St, Line, Ncol, Ntoks) end; scan_char([$\n=C|Cs], St, Line, Col, Toks) -> - Anno = anno(Line, Col, St, ?STR(St, [$$,C])), + Anno = anno(Line, Col, St, ?STR(char, St, [$$,C])), scan1(Cs, St, Line+1, new_column(Col, 1), [{char,Anno,C}|Toks]); scan_char([C|Cs], St, Line, Col, Toks) when ?UNICODE(C) -> - Anno = anno(Line, Col, St, ?STR(St, [$$,C])), + Anno = anno(Line, Col, St, ?STR(char, St, [$$,C])), scan1(Cs, St, Line, incr_column(Col, 2), [{char,Anno,C}|Toks]); scan_char([C|_Cs], _St, Line, Col, _Toks) when ?CHAR(C) -> scan_error({illegal,character}, Line, Col, Line, incr_column(Col, 1), eof); -scan_char([], _St, Line, Col, Toks) -> - {more,{[$$],Col,Toks,Line,[],fun scan/6}}; +scan_char([], St, Line, Col, Toks) -> + {more,{[$$],St,Col,Toks,Line,[],fun scan/6}}; scan_char(eof, _St, Line, Col, _Toks) -> scan_error(char, Line, Col, Line, incr_column(Col, 1), eof). -scan_string(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) -> +%% Scan leading $" characters until we have them all +%% +scan_tqstring(Cs, St, Line, Col, Toks, Qs) -> + case Cs of + [$"|Ncs] -> + scan_tqstring(Ncs, St, Line, Col, Toks, Qs+1); + [] -> + {more, {[], St, Col, Toks, Line, Qs, fun scan_tqstring/6}}; + _ -> + scan_tqstring_finish(Cs, St, Line, Col, Toks, Qs, tqstring) + end. + +scan_tqstring_finish(Cs, St, Line, Col, Toks, Qs, TokTag) when 1 < Qs -> + Anno = anno(Line, Col, St, ?STR(string, St, [$",$"])), + Tok = {TokTag, Anno, ""}, + scan_tqstring_finish( + Cs, St, Line, incr_column(Col, 2), [Tok|Toks], Qs-2, string); +scan_tqstring_finish(Cs, St, Line, Col, Toks, Qs, _TokTag) -> + Ncs = + case Qs of + 1 -> [$"|Cs];%" + 0 -> Cs + end, + scan1(Ncs, St, Line, Col, Toks). + +scan_string(Cs, #erl_scan{}=St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) -> case scan_string0(Cs, St, Line, Col, $\", Str, Wcs) of %" {more,Ncs,Nline,Ncol,Nstr,Nwcs} -> State = {Nwcs,Nstr,Line0,Col0}, - {more,{Ncs,Ncol,Toks,Nline,State,fun scan_string/6}}; + {more,{Ncs,St,Ncol,Toks,Nline,State,fun scan_string/6}}; {char_error,Ncs,Error,Nline,Ncol,EndCol} -> scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs); {error,Nline,Ncol,Nwcs,Ncs} -> Estr = string:slice(Nwcs, 0, 16), % Expanded escape chars. scan_error({string,$\",Estr}, Line0, Col0, Nline, Ncol, Ncs); %" {Ncs,Nline,Ncol,Nstr,Nwcs} -> - Anno = anno(Line0, Col0, St, Nstr), + Anno = anno(Line0, Col0, St, ?STR(string, St, Nstr)), scan1(Ncs, St, Nline, Ncol, [{string,Anno,Nwcs}|Toks]) end. -scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) -> +scan_qatom(Cs, #erl_scan{}=St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) -> case scan_string0(Cs, St, Line, Col, $\', Str, Wcs) of %' {more,Ncs,Nline,Ncol,Nstr,Nwcs} -> State = {Nwcs,Nstr,Line0,Col0}, - {more,{Ncs,Ncol,Toks,Nline,State,fun scan_qatom/6}}; + {more,{Ncs,St,Ncol,Toks,Nline,State,fun scan_qatom/6}}; {char_error,Ncs,Error,Nline,Ncol,EndCol} -> scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs); {error,Nline,Ncol,Nwcs,Ncs} -> Estr = string:slice(Nwcs, 0, 16), % Expanded escape chars. scan_error({string,$\',Estr}, Line0, Col0, Nline, Ncol, Ncs); %' - {Ncs,Nline,Ncol,Nstr,Nwcs} -> - case catch list_to_atom(Nwcs) of + {Ncs,Nline,Ncol,Nstr,Nwcs} -> + try list_to_atom(Nwcs) of A when is_atom(A) -> - Anno = anno(Line0, Col0, St, Nstr), - scan1(Ncs, St, Nline, Ncol, [{atom,Anno,A}|Toks]); - _ -> + Anno = anno(Line0, Col0, St, ?STR(atom, St, Nstr)), + scan1(Ncs, St, Nline, Ncol, [{atom,Anno,A}|Toks]) + catch + _:_ -> scan_error({illegal,atom}, Line0, Col0, Nline, Ncol, Ncs) end end. -scan_string0(Cs, #erl_scan{text=false}, Line, no_col=Col, Q, [], Wcs) -> +scan_string0(Cs, #erl_scan{has_fun=false}, Line, no_col=Col, Q, [], Wcs) -> scan_string_no_col(Cs, Line, Col, Q, Wcs); -scan_string0(Cs, #erl_scan{text=true}, Line, no_col=Col, Q, Str, Wcs) -> +scan_string0(Cs, #erl_scan{has_fun=true}, Line, no_col=Col, Q, Str, Wcs) -> scan_string1(Cs, Line, Col, Q, Str, Wcs); scan_string0(Cs, St, Line, Col, Q, [], Wcs) -> scan_string_col(Cs, St, Line, Col, Q, Wcs); @@ -812,7 +917,7 @@ scan_string_no_col(Cs, Line, Col, Q, Wcs) -> %% Optimization. Col =/= no_col. scan_string_col([Q|Cs], St, Line, Col, Q, Wcs0) -> Wcs = lists:reverse(Wcs0), - Str = ?STR(St, [Q|Wcs++[Q]]), + Str = ?STR(atom, St, [Q|Wcs++[Q]]), {Cs,Line,Col+1,Str,Wcs}; scan_string_col([$\n=C|Cs], St, Line, _xCol, Q, Wcs) -> scan_string_col(Cs, St, Line+1, 1, Q, [C|Wcs]); @@ -861,10 +966,11 @@ scan_string1([]=Cs, Line, Col, _Q, Str, Wcs) -> scan_string1(eof, Line, Col, _Q, _Str, Wcs) -> {error,Line,Col,lists:reverse(Wcs),eof}. --define(OCT(C), C >= $0, C =< $7). --define(HEX(C), C >= $0 andalso C =< $9 orelse - C >= $A andalso C =< $F orelse - C >= $a andalso C =< $f). +-define(OCT(C), (is_integer(C) andalso $0 =< C andalso C =< $7)). +-define(HEX(C), (is_integer(C) andalso + (C >= $0 andalso C =< $9 orelse + C >= $A andalso C =< $F orelse + C >= $a andalso C =< $f))). %% \<1-3> octal digits scan_escape([O1,O2,O3|Cs], Col) when ?OCT(O1), ?OCT(O2), ?OCT(O3) -> @@ -894,12 +1000,14 @@ scan_escape([$x,H1], _Col) when ?HEX(H1) -> more; scan_escape([$x|Cs], Col) -> {error,Cs,{illegal,character},incr_column(Col, 1)}; -%% \^X -> CTL-X -scan_escape([$^=C0,$\n=C|Cs], Col) -> - {nl,C,[C0,C],Cs,new_column(Col, 1)}; +%% \^X -> Control-X scan_escape([$^=C0,C|Cs], Col) when ?CHAR(C) -> - Val = C band 31, - {Val,[C0,C],Cs,incr_column(Col, 2)}; + case caret_char_code(C) of + error -> + {error,[C|Cs],{illegal,character},incr_column(Col, 1)}; + Code -> + {Code,[C0,C],Cs,incr_column(Col, 2)} + end; scan_escape([$^], _Col) -> more; scan_escape([$^|eof], Col) -> @@ -916,26 +1024,31 @@ scan_escape([], _Col) -> scan_escape(eof, Col) -> {eof,Col}. -scan_hex([C|Cs], no_col=Col, Wcs) when ?HEX(C) -> - scan_hex(Cs, Col, [C|Wcs]); scan_hex([C|Cs], Col, Wcs) when ?HEX(C) -> - scan_hex(Cs, Col+1, [C|Wcs]); + scan_hex(Cs, incr_column(Col, 1), [C|Wcs]); scan_hex(Cs, Col, Wcs) -> - scan_esc_end(Cs, Col, Wcs, 16, "x{"). + scan_hex_end(Cs, Col, Wcs, "x{"). -scan_esc_end([$}|Cs], Col, Wcs0, B, Str0) -> +scan_hex_end([$}|Cs], Col, [], _Str) -> + %% Empty escape sequence. + {error,Cs,{illegal,character},incr_column(Col, 1)}; +scan_hex_end([$}|Cs], Col, Wcs0, Str0) -> Wcs = lists:reverse(Wcs0), - case catch erlang:list_to_integer(Wcs, B) of + try list_to_integer(Wcs, 16) of Val when ?UNICODE(Val) -> {Val,Str0++Wcs++[$}],Cs,incr_column(Col, 1)}; - _ -> + _Val -> + {error,Cs,{illegal,character},incr_column(Col, 1)} + catch + error:system_limit -> + %% Extremely unlikely to occur in practice. {error,Cs,{illegal,character},incr_column(Col, 1)} end; -scan_esc_end([], _Col, _Wcs, _B, _Str0) -> +scan_hex_end([], _Col, _Wcs, _Str0) -> more; -scan_esc_end(eof, Col, _Wcs, _B, _Str0) -> +scan_hex_end(eof, Col, _Wcs, _Str0) -> {eof,Col}; -scan_esc_end(Cs, Col, _Wcs, _B, _Str0) -> +scan_hex_end(Cs, Col, _Wcs, _Str0) -> {error,Cs,{illegal,character},Col}. escape_char($n) -> $\n; % \n = LF @@ -949,7 +1062,11 @@ escape_char($s) -> $\s; % \s = SPC escape_char($d) -> $\d; % \d = DEL escape_char(C) -> C. -scan_number(Cs, St, Line, Col, Toks, {Ncs, Us}) -> +caret_char_code($?) -> 16#7f; +caret_char_code(C) when $@ =< C, C =< $_; $a =< C, C =< $z -> C band 16#1f; +caret_char_code(_) -> error. + +scan_number(Cs, #erl_scan{}=St, Line, Col, Toks, {Ncs, Us}) -> scan_number(Cs, St, Line, Col, Toks, Ncs, Us). scan_number([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> @@ -957,30 +1074,36 @@ scan_number([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> scan_number([$_,Next|Cs], St, Line, Col, Toks, [Prev|_]=Ncs, _Us) when ?DIGIT(Next) andalso ?DIGIT(Prev) -> scan_number(Cs, St, Line, Col, Toks, [Next,$_|Ncs], with_underscore); -scan_number([$_]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; +scan_number([$_]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; scan_number([$.,C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> scan_fraction(Cs, St, Line, Col, Toks, [C,$.|Ncs], Us); -scan_number([$.]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; +scan_number([$.]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; scan_number([$#|Cs]=Cs0, St, Line, Col, Toks, Ncs0, Us) -> Ncs = lists:reverse(Ncs0), - case catch list_to_integer(remove_digit_separators(Ncs, Us)) of - B when B >= 2, B =< 1+$Z-$A+10 -> + try list_to_integer(remove_digit_separators(Ncs, Us)) of + B when is_integer(B), 2 =< B, B =< 1+$Z-$A+10 -> Bcs = Ncs++[$#], scan_based_int(Cs, St, Line, Col, Toks, B, [], Bcs, no_underscore); - B -> + B when is_integer(B) -> Len = length(Ncs), scan_error({base,B}, Line, Col, Line, incr_column(Col, Len), Cs0) + catch + error:system_limit -> + %% Extremely unlikely to occur in practice. + scan_error({illegal,base}, Line, Col, Line, Col, Cs0) end; -scan_number([]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; +scan_number([]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_number/6}}; scan_number(Cs, St, Line, Col, Toks, Ncs0, Us) -> Ncs = lists:reverse(Ncs0), - case catch list_to_integer(remove_digit_separators(Ncs, Us)) of - N when is_integer(N) -> - tok3(Cs, St, Line, Col, Toks, integer, Ncs, N); - _ -> + try list_to_integer(remove_digit_separators(Ncs, Us), 10) of + N -> + tok3(Cs, St, Line, Col, Toks, integer, Ncs, N) + catch + error:system_limit -> + %% Extremely unlikely to occur in practice. Ncol = incr_column(Col, length(Ncs)), scan_error({illegal,integer}, Line, Col, Line, Ncol, Cs) end. @@ -991,11 +1114,14 @@ remove_digit_separators(Number, with_underscore) -> [C || C <- Number, C =/= $_]. -define(BASED_DIGIT(C, B), - ((?DIGIT(C) andalso C < $0 + B) - orelse (C >= $A andalso B > 10 andalso C < $A + B - 10) - orelse (C >= $a andalso B > 10 andalso C < $a + B - 10))). - -scan_based_int(Cs, St, Line, Col, Toks, {B,NCs,BCs,Us}) -> + (is_integer(C) + andalso + ((?DIGIT(C) andalso C < $0 + B) + orelse (C >= $A andalso B > 10 andalso C < $A + B - 10) + orelse (C >= $a andalso B > 10 andalso C < $a + B - 10)))). + +scan_based_int(Cs, #erl_scan{}=St, Line, Col, Toks, {B,NCs,BCs,Us}) + when is_integer(B), 2 =< B, B =< 1+$Z-$A+10 -> scan_based_int(Cs, St, Line, Col, Toks, B, NCs, BCs, Us). scan_based_int([C|Cs], St, Line, Col, Toks, B, Ncs, Bcs, Us) when @@ -1005,22 +1131,29 @@ scan_based_int([$_,Next|Cs], St, Line, Col, Toks, B, [Prev|_]=Ncs, Bcs, _Us) when ?BASED_DIGIT(Next, B) andalso ?BASED_DIGIT(Prev, B) -> scan_based_int(Cs, St, Line, Col, Toks, B, [Next,$_|Ncs], Bcs, with_underscore); -scan_based_int([$_]=Cs, _St, Line, Col, Toks, B, NCs, BCs, Us) -> - {more,{Cs,Col,Toks,Line,{B,NCs,BCs,Us},fun scan_based_int/6}}; -scan_based_int([]=Cs, _St, Line, Col, Toks, B, NCs, BCs, Us) -> - {more,{Cs,Col,Toks,Line,{B,NCs,BCs,Us},fun scan_based_int/6}}; -scan_based_int(Cs, St, Line, Col, Toks, B, Ncs0, Bcs, Us) -> +scan_based_int([$_]=Cs, St, Line, Col, Toks, B, NCs, BCs, Us) -> + {more,{Cs,St,Col,Toks,Line,{B,NCs,BCs,Us},fun scan_based_int/6}}; +scan_based_int([]=Cs, St, Line, Col, Toks, B, NCs, BCs, Us) -> + {more,{Cs,St,Col,Toks,Line,{B,NCs,BCs,Us},fun scan_based_int/6}}; +scan_based_int(Cs, _St, Line, Col, _Toks, _B, [], Bcs, _Us) -> + %% No actual digits following the base. + Len = length(Bcs), + Ncol = incr_column(Col, Len), + scan_error({illegal,integer}, Line, Col, Line, Ncol, Cs); +scan_based_int(Cs, St, Line, Col, Toks, B, Ncs0, [_|_]=Bcs, Us) -> Ncs = lists:reverse(Ncs0), - case catch erlang:list_to_integer(remove_digit_separators(Ncs, Us), B) of - N when is_integer(N) -> - tok3(Cs, St, Line, Col, Toks, integer, Bcs++Ncs, N); - _ -> + try list_to_integer(remove_digit_separators(Ncs, Us), B) of + N -> + tok3(Cs, St, Line, Col, Toks, integer, Bcs++Ncs, N) + catch + error:system_limit -> + %% Extremely unlikely to occur in practice. Len = length(Bcs)+length(Ncs), Ncol = incr_column(Col, Len), scan_error({illegal,integer}, Line, Col, Line, Ncol, Cs) end. -scan_fraction(Cs, St, Line, Col, Toks, {Ncs,Us}) -> +scan_fraction(Cs, #erl_scan{}=St, Line, Col, Toks, {Ncs,Us}) -> scan_fraction(Cs, St, Line, Col, Toks, Ncs, Us). scan_fraction([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> @@ -1028,27 +1161,27 @@ scan_fraction([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> scan_fraction([$_,Next|Cs], St, Line, Col, Toks, [Prev|_]=Ncs, _Us) when ?DIGIT(Next) andalso ?DIGIT(Prev) -> scan_fraction(Cs, St, Line, Col, Toks, [Next,$_|Ncs], with_underscore); -scan_fraction([$_]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_fraction/6}}; +scan_fraction([$_]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_fraction/6}}; scan_fraction([E|Cs], St, Line, Col, Toks, Ncs, Us) when E =:= $e; E =:= $E -> scan_exponent_sign(Cs, St, Line, Col, Toks, [E|Ncs], Us); -scan_fraction([]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_fraction/6}}; +scan_fraction([]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_fraction/6}}; scan_fraction(Cs, St, Line, Col, Toks, Ncs, Us) -> float_end(Cs, St, Line, Col, Toks, Ncs, Us). -scan_exponent_sign(Cs, St, Line, Col, Toks, {Ncs, Us}) -> +scan_exponent_sign(Cs, #erl_scan{}=St, Line, Col, Toks, {Ncs, Us}) -> scan_exponent_sign(Cs, St, Line, Col, Toks, Ncs, Us). scan_exponent_sign([C|Cs], St, Line, Col, Toks, Ncs, Us) when C =:= $+; C =:= $- -> scan_exponent(Cs, St, Line, Col, Toks, [C|Ncs], Us); -scan_exponent_sign([]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_exponent_sign/6}}; +scan_exponent_sign([]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_exponent_sign/6}}; scan_exponent_sign(Cs, St, Line, Col, Toks, Ncs, Us) -> scan_exponent(Cs, St, Line, Col, Toks, Ncs, Us). -scan_exponent(Cs, St, Line, Col, Toks, {Ncs, Us}) -> +scan_exponent(Cs, #erl_scan{}=St, Line, Col, Toks, {Ncs, Us}) -> scan_exponent(Cs, St, Line, Col, Toks, Ncs, Us). scan_exponent([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> @@ -1056,23 +1189,27 @@ scan_exponent([C|Cs], St, Line, Col, Toks, Ncs, Us) when ?DIGIT(C) -> scan_exponent([$_,Next|Cs], St, Line, Col, Toks, [Prev|_]=Ncs, _) when ?DIGIT(Next) andalso ?DIGIT(Prev) -> scan_exponent(Cs, St, Line, Col, Toks, [Next,$_|Ncs], with_underscore); -scan_exponent([$_]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_exponent/6}}; -scan_exponent([]=Cs, _St, Line, Col, Toks, Ncs, Us) -> - {more,{Cs,Col,Toks,Line,{Ncs,Us},fun scan_exponent/6}}; +scan_exponent([$_]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_exponent/6}}; +scan_exponent([]=Cs, St, Line, Col, Toks, Ncs, Us) -> + {more,{Cs,St,Col,Toks,Line,{Ncs,Us},fun scan_exponent/6}}; scan_exponent(Cs, St, Line, Col, Toks, Ncs, Us) -> float_end(Cs, St, Line, Col, Toks, Ncs, Us). float_end(Cs, St, Line, Col, Toks, Ncs0, Us) -> Ncs = lists:reverse(Ncs0), - case catch list_to_float(remove_digit_separators(Ncs, Us)) of - F when is_float(F) -> - tok3(Cs, St, Line, Col, Toks, float, Ncs, F); - _ -> + try list_to_float(remove_digit_separators(Ncs, Us)) of + F -> + tok3(Cs, St, Line, Col, Toks, float, Ncs, F) + catch + _:_ -> Ncol = incr_column(Col, length(Ncs)), scan_error({illegal,float}, Line, Col, Line, Ncol, Cs) end. +skip_comment_fun(Cs, #erl_scan{}=St, Line, Col, Toks, N) -> + skip_comment(Cs, St, Line, Col, Toks, N). + skip_comment([C|Cs], St, Line, Col, Toks, N) when C =/= $\n, ?CHAR(C) -> case ?UNICODE(C) of true -> @@ -1081,12 +1218,16 @@ skip_comment([C|Cs], St, Line, Col, Toks, N) when C =/= $\n, ?CHAR(C) -> Ncol = incr_column(Col, N+1), scan_error({illegal,character}, Line, Col, Line, Ncol, Cs) end; -skip_comment([]=Cs, _St, Line, Col, Toks, N) -> - {more,{Cs,Col,Toks,Line,N,fun skip_comment/6}}; +skip_comment([]=Cs, St, Line, Col, Toks, N) -> + {more,{Cs,St,Col,Toks,Line,N,fun skip_comment_fun/6}}; skip_comment(Cs, St, Line, Col, Toks, N) -> scan1(Cs, St, Line, incr_column(Col, N), Toks). -scan_comment([C|Cs], St, Line, Col, Toks, Ncs) when C =/= $\n, ?CHAR(C) -> +scan_comment_fun(Cs, #erl_scan{}=St, Line, Col, Toks, Ncs) -> + scan_comment(Cs, St, Line, Col, Toks, Ncs). + +scan_comment([C|Cs], St, Line, Col, Toks, Ncs) + when C =/= $\n, ?CHAR(C) -> case ?UNICODE(C) of true -> scan_comment(Cs, St, Line, Col, Toks, [C|Ncs]); @@ -1094,35 +1235,77 @@ scan_comment([C|Cs], St, Line, Col, Toks, Ncs) when C =/= $\n, ?CHAR(C) -> Ncol = incr_column(Col, length(Ncs)+1), scan_error({illegal,character}, Line, Col, Line, Ncol, Cs) end; -scan_comment([]=Cs, _St, Line, Col, Toks, Ncs) -> - {more,{Cs,Col,Toks,Line,Ncs,fun scan_comment/6}}; +scan_comment([]=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_comment_fun/6}}; scan_comment(Cs, St, Line, Col, Toks, Ncs0) -> Ncs = lists:reverse(Ncs0), tok3(Cs, St, Line, Col, Toks, comment, Ncs, Ncs). -tok2(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, _Wcs, P) -> +scan_check("%%ssa%" ++ Cs, St, Line, Col, Toks, _Ncs) -> + scan_check1(Cs, St, Line, Toks, Col, 7); +scan_check("%%ssa"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%%ss"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%%s"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%%"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%ssa%" ++ Cs, St, Line, Col, Toks, _Ncs) -> + scan_check1(Cs, St, Line, Toks, Col, 6); +scan_check("%ssa"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%ss"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("%s"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("ssa%" ++ Cs, St, Line, Col, Toks, _Ncs) -> + scan_check1(Cs, St, Line, Toks, Col, 5); +scan_check("ssa"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("ss"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check("s"=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check([]=Cs, St, Line, Col, Toks, Ncs) -> + {more,{Cs,St,Col,Toks,Line,Ncs,fun scan_check/6}}; +scan_check(Cs, St=#erl_scan{comment=true}, Line, Col, Toks, Ncs) -> + scan_comment(Cs, St, Line, Col, Toks, Ncs); +scan_check(Cs, St, Line, Col, Toks, _Ncs) -> + skip_comment(Cs, St, Line, Col, Toks, 1). + +scan_check1(Cs, St=#erl_scan{in_check=true}, Line, Toks, Col, NoofCols) -> + %% Skip as we are already in the check mode + scan1(Cs, St, Line, incr_column(Col, NoofCols), Toks); +scan_check1(Cs, St, Line, Toks, Col, NoofCols) -> + tok2(Cs, St#erl_scan{in_check=true}, Line, + Col, Toks, "%ssa%", '%ssa%', NoofCols). + +tok2(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, _Wcs, P) -> scan1(Cs, St, Line, Col, [{P,anno(Line)}|Toks]); -tok2(Cs, St, Line, Col, Toks, Wcs, P) -> - Anno = anno(Line, Col, St, Wcs), +tok2(Cs, #erl_scan{}=St, Line, Col, Toks, Wcs, P) -> + Anno = anno(Line, Col, St, ?STR(P, St, Wcs)), scan1(Cs, St, Line, incr_column(Col, length(Wcs)), [{P,Anno}|Toks]). -tok2(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, _Wcs, P, _N) -> +tok2(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, _Wcs, P, _N) -> scan1(Cs, St, Line, Col, [{P,anno(Line)}|Toks]); -tok2(Cs, St, Line, Col, Toks, Wcs, P, N) -> - Anno = anno(Line, Col, St, Wcs), +tok2(Cs, #erl_scan{}=St, Line, Col, Toks, Wcs, P, N) -> + Anno = anno(Line, Col, St, ?STR(P,St,Wcs)), scan1(Cs, St, Line, incr_column(Col, N), [{P,Anno}|Toks]). -tok3(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, Item, _S, Sym) -> +tok3(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, Item, _S, Sym) -> scan1(Cs, St, Line, Col, [{Item,anno(Line),Sym}|Toks]); -tok3(Cs, St, Line, Col, Toks, Item, String, Sym) -> - Token = {Item,anno(Line, Col, St, String),Sym}, +tok3(Cs, #erl_scan{}=St, Line, Col, Toks, Item, String, Sym) -> + Token = {Item,anno(Line, Col, St, ?STR(Item, St, String)),Sym}, scan1(Cs, St, Line, incr_column(Col, length(String)), [Token|Toks]). -tok3(Cs, #erl_scan{text = false}=St, Line, no_col=Col, Toks, Item, +tok3(Cs, #erl_scan{has_fun = false}=St, Line, no_col=Col, Toks, Item, _String, Sym, _Length) -> scan1(Cs, St, Line, Col, [{Item,anno(Line),Sym}|Toks]); -tok3(Cs, St, Line, Col, Toks, Item, String, Sym, Length) -> - Token = {Item,anno(Line, Col, St, String),Sym}, +tok3(Cs, #erl_scan{}=St, Line, Col, Toks, Item, String, Sym, Length) -> + Token = {Item,anno(Line, Col, St, ?STR(Item, St, String)),Sym}, scan1(Cs, St, Line, incr_column(Col, Length), [Token|Toks]). scan_error(Error, Line, Col, EndLine, EndCol, Rest) -> @@ -1135,14 +1318,18 @@ scan_error(Error, ErrorLoc, EndLoc, Rest) -> -compile({inline,[anno/4]}). -anno(Line, no_col, #erl_scan{text = false}, _String) -> +anno(Line, no_col, #erl_scan{has_fun = false}, _String) -> anno(Line); -anno(Line, no_col, #erl_scan{text = true}, String) -> +anno(Line, no_col, #erl_scan{has_fun = true}, []) -> + anno(Line); +anno(Line, no_col, #erl_scan{has_fun = true}, String) -> Anno = anno(Line), erl_anno:set_text(String, Anno); -anno(Line, Col, #erl_scan{text = false}, _String) -> +anno(Line, Col, #erl_scan{has_fun = false}, _String) -> + anno({Line, Col}); +anno(Line, Col, #erl_scan{has_fun = true}, []) -> anno({Line, Col}); -anno(Line, Col, #erl_scan{text = true}, String) -> +anno(Line, Col, #erl_scan{has_fun = true}, String) -> Anno = anno({Line, Col}), erl_anno:set_text(String, Anno). @@ -1222,32 +1409,43 @@ tabs(8) -> "\t\t\t\t\t\t\t\t"; tabs(9) -> "\t\t\t\t\t\t\t\t\t"; tabs(10) -> "\t\t\t\t\t\t\t\t\t\t". +%% Dynamic version of reserved_word that knows about the possibility +%% that enabled features might change the set of reserved words. -spec reserved_word(Atom :: atom()) -> boolean(). -reserved_word('after') -> true; -reserved_word('begin') -> true; -reserved_word('case') -> true; -reserved_word('try') -> true; -reserved_word('cond') -> true; -reserved_word('catch') -> true; -reserved_word('andalso') -> true; -reserved_word('orelse') -> true; -reserved_word('end') -> true; -reserved_word('fun') -> true; -reserved_word('if') -> true; -reserved_word('let') -> true; -reserved_word('of') -> true; -reserved_word('receive') -> true; -reserved_word('when') -> true; -reserved_word('bnot') -> true; -reserved_word('not') -> true; -reserved_word('div') -> true; -reserved_word('rem') -> true; -reserved_word('band') -> true; -reserved_word('and') -> true; -reserved_word('bor') -> true; -reserved_word('bxor') -> true; -reserved_word('bsl') -> true; -reserved_word('bsr') -> true; -reserved_word('or') -> true; -reserved_word('xor') -> true; -reserved_word(_) -> false. +reserved_word(Atom) -> + case f_reserved_word(Atom) of + true -> true; + false -> + lists:member(Atom, erl_features:keywords()) + end. + +%% Static version of reserved_words. These represent the fixed set of +%% reserved words. +f_reserved_word('after') -> true; +f_reserved_word('begin') -> true; +f_reserved_word('case') -> true; +f_reserved_word('try') -> true; +f_reserved_word('cond') -> true; +f_reserved_word('catch') -> true; +f_reserved_word('andalso') -> true; +f_reserved_word('orelse') -> true; +f_reserved_word('end') -> true; +f_reserved_word('fun') -> true; +f_reserved_word('if') -> true; +f_reserved_word('let') -> true; +f_reserved_word('of') -> true; +f_reserved_word('receive') -> true; +f_reserved_word('when') -> true; +f_reserved_word('bnot') -> true; +f_reserved_word('not') -> true; +f_reserved_word('div') -> true; +f_reserved_word('rem') -> true; +f_reserved_word('band') -> true; +f_reserved_word('and') -> true; +f_reserved_word('bor') -> true; +f_reserved_word('bxor') -> true; +f_reserved_word('bsl') -> true; +f_reserved_word('bsr') -> true; +f_reserved_word('or') -> true; +f_reserved_word('xor') -> true; +f_reserved_word(_) -> false. diff --git a/lib/stdlib/src/erl_stdlib_errors.erl b/lib/stdlib/src/erl_stdlib_errors.erl index 356ac0b79248..a90d6477a7ca 100644 --- a/lib/stdlib/src/erl_stdlib_errors.erl +++ b/lib/stdlib/src/erl_stdlib_errors.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2020-2021. All Rights Reserved. +%% Copyright Ericsson AB 2020-2023. 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. @@ -73,10 +73,17 @@ format_binary_error(encode_unsigned, [Subject, Endianness], _) -> [must_be_non_neg_integer(Subject), must_be_endianness(Endianness)]; format_binary_error(encode_hex, [Subject], _) -> [must_be_binary(Subject)]; +format_binary_error(encode_hex, [Subject, Case], _) -> + [must_be_binary(Subject), must_be_hex_case(Case)]; format_binary_error(decode_hex, [Subject], _) -> if - is_binary(Subject), byte_size(Subject) rem 2 == 1 -> - ["must contain an even number of bytes"]; + is_binary(Subject) -> + if + byte_size(Subject) rem 2 =:= 1 -> + [<<"must contain an even number of bytes">>]; + true -> + [<<"must only contain hex digits 0-9, A-F, and a-f">>] + end; true -> [must_be_binary(Subject)] end; @@ -189,7 +196,20 @@ format_lists_error(keysearch, Args) -> format_lists_error(member, [_Key, List]) -> [[], must_be_list(List)]; format_lists_error(reverse, [List, _Acc]) -> - [must_be_list(List)]. + [must_be_list(List)]; +format_lists_error(seq, [First, Last, Inc]) -> + case [must_be_integer(First), must_be_integer(Last), must_be_integer(Inc)] of + [[], [], []] -> + IncError = if + (Inc =< 0 andalso First - Inc =< Last) -> + <<"not a positive increment">>; + (Inc >= 0 andalso First - Inc >= Last) -> + <<"not a negative increment">> + end, + [[], [], IncError]; + Errors -> Errors + end. + format_maps_error(filter, Args) -> format_maps_error(map, Args); @@ -212,6 +232,10 @@ format_maps_error(get, [_Key,Map]) -> true -> [[],not_map] end; +format_maps_error(groups_from_list, [Fun, List]) -> + [must_be_fun(Fun, 1), must_be_list(List)]; +format_maps_error(groups_from_list, [Fun1, Fun2, List]) -> + [must_be_fun(Fun1, 1), must_be_fun(Fun2, 1), must_be_list(List)]; format_maps_error(get, [_,_,_]) -> [[],not_map]; format_maps_error(intersect, [Map1, Map2]) -> @@ -220,8 +244,10 @@ format_maps_error(intersect_with, [Combiner, Map1, Map2]) -> [must_be_fun(Combiner, 3), must_be_map(Map1), must_be_map(Map2)]; format_maps_error(is_key, _Args) -> [[], not_map]; -format_maps_error(iterator, _Args) -> - [not_map]; +format_maps_error(iterator, [Map]) -> + [must_be_map(Map)]; +format_maps_error(iterator, [Map, Order]) -> + [must_be_map(Map), must_be_map_iterator_order(Order)]; format_maps_error(keys, _Args) -> [not_map]; format_maps_error(map, [Pred, Map]) -> @@ -230,10 +256,10 @@ format_maps_error(merge, [Map1, Map2]) -> [must_be_map(Map1), must_be_map(Map2)]; format_maps_error(merge_with, [Combiner, Map1, Map2]) -> [must_be_fun(Combiner, 3), must_be_map(Map1), must_be_map(Map2)]; -format_maps_error(put, _Args) -> - [[], [], not_map]; format_maps_error(next, _Args) -> [bad_iterator]; +format_maps_error(put, _Args) -> + [[], [], not_map]; format_maps_error(remove, _Args) -> [[], not_map]; format_maps_error(size, _Args) -> @@ -241,7 +267,7 @@ format_maps_error(size, _Args) -> format_maps_error(take, _Args) -> [[], not_map]; format_maps_error(to_list, _Args) -> - [not_map]; + [not_map_or_iterator]; format_maps_error(update, _Args) -> [[], [], not_map]; format_maps_error(update_with, [_Key, Fun, Map]) -> @@ -382,6 +408,12 @@ format_unicode_error(characters_to_nfkd_list, [_]) -> unicode_char_data(Chars) -> try unicode:characters_to_binary(Chars) of + {error,_,_} -> + bad_char_data; + + {incomplete,_,_} -> + bad_char_data; + _ -> [] catch @@ -426,6 +458,11 @@ format_io_error(_, _, {io, arguments}, true) -> [device_arguments]; format_io_error(_, _, {io, arguments}, false) -> [{general,device_arguments}]; +%% calling_self, Io =:= self() +format_io_error(_, _, {io, calling_self}, true) -> + [calling_self]; +format_io_error(_, _, {io, calling_self}, false) -> + [{general,calling_self}]; %% terminated, monitor(Io) failed format_io_error(_, _, {io, terminated}, true) -> [device_terminated]; @@ -478,7 +515,7 @@ format_io_error_cause(_, _, _, _HasDevice) -> maybe_posix_message(Cause, HasDevice) -> case erl_posix_msg:message(Cause) of - "unknown POSIX error" -> + "unknown POSIX error" ++ _ -> unknown; PosixStr when HasDevice -> [io_lib:format("~ts (~tp)",[PosixStr, Cause])]; @@ -613,6 +650,9 @@ format_ets_error(lookup_element, [_,_,Pos]=Args, Cause) -> [TabCause, "", PosCause] end end; +format_ets_error(lookup_element, [Tab, Key, Pos, _Default], Cause) -> + % The default argument cannot cause an error. + format_ets_error(lookup_element, [Tab, Key, Pos], Cause); format_ets_error(match, [_], _Cause) -> [bad_continuation]; format_ets_error(match, [_,_,_]=Args, Cause) -> @@ -625,17 +665,19 @@ format_ets_error(match_spec_compile, [_], _Cause) -> [bad_matchspec]; format_ets_error(next, Args, Cause) -> format_default(bad_key, Args, Cause); -format_ets_error(new, [Name,Options], _Cause) -> +format_ets_error(new, [Name,Options], Cause) -> NameError = if is_atom(Name) -> []; true -> not_atom end, OptsError = must_be_list(Options), - case {NameError,OptsError} of - {[],[]} -> - [[],bad_options]; - {_,_} -> - [NameError,OptsError] + case {NameError, OptsError, Cause} of + {[], [], already_exists} -> + [name_already_exists, []]; + {[], [], _} -> + [[], bad_options]; + {_, _, _} -> + [NameError, OptsError] end; format_ets_error(prev, Args, Cause) -> format_default(bad_key, Args, Cause); @@ -883,6 +925,10 @@ must_be_binary(Bin, Error) when is_binary(Bin) -> Error; must_be_binary(Bin, _Error) when is_bitstring(Bin) -> bitstring; must_be_binary(_, _) -> not_binary. +must_be_hex_case(uppercase) -> []; +must_be_hex_case(lowercase) -> []; +must_be_hex_case(_) -> bad_hex_case. + must_be_endianness(little) -> []; must_be_endianness(big) -> []; must_be_endianness(_) -> bad_endianness. @@ -929,14 +975,21 @@ must_be_list(_) -> must_be_map(#{}) -> []; must_be_map(_) -> not_map. +must_be_map_iterator_order(undefined) -> + []; +must_be_map_iterator_order(ordered) -> + []; +must_be_map_iterator_order(CmpFun) when is_function(CmpFun, 2) -> + []; +must_be_map_iterator_order(_) -> + not_map_iterator_order. + must_be_map_or_iter(Map) when is_map(Map) -> []; must_be_map_or_iter(Iter) -> - try maps:next(Iter) of - _ -> [] - catch - error:_ -> - not_map_or_iterator + case maps:is_iterator_valid(Iter) of + true -> []; + false -> not_map_or_iterator end. must_be_number(N) -> @@ -1008,6 +1061,8 @@ expand_error(bad_update_op) -> <<"not a valid update operation">>; expand_error(bitstring) -> <<"is a bitstring (expected a binary)">>; +expand_error(calling_self) -> + <<"the device is not allowed to be the current process">>; expand_error(counter_not_integer) -> <<"the value in the given position, in the object, is not an integer">>; expand_error(dead_process) -> @@ -1037,6 +1092,8 @@ expand_error(not_atom) -> <<"not an atom">>; expand_error(not_binary) -> <<"not a binary">>; +expand_error(bad_hex_case) -> + <<"not 'uppercase' or 'lowercase'">>; expand_error(not_compiled_regexp) -> <<"not a compiled regular expression">>; expand_error(not_iodata) -> @@ -1051,6 +1108,8 @@ expand_error(not_integer) -> <<"not an integer">>; expand_error(not_list) -> <<"not a list">>; +expand_error(not_map_iterator_order) -> + <<"not 'undefined', 'ordered', or a fun that takes two arguments">>; expand_error(not_map_or_iterator) -> <<"not a map or an iterator">>; expand_error(not_number) -> diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl index c689be30d810..da188c1bf1c9 100644 --- a/lib/stdlib/src/erl_tar.erl +++ b/lib/stdlib/src/erl_tar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -324,10 +324,17 @@ do_open(Name, Mode) when is_list(Mode) -> open1({binary,Bin0}=Handle, read, _Raw, Opts) when is_binary(Bin0) -> Bin = case lists:member(compressed, Opts) of true -> + %% emulate file:open with Modes = [compressed_one ...] + Z = zlib:open(), + zlib:inflateInit(Z, 31, cut), try - zlib:gunzip(Bin0) + IoList = zlib:inflate(Z, Bin0), + zlib:inflateEnd(Z), + iolist_to_binary(IoList) catch _:_ -> Bin0 + after + zlib:close(Z) end; false -> Bin0 @@ -354,7 +361,13 @@ open1({file, Fd}=Handle, read, [raw], Opts) -> end; open1({file, _Fd}=Handle, read, [], _Opts) -> {error, {Handle, {incompatible_option, cooked}}}; -open1(Name, Access, Raw, Opts) when is_list(Name) or is_binary(Name) -> +open1(Name, Access, Raw, Opts0) when is_list(Name); is_binary(Name) -> + Opts = case lists:member(compressed, Opts0) andalso Access == read of + true -> + [compressed_one | (Opts0 -- [compressed])]; + false -> + Opts0 + end, case file:open(Name, Raw ++ [binary, Access|Opts]) of {ok, File} -> {ok, #reader{handle=File,access=Access,func=fun file_op/2}}; @@ -1019,11 +1032,14 @@ do_get_format({error, _} = Err, _Bin) -> 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 -> + IsBadChecksum = case compute_checksum(Bin) of + Checksum -> false; + _ -> compute_signed_checksum(Bin) =/= Checksum + end, + case IsBadChecksum of + true -> ?FORMAT_UNKNOWN; - true -> + false -> %% guess magic Ustar = to_ustar(V7, Bin), Star = to_star(V7, Bin), @@ -1203,6 +1219,9 @@ compute_signed_checksum(< checksum(Bin, 0). + +checksum(<>, Sum) -> + checksum(Rest, Sum+A+B+C+D); checksum(<>, Sum) -> checksum(Rest, Sum+A); checksum(<<>>, Sum) -> Sum. @@ -1251,39 +1270,40 @@ parse_numeric(<> = Bin) -> parse_octal(Bin) end. -parse_octal(Bin) when is_binary(Bin) -> +parse_octal(<>) -> %% 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(Bin, 0). + +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, <>). + Digit = C - $0, + case Digit band 7 of + Digit -> + do_parse_octal(Rest, Acc bsl 3 bor Digit); + _ -> + throw({error, invalid_tar_checksum}) + end; +do_parse_octal(<<>>, Acc) -> + Acc. parse_string(Bin) when is_binary(Bin) -> - do_parse_string(Bin, <<>>). -do_parse_string(<<>>, Acc) -> - case unicode:characters_to_list(Acc) of + N = strlen(Bin, 0), + <> = Bin, + case unicode:characters_to_list(Prefix) of Str when is_list(Str) -> Str; {incomplete, _Str, _Rest} -> - binary:bin_to_list(Acc); + binary_to_list(Bin); {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, <>). + end. + +strlen(<<>>, N) -> N; +strlen(<<0, _/binary>>, N) -> N; +strlen(<<_, Rest/binary>>, N) -> strlen(Rest, N + 1). convert_header(Bin, #reader{pos=Pos}=Reader) when byte_size(Bin) =:= ?BLOCK_SIZE, (Pos rem ?BLOCK_SIZE) =:= 0 -> diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index 224937d4d345..8628a7e29f61 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -42,22 +42,27 @@ -export([i/0, i/1, i/2, i/3]). --export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]). +-export_type([table/0, table_access/0, table_type/0, + tid/0, match_spec/0, compiled_match_spec/0, match_pattern/0]). %%----------------------------------------------------------------------------- --type access() :: public | protected | private. --type tab() :: atom() | tid(). --type type() :: set | ordered_set | bag | duplicate_bag. --type continuation() :: '$end_of_table' - | {tab(),integer(),integer(),comp_match_spec(),list(),integer()} - | {tab(),_,_,integer(),comp_match_spec(),list(),integer(),integer()}. +-type table_access() :: public | protected | private. +-type table() :: atom() | tid(). +-type table_type() :: set | ordered_set | bag | duplicate_bag. +-type continuation() :: '$end_of_table' + | {table(),integer(),integer(),compiled_match_spec(),list(),integer()} + | {table(),_,_,integer(),compiled_match_spec(),list(),integer(),integer()}. --opaque tid() :: reference(). +-opaque tid() :: reference(). -type match_pattern() :: atom() | tuple(). -type match_spec() :: [{match_pattern(), [_], [_]}]. +%% Keep for backwards compatibility +-export_type([tab/0, comp_match_spec/0]). +-type tab() :: table(). + %%----------------------------------------------------------------------------- %%% BIFs @@ -65,7 +70,7 @@ -export([all/0, delete/1, delete/2, delete_all_objects/1, delete_object/2, first/1, give_away/3, info/1, info/2, insert/2, insert_new/2, is_compiled_ms/1, last/1, lookup/2, - lookup_element/3, match/1, match/2, match/3, match_object/1, + lookup_element/3, lookup_element/4, match/1, match/2, match/3, match_object/1, match_object/2, match_object/3, match_spec_compile/1, match_spec_run_r/3, member/2, new/2, next/2, prev/2, rename/2, safe_fixtable/2, select/1, select/2, select/3, @@ -80,8 +85,8 @@ internal_delete_all/2, internal_select_delete/2]). --spec all() -> [Tab] when - Tab :: tab(). +-spec all() -> [Table] when + Table :: table(). all() -> receive_all(ets:internal_request_all(), @@ -101,57 +106,57 @@ receive_all(Ref, N, All) -> internal_request_all() -> erlang:nif_error(undef). --spec delete(Tab) -> true when - Tab :: tab(). +-spec delete(Table) -> true when + Table :: table(). delete(_) -> erlang:nif_error(undef). --spec delete(Tab, Key) -> true when - Tab :: tab(), +-spec delete(Table, Key) -> true when + Table :: table(), Key :: term(). delete(_, _) -> erlang:nif_error(undef). --spec delete_all_objects(Tab) -> true when - Tab :: tab(). +-spec delete_all_objects(Table) -> true when + Table :: table(). -delete_all_objects(Tab) -> - _ = ets:internal_delete_all(Tab, undefined), +delete_all_objects(Table) -> + _ = ets:internal_delete_all(Table, undefined), true. --spec internal_delete_all(Tab, undefined) -> NumDeleted when - Tab :: tab(), +-spec internal_delete_all(Table, undefined) -> NumDeleted when + Table :: table(), NumDeleted :: non_neg_integer(). internal_delete_all(_, _) -> erlang:nif_error(undef). --spec delete_object(Tab, Object) -> true when - Tab :: tab(), +-spec delete_object(Table, Object) -> true when + Table :: table(), Object :: tuple(). delete_object(_, _) -> erlang:nif_error(undef). --spec first(Tab) -> Key | '$end_of_table' when - Tab :: tab(), +-spec first(Table) -> Key | '$end_of_table' when + Table :: table(), Key :: term(). first(_) -> erlang:nif_error(undef). --spec give_away(Tab, Pid, GiftData) -> true when - Tab :: tab(), +-spec give_away(Table, Pid, GiftData) -> true when + Table :: table(), Pid :: pid(), GiftData :: term(). give_away(_, _, _) -> erlang:nif_error(undef). --spec info(Tab) -> InfoList | undefined when - Tab :: tab(), +-spec info(Table) -> InfoList | undefined when + Table :: table(), InfoList :: [InfoTuple], InfoTuple :: {compressed, boolean()} | {decentralized_counters, boolean()} @@ -163,17 +168,17 @@ give_away(_, _, _) -> | {named_table, boolean()} | {node, node()} | {owner, pid()} - | {protection, access()} + | {protection, table_access()} | {size, non_neg_integer()} - | {type, type()} + | {type, table_type()} | {write_concurrency, boolean()} | {read_concurrency, boolean()}. info(_) -> erlang:nif_error(undef). --spec info(Tab, Item) -> Value | undefined when - Tab :: tab(), +-spec info(Table, Item) -> Value | undefined when + Table :: table(), Item :: binary | compressed | decentralized_counters | fixed | heir | id | keypos | memory | name | named_table | node | owner | protection | safe_fixed | safe_fixed_monotonic_time | size | stats | type @@ -183,15 +188,15 @@ info(_) -> info(_, _) -> erlang:nif_error(undef). --spec insert(Tab, ObjectOrObjects) -> true when - Tab :: tab(), +-spec insert(Table, ObjectOrObjects) -> true when + Table :: table(), ObjectOrObjects :: tuple() | [tuple()]. insert(_, _) -> erlang:nif_error(undef). --spec insert_new(Tab, ObjectOrObjects) -> boolean() when - Tab :: tab(), +-spec insert_new(Table, ObjectOrObjects) -> boolean() when + Table :: table(), ObjectOrObjects :: tuple() | [tuple()]. insert_new(_, _) -> @@ -203,23 +208,23 @@ insert_new(_, _) -> is_compiled_ms(_) -> erlang:nif_error(undef). --spec last(Tab) -> Key | '$end_of_table' when - Tab :: tab(), +-spec last(Table) -> Key | '$end_of_table' when + Table :: table(), Key :: term(). last(_) -> erlang:nif_error(undef). --spec lookup(Tab, Key) -> [Object] when - Tab :: tab(), +-spec lookup(Table, Key) -> [Object] when + Table :: table(), Key :: term(), Object :: tuple(). lookup(_, _) -> erlang:nif_error(undef). --spec lookup_element(Tab, Key, Pos) -> Elem when - Tab :: tab(), +-spec lookup_element(Table, Key, Pos) -> Elem when + Table :: table(), Key :: term(), Pos :: pos_integer(), Elem :: term() | [term()]. @@ -227,17 +232,27 @@ lookup(_, _) -> lookup_element(_, _, _) -> erlang:nif_error(undef). --spec match(Tab, Pattern) -> [Match] when - Tab :: tab(), +-spec lookup_element(Table, Key, Pos, Default) -> Elem when + Table :: table(), + Key :: term(), + Pos :: pos_integer(), + Default :: term(), + Elem :: term() | [term()]. + +lookup_element(_, _, _, _) -> + erlang:nif_error(undef). + +-spec match(Table, Pattern) -> [Match] when + Table :: table(), Pattern :: match_pattern(), Match :: [term()]. match(_, _) -> erlang:nif_error(undef). --spec match(Tab, Pattern, Limit) -> {[Match], Continuation} | +-spec match(Table, Pattern, Limit) -> {[Match], Continuation} | '$end_of_table' when - Tab :: tab(), + Table :: table(), Pattern :: match_pattern(), Limit :: pos_integer(), Match :: [term()], @@ -254,17 +269,17 @@ match(_, _, _) -> match(_) -> erlang:nif_error(undef). --spec match_object(Tab, Pattern) -> [Object] when - Tab :: tab(), +-spec match_object(Table, Pattern) -> [Object] when + Table :: table(), Pattern :: match_pattern(), Object :: tuple(). match_object(_, _) -> erlang:nif_error(undef). --spec match_object(Tab, Pattern, Limit) -> {[Object], Continuation} | +-spec match_object(Table, Pattern, Limit) -> {[Object], Continuation} | '$end_of_table' when - Tab :: tab(), + Table :: table(), Pattern :: match_pattern(), Limit :: pos_integer(), Object :: tuple(), @@ -283,33 +298,34 @@ match_object(_) -> -spec match_spec_compile(MatchSpec) -> CompiledMatchSpec when MatchSpec :: match_spec(), - CompiledMatchSpec :: comp_match_spec(). + CompiledMatchSpec :: compiled_match_spec(). match_spec_compile(_) -> erlang:nif_error(undef). -spec match_spec_run_r(List, CompiledMatchSpec, list()) -> list() when List :: [term()], - CompiledMatchSpec :: comp_match_spec(). + CompiledMatchSpec :: compiled_match_spec(). match_spec_run_r(_, _, _) -> erlang:nif_error(undef). --spec member(Tab, Key) -> boolean() when - Tab :: tab(), +-spec member(Table, Key) -> boolean() when + Table :: table(), Key :: term(). member(_, _) -> erlang:nif_error(undef). --spec new(Name, Options) -> tid() | atom() when +-spec new(Name, Options) -> table() when Name :: atom(), Options :: [Option], Option :: Type | Access | named_table | {keypos,Pos} | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks, - Type :: type(), - Access :: access(), - Tweaks :: {write_concurrency, boolean()} + Type :: table_type(), + Access :: table_access(), + WriteConcurrencyAlternative :: boolean() | auto, + Tweaks :: {write_concurrency, WriteConcurrencyAlternative} | {read_concurrency, boolean()} | {decentralized_counters, boolean()} | compressed, @@ -319,16 +335,16 @@ member(_, _) -> new(_, _) -> erlang:nif_error(undef). --spec next(Tab, Key1) -> Key2 | '$end_of_table' when - Tab :: tab(), +-spec next(Table, Key1) -> Key2 | '$end_of_table' when + Table :: table(), Key1 :: term(), Key2 :: term(). next(_, _) -> erlang:nif_error(undef). --spec prev(Tab, Key1) -> Key2 | '$end_of_table' when - Tab :: tab(), +-spec prev(Table, Key1) -> Key2 | '$end_of_table' when + Table :: table(), Key1 :: term(), Key2 :: term(). @@ -336,31 +352,31 @@ prev(_, _) -> erlang:nif_error(undef). %% Shadowed by erl_bif_types: ets:rename/2 --spec rename(Tab, Name) -> Name when - Tab :: tab(), +-spec rename(Table, Name) -> Name when + Table :: table(), Name :: atom(). rename(_, _) -> erlang:nif_error(undef). --spec safe_fixtable(Tab, Fix) -> true when - Tab :: tab(), +-spec safe_fixtable(Table, Fix) -> true when + Table :: table(), Fix :: boolean(). safe_fixtable(_, _) -> erlang:nif_error(undef). --spec select(Tab, MatchSpec) -> [Match] when - Tab :: tab(), +-spec select(Table, MatchSpec) -> [Match] when + Table :: table(), MatchSpec :: match_spec(), Match :: term(). select(_, _) -> erlang:nif_error(undef). --spec select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | +-spec select(Table, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table' when - Tab :: tab(), + Table :: table(), MatchSpec :: match_spec(), Limit :: pos_integer(), Match :: term(), @@ -376,51 +392,51 @@ select(_, _, _) -> select(_) -> erlang:nif_error(undef). --spec select_count(Tab, MatchSpec) -> NumMatched when - Tab :: tab(), +-spec select_count(Table, MatchSpec) -> NumMatched when + Table :: table(), MatchSpec :: match_spec(), NumMatched :: non_neg_integer(). select_count(_, _) -> erlang:nif_error(undef). --spec select_delete(Tab, MatchSpec) -> NumDeleted when - Tab :: tab(), +-spec select_delete(Table, MatchSpec) -> NumDeleted when + Table :: table(), MatchSpec :: match_spec(), NumDeleted :: non_neg_integer(). -select_delete(Tab, [{'_',[],[true]}]) -> - ets:internal_delete_all(Tab, undefined); -select_delete(Tab, MatchSpec) -> - ets:internal_select_delete(Tab, MatchSpec). +select_delete(Table, [{'_',[],[true]}]) -> + ets:internal_delete_all(Table, undefined); +select_delete(Table, MatchSpec) -> + ets:internal_select_delete(Table, MatchSpec). --spec internal_select_delete(Tab, MatchSpec) -> NumDeleted when - Tab :: tab(), +-spec internal_select_delete(Table, MatchSpec) -> NumDeleted when + Table :: table(), MatchSpec :: match_spec(), NumDeleted :: non_neg_integer(). internal_select_delete(_, _) -> erlang:nif_error(undef). --spec select_replace(Tab, MatchSpec) -> NumReplaced when - Tab :: tab(), +-spec select_replace(Table, MatchSpec) -> NumReplaced when + Table :: table(), MatchSpec :: match_spec(), NumReplaced :: non_neg_integer(). select_replace(_, _) -> erlang:nif_error(undef). --spec select_reverse(Tab, MatchSpec) -> [Match] when - Tab :: tab(), +-spec select_reverse(Table, MatchSpec) -> [Match] when + Table :: table(), MatchSpec :: match_spec(), Match :: term(). select_reverse(_, _) -> erlang:nif_error(undef). --spec select_reverse(Tab, MatchSpec, Limit) -> {[Match],Continuation} | +-spec select_reverse(Table, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table' when - Tab :: tab(), + Table :: table(), MatchSpec :: match_spec(), Limit :: pos_integer(), Match :: term(), @@ -437,8 +453,8 @@ select_reverse(_, _, _) -> select_reverse(_) -> erlang:nif_error(undef). --spec setopts(Tab, Opts) -> true when - Tab :: tab(), +-spec setopts(Table, Opts) -> true when + Table :: table(), Opts :: Opt | [Opt], Opt :: {heir, pid(), HeirData} | {heir,none}, HeirData :: term(). @@ -446,24 +462,24 @@ select_reverse(_) -> setopts(_, _) -> erlang:nif_error(undef). --spec slot(Tab, I) -> [Object] | '$end_of_table' when - Tab :: tab(), +-spec slot(Table, I) -> [Object] | '$end_of_table' when + Table :: table(), I :: non_neg_integer(), Object :: tuple(). slot(_, _) -> erlang:nif_error(undef). --spec take(Tab, Key) -> [Object] when - Tab :: tab(), +-spec take(Table, Key) -> [Object] when + Table :: table(), Key :: term(), Object :: tuple(). take(_, _) -> erlang:nif_error(undef). --spec update_counter(Tab, Key, UpdateOp) -> Result when - Tab :: tab(), +-spec update_counter(Table, Key, UpdateOp) -> Result when + Table :: table(), Key :: term(), UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, Pos :: integer(), @@ -471,8 +487,8 @@ take(_, _) -> Threshold :: integer(), SetValue :: integer(), Result :: integer(); - (Tab, Key, [UpdateOp]) -> [Result] when - Tab :: tab(), + (Table, Key, [UpdateOp]) -> [Result] when + Table :: table(), Key :: term(), UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, Pos :: integer(), @@ -480,8 +496,8 @@ take(_, _) -> Threshold :: integer(), SetValue :: integer(), Result :: integer(); - (Tab, Key, Incr) -> Result when - Tab :: tab(), + (Table, Key, Incr) -> Result when + Table :: table(), Key :: term(), Incr :: integer(), Result :: integer(). @@ -489,8 +505,8 @@ take(_, _) -> update_counter(_, _, _) -> erlang:nif_error(undef). --spec update_counter(Tab, Key, UpdateOp, Default) -> Result when - Tab :: tab(), +-spec update_counter(Table, Key, UpdateOp, Default) -> Result when + Table :: table(), Key :: term(), UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, @@ -500,8 +516,8 @@ update_counter(_, _, _) -> SetValue :: integer(), Result :: integer(), Default :: tuple(); - (Tab, Key, [UpdateOp], Default) -> [Result] when - Tab :: tab(), + (Table, Key, [UpdateOp], Default) -> [Result] when + Table :: table(), Key :: term(), UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, @@ -511,8 +527,8 @@ update_counter(_, _, _) -> SetValue :: integer(), Result :: integer(), Default :: tuple(); - (Tab, Key, Incr, Default) -> Result when - Tab :: tab(), + (Table, Key, Incr, Default) -> Result when + Table :: table(), Key :: term(), Incr :: integer(), Result :: integer(), @@ -521,13 +537,13 @@ update_counter(_, _, _) -> update_counter(_, _, _, _) -> erlang:nif_error(undef). --spec update_element(Tab, Key, ElementSpec :: {Pos, Value}) -> boolean() when - Tab :: tab(), +-spec update_element(Table, Key, ElementSpec :: {Pos, Value}) -> boolean() when + Table :: table(), Key :: term(), Pos :: pos_integer(), Value :: term(); - (Tab, Key, ElementSpec :: [{Pos, Value}]) -> boolean() when - Tab :: tab(), + (Table, Key, ElementSpec :: [{Pos, Value}]) -> boolean() when + Table :: table(), Key :: term(), Pos :: pos_integer(), Value :: term(). @@ -542,11 +558,12 @@ whereis(_) -> %%% End of BIFs --opaque comp_match_spec() :: reference(). +-opaque compiled_match_spec() :: reference(). +-type comp_match_spec() :: compiled_match_spec(). -spec match_spec_run(List, CompiledMatchSpec) -> list() when List :: [term()], - CompiledMatchSpec :: comp_match_spec(). + CompiledMatchSpec :: compiled_match_spec(). match_spec_run(List, CompiledMS) -> lists:reverse(ets:match_spec_run_r(List, CompiledMS, [])). @@ -613,9 +630,9 @@ fun2ms(ShellFun) when is_function(ShellFun) -> shell]}}) end. --spec foldl(Function, Acc0, Tab) -> Acc1 when +-spec foldl(Function, Acc0, Table) -> Acc1 when Function :: fun((Element :: term(), AccIn) -> AccOut), - Tab :: tab(), + Table :: table(), Acc0 :: term(), Acc1 :: term(), AccIn :: term(), @@ -640,9 +657,9 @@ do_foldl(F, Accu0, Key, T) -> ets:next(T, Key), T) end. --spec foldr(Function, Acc0, Tab) -> Acc1 when +-spec foldr(Function, Acc0, Table) -> Acc1 when Function :: fun((Element :: term(), AccIn) -> AccOut), - Tab :: tab(), + Table :: table(), Acc0 :: term(), Acc1 :: term(), AccIn :: term(), @@ -667,8 +684,8 @@ do_foldr(F, Accu0, Key, T) -> ets:prev(T, Key), T) end. --spec from_dets(Tab, DetsTab) -> 'true' when - Tab :: tab(), +-spec from_dets(Table, DetsTab) -> 'true' when + Table :: table(), DetsTab :: dets:tab_name(). from_dets(EtsTable, DetsTable) -> @@ -685,8 +702,8 @@ from_dets(EtsTable, DetsTable) -> erlang:error(Unexpected,[EtsTable,DetsTable]) end. --spec to_dets(Tab, DetsTab) -> DetsTab when - Tab :: tab(), +-spec to_dets(Table, DetsTab) -> DetsTab when + Table :: table(), DetsTab :: dets:tab_name(). to_dets(EtsTable, DetsTable) -> @@ -717,8 +734,8 @@ test_ms(Term, MS) -> Error end. --spec init_table(Tab, InitFun) -> 'true' when - Tab :: tab(), +-spec init_table(Table, InitFun) -> 'true' when + Table :: table(), InitFun :: fun((Arg) -> Res), Arg :: 'read' | 'close', Res :: 'end_of_input' | {Objects :: [term()], InitFun} | term(). @@ -746,8 +763,8 @@ init_table_sub(Table, [H|T]) -> ets:insert(Table, H), init_table_sub(Table, T). --spec match_delete(Tab, Pattern) -> 'true' when - Tab :: tab(), +-spec match_delete(Table, Pattern) -> 'true' when + Table :: table(), Pattern :: match_pattern(). match_delete(Table, Pattern) -> @@ -756,8 +773,8 @@ match_delete(Table, Pattern) -> %% Produce a list of tuples from a table --spec tab2list(Tab) -> [Object] when - Tab :: tab(), +-spec tab2list(Table) -> [Object] when + Table :: table(), Object :: tuple(). tab2list(T) -> @@ -780,23 +797,23 @@ tab2list(T) -> sync = false :: boolean() }). --spec tab2file(Tab, Filename) -> 'ok' | {'error', Reason} when - Tab :: tab(), +-spec tab2file(Table, Filename) -> 'ok' | {'error', Reason} when + Table :: table(), Filename :: file:name(), Reason :: term(). -tab2file(Tab, File) -> - tab2file(Tab, File, []). +tab2file(Table, File) -> + tab2file(Table, File, []). --spec tab2file(Tab, Filename, Options) -> 'ok' | {'error', Reason} when - Tab :: tab(), +-spec tab2file(Table, Filename, Options) -> 'ok' | {'error', Reason} when + Table :: table(), Filename :: file:name(), Options :: [Option], Option :: {'extended_info', [ExtInfo]} | {'sync', boolean()}, ExtInfo :: 'md5sum' | 'object_count', Reason :: term(). -tab2file(Tab, File, Options) -> +tab2file(Table, File, Options) -> try {ok, FtOptions} = parse_ft_options(Options), _ = file:delete(File), @@ -805,16 +822,17 @@ tab2file(Tab, File, Options) -> _ -> throw(eaccess) end, Name = make_ref(), - case disk_log:open([{name, Name}, {file, File}]) of + case disk_log:open([{name, Name}, {file, File}, + {repair, truncate}]) of {ok, Name} -> ok; {error, Reason} -> throw(Reason) end, try - Info0 = case ets:info(Tab) of + Info0 = case ets:info(Table) of undefined -> - %% erlang:error(badarg, [Tab, File, Options]); + %% erlang:error(badarg, [Table, File, Options]); throw(badtab); I -> I @@ -845,14 +863,14 @@ tab2file(Tab, File, Options) -> end, true} end, - ets:safe_fixtable(Tab,true), + ets:safe_fixtable(Table,true), {NewState1,Num} = try NewState = LogFun(InitState,Info), dump_file( - ets:select(Tab,[{'_',[],['$_']}],100), + ets:select(Table,[{'_',[],['$_']}],100), LogFun, NewState, 0) after - (catch ets:safe_fixtable(Tab,false)) + (catch ets:safe_fixtable(Table,false)) end, EndInfo = case FtOptions#filetab_options.object_count of @@ -967,24 +985,24 @@ parse_ft_info_options(_,Malformed) -> %% Opt := {verify,boolean()} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec file2tab(Filename) -> {'ok', Tab} | {'error', Reason} when +-spec file2tab(Filename) -> {'ok', Table} | {'error', Reason} when Filename :: file:name(), - Tab :: tab(), + Table :: table(), Reason :: term(). file2tab(File) -> file2tab(File, []). --spec file2tab(Filename, Options) -> {'ok', Tab} | {'error', Reason} when +-spec file2tab(Filename, Options) -> {'ok', Table} | {'error', Reason} when Filename :: file:name(), - Tab :: tab(), + Table :: table(), Options :: [Option], Option :: {'verify', boolean()}, Reason :: term(). file2tab(File, Opts) -> try - {ok,Verify,TabArg} = parse_f2t_opts(Opts,false,[]), + {ok,Verify,TableArg} = parse_f2t_opts(Opts,false,[]), Name = make_ref(), {ok, Name} = case disk_log:open([{name, Name}, @@ -1019,7 +1037,7 @@ file2tab(File, Opts) -> true -> ok end, - {ok, Tab, HeadCount} = create_tab(FullHeader, TabArg), + {ok, Table, HeadCount} = create_tab(FullHeader, TableArg), StrippedOptions = case Verify of true -> @@ -1061,17 +1079,17 @@ file2tab(File, Opts) -> {false,0,[],DLContext}} end, try - do_read_and_verify(ReadFun,InitState,Tab, + do_read_and_verify(ReadFun,InitState,Table, StrippedOptions,HeadCount,Verify) catch throw:TReason -> - ets:delete(Tab), + ets:delete(Table), throw(TReason); exit:ExReason -> - ets:delete(Tab), + ets:delete(Table), exit(ExReason); error:ErReason:StackTrace -> - ets:delete(Tab), + ets:delete(Table), erlang:raise(error,ErReason,StackTrace) end after @@ -1084,8 +1102,8 @@ file2tab(File, Opts) -> {error,ExReason2} end. -do_read_and_verify(ReadFun,InitState,Tab,FtOptions,HeadCount,Verify) -> - case load_table(ReadFun,InitState,Tab) of +do_read_and_verify(ReadFun,InitState,Table,FtOptions,HeadCount,Verify) -> + case load_table(ReadFun,InitState,Table) of {ok,{_,FinalCount,[],_}} -> case {FtOptions#filetab_options.md5sum, FtOptions#filetab_options.object_count} of @@ -1104,7 +1122,7 @@ do_read_and_verify(ReadFun,InitState,Tab,FtOptions,HeadCount,Verify) -> _ -> throw(badfile) end, - {ok,Tab}; + {ok,Table}; {ok,{FinalMD5State,FinalCount,['$end_of_table',LastInfo],_}} -> ECount = case lists:keyfind(count,1,LastInfo) of {count,N} -> @@ -1152,17 +1170,17 @@ do_read_and_verify(ReadFun,InitState,Tab,FtOptions,HeadCount,Verify) -> ok end end, - {ok,Tab} + {ok,Table} end. -parse_f2t_opts([],Verify,Tab) -> - {ok,Verify,Tab}; -parse_f2t_opts([{verify, true}|T],_OV,Tab) -> - parse_f2t_opts(T,true,Tab); -parse_f2t_opts([{verify,false}|T],OV,Tab) -> - parse_f2t_opts(T,OV,Tab); -parse_f2t_opts([{table,Tab}|T],OV,[]) -> - parse_f2t_opts(T,OV,Tab); +parse_f2t_opts([],Verify,Table) -> + {ok,Verify,Table}; +parse_f2t_opts([{verify, true}|T],_OV,Table) -> + parse_f2t_opts(T,true,Table); +parse_f2t_opts([{verify,false}|T],OV,Table) -> + parse_f2t_opts(T,OV,Table); +parse_f2t_opts([{table,Table}|T],OV,[]) -> + parse_f2t_opts(T,OV,Table); parse_f2t_opts([Unexpected|_],_,_) -> throw({unknown_option,Unexpected}); parse_f2t_opts(Malformed,_,_) -> @@ -1331,17 +1349,17 @@ scan_for_endinfo([Term|T], Count) -> {NewLast,NCount,Rest} = scan_for_endinfo(T, Count+1), {NewLast,NCount,[Term | Rest]}. -load_table(ReadFun, State, Tab) -> +load_table(ReadFun, State, Table) -> {NewState,NewData} = ReadFun(State), case NewData of [] -> {ok,NewState}; List -> - ets:insert(Tab, List), - load_table(ReadFun, NewState, Tab) + ets:insert(Table, List), + load_table(ReadFun, NewState, Table) end. -create_tab(I, TabArg) -> +create_tab(I, TableArg) -> {name, Name} = lists:keyfind(name, 1, I), {type, Type} = lists:keyfind(type, 1, I), {protection, P} = lists:keyfind(protection, 1, I), @@ -1365,16 +1383,16 @@ create_tab(I, TabArg) -> {read_concurrency, _}=Rcc -> [Rcc | L4]; false -> L4 end, - case TabArg of + case TableArg of [] -> try - Tab = ets:new(Name, L5), - {ok, Tab, Sz} + Table = ets:new(Name, L5), + {ok, Table, Sz} catch _:_ -> throw(cannot_create_table) end; _ -> - {ok, TabArg, Sz} + {ok, TableArg, Sz} end. @@ -1446,15 +1464,15 @@ tabfile_info(File) when is_list(File) ; is_atom(File) -> {error,ExReason} end. --spec table(Tab) -> QueryHandle when - Tab :: tab(), +-spec table(Table) -> QueryHandle when + Table :: table(), QueryHandle :: qlc:query_handle(). -table(Tab) -> - table(Tab, []). +table(Table) -> + table(Table, []). --spec table(Tab, Options) -> QueryHandle when - Tab :: tab(), +-spec table(Table, Options) -> QueryHandle when + Table :: table(), QueryHandle :: qlc:query_handle(), Options :: [Option] | Option, Option :: {'n_objects', NObjects} @@ -1463,25 +1481,25 @@ table(Tab) -> TraverseMethod :: 'first_next' | 'last_prev' | 'select' | {'select', MatchSpec :: match_spec()}. -table(Tab, Opts) -> +table(Table, Opts) -> case options(Opts, [traverse, n_objects]) of {badarg,_} -> - erlang:error(badarg, [Tab, Opts]); + erlang:error(badarg, [Table, Opts]); [[Traverse, NObjs], QlcOptions] -> TF = case Traverse of first_next -> - fun() -> qlc_next(Tab, ets:first(Tab)) end; + fun() -> qlc_next(Table, ets:first(Table)) end; last_prev -> - fun() -> qlc_prev(Tab, ets:last(Tab)) end; + fun() -> qlc_prev(Table, ets:last(Table)) end; select -> - fun(MS) -> qlc_select(ets:select(Tab, MS, NObjs)) end; + fun(MS) -> qlc_select(ets:select(Table, MS, NObjs)) end; {select, MS} -> - fun() -> qlc_select(ets:select(Tab, MS, NObjs)) end + fun() -> qlc_select(ets:select(Table, MS, NObjs)) end end, - PreFun = fun(_) -> ets:safe_fixtable(Tab, true) end, - PostFun = fun() -> ets:safe_fixtable(Tab, false) end, - InfoFun = fun(Tag) -> table_info(Tab, Tag) end, - KeyEquality = case ets:info(Tab, type) of + PreFun = fun(_) -> ets:safe_fixtable(Table, true) end, + PostFun = fun() -> ets:safe_fixtable(Table, false) end, + InfoFun = fun(Tag) -> table_info(Table, Tag) end, + KeyEquality = case ets:info(Table, type) of ordered_set -> '=='; _ -> '=:=' end, @@ -1491,28 +1509,28 @@ table(Tab, Opts) -> undefined; _ -> fun(_Pos, [K]) -> - ets:lookup(Tab, K); + ets:lookup(Table, K); (_Pos, Ks) -> - lists:flatmap(fun(K) -> ets:lookup(Tab, K) + lists:flatmap(fun(K) -> ets:lookup(Table, K) end, Ks) end end, FormatFun = fun({all, _NElements, _ElementFun}) -> - As = [Tab | [Opts || _ <- [[]], Opts =/= []]], + As = [Table | [Opts || _ <- [[]], Opts =/= []]], {?MODULE, table, As}; ({match_spec, MS}) -> {?MODULE, table, - [Tab, [{traverse, {select, MS}} | + [Table, [{traverse, {select, MS}} | listify(Opts)]]}; ({lookup, _KeyPos, [Value], _NElements, ElementFun}) -> io_lib:format("~w:lookup(~w, ~w)", - [?MODULE, Tab, ElementFun(Value)]); + [?MODULE, Table, ElementFun(Value)]); ({lookup, _KeyPos, Values, _NElements, ElementFun}) -> Vals = [ElementFun(V) || V <- Values], io_lib:format("lists:flatmap(fun(V) -> " "~w:lookup(~w, V) end, ~w)", - [?MODULE, Tab, Vals]) + [?MODULE, Table, Vals]) end, qlc:table(TF, [{pre_fun, PreFun}, {post_fun, PostFun}, {info_fun, InfoFun}, {format_fun, FormatFun}, @@ -1520,26 +1538,26 @@ table(Tab, Opts) -> {lookup_fun, LookupFun}] ++ QlcOptions) end. -table_info(Tab, num_of_objects) -> - ets:info(Tab, size); -table_info(Tab, keypos) -> - ets:info(Tab, keypos); -table_info(Tab, is_unique_objects) -> - ets:info(Tab, type) =/= duplicate_bag; -table_info(Tab, is_sorted_key) -> - ets:info(Tab, type) =:= ordered_set; -table_info(_Tab, _) -> +table_info(Table, num_of_objects) -> + ets:info(Table, size); +table_info(Table, keypos) -> + ets:info(Table, keypos); +table_info(Table, is_unique_objects) -> + ets:info(Table, type) =/= duplicate_bag; +table_info(Table, is_sorted_key) -> + ets:info(Table, type) =:= ordered_set; +table_info(_Table, _) -> undefined. -qlc_next(_Tab, '$end_of_table') -> +qlc_next(_Table, '$end_of_table') -> []; -qlc_next(Tab, Key) -> - ets:lookup(Tab, Key) ++ fun() -> qlc_next(Tab, ets:next(Tab, Key)) end. +qlc_next(Table, Key) -> + ets:lookup(Table, Key) ++ fun() -> qlc_next(Table, ets:next(Table, Key)) end. -qlc_prev(_Tab, '$end_of_table') -> +qlc_prev(_Table, '$end_of_table') -> []; -qlc_prev(Tab, Key) -> - ets:lookup(Tab, Key) ++ fun() -> qlc_prev(Tab, ets:prev(Tab, Key)) end. +qlc_prev(Table, Key) -> + ets:lookup(Table, Key) ++ fun() -> qlc_prev(Table, ets:prev(Table, Key)) end. qlc_select('$end_of_table') -> []; @@ -1604,20 +1622,20 @@ i() -> tabs() -> lists:sort(ets:all()). -prinfo(Tab) -> - case catch prinfo2(Tab) of +prinfo(Table) -> + case catch prinfo2(Table) of {'EXIT', _} -> - io:format("~-10s ... unreadable \n", [to_string(Tab)]); + io:format("~-10s ... unreadable \n", [to_string(Table)]); ok -> ok end. -prinfo2(Tab) -> - Name = ets:info(Tab, name), - Type = ets:info(Tab, type), - Size = ets:info(Tab, size), - Mem = ets:info(Tab, memory), - Owner = ets:info(Tab, owner), - hform(Tab, Name, Type, Size, Mem, is_reg(Owner)). +prinfo2(Table) -> + Name = ets:info(Table, name), + Type = ets:info(Table, type), + Size = ets:info(Table, size), + Mem = ets:info(Table, memory), + Owner = ets:info(Table, owner), + hform(Table, Name, Type, Size, Mem, is_reg(Owner)). is_reg(Owner) -> case process_info(Owner, registered_name) of @@ -1651,69 +1669,69 @@ to_string(X) -> lists:flatten(io_lib:format("~p", [X])). %% view a specific table --spec i(Tab) -> 'ok' when - Tab :: tab(). +-spec i(Table) -> 'ok' when + Table :: table(). -i(Tab) -> - i(Tab, 40). +i(Table) -> + i(Table, 40). --spec i(tab(), pos_integer()) -> 'ok'. +-spec i(table(), pos_integer()) -> 'ok'. -i(Tab, Height) -> - i(Tab, Height, 80). +i(Table, Height) -> + i(Table, Height, 80). --spec i(tab(), pos_integer(), pos_integer()) -> 'ok'. +-spec i(table(), pos_integer(), pos_integer()) -> 'ok'. -i(Tab, Height, Width) -> - First = ets:first(Tab), - display_items(Height, Width, Tab, First, 1, 1). +i(Table, Height, Width) -> + First = ets:first(Table), + display_items(Height, Width, Table, First, 1, 1). -display_items(Height, Width, Tab, '$end_of_table', Turn, Opos) -> +display_items(Height, Width, Table, '$end_of_table', Turn, Opos) -> P = 'EOT (q)uit (p)Digits (k)ill /Regexp -->', - choice(Height, Width, P, eot, Tab, '$end_of_table', Turn, Opos); -display_items(Height, Width, Tab, Key, Turn, Opos) when Turn < Height -> - do_display(Height, Width, Tab, Key, Turn, Opos); -display_items(Height, Width, Tab, Key, Turn, Opos) when Turn >= Height -> + choice(Height, Width, P, eot, Table, '$end_of_table', Turn, Opos); +display_items(Height, Width, Table, Key, Turn, Opos) when Turn < Height -> + do_display(Height, Width, Table, Key, Turn, Opos); +display_items(Height, Width, Table, Key, Turn, Opos) when Turn >= Height -> P = '(c)ontinue (q)uit (p)Digits (k)ill /Regexp -->', - choice(Height, Width, P, normal, Tab, Key, Turn, Opos). + choice(Height, Width, P, normal, Table, Key, Turn, Opos). -choice(Height, Width, P, Mode, Tab, Key, Turn, Opos) -> +choice(Height, Width, P, Mode, Table, Key, Turn, Opos) -> case get_line(P, "c\n") of "c\n" when Mode =:= normal -> - do_display(Height, Width, Tab, Key, 1, Opos); + do_display(Height, Width, Table, Key, 1, Opos); "c\n" when is_tuple(Mode), element(1, Mode) =:= re -> {re, Re} = Mode, - re_search(Height, Width, Tab, Key, Re, 1, Opos); + re_search(Height, Width, Table, Key, Re, 1, Opos); "q\n" -> ok; "k\n" -> - ets:delete(Tab), + ets:delete(Table), ok; [$p|Digs] -> catch case catch list_to_integer(nonl(Digs)) of {'EXIT', _} -> io:put_chars("Bad digits\n"); Number when Mode =:= normal -> - print_number(Tab, ets:first(Tab), Number); + print_number(Table, ets:first(Table), Number); Number when Mode =:= eot -> - print_number(Tab, ets:first(Tab), Number); + print_number(Table, ets:first(Table), Number); Number -> %% regexp {re, Re} = Mode, - print_re_num(Tab, ets:first(Tab), Number, Re) + print_re_num(Table, ets:first(Table), Number, Re) end, - choice(Height, Width, P, Mode, Tab, Key, Turn, Opos); + choice(Height, Width, P, Mode, Table, Key, Turn, Opos); [$/|Regexp] -> %% from regexp case re:compile(nonl(Regexp),[unicode]) of {ok,Re} -> - re_search(Height, Width, Tab, ets:first(Tab), Re, 1, 1); + re_search(Height, Width, Table, ets:first(Table), Re, 1, 1); {error,{ErrorString,_Pos}} -> io:format("~ts\n", [ErrorString]), - choice(Height, Width, P, Mode, Tab, Key, Turn, Opos) + choice(Height, Width, P, Mode, Table, Key, Turn, Opos) end; eof -> ok; _ -> - choice(Height, Width, P, Mode, Tab, Key, Turn, Opos) + choice(Height, Width, P, Mode, Table, Key, Turn, Opos) end. get_line(P, Default) -> @@ -1731,22 +1749,22 @@ line_string(Other) -> Other. nonl(S) -> string:trim(S, trailing, "$\n"). -print_number(Tab, Key, Num) -> - Os = ets:lookup(Tab, Key), +print_number(Table, Key, Num) -> + Os = ets:lookup(Table, Key), Len = length(Os), if (Num - Len) < 1 -> O = lists:nth(Num, Os), io:format("~p~n", [O]); %% use ppterm here instead true -> - print_number(Tab, ets:next(Tab, Key), Num - Len) + print_number(Table, ets:next(Table, Key), Num - Len) end. -do_display(Height, Width, Tab, Key, Turn, Opos) -> - Objs = ets:lookup(Tab, Key), +do_display(Height, Width, Table, Key, Turn, Opos) -> + Objs = ets:lookup(Table, Key), do_display_items(Height, Width, Objs, Opos), Len = length(Objs), - display_items(Height, Width, Tab, ets:next(Tab, Key), Turn+Len, Opos+Len). + display_items(Height, Width, Table, ets:next(Table, Key), Turn+Len, Opos+Len). do_display_items(Height, Width, [Obj|Tail], Opos) -> do_display_item(Height, Width, Obj, Opos), @@ -1764,37 +1782,37 @@ do_display_item(_Height, Width, I, Opos) -> end, io:format("<~-4w> ~s~n", [Opos,L2]). -re_search(Height, Width, Tab, '$end_of_table', Re, Turn, Opos) -> +re_search(Height, Width, Table, '$end_of_table', Re, Turn, Opos) -> P = 'EOT (q)uit (p)Digits (k)ill /Regexp -->', - choice(Height, Width, P, {re, Re}, Tab, '$end_of_table', Turn, Opos); -re_search(Height, Width, Tab, Key, Re, Turn, Opos) when Turn < Height -> - re_display(Height, Width, Tab, Key, ets:lookup(Tab, Key), Re, Turn, Opos); -re_search(Height, Width, Tab, Key, Re, Turn, Opos) -> + choice(Height, Width, P, {re, Re}, Table, '$end_of_table', Turn, Opos); +re_search(Height, Width, Table, Key, Re, Turn, Opos) when Turn < Height -> + re_display(Height, Width, Table, Key, ets:lookup(Table, Key), Re, Turn, Opos); +re_search(Height, Width, Table, Key, Re, Turn, Opos) -> P = '(c)ontinue (q)uit (p)Digits (k)ill /Regexp -->', - choice(Height, Width, P, {re, Re}, Tab, Key, Turn, Opos). + choice(Height, Width, P, {re, Re}, Table, Key, Turn, Opos). -re_display(Height, Width, Tab, Key, [], Re, Turn, Opos) -> - re_search(Height, Width, Tab, ets:next(Tab, Key), Re, Turn, Opos); -re_display(Height, Width, Tab, Key, [H|T], Re, Turn, Opos) -> +re_display(Height, Width, Table, Key, [], Re, Turn, Opos) -> + re_search(Height, Width, Table, ets:next(Table, Key), Re, Turn, Opos); +re_display(Height, Width, Table, Key, [H|T], Re, Turn, Opos) -> Str = to_string(H), case re:run(Str, Re, [{capture,none}]) of match -> do_display_item(Height, Width, H, Opos), - re_display(Height, Width, Tab, Key, T, Re, Turn+1, Opos+1); + re_display(Height, Width, Table, Key, T, Re, Turn+1, Opos+1); nomatch -> - re_display(Height, Width, Tab, Key, T, Re, Turn, Opos) + re_display(Height, Width, Table, Key, T, Re, Turn, Opos) end. print_re_num(_,'$end_of_table',_,_) -> ok; -print_re_num(Tab, Key, Num, Re) -> - Os = re_match(ets:lookup(Tab, Key), Re), +print_re_num(Table, Key, Num, Re) -> + Os = re_match(ets:lookup(Table, Key), Re), Len = length(Os), if (Num - Len) < 1 -> O = lists:nth(Num, Os), io:format("~p~n", [O]); %% use ppterm here instead true -> - print_re_num(Tab, ets:next(Tab, Key), Num - Len, Re) + print_re_num(Table, ets:next(Table, Key), Num - Len, Re) end. re_match([], _) -> []; diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl index 966bc6590258..b7c4d02ea518 100644 --- a/lib/stdlib/src/eval_bits.erl +++ b/lib/stdlib/src/eval_bits.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2020. All Rights Reserved. +%% Copyright Ericsson AB 1999-2022. 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. @@ -22,8 +22,8 @@ %% Avoid warning for local function error/1 clashing with autoimported BIF. -compile({no_auto_import,[error/1]}). --export([expr_grp/3,expr_grp/5,match_bits/6, - match_bits/7,bin_gen/6]). +-export([expr_grp/3,expr_grp/4,match_bits/6, + match_bits/7,bin_gen/6,bin_gen/7]). -define(STACKTRACE, element(2, erlang:process_info(self(), current_stacktrace))). @@ -40,11 +40,13 @@ %% lookup a variable in the bindings, or add a new binding %% %% @type field(). Represents a field in a "bin". +%% +%% @type errorfun(). A closure invoked in case of errors. %%% Part 1: expression evaluation (binary construction) %% @spec expr_grp(Fields::[field()], Bindings::bindings(), -%% EvalFun::evalfun(), term(), term()) -> +%% EvalFun::evalfun(), ErrorFun::errorfun()) -> %% {value, binary(), bindings()} %% %% @doc Returns a tuple with {value,Bin,Bs} where Bin is the binary @@ -52,29 +54,23 @@ %% contains the present bindings. This function can also throw an %% exception if the construction fails. -expr_grp(Fields, Bindings, EvalFun, [], _) -> - expr_grp(Fields, Bindings, EvalFun, <<>>); -expr_grp(Fields, Bindings, EvalFun, ListOfBits, _) -> - Bin = convert_list(ListOfBits), - expr_grp(Fields, Bindings, EvalFun, Bin). - -convert_list(List) -> - << <> || X <- List >>. +expr_grp(Fields, Bindings, EvalFun, ErrorFun) -> + expr_grp(Fields, Bindings, EvalFun, ErrorFun, <<>>). expr_grp(Fields, Bindings, EvalFun) -> - expr_grp(Fields, Bindings, EvalFun, <<>>). + expr_grp(Fields, Bindings, EvalFun, fun default_error/3, <<>>). -expr_grp(FS, Bs0, Ef, Acc) -> +expr_grp(FS, Bs0, EvalFun, ErrorFun, Acc) -> %% Separate the evaluation of values, sizes, and TLS:s from the %% creation of the binary in order to mimic compiled code when it %% comes to loops and failures. - {ListOfEvalField,Bs1} = expr_grp1(FS, Bs0, Ef, []), + {ListOfEvalField,Bs1} = expr_grp1(FS, Bs0, EvalFun, ErrorFun, [], 1), {value,create_binary(ListOfEvalField, Acc),Bs1}. -expr_grp1([Field | FS], Bs0, Ef, ListOfEvalField) -> - {EvalField,Bs} = eval_field(Field, Bs0, Ef), - expr_grp1(FS, Bs, Ef, [EvalField|ListOfEvalField]); -expr_grp1([], Bs, _Ef, ListOfFieldData) -> +expr_grp1([Field | FS], Bs0, EvalFun, ErrorFun, ListOfEvalField, Pos) -> + {EvalField,Bs} = eval_field(Field, Bs0, EvalFun, ErrorFun, Pos), + expr_grp1(FS, Bs, EvalFun, ErrorFun, [EvalField|ListOfEvalField], Pos + 1); +expr_grp1([], Bs, _EvalFun, _ErrorFun, ListOfFieldData, _Pos) -> {lists:reverse(ListOfFieldData),Bs}. create_binary([EvalField|ListOfEvalField], Acc) -> @@ -83,44 +79,54 @@ create_binary([EvalField|ListOfEvalField], Acc) -> create_binary([], Acc) -> Acc. -eval_field({bin_element, _, {string, _, S}, {integer,_,8}, [integer,{unit,1},unsigned,big]}, Bs0, _Fun) -> +eval_field({bin_element, _, {string, _, S}, {integer,_,8}, [integer,{unit,1},unsigned,big]}, Bs0, _Fun, _ErrorFun, _Pos) -> Latin1 = [C band 16#FF || C <- S], {fun() -> list_to_binary(Latin1) end,Bs0}; -eval_field({bin_element, _, {string, _, S}, default, default}, Bs0, _Fun) -> +eval_field({bin_element, _, {string, _, S}, default, default}, Bs0, _Fun, _ErrorFun, _Pos) -> Latin1 = [C band 16#FF || C <- S], {fun() ->list_to_binary(Latin1) end,Bs0}; -eval_field({bin_element, Anno, {string, _, S}, Size0, Options0}, Bs0, Fun) -> +eval_field({bin_element, Anno, {string, _, S}, Size0, Options0}, Bs0, Fun, ErrorFun, Pos) -> {Size1,[Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), {value,Size,Bs1} = Fun(Size1, Bs0), {fun() -> - Res = << <<(eval_exp_field1(C, Size, Unit, - Type, Endian, Sign))/bitstring>> || + Res = << <<(eval_exp_field1(Anno, C, Size, Unit, + Type, Endian, Sign, ErrorFun, Pos))/bitstring>> || C <- S >>, case S of "" -> % find errors also when the string is empty - _ = eval_exp_field1(0, Size, Unit, Type, Endian, Sign), + _ = eval_exp_field1(Anno, 0, Size, Unit, Type, Endian, Sign, ErrorFun, Pos), ok; _ -> ok end, Res end,Bs1}; -eval_field({bin_element,Anno,E,Size0,Options0}, Bs0, Fun) -> +eval_field({bin_element,Anno,E,Size0,Options0}, Bs0, Fun, ErrorFun, Pos) -> {value,V,Bs1} = Fun(E, Bs0), {Size1,[Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), {value,Size,Bs} = Fun(Size1, Bs1), - {fun() -> eval_exp_field1(V, Size, Unit, Type, Endian, Sign) end,Bs}. + {fun() -> eval_exp_field1(Anno, V, Size, Unit, Type, Endian, Sign, ErrorFun, Pos) end,Bs}. -eval_exp_field1(V, Size, Unit, Type, Endian, Sign) -> +eval_exp_field1(Anno, V, Size, Unit, Type, Endian, Sign, ErrorFun, Pos) -> try - eval_exp_field(V, Size, Unit, Type, Endian, Sign) + eval_exp_field(V, Size, Unit, Type, Endian, Sign) catch - error:system_limit -> - erlang:raise(error, system_limit, ?STACKTRACE); - error:_ -> - erlang:raise(error, badarg, ?STACKTRACE) + error:system_limit:Stacktrace -> + ErrorFun(Anno, system_limit, add_eval_pos_to_error_info(Stacktrace, Pos)); + error:_:Stacktrace -> + ErrorFun(Anno, badarg, add_eval_pos_to_error_info(Stacktrace, Pos)) + end. + +add_eval_pos_to_error_info([{Mod, Fun, Arity, Meta0} = Head, _Skip | Rest], Pos) -> + case lists:keytake(error_info, 1, Meta0) of + {value, {error_info, #{} = Info}, Meta1} -> + Meta2 = Meta1 ++ [{error_info, Info#{override_segment_position => Pos}}], + [{Mod, Fun, Arity, Meta2} | Rest]; + + _ -> + [Head | Rest] end. eval_exp_field(Val, Size, Unit, integer, little, signed) -> @@ -169,7 +175,8 @@ eval_exp_field(Val, Size, Unit, binary, _, _) -> %%% Part 2: matching in binary comprehensions %% @spec bin_gen(BinPattern::{bin,integer(),[field()]}, Bin::binary(), %% GlobalEnv::bindings(), LocalEnv::bindings(), -%% MatchFun::matchfun(), EvalFun::evalfun()) -> +%% MatchFun::matchfun(), EvalFun::evalfun(), +%% ErrorFun::errorfun()) -> %% {match, binary(), bindings()} | {nomatch, binary()} | done %% %% @doc Used to perform matching in a comprehension. If the match @@ -178,25 +185,28 @@ eval_exp_field(Val, Size, Unit, binary, _, _) -> %% If nothing remains of the binary the atom 'done' is returned. bin_gen({bin,_,Fs}, Bin, Bs0, BBs0, Mfun, Efun) -> - bin_gen(Fs, Bin, Bs0, BBs0, Mfun, Efun, true). + bin_gen(Fs, Bin, Bs0, BBs0, Mfun, Efun, fun default_error/3, true). + +bin_gen({bin,_,Fs}, Bin, Bs0, BBs0, Mfun, Efun, ErrorFun) -> + bin_gen(Fs, Bin, Bs0, BBs0, Mfun, Efun, ErrorFun, true). -bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, Flag) +bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, ErrorFun, Flag) when is_function(Mfun, 2), is_function(Efun, 2) -> - case bin_gen_field(F, Bin, Bs0, BBs0, Mfun, Efun) of + case bin_gen_field(F, Bin, Bs0, BBs0, Mfun, Efun, ErrorFun) of {match,Bs,BBs,Rest} -> - bin_gen(Fs, Rest, Bs, BBs, Mfun, Efun, Flag); + bin_gen(Fs, Rest, Bs, BBs, Mfun, Efun, ErrorFun, Flag); {nomatch,Rest} -> - bin_gen(Fs, Rest, Bs0, BBs0, Mfun, Efun, false); + bin_gen(Fs, Rest, Bs0, BBs0, Mfun, Efun, ErrorFun, false); done -> done end; -bin_gen([], Bin, Bs0, _BBs0, _Mfun, _Efun, true) -> +bin_gen([], Bin, Bs0, _BBs0, _Mfun, _Efun, _ErrorFun, true) -> {match, Bin, Bs0}; -bin_gen([], Bin, _Bs0, _BBs0, _Mfun, _Efun, false) -> +bin_gen([], Bin, _Bs0, _BBs0, _Mfun, _Efun, _ErrorFun, false) -> {nomatch, Bin}. bin_gen_field({bin_element,_,{string,_,S},default,default}, - Bin, Bs, BBs, _Mfun, _Efun) -> + Bin, Bs, BBs, _Mfun, _Efun, _ErrorFun) -> Bits = try list_to_binary(S) catch _:_ -> <<>> end, @@ -210,9 +220,9 @@ bin_gen_field({bin_element,_,{string,_,S},default,default}, done end; bin_gen_field({bin_element,Anno,{string,SAnno,S},Size0,Options0}, - Bin0, Bs0, BBs0, Mfun, Efun) -> + Bin0, Bs0, BBs0, Mfun, Efun, ErrorFun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), case catch Efun(Size1, BBs0) of {value, Size, _BBs} -> % F = fun(C, Bin, Bs, BBs) -> @@ -222,9 +232,9 @@ bin_gen_field({bin_element,Anno,{string,SAnno,S},Size0,Options0}, bin_gen_field_string(S, Bin0, Bs0, BBs0, F) end; bin_gen_field({bin_element,Anno,VE,Size0,Options0}, - Bin, Bs0, BBs0, Mfun, Efun) -> + Bin, Bs0, BBs0, Mfun, Efun, ErrorFun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), V = erl_eval:partial_eval(VE), NewV = coerce_to_float(V, Type), case catch Efun(Size1, BBs0) of @@ -264,41 +274,42 @@ bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun) -> %%% Part 3: binary pattern matching %% @spec match_bits(Fields::[field()], Bin::binary(), %% GlobalEnv::bindings(), LocalEnv::bindings(), -%% MatchFun::matchfun(),EvalFun::evalfun(), term()) -> -%% {match, bindings()} +%% MatchFun::matchfun(),EvalFun::evalfun(), +%% ErrorFun::errorfun()) -> +%% {match, bindings()} %% @doc Used to perform matching. If the match succeeds a new %% environment is returned. If the match have some syntactic or %% semantic problem which would have been caught at compile time this %% function throws 'invalid', if the matching fails for other reasons %% the function throws 'nomatch' -match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun, _) -> - match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun). +match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun) -> + match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun, fun default_error/3). -match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun) - when is_function(Mfun, 2), is_function(Efun, 2) -> - case catch match_bits_1(Fs, Bin, Bs0, BBs, Mfun, Efun) of +match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun, ErrorFun) + when is_function(Mfun, 2), is_function(Efun, 2), is_function(ErrorFun, 3) -> + case catch match_bits_1(Fs, Bin, Bs0, BBs, Mfun, Efun, ErrorFun) of {match,Bs} -> {match,Bs}; invalid -> throw(invalid); _Error -> throw(nomatch) end. -match_bits_1([], <<>>, Bs, _BBs, _Mfun, _Efun) -> +match_bits_1([], <<>>, Bs, _BBs, _Mfun, _Efun, _ErrorFun) -> {match,Bs}; -match_bits_1([F|Fs], Bits0, Bs0, BBs0, Mfun, Efun) -> - {Bs,BBs,Bits} = match_field_1(F, Bits0, Bs0, BBs0, Mfun, Efun), - match_bits_1(Fs, Bits, Bs, BBs, Mfun, Efun). +match_bits_1([F|Fs], Bits0, Bs0, BBs0, Mfun, Efun, ErrorFun) -> + {Bs,BBs,Bits} = match_field_1(F, Bits0, Bs0, BBs0, Mfun, Efun, ErrorFun), + match_bits_1(Fs, Bits, Bs, BBs, Mfun, Efun, ErrorFun). match_field_1({bin_element,_,{string,_,S},default,default}, - Bin, Bs, BBs, _Mfun, _Efun) -> + Bin, Bs, BBs, _Mfun, _Efun, _ErrorFun) -> Bits = list_to_binary(S), % fails if there are characters > 255 Size = byte_size(Bits), <> = Bin, {Bs,BBs,Rest}; match_field_1({bin_element,Anno,{string,SAnno,S},Size0,Options0}, - Bin0, Bs0, BBs0, Mfun, Efun) -> + Bin0, Bs0, BBs0, Mfun, Efun, ErrorFun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), Size2 = erl_eval:partial_eval(Size1), {value, Size, _BBs} = Efun(Size2, BBs0), F = fun(C, Bin, Bs, BBs) -> @@ -307,9 +318,9 @@ match_field_1({bin_element,Anno,{string,SAnno,S},Size0,Options0}, end, match_field_string(S, Bin0, Bs0, BBs0, F); match_field_1({bin_element,Anno,VE,Size0,Options0}, - Bin, Bs0, BBs0, Mfun, Efun) -> + Bin, Bs0, BBs0, Mfun, Efun, ErrorFun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = - make_bit_type(Anno, Size0, Options0), + make_bit_type(Anno, Size0, Options0, ErrorFun), V = erl_eval:partial_eval(VE), NewV = coerce_to_float(V, Type), Size2 = erl_eval:partial_eval(Size1), @@ -410,15 +421,18 @@ get_float(Bin, Size, big) -> {Val,Rest}. %% Identical to the one in sys_pre_expand. -make_bit_type(Anno, default, Type0) -> +make_bit_type(Anno, default, Type0, ErrorFun) -> case erl_bits:set_bit_type(default, Type0) of {ok,all,Bt} -> {{atom,Anno,all},erl_bits:as_list(Bt)}; {ok,undefined,Bt} -> {{atom,Anno,undefined},erl_bits:as_list(Bt)}; {ok,Size,Bt} -> {{integer,Anno,Size},erl_bits:as_list(Bt)}; - {error,Reason} -> erlang:raise(error, Reason, ?STACKTRACE) + {error,Reason} -> ErrorFun(Anno, Reason, ?STACKTRACE) end; -make_bit_type(_Anno, Size, Type0) -> %Size evaluates to an integer or 'all' +make_bit_type(Anno, Size, Type0, ErrorFun) -> %Size evaluates to an integer or 'all' case erl_bits:set_bit_type(Size, Type0) of {ok,Size,Bt} -> {Size,erl_bits:as_list(Bt)}; - {error,Reason} -> erlang:raise(error, Reason, ?STACKTRACE) + {error,Reason} -> ErrorFun(Anno, Reason, ?STACKTRACE) end. + +default_error(_Anno, Reason, Stacktrace) -> + erlang:raise(error, Reason, Stacktrace). diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl index 7f8c282a7901..8733fe160b75 100644 --- a/lib/stdlib/src/filelib.erl +++ b/lib/stdlib/src/filelib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -21,7 +21,7 @@ %% File utilities. -export([wildcard/1, wildcard/2, is_dir/1, is_file/1, is_regular/1]). --export([fold_files/5, last_modified/1, file_size/1, ensure_dir/1]). +-export([fold_files/5, last_modified/1, file_size/1, ensure_dir/1, ensure_path/1]). -export([wildcard/3, is_dir/2, is_file/2, is_regular/2]). -export([fold_files/6, last_modified/2, file_size/2]). -export([find_file/2, find_file/3, find_source/1, find_source/2, find_source/3]). @@ -218,6 +218,7 @@ do_file_size(File, Mod) -> 0 end. + %%---------------------------------------------------------------------- %% +type ensure_dir(X) -> ok | {error, Reason}. %% +type X = filename() | dirname() @@ -230,27 +231,37 @@ ensure_dir("/") -> ok; ensure_dir(F) -> Dir = filename:dirname(F), - case do_is_dir(Dir, file) of - true -> - ok; - false when Dir =:= F -> - %% Protect against infinite loop - {error,einval}; - false -> - _ = ensure_dir(Dir), - case file:make_dir(Dir) of - {error,eexist}=EExist -> - case do_is_dir(Dir, file) of - true -> - ok; - false -> - EExist - end; - Err -> - Err - end - end. + ensure_path(Dir). +-spec ensure_path(Path) -> 'ok' | {'error', Reason} when + Path :: dirname_all(), + Reason :: file:posix(). +ensure_path("/") -> + ok; + +ensure_path(Path) -> + case do_is_dir(Path, file) of + true -> + ok; + false -> + case filename:dirname(Path) of + Parent when Parent =:= Path -> + {error,einval}; + Parent -> + _ = ensure_path(Parent), + case file:make_dir(Path) of + {error,eexist}=EExist -> + case do_is_dir(Path, file) of + true -> + ok; + false -> + EExist + end; + Other -> + Other + end + end + end. %%% %%% Pattern matching using a compiled wildcard. @@ -646,6 +657,7 @@ default_search_rules() -> {".o", ".c", c_source_search_rules()}, {"", ".c", c_source_search_rules()}, {"", ".in", basic_source_search_rules()}, + {".beam", ".asn1", asn1_source_search_rules()}, %% plain old directory rules, backwards compatible {"", ""}] ++ erl_source_search_rules(). @@ -661,6 +673,9 @@ erl_source_search_rules() -> c_source_search_rules() -> [{"priv","c_src"}, {"priv","src"}, {"bin","c_src"}, {"bin","src"}, {"", "src"}]. +asn1_source_search_rules() -> + [{"ebin","src"},{"ebin","asn1"}]. + %% Looks for a file relative to a given directory -type find_file_rule() :: {ObjDirSuffix::string(), SrcDirSuffix::string()}. @@ -755,65 +770,65 @@ find_regular_file([File|Files]) -> Cwd :: filename_all(), SafeFilename :: filename_all(). +safe_relative_path(Path, "") -> + safe_relative_path(Path, "."); safe_relative_path(Path, Cwd) -> - case filename:pathtype(Path) of - relative -> safe_relative_path(filename:split(Path), Cwd, [], ""); - _ -> unsafe - end. - -safe_relative_path([], _Cwd, _PrevLinks, Acc) -> - Acc; - -safe_relative_path([Segment | Segments], Cwd, PrevLinks, Acc) -> - AccSegment = join(Acc, Segment), - case 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(filename:split(LinkPath), Cwd, [LinkPath | PrevLinks], Acc) of - unsafe -> unsafe; - NewAcc -> safe_relative_path(Segments, Cwd, [], NewAcc) - end - end; - {error, _} -> - safe_relative_path(Segments, Cwd, PrevLinks, SafeAccSegment) - end - end. - -join([], Path) -> Path; -join(Left, Right) -> filename:join(Left, Right). - -safe_relative_path(Path) -> - case filename:pathtype(Path) of + srp_path(filename:split(Path), + Cwd, + sets:new([{version, 2}]), + []). + +srp_path([], _Cwd, _Seen, []) -> + ""; +srp_path([], _Cwd, _Seen, Acc) -> + filename:join(Acc); +srp_path(["."|Segs], Cwd, Seen, Acc) -> + srp_path(Segs, Cwd, Seen, Acc); +srp_path([<<".">>|Segs], Cwd, Seen, Acc) -> + srp_path(Segs, Cwd, Seen, Acc); +srp_path([".."|_Segs], _Cwd, _Seen, []) -> + unsafe; +srp_path([".."|Segs], Cwd, Seen, [_|_]=Acc) -> + srp_path(Segs, Cwd, Seen, lists:droplast(Acc)); +srp_path([<<"..">>|_Segs], _Cwd, _Seen, []) -> + unsafe; +srp_path([<<"..">>|Segs], Cwd, Seen, [_|_]=Acc) -> + srp_path(Segs, Cwd, Seen, lists:droplast(Acc)); +srp_path([clear|Segs], Cwd, _Seen, Acc) -> + srp_path(Segs, Cwd, sets:new([{version, 2}]), Acc); +srp_path([Seg|_]=Segs, Cwd, Seen, Acc) -> + case filename:pathtype(Seg) of relative -> - Cs0 = filename:split(Path), - safe_relative_path_1(Cs0, []); + srp_segment(Segs, Cwd, Seen, Acc); _ -> 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)). +srp_segment([Seg|Segs], Cwd, Seen, Acc) -> + Path = filename:join([Cwd|Acc]), + case file:read_link(filename:join(Path, Seg)) of + {ok, LinkPath} -> + srp_link(Path, + LinkPath, + Segs, + Cwd, + Seen, + Acc); + {error, _} -> + srp_path(Segs, + Cwd, + Seen, + Acc++[Seg]) + end. -climb(_, []) -> - unsafe; -climb(T, [_|Acc]) -> - safe_relative_path_1(T, Acc). +srp_link(Path, LinkPath, Segs, Cwd, Seen, Acc) -> + FullLinkPath = filename:join(Path, LinkPath), + case sets:is_element(FullLinkPath, Seen) of + true -> + unsafe; + false -> + srp_path(filename:split(LinkPath)++[clear|Segs], + Cwd, + sets:add_element(FullLinkPath, Seen), + Acc) + end. diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl index 68b3f3200d65..fc8e8110a05a 100644 --- a/lib/stdlib/src/filename.erl +++ b/lib/stdlib/src/filename.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -20,7 +20,7 @@ -module(filename). -removed([{find_src,'_',"use filelib:find_source/1,3 instead"}]). --deprecated([{safe_relative_path,1,"use filelib:safe_relative_path/2 instead"}]). +-removed([{safe_relative_path,1,"use filelib:safe_relative_path/2 instead"}]). %% Purpose: Provides generic manipulation of filenames. %% @@ -69,8 +69,7 @@ -export([absname/1, absname/2, absname_join/2, basename/1, basename/2, dirname/1, extension/1, join/1, join/2, pathtype/1, - rootname/1, rootname/2, split/1, flatten/1, nativename/1, - safe_relative_path/1]). + rootname/1, rootname/2, split/1, flatten/1, nativename/1]). -export([basedir/2, basedir/3]). -export([validate/1]). @@ -79,8 +78,10 @@ -include_lib("kernel/include/file.hrl"). --define(IS_DRIVELETTER(Letter),(((Letter >= $A) andalso (Letter =< $Z)) orelse - ((Letter >= $a) andalso (Letter =< $z)))). +-define(IS_DRIVELETTER(Letter), + (is_integer(Letter) + andalso (($A =< Letter andalso Letter =< $Z) + orelse ($a =< Letter andalso Letter =< $z)))). %% Converts a relative filename to an absolute filename %% or the filename itself if it already is an absolute filename @@ -334,8 +335,7 @@ dirname([$/|Rest], Dir, File, Seps) -> dirname([DirSep|Rest], Dir, File, {DirSep,_}=Seps) when is_integer(DirSep) -> dirname(Rest, File++Dir, [$/], Seps); dirname([Dl,DrvSep|Rest], [], [], {_,DrvSep}=Seps) - when is_integer(DrvSep), ((($a =< Dl) and (Dl =< $z)) or - (($A =< Dl) and (Dl =< $Z))) -> + when is_integer(DrvSep), ?IS_DRIVELETTER(Dl) -> dirname(Rest, [DrvSep,Dl], [], Seps); dirname([Char|Rest], Dir, File, Seps) when is_integer(Char) -> dirname(Rest, Dir, [Char|File], Seps); @@ -758,7 +758,8 @@ win32_split([X, $\\|Rest]) when is_integer(X) -> win32_split([X, $/|Rest]); win32_split([X, Y, $\\|Rest]) when is_integer(X), is_integer(Y) -> win32_split([X, Y, $/|Rest]); -win32_split([UcLetter, $:|Rest]) when UcLetter >= $A, UcLetter =< $Z -> +win32_split([UcLetter, $:|Rest]) + when is_integer(UcLetter), $A =< UcLetter, UcLetter =< $Z -> win32_split([UcLetter+$a-$A, $:|Rest]); win32_split([Letter, $:, $/|Rest]) -> split(Rest, [], [[Letter, $:, $/]], win32); @@ -816,39 +817,6 @@ separators() -> _ -> {false, false} end. --spec safe_relative_path(Filename) -> 'unsafe' | SafeFilename when - Filename :: file:name_all(), - SafeFilename :: file:name_all(). - -safe_relative_path(Path) -> - case pathtype(Path) of - relative -> - Cs0 = 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) -> - join(lists:reverse(Acc)). - -climb(_, []) -> - unsafe; -climb(T, [_|Acc]) -> - safe_relative_path_1(T, Acc). - major_os_type() -> {OsT, _} = os:type(), OsT. diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl index 6d6f7d40acb3..aba1bed15639 100644 --- a/lib/stdlib/src/gb_sets.erl +++ b/lib/stdlib/src/gb_sets.erl @@ -205,13 +205,13 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec empty() -> Set when - Set :: set(). + Set :: set(none()). empty() -> {0, nil}. -spec new() -> Set when - Set :: set(). + Set :: set(none()). new() -> empty(). @@ -259,13 +259,13 @@ is_member_1(_, nil) -> Set1 :: set(Element), Set2 :: set(Element). -insert(Key, {S, T}) -> +insert(Key, {S, T}) when is_integer(S), S >= 0 -> S1 = S + 1, {S1, insert_1(Key, T, ?pow(S1, ?p))}. insert_1(Key, {Key1, Smaller, Bigger}, S) when Key < Key1 -> case insert_1(Key, Smaller, ?div2(S)) of - {T1, H1, S1} when is_integer(H1) -> + {T1, H1, S1} when is_integer(H1), is_integer(S1) -> T = {Key1, T1, Bigger}, {H2, S2} = count(Bigger), H = ?mul2(erlang:max(H1, H2)), @@ -282,7 +282,7 @@ insert_1(Key, {Key1, Smaller, Bigger}, S) when Key < Key1 -> end; insert_1(Key, {Key1, Smaller, Bigger}, S) when Key > Key1 -> case insert_1(Key, Bigger, ?div2(S)) of - {T1, H1, S1} when is_integer(H1) -> + {T1, H1, S1} when is_integer(H1), is_integer(S1) -> T = {Key1, Smaller, T1}, {H2, S2} = count(Smaller), H = ?mul2(erlang:max(H1, H2)), @@ -317,7 +317,7 @@ count(nil) -> Set1 :: set(Element), Set2 :: set(Element). -balance({S, T}) -> +balance({S, T}) when is_integer(S), S >= 0 -> {S, balance(T, S)}. balance(T, S) -> @@ -550,9 +550,9 @@ next([]) -> Set2 :: set(Element), Set3 :: set(Element). -union({N1, T1}, {N2, T2}) when N2 < N1 -> +union({N1, T1}, {N2, T2}) when is_integer(N1), is_integer(N2), N2 < N1 -> union(to_list_1(T2), N2, T1, N1); -union({N1, T1}, {N2, T2}) -> +union({N1, T1}, {N2, T2}) when is_integer(N1), is_integer(N2) -> union(to_list_1(T1), N1, T2, N2). %% We avoid the expensive mathematical computations if there is little @@ -633,7 +633,7 @@ push([X | Xs], As) -> push([], As) -> As. -balance_revlist(L, S) -> +balance_revlist(L, S) when is_integer(S) -> {T, _} = balance_revlist_1(L, S), T. @@ -670,9 +670,9 @@ union_list(S, []) -> S. Set2 :: set(Element), Set3 :: set(Element). -intersection({N1, T1}, {N2, T2}) when N2 < N1 -> +intersection({N1, T1}, {N2, T2}) when is_integer(N1), is_integer(N2), N2 < N1 -> intersection(to_list_1(T2), N2, T1, N1); -intersection({N1, T1}, {N2, T2}) -> +intersection({N1, T1}, {N2, T2}) when is_integer(N1), is_integer(N2) -> intersection(to_list_1(T1), N1, T2, N2). intersection(L, _N1, T2, N2) when N2 < 10 -> @@ -770,7 +770,8 @@ subtract(S1, S2) -> Set2 :: set(Element), Set3 :: set(Element). -difference({N1, T1}, {N2, T2}) -> +difference({N1, T1}, {N2, T2}) when is_integer(N1), N1 >= 0, + is_integer(N2), N2 >= 0 -> difference(to_list_1(T1), N1, T2, N2). difference(L, N1, T2, N2) when N2 < 10 -> @@ -820,7 +821,8 @@ difference_2(Xs, [], As, S) -> Set1 :: set(Element), Set2 :: set(Element). -is_subset({N1, T1}, {N2, T2}) -> +is_subset({N1, T1}, {N2, T2}) when is_integer(N1), N1 >= 0, + is_integer(N2), N2 >= 0 -> is_subset(to_list_1(T1), N1, T2, N2). is_subset(L, _N1, T2, N2) when N2 < 10 -> @@ -871,7 +873,7 @@ is_set(_) -> false. Set1 :: set(Element), Set2 :: set(Element). -filter(F, S) -> +filter(F, S) when is_function(F, 1) -> from_ordset([X || X <- to_list(S), F(X)]). -spec fold(Function, Acc0, Set) -> Acc1 when diff --git a/lib/stdlib/src/gb_trees.erl b/lib/stdlib/src/gb_trees.erl index c0cdde012efa..54a5ab6690ed 100644 --- a/lib/stdlib/src/gb_trees.erl +++ b/lib/stdlib/src/gb_trees.erl @@ -169,7 +169,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec empty() -> tree(). +-spec empty() -> tree(none(), none()). empty() -> {0, nil}. @@ -279,7 +279,7 @@ insert(Key, Val, {S, T}) when is_integer(S) -> insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key < Key1 -> case insert_1(Key, Value, Smaller, ?div2(S)) of - {T1, H1, S1} -> + {T1, H1, S1} when is_integer(H1), is_integer(S1) -> T = {Key1, V, T1, Bigger}, {H2, S2} = count(Bigger), H = ?mul2(erlang:max(H1, H2)), @@ -296,7 +296,7 @@ insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key < Key1 -> end; insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key > Key1 -> case insert_1(Key, Value, Bigger, ?div2(S)) of - {T1, H1, S1} -> + {T1, H1, S1} when is_integer(H1), is_integer(S1) -> T = {Key1, V, Smaller, T1}, {H2, S2} = count(Smaller), H = ?mul2(erlang:max(H1, H2)), @@ -349,7 +349,7 @@ count(nil) -> Tree1 :: tree(Key, Value), Tree2 :: tree(Key, Value). -balance({S, T}) -> +balance({S, T}) when is_integer(S), S >= 0 -> {S, balance(T, S)}. balance(T, S) -> diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 9a7ccaa3123c..d03ca78e7cdd 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -29,37 +29,60 @@ -export([start/5, start/6, debug_options/2, hibernate_after/1, name/1, unregister_name/1, get_proc_name/1, get_parent/0, call/3, call/4, reply/2, - send_request/3, wait_response/2, - receive_response/2, check_response/2, + send_request/3, send_request/5, + wait_response/2, receive_response/2, check_response/2, + wait_response/3, receive_response/3, check_response/3, + reqids_new/0, reqids_size/1, + reqids_add/3, reqids_to_list/1, stop/1, stop/3]). -export([init_it/6, init_it/7]). --export([format_status_header/2]). +-export([format_status_header/2, format_status/4]). +-export(['@wait_response_recv_opt'/3]). + +-define(MAX_INT_TIMEOUT, 4294967295). -define(default_timeout, 5000). +-include("logger.hrl"). + %%----------------------------------------------------------------- +-export_type([reply_tag/0, + request_id/0, + request_id_collection/0]). + -type linkage() :: 'monitor' | 'link' | 'nolink'. -type emgr_name() :: {'local', atom()} | {'global', term()} | {'via', Module :: module(), Name :: term()}. --type start_ret() :: {'ok', pid()} | {'ok', {pid(), reference()}} | 'ignore' | {'error', term()}. +-type start_ret() :: {'ok', pid()} + | {'ok', {pid(), reference()}} + | 'ignore' + | {'error', term()}. --type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug' - | {'logfile', string()}. -type option() :: {'timeout', timeout()} - | {'debug', [debug_flag()]} + | {'debug', [sys:debug_option()]} | {'hibernate_after', timeout()} | {'spawn_opt', [proc_lib:spawn_option()]}. --type options() :: [option()]. -type server_ref() :: pid() | atom() | {atom(), node()} | {global, term()} | {via, module(), term()}. --type request_id() :: term(). +-opaque reply_tag() :: % As accepted by reply/2 + reference() + | nonempty_improper_list('alias', reference()) + | nonempty_improper_list( + nonempty_improper_list('alias', reference()), term()). + +-opaque request_id() :: reference(). + +-opaque request_id_collection() :: map(). + +-type response_timeout() :: + 0..?MAX_INT_TIMEOUT | 'infinity' | {abs, integer()}. %%----------------------------------------------------------------- %% Starts a generic process. @@ -77,7 +100,7 @@ %% The 'already_started' is returned only if Name is given %%----------------------------------------------------------------- --spec start(module(), linkage(), emgr_name(), module(), term(), options()) -> +-spec start(module(), linkage(), emgr_name(), module(), term(), [option()]) -> start_ret(). start(GenMod, LinkP, Name, Mod, Args, Options) -> @@ -88,7 +111,7 @@ start(GenMod, LinkP, Name, Mod, Args, Options) -> {error, {already_started, Pid}} end. --spec start(module(), linkage(), module(), term(), options()) -> start_ret(). +-spec start(module(), linkage(), module(), term(), [option()]) -> start_ret(). start(GenMod, LinkP, Mod, Args, Options) -> do_spawn(GenMod, LinkP, Mod, Args, Options). @@ -172,7 +195,8 @@ init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) -> true -> init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options); {false, Pid} -> - proc_lib:init_ack(Starter, {error, {already_started, Pid}}) + proc_lib:init_fail( + Starter, {error, {already_started, Pid}}, {exit, normal}) end. init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) -> @@ -201,6 +225,8 @@ call(Process, Label, Request, Timeout) -dialyzer({no_improper_lists, do_call/4}). +do_call(Process, _Label, _Request, _Timeout) when Process =:= self() -> + exit(calling_self); do_call(Process, Label, Request, infinity) when (is_pid(Process) andalso (node(Process) == node())) @@ -263,11 +289,12 @@ get_node(Process) -> node(Process) end. --spec send_request(Name::server_ref(), Label::term(), Request::term()) -> request_id(). -send_request(Process, Label, Request) when is_pid(Process) -> - do_send_request(Process, Label, Request); -send_request(Process, Label, Request) -> - Fun = fun(Pid) -> do_send_request(Pid, Label, Request) end, +-spec send_request(Name::server_ref(), Tag::term(), Request::term()) -> + request_id(). +send_request(Process, Tag, Request) when is_pid(Process) -> + do_send_request(Process, Tag, Request); +send_request(Process, Tag, Request) -> + Fun = fun(Pid) -> do_send_request(Pid, Tag, Request) end, try do_for_proc(Process, Fun) catch exit:Reason -> %% Make send_request async and fake a down message @@ -276,62 +303,243 @@ send_request(Process, Label, Request) -> Mref end. +-spec send_request(Name::server_ref(), Tag::term(), Request::term(), + Label::term(), ReqIdCol::request_id_collection()) -> + request_id_collection(). +send_request(Process, Tag, Request, Label, ReqIdCol) when is_map(ReqIdCol) -> + maps:put(send_request(Process, Tag, Request), Label, ReqIdCol). + -dialyzer({no_improper_lists, do_send_request/3}). -do_send_request(Process, Label, Request) -> - Mref = erlang:monitor(process, Process, [{alias, demonitor}]), - erlang:send(Process, {Label, {self(), [alias|Mref]}, Request}, [noconnect]), - Mref. +do_send_request(Process, Tag, Request) -> + ReqId = erlang:monitor(process, Process, [{alias, demonitor}]), + _ = erlang:send(Process, {Tag, {self(), [alias|ReqId]}, Request}, [noconnect]), + ReqId. + +-spec '@wait_response_recv_opt'(term(), term(), term()) -> ok. +'@wait_response_recv_opt'(Process, Tag, Request) -> + %% Enables reference optimization in wait_response/2 and + %% receive_response/2 + %% + %% This never actually runs and is only used to trigger the optimization, + %% see the module comment in beam_ssa_recv for details. + _ = wait_response(send_request(Process, Tag, Request), infinity), + _ = receive_response(send_request(Process, Tag, Request), infinity), + ok. %% %% Wait for a reply to the client. %% Note: if timeout is returned monitors are kept. --spec wait_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. -wait_response(Mref, Timeout) when is_reference(Mref) -> +-spec wait_response(ReqId, Timeout) -> Result when + ReqId :: request_id(), + Timeout :: response_timeout(), + Resp :: {reply, Reply::term()} | {error, {Reason::term(), server_ref()}}, + Result :: Resp | 'timeout'. + +wait_response(ReqId, Timeout) -> + TMO = timeout_value(Timeout), receive - {[alias|Mref], Reply} -> - erlang:demonitor(Mref, [flush]), + {[alias|ReqId], Reply} -> + erlang:demonitor(ReqId, [flush]), {reply, Reply}; - {'DOWN', Mref, _, Object, Reason} -> + {'DOWN', ReqId, _, Object, Reason} -> {error, {Reason, Object}} - after Timeout -> + after TMO -> timeout end. --spec receive_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. -receive_response(Mref, Timeout) when is_reference(Mref) -> +-spec wait_response(ReqIdCol, Timeout, Delete) -> Result when + ReqIdCol :: request_id_collection(), + Timeout :: response_timeout(), + Delete :: boolean(), + Resp :: {reply, Reply::term()} | {error, {Reason::term(), server_ref()}}, + Result :: {Resp, Label::term(), NewReqIdCol::request_id_collection()} | + 'no_request' | 'timeout'. + +wait_response(ReqIdCol, Timeout, Delete) when map_size(ReqIdCol) == 0, + is_boolean(Delete) -> + _ = timeout_value(Timeout), + no_request; +wait_response(ReqIdCol, Timeout, Delete) when is_map(ReqIdCol), + is_boolean(Delete) -> + TMO = timeout_value(Timeout), receive - {[alias|Mref], Reply} -> - erlang:demonitor(Mref, [flush]), + {[alias|ReqId], _} = Msg when is_map_key(ReqId, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete); + {'DOWN', ReqId, _, _, _} = Msg when is_map_key(ReqId, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete) + after TMO -> + timeout + end. + +-spec receive_response(ReqId, Timeout) -> Result when + ReqId :: request_id(), + Timeout :: response_timeout(), + Resp :: {reply, Reply::term()} | {error, {Reason::term(), server_ref()}}, + Result :: Resp | 'timeout'. + +receive_response(ReqId, Timeout) -> + TMO = timeout_value(Timeout), + receive + {[alias|ReqId], Reply} -> + erlang:demonitor(ReqId, [flush]), {reply, Reply}; - {'DOWN', Mref, _, Object, Reason} -> + {'DOWN', ReqId, _, Object, Reason} -> {error, {Reason, Object}} - after Timeout -> - erlang:demonitor(Mref, [flush]), + after TMO -> + erlang:demonitor(ReqId, [flush]), receive - {[alias|Mref], Reply} -> + {[alias|ReqId], Reply} -> {reply, Reply} after 0 -> timeout end end. --spec check_response(RequestId::term(), Key::request_id()) -> - {reply, Reply::term()} | 'no_reply' | {error, {term(), server_ref()}}. -check_response(Msg, Mref) when is_reference(Mref) -> +-spec receive_response(ReqIdCol, Timeout, Delete) -> Result when + ReqIdCol :: request_id_collection(), + Timeout :: response_timeout(), + Delete :: boolean(), + Resp :: {reply, Reply::term()} | {error, {Reason::term(), server_ref()}}, + Result :: {Resp, Label::term(), NewReqIdCol::request_id_collection()} + | 'no_request' | 'timeout'. + +receive_response(ReqIdCol, Timeout, Delete) when map_size(ReqIdCol) == 0, + is_boolean(Delete) -> + _ = timeout_value(Timeout), + no_request; +receive_response(ReqIdCol, Timeout, Delete) when is_map(ReqIdCol), + is_boolean(Delete) -> + TMO = timeout_value(Timeout), + receive + {[alias|ReqId], _} = Msg when is_map_key(ReqId, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete); + {'DOWN', Mref, _, _, _} = Msg when is_map_key(Mref, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete) + after TMO -> + maps:foreach(fun (ReqId, _Label) when is_reference(ReqId) -> + erlang:demonitor(ReqId, [flush]); + (_, _) -> + error(badarg) + end, ReqIdCol), + flush_responses(ReqIdCol), + timeout + end. + +-spec check_response(Msg::term(), ReqIdOrReqIdCol) -> Result when + ReqIdOrReqIdCol :: request_id() | request_id_collection(), + ReqIdResp :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + ReqIdColResp :: {{reply, Reply::term()}, Label::term()} | + {{error, {Reason::term(), server_ref()}}, Label::term()}, + Result :: ReqIdResp | ReqIdColResp | 'no_reply'. + +check_response(Msg, ReqId) when is_reference(ReqId) -> case Msg of - {[alias|Mref], Reply} -> - erlang:demonitor(Mref, [flush]), + {[alias|ReqId], Reply} -> + erlang:demonitor(ReqId, [flush]), {reply, Reply}; - {'DOWN', Mref, _, Object, Reason} -> + {'DOWN', ReqId, _, Object, Reason} -> {error, {Reason, Object}}; _ -> no_reply + end; +check_response(_, _) -> + error(badarg). + +-spec check_response(Msg, ReqIdCol, Delete) -> Result when + Msg :: term(), + ReqIdCol :: request_id_collection(), + Delete :: boolean(), + Resp :: {reply, Reply::term()} | {error, {Reason::term(), server_ref()}}, + Result :: {Resp, Label::term(), NewReqIdCol::request_id_collection()} + | 'no_request' | 'no_reply'. + +check_response(_Msg, ReqIdCol, Delete) when map_size(ReqIdCol) == 0, + is_boolean(Delete) -> + no_request; +check_response(Msg, ReqIdCol, Delete) when is_map(ReqIdCol), + is_boolean(Delete) -> + case Msg of + {[alias|ReqId], _} = Msg when is_map_key(ReqId, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete); + {'DOWN', Mref, _, _, _} = Msg when is_map_key(Mref, ReqIdCol) -> + collection_result(Msg, ReqIdCol, Delete); + _ -> + no_reply end. +collection_result({[alias|ReqId], Reply}, ReqIdCol, Delete) -> + _ = erlang:demonitor(ReqId, [flush]), + collection_result({reply, Reply}, ReqId, ReqIdCol, Delete); +collection_result({'DOWN', ReqId, _, Object, Reason}, ReqIdCol, Delete) -> + collection_result({error, {Reason, Object}}, ReqId, ReqIdCol, Delete). + +collection_result(Resp, ReqId, ReqIdCol, false) -> + {Resp, maps:get(ReqId, ReqIdCol), ReqIdCol}; +collection_result(Resp, ReqId, ReqIdCol, true) -> + {Label, NewReqIdCol} = maps:take(ReqId, ReqIdCol), + {Resp, Label, NewReqIdCol}. + +flush_responses(ReqIdCol) -> + receive + {[alias|Mref], _Reply} when is_map_key(Mref, ReqIdCol) -> + flush_responses(ReqIdCol) + after 0 -> + ok + end. + +timeout_value(infinity) -> + infinity; +timeout_value(Timeout) when 0 =< Timeout, Timeout =< ?MAX_INT_TIMEOUT -> + Timeout; +timeout_value({abs, Timeout}) when is_integer(Timeout) -> + case Timeout - erlang:monotonic_time(millisecond) of + TMO when TMO < 0 -> + 0; + TMO when TMO > ?MAX_INT_TIMEOUT -> + error(badarg); + TMO -> + TMO + end; +timeout_value(_) -> + error(badarg). + +-spec reqids_new() -> + NewReqIdCol::request_id_collection(). + +reqids_new() -> + maps:new(). + +-spec reqids_size(request_id_collection()) -> + non_neg_integer(). +reqids_size(ReqIdCol) when is_map(ReqIdCol) -> + maps:size(ReqIdCol); +reqids_size(_) -> + error(badarg). + +-spec reqids_add(ReqId::request_id(), Label::term(), + ReqIdCol::request_id_collection()) -> + NewReqIdCol::request_id_collection(). + +reqids_add(ReqId, _, ReqIdCol) when is_reference(ReqId), + is_map_key(ReqId, ReqIdCol) -> + error(badarg); +reqids_add(ReqId, Label, ReqIdCol) when is_reference(ReqId), + is_map(ReqIdCol) -> + maps:put(ReqId, Label, ReqIdCol); +reqids_add(_, _, _) -> + error(badarg). + +-spec reqids_to_list(ReqIdCol::request_id_collection()) -> + [{ReqId::request_id(), Label::term()}]. + +reqids_to_list(ReqIdCol) when is_map(ReqIdCol) -> + maps:to_list(ReqIdCol); +reqids_to_list(_) -> + error(badarg). + %% %% Send a reply to the client. %% @@ -546,3 +754,41 @@ format_status_header(TagLine, RegName) when is_atom(RegName) -> lists:concat([TagLine, " ", RegName]); format_status_header(TagLine, Name) -> {TagLine, Name}. + +-spec format_status(Mod :: module(), Opt :: terminate | normal, Status, Args) -> + ReturnStatus when + Status :: #{ atom() => term() }, + ReturnStatus :: #{ atom() => term(), '$status' => term()}, + Args :: list(term()) | undefined. +format_status(Mod, Opt, Status, Args) -> + case {erlang:function_exported(Mod, format_status, 1), + erlang:function_exported(Mod, format_status, 2)} of + {true, _} -> + try Mod:format_status(Status) of + NewStatus when is_map(NewStatus) -> + MergedStatus = maps:merge(Status, NewStatus), + case maps:size(MergedStatus) =:= maps:size(NewStatus) of + true -> + MergedStatus; + false -> + Status#{ 'EXIT' => atom_to_list(Mod) ++ ":format_status/1 returned a map with unknown keys" } + end; + _ -> + Status#{ 'EXIT' => atom_to_list(Mod) ++ ":format_status/1 did not return a map" } + catch + _:_ -> + Status#{ 'EXIT' => atom_to_list(Mod) ++ ":format_status/1 crashed" } + end; + {false, true} when is_list(Args) -> + try Mod:format_status(Opt, Args) of + Result -> + Status#{ '$status' => Result } + catch + throw:Result -> + Status#{ '$status' => Result }; + _:_ -> + Status#{ 'EXIT' => atom_to_list(Mod) ++ ":format_status/2 crashed" } + end; + {false, _} -> + Status + end. diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index 17b914e5daec..fd4b5d9add91 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -43,7 +43,11 @@ notify/2, sync_notify/2, add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3, swap_sup_handler/3, which_handlers/1, call/3, call/4, - send_request/3, wait_response/2, receive_response/2, check_response/2, + send_request/3, send_request/5, + wait_response/2, receive_response/2, check_response/2, + wait_response/3, receive_response/3, check_response/3, + reqids_new/0, reqids_size/1, + reqids_add/3, reqids_to_list/1, wake_hib/5]). -export([init_it/6, @@ -58,7 +62,8 @@ -export([format_log/1, format_log/2]). -export_type([handler/0, handler_args/0, add_handler_ret/0, - del_handler_ret/0]). + del_handler_ret/0, request_id/0, request_id_collection/0, + format_status/0]). -record(handler, {module :: atom(), id = false, @@ -118,9 +123,17 @@ PDict :: [{Key :: term(), Value :: term()}], State :: term(), Status :: term(). +-type format_status() :: + #{ state => term(), + message => term(), + reason => term(), + log => [sys:system_event()] }. +-callback format_status(Status) -> NewStatus when + Status :: format_status(), + NewStatus :: format_status(). -optional_callbacks( - [handle_info/2, terminate/2, code_change/3, format_status/2]). + [handle_info/2, terminate/2, code_change/3, format_status/1, format_status/2]). %%--------------------------------------------------------------------------- @@ -141,7 +154,13 @@ | {'via', atom(), term()} | pid(). -type start_ret() :: {'ok', pid()} | {'error', term()}. -type start_mon_ret() :: {'ok', {pid(),reference()}} | {'error', term()}. --type request_id() :: term(). + +-opaque request_id() :: gen:request_id(). + +-opaque request_id_collection() :: gen:request_id_collection(). + +-type response_timeout() :: + timeout() | {abs, integer()}. %%--------------------------------------------------------------------------- @@ -236,32 +255,182 @@ call(M, Handler, Query) -> call1(M, Handler, Query). -spec call(emgr_ref(), handler(), term(), timeout()) -> term(). call(M, Handler, Query, Timeout) -> call1(M, Handler, Query, Timeout). --spec send_request(emgr_ref(), handler(), term()) -> request_id(). -send_request(M, Handler, Query) -> - gen:send_request(M, self(), {call, Handler, Query}). +-spec send_request(EventMgrRef::emgr_ref(), Handler::handler(), Request::term()) -> + ReqId::request_id(). +send_request(M, Handler, Request) -> + try + gen:send_request(M, self(), {call, Handler, Request}) + catch + error:badarg -> + error(badarg, [M, Handler, Request]) + end. --spec wait_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), emgr_ref()}}. -wait_response(RequestId, Timeout) -> - case gen:wait_response(RequestId, Timeout) of +-spec send_request(EventMgrRef::emgr_ref(), + Handler::handler(), + Request::term(), + Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). +send_request(M, Handler, Request, Label, ReqIdCol) -> + try + gen:send_request(M, self(), {call, Handler, Request}, Label, ReqIdCol) + catch + error:badarg -> + error(badarg, [M, Handler, Request, Label, ReqIdCol]) + end. + +-spec wait_response(ReqId, WaitTime) -> Result when + ReqId :: request_id(), + WaitTime :: response_timeout(), + Response :: {reply, Reply::term()} + | {error, {Reason::term(), emgr_ref()}}, + Result :: Response | 'timeout'. + +wait_response(ReqId, WaitTime) -> + try gen:wait_response(ReqId, WaitTime) of {reply, {error, _} = Err} -> Err; Return -> Return + catch + error:badarg -> + error(badarg, [ReqId, WaitTime]) + end. + +-spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + WaitTime :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), emgr_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +wait_response(ReqIdCol, WaitTime, Delete) -> + try gen:wait_response(ReqIdCol, WaitTime, Delete) of + {{reply, {error, _} = Err}, Label, NewReqIdCol} -> + {Err, Label, NewReqIdCol}; + Return -> + Return + catch + error:badarg -> + error(badarg, [ReqIdCol, WaitTime, Delete]) end. --spec receive_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), emgr_ref()}}. -receive_response(RequestId, Timeout) -> - case gen:receive_response(RequestId, Timeout) of +-spec receive_response(ReqId, Timeout) -> Result when + ReqId :: request_id(), + Timeout :: response_timeout(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), emgr_ref()}}, + Result :: Response | 'timeout'. + +receive_response(ReqId, Timeout) -> + try gen:receive_response(ReqId, Timeout) of {reply, {error, _} = Err} -> Err; Return -> Return + catch + error:badarg -> + error(badarg, [ReqId, Timeout]) end. --spec check_response(Msg::term(), RequestId::request_id()) -> - {reply, Reply::term()} | 'no_reply' | {error, {Reason::term(), emgr_ref()}}. -check_response(Msg, RequestId) -> - case gen:check_response(Msg, RequestId) of +-spec receive_response(ReqIdCollection, Timeout, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + Timeout :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), emgr_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +receive_response(ReqIdCol, Timeout, Delete) -> + try gen:receive_response(ReqIdCol, Timeout, Delete) of + {{reply, {error, _} = Err}, Label, NewReqIdCol} -> + {Err, Label, NewReqIdCol}; + Return -> + Return + catch + error:badarg -> + error(badarg, [ReqIdCol, Timeout, Delete]) + end. + +-spec check_response(Msg, ReqId) -> Result when + Msg :: term(), + ReqId :: request_id(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), emgr_ref()}}, + Result :: Response | 'no_reply'. + +check_response(Msg, ReqId) -> + try gen:check_response(Msg, ReqId) of {reply, {error, _} = Err} -> Err; Return -> Return + catch + error:badarg -> + error(badarg, [Msg, ReqId]) + end. + +-spec check_response(Msg, ReqIdCollection, Delete) -> Result when + Msg :: term(), + ReqIdCollection :: request_id_collection(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), emgr_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'no_reply'. + +check_response(Msg, ReqIdCol, Delete) -> + try gen:check_response(Msg, ReqIdCol, Delete) of + {{reply, {error, _} = Err}, Label, NewReqIdCol} -> + {Err, Label, NewReqIdCol}; + Return -> + Return + catch + error:badarg -> + error(badarg, [Msg, ReqIdCol, Delete]) + end. + +-spec reqids_new() -> + NewReqIdCollection::request_id_collection(). + +reqids_new() -> + gen:reqids_new(). + +-spec reqids_size(ReqIdCollection::request_id_collection()) -> + non_neg_integer(). + +reqids_size(ReqIdCollection) -> + try + gen:reqids_size(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) + end. + +-spec reqids_add(ReqId::request_id(), Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). + +reqids_add(ReqId, Label, ReqIdCollection) -> + try + gen:reqids_add(ReqId, Label, ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqId, Label, ReqIdCollection]) + end. + +-spec reqids_to_list(ReqIdCollection::request_id_collection()) -> + [{ReqId::request_id(), Label::term()}]. + +reqids_to_list(ReqIdCollection) -> + try + gen:reqids_to_list(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) end. -spec delete_handler(emgr_ref(), handler(), term()) -> term(). @@ -330,19 +499,25 @@ wake_hib(Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> fetch_msg(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib) -> receive + Msg -> + decode_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib) + after HibernateAfterTimeout -> + loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) + end. + +decode_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug, Hib) -> + case Msg of {system, From, Req} -> sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, [ServerName, MSL, HibernateAfterTimeout, Hib],Hib); {'EXIT', Parent, Reason} -> terminate_server(Reason, Parent, MSL, ServerName); - Msg when Debug =:= [] -> + _Msg when Debug =:= [] -> handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, []); - Msg -> + _Msg -> Debug1 = sys:handle_debug(Debug, fun print_event/3, ServerName, {in, Msg}), handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug1) - after HibernateAfterTimeout -> - loop(Parent, ServerName, MSL, HibernateAfterTimeout, Debug, true) end. handle_msg(Msg, Parent, ServerName, MSL, HibernateAfterTimeout, Debug) -> @@ -776,6 +951,8 @@ do_terminate(Mod, Handler, Args, State, LastIn, SName, Reason) -> ok end. +-spec report_terminate(_, How, _, _, _, _, _) -> ok when + How :: crash | normal | shutdown | {swapped, handler(), false | pid()}. report_terminate(Handler, crash, {error, Why}, State, LastIn, SName, _) -> report_terminate(Handler, Why, State, LastIn, SName); report_terminate(Handler, How, _, State, LastIn, SName, _) -> @@ -795,14 +972,34 @@ report_terminate(Handler, Reason, State, LastIn, SName) -> report_error(_Handler, normal, _, _, _) -> ok; report_error(_Handler, shutdown, _, _, _) -> ok; report_error(_Handler, {swapped,_,_}, _, _, _) -> ok; -report_error(Handler, Reason, State, LastIn, SName) -> +report_error(Handler, Exit, State, LastIn, SName) -> + + %% The reason comes from a catch expression, so we remove + %% the 'EXIT' and stacktrace from it so that the format_status + %% callback does not have deal with that. + {Reason, ReasonFun} = + case Exit of + {'EXIT',{R,ST}} -> + {R, fun(Reason) -> {'EXIT',{Reason,ST}} end}; + {'EXIT',R} -> + {R, fun(Reason) -> {'EXIT',Reason} end}; + R -> + {R, fun(Reason) -> Reason end} + end, + Status = gen:format_status( + Handler#handler.module, + terminate, + #{ state => State, + message => LastIn, + reason => Reason + }, + [get(), State]), ?LOG_ERROR(#{label=>{gen_event,terminate}, handler=>handler(Handler), name=>SName, - last_message=>LastIn, - state=>format_status(terminate,Handler#handler.module, - get(),State), - reason=>Reason}, + last_message=>maps:get(message,Status), + state=>maps:get('$status',Status,maps:get(state,Status)), + reason=>ReasonFun(maps:get(reason,Status))}, #{domain=>[otp], report_cb=>fun gen_event:format_log/2, error_logger=>#{tag=>error, @@ -869,10 +1066,10 @@ format_log_single(#{label:={gen_event,terminate}, Args1 = case Depth of unlimited -> - [Handler,SName,Reason1,LastIn,State]; + [Handler,SName,LastIn,State,Reason1]; _ -> - [Handler,Depth,SName,Depth,Reason1,Depth, - LastIn,Depth,State,Depth] + [Handler,Depth,SName,Depth,LastIn,Depth, + State,Depth,Reason1,Depth] end, {Format1, Args1}; format_log_single(#{label:={gen_event,no_handle_info}, @@ -992,24 +1189,19 @@ get_modules(MSL) -> %% Status information %%----------------------------------------------------------------- format_status(Opt, StatusData) -> - [PDict, SysState, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]] = StatusData, - Header = gen:format_status_header("Status for event handler", - ServerName), - FmtMSL = [MS#handler{state=format_status(Opt, Mod, PDict, State)} - || #handler{module = Mod, state = State} = MS <- MSL], + [PDict, SysState, Parent, Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]] = StatusData, + Header = gen:format_status_header("Status for event handler", ServerName), + {FmtMSL, Logs} = + lists:mapfoldl( + fun(#handler{module = Mod, state = State} = MS, Logs) -> + Status = gen:format_status( + Mod, Opt, #{ log => Logs, state => State }, + [PDict, State]), + {MS#handler{state=maps:get('$status',Status,maps:get(state,Status))}, + maps:get(log,Status)} + end, sys:get_log(Debug), MSL), [{header, Header}, {data, [{"Status", SysState}, + {"Logged Events", Logs}, {"Parent", Parent}]}, {items, {"Installed handlers", FmtMSL}}]. - -format_status(Opt, Mod, PDict, State) -> - case erlang:function_exported(Mod, format_status, 2) of - true -> - Args = [PDict, State], - case catch Mod:format_status(Opt, Args) of - {'EXIT', _} -> State; - Else -> Else - end; - false -> - State - end. diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index 68ff5e2d4d63..6dba530b8518 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -329,30 +329,26 @@ init_it(Starter, self, Name, Mod, Args, Options) -> init_it(Starter, Parent, Name0, Mod, Args, Options) -> Name = gen:name(Name0), Debug = gen:debug_options(Name, Options), - HibernateAfterTimeout = gen:hibernate_after(Options), - case catch Mod:init(Args) of + HibernateAfterTimeout = gen:hibernate_after(Options), + case catch Mod:init(Args) of {ok, StateName, StateData} -> - proc_lib:init_ack(Starter, {ok, self()}), + proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, Debug); {ok, StateName, StateData, Timeout} -> - proc_lib:init_ack(Starter, {ok, self()}), + proc_lib:init_ack(Starter, {ok, self()}), loop(Parent, Name, StateName, StateData, Mod, Timeout, HibernateAfterTimeout, Debug); {stop, Reason} -> - gen:unregister_name(Name0), - proc_lib:init_ack(Starter, {error, Reason}), - exit(Reason); + gen:unregister_name(Name0), + exit(Reason); ignore -> gen:unregister_name(Name0), - proc_lib:init_ack(Starter, ignore), - exit(normal); + proc_lib:init_fail(Starter, ignore, {exit, normal}); {'EXIT', Reason} -> gen:unregister_name(Name0), - proc_lib:init_ack(Starter, {error, Reason}), - exit(Reason); + exit(Reason); Else -> - Error = {bad_return_value, Else}, - proc_lib:init_ack(Starter, {error, Error}), - exit(Error) + Reason = {bad_return_value, Else}, + exit(Reason) end. %%----------------------------------------------------------------- diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index 03541ccb50b9..c574f2aeb2bf 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -97,8 +97,11 @@ start_monitor/3, start_monitor/4, stop/1, stop/3, call/2, call/3, - send_request/2, wait_response/2, - receive_response/2, check_response/2, + send_request/2, send_request/4, + wait_response/2, receive_response/2, check_response/2, + wait_response/3, receive_response/3, check_response/3, + reqids_new/0, reqids_size/1, + reqids_add/3, reqids_to_list/1, cast/2, reply/2, abcast/2, abcast/3, multi_call/2, multi_call/3, multi_call/4, @@ -120,28 +123,54 @@ -include("logger.hrl"). +-export_type( + [from/0, + reply_tag/0, + request_id/0, + request_id_collection/0, + format_status/0]). + +-export_type( + [server_name/0, + server_ref/0, + start_opt/0, + enter_loop_opt/0, + start_ret/0, + start_mon_ret/0]). + -define( STACKTRACE(), element(2, erlang:process_info(self(), current_stacktrace))). - --type server_ref() :: - pid() - | (LocalName :: atom()) - | {Name :: atom(), Node :: atom()} - | {'global', GlobalName :: term()} - | {'via', RegMod :: module(), ViaName :: term()}. - --type request_id() :: term(). - +-define( + is_timeout(X), + ( (X) =:= infinity orelse ( is_integer(X) andalso (X) >= 0 ) ) +). + +-record(callback_cache,{module :: module(), + handle_call :: fun((Request :: term(), From :: from(), State :: term()) -> + {reply, Reply :: term(), NewState :: term()} | + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | + {stop, Reason :: term(), Reply :: term(), NewState :: term()} | + {stop, Reason :: term(), NewState :: term()}), + handle_cast :: fun((Request :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | + {stop, Reason :: term(), NewState :: term()}), + handle_info :: fun((Info :: timeout | term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} | + {stop, Reason :: term(), NewState :: term()})}). %%%========================================================================= %%% API %%%========================================================================= -callback init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate | {continue, term()}} | - {stop, Reason :: term()} | ignore. --callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + {stop, Reason :: term()} | ignore | {error, Reason :: term()}. +-callback handle_call(Request :: term(), From :: from(), State :: term()) -> {reply, Reply :: term(), NewState :: term()} | {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} | @@ -174,9 +203,30 @@ PDict :: [{Key :: term(), Value :: term()}], State :: term(), Status :: term(). +-type format_status() :: + #{ state => term(), + message => term(), + reason => term(), + log => [sys:system_event()] }. +-callback format_status(Status) -> NewStatus when + Status :: format_status(), + NewStatus :: format_status(). -optional_callbacks( - [handle_info/2, handle_continue/2, terminate/2, code_change/3, format_status/2]). + [handle_info/2, handle_continue/2, terminate/2, code_change/3, + format_status/1, format_status/2]). + + + +-type from() :: {Client :: pid(), Tag :: reply_tag()}. +-opaque reply_tag() :: gen:reply_tag(). + +-opaque request_id() :: gen:request_id(). + +-opaque request_id_collection() :: gen:request_id_collection(). + +-type response_timeout() :: + timeout() | {abs, integer()}. %%% ----------------------------------------------------------------- %%% Starts a generic server. @@ -194,23 +244,102 @@ %%% {error, {already_started, Pid}} | %%% {error, Reason} %%% ----------------------------------------------------------------- -start(Mod, Args, Options) -> - gen:start(?MODULE, nolink, Mod, Args, Options). -start(Name, Mod, Args, Options) -> - gen:start(?MODULE, nolink, Name, Mod, Args, Options). +-type server_name() :: % Duplicate of gen:emgr_name() + {'local', LocalName :: atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), ViaName :: term()}. -start_link(Mod, Args, Options) -> - gen:start(?MODULE, link, Mod, Args, Options). +-type server_ref() :: % What gen:call/3,4 and gen:stop/1,3 accepts + pid() + | (LocalName :: atom()) + | {Name :: atom(), Node :: atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), ViaName :: term()}. -start_link(Name, Mod, Args, Options) -> - gen:start(?MODULE, link, Name, Mod, Args, Options). +-type start_opt() :: % Duplicate of gen:option() + {'timeout', Timeout :: timeout()} + | {'spawn_opt', SpawnOptions :: [proc_lib:spawn_option()]} + | enter_loop_opt(). +%% +-type enter_loop_opt() :: % Some gen:option()s works for enter_loop/* + {'hibernate_after', HibernateAfterTimeout :: timeout()} + | {'debug', Dbgs :: [sys:debug_option()]}. -start_monitor(Mod, Args, Options) -> - gen:start(?MODULE, monitor, Mod, Args, Options). +-type start_ret() :: % gen:start_ret() without monitor return + {'ok', Pid :: pid()} + | 'ignore' + | {'error', Reason :: term()}. -start_monitor(Name, Mod, Args, Options) -> - gen:start(?MODULE, monitor, Name, Mod, Args, Options). +-type start_mon_ret() :: % gen:start_ret() with only monitor return + {'ok', {Pid :: pid(), MonRef :: reference()}} + | 'ignore' + | {'error', Reason :: term()}. + +%%% --------------------------------------------------- + +-spec start( + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% +start(Module, Args, Options) -> + gen:start(?MODULE, nolink, Module, Args, Options). + +-spec start( + ServerName :: server_name(), + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% +start(ServerName, Module, Args, Options) -> + gen:start(?MODULE, nolink, ServerName, Module, Args, Options). + +-spec start_link( + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% +start_link(Module, Args, Options) -> + gen:start(?MODULE, link, Module, Args, Options). + +-spec start_link( + ServerName :: server_name(), + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_ret(). +%% +start_link(ServerName, Module, Args, Options) -> + gen:start(?MODULE, link, ServerName, Module, Args, Options). + +-spec start_monitor( + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_mon_ret(). +%% +start_monitor(Module, Args, Options) -> + gen:start(?MODULE, monitor, Module, Args, Options). + +-spec start_monitor( + ServerName :: server_name(), + Module :: module(), + Args :: term(), + Options :: [start_opt()] + ) -> + start_mon_ret(). +%% +start_monitor(ServerName, Module, Args, Options) -> + gen:start(?MODULE, monitor, ServerName, Module, Args, Options). %% ----------------------------------------------------------------- @@ -218,11 +347,22 @@ start_monitor(Name, Mod, Args, Options) -> %% If the server is located at another node, that node will %% be monitored. %% ----------------------------------------------------------------- -stop(Name) -> - gen:stop(Name). -stop(Name, Reason, Timeout) -> - gen:stop(Name, Reason, Timeout). +-spec stop( + ServerRef :: server_ref() + ) -> ok. +%% +stop(ServerRef) -> + gen:stop(ServerRef). + +-spec stop( + ServerRef :: server_ref(), + Reason :: term(), + Timeout :: timeout() + ) -> ok. +%% +stop(ServerRef, Reason, Timeout) -> + gen:stop(ServerRef, Reason, Timeout). %% ----------------------------------------------------------------- %% Make a call to a generic server. @@ -231,20 +371,34 @@ stop(Name, Reason, Timeout) -> %% If the client is trapping exits and is linked server termination %% is handled here (? Shall we do that here (or rely on timeouts) ?). %% ----------------------------------------------------------------- -call(Name, Request) -> - case catch gen:call(Name, '$gen_call', Request) of + +-spec call( + ServerRef :: server_ref(), + Request :: term() + ) -> + Reply :: term(). +%% +call(ServerRef, Request) -> + case catch gen:call(ServerRef, '$gen_call', Request) of {ok,Res} -> Res; {'EXIT',Reason} -> - exit({Reason, {?MODULE, call, [Name, Request]}}) + exit({Reason, {?MODULE, call, [ServerRef, Request]}}) end. -call(Name, Request, Timeout) -> - case catch gen:call(Name, '$gen_call', Request, Timeout) of +-spec call( + ServerRef :: server_ref(), + Request :: term(), + Timeout :: timeout() + ) -> + Reply :: term(). +%% +call(ServerRef, Request, Timeout) -> + case catch gen:call(ServerRef, '$gen_call', Request, Timeout) of {ok,Res} -> Res; {'EXIT',Reason} -> - exit({Reason, {?MODULE, call, [Name, Request, Timeout]}}) + exit({Reason, {?MODULE, call, [ServerRef, Request, Timeout]}}) end. %% ----------------------------------------------------------------- @@ -252,28 +406,183 @@ call(Name, Request, Timeout) -> %% used with wait_response/2 or check_response/2 to fetch the %% result of the request. --spec send_request(Name::server_ref(), Request::term()) -> request_id(). -send_request(Name, Request) -> - gen:send_request(Name, '$gen_call', Request). +-spec send_request(ServerRef::server_ref(), Request::term()) -> + ReqId::request_id(). + +send_request(ServerRef, Request) -> + try + gen:send_request(ServerRef, '$gen_call', Request) + catch + error:badarg -> + error(badarg, [ServerRef, Request]) + end. + +-spec send_request(ServerRef::server_ref(), + Request::term(), + Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). + +send_request(ServerRef, Request, Label, ReqIdCol) -> + try + gen:send_request(ServerRef, '$gen_call', Request, Label, ReqIdCol) + catch + error:badarg -> + error(badarg, [ServerRef, Request, Label, ReqIdCol]) + end. + +-spec wait_response(ReqId, WaitTime) -> Result when + ReqId :: request_id(), + WaitTime :: response_timeout(), + Response :: {reply, Reply::term()} + | {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +wait_response(ReqId, WaitTime) -> + try + gen:wait_response(ReqId, WaitTime) + catch + error:badarg -> + error(badarg, [ReqId, WaitTime]) + end. + +-spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + WaitTime :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +wait_response(ReqIdCol, WaitTime, Delete) -> + try + gen:wait_response(ReqIdCol, WaitTime, Delete) + catch + error:badarg -> + error(badarg, [ReqIdCol, WaitTime, Delete]) + end. + +-spec receive_response(ReqId, Timeout) -> Result when + ReqId :: request_id(), + Timeout :: response_timeout(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +receive_response(ReqId, Timeout) -> + try + gen:receive_response(ReqId, Timeout) + catch + error:badarg -> + error(badarg, [ReqId, Timeout]) + end. + +-spec receive_response(ReqIdCollection, Timeout, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + Timeout :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +receive_response(ReqIdCol, Timeout, Delete) -> + try + gen:receive_response(ReqIdCol, Timeout, Delete) + catch + error:badarg -> + error(badarg, [ReqIdCol, Timeout, Delete]) + end. + +-spec check_response(Msg, ReqId) -> Result when + Msg :: term(), + ReqId :: request_id(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: Response | 'no_reply'. + +check_response(Msg, ReqId) -> + try + gen:check_response(Msg, ReqId) + catch + error:badarg -> + error(badarg, [Msg, ReqId]) + end. + +-spec check_response(Msg, ReqIdCollection, Delete) -> Result when + Msg :: term(), + ReqIdCollection :: request_id_collection(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'no_reply'. + +check_response(Msg, ReqIdCol, Delete) -> + try + gen:check_response(Msg, ReqIdCol, Delete) + catch + error:badarg -> + error(badarg, [Msg, ReqIdCol, Delete]) + end. --spec wait_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), server_ref()}}. -wait_response(RequestId, Timeout) -> - gen:wait_response(RequestId, Timeout). +-spec reqids_new() -> + NewReqIdCollection::request_id_collection(). --spec receive_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), server_ref()}}. -receive_response(RequestId, Timeout) -> - gen:receive_response(RequestId, Timeout). +reqids_new() -> + gen:reqids_new(). --spec check_response(Msg::term(), RequestId::request_id()) -> - {reply, Reply::term()} | 'no_reply' | {error, {Reason::term(), server_ref()}}. -check_response(Msg, RequestId) -> - gen:check_response(Msg, RequestId). +-spec reqids_size(ReqIdCollection::request_id_collection()) -> + non_neg_integer(). + +reqids_size(ReqIdCollection) -> + try + gen:reqids_size(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) + end. + +-spec reqids_add(ReqId::request_id(), Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). + +reqids_add(ReqId, Label, ReqIdCollection) -> + try + gen:reqids_add(ReqId, Label, ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqId, Label, ReqIdCollection]) + end. + +-spec reqids_to_list(ReqIdCollection::request_id_collection()) -> + [{ReqId::request_id(), Label::term()}]. + +reqids_to_list(ReqIdCollection) -> + try + gen:reqids_to_list(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) + end. %% ----------------------------------------------------------------- %% Make a cast to a generic server. %% ----------------------------------------------------------------- + +-spec cast( + ServerRef :: server_ref(), + Request :: term() + ) -> + ok. +%% cast({global,Name}, Request) -> catch global:send(Name, cast_msg(Request)), ok; @@ -296,15 +605,36 @@ cast_msg(Request) -> {'$gen_cast',Request}. %% ----------------------------------------------------------------- %% Send a reply to the client. %% ----------------------------------------------------------------- -reply(From, Reply) -> - gen:reply(From, Reply). + +-spec reply( + Client :: from(), + Reply :: term() + ) -> + ok. +%% +reply(Client, Reply) -> + gen:reply(Client, Reply). %% ----------------------------------------------------------------- %% Asynchronous broadcast, returns nothing, it's just send 'n' pray %%----------------------------------------------------------------- + +-spec abcast( + Name :: atom(), + Request :: term() + ) -> + abcast. +%% abcast(Name, Request) when is_atom(Name) -> do_abcast([node() | nodes()], Name, cast_msg(Request)). +-spec abcast( + Nodes :: [node()], + Name :: atom(), + Request :: term() + ) -> + abcast. +%% abcast(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) -> do_abcast(Nodes, Name, cast_msg(Request)). @@ -323,20 +653,134 @@ do_abcast([], _,_) -> abcast. %%% queue, it would probably become confused. Late answers will %%% now arrive to the terminated middleman and so be discarded. %%% ----------------------------------------------------------------- -multi_call(Name, Req) - when is_atom(Name) -> - do_multi_call([node() | nodes()], Name, Req, infinity). -multi_call(Nodes, Name, Req) +-spec multi_call( + Name :: atom(), + Request :: term() + ) -> + {Replies :: + [{Node :: node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% +multi_call(Name, Request) + when is_atom(Name) -> + multi_call([node() | nodes()], Name, Request, infinity). + +-spec multi_call( + Nodes :: [node()], + Name :: atom(), + Request :: term() + ) -> + {Replies :: + [{Node :: node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% +multi_call(Nodes, Name, Request) when is_list(Nodes), is_atom(Name) -> - do_multi_call(Nodes, Name, Req, infinity). + multi_call(Nodes, Name, Request, infinity). + +-spec multi_call( + Nodes :: [node()], + Name :: atom(), + Request :: term(), + Timeout :: timeout() + ) -> + {Replies :: + [{Node :: node(), Reply :: term()}], + BadNodes :: [node()] + }. +%% +multi_call(Nodes, Name, Request, Timeout) + when is_list(Nodes), is_atom(Name), ?is_timeout(Timeout) -> + Alias = alias(), + try + Timer = if Timeout == infinity -> undefined; + true -> erlang:start_timer(Timeout, self(), Alias) + end, + Reqs = mc_send(Nodes, Name, Alias, Request, Timer, []), + mc_recv(Reqs, Alias, Timer, [], []) + after + _ = unalias(Alias) + end. -multi_call(Nodes, Name, Req, infinity) -> - do_multi_call(Nodes, Name, Req, infinity); -multi_call(Nodes, Name, Req, Timeout) - when is_list(Nodes), is_atom(Name), is_integer(Timeout), Timeout >= 0 -> - do_multi_call(Nodes, Name, Req, Timeout). +-dialyzer({no_improper_lists, mc_send/6}). + +mc_send([], _Name, _Alias, _Request, _Timer, Reqs) -> + Reqs; +mc_send([Node|Nodes], Name, Alias, Request, Timer, Reqs) when is_atom(Node) -> + NN = {Name, Node}, + Mon = try + erlang:monitor(process, NN, [{tag, Alias}]) + catch + error:badarg -> + %% Node not alive... + M = make_ref(), + Alias ! {Alias, M, process, NN, noconnection}, + M + end, + try + %% We use 'noconnect' since it is no point in bringing up a new + %% connection if it was not brought up by the monitor signal... + _ = erlang:send(NN, + {'$gen_call', {self(), [[alias|Alias]|Mon]}, Request}, + [noconnect]), + ok + catch + _:_ -> + ok + end, + mc_send(Nodes, Name, Alias, Request, Timer, [[Node|Mon]|Reqs]); +mc_send(_BadNodes, _Name, Alias, _Request, Timer, Reqs) -> + %% Cleanup then fail... + unalias(Alias), + mc_cancel_timer(Timer, Alias), + _ = mc_recv_tmo(Reqs, Alias, [], []), + error(badarg). + +mc_recv([], Alias, Timer, Replies, BadNodes) -> + mc_cancel_timer(Timer, Alias), + unalias(Alias), + {Replies, BadNodes}; +mc_recv([[Node|Mon] | RestReqs] = Reqs, Alias, Timer, Replies, BadNodes) -> + receive + {[[alias|Alias]|Mon], Reply} -> + erlang:demonitor(Mon, [flush]), + mc_recv(RestReqs, Alias, Timer, [{Node,Reply}|Replies], BadNodes); + {Alias, Mon, process, _, _} -> + mc_recv(RestReqs, Alias, Timer, Replies, [Node|BadNodes]); + {timeout, Timer, Alias} -> + unalias(Alias), + mc_recv_tmo(Reqs, Alias, Replies, BadNodes) + end. +mc_recv_tmo([], _Alias, Replies, BadNodes) -> + {Replies, BadNodes}; +mc_recv_tmo([[Node|Mon] | RestReqs], Alias, Replies, BadNodes) -> + erlang:demonitor(Mon), + receive + {[[alias|Alias]|Mon], Reply} -> + mc_recv_tmo(RestReqs, Alias, [{Node,Reply}|Replies], BadNodes); + {Alias, Mon, process, _, _} -> + mc_recv_tmo(RestReqs, Alias, Replies, [Node|BadNodes]) + after + 0 -> + mc_recv_tmo(RestReqs, Alias, Replies, [Node|BadNodes]) + end. + +mc_cancel_timer(undefined, _Alias) -> + ok; +mc_cancel_timer(Timer, Alias) -> + case erlang:cancel_timer(Timer) of + false -> + receive + {timeout, Timer, Alias} -> + ok + end; + _ -> + ok + end. %%----------------------------------------------------------------- %% enter_loop(Mod, Options, State, , ) ->_ @@ -349,25 +793,108 @@ multi_call(Nodes, Name, Req, Timeout) %% The user is responsible for any initialization of the %% process, including registering a name for it. %%----------------------------------------------------------------- -enter_loop(Mod, Options, State) -> + +-spec enter_loop( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term() + ) -> + no_return(). +%% +enter_loop(Mod, Options, State) + when is_atom(Mod), is_list(Options) -> enter_loop(Mod, Options, State, self(), infinity). +-spec enter_loop( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() | pid() + ) -> + no_return(); + ( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + Timeout :: timeout() + ) -> + no_return(); + ( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + Hibernate :: 'hibernate' + ) -> + no_return(); + ( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + Cont :: {'continue', term()} + ) -> + no_return(). +%% enter_loop(Mod, Options, State, ServerName = {Scope, _}) - when Scope == local; Scope == global -> + when is_atom(Mod), is_list(Options), Scope == local; + is_atom(Mod), is_list(Options), Scope == global -> enter_loop(Mod, Options, State, ServerName, infinity); - -enter_loop(Mod, Options, State, ServerName = {via, _, _}) -> +%% +enter_loop(Mod, Options, State, ServerName = {via, _, _}) + when is_atom(Mod), is_list(Options) -> enter_loop(Mod, Options, State, ServerName, infinity); - -enter_loop(Mod, Options, State, Timeout) -> - enter_loop(Mod, Options, State, self(), Timeout). - -enter_loop(Mod, Options, State, ServerName, Timeout) -> +%% +enter_loop(Mod, Options, State, TimeoutOrHibernate) + when is_atom(Mod), is_list(Options), ?is_timeout(TimeoutOrHibernate); + is_atom(Mod), is_list(Options), TimeoutOrHibernate =:= hibernate -> + enter_loop(Mod, Options, State, self(), TimeoutOrHibernate); +%% +enter_loop(Mod, Options, State, {continue, _}=Continue) + when is_atom(Mod), is_list(Options) -> + enter_loop(Mod, Options, State, self(), Continue). + +-spec enter_loop( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() | pid(), + Timeout :: timeout() + ) -> + no_return(); + ( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() | pid(), + Hibernate :: 'hibernate' + ) -> + no_return(); + ( + Module :: module(), + Options :: [enter_loop_opt()], + State :: term(), + ServerName :: server_name() | pid(), + Cont :: {'continue', term()} + ) -> + no_return(). +%% +enter_loop(Mod, Options, State, ServerName, TimeoutOrHibernate) + when is_atom(Mod), is_list(Options), ?is_timeout(TimeoutOrHibernate); + is_atom(Mod), is_list(Options), TimeoutOrHibernate =:= hibernate -> + Name = gen:get_proc_name(ServerName), + Parent = gen:get_parent(), + Debug = gen:debug_options(Name, Options), + HibernateAfterTimeout = gen:hibernate_after(Options), + CbCache = create_callback_cache(Mod), + loop(Parent, Name, State, CbCache, TimeoutOrHibernate, HibernateAfterTimeout, Debug); +%% +enter_loop(Mod, Options, State, ServerName, {continue, _}=Continue) + when is_atom(Mod), is_list(Options) -> Name = gen:get_proc_name(ServerName), Parent = gen:get_parent(), Debug = gen:debug_options(Name, Options), HibernateAfterTimeout = gen:hibernate_after(Options), - loop(Parent, Name, State, Mod, Timeout, HibernateAfterTimeout, Debug). + CbCache = create_callback_cache(Mod), + loop(Parent, Name, State, CbCache, Continue, HibernateAfterTimeout, Debug). %%%======================================================================== %%% Gen-callback functions @@ -386,15 +913,25 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) -> Name = gen:name(Name0), Debug = gen:debug_options(Name, Options), HibernateAfterTimeout = gen:hibernate_after(Options), - + CbCache = create_callback_cache(Mod), case init_it(Mod, Args) of {ok, {ok, State}} -> - proc_lib:init_ack(Starter, {ok, self()}), - loop(Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug); - {ok, {ok, State, TimeoutHibernateOrContinue}} -> - proc_lib:init_ack(Starter, {ok, self()}), - loop(Parent, Name, State, Mod, TimeoutHibernateOrContinue, - HibernateAfterTimeout, Debug); + proc_lib:init_ack(Starter, {ok, self()}), + loop( + Parent, Name, State, CbCache, infinity, + HibernateAfterTimeout, Debug); + {ok, {ok, State, TimeoutOrHibernate}} + when ?is_timeout(TimeoutOrHibernate); + TimeoutOrHibernate =:= hibernate -> + proc_lib:init_ack(Starter, {ok, self()}), + loop( + Parent, Name, State, CbCache, TimeoutOrHibernate, + HibernateAfterTimeout, Debug); + {ok, {ok, State, {continue, _}=Continue}} -> + proc_lib:init_ack(Starter, {ok, self()}), + loop( + Parent, Name, State, CbCache, Continue, + HibernateAfterTimeout, Debug); {ok, {stop, Reason}} -> %% For consistency, we must make sure that the %% registered name (if any) is unregistered before @@ -403,29 +940,32 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) -> %% an 'already_started' error if it immediately %% tried starting the process again.) gen:unregister_name(Name0), - proc_lib:init_ack(Starter, {error, Reason}), - exit(Reason); + exit(Reason); + {ok, {error, _Reason} = ERROR} -> + %% The point of this clause is that we shall have a silent/graceful + %% termination. The error reason will be returned to the + %% 'Starter' ({error, Reason}), but *no* crash report. + gen:unregister_name(Name0), + proc_lib:init_fail(Starter, ERROR, {exit, normal}); {ok, ignore} -> gen:unregister_name(Name0), - proc_lib:init_ack(Starter, ignore), - exit(normal); + proc_lib:init_fail(Starter, ignore, {exit, normal}); {ok, Else} -> - Error = {bad_return_value, Else}, - proc_lib:init_ack(Starter, {error, Error}), - exit(Error); + gen:unregister_name(Name0), + exit({bad_return_value, Else}); {'EXIT', Class, Reason, Stacktrace} -> gen:unregister_name(Name0), - proc_lib:init_ack(Starter, {error, terminate_reason(Class, Reason, Stacktrace)}), - erlang:raise(Class, Reason, Stacktrace) + erlang:raise(Class, Reason, Stacktrace) end. init_it(Mod, Args) -> try - {ok, Mod:init(Args)} + {ok, Mod:init(Args)} catch - throw:R -> {ok, R}; - Class:R:S -> {'EXIT', Class, R, S} + throw:R -> {ok, R}; + Class:R:S -> {'EXIT', Class, R, S} end. + %%%======================================================================== %%% Internal functions %%%======================================================================== @@ -433,58 +973,68 @@ init_it(Mod, Args) -> %%% The MAIN loop. %%% --------------------------------------------------- -loop(Parent, Name, State, Mod, {continue, Continue} = Msg, HibernateAfterTimeout, Debug) -> - Reply = try_dispatch(Mod, handle_continue, Continue, State), +loop(Parent, Name, State, CbCache, {continue, Continue} = Msg, HibernateAfterTimeout, Debug) -> + Reply = try_handle_continue(CbCache, Continue, State), case Debug of - [] -> - handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, - HibernateAfterTimeout, State); - _ -> - Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, Msg), - handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, - HibernateAfterTimeout, State, Debug1) + [] -> + handle_common_reply(Reply, Parent, Name, undefined, Msg, CbCache, + HibernateAfterTimeout, State); + _ -> + Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, Msg), + handle_common_reply(Reply, Parent, Name, undefined, Msg, CbCache, + HibernateAfterTimeout, State, Debug1) end; -loop(Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug) -> +loop(Parent, Name, State, CbCache, hibernate, HibernateAfterTimeout, Debug) -> + Mod = CbCache#callback_cache.module, proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, HibernateAfterTimeout, Debug]); -loop(Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug) -> - receive - Msg -> - decode_msg(Msg, Parent, Name, State, Mod, infinity, HibernateAfterTimeout, Debug, false) - after HibernateAfterTimeout -> - loop(Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug) - end; +loop(Parent, Name, State, CbCache, infinity, HibernateAfterTimeout, Debug) -> + receive + Msg -> + decode_msg(Msg, Parent, Name, State, CbCache, infinity, HibernateAfterTimeout, Debug, false) + after HibernateAfterTimeout -> + loop(Parent, Name, State, CbCache, hibernate, HibernateAfterTimeout, Debug) + end; -loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug) -> +loop(Parent, Name, State, CbCache, Time, HibernateAfterTimeout, Debug) -> Msg = receive - Input -> - Input - after Time -> - timeout - end, - decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, false). + Input -> + Input + after Time -> + timeout + end, + decode_msg(Msg, Parent, Name, State, CbCache, Time, HibernateAfterTimeout, Debug, false). + +-spec create_callback_cache(module()) -> #callback_cache{}. +create_callback_cache(Mod) -> + #callback_cache{module = Mod, + handle_call = fun Mod:handle_call/3, + handle_cast = fun Mod:handle_cast/2, + handle_info = fun Mod:handle_info/2}. wake_hib(Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> Msg = receive - Input -> - Input - end, - decode_msg(Msg, Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug, true). + Input -> + Input + end, + CbCache = create_callback_cache(Mod), + decode_msg(Msg, Parent, Name, State, CbCache, hibernate, HibernateAfterTimeout, Debug, true). -decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, Hib) -> +decode_msg(Msg, Parent, Name, State, CbCache, Time, HibernateAfterTimeout, Debug, Hib) -> case Msg of - {system, From, Req} -> - sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, - [Name, State, Mod, Time, HibernateAfterTimeout], Hib); - {'EXIT', Parent, Reason} -> - terminate(Reason, ?STACKTRACE(), Name, undefined, Msg, Mod, State, Debug); - _Msg when Debug =:= [] -> - handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout); - _Msg -> - Debug1 = sys:handle_debug(Debug, fun print_event/3, - Name, {in, Msg}), - handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout, Debug1) + {system, From, Req} -> + sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, + [Name, State, CbCache, Time, HibernateAfterTimeout], Hib); + {'EXIT', Parent, Reason} -> + #callback_cache{module = Mod} = CbCache, + terminate(Reason, ?STACKTRACE(), Name, undefined, Msg, Mod, State, Debug); + _Msg when Debug =:= [] -> + handle_msg(Msg, Parent, Name, State, CbCache, HibernateAfterTimeout); + _Msg -> + Debug1 = sys:handle_debug(Debug, fun print_event/3, + Name, {in, Msg}), + handle_msg(Msg, Parent, Name, State, CbCache, HibernateAfterTimeout, Debug1) end. %%% --------------------------------------------------- @@ -497,184 +1047,6 @@ do_send(Dest, Msg) -> end, ok. -do_multi_call([Node], Name, Req, infinity) when Node =:= node() -> - % Special case when multi_call is used with local node only. - % In that case we can leverage the benefit of recv_mark optimisation - % existing in simple gen:call. - try gen:call(Name, '$gen_call', Req, infinity) of - {ok, Res} -> {[{Node, Res}],[]} - catch exit:_ -> - {[], [Node]} - end; -do_multi_call(Nodes, Name, Req, infinity) -> - Tag = make_ref(), - Monitors = send_nodes(Nodes, Name, Tag, Req), - rec_nodes(Tag, Monitors, Name, undefined); -do_multi_call(Nodes, Name, Req, Timeout) -> - Tag = make_ref(), - Caller = self(), - Receiver = - spawn( - fun() -> - %% Middleman process. Should be unsensitive to regular - %% exit signals. The sychronization is needed in case - %% the receiver would exit before the caller started - %% the monitor. - process_flag(trap_exit, true), - Mref = erlang:monitor(process, Caller), - receive - {Caller,Tag} -> - Monitors = send_nodes(Nodes, Name, Tag, Req), - TimerId = erlang:start_timer(Timeout, self(), ok), - Result = rec_nodes(Tag, Monitors, Name, TimerId), - exit({self(),Tag,Result}); - {'DOWN',Mref,_,_,_} -> - %% Caller died before sending us the go-ahead. - %% Give up silently. - exit(normal) - end - end), - Mref = erlang:monitor(process, Receiver), - Receiver ! {self(),Tag}, - receive - {'DOWN',Mref,_,_,{Receiver,Tag,Result}} -> - Result; - {'DOWN',Mref,_,_,Reason} -> - %% The middleman code failed. Or someone did - %% exit(_, kill) on the middleman process => Reason==killed - exit(Reason) - end. - -send_nodes(Nodes, Name, Tag, Req) -> - send_nodes(Nodes, Name, Tag, Req, []). - -send_nodes([Node|Tail], Name, Tag, Req, Monitors) - when is_atom(Node) -> - Monitor = start_monitor(Node, Name), - %% Handle non-existing names in rec_nodes. - catch {Name, Node} ! {'$gen_call', {self(), {Tag, Node}}, Req}, - send_nodes(Tail, Name, Tag, Req, [Monitor | Monitors]); -send_nodes([_Node|Tail], Name, Tag, Req, Monitors) -> - %% Skip non-atom Node - send_nodes(Tail, Name, Tag, Req, Monitors); -send_nodes([], _Name, _Tag, _Req, Monitors) -> - Monitors. - -%% Against old nodes: -%% If no reply has been delivered within 2 secs. (per node) check that -%% the server really exists and wait for ever for the answer. -%% -%% Against contemporary nodes: -%% Wait for reply, server 'DOWN', or timeout from TimerId. - -rec_nodes(Tag, Nodes, Name, TimerId) -> - rec_nodes(Tag, Nodes, Name, [], [], 2000, TimerId). - -rec_nodes(Tag, [{N,R}|Tail], Name, Badnodes, Replies, Time, TimerId ) -> - receive - {'DOWN', R, _, _, _} -> - rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, Time, TimerId); - {{Tag, N}, Reply} -> %% Tag is bound !!! - erlang:demonitor(R, [flush]), - rec_nodes(Tag, Tail, Name, Badnodes, - [{N,Reply}|Replies], Time, TimerId); - {timeout, TimerId, _} -> - erlang:demonitor(R, [flush]), - %% Collect all replies that already have arrived - rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) - end; -rec_nodes(Tag, [N|Tail], Name, Badnodes, Replies, Time, TimerId) -> - %% R6 node - receive - {nodedown, N} -> - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, 2000, TimerId); - {{Tag, N}, Reply} -> %% Tag is bound !!! - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, Badnodes, - [{N,Reply}|Replies], 2000, TimerId); - {timeout, TimerId, _} -> - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - %% Collect all replies that already have arrived - rec_nodes_rest(Tag, Tail, Name, [N | Badnodes], Replies) - after Time -> - case rpc:call(N, erlang, whereis, [Name]) of - Pid when is_pid(Pid) -> % It exists try again. - rec_nodes(Tag, [N|Tail], Name, Badnodes, - Replies, infinity, TimerId); - _ -> % badnode - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes(Tag, Tail, Name, [N|Badnodes], - Replies, 2000, TimerId) - end - end; -rec_nodes(_, [], _, Badnodes, Replies, _, TimerId) -> - case catch erlang:cancel_timer(TimerId) of - false -> % It has already sent it's message - receive - {timeout, TimerId, _} -> ok - after 0 -> - ok - end; - _ -> % Timer was cancelled, or TimerId was 'undefined' - ok - end, - {Replies, Badnodes}. - -%% Collect all replies that already have arrived -rec_nodes_rest(Tag, [{N,R}|Tail], Name, Badnodes, Replies) -> - receive - {'DOWN', R, _, _, _} -> - rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies); - {{Tag, N}, Reply} -> %% Tag is bound !!! - erlang:demonitor(R, [flush]), - rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies]) - after 0 -> - erlang:demonitor(R, [flush]), - rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) - end; -rec_nodes_rest(Tag, [N|Tail], Name, Badnodes, Replies) -> - %% R6 node - receive - {nodedown, N} -> - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies); - {{Tag, N}, Reply} -> %% Tag is bound !!! - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies]) - after 0 -> - receive {nodedown, N} -> ok after 0 -> ok end, - monitor_node(N, false), - rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies) - end; -rec_nodes_rest(_Tag, [], _Name, Badnodes, Replies) -> - {Replies, Badnodes}. - - -%%% --------------------------------------------------- -%%% Monitor functions -%%% --------------------------------------------------- - -start_monitor(Node, Name) when is_atom(Node), is_atom(Name) -> - if node() =:= nonode@nohost, Node =/= nonode@nohost -> - Ref = make_ref(), - self() ! {'DOWN', Ref, process, {Name, Node}, noconnection}, - {Node, Ref}; - true -> - case catch erlang:monitor(process, {Name, Node}) of - {'EXIT', _} -> - %% Remote node is R6 - monitor_node(Node, true), - Node; - Ref when is_reference(Ref) -> - {Node, Ref} - end - end. - %% --------------------------------------------------- %% Helper functions for try-catch of callbacks. %% Returns the return value of the callback, or @@ -685,60 +1057,80 @@ start_monitor(Node, Name) when is_atom(Node), is_atom(Name) -> %% stacktraces. %% --------------------------------------------------- -try_dispatch({'$gen_cast', Msg}, Mod, State) -> - try_dispatch(Mod, handle_cast, Msg, State); -try_dispatch(Info, Mod, State) -> - try_dispatch(Mod, handle_info, Info, State). +try_dispatch({'$gen_cast', Msg}, CbCache, State) -> + try_handle_cast(CbCache, Msg, State); +try_dispatch(Info, CbCache, State) -> + try_handle_info(CbCache, Info, State). + +try_handle_continue(#callback_cache{module = Mod}, Msg, State) -> + try + {ok, Mod:handle_continue(Msg, State)} + catch + throw:R -> + {ok, R}; + Class:R:Stacktrace -> + {'EXIT', Class, R, Stacktrace} + end. -try_dispatch(Mod, Func, Msg, State) -> +try_handle_info(#callback_cache{module = Mod, handle_info = HandleInfo}, Msg, State) -> try - {ok, Mod:Func(Msg, State)} + {ok, HandleInfo(Msg, State)} catch - throw:R -> - {ok, R}; - error:undef = R:Stacktrace when Func == handle_info -> + throw:R -> + {ok, R}; + error:undef = R:Stacktrace -> case erlang:function_exported(Mod, handle_info, 2) of false -> ?LOG_WARNING( - #{label=>{gen_server,no_handle_info}, - module=>Mod, - message=>Msg}, - #{domain=>[otp], - report_cb=>fun gen_server:format_log/2, - error_logger=> - #{tag=>warning_msg, - report_cb=>fun gen_server:format_log/1}}), + #{label=>{gen_server,no_handle_info}, + module=>Mod, + message=>Msg}, + #{domain=>[otp], + report_cb=>fun gen_server:format_log/2, + error_logger=> + #{tag=>warning_msg, + report_cb=>fun gen_server:format_log/1}}), {ok, {noreply, State}}; true -> {'EXIT', error, R, Stacktrace} end; - Class:R:Stacktrace -> - {'EXIT', Class, R, Stacktrace} + Class:R:Stacktrace -> + {'EXIT', Class, R, Stacktrace} end. -try_handle_call(Mod, Msg, From, State) -> +try_handle_cast(#callback_cache{handle_cast = HandleCast}, Msg, State) -> try - {ok, Mod:handle_call(Msg, From, State)} + {ok, HandleCast(Msg, State)} catch - throw:R -> - {ok, R}; - Class:R:Stacktrace -> - {'EXIT', Class, R, Stacktrace} + throw:R -> + {ok, R}; + Class:R:Stacktrace -> + {'EXIT', Class, R, Stacktrace} + end. + +try_handle_call(#callback_cache{handle_call = HandleCall}, Msg, From, State) -> + try + {ok, HandleCall(Msg, From, State)} + catch + throw:R -> + {ok, R}; + Class:R:Stacktrace -> + {'EXIT', Class, R, Stacktrace} end. try_terminate(Mod, Reason, State) -> case erlang:function_exported(Mod, terminate, 2) of - true -> - try - {ok, Mod:terminate(Reason, State)} - catch - throw:R -> - {ok, R}; - Class:R:Stacktrace -> - {'EXIT', Class, R, Stacktrace} - end; - false -> - {ok, ok} + true -> + try + {ok, Mod:terminate(Reason, State)} + catch + throw:R -> + {ok, R}; + Class:R:Stacktrace -> + {'EXIT', Class, R, Stacktrace} + end; + false -> + {ok, ok} end. @@ -746,67 +1138,72 @@ try_terminate(Mod, Reason, State) -> %%% Message handling functions %%% --------------------------------------------------- -handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, HibernateAfterTimeout) -> - Result = try_handle_call(Mod, Msg, From, State), +handle_msg({'$gen_call', From, Msg}, Parent, Name, State, CbCache, HibernateAfterTimeout) -> + Result = try_handle_call(CbCache, Msg, From, State), case Result of {ok, {reply, Reply, NState}} -> reply(From, Reply), - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); - {ok, {reply, Reply, NState, Time1}} -> + loop(Parent, Name, NState, CbCache, infinity, HibernateAfterTimeout, []); + {ok, {reply, Reply, NState, TimeoutOrHibernate}} + when ?is_timeout(TimeoutOrHibernate); + TimeoutOrHibernate =:= hibernate -> reply(From, Reply), - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); - {ok, {noreply, NState}} -> - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); - {ok, {noreply, NState, Time1}} -> - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); + loop(Parent, Name, NState, CbCache, TimeoutOrHibernate, HibernateAfterTimeout, []); + {ok, {reply, Reply, NState, {continue, _}=Continue}} -> + reply(From, Reply), + loop(Parent, Name, NState, CbCache, Continue, HibernateAfterTimeout, []); {ok, {stop, Reason, Reply, NState}} -> try + Mod = CbCache#callback_cache.module, terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, []) after reply(From, Reply) end; - Other -> handle_common_reply(Other, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State) + Other -> handle_common_reply(Other, Parent, Name, From, Msg, CbCache, HibernateAfterTimeout, State) end; -handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout) -> - Reply = try_dispatch(Msg, Mod, State), - handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, HibernateAfterTimeout, State). +handle_msg(Msg, Parent, Name, State, CbCache, HibernateAfterTimeout) -> + Reply = try_dispatch(Msg, CbCache, State), + handle_common_reply(Reply, Parent, Name, undefined, Msg, CbCache, HibernateAfterTimeout, State). -handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> - Result = try_handle_call(Mod, Msg, From, State), +handle_msg({'$gen_call', From, Msg}, Parent, Name, State, CbCache, HibernateAfterTimeout, Debug) -> + Result = try_handle_call(CbCache, Msg, From, State), case Result of {ok, {reply, Reply, NState}} -> Debug1 = reply(Name, From, Reply, NState, Debug), - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); - {ok, {reply, Reply, NState, Time1}} -> + loop(Parent, Name, NState, CbCache, infinity, HibernateAfterTimeout, Debug1); + {ok, {reply, Reply, NState, TimeoutOrHibernate}} + when ?is_timeout(TimeoutOrHibernate); + TimeoutOrHibernate =:= hibernate -> Debug1 = reply(Name, From, Reply, NState, Debug), - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); - {ok, {noreply, NState}} -> - Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, - {noreply, NState}), - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); - {ok, {noreply, NState, Time1}} -> - Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, - {noreply, NState}), - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); + loop(Parent, Name, NState, CbCache, TimeoutOrHibernate, HibernateAfterTimeout, Debug1); + {ok, {reply, Reply, NState, {continue, _}=Continue}} -> + Debug1 = reply(Name, From, Reply, NState, Debug), + loop(Parent, Name, NState, CbCache, Continue, HibernateAfterTimeout, Debug1); {ok, {stop, Reason, Reply, NState}} -> try + Mod = CbCache#callback_cache.module, terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, Debug) after _ = reply(Name, From, Reply, NState, Debug) end; Other -> - handle_common_reply(Other, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State, Debug) + handle_common_reply(Other, Parent, Name, From, Msg, CbCache, HibernateAfterTimeout, State, Debug) end; -handle_msg(Msg, Parent, Name, State, Mod, HibernateAfterTimeout, Debug) -> - Reply = try_dispatch(Msg, Mod, State), - handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, HibernateAfterTimeout, State, Debug). +handle_msg(Msg, Parent, Name, State, CbCache, HibernateAfterTimeout, Debug) -> + Reply = try_dispatch(Msg, CbCache, State), + handle_common_reply(Reply, Parent, Name, undefined, Msg, CbCache, HibernateAfterTimeout, State, Debug). -handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State) -> +handle_common_reply(Reply, Parent, Name, From, Msg, CbCache, HibernateAfterTimeout, State) -> + Mod = CbCache#callback_cache.module, case Reply of {ok, {noreply, NState}} -> - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, []); - {ok, {noreply, NState, Time1}} -> - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, []); + loop(Parent, Name, NState, CbCache, infinity, HibernateAfterTimeout, []); + {ok, {noreply, NState, TimeoutOrHibernate}} + when ?is_timeout(TimeoutOrHibernate); + TimeoutOrHibernate =:= hibernate -> + loop(Parent, Name, NState, CbCache, TimeoutOrHibernate, HibernateAfterTimeout, []); + {ok, {noreply, NState, {continue, _}=Continue}} -> + loop(Parent, Name, NState, CbCache, Continue, HibernateAfterTimeout, []); {ok, {stop, Reason, NState}} -> terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, []); {'EXIT', Class, Reason, Stacktrace} -> @@ -815,16 +1212,21 @@ handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, terminate({bad_return_value, BadReply}, ?STACKTRACE(), Name, From, Msg, Mod, State, []) end. -handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, State, Debug) -> +handle_common_reply(Reply, Parent, Name, From, Msg, CbCache, HibernateAfterTimeout, State, Debug) -> + Mod = CbCache#callback_cache.module, case Reply of {ok, {noreply, NState}} -> Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, {noreply, NState}), - loop(Parent, Name, NState, Mod, infinity, HibernateAfterTimeout, Debug1); - {ok, {noreply, NState, Time1}} -> - Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, - {noreply, NState}), - loop(Parent, Name, NState, Mod, Time1, HibernateAfterTimeout, Debug1); + loop(Parent, Name, NState, CbCache, infinity, HibernateAfterTimeout, Debug1); + {ok, {noreply, NState, TimeoutOrHibernate}} + when ?is_timeout(TimeoutOrHibernate); + TimeoutOrHibernate =:= hibernate -> + Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, {noreply, NState}), + loop(Parent, Name, NState, CbCache, TimeoutOrHibernate, HibernateAfterTimeout, Debug1); + {ok, {noreply, NState, {continue, _}=Continue}} -> + Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, {noreply, NState}), + loop(Parent, Name, NState, CbCache, Continue, HibernateAfterTimeout, Debug1); {ok, {stop, Reason, NState}} -> terminate(Reason, ?STACKTRACE(), Name, From, Msg, Mod, NState, Debug); {'EXIT', Class, Reason, Stacktrace} -> @@ -836,32 +1238,34 @@ handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout, reply(Name, From, Reply, State, Debug) -> reply(From, Reply), sys:handle_debug(Debug, fun print_event/3, Name, - {out, Reply, From, State} ). + {out, Reply, From, State} ). %%----------------------------------------------------------------- %% Callback functions for system messages handling. %%----------------------------------------------------------------- -system_continue(Parent, Debug, [Name, State, Mod, Time, HibernateAfterTimeout]) -> - loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug). +system_continue(Parent, Debug, [Name, State, CbCache, Time, HibernateAfterTimeout]) -> + loop(Parent, Name, State, CbCache, Time, HibernateAfterTimeout, Debug). -spec system_terminate(_, _, _, [_]) -> no_return(). -system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time, _HibernateAfterTimeout]) -> +system_terminate(Reason, _Parent, Debug, [Name, State, CbCache, _Time, _HibernateAfterTimeout]) -> + Mod = CbCache#callback_cache.module, terminate(Reason, ?STACKTRACE(), Name, undefined, [], Mod, State, Debug). -system_code_change([Name, State, Mod, Time, HibernateAfterTimeout], _Module, OldVsn, Extra) -> +system_code_change([Name, State, CbCache, Time, HibernateAfterTimeout], _Module, OldVsn, Extra) -> + Mod = CbCache#callback_cache.module, case catch Mod:code_change(OldVsn, State, Extra) of - {ok, NewState} -> {ok, [Name, NewState, Mod, Time, HibernateAfterTimeout]}; - Else -> Else + {ok, NewState} -> {ok, [Name, NewState, CbCache, Time, HibernateAfterTimeout]}; + Else -> Else end. system_get_state([_Name, State, _Mod, _Time, _HibernateAfterTimeout]) -> {ok, State}. -system_replace_state(StateFun, [Name, State, Mod, Time, HibernateAfterTimeout]) -> +system_replace_state(StateFun, [Name, State, CbCache, Time, HibernateAfterTimeout]) -> NState = StateFun(State), - {ok, NState, [Name, NState, Mod, Time, HibernateAfterTimeout]}. + {ok, NState, [Name, NState, CbCache, Time, HibernateAfterTimeout]}. %%----------------------------------------------------------------- %% Format debug messages. Print them as the call-back module sees @@ -906,27 +1310,28 @@ print_event(Dev, Event, Name) -> -spec terminate(_, _, _, _, _, _, _, _) -> no_return(). terminate(Reason, Stacktrace, Name, From, Msg, Mod, State, Debug) -> - terminate(exit, Reason, Stacktrace, Reason, Name, From, Msg, Mod, State, Debug). + terminate(exit, Reason, Stacktrace, false, Name, From, Msg, Mod, State, Debug). -spec terminate(_, _, _, _, _, _, _, _, _) -> no_return(). terminate(Class, Reason, Stacktrace, Name, From, Msg, Mod, State, Debug) -> - ReportReason = {Reason, Stacktrace}, - terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State, Debug). + terminate(Class, Reason, Stacktrace, true, Name, From, Msg, Mod, State, Debug). -spec terminate(_, _, _, _, _, _, _, _, _, _) -> no_return(). -terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State, Debug) -> - Reply = try_terminate(Mod, terminate_reason(Class, Reason, Stacktrace), State), +terminate(Class, Reason, Stacktrace, ReportStacktrace, Name, From, Msg, Mod, State, Debug) -> + Reply = try_terminate(Mod, catch_result(Class, Reason, Stacktrace), State), case Reply of {'EXIT', C, R, S} -> - error_info({R, S}, Name, From, Msg, Mod, State, Debug), + error_info(R, S, Name, From, Msg, Mod, State, Debug), erlang:raise(C, R, S); _ -> case {Class, Reason} of {exit, normal} -> ok; {exit, shutdown} -> ok; {exit, {shutdown,_}} -> ok; - _ -> - error_info(ReportReason, Name, From, Msg, Mod, State, Debug) + _ when ReportStacktrace -> + error_info(Reason, Stacktrace, Name, From, Msg, Mod, State, Debug); + _ -> + error_info(Reason, undefined, Name, From, Msg, Mod, State, Debug) end end, case Stacktrace of @@ -936,22 +1341,41 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State, erlang:raise(Class, Reason, Stacktrace) end. -terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace}; -terminate_reason(exit, Reason, _Stacktrace) -> Reason. +%% What an old style `catch` would return +catch_result(error, Reason, Stacktrace) -> {Reason, Stacktrace}; +catch_result(exit, Reason, _Stacktrace) -> Reason. -error_info(_Reason, application_controller, _From, _Msg, _Mod, _State, _Debug) -> +error_info(_Reason, _ST, application_controller, _From, _Msg, _Mod, _State, _Debug) -> %% OTP-5811 Don't send an error report if it's the system process %% application_controller which is terminating - let init take care %% of it instead ok; -error_info(Reason, Name, From, Msg, Mod, State, Debug) -> +error_info(Reason, ST, Name, From, Msg, Mod, State, Debug) -> Log = sys:get_log(Debug), + Status = + gen:format_status(Mod, terminate, + #{ reason => Reason, + state => State, + message => Msg, + log => Log }, + [get(),State]), + ReportReason = + if ST == undefined -> + %% When ST is undefined, it should not be included in the + %% reported reason for the crash as it is then caused + %% by an invalid return from a callback and thus thus the + %% stacktrace is irrelevant. + maps:get(reason, Status); + true -> + {maps:get(reason, Status), ST} + end, + ?LOG_ERROR(#{label=>{gen_server,terminate}, name=>Name, - last_message=>Msg, - state=>format_status(terminate, Mod, get(), State), - log=>format_log_state(Mod, Log), - reason=>Reason, + last_message=>maps:get(message,Status), + state=>maps:get('EXIT',Status,maps:get('$status',Status,maps:get(state,Status))), + log=>format_log_state(Mod,maps:get(log,Status)), + reason=>ReportReason, client_info=>client_stacktrace(From)}, #{domain=>[otp], report_cb=>fun gen_server:format_log/2, @@ -1206,39 +1630,45 @@ mod(_) -> "t". %% Status information %%----------------------------------------------------------------- format_status(Opt, StatusData) -> - [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time, _HibernateAfterTimeout]] = StatusData, + [PDict, SysState, Parent, Debug, [Name, State, CbCache, _Time, _HibernateAfterTimeout]] = StatusData, + Mod = CbCache#callback_cache.module, Header = gen:format_status_header("Status for generic server", Name), - Log = sys:get_log(Debug), - Specific = case format_status(Opt, Mod, PDict, State) of - S when is_list(S) -> S; - S -> [S] - end, + Status = + case gen:format_status(Mod, Opt, #{ state => State, log => sys:get_log(Debug) }, + [PDict, State]) of + #{ 'EXIT' := R } = M -> + M#{ '$status' => [{data,[{"State",R}]}] }; + %% Status is set when the old format_status/2 is called, + %% so we do a little backwards compatibility dance here + #{ '$status' := S } = M when is_list(S) -> M; + #{ '$status' := S } = M -> M#{ '$status' := [S] }; + #{ state := S } = M -> + M#{ '$status' => [{data, [{"State",S}] }] } + end, [{header, Header}, {data, [{"Status", SysState}, {"Parent", Parent}, - {"Logged events", format_log_state(Mod, Log)}]} | - Specific]. + {"Logged events", format_log_state(Mod, maps:get(log,Status))}]} | + maps:get('$status',Status)]. format_log_state(Mod, Log) -> - [case Event of - {out,Msg,From,State} -> - {out,Msg,From,format_status(terminate, Mod, get(), State)}; - {noreply,State} -> - {noreply,format_status(terminate, Mod, get(), State)}; - _ -> Event - end || Event <- Log]. - -format_status(Opt, Mod, PDict, State) -> - DefStatus = case Opt of - terminate -> State; - _ -> [{data, [{"State", State}]}] - end, - case erlang:function_exported(Mod, format_status, 2) of - true -> - case catch Mod:format_status(Opt, [PDict, State]) of - {'EXIT', _} -> DefStatus; - Else -> Else - end; - _ -> - DefStatus + %% If format_status/1 was exported, the log has already been handled by + %% that call, so we should not pass all log events into the callback again. + case erlang:function_exported(Mod, format_status, 1) of + false -> + [case Event of + {out,Msg,From,State} -> + Status = gen:format_status( + Mod, terminate, #{ state => State }, + [get(), State]), + {out, Msg, From, maps:get(state, Status) }; + {noreply,State} -> + Status = gen:format_status( + Mod, terminate, #{ state => State }, + [get(), State]), + {noreply, maps:get(state, Status)}; + _ -> Event + end || Event <- Log]; + true -> + Log end. diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 178170f40f81..849bf455618d 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2016-2022. All Rights Reserved. +%% Copyright Ericsson AB 2016-2023. 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. @@ -32,8 +32,12 @@ start_monitor/3,start_monitor/4, stop/1,stop/3, cast/2,call/2,call/3, - send_request/2,wait_response/1,wait_response/2, - receive_response/1,receive_response/2,check_response/2, + send_request/2, send_request/4, + wait_response/1, wait_response/2, wait_response/3, + receive_response/1, receive_response/2, receive_response/3, + check_response/2, check_response/3, + reqids_new/0, reqids_size/1, + reqids_add/3, reqids_to_list/1, enter_loop/4,enter_loop/5,enter_loop/6, reply/1,reply/2]). @@ -61,6 +65,7 @@ -export_type( [event_type/0, from/0, + reply_tag/0, callback_mode_result/0, init_result/1, init_result/2, @@ -70,7 +75,10 @@ event_handler_result/2, reply_action/0, enter_action/0, - action/0 + action/0, + request_id/0, + request_id_collection/0, + format_status/0 ]). %% Old types, not advertised -export_type( @@ -85,15 +93,20 @@ [server_name/0, server_ref/0, start_opt/0, + enter_loop_opt/0, start_ret/0, - enter_loop_opt/0]). + start_mon_ret/0]). + +%% -define(DBG(T), erlang:display({{self(), ?MODULE, ?LINE, ?FUNCTION_NAME}, T})). + %%%========================================================================== %%% Interface functions. %%%========================================================================== -type from() :: - {To :: pid(), Tag :: term()}. % Reply-to specifier for call + {To :: pid(), Tag :: reply_tag()}. % Reply-to specifier for call +-opaque reply_tag() :: gen:reply_tag(). -type state() :: state_name() | % For StateName/3 callback functions @@ -110,6 +123,8 @@ -type timeout_event_type() :: 'timeout' | {'timeout', Name :: term()} | 'state_timeout'. +-type event_content() :: term(). + -type callback_mode_result() :: callback_mode() | [callback_mode() | state_enter()]. -type callback_mode() :: 'state_functions' | 'handle_event_function'. @@ -161,7 +176,7 @@ %% action() list is the first to be delivered. {'next_event', % Insert event as the next to handle EventType :: event_type(), - EventContent :: term()} | + EventContent :: event_content()} | {'change_callback_module', NewModule :: module()} | {'push_callback_module', NewModule :: module()} | 'pop_callback_module' | @@ -174,24 +189,24 @@ -type timeout_action() :: (Time :: event_timeout()) | % {timeout,Time,Time} {'timeout', % Set the event_timeout option - Time :: event_timeout(), EventContent :: term()} | + Time :: event_timeout(), EventContent :: event_content()} | {'timeout', % Set the event_timeout option Time :: event_timeout(), - EventContent :: term(), + EventContent :: event_content(), Options :: (timeout_option() | [timeout_option()])} | %% {{'timeout', Name :: term()}, % Set the generic_timeout option - Time :: generic_timeout(), EventContent :: term()} | + Time :: generic_timeout(), EventContent :: event_content()} | {{'timeout', Name :: term()}, % Set the generic_timeout option Time :: generic_timeout(), - EventContent :: term(), + EventContent :: event_content(), Options :: (timeout_option() | [timeout_option()])} | %% {'state_timeout', % Set the state_timeout option - Time :: state_timeout(), EventContent :: term()} | + Time :: state_timeout(), EventContent :: event_content()} | {'state_timeout', % Set the state_timeout option Time :: state_timeout(), - EventContent :: term(), + EventContent :: event_content(), Options :: (timeout_option() | [timeout_option()])} | timeout_cancel_action() | timeout_update_action(). @@ -200,9 +215,10 @@ {{'timeout', Name :: term()}, 'cancel'} | {'state_timeout', 'cancel'}. -type timeout_update_action() :: - {'timeout', 'update', EventContent :: term()} | - {{'timeout', Name :: term()}, 'update', EventContent :: term()} | - {'state_timeout', 'update', EventContent :: term()}. + {'timeout', 'update', EventContent :: event_content()} | + {{'timeout', Name :: term()}, + 'update', EventContent :: event_content()} | + {'state_timeout', 'update', EventContent :: event_content()}. -type reply_action() :: {'reply', % Reply to a caller From :: from(), Reply :: term()}. @@ -212,8 +228,9 @@ {ok, State :: StateType, Data :: DataType} | {ok, State :: StateType, Data :: DataType, Actions :: [action()] | action()} | - 'ignore' | - {'stop', Reason :: term()}. + 'ignore' | + {'stop', Reason :: term()} | + {'error', Reason :: term()}. %% Old, not advertised -type state_function_result() :: @@ -278,7 +295,12 @@ Replies :: [reply_action()] | reply_action(), NewData :: DataType}. --type request_id() :: term(). +-opaque request_id() :: gen:request_id(). + +-opaque request_id_collection() :: gen:request_id_collection(). + +-type response_timeout() :: + timeout() | {abs, integer()}. %% The state machine init function. It is called only once and %% the server is not running until this function has returned @@ -303,11 +325,11 @@ -callback state_name( 'enter', OldStateName :: state_name(), - Data :: data()) -> + data()) -> state_enter_result('state_name'); (event_type(), - EventContent :: term(), - Data :: data()) -> + event_content(), + data()) -> event_handler_result(state_name()). %% %% State callback for all states @@ -315,21 +337,21 @@ -callback handle_event( 'enter', OldState :: state(), - State, % Current state - Data :: data()) -> - state_enter_result(State); + CurrentState, + data()) -> + state_enter_result(CurrentState); (event_type(), - EventContent :: term(), - State :: state(), % Current state - Data :: data()) -> - event_handler_result(state()). + event_content(), + CurrentState :: state(), + data()) -> + event_handler_result(state()). % New state %% Clean up before the server terminates. -callback terminate( Reason :: 'normal' | 'shutdown' | {'shutdown', term()} | term(), - State :: state(), - Data :: data()) -> + CurrentState :: state(), + data()) -> any(). %% Note that the new code can expect to get an OldState from @@ -347,6 +369,8 @@ %% often condensed way. For StatusOption =:= 'normal' the preferred %% return term is [{data,[{"State",FormattedState}]}], and for %% StatusOption =:= 'terminate' it is just FormattedState. +%% +%% Deprecated -callback format_status( StatusOption, [ [{Key :: term(), Value :: term()}] | @@ -355,8 +379,24 @@ Status :: term() when StatusOption :: 'normal' | 'terminate'. +-type format_status() :: + #{ state => state(), + data => data(), + reason => term(), + queue => [{event_type(), event_content()}], + postponed => [{event_type(), event_content()}], + timeouts => [{timeout_event_type(), event_content()}], + log => [sys:system_event()] }. + +%% Format the callback module status in some sensible that is +%% often condensed way. +-callback format_status(Status) -> NewStatus when + Status :: format_status(), + NewStatus :: format_status(). + -optional_callbacks( - [format_status/2, % Has got a default implementation + [format_status/1, % Has got a default implementation + format_status/2, % Has got a default implementation terminate/3, % Has got a default implementation code_change/4, % Only needed by advanced soft upgrade %% @@ -463,7 +503,7 @@ event_type(Type) -> -record(state, {state_data = {undefined,undefined} :: {State :: term(),Data :: term()}, - postponed = [] :: [{event_type(),term()}], + postponed = [] :: [{event_type(),event_content()}], timers = #{t0q => []} :: #{ %% Timeout 0 Queue. @@ -474,38 +514,44 @@ event_type(Type) -> TimeoutType :: timeout_event_type() => {TimerRef :: reference() | 0, - TimeoutMsg :: term()}}, + TimeoutMsg :: event_content()}}, hibernate = false :: boolean() }). %%%========================================================================== %%% API --type server_name() :: - {'global', GlobalName :: term()} - | {'via', RegMod :: module(), Name :: term()} - | {'local', atom()}. --type server_ref() :: +-type server_name() :: % Duplicate of gen:emgr_name() + {'local', atom()} + | {'global', GlobalName :: term()} + | {'via', RegMod :: module(), Name :: term()}. + +-type server_ref() :: % What gen:call/3,4 and gen:stop/1,3 accepts pid() | (LocalName :: atom()) | {Name :: atom(), Node :: atom()} | {'global', GlobalName :: term()} | {'via', RegMod :: module(), ViaName :: term()}. --type start_opt() :: + +-type start_opt() :: % Duplicate of gen:option() {'timeout', Time :: timeout()} - | {'spawn_opt', [proc_lib:start_spawn_option()]} + | {'spawn_opt', [proc_lib:spawn_option()]} | enter_loop_opt(). --type start_ret() :: +%% +-type enter_loop_opt() :: % Some gen:option()s works for enter_loop/* + {'hibernate_after', HibernateAfterTimeout :: timeout()} + | {'debug', Dbgs :: [sys:debug_option()]}. + +-type start_ret() :: % gen:start_ret() without monitor return {'ok', pid()} | 'ignore' | {'error', term()}. --type start_mon_ret() :: + +-type start_mon_ret() :: % gen:start_ret() with only monitor return {'ok', {pid(),reference()}} | 'ignore' | {'error', term()}. --type enter_loop_opt() :: - {'hibernate_after', HibernateAfterTimeout :: timeout()} - | {'debug', Dbgs :: [sys:debug_option()]}. + @@ -599,45 +645,200 @@ call(ServerRef, Request) -> {'dirty_timeout',T :: timeout()}) -> Reply :: term(). call(ServerRef, Request, infinity = T = Timeout) -> - call_dirty(ServerRef, Request, Timeout, T); + call(ServerRef, Request, Timeout, T); call(ServerRef, Request, {dirty_timeout, T} = Timeout) -> - call_dirty(ServerRef, Request, Timeout, T); + call(ServerRef, Request, Timeout, T); call(ServerRef, Request, {clean_timeout, T} = Timeout) -> - call_clean(ServerRef, Request, Timeout, T); + call(ServerRef, Request, Timeout, T); call(ServerRef, Request, {_, _} = Timeout) -> erlang:error(badarg, [ServerRef,Request,Timeout]); call(ServerRef, Request, Timeout) -> - call_clean(ServerRef, Request, Timeout, Timeout). + call(ServerRef, Request, Timeout, Timeout). -spec send_request(ServerRef::server_ref(), Request::term()) -> - RequestId::request_id(). + ReqId::request_id(). send_request(Name, Request) -> - gen:send_request(Name, '$gen_call', Request). + try + gen:send_request(Name, '$gen_call', Request) + catch + error:badarg -> + error(badarg, [Name, Request]) + end. + +-spec send_request(ServerRef::server_ref(), + Request::term(), + Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). + +send_request(ServerRef, Request, Label, ReqIdCol) -> + try + gen:send_request(ServerRef, '$gen_call', Request, Label, ReqIdCol) + catch + error:badarg -> + error(badarg, [ServerRef, Request, Label, ReqIdCol]) + end. + + +-spec wait_response(ReqId) -> Result when + ReqId :: request_id(), + Response :: {reply, Reply::term()} + | {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +wait_response(ReqId) -> + wait_response(ReqId, infinity). + +-spec wait_response(ReqId, WaitTime) -> Result when + ReqId :: request_id(), + WaitTime :: response_timeout(), + Response :: {reply, Reply::term()} + | {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +wait_response(ReqId, WaitTime) -> + try + gen:wait_response(ReqId, WaitTime) + catch + error:badarg -> + error(badarg, [ReqId, WaitTime]) + end. + +-spec wait_response(ReqIdCollection, WaitTime, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + WaitTime :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +wait_response(ReqIdCol, WaitTime, Delete) -> + try + gen:wait_response(ReqIdCol, WaitTime, Delete) + catch + error:badarg -> + error(badarg, [ReqIdCol, WaitTime, Delete]) + end. + +-spec receive_response(ReqId) -> Result when + ReqId :: request_id(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +receive_response(ReqId) -> + receive_response(ReqId, infinity). + +-spec receive_response(ReqId, Timeout) -> Result when + ReqId :: request_id(), + Timeout :: response_timeout(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: Response | 'timeout'. + +receive_response(ReqId, Timeout) -> + try + gen:receive_response(ReqId, Timeout) + catch + error:badarg -> + error(badarg, [ReqId, Timeout]) + end. + +-spec receive_response(ReqIdCollection, Timeout, Delete) -> Result when + ReqIdCollection :: request_id_collection(), + Timeout :: response_timeout(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'timeout'. + +receive_response(ReqIdCol, Timeout, Delete) -> + try + gen:receive_response(ReqIdCol, Timeout, Delete) + catch + error:badarg -> + error(badarg, [ReqIdCol, Timeout, Delete]) + end. + +-spec check_response(Msg, ReqId) -> Result when + Msg :: term(), + ReqId :: request_id(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: Response | 'no_reply'. + +check_response(Msg, ReqId) -> + try + gen:check_response(Msg, ReqId) + catch + error:badarg -> + error(badarg, [Msg, ReqId]) + end. + +-spec check_response(Msg, ReqIdCollection, Delete) -> Result when + Msg :: term(), + ReqIdCollection :: request_id_collection(), + Delete :: boolean(), + Response :: {reply, Reply::term()} | + {error, {Reason::term(), server_ref()}}, + Result :: {Response, + Label::term(), + NewReqIdCollection::request_id_collection()} | + 'no_request' | + 'no_reply'. + +check_response(Msg, ReqIdCol, Delete) -> + try + gen:check_response(Msg, ReqIdCol, Delete) + catch + error:badarg -> + error(badarg, [Msg, ReqIdCol, Delete]) + end. + +-spec reqids_new() -> + NewReqIdCollection::request_id_collection(). + +reqids_new() -> + gen:reqids_new(). --spec wait_response(RequestId::request_id()) -> - {reply, Reply::term()} | {error, {term(), server_ref()}}. -wait_response(RequestId) -> - gen:wait_response(RequestId, infinity). +-spec reqids_size(ReqIdCollection::request_id_collection()) -> + non_neg_integer(). --spec wait_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. -wait_response(RequestId, Timeout) -> - gen:wait_response(RequestId, Timeout). +reqids_size(ReqIdCollection) -> + try + gen:reqids_size(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) + end. --spec receive_response(RequestId::request_id()) -> - {reply, Reply::term()} | {error, {term(), server_ref()}}. -receive_response(RequestId) -> - gen:receive_response(RequestId, infinity). +-spec reqids_add(ReqId::request_id(), Label::term(), + ReqIdCollection::request_id_collection()) -> + NewReqIdCollection::request_id_collection(). + +reqids_add(ReqId, Label, ReqIdCollection) -> + try + gen:reqids_add(ReqId, Label, ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqId, Label, ReqIdCollection]) + end. --spec receive_response(RequestId::request_id(), timeout()) -> - {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. -receive_response(RequestId, Timeout) -> - gen:receive_response(RequestId, Timeout). +-spec reqids_to_list(ReqIdCollection::request_id_collection()) -> + [{ReqId::request_id(), Label::term()}]. --spec check_response(Msg::term(), RequestId::request_id()) -> - {reply, Reply::term()} | 'no_reply' | {error, {term(), server_ref()}}. -check_response(Msg, RequestId) -> - gen:check_response(Msg, RequestId). +reqids_to_list(ReqIdCollection) -> + try + gen:reqids_to_list(ReqIdCollection) + catch + error:badarg -> error(badarg, [ReqIdCollection]) + end. %% Reply from a state machine callback to whom awaits in call/2 -spec reply([reply_action()] | reply_action()) -> ok. @@ -699,68 +900,21 @@ enter_loop(Module, Opts, State, Data, Server, Actions) -> wrap_cast(Event) -> {'$gen_cast',Event}. -call_dirty(ServerRef, Request, Timeout, T) -> +-compile({inline, [call/4]}). +call(ServerRef, Request, Timeout, T) -> try gen:call(ServerRef, '$gen_call', Request, T) of {ok,Reply} -> Reply catch - Class:Reason:Stacktrace -> + %% 'gen' raises 'exit' for problems + Class:Reason:Stacktrace when Class =:= exit -> erlang:raise( Class, + %% Wrap the reason according to tradition {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}}, Stacktrace) end. -call_clean(ServerRef, Request, Timeout, T) - when (is_pid(ServerRef) - andalso (node(ServerRef) == node())) - orelse (element(2, ServerRef) == node() - andalso is_atom(element(1, ServerRef)) - andalso (tuple_size(ServerRef) =:= 2)) -> - %% No need to use a proxy locally since we know alias will be - %% used as of OTP 24 which will prevent garbage responses... - call_dirty(ServerRef, Request, Timeout, T); -call_clean(ServerRef, Request, Timeout, T) -> - %% Call server through proxy process to dodge any late reply - %% - %% We still need a proxy in the distributed case since we may - %% communicate with a node that does not understand aliases. - %% This can be removed when alias support is mandatory. - %% Probably in OTP 26. - Ref = make_ref(), - Self = self(), - Pid = spawn( - fun () -> - Self ! - try gen:call( - ServerRef, '$gen_call', Request, T) of - Result -> - {Ref,Result} - catch Class:Reason:Stacktrace -> - {Ref,Class,Reason,Stacktrace} - end - end), - Mref = monitor(process, Pid), - receive - {Ref,Result} -> - demonitor(Mref, [flush]), - case Result of - {ok,Reply} -> - Reply - end; - {Ref,Class,Reason,Stacktrace} -> - demonitor(Mref, [flush]), - erlang:raise( - Class, - {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}}, - Stacktrace); - {'DOWN',Mref,_,_,Reason} -> - %% There is a theoretical possibility that the - %% proxy process gets killed between try--of and ! - %% so this clause is in case of that - exit(Reason) - end. - replies([{reply,From,Reply}|Replies]) -> reply(From, Reply), replies(Replies); @@ -821,12 +975,12 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) -> Name, Debug, HibernateAfterTimeout); Class:Reason:Stacktrace -> gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, {error,Reason}), error_info( Class, Reason, Stacktrace, Debug, #params{parent = Parent, name = Name, modules = [Module]}, #state{}, []), - erlang:raise(Class, Reason, Stacktrace) + proc_lib:init_fail( + Starter, {error,Reason}, {Class,Reason,Stacktrace}) end. %%--------------------------------------------------------------------------- @@ -848,21 +1002,24 @@ init_result( State, Data, Actions); {stop,Reason} -> gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, {error,Reason}), - exit(Reason); + exit(Reason); + {error, _Reason} = ERROR -> + %% The point of this clause is that we shall have a *silent* + %% termination. The error reason will be returned to the + %% 'Starter' ({error, Reason}), but *no* crash report. + gen:unregister_name(ServerRef), + proc_lib:init_fail(Starter, ERROR, {exit,normal}); ignore -> gen:unregister_name(ServerRef), - proc_lib:init_ack(Starter, ignore), - exit(normal); + proc_lib:init_fail(Starter, ignore, {exit,normal}); _ -> gen:unregister_name(ServerRef), - Error = {bad_return_from_init,Result}, - proc_lib:init_ack(Starter, {error,Error}), + Reason = {bad_return_from_init,Result}, error_info( - error, Error, ?STACKTRACE(), Debug, + error, Reason, ?STACKTRACE(), Debug, #params{parent = Parent, name = Name, modules = [Module]}, #state{}, []), - exit(Error) + exit(Reason) end. %%%========================================================================== @@ -917,22 +1074,39 @@ system_replace_state( format_status( Opt, [PDict,SysState,Parent,Debug, - {#params{name = Name, modules = Modules} = P, - #state{postponed = Postponed, timers = Timers} = S}]) -> + {#params{name = Name, modules = [Mod | _] = Modules}, + #state{postponed = Postponed, timers = Timers, + state_data = {State,Data}}}]) -> Header = gen:format_status_header("Status for state machine", Name), - Log = sys:get_log(Debug), + + {NumTimers, ListTimers} = list_timeouts(Timers), + StatusMap = #{ state => State, data => Data, + postponed => Postponed, log => sys:get_log(Debug), + timeouts => ListTimers + }, + + NewStatusMap = + case gen:format_status(Mod, Opt, StatusMap, [PDict,State,Data]) of + #{ 'EXIT' := R } -> + Crashed = [{data,[{"State",{State,R}}]}], + StatusMap#{ '$status' => Crashed }; + %% Status is set when the old format_status/2 is called, + %% so we do a little backwards compatibility dance here + #{ '$status' := L } = SM when is_list(L) -> SM; + #{ '$status' := T } = SM -> SM#{ '$status' := [T] }; + #{ state := S, data := D } = SM -> + SM#{ '$status' => [{data,[{"State",{S,D}}]}]} + end, + [{header,Header}, {data, [{"Status",SysState}, {"Parent",Parent}, {"Modules",Modules}, - {"Time-outs",list_timeouts(Timers)}, - {"Logged Events",Log}, - {"Postponed",Postponed}]} | - case format_status(Opt, PDict, update_parent(P, Parent), S) of - L when is_list(L) -> L; - T -> [T] - end]. + {"Time-outs",{NumTimers,maps:get(timeouts,NewStatusMap)}}, + {"Logged Events",maps:get(log,NewStatusMap)}, + {"Postponed",maps:get(postponed,NewStatusMap)}]} | + maps:get('$status',NewStatusMap)]. %% Update #params.parent only if it differs. This should not %% be possible today (OTP-22.0), but could happen for example @@ -2413,25 +2587,44 @@ error_info( Class, Reason, Stacktrace, Debug, #params{ name = Name, - modules = Modules, + modules = [Mod|_] = Modules, callback_mode = CallbackMode, - state_enter = StateEnter} = P, + state_enter = StateEnter}, #state{ postponed = Postponed, - timers = Timers} = S, + timers = Timers, + state_data = {State,Data}}, Q) -> - Log = sys:get_log(Debug), + + {NumTimers,ListTimers} = list_timeouts(Timers), + + Status = + gen:format_status(Mod, terminate, + #{ reason => Reason, + state => State, + data => Data, + queue => Q, + postponed => Postponed, + timeouts => ListTimers, + log => sys:get_log(Debug)}, + [get(),State,Data]), + NewState = case maps:find('$status', Status) of + error -> + {maps:get(state,Status),maps:get(data,Status)}; + {ok, S} -> + S + end, ?LOG_ERROR(#{label=>{gen_statem,terminate}, name=>Name, - queue=>Q, - postponed=>Postponed, + queue=>maps:get(queue,Status), + postponed=>maps:get(postponed,Status), modules=>Modules, callback_mode=>CallbackMode, state_enter=>StateEnter, - state=>format_status(terminate, get(), P, S), - timeouts=>list_timeouts(Timers), - log=>Log, - reason=>{Class,Reason,Stacktrace}, + state=>NewState, + timeouts=>{NumTimers,maps:get(timeouts,Status)}, + log=>maps:get(log,Status), + reason=>{Class,maps:get(reason,Status),Stacktrace}, client_info=>client_stacktrace(Q)}, #{domain=>[otp], report_cb=>fun gen_statem:format_log/2, @@ -2764,34 +2957,6 @@ single(false) -> "". mod(latin1) -> ""; mod(_) -> "t". -%% Call Module:format_status/2 or return a default value -format_status( - Opt, PDict, - #params{modules = [Module | _]}, - #state{state_data = {State,Data} = State_Data}) -> - case erlang:function_exported(Module, format_status, 2) of - true -> - try Module:format_status(Opt, [PDict,State,Data]) - catch - Result -> Result; - _:_ -> - format_status_default( - Opt, - {State, - atom_to_list(Module) ++ ":format_status/2 crashed"}) - end; - false -> - format_status_default(Opt, State_Data) - end. - -%% The default Module:format_status/3 -format_status_default(Opt, State_Data) -> - case Opt of - terminate -> - State_Data; - _ -> - [{data,[{"State",State_Data}]}] - end. -compile({inline, [listify/1]}). listify(Item) when is_list(Item) -> @@ -2860,9 +3025,6 @@ cancel_timer(TimeoutType, Timers) -> %% Return a list of all pending timeouts list_timeouts(Timers) -> {maps:size(Timers) - 1, % Subtract fixed key 't0q' - maps:fold( - fun (t0q, _, Acc) -> - Acc; - (TimeoutType, {_TimerRef,TimeoutMsg}, Acc) -> - [{TimeoutType,TimeoutMsg}|Acc] - end, [], Timers)}. + [{TimeoutType, TimeoutMsg} + || TimeoutType := {_TimerRef, TimeoutMsg} <- Timers, + TimeoutType =/= t0q]}. diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl index d7158f64a8b8..2c3823bdc6ff 100644 --- a/lib/stdlib/src/io.erl +++ b/lib/stdlib/src/io.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -36,11 +36,15 @@ %% Implemented in native code -export([printable_range/0]). --export_type([device/0, format/0, server_no_data/0]). +-export_type([device/0, format/0, server_no_data/0, + standard_io/0, standard_error/0, user/0]). %%------------------------------------------------------------------------- --type device() :: atom() | pid(). +-type standard_io() :: standard_io. +-type standard_error() :: standard_error. +-type user() :: user. +-type device() :: atom() | pid() | standard_io() | standard_error() | user(). -type prompt() :: atom() | unicode:chardata(). %% ErrorDescription is whatever the I/O-server sends. @@ -209,19 +213,22 @@ get_password(Io) -> -type encoding() :: 'latin1' | 'unicode' | 'utf8' | 'utf16' | 'utf32' | {'utf16', 'big' | 'little'} | {'utf32','big' | 'little'}. --type expand_fun() :: fun((term()) -> {'yes'|'no', string(), [string(), ...]}). +-type expand_fun() :: fun((string()) -> {'yes'|'no', string(), list()}). -type opt_pair() :: {'binary', boolean()} | {'echo', boolean()} | {'expand_fun', expand_fun()} - | {'encoding', encoding()}. + | {'encoding', encoding()} + | {atom(), term()}. +-type get_opt_pair() :: opt_pair() + | {'terminal', boolean()}. --spec getopts() -> [opt_pair()] | {'error', Reason} when +-spec getopts() -> [get_opt_pair()] | {'error', Reason} when Reason :: term(). getopts() -> getopts(default_input()). --spec getopts(IoDevice) -> [opt_pair()] | {'error', Reason} when +-spec getopts(IoDevice) -> [get_opt_pair()] | {'error', Reason} when IoDevice :: device(), Reason :: term(). @@ -335,6 +342,7 @@ read(Io, Prompt, Pos0, Options) -> conv_reason(arguments) -> badarg; conv_reason(terminated) -> terminated; +conv_reason(calling_self) -> calling_self; conv_reason({no_translation,_,_}) -> no_translation; conv_reason(_Reason) -> badarg. @@ -596,6 +604,8 @@ request(Name, Request, ErrorTag) when is_atom(Name) -> request(Pid, Request, ErrorTag) end. +execute_request(Pid, _Tuple, ErrorTag) when Pid =:= self() -> + {ErrorTag, calling_self}; execute_request(Pid, {Convert,Converted}, ErrorTag) -> Mref = erlang:monitor(process, Pid), Pid ! {io_request,self(),Mref,Converted}, diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl index e2823b70f215..87010361c050 100644 --- a/lib/stdlib/src/io_lib.erl +++ b/lib/stdlib/src/io_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2019. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -124,7 +124,9 @@ precision := 'none' | integer(), pad_char := char(), encoding := 'unicode' | 'latin1', - strings := boolean() + strings := boolean(), + % `maps_order` has been added since OTP26 and is optional + maps_order => maps:iterator_order() }. %%---------------------------------------------------------------------- @@ -322,7 +324,7 @@ add_modifier(_, C) -> Term :: term(). write(Term) -> - write1(Term, -1, latin1). + write1(Term, -1, latin1, undefined). -spec write(term(), depth(), boolean()) -> chars(). @@ -347,64 +349,65 @@ write(Term, Options) when is_list(Options) -> Depth = get_option(depth, Options, -1), Encoding = get_option(encoding, Options, epp:default_encoding()), CharsLimit = get_option(chars_limit, Options, -1), + MapsOrder = get_option(maps_order, Options, undefined), if Depth =:= 0; CharsLimit =:= 0 -> "..."; - CharsLimit < 0 -> - write1(Term, Depth, Encoding); - CharsLimit > 0 -> + is_integer(CharsLimit), CharsLimit < 0, is_integer(Depth) -> + write1(Term, Depth, Encoding, MapsOrder); + is_integer(CharsLimit), CharsLimit > 0 -> RecDefFun = fun(_, _) -> no end, If = io_lib_pretty:intermediate - (Term, Depth, CharsLimit, RecDefFun, Encoding, _Str=false), + (Term, Depth, CharsLimit, RecDefFun, Encoding, _Str=false, MapsOrder), io_lib_pretty:write(If) end; write(Term, Depth) -> write(Term, [{depth, Depth}, {encoding, latin1}]). -write1(_Term, 0, _E) -> "..."; -write1(Term, _D, _E) when is_integer(Term) -> integer_to_list(Term); -write1(Term, _D, _E) when is_float(Term) -> io_lib_format:fwrite_g(Term); -write1(Atom, _D, latin1) when is_atom(Atom) -> write_atom_as_latin1(Atom); -write1(Atom, _D, _E) when is_atom(Atom) -> write_atom(Atom); -write1(Term, _D, _E) when is_port(Term) -> write_port(Term); -write1(Term, _D, _E) when is_pid(Term) -> pid_to_list(Term); -write1(Term, _D, _E) when is_reference(Term) -> write_ref(Term); -write1(<<_/bitstring>>=Term, D, _E) -> write_binary(Term, D); -write1([], _D, _E) -> "[]"; -write1({}, _D, _E) -> "{}"; -write1([H|T], D, E) -> +write1(_Term, 0, _E, _O) -> "..."; +write1(Term, _D, _E, _O) when is_integer(Term) -> integer_to_list(Term); +write1(Term, _D, _E, _O) when is_float(Term) -> io_lib_format:fwrite_g(Term); +write1(Atom, _D, latin1, _O) when is_atom(Atom) -> write_atom_as_latin1(Atom); +write1(Atom, _D, _E, _O) when is_atom(Atom) -> write_atom(Atom); +write1(Term, _D, _E, _O) when is_port(Term) -> write_port(Term); +write1(Term, _D, _E, _O) when is_pid(Term) -> pid_to_list(Term); +write1(Term, _D, _E, _O) when is_reference(Term) -> write_ref(Term); +write1(<<_/bitstring>>=Term, D, _E, _O) -> write_binary(Term, D); +write1([], _D, _E, _O) -> "[]"; +write1({}, _D, _E, _O) -> "{}"; +write1([H|T], D, E, O) -> if D =:= 1 -> "[...]"; true -> - [$[,[write1(H, D-1, E)|write_tail(T, D-1, E)],$]] + [$[,[write1(H, D-1, E, O)|write_tail(T, D-1, E, O)],$]] end; -write1(F, _D, _E) when is_function(F) -> +write1(F, _D, _E, _O) when is_function(F) -> erlang:fun_to_list(F); -write1(Term, D, E) when is_map(Term) -> - write_map(Term, D, E); -write1(T, D, E) when is_tuple(T) -> +write1(Term, D, E, O) when is_map(Term) -> + write_map(Term, D, E, O); +write1(T, D, E, O) when is_tuple(T) -> if D =:= 1 -> "{...}"; true -> [${, - [write1(element(1, T), D-1, E)|write_tuple(T, 2, D-1, E)], + [write1(element(1, T), D-1, E, O)|write_tuple(T, 2, D-1, E, O)], $}] end. %% write_tail(List, Depth, Encoding) %% Test the terminating case first as this looks better with depth. -write_tail([], _D, _E) -> ""; -write_tail(_, 1, _E) -> [$| | "..."]; -write_tail([H|T], D, E) -> - [$,,write1(H, D-1, E)|write_tail(T, D-1, E)]; -write_tail(Other, D, E) -> - [$|,write1(Other, D-1, E)]. +write_tail([], _D, _E, _O) -> ""; +write_tail(_, 1, _E, _O) -> [$| | "..."]; +write_tail([H|T], D, E, O) -> + [$,,write1(H, D-1, E, O)|write_tail(T, D-1, E, O)]; +write_tail(Other, D, E, O) -> + [$|,write1(Other, D-1, E, O)]. -write_tuple(T, I, _D, _E) when I > tuple_size(T) -> ""; -write_tuple(_, _I, 1, _E) -> [$, | "..."]; -write_tuple(T, I, D, E) -> - [$,,write1(element(I, T), D-1, E)|write_tuple(T, I+1, D-1, E)]. +write_tuple(T, I, _D, _E, _O) when I > tuple_size(T) -> ""; +write_tuple(_, _I, 1, _E, _O) -> [$, | "..."]; +write_tuple(T, I, D, E, O) -> + [$,,write1(element(I, T), D-1, E, O)|write_tuple(T, I+1, D-1, E, O)]. write_port(Port) -> erlang:port_to_list(Port). @@ -412,34 +415,34 @@ write_port(Port) -> write_ref(Ref) -> erlang:ref_to_list(Ref). -write_map(_, 1, _E) -> "#{}"; -write_map(Map, D, E) when is_integer(D) -> - I = maps:iterator(Map), +write_map(_, 1, _E, _O) -> "#{}"; +write_map(Map, D, E, O) when is_integer(D) -> + I = maps:iterator(Map, O), case maps:next(I) of {K, V, NextI} -> D0 = D - 1, - W = write_map_assoc(K, V, D0, E), - [$#,${,[W | write_map_body(NextI, D0, D0, E)],$}]; + W = write_map_assoc(K, V, D0, E, O), + [$#,${,[W | write_map_body(NextI, D0, D0, E, O)],$}]; none -> "#{}" end. -write_map_body(_, 1, _D0, _E) -> ",..."; -write_map_body(I, D, D0, E) -> +write_map_body(_, 1, _D0, _E, _O) -> ",..."; +write_map_body(I, D, D0, E, O) -> case maps:next(I) of {K, V, NextI} -> - W = write_map_assoc(K, V, D0, E), - [$,,W|write_map_body(NextI, D - 1, D0, E)]; + W = write_map_assoc(K, V, D0, E, O), + [$,,W|write_map_body(NextI, D - 1, D0, E, O)]; none -> "" end. -write_map_assoc(K, V, D, E) -> - [write1(K, D, E)," => ",write1(V, D, E)]. +write_map_assoc(K, V, D, E, O) -> + [write1(K, D, E, O)," => ",write1(V, D, E, O)]. write_binary(B, D) when is_integer(D) -> {S, _} = write_binary(B, D, -1), S. -write_binary(B, D, T) -> +write_binary(B, D, T) when is_integer(T) -> {S, Rest} = write_binary_body(B, D, tsub(T, 4), []), {[$<,$<,lists:reverse(S),$>,$>], Rest}. @@ -509,15 +512,16 @@ quote_atom(Atom, Cs0) -> true -> true; false -> case Cs0 of - [C|Cs] when C >= $a, C =< $z -> + [C|Cs] when is_integer(C), C >= $a, C =< $z -> not name_chars(Cs); - [C|Cs] when C >= $ß, C =< $ÿ, C =/= $÷ -> + [C|Cs] when is_integer(C), C >= $ß, C =< $ÿ, C =/= $÷ -> not name_chars(Cs); - _ -> true + [C|_] when is_integer(C) -> true; + [] -> true end end. -name_chars([C|Cs]) -> +name_chars([C|Cs]) when is_integer(C) -> case name_char(C) of true -> name_chars(Cs); false -> false @@ -580,7 +584,7 @@ write_string_as_latin1(S, Q) -> write_string1(_,[], Q) -> [Q]; -write_string1(Enc,[C|Cs], Q) -> +write_string1(Enc,[C|Cs], Q) when is_integer(C) -> string_char(Enc,C, Q, write_string1(Enc,Cs, Q)). string_char(_,Q, Q, Tail) -> [$\\,Q|Tail]; %Must check these first! @@ -803,7 +807,7 @@ collect_chars(Tag, Data, N) -> collect_chars(Tag, Data, latin1, N). %% Now we are aware of encoding... -collect_chars(start, Data, unicode, N) when is_binary(Data) -> +collect_chars(start, Data, unicode, N) when is_binary(Data), is_integer(N) -> {Size,Npos} = count_and_find_utf8(Data,N), if Size > N -> {B1,B2} = split_binary(Data, Npos), @@ -811,9 +815,9 @@ collect_chars(start, Data, unicode, N) when is_binary(Data) -> Size < N -> {binary,[Data],N-Size}; true -> - {stop,Data,eof} + {stop,Data,<<>>} end; -collect_chars(start, Data, latin1, N) when is_binary(Data) -> +collect_chars(start, Data, latin1, N) when is_binary(Data), is_integer(N) -> Size = byte_size(Data), if Size > N -> {B1,B2} = split_binary(Data, N), @@ -821,15 +825,17 @@ collect_chars(start, Data, latin1, N) when is_binary(Data) -> Size < N -> {binary,[Data],N-Size}; true -> - {stop,Data,eof} + {stop,Data,<<>>} end; -collect_chars(start,Data,_,N) when is_list(Data) -> +collect_chars(start,Data,_,N) when is_list(Data), is_integer(N) -> collect_chars_list([], N, Data); collect_chars(start, eof, _,_) -> {stop,eof,eof}; +collect_chars({binary,[<<>>],_N}, eof, _,_) -> + {stop,eof,eof}; collect_chars({binary,Stack,_N}, eof, _,_) -> {stop,binrev(Stack),eof}; -collect_chars({binary,Stack,N}, Data,unicode, _) -> +collect_chars({binary,Stack,N}, Data,unicode, _) when is_integer(N) -> {Size,Npos} = count_and_find_utf8(Data,N), if Size > N -> {B1,B2} = split_binary(Data, Npos), @@ -837,9 +843,9 @@ collect_chars({binary,Stack,N}, Data,unicode, _) -> Size < N -> {binary,[Data|Stack],N-Size}; true -> - {stop,binrev(Stack, [Data]),eof} + {stop,binrev(Stack, [Data]),<<>>} end; -collect_chars({binary,Stack,N}, Data,latin1, _) -> +collect_chars({binary,Stack,N}, Data,latin1, _) when is_integer(N) -> Size = byte_size(Data), if Size > N -> {B1,B2} = split_binary(Data, N), @@ -847,9 +853,9 @@ collect_chars({binary,Stack,N}, Data,latin1, _) -> Size < N -> {binary,[Data|Stack],N-Size}; true -> - {stop,binrev(Stack, [Data]),eof} + {stop,binrev(Stack, [Data]),<<>>} end; -collect_chars({list,Stack,N}, Data, _,_) -> +collect_chars({list,Stack,N}, Data, _,_) when is_integer(N) -> collect_chars_list(Stack, N, Data); %% collect_chars(Continuation, MoreChars, Count) @@ -857,9 +863,9 @@ collect_chars({list,Stack,N}, Data, _,_) -> %% {done,Result,RestChars} %% {more,Continuation} -collect_chars([], Chars, _, N) -> +collect_chars([], Chars, _, N) when is_integer(N) -> collect_chars1(N, Chars, []); -collect_chars({Left,Sofar}, Chars, _, _N) -> +collect_chars({Left,Sofar}, Chars, _, _N) when is_integer(Left) -> collect_chars1(Left, Chars, Sofar). collect_chars1(N, Chars, Stack) when N =< 0 -> @@ -875,6 +881,8 @@ collect_chars1(N, [], Stack) -> collect_chars_list(Stack, 0, Data) -> {stop,lists:reverse(Stack, []),Data}; +collect_chars_list([], _N, eof) -> + {stop,eof,eof}; collect_chars_list(Stack, _N, eof) -> {stop,lists:reverse(Stack, []),eof}; collect_chars_list(Stack, N, []) -> @@ -991,13 +999,13 @@ binrev(L) -> binrev(L, T) -> list_to_binary(lists:reverse(L, T)). --spec limit_term(term(), non_neg_integer()) -> term(). +-spec limit_term(term(), depth()) -> term(). %% The intention is to mimic the depth limitation of io_lib:write() %% and io_lib_pretty:print(). The leaves ('...') should never be %% seen when printed with the same depth. Bitstrings are never %% truncated, which is OK as long as they are not sent to other nodes. -limit_term(Term, Depth) -> +limit_term(Term, Depth) when is_integer(Depth), Depth >= -1 -> try test_limit(Term, Depth) of ok -> Term catch diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl index 40b84405e84b..813125abd99a 100644 --- a/lib/stdlib/src/io_lib_format.erl +++ b/lib/stdlib/src/io_lib_format.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -106,6 +106,8 @@ scan(Format, Args) -> unscan(Cs) -> {print(Cs), args(Cs)}. +args([#{args := As, maps_order := O} | Cs]) when is_function(O, 2); O =:= reversed -> + [O | As] ++ args(Cs); args([#{args := As} | Cs]) -> As ++ args(Cs); args([_C | Cs]) -> @@ -114,17 +116,20 @@ args([]) -> []. print([#{control_char := C, width := F, adjust := Ad, precision := P, - pad_char := Pad, encoding := Encoding, strings := Strings} | Cs]) -> - print(C, F, Ad, P, Pad, Encoding, Strings) ++ print(Cs); -print([C | Cs]) -> + pad_char := Pad, encoding := Encoding, strings := Strings + } = Map | Cs]) -> + MapsOrder = maps:get(maps_order, Map, undefined), + print(C, F, Ad, P, Pad, Encoding, Strings, MapsOrder) ++ print(Cs); +print([C | Cs]) when is_integer(C) -> [C | print(Cs)]; print([]) -> []. -print(C, F, Ad, P, Pad, Encoding, Strings) -> +print(C, F, Ad, P, Pad, Encoding, Strings, MapsOrder) -> [$~] ++ print_field_width(F, Ad) ++ print_precision(P, Pad) ++ print_pad_char(Pad) ++ print_encoding(Encoding) ++ - print_strings(Strings) ++ [C]. + print_strings(Strings) ++ print_maps_order(MapsOrder) ++ + [C]. print_field_width(none, _Ad) -> ""; print_field_width(F, left) -> integer_to_list(-F); @@ -143,6 +148,11 @@ print_encoding(latin1) -> "". print_strings(false) -> "l"; print_strings(true) -> "". +print_maps_order(undefined) -> ""; +print_maps_order(ordered) -> "k"; +print_maps_order(reversed) -> "K"; +print_maps_order(CmpFun) when is_function(CmpFun, 2) -> "K". + collect([$~|Fmt0], Args0) -> {C,Fmt1,Args1} = collect_cseq(Fmt0, Args0), [C|collect(Fmt1, Args1)]; @@ -159,18 +169,23 @@ collect_cseq(Fmt0, Args0) -> precision => P, pad_char => Pad, encoding => latin1, - strings => true}, - {Spec1,Fmt4} = modifiers(Fmt3, Spec0), - {C,As,Fmt5,Args4} = collect_cc(Fmt4, Args3), + strings => true, + maps_order => undefined}, + {Spec1,Fmt4,Args4} = modifiers(Fmt3, Args3, Spec0), + {C,As,Fmt5,Args5} = collect_cc(Fmt4, Args4), Spec2 = Spec1#{control_char => C, args => As}, - {Spec2,Fmt5,Args4}. - -modifiers([$t|Fmt], Spec) -> - modifiers(Fmt, Spec#{encoding => unicode}); -modifiers([$l|Fmt], Spec) -> - modifiers(Fmt, Spec#{strings => false}); -modifiers(Fmt, Spec) -> - {Spec, Fmt}. + {Spec2,Fmt5,Args5}. + +modifiers([$t|Fmt], Args, Spec) -> + modifiers(Fmt, Args, Spec#{encoding => unicode}); +modifiers([$l|Fmt], Args, Spec) -> + modifiers(Fmt, Args, Spec#{strings => false}); +modifiers([$k|Fmt], Args, Spec) -> + modifiers(Fmt, Args, Spec#{maps_order => ordered}); +modifiers([$K|Fmt], [MapsOrder | Args], Spec) -> + modifiers(Fmt, Args, Spec#{maps_order => MapsOrder}); +modifiers(Fmt, Args, Spec) -> + {Spec, Fmt, Args}. field_width([$-|Fmt0], Args0) -> {F,Fmt,Args} = field_value(Fmt0, Args0), @@ -274,12 +289,14 @@ build_small([]) -> []. build_limited([#{control_char := C, args := As, width := F, adjust := Ad, precision := P, pad_char := Pad, encoding := Enc, - strings := Str} | Cs], NumOfPs0, Count0, MaxLen0, I) -> + strings := Str} = Map | Cs], + NumOfPs0, Count0, MaxLen0, I) -> + Ord = maps:get(maps_order, Map, undefined), MaxChars = if MaxLen0 < 0 -> MaxLen0; true -> MaxLen0 div Count0 end, - S = control_limited(C, As, F, Ad, P, Pad, Enc, Str, MaxChars, I), + S = control_limited(C, As, F, Ad, P, Pad, Enc, Str, Ord, MaxChars, I), NumOfPs = decr_pc(C, NumOfPs0), Count = Count0 - 1, MaxLen = if @@ -371,24 +388,34 @@ control_small($n, [], F, Adj, P, Pad, _Enc) -> newline(F, Adj, P, Pad); control_small($i, [_A], _F, _Adj, _P, _Pad, _Enc) -> []; control_small(_C, _As, _F, _Adj, _P, _Pad, _Enc) -> not_small. -control_limited($s, [L0], F, Adj, P, Pad, latin1=Enc, _Str, CL, _I) -> +control_limited($s, [L0], F, Adj, P, Pad, latin1=Enc, _Str, _Ord, CL, _I) -> L = iolist_to_chars(L0, F, CL), string(L, limit_field(F, CL), Adj, P, Pad, Enc); -control_limited($s, [L0], F, Adj, P, Pad, unicode=Enc, _Str, CL, _I) -> +control_limited($s, [L0], F, Adj, P, Pad, unicode=Enc, _Str, _Ord, CL, _I) -> L = cdata_to_chars(L0, F, CL), uniconv(string(L, limit_field(F, CL), Adj, P, Pad, Enc)); -control_limited($w, [A], F, Adj, P, Pad, Enc, _Str, CL, _I) -> - Chars = io_lib:write(A, [{depth, -1}, {encoding, Enc}, {chars_limit, CL}]), +control_limited($w, [A], F, Adj, P, Pad, Enc, _Str, Ord, CL, _I) -> + Chars = io_lib:write(A, [ + {depth, -1}, + {encoding, Enc}, + {chars_limit, CL}, + {maps_order, Ord} + ]), term(Chars, F, Adj, P, Pad); -control_limited($p, [A], F, Adj, P, Pad, Enc, Str, CL, I) -> - print(A, -1, F, Adj, P, Pad, Enc, Str, CL, I); -control_limited($W, [A,Depth], F, Adj, P, Pad, Enc, _Str, CL, _I) +control_limited($p, [A], F, Adj, P, Pad, Enc, Str, Ord, CL, I) -> + print(A, -1, F, Adj, P, Pad, Enc, Str, Ord, CL, I); +control_limited($W, [A,Depth], F, Adj, P, Pad, Enc, _Str, Ord, CL, _I) when is_integer(Depth) -> - Chars = io_lib:write(A, [{depth, Depth}, {encoding, Enc}, {chars_limit, CL}]), + Chars = io_lib:write(A, [ + {depth, Depth}, + {encoding, Enc}, + {chars_limit, CL}, + {maps_order, Ord} + ]), term(Chars, F, Adj, P, Pad); -control_limited($P, [A,Depth], F, Adj, P, Pad, Enc, Str, CL, I) +control_limited($P, [A,Depth], F, Adj, P, Pad, Enc, Str, Ord, CL, I) when is_integer(Depth) -> - print(A, Depth, F, Adj, P, Pad, Enc, Str, CL, I). + print(A, Depth, F, Adj, P, Pad, Enc, Str, Ord, CL, I). -ifdef(UNICODE_AS_BINARIES). uniconv(C) -> @@ -425,17 +452,18 @@ term(T, F, Adj, P0, Pad) -> %% Print a term. Field width sets maximum line length, Precision sets %% initial indentation. -print(T, D, none, Adj, P, Pad, E, Str, ChLim, I) -> - print(T, D, 80, Adj, P, Pad, E, Str, ChLim, I); -print(T, D, F, Adj, none, Pad, E, Str, ChLim, I) -> - print(T, D, F, Adj, I+1, Pad, E, Str, ChLim, I); -print(T, D, F, right, P, _Pad, Enc, Str, ChLim, _I) -> +print(T, D, none, Adj, P, Pad, E, Str, Ord, ChLim, I) -> + print(T, D, 80, Adj, P, Pad, E, Str, Ord, ChLim, I); +print(T, D, F, Adj, none, Pad, E, Str, Ord, ChLim, I) -> + print(T, D, F, Adj, I+1, Pad, E, Str, Ord, ChLim, I); +print(T, D, F, right, P, _Pad, Enc, Str, Ord, ChLim, _I) -> Options = [{chars_limit, ChLim}, {column, P}, {line_length, F}, {depth, D}, {encoding, Enc}, - {strings, Str}], + {strings, Str}, + {maps_order, Ord}], io_lib_pretty:print(T, Options). %% fwrite_e(Float, Field, Adjust, Precision, PadChar) @@ -539,268 +567,10 @@ float_data([_|Cs], Ds) -> %% Returns a correctly rounded string that converts to Float when %% read back with list_to_float/1. -%% -%% When abs(Float) < float(1 bsl 53) the shortest such string is -%% returned, and otherwise the shortest such string using scientific -%% notation is returned. That is, scientific notation is used if and -%% only if scientific notation results in a shorter string than -%% normal notation when abs(Float) < float(1 bsl 53), and scientific -%% notation is used unconditionally if abs(Float) >= float(1 bsl -%% 53). See comment in insert_decimal/2 for an explanation for why -%% float(1 bsl 53) is chosen as cutoff point. -%% -%% The algorithm that is used to find the decimal number that is -%% represented by the returned String is described in "Ryu: Fast -%% Float-to-String Conversion" in Proceedings of 39th ACM SIGPLAN -%% Conference on Programming Language Design and Implementation. -%% https://dl.acm.org/doi/pdf/10.1145/3192366.3192369 -spec fwrite_g(float()) -> string(). fwrite_g(Float) -> - case sign_mantissa_exponent(Float) of - {0, 0, 0} -> "0.0"; - {1, 0, 0} -> "-0.0"; - {S, M, E} when E < 2047 -> - {Place, Digits} = - case is_small_int(M, E) of - {int, M1, E1} -> - compute_shortest_int(M1, E1); - not_int -> - fwrite_g_1(M, E) - end, - DigitList = insert_decimal(Place, Digits, Float), - insert_minus(S, DigitList) - end. - --define(BIG_POW, (1 bsl 52)). --define(DECODE_CORRECTION, 1075). - -sign_mantissa_exponent(F) -> - <> = <>, - {S, M , BE}. - -is_small_int(M, E) -> - M2 = ?BIG_POW bor M, - E2 = E - ?DECODE_CORRECTION, - case E2 > 0 orelse E2 < -52 of - true -> - %% f = m2 * 2^e2 >= 2^53 is an integer. - %% Ignore this case for now. - %% or f < 1 - not_int; - _ -> - %% Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52: 1 <= f = m2 / 2^-e2 < 2^53. - %% Test if the lower -e2 bits of the significand are 0, i.e. whether the fraction is 0. - Mask = (1 bsl -E2) - 1, - Fraction = M2 band Mask, - case Fraction of - 0 -> - %% f is an integer in the range [1, 2^53). - %% Note: mantissa might contain trailing (decimal) 0's. - {int, M2 bsr -E2, 0}; - _ -> - not_int - end - end. - -%% For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros. -compute_shortest_int(M, E) when M rem 10 =:= 0 -> - Q = M div 10, - compute_shortest_int(Q, E + 1); -compute_shortest_int(M, E) -> - {E, integer_to_list(M)}. - -fwrite_g_1(M, E) -> - {Mf, Ef} = decode(M, E), - Shift = mmshift(M, E), - Mv = 4 * Mf, - {Q, Vm, Vr, Vp, E10} = convert_to_decimal(Ef, Mv, Shift), - Accept = M rem 2 == 0, - {VmIsTrailingZero, VrIsTrailingZero, Vp1} = bounds(Mv, Q, Vp, Accept, Ef, Shift), - {D1, E1} = compute_shortest(Vm, Vr, Vp1, VmIsTrailingZero, VrIsTrailingZero, Accept), - {E1 + E10, integer_to_list(D1)}. - -decode(Mantissa, 0) -> - {Mantissa, 1 - ?DECODE_CORRECTION - 2}; -decode(Mantissa, Exponent) -> - {Mantissa + ?BIG_POW, Exponent - ?DECODE_CORRECTION - 2}. - -mmshift(0, E) when E > 1 -> - 0; -mmshift(_M, _E) -> - 1. - -convert_to_decimal(E2, Mv, Shift) when E2 >= 0 -> - Q = max(0, ((E2 * 78913) bsr 18) - 1), - Mul = io_lib_format_ryu_table:inv_value(Q), - K = io_lib_format_ryu_table:pow5_inv_bitcount() + pow5bits(Q) - 1, - I = -E2 + Q + K, - {Vm, Vr, Vp} = mulShiftAll(Mv, Shift, I, Mul), - {Q, Vm, Vr, Vp, Q}; - -convert_to_decimal(E2, Mv, Shift) when E2 < 0 -> - Q = max(0, ((-E2 * 732923) bsr 20) - 1), - I = -E2 - Q, - K = pow5bits(I) - io_lib_format_ryu_table:pow5_bitcount(), - From_file = io_lib_format_ryu_table:value(I), - J = Q - K, - {Vm, Vr, Vp} = mulShiftAll(Mv, Shift, J, From_file), - E10 = E2 + Q, - {Q, Vm, Vr, Vp, E10}. - -pow5bits(E) -> - ((E * 1217359) bsr 19) + 1. - -mulShiftAll(Mv, Shift, J, Mul) -> - A = mulShift64(Mv - 1 - Shift, Mul, J), - B = mulShift64(Mv, Mul, J), - C = mulShift64(Mv + 2,Mul, J), - {A, B, C}. - -mulShift64(M, Mul, J) -> - (M * Mul) bsr J. - -bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 >= 0, Q =< 21, Mv rem 5 =:= 0 -> - {false, multipleOfPowerOf5(Mv, Q) , Vp}; -bounds(Mv, Q, Vp, true, E2, Shift) when E2 >= 0, Q =< 21 -> - {multipleOfPowerOf5(Mv - 1 - Shift, Q), false , Vp}; -bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 >= 0, Q =< 21 -> - {false, false , Vp - vpmodifier(multipleOfPowerOf5(Mv + 2, Q))}; -bounds(_Mv, Q, Vp, true, E2, Shift) when E2 < 0, Q =< 1 -> - {Shift =:= 1, true, Vp}; -bounds(_Mv, Q, Vp, false, E2, _Shift) when E2 < 0, Q =< 1 -> - {false, true, Vp - 1}; -bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 < 0, Q < 63 -> - {false, (Mv band ((1 bsl Q) -1 )) =:= 0, Vp}; -bounds(_Mv, _Q, Vp, _Accept, _E2, _Shift) -> - {false, false, Vp}. - -multipleOfPowerOf5(Value, Q) -> - pow5factor(Value) >= Q. - -pow5factor(Val) -> - pow5factor(Val div 5, 0). - -pow5factor(Val, Count) when (Val rem 5) /= 0-> - Count; -pow5factor(Val, Count) -> - pow5factor(Val div 5, Count + 1). - -vpmodifier(true) -> - 1; -vpmodifier(false) -> - 0. - -compute_shortest(Vm, Vr, Vp, false, false, _Accept) -> - {Vm1, Vr1, Removed, RoundUp} = - general_case(Vm, Vr, Vp, 0, false), - Output = Vr1 + handle_normal_output_mod(Vr1, Vm1, RoundUp), - {Output, Removed}; -compute_shortest(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, Accept) -> - {Vm1, Vr1, Removed, LastRemovedDigit} = - handle_trailing_zeros(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, 0, 0), - Output = Vr1 + handle_zero_output_mod(Vr1, Vm1, Accept, VmIsTrailingZero, LastRemovedDigit), - {Output, Removed}. - -general_case(Vm, Vr, Vp, Removed, RoundUp) when (Vp div 100) =< (Vm div 100)-> - general_case_10(Vm, Vr, Vp, Removed, RoundUp); -general_case(Vm, Vr, Vp, Removed, _RU) -> - VmD100 = Vm div 100, - VrD100 = Vr div 100, - VpD100 = Vp div 100, - RoundUp = ((Vr rem 100) >= 50), - general_case_10(VmD100, VrD100, VpD100, 2 + Removed, RoundUp). - -general_case_10(Vm, Vr, Vp, Removed, RoundUp) - when (Vp div 10) =< (Vm div 10)-> - {Vm, Vr, Removed, RoundUp}; -general_case_10(Vm, Vr, Vp, Removed, _RU) -> - VmD10 = Vm div 10, - VrD10 = Vr div 10, - VpD10 = Vp div 10, - RoundUp = ((Vr rem 10) >= 5), - general_case_10(VmD10, VrD10, VpD10, 1 + Removed, RoundUp). - -handle_normal_output_mod(Vr, Vm, RoundUp) when (Vm =:= Vr) or RoundUp -> - 1; -handle_normal_output_mod(_Vr, _Vm, _RoundUp) -> - 0. - -handle_trailing_zeros(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit) - when (Vp div 10) =< (Vm div 10)-> - vmIsTrailingZero(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit); -handle_trailing_zeros(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, Removed, LastRemovedDigit) -> - VmTZ = VmIsTrailingZero and ((Vm rem 10) =:= 0), - VrTZ = VrIsTrailingZero and (LastRemovedDigit =:= 0), - handle_trailing_zeros(Vm div 10, Vr div 10, Vp div 10, VmTZ, VrTZ, 1 + Removed, Vr rem 10). - -vmIsTrailingZero(Vm, Vr, _Vp, false = _VmTZ, VrTZ, Removed, LastRemovedDigit) -> - handle_50_dotdot_0(Vm, Vr, VrTZ, Removed, LastRemovedDigit); -vmIsTrailingZero(Vm, Vr, _Vp, _VmTZ, VrTZ, Removed, LastRemovedDigit) when (Vm rem 10) /= 0 -> - handle_50_dotdot_0(Vm, Vr, VrTZ, Removed, LastRemovedDigit); -vmIsTrailingZero(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit) -> - vmIsTrailingZero(Vm div 10, Vr div 10, Vp div 10, VmTZ, LastRemovedDigit == 0 andalso VrTZ, 1 + Removed, Vr rem 10). - -handle_50_dotdot_0(Vm, Vr, true, Removed, 5) when (Vr rem 2) =:= 0 -> - {Vm, Vr, Removed, 4}; -handle_50_dotdot_0(Vm, Vr, _VrTZ, Removed, LastRemovedDigit) -> - {Vm, Vr, Removed, LastRemovedDigit}. - -handle_zero_output_mod(_Vr, _Vm, _Accept, _VmTZ, LastRemovedDigit) when LastRemovedDigit >= 5 -> - 1; -handle_zero_output_mod(Vr, Vm, Accept, VmTZ, _LastRemovedDigit) when Vr =:= Vm, ((not Accept) or (not VmTZ)) -> - 1; -handle_zero_output_mod(_Vr, _Vm, _Accept, _VmTZ, _LastRemovedDigit) -> - 0. - -insert_decimal(Place, S, Float) -> - L = length(S), - Exp = Place + L - 1, - ExpL = integer_to_list(Exp), - ExpCost = length(ExpL) + 2, - if - Place < 0 -> - if - Exp >= 0 -> - {S0, S1} = lists:split(L + Place, S), - S0 ++ "." ++ S1; - 2 - Place - L =< ExpCost -> - "0." ++ lists:duplicate(-Place - L, $0) ++ S; - true -> - insert_exp(ExpL, S) - end; - true -> - Dot = if L =:= 1 -> 1; true -> 0 end, - if - %% All integers in the range [-2^53, 2^53] can - %% be stored without loss of precision in an - %% IEEE 754 64-bit double but 2^53+1 cannot be - %% stored in an IEEE 754 64-bit double without - %% loss of precision (float((1 bsl 53)+1) =:= - %% float(1 bsl 53)). It thus makes sense to - %% show floats that are >= 2^53 or <= -2^53 in - %% scientific notation to indicate that the - %% number is so large that there could be loss - %% in precion when adding or subtracting 1. - %% - %% https://stackoverflow.com/questions/1848700/biggest-integer-that-can-be-stored-in-a-double?answertab=votes#tab-top - ExpCost + Dot >= Place + 2 andalso abs(Float) < float(1 bsl 53) -> - S ++ lists:duplicate(Place, $0) ++ ".0"; - true -> - insert_exp(ExpL, S) - end - end. - - -insert_exp(ExpL, [C]) -> - [C] ++ ".0e" ++ ExpL; -insert_exp(ExpL, [C | S]) -> - [C] ++ "." ++ S ++ "e" ++ ExpL. - -insert_minus(0, Digits) -> - Digits; -insert_minus(1, Digits) -> - [$-] ++ Digits. + float_to_list(Float, [short]). %% fwrite_g(Float, Field, Adjust, Precision, PadChar) %% Use the f form if Float is >= 0.1 and < 1.0e4, diff --git a/lib/stdlib/src/io_lib_format_ryu_table.erl b/lib/stdlib/src/io_lib_format_ryu_table.erl deleted file mode 100644 index b20268a939f3..000000000000 --- a/lib/stdlib/src/io_lib_format_ryu_table.erl +++ /dev/null @@ -1,686 +0,0 @@ -%% -%% this file is generated do not modify -%% see ../script/generate_ryu_table.escript - --module(io_lib_format_ryu_table). --export([pow5_bitcount/0, pow5_inv_bitcount/0, value/1, inv_value/1]). - --spec pow5_bitcount() -> integer(). -pow5_bitcount() -> 125. - --spec pow5_inv_bitcount() -> integer(). -pow5_inv_bitcount() -> 125. - --spec value(integer()) -> integer(). -value(0) -> 21267647932558653966460912964485513216; -value(1) -> 26584559915698317458076141205606891520; -value(2) -> 33230699894622896822595176507008614400; -value(3) -> 41538374868278621028243970633760768000; -value(4) -> 25961484292674138142652481646100480000; -value(5) -> 32451855365842672678315602057625600000; -value(6) -> 40564819207303340847894502572032000000; -value(7) -> 25353012004564588029934064107520000000; -value(8) -> 31691265005705735037417580134400000000; -value(9) -> 39614081257132168796771975168000000000; -value(10) -> 24758800785707605497982484480000000000; -value(11) -> 30948500982134506872478105600000000000; -value(12) -> 38685626227668133590597632000000000000; -value(13) -> 24178516392292583494123520000000000000; -value(14) -> 30223145490365729367654400000000000000; -value(15) -> 37778931862957161709568000000000000000; -value(16) -> 23611832414348226068480000000000000000; -value(17) -> 29514790517935282585600000000000000000; -value(18) -> 36893488147419103232000000000000000000; -value(19) -> 23058430092136939520000000000000000000; -value(20) -> 28823037615171174400000000000000000000; -value(21) -> 36028797018963968000000000000000000000; -value(22) -> 22517998136852480000000000000000000000; -value(23) -> 28147497671065600000000000000000000000; -value(24) -> 35184372088832000000000000000000000000; -value(25) -> 21990232555520000000000000000000000000; -value(26) -> 27487790694400000000000000000000000000; -value(27) -> 34359738368000000000000000000000000000; -value(28) -> 21474836480000000000000000000000000000; -value(29) -> 26843545600000000000000000000000000000; -value(30) -> 33554432000000000000000000000000000000; -value(31) -> 41943040000000000000000000000000000000; -value(32) -> 26214400000000000000000000000000000000; -value(33) -> 32768000000000000000000000000000000000; -value(34) -> 40960000000000000000000000000000000000; -value(35) -> 25600000000000000000000000000000000000; -value(36) -> 32000000000000000000000000000000000000; -value(37) -> 40000000000000000000000000000000000000; -value(38) -> 25000000000000000000000000000000000000; -value(39) -> 31250000000000000000000000000000000000; -value(40) -> 39062500000000000000000000000000000000; -value(41) -> 24414062500000000000000000000000000000; -value(42) -> 30517578125000000000000000000000000000; -value(43) -> 38146972656250000000000000000000000000; -value(44) -> 23841857910156250000000000000000000000; -value(45) -> 29802322387695312500000000000000000000; -value(46) -> 37252902984619140625000000000000000000; -value(47) -> 23283064365386962890625000000000000000; -value(48) -> 29103830456733703613281250000000000000; -value(49) -> 36379788070917129516601562500000000000; -value(50) -> 22737367544323205947875976562500000000; -value(51) -> 28421709430404007434844970703125000000; -value(52) -> 35527136788005009293556213378906250000; -value(53) -> 22204460492503130808472633361816406250; -value(54) -> 27755575615628913510590791702270507812; -value(55) -> 34694469519536141888238489627838134765; -value(56) -> 21684043449710088680149056017398834228; -value(57) -> 27105054312137610850186320021748542785; -value(58) -> 33881317890172013562732900027185678482; -value(59) -> 42351647362715016953416125033982098102; -value(60) -> 26469779601696885595885078146238811314; -value(61) -> 33087224502121106994856347682798514142; -value(62) -> 41359030627651383743570434603498142678; -value(63) -> 25849394142282114839731521627186339173; -value(64) -> 32311742677852643549664402033982923967; -value(65) -> 40389678347315804437080502542478654959; -value(66) -> 25243548967072377773175314089049159349; -value(67) -> 31554436208840472216469142611311449186; -value(68) -> 39443045261050590270586428264139311483; -value(69) -> 24651903288156618919116517665087069677; -value(70) -> 30814879110195773648895647081358837096; -value(71) -> 38518598887744717061119558851698546370; -value(72) -> 24074124304840448163199724282311591481; -value(73) -> 30092655381050560203999655352889489352; -value(74) -> 37615819226313200254999569191111861690; -value(75) -> 23509887016445750159374730744444913556; -value(76) -> 29387358770557187699218413430556141945; -value(77) -> 36734198463196484624023016788195177431; -value(78) -> 22958874039497802890014385492621985894; -value(79) -> 28698592549372253612517981865777482368; -value(80) -> 35873240686715317015647477332221852960; -value(81) -> 22420775429197073134779673332638658100; -value(82) -> 28025969286496341418474591665798322625; -value(83) -> 35032461608120426773093239582247903282; -value(84) -> 21895288505075266733183274738904939551; -value(85) -> 27369110631344083416479093423631174439; -value(86) -> 34211388289180104270598866779538968048; -value(87) -> 21382117680737565169124291737211855030; -value(88) -> 26727647100921956461405364671514818788; -value(89) -> 33409558876152445576756705839393523485; -value(90) -> 41761948595190556970945882299241904356; -value(91) -> 26101217871994098106841176437026190222; -value(92) -> 32626522339992622633551470546282737778; -value(93) -> 40783152924990778291939338182853422223; -value(94) -> 25489470578119236432462086364283388889; -value(95) -> 31861838222649045540577607955354236111; -value(96) -> 39827297778311306925722009944192795139; -value(97) -> 24892061111444566828576256215120496962; -value(98) -> 31115076389305708535720320268900621202; -value(99) -> 38893845486632135669650400336125776503; -value(100) -> 24308653429145084793531500210078610314; -value(101) -> 30385816786431355991914375262598262893; -value(102) -> 37982270983039194989892969078247828616; -value(103) -> 23738919364399496868683105673904892885; -value(104) -> 29673649205499371085853882092381116106; -value(105) -> 37092061506874213857317352615476395133; -value(106) -> 23182538441796383660823345384672746958; -value(107) -> 28978173052245479576029181730840933698; -value(108) -> 36222716315306849470036477163551167122; -value(109) -> 22639197697066780918772798227219479451; -value(110) -> 28298997121333476148465997784024349314; -value(111) -> 35373746401666845185582497230030436643; -value(112) -> 22108591501041778240989060768769022902; -value(113) -> 27635739376302222801236325960961278627; -value(114) -> 34544674220377778501545407451201598284; -value(115) -> 21590421387736111563465879657000998927; -value(116) -> 26988026734670139454332349571251248659; -value(117) -> 33735033418337674317915436964064060824; -value(118) -> 42168791772922092897394296205080076030; -value(119) -> 26355494858076308060871435128175047519; -value(120) -> 32944368572595385076089293910218809399; -value(121) -> 41180460715744231345111617387773511748; -value(122) -> 25737787947340144590694760867358444843; -value(123) -> 32172234934175180738368451084198056053; -value(124) -> 40215293667718975922960563855247570067; -value(125) -> 25134558542324359951850352409529731292; -value(126) -> 31418198177905449939812940511912164115; -value(127) -> 39272747722381812424766175639890205143; -value(128) -> 24545467326488632765478859774931378214; -value(129) -> 30681834158110790956848574718664222768; -value(130) -> 38352292697638488696060718398330278460; -value(131) -> 23970182936024055435037948998956424037; -value(132) -> 29962728670030069293797436248695530047; -value(133) -> 37453410837537586617246795310869412559; -value(134) -> 23408381773460991635779247069293382849; -value(135) -> 29260477216826239544724058836616728561; -value(136) -> 36575596521032799430905073545770910702; -value(137) -> 22859747825645499644315670966106819189; -value(138) -> 28574684782056874555394588707633523986; -value(139) -> 35718355977571093194243235884541904982; -value(140) -> 22323972485981933246402022427838690614; -value(141) -> 27904965607477416558002528034798363267; -value(142) -> 34881207009346770697503160043497954084; -value(143) -> 21800754380841731685939475027186221303; -value(144) -> 27250942976052164607424343783982776628; -value(145) -> 34063678720065205759280429729978470785; -value(146) -> 21289799200040753599550268581236544241; -value(147) -> 26612249000050941999437835726545680301; -value(148) -> 33265311250063677499297294658182100376; -value(149) -> 41581639062579596874121618322727625471; -value(150) -> 25988524414112248046326011451704765919; -value(151) -> 32485655517640310057907514314630957399; -value(152) -> 40607069397050387572384392893288696749; -value(153) -> 25379418373156492232740245558305435468; -value(154) -> 31724272966445615290925306947881794335; -value(155) -> 39655341208057019113656633684852242919; -value(156) -> 24784588255035636946035396053032651824; -value(157) -> 30980735318794546182544245066290814780; -value(158) -> 38725919148493182728180306332863518475; -value(159) -> 24203699467808239205112691458039699047; -value(160) -> 30254624334760299006390864322549623809; -value(161) -> 37818280418450373757988580403187029761; -value(162) -> 23636425261531483598742862751991893600; -value(163) -> 29545531576914354498428578439989867001; -value(164) -> 36931914471142943123035723049987333751; -value(165) -> 23082446544464339451897326906242083594; -value(166) -> 28853058180580424314871658632802604493; -value(167) -> 36066322725725530393589573291003255616; -value(168) -> 22541451703578456495993483306877034760; -value(169) -> 28176814629473070619991854133596293450; -value(170) -> 35221018286841338274989817666995366813; -value(171) -> 22013136429275836421868636041872104258; -value(172) -> 27516420536594795527335795052340130322; -value(173) -> 34395525670743494409169743815425162903; -value(174) -> 21497203544214684005731089884640726814; -value(175) -> 26871504430268355007163862355800908518; -value(176) -> 33589380537835443758954827944751135647; -value(177) -> 41986725672294304698693534930938919559; -value(178) -> 26241703545183940436683459331836824724; -value(179) -> 32802129431479925545854324164796030906; -value(180) -> 41002661789349906932317905205995038632; -value(181) -> 25626663618343691832698690753746899145; -value(182) -> 32033329522929614790873363442183623931; -value(183) -> 40041661903662018488591704302729529914; -value(184) -> 25026038689788761555369815189205956196; -value(185) -> 31282548362235951944212268986507445245; -value(186) -> 39103185452794939930265336233134306557; -value(187) -> 24439490907996837456415835145708941598; -value(188) -> 30549363634996046820519793932136176997; -value(189) -> 38186704543745058525649742415170221247; -value(190) -> 23866690339840661578531089009481388279; -value(191) -> 29833362924800826973163861261851735349; -value(192) -> 37291703656001033716454826577314669186; -value(193) -> 23307314785000646072784266610821668241; -value(194) -> 29134143481250807590980333263527085302; -value(195) -> 36417679351563509488725416579408856627; -value(196) -> 22761049594727193430453385362130535392; -value(197) -> 28451311993408991788066731702663169240; -value(198) -> 35564139991761239735083414628328961550; -value(199) -> 22227587494850774834427134142705600969; -value(200) -> 27784484368563468543033917678382001211; -value(201) -> 34730605460704335678792397097977501514; -value(202) -> 21706628412940209799245248186235938446; -value(203) -> 27133285516175262249056560232794923058; -value(204) -> 33916606895219077811320700290993653822; -value(205) -> 42395758619023847264150875363742067278; -value(206) -> 26497349136889904540094297102338792048; -value(207) -> 33121686421112380675117871377923490061; -value(208) -> 41402108026390475843897339222404362576; -value(209) -> 25876317516494047402435837014002726610; -value(210) -> 32345396895617559253044796267503408262; -value(211) -> 40431746119521949066305995334379260328; -value(212) -> 25269841324701218166441247083987037705; -value(213) -> 31587301655876522708051558854983797131; -value(214) -> 39484127069845653385064448568729746414; -value(215) -> 24677579418653533365665280355456091509; -value(216) -> 30846974273316916707081600444320114386; -value(217) -> 38558717841646145883852000555400142982; -value(218) -> 24099198651028841177407500347125089364; -value(219) -> 30123998313786051471759375433906361705; -value(220) -> 37654997892232564339699219292382952131; -value(221) -> 23534373682645352712312012057739345082; -value(222) -> 29417967103306690890390015072174181352; -value(223) -> 36772458879133363612987518840217726691; -value(224) -> 22982786799458352258117199275136079181; -value(225) -> 28728483499322940322646499093920098977; -value(226) -> 35910604374153675403308123867400123721; -value(227) -> 22444127733846047127067577417125077326; -value(228) -> 28055159667307558908834471771406346657; -value(229) -> 35068949584134448636043089714257933322; -value(230) -> 21918093490084030397526931071411208326; -value(231) -> 27397616862605037996908663839264010407; -value(232) -> 34247021078256297496135829799080013009; -value(233) -> 21404388173910185935084893624425008131; -value(234) -> 26755485217387732418856117030531260163; -value(235) -> 33444356521734665523570146288164075204; -value(236) -> 41805445652168331904462682860205094006; -value(237) -> 26128403532605207440289176787628183753; -value(238) -> 32660504415756509300361470984535229692; -value(239) -> 40825630519695636625451838730669037115; -value(240) -> 25516019074809772890907399206668148197; -value(241) -> 31895023843512216113634249008335185246; -value(242) -> 39868779804390270142042811260418981558; -value(243) -> 24917987377743918838776757037761863473; -value(244) -> 31147484222179898548470946297202329342; -value(245) -> 38934355277724873185588682871502911677; -value(246) -> 24333972048578045740992926794689319798; -value(247) -> 30417465060722557176241158493361649748; -value(248) -> 38021831325903196470301448116702062185; -value(249) -> 23763644578689497793938405072938788865; -value(250) -> 29704555723361872242423006341173486082; -value(251) -> 37130694654202340303028757926466857602; -value(252) -> 23206684158876462689392973704041786001; -value(253) -> 29008355198595578361741217130052232502; -value(254) -> 36260443998244472952176521412565290627; -value(255) -> 22662777498902795595110325882853306642; -value(256) -> 28328471873628494493887907353566633302; -value(257) -> 35410589842035618117359884191958291628; -value(258) -> 22131618651272261323349927619973932267; -value(259) -> 27664523314090326654187409524967415334; -value(260) -> 34580654142612908317734261906209269168; -value(261) -> 21612908839133067698583913691380793230; -value(262) -> 27016136048916334623229892114225991537; -value(263) -> 33770170061145418279037365142782489422; -value(264) -> 42212712576431772848796706428478111778; -value(265) -> 26382945360269858030497941517798819861; -value(266) -> 32978681700337322538122426897248524826; -value(267) -> 41223352125421653172653033621560656033; -value(268) -> 25764595078388533232908146013475410020; -value(269) -> 32205743847985666541135182516844262526; -value(270) -> 40257179809982083176418978146055328157; -value(271) -> 25160737381238801985261861341284580098; -value(272) -> 31450921726548502481577326676605725123; -value(273) -> 39313652158185628101971658345757156403; -value(274) -> 24571032598866017563732286466098222752; -value(275) -> 30713790748582521954665358082622778440; -value(276) -> 38392238435728152443331697603278473050; -value(277) -> 23995149022330095277082311002049045656; -value(278) -> 29993936277912619096352888752561307070; -value(279) -> 37492420347390773870441110940701633838; -value(280) -> 23432762717119233669025694337938521149; -value(281) -> 29290953396399042086282117922423151436; -value(282) -> 36613691745498802607852647403028939295; -value(283) -> 22883557340936751629907904626893087059; -value(284) -> 28604446676170939537384880783616358824; -value(285) -> 35755558345213674421731100979520448530; -value(286) -> 22347223965758546513581938112200280331; -value(287) -> 27934029957198183141977422640250350414; -value(288) -> 34917537446497728927471778300312938018; -value(289) -> 21823460904061080579669861437695586261; -value(290) -> 27279326130076350724587326797119482826; -value(291) -> 34099157662595438405734158496399353533; -value(292) -> 21311973539122149003583849060249595958; -value(293) -> 26639966923902686254479811325311994947; -value(294) -> 33299958654878357818099764156639993684; -value(295) -> 41624948318597947272624705195799992106; -value(296) -> 26015592699123717045390440747374995066; -value(297) -> 32519490873904646306738050934218743833; -value(298) -> 40649363592380807883422563667773429791; -value(299) -> 25405852245238004927139102292358393619; -value(300) -> 31757315306547506158923877865447992024; -value(301) -> 39696644133184382698654847331809990030; -value(302) -> 24810402583240239186659279582381243769; -value(303) -> 31013003229050298983324099477976554711; -value(304) -> 38766254036312873729155124347470693389; -value(305) -> 24228908772695546080721952717169183368; -value(306) -> 30286135965869432600902440896461479210; -value(307) -> 37857669957336790751128051120576849012; -value(308) -> 23661043723335494219455031950360530633; -value(309) -> 29576304654169367774318789937950663291; -value(310) -> 36970380817711709717898487422438329114; -value(311) -> 23106488011069818573686554639023955696; -value(312) -> 28883110013837273217108193298779944620; -value(313) -> 36103887517296591521385241623474930775; -value(314) -> 22564929698310369700865776014671831734; -value(315) -> 28206162122887962126082220018339789668; -value(316) -> 35257702653609952657602775022924737085; -value(317) -> 22036064158506220411001734389327960678; -value(318) -> 27545080198132775513752167986659950848; -value(319) -> 34431350247665969392190209983324938560; -value(320) -> 21519593904791230870118881239578086600; -value(321) -> 26899492380989038587648601549472608250; -value(322) -> 33624365476236298234560751936840760312; -value(323) -> 42030456845295372793200939921050950390; -value(324) -> 26269035528309607995750587450656843994; -value(325) -> 32836294410387009994688234313321054992; -value(_) -> error(function_clause). - --spec inv_value(integer()) -> integer(). -inv_value(0) -> 42535295865117307932921825928971026433; -inv_value(1) -> 34028236692093846346337460743176821146; -inv_value(2) -> 27222589353675077077069968594541456917; -inv_value(3) -> 21778071482940061661655974875633165534; -inv_value(4) -> 34844914372704098658649559801013064854; -inv_value(5) -> 27875931498163278926919647840810451883; -inv_value(6) -> 22300745198530623141535718272648361506; -inv_value(7) -> 35681192317648997026457149236237378410; -inv_value(8) -> 28544953854119197621165719388989902728; -inv_value(9) -> 22835963083295358096932575511191922183; -inv_value(10) -> 36537540933272572955092120817907075492; -inv_value(11) -> 29230032746618058364073696654325660394; -inv_value(12) -> 23384026197294446691258957323460528315; -inv_value(13) -> 37414441915671114706014331717536845304; -inv_value(14) -> 29931553532536891764811465374029476243; -inv_value(15) -> 23945242826029513411849172299223580995; -inv_value(16) -> 38312388521647221458958675678757729591; -inv_value(17) -> 30649910817317777167166940543006183673; -inv_value(18) -> 24519928653854221733733552434404946938; -inv_value(19) -> 39231885846166754773973683895047915101; -inv_value(20) -> 31385508676933403819178947116038332081; -inv_value(21) -> 25108406941546723055343157692830665665; -inv_value(22) -> 40173451106474756888549052308529065064; -inv_value(23) -> 32138760885179805510839241846823252051; -inv_value(24) -> 25711008708143844408671393477458601641; -inv_value(25) -> 41137613933030151053874229563933762625; -inv_value(26) -> 32910091146424120843099383651147010100; -inv_value(27) -> 26328072917139296674479506920917608080; -inv_value(28) -> 42124916667422874679167211073468172928; -inv_value(29) -> 33699933333938299743333768858774538343; -inv_value(30) -> 26959946667150639794667015087019630674; -inv_value(31) -> 21567957333720511835733612069615704539; -inv_value(32) -> 34508731733952818937173779311385127263; -inv_value(33) -> 27606985387162255149739023449108101810; -inv_value(34) -> 22085588309729804119791218759286481448; -inv_value(35) -> 35336941295567686591665950014858370317; -inv_value(36) -> 28269553036454149273332760011886696254; -inv_value(37) -> 22615642429163319418666208009509357003; -inv_value(38) -> 36185027886661311069865932815214971205; -inv_value(39) -> 28948022309329048855892746252171976964; -inv_value(40) -> 23158417847463239084714197001737581571; -inv_value(41) -> 37053468555941182535542715202780130514; -inv_value(42) -> 29642774844752946028434172162224104411; -inv_value(43) -> 23714219875802356822747337729779283529; -inv_value(44) -> 37942751801283770916395740367646853646; -inv_value(45) -> 30354201441027016733116592294117482917; -inv_value(46) -> 24283361152821613386493273835293986334; -inv_value(47) -> 38853377844514581418389238136470378133; -inv_value(48) -> 31082702275611665134711390509176302507; -inv_value(49) -> 24866161820489332107769112407341042006; -inv_value(50) -> 39785858912782931372430579851745667209; -inv_value(51) -> 31828687130226345097944463881396533767; -inv_value(52) -> 25462949704181076078355571105117227014; -inv_value(53) -> 40740719526689721725368913768187563222; -inv_value(54) -> 32592575621351777380295131014550050577; -inv_value(55) -> 26074060497081421904236104811640040462; -inv_value(56) -> 41718496795330275046777767698624064739; -inv_value(57) -> 33374797436264220037422214158899251791; -inv_value(58) -> 26699837949011376029937771327119401433; -inv_value(59) -> 21359870359209100823950217061695521147; -inv_value(60) -> 34175792574734561318320347298712833834; -inv_value(61) -> 27340634059787649054656277838970267067; -inv_value(62) -> 21872507247830119243725022271176213654; -inv_value(63) -> 34996011596528190789960035633881941846; -inv_value(64) -> 27996809277222552631968028507105553477; -inv_value(65) -> 22397447421778042105574422805684442782; -inv_value(66) -> 35835915874844867368919076489095108450; -inv_value(67) -> 28668732699875893895135261191276086760; -inv_value(68) -> 22934986159900715116108208953020869408; -inv_value(69) -> 36695977855841144185773134324833391053; -inv_value(70) -> 29356782284672915348618507459866712843; -inv_value(71) -> 23485425827738332278894805967893370274; -inv_value(72) -> 37576681324381331646231689548629392439; -inv_value(73) -> 30061345059505065316985351638903513951; -inv_value(74) -> 24049076047604052253588281311122811161; -inv_value(75) -> 38478521676166483605741250097796497857; -inv_value(76) -> 30782817340933186884593000078237198286; -inv_value(77) -> 24626253872746549507674400062589758629; -inv_value(78) -> 39402006196394479212279040100143613806; -inv_value(79) -> 31521604957115583369823232080114891045; -inv_value(80) -> 25217283965692466695858585664091912836; -inv_value(81) -> 40347654345107946713373737062547060537; -inv_value(82) -> 32278123476086357370698989650037648430; -inv_value(83) -> 25822498780869085896559191720030118744; -inv_value(84) -> 41315998049390537434494706752048189990; -inv_value(85) -> 33052798439512429947595765401638551992; -inv_value(86) -> 26442238751609943958076612321310841594; -inv_value(87) -> 42307582002575910332922579714097346550; -inv_value(88) -> 33846065602060728266338063771277877240; -inv_value(89) -> 27076852481648582613070451017022301792; -inv_value(90) -> 21661481985318866090456360813617841434; -inv_value(91) -> 34658371176510185744730177301788546293; -inv_value(92) -> 27726696941208148595784141841430837035; -inv_value(93) -> 22181357552966518876627313473144669628; -inv_value(94) -> 35490172084746430202603701557031471404; -inv_value(95) -> 28392137667797144162082961245625177124; -inv_value(96) -> 22713710134237715329666368996500141699; -inv_value(97) -> 36341936214780344527466190394400226718; -inv_value(98) -> 29073548971824275621972952315520181375; -inv_value(99) -> 23258839177459420497578361852416145100; -inv_value(100) -> 37214142683935072796125378963865832159; -inv_value(101) -> 29771314147148058236900303171092665728; -inv_value(102) -> 23817051317718446589520242536874132582; -inv_value(103) -> 38107282108349514543232388058998612131; -inv_value(104) -> 30485825686679611634585910447198889705; -inv_value(105) -> 24388660549343689307668728357759111764; -inv_value(106) -> 39021856878949902892269965372414578822; -inv_value(107) -> 31217485503159922313815972297931663058; -inv_value(108) -> 24973988402527937851052777838345330446; -inv_value(109) -> 39958381444044700561684444541352528714; -inv_value(110) -> 31966705155235760449347555633082022971; -inv_value(111) -> 25573364124188608359478044506465618377; -inv_value(112) -> 40917382598701773375164871210344989403; -inv_value(113) -> 32733906078961418700131896968275991523; -inv_value(114) -> 26187124863169134960105517574620793218; -inv_value(115) -> 41899399781070615936168828119393269149; -inv_value(116) -> 33519519824856492748935062495514615319; -inv_value(117) -> 26815615859885194199148049996411692255; -inv_value(118) -> 21452492687908155359318439997129353804; -inv_value(119) -> 34323988300653048574909503995406966087; -inv_value(120) -> 27459190640522438859927603196325572870; -inv_value(121) -> 21967352512417951087942082557060458296; -inv_value(122) -> 35147764019868721740707332091296733273; -inv_value(123) -> 28118211215894977392565865673037386618; -inv_value(124) -> 22494568972715981914052692538429909295; -inv_value(125) -> 35991310356345571062484308061487854871; -inv_value(126) -> 28793048285076456849987446449190283897; -inv_value(127) -> 23034438628061165479989957159352227118; -inv_value(128) -> 36855101804897864767983931454963563388; -inv_value(129) -> 29484081443918291814387145163970850711; -inv_value(130) -> 23587265155134633451509716131176680569; -inv_value(131) -> 37739624248215413522415545809882688910; -inv_value(132) -> 30191699398572330817932436647906151128; -inv_value(133) -> 24153359518857864654345949318324920902; -inv_value(134) -> 38645375230172583446953518909319873443; -inv_value(135) -> 30916300184138066757562815127455898755; -inv_value(136) -> 24733040147310453406050252101964719004; -inv_value(137) -> 39572864235696725449680403363143550406; -inv_value(138) -> 31658291388557380359744322690514840325; -inv_value(139) -> 25326633110845904287795458152411872260; -inv_value(140) -> 40522612977353446860472733043858995616; -inv_value(141) -> 32418090381882757488378186435087196493; -inv_value(142) -> 25934472305506205990702549148069757194; -inv_value(143) -> 41495155688809929585124078636911611511; -inv_value(144) -> 33196124551047943668099262909529289209; -inv_value(145) -> 26556899640838354934479410327623431367; -inv_value(146) -> 42491039425341367895167056524197490187; -inv_value(147) -> 33992831540273094316133645219357992150; -inv_value(148) -> 27194265232218475452906916175486393720; -inv_value(149) -> 21755412185774780362325532940389114976; -inv_value(150) -> 34808659497239648579720852704622583961; -inv_value(151) -> 27846927597791718863776682163698067169; -inv_value(152) -> 22277542078233375091021345730958453735; -inv_value(153) -> 35644067325173400145634153169533525976; -inv_value(154) -> 28515253860138720116507322535626820781; -inv_value(155) -> 22812203088110976093205858028501456625; -inv_value(156) -> 36499524940977561749129372845602330600; -inv_value(157) -> 29199619952782049399303498276481864480; -inv_value(158) -> 23359695962225639519442798621185491584; -inv_value(159) -> 37375513539561023231108477793896786534; -inv_value(160) -> 29900410831648818584886782235117429227; -inv_value(161) -> 23920328665319054867909425788093943382; -inv_value(162) -> 38272525864510487788655081260950309411; -inv_value(163) -> 30618020691608390230924065008760247529; -inv_value(164) -> 24494416553286712184739252007008198023; -inv_value(165) -> 39191066485258739495582803211213116837; -inv_value(166) -> 31352853188206991596466242568970493469; -inv_value(167) -> 25082282550565593277172994055176394776; -inv_value(168) -> 40131652080904949243476790488282231641; -inv_value(169) -> 32105321664723959394781432390625785313; -inv_value(170) -> 25684257331779167515825145912500628250; -inv_value(171) -> 41094811730846668025320233460001005200; -inv_value(172) -> 32875849384677334420256186768000804160; -inv_value(173) -> 26300679507741867536204949414400643328; -inv_value(174) -> 42081087212386988057927919063041029325; -inv_value(175) -> 33664869769909590446342335250432823460; -inv_value(176) -> 26931895815927672357073868200346258768; -inv_value(177) -> 21545516652742137885659094560277007015; -inv_value(178) -> 34472826644387420617054551296443211223; -inv_value(179) -> 27578261315509936493643641037154568979; -inv_value(180) -> 22062609052407949194914912829723655183; -inv_value(181) -> 35300174483852718711863860527557848292; -inv_value(182) -> 28240139587082174969491088422046278634; -inv_value(183) -> 22592111669665739975592870737637022907; -inv_value(184) -> 36147378671465183960948593180219236651; -inv_value(185) -> 28917902937172147168758874544175389321; -inv_value(186) -> 23134322349737717735007099635340311457; -inv_value(187) -> 37014915759580348376011359416544498331; -inv_value(188) -> 29611932607664278700809087533235598665; -inv_value(189) -> 23689546086131422960647270026588478932; -inv_value(190) -> 37903273737810276737035632042541566291; -inv_value(191) -> 30322618990248221389628505634033253033; -inv_value(192) -> 24258095192198577111702804507226602426; -inv_value(193) -> 38812952307517723378724487211562563882; -inv_value(194) -> 31050361846014178702979589769250051106; -inv_value(195) -> 24840289476811342962383671815400040885; -inv_value(196) -> 39744463162898148739813874904640065415; -inv_value(197) -> 31795570530318518991851099923712052332; -inv_value(198) -> 25436456424254815193480879938969641866; -inv_value(199) -> 40698330278807704309569407902351426985; -inv_value(200) -> 32558664223046163447655526321881141588; -inv_value(201) -> 26046931378436930758124421057504913271; -inv_value(202) -> 41675090205499089212999073692007861233; -inv_value(203) -> 33340072164399271370399258953606288986; -inv_value(204) -> 26672057731519417096319407162885031189; -inv_value(205) -> 21337646185215533677055525730308024951; -inv_value(206) -> 34140233896344853883288841168492839922; -inv_value(207) -> 27312187117075883106631072934794271938; -inv_value(208) -> 21849749693660706485304858347835417550; -inv_value(209) -> 34959599509857130376487773356536668080; -inv_value(210) -> 27967679607885704301190218685229334464; -inv_value(211) -> 22374143686308563440952174948183467571; -inv_value(212) -> 35798629898093701505523479917093548114; -inv_value(213) -> 28638903918474961204418783933674838491; -inv_value(214) -> 22911123134779968963535027146939870793; -inv_value(215) -> 36657797015647950341656043435103793269; -inv_value(216) -> 29326237612518360273324834748083034615; -inv_value(217) -> 23460990090014688218659867798466427692; -inv_value(218) -> 37537584144023501149855788477546284307; -inv_value(219) -> 30030067315218800919884630782037027446; -inv_value(220) -> 24024053852175040735907704625629621957; -inv_value(221) -> 38438486163480065177452327401007395130; -inv_value(222) -> 30750788930784052141961861920805916104; -inv_value(223) -> 24600631144627241713569489536644732884; -inv_value(224) -> 39361009831403586741711183258631572614; -inv_value(225) -> 31488807865122869393368946606905258091; -inv_value(226) -> 25191046292098295514695157285524206473; -inv_value(227) -> 40305674067357272823512251656838730356; -inv_value(228) -> 32244539253885818258809801325470984285; -inv_value(229) -> 25795631403108654607047841060376787428; -inv_value(230) -> 41273010244973847371276545696602859885; -inv_value(231) -> 33018408195979077897021236557282287908; -inv_value(232) -> 26414726556783262317616989245825830326; -inv_value(233) -> 42263562490853219708187182793321328522; -inv_value(234) -> 33810849992682575766549746234657062818; -inv_value(235) -> 27048679994146060613239796987725650254; -inv_value(236) -> 21638943995316848490591837590180520204; -inv_value(237) -> 34622310392506957584946940144288832325; -inv_value(238) -> 27697848314005566067957552115431065860; -inv_value(239) -> 22158278651204452854366041692344852688; -inv_value(240) -> 35453245841927124566985666707751764301; -inv_value(241) -> 28362596673541699653588533366201411441; -inv_value(242) -> 22690077338833359722870826692961129153; -inv_value(243) -> 36304123742133375556593322708737806644; -inv_value(244) -> 29043298993706700445274658166990245316; -inv_value(245) -> 23234639194965360356219726533592196253; -inv_value(246) -> 37175422711944576569951562453747514004; -inv_value(247) -> 29740338169555661255961249962998011203; -inv_value(248) -> 23792270535644529004768999970398408963; -inv_value(249) -> 38067632857031246407630399952637454340; -inv_value(250) -> 30454106285624997126104319962109963472; -inv_value(251) -> 24363285028499997700883455969687970778; -inv_value(252) -> 38981256045599996321413529551500753244; -inv_value(253) -> 31185004836479997057130823641200602595; -inv_value(254) -> 24948003869183997645704658912960482076; -inv_value(255) -> 39916806190694396233127454260736771322; -inv_value(256) -> 31933444952555516986501963408589417058; -inv_value(257) -> 25546755962044413589201570726871533646; -inv_value(258) -> 40874809539271061742722513162994453834; -inv_value(259) -> 32699847631416849394178010530395563067; -inv_value(260) -> 26159878105133479515342408424316450454; -inv_value(261) -> 41855804968213567224547853478906320726; -inv_value(262) -> 33484643974570853779638282783125056581; -inv_value(263) -> 26787715179656683023710626226500045265; -inv_value(264) -> 21430172143725346418968500981200036212; -inv_value(265) -> 34288275429960554270349601569920057938; -inv_value(266) -> 27430620343968443416279681255936046351; -inv_value(267) -> 21944496275174754733023745004748837081; -inv_value(268) -> 35111194040279607572837992007598139329; -inv_value(269) -> 28088955232223686058270393606078511463; -inv_value(270) -> 22471164185778948846616314884862809171; -inv_value(271) -> 35953862697246318154586103815780494673; -inv_value(272) -> 28763090157797054523668883052624395738; -inv_value(273) -> 23010472126237643618935106442099516591; -inv_value(274) -> 36816755401980229790296170307359226545; -inv_value(275) -> 29453404321584183832236936245887381236; -inv_value(276) -> 23562723457267347065789548996709904989; -inv_value(277) -> 37700357531627755305263278394735847982; -inv_value(278) -> 30160286025302204244210622715788678386; -inv_value(279) -> 24128228820241763395368498172630942709; -inv_value(280) -> 38605166112386821432589597076209508334; -inv_value(281) -> 30884132889909457146071677660967606667; -inv_value(282) -> 24707306311927565716857342128774085334; -inv_value(283) -> 39531690099084105146971747406038536534; -inv_value(284) -> 31625352079267284117577397924830829227; -inv_value(285) -> 25300281663413827294061918339864663382; -inv_value(286) -> 40480450661462123670499069343783461410; -inv_value(287) -> 32384360529169698936399255475026769128; -inv_value(288) -> 25907488423335759149119404380021415303; -inv_value(289) -> 41451981477337214638591047008034264484; -inv_value(290) -> 33161585181869771710872837606427411587; -inv_value(291) -> 26529268145495817368698270085141929270; -inv_value(292) -> 42446829032793307789917232136227086832; -inv_value(293) -> 33957463226234646231933785708981669466; -inv_value(294) -> 27165970580987716985547028567185335573; -inv_value(295) -> 21732776464790173588437622853748268458; -inv_value(296) -> 34772442343664277741500196565997229533; -inv_value(297) -> 27817953874931422193200157252797783626; -inv_value(298) -> 22254363099945137754560125802238226901; -inv_value(299) -> 35606980959912220407296201283581163042; -inv_value(300) -> 28485584767929776325836961026864930433; -inv_value(301) -> 22788467814343821060669568821491944347; -inv_value(302) -> 36461548502950113697071310114387110955; -inv_value(303) -> 29169238802360090957657048091509688764; -inv_value(304) -> 23335391041888072766125638473207751011; -inv_value(305) -> 37336625667020916425801021557132401617; -inv_value(306) -> 29869300533616733140640817245705921294; -inv_value(307) -> 23895440426893386512512653796564737035; -inv_value(308) -> 38232704683029418420020246074503579256; -inv_value(309) -> 30586163746423534736016196859602863405; -inv_value(310) -> 24468930997138827788812957487682290724; -inv_value(311) -> 39150289595422124462100731980291665158; -inv_value(312) -> 31320231676337699569680585584233332127; -inv_value(313) -> 25056185341070159655744468467386665702; -inv_value(314) -> 40089896545712255449191149547818665122; -inv_value(315) -> 32071917236569804359352919638254932098; -inv_value(316) -> 25657533789255843487482335710603945678; -inv_value(317) -> 41052054062809349579971737136966313085; -inv_value(318) -> 32841643250247479663977389709573050468; -inv_value(319) -> 26273314600197983731181911767658440375; -inv_value(320) -> 42037303360316773969891058828253504599; -inv_value(321) -> 33629842688253419175912847062602803679; -inv_value(322) -> 26903874150602735340730277650082242944; -inv_value(323) -> 21523099320482188272584222120065794355; -inv_value(324) -> 34436958912771501236134755392105270968; -inv_value(325) -> 27549567130217200988907804313684216774; -inv_value(326) -> 22039653704173760791126243450947373419; -inv_value(327) -> 35263445926678017265801989521515797471; -inv_value(328) -> 28210756741342413812641591617212637977; -inv_value(329) -> 22568605393073931050113273293770110382; -inv_value(330) -> 36109768628918289680181237270032176610; -inv_value(331) -> 28887814903134631744144989816025741288; -inv_value(332) -> 23110251922507705395315991852820593031; -inv_value(333) -> 36976403076012328632505586964512948849; -inv_value(334) -> 29581122460809862906004469571610359079; -inv_value(335) -> 23664897968647890324803575657288287263; -inv_value(336) -> 37863836749836624519685721051661259621; -inv_value(337) -> 30291069399869299615748576841329007697; -inv_value(338) -> 24232855519895439692598861473063206158; -inv_value(339) -> 38772568831832703508158178356901129852; -inv_value(340) -> 31018055065466162806526542685520903882; -inv_value(341) -> 24814444052372930245221234148416723105; -inv_value(_) -> error(function_clause). diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl index 98eea64b0ea0..4ed42d6c9f9a 100644 --- a/lib/stdlib/src/io_lib_pretty.erl +++ b/lib/stdlib/src/io_lib_pretty.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -27,7 +27,7 @@ -export([print/1,print/2,print/3,print/4,print/5,print/6]). %% To be used by io_lib only. --export([intermediate/6, write/1]). +-export([intermediate/7, write/1]). %%% %%% Exported functions @@ -64,7 +64,8 @@ print(Term) -> | {'line_length', line_length()} | {'line_max_chars', line_max_chars()} | {'record_print_fun', rec_print_fun()} - | {'strings', boolean()}. + | {'strings', boolean()} + | {'maps_order', maps:iterator_order()}. -type options() :: [option()]. -spec print(term(), rec_print_fun()) -> chars(); @@ -79,7 +80,8 @@ print(Term, Options) when is_list(Options) -> RecDefFun = get_option(record_print_fun, Options, no_fun), Encoding = get_option(encoding, Options, epp:default_encoding()), Strings = get_option(strings, Options, true), - print(Term, Col, Ll, D, M, T, RecDefFun, Encoding, Strings); + MapsOrder = get_option(maps_order, Options, undefined), + print(Term, Col, Ll, D, M, T, RecDefFun, Encoding, Strings, MapsOrder); print(Term, RecDefFun) -> print(Term, -1, RecDefFun). @@ -91,7 +93,7 @@ print(Term, Depth, RecDefFun) -> -spec print(term(), column(), line_length(), depth()) -> chars(). print(Term, Col, Ll, D) -> - print(Term, Col, Ll, D, _M=-1, _T=-1, no_fun, latin1, true). + print(Term, Col, Ll, D, _M=-1, _T=-1, no_fun, latin1, true, undefined). -spec print(term(), column(), line_length(), depth(), rec_print_fun()) -> chars(). @@ -102,7 +104,7 @@ print(Term, Col, Ll, D, RecDefFun) -> rec_print_fun()) -> chars(). print(Term, Col, Ll, D, M, RecDefFun) -> - print(Term, Col, Ll, D, M, _T=-1, RecDefFun, latin1, true). + print(Term, Col, Ll, D, M, _T=-1, RecDefFun, latin1, true, undefined). %% D = Depth, default -1 (infinite), or LINEMAX=30 when printing from shell %% T = chars_limit, that is, maximal number of characters, default -1 @@ -111,22 +113,22 @@ print(Term, Col, Ll, D, M, RecDefFun) -> %% Col = current column, default 1 %% Ll = line length/~p field width, default 80 %% M = CHAR_MAX (-1 if no max, 60 when printing from shell) -print(_, _, _, 0, _M, _T, _RF, _Enc, _Str) -> "..."; -print(_, _, _, _D, _M, 0, _RF, _Enc, _Str) -> "..."; -print(Term, Col, Ll, D, M, T, RecDefFun, Enc, Str) when Col =< 0 -> +print(_, _, _, 0, _M, _T, _RF, _Enc, _Str, _Ord) -> "..."; +print(_, _, _, _D, _M, 0, _RF, _Enc, _Str, _Ord) -> "..."; +print(Term, Col, Ll, D, M, T, RecDefFun, Enc, Str, Ord) when Col =< 0 -> %% ensure Col is at least 1 - print(Term, 1, Ll, D, M, T, RecDefFun, Enc, Str); -print(Atom, _Col, _Ll, _D, _M, _T, _RF, Enc, _Str) when is_atom(Atom) -> + print(Term, 1, Ll, D, M, T, RecDefFun, Enc, Str, Ord); +print(Atom, _Col, _Ll, _D, _M, _T, _RF, Enc, _Str, _Ord) when is_atom(Atom) -> write_atom(Atom, Enc); -print(Term, Col, Ll, D, M0, T, RecDefFun, Enc, Str) when is_tuple(Term); +print(Term, Col, Ll, D, M0, T, RecDefFun, Enc, Str, Ord) when is_tuple(Term); is_list(Term); is_map(Term); is_bitstring(Term) -> %% preprocess and compute total number of chars {_, Len, _Dots, _} = If = case T < 0 of - true -> print_length(Term, D, T, RecDefFun, Enc, Str); - false -> intermediate(Term, D, T, RecDefFun, Enc, Str) + true -> print_length(Term, D, T, RecDefFun, Enc, Str, Ord); + false -> intermediate(Term, D, T, RecDefFun, Enc, Str, Ord) end, %% use Len as CHAR_MAX if M0 = -1 M = max_cs(M0, Len), @@ -143,7 +145,7 @@ print(Term, Col, Ll, D, M0, T, RecDefFun, Enc, Str) when is_tuple(Term); 1), pp(If, Col, Ll, M, TInd, indent(Col), 0, 0) end; -print(Term, _Col, _Ll, _D, _M, _T, _RF, _Enc, _Str) -> +print(Term, _Col, _Ll, _D, _M, _T, _RF, _Enc, _Str, _Ord) -> %% atomic data types (bignums, atoms, ...) are never truncated io_lib:write(Term). @@ -442,19 +444,19 @@ write_tail(E, S) -> }. -spec intermediate(term(), depth(), pos_integer(), rec_print_fun(), - encoding(), boolean()) -> intermediate_format(). + encoding(), boolean(), boolean()) -> intermediate_format(). -intermediate(Term, D, T, RF, Enc, Str) when T > 0 -> +intermediate(Term, D, T, RF, Enc, Str, Ord) when T > 0 -> D0 = 1, - If = print_length(Term, D0, T, RF, Enc, Str), + If = print_length(Term, D0, T, RF, Enc, Str, Ord), case If of {_, Len, Dots, _} when Dots =:= 0; Len > T; D =:= 1 -> If; {_, Len, _, _} -> - find_upper(If, Term, T, D0, 2, D, RF, Enc, Str, Len) + find_upper(If, Term, T, D0, 2, D, RF, Enc, Str, Ord, Len) end. -find_upper(Lower, Term, T, Dl, Dd, D, RF, Enc, Str, LastLen) -> +find_upper(Lower, Term, T, Dl, Dd, D, RF, Enc, Str, Ord, LastLen) -> Dd2 = Dd * 2, D1 = case D < 0 of true -> Dl + Dd2; @@ -468,14 +470,14 @@ find_upper(Lower, Term, T, Dl, Dd, D, RF, Enc, Str, LastLen) -> %% Cannot happen if print_length() is free of bugs. If; {_, Len, _, _} when Len =< T, D1 < D orelse D < 0 -> - find_upper(If, Term, T, D1, Dd2, D, RF, Enc, Str, Len); + find_upper(If, Term, T, D1, Dd2, D, RF, Enc, Str, Ord, Len); _ -> - search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str) + search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str, Ord) end. %% Lower has NumOfDots > 0 and Len =< T. %% Upper has NumOfDots > 0 and Len > T. -search_depth(Lower, Upper, _Term, T, Dl, Du, _RF, _Enc, _Str) +search_depth(Lower, Upper, _Term, T, Dl, Du, _RF, _Enc, _Str, _Ord) when Du - Dl =:= 1 -> %% The returned intermediate format has Len >= T. case Lower of @@ -484,7 +486,7 @@ search_depth(Lower, Upper, _Term, T, Dl, Du, _RF, _Enc, _Str) _ -> Upper end; -search_depth(Lower, Upper, Term, T, Dl, Du, RF, Enc, Str) -> +search_depth(Lower, Upper, Term, T, Dl, Du, RF, Enc, Str, Ord) -> D1 = (Dl + Du) div 2, If = expand(Lower, T, D1 - Dl), case If of @@ -493,9 +495,9 @@ search_depth(Lower, Upper, Term, T, Dl, Du, RF, Enc, Str) -> %% This is a bit expensive since the work to %% crate Upper is wasted. It is the price %% to pay to get a more balanced output. - search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str); + search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str, Ord); _ -> - search_depth(If, Upper, Term, T, D1, Du, RF, Enc, Str) + search_depth(If, Upper, Term, T, D1, Du, RF, Enc, Str, Ord) end. %% The depth (D) is used for extracting and counting the characters to @@ -504,16 +506,16 @@ search_depth(Lower, Upper, Term, T, Dl, Du, RF, Enc, Str) -> %% counted but need to be added later. %% D =/= 0 -print_length([], _D, _T, _RF, _Enc, _Str) -> +print_length([], _D, _T, _RF, _Enc, _Str, _Ord) -> {"[]", 2, 0, no_more}; -print_length({}, _D, _T, _RF, _Enc, _Str) -> +print_length({}, _D, _T, _RF, _Enc, _Str, _Ord) -> {"{}", 2, 0, no_more}; -print_length(#{}=M, _D, _T, _RF, _Enc, _Str) when map_size(M) =:= 0 -> +print_length(#{}=M, _D, _T, _RF, _Enc, _Str, _Ord) when map_size(M) =:= 0 -> {"#{}", 3, 0, no_more}; -print_length(Atom, _D, _T, _RF, Enc, _Str) when is_atom(Atom) -> +print_length(Atom, _D, _T, _RF, Enc, _Str, _Ord) when is_atom(Atom) -> S = write_atom(Atom, Enc), {S, io_lib:chars_length(S), 0, no_more}; -print_length(List, D, T, RF, Enc, Str) when is_list(List) -> +print_length(List, D, T, RF, Enc, Str, Ord) when is_list(List) -> %% only flat lists are "printable" case Str andalso printable_list(List, D, T, Enc) of true -> @@ -527,37 +529,37 @@ print_length(List, D, T, RF, Enc, Str) when is_list(List) -> %% does not make Prefix longer. {[S | "..."], 3 + io_lib:chars_length(S), 0, no_more}; false -> - case print_length_list(List, D, T, RF, Enc, Str) of + case print_length_list(List, D, T, RF, Enc, Str, Ord) of {What, Len, Dots, _More} when Dots > 0 -> More = fun(T1, Dd) -> - ?FUNCTION_NAME(List, D+Dd, T1, RF, Enc, Str) + ?FUNCTION_NAME(List, D+Dd, T1, RF, Enc, Str, Ord) end, {What, Len, Dots, More}; If -> If end end; -print_length(Fun, _D, _T, _RF, _Enc, _Str) when is_function(Fun) -> +print_length(Fun, _D, _T, _RF, _Enc, _Str, _Ord) when is_function(Fun) -> S = io_lib:write(Fun), {S, iolist_size(S), 0, no_more}; -print_length(R, D, T, RF, Enc, Str) when is_atom(element(1, R)), - is_function(RF) -> +print_length(R, D, T, RF, Enc, Str, Ord) when is_atom(element(1, R)), + is_function(RF) -> case RF(element(1, R), tuple_size(R) - 1) of no -> - print_length_tuple(R, D, T, RF, Enc, Str); + print_length_tuple(R, D, T, RF, Enc, Str, Ord); RDefs -> - print_length_record(R, D, T, RF, RDefs, Enc, Str) + print_length_record(R, D, T, RF, RDefs, Enc, Str, Ord) end; -print_length(Tuple, D, T, RF, Enc, Str) when is_tuple(Tuple) -> - print_length_tuple(Tuple, D, T, RF, Enc, Str); -print_length(Map, D, T, RF, Enc, Str) when is_map(Map) -> - print_length_map(Map, D, T, RF, Enc, Str); -print_length(<<>>, _D, _T, _RF, _Enc, _Str) -> +print_length(Tuple, D, T, RF, Enc, Str, Ord) when is_tuple(Tuple) -> + print_length_tuple(Tuple, D, T, RF, Enc, Str, Ord); +print_length(Map, D, T, RF, Enc, Str, Ord) when is_map(Map) -> + print_length_map(Map, D, T, RF, Enc, Str, Ord); +print_length(<<>>, _D, _T, _RF, _Enc, _Str, _Ord) -> {"<<>>", 4, 0, no_more}; -print_length(<<_/bitstring>> = Bin, 1, _T, RF, Enc, Str) -> - More = fun(T1, Dd) -> ?FUNCTION_NAME(Bin, 1+Dd, T1, RF, Enc, Str) end, +print_length(<<_/bitstring>> = Bin, 1, _T, RF, Enc, Str, Ord) -> + More = fun(T1, Dd) -> ?FUNCTION_NAME(Bin, 1+Dd, T1, RF, Enc, Str, Ord) end, {"<<...>>", 7, 3, More}; -print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> +print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str, Ord) -> D1 = D - 1, case Str andalso @@ -573,13 +575,13 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> {true, true, Prefix} -> S = io_lib:write_string(Prefix, $"), %" More = fun(T1, Dd) -> - ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str) + ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str, Ord) end, {[$<,$<,S|"...>>"], 7 + length(S), 3, More}; {false, true, Prefix} -> S = io_lib:write_string(Prefix, $"), %" More = fun(T1, Dd) -> - ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str) + ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str, Ord) end, {[$<,$<,S|"/utf8...>>"], 12 + io_lib:chars_length(S), 3, More}; false -> @@ -588,135 +590,135 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) -> {{bin, S}, iolist_size(S), 0, no_more}; {S, _Rest} -> More = fun(T1, Dd) -> - ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str) + ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str, Ord) end, {{bin, S}, iolist_size(S), 3, More} end end; -print_length(Term, _D, _T, _RF, _Enc, _Str) -> +print_length(Term, _D, _T, _RF, _Enc, _Str, _Ord) -> S = io_lib:write(Term), %% S can contain unicode, so iolist_size(S) cannot be used here {S, io_lib:chars_length(S), 0, no_more}. -print_length_map(Map, 1, _T, RF, Enc, Str) -> - More = fun(T1, Dd) -> ?FUNCTION_NAME(Map, 1+Dd, T1, RF, Enc, Str) end, +print_length_map(Map, 1, _T, RF, Enc, Str, Ord) -> + More = fun(T1, Dd) -> ?FUNCTION_NAME(Map, 1+Dd, T1, RF, Enc, Str, Ord) end, {"#{...}", 6, 3, More}; -print_length_map(Map, D, T, RF, Enc, Str) when is_map(Map) -> - Next = maps:next(maps:iterator(Map)), - PairsS = print_length_map_pairs(Next, D, D - 1, tsub(T, 3), RF, Enc, Str), +print_length_map(Map, D, T, RF, Enc, Str, Ord) when is_map(Map) -> + Next = maps:next(maps:iterator(Map, Ord)), + PairsS = print_length_map_pairs(Next, D, D - 1, tsub(T, 3), RF, Enc, Str, Ord), {Len, Dots} = list_length(PairsS, 3, 0), {{map, PairsS}, Len, Dots, no_more}. -print_length_map_pairs(none, _D, _D0, _T, _RF, _Enc, _Str) -> +print_length_map_pairs(none, _D, _D0, _T, _RF, _Enc, _Str, _Ord) -> []; -print_length_map_pairs(Term, D, D0, T, RF, Enc, Str) when D =:= 1; T =:= 0-> +print_length_map_pairs(Term, D, D0, T, RF, Enc, Str, Ord) when D =:= 1; T =:= 0-> More = fun(T1, Dd) -> - ?FUNCTION_NAME(Term, D+Dd, D0, T1, RF, Enc, Str) + ?FUNCTION_NAME(Term, D+Dd, D0, T1, RF, Enc, Str, Ord) end, {dots, 3, 3, More}; -print_length_map_pairs({K, V, Iter}, D, D0, T, RF, Enc, Str) -> +print_length_map_pairs({K, V, Iter}, D, D0, T, RF, Enc, Str, Ord) -> Next = maps:next(Iter), T1 = case Next =:= none of false -> tsub(T, 1); true -> T end, - Pair1 = print_length_map_pair(K, V, D0, T1, RF, Enc, Str), + Pair1 = print_length_map_pair(K, V, D0, T1, RF, Enc, Str, Ord), {_, Len1, _, _} = Pair1, [Pair1 | - print_length_map_pairs(Next, D - 1, D0, tsub(T1, Len1), RF, Enc, Str)]. + print_length_map_pairs(Next, D - 1, D0, tsub(T1, Len1), RF, Enc, Str, Ord)]. -print_length_map_pair(K, V, D, T, RF, Enc, Str) -> - {_, KL, KD, _} = P1 = print_length(K, D, T, RF, Enc, Str), +print_length_map_pair(K, V, D, T, RF, Enc, Str, Ord) -> + {_, KL, KD, _} = P1 = print_length(K, D, T, RF, Enc, Str, Ord), KL1 = KL + 4, - {_, VL, VD, _} = P2 = print_length(V, D, tsub(T, KL1), RF, Enc, Str), + {_, VL, VD, _} = P2 = print_length(V, D, tsub(T, KL1), RF, Enc, Str, Ord), {{map_pair, P1, P2}, KL1 + VL, KD + VD, no_more}. -print_length_tuple(Tuple, 1, _T, RF, Enc, Str) -> - More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, Enc, Str) end, +print_length_tuple(Tuple, 1, _T, RF, Enc, Str, Ord) -> + More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, Enc, Str, Ord) end, {"{...}", 5, 3, More}; -print_length_tuple(Tuple, D, T, RF, Enc, Str) -> - L = print_length_tuple1(Tuple, 1, D, tsub(T, 2), RF, Enc, Str), +print_length_tuple(Tuple, D, T, RF, Enc, Str, Ord) -> + L = print_length_tuple1(Tuple, 1, D, tsub(T, 2), RF, Enc, Str, Ord), IsTagged = is_atom(element(1, Tuple)) and (tuple_size(Tuple) > 1), {Len, Dots} = list_length(L, 2, 0), {{tuple,IsTagged,L}, Len, Dots, no_more}. -print_length_tuple1(Tuple, I, _D, _T, _RF, _Enc, _Str) +print_length_tuple1(Tuple, I, _D, _T, _RF, _Enc, _Str, _Ord) when I > tuple_size(Tuple) -> []; -print_length_tuple1(Tuple, I, D, T, RF, Enc, Str) when D =:= 1; T =:= 0-> - More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, I, D+Dd, T1, RF, Enc, Str) end, +print_length_tuple1(Tuple, I, D, T, RF, Enc, Str, Ord) when D =:= 1; T =:= 0-> + More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, I, D+Dd, T1, RF, Enc, Str, Ord) end, {dots, 3, 3, More}; -print_length_tuple1(Tuple, I, D, T, RF, Enc, Str) -> +print_length_tuple1(Tuple, I, D, T, RF, Enc, Str, Ord) -> E = element(I, Tuple), T1 = case I =:= tuple_size(Tuple) of false -> tsub(T, 1); true -> T end, - {_, Len1, _, _} = Elem1 = print_length(E, D - 1, T1, RF, Enc, Str), + {_, Len1, _, _} = Elem1 = print_length(E, D - 1, T1, RF, Enc, Str, Ord), T2 = tsub(T1, Len1), - [Elem1 | print_length_tuple1(Tuple, I + 1, D - 1, T2, RF, Enc, Str)]. + [Elem1 | print_length_tuple1(Tuple, I + 1, D - 1, T2, RF, Enc, Str, Ord)]. -print_length_record(Tuple, 1, _T, RF, RDefs, Enc, Str) -> +print_length_record(Tuple, 1, _T, RF, RDefs, Enc, Str, Ord) -> More = fun(T1, Dd) -> - ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, RDefs, Enc, Str) + ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, RDefs, Enc, Str, Ord) end, {"{...}", 5, 3, More}; -print_length_record(Tuple, D, T, RF, RDefs, Enc, Str) -> +print_length_record(Tuple, D, T, RF, RDefs, Enc, Str, Ord) -> Name = [$# | write_atom(element(1, Tuple), Enc)], NameL = io_lib:chars_length(Name), T1 = tsub(T, NameL+2), - L = print_length_fields(RDefs, D - 1, T1, Tuple, 2, RF, Enc, Str), + L = print_length_fields(RDefs, D - 1, T1, Tuple, 2, RF, Enc, Str, Ord), {Len, Dots} = list_length(L, NameL + 2, 0), {{record, [{Name,NameL} | L]}, Len, Dots, no_more}. -print_length_fields([], _D, _T, Tuple, I, _RF, _Enc, _Str) +print_length_fields([], _D, _T, Tuple, I, _RF, _Enc, _Str, _Ord) when I > tuple_size(Tuple) -> []; -print_length_fields(Term, D, T, Tuple, I, RF, Enc, Str) +print_length_fields(Term, D, T, Tuple, I, RF, Enc, Str, Ord) when D =:= 1; T =:= 0 -> More = fun(T1, Dd) -> - ?FUNCTION_NAME(Term, D+Dd, T1, Tuple, I, RF, Enc, Str) + ?FUNCTION_NAME(Term, D+Dd, T1, Tuple, I, RF, Enc, Str, Ord) end, {dots, 3, 3, More}; -print_length_fields([Def | Defs], D, T, Tuple, I, RF, Enc, Str) -> +print_length_fields([Def | Defs], D, T, Tuple, I, RF, Enc, Str, Ord) -> E = element(I, Tuple), T1 = case I =:= tuple_size(Tuple) of false -> tsub(T, 1); true -> T end, - Field1 = print_length_field(Def, D - 1, T1, E, RF, Enc, Str), + Field1 = print_length_field(Def, D - 1, T1, E, RF, Enc, Str, Ord), {_, Len1, _, _} = Field1, T2 = tsub(T1, Len1), [Field1 | - print_length_fields(Defs, D - 1, T2, Tuple, I + 1, RF, Enc, Str)]. + print_length_fields(Defs, D - 1, T2, Tuple, I + 1, RF, Enc, Str, Ord)]. -print_length_field(Def, D, T, E, RF, Enc, Str) -> +print_length_field(Def, D, T, E, RF, Enc, Str, Ord) -> Name = write_atom(Def, Enc), NameL = io_lib:chars_length(Name) + 3, {_, Len, Dots, _} = - Field = print_length(E, D, tsub(T, NameL), RF, Enc, Str), + Field = print_length(E, D, tsub(T, NameL), RF, Enc, Str, Ord), {{field, Name, NameL, Field}, NameL + Len, Dots, no_more}. -print_length_list(List, D, T, RF, Enc, Str) -> - L = print_length_list1(List, D, tsub(T, 2), RF, Enc, Str), +print_length_list(List, D, T, RF, Enc, Str, Ord) -> + L = print_length_list1(List, D, tsub(T, 2), RF, Enc, Str, Ord), {Len, Dots} = list_length(L, 2, 0), {{list, L}, Len, Dots, no_more}. -print_length_list1([], _D, _T, _RF, _Enc, _Str) -> +print_length_list1([], _D, _T, _RF, _Enc, _Str, _Ord) -> []; -print_length_list1(Term, D, T, RF, Enc, Str) when D =:= 1; T =:= 0-> - More = fun(T1, Dd) -> ?FUNCTION_NAME(Term, D+Dd, T1, RF, Enc, Str) end, +print_length_list1(Term, D, T, RF, Enc, Str, Ord) when D =:= 1; T =:= 0-> + More = fun(T1, Dd) -> ?FUNCTION_NAME(Term, D+Dd, T1, RF, Enc, Str, Ord) end, {dots, 3, 3, More}; -print_length_list1([E | Es], D, T, RF, Enc, Str) -> +print_length_list1([E | Es], D, T, RF, Enc, Str, Ord) -> %% If E is the last element in list, don't account length for a comma. T1 = case Es =:= [] of false -> tsub(T, 1); true -> T end, - {_, Len1, _, _} = Elem1 = print_length(E, D - 1, T1, RF, Enc, Str), - [Elem1 | print_length_list1(Es, D - 1, tsub(T1, Len1), RF, Enc, Str)]; -print_length_list1(E, D, T, RF, Enc, Str) -> - print_length(E, D - 1, T, RF, Enc, Str). + {_, Len1, _, _} = Elem1 = print_length(E, D - 1, T1, RF, Enc, Str, Ord), + [Elem1 | print_length_list1(Es, D - 1, tsub(T1, Len1), RF, Enc, Str, Ord)]; +print_length_list1(E, D, T, RF, Enc, Str, Ord) -> + print_length(E, D - 1, T, RF, Enc, Str, Ord). list_length([], Acc, DotsAcc) -> {Acc, DotsAcc}; diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index 161b5634b2d5..cb1c008ed1e5 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -22,29 +22,57 @@ -compile({no_auto_import,[max/2]}). -compile({no_auto_import,[min/2]}). --export([append/2, append/1, subtract/2, reverse/1, - nth/2, nthtail/2, prefix/2, suffix/2, droplast/1, last/1, - seq/2, seq/3, sum/1, duplicate/2, min/1, max/1, sublist/2, sublist/3, - delete/2, - unzip/1, unzip3/1, zip/2, zip3/3, zipwith/3, zipwith3/4, - sort/1, merge/1, merge/2, rmerge/2, merge3/3, rmerge3/3, - usort/1, umerge/1, umerge3/3, umerge/2, rumerge3/3, rumerge/2, - concat/1, flatten/1, flatten/2, flatlength/1, - keydelete/3, keyreplace/4, keytake/3, keystore/4, - keysort/2, keymerge/3, rkeymerge/3, rukeymerge/3, - ukeysort/2, ukeymerge/3, keymap/3]). - --export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]). - --export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2, - partition/2,zf/2,filtermap/2, - mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2, - search/2, splitwith/2,split/2, - join/2]). - -%%% BIFs +%% BIFs (implemented in the runtime system). -export([keyfind/3, keymember/3, keysearch/3, member/2, reverse/2]). +%% Miscellaneous list functions that don't take funs as +%% arguments. Please keep in alphabetical order. +-export([append/1, append/2, concat/1, + delete/2, droplast/1, duplicate/2, + enumerate/1, enumerate/2, enumerate/3, + flatlength/1, flatten/1, flatten/2, + join/2, last/1, min/1, max/1, + nth/2, nthtail/2, + prefix/2, reverse/1, seq/2, seq/3, + split/2, sublist/2, sublist/3, + subtract/2, suffix/2, sum/1, + uniq/1, unzip/1, unzip3/1, + zip/2, zip/3, zip3/3, zip3/4]). + +%% Functions taking a list of tuples and a position within the tuple. +-export([keydelete/3, keyreplace/4, keymap/3, + keytake/3, keystore/4]). + +%% Sort functions that operate on list of tuples. +-export([keymerge/3, keysort/2, ukeymerge/3, ukeysort/2]). + +%% Sort and merge functions. +-export([merge/1, merge/2, merge/3, merge3/3, + sort/1, sort/2, + umerge/1, umerge/2, umerge/3, umerge3/3, + usort/1, usort/2]). + +%% Functions that take fun arguments (high-order functions). Please +%% keep in alphabetical order. +-export([all/2, any/2, dropwhile/2, + filter/2, filtermap/2, flatmap/2, + foldl/3, foldr/3, foreach/2, + map/2, mapfoldl/3, mapfoldr/3, + partition/2, search/2, + splitwith/2, takewhile/2, uniq/2, + zipwith/3, zipwith/4, zipwith3/4, zipwith3/5]). + +%% Undocumented, but used within Erlang/OTP. +-export([zf/2]). + +%% Undocumented and unused merge functions for lists sorted in reverse +%% order. They are exported so that the fundamental building blocks +%% for the sort functions can be tested. (Removing them would save +%% very little because they are thin wrappers calling helper functions +%% used by the documented sort functions.) +-export([rkeymerge/3, rmerge/2, rmerge/3, rmerge3/3, + rukeymerge/3, rumerge/2, rumerge/3, rumerge3/3]). + %% Shadowed by erl_bif_types: lists:keyfind/3 -spec keyfind(Key, N, TupleList) -> Tuple | false when Key :: term(), @@ -168,8 +196,12 @@ reverse([A, B | L]) -> T :: term(). nth(1, [H|_]) -> H; -nth(N, [_|T]) when N > 1 -> - nth(N - 1, T). +nth(N, [_|_]=L) when is_integer(N), N > 1 -> + nth_1(N, L). + +nth_1(1, [H|_]) -> H; +nth_1(N, [_|T]) -> + nth_1(N - 1, T). -spec nthtail(N, List) -> Tail when N :: non_neg_integer(), @@ -177,10 +209,15 @@ nth(N, [_|T]) when N > 1 -> Tail :: [T], T :: term(). +nthtail(0, []) -> []; +nthtail(0, [_|_]=L) -> L; nthtail(1, [_|T]) -> T; -nthtail(N, [_|T]) when N > 1 -> - nthtail(N - 1, T); -nthtail(0, L) when is_list(L) -> L. +nthtail(N, [_|_]=L) when is_integer(N), N > 1 -> + nthtail_1(N, L). + +nthtail_1(1, [_|T]) -> T; +nthtail_1(N, [_|T]) -> + nthtail_1(N - 1, T). %% prefix(Prefix, List) -> (true | false) @@ -259,16 +296,16 @@ seq_loop(0, _, L) -> Incr :: integer(), Seq :: [integer()]. -seq(First, Last, Inc) - when is_integer(First), is_integer(Last), is_integer(Inc) -> - if - Inc > 0, First - Inc =< Last; - Inc < 0, First - Inc >= Last -> - N = (Last - First + Inc) div Inc, - seq_loop(N, Inc*(N-1)+First, Inc, []); - Inc =:= 0, First =:= Last -> - seq_loop(1, First, Inc, []) - end. +seq(First, Last, Inc) + when is_integer(First), is_integer(Last), is_integer(Inc), + (Inc > 0 andalso First - Inc =< Last) orelse + (Inc < 0 andalso First - Inc >= Last) -> + N = (Last - First + Inc) div Inc, + seq_loop(N, Inc * (N - 1) + First, Inc, []); +seq(Same, Same, 0) when is_integer(Same) -> + [Same]; +seq(First, Last, Inc) -> + erlang:error(badarg, [First, Last, Inc], [{error_info, #{module => erl_stdlib_errors}}]). seq_loop(N, X, D, L) when N >= 4 -> Y = X-D, Z = Y-D, W = Z-D, @@ -388,8 +425,35 @@ delete(_, []) -> []. A :: term(), B :: term(). -zip([X | Xs], [Y | Ys]) -> [{X, Y} | zip(Xs, Ys)]; -zip([], []) -> []. +zip(Xs, Ys) -> zip(Xs, Ys, fail). + +-spec zip(List1, List2, How) -> List3 when + List1 :: [A], + List2 :: [B], + List3 :: [{A | DefaultA, B | DefaultB}], + A :: term(), + B :: term(), + How :: 'fail' | 'trim' | {'pad', {DefaultA, DefaultB}}, + DefaultA :: term(), + DefaultB :: term(). + +zip([X | Xs], [Y | Ys], How) -> + [{X, Y} | zip(Xs, Ys, How)]; +zip([], [], fail) -> + []; +zip([], [], trim) -> + []; +zip([], [], {pad, {_, _}}) -> + []; +zip([_ | _], [], trim) -> + []; +zip([], [_ | _], trim) -> + []; +zip([], [_ | _]=Ys, {pad, {X, _}}) -> + [{X, Y} || Y <- Ys]; +zip([_ | _]=Xs, [], {pad, {_, Y}}) -> + [{X, Y} || X <- Xs]. + %% Return {[X0, X1, ..., Xn], [Y0, Y1, ..., Yn]}, for a list [{X0, Y0}, %% {X1, Y1}, ..., {Xn, Yn}]. @@ -418,8 +482,43 @@ unzip([], Xs, Ys) -> {reverse(Xs), reverse(Ys)}. B :: term(), C :: term(). -zip3([X | Xs], [Y | Ys], [Z | Zs]) -> [{X, Y, Z} | zip3(Xs, Ys, Zs)]; -zip3([], [], []) -> []. +zip3(Xs, Ys, Zs) -> zip3(Xs, Ys, Zs, fail). + +-spec zip3(List1, List2, List3, How) -> List4 when + List1 :: [A], + List2 :: [B], + List3 :: [C], + List4 :: [{A | DefaultA, B | DefaultB, C | DefaultC}], + A :: term(), + B :: term(), + C :: term(), + How :: 'fail' | 'trim' | {'pad', {DefaultA, DefaultB, DefaultC}}, + DefaultA :: term(), + DefaultB :: term(), + DefaultC :: term(). + +zip3([X | Xs], [Y | Ys], [Z | Zs], How) -> + [{X, Y, Z} | zip3(Xs, Ys, Zs, How)]; +zip3([], [], [], fail) -> + []; +zip3([], [], [], trim) -> + []; +zip3(Xs, Ys, Zs, trim) when is_list(Xs), is_list(Ys), is_list(Zs) -> + []; +zip3([], [], [], {pad, {_, _, _}}) -> + []; +zip3([], [], [_ |_]=Zs, {pad, {X, Y, _}}) -> + [{X, Y, Z} || Z <- Zs]; +zip3([], [_ | _]=Ys, [], {pad, {X, _, Z}}) -> + [{X, Y, Z} || Y <- Ys]; +zip3([_ | _]=Xs, [], [], {pad, {_, Y, Z}}) -> + [{X, Y, Z} || X <- Xs]; +zip3([], [Y | Ys], [Z | Zs], {pad, {X, _, _}} = How) -> + [{X, Y, Z} | zip3([], Ys, Zs, How)]; +zip3([X | Xs], [], [Z | Zs], {pad, {_, Y, _}} = How) -> + [{X, Y, Z} | zip3(Xs, [], Zs, How)]; +zip3([X | Xs], [Y | Ys], [], {pad, {_, _, Z}} = How) -> + [{X, Y, Z} | zip3(Xs, Ys, [], How)]. %% Return {[X0, X1, ..., Xn], [Y0, Y1, ..., Yn], [Z0, Z1, ..., Zn]}, for %% a list [{X0, Y0, Z0}, {X1, Y1, Z1}, ..., {Xn, Yn, Zn}]. @@ -452,8 +551,36 @@ unzip3([], Xs, Ys, Zs) -> Y :: term(), T :: term(). -zipwith(F, [X | Xs], [Y | Ys]) -> [F(X, Y) | zipwith(F, Xs, Ys)]; -zipwith(F, [], []) when is_function(F, 2) -> []. +zipwith(F, Xs, Ys) -> zipwith(F, Xs, Ys, fail). + +-spec zipwith(Combine, List1, List2, How) -> List3 when + Combine :: fun((X | DefaultX, Y | DefaultY) -> T), + List1 :: [X], + List2 :: [Y], + List3 :: [T], + X :: term(), + Y :: term(), + How :: 'fail' | 'trim' | {'pad', {DefaultX, DefaultY}}, + DefaultX :: term(), + DefaultY :: term(), + T :: term(). + +zipwith(F, [X | Xs], [Y | Ys], How) -> + [F(X, Y) | zipwith(F, Xs, Ys, How)]; +zipwith(F, [], [], fail) when is_function(F, 2) -> + []; +zipwith(F, [], [], trim) when is_function(F, 2) -> + []; +zipwith(F, [], [], {pad, {_, _}}) when is_function(F, 2) -> + []; +zipwith(F, [_ | _], [], trim) when is_function(F, 2) -> + []; +zipwith(F, [], [_ | _], trim) when is_function(F, 2) -> + []; +zipwith(F, [], [_ | _]=Ys, {pad, {X, _}}) -> + [F(X, Y) || Y <- Ys]; +zipwith(F, [_ | _]=Xs, [], {pad, {_, Y}}) -> + [F(X, Y) || X <- Xs]. %% Return [F(X0, Y0, Z0), F(X1, Y1, Z1), ..., F(Xn, Yn, Zn)] for lists %% [X0, X1, ..., Xn], [Y0, Y1, ..., Yn] and [Z0, Z1, ..., Zn]. @@ -469,9 +596,45 @@ zipwith(F, [], []) when is_function(F, 2) -> []. Z :: term(), T :: term(). -zipwith3(F, [X | Xs], [Y | Ys], [Z | Zs]) -> - [F(X, Y, Z) | zipwith3(F, Xs, Ys, Zs)]; -zipwith3(F, [], [], []) when is_function(F, 3) -> []. +zipwith3(F, Xs, Ys, Zs) -> zipwith3(F, Xs, Ys, Zs, fail). + +-spec zipwith3(Combine, List1, List2, List3, How) -> List4 when + Combine :: fun((X | DefaultX, Y | DefaultY, Z | DefaultZ) -> T), + List1 :: [X], + List2 :: [Y], + List3 :: [Z], + List4 :: [T], + X :: term(), + Y :: term(), + Z :: term(), + How :: 'fail' | 'trim' | {'pad', {DefaultX, DefaultY, DefaultZ}}, + DefaultX :: term(), + DefaultY :: term(), + DefaultZ :: term(), + T :: term(). + +zipwith3(F, [X | Xs], [Y | Ys], [Z | Zs], How) -> + [F(X, Y, Z) | zipwith3(F, Xs, Ys, Zs, How)]; +zipwith3(F, [], [], [], fail) when is_function(F, 3) -> + []; +zipwith3(F, [], [], [], trim) when is_function(F, 3) -> + []; +zipwith3(F, Xs, Ys, Zs, trim) when is_function(F, 3), is_list(Xs), is_list(Ys), is_list(Zs) -> + []; +zipwith3(F, [], [], [], {pad, {_, _, _}}) when is_function(F, 3) -> + []; +zipwith3(F, [], [], [_ | _]=Zs, {pad, {X, Y, _}}) -> + [F(X, Y, Z) || Z <- Zs]; +zipwith3(F, [], [_ | _]=Ys, [], {pad, {X, _, Z}}) -> + [F(X, Y, Z) || Y <- Ys]; +zipwith3(F, [_ | _]=Xs, [], [], {pad, {_, Y, Z}}) -> + [F(X, Y, Z) || X <- Xs]; +zipwith3(F, [], [Y | Ys], [Z | Zs], {pad, {X, _, _}} = How) -> + [F(X, Y, Z) | zipwith3(F, [], Ys, Zs, How)]; +zipwith3(F, [X | Xs], [], [Z | Zs], {pad, {_, Y, _}} = How) -> + [F(X, Y, Z) | zipwith3(F, Xs, [], Zs, How)]; +zipwith3(F, [X | Xs], [Y | Ys], [], {pad, {_, _, Z}} = How) -> + [F(X, Y, Z) | zipwith3(F, Xs, Ys, [], How)]. %% sort(List) -> L %% sorts the list L @@ -547,24 +710,44 @@ merge(L) -> Y :: term(), Z :: term(). -merge3(L1, [], L3) -> - merge(L1, L3); -merge3(L1, L2, []) -> - merge(L1, L2); -merge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(merge3_1(L1, [], H2, T2, H3, T3), []). +merge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(merge3_1(L1, [], H2, T2, H3, T3), []); +merge3([_|_]=L1, [_|_]=L2, []) -> + merge(L1, L2); +merge3([_|_]=L1, [], [_|_]=L3) -> + merge(L1, L3); +merge3([_|_]=L1, [], []) -> + L1; +merge3([], [_|_]=L2, [_|_]=L3) -> + merge(L2, L3); +merge3([], [_|_]=L2, []) -> + L2; +merge3([], [], [_|_]=L3) -> + L3; +merge3([], [], []) -> + []. %% rmerge3(X, Y, Z) -> L %% merges three reversed sorted lists X, Y and Z -spec rmerge3([X], [Y], [Z]) -> [(X | Y | Z)]. -rmerge3(L1, [], L3) -> - rmerge(L1, L3); -rmerge3(L1, L2, []) -> - rmerge(L1, L2); -rmerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(rmerge3_1(L1, [], H2, T2, H3, T3), []). +rmerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(rmerge3_1(L1, [], H2, T2, H3, T3), []); +rmerge3([_|_]=L1, [_|_]=L2, []) -> + rmerge(L1, L2); +rmerge3([_|_]=L1, [], [_|_]=L3) -> + rmerge(L1, L3); +rmerge3([_|_]=L1, [], []) -> + L1; +rmerge3([], [_|_]=L2, [_|_]=L3) -> + rmerge(L2, L3); +rmerge3([], [_|_]=L2, []) -> + L2; +rmerge3([], [], [_|_]=L3) -> + L3; +rmerge3([], [], []) -> + []. %% merge(X, Y) -> L %% merges two sorted lists X and Y @@ -576,10 +759,14 @@ rmerge3(L1, [H2 | T2], [H3 | T3]) -> X :: term(), Y :: term(). -merge(T1, []) -> - T1; -merge(T1, [H2 | T2]) -> - lists:reverse(merge2_1(T1, H2, T2, []), []). +merge([_|_]=T1, [H2 | T2]) -> + lists:reverse(merge2_1(T1, H2, T2, []), []); +merge([_|_]=L1, []) -> + L1; +merge([], [_|_]=L2) -> + L2; +merge([], []) -> + []. %% rmerge(X, Y) -> L %% merges two reversed sorted lists X and Y @@ -588,10 +775,14 @@ merge(T1, [H2 | T2]) -> -spec rmerge([X], [Y]) -> [(X | Y)]. -rmerge(T1, []) -> - T1; -rmerge(T1, [H2 | T2]) -> - lists:reverse(rmerge2_1(T1, H2, T2, []), []). +rmerge([_|_]=T1, [H2 | T2]) -> + lists:reverse(rmerge2_1(T1, H2, T2, []), []); +rmerge([_|_]=L1, []) -> + L1; +rmerge([], [_|_]=L2) -> + L2; +rmerge([], []) -> + []. %% concat(L) concatenate the list representation of the elements %% in L - the elements in L can be atoms, numbers of strings. @@ -817,30 +1008,38 @@ keysort_1(_I, X, _EX, [], R) -> T2 :: Tuple, Tuple :: tuple(). -keymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = keymerge2_1(Index, T1, E2, H2, T2, []), - lists:reverse(M, []) - end. +keymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + keymerge_1(Index, L1, L2). + +keymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = keymerge2_1(Index, T1, E2, H2, T2, []), + lists:reverse(M, []); +keymerge_1(_Index, [_|_]=L1, []) -> + L1; +keymerge_1(_Index, [], [_|_]=L2) -> + L2; +keymerge_1(_Index, [], []) -> + []. %% reverse(rkeymerge(I,reverse(A),reverse(B))) is equal to keymerge(I,A,B). -spec rkeymerge(pos_integer(), [X], [Y]) -> [R] when X :: tuple(), Y :: tuple(), R :: tuple(). -rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = rkeymerge2_1(Index, T1, E2, H2, T2, []), - lists:reverse(M, []) - end. +rkeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + rkeymerge_1(Index, L1, L2). + +rkeymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = rkeymerge2_1(Index, T1, E2, H2, T2, []), + lists:reverse(M, []); +rkeymerge_1(_Index, [_|_]=L1, []) -> + L1; +rkeymerge_1(_Index, [], [_|_]=L2) -> + L2; +rkeymerge_1(_Index, [], []) -> + []. -spec ukeysort(N, TupleList1) -> TupleList2 when N :: pos_integer(), @@ -920,30 +1119,38 @@ ukeysort_1(_I, X, _EX, []) -> T2 :: Tuple, Tuple :: tuple(). -ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 -> - case L1 of - [] -> - T2; - [H1 | T1] -> - E1 = element(Index, H1), - M = ukeymerge2_2(Index, T1, E1, H1, T2, []), - lists:reverse(M, []) - end. +ukeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + ukeymerge_1(Index, L1, L2). + +ukeymerge_1(Index, [H1 | T1], [_|_]=T2) -> + E1 = element(Index, H1), + M = ukeymerge2_2(Index, T1, E1, H1, T2, []), + lists:reverse(M, []); +ukeymerge_1(_Index, [_|_]=L1, []) -> + L1; +ukeymerge_1(_Index, [], [_|_]=L2) -> + L2; +ukeymerge_1(_Index, [], []) -> + []. %% reverse(rukeymerge(I,reverse(A),reverse(B))) is equal to ukeymerge(I,A,B). -spec rukeymerge(pos_integer(), [X], [Y]) -> [(X | Y)] when X :: tuple(), Y :: tuple(). -rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = rukeymerge2_1(Index, T1, E2, T2, [], H2), - lists:reverse(M, []) - end. +rukeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + rukeymerge_1(Index, L1, L2). + +rukeymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = rukeymerge2_1(Index, T1, E2, T2, [], H2), + lists:reverse(M, []); +rukeymerge_1(_Index, [_|_]=L1, []) -> + L1; +rukeymerge_1(_Index, [], [_|_]=L2) -> + L2; +rukeymerge_1(_Index, [], []) -> + []. -spec keymap(Fun, N, TupleList1) -> TupleList2 when Fun :: fun((Term1 :: term()) -> Term2 :: term()), @@ -957,6 +1164,36 @@ keymap(Fun, Index, [Tup|Tail]) -> keymap(Fun, Index, []) when is_integer(Index), Index >= 1, is_function(Fun, 1) -> []. +-spec enumerate(List1) -> List2 when + List1 :: [T], + List2 :: [{Index, T}], + Index :: integer(), + T :: term(). +enumerate(List1) -> + enumerate(1, 1, List1). + +-spec enumerate(Index, List1) -> List2 when + List1 :: [T], + List2 :: [{Index, T}], + Index :: integer(), + T :: term(). +enumerate(Index, List1) -> + enumerate(Index, 1, List1). + +-spec enumerate(Index, Step, List1) -> List2 when + List1 :: [T], + List2 :: [{Index, T}], + Index :: integer(), + Step :: integer(), + T :: term(). +enumerate(Index, Step, List1) when is_integer(Index), is_integer(Step) -> + enumerate_1(Index, Step, List1). + +enumerate_1(Index, Step, [H|T]) -> + [{Index, H}|enumerate_1(Index + Step, Step, T)]; +enumerate_1(_Index, _Step, []) -> + []. + %%% Suggestion from OTP-2948: sort and merge with Fun. -spec sort(Fun, List1) -> List2 when @@ -985,19 +1222,33 @@ sort(Fun, [X, Y | T]) -> A :: term(), B :: term(). -merge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> +merge(Fun, L1, L2) when is_function(Fun, 2) -> + merge_1(Fun, L1, L2). + +merge_1(Fun, [_|_]=T1, [H2 | T2]) -> lists:reverse(fmerge2_1(T1, H2, Fun, T2, []), []); -merge(Fun, T1, []) when is_function(Fun, 2) -> - T1. +merge_1(_Fun, [_|_]=L1, []) -> + L1; +merge_1(_Fun, [], [_|_]=L2) -> + L2; +merge_1(_Fun, [], []) -> + []. %% reverse(rmerge(F,reverse(A),reverse(B))) is equal to merge(F,A,B). -spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. -rmerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> +rmerge(Fun, L1, L2) when is_function(Fun, 2) -> + rmerge_1(Fun, L1, L2). + +rmerge_1(Fun, [_|_]=T1, [H2 | T2]) -> lists:reverse(rfmerge2_1(T1, H2, Fun, T2, []), []); -rmerge(Fun, T1, []) when is_function(Fun, 2) -> - T1. +rmerge_1(_Fun, [_|_]=L1, []) -> + L1; +rmerge_1(_Fun, [], [_|_]=L2) -> + L2; +rmerge_1(_Fun, [], []) -> + []. -spec usort(Fun, List1) -> List2 when Fun :: fun((T, T) -> boolean()), @@ -1038,19 +1289,33 @@ usort_1(Fun, X, [Y | L]) -> A :: term(), B :: term(). -umerge(Fun, [], T2) when is_function(Fun, 2) -> - T2; -umerge(Fun, [H1 | T1], T2) when is_function(Fun, 2) -> - lists:reverse(ufmerge2_2(H1, T1, Fun, T2, []), []). +umerge(Fun, L1, L2) when is_function(Fun, 2) -> + umerge_1(Fun, L1, L2). + +umerge_1(Fun, [H1 | T1], [_|_]=T2) -> + lists:reverse(ufmerge2_2(H1, T1, Fun, T2, []), []); +umerge_1(_Fun, [_|_]=L1, []) -> + L1; +umerge_1(_Fun, [], [_|_]=L2) -> + L2; +umerge_1(_Fun, [], []) -> + []. %% reverse(rumerge(F,reverse(A),reverse(B))) is equal to umerge(F,A,B). -spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. -rumerge(Fun, T1, []) when is_function(Fun, 2) -> - T1; -rumerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> - lists:reverse(rufmerge2_1(T1, H2, Fun, T2, []), []). +rumerge(Fun, L1, L2) when is_function(Fun, 2) -> + rumerge_1(Fun, L1, L2). + +rumerge_1(Fun, [_|_]=T1, [H2 | T2]) -> + lists:reverse(rufmerge2_1(T1, H2, Fun, T2, []), []); +rumerge_1(_Fun, [_|_]=L1, []) -> + L1; +rumerge_1(_Fun, [], [_|_]=L2) -> + L2; +rumerge_1(_Fun, [], []) -> + []. %% usort(List) -> L %% sorts the list L, removes duplicates @@ -1135,12 +1400,22 @@ umerge(L) -> Y :: term(), Z :: term(). -umerge3(L1, [], L3) -> - umerge(L1, L3); -umerge3(L1, L2, []) -> - umerge(L1, L2); -umerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(umerge3_1(L1, [H2 | H3], T2, H2, [], T3, H3), []). +umerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(umerge3_1(L1, [H2 | H3], T2, H2, [], T3, H3), []); +umerge3([_|_]=L1, [_|_]=L2, []) -> + umerge(L1, L2); +umerge3([_|_]=L1, [], [_|_]=L3) -> + umerge(L1, L3); +umerge3([_|_]=L1, [], []) -> + L1; +umerge3([], [_|_]=L2, [_|_]=L3) -> + umerge(L2, L3); +umerge3([], [_|_]=L2, []) -> + L2; +umerge3([], [], [_|_]=L3) -> + L3; +umerge3([], [], []) -> + []. %% rumerge3(X, Y, Z) -> L %% merges three reversed sorted lists X, Y and Z without duplicates, @@ -1148,12 +1423,22 @@ umerge3(L1, [H2 | T2], [H3 | T3]) -> -spec rumerge3([X], [Y], [Z]) -> [(X | Y | Z)]. -rumerge3(L1, [], L3) -> - rumerge(L1, L3); -rumerge3(L1, L2, []) -> - rumerge(L1, L2); -rumerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(rumerge3_1(L1, T2, H2, [], T3, H3),[]). +rumerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(rumerge3_1(L1, T2, H2, [], T3, H3),[]); +rumerge3([_|_]=L1, [_|_]=L2, []) -> + rumerge(L1, L2); +rumerge3([_|_]=L1, [], [_|_]=L3) -> + rumerge(L1, L3); +rumerge3([_|_]=L1, [], []) -> + L1; +rumerge3([], [_|_]=L2, [_|_]=L3) -> + rumerge(L2, L3); +rumerge3([], [_|_]=L2, []) -> + L2; +rumerge3([], [], [_|_]=L3) -> + L3; +rumerge3([], [], []) -> + []. %% umerge(X, Y) -> L %% merges two sorted lists X and Y without duplicates, removes duplicates @@ -1165,10 +1450,14 @@ rumerge3(L1, [H2 | T2], [H3 | T3]) -> X :: term(), Y :: term(). -umerge([], T2) -> - T2; -umerge([H1 | T1], T2) -> - lists:reverse(umerge2_2(T1, T2, [], H1), []). +umerge([H1 | T1], [_|_]=T2) -> + lists:reverse(umerge2_2(T1, T2, [], H1), []); +umerge([_|_]=L1, []) -> + L1; +umerge([], [_|_]=L2) -> + L2; +umerge([], []) -> + []. %% rumerge(X, Y) -> L %% merges two reversed sorted lists X and Y without duplicates, @@ -1178,10 +1467,14 @@ umerge([H1 | T1], T2) -> -spec rumerge([X], [Y]) -> [(X | Y)]. -rumerge(T1, []) -> - T1; -rumerge(T1, [H2 | T2]) -> - lists:reverse(rumerge2_1(T1, T2, [], H2), []). +rumerge([_|_]=T1, [H2 | T2]) -> + lists:reverse(rumerge2_1(T1, T2, [], H2), []); +rumerge([_|_]=L1, []) -> + L1; +rumerge([], [_|_]=L2) -> + L2; +rumerge([], []) -> + []. %% all(Predicate, List) %% any(Predicate, List) @@ -1213,24 +1506,46 @@ rumerge(T1, [H2 | T2]) -> List :: [T], T :: term(). -all(Pred, [Hd|Tail]) -> +all(Pred, List) when is_function(Pred, 1) -> + case List of + [Hd | Tail] -> + case Pred(Hd) of + true -> all_1(Pred, Tail); + false -> false + end; + [] -> true + end. + +all_1(Pred, [Hd | Tail]) -> case Pred(Hd) of - true -> all(Pred, Tail); - false -> false + true -> all_1(Pred, Tail); + false -> false end; -all(Pred, []) when is_function(Pred, 1) -> true. +all_1(_Pred, []) -> + true. -spec any(Pred, List) -> boolean() when Pred :: fun((Elem :: T) -> boolean()), List :: [T], T :: term(). -any(Pred, [Hd|Tail]) -> +any(Pred, List) when is_function(Pred, 1) -> + case List of + [Hd | Tail] -> + case Pred(Hd) of + true -> true; + false -> any_1(Pred, Tail) + end; + [] -> false + end. + +any_1(Pred, [Hd | Tail]) -> case Pred(Hd) of - true -> true; - false -> any(Pred, Tail) + true -> true; + false -> any_1(Pred, Tail) end; -any(Pred, []) when is_function(Pred, 1) -> false. +any_1(_Pred, []) -> + false. -spec map(Fun, List1) -> List2 when Fun :: fun((A) -> B), @@ -1239,9 +1554,16 @@ any(Pred, []) when is_function(Pred, 1) -> false. A :: term(), B :: term(). -map(F, [H|T]) -> - [F(H)|map(F, T)]; -map(F, []) when is_function(F, 1) -> []. +map(F, List) when is_function(F, 1) -> + case List of + [Hd | Tail] -> [F(Hd) | map_1(F, Tail)]; + [] -> [] + end. + +map_1(F, [Hd | Tail]) -> + [F(Hd) | map_1(F, Tail)]; +map_1(_F, []) -> + []. -spec flatmap(Fun, List1) -> List2 when Fun :: fun((A) -> [B]), @@ -1250,9 +1572,13 @@ map(F, []) when is_function(F, 1) -> []. A :: term(), B :: term(). -flatmap(F, [Hd|Tail]) -> - F(Hd) ++ flatmap(F, Tail); -flatmap(F, []) when is_function(F, 1) -> []. +flatmap(F, List) when is_function(F, 1) -> + flatmap_1(F, List). + +flatmap_1(F, [Hd | Tail]) -> + F(Hd) ++ flatmap_1(F, Tail); +flatmap_1(_F, []) -> + []. -spec foldl(Fun, Acc0, List) -> Acc1 when Fun :: fun((Elem :: T, AccIn) -> AccOut), @@ -1263,9 +1589,16 @@ flatmap(F, []) when is_function(F, 1) -> []. List :: [T], T :: term(). -foldl(F, Accu, [Hd|Tail]) -> - foldl(F, F(Hd, Accu), Tail); -foldl(F, Accu, []) when is_function(F, 2) -> Accu. +foldl(F, Accu, List) when is_function(F, 2) -> + case List of + [Hd | Tail] -> foldl_1(F, F(Hd, Accu), Tail); + [] -> Accu + end. + +foldl_1(F, Accu, [Hd | Tail]) -> + foldl_1(F, F(Hd, Accu), Tail); +foldl_1(_F, Accu, []) -> + Accu. -spec foldr(Fun, Acc0, List) -> Acc1 when Fun :: fun((Elem :: T, AccIn) -> AccOut), @@ -1276,9 +1609,13 @@ foldl(F, Accu, []) when is_function(F, 2) -> Accu. List :: [T], T :: term(). -foldr(F, Accu, [Hd|Tail]) -> - F(Hd, foldr(F, Accu, Tail)); -foldr(F, Accu, []) when is_function(F, 2) -> Accu. +foldr(F, Accu, List) when is_function(F, 2) -> + foldr_1(F, Accu, List). + +foldr_1(F, Accu, [Hd | Tail]) -> + F(Hd, foldr_1(F, Accu, Tail)); +foldr_1(_F, Accu, []) -> + Accu. -spec filter(Pred, List1) -> List2 when Pred :: fun((Elem :: T) -> boolean()), @@ -1299,15 +1636,15 @@ filter(Pred, List) when is_function(Pred, 1) -> NotSatisfying :: [T], T :: term(). -partition(Pred, L) -> - partition(Pred, L, [], []). +partition(Pred, L) when is_function(Pred, 1) -> + partition_1(Pred, L, [], []). -partition(Pred, [H | T], As, Bs) -> +partition_1(Pred, [H | T], As, Bs) -> case Pred(H) of - true -> partition(Pred, T, [H | As], Bs); - false -> partition(Pred, T, As, [H | Bs]) + true -> partition_1(Pred, T, [H | As], Bs); + false -> partition_1(Pred, T, As, [H | Bs]) end; -partition(Pred, [], As, Bs) when is_function(Pred, 1) -> +partition_1(_Pred, [], As, Bs) -> {reverse(As), reverse(Bs)}. -spec filtermap(Fun, List1) -> List2 when @@ -1317,16 +1654,20 @@ partition(Pred, [], As, Bs) when is_function(Pred, 1) -> Elem :: term(), Value :: term(). -filtermap(F, [Hd|Tail]) -> +filtermap(F, List) when is_function(F, 1) -> + filtermap_1(F, List). + +filtermap_1(F, [Hd|Tail]) -> case F(Hd) of - true -> - [Hd|filtermap(F, Tail)]; - {true,Val} -> - [Val|filtermap(F, Tail)]; - false -> - filtermap(F, Tail) + true -> + [Hd | filtermap_1(F, Tail)]; + {true,Val} -> + [Val | filtermap_1(F, Tail)]; + false -> + filtermap_1(F, Tail) end; -filtermap(F, []) when is_function(F, 1) -> []. +filtermap_1(_F, []) -> + []. -spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)]. @@ -1338,10 +1679,14 @@ zf(F, L) -> List :: [T], T :: term(). -foreach(F, [Hd|Tail]) -> +foreach(F, List) when is_function(F, 1) -> + foreach_1(F, List). + +foreach_1(F, [Hd | Tail]) -> F(Hd), - foreach(F, Tail); -foreach(F, []) when is_function(F, 1) -> ok. + foreach_1(F, Tail); +foreach_1(_F, []) -> + ok. -spec mapfoldl(Fun, Acc0, List1) -> {List2, Acc1} when Fun :: fun((A, AccIn) -> {B, AccOut}), @@ -1354,11 +1699,15 @@ foreach(F, []) when is_function(F, 1) -> ok. A :: term(), B :: term(). -mapfoldl(F, Accu0, [Hd|Tail]) -> - {R,Accu1} = F(Hd, Accu0), - {Rs,Accu2} = mapfoldl(F, Accu1, Tail), - {[R|Rs],Accu2}; -mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}. +mapfoldl(F, Accu, List) when is_function(F, 2) -> + mapfoldl_1(F, Accu, List). + +mapfoldl_1(F, Accu0, [Hd | Tail]) -> + {R, Accu1} = F(Hd, Accu0), + {Rs, Accu2} = mapfoldl_1(F, Accu1, Tail), + {[R | Rs], Accu2}; +mapfoldl_1(_F, Accu, []) -> + {[], Accu}. -spec mapfoldr(Fun, Acc0, List1) -> {List2, Acc1} when Fun :: fun((A, AccIn) -> {B, AccOut}), @@ -1371,11 +1720,15 @@ mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}. A :: term(), B :: term(). -mapfoldr(F, Accu0, [Hd|Tail]) -> - {Rs,Accu1} = mapfoldr(F, Accu0, Tail), - {R,Accu2} = F(Hd, Accu1), - {[R|Rs],Accu2}; -mapfoldr(F, Accu, []) when is_function(F, 2) -> {[],Accu}. +mapfoldr(F, Accu, List) when is_function(F, 2) -> + mapfoldr_1(F, Accu, List). + +mapfoldr_1(F, Accu0, [Hd|Tail]) -> + {Rs, Accu1} = mapfoldr_1(F, Accu0, Tail), + {R, Accu2} = F(Hd, Accu1), + {[R | Rs], Accu2}; +mapfoldr_1(_F, Accu, []) -> + {[], Accu}. -spec takewhile(Pred, List1) -> List2 when Pred :: fun((Elem :: T) -> boolean()), @@ -1383,12 +1736,16 @@ mapfoldr(F, Accu, []) when is_function(F, 2) -> {[],Accu}. List2 :: [T], T :: term(). -takewhile(Pred, [Hd|Tail]) -> +takewhile(Pred, List) when is_function(Pred, 1) -> + takewhile_1(Pred, List). + +takewhile_1(Pred, [Hd | Tail]) -> case Pred(Hd) of - true -> [Hd|takewhile(Pred, Tail)]; - false -> [] + true -> [Hd | takewhile_1(Pred, Tail)]; + false -> [] end; -takewhile(Pred, []) when is_function(Pred, 1) -> []. +takewhile_1(_Pred, []) -> + []. -spec dropwhile(Pred, List1) -> List2 when Pred :: fun((Elem :: T) -> boolean()), @@ -1396,24 +1753,31 @@ takewhile(Pred, []) when is_function(Pred, 1) -> []. List2 :: [T], T :: term(). -dropwhile(Pred, [Hd|Tail]=Rest) -> +dropwhile(Pred, List) when is_function(Pred, 1) -> + dropwhile_1(Pred, List). + +dropwhile_1(Pred, [Hd | Tail]=Rest) -> case Pred(Hd) of - true -> dropwhile(Pred, Tail); - false -> Rest + true -> dropwhile_1(Pred, Tail); + false -> Rest end; -dropwhile(Pred, []) when is_function(Pred, 1) -> []. +dropwhile_1(_Pred, []) -> + []. -spec search(Pred, List) -> {value, Value} | false when Pred :: fun((T) -> boolean()), List :: [T], Value :: T. -search(Pred, [Hd|Tail]) -> +search(Pred, List) when is_function(Pred, 1) -> + search_1(Pred, List). + +search_1(Pred, [Hd | Tail]) -> case Pred(Hd) of true -> {value, Hd}; - false -> search(Pred, Tail) + false -> search_1(Pred, Tail) end; -search(Pred, []) when is_function(Pred, 1) -> +search_1(_Pred, []) -> false. -spec splitwith(Pred, List) -> {List1, List2} when @@ -1424,14 +1788,14 @@ search(Pred, []) when is_function(Pred, 1) -> T :: term(). splitwith(Pred, List) when is_function(Pred, 1) -> - splitwith(Pred, List, []). + splitwith_1(Pred, List, []). -splitwith(Pred, [Hd|Tail], Taken) -> +splitwith_1(Pred, [Hd|Tail], Taken) -> case Pred(Hd) of - true -> splitwith(Pred, Tail, [Hd|Taken]); + true -> splitwith_1(Pred, Tail, [Hd|Taken]); false -> {reverse(Taken), [Hd|Tail]} end; -splitwith(Pred, [], Taken) when is_function(Pred, 1) -> +splitwith_1(_Pred, [], Taken) -> {reverse(Taken),[]}. -spec split(N, List1) -> {List2, List3} when @@ -1543,24 +1907,24 @@ split_2_1(X, Y, [], R, Rs, S) -> %% merge/1 -mergel([[] | L], Acc) -> - mergel(L, Acc); -mergel([T1, [H2 | T2], [H3 | T3] | L], Acc) -> - mergel(L, [merge3_1(T1, [], H2, T2, H3, T3) | Acc]); -mergel([T1, [H2 | T2]], Acc) -> - rmergel([merge2_1(T1, H2, T2, []) | Acc], []); -mergel([L], []) -> - L; -mergel([L], Acc) -> - rmergel([lists:reverse(L, []) | Acc], []); mergel([], []) -> []; +mergel([[_|_]=L], []) -> + L; mergel([], Acc) -> rmergel(Acc, []); -mergel([A, [] | L], Acc) -> +mergel([[] | L], Acc) -> + mergel(L, Acc); +mergel([[_|_]=L], Acc) -> + rmergel([lists:reverse(L, []) | Acc], []); +mergel([[_|_]=A, [] | L], Acc) -> mergel([A | L], Acc); -mergel([A, B, [] | L], Acc) -> - mergel([A, B | L], Acc). +mergel([[_|_]=A, [_|_]=B, [] | L], Acc) -> + mergel([A, B | L], Acc); +mergel([[_|_]=T1, [H2 | T2], [H3 | T3] | L], Acc) -> + mergel(L, [merge3_1(T1, [], H2, T2, H3, T3) | Acc]); +mergel([[_|_]=T1, [H2 | T2]], Acc) -> + rmergel([merge2_1(T1, H2, T2, []) | Acc], []). rmergel([[H3 | T3], [H2 | T2], T1 | L], Acc) -> rmergel(L, [rmerge3_1(T1, [], H2, T2, H3, T3) | Acc]); @@ -1776,28 +2140,28 @@ usplit_2_1(X, Y, [], R, Rs, S) -> umergel(L) -> umergel(L, [], asc). +umergel([], [], _O) -> + []; +umergel([[_|_]=L], [], _O) -> + L; +umergel([], Acc, O) -> + rumergel(Acc, [], O); +umergel([[_|_]=L], Acc, O) -> + rumergel([lists:reverse(L, []) | Acc], [], O); umergel([[] | L], Acc, O) -> umergel(L, Acc, O); -umergel([T1, [H2 | T2], [H3 | T3] | L], Acc, asc) -> - umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], asc); -umergel([[H3 | T3], [H2 | T2], T1 | L], Acc, desc) -> - umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], desc); -umergel([A, [] | L], Acc, O) -> +umergel([[_|_]=A, [] | L], Acc, O) -> umergel([A | L], Acc, O); -umergel([A, B, [] | L], Acc, O) -> +umergel([[_|_]=A, [_|_]=B, [] | L], Acc, O) -> umergel([A, B | L], Acc, O); -umergel([[H1 | T1], T2 | L], Acc, asc) -> +umergel([[_|_]=T1, [H2 | T2], [H3 | T3] | L], Acc, asc) -> + umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], asc); +umergel([[H3 | T3], [H2 | T2], [_|_]=T1 | L], Acc, desc) -> + umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], desc); +umergel([[H1 | T1], [_|_]=T2 | L], Acc, asc) -> umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], asc); -umergel([T2, [H1 | T1] | L], Acc, desc) -> - umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], desc); -umergel([L], [], _O) -> - L; -umergel([L], Acc, O) -> - rumergel([lists:reverse(L, []) | Acc], [], O); -umergel([], [], _O) -> - []; -umergel([], Acc, O) -> - rumergel(Acc, [], O). +umergel([[_|_]=T2, [H1 | T1] | L], Acc, desc) -> + umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], desc). rumergel([[H3 | T3], [H2 | T2], T1 | L], Acc, asc) -> rumergel(L, [rumerge3_1(T1, T2, H2, [], T3, H3) | Acc], asc); @@ -2855,3 +3219,44 @@ rufmerge2_2(H1, T1, Fun, [], M, H2M) -> lists:reverse(T1, [H1, H2M | M]) end. +%% uniq/1: return a new list with the unique elements of the given list + +-spec uniq(List1) -> List2 when + List1 :: [T], + List2 :: [T], + T :: term(). + +uniq(L) -> + uniq_1(L, #{}). + +uniq_1([X | Xs], M) -> + case is_map_key(X, M) of + true -> + uniq_1(Xs, M); + false -> + [X | uniq_1(Xs, M#{X => true})] + end; +uniq_1([], _) -> + []. + +%% uniq/2: return a new list with the unique elements of the given list using a function key + +-spec uniq(Fun, List1) -> List2 when + Fun :: fun((T) -> any()), + List1 :: [T], + List2 :: [T], + T :: term(). + +uniq(F, L) when is_function(F, 1) -> + uniq_2(L, F, #{}). + +uniq_2([X | Xs], F, M) -> + Key = F(X), + case is_map_key(Key, M) of + true -> + uniq_2(Xs, F, M); + false -> + [X | uniq_2(Xs, F, M#{Key => true})] + end; +uniq_2([], _, _) -> + []. diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index e6192eb22b4a..a7689f10b377 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2021. All Rights Reserved. +%% Copyright Ericsson AB 2013-2023. 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. @@ -24,9 +24,14 @@ map/2, size/1, new/0, update_with/3, update_with/4, without/2, with/2, - iterator/1, next/1, + iterator/1, iterator/2, + next/1, intersect/2, intersect_with/3, - merge_with/3]). + merge_with/3, + groups_from_list/2, groups_from_list/3]). + +%% Internal +-export([is_iterator_valid/1]). %% BIFs -export([get/2, find/2, from_list/1, from_keys/2, @@ -35,13 +40,18 @@ to_list/1, update/3, values/1]). -opaque iterator(Key, Value) :: {Key, Value, iterator(Key, Value)} | none - | nonempty_improper_list(integer(), #{Key => Value}). + | nonempty_improper_list(integer(), #{Key => Value}) + | nonempty_improper_list(list(Key), #{Key => Value}). -type iterator() :: iterator(term(), term()). --export_type([iterator/2, iterator/0]). +-type iterator_order(Key) :: undefined | ordered | reversed + | fun((A :: Key, B :: Key) -> boolean()). +-type iterator_order() :: iterator_order(term()). + +-export_type([iterator/2, iterator/0, iterator_order/1, iterator_order/0]). --dialyzer({no_improper_lists, iterator/1}). +-dialyzer({no_improper_lists, [iterator/1, iterator/2]}). %% We must inline these functions so that the stacktrace points to %% the correct function. @@ -219,13 +229,22 @@ remove(_,_) -> erlang:nif_error(undef). take(_,_) -> erlang:nif_error(undef). --spec to_list(Map) -> [{Key,Value}] when - Map :: #{Key => Value}. +-spec to_list(MapOrIterator) -> [{Key, Value}] when + MapOrIterator :: #{Key => Value} | iterator(Key, Value). to_list(Map) when is_map(Map) -> to_list_internal(erts_internal:map_next(0, Map, [])); -to_list(Map) -> - error_with_info({badmap,Map}, [Map]). +to_list(Iter) -> + try to_list_from_iterator(next(Iter)) + catch + error:_ -> + error_with_info({badmap, Iter}, [Iter]) + end. + +to_list_from_iterator({Key, Value, NextIter}) -> + [{Key, Value} | to_list_from_iterator(next(NextIter))]; +to_list_from_iterator(none) -> + []. to_list_internal([Iter, Map | Acc]) when is_integer(Iter) -> to_list_internal(erts_internal:map_next(Iter, Map, Acc)); @@ -297,31 +316,28 @@ get(Key,Map,Default) -> MapOrIter :: #{Key => Value} | iterator(Key, Value), Map :: #{Key => Value}. -filter(Pred, MapOrIter) when is_function(Pred, 2) -> - Iter = if - is_map(MapOrIter) -> - iterator(MapOrIter); - true -> - MapOrIter - end, - try next(Iter) of - Next -> - maps:from_list(filter_1(Pred, Next)) +filter(Pred, Map) when is_map(Map), is_function(Pred, 2) -> + maps:from_list(filter_1(Pred, next(iterator(Map)), undefined)); +filter(Pred, Iter) when is_function(Pred, 2) -> + ErrorTag = make_ref(), + try filter_1(Pred, try_next(Iter, ErrorTag), ErrorTag) of + Result -> + maps:from_list(Result) catch - error:_ -> - error_with_info({badmap,MapOrIter}, [Pred, MapOrIter]) + error:ErrorTag -> + error_with_info({badmap, Iter}, [Pred, Iter]) end; filter(Pred, Map) -> badarg_with_info([Pred, Map]). -filter_1(Pred, {K, V, Iter}) -> +filter_1(Pred, {K, V, Iter}, ErrorTag) -> case Pred(K, V) of true -> - [{K,V} | filter_1(Pred, next(Iter))]; + [{K,V} | filter_1(Pred, try_next(Iter, ErrorTag), ErrorTag)]; false -> - filter_1(Pred, next(Iter)) + filter_1(Pred, try_next(Iter, ErrorTag), ErrorTag) end; -filter_1(_Pred, none) -> +filter_1(_Pred, none, _ErrorTag) -> []. -spec filtermap(Fun, MapOrIter) -> Map when @@ -329,57 +345,52 @@ filter_1(_Pred, none) -> MapOrIter :: #{Key => Value1} | iterator(Key, Value1), Map :: #{Key => Value1 | Value2}. -filtermap(Fun, MapOrIter) when is_function(Fun, 2) -> - Iter = if - is_map(MapOrIter) -> - iterator(MapOrIter); - true -> - MapOrIter - end, - try next(Iter) of - Next -> - maps:from_list(filtermap_1(Fun, Next)) +filtermap(Fun, Map) when is_map(Map), is_function(Fun, 2) -> + maps:from_list(filtermap_1(Fun, next(iterator(Map)), undefined)); +filtermap(Fun, Iter) when is_function(Fun, 2) -> + ErrorTag = make_ref(), + try filtermap_1(Fun, try_next(Iter, ErrorTag), ErrorTag) of + Result -> + maps:from_list(Result) catch - error:_ -> - error_with_info({badmap,MapOrIter}, [Fun, MapOrIter]) + error:ErrorTag -> + error_with_info({badmap, Iter}, [Fun, Iter]) end; filtermap(Fun, Map) -> badarg_with_info([Fun, Map]). -filtermap_1(Pred, {K, V, Iter}) -> - case Pred(K, V) of +filtermap_1(Fun, {K, V, Iter}, ErrorTag) -> + case Fun(K, V) of true -> - [{K, V} | filtermap_1(Pred, next(Iter))]; + [{K, V} | filtermap_1(Fun, try_next(Iter, ErrorTag), ErrorTag)]; {true, NewV} -> - [{K, NewV} | filtermap_1(Pred, next(Iter))]; + [{K, NewV} | filtermap_1(Fun, try_next(Iter, ErrorTag), ErrorTag)]; false -> - filtermap_1(Pred, next(Iter)) + filtermap_1(Fun, try_next(Iter, ErrorTag), ErrorTag) end; -filtermap_1(_Pred, none) -> +filtermap_1(_Fun, none, _ErrorTag) -> []. -spec foreach(Fun,MapOrIter) -> ok when Fun :: fun((Key, Value) -> term()), MapOrIter :: #{Key => Value} | iterator(Key, Value). -foreach(Fun, MapOrIter) when is_function(Fun, 2) -> - Iter = if is_map(MapOrIter) -> iterator(MapOrIter); - true -> MapOrIter - end, - try next(Iter) of - Next -> - foreach_1(Fun, Next) +foreach(Fun, Map) when is_map(Map), is_function(Fun, 2) -> + foreach_1(Fun, next(iterator(Map)), undefined); +foreach(Fun, Iter) when is_function(Fun, 2) -> + ErrorTag = make_ref(), + try foreach_1(Fun, try_next(Iter, ErrorTag), ErrorTag) catch - error:_ -> - error_with_info({badmap, MapOrIter}, [Fun, MapOrIter]) + error:ErrorTag -> + error_with_info({badmap, Iter}, [Fun, Iter]) end; -foreach(Pred, Map) -> - badarg_with_info([Pred, Map]). +foreach(Fun, Map) -> + badarg_with_info([Fun, Map]). -foreach_1(Fun, {K, V, Iter}) -> +foreach_1(Fun, {K, V, Iter}, ErrorTag) -> Fun(K,V), - foreach_1(Fun, next(Iter)); -foreach_1(_Fun, none) -> + foreach_1(Fun, try_next(Iter, ErrorTag), ErrorTag); +foreach_1(_Fun, none, _ErrorTag) -> ok. -spec fold(Fun,Init,MapOrIter) -> Acc when @@ -389,26 +400,21 @@ foreach_1(_Fun, none) -> AccIn :: Init | AccOut, MapOrIter :: #{Key => Value} | iterator(Key, Value). -fold(Fun, Init, MapOrIter) when is_function(Fun, 3) -> - Iter = if - is_map(MapOrIter) -> - iterator(MapOrIter); - true -> - MapOrIter - end, - try next(Iter) of - Next -> - fold_1(Fun, Init, Next) +fold(Fun, Init, Map) when is_map(Map), is_function(Fun, 3) -> + fold_1(Fun, Init, next(iterator(Map)), undefined); +fold(Fun, Init, Iter) when is_function(Fun, 3) -> + ErrorTag = make_ref(), + try fold_1(Fun, Init, try_next(Iter, ErrorTag), ErrorTag) catch - error:_ -> - error_with_info({badmap,MapOrIter}, [Fun, Init, MapOrIter]) + error:ErrorTag -> + error_with_info({badmap, Iter}, [Fun, Init, Iter]) end; fold(Fun, Init, Map) -> badarg_with_info([Fun, Init, Map]). -fold_1(Fun, Acc, {K, V, Iter}) -> - fold_1(Fun, Fun(K,V,Acc), next(Iter)); -fold_1(_Fun, Acc, none) -> +fold_1(Fun, Acc, {K, V, Iter}, ErrorTag) -> + fold_1(Fun, Fun(K,V,Acc), try_next(Iter, ErrorTag), ErrorTag); +fold_1(_Fun, Acc, none, _ErrorTag) -> Acc. -spec map(Fun,MapOrIter) -> Map when @@ -416,27 +422,24 @@ fold_1(_Fun, Acc, none) -> MapOrIter :: #{Key => Value1} | iterator(Key, Value1), Map :: #{Key => Value2}. -map(Fun, MapOrIter) when is_function(Fun, 2) -> - Iter = if - is_map(MapOrIter) -> - iterator(MapOrIter); - true -> - MapOrIter - end, - try next(Iter) of - Next -> - maps:from_list(map_1(Fun, Next)) +map(Fun, Map) when is_map(Map), is_function(Fun, 2) -> + maps:from_list(map_1(Fun, next(iterator(Map)), undefined)); +map(Fun, Iter) when is_function(Fun, 2) -> + ErrorTag = make_ref(), + try map_1(Fun, try_next(Iter, ErrorTag), ErrorTag) of + Result -> + maps:from_list(Result) catch - error:_ -> - error_with_info({badmap,MapOrIter}, [Fun, MapOrIter]) + error:ErrorTag -> + error_with_info({badmap, Iter}, [Fun, Iter]) end; map(Fun, Map) -> badarg_with_info([Fun, Map]). -map_1(Fun, {K, V, Iter}) -> - [{K, Fun(K, V)} | map_1(Fun, next(Iter))]; -map_1(_Fun, none) -> +map_1(Fun, {K, V, Iter}, ErrorTag) -> + [{K, Fun(K, V)} | map_1(Fun, try_next(Iter, ErrorTag), ErrorTag)]; +map_1(_Fun, none, _ErrorTag) -> []. -spec size(Map) -> non_neg_integer() when @@ -454,16 +457,43 @@ size(Map) -> Map :: #{Key => Value}, Iterator :: iterator(Key, Value). -iterator(M) when is_map(M) -> [0 | M]; +iterator(M) when is_map(M) -> iterator(M, undefined); iterator(M) -> error_with_info({badmap, M}, [M]). +-spec iterator(Map, Order) -> Iterator when + Map :: #{Key => Value}, + Order :: iterator_order(Key), + Iterator :: iterator(Key, Value). + +iterator(M, undefined) when is_map(M) -> + [0 | M]; +iterator(M, ordered) when is_map(M) -> + CmpFun = fun(A, B) -> erts_internal:cmp_term(A, B) =< 0 end, + Keys = lists:sort(CmpFun, maps:keys(M)), + [Keys | M]; +iterator(M, reversed) when is_map(M) -> + CmpFun = fun(A, B) -> erts_internal:cmp_term(B, A) =< 0 end, + Keys = lists:sort(CmpFun, maps:keys(M)), + [Keys | M]; +iterator(M, CmpFun) when is_map(M), is_function(CmpFun, 2) -> + Keys = lists:sort(CmpFun, maps:keys(M)), + [Keys | M]; +iterator(M, Order) -> + badarg_with_info([M, Order]). + -spec next(Iterator) -> {Key, Value, NextIterator} | 'none' when Iterator :: iterator(Key, Value), NextIterator :: iterator(Key, Value). next({K, V, I}) -> {K, V, I}; -next([Path | Map]) when is_integer(Path), is_map(Map) -> - erts_internal:map_next(Path, Map, iterator); +next([Path | Map] = Iterator) + when (is_integer(Path) orelse is_list(Path)), is_map(Map) -> + try erts_internal:map_next(Path, Map, iterator) of + Result -> Result + catch + error:badarg -> + badarg_with_info([Iterator]) + end; next(none) -> none; next(Iter) -> @@ -497,6 +527,70 @@ with_1([K|Ks], Map) -> end; with_1([], _Map) -> []. +%% groups_from_list/2 & groups_from_list/3 + +-spec groups_from_list(KeyFun, List) -> GroupsMap when + KeyFun :: fun((Elem) -> Key), + GroupsMap :: #{Key => Group}, + Key :: term(), + List :: [Elem], + Group :: [Elem], + Elem :: term(). + +groups_from_list(Fun, List0) when is_function(Fun, 1) -> + try lists:reverse(List0) of + List -> + groups_from_list_1(Fun, List, #{}) + catch + error:_ -> + badarg_with_info([Fun, List0]) + end; +groups_from_list(Fun, List) -> + badarg_with_info([Fun, List]). + +groups_from_list_1(Fun, [H | Tail], Acc) -> + K = Fun(H), + NewAcc = case Acc of + #{K := Vs} -> Acc#{K := [H | Vs]}; + #{} -> Acc#{K => [H]} + end, + groups_from_list_1(Fun, Tail, NewAcc); +groups_from_list_1(_Fun, [], Acc) -> + Acc. + +-spec groups_from_list(KeyFun, ValueFun, List) -> GroupsMap when + KeyFun :: fun((Elem) -> Key), + ValueFun :: fun((Elem) -> Value), + GroupsMap :: #{Key := Group}, + Key :: term(), + Value :: term(), + List :: [Elem], + Group :: [Value], + Elem :: term(). + +groups_from_list(Fun, ValueFun, List0) when is_function(Fun, 1), + is_function(ValueFun, 1) -> + try lists:reverse(List0) of + List -> + groups_from_list_2(Fun, ValueFun, List, #{}) + catch + error:_ -> + badarg_with_info([Fun, ValueFun, List0]) + end; +groups_from_list(Fun, ValueFun, List) -> + badarg_with_info([Fun, ValueFun, List]). + +groups_from_list_2(Fun, ValueFun, [H | Tail], Acc) -> + K = Fun(H), + V = ValueFun(H), + NewAcc = case Acc of + #{K := Vs} -> Acc#{K := [V | Vs]}; + #{} -> Acc#{K => [V]} + end, + groups_from_list_2(Fun, ValueFun, Tail, NewAcc); +groups_from_list_2(_Fun, _ValueFun, [], Acc) -> + Acc. + error_type(M) when is_map(M) -> badarg; error_type(V) -> {badmap, V}. @@ -515,3 +609,34 @@ badarg_with_info(Args) -> error_with_info(Reason, Args) -> erlang:error(Reason, Args, [{error_info, #{module => erl_stdlib_errors}}]). + +-spec is_iterator_valid(MaybeIter) -> boolean() when + MaybeIter :: iterator() | term(). + +is_iterator_valid(Iter) -> + try is_iterator_valid_1(Iter) + catch + error:badarg -> + false + end. + +is_iterator_valid_1(none) -> + true; +is_iterator_valid_1({_, _, Next}) -> + is_iterator_valid_1(next(Next)); +is_iterator_valid_1(Iter) -> + _ = next(Iter), + true. + +try_next({_, _, _} = KVI, _ErrorTag) -> + KVI; +try_next(none, _ErrorTag) -> + none; +try_next(Iter, undefined) -> + next(Iter); +try_next(Iter, ErrorTag) -> + try next(Iter) + catch + error:badarg -> + error(ErrorTag) + end. diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl index 3a3b384d8f32..cf41cd2f1d7b 100644 --- a/lib/stdlib/src/math.erl +++ b/lib/stdlib/src/math.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -19,7 +19,7 @@ %% -module(math). --export([pi/0]). +-export([pi/0,tau/0]). %%% BIFs @@ -154,5 +154,7 @@ tanh(_) -> %%% End of BIFs -spec pi() -> float(). - pi() -> 3.1415926535897932. + +-spec tau() -> float(). +tau() -> 6.2831853071795864. diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index 890267b439cd..01496adb5508 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2021. All Rights Reserved. +%% Copyright Ericsson AB 2002-2023. 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. @@ -756,7 +756,12 @@ tg({bin_element,Anno,X,Y,Z},B) -> tg({bin,Anno,List},B) -> {bin,Anno,[tg(X,B) || X <- List]}; - + +tg({map_field_assoc, Anno, Field, Value}, B) -> + {map_field_assoc, Anno, tg(Field, B), tg(Value, B)}; +tg({map, Anno, List}, B) -> + {map, Anno, [tg(X, B) || X <- List]}; + tg(T,B) when is_tuple(T), tuple_size(T) >= 2 -> Element = element(1,T), Anno = element(2,T), @@ -858,6 +863,9 @@ th({var,Anno,Name},B,OB) -> Trans -> {{atom,Anno,Trans},B} end; +th({map_field_exact,Anno,Field,Value},B,OB) -> + {[NField, NValue], NB} = th([Field, Value], B, OB), + {{map_field_assoc,Anno,NField,NValue}, NB}; th([H|T],B,OB) -> {NH,NB} = th(H,B,OB), {NT,NNB} = th(T,NB,OB), @@ -969,13 +977,18 @@ real_guard_function(abs,1) -> true; real_guard_function(element,2) -> true; real_guard_function(hd,1) -> true; real_guard_function(length,1) -> true; +real_guard_function(max,2) -> true; +real_guard_function(min,2) -> true; real_guard_function(node,0) -> true; real_guard_function(node,1) -> true; real_guard_function(round,1) -> true; real_guard_function(size,1) -> true; real_guard_function(bit_size,1) -> true; +real_guard_function(byte_size,1) -> true; real_guard_function(map_size,1) -> true; real_guard_function(map_get,2) -> true; +real_guard_function(binary_part,2) -> true; +real_guard_function(binary_part,3) -> true; real_guard_function(tl,1) -> true; real_guard_function(trunc,1) -> true; real_guard_function(self,0) -> true; @@ -1004,6 +1017,9 @@ action_function(set_tcw,1) -> true; action_function(silent,1) -> true; action_function(trace,2) -> true; action_function(trace,3) -> true; +action_function(caller_line,0) -> true; +action_function(current_stacktrace,0) -> true; +action_function(current_stacktrace,1) -> true; action_function(_,_) -> false. bool_operator('and',2) -> @@ -1123,7 +1139,7 @@ normalise({bin,_,Fs}) -> eval_bits:expr_grp(Fs, [], fun(E, _) -> {value, normalise(E), []} - end, [], true), + end), B; normalise({cons,_,Head,Tail}) -> [normalise(Head)|normalise(Tail)]; @@ -1131,12 +1147,11 @@ normalise({op,_,'++',A,B}) -> normalise(A) ++ normalise(B); normalise({tuple,_,Args}) -> list_to_tuple(normalise_list(Args)); -normalise({map,_,Pairs0}) -> - Pairs1 = lists:map(fun ({map_field_exact,_,K,V}) -> - {normalise(K),normalise(V)} - end, - Pairs0), - maps:from_list(Pairs1); +normalise({map,_,Pairs}) -> + maps:from_list(lists:map(fun + %% only allow '=>' + ({map_field_assoc,_,K,V}) -> {normalise(K),normalise(V)} + end, Pairs)); %% Special case for unary +/-. normalise({op,_,'+',{char,_,I}}) -> I; normalise({op,_,'+',{integer,_,I}}) -> I; diff --git a/lib/stdlib/src/orddict.erl b/lib/stdlib/src/orddict.erl index 9a2772949ba6..e78b0187f2b3 100644 --- a/lib/stdlib/src/orddict.erl +++ b/lib/stdlib/src/orddict.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -36,7 +36,7 @@ %%--------------------------------------------------------------------------- --spec new() -> orddict(). +-spec new() -> orddict(none(), none()). new() -> []. diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 86196d47d1cb..5bc0704b68fd 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -31,50 +31,28 @@ obsolete(auth, is_auth, 1) -> {deprecated, "use net_adm:ping/1 instead"}; obsolete(calendar, local_time_to_universal_time, 1) -> {deprecated, "use calendar:local_time_to_universal_time_dst/1 instead"}; -obsolete(code, is_module_native, 1) -> - {deprecated, "HiPE has been removed", "OTP 26"}; -obsolete(code, rehash, 0) -> - {deprecated, "the code path cache feature has been removed", "OTP 26"}; +obsolete(crypto, crypto_dyn_iv_init, 3) -> + {deprecated, "see the documentation for details", "OTP 27"}; +obsolete(crypto, crypto_dyn_iv_update, 3) -> + {deprecated, "see the documentation for details", "OTP 27"}; obsolete(crypto, rand_uniform, 2) -> {deprecated, "use rand:uniform/1 instead"}; -obsolete(disk_log, accessible_logs, 0) -> - {deprecated, "use disk_log:all/0 instead", "OTP 26"}; -obsolete(disk_log, lclose, 1) -> - {deprecated, "use disk_log:close/1 instead", "OTP 26"}; -obsolete(disk_log, lclose, 2) -> - {deprecated, "use disk_log:close/1 instead", "OTP 26"}; +obsolete(dbg, stop_clear, 0) -> + {deprecated, "use dbg:stop/0 instead", "OTP 27"}; +obsolete(disk_log, inc_wrap_file, 1) -> + {deprecated, "use disk_log:next_file/1 instead", "OTP 28"}; obsolete(erlang, now, 0) -> {deprecated, "see the \"Time and Time Correction in Erlang\" chapter of the ERTS User's Guide for more information"}; obsolete(erlang, phash, 2) -> {deprecated, "use erlang:phash2/2 instead"}; -obsolete(filename, safe_relative_path, 1) -> - {deprecated, "use filelib:safe_relative_path/2 instead", "OTP 25"}; -obsolete(ftp, start_service, 1) -> - {deprecated, "use ftp:open/2 instead", "OTP 26"}; -obsolete(ftp, stop_service, 1) -> - {deprecated, "use ftp:close/1 instead", "OTP 26"}; +obsolete(file, pid2name, 1) -> + {deprecated, "this functionality is no longer supported", "OTP 27"}; obsolete(http_uri, decode, 1) -> - {deprecated, "use uri_string functions instead", "OTP 25"}; + {deprecated, "use uri_string:unquote function instead", "OTP 27"}; obsolete(http_uri, encode, 1) -> - {deprecated, "use uri_string functions instead", "OTP 25"}; -obsolete(http_uri, parse, 1) -> - {deprecated, "use uri_string functions instead", "OTP 25"}; -obsolete(http_uri, parse, 2) -> - {deprecated, "use uri_string functions instead", "OTP 25"}; -obsolete(http_uri, scheme_defaults, 0) -> - {deprecated, "use uri_string functions instead", "OTP 25"}; + {deprecated, "use uri_string:quote function instead", "OTP 27"}; obsolete(httpd, parse_query, 1) -> {deprecated, "use uri_string:dissect_query/1 instead"}; -obsolete(httpd_util, flatlength, 1) -> - {deprecated, "use erlang:iolist_size/1 instead", "OTP 26"}; -obsolete(httpd_util, hexlist_to_integer, 1) -> - {deprecated, "use erlang:list_to_integer/2 with base 16 instead", "OTP 26"}; -obsolete(httpd_util, integer_to_hexlist, 1) -> - {deprecated, "use erlang:integer_to_list/2 with base 16 instead", "OTP 26"}; -obsolete(httpd_util, strip, 1) -> - {deprecated, "use string:trim/1 instead", "OTP 26"}; -obsolete(httpd_util, suffix, 1) -> - {deprecated, "use filename:extension/1 and string:trim/2 instead", "OTP 26"}; obsolete(net, broadcast, 3) -> {deprecated, "use rpc:eval_everywhere/3 instead"}; obsolete(net, call, 4) -> @@ -83,84 +61,10 @@ obsolete(net, cast, 4) -> {deprecated, "use rpc:cast/4 instead"}; obsolete(net, ping, 1) -> {deprecated, "use net_adm:ping/1 instead"}; -obsolete(net, relay, 1) -> - {deprecated, "use slave:relay/1 instead"}; obsolete(net, sleep, 1) -> {deprecated, "use 'receive after T -> ok end' instead"}; -obsolete(public_key, ssh_decode, 2) -> - {deprecated, "use ssh_file:decode/2 instead", "OTP 26"}; -obsolete(public_key, ssh_encode, 2) -> - {deprecated, "use ssh_file:encode/2 instead", "OTP 26"}; -obsolete(public_key, ssh_hostkey_fingerprint, 1) -> - {deprecated, "use ssh:hostkey_fingerprint/1 instead", "OTP 26"}; -obsolete(public_key, ssh_hostkey_fingerprint, 2) -> - {deprecated, "use ssh:hostkey_fingerprint/2 instead", "OTP 26"}; obsolete(queue, lait, 1) -> {deprecated, "use queue:liat/1 instead"}; -obsolete(snmpm, async_get, 3) -> - {deprecated, "use snmpm:async_get2/3 instead.", "OTP 25"}; -obsolete(snmpm, async_get, 4) -> - {deprecated, "use snmpm:async_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_get, 5) -> - {deprecated, "use snmpm:async_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_get, 6) -> - {deprecated, "use snmpm:async_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_get_bulk, 5) -> - {deprecated, "use snmpm:async_get_bulk2/5 instead.", "OTP 25"}; -obsolete(snmpm, async_get_bulk, 6) -> - {deprecated, "use snmpm:async_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, async_get_bulk, 7) -> - {deprecated, "use snmpm:async_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, async_get_bulk, 8) -> - {deprecated, "use snmpm:async_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, async_get_next, 3) -> - {deprecated, "use snmpm:async_get_next2/3 instead.", "OTP 25"}; -obsolete(snmpm, async_get_next, 4) -> - {deprecated, "use snmpm:async_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_get_next, 5) -> - {deprecated, "use snmpm:async_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_get_next, 6) -> - {deprecated, "use snmpm:async_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_set, 3) -> - {deprecated, "use snmpm:async_set2/3 instead.", "OTP 25"}; -obsolete(snmpm, async_set, 4) -> - {deprecated, "use snmpm:async_set2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_set, 5) -> - {deprecated, "use snmpm:async_set2/4 instead.", "OTP 25"}; -obsolete(snmpm, async_set, 6) -> - {deprecated, "use snmpm:async_set2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get, 3) -> - {deprecated, "use snmpm:sync_get2/3 instead.", "OTP 25"}; -obsolete(snmpm, sync_get, 4) -> - {deprecated, "use snmpm:sync_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get, 5) -> - {deprecated, "use snmpm:sync_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get, 6) -> - {deprecated, "use snmpm:sync_get2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_bulk, 5) -> - {deprecated, "use snmpm:sync_get_bulk2/5 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_bulk, 6) -> - {deprecated, "use snmpm:sync_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_bulk, 7) -> - {deprecated, "use snmpm:sync_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_bulk, 8) -> - {deprecated, "use snmpm:sync_get_bulk2/6 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_next, 3) -> - {deprecated, "use snmpm:sync_get_next2/3 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_next, 4) -> - {deprecated, "use snmpm:sync_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_next, 5) -> - {deprecated, "use snmpm:sync_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_get_next, 6) -> - {deprecated, "use snmpm:sync_get_next2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_set, 3) -> - {deprecated, "use snmpm:sync_set2/3 instead.", "OTP 25"}; -obsolete(snmpm, sync_set, 4) -> - {deprecated, "use snmpm:sync_set2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_set, 5) -> - {deprecated, "use snmpm:sync_set2/4 instead.", "OTP 25"}; -obsolete(snmpm, sync_set, 6) -> - {deprecated, "use snmpm:sync_set2/4 instead.", "OTP 25"}; obsolete(sys, get_debug, 3) -> {deprecated, "incorrectly documented and only for internal use. Can often be replaced with sys:get_log/1"}; obsolete(wxCalendarCtrl, enableYearChange, 1) -> @@ -189,6 +93,10 @@ obsolete(zlib, inflateChunk, 2) -> {deprecated, "use safeInflate/2 instead", "OTP 27"}; obsolete(zlib, setBufSize, 2) -> {deprecated, "this function will be removed in a future release", "OTP 27"}; +obsolete(code, is_module_native, 1) -> + {removed, "HiPE has been removed"}; +obsolete(code, rehash, 0) -> + {removed, "the code path cache feature has been removed"}; obsolete(core_lib, get_anno, 1) -> {removed, "use cerl:get_ann/1 instead"}; obsolete(core_lib, is_literal, 1) -> @@ -229,6 +137,12 @@ obsolete(crypto, stream_decrypt, 2) -> {removed, "use crypto:crypto_update/2 instead"}; obsolete(crypto, stream_encrypt, 2) -> {removed, "use crypto:crypto_update/2 instead"}; +obsolete(disk_log, accessible_logs, 0) -> + {removed, "use disk_log:all/0 instead"}; +obsolete(disk_log, lclose, 1) -> + {removed, "use disk_log:close/1 instead"}; +obsolete(disk_log, lclose, 2) -> + {removed, "use disk_log:close/1 instead"}; obsolete(erl_lint, modify_line, 2) -> {removed, "use erl_parse:map_anno/2 instead"}; obsolete(erl_parse, get_attribute, 2) -> @@ -243,18 +157,54 @@ obsolete(erlang, get_stacktrace, 0) -> {removed, "use the new try/catch syntax for retrieving the stack backtrace"}; obsolete(erlang, hash, 2) -> {removed, "use erlang:phash2/2 instead"}; +obsolete(filename, safe_relative_path, 1) -> + {removed, "use filelib:safe_relative_path/2 instead"}; +obsolete(ftp, start_service, 1) -> + {removed, "use ftp:open/2 instead"}; +obsolete(ftp, stop_service, 1) -> + {removed, "use ftp:close/1 instead"}; +obsolete(http_uri, parse, 1) -> + {removed, "use uri_string functions instead"}; +obsolete(http_uri, parse, 2) -> + {removed, "use uri_string functions instead"}; +obsolete(http_uri, scheme_defaults, 0) -> + {removed, "use uri_string functions instead"}; obsolete(httpd_conf, check_enum, 2) -> {removed, "use lists:member/2 instead"}; obsolete(httpd_conf, clean, 1) -> - {removed, "use sting:strip/1 instead or possibly the re module"}; + {removed, "use string:strip/1 instead or possibly the re module"}; obsolete(httpd_conf, custom_clean, 3) -> - {removed, "use sting:strip/1 instead or possibly the re module"}; + {removed, "use string:strip/1 instead or possibly the re module"}; obsolete(httpd_conf, is_directory, 1) -> {removed, "use filelib:is_dir/1 instead"}; obsolete(httpd_conf, is_file, 1) -> {removed, "use filelib:is_file/1 instead"}; obsolete(httpd_conf, make_integer, 1) -> {removed, "use erlang:list_to_integer/1 instead"}; +obsolete(httpd_util, decode_hex, 1) -> + {removed, "use uri_string:unquote function instead"}; +obsolete(httpd_util, encode_hex, 1) -> + {removed, "use uri_string:quote function instead"}; +obsolete(httpd_util, flatlength, 1) -> + {removed, "use erlang:iolist_size/1 instead"}; +obsolete(httpd_util, hexlist_to_integer, 1) -> + {removed, "use erlang:list_to_integer/2 with base 16 instead"}; +obsolete(httpd_util, integer_to_hexlist, 1) -> + {removed, "use erlang:integer_to_list/2 with base 16 instead"}; +obsolete(httpd_util, strip, 1) -> + {removed, "use string:trim/1 instead"}; +obsolete(httpd_util, suffix, 1) -> + {removed, "use filename:extension/1 and string:trim/2 instead"}; +obsolete(net, relay, 1) -> + {removed, "use fun Relay(Pid) -> receive X -> Pid ! X end, Relay(Pid) instead"}; +obsolete(public_key, ssh_decode, 2) -> + {removed, "use ssh_file:decode/2 instead"}; +obsolete(public_key, ssh_encode, 2) -> + {removed, "use ssh_file:encode/2 instead"}; +obsolete(public_key, ssh_hostkey_fingerprint, 1) -> + {removed, "use ssh:hostkey_fingerprint/1 instead"}; +obsolete(public_key, ssh_hostkey_fingerprint, 2) -> + {removed, "use ssh:hostkey_fingerprint/2 instead"}; obsolete(rpc, safe_multi_server_call, 2) -> {removed, "use rpc:multi_server_call/2 instead"}; obsolete(rpc, safe_multi_server_call, 3) -> @@ -285,10 +235,16 @@ obsolete(filename, find_src, _) -> {removed, "use filelib:find_source/1,3 instead"}; obsolete(ssl, ssl_accept, _) -> {removed, "use ssl_handshake/1,2,3 instead"}; +obsolete(ct_slave, _, _) -> + {deprecated, "use ?CT_PEER(), or the 'peer' module instead", "OTP 27"}; obsolete(gen_fsm, _, _) -> {deprecated, "use the 'gen_statem' module instead"}; obsolete(random, _, _) -> {deprecated, "use the 'rand' module instead"}; +obsolete(slave, _, _) -> + {deprecated, "use the 'peer' module instead", "OTP 27"}; +obsolete(erts_alloc_config, _, _) -> + {removed, "this module has as of OTP 26.0 been removed"}; obsolete(os_mon_mib, _, _) -> {removed, "this module was removed in OTP 22.0"}; obsolete(pg2, _, _) -> @@ -314,5 +270,21 @@ obsolete_type(erl_scan, line, 0) -> {removed, "use erl_anno:line() instead"}; obsolete_type(erl_scan, location, 0) -> {removed, "use erl_anno:location() instead"}; +obsolete_type(http_uri, default_scheme_port_number, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, fragment, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, host, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, path, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, query, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, scheme, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, uri, 0) -> + {removed, "use uri_string instead"}; +obsolete_type(http_uri, user_info, 0) -> + {removed, "use uri_string instead"}; obsolete_type(_,_,_) -> no. diff --git a/lib/stdlib/src/peer.erl b/lib/stdlib/src/peer.erl new file mode 100644 index 000000000000..0879b799c52e --- /dev/null +++ b/lib/stdlib/src/peer.erl @@ -0,0 +1,1244 @@ +%% +%% Copyright WhatsApp Inc. and its affiliates. 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. +%% + +%% @doc +%% Controller for additional Erlang node running on the same host, +%% or in a different container/host (e.g. Docker). +%% +%% == Terms == +%% Origin node - Erlang VM instance that spawns additional nodes. +%% Peer node - a node spawned by the origin. +%% Control process - a process running on origin node, if it terminates, +%% peer node terminates too. +%% Control connection - a connection between origin and peer, can be +%% ether Erlang Distribution connection, or alternative one. +%% +%% I/O is forwarded from peer node to origin via control connection. +%% +%% When standard_io is used as alternative connection, peer node +%% uses standard out to multiplex console output and control sequences. +%% Characters in range of 192-255 are reserved for control sequences, +%% see encode_port_data for details. If peer node attempts to print +%% characters in this range, an controlling process on the origin +%% node may terminate with an error (because CRC check will fail). +%% +%% Alternative connection via TCP does not have that limitation, but +%% it also does not redirect console I/O from the peer node. +%% @end +-module(peer). +-author("maximfca@gmail.com"). + +%% API +-export([ + start_link/0, + start_link/1, + start/1, + stop/1, + + random_name/0, + random_name/1, + + get_state/1, + + call/4, + call/5, + cast/4, + send/3 + ]). + +-export_type([server_ref/0]). + +-type server_ref() :: % What stop, get_state, call, cast, send accepts + pid(). + + +%% Could be gen_statem too, with peer_state, but most interactions +%% are anyway available in all states. +-behaviour(gen_server). + +%% gen_server callbacks +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2 + ]). + +%% Internal exports for stdin/stdout, non-distribution RPC, and tests +-export([ + start/0, %% this function must be named "start", requirement for user.erl + + %% Peer supervision... + supervision_child_spec/0, + start_supervision/0, + init_supervision/2, + system_continue/3, + system_terminate/4, + system_code_change/4, + system_get_state/1, + system_replace_state/2 + ]). + +%% Origin node will listen to the specified port (port 0 is auto-select), +%% or specified IP/Port, and expect peer node to connect to this port. +-type connection() :: + Port :: 0..65535 | + {inet:ip_address(), 0..65535} | + standard_io. + +%% Specification for boot waiting +-type wait_boot() :: + timeout() | %% wait for node to boot (default, 15 sec), + {pid(), Tag :: term()} | %% do not wait, send {Tag, {started, node(), pid()}} to Pid when node boots + false. %% don't wait, don't notify + +-type exec() :: + file:name() | %% path to "erl" (default is init:get_argument(progname)) + {file:name(), [string()]}. %% SSH support: {"/usr/bin/ssh", ["account@host_b", "/usr/bin/erl"]} + +%% Peer node start options +-type start_options() :: + #{ + name => atom() | string(), %% node name (part before @), if not defined, peer + %% starts in non-distributed mode (requires alternative connection) + longnames => boolean(), %% long/short names (default is net_kernel:longnames(), and shortnames) + host => string(), %% force hostname (when not specified, actual peer node hostname is used) + peer_down => stop | continue | crash, %% stop (default): when peer terminates, peer control process + %% stops normally regardless of the reason. + %% continue: when peer terminates, peer control process stays up + %% saving exit reason in the state + %% crash: when peer terminates, origin process + %% terminates with underlying reason + connection => connection(), %% alternative connection specification + exec => exec(), %% path to executable, or SSH/Docker support + detached => boolean(), %% if the node should be start in detached mode + args => [string()], %% additional command line parameters to append + post_process_args => + fun(([string()]) -> [string()]),%% fix the arguments + env => [{string(), string()}], %% additional environment variables + wait_boot => wait_boot(), %% default is synchronous start with 15 sec timeout + shutdown => close | %% close supervision channel + halt | %% The default... %% stop node using erlang:halt() wait default timeout for nodedown + {halt, disconnect_timeout()} | %% stop node using erlang:halt() wait timeout() for nodedown + disconnect_timeout() %% send init:stop() request and wait up to specified timeout for nodedown + }. + +%% Peer node states +-type peer_state() :: booting | running | {down, Reason :: term()}. + +-export_type([ + start_options/0, + peer_state/0, + exec/0, + disconnect_timeout/0 + ]). + +%% Maximum integer timeout value in a receive... +-define (MAX_INT_TIMEOUT, 4294967295). + +%% Default time we wait for distributed connection to be removed, +%% when shutdown type is halt, before we disconnect from the node... +-define (DEFAULT_HALT_DISCONNECT_TIMEOUT, 5000). + +%% Minimum time we wait for distributed connection to be removed, +%% before we disconnect from the node (except in the shutdown +%% close case)... +-define (MIN_DISCONNECT_TIMEOUT, 1000). + +%% Socket connect timeout, for TCP connection. +-define (CONNECT_TIMEOUT, 10000). + +%% Socket accept timeout, for TCP connection. +-define (ACCEPT_TIMEOUT, 60000). + +%% How long to wait for graceful shutdown. +-define (SHUTDOWN_TIMEOUT, 10000). + +%% Synchronous RPC timeout for alternative connection. +-define (SYNC_RPC_TIMEOUT, 5000). + +%% Default timeout for peer node to boot. +-define (WAIT_BOOT_TIMEOUT, 15000). + +-type disconnect_timeout() :: ?MIN_DISCONNECT_TIMEOUT..?MAX_INT_TIMEOUT | infinity. + +%% Peer supervisor channel connect timeout. +-define(PEER_SUP_CHANNEL_CONNECT_TIMEOUT, 30000). + +%% @doc Creates random node name, using "peer" as prefix. +-spec random_name() -> string(). +random_name() -> + random_name(?MODULE_STRING). + +%% @doc Creates sufficiently random node name, +%% using OS process ID for origin VM, resulting name +%% looks like prefix-3-7161 +-spec random_name(Prefix :: string() | atom()) -> string(). +random_name(Prefix) -> + OsPid = os:getpid(), + Uniq = erlang:unique_integer([positive]), + lists:concat([Prefix, "-", Uniq, "-", OsPid]). + +%% @doc Starts a distributed node with random name, on this host, +%% and waits for that node to boot. Returns full node name, +%% registers local process with the same name as peer node. +-spec start_link() -> {ok, pid(), node()} | {error, Reason :: term()}. +start_link() -> + start_link(#{name => random_name()}). + +%% @doc Starts peer node, linked to the calling process. +%% Accepts additional command line arguments and +%% other important options. +-spec start_link(start_options()) -> {ok, pid()} | {ok, pid(), node()} | {error, Reason} + when Reason :: term(). +start_link(Options) -> + start_it(Options, start_link). + +%% @doc Starts peer node, not linked to the calling process. +-spec start(start_options()) -> {ok, pid()} | {ok, pid(), node()} | {error, Reason} + when Reason :: term(). +start(Options) -> + start_it(Options, start). + +%% @doc Stops controlling process, shutting down peer node synchronously +-spec stop(Dest :: server_ref()) -> ok. +stop(Dest) -> + gen_server:stop(Dest). + +%% @doc returns peer node state. +-spec get_state(Dest :: server_ref()) -> peer_state(). +get_state(Dest) -> + gen_server:call(Dest, get_state). + +%% @doc Calls M:F(A) remotely, via alternative connection, with default 5 seconds timeout +-spec call(Dest :: server_ref(), Module :: module(), Function :: atom(), + Args :: [term()]) -> Result :: term(). +call(Dest, M, F, A) -> + call(Dest, M, F, A, ?SYNC_RPC_TIMEOUT). + +%% @doc Call M:F(A) remotely, timeout is explicitly specified +-spec call(Dest :: server_ref(), Module :: module(), Function :: atom(), + Args :: [term()], Timeout :: timeout()) -> Result :: term(). +call(Dest, M, F, A, Timeout) -> + case gen_server:call(Dest, {call, M, F, A}, Timeout) of + {ok, Reply} -> + Reply; + {Class, {Reason, Stack}} -> + erlang:raise(Class, Reason, Stack); + {error, Reason} -> + erlang:error(Reason) + end. + +%% @doc Cast M:F(A) remotely, don't care about the result +-spec cast(Dest :: server_ref(), Module :: module(), Function :: atom(), Args :: [term()]) -> ok. +cast(Dest, M, F, A) -> + gen_server:cast(Dest, {cast, M, F, A}). + +%% @doc Sends a message to pid or named process on the peer node +%% using alternative connection. No delivery guarantee. +-spec send(Dest :: server_ref(), To :: pid() | atom(), Message :: term()) -> ok. +send(Dest, To, Message) -> + gen_server:cast(Dest, {send, To, Message}). + +%%-------------------------------------------------------------------- +%%% gen_server callbacks + +-record(peer_state, { + options :: start_options(), + %% full node name, can be 'undefined' + node :: atom(), + %% debugging information: executable and arguments used to + %% start the peer + exec :: file:name(), + args :: [string()], + %% alternative connection socket/port + connection :: undefined | port() | gen_tcp:socket(), + %% listening socket, while waiting for network alternative connection + listen_socket :: undefined | gen_tcp:socket(), + %% accumulator for RPC over standard_io + stdio = <<>> :: binary(), + %% peer state + peer_state = booting :: peer_state(), + %% pid/ref saved for gen:reply() when node is booted, or false + notify = false :: false | {pid(), reference()}, + %% counter (reference) for calls. + %% it is not possible to use erlang reference, or pid, + %% because it changes when node becomes distributed dynamically. + seq = 0 :: non_neg_integer(), + %% outstanding calls + outstanding = #{} :: #{non_neg_integer() => {reference(), pid()}} + }). + +-type state() :: #peer_state{}. + +-spec init([Name :: atom(), ... ]) -> {ok, state()}. +init([Notify, Options]) -> + process_flag(trap_exit, true), %% need this to ensure terminate/2 is called + + {ListenSocket, Listen} = maybe_listen(Options), + {Exec, Args} = command_line(Listen, Options), + + Env = maps:get(env, Options, []), + + PostProcessArgs = maps:get(post_process_args, Options, fun(As) -> As end), + FinalArgs = PostProcessArgs(Args), + + %% close port if running detached + Conn = + case maps:find(connection, Options) of + {ok, standard_io} -> + %% Cannot detach a peer that uses stdio. Request exit_status. + open_port({spawn_executable, Exec}, + [{args, FinalArgs}, {env, Env}, hide, + binary, exit_status, stderr_to_stdout]); + _ -> + Port = open_port({spawn_executable, Exec}, + [{args, FinalArgs}, {env, Env}, hide, binary]), + %% peer can close the port before we get here which will cause + %% port_close to throw. Catch this and ignore. + catch erlang:port_close(Port), + receive {'EXIT', Port, _} -> undefined end + end, + + %% Remove the default 'halt' shutdown option if present; the default is + %% defined in terminate()... + SaveOptions = case maps:find(shutdown, Options) of + {ok, halt} -> + maps:remove(shutdown, Options); + _ -> + Options + end, + + State = #peer_state{options = SaveOptions, notify = Notify, args = Args, exec = Exec}, + + %% accept TCP connection if requested + if ListenSocket =:= undefined -> + {ok, State#peer_state{connection = Conn}}; + true -> + _ = prim_inet:async_accept(ListenSocket, ?ACCEPT_TIMEOUT), + {ok, State#peer_state{listen_socket = ListenSocket}} + end. + +%% not connected: no alternative connection available +handle_call({call, _M, _F, _A}, _From, #peer_state{connection = undefined} = State) -> + {reply, {error, noconnection}, State}; + +handle_call({call, M, F, A}, From, + #peer_state{connection = Port, options = #{connection := standard_io}, + outstanding = Out, seq = Seq} = State) -> + origin_to_peer(port, Port, {call, Seq, M, F, A}), + {noreply, State#peer_state{outstanding = Out#{Seq => From}, seq = Seq + 1}}; + +handle_call({call, M, F, A}, From, + #peer_state{connection = Socket, outstanding = Out, seq = Seq} = State) -> + origin_to_peer(tcp, Socket, {call, Seq, M, F, A}), + {noreply, State#peer_state{outstanding = Out#{Seq => From}, seq = Seq + 1}}; + +handle_call({starting, Node}, _From, #peer_state{ options = Options } = State) -> + case maps:find(shutdown, Options) of + {ok, {Timeout, MainCoverNode}} when is_integer(Timeout), + is_atom(MainCoverNode) -> + %% The node was started using test_server:start_peer/2 with cover enabled + %% so we should start cover on the starting node. + Modules = erpc:call(MainCoverNode,cover,modules,[]), + Sticky = [ begin erpc:call(Node, code, unstick_mod, [M]), M end + || M <- Modules, erpc:call(Node, code, is_sticky,[M])], + _ = erpc:call(MainCoverNode, cover, start, [Node]), + _ = [erpc:call(Node, code,stick_mod,[M]) || M <- Sticky], + ok; + _ -> + ok + end, + {reply, ok, State}; +handle_call(get_node, _From, #peer_state{node = Node} = State) -> + {reply, Node, State}; + +handle_call(get_state, _From, #peer_state{peer_state = PeerState} = State) -> + {reply, PeerState, State}; + +handle_call(group_leader, _From, State) -> + {reply, group_leader(), State}. + +handle_cast({cast, _M, _F, _A}, #peer_state{connection = undefined} = State) -> + {noreply, State}; + +handle_cast({cast, M, F, A}, + #peer_state{connection = Port, options = #{connection := standard_io}} = State) -> + origin_to_peer(port, Port, {cast, M, F, A}), + {noreply, State}; + +handle_cast({cast, M, F, A}, #peer_state{connection = Socket} = State) -> + origin_to_peer(tcp, Socket, {cast, M, F, A}), + {noreply, State}; + +handle_cast({send, _Dest, _Message}, #peer_state{connection = undefined} = State) -> + {noreply, State}; + +handle_cast({send, Dest, Message}, + #peer_state{connection = Port, options = #{connection := standard_io}} = State) -> + origin_to_peer(port, Port, {message, Dest, Message}), + {noreply, State}; + +handle_cast({send, Dest, Message}, #peer_state{connection = Socket} = State) -> + origin_to_peer(tcp, Socket, {message, Dest, Message}), + {noreply, State}. + +%%-------------------------------------------------------------------- +%% alternative connections handling + +%% alternative communications - request or response from peer +handle_info({tcp, Socket, SocketData}, #peer_state{connection = Socket} = State) -> + ok = inet:setopts(Socket, [{active, once}]), + {noreply, handle_alternative_data(tcp, binary_to_term(SocketData), State)}; + +%% standard_io +handle_info({Port, {data, PortData}}, #peer_state{connection = Port, stdio = PrevBin} = State) -> + {Str, NewBin} = decode_port_data(PortData, <<>>, PrevBin), + Str =/= <<>> andalso io:put_chars(Str), + {noreply, handle_port_binary(NewBin, State)}; + +%% booting: accepted TCP connection from the peer, but it is not yet +%% complete handshake +handle_info({inet_async, LSock, _Ref, {ok, CliSocket}}, + #peer_state{listen_socket = LSock} = State) -> + true = inet_db:register_socket(CliSocket, inet_tcp), + ok = inet:setopts(CliSocket, [{active, once}]), + catch gen_tcp:close(LSock), + {noreply, State#peer_state{connection = CliSocket, listen_socket = undefined}}; + +handle_info({inet_async, LSock, _Ref, {error, Reason}}, + #peer_state{listen_socket = LSock} = State) -> + %% failed to accept a TCP connection + catch gen_tcp:close(LSock), + %% stop unconditionally, it is essentially a part of gen_server:init callback + {stop, {inet_async, Reason}, State#peer_state{connection = undefined, listen_socket = undefined}}; + +%% booting: peer notifies via Erlang distribution +handle_info({started, Node}, State)-> + true = erlang:monitor_node(Node, true), + {noreply, boot_complete(Node, started, State)}; + +%% nodedown: no-alternative dist-connected peer node is down +handle_info({nodedown, Node}, #peer_state{connection = undefined} = State) -> + maybe_stop({nodedown, Node}, State); + +%% external program exited, returned Status code +handle_info({Port, {exit_status, Status}}, #peer_state{connection = Port} = State) -> + catch erlang:port_close(Port), + maybe_stop({exit_status, Status}, State); + +%% port terminated: cannot proceed, stop the server +handle_info({'EXIT', Port, Reason}, #peer_state{connection = Port} = State) -> + catch erlang:port_close(Port), + maybe_stop(Reason, State); + +handle_info({tcp_closed, Sock}, #peer_state{connection = Sock} = State) -> + %% TCP connection closed, no i/o port - assume node is stopped + catch gen_tcp:close(Sock), + maybe_stop(tcp_closed, State#peer_state{connection = undefined}). + +%%-------------------------------------------------------------------- +%% cleanup/termination + +-spec terminate(Reason :: term(), state()) -> ok. +terminate(_Reason, #peer_state{connection = Port, options = Options, node = Node}) -> + case {maps:get(shutdown, Options, {halt, ?DEFAULT_HALT_DISCONNECT_TIMEOUT}), + maps:find(connection, Options)} of + {close, {ok, standard_io}} -> + Port /= undefined andalso (catch erlang:port_close(Port)); + {close, {ok, _TCP}} -> + Port /= undefined andalso (catch gen_tcp:close(Port)); + {close, error} -> + _ = erlang:disconnect_node(Node); + {{halt, Timeout}, {ok, standard_io}} -> + Port /= undefined andalso (catch erlang:port_close(Port)), + wait_disconnected(Node, {timeout, Timeout}); + {{halt, Timeout}, {ok, _TCP}} -> + Port /= undefined andalso (catch gen_tcp:close(Port)), + wait_disconnected(Node, {timeout, Timeout}); + {{halt, Timeout}, error} -> + try + _ = erpc:call(Node, erlang, halt, [], Timeout), + ok + catch + error:{erpc,noconnection} -> ok; + _:_ -> force_disconnect_node(Node) + end; + {Shutdown, error} -> + Timeout = shutdown(dist, undefined, Node, Shutdown), + wait_disconnected(Node, {timeout, Timeout}); + {Shutdown, {ok, standard_io}} -> + Timeout = shutdown(port, Port, Node, Shutdown), + Deadline = deadline(Timeout), + receive {'EXIT', Port, _Reason2} -> ok after Timeout -> ok end, + catch erlang:port_close(Port), + wait_disconnected(Node, Deadline); + {Shutdown, {ok, _TCP}} -> + Timeout = shutdown(tcp, Port, Node, Shutdown), + Deadline = deadline(Timeout), + receive {tcp_closed, Port} -> ok after Timeout -> ok end, + catch catch gen_tcp:close(Port), + wait_disconnected(Node, Deadline) + end, + ok. + +%%-------------------------------------------------------------------- +%% Internal implementation + +deadline(infinity) -> + {timeout, infinity}; +deadline(Timeout) when is_integer(Timeout) -> + {deadline, erlang:monotonic_time(millisecond) + Timeout}. + +wait_disconnected(Node, WaitUntil) -> + %% Should only be called just before we are exiting the caller, so + %% we do not bother disabling nodes monitoring if we enable it and + %% do not flush any nodeup/nodedown messages that we got due to the + %% nodes monitoring... + case lists:member(Node, nodes(connected)) of + false -> + ok; + true -> + _ = net_kernel:monitor_nodes(true, [{node_type, all}]), + %% Need to check connected nodes list again, since it + %% might have disconnected before we enabled nodes + %% monitoring... + case lists:member(Node, nodes(connected)) of + false -> + ok; + true -> + Tmo = case WaitUntil of + {timeout, T} -> + T; + {deadline, T} -> + TL = T - erlang:monotonic_time(millisecond), + if TL < 0 -> 0; + true -> TL + end + end, + receive {nodedown, Node, _} -> ok + after Tmo -> force_disconnect_node(Node) + end + end + end. + +force_disconnect_node(Node) -> + _ = erlang:disconnect_node(Node), + logger:warning("peer:stop() timed out waiting for disconnect from " + "node ~p. The connection was forcefully taken down.", + [Node]). + +%% This hack is a temporary workaround for test coverage reports +shutdown(_Type, _Port, Node, Timeout) when is_integer(Timeout); Timeout =:= infinity -> + erpc:cast(Node, init, stop, []), + Timeout; +shutdown(dist, undefined, Node, {Timeout, CoverNode}) when is_integer(Timeout); Timeout =:= infinity -> + rpc:call(CoverNode, cover, flush, [Node]), + erpc:cast(Node, init, stop, []), + Timeout; +shutdown(Type, Port, Node, {Timeout, CoverNode}) when is_integer(Timeout); Timeout =:= infinity -> + rpc:call(CoverNode, cover, flush, [Node]), + Port /= undefined andalso origin_to_peer(Type, Port, {cast, init, stop, []}), + Timeout. + +%% Verify options correctness (Dialyzer also does the job, but slightly less convenient) +verify_args(Options) -> + %% verify that "Args" is valid - common problem is when Args aren't strings + Args = maps:get(args, Options, []), + is_list(Args) orelse error({invalid_arg, Args}), + [error({invalid_arg, Arg}) || Arg <- Args, not io_lib:char_list(Arg)], + %% alternative connection must be requested for non-distributed node, + %% or a distributed node when origin is not alive + is_map_key(connection, Options) + orelse + (is_map_key(name, Options) andalso erlang:is_alive()) orelse error(not_alive), + %% exec must be a string, or a tuple of string(), [string()] + case maps:find(exec, Options) of + {ok, {Exec, Strs}} -> + io_lib:char_list(Exec) orelse error({exec, Exec}), + [error({exec, Str}) || Str <- Strs, not io_lib:char_list(Str)], + ok; + {ok, Exec} when is_list(Exec) -> + io_lib:char_list(Exec) orelse error({exec, Exec}), + ok; + error -> + ok; + {ok, Err} -> + error({exec, Err}) + end, + case maps:find(shutdown, Options) of + {ok, close} -> + ok; + {ok, halt} -> + ok; + {ok, {halt, Tmo}} when (is_integer(Tmo) + andalso ?MIN_DISCONNECT_TIMEOUT =< Tmo + andalso Tmo =< ?MAX_INT_TIMEOUT) + orelse Tmo == infinity -> + ok; + {ok, Tmo} when (is_integer(Tmo) + andalso ?MIN_DISCONNECT_TIMEOUT =< Tmo + andalso Tmo =< ?MAX_INT_TIMEOUT) + orelse Tmo == infinity -> + ok; + {ok, {Tmo, Node}} when ((is_integer(Tmo) + andalso ?MIN_DISCONNECT_TIMEOUT =< Tmo + andalso Tmo =< ?MAX_INT_TIMEOUT) + orelse Tmo == infinity) + andalso is_atom(Node) -> + ok; + error -> + ok; + {ok, Err2} -> + error({shutdown, Err2}) + end, + case maps:find(detached, Options) of + {ok, false} when map_get(connection, Options) =:= standard_io -> + error({detached, cannot_detach_with_standard_io}); + _ -> + ok + end. + +make_notify_ref(infinity) -> + {self(), make_ref()}; +make_notify_ref(WaitBoot) when is_integer(WaitBoot) -> + {self(), make_ref()}; +make_notify_ref({ReplyTo, Tag}) when is_pid(ReplyTo) -> + {ReplyTo, Tag}; +make_notify_ref(false) -> + false. + +start_it(Options, StartFun) -> + verify_args(Options), + WaitBoot = maps:get(wait_boot, Options, ?WAIT_BOOT_TIMEOUT), + Notify = make_notify_ref(WaitBoot), + case gen_server:StartFun(?MODULE, [Notify, Options], []) of + {ok, Pid} when WaitBoot =:= infinity; is_integer(WaitBoot) -> + {_, Ref} = Notify, + Mref = erlang:monitor(process, Pid), + receive + {Ref, {started, NodeName, Pid}} -> + erlang:demonitor(Mref, [flush]), + {ok, Pid, NodeName}; + {Ref, {boot_failed, Reason, Pid}} -> + erlang:demonitor(Mref, [flush]), + erlang:exit({boot_failed, Reason}); + {'DOWN', Mref, _, _, Reason} -> + erlang:exit(Reason) + after + WaitBoot -> + _ = gen_server:stop(Pid), + erlang:demonitor(Mref, [flush]), + erlang:exit(timeout) + end; + {ok, Pid} when is_map_key(host, Options) -> + {ok, Pid, node_name(Options)}; + {ok, Pid} -> + {ok, Pid}; + Error -> + Error + end. + +node_name(#{name := Name, host := Host}) -> + list_to_atom(lists:concat([Name, "@", Host])); +node_name(_Options) -> + undefined. + +%% Lost control connection to the peer while the node was +%% booting, this generally means a crash +maybe_stop(Reason, #peer_state{peer_state = booting} = State) -> + _ = boot_complete(Reason, boot_failed, State), + maybe_stop(Reason, State#peer_state{peer_state = {down, Reason}}); +%% +maybe_stop(Reason, #peer_state{options = #{peer_down := crash}} = State) -> + {stop, Reason, State#peer_state{peer_state = {down, Reason}, connection = undefined}}; +%% if state was already down, keep the original reason +maybe_stop(_Reason, #peer_state{options = #{peer_down := continue}, peer_state = {down, _}} = State) -> + {noreply, State}; +%% continue working setting peer state to down +maybe_stop(Reason, #peer_state{options = #{peer_down := continue}} = State) -> + {noreply, State#peer_state{peer_state = {down, Reason}}}; +%% default: ignore Reason and shut down normally +maybe_stop(Reason, State) -> + {stop, normal, State#peer_state{peer_state = {down, Reason}}}. + +%% i/o protocol from origin: +%% * {io_reply, ...} +%% * {message, To, Content} +%% * {call, From, M, F, A} +%% +%% i/o port protocol, from peer: +%% * {io_request, From, ReplyAs, Request} +%% * {message, To, Content} +%% * {reply, From, ok | throw | error | exit | crash, Result | {Reason, Stack}} + +%% Handles bytes coming from alternative connection, forwarding as needed. +handle_alternative_data(Kind, {io_request, From, FromRef, IoReq}, #peer_state{connection = Conn} = State) -> + %% TODO: make i/o completely async + Reply = {io_reply, From, FromRef, forward_request(IoReq)}, + origin_to_peer(Kind, Conn, Reply), + State; +handle_alternative_data(_Kind, {message, To, Content}, State) -> + To ! Content, + State; +handle_alternative_data(_Kind, {reply, Seq, Class, Result}, #peer_state{outstanding = Out} = State) -> + {From, NewOut} = maps:take(Seq, Out), + gen:reply(From, {Class, Result}), + State#peer_state{outstanding = NewOut}; +handle_alternative_data(_Kind, {started, NodeName}, State)-> + boot_complete(NodeName, started, State). + +forward_request(Req) -> + GL = group_leader(), + MRef = erlang:monitor(process, GL), + GL ! {io_request,self(), MRef, Req}, + receive + {io_reply, MRef, Reply} -> + erlang:demonitor(MRef, [flush]), + Reply; + {'DOWN', MRef, _, _, _} -> + {error, terminated} + end. + +%% generic primitive to send data from origin to peer via alternative connection +origin_to_peer(tcp, Sock, Term) -> + ok = gen_tcp:send(Sock, term_to_binary(Term)); +origin_to_peer(port, Port, Term) -> + true = erlang:port_command(Port, encode_port_data(term_to_binary(Term))). + +%% generic primitive to send data from peer to origin +peer_to_origin(tcp, Sock, Term) -> + ok = gen_tcp:send(Sock, term_to_binary(Term)); +peer_to_origin(port, Port, Term) -> + %% converts Erlang term to terminal codes + %% Every binary byte is converted into two 4-bit sequences. + Bytes = term_to_binary(Term), + true = erlang:port_command(Port, encode_port_data(Bytes)). + +%% convert/escape Erlang term into terminal codes. +%% Protocol consists of Erlang terms serialised into +%% External Term Format (ETF) via term_to_binary. Then +%% every byte of the resulting binary is split into two +%% nibbles (4-bit sequences), which are encoded into two +%% characters. +%% Control characters must have first two and last two bits +%% set, so the byte looks this way: 11xxxx11. +%% Example encoding, hexadecimal 16#0F will be encoded as +%% 11000011 11111111 (decimal 195 255). +encode_port_data(Bytes) -> + Size = byte_size(Bytes), + Crc = erlang:crc32(Bytes), + Total = <>, + <<<<3:2, Upper:4, 3:2, 3:2, Lower:4, 3:2>> || <> <= Total>>. + +%% convert terminal codes to Erlang term, printing everything that +%% was detected as text +decode_port_data(<<>>, Str, Bin) -> + {Str, Bin}; +decode_port_data(<<3:2, Quad:4, 3:2, Rest/binary>>, Str, Bin) -> + decode_port_data(Rest, Str, <>); +decode_port_data(<>, Str, Bin) -> + decode_port_data(Rest, <>, Bin). + +%% recursively process buffers, potentially changing the state +handle_port_binary(<>, State) -> + Crc = erlang:crc32(Payload), + Term = binary_to_term(Payload), + NewState = handle_alternative_data(port, Term, State), + handle_port_binary(Rest, NewState); +handle_port_binary(NewBin, State) -> + State#peer_state{stdio = NewBin}. + +boot_complete(Node, _Result, #peer_state{notify = false} = State) -> + State#peer_state{peer_state = running, node = Node}; +boot_complete(Node, Result, #peer_state{notify = {ReplyTo, Tag}} = State) -> + ReplyTo ! {Tag, {Result, Node, self()}}, + State#peer_state{peer_state = running, node = Node}. + +%% check if TCP connection is enabled, and starts listener +maybe_listen(#{connection := Port}) when is_integer(Port) -> + {ok, LSock} = gen_tcp:listen(Port, [binary, {reuseaddr, true}, {packet, 4}]), + {ok, WaitPort} = inet:port(LSock), + %% try guessing a local IP address + {ok, Ifs} = inet:getifaddrs(), + %% next incantation gets all IP addresses of all local interfaces that are up + LocalUp = lists:append( + [proplists:get_all_values(addr, Opts) + || {_, Opts} <- Ifs, lists:member(up, proplists:get_value(flags, Opts, []))]), + %% filter invalid addresses + Local = prefer_localhost([Valid || Valid <- LocalUp, is_list(inet:ntoa(Valid))], [], []), + {LSock, {Local, WaitPort}}; +maybe_listen(#{connection := {Ip, Port}}) when is_integer(Port) -> + {ok, LSock} = gen_tcp:listen(Port, [binary, {reuseaddr, true}, {packet, 4}, {ip, Ip}]), + WaitPort = if Port =:= 0 -> {ok, Dyn} = inet:port(LSock), Dyn; true -> Port end, + {LSock, {[Ip], WaitPort}}; +maybe_listen(_Options) -> + {undefined, undefined}. + +%% prefer localhost, IPv6 localhost, then everything else +prefer_localhost([], Preferred, Other) -> + Preferred ++ Other; +prefer_localhost([{127, _, _, _} = Local | Tail], Preferred, Other) -> + prefer_localhost(Tail, [Local | Preferred], Other); +prefer_localhost([{0, 0, 0, 0, 0, 0, 0, 1} = Local | Tail], Preferred, Other) -> + prefer_localhost(Tail, [Local | Preferred], Other); +prefer_localhost([Local | Tail], Preferred, Other) -> + prefer_localhost(Tail, Preferred, [Local | Other]). + +name_arg(error, error, _) -> + []; %% no name, no host - starting node that is not distributed +name_arg(error, {ok, Host}, LongOrShort) -> + %% interesting fallback: host is set, name is not. Do what predecessor did, + %% take the current node name and use it... + [Name, _] = string:lexemes(atom_to_list(node()), "@"), + name_arg(Name ++ "@" ++ Host, error, LongOrShort); +name_arg({ok, Name}, Host, LongOrShort) -> + name_arg(Name, Host, LongOrShort); %% unpack node name +name_arg(Name, Host, LongOrShort) when is_atom(Name) -> + name_arg(atom_to_list(Name), Host, LongOrShort); %% convert atom to list for command line +name_arg(Name, Host, {ok, ignored}) -> + name_arg(Name, Host, {ok, false}); %% fallback to shortnames when origin is not distributed +name_arg(Name, Host, error) -> + name_arg(Name, Host, {ok, net_kernel:longnames()}); %% no longnames present it start options +name_arg(Name, {ok, Host}, LongOrShort) -> + name_arg(Name ++ "@" ++ Host, error, LongOrShort); %% merge host part +%% only these are actual name creation clauses +name_arg(Name, error, {ok, true}) -> + ["-name", Name]; +name_arg(Name, error, {ok, false}) -> + ["-sname", Name]. + +command_line(Listen, Options) -> + %% Node name/sname + NameArg = name_arg(maps:find(name, Options), maps:find(host, Options), maps:find(longnames, Options)), + %% additional command line args + CmdOpts = maps:get(args, Options, []), + + %% If we should detach from the node. We use -detached to tell erl to detach + %% and -peer_detached to tell peer:start that we are detached. + DetachArgs = case maps:get(detached, Options, true) of + true -> ["-detached","-peer_detached"]; + false -> [] + end, + + %% start command + StartCmd = + case Listen of + undefined when map_get(connection, Options) =:= standard_io -> + ["-user", atom_to_list(?MODULE)]; + undefined -> + Self = base64:encode_to_string(term_to_binary(self())), + DetachArgs ++ ["-user", atom_to_list(?MODULE), "-origin", Self]; + {Ips, Port} -> + IpStr = lists:concat(lists:join(",", [inet:ntoa(Ip) || Ip <- Ips])), + DetachArgs ++ ["-user", atom_to_list(?MODULE), "-origin", IpStr, integer_to_list(Port)] + end, + %% build command line + {Exec, PreArgs} = exec(Options), + {Exec, PreArgs ++ NameArg ++ CmdOpts ++ StartCmd}. + +exec(#{exec := Prog}) when is_list(Prog) -> + {Prog, []}; +exec(#{exec := {Prog, Args}}) when is_list(Prog), is_list(Args) -> + {Prog, Args}; +exec(Options) when not is_map_key(exec, Options) -> + case init:get_argument(progname) of + {ok, [[Prog]]} -> + case os:find_executable(Prog) of + Exec when is_list(Exec) -> + {Exec, []}; + false -> + maybe_otp_test_suite(Prog) + end; + _ -> + default_erts() + end. + +maybe_otp_test_suite(Prog) -> + case string:split(Prog, "cerl ") of + [CerlPath, Args] -> + %% This is a hack to handle the 'cerl' script used + %% by the Erlang/OTP test suites. When 'cerl' + %% starts the runtime system, it typically sets + %% 'progname' to the path of the 'cerl' script, + %% followed by an argument. For example: + %% + %% //cerl -debug + %% //cerl -asan + %% //cerl -gcov + %% + %% We should find a better way to handle this, for + %% example by passing the emulator type and flavor + %% using the '-emu_type' and '-emu_flavor' + %% options. However, this is not without + %% complications as those options do not really + %% work for an installed system. Also, it is + %% probably a good idea to stop using 'slave' + %% before attempting to do this. + {filename:join(CerlPath, "cerl"), parse_args(Args)}; + _ -> + default_erts() + end. + + +%% Split command line string into a list of arguments. +-spec parse_args(string()) -> [string()]. +parse_args([]) -> + []; +parse_args([Deep | _] = AlreadyParsed) when is_list(Deep) -> + AlreadyParsed; +parse_args(CmdLine) -> + %% following regex splits command line, preserving quoted arguments, into argv[] list + Re = <<"((?:\"[^\"\\\\]*(?:\\\\[\\S\\s][^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\[\\S\\s][^'\\\\]*)*'|\\/[^\\/\\\\]*(?:\\\\[\\S\\s][^\\/\\\\]*)*\\/[gimy]*(?=\\s|$)|(?:\\\\\\s|\\S))+)(?=\\s|$)">>, + {match, Args} = re:run(CmdLine, Re, [{capture, all_but_first, list}, global]), + %% unquote arguments. It is possible to change regex capture groups to avoid extra processing. + [unquote(Arg) || [Arg] <- Args]. + +unquote([Q | Arg]) when Q =:= $\"; Q =:= $\' -> + case lists:last(Arg) of + Q -> lists:droplast(Arg); + _ -> [Q | Arg] + end; + unquote(Arg) -> + Arg. + +%% if progname is not known, use `erlexec` from the same ERTS version we're currently running +%% BINDIR environment variable is already set +%% EMU variable it also set +default_erts() -> + Root = code:root_dir(), + Erts = filename:join(Root, lists:concat(["erts-", erlang:system_info(version)])), + BinDir = filename:join(Erts, "bin"), + {filename:join(BinDir, "erlexec"), []}. + +%%-------------------------------------------------------------------- +%% peer node implementation + +notify_when_started(Kind, Port) -> + init:notify_when_started(self()) =:= started andalso + notify_started(Kind, Port), + ok. + +notify_started(dist, Process) -> + Process ! {started, node()}, + ok; +notify_started(Kind, Port) -> + peer_to_origin(Kind, Port, {started, node()}). + +%% +%% Supervision of peer user process (which supervise the control channel) making +%% sure that the peer node is halted if the peer user process crashes... +%% + +supervision_child_spec() -> + case init:get_argument(user) of + {ok, [["peer"]]} -> + {ok, #{id => peer_supervision, + start => {?MODULE, start_supervision, []}, + restart => permanent, + shutdown => 1000, + type => worker, + modules => [?MODULE]}}; + _ -> + none + end. + +start_supervision() -> + proc_lib:start_link(?MODULE, init_supervision, [self(), true]). + +start_orphan_supervision() -> + proc_lib:start(?MODULE, init_supervision, [self(), false]). + +-record(peer_sup_state, {parent, channel, in_sup_tree}). + +-spec init_supervision(term(), term()) -> no_return(). +init_supervision(Parent, InSupTree) -> + try + process_flag(priority, high), + process_flag(trap_exit, true), + register(peer_supervision, self()), + proc_lib:init_ack(Parent, {ok, self()}), + Channel = receive + {channel_connect, Ref, From, ConnectChannel} -> + true = is_pid(ConnectChannel), + From ! Ref, + try + link(ConnectChannel) + catch error:noproc -> + exit({peer_channel_terminated, noproc}) + end, + ConnectChannel + after + ?PEER_SUP_CHANNEL_CONNECT_TIMEOUT -> + exit(peer_channel_connect_timeout) + end, + loop_supervision(#peer_sup_state{parent = Parent, + channel = Channel, + in_sup_tree = InSupTree}) + catch + _:_ when not InSupTree -> + erlang:halt(1) + end. + +peer_sup_connect_channel(PeerSupervision, PeerChannelHandler) -> + Ref = make_ref(), + PeerSupervision ! {channel_connect, Ref, self(), PeerChannelHandler}, + receive + Ref -> ok + after + ?PEER_SUP_CHANNEL_CONNECT_TIMEOUT -> + exit(peer_supervision_connect_timeout) + end. + +loop_supervision(#peer_sup_state{parent = Parent, + channel = Channel} = State) -> + receive + {'EXIT', Channel, Reason} -> + exit({peer_channel_terminated, Reason}); + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State); + _ -> + loop_supervision(State) + end. + + +system_continue(_Parent, _, #peer_sup_state{} = State) -> + loop_supervision(State). + +system_terminate(Reason, _Parent, _Debug, _State) -> + exit(Reason). + +system_code_change(State, _Module, _OldVsn, _Extra) -> + {ok, State}. + +system_get_state(State) -> + {ok, State}. + +system_replace_state(StateFun, State) -> + NState = StateFun(State), + {ok, NState, NState}. + +%% End of peer user supervision + +%% I/O redirection: peer side +-spec start() -> pid(). +start() -> + try + PeerChannelHandler = start_peer_channel_handler(), + PeerSup = case whereis(peer_supervision) of + PeerSup0 when is_pid(PeerSup0) -> + PeerSup0; + undefined -> + {ok, PeerSup0} = start_orphan_supervision(), + PeerSup0 + end, + peer_sup_connect_channel(PeerSup, PeerChannelHandler), + PeerChannelHandler + catch _:_ -> + erlang:halt(1) + end. + +start_peer_channel_handler() -> + case init:get_argument(origin) of + {ok, [[IpStr, PortString]]} -> + %% enter this clause when -origin IpList Port is specified in the command line. + Port = list_to_integer(PortString), + Ips = [begin {ok, Addr} = inet:parse_address(Ip), Addr end || + Ip <- string:lexemes(IpStr, ",")], + TCPConnection = spawn(fun () -> tcp_init(Ips, Port) end), + _ = case init:get_argument(peer_detached) of + {ok, _} -> + _ = register(user, TCPConnection); + error -> + _= user_sup:init( + [Flag || Flag <- init:get_arguments(), Flag =/= {user,["peer"]}]) + end, + TCPConnection; + {ok, [[Base64EncProc]]} -> + %% No alternative connection, but have "-origin Base64EncProc" + OriginProcess = binary_to_term(base64:decode(Base64EncProc)), + OriginLink = spawn( + fun () -> + MRef = monitor(process, OriginProcess), + notify_when_started(dist, OriginProcess), + origin_link(MRef, OriginProcess) + end), + ok = gen_server:call(OriginProcess, {starting, node()}), + _ = case init:get_argument(peer_detached) of + {ok, _} -> + %% We are detached, so setup 'user' process, I/O redirection: + %% ask controlling process who is the group leader. + GroupLeader = gen_server:call(OriginProcess, group_leader), + RelayPid = spawn(fun () -> + link(OriginLink), + relay(GroupLeader) + end), + _ = register(user, RelayPid); + error -> + %% We are not detached, so after we spawn the link process we + %% start the terminal as normal but without the -user peer flag. + _ = user_sup:init( + [Flag || Flag <- init:get_arguments(), Flag =/= {user,["peer"]}]) + end, + OriginLink; + error -> + %% no -origin specified, meaning that standard I/O is used for alternative + spawn(fun io_server/0) + end. + +relay(GroupLeader) -> + receive + IO -> + GroupLeader ! IO, + relay(GroupLeader) + end. + +origin_link(MRef, Origin) -> + receive + {'DOWN', MRef, process, Origin, _Reason} -> + erlang:halt(); + {init, started} -> + notify_started(dist, Origin), + origin_link(MRef, Origin) + end. + +-spec io_server() -> no_return(). +io_server() -> + try + process_flag(trap_exit, true), + Port = erlang:open_port({fd, 0, 1}, [eof, binary]), + register(user, self()), + group_leader(self(), self()), + notify_when_started(port, Port), + io_server_loop(port, Port, #{}, #{}, <<>>) + catch + _:_ -> + erlang:halt(1) + end. + +-spec tcp_init([term()], term()) -> no_return(). +tcp_init(IpList, Port) -> + try + Sock = loop_connect(IpList, Port), + erlang:group_leader(self(), self()), + notify_when_started(tcp, Sock), + io_server_loop(tcp, Sock, #{}, #{}, undefined) + catch + _:_ -> + erlang:halt(1) + end. + +loop_connect([], _Port) -> + error(noconnection); +loop_connect([Ip | More], Port) -> + case gen_tcp:connect(Ip, Port, [binary, {packet, 4}], ?CONNECT_TIMEOUT) of + {ok, Sock} -> + Sock; + _Error -> + loop_connect(More, Port) + end. + +%% Message protocol between peers +io_server_loop(Kind, Port, Refs, Out, PortBuf) -> + receive + {io_request, From, ReplyAs, Request} when is_pid(From) -> + %% i/o request from this node, forward it to origin + peer_to_origin(Kind, Port, {io_request, From, ReplyAs, Request}), + io_server_loop(Kind, Port, Refs, Out, PortBuf); + {Port, {data, Bytes}} when Kind =:= port -> + {_Str, NewBin} = decode_port_data(Bytes, <<>>, PortBuf), + {NewRefs, NewOut, NewBuf} = handle_port_alternative(NewBin, Refs, Out), + io_server_loop(Kind, Port, NewRefs, NewOut, NewBuf); + {Port, eof} when Kind =:= port -> + %% stdin closed, if there is no active alternative, stop the node + erlang:halt(1); + {'EXIT', Port, badsig} when Kind =:= port -> + %% ignore badsig (what is it?) + io_server_loop(Kind, Port, Refs, Out, PortBuf); + {'EXIT', Port, _Reason} when Kind =:= port -> + %% stdin closed, if there is no active alternative, stop the node + erlang:halt(1); + {tcp, Port, Data} when Kind =:= tcp -> + ok = inet:setopts(Port, [{active, once}]), %% flow control + {NewRefs, NewOut} = handle_peer_alternative(binary_to_term(Data), Refs, Out), + io_server_loop(Kind, Port, NewRefs, NewOut, PortBuf); + {tcp_closed, Port} when Kind =:= tcp -> + %% TCP connection closed, time to shut down + erlang:halt(1); + {reply, Seq, Class, Reply} when is_integer(Seq), is_map_key(Seq, Out) -> + %% stdin/stdout RPC + {CallerRef, Out2} = maps:take(Seq, Out), + Refs2 = maps:remove(CallerRef, Refs), + erlang:demonitor(CallerRef, [flush]), + peer_to_origin(Kind, Port, {reply, Seq, Class, Reply}), + io_server_loop(Kind, Port, Refs2, Out2, PortBuf); + %% stdin/stdout message forwarding + {message, To, Content} -> + peer_to_origin(Kind, Port, {message, To, Content}), + io_server_loop(Kind, Port, Refs, Out, PortBuf); + {'DOWN', CallerRef, _, _, Reason} -> + %% this is really not expected to happen, because "do_call" + %% catches all exceptions + {Seq, Refs3} = maps:take(CallerRef, Refs), + {CallerRef, Out3} = maps:take(Seq, Out), + peer_to_origin(Kind, Port, {reply, Seq, crash, Reason}), + io_server_loop(Kind, Port, Refs3, Out3, PortBuf); + {init, started} -> + notify_started(Kind, Port), + io_server_loop(Kind, Port, Refs, Out, PortBuf); + _Other -> + %% below, what is it? + io_server_loop(Kind, Port, Refs, Out, PortBuf) + end. + +handle_peer_alternative({io_reply, From, FromRef, Reply}, Refs, Out) -> + From ! {io_reply, FromRef, Reply}, + {Refs, Out}; +handle_peer_alternative({call, Seq, M, F, A}, Refs, Out) -> + CallerRef = do_call(Seq, M, F, A), + {Refs#{CallerRef => Seq}, Out#{Seq => CallerRef}}; +handle_peer_alternative({cast, M, F, A}, Refs, Out) -> + %% spawn a separate process to avoid blocking further RPC + spawn(fun () -> erlang:apply(M, F, A) end), + {Refs, Out}; +handle_peer_alternative({message, Dest, Message}, Refs, Out) -> + Dest ! Message, + {Refs, Out}. + +%% single port input message may contain multiple messages +handle_port_alternative(<>, Refs, Out) -> + Crc = erlang:crc32(Payload), %% assert + {NewRefs, NewOut} = handle_peer_alternative(binary_to_term(Payload), Refs, Out), + handle_port_alternative(Rest, NewRefs, NewOut); +handle_port_alternative(Rest, Refs, Out) -> + {Refs, Out, Rest}. + +do_call(Seq, M, F, A) -> + Proxy = self(), + {_, CallerRef} = + spawn_monitor( + fun () -> + %% catch all errors, otherwise emulator will log + %% ERROR REPORT when it is not expected + try + Proxy ! {reply, Seq, ok, erlang:apply(M, F, A)} + catch + Class:Reason:Stack -> + Proxy ! {reply, Seq, Class, {Reason, Stack}} + end + end), + CallerRef. diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl index 39f9cb2f4c13..e0fb9b6dfbef 100644 --- a/lib/stdlib/src/pool.erl +++ b/lib/stdlib/src/pool.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -103,6 +103,8 @@ pspawn(M, F, A) -> pspawn_link(M, F, A) -> spawn_link(get_node(), M, F, A). +-compile([{nowarn_deprecated_function,[{slave,start,3}]}]). + start_nodes([], _, _) -> []; start_nodes([Host|Tail], Name, Args) -> case slave:start(Host, Name, Args) of diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index 66438ef2245b..9c7235b95404 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -31,6 +31,7 @@ start_monitor/3, start_monitor/4, start_monitor/5, hibernate/3, init_ack/1, init_ack/2, + init_fail/2, init_fail/3, init_p/3,init_p/5,format/1,format/2,format/3,report_cb/2, initial_call/1, translate_initial_call/1, @@ -46,13 +47,33 @@ %%----------------------------------------------------------------------------- +%% This shall be spawn_option() -- monitor options and must be kept in sync +%% (with erlang:spawn_opt_options()) +%% -type start_spawn_option() :: 'link' | {'priority', erlang:priority_level()} - | {'max_heap_size', erlang:max_heap_size()} + | {'fullsweep_after', non_neg_integer()} | {'min_heap_size', non_neg_integer()} | {'min_bin_vheap_size', non_neg_integer()} - | {'fullsweep_after', non_neg_integer()} + | {'max_heap_size', erlang:max_heap_size()} | {'message_queue_data', erlang:message_queue_data() }. +%% and this macro is used to verify that there are no monitor options +%% which also needs to be kept in sync all kinds of monitor options +%% in erlang:spawn_opt_options(). +%% +-define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts), + Monitor = monitor, + case lists:member(Monitor, Opts) of + true -> + erlang:error(badarg, [M,F,A,T,Opts]); + false -> + case lists:keyfind(Monitor, 1, Opts) of + false -> + ok; + {Monitor, _} -> + erlang:error(badarg, [M,F,A,T,Opts]) + end + end). -type spawn_option() :: erlang:spawn_opt_option(). @@ -62,12 +83,6 @@ %%----------------------------------------------------------------------------- --define(VERIFY_NO_MONITOR_OPT(M, F, A, T, Opts), - case lists:member(monitor, Opts) of - true -> erlang:error(badarg, [M,F,A,T,Opts]); - false -> ok - end). - %%----------------------------------------------------------------------------- -spec spawn(Fun) -> pid() when @@ -259,6 +274,7 @@ exit_reason(exit, Reason, _Stacktrace) -> exit_reason(throw, Reason, Stacktrace) -> {{nocatch, Reason}, Stacktrace}. + -spec start(Module, Function, Args) -> Ret when Module :: module(), Function :: atom(), @@ -295,14 +311,20 @@ sync_start({Pid, Ref}, Timeout) -> {ack, Pid, Return} -> erlang:demonitor(Ref, [flush]), Return; + {nack, Pid, Return} -> + flush_EXIT(Pid), + _ = await_DOWN(Pid, Ref), + Return; {'DOWN', Ref, process, Pid, Reason} -> + flush_EXIT(Pid), {error, Reason} after Timeout -> - erlang:demonitor(Ref, [flush]), - kill_flush(Pid), + kill_flush_EXIT(Pid), + _ = await_DOWN(Pid, Ref), {error, timeout} end. + -spec start_link(Module, Function, Args) -> Ret when Module :: module(), Function :: atom(), @@ -320,7 +342,7 @@ start_link(M, F, A) when is_atom(M), is_atom(F), is_list(A) -> Ret :: term() | {error, Reason :: term()}. start_link(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) -> - sync_start_link(?MODULE:spawn_link(M, F, A), Timeout). + sync_start(?MODULE:spawn_opt(M, F, A, [link,monitor]), Timeout). -spec start_link(Module, Function, Args, Time, SpawnOpts) -> Ret when Module :: module(), @@ -332,18 +354,9 @@ start_link(M, F, A, Timeout) when is_atom(M), is_atom(F), is_list(A) -> start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) -> ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts), - sync_start_link(?MODULE:spawn_opt(M, F, A, [link|SpawnOpts]), Timeout). + sync_start( + ?MODULE:spawn_opt(M, F, A, [link,monitor|SpawnOpts]), Timeout). -sync_start_link(Pid, Timeout) -> - receive - {ack, Pid, Return} -> - Return; - {'EXIT', Pid, Reason} -> - {error, Reason} - after Timeout -> - kill_flush(Pid), - {error, timeout} - end. -spec start_monitor(Module, Function, Args) -> {Ret, Mon} when Module :: module(), @@ -379,29 +392,54 @@ start_monitor(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) -> ?VERIFY_NO_MONITOR_OPT(M, F, A, Timeout, SpawnOpts), - sync_start_monitor(?MODULE:spawn_opt(M, F, A, [monitor|SpawnOpts]), - Timeout). + sync_start_monitor( + ?MODULE:spawn_opt(M, F, A, [monitor|SpawnOpts]), Timeout). sync_start_monitor({Pid, Ref}, Timeout) -> receive {ack, Pid, Return} -> {Return, Ref}; + {nack, Pid, Return} -> + flush_EXIT(Pid), + self() ! await_DOWN(Pid, Ref), + {Return, Ref}; {'DOWN', Ref, process, Pid, Reason} = Down -> + flush_EXIT(Pid), self() ! Down, {{error, Reason}, Ref} after Timeout -> - kill_flush(Pid), + kill_flush_EXIT(Pid), + self() ! await_DOWN(Pid, Ref), {{error, timeout}, Ref} end. --spec kill_flush(Pid) -> 'ok' when - Pid :: pid(). -kill_flush(Pid) -> +%% We regard the existence of an {'EXIT', Pid, _} message +%% as proof enough that there was a link that fired and +%% we had process_flag(trap_exit, true), +%% so the message should be flushed. +%% It is the best we can do. +%% +%% After an unlink(Pid) an {'EXIT', Pid, _} link message +%% cannot arrive so receive after 0 will work, + +flush_EXIT(Pid) -> + unlink(Pid), + receive {'EXIT', Pid, _} -> ok after 0 -> ok end. + +kill_flush_EXIT(Pid) -> + %% unlink/1 has to be called before exit/2 + %% or we might be killed by the link unlink(Pid), exit(Pid, kill), - receive {'EXIT', Pid, _} -> ok after 0 -> ok end, - ok. + receive {'EXIT', Pid, _} -> ok after 0 -> ok end. + +await_DOWN(Pid, Ref) -> + receive + {'DOWN', Ref, process, Pid, _} = Down -> + Down + end. + -spec init_ack(Parent, Ret) -> 'ok' when Parent :: pid(), @@ -418,6 +456,27 @@ init_ack(Return) -> [Parent|_] = get('$ancestors'), init_ack(Parent, Return). +-spec init_fail(_, _, _) -> no_return(). +init_fail(Parent, Return, Exception) -> + _ = Parent ! {nack, self(), Return}, + case Exception of + {error, Reason} -> + erlang:error(Reason); + {exit, Reason} -> + erlang:exit(Reason); + {throw, Reason} -> + erlang:throw(Reason); + {Class, Reason, Stacktrace} -> + erlang:error( + erlang:raise(Class, Reason, Stacktrace), + [Parent, Return, Exception]) + end. + +-spec init_fail(_, _) -> no_return(). +init_fail(Return, Exception) -> + [Parent|_] = get('$ancestors'), + init_fail(Parent, Return, Exception). + %% ----------------------------------------------------- %% Fetch the initial call of a proc_lib spawned process. %% ----------------------------------------------------- @@ -1062,33 +1121,32 @@ stop(Process) -> Reason :: term(), Timeout :: timeout(). stop(Process, Reason, Timeout) -> - {Pid, Mref} = erlang:spawn_monitor(do_stop(Process, Reason)), + Mref = erlang:monitor(process, Process), + T0 = erlang:monotonic_time(millisecond), + RemainingTimeout = try + sys:terminate(Process, Reason, Timeout) + of + ok when Timeout =:= infinity -> + infinity; + ok -> + Timeout - (((erlang:monotonic_time(microsecond) + 999) div 1000) - T0) + catch + exit:{noproc, {sys, terminate, _}} -> + demonitor(Mref, [flush]), + exit(noproc); + exit:{timeout, {sys, terminate, _}} -> + demonitor(Mref, [flush]), + exit(timeout); + exit:Reason1 -> + demonitor(Mref, [flush]), + exit(Reason1) + end, receive {'DOWN', Mref, _, _, Reason} -> ok; - {'DOWN', Mref, _, _, {noproc,{sys,terminate,_}}} -> - exit(noproc); - {'DOWN', Mref, _, _, CrashReason} -> - exit(CrashReason) - after Timeout -> - exit(Pid, kill), - receive - {'DOWN', Mref, _, _, _} -> - exit(timeout) - end - end. - --spec do_stop(Process, Reason) -> Fun when - Process :: pid() | RegName | {RegName,node()}, - RegName :: atom(), - Reason :: term(), - Fun :: fun(() -> no_return()). -do_stop(Process, Reason) -> - fun() -> - Mref = erlang:monitor(process, Process), - ok = sys:terminate(Process, Reason, infinity), - receive - {'DOWN', Mref, _, _, ExitReason} -> - exit(ExitReason) - end + {'DOWN', Mref, _, _, Reason2} -> + exit(Reason2) + after RemainingTimeout -> + demonitor(Mref, [flush]), + exit(timeout) end. diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl index 8f25229cdd81..a1198a972a93 100644 --- a/lib/stdlib/src/proplists.erl +++ b/lib/stdlib/src/proplists.erl @@ -643,7 +643,7 @@ apply_stages(L, []) -> Rest :: [term()]. split(List, Keys) -> - {Store, Rest} = split(List, maps:from_list([{K, []} || K <- Keys]), []), + {Store, Rest} = split(List, #{K => [] || K <- Keys}, []), {[lists:reverse(map_get(K, Store)) || K <- Keys], lists:reverse(Rest)}. diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index 0b1d6c467e4d..fab7207d13f9 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -652,21 +652,20 @@ string_to_handle(Str, Options, Bindings) when is_list(Str) -> {ok, Tokens, _} -> ScanRes = case erl_eval:extended_parse_exprs(Tokens) of - {ok, [Expr0], SBs} -> - {ok, Expr0, SBs}; - {ok, _ExprList, _SBs} -> + {ok, [Expr0]} -> + {ok, Expr0}; + {ok, _ExprList} -> erlang:error(badarg, [Str, Options, Bindings]); E -> E end, case ScanRes of - {ok, Expr, XBs} -> - Bs1 = merge_binding_structs(Bindings, XBs), - case qlc_pt:transform_expression(Expr, Bs1) of + {ok, Expr} -> + case qlc_pt:transform_expression(Expr, Bindings) of {ok, {call, _, _QlcQ, Handle}} -> {value, QLC_lc, _} = - erl_eval:exprs(Handle, Bs1), + erl_eval:exprs(Handle, Bindings), O = #qlc_opt{unique = Unique, cache = Cache, max_lookup = MaxLookup, @@ -792,10 +791,6 @@ all_selections([{I,Cs} | ICs]) -> %%% Local functions %%% -merge_binding_structs(Bs1, Bs2) -> - lists:foldl(fun({N, V}, Bs) -> erl_eval:add_binding(N, V, Bs) - end, Bs1, erl_eval:bindings(Bs2)). - aux_name1(Name, N, AllNames) -> SN = name_suffix(Name, N), case gb_sets:is_member(SN, AllNames) of @@ -1208,9 +1203,7 @@ abstract1({table, TableDesc}, _NElements, _Depth, _A) -> true -> {ok, Tokens, _} = erl_scan:string(lists:flatten(TableDesc++"."), 1, [text]), - {ok, Es, Bs} = - erl_eval:extended_parse_exprs(Tokens), - [Expr] = erl_eval:subst_values_for_vars(Es, Bs), + {ok, [Expr]} = erl_eval:extended_parse_exprs(Tokens), special(Expr); false -> % abstract expression TableDesc @@ -1333,7 +1326,7 @@ abstr_term(PPR, Anno) when is_pid(PPR); is_port(PPR); is_reference(PPR) -> abstr_term(Map, Anno) when is_map(Map) -> {map,Anno, [{map_field_assoc,Anno,abstr_term(K, Anno),abstr_term(V, Anno)} || - {K,V} <- maps:to_list(Map)]}; + K := V <- Map]}; abstr_term(Simple, Anno) -> erl_parse:abstract(Simple, erl_anno:line(Anno)). diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl index 67ea0f8be4b4..82eb7b1df075 100644 --- a/lib/stdlib/src/queue.erl +++ b/lib/stdlib/src/queue.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -59,7 +59,7 @@ %% Creation, inspection and conversion %% O(1) --spec new() -> queue(). +-spec new() -> queue(none()). new() -> {[],[]}. %{RearList,FrontList} %% O(1) @@ -703,11 +703,11 @@ r2f([]) -> {[],[]}; r2f([_]=R) -> {[],R}; -r2f([X,Y]) -> - {[X],[Y]}; +r2f([Y,X]) -> + {[Y],[X]}; r2f(List) -> - {FF,RR} = lists:split(length(List) div 2 + 1, List), - {FF,lists:reverse(RR, [])}. + {RR,FF} = lists:split(length(List) div 2, List), + {RR,lists:reverse(FF, [])}. %% Move half of elements from F to R, if there are enough f2r([]) -> @@ -717,5 +717,5 @@ f2r([_]=F) -> f2r([X,Y]) -> {[Y],[X]}; f2r(List) -> - {FF,RR} = lists:split(length(List) div 2 + 1, List), + {FF,RR} = lists:split(length(List) div 2, List), {lists:reverse(RR, []),FF}. diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl index d5906d373034..9c0f3a5c4384 100644 --- a/lib/stdlib/src/rand.erl +++ b/lib/stdlib/src/rand.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015-2020. All Rights Reserved. +%% Copyright Ericsson AB 2015-2023. 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. @@ -36,6 +36,11 @@ normal/0, normal/2, normal_s/1, normal_s/3 ]). +%% Utilities +-export([exsp_next/1, exsp_jump/1, splitmix64_next/1, + mwc59/1, mwc59_value32/1, mwc59_value/1, mwc59_float/1, + mwc59_seed/0, mwc59_seed/1]). + %% Test, dev and internal -export([exro928_jump_2pow512/1, exro928_jump_2pow20/1, exro928_seed/1, exro928_next/1, exro928_next_state/1, @@ -44,10 +49,11 @@ %% Debug -export([make_float/3, float2str/1, bc64/1]). --compile({inline, [exs64_next/1, exsplus_next/1, exsss_next/1, +-compile({inline, [exs64_next/1, exsp_next/1, exsss_next/1, exs1024_next/1, exs1024_calc/2, exro928_next_state/4, exrop_next/1, exrop_next_s/2, + mwc59_value/1, get_52/1, normal_kiwi/1]}). -define(DEFAULT_ALG_HANDLER, exsss). @@ -88,7 +94,7 @@ %% This depends on the algorithm handler function -type alg_state() :: exsplus_state() | exro928_state() | exrop_state() | exs1024_state() | - exs64_state() | term(). + exs64_state() | dummy_state() | term(). %% This is the algorithm handling definition within this module, %% and the type to use for plugins. @@ -132,7 +138,8 @@ %% Algorithm state -type state() :: {alg_handler(), alg_state()}. -type builtin_alg() :: - exsss | exro928ss | exrop | exs1024s | exsp | exs64 | exsplus | exs1024. + exsss | exro928ss | exrop | exs1024s | exsp | exs64 | exsplus | + exs1024 | dummy. -type alg() :: builtin_alg() | atom(). -type export_state() :: {alg(), alg_state()}. -type seed() :: [integer()] | integer() | {integer(), integer(), integer()}. @@ -141,7 +148,9 @@ state/0, export_state/0, seed/0]). -export_type( [exsplus_state/0, exro928_state/0, exrop_state/0, exs1024_state/0, - exs64_state/0]). + exs64_state/0, mwc59_state/0, dummy_state/0]). +-export_type( + [uint58/0, uint64/0, splitmix64_state/0]). %% ===================================================================== %% Range macro and helper @@ -266,9 +275,12 @@ seed_s({Alg, AlgState}) when is_atom(Alg) -> {AlgHandler,_SeedFun} = mk_alg(Alg), {AlgHandler,AlgState}; seed_s(Alg) -> - seed_s(Alg, {erlang:phash2([{node(),self()}]), - erlang:system_time(), - erlang:unique_integer()}). + seed_s(Alg, default_seed()). + +default_seed() -> + {erlang:phash2([{node(),self()}]), + erlang:system_time(), + erlang:unique_integer()}. %% seed/2: seeds RNG with the algorithm and given values %% and returns the NEW state. @@ -582,6 +594,22 @@ bytes_r(N, AlgHandler, Next, R, Bits, WeakLowBits) -> Shift = Bits - GoodBits, bytes_r(N, AlgHandler, Next, R, <<>>, GoodBytes, GoodBits, Shift). %% +bytes_r(N0, AlgHandler, Next, R0, Bytes0, GoodBytes, GoodBits, Shift) + when (GoodBytes bsl 2) < N0 -> + %% Loop unroll 4 iterations + %% - gives about 25% shorter time for large binaries + {V1, R1} = Next(R0), + {V2, R2} = Next(R1), + {V3, R3} = Next(R2), + {V4, R4} = Next(R3), + Bytes1 = + <>, + N1 = N0 - (GoodBytes bsl 2), + bytes_r(N1, AlgHandler, Next, R4, Bytes1, GoodBytes, GoodBits, Shift); bytes_r(N0, AlgHandler, Next, R0, Bytes0, GoodBytes, GoodBits, Shift) when GoodBytes < N0 -> {V, R1} = Next(R0), @@ -679,11 +707,11 @@ mk_alg(exs64) -> {#{type=>exs64, max=>?MASK(64), next=>fun exs64_next/1}, fun exs64_seed/1}; mk_alg(exsplus) -> - {#{type=>exsplus, max=>?MASK(58), next=>fun exsplus_next/1, + {#{type=>exsplus, max=>?MASK(58), next=>fun exsp_next/1, jump=>fun exsplus_jump/1}, fun exsplus_seed/1}; mk_alg(exsp) -> - {#{type=>exsp, bits=>58, weak_low_bits=>1, next=>fun exsplus_next/1, + {#{type=>exsp, bits=>58, weak_low_bits=>1, next=>fun exsp_next/1, uniform=>fun exsp_uniform/1, uniform_n=>fun exsp_uniform/2, jump=>fun exsplus_jump/1}, fun exsplus_seed/1}; @@ -710,7 +738,12 @@ mk_alg(exro928ss) -> uniform=>fun exro928ss_uniform/1, uniform_n=>fun exro928ss_uniform/2, jump=>fun exro928_jump/1}, - fun exro928_seed/1}. + fun exro928_seed/1}; +mk_alg(dummy=Name) -> + {#{type=>Name, bits=>58, next=>fun dummy_next/1, + uniform=>fun dummy_uniform/1, + uniform_n=>fun dummy_uniform/2}, + fun dummy_seed/1}. %% ===================================================================== %% exs64 PRNG: Xorshift64* @@ -724,7 +757,7 @@ exs64_seed(L) when is_list(L) -> [R] = seed64_nz(1, L), R; exs64_seed(A) when is_integer(A) -> - [R] = seed64(1, ?MASK(64, A)), + [R] = seed64(1, A), R; %% %% Traditional integer triplet seed @@ -788,15 +821,15 @@ exsplus_seed(L) when is_list(L) -> [S0,S1] = seed58_nz(2, L), [S0|S1]; exsplus_seed(X) when is_integer(X) -> - [S0,S1] = seed58(2, ?MASK(64, X)), + [S0,S1] = seed58(2, X), [S0|S1]; %% %% Traditional integer triplet seed exsplus_seed({A1, A2, A3}) -> - {_, R1} = exsplus_next( + {_, R1} = exsp_next( [?MASK(58, (A1 * 4294967197) + 1)| ?MASK(58, (A2 * 4294967231) + 1)]), - {_, R2} = exsplus_next( + {_, R2} = exsp_next( [?MASK(58, (A3 * 4294967279) + 1)| tl(R1)]), R2. @@ -807,21 +840,21 @@ exsss_seed(L) when is_list(L) -> [S0,S1] = seed58_nz(2, L), [S0|S1]; exsss_seed(X) when is_integer(X) -> - [S0,S1] = seed58(2, ?MASK(64, X)), + [S0,S1] = seed58(2, X), [S0|S1]; %% %% Seed from traditional integer triple - mix into splitmix exsss_seed({A1, A2, A3}) -> - {_, X0} = seed58(?MASK(64, A1)), - {S0, X1} = seed58(?MASK(64, A2) bxor X0), - {S1, _} = seed58(?MASK(64, A3) bxor X1), + {_, X0} = seed58(A1), + {S0, X1} = seed58(A2 bxor X0), + {S1, _} = seed58(A3 bxor X1), [S0|S1]. %% Advance Xorshift116 state one step -define( exs_next(S0, S1, S1_b), begin - S1_b = S1 bxor ?BSL(58, S1, 24), + S1_b = ?MASK(58, S1) bxor ?BSL(58, S1, 24), S1_b bxor S0 bxor (S1_b bsr 11) bxor (S0 bsr 41) end). @@ -831,35 +864,38 @@ exsss_seed({A1, A2, A3}) -> %% The multiply by add shifted trick avoids creating bignums %% which improves performance significantly %% - V_a = ?MASK(58, S + ?BSL(58, S, 2)), % V_a = S * 5 - V_b = ?ROTL(58, V_a, 7), - ?MASK(58, V_b + ?BSL(58, V_b, 3)) % V_b * 9 + %% Scramble ** (all operations modulo word size) + %% ((S * 5) rotl 7) * 9 + %% + V_a = S + ?BSL(58, S, 2), % * 5 + V_b = ?BSL(58, V_a, 7) bor ?MASK(7, V_a bsr (58-7)), % rotl 7 + ?MASK(58, V_b + ?BSL(58, V_b, 3)) % * 9 end). --dialyzer({no_improper_lists, exsplus_next/1}). - %% Advance state and generate 58bit unsigned integer --spec exsplus_next(exsplus_state()) -> {uint58(), exsplus_state()}. -exsplus_next([S1|S0]) -> +%% +-dialyzer({no_improper_lists, exsp_next/1}). +-spec exsp_next(AlgState :: exsplus_state()) -> + {X :: uint58(), NewAlgState :: exsplus_state()}. +exsp_next([S1|S0]) -> %% Note: members s0 and s1 are swapped here - NewS1 = ?exs_next(S0, S1, S1_1), - {?MASK(58, S0 + NewS1), [S0|NewS1]}. -%% %% Note: members s0 and s1 are swapped here -%% S11 = S1 bxor ?BSL(58, S1, 24), -%% S12 = S11 bxor S0 bxor (S11 bsr 11) bxor (S0 bsr 41), -%% {?MASK(58, S0 + S12), [S0|S12]}. + S0_1 = ?MASK(58, S0), + NewS1 = ?exs_next(S0_1, S1, S1_b), + %% Scramble + (all operations modulo word size) + %% S0 + NewS1 + {?MASK(58, S0_1 + NewS1), [S0_1|NewS1]}. -dialyzer({no_improper_lists, exsss_next/1}). -spec exsss_next(exsplus_state()) -> {uint58(), exsplus_state()}. exsss_next([S1|S0]) -> %% Note: members s0 and s1 are swapped here - NewS1 = ?exs_next(S0, S1, S1_1), - {?scramble_starstar(S0, V_0, V_1), [S0|NewS1]}. -%% {?MASK(58, S0 + NewS1), [S0|NewS1]}. + S0_1 = ?MASK(58, S0), + NewS1 = ?exs_next(S0_1, S1, S1_b), + {?scramble_starstar(S0_1, V_1, V_2), [S0_1|NewS1]}. exsp_uniform({AlgHandler, R0}) -> - {I, R1} = exsplus_next(R0), + {I, R1} = exsp_next(R0), %% Waste the lowest bit since it is of lower %% randomness quality than the others {(I bsr (58-53)) * ?TWO_POW_MINUS53, {AlgHandler, R1}}. @@ -869,7 +905,7 @@ exsss_uniform({AlgHandler, R0}) -> {(I bsr (58-53)) * ?TWO_POW_MINUS53, {AlgHandler, R1}}. exsp_uniform(Range, {AlgHandler, R}) -> - {V, R1} = exsplus_next(R), + {V, R1} = exsp_next(R), MaxMinusRange = ?BIT(58) - Range, ?uniform_range(Range, AlgHandler, R1, V, MaxMinusRange, I). @@ -879,7 +915,7 @@ exsss_uniform(Range, {AlgHandler, R}) -> ?uniform_range(Range, AlgHandler, R1, V, MaxMinusRange, I). -%% This is the jump function for the exs* generators, +%% This is the jump function for the exs... generators, %% i.e the Xorshift116 generators, equivalent %% to 2^64 calls to next/1; it can be used to generate 2^52 %% non-overlapping subsequences for parallel computations. @@ -918,15 +954,21 @@ exsss_uniform(Range, {AlgHandler, R}) -> -spec exsplus_jump({alg_handler(), exsplus_state()}) -> {alg_handler(), exsplus_state()}. exsplus_jump({AlgHandler, S}) -> + {AlgHandler, exsp_jump(S)}. + +-dialyzer({no_improper_lists, exsp_jump/1}). +-spec exsp_jump(AlgState :: exsplus_state()) -> + NewAlgState :: exsplus_state(). +exsp_jump(S) -> {S1, AS1} = exsplus_jump(S, [0|0], ?JUMPCONST1, ?JUMPELEMLEN), {_, AS2} = exsplus_jump(S1, AS1, ?JUMPCONST2, ?JUMPELEMLEN), - {AlgHandler, AS2}. + AS2. -dialyzer({no_improper_lists, exsplus_jump/4}). exsplus_jump(S, AS, _, 0) -> {S, AS}; exsplus_jump(S, [AS0|AS1], J, N) -> - {_, NS} = exsplus_next(S), + {_, NS} = exsp_next(S), case ?MASK(1, J) of 1 -> [S0|S1] = S, @@ -946,7 +988,7 @@ exsplus_jump(S, [AS0|AS1], J, N) -> exs1024_seed(L) when is_list(L) -> {seed64_nz(16, L), []}; exs1024_seed(X) when is_integer(X) -> - {seed64(16, ?MASK(64, X)), []}; + {seed64(16, X), []}; %% %% Seed from traditional triple, remain backwards compatible exs1024_seed({A1, A2, A3}) -> @@ -1135,13 +1177,13 @@ exs1024_jump({L, RL}, AS, JL, J, N, TN) -> exro928_seed(L) when is_list(L) -> {seed58_nz(16, L), []}; exro928_seed(X) when is_integer(X) -> - {seed58(16, ?MASK(64, X)), []}; + {seed58(16, X), []}; %% %% Seed from traditional integer triple - mix into splitmix exro928_seed({A1, A2, A3}) -> - {S0, X0} = seed58(?MASK(64, A1)), - {S1, X1} = seed58(?MASK(64, A2) bxor X0), - {S2, X2} = seed58(?MASK(64, A3) bxor X1), + {S0, X0} = seed58(A1), + {S1, X1} = seed58(A2 bxor X0), + {S2, X2} = seed58(A3 bxor X1), {[S0,S1,S2|seed58(13, X2)], []}. @@ -1154,13 +1196,6 @@ exro928ss_next({[S15,S0|Ss], Rs}) -> %% const uint64_t result_starstar = rotl(s0 * S, R) * T; %% {?scramble_starstar(S0, V_0, V_1), SR}; -%% %% The multiply by add shifted trick avoids creating bignums -%% %% which improves performance significantly -%% %% -%% V0 = ?MASK(58, S0 + ?BSL(58, S0, 2)), % V0 = S0 * 5 -%% V1 = ?ROTL(58, V0, 7), -%% V = ?MASK(58, V1 + ?BSL(58, V1, 3)), % V = V1 * 9 -%% {V, SR}; exro928ss_next({[S15], Rs}) -> exro928ss_next({[S15|lists:reverse(Rs)], []}). @@ -1185,8 +1220,9 @@ exro928_next_state(Ss, Rs, S15, S0) -> %% NewS15: s[q] = rotl(s0, A) ^ s15 ^ (s15 << B); %% NewS0: s[p] = rotl(s15, C); %% - Q = S15 bxor S0, - NewS15 = ?ROTL(58, S0, 44) bxor Q bxor ?BSL(58, Q, 9), + S0_1 = ?MASK(58, S0), + Q = ?MASK(58, S15) bxor S0_1, + NewS15 = ?ROTL(58, S0_1, 44) bxor Q bxor ?BSL(58, Q, 9), NewS0 = ?ROTL(58, Q, 45), {[NewS0|Ss], [NewS15|Rs]}. @@ -1307,7 +1343,7 @@ exrop_seed(L) when is_list(L) -> [S0,S1] = seed58_nz(2, L), [S0|S1]; exrop_seed(X) when is_integer(X) -> - [S0,S1] = seed58(2, ?MASK(64, X)), + [S0,S1] = seed58(2, X), [S0|S1]; %% %% Traditional integer triplet seed @@ -1373,6 +1409,157 @@ exrop_jump([S__0|S__1] = _S, S0, S1, J, Js) -> exrop_jump(NewS, S0, S1, J bsr 1, Js) end. +%% ===================================================================== +%% dummy "PRNG": Benchmark dummy overhead reference +%% +%% As fast as possible - return something daft and update state; +%% to measure plug-in framework overhead. +%% +%% ===================================================================== + +-type dummy_state() :: uint58(). + +dummy_uniform(_Range, {AlgHandler,R}) -> + {1, {AlgHandler,(R bxor ?MASK(58))}}. % 1 is always in Range +dummy_next(R) -> + {R, R bxor ?MASK(58)}. +dummy_uniform({AlgHandler,R}) -> + {0.5, {AlgHandler,(R bxor ?MASK(58))}}. % Perfect mean value + +%% Serious looking seed, to avoid rand_SUITE seed test failure +%% +dummy_seed(L) when is_list(L) -> + case L of + [] -> + erlang:error(zero_seed); + [X] when is_integer(X) -> + ?MASK(58, X); + [X|_] when is_integer(X) -> + erlang:error(too_many_seed_integers); + [_|_] -> + erlang:error(non_integer_seed) + end; +dummy_seed(X) when is_integer(X) -> + {Z1, _} = splitmix64_next(X), + ?MASK(58, Z1); +dummy_seed({A1, A2, A3}) -> + {_, X1} = splitmix64_next(A1), + {_, X2} = splitmix64_next(A2 bxor X1), + {Z3, _} = splitmix64_next(A3 bxor X2), + ?MASK(58, Z3). + + +%% ===================================================================== +%% mcg58 PRNG: Multiply With Carry generator +%% +%% Parameters deduced in collaboration with +%% Prof. Sebastiano Vigna of the University of Milano. +%% +%% X = CX0 & (2^B - 1) % Low B bits - digit +%% C = CX0 >> B % High bits - carry +%% CX1 = A * X0 + C0 +%% +%% An MWC generator is an efficient alternative implementation of +%% a Multiplicative Congruential Generator, that is, the generator +%% CX1 = (CX0 * 2^B) rem P +%% where P is the safe prime (A * 2^B - 1), that generates +%% the same sequence in the reverse order. The generator +%% CX1 = (A * CX0) rem P +%% that uses the multiplicative inverse mod P is, indeed, +%% an exact equivalent to the corresponding MWC generator. +%% +%% An MWC generator has, due to the power of two multiplier +%% in the corresponding MCG, got known statistical weaknesses +%% in the spectral score for 3 dimensions, so it should be used +%% with a scrambler that hides the flaws. The scramblers +%% have been tried out in the PractRand and TestU01 frameworks +%% and settled for a single Xorshift to get B good bits, +%% and a double Xorshift to get all bits good enough. +%% +%% The chosen parameters are: +%% A = 16#7fa6502 +%% B = 32 +%% Single Xorshift: 8 +%% Double Xorshift: 4, 27 +%% +%% These parameters gives the MWC "digit" size 32 bits +%% which gives them theoretical statistical guarantees, +%% and keeps the state in 59 bits. +%% +%% The state should only be used to mask or rem out low bits. +%% The scramblers return 58 bits from which a number should +%% be masked or rem:ed out. +%% +%% ===================================================================== +-define(MWC59_A, (16#7fa6502)). +-define(MWC59_B, (32)). +-define(MWC59_P, ((?MWC59_A bsl ?MWC59_B) - 1)). + +-define(MWC59_XS, 8). +-define(MWC59_XS1, 4). +-define(MWC59_XS2, 27). + +-type mwc59_state() :: 1..?MWC59_P-1. + +-spec mwc59(CX0 :: mwc59_state()) -> CX1 :: mwc59_state(). +mwc59(CX) when is_integer(CX), 1 =< CX, CX < ?MWC59_P -> + C = CX bsr ?MWC59_B, + X = ?MASK(?MWC59_B, CX), + ?MWC59_A * X + C. + +%%% %% Verification by equivalent MCG generator +%%% mwc59_r(CX1) -> +%%% (CX1 bsl ?MWC59_B) rem ?MWC59_P. % Reverse +%%% %%% (CX1 * ?MWC59_A) rem ?MWC59_P. % Forward +%%% +%%% mwc59(CX0, 0) -> +%%% CX0; +%%% mwc59(CX0, N) -> +%%% CX1 = mwc59(CX0), +%%% CX0 = mwc59_r(CX1), +%%% mwc59(CX1, N - 1). + +-spec mwc59_value32(CX :: mwc59_state()) -> V :: 0..?MASK(32). +mwc59_value32(CX1) when is_integer(CX1), 1 =< CX1, CX1 < ?MWC59_P -> + CX = ?MASK(32, CX1), + CX bxor ?BSL(32, CX, ?MWC59_XS). + +-spec mwc59_value(CX :: mwc59_state()) -> V :: 0..?MASK(59). +mwc59_value(CX) when is_integer(CX), 1 =< CX, CX < ?MWC59_P -> + CX2 = CX bxor ?BSL(59, CX, ?MWC59_XS1), + CX2 bxor ?BSL(59, CX2, ?MWC59_XS2). + +-spec mwc59_float(CX :: mwc59_state()) -> V :: float(). +mwc59_float(CX1) when is_integer(CX1), 1 =< CX1, CX1 < ?MWC59_P -> + CX = ?MASK(53, CX1), + CX2 = CX bxor ?BSL(53, CX, ?MWC59_XS1), + CX3 = CX2 bxor ?BSL(53, CX2, ?MWC59_XS2), + CX3 * ?TWO_POW_MINUS53. + +-spec mwc59_seed() -> CX :: mwc59_state(). +mwc59_seed() -> + {A1, A2, A3} = default_seed(), + X1 = hash58(A1), + X2 = hash58(A2), + X3 = hash58(A3), + (X1 bxor X2 bxor X3) + 1. + +-spec mwc59_seed(S :: 0..?MASK(58)) -> CX :: mwc59_state(). +mwc59_seed(S) when is_integer(S), 0 =< S, S =< ?MASK(58) -> + hash58(S) + 1. + +%% Constants a'la SplitMix64, MurMurHash, etc. +%% Not that critical, just mix the bits using bijections +%% (reversible mappings) to not have any two user input seeds +%% become the same generator start state. +%% +hash58(X) -> + X0 = ?MASK(58, X), + X1 = ?MASK(58, (X0 bxor (X0 bsr 29)) * 16#351afd7ed558ccd), + X2 = ?MASK(58, (X1 bxor (X1 bsr 29)) * 16#0ceb9fe1a85ec53), + X2 bxor (X2 bsr 29). + + %% ===================================================================== %% Mask and fill state list, ensure not all zeros %% ===================================================================== @@ -1436,6 +1623,7 @@ seed64(X_0) -> ZX end. +%% ===================================================================== %% The SplitMix64 generator: %% %% uint64_t splitmix64_next() { @@ -1445,6 +1633,11 @@ seed64(X_0) -> %% return z ^ (z >> 31); %% } %% + +-type splitmix64_state() :: uint64(). + +-spec splitmix64_next(AlgState :: integer()) -> + {X :: uint64(), NewAlgState :: splitmix64_state()}. splitmix64_next(X_0) -> X = ?MASK(64, X_0 + 16#9e3779b97f4a7c15), Z_0 = ?MASK(64, (X bxor (X bsr 30)) * 16#bf58476d1ce4e5b9), @@ -1793,7 +1986,21 @@ bc64(V) -> ?BC(V, 64). %% Linear from high bit - higher probability first gives faster execution bc(V, B, N) when B =< V -> N; bc(V, B, N) -> bc(V, B bsr 1, N - 1). - + + +%%% %% Non-negative rem +%%% mod(Q, X) when 0 =< X, X < Q -> +%%% X; +%%% mod(Q, X) -> +%%% Y = X rem Q, +%%% if +%%% Y < 0 -> +%%% Y + Q; +%%% true -> +%%% Y +%%% end. + + make_float(S, E, M) -> <> = <>, F. diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index 863bbeb65205..0f1f9a137a5d 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -31,6 +31,8 @@ | bsr_anycrlf | bsr_unicode | no_start_optimize | ucp | never_utf. +-type replace_fun() :: fun((binary(), [binary()]) -> iodata() | unicode:charlist()). + %%% BIFs -export([internal_run/4]). @@ -353,7 +355,7 @@ compile_split(_,_) -> -spec replace(Subject, RE, Replacement) -> iodata() | unicode:charlist() when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata(), - Replacement :: iodata() | unicode:charlist(). + Replacement :: iodata() | unicode:charlist() | replace_fun(). replace(Subject,RE,Replacement) -> try @@ -366,7 +368,7 @@ replace(Subject,RE,Replacement) -> -spec replace(Subject, RE, Replacement, Options) -> iodata() | unicode:charlist() when Subject :: iodata() | unicode:charlist(), RE :: mp() | iodata() | unicode:charlist(), - Replacement :: iodata() | unicode:charlist(), + Replacement :: iodata() | unicode:charlist() | replace_fun(), Options :: [Option], Option :: anchored | global | notbol | noteol | notempty | notempty_atstart @@ -380,11 +382,11 @@ replace(Subject,RE,Replacement) -> replace(Subject,RE,Replacement,Options) -> try - {NewOpt,Convert} = process_repl_params(Options,iodata), - Unicode = check_for_unicode(RE, Options), - FlatSubject = to_binary(Subject, Unicode), - FlatReplacement = to_binary(Replacement, Unicode), - IoList = do_replace(FlatSubject,Subject,RE,FlatReplacement,NewOpt), + {NewOpt,Convert} = process_repl_params(Options,iodata), + Unicode = check_for_unicode(RE, Options), + FlatSubject = to_binary(Subject, Unicode), + Replacement1 = normalize_replacement(Replacement, Unicode), + IoList = do_replace(FlatSubject,Subject,RE,Replacement1,NewOpt), case Convert of iodata -> IoList; @@ -412,6 +414,10 @@ replace(Subject,RE,Replacement,Options) -> badarg_with_info([Subject,RE,Replacement,Options]) end. +normalize_replacement(Replacement, _Unicode) when is_function(Replacement, 2) -> + Replacement; +normalize_replacement(Replacement, Unicode) -> + to_binary(Replacement, Unicode). do_replace(FlatSubject,Subject,RE,Replacement,Options) -> case re:run(FlatSubject,RE,Options) of @@ -512,7 +518,9 @@ precomp_repl(<>) -> [<> | T0]; Other -> [<> | Other] - end. + end; +precomp_repl(Repl) when is_function(Repl) -> + Repl. @@ -540,6 +548,16 @@ do_mlist(Whole,Subject,Pos,Repl,[[{MPos,Count} | Sub] | Tail]) [NewData | do_mlist(Whole,Rest,Pos+EatLength,Repl,Tail)]. +do_replace(Subject, Repl, SubExprs0) when is_function(Repl) -> + All = binary:part(Subject, hd(SubExprs0)), + SubExprs1 = + [ if + Pos >= 0, Len > 0 -> + binary:part(Subject, Pos, Len); + true -> + <<>> + end || {Pos, Len} <- tl(SubExprs0) ], + Repl(All, SubExprs1); do_replace(_,[Bin],_) when is_binary(Bin) -> Bin; do_replace(Subject,Repl,SubExprs0) -> diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl index 2783ec11eb10..dccc6dcf3a07 100644 --- a/lib/stdlib/src/sets.erl +++ b/lib/stdlib/src/sets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -89,12 +89,12 @@ %%------------------------------------------------------------------------------ %% new() -> Set --spec new() -> set(). +-spec new() -> set(none()). new() -> Empty = mk_seg(?seg_size), #set{empty = Empty, segs = {Empty}}. --spec new([{version, 1..2}]) -> set(). +-spec new([{version, 1..2}]) -> set(none()). new([{version, 2}]) -> #{}; new(Opts) -> @@ -358,31 +358,51 @@ is_disjoint_1(Set, Iter) -> Set2 :: set(Element), Set3 :: set(Element). -subtract(#{}=S1, #{}=S2) -> - Next = maps:next(maps:iterator(S1)), - subtract_heuristic(Next, [], [], floor(map_size(S1) * 0.75), S1, S2); -subtract(S1, S2) -> - filter(fun (E) -> not is_element(E, S2) end, S1). +subtract(#{}=LHS, #{}=RHS) -> + LSize = map_size(LHS), + RSize = map_size(RHS), + + case RSize =< (LSize div 4) of + true -> + %% If we're guaranteed to keep more than 75% of the keys, it's + %% always cheaper to delete them one-by-one from the start. + Next = maps:next(maps:iterator(RHS)), + subtract_decided(Next, LHS, RHS); + false -> + %% We might delete more than 25% of the keys. Dynamically + %% transition to deleting elements one-by-one if we can determine + %% that we'll keep more than 75%. + KeepThreshold = (LSize * 3) div 4, + Next = maps:next(maps:iterator(LHS)), + subtract_heuristic(Next, [], [], KeepThreshold, LHS, RHS) + end; +subtract(LHS, RHS) -> + filter(fun (E) -> not is_element(E, RHS) end, LHS). -%% If we are keeping more than 75% of the keys, then it is -%% cheaper to delete them. Stop accumulating and start deleting. subtract_heuristic(Next, _Keep, Delete, 0, Acc, Reference) -> - subtract_decided(Next, remove_keys(Delete, Acc), Reference); -subtract_heuristic({Key, _Value, Iterator}, Keep, Delete, KeepCount, Acc, Reference) -> + %% We've kept more than 75% of the keys, transition to removing them + %% one-by-one. + subtract_decided(Next, remove_keys(Delete, Acc), Reference); +subtract_heuristic({Key, _Value, Iterator}, Keep, Delete, + KeepCount, Acc, Reference) -> Next = maps:next(Iterator), case Reference of - #{Key := _} -> - subtract_heuristic(Next, Keep, [Key | Delete], KeepCount, Acc, Reference); + #{ Key := _ } -> + subtract_heuristic(Next, Keep, [Key | Delete], + KeepCount, Acc, Reference); _ -> - subtract_heuristic(Next, [Key | Keep], Delete, KeepCount - 1, Acc, Reference) + subtract_heuristic(Next, [Key | Keep], Delete, + KeepCount - 1, Acc, Reference) end; subtract_heuristic(none, Keep, _Delete, _Count, _Acc, _Reference) -> maps:from_keys(Keep, ?VALUE). subtract_decided({Key, _Value, Iterator}, Acc, Reference) -> case Reference of - #{Key := _} -> - subtract_decided(maps:next(Iterator), maps:remove(Key, Acc), Reference); + #{ Key := _ } -> + subtract_decided(maps:next(Iterator), + maps:remove(Key, Acc), + Reference); _ -> subtract_decided(maps:next(Iterator), Acc, Reference) end; @@ -426,8 +446,10 @@ is_subset_1(Set, Iter) -> Acc1 :: Acc, AccIn :: Acc, AccOut :: Acc. -fold(F, Acc, #{}=D) -> fold_1(F, Acc, maps:iterator(D)); -fold(F, Acc, #set{}=D) -> fold_set(F, Acc, D). +fold(F, Acc, #{}=D) when is_function(F, 2)-> + fold_1(F, Acc, maps:iterator(D)); +fold(F, Acc, #set{}=D) when is_function(F, 2)-> + fold_set(F, Acc, D). fold_1(Fun, Acc, Iter) -> case maps:next(Iter) of @@ -443,21 +465,12 @@ fold_1(Fun, Acc, Iter) -> Pred :: fun((Element) -> boolean()), Set1 :: set(Element), Set2 :: set(Element). -filter(F, #{}=D) -> maps:from_keys(filter_1(F, maps:iterator(D)), ?VALUE); -filter(F, #set{}=D) -> filter_set(F, D). - -filter_1(Fun, Iter) -> - case maps:next(Iter) of - {K, _, NextIter} -> - case Fun(K) of - true -> - [K | filter_1(Fun, NextIter)]; - false -> - filter_1(Fun, NextIter) - end; - none -> - [] - end. +filter(F, #{}=D) when is_function(F, 1)-> + %% For this purpose, it is more efficient to use + %% maps:from_keys than a map comprehension. + maps:from_keys([K || K := _ <- D, F(K)], ?VALUE); +filter(F, #set{}=D) when is_function(F, 1)-> + filter_set(F, D). %% get_slot(Hashdb, Key) -> Slot. %% Get the slot. First hash on the new range, if we hit a bucket @@ -482,7 +495,7 @@ get_bucket(T, Slot) -> get_bucket_s(T#set.segs, Slot). %% implemented map and hash using fold but these should be faster. %% We hope! -fold_set(F, Acc, D) when is_function(F, 2) -> +fold_set(F, Acc, D) -> Segs = D#set.segs, fold_segs(F, Acc, Segs, tuple_size(Segs)). @@ -499,7 +512,7 @@ fold_bucket(F, Acc, [E|Bkt]) -> fold_bucket(F, F(E, Acc), Bkt); fold_bucket(_, Acc, []) -> Acc. -filter_set(F, D) when is_function(F, 1) -> +filter_set(F, D) -> Segs0 = tuple_to_list(D#set.segs), {Segs1,Fc} = filter_seg_list(F, Segs0, [], 0), maybe_contract(D#set{segs = list_to_tuple(Segs1)}, Fc). diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index 246e5ca5670a..af9aea26d651 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -20,10 +20,13 @@ -module(shell). -export([start/0, start/1, start/2, server/1, server/2, history/1, results/1]). --export([whereis_evaluator/0, whereis_evaluator/1]). +-export([get_state/0, get_function/2]). -export([start_restricted/1, stop_restricted/0]). --export([local_allowed/3, non_local_allowed/3]). +-export([local_func/0, local_func/1, local_allowed/3, non_local_allowed/3]). -export([catch_exception/1, prompt_func/1, strings/1]). +-export([start_interactive/0, start_interactive/1]). +-export([read_and_add_records/5]). +-export([whereis/0]). -define(LINEMAX, 30). -define(CHAR_MAX, 60). @@ -36,7 +39,11 @@ -define(RECORDS, shell_records). -define(MAXSIZE_HEAPBINARY, 64). - +-record(shell_state,{ + bindings = [], + records = [], + functions = [] + }). %% When used as the fallback restricted shell callback module... local_allowed(q,[],State) -> {true,State}; @@ -48,6 +55,24 @@ non_local_allowed({init,stop},[],State) -> non_local_allowed(_,_,State) -> {false,State}. +-spec start_interactive() -> ok | {error, already_started}. +start_interactive() -> + user_drv:start_shell(). +-spec start_interactive(noshell | {module(), atom(), [term()]}) -> + ok | {error, already_started}; + ({remote, string()}) -> + ok | {error, already_started | noconnection}; + ({node(), {module(), atom(), [term()]}} | {remote, string(), {module(), atom(), [term()]}}) -> + ok | {error, already_started | noconnection | badfile | nofile | on_load_failure}. +start_interactive({Node, {M, F, A}}) -> + user_drv:start_shell(#{ initial_shell => {Node, M, F ,A} }); +start_interactive(InitialShell) -> + user_drv:start_shell(#{ initial_shell => InitialShell }). + +-spec whereis() -> pid() | undefined. +whereis() -> + group:whereis_shell(). + -spec start() -> pid(). start() -> @@ -60,62 +85,16 @@ start(NoCtrlG) -> start(NoCtrlG, StartSync) -> _ = code:ensure_loaded(user_default), - spawn(fun() -> server(NoCtrlG, StartSync) end). - -%% Find the pid of the current evaluator process. --spec whereis_evaluator() -> 'undefined' | pid(). - -whereis_evaluator() -> - %% locate top group leader, always registered as user - %% can be implemented by group (normally) or user - %% (if oldshell or noshell) - case whereis(user) of - undefined -> - undefined; - User -> - %% get user_drv pid from group, or shell pid from user - case group:interfaces(User) of - [] -> % old- or noshell - case user:interfaces(User) of - [] -> - undefined; - [{shell,Shell}] -> - whereis_evaluator(Shell) - end; - [{user_drv,UserDrv}] -> - %% get current group pid from user_drv - case user_drv:interfaces(UserDrv) of - [] -> - undefined; - [{current_group,Group}] -> - %% get shell pid from group - GrIfs = group:interfaces(Group), - case lists:keyfind(shell, 1, GrIfs) of - {shell, Shell} -> - whereis_evaluator(Shell); - false -> - undefined - end - end - end - end. - --spec whereis_evaluator(pid()) -> 'undefined' | pid(). - -whereis_evaluator(Shell) -> - case process_info(Shell, dictionary) of - {dictionary,Dict} -> - case lists:keyfind(evaluator, 1, Dict) of - {_, Eval} when is_pid(Eval) -> - Eval; - _ -> - undefined - end; - _ -> - undefined - end. - -%% Call this function to start a user restricted shell + Ancestors = [self() | case get('$ancestors') of + undefined -> []; + Anc -> Anc + end], + spawn(fun() -> + put('$ancestors', Ancestors), + server(NoCtrlG, StartSync) + end). + +%% Call this function to start a user restricted shell %% from a normal shell session. -spec start_restricted(Module) -> {'error', Reason} when Module :: module(), @@ -123,16 +102,16 @@ whereis_evaluator(Shell) -> start_restricted(RShMod) when is_atom(RShMod) -> case code:ensure_loaded(RShMod) of - {module,RShMod} -> - application:set_env(stdlib, restricted_shell, RShMod), + {module,RShMod} -> + application:set_env(stdlib, restricted_shell, RShMod), exit(restricted_shell_started); - {error,What} = Error -> - error_logger:error_report( - lists:flatten( - io_lib:fwrite( - "Restricted shell module ~w not found: ~tp\n", - [RShMod,What]))), - Error + {error,What} = Error -> + error_logger:error_report( + lists:flatten( + io_lib:fwrite( + "Restricted shell module ~w not found: ~tp\n", + [RShMod,What]))), + Error end. -spec stop_restricted() -> no_return(). @@ -152,27 +131,27 @@ server(NoCtrlG, StartSync) -> %%% We subscribe with init to get a notification of when. %%% In older releases we didn't syncronize the shell with init, but let it -%%% start in parallell with other system processes. This was bad since +%%% start in parallell with other system processes. This was bad since %%% accessing the shell too early could interfere with the boot procedure. %%% Still, by means of a flag, we make it possible to start the shell the -%%% old way (for backwards compatibility reasons). This should however not +%%% old way (for backwards compatibility reasons). This should however not %%% be used unless for very special reasons necessary. -spec server(boolean()) -> 'terminated'. server(StartSync) -> case init:get_argument(async_shell_start) of - {ok,_} -> - ok; % no sync with init - _ when not StartSync -> - ok; - _ -> - case init:notify_when_started(self()) of - started -> - ok; - _ -> - init:wait_until_started() - end + {ok,_} -> + ok; % no sync with init + _ when not StartSync -> + ok; + _ -> + case init:notify_when_started(self()) of + started -> + ok; + _ -> + init:wait_until_started() + end end, %% Our spawner has fixed the process groups. Bs = erl_eval:new_bindings(), @@ -183,57 +162,71 @@ server(StartSync) -> RT = ets:new(?RECORDS, [public,ordered_set]), _ = initiate_records(Bs, RT), process_flag(trap_exit, true), + %% Store function definitions and types in an ets table. + FT = ets:new(user_functions, [public,ordered_set]), %% Check if we're in user restricted mode. - RShErr = - case application:get_env(stdlib, restricted_shell) of - {ok,RShMod} when is_atom(RShMod) -> - io:fwrite(<<"Restricted ">>, []), - case code:ensure_loaded(RShMod) of - {module,RShMod} -> - undefined; - {error,What} -> - {RShMod,What} - end; + RShErr = + case application:get_env(stdlib, restricted_shell) of + {ok,RShMod} when is_atom(RShMod) -> + io:fwrite(<<"Restricted ">>, []), + case code:ensure_loaded(RShMod) of + {module,RShMod} -> + undefined; + {error,What} -> + {RShMod,What} + end; {ok, Term} -> {Term,not_an_atom}; - undefined -> - undefined - end, - - case get(no_control_g) of - true -> - io:fwrite(<<"Eshell V~s\n">>, [erlang:system_info(version)]); - _undefined_or_false -> - io:fwrite(<<"Eshell V~s (abort with ^G)\n">>, - [erlang:system_info(version)]) + undefined -> + undefined + end, + + JCL = + case get(no_control_g) of + true -> " (type help(). for help)"; + _ -> " (press Ctrl+G to abort, type help(). for help)" + end, + DefaultSessionSlogan = + io_lib:format(<<"Eshell V~s">>, [erlang:system_info(version)]), + SessionSlogan = + case application:get_env(stdlib, shell_session_slogan, DefaultSessionSlogan) of + SloganFun when is_function(SloganFun, 0) -> + SloganFun(); + Slogan -> + Slogan + end, + try + io:fwrite("~ts~ts\n",[unicode:characters_to_list(SessionSlogan),JCL]) + catch _:_ -> + io:fwrite("Warning! The slogan \"~p\" could not be printed.\n",[SessionSlogan]) end, erase(no_control_g), case RShErr of - undefined -> + undefined -> ok; - {RShMod2,What2} -> + {RShMod2,What2} -> io:fwrite( - ("Warning! Restricted shell module ~w not found: ~tp.\n" - "Only the commands q() and init:stop() will be allowed!\n"), + ("Warning! Restricted shell module ~w not found: ~tp.\n" + "Only the commands q() and init:stop() will be allowed!\n"), [RShMod2,What2]), application:set_env(stdlib, restricted_shell, ?MODULE) end, {History,Results} = check_and_get_history_and_results(), - server_loop(0, start_eval(Bs, RT, []), Bs, RT, [], History, Results). + server_loop(0, start_eval(Bs, RT, FT, []), Bs, RT, FT, [], History, Results). -server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) -> +server_loop(N0, Eval_0, Bs00, RT, FT, Ds00, History0, Results0) -> N = N0 + 1, - {Eval_1,Bs0,Ds0,Prompt} = prompt(N, Eval_0, Bs00, RT, Ds00), - {Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, Ds0), - case Res of - {ok,Es0,XBs} -> - Es1 = erl_eval:subst_values_for_vars(Es0, XBs), - case expand_hist(Es1, N) of + {Eval_1,Bs0,Ds0,Prompt} = prompt(N, Eval_0, Bs00, RT, FT, Ds00), + {Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, FT, Ds0), + + case Res of + {ok,Es0} -> + case expand_hist(Es0, N) of {ok,Es} -> - {V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, Ds0, cmd), + {V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, FT, Ds0, cmd), {History,Results} = check_and_get_history_and_results(), add_cmd(N, Es, V), HB1 = del_cmd(command, N - History, N - History0, false), @@ -244,43 +237,88 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) -> if HB -> garb(self()); + Results < Results0 -> + garb(self()); true -> ok end, - server_loop(N, Eval, Bs, RT, Ds, History, Results); + server_loop(N, Eval, Bs, RT, FT, Ds, History, Results); {error,E} -> fwrite_severity(benign, <<"~ts">>, [E]), - server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0) + server_loop(N0, Eval0, Bs0, RT, FT, Ds0, History0, Results0) end; - {error,{Location,Mod,What}} -> + {error,{Location,Mod,What}} -> fwrite_severity(benign, <<"~s: ~ts">>, [pos(Location), Mod:format_error(What)]), - server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0); - {error,terminated} -> %Io process terminated - exit(Eval0, kill), - terminated; - {error,interrupted} -> %Io process interrupted us - exit(Eval0, kill), - {_,Eval,_,_} = shell_rep(Eval0, Bs0, RT, Ds0), - server_loop(N0, Eval, Bs0, RT, Ds0, History0, Results0); - {error,tokens} -> %Most probably character > 255 - fwrite_severity(benign, <<"~w: Invalid tokens.">>, + server_loop(N0, Eval0, Bs0, RT, FT, Ds0, History0, Results0); + {error,terminated} -> %Io process terminated + exit(Eval0, kill), + terminated; + {error,interrupted} -> %Io process interrupted us + exit(Eval0, kill), + {_,Eval,_,_} = shell_rep(Eval0, Bs0, RT, FT, Ds0), + server_loop(N0, Eval, Bs0, RT, FT, Ds0, History0, Results0); + {error,tokens} -> %Most probably character > 255 + fwrite_severity(benign, <<"~w: Invalid tokens.">>, [N]), - server_loop(N0, Eval0, Bs0, RT, Ds0, History0, Results0); - eof -> + server_loop(N0, Eval0, Bs0, RT, FT, Ds0, History0, Results0); + eof -> fwrite_severity(fatal, <<"Terminating erlang (~w)">>, [node()]), - halt() + halt() end. -get_command(Prompt, Eval, Bs, RT, Ds) -> +get_command(Prompt, Eval, Bs, RT, FT, Ds) -> + Ancestors = [self() | get('$ancestors')], + ResWordFun = fun erl_scan:reserved_word/1, Parse = fun() -> + put('$ancestors', Ancestors), exit( case - io:scan_erl_exprs(group_leader(), Prompt, {1,1}, [text]) + io:scan_erl_exprs(group_leader(), Prompt, {1,1}, + [text,{reserved_word_fun,ResWordFun}]) of {ok,Toks,_EndPos} -> - erl_eval:extended_parse_exprs(Toks); + %% NOTE: we can handle function definitions, records and soon type declarations + %% but this cannot be handled by the function which only expects erl_parse:abstract_expressions() + %% for now just pattern match against those types and pass the string to shell local func. + case Toks of + [{'-', _}, {atom, _, Atom}|_] -> + SpecialCase = fun(LocalFunc) -> + FakeLine = begin + case erl_parse:parse_form(Toks) of + {ok, Def} -> lists:flatten(erl_pp:form(Def)); + E -> + exit(E) + end + end, + {done, {ok, FakeResult, _}, _} = erl_scan:tokens( + [], atom_to_list(LocalFunc) ++ "(\""++FakeLine++"\").\n", + {1,1}, [text,{reserved_word_fun,fun erl_scan:reserved_word/1}]), + erl_eval:extended_parse_exprs(FakeResult) + end, + case Atom of + record -> SpecialCase(rd); + spec -> SpecialCase(ft); + type -> SpecialCase(td) + end; + [{atom, _, FunName}, {'(', _}|_] -> + case erl_parse:parse_form(Toks) of + {ok, FunDef} -> + case {edlin_expand:shell_default_or_bif(atom_to_list(FunName)), shell:local_func(FunName)} of + {"user_defined", false} -> + FakeLine =reconstruct(FunDef, FunName), + {done, {ok, FakeResult, _}, _} = erl_scan:tokens( + [], "fd("++ atom_to_list(FunName) ++ ", " ++ FakeLine ++ ").\n", + {1,1}, [text,{reserved_word_fun,fun erl_scan:reserved_word/1}]), + erl_eval:extended_parse_exprs(FakeResult); + _ -> erl_eval:extended_parse_exprs(Toks) + end; + _ -> erl_eval:extended_parse_exprs(Toks) + end; + _ -> + erl_eval:extended_parse_exprs(Toks) + end; {eof,_EndPos} -> eof; {error,ErrorInfo,_EndPos} -> @@ -295,30 +333,62 @@ get_command(Prompt, Eval, Bs, RT, Ds) -> Else -> Else end - ) + ) end, Pid = spawn_link(Parse), - get_command1(Pid, Eval, Bs, RT, Ds). - -get_command1(Pid, Eval, Bs, RT, Ds) -> + get_command1(Pid, Eval, Bs, RT, FT, Ds). + +reconstruct(Fun, Name) -> + lists:flatten(erl_pp:expr(reconstruct1(Fun, Name))). +reconstruct1({function, Anno, Name, Arity, Clauses}, Name) -> + {named_fun, Anno, 'RecursiveFuncVar', reconstruct1(Clauses, Name, Arity)}. +reconstruct1([{call, Anno, {atom, Anno1, Name}, Args}|Body], Name, Arity) when length(Args) =:= Arity -> + [{call, Anno, {var, Anno1, 'RecursiveFuncVar'}, reconstruct1(Args, Name, Arity)}| reconstruct1(Body, Name, Arity)]; +reconstruct1([{call, Anno, {atom, Anno1, Name}, Args}|Body], Name, Arity) -> % arity not the same + [{call, Anno, {remote, Anno1, {atom, Anno1, shell_default}, {atom, Anno1, Name}}, reconstruct1(Args, Name, Arity)}| + reconstruct1(Body, Name, Arity)]; +reconstruct1([{call, Anno, {atom, Anno1, Fun}, Args}|Body], Name, Arity) -> % Name not the same + case {edlin_expand:shell_default_or_bif(atom_to_list(Fun)), shell:local_func(Fun)} of + {"user_defined", false} -> + [{call, Anno, {remote, Anno1, {atom, Anno1, shell_default}, {atom, Anno1, Fun}}, reconstruct1(Args, Name, Arity)}| + reconstruct1(Body, Name, Arity)]; + {"shell_default", false} -> + [{call, Anno, {remote, Anno1, {atom, Anno1, shell_default}, {atom, Anno1, Fun}}, reconstruct1(Args, Name, Arity)}| reconstruct1(Body, Name, Arity)]; + {"erlang", false} -> + [{call, Anno, {remote, Anno1, {atom, Anno1, erlang}, {atom, Anno1, Fun}}, reconstruct1(Args, Name, Arity)}| reconstruct1(Body, Name, Arity)]; + {_, true} -> + [{call, Anno, {atom, Anno1, Fun}, reconstruct1(Args, Name, Arity)}| reconstruct1(Body, Name, Arity)] + end; +reconstruct1([E|Body], Name, Arity) when is_tuple(E) -> + [list_to_tuple(reconstruct1(tuple_to_list(E), Name, Arity))|reconstruct1(Body, Name, Arity)]; +reconstruct1([E|Body], Name, Arity) when is_list(E) -> + [reconstruct1(E, Name, Arity)|reconstruct1(Body, Name, Arity)]; +reconstruct1([E|Body], Name, Arity) -> + [E|reconstruct1(Body, Name, Arity)]; +reconstruct1([], _, _) -> []. + +get_command1(Pid, Eval, Bs, RT, FT, Ds) -> receive - {'EXIT', Pid, Res} -> - {Res, Eval}; - {'EXIT', Eval, {Reason,Stacktrace}} -> + {shell_state, From} -> + From ! {shell_state, Bs, RT, FT}, + get_command1(Pid, Eval, Bs, RT, FT, Ds); + {'EXIT', Pid, Res} -> + {Res, Eval}; + {'EXIT', Eval, {Reason,Stacktrace}} -> report_exception(error, {Reason,Stacktrace}, RT), - get_command1(Pid, start_eval(Bs, RT, Ds), Bs, RT, Ds); - {'EXIT', Eval, Reason} -> + get_command1(Pid, start_eval(Bs, RT, FT, Ds), Bs, RT, FT, Ds); + {'EXIT', Eval, Reason} -> report_exception(error, {Reason,[]}, RT), - get_command1(Pid, start_eval(Bs, RT, Ds), Bs, RT, Ds) + get_command1(Pid, start_eval(Bs, RT, FT, Ds), Bs, RT, FT, Ds) end. -prompt(N, Eval0, Bs0, RT, Ds0) -> +prompt(N, Eval0, Bs0, RT, FT, Ds0) -> case get_prompt_func() of {M,F} -> - L = [{history,N}], A = erl_anno:new(1), - C = {call,A,{remote,A,{atom,A,M},{atom,A,F}},[{value,A,L}]}, - {V,Eval,Bs,Ds} = shell_cmd([C], Eval0, Bs0, RT, Ds0, pmt), + L = {cons,A,{tuple,A,[{atom,A,history},{integer,A,N}]},{nil,A}}, + C = {call,A,{remote,A,{atom,A,M},{atom,A,F}},[L]}, + {V,Eval,Bs,Ds} = shell_cmd([C], Eval0, Bs0, RT, FT, Ds0, pmt), {Eval,Bs,Ds,case V of {pmt,Val} -> Val; @@ -331,15 +401,13 @@ prompt(N, Eval0, Bs0, RT, Ds0) -> end. get_prompt_func() -> - case application:get_env(stdlib, shell_prompt_func) of - {ok,{M,F}=PromptFunc} when is_atom(M), is_atom(F) -> + case application:get_env(stdlib, shell_prompt_func, default) of + {M,F}=PromptFunc when is_atom(M), is_atom(F) -> PromptFunc; - {ok,default=Default} -> + default=Default -> Default; - {ok,Term} -> + Term -> bad_prompt_func(Term), - default; - undefined -> default end. @@ -350,8 +418,8 @@ default_prompt(N) -> %% Don't bother flattening the list irrespective of what the %% I/O-protocol states. case is_alive() of - true -> io_lib:format(<<"(~s)~w> ">>, [node(), N]); - false -> io_lib:format(<<"~w> ">>, [N]) + true -> io_lib:format(<<"(~s)~w> ">>, [node(), N]); + false -> io_lib:format(<<"~w> ">>, [N]) end. %% expand_hist(Expressions, CommandNumber) @@ -390,7 +458,7 @@ expand_expr({record_field,A,R,Name,F}, C) -> {record_field,A,expand_expr(R, C),Name,expand_expr(F, C)}; expand_expr({record,A,R,Name,Ups}, C) -> {record,A,expand_expr(R, C),Name,expand_fields(Ups, C)}; -expand_expr({record_field,A,R,F}, C) -> %This is really illegal! +expand_expr({record_field,A,R,F}, C) -> %This is really illegal! {record_field,A,expand_expr(R, C),expand_expr(F, C)}; expand_expr({block,A,Es}, C) -> {block,A,expand_exprs(Es, C)}; @@ -408,18 +476,18 @@ expand_expr({'receive',A,Cs,To,ToEs}, C) -> expand_expr({call,A,{atom,_,e},[N]}, C) -> case get_cmd(N, C) of {undefined,_,_} -> - no_command(N); - {[Ce],_V,_CommandN} -> - Ce; - {Ces,_V,_CommandN} when is_list(Ces) -> - {block,A,Ces} + no_command(N); + {[Ce],_V,_CommandN} -> + Ce; + {Ces,_V,_CommandN} when is_list(Ces) -> + {block,A,Ces} end; -expand_expr({call,_A,{atom,_,v},[N]}, C) -> +expand_expr({call,CA,{atom,VA,v},[N]}, C) -> case get_cmd(N, C) of - {_,undefined,_} -> - no_command(N); - {Ces,V,CommandN} when is_list(Ces) -> - {value,erl_anno:new(CommandN),V} + {undefined,_,_} -> + no_command(N); + {Ces,_V,CommandN} when is_list(Ces) -> + {call,CA,{atom,VA,v},[{integer,VA,CommandN}]} end; expand_expr({call,A,F,Args}, C) -> {call,A,expand_expr(F, C),expand_exprs(Args, C)}; @@ -442,7 +510,8 @@ expand_expr({clause,A,H,G,B}, C) -> {clause,A,H, G, expand_exprs(B, C)}; expand_expr({bin,A,Fs}, C) -> {bin,A,expand_bin_elements(Fs, C)}; -expand_expr(E, _C) -> % Constants. + %expand_expr({'-'}) +expand_expr(E, _C) -> % Constants. E. expand_cs([{clause,A,P,G,B}|Cs], C) -> @@ -486,9 +555,9 @@ getc(N) -> get_cmd(Num, C) -> case catch erl_eval:expr(Num, erl_eval:new_bindings()) of - {value,N,_} when N < 0 -> getc(C+N); - {value,N,_} -> getc(N); - _Other -> {undefined,undefined,undefined} + {value,N,_} when N < 0 -> getc(C+N); + {value,N,_} -> getc(N); + _Other -> {undefined,undefined,undefined} end. del_cmd(_Type, N, N0, HasBin) when N < N0 -> @@ -519,58 +588,81 @@ has_bin(T, I) -> has_bin(element(I, T)), has_bin(T, I - 1). +get_state() -> + whereis() ! {shell_state, self()}, + receive + {shell_state, Bs, RT, FT} -> + #shell_state{bindings = Bs, records = ets:tab2list(RT), functions = ets:tab2list(FT)} + end. + +get_function(Func, Arity) -> + {shell_state, _Bs, _RT, FT} = get_state(), + try + {value, {_, Fun}} = lists:keysearch({function, {shell_default,Func,Arity}}, 1, FT), + Fun + catch _:_ -> + undefined + end. + %% shell_cmd(Sequence, Evaluator, Bindings, RecordTable, Dictionary, What) %% shell_rep(Evaluator, Bindings, RecordTable, Dictionary) -> -%% {Value,Evaluator,Bindings,Dictionary} +%% {Value,Evaluator,Bindings,Dictionary} %% Send a command to the evaluator and wait for the reply. Start a new %% evaluator if necessary. %% What = pmt | cmd. When evaluating a prompt ('pmt') the evaluated value %% must not be displayed, and it has to be returned. -shell_cmd(Es, Eval, Bs, RT, Ds, W) -> +shell_cmd(Es, Eval, Bs, RT, FT, Ds, W) -> Eval ! {shell_cmd,self(),{eval,Es}, W}, - shell_rep(Eval, Bs, RT, Ds). + shell_rep(Eval, Bs, RT, FT, Ds). -shell_rep(Ev, Bs0, RT, Ds0) -> +shell_rep(Ev, Bs0, RT, FT, Ds0) -> receive - {shell_rep,Ev,{value,V,Bs,Ds}} -> - {V,Ev,Bs,Ds}; + {shell_rep,Ev,{value,V,Bs,Ds}} -> + {V,Ev,Bs,Ds}; {shell_rep,Ev,{command_error,{Location,M,Error}}} -> fwrite_severity(benign, <<"~s: ~ts">>, [pos(Location), M:format_error(Error)]), {{'EXIT',Error},Ev,Bs0,Ds0}; - {shell_req,Ev,get_cmd} -> - Ev ! {shell_rep,self(),get()}, - shell_rep(Ev, Bs0, RT, Ds0); - {shell_req,Ev,exit} -> - Ev ! {shell_rep,self(),exit}, - exit(normal); - {shell_req,Ev,{update_dict,Ds}} -> % Update dictionary - Ev ! {shell_rep,self(),ok}, - shell_rep(Ev, Bs0, RT, Ds); + {shell_req,Ev,{get_cmd,N}} -> + Ev ! {shell_rep,self(),getc(N)}, + shell_rep(Ev, Bs0, RT, FT, Ds0); + {shell_req,Ev,get_cmd} -> + Ev ! {shell_rep,self(),get()}, + shell_rep(Ev, Bs0, RT, FT, Ds0); + {shell_req,Ev,exit} -> + Ev ! {shell_rep,self(),exit}, + exit(normal); + {shell_req,Ev,{update_dict,Ds}} -> % Update dictionary + Ev ! {shell_rep,self(),ok}, + shell_rep(Ev, Bs0, RT, FT, Ds); + {shell_state, From} -> + From ! {shell_state, Bs0, RT, FT}, + shell_rep(Ev, Bs0, RT, FT, Ds0); {ev_exit,{Ev,Class,Reason0}} -> % It has exited unnaturally receive {'EXIT',Ev,normal} -> ok end, - report_exception(Class, Reason0, RT), + report_exception(Class, Reason0, RT), Reason = nocatch(Class, Reason0), - {{'EXIT',Reason},start_eval(Bs0, RT, Ds0), Bs0, Ds0}; + {{'EXIT',Reason},start_eval(Bs0, RT, FT, Ds0), Bs0, Ds0}; {ev_caught,{Ev,Class,Reason0}} -> % catch_exception is in effect - report_exception(Class, benign, Reason0, RT), + report_exception(Class, benign, Reason0, RT), Reason = nocatch(Class, Reason0), {{'EXIT',Reason},Ev,Bs0,Ds0}; - {'EXIT',_Id,interrupt} -> % Someone interrupted us - exit(Ev, kill), - shell_rep(Ev, Bs0, RT, Ds0); + {'EXIT',_Id,interrupt} -> % Someone interrupted us + exit(Ev, kill), + shell_rep(Ev, Bs0, RT, FT, Ds0); {'EXIT',Ev,{Reason,Stacktrace}} -> report_exception(exit, {Reason,Stacktrace}, RT), - {{'EXIT',Reason},start_eval(Bs0, RT, Ds0), Bs0, Ds0}; + {{'EXIT',Reason},start_eval(Bs0, RT, FT, Ds0), Bs0, Ds0}; {'EXIT',Ev,Reason} -> report_exception(exit, {Reason,[]}, RT), - {{'EXIT',Reason},start_eval(Bs0, RT, Ds0), Bs0, Ds0}; - {'EXIT',_Id,R} -> - exit(Ev, R), - exit(R); - _Other -> % Ignore everything else - shell_rep(Ev, Bs0, RT, Ds0) + {{'EXIT',Reason},start_eval(Bs0, RT, FT, Ds0), Bs0, Ds0}; + {'EXIT',_Id,R} -> + exit(Ev, R), + exit(R); + _Other -> % Ignore everything else + io:format("Throwing ~p~n", [_Other]), + shell_rep(Ev, Bs0, RT, FT, Ds0) end. nocatch(throw, {Term,Stack}) -> @@ -594,9 +686,13 @@ report_exception(Class, Severity, {Reason,Stacktrace}, RT) -> {put_chars, unicode, Str}, nl]). -start_eval(Bs, RT, Ds) -> +start_eval(Bs, RT, FT, Ds) -> Self = self(), - Eval = spawn_link(fun() -> evaluator(Self, Bs, RT, Ds) end), + Ancestors = [self() | get('$ancestors')], + Eval = spawn_link(fun() -> + put('$ancestors', Ancestors), + evaluator(Self, Bs, RT, FT, Ds) + end), put(evaluator, Eval), Eval. @@ -604,45 +700,45 @@ start_eval(Bs, RT, Ds) -> %% Evaluate expressions from the shell. Use the "old" variable bindings %% and dictionary. -evaluator(Shell, Bs, RT, Ds) -> +evaluator(Shell, Bs, RT, FT, Ds) -> init_dict(Ds), case application:get_env(stdlib, restricted_shell) of - undefined -> - eval_loop(Shell, Bs, RT); - {ok,RShMod} -> - case get(restricted_shell_state) of - undefined -> put(restricted_shell_state, []); - _ -> ok - end, - put(restricted_expr_state, []), - restricted_eval_loop(Shell, Bs, RT, RShMod) + undefined -> + eval_loop(Shell, Bs, RT, FT); + {ok,RShMod} -> + case get(restricted_shell_state) of + undefined -> put(restricted_shell_state, []); + _ -> ok + end, + put(restricted_expr_state, []), + restricted_eval_loop(Shell, Bs, RT, FT, RShMod) end. -eval_loop(Shell, Bs0, RT) -> +eval_loop(Shell, Bs0, RT, FT) -> receive - {shell_cmd,Shell,{eval,Es},W} -> - Ef = {value, + {shell_cmd,Shell,{eval,Es},W} -> + Ef = {value, fun(MForFun, As) -> apply_fun(MForFun, As, Shell) end}, - Lf = local_func_handler(Shell, RT, Ef), + Lf = local_func_handler(Shell, RT, FT, Ef), Bs = eval_exprs(Es, Shell, Bs0, RT, Lf, Ef, W), - eval_loop(Shell, Bs, RT) + eval_loop(Shell, Bs, RT, FT) end. -restricted_eval_loop(Shell, Bs0, RT, RShMod) -> +restricted_eval_loop(Shell, Bs0, RT, FT, RShMod) -> receive - {shell_cmd,Shell,{eval,Es}, W} -> - {LFH,NLFH} = restrict_handlers(RShMod, Shell, RT), + {shell_cmd,Shell,{eval,Es}, W} -> + {LFH,NLFH} = restrict_handlers(RShMod, Shell, RT, FT), put(restricted_expr_state, []), Bs = eval_exprs(Es, Shell, Bs0, RT, {eval,LFH}, {value,NLFH}, W), - restricted_eval_loop(Shell, Bs, RT, RShMod) + restricted_eval_loop(Shell, Bs, RT, FT, RShMod) end. eval_exprs(Es, Shell, Bs0, RT, Lf, Ef, W) -> - try + try {R,Bs2} = exprs(Es, Bs0, RT, Lf, Ef, W), Shell ! {shell_rep,self(),R}, Bs2 - catch + catch exit:normal -> exit(normal); Class:Reason:Stacktrace -> @@ -667,8 +763,8 @@ do_catch(exit, restricted_shell_stopped) -> do_catch(exit, restricted_shell_started) -> false; do_catch(_Class, _Reason) -> - case application:get_env(stdlib, shell_catch_exception) of - {ok, true} -> + case application:get_env(stdlib, shell_catch_exception, false) of + true -> true; _ -> false @@ -699,14 +795,14 @@ exprs([E0|Es], Bs1, RT, Lf, Ef, Bs0, W) -> W =:= pmt -> {W,V0}; true -> case result_will_be_saved() of - true -> V0; - false -> - erlang:garbage_collect(), - ignored - end + true -> V0; + false -> + erlang:garbage_collect(), + ignored + end end, {{value,V,Bs,get()},Bs}; - true -> + true -> exprs(Es, Bs, RT, Lf, Ef, Bs0, W) end; {error,Error} -> @@ -729,7 +825,7 @@ used_record_defs(E, RT) -> %% Be careful to return a list where used records come before %% records that use them. The linter wants them ordered that way. UR = case used_records(E, [], RT, []) of - [] -> + [] -> []; L0 -> L1 = lists:zip(L0, lists:seq(1, length(L0))), @@ -777,7 +873,7 @@ used_records({call,_,{atom,_,record_info},[A,{atom,_,Name}]}) -> used_records({call,A,{tuple,_,[M,F]},As}) -> used_records({call,A,{remote,A,M,F},As}); used_records({type,_,record,[{atom,_,Name}|Fs]}) -> - {name, Name, Fs}; + {name, Name, Fs}; used_records(T) when is_tuple(T) -> {expr, tuple_to_list(T)}; used_records(E) -> @@ -796,63 +892,63 @@ severity_tag(fatal) -> <<"*** ">>; severity_tag(serious) -> <<"** ">>; severity_tag(benign) -> <<"* ">>. -restrict_handlers(RShMod, Shell, RT) -> - { fun(F,As,Binds) -> - local_allowed(F, As, RShMod, Binds, Shell, RT) +restrict_handlers(RShMod, Shell, RT, FT) -> + { fun(F,As,Binds) -> + local_allowed(F, As, RShMod, Binds, Shell, RT, FT) end, - fun(MF,As) -> - non_local_allowed(MF, As, RShMod, Shell) + fun(MF,As) -> + non_local_allowed(MF, As, RShMod, Shell) end }. -define(BAD_RETURN(M, F, V), try erlang:error(reason) - catch _:_:S -> erlang:raise(exit, {restricted_shell_bad_return,V}, + catch _:_:S -> erlang:raise(exit, {restricted_shell_bad_return,V}, [{M,F,3} | S]) end). -local_allowed(F, As, RShMod, Bs, Shell, RT) when is_atom(F) -> - {LFH,NLFH} = restrict_handlers(RShMod, Shell, RT), - case not_restricted(F, As) of % Not restricted is the same as builtin. - % variable and record manipulations local - % to the shell process. Those are never - % restricted. - true -> - local_func(F, As, Bs, Shell, RT, {eval,LFH}, {value,NLFH}); - false -> +local_allowed(F, As, RShMod, Bs, Shell, RT, FT) when is_atom(F) -> + {LFH,NLFH} = restrict_handlers(RShMod, Shell, RT, FT), + case not_restricted(F, As) of % Not restricted is the same as builtin. + % variable and record manipulations local + % to the shell process. Those are never + % restricted. + true -> + local_func(F, As, Bs, Shell, RT, FT, {eval,LFH}, {value,NLFH}); + false -> {AsEv,Bs1} = expr_list(As, Bs, {eval,LFH}, {value,NLFH}), - case RShMod:local_allowed(F, AsEv, {get(restricted_shell_state), - get(restricted_expr_state)}) of - {Result,{RShShSt,RShExprSt}} -> - put(restricted_shell_state, RShShSt), - put(restricted_expr_state, RShExprSt), - if not Result -> - shell_req(Shell, {update_dict,get()}), - exit({restricted_shell_disallowed,{F,AsEv}}); - true -> % This is never a builtin, - % those are handled above. - non_builtin_local_func(F,AsEv,Bs1) - end; - Unexpected -> % The user supplied non conforming module + case RShMod:local_allowed(F, AsEv, {get(restricted_shell_state), + get(restricted_expr_state)}) of + {Result,{RShShSt,RShExprSt}} -> + put(restricted_shell_state, RShShSt), + put(restricted_expr_state, RShExprSt), + if not Result -> + shell_req(Shell, {update_dict,get()}), + exit({restricted_shell_disallowed,{F,AsEv}}); + true -> % This is never a builtin, + % those are handled above. + non_builtin_local_func(F,AsEv,Bs1, FT) + end; + Unexpected -> % The user supplied non conforming module ?BAD_RETURN(RShMod, local_allowed, Unexpected) - end + end end. non_local_allowed(MForFun, As, RShMod, Shell) -> case RShMod:non_local_allowed(MForFun, As, {get(restricted_shell_state), - get(restricted_expr_state)}) of - {Result,{RShShSt,RShExprSt}} -> - put(restricted_shell_state, RShShSt), - put(restricted_expr_state, RShExprSt), - case Result of - false -> - shell_req(Shell, {update_dict,get()}), - exit({restricted_shell_disallowed,{MForFun,As}}); + get(restricted_expr_state)}) of + {Result,{RShShSt,RShExprSt}} -> + put(restricted_shell_state, RShShSt), + put(restricted_expr_state, RShExprSt), + case Result of + false -> + shell_req(Shell, {update_dict,get()}), + exit({restricted_shell_disallowed,{MForFun,As}}); {redirect, NewMForFun, NewAs} -> apply_fun(NewMForFun, NewAs, Shell); - _ -> - apply_fun(MForFun, As, Shell) - end; - Unexpected -> % The user supplied non conforming module + _ -> + apply_fun(MForFun, As, Shell) + end; + Unexpected -> % The user supplied non conforming module ?BAD_RETURN(RShMod, non_local_allowed, Unexpected) end. @@ -875,6 +971,16 @@ not_restricted(catch_exception, [_]) -> true; not_restricted(exit, []) -> true; +not_restricted(fl, []) -> + true; +not_restricted(fd, [_]) -> + true; +not_restricted(ft, [_]) -> + true; +not_restricted(td, [_]) -> + true; +not_restricted(rd, [_]) -> + true; not_restricted(rd, [_,_]) -> true; not_restricted(rf, []) -> @@ -897,7 +1003,7 @@ not_restricted(_, _) -> false. %% When erlang:garbage_collect() is called from the shell, -%% the shell process process that spawned the evaluating +%% the shell process process that spawned the evaluating %% process is garbage collected as well. %% To garbage collect the evaluating process only the command %% garbage_collect(self()). can be used. @@ -935,7 +1041,7 @@ expand_records(UsedRecords, E0) -> prep_rec({value,_CommandN,_V}=Value) -> %% erl_expand_records cannot handle the history expansion {value,_,_}. {atom,Value,ok}; -prep_rec({atom,{value,_CommandN,_V}=Value,ok}) -> +prep_rec({atom,{value,_CommandN,_V}=Value,ok}) -> %% Undo the effect of the previous clause... Value; prep_rec(T) when is_tuple(T) -> list_to_tuple(prep_rec(tuple_to_list(T))); @@ -947,35 +1053,101 @@ init_dict([{K,V}|Ds]) -> init_dict(Ds); init_dict([]) -> true. -%% local_func(Function, Args, Bindings, Shell, RecordTable, +%% local_func(Function, Args, Bindings, Shell, RecordTable, %% LocalFuncHandler, ExternalFuncHandler) -> {value,Val,Bs} %% Evaluate local functions, including shell commands. %% -%% Note that the predicate not_restricted/2 has to correspond to what's -%% handled internally - it should return 'true' for all local functions -%% handled in this module (i.e. those that are not eventually handled by +%% Note that the predicate not_restricted/2 has to correspond to what's +%% handled internally - it should return 'true' for all local functions +%% handled in this module (i.e. those that are not eventually handled by %% non_builtin_local_func/3 (user_default/shell_default). - -local_func(h, [], Bs, Shell, RT, _Lf, _Ef) -> +local_func() -> [v,h,b,f,fl,rd,rf,rl,rp,rr,history,results,catch_exception]. +local_func(Func) -> + lists:member(Func, local_func()). +local_func(v, [{integer,_,V}], Bs, Shell, _RT, _FT, _Lf, _Ef) -> + %% This command is validated and expanded prior. + {_Ces,Value,_N} = shell_req(Shell, {get_cmd, V}), + {value,Value,Bs}; +local_func(h, [], Bs, Shell, RT, _FT, _Lf, _Ef) -> Cs = shell_req(Shell, get_cmd), Cs1 = lists:filter(fun({{command, _},_}) -> true; - ({{result, _},_}) -> true; - (_) -> false - end, - Cs), + ({{result, _},_}) -> true; + (_) -> false + end, + Cs), Cs2 = lists:map(fun({{T, N}, V}) -> {{N, T}, V} end, - Cs1), + Cs1), Cs3 = lists:keysort(1, Cs2), {value,list_commands(Cs3, RT),Bs}; -local_func(b, [], Bs, _Shell, RT, _Lf, _Ef) -> +local_func(b, [], Bs, _Shell, RT, _FT, _Lf, _Ef) -> {value,list_bindings(erl_eval:bindings(Bs), RT),Bs}; -local_func(f, [], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(f, [], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> {value,ok,erl_eval:new_bindings()}; -local_func(f, [{var,_,Name}], Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(f, [{var,_,Name}], Bs, _Shell, _RT, _FT, _Lf, _Ef) -> {value,ok,erl_eval:del_binding(Name, Bs)}; -local_func(f, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(f, [_Other], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> erlang:raise(error, function_clause, [{shell,f,1}]); -local_func(rd, [{atom,_,RecName0},RecDef0], Bs, _Shell, RT, _Lf, _Ef) -> +local_func(fl, [], Bs, _Shell, _RT, FT, _Lf, _Ef) -> + {value, ets:tab2list(FT), Bs}; +local_func(fd, [{atom,_,FunName}, FunExpr], Bs, _Shell, _RT, FT, _Lf, _Ef) -> + {value, Fun, []} = erl_eval:expr(FunExpr, []), + {arity, Arity} = erlang:fun_info(Fun, arity), + ets:insert(FT, [{{function, {shell_default, FunName, Arity}}, Fun}]), + {value, ok, Bs}; +local_func(fd, [_], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> + erlang:raise(error, function_clause, [{shell, fd, 1}]); +local_func(ft, [{string, _, TypeDef}], Bs, _Shell, _RT, FT, _Lf, _Ef) -> + case erl_scan:tokens([], TypeDef, {1,1}, [text,{reserved_word_fun,fun erl_scan:reserved_word/1}]) of + {done, {ok, Toks, _}, _} -> + case erl_parse:parse_form(Toks) of + {ok, {attribute,_,spec,{{FunName, Arity},_}}=AttrForm} -> + ets:insert(FT, [{{function_type, {shell_default, FunName, Arity}}, AttrForm}]), + {value, ok, Bs}; + {error,{_Location,M,ErrDesc}} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; + {done, {error,{_Location, M, ErrDesc}, _}, _} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; +local_func(ft, [_], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> + erlang:raise(error, function_clause, [{shell, ft, 1}]); +local_func(td, [{string, _, TypeDef}], Bs, _Shell, _RT, FT, _Lf, _Ef) -> + case erl_scan:tokens([], TypeDef, {1,1}, [text,{reserved_word_fun,fun erl_scan:reserved_word/1}]) of + {done, {ok, Toks, _}, _} -> + case erl_parse:parse_form(Toks) of + {ok, {attribute,_,type,{TypeName, _, _}}=AttrForm} -> + ets:insert(FT, [{{type, TypeName}, AttrForm}]), + {value, ok, Bs}; + {error,{_Location,M,ErrDesc}} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; + {done, {error,{_Location, M, ErrDesc}, _}, _} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; +local_func(td, [_], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> + erlang:raise(error, function_clause, [{shell, td, 1}]); +local_func(rd, [{string, _, TypeDef}], Bs, _Shell, RT, _FT, _Lf, _Ef) -> + case erl_scan:tokens([], TypeDef, {1,1}, [text,{reserved_word_fun,fun erl_scan:reserved_word/1}]) of + {done, {ok, Toks, _}, _} -> + case erl_parse:parse_form(Toks) of + {ok,{attribute,_,_,_}=AttrForm} -> + [_] = add_records([AttrForm], Bs, RT), + {value,ok,Bs}; + {error,{_Location,M,ErrDesc}} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; + {done, {error,{_Location, M, ErrDesc}, _}, _} -> + ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), + exit(lists:flatten(ErrStr)) + end; +local_func(rd, [_], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> + erlang:raise(error, function_clause, [{shell, rd, 1}]); +local_func(rd, [{atom,_,RecName0},RecDef0], Bs, _Shell, RT, _FT, _Lf, _Ef) -> RecDef = expand_value(RecDef0), RDs = lists:flatten(erl_pp:expr(RecDef)), RecName = io_lib:write_atom_as_latin1(RecName0), @@ -989,99 +1161,105 @@ local_func(rd, [{atom,_,RecName0},RecDef0], Bs, _Shell, RT, _Lf, _Ef) -> ErrStr = io_lib:fwrite(<<"~ts">>, [M:format_error(ErrDesc)]), exit(lists:flatten(ErrStr)) end; -local_func(rd, [_,_], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(rd, [_,_], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> erlang:raise(error, function_clause, [{shell,rd,2}]); -local_func(rf, [], Bs, _Shell, RT, _Lf, _Ef) -> +local_func(rf, [], Bs, _Shell, RT, _FT, _Lf, _Ef) -> true = ets:delete_all_objects(RT), {value,initiate_records(Bs, RT),Bs}; -local_func(rf, [A], Bs0, _Shell, RT, Lf, Ef) -> +local_func(rf, [A], Bs0, _Shell, RT, _FT, Lf, Ef) -> {[Recs],Bs} = expr_list([A], Bs0, Lf, Ef), if '_' =:= Recs -> true = ets:delete_all_objects(RT); - true -> + true -> lists:foreach(fun(Name) -> true = ets:delete(RT, Name) end, listify(Recs)) end, {value,ok,Bs}; -local_func(rl, [], Bs, _Shell, RT, _Lf, _Ef) -> +local_func(rl, [], Bs, _Shell, RT, _FT, _Lf, _Ef) -> {value,list_records(ets:tab2list(RT)),Bs}; -local_func(rl, [A], Bs0, _Shell, RT, Lf, Ef) -> +local_func(rl, [A], Bs0, _Shell, RT, _FT, Lf, Ef) -> {[Recs],Bs} = expr_list([A], Bs0, Lf, Ef), {value,list_records(record_defs(RT, listify(Recs))),Bs}; -local_func(rp, [A], Bs0, _Shell, RT, Lf, Ef) -> +local_func(rp, [A], Bs0, _Shell, RT, _FT, Lf, Ef) -> {[V],Bs} = expr_list([A], Bs0, Lf, Ef), Cs = pp(V, _Column=1, _Depth=-1, RT), io:requests([{put_chars, unicode, Cs}, nl]), {value,ok,Bs}; -local_func(rr, [A], Bs0, _Shell, RT, Lf, Ef) -> +local_func(rr, [A], Bs0, _Shell, RT, _FT, Lf, Ef) -> {[File],Bs} = expr_list([A], Bs0, Lf, Ef), {value,read_and_add_records(File, '_', [], Bs, RT),Bs}; -local_func(rr, [_,_]=As0, Bs0, _Shell, RT, Lf, Ef) -> +local_func(rr, [_,_]=As0, Bs0, _Shell, RT, _FT, Lf, Ef) -> {[File,Sel],Bs} = expr_list(As0, Bs0, Lf, Ef), {value,read_and_add_records(File, Sel, [], Bs, RT),Bs}; -local_func(rr, [_,_,_]=As0, Bs0, _Shell, RT, Lf, Ef) -> +local_func(rr, [_,_,_]=As0, Bs0, _Shell, RT, _FT, Lf, Ef) -> {[File,Sel,Options],Bs} = expr_list(As0, Bs0, Lf, Ef), {value,read_and_add_records(File, Sel, Options, Bs, RT),Bs}; -local_func(history, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(history, [{integer,_,N}], Bs, _Shell, _RT, _FT, _Lf, _Ef) -> {value,history(N),Bs}; -local_func(history, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(history, [_Other], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> erlang:raise(error, function_clause, [{shell,history,1}]); -local_func(results, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(results, [{integer,_,N}], Bs, _Shell, _RT, _FT, _Lf, _Ef) -> {value,results(N),Bs}; -local_func(results, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(results, [_Other], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> erlang:raise(error, function_clause, [{shell,results,1}]); -local_func(catch_exception, [{atom,_,Bool}], Bs, _Shell, _RT, _Lf, _Ef) - when Bool; not Bool -> +local_func(catch_exception, [{atom,_,Bool}], Bs, _Shell, _RT, _FT, _Lf, _Ef) + when Bool; not Bool -> {value,catch_exception(Bool),Bs}; -local_func(catch_exception, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> +local_func(catch_exception, [_Other], _Bs, _Shell, _RT, _FT, _Lf, _Ef) -> erlang:raise(error, function_clause, [{shell,catch_exception,1}]); -local_func(exit, [], _Bs, Shell, _RT, _Lf, _Ef) -> - shell_req(Shell, exit), %This terminates us +local_func(exit, [], _Bs, Shell, _RT, _FT, _Lf, _Ef) -> + shell_req(Shell, exit), %This terminates us exit(normal); -local_func(F, As0, Bs0, _Shell, _RT, Lf, Ef) when is_atom(F) -> +local_func(F, As0, Bs0, _Shell, _RT, FT, Lf, Ef) when is_atom(F) -> {As,Bs} = expr_list(As0, Bs0, Lf, Ef), - non_builtin_local_func(F,As,Bs). + non_builtin_local_func(F,As,Bs, FT). -non_builtin_local_func(F,As,Bs) -> +non_builtin_local_func(F,As,Bs, FT) -> Arity = length(As), case erlang:function_exported(user_default, F, Arity) of - true -> + true -> {eval,erlang:make_fun(user_default, F, Arity),As,Bs}; - false -> - shell_default(F,As,Bs) + false -> + shell_default(F,As,Bs, FT) end. -shell_default(F,As,Bs) -> +shell_default(F,As,Bs, FT) -> M = shell_default, A = length(As), case code:ensure_loaded(M) of - {module, _} -> - case erlang:function_exported(M,F,A) of - true -> - {eval,erlang:make_fun(M, F, A),As,Bs}; - false -> - shell_undef(F,A) - end; - {error, _} -> - shell_undef(F,A) + {module, _} -> + case erlang:function_exported(M,F,A) of + true -> + {eval,erlang:make_fun(M, F, A),As,Bs}; + false -> + shell_default_local_func(F,As, Bs, FT) + end; + {error, _} -> + shell_default_local_func(F,As, Bs, FT) + end. + +shell_default_local_func(F, As, Bs, FT) -> + case ets:lookup(FT, {function, {shell_default, F, length(As)}}) of + [] -> shell_undef(F, length(As)); + [{_, Fun}] -> {eval, Fun, As, Bs} end. shell_undef(F,A) -> erlang:error({shell_undef,F,A,[]}). -local_func_handler(Shell, RT, Ef) -> - H = fun(Lf) -> - fun(F, As, Bs) -> - local_func(F, As, Bs, Shell, RT, {eval,Lf(Lf)}, Ef) +local_func_handler(Shell, RT, FT, Ef) -> + H = fun(Lf) -> + fun(F, As, Bs) -> + local_func(F, As, Bs, Shell, RT, FT, {eval,Lf(Lf)}, Ef) end - end, + end, {eval,H(H)}. record_print_fun(RT) -> fun(Tag, NoFields) -> case ets:lookup(RT, Tag) of - [{_,{attribute,_,record,{Tag,Fields}}}] - when length(Fields) =:= NoFields -> + [{_,{attribute,_,record,{Tag,Fields}}}] + when length(Fields) =:= NoFields -> record_fields(Fields); _ -> no @@ -1100,7 +1278,7 @@ record_fields([]) -> initiate_records(Bs, RT) -> RNs1 = init_rec(shell_default, Bs, RT), RNs2 = case code:is_loaded(user_default) of - {file,_File} -> + {file,_File} -> init_rec(user_default, Bs, RT); false -> [] @@ -1136,11 +1314,12 @@ read_records(File, Selected, Options) -> RAs; RAs -> Sel = listify(Selected), - [RA || {attribute,_,_,{Name,_}}=RA <- RAs, + [RA || {attribute,_,_,{Name,_}}=RA <- RAs, lists:member(Name, Sel)] end. add_records(RAs, Bs0, RT) -> + %% TODO store File name to support type completion Recs = [{Name,D} || {attribute,_,_,{Name,_}}=D <- RAs], Bs1 = record_bindings(Recs, Bs0), case check_command([], Bs1) of @@ -1174,12 +1353,12 @@ expr_list(Es, Bs, Lf, Ef) -> record_bindings([], Bs) -> Bs; record_bindings(Recs0, Bs0) -> - {Recs1, _} = lists:mapfoldl(fun ({Name,Def}, I) -> {{Name,I,Def},I+1} + {Recs1, _} = lists:mapfoldl(fun ({Name,Def}, I) -> {{Name,I,Def},I+1} end, 0, Recs0), Recs2 = lists:keysort(2, lists:ukeysort(1, Recs1)), lists:foldl(fun ({Name,I,Def}, Bs) -> - erl_eval:add_binding({record,I,Name}, Def, Bs) - end, Bs0, Recs2). + erl_eval:add_binding({record,I,Name}, Def, Bs) + end, Bs0, Recs2). %%% Read record information from file(s) @@ -1205,7 +1384,7 @@ read_records(FileOrModule, Opts0) -> find_file(Mod) when is_atom(Mod) -> case code:which(Mod) of - File when is_list(File) -> + File when is_list(File) -> %% Special cases: %% - Modules not in the code path (loaded with code:load_abs/1): %% code:get_object_code/1 only searches in the code path @@ -1219,8 +1398,8 @@ find_file(Mod) when is_atom(Mod) -> error -> {error, nofile} end; - preloaded -> - {_M, Beam, File} = code:get_object_code(Mod), + preloaded -> + {_M, Beam, File} = code:get_object_code(Mod), {beam, Beam, File}; _Else -> % non_existing, interpreted, cover_compiled {error,nofile} @@ -1282,10 +1461,10 @@ try_sources([Src|Rest], Os) -> is_file(Name) -> case filelib:is_file(Name) of - true -> - not filelib:is_dir(Name); - false -> - false + true -> + not filelib:is_dir(Name); + false -> + false end. parse_file(File, Opts) -> @@ -1318,7 +1497,7 @@ record_attrs(Forms) -> shell_req(Shell, Req) -> Shell ! {shell_req,self(),Req}, receive - {shell_rep,Shell,Rep} -> Rep + {shell_rep,Shell,Rep} -> Rep end. list_commands([{{N,command},Es0}, {{N,result}, V} |Ds], RT) -> @@ -1328,7 +1507,7 @@ list_commands([{{N,command},Es0}, {{N,result}, V} |Ds], RT) -> I = iolist_size(Ns), io:requests([{put_chars, latin1, Ns}, {format,<<"~ts\n">>,[erl_pp:exprs(Es, I, enc())]}, - {format,<<"-> ">>,[]}, + {format,<<"-> ">>,[]}, {put_chars, unicode, VS}, nl]), list_commands(Ds, RT); @@ -1370,7 +1549,7 @@ list_bindings([], _RT) -> ok. list_records(Records) -> - lists:foreach(fun({_Name,Attr}) -> + lists:foreach(fun({_Name,Attr}) -> io:fwrite(<<"~ts">>, [erl_pp:attribute(Attr, enc())]) end, Records). @@ -1401,11 +1580,11 @@ prep_list_commands(E) -> substitute_v1(F, {value,_,_}=Value) -> F(Value); -substitute_v1(F, T) when is_tuple(T) -> +substitute_v1(F, T) when is_tuple(T) -> list_to_tuple(substitute_v1(F, tuple_to_list(T))); -substitute_v1(F, [E | Es]) -> +substitute_v1(F, [E | Es]) -> [substitute_v1(F, E) | substitute_v1(F, Es)]; -substitute_v1(_F, E) -> +substitute_v1(_F, E) -> E. a0() -> @@ -1430,13 +1609,7 @@ pp(V, I, RT) -> pp(V, I, _Depth=?LINEMAX, RT). pp(V, I, D, RT) -> - Strings = - case application:get_env(stdlib, shell_strings) of - {ok, false} -> - false; - _ -> - true - end, + Strings = application:get_env(stdlib, shell_strings, true) =/= false, io_lib_pretty:print(V, ([{column, I}, {line_length, columns()}, {depth, D}, {line_max_chars, ?CHAR_MAX}, {strings, Strings}, @@ -1455,8 +1628,8 @@ encoding() -> enc() -> case lists:keyfind(encoding, 1, io:getopts()) of - false -> [{encoding,latin1}]; % should never happen - Enc -> [Enc] + false -> [{encoding,latin1}]; % should never happen + Enc -> [Enc] end. garb(Shell) -> @@ -1466,33 +1639,31 @@ garb(Shell) -> erlang:garbage_collect(). get_env(V, Def) -> - case application:get_env(stdlib, V) of - {ok, Val} when is_integer(Val), Val >= 0 -> - Val; - _ -> - Def + case application:get_env(stdlib, V, Def) of + Val when is_integer(Val), Val >= 0 -> + Val; + _ -> + Def end. - + check_env(V) -> - case application:get_env(stdlib, V) of - undefined -> - ok; - {ok, Val} when is_integer(Val), Val >= 0 -> - ok; - {ok, Val} -> + case application:get_env(stdlib, V, 0) of + Val when is_integer(Val), Val >= 0 -> + ok; + Val -> Txt = io_lib:fwrite ("Invalid value of STDLIB configuration parameter" "~tw: ~tp\n", [V, Val]), - error_logger:info_report(lists:flatten(Txt)) + error_logger:info_report(lists:flatten(Txt)) end. - + set_env(App, Name, Val, Default) -> Prev = case application:get_env(App, Name) of - undefined -> - Default; - {ok, Old} -> - Old - end, + undefined -> + Default; + {ok, Old} -> + Old + end, application_controller:set_env(App, Name, Val), Prev. @@ -1512,7 +1683,7 @@ results(L) when is_integer(L), L >= 0 -> Bool :: boolean(). catch_exception(Bool) -> - set_env(stdlib, shell_catch_exception, Bool, ?DEF_CATCH_EXCEPTION). + set_env(stdlib, shell_catch_exception, Bool, ?DEF_CATCH_EXCEPTION). -spec prompt_func(PromptFunc) -> PromptFunc2 when PromptFunc :: 'default' | {module(),atom()}, diff --git a/lib/stdlib/src/shell_default.erl b/lib/stdlib/src/shell_default.erl index 3d820c91317b..669266d25504 100644 --- a/lib/stdlib/src/shell_default.erl +++ b/lib/stdlib/src/shell_default.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -25,17 +25,17 @@ -export([help/0,lc/1,c/1,c/2,c/3,nc/1,nl/1,l/1,i/0,pid/3,i/3,m/0,m/1,lm/0,mm/0, memory/0,memory/1,uptime/0, - erlangrc/1,bi/1, regs/0, flush/0,pwd/0,ls/0,ls/1,cd/1, + erlangrc/1,bi/1, regs/0, flush/0,pwd/0,ls/0,ls/1,cd/1, y/1, y/2, - xm/1, bt/1, q/0, + xm/1, bt/1, q/0, h/1, h/2, h/3, ht/1, ht/2, ht/3, hcb/1, hcb/2, hcb/3, - ni/0, nregs/0]). + ni/0, nregs/0]). -export([ih/0,iv/0,im/0,ii/1,ii/2,iq/1,ini/1,ini/2,inq/1,ib/2,ib/3, - ir/2,ir/3,ibd/2,ibe/2,iba/3,ibc/3, - ic/0,ir/1,ir/0,il/0,ipb/0,ipb/1,iaa/1,iaa/2,ist/1,ia/1,ia/2,ia/3, - ia/4,ip/0]). - + ir/2,ir/3,ibd/2,ibe/2,iba/3,ibc/3, + ic/0,ir/1,ir/0,il/0,ipb/0,ipb/1,iaa/1,iaa/2,ist/1,ia/1,ia/2,ia/3, + ia/4,ip/0]). +-export(['$handle_undefined_function'/2]). -import(io, [format/1]). help() -> @@ -78,13 +78,13 @@ help() -> %% these are in alphabetic order it would be nice if they %% were to *stay* so! -bi(I) -> c:bi(I). -bt(Pid) -> c:bt(Pid). -c(File) -> c:c(File). +bi(I) -> c:bi(I). +bt(Pid) -> c:bt(Pid). +c(File) -> c:c(File). c(File, Opt) -> c:c(File, Opt). c(File, Opt, Filter) -> c:c(File, Opt, Filter). cd(D) -> c:cd(D). -erlangrc(X) -> c:erlangrc(X). +erlangrc(X) -> c:erlangrc(X). flush() -> c:flush(). h(M) -> c:h(M). h(M,F) -> c:h(M,F). @@ -95,25 +95,25 @@ ht(M,F,A) -> c:ht(M,F,A). hcb(M) -> c:hcb(M). hcb(M,F) -> c:hcb(M,F). hcb(M,F,A) -> c:hcb(M,F,A). -i() -> c:i(). -i(X,Y,Z) -> c:i(X,Y,Z). -l(Mod) -> c:l(Mod). -lc(X) -> c:lc(X). +i() -> c:i(). +i(X,Y,Z) -> c:i(X,Y,Z). +l(Mod) -> c:l(Mod). +lc(X) -> c:lc(X). ls() -> c:ls(). ls(S) -> c:ls(S). -m() -> c:m(). -m(Mod) -> c:m(Mod). +m() -> c:m(). +m(Mod) -> c:m(Mod). lm() -> c:lm(). mm() -> c:mm(). memory() -> c:memory(). memory(Type) -> c:memory(Type). -nc(X) -> c:nc(X). +nc(X) -> c:nc(X). ni() -> c:ni(). -nl(Mod) -> c:nl(Mod). +nl(Mod) -> c:nl(Mod). nregs() -> c:nregs(). -pid(X,Y,Z) -> c:pid(X,Y,Z). +pid(X,Y,Z) -> c:pid(X,Y,Z). pwd() -> c:pwd(). -q() -> c:q(). +q() -> c:q(). regs() -> c:regs(). uptime() -> c:uptime(). xm(Mod) -> c:xm(Mod). @@ -154,3 +154,11 @@ iv() -> calli(iv, []). calli(F, Args) -> c:appcall(debugger, i, F, Args). + +'$handle_undefined_function'(Func, Args) -> + case shell:get_function(Func, length(Args)) of + undefined -> + error_handler:raise_undef_exception(?MODULE, Func, Args); + Fun when is_function(Fun, length(Args)) -> + apply(Fun, Args) + end. \ No newline at end of file diff --git a/lib/stdlib/src/shell_docs.erl b/lib/stdlib/src/shell_docs.erl index e42b5bb5b864..8c743e20c2a9 100644 --- a/lib/stdlib/src/shell_docs.erl +++ b/lib/stdlib/src/shell_docs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -595,13 +595,18 @@ render_function(FDocs, D, Config) when is_map(Config) -> render_function(FDocs, #docs_v1{ docs = Docs } = D, Config) -> Grouping = lists:foldl( - fun({_Group,_Anno,_Sig,_Doc,#{ equiv := Group }} = Func,Acc) -> - Members = maps:get(Group, Acc, []), - Acc#{ Group => [Func|Members] }; + fun({_Group,_Anno,_Sig,_Doc,#{ equiv := Group }} = Func, Acc) -> + case lists:keytake(Group, 1, Acc) of + false -> [{Group, [Func]} | Acc]; + {value, {Group, Members}, NewAcc} -> + [{Group,[Func|Members]} | NewAcc] + end; ({Group, _Anno, _Sig, _Doc, _Meta} = Func, Acc) -> - Members = maps:get(Group, Acc, []), - Acc#{ Group => [Func|Members] } - end, #{}, lists:sort(FDocs)), + [{Group, [Func]} | Acc] + end, [], + %% We sort only on the group element, so that multiple entries with + %% the same group do not change order. For example erlang:halt/1. + lists:sort(fun(A, B) -> element(1, A) =< element(1, B) end, FDocs)), lists:map( fun({Group,Members}) -> Signatures = lists:flatmap(fun render_signature/1, lists:reverse(Members)), @@ -621,7 +626,7 @@ render_function(FDocs, #docs_v1{ docs = Docs } = D, Config) -> Signatures, get_local_doc(Group, Doc, D), D, Config) end end - end, maps:to_list(Grouping)). + end, lists:reverse(Grouping)). %% Render the signature of either function, type, or anything else really. render_signature({{_Type,_F,_A},_Anno,_Sigs,_Docs,#{ signature := Specs } = Meta}) -> @@ -872,10 +877,16 @@ render_element({li,[],Content},[l | _] = State, Pos, Ind,D) -> render_element({dl,_,Content},State,Pos,Ind,D) -> render_docs(Content, [dl|State], Pos, Ind,D); -render_element({dt,_,Content},[dl | _] = State,Pos,Ind,D) -> +render_element({dt,Attr,Content},[dl | _] = State,Pos,Ind,D) -> + Since = case Attr of + [{since, Vsn}] -> + [" (since ",unicode:characters_to_list(Vsn),$)]; + [] -> + [] + end, Underline = sansi(underline), {Docs, _NewPos} = render_docs(Content, [li | State], Pos, Ind, D), - {[Underline,Docs,ransi(underline),":","\n"], 0}; + {[Underline,Docs,ransi(underline),$:,Since,$\n], 0}; render_element({dd,_,Content},[dl | _] = State,Pos,Ind,D) -> trimnlnl(render_docs(Content, [li | State], Pos, Ind + 2, D)); @@ -1005,18 +1016,18 @@ nl(Chars) -> init_ansi(#config{ ansi = undefined, io_opts = Opts }) -> %% We use this as our heuristic to see if we should print ansi or not case {application:get_env(kernel, shell_docs_ansi), + proplists:get_value(terminal, Opts, false), proplists:is_defined(echo, Opts) andalso - proplists:is_defined(expand_fun, Opts), - os:type()} of + proplists:is_defined(expand_fun, Opts)} of {{ok,false}, _, _} -> put(ansi, noansi); {{ok,true}, _, _} -> put(ansi, []); - {_, _, {win32,_}} -> - put(ansi, noansi); - {_, true,_} -> + {_, true, _} -> + put(ansi, []); + {_, _, true} -> put(ansi, []); - {_, false,_} -> + {_, _, false} -> put(ansi, noansi) end; init_ansi(#config{ ansi = true }) -> diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl index a5169c38f7ae..342c55e3eb9f 100644 --- a/lib/stdlib/src/slave.erl +++ b/lib/stdlib/src/slave.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -19,6 +19,8 @@ %% -module(slave). +-deprecated([{'_','_',"use the 'peer' module instead"}]). + %% If the macro DEBUG is defined during compilation, %% debug printouts are done through erlang:display/1. %% Activate this feature by starting the compiler diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index abef604bdd0a..932d05e895e4 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -21,7 +21,8 @@ {application, stdlib, [{description, "ERTS CXC 138 10"}, {vsn, "%VSN%"}, - {modules, [array, + {modules, [argparse, + array, base64, beam_lib, binary, @@ -36,7 +37,10 @@ digraph, digraph_utils, edlin, + edlin_key, + edlin_context, edlin_expand, + edlin_type_suggestion, epp, eval_bits, erl_abstract_code, @@ -46,6 +50,7 @@ erl_error, erl_eval, erl_expand_records, + erl_features, erl_internal, erl_lint, erl_parse, @@ -71,7 +76,6 @@ io, io_lib, io_lib_format, - io_lib_format_ryu_table, io_lib_fread, io_lib_pretty, lists, @@ -82,6 +86,7 @@ orddict, ordsets, otp_internal, + peer, pool, proc_lib, proplists, @@ -111,6 +116,6 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-3.0","kernel-7.0","erts-12.0","crypto-3.3", + {runtime_dependencies, ["sasl-3.0","kernel-9.0","erts-13.1","crypto-4.5", "compiler-5.0"]} ]}. diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 71644fae1e50..6fc97ec312b0 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -19,33 +19,16 @@ %% %% We allow upgrade from, and downgrade to all previous %% versions from the following OTP releases: -%% - OTP 22 -%% - OTP 23 %% - OTP 24 +%% - OTP 25 +%% - OTP 26 %% %% We also allow upgrade from, and downgrade to all %% versions that have branched off from the above %% stated previous versions. %% {"%VSN%", - [{<<"^3\\.10$">>,[restart_new_emulator]}, - {<<"^3\\.10\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.11$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.12$">>,[restart_new_emulator]}, - {<<"^3\\.12\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.12\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.13$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.14$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.15$">>,[restart_new_emulator]}, + [{<<"^3\\.15$">>,[restart_new_emulator]}, {<<"^3\\.15\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, {<<"^3\\.15\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^3\\.15\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, @@ -56,28 +39,24 @@ {<<"^3\\.17\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, {<<"^3\\.17\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^3\\.17\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.9$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}], - [{<<"^3\\.10$">>,[restart_new_emulator]}, - {<<"^3\\.10\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.11$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.11\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.12$">>,[restart_new_emulator]}, - {<<"^3\\.12\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.12\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.13$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.13\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.14$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.14\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.15$">>,[restart_new_emulator]}, + {<<"^4\\.0$">>,[restart_new_emulator]}, + {<<"^4\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.1$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.2$">>,[restart_new_emulator]}, + {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.3$">>,[restart_new_emulator]}, + {<<"^4\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.0$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.1$">>,[restart_new_emulator]}, + {<<"^5\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}], + [{<<"^3\\.15$">>,[restart_new_emulator]}, {<<"^3\\.15\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, {<<"^3\\.15\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^3\\.15\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, @@ -88,7 +67,20 @@ {<<"^3\\.17\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, {<<"^3\\.17\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, {<<"^3\\.17\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.9$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, - {<<"^3\\.9\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}. + {<<"^4\\.0$">>,[restart_new_emulator]}, + {<<"^4\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.1$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^4\\.2$">>,[restart_new_emulator]}, + {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.3$">>,[restart_new_emulator]}, + {<<"^4\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^4\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.0$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.0\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.1$">>,[restart_new_emulator]}, + {<<"^5\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}. diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl index f8f45dde5645..163bd8d0811a 100644 --- a/lib/stdlib/src/string.erl +++ b/lib/stdlib/src/string.erl @@ -76,7 +76,9 @@ -import(lists,[member/2]). -compile({no_auto_import,[length/1]}). -compile({inline, [btoken/2, rev/1, append/2, stack/2, search_compile/1]}). --define(ASCII_LIST(CP1,CP2), CP1 < 256, CP2 < 256, CP1 =/= $\r). +-define(ASCII_LIST(CP1,CP2), + is_integer(CP1), 0 =< CP1, CP1 < 256, + is_integer(CP2), 0 =< CP2, CP2 < 256, CP1 =/= $\r). -export_type([grapheme_cluster/0]). @@ -223,7 +225,7 @@ slice(CD, N, Length) [] when is_binary(CD) -> <<>>; L -> slice_trail(L, Length) end; -slice(CD, N, infinity) -> +slice(CD, N, infinity) when is_integer(N), N >= 0 -> case slice_l0(CD, N) of [] when is_binary(CD) -> <<>>; Res -> Res @@ -286,11 +288,13 @@ trim(Str, Dir) -> Dir :: direction() | 'both', Characters :: [grapheme_cluster()]. trim(Str, _, []) -> Str; -trim(Str, leading, [Sep]) when is_list(Str), Sep < 256 -> +trim(Str, leading, [Sep]) + when is_list(Str), is_integer(Sep), 0 =< Sep, Sep < 256 -> trim_ls(Str, Sep); trim(Str, leading, Sep) when is_list(Sep) -> trim_l(Str, Sep); -trim(Str, trailing, [Sep]) when is_list(Str), Sep < 256 -> +trim(Str, trailing, [Sep]) + when is_list(Str), is_integer(Sep), 0 =< Sep, Sep < 256 -> trim_ts(Str, Sep); trim(Str, trailing, Seps0) when is_list(Seps0) -> Seps = search_pattern(Seps0), @@ -655,9 +659,10 @@ slice_l0(<>, N) when N > 0 -> slice_l0(L, N) -> slice_l(L, N). -slice_l([CP1|[CP2|_]=Cont], N) when ?ASCII_LIST(CP1,CP2),N > 0 -> +slice_l([CP1|[CP2|_]=Cont], N) + when ?ASCII_LIST(CP1,CP2), is_integer(N), N > 0 -> slice_l(Cont, N-1); -slice_l(CD, N) when N > 0 -> +slice_l(CD, N) when is_integer(N), N > 0 -> case unicode_util:gc(CD) of [_|Cont] -> slice_l(Cont, N-1); [] -> []; @@ -666,7 +671,8 @@ slice_l(CD, N) when N > 0 -> slice_l(Cont, 0) -> Cont. -slice_lb(<>, CP1, N) when ?ASCII_LIST(CP1,CP2), N > 1 -> +slice_lb(<>, CP1, N) + when ?ASCII_LIST(CP1,CP2), is_integer(N), N > 1 -> slice_lb(Bin, CP2, N-1); slice_lb(Bin, CP1, N) -> [_|Rest] = unicode_util:gc([CP1|Bin]), @@ -718,9 +724,13 @@ slice_bin(CD, CP1, N) when N > 0 -> slice_bin(CD, CP1, 0) -> byte_size(CD)+byte_size(<>). -uppercase_list([CP1|[CP2|_]=Cont], _Changed) when $a =< CP1, CP1 =< $z, CP2 < 256 -> +uppercase_list([CP1|[CP2|_]=Cont], _Changed) + when is_integer(CP1), $a =< CP1, CP1 =< $z, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1-32|uppercase_list(Cont, true)]; -uppercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 -> +uppercase_list([CP1|[CP2|_]=Cont], Changed) + when is_integer(CP1), 0 =< CP1, CP1 < 128, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1|uppercase_list(Cont, Changed)]; uppercase_list([], true) -> []; @@ -734,16 +744,16 @@ uppercase_list(CPs0, Changed) -> end. uppercase_bin(CP1, <>, _Changed) - when $a =< CP1, CP1 =< $z, CP2 < 256 -> + when is_integer(CP1), $a =< CP1, CP1 =< $z, CP2 < 256 -> [CP1-32|uppercase_bin(CP2, Bin, true)]; uppercase_bin(CP1, <>, Changed) - when CP1 < 128, CP2 < 256 -> + when is_integer(CP1), 0 =< CP1, CP1 < 128, CP2 < 256 -> [CP1|uppercase_bin(CP2, Bin, Changed)]; uppercase_bin(CP1, Bin, Changed) -> case unicode_util:uppercase([CP1|Bin]) of [CP1|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [CP1|uppercase_bin(Next, Rest, Changed)]; [] when Changed -> [CP1]; @@ -754,7 +764,7 @@ uppercase_bin(CP1, Bin, Changed) -> end; [Char|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [Char|uppercase_bin(Next, Rest, true)]; [] -> [Char]; @@ -763,9 +773,13 @@ uppercase_bin(CP1, Bin, Changed) -> end end. -lowercase_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 -> +lowercase_list([CP1|[CP2|_]=Cont], _Changed) + when is_integer(CP1), $A =< CP1, CP1 =< $Z, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1+32|lowercase_list(Cont, true)]; -lowercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 -> +lowercase_list([CP1|[CP2|_]=Cont], Changed) + when is_integer(CP1), 0 =< CP1, CP1 < 128, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1|lowercase_list(Cont, Changed)]; lowercase_list([], true) -> []; @@ -779,16 +793,16 @@ lowercase_list(CPs0, Changed) -> end. lowercase_bin(CP1, <>, _Changed) - when $A =< CP1, CP1 =< $Z, CP2 < 256 -> + when is_integer(CP1), $A =< CP1, CP1 =< $Z, CP2 < 256 -> [CP1+32|lowercase_bin(CP2, Bin, true)]; lowercase_bin(CP1, <>, Changed) - when CP1 < 128, CP2 < 256 -> + when is_integer(CP1), 0 =< CP1, CP1 < 128, CP2 < 256 -> [CP1|lowercase_bin(CP2, Bin, Changed)]; lowercase_bin(CP1, Bin, Changed) -> case unicode_util:lowercase([CP1|Bin]) of [CP1|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [CP1|lowercase_bin(Next, Rest, Changed)]; [] when Changed -> [CP1]; @@ -799,7 +813,7 @@ lowercase_bin(CP1, Bin, Changed) -> end; [Char|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [Char|lowercase_bin(Next, Rest, true)]; [] -> [Char]; @@ -808,9 +822,13 @@ lowercase_bin(CP1, Bin, Changed) -> end end. -casefold_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 -> +casefold_list([CP1|[CP2|_]=Cont], _Changed) + when is_integer(CP1), $A =< CP1, CP1 =< $Z, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1+32|casefold_list(Cont, true)]; -casefold_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 -> +casefold_list([CP1|[CP2|_]=Cont], Changed) + when is_integer(CP1), 0 =< CP1, CP1 < 128, + is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1|casefold_list(Cont, Changed)]; casefold_list([], true) -> []; @@ -824,16 +842,16 @@ casefold_list(CPs0, Changed) -> end. casefold_bin(CP1, <>, _Changed) - when $A =< CP1, CP1 =< $Z, CP2 < 256 -> + when is_integer(CP1), $A =< CP1, CP1 =< $Z, CP2 < 256 -> [CP1+32|casefold_bin(CP2, Bin, true)]; casefold_bin(CP1, <>, Changed) - when CP1 < 128, CP2 < 256 -> + when is_integer(CP1), 0 =< CP1, CP1 < 128, CP2 < 256 -> [CP1|casefold_bin(CP2, Bin, Changed)]; casefold_bin(CP1, Bin, Changed) -> case unicode_util:casefold([CP1|Bin]) of [CP1|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [CP1|casefold_bin(Next, Rest, Changed)]; [] when Changed -> [CP1]; @@ -844,7 +862,7 @@ casefold_bin(CP1, Bin, Changed) -> end; [Char|CPs] -> case unicode_util:cp(CPs) of - [Next|Rest] -> + [Next|Rest] when is_integer(Next), Next >= 0 -> [Char|casefold_bin(Next, Rest, true)]; [] -> [Char]; @@ -1759,7 +1777,7 @@ bin_search_str_2(Bin0, Start, Cont, First, SearchCPs) -> <<_:Start/binary, Bin/binary>> = Bin0, case binary:match(Bin, First) of nomatch -> {nomatch, byte_size(Bin0), Cont}; - {Where0, _} -> + {Where0, _} when is_integer(Where0) -> Where = Start+Where0, <> = Bin0, [GC|Cs]=unicode_util:gc(Cs0), @@ -2004,7 +2022,7 @@ chars(C, N) -> chars(C, N, []). Tail :: string(), String :: string(). -chars(C, N, Tail) when N > 0 -> +chars(C, N, Tail) when is_integer(N), N > 0 -> chars(C, N-1, [C|Tail]); chars(C, 0, Tail) when is_integer(C) -> Tail. @@ -2134,7 +2152,7 @@ left(String, Len) when is_integer(Len) -> left(String, Len, $\s). Number :: non_neg_integer(), Character :: char(). -left(String, Len, Char) when is_integer(Char) -> +left(String, Len, Char) when is_integer(Len), is_integer(Char) -> Slen = erlang:length(String), if Slen > Len -> substr(String, 1, Len); @@ -2159,7 +2177,7 @@ right(String, Len) when is_integer(Len) -> right(String, Len, $\s). Number :: non_neg_integer(), Character :: char(). -right(String, Len, Char) when is_integer(Char) -> +right(String, Len, Char) when is_integer(Len), is_integer(Char) -> Slen = erlang:length(String), if Slen > Len -> substr(String, Slen-Len+1); @@ -2186,7 +2204,7 @@ centre(String, Len) when is_integer(Len) -> centre(String, Len, $\s). centre(String, 0, Char) when is_list(String), is_integer(Char) -> []; % Strange cases to centre string -centre(String, Len, Char) when is_integer(Char) -> +centre(String, Len, Char) when is_integer(Len), is_integer(Char) -> Slen = erlang:length(String), if Slen > Len -> substr(String, (Slen-Len) div 2 + 1, Len); @@ -2211,7 +2229,8 @@ sub_string(String, Start) -> substr(String, Start). Start :: pos_integer(), Stop :: pos_integer(). -sub_string(String, Start, Stop) -> substr(String, Start, Stop - Start + 1). +sub_string(String, Start, Stop) when is_integer(Start), is_integer(Stop) -> + substr(String, Start, Stop - Start + 1). %% ISO/IEC 8859-1 (latin1) letters are converted, others are ignored %% diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 140838f974f6..6636fbc46d8f 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -72,11 +72,11 @@ -type shutdown() :: 'brutal_kill' | timeout(). -type worker() :: 'worker' | 'supervisor'. -type sup_name() :: {'local', Name :: atom()} - | {'global', Name :: atom()} + | {'global', Name :: term()} | {'via', Module :: module(), Name :: any()}. -type sup_ref() :: (Name :: atom()) | {Name :: atom(), Node :: node()} - | {'global', Name :: atom()} + | {'global', Name :: term()} | {'via', Module :: module(), Name :: any()} | pid(). -type child_spec() :: #{id := child_id(), % mandatory @@ -132,16 +132,16 @@ -type child_rec() :: #child{}. -record(state, {name, - strategy :: strategy() | 'undefined', + strategy = one_for_one:: strategy(), children = {[],#{}} :: children(), % Ids in start order dynamics :: {'maps', #{pid() => list()}} | {'mapsets', #{pid() => []}} | 'undefined', - intensity :: non_neg_integer() | 'undefined', - period :: pos_integer() | 'undefined', + intensity = 1 :: non_neg_integer(), + period = 5 :: pos_integer(), restarts = [], dynamic_restarts = 0 :: non_neg_integer(), - auto_shutdown :: auto_shutdown(), + auto_shutdown = never :: auto_shutdown(), module, args}). -type state() :: #state{}. @@ -161,7 +161,7 @@ %%% --------------------------------------------------- %%% This is a general process supervisor built upon gen_server.erl. %%% Servers/processes should/could also be built using gen_server.erl. -%%% SupName = {local, atom()} | {global, atom()}. +%%% SupName = {local, atom()} | {global, term()}. %%% --------------------------------------------------- -type startlink_err() :: {'already_started', pid()} @@ -255,7 +255,7 @@ which_children(Supervisor) -> Count :: {specs, ChildSpecCount :: non_neg_integer()} | {active, ActiveProcessCount :: non_neg_integer()} | {supervisors, ChildSupervisorCount :: non_neg_integer()} - |{workers, ChildWorkerCount :: non_neg_integer()}. + | {workers, ChildWorkerCount :: non_neg_integer()}. count_children(Supervisor) -> call(Supervisor, count_children). @@ -377,7 +377,7 @@ init_dynamic(_State, StartSpec) -> %%----------------------------------------------------------------- %% Func: start_children/2 %% Args: Children = children() % Ids in start order -%% SupName = {local, atom()} | {global, atom()} | {pid(), Mod} +%% SupName = {local, atom()} | {global, term()} | {pid(), Mod} %% Purpose: Start all children. The new map contains #child's %% with pids. %% Returns: {ok, NChildren} | {error, NChildren, Reason} @@ -716,6 +716,8 @@ handle_start_child(Child, State) -> {{ok, Pid}, save_child(Child#child{pid = Pid}, State)}; {ok, Pid, Extra} -> {{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)}; + {error, {already_started, _Pid} = What} -> + {{error, What}, State}; {error, What} -> {{error, {What, Child}}, State} end; @@ -885,7 +887,7 @@ try_again_restart(TryAgainId) -> %%----------------------------------------------------------------- %% Func: terminate_children/2 %% Args: Children = children() % Ids in termination order -%% SupName = {local, atom()} | {global, atom()} | {pid(),Mod} +%% SupName = {local, atom()} | {global, term()} | {pid(),Mod} %% Returns: NChildren = children() % Ids in startup order %% % (reversed termination order) %%----------------------------------------------------------------- @@ -1302,7 +1304,7 @@ append({Ids1,Db1},{Ids2,Db2}) -> %%----------------------------------------------------------------- %% Func: init_state/4 -%% Args: SupName = {local, atom()} | {global, atom()} | self +%% Args: SupName = {local, atom()} | {global, term()} | self %% Type = {Strategy, MaxIntensity, Period} %% Strategy = one_for_one | one_for_all | simple_one_for_one | %% rest_for_one @@ -1522,7 +1524,7 @@ add_restart(State) -> P = State#state.period, R = State#state.restarts, Now = erlang:monotonic_time(1), - R1 = add_restart([Now|R], Now, P), + R1 = add_restart(R, Now, P), State1 = State#state{restarts = R1}, case length(R1) of CurI when CurI =< I -> @@ -1531,18 +1533,13 @@ add_restart(State) -> {terminate, State1} end. -add_restart([R|Restarts], Now, Period) -> - case inPeriod(R, Now, Period) of - true -> - [R|add_restart(Restarts, Now, Period)]; - _ -> - [] - end; -add_restart([], _, _) -> - []. - -inPeriod(Then, Now, Period) -> - Now =< Then + Period. +add_restart(Restarts0, Now, Period) -> + Treshold = Now - Period, + Restarts1 = lists:takewhile( + fun (R) -> R >= Treshold end, + Restarts0 + ), + [Now | Restarts1]. %%% ------------------------------------------------------ %%% Error and progress reporting. diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl index 20384c22f6ab..abd025b7f725 100644 --- a/lib/stdlib/src/sys.erl +++ b/lib/stdlib/src/sys.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -40,7 +40,7 @@ %% Types %%----------------------------------------------------------------- --export_type([dbg_opt/0, dbg_fun/0, debug_option/0]). +-export_type([dbg_opt/0, dbg_fun/0, debug_option/0, system_event/0]). -type name() :: pid() | atom() | {'global', term()} @@ -138,7 +138,7 @@ get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout). get_state(Name) -> case send_system_msg(Name, get_state) of {error, Reason} -> error(Reason); - State -> State + {ok, State} -> State end. -spec get_state(Name, Timeout) -> State when @@ -148,7 +148,7 @@ get_state(Name) -> get_state(Name, Timeout) -> case send_system_msg(Name, get_state, Timeout) of {error, Reason} -> error(Reason); - State -> State + {ok, State} -> State end. -spec replace_state(Name, StateFun) -> NewState when @@ -158,7 +158,7 @@ get_state(Name, Timeout) -> replace_state(Name, StateFun) -> case send_system_msg(Name, {replace_state, StateFun}) of {error, Reason} -> error(Reason); - State -> State + {ok, State} -> State end. -spec replace_state(Name, StateFun, Timeout) -> NewState when @@ -169,7 +169,7 @@ replace_state(Name, StateFun) -> replace_state(Name, StateFun, Timeout) -> case send_system_msg(Name, {replace_state, StateFun}, Timeout) of {error, Reason} -> error(Reason); - State -> State + {ok, State} -> State end. -spec change_code(Name, Module, OldVsn, Extra) -> 'ok' | {error, Reason} when @@ -333,15 +333,19 @@ remove(Name, FuncOrFuncId, Timeout) -> %% The receiving side should send Msg to handle_system_msg/5. %%----------------------------------------------------------------- send_system_msg(Name, Request) -> - case catch gen:call(Name, system, Request) of - {ok,Res} -> Res; - {'EXIT', Reason} -> exit({Reason, mfa(Name, Request)}) + try gen:call(Name, system, Request) of + {ok, Res} -> + Res + catch exit : Reason -> + exit({Reason, mfa(Name, Request)}) end. send_system_msg(Name, Request, Timeout) -> - case catch gen:call(Name, system, Request, Timeout) of - {ok,Res} -> Res; - {'EXIT', Reason} -> exit({Reason, mfa(Name, Request, Timeout)}) + try gen:call(Name, system, Request, Timeout) of + {ok, Res} -> + Res + catch exit : Reason -> + exit({Reason, mfa(Name, Request, Timeout)}) end. mfa(Name, {debug, {Func, Arg2}}) -> @@ -503,34 +507,50 @@ do_cmd(SysState, Other, _Parent, _Mod, Debug, Misc) -> do_get_state(Mod, Misc) -> case erlang:function_exported(Mod, system_get_state, 1) of true -> - try - {ok, State} = Mod:system_get_state(Misc), - State - catch - Cl:Exc -> - {error, {callback_failed,{Mod,system_get_state},{Cl,Exc}}} - end; + try Mod:system_get_state(Misc) of + {ok, _} = Result -> + Result; + Other -> + {error, + {callback_failed, {Mod,system_get_state}, + {bad_return,Other}}} + catch + Cl : Exc -> + {error, + {callback_failed, {Mod,system_get_state}, + {Cl,Exc}}} + end; false -> - Misc + {ok, Misc} end. do_replace_state(StateFun, Mod, Misc) -> case erlang:function_exported(Mod, system_replace_state, 2) of true -> - try - {ok, State, NMisc} = Mod:system_replace_state(StateFun, Misc), - {State, NMisc} + try Mod:system_replace_state(StateFun, Misc) of + {ok, State, NMisc} -> + {{ok, State}, NMisc}; + Other -> + {{error, + {callback_failed, {Mod,system_replace_state}, + {bad_return,Other}}}, + Misc} catch - Cl:Exc -> - {{error, {callback_failed,{Mod,system_replace_state},{Cl,Exc}}}, Misc} + Cl : Exc -> + {{error, + {callback_failed, {Mod,system_replace_state}, + {Cl,Exc}}}, + Misc} end; false -> - try - NMisc = StateFun(Misc), - {NMisc, NMisc} + try StateFun(Misc) of + NMisc -> + {{ok, NMisc}, NMisc} catch - Cl:Exc -> - {{error, {callback_failed,StateFun,{Cl,Exc}}}, Misc} + Cl : Exc -> + {{error, + {callback_failed, StateFun, {Cl,Exc}}}, + Misc} end end. diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl index df10790ea088..5f1d2eb6b705 100644 --- a/lib/stdlib/src/timer.erl +++ b/lib/stdlib/src/timer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -20,135 +20,220 @@ -module(timer). -export([apply_after/4, - send_after/3, send_after/2, - exit_after/3, exit_after/2, kill_after/2, kill_after/1, - apply_interval/4, send_interval/3, send_interval/2, - cancel/1, sleep/1, tc/1, tc/2, tc/3, now_diff/2, - seconds/1, minutes/1, hours/1, hms/3]). - --export([start_link/0, start/0, - handle_call/3, handle_info/2, - init/1, - code_change/3, handle_cast/2, terminate/2]). - -%% internal exports for test purposes only --export([get_status/0]). - -%% types which can be used by other modules + send_after/3, send_after/2, + exit_after/3, exit_after/2, kill_after/2, kill_after/1, + apply_interval/4, apply_repeatedly/4, + send_interval/3, send_interval/2, + cancel/1, sleep/1, tc/1, tc/2, tc/3, tc/4, now_diff/2, + seconds/1, minutes/1, hours/1, hms/3]). + +-export([start_link/0, start/0, + handle_call/3, handle_info/2, + init/1, + code_change/3, handle_cast/2, terminate/2]). + +%% Types which can be used by other modules -export_type([tref/0]). -%% Max --define(MAX_TIMEOUT, 16#0800000). --define(TIMER_TAB, timer_tab). --define(INTERVAL_TAB, timer_interval_tab). +%% Max value for a receive's after clause. +-define(MAX_RECEIVE_AFTER, 16#ffffffff). + +%% Validations +-define(valid_time(T), is_integer(T), T >= 0). +-define(valid_mfa(M, F, A), is_atom(M), is_atom(F), is_list(A)). %% %% Time is in milliseconds. %% --opaque tref() :: {integer(), reference()}. --type time() :: non_neg_integer(). +-opaque tref() :: {type(), reference()}. +-type type() :: 'once' | 'interval' | 'instant' | 'send_local'. +-type time() :: non_neg_integer(). %% %% Interface functions %% -spec apply_after(Time, Module, Function, Arguments) -> - {'ok', TRef} | {'error', Reason} when - Time :: time(), - Module :: module(), - Function :: atom(), - Arguments :: [term()], - TRef :: tref(), - Reason :: term(). - -apply_after(Time, M, F, A) -> - req(apply_after, {Time, {M, F, A}}). - --spec send_after(Time, Pid, Message) -> {'ok', TRef} | {'error', Reason} when - Time :: time(), - Pid :: pid() | (RegName :: atom()), - Message :: term(), - TRef :: tref(), - Reason :: term(). -send_after(Time, Pid, Message) -> - req(apply_after, {Time, {?MODULE, send, [Pid, Message]}}). - --spec send_after(Time, Message) -> {'ok', TRef} | {'error', Reason} when - Time :: time(), - Message :: term(), - TRef :: tref(), - Reason :: term(). + {'ok', TRef} | {'error', Reason} + when Time :: time(), + Module :: module(), + Function :: atom(), + Arguments :: [term()], + TRef :: tref(), + Reason :: term(). +apply_after(0, M, F, A) + when ?valid_mfa(M, F, A) -> + _ = do_apply({M, F, A}, false), + {ok, {instant, make_ref()}}; +apply_after(Time, M, F, A) + when ?valid_time(Time), + ?valid_mfa(M, F, A) -> + req(apply_once, {system_time(), Time, {M, F, A}}); +apply_after(_Time, _M, _F, _A) -> + {error, badarg}. + +-spec send_after(Time, Destination, Message) -> {'ok', TRef} | {'error', Reason} + when Time :: time(), + Destination :: pid() | (RegName :: atom()) | {RegName :: atom(), Node :: node()}, + Message :: term(), + TRef :: tref(), + Reason :: term(). +send_after(0, PidOrRegName, Message) + when is_pid(PidOrRegName); + is_atom(PidOrRegName) -> + PidOrRegName ! Message, + {ok, {instant, make_ref()}}; +send_after(0, {RegName, Node} = Dest, Message) + when is_atom(RegName), + is_atom(Node) -> + Dest ! Message, + {ok, {instant, make_ref()}}; +send_after(Time, Pid, Message) + when ?valid_time(Time), + is_pid(Pid), + node(Pid) =:= node() -> + TRef = erlang:send_after(Time, Pid, Message), + {ok, {send_local, TRef}}; +send_after(Time, Pid, Message) + when is_pid(Pid) -> + apply_after(Time, ?MODULE, send, [Pid, Message]); +send_after(Time, RegName, Message) + when is_atom(RegName) -> + apply_after(Time, ?MODULE, send, [RegName, Message]); +send_after(Time, {RegName, Node} = Dest, Message) + when is_atom(RegName), + is_atom(Node) -> + apply_after(Time, ?MODULE, send, [Dest, Message]); +send_after(_Time, _PidOrRegName, _Message) -> + {error, badarg}. + +-spec send_after(Time, Message) -> {'ok', TRef} | {'error', Reason} + when Time :: time(), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_after(Time, Message) -> send_after(Time, self(), Message). --spec exit_after(Time, Pid, Reason1) -> {'ok', TRef} | {'error', Reason2} when - Time :: time(), - Pid :: pid() | (RegName :: atom()), - TRef :: tref(), - Reason1 :: term(), - Reason2 :: term(). +-spec exit_after(Time, Target, Reason1) -> {'ok', TRef} | {'error', Reason2} + when Time :: time(), + Target :: pid() | (RegName :: atom()), + TRef :: tref(), + Reason1 :: term(), + Reason2 :: term(). exit_after(Time, Pid, Reason) -> - req(apply_after, {Time, {erlang, exit, [Pid, Reason]}}). + apply_after(Time, erlang, exit, [Pid, Reason]). --spec exit_after(Time, Reason1) -> {'ok', TRef} | {'error', Reason2} when - Time :: time(), - TRef :: tref(), - Reason1 :: term(), - Reason2 :: term(). +-spec exit_after(Time, Reason1) -> {'ok', TRef} | {'error', Reason2} + when Time :: time(), + TRef :: tref(), + Reason1 :: term(), + Reason2 :: term(). exit_after(Time, Reason) -> exit_after(Time, self(), Reason). --spec kill_after(Time, Pid) -> {'ok', TRef} | {'error', Reason2} when - Time :: time(), - Pid :: pid() | (RegName :: atom()), - TRef :: tref(), - Reason2 :: term(). +-spec kill_after(Time, Target) -> {'ok', TRef} | {'error', Reason2} + when Time :: time(), + Target :: pid() | (RegName :: atom()), + TRef :: tref(), + Reason2 :: term(). kill_after(Time, Pid) -> exit_after(Time, Pid, kill). --spec kill_after(Time) -> {'ok', TRef} | {'error', Reason2} when - Time :: time(), - TRef :: tref(), - Reason2 :: term(). +-spec kill_after(Time) -> {'ok', TRef} | {'error', Reason2} + when Time :: time(), + TRef :: tref(), + Reason2 :: term(). kill_after(Time) -> exit_after(Time, self(), kill). -spec apply_interval(Time, Module, Function, Arguments) -> - {'ok', TRef} | {'error', Reason} when - Time :: time(), - Module :: module(), - Function :: atom(), - Arguments :: [term()], - TRef :: tref(), - Reason :: term(). -apply_interval(Time, M, F, A) -> - req(apply_interval, {Time, self(), {M, F, A}}). - --spec send_interval(Time, Pid, Message) -> - {'ok', TRef} | {'error', Reason} when - Time :: time(), - Pid :: pid() | (RegName :: atom()), - Message :: term(), - TRef :: tref(), - Reason :: term(). -send_interval(Time, Pid, Message) -> - req(apply_interval, {Time, Pid, {?MODULE, send, [Pid, Message]}}). - --spec send_interval(Time, Message) -> {'ok', TRef} | {'error', Reason} when - Time :: time(), - Message :: term(), - TRef :: tref(), - Reason :: term(). + {'ok', TRef} | {'error', Reason} + when Time :: time(), + Module :: module(), + Function :: atom(), + Arguments :: [term()], + TRef :: tref(), + Reason :: term(). +apply_interval(Time, M, F, A) + when ?valid_time(Time), + ?valid_mfa(M, F, A) -> + req(apply_interval, {system_time(), Time, self(), {M, F, A}}); +apply_interval(_Time, _M, _F, _A) -> + {error, badarg}. + +-spec apply_repeatedly(Time, Module, Function, Arguments) -> + {'ok', TRef} | {'error', Reason} + when Time :: time(), + Module :: module(), + Function :: atom(), + Arguments :: [term()], + TRef :: tref(), + Reason :: term(). +apply_repeatedly(Time, M, F, A) + when ?valid_time(Time), + ?valid_mfa(M, F, A) -> + req(apply_repeatedly, {system_time(), Time, self(), {M, F, A}}); +apply_repeatedly(_Time, _M, _F, _A) -> + {error, badarg}. + +-spec send_interval(Time, Destination, Message) -> {'ok', TRef} | {'error', Reason} + when Time :: time(), + Destination :: pid() | (RegName :: atom()) | {RegName :: atom(), Node :: node()}, + Message :: term(), + TRef :: tref(), + Reason :: term(). +send_interval(Time, Pid, Message) + when ?valid_time(Time), + is_pid(Pid) -> + req(apply_interval, {system_time(), Time, Pid, {?MODULE, send, [Pid, Message]}}); +send_interval(Time, RegName, Message) + when ?valid_time(Time), + is_atom(RegName) -> + req(apply_interval, {system_time(), Time, RegName, {?MODULE, send, [RegName, Message]}}); +send_interval(Time, Dest = {RegName, Node}, Message) + when ?valid_time(Time), + is_atom(RegName), + is_atom(Node) -> + req(apply_interval, {system_time(), Time, Dest, {?MODULE, send, [Dest, Message]}}); +send_interval(_Time, _Pid, _Message) -> + {error, badarg}. + +-spec send_interval(Time, Message) -> {'ok', TRef} | {'error', Reason} + when Time :: time(), + Message :: term(), + TRef :: tref(), + Reason :: term(). send_interval(Time, Message) -> send_interval(Time, self(), Message). --spec cancel(TRef) -> {'ok', 'cancel'} | {'error', Reason} when - TRef :: tref(), - Reason :: term(). -cancel(BRef) -> - req(cancel, BRef). - --spec sleep(Time) -> 'ok' when - Time :: timeout(). +-spec cancel(TRef) -> {'ok', 'cancel'} | {'error', Reason} + when TRef :: tref(), + Reason :: term(). +cancel({instant, Ref}) + when is_reference(Ref) -> + {ok, cancel}; +cancel({send_local, Ref}) + when is_reference(Ref) -> + _ = erlang:cancel_timer(Ref), + {ok, cancel}; +cancel({once, Ref} = TRef) + when is_reference(Ref) -> + req(cancel, TRef); +cancel({interval, Ref} = TRef) + when is_reference(Ref) -> + req(cancel, TRef); +cancel(_TRef) -> + {error, badarg}. + +-spec sleep(Time) -> 'ok' + when Time :: timeout(). +sleep(T) + when is_integer(T), + T > ?MAX_RECEIVE_AFTER -> + receive + after ?MAX_RECEIVE_AFTER -> + sleep(T - ?MAX_RECEIVE_AFTER) + end; sleep(T) -> receive after T -> ok @@ -157,296 +242,382 @@ sleep(T) -> %% %% Measure the execution time (in microseconds) for Fun(). %% --spec tc(Fun) -> {Time, Value} when - Fun :: function(), - Time :: integer(), - Value :: term(). +-spec tc(Fun) -> {Time, Value} + when Fun :: function(), + Time :: integer(), + Value :: term(). tc(F) -> + tc(F, microsecond). + +%% +%% Measure the execution time (in microseconds) for Fun(Args) +%% or the execution time (in TimeUnit) for Fun(). +%% +-spec tc(Fun, Arguments) -> {Time, Value} + when Fun :: function(), + Arguments :: [term()], + Time :: integer(), + Value :: term(); + (Fun, TimeUnit) -> {Time, Value} + when Fun :: function(), + TimeUnit :: erlang:time_unit(), + Time :: integer(), + Value :: term(). +tc(F, A) when is_list(A) -> + tc(F, A, microsecond); +tc(F, TimeUnit) -> T1 = erlang:monotonic_time(), Val = F(), T2 = erlang:monotonic_time(), - Time = erlang:convert_time_unit(T2 - T1, native, microsecond), + Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit), {Time, Val}. %% -%% Measure the execution time (in microseconds) for Fun(Args). -%% --spec tc(Fun, Arguments) -> {Time, Value} when - Fun :: function(), - Arguments :: [term()], - Time :: integer(), - Value :: term(). -tc(F, A) -> +%% Measure the execution time (in microseconds) for an MFA +%% or the execution time (in TimeUnit) for Fun(Args). +%% +-spec tc(Module, Function, Arguments) -> {Time, Value} + when Module :: module(), + Function :: atom(), + Arguments :: [term()], + Time :: integer(), + Value :: term(); + (Fun, Arguments, TimeUnit) -> {Time, Value} + when Fun :: function(), + Arguments :: [term()], + TimeUnit :: erlang:time_unit(), + Time :: integer(), + Value :: term(). +tc(M, F, A) when is_list(A) -> + tc(M, F, A, microsecond); +tc(F, A, TimeUnit) -> T1 = erlang:monotonic_time(), Val = apply(F, A), T2 = erlang:monotonic_time(), - Time = erlang:convert_time_unit(T2 - T1, native, microsecond), + Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit), {Time, Val}. %% -%% Measure the execution time (in microseconds) for an MFA. +%% Measure the execution time (in TimeUnit) for an MFA. %% --spec tc(Module, Function, Arguments) -> {Time, Value} when - Module :: module(), - Function :: atom(), - Arguments :: [term()], - Time :: integer(), - Value :: term(). -tc(M, F, A) -> +-spec tc(Module, Function, Arguments, TimeUnit) -> {Time, Value} + when Module :: module(), + Function :: atom(), + Arguments :: [term()], + TimeUnit :: erlang:time_unit(), + Time :: integer(), + Value :: term(). +tc(M, F, A, TimeUnit) -> T1 = erlang:monotonic_time(), Val = apply(M, F, A), T2 = erlang:monotonic_time(), - Time = erlang:convert_time_unit(T2 - T1, native, microsecond), + Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit), {Time, Val}. %% %% Calculate the time difference (in microseconds) of two %% erlang:now() timestamps, T2-T1. %% --spec now_diff(T2, T1) -> Tdiff when - T1 :: erlang:timestamp(), - T2 :: erlang:timestamp(), - Tdiff :: integer(). +-spec now_diff(T2, T1) -> Tdiff + when T1 :: erlang:timestamp(), + T2 :: erlang:timestamp(), + Tdiff :: integer(). now_diff({A2, B2, C2}, {A1, B1, C1}) -> ((A2-A1)*1000000 + B2-B1)*1000000 + C2-C1. %% -%% Convert seconds, minutes etc. to milliseconds. +%% Convert seconds, minutes etc. to milliseconds. %% --spec seconds(Seconds) -> MilliSeconds when - Seconds :: non_neg_integer(), - MilliSeconds :: non_neg_integer(). +-spec seconds(Seconds) -> MilliSeconds + when Seconds :: non_neg_integer(), + MilliSeconds :: non_neg_integer(). seconds(Seconds) -> 1000*Seconds. --spec minutes(Minutes) -> MilliSeconds when - Minutes :: non_neg_integer(), - MilliSeconds :: non_neg_integer(). + +-spec minutes(Minutes) -> MilliSeconds + when Minutes :: non_neg_integer(), + MilliSeconds :: non_neg_integer(). minutes(Minutes) -> 1000*60*Minutes. --spec hours(Hours) -> MilliSeconds when - Hours :: non_neg_integer(), - MilliSeconds :: non_neg_integer(). + +-spec hours(Hours) -> MilliSeconds + when Hours :: non_neg_integer(), + MilliSeconds :: non_neg_integer(). hours(Hours) -> 1000*60*60*Hours. --spec hms(Hours, Minutes, Seconds) -> MilliSeconds when - Hours :: non_neg_integer(), - Minutes :: non_neg_integer(), - Seconds :: non_neg_integer(), - MilliSeconds :: non_neg_integer(). + +-spec hms(Hours, Minutes, Seconds) -> MilliSeconds + when Hours :: non_neg_integer(), + Minutes :: non_neg_integer(), + Seconds :: non_neg_integer(), + MilliSeconds :: non_neg_integer(). hms(H, M, S) -> hours(H) + minutes(M) + seconds(S). -%% +%% %% Start/init functions %% -%% Start is only included because of backward compatibility! -spec start() -> 'ok'. start() -> - ensure_started(). + {ok, _Pid} = do_start(), + ok. + +do_start() -> + case + supervisor:start_child( + kernel_sup, + #{ + id => timer_server, + start => {?MODULE, start_link, []}, + restart => permanent, + shutdown => 1000, + type => worker, + modules => [?MODULE] + } + ) + of + {ok, Pid} -> + {ok, Pid}; + {ok, Pid, _} -> + {ok, Pid}; + {error, {already_started, Pid}} -> + {ok, Pid}; + {error, already_present} -> + case supervisor:restart_child(kernel_sup, timer_server) of + {ok, Pid} -> + {ok, Pid}; + {error, {already_started, Pid}} -> + {ok, Pid} + end; + Error -> + Error + end. -spec start_link() -> {'ok', pid()} | {'error', term()}. start_link() -> - gen_server:start_link({local, timer_server}, ?MODULE, [], []). + gen_server:start_link({local, timer_server}, ?MODULE, [], []). --spec init([]) -> {'ok', [], 'infinity'}. +-spec init([]) -> {'ok', ets:tid()}. init([]) -> process_flag(trap_exit, true), - ?TIMER_TAB = ets:new(?TIMER_TAB, [named_table,ordered_set,protected]), - ?INTERVAL_TAB = ets:new(?INTERVAL_TAB, [named_table,protected]), - {ok, [], infinity}. - --spec ensure_started() -> 'ok'. -ensure_started() -> - case whereis(timer_server) of - undefined -> - C = {timer_server, {?MODULE, start_link, []}, permanent, 1000, - worker, [?MODULE]}, - _ = supervisor:start_child(kernel_safe_sup, C), - ok; - _ -> ok - end. + Tab = ets:new(?MODULE, []), + {ok, Tab}. %% server calls +%% Try sending a call. If it fails with reason noproc, +%% try starting the timer server and try once again. req(Req, Arg) -> - SysTime = system_time(), - ensure_started(), - gen_server:call(timer_server, {Req, Arg, SysTime}, infinity). + try + maybe_req(Req, Arg) + catch + exit:{noproc, _} -> + {ok, _Pid} = do_start(), + maybe_req(Req, Arg) + end. -%% -%% handle_call(Request, From, Timers) -> -%% {reply, Response, Timers, Timeout} -%% -%% Time and Timeout is in milliseconds. Started is in microseconds. -%% --type timers() :: term(). % XXX: refine? - --spec handle_call(term(), term(), timers()) -> - {'reply', term(), timers(), timeout()} | {'noreply', timers(), timeout()}. -handle_call({apply_after, {Time, Op}, Started}, _From, _Ts) - when is_integer(Time), Time >= 0 -> - BRef = {Started + 1000*Time, make_ref()}, - Timer = {BRef, timeout, Op}, - ets:insert(?TIMER_TAB, Timer), - Timeout = timer_timeout(system_time()), - {reply, {ok, BRef}, [], Timeout}; -handle_call({apply_interval, {Time, To, MFA}, Started}, _From, _Ts) - when is_integer(Time), Time >= 0 -> - %% To must be a pid or a registered name - case get_pid(To) of - Pid when is_pid(Pid) -> - catch link(Pid), - SysTime = system_time(), - Ref = make_ref(), - BRef1 = {interval, Ref}, - Interval = Time*1000, - BRef2 = {Started + Interval, Ref}, - Timer = {BRef2, {repeat, Interval, Pid}, MFA}, - ets:insert(?INTERVAL_TAB, {BRef1,BRef2,Pid}), - ets:insert(?TIMER_TAB, Timer), - Timeout = timer_timeout(SysTime), - {reply, {ok, BRef1}, [], Timeout}; - _ -> - {reply, {error, badarg}, [], next_timeout()} - end; -handle_call({cancel, BRef = {_Time, Ref}, _}, _From, Ts) - when is_reference(Ref) -> - delete_ref(BRef), - {reply, {ok, cancel}, Ts, next_timeout()}; -handle_call({cancel, _BRef, _}, _From, Ts) -> - {reply, {error, badarg}, Ts, next_timeout()}; -handle_call({apply_after, _, _}, _From, Ts) -> - {reply, {error, badarg}, Ts, next_timeout()}; -handle_call({apply_interval, _, _}, _From, Ts) -> - {reply, {error, badarg}, Ts, next_timeout()}; -handle_call(_Else, _From, Ts) -> % Catch anything else - {noreply, Ts, next_timeout()}. - --spec handle_info(term(), timers()) -> {'noreply', timers(), timeout()}. -handle_info(timeout, Ts) -> % Handle timeouts - Timeout = timer_timeout(system_time()), - {noreply, Ts, Timeout}; -handle_info({'EXIT', Pid, _Reason}, Ts) -> % Oops, someone died - pid_delete(Pid), - {noreply, Ts, next_timeout()}; -handle_info(_OtherMsg, Ts) -> % Other Msg's - {noreply, Ts, next_timeout()}. - --spec handle_cast(term(), timers()) -> {'noreply', timers(), timeout()}. -handle_cast(_Req, Ts) -> % Not predicted but handled - {noreply, Ts, next_timeout()}. - --spec terminate(term(), _State) -> 'ok'. -terminate(_Reason, _State) -> - ok. +maybe_req(Req, Arg) -> + gen_server:call(timer_server, {Req, Arg}, infinity). + +%% Call handling. +-spec handle_call(term(), term(), Tab) -> + {'reply', term(), Tab} | {'noreply', Tab} when + Tab :: ets:tid(). +%% Start a one-shot timer. +handle_call({apply_once, {Started, Time, MFA}}, _From, Tab) -> + Timeout = Started + Time, + Reply = try + erlang:start_timer(Timeout, self(), {apply_once, MFA}, + [{abs, true}]) + of + SRef -> + ets:insert(Tab, {SRef}), + {ok, {once, SRef}} + catch + error:badarg -> + {error, badarg} + end, + {reply, Reply, Tab}; +%% Start an interval timer. +handle_call({apply_interval, {Started, Time, Pid, MFA}}, _From, Tab) -> + {TRef, TPid, Tag} = start_interval_loop(Started, Time, Pid, MFA, false), + ets:insert(Tab, {TRef, TPid, Tag}), + {reply, {ok, {interval, TRef}}, Tab}; +handle_call({apply_repeatedly, {Started, Time, Pid, MFA}}, _From, Tab) -> + {TRef, TPid, Tag} = start_interval_loop(Started, Time, Pid, MFA, true), + ets:insert(Tab, {TRef, TPid, Tag}), + {reply, {ok, {interval, TRef}}, Tab}; +%% Cancel a one-shot timer. +handle_call({cancel, {once, TRef}}, _From, Tab) -> + _ = remove_timer(TRef, Tab), + {reply, {ok, cancel}, Tab}; +%% Cancel an interval timer. +handle_call({cancel, {interval, TRef}}, _From, Tab) -> + _ = case remove_timer(TRef, Tab) of + true -> + demonitor(TRef, [flush]); + false -> + ok + end, + {reply, {ok, cancel}, Tab}; +%% Unexpected. +handle_call(_Req, _From, Tab) -> + {noreply, Tab}. + +%% Info handling. +-spec handle_info(term(), Tab) -> {'noreply', Tab} + when Tab :: ets:tid(). +%% One-shot timer timeout. +handle_info({timeout, TRef, {apply_once, MFA}}, Tab) -> + _ = case ets:take(Tab, TRef) of + [{TRef}] -> + do_apply(MFA, false); + [] -> + ok + end, + {noreply, Tab}; +%% An interval timer loop process died. +handle_info({'DOWN', TRef, process, _Pid, _Reason}, Tab) -> + _ = remove_timer(TRef, Tab), + {noreply, Tab}; +%% Unexpected. +handle_info(_Req, Tab) -> + {noreply, Tab}. + +%% Cast handling. +-spec handle_cast(term(), Tab) -> {'noreply', Tab} + when Tab :: ets:tid(). +%% Unexpected. +handle_cast(_Req, Tab) -> + {noreply, Tab}. + +-spec terminate(term(), _Tab) -> 'ok'. +terminate(_Reason, undefined) -> + ok; +terminate(Reason, Tab) -> + _ = ets:foldl(fun + ({TRef}, Acc) -> + _ = cancel_timer(TRef), + Acc; + ({_TRef, TPid, Tag}, Acc) -> + TPid ! {cancel, Tag}, + Acc + end, + undefined, + Tab), + true = ets:delete(Tab), + terminate(Reason, undefined). -spec code_change(term(), State, term()) -> {'ok', State}. -code_change(_OldVsn, State, _Extra) -> +code_change(_OldVsn, Tab, _Extra) -> %% According to the man for gen server no timer can be set here. - {ok, State}. - -%% -%% timer_timeout(SysTime) -%% -%% Apply and remove already timed-out timers. A timer is a tuple -%% {Time, BRef, Op, MFA}, where Time is in microseconds. -%% Returns {Timeout, Timers}, where Timeout is in milliseconds. -%% -timer_timeout(SysTime) -> - case ets:first(?TIMER_TAB) of - '$end_of_table' -> - infinity; - {Time, _Ref} when Time > SysTime -> - Timeout = (Time - SysTime + 999) div 1000, - %% Returned timeout must fit in a small int - erlang:min(Timeout, ?MAX_TIMEOUT); - Key -> - case ets:lookup(?TIMER_TAB, Key) of - [{Key, timeout, MFA}] -> - ets:delete(?TIMER_TAB,Key), - do_apply(MFA), - timer_timeout(SysTime); - [{{Time, Ref}, Repeat = {repeat, Interv, To}, MFA}] -> - ets:delete(?TIMER_TAB,Key), - NewTime = Time + Interv, - %% Update the interval entry (last in table) - ets:insert(?INTERVAL_TAB,{{interval,Ref},{NewTime,Ref},To}), - do_apply(MFA), - ets:insert(?TIMER_TAB, {{NewTime, Ref}, Repeat, MFA}), - timer_timeout(SysTime) - end + {ok, Tab}. + +start_interval_loop(Started, Time, TargetPid, MFA, WaitComplete) -> + Tag = make_ref(), + TimeServerPid = self(), + {TPid, TRef} = spawn_monitor(fun() -> + TimeServerRef = monitor(process, TimeServerPid), + TargetRef = monitor(process, TargetPid), + TimerRef = schedule_interval_timer(Started, Time, + MFA), + _ = interval_loop(TimeServerRef, TargetRef, Tag, + WaitComplete, TimerRef) + end), + {TRef, TPid, Tag}. + +%% Interval timer loop. +interval_loop(TimerServerMon, TargetMon, Tag, WaitComplete, TimerRef0) -> + receive + {cancel, Tag} -> + ok = cancel_timer(TimerRef0); + {'DOWN', TimerServerMon, process, _, _} -> + ok = cancel_timer(TimerRef0); + {'DOWN', TargetMon, process, _, _} -> + ok = cancel_timer(TimerRef0); + {timeout, TimerRef0, {apply_interval, CurTimeout, Time, MFA}} -> + case do_apply(MFA, WaitComplete) of + {ok, {spawn, ActionMon}} -> + receive + {cancel, Tag} -> + ok; + {'DOWN', TimerServerMon, process, _, _} -> + ok; + {'DOWN', TargetMon, process, _, _} -> + ok; + {'DOWN', ActionMon, process, _, _} -> + TimerRef1 = schedule_interval_timer(CurTimeout, Time, MFA), + interval_loop(TimerServerMon, TargetMon, Tag, WaitComplete, TimerRef1) + end; + _ -> + TimerRef1 = schedule_interval_timer(CurTimeout, Time, MFA), + interval_loop(TimerServerMon, TargetMon, Tag, WaitComplete, TimerRef1) + end end. -%% -%% delete_ref -%% - -delete_ref(BRef = {interval, _}) -> - case ets:lookup(?INTERVAL_TAB, BRef) of - [{_, BRef2, _Pid}] -> - ets:delete(?INTERVAL_TAB, BRef), - ets:delete(?TIMER_TAB, BRef2); - _ -> % TimerReference does not exist, do nothing - ok - end; -delete_ref(BRef) -> - ets:delete(?TIMER_TAB, BRef). - -%% -%% pid_delete -%% - --spec pid_delete(pid()) -> 'ok'. -pid_delete(Pid) -> - IntervalTimerList = - ets:select(?INTERVAL_TAB, - [{{'_', '_','$1'}, - [{'==','$1',Pid}], - ['$_']}]), - lists:foreach(fun({IntKey, TimerKey, _ }) -> - ets:delete(?INTERVAL_TAB, IntKey), - ets:delete(?TIMER_TAB, TimerKey) - end, IntervalTimerList). - -%% Calculate time to the next timeout. Returned timeout must fit in a -%% small int. - --spec next_timeout() -> timeout(). -next_timeout() -> - case ets:first(?TIMER_TAB) of - '$end_of_table' -> - infinity; - {Time, _} -> - erlang:min(positive((Time - system_time() + 999) div 1000), ?MAX_TIMEOUT) +schedule_interval_timer(CurTimeout, Time, MFA) -> + NextTimeout = CurTimeout + Time, + case NextTimeout =< system_time() of + true -> + TimerRef = make_ref(), + self() ! {timeout, TimerRef, {apply_interval, NextTimeout, Time, MFA}}, + TimerRef; + false -> + erlang:start_timer(NextTimeout, self(), {apply_interval, NextTimeout, Time, MFA}, [{abs, true}]) end. -%% Help functions -do_apply({M,F,A}) -> - case {M, F, A} of - {?MODULE, send, A} -> - %% If send op. send directly, (faster than spawn) - catch send(A); - {erlang, exit, [Name, Reason]} -> - catch exit(get_pid(Name), Reason); - _ -> - %% else spawn process with the operation - catch spawn(M,F,A) +%% Remove a timer. +remove_timer(TRef, Tab) -> + case ets:take(Tab, TRef) of + [{TRef}] -> % One-shot timer. + ok = cancel_timer(TRef), + true; + [{TRef, TPid, Tag}] -> % Interval timer. + TPid ! {cancel, Tag}, + true; + [] -> % TimerReference does not exist, do nothing + false end. -positive(X) -> - erlang:max(X, 0). +%% Cancel a timer. +cancel_timer(TRef) -> + erlang:cancel_timer(TRef, [{async, true}, {info, false}]). +%% Help functions -%% -%% system_time() -> time in microseconds -%% +%% If send op. send directly (faster than spawn) +do_apply({?MODULE, send, A}, _) -> + try send(A) + of _ -> {ok, send} + catch _:_ -> error + end; +%% If exit op. resolve registered name +do_apply({erlang, exit, [Name, Reason]}, _) -> + try exit(get_pid(Name), Reason) + of _ -> {ok, exit} + catch _:_ -> error + end; +do_apply({M,F,A}, false) -> + try spawn(M, F, A) + of _ -> {ok, spawn} + catch error:badarg -> error + end; +do_apply({M, F, A}, true) -> + try spawn_monitor(M, F, A) + of {_, Ref} -> {ok, {spawn, Ref}} + catch error:badarg -> error + end. + +%% Get current time in milliseconds, +%% ceil'ed to the next millisecond. system_time() -> - erlang:monotonic_time(1000000). + (erlang:monotonic_time(microsecond) + 999) div 1000. send([Pid, Msg]) -> Pid ! Msg. +%% Resolve a registered name. get_pid(Name) when is_pid(Name) -> Name; get_pid(undefined) -> @@ -455,22 +626,3 @@ get_pid(Name) when is_atom(Name) -> get_pid(whereis(Name)); get_pid(_) -> undefined. - -%% -%% get_status() -> -%% {{TimerTabName,TotalNumTimers},{IntervalTabName,NumIntervalTimers}} -%% -%% This function is for test purposes only; it is used by the test suite. -%% There is a small possibility that there is a mismatch of one entry -%% between the 2 tables if this call is made when the timer server is -%% in the middle of a transaction - --spec get_status() -> - {{?TIMER_TAB,non_neg_integer()},{?INTERVAL_TAB,non_neg_integer()}}. - -get_status() -> - Info1 = ets:info(?TIMER_TAB), - {size,TotalNumTimers} = lists:keyfind(size, 1, Info1), - Info2 = ets:info(?INTERVAL_TAB), - {size,NumIntervalTimers} = lists:keyfind(size, 1, Info2), - {{?TIMER_TAB,TotalNumTimers},{?INTERVAL_TAB,NumIntervalTimers}}. diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index 7ae5dec87896..d2a1edce3d86 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -91,9 +91,9 @@ characters_to_binary(_, _) -> -spec characters_to_list(Data, InEncoding) -> Result when Data :: latin1_chardata() | chardata() | external_chardata(), InEncoding :: encoding(), - Result :: list() - | {error, list(), RestData} - | {incomplete, list(), binary()}, + Result ::string() + | {error, string(), RestData} + | {incomplete, string(), binary()}, RestData :: latin1_chardata() | chardata() | external_chardata(). characters_to_list(_, _) -> @@ -103,9 +103,9 @@ characters_to_list(_, _) -> -spec characters_to_list(Data) -> Result when Data :: latin1_chardata() | chardata() | external_chardata(), - Result :: list() - | {error, list(), RestData} - | {incomplete, list(), binary()}, + Result :: string() + | {error, string(), RestData} + | {incomplete, string(), binary()}, RestData :: latin1_chardata() | chardata() | external_chardata(). characters_to_list(ML) -> @@ -390,6 +390,8 @@ characters_to_binary_int(ML, InEncoding) -> fake_stacktrace(Reason, characters_to_binary, [ML, InEncoding]) end. +-spec fake_stacktrace(term(), atom(), [term()]) -> no_return(). + fake_stacktrace(Reason, Name, Args) -> try error(new_stacktrace, Args) @@ -442,10 +444,12 @@ characters_to_binary_int(ML, InEncoding, OutEncoding) -> {error, Accum, [Part]} end,<<>>), case Res of + Bin when is_binary(Bin) -> + Bin; {incomplete,A,B,_} -> {incomplete,A,B}; - _ -> - Res + {error, _Converted, _Rest} = Error -> + Error end. @@ -525,14 +529,7 @@ ml_map([Part|_] = Whole,_,{{Incomplete, _}, Accum}) when is_integer(Part) -> ml_map([Part|T],Fun,Accum) when is_integer(Part) -> case Fun(Part,Accum) of Bin when is_binary(Bin) -> - case ml_map(T,Fun,Bin) of - Bin2 when is_binary(Bin2) -> - Bin2; - {error, Converted, Rest} -> - {error, Converted, Rest}; - {incomplete, Converted, Rest,X} -> - {incomplete, Converted, Rest,X} - end; + ml_map(T,Fun,Bin); % Can not be incomplete - it's an integer {error, Converted, Rest} -> {error, Converted, [Rest|T]} diff --git a/lib/stdlib/src/uri_string.erl b/lib/stdlib/src/uri_string.erl index 3060f2bfaa1c..dbbb835036c7 100644 --- a/lib/stdlib/src/uri_string.erl +++ b/lib/stdlib/src/uri_string.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017-2020. All Rights Reserved. +%% Copyright Ericsson AB 2017-2022. 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. @@ -237,7 +237,10 @@ recompose/1, resolve/2, resolve/3, - transcode/2]). + transcode/2, + quote/1, + quote/2, + unquote/1]). -export_type([error/0, uri_map/0, uri_string/0]). @@ -518,6 +521,29 @@ percent_decode(URI) when is_list(URI) orelse is_binary(URI) -> raw_decode(URI). +-spec quote(Data) -> QuotedData when + Data :: unicode:chardata(), + QuotedData :: unicode:chardata(). +quote(D) -> + encode(D, fun is_unreserved/1). + +-spec quote(Data, Safe) -> QuotedData when + Data :: unicode:chardata(), + Safe :: string(), + QuotedData :: unicode:chardata(). +quote(D, Safe) -> + UnreservedOrSafe = + fun(C) -> + is_unreserved(C) orelse lists:member(C, Safe) + end, + encode(D, UnreservedOrSafe). + +-spec unquote(QuotedData) -> Data when + QuotedData :: unicode:chardata(), + Data :: unicode:chardata(). +unquote(D) -> + raw_decode(D). + %%------------------------------------------------------------------------- %% Functions for working with the query part of a URI as a list %% of key/value pairs. @@ -2216,8 +2242,9 @@ base10_decode_unicode(<>, _, _) -> normalize_map(URIMap) -> normalize_path_segment( normalize_scheme_based( - normalize_percent_encoding( - normalize_case(URIMap)))). + normalize_undefined_port( + normalize_percent_encoding( + normalize_case(URIMap))))). %% 6.2.2.1. Case Normalization @@ -2357,28 +2384,30 @@ normalize_scheme_based(Map, _, _, _) -> normalize_http(Map, Port, Path) -> - M1 = normalize_port(Map, Port, 80), + M1 = normalize_default_port(Map, Port, 80), normalize_http_path(M1, Path). normalize_https(Map, Port, Path) -> - M1 = normalize_port(Map, Port, 443), + M1 = normalize_default_port(Map, Port, 443), normalize_http_path(M1, Path). normalize_ftp(Map, Port) -> - normalize_port(Map, Port, 21). + normalize_default_port(Map, Port, 21). normalize_ssh_sftp(Map, Port) -> - normalize_port(Map, Port, 22). + normalize_default_port(Map, Port, 22). normalize_tftp(Map, Port) -> - normalize_port(Map, Port, 69). + normalize_default_port(Map, Port, 69). -normalize_port(Map, Port, Default) -> +%% RFC 3986, 3.2.3. Port +%% RFC 3986, 6.2.3. Scheme-Based Normalization +normalize_default_port(Map, Port, Default) -> case Port of Default -> maps:remove(port, Map); @@ -2387,6 +2416,12 @@ normalize_port(Map, Port, Default) -> end. +normalize_undefined_port(#{port := undefined} = Map) -> + maps:remove(port, Map); +normalize_undefined_port(#{} = Map) -> + Map. + + normalize_http_path(Map, Path) -> case Path of "" -> diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl index 4c606761babb..0809dbb492b4 100644 --- a/lib/stdlib/src/zip.erl +++ b/lib/stdlib/src/zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -35,7 +35,7 @@ %% zip server -export([zip_open/1, zip_open/2, - zip_get/1, zip_get/2, + zip_get/1, zip_get/2, zip_get_crc32/2, zip_t/1, zip_tt/1, zip_list_dir/1, zip_list_dir/2, zip_close/1]). @@ -51,7 +51,7 @@ -define(WRITE_BLOCK_SIZE, 8*1024). %% for debugging, to turn off catch --define(CATCH, catch). +-define(CATCH(Expr), (catch (Expr))). %% Debug. -define(SHOW_GP_BIT_11(B, F), ok). @@ -227,7 +227,7 @@ openzip_open(F) -> openzip_open(F, []). openzip_open(F, Options) -> - case ?CATCH do_openzip_open(F, Options) of + case ?CATCH(do_openzip_open(F, Options)) of {ok, OpenZip} -> {ok, OpenZip}; Error -> @@ -252,7 +252,7 @@ do_openzip_open(F, Options) -> %% retrieve all files from an open archive openzip_get(OpenZip) -> - case ?CATCH do_openzip_get(OpenZip) of + case ?CATCH(do_openzip_get(OpenZip)) of {ok, Result} -> {ok, Result}; Error -> {error, Error} end. @@ -267,9 +267,16 @@ do_openzip_get(#openzip{files = Files, in = In0, input = Input, do_openzip_get(_) -> throw(einval). +%% retrieve the crc32 checksum from an open archive +openzip_get_crc32(FileName, #openzip{files = Files}) -> + case file_name_search(FileName, Files) of + {_,#zip_file_extra{crc32=CRC}} -> {ok, CRC}; + _ -> throw(file_not_found) + end. + %% retrieve a file from an open archive openzip_get(FileName, OpenZip) -> - case ?CATCH do_openzip_get(FileName, OpenZip) of + case ?CATCH(do_openzip_get(FileName, OpenZip)) of {ok, Result} -> {ok, Result}; Error -> {error, Error} end. @@ -372,7 +379,7 @@ unzip(F) -> unzip(F, []). | {error, {Name :: file:name(), Reason :: term()}}). unzip(F, Options) -> - case ?CATCH do_unzip(F, Options) of + case ?CATCH(do_unzip(F, Options)) of {ok, R} -> {ok, R}; Error -> {error, Error} end. @@ -452,7 +459,7 @@ zip(F, Files) -> zip(F, Files, []). | {error, Reason :: term()}). zip(F, Files, Options) -> - case ?CATCH do_zip(F, Files, Options) of + case ?CATCH(do_zip(F, Files, Options)) of {ok, R} -> {ok, R}; Error -> {error, Error} end. @@ -496,7 +503,7 @@ list_dir(F) -> list_dir(F, []). Option :: cooked). list_dir(F, Options) -> - case ?CATCH do_list_dir(F, Options) of + case ?CATCH(do_list_dir(F, Options)) of {ok, R} -> {ok, R}; Error -> {error, Error} end. @@ -521,7 +528,7 @@ t(F) when is_record(F, openzip) -> openzip_t(F); t(F) -> t(F, fun raw_short_print_info_etc/5). t(F, RawPrint) -> - case ?CATCH do_t(F, RawPrint) of + case ?CATCH(do_t(F, RawPrint)) of ok -> ok; Error -> {error, Error} end. @@ -1165,6 +1172,9 @@ server_loop(Parent, OpenZip) -> {From, {get, FileName}} -> From ! {self(), openzip_get(FileName, OpenZip)}, server_loop(Parent, OpenZip); + {From, {get_crc32, FileName}} -> + From ! {self(), openzip_get_crc32(FileName, OpenZip)}, + server_loop(Parent, OpenZip); {From, list_dir} -> From ! {self(), openzip_list_dir(OpenZip)}, server_loop(Parent, OpenZip); @@ -1223,6 +1233,15 @@ zip_close(Pid) when is_pid(Pid) -> zip_get(FileName, Pid) when is_pid(Pid) -> request(self(), Pid, {get, FileName}). +-spec(zip_get_crc32(FileName, ZipHandle) -> {ok, CRC} | {error, Reason} when + FileName :: file:name(), + ZipHandle :: handle(), + CRC :: non_neg_integer(), + Reason :: term()). + +zip_get_crc32(FileName, Pid) when is_pid(Pid) -> + request(self(), Pid, {get_crc32, FileName}). + -spec(zip_list_dir(ZipHandle) -> {ok, Result} | {error, Reason} when Result :: [zip_comment() | zip_file()], ZipHandle :: handle(), @@ -1543,7 +1562,7 @@ get_z_data(?DEFLATED, In0, FileName, CompSize, Input, Output, OpO, Z) -> Out0 = Output({open, FileName, [write | OpO]}, []), CRC0 = 0, {In1, Out1, UncompSize, CRC} = get_z_data_loop(CompSize, 0, In0, Out0, Input, Output, CRC0, Z), - ?CATCH zlib:inflateEnd(Z), + _ = ?CATCH(zlib:inflateEnd(Z)), Out2 = Output({close, FileName}, Out1), {Out2, In1, CRC, UncompSize}; get_z_data(?STORED, In0, FileName, CompSize, Input, Output, OpO, _Z) -> diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index bda16c263d81..bdac775256e6 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -7,9 +7,12 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk MODULES= \ array_SUITE \ + argparse_SUITE \ base64_SUITE \ + base64_property_test_SUITE \ beam_lib_SUITE \ binary_module_SUITE \ + binary_property_test_SUITE \ binref \ c_SUITE \ calendar_SUITE \ @@ -22,6 +25,7 @@ MODULES= \ dummy_h \ dummy_via \ edlin_expand_SUITE \ + edlin_context_SUITE \ epp_SUITE \ erl_anno_SUITE \ erl_eval_SUITE \ @@ -48,14 +52,17 @@ MODULES= \ io_SUITE \ io_proto_SUITE \ lists_SUITE \ + lists_property_test_SUITE \ log_mf_h_SUITE \ math_SUITE \ ms_transform_SUITE \ + peer_SUITE \ pool_SUITE \ proc_lib_SUITE \ proplists_SUITE \ qlc_SUITE \ queue_SUITE \ + queue_property_test_SUITE \ rand_SUITE \ random_SUITE \ re_SUITE \ @@ -100,8 +107,15 @@ MODULES= \ zzz_SUITE ERTS_MODULES= erts_test_utils +SASL_MODULES= otp_vsns +KERNEL_MODULES= rtnode -ERL_FILES= $(MODULES:%=%.erl) $(ERTS_MODULES:%=$(ERL_TOP)/erts/emulator/test/%.erl) +ERL_FILES= $(MODULES:%=%.erl) \ + $(ERTS_MODULES:%=$(ERL_TOP)/erts/emulator/test/%.erl) \ + $(SASL_MODULES:%=$(ERL_TOP)/lib/sasl/test/%.erl) \ + $(KERNEL_MODULES:%=$(ERL_TOP)/lib/kernel/test/%.erl) + +EXTRA_FILES= $(ERL_TOP)/otp_versions.table # ---------------------------------------------------- # Release directory specification @@ -112,24 +126,25 @@ RELSYSDIR = $(RELEASE_PATH)/stdlib_test # FLAGS # ---------------------------------------------------- -ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/include \ -I$(ERL_TOP)/lib/stdlib/include +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . EMAKEFILE=Emakefile -COVERFILE=stdlib.cover +COVERFILE=stdlib.cover tty.cover # ---------------------------------------------------- # Targets # ---------------------------------------------------- make_emakefile: - $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) $(ERTS_MODULES) \ + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) \ + $(MODULES) $(ERTS_MODULES) $(SASL_MODULES) $(KERNEL_MODULES) \ > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: @@ -148,9 +163,11 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) stdlib.spec stdlib_bench.spec error_info.spec $(EMAKEFILE) \ - $(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)" + $(INSTALL_DATA) stdlib.spec stdlib_bench.spec stdlib_gh.spec error_info.spec $(EMAKEFILE) \ + $(ERL_FILES) $(COVERFILE) $(EXTRA_FILES) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -) + $(INSTALL_DIR) "$(RELSYSDIR)/stdlib_SUITE_data" + $(INSTALL_DATA) $(ERL_TOP)/make/otp_version_tickets "$(RELSYSDIR)/stdlib_SUITE_data" release_docs_spec: diff --git a/lib/stdlib/test/argparse_SUITE.erl b/lib/stdlib/test/argparse_SUITE.erl new file mode 100644 index 000000000000..a63b8867d25f --- /dev/null +++ b/lib/stdlib/test/argparse_SUITE.erl @@ -0,0 +1,1063 @@ +%% +%% +%% Copyright Maxim Fedorov +%% +%% +%% 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. + +-module(argparse_SUITE). +-author("maximfca@gmail.com"). + +-export([suite/0, all/0, groups/0]). + +-export([ + readme/0, readme/1, + basic/0, basic/1, + long_form_eq/0, long_form_eq/1, + built_in_types/0, built_in_types/1, + type_validators/0, type_validators/1, + invalid_arguments/0, invalid_arguments/1, + complex_command/0, complex_command/1, + unicode/0, unicode/1, + parser_error/0, parser_error/1, + nargs/0, nargs/1, + argparse/0, argparse/1, + negative/0, negative/1, + nodigits/0, nodigits/1, + pos_mixed_with_opt/0, pos_mixed_with_opt/1, + default_for_not_required/0, default_for_not_required/1, + global_default/0, global_default/1, + subcommand/0, subcommand/1, + very_short/0, very_short/1, + multi_short/0, multi_short/1, + proxy_arguments/0, proxy_arguments/1, + + usage/0, usage/1, + usage_required_args/0, usage_required_args/1, + usage_template/0, usage_template/1, + parser_error_usage/0, parser_error_usage/1, + command_usage/0, command_usage/1, + usage_width/0, usage_width/1, + + validator_exception/0, validator_exception/1, + validator_exception_format/0, validator_exception_format/1, + + run_handle/0, run_handle/1 +]). + +-include_lib("stdlib/include/assert.hrl"). + +suite() -> + [{timetrap, {seconds, 30}}]. + +groups() -> + [ + {parser, [parallel], [ + readme, basic, long_form_eq, built_in_types, type_validators, + invalid_arguments, complex_command, unicode, parser_error, + nargs, argparse, negative, nodigits, pos_mixed_with_opt, + default_for_not_required, global_default, subcommand, + very_short, multi_short, proxy_arguments + ]}, + {usage, [parallel], [ + usage, usage_required_args, usage_template, + parser_error_usage, command_usage, usage_width + ]}, + {validator, [parallel], [ + validator_exception, validator_exception_format + ]}, + {run, [parallel], [ + run_handle + ]} + ]. + +all() -> + [{group, parser}, {group, validator}, {group, usage}]. + +%%-------------------------------------------------------------------- +%% Helpers + +prog() -> + {ok, [[ProgStr]]} = init:get_argument(progname), ProgStr. + +parser_error(CmdLine, CmdMap) -> + {error, Reason} = parse(CmdLine, CmdMap), + unicode:characters_to_list(argparse:format_error(Reason)). + +parse_opts(Args, Opts) -> + argparse:parse(string:lexemes(Args, " "), #{arguments => Opts}). + +parse(Args, Command) -> + argparse:parse(string:lexemes(Args, " "), Command). + +parse_cmd(Args, Command) -> + argparse:parse(string:lexemes(Args, " "), #{commands => Command}). + +%% ubiquitous command, containing sub-commands, and all possible option types +%% with all nargs. Not all combinations though. +ubiq_cmd() -> + #{ + arguments => [ + #{name => r, short => $r, type => boolean, help => "recursive"}, + #{name => f, short => $f, type => boolean, long => "-force", help => "force"}, + #{name => v, short => $v, type => boolean, action => count, help => "verbosity level"}, + #{name => interval, short => $i, type => {integer, [{min, 1}]}, help => "interval set"}, + #{name => weird, long => "-req", help => "required optional, right?"}, + #{name => float, long => "-float", type => float, default => 3.14, help => "floating-point long form argument"} + ], + commands => #{ + "start" => #{help => "verifies configuration and starts server", + arguments => [ + #{name => server, help => "server to start"}, + #{name => shard, short => $s, type => integer, nargs => nonempty_list, help => "initial shards"}, + #{name => part, short => $p, type => integer, nargs => list, help => hidden}, + #{name => z, short => $z, type => {integer, [{min, 1}, {max, 10}]}, help => "between"}, + #{name => l, short => $l, type => {integer, [{max, 10}]}, nargs => 'maybe', help => "maybe lower"}, + #{name => more, short => $m, type => {integer, [{max, 10}]}, help => "less than 10"}, + #{name => optpos, required => false, type => {integer, []}, help => "optional positional"}, + #{name => bin, short => $b, type => {binary, <<"m">>}, help => "binary with re"}, + #{name => g, short => $g, type => {binary, <<"m">>, []}, help => "binary with re"}, + #{name => t, short => $t, type => {string, "m"}, help => "string with re"}, + #{name => e, long => "--maybe-req", required => true, type => integer, nargs => 'maybe', help => "maybe required int"}, + #{name => y, required => true, long => "-yyy", short => $y, type => {string, "m", []}, help => "string with re"}, + #{name => u, short => $u, type => {string, ["1", "2"]}, help => "string choices"}, + #{name => choice, short => $c, type => {integer, [1,2,3]}, help => "tough choice"}, + #{name => fc, short => $q, type => {float, [2.1,1.2]}, help => "floating choice"}, + #{name => ac, short => $w, type => {atom, [one, two]}, help => "atom choice"}, + #{name => au, long => "-unsafe", type => {atom, unsafe}, help => "unsafe atom"}, + #{name => as, long => "-safe", type => atom, help => <<"safe atom">>}, + #{name => name, required => false, nargs => list, help => hidden}, + #{name => long, long => "foobar", required => false, help => [<<"foobaring option">>]} + ], commands => #{ + "crawler" => #{arguments => [ + #{name => extra, long => "--extra", help => "extra option very deep"} + ], + help => "controls crawler behaviour"}, + "doze" => #{help => "dozes a bit"}} + }, + "stop" => #{help => <<"stops running server">>, arguments => [] + }, + "status" => #{help => "prints server status", arguments => [], + commands => #{ + "crawler" => #{ + arguments => [#{name => extra, long => "--extra", help => "extra option very deep"}], + help => "crawler status"}} + }, + "restart" => #{help => hidden, arguments => [ + #{name => server, help => "server to restart"}, + #{name => duo, short => $d, long => "-duo", help => "dual option"} + ]} + } + }. + +%%-------------------------------------------------------------------- +%% Parser Test Cases + +readme() -> + [{doc, "Test cases covered in the README"}]. + +readme(Config) when is_list(Config) -> + Prog = prog(), + Rm = #{ + arguments => [ + #{name => dir}, + #{name => force, short => $f, type => boolean, default => false}, + #{name => recursive, short => $r, type => boolean} + ] + }, + ?assertEqual({ok, #{dir => "dir", force => true, recursive => true}, [Prog], Rm}, + argparse:parse(["-rf", "dir"], Rm)), + %% override progname + ?assertEqual("Usage:\n readme\n", + unicode:characters_to_list(argparse:help(#{}, #{progname => "readme"}))), + ?assertEqual("Usage:\n readme\n", + unicode:characters_to_list(argparse:help(#{}, #{progname => readme}))), + ?assertEqual("Usage:\n readme\n", + unicode:characters_to_list(argparse:help(#{}, #{progname => <<"readme">>}))), + %% test that command has priority over just a positional argument: + %% - parsing "opt sub" means "find positional argument "pos", then enter subcommand + %% - parsing "sub opt" means "enter sub-command, and then find positional argument" + Cmd = #{ + commands => #{"sub" => #{}}, + arguments => [#{name => pos}] + }, + ?assertEqual(parse("opt sub", Cmd), parse("sub opt", Cmd)). + +basic() -> + [{doc, "Basic cases"}]. + +basic(Config) when is_list(Config) -> + Prog = prog(), + %% empty command, with full options path + ?assertMatch({ok, #{}, [Prog, "cmd"], #{}}, + argparse:parse(["cmd"], #{commands => #{"cmd" => #{}}})), + %% sub-command, with no path, but user-supplied argument + ?assertEqual({ok, #{}, [Prog, "cmd", "sub"], #{attr => pos}}, + argparse:parse(["cmd", "sub"], #{commands => #{"cmd" => #{commands => #{"sub" => #{attr => pos}}}}})), + %% command with positional argument + PosCmd = #{arguments => [#{name => pos}]}, + ?assertEqual({ok, #{pos => "arg"}, [Prog, "cmd"], PosCmd}, + argparse:parse(["cmd", "arg"], #{commands => #{"cmd" => PosCmd}})), + %% command with optional argument + OptCmd = #{arguments => [#{name => force, short => $f, type => boolean}]}, + ?assertEqual({ok, #{force => true}, [Prog, "rm"], OptCmd}, + parse(["rm -f"], #{commands => #{"rm" => OptCmd}}), "rm -f"), + %% command with optional and positional argument + PosOptCmd = #{arguments => [#{name => force, short => $f, type => boolean}, #{name => dir}]}, + ?assertEqual({ok, #{force => true, dir => "dir"}, [Prog, "rm"], PosOptCmd}, + parse(["rm -f dir"], #{commands => #{"rm" => PosOptCmd}}), "rm -f dir"), + %% no command, just argument list + KernelCmd = #{arguments => [#{name => kernel, long => "kernel", type => atom, nargs => 2}]}, + ?assertEqual({ok, #{kernel => [port, dist]}, [Prog], KernelCmd}, + parse(["-kernel port dist"], KernelCmd)), + %% same but positional + ArgListCmd = #{arguments => [#{name => arg, nargs => 2, type => boolean}]}, + ?assertEqual({ok, #{arg => [true, false]}, [Prog], ArgListCmd}, + parse(["true false"], ArgListCmd)). + +long_form_eq() -> + [{doc, "Tests that long form supports --arg=value"}]. + +long_form_eq(Config) when is_list(Config) -> + Prog = prog(), + %% cmd --arg=value + PosOptCmd = #{arguments => [#{name => arg, long => "-arg"}]}, + ?assertEqual({ok, #{arg => "value"}, [Prog, "cmd"], PosOptCmd}, + parse(["cmd --arg=value"], #{commands => #{"cmd" => PosOptCmd}})), + %% --integer=10 + ?assertMatch({ok, #{int := 10}, _, _}, + parse(["--int=10"], #{arguments => [#{name => int, type => integer, long => "-int"}]})). + +built_in_types() -> + [{doc, "Tests all built-in types supplied as a single argument"}]. + +% built-in types testing +built_in_types(Config) when is_list(Config) -> + Prog = [prog()], + Bool = #{arguments => [#{name => meta, type => boolean, short => $b, long => "-boolean"}]}, + ?assertEqual({ok, #{}, Prog, Bool}, parse([""], Bool)), + ?assertEqual({ok, #{meta => true}, Prog, Bool}, parse(["-b"], Bool)), + ?assertEqual({ok, #{meta => true}, Prog, Bool}, parse(["--boolean"], Bool)), + ?assertEqual({ok, #{meta => false}, Prog, Bool}, parse(["--boolean false"], Bool)), + %% integer tests + Int = #{arguments => [#{name => int, type => integer, short => $i, long => "-int"}]}, + ?assertEqual({ok, #{int => 1}, Prog, Int}, parse([" -i 1"], Int)), + ?assertEqual({ok, #{int => 1}, Prog, Int}, parse(["--int 1"], Int)), + ?assertEqual({ok, #{int => -1}, Prog, Int}, parse(["-i -1"], Int)), + %% floating point + Float = #{arguments => [#{name => f, type => float, short => $f}]}, + ?assertEqual({ok, #{f => 44.44}, Prog, Float}, parse(["-f 44.44"], Float)), + %% atoms, existing + Atom = #{arguments => [#{name => atom, type => atom, short => $a, long => "-atom"}]}, + ?assertEqual({ok, #{atom => atom}, Prog, Atom}, parse(["-a atom"], Atom)), + ?assertEqual({ok, #{atom => atom}, Prog, Atom}, parse(["--atom atom"], Atom)). + +type_validators() -> + [{doc, "Test that parser return expected conversions for valid arguments"}]. + +type_validators(Config) when is_list(Config) -> + %% successful string regexes + ?assertMatch({ok, #{str := "me"}, _, _}, + parse_opts("me", [#{name => str, type => {string, "m."}}])), + ?assertMatch({ok, #{str := "me"}, _, _}, + parse_opts("me", [#{name => str, type => {string, "m.", []}}])), + ?assertMatch({ok, #{"str" := "me"}, _, _}, + parse_opts("me", [#{name => "str", type => {string, "m.", [{capture, none}]}}])), + %% and binary too... + ?assertMatch({ok, #{bin := <<"me">>}, _, _}, + parse_opts("me", [#{name => bin, type => {binary, <<"m.">>}}])), + ?assertMatch({ok, #{<<"bin">> := <<"me">>}, _, _}, + parse_opts("me", [#{name => <<"bin">>, type => {binary, <<"m.">>, []}}])), + ?assertMatch({ok, #{bin := <<"me">>}, _, _}, + parse_opts("me", [#{name => bin, type => {binary, <<"m.">>, [{capture, none}]}}])), + %% successful integer with range validators + ?assertMatch({ok, #{int := 5}, _, _}, + parse_opts("5", [#{name => int, type => {integer, [{min, 0}, {max, 10}]}}])), + ?assertMatch({ok, #{bin := <<"5">>}, _, _}, + parse_opts("5", [#{name => bin, type => binary}])), + ?assertMatch({ok, #{str := "011"}, _, _}, + parse_opts("11", [#{name => str, type => {custom, fun(S) -> [$0|S] end}}])), + %% choices: valid + ?assertMatch({ok, #{bin := <<"K">>}, _, _}, + parse_opts("K", [#{name => bin, type => {binary, [<<"M">>, <<"K">>]}}])), + ?assertMatch({ok, #{str := "K"}, _, _}, + parse_opts("K", [#{name => str, type => {string, ["K", "N"]}}])), + ?assertMatch({ok, #{atom := one}, _, _}, + parse_opts("one", [#{name => atom, type => {atom, [one, two]}}])), + ?assertMatch({ok, #{int := 12}, _, _}, + parse_opts("12", [#{name => int, type => {integer, [10, 12]}}])), + ?assertMatch({ok, #{float := 1.3}, _, _}, + parse_opts("1.3", [#{name => float, type => {float, [1.3, 1.4]}}])), + %% test for unsafe atom + %% ensure the atom does not exist + ?assertException(error, badarg, list_to_existing_atom("$can_never_be")), + {ok, ArgMap, _, _} = parse_opts("$can_never_be", [#{name => atom, type => {atom, unsafe}}]), + argparse:validate(#{arguments => [#{name => atom, type => {atom, unsafe}}]}), + %% now that atom exists, because argparse created it (in an unsafe way!) + ?assertEqual(list_to_existing_atom("$can_never_be"), maps:get(atom, ArgMap)), + %% test successful user-defined conversion + ?assertMatch({ok, #{user := "VER"}, _, _}, + parse_opts("REV", [#{name => user, type => {custom, fun (Str) -> lists:reverse(Str) end}}])). + +invalid_arguments() -> + [{doc, "Test that parser return errors for invalid arguments"}]. + +invalid_arguments(Config) when is_list(Config) -> + %% {float, [{min, float()} | {max, float()}]} | + Prog = [prog()], + MinFloat = #{name => float, type => {float, [{min, 1.0}]}}, + ?assertEqual({error, {Prog, MinFloat, "0.0", <<"is less than accepted minimum">>}}, + parse_opts("0.0", [MinFloat])), + MaxFloat = #{name => float, type => {float, [{max, 1.0}]}}, + ?assertEqual({error, {Prog, MaxFloat, "2.0", <<"is greater than accepted maximum">>}}, + parse_opts("2.0", [MaxFloat])), + %% {int, [{min, integer()} | {max, integer()}]} | + MinInt = #{name => int, type => {integer, [{min, 20}]}}, + ?assertEqual({error, {Prog, MinInt, "10", <<"is less than accepted minimum">>}}, + parse_opts("10", [MinInt])), + MaxInt = #{name => int, type => {integer, [{max, -10}]}}, + ?assertEqual({error, {Prog, MaxInt, "-5", <<"is greater than accepted maximum">>}}, + parse_opts("-5", [MaxInt])), + %% string: regex & regex with options + %% {string, string()} | {string, string(), []} + StrRegex = #{name => str, type => {string, "me.me"}}, + ?assertEqual({error, {Prog, StrRegex, "me", <<"does not match">>}}, + parse_opts("me", [StrRegex])), + StrRegexOpt = #{name => str, type => {string, "me.me", []}}, + ?assertEqual({error, {Prog, StrRegexOpt, "me", <<"does not match">>}}, + parse_opts("me", [StrRegexOpt])), + %% {binary, {re, binary()} | {re, binary(), []} + BinRegex = #{name => bin, type => {binary, <<"me.me">>}}, + ?assertEqual({error, {Prog, BinRegex, "me", <<"does not match">>}}, + parse_opts("me", [BinRegex])), + BinRegexOpt = #{name => bin, type => {binary, <<"me.me">>, []}}, + ?assertEqual({error, {Prog, BinRegexOpt, "me", <<"does not match">>}}, + parse_opts("me", [BinRegexOpt])), + %% invalid integer (comma , is not parsed) + ?assertEqual({error, {Prog, MinInt, "1,", <<"is not an integer">>}}, + parse_opts(["1,"], [MinInt])), + %% test invalid choices + BinChoices = #{name => bin, type => {binary, [<<"M">>, <<"N">>]}}, + ?assertEqual({error, {Prog, BinChoices, "K", <<"is not one of the choices">>}}, + parse_opts("K", [BinChoices])), + StrChoices = #{name => str, type => {string, ["M", "N"]}}, + ?assertEqual({error, {Prog, StrChoices, "K", <<"is not one of the choices">>}}, + parse_opts("K", [StrChoices])), + AtomChoices = #{name => atom, type => {atom, [one, two]}}, + ?assertEqual({error, {Prog, AtomChoices, "K", <<"is not one of the choices">>}}, + parse_opts("K", [AtomChoices])), + IntChoices = #{name => int, type => {integer, [10, 11]}}, + ?assertEqual({error, {Prog, IntChoices, "12", <<"is not one of the choices">>}}, + parse_opts("12", [IntChoices])), + FloatChoices = #{name => float, type => {float, [1.2, 1.4]}}, + ?assertEqual({error, {Prog, FloatChoices, "1.3", <<"is not one of the choices">>}}, + parse_opts("1.3", [FloatChoices])), + %% unsuccessful user-defined conversion + ?assertMatch({error, {Prog, _, "REV", <<"failed faildation">>}}, + parse_opts("REV", [#{name => user, type => {custom, fun (Str) -> integer_to_binary(Str) end}}])). + +complex_command() -> + [{doc, "Parses a complex command that has a mix of optional and positional arguments"}]. + +complex_command(Config) when is_list(Config) -> + Command = #{arguments => [ + %% options + #{name => string, short => $s, long => "-string", action => append, help => "String list option"}, + #{name => boolean, type => boolean, short => $b, action => append, help => "Boolean list option"}, + #{name => float, type => float, short => $f, long => "-float", action => append, help => "Float option"}, + %% positional args + #{name => integer, type => integer, help => "Integer variable"}, + #{name => string, help => "alias for string option", action => extend, nargs => list} + ]}, + CmdMap = #{commands => #{"start" => Command}}, + Parsed = argparse:parse(string:lexemes("start --float 1.04 -f 112 -b -b -s s1 42 --string s2 s3 s4", " "), CmdMap), + Expected = #{float => [1.04, 112], boolean => [true, true], integer => 42, string => ["s1", "s2", "s3", "s4"]}, + ?assertEqual({ok, Expected, [prog(), "start"], Command}, Parsed). + +unicode() -> + [{doc, "Tests basic unicode support"}]. + +unicode(Config) when is_list(Config) -> + %% test unicode short & long + ?assertMatch({ok, #{one := true}, _, _}, + parse(["-Ф"], #{arguments => [#{name => one, short => $Ф, type => boolean}]})), + ?assertMatch({ok, #{long := true}, _, _}, + parse(["--åäö"], #{arguments => [#{name => long, long => "-åäö", type => boolean}]})), + %% test default, help and value in unicode + Cmd = #{arguments => [#{name => text, type => binary, help => "åäö", default => <<"★"/utf8>>}]}, + Expected = #{text => <<"★"/utf8>>}, + Prog = [prog()], + ?assertEqual({ok, Expected, Prog, Cmd}, argparse:parse([], Cmd)), %% default + ?assertEqual({ok, Expected, Prog, Cmd}, argparse:parse(["★"], Cmd)), %% specified in the command line + ?assertEqual("Usage:\n " ++ prog() ++ " \n\nArguments:\n text åäö (binary), default: ★\n", + unicode:characters_to_list(argparse:help(Cmd))), + %% test command name and argument name in unicode + Uni = #{commands => #{"åäö" => #{help => "öФ"}}, handler => optional, + arguments => [#{name => "Ф", short => $ä, long => "åäö"}]}, + UniExpected = "Usage:\n " ++ prog() ++ + " {åäö} [-ä <Ф>] [-åäö <Ф>]\n\nSubcommands:\n åäö öФ\n\nOptional arguments:\n -ä, -åäö Ф\n", + ?assertEqual(UniExpected, unicode:characters_to_list(argparse:help(Uni))), + ParsedExpected = #{"Ф" => "öФ"}, + ?assertEqual({ok, ParsedExpected, Prog, Uni}, argparse:parse(["-ä", "öФ"], Uni)). + +parser_error() -> + [{doc, "Tests error tuples that the parser returns"}]. + +parser_error(Config) when is_list(Config) -> + Prog = prog(), + %% unknown option at the top of the path + ?assertEqual({error, {[Prog], undefined, "arg", <<>>}}, + parse_cmd(["arg"], #{})), + %% positional argument missing in a sub-command + Opt = #{name => mode, required => true}, + ?assertMatch({error, {[Prog, "start"], _, undefined, <<>>}}, + parse_cmd(["start"], #{"start" => #{arguments => [Opt]}})), + %% optional argument missing in a sub-command + Opt1 = #{name => mode, short => $o, required => true}, + ?assertMatch({error, {[Prog, "start"], _, undefined, <<>>}}, + parse_cmd(["start"], #{"start" => #{arguments => [Opt1]}})), + %% positional argument: an atom that does not exist + Opt2 = #{name => atom, type => atom}, + ?assertEqual({error, {[Prog], Opt2, "boo-foo", <<"is not an existing atom">>}}, + parse_opts(["boo-foo"], [Opt2])), + %% optional argument missing some items + Opt3 = #{name => kernel, long => "kernel", type => atom, nargs => 2}, + ?assertEqual({error, {[Prog], Opt3, ["port"], "expected 2, found 1 argument(s)"}}, + parse_opts(["-kernel port"], [Opt3])), + %% positional argument missing some items + Opt4 = #{name => arg, type => atom, nargs => 3}, + ?assertEqual({error, {[Prog], Opt4, ["p1"], "expected 3, found 1 argument(s)"}}, + parse_opts(["p1"], [Opt4])), + %% short option with no argument, when it's needed + ?assertMatch({error, {_, _, undefined, <<"expected argument">>}}, + parse("-1", #{arguments => [#{name => short49, short => 49}]})). + +nargs() -> + [{doc, "Tests argument consumption option, with nargs"}]. + +nargs(Config) when is_list(Config) -> + Prog = [prog()], + %% consume optional list arguments + Opts = [ + #{name => arg, short => $s, nargs => list, type => integer}, + #{name => bool, short => $b, type => boolean} + ], + ?assertMatch({ok, #{arg := [1, 2, 3], bool := true}, _, _}, + parse_opts(["-s 1 2 3 -b"], Opts)), + %% consume one_or_more arguments in an optional list + Opts2 = [ + #{name => arg, short => $s, nargs => nonempty_list}, + #{name => extra, short => $x} + ], + ?assertMatch({ok, #{extra := "X", arg := ["a","b","c"]}, _, _}, + parse_opts(["-s port -s a b c -x X"], Opts2)), + %% error if there is no argument to consume + ?assertMatch({error, {_, _, ["-x"], <<"expected argument">>}}, + parse_opts(["-s -x"], Opts2)), + %% error when positional has nargs = nonempty_list or pos_integer + ?assertMatch({error, {_, _, undefined, <<>>}}, + parse_opts([""], [#{name => req, nargs => nonempty_list}])), + %% positional arguments consumption: one or more positional argument + OptsPos1 = #{arguments => [ + #{name => arg, nargs => nonempty_list}, + #{name => extra, short => $x} + ]}, + ?assertEqual({ok, #{extra => "X", arg => ["b","c"]}, Prog, OptsPos1}, + parse(["-x port -x a b c -x X"], OptsPos1)), + %% positional arguments consumption, any number (maybe zero) + OptsPos2 = #{arguments => [ + #{name => arg, nargs => list}, + #{name => extra, short => $x} + ]}, + ?assertEqual({ok, #{extra => "X", arg => ["a","b","c"]}, Prog, OptsPos2}, + parse(["-x port a b c -x X"], OptsPos2)), + %% positional: consume ALL arguments! + OptsAll = #{arguments => [ + #{name => arg, nargs => all}, + #{name => extra, short => $x} + ]}, + ?assertEqual({ok, #{extra => "port", arg => ["a","b","c", "-x", "X"]}, Prog, OptsAll}, + parse(["-x port a b c -x X"], OptsAll)), + %% maybe with a specified default + OptMaybe = [ + #{name => foo, long => "-foo", nargs => {'maybe', c}, default => d}, + #{name => bar, nargs => 'maybe', default => d} + ], + ?assertMatch({ok, #{foo := "YY", bar := "XX"}, Prog, _}, + parse_opts(["XX --foo YY"], OptMaybe)), + ?assertMatch({ok, #{foo := c, bar := "XX"}, Prog, _}, + parse_opts(["XX --foo"], OptMaybe)), + ?assertMatch({ok, #{foo := d, bar := d}, Prog, _}, + parse_opts([""], OptMaybe)), + %% maybe with default provided by argparse + ?assertMatch({ok, #{foo := d, bar := "XX", baz := ok}, _, _}, + parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, default => ok} | OptMaybe])), + %% maybe arg - with no default given + ?assertMatch({ok, #{foo := d, bar := "XX", baz := 0}, _, _}, + parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => integer} | OptMaybe])), + ?assertMatch({ok, #{foo := d, bar := "XX", baz := ""}, _, _}, + parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => string} | OptMaybe])), + ?assertMatch({ok, #{foo := d, bar := "XX", baz := undefined}, _, _}, + parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => atom} | OptMaybe])), + ?assertMatch({ok, #{foo := d, bar := "XX", baz := <<"">>}, _, _}, + parse_opts(["XX -b"], [#{name => baz, nargs => 'maybe', short => $b, type => binary} | OptMaybe])), + %% nargs: optional list, yet it still needs to be 'not required'! + OptList = [#{name => arg, nargs => list, required => false, type => integer}], + ?assertEqual({ok, #{}, Prog, #{arguments => OptList}}, parse_opts("", OptList)), + %% tests that action "count" with nargs "maybe" counts two times, first time + %% consuming an argument (for "maybe"), second time just counting + Cmd = #{arguments => [ + #{name => short49, short => $1, long => "-force", action => count, nargs => 'maybe'}]}, + ?assertEqual({ok, #{short49 => 2}, Prog, Cmd}, + parse("-1 arg1 --force", Cmd)). + +argparse() -> + [{doc, "Tests success cases, inspired by argparse in Python"}]. + +argparse(Config) when is_list(Config) -> + Prog = [prog()], + Parser = #{arguments => [ + #{name => sum, long => "-sum", action => {store, sum}, default => max}, + #{name => integers, type => integer, nargs => nonempty_list} + ]}, + ?assertEqual({ok, #{integers => [1, 2, 3, 4], sum => max}, Prog, Parser}, + parse("1 2 3 4", Parser)), + ?assertEqual({ok, #{integers => [1, 2, 3, 4], sum => sum}, Prog, Parser}, + parse("1 2 3 4 --sum", Parser)), + ?assertEqual({ok, #{integers => [7, -1, 42], sum => sum}, Prog, Parser}, + parse("--sum 7 -1 42", Parser)), + %% name or flags + Parser2 = #{arguments => [ + #{name => bar, required => true}, + #{name => foo, short => $f, long => "-foo"} + ]}, + ?assertEqual({ok, #{bar => "BAR"}, Prog, Parser2}, parse("BAR", Parser2)), + ?assertEqual({ok, #{bar => "BAR", foo => "FOO"}, Prog, Parser2}, parse("BAR --foo FOO", Parser2)), + %PROG: error: the following arguments are required: bar + ?assertMatch({error, {Prog, _, undefined, <<>>}}, parse("--foo FOO", Parser2)), + %% action tests: default + ?assertMatch({ok, #{foo := "1"}, Prog, _}, + parse("--foo 1", #{arguments => [#{name => foo, long => "-foo"}]})), + %% action test: store + ?assertMatch({ok, #{foo := 42}, Prog, _}, + parse("--foo", #{arguments => [#{name => foo, long => "-foo", action => {store, 42}}]})), + %% action tests: boolean (variants) + ?assertMatch({ok, #{foo := true}, Prog, _}, + parse("--foo", #{arguments => [#{name => foo, long => "-foo", action => {store, true}}]})), + ?assertMatch({ok, #{foo := 42}, Prog, _}, + parse("--foo", #{arguments => [#{name => foo, long => "-foo", type => boolean, action => {store, 42}}]})), + ?assertMatch({ok, #{foo := true}, Prog, _}, + parse("--foo", #{arguments => [#{name => foo, long => "-foo", type => boolean}]})), + ?assertMatch({ok, #{foo := true}, Prog, _}, + parse("--foo true", #{arguments => [#{name => foo, long => "-foo", type => boolean}]})), + ?assertMatch({ok, #{foo := false}, Prog, _}, + parse("--foo false", #{arguments => [#{name => foo, long => "-foo", type => boolean}]})), + %% action tests: append & append_const + ?assertMatch({ok, #{all := [1, "1"]}, Prog, _}, + parse("--x 1 -x 1", #{arguments => [ + #{name => all, long => "-x", type => integer, action => append}, + #{name => all, short => $x, action => append}]})), + ?assertMatch({ok, #{all := ["Z", 2]}, Prog, _}, + parse("--x -x", #{arguments => [ + #{name => all, long => "-x", action => {append, "Z"}}, + #{name => all, short => $x, action => {append, 2}}]})), + %% count: + ?assertMatch({ok, #{v := 3}, Prog, _}, + parse("-v -v -v", #{arguments => [#{name => v, short => $v, action => count}]})). + +negative() -> + [{doc, "Test negative number parser"}]. + +negative(Config) when is_list(Config) -> + Parser = #{arguments => [ + #{name => x, short => $x, type => integer, action => store}, + #{name => foo, nargs => 'maybe', required => false} + ]}, + ?assertMatch({ok, #{x := -1}, _, _}, parse("-x -1", Parser)), + ?assertMatch({ok, #{x := -1, foo := "-5"}, _, _}, parse("-x -1 -5", Parser)), + %% + Parser2 = #{arguments => [ + #{name => one, short => $1}, + #{name => foo, nargs => 'maybe', required => false} + ]}, + + %% negative number options present, so -1 is an option + ?assertMatch({ok, #{one := "X"}, _, _}, parse("-1 X", Parser2)), + %% negative number options present, so -2 is an option + ?assertMatch({error, {_, undefined, "-2", _}}, parse("-2", Parser2)), + + %% negative number options present, so both -1s are options + ?assertMatch({error, {_, _, undefined, _}}, parse("-1 -1", Parser2)), + %% no "-" prefix, can only be an integer + ?assertMatch({ok, #{foo := "-1"}, _, _}, argparse:parse(["-1"], Parser2, #{prefixes => "+"})), + %% no "-" prefix, can only be an integer, but just one integer! + ?assertMatch({error, {_, undefined, "-1", _}}, + argparse:parse(["-2", "-1"], Parser2, #{prefixes => "+"})), + %% just in case, floats work that way too... + ?assertMatch({error, {_, undefined, "-2", _}}, + parse("-2", #{arguments => [#{name => one, long => "1.2"}]})). + +nodigits() -> + [{doc, "Test prefixes and negative numbers together"}]. + +nodigits(Config) when is_list(Config) -> + %% verify nodigits working as expected + Parser3 = #{arguments => [ + #{name => extra, short => $3}, + #{name => arg, nargs => list} + ]}, + %% ensure not to consume optional prefix + ?assertEqual({ok, #{extra => "X", arg => ["a","b","3"]}, [prog()], Parser3}, + argparse:parse(string:lexemes("-3 port a b 3 +3 X", " "), Parser3, #{prefixes => "-+"})). + +pos_mixed_with_opt() -> + [{doc, "Tests that optional argument correctly consumes expected argument" + "inspired by https://github.com/python/cpython/issues/59317"}]. + +pos_mixed_with_opt(Config) when is_list(Config) -> + Parser = #{arguments => [ + #{name => pos}, + #{name => opt, default => 24, type => integer, long => "-opt"}, + #{name => vars, nargs => list} + ]}, + ?assertEqual({ok, #{pos => "1", opt => 8, vars => ["8", "9"]}, [prog()], Parser}, + parse("1 2 --opt 8 8 9", Parser)). + +default_for_not_required() -> + [{doc, "Tests that default value is used for non-required positional argument"}]. + +default_for_not_required(Config) when is_list(Config) -> + ?assertMatch({ok, #{def := 1}, _, _}, + parse("", #{arguments => [#{name => def, short => $d, required => false, default => 1}]})), + ?assertMatch({ok, #{def := 1}, _, _}, + parse("", #{arguments => [#{name => def, required => false, default => 1}]})). + +global_default() -> + [{doc, "Tests that a global default can be enabled for all non-required arguments"}]. + +global_default(Config) when is_list(Config) -> + ?assertMatch({ok, #{def := "global"}, _, _}, + argparse:parse("", #{arguments => [#{name => def, type => integer, required => false}]}, + #{default => "global"})). + +subcommand() -> + [{doc, "Tests subcommands parser"}]. + +subcommand(Config) when is_list(Config) -> + TwoCmd = #{arguments => [#{name => bar}]}, + Cmd = #{ + arguments => [#{name => force, type => boolean, short => $f}], + commands => #{"one" => #{ + arguments => [#{name => foo, type => boolean, long => "-foo"}, #{name => baz}], + commands => #{ + "two" => TwoCmd}}}}, + ?assertEqual({ok, #{force => true, baz => "N1O1O", foo => true, bar => "bar"}, [prog(), "one", "two"], TwoCmd}, + parse("one N1O1O -f two --foo bar", Cmd)), + %% it is an error not to choose subcommand + ?assertEqual({error, {[prog(), "one"], undefined, undefined, <<"subcommand expected">>}}, + parse("one N1O1O -f", Cmd)). + +very_short() -> + [{doc, "Tests short option appended to the optional itself"}]. + +very_short(Config) when is_list(Config) -> + ?assertMatch({ok, #{x := "V"}, _, _}, + parse("-xV", #{arguments => [#{name => x, short => $x}]})). + +multi_short() -> + [{doc, "Tests multiple short arguments blend into one"}]. + +multi_short(Config) when is_list(Config) -> + %% ensure non-flammable argument does not explode, even when it's possible + ?assertMatch({ok, #{v := "xv"}, _, _}, + parse("-vxv", #{arguments => [#{name => v, short => $v}, #{name => x, short => $x}]})), + %% ensure 'verbosity' use-case works + ?assertMatch({ok, #{v := 3}, _, _}, + parse("-vvv", #{arguments => [#{name => v, short => $v, action => count}]})), + %% + ?assertMatch({ok, #{recursive := true, force := true, path := "dir"}, _, _}, + parse("-rf dir", #{arguments => [ + #{name => recursive, short => $r, type => boolean}, + #{name => force, short => $f, type => boolean}, + #{name => path} + ]})). + +proxy_arguments() -> + [{doc, "Tests nargs => all used to proxy arguments to another script"}]. + +proxy_arguments(Config) when is_list(Config) -> + Cmd = #{ + commands => #{ + "start" => #{ + arguments => [ + #{name => shell, short => $s, long => "-shell", type => boolean}, + #{name => skip, short => $x, long => "-skip", type => boolean}, + #{name => args, required => false, nargs => all} + ] + }, + "stop" => #{}, + "status" => #{ + arguments => [ + #{name => skip, required => false, default => "ok"}, + #{name => args, required => false, nargs => all} + ]}, + "state" => #{ + arguments => [ + #{name => skip, required => false}, + #{name => args, required => false, nargs => all} + ]} + }, + arguments => [ + #{name => node} + ], + handler => fun (#{}) -> ok end + }, + Prog = prog(), + ?assertMatch({ok, #{node := "node1"}, _, _}, parse("node1", Cmd)), + ?assertMatch({ok, #{node := "node1"}, [Prog, "stop"], #{}}, parse("node1 stop", Cmd)), + ?assertMatch({ok, #{node := "node2.org", shell := true, skip := true}, _, _}, parse("node2.org start -x -s", Cmd)), + ?assertMatch({ok, #{args := ["-app","key","value"],node := "node1.org"}, [Prog, "start"], _}, + parse("node1.org start -app key value", Cmd)), + ?assertMatch({ok, #{args := ["-app","key","value", "-app2", "key2", "value2"], + node := "node3.org", shell := true}, [Prog, "start"], _}, + parse("node3.org start -s -app key value -app2 key2 value2", Cmd)), + %% test that any non-required positionals are skipped + ?assertMatch({ok, #{args := ["-a","bcd"], node := "node2.org", skip := "ok"}, _, _}, parse("node2.org status -a bcd", Cmd)), + ?assertMatch({ok, #{args := ["-app", "key"], node := "node2.org"}, _, _}, parse("node2.org state -app key", Cmd)). + +%%-------------------------------------------------------------------- +%% Usage Test Cases + +usage() -> + [{doc, "Basic tests for help formatter, including 'hidden' help"}]. + +usage(Config) when is_list(Config) -> + Cmd = ubiq_cmd(), + Usage = "Usage:\n erl start {crawler|doze} [-lrfv] [-s ...] [-z ] [-m ] [-b ]\n" + " [-g ] [-t ] ---maybe-req -y --yyy [-u ] [-c ]\n" + " [-q ] [-w ] [--unsafe ] [--safe ] [-foobar ] [--force]\n" + " [-i ] [--req ] [--float ] []\n\n" + "Subcommands:\n" + " crawler controls crawler behaviour\n" + " doze dozes a bit\n\n" + "Arguments:\n" + " server server to start\n" + " optpos optional positional (int)\n\n" + "Optional arguments:\n" + " -s initial shards (int)\n" + " -z between (1 <= int <= 10)\n" + " -l maybe lower (int <= 10)\n" + " -m less than 10 (int <= 10)\n" + " -b binary with re (binary re: m)\n" + " -g binary with re (binary re: m)\n" + " -t string with re (string re: m)\n" + " ---maybe-req maybe required int (int)\n" + " -y, --yyy string with re (string re: m)\n" + " -u string choices (choice: 1, 2)\n" + " -c tough choice (choice: 1, 2, 3)\n" + " -q floating choice (choice: 2.10000, 1.20000)\n" + " -w atom choice (choice: one, two)\n" + " --unsafe unsafe atom (atom)\n" + " --safe safe atom (existing atom)\n" + " -foobar foobaring option\n" + " -r recursive\n" + " -f, --force force\n" + " -v verbosity level\n" + " -i interval set (int >= 1)\n" + " --req required optional, right?\n" + " --float floating-point long form argument (float), default: 3.14\n", + ?assertEqual(Usage, unicode:characters_to_list(argparse:help(Cmd, + #{progname => "erl", command => ["start"]}))), + FullCmd = "Usage:\n erl" + " [-rfv] [--force] [-i ] [--req ] [--float ]\n\n" + "Subcommands:\n" + " start verifies configuration and starts server\n" + " status prints server status\n" + " stop stops running server\n\n" + "Optional arguments:\n" + " -r recursive\n" + " -f, --force force\n" + " -v verbosity level\n" + " -i interval set (int >= 1)\n" + " --req required optional, right?\n" + " --float floating-point long form argument (float), default: 3.14\n", + ?assertEqual(FullCmd, unicode:characters_to_list(argparse:help(Cmd, + #{progname => erl}))), + CrawlerStatus = "Usage:\n erl status crawler [-rfv] [---extra ] [--force] [-i ]\n" + " [--req ] [--float ]\n\nOptional arguments:\n" + " ---extra extra option very deep\n -r recursive\n" + " -f, --force force\n -v verbosity level\n" + " -i interval set (int >= 1)\n" + " --req required optional, right?\n" + " --float floating-point long form argument (float), default: 3.14\n", + ?assertEqual(CrawlerStatus, unicode:characters_to_list(argparse:help(Cmd, + #{progname => "erl", command => ["status", "crawler"]}))), + ok. + +usage_required_args() -> + [{doc, "Verify that required args are printed as required in usage"}]. + +usage_required_args(Config) when is_list(Config) -> + Cmd = #{commands => #{"test" => #{arguments => [#{name => required, required => true, long => "-req"}]}}}, + Expected = "Usage:\n " ++ prog() ++ " test --req \n\nOptional arguments:\n --req required\n", + ?assertEqual(Expected, unicode:characters_to_list(argparse:help(Cmd, #{command => ["test"]}))). + +usage_template() -> + [{doc, "Tests templates in help/usage"}]. + +usage_template(Config) when is_list(Config) -> + %% Argument (positional) + Cmd = #{arguments => [#{ + name => shard, + type => integer, + default => 0, + help => {"[-s SHARD]", ["initial number, ", type, <<" with a default value of ">>, default]}} + ]}, + ?assertEqual("Usage:\n " ++ prog() ++ " [-s SHARD]\n\nArguments:\n shard initial number, int with a default value of 0\n", + unicode:characters_to_list(argparse:help(Cmd, #{}))), + %% Optional + Cmd1 = #{arguments => [#{ + name => shard, + short => $s, + type => integer, + default => 0, + help => {<<"[-s SHARD]">>, ["initial number"]}} + ]}, + ?assertEqual("Usage:\n " ++ prog() ++ " [-s SHARD]\n\nOptional arguments:\n -s initial number\n", + unicode:characters_to_list(argparse:help(Cmd1, #{}))), + %% ISO Date example + DefaultRange = {{2020, 1, 1}, {2020, 6, 22}}, + CmdISO = #{ + arguments => [ + #{ + name => range, + long => "-range", + short => $r, + help => {"[--range RNG]", fun() -> + {{FY, FM, FD}, {TY, TM, TD}} = DefaultRange, + lists:flatten(io_lib:format("date range, ~b-~b-~b..~b-~b-~b", [FY, FM, FD, TY, TM, TD])) + end}, + type => {custom, fun(S) -> [S, DefaultRange] end}, + default => DefaultRange + } + ] + }, + ?assertEqual("Usage:\n " ++ prog() ++ " [--range RNG]\n\nOptional arguments:\n -r, --range date range, 2020-1-1..2020-6-22\n", + unicode:characters_to_list(argparse:help(CmdISO, #{}))), + ok. + +parser_error_usage() -> + [{doc, "Tests that parser errors have corresponding usage text"}]. + +parser_error_usage(Config) when is_list(Config) -> + %% unknown arguments + Prog = prog(), + ?assertEqual(Prog ++ ": unknown argument: arg", parser_error(["arg"], #{})), + ?assertEqual(Prog ++ ": unknown argument: -a", parser_error(["-a"], #{})), + %% missing argument + ?assertEqual(Prog ++ ": required argument missing: need", parser_error([""], + #{arguments => [#{name => need}]})), + ?assertEqual(Prog ++ ": required argument missing: need", parser_error([""], + #{arguments => [#{name => need, short => $n, required => true}]})), + %% invalid value + ?assertEqual(Prog ++ ": invalid argument for need: foo is not an integer", parser_error(["foo"], + #{arguments => [#{name => need, type => integer}]})), + ?assertEqual(Prog ++ ": invalid argument for need: cAnNotExIsT is not an existing atom", parser_error(["cAnNotExIsT"], + #{arguments => [#{name => need, type => atom}]})). + +command_usage() -> + [{doc, "Test command help template"}]. + +command_usage(Config) when is_list(Config) -> + Cmd = #{arguments => [ + #{name => arg, help => "argument help"}, #{name => opt, short => $o, help => "option help"}], + help => ["Options:\n", options, arguments, <<"NOTAUSAGE">>, usage, "\n"] + }, + ?assertEqual("Options:\n -o option help\n arg argument help\nNOTAUSAGE " ++ prog() ++ " [-o ] \n", + unicode:characters_to_list(argparse:help(Cmd, #{}))). + +usage_width() -> + [{doc, "Test usage fitting in the viewport"}]. + +usage_width(Config) when is_list(Config) -> + Cmd = #{arguments => [ + #{name => arg, help => "argument help that spans way over allowed viewport width, wrapping words"}, + #{name => opt, short => $o, long => "-option_long_name", + help => "another quite long word wrapped thing spanning over several lines"}, + #{name => v, short => $v, type => boolean}, + #{name => q, short => $q, type => boolean}], + commands => #{ + "cmd1" => #{help => "Help for command number 1, not fitting at all"}, + "cmd2" => #{help => <<"Short help">>}, + "cmd3" => #{help => "Yet another instance of a very long help message"} + }, + help => " Very long help line taking much more than 40 characters allowed by the test case. +Also containing a few newlines. + + Indented new lines must be honoured!" + }, + + Expected = "Usage:\n erl {cmd1|cmd2|cmd3} [-vq] [-o ]\n" + " [--option_long_name ] \n\n" + " Very long help line taking much more\n" + "than 40 characters allowed by the test\n" + "case.\n" + "Also containing a few newlines.\n\n" + " Indented new lines must be honoured!\n\n" + "Subcommands:\n" + " cmd1 Help for\n" + " command number\n" + " 1, not fitting\n" + " at all\n" + " cmd2 Short help\n" + " cmd3 Yet another\n" + " instance of a\n" + " very long help\n" + " message\n\n" + "Arguments:\n" + " arg argument help\n" + " that spans way\n" + " over allowed\n" + " viewport width,\n" + " wrapping words\n\n" + "Optional arguments:\n" + " -o, --option_long_name another quite\n" + " long word\n" + " wrapped thing\n" + " spanning over\n" + " several lines\n" + " -v v\n" + " -q q\n", + + ?assertEqual(Expected, unicode:characters_to_list(argparse:help(Cmd, #{columns => 40, progname => "erl"}))). + +%%-------------------------------------------------------------------- +%% Validator Test Cases + +validator_exception() -> + [{doc, "Tests that the validator throws expected exceptions"}]. + +validator_exception(Config) when is_list(Config) -> + Prg = [prog()], + %% conflicting option names + ?assertException(error, {argparse, argument, Prg, short, "short conflicting with previously defined short for one"}, + argparse:validate(#{arguments => [#{name => one, short => $$}, #{name => two, short => $$}]})), + ?assertException(error, {argparse, argument, Prg, long, "long conflicting with previously defined long for one"}, + argparse:validate(#{arguments => [#{name => one, long => "a"}, #{name => two, long => "a"}]})), + %% broken options + %% long must be a string + ?assertException(error, {argparse, argument, Prg, long, _}, + argparse:validate(#{arguments => [#{name => one, long => ok}]})), + %% short must be a printable character + ?assertException(error, {argparse, argument, Prg, short, _}, + argparse:validate(#{arguments => [#{name => one, short => ok}]})), + ?assertException(error, {argparse, argument, Prg, short, _}, + argparse:validate(#{arguments => [#{name => one, short => 7}]})), + %% required is a boolean + ?assertException(error, {argparse, argument, Prg, required, _}, + argparse:validate(#{arguments => [#{name => one, required => ok}]})), + ?assertException(error, {argparse, argument, Prg, help, _}, + argparse:validate(#{arguments => [#{name => one, help => ok}]})), + %% broken commands + try argparse:help(#{}, #{progname => 123}), ?assert(false) + catch error:badarg:Stack -> + [{_, _, _, Ext} | _] = Stack, + #{cause := #{2 := Detail}} = proplists:get_value(error_info, Ext), + ?assertEqual(<<"progname is not valid">>, Detail) + end, + %% not-a-list of arguments provided to a subcommand + Prog = prog(), + ?assertException(error, {argparse, command, [Prog, "start"], arguments, <<"expected a list, [argument()]">>}, + argparse:validate(#{commands => #{"start" => #{arguments => atom}}})), + %% command is not a map + ?assertException(error, {argparse, command, Prg, commands, <<"expected map of #{string() => command()}">>}, + argparse:validate(#{commands => []})), + %% invalid commands field + ?assertException(error, {argparse, command, Prg, commands, _}, + argparse:validate(#{commands => ok})), + ?assertException(error, {argparse, command, _, commands, _}, + argparse:validate(#{commands => #{ok => #{}}})), + ?assertException(error, {argparse, command, _, help, + <<"must be a printable unicode list, or a command help template">>}, + argparse:validate(#{commands => #{"ok" => #{help => ok}}})), + ?assertException(error, {argparse, command, _, handler, _}, + argparse:validate(#{commands => #{"ok" => #{handler => fun validator_exception/0}}})), + %% extend + maybe: validator exception + ?assertException(error, {argparse, argument, _, action, <<"extend action works only with lists">>}, + parse("-1 -1", #{arguments => + [#{action => extend, name => short49, nargs => 'maybe', short => 49}]})). + +validator_exception_format() -> + [{doc, "Tests human-readable (EEP-54) format for exceptions thrown by the validator"}]. + +validator_exception_format(Config) when is_list(Config) -> + %% set up as a contract: test that EEP-54 transformation is done (but don't check strings) + try + argparse:validate(#{commands => #{"one" => #{commands => #{"two" => atom}}}}), + ?assert(false) + catch + error:R1:S1 -> + #{1 := Cmd, reason := RR1, general := G} = argparse:format_error(R1, S1), + ?assertEqual("command specification is invalid", unicode:characters_to_list(G)), + ?assertEqual("command \"" ++ prog() ++ " one two\": invalid field 'commands', reason: expected command()", + unicode:characters_to_list(RR1)), + ?assertEqual(["atom"], Cmd) + end, + %% check argument + try + argparse:validate(#{arguments => [#{}]}), + ?assert(false) + catch + error:R2:S2 -> + #{1 := Cmd2, reason := RR2, general := G2} = argparse:format_error(R2, S2), + ?assertEqual("argument specification is invalid", unicode:characters_to_list(G2)), + ?assertEqual("command \"" ++ prog() ++ + "\", argument '', invalid field 'name': argument must be a map containing 'name' field", + unicode:characters_to_list(RR2)), + ?assertEqual(["#{}"], Cmd2) + end. + +%%-------------------------------------------------------------------- +%% Validator Test Cases + +run_handle() -> + [{doc, "Very basic tests for argparse:run/3, choice of handlers formats"}]. + +%% fun((arg_map()) -> term()) | %% handler accepting arg_map +%% {module(), Fn :: atom()} | %% handler, accepting arg_map, Fn exported from module() +%% {fun(() -> term()), term()} | %% handler, positional form (term() is supplied for omitted args) +%% {module(), atom(), term()} + +run_handle(Config) when is_list(Config) -> + %% no subcommand, basic fun handler with argmap + ?assertEqual(6, + argparse:run(["-i", "3"], #{handler => fun (#{in := Val}) -> Val * 2 end, + arguments => [#{name => in, short => $i, type => integer}]}, #{})), + %% subcommand, positional fun() handler + ?assertEqual(6, + argparse:run(["mul", "2", "3"], #{commands => #{"mul" => #{ + handler => {fun (match, L, R) -> L * R end, match}, + arguments => [#{name => opt, short => $o}, + #{name => l, type => integer}, #{name => r, type => integer}]}}}, + #{})), + %% no subcommand, positional module-based function + ?assertEqual(6, + argparse:run(["2", "3"], #{handler => {erlang, '*', undefined}, + arguments => [#{name => l, type => integer}, #{name => r, type => integer}]}, + #{})), + %% subcommand, module-based function accepting argmap + ?assertEqual([{arg, "arg"}], + argparse:run(["map", "arg"], #{commands => #{"map" => #{ + handler => {maps, to_list}, + arguments => [#{name => arg}]}}}, + #{})). \ No newline at end of file diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl index 1fc4c3fc0e23..0eae2d9f72dc 100644 --- a/lib/stdlib/test/base64_SUITE.erl +++ b/lib/stdlib/test/base64_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2017. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -26,9 +26,11 @@ -export([all/0, suite/0, groups/0, group/1]). %% Test cases must be exported. --export([base64_encode/1, base64_decode/1, base64_otp_5635/1, - base64_otp_6279/1, big/1, illegal/1, mime_decode/1, - mime_decode_to_string/1, +-export([base64_encode/1, base64_encode_to_string/1, base64_encode_modes/1, + base64_decode/1, base64_decode_to_string/1, base64_decode_modes/1, + base64_otp_5635/1, base64_otp_6279/1, big/1, illegal/1, + mime_decode/1, mime_decode_modes/1, + mime_decode_to_string/1, mime_decode_to_string_modes/1, roundtrip_1/1, roundtrip_2/1, roundtrip_3/1, roundtrip_4/1]). %%------------------------------------------------------------------------- @@ -40,8 +42,11 @@ suite() -> {timetrap,{minutes,4}}]. all() -> - [base64_encode, base64_decode, base64_otp_5635, - base64_otp_6279, big, illegal, mime_decode, mime_decode_to_string, + [base64_encode, base64_encode_to_string, base64_encode_modes, + base64_decode, base64_decode_to_string, base64_decode_modes, + base64_otp_5635, base64_otp_6279, big, illegal, + mime_decode, mime_decode_modes, + mime_decode_to_string, mime_decode_to_string_modes, {group, roundtrip}]. groups() -> @@ -53,44 +58,176 @@ group(roundtrip) -> [{timetrap,{minutes,10}}]. %%------------------------------------------------------------------------- -%% Test base64:encode/1. +%% Test base64:encode/1,2. base64_encode(Config) when is_list(Config) -> %% Two pads <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> = base64:encode("Aladdin:open sesame"), + <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">> = + base64:encode("Aladdin:open sesame", #{padding => false}), %% One pad <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>), + <<"SGVsbG8gV29ybGQ">> = base64:encode(<<"Hello World">>, #{padding => false}), + %% No pad + <<"QWxhZGRpbjpvcGVuIHNlc2Ft">> = base64:encode("Aladdin:open sesam"), + <<"QWxhZGRpbjpvcGVuIHNlc2Ft">> = + base64:encode("Aladdin:open sesam", #{padding => false}), + + <<"MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9">> = + base64:encode(<<"0123456789!@#0^&*();:<>,. []{}">>), + ok. + +%%------------------------------------------------------------------------- +%% Test base64:encode_to_string/1,2. +base64_encode_to_string(Config) when is_list(Config) -> + %% Two pads + "QWxhZGRpbjpvcGVuIHNlc2FtZQ==" = + base64:encode_to_string("Aladdin:open sesame"), + "QWxhZGRpbjpvcGVuIHNlc2FtZQ" = + base64:encode_to_string("Aladdin:open sesame", #{padding => false}), + %% One pad + "SGVsbG8gV29ybGQ=" = base64:encode_to_string(<<"Hello World">>), + "SGVsbG8gV29ybGQ" = + base64:encode_to_string(<<"Hello World">>, #{padding => false}), %% No pad "QWxhZGRpbjpvcGVuIHNlc2Ft" = base64:encode_to_string("Aladdin:open sesam"), + "QWxhZGRpbjpvcGVuIHNlc2Ft" = + base64:encode_to_string("Aladdin:open sesam", #{padding => false}), "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" = base64:encode_to_string(<<"0123456789!@#0^&*();:<>,. []{}">>), ok. + +%%------------------------------------------------------------------------- +%% Test base64:encode/2 and base64:encode_to_string/2. +base64_encode_modes(Config) when is_list(Config) -> + Data = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>, + + <<"F+o/o++B/a+r">> = base64:encode(Data, #{mode => standard}), + <<"F-o_o--B_a-r">> = base64:encode(Data, #{mode => urlsafe}), + + "F+o/o++B/a+r" = base64:encode_to_string(Data, #{mode => standard}), + "F-o_o--B_a-r" = base64:encode_to_string(Data, #{mode => urlsafe}), + + ok. + %%------------------------------------------------------------------------- -%% Test base64:decode/1. +%% Test base64:decode/1,2. base64_decode(Config) when is_list(Config) -> %% Two pads <<"Aladdin:open sesame">> = - base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="), + base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>), + <<"Aladdin:open sesame">> = + base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="), + <<"Aladdin:open sesame">> = + base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>, #{padding => false}), + <<"Aladdin:open sesame">> = + base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ", #{padding => false}), + {'EXIT', {'missing_padding', _}} = + catch base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>), + {'EXIT', {'missing_padding', _}} = + catch base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ"), %% One pad <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ=">>), + <<"Hello World">> = base64:decode("SGVsbG8gV29ybGQ="), + <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ">>, #{padding => false}), + <<"Hello World">> = base64:decode("SGVsbG8gV29ybGQ", #{padding => false}), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string("SGVsbG8gV29ybGQ"), %% No pad <<"Aladdin:open sesam">> = - base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"), + base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>), + <<"Aladdin:open sesam">> = + base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"), + <<"Aladdin:open sesam">> = + base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>, #{padding => false}), + <<"Aladdin:open sesam">> = + base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft", #{padding => false}), Alphabet = list_to_binary(lists:seq(0, 255)), Alphabet = base64:decode(base64:encode(Alphabet)), + Alphabet = base64:decode(base64:encode_to_string(Alphabet)), + + %% Encoded base 64 strings may be divided by non base 64 chars. + %% In this cases whitespaces. + <<"0123456789!@#0^&*();:<>,. []{}">> = + base64:decode( + "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"), + <<"0123456789!@#0^&*();:<>,. []{}">> = + base64:decode( + <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>), + ok. + +%%------------------------------------------------------------------------- +%% Test base64:decode_to_string/1,2. +base64_decode_to_string(Config) when is_list(Config) -> + %% Two pads + "Aladdin:open sesame" = + base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>), + "Aladdin:open sesame" = + base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="), + "Aladdin:open sesame" = + base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>, #{padding => false}), + "Aladdin:open sesame" = + base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ", #{padding => false}), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ"), + %% One pad + "Hello World" = base64:decode_to_string(<<"SGVsbG8gV29ybGQ=">>), + "Hello World" = base64:decode_to_string("SGVsbG8gV29ybGQ="), + "Hello World" = base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>, #{padding => false}), + "Hello World" = base64:decode_to_string("SGVsbG8gV29ybGQ", #{padding => false}), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>), + {'EXIT', {'missing_padding', _}} = + catch base64:decode_to_string("SGVsbG8gV29ybGQ"), + %% No pad + "Aladdin:open sesam" = + base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>), + "Aladdin:open sesam" = + base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2Ft"), + "Aladdin:open sesam" = + base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>, #{padding => false}), + "Aladdin:open sesam" = + base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2Ft", #{padding => false}), + + Alphabet = lists:seq(0, 255), + Alphabet = base64:decode_to_string(base64:encode(Alphabet)), + Alphabet = base64:decode_to_string(base64:encode_to_string(Alphabet)), %% Encoded base 64 strings may be divided by non base 64 chars. %% In this cases whitespaces. "0123456789!@#0^&*();:<>,. []{}" = - base64:decode_to_string( - "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"), + base64:decode_to_string( + "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"), "0123456789!@#0^&*();:<>,. []{}" = - base64:decode_to_string( - <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>), + base64:decode_to_string( + <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>), ok. + +%%------------------------------------------------------------------------- +%% Test base64:decode/2 and base64:decode_to_string/2 +base64_decode_modes(Config) when is_list(Config) -> + DataBin = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>, + DataStr = [23, 234, 63, 163, 239, 129, 253, 175, 171], + + DataBin = base64:decode("F+o/o++B/a+r", #{mode => standard}), + DataBin = base64:decode("F-o_o--B_a-r", #{mode => urlsafe}), + {'EXIT', _} = catch base64:decode("F-o_o--B_a-r", #{mode => standard}), + {'EXIT', _} = catch base64:decode("F+o/o++B/a+r", #{mode => urlsafe}), + + DataStr = base64:decode_to_string("F+o/o++B/a+r", #{mode => standard}), + DataStr = base64:decode_to_string("F-o_o--B_a-r", #{mode => urlsafe}), + {'EXIT', _} = catch base64:decode_to_string("F-o_o--B_a-r", #{mode => standard}), + {'EXIT', _} = catch base64:decode_to_string("F+o/o++B/a+r", #{mode => urlsafe}), + + ok. + %%------------------------------------------------------------------------- %% OTP-5635: Some data doesn't pass through base64:decode/1 correctly. base64_otp_5635(Config) when is_list(Config) -> @@ -171,6 +308,31 @@ mime_decode(Config) when is_list(Config) -> <<"o">> = MimeDecode(<<"bw=\000=">>), ok. +%% Test base64:mime_decode/2. +mime_decode_modes(Config) when is_list(Config) -> + MimeDecode = fun (In, Options) -> + Out = base64:mime_decode(In, Options), + Out = base64:mime_decode(binary_to_list(In), Options) + end, + + %% The following all decode to the same data. + Data = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>, + Data = MimeDecode(<<"F+o/o++B/a+r">>, #{mode => standard}), + Data = MimeDecode(<<"F-o_o--B_a-r">>, #{mode => urlsafe}), + + %% The following decodes to different data depending on mode. + Base64 = <<"AB+C+D/E/FG-H-I_J_KL">>, + %% In standard mode, "-" and "_" are invalid and thus ignored. + %% The base64 string to be decoded is equivalent to "AB+C+D/E/FGHIJKL". + <<0, 31, 130, 248, 63, 196, 252, 81, 135, 32, 146, 139>> = + MimeDecode(Base64, #{mode => standard}), + %% In urlsafe mode, "+" and "/" are invalid and thus ignored. + %% The base64 string to be decoded is equivalent to "ABCDEFG-H-I_J_KL". + <<0, 16, 131, 16, 81, 190, 31, 226, 63, 39, 242, 139>> = + MimeDecode(Base64, #{mode => urlsafe}), + + ok. + %%------------------------------------------------------------------------- %% Repeat of mime_decode() tests @@ -221,6 +383,32 @@ mime_decode_to_string(Config) when is_list(Config) -> "o" = MimeDecodeToString(<<"bw=\000=">>), ok. + +%% Test base64:mime_decode_to_string/2. +mime_decode_to_string_modes(Config) when is_list(Config) -> + MimeDecode = fun (In, Options) -> + Out = base64:mime_decode_to_string(In, Options), + Out = base64:mime_decode_to_string(binary_to_list(In), Options) + end, + + %% The following all decode to the same data. + Data = [23, 234, 63, 163, 239, 129, 253, 175, 171], + Data = MimeDecode(<<"F+o/o++B/a+r">>, #{mode => standard}), + Data = MimeDecode(<<"F-o_o--B_a-r">>, #{mode => urlsafe}), + + %% The following decodes to different data depending on mode. + Base64 = <<"AB+C+D/E/FG-H-I_J_KL">>, + %% In standard mode, "-" and "_" are invalid and thus ignored. + %% The base64 string to be decoded is equivalent to "AB+C+D/E/FGHIJKL". + [0, 31, 130, 248, 63, 196, 252, 81, 135, 32, 146, 139] = + MimeDecode(Base64, #{mode => standard}), + %% In urlsafe mode, "+" and "/" are invalid and thus ignored. + %% The base64 string to be decoded is equivalent to "ABCDEFG-H-I_J_KL". + [0, 16, 131, 16, 81, 190, 31, 226, 63, 39, 242, 139] = + MimeDecode(Base64, #{mode => urlsafe}), + + ok. + %%------------------------------------------------------------------------- roundtrip_1(Config) when is_list(Config) -> diff --git a/lib/stdlib/test/base64_property_test_SUITE.erl b/lib/stdlib/test/base64_property_test_SUITE.erl new file mode 100644 index 000000000000..68ac5e9ee7f8 --- /dev/null +++ b/lib/stdlib/test/base64_property_test_SUITE.erl @@ -0,0 +1,122 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(base64_property_test_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-compile([export_all, nowarn_export_all]). + +all() -> + [ + encode_1_case, encode_2_case, + encode_to_string_1_case, encode_to_string_2_case, + decode_1_case, decode_2_case, + decode_1_malformed_case, decode_2_malformed_case, + decode_1_noisy_case, decode_2_noisy_case, + decode_to_string_1_case, decode_to_string_2_case, + decode_to_string_1_malformed_case, decode_to_string_2_malformed_case, + decode_to_string_1_noisy_case, decode_to_string_2_noisy_case, + mime_decode_1_case, mime_decode_2_case, + mime_decode_1_malformed_case, mime_decode_2_malformed_case, + mime_decode_to_string_1_case, mime_decode_to_string_2_case, + mime_decode_to_string_1_malformed_case, mime_decode_to_string_2_malformed_case + ]. + +init_per_suite(Config) -> + ct_property_test:init_per_suite(Config). + +end_per_suite(Config) -> + Config. + +encode_1_case(Config) -> + do_proptest(prop_encode_1, Config). + +encode_2_case(Config) -> + do_proptest(prop_encode_2, Config). + +encode_to_string_1_case(Config) -> + do_proptest(prop_encode_to_string_1, Config). + +encode_to_string_2_case(Config) -> + do_proptest(prop_encode_to_string_2, Config). + +decode_1_case(Config) -> + do_proptest(prop_decode_1, Config). + +decode_2_case(Config) -> + do_proptest(prop_decode_2, Config). + +decode_1_malformed_case(Config) -> + do_proptest(prop_decode_1_malformed, Config). + +decode_2_malformed_case(Config) -> + do_proptest(prop_decode_2_malformed, Config). + +decode_1_noisy_case(Config) -> + do_proptest(prop_decode_1_noisy, Config). + +decode_2_noisy_case(Config) -> + do_proptest(prop_decode_2_noisy, Config). + +decode_to_string_1_case(Config) -> + do_proptest(prop_decode_to_string_1, Config). + +decode_to_string_2_case(Config) -> + do_proptest(prop_decode_to_string_2, Config). + +decode_to_string_1_malformed_case(Config) -> + do_proptest(prop_decode_to_string_1_malformed, Config). + +decode_to_string_2_malformed_case(Config) -> + do_proptest(prop_decode_to_string_2_malformed, Config). + +decode_to_string_1_noisy_case(Config) -> + do_proptest(prop_decode_to_string_1_noisy, Config). + +decode_to_string_2_noisy_case(Config) -> + do_proptest(prop_decode_to_string_2_noisy, Config). + +mime_decode_1_case(Config) -> + do_proptest(prop_mime_decode_1, Config). + +mime_decode_2_case(Config) -> + do_proptest(prop_mime_decode_2, Config). + +mime_decode_1_malformed_case(Config) -> + do_proptest(prop_mime_decode_1_malformed, Config). + +mime_decode_2_malformed_case(Config) -> + do_proptest(prop_mime_decode_2_malformed, Config). + +mime_decode_to_string_1_case(Config) -> + do_proptest(prop_mime_decode_to_string_1, Config). + +mime_decode_to_string_2_case(Config) -> + do_proptest(prop_mime_decode_to_string_2, Config). + +mime_decode_to_string_1_malformed_case(Config) -> + do_proptest(prop_mime_decode_to_string_1_malformed, Config). + +mime_decode_to_string_2_malformed_case(Config) -> + do_proptest(prop_mime_decode_to_string_2_malformed, Config). + +do_proptest(Prop, Config) -> + ct_property_test:quickcheck( + base64_prop:Prop(), + Config). diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl index 097d88c7ec9e..ef3a61569916 100644 --- a/lib/stdlib/test/beam_lib_SUITE.erl +++ b/lib/stdlib/test/beam_lib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -58,7 +58,16 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - ok. + %% Cleanup after strip and strip_add_chunks + case code:is_sticky(sofs) of + false -> + false = code:purge(sofs), + {module, sofs} = code:load_file(sofs), + code:stick_mod(sofs), + ok; + true -> + ok + end. init_per_group(_GroupName, Config) -> Config. @@ -85,7 +94,6 @@ normal(Conf) when is_list(Conf) -> P0 = pps(), do_normal(Source, PrivDir, BeamFile, []), - do_normal(Source, PrivDir, BeamFile, [no_utf8_atoms]), {ok,_} = compile:file(Source, [{outdir,PrivDir}, no_debug_info]), {ok, {simple, [{debug_info, {debug_info_v1, erl_abstract_code, {none, _}}}]}} = @@ -384,22 +392,29 @@ strip(Conf) when is_list(Conf) -> {ok, [{simple,_},{simple2,_},{make_fun,_},{constant,_}]} = beam_lib:strip_files([BeamFileD1, BeamFile2D1, BeamFile3D1, BeamFile4D1]), + %% strip a complex module + OrigSofsPath = code:where_is_file("sofs.beam"), + BeamFileSofs = filename:join(PrivDir,"sofs.beam"), + file:copy(OrigSofsPath, BeamFileSofs), + {ok, {sofs,_}} = beam_lib:strip(BeamFileSofs), + code:unstick_mod(sofs), + false = code:purge(sofs), + %% check that each module can be loaded. {module, simple} = code:load_abs(filename:rootname(BeamFileD1)), {module, simple2} = code:load_abs(filename:rootname(BeamFile2D1)), {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)), {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)), + {module, sofs} = code:load_abs(filename:rootname(BeamFileSofs)), %% check that line number information is still present after stripping {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)), - {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = - (catch lines:t(atom)), + Info = get_line_number_info(), true = code:delete(lines), false = code:purge(lines), {ok, {lines,BeamFile5D1}} = beam_lib:strip(BeamFile5D1), {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)), - {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = - (catch lines:t(atom)), + Info = get_line_number_info(), true = (P0 == pps()), NoOfTables = erlang:system_info(ets_count), @@ -408,7 +423,12 @@ strip(Conf) when is_list(Conf) -> Source2D1, BeamFile2D1, Source3D1, BeamFile3D1, Source4D1, BeamFile4D1, - Source5D1, BeamFile5D1]), + Source5D1, BeamFile5D1, + BeamFileSofs]), + + false = code:purge(sofs), + {module, sofs} = code:load_file(sofs), + code:stick_mod(sofs), ok. strip_add_chunks(Conf) when is_list(Conf) -> @@ -433,7 +453,7 @@ strip_add_chunks(Conf) when is_list(Conf) -> compare_chunks(B1, NB1, NBId1), %% Keep all the extra chunks - ExtraChunks = ["Abst" , "Dbgi" , "Attr" , "CInf" , "LocT" , "Atom" ], + ExtraChunks = ["Abst", "Dbgi", "Attr", "CInf", "LocT", "Atom"], {ok, {simple, AB1}} = beam_lib:strip(B1, ExtraChunks), ABId1 = chunk_ids(AB1), true = length(BId1) == length(ABId1), @@ -450,20 +470,29 @@ strip_add_chunks(Conf) when is_list(Conf) -> {ok, [{simple,_},{simple2,_},{make_fun,_},{constant,_}]} = beam_lib:strip_files([BeamFileD1, BeamFile2D1, BeamFile3D1, BeamFile4D1], ExtraChunks), + %% strip a complex module + OrigSofsPath = code:where_is_file("sofs.beam"), + BeamFileSofs = filename:join(PrivDir,"sofs.beam"), + file:copy(OrigSofsPath, BeamFileSofs), + {ok, {sofs,_}} = beam_lib:strip(BeamFileSofs, ExtraChunks), + code:unstick_mod(sofs), + false = code:purge(sofs), + %% check that each module can be loaded. {module, simple} = code:load_abs(filename:rootname(BeamFileD1)), {module, simple2} = code:load_abs(filename:rootname(BeamFile2D1)), {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)), {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)), + {module, sofs} = code:load_abs(filename:rootname(BeamFileSofs)), %% check that line number information is still present after stripping {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)), - {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = (catch lines:t(atom)), + Info = get_line_number_info(), false = code:purge(lines), true = code:delete(lines), {ok, {lines,BeamFile5D1}} = beam_lib:strip(BeamFile5D1), {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)), - {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = (catch lines:t(atom)), + Info = get_line_number_info(), true = (P0 == pps()), NoOfTables = erlang:system_info(ets_count), @@ -472,7 +501,13 @@ strip_add_chunks(Conf) when is_list(Conf) -> Source2D1, BeamFile2D1, Source3D1, BeamFile3D1, Source4D1, BeamFile4D1, - Source5D1, BeamFile5D1]), + Source5D1, BeamFile5D1, + BeamFileSofs]), + + false = code:purge(sofs), + {module, sofs} = code:load_file(sofs), + code:stick_mod(sofs), + ok. otp_6711(Conf) when is_list(Conf) -> @@ -964,3 +999,13 @@ run_if_crypto_works(Test) -> {skip,"The crypto application is missing or broken"} end. +get_line_number_info() -> + %% The stacktrace for operators such a '+' can vary depending on + %% whether the JIT is used or not. + case catch lines:t(atom) of + {'EXIT',{badarith,[{erlang,'+',[atom,1],_}, + {lines,t,1,Info}|_]}} -> + Info; + {'EXIT',{badarith,[{lines,t,1,Info}|_]}} -> + Info + end. diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index 99f3566eabff..954efae9b709 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -1462,10 +1462,15 @@ error_info(_Config) -> {split, [<<1,2,3>>, {bm,make_ref()}, []]}, {split, [<<1,2,3>>, <<"2">>, [bad_option]]}, - {encode_hex, [{no,a,binary}]}, - {decode_hex, [{no,a,binary}]}, - {decode_hex, [<<"000">>],[allow_rename]}, - {decode_hex, [<<"GG">>],[allow_rename]} + {encode_hex, [{no,binary}]}, + {encode_hex, [{no,binary}, lowercase]}, + {encode_hex, [<<"foobar">>, othercase]}, + {encode_hex, [no_binary, othercase], [{1,".*"}, {2,".*"}]}, + + {decode_hex, [{no,binary}]}, + {decode_hex, [<<"000">>]}, + {decode_hex, [<<"GG">>]}, + {decode_hex, [<<255>>]} ], error_info_lib:test_error_info(binary, L). @@ -1479,6 +1484,23 @@ hex_encoding(Config) when is_list(Config) -> <<"666F6F6261">> = binary:encode_hex(<<"fooba">>), <<"666F6F626172">> = binary:encode_hex(<<"foobar">>), + + <<>> = binary:encode_hex(<<>>, uppercase), + <<"66">> = binary:encode_hex(<<"f">>, uppercase), + <<"666F">> = binary:encode_hex(<<"fo">>, uppercase), + <<"666F6F">> = binary:encode_hex(<<"foo">>, uppercase), + <<"666F6F62">> = binary:encode_hex(<<"foob">>, uppercase), + <<"666F6F6261">> = binary:encode_hex(<<"fooba">>, uppercase), + <<"666F6F626172">> = binary:encode_hex(<<"foobar">>, uppercase), + + <<>> = binary:encode_hex(<<>>, lowercase), + <<"66">> = binary:encode_hex(<<"f">>, lowercase), + <<"666f">> = binary:encode_hex(<<"fo">>, lowercase), + <<"666f6f">> = binary:encode_hex(<<"foo">>, lowercase), + <<"666f6f62">> = binary:encode_hex(<<"foob">>, lowercase), + <<"666f6f6261">> = binary:encode_hex(<<"fooba">>, lowercase), + <<"666f6f626172">> = binary:encode_hex(<<"foobar">>, lowercase), + <<>> = binary:decode_hex(<<>>), <<"f">> = binary:decode_hex(<<"66">>), <<"fo">> = binary:decode_hex(<<"666F">>), @@ -1494,8 +1516,29 @@ hex_encoding(Config) when is_list(Config) -> <<"foobar">> = binary:decode_hex(<<"666f6f626172">>), <<"foobar">> = binary:decode_hex(<<"666f6F626172">>), + + rand:seed(default), + io:format("*** SEED: ~p ***\n", [rand:export_seed()]), + Bytes = iolist_to_binary([rand:bytes(256), lists:seq(0, 255)]), + do_hex_roundtrip(Bytes), + ok. +do_hex_roundtrip(Bytes) -> + UpperHex = binary:encode_hex(Bytes), + UpperHex = binary:encode_hex(Bytes, uppercase), + LowerHex = binary:encode_hex(Bytes, lowercase), + + Bytes = binary:decode_hex(UpperHex), + Bytes = binary:decode_hex(LowerHex), + + case Bytes of + <<_, Rest/binary>> -> + do_hex_roundtrip(Rest); + <<>> -> + ok + end. + %%% %%% Utilities. %%% diff --git a/lib/stdlib/test/binary_property_test_SUITE.erl b/lib/stdlib/test/binary_property_test_SUITE.erl new file mode 100644 index 000000000000..4ec1ba67ab30 --- /dev/null +++ b/lib/stdlib/test/binary_property_test_SUITE.erl @@ -0,0 +1,35 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2022. 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(binary_property_test_SUITE). + +-compile([export_all, nowarn_export_all]). + +all() -> + [encode_hex_case]. + +init_per_suite(Config) -> + ct_property_test:init_per_suite(Config). + +end_per_suite(Config) -> + Config. + +encode_hex_case(Config) -> + ct_property_test:quickcheck(binary_prop:prop_hex_encode_2(), Config). + diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl index a52bda891092..315ae64173a5 100644 --- a/lib/stdlib/test/c_SUITE.erl +++ b/lib/stdlib/test/c_SUITE.erl @@ -180,7 +180,7 @@ ls(Config) when is_list(Config) -> ok = c:ls(File), ok = c:ls([[[[File]]]]), ok = c:ls("no_such_file"), - ok = c:ls(list_to_atom(code:which(c))), + ok = c:ls(code:where_is_file("c.beam")), ok. %% Check that c:memory/[0,1] returns consistent results. diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl index bea5a217db22..1dbbf678fdec 100644 --- a/lib/stdlib/test/calendar_SUITE.erl +++ b/lib/stdlib/test/calendar_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -112,21 +112,23 @@ leap_years(Config) when is_list(Config) -> last_day_of_the_month(Config) when is_list(Config) -> check_last_day_of_the_month({?START_YEAR, 1}, {?END_YEAR, 1}). -%% Tests local_time_to_universal_time_dst for MET. +%% Tests local_time_to_universal_time_dst for CET/CEST/MET/MEST. local_time_to_universal_time_dst(Config) when is_list(Config) -> case os:type() of {unix,_} -> case os:cmd("date '+%Z'") of - "SAST"++_ -> - {comment, "Spoky time zone with zero-set DST, skipped"}; + "ME"++_ -> %% covers MET/MEST + local_time_to_universal_time_dst_x(Config); + "CE"++_ -> %% covers CET/CEST + local_time_to_universal_time_dst_x(Config); _ -> - local_time_to_universal_time_dst_x(Config) + {skip, "This test runs only for MET/MEST/CET/CEST"} end; _ -> local_time_to_universal_time_dst_x(Config) end. local_time_to_universal_time_dst_x(Config) when is_list(Config) -> - %% Assumes MET (UTC+1 / UTC+2(dst) + %% Assumes CET (UTC+1 / UTC+2(dst) or MET (same as CET) LtW = {{2003,01,15},{14,00,00}}, % Winter UtW = {{2003,01,15},{13,00,00}}, % UtWd = {{2003,01,15},{12,00,00}}, % dst @@ -192,15 +194,19 @@ rfc3339(Config) when is_list(Config) -> Mys = [{unit, microsecond}], Ns = [{unit, nanosecond}], S = [{unit, second}], + Na = [{unit, native}], D = [{time_designator, $\s}], Z = [{offset, "Z"}], "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms), - "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12t23:20:50.52z", Ms), + "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12t23:20:50.52z", Na), "1985-04-12T21:20:50.520Z" = test_parse("1985-04-12T23:20:50.52+02:00", Ms), + "1985-04-12T21:20:50.520Z" = + test_parse("1985-04-12T23:20:50.52+02:00", Na), "1985-04-12T23:20:50Z" = test_parse("1985-04-12T23:20:50.52Z", S), "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms), + "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Na), "1985-04-12T23:20:50.520000Z" = test_parse("1985-04-12t23:20:50.52z", Mys), "1985-04-12 21:20:50.520000000Z" = @@ -216,13 +222,15 @@ rfc3339(Config) when is_list(Config) -> "9999-12-31T23:59:59Z" = do_format_z(253402300799, []), "9999-12-31T23:59:59.999Z" = do_format_z(253402300799*1000+999, Ms), + NaPerSec = erlang:convert_time_unit(1, second, native), + "9999-12-31T23:59:59.999Z" = do_format_z(253402300799*NaPerSec+(NaPerSec-1), Na), "9999-12-31T23:59:59.999999Z" = - do_format_z(253402300799*1000000+999999, Mys), + do_format_z(253402300799*1_000_000+999_999, Mys), "9999-12-31T23:59:59.999999999Z" = - do_format_z(253402300799*1000000000+999999999, Ns), + do_format_z(253402300799*1_000_000_000+999_999_999, Ns), {'EXIT', _} = (catch do_format_z(253402300799+1, [])), {'EXIT', _} = (catch do_parse("9999-12-31T23:59:60Z", [])), - {'EXIT', _} = (catch do_format_z(253402300799*1000000000+999999999+1, Ns)), + {'EXIT', _} = (catch do_format_z(253402300799*1_000_000_000+999_999_999+1, Ns)), {'EXIT', _} = (catch do_parse("2010-04-11T22:35:41", [])), % OTP-16514 253402300799 = do_parse("9999-12-31T23:59:59Z", []), @@ -236,6 +244,7 @@ rfc3339(Config) when is_list(Config) -> "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.5Z"), "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.55Z"), "1970-01-02T00:00:00.550Z" = test_parse("1970-01-01T23:59:60.55Z", Ms), + "1970-01-02T00:00:00.550Z" = test_parse("1970-01-01T23:59:60.55Z", Na), "1970-01-02T00:00:00.550000Z" = test_parse("1970-01-01T23:59:60.55Z", Mys), "1970-01-02T00:00:00.550000000Z" = @@ -263,33 +272,45 @@ rfc3339(Config) when is_list(Config) -> Str = "2000-01-01T10:02:00+00:02", Str = do_format(TO, [{offset, 120}]), "2000-01-01T10:02:00.000+00:02" = - do_format(TO * 1000, [{offset, 120 * 1000}]++Ms), + do_format(TO * 1000, [{offset, 120_000}]++Ms), "2000-01-01T10:02:00.000000+00:02" = - do_format(TO * 1000 * 1000, [{offset, 120 * 1000 * 1000}]++Mys), + do_format(TO * 1_000_000, [{offset, 120_000_000}]++Mys), "2000-01-01T10:02:00.000000000+00:02" = - do_format(TO * 1000 * 1000 * 1000, - [{offset, 120 * 1000 * 1000 * 1000}]++Ns), + do_format(TO * 1_000_000_000, + [{offset, 120_000_000_000}]++Ns), + "2000-01-01T10:02:00.000+00:02" = + do_format(TO * NaPerSec, [{offset, 120 * NaPerSec}]++Na), + + 1656147840 = do_parse("2022-06-25 11:04:00+02", []), + 1656155040 = do_parse("2022-06-25 11:04:00-00", []), + NStr = "2000-01-01T09:58:00-00:02", NStr = do_format(TO, [{offset, -120}]), "2000-01-01T09:58:00.000-00:02" = - do_format(TO * 1000, [{offset, -120 * 1000}]++Ms), + do_format(TO * 1000, [{offset, -120_000}]++Ms), + "2000-01-01T09:58:00.000-00:02" = + do_format(TO * NaPerSec, [{offset, -120 * NaPerSec}]++Na), "2000-01-01T09:58:00.000000-00:02" = - do_format(TO * 1000 * 1000, [{offset, -120 * 1000 * 1000}]++Mys), + do_format(TO * 1_000_000, [{offset, -120_000_000}]++Mys), "2000-01-01T09:58:00.000000000-00:02" = - do_format(TO * 1000 * 1000 * 1000, - [{offset, -120 * 1000 * 1000 * 1000}]++Ns), + do_format(TO * 1_000_000_000, + [{offset, -120_000_000_000}]++Ns), + "2000-01-01T09:58:00.000-00:02" = + do_format(TO * 1000, [{offset, -120_000}]++Ms), + "2000-01-01T09:58:00.000-00:02" = + do_format(TO * NaPerSec, [{offset, -120 * NaPerSec}]++Na), - 543210000 = do_parse("1970-01-01T00:00:00.54321Z", Ns), - 54321000 = do_parse("1970-01-01T00:00:00.054321Z", Ns), - 543210 = do_parse("1970-01-01T00:00:00.54321Z", Mys), + 543_210_000 = do_parse("1970-01-01T00:00:00.54321Z", Ns), + 543_210_00 = do_parse("1970-01-01T00:00:00.054321Z", Ns), + 543_210 = do_parse("1970-01-01T00:00:00.54321Z", Mys), 543 = do_parse("1970-01-01T00:00:00.54321Z", Ms), 0 = do_parse("1970-01-01T00:00:00.000001Z", Ms), 1 = do_parse("1970-01-01T00:00:00.000001Z", Mys), 1000 = do_parse("1970-01-01T00:00:00.000001Z", Ns), 0 = do_parse("1970-01-01Q00:00:00.00049Z", Ms), 1 = do_parse("1970-01-01Q00:00:00.0005Z", Ms), - 6543210 = do_parse("1970-01-01T00:00:06.54321Z", Mys), + 6543_210 = do_parse("1970-01-01T00:00:06.54321Z", Mys), 298815132000000 = do_parse("1979-06-21T12:12:12Z", Mys), -1613826000000000 = do_parse("1918-11-11T11:00:00Z", Mys), -1613833200000000 = do_parse("1918-11-11T11:00:00+02:00", Mys), @@ -300,11 +321,11 @@ rfc3339(Config) when is_list(Config) -> "1970-01-01T00:00:00.001Z" = do_format_z(1, Ms), "1970-01-01T00:00:00.000001Z" = do_format_z(1, Mys), "1970-01-01T00:00:00.000000001Z" = do_format_z(1, Ns), - "1970-01-01T00:00:01.000000Z" = do_format_z(1000000, Mys), - "1970-01-01T00:00:00.543210Z" = do_format_z(543210, Mys), + "1970-01-01T00:00:01.000000Z" = do_format_z(1_000_000, Mys), + "1970-01-01T00:00:00.543210Z" = do_format_z(543_210, Mys), "1970-01-01T00:00:00.543Z" = do_format_z(543, Ms), - "1970-01-01T00:00:00.543210000Z" = do_format_z(543210000, Ns), - "1970-01-01T00:00:06.543210Z" = do_format_z(6543210, Mys), + "1970-01-01T00:00:00.543210000Z" = do_format_z(543_210_000, Ns), + "1970-01-01T00:00:06.543210Z" = do_format_z(6_543_210, Mys), "1979-06-21T12:12:12.000000Z" = do_format_z(298815132000000, Mys), "1918-11-11T13:00:00.000000Z" = do_format_z(-1613818800000000, Mys), ok. diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 51aa21f91992..5a19717c28e6 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -46,7 +46,7 @@ otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1, otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1, otp_13229/1, - otp_13260/1, otp_13830/1]). + otp_13260/1, otp_13830/1, receive_optimisation/1]). -export([dets_dirty_loop/0]). @@ -94,7 +94,7 @@ all() -> insert_new, repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709, - otp_13229, otp_13260, otp_13830 + otp_13229, otp_13260, otp_13830, receive_optimisation ]. groups() -> @@ -115,9 +115,9 @@ end_per_group(_GroupName, Config) -> %% OTP-3621 newly_started(Config) when is_list(Config) -> true = is_alive(), - {ok, Node} = test_server:start_node(slave1, slave, []), + {ok, Peer, Node} = ?CT_PEER(), [] = rpc:call(Node, dets, all, []), - test_server:stop_node(Node), + peer:stop(Peer), ok. basic(Config) when is_list(Config) -> @@ -153,7 +153,7 @@ open(Config) when is_list(Config) -> %% Running this test twice means that the Dets server is restarted %% twice. dets_sup specifies a maximum of 4 restarts in an hour. %% If this becomes a problem, one should consider running this - %% test on a slave node. + %% test on a peer node. {Sets, Bags, Dups} = args(Config), @@ -373,12 +373,7 @@ dirty_mark(Config) when is_list(Config) -> exit(other_process_dead) end end, - {ok, Node} = test_server:start_node(dets_dirty_mark, - slave, - [{linked, false}, - {args, "-pa " ++ - filename:dirname - (code:which(?MODULE))}]), + {ok, Peer, Node} = ?CT_PEER(), ok = ensure_node(20, Node), %% io:format("~p~n",[rpc:call(Node, code, get_path, [])]), %% io:format("~p~n",[rpc:call(Node, file, get_cwd, [])]), @@ -387,7 +382,7 @@ dirty_mark(Config) when is_list(Config) -> [?MODULE, dets_dirty_loop, []]), {ok, Tab} = Call(Pid, [open, Tab, [{file, FName}]]), [{opel,germany}] = Call(Pid, [read,Tab,opel]), - test_server:stop_node(Node), + peer:stop(Peer), {ok, Tab} = dets:open_file(Tab,[{file, FName}, {repair,false}]), ok = dets:close(Tab), @@ -421,12 +416,7 @@ dirty_mark2(Config) when is_list(Config) -> exit(other_process_dead) end end, - {ok, Node} = test_server:start_node(dets_dirty_mark2, - slave, - [{linked, false}, - {args, "-pa " ++ - filename:dirname - (code:which(?MODULE))}]), + {ok, Peer, Node} = ?CT_PEER(), ok = ensure_node(20, Node), Pid = rpc:call(Node,erlang, spawn, [?MODULE, dets_dirty_loop, []]), @@ -435,7 +425,7 @@ dirty_mark2(Config) when is_list(Config) -> timer:sleep(2100), %% Read something, just to give auto save time to finish. [{opel,germany}] = Call(Pid, [read,Tab,opel]), - test_server:stop_node(Node), + peer:stop(Peer), {ok, Tab} = dets:open_file(Tab, [{file, FName}, {repair,false}]), ok = dets:close(Tab), file:delete(FName), @@ -3502,6 +3492,34 @@ otp_13830(Config) -> {ok, Tab} = dets:open_file(Tab, [{file, File}, {version, default}]), ok = dets:close(Tab). +receive_optimisation(Config) -> + Tab = dets_receive_optimisation_test, + FName = filename(Tab, Config), + + % Spam message box + lists:foreach(fun(_) -> self() ! {spam, it} end, lists:seq(1, 1_000_000)), + + {ok, _} = dets:open_file(Tab,[{file, FName}]), + ok = dets:insert(Tab,{one, record}), + + StartTime = os:system_time(millisecond), + + % We expect one thousand of simple lookups to finish in one second + Lookups = 1000, + Timeout = 1000, + Loop = fun Loop(N) when N =< 0 -> ok; + Loop(N) -> + Now = os:system_time(millisecond), + (Now - StartTime > Timeout) andalso throw({timeout_after, Lookups - N}), + [{one, record}] = dets:lookup(Tab, one), + Loop(N-1) + end, + + ok = Loop(Lookups), + + ok = dets:close(Tab), + ok = file:delete(FName). + %% %% Parts common to several test cases %% diff --git a/lib/stdlib/test/dummy_h.erl b/lib/stdlib/test/dummy_h.erl index 7a9eb11f98f1..4fffcd86d8c2 100644 --- a/lib/stdlib/test/dummy_h.erl +++ b/lib/stdlib/test/dummy_h.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -22,7 +22,7 @@ %% Test event handler for gen_event_SUITE.erl -export([init/1, handle_event/2, handle_call/2, handle_info/2, - terminate/2]). + terminate/2, format_status/1]). init(make_error) -> {error, my_error}; @@ -63,6 +63,9 @@ handle_call(hibernate, _State) -> handle_call(hibernate_later, _State) -> timer:send_after(1000,sleep), {ok,later,[]}; +handle_call({delayed_answer, T}, State) -> + receive after T -> ok end, + {ok, delayed, State}; handle_call(_Query, State) -> {ok, ok, State}. @@ -97,3 +100,5 @@ terminate(_Reason, {undef_in_terminate, {Mod, Fun}}) -> terminate(_Reason, _State) -> ok. +format_status(#{ state := _State } = S) -> + S#{ state := "dummy1_h handler state" }. diff --git a/lib/stdlib/test/edlin_context_SUITE.erl b/lib/stdlib/test/edlin_context_SUITE.erl new file mode 100644 index 000000000000..5e84a9019940 --- /dev/null +++ b/lib/stdlib/test/edlin_context_SUITE.erl @@ -0,0 +1,189 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2023. 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(edlin_context_SUITE). +-include_lib("common_test/include/ct.hrl"). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1]). + +-export([get_context/1]). + +suite() -> + [{timetrap,{minutes,1}}]. +all() -> + [get_context]. +groups() -> + []. +init_per_suite(Config) -> + Config. +end_per_suite(_Config) -> + ok. + +get_context(_Config) -> + {term, [], {atom, "h"}} = edlin_context:get_context(lists:reverse("h")), + {term} = edlin_context:get_context(lists:reverse("h(file")), + {term} = edlin_context:get_context(lists:reverse("h(file,open")), + {term, [{call, "h(file,open)"}], {atom, "h"}} = edlin_context:get_context(lists:reverse("h(file,open), h")), + {term} = edlin_context:get_context(lists:reverse("h(file,open), h(file")), + {term} = edlin_context:get_context(lists:reverse("h(file,open), h(file,open")), + {term, [{call, "h(file,open)"}], {call, "h(file,open)"}} = edlin_context:get_context(lists:reverse("h(file,open), h(file,open)")), + {function} = edlin_context:get_context(lists:reverse("file:")), + {function} = edlin_context:get_context(lists:reverse("file:open")), + {function, "file", "open", [], [], []} = edlin_context:get_context(lists:reverse("file:open(")), + {string} = edlin_context:get_context(lists:reverse("file:open(\"")), + {string} = edlin_context:get_context(lists:reverse("file:open(\"/")), + {string} = edlin_context:get_context(lists:reverse("file:open(\"Word")), + {function, "file", "open", [], {string, "\"\""}, []} = edlin_context:get_context(lists:reverse("file:open(\"\"")), + {function, "file", "open", [{string, "\"\""}], [], []} = edlin_context:get_context(lists:reverse("file:open(\"\",")), + {function, "file", "open", [{string, "\"\""}], [], [{list, [], []}]} = edlin_context:get_context(lists:reverse("file:open(\"\",[")), + {function, "file", "open", [{string, "\"\""}], [], [{tuple, [], []}]} = edlin_context:get_context(lists:reverse("file:open(\"\",{")), + {function, "file", "open", [{string, "\"\""}], [], [{list, [], []},{tuple, [], []}]} = edlin_context:get_context(lists:reverse("file:open(\"\",[{")), + {function, "file", "open", [{string, "\"\""}], [], [{list, [], {atom, "atom"}}]} = edlin_context:get_context(lists:reverse("file:open(\"\",[atom")), + {function, "file", "open", [{string, "\"\""}], [], [{tuple, [], {atom, "atom"}}]} = edlin_context:get_context(lists:reverse("file:open(\"\",{atom")), + {function, "file", "open", [{string, "\"\""}], [], [{list, [], []},{tuple, [], {atom, "atom"}}]} = edlin_context:get_context(lists:reverse("file:open(\"\",[{atom")), + {function, "file", "open", [{string, "\"\""}], [], [{list, [], []},{tuple, [{atom, "atom"}], []}]} = edlin_context:get_context(lists:reverse("file:open(\"\",[{atom,")), + {function, "file", "open", [{string, "\"\""}], [], [{map, ["atom"], "atom", [], []}]} = edlin_context:get_context(lists:reverse("file:open(\"\",#{ atom =>")), + {term, [], {atom, "list"}} = edlin_context:get_context(lists:reverse("#{list")), + {term, [], {atom, "list"}} = edlin_context:get_context(lists:reverse("{list")), + {term, [], {atom, "list"}} = edlin_context:get_context(lists:reverse("[list")), + {map, "M", []} = edlin_context:get_context(lists:reverse("M#{")), + {map, "M", []} = edlin_context:get_context(lists:reverse("M#{key")), + {map, "M", ["key"]} = edlin_context:get_context(lists:reverse("M#{key=>")), + {map, "M", ["key"]} = edlin_context:get_context(lists:reverse("M#{key:=")), %% map value + {map, "M", ["key"]} = edlin_context:get_context(lists:reverse("M#{key=>0")), + {map, "M", ["key"]} = edlin_context:get_context(lists:reverse("M#{key=>0,")), + {map, "M", ["key", "key2"]} = edlin_context:get_context(lists:reverse("M#{key=>0,key2=>")), + {map_or_record} = edlin_context:get_context(lists:reverse("#")), + {record, "record", [], [], [], [], []} = edlin_context:get_context(lists:reverse("#record{")), + {record, "record", [], [], [], [], []} = edlin_context:get_context(lists:reverse("#record.")), + {record, "record", [], [], [], {atom, "field"}, []} = edlin_context:get_context(lists:reverse("#record{field")), + {record, "record", ["field"], "field", [], [], []} = edlin_context:get_context(lists:reverse("#record{field=>")), + {record, "record", ["field"], "field", [], [], []} = edlin_context:get_context(lists:reverse("#record{field:=")), %% record_field value + {record, "record", ["field"], [], [{integer, "0"}], [], []} = edlin_context:get_context(lists:reverse("R#record{field=>0,")), + {record, "record", ["field", "field2"], "field2", [{integer,"0"}], [], [{list, [], []},{tuple, [{atom, "atom"}], []}]} = edlin_context:get_context(lists:reverse("R#record{field=>0,field2=>[{atom,")), + {term,[],{atom,"fun"}} = edlin_context:get_context(lists:reverse("fun")), + {term,[],{atom,"fun"}} = edlin_context:get_context(lists:reverse("fun ")), + {fun_} = edlin_context:get_context(lists:reverse("fun m")), + {fun_, "m"} = edlin_context:get_context(lists:reverse("fun m:")), + {fun_, "m"} = edlin_context:get_context(lists:reverse("fun m:f")), + {fun_, "m", "f"} = edlin_context:get_context(lists:reverse("fun m:f/")), + {fun_, "m", "f"} = edlin_context:get_context(lists:reverse("fun m:f/1")), + {fun_, "m", "f"} = edlin_context:get_context(lists:reverse("fun m:f/1 ")), + {term,[{fun_,"fun m:f/1"}],[]} = edlin_context:get_context(lists:reverse("fun m:f/1 ,")), + {function,"user_defined","my_fun", + [{keyword,"receive X -> X end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(receive X -> X end, ")), + {function,"user_defined","my_fun", + [{keyword,"maybe X -> X end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(maybe X -> X end, ")), + {function,"user_defined","my_fun", + [{keyword,"try a end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(try a end, ")), + {function,"user_defined","my_fun", + [{keyword,"catch X -> X end"}], + [],[]}= edlin_context:get_context(lists:reverse("my_fun(catch X -> X end, ")), + {function,"user_defined","my_fun", + [{keyword,"try a catch _:_ -> b end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(try a catch _:_ -> b end, ")), + {function,"user_defined","my_fun", + [{keyword,"begin X end"}], + [],[]}= edlin_context:get_context(lists:reverse("my_fun(begin X end, ")), + {function,"user_defined","my_fun", + [{keyword,"if X -> X end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(if X -> X end, ")), + {function,"user_defined","my_fun", + [{keyword,"case X of _ -> X end"}], + [],[]} = edlin_context:get_context(lists:reverse("my_fun(case X of _ -> X end, ")), + {binding} = edlin_context:get_context(lists:reverse("fun() -> X")), + {term,[],{atom,"x"}} = edlin_context:get_context(lists:reverse("fun() -> x")), + {term} = edlin_context:get_context(lists:reverse("fun() ->")), + {macro} = edlin_context:get_context(lists:reverse("?")), %% not supported in edlin_expand + % unknown map + {term,[{operation,"one = a"},{operation,"two = b"}],[]} = edlin_context:get_context(lists:reverse("#{ one = a, two = b, ")), + {term,[{atom,"a"},{atom,"b"}],[]} = edlin_context:get_context(lists:reverse("#{ one := a, two := b, ")), + {term,[{atom,"a"},{atom,"b"}],[]} = edlin_context:get_context(lists:reverse("#{ one => a, two => b, ")), + {term,[{operation,"A = a"},{operation,"B = b"}],[]} = edlin_context:get_context(lists:reverse("A = a, B = b, ")), + {term,[{operation,"one = a"}],[]} = edlin_context:get_context(lists:reverse("#{ one = a, two = ")), + {term,[{atom,"a"}],[]} = edlin_context:get_context(lists:reverse("#{ one := a, two := ")), + {term,[{atom,"a"}],[]} = edlin_context:get_context(lists:reverse("#{ one => a, two => ")), + {term,[{operation,"A = a"}],[]} = edlin_context:get_context(lists:reverse("A = a, B = ")), + {term,[],{operation,"A = a"}} = edlin_context:get_context(lists:reverse("A = a")), + {'end'} = edlin_context:get_context(lists:reverse("a.")), + {record,"record",[],[],[],[],[]} = edlin_context:get_context(lists:reverse("#record.")), + {record,"record",[],[],[],[],[]} = edlin_context:get_context(lists:reverse("{#record.")), + {record,"record",[],[],[],{atom,"a"},[]} = edlin_context:get_context(lists:reverse("#record.a")), + {record,"record",[],[],[],{atom,"a"},[]} = edlin_context:get_context(lists:reverse("{#record.a")), + {term,[],{record,"#record{}"}} = edlin_context:get_context(lists:reverse("#record{}")), + {term,[],{map,"#{ a => b}"}} = edlin_context:get_context(lists:reverse("#{ a => b}")), + {term,[{atom,"a"}],{atom,"tuple"}} = edlin_context:get_context(lists:reverse("{a, tuple")), + {term,[],{tuple,"{a, tuple}"}} = edlin_context:get_context(lists:reverse("{a, tuple}")), + {term,[],{call,"lists:my_fun()"}} = edlin_context:get_context(lists:reverse("lists:my_fun()")), + {term} = edlin_context:get_context(lists:reverse("(")), + {term,[],{parenthesis,"()"}} = edlin_context:get_context(lists:reverse("()")), + {new_fun,"()"} = edlin_context:get_context(lists:reverse("fun()")), + %% 256 $] + {term,[],{list,"[]"}} = edlin_context:get_context(lists:reverse("[]")), + {term,[{atom,"a"}],{atom,"b"}} = edlin_context:get_context(lists:reverse("fun() when a, b")), + {term,[{atom,"a"}],{atom,"b"}} = edlin_context:get_context(lists:reverse("fun() -> a, b")), + {term,[{atom,"a"},{atom,"b"}],[]} = edlin_context:get_context(lists:reverse("fun() -> a, b, ")), + {term, [], {pid, "<1.0.1>"}} = edlin_context:get_context(lists:reverse("<1.0.1>")), + {term, [], {funref, "#Fun"}} = edlin_context:get_context(lists:reverse("#Fun")), + {term, [], {ref, "#Ref<1.0.1>"}} = edlin_context:get_context(lists:reverse("#Ref<1.0.1>")), + %{term, [], {port, "#Port<1.0>"}} = edlin_context:get_context(lists:reverse("#Port<1.0>")), + {term, [], {binary, "<<0>>"}} = edlin_context:get_context(lists:reverse("<<0>>")), + {term,[],{keyword,"fun (X) -> X end"}} = edlin_context:get_context(lists:reverse("fun (X) -> X end")), + {term,[],{keyword,"fun(X) -> X end"}} = edlin_context:get_context(lists:reverse("fun(X) -> X end")), %% should be fun_ too + {term,[],{keyword,"receive X -> X end"}} = edlin_context:get_context(lists:reverse("receive X -> X end")), + {error, _} = edlin_context:get_context(lists:reverse("no_keyword -> X end")), + {term} = edlin_context:get_context(lists:reverse("@")), %% No valid argument 305 + {term,[],{char,"$@"}} = edlin_context:get_context(lists:reverse("$@")), + {term,[],{char,"$ "}} = edlin_context:get_context(lists:reverse("$ ")), + {term,[],{float,"1.0"}} = edlin_context:get_context(lists:reverse("1.0")), + {term,[],{integer,"10#10"}} = edlin_context:get_context(lists:reverse("10#10")), + {term,[],{integer,"1"}} = edlin_context:get_context(lists:reverse("1")), + {binding} = edlin_context:get_context(lists:reverse("{X")), + {term,[{var, "X"}], []} = edlin_context:get_context(lists:reverse("{X, ")), + {error,_} = edlin_context:get_context(lists:reverse("")), + {term} = edlin_context:get_context(lists:reverse("\"\\\"\"")), %% odd quotes "\"" + {error, _} = edlin_context:get_context(lists:reverse("{\"\", $\"}")), %% odd quotes + {term} = edlin_context:get_context(lists:reverse("receive X -> ")), + %% read operator and argument order validity + {error,_} = edlin_context:get_context(lists:reverse("foo bar")), %% TODO what should be returned here, illegal + {term,[],{operation,"\" \" \" \""}} = edlin_context:get_context(lists:reverse("\" \" \" \"")), %% " " " " + {term,[],{operation,"1 + 2"}} = edlin_context:get_context(lists:reverse("1+2")), + {term,[],{operation,"1 andalso 2"}} = edlin_context:get_context(lists:reverse("1 andalso 2")), + {term,[],{operation,"1 and 2"}} = edlin_context:get_context(lists:reverse("1 and 2")), + {term,[],{operation,"1 orelse 2"}} = edlin_context:get_context(lists:reverse("1 orelse 2")), + {term,[],{operation,"1 or 2"}} = edlin_context:get_context(lists:reverse("1 or 2")), + {term,[],{operation,"1 or 2"}} = edlin_context:get_context(lists:reverse("1 or 2")), + {term,[],{operation,"1 =/= 2"}} = edlin_context:get_context(lists:reverse("1 =/= 2")), + {term,[],{operation,"1 =:= 2"}} = edlin_context:get_context(lists:reverse("1 =:= 2")), + {term,[],{operation,"1 <=> 2"}} = edlin_context:get_context(lists:reverse("1 <=> 2")), + {term,[],{operation,"<<1>> > <<2>>"}} = edlin_context:get_context(lists:reverse("<<1>>><<2>>")), + %{term,[],{operation,"<<1>> > <<2>>"}} = edlin_context:get_context(lists:reverse("<<1>> > <<2>>")), + {error,_} = edlin_context:get_context(lists:reverse("1 + + 2")), + {term,[],{integer,"2"}} = edlin_context:get_context(lists:reverse("1 -> 2")), + {term,[],{integer,"2"}} = edlin_context:get_context(lists:reverse("receive X -> 2")), + {term} = edlin_context:get_context(lists:reverse("receive X ->")), + {term,[{integer,"2"}],{operation,"1 + 3"}} = edlin_context:get_context(lists:reverse("receive X -> 2, 1+3")), + {term,[],{integer,"-1"}} = edlin_context:get_context(lists:reverse("-1")), + {term,[],{float,"-1.2"}} = edlin_context:get_context(lists:reverse("-1.2")), + ok. \ No newline at end of file diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl index 22b6ba03afbf..206a8b7246da 100644 --- a/lib/stdlib/test/edlin_expand_SUITE.erl +++ b/lib/stdlib/test/edlin_expand_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -18,12 +18,22 @@ %% %CopyrightEnd% %% -module(edlin_expand_SUITE). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_testcase/2, end_per_testcase/2, - init_per_group/2,end_per_group/2]). --export([normal/1, quoted_fun/1, quoted_module/1, quoted_both/1, erl_1152/1, - erl_352/1, unicode/1]). - +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2, + init_per_group/2,end_per_group/2]). +-export([normal/1, type_completion/1, quoted_fun/1, quoted_module/1, quoted_both/1, erl_1152/1, get_coverage/1, + check_trailing/1, unicode/1, filename_completion/1, binding_completion/1, record_completion/1, + map_completion/1, function_parameter_completion/1, fun_completion/1]). +-record(a_record, + {a_field :: atom1 | atom2 | btom | 'my atom' | {atom3, {atom4, non_neg_integer()}} | 'undefined', + b_field :: boolean() | 'undefined', + c_field :: list(term()) | 'undefined', + d_field :: non_neg_integer() | 'undefined'}). +-record('Quoted_record', + {'A_field' :: atom1 | atom2 | btom | 'my atom' | {atom3, {atom4, non_neg_integer()}} | 'undefined', + b_field :: boolean() | 'undefined', + c_field :: list(term()) | 'undefined', + d_field :: non_neg_integer() | 'undefined'}). -include_lib("common_test/include/ct.hrl"). init_per_testcase(_Case, Config) -> @@ -37,17 +47,20 @@ suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. -all() -> - [normal, quoted_fun, quoted_module, quoted_both, erl_1152, erl_352, +all() -> + [normal, filename_completion, binding_completion, get_coverage, type_completion, + record_completion, fun_completion, map_completion, function_parameter_completion, + quoted_fun, quoted_module, quoted_both, erl_1152, check_trailing, unicode]. -groups() -> +groups() -> []. init_per_suite(Config) -> Config. end_per_suite(_Config) -> + cleanup(), ok. init_per_group(_GroupName, Config) -> @@ -60,53 +73,470 @@ cleanup() -> [try code:purge(M), code:delete(M) - catch _:_ -> ok end || M <- [expand_test, expand_test1, - 'ExpandTestCaps', 'ExpandTestCaps2']]. + catch _:_ -> ok end || M <- [expand_test, expand_test1, expand_function_parameter, + 'ExpandTestCaps', 'ExpandTestCaps1', + complete_function_parameter]]. normal(Config) when is_list(Config) -> {module,expand_test} = compile_and_load(Config,expand_test), %% These tests might fail if another module with the prefix %% "expand_" happens to also be loaded. - {yes, "test:", []} = do_expand("expand_"), + {yes,"test:",[]} = do_expand("expand_"), {no, [], []} = do_expand("expandXX_"), - {no,[], - [{"a_fun_name",1}, - {"a_less_fun_name",1}, - {"b_comes_after_a",1}, - {"expand0arity_entirely",0}, - {"module_info",0}, - {"module_info",1}]} = do_expand("expand_test:"), - {yes,[],[{"a_fun_name",1}, - {"a_less_fun_name",1}]} = do_expand("expand_test:a_"), + {no,[],[#{ + title:="functions", + elems:=[{"a_fun_name",[{ending,"("}]}, + {"a_less_fun_name",_}, + {"b_comes_after_a",_}, + {"expand0arity_entirely",_}, + {"module_info",_}] + }]} = do_expand("expand_test:"), + {yes,[],[#{title:="functions", + elems:=[{"a_fun_name",_},{"a_less_fun_name",_}]}]} = do_expand("expand_test:a_"), {yes,"arity_entirely()",[]} = do_expand("expand_test:expand0"), ok. +to_atom(Str) -> + case erl_scan:string(Str) of + {ok, [{atom,_,A}], _} -> + {ok, A}; + _ -> + error + end. + +type_completion(_Config) -> + ct:timetrap({minutes, 20}), + {Time,_} = timer:tc(fun() -> do_expand("erl_pp:expr(") end), + case Time of + Time when Time > 2600000 -> {skip, "Expansion too slow on this machine"}; + _ -> + parallelforeach( + fun(Mod) -> + Exports = edlin_expand:get_exports(Mod), + [try + Str = io_lib:write_atom(Mod) ++ ":" ++ atom_to_list(Func) ++ "(", + do_expand(Str) + catch E:R:ST -> + erlang:raise(E, {R, Mod, Func}, ST) + end || {Func, _}<- Exports] + end, [list_to_atom(M) || {M,_,_} <- code:all_available()]), + ok + end. + +parallelforeach(Fun, List) -> + case parallelforeach(Fun, List, #{}, erlang:system_info(schedulers_online)) of + [] -> ok; + Else -> ct:fail(Else) + end. +parallelforeach(_Fun, [], Workers, _MaxWorkers) when map_size(Workers) =:= 0 -> + []; +parallelforeach(Fun, List, Workers, MaxWorkers) when MaxWorkers =:= map_size(Workers); + List =:= [] -> + receive + {'DOWN', Ref, _, _, normal} -> + parallelforeach(Fun, List, maps:remove(Ref, Workers), MaxWorkers); + + {'DOWN', Ref, _, _, Reason} -> + {Arg, NewWorkers} = maps:take(Ref, Workers), + [{Arg, Reason} | parallelforeach(Fun, List, NewWorkers, MaxWorkers)] + end; +parallelforeach(Fun, [H|T], Workers, MaxWorkers) -> + {_Pid, Ref} = spawn_monitor(fun() -> Fun(H) end), + parallelforeach(Fun, T, Workers#{ Ref => H }, MaxWorkers). + +filename_completion(Config) -> + DataDir = proplists:get_value(data_dir, Config), + {ok, CWD} = file:get_cwd(), + file:set_cwd(DataDir), + {yes,"e\"",[]} = do_expand("\"visible\\ fil"), + {no,[],[]} = do_expand("\"visible fil"), + {no,[],[]} = do_expand("\" "), + {no,[],[]} = do_expand("\"\""), + {yes, "e\"", []} = do_expand("\".hidden\\ fil"), + {yes,"/", []} = do_expand("\".."), + {yes,"ta/", _} = do_expand("\"../edlin_expand_SUITE_da"), + {yes,"erl\"",[]} = do_expand("\"complete_function_parameter."), + R = case {os:type(), file:native_name_encoding()} of + {{win32,_}, _} -> {skip, "Unicode on filenames in windows are tricky"}; + {_,latin1} -> {skip, "Cannot interpret unicode filenames when native_name_encoding is latin1"}; + _ -> + {yes,"isible", + [{"visible file",_},{"visible_file",_},{"visible😀_file",_}]} = do_expand("\"v"), + {yes,"e\"",[]} = do_expand("\"visible😀_fil"), + {yes,[], + [{"../",[]}, + {".hidden file",_}, + {".hidden_file",_}, + {".hidden😀_file",_}]} = do_expand("\"."), + ok + end, + file:set_cwd(CWD), + R. + +record_completion(_Config) -> + %% test record completion for loaded records + %% test record field name completion + %% test record field completion + {yes,"ord{", []} = do_expand("#a_rec"), + {yes,"uoted_record'{", []} = do_expand("#'Q"), + {no, [], [#{title:="fields", elems:=[{"a_field",_}, {"b_field",_}, {"c_field",_}, {"d_field",_}]}]} = do_expand("#a_record{"), + {no, [], [#{title:="fields", elems:=[{"a_field",_}, {"b_field",_}, {"c_field",_}, {"d_field",_}]}]} = do_expand("#a_record."), + {yes,"eld=", []} = do_expand("#a_record{a_fi"), + {no,[],[#{title:="types",elems:= + [{"atom1",[]}, + {"atom2",[]}, + {"btom",[]}, + {"'my atom'",[]}, + {"{atom3, ...}",[]}], + options:=[{hide,title}]}]} = do_expand("#a_record{a_field="), + %% test that an already specified field does not get suggested again + {no,[], + [#{title:="fields", elems:= + [{"a_field",[{ending,"="}]}, + {"b_field",[{ending,"="}]}, + {"c_field",[{ending,"="}]}, + {"d_field",[{ending,"="}]}], + options:=[highlight_all]}]} = do_expand("#a_record{a_field={atom3,b},"), + %% test match argument and closing parenthesis completion + {yes,", ",[]} = do_expand("#a_record{a_field={atom3"), + {no,[],[#{title:="types",elems:=[{"{atom4, ...}",[]}],options:=[{hide,title}]}]} = do_expand("#a_record{a_field={atom3,"), + {no,[],[#{title:="types",elems:=[{"integer() >= 0",[]}],options:=[{hide,title}]}]} = do_expand("#a_record{a_field={atom3,{atom4, "), + {yes,"}",_} = do_expand("#a_record{a_field={atom3,{atom4, 1"), + {yes,"}",_} = do_expand("#a_record{a_field={atom3,{atom4, 1}"), + ok. + +fun_completion(_Config) -> + {yes, "/1", []} = do_expand("fun lists:unzip3"), + {no, [], []} = do_expand("fun lists:unzip3/1,"), + {no, [], []} = do_expand("lists:unzip3/1"), + {no, [], [{"2",_},{"3",_}]} = do_expand("lists:seq/"), + %{yes, ", ", _} = do_expand("lists:all(fun erlang:is_atom/1"), + {no, [], [#{}]} = do_expand("lists:all(fun erlang:is_atom/1, "), + ok. + +binding_completion(_Config) -> + %% test that bindings in the shell can be completed + {yes,"ding",[]} = do_expand("Bin"), + {yes,"ding",[]} = do_expand("file:open(Bin"), + {yes,"ding",[]} = do_expand("fun (X, Y) -> Bin"), + %% test unicode + {yes,"öndag", []} = do_expand("S"), + {yes,"", []} = do_expand("Ö"), + ok. + +map_completion(_Config) -> + %% test that key suggestion works for a known map in bindings + {no,[],[{"a_key",[{ending, "=>"}]},{"b_key",_},{"c_key",_}]} = do_expand("MapBinding#{"), + {yes, "_key=>", []} = do_expand("MapBinding#{b"), + {yes, "_key=>", []} = do_expand("MapBinding # { b"), + %% test that an already specified key does not get suggested again + {no, [], [{"a_key",_},{"c_key", _}]} = do_expand("MapBinding#{b_key=>1,"), + %% test that unicode works + ok. + +function_parameter_completion(Config) -> + %% test first and second parameter + %% test multiple arities with same type on first parameter + %% test multiple arities with different type on first parameter + %% test that recursive types does not trigger endless loop + %% test that getting type of out of bound parameter does not trigger crash + compile_and_load2(Config,complete_function_parameter), + {no, [], [#{elems:=[#{title:="complete_function_parameter:an_untyped_fun/2", elems:=[]}]}]} = do_expand("complete_function_parameter:an_untyped_fun("), + {yes,":",[]} = do_expand("complete_function_parameter:an_untyped_fun(complete_function_parameter"), + {no, [], [#{elems:=[#{elems:=[#{title:="types",elems:=[{"integer()",[]}]}]}]}]} = do_expand("complete_function_parameter:a_fun_name("), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"integer()",[]}]}]}]}]} = do_expand("complete_function_parameter:a_fun_name(1,"), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"integer()",[]}]}]}]}]} = do_expand("complete_function_parameter : a_fun_name ( 1 , "), + {yes, ")", []} = do_expand("complete_function_parameter:a_fun_name(1,2"), + {no, [], []} = do_expand("complete_function_parameter:a_fun_name(1,2,"), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"any()",[]},{"[any() | [Deeplist]]",[]}]}]}]}]} = do_expand("complete_function_parameter:a_deeplist_fun("), + {no,[],[#{title:="typespecs", + elems:=[#{title:= + "complete_function_parameter:multi_arity_fun(T1)", + elems:=[#{title:="types", + elems:=[{"integer()",[]}], + options:=[{hide,title}]}], + options:=[{highlight_param,1}]}, + #{title:= + "complete_function_parameter:multi_arity_fun(T1, T2)", + elems:=[#{title:="types", + elems:=[{"integer()",[]}], + options:=[{hide,title}]}], + options:=[{highlight_param,1}]}, + #{title:= + "complete_function_parameter:multi_arity_fun()", + options:=[], + elems:=[")"]}], + options:=[highlight_all]}]} = do_expand("complete_function_parameter:multi_arity_fun("), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"true",[]},{"false",[]}]}]}]}]} = do_expand("complete_function_parameter:multi_arity_fun(1,"), + {no,[], + [#{elems := + [#{elems := + [#{elems := [{"integer()",[]}], + options := [{hide,title}], + title := "types"}], + options := [{highlight_param,1}], + title := + "complete_function_parameter:different_multi_arity_fun(T1)"}, + #{elems := + [#{elems := [{"true",[]},{"false",[]}], + options := [{hide,title}], + title := "types"}], + options := [{highlight_param,1}], + title := + "complete_function_parameter:different_multi_arity_fun(B1, T1)"}], + options := [highlight_all], + title := "typespecs"}]} = do_expand("complete_function_parameter:different_multi_arity_fun("), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"integer()",[]}]}]}]}]} = do_expand("complete_function_parameter:different_multi_arity_fun(false,"), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"{atom1, ...}",[]}, + {"atom1",[]}, + {"atom2",[]}, + {"[atom4 | atom5]",[]}]}]}]}]} = do_expand("complete_function_parameter:advanced_nested_parameter("), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"atom1",[]}]}]}]}]} = do_expand("complete_function_parameter:advanced_nested_parameter({"), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"{integer() >= 0, ...}",[]}]}]}]}]} = do_expand("complete_function_parameter:advanced_nested_parameter({atom1,"), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"atom4",[]},{"atom5",[]}]}]}]}]} = do_expand("complete_function_parameter:advanced_nested_parameter(["), + {no, [], [#{elems:=[#{elems:=[#{elems:=[{"atom4",[]},{"atom5",[]}]}]}]}]} = do_expand("complete_function_parameter : advanced_nested_parameter ( [ , "), + {no,[], + [#{elems := + [#{elems := + [#{elems := [{"integer()",[]}], + options := [{hide,title}], + title := "types"}], + options := [{highlight_param,1}], + title := + "complete_function_parameter:different_multi_arity_fun(T1)"}, + #{elems := + [#{elems := [{"true",[]},{"false",[]}], + options := [{hide,title}], + title := "types"}], + options := [{highlight_param,1}], + title := + "complete_function_parameter:different_multi_arity_fun(B1, T1)"}], + options := [highlight_all], + title := "typespecs"}]} = do_expand("complete_function_parameter:different_multi_arity_fun("), + %% Hide results where the type of the first parameters does not match the prototype header + {no,[], + [#{title:="typespecs", + elems:=[#{title:="complete_function_parameter:different_multi_arity_fun(B1, T1)", + elems:=[#{title:="types", + elems:=[{"integer()",[]}], + options:=[{hide,title}]}], + options:=[{highlight_param,2}]}], + options:=[highlight_all]}]} = do_expand("complete_function_parameter:different_multi_arity_fun(false,"), + {no, _, []} = do_expand("complete_function_parameter:different_multi_arity_fun(atom,"), + {yes, _, _} = do_expand("complete_function_parameter:'emoji"), + + ok. + +get_coverage(Config) -> + compile_and_load2(Config,complete_function_parameter), + do_expand("\""), + do_expand("\"."), + do_expand("\"../"), + do_expand("\"/"), + do_expand("fun m:f"), + do_expand("fun m:f/"), + do_expand("#"), + do_expand("MapBinding#{"), + do_expand("B"), + do_expand("#a_record{"), + do_expand("#a_record{a_field=>"), + + %% match_arguments and is_type tests + do_expand("complete_function_parameter:map_parameter_function(#{"), + do_expand("complete_function_parameter:map_parameter_function(#{a"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1,"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1,d=>err"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1,d=>error"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1,d=>error}"), + do_expand("complete_function_parameter:map_parameter_function(#{a=>1,b=>2,c=>3,d=>error"), + do_expand("complete_function_parameter:map_parameter_function(#{}, "), + do_expand("complete_function_parameter:map_parameter_function(#{V=>1}, "), + do_expand("complete_function_parameter:map_parameter_function(#{a=>V}, "), + do_expand("complete_function_parameter:tuple_parameter_function({a,b}, "), + do_expand("complete_function_parameter:tuple_parameter_function({a,V}, "), + do_expand("complete_function_parameter:list_parameter_function([], "), + do_expand("complete_function_parameter:list_parameter_function([atom], "), + true = {no, [], []} =/= do_expand("complete_function_parameter:list_parameter_function([V], "), + do_expand("complete_function_parameter:non_empty_list_parameter_function([atom], "), + do_expand("complete_function_parameter:non_empty_list_parameter_function([], "), + do_expand("complete_function_parameter:binary_parameter_function(<<0>>, "), + do_expand("complete_function_parameter:binary_parameter_function(<>, "), + do_expand("complete_function_parameter:integer_parameter_function(0, "), + do_expand("complete_function_parameter:non_neg_integer_parameter_function(1, "), + do_expand("complete_function_parameter:neg_integer_parameter_function(-1, "), + do_expand("complete_function_parameter:float_parameter_function(0.1, "), + do_expand("complete_function_parameter:pid_parameter_function(<0.1.0>, "), + do_expand("complete_function_parameter:port_parameter_function(#Port<0.1>, "), + do_expand("complete_function_parameter:record_parameter_function(#a_record{a = 1}, "), + do_expand("complete_function_parameter:function_parameter_function(#Fun, "), + do_expand("complete_function_parameter:function_parameter_function(fun(X) -> X end, "), %% Todo verify fun arity + do_expand("complete_function_parameter:function_parameter_function(receive X -> X end, "), + do_expand("complete_function_parameter:function_parameter_function(V, "), + do_expand("complete_function_parameter:function_parameter_function((1+2), "), + do_expand("complete_function_parameter:function_parameter_function(some_call(), "), + do_expand("complete_function_parameter:function_parameter_function(#Nope<1.0>, "), + do_expand("complete_function_parameter:reference_parameter_function(#Ref<1.0.1.0>, "), + do_expand("complete_function_parameter:any_parameter_function(#Ref<1.0.1.0>, "), + do_expand("complete_function_parameter:ann_type_parameter_function(atom, "), + true = {no, [], []} =/= do_expand("complete_function_parameter:ann_type_parameter_function2(1, "), + do_expand("complete_function_parameter:atom_parameter_function(atom, "), + do_expand("complete_function_parameter:ann_type_parameter_function(atom"), + do_expand("complete_function_parameter:atom_parameter_function(atom"), + %% user_defined function + {yes, "func(", _} = + do_expand("my_"), + {no,[],[#{elems := + [#{elems := + [#{elems := [{"#my_record",[]}], + options := [{hide,title}], + title := "types"}], + options := [{highlight_param,1}], + title := "shell_default:my_func(A)"}], + options := [highlight_all], + title := "typespecs"}]} = + do_expand("my_func("), + {yes,"=",[]} = + do_expand("my_func(#my_record{ field"), + {no,[], + [#{elems := + [#{elems := [{"a_value",[]},{"b_value",[]}], + options := [{separator," :: "},{highlight_all}], + title := "erlang:my_type()"}], + options := [{hide,title}], + title := "types"}]} = + do_expand("my_func(#my_record{ field=>"), + {yes,"ue, ",[]} = + do_expand("my_func(#my_record{field=>a_val"), + %% bifs() + {yes, "st(", _} = + do_expand("integer_to_li"), + %% commands() + {yes, "(", _} = + do_expand("bt"), + {yes, ":", _}=edlin_expand:expand(lists:reverse("complete_function_parameter")), + {no, [], _}=edlin_expand:expand(lists:reverse("#")), + {no, [], _}=edlin_expand:expand(lists:reverse("UnbindedMap#")), + {no, [], _}=edlin_expand:expand(lists:reverse("UnbindedMap#{")), + {no, [], _}=edlin_expand:expand(lists:reverse("#{")), + {yes, "(", _}=edlin_expand:expand(lists:reverse("complete_function_parameter:a_fun_name")), + + do_expand("fun l"), + %{yes, ">", _} = + do_expand("fun () -"), + %{yes, "n ", _} = + do_expand("fun () whe "), + %{no, [], []} = + do_expand("fun () when "), + %{no, [], []} = + do_expand("fun () -> "), + %% {keyword, ...} + do_expand("M#"), + do_expand("#non_existant_record"), + do_expand("#a_record{ non_existand_field"), + + + %% match_arguments coverage + do_expand("complete_function_parameter:integer_parameter_function(atom,"), %% match_argument -> false + do_expand("complete_function_parameter:a_zero_arity_fun()"), %% match_argument, parameters empty + do_expand("erlang:system_info(thread"), + do_expand("erlang:system_info(thread_nope"), + do_expand("erlang:system_info(threads"), + do_expand("erlang:process_flag(priori"), + do_expand("erlang:process_flag(priority_nope"), + do_expand("erlang:process_flag(priority, "), + do_expand("erlang:process_flag(priority, atom"), + do_expand("erlang:process_flag(priority, 1"), + do_expand("erlang:system_info({allocator,"), + do_expand("lists:seq(1"), + do_expand("lists:seq(1, 10"), + do_expand("ssh:connect({"), + do_expand("ssh:connect({255,"), + do_expand("ssh:connect({'$i"), + do_expand("ssh:connect({'$x"), + do_expand("ssh:connect({1000,"), + do_expand("ssh:connect({255,255,255,255,255,255,255,255"), + do_expand("ssh:connect({255,255,255,255}, ["), + do_expand("ssh:connect(receive V -> V end, "), + do_expand("ssh:connect((1+2), "), + do_expand("ssh:connect(hej(), "), + do_expand("ssh:connect(fun() -> ok end, "), + do_expand("ssh:connect(fun a:b/1, "), + do_expand("ssh:connect(V, [in"), + do_expand("ssh:connect(V, [inet"), + do_expand("ssh:connect(V, [inet, "), + do_expand("atom_to_list("), + do_expand("help("), + do_expand("h(lists"), + do_expand("ht(lists"), + do_expand("h(file,"), + do_expand("ht(file,"), + do_expand("ht(file,mode"), + do_expand("file:get_cwd()"), + do_expand("fl"), + do_expand("fl("), + do_expand("fl()"), + do_expand("MapBinding#"), + do_expand("RecordBinding#"), + do_expand("TupleBinding#"), + do_expand("Binding#"), + do_expand("MyVar"), + {_, _, M0} = do_expand("ssh:connect("), + do_format(M0), + {_, _, M1} = do_expand("ssh:connect({"), + do_format(M1), + {_, _, M6} = do_expand("ssh:connect({},["), + do_format(M6), + lists:flatten(edlin_expand:format_matches(M6, 20)), + {_, _, M2} = do_expand("e"), + do_format(M2), + {_, _, M3} = do_expand("erlang:i"), + do_format(M3), + {_, _, M4} = do_expand("complete_function_parameter:an_untyped_fun("), + do_format(M4), + lists:flatten(edlin_expand:format_matches(M4, 20)), + {_,_,M5}=edlin_expand:expand("e"), + do_format(M5), + {_,_,M7}=edlin_expand:expand("erlang:"), + do_format(M7), + {_,_,M8}=edlin_expand:expand("e"), + do_format(M8), + lists:flatten(edlin_expand:format_matches(M8, 20)), + {_,_,M9}=edlin_expand:expand("complete_function_parameter:an_untyped_fun("), + lists:flatten(edlin_expand:format_matches(M9, 20)), + do_format(M5), + {_, _, M10} = edlin_expand:expand("ssh:connect({},["), + do_format(M10), + lists:flatten(edlin_expand:format_matches(M10, 20)), + ok. + %% Normal module name, some function names using quoted atoms. quoted_fun(Config) when is_list(Config) -> {module,expand_test} = compile_and_load(Config,expand_test), {module,expand_test1} = compile_and_load(Config,expand_test1), %% should be no colon after test this time - {yes, "test", []} = do_expand("expand_"), + {yes, "test", [#{title:="modules", elems:=[{"expand_test",[{ending, ":"}]},{"expand_test1",_}]}]} = do_expand("expand_"), {no, [], []} = do_expand("expandXX_"), - {no,[],[{"'#weird-fun-name'",1}, - {"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}, - {"a_fun_name",1}, - {"a_less_fun_name",1}, - {"b_comes_after_a",1}, - {"module_info",0}, - {"module_info",1}]} = do_expand("expand_test1:"), - {yes,"_",[]} = do_expand("expand_test1:a"), - {yes,[],[{"a_fun_name",1}, - {"a_less_fun_name",1}]} = do_expand("expand_test1:a_"), - {yes,[], - [{"'#weird-fun-name'",1}, - {"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}]} = do_expand("expand_test1:'"), - {yes,"uoted_fun_",[]} = do_expand("expand_test1:'Q"), - {yes,[], - [{"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}]} = do_expand("expand_test1:'Quoted_fun_"), + {no,[],[#{title:="functions", + elems:=[{"'#weird-fun-name'",_}, + {"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}, + {"a_fun_name",_}, + {"a_less_fun_name",_}, + {"b_comes_after_a",_}, + {"module_info",_}]}]} = do_expand("expand_test1:"), + {yes,"_",[#{elems:=[{"a_fun_name",_}, + {"a_less_fun_name",_}]}]} = do_expand("expand_test1:a"), + {yes,[],[#{elems:=[{"a_fun_name",_}, + {"a_less_fun_name",_}]}]} = do_expand("expand_test1:a_"), + {yes,[],[#{elems:=[{"'#weird-fun-name'",_}, + {"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}]}]} = do_expand("expand_test1:'"), + {yes,"uoted_fun_",[#{elems:=[{"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}]}]} = do_expand("expand_test1:'Q"), + {yes,[],[#{elems:=[{"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}]}]} = do_expand("expand_test1:'Quoted_fun_"), {yes,"weird-fun-name'(",[]} = do_expand("expand_test1:'#"), %% Since there is a module_info/1 as well as a module_info/0 @@ -116,146 +546,127 @@ quoted_fun(Config) when is_list(Config) -> quoted_module(Config) when is_list(Config) -> {module,'ExpandTestCaps'} = compile_and_load(Config,'ExpandTestCaps'), - {yes, "Caps':", []} = do_expand("'ExpandTest"), - {no,[], - [{"a_fun_name",1}, - {"a_less_fun_name",1}, - {"b_comes_after_a",1}, - {"module_info",0}, - {"module_info",1}]} = do_expand("'ExpandTestCaps':"), - {yes,[],[{"a_fun_name",1}, - {"a_less_fun_name",1}]} = do_expand("'ExpandTestCaps':a_"), + {yes, "Caps':",[]} = do_expand("'ExpandTest"), + {no,[],[#{elems:=[{"a_fun_name",_}, + {"a_less_fun_name",_}, + {"b_comes_after_a",_}, + {"module_info",_}]}]} = do_expand("'ExpandTestCaps':"), + {yes,[],[#{title:="functions", elems:=[{"a_fun_name",_}, + {"a_less_fun_name",_}]}]} = do_expand("'ExpandTestCaps':a_"), ok. quoted_both(Config) when is_list(Config) -> {module,'ExpandTestCaps'} = compile_and_load(Config,'ExpandTestCaps'), {module,'ExpandTestCaps1'} = compile_and_load(Config,'ExpandTestCaps1'), %% should be no colon (or quote) after test this time - {yes, "Caps", []} = do_expand("'ExpandTest"), - {no,[],[{"'#weird-fun-name'",0}, - {"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}, - {"a_fun_name",1}, - {"a_less_fun_name",1}, - {"b_comes_after_a",1}, - {"module_info",0}, - {"module_info",1}]} = do_expand("'ExpandTestCaps1':"), - {yes,"_",[]} = do_expand("'ExpandTestCaps1':a"), - {yes,[],[{"a_fun_name",1}, - {"a_less_fun_name",1}]} = do_expand("'ExpandTestCaps1':a_"), - {yes,[], - [{"'#weird-fun-name'",0}, - {"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}]} = do_expand("'ExpandTestCaps1':'"), - {yes,"uoted_fun_",[]} = do_expand("'ExpandTestCaps1':'Q"), - {yes,[], - [{"'Quoted_fun_name'",0}, - {"'Quoted_fun_too'",0}]} = do_expand("'ExpandTestCaps1':'Quoted_fun_"), + {yes, "Caps", [#{elems:=[{"'ExpandTestCaps'",[{ending, ":"}]},{"'ExpandTestCaps1'",_}]}]} = do_expand("'ExpandTest"), + {no,[],[#{elems:=[{"'#weird-fun-name'",_}, + {"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}, + {"a_fun_name",_}, + {"a_less_fun_name",_}, + {"b_comes_after_a",_}, + {"module_info",_}]}]} = do_expand("'ExpandTestCaps1':"), + {yes,"_",[#{elems:=[{"a_fun_name",_},{"a_less_fun_name",_}]}]} = do_expand("'ExpandTestCaps1':a"), + {yes,[],[#{elems:=[{"a_fun_name",_}, + {"a_less_fun_name",_}]}]} = do_expand("'ExpandTestCaps1':a_"), + {yes,[],[#{elems:=[{"'#weird-fun-name'",_}, + {"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}]}]} = do_expand("'ExpandTestCaps1':'"), + {yes,"uoted_fun_",[#{elems:=[{"'Quoted_fun_name'",_},{"'Quoted_fun_too'",_}]}]} = do_expand("'ExpandTestCaps1':'Q"), + {yes,[],[#{elems:=[{"'Quoted_fun_name'",_}, + {"'Quoted_fun_too'",_}]}]} = do_expand("'ExpandTestCaps1':'Quoted_fun_"), {yes,"weird-fun-name'()",[]} = do_expand("'ExpandTestCaps1':'#"), ok. %% Note: pull request #1152. erl_1152(Config) when is_list(Config) -> - "\n"++"foo"++" "++[1089]++_ = do_format(["foo",[1089]]), + "foo"++" "++[1089]++_ = do_format(["foo",[1089]]), ok. -erl_352(Config) when is_list(Config) -> - erl_352_test(3, 3), - - erl_352_test(3, 75), - erl_352_test(3, 76, [trailing]), - erl_352_test(4, 74), - erl_352_test(4, 75, [leading]), - erl_352_test(4, 76, [leading, trailing]), - - erl_352_test(75, 3), - erl_352_test(76, 3, [leading]), - erl_352_test(74, 4), - erl_352_test(75, 4, [leading]), - erl_352_test(76, 4, [leading]), - - erl_352_test(74, 74, [leading]), - erl_352_test(74, 75, [leading]), - erl_352_test(74, 76, [leading, trailing]). - -erl_352_test(PrefixLen, SuffixLen) -> - erl_352_test(PrefixLen, SuffixLen, []). - -erl_352_test(PrefixLen, SuffixLen, Dots) -> - io:format("\nPrefixLen = ~w, SuffixLen = ~w\n", [PrefixLen, SuffixLen]), - - PrefixM = lists:duplicate(PrefixLen, $p), - SuffixM = lists:duplicate(SuffixLen, $s), - LM = [PrefixM ++ S ++ SuffixM || S <- ["1", "2"]], - StrM = do_format(LM), - check_leading(StrM, "", PrefixM, SuffixM, Dots), - - PrefixF = lists:duplicate(PrefixLen, $p), - SuffixF = lists:duplicate(SuffixLen-2, $s), - LF = [{PrefixF ++ S ++ SuffixF, 1} || S <- ["1", "2"]], - StrF = do_format(LF), - true = check_leading(StrF, "/1", PrefixF, SuffixF, Dots), - +check_trailing(Config) when is_list(Config) -> + Str = lists:duplicate(80, $1), + StrF = do_format([Str]), + {_, "...\n"} = lists:split(76, StrF), ok. -check_leading(FormStr, ArityStr, Prefix, Suffix, Dots) -> - List = string:tokens(FormStr, "\n "), - io:format("~p\n", [List]), - true = lists:all(fun(L) -> length(L) < 80 end, List), - case lists:member(leading, Dots) of - true -> - true = lists:all(fun(L) -> - {"...", Rest} = lists:split(3, L), - check_trailing(Rest, ArityStr, - Suffix, Dots) - end, List); - false -> - true = lists:all(fun(L) -> - {Prefix, Rest} = - lists:split(length(Prefix), L), - check_trailing(Rest, ArityStr, - Suffix, Dots) - end, List) - end. - -check_trailing([I|Str], ArityStr, Suffix, Dots) -> - true = lists:member(I, [$1, $2]), - case lists:member(trailing, Dots) of - true -> - {Rest, "..." ++ ArityStr} = - lists:split(length(Str) - (3 + length(ArityStr)), Str), - true = lists:prefix(Rest, Suffix); - false -> - {Rest, ArityStr} = - lists:split(length(Str) - length(ArityStr), Str), - Rest =:= Suffix - end. - unicode(Config) when is_list(Config) -> {module,unicode_expand} = compile_and_load(Config,'unicode_expand'), - {no,[],[{"'кlирилли́ческий атом'",0}, - {"'кlирилли́ческий атом'",1}, - {"'кlирилли́ческий атомB'",1}, - {"module_info",0}, - {"module_info",1}]} = do_expand("unicode_expand:"), - {yes,"рилли́ческий атом", []} = do_expand("unicode_expand:'кlи"), - {yes,"еский атом", []} = do_expand("unicode_expand:'кlирилли́ч"), - {yes,"(",[]} = do_expand("unicode_expand:'кlирилли́ческий атомB'"), - "\n'кlирилли́ческий атом'/0 'кlирилли́ческий атом'/1 " - "'кlирилли́ческий атомB'/1 \nmodule_info/0 " - "module_info/1 \n" = - do_format([{"'кlирилли́ческий атом'",0}, - {"'кlирилли́ческий атом'",1}, - {"'кlирилли́ческий атомB'",1}, - {"module_info",0}, - {"module_info",1}]), + {no,[], [#{elems:=[{"'кlирилли́ческий атом'",_}, + {"'кlирилли́ческий атомB'",_}, + {"module_info",_}]}]} = do_expand("unicode_expand:"), + {yes,"рилли́ческий атом", [#{elems:=[{"'кlирилли́ческий атом'",_}, + {"'кlирилли́ческий атомB'",_}]}]} = do_expand("unicode_expand:'кlи"), + {yes,"еский атом", [#{elems:=[{"'кlирилли́ческий атом'",_}, + {"'кlирилли́ческий атомB'",_}]}]} = do_expand("unicode_expand:'кlирилли́ч"), + {yes,"(", []} = do_expand("unicode_expand:'кlирилли́ческий атомB'"), + "'кlирилли́ческий атом' 'кlирилли́ческий атомB' module_info\n" = + do_format([{"'кlирилли́ческий атом'",[]}, + {"'кlирилли́ческий атомB'",[]}, + {"module_info",[]}]), ok. do_expand(String) -> - edlin_expand:expand(lists:reverse(String)). + erlang:display(String), + Bs = [ + {'Binding', 0}, + {'MapBinding', #{a_key=>0, b_key=>1, c_key=>2}}, + {'RecordBinding', {some_record, 1, 2}}, + {'TupleBinding', {0, 1, 2}}, + {'Söndag', 0}, + {'Ö', 0}], + Rt = ets:new(records, []), + + Rt2 = [{my_record, {attribute,[{text,"record"}, + {location,{1,2}}], + record, + {my_record, [{typed_record_field,{record_field,[{text,"field"}, + {location,{1,20}}], + {atom,[{text,"field"},{location,{1,20}}],field}, + {atom,[{text,"a_value"},{location,{1,28}}],a_value}}, + {user_type,[{text,"my_type"},{location,{1,33}}], + my_type,[]}}]}}}], + Ft = [{{function,{shell_default,my_func,1}},fun(_A)->0 end}, + {{function_type,{shell_default,my_func,1}}, + {attribute,[{text,"spec"},{location,{1,2}}], + spec, + {{my_func,1}, + [{type,[{text,"("},{location,{1,14}}], + bounded_fun, + [{type,[{text,"("},{location,{1,14}}], + 'fun', + [{type,[{text,"("},{location,{1,14}}], + product, + [{var,[{text,"A"},{location,{1,15}}],'A'}]}, + {type,[{text,"integer"},{location,{1,21}}],integer,[]}]}, + [{type,[{text,"A"},{location,{1,36}}], + constraint, + [{atom,[{text,"A"},{location,{1,36}}],is_subtype}, + [{var,[{text,"A"},{location,{1,36}}],'A'}, + {type,[{text,"#"},{location,{1,41}}], + record, + [{atom,[{text,"my_record"},{location,{1,42}}], + my_record}]}]]}]]}]}}}, + {{type,my_type}, + {attribute,[{text,"type"},{location,{1,2}}], + type, + {my_type,{type,[{text,"a"},{location,{1,20}}], + union, + [{atom,[{text,"a_value"},{location,{1,20}}],a_value}, + {atom,[{text,"b_value"},{location,{1,24}}],b_value}]}, + []}}}], + shell:read_and_add_records(edlin_expand_SUITE, '_', [], Bs, Rt), + edlin_expand:expand(lists:reverse(String), [], {shell_state, Bs, ets:tab2list(Rt)++Rt2, Ft}). do_format(StringList) -> - lists:flatten(edlin_expand:format_matches(StringList)). + lists:flatten(edlin_expand:format_matches(StringList, 79)). + +compile_and_load2(Config, Module) -> + Filename = filename:join( + proplists:get_value(data_dir,Config), + atom_to_list(Module)), + PrivDir = proplists:get_value(priv_dir,Config), + c:c(Filename, [debug_info, {outdir, PrivDir}]). compile_and_load(Config,Module) -> Filename = filename:join( diff --git a/lib/dialyzer/test/race_SUITE_data/results/whereis_vars18 b/lib/stdlib/test/edlin_expand_SUITE_data/.hidden file similarity index 100% rename from lib/dialyzer/test/race_SUITE_data/results/whereis_vars18 rename to lib/stdlib/test/edlin_expand_SUITE_data/.hidden file diff --git a/lib/dialyzer/test/race_SUITE_data/results/whereis_vars19 b/lib/stdlib/test/edlin_expand_SUITE_data/.hidden_file similarity index 100% rename from lib/dialyzer/test/race_SUITE_data/results/whereis_vars19 rename to lib/stdlib/test/edlin_expand_SUITE_data/.hidden_file diff --git a/lib/dialyzer/test/race_SUITE_data/results/whereis_vars20 "b/lib/stdlib/test/edlin_expand_SUITE_data/.hidden\360\237\230\200_file" similarity index 100% rename from lib/dialyzer/test/race_SUITE_data/results/whereis_vars20 rename to "lib/stdlib/test/edlin_expand_SUITE_data/.hidden\360\237\230\200_file" diff --git a/lib/stdlib/test/edlin_expand_SUITE_data/complete_function_parameter.erl b/lib/stdlib/test/edlin_expand_SUITE_data/complete_function_parameter.erl new file mode 100644 index 000000000000..c4ad9e13f883 --- /dev/null +++ b/lib/stdlib/test/edlin_expand_SUITE_data/complete_function_parameter.erl @@ -0,0 +1,164 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2023. 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(complete_function_parameter). + +-export( + [a_fun_name/2, + an_untyped_fun/2, + a_deeplist_fun/1, + a_zero_arity_fun/0, + multi_arity_fun/0, + multi_arity_fun/1, + multi_arity_fun/2, + different_multi_arity_fun/1, + different_multi_arity_fun/2, + advanced_nested_parameter/1, + test_year/1, + 'emoji_function🤯'/1, + map_parameter_function/1, + map_parameter_function/2, + tuple_parameter_function/2, + list_parameter_function/2, + non_empty_list_parameter_function/2, + binary_parameter_function/2, + neg_integer_parameter_function/2, + non_neg_integer_parameter_function/2, + integer_parameter_function/2, + float_parameter_function/2, + port_parameter_function/2, + pid_parameter_function/2, + record_parameter_function/2, + function_parameter_function/2, + reference_parameter_function/2, + any_parameter_function/2, + ann_type_parameter_function/2, + ann_type_parameter_function2/2, + atom_parameter_function/2 + ]). +-record(a_record, {}). +%% test first and second parameter + %% test multiple arities with same type on first parameter + %% test multiple arities with different type on first parameter + %% test that recursive types does not trigger endless loop + %% test that getting type of out of bound parameter does not trigger crash +-spec a_fun_name(Start, End) -> Return when + Start :: integer(), + End :: integer(), + Return:: integer(). +a_fun_name(_Start, _End) -> 0. + +an_untyped_fun(_Start, _End) -> 1. + +-spec a_deeplist_fun(Deeplist) -> integer() when + Deeplist :: T | [Deeplist], + T :: term(). +a_deeplist_fun(Deeplist) -> lists:flatten(Deeplist). + +a_zero_arity_fun() -> 0. + +-spec multi_arity_fun() -> integer(). +multi_arity_fun() -> 0. + +-spec multi_arity_fun(T1) -> integer() when + T1 :: integer(). +multi_arity_fun(_T1) -> 1. + +-spec multi_arity_fun(T1,T2) -> integer() when + T1 :: integer(), + T2 :: boolean(). +multi_arity_fun(_T1, _T2) -> 2. + +-spec different_multi_arity_fun(T1) -> integer() when + T1 :: integer(). +different_multi_arity_fun(_T1) -> 1. +-spec different_multi_arity_fun(B1, T1) -> integer() when + B1 :: boolean(), + T1 :: integer(). +different_multi_arity_fun(_T1, _T2) -> 2. + +-spec advanced_nested_parameter(T1) -> integer() when + T1 :: {atom1, {non_neg_integer(), non_neg_integer()}} | 'atom1' | 'atom2' | ['atom4' | 'atom5']. +advanced_nested_parameter(_T1) -> 0. + +-spec test_year(Y) -> integer() when + Y :: calendar:year(). +test_year(_Y) -> 0. + +-spec 'emoji_function🤯'(integer()) -> integer(). +'emoji_function🤯'(_) -> 0. + +-spec map_parameter_function(Map) -> boolean() when + Map :: #{a => 1, b => 2, c => 3, d => error}. +map_parameter_function(_) -> false. +-spec map_parameter_function(Map, any()) -> boolean() when + Map :: #{a => 1, b => 2, c => 3, d => error}. +map_parameter_function(_,_) -> false. + +-spec binary_parameter_function(binary(), any()) -> boolean(). +binary_parameter_function(_,_) -> false. + +-spec tuple_parameter_function(tuple(), any()) -> boolean(). +tuple_parameter_function(_,_) -> false. + +-spec list_parameter_function(list(), any()) -> boolean(). +list_parameter_function(_,_) -> false. + +-spec non_empty_list_parameter_function(nonempty_list(), any()) -> boolean(). +non_empty_list_parameter_function(_,_) -> false. + +-spec integer_parameter_function(integer(), any()) -> boolean(). +integer_parameter_function(_,_) -> false. + +-spec non_neg_integer_parameter_function(non_neg_integer(), any()) -> boolean(). +non_neg_integer_parameter_function(_,_) -> false. + +-spec neg_integer_parameter_function(neg_integer(), any()) -> boolean(). +neg_integer_parameter_function(_,_) -> false. + +-spec float_parameter_function(float(), any()) -> boolean(). +float_parameter_function(_,_) -> false. + +-spec pid_parameter_function(pid(), any()) -> boolean(). +pid_parameter_function(_,_) -> false. + +-spec port_parameter_function(port(), any()) -> boolean(). +port_parameter_function(_,_) -> false. + +-spec record_parameter_function(A, any()) -> boolean() when + A :: #a_record{}. +record_parameter_function(_,_) -> false. + +-spec function_parameter_function(fun((any()) -> any()), any()) -> boolean(). +function_parameter_function(_,_) -> false. + +-spec reference_parameter_function(reference(), any()) -> boolean(). +reference_parameter_function(_,_) -> false. + +-spec any_parameter_function(any(), any()) -> boolean(). +any_parameter_function(_,_) -> false. + +-spec atom_parameter_function(atom, any()) -> boolean(). +atom_parameter_function(_,_) -> false. + +-spec ann_type_parameter_function(V::atom(), W::any()) -> boolean(). +ann_type_parameter_function(_,_) -> false. + +-spec ann_type_parameter_function2(W::any(), V::atom()) -> boolean(). +ann_type_parameter_function2(_,_) -> false. diff --git a/lib/dialyzer/test/race_SUITE_data/results/whereis_vars21 b/lib/stdlib/test/edlin_expand_SUITE_data/visible file similarity index 100% rename from lib/dialyzer/test/race_SUITE_data/results/whereis_vars21 rename to lib/stdlib/test/edlin_expand_SUITE_data/visible file diff --git a/lib/snmp/test/exp/.gitignore b/lib/stdlib/test/edlin_expand_SUITE_data/visible_file similarity index 100% rename from lib/snmp/test/exp/.gitignore rename to lib/stdlib/test/edlin_expand_SUITE_data/visible_file diff --git a/lib/tools/bin/.gitignore "b/lib/stdlib/test/edlin_expand_SUITE_data/visible\360\237\230\200_file" similarity index 100% rename from lib/tools/bin/.gitignore rename to "lib/stdlib/test/edlin_expand_SUITE_data/visible\360\237\230\200_file" diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index d9462fc17beb..9d7fef5da942 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -29,7 +29,9 @@ otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1, otp_11728/1, encoding/1, extends/1, function_macro/1, test_error/1, test_warning/1, otp_14285/1, - test_if/1,source_name/1,otp_16978/1,otp_16824/1,scan_file/1,file_macro/1]). + test_if/1,source_name/1,otp_16978/1,otp_16824/1,scan_file/1,file_macro/1, + triple_quotes_warning/1, + deterministic_include/1, nondeterministic_include/1]). -export([epp_parse_erl_form/2]). @@ -50,6 +52,7 @@ config(data_dir, _) -> filename:absname("./epp_SUITE_data"). -else. -include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). -export([init_per_testcase/2, end_per_testcase/2]). init_per_testcase(_, Config) -> @@ -70,7 +73,9 @@ all() -> overload_mac, otp_8388, otp_8470, otp_8562, otp_8665, otp_8911, otp_10302, otp_10820, otp_11728, encoding, extends, function_macro, test_error, test_warning, - otp_14285, test_if, source_name, otp_16978, otp_16824, scan_file, file_macro]. + otp_14285, test_if, source_name, otp_16978, otp_16824, scan_file, file_macro, + triple_quotes_warning, + deterministic_include, nondeterministic_include]. groups() -> [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]}, @@ -124,6 +129,64 @@ file_macro(Config) when is_list(Config) -> "Other source" = FileA = FileB, ok. +deterministic_include(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + File = filename:join(DataDir, "deterministic_include.erl"), + {ok, List} = epp:parse_file(File, [{includes, [DataDir]}, + {deterministic, true}, + {source_name, "deterministic_include.erl"}]), + + %% In deterministic mode, only basenames, rather than full paths, should + %% be written to the -file() attributes resulting from -include and -include_lib + ?assert(lists:any(fun + ({attribute,_Anno,file,{"baz.hrl",_Line}}) -> true; + (_) -> false + end, + List), + "Expected a basename in the -file attribute resulting from " ++ + "including baz.hrl in deterministic mode."), + ?assert(lists:any(fun + ({attribute,_Anno,file,{"file.hrl",_Line}}) -> true; + (_) -> false + end, + List), + "Expected a basename in the -file attribute resulting from " ++ + "including file.hrl in deterministic mode."), + ok. + +nondeterministic_include(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + File = filename:join(DataDir, "deterministic_include.erl"), + {ok, List} = epp:parse_file(File, [{includes, [DataDir]}, + {source_name, "deterministic_include.erl"}]), + + %% Outside of deterministic mode, full paths, should be written to + %% the -file() attributes resulting from -include and -include_lib + %% to make debugging easier. + %% We don't try to assume what the full absolute path will be in the + %% unit test, since that can depend on the environment and how the + %% test is executed. Instead, we just look for whether there is + %% the parent directory along with the basename at least. + IncludeAbsolutePathSuffix = filename:join("include","baz.hrl"), + ?assert(lists:any(fun + ({attribute,_Anno,file,{IncludePath,_Line}}) -> + lists:suffix(IncludeAbsolutePathSuffix,IncludePath); + (_) -> false + end, + List), + "Expected an absolute in the -file attribute resulting from " ++ + "including baz.hrl outside of deterministic mode."), + IncludeLibAbsolutePathSuffix = filename:join("include","file.hrl"), + ?assert(lists:any(fun + ({attribute,_Anno,file,{IncludePath,_line}}) -> + lists:suffix(IncludeLibAbsolutePathSuffix,IncludePath); + (_) -> false + end, + List), + "Expected an absolute in the -file attribute resulting from " ++ + "including file.hrl outside of deterministic mode."), + ok. + %%% Here is a little reimplementation of epp:parse_file, which times out %%% after 4 seconds if the epp server doesn't respond. If we use the %%% regular epp:parse_file, the test case will time out, and then epp @@ -816,7 +879,8 @@ otp_8130(Config) when is_list(Config) -> "t() -> ?a.\n"), {ok,Epp} = epp:open(File, []), PreDefMacs = macs(Epp), - ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE', + ['BASE_MODULE','BASE_MODULE_STRING','BEAM', + 'FEATURE_AVAILABLE', 'FEATURE_ENABLED','FILE', 'FUNCTION_ARITY','FUNCTION_NAME', 'LINE','MACHINE','MODULE','MODULE_STRING', 'OTP_RELEASE'] = PreDefMacs, @@ -941,7 +1005,7 @@ ifdef(Config) -> "-else.\n" "t() -> a.\n" "-endif.\n">>, - {errors,[{{3,1},epp,{bad,else}}],[]}}, + {errors,[{{3,1},epp,{bad,'else'}}],[]}}, {ifdef_c8, <<"-ifdef(a).\n" @@ -1530,20 +1594,20 @@ otp_10820(Config) when is_list(Config) -> Dir = proplists:get_value(priv_dir, Config), File = filename:join(Dir, L++".erl"), C1 = <<"%% coding: utf-8\n -module(any).">>, - ok = do_otp_10820(File, C1, "+pc latin1"), - ok = do_otp_10820(File, C1, "+pc unicode"), + ok = do_otp_10820(File, C1, ["+pc", "latin1"]), + ok = do_otp_10820(File, C1, ["+pc", "unicode"]), C2 = <<"\n-module(any).">>, - ok = do_otp_10820(File, C2, "+pc latin1"), - ok = do_otp_10820(File, C2, "+pc unicode"). + ok = do_otp_10820(File, C2, ["+pc", "latin1"]), + ok = do_otp_10820(File, C2, ["+pc", "unicode"]). do_otp_10820(File, C, PC) -> - {ok,Node} = start_node(erl_pp_helper, "+fnu " ++ PC), + {ok,Peer,Node} = ?CT_PEER(["+fnu"] ++ PC), ok = rpc:call(Node, file, write_file, [File, C]), {ok, Forms} = rpc:call(Node, epp, parse_file, [File, [],[]]), [{attribute,1,file,{File,1}}, {attribute,2,module,any}, {eof,2}] = unopaque_forms(Forms), - true = test_server:stop_node(Node), + peer:stop(Peer), ok. %% OTP_14285: Unicode atoms. @@ -1609,8 +1673,9 @@ encoding(Config) when is_list(Config) -> epp_parse_file(ErlFile, [{default_encoding,latin1}]), {ok,[{attribute,1,file,_}, {attribute,1,module,encoding}, - {eof,3}],[{encoding,none}]} = + {eof,3}],Extra0} = epp_parse_file(ErlFile, [{default_encoding,latin1},extra]), + none = proplists:get_value(encoding, Extra0), %% Try a latin-1 file with encoding given in a comment. C2 = <<"-module(encoding). @@ -1632,16 +1697,20 @@ encoding(Config) when is_list(Config) -> epp_parse_file(ErlFile, [{default_encoding,utf8}]), {ok,[{attribute,1,file,_}, {attribute,1,module,encoding}, - {eof,4}],[{encoding,latin1}]} = + {eof,4}],Extra1} = epp_parse_file(ErlFile, [extra]), + latin1 = proplists:get_value(encoding, Extra1), + {ok,[{attribute,1,file,_}, {attribute,1,module,encoding}, - {eof,4}],[{encoding,latin1}]} = + {eof,4}],Extra2} = epp_parse_file(ErlFile, [{default_encoding,latin1},extra]), + latin1 = proplists:get_value(encoding, Extra2), {ok,[{attribute,1,file,_}, {attribute,1,module,encoding}, - {eof,4}],[{encoding,latin1}]} = + {eof,4}],Extra3} = epp_parse_file(ErlFile, [{default_encoding,utf8},extra]), + latin1 = proplists:get_value(encoding, Extra3), ok. extends(Config) -> @@ -1802,7 +1871,7 @@ otp_16824(Config) when is_list(Config) -> {otp_16824_8, <<"\n-else\n" "-endif.">>, - {errors,[{{3,1},epp,{bad,else}}],[]}}, + {errors,[{{3,1},epp,{bad,'else'}}],[]}}, {otp_16824_9, <<"\n-ifndef.\n" @@ -1988,6 +2057,73 @@ otp_16824(Config) when is_list(Config) -> [] = compile(Config, Cs), ok. +triple_quotes_warning(Config) when is_list(Config) -> + Cs1 = + [{triple_quotes_warning_1, + <<"\n-doc \"foo\".\n">>, + []}, + {triple_quotes_warning_2, + <<"\n-doc \"\" \"foo\" \"\".\n">>, + []}, + {triple_quotes_warning_3, + <<"\n" + "-doc \"\"\"\n" + " foo\n" + " \"\"\".\n">>, + {warnings,[{{2,6},epp,tqstring}]}}, + {triple_quotes_warning_4, + <<"\n" + "-doc \"\"\"\"\n" + " \"\"\"\".\n">>, + {warnings, + [{{2,7},epp,tqstring}, + {{3,7},epp,tqstring}]}}, + {triple_quotes_warning_5, + <<"\n" + "-doc \"\"\"\"\"\n" + " foo\n" + " \"\"\"\"\".\n">>, + {warnings, + [{{2,8},epp,tqstring}, + {{4,9},epp,tqstring}]}} + ], + [] = compile(Config, Cs1), + + Cs2 = + [{triple_quotes_warning_10, + <<"\n" + "-export([foo/0]).\n" + "foo() ->\n" + " \"\"\"\n" + " bar\n" + " \"\"\".\n">>, + {warnings,[{{4,5},epp,tqstring}]}}, + {triple_quotes_warning_11, + <<"\n" + "-export([foo/0]).\n" + "foo() ->\n" + " \"\"\"\"\n" + " ++ lists:duplicate(4, $x) ++\n" + " \"\"\"\".\n">>, + {warnings, + [{{4,5},epp,tqstring}, + {{6,5},epp,tqstring}]}}, + {triple_quotes_warning_12, + <<"\n" + "-export([foo/0]).\n" + "foo() ->\n" + " \"\"\"\"\"\n" + " bar\n" + " \"\"\"\"\".\n">>, + {warnings, + [{{4,5},epp,tqstring}, + {{6,6},epp,tqstring}]}} ], + [] = compile(Config, Cs2), + + ok. + + + %% Start location is 1. check(Config, Tests) -> eval_tests(Config, fun check_test/3, Tests). @@ -2010,11 +2146,16 @@ eval_tests(Config, Fun, Tests) -> F = fun({N,P,Opts,E}, BadL) -> %% io:format("Testing ~p~n", [P]), Return = Fun(Config, P, Opts), + %% The result should be the same when enabling maybe ... end + %% (making 'else' a keyword instead of an atom). + Return = Fun(Config, P, [{feature,maybe_expr,enable}|Opts]), case message_compare(E, Return) of true -> case E of {errors, Errors} -> call_format_error(Errors); + {warnings, Errors} -> + call_format_error(Errors); _ -> ok end, @@ -2032,7 +2173,7 @@ check_test(Config, Test, Opts) -> PrivDir = proplists:get_value(priv_dir, Config), File = filename:join(PrivDir, Filename), ok = file:write_file(File, Test), - case epp:parse_file(File, [PrivDir], Opts) of + case epp:parse_file(File, [{includes, PrivDir}| Opts]) of {ok,Forms} -> Errors = [E || E={error,_} <- Forms], call_format_error([E || {error,E} <- Errors]), @@ -2107,18 +2248,28 @@ run_test(Config, Test0, Opts0) -> Opts = [return, {i,PrivDir},{outdir,PrivDir}] ++ Opts0, {ok, epp_test, []} = compile:file(File, Opts), AbsFile = filename:rootname(File, ".erl"), - {module, epp_test} = code:load_abs(AbsFile, epp_test), - Reply = epp_test:t(), - code:purge(epp_test), - Reply. + + case lists:member({feature, maybe_expr, enable}, Opts0) of + false -> + %% Run in node + {module, epp_test} = code:load_abs(AbsFile, epp_test), + Reply = epp_test:t(), + code:purge(epp_test), + Reply; + true -> + %% Run in peer with maybe_expr enabled + {ok, Peer, Node} = + ?CT_PEER(#{args => ["-enable-feature","maybe_expr"], + connection => 0}), + {module, epp_test} = + rpc:call(Node, code, load_abs, [AbsFile, epp_test]), + Reply = rpc:call(Node, epp_test, t, []), + peer:stop(Peer), + Reply + end. fail() -> ct:fail(failed). message_compare(T, T) -> T =:= T. - -%% +fnu means a peer node has to be started; slave will not do -start_node(Name, Xargs) -> - PA = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, peer, [{args, "-pa " ++ PA ++ " " ++ Xargs}]). diff --git a/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl b/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl new file mode 100644 index 000000000000..67763b29a00f --- /dev/null +++ b/lib/stdlib/test/epp_SUITE_data/deterministic_include.erl @@ -0,0 +1,6 @@ +-module(deterministic_include). + +-export([]). + +-include("include/baz.hrl"). +-include_lib("kernel/include/file.hrl"). diff --git a/lib/stdlib/test/epp_SUITE_data/include/baz.hrl b/lib/stdlib/test/epp_SUITE_data/include/baz.hrl new file mode 100644 index 000000000000..c0ef7a6e519e --- /dev/null +++ b/lib/stdlib/test/epp_SUITE_data/include/baz.hrl @@ -0,0 +1 @@ +-define(BAZ, true). diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 0bf59cf60e34..af6802254cf2 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2023. 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. @@ -18,6 +18,7 @@ %% %CopyrightEnd% -module(erl_eval_SUITE). +-feature(maybe_expr, enable). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2, init_per_group/2,end_per_group/2]). @@ -43,6 +44,7 @@ otp_13228/1, otp_14826/1, funs/1, + custom_stacktrace/1, try_catch/1, eval_expr_5/1, zero_width/1, @@ -52,7 +54,10 @@ otp_16439/1, otp_14708/1, otp_16545/1, - otp_16865/1]). + otp_16865/1, + eep49/1, + binary_and_map_aliases/1, + eep58/1]). %% %% Define to run outside of test server @@ -91,8 +96,9 @@ all() -> simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, otp_8133, otp_10622, otp_13228, otp_14826, - funs, try_catch, eval_expr_5, zero_width, - eep37, eep43, otp_15035, otp_16439, otp_14708, otp_16545, otp_16865]. + funs, custom_stacktrace, try_catch, eval_expr_5, zero_width, + eep37, eep43, otp_15035, otp_16439, otp_14708, otp_16545, otp_16865, + eep49, binary_and_map_aliases, eep58]. groups() -> []. @@ -1000,23 +1006,23 @@ otp_14826(_Config) -> backtrace_check("fun(P) when is_pid(P) -> true end(a).", function_clause, [{erl_eval,'-inside-an-interpreted-fun-',[a],[]}, - {erl_eval,eval_fun,6}, + {erl_eval,eval_fun,8}, ?MODULE]), backtrace_check("B.", {unbound_var, 'B'}, [{erl_eval,expr,2}, ?MODULE]), backtrace_check("B.", {unbound, 'B'}, - [{erl_eval,expr,5}, ?MODULE], + [{erl_eval,expr,6}, ?MODULE], none, none), backtrace_check("1/0.", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), backtrace_catch("catch 1/0.", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), check(fun() -> catch exit(foo) end, "catch exit(foo).", {'EXIT', foo}), @@ -1026,33 +1032,33 @@ otp_14826(_Config) -> backtrace_check("try 1/0 after foo end.", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), backtrace_catch("catch (try 1/0 after foo end).", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), backtrace_catch("try catch 1/0 after foo end.", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), backtrace_check("try a of b -> bar after foo end.", {try_clause,a}, - [{erl_eval,try_clauses,8}]), + [{erl_eval,try_clauses,10}]), check(fun() -> X = try foo:bar() catch A:B:C -> {A,B} end, X end, "try foo:bar() catch A:B:C -> {A,B} end.", {error, undef}), backtrace_check("C = 4, try foo:bar() catch A:B:C -> {A,B,C} end.", stacktrace_bound, - [{erl_eval,check_stacktrace_vars,2}, - {erl_eval,try_clauses,8}], + [{erl_eval,check_stacktrace_vars,5}, + {erl_eval,try_clauses,10}], none, none), backtrace_catch("catch (try a of b -> bar after foo end).", {try_clause,a}, - [{erl_eval,try_clauses,8}]), + [{erl_eval,try_clauses,10}]), backtrace_check("try 1/0 catch exit:a -> foo end.", badarith, [{erlang,'/',[1,0],[]}, - {erl_eval,do_apply,6}]), + {erl_eval,do_apply,7}]), Es = [{'try',1,[{call,1,{remote,1,{atom,1,foo},{atom,1,bar}},[]}], [], [{clause,1,[{tuple,1,[{var,1,'A'},{var,1,'B'},{atom,1,'C'}]}], @@ -1062,8 +1068,8 @@ otp_14826(_Config) -> ct:fail(stacktrace_variable) catch error:{illegal_stacktrace_variable,{atom,1,'C'}}:S -> - [{erl_eval,check_stacktrace_vars,2,_}, - {erl_eval,try_clauses,8,_}|_] = S + [{erl_eval,check_stacktrace_vars,5,_}, + {erl_eval,try_clauses,10,_}|_] = S end, backtrace_check("{1,1} = {A = 1, A = 2}.", {badmatch, 1}, @@ -1073,53 +1079,53 @@ otp_14826(_Config) -> [{erl_eval,guard0,4}], none, none), backtrace_check("case a of foo() -> ok end.", {illegal_pattern,{call,1,{atom,1,foo},[]}}, - [{erl_eval,match,4}], none, none), + [{erl_eval,match,6}], none, none), backtrace_check("case a of b -> ok end.", {case_clause,a}, - [{erl_eval,case_clauses,6}, ?MODULE]), + [{erl_eval,case_clauses,8}, ?MODULE]), backtrace_check("if a =:= b -> ok end.", if_clause, - [{erl_eval,if_clauses,5}, ?MODULE]), + [{erl_eval,if_clauses,7}, ?MODULE]), backtrace_check("fun A(b) -> ok end(a).", function_clause, [{erl_eval,'-inside-an-interpreted-fun-',[a],[]}, - {erl_eval,eval_named_fun,8}, + {erl_eval,eval_named_fun,10}, ?MODULE]), backtrace_check("[A || A <- a].", {bad_generator, a}, - [{erl_eval,eval_generate,7}, {erl_eval, eval_lc, 6}]), + [{erl_eval,eval_generate,8}, {erl_eval, eval_lc, 7}]), backtrace_check("<< <> || <> <= a>>.", {bad_generator, a}, - [{erl_eval,eval_b_generate,7}, {erl_eval, eval_bc, 6}]), + [{erl_eval,eval_b_generate,8}, {erl_eval, eval_bc, 7}]), backtrace_check("[A || A <- [1], begin a end].", {bad_filter, a}, - [{erl_eval,eval_filter,6}, {erl_eval, eval_generate, 7}]), + [{erl_eval,eval_filter,7}, {erl_eval, eval_generate, 8}]), fun() -> {'EXIT', {{badarity, {_Fun, []}}, BT}} = (catch parse_and_run("fun(A) -> A end().")), - check_backtrace([{erl_eval,do_apply,5}, ?MODULE], BT) + check_backtrace([{erl_eval,do_apply,6}, ?MODULE], BT) end(), fun() -> {'EXIT', {{badarity, {_Fun, []}}, BT}} = (catch parse_and_run("fun F(A) -> A end().")), - check_backtrace([{erl_eval,do_apply,5}, ?MODULE], BT) + check_backtrace([{erl_eval,do_apply,6}, ?MODULE], BT) end(), backtrace_check("foo().", undef, - [{erl_eval,foo,0},{erl_eval,local_func,6}], + [{erl_eval,foo,0},{erl_eval,local_func,8}], none, none), backtrace_check("a orelse false.", {badarg, a}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("a andalso false.", {badarg, a}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("t = u.", {badmatch, u}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("{math,sqrt}(2).", {badfun, {math,sqrt}}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("erl_eval_SUITE:simple().", simple, [{?MODULE,simple1,0},{?MODULE,simple,0},erl_eval]), @@ -1128,31 +1134,39 @@ otp_14826(_Config) -> "19,20,21,22,23,24,25,26,27,28,29,30) -> a end.", {argument_limit, {'fun',1,[{clause,1,Args,[],[{atom,1,a}]}]}}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("fun F(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18," "19,20,21,22,23,24,25,26,27,28,29,30) -> a end.", {argument_limit, {named_fun,1,'F',[{clause,1,Args,[],[{atom,1,a}]}]}}, - [{erl_eval,expr,5}, ?MODULE]), + [{erl_eval,expr,6}, ?MODULE]), backtrace_check("#r{}.", {undef_record,r}, - [{erl_eval,expr,5}, ?MODULE], + [{erl_eval,expr,6}, ?MODULE], none, none), %% eval_bits backtrace_check("<<100:8/bitstring>>.", badarg, - [{eval_bits,eval_exp_field1,6}, + [{eval_bits,eval_exp_field,6}, eval_bits,eval_bits,erl_eval]), backtrace_check("<<100:8/foo>>.", {undefined_bittype,foo}, - [{eval_bits,make_bit_type,3},eval_bits, + [{eval_bits,make_bit_type,4},eval_bits, eval_bits,eval_bits], none, none), backtrace_check("B = <<\"foo\">>, <>.", badarg, - [{eval_bits,eval_exp_field1,6}, + [{eval_bits,eval_exp_field,6}, eval_bits,eval_bits,erl_eval], none, none), + + %% eval_bits with error info + {error_info, #{cause := _, override_segment_position := 1}} = + error_info_catch("<<100:8/bitstring>>.", badarg), + + {error_info, #{cause := _, override_segment_position := 2}} = + error_info_catch("<<0:8, 100:8/bitstring>>.", badarg), + ok. simple() -> @@ -1172,13 +1186,143 @@ simple1() -> WillNeverHappen -> WillNeverHappen end. +custom_stacktrace(Config) when is_list(Config) -> + EFH = {value, fun custom_stacktrace_eval_handler/3}, + + backtrace_check("1 + atom.", badarith, + [{erlang,'+',[1,atom]}, mystack(1)], none, EFH), + backtrace_check("\n1 + atom.", badarith, + [{erlang,'+',[1,atom]}, mystack(2)], none, EFH), + + backtrace_check("lists:flatten(atom).", function_clause, + [{lists,flatten,[atom]}, mystack(1)], none, EFH), + + backtrace_check("invalid andalso true.", {badarg, invalid}, + [mystack(1)], none, EFH), + backtrace_check("invalid orelse true.", {badarg, invalid}, + [mystack(1)], none, EFH), + + backtrace_check("invalid = valid.", {badmatch, valid}, + [erl_eval, mystack(1)], none, EFH), + + backtrace_check("1:2.", {badexpr, ':'}, + [erl_eval, mystack(1)], none, EFH), + + backtrace_check("Unknown.", {unbound, 'Unknown'}, + [erl_eval, mystack(1)], none, EFH), + + backtrace_check("#unknown{}.", {undef_record,unknown}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("#unknown{foo=bar}.", {undef_record,unknown}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("#unknown.index.", {undef_record,unknown}, + [erl_eval, mystack(1)], none, EFH), + + backtrace_check("fun foo/2.", undef, + [{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH), + backtrace_check("foo(1, 2).", undef, + [{erl_eval, foo, 2}, erl_eval, mystack(1)], none, EFH), + + fun() -> + {'EXIT', {{badarity, {_Fun, []}}, BT}} = + (catch parse_and_run("fun(A) -> A end().", none, EFH)), + check_backtrace([erl_eval, mystack(1)], BT) + end(), + + fun() -> + {'EXIT', {{badarity, {_Fun, []}}, BT}} = + (catch parse_and_run("fun F(A) -> A end().", none, EFH)), + check_backtrace([erl_eval, mystack(1)], BT) + end(), + + backtrace_check("[X || X <- 1].", {bad_generator, 1}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("[X || <> <= 1].", {bad_generator, 1}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("<>.", {bad_generator, 1}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("<> <= 1>>.", {bad_generator, 1}, + [erl_eval, mystack(1)], none, EFH), + + backtrace_check("if false -> true end.", if_clause, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("case 0 of 1 -> true end.", {case_clause, 0}, + [erl_eval, mystack(1)], none, EFH), + backtrace_check("try 0 of 1 -> true after ok end.", {try_clause, 0}, + [mystack(1)], none, EFH), + + backtrace_check("fun(0) -> 1 end(1).", function_clause, + [{erl_eval,'-inside-an-interpreted-fun-', [1]}, erl_eval, mystack(1)], + none, EFH), + backtrace_check("fun F(0) -> 1 end(1).", function_clause, + [{erl_eval,'-inside-an-interpreted-fun-', [1]}, erl_eval, mystack(1)], + none, EFH), + + fun() -> + {'EXIT', {{illegal_pattern,_}, BT}} = + (catch parse_and_run("make_ref() = 1.", none, EFH)), + check_backtrace([erl_eval, mystack(1)], BT) + end(), + + %% eval_bits + backtrace_check("<<100:8/bitstring>>.", + badarg, + [{eval_bits,eval_exp_field,6}, mystack(1)], + none, EFH), + backtrace_check("<<100:8/foo>>.", + {undefined_bittype,foo}, + [{eval_bits,make_bit_type,4}, mystack(1)], + none, EFH), + backtrace_check("B = <<\"foo\">>, <>.", + badarg, + [{eval_bits,eval_exp_field,6}, mystack(1)], + none, EFH), + + ok. + +mystack(Line) -> + {my_module, my_function, 0, [{file, "evaluator"}, {line, Line}]}. + +custom_stacktrace_eval_handler(Ann, FunOrModFun, Args) -> + try + case FunOrModFun of + {Mod, Fun} -> apply(Mod, Fun, Args); + Fun -> apply(Fun, Args) + end + catch + Kind:Reason:Stacktrace -> + %% Take everything up to the evaluation function + Pruned = + lists:takewhile(fun + ({erl_eval_SUITE,backtrace_check,5,_}) -> false; + (_) -> true + end, Stacktrace), + %% Now we prune any shared code path from erl_eval + {current_stacktrace, Current} = + erlang:process_info(self(), current_stacktrace), + Reversed = drop_common(lists:reverse(Current), lists:reverse(Pruned)), + Location = [{file, "evaluator"}, {line, erl_anno:line(Ann)}], + %% Add our file+line information at the bottom + Custom = lists:reverse([{my_module, my_function, 0, Location} | Reversed]), + erlang:raise(Kind, Reason, Custom) + end. + +drop_common([H | T1], [H | T2]) -> drop_common(T1, T2); +drop_common([H | T1], T2) -> drop_common(T1, T2); +drop_common([], [{?MODULE, custom_stacktrace_eval_handler, _, _} | T2]) -> T2; +drop_common([], T2) -> T2. + %% Simple cases, just to cover some code. funs(Config) when is_list(Config) -> do_funs(none, none), do_funs(lfh(), none), + do_funs(none, efh()), do_funs(lfh(), efh()), + do_funs(none, ann_efh()), + do_funs(lfh(), ann_efh()), error_check("nix:foo().", {access_not_allowed,nix}, lfh(), efh()), + error_check("nix:foo().", {access_not_allowed,nix}, lfh(), ann_efh()), error_check("bar().", undef, none, none), check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, @@ -1217,6 +1361,15 @@ funs(Config) when is_list(Config) -> error_check("apply(timer, sleep, [1]).", got_it, none, EFH), error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.", got_it, none, EFH), + + AnnEF = fun(1, {timer,sleep}, As) when length(As) == 1 -> exit({got_it,sleep}); + (1, {M,F}, As) -> apply(M, F, As) + end, + AnnEFH = {value, AnnEF}, + error_check("apply(timer, sleep, [1]).", got_it, none, AnnEFH), + error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.", + got_it, none, AnnEFH), + error_check("fun c/1.", undef), error_check("fun a:b/0().", undef), @@ -1398,6 +1551,9 @@ local_func_value(F, As) when is_atom(F) -> efh() -> {value, fun(F, As) -> external_func(F, As) end}. +ann_efh() -> + {value, fun(_Ann, F, As) -> external_func(F, As) end}. + external_func({M,_}, _As) when M == nix -> exit({{access_not_allowed,M},[mfa]}); external_func(F, As) when is_function(F) -> @@ -1756,6 +1912,125 @@ otp_16865(Config) when is_list(Config) -> {badmatch, b}), ok. +eep49(Config) when is_list(Config) -> + check(fun() -> + maybe empty end + end, + "maybe empty end.", + empty), + check(fun() -> + maybe ok ?= ok end + end, + "maybe ok ?= ok end.", + ok), + check(fun() -> + maybe {ok,A} ?= {ok,good}, A end + end, + "maybe {ok,A} ?= {ok,good}, A end.", + good), + check(fun() -> + maybe {ok,A} ?= {ok,good}, {ok,B} ?= {ok,also_good}, {A,B} end + end, + "maybe {ok,A} ?= {ok,good}, {ok,B} ?= {ok,also_good}, {A,B} end.", + {good,also_good}), + check(fun() -> + maybe {ok,A} ?= {ok,good}, {ok,B} ?= {error,wrong}, {A,B} end + end, + "maybe {ok,A} ?= {ok,good}, {ok,B} ?= {error,wrong}, {A,B} end.", + {error,wrong}), + + %% Test maybe ... else ... end. + check(fun() -> + maybe empty else _ -> error end + end, + "maybe empty else _ -> error end.", + empty), + check(fun() -> + maybe ok ?= ok else _ -> error end + end, + "maybe ok ?= ok else _ -> error end.", + ok), + check(fun() -> + maybe ok ?= other else _ -> error end + end, + "maybe ok ?= other else _ -> error end.", + error), + check(fun() -> + maybe {ok,A} ?= {ok,good}, {ok,B} ?= {ok,also_good}, {A,B} + else {error,_} -> error end + end, + "maybe {ok,A} ?= {ok,good}, {ok,B} ?= {ok,also_good}, {A,B} " + "else {error,_} -> error end.", + {good,also_good}), + check(fun() -> + maybe {ok,A} ?= {ok,good}, {ok,B} ?= {error,other}, {A,B} + else {error,_} -> error end + end, + "maybe {ok,A} ?= {ok,good}, {ok,B} ?= {error,other}, {A,B} " + "else {error,_} -> error end.", + error), + error_check("maybe ok ?= simply_wrong else {error,_} -> error end.", + {else_clause,simply_wrong}), + ok. + +%% GH-6348/OTP-18297: Lift restrictions for matching of binaries and maps. +binary_and_map_aliases(Config) when is_list(Config) -> + check(fun() -> + <> = <> = <<16#cafe:16>>, + {A,B,C} + end, + "begin <> = <> = <<16#cafe:16>>, {A,B,C} end.", + {16#cafe,16#ca,16#fe}), + check(fun() -> + <> = + <> = + <> = + <<16#abcdef57:32>>, + {A,B,C,D,E,F,G,H} + end, + "begin <> = + <> = + <> = + <<16#abcdef57:32>>, + {A,B,C,D,E,F,G,H} + end.", + {<<16#ab>>,<<16#cdef57:24>>, 16#abcd,16#ef57, 16#ab,16#cd,16#ef,16#57}), + check(fun() -> + #{K := V} = #{k := K} = #{k => my_key, my_key => 42}, + V + end, + "begin #{K := V} = #{k := K} = #{k => my_key, my_key => 42}, V end.", + 42), + ok. + +%% EEP 58: Map comprehensions. +eep58(Config) when is_list(Config) -> + check(fun() -> X = 32, #{X => X*X || X <- [1,2,3]} end, + "begin X = 32, #{X => X*X || X <- [1,2,3]} end.", + #{1 => 1, 2 => 4, 3 => 9}), + check(fun() -> + K = V = none, + #{K => V*V || K := V <- #{1 => 1, 2 => 2, 3 => 3}} + end, + "begin K = V = none, #{K => V*V || K := V <- #{1 => 1, 2 => 2, 3 => 3}} end.", + #{1 => 1, 2 => 4, 3 => 9}), + check(fun() -> + #{K => V*V || K := V <- maps:iterator(#{1 => 1, 2 => 2, 3 => 3})} + end, + "#{K => V*V || K := V <- maps:iterator(#{1 => 1, 2 => 2, 3 => 3})}.", + #{1 => 1, 2 => 4, 3 => 9}), + check(fun() -> << <> || K := V <- #{42 => 7777} >> end, + "<< <> || K := V <- #{42 => 7777} >>.", + <<42:8,7777:24>>), + check(fun() -> [X || X := X <- #{a => 1, b => b}] end, + "[X || X := X <- #{a => 1, b => b}].", + [b]), + + error_check("[K+V || K := V <- a].", {bad_generator,a}), + error_check("[K+V || K := V <- [-1|#{}]].", {bad_generator,[-1|#{}]}), + + ok. + %% Check the string in different contexts: as is; in fun; from compiled code. check(F, String, Result) -> check1(F, String, Result), @@ -1869,6 +2144,14 @@ backtrace_catch(String, Result, Backtrace) -> ct:fail({eval, Other, Result}) end. +error_info_catch(String, Result) -> + case catch parse_and_run(String) of + {'EXIT', {Result, [{_, _, _, Info}|_]}} -> + lists:keyfind(error_info, 1, Info); + Other -> + ct:fail({eval, Other, Result}) + end. + check_backtrace([B1|Backtrace], [B2|BT]) -> case {B1, B2} of {M, {M,_,_,_}} -> @@ -1887,15 +2170,26 @@ eval_string(String) -> Result. parse_expr(String) -> - {ok,Tokens,_} = erl_scan:string(String), + Tokens = erl_scan_string(String), {ok, [Expr]} = erl_parse:parse_exprs(Tokens), Expr. parse_exprs(String) -> - {ok,Tokens,_} = erl_scan:string(String), + Tokens = erl_scan_string(String), {ok, Exprs} = erl_parse:parse_exprs(Tokens), Exprs. +erl_scan_string(String) -> + %% FIXME: When the experimental features EEP has been implemented, we should + %% dig out all keywords defined in all features. + ResWordFun = + fun('maybe') -> true; + ('else') -> true; + (Other) -> erl_scan:reserved_word(Other) + end, + {ok,Tokens,_} = erl_scan:string(String, 1, [{reserved_word_fun,ResWordFun}]), + Tokens. + parse_and_run(String) -> erl_eval:expr(parse_expr(String), []). diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl index ed5b6325fc2f..13aaf0abdb93 100644 --- a/lib/stdlib/test/erl_expand_records_SUITE.erl +++ b/lib/stdlib/test/erl_expand_records_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -39,7 +39,8 @@ -export([attributes/1, expr/1, guard/1, init/1, pattern/1, strict/1, update/1, otp_5915/1, otp_7931/1, otp_5990/1, - otp_7078/1, otp_7101/1, maps/1]). + otp_7078/1, maps/1, + side_effects/1]). init_per_testcase(_Case, Config) -> Config. @@ -53,11 +54,12 @@ suite() -> all() -> [attributes, expr, guard, init, - pattern, strict, update, maps, {group, tickets}]. + pattern, strict, update, maps, + side_effects, {group, tickets}]. groups() -> [{tickets, [], - [otp_5915, otp_7931, otp_5990, otp_7078, otp_7101]}]. + [otp_5915, otp_7931, otp_5990, otp_7078]}]. init_per_suite(Config) -> Config. @@ -146,6 +148,22 @@ expr(Config) when is_list(Config) -> is_record(_, _, _) -> error(wrong_is_record). + ">>, + <<" + -record(foo, {bar = [Bar || Bar <- ?MODULE:id([]), size(Bar) > 0]}). + + t() -> + {'EXIT',{{bad_filter,{foo,[]}},[_|_]}} = catch gh6501a(whatever), + [whatever] = gh6501b(whatever), + ok. + + gh6501a(Bar) -> + [Bar || #foo{}]. + + gh6501b(Bar) -> + [Bar || is_tuple(#foo{})]. + + id(I) -> I. ">> ], @@ -317,7 +335,7 @@ strict(Config) when is_list(Config) -> ok = try {1, 2} = {A#r2.a, A#r2.b}, not_ok - catch error:{badrecord,r2} -> ok + catch error:{badrecord,{r1,1,2}} -> ok end, try case foo of @@ -701,65 +719,30 @@ otp_7078(Config) when is_list(Config) -> run(Config, Ts, [strict_record_tests]), ok. --record(otp_7101, {a,b,c=[],d=[],e=[]}). - id(I) -> I. -%% OTP-7101. Record update: more than one call to setelement/3. -otp_7101(Config) when is_list(Config) -> - %% Ensure the compiler won't do any funny constant propagation tricks. - id(#otp_7101{a=a,b=b,c=c,d=d,e=e}), - Rec = id(#otp_7101{}), - - %% Spawn a tracer process to count the number of setelement/3 calls. - %% The tracer will forward all trace messages to us. - Self = self(), - Tracer = spawn_link(fun() -> otp_7101_tracer(Self, 0) end), - 1 = erlang:trace_pattern({erlang,setelement,3}, true), - erlang:trace(self(), true, [{tracer,Tracer},call]), - - %% Update the record. - #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update1(Rec), - #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update2(Rec), - #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update3(Rec), - #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update4(Rec), - - %% Verify that setelement/3 was called the same number of times as - %% the number of record updates. - Ref = erlang:trace_delivered(Self), - receive - {trace_delivered, Self, Ref} -> - Tracer ! done - end, - 1 = erlang:trace_pattern({erlang,setelement,3}, false), - receive - 4 -> - ok; - Other -> - ct:fail({unexpected,Other}) - end. +-record(side_effects, {a,b,c}). -otp_7101_tracer(Parent, N) -> - receive - {trace,Parent,call,{erlang,setelement,[_,_,_]}} -> - otp_7101_tracer(Parent, N+1); - done -> - Parent ! N - end. +%% Make sure that the record expression is only evaluated once. +side_effects(_Config) -> + init_counter(), -otp_7101_update1(R) -> - R#otp_7101{b=1, - a=2}. + {'EXIT',{{badrecord,0},_}} = catch (id(bump_counter()))#side_effects{a=1}, + 1 = read_counter(), + + {'EXIT',{{badrecord,1},_}} = catch (id(bump_counter()))#side_effects.b, + 2 = read_counter(), + + ok. -otp_7101_update2(R) -> - R#otp_7101{a=1, - b=2}. +init_counter() -> + put(counter, 0). -otp_7101_update3(R) -> - R#otp_7101{b=1,a=2}. +bump_counter() -> + put(counter, get(counter) + 1). -otp_7101_update4(R) -> - R#otp_7101{a=1,b=2}. +read_counter() -> + get(counter). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/test/erl_internal_SUITE.erl b/lib/stdlib/test/erl_internal_SUITE.erl index 7d9df1f989e7..5c2d6b00910e 100644 --- a/lib/stdlib/test/erl_internal_SUITE.erl +++ b/lib/stdlib/test/erl_internal_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2017. All Rights Reserved. +%% Copyright Ericsson AB 1999-2021. 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. @@ -80,7 +80,7 @@ callbacks(application) -> callbacks(gen_server) -> [{init,1}, {handle_call,3}, {handle_cast,2}, {handle_info,2}, {terminate,2}, {code_change,3}, - {format_status,2}, {handle_continue, 2}]; + {format_status,1}, {format_status,2}, {handle_continue, 2}]; callbacks(gen_fsm) -> [{init,1}, {handle_event,3}, {handle_sync_event,4}, {handle_info,3}, {terminate,3}, {code_change,4}, @@ -88,11 +88,11 @@ callbacks(gen_fsm) -> callbacks(gen_event) -> [{init,1}, {handle_event,2}, {handle_call,2}, {handle_info,2}, {terminate,2}, {code_change,3}, - {format_status,2}]; + {format_status,1}, {format_status,2}]; callbacks(gen_statem) -> [{init, 1}, {callback_mode, 0}, {state_name, 3}, {handle_event, 4}, {terminate, 3}, {code_change, 4}, - {format_status, 2}]; + {format_status, 1}, {format_status, 2}]; callbacks(supervisor_bridge) -> [{init,1}, {terminate,2}]; callbacks(supervisor) -> @@ -101,14 +101,14 @@ callbacks(supervisor) -> optional_callbacks(application) -> []; optional_callbacks(gen_server) -> - [{handle_info, 2}, {handle_continue, 2}, {terminate, 2}, {code_change, 3}, {format_status, 2}]; + [{handle_info, 2}, {handle_continue, 2}, {terminate, 2}, {code_change, 3}, {format_status, 1}, {format_status, 2}]; optional_callbacks(gen_fsm) -> [{handle_info, 3}, {terminate, 3}, {code_change, 4}, {format_status, 2}]; optional_callbacks(gen_event) -> - [{handle_info, 2}, {terminate, 2}, {code_change, 3}, {format_status, 2}]; + [{handle_info, 2}, {terminate, 2}, {code_change, 3}, {format_status, 1}, {format_status, 2}]; optional_callbacks(gen_statem) -> [{state_name, 3}, {handle_event, 4}, - {terminate, 3}, {code_change, 4}, {format_status, 2}]; + {terminate, 3}, {code_change, 4}, {format_status, 1}, {format_status, 2}]; optional_callbacks(supervisor_bridge) -> []; optional_callbacks(supervisor) -> diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 8a149947fbb6..64cf5643f776 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2022. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -35,7 +35,8 @@ -export([all/0, suite/0, groups/0]). --export([unused_vars_warn_basic/1, +-export([singleton_type_var_errors/1, + unused_vars_warn_basic/1, unused_vars_warn_lc/1, unused_vars_warn_rec/1, unused_vars_warn_fun/1, @@ -49,7 +50,8 @@ unsafe_vars_try/1, unsized_binary_in_bin_gen_pattern/1, guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1, - otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1, + otp_5362/1, otp_5371/1, otp_7227/1, binary_aliases/1, + otp_5494/1, otp_5644/1, otp_5878/1, otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1, otp_11772/1, otp_11771/1, otp_11872/1, export_all/1, @@ -65,16 +67,24 @@ maps/1,maps_type/1,maps_parallel_match/1, otp_11851/1,otp_11879/1,otp_13230/1, record_errors/1, otp_11879_cont/1, - non_latin1_module/1, otp_14323/1, + non_latin1_module/1, illegal_module_name/1, otp_14323/1, stacktrace_syntax/1, otp_14285/1, otp_14378/1, external_funs/1,otp_15456/1,otp_15563/1, unused_type/1,binary_types/1,removed/1, otp_16516/1, inline_nifs/1, + undefined_nifs/1, + no_load_nif/1, warn_missing_spec/1, otp_16824/1, underscore_match/1, - unused_record/1]). + unused_record/1, + unused_type2/1, + eep49/1, + redefined_builtin_type/1, + tilde_k/1, + match_float_zero/1, + undefined_module/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -86,7 +96,7 @@ all() -> unsafe_vars, unsafe_vars2, unsafe_vars_try, guard, unsized_binary_in_bin_gen_pattern, otp_4886, otp_4988, otp_5091, otp_5276, otp_5338, - otp_5362, otp_5371, otp_7227, otp_5494, otp_5644, + otp_5362, otp_5371, otp_7227, binary_aliases, otp_5494, otp_5644, otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254, otp_11772, otp_11771, otp_11872, export_all, bif_clash, behaviour_basic, behaviour_multiple, otp_11861, @@ -94,11 +104,20 @@ all() -> too_many_arguments, basic_errors, bin_syntax_errors, predef, maps, maps_type, maps_parallel_match, otp_11851, otp_11879, otp_13230, - record_errors, otp_11879_cont, non_latin1_module, otp_14323, + record_errors, otp_11879_cont, + non_latin1_module, illegal_module_name, otp_14323, stacktrace_syntax, otp_14285, otp_14378, external_funs, otp_15456, otp_15563, unused_type, binary_types, removed, otp_16516, + undefined_nifs, + no_load_nif, inline_nifs, warn_missing_spec, otp_16824, - underscore_match, unused_record]. + underscore_match, unused_record, unused_type2, + eep49, + redefined_builtin_type, + tilde_k, + singleton_type_var_errors, + match_float_zero, + undefined_module]. groups() -> [{unused_vars_warn, [], @@ -158,7 +177,13 @@ c(A) -> g({M, F}) -> (Z=M):(Z=F)(); g({M, F, Arg}) -> (Z=M):F(Z=Arg). h(X, Y) -> (Z=X) + (Z=Y).">>, - [warn_unused_vars], []}], + [warn_unused_vars], []}, + {basic3, + <<"f(E) -> + X = Y = E.">>, + [warn_unused_vars], + {warnings,[{{2,19},erl_lint,{unused_var,'X'}}, + {{2,23},erl_lint,{unused_var,'Y'}}]}}], [] = run(Config, Ts), ok. @@ -289,7 +314,7 @@ unused_vars_warn_lc(Config) when is_list(Config) -> j(X) -> [foo || X <- X, % X shadowed. X <- % X shadowed. X unused. - X = + X = Y = [[1,2,3]], % Y unused. X <- [], % X shadowed. X <- X]. % X shadowed. X unused. @@ -884,6 +909,126 @@ unused_import(Config) when is_list(Config) -> [] = run(Config, Ts), ok. +%% Test singleton type variables +singleton_type_var_errors(Config) when is_list(Config) -> + Ts = [{singleton_error1, + <<"-spec test_singleton_typevars_in_union(Opts) -> term() when + Opts :: {ok, Unknown} | {error, Unknown}. + test_singleton_typevars_in_union(_) -> + error. + ">>, + [], + {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}}, + + {singleton_error2, + <<"-spec test_singleton_list_typevars_in_union([Opts]) -> term() when + Opts :: {ok, Unknown} | {error, Unknown}. + test_singleton_list_typevars_in_union(_) -> + error.">>, + [], + {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}}, + + {singleton_error3, + <<"-spec test_singleton_list_typevars_in_list([Opts]) -> term() when + Opts :: {ok, Unknown}. + test_singleton_list_typevars_in_list(_) -> + error.">>, + [], + {errors, + [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}],[]}}, + + {singleton_error4, + <<"-spec test_singleton_list_typevars_in_list_with_type_subst([{ok, Unknown}]) -> term(). + test_singleton_list_typevars_in_list_with_type_subst(_) -> + error.">>, + [], + {errors,[{{1,86},erl_lint,{singleton_typevar,'Unknown'}}],[]}}, + + {singleton_error5, + <<"-spec test_singleton_buried_typevars_in_union(Opts) -> term() when + Opts :: {ok, Foo} | {error, Foo}, + Foo :: {true, X} | {false, X}. + test_singleton_buried_typevars_in_union(_) -> + error.">>, + [], + {warnings,[{{3,38},erl_lint,{singleton_typevar,'X'}}]}}, + + {singleton_error6, + <<"-spec test_multiple_subtypes_to_same_typevar(Opts) -> term() when + Opts :: {Foo, Bar} | Y, + Foo :: X, + Bar :: X, + Y :: Z. + test_multiple_subtypes_to_same_typevar(_) -> + error.">>, + [], + {errors,[{{5,31},erl_lint,{singleton_typevar,'Z'}}],[]}}, + + {singleton_error7, + <<"-spec test_duplicate_non_terminal_var_in_union(Opts) -> term() when + Opts :: {ok, U, U} | {error, U, U}, + U :: Foo. + test_duplicate_non_terminal_var_in_union(_) -> + error.">>, + [], + {errors,[{{3,31},erl_lint,{singleton_typevar,'Foo'}}],[]}}, + + {singleton_error8, + <<"-spec test_unused_outside_union(Opts) -> term() when + Unused :: Unknown, + A :: Unknown, + Opts :: {Unknown | A}. + test_unused_outside_union(_) -> + error.">>, + [], + {errors,[{{2,21},erl_lint,{singleton_typevar,'Unused'}}],[]}}, + + {singleton_disabled_warning, + <<"-spec test_singleton_typevars_in_union(Opts) -> term() when + Opts :: {ok, Unknown} | {error, Unknown}. + test_singleton_typevars_in_union(_) -> + error. + ">>, + [nowarn_singleton_typevar], + []}, + + {singleton_ok1, + <<"-spec test_multiple_occurrences_singleton(Opts) -> term() when + Opts :: {Foo, Foo}. + test_multiple_occurrences_singleton(_) -> + ok.">>, + [], + []}, + + {singleton_ok2, + <<"-spec id(X) -> X. + id(X) -> + X.">>, + [], + []}, + + {singleton_ok3, + <<"-spec ok(Opts) -> term() when + Opts :: {Unknown, {ok, Unknown} | {error, Unknown}}. + ok(_) -> + error.">>, + [], + []}, + + {singleton_ok4, + <<"-spec ok(Opts) -> term() when + Union :: {ok, Unknown} | {error, Unknown}, + Opts :: {{tag, Unknown} | Union}. + ok(_) -> + error.">>, + [], + []} + + ], + + [] = run(Config, Ts), + ok. + %% Test warnings for unused functions. unused_function(Config) when is_list(Config) -> Ts = [{func1, @@ -959,13 +1104,12 @@ binary_types(Config) when is_list(Config) -> <<"-type nonempty_binary() :: term().">>, [nowarn_unused_type], {warnings,[{{1,22},erl_lint, - {new_builtin_type,{nonempty_binary,0}}}]}}, - + {redefine_builtin_type,{nonempty_binary,0}}}]}}, {binary2, <<"-type nonempty_bitstring() :: term().">>, [nowarn_unused_type], {warnings,[{{1,22},erl_lint, - {new_builtin_type,{nonempty_bitstring,0}}}]}}], + {redefine_builtin_type,{nonempty_bitstring,0}}}]}}], [] = run(Config, Ts), ok. @@ -2289,22 +2433,22 @@ otp_15456(Config) when is_list(Config) -> ok. %% OTP-5371. Aliases for bit syntax expressions are no longer allowed. +%% GH-6348/OTP-18297: Updated for OTP 26 to allow aliases. otp_5371(Config) when is_list(Config) -> Ts = [{otp_5371_1, <<"t(<> = <>) -> {A,B}. ">>, [], - {errors,[{{1,23},erl_lint,illegal_bin_pattern}],[]}}, + []}, {otp_5371_2, <<"x([<>] = [<>]) -> {A,B}. y({a,<>} = {b,<>}) -> {A,B}. ">>, - [], - {errors,[{{1,24},erl_lint,illegal_bin_pattern}, - {{3,20},erl_lint,illegal_bin_pattern}],[]}}, + [], + {warnings,[{{3,15},v3_core,{nomatch,pattern}}]}}, {otp_5371_3, <<"-record(foo, {a,b,c}). -record(bar, {x,y,z}). @@ -2321,11 +2465,10 @@ otp_5371(Config) when is_list(Config) -> {X,Y}. ">>, [], - {errors,[{{4,26},erl_lint,illegal_bin_pattern}, - {{6,26},erl_lint,illegal_bin_pattern}, - {{8,26},erl_lint,illegal_bin_pattern}, - {{10,30},erl_lint,illegal_bin_pattern}, - {{12,30},erl_lint,illegal_bin_pattern}],[]}}, + {warnings,[{{4,15},v3_core,{nomatch,pattern}}, + {{8,15},v3_core,{nomatch,pattern}}, + {{10,15},v3_core,{nomatch,pattern}}, + {{12,15},v3_core,{nomatch,pattern}}]}}, {otp_5371_4, <<"-record(foo, {a,b,c}). -record(bar, {x,y,z}). @@ -2345,42 +2488,41 @@ otp_5371(Config) when is_list(Config) -> [] = run(Config, Ts), ok. -%% OTP_7227. Some aliases for bit syntax expressions were still allowed. +%% OTP-7227. Some aliases for bit syntax expressions were still allowed. +%% GH-6348/OTP-18297: Updated for OTP 26 to allow aliases. otp_7227(Config) when is_list(Config) -> Ts = [{otp_7227_1, <<"t([<> = {C,D} = <>]) -> {A,B,C,D}. ">>, [], - {errors,[{{1,42},erl_lint,illegal_bin_pattern}],[]}}, + {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}}, {otp_7227_2, <<"t([(<> = {C,D}) = <>]) -> {A,B,C,D}. ">>, [], - {errors,[{{1,25},erl_lint,illegal_bin_pattern}],[]}}, + {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}}, {otp_7227_3, <<"t([(<> = {C,D}) = (<> = <>)]) -> {A,B,C,D}. ">>, [], - {errors,[{{1,45},erl_lint,illegal_bin_pattern}, - {{1,45},erl_lint,illegal_bin_pattern}, - {{1,55},erl_lint,illegal_bin_pattern}],[]}}, + {warnings,[{{1,21},v3_core,{nomatch,pattern}}]}}, {otp_7227_4, <<"t(Val) -> <> = <> = Val, {A,B}. ">>, [], - {errors,[{{2,19},erl_lint,illegal_bin_pattern}],[]}}, + []}, {otp_7227_5, <<"t(Val) -> <> = X = <> = Val, {A,B,X}. ">>, [], - {errors,[{{2,19},erl_lint,illegal_bin_pattern}],[]}}, + []}, {otp_7227_6, <<"t(X, Y) -> <> = <>, @@ -2394,27 +2536,70 @@ otp_7227(Config) when is_list(Config) -> {A,B,X}. ">>, [], - {errors,[{{2,36},erl_lint,illegal_bin_pattern}, - {{2,36},erl_lint,illegal_bin_pattern}, - {{2,46},erl_lint,illegal_bin_pattern}],[]}}, - {otp_7227_8, + []}, + {otp_7227_8, <<"t(Val) -> (<> = X) = (Y = <>) = Val, {A,B,X,Y}. ">>, [], - {errors,[{{2,40},erl_lint,illegal_bin_pattern}],[]}}, + []}, {otp_7227_9, <<"t(Val) -> (Z = <> = X) = (Y = <> = W) = Val, {A,B,X,Y,Z,W}. ">>, [], - {errors,[{{2,44},erl_lint,illegal_bin_pattern}],[]}} + []} ], [] = run(Config, Ts), ok. +%% GH-6348/OTP-18297: Allow aliases of binary patterns. +binary_aliases(Config) when is_list(Config) -> + Ts = [{binary_aliases_1, + <<"t([<> = <<_:8,Data:Size/bits>>]) -> + Data. + ">>, + [], + {errors,[{{1,55},erl_lint,{unbound_var,'Size'}}],[]}}, + {binary_aliases_2, + <<"t(#{key := <>} = #{key := <<_:8,Data:Size/bits>>}) -> + Data. + ">>, + [], + {errors,[{{1,73},erl_lint,{unbound_var,'Size'}}],[]}}, + {binary_aliases_3, + <<"t(<<_:8,Data:Size/bits>> = <>) -> + Data. + ">>, + [], + {errors,[{{1,34},erl_lint,{unbound_var,'Size'}}],[]}}, + {binary_aliases_4, + <<"t([<<_:8,Data:Size/bits>> = <>]) -> + Data. + ">>, + [], + {errors,[{{1,35},erl_lint,{unbound_var,'Size'}}],[]}}, + {binary_aliases_5, + <<"t(Bin) -> + <<_:8,A:Size>> = <<_:8,B:Size/bits>> = <> = Bin, + {A,B,Size}. + ">>, + [], + []}, + {binary_aliases_6, + <<"t(<<_:8,A:Size>> = <<_:8,B:Size/bits>> = <>) -> + {A,B,Size}. + ">>, + [], + {errors,[{{1,31},erl_lint,{unbound_var,'Size'}}, + {{1,48},erl_lint,{unbound_var,'Size'}}], + []}} + ], + [] = run(Config, Ts), + ok. + %% OTP-5494. Warnings for functions exported more than once. otp_5494(Config) when is_list(Config) -> Ts = [{otp_5494_1, @@ -2773,14 +2958,6 @@ otp_10436(Config) when is_list(Config) -> {warnings,[{{4,14},erl_lint,{not_exported_opaque,{t2,0}}}, {{4,14},erl_lint,{unused_type,{t2,0}}}]} = run_test2(Config, Ts, []), - Ts2 = <<"-module(otp_10436_2). - -export_type([t1/0, t2/0]). - -opaque t1() :: term(). - -opaque t2() :: any(). - ">>, - {warnings,[{{3,15},erl_lint,{underspecified_opaque,{t1,0}}}, - {{4,15},erl_lint,{underspecified_opaque,{t2,0}}}]} = - run_test2(Config, Ts2, []), ok. %% OTP-11254. M:F/A could crash the linter. @@ -2815,9 +2992,9 @@ otp_11772(Config) when is_list(Config) -> t() -> 1. ">>, - {errors,[{{7,14},erl_lint,{builtin_type,{node,0}}}, - {{8,14},erl_lint,{builtin_type,{mfa,0}}}], - []} = run_test2(Config, Ts, []), + {warnings,[{{7,14},erl_lint,{redefine_builtin_type,{node,0}}}, + {{8,14},erl_lint,{redefine_builtin_type,{mfa,0}}}]} = + run_test2(Config, Ts, []), ok. %% OTP-11771. Do not allow redefinition of the types arity(_) &c.. @@ -2840,11 +3017,11 @@ otp_11771(Config) when is_list(Config) -> t() -> 1. ">>, - {errors,[{{7,14},erl_lint,{builtin_type,{arity,0}}}, - {{8,14},erl_lint,{builtin_type,{bitstring,0}}}, - {{9,14},erl_lint,{builtin_type,{iodata,0}}}, - {{10,14},erl_lint,{builtin_type,{boolean,0}}}], - []} = run_test2(Config, Ts, []), + {warnings,[{{7,14},erl_lint,{redefine_builtin_type,{arity,0}}}, + {{8,14},erl_lint,{redefine_builtin_type,{bitstring,0}}}, + {{9,14},erl_lint,{redefine_builtin_type,{iodata,0}}}, + {{10,14},erl_lint,{redefine_builtin_type,{boolean,0}}}]} = + run_test2(Config, Ts, []), ok. %% OTP-11872. The type map() undefined when exported. @@ -2856,15 +3033,16 @@ otp_11872(Config) when is_list(Config) -> -export_type([map/0, product/0]). - -opaque map() :: dict(). + -opaque map() :: unknown_type(). -spec t() -> map(). t() -> 1. ">>, - {errors,[{{6,14},erl_lint,{undefined_type,{product,0}}}, - {{8,14},erl_lint,{builtin_type,{map,0}}}], []} = + {error,[{{6,14},erl_lint,{undefined_type,{product,0}}}, + {{8,30},erl_lint,{undefined_type,{unknown_type,0}}}], + [{{8,14},erl_lint,{redefine_builtin_type,{map,0}}}]} = run_test2(Config, Ts, []), ok. @@ -3737,7 +3915,10 @@ predef(Config) when is_list(Config) -> %% dict(), digraph() and so on were removed in Erlang/OTP 18.0. E2 = get_compilation_result(Config, "predef2", []), Tag = undefined_type, - {[{{7,13},erl_lint,{Tag,{array,0}}}, + {[{{5,2},erl_lint,{Tag,{array,0}}}, + {{5,2},erl_lint,{Tag,{digraph,0}}}, + {{5,2},erl_lint,{Tag,{gb_set,0}}}, + {{7,13},erl_lint,{Tag,{array,0}}}, {{12,12},erl_lint,{Tag,{dict,0}}}, {{17,15},erl_lint,{Tag,{digraph,0}}}, {{27,14},erl_lint,{Tag,{gb_set,0}}}, @@ -3871,35 +4052,61 @@ maps_type(Config) when is_list(Config) -> t(M) -> M. ">>, [], - {errors,[{{3,7},erl_lint,{builtin_type,{map,0}}}],[]}}], + {warnings,[{{3,7},erl_lint,{redefine_builtin_type,{map,0}}}]}}], [] = run(Config, Ts), ok. +%% GH-6348/OTP-18297: In OTP 26 parallel matching of maps +%% has been extended. maps_parallel_match(Config) when is_list(Config) -> - Ts = [{parallel_map_patterns_unbound1, + Ts = [{parallel_map_patterns_unbound, <<" t(#{} = M) -> - #{K := V} = #{k := K} = M, + #{k := K} = #{K := V} = M, V. ">>, [], - {errors,[{{3,18},erl_lint,{unbound_var,'K'}}],[]}}, - {parallel_map_patterns_unbound2, + {errors,[{{3,30},erl_lint,{unbound_var,'K'}}],[]}}, + {parallel_map_patterns_not_toplevel1, + <<" + t(#{} = M) -> + [#{K1 := V1} = + #{K2 := V2} = + #{k1 := K1,k2 := K2}] = [M], + [V1,V2]. + ">>, + [], + {errors,[{{3,19},erl_lint,{unbound_var,'K1'}}, + {{4,19},erl_lint,{unbound_var,'K2'}}],[]}}, + {parallel_map_patterns_unbound_not_toplevel2, <<" t(#{} = M) -> + [#{k := K} = #{K := V}] = [M], + V. + ">>, + [], + {errors,[{{3,31},erl_lint,{unbound_var,'K'}}],[]}}, + {parallel_map_patterns_bound1, + <<" + t(#{} = M,K1,K2) -> #{K1 := V1} = #{K2 := V2} = #{k1 := K1,k2 := K2} = M, [V1,V2]. ">>, [], - {errors,[{{3,18},erl_lint,{unbound_var,'K1'}}, - {{3,18},erl_lint,{unbound_var,'K1'}}, - {{4,18},erl_lint,{unbound_var,'K2'}}, - {{4,18},erl_lint,{unbound_var,'K2'}}],[]}}, - {parallel_map_patterns_bound, + []}, + {parallel_map_patterns_bound2, <<" - t(#{} = M,K1,K2) -> + t(#{} = M) -> + #{K := V} = #{k := K} = M, + V. + ">>, + [], + []}, + {parallel_map_patterns_bound3, + <<" + t(#{} = M) -> #{K1 := V1} = #{K2 := V2} = #{k1 := K1,k2 := K2} = M, @@ -4103,9 +4310,10 @@ otp_11879_cont(Config) -> %% OTP-14285: We currently don't support non-latin1 module names. non_latin1_module(Config) -> - do_non_latin1_module('юникод'), - do_non_latin1_module(list_to_atom([256,$a,$b,$c])), - do_non_latin1_module(list_to_atom([$a,$b,256,$c])), + Expected = [non_latin1_module_unsupported], + Expected = check_module_name('юникод'), + Expected = check_module_name(list_to_atom([256,$a,$b,$c])), + Expected = check_module_name(list_to_atom([$a,$b,256,$c])), "module names with non-latin1 characters are not supported" = format_error(non_latin1_module_unsupported), @@ -4164,16 +4372,48 @@ non_latin1_module(Config) -> run(Config, Ts), ok. -do_non_latin1_module(Mod) -> +illegal_module_name(_Config) -> + [empty_module_name] = check_module_name(''), + + [ctrl_chars_in_module_name] = check_module_name('\x00'), + [ctrl_chars_in_module_name] = check_module_name('abc\x1F'), + [ctrl_chars_in_module_name] = check_module_name('\x7F'), + [ctrl_chars_in_module_name] = check_module_name('abc\x80'), + [ctrl_chars_in_module_name] = check_module_name('abc\x80xyz'), + [ctrl_chars_in_module_name] = check_module_name('\x9Fxyz'), + + [ctrl_chars_in_module_name, + non_latin1_module_unsupported] = check_module_name('атом\x00'), + + [blank_module_name] = check_module_name(' '), + [blank_module_name] = check_module_name('\xA0'), + [blank_module_name] = check_module_name('\xAD'), + [blank_module_name] = check_module_name(' \xA0\xAD '), + + %% White space and soft hyphens are OK if there are visible + %% characters in the name. + ok = check_module_name(' abc '), + ok = check_module_name('abc '), + ok = check_module_name(' abc '), + ok = check_module_name(' abc xyz '), + ok = check_module_name(' abc\xADxyz '), + + ok. + +check_module_name(Mod) -> File = atom_to_list(Mod) ++ ".erl", L1 = erl_anno:new(1), Forms = [{attribute,L1,file,{File,1}}, {attribute,L1,module,Mod}, {eof,2}], - error = compile:forms(Forms), - {error,_,[]} = compile:forms(Forms, [return]), - ok. - + _ = compile:forms(Forms), + case compile:forms(Forms, [return]) of + {error,Errors,[]} -> + [{_ModName,L}] = Errors, + lists:sort([Reason || {1,erl_lint,Reason} <- L]); + {ok,Mod,Code,Ws} when is_binary(Code), is_list(Ws) -> + ok + end. otp_14378(Config) -> Ts = [ @@ -4205,8 +4445,8 @@ otp_14323(Config) -> -dialyzer(nowarn_function). % unknown option -dialyzer(1). % badly formed - -dialyzer(malformed). % unkonwn option - -dialyzer({malformed,f/0}). % unkonwn option + -dialyzer(malformed). % unknown option + -dialyzer({malformed,f/0}). % unknown option -dialyzer({nowarn_function,a/1}). % undefined function -dialyzer({nowarn_function,{a,-1}}). % badly formed @@ -4491,6 +4731,34 @@ inline_nifs(Config) -> {warnings,[{{2,22},erl_lint,nif_inline}]}}], [] = run(Config, Ts). +undefined_nifs(Config) when is_list(Config) -> + Ts = [{undefined_nifs, + <<"-export([t/0]). + -nifs([hej/1]). + t() -> + erlang:load_nif(\"lib\", []). + ">>, + [], + {errors,[{{2,15},erl_lint,{undefined_nif,{hej,1}}}],[]}} + ], + [] = run(Config, Ts), + + ok. + +no_load_nif(Config) when is_list(Config) -> + Ts = [{no_load_nif, + <<"-export([t/0]). + -nifs([t/0]). + t() -> + a. + ">>, + [], + {warnings,[{{2,15},erl_lint,no_load_nif}]}} + ], + [] = run(Config, Ts), + + ok. + warn_missing_spec(Config) -> Test = <<"-export([external_with_spec/0, external_no_spec/0]). @@ -4643,6 +4911,325 @@ unused_record(Config) when is_list(Config) -> ok. +unused_type2(Config) when is_list(Config) -> + Ts = [{unused_type2_1, + <<"-type t() :: [t()]. + t() -> + a. + ">>, + {[]}, + {warnings,[{{1,22},erl_lint,{unused_type,{t,0}}}, + {{2,15},erl_lint,{unused_function,{t,0}}}]}}, + {unused_type2_2, + <<"-type t1() :: t2(). + -type t2() :: t1(). + t() -> + a. + ">>, + {[]}, + {warnings,[{{1,22},erl_lint,{unused_type,{t1,0}}}, + {{2,16},erl_lint,{unused_type,{t2,0}}}, + {{3,16},erl_lint,{unused_function,{t,0}}}]}}, + {unused_type2_3, + <<"-callback cb() -> t(). + -type t() :: atom(). + t() -> + a. + ">>, + {[]}, + {warnings,[{{3,16},erl_lint,{unused_function,{t,0}}}]}}, + {unused_type2_4, + <<"-spec t() -> t(). + -type t() :: atom(). + t() -> + a. + ">>, + {[]}, + {warnings,[{{3,16},erl_lint,{unused_function,{t,0}}}]}}, + {unused_type2_5, + <<"-export_type([t/0]). + -type t() :: atom(). + t() -> + a. + ">>, + {[]}, + {warnings,[{{3,16},erl_lint,{unused_function,{t,0}}}]}}, + {unused_type2_6, + <<"-record(r, {f :: t()}). + -type t() :: atom(). + t() -> + a. + ">>, + {[]}, + {warnings,[{{1,22},erl_lint,{unused_record,r}}, + {{3,16},erl_lint,{unused_function,{t,0}}}]}} + ], + [] = run(Config, Ts), + + ok. + +%% Test maybe ... else ... end. +eep49(Config) when is_list(Config) -> + EnableMaybe = {feature,maybe_expr,enable}, + Ts = [{exp1, + <<"t(X) -> + maybe + A = X() + end, + A. + ">>, + [EnableMaybe], + {errors,[{{5,19},erl_lint,{unsafe_var,'A',{'maybe',{2,19}}}}], + []}}, + + {exp2, + <<"t(X) -> + maybe + A = X() + else + _ -> {ok,A} + end, + A. + ">>, + [EnableMaybe], + {errors,[{{5,32},erl_lint,{unsafe_var,'A',{'maybe',{2,19}}}}, + {{7,19},erl_lint,{unsafe_var,'A',{'maybe',{2,19}}}}], + []}}, + + {exp3, + <<"t(X) -> + maybe + X() + else + A -> + B = 42, + {error,A} + end, + {A,B}. + ">>, + [EnableMaybe], + {errors,[{{9,20},erl_lint,{unsafe_var,'A',{'else',{4,19}}}}, + {{9,22},erl_lint,{unsafe_var,'B',{'else',{4,19}}}}], + []}}, + + {exp4, + <<"t(X) -> + maybe + X() + else + ok -> + A = 42; + error -> + error + end, + A. + ">>, + [EnableMaybe], + {errors,[{{10,19},erl_lint,{unsafe_var,'A',{'else',{4,19}}}}], + []}}, + + %% Using '?=' not at the top-level of a 'maybe' ... 'else' is forbidden. + {illegal_maybe_match1, + <<"t(X) -> + maybe (ok ?= X()) end. + ">>, + [EnableMaybe], + {errors,[{{2,29},erl_parse,["syntax error before: ","'?='"]}],[]}}, + {illegal_maybe_match2, + <<"t(X) -> + ok ?= X(). + ">>, + [EnableMaybe], + {errors,[{{2,22},erl_parse,["syntax error before: ","'?='"]}],[]}} + ], + + [] = run(Config, Ts), + ok. + +%% GH-6132: Allow local redefinition of types. +redefined_builtin_type(Config) -> + Ts = [{redef1, + <<"-type nonempty_binary() :: term(). + -type map() :: {_,_}.">>, + [nowarn_unused_type, + nowarn_redefined_builtin_type], + []}, + {redef2, + <<"-type nonempty_bitstring() :: term(). + -type map() :: {_,_}.">>, + [nowarn_unused_type, + {nowarn_redefined_builtin_type,{map,0}}], + {warnings,[{{1,22},erl_lint, + {redefine_builtin_type,{nonempty_bitstring,0}}}]}}, + {redef3, + <<"-compile({nowarn_redefined_builtin_type,{map,0}}). + -compile({nowarn_redefined_builtin_type,[{nonempty_bitstring,0}]}). + -type nonempty_bitstring() :: term(). + -type map() :: {_,_}. + -type list() :: erlang:map().">>, + [nowarn_unused_type, + {nowarn_redefined_builtin_type,{map,0}}], + {warnings,[{{5,16},erl_lint, + {redefine_builtin_type,{list,0}}}]}}, + {redef4, + <<"-type tuple() :: 'tuple'. + -type map() :: 'map'. + -type list() :: 'list'. + -spec t(tuple() | map()) -> list(). + t(_) -> ok. + ">>, + [], + {warnings,[{{1,22},erl_lint,{redefine_builtin_type,{tuple,0}}}, + {{2,16},erl_lint,{redefine_builtin_type,{map,0}}}, + {{3,16},erl_lint,{redefine_builtin_type,{list,0}}} + ]}}, + {redef5, + <<"-type atom() :: 'atom'. + -type integer() :: 'integer'. + -type reference() :: 'ref'. + -type pid() :: 'pid'. + -type port() :: 'port'. + -type float() :: 'float'. + -type iodata() :: 'iodata'. + -type ref_set() :: gb_sets:set(reference()). + -type pid_map() :: #{pid() => port()}. + -type atom_int_fun() :: fun((atom()) -> integer()). + -type collection(Type) :: {'collection', Type}. + -callback b1(I :: iodata()) -> atom(). + -spec t(collection(float())) -> {pid_map(), ref_set(), atom_int_fun()}. + t(_) -> ok. + ">>, + [], + {warnings,[{{1,22},erl_lint,{redefine_builtin_type,{atom,0}}}, + {{2,16},erl_lint,{redefine_builtin_type,{integer,0}}}, + {{3,16},erl_lint,{redefine_builtin_type,{reference,0}}}, + {{4,16},erl_lint,{redefine_builtin_type,{pid,0}}}, + {{5,16},erl_lint,{redefine_builtin_type,{port,0}}}, + {{6,16},erl_lint,{redefine_builtin_type,{float,0}}}, + {{7,16},erl_lint,{redefine_builtin_type,{iodata,0}}} + ]}}, + {redef6, + <<"-spec bar(function()) -> bar(). + bar({function, F}) -> F(). + -type function() :: {function, fun(() -> bar())}. + -type bar() :: {bar, binary()}. + ">>, + [], + {warnings,[{{3,16},erl_lint, + {redefine_builtin_type,{function,0}}}]}}, + {redef7, + <<"-type function() :: {function, fun(() -> bar())}. + -type bar() :: {bar, binary()}. + -spec bar(function()) -> bar(). + bar({function, F}) -> F(). + ">>, + [], + {warnings,[{{1,22},erl_lint, + {redefine_builtin_type,{function,0}}}]}}, + {redef8, + <<"-type function() :: {function, fun(() -> atom())}. + ">>, + [], + {warnings,[{{1,22},erl_lint, + {redefine_builtin_type,{function,0}}}, + {{1,22},erl_lint, + {unused_type,{function,0}}}]}}, + {redef9, + <<"-spec foo() -> fun(). + foo() -> fun() -> ok end. + ">>, + [], + []} + ], + [] = run(Config, Ts), + ok. + +tilde_k(Config) -> + Ts = [{tilde_k_1, + <<"t(Map) -> + io:format(\"~kp\n\", [Map]), + io:format(\"~kP\n\", [Map,10]), + io:format(\"~kw\n\", [Map]), + io:format(\"~kW\n\", [Map,5]), + io:format(\"~tkp\n\", [Map]), + io:format(\"~klp\n\", [Map]), + RevCmpFun = fun erlang:'>='/2, + io:format(\"~Kp\n\", [RevCmpFun,Map]), + io:format(\"~KP\n\", [RevCmpFun,Map,10]), + io:format(\"~Kw\n\", [RevCmpFun,Map]), + io:format(\"~KW\n\", [RevCmpFun,Map,5]), + ok.">>, + [], + []}, + {tilde_k_2, + <<"t(Map) -> + io:format(\"~kkp\n\", [Map]), + io:format(\"~kKp\n\", [Map]), + io:format(\"~ks\n\", [Map]), + ok.">>, + [], + {warnings, + [{{2,29}, + erl_lint, + {format_error,{"format string invalid (~ts)", + ["repeated modifier k"]}}}, + {{4,29}, + erl_lint, + {format_error,{"format string invalid (~ts)", + ["conflicting modifiers ~Kkp"]}}}, + {{6,29}, + erl_lint, + {format_error,{"format string invalid (~ts)", + ["invalid modifier/control combination ~ks"]}}}]} + } + ], + [] = run(Config, Ts), + + ok. + +match_float_zero(Config) -> + Ts = [{float_zero_1, + <<"t(+0.0) -> ok.\n" + "k(-0.0) -> ok.\n">>, + [], + []}, + {float_zero_2, + <<"t(0.0) -> ok.\n" + "k({0.0}) -> ok.\n">>, + [], + {warnings,[{{1,23},erl_lint,match_float_zero}, + {{2,4},erl_lint,match_float_zero}]}}, + {float_zero_3, + <<"t(A) when A =:= 0.0 -> ok;\n" %% Should warn. + "t(A) when A =:= {0.0} -> ok.\n" %% Should warn. + "k(A) -> A =:= 0.0.\n" %% Should warn. + "q(A) -> A =:= {0.0}.\n" %% Should warn. + "z(A) when A =:= +0.0 -> ok;\n" %% Should not warn. + "z(A) when A =:= {+0.0} -> ok.\n">>, %% Should not warn. + [], + {warnings,[{{1,37},erl_lint,match_float_zero}, + {{2,18},erl_lint,match_float_zero}, + {{3,15},erl_lint,match_float_zero}, + {{4,16},erl_lint,match_float_zero}]}} + ], + [] = run(Config, Ts), + + ok. + +%% GH-7655. When the module definition was missing, spurious +%% diagnostics would be emitted for each spec. +undefined_module(Config) -> + Code = <<"-spec foo() -> 'ok'. + foo() -> ok. + ">>, + {errors,[{{1,2},erl_lint,undefined_module}],[]} = run_test2(Config, Code, []), + + ok. + +%%% +%%% Common utilities. +%%% + format_error(E) -> lists:flatten(erl_lint:format_error(E)). diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index ce0abd213e63..ef021aa69170 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2023. 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. @@ -48,13 +48,15 @@ neg_indent/1, maps_syntax/1, format_options/1, - quoted_atom_types/1, + form_vars/1, + quoted_atom_types/1, otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1, otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1, otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1, otp_15755/1, - otp_16435/1]). + otp_16435/1, gh_5093/1, + eep49/1, eep58/1]). %% Internal export. -export([ehook/6]). @@ -78,14 +80,15 @@ groups() -> [func, call, recs, try_catch, if_then, receive_after, bits, head_tail, cond1, block, case1, ops, messages, maps_syntax, quoted_atom_types, - format_options + format_options, form_vars ]}, {attributes, [], [misc_attrs, import_export, dialyzer_attrs]}, {tickets, [], [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, otp_8473, otp_8522, otp_8567, otp_8664, otp_9147, otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662, - otp_14285, otp_15592, otp_15751, otp_15755, otp_16435]}]. + otp_14285, otp_15592, otp_15751, otp_15755, otp_16435, + gh_5093, eep49, eep58]}]. init_per_suite(Config) -> Config. @@ -577,6 +580,37 @@ format_options(Config) when is_list(Config) -> ) ). +form_vars(Config) when is_list(Config) -> + %% Check that erl_pp:legalize_vars/1 does its job. If + %% legalize_vars/1 fails to convert variable names starting with a + %% lower case letter, the compiler will detect that `X` is an atom + %% and report that the `+` operation will fail. If legalize_vars/1 + %% fails to generate unique variable names and just converts the + %% name to uppercase, the variable named `REC0` will be used in an + %% unsafe way. + String = <<"-module(erl_pp_test). + -export([f/1]). + -record(r, {a, b}). + f(#r{b = B} = C) -> + receive + B -> + X = C#r.a, + REC0 = X + X, + REC0 + end.">>, + FileName = filename('erl_pp_test.erl', Config), + ok = file:write_file(FileName, String), + Opts = [binary,deterministic,nowarn_unused_record], + {ok, [], Forms} = compile:file(FileName, ['E'|Opts]), + Forms1 = lists:map(fun(F={function,_,_,_,_}) -> + erl_pp:legalize_vars(F); + (F) -> + F + end, Forms), + ok = file:write_file(FileName, [erl_pp:form(F) || F <- Forms1]), + {ok, _, _, []} = compile:file(FileName, [return|Opts]), + ok. + misc_attrs(Config) when is_list(Config) -> ok = pp_forms(<<"-module(m). ">>), ok = pp_forms(<<"-module(m, [Aafjlksfjdlsjflsdfjlsdjflkdsfjlk," @@ -1085,14 +1119,14 @@ unicode_hook({foo,E}, I, P, H) -> %% OTP-10820. Unicode filenames. otp_10820(Config) when is_list(Config) -> C1 = <<"%% coding: utf-8\n -module(any).">>, - ok = do_otp_10820(Config, C1, "+pc latin1"), - ok = do_otp_10820(Config, C1, "+pc unicode"), + ok = do_otp_10820(Config, C1, ["+pc", "latin1"]), + ok = do_otp_10820(Config, C1, ["+pc", "unicode"]), C2 = <<"%% coding: latin-1\n -module(any).">>, - ok = do_otp_10820(Config, C2, "+pc latin1"), - ok = do_otp_10820(Config, C2, "+pc unicode"). + ok = do_otp_10820(Config, C2, ["+pc", "latin1"]), + ok = do_otp_10820(Config, C2, ["+pc", "unicode"]). do_otp_10820(Config, C, PC) -> - {ok,Node} = start_node(erl_pp_helper, "+fnu " ++ PC), + {ok,Peer,Node} = ?CT_PEER(["+fnu"] ++ PC), L = [915,953,959,973,957,953,954,959,957,964], FileName = filename(L++".erl", Config), ok = rpc:call(Node, file, write_file, [FileName, C]), @@ -1100,7 +1134,7 @@ do_otp_10820(Config, C, PC) -> [FileName, [return,'P',{outdir,?privdir}]]), PFileName = filename(L++".P", Config), {ok, Bin} = rpc:call(Node, file, read_file, [PFileName]), - true = test_server:stop_node(Node), + peer:stop(Peer), true = file_attr_is_string(binary_to_list(Bin)), ok. @@ -1335,6 +1369,51 @@ otp_16435(_Config) -> ok. +gh_5093(_Config) -> + assert_same("f() ->\n -1.\n"), + assert_same("f() ->\n +1.\n"), + assert_same("f() ->\n +1.1.\n"), + assert_same("f() ->\n +(+1).\n"), + assert_same("f(X) ->\n -X.\n"), + assert_same("f(X) ->\n +X.\n"), + assert_same("f(X, Y) ->\n X + Y.\n"), + assert_same("f(X, Y) ->\n X + +Y.\n"), + assert_same("f(X, Y) ->\n X - Y.\n"), + ok. + +eep49(_Config) -> + assert_same("f() ->\n" + " maybe ok ?= ok end.\n"), + assert_same("f() ->\n" + " maybe\n" + " ok ?= ok\n" + " else\n" + " {error, _} ->\n" + " error\n" + " end.\n"), + ok. + +eep58(_Config) -> + assert_same("lc_map(Map) ->\n" + " [ \n" + " {K, V} ||\n" + " K := V <- Map\n" + " ].\n"), + + assert_same("bc_map(Map) ->\n" + " << \n" + " <> ||\n" + " K := V <- Map\n" + " >>.\n"), + + assert_same("mc(Map) ->\n" + " #{ \n" + " K => V + 1 ||\n" + " K := V <- Map\n" + " }.\n"), + + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile(Config, Tests) -> @@ -1430,7 +1509,15 @@ parse_forms(Chars) -> parse_forms2([], _Cont, _Line, Forms) -> lists:reverse(Forms); parse_forms2(String, Cont0, Line, Forms) -> - case erl_scan:tokens(Cont0, String, Line) of + %% FIXME: When the experimental features EEP has been implemented, we should + %% dig out all keywords defined in all features. + ResWordFun = + fun('maybe') -> true; + ('else') -> true; + (Other) -> erl_scan:reserved_word(Other) + end, + Options = [{reserved_word_fun,ResWordFun}], + case erl_scan:tokens(Cont0, String, Line, Options) of {done, {ok, Tokens, EndLine}, Chars} -> {ok, Form} = erl_parse:parse_form(Tokens), parse_forms2(Chars, [], EndLine, [Form | Forms]); @@ -1514,7 +1601,9 @@ filename(Name, Config) -> fail() -> ct:fail(failed). -%% +fnu means a peer node has to be started; slave will not do -start_node(Name, Xargs) -> - PA = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, peer, [{args, "-pa " ++ PA ++ " " ++ Xargs}]). +assert_same(Expected) when is_list(Expected) -> + Actual = binary_to_list(iolist_to_binary(parse_and_pp_forms(Expected, []))), + case Expected == Actual of + true -> ok; + false -> error({Expected, Actual}) + end. diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index f853ad7ad794..96c68039aee5 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2021. All Rights Reserved. +%% Copyright Ericsson AB 1998-2022. 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. @@ -23,7 +23,8 @@ init_per_group/2,end_per_group/2]). -export([error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1, - otp_10990/1, otp_10992/1, otp_11807/1, otp_16480/1, otp_17024/1]). + otp_10990/1, otp_10992/1, otp_11807/1, otp_16480/1, otp_17024/1, + text_fun/1]). -import(lists, [nth/2,flatten/1]). -import(io_lib, [print/1]). @@ -58,7 +59,7 @@ suite() -> all() -> [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992, - otp_11807, otp_16480, otp_17024]. + otp_11807, otp_16480, otp_17024, text_fun]. groups() -> [{error, [], [error_1, error_2]}]. @@ -515,12 +516,17 @@ chars() -> test_string(L, Ts) end || C <- lists:seq(0, 255)], - %% $\^\n now increments the line... + %% GH-6477. Test legal use of caret notation. [begin L = "$\\^" ++ [C], - Ts = [{char,{1,1},C band 2#11111}], + Ts = case C of + $? -> + [{char,{1,1},127}]; + _ -> + [{char,{1,1},C band 2#11111}] + end, test_string(L, Ts) - end || C <- lists:seq(0, 255)], + end || C <- lists:seq($?, $Z) ++ lists:seq($a, $z)], [begin L = "$\\" ++ [C], @@ -671,10 +677,18 @@ illegal() -> erl_scan:string(String, {1,1}), {done,{error,{{1,4},erl_scan,{illegal,character}},{1,14}},"34\". "} = erl_scan:tokens([], String++". ", {1,1}), + + %% GH-6477. Test for illegal characters in caret notation. + _ = [begin + S = [$$,$\\,$^,C], + {error,{1,erl_scan,{illegal,character}},1} = erl_scan:string(S) + end || C <- lists:seq(0, 16#3e) ++ [16#60] ++ lists:seq($z+1, 16#10ffff)], ok. crashes() -> {'EXIT',_} = (catch {foo, erl_scan:string([-1])}), % type error + {'EXIT',_} = (catch erl_scan:string("'a" ++ [999999999] ++ "c'")), + {'EXIT',_} = (catch {foo, erl_scan:string("$"++[-1])}), {'EXIT',_} = (catch {foo, erl_scan:string("$\\"++[-1])}), {'EXIT',_} = (catch {foo, erl_scan:string("$\\^"++[-1])}), @@ -697,6 +711,7 @@ crashes() -> (catch {foo, erl_scan:string("% foo"++[a],{1,1})}), {'EXIT',_} = (catch {foo, erl_scan:string([3.0])}), % type error + {'EXIT',_} = (catch {foo, erl_scan:string("A" ++ [999999999])}), ok. @@ -866,11 +881,11 @@ unicode() -> erl_scan:string([1089]), {error,{{1,1},erl_scan,{illegal,character}},{1,2}} = erl_scan:string([1089], {1,1}), - {error,{{1,3},erl_scan,{illegal,character}},{1,4}} = - erl_scan:string("'a" ++ [999999999] ++ "c'", {1,1}), + {error,{{1,1},erl_scan,{illegal,character}},{1,2}} = + erl_scan:string([16#D800], {1,1}), test("\"a"++[1089]++"b\""), - {ok,[{char,1,1}],1} = + {error,{1,erl_scan,{illegal,character}},1} = erl_scan_string([$$,$\\,$^,1089], 1), {error,{1,erl_scan,Error},1} = @@ -907,7 +922,7 @@ unicode() -> U3 = "\"a\n\\x{fff}\n\"", {ok,[{string,1,[$a,$\n,$\x{fff},$\n]}],3} = erl_scan_string(U3, 1), - U4 = "\"\\^\n\\x{aaa}\\^\n\"", + U4 = "\"\n\\x{aaa}\n\"", {ok,[{string,1,[$\n,$\x{aaa},$\n]}],3} = erl_scan_string(U4, 1), %% Keep these tests: @@ -1022,7 +1037,7 @@ otp_10302(Config) when is_list(Config) -> U3 = "\"a\n\\x{fff}\n\"", {ok,[{string,1,[97,10,4095,10]}],3} = erl_scan_string(U3, 1), - U4 = "\"\\^\n\\x{aaa}\\^\n\"", + U4 = "\"\n\\x{aaa}\n\"", {ok,[{string,1,[10,2730,10]}],3} = erl_scan_string(U4, 1,[]), Str1 = "\"ab" ++ [1089] ++ "cd\"", @@ -1212,6 +1227,79 @@ otp_17024(Config) when is_list(Config) -> {integer,Location,1} = erl_parse_abstract(1, Opts2), ok. +text_fun(Config) when is_list(Config) -> + KeepClass = fun(Class) -> + fun(C, _) -> C == Class end + end, + + Join = fun(L, S) -> string:join(L, S) end, + String = fun(L) -> Join(L, " ") end, + + TextAtom = KeepClass(atom), + TextInt = KeepClass(integer), + %% Keep text for integers written with a base. + TextBase = fun(C, S) -> + C == integer andalso string:find(S, "#") /= nomatch + end, + %% Keep text for long strings, regardless of class + TextLong = fun(_, S) -> length(S) > 10 end, + + Texts = fun(Toks) -> [erl_scan:text(T) || T <- Toks] end, + Values = fun(Toks) -> [erl_scan:symbol(T) || T <- Toks] end, + + Atom1 = "foo", + Atom2 = "'this is a long atom'", + Int1 = "42", + Int2 = "16#10", + Int3 = "8#20", + Int4 = "16", + Int5 = "12345678901234567890", + String1 = "\"A String\"", + String2 = "\"guitar string\"", + Name1 = "Short", + Name2 = "LongAndDescriptiveName", + Sep1 = "{", + Sep2 = "+", + Sep3 = "]", + Sep4 = "/", + + All = [Atom1, Atom2, Int1, Int2, Int3, Int4, Int5, + String1, String2, Name1, Name2, + Sep1, Sep2, Sep3, Sep4], + + {ok, Tokens0, 2} = + erl_scan:string(String([Atom1, Int1]), 2, [{text_fun, TextAtom}]), + [Atom1, undefined] = Texts(Tokens0), + [foo, 42] = Values(Tokens0), + + {ok, Tokens1, 3} = + erl_scan:string(Join([Int2, Int3, Int4], "\n"), 1, + [{text_fun, TextInt}]), + [Int2, Int3, Int4] = Texts(Tokens1), + [16, 16, 16] = Values(Tokens1), + + TS = [Int2, String1, Atom1, Int3, Int4, String2], + {ok, Tokens2, 6} = + %% If text is present, we supply text for *all* tokens. + erl_scan:string(Join(TS, "\n"), 1, [{text_fun, TextAtom}, text]), + TS = Texts(Tokens2), + [16, "A String", foo, 16, 16, "guitar string"] = Values(Tokens2), + + Ints = [Int1, Int2, Int3, Int4], + {ok, Tokens3, 1} = erl_scan:string(String(Ints), 1, [{text_fun, TextBase}]), + [undefined, Int2, Int3, undefined] = Texts(Tokens3), + [42, 16, 16, 16] = Values(Tokens3), + + Longs = lists:filter(fun(S) -> length(S) > 10 end, All), + {ok, Tokens4, 1} = + erl_scan:string(String(All), 1, [{text_fun, TextLong}]), + Longs = lists:filter(fun(T) -> T /= undefined end, Texts(Tokens4)), + + {ok, Tokens5, 7} = + erl_scan:string(String(All), 7, [{text_fun, KeepClass('{')}]), + [Sep1] = lists:filter(fun(T) -> T /= undefined end, Texts(Tokens5)). + + test_string(String, ExpectedWithCol) -> {ok, ExpectedWithCol, _EndWithCol} = erl_scan_string(String, {1, 1}, []), Expected = [ begin diff --git a/lib/stdlib/test/error_info_lib.erl b/lib/stdlib/test/error_info_lib.erl index 716fa47eb9d5..22347b663802 100644 --- a/lib/stdlib/test/error_info_lib.erl +++ b/lib/stdlib/test/error_info_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2021. All Rights Reserved. +%% Copyright Ericsson AB 2021-2022. 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. @@ -20,6 +20,21 @@ -module(error_info_lib). -export([test_error_info/2, test_error_info/3]). +%% The wrapper fun should behave as if it was apply/3. +%% See os_SUITE for an example usage. +-type wrapper() :: fun((module(),function(),list(term)) -> term()). + +%% Options that can be given to testcases +-type option() :: {integer(), Regexp :: string()} | %% Match argument #1 against RegExp + {general, Regexp :: string()} | %% Match general info against RegExp + {wrapper, wrapper()} | %% Wrap the test call using this fun + {gl, pid()} | %% Use this group leader for the test + no_fail | %% The test will not fail + allow_rename | %% Allow the exception to not originate from Func + unexplained. %% Allow the test to not provide any explanation +-type test() :: {Func :: function(), Args :: [term()]} | + {Func :: function(), Args :: [term()], Opts :: list(option())}. +-spec test_error_info(module(), list(test())) -> ok. test_error_info(Module, List) -> test_error_info(Module, List, []). @@ -75,7 +90,8 @@ do_error_info([], _Module, Errors0) -> eval_bif_error(F, Args, Opts, T, Module, Errors0) -> OldGl = group_leader(), group_leader(proplists:get_value(gl, Opts, OldGl), self()), - try apply(Module, F, Args) of + Wrapper = proplists:get_value(wrapper, Opts, fun(M, Fun, A) -> apply(M, Fun, A) end), + try Wrapper(Module, F, Args) of Result -> group_leader(OldGl, self()), case lists:member(no_fail, Opts) of diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl index bf9b6d9ad6d5..3dcbc2664a82 100644 --- a/lib/stdlib/test/error_logger_h_SUITE.erl +++ b/lib/stdlib/test/error_logger_h_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2015-2018. All Rights Reserved. +%% Copyright Ericsson AB 2015-2023. 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. @@ -57,8 +57,7 @@ logfile(Config) -> do_one_logfile(Log, Ev, unlimited), - Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), - {ok,Node} = start_node(logfile, Pa), + {ok,Peer,Node} = ?CT_PEER(), error_logger:logfile({open,Log}), ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]), @@ -67,19 +66,19 @@ logfile(Config) -> analyse_events(Log, Ev, [AtNode], unlimited), %% Make sure that the file_io_server process has been stopped - [] = lists:filtermap( - fun(X) -> - case {process_info(X, [current_function]), - file:pid2name(X)} of - {[{current_function, {file_io_server, _, _}}], - {ok,P2N = Log}} -> - {true, {X, P2N}}; - _ -> - false - end - end, processes()), - - test_server:stop_node(Node), + [] = lists:filtermap(fun(X) -> + case process_info(X, [current_function]) of + [{current_function, {file_io_server, _, _}}] -> + case file:pid2name(X) of + {ok, Log} -> {true, {X, Log}}; + _ -> false + end; + _ -> + false + end + end, processes()), + + peer:stop(Peer), cleanup(Log), ok. @@ -119,8 +118,7 @@ tty(Config) -> do_one_tty(Log, Ev, unlimited), - Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), - {ok,Node} = start_node(tty, Pa), + {ok,Peer,Node} = ?CT_PEER(), tty_log_open(Log), ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]), tty_log_close(), @@ -128,7 +126,7 @@ tty(Config) -> timer:sleep(1000), % some time get all log events in the log analyse_events(Log, Ev, [AtNode], unlimited), - test_server:stop_node(Node), + peer:stop(Peer), cleanup(Log), ok. @@ -339,14 +337,6 @@ match_head(Tag, Head) -> "\\d\\d:\\d\\d:\\d\\d ===$">>, {match,_} = re:run(Head, Re). -start_node(Name, Args) -> - case test_server:start_node(Name, slave, [{args,Args}]) of - {ok,Node} -> - {ok,Node}; - Error -> - ct:fail(Error) - end. - cleanup(File) -> %% The point of this test case is not to test file operations. %% Therefore ignore any failures. diff --git a/lib/stdlib/test/escript_SUITE_data/arg_overflow b/lib/stdlib/test/escript_SUITE_data/arg_overflow index dd5accc05184..e3138cabbdaf 100755 --- a/lib/stdlib/test/escript_SUITE_data/arg_overflow +++ b/lib/stdlib/test/escript_SUITE_data/arg_overflow @@ -1,5 +1,5 @@ #! /usr/bin/env escript %% -*- erlang -*- -%%!x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x +%%!-x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x -x main(_) -> halt(0). diff --git a/lib/stdlib/test/escript_SUITE_data/linebuf_overflow b/lib/stdlib/test/escript_SUITE_data/linebuf_overflow index 33133c1ce903..018be1f26d0a 100755 --- a/lib/stdlib/test/escript_SUITE_data/linebuf_overflow +++ b/lib/stdlib/test/escript_SUITE_data/linebuf_overflow @@ -1,5 +1,5 @@ #! /usr/bin/env escript %% -*- erlang -*- -%%!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +%%!-v xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx main(_) -> halt(0). diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index dff1936e846f..9433757d6bb8 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -36,13 +36,15 @@ -export([dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]). -export([info_binary_stress/1]). -export([info_whereis_busy/1]). +-export([insert_trap_delete/1, insert_trap_rename/1]). -export([tab2file/1, tab2file2/1, tabfile_ext1/1, tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1, badfile/1]). -export([heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]). --export([lookup_element_mult/1]). +-export([lookup_element_mult/1, lookup_element_default/1]). -export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]). -export([t_delete_object/1, t_init_table/1, t_whitebox/1, select_bound_chunk/1, t_delete_all_objects/1, t_test_ms/1, + t_delete_all_objects_trap/1, t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1, t_select_pam_stack_overflow_bug/1, t_select_flatmap_term_copy_bug/1, @@ -51,7 +53,8 @@ -export([t_insert_list/1, t_insert_list_bag/1, t_insert_list_duplicate_bag/1, t_insert_list_set/1, t_insert_list_delete_set/1, t_insert_list_parallel/1, t_insert_list_delete_parallel/1, - t_insert_list_kill_process/1]). + t_insert_list_kill_process/1, + t_insert_list_insert_order_preserved/1]). -export([test_table_size_concurrency/1,test_table_memory_concurrency/1, test_delete_table_while_size_snapshot/1, test_delete_table_while_size_snapshot_helper/1, test_decentralized_counters_setting/1]). @@ -99,6 +102,7 @@ -export([otp_9932/1]). -export([otp_9423/1]). -export([otp_10182/1]). +-export([compress_magic_ref/1]). -export([ets_all/1]). -export([massive_ets_all/1]). -export([take/1]). @@ -134,7 +138,7 @@ end_per_testcase(_Func, _Config) -> suite() -> [{ct_hooks,[ts_install_cth]}, - {timetrap,{minutes,5}}]. + {timetrap,{minutes,30}}]. all() -> [{group, new}, {group, insert}, {group, lookup}, @@ -152,6 +156,7 @@ all() -> match_heavy, {group, fold}, member, t_delete_object, select_bound_chunk, t_init_table, t_whitebox, t_delete_all_objects, + t_delete_all_objects_trap, t_test_ms, t_select_delete, t_select_replace, t_select_replace_next_bug, t_select_pam_stack_overflow_bug, @@ -173,19 +178,21 @@ all() -> otp_10182, otp_9932, otp_9423, + compress_magic_ref, ets_all, massive_ets_all, take, whereis_table, delete_unfix_race, - %test_throughput_benchmark, - %{group, benchmark}, + test_throughput_benchmark, + {group, benchmark}, test_table_size_concurrency, test_table_memory_concurrency, test_delete_table_while_size_snapshot, test_decentralized_counters_setting, ms_excessive_nesting, - error_info]. + error_info + ]. groups() -> @@ -194,7 +201,7 @@ groups() -> privacy]}, {insert, [], [empty, badinsert]}, {lookup, [], [badlookup, lookup_order]}, - {lookup_element, [], [lookup_element_mult]}, + {lookup_element, [], [lookup_element_mult, lookup_element_default]}, {delete, [], [delete_elem, delete_tab, delete_large_tab, delete_large_named_table, evil_delete, table_leak, @@ -221,7 +228,10 @@ groups() -> [t_insert_list, t_insert_list_set, t_insert_list_bag, t_insert_list_duplicate_bag, t_insert_list_delete_set, t_insert_list_parallel, t_insert_list_delete_parallel, - t_insert_list_kill_process]}]. + t_insert_list_kill_process, + t_insert_list_insert_order_preserved, + insert_trap_delete, + insert_trap_rename]}]. init_per_suite(Config) -> erts_debug:set_internal_state(available_internal_state, true), @@ -270,10 +280,15 @@ end_per_group(benchmark, Config) -> T = proplists:get_value(ets_benchmark_result_summary_tab, Config), EtsProcess = proplists:get_value(ets_benchmark_result_summary_tab_process, Config), Report = - fun(NOfBenchmarksCtr, TotThroughoutCtr, Name) -> + fun(NOfBenchmarksCtr, TotThroughputCtr, Name) -> Average = - ets:lookup_element(T, TotThroughoutCtr, 2) / - ets:lookup_element(T, NOfBenchmarksCtr, 2), + case {ets:lookup_element(T, TotThroughputCtr, 2), + ets:lookup_element(T, NOfBenchmarksCtr, 2)} of + {0.0, 0.0} -> + 0; + {TotThrp, NBench} -> + TotThrp / NBench + end, io:format("~p ~p~n", [Name, Average]), ct_event:notify( #event{name = benchmark_data, @@ -588,12 +603,14 @@ t_repair_continuation(Config) when is_list(Config) -> repeat_for_opts(fun t_repair_continuation_do/1). -t_repair_continuation_do(Opts) -> +t_repair_continuation_do(OptsIn) -> EtsMem = etsmem(), MS = [{'_',[],[true]}], MS2 = [{{{'$1','_'},'_'},[],['$1']}], - (fun() -> - T = ets_new(x,[ordered_set|Opts]), + run_if_valid_opts( + [ordered_set|OptsIn], + fun(Opts) -> + T = ets_new(x, Opts), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, F(1000,F), {_,C} = ets:select(T,MS,5), @@ -603,9 +620,11 @@ t_repair_continuation_do(Opts) -> {[true,true,true,true,true],_} = ets:select(C3), {[true,true,true,true,true],_} = ets:select(C), true = ets:delete(T) - end)(), - (fun() -> - T = ets_new(x,[ordered_set|Opts]), + end), + run_if_valid_opts( + [ordered_set|OptsIn], + fun(Opts) -> + T = ets_new(x, Opts), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end, F(1000,F), {_,C} = ets:select(T,MS,1001), @@ -614,10 +633,12 @@ t_repair_continuation_do(Opts) -> '$end_of_table' = ets:select(C3), '$end_of_table' = ets:select(C), true = ets:delete(T) - end)(), + end), - (fun() -> - T = ets_new(x,[ordered_set|Opts]), + run_if_valid_opts( + [ordered_set|OptsIn], + fun(Opts) -> + T = ets_new(x, Opts), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -630,9 +651,11 @@ t_repair_continuation_do(Opts) -> {[true,true,true,true,true],_} = ets:select(C3), {[true,true,true,true,true],_} = ets:select(C), true = ets:delete(T) - end)(), - (fun() -> - T = ets_new(x,[ordered_set|Opts]), + end), + run_if_valid_opts( + [ordered_set|OptsIn], + fun(Opts) -> + T = ets_new(x, Opts), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{{integer_to_list(N),N},N}), F(N-1,F) @@ -645,10 +668,10 @@ t_repair_continuation_do(Opts) -> {[_,_,_,_,_],_} = ets:select(C3), {[_,_,_,_,_],_} = ets:select(C), true = ets:delete(T) - end)(), + end), (fun() -> - T = ets_new(x,[set|Opts]), + T = ets_new(x,[set|OptsIn]), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) @@ -663,7 +686,7 @@ t_repair_continuation_do(Opts) -> true = ets:delete(T) end)(), (fun() -> - T = ets_new(x,[set|Opts]), + T = ets_new(x,[set|OptsIn]), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -678,7 +701,7 @@ t_repair_continuation_do(Opts) -> true = ets:delete(T) end)(), (fun() -> - T = ets_new(x,[bag|Opts]), + T = ets_new(x,[bag|OptsIn]), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -693,7 +716,7 @@ t_repair_continuation_do(Opts) -> true = ets:delete(T) end)(), (fun() -> - T = ets_new(x,[duplicate_bag|Opts]), + T = ets_new(x,[duplicate_bag|OptsIn]), F = fun(0,_)->ok;(N,F) -> ets:insert(T,{integer_to_list(N),N}), F(N-1,F) @@ -894,14 +917,19 @@ whitebox_1(Opts) -> ets:delete(T), ok. -whitebox_2(Opts) -> - T=ets_new(x,[ordered_set, {keypos,2} | Opts]), - T2=ets_new(x,[set, {keypos,2}| Opts]), - 0 = ets:select_delete(T,[{{hej},[],[true]}]), - 0 = ets:select_delete(T,[{{hej,hopp},[],[true]}]), +whitebox_2(OptsIn) -> + run_if_valid_opts( + [ordered_set, {keypos,2} | OptsIn], + fun (Opts) -> + T = ets_new(x, Opts), + 0 = ets:select_delete(T,[{{hej},[],[true]}]), + 0 = ets:select_delete(T,[{{hej,hopp},[],[true]}]), + ets:delete(T) + end), + + T2 = ets_new(x,[set, {keypos,2}| OptsIn]), 0 = ets:select_delete(T2,[{{hej},[],[true]}]), 0 = ets:select_delete(T2,[{{hej,hopp},[],[true]}]), - ets:delete(T), ets:delete(T2), ok. @@ -958,14 +986,14 @@ t_delete_all_objects(Config) when is_list(Config) -> get_kept_objects(T) -> case ets:info(T,stats) of - {_,_,_,_,_,_,KO} -> + {_,_,_,_,_,_,KO,_} -> KO; _ -> 0 end. t_delete_all_objects_do(Opts) -> - KeyRange = 4000, + KeyRange = 40_000, T=ets_new(x, Opts, KeyRange), filltabint(T,KeyRange), O=ets:first(T), @@ -1044,6 +1072,79 @@ inserter(T, Next, Papa) -> end. +%% Poke table during delete_all_objects +t_delete_all_objects_trap(Config) when is_list(Config) -> + EtsMem = etsmem(), + repeat_for_opts_all_set_table_types( + fun(Opts) -> + delete_all_objects_trap(Opts, unfix), + delete_all_objects_trap(Opts, exit), + delete_all_objects_trap(Opts, rename) + end), + verify_etsmem(EtsMem), + ok. + +delete_all_objects_trap(Opts, Mode) -> + io:format("Opts = ~p\nMode = ~p\n", [Opts, Mode]), + Tester = self(), + KeyRange = 50_000, + TableName = delete_all_objects_trap, + {Tref,T} = + case Mode of + rename -> + TableName = ets_new(TableName, [named_table,public|Opts], KeyRange), + {ets:whereis(TableName), TableName}; + _ -> + Tid = ets_new(x, Opts, KeyRange), + {Tid,Tid} + end, + filltabint(T, KeyRange), + KeyRange = ets:info(T,size), + FixerFun = + fun() -> + erlang:trace(Tester, true, [running]), + case Mode of + rename -> ok; + _ -> ets:safe_fixtable(T, true) + end, + io:format("Wait for ets:delete_all_objects/1 to yield...\n", []), + Tester ! {ready, self()}, + repeat_while( + fun() -> + case receive_any() of + {trace, Tester, out, {ets,internal_delete_all,2}} -> + false; + "delete_all_objects done" -> + ct:fail("No trap detected"); + _M -> + %%io:format("Ignored msg: ~p\n", [_M]), + true + end + end), + case Mode of + unfix -> + io:format("Unfix table and then exit...\n",[]), + ets:safe_fixtable(T, false); + exit -> + %%io:format("Exit and do auto-unfix...\n",[]), + exit; + rename -> + %%io:format("Rename table...\n",[]), + renamed = ets:rename(T, renamed) + end + end, + {Fixer, Mon} = spawn_opt(FixerFun, [link, monitor]), + {ready, Fixer} = receive_any(), + true = ets:delete_all_objects(T), + Fixer ! "delete_all_objects done", + 0 = ets:info(Tref,size), + {'DOWN', Mon, process, Fixer, normal} = receive_any(), + 0 = get_kept_objects(Tref), + false = ets:info(Tref,safe_fixed), + ets:delete(Tref), + ok. + + %% Test ets:delete_object/2. t_delete_object(Config) when is_list(Config) -> EtsMem = etsmem(), @@ -1068,12 +1169,16 @@ t_delete_object_do(Opts) -> 3999 = ets:info(T,size), 0 = get_kept_objects(T), ets:delete(T), - T1 = ets_new(x,[ordered_set | Opts]), - filltabint(T1,4000), - del_one_by_one_set(T1,1,4001), - filltabint(T1,4000), - del_one_by_one_set(T1,4000,0), - ets:delete(T1), + run_if_valid_opts( + [ordered_set | Opts], + fun (Opts1) -> + T1 = ets_new(x, Opts1), + filltabint(T1,4000), + del_one_by_one_set(T1,1,4001), + filltabint(T1,4000), + del_one_by_one_set(T1,4000,0), + ets:delete(T1) + end), T2 = ets_new(x,[bag | Opts]), filltabint2(T2,4000), del_one_by_one_bag(T2,1,4001), @@ -1456,6 +1561,32 @@ t_insert_list_kill_process_do(Opts) -> fun ets:insert_new/2]], ok. +t_insert_list_insert_order_preserved(Config) when is_list(Config) -> + insert_list_insert_order_preserved(bag), + insert_list_insert_order_preserved(duplicate_bag), + ok. + +insert_list_insert_order_preserved(Type) -> + Tab = ets:new(?FUNCTION_NAME, [Type]), + K = a, + Values1 = [{K, 1}, {K, 2}, {K, 3}], + Values2 = [{K, 4}, {K, 5}, {K, 6}], + ets:insert(Tab, Values1), + ets:insert(Tab, Values2), + [{K, 1}, {K, 2}, {K, 3}, {K, 4}, {K, 5}, {K, 6}] = ets:lookup(Tab, K), + + ets:delete(Tab, K), + [] = ets:lookup(Tab, K), + + %% Insert order in duplicate_bag depended on reductions left + ITERATIONS_PER_RED = 8, + NTuples = 4000 * ITERATIONS_PER_RED + 10, + LongList = [{K, V} || V <- lists:seq(1, NTuples)], + ets:insert(Tab, LongList), + LongList = ets:lookup(Tab, K), + + ets:delete(Tab). + %% Test interface of ets:test_ms/2. t_test_ms(Config) when is_list(Config) -> EtsMem = etsmem(), @@ -1911,7 +2042,7 @@ t_select_replace_next_bug(Config) when is_list(Config) -> %% OTP-17379 -t_select_pam_stack_overflow_bug(Config) -> +t_select_pam_stack_overflow_bug(_Config) -> T = ets:new(k, []), ets:insert(T,[{x,17}]), [{x,18}] = ets:select(T,[{{x,17}, [], [{{{element,1,'$_'},{const,18}}}]}]), @@ -2312,11 +2443,16 @@ update_element_opts(Opts) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) -> Set = ets_new(set,[{keypos,KeyPos} | Opts]), - OrdSet = ets_new(ordered_set,[ordered_set,{keypos,KeyPos} | Opts]), update_element(Set,Tuple,KeyPos,UpdPos), - update_element(OrdSet,Tuple,KeyPos,UpdPos), true = ets:delete(Set), - true = ets:delete(OrdSet), + + run_if_valid_opts( + [ordered_set,{keypos,KeyPos} | Opts], + fun (OptsOrdSet) -> + OrdSet = ets_new(ordered_set, OptsOrdSet), + update_element(OrdSet,Tuple,KeyPos,UpdPos), + true = ets:delete(OrdSet) + end), ok. update_element(T,Tuple,KeyPos,UpdPos) -> @@ -2337,13 +2473,19 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> Big32 = 16#12345678, Big64 = 16#123456789abcdef0, - Values = { 623, -27, 0, Big32, -Big32, Big64, -Big64, Big32*Big32, + RefcBin = list_to_binary(lists:seq(1,100)), + BigMap1 = maps:from_list([{N,N} || N <- lists:seq(1,33)]), + BigMap2 = BigMap1#{key => RefcBin, RefcBin => value}, + Values = { 623, -27, Big32, -Big32, Big64, -Big64, Big32*Big32, -Big32*Big32, Big32*Big64, -Big32*Big64, Big64*Big64, -Big64*Big64, "A", "Sverker", [], {12,-132}, {}, - <<45,232,0,12,133>>, <<234,12,23>>, list_to_binary(lists:seq(1,100)), + <<45,232,0,12,133>>, <<234,12,23>>, RefcBin, (fun(X) -> X*Big32 end), - make_ref(), make_ref(), self(), ok, update_element, 28, 29 }, - Length = size(Values), + make_ref(), make_ref(), self(), ok, update_element, + #{a => value, "hello" => "world", 1.0 => RefcBin }, + BigMap1, BigMap2}, + Length = tuple_size(Values), + 29 = Length, PosValArgF = fun(ToIx, ResList, [Pos | PosTail], Rand, MeF) -> NextIx = (ToIx+Rand) rem Length, @@ -2363,7 +2505,12 @@ update_element_do(Tab,Tuple,Key,UpdPos) -> true = ets:update_element(Tab, Key, PosValArg), ArgHash = erlang:phash2({Tab,Key,PosValArg}), NewTuple = update_tuple(PosValArg,Tuple), - [NewTuple] = ets:lookup(Tab,Key) + [NewTuple] = ets:lookup(Tab,Key), + [begin + Elem = element(I, NewTuple), + Elem = ets:lookup_element(Tab, Key, I) + end + || I <- lists:seq(1, tuple_size(NewTuple))] end, LoopF = fun(_FromIx, Incr, _Times, Checksum, _MeF) when Incr >= Length -> @@ -2401,13 +2548,18 @@ update_tuple([], Tpl) -> update_element_neg(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_element_neg_do(Set), - update_element_neg_do(OrdSet), ets:delete(Set), {'EXIT',{badarg,_}} = (catch ets:update_element(Set,key,{2,1})), - ets:delete(OrdSet), - {'EXIT',{badarg,_}} = (catch ets:update_element(OrdSet,key,{2,1})), + + run_if_valid_opts( + [ordered_set | Opts], + fun(OptsOrdSet) -> + OrdSet = ets_new(ordered_set, OptsOrdSet), + update_element_neg_do(OrdSet), + ets:delete(OrdSet), + {'EXIT',{badarg,_}} = (catch ets:update_element(OrdSet,key,{2,1})) + end), Bag = ets_new(bag,[bag | Opts]), DBag = ets_new(duplicate_bag,[duplicate_bag | Opts]), @@ -2458,19 +2610,25 @@ update_counter(Config) when is_list(Config) -> update_counter_do(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_counter_for(Set), - update_counter_for(OrdSet), ets:delete_all_objects(Set), - ets:delete_all_objects(OrdSet), ets:safe_fixtable(Set, true), - ets:safe_fixtable(OrdSet, true), update_counter_for(Set), - update_counter_for(OrdSet), ets:safe_fixtable(Set, false), - ets:safe_fixtable(OrdSet, false), ets:delete(Set), - ets:delete(OrdSet), + + run_if_valid_opts( + [ordered_set | Opts], + fun (OptsOrdSet) -> + OrdSet = ets_new(ordered_set, OptsOrdSet), + update_counter_for(OrdSet), + ets:delete_all_objects(OrdSet), + ets:safe_fixtable(OrdSet, true), + update_counter_for(OrdSet), + ets:safe_fixtable(OrdSet, false), + ets:delete(OrdSet) + end), + update_counter_neg(Opts). update_counter_for(T) -> @@ -2618,13 +2776,18 @@ uc_adder(Init, {_Pos, Add, Thres, Warp}) -> update_counter_neg(Opts) -> Set = ets_new(set,Opts), - OrdSet = ets_new(ordered_set,[ordered_set | Opts]), update_counter_neg_for(Set), - update_counter_neg_for(OrdSet), ets:delete(Set), {'EXIT',{badarg,_}} = (catch ets:update_counter(Set,key,1)), - ets:delete(OrdSet), - {'EXIT',{badarg,_}} = (catch ets:update_counter(OrdSet,key,1)), + + run_if_valid_opts( + [ordered_set | Opts], + fun (OptsOrdSet) -> + OrdSet = ets_new(ordered_set, OptsOrdSet), + update_counter_neg_for(OrdSet), + ets:delete(OrdSet), + {'EXIT',{badarg,_}} = (catch ets:update_counter(OrdSet,key,1)) + end), Bag = ets_new(bag,[bag | Opts]), DBag = ets_new(duplicate_bag,[duplicate_bag | Opts]), @@ -2749,39 +2912,43 @@ update_counter_with_default_do(Opts) -> 2 = ets:info(T1, size), %% Same with ordered set. - T2 = ets_new(b, [ordered_set | Opts]), - 3 = ets:update_counter(T2, foo, 2, {maroilles,1}), - 1 = ets:info(T2, size), - 5 = ets:update_counter(T2, foo, 2, {mimolette,1}), - 1 = ets:info(T2, size), - [9] = ets:update_counter(T2, foo, [{2,4}], {morbier,1}), - 1 = ets:info(T2, size), - 3 = ets:update_counter(T2, {foo,bar}, 2, {{laguiole},1}), - 2 = ets:info(T2, size), - 5 = ets:update_counter(T2, {foo,bar}, 2, {{saint,nectaire},1}), - 2 = ets:info(T2, size), - [9] = ets:update_counter(T2, {foo,bar}, [{2,4}], {{rocamadour},1}), - 2 = ets:info(T2, size), - %% Arithmetically-equal keys. - 3 = ets:update_counter(T2, 1.0, 2, {1,1}), - 3 = ets:info(T2, size), - 5 = ets:update_counter(T2, 1, 2, {1,1}), - 3 = ets:info(T2, size), - 7 = ets:update_counter(T2, 1, 2, {1.0,1}), - 3 = ets:info(T2, size), - %% Same with reversed type difference. - 3 = ets:update_counter(T2, 2, 2, {2.0,1}), - 4 = ets:info(T2, size), - 5 = ets:update_counter(T2, 2.0, 2, {2.0,1}), - 4 = ets:info(T2, size), - 7 = ets:update_counter(T2, 2.0, 2, {2,1}), - 4 = ets:info(T2, size), - %% default counter is not an integer. - {'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, 3, {saint,félicien})), - 4 = ets:info(T2, size), - %% No third element in default value. - {'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, [{3,1}], {roquefort,1})), - 4 = ets:info(T2, size), + run_if_valid_opts( + [ordered_set | Opts], + fun (Opts2) -> + T2 = ets_new(b, Opts2), + 3 = ets:update_counter(T2, foo, 2, {maroilles,1}), + 1 = ets:info(T2, size), + 5 = ets:update_counter(T2, foo, 2, {mimolette,1}), + 1 = ets:info(T2, size), + [9] = ets:update_counter(T2, foo, [{2,4}], {morbier,1}), + 1 = ets:info(T2, size), + 3 = ets:update_counter(T2, {foo,bar}, 2, {{laguiole},1}), + 2 = ets:info(T2, size), + 5 = ets:update_counter(T2, {foo,bar}, 2, {{saint,nectaire},1}), + 2 = ets:info(T2, size), + [9] = ets:update_counter(T2, {foo,bar}, [{2,4}], {{rocamadour},1}), + 2 = ets:info(T2, size), + %% Arithmetically-equal keys. + 3 = ets:update_counter(T2, 1.0, 2, {1,1}), + 3 = ets:info(T2, size), + 5 = ets:update_counter(T2, 1, 2, {1,1}), + 3 = ets:info(T2, size), + 7 = ets:update_counter(T2, 1, 2, {1.0,1}), + 3 = ets:info(T2, size), + %% Same with reversed type difference. + 3 = ets:update_counter(T2, 2, 2, {2.0,1}), + 4 = ets:info(T2, size), + 5 = ets:update_counter(T2, 2.0, 2, {2.0,1}), + 4 = ets:info(T2, size), + 7 = ets:update_counter(T2, 2.0, 2, {2,1}), + 4 = ets:info(T2, size), + %% default counter is not an integer. + {'EXIT',{badarg,_}} = (catch ets:update_counter(T2, qux, 3, {saint,félicien})), + 4 = ets:info(T2, size), + %% No third element in default value. + {'EXIT',{badarg,_}} = (catch ets:update_counter(T2, qux, [{3,1}], {roquefort,1})), + 4 = ets:info(T2, size) + end), ok. %% ERL-1125 @@ -2805,8 +2972,14 @@ update_counter_table_growth(_Config) -> update_counter_table_growth_do(Opts) -> Set = ets_new(b, [set | Opts]), [ets:update_counter(Set, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], - OrderedSet = ets_new(b, [ordered_set | Opts]), - [ets:update_counter(OrderedSet, N, {2, 1}, {N, 1}) || N <- lists:seq(1,10000)], + + run_if_valid_opts( + [ordered_set | Opts], + fun(OptsOrdSet) -> + OrdSet = ets_new(b, OptsOrdSet), + [ets:update_counter(OrdSet, N, {2, 1}, {N, 1}) + || N <- lists:seq(1,10000)] + end), ok. %% Check that a first-next sequence always works on a fixed table. @@ -3059,8 +3232,9 @@ write_concurrency(Config) when is_list(Config) -> YesTreeMem = ets:info(Yes7,memory), YesYesTreeMem = ets:info(Yes14,memory), NoTreeMem = ets:info(No4,memory), - io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p YesTreeMem=~p\n",[YesMem,NoHashMem, - NoTreeMem,YesTreeMem]), + + io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p YesTreeMem=~p YesYesTreeMem=~p\n", + [YesMem,NoHashMem,NoTreeMem,YesTreeMem,YesYesTreeMem]), YesMem = ets:info(Yes2,memory), YesMem = ets:info(Yes3,memory), @@ -3085,14 +3259,26 @@ write_concurrency(Config) when is_list(Config) -> true = YesMem > YesTreeMem, - case erlang:system_info(schedulers) > 1 of - true -> + case erlang:system_info(schedulers) of + 1 -> + YesMem = NoHashMem, + YesTreeMem = NoTreeMem, + YesYesTreeMem = YesTreeMem; + NoSchedulers -> true = YesMem > NoHashMem, true = YesMem > NoTreeMem, - true = YesTreeMem < NoTreeMem, - true = YesYesTreeMem > YesTreeMem; - _ -> - one_scheduler_only + + %% The memory of ordered_set with write concurrency is + %% smaller than without write concurrency on 64-bit systems with + %% few schedulers. + Bits = 8*erlang:system_info(wordsize), + if Bits =:= 32; + NoSchedulers > 6 -> + true = YesTreeMem >= NoTreeMem; + true -> + true = YesTreeMem < NoTreeMem + end, + true = YesYesTreeMem > YesTreeMem end, {'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency,foo}])), @@ -3576,7 +3762,8 @@ interface_equality(Config) when is_list(Config) -> interface_equality_do(Opts) -> EtsMem = etsmem(), Set = ets_new(set,[set | Opts]), - OrderedSet = ets_new(ordered_set,[ordered_set | Opts]), + OrderedSet = ets_new(ordered_set, + replace_dbg_hash_fixed_nr_of_locks([ordered_set | Opts])), F = fun(X,T,FF) -> case X of 0 -> true; _ -> @@ -3635,7 +3822,7 @@ maybe_sort(Any) -> %% Test match, match_object and match_delete in ordered set's. ordered_match(Config) when is_list(Config)-> - repeat_for_opts(fun ordered_match_do/1). + repeat_for_opts_extra_opt(fun ordered_match_do/1, ordered_set). ordered_match_do(Opts) -> EtsMem = etsmem(), @@ -3681,7 +3868,7 @@ ordered_match_do(Opts) -> %% Test basic functionality in ordered_set's. ordered(Config) when is_list(Config) -> - repeat_for_opts(fun ordered_do/1). + repeat_for_opts_extra_opt(fun ordered_do/1, ordered_set). ordered_do(Opts) -> EtsMem = etsmem(), @@ -4032,6 +4219,41 @@ fill_tab(Tab,Val) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +lookup_element_default(Config) when is_list(Config) -> + EtsMem = etsmem(), + + TabSet = ets_new(foo, [set]), + ets:insert(TabSet, {key, 42}), + 42 = ets:lookup_element(TabSet, key, 2, 13), + 13 = ets:lookup_element(TabSet, not_key, 2, 13), + {'EXIT',{badarg,_}} = catch ets:lookup_element(TabSet, key, 3, 13), + true = ets:delete(TabSet), + + TabOrderedSet = ets_new(foo, [ordered_set]), + ets:insert(TabOrderedSet, {key, 42}), + 42 = ets:lookup_element(TabOrderedSet, key, 2, 13), + 13 = ets:lookup_element(TabOrderedSet, not_key, 2, 13), + {'EXIT',{badarg,_}} = catch ets:lookup_element(TabOrderedSet, key, 3, 13), + true = ets:delete(TabOrderedSet), + + TabBag = ets_new(foo, [bag]), + ets:insert(TabBag, {key, 42}), + ets:insert(TabBag, {key, 43, 44}), + [42, 43] = ets:lookup_element(TabBag, key, 2, 13), + 13 = ets:lookup_element(TabBag, not_key, 2, 13), + {'EXIT',{badarg,_}} = catch ets:lookup_element(TabBag, key, 3, 13), + true = ets:delete(TabBag), + + TabDuplicateBag = ets_new(foo, [duplicate_bag]), + ets:insert(TabDuplicateBag, {key, 42}), + ets:insert(TabDuplicateBag, {key, 42}), + ets:insert(TabDuplicateBag, {key, 43, 44}), + [42, 42, 43] = ets:lookup_element(TabDuplicateBag, key, 2, 13), + 13 = ets:lookup_element(TabDuplicateBag, not_key, 2, 13), + {'EXIT',{badarg,_}} = catch ets:lookup_element(TabDuplicateBag, key, 3, 13), + true = ets:delete(TabDuplicateBag), + + verify_etsmem(EtsMem). %% OTP-2386. Multiple return elements. lookup_element_mult(Config) when is_list(Config) -> @@ -4118,8 +4340,16 @@ delete_large_tab(Config) when is_list(Config) -> delete_large_tab_do(Config, Opts,Data) -> delete_large_tab_1(Config, foo_hash, Opts, Data, false), - delete_large_tab_1(Config, foo_tree, [ordered_set | Opts], Data, false), - delete_large_tab_1(Config, foo_tree, [stim_cat_ord_set | Opts], Data, false), + run_if_valid_opts( + [ordered_set | Opts], + fun(OptsOrdSet) -> + delete_large_tab_1(Config, foo_tree, OptsOrdSet, Data, false) + end), + run_if_valid_opts( + [stim_cat_ord_set | Opts], + fun(OptsCat) -> + delete_large_tab_1(Config, foo_tree, OptsCat, Data, false) + end), delete_large_tab_1(Config, foo_hash_fix, Opts, Data, true). @@ -4208,8 +4438,16 @@ delete_large_named_table(Config) when is_list(Config) -> delete_large_named_table_do(Opts,Data) -> delete_large_named_table_1(foo_hash, [named_table | Opts], Data, false), - delete_large_named_table_1(foo_tree, [ordered_set,named_table | Opts], Data, false), - delete_large_named_table_1(foo_tree, [stim_cat_ord_set,named_table | Opts], Data, false), + run_if_valid_opts( + [ordered_set,named_table | Opts], + fun(OptsOrdSet) -> + delete_large_named_table_1(foo_tree, OptsOrdSet, Data, false) + end), + run_if_valid_opts( + [stim_cat_ord_set,named_table | Opts], + fun(OptsStimCat) -> + delete_large_named_table_1(foo_tree, OptsStimCat, Data, false) + end), delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true). delete_large_named_table_1(Name, Flags, Data, Fix) -> @@ -4381,15 +4619,39 @@ exit_many_tables_owner(Config) when is_list(Config) -> exit_many_many_tables_owner(Config) when is_list(Config) -> Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 50)], FEData = fun(Do) -> lists:foreach(Do, Data) end, - repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,FEData,Config) end). + repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do1(Opts,FEData,Config) end). -exit_many_many_tables_owner_do(Opts,FEData,Config) -> - verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, 200, 5), - verify_rescheduling_exit(Config, FEData, Opts, false, 200, 5), +exit_many_many_tables_owner_do1(Opts,FEData,Config) -> + case has_fixed_number_of_locks(Opts) of + true -> + %% Few memory hogging tables => not enough yielding for the test + io:format("Skip option combo ~p\n", [Opts]); + false -> + exit_many_many_tables_owner_do2(Opts,FEData,Config) + end. + +exit_many_many_tables_owner_do2(Opts,FEData,Config) -> + E = ets_new(tmp,Opts), + FEData(fun(Data) -> ets:insert(E, Data) end), + Mem = ets:info(E,memory) * erlang:system_info(wordsize), + ets:delete(E), + + ct:log("Memory per table: ~p bytes",[Mem]), + + Tables = + case erlang:system_info(wordsize) of + 8 -> + 200; + 4 -> + lists:min([200,2_000_000_000 div (Mem * 5)]) + end, + + verify_rescheduling_exit(Config, FEData, [named_table | Opts], true, Tables, 5), + verify_rescheduling_exit(Config, FEData, Opts, false, Tables, 5), wait_for_test_procs(), EtsMem = etsmem(), - verify_rescheduling_exit(Config, FEData, Opts, true, 200, 5), - verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, 200, 5), + verify_rescheduling_exit(Config, FEData, Opts, true, Tables, 5), + verify_rescheduling_exit(Config, FEData, [named_table | Opts], false, Tables, 5), verify_etsmem(EtsMem). @@ -4954,6 +5216,44 @@ info(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch ets:info(make_ref())), {'EXIT',{badarg,_}} = (catch ets:info(make_ref(), type)), + case erlang:system_info(schedulers) of + 1 -> %% Fine grained locking is not activated when there is only one scheduler + lists:foreach( + fun(Type) -> + T1 = ets:new(t1, [public, Type, {write_concurrency, auto}]), + false = ets:info(T1, write_concurrency), + T2 = ets:new(t2, [public, Type, {write_concurrency, true}]), + false = ets:info(T2, write_concurrency) + end, + [set, bag, duplicate_bag, ordered_set]), + T2 = ets:new(t2, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2049}}]), + false = ets:info(T2, write_concurrency); + _ -> + %% Test that one can set the synchronization granularity level for + %% tables of type set + T1 = ets:new(t1, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}]), + {debug_hash_fixed_number_of_locks, 1024} = ets:info(T1, write_concurrency), + T2 = ets:new(t2, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2048}}]), + {debug_hash_fixed_number_of_locks, 2048} = ets:info(T2, write_concurrency), + T3 = ets:new(t3, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}, {write_concurrency, true}]), + true = ets:info(T3, write_concurrency), + T4 = ets:new(t4, [private, {write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}]), + false = ets:info(T4, write_concurrency), + %% Test the auto option + lists:foreach( + fun(Type) -> + T5 = ets:new(t5, [public, Type, {write_concurrency, auto}]), + auto = ets:info(T5, write_concurrency) + end, + [set, bag, duplicate_bag, ordered_set]), + T6 = ets:new(t6, [private, {write_concurrency, true}]), + false = ets:info(T6, write_concurrency), + T7 = ets:new(t7, [private, {write_concurrency, auto}]), + false = ets:info(T7, write_concurrency), + %% Test that the number of locks is rounded down to the nearest power of two + T8 = ets:new(t8, [public, {write_concurrency, {debug_hash_fixed_number_of_locks, 2049}}]), + {debug_hash_fixed_number_of_locks, 2048} = ets:info(T8, write_concurrency) + end, ok. info_do(Opts) -> @@ -5019,7 +5319,6 @@ info_do(Opts) -> {value, {id, Tab}} = lists:keysearch(id, 1, Res), {value, {decentralized_counters, _DecentralizedCtrs}} = lists:keysearch(decentralized_counters, 1, Res), - %% Test 'binary' [] = ?ets_info(Tab, binary, SlavePid), BinSz = 100, @@ -5044,7 +5343,6 @@ info_do(Opts) -> unlink(SlavePid), exit(SlavePid,kill), - true = ets:delete(Tab), verify_etsmem(EtsMem). @@ -5203,22 +5501,208 @@ info_whereis_busy(Config) when is_list(Config) -> ets:delete(T), ok. +%% Delete table during trapping ets:insert +insert_trap_delete(Config) when is_list(Config) -> + repeat_for_opts(fun(Opts) -> + [insert_trap_delete_run1({Opts,InsertFunc,Mode}) + || InsertFunc <- [insert,insert_new], + Mode <- [exit, delete]] + end, + [all_non_stim_types, write_concurrency, compressed]), + ok. + +insert_trap_delete_run1(Params) -> + NKeys = 50_000 + rand:uniform(50_000), + %% First measure how many traps the insert op will do + Traps0 = insert_trap_delete_run3(unlimited, Params, NKeys), + %% Then do again and delete table at different moments + Decr = (Traps0 div 5) + 1, + insert_trap_delete_run2(Traps0-1, Decr, Params, NKeys). + +insert_trap_delete_run2(Traps, _Decr, Params, NKeys) when Traps =< 1 -> + insert_trap_delete_run3(1, Params, NKeys), + ok; +insert_trap_delete_run2(Traps, Decr, Params, NKeys) -> + insert_trap_delete_run3(Traps, Params, NKeys), + insert_trap_delete_run2(Traps - Decr, Decr, Params, NKeys). + +insert_trap_delete_run3(Traps, {Opts, InsertFunc, Mode}, NKeys) -> + io:format("insert_trap_delete_run(~p, ~p, ~p) NKeys=~p\n", + [Traps, InsertFunc, Mode, NKeys]), + TabName = insert_trap_delete, + Tester = self(), + Tuples = [{K} || K <- lists:seq(1,NKeys)], + + OwnerFun = + fun() -> + erlang:trace(Tester, true, [running]), + ets_new(TabName, [named_table, public | Opts]), + Tester ! {ets_new, ets:whereis(TabName)}, + io:format("Wait for ets:~p/2 to yield...\n", [InsertFunc]), + GotTraps = repeat_while( + fun(N) -> + case receive_any() of + {trace, Tester, out, {ets,InsertFunc,2}} -> + case N of + Traps -> {false, Traps}; + _ -> {true, N+1} + end; + "Insert done" -> + io:format("Too late! Got ~p traps\n", [N]), + {false, N}; + _M -> + %%io:format("[~p] Ignored msg: ~p\n", [N,_M]), + {true, N} + end + end, + 0), + case Mode of + delete -> + io:format("Delete table and then exit...\n",[]), + ets:delete(TabName); + exit -> + io:format("Exit and let table die...\n",[]) + end, + Tester ! {traps, GotTraps} + end, + {Owner, Mon} = spawn_opt(OwnerFun, [link, monitor]), + + {ets_new, Tid} = receive_any(), + try ets:InsertFunc(TabName, Tuples) of + true -> + try ets:lookup(Tid, NKeys) of + [{NKeys}] -> ok + catch + error:badarg -> + %% Table must been deleted just after insert finished + undefined = ets:info(Tid, id), + undefined = ets:whereis(TabName) + end, + Owner ! "Insert done" + catch + error:badarg -> + %% Insert failed, table must have been deleted + undefined = ets:info(Tid, id), + undefined = ets:whereis(TabName) + end, + {traps, GotTraps} = receive_any(), + {'DOWN', Mon, process, Owner, _} = receive_any(), + undefined = ets:whereis(TabName), + undefined = ets:info(Tid, id), + GotTraps. + +%% Rename table during trapping ets:insert +insert_trap_rename(Config) when is_list(Config) -> + repeat_for_opts(fun(Opts) -> + [insert_trap_rename_run1(Opts, InsertFunc) + || InsertFunc <- [insert, insert_new]] + end, + [all_non_stim_types, write_concurrency, compressed]), + ok. + +insert_trap_rename_run1(Opts, InsertFunc) -> + NKeys = 50_000 + rand:uniform(50_000), + %% First measure how many traps the insert op will do + Traps0 = insert_trap_rename_run3(Opts, unlimited, InsertFunc, NKeys), + %% Then do again and rename table at different moments + Decr = (Traps0 div 5) + 1, + insert_trap_rename_run2(Opts, Traps0-1, Decr, InsertFunc, NKeys), + ok. + +insert_trap_rename_run2(Opts, Traps, _Decr, InsertFunc, NKeys) when Traps =< 1 -> + insert_trap_rename_run3(Opts, 1, InsertFunc, NKeys), + ok; +insert_trap_rename_run2(Opts, Traps, Decr, InsertFunc, NKeys) -> + insert_trap_rename_run3(Opts, Traps, InsertFunc, NKeys), + insert_trap_rename_run2(Opts, Traps - Decr, Decr, InsertFunc, NKeys). + + +insert_trap_rename_run3(Opts, Traps, InsertFunc, NKeys) -> + io:format("insert_trap_rename_run(~p, ~p)\n", [Traps, InsertFunc]), + TabName = insert_trap_rename, + TabRenamed = insert_trap_rename_X, + Tester = self(), + Tuples = [{K} || K <- lists:seq(1,NKeys)], + + OwnerFun = + fun() -> + erlang:trace(Tester, true, [running]), + ets_new(TabName, [named_table, public | Opts]), + Tester ! {ets_new, ets:whereis(TabName)}, + io:format("Wait for ets:~p/2 to yield...\n", [InsertFunc]), + GotTraps = repeat_while( + fun(N) -> + case receive_any() of + {trace, Tester, out, {ets,InsertFunc,2}} -> + case N of + Traps -> {false, ok}; + _ -> {true, N+1} + end; + "Insert done" -> + io:format("Too late! Got ~p traps\n", [N]), + {false, N}; + _M -> + %%io:format("[~p] Ignored msg: ~p\n", [N,_M]), + {true, N} + end + end, + 0), + io:format("Rename table and wait...\n",[]), + ets:rename(TabName, TabRenamed), + ets:delete(TabRenamed, 42), + Tester ! {renamed, GotTraps}, + receive die -> ok end + end, + {Owner, Mon} = spawn_opt(OwnerFun, [link,monitor]), + + {ets_new, Tid} = receive_any(), + try ets:InsertFunc(TabName, Tuples) of + true -> + io:format("ets:~p succeeded\n", [InsertFunc]), + true = ets:member(Tid, 1), + true = ets:member(Tid, NKeys) + catch + error:badarg -> + io:format("ets:~p failed\n", [InsertFunc]), + false = ets:member(Tid, 1), + false = ets:member(Tid, NKeys) + end, + Owner ! "Insert done", + {renamed, GotTraps} = receive_any(), + [] = ets:lookup(Tid, 42), + undefined = ets:whereis(TabName), + Tid = ets:whereis(TabRenamed), + Owner ! die, + {'DOWN', Mon, process, Owner, _} = receive_any(), + undefined = ets:whereis(TabName), + undefined = ets:whereis(TabRenamed), + GotTraps. + + test_table_size_concurrency(Config) when is_list(Config) -> case erlang:system_info(schedulers) of 1 -> {skip,"Only valid on smp > 1 systems"}; _ -> - BaseOptions = [public, {write_concurrency, true}], - test_table_counter_concurrency(size, [set | BaseOptions]), - test_table_counter_concurrency(size, [ordered_set | BaseOptions]) + lists:foreach( + fun(WriteConcurrencyOpt) -> + BaseOptions = [public, {write_concurrency, WriteConcurrencyOpt}], + test_table_counter_concurrency(size, [set | BaseOptions]), + test_table_counter_concurrency(size, [ordered_set | BaseOptions]) + end, + [true, auto]) end. test_table_memory_concurrency(Config) when is_list(Config) -> case erlang:system_info(schedulers) of 1 -> {skip,"Only valid on smp > 1 systems"}; _ -> - BaseOptions = [public, {write_concurrency, true}], - test_table_counter_concurrency(memory, [set | BaseOptions]), - test_table_counter_concurrency(memory, [ordered_set | BaseOptions]) + lists:foreach( + fun(WriteConcurrencyOpt) -> + BaseOptions = [public, {write_concurrency, WriteConcurrencyOpt}], + test_table_counter_concurrency(memory, [set | BaseOptions]), + test_table_counter_concurrency(memory, [ordered_set | BaseOptions]) + end, + [true, auto]) end. %% Tests that calling the ets:delete operation on a table T with @@ -5228,13 +5712,13 @@ test_delete_table_while_size_snapshot(Config) when is_list(Config) -> %% Run test case in a slave node as other test suites in stdlib %% depend on that pids are ordered in creation order which is no %% longer the case when many processes have been started before - Node = start_slave(), + {ok, Peer, Node} = ?CT_PEER(), [ok = rpc:call(Node, ?MODULE, test_delete_table_while_size_snapshot_helper, [TableType]) || TableType <- [set, ordered_set]], - test_server:stop_node(Node), + peer:stop(Peer), ok. test_delete_table_while_size_snapshot_helper(TableType) -> @@ -5271,13 +5755,6 @@ size_process(Table, Parent) -> E -> Parent ! {got_unexpected_exception, E} end. -start_slave() -> - MicroSecs = erlang:monotonic_time(), - Name = "ets_" ++ integer_to_list(MicroSecs), - Pa = filename:dirname(code:which(?MODULE)), - {ok, Node} = test_server:start_node(list_to_atom(Name), slave, [{args, "-pa " ++ Pa}]), - Node. - repeat_par(FunToRepeat, NrOfTimes) -> repeat_par_help(FunToRepeat, NrOfTimes, NrOfTimes). @@ -5308,25 +5785,42 @@ test_decentralized_counters_setting(Config) when is_list(Config) -> do_test_decentralized_counters_setting(TableType) -> wait_for_memory_deallocations(), FlxCtrMemUsage = erts_debug:get_internal_state(flxctr_memory_usage), + FixOptsList = + fun(Opts) -> + case TableType of + ordered_set -> + replace_dbg_hash_fixed_nr_of_locks(Opts); + set -> + Opts + end + end, lists:foreach( fun(OptList) -> - T1 = ets:new(t1, [public, TableType] ++ OptList ++ [TableType]), + T1 = ets:new(t1, FixOptsList([public, TableType] ++ OptList ++ [TableType])), check_decentralized_counters(T1, false, FlxCtrMemUsage), ets:delete(T1) end, - [[{write_concurrency, false}], - [{write_concurrency, true}, {decentralized_counters, false}]]), + [[{write_concurrency, false}]] ++ + case TableType of + set -> + [[{write_concurrency, true}, {decentralized_counters, false}], + [{write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}, {write_concurrency, true}]]; + ordered_set -> [] + end), lists:foreach( fun(OptList) -> - T1 = ets:new(t1, [public, - TableType, - {write_concurrency, true}] ++ OptList ++ [TableType]), + T1 = ets:new(t1, + FixOptsList([public, + TableType, + {write_concurrency, true}] ++ OptList ++ [TableType])), check_decentralized_counters(T1, true, FlxCtrMemUsage), ets:delete(T1), wait_for_memory_deallocations(), FlxCtrMemUsage = erts_debug:get_internal_state(flxctr_memory_usage) end, - [[{decentralized_counters, true}]]), + [[{decentralized_counters, true}], + [{write_concurrency, {debug_hash_fixed_number_of_locks, 1024}}], + [{write_concurrency, auto}]]), ok. do_test_decentralized_counters_default_setting() -> @@ -6118,7 +6612,8 @@ xfilltabstr(Tab,N) -> fill_sets_int(N) -> fill_sets_int(N,[]). fill_sets_int(N,Opts) -> - Tab1 = ets_new(xxx, [ordered_set|Opts]), + Tab1 = ets_new(xxx, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), filltabint(Tab1,N), Tab2 = ets_new(xxx, [set|Opts]), filltabint(Tab2,N), @@ -6129,7 +6624,8 @@ fill_sets_int(N,Opts) -> [Tab1,Tab2,Tab3,Tab4]. fill_sets_intup(N,Opts) -> - Tab1 = ets_new(xxx, [ordered_set|Opts]), + Tab1 = ets_new(xxx, + replace_dbg_hash_fixed_nr_of_locks([ordered_set|Opts])), filltabintup(Tab1,N), Tab2 = ets_new(xxx, [set|Opts]), filltabintup(Tab2,N), @@ -7000,7 +7496,7 @@ verify_table_load(T) -> ordered_set -> ok; _ -> Stats = ets:info(T,stats), - {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats, + {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_,_} = Stats, ok = if AvgLen > 1.2 -> io:format("Table overloaded: Stats=~p\n~p\n", @@ -7370,6 +7866,28 @@ otp_10182(Config) when is_list(Config) -> In = Out end). +%% Verify magic refs in compressed table are reference counted correctly +compress_magic_ref(Config) when is_list(Config)-> + F = fun(Opts) -> + T = ets:new(banana, Opts), + ets:insert(T, {key, atomics:new(2, [])}), + erlang:garbage_collect(), % make really sure no ref on heap + [{_, Ref}] = ets:lookup(T, key), + #{size := 2} = atomics:info(Ref), % Still alive! + + %% Now test ets:delete will deallocate if last ref + WeakRef = term_to_binary(Ref), + erlang:garbage_collect(), % make sure no Ref on heap + ets:delete(T, key), + StaleRef = binary_to_term(WeakRef), + badarg = try atomics:info(StaleRef) + catch error:badarg -> badarg end, + ets:delete(T), + ok + end, + repeat_for_opts(F, [[set, ordered_set], compressed]), + ok. + %% Test that ets:all include/exclude tables that we know are created/deleted ets_all(Config) when is_list(Config) -> Pids = [spawn_link(fun() -> ets_all_run() end) || _ <- [1,2]], @@ -7496,9 +8014,15 @@ whereis_table(Config) when is_list(Config) -> Tid = ets:whereis(whereis_test), ets:insert(whereis_test, [{hello}, {there}]), - - [[{hello}],[{there}]] = ets:match(whereis_test, '$1'), - [[{hello}],[{there}]] = ets:match(Tid, '$1'), + CheckMatch = + fun(MatchRes) -> + case MatchRes of + [[{there}],[{hello}]] -> ok; + [[{hello}],[{there}]] -> ok + end + end, + CheckMatch(ets:match(whereis_test, '$1')), + CheckMatch(ets:match(Tid, '$1')), true = ets:delete_all_objects(Tid), @@ -7764,7 +8288,9 @@ prefill_insert_map_loop(T, RS0, N, ObjFun, InsertMap, NrOfSchedulers) -> [set, public], [set, public, {write_concurrency, true}], [set, public, {read_concurrency, true}], - [set, public, {write_concurrency, true}, {read_concurrency, true}] + [set, public, {write_concurrency, true}, {read_concurrency, true}], + [set, public, {write_concurrency, auto}, {read_concurrency, true}], + [set, public, {write_concurrency, {debug_hash_fixed_number_of_locks, 16384}}] ], etsmem_fun = fun() -> ok end, verify_etsmem_fun = fun(_) -> true end, @@ -8129,10 +8655,15 @@ long_throughput_benchmark(Config) when is_list(Config) -> ] ], table_types = - [ - [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}], - [set, public, {write_concurrency, true}, {read_concurrency, true}] - ], + ([ + [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}], + [set, public, {write_concurrency, true}, {read_concurrency, true}] + ] ++ + case catch list_to_integer(erlang:system_info(otp_release)) of + Recent when is_integer(Recent), Recent >= 25 -> + [[set, public, {write_concurrency, auto}, {read_concurrency, true}]]; + _Old -> [] + end), etsmem_fun = fun etsmem/0, verify_etsmem_fun = fun verify_etsmem/1, notify_res_fun = @@ -8528,7 +9059,7 @@ repeat_for_permutations(Fun, List, N) -> receive_any() -> receive M -> - io:format("Process ~p got msg ~p\n", [self(),M]), + %%io:format("Process ~p got msg ~p\n", [self(),M]), M end. @@ -8725,6 +9256,7 @@ error_info(_Config) -> end), receive T -> T end end, + _ = ets:new(name_already_exists, [named_table]), L = [{delete, ['$Tab']}, {delete, ['$Tab', no_key], [no_fail]}, @@ -8766,6 +9298,8 @@ error_info(_Config) -> {insert, ['$Tab', [a|b]]}, {insert, ['$Tab', {a,b,c}], [no_fail]}, {insert, ['$Tab', [{a,b,c}]], [no_fail]}, + {insert, ['$Tab', [{a,b,c},{d,e,f}]], [no_fail]}, + {insert, ['$Tab', [{I,b,c} || I <- lists:seq(1,10_000)]], [no_fail]}, {insert_new, ['$Tab', bad_object]}, {insert_new, ['$Tab', {a,b,c}], [no_fail]}, @@ -8787,6 +9321,9 @@ error_info(_Config) -> {lookup_element, [OneKeyTab, one, 4]}, + {lookup_element, ['$Tab', no_key, 1, default_value], [no_fail]}, + {lookup_element, [OneKeyTab, one, 4, default_value]}, + {match, [bad_continuation], [no_table]}, {match, ['$Tab', <<1,2,3>>], [no_fail]}, @@ -8809,6 +9346,8 @@ error_info(_Config) -> {new, [name, [a|b]], [no_table]}, {new, [name, [a,b]], [no_table]}, {new, [{bad,name}, [a,b]], [no_table]}, + {new, [name_already_exists, [named_table]], [no_table, + {error_term,already_exists}]}, %% For a set, ets:next/2 and ets:prev/2 fails if the key does %% not exist. @@ -8924,7 +9463,7 @@ error_info(_Config) -> [] -> ok; [_|_]=Errors -> - io:format("~p\n", [Errors]), + io:format("~P\n", [Errors, 100]), ct:fail({length(Errors),errors}) end. @@ -8981,8 +9520,9 @@ ets_eval_bif_errors_once(F, Args, Opts) -> io:format("\n\n*** ets:~p/~p", [F,length(Args)]), NoFail = lists:member(no_fail, Opts), + ErrorTerm = proplists:get_value(error_term, Opts, none), case ets_apply(F, Args, Opts) of - {error,none} -> + {error,ErrorTerm} when not NoFail -> ok; {error,Info} -> store_error(wrong_failure_reason, MFA, Info); @@ -9149,7 +9689,7 @@ ets_apply(F, Args, Opts) -> end. ets_format_args(Args) -> - lists:join(", ", [io_lib:format("~p", [A]) || A <- Args]). + lists:join(", ", [io_lib:format("~P", [A,10]) || A <- Args]). %%% %%% Common utility functions. @@ -9300,8 +9840,30 @@ make_unaligned_sub_binary(Bin0) when is_binary(Bin0) -> make_unaligned_sub_binary(List) -> make_unaligned_sub_binary(list_to_binary(List)). +replace_dbg_hash_fixed_nr_of_locks(Opts) -> + [case X of + {write_concurrency, {debug_hash_fixed_number_of_locks, _}} -> + {write_concurrency, true}; + _ -> X + end || X <- Opts]. + %% Repeat test function with different combination of table options -%% +%% +repeat_for_opts_extra_opt(F, Extra) -> + repeat_for_opts( + fun(Opts) -> + WithExtra = + case erlang:is_list(Extra) of + true -> Extra ++ Opts; + false ->[Extra | Opts] + end, + case is_invalid_opts_combo(WithExtra) of + true -> ok; + false -> F(WithExtra) + end + end, + [write_concurrency, read_concurrency, compressed]). + repeat_for_opts(F) -> repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]). @@ -9360,17 +9922,44 @@ repeat_for_opts_atom2list(ord_set_types) -> [ordered_set,stim_cat_ord_set,cat_or repeat_for_opts_atom2list(all_types) -> [set,ordered_set,stim_cat_ord_set,cat_ord_set,bag,duplicate_bag]; repeat_for_opts_atom2list(all_non_stim_types) -> [set,ordered_set,cat_ord_set,bag,duplicate_bag]; repeat_for_opts_atom2list(all_non_stim_set_types) -> [set,ordered_set,cat_ord_set]; -repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}]; +repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false}, + {write_concurrency,true}, + {write_concurrency, {debug_hash_fixed_number_of_locks, 2048}}, + {write_concurrency,auto}]; repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}]; repeat_for_opts_atom2list(compressed) -> [void,compressed]. +has_fixed_number_of_locks(Opts) -> + lists:any( + fun({write_concurrency, {debug_hash_fixed_number_of_locks, _}}) -> + true; + (_) -> + false + end, + Opts). + +is_invalid_opts_combo(Opts) -> + OrderedSet = lists:member(ordered_set, Opts) orelse + lists:member(stim_cat_ord_set, Opts) orelse + lists:member(cat_ord_set, Opts), + OrderedSet andalso has_fixed_number_of_locks(Opts). + +run_if_valid_opts(Opts, F) -> + case is_invalid_opts_combo(Opts) of + true -> ignore; + false -> F(Opts) + end. + is_redundant_opts_combo(Opts) -> - (lists:member(stim_cat_ord_set, Opts) orelse - lists:member(cat_ord_set, Opts)) - andalso - (lists:member({write_concurrency, false}, Opts) orelse - lists:member(private, Opts) orelse - lists:member(protected, Opts)). + IsRed1 = + ((lists:member(stim_cat_ord_set, Opts) orelse + lists:member(cat_ord_set, Opts)) + andalso + (lists:member({write_concurrency, false}, Opts) orelse + lists:member(private, Opts) orelse + lists:member(protected, Opts))), + IsRed2 = is_invalid_opts_combo(Opts), + IsRed1 orelse IsRed2. %% Add fake table option with info about key range. %% Will be consumed by ets_new and used for stim_cat_ord_set. diff --git a/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html index 922a3790eac0..43076c70cab2 100644 --- a/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html +++ b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html @@ -4,7 +4,7 @@ - + @@ -240,10 +240,12 @@

    ETS Benchmark Result Viewer

    function plotScenario(name, plotType) { var data = scenarioDataMap[name]; var yAxisTitle = undefined; + var graphId = "graph" + nrOfGraphs; + var fullscreenButtonid = "fullscreenButton" + nrOfGraphs; nrOfGraphs = nrOfGraphs + 1; - $("
    ") + $("
    ") .insertBefore(insertPlaceholder); - $("") + $("") .insertBefore(insertPlaceholder); $("


    ") .insertBefore(insertPlaceholder); @@ -265,17 +267,17 @@

    ETS Benchmark Result Viewer

    title: yAxisTitle } }; - $("#fullscreenButton" + nrOfGraphs).click( + $("#" + fullscreenButtonid).click( function () { - $('#graph' + nrOfGraphs).replaceWith( - $("
    ")); + $('#' + graphId).replaceWith( + $("
    ")); layout = $.extend({}, layout, { width: $(window).width() - 40, height: $(window).height() - 40 }); - Plotly.newPlot('graph' + nrOfGraphs, data, layout); + Plotly.newPlot(graphId, data, layout); }); - Plotly.newPlot('graph' + nrOfGraphs, data, layout); + Plotly.newPlot(graphId, data, layout); } $.each(scenarioList, function (index, name) { diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl index 15603aee9add..95893f43d4e4 100644 --- a/lib/stdlib/test/filelib_SUITE.erl +++ b/lib/stdlib/test/filelib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2020. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -25,9 +25,13 @@ init_per_testcase/2,end_per_testcase/2, wildcard_one/1,wildcard_two/1,wildcard_errors/1, fold_files/1,otp_5960/1,ensure_dir_eexist/1,ensure_dir_symlink/1, + ensure_path_single_dir/1, ensure_path_nested_dirs/1, + ensure_path_binary_args/1, ensure_path_symlink/1, + ensure_path_relative_path/1, ensure_path_relative_path_dot_dot/1, + ensure_path_invalid_path/1, wildcard_symlink/1, is_file_symlink/1, file_props_symlink/1, - find_source/1, find_source_subdir/1, safe_relative_path/1, - safe_relative_path_links/1]). + find_source/1, find_source_subdir/1, find_source_otp/1, + safe_relative_path/1, safe_relative_path_links/1]). -import(lists, [foreach/2]). @@ -49,9 +53,13 @@ suite() -> all() -> [wildcard_one, wildcard_two, wildcard_errors, fold_files, otp_5960, ensure_dir_eexist, ensure_dir_symlink, + ensure_path_single_dir, ensure_path_nested_dirs, ensure_path_binary_args, + ensure_path_symlink, ensure_path_relative_path, + ensure_path_relative_path_dot_dot, + ensure_path_invalid_path, wildcard_symlink, is_file_symlink, file_props_symlink, - find_source, find_source_subdir, safe_relative_path, - safe_relative_path_links]. + find_source, find_source_subdir, find_source_otp, + safe_relative_path, safe_relative_path_links]. groups() -> []. @@ -458,6 +466,83 @@ ensure_dir_symlink(Config) when is_list(Config) -> ok = filelib:ensure_dir(SymlinkedName) end. +ensure_path_single_dir(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + Dir = filename:join(PrivDir, "ensure_path_single_dir"), + ok = filelib:ensure_path(Dir), + true = filelib:is_dir(Dir). + +ensure_path_nested_dirs(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + BaseDir = filename:join(PrivDir, "ensure_path_nested_dirs"), + Path = filename:join(BaseDir, "foo/bar/baz"), + ok = filelib:ensure_path(Path), + true = filelib:is_dir(Path). + +ensure_path_binary_args(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + BaseDir = filename:join(PrivDir, "ensure_path_binary_args"), + Path = filename:join(BaseDir, "foo/bar/baz"), + ok = filelib:ensure_path(list_to_binary(Path)), + true = filelib:is_dir(Path). + +ensure_path_invalid_path(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + BaseDir = filename:join(PrivDir, "ensure_path_invalid_path"), + ok = filelib:ensure_path(BaseDir), + FileName = filename:join(BaseDir, "foo"), + ok = file:write_file(FileName, <<"eh?\n">>), + Path = filename:join(FileName, "foo/bar/baz"), + case filelib:ensure_path(Path) of + {error,enotdir} -> + ok; + {error,enoent} -> + %% The documentation has the following to say about the + %% `enotdir` error reason: + %% + %% "On some platforms, enoent is returned instead." + ok + end, + false = filelib:is_dir(Path). + +ensure_path_relative_path(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + BaseDir = filename:join(PrivDir, "ensure_path_relative_path"), + ok = filelib:ensure_path(BaseDir), + ok = file:set_cwd(BaseDir), + Path = filename:join(BaseDir, "foo/bar/baz"), + ok = filelib:ensure_path("foo/bar/baz"), + true = filelib:is_dir(Path). + +ensure_path_relative_path_dot_dot(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + BaseDir = filename:join(PrivDir, "ensure_path_relative_path"), + SubDir = filename:join(BaseDir, "dot_dot"), + ok = filelib:ensure_path(SubDir), + ok = file:set_cwd(SubDir), + Path = filename:join(BaseDir, "foo/bar/baz"), + ok = filelib:ensure_path("../foo/bar/baz"), + true = filelib:is_dir(Path). + +ensure_path_symlink(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + Dir = filename:join(PrivDir, "ensure_path_symlink"), + Name = filename:join(Dir, "same_name_as_file_and_dir"), + ok = filelib:ensure_path(Dir), + ok = file:write_file(Name, <<"some string\n">>), + %% With a symlink to the directory. + Symlink = filename:join(PrivDir, "ensure_path_symlink_link"), + case file:make_symlink(Dir, Symlink) of + {error,enotsup} -> + {skip,"Symlinks not supported on this platform"}; + {error,eperm} -> + {win32,_} = os:type(), + {skip,"Windows user not privileged to create symlinks"}; + ok -> + SymlinkedName = filename:join(Symlink, "same_name_as_file_and_dir"), + ok = filelib:ensure_dir(SymlinkedName) + end. + wildcard_symlink(Config) when is_list(Config) -> PrivDir = proplists:get_value(priv_dir, Config), Dir = filename:join(PrivDir, ?MODULE_STRING++"_wildcard_symlink"), @@ -652,6 +737,32 @@ find_source_subdir(Config) when is_list(Config) -> ok. +%% Test that all available beam files in Erlang/OTP can be +%% tracked to their source files. +find_source_otp(Config) when is_list(Config) -> + %% We do this in a peer as testcases before this may have + %% edited the code path and thus more modules show up as + %% available than should. + {ok, Peer, Node} = ?CT_PEER(#{ env => [{"ERL_LIBS", false}] }), + erpc:call( + Node, + fun() -> + lists:map( + fun F({Module, preloaded, Loaded}) -> + F({Module, code:where_is_file(Module ++ ".beam"), Loaded}); + F({Module, cover_compiled, Loaded}) -> + ok; + F({Module, Filename, _Loaded}) -> + case filelib:find_source(Filename) of + {ok, _} -> ok; + {error,_} = E -> + ct:fail({failed_to_find, Module, Filename, E}) + end + end, code:all_available()) + end), + peer:stop(Peer), + ok. + safe_relative_path(Config) -> PrivDir = proplists:get_value(priv_dir, Config), Root = filename:join(PrivDir, "filelib_SUITE_safe_relative_path"), @@ -729,7 +840,10 @@ safe_relative_path_links(Config) -> nested_links_test(BaseDir), loop_test(BaseDir), loop_with_parent_test(BaseDir), - revist_links_test(BaseDir); + revist_links_test(BaseDir), + descend_climb_cwd_link_test(BaseDir), + chained_links_same_target_name_test(BaseDir), + ok; false -> {skipped, "This platform/user can't create symlinks."} end @@ -803,6 +917,32 @@ revist_links_test(BaseDir) -> "file" = filelib:safe_relative_path("x/x/y/y/file", filename:join(BaseDir, "revist_links_test")), "file" = filelib:safe_relative_path("x/z/y/x/./z/foo/../x/./y/file", filename:join(BaseDir, "revist_links_test")). +descend_climb_cwd_link_test(BaseDir) -> + Dir = filename:join(BaseDir, ?FUNCTION_NAME), + + ok = file:make_dir(Dir), + ok = file:make_dir(filename:join(Dir, "cwd")), + + ok = file:make_symlink("cwd", filename:join(Dir, "cwd_link")), + + "" = filelib:safe_relative_path("foo/..", filename:join(Dir, "cwd_link")), + "bar" = filelib:safe_relative_path("foo/../bar", filename:join(Dir, "cwd_link")), + "" = filelib:safe_relative_path("foo/..", filename:join(Dir, "cwd")), + "bar" = filelib:safe_relative_path("foo/../bar", filename:join(Dir, "cwd")). + +chained_links_same_target_name_test(BaseDir) -> + Dir = filename:join(BaseDir, ?FUNCTION_NAME), + + ok = file:make_dir(Dir), + ok = file:make_dir(filename:join(Dir, "foo")), + ok = file:make_dir(filename:join(Dir, "foo/foo")), + ok = file:make_dir(filename:join(Dir, "foo/foo/bar")), + + ok = file:make_symlink("foo/bar", filename:join(Dir, "foo/bar")), + ok = file:make_symlink("foo/bar", filename:join(Dir, "bar")), + + "foo/foo/bar" = filelib:safe_relative_path("bar", Dir). + rm_rf(Dir) -> case file:read_link_info(Dir) of {ok, #file_info{type = directory}} -> diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl index 1fdea7584449..b005651302c6 100644 --- a/lib/stdlib/test/filename_SUITE.erl +++ b/lib/stdlib/test/filename_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -29,7 +29,6 @@ dirname_bin/1, extension_bin/1, join_bin/1, t_nativename_bin/1]). -export([pathtype_bin/1,rootname_bin/1,split_bin/1]). -export([t_basedir_api/1, t_basedir_xdg/1, t_basedir_windows/1]). --export([safe_relative_path/1]). -include_lib("common_test/include/ct.hrl"). @@ -41,8 +40,7 @@ all() -> [absname, absname_2, absname_bin, absname_bin_2, {group,p}, - t_basedir_xdg, t_basedir_windows, - safe_relative_path]. + t_basedir_xdg, t_basedir_windows]. groups() -> [{p, [parallel], @@ -876,71 +874,6 @@ t_nativename_bin(Config) when is_list(Config) -> filename:nativename(<<"/usr/tmp//arne/">>) end. -safe_relative_path(Config) -> - PrivDir = proplists:get_value(priv_dir, Config), - Root = filename:join(PrivDir, "filename_SUITE_safe_relative_path"), - ok = file:make_dir(Root), - ok = file:set_cwd(Root), - - ok = file:make_dir("a"), - ok = file:set_cwd("a"), - ok = file:make_dir("b"), - ok = file:set_cwd("b"), - ok = file:make_dir("c"), - - ok = file:set_cwd(Root), - - "a" = test_srp("a"), - "a/b" = test_srp("a/b"), - "a/b" = test_srp("a/./b"), - "a/b" = test_srp("a/./b/."), - - "" = test_srp("a/.."), - "" = test_srp("a/./.."), - "" = test_srp("a/../."), - "a" = test_srp("a/b/.."), - "a" = test_srp("a/../a"), - "a" = test_srp("a/../a/../a"), - "a/b/c" = test_srp("a/../a/b/c"), - - unsafe = test_srp("a/../.."), - unsafe = test_srp("a/../../.."), - unsafe = test_srp("a/./../.."), - unsafe = test_srp("a/././../../.."), - unsafe = test_srp("a/b/././../../.."), - - unsafe = test_srp(PrivDir), %Absolute path. - - ok. - -test_srp(RelPath) -> - Res = do_test_srp(RelPath), - Res = case do_test_srp(list_to_binary(RelPath)) of - Bin when is_binary(Bin) -> - binary_to_list(Bin); - Other -> - Other - end. - -do_test_srp(RelPath) -> - {ok,Root} = file:get_cwd(), - ok = file:set_cwd(RelPath), - {ok,Cwd} = file:get_cwd(), - ok = file:set_cwd(Root), - case filename:safe_relative_path(RelPath) of - unsafe -> - true = length(Cwd) < length(Root), - unsafe; - "" -> - ""; - SafeRelPath -> - ok = file:set_cwd(SafeRelPath), - {ok,Cwd} = file:get_cwd(), - true = length(Cwd) >= length(Root), - ok = file:set_cwd(Root), - SafeRelPath - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% basedirs t_basedir_api(Config) when is_list(Config) -> diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl index 0787dee5e187..65c5a83c9ea2 100644 --- a/lib/stdlib/test/gen_event_SUITE.erl +++ b/lib/stdlib/test/gen_event_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -32,7 +32,9 @@ start_opt/1, undef_init/1, undef_handle_call/1, undef_handle_event/1, undef_handle_info/1, undef_code_change/1, undef_terminate/1, - undef_in_terminate/1, format_log_1/1, format_log_2/1]). + undef_in_terminate/1, format_log_1/1, format_log_2/1, + send_request_receive_reqid_collection/1, send_request_wait_reqid_collection/1, + send_request_check_reqid_collection/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -41,7 +43,9 @@ all() -> call_format_status, call_format_status_anon, error_format_status, get_state, replace_state, start_opt, {group, undef_callbacks}, undef_in_terminate, - format_log_1, format_log_2]. + format_log_1, format_log_2, + send_request_receive_reqid_collection, send_request_wait_reqid_collection, + send_request_check_reqid_collection]. groups() -> [{test_all, [], @@ -974,7 +978,7 @@ call(Config) when is_list(Config) -> ok. flush() -> - receive _ -> flush() after 0 -> ok end. + receive M -> [M|flush()] after 0 -> [] end. info(Config) when is_list(Config) -> {ok,_} = gen_event:start({local, my_dummy_handler}), @@ -1100,22 +1104,25 @@ info(Config) when is_list(Config) -> ok = gen_event:stop(my_dummy_handler), ok. -%% Test that sys:get_status/1,2 calls format_status/2. +%% Test that sys:get_status/1,2 calls format_status/1,2. call_format_status(Config) when is_list(Config) -> + call_format_status(dummy1_h), + call_format_status(dummy_h); +call_format_status(Module) when is_atom(Module) -> {ok, Pid} = gen_event:start({local, my_dummy_handler}), %% State here intentionally differs from what we expect from format_status State = self(), FmtState = "dummy1_h handler state", - ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State]), + ok = gen_event:add_handler(my_dummy_handler, Module, [State]), Status1 = sys:get_status(Pid), Status2 = sys:get_status(Pid, 5000), ok = gen_event:stop(Pid), {status, Pid, _, [_, _, Pid, [], Data1]} = Status1, HandlerInfo1 = proplists:get_value(items, Data1), - {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo1, + {"Installed handlers", [{_,Module,_,FmtState,_}]} = HandlerInfo1, {status, Pid, _, [_, _, Pid, [], Data2]} = Status2, HandlerInfo2 = proplists:get_value(items, Data2), - {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2, + {"Installed handlers", [{_,Module,_,FmtState,_}]} = HandlerInfo2, ok. %% Test that sys:get_status/1,2 calls format_status/2 for anonymous @@ -1136,28 +1143,38 @@ call_format_status_anon(Config) when is_list(Config) -> error_format_status(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), + try + error_format_status(dummy1_h), + error_format_status(dummy_h) + after + process_flag(trap_exit, OldFl), + error_logger_forwarder:unregister() + end; +error_format_status(Module) when is_atom(Module) -> State = self(), {ok, Pid} = gen_event:start({local, my_dummy_handler}), - ok = gen_event:add_sup_handler(my_dummy_handler, dummy1_h, [State]), + ok = gen_event:add_sup_handler(my_dummy_handler, Module, [State]), ok = gen_event:notify(my_dummy_handler, do_crash), receive - {gen_event_EXIT,dummy1_h,{'EXIT',_}} -> ok + {gen_event_EXIT,Module,{'EXIT',_}} -> ok after 5000 -> - ct:fail(exit_gen_event) + ct:fail({exit_gen_event,flush()}) end, FmtState = "dummy1_h handler state", receive {error,_GroupLeader, {Pid, "** gen_event handler"++_, - [dummy1_h,my_dummy_handler,do_crash, + [Module,my_dummy_handler,do_crash, FmtState, _]}} -> ok; Other -> - io:format("Unexpected: ~p", [Other]), + ct:pal("Unexpected: ~p", [Other]), ct:fail(failed) + after 5000 -> + ct:fail({exit_gen_event,flush()}) end, + unlink(Pid), ok = gen_event:stop(Pid), - process_flag(trap_exit, OldFl), ok. %% Test that sys:get_state/1,2 return the gen_event state. @@ -1321,23 +1338,30 @@ format_log_1(_Config) -> Warning = #{label=>{gen_event,no_handle_info}, module=>?MODULE, - message=>Term}, + message=> Term}, {WF1,WA1} = gen_event:format_log(Warning), WFExpected1 = "** Undefined handle_info in ~p\n" "** Unhandled message: ~tp\n", ct:log("WF1: ~ts~nWA1: ~tp", [WF1,WA1]), WFExpected1 = WF1, [?MODULE,Term] = WA1, + WarningLimited = [1,2,3,4,5,6,7,8,9,'...'], Depth = 10, ok = application:set_env(kernel, error_logger_format_depth, Depth), - Limited = [1,2,3,4,5,6,7,8,9,'...'], + Limited = [1,2,3,4,5,6,7,8,'...'], + LastMsg = ["Last msg" | Term], + State = ["State" | Term], + Reason = ["Reason" | Term], + LastMsgLimited = ["Last msg" | Limited], + StateLimited = ["State" | Limited], + ReasonLimited = ["Reason" | Limited], {F2,A2} = gen_event:format_log(#{label=>{gen_event,terminate}, handler=>Handler, name=>Name, - last_message=>Term, - state=>Term, - reason=>Term}), + last_message=>LastMsg, + state=>State, + reason=>Reason}), FExpected2 = "** gen_event handler ~tP crashed.\n" "** Was installed in ~tP\n" "** Last event was: ~tP\n" @@ -1345,14 +1369,15 @@ format_log_1(_Config) -> "** Reason == ~tP\n", ct:log("F2: ~ts~nA2: ~tp", [F2,A2]), FExpected2 = F2, - [Handler,Depth,Name,Depth,Limited,Depth,Limited,Depth,Limited,Depth] = A2, + [Handler,Depth,Name,Depth,LastMsgLimited,Depth,StateLimited,Depth,ReasonLimited,Depth] = A2, {WF2,WA2} = gen_event:format_log(Warning), WFExpected2 = "** Undefined handle_info in ~p\n" "** Unhandled message: ~tP\n", ct:log("WF2: ~ts~nWA2: ~tp", [WF2,WA2]), WFExpected2 = WF2, - [?MODULE,Limited,Depth] = WA2, + ct:log("WF2: ~tp~nWA2: ~tp", [[?MODULE,WarningLimited,Depth], WA2]), + [?MODULE,WarningLimited,Depth] = WA2, case FD of undefined -> @@ -1501,3 +1526,324 @@ format_log_2(_Config) -> flatten_format_log(Report, Format) -> lists:flatten(gen_event:format_log(Report, Format)). + + +send_request_receive_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_event:start(), + ok = gen_event:add_handler(Pid1, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid1), + {ok, Pid2} = gen_event:start(), + ok = gen_event:add_handler(Pid2, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid2), + {ok, Pid3} = gen_event:start(), + ok = gen_event:add_handler(Pid3, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid3), + send_request_receive_reqid_collection(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3), + ok = gen_event:stop(Pid1), + try gen_event:stop(Pid2) catch exit:noproc -> ok end, + ok = gen_event:stop(Pid3). + +send_request_receive_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_event:reqids_size(ReqIdC1), + + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_event:reqids_size(ReqIdC2), + + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_event:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_event:receive_response(ReqIdC3, infinity, true), + 2 = gen_event:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:receive_response(ReqIdC4, 5678, true), + 1 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_event:receive_response(ReqIdC5, 5000, true), + 0 = gen_event:reqids_size(ReqIdC6), + + no_request = gen_event:receive_response(ReqIdC6, 5000, true), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,1000}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,500}), + ReqIdC3 = gen_event:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_event:receive_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_event:reqids_size(ReqIdC4), + + timeout = gen_event:receive_response(ReqIdC4, {abs, Deadline}, true), + + Abandoned = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Abandoned = lists:sort(gen_event:reqids_to_list(ReqIdC4)), + + %% Make sure requests were abandoned... + timeout = gen_event:receive_response(ReqIdC4, {abs, Deadline+1000}, true), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_event:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + ReqIdC4 = gen_event:send_request(Pid1, bad_h, hejsan, req4, ReqIdC3), + 4 = gen_event:reqids_size(ReqIdC4), + + {{error, {noproc, _}}, req2, ReqIdC5} = gen_event:receive_response(ReqIdC4, 2000, true), + 3 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:receive_response(ReqIdC5, infinity, false), + {{reply, delayed}, req1, ReqIdC5} = gen_event:receive_response(ReqIdC5, infinity, false), + {{error, bad_module}, req4, ReqIdC5} = gen_event:wait_response(ReqIdC5, infinity, false), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_event:start(), + ok = gen_event:add_handler(Pid1, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid1), + {ok, Pid2} = gen_event:start(), + ok = gen_event:add_handler(Pid2, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid2), + {ok, Pid3} = gen_event:start(), + ok = gen_event:add_handler(Pid3, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid3), + send_request_wait_reqid_collection(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3), + ok = gen_event:stop(Pid1), + try gen_event:stop(Pid2) catch exit:noproc -> ok end, + ok = gen_event:stop(Pid3). + +send_request_wait_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_event:reqids_size(ReqIdC1), + + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_event:reqids_size(ReqIdC2), + + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_event:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_event:wait_response(ReqIdC3, infinity, true), + 2 = gen_event:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:wait_response(ReqIdC4, 5678, true), + 1 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_event:wait_response(ReqIdC5, 5000, true), + 0 = gen_event:reqids_size(ReqIdC6), + + no_request = gen_event:wait_response(ReqIdC6, 5000, true), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,1000}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,500}), + ReqIdC3 = gen_event:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_event:wait_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_event:reqids_size(ReqIdC4), + + timeout = gen_event:wait_response(ReqIdC4, {abs, Deadline}, true), + + Unhandled = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Unhandled = lists:sort(gen_event:reqids_to_list(ReqIdC4)), + + %% Make sure requests were not abandoned... + {{reply, delayed}, req3, ReqIdC4} = gen_event:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + {{reply, delayed}, req1, ReqIdC4} = gen_event:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_event:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + ReqIdC4 = gen_event:send_request(Pid1, bad_h, hejsan, req4, ReqIdC3), + 4 = gen_event:reqids_size(ReqIdC4), + + {{error, {noproc, _}}, req2, ReqIdC5} = gen_event:wait_response(ReqIdC4, 2000, true), + 3 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:wait_response(ReqIdC5, infinity, false), + {{reply, delayed}, req1, ReqIdC5} = gen_event:wait_response(ReqIdC5, infinity, false), + {{error, bad_module}, req4, ReqIdC5} = gen_event:wait_response(ReqIdC5, infinity, false), + + {reply, {ok, hejhopp}} = gen_event:receive_response(ReqId0, infinity), + + ok. + +send_request_check_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_event:start(), + ok = gen_event:add_handler(Pid1, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid1), + {ok, Pid2} = gen_event:start(), + ok = gen_event:add_handler(Pid2, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid2), + {ok, Pid3} = gen_event:start(), + ok = gen_event:add_handler(Pid3, dummy_h, [self()]), + [dummy_h] = gen_event:which_handlers(Pid3), + send_request_check_reqid_collection(Pid1, Pid2, Pid3), + send_request_check_reqid_collection_error(Pid1, Pid2, Pid3), + ok = gen_event:stop(Pid1), + try gen_event:stop(Pid2) catch exit:noproc -> ok end, + ok = gen_event:stop(Pid3). + +send_request_check_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + receive after 100 -> ok end, + + ReqIdC0 = gen_event:reqids_new(), + + ReqIdC1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}, req1, ReqIdC0), + 1 = gen_event:reqids_size(ReqIdC1), + + ReqId2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}), + ReqIdC2 = gen_event:reqids_add(ReqId2, req2, ReqIdC1), + 2 = gen_event:reqids_size(ReqIdC2), + + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_event:reqids_size(ReqIdC3), + + Msg0 = next_msg(), + no_reply = gen_event:check_response(Msg0, ReqIdC3, true), + + {{reply, delayed}, req2, ReqIdC4} = gen_event:check_response(next_msg(), ReqIdC3, true), + 2 = gen_event:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:check_response(next_msg(), ReqIdC4, true), + 1 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_event:check_response(next_msg(), ReqIdC5, true), + 0 = gen_event:reqids_size(ReqIdC6), + + no_request = gen_event:check_response(Msg0, ReqIdC6, true), + + {reply, {ok, hejhopp}} = gen_event:check_response(Msg0, ReqId0), + + ok. + +send_request_check_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_event:send_request(Pid1, dummy_h, hejsan), + + receive after 100 -> ok end, + + ReqIdC0 = gen_event:reqids_new(), + + ReqId1 = gen_event:send_request(Pid1, dummy_h, {delayed_answer,400}), + ReqIdC1 = gen_event:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_event:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_event:send_request(Pid2, dummy_h, {delayed_answer,1}, req2, ReqIdC1), + + ReqIdC3 = gen_event:send_request(Pid3, dummy_h, {delayed_answer,200}, req3, ReqIdC2), + + ReqIdC4 = gen_event:send_request(Pid1, bad_h, hejsan, req4, ReqIdC3), + 4 = gen_event:reqids_size(ReqIdC4), + + Msg0 = next_msg(), + + no_reply = gen_event:check_response(Msg0, ReqIdC3, true), + + {{error, {noproc, _}}, req2, ReqIdC5} = gen_event:check_response(next_msg(), ReqIdC4, true), + 3 = gen_event:reqids_size(ReqIdC5), + + {{reply, delayed}, req3, ReqIdC5} = gen_event:check_response(next_msg(), ReqIdC5, false), + {{reply, delayed}, req1, ReqIdC5} = gen_event:check_response(next_msg(), ReqIdC5, false), + {{error, bad_module}, req4, ReqIdC5} = gen_event:check_response(next_msg(), ReqIdC5, false), + + no_reply = gen_event:check_response(Msg0, ReqIdC3, false), + + {reply, {ok, hejhopp}} = gen_event:check_response(Msg0, ReqId0), + + ok. + +next_msg() -> + receive M -> M end. diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl index d416bf2f8fdf..9d912ab25771 100644 --- a/lib/stdlib/test/gen_fsm_SUITE.erl +++ b/lib/stdlib/test/gen_fsm_SUITE.erl @@ -366,20 +366,20 @@ stop7(_Config) -> %% Anonymous on remote node stop8(_Config) -> - {ok,Node} = test_server:start_node(gen_fsm_SUITE_stop8,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_fsm,start,[?MODULE,[],[]]), ok = gen_fsm:stop(Pid), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_fsm:stop(Pid)), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',{{nodedown,Node},_}} = (catch gen_fsm:stop(Pid)), ok. %% Registered name on remote node stop9(_Config) -> - {ok,Node} = test_server:start_node(gen_fsm_SUITE_stop9,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_fsm,start,[{local,to_stop},?MODULE,[],[]]), @@ -387,13 +387,13 @@ stop9(_Config) -> undefined = rpc:call(Node,erlang,whereis,[to_stop]), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_fsm:stop({to_stop,Node})), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',{{nodedown,Node},_}} = (catch gen_fsm:stop({to_stop,Node})), ok. %% Globally registered name on remote node stop10(_Config) -> - {ok,Node} = test_server:start_node(gen_fsm_SUITE_stop10,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_fsm,start,[{global,to_stop},?MODULE,[],[]]), @@ -401,7 +401,7 @@ stop10(_Config) -> ok = gen_fsm:stop({global,to_stop}), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_fsm:stop({global,to_stop})), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',noproc} = (catch gen_fsm:stop({global,to_stop})), ok. diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 0118b7bc66bc..52f6a2ceb9b1 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2021. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -26,14 +26,23 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([start/1, crash/1, call/1, send_request/1, cast/1, cast_fast/1, - continue/1, info/1, abcast/1, multicall/1, multicall_down/1, - call_remote1/1, call_remote2/1, call_remote3/1, +-export([start/1, crash/1, loop_start_fail/1, call/1, send_request/1, + send_request_receive_reqid_collection/1, + send_request_wait_reqid_collection/1, + send_request_check_reqid_collection/1, + cast/1, cast_fast/1, continue/1, info/1, abcast/1, + multicall/1, multicall_down/1, multicall_remote/1, + multicall_remote_old1/1, multicall_remote_old2/1, + multicall_recv_opt_success/1, + multicall_recv_opt_timeout/1, + multicall_recv_opt_noconnection/1, + call_remote1/1, call_remote2/1, call_remote3/1, calling_self/1, call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1, spec_init_local_registered_parent/1, spec_init_global_registered_parent/1, otp_5854/1, hibernate/1, auto_hibernate/1, otp_7669/1, call_format_status/1, - error_format_status/1, terminate_crash_format/1, + error_format_status/1, terminate_crash_format/1, crash_in_format_status/1, + throw_in_format_status/1, format_all_status/1, get_state/1, replace_state/1, call_with_huge_message_queue/1, undef_handle_call/1, undef_handle_cast/1, undef_handle_info/1, undef_init/1, undef_code_change/1, undef_terminate1/1, @@ -54,24 +63,39 @@ spec_init_anonymous_default_timeout/1, spec_init_not_proc_lib/1, cast_fast_messup/0]). +%% Internal test specific exports +-export([multicall_srv_ctrlr/2, multicall_suspender/2]). %% The gen_server behaviour -export([init/1, handle_call/3, handle_cast/2, handle_continue/2, handle_info/2, code_change/3, terminate/2, format_status/2]). +%% This module needs to compile on old nodes... +-ifndef(CT_PEER). +-define(CT_PEER(), {ok, undefined, undefined}). +-define(CT_PEER(Opts), {ok, undefined, undefined}). +-endif. +-ifndef(CT_PEER_REL). +-define(CT_PEER_REL(Opts, Release, PrivDir), {ok, undefined, undefined}). +-endif. + suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. all() -> - [start, {group,stop}, crash, call, send_request, cast, cast_fast, info, abcast, - continue, multicall, multicall_down, call_remote1, call_remote2, + [start, {group,stop}, crash, loop_start_fail, call, send_request, + send_request_receive_reqid_collection, send_request_wait_reqid_collection, + send_request_check_reqid_collection, cast, cast_fast, info, abcast, + continue, + {group, multi_call}, + call_remote1, call_remote2, calling_self, call_remote3, call_remote_n1, call_remote_n2, call_remote_n3, spec_init, spec_init_local_registered_parent, spec_init_global_registered_parent, otp_5854, hibernate, auto_hibernate, otp_7669, - call_format_status, error_format_status, terminate_crash_format, + {group, format_status}, get_state, replace_state, call_with_huge_message_queue, {group, undef_callbacks}, undef_in_terminate, undef_in_handle_info, @@ -80,12 +104,25 @@ all() -> groups() -> [{stop, [], [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]}, + {multi_call, [], [{group, multi_call_parallel}, {group, multi_call_sequence}]}, + {multi_call_parallel, [parallel], + [multicall, multicall_down, multicall_remote, multicall_remote_old1, + multicall_remote_old2]}, + {multi_call_sequence, [], + [multicall_recv_opt_success, multicall_recv_opt_timeout, + multicall_recv_opt_noconnection]}, + {format_status, [], + [call_format_status, error_format_status, terminate_crash_format, + crash_in_format_status, throw_in_format_status, format_all_status]}, {undef_callbacks, [], [undef_handle_call, undef_handle_cast, undef_handle_info, undef_handle_continue, undef_init, undef_code_change, undef_terminate1, undef_terminate2]}]. init_per_suite(Config) -> + DataDir = ?config(data_dir, Config), + Server = filename:join(DataDir, "format_status_server.erl"), + {ok, format_status_server} = compile:file(Server), Config. end_per_suite(_Config) -> @@ -110,18 +147,22 @@ init_per_testcase(Case, Config) when Case == call_remote1; Case == call_remote_n2; Case == call_remote_n3; Case == send_request -> - {ok,N} = start_node(hubba), - [{node,N} | Config]; + {ok,Peer,Node} = ?CT_PEER(), + ok = global:sync(), + [{node,Node}, {peer, Peer} | Config]; init_per_testcase(_Case, Config) -> Config. end_per_testcase(_Case, Config) -> - case proplists:get_value(node, Config) of + case proplists:get_value(peer, Config) of undefined -> ok; - N -> - test_server:stop_node(N) + Peer -> + try peer:stop(Peer) + catch exit : noproc -> + ok + end end, ok. @@ -134,6 +175,7 @@ start(Config) when is_list(Config) -> OldFl = process_flag(trap_exit, true), %% anonymous + io:format("anonymous~n", []), {ok, Pid0} = gen_server:start(gen_server_SUITE, [], []), ok = gen_server:call(Pid0, started_p), ok = gen_server:call(Pid0, stop), @@ -141,6 +183,7 @@ start(Config) when is_list(Config) -> {'EXIT', {noproc,_}} = (catch gen_server:call(Pid0, started_p, 1)), %% anonymous with timeout + io:format("try init timeout~n", []), {ok, Pid00} = gen_server:start(gen_server_SUITE, [], [{timeout,1000}]), ok = gen_server:call(Pid00, started_p), @@ -149,9 +192,16 @@ start(Config) when is_list(Config) -> [{timeout,100}]), %% anonymous with ignore + io:format("try init ignore~n", []), ignore = gen_server:start(gen_server_SUITE, ignore, []), + %% anonymous with shutdown + io:format("try init shutdown~n", []), + {error, foobar} = + gen_server:start(gen_server_SUITE, {error, foobar}, []), + %% anonymous with stop + io:format("try init stop~n", []), {error, stopped} = gen_server:start(gen_server_SUITE, stop, []), %% anonymous linked @@ -365,20 +415,20 @@ stop7(_Config) -> %% Anonymous on remote node stop8(_Config) -> - {ok,Node} = test_server:start_node(gen_server_SUITE_stop8,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_server,start,[?MODULE,[],[]]), ok = gen_server:stop(Pid), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_server:stop(Pid)), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',{{nodedown,Node},_}} = (catch gen_server:stop(Pid)), ok. %% Registered name on remote node stop9(_Config) -> - {ok,Node} = test_server:start_node(gen_server_SUITE_stop9,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_server,start,[{local,to_stop},?MODULE,[],[]]), @@ -386,13 +436,13 @@ stop9(_Config) -> undefined = rpc:call(Node,erlang,whereis,[to_stop]), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_server:stop({to_stop,Node})), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',{{nodedown,Node},_}} = (catch gen_server:stop({to_stop,Node})), ok. %% Globally registered name on remote node stop10(_Config) -> - {ok,Node} = test_server:start_node(gen_server_SUITE_stop10,slave,[]), + {ok,Peer,Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), {ok, Pid} = rpc:call(Node,gen_server,start,[{global,to_stop},?MODULE,[],[]]), @@ -400,7 +450,7 @@ stop10(_Config) -> ok = gen_server:stop({global,to_stop}), false = rpc:call(Node,erlang,is_process_alive,[Pid]), {'EXIT',noproc} = (catch gen_server:stop({global,to_stop})), - true = test_server:stop_node(Node), + peer:stop(Peer), {'EXIT',noproc} = (catch gen_server:stop({global,to_stop})), ok. @@ -471,6 +521,55 @@ crash(Config) when is_list(Config) -> ok. + +loop_start_fail(Config) -> + _ = process_flag(trap_exit, true), + loop_start_fail( + Config, + [{start, []}, {start, [link]}, + {start_link, []}, + {start_monitor, [link]}, {start_monitor, []}]). + +loop_start_fail(_Config, []) -> + ok; +loop_start_fail(Config, [{Start, Opts} | Start_Opts]) -> + loop_start_fail( + fun gen_server:Start/3, + {ets, {return, {stop, failed_to_start}}}, Opts, + fun ({error, failed_to_start}) -> ok end), + loop_start_fail( + fun gen_server:Start/3, + {ets, {return, ignore}}, Opts, + fun (ignore) -> ok end), + loop_start_fail( + fun gen_server:Start/3, + {ets, {return, 4711}}, Opts, + fun ({error, {bad_return_value, 4711}}) -> ok end), + loop_start_fail( + fun gen_server:Start/3, + {ets, {crash, error, bailout}}, Opts, + fun ({error, {bailout, ST}}) when is_list(ST) -> ok end), + loop_start_fail( + fun gen_server:Start/3, + {ets, {crash, exit, bailout}}, Opts, + fun ({error, bailout}) -> ok end), + loop_start_fail( + fun gen_server:Start/3, + {ets, {wait, 1000, void}}, [{timeout, 200} | Opts], + fun ({error, timeout}) -> ok end), + loop_start_fail(Config, Start_Opts). + +loop_start_fail(GenStartFun, Arg, Opts, ValidateFun) -> + loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, 5). +%% +loop_start_fail(_GenStartFun, _Arg, _Opts, _ValidateFun, 0) -> + ok; +loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, N) -> + ok = ValidateFun(GenStartFun(?MODULE, Arg, Opts)), + loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, N - 1). + + + %% -------------------------------------- %% Test gen_server:call and handle_call. %% Test all different return values from @@ -590,6 +689,323 @@ send_request(Config) when is_list(Config) -> process_flag(trap_exit, OldFl), ok. +send_request_receive_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_server:start_link({local, my_test_name1}, + gen_server_SUITE, [], []), + {ok, Pid2} = gen_server:start_link({local, my_test_name2}, + gen_server_SUITE, [], []), + {ok, Pid3} = gen_server:start_link({local, my_test_name3}, + gen_server_SUITE, [], []), + send_request_receive_reqid_collection(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3), + unlink(Pid1), + exit(Pid1, kill), + unlink(Pid2), + exit(Pid2, kill), + unlink(Pid3), + exit(Pid3, kill), + false = is_process_alive(Pid1), + false = is_process_alive(Pid2), + false = is_process_alive(Pid3), + ok. + +send_request_receive_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_server:reqids_size(ReqIdC1), + + ReqIdC2 = gen_server:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_server:reqids_size(ReqIdC2), + + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_server:receive_response(ReqIdC3, infinity, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_server:receive_response(ReqIdC4, 5678, true), + 1 = gen_server:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_server:receive_response(ReqIdC5, 5000, true), + 0 = gen_server:reqids_size(ReqIdC6), + + no_request = gen_server:receive_response(ReqIdC6, 5000, true), + + {reply, ok} = gen_server:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,1000}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_server:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_server:send_request(Pid3, {delayed_answer,500}), + ReqIdC3 = gen_server:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_server:receive_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_server:reqids_size(ReqIdC4), + + timeout = gen_server:receive_response(ReqIdC4, {abs, Deadline}, true), + + Abandoned = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Abandoned = lists:sort(gen_server:reqids_to_list(ReqIdC4)), + + %% Make sure requests were abandoned... + timeout = gen_server:receive_response(ReqIdC4, {abs, Deadline+1000}, true), + + {reply, ok} = gen_server:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_server:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + ReqIdC2 = gen_server:send_request(Pid2, stop_shutdown, req2, ReqIdC1), + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + {{error, {shutdown, _}}, req2, ReqIdC4} = gen_server:receive_response(ReqIdC3, 2000, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_server:receive_response(ReqIdC4, infinity, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_server:receive_response(ReqIdC4, infinity, false), + + {reply, ok} = gen_server:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_server:start_link({local, my_test_name1}, + gen_server_SUITE, [], []), + {ok, Pid2} = gen_server:start_link({local, my_test_name2}, + gen_server_SUITE, [], []), + {ok, Pid3} = gen_server:start_link({local, my_test_name3}, + gen_server_SUITE, [], []), + send_request_wait_reqid_collection(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3), + unlink(Pid1), + exit(Pid1, kill), + unlink(Pid2), + exit(Pid2, kill), + unlink(Pid3), + exit(Pid3, kill), + false = is_process_alive(Pid1), + false = is_process_alive(Pid2), + false = is_process_alive(Pid3), + ok. + +send_request_wait_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_server:reqids_size(ReqIdC1), + + ReqIdC2 = gen_server:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_server:reqids_size(ReqIdC2), + + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_server:wait_response(ReqIdC3, infinity, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_server:wait_response(ReqIdC4, 5678, true), + 1 = gen_server:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_server:wait_response(ReqIdC5, 5000, true), + 0 = gen_server:reqids_size(ReqIdC6), + + no_request = gen_server:wait_response(ReqIdC6, 5000, true), + + {reply, ok} = gen_server:wait_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,1000}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_server:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_server:send_request(Pid3, {delayed_answer,500}), + ReqIdC3 = gen_server:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_server:wait_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_server:reqids_size(ReqIdC4), + + timeout = gen_server:wait_response(ReqIdC4, {abs, Deadline}, true), + + Unhandled = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Unhandled = lists:sort(gen_server:reqids_to_list(ReqIdC4)), + + %% Make sure requests were not abandoned... + {{reply, delayed}, req3, ReqIdC4} = gen_server:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + {{reply, delayed}, req1, ReqIdC4} = gen_server:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + + {reply, ok} = gen_server:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_server:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + ReqIdC2 = gen_server:send_request(Pid2, stop_shutdown, req2, ReqIdC1), + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + {{error, {shutdown, _}}, req2, ReqIdC4} = gen_server:wait_response(ReqIdC3, 2000, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_server:wait_response(ReqIdC4, infinity, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_server:wait_response(ReqIdC4, infinity, false), + + {reply, ok} = gen_server:wait_response(ReqId0, infinity), + + ok. + +send_request_check_reqid_collection(Config) when is_list(Config) -> + {ok, Pid1} = gen_server:start_link({local, my_test_name1}, + gen_server_SUITE, [], []), + {ok, Pid2} = gen_server:start_link({local, my_test_name2}, + gen_server_SUITE, [], []), + {ok, Pid3} = gen_server:start_link({local, my_test_name3}, + gen_server_SUITE, [], []), + send_request_check_reqid_collection(Pid1, Pid2, Pid3), + send_request_check_reqid_collection_error(Pid1, Pid2, Pid3), + unlink(Pid1), + exit(Pid1, kill), + unlink(Pid2), + exit(Pid2, kill), + unlink(Pid3), + exit(Pid3, kill), + false = is_process_alive(Pid1), + false = is_process_alive(Pid2), + false = is_process_alive(Pid3), + ok. + +send_request_check_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + receive after 100 -> ok end, + + ReqIdC0 = gen_server:reqids_new(), + + ReqIdC1 = gen_server:send_request(Pid1, {delayed_answer,400}, req1, ReqIdC0), + 1 = gen_server:reqids_size(ReqIdC1), + + ReqId2 = gen_server:send_request(Pid2, {delayed_answer,1}), + ReqIdC2 = gen_server:reqids_add(ReqId2, req2, ReqIdC1), + 2 = gen_server:reqids_size(ReqIdC2), + + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + Msg0 = next_msg(), + no_reply = gen_server:check_response(Msg0, ReqIdC3, true), + + {{reply, delayed}, req2, ReqIdC4} = gen_server:check_response(next_msg(), ReqIdC3, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_server:check_response(next_msg(), ReqIdC4, true), + 1 = gen_server:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_server:check_response(next_msg(), ReqIdC5, true), + 0 = gen_server:reqids_size(ReqIdC6), + + no_request = gen_server:check_response(Msg0, ReqIdC6, true), + + {reply, ok} = gen_server:check_response(Msg0, ReqId0), + + ok. + +send_request_check_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_server:send_request(Pid1, started_p), + + receive after 100 -> ok end, + + ReqIdC0 = gen_server:reqids_new(), + + ReqId1 = gen_server:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_server:reqids_add(ReqId1, req1, ReqIdC0), + + unlink(Pid2), + ReqIdC2 = gen_server:send_request(Pid2, stop_shutdown, req2, ReqIdC1), + + ReqIdC3 = gen_server:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_server:reqids_size(ReqIdC3), + + Msg0 = next_msg(), + + no_reply = gen_server:check_response(Msg0, ReqIdC3, true), + + {{error, {shutdown, _}}, req2, ReqIdC4} = gen_server:check_response(next_msg(), ReqIdC3, true), + 2 = gen_server:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_server:check_response(next_msg(), ReqIdC4, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_server:check_response(next_msg(), ReqIdC4, false), + + {reply, ok} = gen_server:check_response(Msg0, ReqId0), + + ok. + +next_msg() -> + receive M -> M end. %% -------------------------------------- %% Test handle_continue. @@ -636,15 +1052,6 @@ read_replies() -> %% Test call to nonexisting processes on remote nodes %% -------------------------------------- -start_node(Name) -> - Pa = filename:dirname(code:which(?MODULE)), - N = test_server:start_node(Name, slave, [{args, " -pa " ++ Pa}]), - %% After starting a slave, it takes a little while until global knows - %% about it, even if nodes() includes it, so we make sure that global - %% knows about it before registering something on all nodes. - ok = global:sync(), - N. - call_remote1(Config) when is_list(Config) -> N = hubba, Node = proplists:get_value(node,Config), @@ -691,7 +1098,7 @@ call_remote_n1(Config) when is_list(Config) -> Node = proplists:get_value(node,Config), {ok, _Pid} = rpc:call(Node, gen_server, start, [{global, N}, ?MODULE, [], []]), - _ = test_server:stop_node(Node), + peer:stop(proplists:get_value(peer,Config)), {'EXIT', {noproc, _}} = (catch gen_server:call({global, N}, started_p, infinity)), @@ -703,7 +1110,7 @@ call_remote_n2(Config) when is_list(Config) -> {ok, Pid} = rpc:call(Node, gen_server, start, [{global, N}, ?MODULE, [], []]), - _ = test_server:stop_node(Node), + peer:stop(proplists:get_value(peer,Config)), {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call(Pid, started_p, infinity)), @@ -714,12 +1121,21 @@ call_remote_n3(Config) when is_list(Config) -> {ok, _Pid} = rpc:call(Node, gen_server, start, [{local, piller}, ?MODULE, [], []]), - _ = test_server:stop_node(Node), + peer:stop(proplists:get_value(peer,Config)), {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call({piller, Node}, started_p, infinity)), ok. +%% -------------------------------------- +%% Other bad calls +%% -------------------------------------- + +calling_self(Config) when is_list(Config) -> + {'EXIT', {calling_self, _}} = (catch gen_server:call(self(), oops)), + {'EXIT', {calling_self, _}} = (catch gen_server:call(self(), oops, infinity)), + ok. + %% -------------------------------------- %% Test gen_server:cast and handle_cast. %% Test all different return values from @@ -760,7 +1176,11 @@ cast(Config) when is_list(Config) -> %% Test that cast really return immediately. cast_fast(Config) when is_list(Config) -> - {ok,Node} = start_node(hubba), + {ok,Peer,Node} = ?CT_PEER(), + %% After starting a slave, it takes a little while until global knows + %% about it, even if nodes() includes it, so we make sure that global + %% knows about it before registering something on all nodes. + ok = global:sync(), {_,"@"++Host} = lists:splitwith(fun ($@) -> false; (_) -> true end, atom_to_list(Node)), FalseNode = list_to_atom("hopp@"++Host), @@ -770,7 +1190,7 @@ cast_fast(Config) when is_list(Config) -> {Time,ok} = timer:tc(fun() -> gen_server:cast({hopp,FalseNode}, hopp) end), - true = test_server:stop_node(Node), + peer:stop(Peer), if Time > 1000000 -> % Default listen timeout is about 7.0 s ct:fail(hanging_cast); true -> @@ -1099,6 +1519,251 @@ busy_wait_for_process(Pid,N) -> _ -> ok end. + +multicall_remote(Config) when is_list(Config) -> + PNs = lists:map(fun (_) -> + {ok, P, N} = ?CT_PEER(), + {P, N} + end, lists:seq(1, 4)), + multicall_remote_test(PNs, ?FUNCTION_NAME), + ok. + +multicall_remote_old1(Config) when is_list(Config) -> + multicall_remote_old_test(Config, 1, ?FUNCTION_NAME). + +multicall_remote_old2(Config) when is_list(Config) -> + multicall_remote_old_test(Config, 2, ?FUNCTION_NAME). + + +multicall_remote_old_test(Config, OldN, Name) -> + try + {OldRelName, OldRel} = old_release(OldN), + PD = proplists:get_value(priv_dir, Config), + PNs = lists:map(fun (I) -> + Dir = atom_to_list(Name)++"-"++integer_to_list(I), + AbsDir = filename:join([PD, Dir]), + ok = file:make_dir(AbsDir), + case ?CT_PEER_REL(#{connection => 0}, OldRelName, AbsDir) of + not_available -> + throw({skipped, "No OTP "++OldRel++" available"}); + {ok, P, N} -> + {P, N} + end + end, lists:seq(1, 4)), + OldNodes = lists:map(fun ({_, N}) -> N end, PNs), + %% Recompile on one old node and load this on all old nodes... + SrcFile = filename:rootname(code:which(?MODULE)) ++ ".erl", + {ok, ?MODULE, BeamCode} = erpc:call(hd(OldNodes), compile, file, [SrcFile, [binary]]), + LoadResult = lists:duplicate(length(OldNodes), {ok, {module, ?MODULE}}), + LoadResult = erpc:multicall(OldNodes, code, load_binary, [?MODULE, SrcFile, BeamCode]), + multicall_remote_test(PNs, Name) + catch + throw:Res -> + Res + end. + +multicall_remote_test([{Peer1, Node1}, + {Peer2, Node2}, + {Peer3, Node3}, + {Peer4, Node4}], + Name) -> + Tester = self(), + ThisNode = node(), + + Nodes = [Node1, Node2, Node3, Node4, ThisNode], + + SrvList = + lists:map(fun (Node) -> + Ctrl = spawn_link(Node, ?MODULE, + multicall_srv_ctrlr, + [Tester, Name]), + receive + {Ctrl, _Srv} = Procs -> + {Node, Procs} + end + end, Nodes), + SrvMap = maps:from_list(SrvList), + + Res0 = {lists:map(fun (Node) -> + {Node,ok} + end, Nodes), []}, + + Res0 = gen_server:multi_call(Nodes, Name, started_p), + + true = try + _ = gen_server:multi_call([Node1, Node2, Node3, node(), {Node4}], + Name, {delayed_answer,1}), + false + catch + _:_ -> + true + end, + + Res1 = {lists:map(fun (Node) -> + {Node,delayed} + end, Nodes), []}, + + Res1 = gen_server:multi_call(Nodes, Name, {delayed_answer,1}), + + Res2 = {[], Nodes}, + + Start = erlang:monotonic_time(millisecond), + Res2 = gen_server:multi_call(Nodes, Name, {delayed_answer,1000}, 100), + End = erlang:monotonic_time(millisecond), + Time = End-Start, + ct:log("Time: ~p ms~n", [Time]), + true = 200 >= Time, + + {Ctrl2, Srv2} = maps:get(Node2, SrvMap), + unlink(Ctrl2), + exit(Ctrl2, kill), + wait_until(fun () -> + false == erpc:call(Node2, erlang, + is_process_alive, [Srv2]) + end), + + {Ctrl3, _Srv3} = maps:get(Node3, SrvMap), + unlink(Ctrl3), + peer:stop(Peer3), + + {Ctrl4, Srv4} = maps:get(Node4, SrvMap), + Spndr = spawn_link(Node4, ?MODULE, multicall_suspender, [Tester, Srv4]), + + Res3 = {[{Node1, delayed}, {ThisNode, delayed}], + [Node2, Node3, Node4]}, + + Res3 = gen_server:multi_call(Nodes, Name, {delayed_answer,1}, 1000), + + Spndr ! {Tester, resume_it}, + + receive Msg -> ct:fail({unexpected_msg, Msg}) + after 1000 -> ok + end, + + unlink(Ctrl4), + + {Ctrl1, _Srv1} = maps:get(Node1, SrvMap), + + unlink(Ctrl1), + + peer:stop(Peer1), + peer:stop(Peer2), + peer:stop(Peer4), + + ok. + +multicall_srv_ctrlr(Tester, Name) -> + {ok, Srv} = gen_server:start_link({local, Name}, + gen_server_SUITE, [], []), + Tester ! {self(), Srv}, + receive after infinity -> ok end. + +multicall_suspender(Tester, Suspendee) -> + true = erlang:suspend_process(Suspendee), + receive + {Tester, resume_it} -> + erlang:resume_process(Suspendee) + end. + +multicall_recv_opt_success(Config) when is_list(Config) -> + multicall_recv_opt_test(success). + +multicall_recv_opt_timeout(Config) when is_list(Config) -> + multicall_recv_opt_test(timeout). + +multicall_recv_opt_noconnection(Config) when is_list(Config) -> + multicall_recv_opt_test(noconnection). + +multicall_recv_opt_test(Type) -> + Tester = self(), + Name = ?FUNCTION_NAME, + Loops = 1000, + HugeMsgQ = 500000, + process_flag(message_queue_data, off_heap), + + {ok, Peer1, Node1} = ?CT_PEER(), + {ok, Peer2, Node2} = ?CT_PEER(), + + if Type == noconnection -> peer:stop(Peer2); + true -> ok + end, + + Nodes = [Node1, Node2], + + SrvList = + lists:map(fun (Node) -> + Ctrl = spawn_link(Node, ?MODULE, + multicall_srv_ctrlr, + [Tester, Name]), + receive + {Ctrl, _Srv} = Procs -> + {Node, Procs} + end + end, + if Type == noconnection -> [Node1]; + true -> Nodes + end), + + {Req, ExpRes, Tmo} = case Type of + success -> + {ping, + {[{Node1, pong}, {Node2, pong}], []}, + infinity}; + timeout -> + {{delayed_answer,100}, + {[], Nodes}, + 1}; + noconnection -> + {ping, + {[{Node1, pong}], [Node2]}, + infinity} + end, + + _Warmup = time_multicall(ExpRes, Nodes, Name, Req, Tmo, Loops div 10), + + Empty = time_multicall(ExpRes, Nodes, Name, Req, Tmo, Loops), + ct:pal("Time with empty message queue: ~p microsecond~n", + [erlang:convert_time_unit(Empty, native, microsecond)]), + + make_msgq(HugeMsgQ), + + Huge = time_multicall(ExpRes, Nodes, Name, Req, Tmo, Loops), + ct:pal("Time with huge message queue: ~p microsecond~n", + [erlang:convert_time_unit(Huge, native, microsecond)]), + + lists:foreach(fun ({_Node, {Ctrl, _Srv}}) -> unlink(Ctrl) end, SrvList), + + peer:stop(Peer1), + if Type == noconnection -> ok; + true -> peer:stop(Peer2) + end, + + Q = Huge / Empty, + HugeMsgQ = flush_msgq(), + case Q > 10 of + true -> + ct:fail({ratio, Q}); + false -> + {comment, "Ratio: "++erlang:float_to_list(Q)} + end. + +time_multicall(Expect, Nodes, Name, Req, Tmo, Times) -> + Start = erlang:monotonic_time(), + ok = do_time_multicall(Expect, Nodes, Name, Req, Tmo, Times), + erlang:monotonic_time() - Start. + +do_time_multicall(_Expect, _Nodes, _Name, _Req, _Tmo, 0) -> + ok; +do_time_multicall(Expect, Nodes, Name, Req, Tmo, N) -> + Expect = gen_server:multi_call(Nodes, Name, Req, Tmo), + do_time_multicall(Expect, Nodes, Name, Req, Tmo, N-1). + +make_msgq(0) -> + ok; +make_msgq(N) -> + self() ! {a, msg}, + make_msgq(N-1). + %%-------------------------------------------------------------- %% Test gen_server:enter_loop/[3,4,5]. Used when you want to write %% your own special init-phase. @@ -1330,48 +1995,65 @@ do_otp_7669_stop() -> ?MODULE, stop, []), undefined = global:whereis_name(?MODULE). -%% Verify that sys:get_status correctly calls our format_status/2 fun. +%% Verify that sys:get_status correctly calls our format_status/1,2 fun. call_format_status(Config) when is_list(Config) -> + OldFl = process_flag(trap_exit, true), + call_format_status(?MODULE, format_status_called), + call_format_status(format_status_server,{data,[{"State",format_status_called}]}), + process_flag(trap_exit, OldFl). +call_format_status(Module, Match) when is_atom(Module) -> + Parent = self(), {ok, Pid} = gen_server:start_link({local, call_format_status}, - ?MODULE, [], []), + Module, [], []), Status1 = sys:get_status(call_format_status), {status, Pid, Mod, [_Pdict1, running, Parent, _, Data1]} = Status1, - [format_status_called | _] = lists:reverse(Data1), + [Match | _] = lists:reverse(Data1), Status2 = sys:get_status(call_format_status, 5000), {status, Pid, Mod, [_Pdict2, running, Parent, _, Data2]} = Status2, - [format_status_called | _] = lists:reverse(Data2), + [Match | _] = lists:reverse(Data2), + gen_server:call(Pid, stop), + receive {'EXIT',_,_} -> ok end, %% check that format_status can handle a name being a pid (atom is %% already checked by the previous test) - {ok, Pid3} = gen_server:start_link(gen_server_SUITE, [], []), + {ok, Pid3} = gen_server:start_link(Module, [], []), Status3 = sys:get_status(Pid3), {status, Pid3, Mod, [_PDict3, running, Parent, _, Data3]} = Status3, - [format_status_called | _] = lists:reverse(Data3), + [Match | _] = lists:reverse(Data3), + gen_server:call(Pid3, stop), + receive {'EXIT',_,_} -> ok end, %% check that format_status can handle a name being a term other than a %% pid or atom GlobalName1 = {global, "CallFormatStatus"}, - {ok, Pid4} = gen_server:start_link(GlobalName1, - gen_server_SUITE, [], []), + {ok, Pid4} = gen_server:start_link(GlobalName1, Module, [], []), Status4 = sys:get_status(Pid4), {status, Pid4, Mod, [_PDict4, running, Parent, _, Data4]} = Status4, - [format_status_called | _] = lists:reverse(Data4), + [Match | _] = lists:reverse(Data4), + gen_server:call(Pid4, stop), + receive {'EXIT',_,_} -> ok end, GlobalName2 = {global, {name, "term"}}, - {ok, Pid5} = gen_server:start_link(GlobalName2, - gen_server_SUITE, [], []), + {ok, Pid5} = gen_server:start_link(GlobalName2, Module, [], []), Status5 = sys:get_status(GlobalName2), {status, Pid5, Mod, [_PDict5, running, Parent, _, Data5]} = Status5, - [format_status_called | _] = lists:reverse(Data5), + [Match | _] = lists:reverse(Data5), + gen_server:call(Pid5, stop), + receive {'EXIT',_,_} -> ok end, ok. -%% Verify that error termination correctly calls our format_status/2 fun. +%% Verify that error termination correctly calls our format_status/1,2 fun. error_format_status(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), + error_format_status(?MODULE), + error_format_status(format_status_server), + process_flag(trap_exit, OldFl); +error_format_status(Module) when is_atom(Module) -> + State = "called format_status", - {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []), + {ok, Pid} = gen_server:start_link(Module, {state, State}, []), {'EXIT',{crashed,_}} = (catch gen_server:call(Pid, crash)), receive {'EXIT', Pid, crashed} -> @@ -1387,19 +2069,24 @@ error_format_status(Config) when is_list(Config) -> ClientPid, [_|_] = _ClientStack]}} -> ok; Other -> - io:format("Unexpected: ~p", [Other]), + ct:pal("Unexpected: ~p", [Other]), ct:fail(failed) end, - process_flag(trap_exit, OldFl), + receive + {error_report,_,_} -> ok + end, ok. -%% Verify that error when terminating correctly calls our format_status/2 fun -%% +%% Verify that error when terminating correctly calls our format_status/1,2 fun terminate_crash_format(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), + terminate_crash_format(?MODULE), + terminate_crash_format(format_status_server), + process_flag(trap_exit, OldFl); +terminate_crash_format(Module) when is_atom(Module) -> State = crash_terminate, - {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []), + {ok, Pid} = gen_server:start_link(Module, {state, State}, []), gen_server:call(Pid, stop), receive {'EXIT', Pid, {crash, terminate}} -> ok end, ClientPid = self(), @@ -1418,9 +2105,167 @@ terminate_crash_format(Config) when is_list(Config) -> io:format("Timeout: expected error logger msg", []), ct:fail(failed) end, - process_flag(trap_exit, OldFl), + receive + {error_report,_,_} -> ok + end, + ok. + +crash_in_format_status(Config) when is_list(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + crash_in_format_status(?MODULE, "gen_server_SUITE:format_status/2 crashed"), + crash_in_format_status(format_status_server, "format_status_server:format_status/1 crashed"), + process_flag(trap_exit, OldFl). +crash_in_format_status(Module, Match) when is_atom(Module) -> + State = fun(_) -> exit({crash,format_status}) end, + {ok, Pid} = gen_server:start_link(Module, {state, State}, []), + + {status,Pid, _, [_,_,_,_,Info]} = sys:get_status(Pid), + {data,[{"State",Match}]} = lists:last(Info), + + gen_server:call(Pid, stop), + receive {'EXIT', Pid, stopped} -> ok end, + ClientPid = self(), + receive + {error,_GroupLeader, + {Pid, + "** Generic server"++_, + [Pid, stop, Match, stopped, + ClientPid, [_|_] = _ClientStack]}} -> + ok; + Other -> + ct:pal("Unexpected: ~p", [Other]), + ct:fail(failed) + after 5000 -> + io:format("Timeout: expected error logger msg", []), + ct:fail(failed) + end, + receive + {error_report,_,_} -> ok + end, ok. +throw_in_format_status(Config) when is_list(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + throw_in_format_status(?MODULE,{throw,format_status}), + throw_in_format_status(format_status_server,"format_status_server:format_status/1 crashed"), + process_flag(trap_exit, OldFl). +throw_in_format_status(Module, Match) when is_atom(Module) -> + State = fun(_) -> throw({throw,format_status}) end, + {ok, Pid} = gen_server:start_link(Module, {state, State}, []), + + {status,Pid, _, [_,_,_,_,Info]} = sys:get_status(Pid), + case lists:last(Info) of + {data,[{"State",Match}]} -> + ok; + Match -> + ok + end, + + gen_server:call(Pid, stop), + receive {'EXIT', Pid, stopped} -> ok end, + ClientPid = self(), + receive + {error,_GroupLeader, + {Pid, "** Generic server"++_, + [Pid, stop, Match, stopped, + ClientPid, [_|_] = _ClientStack]}} -> + ok; + Other -> + ct:pal("Unexpected: ~p", [Other]), + ct:fail(failed) + after 5000 -> + io:format("Timeout: expected error logger msg", []), + ct:fail(failed) + end, + receive + {error_report,_,_} -> ok + end, + ok. + +%% Test that the state, reason, message format status calls works as they should +%% The test makes sure that both sys:get_status and the crash report works as they +%% should and can be used to strip data from both the reason, message, state and the +%% sys logger logs. + +%%%% The sys logger log messages that should be matched +-define(LOG_MESSAGES, + {log,{in,{_,_,started_p}}}, + {log,{out,ok,_,State}}, + {log,{in,{_,_,{delayed_answer,10}}}}, + {log,{noreply,{_,_,State}}}, + {log,{in,timeout}}, + {log,{noreply,State}}). + +format_all_status(Config) when is_list(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + + State = fun(M) -> + maps:map( + fun(log, Values) -> + [{log, Value} || Value <- Values]; + (Key, Value) -> + {Key, Value} + end, M) + end, + {ok, Pid} = gen_server:start_link(format_status_server, {state, State}, []), + sys:log(Pid, true), + ok = gen_server:call(Pid, started_p), + delayed = gen_server:call(Pid, {delayed_answer, 10}), + + {status,Pid, _, [_,_,_,_,Info]} = sys:get_status(Pid), + [{header, _Hdr}, + {data, [_Status,_Parent,{"Logged events",LoggedEvents}]}, + {data, [{"State",{state,State}}]}] = Info, + + [?LOG_MESSAGES] = LoggedEvents, + + ok = gen_server:call(Pid, stop), + receive {'EXIT', Pid, stopped} -> ok end, + ClientPid = self(), + receive + {error,_GroupLeader, + {Pid, "** Generic server"++_, + [Pid, {message, stop}, {state,State}, {reason, stopped}, + ?LOG_MESSAGES, {log,{in,{_,_,stop}}}, + ClientPid, [_|_] = _ClientStack]}} -> + ok; + Other -> + ct:pal("Unexpected: ~p", [Other]), + ct:fail(failed) + after 5000 -> + io:format("Timeout: expected error logger msg", []), + ct:fail(failed) + end, + receive + {error_report,_,_} -> ok + end, + + {ok, Pid2} = gen_server:start_link(format_status_server, {state, State}, []), + catch gen_server:call(Pid2, crash), + receive {'EXIT', Pid2, crashed} -> ok end, + receive + {error,_GroupLeader2, + {Pid2, "** Generic server"++_, + [Pid2, {message, crash}, {state,State}, + {{reason, crashed},[_|_] = _ServerStack}, + ClientPid, [_|_] = _ClientStack2]}} -> + ok; + Other2 -> + ct:pal("Unexpected: ~p", [Other2]), + ct:fail(failed) + after 5000 -> + io:format("Timeout: expected error logger msg", []), + ct:fail(failed) + end, + receive + {error_report,_,_} -> ok + end, + + process_flag(trap_exit, OldFl). + %% Verify that sys:get_state correctly returns gen_server state get_state(Config) when is_list(Config) -> State = self(), @@ -1534,11 +2379,10 @@ undef_init(_Config) -> {error, {undef, [{oc_init_server, init, [_], _}|_]}} = (catch gen_server:start_link(oc_init_server, [], [])), receive - {'EXIT', Server, - {undef, [{oc_init_server, init, [_], _}|_]}} when is_pid(Server) -> + Msg -> + ct:fail({unexpected_msg, Msg}) + after 500 -> ok - after 1000 -> - ct:fail(expected_exit_msg) end. %% The upgrade should fail if code_change is expected in the callback module @@ -1968,30 +2812,52 @@ spec_init_not_proc_lib(Options) -> init([]) -> {ok, []}; init(ignore) -> + io:format("init(ignore)~n"), ignore; +init({error, Reason}) -> + io:format("init(error) -> ~w~n", [Reason]), + {error, Reason}; init(stop) -> + io:format("init(stop)~n"), {stop, stopped}; init(hibernate) -> + io:format("init(hibernate)~n"), {ok,[],hibernate}; init(sleep) -> + io:format("init(sleep)~n"), ct:sleep(1000), {ok, []}; init({continue, Pid}) -> + io:format("init(continue) -> ~p~n", [Pid]), self() ! {after_continue, Pid}, {ok, [], {continue, {message, Pid}}}; init({state,State}) -> - {ok,State}. + io:format("init(state) -> ~p~n", [State]), + {ok,State}; +init({ets,InitResult}) -> + ?MODULE = ets:new(?MODULE, [named_table]), + case InitResult of + {return, Value} -> + Value; + {crash, Class, Reason} -> + erlang:Class(Reason); + {wait, Time, Value} -> + receive after Time -> Value end + end. handle_call(started_p, _From, State) -> io:format("FROZ"), {reply,ok,State}; -handle_call({delayed_answer, T}, From, _State) -> - {noreply,{reply_to,From},T}; +handle_call(ping, _From, State) -> + {reply,pong,State}; +handle_call({delayed_answer, T}, From, State) -> + {noreply,{reply_to,From,State},T}; handle_call({call_within, T}, _From, _) -> {reply,ok,call_within,T}; handle_call(next_call, _From, call_within) -> {reply,ok,[]}; handle_call(next_call, _From, State) -> + io:format("handle_call(next_call) -> State: ~p~n", [State]), {reply,false,State}; handle_call(badreturn, _From, _State) -> badreturn; @@ -2042,9 +2908,9 @@ handle_cast({From, stop}, State) -> io:format("BAZ"), {stop, {From,stopped}, State}. -handle_info(timeout, {reply_to, From}) -> +handle_info(timeout, {reply_to, From, State}) -> gen_server:reply(From, delayed), - {noreply, []}; + {noreply, State}; handle_info(timeout, hibernate_me) -> % Arrive here from % handle_info(hibernate_later,...) {noreply, [], hibernate}; @@ -2124,7 +2990,34 @@ terminate(_, {undef_in_terminate, {Mod, Fun}}) -> terminate(_Reason, _State) -> ok. +format_status(_, [_PDict, Fun] = S) when is_function(Fun) -> + Fun(S); format_status(terminate, [_PDict, State]) -> {formatted, State}; format_status(normal, [_PDict, _State]) -> format_status_called. + +%% Utils... + +wait_until(Fun) -> + case catch Fun() of + true -> + ok; + _ -> + receive after 100 -> ok end, + wait_until(Fun) + end. + +old_release(N) -> + OldRel = integer_to_list(list_to_integer(erlang:system_info(otp_release))-N), + {OldRel++"_latest", OldRel}. + +flush_msgq() -> + flush_msgq(0). +flush_msgq(N) -> + receive + _ -> + flush_msgq(N+1) + after 0 -> + N + end. diff --git a/lib/stdlib/test/gen_server_SUITE_data/format_status_server.erl b/lib/stdlib/test/gen_server_SUITE_data/format_status_server.erl new file mode 100644 index 000000000000..96f1f74132c8 --- /dev/null +++ b/lib/stdlib/test/gen_server_SUITE_data/format_status_server.erl @@ -0,0 +1,55 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017-2021. 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(format_status_server). + +-behaviour(gen_server). + +%% API +-export([start/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, format_status/1]). + +start(Arg) -> + gen_server:start(?MODULE, ok, Arg). +init(Args) -> + gen_server_SUITE:init(Args). +handle_call(Call, From, State) -> + gen_server_SUITE:handle_call(Call, From, State). +handle_cast(Cast, State) -> + gen_server_SUITE:handle_cast(Cast, State). +handle_info(Info, State) -> + gen_server_SUITE:handle_info(Info, State). +terminate(Reason, State) -> + gen_server_SUITE:terminate(Reason, State). + +format_status(#{ state := Fun } = S) when is_function(Fun) -> + Fun(S); +format_status(#{ state := {_,_,Fun} } = S) when is_function(Fun) -> + Fun(S); +format_status(#{ message := Msg } = S) when not is_map_key(state, S) -> + S#{message := {message,Msg}}; +format_status(#{ reason := _, state := State } = Map) -> + ct:pal("format_status(~p)",[Map]), + Map#{ state => {formatted, State}}; +format_status(Map) -> + ct:pal("format_status(~p)",[Map]), + Map#{ state => format_status_called }. diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 88cc2c412b9c..8257cd3b3b04 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2016-2022. All Rights Reserved. +%% Copyright Ericsson AB 2016-2023. 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. @@ -37,13 +37,15 @@ all() -> {group, stop_handle_event}, {group, abnormal}, {group, abnormal_handle_event}, - shutdown, stop_and_reply, state_enter, event_order, + shutdown, loop_start_fail, stop_and_reply, state_enter, event_order, state_timeout, timeout_cancel_and_update, event_types, generic_timers, code_change, {group, sys}, hibernate, auto_hibernate, enter_loop, {group, undef_callbacks}, undef_in_terminate, {group, format_log}, - reply_by_alias_with_payload]. + reply_by_alias_with_payload, + send_request_receive_reqid_collection, send_request_wait_reqid_collection, + send_request_check_reqid_collection]. groups() -> [{start, [], tcs(start)}, @@ -53,12 +55,13 @@ groups() -> {abnormal, [], tcs(abnormal)}, {abnormal_handle_event, [], tcs(abnormal)}, {sys, [], tcs(sys)}, + {format_status, [], tcs(format_status)}, {sys_handle_event, [], tcs(sys)}, {undef_callbacks, [], tcs(undef_callbacks)}, {format_log, [], tcs(format_log)}]. tcs(start) -> - [start1, start2, start3, start4, start5, start6, start7, + [start1, start2, start3, start4, start5a, start5b, start6, start7, start8, start9, start10, start11, start12, next_events]; tcs(stop) -> [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]; @@ -66,9 +69,10 @@ tcs(abnormal) -> [abnormal1, abnormal1clean, abnormal1dirty, abnormal2, abnormal3, abnormal4]; tcs(sys) -> - [sys1, call_format_status, - error_format_status, terminate_crash_format, - get_state, replace_state]; + [sys1, {group, format_status}, get_state, replace_state]; +tcs(format_status) -> + [call_format_status, error_format_status, terminate_crash_format, + format_all_status]; tcs(undef_callbacks) -> [undef_code_change, undef_terminate1, undef_terminate2, pop_too_many]; @@ -93,6 +97,9 @@ init_per_group(undef_callbacks, Config) -> {fail,{Class,Reason,Stacktrace}} end, Config; +init_per_group(sys, Config) -> + compile_format_status_statem(Config), + Config; init_per_group(_GroupName, Config) -> Config. @@ -122,6 +129,12 @@ compile_oc_statem(Config) -> {ok, oc_statem} = compile:file(StatemPath), ok. +compile_format_status_statem(Config) -> + DataDir = ?config(data_dir, Config), + StatemPath = filename:join(DataDir, "format_status_statem.erl"), + {ok, format_status_statem} = compile:file(StatemPath), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(EXPECT_FAILURE(Code, Reason), try begin Code end of @@ -197,7 +210,7 @@ start4(Config) -> ok = verify_empty_msgq(). %% anonymous with stop -start5(Config) -> +start5a(Config) -> OldFl = process_flag(trap_exit, true), {error,stopped} = gen_statem:start(?MODULE, start_arg(Config, stop), []), @@ -205,6 +218,16 @@ start5(Config) -> process_flag(trap_exit, OldFl), ok = verify_empty_msgq(). +%% anonymous with shutdown +start5b(Config) -> + OldFl = process_flag(trap_exit, true), + + {error, foobar} = + gen_statem:start(?MODULE, start_arg(Config, {error, foobar}), []), + + process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + %% anonymous linked start6(Config) -> {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), @@ -455,76 +478,64 @@ stop7(Config) -> %% Anonymous on remote node stop8(Config) -> - Node = gen_statem_stop8, - {ok,NodeName} = ct_slave:start(Node), - Statem = - try - Dir = filename:dirname(code:which(?MODULE)), - rpc:block_call(NodeName, code, add_path, [Dir]), - {ok,Pid} = - rpc:block_call( - NodeName, gen_statem,start, - [?MODULE,start_arg(Config, []),[]]), - ok = gen_statem:stop(Pid), - false = rpc:block_call(NodeName, erlang, is_process_alive, [Pid]), - noproc = - ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason1), - Pid - after - {ok,NodeName} = ct_slave:stop(Node) - end, + {ok,Peer,NodeName} = ?CT_PEER(), + Dir = filename:dirname(code:which(?MODULE)), + rpc:block_call(NodeName, code, add_path, [Dir]), + {ok,Pid} = + rpc:block_call( + NodeName, gen_statem,start, + [?MODULE,start_arg(Config, []),[]]), + ok = gen_statem:stop(Pid), + false = rpc:block_call(NodeName, erlang, is_process_alive, [Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason1), + + peer:stop(Peer), {{nodedown,NodeName},{sys,terminate,_}} = - ?EXPECT_FAILURE(gen_statem:stop(Statem), Reason2), + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason2), ok. %% Registered name on remote node stop9(Config) -> Name = to_stop, LocalSTM = {local,Name}, - Node = gen_statem__stop9, - {ok,NodeName} = ct_slave:start(Node), - Statem = - try - STM = {Name,NodeName}, - Dir = filename:dirname(code:which(?MODULE)), - rpc:block_call(NodeName, code, add_path, [Dir]), - {ok,Pid} = - rpc:block_call( - NodeName, gen_statem, start, - [LocalSTM,?MODULE,start_arg(Config, []),[]]), - ok = gen_statem:stop(STM), - undefined = rpc:block_call(NodeName,erlang,whereis,[Name]), - false = rpc:block_call(NodeName,erlang,is_process_alive,[Pid]), - noproc = - ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), - STM - after - {ok,NodeName} = ct_slave:stop(Node) - end, + {ok,Peer,NodeName} = ?CT_PEER(), + + STM = {Name,NodeName}, + Dir = filename:dirname(code:which(?MODULE)), + rpc:block_call(NodeName, code, add_path, [Dir]), + {ok,Pid} = + rpc:block_call( + NodeName, gen_statem, start, + [LocalSTM,?MODULE,start_arg(Config, []),[]]), + ok = gen_statem:stop(STM), + undefined = rpc:block_call(NodeName,erlang,whereis,[Name]), + false = rpc:block_call(NodeName,erlang,is_process_alive,[Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), + peer:stop(Peer), + {{nodedown,NodeName},{sys,terminate,_}} = - ?EXPECT_FAILURE(gen_statem:stop(Statem), Reason2), + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), ok. %% Globally registered name on remote node stop10(Config) -> - Node = gen_statem_stop10, STM = {global,to_stop}, - {ok,NodeName} = ct_slave:start(Node), - try - Dir = filename:dirname(code:which(?MODULE)), - rpc:block_call(NodeName,code,add_path,[Dir]), - {ok,Pid} = - rpc:block_call( - NodeName, gen_statem, start, - [STM,?MODULE,start_arg(Config, []),[]]), - global:sync(), - ok = gen_statem:stop(STM), - false = rpc:block_call(NodeName, erlang, is_process_alive, [Pid]), - noproc = - ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1) - after - {ok,NodeName} = ct_slave:stop(Node) - end, + {ok,Peer,NodeName} = ?CT_PEER(), + Dir = filename:dirname(code:which(?MODULE)), + rpc:block_call(NodeName,code,add_path,[Dir]), + {ok,Pid} = + rpc:block_call( + NodeName, gen_statem, start, + [STM,?MODULE,start_arg(Config, []),[]]), + global:sync(), + ok = gen_statem:stop(STM), + false = rpc:block_call(NodeName, erlang, is_process_alive, [Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), + peer:stop(Peer), + noproc = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), ok. @@ -675,6 +686,53 @@ shutdown(Config) -> end. +loop_start_fail(Config) -> + _ = process_flag(trap_exit, true), + loop_start_fail( + Config, + [{start, []}, {start, [link]}, + {start_link, []}, + {start_monitor, [link]}, {start_monitor, []}]). + +loop_start_fail(_Config, []) -> + ok; +loop_start_fail(Config, [{Start, Opts} | Start_Opts]) -> + loop_start_fail( + fun gen_statem:Start/3, + {ets, {return, {stop, failed_to_start}}}, Opts, + fun ({error, failed_to_start}) -> ok end), + loop_start_fail( + fun gen_statem:Start/3, + {ets, {return, ignore}}, Opts, + fun (ignore) -> ok end), + loop_start_fail( + fun gen_statem:Start/3, + {ets, {return, 4711}}, Opts, + fun ({error, {bad_return_from_init, 4711}}) -> ok end), + loop_start_fail( + fun gen_statem:Start/3, + {ets, {crash, error, bailout}}, Opts, + fun ({error, bailout}) -> ok end), + loop_start_fail( + fun gen_statem:Start/3, + {ets, {crash, exit, bailout}}, Opts, + fun ({error, bailout}) -> ok end), + loop_start_fail( + fun gen_statem:Start/3, + {ets, {wait, 1000, void}}, [{timeout, 200} | Opts], + fun ({error, timeout}) -> ok end), + loop_start_fail(Config, Start_Opts). + +loop_start_fail(GenStartFun, Arg, Opts, ValidateFun) -> + loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, 5). +%% +loop_start_fail(_GenStartFun, _Arg, _Opts, _ValidateFun, 0) -> + ok; +loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, N) -> + ok = ValidateFun(GenStartFun(?MODULE, Arg, Opts)), + loop_start_fail(GenStartFun, Arg, Opts, ValidateFun, N - 1). + + stop_and_reply(_Config) -> process_flag(trap_exit, true), @@ -1243,20 +1301,24 @@ code_change(_Config) -> stop_it(Pid). call_format_status(Config) -> - {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), + call_format_status(Config,?MODULE,format_status_called), + call_format_status(Config, format_status_statem, + {data,[{"State",{format_status_called,format_data}}]}). +call_format_status(Config, Module, Match) -> + {ok,Pid} = gen_statem:start(Module, start_arg(Config, []), []), Status = sys:get_status(Pid), {status,Pid,_Mod,[_PDict,running,_,_, Data]} = Status, - [format_status_called|_] = lists:reverse(Data), + [Match|_] = lists:reverse(Data), stop_it(Pid), %% check that format_status can handle a name being an atom (pid is %% already checked by the previous test) {ok, Pid2} = gen_statem:start( - {local, gstm}, ?MODULE, start_arg(Config, []), []), + {local, gstm}, Module, start_arg(Config, []), []), Status2 = sys:get_status(gstm), {status,Pid2,Mod,[_PDict2,running,_,_,Data2]} = Status2, - [format_status_called|_] = lists:reverse(Data2), + [Match|_] = lists:reverse(Data2), stop_it(Pid2), %% check that format_status can handle a name being a term other than a @@ -1264,47 +1326,54 @@ call_format_status(Config) -> GlobalName1 = {global,"CallFormatStatus"}, {ok,Pid3} = gen_statem:start( - GlobalName1, ?MODULE, start_arg(Config, []), []), + GlobalName1, Module, start_arg(Config, []), []), Status3 = sys:get_status(GlobalName1), {status,Pid3,Mod,[_PDict3,running,_,_,Data3]} = Status3, - [format_status_called|_] = lists:reverse(Data3), + [Match|_] = lists:reverse(Data3), stop_it(Pid3), GlobalName2 = {global,{name, "term"}}, {ok,Pid4} = gen_statem:start( - GlobalName2, ?MODULE, start_arg(Config, []), []), + GlobalName2, Module, start_arg(Config, []), []), Status4 = sys:get_status(GlobalName2), {status,Pid4,Mod,[_PDict4,running,_,_, Data4]} = Status4, - [format_status_called|_] = lists:reverse(Data4), + [Match|_] = lists:reverse(Data4), stop_it(Pid4), %% check that format_status can handle a name being a term other than a %% pid or atom dummy_via:reset(), ViaName1 = {via,dummy_via,"CallFormatStatus"}, - {ok,Pid5} = gen_statem:start(ViaName1, ?MODULE, start_arg(Config, []), []), + {ok,Pid5} = gen_statem:start(ViaName1, Module, start_arg(Config, []), []), Status5 = sys:get_status(ViaName1), {status,Pid5,Mod, [_PDict5,running,_,_, Data5]} = Status5, - [format_status_called|_] = lists:reverse(Data5), + [Match|_] = lists:reverse(Data5), stop_it(Pid5), ViaName2 = {via,dummy_via,{name,"term"}}, {ok, Pid6} = gen_statem:start( - ViaName2, ?MODULE, start_arg(Config, []), []), + ViaName2, Module, start_arg(Config, []), []), Status6 = sys:get_status(ViaName2), {status,Pid6,Mod,[_PDict6,running,_,_,Data6]} = Status6, - [format_status_called|_] = lists:reverse(Data6), + [Match|_] = lists:reverse(Data6), stop_it(Pid6). - - error_format_status(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), + try + error_format_status(Config,?MODULE,{formatted,idle,"called format_status"}), + error_format_status(Config,format_status_statem, + {{formatted,idle},{formatted,"called format_status"}}) + after + process_flag(trap_exit, OldFl), + error_logger_forwarder:unregister() + end. +error_format_status(Config,Module,Match) -> Data = "called format_status", {ok,Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {data,Data}), []), + Module, start_arg(Config, {data,Data}), []), %% bad return value in the gen_statem loop {{{bad_return_from_state_function,badreturn},_},_} = ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), @@ -1313,18 +1382,15 @@ error_format_status(Config) -> {Pid, "** State machine"++_, [Pid,{{call,_},badreturn}, - {formatted,idle,Data}, + Match, error,{bad_return_from_state_function,badreturn}|_]}} -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> - error_logger_forwarder:unregister(), ct:fail({unexpected,Other}) after 1000 -> - error_logger_forwarder:unregister(), - ct:fail(timeout) + ct:fail({timeout,(fun F() -> receive M -> [M|F()] after 0 -> [] end end)()}) end, - process_flag(trap_exit, OldFl), - error_logger_forwarder:unregister(), + receive %% Comes with SASL {error_report,_,{Pid,crash_report,_}} -> @@ -1335,12 +1401,24 @@ error_format_status(Config) -> ok = verify_empty_msgq(). terminate_crash_format(Config) -> + dbg:tracer(), error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), + try + terminate_crash_format(Config,?MODULE,{formatted,idle,crash_terminate}), + terminate_crash_format(Config,format_status_statem, + {{formatted,idle},{formatted,crash_terminate}}) + after + dbg:stop(), + process_flag(trap_exit, OldFl), + error_logger_forwarder:unregister() + end. + +terminate_crash_format(Config, Module, Match) -> Data = crash_terminate, {ok,Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {data,Data}), []), + Module, start_arg(Config, {data,Data}), []), stop_it(Pid), Self = self(), receive @@ -1349,18 +1427,14 @@ terminate_crash_format(Config) -> "** State machine"++_, [Pid, {{call,{Self,_}},stop}, - {formatted,idle,Data}, - exit,{crash,terminate}|_]}} -> + Match,exit,{crash,terminate}|_]}} -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> - error_logger_forwarder:unregister(), ct:fail({unexpected,Other}) after 1000 -> - error_logger_forwarder:unregister(), - ct:fail(timeout) + ct:fail({timeout,flush()}) end, - process_flag(trap_exit, OldFl), - error_logger_forwarder:unregister(), + receive %% Comes with SASL {error_report,_,{Pid,crash_report,_}} -> @@ -1370,6 +1444,67 @@ terminate_crash_format(Config) -> end, ok = verify_empty_msgq(). +%% We test that all of the different status items can be +%% formatted by the format_status/1 callback. +format_all_status(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + + Data = fun(M) -> + maps:map( + fun(Key, Values) when Key =:= log; + Key =:= queue; + Key =:= postponed; + Key =:= timeouts -> + [{Key, Value} || Value <- Values]; + (Key, Value) -> + {Key, Value} + end, M) + end, + {ok,Pid} = + gen_statem:start( + format_status_statem, start_arg(Config, {data,Data}), []), + sys:log(Pid, true), + ok = gen_statem:cast(Pid, postpone_event), + ok = gen_statem:cast(Pid, {timeout, 100000}), + + {status,Pid, _, [_,_,_,_,Info]} = sys:get_status(Pid), + [{header, _Hdr}, + {data, [_Status,_Parent,_Modules, + {"Time-outs",{1,[{timeouts,_}]}}, + {"Logged Events",[{log,_}|_]}, + {"Postponed",[{postponed,_}]}]}, + {data, [{"State",{{state,idle},{data,Data}}}]}] = Info, + + %% bad return value in the gen_statem loop + {{{bad_return_from_state_function,badreturn},_},_} = + ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), + Self = self(), + receive + {error,_GroupLeader, + {Pid, + "** State machine"++_, + [Pid, + {queue,{{call,{Self,_}},badreturn}}, + {{state,idle},{data,Data}},error, + {reason,{bad_return_from_state_function,badreturn}}, + __Modules,_StateFunctions, + [{postponed,{cast,postpone_event}}], + [_|_] = _Stacktrace, + {1,[{timeouts,{timeout,idle}}]}, + [{log,_}|_] |_]}} -> + ok; + Other when is_tuple(Other), element(1, Other) =:= error -> + ct:fail({unexpected,Other}) + after 1000 -> + ct:fail({timeout,flush()}) + end, + receive + {error_report,_,_} -> ok + end, + error_logger_forwarder:unregister(), + process_flag(trap_exit, OldFl), + ok. get_state(Config) -> State = self(), @@ -1428,17 +1563,25 @@ replace_state(Config) -> {state0,NState3} = sys:replace_state(Pid, Replace4), ok = sys:resume(Pid), {state0,NState3} = sys:get_state(Pid, 5000), + %% State 'error' does not exist but is never touched, + %% just verify that sys handles it as a state, not as an error return + {error,NState3} = + sys:replace_state(Pid, fun ({state0, SD}) -> {error, SD} end), + {error, NState3} = sys:get_state(Pid), + {state0,NState3} = + sys:replace_state(Pid, fun ({error, SD}) -> {state0, SD} end), stop_it(Pid), ok = verify_empty_msgq(). %% Hibernation hibernate(Config) -> OldFl = process_flag(trap_exit, true), + WaitHibernate = 500, {ok,Pid0} = gen_statem:start_link( ?MODULE, start_arg(Config, hiber_now), []), - wait_erlang_hibernate(Pid0), + wait_erlang_hibernate(Pid0, WaitHibernate), stop_it(Pid0), receive {'EXIT',Pid0,normal} -> ok @@ -1451,38 +1594,38 @@ hibernate(Config) -> true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), good_morning = gen_statem:call(Pid, wakeup_sync), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), hibernating = gen_statem:call(Pid, hibernate_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), please_just_five_more = gen_statem:call(Pid, snooze_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), good_morning = gen_statem:call(Pid, wakeup_sync), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, hibernate_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, wakeup_async), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, hibernate_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, snooze_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, wakeup_async), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), - Pid ! hibernate_later, + Pid ! {hibernate_later, WaitHibernate div 2}, true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), 'alive!' = gen_statem:call(Pid, 'alive?'), true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), Pid ! hibernate_now, - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), 'alive!' = gen_statem:call(Pid, 'alive?'), true = @@ -1490,37 +1633,37 @@ hibernate(Config) -> erlang:process_info(Pid, current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), good_morning = gen_statem:call(Pid, wakeup_sync), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), hibernating = gen_statem:call(Pid, hibernate_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), please_just_five_more = gen_statem:call(Pid, snooze_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), good_morning = gen_statem:call(Pid, wakeup_sync), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, hibernate_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, wakeup_async), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, hibernate_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, snooze_async), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), ok = gen_statem:cast(Pid, wakeup_async), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), hibernating = gen_statem:call(Pid, hibernate_sync), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), sys:suspend(Pid), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), sys:resume(Pid), - wait_erlang_hibernate(Pid), - receive after 1000 -> ok end, - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, WaitHibernate), + receive after WaitHibernate -> ok end, + wait_erlang_hibernate(Pid, WaitHibernate), good_morning = gen_statem:call(Pid, wakeup_sync), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, WaitHibernate), stop_it(Pid), process_flag(trap_exit, OldFl), receive @@ -1533,73 +1676,74 @@ hibernate(Config) -> %% Auto-hibernation timeout auto_hibernate(Config) -> OldFl = process_flag(trap_exit, true), - HibernateAfterTimeout = 1000, + HibernateAfterTimeout = 500, + WaitTime = 1000, {ok,Pid} = gen_statem:start_link( ?MODULE, start_arg(Config, []), [{hibernate_after, HibernateAfterTimeout}]), %% After init test - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), %% After info test Pid ! {hping, self()}, receive {Pid, hpong} -> ok - after 1000 -> + after WaitTime -> ct:fail(info) end, - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), %% After cast test ok = gen_statem:cast(Pid, {hping, self()}), receive {Pid, hpong} -> ok - after 1000 -> + after WaitTime -> ct:fail(cast) end, - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), %% After call test hpong = gen_statem:call(Pid, hping), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), %% Timer test 1 TimerTimeout1 = HibernateAfterTimeout div 2, ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout1}), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(TimerTimeout1), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), receive {Pid, htimer_timeout} -> ok - after 1000 -> + after WaitTime -> ct:fail(timer1) end, - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), %% Timer test 2 TimerTimeout2 = HibernateAfterTimeout * 2, ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout2}), - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), receive {Pid, htimer_timeout} -> ok after TimerTimeout2 -> ct:fail(timer2) end, - is_not_in_erlang_hibernate(Pid), + is_not_in_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), timer:sleep(HibernateAfterTimeout), - wait_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid, 2 * HibernateAfterTimeout), stop_it(Pid), process_flag(trap_exit, OldFl), receive @@ -1610,35 +1754,35 @@ auto_hibernate(Config) -> ok = verify_empty_msgq(). -wait_erlang_hibernate(Pid) -> +wait_erlang_hibernate(Pid, Time) -> receive after 1 -> ok end, - wait_erlang_hibernate_1(200, Pid). + wait_erlang_hibernate_1(Pid, Time, Time div 100). -wait_erlang_hibernate_1(0, Pid) -> +wait_erlang_hibernate_1(Pid, Time, _T) when Time =< 0 -> ct:log("~p\n", [erlang:process_info(Pid, current_function)]), ct:fail(should_be_in_erlang_hibernate_3); -wait_erlang_hibernate_1(N, Pid) -> +wait_erlang_hibernate_1(Pid, Time, T) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of {erlang,hibernate,3} -> ok; _ -> - receive after 10 -> ok end, - wait_erlang_hibernate_1(N-1, Pid) + receive after T -> ok end, + wait_erlang_hibernate_1(Pid, Time - T, T) end. -is_not_in_erlang_hibernate(Pid) -> +is_not_in_erlang_hibernate(Pid, Time) -> receive after 1 -> ok end, - is_not_in_erlang_hibernate_1(200, Pid). + is_not_in_erlang_hibernate_1(Pid, Time, Time div 100). -is_not_in_erlang_hibernate_1(0, _Pid) -> +is_not_in_erlang_hibernate_1(_Pid, Time, _T) when Time =< 0 -> ct:fail(should_not_be_in_erlang_hibernate_3); -is_not_in_erlang_hibernate_1(N, Pid) -> +is_not_in_erlang_hibernate_1(Pid, Time, T) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of {erlang,hibernate,3} -> - receive after 10 -> ok end, - is_not_in_erlang_hibernate_1(N-1, Pid); + receive after T -> ok end, + is_not_in_erlang_hibernate_1(Pid, Time - T, T); _ -> ok end. @@ -2235,6 +2379,311 @@ reply_by_alias_with_payload(Config) when is_list(Config) -> ok end. +send_request_receive_reqid_collection(Config) when is_list(Config) -> + {ok,Pid1} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid2} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid3} = gen_statem:start(?MODULE, start_arg(Config, []), []), + send_request_receive_reqid_collection(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3), + stopped = gen_statem:call(Pid1, {stop,shutdown}), + stopped = gen_statem:call(Pid3, {stop,shutdown}), + check_stopped(Pid1), + check_stopped(Pid2), + check_stopped(Pid3), + ok. + +send_request_receive_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_statem:reqids_size(ReqIdC1), + + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_statem:reqids_size(ReqIdC2), + + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_statem:receive_response(ReqIdC3, infinity, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_statem:receive_response(ReqIdC4, 5678, true), + 1 = gen_statem:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_statem:receive_response(ReqIdC5, 5000, true), + 0 = gen_statem:reqids_size(ReqIdC6), + + no_request = gen_statem:receive_response(ReqIdC6, 5000, true), + + {reply, yes} = gen_statem:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,1000}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_statem:send_request(Pid3, {delayed_answer,500}), + ReqIdC3 = gen_statem:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_statem:receive_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + timeout = gen_statem:receive_response(ReqIdC4, {abs, Deadline}, true), + + Abandoned = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Abandoned = lists:sort(gen_statem:reqids_to_list(ReqIdC4)), + + %% Make sure requests were abandoned... + timeout = gen_statem:receive_response(ReqIdC4, {abs, Deadline+1000}, true), + + {reply, yes} = gen_statem:receive_response(ReqId0, infinity), + + ok. + +send_request_receive_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_statem:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + {{error, {noproc, _}}, req2, ReqIdC4} = gen_statem:receive_response(ReqIdC3, 2000, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_statem:receive_response(ReqIdC4, infinity, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_statem:receive_response(ReqIdC4, infinity, false), + + {reply, yes} = gen_statem:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection(Config) when is_list(Config) -> + {ok,Pid1} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid2} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid3} = gen_statem:start(?MODULE, start_arg(Config, []), []), + send_request_wait_reqid_collection(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3), + send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3), + stopped = gen_statem:call(Pid1, {stop,shutdown}), + stopped = gen_statem:call(Pid3, {stop,shutdown}), + check_stopped(Pid1), + check_stopped(Pid2), + check_stopped(Pid3), + ok. + +send_request_wait_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + 1 = gen_statem:reqids_size(ReqIdC1), + + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + 2 = gen_statem:reqids_size(ReqIdC2), + + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + {{reply, delayed}, req2, ReqIdC4} = gen_statem:wait_response(ReqIdC3, infinity, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_statem:wait_response(ReqIdC4, 5678, true), + 1 = gen_statem:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_statem:wait_response(ReqIdC5, 5000, true), + 0 = gen_statem:reqids_size(ReqIdC6), + + no_request = gen_statem:wait_response(ReqIdC6, 5000, true), + + {reply, yes} = gen_statem:receive_response(ReqId0, infinity), + + ok. + +send_request_wait_reqid_collection_timeout(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,1000}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + + ReqId3 = gen_statem:send_request(Pid3, {delayed_answer,500}), + ReqIdC3 = gen_statem:reqids_add(ReqId3, req3, ReqIdC2), + + Deadline = erlang:monotonic_time(millisecond) + 100, + + {{reply, delayed}, req2, ReqIdC4} = gen_statem:wait_response(ReqIdC3, {abs, Deadline}, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + timeout = gen_statem:wait_response(ReqIdC4, {abs, Deadline}, true), + + Unhandled = lists:sort([{ReqId1, req1}, {ReqId3, req3}]), + Unhandled = lists:sort(gen_statem:reqids_to_list(ReqIdC4)), + + %% Make sure requests were not abandoned... + {{reply, delayed}, req3, ReqIdC4} = gen_statem:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + {{reply, delayed}, req1, ReqIdC4} = gen_statem:wait_response(ReqIdC4, {abs, Deadline+1500}, false), + + {reply, yes} = gen_statem:receive_response(ReqId0), + + ok. + +send_request_wait_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_statem:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + {{error, {noproc, _}}, req2, ReqIdC4} = gen_statem:wait_response(ReqIdC3, 2000, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_statem:wait_response(ReqIdC4, infinity, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_statem:wait_response(ReqIdC4, infinity, false), + + {reply, yes} = gen_statem:receive_response(ReqId0, infinity), + + ok. + +send_request_check_reqid_collection(Config) when is_list(Config) -> + {ok,Pid1} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid2} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {ok,Pid3} = gen_statem:start(?MODULE, start_arg(Config, []), []), + send_request_check_reqid_collection(Pid1, Pid2, Pid3), + send_request_check_reqid_collection_error(Pid1, Pid2, Pid3), + stopped = gen_statem:call(Pid1, {stop,shutdown}), + stopped = gen_statem:call(Pid3, {stop,shutdown}), + check_stopped(Pid1), + check_stopped(Pid2), + check_stopped(Pid3), + ok. + +send_request_check_reqid_collection(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + receive after 100 -> ok end, + + ReqIdC0 = gen_statem:reqids_new(), + + ReqIdC1 = gen_statem:send_request(Pid1, {delayed_answer,400}, req1, ReqIdC0), + 1 = gen_statem:reqids_size(ReqIdC1), + + ReqId2 = gen_statem:send_request(Pid2, {delayed_answer,1}), + ReqIdC2 = gen_statem:reqids_add(ReqId2, req2, ReqIdC1), + 2 = gen_statem:reqids_size(ReqIdC2), + + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + Msg0 = next_msg(), + no_reply = gen_statem:check_response(Msg0, ReqIdC3, true), + + {{reply, delayed}, req2, ReqIdC4} = gen_statem:check_response(next_msg(), ReqIdC3, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC5} = gen_statem:check_response(next_msg(), ReqIdC4, true), + 1 = gen_statem:reqids_size(ReqIdC5), + + {{reply, delayed}, req1, ReqIdC6} = gen_statem:check_response(next_msg(), ReqIdC5, true), + 0 = gen_statem:reqids_size(ReqIdC6), + + no_request = gen_statem:check_response(Msg0, ReqIdC6, true), + + {reply, yes} = gen_statem:check_response(Msg0, ReqId0), + + ok. + +send_request_check_reqid_collection_error(Pid1, Pid2, Pid3) -> + + ReqId0 = gen_statem:send_request(Pid1, 'alive?'), + + receive after 100 -> ok end, + + ReqIdC0 = gen_statem:reqids_new(), + + ReqId1 = gen_statem:send_request(Pid1, {delayed_answer,400}), + ReqIdC1 = gen_statem:reqids_add(ReqId1, req1, ReqIdC0), + try + nope = gen_statem:reqids_add(ReqId1, req2, ReqIdC1) + catch + error:badarg -> ok + end, + + unlink(Pid2), + exit(Pid2, kill), + ReqIdC2 = gen_statem:send_request(Pid2, {delayed_answer,1}, req2, ReqIdC1), + + ReqIdC3 = gen_statem:send_request(Pid3, {delayed_answer,200}, req3, ReqIdC2), + 3 = gen_statem:reqids_size(ReqIdC3), + + Msg0 = next_msg(), + + no_reply = gen_statem:check_response(Msg0, ReqIdC3, true), + + {{error, {noproc, _}}, req2, ReqIdC4} = gen_statem:check_response(next_msg(), ReqIdC3, true), + 2 = gen_statem:reqids_size(ReqIdC4), + + {{reply, delayed}, req3, ReqIdC4} = gen_statem:check_response(next_msg(), ReqIdC4, false), + + {{reply, delayed}, req1, ReqIdC4} = gen_statem:check_response(next_msg(), ReqIdC4, false), + + {reply, yes} = gen_statem:check_response(Msg0, ReqId0), + + ok. + +next_msg() -> + receive M -> M end. + %% %% Functionality check %% @@ -2368,25 +2817,37 @@ start_arg(Config, Arg) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init(ignore) -> + io:format("init(ignore)~n", []), ignore; init(stop) -> + io:format("init(stop)~n", []), {stop,stopped}; +init({error, Reason}) -> + io:format("init(error) -> Reason: ~p~n", [Reason]), + {error, Reason}; init(stop_shutdown) -> + io:format("init(stop_shutdown)~n", []), {stop,shutdown}; init(sleep) -> + io:format("init(sleep)~n", []), ct:sleep(1000), init_sup({ok,idle,data}); init(hiber) -> + io:format("init(hiber)~n", []), init_sup({ok,hiber_idle,[]}); init(hiber_now) -> + io:format("init(hiber_now)~n", []), init_sup({ok,hiber_idle,[],[hibernate]}); init({data, Data}) -> + io:format("init(data)~n", []), init_sup({ok,idle,Data}); init({callback_mode,CallbackMode,Arg}) -> + io:format("init(callback_mode)~n", []), ets:new(?MODULE, [named_table,private]), ets:insert(?MODULE, {callback_mode,CallbackMode}), init(Arg); init({map_statem,#{init := Init}=Machine,Modes}) -> + io:format("init(map_statem)~n", []), ets:new(?MODULE, [named_table,private]), ets:insert(?MODULE, {callback_mode,[handle_event_function|Modes]}), case Init() of @@ -2397,7 +2858,19 @@ init({map_statem,#{init := Init}=Machine,Modes}) -> Other -> init_sup(Other) end; +init({ets, InitResult}) -> + ?MODULE = ets:new(?MODULE, [named_table]), + init_sup( + case InitResult of + {return, Value} -> + Value; + {crash, Class, Reason} -> + erlang:Class(Reason); + {wait, Time, Value} -> + receive after Time -> Value end + end); init([]) -> + io:format("init~n", []), init_sup({ok,idle,data}). %% Supervise state machine parent i.e the test case, and if it dies @@ -2479,6 +2952,11 @@ idle({call,From}, {timeout,Time}, _Data) -> AbsTime = erlang:monotonic_time(millisecond) + Time, {next_state,timeout,{From,Time}, {timeout,AbsTime,idle,[{abs,true}]}}; +idle(cast, {timeout,Time}, _Data) -> + AbsTime = erlang:monotonic_time(millisecond) + Time, + {keep_state_and_data,{timeout,AbsTime,idle,[{abs,true}]}}; +idle(cast, postpone_event, _Data) -> + {keep_state_and_data,postpone}; idle(cast, next_event, _Data) -> {next_state,next_events,[a,b,c], [{next_event,internal,a}, @@ -2584,8 +3062,8 @@ hiber_idle({call,From}, hibernate_sync, Data) -> {next_state,hiber_wakeup,Data, [{reply,From,hibernating}, hibernate]}; -hiber_idle(info, hibernate_later, _) -> - Tref = erlang:start_timer(1000, self(), hibernate), +hiber_idle(info, {hibernate_later, Time}, _) -> + Tref = erlang:start_timer(Time, self(), hibernate), {keep_state,Tref}; hiber_idle(info, hibernate_now, Data) -> {keep_state,Data, diff --git a/lib/stdlib/test/gen_statem_SUITE_data/format_status_statem.erl b/lib/stdlib/test/gen_statem_SUITE_data/format_status_statem.erl new file mode 100644 index 000000000000..7c0ee1f4d084 --- /dev/null +++ b/lib/stdlib/test/gen_statem_SUITE_data/format_status_statem.erl @@ -0,0 +1,40 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017-2021. 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(format_status_statem). + +%% gen_statem callbacks +-export(['$handle_undefined_function'/2, terminate/3, format_status/1]). + +'$handle_undefined_function'(format_status, [_,_]) -> + erlang:error(undef); +'$handle_undefined_function'(Func, Args) -> + apply(gen_statem_SUITE, Func, Args). + +terminate(Reason, State, Data) -> + gen_statem_SUITE:terminate(Reason, State, Data). + +format_status(#{ data := Fun } = S) when is_function(Fun) -> + Fun(S); +format_status(#{ reason := _, state := State, data := Data } = Map) -> + ct:pal("format_status(~p)",[Map]), + Map#{ state := {formatted, State}, data := {formatted, Data}}; +format_status(Map) -> + ct:pal("format_status(~p)",[Map]), + Map#{ data := format_data, state := format_status_called }. diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl index 0addf0946156..a8d52c1680c5 100644 --- a/lib/stdlib/test/id_transform_SUITE.erl +++ b/lib/stdlib/test/id_transform_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2018. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -59,7 +59,7 @@ end_per_group(_GroupName, Config) -> id_transform(Config) when is_list(Config) -> File = filename:join([code:lib_dir(stdlib),"examples", "erl_id_trans.erl"]), - {ok,erl_id_trans,Bin} = compile:file(File,[binary]), + {ok,erl_id_trans,Bin} = compile:file(File, [binary,report]), {module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin), case test_server:is_valgrind() of false -> diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl index 046bd71ed640..f26d98cc1898 100644 --- a/lib/stdlib/test/io_SUITE.erl +++ b/lib/stdlib/test/io_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2021. All Rights Reserved. +%% Copyright Ericsson AB 1999-2023. 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. @@ -28,12 +28,13 @@ io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1, printable_range/1, bad_printable_range/1, io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1, - otp_10836/1, io_lib_width_too_small/1, + otp_10836/1, io_lib_width_too_small/1, calling_self/1, io_with_huge_message_queue/1, format_string/1, format_neg_zero/1, maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1, otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1, otp_15159/1, otp_15639/1, otp_15705/1, otp_15847/1, otp_15875/1, - github_4801/1, chars_limit/1, error_info/1, otp_17525/1]). + github_4801/1, chars_limit/1, error_info/1, otp_17525/1, + unscan_format_without_maps_order/1, build_text_without_maps_order/1]). -export([pretty/2, trf/3]). @@ -63,11 +64,12 @@ all() -> io_fread_newlines, otp_8989, io_lib_fread_literal, printable_range, bad_printable_range, format_neg_zero, io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836, - io_lib_width_too_small, io_with_huge_message_queue, + io_lib_width_too_small, io_with_huge_message_queue, calling_self, format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175, otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159, otp_15639, otp_15705, otp_15847, otp_15875, github_4801, chars_limit, - error_info, otp_17525]. + error_info, otp_17525, unscan_format_without_maps_order, + build_text_without_maps_order]. %% Error cases for output. error_1(Config) when is_list(Config) -> @@ -210,6 +212,10 @@ float_w(Config) when is_list(Config) -> ok. +calling_self(Config) when is_list(Config) -> + {'EXIT', {calling_self, _}} = (catch io:format(self(), "~p", [oops])), + ok. + %% OTP-5403. ~s formats I/O lists and a single binary. otp_5403(Config) when is_list(Config) -> "atom" = fmt("~s", [atom]), @@ -1966,22 +1972,16 @@ io_lib_fread_literal(Suite) when is_list(Suite) -> %% Check that the printable range set by the user actually works. printable_range(Suite) when is_list(Suite) -> - Pa = filename:dirname(code:which(?MODULE)), - {ok, UNode} = test_server:start_node(printable_range_unicode, slave, - [{args, " +pc unicode -pa " ++ Pa}]), - {ok, LNode} = test_server:start_node(printable_range_latin1, slave, - [{args, " +pc latin1 -pa " ++ Pa}]), - {ok, DNode} = test_server:start_node(printable_range_default, slave, - [{args, " -pa " ++ Pa}]), - unicode = rpc:call(UNode,io,printable_range,[]), - latin1 = rpc:call(LNode,io,printable_range,[]), + {ok, UPeer0, UNode0} = ?CT_PEER(["+pc", "unicode"]), + {ok, LPeer0, LNode0} = ?CT_PEER(["+pc", "latin1"]), + {ok, DPeer, DNode} = ?CT_PEER(), + unicode = rpc:call(UNode0,io,printable_range,[]), + latin1 = rpc:call(LNode0,io,printable_range,[]), latin1 = rpc:call(DNode,io,printable_range,[]), - test_server:stop_node(UNode), - test_server:stop_node(LNode), - {ok, UNode} = test_server:start_node(printable_range_unicode, slave, - [{args, " +pcunicode -pa " ++ Pa}]), - {ok, LNode} = test_server:start_node(printable_range_latin1, slave, - [{args, " +pclatin1 -pa " ++ Pa}]), + peer:stop(UPeer0), + peer:stop(LPeer0), + {ok, UPeer, UNode} = ?CT_PEER(["+pcunicode"]), + {ok, LPeer, LNode} = ?CT_PEER(["+pclatin1"]), unicode = rpc:call(UNode,io,printable_range,[]), latin1 = rpc:call(LNode,io,printable_range,[]), PrettyOptions = [{column,1}, @@ -2029,9 +2029,9 @@ printable_range(Suite) when is_list(Suite) -> $\e = format_max(LNode, ["~ts", [PrintableControls]]), $\e = format_max(DNode, ["~ts", [PrintableControls]]), - test_server:stop_node(UNode), - test_server:stop_node(LNode), - test_server:stop_node(DNode), + peer:stop(UPeer), + peer:stop(LPeer), + peer:stop(DPeer), ok. print_max(Node, Args) -> @@ -2079,11 +2079,8 @@ io_lib_print_binary_depth_one(Suite) when is_list(Suite) -> %% OTP-10302. Unicode. otp_10302(Suite) when is_list(Suite) -> - Pa = filename:dirname(code:which(?MODULE)), - {ok, UNode} = test_server:start_node(printable_range_unicode, slave, - [{args, " +pc unicode -pa " ++ Pa}]), - {ok, LNode} = test_server:start_node(printable_range_latin1, slave, - [{args, " +pc latin1 -pa " ++ Pa}]), + {ok, UPeer, UNode} = ?CT_PEER(["+pc", "unicode"]), + {ok, LPeer, LNode} = ?CT_PEER(["+pc", "latin1"]), "\"\x{400}\"" = rpc:call(UNode,?MODULE,pretty,["\x{400}", -1]), "<<\"\x{400}\"/utf8>>" = rpc:call(UNode,?MODULE,pretty, [<<"\x{400}"/utf8>>, -1]), @@ -2094,8 +2091,8 @@ otp_10302(Suite) when is_list(Suite) -> "<<208,128>>" = rpc:call(LNode,?MODULE,pretty,[<<"\x{400}"/utf8>>, -1]), "<<208,...>>" = rpc:call(LNode,?MODULE,pretty,[<<"\x{400}foo"/utf8>>, 2]), - test_server:stop_node(UNode), - test_server:stop_node(LNode), + peer:stop(UPeer), + peer:stop(LPeer), "<<\"äppl\"/utf8>>" = pretty(<<"äppl"/utf8>>, 2), "<<\"äppl\"/utf8...>>" = pretty(<<"äpple"/utf8>>, 2), @@ -2189,14 +2186,16 @@ otp_10755(Suite) when is_list(Suite) -> " io:format(\"~ltw\", [S]),\n" " io:format(\"~tlw\", [S]),\n" " io:format(\"~ltW\", [S, 1]),\n" - " io:format(\"~tlW\", [S, 1]).\n", + " io:format(\"~tlW\", [S, 1]),\n" + " io:format(\"~ltp\", [S, 1]).\n", {ok,l_mod,[{_File,Ws}]} = compile_file("l_mod.erl", Text, Suite), - ["format string invalid (invalid control ~lw)", - "format string invalid (invalid control ~lW)", - "format string invalid (invalid control ~ltw)", - "format string invalid (invalid control ~ltw)", - "format string invalid (invalid control ~ltW)", - "format string invalid (invalid control ~ltW)"] = + ["format string invalid (invalid modifier/control combination ~lw)", + "format string invalid (invalid modifier/control combination ~lW)", + "format string invalid (invalid modifier/control combination ~lw)", + "format string invalid (invalid modifier/control combination ~lw)", + "format string invalid (invalid modifier/control combination ~lW)", + "format string invalid (invalid modifier/control combination ~lW)", + "format string invalid (conflicting modifiers ~ltp)"] = [lists:flatten(M:format_error(E)) || {_L,M,E} <- Ws], ok. @@ -2276,34 +2275,64 @@ format_string(_Config) -> ok. maps(_Config) -> - %% Note that order in which a map is printed is arbitrary. In - %% practice, small maps (non-HAMT) are printed in key order, but - %% the breakpoint for creating big maps (HAMT) is lower in the - %% debug-compiled run-time system than in the optimized run-time - %% system. - %% + %% Note that order in which a map is printed is arbitrary. %% Therefore, play it completely safe by not assuming any order %% in a map with more than one element. + AOrdCmpFun = fun(A, B) -> A =< B end, + ARevCmpFun = fun(A, B) -> B < A end, + + AtomMap1 = #{a => b}, + AtomMap2 = #{a => b, c => d}, + AtomMap3 = #{a => b, c => d, e => f}, + "#{}" = fmt("~w", [#{}]), - "#{a => b}" = fmt("~w", [#{a=>b}]), - re_fmt(<<"#\\{(a => b),[.][.][.]\\}">>, - "~W", [#{a => b,c => d},2]), - re_fmt(<<"#\\{(a => b),[.][.][.]\\}">>, - "~W", [#{a => b,c => d,e => f},2]), + "#{a => b}" = fmt("~w", [AtomMap1]), + re_fmt(<<"#\\{(a => b|c => d),[.][.][.]\\}">>, + "~W", [AtomMap2, 2]), + re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, + "~W", [AtomMap3, 2]), + "#{a => b,c => d,e => f}" = fmt("~kw", [AtomMap3]), + re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, + "~KW", [undefined, AtomMap3, 2]), + "#{a => b,c => d,e => f}" = fmt("~Kw", [ordered, AtomMap3]), + "#{e => f,c => d,a => b}" = fmt("~Kw", [reversed, AtomMap3]), + "#{a => b,c => d,e => f}" = fmt("~Kw", [AOrdCmpFun, AtomMap3]), + "#{e => f,c => d,a => b}" = fmt("~Kw", [ARevCmpFun, AtomMap3]), "#{}" = fmt("~p", [#{}]), - "#{a => b}" = fmt("~p", [#{a => b}]), - "#{...}" = fmt("~P", [#{a => b},1]), + "#{a => b}" = fmt("~p", [AtomMap1]), + "#{...}" = fmt("~P", [AtomMap1, 1]), re_fmt(<<"#\\{(a => b|c => d),[.][.][.]\\}">>, - "~P", [#{a => b,c => d},2]), + "~P", [AtomMap2, 2]), re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, - "~P", [#{a => b,c => d,e => f},2]), + "~P", [AtomMap3, 2]), + "#{a => b,c => d,e => f}" = fmt("~kp", [AtomMap3]), + re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>, + "~KP", [undefined, AtomMap3, 2]), + "#{a => b,c => d,e => f}" = fmt("~Kp", [ordered, AtomMap3]), + "#{e => f,c => d,a => b}" = fmt("~Kp", [reversed, AtomMap3]), + "#{a => b,c => d,e => f}" = fmt("~Kp", [AOrdCmpFun, AtomMap3]), + "#{e => f,c => d,a => b}" = fmt("~Kp", [ARevCmpFun, AtomMap3]), - List = [{I,I*I} || I <- lists:seq(1, 20)], + List = [{I, I * I} || I <- lists:seq(1, 64)], Map = maps:from_list(List), - "#{...}" = fmt("~P", [Map,1]), + "#{...}" = fmt("~P", [Map, 1]), + "#{1 => 1,...}" = fmt("~kP", [Map, 2]), + "#{1 => 1,...}" = fmt("~KP", [ordered, Map, 2]), + "#{64 => 4096,...}" = fmt("~KP", [reversed, Map, 2]), + "#{1 => 1,...}" = fmt("~KP", [AOrdCmpFun, Map, 2]), + "#{64 => 4096,...}" = fmt("~KP", [ARevCmpFun, Map, 2]), + + FloatIntegerMap = #{-1.0 => a, 0.0 => b, -1 => c, 0 => d}, + re_fmt(<<"#\\{(-1.0 => a|0.0 => b|-1 => c|0 => d),[.][.][.]\\}">>, + "~P", [FloatIntegerMap, 2]), + "#{-1 => c,0 => d,-1.0 => a,0.0 => b}" = fmt("~kp", [FloatIntegerMap]), + re_fmt(<<"#\\{(-1.0 => a|0.0 => b|-1 => c|0 => d),[.][.][.]\\}">>, + "~KP", [undefined, FloatIntegerMap, 2]), + "#{-1 => c,0 => d,-1.0 => a,0.0 => b}" = fmt("~Kp", [ordered, FloatIntegerMap]), + "#{0.0 => b,-1.0 => a,0 => d,-1 => c}" = fmt("~Kp", [reversed, FloatIntegerMap]), %% Print a map and parse it back to a map. S = fmt("~p\n", [Map]), @@ -2740,9 +2769,7 @@ trunc_string() -> "str str" = trf("str ~s", ["str"], 7), "str str" = trf("str ~8s", ["str"], 6), "str ..." = trf("str ~8s", ["str1"], 6), - Pa = filename:dirname(code:which(?MODULE)), - {ok, UNode} = test_server:start_node(printable_range_unicode, slave, - [{args, " +pc unicode -pa " ++ Pa}]), + {ok, UPeer, UNode} = ?CT_PEER(["+pc", "unicode"]), U = "кирилли́ческий атом", UFun = fun(Format, Args, CharsLimit) -> rpc:call(UNode, @@ -2760,7 +2787,7 @@ trunc_string() -> "<<\"кирилли́\"/utf8...>>" = UFun("~tp", [BU], 20), "<<\"кирилли́\"/utf8...>>" = UFun("~tp", [BU], 21), "<<\"кирилли́ческ\"/utf8...>>" = UFun("~tp", [BU], 22), - test_server:stop_node(UNode). + peer:stop(UPeer). trunc_depth(D, Fun) -> "..." = Fun("", D, 0), @@ -3011,6 +3038,11 @@ error_info(Config) -> Dev end, + UnicodeDev = fun() -> + {ok, Dev} = file:open(TmpFile, [read, write, {encoding, unicode}]), + Dev + end, + DeadDev = spawn(fun() -> ok end), UserDev = fun() -> whereis(user) end, @@ -3032,8 +3064,12 @@ error_info(Config) -> {put_chars,["test"], [{gl,FullDev()},{general,"no space left on device"}]}, {put_chars,[Latin1Dev(),"Спутник-1"], [{1,"transcode"}]}, {put_chars,[a], [{1,"not valid character data"}]}, + {put_chars,[UnicodeDev(), <<222>>], [{1,"transcode"}]}, + {put_chars,[<<1:1>>], [{1,"not valid character data"}]}, {put_chars,[UnknownDev(),"test"], [{general,"unknown error: 'Спутник-1'"}]}, {put_chars,["test"], [{gl,UnknownDev()},{general,"unknown error: 'Спутник-1'"}]}, + {put_chars,[self(),"test"],[{1,"the device is not allowed to be the current process"}]}, + {put_chars,["test"],[{gl,self()},{general,"the device is not allowed to be the current process"}]}, {write,[DeadDev,"test"],[{1,"terminated"}]}, {write,["test"],[{gl,DeadDev},{general,"terminated"}]}, @@ -3148,3 +3184,29 @@ otp_17525(_Config) -> " {...}|...]" = lists:flatten(S), ok. + +unscan_format_without_maps_order(_Config) -> + FormatSpec = #{ + adjust => right, + args => [[<<"1">>]], + control_char => 115, + encoding => unicode, + pad_char => 32, + precision => none, + strings => true, + width => none + }, + {"~ts",[[<<"1">>]]} = io_lib:unscan_format([FormatSpec]). + +build_text_without_maps_order(_Config) -> + FormatSpec = #{ + adjust => right, + args => [[<<"1">>]], + control_char => 115, + encoding => unicode, + pad_char => 32, + precision => none, + strings => true, + width => none + }, + [["1"]] = io_lib:build_text([FormatSpec]). diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index df6958cfa987..acc0d8ab82f4 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2019. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -22,55 +22,36 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([init_per_testcase/2, end_per_testcase/2]). - -export([setopts_getopts/1,unicode_options/1,unicode_options_gen/1, binary_options/1, read_modes_gl/1, - read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1,unicode_prompt/1]). + read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1, + unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1, + file_read_stdin_binary_mode/1, file_read_stdin_list_mode/1, + io_get_chars_stdin_binary_mode/1, io_get_chars_stdin_list_mode/1, + io_get_chars_file_read_stdin_binary_mode/1, + file_read_stdin_latin1_binary_mode/1, + file_read_stdin_latin1_list_mode/1, + io_fwrite_stdin_latin1_mode/1 + ]). -export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1, proxy_setnext/2, proxy_quit/1]). %% For spawn --export([toerl_server/3,answering_machine1/3, - answering_machine2/3]). +-export([answering_machine1/3, answering_machine2/3]). --export([uprompt/1]). +-export([uprompt/1, slogan/0, session_slogan/0]). -%%-define(without_test_server, true). - --ifdef(without_test_server). --define(line, put(line, ?LINE), ). --define(config(X,Y), foo). --define(t, test_server). --define(privdir(_), "./io_SUITE_priv"). --else. --include_lib("common_test/include/ct.hrl"). --define(privdir(Conf), proplists:get_value(priv_dir, Conf)). --endif. +-export([write_raw_to_stdout/0, read_raw_from_stdin/1]). %%-define(debug, true). -ifdef(debug). --define(format(S, A), io:format(S, A)). -define(dbg(Data),io:format(standard_error, "DBG: ~p\r\n",[Data])). --define(RM_RF(Dir),begin io:format(standard_error, "Not Removed: ~p\r\n",[Dir]), - ok end). -else. --define(format(S, A), ok). -define(dbg(Data),noop). --define(RM_RF(Dir),rm_rf(Dir)). -endif. -init_per_testcase(_Case, Config) -> - Term = os:getenv("TERM", "dumb"), - os:putenv("TERM","vt100"), - [{term, Term} | Config]. -end_per_testcase(_Case, Config) -> - Term = proplists:get_value(term,Config), - os:putenv("TERM",Term), - ok. - suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,5}}]. @@ -78,16 +59,30 @@ suite() -> all() -> [setopts_getopts, unicode_options, unicode_options_gen, binary_options, read_modes_gl, read_modes_ogl, - broken_unicode, eof_on_pipe, unicode_prompt]. + broken_unicode, eof_on_pipe, unicode_prompt, + shell_slogan, raw_stdout, raw_stdout_isatty, + file_read_stdin_binary_mode, + file_read_stdin_list_mode, + io_get_chars_stdin_binary_mode, + io_get_chars_stdin_list_mode, + io_get_chars_file_read_stdin_binary_mode, + file_read_stdin_latin1_binary_mode, + file_read_stdin_latin1_list_mode, + io_fwrite_stdin_latin1_mode + ]. groups() -> []. init_per_suite(Config) -> - DefShell = get_default_shell(), - [{default_shell,DefShell}|Config]. + Term = os:getenv("TERM", "dumb"), + os:putenv("TERM","vt100"), + DefShell = rtnode:get_default_shell(), + [{default_shell,DefShell},{term, Term}|Config]. -end_per_suite(_Config) -> +end_per_suite(Config) -> + Term = proplists:get_value(term,Config), + os:putenv("TERM",Term), ok. init_per_group(_GroupName, Config) -> @@ -96,13 +91,11 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - - -record(state, { - q = [], - nxt = eof, - mode = list - }). + q = [], + nxt = eof, + mode = list + }). uprompt(_L) -> [1050,1072,1082,1074,1086,32,1077,32,85,110,105,99,111,100,101,32,63]. @@ -111,41 +104,73 @@ uprompt(_L) -> unicode_prompt(Config) when is_list(Config) -> PA = filename:dirname(code:which(?MODULE)), case proplists:get_value(default_shell,Config) of - old -> - ok; new -> - rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, - {getline, "default"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"} - ],[],[],"-pa \""++ PA++"\"") + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2"}, + {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, + {expect, "[\n ]default"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true}])."}, + {expect, "[\n ]ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect,"[\n ]hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"} + ],[],"",["-pa",PA]); + _ -> + ok end, %% And one with oldshell - rtnode([{putline,""}, - {putline, "2."}, - {getline_re, ".*2$"}, - {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, - {getline_re, ".*default"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*\"hej\\\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline_re, ".*ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*<<\"hej\\\\n\">>"} - ],[],[],"-oldshell -pa \""++PA++"\""), + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2"}, + {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, + {expect, "default"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true}])."}, + {expect, "[\n ]\\?*ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect,"[\n ]\\?*hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"} + ],[],"",["-oldshell","-pa",PA]), ok. +%% Test that an Unicode prompt does not crash the shell. +shell_slogan(Config) when is_list(Config) -> + PA = filename:dirname(code:which(?MODULE)), + case proplists:get_value(default_shell,Config) of + new -> + rtnode:run( + [{expect, "\\Q"++string:trim(erlang:system_info(system_version))++"\\E"}, + {expect, "\\Q"++io_lib:format("Eshell V~s (press Ctrl+G to abort, type help(). for help)",[erlang:system_info(version)])++"\\E"} + ],[],"",[]), + rtnode:run( + [{expect, "\nTest slogan"}, + {expect, "\nTest session slogan \\("} + ],[],"",["-stdlib","shell_slogan","\"Test slogan\"", + "-stdlib","shell_session_slogan","\"Test session slogan\""]), + rtnode:run( + [{expect, "\nTest slogan"}, + {expect, "\\Q\nTest session slogan (\\E"} + ],[],"",["-stdlib","shell_slogan","fun io_proto_SUITE:slogan/0", + "-stdlib","shell_session_slogan","fun io_proto_SUITE:session_slogan/0", + "-pa",PA]); + _ -> + ok + end. + +slogan() -> + "Test slogan". +session_slogan() -> + "Test session slogan". %% Check io:setopts and io:getopts functions. setopts_getopts(Config) when is_list(Config) -> @@ -222,42 +247,287 @@ setopts_getopts(Config) when is_list(Config) -> eof = io:get_line(RFile,''), file:close(RFile), case proplists:get_value(default_shell,Config) of - old -> - ok; new -> %% So, lets test another node with new interactive shell - rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline, "{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"} - ],[]) + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {expect, "{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true}])."}, + {expect, "[\n ]ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"} + ],[]); + _ -> + ok end, %% And one with oldshell - rtnode([{putline,""}, - {putline, "2."}, - {getline_re, ".*2$"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline_re, ".*{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*\"hej\\\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline_re, ".*ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*<<\"hej\\\\n\">>"} - ],[],[],"-oldshell"), + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {expect, "[\n ]{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true}])."}, + {expect, "[\n ]ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"} + ],[],"",["-oldshell"]), + ok. + +%% Test that reading from stdin using file:read works when io is in binary mode +file_read_stdin_binary_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node(fun() -> file:read(standard_io, 3) end, [binary]), + + erlang:port_command(ErlPort, "abc"), + {ok, "got: <<\"abc\">>\n"} = gen_tcp:recv(P, 0), + erlang:port_command(ErlPort, "def"), + {ok, "got: <<\"def\">>\n"} = gen_tcp:recv(P, 0), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0), + + ok. + +%% Test that reading from stdin using file:read works when io is in binary mode +file_read_stdin_list_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node(fun() -> file:read(standard_io, 3) end, [list]), + + erlang:port_command(ErlPort, "abc"), + {ok, "got: \"abc\"\n"} = gen_tcp:recv(P, 0), + erlang:port_command(ErlPort, "def"), + {ok, "got: \"def\"\n"} = gen_tcp:recv(P, 0), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0), + + ok. + +%% Test that reading from stdin using file:read works when io is in binary mode +io_get_chars_stdin_binary_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node( + fun() -> + case io:get_chars(standard_io, "", 1) of + eof -> eof; + Chars -> {ok, Chars} + end + end, [binary]), + + erlang:port_command(ErlPort, "x\n"), + {ok, "got: <<\"x\">>\n"} = gen_tcp:recv(P, 0), + {ok, "got: <<\"\\n\">>\n"} = gen_tcp:recv(P, 0), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0), + ok. +%% Test that reading from stdin using file:read works when io is in binary mode +io_get_chars_stdin_list_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node( + fun() -> case io:get_chars(standard_io, "", 1) of + eof -> eof; + Chars -> {ok, Chars} + end + end, [list]), + + erlang:port_command(ErlPort, "x\n"), + {ok, "got: \"x\"\n"} = gen_tcp:recv(P, 0), + {ok, "got: \"\\n\"\n"} = gen_tcp:recv(P, 0), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0), + + ok. + +%% Test that mixing io:get_chars and file:read works when stdin is in binary mode. +io_get_chars_file_read_stdin_binary_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node( + fun() -> case file:read(standard_io, 1) of + eof -> eof; + {ok, Chars} -> + case io:get_line(standard_io, "") of + eof -> Chars; + Line -> + {ok, [Chars, Line]} + end + end + end, [binary]), + + erlang:port_command(ErlPort, "1\n"), + {ok, "got: [<<\"1\">>,<<\"\\n\">>]\n"} = gen_tcp:recv(P, 0), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0), + + ok. + +%% Test that reading from stdin using file:read_line works when io is not utf8 +file_read_stdin_latin1_binary_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node( + fun() -> file:read_line(standard_io) end, + [binary], + "-kernel standard_io_encoding latin1"), + + %% Invalid utf8 + erlang:port_command(ErlPort, <<192,128,10,192,128,10,192,128,10>>), + + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000), + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000), + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0, 5000), + + {ok, P2, ErlPort2} = start_stdin_node( + fun() -> file:read(standard_io, 5) end, + [binary], + "-kernel standard_io_encoding latin1"), + + %% Valid utf8 + erlang:port_command(ErlPort2, <<"duπaduπaduπa"/utf8>>), + + {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000), + {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000), + {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000), + ErlPort2 ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P2, 0, 5000), + + %% Setting using io:setopts used to hang on Windows, see #7459 for details. + {ok, P3, ErlPort3} = start_stdin_node( + fun() -> file:read_line(standard_io) end, + [binary], + "-eval \"io:setopts([{encoding, latin1}])\""), + + %% Invalid utf8 + erlang:port_command(ErlPort3, <<192,128,10,192,128,10,192,128,10>>), + + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P3, 0, 5000), + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P3, 0, 5000), + {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P3, 0, 5000), + ErlPort3 ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P3, 0, 5000), + + ok. + +%% Test that reading from stdin using file:read_line works when io is not utf8 +file_read_stdin_latin1_list_mode(_Config) -> + {ok, P, ErlPort} = start_stdin_node( + fun() -> file:read_line(standard_io) end, + [list], + "-kernel standard_io_encoding latin1"), + + %% Invalid utf8 + erlang:port_command(ErlPort, <<192,128,10,192,128,10,192,128,10>>), + + {ok, "got: [192,128,10]\n"} = gen_tcp:recv(P, 0, 5000), + {ok, "got: [192,128,10]\n"} = gen_tcp:recv(P, 0, 5000), + {ok, "got: [192,128,10]\n"} = gen_tcp:recv(P, 0, 5000), + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0, 5000), + + {ok, P2, ErlPort2} = start_stdin_node( + fun() -> file:read(standard_io, 5) end, + [list], + "-kernel standard_io_encoding latin1"), + + %% Valid utf8 + erlang:port_command(ErlPort2, <<"duπaduπaduπa"/utf8>>), + + {ok, "got: [100,117,207,128,97]\n"} = gen_tcp:recv(P2, 0, 5000), + {ok, "got: [100,117,207,128,97]\n"} = gen_tcp:recv(P2, 0, 5000), + {ok, "got: [100,117,207,128,97]\n"} = gen_tcp:recv(P2, 0, 5000), + ErlPort2 ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P2, 0, 5000), + + ok. + +%% Test that reading from stdin using file:read works when io is not utf8, +%% but unicode is printed out +io_fwrite_stdin_latin1_mode(_Config) -> + {ok, P, ErlPort} = + start_stdin_node( + fun() -> case file:read(standard_io, 5) of + {ok, Chars} -> + %% We've read a unicode string as latin1, + %% which means that if we convert it to + %% a binary it will be seen as the original + %% unicode string. + io:format("~ts",[list_to_binary(Chars)]), + {ok, Chars}; + Else -> + Else + end + end, + [list], + "-kernel standard_io_encoding latin1"), + + %% Valid utf8 + erlang:port_command(ErlPort, <<"duπa"/utf8>>), + + {ok, "got: [100,117,207,128,97]\n"} = gen_tcp:recv(P, 0, 5000), + receive + {ErlPort, {data, Data}} -> + %% On stdout any unicode should be translated to hex syntax + "du\\x{3C0}a" = Data + end, + + ErlPort ! {self(), close}, + {ok, "got: eof"} = gen_tcp:recv(P, 0, 5000), + + ok. + +start_stdin_node(ReadFun, IoOptions) -> + start_stdin_node(ReadFun, IoOptions, ""). +start_stdin_node(ReadFun, IoOptions, ExtraArgs) -> + {ok, L} = gen_tcp:listen(0,[{active, false},{packet,4}]), + {ok, Port} = inet:port(L), + Cmd = lists:append( + [ct:get_progname(), + " -noshell ", + ExtraArgs, + " -pa ", filename:dirname(code:which(?MODULE)), + " -s ", atom_to_list(?MODULE), " read_raw_from_stdin ", integer_to_list(Port)]), + ct:log("~p~n", [Cmd]), + ErlPort = open_port({spawn, Cmd}, [stream, eof, stderr_to_stdout]), + {ok, P} = gen_tcp:accept(L), + gen_tcp:send(P, term_to_binary(IoOptions)), + gen_tcp:send(P, term_to_binary(ReadFun)), + {ok, P, ErlPort}. + +read_raw_from_stdin([Port]) -> + try + {ok, P} = gen_tcp:connect(localhost, list_to_integer(atom_to_list(Port)), + [binary, {packet, 4}, {active, false}]), + {ok, OptionsBin} = gen_tcp:recv(P, 0), + io:setopts(standard_io, binary_to_term(OptionsBin)), + {ok, ReadFunBin} = gen_tcp:recv(P, 0), + spawn(fun() -> + gen_tcp:recv(P, 0), + init:stop("crash") + end), + read_raw_from_stdin(binary_to_term(ReadFunBin), P) + catch E:R:ST -> + io:format(standard_error, "~p ~p",[Port,{E,R,ST}]) + end. +read_raw_from_stdin(ReadFun, P) -> + case ReadFun() of + eof -> + gen_tcp:send(P, "got: eof"), + init:stop(); + {ok, Char} -> + gen_tcp:send(P, unicode:characters_to_binary( + io_lib:format("got: ~p\n",[Char]))), + read_raw_from_stdin(ReadFun, P); + {ok, Fmt, Char} -> + gen_tcp:send(P, unicode:characters_to_binary( + io_lib:format("got: "++Fmt++"\n",[Char]))), + read_raw_from_stdin(ReadFun, P) + end. get_lc_ctype() -> case {os:type(),os:version()} of @@ -419,48 +689,45 @@ unicode_options(Config) when is_list(Config) -> [ ok = CannotWriteFile(F,FailDir) || F <- AllNoBom ], case proplists:get_value(default_shell,Config) of - old -> - ok; new -> %% OK, time for the group_leaders... - rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(encoding,1,io:getopts())."}, - {getline, "{encoding,latin1}"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline, "\\x{400}"}, - {putline, "io:setopts([unicode])."}, - {getline, "ok"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline, - binary_to_list(unicode:characters_to_binary( - [1024],unicode,utf8))} - ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; " - "export LC_CTYPE; ") + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(encoding,1,io:getopts())."}, + {expect, "{encoding,latin1}"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {expect, "\\Q\\x{400}\\E"}, + {putline, "io:setopts([unicode])."}, + {expect, "[\n ]ok"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {expect, "[\n ]"++[1024]} + ],[],"",["-env","LC_ALL",get_lc_ctype()]); + _ -> + ok end, - rtnode([{putline,""}, - {putline, "2."}, - {getline_re, ".*2$"}, - {putline, "lists:keyfind(encoding,1,io:getopts())."}, - {getline_re, ".*{encoding,latin1}"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline_re, ".*\\\\x{400\\}"}, - {putline, "io:setopts([{encoding,unicode}])."}, - {getline_re, ".*ok"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline_re, - ".*"++binary_to_list(unicode:characters_to_binary( - [1024],unicode,utf8))} - ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; export LC_CTYPE; ", - " -oldshell "), - + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(encoding,1,io:getopts())."}, + {expect, "[\n ]{encoding,latin1}"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {expect, "\\Q\\x{400}\\E"}, + {putline, "io:setopts([{encoding,unicode}])."}, + {expect, "[\n ]ok"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {expect, "[\n ]"++[1024]} + ],[],"", + ["-oldshell","-env","LC_ALL",get_lc_ctype()]), ok. %% Tests various unicode options on random generated files. unicode_options_gen(Config) when is_list(Config) -> ct:timetrap({minutes,30}), %% valgrind needs a alot of time - random:seed(1240, 900586, 553728), + rand:seed(default), + io:format("*** SEED: ~p ***\n", [rand:export_seed()]), PrivDir = proplists:get_value(priv_dir, Config), AllModes = [utf8,utf16,{utf16,big},{utf16,little}, utf32,{utf32,big},{utf32,little}], @@ -513,12 +780,11 @@ unicode_options_gen(Config) when is_list(Config) -> [read,read_ahead,{encoding,Encoding}], Read4), - Ulist2 = [X || X <- Ulist, X =/= $\n, X =/= $\s], - Ulist3 = [X || X <- Ulist, X =/= $\n], + Ulist2 = [X || X <- Ulist, X =/= $\n, X =/= $\s, X =/= $\t], Ulist = done(Res1), Ulist = done(Res2), Ulist2 = done(Res3), - Ulist3 = done(Res4), + Ulist2 = done(Res4), file:delete(Fname) end, @@ -635,22 +901,31 @@ enc2str({A1,A2}) when is_atom(A1), is_atom(A2) -> random_unicode(0) -> - []; + %% io:fread(Device, Promp, "~ts") will return an error if the file + %% ends with whitespace characters. This behavior seems to be + %% deliberate. Therefore, be sure that we never end the file with + %% a sequence of whitespace characters. + [$! + rand:uniform(64) | + case rand:uniform(20) of + A when A =< 1 -> [$\n]; + _ -> [] + end]; random_unicode(N) -> - %% Favour large unicode and make linebreaks - X = case random:uniform(20) of + %% Favor large unicode code points and make line breaks. + X = case rand:uniform(20) of A when A =< 1 -> $\n; - A0 when A0 =< 3 -> random:uniform(16#10FFFF); - A1 when A1 =< 6 -> random:uniform(16#10FFFF - 16#7F) + 16#7F; - A2 when A2 =< 12 -> random:uniform(16#10FFFF - 16#7FF) + 16#7FF; - _ -> random:uniform(16#10FFFF - 16#FFFF) + 16#FFFF + A when A =< 3 -> rand:uniform(16#10FFFF); + A when A =< 6 -> rand:uniform(16#10FFFF - 16#7F) + 16#7F; + A when A =< 12 -> rand:uniform(16#10FFFF - 16#7FF) + 16#7FF; + _ -> rand:uniform(16#10FFFF - 16#FFFF) + 16#FFFF end, - case X of - Inv1 when Inv1 >= 16#D800, Inv1 =< 16#DFFF; - Inv1 =:= 16#FFFE; - Inv1 =:= 16#FFFF -> + if + X =:= $\r; %Can be eaten by io:get_line/2. + 16#D800 =< X, X =< 16#DFFF; + X =:= 16#FFFE; + X =:= 16#FFFF -> random_unicode(N); - _ -> + true -> [X | random_unicode(N-1)] end. @@ -700,115 +975,124 @@ binary_options(Config) when is_list(Config) -> %% OK, time for the group_leaders... case proplists:get_value(default_shell,Config) of - old -> - ok; new -> - rtnode([{putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline, "{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true},unicode])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"}, - {putline, "io:get_line('')."}, - {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, - {getline, "<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\"/utf8>>"} - ],[]) + rtnode:run( + [{putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {expect, "[\n ]{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true},unicode])."}, + {expect, "[\n ]ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"}, + {putline, "io:get_line('')."}, + {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, + {expect, latin1, "[\n ]\\Q<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\"/utf8>>\\E"} + ],[]); + _ -> + ok end, %% And one with oldshell - rtnode([{putline, "2."}, - {getline_re, ".*2$"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline_re, ".*{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*\"hej\\\\n\""}, - {putline, "io:setopts([{binary,true},unicode])."}, - {getline_re, ".*ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline_re, ".*<<\"hej\\\\n\">>"}, - {putline, "io:get_line('')."}, - {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, - {getline_re, ".*<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\\\n\"/utf8>>"} - ],[],[],"-oldshell"), + rtnode:run( + [{putline, "2."}, + {expect, "[\n ]2[^.]"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {expect, "[\n ]{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "[\n ]\\Q\"hej\\n\"\\E"}, + {putline, "io:setopts([{binary,true},unicode])."}, + {expect, "[\n ]ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {expect, "\\Q<<\"hej\\n\">>\\E"}, + {putline, "io:get_line('')."}, + {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, + {expect, latin1, "[\n ]\\Q<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\"/utf8>>\\E"} + ],[],"",["-oldshell"]), ok. - - - answering_machine1(OthNode,OthReg,Me) -> TestDataLine1 = [229,228,246], TestDataUtf = binary_to_list(unicode:characters_to_binary(TestDataLine1)), - rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."}, - {getline, "<"}, - %% get_line - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - %% get_chars - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - %% fread - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"} - - ],Me,"LC_CTYPE=\""++get_lc_ctype()++"\"; export LC_CTYPE; "), + TestDataLine1Oct = "\\\\345( \b)*\\\\344( \b)*\\\\366", + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "2"}, + {putline, "io:getopts()."}, + {expect, ">"}, + {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."}, + {expect, "<"}, + %% get_line + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + %% get_chars + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + %% fread + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1Oct}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"} + + ],Me,"",["-env","LC_ALL",get_lc_ctype()]), O = list_to_atom(OthReg), O ! {self(),done}, ok. @@ -816,70 +1100,77 @@ answering_machine1(OthNode,OthReg,Me) -> answering_machine2(OthNode,OthReg,Me) -> TestDataLine1 = [229,228,246], TestDataUtf = binary_to_list(unicode:characters_to_binary(TestDataLine1)), - rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."}, - {getline_re, ".*<[0-9].*"}, - %% get_line - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - %% get_chars - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - %% fread - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, "Hej"}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataLine1}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"}, - {getline_re, ".*Prompt"}, - {putline, TestDataUtf}, - {getline_re, ".*Okej"} - - ],Me,"LC_CTYPE=\""++get_lc_ctype()++"\"; export LC_CTYPE; "," -oldshell "), + rtnode:run( + [{putline,""}, + {putline, "2."}, + {expect, "2"}, + {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."}, + {expect, "<[0-9].*"}, + %% get_line + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + %% get_chars + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + %% fread + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, "Hej"}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataLine1}, + {expect, latin1, "\n" ++ TestDataLine1}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"}, + {expect, "Prompt"}, + {putline, TestDataUtf}, + {expect, "Okej"} + + ],Me,"",["-oldshell","-env","LC_ALL",get_lc_ctype()]), O = list_to_atom(OthReg), O ! {self(),done}, ok. @@ -887,20 +1178,20 @@ answering_machine2(OthNode,OthReg,Me) -> %% Test various modes when reading from the group leade from another machine. read_modes_ogl(Config) when is_list(Config) -> - case get_progs() of - {error,Reason} -> - {skipped,Reason}; + case proplists:get_value(default_shell,Config) of + noshell -> + {skipped,"No run_erl"}; _ -> read_modes_gl_1(Config,answering_machine2) end. %% Test various modes when reading from the group leade from another machine. read_modes_gl(Config) when is_list(Config) -> - case {get_progs(),proplists:get_value(default_shell,Config)} of - {{error,Reason},_} -> - {skipped,Reason}; - {_,old} -> - {skipper,"No new shell"}; + case proplists:get_value(default_shell,Config) of + noshell -> + {skipped,"No run_erl"}; + old -> + {skipped,"No new shell"}; _ -> read_modes_gl_1(Config,answering_machine1) end. @@ -910,7 +1201,7 @@ read_modes_gl_1(_Config,Machine) -> TestDataLine1BinUtf = unicode:characters_to_binary(TestDataLine1), TestDataLine1BinLatin = list_to_binary(TestDataLine1), - {ok,N2List} = create_nodename(), + N2List = peer:random_name(?FUNCTION_NAME), MyNodeList = atom2list(node()), register(io_proto_suite,self()), AM1 = spawn(?MODULE,Machine, @@ -1014,14 +1305,10 @@ loop_through_file2(_,{error,_Err},_,_) -> loop_through_file2(F,Bin,Chunk,Enc) when is_binary(Bin) -> loop_through_file2(F,io:get_chars(F,'',Chunk),Chunk,Enc). - - %% Test eof before newline on stdin when erlang is in pipe. eof_on_pipe(Config) when is_list(Config) -> - case {get_progs(),os:type()} of - {{error,Reason},_} -> - {skipped,Reason}; - {{_,_,Erl},{unix,linux}} -> + case {ct:get_progname(),os:type()} of + {Erl,{unix,linux}} -> %% Not even Linux is reliable - echo can be both styles try EchoLine = case os:cmd("echo -ne \"test\\ntest\"") of @@ -1065,453 +1352,45 @@ eof_on_pipe(Config) when is_list(Config) -> {skipped,"Only on linux"} end. +raw_stdout(Config) when is_list(Config) -> + Cmd = lists:append( + [ct:get_progname(), + " -noshell -noinput", + " -pa ", filename:dirname(code:which(?MODULE)), + " -s ", atom_to_list(?MODULE), " write_raw_to_stdout"]), + ct:log("~p~n", [Cmd]), + Port = open_port({spawn, Cmd}, [stream, eof]), + Expected = lists:seq(0,255), + Expected = get_all_port_data(Port, []), + Port ! {self(), close}, + ok. -%% -%% Tool for running interactive shell (stolen from the kernel -%% test suite interactive_shell_SUITE) -%% --undef(line). --define(line,). -rtnode(C,N) -> - rtnode(C,N,[]). -rtnode(Commands,Nodename,ErlPrefix) -> - rtnode(Commands,Nodename,ErlPrefix,[]). -rtnode(Commands,Nodename,ErlPrefix,Extra) -> - case get_progs() of - {error,_Reason} -> - {skip,"No runerl present"}; - {RunErl,ToErl,Erl} -> - case create_tempdir() of - {error, Reason2} -> - {skip, Reason2}; - Tempdir -> - SPid = start_runerl_node(RunErl, ErlPrefix++ - "\\\""++Erl++"\\\"", - Tempdir, Nodename, Extra), - CPid = start_toerl_server(ToErl, Tempdir), - put(getline_skipped, []), - Res = (catch get_and_put(CPid, Commands, 1)), - case stop_runerl_node(CPid) of - {error,_} -> - CPid2 = start_toerl_server(ToErl, Tempdir), - put(getline_skipped, []), - ok = get_and_put - (CPid2, - [{putline,[7]}, - {sleep, - timeout(short)}, - {putline,""}, - {getline," -->"}, - {putline,"s"}, - {putline,"c"}, - {putline,""}], 1), - stop_runerl_node(CPid2); - _ -> - ok - end, - wait_for_runerl_server(SPid), - ok = ?RM_RF(Tempdir), - ok = Res - end - end. - -timeout(long) -> - 2 * timeout(normal); -timeout(short) -> - timeout(normal) div 10; -timeout(normal) -> - 10000 * test_server:timetrap_scale_factor(). - - -%% start_noshell_node(Name) -> -%% PADir = filename:dirname(code:which(?MODULE)), -%% {ok, Node} = test_server:start_node(Name,slave,[{args," -noshell -pa "++ -%% PADir++" "}]), -%% Node. -%% stop_noshell_node(Node) -> -%% test_server:stop_node(Node). - --ifndef(debug). -rm_rf(Dir) -> - try - {ok,List} = file:list_dir(Dir), - Files = [filename:join([Dir,X]) || X <- List], - [case file:list_dir(Y) of - {error, enotdir} -> - ok = file:delete(Y); - _ -> - ok = rm_rf(Y) - end || Y <- Files], - ok = file:del_dir(Dir), - ok - catch - _:Exception -> {error, {Exception,Dir}} - end. --endif. - -get_and_put(_CPid,[],_) -> - ok; -get_and_put(CPid, [{sleep, X}|T],N) -> - ?dbg({sleep, X}), - receive - after X -> - get_and_put(CPid,T,N+1) - end; -get_and_put(CPid, [{getline_pred,Pred,Msg}|T]=T0, N) - when is_function(Pred) -> - ?dbg({getline, Match}), - CPid ! {self(), {get_line, timeout(normal)}}, - receive - {get_line, timeout} -> - error_logger:error_msg("~p: getline timeout waiting for \"~s\" " - "(command number ~p, skipped: ~p)~n", - [?MODULE,Msg,N,get(getline_skipped)]), - {error, timeout}; - {get_line, Data} -> - ?dbg({data,Data}), - case Pred(Data) of - yes -> - put(getline_skipped, []), - get_and_put(CPid, T,N+1); - no -> - error_logger:error_msg("~p: getline match failure " - "\"~s\" " - "(command number ~p)\n", - [?MODULE,Msg,N]), - {error, no_match}; - maybe -> - List = get(getline_skipped), - put(getline_skipped, List ++ [Data]), - get_and_put(CPid, T0, N) - end - end; -get_and_put(CPid, [{getline, Match}|T],N) -> - ?dbg({getline, Match}), - F = fun(Data) -> - case lists:prefix(Match, Data) of - true -> yes; - false -> maybe - end - end, - get_and_put(CPid, [{getline_pred,F,Match}|T], N); -get_and_put(CPid, [{getline_re, Match}|T],N) -> - F = fun(Data) -> - case re:run(Data, Match, [{capture,none}]) of - match -> yes; - _ -> maybe - end - end, - get_and_put(CPid, [{getline_pred,F,Match}|T], N); -get_and_put(CPid, [{putline_raw, Line}|T],N) -> - ?dbg({putline_raw, Line}), - CPid ! {self(), {send_line, Line}}, - Timeout = timeout(normal), - receive - {send_line, ok} -> - get_and_put(CPid, T,N+1) - after Timeout -> - error_logger:error_msg("~p: putline_raw timeout (~p) sending " - "\"~s\" (command number ~p)~n", - [?MODULE, Timeout, Line, N]), - {error, timeout} - end; - -get_and_put(CPid, [{putline, Line}|T],N) -> - ?dbg({putline, Line}), - CPid ! {self(), {send_line, Line}}, - Timeout = timeout(normal), - receive - {send_line, ok} -> - get_and_put(CPid, [{getline, []}|T],N) - after Timeout -> - error_logger:error_msg("~p: putline timeout (~p) sending " - "\"~s\" (command number ~p)~n[~p]~n", - [?MODULE, Timeout, Line, N,get()]), - {error, timeout} - end. - -wait_for_runerl_server(SPid) -> - Ref = erlang:monitor(process, SPid), - Timeout = timeout(long), - receive - {'DOWN', Ref, process, SPid, _} -> - ok - after Timeout -> - {error, timeout} - end. - - - -stop_runerl_node(CPid) -> - Ref = erlang:monitor(process, CPid), - CPid ! {self(), kill_emulator}, - Timeout = timeout(long), - receive - {'DOWN', Ref, process, CPid, noproc} -> - ok; - {'DOWN', Ref, process, CPid, normal} -> - ok; - {'DOWN', Ref, process, CPid, {error, Reason}} -> - {error, Reason} - after Timeout -> - {error, timeout} - end. - -get_progs() -> - case os:type() of - {unix,freebsd} -> - {error,"cant use run_erl on freebsd"}; - {unix,openbsd} -> - {error,"cant use run_erl on openbsd"}; - {unix,_} -> - case os:find_executable("run_erl") of - RE when is_list(RE) -> - case os:find_executable("to_erl") of - TE when is_list(TE) -> - case os:find_executable("erl") of - E when is_list(E) -> - {RE,TE,E}; - _ -> - {error, "Could not find erl command"} - end; - _ -> - {error, "Could not find to_erl command"} - end; - _ -> - {error, "Could not find run_erl command"} - end; - _ -> - {error, "Not a unix OS"} - end. - -create_tempdir() -> - create_tempdir(filename:join(["/tmp","rtnode"++os:getpid()]),$A). - -create_tempdir(Dir,X) when X > $Z, X < $a -> - create_tempdir(Dir,$a); -create_tempdir(Dir,X) when X > $z -> - Estr = lists:flatten( - io_lib:format("Unable to create ~s, reason eexist", - [Dir++[$z]])), - {error, Estr}; -create_tempdir(Dir0, Ch) -> - %% Expect fairly standard unix. - Dir = Dir0++[Ch], - case file:make_dir(Dir) of - {error, eexist} -> - create_tempdir(Dir0, Ch+1); - {error, Reason} -> - Estr = lists:flatten( - io_lib:format("Unable to create ~s, reason ~p", - [Dir,Reason])), - {error,Estr}; - ok -> - Dir - end. - -create_nodename() -> - create_nodename($A). - -create_nodename(X) when X > $Z, X < $a -> - create_nodename($a); -create_nodename(X) when X > $z -> - {error,out_of_nodenames}; -create_nodename(X) -> - NN = "rtnode"++os:getpid()++[X], - case file:read_file_info(filename:join(["/tmp",NN])) of - {error,enoent} -> - Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")), - {ok,NN++"@"++Host}; - _ -> - create_nodename(X+1) - end. - - -start_runerl_node(RunErl,Erl,Tempdir,Nodename,Extra) -> - XArg = case Nodename of - [] -> - []; - _ -> - " -sname "++(if is_atom(Nodename) -> atom_to_list(Nodename); - true -> Nodename - end)++ - " -setcookie "++atom_to_list(erlang:get_cookie()) - end, - XXArg = case Extra of - [] -> - []; - _ -> - " "++Extra - end, - spawn(fun() -> - ?dbg("\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++ - " \""++Erl++XArg++XXArg++"\""), - os:cmd("\""++RunErl++"\" "++Tempdir++"/ "++Tempdir++ - " \""++Erl++XArg++XXArg++"\"") - end). - -start_toerl_server(ToErl,Tempdir) -> - Pid = spawn(?MODULE,toerl_server,[self(),ToErl,Tempdir]), - receive - {Pid,started} -> - Pid; - {Pid,error,Reason} -> - {error,Reason} - end. - -try_to_erl(_Command, 0) -> - {error, cannot_to_erl}; -try_to_erl(Command, N) -> - ?dbg({?LINE,N}), - Port = open_port({spawn, Command},[eof,{line,1000}]), - Timeout = timeout(normal) div 2, - receive - {Port, eof} -> - receive after Timeout -> - ok - end, - try_to_erl(Command, N-1) - after Timeout -> - ?dbg(Port), - Port - end. - -toerl_server(Parent,ToErl,Tempdir) -> - Port = try_to_erl("\""++ToErl++"\" "++Tempdir++"/ 2>/dev/null",8), - case Port of - P when is_port(P) -> - Parent ! {self(),started}; - {error,Other} -> - Parent ! {self(),error,Other}, - exit(Other) - end, - case toerl_loop(Port,[]) of - normal -> - ok; - {error, Reason} -> - error_logger:error_msg("toerl_server exit with reason ~p~n", - [Reason]), - exit(Reason) - end. - -toerl_loop(Port,Acc) -> - ?dbg({toerl_loop, Port, Acc}), - receive - {Port,{data,{Tag0,Data}}} when is_port(Port) -> - ?dbg({?LINE,Port,{data,{Tag0,Data}}}), - case Acc of - [{noeol,Data0}|T0] -> - toerl_loop(Port,[{Tag0, Data0++Data}|T0]); - _ -> - toerl_loop(Port,[{Tag0,Data}|Acc]) - end; - {Pid,{get_line,Timeout}} -> - case Acc of - [] -> - case get_data_within(Port,Timeout,[]) of - timeout -> - Pid ! {get_line, timeout}, - toerl_loop(Port,[]); - {noeol,Data1} -> - Pid ! {get_line, timeout}, - toerl_loop(Port,[{noeol,Data1}]); - {eol,Data2} -> - Pid ! {get_line, Data2}, - toerl_loop(Port,[]) - end; - [{noeol,Data3}] -> - case get_data_within(Port,Timeout,Data3) of - timeout -> - Pid ! {get_line, timeout}, - toerl_loop(Port,Acc); - {noeol,Data4} -> - Pid ! {get_line, timeout}, - toerl_loop(Port,[{noeol,Data4}]); - {eol,Data5} -> - Pid ! {get_line, Data5}, - toerl_loop(Port,[]) - end; - List -> - {NewAcc,[{eol,Data6}]} = lists:split(length(List)-1,List), - Pid ! {get_line,Data6}, - toerl_loop(Port,NewAcc) - end; - {Pid, {send_line, Data7}} -> - Port ! {self(),{command, Data7++"\n"}}, - Pid ! {send_line, ok}, - toerl_loop(Port,Acc); - {_Pid, kill_emulator} -> - Port ! {self(),{command, "init:stop().\n"}}, - Timeout1 = timeout(long), - receive - {Port,eof} -> - normal - after Timeout1 -> - {error, kill_timeout} - end; - {Port, eof} -> - {error, unexpected_eof}; - Other -> - {error, {unexpected, Other}} - end. - -millistamp() -> - erlang:monotonic_time(millisecond). - -get_data_within(Port, X, Acc) when X =< 0 -> - ?dbg({get_data_within, X, Acc, ?LINE}), +get_all_port_data(Port, Acc) -> receive - {Port,{data,{Tag0,Data}}} -> - ?dbg({?LINE,Port,{data,{Tag0,Data}}}), - {Tag0, Acc++Data} - after 0 -> - case Acc of - [] -> - timeout; - Noeol -> - {noeol,Noeol} - end - end; - - -get_data_within(Port, Timeout, Acc) -> - ?dbg({get_data_within, Timeout, Acc, ?LINE}), - T1 = millistamp(), - receive - {Port,{data,{noeol,Data}}} -> - ?dbg({?LINE,Port,{data,{noeol,Data}}}), - Elapsed = millistamp() - T1 + 1, - get_data_within(Port, Timeout - Elapsed, Acc ++ Data); - {Port,{data,{eol,Data1}}} -> - ?dbg({?LINE,Port,{data,{eol,Data1}}}), - {eol, Acc ++ Data1} - after Timeout -> - timeout + {Port, {data, Data}} -> + get_all_port_data(Port, [Acc|Data]); + {Port, eof} -> + lists:flatten(Acc) end. -get_default_shell() -> - Match = fun(Data) -> - case lists:prefix("undefined", Data) of - true -> - yes; - false -> - case re:run(Data, "<\\d+[.]\\d+[.]\\d+>", - [{capture,none}]) of - match -> no; - _ -> maybe - end - end - end, +write_raw_to_stdout() -> try - rtnode([{putline,""}, - {putline, "whereis(user_drv)."}, - {getline_pred, Match, "matching of user_drv pid"}], []), - old - catch _E:_R -> - ?dbg({_E,_R}), - new + ok = io:setopts(standard_io, [{encoding, latin1}]), + ok = file:write(standard_io, lists:seq(0,255)), + halt(0) + catch + Class:Reason:StackTrace -> + io:format(standard_error, "~p~p~p", [Class, Reason, StackTrace]), + halt(17) end. +raw_stdout_isatty(Config) when is_list(Config) -> + rtnode:run( + [{putline,"io:setopts(group_leader(), [{encoding, latin1}])."}, + {putline,"file:write(group_leader(),[90, 127, 128, 255, 131, 90, 10])."},% + {expect, "\\QZ^?\\200\\377\\203Z\\E"} + ],[]), + ok. %% %% Test I/O-server %% diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index bbd0d81b1c7a..59f2e8bd0350 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -32,7 +32,7 @@ %% Test cases must be exported. -export([member/1, reverse/1, keymember/1, keysearch_keyfind/1, - keystore/1, keytake/1, keyreplace/1, + keystore/1, keytake/1, keyreplace/1, append_1/1, append_2/1, seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1, @@ -53,12 +53,17 @@ ufunmerge/1, rufunmerge/1, ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1, ufunsort_error/1, + uniq_1/1, uniq_2/1, zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, + zip_fail/1, zip_trim/1, zip_pad/1, + zip3_fail/1, zip3_trim/1, zip3_pad/1, + zipwith_fail/1, zipwith_trim/1, zipwith_pad/1, + zipwith3_fail/1, zipwith3_trim/1, zipwith3_pad/1, filter_partition/1, join/1, otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1, suffix/1, subtract/1, droplast/1, search/1, hof/1, - error_info/1]). + enumerate/1, error_info/1]). %% Sort randomized lists until stopped. %% @@ -81,10 +86,11 @@ suite() -> all() -> [{group, append}, {group, key}, - {group,sort}, + {group, sort}, {group, usort}, {group, keysort}, {group, ukeysort}, + {group, uniq}, {group, funsort}, {group, ufunsort}, {group, sublist}, @@ -119,10 +125,15 @@ groups() -> {flatten, [parallel], [flatten_1, flatten_2, flatten_1_e, flatten_2_e]}, {tickets, [parallel], [otp_5939, otp_6023, otp_6606, otp_7230]}, - {zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3]}, + {zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3, + zip_fail, zip_trim, zip_pad, + zip3_fail, zip3_trim, zip3_pad, + zipwith_fail, zipwith_trim, zipwith_pad, + zipwith3_fail, zipwith3_trim, zipwith3_pad]}, + {uniq, [parallel], [uniq_1, uniq_2]}, {misc, [parallel], [reverse, member, dropwhile, takewhile, filter_partition, suffix, subtract, join, - hof, droplast, search, error_info]} + hof, droplast, search, enumerate, error_info]} ]. init_per_suite(Config) -> @@ -430,6 +441,8 @@ keyreplace(Config) when is_list(Config) -> merge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), + %% merge list of lists [] = lists:merge([]), [] = lists:merge([[]]), @@ -452,6 +465,33 @@ merge(Config) when is_list(Config) -> Seq = lists:seq(1,100), true = Seq == lists:merge(lists:map(fun(E) -> [E] end, Seq)), + true = erts_debug:same(Singleton, lists:merge([Singleton])), + true = erts_debug:same(Singleton, lists:merge([Singleton, []])), + true = erts_debug:same(Singleton, lists:merge([[], Singleton])), + true = erts_debug:same(Singleton, lists:merge([Singleton, [], []])), + true = erts_debug:same(Singleton, lists:merge([[], Singleton, []])), + true = erts_debug:same(Singleton, lists:merge([[], [], Singleton])), + + {'EXIT', _} = (catch lists:merge([a])), + {'EXIT', _} = (catch lists:merge([a, b])), + {'EXIT', _} = (catch lists:merge([a, []])), + {'EXIT', _} = (catch lists:merge([[], b])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b])), + {'EXIT', _} = (catch lists:merge([a, b, c])), + {'EXIT', _} = (catch lists:merge([a, b, []])), + {'EXIT', _} = (catch lists:merge([a, [], c])), + {'EXIT', _} = (catch lists:merge([a, [], []])), + {'EXIT', _} = (catch lists:merge([[], b, c])), + {'EXIT', _} = (catch lists:merge([[], b, []])), + {'EXIT', _} = (catch lists:merge([[], [], c])), + {'EXIT', _} = (catch lists:merge([a, b, [1, 2, 3]])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3], c])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3], [4, 5, 6]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b, c])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b, [4, 5, 6]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], [4, 5, 6], c])), + Two = [1,2], Six = [1,2,3,4,5,6], @@ -471,6 +511,15 @@ merge(Config) when is_list(Config) -> [1,2,3,4,5,7] = lists:merge([2,4], [1,3,5,7]), [1,2,3,4,5,6,7] = lists:merge([2,4,6], [1,3,5,7]), + true = erts_debug:same(Singleton, lists:merge([], Singleton)), + true = erts_debug:same(Singleton, lists:merge(Singleton, [])), + + {'EXIT', _} = (catch lists:merge(a, b)), + {'EXIT', _} = (catch lists:merge(a, [])), + {'EXIT', _} = (catch lists:merge([], b)), + {'EXIT', _} = (catch lists:merge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge([1, 2, 3], b)), + %% 3-way merge [] = lists:merge3([], [], []), Two = lists:merge3([], [], Two), @@ -487,11 +536,28 @@ merge(Config) when is_list(Config) -> Nine = lists:merge3([7,8,9],[4,5,6],[1,2,3]), Nine = lists:merge3([4,5,6],[7,8,9],[1,2,3]), + true = erts_debug:same(Singleton, lists:merge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:merge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:merge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:merge3(a, b, c)), + {'EXIT', _} = (catch lists:merge3(a, b, [])), + {'EXIT', _} = (catch lists:merge3(a, [], c)), + {'EXIT', _} = (catch lists:merge3(a, [], [])), + {'EXIT', _} = (catch lists:merge3([], b, [])), + {'EXIT', _} = (catch lists:merge3([], [], c)), + {'EXIT', _} = (catch lists:merge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:merge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:merge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:merge3([1, 2, 3], [4, 5, 6], c)), + ok. %% reverse merge functions rmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], @@ -511,6 +577,15 @@ rmerge(Config) when is_list(Config) -> [7,5,4,3,2,1] = lists:rmerge([4,2], [7,5,3,1]), [7,6,5,4,3,2,1] = lists:rmerge([6,4,2], [7,5,3,1]), + true = erts_debug:same(Singleton, lists:rmerge([], Singleton)), + true = erts_debug:same(Singleton, lists:rmerge(Singleton, [])), + + {'EXIT', _} = (catch lists:rmerge(a, b)), + {'EXIT', _} = (catch lists:rmerge(a, [])), + {'EXIT', _} = (catch lists:rmerge([], b)), + {'EXIT', _} = (catch lists:rmerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge([1, 2, 3], b)), + Nine = [9,8,7,6,5,4,3,2,1], %% 3-way reversed merge @@ -529,6 +604,22 @@ rmerge(Config) when is_list(Config) -> Nine = lists:rmerge3([9,8,7],[6,5,4],[3,2,1]), Nine = lists:rmerge3([6,5,4],[9,8,7],[3,2,1]), + true = erts_debug:same(Singleton, lists:rmerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:rmerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:rmerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:rmerge3(a, b, c)), + {'EXIT', _} = (catch lists:rmerge3(a, b, [])), + {'EXIT', _} = (catch lists:rmerge3(a, [], c)), + {'EXIT', _} = (catch lists:rmerge3(a, [], [])), + {'EXIT', _} = (catch lists:rmerge3([], b, [])), + {'EXIT', _} = (catch lists:rmerge3([], [], c)), + {'EXIT', _} = (catch lists:rmerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:rmerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:rmerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:rmerge3([1, 2, 3], [4, 5, 6], c)), + ok. sort_1(Config) when is_list(Config) -> @@ -629,6 +720,8 @@ usort_1(Conf) when is_list(Conf) -> ok. umerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), + %% merge list of lists [] = lists:umerge([]), [] = lists:umerge([[]]), @@ -652,6 +745,33 @@ umerge(Conf) when is_list(Conf) -> Seq = lists:seq(1,100), true = Seq == lists:umerge(lists:map(fun(E) -> [E] end, Seq)), + true = erts_debug:same(Singleton, lists:umerge([Singleton])), + true = erts_debug:same(Singleton, lists:umerge([Singleton, []])), + true = erts_debug:same(Singleton, lists:umerge([[], Singleton])), + true = erts_debug:same(Singleton, lists:umerge([Singleton, [], []])), + true = erts_debug:same(Singleton, lists:umerge([[], Singleton, []])), + true = erts_debug:same(Singleton, lists:umerge([[], [], Singleton])), + + {'EXIT', _} = (catch lists:umerge([a])), + {'EXIT', _} = (catch lists:umerge([a, b])), + {'EXIT', _} = (catch lists:umerge([a, []])), + {'EXIT', _} = (catch lists:umerge([[], b])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b])), + {'EXIT', _} = (catch lists:umerge([a, b, c])), + {'EXIT', _} = (catch lists:umerge([a, b, []])), + {'EXIT', _} = (catch lists:umerge([a, [], c])), + {'EXIT', _} = (catch lists:umerge([a, [], []])), + {'EXIT', _} = (catch lists:umerge([[], b, c])), + {'EXIT', _} = (catch lists:umerge([[], b, []])), + {'EXIT', _} = (catch lists:umerge([[], [], c])), + {'EXIT', _} = (catch lists:umerge([a, b, [1, 2, 3]])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3], c])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3], [4, 5, 6]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b, c])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b, [4, 5, 6]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], [4, 5, 6], c])), + Two = [1,2], Six = [1,2,3,4,5,6], @@ -678,6 +798,15 @@ umerge(Conf) when is_list(Conf) -> [1,2,3,4,5,7] = lists:umerge([2,4], [1,2,3,4,5,7]), [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,2,3,4,5,6,7]), + true = erts_debug:same(Singleton, lists:umerge([], Singleton)), + true = erts_debug:same(Singleton, lists:umerge(Singleton, [])), + + {'EXIT', _} = (catch lists:umerge(a, b)), + {'EXIT', _} = (catch lists:umerge(a, [])), + {'EXIT', _} = (catch lists:umerge([], b)), + {'EXIT', _} = (catch lists:umerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge([1, 2, 3], b)), + %% 3-way unique merge [] = lists:umerge3([], [], []), Two = lists:umerge3([], [], Two), @@ -699,9 +828,27 @@ umerge(Conf) when is_list(Conf) -> [1,2,3] = lists:umerge3([1,2,3],[2,3],[1,2,3]), [1,2,3,4] = lists:umerge3([2,3,4],[3,4],[1,2,3]), + true = erts_debug:same(Singleton, lists:umerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:umerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:umerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:umerge3(a, b, c)), + {'EXIT', _} = (catch lists:umerge3(a, b, [])), + {'EXIT', _} = (catch lists:umerge3(a, [], c)), + {'EXIT', _} = (catch lists:umerge3(a, [], [])), + {'EXIT', _} = (catch lists:umerge3([], b, [])), + {'EXIT', _} = (catch lists:umerge3([], [], c)), + {'EXIT', _} = (catch lists:umerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:umerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:umerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:umerge3([1, 2, 3], [4, 5, 6], c)), + ok. rumerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), + Two = [2,1], Six = [6,5,4,3,2,1], @@ -728,6 +875,15 @@ rumerge(Conf) when is_list(Conf) -> [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,4,3,2,1]), [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,6,5,4,3,2,1]), + true = erts_debug:same(Singleton, lists:rumerge([], Singleton)), + true = erts_debug:same(Singleton, lists:rumerge(Singleton, [])), + + {'EXIT', _} = (catch lists:rumerge(a, b)), + {'EXIT', _} = (catch lists:rumerge(a, [])), + {'EXIT', _} = (catch lists:rumerge([], b)), + {'EXIT', _} = (catch lists:rumerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge([1, 2, 3], b)), + Nine = [9,8,7,6,5,4,3,2,1], %% 3-way reversed unique merge @@ -756,6 +912,23 @@ rumerge(Conf) when is_list(Conf) -> true = lists:umerge(L1, L2) == lists:reverse(lists:rumerge(lists:reverse(L1), lists:reverse(L2))), + + true = erts_debug:same(Singleton, lists:rumerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:rumerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:rumerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:rumerge3(a, b, c)), + {'EXIT', _} = (catch lists:rumerge3(a, b, [])), + {'EXIT', _} = (catch lists:rumerge3(a, [], c)), + {'EXIT', _} = (catch lists:rumerge3(a, [], [])), + {'EXIT', _} = (catch lists:rumerge3([], b, [])), + {'EXIT', _} = (catch lists:rumerge3([], [], c)), + {'EXIT', _} = (catch lists:rumerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:rumerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:rumerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:rumerge3([1, 2, 3], [4, 5, 6], c)), + ok. %% usort/1 on big randomized lists. @@ -812,6 +985,7 @@ ucheck_stability(L) -> %% Key merge two lists. keymerge(Config) when is_list(Config) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{1,a},{2,b}], Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], @@ -840,11 +1014,21 @@ keymerge(Config) when is_list(Config) -> [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = lists:keymerge(1,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:keymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:keymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:keymerge(1, a, b)), + {'EXIT', _} = (catch lists:keymerge(1, a, [])), + {'EXIT', _} = (catch lists:keymerge(1, [], b)), + {'EXIT', _} = (catch lists:keymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:keymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. %% Reverse key merge two lists. rkeymerge(Config) when is_list(Config) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{2,b},{1,a}], Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], @@ -877,6 +1061,15 @@ rkeymerge(Config) when is_list(Config) -> lists:reverse(lists:rkeymerge(1,lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rkeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:rkeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:rkeymerge(1, a, b)), + {'EXIT', _} = (catch lists:rkeymerge(1, a, [])), + {'EXIT', _} = (catch lists:rkeymerge(1, [], b)), + {'EXIT', _} = (catch lists:rkeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:rkeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. keysort_1(Config) when is_list(Config) -> @@ -995,6 +1188,7 @@ keycompare(I, J, A, B) when element(I, A) == element(I, B), %% Merge two lists while removing duplicates. ukeymerge(Conf) when is_list(Conf) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{1,a},{2,b}], Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], @@ -1044,11 +1238,21 @@ ukeymerge(Conf) when is_list(Conf) -> L2 = [{b,1},{b,3},{b,5},{b,7}], L1 = lists:ukeymerge(2, L1, L2), + true = erts_debug:same(Singleton, lists:ukeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:ukeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:ukeymerge(1, a, b)), + {'EXIT', _} = (catch lists:ukeymerge(1, a, [])), + {'EXIT', _} = (catch lists:ukeymerge(1, [], b)), + {'EXIT', _} = (catch lists:ukeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:ukeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. %% Reverse merge two lists while removing duplicates. rukeymerge(Conf) when is_list(Conf) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{2,b},{1,a}], Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], @@ -1098,6 +1302,15 @@ rukeymerge(Conf) when is_list(Conf) -> lists:reverse(lists:rukeymerge(2, lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rukeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:rukeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:rukeymerge(1, a, b)), + {'EXIT', _} = (catch lists:rukeymerge(1, a, [])), + {'EXIT', _} = (catch lists:rukeymerge(1, [], b)), + {'EXIT', _} = (catch lists:rukeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:rukeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. ukeysort_1(Config) when is_list(Config) -> @@ -1275,6 +1488,7 @@ ukeycompare(I, J, A, B) when A =/= B, %% Merge two lists using a fun. funmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [1,2], Six = [1,2,3,4,5,6], F = fun(X, Y) -> X =< Y end, @@ -1299,11 +1513,21 @@ funmerge(Config) when is_list(Config) -> [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:merge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:merge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:merge(F, a, b)), + {'EXIT', _} = (catch lists:merge(F, a, [])), + {'EXIT', _} = (catch lists:merge(F, [], b)), + {'EXIT', _} = (catch lists:merge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge(F, [1, 2, 3], b)), + ok. %% Reverse merge two lists using a fun. rfunmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], F = fun(X, Y) -> X =< Y end, @@ -1331,6 +1555,15 @@ rfunmerge(Config) when is_list(Config) -> lists:merge(F2, L1, L2) == lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rmerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:rmerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:rmerge(F, a, b)), + {'EXIT', _} = (catch lists:rmerge(F, a, [])), + {'EXIT', _} = (catch lists:rmerge(F, [], b)), + {'EXIT', _} = (catch lists:rmerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge(F, [1, 2, 3], b)), + ok. @@ -1400,6 +1633,7 @@ funsort_check(I, Input, Expected) -> %% Merge two lists while removing duplicates using a fun. ufunmerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), Two = [1,2], Six = [1,2,3,4,5,6], F = fun(X, Y) -> X =< Y end, @@ -1434,10 +1668,20 @@ ufunmerge(Conf) when is_list(Conf) -> [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] = lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:umerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:umerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:umerge(F, a, b)), + {'EXIT', _} = (catch lists:umerge(F, a, [])), + {'EXIT', _} = (catch lists:umerge(F, [], b)), + {'EXIT', _} = (catch lists:umerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge(F, [1, 2, 3], b)), + ok. %% Reverse merge two lists while removing duplicates using a fun. rufunmerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], F = fun(X, Y) -> X =< Y end, @@ -1477,6 +1721,15 @@ rufunmerge(Conf) when is_list(Conf) -> lists:umerge(F2, L3, L4) == lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))), + true = erts_debug:same(Singleton, lists:rumerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:rumerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:rumerge(F, a, b)), + {'EXIT', _} = (catch lists:rumerge(F, a, [])), + {'EXIT', _} = (catch lists:rumerge(F, [], b)), + {'EXIT', _} = (catch lists:rumerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge(F, [1, 2, 3], b)), + ok. ufunsort_1(Config) when is_list(Config) -> @@ -2359,6 +2612,41 @@ zip_unzip(Config) when is_list(Config) -> {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])), ok. +zip_fail(Config) when is_list(Config) -> + [] = lists:zip([], [], fail), + {'EXIT', {function_clause, _}} = (catch lists:zip([a], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip([], [c], fail)), + + [{a, c}] = lists:zip([a], [c], fail), + {'EXIT', {function_clause, _}} = (catch lists:zip([a, b], [c], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip([a], [c, d], fail)), + + ok. + +zip_trim(Config) when is_list(Config) -> + [] = lists:zip([], [], trim), + [] = lists:zip([a], [], trim), + [] = lists:zip([], [c], trim), + + [{a, c}] = lists:zip([a], [c], trim), + [{a, c}] = lists:zip([a, b], [c], trim), + [{a, c}] = lists:zip([a], [c, d], trim), + + ok. + +zip_pad(Config) when is_list(Config) -> + How = {pad, {x, y}}, + + [] = lists:zip([], [], How), + [{a, y}] = lists:zip([a], [], How), + [{x, c}] = lists:zip([], [c], How), + + [{a, c}] = lists:zip([a], [c], How), + [{a, c}, {b, y}] = lists:zip([a, b], [c], How), + [{a, c}, {x, d}] = lists:zip([a], [c, d], How), + + ok. + %% Test lists:zip3/3, lists:unzip3/1. zip_unzip3(Config) when is_list(Config) -> [] = lists:zip3([], [], []), @@ -2385,6 +2673,65 @@ zip_unzip3(Config) when is_list(Config) -> ok. +zip3_fail(Config) when is_list(Config) -> + [] = lists:zip3([], [], [], fail), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([], [c], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [c], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([], [], [e], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [], [e], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([], [c], [e], fail)), + + [{a, c, e}] = lists:zip3([a], [c], [e], fail), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a, b], [c], [e], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [c, d], [e], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a, b], [c, d], [e], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [c], [e, f], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a, b], [c], [e, f], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zip3([a], [c, d], [e, f], fail)), + + ok. + +zip3_trim(Config) when is_list(Config) -> + [] = lists:zip3([], [], [], trim), + [] = lists:zip3([a], [], [], trim), + [] = lists:zip3([], [c], [], trim), + [] = lists:zip3([a], [c], [], trim), + [] = lists:zip3([], [], [e], trim), + [] = lists:zip3([a], [], [e], trim), + [] = lists:zip3([], [c], [e], trim), + + [{a, c, e}] = lists:zip3([a], [c], [e], trim), + [{a, c, e}] = lists:zip3([a, b], [c], [e], trim), + [{a, c, e}] = lists:zip3([a], [c, d], [e], trim), + [{a, c, e}] = lists:zip3([a, b], [c, d], [e], trim), + [{a, c, e}] = lists:zip3([a], [c], [e, f], trim), + [{a, c, e}] = lists:zip3([a, b], [c], [e, f], trim), + [{a, c, e}] = lists:zip3([a], [c, d], [e, f], trim), + + ok. + +zip3_pad(Config) when is_list(Config) -> + How = {pad, {x, y, z}}, + + [] = lists:zip3([], [], [], How), + [{a, y, z}] = lists:zip3([a], [], [], How), + [{x, c, z}] = lists:zip3([], [c], [], How), + [{a, c, z}] = lists:zip3([a], [c], [], How), + [{x, y, e}] = lists:zip3([], [], [e], How), + [{a, y, e}] = lists:zip3([a], [], [e], How), + [{x, c, e}] = lists:zip3([], [c], [e], How), + + [{a, c, e}] = lists:zip3([a], [c], [e], How), + [{a, c, e}, {b, y, z}] = lists:zip3([a, b], [c], [e], How), + [{a, c, e}, {x, d, z}] = lists:zip3([a], [c, d], [e], How), + [{a, c, e}, {b, d, z}] = lists:zip3([a, b], [c, d], [e], How), + [{a, c, e}, {x, y, f}] = lists:zip3([a], [c], [e, f], How), + [{a, c, e}, {b, y, f}] = lists:zip3([a, b], [c], [e, f], How), + [{a, c, e}, {x, d, f}] = lists:zip3([a], [c, d], [e, f], How), + + ok. + %% Test lists:zipwith/3. zipwith(Config) when is_list(Config) -> Zip = fun(A, B) -> [A|B] end, @@ -2407,6 +2754,47 @@ zipwith(Config) when is_list(Config) -> {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])), ok. +zipwith_fail(Config) when is_list(Config) -> + Zip = fun(A, B) -> A * B end, + + [] = lists:zipwith(Zip, [], [], fail), + {'EXIT', {function_clause, _}} = (catch lists:zipwith(Zip, [2], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith(Zip, [], [5], fail)), + + [2 * 5] = lists:zipwith(Zip, [2], [5], fail), + {'EXIT', {function_clause, _}} = (catch lists:zipwith(Zip, [2, 3], [5], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith(Zip, [2], [5, 7], fail)), + + ok. + +zipwith_trim(Config) when is_list(Config) -> + Zip = fun(A, B) -> A * B end, + + [] = lists:zipwith(Zip, [], [], trim), + [] = lists:zipwith(Zip, [2], [], trim), + [] = lists:zipwith(Zip, [], [5], trim), + + [2 * 5] = lists:zipwith(Zip, [2], [5], trim), + [2 * 5] = lists:zipwith(Zip, [2, 3], [5], trim), + [2 * 5] = lists:zipwith(Zip, [2], [5, 7], trim), + + ok. + +zipwith_pad(Config) when is_list(Config) -> + How = {pad, {17, 19}}, + + Zip = fun(A, B) -> A * B end, + + [] = lists:zipwith(Zip, [], [], How), + [ 2 * 19] = lists:zipwith(Zip, [2], [], How), + [17 * 5] = lists:zipwith(Zip, [], [5], How), + + [2 * 5] = lists:zipwith(Zip, [2], [5], How), + [2 * 5, 3 * 19] = lists:zipwith(Zip, [2, 3], [5], How), + [2 * 5, 17 * 7] = lists:zipwith(Zip, [2], [5, 7], How), + + ok. + %% Test lists:zipwith3/4. zipwith3(Config) when is_list(Config) -> Zip = fun(A, B, C) -> [A,B,C] end, @@ -2431,6 +2819,69 @@ zipwith3(Config) when is_list(Config) -> ok. +zipwith3_fail(Config) when is_list(Config) -> + Zip = fun(A, B, C) -> A * B * C end, + + [] = lists:zipwith3(Zip, [], [], [], fail), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [], [5], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [5], [], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [], [], [11], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [], [11], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [], [5], [11], fail)), + + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5], [11], fail), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2, 3], [5], [11], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [5, 7], [11], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2, 3], [5, 7], [11], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [5], [11, 13], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2, 3], [5], [11, 13], fail)), + {'EXIT', {function_clause, _}} = (catch lists:zipwith3(Zip, [2], [5, 7], [11, 13], fail)), + + ok. + +zipwith3_trim(Config) when is_list(Config) -> + Zip = fun(A, B, C) -> A * B * C end, + + [] = lists:zipwith3(Zip, [], [], [], trim), + [] = lists:zipwith3(Zip, [2], [], [], trim), + [] = lists:zipwith3(Zip, [], [5], [], trim), + [] = lists:zipwith3(Zip, [], [], [11], trim), + [] = lists:zipwith3(Zip, [2], [], [11], trim), + [] = lists:zipwith3(Zip, [], [5], [11], trim), + + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5], [11], trim), + [2 * 5 * 11] = lists:zipwith3(Zip, [2, 3], [5], [11], trim), + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5, 7], [11], trim), + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5], [11, 13], trim), + [2 * 5 * 11] = lists:zipwith3(Zip, [2, 3], [5], [11, 13], trim), + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5, 7], [11, 13], trim), + + ok. + +zipwith3_pad(Config) when is_list(Config) -> + How = {pad, {17, 19, 23}}, + + Zip = fun(A, B, C) -> A * B * C end, + + [] = lists:zipwith3(Zip, [], [], [], How), + [ 2 * 19 * 23] = lists:zipwith3(Zip, [2], [], [], How), + [17 * 5 * 23] = lists:zipwith3(Zip, [], [5], [], How), + [ 2 * 5 * 23] = lists:zipwith3(Zip, [2], [5], [], How), + [17 * 19 * 11] = lists:zipwith3(Zip, [], [], [11], How), + [ 2 * 19 * 11] = lists:zipwith3(Zip, [2], [], [11], How), + [17 * 5 * 11] = lists:zipwith3(Zip, [], [5], [11], How), + + [2 * 5 * 11] = lists:zipwith3(Zip, [2], [5], [11], How), + [2 * 5 * 11, 3 * 19 * 23] = lists:zipwith3(Zip, [2, 3], [5], [11], How), + [2 * 5 * 11, 17 * 7 * 23] = lists:zipwith3(Zip, [2], [5, 7], [11], How), + [2 * 5 * 11, 3 * 7 * 23] = lists:zipwith3(Zip, [2, 3], [5, 7], [11], How), + [2 * 5 * 11, 17 * 19 * 13] = lists:zipwith3(Zip, [2], [5], [11, 13], How), + [2 * 5 * 11, 3 * 19 * 13] = lists:zipwith3(Zip, [2, 3], [5], [11, 13], How), + [2 * 5 * 11, 17 * 7 * 13] = lists:zipwith3(Zip, [2], [5, 7], [11, 13], How), + + ok. + %% Test lists:join/2 join(Config) when is_list(Config) -> A = [a,b,c], @@ -2743,6 +3194,46 @@ hof(Config) when is_list(Config) -> ok. +%% Test lists:enumerate/1 and lists:enumerate/2 +enumerate(Config) when is_list(Config) -> + [] = lists:enumerate([]), + [] = lists:enumerate(10, []), + [] = lists:enumerate(-10, []), + [] = lists:enumerate(10, 2, []), + [] = lists:enumerate(10, -2, []), + [] = lists:enumerate(-10, 2, []), + [] = lists:enumerate(-10, -2, []), + [{1,a},{2,b},{3,c}] = lists:enumerate([a,b,c]), + [{10,a},{11,b},{12,c}] = lists:enumerate(10, [a,b,c]), + [{-10,a},{-9,b},{-8,c}] = lists:enumerate(-10, [a,b,c]), + [{10,a},{12,b},{14,c}] = lists:enumerate(10, 2, [a,b,c]), + [{10,a},{8,b},{6,c}] = lists:enumerate(10, -2, [a,b,c]), + [{-10,a},{-12,b},{-14,c}] = lists:enumerate(-10, -2, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(0), + {'EXIT', {function_clause, _}} = catch lists:enumerate(0, 10), + {'EXIT', {function_clause, _}} = catch lists:enumerate(0, 10, 20), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, 2, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, 2, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, 2.0, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, 2.0, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, 2.0, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1.0, 2.0, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, 2, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, 2, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, <<2>>, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, <<2>>, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, <<2>>, []), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1>>, <<2>>, [a,b,c]), + {'EXIT', {function_clause, _}} = catch lists:enumerate(<<1,2,3>>), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, <<1,2,3>>), + {'EXIT', {function_clause, _}} = catch lists:enumerate(1, 2, <<1,2,3>>), + + ok. + error_info(_Config) -> L = [{keyfind, [whatever, bad_position, bad_list], [{2,".*"},{3,".*"}]}, {keymember, [key, 0, bad_list], [{2,".*"}, {3,".*"}]}, @@ -2767,3 +3258,22 @@ do_error_info(L0) -> NYI = [{F,lists:duplicate(A, '*'),nyi} || {F,A} <- Bifs -- Tests], L = lists:sort(NYI ++ L1), error_info_lib:test_error_info(lists, L, [snifs_only]). + +uniq_1(_Config) -> + [] = lists:uniq([]), + [foo] = lists:uniq([foo]), + ["foo", "bar", "zoo"] = lists:uniq(["foo", "foo", "bar", "foo", "zoo", + "foo", "bar", "zoo"]), + [a, 1, b, 2] = lists:uniq([a, a, a, 1, b, 2, a, 2, 1]), + [<<"home">>, "home"] = lists:uniq([<<"home">>, "home"]), + [3.14159, 2.71828, 3.17] = lists:uniq([3.14159, 3.14159, 2.71828, 3.17]), + [42, 42.0] = lists:uniq([42, 42.0, 42, 42.0]), + ok. + +uniq_2(_Config) -> + [] = lists:uniq(fun(X) -> X end, []), + [{42, 1}, {42.0, 99}, {a, 99}] = + lists:uniq(fun(X) -> element(1, X) end, + [{42, 1}, {42.0, 99}, {a, 99}, {a, 1}, {42, 100}]), + [1] = lists:uniq(fun(_) -> whatever end, lists:seq(1, 10)), + ok. diff --git a/lib/stdlib/test/lists_property_test_SUITE.erl b/lib/stdlib/test/lists_property_test_SUITE.erl new file mode 100644 index 000000000000..ecbf14309e6d --- /dev/null +++ b/lib/stdlib/test/lists_property_test_SUITE.erl @@ -0,0 +1,441 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2023. 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(lists_property_test_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-compile(export_all). + +all() -> + [ + all_true_case, all_false_case, + any_true_case, any_false_case, + append_1_case, + append_2_case, + concat_case, + delete_case, delete_absent_case, + droplast_case, + dropwhile_case, + duplicate_case, + enumerate_1_case, + enumerate_2_case, + enumerate_3_case, + filter_case, + filtermap_case, + flatlength_case, + flatmap_case, + flatten_1_case, + flatten_2_case, + foldl_case, + foldr_case, + foreach_case, + join_case, + keydelete_case, keydelete_absent_case, + keyfind_case, keyfind_absent_case, + keymap_case, + keymember_case, keymember_absent_case, + keymerge_case, keymerge_invalid_case, + keyreplace_case, keyreplace_absent_case, + keysearch_case, keysearch_absent_case, + keysort_case, + keystore_case, keystore_absent_case, + keytake_case, keytake_absent_case, + last_case, + map_case, + mapfoldl_case, + mapfoldr_case, + max_case, + member_case, member_absent_case, + merge_1_case, merge_1_invalid_case, + merge_2_case, merge_2_invalid_case, + merge_3_case, merge_3_invalid_case, + merge3_case, merge3_invalid_case, + min_case, + nth_case, nth_outofrange_case, + nthtail_case, nthtail_outofrange_case, + partition_case, + prefix_case, + reverse_1_case, + reverse_2_case, + search_case, search_absent_case, + seq2_case, + seq3_case, + sort_1_case, + sort_2_case, + split_case, split_outofrange_case, + splitwith_case, + sublist_2_case, + sublist_3_case, + subtract_case, + suffix_case, + sum_case, + takewhile_case, + ukeymerge_case, ukeymerge_invalid_case, + ukeysort_case, + umerge_1_case, umerge_1_invalid_case, + umerge_2_case, umerge_2_invalid_case, + umerge_3_case, umerge_3_invalid_case, + umerge3_case, umerge3_invalid_case, + uniq_1_case, + uniq_2_case, + unzip_case, + unzip3_case, + usort_1_case, + usort_2_case, + zip_2_case, + zip_3_case, + zip3_3_case, + zip3_4_case, + zipwith_3_case, + zipwith_4_case, + zipwith3_4_case, + zipwith3_5_case + ]. + +init_per_suite(Config) -> + ct_property_test:init_per_suite(Config). + +end_per_suite(Config) -> + persistent_term:erase({lists_prop, random_atoms}), + Config. + +do_proptest(Prop, Config) -> + ct_property_test:quickcheck(lists_prop:Prop(), Config). + +all_true_case(Config) -> + do_proptest(prop_all_true, Config). + +all_false_case(Config) -> + do_proptest(prop_all_false, Config). + +any_true_case(Config) -> + do_proptest(prop_any_true, Config). + +any_false_case(Config) -> + do_proptest(prop_any_false, Config). + +append_1_case(Config) -> + do_proptest(prop_append_1, Config). + +append_2_case(Config) -> + do_proptest(prop_append_2, Config). + +concat_case(Config) -> + do_proptest(prop_concat, Config). + +delete_case(Config) -> + do_proptest(prop_delete, Config). + +delete_absent_case(Config) -> + do_proptest(prop_delete_absent, Config). + +droplast_case(Config) -> + do_proptest(prop_droplast, Config). + +dropwhile_case(Config) -> + do_proptest(prop_dropwhile, Config). + +duplicate_case(Config) -> + do_proptest(prop_duplicate, Config). + +enumerate_1_case(Config) -> + do_proptest(prop_enumerate_1, Config). + +enumerate_2_case(Config) -> + do_proptest(prop_enumerate_2, Config). + +enumerate_3_case(Config) -> + do_proptest(prop_enumerate_3, Config). + +filter_case(Config) -> + do_proptest(prop_filter, Config). + +filtermap_case(Config) -> + do_proptest(prop_filtermap, Config). + +flatlength_case(Config) -> + do_proptest(prop_flatlength, Config). + +flatmap_case(Config) -> + do_proptest(prop_flatmap, Config). + +flatten_1_case(Config) -> + do_proptest(prop_flatten_1, Config). + +flatten_2_case(Config) -> + do_proptest(prop_flatten_2, Config). + +foldl_case(Config) -> + do_proptest(prop_foldl, Config). + +foldr_case(Config) -> + do_proptest(prop_foldr, Config). + +foreach_case(Config) -> + do_proptest(prop_foreach, Config). + +join_case(Config) -> + do_proptest(prop_join, Config). + +keydelete_case(Config) -> + do_proptest(prop_keydelete, Config). + +keydelete_absent_case(Config) -> + do_proptest(prop_keydelete_absent, Config). + +keyfind_case(Config) -> + do_proptest(prop_keyfind, Config). + +keyfind_absent_case(Config) -> + do_proptest(prop_keyfind_absent, Config). + +keymap_case(Config) -> + do_proptest(prop_keymap, Config). + +keymember_case(Config) -> + do_proptest(prop_keymember, Config). + +keymember_absent_case(Config) -> + do_proptest(prop_keymember_absent, Config). + +keymerge_case(Config) -> + do_proptest(prop_keymerge, Config). + +keymerge_invalid_case(Config) -> + do_proptest(prop_keymerge_invalid, Config). + +keyreplace_case(Config) -> + do_proptest(prop_keyreplace, Config). + +keyreplace_absent_case(Config) -> + do_proptest(prop_keyreplace_absent, Config). + +keysearch_case(Config) -> + do_proptest(prop_keysearch, Config). + +keysearch_absent_case(Config) -> + do_proptest(prop_keysearch_absent, Config). + +keysort_case(Config) -> + do_proptest(prop_keysort, Config). + +keystore_case(Config) -> + do_proptest(prop_keystore, Config). + +keystore_absent_case(Config) -> + do_proptest(prop_keystore_absent, Config). + +keytake_case(Config) -> + do_proptest(prop_keytake, Config). + +keytake_absent_case(Config) -> + do_proptest(prop_keytake_absent, Config). + +last_case(Config) -> + do_proptest(prop_last, Config). + +map_case(Config) -> + do_proptest(prop_map, Config). + +mapfoldl_case(Config) -> + do_proptest(prop_mapfoldl, Config). + +mapfoldr_case(Config) -> + do_proptest(prop_mapfoldr, Config). + +max_case(Config) -> + do_proptest(prop_max, Config). + +member_case(Config) -> + do_proptest(prop_member, Config). + +member_absent_case(Config) -> + do_proptest(prop_member_absent, Config). + +merge_1_case(Config) -> + do_proptest(prop_merge_1, Config). + +merge_1_invalid_case(Config) -> + do_proptest(prop_merge_1_invalid, Config). + +merge_2_case(Config) -> + do_proptest(prop_merge_2, Config). + +merge_2_invalid_case(Config) -> + do_proptest(prop_merge_2_invalid, Config). + +merge_3_case(Config) -> + do_proptest(prop_merge_3, Config). + +merge_3_invalid_case(Config) -> + do_proptest(prop_merge_3_invalid, Config). + +merge3_case(Config) -> + do_proptest(prop_merge3, Config). + +merge3_invalid_case(Config) -> + do_proptest(prop_merge3_invalid, Config). + +min_case(Config) -> + do_proptest(prop_min, Config). + +nth_case(Config) -> + do_proptest(prop_nth, Config). + +nth_outofrange_case(Config) -> + do_proptest(prop_nth_outofrange, Config). + +nthtail_case(Config) -> + do_proptest(prop_nthtail, Config). + +nthtail_outofrange_case(Config) -> + do_proptest(prop_nthtail_outofrange, Config). + +partition_case(Config) -> + do_proptest(prop_partition, Config). + +prefix_case(Config) -> + do_proptest(prop_prefix, Config). + +reverse_1_case(Config) -> + do_proptest(prop_reverse_1, Config). + +reverse_2_case(Config) -> + do_proptest(prop_reverse_2, Config). + +search_case(Config) -> + do_proptest(prop_search, Config). + +search_absent_case(Config) -> + do_proptest(prop_search_absent, Config). + +seq2_case(Config) -> + do_proptest(prop_seq2, Config). + +seq3_case(Config) -> + do_proptest(prop_seq3, Config). + +sort_1_case(Config) -> + do_proptest(prop_sort_1, Config). + +sort_2_case(Config) -> + do_proptest(prop_sort_2, Config). + +split_case(Config) -> + do_proptest(prop_split, Config). + +split_outofrange_case(Config) -> + do_proptest(prop_split_outofrange, Config). + +splitwith_case(Config) -> + do_proptest(prop_splitwith, Config). + +sublist_2_case(Config) -> + do_proptest(prop_sublist_2, Config). + +sublist_3_case(Config) -> + do_proptest(prop_sublist_3, Config). + +subtract_case(Config) -> + do_proptest(prop_subtract, Config). + +suffix_case(Config) -> + do_proptest(prop_suffix, Config). + +sum_case(Config) -> + do_proptest(prop_sum, Config). + +takewhile_case(Config) -> + do_proptest(prop_takewhile, Config). + +ukeymerge_case(Config) -> + do_proptest(prop_ukeymerge, Config). + +ukeymerge_invalid_case(Config) -> + do_proptest(prop_ukeymerge_invalid, Config). + +ukeysort_case(Config) -> + do_proptest(prop_ukeysort, Config). + +umerge_1_case(Config) -> + do_proptest(prop_umerge_1, Config). + +umerge_1_invalid_case(Config) -> + do_proptest(prop_umerge_1_invalid, Config). + +umerge_2_case(Config) -> + do_proptest(prop_umerge_2, Config). + +umerge_2_invalid_case(Config) -> + do_proptest(prop_umerge_2_invalid, Config). + +umerge_3_case(Config) -> + do_proptest(prop_umerge_3, Config). + +umerge_3_invalid_case(Config) -> + do_proptest(prop_umerge_3_invalid, Config). + +umerge3_case(Config) -> + do_proptest(prop_umerge3, Config). + +umerge3_invalid_case(Config) -> + do_proptest(prop_umerge3_invalid, Config). + +uniq_1_case(Config) -> + do_proptest(prop_uniq_1, Config). + +uniq_2_case(Config) -> + do_proptest(prop_uniq_2, Config). + +unzip_case(Config) -> + do_proptest(prop_unzip, Config). + +unzip3_case(Config) -> + do_proptest(prop_unzip3, Config). + +usort_1_case(Config) -> + do_proptest(prop_usort_1, Config). + +usort_2_case(Config) -> + do_proptest(prop_usort_2, Config). + +zip_2_case(Config) -> + do_proptest(prop_zip_2, Config). + +zip_3_case(Config) -> + do_proptest(prop_zip_3, Config). + +zip3_3_case(Config) -> + do_proptest(prop_zip3_3, Config). + +zip3_4_case(Config) -> + do_proptest(prop_zip3_4, Config). + +zipwith_3_case(Config) -> + do_proptest(prop_zipwith_3, Config). + +zipwith_4_case(Config) -> + do_proptest(prop_zipwith_4, Config). + +zipwith3_4_case(Config) -> + do_proptest(prop_zipwith3_4, Config). + +zipwith3_5_case(Config) -> + do_proptest(prop_zipwith3_5, Config). + diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl index 28895c4efe93..0f203988038d 100644 --- a/lib/stdlib/test/maps_SUITE.erl +++ b/lib/stdlib/test/maps_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2021. All Rights Reserved. +%% Copyright Ericsson AB 1997-2023. 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. @@ -30,7 +30,9 @@ -export([t_update_with_3/1, t_update_with_4/1, t_get_3/1, t_filter_2/1, t_filtermap_2/1, t_fold_3/1,t_map_2/1,t_size_1/1, t_foreach_2/1, - t_iterator_1/1, t_put_opt/1, t_merge_opt/1, + t_iterator_1/1, t_iterator_2/1, + t_iterator_valid/1, + t_put_opt/1, t_merge_opt/1, t_with_2/1,t_without_2/1, t_intersect/1, t_intersect_with/1, t_merge_with/1, t_from_keys/1, @@ -42,7 +44,8 @@ t_from_list_check_trapping/1, t_from_keys_check_trapping/1, t_keys_trapping/1, - t_values_trapping/1]). + t_values_trapping/1, + t_groups_from_list/1]). -define(badmap(V,F,Args), {'EXIT', {{badmap,V}, [{maps,F,Args,_}|_]}}). -define(badkey(K,F,Args), {'EXIT', {{badkey,K}, [{maps,F,Args,_}|_]}}). @@ -56,7 +59,9 @@ all() -> [t_update_with_3,t_update_with_4, t_get_3,t_filter_2,t_filtermap_2, t_fold_3,t_map_2,t_size_1,t_foreach_2, - t_iterator_1,t_put_opt,t_merge_opt, + t_iterator_1,t_iterator_2, + t_iterator_valid, + t_put_opt,t_merge_opt, t_with_2,t_without_2, t_intersect, t_intersect_with, t_merge_with, t_from_keys, @@ -68,7 +73,8 @@ all() -> t_from_list_check_trapping, t_from_keys_check_trapping, t_keys_trapping, - t_values_trapping]. + t_values_trapping, + t_groups_from_list]. t_from_list_kill_process(Config) when is_list(Config) -> Killer = self(), @@ -352,7 +358,8 @@ t_get_3(Config) when is_list(Config) -> DefaultValue = maps:get(key3, Map, DefaultValue), %% error case - ?badmap(a,get,[[a,b],a,def]) = (catch maps:get([a,b],id(a),def)), + {'EXIT', {{badmap,a}, _}} = (catch maps:get([a,b],id(a),def)), + ok. t_without_2(_Config) -> @@ -392,7 +399,8 @@ t_filter_2(Config) when is_list(Config) -> #{a := 2,c := 4} = maps:filter(Pred1,maps:iterator(M)), #{"b" := 2,"c" := 4} = maps:filter(Pred2,maps:iterator(M)), %% error case - ?badmap(a,filter,[_,a]) = (catch maps:filter(fun(_,_) -> ok end,id(a))), + ?badmap(a,filter,[_,a]) = (catch maps:filter(fun(_,_) -> true end,id(a))), + ?badmap({a,b,c},filter,[_,{a,b,c}]) = (catch maps:filter(fun(_,_) -> true end,id({a,b,c}))), ?badarg(filter,[<<>>,#{}]) = (catch maps:filter(id(<<>>),#{})), ok. @@ -406,7 +414,8 @@ t_filtermap_2(Config) when is_list(Config) -> false = maps:is_key(20, M1), true = M1 =:= M2, %% error case - ?badmap(a,filtermap,[_,a]) = (catch maps:filtermap(fun(_,_) -> ok end,id(a))), + ?badmap(a,filtermap,[_,a]) = (catch maps:filtermap(fun(_,_) -> true end,id(a))), + ?badmap({a,b,c},filtermap,[_,{a,b,c}]) = (catch maps:filtermap(fun(_,_) -> true end,id({a,b,c}))), ?badarg(filtermap,[<<>>,#{}]) = (catch maps:filtermap(id(<<>>),#{})), ok. @@ -422,6 +431,7 @@ t_fold_3(Config) when is_list(Config) -> %% error case ?badmap(a,fold,[_,0,a]) = (catch maps:fold(fun(_,_,_) -> ok end,0,id(a))), + ?badmap({a,b,c},fold,[_,0,{a,b,c}]) = (catch maps:fold(fun(_,_,_) -> ok end,0,id({a,b,c}))), ?badarg(fold,[<<>>,0,#{}]) = (catch maps:fold(id(<<>>),0,#{})), ok. @@ -436,6 +446,7 @@ t_map_2(Config) when is_list(Config) -> %% error case ?badmap(a,map,[_,a]) = (catch maps:map(fun(_,_) -> ok end, id(a))), + ?badmap({a,b,c},map,[_,{a,b,c}]) = (catch maps:map(fun(_,_) -> ok end, id({a,b,c}))), ?badarg(map,[<<>>,#{}]) = (catch maps:map(id(<<>>),#{})), ok. @@ -446,6 +457,7 @@ t_foreach_2(Config) when is_list(Config) -> ?badmap({},foreach,[_,{}]) = (catch maps:foreach(fun(_,_) -> ok end, id({}))), ?badmap(42,foreach,[_,42]) = (catch maps:foreach(fun(_,_) -> ok end, id(42))), ?badmap(<<>>,foreach,[_,<<>>]) = (catch maps:foreach(fun(_,_) -> ok end, id(<<>>))), + ?badmap({a,b,c},foreach,[_,{a,b,c}]) = (catch maps:foreach(fun(_,_) -> ok end, id({a,b,c}))), ?badarg(foreach,[<<>>,#{}]) = (catch maps:foreach(id(<<>>),#{})), F0 = fun() -> ok end, @@ -469,12 +481,15 @@ t_iterator_1(Config) when is_list(Config) -> KVList = lists:sort([{K1,V1},{K2,V2}]), KVList = lists:sort(maps:to_list(M0)), + KList = lists:sort([K1,K2]), + KList = lists:sort(maps:keys(M0)), %% Large map test Vs2 = lists:seq(1,200), M2 = maps:from_list([{{k,I},I}||I<-Vs2]), KVList2 = lists:sort(iter_kv(maps:iterator(M2))), + KVList2 = lists:sort(maps:to_list(maps:iterator(M2))), KVList2 = lists:sort(maps:to_list(M2)), %% Larger map test @@ -482,9 +497,101 @@ t_iterator_1(Config) when is_list(Config) -> Vs3 = lists:seq(1,10000), M3 = maps:from_list([{{k,I},I}||I<-Vs3]), KVList3 = lists:sort(iter_kv(maps:iterator(M3))), + KVList3 = lists:sort(maps:to_list(maps:iterator(M3))), KVList3 = lists:sort(maps:to_list(M3)), ok. +t_iterator_2(Config) when is_list(Config) -> + + AOrdCmpFun = fun(A, B) -> A =< B end, + ARevCmpFun = fun(A, B) -> B =< A end, + + %% Small map test + M0 = #{ a => 1, b => 2 }, + TOrdI0 = maps:iterator(M0, ordered), + {K1 = a, V1 = 1, TOrdI1} = maps:next(TOrdI0), + {K2 = b, V2 = 2, TOrdI2} = maps:next(TOrdI1), + none = maps:next(TOrdI2), + + TRevI0 = maps:iterator(M0, reversed), + {K2 = b, V2 = 2, TRevI1} = maps:next(TRevI0), + {K1 = a, V1 = 1, TRevI2} = maps:next(TRevI1), + none = maps:next(TRevI2), + + AOrdI0 = maps:iterator(M0, AOrdCmpFun), + {K1 = a, V1 = 1, AOrdI1} = maps:next(AOrdI0), + {K2 = b, V2 = 2, AOrdI2} = maps:next(AOrdI1), + none = maps:next(AOrdI2), + + ARevI0 = maps:iterator(M0, ARevCmpFun), + {K2 = b, V2 = 2, ARevI1} = maps:next(ARevI0), + {K1 = a, V1 = 1, ARevI2} = maps:next(ARevI1), + none = maps:next(ARevI2), + + OrdKVList = [{K1, V1}, {K2, V2}], + OrdKVList = maps:to_list(TOrdI0), + OrdKVList = maps:to_list(AOrdI0), + + RevKVList = [{K2, V2}, {K1, V1}], + RevKVList = maps:to_list(TRevI0), + RevKVList = maps:to_list(ARevI0), + + %% Large map test + + Vs2 = lists:seq(1, 200), + OrdKVList2 = [{{k, I}, I} || I <- Vs2], + M2 = maps:from_list(OrdKVList2), + ok = iterator_2_check_order(M2, ordered, reversed), + ok = iterator_2_check_order(M2, AOrdCmpFun, ARevCmpFun), + + %% Larger map test + + Vs3 = lists:seq(1, 10000), + OrdKVList3 = [{{k, I}, I} || I <- Vs3], + M3 = maps:from_list(OrdKVList3), + ok = iterator_2_check_order(M3, ordered, reversed), + ok = iterator_2_check_order(M3, AOrdCmpFun, ARevCmpFun), + + %% Float and integer keys + + M4 = #{-1.0 => a, 0.0 => b, -1 => c, 0 => d}, + OrdIter4 = maps:iterator(M4, ordered), + [{-1, c}, {0, d}, {-1.0, a}, {0.0, b}] = maps:to_list(OrdIter4), + ok = iterator_2_check_order(M4, ordered, reversed), + + ok. + +iterator_2_option_to_fun(ordered) -> + fun(A, B) -> erts_internal:cmp_term(A, B) =< 0 end; +iterator_2_option_to_fun(reversed) -> + fun(A, B) -> erts_internal:cmp_term(B, A) =< 0 end; +iterator_2_option_to_fun(F) when is_function(F, 2) -> + F. + +iterator_2_check_order(M, OrdOption, RevOption) -> + OrdCmpFun = iterator_2_option_to_fun(OrdOption), + RevCmpFun = iterator_2_option_to_fun(RevOption), + OrdKVCmpFun = fun({A, _}, {B, _}) -> OrdCmpFun(A, B) end, + RevKVCmpFun = fun({A, _}, {B, _}) -> RevCmpFun(A, B) end, + + OrdKVList = lists:sort(OrdKVCmpFun, maps:to_list(M)), + RevKVList = lists:sort(RevKVCmpFun, maps:to_list(M)), + RevKVList = lists:reverse(OrdKVList), + + Iter = maps:iterator(M, undefined), + OrdIter = maps:iterator(M, OrdOption), + RevIter = maps:iterator(M, RevOption), + + OrdKVList = lists:sort(OrdKVCmpFun, iter_kv(Iter)), + OrdKVList = lists:sort(OrdKVCmpFun, maps:to_list(Iter)), + OrdKVList = iter_kv(OrdIter), + OrdKVList = maps:to_list(OrdIter), + + RevKVList = iter_kv(RevIter), + RevKVList = maps:to_list(RevIter), + + ok. + iter_kv(I) -> case maps:next(I) of none -> @@ -493,6 +600,59 @@ iter_kv(I) -> [{K,V} | iter_kv(NI)] end. +t_iterator_valid(Config) when is_list(Config) -> + %% good iterators created via maps:iterator + true = maps:is_iterator_valid(maps:iterator(#{})), + true = maps:is_iterator_valid(maps:iterator(#{a => b})), + true = maps:is_iterator_valid(maps:iterator(#{a => b, c => d})), + true = maps:is_iterator_valid(maps:iterator(#{}, undefined)), + true = maps:is_iterator_valid(maps:iterator(#{a => b}, undefined)), + true = maps:is_iterator_valid(maps:iterator(#{a => b, c => d}, undefined)), + true = maps:is_iterator_valid(maps:iterator(#{}, ordered)), + true = maps:is_iterator_valid(maps:iterator(#{a => b}, ordered)), + true = maps:is_iterator_valid(maps:iterator(#{a => b, c => d}, ordered)), + true = maps:is_iterator_valid(maps:iterator(#{}, reversed)), + true = maps:is_iterator_valid(maps:iterator(#{a => b}, reversed)), + true = maps:is_iterator_valid(maps:iterator(#{a => b, c => d}, reversed)), + true = maps:is_iterator_valid(maps:iterator(#{}, fun erlang:'=<'/2)), + true = maps:is_iterator_valid(maps:iterator(#{a => b}, fun erlang:'=<'/2)), + true = maps:is_iterator_valid(maps:iterator(#{a => b, c => d}, fun erlang:'=<'/2)), + + %% good makeshift iterators + true = maps:is_iterator_valid(none), + true = maps:is_iterator_valid({a, b, none}), + true = maps:is_iterator_valid({a, b, {c, d, none}}), + true = maps:is_iterator_valid({a, b, {c, d, {e, f, none}}}), + true = maps:is_iterator_valid({a, b, maps:iterator(#{})}), + true = maps:is_iterator_valid({a, b, maps:iterator(#{c => d})}), + + %% not iterators + false = maps:is_iterator_valid(no_iter), + false = maps:is_iterator_valid(1), + false = maps:is_iterator_valid(1.0), + false = maps:is_iterator_valid([]), + false = maps:is_iterator_valid("foo"), + false = maps:is_iterator_valid(<<"foo">>), + false = maps:is_iterator_valid(fun() -> ok end), + false = maps:is_iterator_valid(self()), + false = maps:is_iterator_valid(make_ref()), + false = maps:is_iterator_valid(#{}), + false = maps:is_iterator_valid({}), + false = maps:is_iterator_valid({a}), + false = maps:is_iterator_valid({a, b}), + false = maps:is_iterator_valid({a, b, c, d}), + + %% bad makeshift iterators that only fail on later (ie, subsequent) calls to maps:next/1 + %% maps:next({a, b, c}) -> {a, b, c} + %% maps:next(c) -> badarg + false = maps:is_iterator_valid({a, b, c}), + %% maps:next({a, b, {c, d, e}}) -> {a, b, {c, d, e}} + %% maps:next({c, d, e}) -> {c, d, e} + %% maps:next(e) -> badarg + false = maps:is_iterator_valid({a, b, {c, d, e}}), + + ok. + t_put_opt(Config) when is_list(Config) -> Value = id(#{complex => map}), Small = id(#{a => Value}), @@ -770,17 +930,34 @@ t_size_1(Config) when is_list(Config) -> {'EXIT', {{badmap,<<>>}, _}} = (catch maps:size(id(<<>>))), ok. +t_groups_from_list(_Config) -> + #{} = maps:groups_from_list(fun erlang:length/1, []), + #{3 := ["tna","tac"], 5 := ["ognid"], 7 := ["olaffub"]} = + maps:groups_from_list( + fun erlang:length/1, + fun lists:reverse/1, + ["ant", "buffalo", "cat", "dingo"] + ), + #{0 := [2], 1 := [1, 3]} = maps:groups_from_list(fun(X) -> X rem 2 end, [1, 2, 3]). + error_info(_Config) -> BadIterator = [-1|#{}], + BadIterator2 = {x, y, z}, GoodIterator = maps:iterator(#{}), + BadOrder = fun(_) -> true end, + GoodOrder = fun(A, B) -> A =< B end, - L = [{filter, [fun(_, _) -> true end, abc]}, + L = [ + {filter, [fun(_, _) -> true end, abc]}, {filter, [fun(_, _) -> true end, BadIterator]}, + {filter, [fun(_, _) -> true end, BadIterator2]}, {filter, [bad_fun, BadIterator],[{1,".*"},{2,".*"}]}, + {filter, [bad_fun, BadIterator2],[{1,".*"},{2,".*"}]}, {filter, [bad_fun, GoodIterator]}, {filtermap, [fun(_, _) -> true end, abc]}, {filtermap, [fun(_, _) -> true end, BadIterator]}, + {filtermap, [fun(_, _) -> true end, BadIterator2]}, {filtermap, [fun(_) -> true end, GoodIterator]}, {filtermap, [fun(_) -> ok end, #{}]}, @@ -788,11 +965,13 @@ error_info(_Config) -> {fold, [fun(_, _, _) -> true end, init, abc]}, {fold, [fun(_, _, _) -> true end, init, BadIterator]}, + {fold, [fun(_, _, _) -> true end, init, BadIterator2]}, {fold, [fun(_) -> true end, init, GoodIterator]}, {fold, [fun(_) -> ok end, init, #{}]}, {foreach, [fun(_, _) -> ok end, no_map]}, {foreach, [fun(_, _) -> ok end, BadIterator]}, + {foreach, [fun(_, _) -> ok end, BadIterator2]}, {foreach, [fun(_) -> ok end, GoodIterator]}, {foreach, [fun(_) -> ok end, #{}]}, @@ -806,6 +985,13 @@ error_info(_Config) -> {get, [key, {no,map}]}, {get, [key, {no,map}, default]}, + {groups_from_list, [not_a_fun, []]}, + {groups_from_list, [fun hd/1, not_a_list]}, + + {groups_from_list, [not_a_fun, fun(_) -> ok end, []]}, + {groups_from_list, [fun(_) -> ok end, not_a_fun, []]}, + {groups_from_list, [fun(_) -> ok end, fun(_) -> ok end, not_a_list]}, + {intersect, [#{a => b}, y]}, {intersect, [x, #{a => b}]}, {intersect, [x, y],[{1,".*"},{2,".*"}]}, @@ -815,14 +1001,26 @@ error_info(_Config) -> {intersect_with, [fun(_, _, _) -> ok end, x, y],[{2,".*"},{3,".*"}]}, {intersect_with, [fun(_, _) -> ok end, #{}, #{}]}, + {is_iterator_valid, [GoodIterator], [no_fail]}, + {is_iterator_valid, [BadIterator], [no_fail]}, + {is_iterator_valid, [BadIterator2], [no_fail]}, + {is_key,[key, no_map]}, {iterator,[{no,map}]}, + {iterator, [{no,map}, undefined], [{1, ".*"}]}, + {iterator, [{no,map}, ordered], [{1, ".*"}]}, + {iterator, [{no,map}, reversed], [{1, ".*"}]}, + {iterator, [{no,map}, GoodOrder], [{1, ".*"}]}, + {iterator, [#{a => b}, BadOrder], [{2, ".*"}]}, + {iterator, [{no,map}, BadOrder], [{1, ".*"}, {2, ".*"}]}, + {keys, [{no,map}]}, {map, [fun(_, _) -> true end, abc]}, {map, [fun(_, _) -> true end, BadIterator]}, + {map, [fun(_, _) -> true end, BadIterator2]}, {map, [fun(_) -> true end, GoodIterator]}, {map, [fun(_) -> ok end, #{}]}, @@ -834,6 +1032,7 @@ error_info(_Config) -> {merge_with, [a, b, c],[{1,".*"},{2,".*"},{3,".*"}]}, {next,[no_iterator]}, + {next,[BadIterator]}, {put, [key, value, {no,map}]}, @@ -844,6 +1043,8 @@ error_info(_Config) -> {take, [key, no_map]}, {to_list,[xyz]}, + {to_list,[BadIterator]}, + {to_list,[BadIterator2]}, {update,[key, value, no_map]}, diff --git a/lib/stdlib/test/math_SUITE.erl b/lib/stdlib/test/math_SUITE.erl index 5804c5bb46f3..5e92debd6911 100644 --- a/lib/stdlib/test/math_SUITE.erl +++ b/lib/stdlib/test/math_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2021. All Rights Reserved. +%% Copyright Ericsson AB 2007-2023. 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. @@ -28,7 +28,7 @@ init_per_testcase/2, end_per_testcase/2]). %% Test cases --export([floor_ceil/1, error_info/1]). +-export([floor_ceil/1, error_info/1, constants/1]). suite() -> @@ -36,7 +36,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - [floor_ceil, error_info]. + [floor_ceil, error_info, constants]. groups() -> []. @@ -60,6 +60,11 @@ init_per_testcase(_Case, Config) -> end_per_testcase(_Case, _Config) -> ok. +constants(_Config) -> + 3.1415926535897932 = math:pi(), + 6.2831853071795864 = math:tau(), + ok. + floor_ceil(_Config) -> MinusZero = 0.0/(-1.0), -43.0 = do_floor_ceil(-42.1), diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index a28de1937244..5e8e6076ae21 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2021. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -30,12 +30,19 @@ -export([from_shell/1]). -export([records/1]). -export([record_index/1]). --export([multipass/1]). +-export([map_pattern/1]). +-export([map_expr_in_head/1]). +-export([map_pattern_from_shell/1]). +-export([map_expr_in_head_from_shell/1]). +-export([map_exprs/1]). +-export([map_exprs_from_shell/1]). -export([top_match/1]). +-export([multipass/1]). -export([old_guards/1]). -export([autoimported/1]). -export([semicolon/1]). -export([bitsyntax/1]). +-export([binary_bifs/1]). -export([record_defaults/1]). -export([andalso_orelse/1]). -export([float_1_function/1]). @@ -59,10 +66,13 @@ suite() -> all() -> [from_shell, basic_ets, basic_dbg, records, - record_index, multipass, bitsyntax, record_defaults, + record_index, multipass, bitsyntax, binary_bifs, record_defaults, andalso_orelse, float_1_function, action_function, warnings, no_warnings, top_match, old_guards, autoimported, - semicolon, eep37, otp_14454, otp_16824, unused_record]. + semicolon, eep37, otp_14454, otp_16824, unused_record, + map_pattern, map_expr_in_head, + map_pattern_from_shell, map_expr_in_head_from_shell, + map_exprs, map_exprs_from_shell]. groups() -> []. @@ -257,6 +267,32 @@ bitsyntax(Config) when is_list(Config) -> " end)">>), ok. + +%% Test that binary BIFs byte_size/1, binary_part/2, binary_part/3 are accepted +binary_bifs(Config) when is_list(Config) -> + setup(Config), + TestSet = [{<<"hello">>, <<"world">>}, {<<"souldn't">>, <<"match">>}], + RunMS = fun(MS) -> ets:match_spec_run(TestSet, ets:match_spec_compile(MS)) end, + % check byte_size/1 + MS1 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when byte_size(A) == 5 -> {A, byte_size(B)} end)">>), + [{{'$1','$2'}, + [{'==',{byte_size,'$1'},5}], + [{{'$1',{byte_size,'$2'}}}]}] = MS1, + [{<<"hello">>, 5}] = RunMS(MS1), + % check binary_part/2 + MS2 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when binary_part(A, {1, 2}) == <<\"el\">> -> binary_part(B, {2, 3}) end)">>), + [{{'$1','$2'}, + [{'==',{binary_part,'$1',{{1,2}}},<<"el">>}], + [{binary_part,'$2',{{2,3}}}]}] = MS2, + [<<"rld">>] = RunMS(MS2), + % check binary_part/3 + MS3 = compile_and_run(<<"ets:fun2ms(fun({A, B}) when binary_part(A, 1, 2) == <<\"el\">> -> binary_part(B, 2, 3) end)">>), + [{{'$1','$2'}, + [{'==',{binary_part,'$1',1,2},<<"el">>}], + [{binary_part,'$2',2,3}]}] = MS3, + [<<"rld">>] = RunMS(MS3), + ok. + %% Test that record defaults works. record_defaults(Config) when is_list(Config) -> setup(Config), @@ -289,7 +325,7 @@ basic_ets(Config) when is_list(Config) -> compile_and_run(<<"ets:fun2ms(fun({\"foo\" ++ _, X}) -> X end)">>), ok. -%% Tests basic ets:fun2ms. +%% Tests basic dbg:fun2ms. basic_dbg(Config) when is_list(Config) -> setup(Config), [{[a,b],[],[{message,banan},{return_trace}]}] = @@ -382,6 +418,59 @@ record_index(Config) when is_list(Config) -> <<"ets:fun2ms(fun({#a.a,A}) when A > #a.a -> #a.a end)">>), ok. +map_pattern(Config) when is_list(Config) -> + setup(Config), + MS = [{{key, #{foo => '$1'}},[],['$1']}], + MS = compile_and_run(<<"ets:fun2ms(fun({key, #{foo := V}}) -> V end)">>), + ok. + +map_expr_in_head(Config) when is_list(Config) -> + setup(Config), + MS = [{{key, #{foo => '$1'}},[],['$1']}], + %% Accidentally it is possible to use => instead of := in the fun head, + %% in compiled code. + %% Although this is not an intended behaviour it is kept to + %% maintain backwards compatibility. + MS = compile_and_run(<<"ets:fun2ms(fun({key, #{foo => V}}) -> V end)">>), + ok. + +map_pattern_from_shell(Config) when is_list(Config) -> + MS = [{{key, #{foo => '$1'}},[],['$1']}], + MS = do_eval("ets:fun2ms(fun({key, #{foo := V}}) -> V end)"), + ok. + +map_expr_in_head_from_shell(Config) when is_list(Config) -> + setup(Config), + MS = [{{key, #{foo => '$1'}},[],['$1']}], + %% Accidentally it is possible to use => instead of := in the fun head, + %% in compiled code. This behaviour is kept for backwards compatibility. + + %% As a side-effect, it is also possible to do the same with + %% `transform_from_shell/3', if the AST of the shell fun is + %% created bypassing the linter. (The linter would prevent + %% constructing such invalid syntax, so normally this is not + %% possible in the Erlang shell) + MS = do_eval("ets:fun2ms(fun({key, #{foo => V}}) -> V end)"), + ok. + +map_exprs(Config) when is_list(Config) -> + setup(Config), + MSGuard = [{{key,'$1','$2'}, [{'=:=','$1',#{foo => '$2'}}], ['$1']}], + MSGuard = compile_and_run( + <<"ets:fun2ms(fun({key, V1, V2}) when V1 =:= #{foo => V2} -> V1 end)">>), + MSBody = [{{key,'$1'}, [], [#{foo => '$1'}]}], + MSBody = compile_and_run( + <<"ets:fun2ms(fun({key, V}) -> #{foo => V} end)">>), + ok. + +map_exprs_from_shell(Config) when is_list(Config) -> + setup(Config), + MSGuard = [{{key,'$1','$2'}, [{'=:=','$1',#{foo => '$2'}}], ['$1']}], + MSGuard = do_eval("ets:fun2ms(fun({key, V1, V2}) when V1 =:= #{foo => V2} -> V1 end)"), + MSBody = [{{key,'$1'}, [], [#{foo => '$1'}]}], + MSBody = do_eval("ets:fun2ms(fun({key, V}) -> #{foo => V} end)"), + ok. + %% Tests matching on top level in head to give alias for object(). top_match(Config) when is_list(Config) -> setup(Config), @@ -493,6 +582,8 @@ autoimported(Config) when is_list(Config) -> {element,2}, {hd,1}, {length,1}, + {max,2}, + {min,2}, {node,0}, {node,1}, {round,1}, @@ -768,6 +859,16 @@ action_function(Config) when is_list(Config) -> "silent(true), " "trace([send], [procs]), " "trace(Y, [procs], [send]) end)">>), + [{['$1','$2'], + [], + [{caller_line}, + {current_stacktrace}, + {current_stacktrace,3}]}] = + compile_and_run + (<<"dbg:fun2ms(fun([X,Y]) -> " + "caller_line()," + "current_stacktrace()," + "current_stacktrace(3) end)">>), ok. @@ -897,5 +998,5 @@ do_eval(String) -> [], String++".\n",1), {ok,Tree} = erl_parse:parse_exprs(T), - {value,Res,[]} = erl_eval:exprs(Tree,[]), + {value,Res,[]} = erl_eval:exprs(Tree,[],none,none), Res. diff --git a/lib/stdlib/test/peer_SUITE.erl b/lib/stdlib/test/peer_SUITE.erl new file mode 100644 index 000000000000..9b48f4f28edd --- /dev/null +++ b/lib/stdlib/test/peer_SUITE.erl @@ -0,0 +1,742 @@ +%%% @doc +%%% Smoke tests for peer node controller +%%% @end +-module(peer_SUITE). +-author("maximfca@gmail.com"). + +%% Common Test headers +-include_lib("stdlib/include/assert.hrl"). +-include_lib("common_test/include/ct.hrl"). + +%% Test server callbacks +-export([ + suite/0, + all/0, + groups/0, + init_per_suite/1, + end_per_suite/1, + init_per_group/2, + end_per_group/2 +]). + +%% Test cases +-export([ + dist/0, dist/1, + peer_down_crash/0, peer_down_crash/1, + peer_down_crash_tcp/1, + peer_down_continue/0, peer_down_continue/1, + peer_down_boot/0, peer_down_boot/1, + dist_io_redirect/0, dist_io_redirect/1, + dist_localhost/0, dist_localhost/1, + errors/0, errors/1, + basic/0, basic/1, + peer_states/0, peer_states/1, + cast/0, cast/1, + detached/0, detached/1, + dyn_peer/0, dyn_peer/1, + stop_peer/0, stop_peer/1, + shutdown_halt/0, shutdown_halt/1, + shutdown_halt_timeout/0, shutdown_halt_timeout/1, + shutdown_stop/0, shutdown_stop/1, + shutdown_stop_timeout/0, shutdown_stop_timeout/1, + shutdown_close/0, shutdown_close/1, + init_debug/0, init_debug/1, + io_redirect/0, io_redirect/1, + multi_node/0, multi_node/1, + dist_up_down/0, dist_up_down/1, + duplicate_name/0, duplicate_name/1, + old_release/0, old_release/1, + ssh/0, ssh/1, + docker/0, docker/1, + post_process_args/0, post_process_args/1, + attached/0, attached/1, + attached_cntrl_channel_handler_crash/0, attached_cntrl_channel_handler_crash/1, + cntrl_channel_handler_crash/0, cntrl_channel_handler_crash/1, + cntrl_channel_handler_crash_old_release/0, cntrl_channel_handler_crash_old_release/1 +]). + +suite() -> + [{timetrap, {minutes, 1}}]. + +init_per_suite(Config) -> + %% Restrict number of schedulers so that we do not run out of + %% file descriptors during test + os:putenv("ERL_FLAGS","+S1 +SDio 1"), + Config. + +end_per_suite(_Config) -> + os:unsetenv("ERL_FLAGS"), + ok. + +shutdown_alternatives() -> + [shutdown_halt, shutdown_halt_timeout, shutdown_stop, shutdown_stop_timeout, shutdown_close]. + +alternative() -> + [basic, peer_states, cast, detached, dyn_peer, stop_peer, + io_redirect, multi_node, duplicate_name, attached, attached_cntrl_channel_handler_crash, + cntrl_channel_handler_crash, cntrl_channel_handler_crash_old_release | shutdown_alternatives()]. + +groups() -> + [ + {dist, [parallel], [errors, dist, peer_down_crash, peer_down_continue, peer_down_boot, + dist_up_down, dist_localhost, post_process_args, attached, + attached_cntrl_channel_handler_crash, cntrl_channel_handler_crash, + cntrl_channel_handler_crash_old_release | shutdown_alternatives()]}, + {dist_seq, [], [dist_io_redirect, %% Cannot be run in parallel in dist group + peer_down_crash_tcp]}, + {tcp, [parallel], alternative()}, + {standard_io, [parallel], [init_debug | alternative()]}, + {compatibility, [parallel], [old_release]}, + {remote, [parallel], [ssh]} + ]. + +all() -> + [{group, dist}, {group, dist_seq}, {group, tcp}, {group, standard_io}, + {group, compatibility}, {group, remote}]. + +init_per_group(remote, Config) -> + %% check that SSH can connect to localhost, skip the test if not + try os:cmd("timeout 10s ssh localhost echo ok") of + "ok\n" -> Config; + _ -> {skip, "'ssh localhost echo ok' did not return ok"} + catch + Class:Reason -> + SkipReason = io_lib:format("'ssh localhost echo ok' failed with ~s:~p", [Class, Reason]), + {skip, SkipReason} + end; +init_per_group(dist, Config) -> + case erlang:is_alive() of + true -> Config; + false -> {skip, "origin is not distributed"} + end; +init_per_group(tcp, Config) -> + [{connection, 0} | Config]; +init_per_group(standard_io, Config) -> + [{connection, standard_io} | Config]; +init_per_group(_Group, Config) -> + Config. + +end_per_group(_TestCase, Config) -> + proplists:delete(connection, Config). + +%% ------------------------------------------------------------------- +%% Distribution-enabled cases + +errors() -> + [{doc, "Verify that invalid command line is rejected immediately"}]. + +errors(Config) when is_list(Config) -> + ?assertException(error, {invalid_arg, atom}, peer:start(#{args => atom})), + ?assertException(error, {invalid_arg, $s}, peer:start(#{args => "string"})), + ?assertException(error, {invalid_arg, ["2"]}, peer:start(#{args => ["1", ["2"]]})), + ?assertException(error, {exec, atom}, peer:start(#{exec => atom, name => name})), + ?assertException(error, {exec, atom}, peer:start(#{exec => {atom, []}, name => name})), + ?assertException(error, {exec, atom}, peer:start(#{exec => {"erl", [atom]}, name => name})), + ?assertException(error, not_alive, peer:start(#{})). %% peer node won't start - it's not alive + +dist() -> + [{doc, "Classic behaviour: detached peer with no alternative, connects via dist"}]. + +%% Classic 'slave': start new node locally, with random name, ask peer control process to exit normally +dist(Config) when is_list(Config) -> + {ok, Peer, Node} = peer:start_link(), + %% distribution is expected to be connected + ?assertEqual(Node, erpc:call(Node, erlang, node, [])), + %% but not alternative... + ?assertException(error, noconnection, peer:call(Peer, erlang, node, [])), + ?assertEqual(true, net_kernel:disconnect(Node)), + %% ^^^ this makes the node go down, but we also need to ensure that net_kernel + %% finished processing + ct:sleep(500), + _ = sys:get_state(net_kernel), + ?assertException(exit, {noproc, _}, peer:get_state(Peer)). + +peer_down_crash() -> + [{doc, "Tests peer_down handling when crash mode is requested"}]. + +peer_down_crash(Config) when is_list(Config) -> + %% two-way link: "crash" mode + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + args => ["-connect_all", "false"], peer_down => crash}), + %% verify node started locally + ?assertEqual(Node, erpc:call(Node, erlang, node, [])), + %% verify there is no alternative connection + ?assertException(error, noconnection, peer:call(Peer, erlang, node, [])), + %% unlink and monitor + unlink(Peer), + MRef = monitor(process, Peer), + ?assertEqual(true, net_kernel:disconnect(Node)), + %% ^^^ this makes the node go down + %% since two-way link is requested, it triggers peer to stop + receive + {'DOWN', MRef, process, Peer, {nodedown, Node}} -> + ok + after 2000 -> + link(Peer), + {fail, disconnect_timeout} + end. + +%% Verify option combo #{peer_down=>crash, connection=>0} +%% exits control process abnormally. +peer_down_crash_tcp(Config) when is_list(Config) -> + %% two-way link: "crash" mode + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + peer_down => crash, + connection => 0}), + %% verify node started locally + ?assertEqual(Node, peer:call(Peer, erlang, node, [])), + %% verify there is no distribution connection + ?assertEqual([], erlang:nodes(connected)), + %% unlink and monitor + unlink(Peer), + MRef = monitor(process, Peer), + %% Make the node go down + ok = erpc:cast(Node, erlang, halt, [0]), + + %% since two-way link is requested, it triggers peer to stop + receive + {'DOWN', MRef, process, Peer, tcp_closed} -> + ok + after 5000 -> + link(Peer), + {fail, disconnect_timeout} + end. + +peer_down_continue() -> + [{doc, "Tests peer_down handling for continue setting"}]. + +peer_down_continue(Config) when is_list(Config) -> + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + args => ["-connect_all", "false"], peer_down => continue}), + ?assertEqual(ok, erpc:cast(Node, erlang, halt, [])), + ct:sleep(500), + sys:replace_state(net_kernel, fun(S) -> sys:get_state(Peer), S end), + ?assertMatch({down, _}, peer:get_state(Peer)), + peer:stop(Peer). + +peer_down_boot() -> + [{doc, "Tests that peer node failing boot fails start_link correctly"}]. + +peer_down_boot(Config) when is_list(Config) -> + ?assertException(exit, {boot_failed, {exit_status, 1}}, + peer:start_link(#{connection => standard_io, name => peer:random_name(), args => ["-no_epmd"]})). + +dist_io_redirect() -> + [{doc, "Tests i/o redirection working for dist"}]. + +dist_io_redirect(Config) when is_list(Config) -> + %% Common Test changes group leader process to capture output. + %% 'peer' relays output via control process group leader. + ct:capture_start(), + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + args => ["-connect_all", "false", "-eval", "io:format(\"out\")."]}), + %% RPC is smart enough to set the group leader, so force 'user' output + %% to check that peer node redirects 'user' to the current process group + %% leader. + ?assertEqual(ok, erpc:call(Node, io, format, [user, "STRONGFLOUR.", []])), + %% verify that 'send' is ignored when no alternative connection is done + ?assertEqual(ok, peer:send(Peer, init, {stop, stop})), + %% check that RPC sets the group leader, even via 'apply' + ?assertEqual(ok, erpc:call(Node, erlang, apply, [io, format, ["second."]])), + %% 'eval' at the end may be quite slow, so have to wait here + ct:sleep(500), + peer:stop(Peer), + ct:capture_stop(), + Texts = ct:capture_get(), + %% order is not guaranteed, so sort explicitly + ?assertEqual(lists:sort(["STRONGFLOUR.", "second.", "out"]), lists:sort(Texts)). + +dist_up_down() -> + [{doc, "Test that Erlang distribution can go up and down (with TCP alternative)"}]. + +dist_up_down(Config) when is_list(Config) -> + %% skip establishing full mesh, for it makes 'global' hang + %% TODO: fix 'global.erl' locker process so it does not hang + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + connection => {{127, 0, 0, 1}, 0}, args => ["-connect_all", "false"]}), + ?assertEqual(true, net_kernel:connect_node(Node)), + ?assertEqual(true, net_kernel:disconnect(Node)), + ?assertEqual(true, net_kernel:connect_node(Node)), + peer:stop(Peer). + +dist_localhost() -> + [{doc, "Test that localhost and gethostname operate together"}]. + +dist_localhost(Config) when is_list(Config) -> + {ok, Peer, Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), host => "localhost"}), + ?assertMatch([_, "localhost"], string:lexemes(atom_to_list(Node), "@")), + %% start second peer, ensure they see each other + {ok, Host} = inet:gethostname(), + {ok, Peer2, Node2} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), host => Host}), + true = erpc:call(Node, net_kernel, connect_node, [Node2]), + peer:stop(Peer), + peer:stop(Peer2). + +%% ------------------------------------------------------------------- +%% alternative connection cases + +%% Runs in the peer node context, forward a message from peer node to origin +%% node via alternative connection. +-spec forward(Dest :: pid() | atom(), Message :: term()) -> term(). +forward(Dest, Message) -> + group_leader() ! {message, Dest, Message}. + +basic() -> + [{doc, "Tests peer node start, and do some RPC via stdin/stdout"}]. + +basic(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{connection => Conn}), + %% test the alternative connection + ?assertEqual('nonode@nohost', peer:call(Peer, erlang, node, [])), + ?assertException(throw, ball, peer:call(Peer, erlang, throw, [ball])), + %% setup code path to this module (needed to "fancy RPC") + Path = filename:dirname(code:which(?MODULE)), + ?assertEqual(true, peer:call(Peer, code, add_path, [Path])), + %% fancy RPC via message exchange (uses forwarding from the peer) + Control = self(), + RFun = fun() -> receive do -> forward(Control, done) end end, + RemotePid = peer:call(Peer, erlang, spawn, [RFun]), + peer:send(Peer, RemotePid, do), + %% wait back from that process + receive done -> ok end, + %% shutdown the node + ?assertEqual(ok, peer:stop(Peer)), + ?assertNot(is_process_alive(Peer)). + +peer_states() -> + [{doc, "Tests peer node states"}]. + +peer_states(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer} = peer:start_link(#{connection => Conn, wait_boot => {self(), ?FUNCTION_NAME}, + peer_down => continue}), + ?assertEqual(booting, peer:get_state(Peer)), + %% running + receive {?FUNCTION_NAME, {started, _Node, Peer}} -> ok end, + ?assertEqual(running, peer:get_state(Peer)), + peer:cast(Peer, erlang, halt, []), + ct:sleep(1000), %% source of flakiness, should switch to some better notification mechanism + %% down + ?assertMatch({down, _}, peer:get_state(Peer)), + peer:stop(Peer). + +cast() -> + [{doc, "Tests casts via alternative connections"}]. + +cast(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{connection => Conn}), + %% cast RPC + ?assertEqual(undefined, peer:call(Peer, application, get_env, [kernel, foo])), + peer:cast(Peer, application, set_env, [kernel, foo, bar]), + %% this is only to ensure application_controller completed processing + peer:call(Peer, sys, get_state, [application_controller]), + ?assertEqual({ok, bar}, peer:call(Peer, application, get_env, [kernel, foo])), + peer:stop(Peer). + +detached() -> + [{doc, "Tests detached node (RPC via alternative connection)"}]. + +detached(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{connection => Conn}), + ?assertEqual('nonode@nohost', peer:call(Peer, erlang, node, [])), + %% check exceptions + ?assertException(throw, ball, peer:call(Peer, erlang, throw, [ball])), + %% check tcp forwarding + Path = filename:dirname(code:which(?MODULE)), + ?assertEqual(true, peer:call(Peer, code, add_path, [Path])), + %% fancy RPC via message exchange (uses forwarding from the peer) + Control = self(), + RFun = fun() -> receive do -> forward(Control, done) end end, + RemotePid = peer:call(Peer, erlang, spawn, [RFun]), + %% test that sending message over alternative TCP connection works + peer:send(Peer, RemotePid, do), + %% wait back from that process + receive done -> ok end, + %% logging via TCP + ct:capture_start(), + peer:call(Peer, io, format, ["one."]), + peer:call(Peer, erlang, apply, [io, format, ["two."]]), + peer:stop(Peer), + ct:capture_stop(), + Texts = ct:capture_get(), + %% just stop + ?assertEqual(["one.", "two."], Texts). + +dyn_peer() -> + [{doc, "Origin is not distributed, and peer becomes distributed dynamically"}]. + +dyn_peer(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, 'nonode@nohost'} = peer:start_link(#{connection => Conn}), %% start not distributed + Node = list_to_atom(lists:concat([peer:random_name(?FUNCTION_NAME), "@forced.host"])), + {ok, _} = peer:call(Peer, net_kernel, start, [[Node, longnames]]), + ?assertEqual(Node, peer:call(Peer, erlang, node, [])), + peer:stop(Peer). + +stop_peer() -> + [{doc, "Test that peer shuts down even when node sleeps, but control connection closed"}]. + +stop_peer(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + connection => Conn, args => ["-eval", "timer:sleep(60000)."]}), + %% shutdown node + peer:stop(Peer). + +shutdown_halt() -> + [{doc, "Test that peer shutdown halt wait until node connection is down"}]. +shutdown_halt(Config) when is_list(Config) -> + false = shutdown_test(Config, ?FUNCTION_NAME, halt, 500, false, 1000), + ok. + +shutdown_halt_timeout() -> + [{doc, "Test that peer shutdown halt forcefully takes down connection on timeout"}]. +shutdown_halt_timeout(Config) when is_list(Config) -> + false = shutdown_test(Config, ?FUNCTION_NAME, {halt, 1000}, 5000, true, 1500), + ok. + +shutdown_stop() -> + [{doc, "Test that peer shutdown stop wait until node connection is down"}]. +shutdown_stop(Config) when is_list(Config) -> + false = shutdown_test(Config, ?FUNCTION_NAME, infinity, 500, false, 2000), + ok. + +shutdown_stop_timeout() -> + [{doc, "Test that peer shutdown stop forcefully takes down connection on timeout"}]. +shutdown_stop_timeout(Config) when is_list(Config) -> + false = shutdown_test(Config, ?FUNCTION_NAME, 1000, 5000, true, 2500), + ok. + +shutdown_close() -> + [{doc, "Test that peer shutdown close does not wait for dist connection"}]. +shutdown_close(Config) when is_list(Config) -> + _ = shutdown_test(Config, ?FUNCTION_NAME, close, 5000, true, 200), + ok. + +shutdown_test(Config, TC, Shutdown, BlockTime, StopWhileBlocked, MaxWaitTime) -> + Options0 = #{name => ?CT_PEER_NAME(TC), + shutdown => Shutdown, + args => ["-hidden", "-pa", filename:dirname(code:which(?MODULE)), + "-setcookie", atom_to_list(erlang:get_cookie())]}, + Options = case proplists:get_value(connection, Config) of + undefined -> Options0; + Conn -> maps:put(connection, Conn, Options0) + end, + {ok, Peer, Node} = peer:start_link(Options), + EnsureBlockedWait = 500, + BlockStart = erlang:monotonic_time(millisecond), + erpc:cast(Node, + fun () -> + erts_debug:set_internal_state(available_internal_state, true), + erts_debug:set_internal_state(block, BlockTime+EnsureBlockedWait) + end), + receive after EnsureBlockedWait -> ok end, %% Ensure blocked... + Start = erlang:monotonic_time(millisecond), + peer:stop(Peer), + End = erlang:monotonic_time(millisecond), + WaitTime = End - Start, + BlockTimeLeft = BlockTime + EnsureBlockedWait - (Start - BlockStart), + Connected = lists:member(Node, nodes(connected)), + ct:pal("Connected = ~p~nWaitTime = ~p~nBlockTimeLeft = ~p~n", + [Connected, WaitTime, BlockTimeLeft]), + true = WaitTime =< MaxWaitTime, + case StopWhileBlocked of + true -> ok; + false -> true = WaitTime >= BlockTimeLeft, ok + end, + Connected. + +init_debug() -> + [{doc, "Test that debug messages in init work"}]. + +init_debug(Config) when is_list(Config) -> + ct:capture_start(), + {ok, Peer, _Node} = peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), shutdown => 1000, + connection => standard_io, args => ["-init_debug"]}), + ct:sleep(200), %% without this sleep, peer is not fast enough to print + peer:stop(Peer), + ct:capture_stop(), + Texts = lists:append([string:trim(Str, trailing, "\r\n") || Str <- ct:capture_get()]), + %% every boot script starts with this + Expected = "{progress,preloaded}", + Actual = lists:sublist(Texts, 1, length(Expected)), + ?assertEqual(Expected, Actual). + +io_redirect() -> + [{doc, "Tests i/o redirection working for std"}]. + +io_redirect(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{connection => Conn}), + ct:capture_start(), + peer:call(Peer, io, format, [user, "test.", []]), + peer:call(Peer, erlang, apply, [io, format, ["second."]]), + %% ensure no dist connection is set up + ?assertNot(lists:member(Peer, nodes()), {dist_connected, Peer, nodes()}), + ct:capture_stop(), + Texts = ct:capture_get(), + peer:stop(Peer), + ?assertEqual(["test.", "second."], Texts). + +multi_node() -> + [{doc, "Tests several nodes starting concurrently"}]. + +multi_node(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + Peers = [ + peer:start_link(#{name => peer:random_name(?FUNCTION_NAME), + wait_boot => {self(), tag}, connection => Conn}) + || _ <- lists:seq(1, 4)], + Nodes = [receive {tag, {started, Node, Peer}} -> Node end || {ok, Peer} <- Peers], + ?assertEqual(4, length(Nodes)), + [?assertEqual(ok, peer:stop(Peer)) || {ok, Peer} <- Peers]. + +duplicate_name() -> + [{doc, "Tests that a node with the same name fails to start"}]. + +duplicate_name(Config) when is_list(Config) -> + Conn = proplists:get_value(connection, Config), + {ok, Peer, _Node} = peer:start_link(#{connection => Conn, name => ?FUNCTION_NAME, register => false}), + ?assertException(exit, _, peer:start_link(#{connection => standard_io, name => ?FUNCTION_NAME})), + peer:stop(Peer). + +post_process_args() -> + [{doc, "Test that the post_process_args option works"}]. + +post_process_args(Config) when is_list(Config) -> + case {os:type(),os:find_executable("bash")} of + {{win32,_}, _Bash} -> + {skip,"Test does not work on windows"}; + {_, false} -> + {skip,"Test needs bash to run"}; + {_, Bash} -> + Erl = string:split(ct:get_progname()," ",all), + [throw({skip, "Needs bash to run"}) || Bash =:= false], + {ok, Peer, _Node} = + peer:start_link( + #{ name => ?CT_PEER_NAME(), + exec => {Bash,["-c"|Erl]}, + post_process_args => + fun(["-c"|Args]) -> + ["-c", lists:flatten(lists:join($\s, Args))] + end }), + peer:stop(Peer) + end. + +%% ------------------------------------------------------------------- +%% Compatibility: old releases +old_release() -> + [{doc, "Verity running with previous OTP release"}]. + +old_release(Config) when is_list(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + %% don't expect OTP 10 to be available + ?assertEqual(not_available, ?CT_PEER_REL([], "10", PrivDir)), + PrevRel = integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 2), + case ?CT_PEER_REL([], PrevRel, PrivDir) of + not_available -> + {skip, "OTP " ++ PrevRel ++ " not found"}; + {ok, Peer, Node} -> + ?assertEqual(PrevRel, rpc:call(Node, erlang, system_info, [otp_release])), + peer:stop(Peer) + end. + +%% ------------------------------------------------------------------- +%% SSH/Docker cases + +ssh() -> + [{doc, "Tests ssh (localhost) node support"}]. + +ssh(Config) when is_list(Config) -> + %% figure out path to 'erl' locally ('erl' may not be in path via SSH) + case {os:find_executable("erl"), os:find_executable("ssh")} of + {false, _} -> + {skip, "erl not found"}; + {ErlPath, SshPath} -> + Name = peer:random_name(?FUNCTION_NAME), + {OsName, _} = os:type(), + Options = #{exec => {SshPath, ["localhost", ErlPath]}, + connection => standard_io, name => Name, host => "localhost"}, + {ok, Peer, _Node} = + try peer:start_link(Options) of + Result -> Result + catch error:{boot_failed, normal} when OsName =:= win32 -> + %% If the boot fails on windows, ssh may have ended up + %% in wsl, so we try to boot using a wsl path + WslPath = string:trim(os:cmd("wsl wslpath -u " ++ ErlPath)), + peer:start_link( + Options#{ exec => {SshPath, ["localhost", WslPath]}}) + end, + + %% TODO: how to check it really goes over SSH? + %% ssh-ed node is not distributed + ?assertEqual(list_to_atom(Name ++ "@localhost"), peer:call(Peer, erlang, node, [])), + peer:stop(Peer) + end. + +docker() -> + [{doc, "Tests starting peer node in Docker container"}, {timetrap, {seconds, 60}}]. + +build_release(Dir) -> + application:load(sasl), %% otherwise application:get_key will fail + %% build release (tarball) + RelFile = filename:join(Dir, "lambda.rel"), + Release = {release, {"lambda", "1.0.0"}, {erts, erlang:system_info(version)}, + [{App, begin {ok, Vsn} = application:get_key(App, vsn), Vsn end} || App <- [kernel, stdlib, sasl]]}, + ok = file:write_file(RelFile, list_to_binary(lists:flatten(io_lib:format("~tp.", [Release])))), + RelFileNoExt = filename:join(Dir, "lambda"), + {ok, systools_make, []} = systools:make_script(RelFileNoExt, [silent, {outdir, Dir}]), + ok = systools:make_tar(RelFileNoExt, [{erts, code:root_dir()}]). + +build_image(Dir) -> + %% build docker image + BuildScript = filename:join(Dir, "Dockerfile"), + Dockerfile = + "FROM ubuntu:20.04 as runner\n" + "WORKDIR /opt/lambda\n" + "COPY lambda.tar.gz /tmp\n" + "RUN tar -zxvf /tmp/lambda.tar.gz -C /opt/lambda\n" + "ENTRYPOINT [\"/opt/lambda/erts-" ++ erlang:system_info(version) ++ "/bin/dyn_erl\", \"-boot\", \"/opt/lambda/releases/1.0.0/start\"]\n", + ok = file:write_file(BuildScript, Dockerfile), + Output = os:cmd("docker build -t lambda " ++ Dir), + ct:pal("Build result: ~s~n", [Output]). + +docker(Config) when is_list(Config) -> + case os:find_executable("docker") of + false -> + {skip, "Docker not found"}; + Docker -> + PrivDir = proplists:get_value(priv_dir, Config), + build_release(PrivDir), + build_image(PrivDir), + + {ok, Peer, Node} = peer:start_link(#{name => ?CT_PEER_NAME(), + exec => {Docker, ["run", "-i", "lambda"]}, connection => standard_io}), + ?assertEqual(Node, peer:call(Peer, erlang, node, [])), + peer:stop(Peer) + end. + +attached() -> + [{doc, "Test that it is possible to start a peer node using run_erl aka attached"}]. + +attached(Config) -> + attached_test(false, Config). + +attached_cntrl_channel_handler_crash() -> + [{doc, "Test that peer node is halted if peer control channel handler process crashes and peer node is attached"}]. + +attached_cntrl_channel_handler_crash(Config) -> + attached_test(true, Config). + +attached_test(CrashConnectionHandler, Config) -> + RunErl = os:find_executable("run_erl"), + [throw({skip, "Could not find run_erl"}) || RunErl =:= false], + Erl = string:split(ct:get_progname()," ",all), + RunErlDir = filename:join(proplists:get_value(priv_dir, Config),?FUNCTION_NAME), + filelib:ensure_path(RunErlDir), + Connection = proplists:get_value(connection, Config), + Conn = if Connection =:= undefined -> #{ name => ?CT_PEER_NAME() }; + true -> + case CrashConnectionHandler of + false -> + #{ connection => Connection }; + true -> + #{name => ?CT_PEER_NAME(), + connection => Connection} + end + end, + try peer:start( + Conn#{ + exec => {RunErl, Erl}, + detached => false, + post_process_args => + fun(Args) -> + [RunErlDir ++ "/", RunErlDir, + lists:flatten(lists:join(" ",[[$',A,$'] || A <- Args]))] + end + }) of + {ok, Peer, Node} when Connection =:= undefined; Connection =:= 0 -> + case CrashConnectionHandler of + false -> peer:stop(Peer); + true -> cntrl_channel_handler_crash_test(Node) + end + catch error:{detached,_} when Connection =:= standard_io -> + ok + end. + +cntrl_channel_handler_crash() -> + [{doc, "Test that peer node is halted if peer control channel handler process crashes"}]. + +cntrl_channel_handler_crash(Config) -> + NameOpts = #{name => ?CT_PEER_NAME()}, + Opts = case proplists:get_value(connection, Config) of + undefined -> NameOpts; + Conn -> NameOpts#{connection => Conn} + end, + {ok, _Peer, Node} = peer:start_link(Opts), + cntrl_channel_handler_crash_test(Node). + +cntrl_channel_handler_crash_old_release() -> + [{doc, "Test that peer node running an old release is halted if peer control channel handler process crashes"}]. + +cntrl_channel_handler_crash_old_release(Config) -> + NameOpts = #{name => ?CT_PEER_NAME()}, + Opts = case proplists:get_value(connection, Config) of + undefined -> NameOpts; + Conn -> NameOpts#{connection => Conn} + end, + PrivDir = proplists:get_value(priv_dir, Config), + OldRel = integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 2), + case ?CT_PEER_REL(Opts, OldRel, PrivDir) of + not_available -> + {skip, "No OTP " ++ OldRel ++ " installation found"}; + {ok, _Peer, Node} -> + cntrl_channel_handler_crash_test(Node) + end. + +cntrl_channel_handler_crash_test(Node) -> + true = monitor_node(Node, true), + ChkStck = fun ChkStck (_Pid, []) -> + ok; + ChkStck (Pid, [{peer, io_server_loop, _, _} | _]) -> + throw(Pid); + ChkStck (Pid, [{peer, origin_link, _, _} | _]) -> + throw(Pid); + ChkStck (Pid, [_SF|SFs]) -> + ChkStck(Pid, SFs) + end, + ChkConnHandler = fun (undefined) -> + ok; + (Pid) when is_pid(Pid) -> + case erpc:call(Node, erlang, process_info, + [Pid, current_stacktrace]) of + {current_stacktrace, STrace} -> + ChkStck(Pid, STrace); + _ -> + ok + end + end, + ConnHandler = try + ChkConnHandler(erpc:call(Node, erlang, whereis, [user])), + lists:foreach(fun (Pid) -> + ChkConnHandler(Pid) + end, erpc:call(Node, erlang, processes, [])), + error(no_cntrl_channel_handler_found) + catch + throw:Pid when is_pid(Pid) -> Pid + end, + PeerSup = erpc:call(Node, erlang, whereis, [peer_supervision]), + ct:log("peer_supervision state: ~p~n", [erpc:call(Node, sys, get_state, [PeerSup])]), + {links, Links} = erpc:call(Node, erlang, process_info, [PeerSup, links]), + true = lists:member(ConnHandler, Links), + ok = erpc:cast(Node, erlang, exit, [ConnHandler, kill]), + receive + {nodedown, Node} -> + ok + after + 5000 -> + ct:fail(peer_did_not_halt) + end. diff --git a/lib/stdlib/test/pool_SUITE.erl b/lib/stdlib/test/pool_SUITE.erl index 618d71f6c45b..a097f1a17e09 100644 --- a/lib/stdlib/test/pool_SUITE.erl +++ b/lib/stdlib/test/pool_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -23,6 +23,8 @@ init_per_group/2,end_per_group/2]). -export([basic/1, link_race/1, echo/1]). +-include_lib("common_test/include/ct.hrl"). + suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames, 1}]}]}]. all() -> @@ -45,7 +47,7 @@ end_per_group(_GroupName, Config) -> basic(Config) -> - {ok, Node, PoolNode} = init_pool(pool_SUITE_basic, basic, Config), + {ok, Peer, Node, PoolNode} = init_pool(?FUNCTION_NAME, basic, Config), Node = rpc:call(Node, pool, get_node, []), PoolNode = rpc:call(Node, pool, get_node, []), @@ -53,19 +55,19 @@ basic(Config) -> do_echo(Node), do_echo(Node), - test_server:stop_node(Node), + peer:stop(Peer), ok. link_race(Config) -> - {ok, Node, PoolNode} = init_pool(pool_SUITE_basic, basic, Config), + {ok, Peer, Node, PoolNode} = init_pool(?FUNCTION_NAME, basic, Config), Node = rpc:call(Node, pool, get_node, []), PoolNode = rpc:call(Node, pool, get_node, []), rpc:call(Node, pool, pspawn_link, [erlang, is_atom, [?MODULE]]), - test_server:stop_node(Node), + peer:stop(Peer), ok. do_echo(Node) -> @@ -79,10 +81,9 @@ echo(Parent) -> end. -init_pool(Proxy, Name, Config) -> +init_pool(Case, Name, Config) -> PrivDir = proplists:get_value(priv_dir, Config), - [Slave] = proplists:get_value(nodenames, Config), - {ok, Node} = test_server:start_node(Proxy, slave, []), + {ok, Peer, Node} = ?CT_PEER(#{name => Case}), {ok, Hostname} = inet:gethostname(), file:write_file(filename:join(PrivDir,".hosts.erlang"),"'"++Hostname++"'.\n"), ok = rpc:call(Node, file, set_cwd, [PrivDir]), @@ -92,4 +93,4 @@ init_pool(Proxy, Name, Config) -> Nodes = rpc:call(Node, pool, get_nodes, []), [rpc:call(N, code, add_patha, [filename:dirname(code:which(?MODULE))]) || N <- Nodes], - {ok, Node, PoolNode}. + {ok, Peer, Node, PoolNode}. diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index b2ad0ba28fbd..5db6d88a1531 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -668,40 +668,53 @@ stop(_Config) -> Pid3 = proc_lib:spawn(HangProc), {'EXIT',timeout} = (catch proc_lib:stop(Pid3,normal,1000)), + %% Ensure that a termination message is always sent to the + %% target process and that it eventually terminates. + Pid4 = proc_lib:spawn(HangProc), + Ref4 = monitor(process, Pid4), + {'EXIT', timeout} = (catch proc_lib:stop(Pid4, normal, 0)), + ok = receive + {'DOWN', Ref4, process, _, _} -> + ok; + M -> M + after 6000 -> + timeout + end, + %% Success case with other reason than 'normal' - Pid4 = proc_lib:spawn(SysMsgProc), - ok = proc_lib:stop(Pid4,other_reason,infinity), - false = erlang:is_process_alive(Pid4), + Pid5 = proc_lib:spawn(SysMsgProc), + ok = proc_lib:stop(Pid5,other_reason,infinity), + false = erlang:is_process_alive(Pid5), %% System message is handled, but process dies with other reason %% than the given (in system_terminate/4 below) - Pid5 = proc_lib:spawn(SysMsgProc), - {'EXIT',{{badmatch,2},_Stacktrace}} = (catch proc_lib:stop(Pid5,crash,infinity)), - false = erlang:is_process_alive(Pid5), + Pid6 = proc_lib:spawn(SysMsgProc), + {'EXIT',{{badmatch,2},_Stacktrace}} = (catch proc_lib:stop(Pid6,crash,infinity)), + false = erlang:is_process_alive(Pid6), %% Local registered name - Pid6 = proc_lib:spawn(SysMsgProc), - register(to_stop,Pid6), + Pid7 = proc_lib:spawn(SysMsgProc), + register(to_stop,Pid7), ok = proc_lib:stop(to_stop), undefined = whereis(to_stop), - false = erlang:is_process_alive(Pid6), + false = erlang:is_process_alive(Pid7), %% Remote registered name - {ok,Node} = test_server:start_node(proc_lib_SUITE_stop,slave,[]), + {ok, Peer, Node} = ?CT_PEER(), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), - Pid7 = spawn(Node,SysMsgProc), - true = rpc:call(Node,erlang,register,[to_stop,Pid7]), - Pid7 = rpc:call(Node,erlang,whereis,[to_stop]), + Pid8 = spawn(Node,SysMsgProc), + true = rpc:call(Node,erlang,register,[to_stop,Pid8]), + Pid8 = rpc:call(Node,erlang,whereis,[to_stop]), ok = proc_lib:stop({to_stop,Node}), undefined = rpc:call(Node,erlang,whereis,[to_stop]), - false = rpc:call(Node,erlang,is_process_alive,[Pid7]), + false = rpc:call(Node,erlang,is_process_alive,[Pid8]), %% Local and remote registered name, but non-existing {'EXIT',noproc} = (catch proc_lib:stop(to_stop)), {'EXIT',noproc} = (catch proc_lib:stop({to_stop,Node})), - true = test_server:stop_node(Node), + peer:stop(Peer), %% Remote registered name, but non-existing node {'EXIT',{{nodedown,Node},_}} = (catch proc_lib:stop({to_stop,Node})), diff --git a/lib/stdlib/test/property_test/base64_prop.erl b/lib/stdlib/test/property_test/base64_prop.erl new file mode 100644 index 000000000000..f4d7f264f10b --- /dev/null +++ b/lib/stdlib/test/property_test/base64_prop.erl @@ -0,0 +1,556 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2023. 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(base64_prop). + +-compile([export_all, nowarn_export_all]). + +-proptest(eqc). +-proptest([triq, proper]). + +-ifndef(EQC). +-ifndef(PROPER). +-ifndef(TRIQ). +-define(EQC, true). +-endif. +-endif. +-endif. + +-ifdef(EQC). +-include_lib("eqc/include/eqc.hrl"). +-define(MOD_eqc,eqc). + +-else. +-ifdef(PROPER). +-include_lib("proper/include/proper.hrl"). +-define(MOD_eqc,proper). + +-else. +-ifdef(TRIQ). +-define(MOD_eqc,triq). +-include_lib("triq/include/triq.hrl"). + +-endif. +-endif. +-endif. + +%%%%%%%%%%%%%%%%%% +%%% Properties %%% +%%%%%%%%%%%%%%%%%% + +prop_encode_1() -> + ?FORALL( + Str, + oneof([list(byte()), binary()]), + begin + Enc = base64:encode(Str), + Dec = base64:decode(Enc), + is_b64_binary(standard, Enc) andalso str_equals(Str, Dec) + end + ). + +prop_encode_2() -> + ?FORALL( + {Str, Mode}, + {oneof([list(byte()), binary()]), mode()}, + begin + Enc = base64:encode(Str, #{mode => Mode}), + Dec = base64:decode(Enc, #{mode => Mode}), + is_b64_binary(Mode, Enc) andalso str_equals(Str, Dec) + end + ). + +prop_encode_to_string_1() -> + ?FORALL( + Str, + oneof([list(byte()), binary()]), + begin + Enc = base64:encode_to_string(Str), + Dec = base64:decode_to_string(Enc), + is_b64_string(standard, Enc) andalso str_equals(Str, Dec) + end + ). + +prop_encode_to_string_2() -> + ?FORALL( + {Str, Mode}, + {oneof([list(byte()), binary()]), mode()}, + begin + Enc = base64:encode_to_string(Str, #{mode => Mode}), + Dec = base64:decode_to_string(Enc, #{mode => Mode}), + is_b64_string(Mode, Enc) andalso str_equals(Str, Dec) + end + ). + +prop_decode_1() -> + ?FORALL( + {NormalizedB64, WspedB64}, + wsped_b64(standard), + begin + Dec = base64:decode(WspedB64), + Enc = base64:encode(Dec), + is_binary(Dec) andalso b64_equals(standard, NormalizedB64, Enc) + end + ). + +prop_decode_2() -> + ?FORALL( + {{NormalizedB64, WspedB64}, Mode}, + ?LET( + Mode, + mode(), + {wsped_b64(Mode), Mode} + ), + begin + Dec = base64:decode(WspedB64, #{mode => Mode}), + Enc = base64:encode(Dec, #{mode => Mode}), + is_binary(Dec) andalso b64_equals(Mode, NormalizedB64, Enc) + end + ). + +prop_decode_1_malformed() -> + common_decode_malformed(fun wsped_b64/1, standard, fun(Data, _) -> base64:decode(Data) end). + +prop_decode_2_malformed() -> + common_decode_malformed(fun wsped_b64/1, mode(), fun base64:decode/2). + +prop_decode_1_noisy() -> + common_decode_noisy(standard, fun(Data, _) -> base64:decode(Data) end). + +prop_decode_2_noisy() -> + common_decode_noisy(mode(), fun base64:decode/2). + +prop_decode_to_string_1() -> + ?FORALL( + {NormalizedB64, WspedB64}, + wsped_b64(standard), + begin + Dec = base64:decode_to_string(WspedB64), + Enc = base64:encode(Dec), + is_bytelist(Dec) andalso b64_equals(standard, NormalizedB64, Enc) + end + ). + +prop_decode_to_string_2() -> + ?FORALL( + {{NormalizedB64, WspedB64}, Mode}, + ?LET( + Mode, + mode(), + {wsped_b64(Mode), Mode} + ), + begin + Dec = base64:decode_to_string(WspedB64, #{mode => Mode}), + Enc = base64:encode(Dec, #{mode => Mode}), + is_bytelist(Dec) andalso b64_equals(Mode, NormalizedB64, Enc) + end + ). + +prop_decode_to_string_1_malformed() -> + common_decode_malformed(fun wsped_b64/1, standard, fun(Data, _) -> base64:decode_to_string(Data) end). + +prop_decode_to_string_2_malformed() -> + common_decode_malformed(fun wsped_b64/1, mode(), fun base64:decode_to_string/2). + +prop_decode_to_string_1_noisy() -> + common_decode_noisy(standard, fun(Data, _) -> base64:decode_to_string(Data) end). + +prop_decode_to_string_2_noisy() -> + common_decode_noisy(mode(), fun base64:decode_to_string/2). + +prop_mime_decode_1() -> + ?FORALL( + {NormalizedB64, NoisyB64}, + noisy_b64(standard), + begin + Dec = base64:mime_decode(NoisyB64), + Enc = base64:encode(Dec), + is_binary(Dec) andalso b64_equals(standard, NormalizedB64, Enc) + end + ). + +prop_mime_decode_2() -> + ?FORALL( + {{NormalizedB64, NoisyB64}, Mode}, + ?LET( + Mode, + mode(), + {wsped_b64(Mode), Mode} + ), + begin + Dec = base64:mime_decode(NoisyB64, #{mode => Mode}), + Enc = base64:encode(Dec, #{mode => Mode}), + is_binary(Dec) andalso b64_equals(Mode, NormalizedB64, Enc) + end + ). + +prop_mime_decode_1_malformed() -> + common_decode_malformed(fun noisy_b64/1, standard, fun(Data, _) -> base64:mime_decode(Data) end). + +prop_mime_decode_2_malformed() -> + common_decode_malformed(fun noisy_b64/1, mode(), fun base64:mime_decode/2). + +prop_mime_decode_to_string_1() -> + ?FORALL( + {NormalizedB64, NoisyB64}, + noisy_b64(standard), + begin + Dec = base64:mime_decode_to_string(NoisyB64), + Enc = base64:encode(Dec), + is_bytelist(Dec) andalso b64_equals(standard, NormalizedB64, Enc) + end + ). + +prop_mime_decode_to_string_2() -> + ?FORALL( + {{NormalizedB64, NoisyB64}, Mode}, + ?LET( + Mode, + mode(), + {wsped_b64(Mode), Mode} + ), + begin + Dec = base64:mime_decode_to_string(NoisyB64, #{mode => Mode}), + Enc = base64:encode(Dec, #{mode => Mode}), + is_bytelist(Dec) andalso b64_equals(Mode, NormalizedB64, Enc) + end + ). + +prop_mime_decode_to_string_1_malformed() -> + common_decode_malformed(fun noisy_b64/1, standard, fun(Data, _) -> base64:mime_decode_to_string(Data) end). + +prop_mime_decode_to_string_2_malformed() -> + common_decode_malformed(fun noisy_b64/1, mode(), fun base64:mime_decode_to_string/2). + +common_decode_noisy(ModeGen, Fn) -> + ?FORALL( + {{_, NoisyB64}, Mode}, + ?LET( + Mode, + ModeGen, + {?SUCHTHAT({NormalizedB64, NoisyB64}, noisy_b64(Mode), NormalizedB64 =/= NoisyB64), Mode} + ), + try + Fn(NoisyB64, #{mode => Mode}) + of + _ -> + false + catch + error:_ -> + true + end + ). + +common_decode_malformed(DataGen, ModeGen, Fn) -> + ?FORALL( + {MalformedB64, Mode}, + ?LET( + Mode, + ModeGen, + ?LET( + {{NormalizedB64, NoisyB64}, Malformings, InsertFn}, + { + DataGen(Mode), + oneof( + [ + [b64_char(Mode)], + [b64_char(Mode), b64_char(Mode)], + [b64_char(Mode), b64_char(Mode), b64_char(Mode)] + ] + ), + function1(boolean()) + }, + {{NormalizedB64, insert_noise(NoisyB64, Malformings, InsertFn)}, Mode} + ) + ), + try + Fn(MalformedB64, #{mode => Mode}) + of + _ -> + false + catch + error:_ -> + true + end + ). + +%%%%%%%%%%%%%%%%%% +%%% Generators %%% +%%%%%%%%%%%%%%%%%% + +%% Generate base64 encoding mode. +mode() -> + oneof([standard, urlsafe]). + +%% Generate a single character from the base64 alphabet. +b64_char(Mode) -> + oneof(b64_chars(Mode)). + +%% Generate a string of characters from the base64 alphabet, +%% including padding if needed. +b64_string(Mode) -> + ?LET( + {L, Filler}, + {list(b64_char(Mode)), b64_char(Mode)}, + case length(L) rem 4 of + 0 -> L; + 1 -> L ++ [Filler, $=, $=]; + 2 -> L ++ [$=, $=]; + 3 -> L ++ [$=] + end + ). + +%% Generate a binary of characters from the base64 alphabet, +%% including padding if needed. +b64_binary(Mode) -> + ?LET( + L, + b64_string(Mode), + list_to_binary(L) + ). + +%% Generate a string or binary of characters from the +%% base64 alphabet, including padding if needed. +b64(Mode) -> + oneof([b64_string(Mode), b64_binary(Mode)]). + +%% Generate a string or binary of characters from the +%% base64 alphabet, including padding if needed, with +%% whitespaces inserted at random indexes. +wsped_b64(Mode) -> + ?LET( + {B64, Wsps, InsertFn}, + {b64(Mode), list(oneof([$\t, $\r, $\n, $\s])), function1(boolean())}, + {B64, insert_noise(B64, Wsps, InsertFn)} + ). + +%% Generate a single character outside of the base64 alphabet. +%% As whitespaces are allowed but ignored in base64, this generator +%% will produce no whitespaces, either. +non_b64_char(Mode) -> + oneof(lists:seq(16#00, 16#FF) -- b64_allowed_chars(Mode)). + +%% Generate a string or binary of characters from the +%% base64 alphabet, including padding if needed, with +%% whitespaces and non-base64 ("invalid") characters +%% inserted at random indexes. +noisy_b64(Mode) -> + ?LET( + {{B64, WspedB64}, Noise, InsertFn}, + {wsped_b64(Mode), non_empty(list(non_b64_char(Mode))), function1(boolean())}, + {B64, insert_noise(WspedB64, Noise, InsertFn)} + ). + +%%%%%%%%%%%%%%% +%%% Helpers %%% +%%%%%%%%%%%%%%% + +%% The characters of the base64 alphabet. +%% "=" is not included, as it is special in that it +%% may only appear at the end of a base64 encoded string +%% for padding. +b64_chars_common() -> + lists:seq($0, $9) ++ + lists:seq($a, $z) ++ + lists:seq($A, $Z). + +b64_chars(standard) -> + b64_chars_common() ++ [$+, $/]; +b64_chars(urlsafe) -> + b64_chars_common() ++ [$-, $_]. + +%% In addition to the above, the whitespace characters +%% HTAB, CR, LF and SP are allowed to appear in a base64 +%% encoded string and should be ignored. +b64_allowed_chars(Mode) -> + [$\t, $\r, $\n, $\s | b64_chars(Mode)]. + +%% Insert the given list of noise characters at random +%% places into the given base64 string. +insert_noise(B64, Noise, InsertFn) -> + insert_noise(B64, Noise, InsertFn, 0). + +insert_noise(B64, [], _, _) -> + B64; +insert_noise([], Noise, _, _) -> + Noise; +insert_noise(<<>>, Noise, _, _) -> + list_to_binary(Noise); +insert_noise([B|Bs] = B64, [N|Ns] = Noise, InsertFn, Idx) -> + case InsertFn(Idx) of + true -> + [B|insert_noise(Bs, Noise, InsertFn, Idx + 1)]; + false -> + [N|insert_noise(B64, Ns, InsertFn, Idx + 1)] + end; +insert_noise(<> = B64, [N|Ns] = Noise, InsertFn, Idx) -> + case InsertFn(Idx) of + true -> + <>; + false -> + <> + end. + +%% Check if the given character is in the base64 alphabet. +%% This does not include the padding character "=". +is_b64_char(standard, $+) -> + true; +is_b64_char(standard, $/) -> + true; +is_b64_char(urlsafe, $-) -> + true; +is_b64_char(urlsafe, $_) -> + true; +is_b64_char(_, C) when C >= $0, C =< $9 -> + true; +is_b64_char(_, C) when C >= $A, C =< $Z -> + true; +is_b64_char(_, C) when C >= $a, C =< $z -> + true; +is_b64_char(_, _) -> + false. + +%% Check if the given argument is a base64 binary, +%% ie that it consists of quadruplets of characters +%% from the base64 alphabet, whereas the last quadruplet +%% may be padded with one or two "="s +is_b64_binary(Mode, B) -> + is_b64_binary(Mode, B, 0). + +is_b64_binary(_, <<>>, N) -> + N rem 4 =:= 0; +is_b64_binary(_, <<$=>>, N) -> + N rem 4 =:= 3; +is_b64_binary(_, <<$=, $=>>, N) -> + N rem 4 =:= 2; +is_b64_binary(Mode, <>, N) -> + case is_b64_char(Mode, C) of + true -> + is_b64_binary(Mode, More, N + 1); + false -> + false + end. + +%% Check if the given argument is a base64 string +%% (see is_b64_binary/1) +is_b64_string(Mode, S) -> + is_b64_binary(Mode, list_to_binary(S)). + +%% Check if the argument is a list of bytes. +is_bytelist(L) -> + lists:all( + fun (B) -> + is_integer(B) andalso B >= 16#00 andalso B =< 16#FF + end, + L + ). + +%% Check two byte-lists or binaries for equality. +str_equals(Str1, Str2) when is_list(Str1) -> + str_equals(list_to_binary(Str1), Str2); +str_equals(Str1, Str2) when is_list(Str2) -> + str_equals(Str1, list_to_binary(Str2)); +str_equals(Str1, Str2) when is_binary(Str1), is_binary(Str2) -> + Str1 =:= Str2. + +%% Check two base64-encoded byte-lists or binaries for equality. +%% Assumes that the given arguments are in a normalized form, +%% ie that they consist only of characters from the base64 +%% alphabet and possible padding ("="). +b64_equals(Mode, L, B) when is_list(L) -> + b64_equals(Mode, list_to_binary(L), B); +b64_equals(Mode, B, L) when is_list(L) -> + b64_equals(Mode, B, list_to_binary(L)); +b64_equals(Mode, B1, B2) when is_binary(B1), is_binary(B2) -> + b64_equals1(Mode, B1, B2). + +b64_equals1(Mode, <>, <>) -> + is_b64_binary(Mode, Eq); +b64_equals1(Mode, <>, <>) -> + case lists:all(fun(C) -> is_b64_char(Mode, C) end, binary_to_list(Eq)) of + true -> + b64_equals1(Mode, More1, More2); + false -> + false + end; +b64_equals1(Mode, <>, <>) -> + %% If the encoded string ends with "==", there exist multiple + %% possibilities for the character preceding the "==" as only the + %% 3rd and 4th bits of the encoded byte represented by that + %% character are significant. + %% + %% For example, all of the encoded strings "QQ==", "QR==", ..., "QZ==" + %% decode to the string "A", since all the bytes represented by Q to Z + %% are the same in the significant 3rd and 4th bit. + case is_b64_char(Mode, Eq) of + true -> + Normalize = fun + (C) when C >= $A, C =< $P -> $A; + (C) when C >= $Q, C =< $Z -> $Q; + (C) when C >= $a, C =< $f -> $Q; + (C) when C >= $g, C =< $v -> $g; + (C) when C >= $w, C =< $z -> $w; + (C) when C >= $0, C =< $9 -> $w; + ($+) when Mode =:= standard -> $w; + ($-) when Mode =:= urlsafe -> $w; + ($/) when Mode =:= standard -> $w; + ($_) when Mode =:= urlsafe -> $w + end, + Normalize(B1) =:= Normalize(B2); + false -> + false + end; +b64_equals1(Mode, <>, <>) -> + %% Similar to the above, but with the encoded string ending with a + %% single "=" the 3rd to 6th bits of the encoded byte are significant, + %% such that, for example, all the encoded strings "QUE=" to "QUH=" + %% decode to the same string "AA". + case is_b64_char(Mode, Eq1) andalso is_b64_char(Mode, Eq2) of + true -> + Normalize = fun + (C) when C >= $A, C =< $D -> $A; + (C) when C >= $E, C =< $H -> $E; + (C) when C >= $I, C =< $L -> $I; + (C) when C >= $M, C =< $P -> $M; + (C) when C >= $Q, C =< $T -> $Q; + (C) when C >= $U, C =< $X -> $U; + (C) when C >= $Y, C =< $Z -> $Y; + (C) when C >= $a, C =< $b -> $Y; + (C) when C >= $c, C =< $f -> $c; + (C) when C >= $g, C =< $j -> $g; + (C) when C >= $k, C =< $n -> $k; + (C) when C >= $o, C =< $r -> $o; + (C) when C >= $s, C =< $v -> $s; + (C) when C >= $w, C =< $z -> $w; + (C) when C >= $0, C =< $3 -> $0; + (C) when C >= $4, C =< $7 -> $4; + (C) when C >= $8, C =< $9 -> $8; + ($+) when Mode =:= standard -> $8; + ($-) when Mode =:= urlsafe -> $8; + ($/) when Mode =:= standard -> $8; + ($_) when Mode =:= urlsafe -> $8 + end, + Normalize(B1) =:= Normalize(B2); + false -> + false + end; +b64_equals1(_, <<>>, <<>>) -> + true; +b64_equals1(_, _, _) -> + false. diff --git a/lib/stdlib/test/property_test/binary_prop.erl b/lib/stdlib/test/property_test/binary_prop.erl new file mode 100644 index 000000000000..00efa77b8ce3 --- /dev/null +++ b/lib/stdlib/test/property_test/binary_prop.erl @@ -0,0 +1,37 @@ +-module(binary_prop). + +-export([prop_hex_encode_2/0]). + +-compile([export_all, nowarn_export_all]). + +-include_lib("common_test/include/ct_property_test.hrl"). + +prop_hex_encode_2() -> + ?FORALL(Data, data(), + begin + UpperHex = binary:encode_hex(Data, uppercase), + LowerHex = binary:encode_hex(Data, lowercase), + binary:decode_hex(LowerHex) =:= Data andalso + binary:decode_hex(UpperHex) =:= Data andalso + check_hex_encoded(Data, UpperHex, LowerHex) + end). + +data() -> + ?SIZED(Size, resize(Size * 2, binary())). + + +%% @doc Credit to the comment of @Maria-12648430 +-spec check_hex_encoded(Data :: binary(), UpperHex :: binary(), LoweHex :: binary()) -> boolean(). +check_hex_encoded(<>, <>, <>) -> + check_hex_chars_match(I1, U1, L1) andalso + check_hex_chars_match(I2, U2, L2) andalso + check_hex_encoded(Ins, UCs, LCs); +check_hex_encoded(<<>>, <<>>, <<>>) -> + true; +check_hex_encoded(_, _, _) -> + false. + +check_hex_chars_match(X, U, L) when X < 10 -> + (U =:= $0 + X) andalso (L =:= $0 + X); +check_hex_chars_match(X, U, L) -> + (U =:= $A + X -10) andalso (L =:= $a + X -10). diff --git a/lib/stdlib/test/property_test/lists_prop.erl b/lib/stdlib/test/property_test/lists_prop.erl new file mode 100644 index 000000000000..68c087b76d3d --- /dev/null +++ b/lib/stdlib/test/property_test/lists_prop.erl @@ -0,0 +1,2146 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2023. 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(lists_prop). + +-compile([export_all, nowarn_export_all]). + +-proptest(eqc). +-proptest([triq, proper]). + +-ifndef(EQC). +-ifndef(PROPER). +-ifndef(TRIQ). +-define(EQC, true). +-endif. +-endif. +-endif. + +-ifdef(EQC). +-include_lib("eqc/include/eqc.hrl"). +-define(MOD_eqc,eqc). + +-else. +-ifdef(PROPER). +-include_lib("proper/include/proper.hrl"). +-define(MOD_eqc,proper). + +-else. +-ifdef(TRIQ). +-define(MOD_eqc,triq). +-include_lib("triq/include/triq.hrl"). + +-endif. +-endif. +-endif. + +-define(RANDOM_ATOMS, 1000). + +%%%%%%%%%%%%%%%%%% +%%% Properties %%% +%%%%%%%%%%%%%%%%%% + +%% all/2 +prop_all_true() -> + ?FORALL( + InList, + gen_list(), + lists:all(fun(_) -> true end, InList) + ). + +prop_all_false() -> + ?FORALL( + {InList, Elem}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), make_ref()}, + {F ++ [E|R], E} + ), + not lists:all(fun(T) -> T =/= Elem end, InList) + ). + +%% any/2 +prop_any_true() -> + ?FORALL( + {InList, Elem}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), make_ref()}, + {F ++ [E|R], E} + ), + lists:any(fun(T) -> T =:= Elem end, InList) + ). + +prop_any_false() -> + ?FORALL( + InList, + gen_list(), + not lists:any(fun(_) -> false end, InList) + ). + +%% append/1 +prop_append_1() -> + ?FORALL( + InLists, + list(gen_list()), + check_appended(InLists, lists:append(InLists)) + ). + +%% append/2 +prop_append_2() -> + ?FORALL( + {InList1, InList2}, + {gen_list(), gen_list()}, + lists:append(InList1, InList2) =:= InList1 ++ InList2 + ). + +%% concat/1 +prop_concat() -> + ?FORALL( + {InList, ExpString}, + gen_list_fold( + oneof([gen_atom(), number(), string()]), + fun + (A, Acc) when is_atom(A) -> Acc ++ atom_to_list(A); + (I, Acc) when is_integer(I) -> Acc ++ integer_to_list(I); + (F, Acc) when is_float(F) -> Acc ++ float_to_list(F); + (L, Acc) when is_list(L) -> Acc ++ L + end, + [] + ), + lists:concat(InList) =:= ExpString + ). + +%% delete/2 +prop_delete() -> + ?FORALL( + {InList, DelElem}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_any()}, + {F ++ [E|R], E} + ), + begin + DeletedList = lists:delete(DelElem, InList), + length(DeletedList) =:= length(InList) - 1 andalso + check_deleted(DelElem, InList, DeletedList) + end + ). + +prop_delete_absent() -> + ?FORALL( + InList, + gen_list(), + lists:delete(make_ref(), InList) =:= InList + ). + +%% droplast/1 +prop_droplast() -> + ?FORALL( + InList, + gen_list(), + try + lists:droplast(InList) =:= lists:reverse(tl(lists:reverse(InList))) + catch + error:_ -> + InList =:= [] + end + ). + +%% dropwhile/2 +prop_dropwhile() -> + ?FORALL( + {Pred, InList, ExpList}, + ?LET( + Fn, + function1(boolean()), + ?LET( + {L, {_, DL}}, + gen_list_fold( + gen_any(), + fun(E, {Drop, Acc}) -> + case Drop andalso Fn(E) of + true -> {true, Acc}; + false -> {false, Acc ++ [E]} + end + end, + {true, []} + ), + {Fn, L, DL} + ) + ), + lists:dropwhile(Pred, InList) =:= ExpList + ). + +%% duplicate/2 +prop_duplicate() -> + ?FORALL( + {N, Term, ExpList}, + ?LET( + T, + gen_any(), + ?LET(L, list(T), {length(L), T, L}) + ), + lists:duplicate(N, Term) =:= ExpList + ). + +%% enumerate/1 +prop_enumerate_1() -> + ?FORALL( + {InList, ExpList}, + ?LET( + {L, {_, EL}}, + gen_list_fold( + gen_any(), + fun(T, {I, Acc}) -> + {I + 1, Acc ++ [{I, T}]} + end, + {1, []} + ), + {L, EL} + ), + lists:enumerate(InList) =:= ExpList + ). + +%% enumerate/2 +prop_enumerate_2() -> + ?FORALL( + {StartIndex, InList, ExpList}, + ?LET( + N, + integer(), + ?LET( + {L, {_, EL}}, + gen_list_fold( + gen_any(), + fun(T, {I, Acc}) -> + {I + 1, Acc ++ [{I, T}]} + end, + {N, []} + ), + {N, L, EL} + ) + ), + lists:enumerate(StartIndex, InList) =:= ExpList + ). + +%% enumerate/3 +prop_enumerate_3() -> + ?FORALL( + {StartIndex, Step, InList, ExpList}, + ?LET( + {N, S}, + {integer(), integer()}, + ?LET( + {L, {_, EL}}, + gen_list_fold( + gen_any(), + fun(T, {I, Acc}) -> + {I + S, Acc ++ [{I, T}]} + end, + {N, []} + ), + {N, S, L, EL} + ) + ), + lists:enumerate(StartIndex, Step, InList) =:= ExpList + ). + +%% filter/2 +prop_filter() -> + ?FORALL( + {Pred, InList, ExpList}, + ?LET( + P, + function1(boolean()), + ?LET( + {L, F}, + gen_list_fold( + gen_any(), + fun(T, Acc) -> + case P(T) of + true -> Acc ++ [T]; + false -> Acc + end + end, + [] + ), + {P, L, F} + ) + ), + lists:filter(Pred, InList) =:= ExpList + ). + +%% filtermap/2 +prop_filtermap() -> + ?FORALL( + {FilterMapFn, InList, ExpList}, + ?LET( + Fn, + function1(oneof([true, false, {true, gen_any()}])), + ?LET( + {L, FM}, + gen_list_fold( + gen_any(), + fun(T, Acc) -> + case Fn(T) of + false -> Acc; + true -> Acc ++ [T]; + {true, T1} -> Acc ++ [T1] + end + end, + [] + ), + {Fn, L, FM} + ) + ), + lists:filtermap(FilterMapFn, InList) =:= ExpList + ). + +%% flatlength/1 +prop_flatlength() -> + ?FORALL( + {DeepList, Len}, + gen_list_deepfold(fun(_, _, Cnt) -> Cnt + 1 end, 0), + lists:flatlength(DeepList) =:= Len + ). + +%% flatmap/2 +prop_flatmap() -> + ?FORALL( + {MapFn, InList, ExpList}, + ?LET( + Fn, + function1(gen_list()), + ?LET( + {L, FlatMapped}, + gen_list_fold( + gen_any(), + fun(T, Acc) -> + Acc ++ Fn(T) + end, + [] + ), + {Fn, L, FlatMapped} + ) + ), + lists:flatmap(MapFn, InList) =:= ExpList + ). + +%% flatten/1 +prop_flatten_1() -> + ?FORALL( + {DeepList, FlatList}, + gen_list_deepfold(fun(_, E, Acc) -> Acc ++ [E] end, []), + lists:flatten(DeepList) =:= FlatList + ). + +%% flatten/2 +prop_flatten_2() -> + ?FORALL( + {{DeepList, FlatList}, Tail}, + {gen_list_deepfold(fun(_, E, Acc) -> Acc ++ [E] end, []), gen_list()}, + lists:flatten(DeepList, Tail) =:= FlatList ++ Tail + ). + +%% foldl/3 +prop_foldl() -> + ?FORALL( + {FoldFn, InList, Acc0, Exp}, + ?LET( + {Fn, Acc0}, + {function2(gen_any()), gen_any()}, + ?LET( + {L, V}, + gen_list_fold(gen_any(), Fn, Acc0), + {Fn, L, Acc0, V} + ) + ), + lists:foldl(FoldFn, Acc0, InList) =:= Exp + ). + +%% foldr/3 +prop_foldr() -> + ?FORALL( + {FoldFn, InList, Acc0, Exp}, + ?LET( + {Fn, Acc0}, + {function2(gen_any()), gen_any()}, + ?LET( + {L, V}, + gen_list_fold(gen_any(), Fn, Acc0), + {Fn, lists:reverse(L), Acc0, V} + ) + ), + lists:foldr(FoldFn, Acc0, InList) =:= Exp + ). + +%% foreach/2 +prop_foreach() -> + ?FORALL( + InList, + gen_list(), + begin + Tag = make_ref(), + lists:foreach(fun(E) -> self() ! {Tag, E} end, InList), + [receive {Tag, T} -> T after 100 -> error(timeout) end || _ <- InList] =:= InList + end + ). + +%% join/2 +prop_join() -> + ?FORALL( + {Sep, InList}, + {gen_any(), gen_list()}, + check_joined(Sep, InList, lists:join(Sep, InList)) + ). + +%% keydelete/3 +prop_keydelete() -> + ?FORALL( + {Key, N, InList}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3)}, + {K, N, F ++ [E|R]} + ) + ), + begin + DeletedL = lists:keydelete(Key, N, InList), + length(DeletedL) =:= length(InList) - 1 andalso + check_keydeleted(Key, N, InList, DeletedL) + end + ). + +prop_keydelete_absent() -> + ?FORALL( + {N, InList}, + {pos_integer(), gen_list()}, + lists:keydelete(make_ref(), N, InList) =:= InList + ). + +%% keyfind/3 +prop_keyfind() -> + ?FORALL( + {Key, N, InList}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3)}, + {K, N, F ++ [E|R]} + ) + ), + begin + Found = lists:keyfind(Key, N, InList), + is_tuple(Found) andalso + tuple_size(Found) >= N andalso + element(N, Found) == Key + end + ). + +prop_keyfind_absent() -> + ?FORALL( + {N, InList}, + {pos_integer(), gen_list()}, + not lists:keyfind(make_ref(), N, InList) + ). + +%% keymap/3 +prop_keymap() -> + ?FORALL( + {MapFn, N, InList, ExpList}, + ?LET( + Fn, + function([gen_any()], gen_any()), + ?LET( + N, + range(1, 5), + ?LET( + {L, M}, + gen_list_fold( + gen_tuple(N, N + 3), + fun(T, Acc) -> + Acc ++ [setelement(N, T, Fn(element(N, T)))] + end, + [] + ), + {Fn, N, L, M} + ) + ) + ), + lists:keymap(MapFn, N, InList) =:= ExpList + ). + +%% keymember/3 +prop_keymember() -> + ?FORALL( + {Key, N, InList}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3)}, + {K, N, F ++ [E|R]} + ) + ), + lists:keymember(Key, N, InList) + ). + +prop_keymember_absent() -> + ?FORALL( + {N, InList}, + {pos_integer(), gen_list()}, + not lists:keymember(make_ref(), N, InList) + ). + +%% keymerge/3 +prop_keymerge() -> + ?FORALL( + {N, InList1, InList2}, + ?LET( + N, + range(1, 5), + ?LET( + {L1, L2}, + {list(gen_tuple(N, N+3)), list(gen_tuple(N, N+3))}, + {N, lists:sort(L1), lists:sort(L2)} + ) + ), + check_merged( + fun (E1, E2) -> element(N, E1) =< element(N, E2) end, + [InList1, InList2], + lists:keymerge(N, InList1, InList2) + ) + ). + +prop_keymerge_invalid() -> + ?FORALL( + {N, InList, X, Y}, + ?LET( + N, + range(1, 5), + ?LET( + {L, X, Y}, + {list(gen_tuple(N, N+3)), non_list(), non_list()}, + {N, L, X, Y} + ) + ), + expect_error(fun lists:keymerge/3, [N, InList, Y]) andalso + expect_error(fun lists:keymerge/3, [N, X, InList]) andalso + expect_error(fun lists:keymerge/3, [N, X, Y]) + ). + +%% keyreplace/4 +prop_keyreplace() -> + ?FORALL( + {Key, N, InList, Replacement}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E0, E1}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3), gen_tuple()}, + {K, N, F ++ [E0|R], E1} + ) + ), + check_keyreplaced(Key, N, Replacement, InList, lists:keyreplace(Key, N, InList, Replacement)) + ). + +prop_keyreplace_absent() -> + ?FORALL( + {N, InList, Replacement}, + {pos_integer(), gen_list(), gen_tuple()}, + lists:keyreplace(make_ref(), N, InList, Replacement) =:= InList + ). + +%% keysearch/3 +prop_keysearch() -> + ?FORALL( + {Key, N, InList}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3)}, + {K, N, F ++ [E|R]} + ) + ), + begin + {value, Found} = lists:keysearch(Key, N, InList), + is_tuple(Found) andalso + tuple_size(Found) >= N andalso + element(N, Found) == Key + end + ). + +prop_keysearch_absent() -> + ?FORALL( + {N, InList}, + {pos_integer(), gen_list()}, + not lists:keysearch(make_ref(), N, InList) + ). + +%% keysort/2 +prop_keysort() -> + ?FORALL( + {N, InList}, + ?LET( + N, + range(1, 5), + {N, list(gen_tuple(N, N + 3))} + ), + begin + Sorted = lists:keysort(N, InList), + length(Sorted) =:= length(InList) andalso + check_sorted(fun(E1, E2) -> element(N, E1) =< element(N, E2) end, InList, Sorted) + end + ). + +%% keystore/4 +prop_keystore() -> + ?FORALL( + {Key, N, InList, ToStore}, + ?LET( + {K, N}, + {gen_any(), range(1, 5)}, + ?LET( + {F, R, E0, E1}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3), gen_tuple()}, + {K, N, F ++ [E0|R], E1} + ) + ), + check_keyreplaced(Key, N, ToStore, InList, lists:keystore(Key, N, InList, ToStore)) + ). + +prop_keystore_absent() -> + ?FORALL( + {N, InList, ToStore}, + {pos_integer(), gen_list(), gen_tuple()}, + lists:keystore(make_ref(), N, InList, ToStore) =:= InList ++ [ToStore] + ). + +%% keytake/3 +prop_keytake() -> + ?FORALL( + {Key, N, InList, ExpList, ExpElem}, + ?LET( + {K, N}, + {make_ref(), range(1, 5)}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_keytuple(K, N, N + 3)}, + {K, N, F ++ [E|R], F ++ R, E} + ) + ), + lists:keytake(Key, N, InList) =:= {value, ExpElem, ExpList} + ). + +prop_keytake_absent() -> + ?FORALL( + {N, InList}, + {pos_integer(), gen_list()}, + lists:keytake(make_ref(), N, InList) =:= false + ). + +%% last/1 +prop_last() -> + ?FORALL( + InList, + gen_list(), + try + lists:last(InList) =:= hd(lists:reverse(InList)) + catch + error:_ -> + InList =:= [] + end + ). + +%% map/2 +prop_map() -> + ?FORALL( + {MapFn, InList, ExpList}, + ?LET( + Fn, + function1(gen_any()), + ?LET( + {L, M}, + gen_list_fold( + gen_any(), + fun(T, Acc) -> + Acc ++ [Fn(T)] + end, + [] + ), + {Fn, L, M} + ) + ), + lists:map(MapFn, InList) =:= ExpList + ). + +%% mapfoldl/3 +prop_mapfoldl() -> + ?FORALL( + {MapFoldFn, InList, Acc0, Exp}, + ?LET( + {MapFn, FoldFn, Acc0}, + {function1(gen_any()), function2(gen_any()), gen_any()}, + ?LET( + {L, MV}, + gen_list_fold( + gen_any(), + fun(T, {AccM, AccF}) -> + {AccM ++ [MapFn(T)], FoldFn(T, AccF)} + end, + {[], Acc0} + ), + {fun(T, Acc) -> {MapFn(T), FoldFn(T, Acc)} end, L, Acc0, MV} + ) + ), + lists:mapfoldl(MapFoldFn, Acc0, InList) =:= Exp + ). + +%% mapfoldr/3 +prop_mapfoldr() -> + ?FORALL( + {MapFoldFn, InList, Acc0, Exp}, + ?LET( + {MapFn, FoldFn, Acc0}, + {function1(gen_any()), function2(gen_any()), gen_any()}, + ?LET( + {L, MV}, + gen_list_fold( + gen_any(), + fun(T, {AccM, AccF}) -> + {[MapFn(T)|AccM], FoldFn(T, AccF)} + end, + {[], Acc0} + ), + {fun(T, Acc) -> {MapFn(T), FoldFn(T, Acc)} end, lists:reverse(L), Acc0, MV} + ) + ), + lists:mapfoldr(MapFoldFn, Acc0, InList) =:= Exp + ). + +%% max/1 +prop_max() -> + ?FORALL( + {InList, ExpMax}, + gen_list_fold(gen_any(), fun erlang:max/2), + try + lists:max(InList) == ExpMax + catch + error:_ -> + InList =:= [] + end + ). + +%% member/2 +prop_member() -> + ?FORALL( + {InList, Member}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_any()}, + {F ++ [E|R], E} + ), + lists:member(Member, InList) + ). + +prop_member_absent() -> + ?FORALL( + InList, + gen_list(), + not lists:member(make_ref(), InList) + ). + +%% merge/1 +prop_merge_1() -> + ?FORALL( + InLists, + list(?LET(L, gen_list(), lists:sort(L))), + check_merged(fun erlang:'=<'/2, InLists, lists:merge(InLists)) + ). + +prop_merge_1_invalid() -> + ?FORALL( + InLists, + ?LET( + {L1, X, L2}, + {list(oneof([non_list(), gen_list()])), non_list(), list(oneof([non_list(), gen_list()]))}, + L1 ++ [X|L2] + ), + expect_error(fun lists:merge/1, [InLists]) + ). + +%% merge/2 +prop_merge_2() -> + ?FORALL( + {InList1, InList2}, + ?LET( + {L1, L2}, + {gen_list(), gen_list()}, + {lists:sort(L1), lists:sort(L2)} + ), + check_merged(fun erlang:'=<'/2, [InList1, InList2], lists:merge(InList1, InList2)) + ). + +prop_merge_2_invalid() -> + ?FORALL( + {InList, X, Y}, + {gen_list(), non_list(), non_list()}, + expect_error(fun lists:merge/2, [InList, X]) andalso + expect_error(fun lists:merge/2, [X, InList]) andalso + expect_error(fun lists:merge/2, [X, Y]) + ). + +%% merge/3 +prop_merge_3() -> + ?FORALL( + {SortFn, InList1, InList2}, + ?LET( + {Fn, L1, L2}, + {gen_ordering_fun(), gen_list(), gen_list()}, + {Fn, lists:sort(Fn, L1), lists:sort(Fn, L2)} + ), + check_merged(SortFn, [InList1, InList2], lists:merge(SortFn, InList1, InList2)) + ). + +prop_merge_3_invalid() -> + ?FORALL( + {SortFn, InList, X, Y}, + {gen_ordering_fun(), gen_list(), non_list(), non_list()}, + expect_error(fun lists:merge/3, [SortFn, InList, Y]) andalso + expect_error(fun lists:merge/3, [SortFn, X, InList]) andalso + expect_error(fun lists:merge/3, [SortFn, X, Y]) + ). + +%% merge3/3 +prop_merge3() -> + ?FORALL( + {InList1, InList2, InList3}, + ?LET( + {L1, L2, L3}, + {gen_list(), gen_list(), gen_list()}, + {lists:sort(L1), lists:sort(L2), lists:sort(L3)} + ), + check_merged(fun erlang:'=<'/2, [InList1, InList2, InList3], lists:merge3(InList1, InList2, InList3)) + ). + +prop_merge3_invalid() -> + ?FORALL( + {InList, X, Y, Z}, + {gen_list(), non_list(), non_list(), non_list()}, + expect_error(fun lists:merge/3, [InList, InList, Z]) andalso + expect_error(fun lists:merge/3, [InList, Y, InList]) andalso + expect_error(fun lists:merge/3, [InList, Y, Z]) andalso + expect_error(fun lists:merge/3, [X, InList, Z]) andalso + expect_error(fun lists:merge/3, [X, Y, InList]) andalso + expect_error(fun lists:merge/3, [X, Y, Z]) + ). + +%% min/1 +prop_min() -> + ?FORALL( + {InList, ExpMin}, + gen_list_fold(gen_any(), fun erlang:min/2), + try + lists:min(InList) == ExpMin + catch + error:_ -> + InList =:= [] + end + ). + +%% nth/2 +prop_nth() -> + ?FORALL( + {InList, N, ExpElem}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), gen_any()}, + {F ++ [E|R], length(F)+1, E} + ), + lists:nth(N, InList) =:= ExpElem + ). + +prop_nth_outofrange() -> + ?FORALL( + {N, InList}, + ?LET( + {L, Offset}, + {gen_list(), pos_integer()}, + {length(L) + Offset, L} + ), + try + lists:nth(N, InList) + of + _ -> + false + catch + error:_ -> + true + end + ). + +%% nthtail/2 +prop_nthtail() -> + ?FORALL( + {InList, N, ExpTail}, + ?LET( + {F, R}, + {gen_list(), gen_list()}, + {F ++ R, length(F), R} + ), + lists:nthtail(N, InList) =:= ExpTail + ). + +prop_nthtail_outofrange() -> + ?FORALL( + {N, InList}, + ?LET( + {L, Offset}, + {gen_list(), pos_integer()}, + {length(L) + Offset, L} + ), + try + lists:nthtail(N, InList) + of + _ -> + false + catch + error:_ -> + true + end + ). + +%% partition/2 +prop_partition() -> + ?FORALL( + {Pred, InList}, + {function1(boolean()), gen_list()}, + begin + {Group1, Group2} = lists:partition(Pred, InList), + check_partitioned(Pred, InList, Group1, Group2) + end + ). + +%% prefix/2 +prop_prefix() -> + ?FORALL( + {InList, Prefix}, + ?LET( + {F, R}, + {gen_list(), gen_list()}, + {F ++ R, F} + ), + lists:prefix(Prefix, InList) andalso + not lists:prefix([make_ref()|Prefix], InList) andalso + not lists:prefix(Prefix ++ [make_ref()], InList) andalso + (not lists:prefix(Prefix, [make_ref()|InList]) orelse Prefix =:= []) + ). + +%% reverse/1 +prop_reverse_1() -> + ?FORALL( + InList, + gen_list(), + check_reversed(InList, lists:reverse(InList)) andalso + lists:reverse(lists:reverse(InList)) =:= InList + ). + +%% reverse/2 +prop_reverse_2() -> + ?FORALL( + {InList, InTail}, + {gen_list(), gen_list()}, + check_reversed(InList, lists:reverse(InList, InTail), InTail) + ). + +%% search/2 +prop_search() -> + ?FORALL( + {Pred, InList, ExpElem}, + ?LET( + {F, R, E}, + {gen_list(), gen_list(), make_ref()}, + {fun(T) -> T =:= E end, F ++ [E|R], E} + ), + lists:search(Pred, InList) =:= {value, ExpElem} + ). + +prop_search_absent() -> + ?FORALL( + InList, + gen_list(), + lists:search(fun(_) -> false end, InList) =:= false + ). + +%% seq/2 +prop_seq2() -> + ?FORALL( + {From, To}, + {integer(), integer()}, + try + lists:seq(From, To) + of + Seq -> + To >= From - 1 andalso + check_seq(Seq, From, To, 1) + catch + error:_ -> + To < From - 1 + end + ). + +%% seq/3 +prop_seq3() -> + ?FORALL( + {From, To, Step}, + {integer(), integer(), integer()}, + try + lists:seq(From, To, Step) + of + Seq when Step > 0 -> + To >= From - Step andalso + check_seq(Seq, From, To, Step); + Seq when Step < 0 -> + To =< From - Step andalso + check_seq(Seq, From, To, Step); + Seq when Step =:= 0 -> + From =:= To andalso + check_seq(Seq, From, To, Step) + catch + error:_ when Step > 0 -> + To < From - Step; + error:_ when Step < 0 -> + To > From - Step; + error:_ when Step =:= 0 -> + From =/= To + end + ). + +%% sort/1 +prop_sort_1() -> + ?FORALL( + InList, + gen_list(), + begin + Sorted = lists:sort(InList), + length(Sorted) =:= length(InList) andalso + check_sorted(InList, Sorted) + end + ). + +%% sort/2 +prop_sort_2() -> + ?FORALL( + {SortFn, InList}, + {gen_ordering_fun(), gen_list()}, + begin + Sorted = lists:sort(SortFn, InList), + length(Sorted) =:= length(InList) andalso + check_sorted(SortFn, InList, Sorted) + end + ). + +%% split/2 +prop_split() -> + ?FORALL( + {N, InList, ExpList1, ExpList2}, + ?LET( + {F, R}, + {gen_list(), gen_list()}, + {length(F), F ++ R, F, R} + ), + lists:split(N, InList) =:= {ExpList1, ExpList2} + ). + +prop_split_outofrange() -> + ?FORALL( + {N, InList}, + ?LET( + {L, Offset}, + {gen_list(), pos_integer()}, + {length(L) + Offset, L} + ), + try + lists:split(N, InList) + of + _ -> + false + catch + error:_ -> + true + end + ). + +%% splitwith/2 +prop_splitwith() -> + ?FORALL( + {Pred, InList}, + {function1(boolean()), gen_list()}, + begin + {Part1, Part2} = lists:splitwith(Pred, InList), + check_splitwithed(Pred, InList, Part1, Part2) + end + ). + +%% sublist/2 +prop_sublist_2() -> + ?FORALL( + {Len, InList, ExpList}, + ?LET( + {F, R}, + {gen_list(), gen_list()}, + {length(F), F ++ R, F} + ), + lists:sublist(InList, Len) =:= ExpList + ). + +%% sublist/3 +prop_sublist_3() -> + ?FORALL( + {Start, Len, InList, ExpList}, + ?LET( + {F, M, R}, + {gen_list(), gen_list(), gen_list()}, + {length(F)+1, length(M), F ++ M ++ R, M} + ), + lists:sublist(InList, Start, Len) =:= ExpList + ). + +%% subtract/2 +prop_subtract() -> + ?FORALL( + {InList, SubtractList}, + ?LET( + {L, B, S}, + {gen_list(), gen_list(), gen_list()}, + {L ++ B, S ++ B} + ), + lists:subtract(InList, SubtractList) =:= InList -- SubtractList + ). + +%% suffix/2 +prop_suffix() -> + ?FORALL( + {InList, Suffix}, + ?LET( + {F, R}, + {gen_list(), gen_list()}, + {F ++ R, R} + ), + lists:suffix(Suffix, InList) andalso + not lists:suffix([make_ref()|Suffix], InList) andalso + not lists:suffix(Suffix ++ [make_ref()], InList) andalso + (not lists:suffix(Suffix, InList ++ [make_ref()]) orelse Suffix =:= []) + ). + +%% sum/1 +prop_sum() -> + ?FORALL( + {InList, ExpSum}, + gen_list_fold(number(), fun erlang:'+'/2, 0), + lists:sum(InList) =:= ExpSum + ). + +%% takewhile/2 +prop_takewhile() -> + ?FORALL( + {Pred, InList, ExpList}, + ?LET( + Fn, + function1(boolean()), + ?LET( + {L, {_, TL}}, + gen_list_fold( + gen_any(), + fun(E, {Take, Acc}) -> + case Take andalso Fn(E) of + true -> {true, Acc ++ [E]}; + false -> {false, Acc} + end + end, + {true, []} + ), + {Fn, L, TL} + ) + ), + lists:takewhile(Pred, InList) =:= ExpList + ). + +%% ukeymerge/3 +prop_ukeymerge() -> + ?FORALL( + {N, InList1, InList2}, + ?LET( + N, + range(1, 5), + ?LET( + {L1, L2}, + {list(gen_tuple(N, N+3)), list(gen_tuple(N, N+3))}, + {N, lists:ukeysort(N, L1), lists:ukeysort(N, L2)} + ) + ), + check_umerged( + fun(E1, E2) -> element(N, E1) =< element(N, E2) end, + [InList1, InList2], + lists:ukeymerge(N, InList1, InList2) + ) + ). + +prop_ukeymerge_invalid() -> + ?FORALL( + {N, InList, X, Y}, + ?LET( + N, + range(1, 5), + ?LET( + {L, X, Y}, + {list(gen_tuple(N, N+3)), non_list(), non_list()}, + {N, L, X, Y} + ) + ), + expect_error(fun lists:ukeymerge/3, [N, InList, Y]) andalso + expect_error(fun lists:ukeymerge/3, [N, X, InList]) andalso + expect_error(fun lists:ukeymerge/3, [N, X, Y]) + ). + +%% ukeysort/2 +prop_ukeysort() -> + ?FORALL( + {N, InList}, + ?LET( + N, + range(1, 5), + {N, list(gen_tuple(N, N + 3))} + ), + begin + Sorted = lists:ukeysort(N, InList), + length(Sorted) =< length(InList) andalso + check_usorted(fun(E1, E2) -> element(N, E1) =< element(N, E2) end, InList, Sorted) + end + ). + +%% umerge/1 +prop_umerge_1() -> + ?FORALL( + InLists, + list(?LET(L, gen_list(), lists:usort(L))), + check_umerged(InLists, lists:umerge(InLists)) + ). + +prop_umerge_1_invalid() -> + ?FORALL( + InList, + ?LET( + {L1, X, L2}, + {list(oneof([non_list(), gen_list()])), non_list(), list(oneof([non_list(), gen_list()]))}, + L1 ++ [X|L2] + ), + expect_error(fun lists:umerge/1, [InList]) + ). + +%% umerge/2 +prop_umerge_2() -> + ?FORALL( + {InList1, InList2}, + ?LET( + {L1, L2}, + {gen_list(), gen_list()}, + {lists:usort(L1), lists:usort(L2)} + ), + check_umerged([InList1, InList2], lists:umerge(InList1, InList2)) + ). + +prop_umerge_2_invalid() -> + ?FORALL( + {InList, X, Y}, + {gen_list(), non_list(), non_list()}, + expect_error(fun lists:umerge/2, [InList, Y]) andalso + expect_error(fun lists:umerge/2, [X, InList]) andalso + expect_error(fun lists:umerge/2, [X, Y]) + ). + +%% umerge/3 +prop_umerge_3() -> + ?FORALL( + {SortFn, InList1, InList2}, + ?LET( + {Fn, L1, L2}, + {gen_ordering_fun(), gen_list(), gen_list()}, + {Fn, lists:usort(Fn, L1), lists:usort(Fn, L2)} + ), + check_umerged(SortFn, [InList1, InList2], lists:umerge(SortFn, InList1, InList2)) + ). + +prop_umerge_3_invalid() -> + ?FORALL( + {SortFn, InList, X, Y}, + {gen_ordering_fun(), gen_list(), non_list(), non_list()}, + expect_error(fun lists:umerge/3, [SortFn, InList, Y]) andalso + expect_error(fun lists:umerge/3, [SortFn, X, InList]) andalso + expect_error(fun lists:umerge/3, [SortFn, X, Y]) + ). + +%% umerge3/3 +prop_umerge3() -> + ?FORALL( + {InList1, InList2, InList3}, + ?LET( + {L1, L2, L3}, + {gen_list(), gen_list(), gen_list()}, + {lists:usort(L1), lists:usort(L2), lists:usort(L3)} + ), + check_umerged([InList1, InList2, InList3], lists:umerge3(InList1, InList2, InList3)) + ). + +prop_umerge3_invalid() -> + ?FORALL( + {InList, X, Y, Z}, + {gen_list(), non_list(), non_list(), non_list()}, + expect_error(fun lists:umerge3/3, [InList, InList, Z]) andalso + expect_error(fun lists:umerge3/3, [InList, Y, InList]) andalso + expect_error(fun lists:umerge3/3, [InList, Y, Z]) andalso + expect_error(fun lists:umerge3/3, [X, InList, InList]) andalso + expect_error(fun lists:umerge3/3, [X, InList, Z]) andalso + expect_error(fun lists:umerge3/3, [X, Y, InList]) andalso + expect_error(fun lists:umerge3/3, [X, Y, Z]) + ). + +%% uniq/1 +prop_uniq_1() -> + ?FORALL( + InList, + ?LET( + {L, M}, + {gen_list(), gen_list()}, + ?LET( + S, + vector(length(L) + 2 * length(M), integer()), + [E || {_, E} <- lists:sort(lists:zip(S, L ++ M ++ M))] + ) + ), + check_uniqed(InList, lists:uniq(InList)) + ). + +%% uniq/2 +prop_uniq_2() -> + ?FORALL( + {UniqFn, InList}, + {function1(oneof([a, b, c])), gen_list()}, + check_uniqed(UniqFn, InList, lists:uniq(UniqFn, InList)) + ). + +%% unzip/1 +prop_unzip() -> + ?FORALL( + {InList, {ExpList1, ExpList2}}, + gen_list_fold( + {gen_any(), gen_any()}, + fun({T1, T2}, {L1, L2}) -> + {L1 ++ [T1], L2 ++ [T2]} + end, + {[], []} + ), + lists:unzip(InList) =:= {ExpList1, ExpList2} + ). + +%% unzip3/1 +prop_unzip3() -> + ?FORALL( + {InList, {ExpList1, ExpList2, ExpList3}}, + gen_list_fold( + {gen_any(), gen_any(), gen_any()}, + fun({T1, T2, T3}, {L1, L2, L3}) -> + {L1 ++ [T1], L2 ++ [T2], L3 ++ [T3]} + end, + {[], [], []} + ), + lists:unzip3(InList) =:= {ExpList1, ExpList2, ExpList3} + ). + +%% usort/1 +prop_usort_1() -> + ?FORALL( + InList, + gen_list(), + begin + Sorted = lists:usort(InList), + length(Sorted) =< length(InList) andalso + check_usorted(InList, Sorted) + end + ). + +%% usort/2 +prop_usort_2() -> + ?FORALL( + {SortFn, InList}, + {gen_ordering_fun(), gen_list()}, + begin + Sorted = lists:usort(SortFn, InList), + length(Sorted) =< length(InList) andalso + check_usorted(SortFn, InList, Sorted) + end + ). + +%% zip/2 +prop_zip_2() -> + ?FORALL( + {ExpList, {InList1, InList2}}, + gen_list_fold( + {gen_any(), gen_any()}, + fun({T1, T2}, {L1, L2}) -> + {L1 ++ [T1], L2 ++ [T2]} + end, + {[], []} + ), + lists:zip(InList1, InList2) =:= ExpList + ). + +%% zip/3 +prop_zip_3() -> + ?FORALL( + {{ExpList, {InList1, InList2}}, ExtraList}, + { + gen_list_fold( + {gen_any(), gen_any()}, + fun({T1, T2}, {L1, L2}) -> + {L1 ++ [T1], L2 ++ [T2]} + end, + {[], []} + ), + non_empty(gen_list()) + }, + begin + Tag = make_ref(), + + Res1 = ExpList =:= lists:zip(InList1, InList2, fail) andalso + ExpList =:= lists:zip(InList1, InList2, trim) andalso + ExpList =:= lists:zip(InList1, InList2, {pad, {Tag, Tag}}), + + Res2 = try lists:zip(InList1, InList2 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip(InList1 ++ ExtraList, InList2, fail) of _ -> false catch error:_ -> true end, + + Res3 = ExpList =:= lists:zip(InList1, InList2 ++ ExtraList, trim) andalso + ExpList =:= lists:zip(InList1 ++ ExtraList, InList2, trim), + + Padded1 = lists:zip(InList1, InList2 ++ ExtraList, {pad, {Tag, Tag}}), + Padded2 = lists:zip(InList1 ++ ExtraList, InList2, {pad, {Tag, Tag}}), + Res4 = Padded1 =:= ExpList ++ [{Tag, X} || X <- ExtraList] andalso + Padded2 =:= ExpList ++ [{X, Tag} || X <- ExtraList], + + Res1 andalso Res2 andalso Res3 andalso Res4 + end + ). + +%% zip3/3 +prop_zip3_3() -> + ?FORALL( + {ExpList, {InList1, InList2, InList3}}, + gen_list_fold( + {gen_any(), gen_any(), gen_any()}, + fun({T1, T2, T3}, {L1, L2, L3}) -> + {L1 ++ [T1], L2 ++ [T2], L3 ++ [T3]} + end, + {[], [], []} + ), + lists:zip3(InList1, InList2, InList3) =:= ExpList + ). + +%% zip3/4 +prop_zip3_4() -> + ?FORALL( + {{ExpList, {InList1, InList2, InList3}}, ExtraList}, + { + gen_list_fold( + {gen_any(), gen_any(), gen_any()}, + fun({T1, T2, T3}, {L1, L2, L3}) -> + {L1 ++ [T1], L2 ++ [T2], L3 ++ [T3]} + end, + {[], [], []} + ), + non_empty(gen_list()) + }, + begin + Tag = make_ref(), + + Res1 = ExpList =:= lists:zip3(InList1, InList2, InList3, fail) andalso + ExpList =:= lists:zip3(InList1, InList2, InList3, trim) andalso + ExpList =:= lists:zip3(InList1, InList2, InList3, {pad, {Tag, Tag, Tag}}), + + Res2 = try lists:zip3(InList1, InList2, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip3(InList1, InList2 ++ ExtraList, InList3, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip3(InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip3(InList1 ++ ExtraList, InList2, InList3, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip3(InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zip3(InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, fail) of _ -> false catch error:_ -> true end, + + Res3 = ExpList =:= lists:zip3(InList1, InList2, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zip3(InList1, InList2 ++ ExtraList, InList3, trim) andalso + ExpList =:= lists:zip3(InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zip3(InList1 ++ ExtraList, InList2, InList3, trim) andalso + ExpList =:= lists:zip3(InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zip3(InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, trim), + + Padded1 = lists:zip3(InList1, InList2, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded2 = lists:zip3(InList1, InList2 ++ ExtraList, InList3, {pad, {Tag, Tag, Tag}}), + Padded3 = lists:zip3(InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded4 = lists:zip3(InList1 ++ ExtraList, InList2, InList3, {pad, {Tag, Tag, Tag}}), + Padded5 = lists:zip3(InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded6 = lists:zip3(InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, {pad, {Tag, Tag, Tag}}), + Res4 = Padded1 =:= ExpList ++ [{Tag, Tag, X} || X <- ExtraList] andalso + Padded2 =:= ExpList ++ [{Tag, X, Tag} || X <- ExtraList] andalso + Padded3 =:= ExpList ++ [{Tag, X, X} || X <- ExtraList] andalso + Padded4 =:= ExpList ++ [{X, Tag, Tag} || X <- ExtraList] andalso + Padded5 =:= ExpList ++ [{X, Tag, X} || X <- ExtraList] andalso + Padded6 =:= ExpList ++ [{X, X, Tag} || X <- ExtraList], + + Res1 andalso Res2 andalso Res3 andalso Res4 + end + ). + +%% zipwith/3 +prop_zipwith_3() -> + ?FORALL( + {ZipFn, InList1, InList2, ExpList}, + ?LET( + Fn, + function2(gen_any()), + ?LET( + {_, {L1, L2, Z}}, + gen_list_fold( + {gen_any(), gen_any()}, + fun({T1, T2}, {L1, L2, Z}) -> + {L1 ++ [T1], L2 ++ [T2], Z ++ [Fn(T1, T2)]} + end, + {[], [], []} + ), + {Fn, L1, L2, Z} + ) + ), + lists:zipwith(ZipFn, InList1, InList2) =:= ExpList + ). + +%% zipwith/4 +prop_zipwith_4() -> + ?FORALL( + {ZipFn, InList1, InList2, ExpList, ExtraList}, + ?LET( + {Extra, Fn}, + {non_empty(gen_list()), function2(gen_any())}, + ?LET( + {_, {L1, L2, Z}}, + gen_list_fold( + {gen_any(), gen_any()}, + fun({T1, T2}, {L1, L2, Z}) -> + {L1 ++ [T1], L2 ++ [T2], Z ++ [Fn(T1, T2)]} + end, + {[], [], []} + ), + {Fn, L1, L2, Z, Extra} + ) + ), + begin + Tag = make_ref(), + + Res1 = ExpList =:= lists:zipwith(ZipFn, InList1, InList2, fail) andalso + ExpList =:= lists:zipwith(ZipFn, InList1, InList2, trim) andalso + ExpList =:= lists:zipwith(ZipFn, InList1, InList2, {pad, {Tag, Tag}}), + + Res2 = try lists:zipwith(ZipFn, InList1, InList2 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith(ZipFn, InList1 ++ ExtraList, InList2, fail) of _ -> false catch error:_ -> true end, + + Res3 = ExpList =:= lists:zipwith(ZipFn, InList1, InList2 ++ ExtraList, trim) andalso + ExpList =:= lists:zipwith(ZipFn, InList1 ++ ExtraList, InList2, trim), + + Padded1 = lists:zipwith(ZipFn, InList1, InList2 ++ ExtraList, {pad, {Tag, Tag}}), + Padded2 = lists:zipwith(ZipFn, InList1 ++ ExtraList, InList2, {pad, {Tag, Tag}}), + Res4 = Padded1 =:= ExpList ++ [ZipFn(Tag, X) || X <- ExtraList] andalso + Padded2 =:= ExpList ++ [ZipFn(X, Tag) || X <- ExtraList], + + Res1 andalso Res2 andalso Res3 andalso Res4 + end + ). + +%% zipwith3/4 +prop_zipwith3_4() -> + ?FORALL( + {ZipFn, InList1, InList2, InList3, ExpList}, + ?LET( + Fn, + function3(gen_any()), + ?LET( + {_, {L1, L2, L3, Z}}, + gen_list_fold( + {gen_any(), gen_any(), gen_any()}, + fun({T1, T2, T3}, {L1, L2, L3, Z}) -> + {L1 ++ [T1], L2 ++ [T2], L3 ++ [T3], Z ++ [Fn(T1, T2, T3)]} + end, + {[], [], [], []} + ), + {Fn, L1, L2, L3, Z} + ) + ), + lists:zipwith3(ZipFn, InList1, InList2, InList3) =:= ExpList + ). + +%% zipwith3/5 +prop_zipwith3_5() -> + ?FORALL( + {ZipFn, InList1, InList2, InList3, ExpList, ExtraList}, + ?LET( + {Extra, Fn}, + {non_empty(gen_list()), function3(gen_any())}, + ?LET( + {_, {L1, L2, L3, Z}}, + gen_list_fold( + {gen_any(), gen_any(), gen_any()}, + fun({T1, T2, T3}, {L1, L2, L3, Z}) -> + {L1 ++ [T1], L2 ++ [T2], L3 ++ [T3], Z ++ [Fn(T1, T2, T3)]} + end, + {[], [], [], []} + ), + {Fn, L1, L2, L3, Z, Extra} + ) + ), + begin + Tag = make_ref(), + + Res1 = ExpList =:= lists:zipwith3(ZipFn, InList1, InList2, InList3, fail) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1, InList2, InList3, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1, InList2, InList3, {pad, {Tag, Tag, Tag}}), + + Res2 = try lists:zipwith3(ZipFn, InList1, InList2, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, fail) of _ -> false catch error:_ -> true end andalso + try lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, fail) of _ -> false catch error:_ -> true end, + + Res3 = ExpList =:= lists:zipwith3(ZipFn, InList1, InList2, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, trim) andalso + ExpList =:= lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, trim), + + Padded1 = lists:zipwith3(ZipFn, InList1, InList2, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded2 = lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3, {pad, {Tag, Tag, Tag}}), + Padded3 = lists:zipwith3(ZipFn, InList1, InList2 ++ ExtraList, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded4 = lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3, {pad, {Tag, Tag, Tag}}), + Padded5 = lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2, InList3 ++ ExtraList, {pad, {Tag, Tag, Tag}}), + Padded6 = lists:zipwith3(ZipFn, InList1 ++ ExtraList, InList2 ++ ExtraList, InList3, {pad, {Tag, Tag, Tag}}), + Res4 = Padded1 =:= ExpList ++ [ZipFn(Tag, Tag, X) || X <- ExtraList] andalso + Padded2 =:= ExpList ++ [ZipFn(Tag, X, Tag) || X <- ExtraList] andalso + Padded3 =:= ExpList ++ [ZipFn(Tag, X, X) || X <- ExtraList] andalso + Padded4 =:= ExpList ++ [ZipFn(X, Tag, Tag) || X <- ExtraList] andalso + Padded5 =:= ExpList ++ [ZipFn(X, Tag, X) || X <- ExtraList] andalso + Padded6 =:= ExpList ++ [ZipFn(X, X, Tag) || X <- ExtraList], + + Res1 andalso Res2 andalso Res3 andalso Res4 + end + ). + +%%%%%%%%%%%%%%%%%% +%%% Generators %%% +%%%%%%%%%%%%%%%%%% + +non_list() -> + ?SUCHTHAT(NonList, gen_any(), not is_list(NonList)). + +%% Generator for lists of the given type, folding the given function +%% over values on the top level as they are generated. The first generated +%% value serves as the initial accumulator. +gen_list_fold(Gen, FoldFn) -> + ?SIZED( + Size, + ?LET( + T, + Gen, + if + Size =< 1 -> + {[], T}; + true -> + gen_list_fold(max(0, Size - 1), Gen, [T], FoldFn, T) + end + ) + ). + +%% Generator for lists of the given type, folding the given function +%% over values on the top level as they are generated. +gen_list_fold(Gen, FoldFn, Acc0) -> + ?SIZED( + Size, + gen_list_fold(max(0, Size - 1), Gen, [], FoldFn, Acc0) + ). + +gen_list_fold(0, _Gen, L, _FoldFn, Acc) -> + {L, Acc}; +gen_list_fold(N, Gen, L, FoldFn, Acc) -> + ?LET( + E, + Gen, + gen_list_fold(N - 1, Gen, L ++ [E], FoldFn, FoldFn(E, Acc)) + ). + +%% Generator for key tuples of the given size, +%% with the given key in the given (ie, last) position. +gen_keytuple(Key, Size) -> + gen_keytuple(Key, Size, Size). + +%% Generator for key tuples of the given minimum and maximum +%% sizes, with the given key in the given minimum position. +gen_keytuple(Key, MinSize, MaxSize) -> + ?LET( + Tuple, + gen_tuple(MinSize, MaxSize), + setelement(MinSize, Tuple, Key) + ). + +%% Generator for tuples of random size. +gen_tuple() -> + ?LET( + N, + non_neg_integer(), + gen_tuple(N) + ). + +%% Generator for tuples of the given size. +gen_tuple(Size) -> + ?LET( + V, + vector(Size, gen_any()), + list_to_tuple(V) + ). + +%% Generator for tuples of the given minimum and +%% maximum sizes. +gen_tuple(MinSize, MaxSize) -> + ?LET( + N, + range(MinSize, MaxSize), + ?LET( + V, + vector(N, gen_any()), + list_to_tuple(V) + ) + ). + +%% Generator for lists of anything. +gen_list() -> + list(gen_any()). + +%% Generator for lists of anything, folding the given function +%% over values on all levels of list-nesting as they are generated. +gen_list_deepfold(FoldFn, Acc0) -> + ?SIZED( + Size, + ?LET( + {_, L, Acc}, + gen_list_deepfold(max(0, Size - 1), 0, [], FoldFn, Acc0), + {L, Acc} + ) + ). + +gen_list_deepfold(N, _Level, L, _FoldFn, Acc) when N =< 0 -> + {N, lists:reverse(L), Acc}; +gen_list_deepfold(N, Level, L, FoldFn, Acc) -> + ?LET( + X, + frequency([ + {4, {term, gen_any_simple()}}, + {1, deeplist}, + {1, tuple}, + {2, stop} + ]), + case X of + deeplist -> + ?LET( + {N1, L1, Acc1}, + gen_list_deepfold(N, Level + 1, [], FoldFn, Acc), + gen_list_deepfold(N1, Level, [L1|L], FoldFn, Acc1) + ); + tuple -> + ?LET( + {N1, L1, _}, + gen_list_deepfold(N, Level + 1, [], fun(_, _, _) -> undefined end, undefined), + begin + E = list_to_tuple(L1), + gen_list_deepfold(N1, Level, [E|L], FoldFn, FoldFn(Level, E, Acc)) + end + ); + stop -> + {N, lists:reverse(L), Acc}; + {term, E} -> + gen_list_deepfold(N - 1, Level, [E|L], FoldFn, FoldFn(Level, E, Acc)) + end + ). + +%% Generator for simple and composite (lists and tuples) types. +gen_any() -> + frequency( + [ + {4, gen_any_simple()}, + {1, ?LET({L, _}, gen_list_deepfold(fun(_, _, Acc) -> Acc end, undefined), L)}, + {1, ?LET({L, _}, gen_list_deepfold(fun(_, _, Acc) -> Acc end, undefined), list_to_tuple(L))} + ] + ). + +%% Generator for simple types: +%% - atoms +%% - integers +%% - floats +%% - bitstrings +gen_any_simple() -> + oneof([gen_atom(), integer(), float(), bitstring()]). + +%% Generator for interesting atoms: +%% - well-known atoms like `ok', `undefined', `infinity'... +%% - randomly generated "weird" atoms +gen_atom() -> + oneof( + [ + oneof([ok, error, true, false, undefined, infinity]), + oneof(['', '"', '\'', '(', ')', '()', '[', '[', '[]', '{', '}', '{}']), + gen_random_atom() + ] + ). + +%% Generator for a limited set of random atoms. The number of +%% atoms that will be generated is set in `?RANDOM_ATOMS'. +gen_random_atom() -> + ?LAZY( + ?LET( + N, + range(1, ?RANDOM_ATOMS), + try + persistent_term:get({?MODULE, random_atoms}) + of + Atoms -> + maps:get(N, Atoms) + catch + error:badarg -> + ?LET( + AtomsList, + vector(?RANDOM_ATOMS, ?SIZED(Size, resize(Size * 100, atom()))), + begin + Fn = fun + F(_, [], Acc) -> + Acc; + F(Index, [A|As], Acc) -> + F(Index + 1, As, Acc#{Index => A}) + end, + Atoms = Fn(1, AtomsList, #{}), + persistent_term:put({?MODULE, random_atoms}, Atoms), + maps:get(N, Atoms) + end + ) + end + ) + ). + +%% Generator for ordering functions, to be used for sorting and merging. +%% The generated ordering functions are designed to fulfill the requirements given +%% at the top of the `lists' documentation, namely to be antisymmetric, transitive, +%% and total. Further, the chances that two terms compare equal, less or greater +%% are equal. +gen_ordering_fun() -> + ?LET( + F, + function1(range(1, 3)), + fun(T1, T2) -> + F(T1) =< F(T2) + end + ). + +%%%%%%%%%%%%%%% +%%% Helpers %%% +%%%%%%%%%%%%%%% + +%% -------------------------------------------------------------------- +expect_error(Fn, Args) when is_function(Fn, length(Args))-> + try + erlang:apply(Fn, Args) + of + _ -> false + catch + error:_ -> true; + _:_ -> false + end. + +%% -------------------------------------------------------------------- +check_appended([], []) -> + true; +check_appended([[]|Ls], AL) -> + check_appended(Ls, AL); +check_appended([L], AL) -> + L =:= AL; +check_appended([[E1|L]|Ls], [E2|AL]) -> + E1 =:= E2 andalso + check_appended([L|Ls], AL); +check_appended(_Ls, _AL) -> + false. + +%% -------------------------------------------------------------------- +check_deleted(E, [E|L], DL) -> + L =:= DL; +check_deleted(E, [_|L], [_|DL]) -> + check_deleted(E, L, DL); +check_deleted(_E, [], []) -> + true; +check_deleted(_E, _L, _DL) -> + false. + +%% -------------------------------------------------------------------- +check_joined(Sep, [E|L], [E, Sep|JL]) -> + check_joined(Sep, L, JL); +check_joined(_Sep, [E], [E]) -> + true; +check_joined(_Sep, [], []) -> + true; +check_joined(_Sep, _L, _JL) -> + false. + +%% -------------------------------------------------------------------- +check_keydeleted(K, N, [E|L], KDL) when element(N, E) == K -> + L =:= KDL; +check_keydeleted(K, N, [_|L], [_|KDL]) -> + check_keydeleted(K, N, L, KDL); +check_keydeleted(_K, _N, _L, _KDL) -> + false. + +%% -------------------------------------------------------------------- +check_keyreplaced(K, N, R, [E1|L], [E2|KRL]) when element(N, E1) == K -> + E2 =:= R andalso L =:= KRL; +check_keyreplaced(K, N, R, [_|L], [_|KRL]) -> + check_keyreplaced(K, N, R, L, KRL); +check_keyreplaced(_K, _N, _R, _L, _KRL) -> + false. + +%% -------------------------------------------------------------------- +check_merged(Ls, ML) -> + check_merged(fun erlang:'=<'/2, Ls, ML). + +check_merged(Fn, [[]|Ls], ML) -> + check_merged(Fn, Ls, ML); +check_merged(_Fn, [], ML) -> + ML =:= []; +check_merged(_Fn, [L], ML) -> + ML =:= L; +check_merged(Fn, Ls, [E|ML]) -> + case find_in_heads(Fn, E, Ls) of + {true, Ls1} -> + check_merged(Fn, Ls1, ML); + false -> + false + end; +check_merged(_Fn, _Ls, _ML) -> + false. + +find_in_heads(Fn, E, Ls) -> + find_in_heads(Fn, E, Ls, []). + +find_in_heads(Fn, E, [[]|Ls], Seen) -> + find_in_heads(Fn, E, Ls, Seen); +find_in_heads(Fn, E, [[E1|LRest]=L|Ls], Seen) -> + case Fn(E, E1) andalso Fn(E1, E) of + true -> + {true, lists:reverse(Seen, [LRest|Ls])}; + false -> + find_in_heads(Fn, E, Ls, [L|Seen]) + end; +find_in_heads(_Fn, _E, _Ls, _Seen) -> + false. + +%% -------------------------------------------------------------------- +check_partitioned(Pred, [E|L], P1, P2) -> + case {Pred(E), P1, P2} of + {true, [E|Rest], _} -> + check_partitioned(Pred, L, Rest, P2); + {false, _, [E|Rest]} -> + check_partitioned(Pred, L, P1, Rest); + _ -> + false + end; +check_partitioned(_Pred, [], [], []) -> + true; +check_partitioned(_Pred, _L, _P1, _P2) -> + false. + +%% -------------------------------------------------------------------- +check_reversed(L1, L2) -> + check_reversed(L1, L2, []). + +check_reversed(L1, L2, Tail) -> + check_reversed1(L1, L2) =:= Tail. + +check_reversed1([], L2) -> + L2; +check_reversed1([E|L1], L2) -> + case check_reversed1(L1, L2) of + [E|L2Rest] -> L2Rest; + _ -> false + end. + +%% -------------------------------------------------------------------- +check_seq([F|Seq], F, T, S) -> + check_seq(Seq, F + S, T, S); +check_seq([], F, T, S) when S >= 0 -> + F >= T; +check_seq([], F, T, S) when S < 0 -> + F =< T; +check_seq(_Seq, _F, _T, _S) -> + false. + +%% -------------------------------------------------------------------- +check_sorted(L, Sorted) -> + check_sorted(fun erlang:'=<'/2, L, Sorted). + +check_sorted(SortFun, L, Sorted) -> + ExpElems = count_elems(L), + check_sorted(SortFun, Sorted, ExpElems, #{}). + +check_sorted(_SortFun, [], ExpElems, FoundElems) -> + ExpElems =:= FoundElems; +check_sorted(SortFun, [E], ExpElems, FoundElems) -> + maps:is_key(E, ExpElems) andalso + check_sorted(SortFun, [], ExpElems, maps:update_with(E, fun(Cnt) -> Cnt + 1 end, 1, FoundElems)); +check_sorted(SortFun, [E1|[E2|_]=L], ExpElems, FoundElems) -> + SortFun(E1, E2) andalso + maps:is_key(E1, ExpElems) andalso + check_sorted(SortFun, L, ExpElems, maps:update_with(E1, fun(Cnt) -> Cnt + 1 end, 1, FoundElems)); +check_sorted(_SortFun, _L, _ExpElems, _FoundElems) -> + false. + +count_elems(L) -> + count_elems(L, #{}). + +count_elems([E|Es], Acc) -> + count_elems(Es, maps:update_with(E, fun(Cnt) -> Cnt + 1 end, 1, Acc)); +count_elems([], Acc) -> + Acc. + +%% -------------------------------------------------------------------- +check_splitwithed(Pred, [E|L], [E|P1], P2) -> + Pred(E) andalso + check_splitwithed(Pred, L, P1, P2); +check_splitwithed(Pred, [E|_]=L, [], P2) -> + not Pred(E) andalso L =:= P2; +check_splitwithed(_Pred, [], [], []) -> + true; +check_splitwithed(_Pred, _L, _P1, _P2) -> + false. + +%% -------------------------------------------------------------------- +check_umerged(Ls, ML) -> + check_umerged(fun erlang:'=<'/2, Ls, ML). + +check_umerged(Fn, [[]|Ls], ML) -> + check_umerged(Fn, Ls, ML); +check_umerged(_Fn, [L], ML) -> + ML =:= L; +check_umerged(_Fn, [], ML) -> + ML =:= []; +check_umerged(Fn, Ls, [E|ML]) -> + case find_and_remove_from_heads(Fn, E, Ls) of + {true, Ls1} -> + check_umerged(Fn, Ls1, ML); + false -> + false + end; +check_umerged(_Fn, _Ls, _ML) -> + false. + +find_and_remove_from_heads(Fn, E, Ls) -> + find_and_remove_from_heads(false, Fn, E, Ls, []). + +find_and_remove_from_heads(Found, Fn, E, [[]|Ls], Seen) -> + find_and_remove_from_heads(Found, Fn, E, Ls, Seen); +find_and_remove_from_heads(false, _Fn, _E, [], _Seen) -> + false; +find_and_remove_from_heads(true, _Fn, _E, [], Seen) -> + {true, lists:reverse(Seen)}; +find_and_remove_from_heads(Found, Fn, E, [[E1|LRest]=L|Ls], Seen) -> + case Fn(E, E1) andalso Fn(E1, E) of + true -> + find_and_remove_from_heads(true, Fn, E, Ls, [LRest|Seen]); + false -> + find_and_remove_from_heads(Found, Fn, E, Ls, [L|Seen]) + end. + +%% -------------------------------------------------------------------- +check_uniqed(L, UL) -> + check_uniqed(fun(X) -> X end, L, UL). + +check_uniqed(Fn, L, UL) -> + check_uniqed1(Fn, L, UL, sets:new([{version, 2}])). + +check_uniqed1(Fn, [E|L], [], Seen) -> + sets:is_element(Fn(E), Seen) andalso + check_uniqed1(Fn, L, [], Seen); +check_uniqed1(Fn, [E1|L], [E2|URest]=U, Seen) -> + X1 = Fn(E1), + X2 = Fn(E2), + case sets:is_element(X1, Seen) of + true -> + X1 =/= X2 andalso + check_uniqed1(Fn, L, U, Seen); + false -> + X1 =:= X2 andalso + check_uniqed1(Fn, L, URest, sets:add_element(X1, Seen)) + end; +check_uniqed1(_Fn, [], [], _Seen) -> + true; +check_uniqed1(_Fn, _L, _UL, _Seen) -> + false. + +%% -------------------------------------------------------------------- +check_usorted(L, Sorted) -> + check_usorted(fun erlang:'=<'/2, L, Sorted). + +check_usorted(SortFun, L, Sorted) -> + ExpElems = ucount_elems(SortFun, L), + check_sorted(SortFun, Sorted, ExpElems, #{}). + +ucount_elems(SortFun, L) -> + ucount_elems(SortFun, L, #{}). + +ucount_elems(SortFun, [E|Es], Acc) -> + K = ufind_key(SortFun, E, maps:keys(Acc)), + ucount_elems(SortFun, Es, maps:put(K, 1, Acc)); +ucount_elems(_SortFun, [], Acc) -> + Acc. + +ufind_key(SortFun, E, [K|Keys]) -> + case SortFun(E, K) andalso SortFun(K, E) of + true -> + K; + false -> + ufind_key(SortFun, E, Keys) + end; +ufind_key(_SortFun, E, []) -> + E. diff --git a/lib/stdlib/test/property_test/queue_prop.erl b/lib/stdlib/test/property_test/queue_prop.erl new file mode 100644 index 000000000000..03372d2aab20 --- /dev/null +++ b/lib/stdlib/test/property_test/queue_prop.erl @@ -0,0 +1,898 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(queue_prop). + +-compile(export_all). + +-proptest(eqc). +-proptest([triq, proper]). + +-ifndef(EQC). +-ifndef(PROPER). +-ifndef(TRIQ). +-define(EQC, true). +-endif. +-endif. +-endif. + +-ifdef(EQC). +-include_lib("eqc/include/eqc.hrl"). +-define(MOD_eqc,eqc). + +-else. +-ifdef(PROPER). +-include_lib("proper/include/proper.hrl"). +-define(MOD_eqc,proper). + +-else. +-ifdef(TRIQ). +-define(MOD_eqc,triq). +-include_lib("triq/include/triq.hrl"). + +-endif. +-endif. +-endif. + +%%%%%%%%%%%%%%%%%% +%%% Properties %%% +%%%%%%%%%%%%%%%%%% + +prop_new() -> + [] =:= queue:to_list(queue:new()). + +prop_is_queue() -> + ?FORALL( + {IsQueue, Q}, + oneof([ + {true, queue()}, + {false, non_queue()} + ]), + begin + IsQueue =:= queue:is_queue(Q) + end + ). + +prop_list_conversion() -> + ?FORALL( + List, + list(), + begin + Queue = queue:from_list(List), + queue:is_queue(Queue) andalso + List =:= queue:to_list(Queue) + end + ). + +prop_from_list_invalid() -> + ?FORALL( + NonList, + ?SUCHTHAT(T, term(), not is_list(T)), + expect_badarg(fun queue:from_list/1, [NonList]) + ). + +prop_to_list_invalid() -> + common_invalid(fun queue:to_list/1). + +prop_all() -> + ?FORALL( + {L, Q}, + oneof([list_queue(atom()), list_queue(term())]), + begin + lists:all(fun is_atom/1, L) =:= queue:all(fun is_atom/1, Q) + end + ). + +prop_all_invalid() -> + common_invalid_pred(fun queue:all/2). + +prop_any() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + lists:any(fun is_atom/1, L) =:= queue:any(fun is_atom/1, Q) + end + ). + +prop_any_invalid() -> + common_invalid_pred(fun queue:any/2). + +prop_cons() -> + common_in_r_cons(fun queue:cons/2). + +prop_cons_invalid() -> + common_invalid_term(fun queue:cons/2). + +prop_daeh() -> + common_get_r_last_daeh(fun queue:daeh/1). + +prop_daeh_invalid() -> + common_invalid(fun queue:daeh/1). + +prop_delete() -> + ?FORALL( + {X, {L, Q}}, + {term(), list_queue()}, + begin + R1 = if + L =:= [] -> + true; + true -> + Y = lists:nth(rand:uniform(length(L)), L), + equal(lists:delete(Y, L), queue:delete(Y, Q)) + end, + R2 = equal(lists:delete(X, L), queue:delete(X, Q)), + + R1 andalso R2 + end + ). + +prop_delete_invalid() -> + common_invalid_term(fun queue:delete/2). + +prop_delete_r() -> + ?FORALL( + {X, {L, Q}}, + {term(), list_queue()}, + begin + R1 = if + L =:= [] -> + true; + true -> + Y = lists:nth(rand:uniform(length(L)), L), + equal(lists:reverse(lists:delete(Y, lists:reverse(L))), queue:delete_r(Y, Q)) + end, + R2 = equal(lists:reverse(lists:delete(X, lists:reverse(L))), queue:delete_r(X, Q)), + + R1 andalso R2 + end + ). + +prop_delete_r_invalid() -> + common_invalid_term(fun queue:delete_r/2). + +prop_delete_with() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + Q1 = queue:delete_with(fun is_atom/1, Q), + L1 = case lists:search(fun is_atom/1, L) of + false -> + L; + {value, V} -> + lists:delete(V, L) + end, + equal(L1, Q1) + end + ). + +prop_delete_with_invalid() -> + common_invalid_pred(fun queue:delete_with/2). + +prop_delete_with_r() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + Q1 = queue:delete_with_r(fun is_atom/1, Q), + L1 = lists:reverse(L), + L2 = case lists:search(fun is_atom/1, L1) of + false -> + L; + {value, V} -> + lists:reverse(lists:delete(V, L1)) + end, + equal(L2, Q1) + end + ). + +prop_delete_with_r_invalid() -> + common_invalid_pred(fun queue:delete_with_r/2). + +prop_drop() -> + common_drop_tail(fun queue:drop/1). + +prop_drop_invalid() -> + common_invalid(fun queue:drop/1). + +prop_drop_r() -> + common_drop_r_init_liat(fun queue:drop_r/1). + +prop_drop_r_invalid() -> + common_invalid(fun queue:drop_r/1). + +prop_filter() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + Q1 = queue:filter( + fun + (I) when is_atom(I) -> true; + (I) when is_integer(I) -> [I * 2]; + (I) when is_float(I) -> [{I, I}]; + (I) when is_tuple(I) -> [I, I]; + (_) -> false + end, + Q + ), + L1 = lists:foldr( + fun + (I, Acc) when is_atom(I) -> [I|Acc]; + (I, Acc) when is_integer(I) -> [I * 2|Acc]; + (I, Acc) when is_float(I) -> [{I, I}|Acc]; + (I, Acc) when is_tuple(I) -> [I, I|Acc]; + (_, Acc) -> Acc + end, + [], + L + ), + equal(L1, Q1) + end + ). + +prop_filter_invalid() -> + common_invalid_pred(fun queue:filter/2). + +prop_filtermap() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + F = fun + (I) when is_atom(I) -> + true; + (I) when is_integer(I) -> + {true, {I, I}}; + (_) -> + false + end, + Q1 = queue:filtermap(F, Q), + L1 = lists:filtermap(F, L), + equal(L1, Q1) + end + ). + +prop_filtermap_invalid() -> + common_invalid_pred(fun queue:filtermap/2). + +prop_fold() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + % order-independent fold + F1 = fun + (I, Acc) when is_number(I) -> Acc + 2 * I; + (_, Acc) -> Acc + end, + RQ1 = queue:fold(F1, 0, Q), + RL1 = lists:foldl(F1, 0, L), + + % order-dependent fold + F2 = fun + (I, Acc) -> [{I, I}|Acc] + end, + RQ2 = queue:fold(F2, [], Q), + RL2 = lists:foldl(F2, [], L), + + RQ1 =:= RL1 andalso + RQ2 =:= RL2 + end + ). + +prop_fold_invalid() -> + ?FORALL( + {Q, Fn}, + oneof([{non_queue(), fun erlang:'+'/2}, {queue(), non_fun(2)}, {non_queue(), non_fun(2)}]), + expect_badarg(fun queue:fold/3, [Fn, 0, Q]) + ). + +prop_get() -> + common_get_head(fun queue:get/1). + +prop_get_invalid() -> + common_invalid(fun queue:get/1). + +prop_get_r() -> + common_get_r_last_daeh(fun queue:get_r/1). + +prop_get_r_invalid() -> + common_invalid(fun queue:get_r/1). + +prop_head() -> + common_get_head(fun queue:head/1). + +prop_head_invalid() -> + common_invalid(fun queue:head/1). + +prop_in() -> + ?FORALL( + L, + list(), + begin + Q = lists:foldl( + fun(I, Acc) -> + queue:in(I, Acc) + end, + queue:new(), + L + ), + equal(L, Q) + end + ). + +prop_in_invalid() -> + common_invalid_term(fun queue:in/2). + +prop_in_r() -> + common_in_r_cons(fun queue:in_r/2). + +prop_in_r_invalid() -> + common_invalid_term(fun queue:in_r/2). + +prop_init() -> + common_drop_r_init_liat(fun queue:init/1). + +prop_init_invalid() -> + common_invalid(fun queue:init/1). + +prop_is_empty() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + (length(L) =:= 0) =:= queue:is_empty(Q) + end + ). + +prop_is_empty_invalid() -> + common_invalid(fun queue:is_empty/1). + +prop_join() -> + ?FORALL( + {{L1, Q1}, {L2, Q2}}, + {list_queue(), list_queue()}, + begin + equal(L1 ++ L2, queue:join(Q1, Q2)) + end + ). + +prop_join_invalid() -> + ?FORALL( + {Q1, Q2}, + oneof([{non_queue(), queue()}, {queue(), non_queue()}, {non_queue(), non_queue()}]), + expect_badarg(fun queue:join/2, [Q1, Q2]) + ). + +prop_last() -> + common_get_r_last_daeh(fun queue:last/1). + +prop_last_invalid() -> + common_invalid(fun queue:last/1). + +prop_len() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + length(L) =:= queue:len(Q) + end + ). + +prop_len_invalid() -> + common_invalid(fun queue:len/1). + +prop_liat() -> + common_drop_r_init_liat(fun queue:liat/1). + +prop_liat_invalid() -> + common_invalid(fun queue:liat/1). + +prop_member() -> + ?FORALL( + {X, {L, Q}}, + {term(), list_queue()}, + begin + % all members of L are members of Q + lists:all( + fun(I) -> + queue:member(I, Q) + end, + L + ) + andalso + % all members of Q are members of L + lists:all( + fun(I) -> + lists:member(I, L) + end, + queue:to_list(Q) + ) + andalso + % if X is a member of L, it is also a member of Q, + % and if X is not a member of L, it is also not a + % member of Q + lists:member(X, L) =:= queue:member(X, Q) + end + ). + +prop_member_invalid() -> + common_invalid_term(fun queue:member/2). + +prop_out() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + case queue:out(Q) of + {{value, I}, Q1} -> + I =:= hd(L) andalso + equal(tl(L), Q1); + {empty, Q1} -> + L =:= [] andalso + equal(L, Q1) + end + end + ). + +prop_out_invalid() -> + common_invalid(fun queue:out/1). + +prop_out_r() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + case queue:out_r(Q) of + {{value, I}, Q1} -> + L1 = lists:reverse(L), + I =:= hd(L1) andalso + equal(lists:reverse(tl(L1)), Q1); + {empty, Q1} -> + L =:= [] andalso + equal(L, Q1) + end + end + ). + +prop_out_r_invalid() -> + common_invalid(fun queue:out_r/1). + +prop_peek() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + case queue:peek(Q) of + {value, I} -> + I =:= hd(L); + empty -> + L =:= [] + end + end + ). + +prop_peek_invalid() -> + common_invalid(fun queue:peek/1). + +prop_peek_r() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + case queue:peek_r(Q) of + {value, I} -> + I =:= lists:last(L); + empty -> + L =:= [] + end + end + ). + +prop_peek_r_invalid() -> + common_invalid(fun queue:peek_r/1). + +prop_reverse() -> + ?FORALL( + {L, Q}, + list_queue(), + begin + equal(lists:reverse(L), queue:reverse(Q)) + end + ). + +prop_reverse_invalid() -> + common_invalid(fun queue:reverse/1). + +prop_snoc() -> + ?FORALL( + L, + list(), + begin + Q = lists:foldl( + fun(I, Acc) -> + queue:snoc(Acc, I) + end, + queue:new(), + L + ), + equal(L, Q) + end + ). + +prop_snoc_invalid() -> + ?FORALL( + {I, NonQueue}, + {term(), non_queue()}, + expect_badarg(fun queue:snoc/2, [NonQueue, I]) + ). + +prop_split() -> + ?FORALL( + {N, {L, Q}}, + {non_neg_integer(), list_queue()}, + begin + N1 = N rem (length(L) + 1), + {Q1, Q2} = queue:split(N1, Q), + {L1, L2} = lists:split(N1, L), + + equal(L1, Q1) andalso + equal(L2, Q2) + end + ). + +prop_split_invalid() -> + ?FORALL( + {Q, N}, + oneof( + [ + {non_queue(), 0}, + ?SUCHTHAT( + {Q1, N1}, + {queue(), term()}, + not(is_integer(N1) andalso N1>=0 andalso N1= + common_drop_tail(fun queue:tail/1). + +prop_tail_invalid() -> + common_invalid(fun queue:tail/1). + +% Test sequences of insert and retrieval operations +prop_ops() -> + ?FORALL( + {Ops, {L, Q}}, + { + list( + oneof([{cons, term()}, + daeh, + drop, + drop_r, + get, + get_r, + head, + {in, term()}, + {in_r, term()}, + init, + liat, + last, + out, + out_r, + peek, + peek_r, + {snoc, term()}, + tail]) + ), + list_queue() + }, + do_ops(Ops, L, Q) + ). + +%% Executes the given sequence of queue operations on a model (list) +%% and a queue and compares the returned items (if any) as well as +%% the model and queue. +do_ops([], L, Q) -> + equal(L, Q); +do_ops([Op|Ops], L0, Q0) -> + {LItem, L1} = do_op_list(Op, L0), + {QItem, Q1} = do_op_queue(Op, Q0), + + LItem =:= QItem andalso + equal(L1, Q1) andalso + do_ops(Ops, L1, Q1). + +list_op_map() -> + % Inserts item at the rear; affects only the model list, returns no value + InsertRearOp = fun(I, L) -> {undefined, L ++ [I]} end, + % Inserts item at the front; affects only the model list, returns no value + InsertFrontOp = fun(I, L) -> {undefined, [I|L]} end, + + % Helper for functions that should return empty when the model list is empty + MaybeEmpty = fun(F) -> fun([]) -> {empty, []}; (L) -> F(L) end end, + + % For functions that both affect the model list and return a value + TakeOp = fun(VF, QF) -> fun(L) -> {{value, VF(L)}, QF(L)} end end, + + % For functions that do not affect the model list but return a value + ValueOp = fun(F) -> fun(L) -> {{value, F(L)}, L} end end, + + % For functions that affect the model list and do not return a value + QueueOp = fun(F) -> fun(L) -> {undefined, F(L)} end end, + + #{ + in => InsertRearOp, + in_r => InsertFrontOp, + cons => InsertFrontOp, + snoc => InsertRearOp, + out => MaybeEmpty(TakeOp(fun erlang:hd/1, fun erlang:tl/1)), + out_r => MaybeEmpty(TakeOp(fun lists:last/1, fun lists:droplast/1)), + peek => MaybeEmpty(ValueOp(fun erlang:hd/1)), + peek_r => MaybeEmpty(ValueOp(fun lists:last/1)), + get => MaybeEmpty(ValueOp(fun erlang:hd/1)), + get_r => MaybeEmpty(ValueOp(fun lists:last/1)), + head => MaybeEmpty(ValueOp(fun erlang:hd/1)), + daeh => MaybeEmpty(ValueOp(fun lists:last/1)), + last => MaybeEmpty(ValueOp(fun lists:last/1)), + init => MaybeEmpty(QueueOp(fun lists:droplast/1)), + drop => MaybeEmpty(QueueOp(fun erlang:tl/1)), + drop_r => MaybeEmpty(QueueOp(fun lists:droplast/1)), + tail => MaybeEmpty(QueueOp(fun erlang:tl/1)), + liat => MaybeEmpty(QueueOp(fun lists:droplast/1)) + }. + +do_op_list({Op, I}, L) -> + F = maps:get(Op, list_op_map()), + F(I, L); +do_op_list(Op, L) -> + F = maps:get(Op, list_op_map()), + F(L). + +queue_op_map() -> + % Helper for swapping arguments + SwapArgs = fun(F) -> fun(X, Y) -> F(Y, X) end end, + + % For functions that affect the queue but do not return a value + QueueOp1 = fun(F) -> fun(Q) -> {undefined, F(Q)} end end, + QueueOp2 = fun(F) -> fun(I, Q) -> {undefined, F(I, Q)} end end, + + % For functions that return a value wrapped in a tuple + WrappedReturn = fun(F) -> fun(Q) -> {F(Q), Q} end end, + + % For functions that return an unwrapped value + PlainReturn = fun(F) -> fun(Q) -> {{value, F(Q)}, Q} end end, + + % Helper for functions that raise an error when used on + % an empty queue + CatchEmpty = fun(F) -> + fun(Q) -> + try F(Q) catch error:empty -> {empty, Q} end + end + end, + + #{ + in => QueueOp2(fun queue:in/2), + in_r => QueueOp2(fun queue:in_r/2), + cons => QueueOp2(fun queue:cons/2), + snoc => QueueOp2(SwapArgs(fun queue:snoc/2)), + out => fun queue:out/1, + out_r => fun queue:out_r/1, + peek => WrappedReturn(fun queue:peek/1), + peek_r => WrappedReturn(fun queue:peek_r/1), + get => CatchEmpty(PlainReturn(fun queue:get/1)), + get_r => CatchEmpty(PlainReturn(fun queue:get_r/1)), + head => CatchEmpty(PlainReturn(fun queue:head/1)), + daeh => CatchEmpty(PlainReturn(fun queue:daeh/1)), + last => CatchEmpty(PlainReturn(fun queue:last/1)), + init => CatchEmpty(QueueOp1(fun queue:init/1)), + drop => CatchEmpty(QueueOp1(fun queue:drop/1)), + drop_r => CatchEmpty(QueueOp1(fun queue:drop_r/1)), + tail => CatchEmpty(QueueOp1(fun queue:tail/1)), + liat => CatchEmpty(QueueOp1(fun queue:liat/1)) + }. + +do_op_queue({Op, I}, Q) -> + F = maps:get(Op, queue_op_map()), + F(I, Q); +do_op_queue(Op, Q) -> + F = maps:get(Op, queue_op_map()), + F(Q). + +%%%%%%%%%%%%%%%%%%%%%%%% +%%% Property helpers %%% +%%%%%%%%%%%%%%%%%%%%%%%% + +% get/1 and head/1 have the same semantics +common_get_head(Fn) -> + ?FORALL( + {L, Q}, + list_queue(), + try + Fn(Q) + of E -> + E =:= hd(L) + catch error:empty -> + L =:= [] + end + ). + +% get_r/1, last/1 and daeh/1 have the same semantics +common_get_r_last_daeh(Fn) -> + ?FORALL( + {L, Q}, + list_queue(), + try + Fn(Q) + of E -> + E =:= lists:last(L) + catch error:empty -> + L =:= [] + end + ). + +% drop_r/1, init/1 and liat/1 have the same semantics +common_drop_r_init_liat(Fn) -> + ?FORALL( + {L, Q}, + list_queue(), + try + Fn(Q) + of Q1 -> + equal(lists:droplast(L), Q1) + catch error:empty -> + L =:= [] + end + ). + +% drop/1 and tail/1 have the same semantics +common_drop_tail(Fn) -> + ?FORALL( + {L, Q}, + list_queue(), + try + Fn(Q) + of Q1 -> + equal(tl(L), Q1) + catch error:empty -> + L =:= [] + end + ). + +% in_r/2 and cons/2 have the same semantics +common_in_r_cons(Fn) -> + ?FORALL( + L, + list(), + begin + Q = lists:foldl( + fun(I, Acc) -> + Fn(I, Acc) + end, + queue:new(), + L + ), + equal(lists:reverse(L), Q) + end + ). + +common_invalid(Fn) -> + ?FORALL( + NonQueue, + non_queue(), + expect_badarg(Fn, [NonQueue]) + ). + +common_invalid_pred(Fn) -> + ?FORALL( + {Q, Pred}, + oneof([{non_queue(), fun is_atom/1}, {queue(), non_fun(1)}, {non_queue(), non_fun(1)}]), + expect_badarg(Fn, [Pred, Q]) + ). + +common_invalid_term(Fn) -> + ?FORALL( + {I, NonQueue}, + {term(), non_queue()}, + expect_badarg(Fn, [I, NonQueue]) + ). + +%%%%%%%%%%%%%%%%%% +%%% Generators %%% +%%%%%%%%%%%%%%%%%% + +list_queue() -> + list_queue(term()). + +list_queue(Type) -> + ?LET( + {List1, List2}, + {list(Type), list(Type)}, + begin + Queue=lists:foldl( + fun(X, Acc) -> queue:in(X, Acc) end, + queue:from_list(List1), + List2 + ), + {List1 ++ List2, Queue} + end + ). + +queue() -> + queue(term()). + +queue(Type) -> + ?LET(List, list(Type), queue:from_list(List)). + +%% This generator produces terms that are not queues. +%% +%% Therefore, it relies on knowledge of the internal representation +%% of queues (at the time of this writing, a tuple of two lists) in +%% order to prevent accidential generation of a queue. +%% +%% If the internal representation of queues ever changes, this +%% generator has to be changed to reflect this. +non_queue() -> + ?SUCHTHAT( + T, + term(), + not( + is_tuple(T) andalso + tuple_size(T) =:= 2 andalso + is_list(element(1, T)) andalso + is_list(element(2, T)) + ) + ). + +non_fun(Arity) -> + ?SUCHTHAT( + T, + term(), + not is_function(T, Arity) + ). + +%%%%%%%%%%%%%%% +%%% Helpers %%% +%%%%%%%%%%%%%%% + +% Check equality of lists and/or queues, +% ie that they contain the same items in +% the same order. +equal(L1, L2) when is_list(L1), is_list(L2) -> + L1 =:= L2; +equal(Q, L) when is_list(L) -> + equal(queue:to_list(Q), L); +equal(L, Q) -> + equal(L, queue:to_list(Q)). + +expect_badarg(Fn, Args) when is_function(Fn, length(Args)) -> + try + erlang:apply(Fn, Args) + of + _ -> false + catch + error:badarg -> true; + _:_ -> false + end. diff --git a/lib/stdlib/test/property_test/uri_string_recompose.erl b/lib/stdlib/test/property_test/uri_string_recompose.erl index 1720ea78d3b0..4f37e4aa9c12 100644 --- a/lib/stdlib/test/property_test/uri_string_recompose.erl +++ b/lib/stdlib/test/property_test/uri_string_recompose.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -84,7 +84,7 @@ prop_recompose() -> Map =:= uri_string:parse(uri_string:recompose(Map))). prop_normalize() -> - ?FORALL(Map, map(), + ?FORALL(Map, property_map(), uri_string:percent_decode( uri_string:normalize(Map, [return_map])) =:= uri_string:percent_decode( @@ -94,11 +94,11 @@ prop_normalize() -> %% Stats prop_map_key_length_collect() -> - ?FORALL(List, map(), + ?FORALL(List, property_map(), collect(length(maps:keys(List)), true)). prop_map_collect() -> - ?FORALL(List, map(), + ?FORALL(List, property_map(), collect(lists:sort(maps:keys(List)), true)). prop_scheme_collect() -> @@ -110,7 +110,7 @@ prop_scheme_collect() -> %%% Generators %%%======================================================================== -map() -> +property_map() -> ?LET(Gen, comp_proplist(), proplist_to_map(Gen)). map_no_unicode() -> diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index cb4e710c44c0..2e1b722b8efd 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2023. 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. @@ -401,6 +401,7 @@ nomatch(Config) when is_list(Config) -> %% {warnings,[{{3,52},qlc,nomatch_pattern}]}}, {warnings,[{{3,37},v3_core,{nomatch,pattern}}]}}, + %% No longer illegal in OTP 26. {nomatch4, <<"nomatch() -> etsc(fun(E) -> @@ -411,7 +412,7 @@ nomatch(Config) when is_list(Config) -> end, [{<<34>>},{<<40>>}]). ">>, [], - {errors,[{{3,48},erl_lint,illegal_bin_pattern}],[]}}, + []}, {nomatch5, <<"nomatch() -> @@ -1163,9 +1164,9 @@ append(Config) when is_list(Config) -> evaluator(Config) when is_list(Config) -> true = is_alive(), evaluator_2(Config, []), - {ok, Node} = start_node(qlc_SUITE_evaluator), + {ok, Peer, Node} = ?CT_PEER(), ok = rpc:call(Node, ?MODULE, evaluator_2, [Config, [compiler]]), - test_server:stop_node(Node), + peer:stop(Peer), ok. evaluator_2(Config, Apps) -> @@ -1191,10 +1192,6 @@ evaluator_2(Config, Apps) -> _ = file:delete(FileName), ok. -start_node(Name) -> - PA = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, slave, [{args, "-pa " ++ PA}]). - %% string_to_handle/1,2. string_to_handle(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch qlc:string_to_handle(14)), @@ -2636,9 +2633,9 @@ info(Config) when is_list(Config) -> L = [{#{k => #{v => Fun}}, Fun}], H = qlc:q([Q || Q <- L, Q =:= {#{k => #{v => Fun}}, Fun}]), L = qlc:e(H), - {call,_,_,[{lc,_,{var,_,'Q'}, - [{generate,_,_,_}, - {op,_,_,_,_}]}]} = + {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}}, + [_, + {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_compile}},[_]}]} = qlc:info(H, [{format,abstract_code}])">> ], @@ -6560,15 +6557,15 @@ otp_7114(Config) when is_list(Config) -> %% OTP-7232. qlc:info() bug (pids, ports, refs, funs). otp_7232(Config) when is_list(Config) -> - Ts = [<<"L = [fun math:sqrt/1, list_to_pid(\"<0.4.1>\"), + Ts = [<<"L = [fun math:sqrt/1, list_to_pid(\"<0.4.0>\"), erlang:make_ref()], - \"[fun math:sqrt/1, <0.4.1>, #Ref<\" ++ _ = qlc:info(L), + \"[fun math:sqrt/1, <0.4.0>, #Ref<\" ++ _ = qlc:info(L), {call,_, {remote,_,{atom,_,qlc},{atom,_,sort}}, [{cons,_, {'fun',_,{function,{atom,_,math},{atom,_,sqrt},_}}, {cons,_, - {string,_,\"<0.4.1>\"}, % could use list_to_pid.. + {string,_,\"<0.4.0>\"}, % could use list_to_pid.. {cons,_,{string,_,\"#Ref<\"++_},{nil,_}}}}, {nil,_}]} = qlc:info(qlc:sort(L),{format,abstract_code})">>, @@ -7470,10 +7467,10 @@ etsc(F, Opts, Objs) -> V. join_info(H) -> - {{qlc, S, Options}, Bs} = strip_qlc_call2(H), + {qlc, S, Options} = strip_qlc_call(H), %% "Hide" the call to qlc_pt from the test in run_test(). LoadedPT = code:is_loaded(qlc_pt), - QH = qlc:string_to_handle(S, Options, Bs), + QH = qlc:string_to_handle(S, Options, []), _ = [unload_pt() || false <- [LoadedPT]], % doesn't take long... case {join_info_count(H), join_info_count(QH)} of {N, N} -> @@ -7483,26 +7480,22 @@ join_info(H) -> end. strip_qlc_call(H) -> - {Expr, _Bs} = strip_qlc_call2(H), - Expr. - -strip_qlc_call2(H) -> S = qlc:info(H, {flat, false}), {ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]), - {ok, [Expr], Bs} = erl_eval:extended_parse_exprs(Tokens), - {case Expr of - {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} -> - {qlc, lists:flatten([erl_pp:expr(LC), "."]), []}; - {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC, Opts]} -> - {qlc, lists:flatten([erl_pp:expr(LC), "."]), - erl_parse:normalise(Opts)}; - {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} -> - {match_spec, Expr}; - {call,_,{remote,_,{atom,_,M},{atom,_,table}},_} -> - {table, M, Expr}; - _ -> - [] - end, Bs}. + {ok, [Expr]} = erl_eval:extended_parse_exprs(Tokens), + case Expr of + {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} -> + {qlc, lists:flatten([erl_pp:expr(LC), "."]), []}; + {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC, Opts]} -> + {qlc, lists:flatten([erl_pp:expr(LC), "."]), + erl_parse:normalise(Opts)}; + {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} -> + {match_spec, Expr}; + {call,_,{remote,_,{atom,_,M},{atom,_,table}},_} -> + {table, M, Expr}; + _ -> + [] + end. -record(ji, {nmerge = 0, nlookup = 0, nnested_loop = 0, nkeysort = 0}). @@ -7510,7 +7503,7 @@ strip_qlc_call2(H) -> join_info_count(H) -> S = qlc:info(H, {flat, false}), {ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]), - {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens), + {ok, [Expr]} = erl_eval:extended_parse_exprs(Tokens), #ji{nmerge = Nmerge, nlookup = Nlookup, nkeysort = NKeysort, nnested_loop = Nnested_loop} = ji(Expr, #ji{}), @@ -7554,7 +7547,7 @@ lookup_keys({generate,_,Q}, L) -> lookup_keys(Q, L); lookup_keys({table,Chars}, L) when is_list(Chars) -> {ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++"."), 1, [text]), - {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens), + {ok, [Expr]} = erl_eval:extended_parse_exprs(Tokens), case Expr of {call,_,_,[_fun,AKs]} -> case erl_parse:normalise(AKs) of diff --git a/lib/stdlib/test/queue_property_test_SUITE.erl b/lib/stdlib/test/queue_property_test_SUITE.erl new file mode 100644 index 000000000000..497e8c5fd80d --- /dev/null +++ b/lib/stdlib/test/queue_property_test_SUITE.erl @@ -0,0 +1,327 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2021-2022. 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(queue_property_test_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-compile(export_all). + +all() -> [ + new_case, + is_queue_case, + list_conversion_case, + from_list_invalid_case, + to_list_invalid_case, + + all_case, + all_invalid_case, + any_case, + any_invalid_case, + cons_case, + cons_invalid_case, + daeh_case, + daeh_invalid_case, + delete_case, + delete_invalid_case, + delete_r_case, + delete_r_invalid_case, + delete_with_case, + delete_with_invalid_case, + delete_with_r_case, + delete_with_r_invalid_case, + drop_case, + drop_invalid_case, + drop_r_case, + drop_r_invalid_case, + filter_case, + filter_invalid_case, + filtermap_case, + filtermap_invalid_case, + fold_case, + fold_invalid_case, + get_case, + get_invalid_case, + get_r_case, + get_r_invalid_case, + head_case, + head_invalid_case, + in_case, + in_invalid_case, + in_r_case, + in_r_invalid_case, + init_case, + init_invalid_case, + is_empty_case, + is_empty_invalid_case, + join_case, + join_invalid_case, + last_case, + last_invalid_case, + len_case, + len_invalid_case, + liat_case, + liat_invalid_case, + member_case, + member_invalid_case, + out_case, + out_invalid_case, + out_r_case, + out_r_invalid_case, + peek_case, + peek_invalid_case, + peek_r_case, + peek_r_invalid_case, + reverse_case, + reverse_invalid_case, + snoc_case, + snoc_invalid_case, + split_case, + split_invalid_case, + tail_case, + tail_invalid_case, + + ops_case + ]. + +init_per_suite(Config) -> + ct_property_test:init_per_suite(Config). + +end_per_suite(Config) -> + Config. + +new_case(Config) -> + do_proptest(prop_new, Config). + +is_queue_case(Config) -> + do_proptest(prop_is_queue, Config). + +list_conversion_case(Config) -> + do_proptest(prop_list_conversion, Config). + +from_list_invalid_case(Config) -> + do_proptest(prop_from_list_invalid, Config). + +to_list_invalid_case(Config) -> + do_proptest(prop_to_list_invalid, Config). + +all_case(Config) -> + do_proptest(prop_all, Config). + +all_invalid_case(Config) -> + do_proptest(prop_all_invalid, Config). + +any_case(Config) -> + do_proptest(prop_any, Config). + +any_invalid_case(Config) -> + do_proptest(prop_any_invalid, Config). + +cons_case(Config) -> + do_proptest(prop_cons, Config). + +cons_invalid_case(Config) -> + do_proptest(prop_cons_invalid, Config). + +daeh_case(Config) -> + do_proptest(prop_daeh, Config). + +daeh_invalid_case(Config) -> + do_proptest(prop_daeh_invalid, Config). + +delete_case(Config) -> + do_proptest(prop_delete, Config). + +delete_invalid_case(Config) -> + do_proptest(prop_delete_invalid, Config). + +delete_r_case(Config) -> + do_proptest(prop_delete_r, Config). + +delete_r_invalid_case(Config) -> + do_proptest(prop_delete_r_invalid, Config). + +delete_with_case(Config) -> + do_proptest(prop_delete_with, Config). + +delete_with_invalid_case(Config) -> + do_proptest(prop_delete_with_invalid, Config). + +delete_with_r_case(Config) -> + do_proptest(prop_delete_with_r, Config). + +delete_with_r_invalid_case(Config) -> + do_proptest(prop_delete_with_r_invalid, Config). + +drop_case(Config) -> + do_proptest(prop_drop, Config). + +drop_invalid_case(Config) -> + do_proptest(prop_drop_invalid, Config). + +drop_r_case(Config) -> + do_proptest(prop_drop_r, Config). + +drop_r_invalid_case(Config) -> + do_proptest(prop_drop_r_invalid, Config). + +filter_case(Config) -> + do_proptest(prop_filter, Config). + +filter_invalid_case(Config) -> + do_proptest(prop_filter_invalid, Config). + +filtermap_case(Config) -> + do_proptest(prop_filtermap, Config). + +filtermap_invalid_case(Config) -> + do_proptest(prop_filtermap_invalid, Config). + +fold_case(Config) -> + do_proptest(prop_fold, Config). + +fold_invalid_case(Config) -> + do_proptest(prop_fold_invalid, Config). + +get_case(Config) -> + do_proptest(prop_get, Config). + +get_invalid_case(Config) -> + do_proptest(prop_get_invalid, Config). + +get_r_case(Config) -> + do_proptest(prop_get_r, Config). + +get_r_invalid_case(Config) -> + do_proptest(prop_get_r_invalid, Config). + +head_case(Config) -> + do_proptest(prop_head, Config). + +head_invalid_case(Config) -> + do_proptest(prop_head_invalid, Config). + +in_case(Config) -> + do_proptest(prop_in, Config). + +in_invalid_case(Config) -> + do_proptest(prop_in_invalid, Config). + +in_r_case(Config) -> + do_proptest(prop_in_r, Config). + +in_r_invalid_case(Config) -> + do_proptest(prop_in_r_invalid, Config). + +init_case(Config) -> + do_proptest(prop_init, Config). + +init_invalid_case(Config) -> + do_proptest(prop_init_invalid, Config). + +is_empty_case(Config) -> + do_proptest(prop_is_empty, Config). + +is_empty_invalid_case(Config) -> + do_proptest(prop_is_empty_invalid, Config). + +join_case(Config) -> + do_proptest(prop_join, Config). + +join_invalid_case(Config) -> + do_proptest(prop_join_invalid, Config). + +last_case(Config) -> + do_proptest(prop_last, Config). + +last_invalid_case(Config) -> + do_proptest(prop_last_invalid, Config). + +len_case(Config) -> + do_proptest(prop_len, Config). + +len_invalid_case(Config) -> + do_proptest(prop_len_invalid, Config). + +liat_case(Config) -> + do_proptest(prop_liat, Config). + +liat_invalid_case(Config) -> + do_proptest(prop_liat_invalid, Config). + +member_case(Config) -> + do_proptest(prop_member, Config). + +member_invalid_case(Config) -> + do_proptest(prop_member_invalid, Config). + +out_case(Config) -> + do_proptest(prop_out, Config). + +out_invalid_case(Config) -> + do_proptest(prop_out_invalid, Config). + +out_r_case(Config) -> + do_proptest(prop_out_r, Config). + +out_r_invalid_case(Config) -> + do_proptest(prop_out_r_invalid, Config). + +peek_case(Config) -> + do_proptest(prop_peek, Config). + +peek_invalid_case(Config) -> + do_proptest(prop_peek_invalid, Config). + +peek_r_case(Config) -> + do_proptest(prop_peek_r, Config). + +peek_r_invalid_case(Config) -> + do_proptest(prop_peek_r_invalid, Config). + +reverse_case(Config) -> + do_proptest(prop_reverse, Config). + +reverse_invalid_case(Config) -> + do_proptest(prop_reverse_invalid, Config). + +snoc_case(Config) -> + do_proptest(prop_snoc, Config). + +snoc_invalid_case(Config) -> + do_proptest(prop_snoc_invalid, Config). + +split_case(Config) -> + do_proptest(prop_split, Config). + +split_invalid_case(Config) -> + do_proptest(prop_split_invalid, Config). + +tail_case(Config) -> + do_proptest(prop_tail, Config). + +tail_invalid_case(Config) -> + do_proptest(prop_tail_invalid, Config). + +ops_case(Config) -> + do_proptest(prop_ops, Config). + +do_proptest(Prop, Config) -> + ct_property_test:quickcheck( + queue_prop:Prop(), + Config). diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl index 207cff00e5ab..11722fd060a7 100644 --- a/lib/stdlib/test/rand_SUITE.erl +++ b/lib/stdlib/test/rand_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2020. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -35,6 +35,9 @@ all() -> [seed, interval_int, interval_float, bytes_count, api_eq, + mwc59_api, + exsp_next_api, exsp_jump_api, + splitmix64_next_api, reference, {group, basic_stats}, {group, distr_stats}, @@ -205,6 +208,106 @@ api_eq_1(S00) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Verify mwc59 behaviour +%% +mwc59_api(Config) when is_list(Config) -> + try rand:mwc59_seed(-1) of + CX1 -> + error({bad_return, CX1}) + catch + error : function_clause -> + try rand:mwc59_seed(1 bsl 58) of + CX2 -> + error({bad_return, CX2}) + catch + error : function_clause -> + Seed = 11213862807209314, + Seed = rand:mwc59_seed(1), + mwc59_api(Seed, 1000000) + end + end. + +mwc59_api(CX0, 0) -> + CX = 182322083224642863, + {CX, CX} = {CX0, CX}, + V0 = rand:mwc59_value32(CX0), + V = 2905950767, + {V, V} = {V0, V}, + W0 = rand:mwc59_value(CX0), + W = 269866568368142303, + {W, W} = {W0, W}, + F0 = rand:mwc59_float(CX0), + F = (W band ((1 bsl 53)-1)) * (1 / (1 bsl 53)), + {F, F} = {F0, F}, + ok; +mwc59_api(CX, N) + when is_integer(CX), 1 =< CX, CX < (16#7fa6502 bsl 32) - 1 -> + V = rand:mwc59_value32(CX), + W = rand:mwc59_value(CX), + F = rand:mwc59_float(CX), + true = 0 =< V, + true = V < 1 bsl 32, + true = 0 =< W, + true = W < 1 bsl 59, + true = 0.0 =< F, + true = F < 1.0, + mwc59_api(rand:mwc59(CX), N - 1). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Verify exsp_next behaviour +%% +exsp_next_api(Config) when is_list(Config) -> + {_, AlgState} = State = rand:seed_s(exsp, 87654321), + exsp_next_api(State, AlgState, 1000000). + +exsp_next_api(_State, _AlgState, 0) -> + ok; +exsp_next_api(State, AlgState, N) -> + {X, NewState} = rand:uniform_s(1 bsl 58, State), + {Y, NewAlgState} = rand:exsp_next(AlgState), + Y1 = Y + 1, + {X, X, N} = {Y1, X, N}, + exsp_next_api(NewState, NewAlgState, N - 1). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Verify exsp_jump behaviour +%% +exsp_jump_api(Config) when is_list(Config) -> + {_, AlgState} = State = rand:seed_s(exsp, 12345678), + exsp_jump_api(State, AlgState, 10000). + +exsp_jump_api(_State, _AlgState, 0) -> + ok; +exsp_jump_api(State, AlgState, N) -> + {X, NewState} = rand:uniform_s(1 bsl 58, State), + {Y, NewAlgState} = rand:exsp_next(AlgState), + Y1 = Y + 1, + {X, X, N} = {Y1, X, N}, + exsp_jump_api( + rand:jump(NewState), + rand:exsp_jump(NewAlgState), + N - 1). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Verify splitmix64_next behaviour +%% +splitmix64_next_api(Config) when is_list(Config) -> + splitmix64_next_api(55555555, 100000, 0). + +splitmix64_next_api(_State, 0, X) -> + X0 = 13069087632117122295, + {X0, X0} = {X, X0}, + ok; +splitmix64_next_api(AlgState, N, X) + when is_integer(X), 0 =< X, X < 1 bsl 64 -> + {X1, NewAlgState} = rand:splitmix64_next(AlgState), + splitmix64_next_api(NewAlgState, N - 1, X1). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Check that uniform/1 returns values within the proper interval. interval_int(Config) when is_list(Config) -> Algs = [default|algs()], @@ -350,21 +453,35 @@ gen(_, _, _, Acc) -> lists:reverse(Acc). basic_stats_uniform_1(Config) when is_list(Config) -> ct:timetrap({minutes,15}), %% valgrind needs a lot of time - [basic_uniform_1(?LOOP, rand:seed_s(Alg), 0.0, array:new([{default, 0}])) - || Alg <- [default|algs()]], + Result = + lists:filter( + fun (R) -> R =/= [] end, + [basic_uniform_1(Alg, ?LOOP, 100) + || Alg <- [default|algs()]]), + Result =:= [] orelse + ct:fail(Result), ok. basic_stats_uniform_2(Config) when is_list(Config) -> ct:timetrap({minutes,15}), %% valgrind needs a lot of time - [basic_uniform_2(?LOOP, rand:seed_s(Alg), 0, array:new([{default, 0}])) - || Alg <- [default|algs()]], + Result = + lists:filter( + fun (R) -> R =/= [] end, + [basic_uniform_2(Alg, ?LOOP, 100) + || Alg <- [default|algs()]]), + Result =:= [] orelse + ct:fail(Result), ok. basic_stats_bytes(Config) when is_list(Config) -> ct:timetrap({minutes,15}), %% valgrind needs a lot of time - [basic_bytes( - ?LOOP div 100, rand:seed_s(Alg), 0, array:new(256, [{default, 0}])) - || Alg <- [default|algs()]], + Result = + lists:filter( + fun (R) -> R =/= [] end, + [basic_bytes(Alg, ?LOOP div 100, 113) + || Alg <- [default|algs()]]), + Result =:= [] orelse + ct:fail(Result), ok. basic_stats_standard_normal(Config) when is_list(Config) -> @@ -372,9 +489,14 @@ basic_stats_standard_normal(Config) when is_list(Config) -> io:format("Testing standard normal~n",[]), IntendedMean = 0, IntendedVariance = 1, - [basic_normal_1(?LOOP, IntendedMean, IntendedVariance, - rand:seed_s(Alg), 0, 0) - || Alg <- [default|algs()]], + Result = + lists:filter( + fun (R) -> R =/= [] end, + [basic_normal_1(?LOOP, IntendedMean, IntendedVariance, + rand:seed_s(Alg), 0, 0) + || Alg <- [default|algs()]]), + Result =:= [] orelse + ct:fail(Result), ok. basic_stats_normal(Config) when is_list(Config) -> @@ -385,20 +507,32 @@ basic_stats_normal(Config) when is_list(Config) -> [{Mean, Variance} || Mean <- IntendedMeans, Variance <- IntendedVariances], - ct:timetrap({minutes, 6 * length(IntendedMeanVariancePairs)}), %% valgrind needs a lot of time - lists:foreach( - fun ({IntendedMean, IntendedVariance}) -> - ct:pal( - "Testing normal(~.2f, ~.2f)~n", - [float(IntendedMean), float(IntendedVariance)]), - [basic_normal_1(?LOOP, IntendedMean, IntendedVariance, - rand:seed_s(Alg), 0, 0) - || Alg <- [default|algs()]] - end, - IntendedMeanVariancePairs). - - -basic_uniform_1(N, S0, Sum, A0) when N > 0 -> + %% valgrind needs a lot of time + ct:timetrap({minutes, 6 * length(IntendedMeanVariancePairs)}), + Result = + lists:filter( + fun (R) -> R =/= [] end, + [begin + ct:pal( + "Testing normal(~.2f, ~.2f)~n", + [float(IntendedMean), float(IntendedVariance)]), + lists:filter( + fun (R) -> R =/= [] end, + [basic_normal_1(?LOOP, IntendedMean, IntendedVariance, + rand:seed_s(Alg), 0, 0) + || Alg <- [default|algs()]]) + end || {IntendedMean, IntendedVariance} + <- IntendedMeanVariancePairs]), + Result =:= [] orelse + ct:fail(Result), + ok. + +basic_uniform_1(Alg, Loop, Buckets) -> + basic_uniform_1( + 0, Loop, Buckets, rand:seed_s(Alg), 0.0, + array:new(Buckets, [{default, 0}])). +%% +basic_uniform_1(N, Loop, Buckets, S0, Sum, A0) when N < Loop -> {X,S} = case N band 1 of 0 -> @@ -406,45 +540,41 @@ basic_uniform_1(N, S0, Sum, A0) when N > 0 -> 1 -> rand:uniform_real_s(S0) end, - I = trunc(X*100), + I = trunc(X*Buckets), A = array:set(I, 1+array:get(I,A0), A0), - basic_uniform_1(N-1, S, Sum+X, A); -basic_uniform_1(0, {#{type:=Alg}, _}, Sum, A) -> - Loop = ?LOOP, + basic_uniform_1(N+1, Loop, Buckets, S, Sum+X, A); +basic_uniform_1(_N, Loop, Buckets, {#{type:=Alg}, _}, Sum, A) -> AverExp = 1.0 / 2, - Buckets = 100, Counters = array:to_list(A), - Min = lists:min(Counters), - Max = lists:max(Counters), - basic_verify(Alg, Loop, Sum, AverExp, Buckets, Min, Max). + basic_verify(Alg, Loop, Sum, AverExp, Buckets, Counters). -basic_uniform_2(N, S0, Sum, A0) when N > 0 -> - {X,S} = rand:uniform_s(100, S0), +basic_uniform_2(Alg, Loop, Buckets) -> + basic_uniform_2( + 0, Loop, Buckets, rand:seed_s(Alg), 0, + array:new(Buckets, [ {default, 0}])). +%% +basic_uniform_2(N, Loop, Buckets, S0, Sum, A0) when N < Loop -> + {X,S} = rand:uniform_s(Buckets, S0), A = array:set(X-1, 1+array:get(X-1,A0), A0), - basic_uniform_2(N-1, S, Sum+X, A); -basic_uniform_2(0, {#{type:=Alg}, _}, Sum, A) -> - Loop = ?LOOP, - AverExp = ((100 - 1) / 2) + 1, - Buckets = 100, + basic_uniform_2(N+1, Loop, Buckets, S, Sum+X, A); +basic_uniform_2(_N, Loop, Buckets, {#{type:=Alg}, _}, Sum, A) -> + AverExp = ((Buckets - 1) / 2) + 1, Counters = tl(array:to_list(A)), - Min = lists:min(Counters), - Max = lists:max(Counters), - basic_verify(Alg, Loop, Sum, AverExp, Buckets, Min, Max). - -basic_bytes(N, S0, Sum0, A0) when N > 0 -> - ByteSize = 100, - {Bin,S} = rand:bytes_s(ByteSize, S0), + basic_verify(Alg, Loop, Sum, AverExp, Buckets, Counters). + +basic_bytes(Alg, Loop, BytesSize) -> + basic_bytes( + 0, Loop, BytesSize, rand:seed_s(Alg), 0, + array:new(256, [{default, 0}])). +basic_bytes(N, Loop, BytesSize, S0, Sum0, A0) when N < Loop -> + {Bin,S} = rand:bytes_s(BytesSize, S0), {Sum,A} = basic_bytes_incr(Bin, Sum0, A0), - basic_bytes(N-1, S, Sum, A); -basic_bytes(0, {#{type:=Alg}, _}, Sum, A) -> - ByteSize = 100, - Loop = (?LOOP * ByteSize) div 100, + basic_bytes(N+1, Loop, BytesSize, S, Sum, A); +basic_bytes(_N, Loop, BytesSize, {#{type:=Alg}, _}, Sum, A) -> Buckets = 256, AverExp = (Buckets - 1) / 2, Counters = array:to_list(A), - Min = lists:min(Counters), - Max = lists:max(Counters), - basic_verify(Alg, Loop, Sum, AverExp, Buckets, Min, Max). + basic_verify(Alg, Loop * BytesSize, Sum, AverExp, Buckets, Counters). basic_bytes_incr(Bin, Sum, A) -> basic_bytes_incr(Bin, Sum, A, 0). @@ -458,7 +588,7 @@ basic_bytes_incr(Bin, Sum, A, N) -> {Sum,A} end. -basic_verify(Alg, Loop, Sum, AverExp, Buckets, Min, Max) -> +basic_verify(Alg, Loop, Sum, AverExp, Buckets, Counters) -> AverDiff = AverExp * 0.01, Aver = Sum / Loop, io:format( @@ -467,19 +597,39 @@ basic_verify(Alg, Loop, Sum, AverExp, Buckets, Min, Max) -> %% CountExp = Loop / Buckets, CountDiff = CountExp * 0.1, + {MinBucket, Min} = lists_where(fun erlang:min/2, Counters), + {MaxBucket, Max} = lists_where(fun erlang:max/2, Counters), io:format( "~.12w: Expected Count: ~p, Allowed Diff: ~p, Min: ~p, Max: ~p~n", [Alg, CountExp, CountDiff, Min, Max]), %% %% Verify that the basic statistics are ok - %% be gentle we don't want to see to many failing tests - abs(Aver - AverExp) < AverDiff orelse - ct:fail({average, Alg, Aver, AverExp, AverDiff}), - abs(Min - CountExp) < CountDiff orelse - ct:fail({min, Alg, Min, CountExp, CountDiff}), - abs(Max - CountExp) < CountDiff orelse - ct:fail({max, Alg, Max, CountExp, CountDiff}), - ok. + %% be gentle - we don't want to see to many failing tests + if + abs(Aver - AverExp) < AverDiff -> []; + true -> [{average, Alg, Aver, AverExp, AverDiff}] + end ++ + if + abs(Min - CountExp) < CountDiff -> []; + true -> [{min, Alg, {MinBucket,Min}, CountExp, CountDiff}] + end ++ + if + abs(Max - CountExp) < CountDiff -> []; + true -> [{max, Alg, {MaxBucket,Max}, CountExp, CountDiff}] + end. + +lists_where(Fun, [X | L]) -> + lists_where(Fun, L, 2, 1, X). +%% +lists_where(_Fun, [], _N, Where, What) -> + {Where, What}; +lists_where(Fun, [X | L], N, Where, What) -> + case Fun(X, What) of + What -> + lists_where(Fun, L, N+1, Where, What); + X -> + lists_where(Fun, L, N+1, N, X) + end. basic_normal_1(N, IntendedMean, IntendedVariance, S0, StandardSum, StandardSq) when N > 0 -> @@ -491,7 +641,7 @@ basic_normal_1(N, IntendedMean, IntendedVariance, S0, StandardSum, StandardSq) w StandardX = (X - IntendedMean) / math:sqrt(IntendedVariance), basic_normal_1(N-1, IntendedMean, IntendedVariance, S, StandardX+StandardSum, StandardX*StandardX+StandardSq); -basic_normal_1(0, _IntendedMean, _IntendedVariance, {#{type:=Alg}, _}, StandardSum, StandardSumSq) -> +basic_normal_1(0, IntendedMean, IntendedVariance, {#{type:=Alg}, _}, StandardSum, StandardSumSq) -> StandardMean = StandardSum / ?LOOP, StandardVariance = (StandardSumSq - (StandardSum*StandardSum/?LOOP))/(?LOOP - 1), StandardStdDev = math:sqrt(StandardVariance), @@ -500,9 +650,16 @@ basic_normal_1(0, _IntendedMean, _IntendedVariance, {#{type:=Alg}, _}, StandardS %% %% Verify that the basic statistics are ok %% be gentle we don't want to see to many failing tests - abs(StandardMean) < 0.005 orelse ct:fail({average, Alg, StandardMean}), - abs(StandardStdDev - 1.0) < 0.005 orelse ct:fail({stddev, Alg, StandardStdDev}), - ok. + if + abs(StandardMean) < 0.005 -> []; + true -> + [{average, Alg, StandardMean, IntendedMean, IntendedVariance}] + end ++ + if + abs(StandardStdDev - 1.0) < 0.005 -> []; + true -> + [{stddev, Alg, StandardStdDev, IntendedMean, IntendedVariance}] + end. normal_s(Mean, Variance, State0) when Mean == 0, Variance == 1 -> % Make sure we're also testing the standard normal interface @@ -904,14 +1061,19 @@ crypto64_uniform_n(N, State0) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Not a test but measures the time characteristics of the different algorithms -measure(Config) -> +measure(Config) when is_list(Config) -> ct:timetrap({minutes,60}), %% valgrind needs a lot of time case ct:get_timetrap_info() of {_,{_,1}} -> % No scaling - do_measure(Config); + Effort = proplists:get_value(measure_effort, Config, 1), + measure(Effort); {_,{_,Scale}} -> {skip,{will_not_run_in_scaled_time,Scale}} - end. + end; +measure(Effort) when is_integer(Effort) -> + Iterations = ?LOOP div 5, + do_measure(Iterations * Effort). + -define(CHECK_UNIFORM_RANGE(Gen, Range, X, St), case (Gen) of @@ -939,7 +1101,7 @@ measure(Config) -> St end). -do_measure(_Config) -> +do_measure(Iterations) -> Algs = case crypto_support() of ok -> @@ -949,218 +1111,607 @@ do_measure(_Config) -> end, %% ct:pal("~nRNG uniform integer range 10000 performance~n",[]), + [TMarkUniformRange10000,OverheadUniformRange1000|_] = + measure_1( + fun (Mod, _State) -> + Range = 10000, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), _ = measure_1( - fun (_) -> 10000 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + St1 = rand:mwc59(St0), + %% Just a 'rem' with slightly skewed distribution + case (St1 rem Range) + 1 of + R when is_integer(R), 0 < R, R =< Range -> + St1 + end + end end, - Algs), + {mwc59,raw_mod}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + St1 = rand:mwc59(St0), + %% Just a 'rem' with slightly skewed distribution + case (rand:mwc59_value(St1) rem Range) + 1 of + R when is_integer(R), 0 < R, R =< Range -> + St1 + end + end + end, + {mwc59,value_mod}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + {V,St1} = rand:exsp_next(St0), + %% Just a 'rem' with slightly skewed distribution + case (V rem Range) + 1 of + X when is_integer(X), 0 < X, X =< Range -> + St1 + end + end + end, + {exsp,mod}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + St1 = rand:mwc59(St0), + %% Truncated multiplication, slightly skewed + case + ((Range * (St1 band ((1 bsl 16)-1))) bsr 16) + + 1 + of + R when is_integer(R), 0 < R, R =< Range -> + St1 + end + end + end, + {mwc59,raw_tm}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + St1 = rand:mwc59(St0), + %% Truncated multiplication, slightly skewed + case + ((Range * rand:mwc59_value32(St1)) bsr 32) + + 1 + of + R when is_integer(R), 0 < R, R =< Range -> + St1 + end + end + end, + {mwc59,value32_tm}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, % 14 bits + fun (St0) -> + St1 = rand:mwc59(St0), + %% Truncated multiplication, slightly skewed + case + ( (Range * + (rand:mwc59_value(St1) bsr 14) ) + bsr (59-14) ) + + 1 + of + R when is_integer(R), 0 < R, R =< Range -> + St1 + end + end + end, + {mwc59,value_tm}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + {V,St1} = rand:exsp_next(St0), + %% Truncated multiplication, slightly skewed + case + ((Range * (V bsr 14)) bsr (58-14)) + 1 + of + X when is_integer(X), 0 < X, X =< Range -> + St1 + end + end + end, + {exsp,tm}, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + %% Just a 'rem' with slightly skewed distribution + case + erlang:phash2(erlang:unique_integer(), Range) + of + X when is_integer(X), 0 =< X, X < Range -> + St0 + end + end + end, + unique_phash2, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 10000, + fun (St0) -> + %% Just a 'rem' with slightly skewed distribution + case os:system_time(microsecond) rem Range of + R + when is_integer(R), 0 =< R, R < Range -> + St0 + end + end + end, + system_time, Iterations, + TMarkUniformRange10000, OverheadUniformRange1000), %% ct:pal("~nRNG uniform integer 32 bit performance~n",[]), + [TMarkUniform32Bit,OverheadUniform32Bit|_] = + measure_1( + fun (Mod, _State) -> + Range = 1 bsl 32, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, + Algs, Iterations), _ = measure_1( - fun (_) -> 1 bsl 32 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + St1 = rand:mwc59(St0), + case St1 band ((1 bsl 32)-1) of + R when is_integer(R), 0 =< R, R < Range -> + St1 + end + end end, - Algs), + {mwc59,raw_mask}, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + St1 = rand:mwc59(St0), + case rand:mwc59_value32(St1) of + R when is_integer(R), 0 =< R, R < Range -> + St1 + end + end + end, + {mwc59,value32}, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + St1 = rand:mwc59(St0), + case rand:mwc59_value(St1) bsr (59-32) of + R when is_integer(R), 0 =< R, R < Range -> + St1 + end + end + end, + {mwc59,value_shift}, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + {V, St1} = rand:exsp_next(St0), + case V bsr (58-32) of + R when is_integer(R), 0 =< R, R < Range -> + St1 + end + end + end, + {exsp,shift}, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + case + erlang:phash2(erlang:unique_integer(), Range) + of + R + when is_integer(R), 0 =< R, R < Range -> + St0 + end + end + end, + unique_phash2, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 32, + fun (St0) -> + case + os:system_time(microsecond) + band ((1 bsl 32) - 1) + of + R when is_integer(R), 0 =< R, R < Range -> + St0 + end + end + end, + system_time, Iterations, + TMarkUniform32Bit, OverheadUniform32Bit), %% ct:pal("~nRNG uniform integer half range performance~n",[]), _ = measure_1( - fun (State) -> half_range(State) end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) + fun (Mod, State) -> + Range = half_range(State), + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end end, - Algs), + Algs, Iterations), %% ct:pal("~nRNG uniform integer half range + 1 performance~n",[]), _ = measure_1( - fun (State) -> half_range(State) + 1 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) - end, - Algs), + fun (Mod, State) -> + Range = half_range(State) + 1, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), %% ct:pal("~nRNG uniform integer full range - 1 performance~n",[]), _ = measure_1( - fun (State) -> (half_range(State) bsl 1) - 1 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) - end, - Algs), + fun (Mod, State) -> + Range = (half_range(State) bsl 1) - 1, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), %% ct:pal("~nRNG uniform integer full range performance~n",[]), + [TMarkUniformFullRange,OverheadUniformFullRange|_] = + measure_1( + fun (Mod, State) -> + Range = half_range(State) bsl 1, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs ++ [dummy], Iterations), _ = measure_1( - fun (State) -> half_range(State) bsl 1 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) + fun (_Mod, _State) -> + Range = (16#7fa6502 bsl 32) - 1, + fun (St0) -> + St1 = rand:mwc59(St0), + V = St1, + if + is_integer(V), 1 =< V, V < Range -> + St1 + end + end + end, + {mwc59,raw}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = (1 bsl 32) - 1, + fun (St0) -> + St1 = rand:mwc59(St0), + V = rand:mwc59_value32(St1), + if + is_integer(V), 0 =< V, V =< Range -> + St1 + end + end end, - Algs), + {mwc59,value32}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = (1 bsl 59) - 1, + fun (St0) -> + St1 = rand:mwc59(St0), + V = rand:mwc59_value(St1), + if + is_integer(V), 0 =< V, V =< Range -> + St1 + end + end + end, + {mwc59,value}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 58, + fun (St0) -> + {V, St1} = rand:exsp_next(St0), + if + is_integer(V), 0 =< V, V < Range -> + St1 + end + end + end, + {exsp,next}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 64, + fun (St0) -> + {V, St1} = rand:splitmix64_next(St0), + if + is_integer(V), 0 =< V, V < Range -> + St1 + end + end + end, + {splitmix64,next}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = 1 bsl 27, + fun (St0) -> + case erlang:phash2(erlang:unique_integer()) of + X + when is_integer(X), 0 =< X, X < Range -> + St0 + end + end + end, + unique_phash2, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (Mod, _State) -> + Range = 1 bsl 27, + Generator = fun Mod:uniform/1, + fun (St0) -> + case Generator(Range) of + X when is_integer(X), 1 =< X, X =< Range -> + St0 + end + end + end, + procdict, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), + _ = + measure_1( + fun (_Mod, _State) -> + Range = (16#7fa6502 bsl 32) - 1, + fun (St0) -> + case + put(mwc59_procdict, + rand:mwc59(get(mwc59_procdict))) + of + X when is_integer(X), 0 =< X, X < Range -> + St0 + end + end + end, + {mwc59,procdict}, Iterations, + TMarkUniformFullRange, OverheadUniformFullRange), %% ct:pal("~nRNG uniform integer full range + 1 performance~n",[]), _ = measure_1( - fun (State) -> (half_range(State) bsl 1) + 1 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) - end, - Algs), + fun (Mod, State) -> + Range = (half_range(State) bsl 1) + 1, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), %% ct:pal("~nRNG uniform integer double range performance~n",[]), _ = measure_1( - fun (State) -> - half_range(State) bsl 2 - end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) - end, - Algs), + fun (Mod, State) -> + Range = half_range(State) bsl 2, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), %% ct:pal("~nRNG uniform integer double range + 1 performance~n",[]), _ = measure_1( - fun (State) -> - (half_range(State) bsl 2) + 1 - end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) - end, - Algs), + fun (Mod, State) -> + Range = (half_range(State) bsl 2) + 1, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), %% ct:pal("~nRNG uniform integer 64 bit performance~n",[]), + [TMarkUniform64Bit, OverheadUniform64Bit | _] = + measure_1( + fun (Mod, _State) -> + Range = 1 bsl 64, + Generator = fun Mod:uniform_s/2, + fun (St0) -> + ?CHECK_UNIFORM_RANGE( + Generator(Range, St0), Range, X, St1) + end + end, Algs, Iterations), _ = measure_1( - fun (_) -> 1 bsl 64 end, - fun (State, Range, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM_RANGE( - Mod:uniform_s(Range, St0), Range, - X, St1) - end, - State) + fun (_Mod, _State) -> + Range = 1 bsl 64, + fun (St0) -> + {V, St1} = rand:splitmix64_next(St0), + if + is_integer(V), 0 =< V, V < Range -> + St1 + end + end end, - Algs), + {splitmix64,next}, Iterations, + TMarkUniform64Bit, OverheadUniform64Bit), %% ByteSize = 16, % At about 100 bytes crypto_bytes breaks even to exsss ct:pal("~nRNG ~w bytes performance~n",[ByteSize]), + [TMarkBytes1,OverheadBytes1|_] = + measure_1( + fun (Mod, _State) -> + Generator = fun Mod:bytes_s/2, + fun (St0) -> + ?CHECK_BYTE_SIZE( + Generator(ByteSize, St0), ByteSize, Bin, St1) + end + end, + case crypto_support() of + ok -> + Algs ++ [crypto_bytes, crypto_bytes_cached]; + _ -> + Algs + end, Iterations), _ = measure_1( - fun (_) -> ByteSize end, - fun (State, Size, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_BYTE_SIZE( - Mod:bytes_s(Size, St0), Size, - Bin, St1) - end, - State) + fun (_Mod, _State) -> + fun (St0) -> + ?CHECK_BYTE_SIZE( + mwc59_bytes(ByteSize, St0), ByteSize, Bin, St1) + end + end, {mwc59,bytes}, Iterations, + TMarkBytes1, OverheadBytes1), + %% + ByteSize2 = 1000, % At about 100 bytes crypto_bytes breaks even to exsss + ct:pal("~nRNG ~w bytes performance~n",[ByteSize2]), + [TMarkBytes2,OverheadBytes2|_] = + measure_1( + fun (Mod, _State) -> + Generator = fun Mod:bytes_s/2, + fun (St0) -> + ?CHECK_BYTE_SIZE( + Generator(ByteSize2, St0), ByteSize2, Bin, St1) + end end, case crypto_support() of ok -> Algs ++ [crypto_bytes, crypto_bytes_cached]; _ -> Algs - end), + end, Iterations div 50), + _ = + measure_1( + fun (_Mod, _State) -> + fun (St0) -> + ?CHECK_BYTE_SIZE( + mwc59_bytes(ByteSize2, St0), ByteSize2, Bin, St1) + end + end, {mwc59,bytes}, Iterations div 50, + TMarkBytes2, OverheadBytes2), %% ct:pal("~nRNG uniform float performance~n",[]), + [TMarkUniformFloat,OverheadUniformFloat|_] = + measure_1( + fun (Mod, _State) -> + Generator = fun Mod:uniform_s/1, + fun (St0) -> + ?CHECK_UNIFORM(Generator(St0), X, St) + end + end, + Algs, Iterations), _ = measure_1( - fun (_) -> 0 end, - fun (State, _, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM(Mod:uniform_s(St0), X, St) - end, - State) + fun (_Mod, _State) -> + fun (St0) -> + St1 = rand:mwc59(St0), + case rand:mwc59_float(St1) of + R when is_float(R), 0.0 =< R, R < 1.0 -> + St1 + end + end + end, + {mwc59,float}, Iterations, + TMarkUniformFloat, OverheadUniformFloat), + _ = + measure_1( + fun (_Mod, _State) -> + fun (St0) -> + {V,St1} = rand:exsp_next(St0), + case V * (1/(1 bsl 58)) of + R when is_float(R), 0.0 =< R, R < 1.0 -> + St1 + end + end end, - Algs), + {exsp,float}, Iterations, + TMarkUniformFloat, OverheadUniformFloat), %% ct:pal("~nRNG uniform_real float performance~n",[]), _ = measure_1( - fun (_) -> 0 end, - fun (State, _, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_UNIFORM(Mod:uniform_real_s(St0), X, St) - end, - State) + fun (Mod, _State) -> + Generator = fun Mod:uniform_real_s/1, + fun (St0) -> + ?CHECK_UNIFORM(Generator(St0), X, St) + end end, - Algs), + Algs, Iterations), %% ct:pal("~nRNG normal float performance~n",[]), - [TMarkNormalFloat|_] = + [TMarkNormalFloat, OverheadNormalFloat|_] = measure_1( - fun (_) -> 0 end, - fun (State, _, Mod) -> - measure_loop( - fun (St0) -> - ?CHECK_NORMAL(Mod:normal_s(St0), X, St1) - end, - State) + fun (Mod, _State) -> + Generator = fun Mod:normal_s/1, + fun (St0) -> + ?CHECK_NORMAL(Generator(St0), X, St1) + end end, - Algs), + Algs, Iterations), %% Just for fun try an implementation of the Box-Muller %% transformation for creating normal distribution floats %% to compare with our Ziggurat implementation. @@ -1170,81 +1721,121 @@ do_measure(_Config) -> TwoPi = 2 * math:pi(), _ = measure_1( - fun (_) -> 0 end, - fun (State, _, Mod) -> - measure_loop( - fun (State0) -> - {U1, State1} = Mod:uniform_real_s(State0), - {U2, State2} = Mod:uniform_s(State1), - R = math:sqrt(-2.0 * math:log(U1)), - T = TwoPi * U2, - Z0 = R * math:cos(T), - Z1 = R * math:sin(T), - ?CHECK_NORMAL({Z0 + Z1, State2}, X, State3) - end, - State) + fun (Mod, _State) -> + fun (St0) -> + {U1, St1} = Mod:uniform_real_s(St0), + {U2, St2} = Mod:uniform_s(St1), + R = math:sqrt(-2.0 * math:log(U1)), + T = TwoPi * U2, + Z0 = R * math:cos(T), + Z1 = R * math:sin(T), + ?CHECK_NORMAL({Z0 + Z1, St2}, X, St3) + end end, - exsss, TMarkNormalFloat), + exsss, Iterations, + TMarkNormalFloat, OverheadNormalFloat), ok. --define(LOOP_MEASURE, (?LOOP div 5)). - -measure_loop(Fun, State) -> - measure_loop(Fun, State, ?LOOP_MEASURE). -%% -measure_loop(Fun, State, N) when 0 < N -> - measure_loop(Fun, Fun(State), N-1); +measure_loop(State, Fun, I) when 10 =< I -> + %% Loop unrolling to dilute benchmark overhead... + measure_loop( + Fun(Fun(Fun(Fun(Fun( Fun(Fun(Fun(Fun(Fun(State))))) ))))), + Fun, I - 10); +measure_loop(State, Fun, I) when 1 =< I -> + measure_loop(Fun(State), Fun, I - 1); measure_loop(_, _, _) -> ok. -measure_1(RangeFun, Fun, Algs) -> - TMark = measure_1(RangeFun, Fun, hd(Algs), undefined), - [TMark] ++ - [measure_1(RangeFun, Fun, Alg, TMark) || Alg <- tl(Algs)]. - -measure_1(RangeFun, Fun, Alg, TMark) -> +measure_1(InitFun, Algs, Iterations) -> + WMark = measure_1(InitFun, hd(Algs), Iterations, warm_up, 0), + Overhead = + measure_1( + fun (_Mod, _State) -> + Range = 1, + fun (St0) + when is_integer(St0), 1 =< St0, St0 =< Range -> + St0 + end + end, overhead, Iterations, WMark, 0), + TMark = measure_1(InitFun, hd(Algs), Iterations, undefined, Overhead), + [TMark,Overhead] ++ + [measure_1(InitFun, Alg, Iterations, TMark, Overhead) + || Alg <- tl(Algs)]. + +measure_1(InitFun, Alg, Iterations, TMark, Overhead) -> Parent = self(), - {Mod, State} = - case Alg of - crypto64 -> - {rand, crypto64_seed()}; - crypto_cache -> - {rand, crypto:rand_seed_alg(crypto_cache)}; - crypto -> - {rand, crypto:rand_seed_s()}; - crypto_aes -> - {rand, - crypto:rand_seed_alg( - crypto_aes, crypto:strong_rand_bytes(256))}; - random -> - {random, random:seed(os:timestamp()), get(random_seed)}; - crypto_bytes -> - {?MODULE, ignored_state}; - crypto_bytes_cached -> - {?MODULE, <<>>}; - _ -> - {rand, rand:seed_s(Alg)} + MeasureFun = + fun () -> + {Mod, State} = measure_init(Alg), + IterFun = InitFun(Mod, State), + {T, ok} = + timer:tc( + fun () -> + measure_loop(State, IterFun, Iterations) + end), + Time = T - Overhead, + Percent = + case TMark of + warm_up -> "(warm-up)"; + undefined -> " 100.0%"; + _ -> + io_lib:format( + "~8.1f%", [(Time * 100 + 50) / TMark]) + end, + io:format( + "~.24w: ~8.1f ns ~s~n", + [Alg, (Time * 1000 + 500) / Iterations, Percent]), + Parent ! {self(), Time}, + ok end, - Range = RangeFun(State), - Pid = spawn_link( - fun() -> - {Time, ok} = timer:tc(fun () -> Fun(State, Range, Mod) end), - Percent = - case TMark of - undefined -> 100; - _ -> (Time * 100 + 50) div TMark - end, - io:format( - "~.20w: ~p ns ~p% [16#~.16b]~n", - [Alg, (Time * 1000 + 500) div ?LOOP_MEASURE, - Percent, Range]), - Parent ! {self(), Time}, - normal - end), + Pid = spawn_link(MeasureFun), receive {Pid, Msg} -> Msg end. +measure_init(Alg) -> + case Alg of + overhead -> + {?MODULE, 1}; + crypto64 -> + {rand, crypto64_seed()}; + crypto_cache -> + {rand, crypto:rand_seed_alg(crypto_cache)}; + crypto -> + {rand, crypto:rand_seed_s()}; + crypto_aes -> + {rand, + crypto:rand_seed_alg( + crypto_aes, crypto:strong_rand_bytes(256))}; + random -> + {random, random:seed(os:timestamp()), get(random_seed)}; + crypto_bytes -> + {?MODULE, undefined}; + crypto_bytes_cached -> + {?MODULE, <<>>}; + unique_phash2 -> + {?MODULE, undefined}; + system_time -> + {?MODULE, undefined}; + procdict -> + {rand, rand:seed(exsss)}; + {Name, Tag} -> + case Name of + mwc59 when Tag =:= procdict -> + _ = put(mwc59_procdict, rand:mwc59_seed()), + {rand, undefined}; + mwc59 -> + {rand, rand:mwc59_seed()}; + exsp -> + {_, S} = rand:seed_s(exsp), + {rand, S}; + splitmix64 -> + {rand, erlang:unique_integer()} + end; + _ -> + {rand, rand:seed_s(Alg)} + end. + %% Comparison algorithm for rand:bytes_s/2 vs. crypto:strong_rand_bytes/1 bytes_s(N, Cache) when is_binary(Cache) -> %% crypto_bytes_cached @@ -1256,10 +1847,37 @@ bytes_s(N, Cache) when is_binary(Cache) -> <>, {Bytes, Rest} end; -bytes_s(N, ignored_state = St) -> +bytes_s(N, undefined = St) -> %% crypto_bytes {crypto:strong_rand_bytes(N), St}. +mwc59_bytes(N, R0) -> + mwc59_bytes(N, R0, <<>>). +%% +mwc59_bytes(N, R0, Bin) when is_integer(N), 7*4 =< N -> + R1 = rand:mwc59(R0), + R2 = rand:mwc59(R1), + R3 = rand:mwc59(R2), + R4 = rand:mwc59(R3), + Shift = 59 - 56, + V1 = rand:mwc59_value(R1) bsr Shift, + V2 = rand:mwc59_value(R2) bsr Shift, + V3 = rand:mwc59_value(R3) bsr Shift, + V4 = rand:mwc59_value(R4) bsr Shift, + mwc59_bytes(N-7*4, R4, <>); +mwc59_bytes(N, R0, Bin) when is_integer(N), 7 =< N -> + R1 = rand:mwc59(R0), + V = rand:mwc59_value(R1) bsr (59-56), + mwc59_bytes(N-7, R1, <>); +mwc59_bytes(N, R0, Bin) when is_integer(N), 0 < N -> + R1 = rand:mwc59(R0), + Bits = N bsl 3, + V = rand:mwc59_value(R1) bsr (59-Bits), + {<>, R1}; +mwc59_bytes(0, R0, Bin) -> + {Bin, R0}. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% The jump sequence tests has two parts %% for those with the functional API (jump/1) diff --git a/lib/stdlib/test/random_iolist.erl b/lib/stdlib/test/random_iolist.erl index 6621c7ac770f..63a6c7dd030e 100644 --- a/lib/stdlib/test/random_iolist.erl +++ b/lib/stdlib/test/random_iolist.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2017. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -40,7 +40,7 @@ random_list(N,Acc) -> random_list(N-1,[random_byte() | Acc]). random_binary(N) -> - B = list_to_binary(random_list(N,[])), + B = rand:bytes(N), case {rand:uniform(2),size(B)} of {2,M} when M > 1 -> S = M-1, diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index 1c9919c8de7b..fc6e97794252 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -22,7 +22,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, pcre/1,compile_options/1, run_options/1,combined_options/1,replace_autogen/1, - global_capture/1,replace_input_types/1,replace_return/1, + global_capture/1,replace_input_types/1,replace_with_fun/1,replace_return/1, split_autogen/1,split_options/1,split_specials/1, error_handling/1,pcre_cve_2008_2371/1,re_version/1, pcre_compile_workspace_overflow/1,re_infinite_loop/1, @@ -42,7 +42,7 @@ suite() -> all() -> [pcre, compile_options, run_options, combined_options, replace_autogen, global_capture, replace_input_types, - replace_return, split_autogen, split_options, + replace_with_fun, replace_return, split_autogen, split_options, split_specials, error_handling, pcre_cve_2008_2371, pcre_compile_workspace_overflow, re_infinite_loop, re_backwards_accented, opt_dupnames, opt_all_names, @@ -162,7 +162,7 @@ run_options(Config) when is_list(Config) -> {match,["ABCabcdABC","abcd"]} = re:run("ABCabcdABC",MP,[{capture,all,list}]), {match,[<<"ABCabcdABC">>,<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all,binary}]), {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first}]), - {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first,index}]), ?line {match,["ABCabcdABC"]} = re:run("ABCabcdABC",MP,[{capture,first,list}]), + {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first,index}]), {match,["ABCabcdABC"]} = re:run("ABCabcdABC",MP,[{capture,first,list}]), {match,[<<"ABCabcdABC">>]} = re:run("ABCabcdABC",MP,[{capture,first,binary}]), {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first}]), @@ -365,6 +365,16 @@ replace_input_types(Config) when is_list(Config) -> <<"a",208,128,"cd">> = re:replace(<<"abcd">>,"b","\x{400}",[{return,binary},unicode]), ok. +%% Test replace with a replacement function. +replace_with_fun(Config) when is_list(Config) -> + <<"ABCD">> = re:replace("abcd", ".", fun(<>, []) -> <<(C - $a + $A)>> end, [global, {return, binary}]), + <<"AbCd">> = re:replace("abcd", ".", fun(<>, []) when (C - $a) rem 2 =:= 0 -> <<(C - $a + $A)>>; (C, []) -> C end, [global, {return, binary}]), + <<"b-ad-c">> = re:replace("abcd", "(.)(.)", fun(_, [A, B]) -> <> end, [global, {return, binary}]), + <<"#ab-B#cd">> = re:replace("abcd", ".(.)", fun(Whole, [<>]) -> <<$#, Whole/binary, $-, (C - $a + $A), $#>> end, [{return, binary}]), + <<"#ab#cd">> = re:replace("abcd", ".(x)?(.)", fun(Whole, [<<>>, _]) -> <<$#, Whole/binary, $#>> end, [{return, binary}]), + <<"#ab#cd">> = re:replace("abcd", ".(.)(x)?", fun(Whole, [_]) -> <<$#, Whole/binary, $#>> end, [{return, binary}]), + ok. + %% Test return options of replace together with global searching. replace_return(Config) when is_list(Config) -> {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")), diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index 25ea6d02f1bb..142f8ad4450f 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2021. All Rights Reserved. +%% Copyright Ericsson AB 2004-2022. 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. @@ -18,24 +18,25 @@ %% %CopyrightEnd% %% -module(shell_SUITE). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). - -export([forget/1, records/1, known_bugs/1, otp_5226/1, otp_5327/1, otp_5435/1, otp_5195/1, otp_5915/1, otp_5916/1, bs_match_misc_SUITE/1, bs_match_int_SUITE/1, bs_match_tail_SUITE/1, bs_match_bin_SUITE/1, bs_construct_SUITE/1, - refman_bit_syntax/1, - progex_bit_syntax/1, progex_records/1, + refman_bit_syntax/1, + progex_bit_syntax/1, progex_records/1, progex_lc/1, progex_funs/1, otp_5990/1, otp_6166/1, otp_6554/1, otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1, otp_13719/1, - otp_14285/1, otp_14296/1, typed_records/1]). + otp_14285/1, otp_14296/1, typed_records/1, types/1]). --export([ start_restricted_from_shell/1, +-export([ start_restricted_from_shell/1, start_restricted_on_command_line/1,restricted_local/1]). +-export([ start_interactive/1, whereis/1 ]). + %% Internal export. -export([otp_5435_2/0, prompt1/1, prompt2/1, prompt3/1, prompt4/1, prompt5/1]). @@ -73,19 +74,21 @@ suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,10}}]. -all() -> +all() -> [forget, known_bugs, otp_5226, otp_5327, - otp_5435, otp_5195, otp_5915, otp_5916, {group, bits}, + otp_5435, otp_5195, otp_5915, otp_5916, + start_interactive, whereis, {group, bits}, {group, refman}, {group, progex}, {group, tickets}, - {group, restricted}, {group, records}]. + {group, restricted}, {group, records}, {group, definitions}]. -groups() -> +groups() -> [{restricted, [], [start_restricted_from_shell, start_restricted_on_command_line, restricted_local]}, {bits, [], [bs_match_misc_SUITE, bs_match_tail_SUITE, bs_match_bin_SUITE, bs_construct_SUITE]}, + {definitions, [], [types]}, {records, [], [records, typed_records]}, {refman, [], [refman_bit_syntax]}, @@ -190,16 +193,15 @@ ok. %% Check restricted shell when started from the command line. start_restricted_on_command_line(Config) when is_list(Config) -> - {ok,Node} = start_node(shell_suite_helper_1, - "-pa "++proplists:get_value(priv_dir,Config)++ - " -stdlib restricted_shell foo"), + {ok, Peer, Node} = ?CT_PEER(["-pa", proplists:get_value(priv_dir,Config), + "-stdlib", "restricted_shell", "foo"]), "Warning! Restricted shell module foo not found: nofile"++_ = t({Node, <<"begin m() end.">>}), "exception exit: restricted shell does not allow m()" = comm_err({Node, <<"begin m() end.">>}), [ok] = (catch scan({Node, <<"begin q() end.">>})), - test_server:stop_node(Node), + peer:stop(Peer), Test = filename:join(proplists:get_value(priv_dir, Config), "test_restricted2.erl"), Contents = <<"-module(test_restricted2). @@ -217,9 +219,8 @@ start_restricted_on_command_line(Config) when is_list(Config) -> {false,State}. ">>, ok = compile_file(Config, Test, Contents, []), - {ok,Node2} = start_node(shell_suite_helper_2, - "-pa "++proplists:get_value(priv_dir,Config)++ - " -stdlib restricted_shell test_restricted2"), + {ok, Peer2, Node2} = ?CT_PEER(["-pa", proplists:get_value(priv_dir,Config), + "-stdlib", "restricted_shell", "test_restricted2"]), "Module" ++ _ = t({Node2,<<"begin m() end.">>, utf8}), "exception exit: restricted shell does not allow c(foo)" = comm_err({Node2,<<"begin c(foo) end.">>}), @@ -235,7 +236,7 @@ start_restricted_on_command_line(Config) when is_list(Config) -> comm_err({Node2,<<"begin shell:stop_restricted() end.">>}), [ok] = scan({Node2, <<"begin q() end.">>}), - test_server:stop_node(Node2), + peer:stop(Peer2), ok. %% Tests calling local shell functions with spectacular arguments in @@ -258,6 +259,8 @@ restricted_local(Config) when is_list(Config) -> local_allowed(_,_,State) -> {false,State}. + non_local_allowed({erlang,raise},[error, _, _],State) -> + {true,State}; non_local_allowed({shell,stop_restricted},[],State) -> {true,State}; non_local_allowed(_,_,State) -> @@ -300,7 +303,7 @@ restricted_local(Config) when is_list(Config) -> application:get_env(stdlib, restricted_shell), true = purge_and_delete(user_default), ok. - + %% f/0 and f/1. forget(Config) when is_list(Config) -> @@ -319,15 +322,73 @@ forget(Config) when is_list(Config) -> comm_err(<<"f(a).">>), ok. +%% type definition support +types(Config) when is_list(Config) -> + %% type + [ok] = scan(<<"-type baz() :: integer().">>), + %% record + [ok] = scan(<<"-record(foo, {bar :: baz()}).">>), + %% spec + [ok] = scan(<<"-spec foo(Bar) -> Baz when + Bar :: string(), + Baz :: integer().">>), + shell_attribute_test(Config), + ok. +shell_attribute_test(Config) -> + Path = filename:join([proplists:get_value(priv_dir, Config), + "shell_history", "function_def"]), + rtnode:run( + [{putline, "foo(Bar) -> Bar."}, + {expect, "ok"}, + {putline, "fl()."}, + {expect, "\\Q{function,{shell_default,foo,1}}\\E"}, + {putline, "foo(1)."}, + {expect, "1"}, + {putline, "shell_default:foo(2)."}, + {expect, "2"} + ],[],"", ["-kernel","shell_history","enabled", + "-kernel","shell_history_path","\"" ++ Path ++ "\"", + "-kernel","shell_history_drop","[\"init:stop().\"]"]), + receive after 1000 -> ok end, + rtnode:run( + [{putline, "-record(hej, {a = 0 :: integer()})."}, + {expect, "ok"}, + {putline, "rl()."}, + {expect, "\\Q-record(hej,{a = 0 :: integer()}).\\E"}, + {putline, "#hej{a=1}."}, + {expect, "\\Q#hej{a = 1}\\E"} + ],[],"", ["-kernel","shell_history","enabled", + "-kernel","shell_history_path","\"" ++ Path ++ "\"", + "-kernel","shell_history_drop","[\"init:stop().\"]"]), + receive after 1000 -> ok end, + rtnode:run( + [{putline, "-spec foo(Bar) -> Bar when Bar :: integer()."}, + {expect, "ok"}, + {putline, "fl()."}, + {expect, "\\Q{function_type,{shell_default,foo,1}}\\E"} + ],[],"", ["-kernel","shell_history","enabled", + "-kernel","shell_history_path","\"" ++ Path ++ "\"", + "-kernel","shell_history_drop","[\"init:stop().\"]"]), + receive after 1000 -> ok end, + rtnode:run( + [{putline, "-type my_type() :: boolean() | integer()."}, + {expect, "ok"}, + {putline, "fl()."}, + {expect, "\\Q{type,my_type}\\E"} + ],[],"", ["-kernel","shell_history","enabled", + "-kernel","shell_history_path","\"" ++ Path ++ "\"", + "-kernel","shell_history_drop","[\"init:stop().\"]"]), + ok. + %% Test of the record support. OTP-5063. records(Config) when is_list(Config) -> %% rd/2 [{attribute,_,record,{bar,_}},ok] = - scan(<<"rd(foo,{bar}), + scan(<<"rd(foo,{bar}), rd(bar,{foo = (#foo{})#foo.bar}), rl(bar).">>), "variable 'R' is unbound" = % used to work (before OTP-5878, R11B) - exit_string(<<"rd(foo,{bar}), + exit_string(<<"rd(foo,{bar}), R = #foo{}, rd(bar,{foo = R#foo.bar}).">>), "exception error: no function clause matching call to rd/2" = @@ -401,7 +462,7 @@ records(Config) when is_list(Config) -> [{attribute,A1,record,{test1,_}},ok] = scan(RR5), RR6 = "rr(\"" ++ Test ++ "\", '_', {d,test2}), rl([test1,test2]).", [{attribute,A1,record,{test2,_}},ok] = scan(RR6), - RR7 = "rr(\"" ++ Test ++ + RR7 = "rr(\"" ++ Test ++ "\", '_', [{d,test1},{d,test2,17}]), rl([test1,test2]).", [{attribute,A1,record,{test1,_}},{attribute,A1,record,{test2,_}},ok] = scan(RR7), @@ -503,7 +564,7 @@ records(Config) when is_list(Config) -> [ok] = scan(<<"rd(a,{}), is_record({a},a) andalso true, b().">>), - + %% nested record defs "#b{a = #a{}}.\n" = t(<<"rd(a,{}), rd(b, {a = #a{}}), #b{}.">>), @@ -590,11 +651,11 @@ otp_5327(Config) when is_list(Config) -> default,default}]}), [<<"abc">>] = scan(<<"<<(<<\"abc\">>):3/binary>>.">>), [<<"abc">>] = scan(<<"<<(<<\"abc\">>)/binary>>.">>), - "exception error: bad argument" = + "exception error: construction of binary failed" = comm_err(<<"<<(<<\"abc\">>):4/binary>>.">>), true = byte_size(hd(scan("<<3.14:64/float>>."))) =:= 8, true = byte_size(hd(scan("<<3.14:32/float>>."))) =:= 4, - "exception error: bad argument" = + "exception error: construction of binary failed" = comm_err(<<"<<3.14:128/float>>.">>), "exception error: bad argument" = comm_err(<<"<<10:default>>.">>), @@ -661,22 +722,18 @@ otp_5435(Config) when is_list(Config) -> true = <<103133.0:64/float>> =:= evaluate(<<"<<103133.0:64/float>> = <<103133:64/float>>.">>, []), true = is_alive(), - {ok, Node} = start_node(shell_SUITE_otp_5435), + {ok, Peer, Node} = ?CT_PEER(), ok = rpc:call(Node, ?MODULE, otp_5435_2, []), - test_server:stop_node(Node), + peer:stop(Peer), ok. -start_node(Name) -> - PA = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, slave, [{args, "-pa " ++ PA}]). - otp_5435_2() -> true = code:del_path(compiler), %% Make sure record evaluation is not dependent on the compiler %% application being in the path. %% OTP-5876. [{attribute,_,record,{bar,_}},ok] = - scan(<<"rd(foo,{bar}), + scan(<<"rd(foo,{bar}), rd(bar,{foo = (#foo{})#foo.bar}), rl(bar).">>), ok. @@ -689,7 +746,7 @@ otp_5195(Config) when is_list(Config) -> %% An experimental shell used to translate error tuples: %% "(qlc) \"1: generated variable 'X' must not be used in " - %% "list expression\".\n" = + %% "list expression\".\n" = %% t(<<"qlc:q([X || X <- [{a}], Y <- [X]]).">>), %% Same as last one (if the shell does not translate error tuples): [{error,qlc,{{1,31},qlc,{used_generator_variable,'X'}}}] = @@ -701,7 +758,7 @@ otp_5195(Config) when is_list(Config) -> {'EXIT',{undef,_}} = (catch evaluate(Ugly, [])), V_1 = <<"qlc:e(qlc:q([X || X <- qlc:append([[1,2,3],v(-1)])])).">>, - "- 1: command not found" = comm_err(V_1), + "-1: command not found" = comm_err(V_1), {'EXIT', {undef,_}} = (catch evaluate(V_1, [])), "1\n2\n3\n3.\n" = @@ -1208,7 +1265,7 @@ bs_match_int_SUITE(Config) when is_list(Config) -> Int -> ok; Other -> io:format(\"Bin = ~p,\", [Bin]), - io:format(\"SkipBef = ~p, N = ~p\", + io:format(\"SkipBef = ~p, N = ~p\", [SkipBef,N]), io:format(\"Expected ~p, got ~p\", [Int,Other]) @@ -1315,8 +1372,8 @@ ok = evaluate(C, []). %% OTP-5327. Adopted from emulator/test/bs_match_bin_SUITE.erl. bs_match_bin_SUITE(Config) when is_list(Config) -> - ByteSplitBinary = - <<"ByteSplit = + ByteSplitBinary = + <<"ByteSplit = fun(L, B, Pos, Fun) when Pos >= 0 -> Sz1 = Pos, Sz2 = size(B) - Pos, @@ -1347,7 +1404,7 @@ ok = evaluate(ByteSplitBinary, []), BitSplitBinary = <<"Mkbin = fun(L) when list(L) -> list_to_binary(L) end, - MakeInt = + MakeInt = fun(List, 0, Acc, _F) -> Acc; ([H|T], N, Acc, F) -> F(T, N-1, Acc bsl 1 bor H, F) end, @@ -1456,7 +1513,7 @@ bs_construct_SUITE(Config) when is_list(Config) -> ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>) "," ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>) "," ?FAIL(<<<<23,56,0,2>>:(anka)>>) " - end, + end, TestF(), NotUsed1 = fun(I, BinString) -> <>, ok end, @@ -1516,7 +1573,7 @@ ok = evaluate(C1, []), C2 = <<" I = fun(X) -> X end, - Fail = fun() -> + Fail = fun() -> I_minus_777 = I(-777), I_minus_2047 = I(-2047), @@ -1638,8 +1695,8 @@ progex_bit_syntax(Config) when is_list(Config) -> Fun4 = fun(Dgram) -> DgramSize = byte_size(Dgram), - case Dgram of - < triples_to_bin1([{X,Y,Z} | T], Acc) -> triples_to_bin1(T, <>); % inefficient -triples_to_bin1([], Acc) -> +triples_to_bin1([], Acc) -> Acc. triples_to_bin2(T) -> @@ -1748,12 +1805,12 @@ triples_to_bin2(T) -> triples_to_bin2([{X,Y,Z} | T], Acc) -> triples_to_bin2(T, [<> | Acc]); -triples_to_bin2([], Acc) -> +triples_to_bin2([], Acc) -> list_to_binary(lists:reverse(Acc)). %% Record examples from Programming Examples. OTP-5237. progex_records(Config) when is_list(Config) -> - Test1 = + Test1 = <<"-module(recs). -record(person, {name = \"\", phone = [], address}). -record(name, {first = \"Robert\", last = \"Ericsson\"}). @@ -1790,7 +1847,7 @@ t() -> c), P3 = #person{name=\"Joe\", phone=[0,0,7], address=\"A street\"}, - #person{name = Name} = P3, + #person{name = Name} = P3, \"Joe\" = Name, \"Robert\" = demo(), @@ -1858,7 +1915,7 @@ Test1_shell = Find), P3 = #person{name=\"Joe\", phone=[0,0,7], address=\"A street\"}, - #person{name = Name} = P3, + #person{name = Name} = P3, \"Joe\" = Name, Demo = fun() -> @@ -1888,7 +1945,7 @@ print(#person{name = Name, age = Age, io:format(\"Name: ~s, Age: ~w, Phone: ~w ~n\" \"Dictionary: ~w.~n\", [Name, Age, Phone, Dict]). - birthday(P) when record(P, person) -> + birthday(P) when record(P, person) -> P#person{age = P#person.age + 1}. register_two_hackers() -> @@ -1906,7 +1963,7 @@ ok. %% List comprehension examples from Programming Examples. OTP-5237. progex_lc(Config) when is_list(Config) -> - Test1 = + Test1 = <<"-module(lc). -export([t/0]). @@ -2040,7 +2097,7 @@ ok. %% Funs examples from Programming Examples. OTP-5237. progex_funs(Config) when is_list(Config) -> - Test1 = + Test1 = <<"-module(funs). -export([t/0]). @@ -2277,7 +2334,7 @@ Test2_shell = \"ERLANG\" = Upcase_word(\"Erlang\"), [\"I\",\"LIKE\",\"ERLANG\"] = lists:map(Upcase_word, L), {[\"I\",\"LIKE\",\"ERLANG\"],11} = - lists:mapfoldl(fun(Word, Sum) -> + lists:mapfoldl(fun(Word, Sum) -> {Upcase_word(Word), Sum + length(Word)} end, 0, L), [500,12,45] = lists:filter(Big, [500,12,2,45,6,7]), @@ -2322,10 +2379,10 @@ otp_6166(Config) when is_list(Config) -> -record(r6, {f = #r5{}}). % r6 > r0 -record(r0, {f = #r5{}, g = #r5{}}). % r0 < r5">>, ok = file:write_file(Test2, Contents2), - - RR12 = "[r1,r2,r3,r4,r5] = rr(\"" ++ Test1 ++ "\"), - [r0,r1,r2,r3,r4,r5,r6] = rr(\"" ++ Test2 ++ "\"), - R0 = #r0{}, R6 = #r6{}, + + RR12 = "[r1,r2,r3,r4,r5] = rr(\"" ++ Test1 ++ "\"), + [r0,r1,r2,r3,r4,r5,r6] = rr(\"" ++ Test2 ++ "\"), + R0 = #r0{}, R6 = #r6{}, true = is_record(R0, r0), true = is_record(R6, r6), ok. ", @@ -2442,7 +2499,7 @@ otp_6554(Config) when is_list(Config) -> "exception error: undefined function math:sqrt/2" = comm_err(<<"math:sqrt(2, 2).">>), "exception error: limit of number of arguments to interpreted function " - "exceeded" = + "exceeded" = comm_err(<<"fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) ->" " a end().">>), "exception error: bad filter a" = @@ -2540,7 +2597,7 @@ otp_6554(Config) when is_list(Config) -> t(<<"results(2). 1. v(2). h().">>), application:unset_env(stdlib, shell_saved_results), "1\nfoo\n17\nB = foo\nC = 17\nF = fun() ->\n foo" - "\n end.\nok.\n" = + "\n end.\nok.\n" = t(<<"begin F = fun() -> foo end, 1 end. B = F(). C = 17. b().">>), "3: command not found" = comm_err(<<"#{v(3) => v}.">>), @@ -2566,9 +2623,9 @@ otp_7184(Config) when is_list(Config) -> t(<<"P = self(), spawn_link(fun() -> process_flag(trap_exit,true), P ! up, - receive X -> + receive X -> otp_7184 ! {otp_7184, X} - end + end end), receive up -> ok end, erlang:raise(throw, thrown, []).">>), @@ -2578,9 +2635,9 @@ otp_7184(Config) when is_list(Config) -> t(<<"P = self(), spawn_link(fun() -> process_flag(trap_exit,true), P ! up, - receive X -> + receive X -> otp_7184 ! {otp_7184, X} - end + end end), receive up -> ok end, erlang:raise(exit, fini, []).">>), @@ -2590,9 +2647,9 @@ otp_7184(Config) when is_list(Config) -> t(<<"P = self(), spawn_link(fun() -> process_flag(trap_exit,true), P ! up, - receive X -> + receive X -> otp_7184 ! {otp_7184,X} - end + end end), receive up -> ok end, erlang:raise(error, bad, []).">>), @@ -2717,7 +2774,7 @@ exit_term(B) -> -endif. error_string(B) -> - "** exception error:" ++ Reply = t(B), + "** exception error:" ++ Reply = t(B), caught_string(Reply). exit_string(B) -> @@ -2750,9 +2807,8 @@ prompt_err(B) -> %% OTP-10302. Unicode. Also OTP-14285, Unicode atoms. otp_10302(Config) when is_list(Config) -> - {ok,Node} = start_node(shell_suite_helper_2, - "-pa "++proplists:get_value(priv_dir,Config)++ - " +pc unicode"), + {ok, Peer, Node} = ?CT_PEER(["-pa", proplists:get_value(priv_dir,Config), + "+pc", "unicode"]), Test1 = <<"begin io:setopts([{encoding,utf8}]), @@ -2825,7 +2881,7 @@ otp_10302(Config) when is_list(Config) -> {ok, Es} = erl_parse:parse_exprs(Ts), B = erl_eval:new_bindings(), erl_eval:exprs(Es, B).">>, - + "ok.\n** exception error: an error occurred when evaluating" " an arithmetic expression\n in operator '/'/2\n" " called as <<\"ª\">> / <<\"ª\">>.\n" = t({Node,Test7}), @@ -2902,7 +2958,7 @@ otp_10302(Config) when is_list(Config) -> "ok.\n** exception error: undefined function " "shell_SUITE:'\x{447}\x{435}'/0.\n" = t({Node,Test17}), - test_server:stop_node(Node), + peer:stop(Peer), ok. otp_13719(Config) when is_list(Config) -> @@ -2919,9 +2975,8 @@ otp_13719(Config) when is_list(Config) -> ok. otp_14285(Config) -> - {ok,Node} = start_node(shell_suite_helper_4, - "-pa "++proplists:get_value(priv_dir,Config)++ - " +pc unicode"), + {ok, Peer, Node} = ?CT_PEER(["-pa", proplists:get_value(priv_dir,Config), + "+pc", "unicode"]), Test1 = <<"begin io:setopts([{encoding,utf8}]), @@ -2931,7 +2986,7 @@ otp_14285(Config) -> end.">>, "-record('\x{400}',{'\x{400}' = '\x{400}'}).\nok.\n" = t({Node,Test1}), - test_server:stop_node(Node), + peer:stop(Peer), ok. otp_14296(Config) when is_list(Config) -> @@ -3020,11 +3075,198 @@ otp_14296(Config) when is_list(Config) -> {error, {_,_,"bad term"}} = TF("1, 2"), ok. +start_interactive(_Config) -> + start_interactive_shell([]), + start_interactive_shell(["-env","TERM","dumb"]). + +start_interactive_shell(ExtraArgs) -> + + %% Basic test case + rtnode:run( + [{expect, "eval_test"}, + {putline, "test."}, + {eval, fun() -> shell:start_interactive() end}, + {expect, "1>"}, + {expect, "2>"}, + {eval, fun() -> {error,already_started} = shell:start_interactive(), ok end} + ],[],"",["-noinput","-eval","io:format(\"eval_test~n\")"] ++ ExtraArgs), + + %% Test that custom MFA works + rtnode:run( + [{expect, "eval_test"}, + {putline, "test."}, + {eval, fun() -> shell:start_interactive({shell,start,[]}) end}, + {expect, "1>"}, + {expect, "2>"} + ],[],"",["-noinput","-eval","io:format(\"eval_test~n\")"] ++ ExtraArgs), + + %% Test that we can start noshell and then a shell + rtnode:run( + [{expect, "eval_test"}, + {putline, "test."}, + {eval, fun() -> shell:start_interactive(noshell) end}, + {eval, fun() -> io:format(user,"~ts",[io:get_line(user, "")]) end}, + {expect, "test\\."}, + {eval, fun() -> shell:start_interactive() end}, + {expect, "1>"}, + {putline, "test."}, + {expect, "2>"} + ],[],"",["-noinput","-eval","io:format(\"eval_test~n\")"] ++ ExtraArgs), + + %% Test that we can start various remote shell combos + [ begin + {ok, Peer, Node} = ?CT_PEER(), + SNode = atom_to_list(Node), + rtnode:run( + [{expect, "eval_test"}, + {putline, "test."}, + {eval, fun() -> shell:start_interactive(Arg(Node)) end}, + {expect, "\\Q("++SNode++")\\E2>"} + ] ++ quit_hosting_node(), + [],"",["-noinput","-eval","io:format(\"eval_test~n\")"] ++ ExtraArgs), + peer:stop(Peer) + end || Arg <- [fun(Node) -> {Node, {shell,start,[]}} end, + fun(Node) -> {remote, atom_to_list(Node)} end, + fun(Node) -> {remote, hd(string:split(atom_to_list(Node),"@"))} end, + fun(Node) -> {remote, atom_to_list(Node), {shell,start,[]}} end + ]], + + %% Test that errors work as they should + {ok, Peer, Node} = ?CT_PEER(), + rtnode:run( + [{expect, "eval_test"}, + {eval, fun() -> + {error,noconnection} = shell:start_interactive( + {remote,"invalid_node"}), + {error,noconnection} = shell:start_interactive( + {remote,"invalid_node", + {invalid_module, start, []}}), + {error,nofile} = shell:start_interactive( + {remote,atom_to_list(Node), + {invalid_module, start, []}}), + shell:start_interactive({remote, atom_to_list(Node)}) + end}, + {expect, "1> $"} + ] ++ quit_hosting_node(), + [],"",["-noinput","-eval","io:format(\"eval_test~n\")"] ++ ExtraArgs), + peer:stop(Peer), + + ok. + +whereis(_Config) -> + Proxy = spawn_link( + fun() -> + (fun F(P) -> + receive + {set,NewPid} -> + F(NewPid); + {get,From} -> + From ! P, + F(P) + end + end)(undefined) + end), + + %% Test that shell:whereis() works with JCL in newshell + rtnode:run( + [{expect,"1> $"}, + {putline,"shell:whereis()."}, + {expect,"2> $"}, + {eval,fun() -> + group_leader(erlang:whereis(user),self()), + Proxy ! {set,shell:whereis()}, + ok + end}, + {putline,"\^g"}, + {expect, "--> $"}, + {putline, "s"}, + {expect, "--> $"}, + {putline, "c"}, + {expect, "\r\nEshell"}, + {putline,"shell:whereis()."}, + {expect,"2> $"}, + {eval,fun() -> + group_leader(erlang:whereis(user),self()), + Proxy ! {get, self()}, + receive PrevPid -> PrevPid end, + io:format("~p =:= ~p~n",[PrevPid, shell:whereis()]), + false = PrevPid =:= shell:whereis(), + ok + end}, + {putline,"\^g"}, + {expect, "--> $"}, + {putline, "c 1"}, + {expect, "\r\n"}, + {putline, ""}, + {expect, "2> $"}, + {eval,fun() -> + group_leader(erlang:whereis(user),self()), + Proxy ! {get, self()}, + receive PrevPid -> PrevPid end, + true = PrevPid =:= shell:whereis(), + ok + end}]), + + %% Test that shell:whereis() works in oldshell + rtnode:run( + [{expect,"1>"}, + {eval,fun() -> + group_leader(erlang:whereis(user),self()), + true = is_pid(shell:whereis()), + ok + end}], + [],"",["-env","TERM","dumb"]), + + %% Test that noinput and noshell gives undefined shell process + rtnode:run( + [{eval,fun() -> + group_leader(erlang:whereis(user),self()), + undefined = shell:whereis(), + ok + end}], + [],"",["-noinput"]), + rtnode:run( + [{eval,fun() -> + group_leader(erlang:whereis(user),self()), + undefined = shell:whereis(), + ok + end}], + [],"",["-noshell"]), + + %% Test that remsh gives the correct shell process + {ok, Peer, Node} = ?CT_PEER(), + NodeStr = lists:flatten(io_lib:format("~w",[Node])), + rtnode:run( + [{expect, "1>"}, + {putline,"shell:whereis()."}, + {expect,"\n<0[.]"}, + {expect, "2>"}, + {eval, fun() -> + group_leader(erlang:whereis(user),self()), + true = Node =:= node(shell:whereis()), + ok + end}] ++ quit_hosting_node(), + peer:random_name(?FUNCTION_NAME), " ", "-remsh " ++ NodeStr ++ + " -pa " ++ filename:dirname(code:which(?MODULE))), + + peer:stop(Peer), + + ok. + +quit_hosting_node() -> + [{putline, "\^g"}, + {expect, "--> $"}, + {putline, "s"}, + {expect, "--> $"}, + {putline, "c"}, + {expect, ["Eshell"]}, + {expect, ["1> $"]}]. + term_to_string(T) -> lists:flatten(io_lib:format("~w", [T])). scan(B) -> - F = fun(Ts) -> + F = fun(Ts) -> case erl_parse:parse_term(Ts) of {ok,Term} -> Term; @@ -3065,18 +3307,18 @@ t1(Parent, {Bin,Enc}, F) -> S = #state{bin = Bin, unic = Enc, reply = [], leader = group_leader()}, group_leader(self(), self()), _Shell = F(), - try + try server_loop(S) catch exit:R -> Parent ! {self(), R}; throw:{?MODULE,LoopReply,latin1} -> - L0 = binary_to_list(list_to_binary(LoopReply)), - [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0), - Parent ! {self(), dotify(L1)}; + L0 = binary_to_list(list_to_binary(LoopReply)), + [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0), + Parent ! {self(), dotify(L1)}; throw:{?MODULE,LoopReply,_Uni} -> - Tmp = unicode:characters_to_binary(LoopReply), - L0 = unicode:characters_to_list(Tmp), - [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0), - Parent ! {self(), dotify(L1)} + Tmp = unicode:characters_to_binary(LoopReply), + L0 = unicode:characters_to_list(Tmp), + [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0), + Parent ! {self(), dotify(L1)} after group_leader(S#state.leader, self()) end. @@ -3108,20 +3350,20 @@ start_new_shell(Node) -> %% This is a very minimal implementation of the IO protocol... server_loop(S) -> - receive + receive {io_request, From, ReplyAs, Request} when is_pid(From) -> - server_loop(do_io_request(Request, From, S, ReplyAs)); - NotExpected -> + server_loop(do_io_request(Request, From, S, ReplyAs)); + NotExpected -> exit(NotExpected) end. - + do_io_request(Req, From, S, ReplyAs) -> case io_requests([Req], [], S) of {_Status,{eof,_},S1} -> - io_reply(From, ReplyAs, {error,terminated}), - throw({?MODULE,S1#state.reply,S1#state.unic}); - {_Status,Reply,S1} -> - io_reply(From, ReplyAs, Reply), + io_reply(From, ReplyAs, {error,terminated}), + throw({?MODULE,S1#state.reply,S1#state.unic}); + {_Status,Reply,S1} -> + io_reply(From, ReplyAs, Reply), S1 end. @@ -3139,7 +3381,7 @@ io_requests([R | Rs], Cont, S) -> end; io_requests([], [Rs|Cont], S) -> io_requests(Rs, Cont, S); -io_requests([], [], S) -> +io_requests([], [], S) -> {ok,ok,S}. io_request({setopts, Opts}, S) -> @@ -3171,7 +3413,7 @@ io_request({put_chars,unicode,Chars0}, S) -> {ok,ok,S#state{reply = [S#state.reply | Chars]}}; io_request({put_chars,Enc,Mod,Func,Args}, S) -> case catch apply(Mod, Func, Args) of - Chars when is_list(Chars) -> + Chars when is_list(Chars) -> io_request({put_chars,Enc,Chars}, S) end; io_request({get_until,Enc,_Prompt,Mod,Func,ExtraArgs}, S) -> @@ -3184,7 +3426,7 @@ get_until_loop(M, F, As, S, {more,Cont}, Enc) -> Bin = S#state.bin, case byte_size(Bin) of 0 -> - get_until_loop(M, F, As, S, + get_until_loop(M, F, As, S, catch apply(M, F, [Cont,eof|As]), Enc); _ when S#state.unic =:= latin1 -> get_until_loop(M, F, As, S#state{bin = <<>>}, @@ -3214,7 +3456,7 @@ run_file(Config, Module, Test) -> ok = file:write_file(FileName, Test), ok = compile_file(Config, FileName, Test, []), code:purge(Module), - {module, Module} = code:load_abs(LoadBeamFile), + {module, Module} = code:load_abs(LoadBeamFile), ok = Module:t(), file:delete(FileName), file:delete(BeamFile), @@ -3233,11 +3475,6 @@ filename(Name, Config) when is_atom(Name) -> filename(Name, Config) -> filename:join(proplists:get_value(priv_dir, Config), Name). -start_node(Name, Xargs) -> - N = test_server:start_node(Name, slave, [{args, " " ++ Xargs}]), - global:sync(), - N. - purge_and_delete(Module) -> (catch code:purge(Module)), (catch code:delete(Module)). diff --git a/lib/stdlib/test/shell_docs_SUITE.erl b/lib/stdlib/test/shell_docs_SUITE.erl index ba0f256df96b..97a9a73d712a 100644 --- a/lib/stdlib/test/shell_docs_SUITE.erl +++ b/lib/stdlib/test/shell_docs_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2020-2021. All Rights Reserved. +%% Copyright Ericsson AB 2020-2023. 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. @@ -70,7 +70,7 @@ end_per_group(_GroupName, Config) -> %% tested. %% %% Currently the modules are: --define(RENDER_MODULES, [sofs, re, file, erlang]). +-define(RENDER_MODULES, [sofs, re, file, erlang, user_drv, ?MODULE]). %% If you need to update the definition because this %% testcase fails, just run update_render/0,1. render(Config) -> @@ -88,7 +88,12 @@ render(Config) -> {ok, Original} -> ct:log("Original: ~n~ts",[Original]), ct:log("Current : ~n~ts",[Current]), - ct:fail(output_changed) + ct:fail(output_changed); + {error, enoent} -> + %% All modules are not available on all + %% platforms. For instance socket is not + %% available on windows. + ok end end, render_module(Module, D)) end, ?RENDER_MODULES). @@ -108,7 +113,9 @@ update_render(DataDir) -> maps:map( fun(FName, Output) -> ok = file:write_file(filename:join(DataDir, FName), Output) - end, render_module(Module, D)) + end, render_module(Module, D)); + E -> + io:format("Error processing: ~p ~p",[Module, E]) end end, ?RENDER_MODULES). @@ -248,14 +255,15 @@ render_non_native(_Config) -> beam_language = not_erlang, format = <<"text/asciidoc">>, module_doc = #{<<"en">> => <<"This is\n\npure text">>}, - docs= [] + docs = [] }, <<"\n\tnot_an_erlang_module\n\n" " This is\n" " \n" " pure text\n">> = - unicode:characters_to_binary(shell_docs:render(not_an_erlang_module, Docs, #{})), + unicode:characters_to_binary( + shell_docs:render(not_an_erlang_module, Docs, #{ ansi => false })), ok. @@ -275,8 +283,8 @@ render_all(Dir) -> docsmap(fun(Mod, D) -> maps:map( fun(FName, Value) -> - file:write_file(filename:join(Dir, FName), Value) end, - render_module(Mod, D)) + file:write_file(filename:join(Dir, FName), Value) + end, render_module(Mod, D)) end). render_module(Mod, #docs_v1{ docs = Docs } = D) -> @@ -315,7 +323,11 @@ render_module(Mod, #docs_v1{ docs = Docs } = D) -> end, Files, Docs). sanitize(FName) -> - re:replace(FName,"[/:]","_",[global,{return,list}]). + lists:foldl( + fun({Re,Replace}, Txt) -> + re:replace(Txt,Re,Replace,[global,{return,list}]) + end, FName, [{"/","slash"},{":","colon"}, + {"\\*","star"},{"<","lt"},{">","gt"},{"=","eq"}]). docsmap(Fun) -> lists:map( diff --git a/lib/stdlib/test/shell_docs_SUITE_data/erlang.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/erlang.docs_v1 index 71704fff5a8a..86c2e27a2c7d 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/erlang.docs_v1 +++ b/lib/stdlib/test/shell_docs_SUITE_data/erlang.docs_v1 @@ -1 +1 @@ -{docs_v1,[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<66,121,32,99,111,110,118,101,110,116,105,111,110,44,32,109,111,115,116,32,66,117,105,108,116,45,73,110,32,70,117,110,99,116,105,111,110,115,32,40,66,73,70,115,41,32,97,114,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,46,32,83,111,109,101,32,111,102,32,116,104,101,32,66,73,70,115,32,97,114,101,32,118,105,101,119,101,100,32,109,111,114,101,32,111,114,32,108,101,115,115,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,32,97,110,100,32,97,114,101,32>>,{em,[],[<<97,117,116,111,45,105,109,112,111,114,116,101,100>>]},<<46,32,84,104,117,115,44,32,105,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,121,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,109,111,100,117,108,101,32,110,97,109,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,97,108,108,115,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,101,114,108,97,110,103,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,97,116,111,109,95,116,111,95,108,105,115,116,40,101,114,108,97,110,103,41>>]},<<32,97,114,101,32,105,100,101,110,116,105,99,97,108,46>>]},{p,[],[<<65,117,116,111,45,105,109,112,111,114,116,101,100,32,66,73,70,115,32,97,114,101,32,108,105,115,116,101,100,32,119,105,116,104,111,117,116,32,109,111,100,117,108,101,32,112,114,101,102,105,120,46,32,66,73,70,115,32,108,105,115,116,101,100,32,119,105,116,104,32,109,111,100,117,108,101,32,112,114,101,102,105,120,32,97,114,101,32,110,111,116,32,97,117,116,111,45,105,109,112,111,114,116,101,100,46>>]},{p,[],[<<66,73,70,115,32,99,97,110,32,102,97,105,108,32,102,111,114,32,118,97,114,105,111,117,115,32,114,101,97,115,111,110,115,46,32,65,108,108,32,66,73,70,115,32,102,97,105,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,121,32,97,114,101,32,99,97,108,108,101,100,32,119,105,116,104,32,97,114,103,117,109,101,110,116,115,32,111,102,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,46,32,84,104,101,32,111,116,104,101,114,32,114,101,97,115,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,101,97,99,104,32,105,110,100,105,118,105,100,117,97,108,32,66,73,70,46>>]},{p,[],[<<83,111,109,101,32,66,73,70,115,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,32,97,110,100,32,97,114,101,32,109,97,114,107,101,100,32,119,105,116,104,32,34,65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,34,46>>]}]},#{name => <<101,114,108,97,110,103>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,101,114,108,97,110,103,46,120,109,108],types => #{{time_unit,0} => {attribute,93,type,{time_unit,{type,94,union,[{type,94,pos_integer,[]},{atom,95,second},{atom,96,millisecond},{atom,97,microsecond},{atom,98,nanosecond},{atom,99,native},{atom,100,perf_counter},{user_type,101,deprecated_time_unit,[]}]},[]}},{prepared_code,0} => {attribute,110,opaque,{prepared_code,{type,110,reference,[]},[]}},{nif_resource,0} => {attribute,113,opaque,{nif_resource,{type,113,reference,[]},[]}},{system_monitor_option,0} => {attribute,274,type,{system_monitor_option,{type,275,union,[{atom,275,busy_port},{atom,276,busy_dist_port},{type,277,tuple,[{atom,277,long_gc},{type,277,non_neg_integer,[]}]},{type,278,tuple,[{atom,278,long_schedule},{type,278,non_neg_integer,[]}]},{type,279,tuple,[{atom,279,large_heap},{type,279,non_neg_integer,[]}]}]},[]}},{module_info_key,0} => {attribute,2123,type,{module_info_key,{type,2123,union,[{atom,2123,attributes},{atom,2123,compile},{atom,2123,exports},{atom,2123,functions},{atom,2123,md5},{atom,2124,module},{atom,2124,native},{atom,2124,native_addresses},{atom,2124,nifs}]},[]}},{trace_info_flag,0} => {attribute,327,type,{trace_info_flag,{type,328,union,[{atom,328,send},{atom,329,'receive'},{atom,330,set_on_spawn},{atom,331,call},{atom,332,return_to},{atom,333,procs},{atom,334,set_on_first_spawn},{atom,335,set_on_link},{atom,336,running},{atom,337,garbage_collection},{atom,338,timestamp},{atom,339,monotonic_timestamp},{atom,340,strict_monotonic_timestamp},{atom,341,arity}]},[]}},{ext_iovec,0} => {attribute,88,type,{ext_iovec,{user_type,88,iovec,[]},[]}},{trace_match_spec,0} => {attribute,2702,type,{trace_match_spec,{type,2703,list,[{type,2703,tuple,[{type,2703,union,[{type,2703,list,[{type,2703,term,[]}]},{atom,2703,'_'},{user_type,2703,match_variable,[]}]},{type,2703,list,[{type,2703,term,[]}]},{type,2703,list,[{type,2703,term,[]}]}]}]},[]}},{max_heap_size,0} => {attribute,2981,type,{max_heap_size,{ann_type,2982,[{var,2982,'Size'},{type,2982,union,[{type,2982,non_neg_integer,[]},{type,2984,map,[{type,2984,map_field_assoc,[{atom,2984,size},{type,2984,non_neg_integer,[]}]},{type,2985,map_field_assoc,[{atom,2985,kill},{type,2985,boolean,[]}]},{type,2986,map_field_assoc,[{atom,2986,error_logger},{type,2986,boolean,[]}]}]}]}]},[]}},{fun_info_item,0} => {attribute,247,type,{fun_info_item,{type,248,union,[{atom,248,arity},{atom,249,env},{atom,250,index},{atom,251,name},{atom,252,module},{atom,253,new_index},{atom,254,new_uniq},{atom,255,pid},{atom,256,type},{atom,257,uniq}]},[]}},{stack_item,0} => {attribute,2472,type,{stack_item,{type,2473,tuple,[{ann_type,2473,[{var,2473,'Module'},{type,2473,module,[]}]},{ann_type,2474,[{var,2474,'Function'},{type,2474,atom,[]}]},{ann_type,2475,[{var,2475,'Arity'},{type,2475,union,[{type,2475,arity,[]},{ann_type,2475,[{var,2475,'Args'},{type,2475,list,[{type,2475,term,[]}]}]}]}]},{ann_type,2476,[{var,2476,'Location'},{type,2476,list,[{type,2476,union,[{type,2476,tuple,[{atom,2476,file},{ann_type,2476,[{var,2476,'Filename'},{type,2476,string,[]}]}]},{type,2477,tuple,[{atom,2477,line},{ann_type,2477,[{var,2477,'Line'},{type,2477,pos_integer,[]}]}]}]}]}]}]},[]}},{monitor_option,0} => {attribute,1397,type,{monitor_option,{type,1397,union,[{type,1397,tuple,[{atom,1397,alias},{type,1397,union,[{atom,1397,explicit_unalias},{atom,1397,demonitor},{atom,1397,reply_demonitor}]}]},{type,1398,tuple,[{atom,1398,tag},{type,1398,term,[]}]}]},[]}},{trace_flag,0} => {attribute,291,type,{trace_flag,{type,292,union,[{atom,292,all},{atom,293,send},{atom,294,'receive'},{atom,295,procs},{atom,296,ports},{atom,297,call},{atom,298,arity},{atom,299,return_to},{atom,300,silent},{atom,301,running},{atom,302,exiting},{atom,303,running_procs},{atom,304,running_ports},{atom,305,garbage_collection},{atom,306,timestamp},{atom,307,cpu_timestamp},{atom,308,monotonic_timestamp},{atom,309,strict_monotonic_timestamp},{atom,310,set_on_spawn},{atom,311,set_on_first_spawn},{atom,312,set_on_link},{atom,313,set_on_first_link},{type,314,tuple,[{atom,314,tracer},{type,314,union,[{type,314,pid,[]},{type,314,port,[]}]}]},{type,315,tuple,[{atom,315,tracer},{type,315,module,[]},{type,315,term,[]}]}]},[]}},{sub_level,0} => {attribute,2760,type,{sub_level,{type,2760,union,[{type,2760,list,[{ann_type,2760,[{var,2760,'LevelEntry'},{user_type,2760,level_entry,[]}]}]},{ann_type,2761,[{var,2761,'LogicalCpuId'},{type,2761,tuple,[{atom,2761,logical},{type,2761,non_neg_integer,[]}]}]}]},[]}},{monitor_port_identifier,0} => {attribute,1396,type,{monitor_port_identifier,{type,1396,union,[{type,1396,port,[]},{user_type,1396,registered_name,[]}]},[]}},{iovec,0} => {attribute,119,type,{iovec,{type,119,list,[{type,119,binary,[]}]},[]}},{ext_binary,0} => {attribute,87,type,{ext_binary,{type,87,binary,[]},[]}},{registered_process_identifier,0} => {attribute,1394,type,{registered_process_identifier,{type,1394,union,[{user_type,1394,registered_name,[]},{type,1394,tuple,[{user_type,1394,registered_name,[]},{type,1394,node,[]}]}]},[]}},{process_info_result_item,0} => {attribute,2425,type,{process_info_result_item,{type,2426,union,[{type,2426,tuple,[{atom,2426,backtrace},{ann_type,2426,[{var,2426,'Bin'},{type,2426,binary,[]}]}]},{type,2427,tuple,[{atom,2427,binary},{ann_type,2427,[{var,2427,'BinInfo'},{type,2427,list,[{type,2427,tuple,[{type,2427,non_neg_integer,[]},{type,2428,non_neg_integer,[]},{type,2429,non_neg_integer,[]}]}]}]}]},{type,2430,tuple,[{atom,2430,catchlevel},{ann_type,2430,[{var,2430,'CatchLevel'},{type,2430,non_neg_integer,[]}]}]},{type,2431,tuple,[{atom,2431,current_function},{type,2432,union,[{type,2432,tuple,[{ann_type,2432,[{var,2432,'Module'},{type,2432,module,[]}]},{ann_type,2432,[{var,2432,'Function'},{type,2432,atom,[]}]},{ann_type,2432,[{var,2432,'Arity'},{type,2432,arity,[]}]}]},{atom,2432,undefined}]}]},{type,2433,tuple,[{atom,2433,current_location},{type,2434,tuple,[{ann_type,2434,[{var,2434,'Module'},{type,2434,module,[]}]},{ann_type,2434,[{var,2434,'Function'},{type,2434,atom,[]}]},{ann_type,2434,[{var,2434,'Arity'},{type,2434,arity,[]}]},{ann_type,2435,[{var,2435,'Location'},{type,2435,list,[{type,2435,union,[{type,2435,tuple,[{atom,2435,file},{ann_type,2435,[{var,2435,'Filename'},{type,2435,string,[]}]}]},{type,2436,tuple,[{atom,2436,line},{ann_type,2436,[{var,2436,'Line'},{type,2436,pos_integer,[]}]}]}]}]}]}]}]},{type,2437,tuple,[{atom,2437,current_stacktrace},{ann_type,2437,[{var,2437,'Stack'},{type,2437,list,[{user_type,2437,stack_item,[]}]}]}]},{type,2438,tuple,[{atom,2438,dictionary},{ann_type,2438,[{var,2438,'Dictionary'},{type,2438,list,[{type,2438,tuple,[{ann_type,2438,[{var,2438,'Key'},{type,2438,term,[]}]},{ann_type,2438,[{var,2438,'Value'},{type,2438,term,[]}]}]}]}]}]},{type,2439,tuple,[{atom,2439,error_handler},{ann_type,2439,[{var,2439,'Module'},{type,2439,module,[]}]}]},{type,2440,tuple,[{atom,2440,garbage_collection},{ann_type,2440,[{var,2440,'GCInfo'},{type,2440,list,[{type,2440,tuple,[{type,2440,atom,[]},{type,2440,non_neg_integer,[]}]}]}]}]},{type,2441,tuple,[{atom,2441,garbage_collection_info},{ann_type,2441,[{var,2441,'GCInfo'},{type,2441,list,[{type,2441,tuple,[{type,2441,atom,[]},{type,2441,non_neg_integer,[]}]}]}]}]},{type,2442,tuple,[{atom,2442,group_leader},{ann_type,2442,[{var,2442,'GroupLeader'},{type,2442,pid,[]}]}]},{type,2443,tuple,[{atom,2443,heap_size},{ann_type,2443,[{var,2443,'Size'},{type,2443,non_neg_integer,[]}]}]},{type,2444,tuple,[{atom,2444,initial_call},{type,2444,mfa,[]}]},{type,2445,tuple,[{atom,2445,links},{ann_type,2445,[{var,2445,'PidsAndPorts'},{type,2445,list,[{type,2445,union,[{type,2445,pid,[]},{type,2445,port,[]}]}]}]}]},{type,2446,tuple,[{atom,2446,last_calls},{type,2446,union,[{atom,2446,false},{ann_type,2446,[{var,2446,'Calls'},{type,2446,list,[{type,2446,mfa,[]}]}]}]}]},{type,2447,tuple,[{atom,2447,memory},{ann_type,2447,[{var,2447,'Size'},{type,2447,non_neg_integer,[]}]}]},{type,2448,tuple,[{atom,2448,message_queue_len},{ann_type,2448,[{var,2448,'MessageQueueLen'},{type,2448,non_neg_integer,[]}]}]},{type,2449,tuple,[{atom,2449,messages},{ann_type,2449,[{var,2449,'MessageQueue'},{type,2449,list,[{type,2449,term,[]}]}]}]},{type,2450,tuple,[{atom,2450,min_heap_size},{ann_type,2450,[{var,2450,'MinHeapSize'},{type,2450,non_neg_integer,[]}]}]},{type,2451,tuple,[{atom,2451,min_bin_vheap_size},{ann_type,2451,[{var,2451,'MinBinVHeapSize'},{type,2451,non_neg_integer,[]}]}]},{type,2452,tuple,[{atom,2452,max_heap_size},{ann_type,2452,[{var,2452,'MaxHeapSize'},{user_type,2452,max_heap_size,[]}]}]},{type,2453,tuple,[{atom,2453,monitored_by},{ann_type,2453,[{var,2453,'MonitoredBy'},{type,2453,list,[{type,2453,union,[{type,2453,pid,[]},{type,2453,port,[]},{user_type,2453,nif_resource,[]}]}]}]}]},{type,2454,tuple,[{atom,2454,monitors},{ann_type,2455,[{var,2455,'Monitors'},{type,2455,list,[{type,2455,tuple,[{type,2455,union,[{atom,2455,process},{atom,2455,port}]},{ann_type,2455,[{var,2455,'Pid'},{type,2455,union,[{type,2455,pid,[]},{type,2455,port,[]},{type,2456,tuple,[{ann_type,2456,[{var,2456,'RegName'},{type,2456,atom,[]}]},{ann_type,2456,[{var,2456,'Node'},{type,2456,node,[]}]}]}]}]}]}]}]}]},{type,2457,tuple,[{atom,2457,message_queue_data},{ann_type,2457,[{var,2457,'MQD'},{user_type,2457,message_queue_data,[]}]}]},{type,2458,tuple,[{atom,2458,priority},{ann_type,2458,[{var,2458,'Level'},{user_type,2458,priority_level,[]}]}]},{type,2459,tuple,[{atom,2459,reductions},{ann_type,2459,[{var,2459,'Number'},{type,2459,non_neg_integer,[]}]}]},{type,2460,tuple,[{atom,2460,registered_name},{type,2460,union,[{type,2460,nil,[]},{ann_type,2460,[{var,2460,'Atom'},{type,2460,atom,[]}]}]}]},{type,2461,tuple,[{atom,2461,sequential_trace_token},{type,2461,union,[{type,2461,nil,[]},{ann_type,2461,[{var,2461,'SequentialTraceToken'},{type,2461,term,[]}]}]}]},{type,2462,tuple,[{atom,2462,stack_size},{ann_type,2462,[{var,2462,'Size'},{type,2462,non_neg_integer,[]}]}]},{type,2463,tuple,[{atom,2463,status},{ann_type,2463,[{var,2463,'Status'},{type,2463,union,[{atom,2463,exiting},{atom,2463,garbage_collecting},{atom,2463,waiting},{atom,2463,running},{atom,2463,runnable},{atom,2463,suspended}]}]}]},{type,2464,tuple,[{atom,2464,suspending},{ann_type,2465,[{var,2465,'SuspendeeList'},{type,2465,list,[{type,2465,tuple,[{ann_type,2465,[{var,2465,'Suspendee'},{type,2465,pid,[]}]},{ann_type,2466,[{var,2466,'ActiveSuspendCount'},{type,2466,non_neg_integer,[]}]},{ann_type,2467,[{var,2467,'OutstandingSuspendCount'},{type,2467,non_neg_integer,[]}]}]}]}]}]},{type,2468,tuple,[{atom,2468,total_heap_size},{ann_type,2468,[{var,2468,'Size'},{type,2468,non_neg_integer,[]}]}]},{type,2469,tuple,[{atom,2469,trace},{ann_type,2469,[{var,2469,'InternalTraceFlags'},{type,2469,non_neg_integer,[]}]}]},{type,2470,tuple,[{atom,2470,trap_exit},{ann_type,2470,[{var,2470,'Boolean'},{type,2470,boolean,[]}]}]}]},[]}},{seq_trace_info_returns,0} => {attribute,259,type,{seq_trace_info_returns,{type,260,union,[{type,260,tuple,[{type,260,union,[{atom,260,send},{atom,260,'receive'},{atom,260,print},{atom,260,timestamp},{atom,260,monotonic_timestamp},{atom,260,strict_monotonic_timestamp}]},{type,260,boolean,[]}]},{type,261,tuple,[{atom,261,label},{type,261,term,[]}]},{type,262,tuple,[{atom,262,serial},{type,262,tuple,[{type,262,non_neg_integer,[]},{type,262,non_neg_integer,[]}]}]},{type,263,nil,[]}]},[]}},{process_info_item,0} => {attribute,2390,type,{process_info_item,{type,2391,union,[{atom,2391,backtrace},{atom,2392,binary},{atom,2393,catchlevel},{atom,2394,current_function},{atom,2395,current_location},{atom,2396,current_stacktrace},{atom,2397,dictionary},{atom,2398,error_handler},{atom,2399,garbage_collection},{atom,2400,garbage_collection_info},{atom,2401,group_leader},{atom,2402,heap_size},{atom,2403,initial_call},{atom,2404,links},{atom,2405,last_calls},{atom,2406,memory},{atom,2407,message_queue_len},{atom,2408,messages},{atom,2409,min_heap_size},{atom,2410,min_bin_vheap_size},{atom,2411,monitored_by},{atom,2412,monitors},{atom,2413,message_queue_data},{atom,2414,priority},{atom,2415,reductions},{atom,2416,registered_name},{atom,2417,sequential_trace_token},{atom,2418,stack_size},{atom,2419,status},{atom,2420,suspending},{atom,2421,total_heap_size},{atom,2422,trace},{atom,2423,trap_exit}]},[]}},{trace_info_return,0} => {attribute,343,type,{trace_info_return,{type,344,union,[{atom,344,undefined},{type,345,tuple,[{atom,345,flags},{type,345,list,[{user_type,345,trace_info_flag,[]}]}]},{type,346,tuple,[{atom,346,tracer},{type,346,union,[{type,346,pid,[]},{type,346,port,[]},{type,346,nil,[]}]}]},{type,347,tuple,[{atom,347,tracer},{type,347,module,[]},{type,347,term,[]}]},{user_type,348,trace_info_item_result,[]},{type,349,tuple,[{atom,349,all},{type,349,union,[{type,349,list,[{user_type,349,trace_info_item_result,[]}]},{atom,349,false},{atom,349,undefined}]}]}]},[]}},{trace_info_item_result,0} => {attribute,317,type,{trace_info_item_result,{type,318,union,[{type,318,tuple,[{atom,318,traced},{type,318,union,[{atom,318,global},{atom,318,local},{atom,318,false},{atom,318,undefined}]}]},{type,319,tuple,[{atom,319,match_spec},{type,319,union,[{user_type,319,trace_match_spec,[]},{atom,319,false},{atom,319,undefined}]}]},{type,320,tuple,[{atom,320,meta},{type,320,union,[{type,320,pid,[]},{type,320,port,[]},{atom,320,false},{atom,320,undefined},{type,320,nil,[]}]}]},{type,321,tuple,[{atom,321,meta},{type,321,module,[]},{type,321,term,[]}]},{type,322,tuple,[{atom,322,meta_match_spec},{type,322,union,[{user_type,322,trace_match_spec,[]},{atom,322,false},{atom,322,undefined}]}]},{type,323,tuple,[{atom,323,call_count},{type,323,union,[{type,323,non_neg_integer,[]},{type,323,boolean,[]},{atom,323,undefined}]}]},{type,324,tuple,[{atom,324,call_time},{type,324,union,[{type,324,list,[{type,324,tuple,[{type,324,pid,[]},{type,324,non_neg_integer,[]},{type,325,non_neg_integer,[]},{type,325,non_neg_integer,[]}]}]},{type,325,boolean,[]},{atom,325,undefined}]}]}]},[]}},{trace_pattern_mfa,0} => {attribute,2700,type,{trace_pattern_mfa,{type,2701,union,[{type,2701,tuple,[{type,2701,atom,[]},{type,2701,atom,[]},{type,2701,union,[{type,2701,arity,[]},{atom,2701,'_'}]}]},{atom,2701,on_load}]},[]}},{registered_name,0} => {attribute,1393,type,{registered_name,{type,1393,atom,[]},[]}},{dist_handle,0} => {attribute,116,opaque,{dist_handle,{type,116,atom,[]},[]}},{info_list,0} => {attribute,2762,type,{info_list,{type,2762,nil,[]},[]}},{cpu_topology,0} => {attribute,2752,type,{cpu_topology,{type,2753,union,[{type,2753,list,[{ann_type,2753,[{var,2753,'LevelEntry'},{user_type,2753,level_entry,[]}]}]},{atom,2753,undefined}]},[]}},{memory_type,0} => {attribute,3977,type,{memory_type,{type,3977,union,[{atom,3977,total},{atom,3977,processes},{atom,3977,processes_used},{atom,3977,system},{atom,3978,atom},{atom,3978,atom_used},{atom,3978,binary},{atom,3978,code},{atom,3978,ets}]},[]}},{level_tag,0} => {attribute,2759,type,{level_tag,{type,2759,union,[{atom,2759,core},{atom,2759,node},{atom,2759,processor},{atom,2759,thread}]},[]}},{timestamp,0} => {attribute,89,type,{timestamp,{type,89,tuple,[{ann_type,89,[{var,89,'MegaSecs'},{type,89,non_neg_integer,[]}]},{ann_type,90,[{var,90,'Secs'},{type,90,non_neg_integer,[]}]},{ann_type,91,[{var,91,'MicroSecs'},{type,91,non_neg_integer,[]}]}]},[]}},{deprecated_time_unit,0} => {attribute,104,type,{deprecated_time_unit,{type,105,union,[{atom,105,seconds},{atom,106,milli_seconds},{atom,107,micro_seconds},{atom,108,nano_seconds}]},[]}},{spawn_opt_option,0} => {attribute,2988,type,{spawn_opt_option,{type,2989,union,[{atom,2989,link},{atom,2990,monitor},{type,2991,tuple,[{atom,2991,monitor},{ann_type,2991,[{var,2991,'MonitorOpts'},{type,2991,list,[{user_type,2991,monitor_option,[]}]}]}]},{type,2992,tuple,[{atom,2992,priority},{ann_type,2992,[{var,2992,'Level'},{user_type,2992,priority_level,[]}]}]},{type,2993,tuple,[{atom,2993,fullsweep_after},{ann_type,2993,[{var,2993,'Number'},{type,2993,non_neg_integer,[]}]}]},{type,2994,tuple,[{atom,2994,min_heap_size},{ann_type,2994,[{var,2994,'Size'},{type,2994,non_neg_integer,[]}]}]},{type,2995,tuple,[{atom,2995,min_bin_vheap_size},{ann_type,2995,[{var,2995,'VSize'},{type,2995,non_neg_integer,[]}]}]},{type,2996,tuple,[{atom,2996,max_heap_size},{ann_type,2996,[{var,2996,'Size'},{user_type,2996,max_heap_size,[]}]}]},{type,2997,tuple,[{atom,2997,message_queue_data},{ann_type,2997,[{var,2997,'MQD'},{user_type,2997,message_queue_data,[]}]}]}]},[]}},{dst,0} => {attribute,3452,type,{dst,{type,3452,union,[{type,3452,pid,[]},{type,3453,reference,[]},{type,3454,port,[]},{ann_type,3455,[{var,3455,'RegName'},{type,3455,atom,[]}]},{type,3456,tuple,[{ann_type,3456,[{var,3456,'RegName'},{type,3456,atom,[]}]},{ann_type,3456,[{var,3456,'Node'},{type,3456,node,[]}]}]}]},[]}},{bitstring_list,0} => {attribute,288,type,{bitstring_list,{type,289,maybe_improper_list,[{type,289,union,[{type,289,byte,[]},{type,289,bitstring,[]},{user_type,289,bitstring_list,[]}]},{type,289,union,[{type,289,bitstring,[]},{type,289,nil,[]}]}]},[]}},{match_variable,0} => {attribute,2699,type,{match_variable,{type,2699,atom,[]},[]}},{monitor_process_identifier,0} => {attribute,1395,type,{monitor_process_identifier,{type,1395,union,[{type,1395,pid,[]},{user_type,1395,registered_process_identifier,[]}]},[]}},{scheduler_bind_type,0} => {attribute,2596,type,{scheduler_bind_type,{type,2597,union,[{atom,2597,no_node_processor_spread},{atom,2598,no_node_thread_spread},{atom,2599,no_spread},{atom,2600,processor_spread},{atom,2601,spread},{atom,2602,thread_spread},{atom,2603,thread_no_node_processor_spread},{atom,2604,unbound}]},[]}},{trace_pattern_flag,0} => {attribute,2718,type,{trace_pattern_flag,{type,2719,union,[{atom,2719,global},{atom,2719,local},{atom,2720,meta},{type,2720,tuple,[{atom,2720,meta},{ann_type,2720,[{var,2720,'Pid'},{type,2720,pid,[]}]}]},{type,2721,tuple,[{atom,2721,meta},{ann_type,2721,[{var,2721,'TracerModule'},{type,2721,module,[]}]},{ann_type,2721,[{var,2721,'TracerState'},{type,2721,term,[]}]}]},{atom,2722,call_count},{atom,2723,call_time}]},[]}},{system_profile_option,0} => {attribute,265,type,{system_profile_option,{type,266,union,[{atom,266,exclusive},{atom,267,runnable_ports},{atom,268,runnable_procs},{atom,269,scheduler},{atom,270,timestamp},{atom,271,monotonic_timestamp},{atom,272,strict_monotonic_timestamp}]},[]}},{message_queue_data,0} => {attribute,2353,type,{message_queue_data,{type,2354,union,[{atom,2354,off_heap},{atom,2354,on_heap}]},[]}},{raise_stacktrace,0} => {attribute,282,type,{raise_stacktrace,{type,283,union,[{type,283,list,[{type,283,union,[{type,283,tuple,[{type,283,module,[]},{type,283,atom,[]},{type,283,union,[{type,283,arity,[]},{type,283,list,[{type,283,term,[]}]}]}]},{type,284,tuple,[{type,284,function,[]},{type,284,list,[{type,284,term,[]}]}]}]}]},{type,285,list,[{type,285,union,[{type,285,tuple,[{type,285,module,[]},{type,285,atom,[]},{type,285,union,[{type,285,arity,[]},{type,285,list,[{type,285,term,[]}]}]},{type,285,list,[{type,285,tuple,[{type,285,atom,[]},{type,285,term,[]}]}]}]},{type,286,tuple,[{type,286,function,[]},{type,286,list,[{type,286,term,[]}]},{type,286,list,[{type,286,tuple,[{type,286,atom,[]},{type,286,term,[]}]}]}]}]}]}]},[]}},{priority_level,0} => {attribute,2350,type,{priority_level,{type,2351,union,[{atom,2351,low},{atom,2351,normal},{atom,2351,high},{atom,2351,max}]},[]}},{level_entry,0} => {attribute,2754,type,{level_entry,{type,2755,union,[{type,2755,tuple,[{ann_type,2755,[{var,2755,'LevelTag'},{user_type,2755,level_tag,[]}]},{ann_type,2755,[{var,2755,'SubLevel'},{user_type,2755,sub_level,[]}]}]},{type,2756,tuple,[{ann_type,2756,[{var,2756,'LevelTag'},{user_type,2756,level_tag,[]}]},{ann_type,2757,[{var,2757,'InfoList'},{user_type,2757,info_list,[]}]},{ann_type,2758,[{var,2758,'SubLevel'},{user_type,2758,sub_level,[]}]}]}]},[]}}}},[{{function,abs,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2100}],[<<97,98,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,111,114,32,102,108,111,97,116,32,116,104,97,116,32,105,115,32,116,104,101,32,97,114,105,116,104,109,101,116,105,99,97,108,32,97,98,115,111,108,117,116,101,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,111,114,32>>,{code,[],[<<73,110,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,98,115,40,45,51,46,51,51,41,46,10,51,46,51,51,10,62,32,97,98,115,40,45,51,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,54>>,signature => [{attribute,2100,spec,{{abs,1},[{type,2100,bounded_fun,[{type,2100,'fun',[{type,2100,product,[{var,2100,'Float'}]},{type,2100,float,[]}]},[{type,2101,constraint,[{atom,2101,is_subtype},[{var,2101,'Float'},{type,2101,float,[]}]]}]]},{type,2102,bounded_fun,[{type,2102,'fun',[{type,2102,product,[{var,2102,'Int'}]},{type,2102,non_neg_integer,[]}]},[{type,2103,constraint,[{atom,2103,is_subtype},[{var,2103,'Int'},{type,2103,integer,[]}]]}]]}]}}]}},{{function,adler32,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,353}],[<<97,100,108,101,114,51,50,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,32,102,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,51>>,signature => [{attribute,353,spec,{{erlang,adler32,1},[{type,353,bounded_fun,[{type,353,'fun',[{type,353,product,[{var,353,'Data'}]},{type,353,non_neg_integer,[]}]},[{type,354,constraint,[{atom,354,is_subtype},[{var,354,'Data'},{type,354,iodata,[]}]]}]]}]}}]}},{{function,adler32,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,359}],[<<97,100,108,101,114,51,50,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,116,105,110,117,101,115,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,32,98,121,32,99,111,109,98,105,110,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,101,99,107,115,117,109,44,32>>,{code,[],[<<79,108,100,65,100,108,101,114>>]},<<44,32,119,105,116,104,32,116,104,101,32,99,104,101,99,107,115,117,109,32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,88,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<89>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,91,68,97,116,97,49,44,68,97,116,97,50,93,41,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,50>>,signature => [{attribute,359,spec,{{erlang,adler32,2},[{type,359,bounded_fun,[{type,359,'fun',[{type,359,product,[{var,359,'OldAdler'},{var,359,'Data'}]},{type,359,non_neg_integer,[]}]},[{type,360,constraint,[{atom,360,is_subtype},[{var,360,'OldAdler'},{type,360,non_neg_integer,[]}]]},{type,361,constraint,[{atom,361,is_subtype},[{var,361,'Data'},{type,361,iodata,[]}]]}]]}]}}]}},{{function,adler32_combine,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,366}],[<<97,100,108,101,114,51,50,95,99,111,109,98,105,110,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32,116,119,111,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,117,116,101,100,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,115,46,32,84,104,105,115,32,99,111,109,112,117,116,97,116,105,111,110,32,114,101,113,117,105,114,101,115,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,111,98,106,101,99,116,32,102,111,114,32,116,104,101,32,115,101,99,111,110,100,32,99,104,101,99,107,115,117,109,32,116,111,32,98,101,32,107,110,111,119,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,90,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,89,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<90>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,50,41,44,10,90,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,95,99,111,109,98,105,110,101,40,88,44,89,44,105,111,108,105,115,116,95,115,105,122,101,40,68,97,116,97,50,41,41,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,57>>,signature => [{attribute,366,spec,{{erlang,adler32_combine,3},[{type,366,bounded_fun,[{type,366,'fun',[{type,366,product,[{var,366,'FirstAdler'},{var,366,'SecondAdler'},{var,366,'SecondSize'}]},{type,366,non_neg_integer,[]}]},[{type,367,constraint,[{atom,367,is_subtype},[{var,367,'FirstAdler'},{type,367,non_neg_integer,[]}]]},{type,368,constraint,[{atom,368,is_subtype},[{var,368,'SecondAdler'},{type,368,non_neg_integer,[]}]]},{type,369,constraint,[{atom,369,is_subtype},[{var,369,'SecondSize'},{type,369,non_neg_integer,[]}]]}]]}]}}]}},{{function,alias,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,759}],[<<97,108,105,97,115,47,49>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,56>>,equiv => {function,alias,0},signature => [{attribute,759,spec,{{alias,1},[{type,759,bounded_fun,[{type,759,'fun',[{type,759,product,[{var,759,'Opts'}]},{var,759,'Alias'}]},[{type,760,constraint,[{atom,760,is_subtype},[{var,760,'Alias'},{type,760,reference,[]}]]},{type,761,constraint,[{atom,761,is_subtype},[{var,761,'Opts'},{type,761,list,[{type,761,union,[{atom,761,explicit_unalias},{atom,761,reply}]}]}]]}]]}]}}],since => <<79,84,80,32,64,79,84,80,45,49,54,55,49,56,64>>}},{{function,alias,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,753}],[<<97,108,105,97,115,47,48>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,32,97,110,32,97,108,105,97,115,32,119,104,105,99,104,32,99,97,110,32,98,101,32,117,115,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,97,108,105,97,115,46,32,87,104,101,110,32,116,104,101,32,97,108,105,97,115,32,104,97,115,32,98,101,101,110,32,100,101,97,99,116,105,118,97,116,101,100,44,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,117,115,105,110,103,32,116,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,100,114,111,112,112,101,100,46,32,65,110,32,97,108,105,97,115,32,99,97,110,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,97,108,105,97,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,97,108,105,97,115,47,49>>]}]},<<46,32,67,117,114,114,101,110,116,108,121,32,97,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,32,102,111,114,32>>,{code,[],[<<97,108,105,97,115,47,49>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,112,108,105,99,105,116,95,117,110,97,108,105,97,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,99,97,110,32,111,110,108,121,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,117,114,32,105,102,32,110,111,32,111,112,116,105,111,110,115,32,97,114,101,32,112,97,115,115,101,100,32,111,114,32,105,102,32>>,{code,[],[<<97,108,105,97,115,47,48>>]},<<32,105,115,32,99,97,108,108,101,100,46>>]}]},{dt,[],[{code,[],[<<114,101,112,108,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,99,101,105,118,101,100,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,56>>,signature => [{attribute,753,spec,{{alias,0},[{type,753,bounded_fun,[{type,753,'fun',[{type,753,product,[]},{var,753,'Alias'}]},[{type,754,constraint,[{atom,754,is_subtype},[{var,754,'Alias'},{type,754,reference,[]}]]}]]}]}}],since => <<79,84,80,32,64,79,84,80,45,49,54,55,49,56,64>>}},{{function,append_element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,374}],[<<97,112,112,101,110,100,95,101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,116,104,97,116,32,104,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,109,111,114,101,32,116,104,97,110,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<44,32,97,110,100,32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,115,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,46,32,83,101,109,97,110,116,105,99,97,108,108,121,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<108,105,115,116,95,116,111,95,116,117,112,108,101,40,116,117,112,108,101,95,116,111,95,108,105,115,116,40,84,117,112,108,101,49,41,32,43,43,32,91,84,101,114,109,93,41>>]},<<44,32,98,117,116,32,109,117,99,104,32,102,97,115,116,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,97,112,112,101,110,100,95,101,108,101,109,101,110,116,40,123,111,110,101,44,32,116,119,111,125,44,32,116,104,114,101,101,41,46,10,123,111,110,101,44,116,119,111,44,116,104,114,101,101,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,48>>,signature => [{attribute,374,spec,{{erlang,append_element,2},[{type,374,bounded_fun,[{type,374,'fun',[{type,374,product,[{var,374,'Tuple1'},{var,374,'Term'}]},{var,374,'Tuple2'}]},[{type,375,constraint,[{atom,375,is_subtype},[{var,375,'Tuple1'},{type,375,tuple,any}]]},{type,376,constraint,[{atom,376,is_subtype},[{var,376,'Tuple2'},{type,376,tuple,any}]]},{type,377,constraint,[{atom,377,is_subtype},[{var,377,'Term'},{type,377,term,[]}]]}]]}]}}]}},{{function,apply,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2888}],[<<97,112,112,108,121,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,108,108,115,32,97,32,102,117,110,44,32,112,97,115,115,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<65,114,103,115>>]},<<32,97,115,32,97,114,103,117,109,101,110,116,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,107,110,111,119,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,116,104,101,32,99,97,108,108,32,105,115,32,98,101,116,116,101,114,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<70,117,110,40,65,114,103,49,44,32,65,114,103,50,44,32,46,46,46,32,65,114,103,78,41>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<69,97,114,108,105,101,114,44,32>>,{code,[],[<<70,117,110>>]},<<32,99,111,117,108,100,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,125>>]},<<44,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<97,112,112,108,121,40,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,103,115,41>>]},<<46,32>>,{em,[],[<<84,104,105,115,32,117,115,101,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,110,100,32,119,105,108,108,32,115,116,111,112,32,119,111,114,107,105,110,103,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,55>>,signature => [{attribute,2888,spec,{{apply,2},[{type,2888,bounded_fun,[{type,2888,'fun',[{type,2888,product,[{var,2888,'Fun'},{var,2888,'Args'}]},{type,2888,term,[]}]},[{type,2889,constraint,[{atom,2889,is_subtype},[{var,2889,'Fun'},{type,2889,function,[]}]]},{type,2890,constraint,[{atom,2890,is_subtype},[{var,2890,'Args'},{type,2890,list,[{type,2890,term,[]}]}]]}]]}]}}]}},{{function,apply,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2895}],[<<97,112,112,108,121,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,110,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,84,104,101,32,97,112,112,108,105,101,100,32,102,117,110,99,116,105,111,110,32,109,117,115,116,32,98,101,32,101,120,112,111,114,116,101,100,32,102,114,111,109,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,84,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,112,112,108,121,40,108,105,115,116,115,44,32,114,101,118,101,114,115,101,44,32,91,91,97,44,32,98,44,32,99,93,93,41,46,10,91,99,44,98,44,97,93,10,62,32,97,112,112,108,121,40,101,114,108,97,110,103,44,32,97,116,111,109,95,116,111,95,108,105,115,116,44,32,91,39,69,114,108,97,110,103,39,93,41,46,10,34,69,114,108,97,110,103,34>>]}]},{p,[],[<<73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,107,110,111,119,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,116,104,101,32,99,97,108,108,32,105,115,32,98,101,116,116,101,114,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,40,65,114,103,49,44,32,65,114,103,50,44,32,46,46,46,44,32,65,114,103,78,41>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{a,[{href,<<107,101,114,110,101,108,58,101,114,114,111,114,95,104,97,110,100,108,101,114,35,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114,58,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,47,51>>]}]},<<32,105,115,32,99,97,108,108,101,100,32,105,102,32,116,104,101,32,97,112,112,108,105,101,100,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,101,120,112,111,114,116,101,100,46,32,84,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,99,97,110,32,98,101,32,114,101,100,101,102,105,110,101,100,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<41,46,32,73,102,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,111,114,32,105,102,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,100,101,102,105,110,101,100,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,115,111,32,116,104,101,32,114,101,112,108,97,99,101,109,101,110,116,32,109,111,100,117,108,101,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,32,101,114,114,111,114,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<117,110,100,101,102>>]},<<32,105,115,32,103,101,110,101,114,97,116,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,53>>,signature => [{attribute,2895,spec,{{apply,3},[{type,2895,bounded_fun,[{type,2895,'fun',[{type,2895,product,[{var,2895,'Module'},{var,2895,'Function'},{var,2895,'Args'}]},{type,2895,term,[]}]},[{type,2896,constraint,[{atom,2896,is_subtype},[{var,2896,'Module'},{type,2896,module,[]}]]},{type,2897,constraint,[{atom,2897,is_subtype},[{var,2897,'Function'},{type,2897,atom,[]}]]},{type,2898,constraint,[{atom,2898,is_subtype},[{var,2898,'Args'},{type,2898,list,[{type,2898,term,[]}]}]]}]]}]}}]}},{{function,atom_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,382}],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121>>]},<<32>>]},{code,[],[<<40,65,116,111,109,44,32,117,116,102,56,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,53>>,signature => [{attribute,382,spec,{{atom_to_binary,1},[{type,382,bounded_fun,[{type,382,'fun',[{type,382,product,[{var,382,'Atom'}]},{type,382,binary,[]}]},[{type,383,constraint,[{atom,383,is_subtype},[{var,383,'Atom'},{type,383,atom,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,atom_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,393}],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<65,116,111,109>>]},<<46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,98,121,116,101,32,101,120,105,115,116,115,32,102,111,114,32,101,97,99,104,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,111,114,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,85,84,70,45,56,32,119,104,101,114,101,32,99,104,97,114,97,99,116,101,114,115,32,109,97,121,32,114,101,113,117,105,114,101,32,109,117,108,116,105,112,108,101,32,98,121,116,101,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32,97,116,111,109,115,32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32>>,{code,[],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,40,65,116,111,109,44,32,108,97,116,105,110,49,41>>]},<<32,109,97,121,32,102,97,105,108,32,105,102,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<65,116,111,109>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,62,32,50,53,53,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,98,105,110,97,114,121,40,39,69,114,108,97,110,103,39,44,32,108,97,116,105,110,49,41,46,10,60,60,34,69,114,108,97,110,103,34,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,53>>,signature => [{attribute,393,spec,{{atom_to_binary,2},[{type,393,bounded_fun,[{type,393,'fun',[{type,393,product,[{var,393,'Atom'},{var,393,'Encoding'}]},{type,393,binary,[]}]},[{type,394,constraint,[{atom,394,is_subtype},[{var,394,'Atom'},{type,394,atom,[]}]]},{type,395,constraint,[{atom,395,is_subtype},[{var,395,'Encoding'},{type,395,union,[{atom,395,latin1},{atom,395,unicode},{atom,395,utf8}]}]]}]]}]}}]}},{{function,atom_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,400}],[<<97,116,111,109,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,117,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<65,116,111,109>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,108,105,115,116,40,39,69,114,108,97,110,103,39,41,46,10,34,69,114,108,97,110,103,34>>]}]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,108,105,115,116,40,39,228,189,160,229,165,189,39,41,46,10,91,50,48,51,50,48,44,50,50,57,48,57,93>>]}]},{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,100,108,105,98,58,117,110,105,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,105,99,111,100,101,40,51,41>>]}]},<<32,102,111,114,32,104,111,119,32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,32,116,111,32,100,105,102,102,101,114,101,110,116,32,102,111,114,109,97,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,53,48>>,signature => [{attribute,400,spec,{{atom_to_list,1},[{type,400,bounded_fun,[{type,400,'fun',[{type,400,product,[{var,400,'Atom'}]},{type,400,string,[]}]},[{type,401,constraint,[{atom,401,is_subtype},[{var,401,'Atom'},{type,401,atom,[]}]]}]]}]}}]}},{{function,binary_part,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,407}],[<<98,105,110,97,114,121,95,112,97,114,116,47,50>>],#{<<101,110>> => [{p,[],[<<69,120,116,114,97,99,116,115,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,100,101,115,99,114,105,98,101,100,32,98,121,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<46>>]},{p,[],[<<78,101,103,97,116,105,118,101,32,108,101,110,103,116,104,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,101,120,116,114,97,99,116,32,98,121,116,101,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,98,105,110,97,114,121,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<49,62,32,66,105,110,32,61,32,60,60,49,44,50,44,51,44,52,44,53,44,54,44,55,44,56,44,57,44,49,48,62,62,46,10,50,62,32,98,105,110,97,114,121,95,112,97,114,116,40,66,105,110,44,123,98,121,116,101,95,115,105,122,101,40,66,105,110,41,44,32,45,53,125,41,46,10,60,60,54,44,55,44,56,44,57,44,49,48,62,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<32,105,110,32,97,110,121,32,119,97,121,32,114,101,102,101,114,101,110,99,101,115,32,111,117,116,115,105,100,101,32,116,104,101,32,98,105,110,97,114,121,46>>]},{p,[],[{code,[],[<<83,116,97,114,116>>]},<<32,105,115,32,122,101,114,111,45,98,97,115,101,100,44,32,116,104,97,116,32,105,115,58>>]},{pre,[],[{code,[],[<<49,62,32,66,105,110,32,61,32,60,60,49,44,50,44,51,62,62,10,50,62,32,98,105,110,97,114,121,95,112,97,114,116,40,66,105,110,44,123,48,44,50,125,41,46,10,60,60,49,44,50,62,62>>]}]},{p,[],[<<70,111,114,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<32,115,101,109,97,110,116,105,99,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,100,108,105,98,58,98,105,110,97,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<98,105,110,97,114,121,40,51,41>>]}]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,54,56>>,signature => [{attribute,407,spec,{{binary_part,2},[{type,407,bounded_fun,[{type,407,'fun',[{type,407,product,[{var,407,'Subject'},{var,407,'PosLen'}]},{type,407,binary,[]}]},[{type,408,constraint,[{atom,408,is_subtype},[{var,408,'Subject'},{type,408,binary,[]}]]},{type,409,constraint,[{atom,409,is_subtype},[{var,409,'PosLen'},{type,409,tuple,[{ann_type,409,[{var,409,'Start'},{type,409,non_neg_integer,[]}]},{ann_type,409,[{var,409,'Length'},{type,409,integer,[]}]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,binary_part,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,415}],[<<98,105,110,97,114,121,95,112,97,114,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<98,105,110,97,114,121,95,112,97,114,116,40,83,117,98,106,101,99,116,44,32,123,83,116,97,114,116,44,32,76,101,110,103,116,104,125,41>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,51>>,signature => [{attribute,415,spec,{{binary_part,3},[{type,415,bounded_fun,[{type,415,'fun',[{type,415,product,[{var,415,'Subject'},{var,415,'Start'},{var,415,'Length'}]},{type,415,binary,[]}]},[{type,416,constraint,[{atom,416,is_subtype},[{var,416,'Subject'},{type,416,binary,[]}]]},{type,417,constraint,[{atom,417,is_subtype},[{var,417,'Start'},{type,417,non_neg_integer,[]}]]},{type,418,constraint,[{atom,418,is_subtype},[{var,418,'Length'},{type,418,integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,binary_to_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,423}],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109>>]},<<32>>]},{code,[],[<<40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,51>>,signature => [{attribute,423,spec,{{binary_to_atom,1},[{type,423,bounded_fun,[{type,423,'fun',[{type,423,product,[{var,423,'Binary'}]},{type,423,atom,[]}]},[{type,424,constraint,[{atom,424,is_subtype},[{var,424,'Binary'},{type,424,binary,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,binary_to_atom,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,433}],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,111,114,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,98,105,110,97,114,121,32,109,117,115,116,32,99,111,110,116,97,105,110,32,118,97,108,105,100,32,85,84,70,45,56,32,115,101,113,117,101,110,99,101,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<32,105,115,32,99,97,112,97,98,108,101,32,111,102,32,101,110,99,111,100,105,110,103,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,46,32,69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,119,111,117,108,100,32,102,97,105,108,32,105,102,32,116,104,101,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,101,100,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,62,32,50,53,53,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,85,110,105,99,111,100,101,32,115,117,112,112,111,114,116,32,105,110,32,97,116,111,109,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116,35,117,116,102,56,95,97,116,111,109,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,116,101,32,111,110,32,85,84,70,45,56,32,101,110,99,111,100,101,100,32,97,116,111,109,115>>]},<<32,105,110,32,115,101,99,116,105,111,110,32,34,69,120,116,101,114,110,97,108,32,84,101,114,109,32,70,111,114,109,97,116,34,32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,110,115,105,100,101,114,32,119,104,101,116,104,101,114,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>]},<<32,105,115,32,97,32,98,101,116,116,101,114,32,111,112,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,60,60,34,69,114,108,97,110,103,34,62,62,44,32,108,97,116,105,110,49,41,46,10,39,69,114,108,97,110,103,39>>]}]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,60,60,49,48,50,52,47,117,116,102,56,62,62,44,32,117,116,102,56,41,46,10,39,208,128,39>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,49,51>>,signature => [{attribute,433,spec,{{binary_to_atom,2},[{type,433,bounded_fun,[{type,433,'fun',[{type,433,product,[{var,433,'Binary'},{var,433,'Encoding'}]},{type,433,atom,[]}]},[{type,434,constraint,[{atom,434,is_subtype},[{var,434,'Binary'},{type,434,binary,[]}]]},{type,435,constraint,[{atom,435,is_subtype},[{var,435,'Encoding'},{type,435,union,[{atom,435,latin1},{atom,435,unicode},{atom,435,utf8}]}]]}]]}]}}]}},{{function,binary_to_existing_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,440}],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109>>]}]},<<32>>,{code,[],[<<40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,53,54>>,signature => [{attribute,440,spec,{{binary_to_existing_atom,1},[{type,440,bounded_fun,[{type,440,'fun',[{type,440,product,[{var,440,'Binary'}]},{type,440,atom,[]}]},[{type,441,constraint,[{atom,441,is_subtype},[{var,441,'Binary'},{type,441,binary,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,binary_to_existing_atom,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,450}],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]}]},<<44,32,98,117,116,32,116,104,101,32,97,116,111,109,32,109,117,115,116,32,101,120,105,115,116,46>>]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,104,97,115,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116>>]},<<32,102,111,114,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,44,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,110,111,116,32,115,97,102,101,32,116,111,32,99,114,101,97,116,101,32,109,97,110,121,32,97,116,111,109,115,32,102,114,111,109,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,99,111,109,101,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,105,108,101,32,102,101,116,99,104,101,100,32,102,114,111,109,32,116,104,101,32,73,110,116,101,114,110,101,116,41,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]}]},<<46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,117,115,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,111,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,105,110,112,117,116,32,98,105,110,97,114,121,32,99,111,109,101,115,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,46>>]},{p,[],[<<65,110,32,97,116,111,109,32,101,120,105,115,116,115,32,105,110,32,97,110,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,119,104,101,110,32,105,110,99,108,117,100,101,100,32,105,110,32,97,32,108,111,97,100,101,100,32,69,114,108,97,110,103,32,109,111,100,117,108,101,32,111,114,32,119,104,101,110,32,99,114,101,97,116,101,100,32,112,114,111,103,114,97,109,109,97,116,105,99,97,108,108,121,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,98,121,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]},<<41,46,32,83,101,101,32,116,104,101,32,110,101,120,116,32,110,111,116,101,32,102,111,114,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,119,104,101,110,32,97,110,32,97,116,111,109,32,101,120,105,115,116,115,32,105,110,32,116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,32,102,111,114,32,97,110,32,69,114,108,97,110,103,32,109,111,100,117,108,101,32,98,117,116,32,110,111,116,32,105,110,32,116,104,101,32,99,111,109,112,105,108,101,100,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,115,97,109,101,32,109,111,100,117,108,101,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,97,116,111,109,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,99,111,109,112,105,108,101,114,32,109,97,121,32,111,112,116,105,109,105,122,101,32,97,119,97,121,32,97,116,111,109,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,111,109,112,105,108,101,114,32,119,105,108,108,32,114,101,119,114,105,116,101,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,115,111,109,101,95,97,116,111,109,41>>]},<<32,116,111,32>>,{code,[],[<<34,115,111,109,101,95,97,116,111,109,34>>]},<<46,32,73,102,32,116,104,97,116,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,110,116,105,111,110,32,111,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,111,109,101,95,97,116,111,109>>]},<<32,105,110,32,116,104,101,32,99,111,110,116,97,105,110,105,110,103,32,109,111,100,117,108,101,44,32,116,104,101,32,97,116,111,109,32,119,105,108,108,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,108,111,97,100,101,100,44,32,97,110,100,32,97,32,115,117,98,115,101,113,117,101,110,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,40,60,60,34,115,111,109,101,95,97,116,111,109,34,62,62,44,32,117,116,102,56,41>>]},<<32,119,105,108,108,32,102,97,105,108,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,55>>,signature => [{attribute,450,spec,{{binary_to_existing_atom,2},[{type,450,bounded_fun,[{type,450,'fun',[{type,450,product,[{var,450,'Binary'},{var,450,'Encoding'}]},{type,450,atom,[]}]},[{type,451,constraint,[{atom,451,is_subtype},[{var,451,'Binary'},{type,451,binary,[]}]]},{type,452,constraint,[{atom,452,is_subtype},[{var,452,'Encoding'},{type,452,union,[{atom,452,latin1},{atom,452,unicode},{atom,452,utf8}]}]]}]]}]}}]}},{{function,binary_to_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,457}],[<<98,105,110,97,114,121,95,116,111,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,102,108,111,97,116,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,102,108,111,97,116,40,60,60,34,50,46,50,48,49,55,55,54,52,101,43,48,34,62,62,41,46,10,50,46,50,48,49,55,55,54,52>>]}]},{p,[],[<<84,104,101,32,102,108,111,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,102,111,114,109,97,116,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,102,108,111,97,116,32,108,105,116,101,114,97,108,115>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,97,116,32,117,110,100,101,114,115,99,111,114,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,102,108,111,97,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,51>>,signature => [{attribute,457,spec,{{binary_to_float,1},[{type,457,bounded_fun,[{type,457,'fun',[{type,457,product,[{var,457,'Binary'}]},{type,457,float,[]}]},[{type,458,constraint,[{atom,458,is_subtype},[{var,458,'Binary'},{type,458,binary,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,463}],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,40,60,60,34,49,50,51,34,62,62,41,46,10,49,50,51>>]}]},{p,[],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,49>>]},<<32,97,99,99,101,112,116,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,102,111,114,109,97,116,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,49>>,signature => [{attribute,463,spec,{{binary_to_integer,1},[{type,463,bounded_fun,[{type,463,'fun',[{type,463,product,[{var,463,'Binary'}]},{type,463,integer,[]}]},[{type,464,constraint,[{atom,464,is_subtype},[{var,464,'Binary'},{type,464,binary,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_integer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,469}],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,40,60,60,34,51,70,70,34,62,62,44,32,49,54,41,46,10,49,48,50,51>>]}]},{p,[],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,50>>]},<<32,97,99,99,101,112,116,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,102,111,114,109,97,116,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,56>>,signature => [{attribute,469,spec,{{binary_to_integer,2},[{type,469,bounded_fun,[{type,469,'fun',[{type,469,product,[{var,469,'Binary'},{var,469,'Base'}]},{type,469,integer,[]}]},[{type,470,constraint,[{atom,470,is_subtype},[{var,470,'Binary'},{type,470,binary,[]}]]},{type,471,constraint,[{atom,471,is_subtype},[{var,471,'Base'},{type,471,range,[{integer,471,2},{integer,471,36}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,476}],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,111,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,54>>,signature => [{attribute,476,spec,{{binary_to_list,1},[{type,476,bounded_fun,[{type,476,'fun',[{type,476,product,[{var,476,'Binary'}]},{type,476,list,[{type,476,byte,[]}]}]},[{type,477,constraint,[{atom,477,is_subtype},[{var,477,'Binary'},{type,477,binary,[]}]]}]]}]}}]}},{{function,binary_to_list,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,482}],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>]},<<44,32,98,117,116,32,114,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,102,114,111,109,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<83,116,97,114,116>>]},<<32,116,111,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<83,116,111,112>>]},<<32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46,32,84,104,101,32,112,111,115,105,116,105,111,110,115,32,105,110,32,116,104,101,32,98,105,110,97,114,121,32,97,114,101,32,110,117,109,98,101,114,101,100,32,115,116,97,114,116,105,110,103,32,102,114,111,109,32,49,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{em,[],[<<84,104,101,32,111,110,101,45,98,97,115,101,100,32,105,110,100,101,120,105,110,103,32,102,111,114,32,98,105,110,97,114,105,101,115,32,117,115,101,100,32,98,121,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,78,101,119,32,99,111,100,101,32,105,115,32,116,111,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,98,105,110,97,114,121,35,98,105,110,95,116,111,95,108,105,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,58,98,105,110,95,116,111,95,108,105,115,116,47,51>>]}]},<<32,105,110,32,83,84,68,76,73,66,32,105,110,115,116,101,97,100,46,32,65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,99,111,110,115,105,115,116,101,110,116,108,121,32,117,115,101,32,122,101,114,111,45,98,97,115,101,100,32,105,110,100,101,120,105,110,103,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,53>>,signature => [{attribute,482,spec,{{binary_to_list,3},[{type,482,bounded_fun,[{type,482,'fun',[{type,482,product,[{var,482,'Binary'},{var,482,'Start'},{var,482,'Stop'}]},{type,482,list,[{type,482,byte,[]}]}]},[{type,483,constraint,[{atom,483,is_subtype},[{var,483,'Binary'},{type,483,binary,[]}]]},{type,484,constraint,[{atom,484,is_subtype},[{var,484,'Start'},{type,484,pos_integer,[]}]]},{type,485,constraint,[{atom,485,is_subtype},[{var,485,'Stop'},{type,485,pos_integer,[]}]]}]]}]}}]}},{{function,binary_to_term,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,490}],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,100,101,99,111,100,105,110,103,32,98,105,110,97,114,121,32,111,98,106,101,99,116,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,119,104,105,99,104,32,109,117,115,116,32,98,101,32,101,110,99,111,100,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116>>]},<<46>>]},{pre,[],[{code,[],[<<62,32,66,105,110,32,61,32,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,104,101,108,108,111,41,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,10,62,32,104,101,108,108,111,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,66,105,110,41,46,10,104,101,108,108,111>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<87,104,101,110,32,100,101,99,111,100,105,110,103,32,98,105,110,97,114,105,101,115,32,102,114,111,109,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,115,44,32,99,111,110,115,105,100,101,114,32,117,115,105,110,103,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>]},<<32,116,111,32,112,114,101,118,101,110,116,32,68,101,110,105,97,108,32,111,102,32,83,101,114,118,105,99,101,32,97,116,116,97,99,107,115,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,55>>,signature => [{attribute,490,spec,{{binary_to_term,1},[{type,490,bounded_fun,[{type,490,'fun',[{type,490,product,[{var,490,'Binary'}]},{type,490,term,[]}]},[{type,491,constraint,[{atom,491,is_subtype},[{var,491,'Binary'},{user_type,491,ext_binary,[]}]]}]]}]}}]}},{{function,binary_to_term,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,496}],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<44,32,98,117,116,32,116,97,107,101,115,32,116,104,101,115,101,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,97,102,101>>]}]},{dd,[],[{p,[],[<<85,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,119,104,101,110,32,114,101,99,101,105,118,105,110,103,32,98,105,110,97,114,105,101,115,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,46>>]},{p,[],[<<87,104,101,110,32,101,110,97,98,108,101,100,44,32,105,116,32,112,114,101,118,101,110,116,115,32,100,101,99,111,100,105,110,103,32,100,97,116,97,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,116,116,97,99,107,32,116,104,101,32,69,114,108,97,110,103,32,115,121,115,116,101,109,46,32,73,110,32,116,104,101,32,101,118,101,110,116,32,111,102,32,114,101,99,101,105,118,105,110,103,32,117,110,115,97,102,101,32,100,97,116,97,44,32,100,101,99,111,100,105,110,103,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,114,114,111,114,46>>]},{p,[],[<<84,104,105,115,32,112,114,101,118,101,110,116,115,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,97,116,111,109,115,32,100,105,114,101,99,116,108,121,44,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,97,116,111,109,115,32,105,110,100,105,114,101,99,116,108,121,32,40,97,115,32,116,104,101,121,32,97,114,101,32,101,109,98,101,100,100,101,100,32,105,110,32,99,101,114,116,97,105,110,32,115,116,114,117,99,116,117,114,101,115,44,32,115,117,99,104,32,97,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,114,101,102,115,44,32,97,110,100,32,102,117,110,115,41,44,32,97,110,100,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,101,120,116,101,114,110,97,108,32,102,117,110,99,116,105,111,110,32,114,101,102,101,114,101,110,99,101,115,46,32,78,111,110,101,32,111,102,32,116,104,111,115,101,32,114,101,115,111,117,114,99,101,115,32,97,114,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,44,32,115,111,32,117,110,99,104,101,99,107,101,100,32,99,114,101,97,116,105,111,110,32,111,102,32,116,104,101,109,32,99,97,110,32,101,120,104,97,117,115,116,32,97,118,97,105,108,97,98,108,101,32,109,101,109,111,114,121,46>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,62,62,44,32,91,115,97,102,101,93,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,114,114,111,114,58,32,98,97,100,32,97,114,103,117,109,101,110,116,10,62,32,104,101,108,108,111,46,10,104,101,108,108,111,10,62,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,62,62,44,32,91,115,97,102,101,93,41,46,10,104,101,108,108,111>>]}]}]},{dt,[],[{code,[],[<<117,115,101,100>>]}]},{dd,[],[{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<123,84,101,114,109,44,32,85,115,101,100,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<85,115,101,100>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,97,99,116,117,97,108,108,121,32,114,101,97,100,32,102,114,111,109,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46>>]},{pre,[],[{code,[],[<<62,32,73,110,112,117,116,32,61,32,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,44,34,119,111,114,108,100,34,62,62,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,44,49,49,57,44,49,49,49,44,49,49,52,44,49,48,56,44,49,48,48,62,62,10,62,32,123,84,101,114,109,44,32,85,115,101,100,125,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,73,110,112,117,116,44,32,91,117,115,101,100,93,41,46,10,123,104,101,108,108,111,44,32,57,125,10,62,32,115,112,108,105,116,95,98,105,110,97,114,121,40,73,110,112,117,116,44,32,85,115,101,100,41,46,10,123,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,44,32,60,60,34,119,111,114,108,100,34,62,62,125>>]}]}]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<115,97,102,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,110,100,32,117,110,115,97,102,101,32,100,97,116,97,32,105,115,32,100,101,99,111,100,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,51>>,signature => [{attribute,496,spec,{{binary_to_term,2},[{type,496,bounded_fun,[{type,496,'fun',[{type,496,product,[{var,496,'Binary'},{var,496,'Opts'}]},{type,496,union,[{type,496,term,[]},{type,496,tuple,[{type,496,term,[]},{var,496,'Used'}]}]}]},[{type,497,constraint,[{atom,497,is_subtype},[{var,497,'Binary'},{user_type,497,ext_binary,[]}]]},{type,498,constraint,[{atom,498,is_subtype},[{var,498,'Opt'},{type,498,union,[{atom,498,safe},{atom,498,used}]}]]},{type,499,constraint,[{atom,499,is_subtype},[{var,499,'Opts'},{type,499,list,[{var,499,'Opt'}]}]]},{type,500,constraint,[{atom,500,is_subtype},[{var,500,'Used'},{type,500,pos_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,bit_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,506}],[<<98,105,116,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,105,116,115,32,111,102,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,116,95,115,105,122,101,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,49,57,10,62,32,98,105,116,95,115,105,122,101,40,60,60,49,44,50,44,51,62,62,41,46,10,50,52>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,55>>,signature => [{attribute,506,spec,{{bit_size,1},[{type,506,bounded_fun,[{type,506,'fun',[{type,506,product,[{var,506,'Bitstring'}]},{type,506,non_neg_integer,[]}]},[{type,507,constraint,[{atom,507,is_subtype},[{var,507,'Bitstring'},{type,507,bitstring,[]}]]}]]}]}}]}},{{function,bitstring_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,512}],[<<98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,111,102,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32,116,104,101,32,98,105,110,97,114,121,32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,108,105,115,116,32,105,115,32,97,32,98,105,116,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,49,45,55,32,98,105,116,115,46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,40,60,60,52,51,51,58,49,54,62,62,41,46,10,91,49,44,49,55,55,93>>]}]},{pre,[],[{code,[],[<<62,32,98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,91,49,44,49,55,55,44,60,60,51,58,51,62,62,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,50>>,signature => [{attribute,512,spec,{{bitstring_to_list,1},[{type,512,bounded_fun,[{type,512,'fun',[{type,512,product,[{var,512,'Bitstring'}]},{type,512,list,[{type,512,union,[{type,512,byte,[]},{type,512,bitstring,[]}]}]}]},[{type,513,constraint,[{atom,513,is_subtype},[{var,513,'Bitstring'},{type,513,bitstring,[]}]]}]]}]}}]}},{{function,bump_reductions,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,518}],[<<98,117,109,112,95,114,101,100,117,99,116,105,111,110,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,105,115,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,99,114,101,109,101,110,116,115,32,116,104,101,32,114,101,100,117,99,116,105,111,110,32,99,111,117,110,116,101,114,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,73,110,32,116,104,101,32,66,101,97,109,32,101,109,117,108,97,116,111,114,44,32,116,104,101,32,114,101,100,117,99,116,105,111,110,32,99,111,117,110,116,101,114,32,105,115,32,110,111,114,109,97,108,108,121,32,105,110,99,114,101,109,101,110,116,101,100,32,98,121,32,111,110,101,32,102,111,114,32,101,97,99,104,32,102,117,110,99,116,105,111,110,32,97,110,100,32,66,73,70,32,99,97,108,108,46,32,65,32,99,111,110,116,101,120,116,32,115,119,105,116,99,104,32,105,115,32,102,111,114,99,101,100,32,119,104,101,110,32,116,104,101,32,99,111,117,110,116,101,114,32,114,101,97,99,104,101,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,102,111,114,32,97,32,112,114,111,99,101,115,115,32,40,52,48,48,48,32,114,101,100,117,99,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103,47,79,84,80,32,49,57,46,50,32,97,110,100,32,108,97,116,101,114,41,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,99,97,110,32,98,101,32,114,101,109,111,118,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,66,101,97,109,32,109,97,99,104,105,110,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,119,97,114,110,105,110,103,46,32,73,116,32,105,115,32,117,110,108,105,107,101,108,121,32,116,111,32,98,101,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,111,116,104,101,114,32,69,114,108,97,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,48,57>>,signature => [{attribute,518,spec,{{erlang,bump_reductions,1},[{type,518,bounded_fun,[{type,518,'fun',[{type,518,product,[{var,518,'Reductions'}]},{atom,518,true}]},[{type,519,constraint,[{atom,519,is_subtype},[{var,519,'Reductions'},{type,519,pos_integer,[]}]]}]]}]}}]}},{{function,byte_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,525}],[<<98,121,116,101,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,110,101,101,100,101,100,32,116,111,32,99,111,110,116,97,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,115,32,114,111,117,110,100,101,100,32>>,{em,[],[<<117,112>>]},<<46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,121,116,101,95,115,105,122,101,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,51,10,62,32,98,121,116,101,95,115,105,122,101,40,60,60,49,44,50,44,51,62,62,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,55>>,signature => [{attribute,525,spec,{{byte_size,1},[{type,525,bounded_fun,[{type,525,'fun',[{type,525,product,[{var,525,'Bitstring'}]},{type,525,non_neg_integer,[]}]},[{type,526,constraint,[{atom,526,is_subtype},[{var,526,'Bitstring'},{type,526,bitstring,[]}]]}]]}]}}]}},{{function,cancel_timer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,537}],[<<99,97,110,99,101,108,95,116,105,109,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<67,97,110,99,101,108,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,84,105,109,101,114,82,101,102,44,32,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,52,52>>,signature => [{attribute,537,spec,{{erlang,cancel_timer,1},[{type,537,bounded_fun,[{type,537,'fun',[{type,537,product,[{var,537,'TimerRef'}]},{var,537,'Result'}]},[{type,538,constraint,[{atom,538,is_subtype},[{var,538,'TimerRef'},{type,538,reference,[]}]]},{type,539,constraint,[{atom,539,is_subtype},[{var,539,'Time'},{type,539,non_neg_integer,[]}]]},{type,540,constraint,[{atom,540,is_subtype},[{var,540,'Result'},{type,540,union,[{var,540,'Time'},{atom,540,false}]}]]}]]}]}}]}},{{function,cancel_timer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,546}],[<<99,97,110,99,101,108,95,116,105,109,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,110,99,101,108,115,32,97,32,116,105,109,101,114,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114>>]}]},<<46,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,105,100,101,110,116,105,102,105,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,119,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,66,73,70,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,116,105,109,101,114,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,65,115,121,110,99,125>>]}]},{dd,[],[{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,99,97,110,99,101,108,108,97,116,105,111,110,46,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,32,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,99,97,110,99,101,108,32,111,112,101,114,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<32,115,101,110,100,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,99,97,110,99,101,108,108,97,116,105,111,110,32,116,111,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,105,110,102,111,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<82,101,113,117,101,115,116,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,111,102,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,103,105,118,101,110,46,32,87,104,101,110,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,105,115,32,103,105,118,101,110,46>>]},{ul,[],[{li,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<58,32,105,102,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<46,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<111,107>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{li,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<58,32,105,102,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,99,97,110,99,101,108,95,116,105,109,101,114,44,32,84,105,109,101,114,82,101,102,44,32,82,101,115,117,108,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<32,119,104,101,110,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,44,32,111,116,104,101,114,119,105,115,101,32,110,111,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]}]}]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,109,97,121,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,105,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32,108,101,102,116,32,117,110,116,105,108,32,116,104,101,32,99,97,110,99,101,108,101,100,32,116,105,109,101,114,32,119,111,117,108,100,32,104,97,118,101,32,101,120,112,105,114,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,97,32,116,105,109,101,114,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,102,111,117,110,100,46,32,84,104,105,115,32,99,97,110,32,98,101,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,97,108,114,101,97,100,121,32,104,97,100,32,98,101,101,110,32,99,97,110,99,101,108,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,110,101,118,101,114,32,99,111,114,114,101,115,112,111,110,100,101,100,32,116,111,32,97,32,116,105,109,101,114,46,32,69,118,101,110,32,105,102,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,108,108,32,121,111,117,32,105,102,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,32,104,97,115,32,97,114,114,105,118,101,100,32,97,116,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,32,121,101,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,32,99,97,110,32,98,101,32,99,111,45,108,111,99,97,116,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32,115,99,104,101,100,117,108,101,114,32,116,104,97,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32,73,102,32,115,111,44,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,116,105,109,101,32,116,104,97,110,32,105,102,32,105,116,32,105,115,32,108,111,99,97,116,101,100,32,108,111,99,97,108,108,121,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,105,110,32,99,114,105,116,105,99,97,108,32,112,97,116,104,44,32,97,110,100,32,99,97,110,32,100,111,32,111,116,104,101,114,32,116,104,105,110,103,115,32,119,104,105,108,101,32,119,97,105,116,105,110,103,32,102,111,114,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,44,32,111,114,32,105,115,32,110,111,116,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,116,114,117,101,125>>]},<<46,32,73,102,32,117,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,102,97,108,115,101,125>>]},<<44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,98,108,111,99,107,115,32,117,110,116,105,108,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,52>>,signature => [{attribute,546,spec,{{erlang,cancel_timer,2},[{type,546,bounded_fun,[{type,546,'fun',[{type,546,product,[{var,546,'TimerRef'},{var,546,'Options'}]},{type,546,union,[{var,546,'Result'},{atom,546,ok}]}]},[{type,547,constraint,[{atom,547,is_subtype},[{var,547,'TimerRef'},{type,547,reference,[]}]]},{type,548,constraint,[{atom,548,is_subtype},[{var,548,'Async'},{type,548,boolean,[]}]]},{type,549,constraint,[{atom,549,is_subtype},[{var,549,'Info'},{type,549,boolean,[]}]]},{type,550,constraint,[{atom,550,is_subtype},[{var,550,'Option'},{type,550,union,[{type,550,tuple,[{atom,550,async},{var,550,'Async'}]},{type,550,tuple,[{atom,550,info},{var,550,'Info'}]}]}]]},{type,551,constraint,[{atom,551,is_subtype},[{var,551,'Options'},{type,551,list,[{var,551,'Option'}]}]]},{type,552,constraint,[{atom,552,is_subtype},[{var,552,'Time'},{type,552,non_neg_integer,[]}]]},{type,553,constraint,[{atom,553,is_subtype},[{var,553,'Result'},{type,553,union,[{var,553,'Time'},{atom,553,false}]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,ceil,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,560}],[<<99,101,105,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,105,110,116,101,103,101,114,32,110,111,116,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,101,105,108,40,53,46,53,41,46,10,54>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,51,54>>,signature => [{attribute,560,spec,{{ceil,1},[{type,560,bounded_fun,[{type,560,'fun',[{type,560,product,[{var,560,'Number'}]},{type,560,integer,[]}]},[{type,561,constraint,[{atom,561,is_subtype},[{var,561,'Number'},{type,561,number,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,check_old_code,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,566}],[<<99,104,101,99,107,95,111,108,100,95,99,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,104,97,115,32,111,108,100,32,99,111,100,101,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,52,57>>,signature => [{attribute,566,spec,{{check_old_code,1},[{type,566,bounded_fun,[{type,566,'fun',[{type,566,product,[{var,566,'Module'}]},{type,566,boolean,[]}]},[{type,567,constraint,[{atom,567,is_subtype},[{var,567,'Module'},{type,567,module,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,check_process_code,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,572}],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,40,80,105,100,44,32,77,111,100,117,108,101,44,32,91,93,41>>]},<<32>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,54,48>>,signature => [{attribute,572,spec,{{check_process_code,2},[{type,572,bounded_fun,[{type,572,'fun',[{type,572,product,[{var,572,'Pid'},{var,572,'Module'}]},{var,572,'CheckResult'}]},[{type,573,constraint,[{atom,573,is_subtype},[{var,573,'Pid'},{type,573,pid,[]}]]},{type,574,constraint,[{atom,574,is_subtype},[{var,574,'Module'},{type,574,module,[]}]]},{type,575,constraint,[{atom,575,is_subtype},[{var,575,'CheckResult'},{type,575,boolean,[]}]]}]]}]}}]}},{{function,check_process_code,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,584}],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,101,99,107,115,32,105,102,32,116,104,101,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,98,111,111,108,101,97,110,40,41,125>>]}]},{dd,[],[{p,[],[<<68,101,116,101,114,109,105,110,101,115,32,105,102,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,108,108,111,119,101,100,32,119,104,101,110,32,112,101,114,102,111,114,109,105,110,103,32,116,104,101,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,102,97,108,115,101,125>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,97,110,100,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,110,101,101,100,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,97,98,111,114,116,101,100,32,40,115,101,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32>>,{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,98,101,108,111,119,41,46,32,84,104,101,32,100,101,102,97,117,108,116,32,105,115,32,116,111,32,97,108,108,111,119,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,44,32,116,104,97,116,32,105,115,44,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,116,114,117,101,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,82,101,113,117,101,115,116,73,100,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,101,110,116,46,32,87,104,101,110,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,112,97,115,115,101,100,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,44,32,82,101,113,117,101,115,116,73,100,44,32,67,104,101,99,107,82,101,115,117,108,116,125>>]},<<46>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<44,32,97,110,100,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,116,32,111,110,99,101,46,32,79,116,104,101,114,119,105,115,101,32,97,32,114,101,113,117,101,115,116,32,102,111,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,110,100,32,105,115,32,104,97,110,100,108,101,100,32,119,104,101,110,32,97,112,112,114,111,112,114,105,97,116,101,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,98,108,111,99,107,115,32,117,110,116,105,108,32>>,{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,105,115,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,114,101,113,117,101,115,116,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,99,111,110,116,97,105,110,115,32,102,117,110,115,32,116,104,97,116,32,114,101,102,101,114,101,110,99,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,101,99,117,116,101,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,98,111,114,116,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,97,98,111,114,116,101,100,44,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,110,101,101,100,101,100,32,116,111,32,98,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,114,101,115,117,108,116,44,32,97,110,100,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,114,101,113,117,101,115,116,101,100,32,98,121,32,112,97,115,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,102,97,108,115,101,125>>]},<<46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<85,112,32,117,110,116,105,108,32,69,82,84,83,32,118,101,114,115,105,111,110,32,56,46,42,44,32,116,104,101,32,99,104,101,99,107,32,112,114,111,99,101,115,115,32,99,111,100,101,32,111,112,101,114,97,116,105,111,110,32,99,104,101,99,107,115,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,111,108,100,32,99,111,100,101,46,32,84,104,97,116,32,105,115,44,32,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,40,101,46,103,46,32,114,101,116,117,114,110,32,97,100,100,114,101,115,115,101,115,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,41,44,32,105,110,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,40>>,{code,[],[<<102,117,110>>]},<<115,32,105,110,32,112,114,111,99,101,115,115,32,99,111,110,116,101,120,116,41,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,108,105,116,101,114,97,108,115,32,105,110,32,116,104,101,32,99,111,100,101,46>>]},{p,[],[<<65,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,57,46,48,44,32,116,104,101,32,99,104,101,99,107,32,112,114,111,99,101,115,115,32,99,111,100,101,32,111,112,101,114,97,116,105,111,110,32,111,110,108,121,32,99,104,101,99,107,115,32,102,111,114,32,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,99,111,100,101,46,32,73,110,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,118,105,97,32>>,{code,[],[<<102,117,110>>]},<<115,32,119,105,108,108,32,98,101,32,105,103,110,111,114,101,100,46,32,73,102,32,115,117,99,104,32>>,{code,[],[<<102,117,110>>]},<<115,32,101,120,105,115,116,32,97,110,100,32,97,114,101,32,117,115,101,100,32,97,102,116,101,114,32,97,32,112,117,114,103,101,32,111,102,32,116,104,101,32,111,108,100,32,99,111,100,101,44,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,105,108,108,32,98,101,32,114,97,105,115,101,100,32,117,112,111,110,32,117,115,97,103,101,32,40,115,97,109,101,32,97,115,32,116,104,101,32,99,97,115,101,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<102,117,110>>]},<<32,105,115,32,114,101,99,101,105,118,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,97,102,116,101,114,32,116,104,101,32,112,117,114,103,101,41,46,32,76,105,116,101,114,97,108,115,32,119,105,108,108,32,98,101,32,116,97,107,101,110,32,99,97,114,101,32,111,102,32,40,99,111,112,105,101,100,41,32,97,116,32,97,32,108,97,116,101,114,32,115,116,97,103,101,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,99,97,110,32,97,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,56,46,49,32,98,101,32,101,110,97,98,108,101,100,32,119,104,101,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,105,110,115,116,97,108,108,97,116,105,111,110,95,103,117,105,100,101,58,73,78,83,84,65,76,76,35,65,100,118,97,110,99,101,100,45,99,111,110,102,105,103,117,114,97,116,105,111,110,45,97,110,100,45,98,117,105,108,100,45,111,102,45,69,114,108,97,110,103,79,84,80,95,67,111,110,102,105,103,117,114,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<98,117,105,108,100,105,110,103,32,79,84,80>>]},<<44,32,97,110,100,32,119,105,108,108,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,98,101,32,101,110,97,98,108,101,100,32,105,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,32,115,117,112,112,111,114,116,32,105,115,32,101,110,97,98,108,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,55,49>>,signature => [{attribute,584,spec,{{check_process_code,3},[{type,584,bounded_fun,[{type,584,'fun',[{type,584,product,[{var,584,'Pid'},{var,584,'Module'},{var,584,'OptionList'}]},{type,584,union,[{var,584,'CheckResult'},{atom,584,async}]}]},[{type,585,constraint,[{atom,585,is_subtype},[{var,585,'Pid'},{type,585,pid,[]}]]},{type,586,constraint,[{atom,586,is_subtype},[{var,586,'Module'},{type,586,module,[]}]]},{type,587,constraint,[{atom,587,is_subtype},[{var,587,'RequestId'},{type,587,term,[]}]]},{type,588,constraint,[{atom,588,is_subtype},[{var,588,'Option'},{type,588,union,[{type,588,tuple,[{atom,588,async},{var,588,'RequestId'}]},{type,588,tuple,[{atom,588,allow_gc},{type,588,boolean,[]}]}]}]]},{type,589,constraint,[{atom,589,is_subtype},[{var,589,'OptionList'},{type,589,list,[{var,589,'Option'}]}]]},{type,590,constraint,[{atom,590,is_subtype},[{var,590,'CheckResult'},{type,590,union,[{type,590,boolean,[]},{atom,590,aborted}]}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,convert_time_unit,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1556}],[<<99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,111,102,32,116,105,109,101,32,117,110,105,116,32>>,{code,[],[<<70,114,111,109,85,110,105,116>>]},<<32,116,111,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<67,111,110,118,101,114,116,101,100,84,105,109,101>>]},<<32,118,97,108,117,101,32,111,102,32,116,105,109,101,32,117,110,105,116,32>>,{code,[],[<<84,111,85,110,105,116>>]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,105,115,32,114,111,117,110,100,101,100,32,117,115,105,110,103,32,116,104,101,32,102,108,111,111,114,32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<89,111,117,32,99,97,110,32,108,111,115,101,32,97,99,99,117,114,97,99,121,32,97,110,100,32,112,114,101,99,105,115,105,111,110,32,119,104,101,110,32,99,111,110,118,101,114,116,105,110,103,32,98,101,116,119,101,101,110,32,116,105,109,101,32,117,110,105,116,115,46,32,84,111,32,109,105,110,105,109,105,122,101,32,115,117,99,104,32,108,111,115,115,44,32,99,111,108,108,101,99,116,32,97,108,108,32,100,97,116,97,32,97,116,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,97,110,100,32,100,111,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,111,110,32,116,104,101,32,101,110,100,32,114,101,115,117,108,116,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,55,52>>,signature => [{attribute,1556,spec,{{erlang,convert_time_unit,3},[{type,1556,bounded_fun,[{type,1556,'fun',[{type,1556,product,[{var,1556,'Time'},{var,1556,'FromUnit'},{var,1556,'ToUnit'}]},{var,1556,'ConvertedTime'}]},[{type,1557,constraint,[{atom,1557,is_subtype},[{var,1557,'Time'},{type,1557,integer,[]}]]},{type,1558,constraint,[{atom,1558,is_subtype},[{var,1558,'ConvertedTime'},{type,1558,integer,[]}]]},{type,1559,constraint,[{atom,1559,is_subtype},[{var,1559,'FromUnit'},{user_type,1559,time_unit,[]}]]},{type,1560,constraint,[{atom,1560,is_subtype},[{var,1560,'ToUnit'},{user_type,1560,time_unit,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,crc32,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,602}],[<<99,114,99,51,50,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,99,114,99,51,50,32,40,73,69,69,69,32,56,48,50,46,51,32,115,116,121,108,101,41,32,99,104,101,99,107,115,117,109,32,102,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,57,50>>,signature => [{attribute,602,spec,{{erlang,crc32,1},[{type,602,bounded_fun,[{type,602,'fun',[{type,602,product,[{var,602,'Data'}]},{type,602,non_neg_integer,[]}]},[{type,603,constraint,[{atom,603,is_subtype},[{var,603,'Data'},{type,603,iodata,[]}]]}]]}]}}]}},{{function,crc32,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,608}],[<<99,114,99,51,50,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,116,105,110,117,101,115,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,99,114,99,51,50,32,99,104,101,99,107,115,117,109,32,98,121,32,99,111,109,98,105,110,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,101,99,107,115,117,109,44,32>>,{code,[],[<<79,108,100,67,114,99>>]},<<44,32,119,105,116,104,32,116,104,101,32,99,104,101,99,107,115,117,109,32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,88,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<89>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,91,68,97,116,97,49,44,68,97,116,97,50,93,41,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,48,49>>,signature => [{attribute,608,spec,{{erlang,crc32,2},[{type,608,bounded_fun,[{type,608,'fun',[{type,608,product,[{var,608,'OldCrc'},{var,608,'Data'}]},{type,608,non_neg_integer,[]}]},[{type,609,constraint,[{atom,609,is_subtype},[{var,609,'OldCrc'},{type,609,non_neg_integer,[]}]]},{type,610,constraint,[{atom,610,is_subtype},[{var,610,'Data'},{type,610,iodata,[]}]]}]]}]}}]}},{{function,crc32_combine,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,615}],[<<99,114,99,51,50,95,99,111,109,98,105,110,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32,116,119,111,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,117,116,101,100,32,99,114,99,51,50,32,99,104,101,99,107,115,117,109,115,46,32,84,104,105,115,32,99,111,109,112,117,116,97,116,105,111,110,32,114,101,113,117,105,114,101,115,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,111,98,106,101,99,116,32,102,111,114,32,116,104,101,32,115,101,99,111,110,100,32,99,104,101,99,107,115,117,109,32,116,111,32,98,101,32,107,110,111,119,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,90,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,89,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<90>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,50,41,44,10,90,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,95,99,111,109,98,105,110,101,40,88,44,89,44,105,111,108,105,115,116,95,115,105,122,101,40,68,97,116,97,50,41,41,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,49,56>>,signature => [{attribute,615,spec,{{erlang,crc32_combine,3},[{type,615,bounded_fun,[{type,615,'fun',[{type,615,product,[{var,615,'FirstCrc'},{var,615,'SecondCrc'},{var,615,'SecondSize'}]},{type,615,non_neg_integer,[]}]},[{type,616,constraint,[{atom,616,is_subtype},[{var,616,'FirstCrc'},{type,616,non_neg_integer,[]}]]},{type,617,constraint,[{atom,617,is_subtype},[{var,617,'SecondCrc'},{type,617,non_neg_integer,[]}]]},{type,618,constraint,[{atom,618,is_subtype},[{var,618,'SecondSize'},{type,618,non_neg_integer,[]}]]}]]}]}}]}},{{function,date,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,623}],[<<100,97,116,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,100,97,116,101,32,97,115,32>>,{code,[],[<<123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125>>]},<<46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,100,97,116,101,40,41,46,10,123,49,57,57,53,44,50,44,49,57,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,51,55>>,signature => [{attribute,623,spec,{{date,0},[{type,623,bounded_fun,[{type,623,'fun',[{type,623,product,[]},{var,623,'Date'}]},[{type,624,constraint,[{atom,624,is_subtype},[{var,624,'Date'},{remote_type,624,[{atom,624,calendar},{atom,624,date},[]]}]]}]]}]}}]}},{{function,decode_packet,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,629}],[<<100,101,99,111,100,101,95,112,97,99,107,101,116,47,51>>],#{<<101,110>> => [{p,[],[<<68,101,99,111,100,101,115,32,116,104,101,32,98,105,110,97,114,121,32>>,{code,[],[<<66,105,110>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,112,97,99,107,101,116,32,112,114,111,116,111,99,111,108,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<84,121,112,101>>]},<<46,32,83,105,109,105,108,97,114,32,116,111,32,116,104,101,32,112,97,99,107,101,116,32,104,97,110,100,108,105,110,103,32,100,111,110,101,32,98,121,32,115,111,99,107,101,116,115,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,112,97,99,107,101,116,44,84,121,112,101,125,46>>]}]},{p,[],[<<73,102,32,97,110,32,101,110,116,105,114,101,32,112,97,99,107,101,116,32,105,115,32,99,111,110,116,97,105,110,101,100,32,105,110,32>>,{code,[],[<<66,105,110>>]},<<44,32,105,116,32,105,115,32,114,101,116,117,114,110,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,97,115,32>>,{code,[],[<<123,111,107,44,80,97,99,107,101,116,44,82,101,115,116,125>>]},<<46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,105,110>>]},<<32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,116,104,101,32,101,110,116,105,114,101,32,112,97,99,107,101,116,44,32>>,{code,[],[<<123,109,111,114,101,44,76,101,110,103,116,104,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32>>,{code,[],[<<76,101,110,103,116,104>>]},<<32,105,115,32,101,105,116,104,101,114,32,116,104,101,32,101,120,112,101,99,116,101,100,32>>,{em,[],[<<116,111,116,97,108,32,115,105,122,101>>]},<<32,111,102,32,116,104,101,32,112,97,99,107,101,116,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,101,120,112,101,99,116,101,100,32,112,97,99,107,101,116,32,115,105,122,101,32,105,115,32,117,110,107,110,111,119,110,46,32>>,{code,[],[<<100,101,99,111,100,101,95,112,97,99,107,101,116>>]},<<32,99,97,110,32,116,104,101,110,32,98,101,32,99,97,108,108,101,100,32,97,103,97,105,110,32,119,105,116,104,32,109,111,114,101,32,100,97,116,97,32,97,100,100,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,97,99,107,101,116,32,100,111,101,115,32,110,111,116,32,99,111,110,102,111,114,109,32,116,111,32,116,104,101,32,112,114,111,116,111,99,111,108,32,102,111,114,109,97,116,44,32>>,{code,[],[<<123,101,114,114,111,114,44,82,101,97,115,111,110,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<114,97,119,32,124,32,48>>]}]},{dd,[],[{p,[],[<<78,111,32,112,97,99,107,101,116,32,104,97,110,100,108,105,110,103,32,105,115,32,100,111,110,101,46,32,84,104,101,32,101,110,116,105,114,101,32,98,105,110,97,114,121,32,105,115,32,114,101,116,117,114,110,101,100,32,117,110,108,101,115,115,32,105,116,32,105,115,32,101,109,112,116,121,46>>]}]},{dt,[],[{code,[],[<<49,32,124,32,50,32,124,32,52>>]}]},{dd,[],[{p,[],[<<80,97,99,107,101,116,115,32,99,111,110,115,105,115,116,32,111,102,32,97,32,104,101,97,100,101,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,110,32,116,104,101,32,112,97,99,107,101,116,44,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,97,116,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46,32,84,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,104,101,97,100,101,114,32,99,97,110,32,98,101,32,111,110,101,44,32,116,119,111,44,32,111,114,32,102,111,117,114,32,98,121,116,101,115,59,32,116,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,98,121,116,101,115,32,105,115,32,98,105,103,45,101,110,100,105,97,110,46,32,84,104,101,32,104,101,97,100,101,114,32,105,115,32,115,116,114,105,112,112,101,100,32,111,102,102,32,119,104,101,110,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{code,[],[<<108,105,110,101>>]}]},{dd,[],[{p,[],[<<65,32,112,97,99,107,101,116,32,105,115,32,97,32,108,105,110,101,45,116,101,114,109,105,110,97,116,101,100,32,98,121,32,97,32,100,101,108,105,109,105,116,101,114,32,98,121,116,101,44,32,100,101,102,97,117,108,116,32,105,115,32,116,104,101,32,108,97,116,105,110,45,49,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,100,101,108,105,109,105,116,101,114,32,98,121,116,101,32,105,115,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,112,97,99,107,101,116,32,117,110,108,101,115,115,32,116,104,101,32,108,105,110,101,32,119,97,115,32,116,114,117,110,99,97,116,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,111,112,116,105,111,110,32>>,{code,[],[<<108,105,110,101,95,108,101,110,103,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,115,110,49,32,124,32,99,100,114,32,124,32,115,117,110,114,109,32,124,32,102,99,103,105,32,124,32,116,112,107,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,104,101,97,100,101,114,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,116,114,105,112,112,101,100,32,111,102,102,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,116,121,112,101,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,115,110,49>>]},<<32,45,32,65,83,78,46,49,32,66,69,82>>]},{dd,[],[]},{dt,[],[{code,[],[<<115,117,110,114,109>>]},<<32,45,32,83,117,110,39,115,32,82,80,67,32,101,110,99,111,100,105,110,103>>]},{dd,[],[]},{dt,[],[{code,[],[<<99,100,114>>]},<<32,45,32,67,79,82,66,65,32,40,71,73,79,80,32,49,46,49,41>>]},{dd,[],[]},{dt,[],[{code,[],[<<102,99,103,105>>]},<<32,45,32,70,97,115,116,32,67,71,73>>]},{dd,[],[]},{dt,[],[{code,[],[<<116,112,107,116>>]},<<32,45,32,84,80,75,84,32,102,111,114,109,97,116,32,91,82,70,67,49,48,48,54,93>>]},{dd,[],[]}]}]},{dt,[],[{code,[],[<<104,116,116,112,32,124,32,104,116,116,112,104,32,124,32,104,116,116,112,95,98,105,110,32,124,32,104,116,116,112,104,95,98,105,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,72,121,112,101,114,116,101,120,116,32,84,114,97,110,115,102,101,114,32,80,114,111,116,111,99,111,108,46,32,84,104,101,32,112,97,99,107,101,116,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,119,105,116,104,32,116,104,101,32,102,111,114,109,97,116,32,97,99,99,111,114,100,105,110,103,32,116,111,32>>,{code,[],[<<72,116,116,112,80,97,99,107,101,116>>]},<<32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46,32,65,32,112,97,99,107,101,116,32,105,115,32,101,105,116,104,101,114,32,97,32,114,101,113,117,101,115,116,44,32,97,32,114,101,115,112,111,110,115,101,44,32,97,32,104,101,97,100,101,114,44,32,111,114,32,97,110,32,101,110,100,32,111,102,32,104,101,97,100,101,114,32,109,97,114,107,46,32,73,110,118,97,108,105,100,32,108,105,110,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32>>,{code,[],[<<72,116,116,112,69,114,114,111,114>>]},<<46>>]},{p,[],[<<82,101,99,111,103,110,105,122,101,100,32,114,101,113,117,101,115,116,32,109,101,116,104,111,100,115,32,97,110,100,32,104,101,97,100,101,114,32,102,105,101,108,100,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,97,116,111,109,115,46,32,79,116,104,101,114,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,115,116,114,105,110,103,115,46,32,83,116,114,105,110,103,115,32,111,102,32,117,110,114,101,99,111,103,110,105,122,101,100,32,104,101,97,100,101,114,32,102,105,101,108,100,115,32,97,114,101,32,102,111,114,109,97,116,116,101,100,32,119,105,116,104,32,111,110,108,121,32,99,97,112,105,116,97,108,32,108,101,116,116,101,114,115,32,102,105,114,115,116,32,97,110,100,32,97,102,116,101,114,32,104,121,112,104,101,110,32,99,104,97,114,97,99,116,101,114,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<34,83,101,99,45,87,101,98,115,111,99,107,101,116,45,75,101,121,34>>]},<<46,32,72,101,97,100,101,114,32,102,105,101,108,100,32,110,97,109,101,115,32,97,114,101,32,97,108,115,111,32,114,101,116,117,114,110,101,100,32,105,110,32>>,{code,[],[<<85,110,109,111,100,105,102,105,101,100,70,105,101,108,100>>]},<<32,97,115,32,115,116,114,105,110,103,115,44,32,119,105,116,104,111,117,116,32,97,110,121,32,99,111,110,118,101,114,115,105,111,110,32,111,114,32,102,111,114,109,97,116,116,105,110,103,46>>]},{p,[],[<<84,104,101,32,112,114,111,116,111,99,111,108,32,116,121,112,101,32>>,{code,[],[<<104,116,116,112>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,108,105,110,101,32,119,104,101,110,32,97,110,32>>,{code,[],[<<72,116,116,112,82,101,113,117,101,115,116>>]},<<32,111,114,32,97,110,32>>,{code,[],[<<72,116,116,112,82,101,115,112,111,110,115,101>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,97,114,101,32,116,111,32,117,115,101,32>>,{code,[],[<<104,116,116,112,104>>]},<<32,116,111,32,103,101,116,32>>,{code,[],[<<72,116,116,112,72,101,97,100,101,114>>]},<<115,32,117,110,116,105,108,32>>,{code,[],[<<104,116,116,112,95,101,111,104>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,119,104,105,99,104,32,109,97,114,107,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,104,101,97,100,101,114,115,32,97,110,100,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,110,121,32,102,111,108,108,111,119,105,110,103,32,109,101,115,115,97,103,101,32,98,111,100,121,46>>]},{p,[],[<<84,104,101,32,118,97,114,105,97,110,116,115,32>>,{code,[],[<<104,116,116,112,95,98,105,110>>]},<<32,97,110,100,32>>,{code,[],[<<104,116,116,112,104,95,98,105,110>>]},<<32,114,101,116,117,114,110,32,115,116,114,105,110,103,115,32,40>>,{code,[],[<<72,116,116,112,83,116,114,105,110,103>>]},<<41,32,97,115,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,108,105,115,116,115,46>>]}]}]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,97,99,107,101,116,95,115,105,122,101,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,97,108,108,111,119,101,100,32,115,105,122,101,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,98,111,100,121,46,32,73,102,32,116,104,101,32,112,97,99,107,101,116,32,104,101,97,100,101,114,32,105,110,100,105,99,97,116,101,115,32,116,104,97,116,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,101,32,109,97,120,105,109,117,109,32,97,108,108,111,119,101,100,32,108,101,110,103,116,104,44,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,105,110,118,97,108,105,100,46,32,68,101,102,97,117,108,116,115,32,116,111,32,48,44,32,119,104,105,99,104,32,109,101,97,110,115,32,110,111,32,115,105,122,101,32,108,105,109,105,116,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,95,108,101,110,103,116,104,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<70,111,114,32,112,97,99,107,101,116,32,116,121,112,101,32>>,{code,[],[<<108,105,110,101>>]},<<44,32,108,105,110,101,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,101,32,105,110,100,105,99,97,116,101,100,32,108,101,110,103,116,104,32,97,114,101,32,116,114,117,110,99,97,116,101,100,46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<108,105,110,101,95,108,101,110,103,116,104>>]},<<32,97,108,115,111,32,97,112,112,108,105,101,115,32,116,111,32>>,{code,[],[<<104,116,116,112,42>>]},<<32,112,97,99,107,101,116,32,116,121,112,101,115,32,97,115,32,97,110,32,97,108,105,97,115,32,102,111,114,32,111,112,116,105,111,110,32>>,{code,[],[<<112,97,99,107,101,116,95,115,105,122,101>>]},<<32,105,102,32>>,{code,[],[<<112,97,99,107,101,116,95,115,105,122,101>>]},<<32,105,116,115,101,108,102,32,105,115,32,110,111,116,32,115,101,116,46,32,84,104,105,115,32,117,115,101,32,105,115,32,111,110,108,121,32,105,110,116,101,110,100,101,100,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,95,100,101,108,105,109,105,116,101,114,44,32,48,32,61,60,32,98,121,116,101,40,41,32,61,60,32,50,53,53,125>>]}]},{dd,[],[{p,[],[<<70,111,114,32,112,97,99,107,101,116,32,116,121,112,101,32>>,{code,[],[<<108,105,110,101>>]},<<44,32,115,101,116,115,32,116,104,101,32,100,101,108,105,109,105,116,105,110,103,32,98,121,116,101,46,32,68,101,102,97,117,108,116,32,105,115,32,116,104,101,32,108,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<36,92,110>>]},<<46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,100,101,99,111,100,101,95,112,97,99,107,101,116,40,49,44,60,60,51,44,34,97,98,99,100,34,62,62,44,91,93,41,46,10,123,111,107,44,60,60,34,97,98,99,34,62,62,44,60,60,34,100,34,62,62,125,10,62,32,101,114,108,97,110,103,58,100,101,99,111,100,101,95,112,97,99,107,101,116,40,49,44,60,60,53,44,34,97,98,99,100,34,62,62,44,91,93,41,46,10,123,109,111,114,101,44,54,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,53,50>>,signature => [{attribute,629,spec,{{erlang,decode_packet,3},[{type,629,bounded_fun,[{type,629,'fun',[{type,629,product,[{var,629,'Type'},{var,629,'Bin'},{var,629,'Options'}]},{type,630,union,[{type,630,tuple,[{atom,630,ok},{var,630,'Packet'},{var,630,'Rest'}]},{type,631,tuple,[{atom,631,more},{var,631,'Length'}]},{type,632,tuple,[{atom,632,error},{var,632,'Reason'}]}]}]},[{type,633,constraint,[{atom,633,is_subtype},[{var,633,'Type'},{type,633,union,[{atom,633,raw},{integer,633,0},{integer,633,1},{integer,633,2},{integer,633,4},{atom,633,asn1},{atom,633,cdr},{atom,633,sunrm},{atom,633,fcgi},{atom,634,tpkt},{atom,634,line},{atom,634,http},{atom,634,http_bin},{atom,634,httph},{atom,634,httph_bin}]}]]},{type,635,constraint,[{atom,635,is_subtype},[{var,635,'Bin'},{type,635,binary,[]}]]},{type,636,constraint,[{atom,636,is_subtype},[{var,636,'Options'},{type,636,list,[{var,636,'Opt'}]}]]},{type,637,constraint,[{atom,637,is_subtype},[{var,637,'Opt'},{type,637,union,[{type,637,tuple,[{atom,637,packet_size},{type,637,non_neg_integer,[]}]},{type,638,tuple,[{atom,638,line_length},{type,638,non_neg_integer,[]}]}]}]]},{type,639,constraint,[{atom,639,is_subtype},[{var,639,'Packet'},{type,639,union,[{type,639,binary,[]},{var,639,'HttpPacket'}]}]]},{type,640,constraint,[{atom,640,is_subtype},[{var,640,'Rest'},{type,640,binary,[]}]]},{type,641,constraint,[{atom,641,is_subtype},[{var,641,'Length'},{type,641,union,[{type,641,non_neg_integer,[]},{atom,641,undefined}]}]]},{type,642,constraint,[{atom,642,is_subtype},[{var,642,'Reason'},{type,642,term,[]}]]},{type,643,constraint,[{atom,643,is_subtype},[{var,643,'HttpPacket'},{type,643,union,[{var,643,'HttpRequest'},{var,644,'HttpResponse'},{var,645,'HttpHeader'},{atom,646,http_eoh},{var,647,'HttpError'}]}]]},{type,648,constraint,[{atom,648,is_subtype},[{var,648,'HttpRequest'},{type,648,tuple,[{atom,648,http_request},{var,648,'HttpMethod'},{var,648,'HttpUri'},{var,648,'HttpVersion'}]}]]},{type,649,constraint,[{atom,649,is_subtype},[{var,649,'HttpResponse'},{type,649,tuple,[{atom,649,http_response},{var,649,'HttpVersion'},{type,649,integer,[]},{var,649,'HttpString'}]}]]},{type,650,constraint,[{atom,650,is_subtype},[{var,650,'HttpHeader'},{type,650,tuple,[{atom,650,http_header},{type,651,integer,[]},{var,652,'HttpField'},{ann_type,653,[{var,653,'UnmodifiedField'},{var,653,'HttpString'}]},{ann_type,654,[{var,654,'Value'},{var,654,'HttpString'}]}]}]]},{type,655,constraint,[{atom,655,is_subtype},[{var,655,'HttpError'},{type,655,tuple,[{atom,655,http_error},{var,655,'HttpString'}]}]]},{type,656,constraint,[{atom,656,is_subtype},[{var,656,'HttpMethod'},{type,656,union,[{atom,656,'OPTIONS'},{atom,656,'GET'},{atom,656,'HEAD'},{atom,656,'POST'},{atom,656,'PUT'},{atom,656,'DELETE'},{atom,657,'TRACE'},{var,657,'HttpString'}]}]]},{type,658,constraint,[{atom,658,is_subtype},[{var,658,'HttpUri'},{type,658,union,[{atom,658,'*'},{type,659,tuple,[{atom,659,absoluteURI},{type,660,union,[{atom,660,http},{atom,660,https}]},{ann_type,661,[{var,661,'Host'},{var,661,'HttpString'}]},{ann_type,662,[{var,662,'Port'},{type,662,union,[{remote_type,662,[{atom,662,inet},{atom,662,port_number},[]]},{atom,662,undefined}]}]},{ann_type,663,[{var,663,'Path'},{var,663,'HttpString'}]}]},{type,664,tuple,[{atom,664,scheme},{ann_type,664,[{var,664,'Scheme'},{var,664,'HttpString'}]},{var,664,'HttpString'}]},{type,665,tuple,[{atom,665,abs_path},{var,665,'HttpString'}]},{var,666,'HttpString'}]}]]},{type,667,constraint,[{atom,667,is_subtype},[{var,667,'HttpVersion'},{type,667,tuple,[{ann_type,667,[{var,667,'Major'},{type,667,non_neg_integer,[]}]},{ann_type,667,[{var,667,'Minor'},{type,667,non_neg_integer,[]}]}]}]]},{type,668,constraint,[{atom,668,is_subtype},[{var,668,'HttpField'},{type,668,union,[{atom,668,'Cache-Control'},{atom,669,'Connection'},{atom,670,'Date'},{atom,671,'Pragma'},{atom,672,'Transfer-Encoding'},{atom,673,'Upgrade'},{atom,674,'Via'},{atom,675,'Accept'},{atom,676,'Accept-Charset'},{atom,677,'Accept-Encoding'},{atom,678,'Accept-Language'},{atom,679,'Authorization'},{atom,680,'From'},{atom,681,'Host'},{atom,682,'If-Modified-Since'},{atom,683,'If-Match'},{atom,684,'If-None-Match'},{atom,685,'If-Range'},{atom,686,'If-Unmodified-Since'},{atom,687,'Max-Forwards'},{atom,688,'Proxy-Authorization'},{atom,689,'Range'},{atom,690,'Referer'},{atom,691,'User-Agent'},{atom,692,'Age'},{atom,693,'Location'},{atom,694,'Proxy-Authenticate'},{atom,695,'Public'},{atom,696,'Retry-After'},{atom,697,'Server'},{atom,698,'Vary'},{atom,699,'Warning'},{atom,700,'Www-Authenticate'},{atom,701,'Allow'},{atom,702,'Content-Base'},{atom,703,'Content-Encoding'},{atom,704,'Content-Language'},{atom,705,'Content-Length'},{atom,706,'Content-Location'},{atom,707,'Content-Md5'},{atom,708,'Content-Range'},{atom,709,'Content-Type'},{atom,710,'Etag'},{atom,711,'Expires'},{atom,712,'Last-Modified'},{atom,713,'Accept-Ranges'},{atom,714,'Set-Cookie'},{atom,715,'Set-Cookie2'},{atom,716,'X-Forwarded-For'},{atom,717,'Cookie'},{atom,718,'Keep-Alive'},{atom,719,'Proxy-Connection'},{var,720,'HttpString'}]}]]},{type,721,constraint,[{atom,721,is_subtype},[{var,721,'HttpString'},{type,721,union,[{type,721,string,[]},{type,721,binary,[]}]}]]}]]}]}}]}},{{function,delete_element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,726}],[<<100,101,108,101,116,101,95,101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,119,105,116,104,32,101,108,101,109,101,110,116,32,97,116,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,100,101,108,101,116,101,95,101,108,101,109,101,110,116,40,50,44,32,123,111,110,101,44,32,116,119,111,44,32,116,104,114,101,101,125,41,46,10,123,111,110,101,44,116,104,114,101,101,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,54,52>>,signature => [{attribute,726,spec,{{erlang,delete_element,2},[{type,726,bounded_fun,[{type,726,'fun',[{type,726,product,[{var,726,'Index'},{var,726,'Tuple1'}]},{var,726,'Tuple2'}]},[{type,727,constraint,[{atom,727,is_subtype},[{var,727,'Index'},{type,727,pos_integer,[]}]]},{type,728,constraint,[{atom,728,is_subtype},[{var,728,'Tuple1'},{type,728,tuple,any}]]},{type,729,constraint,[{atom,729,is_subtype},[{var,729,'Tuple2'},{type,729,tuple,any}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,delete_module,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,734}],[<<100,101,108,101,116,101,95,109,111,100,117,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<77,97,107,101,115,32,116,104,101,32,99,117,114,114,101,110,116,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,98,101,99,111,109,101,32,111,108,100,32,99,111,100,101,32,97,110,100,32,100,101,108,101,116,101,115,32,97,108,108,32,114,101,102,101,114,101,110,99,101,115,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,102,114,111,109,32,116,104,101,32,101,120,112,111,114,116,32,116,97,98,108,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,97,108,114,101,97,100,121,32,105,115,32,97,110,32,111,108,100,32,118,101,114,115,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,55,55>>,signature => [{attribute,734,spec,{{delete_module,1},[{type,734,bounded_fun,[{type,734,'fun',[{type,734,product,[{var,734,'Module'}]},{type,734,union,[{atom,734,true},{atom,734,undefined}]}]},[{type,735,constraint,[{atom,735,is_subtype},[{var,735,'Module'},{type,735,module,[]}]]}]]}]}}]}},{{function,demonitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,740}],[<<100,101,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,111,98,116,97,105,110,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,50>>]}]},<<44,32,116,104,105,115,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,46,32,73,102,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,97,108,114,101,97,100,121,32,116,117,114,110,101,100,32,111,102,102,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46>>]},{p,[],[<<79,110,99,101,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]},<<32,104,97,115,32,114,101,116,117,114,110,101,100,44,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,110,111,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,44,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,44,32,119,105,108,108,32,98,101,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46,32,72,111,119,101,118,101,114,44,32,97,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,32,99,97,110,32,104,97,118,101,32,98,101,101,110,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,46,32,73,116,32,105,115,32,116,104,101,114,101,102,111,114,101,32,117,115,117,97,108,108,121,32,97,100,118,105,115,97,98,108,101,32,116,111,32,114,101,109,111,118,101,32,115,117,99,104,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,102,114,111,109,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,102,116,101,114,32,109,111,110,105,116,111,114,105,110,103,32,104,97,115,32,98,101,101,110,32,115,116,111,112,112,101,100,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,102,108,117,115,104,93,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]},<<32,105,102,32,116,104,105,115,32,99,108,101,97,110,117,112,32,105,115,32,119,97,110,116,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,32,40,69,82,84,83,32,53,46,53,41,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]},<<32,98,101,104,97,118,101,100,32,99,111,109,112,108,101,116,101,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,97,99,116,105,118,101,32,117,110,116,105,108,32,116,104,101,32,34,100,101,109,111,110,105,116,111,114,32,115,105,103,110,97,108,34,32,114,101,97,99,104,101,100,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,46,32,84,104,105,115,32,104,97,100,32,111,110,101,32,117,110,100,101,115,105,114,97,98,108,101,32,101,102,102,101,99,116,46,32,89,111,117,32,99,111,117,108,100,32,110,101,118,101,114,32,107,110,111,119,32,119,104,101,110,32,121,111,117,32,119,101,114,101,32,103,117,97,114,97,110,116,101,101,100,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,114,101,99,101,105,118,101,32,97,32>>,{code,[],[<<68,79,87,78>>]},<<32,109,101,115,115,97,103,101,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,118,105,101,119,101,100,32,97,115,32,116,119,111,32,99,111,109,98,105,110,101,100,32,111,112,101,114,97,116,105,111,110,115,58,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,32,115,101,110,100,32,97,32,34,100,101,109,111,110,105,116,111,114,32,115,105,103,110,97,108,34,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,32,97,110,100,32,105,103,110,111,114,101,32,97,110,121,32,102,117,116,117,114,101,32,114,101,115,117,108,116,115,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32,73,116,32,105,115,32,97,110,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,109,111,110,105,116,111,114,105,110,103,32,115,116,97,114,116,101,100,32,98,121,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,78,111,116,32,97,108,108,32,115,117,99,104,32,99,97,115,101,115,32,97,114,101,32,99,104,101,97,112,32,116,111,32,99,104,101,99,107,46,32,73,102,32,99,104,101,99,107,105,110,103,32,105,115,32,99,104,101,97,112,44,32,116,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,32,105,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,105,115,32,97,32,114,101,109,111,116,101,32,114,101,102,101,114,101,110,99,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,57,53>>,signature => [{attribute,740,spec,{{demonitor,1},[{type,740,bounded_fun,[{type,740,'fun',[{type,740,product,[{var,740,'MonitorRef'}]},{atom,740,true}]},[{type,741,constraint,[{atom,741,is_subtype},[{var,741,'MonitorRef'},{type,741,reference,[]}]]}]]}]}}]}},{{function,demonitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,746}],[<<100,101,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,117,110,108,101,115,115,32>>,{code,[],[<<105,110,102,111>>]},<<32,105,115,32,112,97,114,116,32,111,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<46>>]},{p,[],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]}]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,108,117,115,104>>]}]},{dd,[],[{p,[],[<<82,101,109,111,118,101,115,32,40,111,110,101,41,32>>,{code,[],[<<123,95,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,44,32,105,102,32,116,104,101,114,101,32,105,115,32,111,110,101,44,32,102,114,111,109,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,102,116,101,114,32,109,111,110,105,116,111,114,105,110,103,32,104,97,115,32,98,101,101,110,32,115,116,111,112,112,101,100,46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,102,108,117,115,104,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41,44,10,114,101,99,101,105,118,101,10,32,32,32,32,123,95,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,97,102,116,101,114,32,48,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,101,110,100>>]}]}]},{dt,[],[{code,[],[<<105,110,102,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,102,111,117,110,100,32,97,110,100,32,114,101,109,111,118,101,100,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,110,111,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,105,115,32,109,111,110,105,116,111,114,32,104,97,115,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,97,110,100,32,119,105,108,108,32,110,111,116,32,98,101,32,100,101,108,105,118,101,114,101,100,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,110,111,116,32,102,111,117,110,100,32,97,110,100,32,99,111,117,108,100,32,110,111,116,32,98,101,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,112,114,111,98,97,98,108,121,32,98,101,99,97,117,115,101,32,115,111,109,101,111,110,101,32,97,108,114,101,97,100,121,32,104,97,115,32,112,108,97,99,101,100,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,105,115,32,109,111,110,105,116,111,114,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]}]}]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<105,110,102,111>>]},<<32,105,115,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<102,108,117,115,104>>]},<<44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,102,32,97,32,102,108,117,115,104,32,119,97,115,32,110,101,101,100,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<77,111,114,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<84,104,101,32,115,97,109,101,32,102,97,105,108,117,114,101,32,97,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]}]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,51,55>>,signature => [{attribute,746,spec,{{demonitor,2},[{type,746,bounded_fun,[{type,746,'fun',[{type,746,product,[{var,746,'MonitorRef'},{var,746,'OptionList'}]},{type,746,boolean,[]}]},[{type,747,constraint,[{atom,747,is_subtype},[{var,747,'MonitorRef'},{type,747,reference,[]}]]},{type,748,constraint,[{atom,748,is_subtype},[{var,748,'OptionList'},{type,748,list,[{var,748,'Option'}]}]]},{type,749,constraint,[{atom,749,is_subtype},[{var,749,'Option'},{type,749,union,[{atom,749,flush},{atom,749,info}]}]]}]]}]}}]}},{{function,disconnect_node,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3429}],[<<100,105,115,99,111,110,110,101,99,116,95,110,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<70,111,114,99,101,115,32,116,104,101,32,100,105,115,99,111,110,110,101,99,116,105,111,110,32,111,102,32,97,32,110,111,100,101,46,32,84,104,105,115,32,97,112,112,101,97,114,115,32,116,111,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<32,97,115,32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,104,97,115,32,99,114,97,115,104,101,100,46,32,84,104,105,115,32,66,73,70,32,105,115,32,109,97,105,110,108,121,32,117,115,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,110,101,116,119,111,114,107,32,97,117,116,104,101,110,116,105,99,97,116,105,111,110,32,112,114,111,116,111,99,111,108,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,100,105,115,99,111,110,110,101,99,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<105,103,110,111,114,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,109,97,121,32,114,101,116,117,114,110,32,98,101,102,111,114,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,110,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,115>>]},<<32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,48,53>>,signature => [{attribute,3429,spec,{{disconnect_node,1},[{type,3429,bounded_fun,[{type,3429,'fun',[{type,3429,product,[{var,3429,'Node'}]},{type,3429,union,[{type,3429,boolean,[]},{atom,3429,ignored}]}]},[{type,3430,constraint,[{atom,3430,is_subtype},[{var,3430,'Node'},{type,3430,node,[]}]]}]]}]}}]}},{{function,display,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,773}],[<<100,105,115,112,108,97,121,47,49>>],#{<<101,110>> => [{p,[],[<<80,114,105,110,116,115,32,97,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,111,110,32,116,104,101,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,50,52>>,signature => [{attribute,773,spec,{{erlang,display,1},[{type,773,bounded_fun,[{type,773,'fun',[{type,773,product,[{var,773,'Term'}]},{atom,773,true}]},[{type,774,constraint,[{atom,774,is_subtype},[{var,774,'Term'},{type,774,term,[]}]]}]]}]}}]}},{{function,dist_ctrl_get_data,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3713}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>],#{<<101,110>> => [{p,[],[<<71,101,116,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,100,97,116,97,32,102,114,111,109,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,116,104,97,116,32,105,115,32,116,111,32,98,101,32,112,97,115,115,101,100,32,116,111,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,46,32,84,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,73,102,32,110,111,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,44,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,110,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,110,101,32,99,97,110,32,114,101,113,117,101,115,116,32,116,111,32,98,101,32,105,110,102,111,114,109,101,100,32,98,121,32,97,32,109,101,115,115,97,103,101,32,119,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,40,68,72,97,110,100,108,101,41>>]}]},<<46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,119,104,101,110,32,116,104,101,114,101,32,97,114,101,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,99,111,110,102,105,103,117,114,101,100,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>]}]},<<32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,51,54>>,signature => [{attribute,3713,spec,{{erlang,dist_ctrl_get_data,1},[{type,3713,bounded_fun,[{type,3713,'fun',[{type,3713,product,[{var,3713,'DHandle'}]},{type,3713,union,[{type,3713,tuple,[{var,3713,'Size'},{var,3713,'Data'}]},{var,3713,'Data'},{atom,3713,none}]}]},[{type,3714,constraint,[{atom,3714,is_subtype},[{var,3714,'Size'},{type,3714,non_neg_integer,[]}]]},{type,3715,constraint,[{atom,3715,is_subtype},[{var,3715,'DHandle'},{user_type,3715,dist_handle,[]}]]},{type,3716,constraint,[{atom,3716,is_subtype},[{var,3716,'Data'},{user_type,3716,iovec,[]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_get_opt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3735}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,111,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>]}]},<<32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,55,55>>,signature => [{attribute,3735,spec,{{erlang,dist_ctrl_get_opt,2},[{type,3735,bounded_fun,[{type,3735,'fun',[{type,3735,product,[{var,3735,'DHandle'},{atom,3735,get_size}]},{var,3735,'Value'}]},[{type,3736,constraint,[{atom,3736,is_subtype},[{var,3736,'DHandle'},{user_type,3736,dist_handle,[]}]]},{type,3737,constraint,[{atom,3737,is_subtype},[{var,3737,'Value'},{type,3737,boolean,[]}]]}]]}]}}],since => <<79,84,80,32,50,50,46,48>>}},{{function,dist_ctrl_get_data_notification,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3721}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,113,117,101,115,116,32,110,111,116,105,102,105,99,97,116,105,111,110,32,119,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,102,101,116,99,104,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]}]},<<32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,87,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<46,32,79,110,99,101,32,97,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<32,109,101,115,115,97,103,101,115,32,104,97,115,32,98,101,101,110,32,115,101,110,116,44,32,110,111,32,109,111,114,101,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<32,109,101,115,115,97,103,101,115,32,119,105,108,108,32,98,101,32,115,101,110,116,32,117,110,116,105,108,32,116,104,101,32>>,{code,[],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>]},<<32,102,117,110,99,116,105,111,110,32,104,97,115,32,98,101,101,110,32,99,97,108,108,101,100,32,97,103,97,105,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,53,48,54>>,signature => [{attribute,3721,spec,{{erlang,dist_ctrl_get_data_notification,1},[{type,3721,bounded_fun,[{type,3721,'fun',[{type,3721,product,[{var,3721,'DHandle'}]},{atom,3721,ok}]},[{type,3722,constraint,[{atom,3722,is_subtype},[{var,3722,'DHandle'},{user_type,3722,dist_handle,[]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_input_handler,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3699}],[<<100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,103,105,115,116,101,114,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,79,110,99,101,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,104,97,115,32,98,101,101,110,32,99,97,108,108,101,100,44,32>>,{code,[],[<<73,110,112,117,116,72,97,110,100,108,101,114>>]},<<32,105,115,32,116,104,101,32,111,110,108,121,32,112,114,111,99,101,115,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,40,68,72,97,110,100,108,101,44,32,68,97,116,97,41>>]}]},<<32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,100,101,110,116,105,102,105,110,103,32,116,104,105,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,53,52,50>>,signature => [{attribute,3699,spec,{{erlang,dist_ctrl_input_handler,2},[{type,3699,bounded_fun,[{type,3699,'fun',[{type,3699,product,[{var,3699,'DHandle'},{var,3699,'InputHandler'}]},{atom,3699,ok}]},[{type,3700,constraint,[{atom,3700,is_subtype},[{var,3700,'DHandle'},{user_type,3700,dist_handle,[]}]]},{type,3701,constraint,[{atom,3701,is_subtype},[{var,3701,'InputHandler'},{type,3701,pid,[]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_put_data,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3706}],[<<100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,47,50>>],#{<<101,110>> => [{p,[],[<<68,101,108,105,118,101,114,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,100,97,116,97,32,102,114,111,109,32,97,32,114,101,109,111,116,101,32,110,111,100,101,32,116,111,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,117,110,108,101,115,115,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,40,68,72,97,110,100,108,101,44,32,73,110,112,117,116,72,97,110,100,108,101,114,41>>]}]},<<46,32,73,102,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,104,97,115,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,44,32,111,110,108,121,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,53,55,53>>,signature => [{attribute,3706,spec,{{erlang,dist_ctrl_put_data,2},[{type,3706,bounded_fun,[{type,3706,'fun',[{type,3706,product,[{var,3706,'DHandle'},{var,3706,'Data'}]},{atom,3706,ok}]},[{type,3707,constraint,[{atom,3707,is_subtype},[{var,3707,'DHandle'},{user_type,3707,dist_handle,[]}]]},{type,3708,constraint,[{atom,3708,is_subtype},[{var,3708,'Data'},{type,3708,iodata,[]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_set_opt,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3727}],[<<100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,84,104,105,115,32,111,112,116,105,111,110,32,99,111,110,116,114,111,108,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,99,97,108,108,115,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,117,115,101,100,32,119,104,101,110,32,115,101,116,116,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46,32,87,104,101,110,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[<<97,110,100,32,116,104,101,114,101,32,97,114,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,44,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,105,108,108,32,106,117,115,116,32,114,101,116,117,114,110,32>>,{code,[],[<<68,97,116,97>>]},<<32,116,111,32,112,97,115,115,32,111,118,101,114,32,116,104,101,32,99,104,97,110,110,101,108,46,32,84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,46>>]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[<<97,110,100,32,116,104,101,114,101,32,97,114,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,44,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,105,108,108,32,114,101,116,117,114,110,32>>,{code,[],[<<68,97,116,97>>]},<<32,116,111,32,112,97,115,115,32,111,118,101,114,32,116,104,101,32,99,104,97,110,110,101,108,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32>>,{code,[],[<<83,105,122,101>>]},<<32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,110,32,98,121,116,101,115,46,32,84,104,105,115,32,105,115,32,114,101,116,117,114,110,101,100,32,97,115,32,97,32,116,117,112,108,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,83,105,122,101,44,32,68,97,116,97,125>>]},<<46>>]}]},{p,[],[<<65,108,108,32,111,112,116,105,111,110,115,32,97,114,101,32,115,101,116,32,116,111,32,100,101,102,97,117,108,116,32,119,104,101,110,32,97,32,99,104,97,110,110,101,108,32,105,115,32,99,108,111,115,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,48,56>>,signature => [{attribute,3727,spec,{{erlang,dist_ctrl_set_opt,3},[{type,3727,bounded_fun,[{type,3727,'fun',[{type,3727,product,[{var,3727,'DHandle'},{atom,3727,get_size},{var,3727,'Value'}]},{var,3727,'OldValue'}]},[{type,3728,constraint,[{atom,3728,is_subtype},[{var,3728,'DHandle'},{user_type,3728,dist_handle,[]}]]},{type,3729,constraint,[{atom,3729,is_subtype},[{var,3729,'Value'},{type,3729,boolean,[]}]]},{type,3730,constraint,[{atom,3730,is_subtype},[{var,3730,'OldValue'},{type,3730,boolean,[]}]]}]]}]}}],since => <<79,84,80,32,50,50,46,48>>}},{{function,element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2116}],[<<101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{code,[],[<<78>>]},<<116,104,32,101,108,101,109,101,110,116,32,40,110,117,109,98,101,114,105,110,103,32,102,114,111,109,32,49,41,32,111,102,32>>,{code,[],[<<84,117,112,108,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,108,101,109,101,110,116,40,50,44,32,123,97,44,32,98,44,32,99,125,41,46,10,98>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,53,55>>,signature => [{attribute,2116,spec,{{element,2},[{type,2116,bounded_fun,[{type,2116,'fun',[{type,2116,product,[{var,2116,'N'},{var,2116,'Tuple'}]},{type,2116,term,[]}]},[{type,2117,constraint,[{atom,2117,is_subtype},[{var,2117,'N'},{type,2117,pos_integer,[]}]]},{type,2118,constraint,[{atom,2118,is_subtype},[{var,2118,'Tuple'},{type,2118,tuple,any}]]}]]}]}}]}},{{function,erase,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,832}],[<<101,114,97,115,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,110,100,32,100,101,108,101,116,101,115,32,105,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,123,49,44,32,50,44,32,51,125,41,44,10,112,117,116,40,107,101,121,50,44,32,91,97,44,32,98,44,32,99,93,41,44,10,101,114,97,115,101,40,41,46,10,91,123,107,101,121,49,44,123,49,44,50,44,51,125,125,44,123,107,101,121,50,44,91,97,44,98,44,99,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,55,49>>,signature => [{attribute,832,spec,{{erase,0},[{type,832,bounded_fun,[{type,832,'fun',[{type,832,product,[]},{type,832,list,[{type,832,tuple,[{var,832,'Key'},{var,832,'Val'}]}]}]},[{type,833,constraint,[{atom,833,is_subtype},[{var,833,'Key'},{type,833,term,[]}]]},{type,834,constraint,[{atom,834,is_subtype},[{var,834,'Val'},{type,834,term,[]}]]}]]}]}}]}},{{function,erase,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,839}],[<<101,114,97,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,97,110,100,32,100,101,108,101,116,101,115,32,105,116,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,110,111,32,118,97,108,117,101,32,105,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<46,32,84,104,101,32,97,118,101,114,97,103,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,123,109,101,114,114,121,44,32,108,97,109,98,115,44,32,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,88,32,61,32,101,114,97,115,101,40,107,101,121,49,41,44,10,123,88,44,32,101,114,97,115,101,40,107,101,121,49,41,125,46,10,123,123,109,101,114,114,121,44,108,97,109,98,115,44,97,114,101,44,112,108,97,121,105,110,103,125,44,117,110,100,101,102,105,110,101,100,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,56,53>>,signature => [{attribute,839,spec,{{erase,1},[{type,839,bounded_fun,[{type,839,'fun',[{type,839,product,[{var,839,'Key'}]},{type,839,union,[{var,839,'Val'},{atom,839,undefined}]}]},[{type,840,constraint,[{atom,840,is_subtype},[{var,840,'Key'},{type,840,term,[]}]]},{type,841,constraint,[{atom,841,is_subtype},[{var,841,'Val'},{type,841,term,[]}]]}]]}]}}]}},{{function,error,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,847}],[<<101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,46,32,84,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,32>>,{code,[],[<<123,82,101,97,115,111,110,44,32,87,104,101,114,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<87,104,101,114,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,99,97,108,108,101,100,32,40,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,102,105,114,115,116,41,46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,116,104,114,111,119,110,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,97,116,99,104,32,101,114,114,111,114,40,102,111,111,98,97,114,41,46,10,123,39,69,88,73,84,39,44,123,102,111,111,98,97,114,44,91,123,115,104,101,108,108,44,97,112,112,108,121,95,102,117,110,44,51,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,57,48,54,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,101,114,108,95,101,118,97,108,44,100,111,95,97,112,112,108,121,44,54,44,91,123,102,105,108,101,44,34,101,114,108,95,101,118,97,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,55,55,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,101,114,108,95,101,118,97,108,44,101,120,112,114,44,53,44,91,123,102,105,108,101,44,34,101,114,108,95,101,118,97,108,46,101,114,108,34,125,44,123,108,105,110,101,44,52,51,48,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,120,112,114,115,44,55,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,56,55,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,118,97,108,95,101,120,112,114,115,44,55,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,52,50,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,118,97,108,95,108,111,111,112,44,51,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,50,55,125,93,125,93,125,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,48,54>>,signature => [{attribute,847,spec,{{error,1},[{type,847,bounded_fun,[{type,847,'fun',[{type,847,product,[{var,847,'Reason'}]},{type,847,no_return,[]}]},[{type,848,constraint,[{atom,848,is_subtype},[{var,848,'Reason'},{type,848,term,[]}]]}]]}]}}]}},{{function,error,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,854}],[<<101,114,114,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,46,32,84,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,32>>,{code,[],[<<123,82,101,97,115,111,110,44,32,87,104,101,114,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<87,104,101,114,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,99,97,108,108,101,100,32,40,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,102,105,114,115,116,41,46,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,116,104,101,32,108,105,115,116,32,111,102,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,59,32,105,116,32,105,115,32,117,115,101,100,32,116,111,32,112,114,111,118,105,100,101,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,101,32,116,101,114,109,32>>,{code,[],[<<87,104,101,114,101>>]},<<46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46,32,69,120,97,109,112,108,101,58>>]},{p,[],[{code,[],[<<116,101,115,116,46,101,114,108>>]},<<58>>]},{pre,[],[{code,[],[<<45,109,111,100,117,108,101,40,116,101,115,116,41,46,10,45,101,120,112,111,114,116,40,91,101,120,97,109,112,108,101,95,102,117,110,47,50,93,41,46,10,10,101,120,97,109,112,108,101,95,102,117,110,40,65,49,44,32,65,50,41,32,45,62,10,32,32,32,32,101,114,108,97,110,103,58,101,114,114,111,114,40,109,121,95,101,114,114,111,114,44,32,91,65,49,44,32,65,50,93,41,46>>]}]},{p,[],[<<69,114,108,97,110,103,32,115,104,101,108,108,58>>]},{pre,[],[{code,[],[<<54,62,32,99,40,116,101,115,116,41,46,10,123,111,107,44,116,101,115,116,125,10,55,62,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,40,97,114,103,49,44,34,116,104,105,115,32,105,115,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,34,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,114,114,111,114,58,32,109,121,95,101,114,114,111,114,10,32,32,32,32,32,105,110,32,102,117,110,99,116,105,111,110,32,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,47,50,10,32,32,32,32,32,32,32,32,32,99,97,108,108,101,100,32,97,115,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,40,97,114,103,49,44,34,116,104,105,115,32,105,115,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,34,41,10,32>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,51,53>>,signature => [{attribute,854,spec,{{error,2},[{type,854,bounded_fun,[{type,854,'fun',[{type,854,product,[{var,854,'Reason'},{var,854,'Args'}]},{type,854,no_return,[]}]},[{type,855,constraint,[{atom,855,is_subtype},[{var,855,'Reason'},{type,855,term,[]}]]},{type,856,constraint,[{atom,856,is_subtype},[{var,856,'Args'},{type,856,list,[{type,856,term,[]}]}]]}]]}]}}]}},{{function,error,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,862}],[<<101,114,114,111,114,47,51>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,46,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,116,104,101,32,108,105,115,116,32,111,102,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,59,32,105,116,32,105,115,32,117,115,101,100,32,116,111,32,112,114,111,118,105,100,101,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,101,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,46,32,73,102,32,116,104,101,32>>,{code,[],[<<123,101,114,114,111,114,95,105,110,102,111,44,32,69,114,114,111,114,73,110,102,111,77,97,112,125>>]},<<32,111,112,116,105,111,110,32,105,115,32,103,105,118,101,110,44,32,105,116,32,119,105,108,108,32,98,101,32,105,110,106,101,99,116,101,100,32,105,110,116,111,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,46>>]},{p,[],[<<65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,55,53>>,signature => [{attribute,862,spec,{{error,3},[{type,862,bounded_fun,[{type,862,'fun',[{type,862,product,[{var,862,'Reason'},{var,862,'Args'},{var,862,'Options'}]},{type,862,no_return,[]}]},[{type,863,constraint,[{atom,863,is_subtype},[{var,863,'Reason'},{type,863,term,[]}]]},{type,864,constraint,[{atom,864,is_subtype},[{var,864,'Args'},{type,864,list,[{type,864,term,[]}]}]]},{type,865,constraint,[{atom,865,is_subtype},[{var,865,'Options'},{type,865,list,[{var,865,'Option'}]}]]},{type,866,constraint,[{atom,866,is_subtype},[{var,866,'Option'},{type,866,tuple,[{atom,866,error_info},{var,866,'ErrorInfoMap'}]}]]},{type,867,constraint,[{atom,867,is_subtype},[{var,867,'ErrorInfoMap'},{type,867,map,[{type,867,map_field_assoc,[{atom,867,cause},{type,867,term,[]}]},{type,868,map_field_assoc,[{atom,868,module},{type,868,module,[]}]},{type,869,map_field_assoc,[{atom,869,function},{type,869,atom,[]}]}]}]]}]]}]}}],since => <<50,52,46,48>>}},{{function,exit,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,875}],[<<101,120,105,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,120,105,116>>]},<<32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,105,110,116,101,110,116,32,105,115,32,116,111,32,115,116,111,112,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,100,105,102,102,101,114,32,102,114,111,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,114,114,111,114,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,114,114,111,114,47,50>>]}]},<<32,98,121,32,99,97,117,115,105,110,103,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,97,32,100,105,102,102,101,114,101,110,116,32,99,108,97,115,115,32,97,110,100,32,98,121,32,104,97,118,105,110,103,32,97,32,114,101,97,115,111,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,116,104,101,32,108,105,115,116,32,111,102,32,102,117,110,99,116,105,111,110,115,32,102,114,111,109,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,120,105,116,40,102,111,111,98,97,114,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,120,105,116,58,32,102,111,111,98,97,114,10,62,32,99,97,116,99,104,32,101,120,105,116,40,102,111,111,98,97,114,41,46,10,123,39,69,88,73,84,39,44,102,111,111,98,97,114,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,99,97,108,108,115,32>>,{code,[],[<<101,120,105,116,40,107,105,108,108,41>>]},<<32,97,110,100,32,100,111,101,115,32,110,111,116,32,99,97,116,99,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,44,32,105,116,32,119,105,108,108,32,116,101,114,109,105,110,97,116,101,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,97,110,100,32,97,108,115,111,32,101,109,105,116,32,101,120,105,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,40,110,111,116,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<41,32,116,111,32,97,108,108,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,83,117,99,104,32,101,120,105,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,99,97,110,32,98,101,32,116,114,97,112,112,101,100,32,98,121,32,116,104,101,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,98,101,104,97,118,101,32,100,105,102,102,101,114,101,110,116,108,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,121,32,97,114,101,32,115,101,110,116,32,98,101,99,97,117,115,101,32,116,104,101,32,115,105,103,110,97,108,32,119,105,108,108,32,98,101,32,117,110,116,114,97,112,112,97,98,108,101,32,105,102,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,115,117,99,104,32,97,32,115,105,103,110,97,108,32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]}]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,57,55>>,signature => [{attribute,875,spec,{{exit,1},[{type,875,bounded_fun,[{type,875,'fun',[{type,875,product,[{var,875,'Reason'}]},{type,875,no_return,[]}]},[{type,876,constraint,[{atom,876,is_subtype},[{var,876,'Reason'},{type,876,term,[]}]]}]]}]}}]}},{{function,exit,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,881}],[<<101,120,105,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,98,101,104,97,118,105,111,114,32,97,112,112,108,105,101,115,32,105,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,44,32,101,120,99,101,112,116,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,111,114,32>>,{code,[],[<<107,105,108,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<80>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32>>,{code,[],[<<80>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,115,101,110,116,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,102,32>>,{code,[],[<<80>>]},<<46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,98,101,104,97,118,105,111,114,32,97,112,112,108,105,101,115,32,105,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,116,101,114,109,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80>>]},<<32,119,104,105,99,104,32,105,115,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,110,118,111,107,101,100,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,40,80,105,100,44,32,110,111,114,109,97,108,41>>]},<<32,40,116,104,101,32,98,101,104,97,118,105,111,114,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,97,32,115,105,103,110,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,114,101,97,115,111,110,32,116,111,32,105,116,115,101,108,102,32,105,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,119,97,114,110,105,110,103,41,58>>]},{ul,[],[{li,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,110,111,114,109,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,115,101,110,116,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80>>]},<<39,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{li,[],[<<84,104,101,32,115,105,103,110,97,108,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,105,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,46>>]}]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<107,105,108,108>>]},<<44,32,116,104,97,116,32,105,115,44,32,105,102,32>>,{code,[],[<<101,120,105,116,40,80,105,100,44,32,107,105,108,108,41>>]},<<32,105,115,32,99,97,108,108,101,100,44,32,97,110,32,117,110,116,114,97,112,112,97,98,108,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,119,104,105,99,104,32,117,110,99,111,110,100,105,116,105,111,110,97,108,108,121,32,101,120,105,116,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<46,32,84,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32>>,{code,[],[<<107,105,108,108>>]},<<32,116,111,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<32,116,111,32,104,105,110,116,32,116,111,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,116,104,101,32,107,105,108,108,101,100,32,112,114,111,99,101,115,115,32,103,111,116,32,107,105,108,108,101,100,32,98,121,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,120,105,116,40,80,105,100,44,32,107,105,108,108,41>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]}]},<<32,97,114,101,32,110,97,109,101,100,32,115,105,109,105,108,97,114,108,121,32,98,117,116,32,112,114,111,118,105,100,101,32,118,101,114,121,32,100,105,102,102,101,114,101,110,116,32,102,117,110,99,116,105,111,110,97,108,105,116,105,101,115,46,32,84,104,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]},<<32,102,117,110,99,116,105,111,110,32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,105,110,116,101,110,116,32,105,115,32,116,111,32,115,116,111,112,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,119,104,105,108,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,105,110,116,101,110,116,32,105,115,32,116,111,32,115,101,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,78,111,116,101,32,97,108,115,111,32,116,104,97,116,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]},<<32,114,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,99,97,110,32,98,101,32,99,97,117,103,104,116,32,119,104,105,108,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,100,111,101,115,32,110,111,116,32,99,97,117,115,101,32,97,110,121,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,32,111,110,108,121,32,115,99,101,110,97,114,105,111,32,116,104,97,116,32,104,97,115,32,110,111,116,32,98,101,101,110,32,99,111,118,101,114,101,100,32,98,121,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,97,98,111,118,101,32,105,115,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80>>]},<<32,115,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,116,111,32,105,116,115,101,108,102,44,32,116,104,97,116,32,105,115,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,40,115,101,108,102,40,41,44,32,110,111,114,109,97,108,41>>]},<<46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,110,32,116,104,105,115,32,115,99,101,110,97,114,105,111,32,105,115,32,97,115,32,102,111,108,108,111,119,115,58>>]},{ul,[],[{li,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,110,111,114,109,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32>>,{code,[],[<<80>>]},<<39,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80>>]},<<39,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{li,[],[{code,[],[<<80>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,105,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,46>>]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,98,101,104,97,118,105,111,114,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,97,114,103,117,97,98,108,121,32,115,116,114,97,110,103,101,32,98,117,116,32,116,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,114,101,97,115,111,110,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,56,51,57>>,signature => [{attribute,881,spec,{{exit,2},[{type,881,bounded_fun,[{type,881,'fun',[{type,881,product,[{var,881,'Pid'},{var,881,'Reason'}]},{atom,881,true}]},[{type,882,constraint,[{atom,882,is_subtype},[{var,882,'Pid'},{type,882,union,[{type,882,pid,[]},{type,882,port,[]}]}]]},{type,883,constraint,[{atom,883,is_subtype},[{var,883,'Reason'},{type,883,term,[]}]]}]]}]}}]}},{{function,external_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,895}],[<<101,120,116,101,114,110,97,108,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,97,108,99,117,108,97,116,101,115,44,32,119,105,116,104,111,117,116,32,100,111,105,110,103,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,109,97,120,105,109,117,109,32,98,121,116,101,32,115,105,122,101,32,102,111,114,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,110,100,105,116,105,111,110,32,97,112,112,108,105,101,115,32,97,108,119,97,121,115,58>>]},{pre,[],[{code,[],[<<62,32,83,105,122,101,49,32,61,32,98,121,116,101,95,115,105,122,101,40,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,41,41,44,10,62,32,83,105,122,101,50,32,61,32,101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,41,44,10,62,32,116,114,117,101,32,61,32,83,105,122,101,49,32,61,60,32,83,105,122,101,50,46,10,116,114,117,101>>]}]},{p,[],[<<84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,97,32,99,97,108,108,32,116,111,58>>]},{pre,[],[{code,[],[<<101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,44,32,91,93,41>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,50,53>>,signature => [{attribute,895,spec,{{erlang,external_size,1},[{type,895,bounded_fun,[{type,895,'fun',[{type,895,product,[{var,895,'Term'}]},{type,895,non_neg_integer,[]}]},[{type,896,constraint,[{atom,896,is_subtype},[{var,896,'Term'},{type,896,term,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,external_size,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,901}],[<<101,120,116,101,114,110,97,108,95,115,105,122,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,108,99,117,108,97,116,101,115,44,32,119,105,116,104,111,117,116,32,100,111,105,110,103,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,109,97,120,105,109,117,109,32,98,121,116,101,32,115,105,122,101,32,102,111,114,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,110,100,105,116,105,111,110,32,97,112,112,108,105,101,115,32,97,108,119,97,121,115,58>>]},{pre,[],[{code,[],[<<62,32,83,105,122,101,49,32,61,32,98,121,116,101,95,115,105,122,101,40,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,44,32,79,112,116,105,111,110,115,41,41,44,10,62,32,83,105,122,101,50,32,61,32,101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,44,32,79,112,116,105,111,110,115,41,44,10,62,32,116,114,117,101,32,61,32,83,105,122,101,49,32,61,60,32,83,105,122,101,50,46,10,116,114,117,101>>]}]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<123,109,105,110,111,114,95,118,101,114,115,105,111,110,44,32,86,101,114,115,105,111,110,125>>]},<<32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,102,108,111,97,116,115,32,97,114,101,32,101,110,99,111,100,101,100,46,32,70,111,114,32,97,32,100,101,116,97,105,108,101,100,32,100,101,115,99,114,105,112,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,52,52>>,signature => [{attribute,901,spec,{{erlang,external_size,2},[{type,901,bounded_fun,[{type,901,'fun',[{type,901,product,[{var,901,'Term'},{var,901,'Options'}]},{type,901,non_neg_integer,[]}]},[{type,902,constraint,[{atom,902,is_subtype},[{var,902,'Term'},{type,902,term,[]}]]},{type,903,constraint,[{atom,903,is_subtype},[{var,903,'Options'},{type,903,list,[{type,903,tuple,[{atom,903,minor_version},{ann_type,903,[{var,903,'Version'},{type,903,non_neg_integer,[]}]}]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,925}],[<<102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,102,108,111,97,116,32,98,121,32,99,111,110,118,101,114,116,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,97,32,102,108,111,97,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,40,53,53,41,46,10,53,53,46,48>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,117,115,101,100,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,105,110,32,97,32,103,117,97,114,100,44,32,105,116,32,116,101,115,116,115,32,119,104,101,116,104,101,114,32,116,104,101,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,59,32,102,111,114,32,99,108,97,114,105,116,121,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,115,95,102,108,111,97,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,102,108,111,97,116,47,49>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<87,104,101,110,32>>,{code,[],[<<102,108,111,97,116,47,49>>]},<<32,105,115,32,117,115,101,100,32,105,110,32,97,110,32,101,120,112,114,101,115,115,105,111,110,32,105,110,32,97,32,103,117,97,114,100,44,32,115,117,99,104,32,97,115,32,39>>,{code,[],[<<102,108,111,97,116,40,65,41,32,61,61,32,52,46,48>>]},<<39,44,32,105,116,32,99,111,110,118,101,114,116,115,32,97,32,110,117,109,98,101,114,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,54,52>>,signature => [{attribute,925,spec,{{float,1},[{type,925,bounded_fun,[{type,925,'fun',[{type,925,product,[{var,925,'Number'}]},{type,925,float,[]}]},[{type,926,constraint,[{atom,926,is_subtype},[{var,926,'Number'},{type,926,number,[]}]]}]]}]}}]}},{{function,float_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,931}],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,70,108,111,97,116,44,91,123,115,99,105,101,110,116,105,102,105,99,44,50,48,125,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,56,54>>,signature => [{attribute,931,spec,{{float_to_binary,1},[{type,931,bounded_fun,[{type,931,'fun',[{type,931,product,[{var,931,'Float'}]},{type,931,binary,[]}]},[{type,932,constraint,[{atom,932,is_subtype},[{var,932,'Float'},{type,932,float,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,float_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,937}],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,117,115,105,110,103,32,102,105,120,101,100,32,100,101,99,105,109,97,108,32,112,111,105,110,116,32,102,111,114,109,97,116,116,105,110,103,46,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<32,98,101,104,97,118,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>]}]},<<46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,93,41,46,10,60,60,34,55,46,49,50,48,48,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,44,32,99,111,109,112,97,99,116,93,41,46,10,60,60,34,55,46,49,50,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,115,99,105,101,110,116,105,102,105,99,44,32,51,125,93,41,46,10,60,60,34,55,46,49,50,48,101,43,48,48,34,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,57,53>>,signature => [{attribute,937,spec,{{float_to_binary,2},[{type,937,bounded_fun,[{type,937,'fun',[{type,937,product,[{var,937,'Float'},{var,937,'Options'}]},{type,937,binary,[]}]},[{type,938,constraint,[{atom,938,is_subtype},[{var,938,'Float'},{type,938,float,[]}]]},{type,939,constraint,[{atom,939,is_subtype},[{var,939,'Options'},{type,939,list,[{var,939,'Option'}]}]]},{type,940,constraint,[{atom,940,is_subtype},[{var,940,'Option'},{type,940,union,[{type,940,tuple,[{atom,940,decimals},{ann_type,940,[{var,940,'Decimals'},{type,940,range,[{integer,940,0},{integer,940,253}]}]}]},{type,941,tuple,[{atom,941,scientific},{ann_type,941,[{var,941,'Decimals'},{type,941,range,[{integer,941,0},{integer,941,249}]}]}]},{atom,942,compact}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,float_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,947}],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,40,70,108,111,97,116,44,91,123,115,99,105,101,110,116,105,102,105,99,44,50,48,125,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,49,53>>,signature => [{attribute,947,spec,{{float_to_list,1},[{type,947,bounded_fun,[{type,947,'fun',[{type,947,product,[{var,947,'Float'}]},{type,947,string,[]}]},[{type,948,constraint,[{atom,948,is_subtype},[{var,948,'Float'},{type,948,float,[]}]]}]]}]}}]}},{{function,float_to_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,953}],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,117,115,105,110,103,32,102,105,120,101,100,32,100,101,99,105,109,97,108,32,112,111,105,110,116,32,102,111,114,109,97,116,116,105,110,103,46>>]},{p,[],[<<65,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,99,105,109,97,108,115>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,99,111,110,116,97,105,110,115,32,97,116,32,109,111,115,116,32>>,{code,[],[<<68,101,99,105,109,97,108,115>>]},<<32,110,117,109,98,101,114,32,111,102,32,100,105,103,105,116,115,32,112,97,115,116,32,116,104,101,32,100,101,99,105,109,97,108,32,112,111,105,110,116,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,100,111,101,115,32,110,111,116,32,102,105,116,32,105,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,115,116,97,116,105,99,32,98,117,102,102,101,114,32,111,102,32,50,53,54,32,98,121,116,101,115,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,104,114,111,119,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,97,99,116>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,116,114,97,105,108,105,110,103,32,122,101,114,111,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,108,105,115,116,32,97,114,101,32,116,114,117,110,99,97,116,101,100,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,109,101,97,110,105,110,103,102,117,108,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,99,105,109,97,108,115>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<115,99,105,101,110,116,105,102,105,99>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,108,111,97,116,32,105,115,32,102,111,114,109,97,116,116,101,100,32,117,115,105,110,103,32,115,99,105,101,110,116,105,102,105,99,32,110,111,116,97,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<68,101,99,105,109,97,108,115>>]},<<32,100,105,103,105,116,115,32,111,102,32,112,114,101,99,105,115,105,111,110,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32>>,{code,[],[<<91,93>>]},<<44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,98,101,104,97,118,101,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>]}]},<<46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,93,41,46,10,34,55,46,49,50,48,48,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,44,32,99,111,109,112,97,99,116,93,41,46,10,34,55,46,49,50,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,115,99,105,101,110,116,105,102,105,99,44,32,51,125,93,41,46,10,34,55,46,49,50,48,101,43,48,48,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,48,46,49,43,48,46,50,41,10,34,51,46,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,52,52,48,57,101,45,48,49,34>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,40,48,46,49,43,48,46,50,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<34,51,46,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,52,52,48,57,101,45,48,49,34>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,101,120,112,108,97,105,110,101,100,32,105,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,50,52>>,signature => [{attribute,953,spec,{{float_to_list,2},[{type,953,bounded_fun,[{type,953,'fun',[{type,953,product,[{var,953,'Float'},{var,953,'Options'}]},{type,953,string,[]}]},[{type,954,constraint,[{atom,954,is_subtype},[{var,954,'Float'},{type,954,float,[]}]]},{type,955,constraint,[{atom,955,is_subtype},[{var,955,'Options'},{type,955,list,[{var,955,'Option'}]}]]},{type,956,constraint,[{atom,956,is_subtype},[{var,956,'Option'},{type,956,union,[{type,956,tuple,[{atom,956,decimals},{ann_type,956,[{var,956,'Decimals'},{type,956,range,[{integer,956,0},{integer,956,253}]}]}]},{type,957,tuple,[{atom,957,scientific},{ann_type,957,[{var,957,'Decimals'},{type,957,range,[{integer,957,0},{integer,957,249}]}]}]},{atom,958,compact}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,floor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,964}],[<<102,108,111,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,97,114,103,101,115,116,32,105,110,116,101,103,101,114,32,110,111,116,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,111,114,40,45,49,48,46,53,41,46,10,45,49,49>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,55,48>>,signature => [{attribute,964,spec,{{floor,1},[{type,964,bounded_fun,[{type,964,'fun',[{type,964,product,[{var,964,'Number'}]},{type,964,integer,[]}]},[{type,965,constraint,[{atom,965,is_subtype},[{var,965,'Number'},{type,965,number,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,fun_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3434}],[<<102,117,110,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,117,110,32>>,{code,[],[<<70,117,110>>]},<<46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,117,112,108,101,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,100,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,109,97,105,110,108,121,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,44,32,98,117,116,32,105,116,32,99,97,110,32,115,111,109,101,116,105,109,101,115,32,98,101,32,117,115,101,102,117,108,32,105,110,32,108,105,98,114,97,114,121,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,110,101,101,100,32,116,111,32,118,101,114,105,102,121,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,97,114,105,116,121,32,111,102,32,97,32,102,117,110,46>>]}]},{p,[],[<<84,119,111,32,116,121,112,101,115,32,111,102,32,102,117,110,115,32,104,97,118,101,32,115,108,105,103,104,116,108,121,32,100,105,102,102,101,114,101,110,116,32,115,101,109,97,110,116,105,99,115,58>>]},{ul,[],[{li,[],[{p,[],[<<65,32,102,117,110,32,99,114,101,97,116,101,100,32,98,121,32>>,{code,[],[<<102,117,110,32,77,58,70,47,65>>]},<<32,105,115,32,99,97,108,108,101,100,32,97,110,32>>,{em,[],[<<101,120,116,101,114,110,97,108>>]},<<32,102,117,110,46,32,67,97,108,108,105,110,103,32,105,116,32,119,105,108,108,32,97,108,119,97,121,115,32,99,97,108,108,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70>>]},<<32,119,105,116,104,32,97,114,105,116,121,32>>,{code,[],[<<65>>]},<<32,105,110,32,116,104,101,32,108,97,116,101,115,116,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,100,117,108,101,32>>,{code,[],[<<77>>]},<<32,100,111,101,115,32,110,111,116,32,101,118,101,110,32,110,101,101,100,32,116,111,32,98,101,32,108,111,97,100,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,32>>,{code,[],[<<102,117,110,32,77,58,70,47,65>>]},<<32,105,115,32,99,114,101,97,116,101,100,46>>]}]},{li,[],[{p,[],[<<65,108,108,32,111,116,104,101,114,32,102,117,110,115,32,97,114,101,32,99,97,108,108,101,100,32>>,{em,[],[<<108,111,99,97,108>>]},<<46,32,87,104,101,110,32,97,32,108,111,99,97,108,32,102,117,110,32,105,115,32,99,97,108,108,101,100,44,32,116,104,101,32,115,97,109,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,102,117,110,32,105,115,32,99,97,108,108,101,100,32,40,101,118,101,110,32,105,102,32,97,32,110,101,119,101,114,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,109,111,100,117,108,101,32,104,97,115,32,98,101,101,110,32,108,111,97,100,101,100,41,46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,108,101,109,101,110,116,115,32,97,114,101,32,97,108,119,97,121,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,32,102,111,114,32,98,111,116,104,32,108,111,99,97,108,32,97,110,100,32,101,120,116,101,114,110,97,108,32,102,117,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,116,121,112,101,44,32,84,121,112,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,114,32>>,{code,[],[<<101,120,116,101,114,110,97,108>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,111,100,117,108,101,44,32,77,111,100,117,108,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,40,97,110,32,97,116,111,109,41,32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,110,97,109,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,105,110,32,119,104,105,99,104,32,116,104,101,32,102,117,110,32,105,115,32,100,101,102,105,110,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,116,104,97,116,32,116,104,101,32,102,117,110,32,114,101,102,101,114,115,32,116,111,46>>]}]},{dt,[],[{code,[],[<<123,110,97,109,101,44,32,78,97,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,40,97,110,32,97,116,111,109,41,32,105,115,32,97,32,102,117,110,99,116,105,111,110,32,110,97,109,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,105,109,112,108,101,109,101,110,116,115,32,116,104,101,32,102,117,110,46,32,40,84,104,105,115,32,110,97,109,101,32,119,97,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,97,110,100,32,105,115,32,111,110,108,121,32,111,102,32,105,110,102,111,114,109,97,116,105,111,110,97,108,32,117,115,101,46,32,65,115,32,105,116,32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,99,97,108,108,101,100,32,100,105,114,101,99,116,108,121,46,41,32,73,102,32,110,111,32,99,111,100,101,32,105,115,32,99,117,114,114,101,110,116,108,121,32,108,111,97,100,101,100,32,102,111,114,32,116,104,101,32,102,117,110,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,97,110,32,97,116,111,109,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,116,104,101,32,102,117,110,32,114,101,102,101,114,115,32,116,111,46>>]}]},{dt,[],[{code,[],[<<123,97,114,105,116,121,44,32,65,114,105,116,121,125>>]}]},{dd,[],[{p,[],[{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,116,104,97,116,32,116,104,101,32,102,117,110,32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,119,105,116,104,46>>]}]},{dt,[],[{code,[],[<<123,101,110,118,44,32,69,110,118,125>>]}]},{dd,[],[{p,[],[{code,[],[<<69,110,118>>]},<<32,40,97,32,108,105,115,116,41,32,105,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,114,32,102,114,101,101,32,118,97,114,105,97,98,108,101,115,32,102,111,114,32,116,104,101,32,102,117,110,46,32,70,111,114,32,101,120,116,101,114,110,97,108,32,102,117,110,115,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,105,115,32,97,108,119,97,121,115,32,101,109,112,116,121,46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,108,101,109,101,110,116,115,32,97,114,101,32,111,110,108,121,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,32,105,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,108,111,99,97,108,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,105,100,44,32,80,105,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,114,105,103,105,110,97,108,108,121,32,99,114,101,97,116,101,100,32,116,104,101,32,102,117,110,46>>]},{p,[],[<<73,116,32,109,105,103,104,116,32,112,111,105,110,116,32,116,111,32,116,104,101,32>>,{code,[],[<<105,110,105,116>>]},<<32,112,114,111,99,101,115,115,32,105,102,32,116,104,101,32>>,{code,[],[<<70,117,110>>]},<<32,119,97,115,32,115,116,97,116,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,119,104,101,110,32,109,111,100,117,108,101,32,119,97,115,32,108,111,97,100,101,100,32,40,116,104,105,115,32,111,112,116,105,109,105,115,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,102,111,114,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,100,111,32,110,111,116,32,99,97,112,116,117,114,101,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,41,46>>]}]},{dt,[],[{code,[],[<<123,105,110,100,101,120,44,32,73,110,100,101,120,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,110,32,105,110,100,101,120,32,105,110,116,111,32,116,104,101,32,109,111,100,117,108,101,32,102,117,110,32,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,95,105,110,100,101,120,44,32,73,110,100,101,120,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,110,32,105,110,100,101,120,32,105,110,116,111,32,116,104,101,32,109,111,100,117,108,101,32,102,117,110,32,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,95,117,110,105,113,44,32,85,110,105,113,125>>]}]},{dd,[],[{p,[],[{code,[],[<<85,110,105,113>>]},<<32,40,97,32,98,105,110,97,114,121,41,32,105,115,32,97,32,117,110,105,113,117,101,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,46,32,73,116,32,105,115,32,99,97,108,99,117,108,97,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,109,111,100,117,108,101,46>>]}]},{dt,[],[{code,[],[<<123,117,110,105,113,44,32,85,110,105,113,125>>]}]},{dd,[],[{p,[],[{code,[],[<<85,110,105,113>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,32,117,110,105,113,117,101,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,46,32,65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,53,44,32,116,104,105,115,32,105,110,116,101,103,101,114,32,105,115,32,99,97,108,99,117,108,97,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,109,111,100,117,108,101,46,32,66,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,53,44,32,116,104,105,115,32,105,110,116,101,103,101,114,32,119,97,115,32,98,97,115,101,100,32,111,110,32,111,110,108,121,32,116,104,101,32,98,111,100,121,32,111,102,32,116,104,101,32,102,117,110,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,56,52>>,signature => [{attribute,3434,spec,{{erlang,fun_info,1},[{type,3434,bounded_fun,[{type,3434,'fun',[{type,3434,product,[{var,3434,'Fun'}]},{type,3434,list,[{type,3434,tuple,[{var,3434,'Item'},{var,3434,'Info'}]}]}]},[{type,3435,constraint,[{atom,3435,is_subtype},[{var,3435,'Fun'},{type,3435,function,[]}]]},{type,3436,constraint,[{atom,3436,is_subtype},[{var,3436,'Item'},{type,3436,union,[{atom,3436,arity},{atom,3436,env},{atom,3436,index},{atom,3436,name},{atom,3437,module},{atom,3437,new_index},{atom,3437,new_uniq},{atom,3437,pid},{atom,3437,type},{atom,3437,uniq}]}]]},{type,3438,constraint,[{atom,3438,is_subtype},[{var,3438,'Info'},{type,3438,term,[]}]]}]]}]}}]}},{{function,fun_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,970}],[<<102,117,110,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<102,117,110,95,105,110,102,111,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32>>,{code,[],[<<70,117,110>>]},<<32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,73,116,101,109,44,73,110,102,111,125>>]},<<46>>]},{p,[],[<<70,111,114,32,97,110,121,32,102,117,110,44,32>>,{code,[],[<<73,116,101,109>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<109,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<110,97,109,101>>]},<<44,32>>,{code,[],[<<97,114,105,116,121>>]},<<44,32>>,{code,[],[<<101,110,118>>]},<<44,32,111,114,32>>,{code,[],[<<116,121,112,101>>]},<<46>>]},{p,[],[<<70,111,114,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<73,116,101,109>>]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<44,32>>,{code,[],[<<110,101,119,95,105,110,100,101,120>>]},<<44,32>>,{code,[],[<<110,101,119,95,117,110,105,113>>]},<<44,32>>,{code,[],[<<117,110,105,113>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,105,100>>]},<<46,32,70,111,114,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,97,110,121,32,111,102,32,116,104,101,115,101,32,105,116,101,109,115,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,49,56,57>>,signature => [{attribute,970,spec,{{erlang,fun_info,2},[{type,970,bounded_fun,[{type,970,'fun',[{type,970,product,[{var,970,'Fun'},{var,970,'Item'}]},{type,970,tuple,[{var,970,'Item'},{var,970,'Info'}]}]},[{type,971,constraint,[{atom,971,is_subtype},[{var,971,'Fun'},{type,971,function,[]}]]},{type,972,constraint,[{atom,972,is_subtype},[{var,972,'Item'},{user_type,972,fun_info_item,[]}]]},{type,973,constraint,[{atom,973,is_subtype},[{var,973,'Info'},{type,973,term,[]}]]}]]}]}}]}},{{function,fun_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,987}],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,116,104,97,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,99,114,101,97,116,101,100,32>>,{code,[],[<<70,117,110>>]},<<46>>]},{p,[],[{code,[],[<<83,116,114,105,110,103>>]},<<32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,44,32,105,102,32>>,{code,[],[<<70,117,110>>]},<<32,119,97,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,102,117,110,45,101,120,112,114,101,115,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,117,110,32,101,120,112,114,101,115,115,105,111,110>>]},<<32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<102,117,110,32,77,111,100,117,108,101,78,97,109,101,58,70,117,110,99,78,97,109,101,47,65,114,105,116,121>>]},<<58>>]},{p,[],[{code,[],[<<34,102,117,110,32,77,111,100,117,108,101,78,97,109,101,58,70,117,110,99,78,97,109,101,47,65,114,105,116,121,34>>]}]},{p,[],[<<84,104,101,32,102,111,114,109,32,111,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,119,104,101,110,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,111,116,104,101,114,32,116,121,112,101,115,32,111,102,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,102,117,110,45,101,120,112,114,101,115,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,117,110,32,101,120,112,114,101,115,115,105,111,110,115>>]},<<32,100,105,102,102,101,114,115,32,100,101,112,101,110,100,105,110,103,32,111,110,32,105,102,32,116,104,101,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,101,120,101,99,117,116,101,100,32,119,104,105,108,101,32,101,120,101,99,117,116,105,110,103,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,111,114,32,105,102,32,116,104,101,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,101,120,101,99,117,116,101,100,32,119,104,105,108,101,32,101,120,101,99,117,116,105,110,103,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,40,117,110,99,111,109,112,105,108,101,100,32,101,115,99,114,105,112,116,115,44,32,116,104,101,32,69,114,108,97,110,103,32,115,104,101,108,108,44,32,97,110,100,32,111,116,104,101,114,32,99,111,100,101,32,101,120,101,99,117,116,101,100,32,98,121,32,116,104,101,32,101,114,108,95,101,118,97,108,32,109,111,100,117,108,101,41,58>>]},{dl,[],[{dt,[],[<<99,111,109,112,105,108,101,100,32,99,111,100,101>>]},{dd,[],[{p,[],[{code,[],[<<34,35,70,117,110,60,77,46,73,46,85,62,34>>]},<<44,32,119,104,101,114,101,32,77,44,32,73,32,97,110,100,32,85,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,116,104,101,32,118,97,108,117,101,115,32,110,97,109,101,100,32>>,{code,[],[<<109,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<105,110,100,101,120>>]},<<32,97,110,100,32>>,{code,[],[<<117,110,105,113>>]},<<32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,40,70,117,110,41>>]}]},<<46>>]}]},{dt,[],[<<117,110,99,111,109,112,105,108,101,100,32,99,111,100,101>>]},{dd,[],[<<65,108,108,32,102,117,110,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,97,114,105,116,121,32,97,114,101,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,98,121,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<71,101,110,101,114,97,108,108,121,44,32,111,110,101,32,99,97,110,32,110,111,116,32,117,115,101,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,116,111,32,99,104,101,99,107,32,105,102,32,116,119,111,32,102,117,110,115,32,97,114,101,32,101,113,117,97,108,32,97,115,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,100,111,101,115,32,110,111,116,32,116,97,107,101,32,116,104,101,32,102,117,110,39,115,32,101,110,118,105,114,111,110,109,101,110,116,32,105,110,116,111,32,97,99,99,111,117,110,116,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,47,49>>]}]},<<32,102,111,114,32,104,111,119,32,116,111,32,103,101,116,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,102,32,97,32,102,117,110,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,111,117,116,112,117,116,32,111,102,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,69,114,108,97,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,32,97,110,100,32,109,97,121,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,115,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<45,109,111,100,117,108,101,40,116,101,115,116,41,46,10,45,101,120,112,111,114,116,40,91,97,100,100,47,49,44,32,97,100,100,50,47,48,44,32,102,117,110,95,116,117,112,108,101,47,48,93,41,46,10,97,100,100,40,65,41,32,45,62,32,102,117,110,40,66,41,32,45,62,32,65,32,43,32,66,32,101,110,100,46,10,97,100,100,50,40,41,32,45,62,32,102,117,110,32,97,100,100,47,49,46,10,102,117,110,95,116,117,112,108,101,40,41,32,45,62,32,123,102,117,110,40,41,32,45,62,32,49,32,101,110,100,44,32,102,117,110,40,41,32,45,62,32,49,32,101,110,100,125,46,10,32,32,32,32,32,32,32,32>>]}]},{pre,[],[{code,[],[<<62,32,123,102,117,110,32,116,101,115,116,58,97,100,100,47,49,44,32,116,101,115,116,58,97,100,100,50,40,41,125,46,10,123,102,117,110,32,116,101,115,116,58,97,100,100,47,49,44,35,70,117,110,60,116,101,115,116,46,49,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32>>,{code,[],[<<102,117,110,32,116,101,115,116,58,97,100,100,47,49>>]},<<32,105,115,32,117,112,103,114,97,100,97,98,108,101,32,98,117,116,32>>,{code,[],[<<116,101,115,116,58,97,100,100,50,40,41>>]},<<32,105,115,32,110,111,116,32,117,112,103,114,97,100,97,98,108,101,46>>]},{pre,[],[{code,[],[<<62,32,123,116,101,115,116,58,97,100,100,40,49,41,44,32,116,101,115,116,58,97,100,100,40,52,50,41,125,46,10,123,35,70,117,110,60,116,101,115,116,46,48,46,49,48,55,55,51,56,57,56,51,62,44,35,70,117,110,60,116,101,115,116,46,48,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32>>,{code,[],[<<116,101,115,116,58,97,100,100,40,49,41>>]},<<32,97,110,100,32>>,{code,[],[<<116,101,115,116,58,97,100,100,40,52,50,41>>]},<<32,104,97,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,97,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,105,115,32,110,111,116,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,46>>]},{pre,[],[{code,[],[<<62,116,101,115,116,58,102,117,110,95,116,117,112,108,101,40,41,46,10,123,35,70,117,110,60,116,101,115,116,46,50,46,49,48,55,55,51,56,57,56,51,62,44,35,70,117,110,60,116,101,115,116,46,51,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32,84,104,101,32,115,116,114,105,110,103,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,32,100,105,102,102,101,114,32,98,101,99,97,117,115,101,32,116,104,101,32,102,117,110,115,32,99,111,109,101,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,102,117,110,32,101,120,112,101,114,115,115,105,111,110,115,46>>]},{pre,[],[{code,[],[<<62,32,123,102,117,110,40,41,32,45,62,32,49,32,101,110,100,44,32,102,117,110,40,41,32,45,62,32,49,32,101,110,100,125,46,32,62,32,10,123,35,70,117,110,60,101,114,108,95,101,118,97,108,46,52,53,46,57,55,50,56,51,48,57,53,62,44,35,70,117,110,60,101,114,108,95,101,118,97,108,46,52,53,46,57,55,50,56,51,48,57,53,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32,65,108,108,32,102,117,110,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,115,32,111,102,32,116,104,105,115,32,102,111,114,109,32,105,110,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,97,114,105,116,121,32,97,114,101,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,98,121,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,50,48,57>>,signature => [{attribute,987,spec,{{erlang,fun_to_list,1},[{type,987,bounded_fun,[{type,987,'fun',[{type,987,product,[{var,987,'Fun'}]},{ann_type,987,[{var,987,'String'},{type,987,string,[]}]}]},[{type,988,constraint,[{atom,988,is_subtype},[{var,988,'Fun'},{type,988,function,[]}]]}]]}]}}]}},{{function,function_exported,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,993}],[<<102,117,110,99,116,105,111,110,95,101,120,112,111,114,116,101,100,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,108,111,97,100,101,100,32,97,110,100,32,99,111,110,116,97,105,110,115,32,97,110,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<44,32,111,114,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,66,73,70,32,40,97,32,98,117,105,108,116,45,105,110,32,102,117,110,99,116,105,111,110,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,67,41,32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,110,97,109,101,44,32,111,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,117,115,101,100,32,116,111,32,114,101,116,117,114,110,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,102,111,114,32,66,73,70,115,32,98,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,49,56,46,48,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,50,57,56>>,signature => [{attribute,993,spec,{{erlang,function_exported,3},[{type,993,bounded_fun,[{type,993,'fun',[{type,993,product,[{var,993,'Module'},{var,993,'Function'},{var,993,'Arity'}]},{type,993,boolean,[]}]},[{type,994,constraint,[{atom,994,is_subtype},[{var,994,'Module'},{type,994,module,[]}]]},{type,995,constraint,[{atom,995,is_subtype},[{var,995,'Function'},{type,995,atom,[]}]]},{type,996,constraint,[{atom,996,is_subtype},[{var,996,'Arity'},{type,996,arity,[]}]]}]]}]}}]}},{{function,garbage_collect,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1001}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>],#{<<101,110>> => [{p,[],[<<70,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,116,104,101,32,101,120,101,99,117,116,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,117,110,108,101,115,115,32,105,116,32,104,97,115,32,98,101,101,110,32,110,111,116,105,99,101,100,32,40,111,114,32,116,104,101,114,101,32,97,114,101,32,103,111,111,100,32,114,101,97,115,111,110,115,32,116,111,32,115,117,115,112,101,99,116,41,32,116,104,97,116,32,116,104,101,32,115,112,111,110,116,97,110,101,111,117,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,119,105,108,108,32,111,99,99,117,114,32,116,111,111,32,108,97,116,101,32,111,114,32,110,111,116,32,97,116,32,97,108,108,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,109,112,114,111,112,101,114,32,117,115,101,32,99,97,110,32,115,101,114,105,111,117,115,108,121,32,100,101,103,114,97,100,101,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,49,52>>,signature => [{attribute,1001,spec,{{garbage_collect,0},[{type,1001,'fun',[{type,1001,product,[]},{atom,1001,true}]}]}}]}},{{function,garbage_collect,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1006}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,40,80,105,100,44,32,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,51,48>>,signature => [{attribute,1006,spec,{{garbage_collect,1},[{type,1006,bounded_fun,[{type,1006,'fun',[{type,1006,product,[{var,1006,'Pid'}]},{var,1006,'GCResult'}]},[{type,1007,constraint,[{atom,1007,is_subtype},[{var,1007,'Pid'},{type,1007,pid,[]}]]},{type,1008,constraint,[{atom,1008,is_subtype},[{var,1008,'GCResult'},{type,1008,boolean,[]}]]}]]}]}}]}},{{function,garbage_collect,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1022}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<71,97,114,98,97,103,101,32,99,111,108,108,101,99,116,115,32,116,104,101,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,82,101,113,117,101,115,116,73,100,125>>]}]},{dd,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,101,110,116,46,32,87,104,101,110,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,112,97,115,115,101,100,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,44,32,82,101,113,117,101,115,116,73,100,44,32,71,67,82,101,115,117,108,116,125>>]},<<46>>]},{dt,[],[{code,[],[<<123,116,121,112,101,44,32,39,109,97,106,111,114,39,32,124,32,39,109,105,110,111,114,39,125>>]}]},{dd,[],[<<84,114,105,103,103,101,114,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,114,101,113,117,101,115,116,101,100,32,116,121,112,101,46,32,68,101,102,97,117,108,116,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<39,109,97,106,111,114,39>>]},<<44,32,119,104,105,99,104,32,119,111,117,108,100,32,116,114,105,103,103,101,114,32,97,32,102,117,108,108,115,119,101,101,112,32,71,67,46,32,84,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<39,109,105,110,111,114,39>>]},<<32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,32,104,105,110,116,32,97,110,100,32,109,97,121,32,108,101,97,100,32,116,111,32,101,105,116,104,101,114,32,109,105,110,111,114,32,111,114,32,109,97,106,111,114,32,71,67,32,114,117,110,46>>]}]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<44,32,97,110,100,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,116,32,111,110,99,101,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>]}]},<<46,32,79,116,104,101,114,119,105,115,101,32,97,32,114,101,113,117,101,115,116,32,102,111,114,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,110,100,32,119,105,108,108,32,98,101,32,104,97,110,100,108,101,100,32,119,104,101,110,32,97,112,112,114,111,112,114,105,97,116,101,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,98,108,111,99,107,115,32,117,110,116,105,108,32>>,{code,[],[<<71,67,82,101,115,117,108,116>>]},<<32,105,115,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<71,67,82,101,115,117,108,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,114,101,113,117,101,115,116,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,104,97,115,32,98,101,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46>>]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[<<78,111,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,119,97,115,32,112,101,114,102,111,114,109,101,100,44,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,116,101,114,109,105,110,97,116,101,100,32,98,101,102,111,114,101,32,116,104,101,32,114,101,113,117,101,115,116,32,99,111,117,108,100,32,98,101,32,115,97,116,105,115,102,105,101,100,46>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,97,109,101,32,99,97,118,101,97,116,115,32,97,112,112,108,121,32,97,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,52,48>>,signature => [{attribute,1022,spec,{{garbage_collect,2},[{type,1022,bounded_fun,[{type,1022,'fun',[{type,1022,product,[{var,1022,'Pid'},{var,1022,'OptionList'}]},{type,1022,union,[{var,1022,'GCResult'},{atom,1022,async}]}]},[{type,1023,constraint,[{atom,1023,is_subtype},[{var,1023,'Pid'},{type,1023,pid,[]}]]},{type,1024,constraint,[{atom,1024,is_subtype},[{var,1024,'RequestId'},{type,1024,term,[]}]]},{type,1025,constraint,[{atom,1025,is_subtype},[{var,1025,'Option'},{type,1025,union,[{type,1025,tuple,[{atom,1025,async},{var,1025,'RequestId'}]},{type,1025,tuple,[{atom,1025,type},{type,1025,union,[{atom,1025,major},{atom,1025,minor}]}]}]}]]},{type,1026,constraint,[{atom,1026,is_subtype},[{var,1026,'OptionList'},{type,1026,list,[{var,1026,'Option'}]}]]},{type,1027,constraint,[{atom,1027,is_subtype},[{var,1027,'GCResult'},{type,1027,boolean,[]}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,get,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1076}],[<<103,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,75,101,121,44,32,86,97,108,125>>]},<<32,116,117,112,108,101,115,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,109,101,114,114,121,41,44,10,112,117,116,40,107,101,121,50,44,32,108,97,109,98,115,41,44,10,112,117,116,40,107,101,121,51,44,32,123,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,103,101,116,40,41,46,10,91,123,107,101,121,49,44,109,101,114,114,121,125,44,123,107,101,121,50,44,108,97,109,98,115,125,44,123,107,101,121,51,44,123,97,114,101,44,112,108,97,121,105,110,103,125,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,48,53>>,signature => [{attribute,1076,spec,{{get,0},[{type,1076,bounded_fun,[{type,1076,'fun',[{type,1076,product,[]},{type,1076,list,[{type,1076,tuple,[{var,1076,'Key'},{var,1076,'Val'}]}]}]},[{type,1077,constraint,[{atom,1077,is_subtype},[{var,1077,'Key'},{type,1077,term,[]}]]},{type,1078,constraint,[{atom,1078,is_subtype},[{var,1078,'Val'},{type,1078,term,[]}]]}]]}]}}]}},{{function,get,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1083}],[<<103,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32>>,{code,[],[<<75,101,121>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,84,104,101,32,101,120,112,101,99,116,101,100,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,109,101,114,114,121,41,44,10,112,117,116,40,107,101,121,50,44,32,108,97,109,98,115,41,44,10,112,117,116,40,123,97,110,121,44,32,91,118,97,108,105,100,44,32,116,101,114,109,93,125,44,32,123,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,103,101,116,40,123,97,110,121,44,32,91,118,97,108,105,100,44,32,116,101,114,109,93,125,41,46,10,123,97,114,101,44,112,108,97,121,105,110,103,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,50,50>>,signature => [{attribute,1083,spec,{{get,1},[{type,1083,bounded_fun,[{type,1083,'fun',[{type,1083,product,[{var,1083,'Key'}]},{type,1083,union,[{var,1083,'Val'},{atom,1083,undefined}]}]},[{type,1084,constraint,[{atom,1084,is_subtype},[{var,1084,'Key'},{type,1084,term,[]}]]},{type,1085,constraint,[{atom,1085,is_subtype},[{var,1085,'Val'},{type,1085,term,[]}]]}]]}]}}]}},{{function,get_cookie,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3794}],[<<103,101,116,95,99,111,111,107,105,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,102,32,116,104,101,32,110,111,100,101,32,105,115,32,97,108,105,118,101,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,99,111,111,107,105,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,52,50>>,signature => [{attribute,3794,spec,{{erlang,get_cookie,0},[{type,3794,bounded_fun,[{type,3794,'fun',[{type,3794,product,[]},{type,3794,union,[{var,3794,'Cookie'},{atom,3794,nocookie}]}]},[{type,3795,constraint,[{atom,3795,is_subtype},[{var,3795,'Cookie'},{type,3795,atom,[]}]]}]]}]}}]}},{{function,get_keys,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1090}],[<<103,101,116,95,107,101,121,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,107,101,121,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,100,111,103,44,32,123,97,110,105,109,97,108,44,49,125,41,44,10,112,117,116,40,99,111,119,44,32,123,97,110,105,109,97,108,44,50,125,41,44,10,112,117,116,40,108,97,109,98,44,32,123,97,110,105,109,97,108,44,51,125,41,44,10,103,101,116,95,107,101,121,115,40,41,46,10,91,100,111,103,44,99,111,119,44,108,97,109,98,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,53,49>>,signature => [{attribute,1090,spec,{{get_keys,0},[{type,1090,bounded_fun,[{type,1090,'fun',[{type,1090,product,[]},{type,1090,list,[{var,1090,'Key'}]}]},[{type,1091,constraint,[{atom,1091,is_subtype},[{var,1091,'Key'},{type,1091,term,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,get_keys,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1096}],[<<103,101,116,95,107,101,121,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,107,101,121,115,32,116,104,97,116,32,97,114,101,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,109,97,114,121,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,104,97,100,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,97,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,108,105,116,116,108,101,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,100,111,103,44,32,123,49,44,32,51,125,41,44,10,112,117,116,40,108,97,109,98,44,32,123,49,44,32,50,125,41,44,10,103,101,116,95,107,101,121,115,40,123,49,44,32,50,125,41,46,10,91,109,97,114,121,44,104,97,100,44,97,44,108,105,116,116,108,101,44,108,97,109,98,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,54,56>>,signature => [{attribute,1096,spec,{{get_keys,1},[{type,1096,bounded_fun,[{type,1096,'fun',[{type,1096,product,[{var,1096,'Val'}]},{type,1096,list,[{var,1096,'Key'}]}]},[{type,1097,constraint,[{atom,1097,is_subtype},[{var,1097,'Val'},{type,1097,term,[]}]]},{type,1098,constraint,[{atom,1098,is_subtype},[{var,1098,'Key'},{type,1098,term,[]}]]}]]}]}}]}},{{function,group_leader,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1110}],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<69,118,101,114,121,32,112,114,111,99,101,115,115,32,105,115,32,97,32,109,101,109,98,101,114,32,111,102,32,115,111,109,101,32,112,114,111,99,101,115,115,32,103,114,111,117,112,32,97,110,100,32,97,108,108,32,103,114,111,117,112,115,32,104,97,118,101,32,97,32>>,{em,[],[<<103,114,111,117,112,32,108,101,97,100,101,114>>]},<<46,32,65,108,108,32,73,47,79,32,102,114,111,109,32,116,104,101,32,103,114,111,117,112,32,105,115,32,99,104,97,110,110,101,108,101,100,32,116,111,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,46,32,87,104,101,110,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,112,97,119,110,101,100,44,32,105,116,32,103,101,116,115,32,116,104,101,32,115,97,109,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,97,115,32,116,104,101,32,115,112,97,119,110,105,110,103,32,112,114,111,99,101,115,115,46,32,73,110,105,116,105,97,108,108,121,44,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,117,112,44,32>>,{code,[],[<<105,110,105,116>>]},<<32,105,115,32,98,111,116,104,32,105,116,115,32,111,119,110,32,103,114,111,117,112,32,108,101,97,100,101,114,32,97,110,100,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32,97,108,108,32,112,114,111,99,101,115,115,101,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,56,56>>,signature => [{attribute,1110,spec,{{group_leader,0},[{type,1110,'fun',[{type,1110,product,[]},{type,1110,pid,[]}]}]}}]}},{{function,group_leader,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1115}],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<32,116,111,32>>,{code,[],[<<71,114,111,117,112,76,101,97,100,101,114>>]},<<46,32,84,121,112,105,99,97,108,108,121,44,32,116,104,105,115,32,105,115,32,117,115,101,100,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,102,114,111,109,32,97,32,99,101,114,116,97,105,110,32,115,104,101,108,108,32,105,115,32,116,111,32,104,97,118,101,32,97,110,111,116,104,101,114,32,103,114,111,117,112,32,108,101,97,100,101,114,32,116,104,97,110,32>>,{code,[],[<<105,110,105,116>>]},<<46>>]},{p,[],[<<84,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,115,104,111,117,108,100,32,98,101,32,114,97,114,101,108,121,32,99,104,97,110,103,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,115,32,119,105,116,104,32,97,32,115,117,112,101,114,118,105,115,105,111,110,32,116,114,101,101,44,32,98,101,99,97,117,115,101,32,79,84,80,32,97,115,115,117,109,101,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32,116,104,101,105,114,32,112,114,111,99,101,115,115,101,115,32,105,115,32,116,104,101,105,114,32,97,112,112,108,105,99,97,116,105,111,110,32,109,97,115,116,101,114,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,114,111,117,112,95,108,101,97,100,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,48>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,121,115,116,101,109,47,100,101,115,105,103,110,95,112,114,105,110,99,105,112,108,101,115,58,97,112,112,108,105,99,97,116,105,111,110,115,35,115,116,111,112,112,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,84,80,32,100,101,115,105,103,110,32,112,114,105,110,99,105,112,108,101,115>>]},<<32,114,101,108,97,116,101,100,32,116,111,32,115,116,97,114,116,105,110,103,32,97,110,100,32,115,116,111,112,112,105,110,103,32,97,112,112,108,105,99,97,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,48,51>>,signature => [{attribute,1115,spec,{{group_leader,2},[{type,1115,bounded_fun,[{type,1115,'fun',[{type,1115,product,[{var,1115,'GroupLeader'},{var,1115,'Pid'}]},{atom,1115,true}]},[{type,1116,constraint,[{atom,1116,is_subtype},[{var,1116,'GroupLeader'},{type,1116,pid,[]}]]},{type,1117,constraint,[{atom,1117,is_subtype},[{var,1117,'Pid'},{type,1117,pid,[]}]]}]]}]}}]}},{{function,halt,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1135}],[<<104,97,108,116,47,48>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<104,97,108,116,40,48,44,32,91,93,41>>]}]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,104,97,108,116,40,41,46,10,111,115,95,112,114,111,109,112,116,37>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,50,52>>,signature => [{attribute,1135,spec,{{halt,0},[{type,1135,'fun',[{type,1135,product,[]},{type,1135,no_return,[]}]}]}}]}},{{function,halt,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1141}],[<<104,97,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<104,97,108,116,40,83,116,97,116,117,115,44,32,91,93,41>>]}]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,104,97,108,116,40,49,55,41,46,10,111,115,95,112,114,111,109,112,116,37,32,101,99,104,111,32,36,63,10,49,55,10,111,115,95,112,114,111,109,112,116,37>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,51,55>>,signature => [{attribute,1141,spec,{{halt,1},[{type,1141,bounded_fun,[{type,1141,'fun',[{type,1141,product,[{var,1141,'Status'}]},{type,1141,no_return,[]}]},[{type,1142,constraint,[{atom,1142,is_subtype},[{var,1142,'Status'},{type,1142,union,[{type,1142,non_neg_integer,[]},{atom,1142,abort},{type,1142,string,[]}]}]]}]]}]}}]}},{{function,halt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1153}],[<<104,97,108,116,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<83,116,97,116,117,115>>]},<<32,109,117,115,116,32,98,101,32,97,32,110,111,110,45,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,44,32,97,32,115,116,114,105,110,103,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<97,98,111,114,116>>]},<<46,32,72,97,108,116,115,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,72,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,68,101,112,101,110,100,105,110,103,32,111,110,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,99,99,117,114,115,58>>]},{dl,[],[{dt,[],[<<105,110,116,101,103,101,114,40,41>>]},{dd,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,101,120,105,116,115,32,119,105,116,104,32,105,110,116,101,103,101,114,32,118,97,108,117,101,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<32,97,115,32,115,116,97,116,117,115,32,99,111,100,101,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,101,110,118,105,114,111,110,109,101,110,116,32,40,79,83,41,46>>,{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,32,109,97,110,121,32,112,108,97,116,102,111,114,109,115,44,32,116,104,101,32,79,83,32,115,117,112,112,111,114,116,115,32,111,110,108,121,32,115,116,97,116,117,115,32,99,111,100,101,115,32,48,45,50,53,53,46,32,65,32,116,111,111,32,108,97,114,103,101,32,115,116,97,116,117,115,32,99,111,100,101,32,105,115,32,116,114,117,110,99,97,116,101,100,32,98,121,32,99,108,101,97,114,105,110,103,32,116,104,101,32,104,105,103,104,32,98,105,116,115,46>>]}]}]},{dt,[],[<<115,116,114,105,110,103,40,41>>]},{dd,[],[<<65,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,32,105,115,32,112,114,111,100,117,99,101,100,32,119,105,116,104,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<32,97,115,32,115,108,111,103,97,110,46,32,84,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,101,120,105,116,115,32,119,105,116,104,32,115,116,97,116,117,115,32,99,111,100,101,32>>,{code,[],[<<49>>]},<<46,32,84,104,101,32,115,116,114,105,110,103,32,119,105,108,108,32,98,101,32,116,114,117,110,99,97,116,101,100,32,105,102,32,108,111,110,103,101,114,32,116,104,97,110,32,50,48,48,32,99,104,97,114,97,99,116,101,114,115,46>>,{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,82,84,83,32,57,46,49,32,40,79,84,80,45,50,48,46,49,41,32,111,110,108,121,32,99,111,100,101,32,112,111,105,110,116,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,45,50,53,53,32,119,97,115,32,97,99,99,101,112,116,101,100,32,105,110,32,116,104,101,32,115,116,114,105,110,103,46,32,78,111,119,32,97,110,121,32,117,110,105,99,111,100,101,32,115,116,114,105,110,103,32,105,115,32,118,97,108,105,100,46>>]}]}]},{dt,[],[{code,[],[<<97,98,111,114,116>>]}]},{dd,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,97,98,111,114,116,115,32,112,114,111,100,117,99,105,110,103,32,97,32,99,111,114,101,32,100,117,109,112,44,32,105,102,32,116,104,97,116,32,105,115,32,101,110,97,98,108,101,100,32,105,110,32,116,104,101,32,79,83,46>>]}]},{p,[],[<<70,111,114,32,105,110,116,101,103,101,114,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<44,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,99,108,111,115,101,115,32,97,108,108,32,112,111,114,116,115,32,97,110,100,32,97,108,108,111,119,115,32,97,115,121,110,99,32,116,104,114,101,97,100,115,32,116,111,32,102,105,110,105,115,104,32,116,104,101,105,114,32,111,112,101,114,97,116,105,111,110,115,32,98,101,102,111,114,101,32,101,120,105,116,105,110,103,46,32,84,111,32,101,120,105,116,32,119,105,116,104,111,117,116,32,115,117,99,104,32,102,108,117,115,104,105,110,103,44,32,117,115,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<32,97,115,32>>,{code,[],[<<123,102,108,117,115,104,44,102,97,108,115,101,125>>]},<<46>>]},{p,[],[<<70,111,114,32,115,116,97,116,117,115,101,115,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<32,97,110,100,32>>,{code,[],[<<97,98,111,114,116>>]},<<44,32,111,112,116,105,111,110,32>>,{code,[],[<<102,108,117,115,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,32,97,110,100,32,102,108,117,115,104,105,110,103,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,100,111,110,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,53,49>>,signature => [{attribute,1153,spec,{{halt,2},[{type,1153,bounded_fun,[{type,1153,'fun',[{type,1153,product,[{var,1153,'Status'},{var,1153,'Options'}]},{type,1153,no_return,[]}]},[{type,1154,constraint,[{atom,1154,is_subtype},[{var,1154,'Status'},{type,1154,union,[{type,1154,non_neg_integer,[]},{atom,1154,abort},{type,1154,string,[]}]}]]},{type,1155,constraint,[{atom,1155,is_subtype},[{var,1155,'Options'},{type,1155,list,[{var,1155,'Option'}]}]]},{type,1156,constraint,[{atom,1156,is_subtype},[{var,1156,'Option'},{type,1156,tuple,[{atom,1156,flush},{type,1156,boolean,[]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,hd,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2133}],[<<104,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,104,101,97,100,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,104,100,40,91,49,44,50,44,51,44,52,44,53,93,41,46,10,49>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,105,115,116>>]},<<32,105,115,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,53,57,51>>,signature => [{attribute,2133,spec,{{hd,1},[{type,2133,bounded_fun,[{type,2133,'fun',[{type,2133,product,[{var,2133,'List'}]},{type,2133,term,[]}]},[{type,2134,constraint,[{atom,2134,is_subtype},[{var,2134,'List'},{type,2134,nonempty_list,[{type,2134,term,[]}]}]]}]]}]}}]}},{{function,hibernate,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1167}],[<<104,105,98,101,114,110,97,116,101,47,51>>],#{<<101,110>> => [{p,[],[<<80,117,116,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,110,116,111,32,97,32,119,97,105,116,32,115,116,97,116,101,32,119,104,101,114,101,32,105,116,115,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,114,101,100,117,99,101,100,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,100,111,101,115,32,110,111,116,32,101,120,112,101,99,116,32,116,111,32,114,101,99,101,105,118,101,32,97,110,121,32,109,101,115,115,97,103,101,115,32,115,111,111,110,46>>]},{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,32,119,104,101,110,32,97,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,105,116,44,32,97,110,100,32,99,111,110,116,114,111,108,32,114,101,115,117,109,101,115,32,105,110,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,119,105,116,104,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<65,114,103,115>>]},<<32,119,105,116,104,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,101,109,112,116,105,101,100,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,116,104,101,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,32,119,104,101,110,32,116,104,97,116,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46,32,84,104,117,115,32>>,{code,[],[<<101,114,108,97,110,103,58,104,105,98,101,114,110,97,116,101,47,51>>]},<<32,110,101,118,101,114,32,114,101,116,117,114,110,115,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,97,110,121,32,109,101,115,115,97,103,101,32,105,110,32,105,116,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,44,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,101,100,32,105,109,109,101,100,105,97,116,101,108,121,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46>>]},{p,[],[<<73,110,32,109,111,114,101,32,116,101,99,104,110,105,99,97,108,32,116,101,114,109,115,44,32>>,{code,[],[<<101,114,108,97,110,103,58,104,105,98,101,114,110,97,116,101,47,51>>]},<<32,100,105,115,99,97,114,100,115,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,97,110,100,32,116,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,115,32,116,104,101,32,112,114,111,99,101,115,115,46,32,65,102,116,101,114,32,116,104,105,115,44,32,97,108,108,32,108,105,118,101,32,100,97,116,97,32,105,115,32,105,110,32,111,110,101,32,99,111,110,116,105,110,117,111,117,115,32,104,101,97,112,46,32,84,104,101,32,104,101,97,112,32,105,115,32,116,104,101,110,32,115,104,114,117,110,107,101,110,32,116,111,32,116,104,101,32,101,120,97,99,116,32,115,97,109,101,32,115,105,122,101,32,97,115,32,116,104,101,32,108,105,118,101,32,100,97,116,97,32,116,104,97,116,32,105,116,32,104,111,108,100,115,32,40,101,118,101,110,32,105,102,32,116,104,97,116,32,115,105,122,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,41,46>>]},{p,[],[<<73,102,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,108,105,118,101,32,100,97,116,97,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,44,32,116,104,101,32,102,105,114,115,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,99,99,117,114,114,105,110,103,32,97,102,116,101,114,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,101,100,32,101,110,115,117,114,101,115,32,116,104,97,116,32,116,104,101,32,104,101,97,112,32,115,105,122,101,32,105,115,32,99,104,97,110,103,101,100,32,116,111,32,97,32,115,105,122,101,32,110,111,116,32,115,109,97,108,108,101,114,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,101,109,112,116,121,105,110,103,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,109,101,97,110,115,32,116,104,97,116,32,97,110,121,32,115,117,114,114,111,117,110,100,105,110,103,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,105,115,32,114,101,109,111,118,101,100,32,97,110,100,32,109,117,115,116,32,98,101,32,114,101,45,105,110,115,101,114,116,101,100,32,97,102,116,101,114,32,104,105,98,101,114,110,97,116,105,111,110,46,32,79,110,101,32,101,102,102,101,99,116,32,111,102,32,116,104,105,115,32,105,115,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,115,116,97,114,116,101,100,32,117,115,105,110,103,32>>,{code,[],[<<112,114,111,99,95,108,105,98>>]},<<32,40,97,108,115,111,32,105,110,100,105,114,101,99,116,108,121,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<103,101,110,95,115,101,114,118,101,114>>]},<<32,112,114,111,99,101,115,115,101,115,41,44,32,97,114,101,32,116,111,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,112,114,111,99,95,108,105,98,35,104,105,98,101,114,110,97,116,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,95,108,105,98,58,104,105,98,101,114,110,97,116,101,47,51>>]}]},<<32,105,110,115,116,101,97,100,44,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,104,97,110,100,108,101,114,32,99,111,110,116,105,110,117,101,115,32,116,111,32,119,111,114,107,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,107,101,115,32,117,112,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,48,56>>,signature => [{attribute,1167,spec,{{erlang,hibernate,3},[{type,1167,bounded_fun,[{type,1167,'fun',[{type,1167,product,[{var,1167,'Module'},{var,1167,'Function'},{var,1167,'Args'}]},{type,1167,no_return,[]}]},[{type,1168,constraint,[{atom,1168,is_subtype},[{var,1168,'Module'},{type,1168,module,[]}]]},{type,1169,constraint,[{atom,1169,is_subtype},[{var,1169,'Function'},{type,1169,atom,[]}]]},{type,1170,constraint,[{atom,1170,is_subtype},[{var,1170,'Args'},{type,1170,list,[{type,1170,term,[]}]}]]}]]}]}}]}},{{function,insert_element,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1175}],[<<105,110,115,101,114,116,95,101,108,101,109,101,110,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,119,105,116,104,32,101,108,101,109,101,110,116,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,110,115,101,114,116,101,100,32,97,116,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,105,110,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<46,32,65,108,108,32,101,108,101,109,101,110,116,115,32,102,114,111,109,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,97,110,100,32,117,112,119,97,114,100,115,32,97,114,101,32,112,117,115,104,101,100,32,111,110,101,32,115,116,101,112,32,104,105,103,104,101,114,32,105,110,32,116,104,101,32,110,101,119,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,50>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,105,110,115,101,114,116,95,101,108,101,109,101,110,116,40,50,44,32,123,111,110,101,44,32,116,119,111,44,32,116,104,114,101,101,125,44,32,110,101,119,41,46,10,123,111,110,101,44,110,101,119,44,116,119,111,44,116,104,114,101,101,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,52,57>>,signature => [{attribute,1175,spec,{{erlang,insert_element,3},[{type,1175,bounded_fun,[{type,1175,'fun',[{type,1175,product,[{var,1175,'Index'},{var,1175,'Tuple1'},{var,1175,'Term'}]},{var,1175,'Tuple2'}]},[{type,1176,constraint,[{atom,1176,is_subtype},[{var,1176,'Index'},{type,1176,pos_integer,[]}]]},{type,1177,constraint,[{atom,1177,is_subtype},[{var,1177,'Tuple1'},{type,1177,tuple,any}]]},{type,1178,constraint,[{atom,1178,is_subtype},[{var,1178,'Tuple2'},{type,1178,tuple,any}]]},{type,1179,constraint,[{atom,1179,is_subtype},[{var,1179,'Term'},{type,1179,term,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1184}],[<<105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,40,55,55,41,46,10,60,60,34,55,55,34,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,54,55>>,signature => [{attribute,1184,spec,{{integer_to_binary,1},[{type,1184,bounded_fun,[{type,1184,'fun',[{type,1184,product,[{var,1184,'Integer'}]},{type,1184,binary,[]}]},[{type,1185,constraint,[{atom,1185,is_subtype},[{var,1185,'Integer'},{type,1185,integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3805}],[<<105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,40,49,48,50,51,44,32,49,54,41,46,10,60,60,34,51,70,70,34,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,55,57>>,signature => [{attribute,3805,spec,{{integer_to_binary,2},[{type,3805,bounded_fun,[{type,3805,'fun',[{type,3805,product,[{var,3805,'Integer'},{var,3805,'Base'}]},{type,3805,binary,[]}]},[{type,3806,constraint,[{atom,3806,is_subtype},[{var,3806,'Integer'},{type,3806,integer,[]}]]},{type,3807,constraint,[{atom,3807,is_subtype},[{var,3807,'Base'},{type,3807,range,[{integer,3807,2},{integer,3807,36}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1190}],[<<105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,40,55,55,41,46,10,34,55,55,34>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,57,50>>,signature => [{attribute,1190,spec,{{integer_to_list,1},[{type,1190,bounded_fun,[{type,1190,'fun',[{type,1190,product,[{var,1190,'Integer'}]},{type,1190,string,[]}]},[{type,1191,constraint,[{atom,1191,is_subtype},[{var,1191,'Integer'},{type,1191,integer,[]}]]}]]}]}}]}},{{function,integer_to_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3799}],[<<105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,40,49,48,50,51,44,32,49,54,41,46,10,34,51,70,70,34>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,48,52>>,signature => [{attribute,3799,spec,{{integer_to_list,2},[{type,3799,bounded_fun,[{type,3799,'fun',[{type,3799,product,[{var,3799,'Integer'},{var,3799,'Base'}]},{type,3799,string,[]}]},[{type,3800,constraint,[{atom,3800,is_subtype},[{var,3800,'Integer'},{type,3800,integer,[]}]]},{type,3801,constraint,[{atom,3801,is_subtype},[{var,3801,'Base'},{type,3801,range,[{integer,3801,2},{integer,3801,36}]}]]}]]}]}}]}},{{function,iolist_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1196}],[<<105,111,108,105,115,116,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,97,116,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,121,116,101,115,44,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,116,104,97,116,32,119,111,117,108,100,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,73,116,101,109,41>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,111,108,105,115,116,95,115,105,122,101,40,91,49,44,50,124,60,60,51,44,52,62,62,93,41,46,10,52>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,49,55>>,signature => [{attribute,1196,spec,{{iolist_size,1},[{type,1196,bounded_fun,[{type,1196,'fun',[{type,1196,product,[{var,1196,'Item'}]},{type,1196,non_neg_integer,[]}]},[{type,1197,constraint,[{atom,1197,is_subtype},[{var,1197,'Item'},{type,1197,union,[{type,1197,iolist,[]},{type,1197,binary,[]}]}]]}]]}]}}]}},{{function,iolist_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1202}],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116,79,114,66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,62,62,46,10,60,60,54,62,62,10,62,32,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,51,48>>,signature => [{attribute,1202,spec,{{iolist_to_binary,1},[{type,1202,bounded_fun,[{type,1202,'fun',[{type,1202,product,[{var,1202,'IoListOrBinary'}]},{type,1202,binary,[]}]},[{type,1203,constraint,[{atom,1203,is_subtype},[{var,1203,'IoListOrBinary'},{type,1203,union,[{type,1203,iolist,[]},{type,1203,binary,[]}]}]]}]]}]}}]}},{{function,iolist_to_iovec,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1208}],[<<105,111,108,105,115,116,95,116,111,95,105,111,118,101,99,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,111,118,101,99,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116,79,114,66,105,110,97,114,121>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,52,56>>,signature => [{attribute,1208,spec,{{erlang,iolist_to_iovec,1},[{type,1208,bounded_fun,[{type,1208,'fun',[{type,1208,product,[{var,1208,'IoListOrBinary'}]},{user_type,1208,iovec,[]}]},[{type,1209,constraint,[{atom,1209,is_subtype},[{var,1209,'IoListOrBinary'},{type,1209,union,[{type,1209,iolist,[]},{type,1209,binary,[]}]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,49>>}},{{function,is_alive,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1214}],[<<105,115,95,97,108,105,118,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,97,108,105,118,101,32,40,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,111,100,101,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,97,32,100,105,115,116,114,105,98,117,116,101,100,32,115,121,115,116,101,109,41,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,65,32,110,111,100,101,32,105,115,32,97,108,105,118,101,32,105,102,32,105,116,32,105,115,32,115,116,97,114,116,101,100,32,119,105,116,104,58>>]},{ol,[],[{li,[],[{a,[{href,<<101,114,116,115,58,101,114,108,35,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<34,101,114,108,32,45,110,97,109,101,32,76,79,78,71,78,65,77,69,34>>]}]},<<32,111,114,44>>]},{li,[],[{a,[{href,<<101,114,116,115,58,101,114,108,35,115,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<34,101,114,108,32,45,115,110,97,109,101,32,83,72,79,82,84,78,65,77,69,34>>]}]},<<46>>]}]},{p,[],[<<65,32,110,111,100,101,32,99,97,110,32,97,108,115,111,32,98,101,32,97,108,105,118,101,32,105,102,32,105,116,32,104,97,115,32,103,111,116,32,97,32,110,97,109,101,32,102,114,111,109,32,97,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,97,114,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,97,114,116,47,49>>]}]},<<32,97,110,100,32,104,97,115,32,110,111,116,32,98,101,101,110,32,115,116,111,112,112,101,100,32,98,121,32,97,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,111,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,111,112,47,48>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,53,55>>,signature => [{attribute,1214,spec,{{is_alive,0},[{type,1214,'fun',[{type,1214,product,[]},{type,1214,boolean,[]}]}]}}]}},{{function,is_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2141}],[<<105,115,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,97,116,111,109,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,55,54>>,signature => [{attribute,2141,spec,{{is_atom,1},[{type,2141,bounded_fun,[{type,2141,'fun',[{type,2141,product,[{var,2141,'Term'}]},{type,2141,boolean,[]}]},[{type,2142,constraint,[{atom,2142,is_subtype},[{var,2142,'Term'},{type,2142,term,[]}]]}]]}]}}]}},{{function,is_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2147}],[<<105,115,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,32,98,105,110,97,114,121,32,97,108,119,97,121,115,32,99,111,110,116,97,105,110,115,32,97,32,99,111,109,112,108,101,116,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,56,54>>,signature => [{attribute,2147,spec,{{is_binary,1},[{type,2147,bounded_fun,[{type,2147,'fun',[{type,2147,product,[{var,2147,'Term'}]},{type,2147,boolean,[]}]},[{type,2148,constraint,[{atom,2148,is_subtype},[{var,2148,'Term'},{type,2148,term,[]}]]}]]}]}}]}},{{function,is_bitstring,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2153}],[<<105,115,95,98,105,116,115,116,114,105,110,103,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,98,105,116,115,116,114,105,110,103,32,40,105,110,99,108,117,100,105,110,103,32,97,32,98,105,110,97,114,121,41,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,57,55>>,signature => [{attribute,2153,spec,{{is_bitstring,1},[{type,2153,bounded_fun,[{type,2153,'fun',[{type,2153,product,[{var,2153,'Term'}]},{type,2153,boolean,[]}]},[{type,2154,constraint,[{atom,2154,is_subtype},[{var,2154,'Term'},{type,2154,term,[]}]]}]]}]}}]}},{{function,is_boolean,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2159}],[<<105,115,95,98,111,111,108,101,97,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<116,114,117,101>>]},<<32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,116,104,97,116,32,105,115,44,32,97,32,98,111,111,108,101,97,110,41,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,48,55>>,signature => [{attribute,2159,spec,{{is_boolean,1},[{type,2159,bounded_fun,[{type,2159,'fun',[{type,2159,product,[{var,2159,'Term'}]},{type,2159,boolean,[]}]},[{type,2160,constraint,[{atom,2160,is_subtype},[{var,2160,'Term'},{type,2160,term,[]}]]}]]}]}}]}},{{function,is_builtin,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1219}],[<<105,115,95,98,117,105,108,116,105,110,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,117,115,101,102,117,108,32,102,111,114,32,98,117,105,108,100,101,114,115,32,111,102,32,99,114,111,115,115,45,114,101,102,101,114,101,110,99,101,32,116,111,111,108,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,105,115,32,97,32,66,73,70,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,67,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,49,56>>,signature => [{attribute,1219,spec,{{erlang,is_builtin,3},[{type,1219,bounded_fun,[{type,1219,'fun',[{type,1219,product,[{var,1219,'Module'},{var,1219,'Function'},{var,1219,'Arity'}]},{type,1219,boolean,[]}]},[{type,1220,constraint,[{atom,1220,is_subtype},[{var,1220,'Module'},{type,1220,module,[]}]]},{type,1221,constraint,[{atom,1221,is_subtype},[{var,1221,'Function'},{type,1221,atom,[]}]]},{type,1222,constraint,[{atom,1222,is_subtype},[{var,1222,'Arity'},{type,1222,arity,[]}]]}]]}]}}]}},{{function,is_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2165}],[<<105,115,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,50,57>>,signature => [{attribute,2165,spec,{{is_float,1},[{type,2165,bounded_fun,[{type,2165,'fun',[{type,2165,product,[{var,2165,'Term'}]},{type,2165,boolean,[]}]},[{type,2166,constraint,[{atom,2166,is_subtype},[{var,2166,'Term'},{type,2166,term,[]}]]}]]}]}}]}},{{function,is_function,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2171}],[<<105,115,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,117,110,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,51,57>>,signature => [{attribute,2171,spec,{{is_function,1},[{type,2171,bounded_fun,[{type,2171,'fun',[{type,2171,product,[{var,2171,'Term'}]},{type,2171,boolean,[]}]},[{type,2172,constraint,[{atom,2172,is_subtype},[{var,2172,'Term'},{type,2172,term,[]}]]}]]}]}}]}},{{function,is_function,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2177}],[<<105,115,95,102,117,110,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,117,110,32,116,104,97,116,32,99,97,110,32,98,101,32,97,112,112,108,105,101,100,32,119,105,116,104,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,52,57>>,signature => [{attribute,2177,spec,{{is_function,2},[{type,2177,bounded_fun,[{type,2177,'fun',[{type,2177,product,[{var,2177,'Term'},{var,2177,'Arity'}]},{type,2177,boolean,[]}]},[{type,2178,constraint,[{atom,2178,is_subtype},[{var,2178,'Term'},{type,2178,term,[]}]]},{type,2179,constraint,[{atom,2179,is_subtype},[{var,2179,'Arity'},{type,2179,arity,[]}]]}]]}]}}]}},{{function,is_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2184}],[<<105,115,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,54,49>>,signature => [{attribute,2184,spec,{{is_integer,1},[{type,2184,bounded_fun,[{type,2184,'fun',[{type,2184,product,[{var,2184,'Term'}]},{type,2184,boolean,[]}]},[{type,2185,constraint,[{atom,2185,is_subtype},[{var,2185,'Term'},{type,2185,term,[]}]]}]]}]}}]}},{{function,is_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2190}],[<<105,115,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,108,105,115,116,32,119,105,116,104,32,122,101,114,111,32,111,114,32,109,111,114,101,32,101,108,101,109,101,110,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,55,49>>,signature => [{attribute,2190,spec,{{is_list,1},[{type,2190,bounded_fun,[{type,2190,'fun',[{type,2190,product,[{var,2190,'Term'}]},{type,2190,boolean,[]}]},[{type,2191,constraint,[{atom,2191,is_subtype},[{var,2191,'Term'},{type,2191,term,[]}]]}]]}]}}]}},{{function,is_map,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2208}],[<<105,115,95,109,97,112,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,109,97,112,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,56,49>>,signature => [{attribute,2208,spec,{{is_map,1},[{type,2208,bounded_fun,[{type,2208,'fun',[{type,2208,product,[{var,2208,'Term'}]},{type,2208,boolean,[]}]},[{type,2209,constraint,[{atom,2209,is_subtype},[{var,2209,'Term'},{type,2209,term,[]}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,is_map_key,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1227}],[<<105,115,95,109,97,112,95,107,101,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,109,97,112,32>>,{code,[],[<<77,97,112>>]},<<32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<75,101,121>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,116,104,101,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,109,97,112,44,77,97,112,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,105,115,32,110,111,116,32,97,32,109,97,112,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<62,32,77,97,112,32,61,32,35,123,34,52,50,34,32,61,62,32,118,97,108,117,101,125,46,10,35,123,34,52,50,34,32,61,62,32,118,97,108,117,101,125,10,62,32,105,115,95,109,97,112,95,107,101,121,40,34,52,50,34,44,77,97,112,41,46,10,116,114,117,101,10,62,32,105,115,95,109,97,112,95,107,101,121,40,118,97,108,117,101,44,77,97,112,41,46,10,102,97,108,115,101>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,57,49>>,signature => [{attribute,1227,spec,{{is_map_key,2},[{type,1227,bounded_fun,[{type,1227,'fun',[{type,1227,product,[{var,1227,'Key'},{var,1227,'Map'}]},{type,1227,boolean,[]}]},[{type,1228,constraint,[{atom,1228,is_subtype},[{var,1228,'Key'},{type,1228,term,[]}]]},{type,1229,constraint,[{atom,1229,is_subtype},[{var,1229,'Map'},{type,1229,map,any}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,is_number,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2196}],[<<105,115,95,110,117,109,98,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,111,114,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,49,50>>,signature => [{attribute,2196,spec,{{is_number,1},[{type,2196,bounded_fun,[{type,2196,'fun',[{type,2196,product,[{var,2196,'Term'}]},{type,2196,boolean,[]}]},[{type,2197,constraint,[{atom,2197,is_subtype},[{var,2197,'Term'},{type,2197,term,[]}]]}]]}]}}]}},{{function,is_pid,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2202}],[<<105,115,95,112,105,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,50,50>>,signature => [{attribute,2202,spec,{{is_pid,1},[{type,2202,bounded_fun,[{type,2202,'fun',[{type,2202,product,[{var,2202,'Term'}]},{type,2202,boolean,[]}]},[{type,2203,constraint,[{atom,2203,is_subtype},[{var,2203,'Term'},{type,2203,term,[]}]]}]]}]}}]}},{{function,is_port,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2214}],[<<105,115,95,112,111,114,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,51,50>>,signature => [{attribute,2214,spec,{{is_port,1},[{type,2214,bounded_fun,[{type,2214,'fun',[{type,2214,product,[{var,2214,'Term'}]},{type,2214,boolean,[]}]},[{type,2215,constraint,[{atom,2215,is_subtype},[{var,2215,'Term'},{type,2215,term,[]}]]}]]}]}}]}},{{function,is_process_alive,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1234}],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100>>]},<<32,109,117,115,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,115,116,115,32,97,110,100,32,105,115,32,97,108,105,118,101,44,32,116,104,97,116,32,105,115,44,32,105,115,32,110,111,116,32,101,120,105,116,105,110,103,32,97,110,100,32,104,97,115,32,110,111,116,32,101,120,105,116,101,100,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<73,102,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,49>>]},<<32,99,97,108,108,115,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,40,80,50,80,105,100,41>>]},<<32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,108,108,32,115,105,103,110,97,108,115,44,32,115,101,110,116,32,102,114,111,109,32>>,{code,[],[<<80,49>>]},<<32,116,111,32>>,{code,[],[<<80,50>>]},<<32,40>>,{code,[],[<<80,50>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<80,50,80,105,100>>]},<<41,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,44,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80,50>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,97,108,105,118,101,110,101,115,115,32,111,102,32>>,{code,[],[<<80,50>>]},<<32,105,115,32,99,104,101,99,107,101,100,46,32,84,104,105,115,32,103,117,97,114,97,110,116,101,101,32,109,101,97,110,115,32,116,104,97,116,32,111,110,101,32,99,97,110,32,117,115,101,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>]},<<32,116,111,32,108,101,116,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,49>>]},<<32,119,97,105,116,32,117,110,116,105,108,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,50>>]},<<44,32,119,104,105,99,104,32,104,97,115,32,103,111,116,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,102,114,111,109,32,80,49,44,32,105,115,32,107,105,108,108,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<101,120,105,116,40,80,50,80,105,100,44,32,107,105,108,108,41,44,10,37,32,80,50,32,109,105,103,104,116,32,110,111,116,32,98,101,32,107,105,108,108,101,100,10,105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,40,80,50,80,105,100,41,44,10,37,32,80,50,32,105,115,32,110,111,116,32,97,108,105,118,101,32,40,116,104,101,32,99,97,108,108,32,97,98,111,118,101,32,97,108,119,97,121,115,32,114,101,116,117,114,110,32,102,97,108,115,101,41>>]}]},{p,[],[<<83,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,99,111,109,109,117,110,105,99,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,111,109,109,117,110,105,99,97,116,105,111,110,32,105,110,32,69,114,108,97,110,103>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,105,103,110,97,108,115,32,97,110,100,32,101,120,105,116,32,115,105,110,103,110,97,108,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,52,50>>,signature => [{attribute,1234,spec,{{is_process_alive,1},[{type,1234,bounded_fun,[{type,1234,'fun',[{type,1234,product,[{var,1234,'Pid'}]},{type,1234,boolean,[]}]},[{type,1235,constraint,[{atom,1235,is_subtype},[{var,1235,'Pid'},{type,1235,pid,[]}]]}]]}]}}]}},{{function,is_record,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2220}],[<<105,115,95,114,101,99,111,114,100,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,32,97,110,100,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,114,109,97,108,108,121,32,116,104,101,32,99,111,109,112,105,108,101,114,32,116,114,101,97,116,115,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,101,115,112,101,99,105,97,108,108,121,46,32,73,116,32,101,109,105,116,115,32,99,111,100,101,32,116,111,32,118,101,114,105,102,121,32,116,104,97,116,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,116,104,97,116,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,115,105,122,101,32,105,115,32,99,111,114,114,101,99,116,46,32,72,111,119,101,118,101,114,44,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,110,111,116,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,44,32,116,104,101,32,66,73,70,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,115,116,101,97,100,32,97,110,100,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,116,117,112,108,101,32,105,115,32,110,111,116,32,118,101,114,105,102,105,101,100,46>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,44,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,55,52>>,signature => [{attribute,2220,spec,{{is_record,2},[{type,2220,bounded_fun,[{type,2220,'fun',[{type,2220,product,[{var,2220,'Term'},{var,2220,'RecordTag'}]},{type,2220,boolean,[]}]},[{type,2221,constraint,[{atom,2221,is_subtype},[{var,2221,'Term'},{type,2221,term,[]}]]},{type,2222,constraint,[{atom,2222,is_subtype},[{var,2222,'RecordTag'},{type,2222,atom,[]}]]}]]}]}}]}},{{function,is_record,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2227}],[<<105,115,95,114,101,99,111,114,100,47,51>>],#{<<101,110>> => [{p,[],[{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,109,117,115,116,32,98,101,32,97,110,32,97,116,111,109,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<44,32,97,110,100,32,105,116,115,32,115,105,122,101,32,105,115,32>>,{code,[],[<<83,105,122,101>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,32,97,110,100,32>>,{code,[],[<<83,105,122,101>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,105,110,116,101,103,101,114,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,100,111,99,117,109,101,110,116,101,100,32,102,111,114,32,99,111,109,112,108,101,116,101,110,101,115,115,46,32,85,115,117,97,108,108,121,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,105,115,32,116,111,32,98,101,32,117,115,101,100,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,57,53>>,signature => [{attribute,2227,spec,{{is_record,3},[{type,2227,bounded_fun,[{type,2227,'fun',[{type,2227,product,[{var,2227,'Term'},{var,2227,'RecordTag'},{var,2227,'Size'}]},{type,2227,boolean,[]}]},[{type,2228,constraint,[{atom,2228,is_subtype},[{var,2228,'Term'},{type,2228,term,[]}]]},{type,2229,constraint,[{atom,2229,is_subtype},[{var,2229,'RecordTag'},{type,2229,atom,[]}]]},{type,2230,constraint,[{atom,2230,is_subtype},[{var,2230,'Size'},{type,2230,non_neg_integer,[]}]]}]]}]}}]}},{{function,is_reference,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2235}],[<<105,115,95,114,101,102,101,114,101,110,99,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,49,52>>,signature => [{attribute,2235,spec,{{is_reference,1},[{type,2235,bounded_fun,[{type,2235,'fun',[{type,2235,product,[{var,2235,'Term'}]},{type,2235,boolean,[]}]},[{type,2236,constraint,[{atom,2236,is_subtype},[{var,2236,'Term'},{type,2236,term,[]}]]}]]}]}}]}},{{function,is_tuple,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2241}],[<<105,115,95,116,117,112,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,50,52>>,signature => [{attribute,2241,spec,{{is_tuple,1},[{type,2241,bounded_fun,[{type,2241,'fun',[{type,2241,product,[{var,2241,'Term'}]},{type,2241,boolean,[]}]},[{type,2242,constraint,[{atom,2242,is_subtype},[{var,2242,'Term'},{type,2242,term,[]}]]}]]}]}}]}},{{function,length,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1241}],[<<108,101,110,103,116,104,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,101,110,103,116,104,40,91,49,44,50,44,51,44,52,44,53,44,54,44,55,44,56,44,57,93,41,46,10,57>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,51,52>>,signature => [{attribute,1241,spec,{{length,1},[{type,1241,bounded_fun,[{type,1241,'fun',[{type,1241,product,[{var,1241,'List'}]},{type,1241,non_neg_integer,[]}]},[{type,1242,constraint,[{atom,1242,is_subtype},[{var,1242,'List'},{type,1242,list,[{type,1242,term,[]}]}]]}]]}]}}]}},{{function,link,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1247}],[<<108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,40,111,114,32,112,111,114,116,41,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<46,32,73,102,32,116,104,101,32,108,105,110,107,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,32,111,114,32,97,32,112,114,111,99,101,115,115,32,97,116,116,101,109,112,116,115,32,116,111,32,99,114,101,97,116,101,32,97,32,108,105,110,107,32,116,111,32,105,116,115,101,108,102,44,32,110,111,116,104,105,110,103,32,105,115,32,100,111,110,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,108,105,110,107,32,105,115,32,115,101,116,32,117,112,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,97,110,100,32,99,104,101,99,107,105,110,103,32,105,116,32,105,115,32,99,104,101,97,112,44,32,97,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,101,114,114,111,114,32,105,115,32,114,97,105,115,101,100,46,32,67,117,114,114,101,110,116,108,121,44,32,99,104,101,99,107,105,110,103,32,105,115,32,99,104,101,97,112,32,105,102,32,116,104,101,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,108,111,99,97,108,32,97,110,100,32,116,104,101,32,99,97,108,108,101,114,32,100,111,101,115,32,110,111,116,32,116,114,97,112,32,101,120,105,116,115,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50,32>>]}]},<<41,46>>]},{p,[],[<<65,112,97,114,116,32,102,114,111,109,32,97,110,121,32,101,120,105,116,32,115,105,103,110,97,108,115,32,102,114,111,109,32,116,104,101,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,32,105,116,115,101,108,102,44,32,116,119,111,32,115,112,101,99,105,97,108,32,101,120,105,116,32,115,105,103,110,97,108,115,32,109,97,121,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<110,111,112,114,111,99>>]},<<32,105,115,32,115,101,110,116,32,105,109,109,101,100,105,97,116,101,108,121,32,105,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,108,105,110,107,105,110,103,32,40,105,102,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,32,111,114,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,114,101,109,111,116,101,41,46>>]}]},{li,[],[{p,[],[{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,105,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,114,101,109,111,116,101,32,97,110,100,32,97,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,116,104,101,32,110,111,100,101,115,32,99,111,117,108,100,32,110,111,116,32,98,101,32,101,115,116,97,98,108,105,115,104,101,100,32,111,114,32,119,97,115,32,115,101,118,101,114,101,100,46>>]}]}]},{p,[],[<<83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,108,105,110,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<80,114,111,99,101,115,115,101,115,32,226,158,156,32,76,105,110,107,115>>]},<<32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,52,54>>,signature => [{attribute,1247,spec,{{link,1},[{type,1247,bounded_fun,[{type,1247,'fun',[{type,1247,product,[{var,1247,'PidOrPort'}]},{atom,1247,true}]},[{type,1248,constraint,[{atom,1248,is_subtype},[{var,1248,'PidOrPort'},{type,1248,union,[{type,1248,pid,[]},{type,1248,port,[]}]}]]}]]}]}}]}},{{function,list_to_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1253}],[<<108,105,115,116,95,116,111,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,97,121,32,99,111,110,116,97,105,110,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,46,32,69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,97,108,108,111,119,101,100,32,111,110,108,121,32,73,83,79,45,108,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,116,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,100,105,100,32,110,111,116,32,97,108,108,111,119,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,97,98,111,118,101,32,50,53,53,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,85,110,105,99,111,100,101,32,115,117,112,112,111,114,116,32,105,110,32,97,116,111,109,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116,35,117,116,102,56,95,97,116,111,109,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,116,101,32,111,110,32,85,84,70,45,56,32,101,110,99,111,100,101,100,32,97,116,111,109,115>>]},<<32,105,110,32,115,101,99,116,105,111,110,32,34,69,120,116,101,114,110,97,108,32,84,101,114,109,32,70,111,114,109,97,116,34,32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,110,115,105,100,101,114,32,105,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>]}]},<<32,105,115,32,97,32,98,101,116,116,101,114,32,111,112,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<108,105,115,116,95,116,111,95,97,116,111,109,47,49>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,97,116,111,109,40,34,69,114,108,97,110,103,34,41,46,10,39,69,114,108,97,110,103,39>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,56,52>>,signature => [{attribute,1253,spec,{{list_to_atom,1},[{type,1253,bounded_fun,[{type,1253,'fun',[{type,1253,product,[{var,1253,'String'}]},{type,1253,atom,[]}]},[{type,1254,constraint,[{atom,1254,is_subtype},[{var,1254,'String'},{type,1254,string,[]}]]}]]}]}}]}},{{function,list_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1259}],[<<108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,62,62,46,10,60,60,54,62,62,10,62,32,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,50,48>>,signature => [{attribute,1259,spec,{{list_to_binary,1},[{type,1259,bounded_fun,[{type,1259,'fun',[{type,1259,product,[{var,1259,'IoList'}]},{type,1259,binary,[]}]},[{type,1260,constraint,[{atom,1260,is_subtype},[{var,1260,'IoList'},{type,1260,iolist,[]}]]}]]}]}}]}},{{function,list_to_bitstring,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1265}],[<<108,105,115,116,95,116,111,95,98,105,116,115,116,114,105,110,103,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<98,105,116,115,116,114,105,110,103,95,108,105,115,116>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,116,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,116,115,116,114,105,110,103,115,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103,76,105,115,116>>]},<<46,32,40,84,104,101,32,108,97,115,116,32,116,97,105,108,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103,76,105,115,116>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,32,98,105,116,115,116,114,105,110,103,46,41,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,44,55,58,52,62,62,46,10,60,60,54,44,55,58,52,62,62,10,62,32,108,105,115,116,95,116,111,95,98,105,116,115,116,114,105,110,103,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,44,55,58,52,62,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,51,56>>,signature => [{attribute,1265,spec,{{list_to_bitstring,1},[{type,1265,bounded_fun,[{type,1265,'fun',[{type,1265,product,[{var,1265,'BitstringList'}]},{type,1265,bitstring,[]}]},[{type,1266,constraint,[{atom,1266,is_subtype},[{var,1266,'BitstringList'},{user_type,1266,bitstring_list,[]}]]}]]}]}}]}},{{function,list_to_existing_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1271}],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,98,117,116,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,32,115,117,99,104,32,97,116,111,109,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,100,111,101,115,32,110,111,116,32,97,108,114,101,97,100,121,32,101,120,105,115,116,32,97,110,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,99,111,109,112,105,108,101,114,32,109,97,121,32,111,112,116,105,109,105,122,101,32,97,119,97,121,32,97,116,111,109,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,111,109,112,105,108,101,114,32,119,105,108,108,32,114,101,119,114,105,116,101,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,115,111,109,101,95,97,116,111,109,41>>]},<<32,116,111,32>>,{code,[],[<<34,115,111,109,101,95,97,116,111,109,34>>]},<<46,32,73,102,32,116,104,97,116,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,110,116,105,111,110,32,111,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,111,109,101,95,97,116,111,109>>]},<<32,105,110,32,116,104,101,32,99,111,110,116,97,105,110,105,110,103,32,109,111,100,117,108,101,44,32,116,104,101,32,97,116,111,109,32,119,105,108,108,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,108,111,97,100,101,100,44,32,97,110,100,32,97,32,115,117,98,115,101,113,117,101,110,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,40,34,115,111,109,101,95,97,116,111,109,34,41>>]},<<32,119,105,108,108,32,102,97,105,108,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,53,57>>,signature => [{attribute,1271,spec,{{list_to_existing_atom,1},[{type,1271,bounded_fun,[{type,1271,'fun',[{type,1271,product,[{var,1271,'String'}]},{type,1271,atom,[]}]},[{type,1272,constraint,[{atom,1272,is_subtype},[{var,1272,'String'},{type,1272,string,[]}]]}]]}]}}]}},{{function,list_to_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1277}],[<<108,105,115,116,95,116,111,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,102,108,111,97,116,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,102,108,111,97,116,40,34,50,46,50,48,49,55,55,54,52,101,43,48,34,41,46,10,50,46,50,48,49,55,55,54,52>>]}]},{p,[],[<<84,104,101,32,102,108,111,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,102,111,114,109,97,116,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,102,108,111,97,116,32,108,105,116,101,114,97,108,115>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,97,116,32,117,110,100,101,114,115,99,111,114,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,102,108,111,97,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,56,48>>,signature => [{attribute,1277,spec,{{list_to_float,1},[{type,1277,bounded_fun,[{type,1277,'fun',[{type,1277,product,[{var,1277,'String'}]},{type,1277,float,[]}]},[{type,1278,constraint,[{atom,1278,is_subtype},[{var,1278,'String'},{type,1278,string,[]}]]}]]}]}}]}},{{function,list_to_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1283}],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,49,50,51,34,41,46,10,49,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,45,49,50,51,34,41,46,10,45,49,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,43,49,50,51,50,51,52,57,56,50,51,48,52,57,56,50,51,48,57,52,56,50,48,57,51,56,51,51,50,51,52,50,51,52,34,41,46,10,49,50,51,50,51,52,57,56,50,51,48,52,57,56,50,51,48,57,52,56,50,48,57,51,56,51,51,50,51,52,50,51,52>>]}]},{p,[],[{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,99,111,110,116,97,105,110,32,97,116,32,108,101,97,115,116,32,111,110,101,32,100,105,103,105,116,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32,99,97,110,32,104,97,118,101,32,97,110,32,111,112,116,105,111,110,97,108,32,112,114,101,102,105,120,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32,97,32,115,105,110,103,108,101,32,34>>,{code,[],[<<43>>]},<<34,32,111,114,32,34>>,{code,[],[<<45>>]},<<34,32,99,104,97,114,97,99,116,101,114,32,40,116,104,97,116,32,105,115,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<34,94,91,43,45,93,63,91,48,45,57,93,43,36,34>>]},<<41,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,57,56>>,signature => [{attribute,1283,spec,{{list_to_integer,1},[{type,1283,bounded_fun,[{type,1283,'fun',[{type,1283,product,[{var,1283,'String'}]},{type,1283,integer,[]}]},[{type,1284,constraint,[{atom,1284,is_subtype},[{var,1284,'String'},{type,1284,string,[]}]]}]]}]}}]}},{{function,list_to_integer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1289}],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,70,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,43,51,70,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,102,102,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,102,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,45,51,70,70,34,44,32,49,54,41,46,10,45,49,48,50,51>>]}]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32,49,54,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<34,94,91,43,45,93,63,40,91,48,45,57,93,124,91,65,45,70,93,124,91,97,45,102,93,41,43,36,34>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,50,51>>,signature => [{attribute,1289,spec,{{list_to_integer,2},[{type,1289,bounded_fun,[{type,1289,'fun',[{type,1289,product,[{var,1289,'String'},{var,1289,'Base'}]},{type,1289,integer,[]}]},[{type,1290,constraint,[{atom,1290,is_subtype},[{var,1290,'String'},{type,1290,string,[]}]]},{type,1291,constraint,[{atom,1291,is_subtype},[{var,1291,'Base'},{type,1291,range,[{integer,1291,2},{integer,1291,36}]}]]}]]}]}}]}},{{function,list_to_pid,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1296}],[<<108,105,115,116,95,116,111,95,112,105,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,112,105,100,40,34,60,48,46,52,46,49,62,34,41,46,10,60,48,46,52,46,49,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,53,51>>,signature => [{attribute,1296,spec,{{list_to_pid,1},[{type,1296,bounded_fun,[{type,1296,'fun',[{type,1296,product,[{var,1296,'String'}]},{type,1296,pid,[]}]},[{type,1297,constraint,[{atom,1297,is_subtype},[{var,1297,'String'},{type,1297,string,[]}]]}]]}]}}]}},{{function,list_to_port,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1302}],[<<108,105,115,116,95,116,111,95,112,111,114,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,112,111,114,116,40,34,35,80,111,114,116,60,48,46,52,62,34,41,46,10,35,80,111,114,116,60,48,46,52,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,55,49>>,signature => [{attribute,1302,spec,{{list_to_port,1},[{type,1302,bounded_fun,[{type,1302,'fun',[{type,1302,product,[{var,1302,'String'}]},{type,1302,port,[]}]},[{type,1303,constraint,[{atom,1303,is_subtype},[{var,1303,'String'},{type,1303,string,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,list_to_ref,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1308}],[<<108,105,115,116,95,116,111,95,114,101,102,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,114,101,102,101,114,101,110,99,101,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,114,101,102,40,34,35,82,101,102,60,48,46,52,49,57,50,53,51,55,54,55,56,46,52,48,55,51,49,57,51,52,55,53,46,55,49,49,56,49,62,34,41,46,10,35,82,101,102,60,48,46,52,49,57,50,53,51,55,54,55,56,46,52,48,55,51,49,57,51,52,55,53,46,55,49,49,56,49,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,114,101,102,101,114,101,110,99,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,56,57>>,signature => [{attribute,1308,spec,{{list_to_ref,1},[{type,1308,bounded_fun,[{type,1308,'fun',[{type,1308,product,[{var,1308,'String'}]},{type,1308,reference,[]}]},[{type,1309,constraint,[{atom,1309,is_subtype},[{var,1309,'String'},{type,1309,string,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,list_to_tuple,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1314}],[<<108,105,115,116,95,116,111,95,116,117,112,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,116,117,112,108,101,40,91,115,104,97,114,101,44,32,91,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,93,93,41,46,10,123,115,104,97,114,101,44,32,91,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,93,125>>]}]},{p,[],[{code,[],[<<76,105,115,116>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,48,55>>,signature => [{attribute,1314,spec,{{list_to_tuple,1},[{type,1314,bounded_fun,[{type,1314,'fun',[{type,1314,product,[{var,1314,'List'}]},{type,1314,tuple,any}]},[{type,1315,constraint,[{atom,1315,is_subtype},[{var,1315,'List'},{type,1315,list,[{type,1315,term,[]}]}]]}]]}]}}]}},{{function,load_module,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2246}],[<<108,111,97,100,95,109,111,100,117,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<44,32,116,104,105,115,32,66,73,70,32,108,111,97,100,115,32,116,104,97,116,32,111,98,106,101,99,116,32,99,111,100,101,46,32,73,102,32,116,104,101,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,44,32,97,108,108,32,101,120,112,111,114,116,32,114,101,102,101,114,101,110,99,101,115,32,97,114,101,32,114,101,112,108,97,99,101,100,32,115,111,32,116,104,101,121,32,112,111,105,110,116,32,116,111,32,116,104,101,32,110,101,119,108,121,32,108,111,97,100,101,100,32,99,111,100,101,46,32,84,104,101,32,112,114,101,118,105,111,117,115,108,121,32,108,111,97,100,101,100,32,99,111,100,101,32,105,115,32,107,101,112,116,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,97,115,32,111,108,100,32,99,111,100,101,44,32,97,115,32,116,104,101,114,101,32,99,97,110,32,115,116,105,108,108,32,98,101,32,112,114,111,99,101,115,115,101,115,32,101,120,101,99,117,116,105,110,103,32,116,104,97,116,32,99,111,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,101,105,116,104,101,114,32>>,{code,[],[<<123,109,111,100,117,108,101,44,32,77,111,100,117,108,101,125>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,102,32,108,111,97,100,105,110,103,32,102,97,105,108,115,46,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,102,105,108,101>>]}]},{dd,[],[<<84,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,102,111,114,109,97,116,32>>,{em,[],[<<111,114>>]},<<32,116,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,99,111,110,116,97,105,110,115,32,99,111,100,101,32,102,111,114,32,97,110,111,116,104,101,114,32,109,111,100,117,108,101,32,116,104,97,110,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,116,95,112,117,114,103,101,100>>]}]},{dd,[],[{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,109,111,100,117,108,101,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,108,111,97,100,101,100,32,98,101,99,97,117,115,101,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,50,48>>,signature => [{attribute,2246,spec,{{load_module,2},[{type,2246,bounded_fun,[{type,2246,'fun',[{type,2246,product,[{var,2246,'Module'},{var,2246,'Binary'}]},{type,2246,union,[{type,2246,tuple,[{atom,2246,module},{var,2246,'Module'}]},{type,2246,tuple,[{atom,2246,error},{var,2246,'Reason'}]}]}]},[{type,2247,constraint,[{atom,2247,is_subtype},[{var,2247,'Module'},{type,2247,module,[]}]]},{type,2248,constraint,[{atom,2248,is_subtype},[{var,2248,'Binary'},{type,2248,binary,[]}]]},{type,2249,constraint,[{atom,2249,is_subtype},[{var,2249,'Reason'},{type,2249,union,[{atom,2249,badfile},{atom,2249,not_purged},{atom,2249,on_load}]}]]}]]}]}}]}},{{function,load_nif,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2267}],[<<108,111,97,100,95,110,105,102,47,50>>],#{<<101,110>> => [{p,[],[<<76,111,97,100,115,32,97,110,100,32,108,105,110,107,115,32,97,32,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,110,97,116,105,118,101,32,105,109,112,108,101,109,101,110,116,101,100,32,102,117,110,99,116,105,111,110,115,32,40,78,73,70,115,41,32,102,111,114,32,97,32,109,111,100,117,108,101,46,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,97,32,102,105,108,101,32,112,97,116,104,32,116,111,32,116,104,101,32,115,104,97,114,101,97,98,108,101,32,111,98,106,101,99,116,47,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,32,102,105,108,101,32,109,105,110,117,115,32,116,104,101,32,79,83,45,100,101,112,101,110,100,101,110,116,32,102,105,108,101,32,101,120,116,101,110,115,105,111,110,32,40>>,{code,[],[<<46,115,111>>]},<<32,102,111,114,32,85,110,105,120,32,97,110,100,32>>,{code,[],[<<46,100,108,108>>]},<<32,102,111,114,32,87,105,110,100,111,119,115,41,46,32,78,111,116,105,99,101,32,116,104,97,116,32,111,110,32,109,111,115,116,32,79,83,115,32,116,104,101,32,108,105,98,114,97,114,121,32,104,97,115,32,116,111,32,104,97,118,101,32,97,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,32,111,110,32,100,105,115,99,32,119,104,101,110,32,97,110,32,117,112,103,114,97,100,101,32,111,102,32,116,104,101,32,110,105,102,32,105,115,32,100,111,110,101,46,32,73,102,32,116,104,101,32,110,97,109,101,32,105,115,32,116,104,101,32,115,97,109,101,44,32,98,117,116,32,116,104,101,32,99,111,110,116,101,110,116,115,32,100,105,102,102,101,114,44,32,116,104,101,32,111,108,100,32,108,105,98,114,97,114,121,32,109,97,121,32,98,101,32,108,111,97,100,101,100,32,105,110,115,116,101,97,100,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,32,78,73,70,32,108,105,98,114,97,114,121,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,108,95,110,105,102>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,110,105,102,40,51,41>>]}]},<<46>>]},{p,[],[{code,[],[<<76,111,97,100,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,46,32,73,116,32,105,115,32,112,97,115,115,101,100,32,111,110,32,116,111,32,116,104,101,32,108,105,98,114,97,114,121,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,105,110,105,116,105,97,108,105,122,97,116,105,111,110,46,32,65,32,103,111,111,100,32,112,114,97,99,116,105,99,101,32,105,115,32,116,111,32,105,110,99,108,117,100,101,32,97,32,109,111,100,117,108,101,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,116,111,32,115,117,112,112,111,114,116,32,102,117,116,117,114,101,32,99,111,100,101,32,117,112,103,114,97,100,101,32,115,99,101,110,97,114,105,111,115,46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,111,97,100,95,110,105,102,47,50>>]},<<32,109,117,115,116,32,98,101,32,109,97,100,101,32>>,{em,[],[<<100,105,114,101,99,116,108,121>>]},<<32,102,114,111,109,32,116,104,101,32,69,114,108,97,110,103,32,99,111,100,101,32,111,102,32,116,104,101,32,109,111,100,117,108,101,32,116,104,97,116,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,98,101,108,111,110,103,115,32,116,111,46,32,73,116,32,114,101,116,117,114,110,115,32,101,105,116,104,101,114,32>>,{code,[],[<<111,107>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,123,82,101,97,115,111,110,44,84,101,120,116,125,125>>]},<<32,105,102,32,108,111,97,100,105,110,103,32,102,97,105,108,115,46,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,32,119,104,105,108,101,32>>,{code,[],[<<84,101,120,116>>]},<<32,105,115,32,97,32,104,117,109,97,110,32,114,101,97,100,97,98,108,101,32,115,116,114,105,110,103,32,116,104,97,116,32,99,97,110,32,103,105,118,101,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,97,105,108,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,97,100,95,102,97,105,108,101,100>>]}]},{dd,[],[<<84,104,101,32,79,83,32,102,97,105,108,101,100,32,116,111,32,108,111,97,100,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,46>>]},{dt,[],[{code,[],[<<98,97,100,95,108,105,98>>]}]},{dd,[],[<<84,104,101,32,108,105,98,114,97,114,121,32,100,105,100,32,110,111,116,32,102,117,108,102,105,108,108,32,116,104,101,32,114,101,113,117,105,114,101,109,101,110,116,115,32,97,115,32,97,32,78,73,70,32,108,105,98,114,97,114,121,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,109,111,100,117,108,101,46>>]},{dt,[],[{code,[],[<<108,111,97,100,32,124,32,117,112,103,114,97,100,101>>]}]},{dd,[],[<<84,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,98,114,97,114,121,32,99,97,108,108,98,97,99,107,32,119,97,115,32,117,110,115,117,99,99,101,115,115,102,117,108,46>>]},{dt,[],[{code,[],[<<114,101,108,111,97,100>>]}]},{dd,[],[<<65,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,97,108,114,101,97,100,121,32,108,111,97,100,101,100,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,105,110,115,116,97,110,99,101,46,32,84,104,101,32,112,114,101,118,105,111,117,115,108,121,32,100,101,112,114,101,99,97,116,101,100,32>>,{code,[],[<<114,101,108,111,97,100>>]},<<32,102,101,97,116,117,114,101,32,119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,79,84,80,32,50,48,46>>]},{dt,[],[{code,[],[<<111,108,100,95,99,111,100,101>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,111,97,100,95,110,105,102,47,50>>]},<<32,119,97,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,111,108,100,32,99,111,100,101,32,111,102,32,97,32,109,111,100,117,108,101,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,117,112,103,114,97,100,101,100,59,32,116,104,105,115,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,53,51>>,signature => [{attribute,2267,spec,{{erlang,load_nif,2},[{type,2267,bounded_fun,[{type,2267,'fun',[{type,2267,product,[{var,2267,'Path'},{var,2267,'LoadInfo'}]},{type,2267,union,[{atom,2267,ok},{var,2267,'Error'}]}]},[{type,2268,constraint,[{atom,2268,is_subtype},[{var,2268,'Path'},{type,2268,string,[]}]]},{type,2269,constraint,[{atom,2269,is_subtype},[{var,2269,'LoadInfo'},{type,2269,term,[]}]]},{type,2270,constraint,[{atom,2270,is_subtype},[{var,2270,'Error'},{type,2270,tuple,[{atom,2270,error},{type,2270,tuple,[{var,2270,'Reason'},{ann_type,2270,[{var,2270,'Text'},{type,2270,string,[]}]}]}]}]]},{type,2271,constraint,[{atom,2271,is_subtype},[{var,2271,'Reason'},{type,2271,union,[{atom,2271,load_failed},{atom,2271,bad_lib},{atom,2271,load},{atom,2271,reload},{atom,2271,upgrade},{atom,2271,old_code}]}]]}]]}]}}]}},{{function,loaded,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1320}],[<<108,111,97,100,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,108,111,97,100,101,100,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,40,99,117,114,114,101,110,116,32,97,110,100,32,111,108,100,32,99,111,100,101,41,44,32,105,110,99,108,117,100,105,110,103,32,112,114,101,108,111,97,100,101,100,32,109,111,100,117,108,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,48,50>>,signature => [{attribute,1320,spec,{{erlang,loaded,0},[{type,1320,bounded_fun,[{type,1320,'fun',[{type,1320,product,[]},{type,1320,list,[{var,1320,'Module'}]}]},[{type,1321,constraint,[{atom,1321,is_subtype},[{var,1321,'Module'},{type,1321,module,[]}]]}]]}]}}]}},{{function,localtime,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1326}],[<<108,111,99,97,108,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,44,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,40,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,49,51>>,signature => [{attribute,1326,spec,{{erlang,localtime,0},[{type,1326,bounded_fun,[{type,1326,'fun',[{type,1326,product,[]},{var,1326,'DateTime'}]},[{type,1327,constraint,[{atom,1327,is_subtype},[{var,1327,'DateTime'},{remote_type,1327,[{atom,1327,calendar},{atom,1327,datetime},[]]}]]}]]}]}}]}},{{function,localtime_to_universaltime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3481}],[<<108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,44,32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,110,111,32,99,111,110,118,101,114,115,105,111,110,32,105,115,32,100,111,110,101,32,97,110,100,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,51,48>>,signature => [{attribute,3481,spec,{{erlang,localtime_to_universaltime,1},[{type,3481,bounded_fun,[{type,3481,'fun',[{type,3481,product,[{var,3481,'Localtime'}]},{var,3481,'Universaltime'}]},[{type,3482,constraint,[{atom,3482,is_subtype},[{var,3482,'Localtime'},{remote_type,3482,[{atom,3482,calendar},{atom,3482,datetime},[]]}]]},{type,3483,constraint,[{atom,3483,is_subtype},[{var,3483,'Universaltime'},{remote_type,3483,[{atom,3483,calendar},{atom,3483,datetime},[]]}]]}]]}]}}]}},{{function,localtime_to_universaltime,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2275}],[<<108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,97,115,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,49>>]},<<44,32,98,117,116,32,116,104,101,32,99,97,108,108,101,114,32,100,101,99,105,100,101,115,32,105,102,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,105,115,32,97,99,116,105,118,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,116,114,117,101>>]},<<44,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,105,115,32,100,117,114,105,110,103,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,44,32,105,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,102,97,108,115,101>>]},<<32,105,116,32,105,115,32,110,111,116,46,32,73,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,117,110,100,101,102,105,110,101,100>>]},<<44,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,32,99,97,110,32,103,117,101,115,115,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,76,111,99,97,108,116,105,109,101,41>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,116,114,117,101,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,50,44,52,53,44,49,55,125,125,10,62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,102,97,108,115,101,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125,10,62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,117,110,100,101,102,105,110,101,100,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,52,55>>,signature => [{attribute,2275,spec,{{erlang,localtime_to_universaltime,2},[{type,2275,bounded_fun,[{type,2275,'fun',[{type,2275,product,[{var,2275,'Localtime'},{var,2275,'IsDst'}]},{var,2275,'Universaltime'}]},[{type,2276,constraint,[{atom,2276,is_subtype},[{var,2276,'Localtime'},{remote_type,2276,[{atom,2276,calendar},{atom,2276,datetime},[]]}]]},{type,2277,constraint,[{atom,2277,is_subtype},[{var,2277,'Universaltime'},{remote_type,2277,[{atom,2277,calendar},{atom,2277,datetime},[]]}]]},{type,2278,constraint,[{atom,2278,is_subtype},[{var,2278,'IsDst'},{type,2278,union,[{atom,2278,true},{atom,2278,false},{atom,2278,undefined}]}]]}]]}]}}]}},{{function,make_ref,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1332}],[<<109,97,107,101,95,114,101,102,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,114,101,102,101,114,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<117,110,105,113,117,101,32,114,101,102,101,114,101,110,99,101>>]},<<46,32,84,104,101,32,114,101,102,101,114,101,110,99,101,32,105,115,32,117,110,105,113,117,101,32,97,109,111,110,103,32,99,111,110,110,101,99,116,101,100,32,110,111,100,101,115,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<75,110,111,119,110,32,105,115,115,117,101,58,32,87,104,101,110,32,97,32,110,111,100,101,32,105,115,32,114,101,115,116,97,114,116,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,110,97,109,101,44,32,114,101,102,101,114,101,110,99,101,115,32,99,114,101,97,116,101,100,32,111,110,32,97,32,110,101,119,101,114,32,110,111,100,101,32,99,97,110,32,98,101,32,109,105,115,116,97,107,101,110,32,102,111,114,32,97,32,114,101,102,101,114,101,110,99,101,32,99,114,101,97,116,101,100,32,111,110,32,97,110,32,111,108,100,101,114,32,110,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,110,97,109,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,55,51>>,signature => [{attribute,1332,spec,{{make_ref,0},[{type,1332,'fun',[{type,1332,product,[]},{type,1332,reference,[]}]}]}}]}},{{function,make_tuple,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2294}],[<<109,97,107,101,95,116,117,112,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,110,101,119,32,116,117,112,108,101,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32>>,{code,[],[<<65,114,105,116,121>>]},<<44,32,119,104,101,114,101,32,97,108,108,32,101,108,101,109,101,110,116,115,32,97,114,101,32>>,{code,[],[<<73,110,105,116,105,97,108,86,97,108,117,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,109,97,107,101,95,116,117,112,108,101,40,52,44,32,91,93,41,46,10,123,91,93,44,91,93,44,91,93,44,91,93,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,57,48>>,signature => [{attribute,2294,spec,{{erlang,make_tuple,2},[{type,2294,bounded_fun,[{type,2294,'fun',[{type,2294,product,[{var,2294,'Arity'},{var,2294,'InitialValue'}]},{type,2294,tuple,any}]},[{type,2295,constraint,[{atom,2295,is_subtype},[{var,2295,'Arity'},{type,2295,arity,[]}]]},{type,2296,constraint,[{atom,2296,is_subtype},[{var,2296,'InitialValue'},{type,2296,term,[]}]]}]]}]}}]}},{{function,make_tuple,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2301}],[<<109,97,107,101,95,116,117,112,108,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,116,117,112,108,101,32,111,102,32,115,105,122,101,32>>,{code,[],[<<65,114,105,116,121>>]},<<44,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,104,97,115,32,118,97,108,117,101,32>>,{code,[],[<<68,101,102,97,117,108,116,86,97,108,117,101>>]},<<44,32,97,110,100,32,116,104,101,110,32,102,105,108,108,115,32,105,110,32,118,97,108,117,101,115,32,102,114,111,109,32>>,{code,[],[<<73,110,105,116,76,105,115,116>>]},<<46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<73,110,105,116,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32,97,32,116,119,111,45,116,117,112,108,101,44,32,119,104,101,114,101,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,116,117,112,108,101,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32,105,115,32,97,110,121,32,116,101,114,109,46,32,73,102,32,97,32,112,111,115,105,116,105,111,110,32,111,99,99,117,114,115,32,109,111,114,101,32,116,104,97,110,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,116,104,101,32,116,101,114,109,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,108,97,115,116,32,111,99,99,117,114,114,101,110,99,101,32,105,115,32,117,115,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,109,97,107,101,95,116,117,112,108,101,40,53,44,32,91,93,44,32,91,123,50,44,105,103,110,111,114,101,100,125,44,123,53,44,122,122,125,44,123,50,44,97,97,125,93,41,46,10,123,91,93,44,97,97,44,91,93,44,91,93,44,122,122,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,48,50>>,signature => [{attribute,2301,spec,{{erlang,make_tuple,3},[{type,2301,bounded_fun,[{type,2301,'fun',[{type,2301,product,[{var,2301,'Arity'},{var,2301,'DefaultValue'},{var,2301,'InitList'}]},{type,2301,tuple,any}]},[{type,2302,constraint,[{atom,2302,is_subtype},[{var,2302,'Arity'},{type,2302,arity,[]}]]},{type,2303,constraint,[{atom,2303,is_subtype},[{var,2303,'DefaultValue'},{type,2303,term,[]}]]},{type,2304,constraint,[{atom,2304,is_subtype},[{var,2304,'InitList'},{type,2304,list,[{type,2304,tuple,[{ann_type,2304,[{var,2304,'Position'},{type,2304,pos_integer,[]}]},{type,2304,term,[]}]}]}]]}]]}]}}]}},{{function,map_get,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1343}],[<<109,97,112,95,103,101,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,109,97,112,44,77,97,112,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,105,115,32,110,111,116,32,97,32,109,97,112,44,32,111,114,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,107,101,121,44,75,101,121,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32,110,111,32,118,97,108,117,101,32,105,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<62,32,75,101,121,32,61,32,49,51,51,55,44,10,32,32,77,97,112,32,61,32,35,123,52,50,32,61,62,32,118,97,108,117,101,95,116,119,111,44,49,51,51,55,32,61,62,32,34,118,97,108,117,101,32,111,110,101,34,44,34,97,34,32,61,62,32,49,125,44,10,32,32,109,97,112,95,103,101,116,40,75,101,121,44,77,97,112,41,46,10,34,118,97,108,117,101,32,111,110,101,34>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,50,48>>,signature => [{attribute,1343,spec,{{map_get,2},[{type,1343,bounded_fun,[{type,1343,'fun',[{type,1343,product,[{var,1343,'Key'},{var,1343,'Map'}]},{var,1343,'Value'}]},[{type,1344,constraint,[{atom,1344,is_subtype},[{var,1344,'Map'},{type,1344,map,any}]]},{type,1345,constraint,[{atom,1345,is_subtype},[{var,1345,'Key'},{type,1345,any,[]}]]},{type,1346,constraint,[{atom,1346,is_subtype},[{var,1346,'Value'},{type,1346,any,[]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,48>>}},{{function,map_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1337}],[<<109,97,112,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,107,101,121,45,118,97,108,117,101,32,112,97,105,114,115,32,105,110,32>>,{code,[],[<<77,97,112>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,109,97,112,95,115,105,122,101,40,35,123,97,61,62,49,44,32,98,61,62,50,44,32,99,61,62,51,125,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,52,48>>,signature => [{attribute,1337,spec,{{map_size,1},[{type,1337,bounded_fun,[{type,1337,'fun',[{type,1337,product,[{var,1337,'Map'}]},{type,1337,non_neg_integer,[]}]},[{type,1338,constraint,[{atom,1338,is_subtype},[{var,1338,'Map'},{type,1338,map,any}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,match_spec_test,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1351}],[<<109,97,116,99,104,95,115,112,101,99,95,116,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,101,115,116,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,117,115,101,100,32,105,110,32,99,97,108,108,115,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,115,101,108,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,116,115,58,115,101,108,101,99,116,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,101,115,116,115,32,98,111,116,104,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,34,115,121,110,116,97,99,116,105,99,34,32,99,111,114,114,101,99,116,110,101,115,115,32,97,110,100,32,114,117,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,103,97,105,110,115,116,32,116,104,101,32,111,98,106,101,99,116,46,32,73,102,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,99,111,110,116,97,105,110,115,32,101,114,114,111,114,115,44,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,69,114,114,111,114,115,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,119,104,101,114,101,32>>,{code,[],[<<69,114,114,111,114,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,110,97,116,117,114,97,108,32,108,97,110,103,117,97,103,101,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,119,104,97,116,32,119,97,115,32,119,114,111,110,103,32,119,105,116,104,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<116,97,98,108,101>>]},<<44,32,116,104,101,32,111,98,106,101,99,116,32,116,111,32,109,97,116,99,104,32,97,103,97,105,110,115,116,32,105,115,32,116,111,32,98,101,32,97,32,116,117,112,108,101,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,82,101,115,117,108,116,44,91,93,44,87,97,114,110,105,110,103,115,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,119,104,97,116,32,119,111,117,108,100,32,104,97,118,101,32,98,101,101,110,32,116,104,101,32,114,101,115,117,108,116,32,105,110,32,97,32,114,101,97,108,32>>,{code,[],[<<101,116,115,58,115,101,108,101,99,116,47,50>>]},<<32,99,97,108,108,44,32,111,114,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,111,98,106,101,99,116,32,116,117,112,108,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<116,114,97,99,101>>]},<<44,32,116,104,101,32,111,98,106,101,99,116,32,116,111,32,109,97,116,99,104,32,97,103,97,105,110,115,116,32,105,115,32,116,111,32,98,101,32,97,32,108,105,115,116,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,82,101,115,117,108,116,44,32,70,108,97,103,115,44,32,87,97,114,110,105,110,103,115,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<116,114,117,101>>]},<<32,105,102,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,116,111,32,98,101,32,101,109,105,116,116,101,100>>]},{li,[],[{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,110,111,116,32,116,111,32,98,101,32,101,109,105,116,116,101,100>>]},{li,[],[<<84,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,32,116,111,32,98,101,32,97,112,112,101,110,100,101,100,32,116,111,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101>>]}]},{p,[],[{code,[],[<<70,108,97,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,116,111,32,98,101,32,101,110,97,98,108,101,100,44,32,99,117,114,114,101,110,116,108,121,32,116,104,105,115,32,105,115,32,111,110,108,121,32>>,{code,[],[<<114,101,116,117,114,110,95,116,114,97,99,101>>]},<<46>>]},{p,[],[<<84,104,105,115,32,105,115,32,97,32,117,115,101,102,117,108,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,116,101,115,116,32,116,111,111,108,44,32,101,115,112,101,99,105,97,108,108,121,32,119,104,101,110,32,119,114,105,116,105,110,103,32,99,111,109,112,108,105,99,97,116,101,100,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,116,101,115,116,95,109,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,116,115,58,116,101,115,116,95,109,115,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,53,51>>,signature => [{attribute,1351,spec,{{erlang,match_spec_test,3},[{type,1351,bounded_fun,[{type,1351,'fun',[{type,1351,product,[{var,1351,'MatchAgainst'},{var,1351,'MatchSpec'},{var,1351,'Type'}]},{var,1351,'TestResult'}]},[{type,1352,constraint,[{atom,1352,is_subtype},[{var,1352,'MatchAgainst'},{type,1352,union,[{type,1352,list,[{type,1352,term,[]}]},{type,1352,tuple,any}]}]]},{type,1353,constraint,[{atom,1353,is_subtype},[{var,1353,'MatchSpec'},{type,1353,term,[]}]]},{type,1354,constraint,[{atom,1354,is_subtype},[{var,1354,'Type'},{type,1354,union,[{atom,1354,table},{atom,1354,trace}]}]]},{type,1355,constraint,[{atom,1355,is_subtype},[{var,1355,'TestResult'},{type,1355,union,[{type,1355,tuple,[{atom,1355,ok},{type,1355,term,[]},{type,1355,list,[{atom,1355,return_trace}]},{type,1355,list,[{type,1355,tuple,[{type,1355,union,[{atom,1355,error},{atom,1355,warning}]},{type,1355,string,[]}]}]}]},{type,1355,tuple,[{atom,1355,error},{type,1355,list,[{type,1355,tuple,[{type,1355,union,[{atom,1355,error},{atom,1355,warning}]},{type,1355,string,[]}]}]}]}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,max,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3962}],[<<109,97,120,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,97,114,103,101,115,116,32,111,102,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,97,110,100,32>>,{code,[],[<<84,101,114,109,50>>]},<<46,32,73,102,32,116,104,101,32,116,101,114,109,115,32,99,111,109,112,97,114,101,32,101,113,117,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,44,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,101,114,109,45,99,111,109,112,97,114,105,115,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,120,112,114,101,115,115,105,111,110,115,32,115,101,99,116,105,111,110>>]},<<32,99,111,110,116,97,105,110,115,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,32,97,110,100,32,104,111,119,32,116,101,114,109,115,32,97,114,101,32,111,114,100,101,114,101,100,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,44,32,50,41,46,10,50>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,46,48,44,32,49,41,46,10,49,46,48>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,44,32,49,46,48,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,34,97,98,99,34,44,32,34,98,34,41,46,10,34,98,34>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,57,49>>,signature => [{attribute,3962,spec,{{max,2},[{type,3962,bounded_fun,[{type,3962,'fun',[{type,3962,product,[{var,3962,'Term1'},{var,3962,'Term2'}]},{var,3962,'Maximum'}]},[{type,3963,constraint,[{atom,3963,is_subtype},[{var,3963,'Term1'},{type,3963,term,[]}]]},{type,3964,constraint,[{atom,3964,is_subtype},[{var,3964,'Term2'},{type,3964,term,[]}]]},{type,3965,constraint,[{atom,3965,is_subtype},[{var,3965,'Maximum'},{type,3965,term,[]}]]}]]}]}}]}},{{function,md5,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1360}],[<<109,100,53,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,32,77,68,53,32,109,101,115,115,97,103,101,32,100,105,103,101,115,116,32,102,114,111,109,32>>,{code,[],[<<68,97,116,97>>]},<<44,32,119,104,101,114,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,100,105,103,101,115,116,32,105,115,32,49,50,56,32,98,105,116,115,32,40,49,54,32,98,121,116,101,115,41,46,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,111,114,32,97,32,108,105,115,116,32,111,102,32,115,109,97,108,108,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,77,68,53,44,32,115,101,101,32>>,{a,[{href,<<104,116,116,112,115,58,47,47,119,119,119,46,105,101,116,102,46,111,114,103,47,114,102,99,47,114,102,99,49,51,50,49,46,116,120,116>>}],[<<82,70,67,32,49,51,50,49,32,45,32,84,104,101,32,77,68,53,32,77,101,115,115,97,103,101,45,68,105,103,101,115,116,32,65,108,103,111,114,105,116,104,109>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,32,77,68,53,32,77,101,115,115,97,103,101,45,68,105,103,101,115,116,32,65,108,103,111,114,105,116,104,109,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,99,111,110,115,105,100,101,114,101,100,32,115,97,102,101,32,102,111,114,32,99,111,100,101,45,115,105,103,110,105,110,103,32,111,114,32,115,111,102,116,119,97,114,101,45,105,110,116,101,103,114,105,116,121,32,112,117,114,112,111,115,101,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,50,48>>,signature => [{attribute,1360,spec,{{erlang,md5,1},[{type,1360,bounded_fun,[{type,1360,'fun',[{type,1360,product,[{var,1360,'Data'}]},{var,1360,'Digest'}]},[{type,1361,constraint,[{atom,1361,is_subtype},[{var,1361,'Data'},{type,1361,iodata,[]}]]},{type,1362,constraint,[{atom,1362,is_subtype},[{var,1362,'Digest'},{type,1362,binary,[]}]]}]]}]}}]}},{{function,md5_final,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1367}],[<<109,100,53,95,102,105,110,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<70,105,110,105,115,104,101,115,32,116,104,101,32,117,112,100,97,116,101,32,111,102,32,97,110,32,77,68,53,32>>,{code,[],[<<67,111,110,116,101,120,116>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,99,111,109,112,117,116,101,100,32>>,{code,[],[<<77,68,53>>]},<<32,109,101,115,115,97,103,101,32,100,105,103,101,115,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,51,56>>,signature => [{attribute,1367,spec,{{erlang,md5_final,1},[{type,1367,bounded_fun,[{type,1367,'fun',[{type,1367,product,[{var,1367,'Context'}]},{var,1367,'Digest'}]},[{type,1368,constraint,[{atom,1368,is_subtype},[{var,1368,'Context'},{type,1368,binary,[]}]]},{type,1369,constraint,[{atom,1369,is_subtype},[{var,1369,'Digest'},{type,1369,binary,[]}]]}]]}]}}]}},{{function,md5_init,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1374}],[<<109,100,53,95,105,110,105,116,47,48>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,110,32,77,68,53,32,99,111,110,116,101,120,116,44,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,100,53,95,117,112,100,97,116,101,47,50>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,52,56>>,signature => [{attribute,1374,spec,{{erlang,md5_init,0},[{type,1374,bounded_fun,[{type,1374,'fun',[{type,1374,product,[]},{var,1374,'Context'}]},[{type,1375,constraint,[{atom,1375,is_subtype},[{var,1375,'Context'},{type,1375,binary,[]}]]}]]}]}}]}},{{function,md5_update,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1380}],[<<109,100,53,95,117,112,100,97,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<85,112,100,97,116,101,32,97,110,32,77,68,53,32>>,{code,[],[<<67,111,110,116,101,120,116>>]},<<32,119,105,116,104,32>>,{code,[],[<<68,97,116,97>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32,97,32>>,{code,[],[<<78,101,119,67,111,110,116,101,120,116>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,53,55>>,signature => [{attribute,1380,spec,{{erlang,md5_update,2},[{type,1380,bounded_fun,[{type,1380,'fun',[{type,1380,product,[{var,1380,'Context'},{var,1380,'Data'}]},{var,1380,'NewContext'}]},[{type,1381,constraint,[{atom,1381,is_subtype},[{var,1381,'Context'},{type,1381,binary,[]}]]},{type,1382,constraint,[{atom,1382,is_subtype},[{var,1382,'Data'},{type,1382,iodata,[]}]]},{type,1383,constraint,[{atom,1383,is_subtype},[{var,1383,'NewContext'},{type,1383,binary,[]}]]}]]}]}}]}},{{function,memory,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3994}],[<<109,101,109,111,114,121,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,109,111,114,121,95,116,121,112,101>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,101,109,111,114,121,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,84,121,112,101,44,32,83,105,122,101,125>>]},<<46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,109,101,109,111,114,121,32,116,121,112,101,46,32,84,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,105,110,32,98,121,116,101,115,46>>]},{p,[],[<<77,101,109,111,114,121,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,111,116,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,102,111,114,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46,32,84,104,105,115,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,101,32,101,109,117,108,97,116,111,114,32,116,104,97,116,32,105,115,32,110,111,116,32,100,105,114,101,99,116,108,121,32,114,101,108,97,116,101,100,32,116,111,32,97,110,121,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46,32,77,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,105,115,32,109,101,109,111,114,121,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,111,111,108,115,58,105,110,115,116,114,117,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,115,116,114,117,109,101,110,116,40,51,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,116,32,97,32,109,111,114,101,32,100,101,116,97,105,108,101,100,32,98,114,101,97,107,100,111,119,110,32,111,102,32,119,104,97,116,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,105,115,32,116,121,112,101,46>>]}]},{dt,[],[{code,[],[<<97,116,111,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,97,116,111,109,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<97,116,111,109,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,102,111,114,32,97,116,111,109,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<97,116,111,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,98,105,110,97,114,105,101,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<99,111,100,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,69,114,108,97,110,103,32,99,111,100,101,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,116,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,69,84,83,32,116,97,98,108,101,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<108,111,119>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,111,110,32,54,52,45,98,105,116,32,104,97,108,102,119,111,114,100,32,101,109,117,108,97,116,111,114,46,32,84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,105,110,32,108,111,119,32,109,101,109,111,114,121,32,97,114,101,97,115,32,116,104,97,116,32,97,114,101,32,114,101,115,116,114,105,99,116,101,100,32,116,111,32,60,32,52,32,71,66,44,32,97,108,116,104,111,117,103,104,32,116,104,101,32,115,121,115,116,101,109,32,99,97,110,32,104,97,118,101,32,109,111,114,101,32,109,101,109,111,114,121,46>>]},{p,[],[<<67,97,110,32,98,101,32,114,101,109,111,118,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,32,111,102,32,116,104,101,32,104,97,108,102,119,111,114,100,32,101,109,117,108,97,116,111,114,46>>]}]},{dt,[],[{code,[],[<<109,97,120,105,109,117,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,115,105,110,99,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,115,116,97,114,116,101,100,46,32,84,104,105,115,32,116,117,112,108,101,32,105,115,32,111,110,108,121,32,112,114,101,115,101,110,116,32,119,104,101,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,114,117,110,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,114,117,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,111,111,108,115,58,105,110,115,116,114,117,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,115,116,114,117,109,101,110,116,40,51,41>>]}]},<<32,97,110,100,47,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<101,114,108,40,49,41>>]}]},<<46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,32,105,115,32,110,111,116,32,99,111,109,112,108,101,116,101,46,32,83,111,109,101,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,105,115,32,118,97,108,117,101,32,105,115,32,110,111,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,114,117,110,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,44,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,32,105,115,32,109,111,114,101,32,97,99,99,117,114,97,116,101,44,32,98,117,116,32,109,101,109,111,114,121,32,100,105,114,101,99,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32>>,{code,[],[<<109,97,108,108,111,99>>]},<<32,40,97,110,100,32,102,114,105,101,110,100,115,41,32,105,115,32,115,116,105,108,108,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,46,32,68,105,114,101,99,116,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,97,108,108,111,99>>]},<<32,97,114,101,32,111,110,108,121,32,100,111,110,101,32,102,114,111,109,32,79,83,45,115,112,101,99,105,102,105,99,32,114,117,110,116,105,109,101,32,108,105,98,114,97,114,105,101,115,32,97,110,100,32,112,101,114,104,97,112,115,32,102,114,111,109,32,117,115,101,114,45,105,109,112,108,101,109,101,110,116,101,100,32,69,114,108,97,110,103,32,100,114,105,118,101,114,115,32,116,104,97,116,32,100,111,32,110,111,116,32,117,115,101,32,116,104,101,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,100,114,105,118,101,114,32,105,110,116,101,114,102,97,99,101,46>>]},{p,[],[<<65,115,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32,116,104,101,32,115,117,109,32,111,102,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<44,32,116,104,101,32,101,114,114,111,114,32,105,110,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,112,114,111,112,97,103,97,116,101,115,32,116,111,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,46>>]},{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,97,109,111,117,110,116,115,32,111,102,32,109,101,109,111,114,121,32,116,104,97,116,32,97,114,101,32,115,117,109,109,101,100,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,44,32,119,104,105,99,104,32,105,110,116,114,111,100,117,99,101,115,32,97,110,32,101,114,114,111,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,118,97,108,117,101,115,32,104,97,118,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,108,97,116,105,111,110,32,116,111,32,101,97,99,104,32,111,116,104,101,114,46,32,86,97,108,117,101,115,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,97,110,32,117,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,32,105,115,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<116,111,116,97,108,32,32,32,32,32,32,61,32,112,114,111,99,101,115,115,101,115,32,43,32,115,121,115,116,101,109,10,112,114,111,99,101,115,115,101,115,32,32,61,32,112,114,111,99,101,115,115,101,115,95,117,115,101,100,32,43,32,80,114,111,99,101,115,115,101,115,78,111,116,85,115,101,100,10,115,121,115,116,101,109,32,32,32,32,32,61,32,97,116,111,109,32,43,32,98,105,110,97,114,121,32,43,32,99,111,100,101,32,43,32,101,116,115,32,43,32,79,116,104,101,114,83,121,115,116,101,109,10,97,116,111,109,32,32,32,32,32,32,32,61,32,97,116,111,109,95,117,115,101,100,32,43,32,65,116,111,109,78,111,116,85,115,101,100,10,82,101,97,108,84,111,116,97,108,32,32,61,32,112,114,111,99,101,115,115,101,115,32,43,32,82,101,97,108,83,121,115,116,101,109,10,82,101,97,108,83,121,115,116,101,109,32,61,32,115,121,115,116,101,109,32,43,32,77,105,115,115,101,100,83,121,115,116,101,109>>]}]},{p,[],[<<77,111,114,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,104,97,114,101,100,32,108,105,98,114,97,114,105,101,115,44,32,116,104,101,32,99,111,100,101,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,116,115,101,108,102,44,32,97,110,100,32,116,104,101,32,101,109,117,108,97,116,111,114,32,115,116,97,99,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,105,110,99,108,117,100,101,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,101,113,117,97,108,32,116,111,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,97,108,108,32,112,97,103,101,115,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,101,109,117,108,97,116,111,114,46>>]},{p,[],[<<65,108,115,111,44,32,98,101,99,97,117,115,101,32,111,102,32,102,114,97,103,109,101,110,116,97,116,105,111,110,32,97,110,100,32,112,114,101,114,101,115,101,114,118,97,116,105,111,110,32,111,102,32,109,101,109,111,114,121,32,97,114,101,97,115,44,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,115,101,103,109,101,110,116,115,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,98,108,111,99,107,115,32,99,97,110,32,98,101,32,109,117,99,104,32,108,97,114,103,101,114,32,116,104,97,110,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,116,104,101,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,98,108,111,99,107,115,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,52,44,32>>,{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]},<<32,114,101,113,117,105,114,101,115,32,116,104,97,116,32,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,101,110,97,98,108,101,100,32,40,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,41,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,105,102,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,105,115,97,98,108,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,54,56>>,signature => [{attribute,3994,spec,{{erlang,memory,0},[{type,3994,bounded_fun,[{type,3994,'fun',[{type,3994,product,[]},{type,3994,list,[{type,3994,tuple,[{var,3994,'Type'},{var,3994,'Size'}]}]}]},[{type,3995,constraint,[{atom,3995,is_subtype},[{var,3995,'Type'},{user_type,3995,memory_type,[]}]]},{type,3996,constraint,[{atom,3996,is_subtype},[{var,3996,'Size'},{type,3996,non_neg_integer,[]}]]}]]}]}}]}},{{function,memory,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4013}],[<<109,101,109,111,114,121,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,109,111,114,121,95,116,121,112,101>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,105,110,32,98,121,116,101,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,109,101,109,111,114,121,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84,121,112,101>>]},<<46,32,84,104,101,32,97,114,103,117,109,101,110,116,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<109,101,109,111,114,121,95,116,121,112,101,40,41>>]},<<32,97,116,111,109,115,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,97,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,109,101,109,111,114,121,95,116,121,112,101,40,41,44,32,83,105,122,101,32,58,58,32,105,110,116,101,103,101,114,32,62,61,32,48,125>>]},<<32,116,117,112,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,52,44,32>>,{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,49>>]},<<32,114,101,113,117,105,114,101,115,32,116,104,97,116,32,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,101,110,97,98,108,101,100,32,40,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,41,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,110,111,116,32,111,110,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,116,121,112,101,115,32,108,105,115,116,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]}]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<109,97,120,105,109,117,109>>]},<<32,105,115,32,112,97,115,115,101,100,32,97,115,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,110,100,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,110,111,116,32,114,117,110,32,105,110,32,105,110,115,116,114,117,109,101,110,116,101,100,32,109,111,100,101,46>>]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,105,115,97,98,108,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,49,50>>,signature => [{attribute,4013,spec,{{erlang,memory,1},[{type,4013,'fun',[{type,4013,product,[{ann_type,4013,[{var,4013,'Type'},{user_type,4013,memory_type,[]}]}]},{type,4013,non_neg_integer,[]}]},{type,4014,'fun',[{type,4014,product,[{ann_type,4014,[{var,4014,'TypeList'},{type,4014,list,[{user_type,4014,memory_type,[]}]}]}]},{type,4014,list,[{type,4014,tuple,[{user_type,4014,memory_type,[]},{type,4014,non_neg_integer,[]}]}]}]}]}}]}},{{function,min,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3955}],[<<109,105,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,97,110,100,32>>,{code,[],[<<84,101,114,109,50>>]},<<46,32,73,102,32,116,104,101,32,116,101,114,109,115,32,99,111,109,112,97,114,101,32,101,113,117,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,44,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,101,114,109,45,99,111,109,112,97,114,105,115,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,120,112,114,101,115,115,105,111,110,115,32,115,101,99,116,105,111,110>>]},<<32,99,111,110,116,97,105,110,115,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,32,97,110,100,32,104,111,119,32,116,101,114,109,115,32,97,114,101,32,111,114,100,101,114,101,100,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,44,32,50,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,46,48,44,32,49,41,46,10,49,46,48>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,44,32,49,46,48,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,34,97,98,99,34,44,32,34,98,34,41,46,10,34,97,98,99,34>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,53,50>>,signature => [{attribute,3955,spec,{{min,2},[{type,3955,bounded_fun,[{type,3955,'fun',[{type,3955,product,[{var,3955,'Term1'},{var,3955,'Term2'}]},{var,3955,'Minimum'}]},[{type,3956,constraint,[{atom,3956,is_subtype},[{var,3956,'Term1'},{type,3956,term,[]}]]},{type,3957,constraint,[{atom,3957,is_subtype},[{var,3957,'Term2'},{type,3957,term,[]}]]},{type,3958,constraint,[{atom,3958,is_subtype},[{var,3958,'Minimum'},{type,3958,term,[]}]]}]]}]}}]}},{{function,module_loaded,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1388}],[<<109,111,100,117,108,101,95,108,111,97,100,101,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,108,111,97,100,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,116,116,101,109,112,116,32,116,111,32,108,111,97,100,32,116,104,101,32,109,111,100,117,108,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,56,49>>,signature => [{attribute,1388,spec,{{module_loaded,1},[{type,1388,bounded_fun,[{type,1388,'fun',[{type,1388,product,[{var,1388,'Module'}]},{type,1388,boolean,[]}]},[{type,1389,constraint,[{atom,1389,is_subtype},[{var,1389,'Module'},{type,1389,module,[]}]]}]]}]}}]}},{{function,monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1401}],[<<109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,111,110,105,116,111,114,95,112,111,114,116,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]}]},{p,[],[{a,[{id,<<109,111,110,105,116,111,114,95,109,101,115,115,97,103,101>>}],[]},<<83,101,110,100,115,32,97,32,109,111,110,105,116,111,114,32,114,101,113,117,101,115,116,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,116,111,32,116,104,101,32,101,110,116,105,116,121,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<46,32,73,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,111,114,32,105,116,32,99,104,97,110,103,101,115,32,109,111,110,105,116,111,114,101,100,32,115,116,97,116,101,44,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,105,115,32,110,111,116,105,102,105,101,100,32,98,121,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,97,116,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,84,97,103,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,79,98,106,101,99,116,44,32,73,110,102,111,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,114,101,113,117,101,115,116,32,105,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,115,105,103,110,97,108,46,32,84,104,97,116,32,105,115,44,32,105,116,32,116,97,107,101,115,32,116,105,109,101,32,98,101,102,111,114,101,32,116,104,101,32,115,105,103,110,97,108,32,114,101,97,99,104,101,115,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,46>>]}]},{p,[],[{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,58,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<44,32>>,{code,[],[<<112,111,114,116>>]},<<32,111,114,32>>,{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]},<<46>>]},{p,[],[<<65,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,111,110,108,121,32,111,110,99,101,44,32,97,102,116,101,114,32,116,104,97,116,32,105,116,32,105,115,32,114,101,109,111,118,101,100,32,102,114,111,109,32,98,111,116,104,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,46,32,77,111,110,105,116,111,114,115,32,97,114,101,32,102,105,114,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,116,101,114,109,105,110,97,116,101,115,44,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,97,116,32,116,104,101,32,109,111,109,101,110,116,32,111,102,32,99,114,101,97,116,105,111,110,44,32,111,114,32,105,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,105,116,32,105,115,32,108,111,115,116,46,32,73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,105,116,32,105,115,32,108,111,115,116,44,32,119,101,32,100,111,32,110,111,116,32,107,110,111,119,32,105,102,32,105,116,32,115,116,105,108,108,32,101,120,105,115,116,115,46,32,84,104,101,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,97,108,115,111,32,116,117,114,110,101,100,32,111,102,102,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<100,101,109,111,110,105,116,111,114,47,49>>]},<<32,105,115,32,99,97,108,108,101,100,46>>]},{p,[],[<<65,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,98,121,32,110,97,109,101,32,114,101,115,111,108,118,101,115,32,116,104,101,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,116,111,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,111,110,108,121,32,111,110,99,101,32,97,116,32,116,104,101,32,109,111,109,101,110,116,32,111,102,32,109,111,110,105,116,111,114,32,105,110,115,116,97,110,116,105,97,116,105,111,110,44,32,108,97,116,101,114,32,99,104,97,110,103,101,115,32,116,111,32,116,104,101,32,110,97,109,101,32,114,101,103,105,115,116,114,97,116,105,111,110,32,119,105,108,108,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,101,120,105,115,116,105,110,103,32,109,111,110,105,116,111,114,46>>]},{p,[],[<<87,104,101,110,32,97,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,44,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,104,97,116,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,79,98,106,101,99,116,44,32,73,110,102,111,125>>]}]},{p,[],[<<73,110,32,116,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,97,110,100,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,44,32,97,110,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<79,98,106,101,99,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,44,32,119,104,105,99,104,32,116,114,105,103,103,101,114,101,100,32,116,104,101,32,101,118,101,110,116,46,32,87,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<32,119,105,108,108,32,98,101,32,101,113,117,97,108,32,116,111,32,116,104,101,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,116,104,97,116,32,119,97,115,32,98,101,105,110,103,32,109,111,110,105,116,111,114,101,100,46,32,87,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,98,121,32,110,97,109,101,44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<32,119,105,108,108,32,104,97,118,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,119,104,105,99,104,32,104,97,115,32,98,101,101,110,32,117,115,101,100,32,119,105,116,104,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,99,97,108,108,32,97,110,100,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,108,111,99,97,108,32,111,114,32,114,101,109,111,116,101,32,110,111,100,101,32,110,97,109,101,32,40,102,111,114,32,112,111,114,116,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,44,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,97,108,119,97,121,115,32,108,111,99,97,108,32,110,111,100,101,32,110,97,109,101,41,46>>]}]},{dt,[],[{code,[],[<<73,110,102,111>>]}]},{dd,[],[{p,[],[<<69,105,116,104,101,114,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,44,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,40,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,100,105,100,32,110,111,116,32,101,120,105,115,116,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,109,111,110,105,116,111,114,32,99,114,101,97,116,105,111,110,41,44,32,111,114,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,40,110,111,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,110,111,100,101,32,119,104,101,114,101,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,114,101,115,105,100,101,115,41,46>>]}]}]},{dl,[],[{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115>>}],[]},{code,[],[<<112,114,111,99,101,115,115>>]}]},{dd,[],[{p,[],[<<67,114,101,97,116,101,115,32,109,111,110,105,116,111,114,32,98,101,116,119,101,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,97,110,100,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,40,108,111,99,97,108,32,111,114,32,114,101,109,111,116,101,41,44,32,97,110,32,97,116,111,109,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,44,32,108,111,99,97,116,101,100,32,101,108,115,101,119,104,101,114,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,82,84,83,32,49,48,46,48,32,40,79,84,80,32,50,49,46,48,41,44,32,109,111,110,105,116,111,114,105,110,103,32,97,32,112,114,111,99,101,115,115,32,99,111,117,108,100,32,102,97,105,108,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,114,101,115,105,100,101,100,32,111,110,32,97,32,112,114,105,109,105,116,105,118,101,32,110,111,100,101,32,40,115,117,99,104,32,97,115,32,101,114,108,95,105,110,116,101,114,102,97,99,101,32,111,114,32,106,105,110,116,101,114,102,97,99,101,41,44,32,119,104,101,114,101,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,46>>]},{p,[],[<<78,111,119,44,32,115,117,99,104,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,119,105,108,108,32,105,110,115,116,101,97,100,32,115,117,99,99,101,101,100,32,97,110,100,32,97,32,109,111,110,105,116,111,114,32,105,115,32,99,114,101,97,116,101,100,46,32,66,117,116,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,111,110,108,121,32,115,117,112,101,114,118,105,115,101,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,97,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,95,44,32,112,114,111,99,101,115,115,44,32,95,44,32,110,111,99,111,110,110,101,99,116,105,111,110,125>>]},<<32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,115,115,97,103,101,32,116,104,97,116,32,109,97,121,32,98,101,32,114,101,99,101,105,118,101,100,44,32,97,115,32,116,104,101,32,112,114,105,109,105,116,105,118,101,32,110,111,100,101,32,104,97,118,101,32,110,111,32,119,97,121,32,111,102,32,114,101,112,111,114,116,105,110,103,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,46>>]}]}]},{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,112,111,114,116>>}],[]},{code,[],[<<112,111,114,116>>]}]},{dd,[],[{p,[],[<<67,114,101,97,116,101,115,32,109,111,110,105,116,111,114,32,98,101,116,119,101,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,97,110,100,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,97,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,40,111,110,108,121,32,108,111,99,97,108,41,44,32,97,110,32,97,116,111,109,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,111,114,116,44,32,108,111,99,97,116,101,100,32,111,110,32,116,104,105,115,32,110,111,100,101,46,32,78,111,116,101,44,32,116,104,97,116,32,97,116,116,101,109,112,116,32,116,111,32,109,111,110,105,116,111,114,32,97,32,114,101,109,111,116,101,32,112,111,114,116,32,119,105,108,108,32,114,101,115,117,108,116,32,105,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46>>]}]},{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,116,105,109,101,95,111,102,102,115,101,116>>}],[]},{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,99,104,97,110,103,101,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,105,109,101,32,111,102,102,115,101,116>>]}]},<<32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<46,32,79,110,101,32,118,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,101,120,105,115,116,115,32,105,110,32,99,111,109,98,105,110,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<116,105,109,101,95,111,102,102,115,101,116,32,84,121,112,101>>]},<<44,32,110,97,109,101,108,121,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,108,111,99,107,95,115,101,114,118,105,99,101>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,108,111,99,107,95,115,101,114,118,105,99,101>>]},<<32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,32,112,114,111,99,101,115,115,46,32,73,110,32,116,104,105,115,32,99,97,115,101,32,105,116,32,115,101,114,118,101,115,32,97,115,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,116,101,114,110,97,108,32,99,108,111,99,107,32,115,101,114,118,105,99,101,32,97,116,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,119,104,101,110,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,46,32,84,104,105,115,32,101,105,116,104,101,114,32,105,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,118,97,108,117,101,32,105,115,32,99,104,97,110,103,101,100,44,32,111,114,32,105,102,32,116,104,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32,112,114,101,108,105,109,105,110,97,114,121,32,116,111,32,102,105,110,97,108,32,100,117,114,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,110,97,108,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116>>]},<<32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46,32,87,104,101,110,32,97,32,99,104,97,110,103,101,32,102,114,111,109,32,112,114,101,108,105,109,105,110,97,114,121,32,116,111,32,102,105,110,97,108,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,109,97,100,101,44,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,111,110,99,101,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,118,97,108,117,101,32,119,97,115,32,99,104,97,110,103,101,100,32,111,114,32,110,111,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,101,116,101,99,116,115,32,116,104,97,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,104,97,115,32,99,104,97,110,103,101,100,46,32,84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,111,101,115,44,32,104,111,119,101,118,101,114,44,32,110,111,116,32,100,101,116,101,99,116,32,116,104,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,46,32,65,32,116,97,115,107,32,99,104,101,99,107,105,110,103,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,101,120,101,99,117,116,101,32,97,116,32,108,101,97,115,116,32,111,110,99,101,32,97,32,109,105,110,117,116,101,44,32,115,111,32,117,110,100,101,114,32,110,111,114,109,97,108,32,111,112,101,114,97,116,105,111,110,32,116,104,105,115,32,105,115,32,116,111,32,98,101,32,100,101,116,101,99,116,101,100,32,119,105,116,104,105,110,32,97,32,109,105,110,117,116,101,44,32,98,117,116,32,100,117,114,105,110,103,32,104,101,97,118,121,32,108,111,97,100,32,105,116,32,99,97,110,32,116,97,107,101,32,108,111,110,103,101,114,32,116,105,109,101,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,97,102,116,101,114,32,105,116,32,104,97,115,32,98,101,101,110,32,116,114,105,103,103,101,114,101,100,46,32,84,104,97,116,32,105,115,44,32,114,101,112,101,97,116,101,100,32,99,104,97,110,103,101,115,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,116,114,105,103,103,101,114,32,116,104,101,32,109,111,110,105,116,111,114,32,114,101,112,101,97,116,101,100,108,121,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,97,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,46,32,65,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,39,67,72,65,78,71,69,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,73,116,101,109,44,32,78,101,119,84,105,109,101,79,102,102,115,101,116,125>>]}]},{p,[],[<<119,104,101,114,101,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<44,32>>,{code,[],[<<84,121,112,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,44,32,97,110,100,32>>,{code,[],[<<78,101,119,84,105,109,101,79,102,102,115,101,116>>]},<<32,105,115,32,116,104,101,32,110,101,119,32,116,105,109,101,32,111,102,102,115,101,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,104,97,115,32,98,101,101,110,32,114,101,99,101,105,118,101,100,32,121,111,117,32,97,114,101,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,114,101,116,114,105,101,118,101,32,116,104,101,32,111,108,100,32,116,105,109,101,32,111,102,102,115,101,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,121,111,117,32,99,97,110,32,111,98,115,101,114,118,101,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]},<<32,98,101,102,111,114,101,32,121,111,117,32,103,101,116,32,116,104,101,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,46>>]}]}]},{p,[],[<<77,97,107,105,110,103,32,115,101,118,101,114,97,108,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,102,111,114,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,110,100,47,111,114,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,59,32,105,116,32,114,101,115,117,108,116,115,32,105,110,32,97,115,32,109,97,110,121,32,105,110,100,101,112,101,110,100,101,110,116,32,109,111,110,105,116,111,114,105,110,103,32,105,110,115,116,97,110,99,101,115,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,101,120,116,101,110,100,101,100,46,32,84,104,97,116,32,105,115,44,32,111,116,104,101,114,32>>,{code,[],[<<84,121,112,101>>]},<<115,32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,115,117,112,112,111,114,116,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,111,114,32,119,104,101,110,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,105,115,32,101,120,116,101,110,100,101,100,44,32,111,116,104,101,114,32,112,111,115,115,105,98,108,101,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<84,97,103>>]},<<44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,110,32,116,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,105,110,116,114,111,100,117,99,101,100,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,57,54>>,signature => [{attribute,1401,spec,{{monitor,2},[{type,1402,bounded_fun,[{type,1402,'fun',[{type,1402,product,[{atom,1402,process},{user_type,1402,monitor_process_identifier,[]}]},{var,1402,'MonitorRef'}]},[{type,1403,constraint,[{atom,1403,is_subtype},[{var,1403,'MonitorRef'},{type,1403,reference,[]}]]}]]},{type,1404,bounded_fun,[{type,1404,'fun',[{type,1404,product,[{atom,1404,port},{user_type,1404,monitor_port_identifier,[]}]},{var,1404,'MonitorRef'}]},[{type,1405,constraint,[{atom,1405,is_subtype},[{var,1405,'MonitorRef'},{type,1405,reference,[]}]]}]]},{type,1406,bounded_fun,[{type,1406,'fun',[{type,1406,product,[{atom,1406,time_offset},{atom,1406,clock_service}]},{var,1406,'MonitorRef'}]},[{type,1407,constraint,[{atom,1407,is_subtype},[{var,1407,'MonitorRef'},{type,1407,reference,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48,44,79,84,80,32,49,57,46,48>>}},{{function,monitor,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1413}],[<<109,111,110,105,116,111,114,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,111,110,105,116,111,114,95,112,111,114,116,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]}]},{p,[],[<<80,114,111,118,105,100,101,115,32,97,110,32,111,112,116,105,111,110,32,108,105,115,116,32,102,111,114,32,109,111,100,105,102,105,99,97,116,105,111,110,32,111,102,32,109,111,110,105,116,111,114,105,110,103,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,112,114,111,118,105,100,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,50>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,114,103,117,109,101,110,116,115,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,109,101,97,110,105,110,103,32,97,115,32,119,104,101,110,32,112,97,115,115,101,100,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<46,32,67,117,114,114,101,110,116,108,121,32,97,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,108,105,97,115,44,32,85,110,97,108,105,97,115,79,112,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,109,111,110,105,116,111,114,32,114,101,102,101,114,101,110,99,101,32,119,105,108,108,32,97,108,115,111,32,98,101,99,111,109,101,32,97,110,32,97,108,105,97,115,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,108,105,97,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,108,105,97,115,47,48>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<85,110,97,108,105,97,115,79,112,116>>]},<<32,100,101,116,101,114,109,105,110,101,115,32,104,111,119,32,116,104,101,32,97,108,105,97,115,32,115,104,111,117,108,100,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,46>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,112,108,105,99,105,116,95,117,110,97,108,105,97,115>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,97,110,32,101,120,112,108,105,99,105,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,97,108,105,97,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,97,108,105,97,115,47,49>>]}]},<<32,119,105,108,108,32,100,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,46>>]}]},{dt,[],[{code,[],[<<100,101,109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,101,105,116,104,101,114,32,118,105,97,32,97,110,32,101,120,112,108,105,99,105,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]}]},<<32,111,114,32,119,104,101,110,32,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,97,115,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,100,101,108,105,118,101,114,101,100,32,100,117,101,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46>>]}]},{dt,[],[{code,[],[<<114,101,112,108,121,95,100,101,109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,114,101,109,111,118,101,100,32,40,115,101,101,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114>>]},<<32,111,112,116,105,111,110,32,97,98,111,118,101,41,32,111,114,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,99,101,105,118,101,100,46,32,87,104,101,110,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,115,32,114,101,99,101,105,118,101,100,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,97,108,115,111,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,110,32,99,108,105,101,110,116,47,115,101,114,118,101,114,32,115,99,101,110,97,114,105,111,115,32,119,104,101,110,32,97,32,99,108,105,101,110,116,32,109,111,110,105,116,111,114,115,32,116,104,101,32,115,101,114,118,101,114,32,97,110,100,32,119,105,108,108,32,103,101,116,32,116,104,101,32,114,101,112,108,121,32,118,105,97,32,116,104,101,32,97,108,105,97,115,46,32,79,110,99,101,32,116,104,101,32,114,101,115,112,111,110,115,101,32,105,115,32,114,101,99,101,105,118,101,100,32,98,111,116,104,32,116,104,101,32,97,108,105,97,115,32,97,110,100,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,114,101,115,112,111,110,115,101,32,105,115,32,97,32,114,101,112,108,121,32,111,114,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46,32,78,111,116,101,32,116,104,97,116,32,105,102,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,109,111,118,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<32,66,73,70,44,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,115,116,105,108,108,32,98,101,32,108,101,102,116,32,97,99,116,105,118,101,46>>]}]}]}]},{dt,[],[{code,[],[<<123,116,97,103,44,32,85,115,101,114,68,101,102,105,110,101,100,84,97,103,125>>]}]},{dd,[],[{p,[],[<<82,101,112,108,97,99,101,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<84,97,103>>]},<<32,119,105,116,104,32>>,{code,[],[<<85,115,101,114,68,101,102,105,110,101,100,84,97,103>>]},<<32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,111,110,105,116,111,114,32,109,101,115,115,97,103,101>>]},<<32,100,101,108,105,118,101,114,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,97,32,112,114,111,99,101,115,115,44,32,116,104,101,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,116,97,103,32,105,110,32,116,104,101,32,100,111,119,110,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,114,101,112,108,97,99,101,100,32,98,121,32>>,{code,[],[<<85,115,101,114,68,101,102,105,110,101,100,84,97,103>>]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,48,55,50>>,signature => [{attribute,1413,spec,{{monitor,3},[{type,1414,bounded_fun,[{type,1414,'fun',[{type,1414,product,[{atom,1414,process},{user_type,1414,monitor_process_identifier,[]},{type,1414,list,[{user_type,1414,monitor_option,[]}]}]},{var,1414,'MonitorRef'}]},[{type,1415,constraint,[{atom,1415,is_subtype},[{var,1415,'MonitorRef'},{type,1415,reference,[]}]]}]]},{type,1416,bounded_fun,[{type,1416,'fun',[{type,1416,product,[{atom,1416,port},{user_type,1416,monitor_port_identifier,[]},{type,1416,list,[{user_type,1416,monitor_option,[]}]}]},{var,1416,'MonitorRef'}]},[{type,1417,constraint,[{atom,1417,is_subtype},[{var,1417,'MonitorRef'},{type,1417,reference,[]}]]}]]},{type,1418,bounded_fun,[{type,1418,'fun',[{type,1418,product,[{atom,1418,time_offset},{atom,1418,clock_service},{type,1418,list,[{user_type,1418,monitor_option,[]}]}]},{var,1418,'MonitorRef'}]},[{type,1419,constraint,[{atom,1419,is_subtype},[{var,1419,'MonitorRef'},{type,1419,reference,[]}]]}]]}]}}],since => <<79,84,80,32,64,79,84,80,45,49,54,55,49,56,64>>}},{{function,monitor_node,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1425}],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<77,111,110,105,116,111,114,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,110,46,32,73,102,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,46>>]},{p,[],[<<77,97,107,105,110,103,32,115,101,118,101,114,97,108,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,40,78,111,100,101,44,32,116,114,117,101,41>>]},<<32,102,111,114,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,59,32,105,116,32,114,101,115,117,108,116,115,32,105,110,32,97,115,32,109,97,110,121,32,105,110,100,101,112,101,110,100,101,110,116,32,109,111,110,105,116,111,114,105,110,103,32,105,110,115,116,97,110,99,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,102,97,105,108,115,32,111,114,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,110,111,100,101,100,111,119,110,44,32,78,111,100,101,125>>]},<<32,105,115,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,109,97,100,101,32,116,119,111,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,40,78,111,100,101,44,32,116,114,117,101,41>>]},<<32,97,110,100,32>>,{code,[],[<<78,111,100,101>>]},<<32,116,101,114,109,105,110,97,116,101,115,44,32,116,119,111,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,114,101,32,105,115,32,110,111,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32>>,{code,[],[<<78,111,100,101>>]},<<44,32,97,110,32,97,116,116,101,109,112,116,32,105,115,32,109,97,100,101,32,116,111,32,99,114,101,97,116,101,32,111,110,101,46,32,73,102,32,116,104,105,115,32,102,97,105,108,115,44,32,97,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,100,101,108,105,118,101,114,101,100,46>>]},{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,104,114,111,117,103,104,32,104,105,100,100,101,110,32,99,111,110,110,101,99,116,105,111,110,115,32,99,97,110,32,98,101,32,109,111,110,105,116,111,114,101,100,32,97,115,32,97,110,121,32,111,116,104,101,114,32,110,111,100,101,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,116,97,108,105,118,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,53,52>>,signature => [{attribute,1425,spec,{{monitor_node,2},[{type,1425,bounded_fun,[{type,1425,'fun',[{type,1425,product,[{var,1425,'Node'},{var,1425,'Flag'}]},{atom,1425,true}]},[{type,1426,constraint,[{atom,1426,is_subtype},[{var,1426,'Node'},{type,1426,node,[]}]]},{type,1427,constraint,[{atom,1427,is_subtype},[{var,1427,'Flag'},{type,1427,boolean,[]}]]}]]}]}}]}},{{function,monitor_node,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1432}],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,51>>],#{<<101,110>> => [{p,[],[<<66,101,104,97,118,101,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,110,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,50>>]}]},<<32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,97,108,108,111,119,115,32,97,110,32,101,120,116,114,97,32,111,112,116,105,111,110,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,44,32,110,97,109,101,108,121,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<46,32,84,104,105,115,32,111,112,116,105,111,110,32,97,108,108,111,119,115,32,116,104,101,32,66,73,70,32,116,111,32,119,97,105,116,32,116,104,101,32,110,111,114,109,97,108,32,110,101,116,119,111,114,107,32,99,111,110,110,101,99,116,105,111,110,32,116,105,109,101,45,111,117,116,32,102,111,114,32,116,104,101,32>>,{em,[],[<<109,111,110,105,116,111,114,101,100,32,110,111,100,101>>]},<<32,116,111,32,99,111,110,110,101,99,116,32,105,116,115,101,108,102,44,32,101,118,101,110,32,105,102,32,105,116,32,99,97,110,110,111,116,32,98,101,32,97,99,116,105,118,101,108,121,32,99,111,110,110,101,99,116,101,100,32,102,114,111,109,32,116,104,105,115,32,110,111,100,101,32,40,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,98,108,111,99,107,101,100,41,46,32,84,104,101,32,115,116,97,116,101,32,119,104,101,114,101,32,116,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,99,97,110,32,111,110,108,121,32,98,101,32,97,99,104,105,101,118,101,100,32,98,121,32,117,115,105,110,103,32,116,104,101,32,75,101,114,110,101,108,32,111,112,116,105,111,110,32>>,{code,[],[<<100,105,115,116,95,97,117,116,111,95,99,111,110,110,101,99,116,32,111,110,99,101>>]},<<46,32,73,102,32,116,104,97,116,32,111,112,116,105,111,110,32,105,115,32,110,111,116,32,117,115,101,100,44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<32,105,115,32,117,115,101,100,32,105,110,116,101,114,110,97,108,108,121,32,97,110,100,32,105,115,32,115,101,108,100,111,109,32,110,101,101,100,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,115,32,119,104,101,114,101,32,116,104,101,32,110,101,116,119,111,114,107,32,116,111,112,111,108,111,103,121,32,97,110,100,32,116,104,101,32,75,101,114,110,101,108,32,111,112,116,105,111,110,115,32,105,110,32,101,102,102,101,99,116,32,97,114,101,32,107,110,111,119,110,32,105,110,32,97,100,118,97,110,99,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,32,111,114,32,116,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,105,115,32,109,97,108,102,111,114,109,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,55,56>>,signature => [{attribute,1432,spec,{{erlang,monitor_node,3},[{type,1432,bounded_fun,[{type,1432,'fun',[{type,1432,product,[{var,1432,'Node'},{var,1432,'Flag'},{var,1432,'Options'}]},{atom,1432,true}]},[{type,1433,constraint,[{atom,1433,is_subtype},[{var,1433,'Node'},{type,1433,node,[]}]]},{type,1434,constraint,[{atom,1434,is_subtype},[{var,1434,'Flag'},{type,1434,boolean,[]}]]},{type,1435,constraint,[{atom,1435,is_subtype},[{var,1435,'Options'},{type,1435,list,[{var,1435,'Option'}]}]]},{type,1436,constraint,[{atom,1436,is_subtype},[{var,1436,'Option'},{atom,1436,allow_passive_connect}]]}]]}]}}]}},{{function,monotonic_time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1534}],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46,32,84,104,105,115,32,105,115,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,115,105,110,99,101,32,115,111,109,101,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,32,105,110,32,116,105,109,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,105,115,32,97,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,116,105,109,101,44,32,98,117,116,32>>,{em,[],[<<110,111,116>>]},<<32,97,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,116,114,105,99,116,108,121,95,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32,99,111,110,115,101,99,117,116,105,118,101,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>]},<<32,99,97,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<68,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,32,119,105,108,108,32,117,115,101,32,100,105,102,102,101,114,101,110,116,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,115,32,105,110,32,116,105,109,101,32,97,115,32,98,97,115,101,32,102,111,114,32,116,104,101,105,114,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,99,108,111,99,107,115,46,32,84,104,97,116,32,105,115,44,32,105,116,32,105,115,32>>,{em,[],[<<112,111,105,110,116,108,101,115,115>>]},<<32,99,111,109,112,97,114,105,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,115,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,46,32,68,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,32,99,97,110,32,97,108,115,111,32,112,108,97,99,101,32,116,104,105,115,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,100,105,102,102,101,114,101,110,116,32,114,101,108,97,116,105,118,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,46,32,73,116,32,99,97,110,32,98,101,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,97,32,110,101,103,97,116,105,118,101,32,118,97,108,117,101,41,44,32,116,104,101,32,112,97,115,116,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,118,97,108,117,101,41,44,32,111,114,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,122,101,114,111,41,46,32,84,104,101,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,97,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,116,97,114,116,95,116,105,109,101,41>>]}]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,48,52>>,signature => [{attribute,1534,spec,{{erlang,monotonic_time,0},[{type,1534,'fun',[{type,1534,product,[]},{type,1534,integer,[]}]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,monotonic_time,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1539}],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<83,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<44,32,104,111,119,101,118,101,114,32,111,112,116,105,109,105,122,101,100,32,102,111,114,32,99,111,109,109,111,110,108,121,32,117,115,101,100,32>>,{code,[],[<<85,110,105,116>>]},<<115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,51,56>>,signature => [{attribute,1539,spec,{{erlang,monotonic_time,1},[{type,1539,bounded_fun,[{type,1539,'fun',[{type,1539,product,[{var,1539,'Unit'}]},{type,1539,integer,[]}]},[{type,1540,constraint,[{atom,1540,is_subtype},[{var,1540,'Unit'},{user_type,1540,time_unit,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,nif_error,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1442}],[<<110,105,102,95,101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,101,120,97,99,116,108,121,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,49>>]}]},<<44,32,98,117,116,32,68,105,97,108,121,122,101,114,32,116,104,105,110,107,115,32,116,104,97,116,32,116,104,105,115,32,66,73,70,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32,97,114,98,105,116,114,97,114,121,32,116,101,114,109,46,32,87,104,101,110,32,117,115,101,100,32,105,110,32,97,32,115,116,117,98,32,102,117,110,99,116,105,111,110,32,102,111,114,32,97,32,78,73,70,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,110,111,116,32,108,111,97,100,101,100,44,32,68,105,97,108,121,122,101,114,32,100,111,101,115,32,110,111,116,32,103,101,110,101,114,97,116,101,32,102,97,108,115,101,32,119,97,114,110,105,110,103,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,53,54>>,signature => [{attribute,1442,spec,{{erlang,nif_error,1},[{type,1442,bounded_fun,[{type,1442,'fun',[{type,1442,product,[{var,1442,'Reason'}]},{type,1442,no_return,[]}]},[{type,1443,constraint,[{atom,1443,is_subtype},[{var,1443,'Reason'},{type,1443,term,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,nif_error,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1449}],[<<110,105,102,95,101,114,114,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,101,120,97,99,116,108,121,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,50>>]}]},<<44,32,98,117,116,32,68,105,97,108,121,122,101,114,32,116,104,105,110,107,115,32,116,104,97,116,32,116,104,105,115,32,66,73,70,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32,97,114,98,105,116,114,97,114,121,32,116,101,114,109,46,32,87,104,101,110,32,117,115,101,100,32,105,110,32,97,32,115,116,117,98,32,102,117,110,99,116,105,111,110,32,102,111,114,32,97,32,78,73,70,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,110,111,116,32,108,111,97,100,101,100,44,32,68,105,97,108,121,122,101,114,32,100,111,101,115,32,110,111,116,32,103,101,110,101,114,97,116,101,32,102,97,108,115,101,32,119,97,114,110,105,110,103,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,54,57>>,signature => [{attribute,1449,spec,{{erlang,nif_error,2},[{type,1449,bounded_fun,[{type,1449,'fun',[{type,1449,product,[{var,1449,'Reason'},{var,1449,'Args'}]},{type,1449,no_return,[]}]},[{type,1450,constraint,[{atom,1450,is_subtype},[{var,1450,'Reason'},{type,1450,term,[]}]]},{type,1451,constraint,[{atom,1451,is_subtype},[{var,1451,'Args'},{type,1451,list,[{type,1451,term,[]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,node,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1457}],[<<110,111,100,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,73,102,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<110,111,110,111,100,101,64,110,111,104,111,115,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,56,50>>,signature => [{attribute,1457,spec,{{node,0},[{type,1457,bounded_fun,[{type,1457,'fun',[{type,1457,product,[]},{var,1457,'Node'}]},[{type,1458,constraint,[{atom,1458,is_subtype},[{var,1458,'Node'},{type,1458,node,[]}]]}]]}]}}]}},{{function,node,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1464}],[<<110,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,111,100,101,32,119,104,101,114,101,32>>,{code,[],[<<65,114,103>>]},<<32,111,114,105,103,105,110,97,116,101,115,46,32>>,{code,[],[<<65,114,103>>]},<<32,99,97,110,32,98,101,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,97,32,112,111,114,116,46,32,73,102,32>>,{code,[],[<<65,114,103>>]},<<32,111,114,105,103,105,110,97,116,101,115,32,102,114,111,109,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,110,100,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<110,111,110,111,100,101,64,110,111,104,111,115,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,57,50>>,signature => [{attribute,1464,spec,{{node,1},[{type,1464,bounded_fun,[{type,1464,'fun',[{type,1464,product,[{var,1464,'Arg'}]},{var,1464,'Node'}]},[{type,1465,constraint,[{atom,1465,is_subtype},[{var,1465,'Arg'},{type,1465,union,[{type,1465,pid,[]},{type,1465,port,[]},{type,1465,reference,[]}]}]]},{type,1466,constraint,[{atom,1466,is_subtype},[{var,1466,'Node'},{type,1466,node,[]}]]}]]}]}}]}},{{function,nodes,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3424}],[<<110,111,100,101,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,110,111,114,109,97,108,32,99,111,110,110,101,99,116,105,111,110,115,32,40,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100,35,104,105,100,100,101,110,45,110,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<104,105,100,100,101,110,32,110,111,100,101,115>>]},<<32,97,114,101,32,110,111,116,32,108,105,115,116,101,100,41,46,32,83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,100,101,115,95,118,105,115,105,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,111,100,101,115,40,118,105,115,105,98,108,101,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,48,53>>,signature => [{attribute,3424,spec,{{nodes,0},[{type,3424,bounded_fun,[{type,3424,'fun',[{type,3424,product,[]},{var,3424,'Nodes'}]},[{type,3425,constraint,[{atom,3425,is_subtype},[{var,3425,'Nodes'},{type,3425,list,[{type,3425,node,[]}]}]]}]]}]}}]}},{{function,nodes,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2308}],[<<110,111,100,101,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,110,111,100,101,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,97,114,103,117,109,101,110,116,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,114,101,115,117,108,116,44,32,119,104,101,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,44,32,105,115,32,116,104,101,32,108,105,115,116,32,111,102,32,110,111,100,101,115,32,115,97,116,105,115,102,121,105,110,103,32,116,104,101,32,100,105,115,106,117,110,99,116,105,111,110,40,115,41,32,111,102,32,116,104,101,32,108,105,115,116,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[{code,[],[<<78,111,100,101,84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{a,[{id,<<110,111,100,101,115,95,118,105,115,105,98,108,101>>}],[]},{code,[],[<<118,105,115,105,98,108,101>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,110,111,114,109,97,108,32,99,111,110,110,101,99,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<104,105,100,100,101,110>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,104,105,100,100,101,110,32,99,111,110,110,101,99,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<99,111,110,110,101,99,116,101,100>>]}]},{dd,[],[{p,[],[<<65,108,108,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,46>>]}]},{dt,[],[{code,[],[<<116,104,105,115>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,110,111,100,101,46>>]}]},{dt,[],[{code,[],[<<107,110,111,119,110>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,116,104,97,116,32,97,114,101,32,107,110,111,119,110,32,116,111,32,116,104,105,115,32,110,111,100,101,46,32,84,104,97,116,32,105,115,44,32,99,111,110,110,101,99,116,101,100,32,110,111,100,101,115,32,97,110,100,32,110,111,100,101,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,32,108,111,99,97,116,101,100,32,111,110,32,116,104,105,115,32,110,111,100,101,46,32,84,104,101,32,115,101,116,32,111,102,32,107,110,111,119,110,32,110,111,100,101,115,32,105,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,99,97,110,32,98,101,32,100,101,108,97,121,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99,41>>]}]},<<46>>]}]}]},{p,[],[<<83,111,109,101,32,101,113,117,97,108,105,116,105,101,115,58,32>>,{code,[],[<<91,110,111,100,101,40,41,93,32,61,32,110,111,100,101,115,40,116,104,105,115,41>>]},<<44,32>>,{code,[],[<<110,111,100,101,115,40,99,111,110,110,101,99,116,101,100,41,32,61,32,110,111,100,101,115,40,91,118,105,115,105,98,108,101,44,32,104,105,100,100,101,110,93,41>>]},<<44,32,97,110,100,32>>,{code,[],[<<110,111,100,101,115,40,41,32,61,32,110,111,100,101,115,40,118,105,115,105,98,108,101,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,49,55>>,signature => [{attribute,2308,spec,{{nodes,1},[{type,2308,bounded_fun,[{type,2308,'fun',[{type,2308,product,[{var,2308,'Arg'}]},{var,2308,'Nodes'}]},[{type,2309,constraint,[{atom,2309,is_subtype},[{var,2309,'Arg'},{type,2309,union,[{var,2309,'NodeType'},{type,2309,list,[{var,2309,'NodeType'}]}]}]]},{type,2310,constraint,[{atom,2310,is_subtype},[{var,2310,'NodeType'},{type,2310,union,[{atom,2310,visible},{atom,2310,hidden},{atom,2310,connected},{atom,2310,this},{atom,2310,known}]}]]},{type,2311,constraint,[{atom,2311,is_subtype},[{var,2311,'Nodes'},{type,2311,list,[{type,2311,node,[]}]}]]}]]}]}}]}},{{function,now,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1471}],[<<110,111,119,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,105,109,101,115,116,97,109,112>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,68,111,32,110,111,116,32,117,115,101,32,105,116,46>>]}]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<84,105,109,101,32,97,110,100,32,84,105,109,101,32,67,111,114,114,101,99,116,105,111,110>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46,32,83,112,101,99,105,102,105,99,97,108,108,121,44,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,68,111,115,95,97,110,100,95,68,111,110,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,111,115,32,97,110,100,32,68,111,110,116,39,115>>]},<<32,100,101,115,99,114,105,98,101,115,32,119,104,97,116,32,116,111,32,117,115,101,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]},<<46>>]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,101,108,97,112,115,101,100,32,116,105,109,101,32,115,105,110,99,101,32,48,48,58,48,48,32,71,77,84,44,32,74,97,110,117,97,114,121,32,49,44,32,49,57,55,48,32,40,122,101,114,111,32,104,111,117,114,41,44,32,105,102,32,112,114,111,118,105,100,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,115,111,109,101,32,111,116,104,101,114,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,105,115,32,99,104,111,115,101,110,46,32,73,116,32,105,115,32,97,108,115,111,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,116,111,32,116,104,105,115,32,66,73,70,32,114,101,116,117,114,110,32,99,111,110,116,105,110,117,111,117,115,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,46,32,72,101,110,99,101,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,110,101,114,97,116,101,32,117,110,105,113,117,101,32,116,105,109,101,32,115,116,97,109,112,115,46,32,73,102,32,105,116,32,105,115,32,99,97,108,108,101,100,32,105,110,32,97,32,116,105,103,104,116,32,108,111,111,112,32,111,110,32,97,32,102,97,115,116,32,109,97,99,104,105,110,101,44,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,110,111,100,101,32,99,97,110,32,98,101,99,111,109,101,32,115,107,101,119,101,100,46>>]},{p,[],[<<67,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,116,111,32,99,104,101,99,107,32,116,104,101,32,108,111,99,97,108,32,116,105,109,101,32,111,102,32,100,97,121,32,105,102,32,116,104,101,32,116,105,109,101,45,122,111,110,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,102,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,32,105,115,32,112,114,111,112,101,114,108,121,32,99,111,110,102,105,103,117,114,101,100,46>>]}]},#{deprecated => <<101,114,108,97,110,103,58,110,111,119,47,48,32,105,115,32,100,101,112,114,101,99,97,116,101,100,59,32,115,101,101,32,116,104,101,32,34,84,105,109,101,32,97,110,100,32,84,105,109,101,32,67,111,114,114,101,99,116,105,111,110,32,105,110,32,69,114,108,97,110,103,34,32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32,69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110>>,edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,54,48>>,signature => [{attribute,1471,spec,{{now,0},[{type,1471,bounded_fun,[{type,1471,'fun',[{type,1471,product,[]},{var,1471,'Timestamp'}]},[{type,1472,constraint,[{atom,1472,is_subtype},[{var,1472,'Timestamp'},{user_type,1472,timestamp,[]}]]}]]}]}}]}},{{function,open_port,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2315}],[<<111,112,101,110,95,112,111,114,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,111,112,101,110,105,110,103,32,97,32,110,101,119,32,69,114,108,97,110,103,32,112,111,114,116,46,32,65,32,112,111,114,116,32,99,97,110,32,98,101,32,115,101,101,110,32,97,115,32,97,110,32,101,120,116,101,114,110,97,108,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<84,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,115,112,101,99,105,102,101,100,32,105,110,32>>,{code,[],[<<99,100>>]},<<44,32>>,{code,[],[<<101,110,118>>]},<<44,32>>,{code,[],[<<97,114,103,115>>]},<<44,32,97,110,100,32>>,{code,[],[<<97,114,103,48>>]},<<32,97,114,101,32,115,117,98,106,101,99,116,32,116,111,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,116,114,97,110,115,108,97,116,105,111,110,32,105,102,32,116,104,101,32,115,121,115,116,101,109,32,105,115,32,114,117,110,110,105,110,103,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,46,32,84,111,32,97,118,111,105,100,32,116,114,97,110,115,108,97,116,105,111,110,32,111,114,32,116,111,32,102,111,114,99,101,44,32,102,111,114,32,101,120,97,109,112,108,101,32,85,84,70,45,56,44,32,115,117,112,112,108,121,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,97,110,100,47,111,114,32,97,114,103,117,109,101,110,116,115,32,97,115,32,97,32,98,105,110,97,114,121,32,105,110,32,116,104,101,32,99,111,114,114,101,99,116,32,101,110,99,111,100,105,110,103,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32,116,104,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,102,105,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,40,51,41>>]}]},<<44,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,105,108,101,58,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>]}]},<<32,105,110,32,75,101,114,110,101,108,44,32,97,110,100,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,100,108,105,98,58,117,110,105,99,111,100,101,95,117,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<85,115,105,110,103,32,85,110,105,99,111,100,101,32,105,110,32,69,114,108,97,110,103>>]}]},<<32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,110,97,109,101,32,40,105,102,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,108,105,115,116,41,32,99,97,110,32,111,110,108,121,32,98,101,32,62,32,50,53,53,32,105,102,32,116,104,101,32,69,114,108,97,110,103,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,105,115,32,115,116,97,114,116,101,100,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,116,114,97,110,115,108,97,116,105,111,110,32,109,111,100,101,46,32,79,116,104,101,114,119,105,115,101,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,105,115,32,108,105,109,105,116,101,100,32,116,111,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]}]},{p,[],[{code,[],[<<80,111,114,116,78,97,109,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,97,110,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,116,111,32,98,101,32,114,117,110,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,114,117,110,115,32,111,117,116,115,105,100,101,32,116,104,101,32,69,114,108,97,110,103,32,119,111,114,107,32,115,112,97,99,101,32,117,110,108,101,115,115,32,97,110,32,69,114,108,97,110,103,32,100,114,105,118,101,114,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32,102,111,117,110,100,44,32,116,104,97,116,32,100,114,105,118,101,114,32,105,115,32,115,116,97,114,116,101,100,46,32,65,32,100,114,105,118,101,114,32,114,117,110,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,119,111,114,107,32,115,112,97,99,101,44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,104,97,116,32,105,116,32,105,115,32,108,105,110,107,101,100,32,119,105,116,104,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<70,111,114,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,44,32>>,{code,[],[<<80,65,84,72>>]},<<32,105,115,32,115,101,97,114,99,104,101,100,32,40,111,114,32,97,110,32,101,113,117,105,118,97,108,101,110,116,32,109,101,116,104,111,100,32,105,115,32,117,115,101,100,32,116,111,32,102,105,110,100,32,112,114,111,103,114,97,109,115,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,79,83,41,46,32,84,104,105,115,32,105,115,32,100,111,110,101,32,98,121,32,105,110,118,111,107,105,110,103,32,116,104,101,32,115,104,101,108,108,32,111,110,32,99,101,114,116,97,105,110,32,112,108,97,116,102,111,114,109,115,46,32,84,104,101,32,102,105,114,115,116,32,115,112,97,99,101,45,115,101,112,97,114,97,116,101,100,32,116,111,107,101,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,40,111,114,32,100,114,105,118,101,114,41,46,32,84,104,105,115,32,40,97,109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,41,32,109,97,107,101,115,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,115,117,105,116,97,98,108,101,32,102,111,114,32,114,117,110,110,105,110,103,32,112,114,111,103,114,97,109,115,32,119,105,116,104,32,115,112,97,99,101,115,32,105,110,32,102,105,108,101,110,97,109,101,115,32,111,114,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,46,32,73,102,32,115,112,97,99,101,115,32,105,110,32,101,120,101,99,117,116,97,98,108,101,32,102,105,108,101,110,97,109,101,115,32,97,114,101,32,100,101,115,105,114,101,100,44,32,117,115,101,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125>>]},<<32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,115,112,97,119,110,95,100,114,105,118,101,114,44,32,67,111,109,109,97,110,100,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,98,117,116,32,100,101,109,97,110,100,115,32,116,104,101,32,102,105,114,115,116,32,40,115,112,97,99,101,45,115,101,112,97,114,97,116,101,100,41,32,116,111,107,101,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,32,116,111,32,98,101,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,108,111,97,100,101,100,32,100,114,105,118,101,114,46,32,73,102,32,110,111,32,100,114,105,118,101,114,32,119,105,116,104,32,116,104,97,116,32,110,97,109,101,32,105,115,32,108,111,97,100,101,100,44,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,114,114,111,114,32,105,115,32,114,97,105,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<123,115,112,97,119,110,44,32,70,105,108,101,78,97,109,101,125>>]},<<44,32,98,117,116,32,111,110,108,121,32,114,117,110,115,32,101,120,116,101,114,110,97,108,32,101,120,101,99,117,116,97,98,108,101,115,46,32>>,{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,105,110,32,105,116,115,32,119,104,111,108,101,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,44,32,105,110,99,108,117,100,105,110,103,32,97,110,121,32,115,112,97,99,101,115,46,32,73,102,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,116,111,32,98,101,32,112,97,115,115,101,100,44,32,116,104,101,32>>,{code,[],[<<80,111,114,116,83,101,116,116,105,110,103,115>>]},<<32>>,{code,[],[<<97,114,103,115>>]},<<32,97,110,100,32>>,{code,[],[<<97,114,103,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,115,104,101,108,108,32,105,115,32,117,115,117,97,108,108,121,32,110,111,116,32,105,110,118,111,107,101,100,32,116,111,32,115,116,97,114,116,32,116,104,101,32,112,114,111,103,114,97,109,44,32,105,116,32,105,115,32,101,120,101,99,117,116,101,100,32,100,105,114,101,99,116,108,121,46,32>>,{code,[],[<<80,65,84,72>>]},<<32,40,111,114,32,101,113,117,105,118,97,108,101,110,116,41,32,105,115,32,110,111,116,32,115,101,97,114,99,104,101,100,46,32,84,111,32,102,105,110,100,32,97,32,112,114,111,103,114,97,109,32,105,110,32>>,{code,[],[<<80,65,84,72>>]},<<32,116,111,32,101,120,101,99,117,116,101,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,102,105,110,100,95,101,120,101,99,117,116,97,98,108,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,102,105,110,100,95,101,120,101,99,117,116,97,98,108,101,47,49>>]}]},<<46>>]},{p,[],[<<79,110,108,121,32,105,102,32,97,32,115,104,101,108,108,32,115,99,114,105,112,116,32,111,114,32>>,{code,[],[<<46,98,97,116>>]},<<32,102,105,108,101,32,105,115,32,101,120,101,99,117,116,101,100,44,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,99,111,109,109,97,110,100,32,105,110,116,101,114,112,114,101,116,101,114,32,105,115,32,105,110,118,111,107,101,100,32,105,109,112,108,105,99,105,116,108,121,44,32,98,117,116,32,116,104,101,114,101,32,105,115,32,115,116,105,108,108,32,110,111,32,99,111,109,109,97,110,100,45,97,114,103,117,109,101,110,116,32,101,120,112,97,110,115,105,111,110,32,111,114,32,105,109,112,108,105,99,105,116,32>>,{code,[],[<<80,65,84,72>>]},<<32,115,101,97,114,99,104,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,117,110,44,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,105,115,32,114,97,105,115,101,100,44,32,119,105,116,104,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,32,97,115,32,116,104,101,32,114,101,97,115,111,110,46,32,84,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,79,83,115,46,32,84,121,112,105,99,97,108,108,121,32,116,104,101,32,101,114,114,111,114,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,97,105,115,101,100,32,119,104,101,110,32,97,110,32,97,116,116,101,109,112,116,32,105,115,32,109,97,100,101,32,116,111,32,114,117,110,32,97,32,112,114,111,103,114,97,109,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,117,110,100,32,97,110,100,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,105,115,32,114,97,105,115,101,100,32,119,104,101,110,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,105,108,101,32,105,115,32,110,111,116,32,101,120,101,99,117,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,102,100,44,32,73,110,44,32,79,117,116,125>>]}]},{dd,[],[{p,[],[<<65,108,108,111,119,115,32,97,110,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,116,111,32,97,99,99,101,115,115,32,97,110,121,32,99,117,114,114,101,110,116,108,121,32,111,112,101,110,101,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,117,115,101,100,32,98,121,32,69,114,108,97,110,103,46,32,84,104,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32>>,{code,[],[<<73,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,44,32,97,110,100,32,116,104,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32>>,{code,[],[<<79,117,116>>]},<<32,102,111,114,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,46,32,73,116,32,105,115,32,111,110,108,121,32,117,115,101,100,32,102,111,114,32,118,97,114,105,111,117,115,32,115,101,114,118,101,114,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,79,83,32,40>>,{code,[],[<<115,104,101,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<117,115,101,114>>]},<<41,46,32,72,101,110,99,101,44,32,105,116,115,32,117,115,101,32,105,115,32,108,105,109,105,116,101,100,46>>]}]}]},{p,[],[{code,[],[<<80,111,114,116,83,101,116,116,105,110,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,115,101,116,116,105,110,103,115,32,102,111,114,32,116,104,101,32,112,111,114,116,46,32,84,104,101,32,118,97,108,105,100,32,115,101,116,116,105,110,103,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,97,99,107,101,116,44,32,78,125>>]}]},{dd,[],[{p,[],[<<77,101,115,115,97,103,101,115,32,97,114,101,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,101,105,114,32,108,101,110,103,116,104,44,32,115,101,110,116,32,105,110,32>>,{code,[],[<<78>>]},<<32,98,121,116,101,115,44,32,119,105,116,104,32,116,104,101,32,109,111,115,116,32,115,105,103,110,105,102,105,99,97,110,116,32,98,121,116,101,32,102,105,114,115,116,46,32,84,104,101,32,118,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<78>>]},<<32,97,114,101,32,49,44,32,50,44,32,97,110,100,32,52,46>>]}]},{dt,[],[{code,[],[<<115,116,114,101,97,109>>]}]},{dd,[],[{p,[],[<<79,117,116,112,117,116,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,119,105,116,104,111,117,116,32,112,97,99,107,101,116,32,108,101,110,103,116,104,115,46,32,65,32,117,115,101,114,45,100,101,102,105,110,101,100,32,112,114,111,116,111,99,111,108,32,109,117,115,116,32,98,101,32,117,115,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,101,120,116,101,114,110,97,108,32,111,98,106,101,99,116,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,44,32,76,125>>]}]},{dd,[],[{p,[],[<<77,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,111,110,32,97,32,112,101,114,32,108,105,110,101,32,98,97,115,105,115,46,32,69,97,99,104,32,108,105,110,101,32,40,100,101,108,105,109,105,116,101,100,32,98,121,32,116,104,101,32,79,83,45,100,101,112,101,110,100,101,110,116,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,41,32,105,115,32,100,101,108,105,118,101,114,101,100,32,105,110,32,97,32,115,105,110,103,108,101,32,109,101,115,115,97,103,101,46,32,84,104,101,32,109,101,115,115,97,103,101,32,100,97,116,97,32,102,111,114,109,97,116,32,105,115,32>>,{code,[],[<<123,70,108,97,103,44,32,76,105,110,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<101,111,108>>]},<<32,111,114,32>>,{code,[],[<<110,111,101,111,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<76,105,110,101>>]},<<32,105,115,32,116,104,101,32,100,97,116,97,32,100,101,108,105,118,101,114,101,100,32,40,119,105,116,104,111,117,116,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,41,46>>]},{p,[],[{code,[],[<<76>>]},<<32,115,112,101,99,105,102,105,101,115,32,116,104,101,32,109,97,120,105,109,117,109,32,108,105,110,101,32,108,101,110,103,116,104,32,105,110,32,98,121,116,101,115,46,32,76,105,110,101,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,105,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,105,110,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,109,101,115,115,97,103,101,44,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<110,111,101,111,108>>]},<<32,102,111,114,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,109,101,115,115,97,103,101,46,32,73,102,32,101,110,100,32,111,102,32,102,105,108,101,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,32,97,110,121,119,104,101,114,101,32,101,108,115,101,32,116,104,97,110,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,105,110,103,32,97,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,44,32,116,104,101,32,108,97,115,116,32,108,105,110,101,32,105,115,32,97,108,115,111,32,100,101,108,105,118,101,114,101,100,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<110,111,101,111,108>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,108,105,110,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<101,111,108>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<123,112,97,99,107,101,116,44,32,78,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,108,105,110,101,44,32,76,125>>]},<<32,115,101,116,116,105,110,103,115,32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,46>>]}]},{dt,[],[{code,[],[<<123,99,100,44,32,68,105,114,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,84,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,115,116,97,114,116,115,32,117,115,105,110,103,32>>,{code,[],[<<68,105,114>>]},<<32,97,115,32,105,116,115,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,46,32>>,{code,[],[<<68,105,114>>]},<<32,109,117,115,116,32,98,101,32,97,32,115,116,114,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,101,110,118,44,32,69,110,118,125>>]}]},{dd,[],[{p,[],[<<84,121,112,101,115,58>>,{br,[],[]},<<194,160,194,160>>,{code,[],[<<78,97,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,111,115,35,101,110,118,95,118,97,114,95,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<111,115,58,101,110,118,95,118,97,114,95,110,97,109,101,40,41>>]}]},{br,[],[]},<<194,160,194,160>>,{code,[],[<<86,97,108,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,111,115,35,101,110,118,95,118,97,114,95,118,97,108,117,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<111,115,58,101,110,118,95,118,97,114,95,118,97,108,117,101,40,41>>]}]},{code,[],[<<32,124,32,102,97,108,115,101>>]},{br,[],[]},<<194,160,194,160>>,{code,[],[<<69,110,118,32,61,32,91,123,78,97,109,101,44,32,86,97,108,125,93>>]}]},{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,84,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,102,32,116,104,101,32,115,116,97,114,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,101,120,116,101,110,100,101,100,32,117,115,105,110,103,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32>>,{code,[],[<<69,110,118>>]},<<46>>]},{p,[],[{code,[],[<<69,110,118>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32>>,{code,[],[<<123,78,97,109,101,44,32,86,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,97,110,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,44,32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<32,105,115,32,116,104,101,32,118,97,108,117,101,32,105,116,32,105,115,32,116,111,32,104,97,118,101,32,105,110,32,116,104,101,32,115,112,97,119,110,101,100,32,112,111,114,116,32,112,114,111,99,101,115,115,46,32,66,111,116,104,32>>,{code,[],[<<78,97,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<32,109,117,115,116,32,98,101,32,115,116,114,105,110,103,115,46,32,84,104,101,32,111,110,101,32,101,120,99,101,112,116,105,111,110,32,105,115,32>>,{code,[],[<<86,97,108>>]},<<32,98,101,105,110,103,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,105,110,32,97,110,97,108,111,103,121,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,103,101,116,101,110,118,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,103,101,116,101,110,118,47,49>>]}]},<<44,32,119,104,105,99,104,32,114,101,109,111,118,101,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,101,110,99,111,100,105,110,103,32,114,101,113,117,105,114,101,109,101,110,116,115,44,32,115,101,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,121,112,101,115,32,102,111,114,32>>,{code,[],[<<78,97,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,114,103,115,44,32,91,32,115,116,114,105,110,103,40,41,32,124,32,98,105,110,97,114,121,40,41,32,93,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,97,110,100,32,115,112,101,99,105,102,105,101,115,32,97,114,103,117,109,101,110,116,115,32,116,111,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,46,32,69,97,99,104,32,97,114,103,117,109,101,110,116,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,115,101,112,97,114,97,116,101,32,115,116,114,105,110,103,32,97,110,100,32,40,111,110,32,85,110,105,120,41,32,101,118,101,110,116,117,97,108,108,121,32,101,110,100,115,32,117,112,32,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,101,97,99,104,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,118,101,99,116,111,114,46,32,79,110,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,44,32,97,32,115,105,109,105,108,97,114,32,98,101,104,97,118,105,111,114,32,105,115,32,109,105,109,105,99,107,101,100,46>>]},{p,[],[<<84,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,110,111,116,32,101,120,112,97,110,100,101,100,32,98,121,32,116,104,101,32,115,104,101,108,108,32,98,101,102,111,114,101,32,116,104,101,121,32,97,114,101,32,115,117,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,46,32,77,111,115,116,32,110,111,116,97,98,108,121,32,116,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,102,105,108,101,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,46,32,84,111,32,101,120,112,97,110,100,32,119,105,108,100,99,97,114,100,115,32,102,111,114,32,116,104,101,32,97,114,103,117,109,101,110,116,115,44,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,102,105,108,101,108,105,98,35,119,105,108,100,99,97,114,100,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,105,108,101,108,105,98,58,119,105,108,100,99,97,114,100,47,49>>]}]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,101,118,101,110,32,105,102,32,116,104,101,32,112,114,111,103,114,97,109,32,105,115,32,97,32,85,110,105,120,32,115,104,101,108,108,32,115,99,114,105,112,116,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,116,104,101,32,115,104,101,108,108,32,117,108,116,105,109,97,116,101,108,121,32,105,115,32,105,110,118,111,107,101,100,44,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,44,32,97,110,100,32,116,104,101,32,115,99,114,105,112,116,32,105,115,32,112,114,111,118,105,100,101,100,32,119,105,116,104,32,116,104,101,32,117,110,116,111,117,99,104,101,100,32,97,114,103,117,109,101,110,116,115,46,32,79,110,32,87,105,110,100,111,119,115,44,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,105,115,32,97,108,119,97,121,115,32,117,112,32,116,111,32,116,104,101,32,112,114,111,103,114,97,109,32,105,116,115,101,108,102,44,32,116,104,101,114,101,102,111,114,101,32,116,104,105,115,32,105,115,32,110,111,116,32,97,110,32,105,115,115,117,101,46>>]},{p,[],[<<84,104,101,32,101,120,101,99,117,116,97,98,108,101,32,110,97,109,101,32,40,97,108,115,111,32,107,110,111,119,110,32,97,115,32>>,{code,[],[<<97,114,103,118,91,48,93>>]},<<41,32,105,115,32,110,111,116,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,105,115,32,108,105,115,116,46,32,84,104,101,32,112,114,111,112,101,114,32,101,120,101,99,117,116,97,98,108,101,32,110,97,109,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,117,115,101,100,32,97,115,32>>,{code,[],[<<97,114,103,118,91,48,93>>]},<<44,32,119,104,101,114,101,32,97,112,112,108,105,99,97,98,108,101,46>>]},{p,[],[<<73,102,32,121,111,117,32,101,120,112,108,105,99,105,116,108,121,32,119,97,110,116,32,116,111,32,115,101,116,32,116,104,101,32,112,114,111,103,114,97,109,32,110,97,109,101,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,118,101,99,116,111,114,44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,114,103,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,97,114,103,48,44,32,115,116,114,105,110,103,40,41,32,124,32,98,105,110,97,114,121,40,41,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,97,110,100,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,115,32,116,104,101,32,112,114,111,103,114,97,109,32,110,97,109,101,32,97,114,103,117,109,101,110,116,32,119,104,101,110,32,114,117,110,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,46,32,84,104,105,115,32,99,97,110,32,105,110,32,115,111,109,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,44,32,111,110,32,115,111,109,101,32,79,83,115,44,32,98,101,32,100,101,115,105,114,97,98,108,101,46,32,72,111,119,32,116,104,101,32,112,114,111,103,114,97,109,32,114,101,115,112,111,110,100,115,32,116,111,32,116,104,105,115,32,105,115,32,104,105,103,104,108,121,32,115,121,115,116,101,109,45,100,101,112,101,110,100,101,110,116,32,97,110,100,32,110,111,32,115,112,101,99,105,102,105,99,32,101,102,102,101,99,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,46>>]}]},{dt,[],[{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,110,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,44,32,97,110,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,99,101,115,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,101,120,105,116,115,44,32,97,32,109,101,115,115,97,103,101,32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,80,111,114,116,44,123,101,120,105,116,95,115,116,97,116,117,115,44,83,116,97,116,117,115,125,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,44,32,119,104,101,114,101,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<32,105,115,32,116,104,101,32,101,120,105,116,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,32,112,114,111,103,114,97,109,32,97,98,111,114,116,115,32,111,110,32,85,110,105,120,44,32,116,104,101,32,115,97,109,101,32,99,111,110,118,101,110,116,105,111,110,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,115,104,101,108,108,115,32,100,111,32,40,116,104,97,116,32,105,115,44,32,49,50,56,43,115,105,103,110,97,108,41,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<101,111,102>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,108,115,111,44,32,116,104,101,32,109,101,115,115,97,103,101,115,32>>,{code,[],[<<101,111,102>>]},<<32,97,110,100,32>>,{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]},<<32,97,112,112,101,97,114,32,105,110,32,97,110,32,117,110,115,112,101,99,105,102,105,101,100,32,111,114,100,101,114,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,99,108,111,115,101,115,32,105,116,115,32>>,{code,[],[<<115,116,100,111,117,116>>]},<<32,119,105,116,104,111,117,116,32,101,120,105,116,105,110,103,44,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]},<<32,100,111,101,115,32,110,111,116,32,119,111,114,107,46>>]}]},{dt,[],[{code,[],[<<117,115,101,95,115,116,100,105,111>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,73,116,32,97,108,108,111,119,115,32,116,104,101,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,32,97,110,100,32,111,117,116,112,117,116,32,40,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,48,32,97,110,100,32,49,41,32,111,102,32,116,104,101,32,115,112,97,119,110,101,100,32,40,85,110,105,120,41,32,112,114,111,99,101,115,115,32,102,111,114,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,69,114,108,97,110,103,46>>]}]},{dt,[],[{code,[],[<<110,111,117,115,101,95,115,116,100,105,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,112,111,115,105,116,101,32,111,102,32>>,{code,[],[<<117,115,101,95,115,116,100,105,111>>]},<<46,32,73,116,32,117,115,101,115,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,51,32,97,110,100,32,52,32,102,111,114,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,69,114,108,97,110,103,46>>]}]},{dt,[],[{code,[],[<<115,116,100,101,114,114,95,116,111,95,115,116,100,111,117,116>>]}]},{dd,[],[{p,[],[<<65,102,102,101,99,116,115,32,112,111,114,116,115,32,116,111,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,46,32,84,104,101,32,101,120,101,99,117,116,101,100,32,112,114,111,103,114,97,109,32,103,101,116,115,32,105,116,115,32,115,116,97,110,100,97,114,100,32,101,114,114,111,114,32,102,105,108,101,32,114,101,100,105,114,101,99,116,101,100,32,116,111,32,105,116,115,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,32,102,105,108,101,46,32>>,{code,[],[<<115,116,100,101,114,114,95,116,111,95,115,116,100,111,117,116>>]},<<32,97,110,100,32>>,{code,[],[<<110,111,117,115,101,95,115,116,100,105,111>>]},<<32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,46>>]}]},{dt,[],[{code,[],[<<111,118,101,114,108,97,112,112,101,100,95,105,111>>]}]},{dd,[],[{p,[],[<<65,102,102,101,99,116,115,32,112,111,114,116,115,32,116,111,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,32,111,110,32,87,105,110,100,111,119,115,32,111,110,108,121,46,32,84,104,101,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,32,97,110,100,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,32,104,97,110,100,108,101,115,32,111,102,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,97,114,101,44,32,105,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,117,112,112,108,105,101,100,44,32,111,112,101,110,101,100,32,119,105,116,104,32,102,108,97,103,32>>,{code,[],[<<70,73,76,69,95,70,76,65,71,95,79,86,69,82,76,65,80,80,69,68>>]},<<44,32,115,111,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,99,97,110,32,40,97,110,100,32,109,117,115,116,41,32,100,111,32,111,118,101,114,108,97,112,112,101,100,32,73,47,79,32,111,110,32,105,116,115,32,115,116,97,110,100,97,114,100,32,104,97,110,100,108,101,115,46,32,84,104,105,115,32,105,115,32,110,111,116,32,110,111,114,109,97,108,108,121,32,116,104,101,32,99,97,115,101,32,102,111,114,32,115,105,109,112,108,101,32,112,111,114,116,32,112,114,111,103,114,97,109,115,44,32,98,117,116,32,97,110,32,111,112,116,105,111,110,32,111,102,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,101,120,112,101,114,105,101,110,99,101,100,32,87,105,110,100,111,119,115,32,112,114,111,103,114,97,109,109,101,114,46,32>>,{em,[],[<<79,110,32,97,108,108,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,105,108,101,110,116,108,121,32,100,105,115,99,97,114,100,101,100,46>>]}]}]},{dt,[],[{code,[],[<<105,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,102,111,114,32,105,110,112,117,116,46>>]}]},{dt,[],[{code,[],[<<111,117,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,102,111,114,32,111,117,116,112,117,116,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,32,73,47,79,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,115,32,97,115,32,111,112,112,111,115,101,100,32,116,111,32,108,105,115,116,115,32,111,102,32,98,121,116,101,115,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,99,108,111,115,101,100,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,32,97,110,100,32,100,111,101,115,32,110,111,116,32,112,114,111,100,117,99,101,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,46,32,73,110,115,116,101,97,100,44,32,105,116,32,114,101,109,97,105,110,115,32,111,112,101,110,32,97,110,100,32,97,32>>,{code,[],[<<123,80,111,114,116,44,32,101,111,102,125>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,104,111,108,100,105,110,103,32,116,104,101,32,112,111,114,116,46>>]}]},{dt,[],[{code,[],[<<104,105,100,101>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,114,117,110,110,105,110,103,32,111,110,32,87,105,110,100,111,119,115,44,32,115,117,112,112,114,101,115,115,101,115,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,101,119,32,99,111,110,115,111,108,101,32,119,105,110,100,111,119,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,46,32,40,84,104,105,115,32,111,112,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,111,110,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,46,41>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,105,115,109,44,32,66,111,111,108,101,97,110,125>>]}]},{dd,[],[{a,[{id,<<111,112,101,110,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>}],[]},{p,[],[<<83,101,116,115,32,115,99,104,101,100,117,108,101,114,32,104,105,110,116,32,102,111,114,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,115,99,104,101,100,117,108,101,115,32,112,111,114,116,32,116,97,115,107,115,59,32,119,104,101,110,32,100,111,105,110,103,32,115,111,44,32,105,116,32,105,109,112,114,111,118,101,115,32,112,97,114,97,108,108,101,108,105,115,109,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,116,114,105,101,115,32,116,111,32,112,101,114,102,111,114,109,32,112,111,114,116,32,116,97,115,107,115,32,105,109,109,101,100,105,97,116,101,108,121,44,32,105,109,112,114,111,118,105,110,103,32,108,97,116,101,110,99,121,32,97,116,32,116,104,101,32,101,120,112,101,110,115,101,32,111,102,32,112,97,114,97,108,108,101,108,105,115,109,46,32,84,104,101,32,100,101,102,97,117,108,116,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,112,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,112,112>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,98,117,115,121,95,108,105,109,105,116,115,95,112,111,114,116,44,32,123,76,111,119,44,32,72,105,103,104,125,32,124,32,100,105,115,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,108,105,109,105,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,111,110,116,114,111,108,108,105,110,103,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,32,111,102,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,112,111,114,116,115,32,105,110,116,101,114,110,97,108,32,111,117,116,112,117,116,32,113,117,101,117,101,32,115,105,122,101,32,98,101,99,111,109,101,115,32,108,97,114,103,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<72,105,103,104>>]},<<32,98,121,116,101,115,44,32,105,116,32,101,110,116,101,114,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,105,116,32,98,101,99,111,109,101,115,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<76,111,119>>]},<<32,98,121,116,101,115,32,105,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,116,104,101,32,112,111,114,116,32,105,115,32,105,110,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,44,32,112,114,111,99,101,115,115,101,115,32,115,101,110,100,105,110,103,32,99,111,109,109,97,110,100,115,32,116,111,32,105,116,32,119,105,108,108,32,98,101,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,67,111,109,109,97,110,100,115,32,97,114,101,32,105,110,32,116,104,105,115,32,99,111,110,116,101,120,116,32,101,105,116,104,101,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,91,50,44,51,93>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<76,111,119>>]},<<32,108,105,109,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,102,32,105,116,32,105,115,32,115,101,116,32,108,97,114,103,101,114,32,116,104,101,110,32>>,{code,[],[<<72,105,103,104>>]},<<46,32,86,97,108,105,100,32,114,97,110,103,101,32,111,102,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<76,111,119>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,115,32>>,{code,[],[<<91,49,44,32,40,49,32,98,115,108,32,40,56,42,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,119,111,114,100,115,105,122,101,41,41,41,45,50,93>>]},<<46,32,73,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,116,104,101,32,112,111,114,116,32,119,105,108,108,32,110,101,118,101,114,32,101,110,116,101,114,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,115,32,97,114,101,32>>,{code,[],[<<76,111,119,32,61,32,52,48,57,54>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104,32,61,32,56,49,57,50>>]},<<46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,118,97,108,105,100,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,32,40,112,111,114,116,32,112,114,111,103,114,97,109,41,32,98,121,32,111,112,101,110,105,110,103,32,116,104,101,32,115,112,97,119,110,32,100,114,105,118,101,114,32,97,110,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32>>,{code,[],[<<102,100>>]},<<32,100,114,105,118,101,114,46,32,84,104,105,115,32,111,112,116,105,111,110,32,119,105,108,108,32,99,97,117,115,101,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,111,112,101,110,105,110,103,32,111,116,104,101,114,32,100,114,105,118,101,114,115,46>>]}]},{dt,[],[{code,[],[<<123,98,117,115,121,95,108,105,109,105,116,115,95,109,115,103,113,44,32,123,76,111,119,44,32,72,105,103,104,125,32,124,32,100,105,115,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,108,105,109,105,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,111,110,116,114,111,108,108,105,110,103,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,32,111,102,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,112,111,114,116,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,115,105,122,101,32,98,101,99,111,109,101,115,32,108,97,114,103,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<72,105,103,104>>]},<<32,98,121,116,101,115,32,105,116,32,101,110,116,101,114,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,105,116,32,98,101,99,111,109,101,115,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<76,111,119>>]},<<32,98,121,116,101,115,32,105,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,115,32,105,110,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,44,32,112,114,111,99,101,115,115,101,115,32,115,101,110,100,105,110,103,32,99,111,109,109,97,110,100,115,32,116,111,32,105,116,32,119,105,108,108,32,98,101,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,67,111,109,109,97,110,100,115,32,97,114,101,32,105,110,32,116,104,105,115,32,99,111,110,116,101,120,116,32,101,105,116,104,101,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,91,50,44,51,93>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<76,111,119>>]},<<32,108,105,109,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,102,32,105,116,32,105,115,32,115,101,116,32,108,97,114,103,101,114,32,116,104,101,110,32>>,{code,[],[<<72,105,103,104>>]},<<46,32,86,97,108,105,100,32,114,97,110,103,101,32,111,102,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<76,111,119>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,115,32>>,{code,[],[<<91,49,44,32,40,49,32,98,115,108,32,40,56,42,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,119,111,114,100,115,105,122,101,41,41,41,45,50,93>>]},<<46,32,73,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,110,101,118,101,114,32,101,110,116,101,114,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,105,102,32,116,104,101,32,100,114,105,118,101,114,32,115,116,97,116,105,99,97,108,108,121,32,104,97,115,32,100,105,115,97,98,108,101,100,32,116,104,101,32,117,115,101,32,111,102,32,116,104,105,115,32,102,101,97,116,117,114,101,44,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,119,105,108,108,32,98,101,32,114,97,105,115,101,100,32,117,110,108,101,115,115,32,116,104,105,115,32,111,112,116,105,111,110,32,97,108,115,111,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<100,105,115,97,98,108,101>>]},<<32,111,114,32,110,111,116,32,112,97,115,115,101,100,32,97,116,32,97,108,108,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,115,32,97,114,101,32>>,{code,[],[<<76,111,119,32,61,32,52,48,57,54>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104,32,61,32,56,49,57,50>>]},<<32,117,110,108,101,115,115,32,116,104,101,32,100,114,105,118,101,114,32,105,116,115,101,108,102,32,100,111,101,115,32,109,111,100,105,102,105,99,97,116,105,111,110,115,32,111,102,32,116,104,101,115,101,32,118,97,108,117,101,115,46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,116,104,101,32,100,114,105,118,101,114,32,109,105,103,104,116,32,102,97,105,108,32,105,102,32,105,116,32,97,108,115,111,32,97,100,106,117,115,116,32,116,104,101,115,101,32,108,105,109,105,116,115,32,98,121,32,105,116,115,101,108,102,32,97,110,100,32,121,111,117,32,104,97,118,101,32,100,105,115,97,98,108,101,100,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]},{p,[],[<<84,104,101,32,115,112,97,119,110,32,100,114,105,118,101,114,32,40,117,115,101,100,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,41,32,97,110,100,32,116,104,101,32>>,{code,[],[<<102,100>>]},<<32,100,114,105,118,101,114,32,100,111,32,110,111,116,32,100,105,115,97,98,108,101,32,116,104,105,115,32,102,101,97,116,117,114,101,32,97,110,100,32,100,111,32,110,111,116,32,97,100,106,117,115,116,32,116,104,101,115,101,32,108,105,109,105,116,115,32,98,121,32,116,104,101,109,115,101,108,118,101,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,101,114,108,95,100,114,118,95,98,117,115,121,95,109,115,103,113,95,108,105,109,105,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,100,114,118,95,98,117,115,121,95,109,115,103,113,95,108,105,109,105,116,115,40,41>>]}]},<<46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<115,116,114,101,97,109>>]},<<32,102,111,114,32,97,108,108,32,112,111,114,116,32,116,121,112,101,115,32,97,110,100,32>>,{code,[],[<<117,115,101,95,115,116,100,105,111>>]},<<32,102,111,114,32,115,112,97,119,110,101,100,32,112,111,114,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32,105,102,32,116,104,101,32,112,111,114,116,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,44,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32>>,{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]},<<44,32,111,114,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,32,116,104,97,116,32,109,111,115,116,32,99,108,111,115,101,108,121,32,100,101,115,99,114,105,98,101,115,32,116,104,101,32,101,114,114,111,114,44,32,111,114,32>>,{code,[],[<<101,105,110,118,97,108>>]},<<32,105,102,32,110,111,32,80,79,83,73,88,32,99,111,100,101,32,105,115,32,97,112,112,114,111,112,114,105,97,116,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<66,97,100,32,105,110,112,117,116,32,97,114,103,117,109,101,110,116,115,32,116,111,32>>,{code,[],[<<111,112,101,110,95,112,111,114,116>>]},<<46>>]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[<<65,108,108,32,97,118,97,105,108,97,98,108,101,32,112,111,114,116,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,32,97,114,101,32,105,110,32,117,115,101,46>>]},{dt,[],[{code,[],[<<101,110,111,109,101,109>>]}]},{dd,[],[<<78,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,32,116,111,32,99,114,101,97,116,101,32,116,104,101,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<101,97,103,97,105,110>>]}]},{dd,[],[<<78,111,32,109,111,114,101,32,97,118,97,105,108,97,98,108,101,32,79,83,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<101,110,97,109,101,116,111,111,108,111,110,103>>]}]},{dd,[],[<<84,111,111,32,108,111,110,103,32,101,120,116,101,114,110,97,108,32,99,111,109,109,97,110,100,46>>]},{dt,[],[{code,[],[<<101,109,102,105,108,101>>]}]},{dd,[],[<<78,111,32,109,111,114,101,32,97,118,97,105,108,97,98,108,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,40,102,111,114,32,116,104,101,32,79,83,32,112,114,111,99,101,115,115,32,116,104,97,116,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,32,114,117,110,115,32,105,110,41,46>>]},{dt,[],[{code,[],[<<101,110,102,105,108,101>>]}]},{dd,[],[<<70,117,108,108,32,102,105,108,101,32,116,97,98,108,101,32,40,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,79,83,41,46>>]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{code,[],[<<67,111,109,109,97,110,100>>]},<<32,115,112,101,99,105,102,105,101,100,32,105,110,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125>>]},<<32,100,111,101,115,32,110,111,116,32,112,111,105,110,116,32,111,117,116,32,97,110,32,101,120,101,99,117,116,97,98,108,101,32,102,105,108,101,46>>]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,115,112,101,99,105,102,105,101,100,32,105,110,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,100,111,101,115,32,110,111,116,32,112,111,105,110,116,32,111,117,116,32,97,110,32,101,120,105,115,116,105,110,103,32,102,105,108,101,46>>]}]},{p,[],[<<68,117,114,105,110,103,32,117,115,101,32,111,102,32,97,32,112,111,114,116,32,111,112,101,110,101,100,32,117,115,105,110,103,32>>,{code,[],[<<123,115,112,97,119,110,44,32,78,97,109,101,125>>]},<<44,32>>,{code,[],[<<123,115,112,97,119,110,95,100,114,105,118,101,114,44,32,78,97,109,101,125>>]},<<44,32,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,78,97,109,101,125>>]},<<44,32,101,114,114,111,114,115,32,97,114,105,115,105,110,103,32,119,104,101,110,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,105,116,32,97,114,101,32,114,101,112,111,114,116,101,100,32,116,111,32,116,104,101,32,111,119,110,105,110,103,32,112,114,111,99,101,115,115,32,117,115,105,110,103,32,115,105,103,110,97,108,115,32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,80,111,114,116,44,32,80,111,115,105,120,67,111,100,101,125>>]},<<46,32,70,111,114,32,116,104,101,32,112,111,115,115,105,98,108,101,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<80,111,115,105,120,67,111,100,101>>]},<<44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,102,105,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,40,51,41>>]}]},<<46>>]},{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,111,114,116,115,32,116,104,97,116,32,99,97,110,32,98,101,32,111,112,101,110,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,109,97,120,95,112,111,114,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,81>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,56,57>>,signature => [{attribute,2315,spec,{{open_port,2},[{type,2315,bounded_fun,[{type,2315,'fun',[{type,2315,product,[{var,2315,'PortName'},{var,2315,'PortSettings'}]},{type,2315,port,[]}]},[{type,2316,constraint,[{atom,2316,is_subtype},[{var,2316,'PortName'},{type,2316,union,[{type,2316,tuple,[{atom,2316,spawn},{ann_type,2316,[{var,2316,'Command'},{type,2316,union,[{type,2316,string,[]},{type,2316,binary,[]}]}]}]},{type,2317,tuple,[{atom,2317,spawn_driver},{ann_type,2317,[{var,2317,'Command'},{type,2317,union,[{type,2317,string,[]},{type,2317,binary,[]}]}]}]},{type,2318,tuple,[{atom,2318,spawn_executable},{ann_type,2318,[{var,2318,'FileName'},{remote_type,2318,[{atom,2318,file},{atom,2318,name_all},[]]}]}]},{type,2319,tuple,[{atom,2319,fd},{ann_type,2319,[{var,2319,'In'},{type,2319,non_neg_integer,[]}]},{ann_type,2319,[{var,2319,'Out'},{type,2319,non_neg_integer,[]}]}]}]}]]},{type,2320,constraint,[{atom,2320,is_subtype},[{var,2320,'PortSettings'},{type,2320,list,[{var,2320,'Opt'}]}]]},{type,2321,constraint,[{atom,2321,is_subtype},[{var,2321,'Opt'},{type,2321,union,[{type,2321,tuple,[{atom,2321,packet},{ann_type,2321,[{var,2321,'N'},{type,2321,union,[{integer,2321,1},{integer,2321,2},{integer,2321,4}]}]}]},{atom,2322,stream},{type,2323,tuple,[{atom,2323,line},{ann_type,2323,[{var,2323,'L'},{type,2323,non_neg_integer,[]}]}]},{type,2324,tuple,[{atom,2324,cd},{ann_type,2324,[{var,2324,'Dir'},{type,2324,union,[{type,2324,string,[]},{type,2324,binary,[]}]}]}]},{type,2325,tuple,[{atom,2325,env},{ann_type,2325,[{var,2325,'Env'},{type,2325,list,[{type,2325,tuple,[{ann_type,2325,[{var,2325,'Name'},{remote_type,2325,[{atom,2325,os},{atom,2325,env_var_name},[]]}]},{ann_type,2325,[{var,2325,'Val'},{type,2325,union,[{remote_type,2325,[{atom,2325,os},{atom,2325,env_var_value},[]]},{atom,2325,false}]}]}]}]}]}]},{type,2326,tuple,[{atom,2326,args},{type,2326,list,[{type,2326,union,[{type,2326,string,[]},{type,2326,binary,[]}]}]}]},{type,2327,tuple,[{atom,2327,arg0},{type,2327,union,[{type,2327,string,[]},{type,2327,binary,[]}]}]},{atom,2328,exit_status},{atom,2329,use_stdio},{atom,2330,nouse_stdio},{atom,2331,stderr_to_stdout},{atom,2332,in},{atom,2333,out},{atom,2334,binary},{atom,2335,eof},{type,2336,tuple,[{atom,2336,parallelism},{ann_type,2336,[{var,2336,'Boolean'},{type,2336,boolean,[]}]}]},{atom,2337,hide},{type,2338,tuple,[{atom,2338,busy_limits_port},{type,2338,union,[{type,2338,tuple,[{type,2338,non_neg_integer,[]},{type,2338,non_neg_integer,[]}]},{atom,2338,disabled}]}]},{type,2339,tuple,[{atom,2339,busy_limits_msgq},{type,2339,union,[{type,2339,tuple,[{type,2339,non_neg_integer,[]},{type,2339,non_neg_integer,[]}]},{atom,2339,disabled}]}]}]}]]}]]}]}}]}},{{function,phash,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1477}],[<<112,104,97,115,104,47,50>>],#{<<101,110>> => [{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,104,97,115,104,50,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,50,47,50>>]}]},<<32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,102,111,114,32,110,101,119,32,99,111,100,101,46,32,78,111,116,101,32,116,104,97,116,32>>,{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,40,88,44,78,41>>]},<<32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,121,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,50,40,88,44,78,41>>]}]}]},{p,[],[<<80,111,114,116,97,98,108,101,32,104,97,115,104,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,104,97,115,104,32,102,111,114,32,116,104,101,32,115,97,109,101,32,69,114,108,97,110,103,32,116,101,114,109,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,109,97,99,104,105,110,101,32,97,114,99,104,105,116,101,99,116,117,114,101,32,97,110,100,32,69,82,84,83,32,118,101,114,115,105,111,110,32,40,116,104,101,32,66,73,70,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,52,46,57,46,49,46,49,41,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,97,32,104,97,115,104,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<84,101,114,109>>]},<<32,119,105,116,104,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<49,46,46,82,97,110,103,101>>]},<<46,32,84,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<82,97,110,103,101>>]},<<32,105,115,32,50,94,51,50,46>>]}]},#{deprecated => <<101,114,108,97,110,103,58,112,104,97,115,104,47,50,32,105,115,32,100,101,112,114,101,99,97,116,101,100,59,32,117,115,101,32,101,114,108,97,110,103,58,112,104,97,115,104,50,47,50,32,105,110,115,116,101,97,100>>,edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,55,57,53>>,signature => [{attribute,1477,spec,{{erlang,phash,2},[{type,1477,bounded_fun,[{type,1477,'fun',[{type,1477,product,[{var,1477,'Term'},{var,1477,'Range'}]},{var,1477,'Hash'}]},[{type,1478,constraint,[{atom,1478,is_subtype},[{var,1478,'Term'},{type,1478,term,[]}]]},{type,1479,constraint,[{atom,1479,is_subtype},[{var,1479,'Range'},{type,1479,pos_integer,[]}]]},{type,1480,constraint,[{atom,1480,is_subtype},[{var,1480,'Hash'},{type,1480,pos_integer,[]}]]}]]}]}}]}},{{function,phash2,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1492}],[<<112,104,97,115,104,50,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,56,49,55>>,equiv => {function,phash2,1},signature => [{attribute,1492,spec,{{erlang,phash2,2},[{type,1492,bounded_fun,[{type,1492,'fun',[{type,1492,product,[{var,1492,'Term'},{var,1492,'Range'}]},{var,1492,'Hash'}]},[{type,1493,constraint,[{atom,1493,is_subtype},[{var,1493,'Term'},{type,1493,term,[]}]]},{type,1494,constraint,[{atom,1494,is_subtype},[{var,1494,'Range'},{type,1494,pos_integer,[]}]]},{type,1495,constraint,[{atom,1495,is_subtype},[{var,1495,'Hash'},{type,1495,non_neg_integer,[]}]]}]]}]}}]}},{{function,phash2,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1485}],[<<112,104,97,115,104,50,47,49>>],#{<<101,110>> => [{p,[],[<<80,111,114,116,97,98,108,101,32,104,97,115,104,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,104,97,115,104,32,102,111,114,32,116,104,101,32,115,97,109,101,32,69,114,108,97,110,103,32,116,101,114,109,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,109,97,99,104,105,110,101,32,97,114,99,104,105,116,101,99,116,117,114,101,32,97,110,100,32,69,82,84,83,32,118,101,114,115,105,111,110,32,40,116,104,101,32,66,73,70,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,53,46,50,41,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,97,32,104,97,115,104,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<84,101,114,109>>]},<<32,119,105,116,104,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<48,46,46,82,97,110,103,101,45,49>>]},<<46,32,84,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<82,97,110,103,101>>]},<<32,105,115,32,50,94,51,50,46,32,87,104,101,110,32,119,105,116,104,111,117,116,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<82,97,110,103,101>>]},<<44,32,97,32,118,97,108,117,101,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,46,46,50,94,50,55,45,49,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,97,108,119,97,121,115,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,104,97,115,104,105,110,103,32,116,101,114,109,115,46,32,73,116,32,100,105,115,116,114,105,98,117,116,101,115,32,115,109,97,108,108,32,105,110,116,101,103,101,114,115,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<112,104,97,115,104,47,50>>]},<<44,32,97,110,100,32,105,116,32,105,115,32,102,97,115,116,101,114,32,102,111,114,32,98,105,103,110,117,109,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<48,46,46,82,97,110,103,101,45,49>>]},<<32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,114,97,110,103,101,32,111,102,32>>,{code,[],[<<112,104,97,115,104,47,50>>]},<<44,32,119,104,105,99,104,32,105,115,32>>,{code,[],[<<49,46,46,82,97,110,103,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,56,49,55>>,signature => [{attribute,1485,spec,{{erlang,phash2,1},[{type,1485,bounded_fun,[{type,1485,'fun',[{type,1485,product,[{var,1485,'Term'}]},{var,1485,'Hash'}]},[{type,1486,constraint,[{atom,1486,is_subtype},[{var,1486,'Term'},{type,1486,term,[]}]]},{type,1487,constraint,[{atom,1487,is_subtype},[{var,1487,'Hash'},{type,1487,non_neg_integer,[]}]]}]]}]}}]}},{{function,pid_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1500}],[<<112,105,100,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,112,105,100,95,116,111,95,108,105,115,116,40,115,101,108,102,40,41,41,46,10,34,60,48,46,56,53,46,48,62,34>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,108,95,100,105,115,116,95,112,114,111,116,111,99,111,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,114,101,97,116,105,111,110>>]},<<32,102,111,114,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,105,110,32,100,105,102,102,101,114,101,110,116,32,105,110,99,97,114,110,97,116,105,111,110,115,32,111,102,32,97,32,110,111,100,101,32,119,105,116,104,32,97,32,115,112,101,99,105,102,105,99,32,110,97,109,101,32,99,97,110,32,103,101,116,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,56,52,50>>,signature => [{attribute,1500,spec,{{pid_to_list,1},[{type,1500,bounded_fun,[{type,1500,'fun',[{type,1500,product,[{var,1500,'Pid'}]},{type,1500,string,[]}]},[{type,1501,constraint,[{atom,1501,is_subtype},[{var,1501,'Pid'},{type,1501,pid,[]}]]}]]}]}}]}},{{function,port_call,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3594}],[<<112,111,114,116,95,99,97,108,108,47,51>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,97,108,108,32,116,111,32,97,32,112,111,114,116,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,97,110,100,32>>,{code,[],[<<68,97,116,97>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,44,32,116,104,97,116,32,105,115,44,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,78,111,116,32,97,108,108,32,112,111,114,116,32,100,114,105,118,101,114,115,32,115,117,112,112,111,114,116,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]},{p,[],[{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,114,101,102,101,114,114,105,110,103,32,116,111,32,97,32,100,114,105,118,101,114,46>>]},{p,[],[{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,119,104,105,99,104,32,105,115,32,112,97,115,115,101,100,32,111,110,32,116,111,32,116,104,101,32,100,114,105,118,101,114,46>>]},{p,[],[{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,46,32,84,104,105,115,32,100,97,116,97,32,105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,98,105,110,97,114,121,32,116,101,114,109,32,102,111,114,109,97,116,32,97,110,100,32,115,101,110,116,32,116,111,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,101,114,109,32,102,114,111,109,32,116,104,101,32,100,114,105,118,101,114,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,100,97,116,97,32,97,108,115,111,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,100,111,101,115,32,110,111,116,32,102,105,116,32,105,110,32,97,32,51,50,45,98,105,116,32,105,110,116,101,103,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,115,111,32,100,101,99,105,100,101,115,32,102,111,114,32,97,110,121,32,114,101,97,115,111,110,32,40,112,114,111,98,97,98,108,121,32,115,111,109,101,116,104,105,110,103,32,119,114,111,110,103,32,119,105,116,104,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<41,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,99,97,108,108,32>>,{code,[],[<<112,111,114,116,95,99,97,108,108>>]},<<32,119,105,116,104,32,97,110,32,117,110,107,110,111,119,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,101,120,112,101,99,116,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,115,117,112,112,108,105,101,100,32,97,114,103,117,109,101,110,116,115,46>>]}]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,56,54,49>>,signature => [{attribute,3594,spec,{{erlang,port_call,3},[{type,3594,bounded_fun,[{type,3594,'fun',[{type,3594,product,[{var,3594,'Port'},{var,3594,'Operation'},{var,3594,'Data'}]},{type,3594,term,[]}]},[{type,3595,constraint,[{atom,3595,is_subtype},[{var,3595,'Port'},{type,3595,union,[{type,3595,port,[]},{type,3595,atom,[]}]}]]},{type,3596,constraint,[{atom,3596,is_subtype},[{var,3596,'Operation'},{type,3596,integer,[]}]]},{type,3597,constraint,[{atom,3597,is_subtype},[{var,3597,'Data'},{type,3597,term,[]}]]}]]}]}}]}},{{function,port_close,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3555}],[<<112,111,114,116,95,99,108,111,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,108,111,115,101,115,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,82,111,117,103,104,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,99,108,111,115,101,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,40,115,101,101,32,98,101,108,111,119,41,44,32,98,101,105,110,103,32,115,121,110,99,104,114,111,110,111,117,115,44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,114,101,112,108,121,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,108,111,115,101,100,125>>]},<<46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,99,108,111,115,101,32,97,32,112,111,114,116,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<44,32,110,111,116,32,111,110,108,121,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,41,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<32,114,101,116,117,114,110,115,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,99,108,111,115,101,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32,112,111,114,116,32,114,101,112,108,105,101,115,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,108,111,115,101,100,125>>]},<<32,119,104,101,110,32,97,108,108,32,98,117,102,102,101,114,115,32,104,97,118,101,32,98,101,101,110,32,102,108,117,115,104,101,100,32,97,110,100,32,116,104,101,32,112,111,114,116,32,114,101,97,108,108,121,32,99,108,111,115,101,115,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,99,108,111,115,101,32,97,32,112,111,114,116,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,99,108,111,115,101,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,98,117,116,32,116,104,101,32,114,101,112,108,121,32,97,108,119,97,121,115,32,103,111,101,115,32,116,111,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,99,108,111,115,101,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,49,51>>,signature => [{attribute,3555,spec,{{port_close,1},[{type,3555,bounded_fun,[{type,3555,'fun',[{type,3555,product,[{var,3555,'Port'}]},{atom,3555,true}]},[{type,3556,constraint,[{atom,3556,is_subtype},[{var,3556,'Port'},{type,3556,union,[{type,3556,port,[]},{type,3556,atom,[]}]}]]}]]}]}}]}},{{function,port_command,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3513}],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,46,32,83,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,97,110,100,32,98,101,105,110,103,32,115,121,110,99,104,114,111,110,111,117,115,32,40,115,101,101,32,98,101,108,111,119,41,46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]},<<44,32,110,111,116,32,111,110,108,121,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,41,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,116,104,101,32,100,97,116,97,32,109,101,115,115,97,103,101,32,100,105,115,97,112,112,101,97,114,115,32,119,105,116,104,111,117,116,32,97,32,115,111,117,110,100,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,111,112,101,110,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46,32,84,104,101,32,112,111,114,116,32,111,119,110,101,114,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<32,97,108,115,111,32,105,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,110,100,32,116,111,32,97,32,112,111,114,116,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,98,117,115,121,32,97,110,121,32,109,111,114,101,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]}]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,110,32,117,110,107,110,111,119,110,32,112,111,114,116,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,100,97,116,97,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,53,51>>,signature => [{attribute,3513,spec,{{port_command,2},[{type,3513,bounded_fun,[{type,3513,'fun',[{type,3513,product,[{var,3513,'Port'},{var,3513,'Data'}]},{atom,3513,true}]},[{type,3514,constraint,[{atom,3514,is_subtype},[{var,3514,'Port'},{type,3514,union,[{type,3514,port,[]},{type,3514,atom,[]}]}]]},{type,3515,constraint,[{atom,3515,is_subtype},[{var,3515,'Data'},{type,3515,iodata,[]}]]}]]}]}}]}},{{function,port_command,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3526}],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,46,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,40,80,111,114,116,44,32,68,97,116,97,44,32,91,93,41>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,40,80,111,114,116,44,32,68,97,116,97,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,97,98,111,114,116,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,98,117,115,121,32,97,110,121,109,111,114,101,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,111,114,99,101>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,102,111,114,99,101,100,32,116,104,114,111,117,103,104,46,32,84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32,116,104,101,32,100,114,105,118,101,114,32,111,102,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,100,114,105,118,101,114,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,100,114,105,118,101,114,95,101,110,116,114,121,35,100,114,105,118,101,114,95,102,108,97,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<69,82,76,95,68,82,86,95,70,76,65,71,95,83,79,70,84,95,66,85,83,89>>]}]},<<46>>]},{dt,[],[{code,[],[<<110,111,115,117,115,112,101,110,100>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,97,98,111,114,116,101,100,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<77,111,114,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<102,111,114,99,101>>]},<<32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,98,117,116,32,116,104,101,32,100,114,105,118,101,114,32,111,102,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,102,111,114,99,105,110,103,32,116,104,114,111,117,103,104,32,97,32,98,117,115,121,32,112,111,114,116,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,110,32,117,110,107,110,111,119,110,32,112,111,114,116,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,100,97,116,97,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,48,53>>,signature => [{attribute,3526,spec,{{port_command,3},[{type,3526,bounded_fun,[{type,3526,'fun',[{type,3526,product,[{var,3526,'Port'},{var,3526,'Data'},{var,3526,'OptionList'}]},{type,3526,boolean,[]}]},[{type,3527,constraint,[{atom,3527,is_subtype},[{var,3527,'Port'},{type,3527,union,[{type,3527,port,[]},{type,3527,atom,[]}]}]]},{type,3528,constraint,[{atom,3528,is_subtype},[{var,3528,'Data'},{type,3528,iodata,[]}]]},{type,3529,constraint,[{atom,3529,is_subtype},[{var,3529,'Option'},{type,3529,union,[{atom,3529,force},{atom,3529,nosuspend}]}]]},{type,3530,constraint,[{atom,3530,is_subtype},[{var,3530,'OptionList'},{type,3530,list,[{var,3530,'Option'}]}]]}]]}]}}]}},{{function,port_connect,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3542}],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,111,114,116,41,32,116,111,32>>,{code,[],[<<80,105,100>>]},<<46,32,82,111,117,103,104,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,100,105,102,102,101,114,115,44,32,115,101,101,32,98,101,108,111,119,46>>]}]},{li,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,114,101,112,108,121,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,99,111,110,110,101,99,116,101,100,125>>]},<<46>>]}]},{li,[],[{p,[],[{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,49>>]},<<32,105,115,32,115,121,110,99,104,114,111,110,111,117,115,44,32,115,101,101,32,98,101,108,111,119,46>>]}]},{li,[],[{p,[],[<<84,104,101,32,110,101,119,32,112,111,114,116,32,111,119,110,101,114,32,103,101,116,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,46>>]}]}]},{p,[],[<<84,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,32,115,116,97,121,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,97,110,100,32,109,117,115,116,32,99,97,108,108,32>>,{code,[],[<<117,110,108,105,110,107,40,80,111,114,116,41>>]},<<32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,100,101,115,105,114,101,100,46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,116,111,32,98,101,32,97,110,121,32,112,114,111,99,101,115,115,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>]},<<46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32,112,111,114,116,32,114,101,112,108,105,101,115,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,111,110,110,101,99,116,101,100,125>>]},<<32,116,111,32,116,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,32,105,115,32,115,116,105,108,108,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,119,104,105,108,101,32,116,104,101,32,110,101,119,32,105,115,32,110,111,116,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46,32,84,104,101,32,112,111,114,116,32,111,119,110,101,114,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<32,97,108,115,111,32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,98,117,116,32,116,104,101,32,114,101,112,108,121,32,97,108,119,97,121,115,32,103,111,101,115,32,116,111,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,54,57>>,signature => [{attribute,3542,spec,{{port_connect,2},[{type,3542,bounded_fun,[{type,3542,'fun',[{type,3542,product,[{var,3542,'Port'},{var,3542,'Pid'}]},{atom,3542,true}]},[{type,3543,constraint,[{atom,3543,is_subtype},[{var,3543,'Port'},{type,3543,union,[{type,3543,port,[]},{type,3543,atom,[]}]}]]},{type,3544,constraint,[{atom,3544,is_subtype},[{var,3544,'Pid'},{type,3544,pid,[]}]]}]]}]}}]}},{{function,port_control,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3567}],[<<112,111,114,116,95,99,111,110,116,114,111,108,47,51>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,32,111,110,32,97,32,112,111,114,116,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,97,110,100,32>>,{code,[],[<<68,97,116,97>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,44,32,116,104,97,116,32,105,115,44,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,78,111,116,32,97,108,108,32,112,111,114,116,32,100,114,105,118,101,114,115,32,115,117,112,112,111,114,116,32,116,104,105,115,32,99,111,110,116,114,111,108,32,102,101,97,116,117,114,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,46,46,50,53,53,44,32,111,114,32,97,32,98,105,110,97,114,121,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,100,97,116,97,32,97,108,115,111,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,111,112,101,110,32,112,111,114,116,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,99,97,110,110,111,116,32,102,105,116,32,105,110,32,97,32,51,50,45,98,105,116,32,105,110,116,101,103,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,115,111,32,100,101,99,105,100,101,115,32,102,111,114,32,97,110,121,32,114,101,97,115,111,110,32,40,112,114,111,98,97,98,108,121,32,115,111,109,101,116,104,105,110,103,32,119,114,111,110,103,32,119,105,116,104,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<41,46>>,{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,99,97,108,108,32>>,{code,[],[<<112,111,114,116,95,99,111,110,116,114,111,108,47,51>>]},<<32,119,105,116,104,32,97,110,32,117,110,107,110,111,119,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,101,120,112,101,99,116,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,115,117,112,112,108,105,101,100,32,97,114,103,117,109,101,110,116,115,46>>]}]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,49,51,56>>,signature => [{attribute,3567,spec,{{port_control,3},[{type,3567,bounded_fun,[{type,3567,'fun',[{type,3567,product,[{var,3567,'Port'},{var,3567,'Operation'},{var,3567,'Data'}]},{type,3567,union,[{type,3567,iodata,[]},{type,3567,binary,[]}]}]},[{type,3568,constraint,[{atom,3568,is_subtype},[{var,3568,'Port'},{type,3568,union,[{type,3568,port,[]},{type,3568,atom,[]}]}]]},{type,3569,constraint,[{atom,3569,is_subtype},[{var,3569,'Operation'},{type,3569,integer,[]}]]},{type,3570,constraint,[{atom,3570,is_subtype},[{var,3570,'Data'},{type,3570,iodata,[]}]]}]]}]}}]}},{{function,port_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3608}],[<<112,111,114,116,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,117,112,108,101,115,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,111,112,101,110,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,100,32,97,108,108,32,116,104,101,32,116,117,112,108,101,115,32,97,114,101,32,110,111,116,32,109,97,110,100,97,116,111,114,121,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,49>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,99,111,110,116,97,105,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,58>>]},{ul,[],[{li,[],[{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,40,105,102,32,116,104,101,32,112,111,114,116,32,104,97,115,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,41>>]},{li,[],[{code,[],[<<105,100>>]}]},{li,[],[{code,[],[<<99,111,110,110,101,99,116,101,100>>]}]},{li,[],[{code,[],[<<108,105,110,107,115>>]}]},{li,[],[{code,[],[<<110,97,109,101>>]}]},{li,[],[{code,[],[<<105,110,112,117,116>>]}]},{li,[],[{code,[],[<<111,117,116,112,117,116>>]}]}]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32>>,{code,[],[<<73,116,101,109>>]},<<115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,49,56,50>>,signature => [{attribute,3608,spec,{{erlang,port_info,1},[{type,3608,bounded_fun,[{type,3608,'fun',[{type,3608,product,[{var,3608,'Port'}]},{var,3608,'Result'}]},[{type,3609,constraint,[{atom,3609,is_subtype},[{var,3609,'Port'},{type,3609,union,[{type,3609,port,[]},{type,3609,atom,[]}]}]]},{type,3610,constraint,[{atom,3610,is_subtype},[{var,3610,'ResultItem'},{type,3610,union,[{type,3610,tuple,[{atom,3610,registered_name},{ann_type,3610,[{var,3610,'RegisteredName'},{type,3610,atom,[]}]}]},{type,3611,tuple,[{atom,3611,id},{ann_type,3611,[{var,3611,'Index'},{type,3611,non_neg_integer,[]}]}]},{type,3612,tuple,[{atom,3612,connected},{ann_type,3612,[{var,3612,'Pid'},{type,3612,pid,[]}]}]},{type,3613,tuple,[{atom,3613,links},{ann_type,3613,[{var,3613,'Pids'},{type,3613,list,[{type,3613,pid,[]}]}]}]},{type,3614,tuple,[{atom,3614,name},{ann_type,3614,[{var,3614,'String'},{type,3614,string,[]}]}]},{type,3615,tuple,[{atom,3615,input},{ann_type,3615,[{var,3615,'Bytes'},{type,3615,non_neg_integer,[]}]}]},{type,3616,tuple,[{atom,3616,output},{ann_type,3616,[{var,3616,'Bytes'},{type,3616,non_neg_integer,[]}]}]},{type,3617,tuple,[{atom,3617,os_pid},{ann_type,3617,[{var,3617,'OsPid'},{type,3617,union,[{type,3617,non_neg_integer,[]},{atom,3617,undefined}]}]}]}]}]]},{type,3618,constraint,[{atom,3618,is_subtype},[{var,3618,'Result'},{type,3618,union,[{type,3618,list,[{var,3618,'ResultItem'}]},{atom,3618,undefined}]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,49,51>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3629,bounded_fun,[{type,3629,'fun',[{type,3629,product,[{var,3629,'Port'},{atom,3629,connected}]},{type,3629,union,[{type,3629,tuple,[{atom,3629,connected},{var,3629,'Pid'}]},{atom,3629,undefined}]}]},[{type,3630,constraint,[{atom,3630,is_subtype},[{var,3630,'Port'},{type,3630,union,[{type,3630,port,[]},{type,3630,atom,[]}]}]]},{type,3631,constraint,[{atom,3631,is_subtype},[{var,3631,'Pid'},{type,3631,pid,[]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,105,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,105,110,100,101,120,32,111,102,32,116,104,101,32,112,111,114,116,46,32,84,104,105,115,32,105,110,100,101,120,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,101,112,97,114,97,116,101,32,112,111,114,116,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,50,57>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3632,bounded_fun,[{type,3632,'fun',[{type,3632,product,[{var,3632,'Port'},{atom,3632,id}]},{type,3632,union,[{type,3632,tuple,[{atom,3632,id},{var,3632,'Index'}]},{atom,3632,undefined}]}]},[{type,3633,constraint,[{atom,3633,is_subtype},[{var,3633,'Port'},{type,3633,union,[{type,3633,port,[]},{type,3633,atom,[]}]}]]},{type,3634,constraint,[{atom,3634,is_subtype},[{var,3634,'Index'},{type,3634,non_neg_integer,[]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,52,53>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3635,bounded_fun,[{type,3635,'fun',[{type,3635,product,[{var,3635,'Port'},{atom,3635,input}]},{type,3635,union,[{type,3635,tuple,[{atom,3635,input},{var,3635,'Bytes'}]},{atom,3635,undefined}]}]},[{type,3636,constraint,[{atom,3636,is_subtype},[{var,3636,'Port'},{type,3636,union,[{type,3636,port,[]},{type,3636,atom,[]}]}]]},{type,3637,constraint,[{atom,3637,is_subtype},[{var,3637,'Bytes'},{type,3637,non_neg_integer,[]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,105,115,32,108,105,110,107,101,100,32,116,111,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,54,49>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3638,bounded_fun,[{type,3638,'fun',[{type,3638,product,[{var,3638,'Port'},{atom,3638,links}]},{type,3638,union,[{type,3638,tuple,[{atom,3638,links},{var,3638,'Pids'}]},{atom,3638,undefined}]}]},[{type,3639,constraint,[{atom,3639,is_subtype},[{var,3639,'Port'},{type,3639,union,[{type,3639,port,[]},{type,3639,atom,[]}]}]]},{type,3640,constraint,[{atom,3640,is_subtype},[{var,3640,'Pids'},{type,3640,list,[{type,3640,pid,[]}]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<76,111,99,107,105,110,103>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<112,111,114,116,95,108,101,118,101,108>>]},<<32,40,112,111,114,116,45,115,112,101,99,105,102,105,99,32,108,111,99,107,105,110,103,41>>]},{li,[],[{code,[],[<<100,114,105,118,101,114,95,108,101,118,101,108>>]},<<32,40,100,114,105,118,101,114,45,115,112,101,99,105,102,105,99,32,108,111,99,107,105,110,103,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,114,101,115,117,108,116,115,32,97,114,101,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,55,55>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3641,bounded_fun,[{type,3641,'fun',[{type,3641,product,[{var,3641,'Port'},{atom,3641,locking}]},{type,3641,union,[{type,3641,tuple,[{atom,3641,locking},{var,3641,'Locking'}]},{atom,3641,undefined}]}]},[{type,3642,constraint,[{atom,3642,is_subtype},[{var,3642,'Port'},{type,3642,union,[{type,3642,port,[]},{type,3642,atom,[]}]}]]},{type,3643,constraint,[{atom,3643,is_subtype},[{var,3643,'Locking'},{type,3643,union,[{atom,3643,false},{atom,3643,port_level},{atom,3643,driver_level}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{a,[{id,<<112,111,114,116,95,105,110,102,111,95,109,101,109,111,114,121>>}],[]},{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,105,115,32,112,111,114,116,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,112,111,114,116,32,105,116,115,101,108,102,32,99,97,110,32,104,97,118,101,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32>>,{code,[],[<<66,121,116,101,115>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,57,56>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3644,bounded_fun,[{type,3644,'fun',[{type,3644,product,[{var,3644,'Port'},{atom,3644,memory}]},{type,3644,union,[{type,3644,tuple,[{atom,3644,memory},{var,3644,'Bytes'}]},{atom,3644,undefined}]}]},[{type,3645,constraint,[{atom,3645,is_subtype},[{var,3645,'Port'},{type,3645,union,[{type,3645,port,[]},{type,3645,atom,[]}]}]]},{type,3646,constraint,[{atom,3646,is_subtype},[{var,3646,'Bytes'},{type,3646,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<77,111,110,105,116,111,114,115>>]},<<32,114,101,112,114,101,115,101,110,116,32,112,114,111,99,101,115,115,101,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,116,104,105,115,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,51,49,55>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3647,bounded_fun,[{type,3647,'fun',[{type,3647,product,[{var,3647,'Port'},{atom,3647,monitors}]},{type,3647,union,[{type,3647,tuple,[{atom,3647,monitors},{var,3647,'Monitors'}]},{atom,3647,undefined}]}]},[{type,3648,constraint,[{atom,3648,is_subtype},[{var,3648,'Port'},{type,3648,union,[{type,3648,port,[]},{type,3648,atom,[]}]}]]},{type,3649,constraint,[{atom,3649,is_subtype},[{var,3649,'Monitors'},{type,3649,list,[{type,3649,tuple,[{atom,3649,process},{type,3649,pid,[]}]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,108,105,115,116,32,111,102,32,112,105,100,115,32,116,104,97,116,32,97,114,101,32,109,111,110,105,116,111,114,105,110,103,32,103,105,118,101,110,32,112,111,114,116,32,97,116,32,116,104,101,32,109,111,109,101,110,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,51,51,51>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3650,bounded_fun,[{type,3650,'fun',[{type,3650,product,[{var,3650,'Port'},{atom,3650,monitored_by}]},{type,3650,union,[{type,3650,tuple,[{atom,3650,monitored_by},{var,3650,'MonitoredBy'}]},{atom,3650,undefined}]}]},[{type,3651,constraint,[{atom,3651,is_subtype},[{var,3651,'Port'},{type,3651,union,[{type,3651,port,[]},{type,3651,atom,[]}]}]]},{type,3652,constraint,[{atom,3652,is_subtype},[{var,3652,'MonitoredBy'},{type,3652,list,[{type,3652,pid,[]}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,99,111,109,109,97,110,100,32,110,97,109,101,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,47,50>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,51,52,57>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3653,bounded_fun,[{type,3653,'fun',[{type,3653,product,[{var,3653,'Port'},{atom,3653,name}]},{type,3653,union,[{type,3653,tuple,[{atom,3653,name},{var,3653,'Name'}]},{atom,3653,undefined}]}]},[{type,3654,constraint,[{atom,3654,is_subtype},[{var,3654,'Port'},{type,3654,union,[{type,3654,port,[]},{type,3654,atom,[]}]}]]},{type,3655,constraint,[{atom,3655,is_subtype},[{var,3655,'Name'},{type,3655,string,[]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<79,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,111,114,32,101,113,117,105,118,97,108,101,110,116,41,32,111,102,32,97,110,32,79,83,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,40,123,115,112,97,119,110,32,124,32,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125,44,32,79,112,116,105,111,110,115,41>>]}]},<<46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,112,97,119,110,105,110,103,32,97,110,32,79,83,32,112,114,111,99,101,115,115,44,32,116,104,101,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,51,54,53>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3656,bounded_fun,[{type,3656,'fun',[{type,3656,product,[{var,3656,'Port'},{atom,3656,os_pid}]},{type,3656,union,[{type,3656,tuple,[{atom,3656,os_pid},{var,3656,'OsPid'}]},{atom,3656,undefined}]}]},[{type,3657,constraint,[{atom,3657,is_subtype},[{var,3657,'Port'},{type,3657,union,[{type,3657,port,[]},{type,3657,atom,[]}]}]]},{type,3658,constraint,[{atom,3658,is_subtype},[{var,3658,'OsPid'},{type,3658,union,[{type,3658,non_neg_integer,[]},{atom,3658,undefined}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,112,111,114,116,32,102,114,111,109,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,99,111,109,109,97,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,99,111,109,109,97,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,51>>]}]},<<44,32,111,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,51,56,52>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3659,bounded_fun,[{type,3659,'fun',[{type,3659,product,[{var,3659,'Port'},{atom,3659,output}]},{type,3659,union,[{type,3659,tuple,[{atom,3659,output},{var,3659,'Bytes'}]},{atom,3659,undefined}]}]},[{type,3660,constraint,[{atom,3660,is_subtype},[{var,3660,'Port'},{type,3660,union,[{type,3660,port,[]},{type,3660,atom,[]}]}]]},{type,3661,constraint,[{atom,3661,is_subtype},[{var,3661,'Bytes'},{type,3661,non_neg_integer,[]}]]}]]}]}}]}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,111,111,108,101,97,110>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,32,104,105,110,116,32,117,115,101,100,32,98,121,32,116,104,105,115,32,112,111,114,116,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,97,114,97,108,108,101,108,105,115,109>>]}]},<<32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,48,51>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3662,bounded_fun,[{type,3662,'fun',[{type,3662,product,[{var,3662,'Port'},{atom,3662,parallelism}]},{type,3662,union,[{type,3662,tuple,[{atom,3662,parallelism},{var,3662,'Boolean'}]},{atom,3662,undefined}]}]},[{type,3663,constraint,[{atom,3663,is_subtype},[{var,3663,'Port'},{type,3663,union,[{type,3663,port,[]},{type,3663,atom,[]}]}]]},{type,3664,constraint,[{atom,3664,is_subtype},[{var,3664,'Boolean'},{type,3664,boolean,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,113,117,101,117,101,100,32,98,121,32,116,104,101,32,112,111,114,116,32,117,115,105,110,103,32,116,104,101,32,69,82,84,83,32,100,114,105,118,101,114,32,113,117,101,117,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,49,52>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3665,bounded_fun,[{type,3665,'fun',[{type,3665,product,[{var,3665,'Port'},{atom,3665,queue_size}]},{type,3665,union,[{type,3665,tuple,[{atom,3665,queue_size},{var,3665,'Bytes'}]},{atom,3665,undefined}]}]},[{type,3666,constraint,[{atom,3666,is_subtype},[{var,3666,'Port'},{type,3666,union,[{type,3666,port,[]},{type,3666,atom,[]}]}]]},{type,3667,constraint,[{atom,3667,is_subtype},[{var,3667,'Bytes'},{type,3667,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3629}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,116,104,101,32,112,111,114,116,46,32,73,102,32,116,104,101,32,112,111,114,116,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,51,49>>,signature => [{attribute,3629,spec,{{erlang,port_info,2},[{type,3668,bounded_fun,[{type,3668,'fun',[{type,3668,product,[{var,3668,'Port'},{atom,3668,registered_name}]},{type,3668,union,[{type,3668,tuple,[{atom,3668,registered_name},{var,3668,'RegisteredName'}]},{type,3668,nil,[]},{atom,3668,undefined}]}]},[{type,3669,constraint,[{atom,3669,is_subtype},[{var,3669,'Port'},{type,3669,union,[{type,3669,port,[]},{type,3669,atom,[]}]}]]},{type,3670,constraint,[{atom,3670,is_subtype},[{var,3670,'RegisteredName'},{type,3670,atom,[]}]]}]]}]}}]}},{{function,port_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1506}],[<<112,111,114,116,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,52,56>>,signature => [{attribute,1506,spec,{{port_to_list,1},[{type,1506,bounded_fun,[{type,1506,'fun',[{type,1506,product,[{var,1506,'Port'}]},{type,1506,string,[]}]},[{type,1507,constraint,[{atom,1507,is_subtype},[{var,1507,'Port'},{type,1507,port,[]}]]}]]}]}}]}},{{function,ports,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1512}],[<<112,111,114,116,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,97,108,108,32,116,104,101,32,112,111,114,116,115,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,32,101,120,105,116,105,110,103,32,112,111,114,116,32,101,120,105,115,116,115,44,32,98,117,116,32,105,115,32,110,111,116,32,111,112,101,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,53,55>>,signature => [{attribute,1512,spec,{{erlang,ports,0},[{type,1512,'fun',[{type,1512,product,[]},{type,1512,list,[{type,1512,port,[]}]}]}]}}]}},{{function,pre_loaded,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1658}],[<<112,114,101,95,108,111,97,100,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,116,104,97,116,32,97,114,101,32,112,114,101,108,111,97,100,101,100,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,65,115,32,97,108,108,32,108,111,97,100,105,110,103,32,111,102,32,99,111,100,101,32,105,115,32,100,111,110,101,32,116,104,114,111,117,103,104,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,44,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,109,117,115,116,32,104,97,118,101,32,98,101,101,110,32,108,111,97,100,101,100,32,112,114,101,118,105,111,117,115,108,121,46,32,72,101,110,99,101,44,32,97,116,32,108,101,97,115,116,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<105,110,105,116>>]},<<32,109,117,115,116,32,98,101,32,112,114,101,108,111,97,100,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,54,55>>,signature => [{attribute,1658,spec,{{pre_loaded,0},[{type,1658,'fun',[{type,1658,product,[]},{type,1658,list,[{type,1658,module,[]}]}]}]}}]}},{{function,process_display,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1663}],[<<112,114,111,99,101,115,115,95,100,105,115,112,108,97,121,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<32,111,110,32,115,116,97,110,100,97,114,100,32,101,114,114,111,114,46,32,84,104,101,32,111,110,108,121,32,97,108,108,111,119,101,100,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<98,97,99,107,116,114,97,99,101>>]},<<44,32,119,104,105,99,104,32,115,104,111,119,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,44,32,105,110,99,108,117,100,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,97,108,108,32,99,104,97,105,110,44,32,119,105,116,104,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,112,114,105,110,116,101,100,32,102,105,114,115,116,46,32,84,104,101,32,102,111,114,109,97,116,32,111,102,32,116,104,101,32,111,117,116,112,117,116,32,105,115,32,110,111,116,32,102,117,114,116,104,101,114,32,100,101,102,105,110,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,55,56>>,signature => [{attribute,1663,spec,{{erlang,process_display,2},[{type,1663,bounded_fun,[{type,1663,'fun',[{type,1663,product,[{var,1663,'Pid'},{var,1663,'Type'}]},{atom,1663,true}]},[{type,1664,constraint,[{atom,1664,is_subtype},[{var,1664,'Pid'},{type,1664,pid,[]}]]},{type,1665,constraint,[{atom,1665,is_subtype},[{var,1665,'Type'},{atom,1665,backtrace}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<87,104,101,110,32>>,{code,[],[<<116,114,97,112,95,101,120,105,116>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,101,120,105,116,32,115,105,103,110,97,108,115,32,97,114,114,105,118,105,110,103,32,116,111,32,97,32,112,114,111,99,101,115,115,32,97,114,101,32,99,111,110,118,101,114,116,101,100,32,116,111,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,82,101,97,115,111,110,125>>]},<<32,109,101,115,115,97,103,101,115,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,114,101,99,101,105,118,101,100,32,97,115,32,111,114,100,105,110,97,114,121,32,109,101,115,115,97,103,101,115,46,32,73,102,32>>,{code,[],[<<116,114,97,112,95,101,120,105,116>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,105,102,32,105,116,32,114,101,99,101,105,118,101,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,111,116,104,101,114,32,116,104,97,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,112,114,111,112,97,103,97,116,101,100,32,116,111,32,105,116,115,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,65,112,112,108,105,99,97,116,105,111,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,110,111,114,109,97,108,108,121,32,110,111,116,32,116,111,32,116,114,97,112,32,101,120,105,116,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,120,105,116,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,52,57,50>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2356,bounded_fun,[{type,2356,'fun',[{type,2356,product,[{atom,2356,trap_exit},{var,2356,'Boolean'}]},{var,2356,'OldBoolean'}]},[{type,2357,constraint,[{atom,2357,is_subtype},[{var,2357,'Boolean'},{type,2357,boolean,[]}]]},{type,2358,constraint,[{atom,2358,is_subtype},[{var,2358,'OldBoolean'},{type,2358,boolean,[]}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<85,115,101,100,32,98,121,32,97,32,112,114,111,99,101,115,115,32,116,111,32,114,101,100,101,102,105,110,101,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,102,111,114,32,117,110,100,101,102,105,110,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,110,100,32,117,110,100,101,102,105,110,101,100,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,101,115,46,32,73,110,101,120,112,101,114,105,101,110,99,101,100,32,117,115,101,114,115,32,97,114,101,32,110,111,116,32,116,111,32,117,115,101,32,116,104,105,115,32,102,108,97,103,44,32,97,115,32,99,111,100,101,32,97,117,116,111,45,108,111,97,100,105,110,103,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,99,111,114,114,101,99,116,32,111,112,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,32,109,111,100,117,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,53,48,57>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2359,bounded_fun,[{type,2359,'fun',[{type,2359,product,[{atom,2359,error_handler},{var,2359,'Module'}]},{var,2359,'OldModule'}]},[{type,2360,constraint,[{atom,2360,is_subtype},[{var,2360,'Module'},{type,2360,atom,[]}]]},{type,2361,constraint,[{atom,2361,is_subtype},[{var,2361,'OldModule'},{type,2361,atom,[]}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,53,50,51>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2362,bounded_fun,[{type,2362,'fun',[{type,2362,product,[{atom,2362,min_heap_size},{var,2362,'MinHeapSize'}]},{var,2362,'OldMinHeapSize'}]},[{type,2363,constraint,[{atom,2363,is_subtype},[{var,2363,'MinHeapSize'},{type,2363,non_neg_integer,[]}]]},{type,2364,constraint,[{atom,2364,is_subtype},[{var,2364,'OldMinHeapSize'},{type,2364,non_neg_integer,[]}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,53,51,52>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2365,bounded_fun,[{type,2365,'fun',[{type,2365,product,[{atom,2365,min_bin_vheap_size},{var,2365,'MinBinVHeapSize'}]},{var,2365,'OldMinBinVHeapSize'}]},[{type,2366,constraint,[{atom,2366,is_subtype},[{var,2366,'MinBinVHeapSize'},{type,2366,non_neg_integer,[]}]]},{type,2367,constraint,[{atom,2367,is_subtype},[{var,2367,'OldMinBinVHeapSize'},{type,2367,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]}]},{p,[],[<<84,104,105,115,32,102,108,97,103,32,115,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<77,97,120,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<107,105,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]},<<32,97,114,101,32,117,115,101,100,46>>]},{dl,[],[{dt,[],[{code,[],[<<115,105,122,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,115,105,122,101,32,105,110,32,119,111,114,100,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,115,101,116,32,116,111,32,122,101,114,111,44,32,116,104,101,32,104,101,97,112,32,115,105,122,101,32,108,105,109,105,116,32,105,115,32,100,105,115,97,98,108,101,100,46,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,115,32,98,101,32,116,104,114,111,119,110,32,105,102,32,116,104,101,32,118,97,108,117,101,32,105,115,32,115,109,97,108,108,101,114,32,116,104,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},<<46,32,84,104,101,32,115,105,122,101,32,99,104,101,99,107,32,105,115,32,111,110,108,121,32,100,111,110,101,32,119,104,101,110,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,116,114,105,103,103,101,114,101,100,46>>]},{p,[],[{code,[],[<<115,105,122,101>>]},<<32,105,115,32,116,104,101,32,101,110,116,105,114,101,32,104,101,97,112,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,119,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,116,114,105,103,103,101,114,101,100,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,97,108,108,32,103,101,110,101,114,97,116,105,111,110,97,108,32,104,101,97,112,115,44,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,44,32,97,110,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,101,115,115,97,103,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112>>]},<<44,32,97,110,100,32,97,110,121,32,101,120,116,114,97,32,109,101,109,111,114,121,32,116,104,97,116,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,111,114,32,110,101,101,100,115,32,100,117,114,105,110,103,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[{code,[],[<<115,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,95,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101,41>>]}]},<<44,32,111,114,32,98,121,32,97,100,100,105,110,103,32>>,{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<32,97,110,100,32>>,{code,[],[<<109,98,117,102,95,115,105,122,101>>]},<<32,102,114,111,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<107,105,108,108>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,101,110,100,115,32,97,110,32,117,110,116,114,97,112,112,97,98,108,101,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,102,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,105,115,32,114,101,97,99,104,101,100,46,32,84,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,116,104,97,116,32,116,114,105,103,103,101,114,101,100,32,116,104,101,32>>,{code,[],[<<107,105,108,108>>]},<<32,105,115,32,110,111,116,32,99,111,109,112,108,101,116,101,100,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,97,115,32,115,111,111,110,32,97,115,32,112,111,115,115,105,98,108,101,46,32,87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,110,111,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,44,32,105,110,115,116,101,97,100,32,105,116,32,99,111,110,116,105,110,117,101,115,32,101,120,101,99,117,116,105,110,103,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<107,105,108,108>>]},<<32,105,115,32,110,111,116,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,109,97,112,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,119,105,108,108,32,98,101,32,117,115,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,101,105,116,104,101,114,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,104,109,97,120,107>>]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,108,111,103,115,32,97,110,32,101,114,114,111,114,32,101,118,101,110,116,32,118,105,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,103,101,114>>]}]},<<44,32,99,111,110,116,97,105,110,105,110,103,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,119,104,101,110,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,105,115,32,114,101,97,99,104,101,100,46,32,79,110,101,32,108,111,103,32,101,118,101,110,116,32,105,115,32,115,101,110,116,32,101,97,99,104,32,116,105,109,101,32,116,104,101,32,108,105,109,105,116,32,105,115,32,114,101,97,99,104,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]},<<32,105,115,32,110,111,116,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,109,97,112,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32,117,115,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,101,105,116,104,101,114,32,116,104,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,104,109,97,120,101,108>>]},<<32,105,110,116,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,104,101,97,112,32,115,105,122,101,32,111,102,32,97,32,112,114,111,99,101,115,115,32,105,115,32,113,117,105,116,101,32,104,97,114,100,32,116,111,32,112,114,101,100,105,99,116,44,32,101,115,112,101,99,105,97,108,108,121,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,117,115,101,100,32,100,117,114,105,110,103,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,99,111,110,116,101,109,112,108,97,116,105,110,103,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,102,105,114,115,116,32,114,117,110,32,105,116,32,105,110,32,112,114,111,100,117,99,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<107,105,108,108>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,97,110,100,32,105,110,115,112,101,99,116,32,116,104,101,32,108,111,103,32,101,118,101,110,116,115,32,116,111,32,115,101,101,32,119,104,97,116,32,116,104,101,32,110,111,114,109,97,108,32,112,101,97,107,32,115,105,122,101,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,105,115,32,97,110,100,32,116,104,101,110,32,116,117,110,101,32,116,104,101,32,118,97,108,117,101,32,97,99,99,111,114,100,105,110,103,108,121,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,53,52,53>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2368,bounded_fun,[{type,2368,'fun',[{type,2368,product,[{atom,2368,max_heap_size},{var,2368,'MaxHeapSize'}]},{var,2368,'OldMaxHeapSize'}]},[{type,2369,constraint,[{atom,2369,is_subtype},[{var,2369,'MaxHeapSize'},{user_type,2369,max_heap_size,[]}]]},{type,2370,constraint,[{atom,2370,is_subtype},[{var,2370,'OldMaxHeapSize'},{user_type,2370,max_heap_size,[]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]}]},{p,[],[<<84,104,105,115,32,102,108,97,103,32,100,101,116,101,114,109,105,110,101,115,32,104,111,119,32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,114,101,32,115,116,111,114,101,100,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,102,102,95,104,101,97,112>>]}]},{dd,[],[{p,[],[{em,[],[<<65,108,108>>]},<<32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,98,101,32,115,116,111,114,101,100,32,111,117,116,115,105,100,101,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,104,101,97,112,46,32,84,104,105,115,32,105,109,112,108,105,101,115,32,116,104,97,116,32>>,{em,[],[<<110,111>>]},<<32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,98,101,32,112,97,114,116,32,111,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<111,110,95,104,101,97,112>>]}]},{dd,[],[{p,[],[<<65,108,108,32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,101,118,101,110,116,117,97,108,108,121,32,98,101,32,112,108,97,99,101,100,32,111,110,32,104,101,97,112,46,32,84,104,101,121,32,99,97,110,32,104,111,119,101,118,101,114,32,116,101,109,112,111,114,97,114,105,108,121,32,98,101,32,115,116,111,114,101,100,32,111,102,102,32,104,101,97,112,46,32,84,104,105,115,32,105,115,32,104,111,119,32,109,101,115,115,97,103,101,115,32,97,108,119,97,121,115,32,104,97,118,101,32,98,101,101,110,32,115,116,111,114,101,100,32,117,112,32,117,110,116,105,108,32,69,82,84,83,32,56,46,48,46>>]}]}]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,112,111,116,101,110,116,105,97,108,108,121,32,99,97,110,32,103,101,116,32,109,97,110,121,32,109,101,115,115,97,103,101,115,32,105,110,32,105,116,115,32,113,117,101,117,101,44,32,121,111,117,32,97,114,101,32,97,100,118,105,115,101,100,32,116,111,32,115,101,116,32,116,104,101,32,102,108,97,103,32,116,111,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<46,32,84,104,105,115,32,98,101,99,97,117,115,101,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,119,105,116,104,32,109,97,110,121,32,109,101,115,115,97,103,101,115,32,112,108,97,99,101,100,32,111,110,32,116,104,101,32,104,101,97,112,32,99,97,110,32,98,101,99,111,109,101,32,101,120,116,114,101,109,101,108,121,32,101,120,112,101,110,115,105,118,101,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,110,32,99,111,110,115,117,109,101,32,108,97,114,103,101,32,97,109,111,117,110,116,115,32,111,102,32,109,101,109,111,114,121,46,32,80,101,114,102,111,114,109,97,110,99,101,32,111,102,32,116,104,101,32,97,99,116,117,97,108,32,109,101,115,115,97,103,101,32,112,97,115,115,105,110,103,32,105,115,32,104,111,119,101,118,101,114,32,103,101,110,101,114,97,108,108,121,32,98,101,116,116,101,114,32,119,104,101,110,32,110,111,116,32,117,115,105,110,103,32,102,108,97,103,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<46>>]},{p,[],[<<87,104,101,110,32,99,104,97,110,103,105,110,103,32,116,104,105,115,32,102,108,97,103,32,109,101,115,115,97,103,101,115,32,119,105,108,108,32,98,101,32,109,111,118,101,100,46,32,84,104,105,115,32,119,111,114,107,32,104,97,115,32,98,101,101,110,32,105,110,105,116,105,97,116,101,100,32,98,117,116,32,110,111,116,32,99,111,109,112,108,101,116,101,100,32,119,104,101,110,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,114,101,116,117,114,110,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,49,57>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2371,bounded_fun,[{type,2371,'fun',[{type,2371,product,[{atom,2371,message_queue_data},{var,2371,'MQD'}]},{var,2371,'OldMQD'}]},[{type,2372,constraint,[{atom,2372,is_subtype},[{var,2372,'MQD'},{user_type,2372,message_queue_data,[]}]]},{type,2373,constraint,[{atom,2373,is_subtype},[{var,2373,'OldMQD'},{user_type,2373,message_queue_data,[]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,112,114,105,111,114,105,116,121,46,32>>,{code,[],[<<76,101,118,101,108>>]},<<32,105,115,32,97,110,32,97,116,111,109,46,32,70,111,117,114,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,115,32,101,120,105,115,116,58,32>>,{code,[],[<<108,111,119>>]},<<44,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<44,32>>,{code,[],[<<104,105,103,104>>]},<<44,32,97,110,100,32>>,{code,[],[<<109,97,120>>]},<<46,32,68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<80,114,105,111,114,105,116,121,32,108,101,118,101,108,32>>,{code,[],[<<109,97,120>>]},<<32,105,115,32,114,101,115,101,114,118,101,100,32,102,111,114,32,105,110,116,101,114,110,97,108,32,117,115,101,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,44,32,97,110,100,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,98,101,32,117,115,101,100,32,98,121,32,111,116,104,101,114,115,46>>]}]},{p,[],[<<73,110,116,101,114,110,97,108,108,121,32,105,110,32,101,97,99,104,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,44,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,115,99,104,101,100,117,108,101,100,32,105,110,32,97,32,114,111,117,110,100,32,114,111,98,105,110,32,102,97,115,104,105,111,110,46>>]},{p,[],[<<69,120,101,99,117,116,105,111,110,32,111,102,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<108,111,119>>]},<<32,97,114,101,32,105,110,116,101,114,108,101,97,118,101,100,46,32,80,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,108,101,115,115,32,102,114,101,113,117,101,110,116,108,121,32,116,104,97,110,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,97,98,108,101,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<32,101,120,105,115,116,44,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,111,114,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46,32,78,111,116,105,99,101,32,104,111,119,101,118,101,114,32,116,104,97,116,32,116,104,105,115,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,109,101,97,110,32,116,104,97,116,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,111,114,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,99,97,110,32,114,117,110,32,119,104,101,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,114,117,110,110,105,110,103,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,87,104,101,110,32,117,115,105,110,103,32,109,117,108,116,105,112,108,101,32,115,99,104,101,100,117,108,101,114,115,44,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,32,99,97,110,32,98,101,32,114,117,110,110,105,110,103,32,105,110,32,112,97,114,97,108,108,101,108,32,116,104,97,110,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,84,104,97,116,32,105,115,44,32,97,32>>,{code,[],[<<108,111,119>>]},<<32,97,110,100,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,99,97,110,32,101,120,101,99,117,116,101,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,97,98,108,101,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<109,97,120>>]},<<32,101,120,105,115,116,44,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<44,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<44,32,111,114,32>>,{code,[],[<<104,105,103,104>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46,32,65,115,32,119,105,116,104,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<44,32,112,114,111,99,101,115,115,101,115,32,111,110,32,108,111,119,101,114,32,112,114,105,111,114,105,116,105,101,115,32,99,97,110,32,101,120,101,99,117,116,101,32,105,110,32,112,97,114,97,108,108,101,108,32,119,105,116,104,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<109,97,120>>]},<<46>>]},{p,[],[<<83,99,104,101,100,117,108,105,110,103,32,105,115,32,112,114,101,45,101,109,112,116,105,118,101,46,32,82,101,103,97,114,100,108,101,115,115,32,111,102,32,112,114,105,111,114,105,116,121,44,32,97,32,112,114,111,99,101,115,115,32,105,115,32,112,114,101,45,101,109,112,116,101,100,32,119,104,101,110,32,105,116,32,104,97,115,32,99,111,110,115,117,109,101,100,32,109,111,114,101,32,116,104,97,110,32,97,32,99,101,114,116,97,105,110,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,105,116,32,119,97,115,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,115,99,104,101,100,117,108,105,110,103,32,116,111,32,114,101,109,97,105,110,32,101,120,97,99,116,108,121,32,97,115,32,105,116,32,105,115,32,116,111,100,97,121,46,32,83,99,104,101,100,117,108,105,110,103,32,105,115,32,108,105,107,101,108,121,32,116,111,32,98,101,32,99,104,97,110,103,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,32,116,111,32,117,115,101,32,97,118,97,105,108,97,98,108,101,32,112,114,111,99,101,115,115,111,114,32,99,111,114,101,115,32,98,101,116,116,101,114,46>>]}]},{p,[],[<<84,104,101,114,101,32,105,115,32>>,{em,[],[<<110,111>>]},<<32,97,117,116,111,109,97,116,105,99,32,109,101,99,104,97,110,105,115,109,32,102,111,114,32,97,118,111,105,100,105,110,103,32,112,114,105,111,114,105,116,121,32,105,110,118,101,114,115,105,111,110,44,32,115,117,99,104,32,97,115,32,112,114,105,111,114,105,116,121,32,105,110,104,101,114,105,116,97,110,99,101,32,111,114,32,112,114,105,111,114,105,116,121,32,99,101,105,108,105,110,103,115,46,32,87,104,101,110,32,117,115,105,110,103,32,112,114,105,111,114,105,116,105,101,115,44,32,116,97,107,101,32,116,104,105,115,32,105,110,116,111,32,97,99,99,111,117,110,116,32,97,110,100,32,104,97,110,100,108,101,32,115,117,99,104,32,115,99,101,110,97,114,105,111,115,32,98,121,32,121,111,117,114,115,101,108,102,46>>]},{p,[],[<<77,97,107,105,110,103,32,99,97,108,108,115,32,102,114,111,109,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,105,110,116,111,32,99,111,100,101,32,116,104,97,116,32,121,111,117,32,104,97,115,32,110,111,32,99,111,110,116,114,111,108,32,111,118,101,114,32,99,97,110,32,99,97,117,115,101,32,116,104,101,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,116,111,32,119,97,105,116,32,102,111,114,32,97,32,112,114,111,99,101,115,115,32,119,105,116,104,32,108,111,119,101,114,32,112,114,105,111,114,105,116,121,46,32,84,104,97,116,32,105,115,44,32,101,102,102,101,99,116,105,118,101,108,121,32,100,101,99,114,101,97,115,105,110,103,32,116,104,101,32,112,114,105,111,114,105,116,121,32,111,102,32,116,104,101,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,100,117,114,105,110,103,32,116,104,101,32,99,97,108,108,46,32,69,118,101,110,32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,116,104,101,32,99,97,115,101,32,119,105,116,104,32,111,110,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,121,111,117,32,104,97,118,101,32,110,111,32,99,111,110,116,114,111,108,32,111,118,101,114,44,32,105,116,32,99,97,110,32,98,101,32,116,104,101,32,99,97,115,101,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,105,116,46,32,84,104,105,115,32,99,97,110,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,111,99,99,117,114,32,105,102,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,116,114,105,103,103,101,114,115,32,99,111,100,101,32,108,111,97,100,105,110,103,44,32,97,115,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,114,117,110,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<79,116,104,101,114,32,112,114,105,111,114,105,116,105,101,115,32,116,104,97,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,114,101,32,110,111,114,109,97,108,108,121,32,110,111,116,32,110,101,101,100,101,100,46,32,87,104,101,110,32,111,116,104,101,114,32,112,114,105,111,114,105,116,105,101,115,32,97,114,101,32,117,115,101,100,44,32,117,115,101,32,116,104,101,109,32,119,105,116,104,32,99,97,114,101,44,32>>,{em,[],[<<101,115,112,101,99,105,97,108,108,121>>]},<<32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,65,32,112,114,111,99,101,115,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,112,101,114,102,111,114,109,32,119,111,114,107,32,102,111,114,32,115,104,111,114,116,32,112,101,114,105,111,100,115,46,32,66,117,115,121,32,108,111,111,112,105,110,103,32,102,111,114,32,108,111,110,103,32,112,101,114,105,111,100,115,32,105,110,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,99,97,117,115,101,115,32,109,111,115,116,32,108,105,107,101,108,121,32,112,114,111,98,108,101,109,115,44,32,97,115,32,105,109,112,111,114,116,97,110,116,32,79,84,80,32,115,101,114,118,101,114,115,32,114,117,110,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,54,49>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2374,bounded_fun,[{type,2374,'fun',[{type,2374,product,[{atom,2374,priority},{var,2374,'Level'}]},{var,2374,'OldLevel'}]},[{type,2375,constraint,[{atom,2375,is_subtype},[{var,2375,'Level'},{user_type,2375,priority_level,[]}]]},{type,2376,constraint,[{atom,2376,is_subtype},[{var,2376,'OldLevel'},{user_type,2376,priority_level,[]}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<78>>]},<<32,109,117,115,116,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,116,104,101,32,105,110,116,101,114,118,97,108,32,48,46,46,49,48,48,48,48,46,32,73,102,32>>,{code,[],[<<78>>]},<<32,62,32,48,44,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,109,97,100,101,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<78>>]},<<32,109,111,115,116,32,114,101,99,101,110,116,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,66,73,70,32,99,97,108,108,115,44,32,115,101,110,100,115,44,32,97,110,100,32,114,101,99,101,105,118,101,115,32,109,97,100,101,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,97,114,101,32,115,97,118,101,100,32,105,110,32,97,32,108,105,115,116,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,119,105,116,104,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,108,97,115,116,95,99,97,108,108,115,41>>]},<<46,32,65,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,105,115,32,111,110,101,32,105,110,32,119,104,105,99,104,32,116,104,101,32,109,111,100,117,108,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,109,101,110,116,105,111,110,101,100,46,32,79,110,108,121,32,97,32,102,105,120,101,100,32,97,109,111,117,110,116,32,111,102,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,115,97,118,101,100,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{ul,[],[{li,[],[{p,[],[<<65,32,116,117,112,108,101,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<32,102,111,114,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115>>]}]},{li,[],[{p,[],[<<84,104,101,32,97,116,111,109,115,32>>,{code,[],[<<115,101,110,100>>]},<<44,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<44,32,97,110,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,102,111,114,32,115,101,110,100,115,32,97,110,100,32,114,101,99,101,105,118,101,115,32,40>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,119,104,101,110,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,99,101,105,118,101,100,32,97,110,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,119,104,101,110,32,97,32,114,101,99,101,105,118,101,32,116,105,109,101,115,32,111,117,116,41>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<78>>]},<<32,61,32,48,44,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,100,105,115,97,98,108,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46,32,87,104,101,110,101,118,101,114,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,32,105,115,32,115,101,116,44,32,105,116,115,32,99,111,110,116,101,110,116,115,32,97,114,101,32,114,101,115,101,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,51,52>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2377,bounded_fun,[{type,2377,'fun',[{type,2377,product,[{atom,2377,save_calls},{var,2377,'N'}]},{var,2377,'OldN'}]},[{type,2378,constraint,[{atom,2378,is_subtype},[{var,2378,'N'},{type,2378,range,[{integer,2378,0},{integer,2378,10000}]}]]},{type,2379,constraint,[{atom,2379,is_subtype},[{var,2379,'OldN'},{type,2379,range,[{integer,2379,0},{integer,2379,10000}]}]]}]]}]}}]}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2356}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,111,114,32,99,108,101,97,114,115,32,102,108,97,103,32>>,{code,[],[<<115,101,110,115,105,116,105,118,101>>]},<<32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,87,104,101,110,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,109,97,114,107,101,100,32,97,115,32,115,101,110,115,105,116,105,118,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,115,101,110,115,105,116,105,118,101,44,32,116,114,117,101,41>>]},<<44,32,102,101,97,116,117,114,101,115,32,105,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,101,120,97,109,105,110,105,110,103,32,116,104,101,32,100,97,116,97,32,111,114,32,105,110,110,101,114,32,119,111,114,107,105,110,103,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,97,114,101,32,115,105,108,101,110,116,108,121,32,100,105,115,97,98,108,101,100,46>>]},{p,[],[<<70,101,97,116,117,114,101,115,32,116,104,97,116,32,97,114,101,32,100,105,115,97,98,108,101,100,32,105,110,99,108,117,100,101,32,40,98,117,116,32,97,114,101,32,110,111,116,32,108,105,109,105,116,101,100,32,116,111,41,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{p,[],[<<84,114,97,99,105,110,103,46,32,84,114,97,99,101,32,102,108,97,103,115,32,99,97,110,32,115,116,105,108,108,32,98,101,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,98,117,116,32,110,111,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,111,102,32,97,110,121,32,107,105,110,100,32,97,114,101,32,103,101,110,101,114,97,116,101,100,46,32,40,73,102,32,102,108,97,103,32>>,{code,[],[<<115,101,110,115,105,116,105,118,101>>]},<<32,105,115,32,116,117,114,110,101,100,32,111,102,102,44,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,97,103,97,105,110,32,103,101,110,101,114,97,116,101,100,32,105,102,32,97,110,121,32,116,114,97,99,101,32,102,108,97,103,115,32,97,114,101,32,115,101,116,46,41>>]}]},{li,[],[{p,[],[<<83,101,113,117,101,110,116,105,97,108,32,116,114,97,99,105,110,103,46,32,84,104,101,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,116,111,107,101,110,32,105,115,32,112,114,111,112,97,103,97,116,101,100,32,97,115,32,117,115,117,97,108,44,32,98,117,116,32,110,111,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,103,101,110,101,114,97,116,101,100,46>>]}]}]},{p,[],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49,44,50>>]},<<32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,32,116,111,32,114,101,97,100,32,111,117,116,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,40,98,111,116,104,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,101,109,112,116,121,32,108,105,115,116,115,41,46>>]},{p,[],[<<83,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,115,32,99,97,110,110,111,116,32,98,101,32,100,105,115,112,108,97,121,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,110,32,99,114,97,115,104,32,100,117,109,112,115,44,32,116,104,101,32,115,116,97,99,107,44,32,109,101,115,115,97,103,101,115,44,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,114,101,32,111,109,105,116,116,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<123,115,97,118,101,95,99,97,108,108,115,44,78,125>>]},<<32,104,97,115,32,98,101,101,110,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,110,111,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,115,97,118,101,100,32,116,111,32,116,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,46,32,40,84,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,32,105,115,32,110,111,116,32,99,108,101,97,114,101,100,46,32,65,108,115,111,44,32,115,101,110,100,44,32,114,101,99,101,105,118,101,44,32,97,110,100,32,116,105,109,101,45,111,117,116,32,101,118,101,110,116,115,32,97,114,101,32,115,116,105,108,108,32,97,100,100,101,100,32,116,111,32,116,104,101,32,108,105,115,116,46,41>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,54,53>>,signature => [{attribute,2356,spec,{{process_flag,2},[{type,2380,bounded_fun,[{type,2380,'fun',[{type,2380,product,[{atom,2380,sensitive},{var,2380,'Boolean'}]},{var,2380,'OldBoolean'}]},[{type,2381,constraint,[{atom,2381,is_subtype},[{var,2381,'Boolean'},{type,2381,boolean,[]}]]},{type,2382,constraint,[{atom,2382,is_subtype},[{var,2382,'OldBoolean'},{type,2382,boolean,[]}]]}]]}]}}]}},{{function,process_flag,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1685}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,99,101,114,116,97,105,110,32,102,108,97,103,115,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<44,32,105,110,32,116,104,101,32,115,97,109,101,32,109,97,110,110,101,114,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46,32,82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46,32,84,104,101,32,118,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<70,108,97,103>>]},<<32,97,114,101,32,111,110,108,121,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,111,115,101,32,97,108,108,111,119,101,100,32,105,110,32>>,{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]},<<44,32,110,97,109,101,108,121,32>>,{code,[],[<<115,97,118,101,95,99,97,108,108,115>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,57,57>>,signature => [{attribute,1685,spec,{{process_flag,3},[{type,1685,bounded_fun,[{type,1685,'fun',[{type,1685,product,[{var,1685,'Pid'},{var,1685,'Flag'},{var,1685,'Value'}]},{var,1685,'OldValue'}]},[{type,1686,constraint,[{atom,1686,is_subtype},[{var,1686,'Pid'},{type,1686,pid,[]}]]},{type,1687,constraint,[{atom,1687,is_subtype},[{var,1687,'Flag'},{atom,1687,save_calls}]]},{type,1688,constraint,[{atom,1688,is_subtype},[{var,1688,'Value'},{type,1688,non_neg_integer,[]}]]},{type,1689,constraint,[{atom,1689,is_subtype},[{var,1689,'OldValue'},{type,1689,non_neg_integer,[]}]]}]]}]}}]}},{{function,process_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1702}],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,114,101,115,117,108,116,95,105,116,101,109>>}],[]},{li,[{name,<<115,116,97,99,107,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{p,[],[<<84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,105,115,32,117,110,100,101,102,105,110,101,100,32,97,110,100,32,97,108,108,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,97,114,101,32,110,111,116,32,109,97,110,100,97,116,111,114,121,46,32,84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,116,101,109,115,32,97,114,101,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,58>>]},{ul,[],[{li,[],[{code,[],[<<99,117,114,114,101,110,116,95,102,117,110,99,116,105,111,110>>]}]},{li,[],[{code,[],[<<105,110,105,116,105,97,108,95,99,97,108,108>>]}]},{li,[],[{code,[],[<<115,116,97,116,117,115>>]}]},{li,[],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,108,101,110>>]}]},{li,[],[{code,[],[<<108,105,110,107,115>>]}]},{li,[],[{code,[],[<<100,105,99,116,105,111,110,97,114,121>>]}]},{li,[],[{code,[],[<<116,114,97,112,95,101,120,105,116>>]}]},{li,[],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]}]},{li,[],[{code,[],[<<112,114,105,111,114,105,116,121>>]}]},{li,[],[{code,[],[<<103,114,111,117,112,95,108,101,97,100,101,114>>]}]},{li,[],[{code,[],[<<116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<104,101,97,112,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<114,101,100,117,99,116,105,111,110,115>>]}]},{li,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,104,97,115,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,97,108,115,111,32,97,110,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,119,105,116,104,32,105,116,101,109,32>>,{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,105,110,99,108,117,100,101,100,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,112,101,99,105,102,105,99,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>]}]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32>>,{em,[],[<<100,101,98,117,103,103,105,110,103,32,111,110,108,121>>]},<<46,32,70,111,114,32,97,108,108,32,111,116,104,101,114,32,112,117,114,112,111,115,101,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>]}]},<<46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,56,49,52>>,signature => [{attribute,1702,spec,{{process_info,1},[{type,1702,bounded_fun,[{type,1702,'fun',[{type,1702,product,[{var,1702,'Pid'}]},{var,1702,'Info'}]},[{type,1703,constraint,[{atom,1703,is_subtype},[{var,1703,'Pid'},{type,1703,pid,[]}]]},{type,1704,constraint,[{atom,1704,is_subtype},[{var,1704,'Info'},{type,1704,union,[{type,1704,list,[{var,1704,'InfoTuple'}]},{atom,1704,undefined}]}]]},{type,1705,constraint,[{atom,1705,is_subtype},[{var,1705,'InfoTuple'},{user_type,1705,process_info_result_item,[]}]]}]]}]}}]}},{{function,process_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2479}],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,105,116,101,109>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,114,101,115,117,108,116,95,105,116,101,109>>}],[]},{li,[{name,<<115,116,97,99,107,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<32,111,114,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,108,105,118,101,32,97,110,100,32,97,32,115,105,110,103,108,101,32>>,{code,[],[<<73,116,101,109>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<44,32,117,110,108,101,115,115,32>>,{code,[],[<<73,116,101,109,32,61,58,61,32,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,115,116,114,97,110,103,101,32,98,101,104,97,118,105,111,114,32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,104,105,115,116,111,114,105,99,97,108,32,114,101,97,115,111,110,115,44,32,97,110,100,32,105,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<46,32,84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,105,110,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<32,97,114,101,32,105,110,99,108,117,100,101,100,32,119,105,116,104,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,105,110,32,116,104,101,32,115,97,109,101,32,111,114,100,101,114,32,97,115,32,116,104,101,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,119,101,114,101,32,105,110,99,108,117,100,101,100,32,105,110,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46,32,86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,105,110,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32>>,{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,112,97,114,116,32,111,102,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,110,97,109,101,32,114,101,103,105,115,116,101,114,101,100,44,32,97,32>>,{code,[],[<<123,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101,44,32,91,93,125>>]},<<44,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32>>,{em,[],[<<119,105,108,108>>]},<<32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,100,105,102,102,101,114,101,110,116,32,119,104,101,110,32,97,32,115,105,110,103,108,101,32>>,{code,[],[<<73,116,101,109,32,61,58,61,32,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,97,110,100,32,119,104,101,110,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,98,97,99,107,116,114,97,99,101,44,32,66,105,110,125>>]}]},{dd,[],[{p,[],[<<66,105,110,97,114,121,32>>,{code,[],[<<66,105,110>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,115,32,116,104,101,32,111,117,116,112,117,116,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,100,105,115,112,108,97,121,40,80,105,100,44,32,98,97,99,107,116,114,97,99,101,41>>]},<<46,32,85,115,101,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>]},<<32,116,111,32,111,98,116,97,105,110,32,116,104,101,32,115,116,114,105,110,103,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,98,105,110,97,114,121,46>>]}]},{dt,[],[{code,[],[<<123,98,105,110,97,114,121,44,32,66,105,110,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<66,105,110,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,98,105,110,97,114,105,101,115,32,111,110,32,116,104,101,32,104,101,97,112,32,111,102,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,73,110,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32>>,{code,[],[<<66,105,110,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,46,32,84,104,101,32,116,117,112,108,101,115,32,99,111,110,116,97,105,110,59,32>>,{code,[],[<<66,105,110,97,114,121,73,100>>]},<<44,32>>,{code,[],[<<66,105,110,97,114,121,83,105,122,101>>]},<<44,32>>,{code,[],[<<66,105,110,97,114,121,82,101,102,99,67,111,117,110,116>>]},<<46>>]},{p,[],[<<84,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,115,32,111,110,32,116,104,101,32,104,101,97,112,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,99,97,116,99,104,108,101,118,101,108,44,32,67,97,116,99,104,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<67,97,116,99,104,76,101,118,101,108>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,99,117,114,114,101,110,116,108,121,32,97,99,116,105,118,101,32,99,97,116,99,104,101,115,32,105,110,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,102,117,110,99,116,105,111,110,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125,32,124,32,117,110,100,101,102,105,110,101,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,118,97,108,117,101,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,99,117,114,114,101,110,116,108,121,32,101,120,101,99,117,116,105,110,103,32,110,97,116,105,118,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,108,111,99,97,116,105,111,110,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,44,32,76,111,99,97,116,105,111,110,125,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,108,111,99,97,116,105,111,110,32,105,110,32,116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,115,116,97,99,107,116,114,97,99,101,44,32,83,116,97,99,107,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,32,40>>,{em,[],[<<115,116,97,99,107,116,114,97,99,101>>]},<<41,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,115,116,97,99,107,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,115,32,105,110,32,116,104,101,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,112,97,114,116,32,111,102,32,97,32>>,{code,[],[<<116,114,121>>]},<<46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115,35,115,116,97,99,107,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<84,104,101,32,99,97,108,108,45,115,116,97,99,107,32,98,97,99,107,32,116,114,97,99,101,32,40,115,116,97,99,107,116,114,97,99,101,41>>]},<<46,32,84,104,101,32,100,101,112,116,104,32,111,102,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,32,105,115,32,116,114,117,110,99,97,116,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{code,[],[<<98,97,99,107,116,114,97,99,101,95,100,101,112,116,104>>]},<<32,115,121,115,116,101,109,32,102,108,97,103,32,115,101,116,116,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,100,105,99,116,105,111,110,97,114,121,44,32,68,105,99,116,105,111,110,97,114,121,125>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,99,116,105,111,110,97,114,121>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,95,104,97,110,100,108,101,114,44,32,77,111,100,117,108,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,109,111,100,117,108,101,32,117,115,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,40,102,111,114,32,117,110,100,101,102,105,110,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,102,111,114,32,101,120,97,109,112,108,101,41,46>>]}]},{dt,[],[{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,44,32,71,67,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,67,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32>>,{code,[],[<<71,67,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111>>}],[]},{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111,44,32,71,67,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,67,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,100,101,116,97,105,108,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32>>,{code,[],[<<71,67,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,70,111,114,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,101,97,99,104,32,105,116,101,109,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,103,114,111,117,112,95,108,101,97,100,101,114,44,32,71,114,111,117,112,76,101,97,100,101,114,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,114,111,117,112,76,101,97,100,101,114>>]},<<32,105,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,102,111,114,32,116,104,101,32,73,47,79,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,119,111,114,100,115,32,111,102,32,116,104,101,32,121,111,117,110,103,101,115,116,32,104,101,97,112,32,103,101,110,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,103,101,110,101,114,97,116,105,111,110,32,105,110,99,108,117,100,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,46,32,84,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,44,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,102,32,116,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,99,104,97,110,103,101,115,46>>]}]},{dt,[],[{code,[],[<<123,105,110,105,116,105,97,108,95,99,97,108,108,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,105,110,105,116,105,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,119,105,116,104,32,119,104,105,99,104,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,115,112,97,119,110,101,100,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,107,115,44,32,80,105,100,115,65,110,100,80,111,114,116,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,105,100,115,65,110,100,80,111,114,116,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,97,110,100,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,119,105,116,104,32,112,114,111,99,101,115,115,101,115,32,111,114,32,112,111,114,116,115,32,116,111,32,119,104,105,99,104,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,97,32,108,105,110,107,46>>]}]},{dt,[],[{code,[],[<<123,108,97,115,116,95,99,97,108,108,115,44,32,102,97,108,115,101,124,67,97,108,108,115,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,110,111,116,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,51>>]}]},<<41,46,32,73,102,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,97,99,116,105,118,101,44,32,97,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,44,32,105,110,32,119,104,105,99,104,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,99,97,108,108,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,101,109,111,114,121,44,32,83,105,122,101,125>>]}]},{dd,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,109,101,109,111,114,121>>}],[]},{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,121,116,101,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,99,97,108,108,32,115,116,97,99,107,44,32,104,101,97,112,44,32,97,110,100,32,105,110,116,101,114,110,97,108,32,115,116,114,117,99,116,117,114,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,108,101,110,44,32,77,101,115,115,97,103,101,81,117,101,117,101,76,101,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101,76,101,110>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,109,101,115,115,97,103,101,115,32,99,117,114,114,101,110,116,108,121,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101>>]},<<32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,116,101,109,32>>,{code,[],[<<109,101,115,115,97,103,101,115>>]},<<32,40,115,101,101,32,98,101,108,111,119,41,46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,115,44,32,77,101,115,115,97,103,101,81,117,101,117,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,44,32,119,104,105,99,104,32,104,97,118,101,32,110,111,116,32,121,101,116,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,77,105,110,72,101,97,112,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,105,110,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,77,105,110,66,105,110,86,72,101,97,112,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,105,110,66,105,110,86,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,101,100,95,98,121,44,32,77,111,110,105,116,111,114,101,100,66,121,125>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,105,100,101,110,116,105,102,105,101,114,115,32,102,111,114,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,44,32,112,111,114,116,115,32,97,110,100,32,78,73,70,32,114,101,115,111,117,114,99,101,115,44,32,116,104,97,116,32,97,114,101,32,109,111,110,105,116,111,114,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,115,44,32,77,111,110,105,116,111,114,115,125>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,111,110,105,116,111,114,115,32,40,115,116,97,114,116,101,100,32,98,121,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<41,32,116,104,97,116,32,97,114,101,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,70,111,114,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,32,111,114,32,97,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,32,98,121,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,101,32,108,105,115,116,32,99,111,110,115,105,115,116,115,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,114,111,99,101,115,115,44,32,80,105,100,125>>]}]},{dd,[],[<<80,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,112,105,100,46>>]},{dt,[],[{code,[],[<<123,112,114,111,99,101,115,115,44,32,123,82,101,103,78,97,109,101,44,32,78,111,100,101,125,125>>]}]},{dd,[],[<<76,111,99,97,108,32,111,114,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,46>>]},{dt,[],[{code,[],[<<123,112,111,114,116,44,32,80,111,114,116,73,100,125>>]}]},{dd,[],[<<76,111,99,97,108,32,112,111,114,116,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,112,111,114,116,32,105,100,46>>]},{dt,[],[{code,[],[<<123,112,111,114,116,44,32,123,82,101,103,78,97,109,101,44,32,78,111,100,101,125,125>>]}]},{dd,[],[<<76,111,99,97,108,32,112,111,114,116,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,46,32,80,108,101,97,115,101,32,110,111,116,101,44,32,116,104,97,116,32,114,101,109,111,116,101,32,112,111,114,116,32,109,111,110,105,116,111,114,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,44,32,115,111,32>>,{code,[],[<<78,111,100,101>>]},<<32,119,105,108,108,32,97,108,119,97,121,115,32,98,101,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,110,97,109,101,46>>]}]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,116,101,32,111,102,32,112,114,111,99,101,115,115,32,102,108,97,103,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<46,32>>,{code,[],[<<77,81,68>>]},<<32,105,115,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<76,101,118,101,108>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,105,111,114,105,116,105,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,100,117,99,116,105,111,110,115,44,32,78,117,109,98,101,114,125>>]}]},{dd,[],[{p,[],[{code,[],[<<78,117,109,98,101,114>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,101,120,101,99,117,116,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101,44,32,65,116,111,109,125>>]}]},{dd,[],[{p,[],[{code,[],[<<65,116,111,109>>]},<<32,105,115,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,32,110,97,109,101,46,32,73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,116,104,105,115,32,116,117,112,108,101,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,46>>]}]},{dt,[],[{code,[],[<<123,115,101,113,117,101,110,116,105,97,108,95,116,114,97,99,101,95,116,111,107,101,110,44,32,91,93,32,124,32,83,101,113,117,101,110,116,105,97,108,84,114,97,99,101,84,111,107,101,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,101,113,117,101,110,116,105,97,108,84,114,97,99,101,84,111,107,101,110>>]},<<32,105,115,32,116,104,101,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,116,111,107,101,110,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,115,116,97,99,107,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,116,97,99,107,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,44,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,115,116,97,116,117,115,44,32,83,116,97,116,117,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,116,97,116,117,115>>]},<<32,105,115,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,97,110,100,32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<101,120,105,116,105,110,103>>]}]},{li,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,110,103>>]}]},{li,[],[{code,[],[<<119,97,105,116,105,110,103>>]},<<32,40,102,111,114,32,97,32,109,101,115,115,97,103,101,41>>]},{li,[],[{code,[],[<<114,117,110,110,105,110,103>>]}]},{li,[],[{code,[],[<<114,117,110,110,97,98,108,101>>]},<<32,40,114,101,97,100,121,32,116,111,32,114,117,110,44,32,98,117,116,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,105,115,32,114,117,110,110,105,110,103,41>>]},{li,[],[{code,[],[<<115,117,115,112,101,110,100,101,100>>]},<<32,40,115,117,115,112,101,110,100,101,100,32,111,110,32,97,32,34,98,117,115,121,34,32,112,111,114,116,32,111,114,32,98,121,32,116,104,101,32,66,73,70,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49,44,50>>]},<<41>>]}]}]},{dt,[],[{code,[],[<<123,115,117,115,112,101,110,100,105,110,103,44,32,83,117,115,112,101,110,100,101,101,76,105,115,116,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101,76,105,115,116>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,83,117,115,112,101,110,100,101,101,44,32,65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116,44,32,79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116,125>>]},<<32,116,117,112,108,101,115,46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,98,101,101,110,44,32,111,114,32,105,115,32,116,111,32,98,101,44,32,115,117,115,112,101,110,100,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,116,104,114,111,117,103,104,32,116,104,101,32,66,73,70,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>]}]},<<46>>]},{p,[],[{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,110,111,116,32,121,101,116,32,99,111,109,112,108,101,116,101,100,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,115,32,115,101,110,116,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116,32,61,47,61,32,48>>]},<<44,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,99,117,114,114,101,110,116,108,121,32,105,110,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116,32,61,47,61,32,48>>]},<<44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,104,97,115,32,98,101,101,110,32,117,115,101,100,32,97,110,100,32,116,104,101,32,115,117,115,112,101,110,100,101,101,32,104,97,115,32,110,111,116,32,121,101,116,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,97,114,101,32,110,111,116,32,116,104,101,32,116,111,116,97,108,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<44,32,111,110,108,121,32,116,104,101,32,112,97,114,116,115,32,99,111,110,116,114,105,98,117,116,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<123,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,44,32,111,102,32,97,108,108,32,104,101,97,112,32,102,114,97,103,109,101,110,116,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,32,97,110,100,32,97,110,121,32,117,110,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,44,32,73,110,116,101,114,110,97,108,84,114,97,99,101,70,108,97,103,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,116,101,114,110,97,108,84,114,97,99,101,70,108,97,103,115>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,105,110,116,101,114,110,97,108,32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,112,95,101,120,105,116,44,32,66,111,111,108,101,97,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<66,111,111,108,101,97,110>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,110,111,116,32,97,108,108,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,32,115,117,112,112,111,114,116,32,97,108,108,32,116,104,101,115,101,32>>,{code,[],[<<73,116,101,109>>]},<<115,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<73,116,101,109>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,105,116,101,109,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,56,54,53>>,signature => [{attribute,2479,spec,{{process_info,2},[{type,2479,bounded_fun,[{type,2479,'fun',[{type,2479,product,[{var,2479,'Pid'},{var,2479,'Item'}]},{type,2480,union,[{var,2480,'InfoTuple'},{type,2480,nil,[]},{atom,2480,undefined}]}]},[{type,2481,constraint,[{atom,2481,is_subtype},[{var,2481,'Pid'},{type,2481,pid,[]}]]},{type,2482,constraint,[{atom,2482,is_subtype},[{var,2482,'Item'},{user_type,2482,process_info_item,[]}]]},{type,2483,constraint,[{atom,2483,is_subtype},[{var,2483,'InfoTuple'},{user_type,2483,process_info_result_item,[]}]]}]]},{type,2484,bounded_fun,[{type,2484,'fun',[{type,2484,product,[{var,2484,'Pid'},{var,2484,'ItemList'}]},{type,2484,union,[{var,2484,'InfoTupleList'},{type,2484,nil,[]},{atom,2484,undefined}]}]},[{type,2485,constraint,[{atom,2485,is_subtype},[{var,2485,'Pid'},{type,2485,pid,[]}]]},{type,2486,constraint,[{atom,2486,is_subtype},[{var,2486,'ItemList'},{type,2486,list,[{var,2486,'Item'}]}]]},{type,2487,constraint,[{atom,2487,is_subtype},[{var,2487,'Item'},{user_type,2487,process_info_item,[]}]]},{type,2488,constraint,[{atom,2488,is_subtype},[{var,2488,'InfoTupleList'},{type,2488,list,[{var,2488,'InfoTuple'}]}]]},{type,2489,constraint,[{atom,2489,is_subtype},[{var,2489,'InfoTuple'},{user_type,2489,process_info_result_item,[]}]]}]]}]}}]}},{{function,processes,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1710}],[<<112,114,111,99,101,115,115,101,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,32,101,120,105,115,116,115,44,32,98,117,116,32,105,115,32,110,111,116,32,97,108,105,118,101,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,102,111,114,32,97,110,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,44,32,98,117,116,32,105,116,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115,47,48>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,114,111,99,101,115,115,101,115,40,41,46,10,91,60,48,46,48,46,48,62,44,60,48,46,50,46,48,62,44,60,48,46,52,46,48,62,44,60,48,46,53,46,48,62,44,60,48,46,55,46,48,62,44,60,48,46,56,46,48,62,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,48,51>>,signature => [{attribute,1710,spec,{{processes,0},[{type,1710,'fun',[{type,1710,product,[]},{type,1710,list,[{type,1710,pid,[]}]}]}]}}]}},{{function,purge_module,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1715}],[<<112,117,114,103,101,95,109,111,100,117,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,66,101,102,111,114,101,32,116,104,105,115,32,66,73,70,32,105,115,32,117,115,101,100,44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>]}]},<<32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,116,111,32,99,104,101,99,107,32,116,104,97,116,32,110,111,32,112,114,111,99,101,115,115,101,115,32,101,120,101,99,117,116,101,32,111,108,100,32,99,111,100,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,56,46,48,32,40,69,114,108,97,110,103,47,79,84,80,32,49,57,41,44,32,97,110,121,32,108,105,110,103,101,114,105,110,103,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,115,116,105,108,108,32,101,120,101,99,117,116,101,32,116,104,101,32,111,108,100,32,99,111,100,101,32,105,115,32,107,105,108,108,101,100,32,98,121,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,73,110,32,101,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,44,32,115,117,99,104,32,105,110,99,111,114,114,101,99,116,32,117,115,101,32,99,111,117,108,100,32,99,97,117,115,101,32,109,117,99,104,32,109,111,114,101,32,102,97,116,97,108,32,102,97,105,108,117,114,101,115,44,32,108,105,107,101,32,101,109,117,108,97,116,111,114,32,99,114,97,115,104,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,50,48>>,signature => [{attribute,1715,spec,{{purge_module,1},[{type,1715,bounded_fun,[{type,1715,'fun',[{type,1715,product,[{var,1715,'Module'}]},{atom,1715,true}]},[{type,1716,constraint,[{atom,1716,is_subtype},[{var,1716,'Module'},{type,1716,atom,[]}]]}]]}]}}]}},{{function,put,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1729}],[<<112,117,116,47,50>>],#{<<101,110>> => [{p,[],[<<65,100,100,115,32,97,32,110,101,119,32>>,{code,[],[<<75,101,121>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,44,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<44,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46,32,73,102,32>>,{code,[],[<<75,101,121>>]},<<32,101,120,105,115,116,115,44,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,105,115,32,100,101,108,101,116,101,100,32,97,110,100,32,114,101,112,108,97,99,101,100,32,98,121,32>>,{code,[],[<<86,97,108>>]},<<44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,46,32,84,104,101,32,97,118,101,114,97,103,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,88,32,61,32,112,117,116,40,110,97,109,101,44,32,119,97,108,114,117,115,41,44,32,89,32,61,32,112,117,116,40,110,97,109,101,44,32,99,97,114,112,101,110,116,101,114,41,44,10,90,32,61,32,103,101,116,40,110,97,109,101,41,44,10,123,88,44,32,89,44,32,90,125,46,10,123,117,110,100,101,102,105,110,101,100,44,119,97,108,114,117,115,44,99,97,114,112,101,110,116,101,114,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,118,97,108,117,101,115,32,115,116,111,114,101,100,32,119,104,101,110,32>>,{code,[],[<<112,117,116>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,116,104,101,32,115,99,111,112,101,32,111,102,32,97,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,97,114,101,32,110,111,116,32,114,101,116,114,97,99,116,101,100,32,105,102,32,97,32>>,{code,[],[<<116,104,114,111,119>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,44,32,111,114,32,105,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,52,53>>,signature => [{attribute,1729,spec,{{put,2},[{type,1729,bounded_fun,[{type,1729,'fun',[{type,1729,product,[{var,1729,'Key'},{var,1729,'Val'}]},{type,1729,term,[]}]},[{type,1730,constraint,[{atom,1730,is_subtype},[{var,1730,'Key'},{type,1730,term,[]}]]},{type,1731,constraint,[{atom,1731,is_subtype},[{var,1731,'Val'},{type,1731,term,[]}]]}]]}]}}]}},{{function,raise,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1736}],[<<114,97,105,115,101,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<114,97,105,115,101,95,115,116,97,99,107,116,114,97,99,101>>}],[]}]},{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,99,108,97,115,115,44,32,114,101,97,115,111,110,44,32,97,110,100,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,116,114,97,99,101,32,40>>,{em,[],[<<115,116,97,99,107,116,114,97,99,101>>]},<<41,46>>]},{p,[],[{code,[],[<<67,108,97,115,115>>]},<<32,105,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<44,32>>,{code,[],[<<101,120,105,116>>]},<<44,32,111,114,32>>,{code,[],[<<116,104,114,111,119>>]},<<46,32,83,111,44,32,105,102,32,105,116,32,119,101,114,101,32,110,111,116,32,102,111,114,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,44,32>>,{code,[],[<<101,114,108,97,110,103,58,114,97,105,115,101,40,67,108,97,115,115,44,32,82,101,97,115,111,110,44,32,83,116,97,99,107,116,114,97,99,101,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,67,108,97,115,115,40,82,101,97,115,111,110,41>>]},<<32,40,103,105,118,101,110,32,116,104,97,116,32>>,{code,[],[<<67,108,97,115,115>>]},<<32,105,115,32,97,32,118,97,108,105,100,32,99,108,97,115,115,41,46>>]},{p,[],[{code,[],[<<82,101,97,115,111,110>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,46>>]},{p,[],[{code,[],[<<83,116,97,99,107,116,114,97,99,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,97,115,32,112,114,111,118,105,100,101,100,32,105,110,32,97,32,116,114,121,45,99,97,116,99,104,32,99,108,97,117,115,101,46>>]},{pre,[],[{code,[],[<<116,114,121,10,32,32,32,32,46,46,46,10,99,97,116,99,104,32,67,108,97,115,115,58,82,101,97,115,111,110,58,83,116,97,99,107,116,114,97,99,101,32,45,62,10,32,32,32,32,46,46,46,10,101,110,100>>]}]},{p,[],[<<84,104,97,116,32,105,115,44,32,97,32,108,105,115,116,32,111,102,32,102,111,117,114,45,116,117,112,108,101,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,32,124,32,65,114,103,115,44,32,76,111,99,97,116,105,111,110,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,97,110,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,97,114,101,32,97,116,111,109,115,44,32,97,110,100,32,116,104,101,32,116,104,105,114,100,32,101,108,101,109,101,110,116,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,97,114,105,116,121,32,111,114,32,97,110,32,97,114,103,117,109,101,110,116,32,108,105,115,116,46,32,84,104,101,32,115,116,97,99,107,116,114,97,99,101,32,99,97,110,32,97,108,115,111,32,99,111,110,116,97,105,110,32>>,{code,[],[<<123,70,117,110,44,32,65,114,103,115,44,32,76,111,99,97,116,105,111,110,125>>]},<<32,116,117,112,108,101,115,44,32,119,104,101,114,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,32,97,110,100,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,97,110,32,97,114,103,117,109,101,110,116,32,108,105,115,116,46>>]},{p,[],[<<69,108,101,109,101,110,116,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,97,116,32,116,104,101,32,101,110,100,32,105,115,32,111,112,116,105,111,110,97,108,46,32,79,109,105,116,116,105,110,103,32,105,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,112,101,99,105,102,121,105,110,103,32,97,110,32,101,109,112,116,121,32,108,105,115,116,46>>]},{p,[],[<<84,104,101,32,115,116,97,99,107,116,114,97,99,101,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,115,116,97,99,107,116,114,97,99,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,59,32,105,116,32,105,115,32,116,114,117,110,99,97,116,101,100,32,116,111,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,120,105,109,117,109,32,115,116,97,99,107,116,114,97,99,101,32,100,101,112,116,104,46>>]},{p,[],[<<65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,111,32,116,101,114,109,105,110,97,116,101,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,32,117,110,108,101,115,115,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,105,110,118,97,108,105,100,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{em,[],[<<114,101,116,117,114,110,115,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110>>]},<<32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,98,101,32,115,117,114,101,32,110,111,116,32,116,111,32,114,101,116,117,114,110,44,32,121,111,117,32,99,97,110,32,99,97,108,108,32>>,{code,[],[<<101,114,114,111,114,40,101,114,108,97,110,103,58,114,97,105,115,101,40,67,108,97,115,115,44,32,82,101,97,115,111,110,44,32,83,116,97,99,107,116,114,97,99,101,41,41>>]},<<32,97,110,100,32,104,111,112,101,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,101,120,99,101,112,116,105,111,110,115,32,108,97,116,101,114,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,109,97,110,117,97,108,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,101,115,32,97,110,100,32,104,111,119,32,116,111,32,99,97,116,99,104,32,101,120,99,101,112,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,55,49>>,signature => [{attribute,1736,spec,{{erlang,raise,3},[{type,1736,bounded_fun,[{type,1736,'fun',[{type,1736,product,[{var,1736,'Class'},{var,1736,'Reason'},{var,1736,'Stacktrace'}]},{atom,1736,badarg}]},[{type,1737,constraint,[{atom,1737,is_subtype},[{var,1737,'Class'},{type,1737,union,[{atom,1737,error},{atom,1737,exit},{atom,1737,throw}]}]]},{type,1738,constraint,[{atom,1738,is_subtype},[{var,1738,'Reason'},{type,1738,term,[]}]]},{type,1739,constraint,[{atom,1739,is_subtype},[{var,1739,'Stacktrace'},{user_type,1739,raise_stacktrace,[]}]]}]]}]}}]}},{{function,read_timer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1744}],[<<114,101,97,100,95,116,105,109,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,40,84,105,109,101,114,82,101,102,44,32,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,50,49>>,signature => [{attribute,1744,spec,{{erlang,read_timer,1},[{type,1744,bounded_fun,[{type,1744,'fun',[{type,1744,product,[{var,1744,'TimerRef'}]},{var,1744,'Result'}]},[{type,1745,constraint,[{atom,1745,is_subtype},[{var,1745,'TimerRef'},{type,1745,reference,[]}]]},{type,1746,constraint,[{atom,1746,is_subtype},[{var,1746,'Time'},{type,1746,non_neg_integer,[]}]]},{type,1747,constraint,[{atom,1747,is_subtype},[{var,1747,'Result'},{type,1747,union,[{var,1747,'Time'},{atom,1747,false}]}]]}]]}]}}]}},{{function,read_timer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1753}],[<<114,101,97,100,95,116,105,109,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,97,32,116,105,109,101,114,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,32,98,121,32,101,105,116,104,101,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114>>]}]},<<46,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,105,100,101,110,116,105,102,105,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,119,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,66,73,70,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,116,105,109,101,114,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,65,115,121,110,99,125>>]}]},{dd,[],[{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,115,116,97,116,101,32,105,110,102,111,114,109,97,116,105,111,110,46,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,32,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<46,32,87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<32,115,101,110,100,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,116,104,101,32,115,116,97,116,101,32,105,110,102,111,114,109,97,116,105,111,110,32,116,111,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<46,32,65,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,114,101,97,100,95,116,105,109,101,114,44,32,84,105,109,101,114,82,101,102,44,32,82,101,115,117,108,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<32,119,104,101,110,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,46>>]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,105,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32,108,101,102,116,32,117,110,116,105,108,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,97,32,116,105,109,101,114,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,102,111,117,110,100,46,32,84,104,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,111,114,32,98,101,101,110,32,99,97,110,99,101,108,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,110,101,118,101,114,32,104,97,115,32,99,111,114,114,101,115,112,111,110,100,101,100,32,116,111,32,97,32,116,105,109,101,114,46,32,69,118,101,110,32,105,102,32,116,104,101,32,116,105,109,101,114,32,104,97,115,32,101,120,112,105,114,101,100,44,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,108,108,32,121,111,117,32,119,104,101,116,104,101,114,32,111,114,32,110,111,116,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,32,104,97,115,32,97,114,114,105,118,101,100,32,97,116,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,32,121,101,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,32,99,97,110,32,98,101,32,99,111,45,108,111,99,97,116,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32,115,99,104,101,100,117,108,101,114,32,116,104,97,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32,73,102,32,115,111,44,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,116,105,109,101,32,116,104,97,110,32,105,102,32,105,116,32,105,115,32,108,111,99,97,116,101,100,32,108,111,99,97,108,108,121,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,105,110,32,97,32,99,114,105,116,105,99,97,108,32,112,97,116,104,44,32,97,110,100,32,99,97,110,32,100,111,32,111,116,104,101,114,32,116,104,105,110,103,115,32,119,104,105,108,101,32,119,97,105,116,105,110,103,32,102,111,114,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,44,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,116,114,117,101,125>>]},<<46,32,73,102,32,117,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,102,97,108,115,101,125>>]},<<44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,98,108,111,99,107,101,100,32,117,110,116,105,108,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,51,49>>,signature => [{attribute,1753,spec,{{erlang,read_timer,2},[{type,1753,bounded_fun,[{type,1753,'fun',[{type,1753,product,[{var,1753,'TimerRef'},{var,1753,'Options'}]},{type,1753,union,[{var,1753,'Result'},{atom,1753,ok}]}]},[{type,1754,constraint,[{atom,1754,is_subtype},[{var,1754,'TimerRef'},{type,1754,reference,[]}]]},{type,1755,constraint,[{atom,1755,is_subtype},[{var,1755,'Async'},{type,1755,boolean,[]}]]},{type,1756,constraint,[{atom,1756,is_subtype},[{var,1756,'Option'},{type,1756,tuple,[{atom,1756,async},{var,1756,'Async'}]}]]},{type,1757,constraint,[{atom,1757,is_subtype},[{var,1757,'Options'},{type,1757,list,[{var,1757,'Option'}]}]]},{type,1758,constraint,[{atom,1758,is_subtype},[{var,1758,'Time'},{type,1758,non_neg_integer,[]}]]},{type,1759,constraint,[{atom,1759,is_subtype},[{var,1759,'Result'},{type,1759,union,[{var,1759,'Time'},{atom,1759,false}]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,ref_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1765}],[<<114,101,102,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<82,101,102>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,56,55>>,signature => [{attribute,1765,spec,{{ref_to_list,1},[{type,1765,bounded_fun,[{type,1765,'fun',[{type,1765,product,[{var,1765,'Ref'}]},{type,1765,string,[]}]},[{type,1766,constraint,[{atom,1766,is_subtype},[{var,1766,'Ref'},{type,1766,reference,[]}]]}]]}]}}]}},{{function,register,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1771}],[<<114,101,103,105,115,116,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<65,115,115,111,99,105,97,116,101,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,119,105,116,104,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,46,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<44,32,119,104,105,99,104,32,109,117,115,116,32,98,101,32,97,110,32,97,116,111,109,44,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,112,105,100,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,105,110,32,115,101,110,100,32,111,112,101,114,97,116,111,114,32,40>>,{code,[],[<<82,101,103,78,97,109,101,32,33,32,77,101,115,115,97,103,101>>]},<<41,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,114,101,103,105,115,116,101,114,40,100,98,44,32,80,105,100,41,46,10,116,114,117,101>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,97,108,114,101,97,100,121,32,105,110,32,117,115,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,115,32,97,108,114,101,97,100,121,32,114,101,103,105,115,116,101,114,101,100,32,40,97,108,114,101,97,100,121,32,104,97,115,32,97,32,110,97,109,101,41,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,48,48>>,signature => [{attribute,1771,spec,{{register,2},[{type,1771,bounded_fun,[{type,1771,'fun',[{type,1771,product,[{var,1771,'RegName'},{var,1771,'PidOrPort'}]},{atom,1771,true}]},[{type,1772,constraint,[{atom,1772,is_subtype},[{var,1772,'RegName'},{type,1772,atom,[]}]]},{type,1773,constraint,[{atom,1773,is_subtype},[{var,1773,'PidOrPort'},{type,1773,union,[{type,1773,port,[]},{type,1773,pid,[]}]}]]}]]}]}}]}},{{function,registered,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1778}],[<<114,101,103,105,115,116,101,114,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,110,97,109,101,115,32,116,104,97,116,32,104,97,118,101,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,103,105,115,116,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,103,105,115,116,101,114,47,50>>]}]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,114,101,103,105,115,116,101,114,101,100,40,41,46,10,91,99,111,100,101,95,115,101,114,118,101,114,44,32,102,105,108,101,95,115,101,114,118,101,114,44,32,105,110,105,116,44,32,117,115,101,114,44,32,109,121,95,100,98,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,50,57>>,signature => [{attribute,1778,spec,{{registered,0},[{type,1778,bounded_fun,[{type,1778,'fun',[{type,1778,product,[]},{type,1778,list,[{var,1778,'RegName'}]}]},[{type,1779,constraint,[{atom,1779,is_subtype},[{var,1779,'RegName'},{type,1779,atom,[]}]]}]]}]}}]}},{{function,resume_process,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1784}],[<<114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,99,114,101,97,115,101,115,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,112,114,101,118,105,111,117,115,108,121,32,116,111,32,104,97,118,101,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,116,104,114,111,117,103,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>]}]},<<32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<46,32,87,104,101,110,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,97,99,104,101,115,32,122,101,114,111,44,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,114,101,115,117,109,101,100,44,32,116,104,97,116,32,105,115,44,32,105,116,115,32,115,116,97,116,101,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32,115,117,115,112,101,110,100,101,100,32,105,110,116,111,32,116,104,101,32,115,116,97,116,101,32,105,116,32,104,97,100,32,98,101,102,111,114,101,32,105,116,32,119,97,115,32,115,117,115,112,101,110,100,101,100,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>]},<<32,104,97,100,32,110,111,116,32,112,114,101,118,105,111,117,115,108,121,32,105,110,99,114,101,97,115,101,100,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,52,50>>,signature => [{attribute,1784,spec,{{erlang,resume_process,1},[{type,1784,bounded_fun,[{type,1784,'fun',[{type,1784,product,[{var,1784,'Suspendee'}]},{atom,1784,true}]},[{type,1785,constraint,[{atom,1785,is_subtype},[{var,1785,'Suspendee'},{type,1785,pid,[]}]]}]]}]}}]}},{{function,round,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1791}],[<<114,111,117,110,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,98,121,32,114,111,117,110,100,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,111,117,110,100,40,52,50,46,49,41,46,10,52,50>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,53,46,53,41,46,10,54>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,45,53,46,53,41,46,10,45,54>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41,46,10,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<114,111,117,110,100,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,116,104,97,116,32,116,104,101,32,110,117,109,98,101,114,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,73,110,115,116,101,97,100,44,32,116,104,101,32,102,108,111,97,116,32,108,105,116,101,114,97,108,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56,46,48>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,99,108,111,115,101,115,116,32,110,117,109,98,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,56,51>>,signature => [{attribute,1791,spec,{{round,1},[{type,1791,bounded_fun,[{type,1791,'fun',[{type,1791,product,[{var,1791,'Number'}]},{type,1791,integer,[]}]},[{type,1792,constraint,[{atom,1792,is_subtype},[{var,1792,'Number'},{type,1792,number,[]}]]}]]}]}}]}},{{function,self,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1798}],[<<115,101,108,102,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,101,108,102,40,41,46,10,60,48,46,50,54,46,48,62>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,49,52>>,signature => [{attribute,1798,spec,{{self,0},[{type,1798,'fun',[{type,1798,product,[]},{type,1798,pid,[]}]}]}}]}},{{function,send,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2493}],[<<115,101,110,100,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,115,116>>}],[]}]},{p,[],[<<83,101,110,100,115,32,97,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<77,115,103>>]},<<46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,115,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,101,110,100,32,111,112,101,114,97,116,111,114>>]},<<58,32>>,{code,[],[<<68,101,115,116,32,33,32,77,115,103>>]},<<46>>]},{p,[],[{code,[],[<<68,101,115,116>>]},<<32,99,97,110,32,98,101,32,97,32,114,101,109,111,116,101,32,111,114,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,32,40,108,111,99,97,108,41,32,112,111,114,116,44,32,97,32,108,111,99,97,108,108,121,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,97,116,32,97,110,111,116,104,101,114,32,110,111,100,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,114,117,110,45,116,105,109,101,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32,97,116,111,109,32,110,97,109,101,44,32,98,117,116,32,116,104,105,115,32,110,97,109,101,32,105,115,32,110,111,116,32,114,101,103,105,115,116,101,114,101,100,46,32,84,104,105,115,32,105,115,32,116,104,101,32,111,110,108,121,32,99,97,115,101,32,119,104,101,110,32>>,{code,[],[<<115,101,110,100>>]},<<32,102,97,105,108,115,32,102,111,114,32,97,110,32,117,110,114,101,97,99,104,97,98,108,101,32,100,101,115,116,105,110,97,116,105,111,110,32>>,{code,[],[<<68,101,115,116>>]},<<32,40,111,102,32,99,111,114,114,101,99,116,32,116,121,112,101,41,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,50,55>>,signature => [{attribute,2493,spec,{{erlang,send,2},[{type,2493,bounded_fun,[{type,2493,'fun',[{type,2493,product,[{var,2493,'Dest'},{var,2493,'Msg'}]},{var,2493,'Msg'}]},[{type,2494,constraint,[{atom,2494,is_subtype},[{var,2494,'Dest'},{user_type,2494,dst,[]}]]},{type,2495,constraint,[{atom,2495,is_subtype},[{var,2495,'Msg'},{type,2495,term,[]}]]}]]}]}}]}},{{function,send,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2499}],[<<115,101,110,100,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,115,116>>}],[]}]},{p,[],[<<69,105,116,104,101,114,32,115,101,110,100,115,32,97,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<44,32,111,114,32,100,111,101,115,32,110,111,116,32,115,101,110,100,32,116,104,101,32,109,101,115,115,97,103,101,32,98,117,116,32,114,101,116,117,114,110,115,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,40,115,101,101,32,98,101,108,111,119,41,46,32,79,116,104,101,114,119,105,115,101,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,47,50>>]}]},<<46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,101,100,32,101,120,112,108,97,110,97,116,105,111,110,32,97,110,100,32,119,97,114,110,105,110,103,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50,44,51>>]}]},<<46>>]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,115,117,115,112,101,110,100>>]}]},{dd,[],[<<73,102,32,116,104,101,32,115,101,110,100,101,114,32,119,111,117,108,100,32,104,97,118,101,32,116,111,32,98,101,32,115,117,115,112,101,110,100,101,100,32,116,111,32,100,111,32,116,104,101,32,115,101,110,100,44,32>>,{code,[],[<<110,111,115,117,115,112,101,110,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]},{dt,[],[{code,[],[<<110,111,99,111,110,110,101,99,116>>]}]},{dd,[],[<<73,102,32,116,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,110,111,100,101,32,119,111,117,108,100,32,104,97,118,101,32,116,111,32,98,101,32,97,117,116,111,45,99,111,110,110,101,99,116,101,100,32,116,111,32,100,111,32,116,104,101,32,115,101,110,100,44,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<65,115,32,119,105,116,104,32>>,{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50,44,51>>]},<<58,32,117,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,52,55>>,signature => [{attribute,2499,spec,{{erlang,send,3},[{type,2499,bounded_fun,[{type,2499,'fun',[{type,2499,product,[{var,2499,'Dest'},{var,2499,'Msg'},{var,2499,'Options'}]},{var,2499,'Res'}]},[{type,2500,constraint,[{atom,2500,is_subtype},[{var,2500,'Dest'},{user_type,2500,dst,[]}]]},{type,2501,constraint,[{atom,2501,is_subtype},[{var,2501,'Msg'},{type,2501,term,[]}]]},{type,2502,constraint,[{atom,2502,is_subtype},[{var,2502,'Options'},{type,2502,list,[{type,2502,union,[{atom,2502,nosuspend},{atom,2502,noconnect}]}]}]]},{type,2503,constraint,[{atom,2503,is_subtype},[{var,2503,'Res'},{type,2503,union,[{atom,2503,ok},{atom,2503,nosuspend},{atom,2503,noconnect}]}]]}]]}]}}]}},{{function,send_after,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1803}],[<<115,101,110,100,95,97,102,116,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,40,84,105,109,101,44,32,68,101,115,116,44,32,77,115,103,44,32,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,55,57>>,signature => [{attribute,1803,spec,{{erlang,send_after,3},[{type,1803,bounded_fun,[{type,1803,'fun',[{type,1803,product,[{var,1803,'Time'},{var,1803,'Dest'},{var,1803,'Msg'}]},{var,1803,'TimerRef'}]},[{type,1804,constraint,[{atom,1804,is_subtype},[{var,1804,'Time'},{type,1804,non_neg_integer,[]}]]},{type,1805,constraint,[{atom,1805,is_subtype},[{var,1805,'Dest'},{type,1805,union,[{type,1805,pid,[]},{type,1805,atom,[]}]}]]},{type,1806,constraint,[{atom,1806,is_subtype},[{var,1806,'Msg'},{type,1806,term,[]}]]},{type,1807,constraint,[{atom,1807,is_subtype},[{var,1807,'TimerRef'},{type,1807,reference,[]}]]}]]}]}}]}},{{function,send_after,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1813}],[<<115,101,110,100,95,97,102,116,101,114,47,52>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,87,104,101,110,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,101,115,116>>]},<<46,32,65,112,97,114,116,32,102,114,111,109,32,116,104,101,32,102,111,114,109,97,116,32,111,102,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,111,114,107,115,32,101,120,97,99,116,108,121,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,57,48>>,signature => [{attribute,1813,spec,{{erlang,send_after,4},[{type,1813,bounded_fun,[{type,1813,'fun',[{type,1813,product,[{var,1813,'Time'},{var,1813,'Dest'},{var,1813,'Msg'},{var,1813,'Options'}]},{var,1813,'TimerRef'}]},[{type,1814,constraint,[{atom,1814,is_subtype},[{var,1814,'Time'},{type,1814,integer,[]}]]},{type,1815,constraint,[{atom,1815,is_subtype},[{var,1815,'Dest'},{type,1815,union,[{type,1815,pid,[]},{type,1815,atom,[]}]}]]},{type,1816,constraint,[{atom,1816,is_subtype},[{var,1816,'Msg'},{type,1816,term,[]}]]},{type,1817,constraint,[{atom,1817,is_subtype},[{var,1817,'Options'},{type,1817,list,[{var,1817,'Option'}]}]]},{type,1818,constraint,[{atom,1818,is_subtype},[{var,1818,'Abs'},{type,1818,boolean,[]}]]},{type,1819,constraint,[{atom,1819,is_subtype},[{var,1819,'Option'},{type,1819,tuple,[{atom,1819,abs},{var,1819,'Abs'}]}]]},{type,1820,constraint,[{atom,1820,is_subtype},[{var,1820,'TimerRef'},{type,1820,reference,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,send_nosuspend,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3458}],[<<115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,115,116>>}],[]}]},{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,40,68,101,115,116,44,32,77,115,103,44,32,91,110,111,115,117,115,112,101,110,100,93,41>>]}]},<<44,32,98,117,116,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,101,115,115,97,103,101,32,119,97,115,32,115,101,110,116,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,109,101,115,115,97,103,101,32,119,97,115,32,110,111,116,32,115,101,110,116,32,98,101,99,97,117,115,101,32,116,104,101,32,115,101,110,100,101,114,32,119,111,117,108,100,32,104,97,118,101,32,104,97,100,32,116,111,32,98,101,32,115,117,115,112,101,110,100,101,100,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,97,110,32,117,110,114,101,108,105,97,98,108,101,32,114,101,109,111,116,101,32,110,111,100,101,32,119,105,116,104,111,117,116,32,101,118,101,114,32,98,108,111,99,107,105,110,103,32,116,104,101,32,115,101,110,100,105,110,103,32,40,69,114,108,97,110,103,41,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,32,40,117,115,117,97,108,108,121,32,110,111,116,32,97,32,114,101,97,108,32,69,114,108,97,110,103,32,110,111,100,101,44,32,98,117,116,32,97,32,110,111,100,101,32,119,114,105,116,116,101,110,32,105,110,32,67,32,111,114,32,74,97,118,97,41,32,105,115,32,111,118,101,114,108,111,97,100,101,100,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32>>,{em,[],[<<100,111,101,115,32,110,111,116,32,115,101,110,100,32,116,104,101,32,109,101,115,115,97,103,101>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<84,104,101,32,115,97,109,101,32,111,99,99,117,114,115,32,105,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,108,111,99,97,108,32,112,111,114,116,32,116,104,97,116,32,105,115,32,98,117,115,121,46,32,70,111,114,32,97,108,108,32,111,116,104,101,114,32,100,101,115,116,105,110,97,116,105,111,110,115,32,40,97,108,108,111,119,101,100,32,102,111,114,32,116,104,101,32,111,114,100,105,110,97,114,121,32,115,101,110,100,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<39,33,39>>]},<<41,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,115,101,110,100,115,32,116,104,101,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,114,97,114,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,32,119,104,101,114,101,32,97,32,112,114,111,99,101,115,115,32,99,111,109,109,117,110,105,99,97,116,101,115,32,119,105,116,104,32,69,114,108,97,110,103,32,110,111,100,101,115,32,116,104,97,116,32,99,97,110,32,100,105,115,97,112,112,101,97,114,32,119,105,116,104,111,117,116,32,97,110,121,32,116,114,97,99,101,44,32,99,97,117,115,105,110,103,32,116,104,101,32,84,67,80,32,98,117,102,102,101,114,115,32,97,110,100,32,116,104,101,32,100,114,105,118,101,114,115,32,113,117,101,117,101,32,116,111,32,98,101,32,111,118,101,114,45,102,117,108,108,32,98,101,102,111,114,101,32,116,104,101,32,110,111,100,101,32,105,115,32,115,104,117,116,32,100,111,119,110,32,40,98,101,99,97,117,115,101,32,111,102,32,116,105,99,107,32,116,105,109,101,45,111,117,116,115,41,32,98,121,32>>,{code,[],[<<110,101,116,95,107,101,114,110,101,108>>]},<<46,32,84,104,101,32,110,111,114,109,97,108,32,114,101,97,99,116,105,111,110,32,116,111,32,116,97,107,101,32,119,104,101,110,32,116,104,105,115,32,111,99,99,117,114,115,32,105,115,32,115,111,109,101,32,107,105,110,100,32,111,102,32,112,114,101,109,97,116,117,114,101,32,115,104,117,116,100,111,119,110,32,111,102,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,103,110,111,114,105,110,103,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,111,117,108,100,32,114,101,115,117,108,116,32,105,110,32,97,110,32>>,{em,[],[<<117,110,114,101,108,105,97,98,108,101>>]},<<32,109,101,115,115,97,103,101,32,112,97,115,115,105,110,103,44,32,119,104,105,99,104,32,105,115,32,99,111,110,116,114,97,100,105,99,116,111,114,121,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,105,110,103,32,109,111,100,101,108,46,32,84,104,101,32,109,101,115,115,97,103,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,101,110,116,32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<73,110,32,109,97,110,121,32,115,121,115,116,101,109,115,44,32,116,114,97,110,115,105,101,110,116,32,115,116,97,116,101,115,32,111,102,32,111,118,101,114,108,111,97,100,101,100,32,113,117,101,117,101,115,32,97,114,101,32,110,111,114,109,97,108,46,32,65,108,116,104,111,117,103,104,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,100,111,101,115,32,110,111,116,32,109,101,97,110,32,116,104,97,116,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,110,111,110,45,114,101,115,112,111,110,115,105,118,101,44,32,105,116,32,99,111,117,108,100,32,98,101,32,97,32,116,101,109,112,111,114,97,114,121,32,111,118,101,114,108,111,97,100,46,32,65,108,115,111,44,32,97,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<116,114,117,101>>]},<<32,100,111,101,115,32,111,110,108,121,32,109,101,97,110,32,116,104,97,116,32,116,104,101,32,109,101,115,115,97,103,101,32,99,97,110,32,98,101,32,115,101,110,116,32,111,110,32,116,104,101,32,40,84,67,80,41,32,99,104,97,110,110,101,108,32,119,105,116,104,111,117,116,32,98,108,111,99,107,105,110,103,59,32,116,104,101,32,109,101,115,115,97,103,101,32,105,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,97,114,114,105,118,101,32,97,116,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,46,32,70,111,114,32,97,32,100,105,115,99,111,110,110,101,99,116,101,100,32,110,111,110,45,114,101,115,112,111,110,115,105,118,101,32,110,111,100,101,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,40,109,105,109,105,99,115,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<33>>]},<<41,46,32,84,104,101,32,101,120,112,101,99,116,101,100,32,98,101,104,97,118,105,111,114,32,97,110,100,32,116,104,101,32,97,99,116,105,111,110,115,32,116,111,32,116,97,107,101,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,97,114,101,32,97,112,112,108,105,99,97,116,105,111,110,45,32,97,110,100,32,104,97,114,100,119,97,114,101,45,115,112,101,99,105,102,105,99,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<85,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,48,51>>,signature => [{attribute,3458,spec,{{erlang,send_nosuspend,2},[{type,3458,bounded_fun,[{type,3458,'fun',[{type,3458,product,[{var,3458,'Dest'},{var,3458,'Msg'}]},{type,3458,boolean,[]}]},[{type,3459,constraint,[{atom,3459,is_subtype},[{var,3459,'Dest'},{user_type,3459,dst,[]}]]},{type,3460,constraint,[{atom,3460,is_subtype},[{var,3460,'Msg'},{type,3460,term,[]}]]}]]}]}}]}},{{function,send_nosuspend,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3468}],[<<115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,115,116>>}],[]}]},{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,40,68,101,115,116,44,32,77,115,103,44,32,91,110,111,115,117,115,112,101,110,100,32,124,32,79,112,116,105,111,110,115,93,41>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,32,66,111,111,108,101,97,110,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,98,101,104,97,118,101,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>]}]},<<44,32,98,117,116,32,116,97,107,101,115,32,97,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,44,32,97,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46,32,84,104,101,32,111,110,108,121,32,111,112,116,105,111,110,32,105,115,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<44,32,119,104,105,99,104,32,109,97,107,101,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,32,105,115,32,110,111,116,32,99,117,114,114,101,110,116,108,121,32,114,101,97,99,104,97,98,108,101,32,98,121,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,110,111,114,109,97,108,32,98,101,104,97,118,105,111,114,32,105,115,32,116,111,32,116,114,121,32,116,111,32,99,111,110,110,101,99,116,32,116,111,32,116,104,101,32,110,111,100,101,44,32,119,104,105,99,104,32,99,97,110,32,115,116,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,32,100,117,114,105,110,103,32,97,32,115,104,111,114,116,32,112,101,114,105,111,100,46,32,84,104,101,32,117,115,101,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,98,101,32,115,117,114,101,32,110,111,116,32,116,111,32,103,101,116,32,116,104,101,32,115,108,105,103,104,116,101,115,116,32,100,101,108,97,121,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,111,32,97,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,101,115,112,101,99,105,97,108,108,121,32,117,115,101,102,117,108,32,119,104,101,110,32,99,111,109,109,117,110,105,99,97,116,105,110,103,32,119,105,116,104,32,110,111,100,101,115,32,116,104,97,116,32,101,120,112,101,99,116,32,116,111,32,97,108,119,97,121,115,32,98,101,32,116,104,101,32,99,111,110,110,101,99,116,105,110,103,32,112,97,114,116,32,40,116,104,97,116,32,105,115,44,32,110,111,100,101,115,32,119,114,105,116,116,101,110,32,105,110,32,67,32,111,114,32,74,97,118,97,41,46>>]},{p,[],[<<87,104,101,110,101,118,101,114,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,101,105,116,104,101,114,32,119,104,101,110,32,97,32,115,117,115,112,101,110,100,32,119,111,117,108,100,32,111,99,99,117,114,32,111,114,32,119,104,101,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,119,97,115,32,115,112,101,99,105,102,105,101,100,32,97,110,100,32,116,104,101,32,110,111,100,101,32,119,97,115,32,110,111,116,32,97,108,114,101,97,100,121,32,99,111,110,110,101,99,116,101,100,41,44,32,116,104,101,32,109,101,115,115,97,103,101,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,104,97,118,101,32,98,101,101,110,32,115,101,110,116,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<85,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,53,51>>,signature => [{attribute,3468,spec,{{erlang,send_nosuspend,3},[{type,3468,bounded_fun,[{type,3468,'fun',[{type,3468,product,[{var,3468,'Dest'},{var,3468,'Msg'},{var,3468,'Options'}]},{type,3468,boolean,[]}]},[{type,3469,constraint,[{atom,3469,is_subtype},[{var,3469,'Dest'},{user_type,3469,dst,[]}]]},{type,3470,constraint,[{atom,3470,is_subtype},[{var,3470,'Msg'},{type,3470,term,[]}]]},{type,3471,constraint,[{atom,3471,is_subtype},[{var,3471,'Options'},{type,3471,list,[{atom,3471,noconnect}]}]]}]]}]}}]}},{{function,set_cookie,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3783}],[<<115,101,116,95,99,111,111,107,105,101,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,111,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,116,111,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<67,111,111,107,105,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,108,115,111,32,115,101,116,115,32,116,104,101,32,99,111,111,107,105,101,32,111,102,32,97,108,108,32,111,116,104,101,114,32,117,110,107,110,111,119,110,32,110,111,100,101,115,32,116,111,32>>,{code,[],[<<67,111,111,107,105,101>>]},<<32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,105,115,116,114,105,98,117,116,101,100,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,32,105,110,32,83,121,115,116,101,109,32,68,111,99,117,109,101,110,116,97,116,105,111,110,41,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<102,117,110,99,116,105,111,110,95,99,108,97,117,115,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,56,54>>,signature => [{attribute,3783,spec,{{erlang,set_cookie,2},[{type,3783,bounded_fun,[{type,3783,'fun',[{type,3783,product,[{var,3783,'Node'},{var,3783,'Cookie'}]},{atom,3783,true}]},[{type,3784,constraint,[{atom,3784,is_subtype},[{var,3784,'Node'},{type,3784,node,[]}]]},{type,3785,constraint,[{atom,3785,is_subtype},[{var,3785,'Cookie'},{type,3785,atom,[]}]]}]]}]}}]}},{{function,setelement,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2520}],[<<115,101,116,101,108,101,109,101,110,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,116,104,97,116,32,105,115,32,97,32,99,111,112,121,32,111,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<32,119,105,116,104,32,116,104,101,32,101,108,101,109,101,110,116,32,115,112,101,99,105,102,105,101,100,32,98,121,32,105,110,116,101,103,101,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,40,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,101,108,101,109,101,110,116,32,119,105,116,104,32,105,110,100,101,120,32,49,41,32,114,101,112,108,97,99,101,100,32,98,121,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<86,97,108,117,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,101,116,101,108,101,109,101,110,116,40,50,44,32,123,49,48,44,32,103,114,101,101,110,44,32,98,111,116,116,108,101,115,125,44,32,114,101,100,41,46,10,123,49,48,44,114,101,100,44,98,111,116,116,108,101,115,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,48,51>>,signature => [{attribute,2520,spec,{{setelement,3},[{type,2520,bounded_fun,[{type,2520,'fun',[{type,2520,product,[{var,2520,'Index'},{var,2520,'Tuple1'},{var,2520,'Value'}]},{var,2520,'Tuple2'}]},[{type,2521,constraint,[{atom,2521,is_subtype},[{var,2521,'Index'},{type,2521,pos_integer,[]}]]},{type,2522,constraint,[{atom,2522,is_subtype},[{var,2522,'Tuple1'},{type,2522,tuple,any}]]},{type,2523,constraint,[{atom,2523,is_subtype},[{var,2523,'Tuple2'},{type,2523,tuple,any}]]},{type,2524,constraint,[{atom,2524,is_subtype},[{var,2524,'Value'},{type,2524,term,[]}]]}]]}]}}]}},{{function,size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1874}],[<<115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32,97,32,116,117,112,108,101,32,111,114,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,110,32,97,32,98,105,110,97,114,121,32,111,114,32,98,105,116,115,116,114,105,110,103,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,105,122,101,40,123,109,111,114,110,105,44,32,109,117,108,108,101,44,32,98,119,97,110,103,101,125,41,46,10,51,10,62,32,115,105,122,101,40,60,60,49,49,44,32,50,50,44,32,51,51,62,62,41,46,10,51>>]}]},{p,[],[<<70,111,114,32,98,105,116,115,116,114,105,110,103,115,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,119,104,111,108,101,32,98,121,116,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32,116,104,101,32,98,105,116,115,116,114,105,110,103,32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,115,32,114,111,117,110,100,101,100,32>>,{em,[],[<<100,111,119,110>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,117,112,108,101,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,117,112,108,101,95,115,105,122,101,47,49>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,121,116,101,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,121,116,101,95,115,105,122,101,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,116,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,116,95,115,105,122,101,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,50,48>>,signature => [{attribute,1874,spec,{{size,1},[{type,1874,bounded_fun,[{type,1874,'fun',[{type,1874,product,[{var,1874,'Item'}]},{type,1874,non_neg_integer,[]}]},[{type,1875,constraint,[{atom,1875,is_subtype},[{var,1875,'Item'},{type,1875,union,[{type,1875,tuple,any},{type,1875,binary,[]}]}]]}]]}]}}]}},{{function,spawn,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,112,97,119,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,52,51>>,signature => [{attribute,2904,spec,{{spawn,1},[{type,2904,bounded_fun,[{type,2904,'fun',[{type,2904,product,[{var,2904,'Fun'}]},{type,2904,pid,[]}]},[{type,2905,constraint,[{atom,2905,is_subtype},[{var,2905,'Fun'},{type,2905,function,[]}]]}]]}]}}]}},{{function,spawn,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2913}],[<<115,112,97,119,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,53,52>>,signature => [{attribute,2913,spec,{{spawn,2},[{type,2913,bounded_fun,[{type,2913,'fun',[{type,2913,product,[{var,2913,'Node'},{var,2913,'Fun'}]},{type,2913,pid,[]}]},[{type,2914,constraint,[{atom,2914,is_subtype},[{var,2914,'Node'},{type,2914,node,[]}]]},{type,2915,constraint,[{atom,2915,is_subtype},[{var,2915,'Fun'},{type,2915,function,[]}]]}]]}]}}]}},{{function,spawn,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1880}],[<<115,112,97,119,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]},{p,[],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114,58,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,40,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,103,115,41>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,32,98,121,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,105,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,40,119,104,101,114,101,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<41,46,32,84,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,99,97,110,32,98,101,32,114,101,100,101,102,105,110,101,100,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<41,46,32,73,102,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,111,114,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,100,101,102,105,110,101,100,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,97,110,100,32,105,116,115,32,114,101,112,108,97,99,101,109,101,110,116,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<117,110,100,101,102>>]},<<32,111,99,99,117,114,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,112,97,119,110,40,115,112,101,101,100,44,32,114,101,103,117,108,97,116,111,114,44,32,91,104,105,103,104,95,115,112,101,101,100,44,32,116,104,105,110,95,99,117,116,93,41,46,10,60,48,46,49,51,46,49,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,54,56>>,signature => [{attribute,1880,spec,{{spawn,3},[{type,1880,bounded_fun,[{type,1880,'fun',[{type,1880,product,[{var,1880,'Module'},{var,1880,'Function'},{var,1880,'Args'}]},{type,1880,pid,[]}]},[{type,1881,constraint,[{atom,1881,is_subtype},[{var,1881,'Module'},{type,1881,module,[]}]]},{type,1882,constraint,[{atom,1882,is_subtype},[{var,1882,'Function'},{type,1882,atom,[]}]]},{type,1883,constraint,[{atom,1883,is_subtype},[{var,1883,'Args'},{type,1883,list,[{type,1883,term,[]}]}]]}]]}]}}]}},{{function,spawn,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3042}],[<<115,112,97,119,110,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,57,51>>,signature => [{attribute,3042,spec,{{spawn,4},[{type,3042,bounded_fun,[{type,3042,'fun',[{type,3042,product,[{var,3042,'Node'},{var,3042,'Module'},{var,3042,'Function'},{var,3042,'Args'}]},{type,3042,pid,[]}]},[{type,3043,constraint,[{atom,3043,is_subtype},[{var,3043,'Node'},{type,3043,node,[]}]]},{type,3044,constraint,[{atom,3044,is_subtype},[{var,3044,'Module'},{type,3044,module,[]}]]},{type,3045,constraint,[{atom,3045,is_subtype},[{var,3045,'Function'},{type,3045,atom,[]}]]},{type,3046,constraint,[{atom,3046,is_subtype},[{var,3046,'Args'},{type,3046,list,[{type,3046,term,[]}]}]]}]]}]}}]}},{{function,spawn_link,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2925}],[<<115,112,97,119,110,95,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,48,56>>,signature => [{attribute,2925,spec,{{spawn_link,1},[{type,2925,bounded_fun,[{type,2925,'fun',[{type,2925,product,[{var,2925,'Fun'}]},{type,2925,pid,[]}]},[{type,2926,constraint,[{atom,2926,is_subtype},[{var,2926,'Fun'},{type,2926,function,[]}]]}]]}]}}]}},{{function,spawn_link,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2934}],[<<115,112,97,119,110,95,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,50,50>>,signature => [{attribute,2934,spec,{{spawn_link,2},[{type,2934,bounded_fun,[{type,2934,'fun',[{type,2934,product,[{var,2934,'Node'},{var,2934,'Fun'}]},{type,2934,pid,[]}]},[{type,2935,constraint,[{atom,2935,is_subtype},[{var,2935,'Node'},{type,2935,node,[]}]]},{type,2936,constraint,[{atom,2936,is_subtype},[{var,2936,'Fun'},{type,2936,function,[]}]]}]]}]}}]}},{{function,spawn_link,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1888}],[<<115,112,97,119,110,95,108,105,110,107,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,51,57>>,signature => [{attribute,1888,spec,{{spawn_link,3},[{type,1888,bounded_fun,[{type,1888,'fun',[{type,1888,product,[{var,1888,'Module'},{var,1888,'Function'},{var,1888,'Args'}]},{type,1888,pid,[]}]},[{type,1889,constraint,[{atom,1889,is_subtype},[{var,1889,'Module'},{type,1889,module,[]}]]},{type,1890,constraint,[{atom,1890,is_subtype},[{var,1890,'Function'},{type,1890,atom,[]}]]},{type,1891,constraint,[{atom,1891,is_subtype},[{var,1891,'Args'},{type,1891,list,[{type,1891,term,[]}]}]]}]]}]}}]}},{{function,spawn_link,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3064}],[<<115,112,97,119,110,95,108,105,110,107,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,53,51>>,signature => [{attribute,3064,spec,{{spawn_link,4},[{type,3064,bounded_fun,[{type,3064,'fun',[{type,3064,product,[{var,3064,'Node'},{var,3064,'Module'},{var,3064,'Function'},{var,3064,'Args'}]},{type,3064,pid,[]}]},[{type,3065,constraint,[{atom,3065,is_subtype},[{var,3065,'Node'},{type,3065,node,[]}]]},{type,3066,constraint,[{atom,3066,is_subtype},[{var,3066,'Module'},{type,3066,module,[]}]]},{type,3067,constraint,[{atom,3067,is_subtype},[{var,3067,'Function'},{type,3067,atom,[]}]]},{type,3068,constraint,[{atom,3068,is_subtype},[{var,3068,'Args'},{type,3068,list,[{type,3068,term,[]}]}]]}]]}]}}]}},{{function,spawn_monitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2948}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,44,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<44,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,97,32,109,111,110,105,116,111,114,32,99,114,101,97,116,101,100,32,116,111,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,55,49>>,signature => [{attribute,2948,spec,{{spawn_monitor,1},[{type,2948,bounded_fun,[{type,2948,'fun',[{type,2948,product,[{var,2948,'Fun'}]},{type,2948,tuple,[{type,2948,pid,[]},{type,2948,reference,[]}]}]},[{type,2949,constraint,[{atom,2949,is_subtype},[{var,2949,'Fun'},{type,2949,function,[]}]]}]]}]}}]}},{{function,spawn_monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2955}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,44,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<44,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,97,32,109,111,110,105,116,111,114,32,99,114,101,97,116,101,100,32,116,111,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,100,105,115,116,114,105,98,117,116,101,100,32>>,{code,[],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,40,41>>]},<<44,32,116,104,101,32,99,97,108,108,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,56,56,53>>,signature => [{attribute,2955,spec,{{spawn_monitor,2},[{type,2955,bounded_fun,[{type,2955,'fun',[{type,2955,product,[{var,2955,'Node'},{var,2955,'Fun'}]},{type,2955,tuple,[{type,2955,pid,[]},{type,2955,reference,[]}]}]},[{type,2956,constraint,[{atom,2956,is_subtype},[{var,2956,'Node'},{type,2956,node,[]}]]},{type,2957,constraint,[{atom,2957,is_subtype},[{var,2957,'Fun'},{type,2957,function,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_monitor,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2969}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,51>>],#{<<101,110>> => [{p,[],[<<65,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,48,50>>,signature => [{attribute,2969,spec,{{spawn_monitor,3},[{type,2969,bounded_fun,[{type,2969,'fun',[{type,2969,product,[{var,2969,'Module'},{var,2969,'Function'},{var,2969,'Args'}]},{type,2969,tuple,[{type,2969,pid,[]},{type,2969,reference,[]}]}]},[{type,2970,constraint,[{atom,2970,is_subtype},[{var,2970,'Module'},{type,2970,module,[]}]]},{type,2971,constraint,[{atom,2971,is_subtype},[{var,2971,'Function'},{type,2971,atom,[]}]]},{type,2972,constraint,[{atom,2972,is_subtype},[{var,2972,'Args'},{type,2972,list,[{type,2972,term,[]}]}]]}]]}]}}]}},{{function,spawn_monitor,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3086}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,52>>],#{<<101,110>> => [{p,[],[<<65,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,100,105,115,116,114,105,98,117,116,101,100,32>>,{code,[],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,40,41>>]},<<44,32,116,104,101,32,99,97,108,108,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,49,54>>,signature => [{attribute,3086,spec,{{spawn_monitor,4},[{type,3086,bounded_fun,[{type,3086,'fun',[{type,3086,product,[{var,3086,'Node'},{var,3086,'Module'},{var,3086,'Function'},{var,3086,'Args'}]},{type,3086,tuple,[{type,3086,pid,[]},{type,3086,reference,[]}]}]},[{type,3087,constraint,[{atom,3087,is_subtype},[{var,3087,'Node'},{type,3087,node,[]}]]},{type,3088,constraint,[{atom,3088,is_subtype},[{var,3088,'Module'},{type,3088,module,[]}]]},{type,3089,constraint,[{atom,3089,is_subtype},[{var,3089,'Function'},{type,3089,atom,[]}]]},{type,3090,constraint,[{atom,3090,is_subtype},[{var,3090,'Args'},{type,3090,list,[{type,3090,term,[]}]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_opt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2999}],[<<115,112,97,119,110,95,111,112,116,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,44,32,97,110,100,32,98,111,116,104,32,116,104,101,32,112,105,100,32,97,110,100,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,32,97,114,101,32,114,101,116,117,114,110,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,51,51>>,signature => [{attribute,2999,spec,{{spawn_opt,2},[{type,2999,bounded_fun,[{type,2999,'fun',[{type,2999,product,[{var,2999,'Fun'},{var,2999,'Options'}]},{type,2999,union,[{type,2999,pid,[]},{type,2999,tuple,[{type,2999,pid,[]},{type,2999,reference,[]}]}]}]},[{type,3000,constraint,[{atom,3000,is_subtype},[{var,3000,'Fun'},{type,3000,function,[]}]]},{type,3001,constraint,[{atom,3001,is_subtype},[{var,3001,'Options'},{type,3001,list,[{user_type,3001,spawn_opt_option,[]}]}]]}]]}]}}]}},{{function,spawn_opt,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3014}],[<<115,112,97,119,110,95,111,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<86,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,53,49>>,signature => [{attribute,3014,spec,{{spawn_opt,3},[{type,3014,bounded_fun,[{type,3014,'fun',[{type,3014,product,[{var,3014,'Node'},{var,3014,'Fun'},{var,3014,'Options'}]},{type,3014,union,[{type,3014,pid,[]},{type,3014,tuple,[{type,3014,pid,[]},{type,3014,reference,[]}]}]}]},[{type,3015,constraint,[{atom,3015,is_subtype},[{var,3015,'Node'},{type,3015,node,[]}]]},{type,3016,constraint,[{atom,3016,is_subtype},[{var,3016,'Fun'},{type,3016,function,[]}]]},{type,3017,constraint,[{atom,3017,is_subtype},[{var,3017,'Options'},{type,3017,list,[{type,3017,union,[{atom,3017,monitor},{type,3018,tuple,[{atom,3018,monitor},{type,3018,list,[{user_type,3018,monitor_option,[]}]}]},{atom,3019,link},{var,3020,'OtherOption'}]}]}]]},{type,3021,constraint,[{atom,3021,is_subtype},[{var,3021,'OtherOption'},{type,3021,term,[]}]]}]]}]}}]}},{{function,spawn_opt,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3131}],[<<115,112,97,119,110,95,111,112,116,47,52>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<87,111,114,107,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,97,110,32,101,120,116,114,97,32,111,112,116,105,111,110,32,108,105,115,116,32,105,115,32,115,112,101,99,105,102,105,101,100,32,119,104,101,110,32,99,114,101,97,116,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,44,32,97,110,100,32,98,111,116,104,32,116,104,101,32,112,105,100,32,97,110,100,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,32,97,114,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,105,110,107>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,97,32,108,105,110,107,32,116,111,32,116,104,101,32,112,97,114,101,110,116,32,112,114,111,99,101,115,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,108,105,110,107,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,108,105,110,107,47,51>>]}]},<<32,100,111,101,115,41,46>>]}]},{dt,[],[{code,[],[<<109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]}]},<<32,100,111,101,115,41,46,32,65,32>>,{code,[],[<<123,80,105,100,44,32,77,111,110,105,116,111,114,82,101,102,125>>]},<<32,116,117,112,108,101,32,119,105,108,108,32,98,101,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,106,117,115,116,32,97,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,44,32,77,111,110,105,116,111,114,79,112,116,115,125>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,119,105,116,104,32,111,112,116,105,111,110,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,44,32,77,111,110,105,116,111,114,79,112,116,115,41>>]}]},<<32,100,111,101,115,41,46,32,65,32>>,{code,[],[<<123,80,105,100,44,32,77,111,110,105,116,111,114,82,101,102,125>>]},<<32,116,117,112,108,101,32,119,105,108,108,32,98,101,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,106,117,115,116,32,97,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,105,111,114,105,116,121,32,111,102,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,69,113,117,105,118,97,108,101,110,116,32,116,111,32,101,120,101,99,117,116,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<32,105,110,32,116,104,101,32,115,116,97,114,116,32,102,117,110,99,116,105,111,110,32,111,102,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,112,114,105,111,114,105,116,121,32,105,115,32,115,101,116,32,98,101,102,111,114,101,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,105,111,114,105,116,105,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114,44,32,78,117,109,98,101,114,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,117,115,101,115,32,97,32,103,101,110,101,114,97,116,105,111,110,97,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,99,104,101,109,101,44,32,117,115,105,110,103,32,97,110,32,34,111,108,100,32,104,101,97,112,34,32,102,111,114,32,100,97,116,97,32,116,104,97,116,32,104,97,115,32,115,117,114,118,105,118,101,100,32,97,116,32,108,101,97,115,116,32,111,110,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,116,104,101,114,101,32,105,115,32,110,111,32,109,111,114,101,32,114,111,111,109,32,111,110,32,116,104,101,32,111,108,100,32,104,101,97,112,44,32,97,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,103,101,110,101,114,97,116,105,111,110,97,108,32,99,111,108,108,101,99,116,105,111,110,115,32,98,101,102,111,114,101,32,102,111,114,99,105,110,103,32,97,32,102,117,108,108,115,119,101,101,112,44,32,101,118,101,110,32,105,102,32,116,104,101,114,101,32,105,115,32,114,111,111,109,32,111,110,32,116,104,101,32,111,108,100,32,104,101,97,112,46,32,83,101,116,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,116,111,32,122,101,114,111,32,100,105,115,97,98,108,101,115,32,116,104,101,32,103,101,110,101,114,97,108,32,99,111,108,108,101,99,116,105,111,110,32,97,108,103,111,114,105,116,104,109,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,108,105,118,101,32,100,97,116,97,32,105,115,32,99,111,112,105,101,100,32,97,116,32,101,118,101,114,121,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<65,32,102,101,119,32,99,97,115,101,115,32,119,104,101,110,32,105,116,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,116,111,32,99,104,97,110,103,101,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,97,114,101,32,110,111,32,108,111,110,103,101,114,32,117,115,101,100,32,97,114,101,32,116,111,32,98,101,32,116,104,114,111,119,110,32,97,119,97,121,32,97,115,32,115,111,111,110,32,97,115,32,112,111,115,115,105,98,108,101,46,32,40,83,101,116,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,122,101,114,111,46,41>>]}]},{li,[],[{p,[],[<<65,32,112,114,111,99,101,115,115,32,116,104,97,116,32,109,111,115,116,108,121,32,104,97,118,101,32,115,104,111,114,116,45,108,105,118,101,100,32,100,97,116,97,32,105,115,32,102,117,108,108,115,119,101,101,112,101,100,32,115,101,108,100,111,109,32,111,114,32,110,101,118,101,114,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,111,108,100,32,104,101,97,112,32,99,111,110,116,97,105,110,115,32,109,111,115,116,108,121,32,103,97,114,98,97,103,101,46,32,84,111,32,101,110,115,117,114,101,32,97,32,102,117,108,108,115,119,101,101,112,32,111,99,99,97,115,105,111,110,97,108,108,121,44,32,115,101,116,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,97,32,115,117,105,116,97,98,108,101,32,118,97,108,117,101,44,32,115,117,99,104,32,97,115,32,49,48,32,111,114,32,50,48,46>>]}]},{li,[],[<<73,110,32,101,109,98,101,100,100,101,100,32,115,121,115,116,101,109,115,32,119,105,116,104,32,97,32,108,105,109,105,116,101,100,32,97,109,111,117,110,116,32,111,102,32,82,65,77,32,97,110,100,32,110,111,32,118,105,114,116,117,97,108,32,109,101,109,111,114,121,44,32,121,111,117,32,109,105,103,104,116,32,119,97,110,116,32,116,111,32,112,114,101,115,101,114,118,101,32,109,101,109,111,114,121,32,98,121,32,115,101,116,116,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,122,101,114,111,46,32,40,84,104,101,32,118,97,108,117,101,32,99,97,110,32,98,101,32,115,101,116,32,103,108,111,98,97,108,108,121,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,47,50>>]}]},<<46,41>>]}]}]},{dt,[],[{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<71,105,118,101,115,32,97,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,118,97,108,117,101,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,99,97,110,32,115,112,101,101,100,32,117,112,32,115,111,109,101,32,112,114,111,99,101,115,115,101,115,32,98,101,99,97,117,115,101,32,108,101,115,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46,32,72,111,119,101,118,101,114,44,32,115,101,116,116,105,110,103,32,97,32,116,111,111,32,104,105,103,104,32,118,97,108,117,101,32,99,97,110,32,119,97,115,116,101,32,109,101,109,111,114,121,32,97,110,100,32,115,108,111,119,32,100,111,119,110,32,116,104,101,32,115,121,115,116,101,109,32,98,101,99,97,117,115,101,32,111,102,32,119,111,114,115,101,32,100,97,116,97,32,108,111,99,97,108,105,116,121,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,102,111,114,32,102,105,110,101,45,116,117,110,105,110,103,32,97,110,32,97,112,112,108,105,99,97,116,105,111,110,32,97,110,100,32,116,111,32,109,101,97,115,117,114,101,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,119,105,116,104,32,118,97,114,105,111,117,115,32>>,{code,[],[<<83,105,122,101>>]},<<32,118,97,108,117,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,86,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<71,105,118,101,115,32,97,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,118,97,108,117,101,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,99,97,110,32,115,112,101,101,100,32,117,112,32,115,111,109,101,32,112,114,111,99,101,115,115,101,115,32,98,101,99,97,117,115,101,32,108,101,115,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46,32,72,111,119,101,118,101,114,44,32,115,101,116,116,105,110,103,32,97,32,116,111,111,32,104,105,103,104,32,118,97,108,117,101,32,99,97,110,32,119,97,115,116,101,32,109,101,109,111,114,121,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,102,111,114,32,102,105,110,101,45,116,117,110,105,110,103,32,97,110,32,97,112,112,108,105,99,97,116,105,111,110,32,97,110,100,32,116,111,32,109,101,97,115,117,114,101,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,119,105,116,104,32,118,97,114,105,111,117,115,32>>,{code,[],[<<86,83,105,122,101>>]},<<32,118,97,108,117,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,46,32,84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,46,32>>,{code,[],[<<77,81,68>>]},<<32,105,115,32,116,111,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,57,55,52>>,signature => [{attribute,3131,spec,{{spawn_opt,4},[{type,3131,bounded_fun,[{type,3131,'fun',[{type,3131,product,[{var,3131,'Module'},{var,3131,'Function'},{var,3131,'Args'},{var,3131,'Options'}]},{type,3132,union,[{var,3132,'Pid'},{type,3132,tuple,[{var,3132,'Pid'},{var,3132,'MonitorRef'}]}]}]},[{type,3133,constraint,[{atom,3133,is_subtype},[{var,3133,'Module'},{type,3133,module,[]}]]},{type,3134,constraint,[{atom,3134,is_subtype},[{var,3134,'Function'},{type,3134,atom,[]}]]},{type,3135,constraint,[{atom,3135,is_subtype},[{var,3135,'Args'},{type,3135,list,[{type,3135,term,[]}]}]]},{type,3136,constraint,[{atom,3136,is_subtype},[{var,3136,'Options'},{type,3136,list,[{user_type,3136,spawn_opt_option,[]}]}]]},{type,3137,constraint,[{atom,3137,is_subtype},[{var,3137,'Pid'},{type,3137,pid,[]}]]},{type,3138,constraint,[{atom,3138,is_subtype},[{var,3138,'MonitorRef'},{type,3138,reference,[]}]]}]]}]}}]}},{{function,spawn_opt,5},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3143}],[<<115,112,97,119,110,95,111,112,116,47,53>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<86,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,50,50>>,signature => [{attribute,3143,spec,{{spawn_opt,5},[{type,3143,bounded_fun,[{type,3143,'fun',[{type,3143,product,[{var,3143,'Node'},{var,3143,'Module'},{var,3143,'Function'},{var,3143,'Args'},{var,3143,'Options'}]},{type,3144,union,[{type,3144,pid,[]},{type,3144,tuple,[{type,3144,pid,[]},{type,3144,reference,[]}]}]}]},[{type,3145,constraint,[{atom,3145,is_subtype},[{var,3145,'Node'},{type,3145,node,[]}]]},{type,3146,constraint,[{atom,3146,is_subtype},[{var,3146,'Module'},{type,3146,module,[]}]]},{type,3147,constraint,[{atom,3147,is_subtype},[{var,3147,'Function'},{type,3147,atom,[]}]]},{type,3148,constraint,[{atom,3148,is_subtype},[{var,3148,'Args'},{type,3148,list,[{type,3148,term,[]}]}]]},{type,3149,constraint,[{atom,3149,is_subtype},[{var,3149,'Options'},{type,3149,list,[{type,3149,union,[{atom,3149,monitor},{type,3150,tuple,[{atom,3150,monitor},{type,3150,list,[{user_type,3150,monitor_option,[]}]}]},{atom,3151,link},{var,3152,'OtherOption'}]}]}]]},{type,3153,constraint,[{atom,3153,is_subtype},[{var,3153,'OtherOption'},{type,3153,term,[]}]]}]]}]}}]}},{{function,spawn_request,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3246}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,70,117,110,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,52,54>>,signature => [{attribute,3246,spec,{{spawn_request,1},[{type,3246,bounded_fun,[{type,3246,'fun',[{type,3246,product,[{var,3246,'Fun'}]},{var,3246,'ReqId'}]},[{type,3247,constraint,[{atom,3247,is_subtype},[{var,3247,'Fun'},{type,3247,function,[]}]]},{type,3248,constraint,[{atom,3248,is_subtype},[{var,3248,'ReqId'},{type,3248,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3264}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,70,117,110,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,53,56>>,signature => [{attribute,3264,spec,{{spawn_request,2},[{type,3264,bounded_fun,[{type,3264,'fun',[{type,3264,product,[{var,3264,'Fun'},{var,3264,'Options'}]},{var,3264,'ReqId'}]},[{type,3265,constraint,[{atom,3265,is_subtype},[{var,3265,'Fun'},{type,3265,function,[]}]]},{type,3266,constraint,[{atom,3266,is_subtype},[{var,3266,'Option'},{type,3266,union,[{type,3266,tuple,[{atom,3266,reply_tag},{var,3266,'ReplyTag'}]},{type,3267,tuple,[{atom,3267,reply},{var,3267,'Reply'}]},{user_type,3268,spawn_opt_option,[]}]}]]},{type,3269,constraint,[{atom,3269,is_subtype},[{var,3269,'ReplyTag'},{type,3269,term,[]}]]},{type,3270,constraint,[{atom,3270,is_subtype},[{var,3270,'Reply'},{type,3270,union,[{atom,3270,yes},{atom,3270,no},{atom,3270,error_only},{atom,3270,success_only}]}]]},{type,3271,constraint,[{atom,3271,is_subtype},[{var,3271,'Options'},{type,3271,list,[{var,3271,'Option'}]}]]},{type,3272,constraint,[{atom,3272,is_subtype},[{var,3272,'ReqId'},{type,3272,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3264}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,70,117,110,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,55,48>>,signature => [{attribute,3264,spec,{{spawn_request,2},[{type,3273,bounded_fun,[{type,3273,'fun',[{type,3273,product,[{var,3273,'Node'},{var,3273,'Fun'}]},{var,3273,'ReqId'}]},[{type,3274,constraint,[{atom,3274,is_subtype},[{var,3274,'Node'},{type,3274,node,[]}]]},{type,3275,constraint,[{atom,3275,is_subtype},[{var,3275,'Fun'},{type,3275,function,[]}]]},{type,3276,constraint,[{atom,3276,is_subtype},[{var,3276,'ReqId'},{type,3276,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3299}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,101,114,108,97,110,103,44,97,112,112,108,121,44,91,70,117,110,44,91,93,93,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,117,115,105,110,103,32,116,104,101,32,102,117,110,32>>,{code,[],[<<70,117,110>>]},<<32,111,102,32,97,114,105,116,121,32,122,101,114,111,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,117,110>>]},<<32,105,115,32,110,111,116,32,97,32,102,117,110,32,111,102,32,97,114,105,116,121,32,122,101,114,111,46>>]}]},{li,[],[{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,56,50>>,signature => [{attribute,3299,spec,{{spawn_request,3},[{type,3299,bounded_fun,[{type,3299,'fun',[{type,3299,product,[{var,3299,'Node'},{var,3299,'Fun'},{var,3299,'Options'}]},{var,3299,'ReqId'}]},[{type,3300,constraint,[{atom,3300,is_subtype},[{var,3300,'Node'},{type,3300,node,[]}]]},{type,3301,constraint,[{atom,3301,is_subtype},[{var,3301,'Fun'},{type,3301,function,[]}]]},{type,3302,constraint,[{atom,3302,is_subtype},[{var,3302,'Options'},{type,3302,list,[{var,3302,'Option'}]}]]},{type,3303,constraint,[{atom,3303,is_subtype},[{var,3303,'Option'},{type,3303,union,[{atom,3303,monitor},{type,3304,tuple,[{atom,3304,monitor},{type,3304,list,[{user_type,3304,monitor_option,[]}]}]},{atom,3305,link},{type,3306,tuple,[{atom,3306,reply_tag},{var,3306,'ReplyTag'}]},{type,3307,tuple,[{atom,3307,reply},{var,3307,'Reply'}]},{var,3308,'OtherOption'}]}]]},{type,3309,constraint,[{atom,3309,is_subtype},[{var,3309,'ReplyTag'},{type,3309,term,[]}]]},{type,3310,constraint,[{atom,3310,is_subtype},[{var,3310,'Reply'},{type,3310,union,[{atom,3310,yes},{atom,3310,no},{atom,3310,error_only},{atom,3310,success_only}]}]]},{type,3311,constraint,[{atom,3311,is_subtype},[{var,3311,'OtherOption'},{type,3311,term,[]}]]},{type,3312,constraint,[{atom,3312,is_subtype},[{var,3312,'ReqId'},{type,3312,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3299}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,48,50>>,signature => [{attribute,3299,spec,{{spawn_request,3},[{type,3313,bounded_fun,[{type,3313,'fun',[{type,3313,product,[{var,3313,'Module'},{var,3313,'Function'},{var,3313,'Args'}]},{var,3314,'ReqId'}]},[{type,3315,constraint,[{atom,3315,is_subtype},[{var,3315,'Module'},{type,3315,module,[]}]]},{type,3316,constraint,[{atom,3316,is_subtype},[{var,3316,'Function'},{type,3316,atom,[]}]]},{type,3317,constraint,[{atom,3317,is_subtype},[{var,3317,'Args'},{type,3317,list,[{type,3317,term,[]}]}]]},{type,3318,constraint,[{atom,3318,is_subtype},[{var,3318,'ReqId'},{type,3318,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3339}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,52>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,49,52>>,signature => [{attribute,3339,spec,{{spawn_request,4},[{type,3339,bounded_fun,[{type,3339,'fun',[{type,3339,product,[{var,3339,'Node'},{var,3339,'Module'},{var,3339,'Function'},{var,3339,'Args'}]},{var,3340,'ReqId'}]},[{type,3341,constraint,[{atom,3341,is_subtype},[{var,3341,'Node'},{type,3341,node,[]}]]},{type,3342,constraint,[{atom,3342,is_subtype},[{var,3342,'Module'},{type,3342,module,[]}]]},{type,3343,constraint,[{atom,3343,is_subtype},[{var,3343,'Function'},{type,3343,atom,[]}]]},{type,3344,constraint,[{atom,3344,is_subtype},[{var,3344,'Args'},{type,3344,list,[{type,3344,term,[]}]}]]},{type,3345,constraint,[{atom,3345,is_subtype},[{var,3345,'ReqId'},{type,3345,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3339}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,52>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,50,54>>,signature => [{attribute,3339,spec,{{spawn_request,4},[{type,3346,bounded_fun,[{type,3346,'fun',[{type,3346,product,[{var,3346,'Module'},{var,3346,'Function'},{var,3346,'Args'},{var,3346,'Options'}]},{var,3347,'ReqId'}]},[{type,3348,constraint,[{atom,3348,is_subtype},[{var,3348,'Module'},{type,3348,module,[]}]]},{type,3349,constraint,[{atom,3349,is_subtype},[{var,3349,'Function'},{type,3349,atom,[]}]]},{type,3350,constraint,[{atom,3350,is_subtype},[{var,3350,'Args'},{type,3350,list,[{type,3350,term,[]}]}]]},{type,3351,constraint,[{atom,3351,is_subtype},[{var,3351,'Option'},{type,3351,union,[{type,3351,tuple,[{atom,3351,reply_tag},{var,3351,'ReplyTag'}]},{type,3352,tuple,[{atom,3352,reply},{var,3352,'Reply'}]},{user_type,3353,spawn_opt_option,[]}]}]]},{type,3354,constraint,[{atom,3354,is_subtype},[{var,3354,'ReplyTag'},{type,3354,term,[]}]]},{type,3355,constraint,[{atom,3355,is_subtype},[{var,3355,'Reply'},{type,3355,union,[{atom,3355,yes},{atom,3355,no},{atom,3355,error_only},{atom,3355,success_only}]}]]},{type,3356,constraint,[{atom,3356,is_subtype},[{var,3356,'Options'},{type,3356,list,[{var,3356,'Option'}]}]]},{type,3357,constraint,[{atom,3357,is_subtype},[{var,3357,'ReqId'},{type,3357,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,5},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3380}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>],#{<<101,110>> => [{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,108,121,32,115,101,110,100,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32,82,101,116,117,114,110,115,32,97,32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<82,101,113,73,100>>]},<<46>>]},{a,[{id,<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>}],[]},{p,[],[<<73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,99,114,101,97,116,101,100,32,111,110,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,121,32,100,101,102,97,117,108,116,32,98,101,32,115,101,110,116,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,82,101,113,73,100,44,32,111,107,44,32,80,105,100,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,83,117,99,104,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,97,32>>,{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]},<<32,98,101,108,111,119,32,105,110,32,116,104,101,32,116,101,120,116,46,32>>,{code,[],[<<82,101,112,108,121,84,97,103>>]},<<32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,112,97,119,110,95,114,101,112,108,121>>]},<<32,117,110,108,101,115,115,32,109,111,100,105,102,105,101,100,32,98,121,32,116,104,101,32>>,{code,[],[<<123,114,101,112,108,121,95,116,97,103,44,32,82,101,112,108,121,84,97,103,125>>]},<<32,111,112,116,105,111,110,46,32,84,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]},{a,[{id,<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>}],[]},{p,[],[<<84,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,32,101,105,116,104,101,114,32,105,102,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,102,97,105,108,101,100,32,111,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,105,110,116,101,114,114,117,112,116,101,100,32,98,121,32,97,32,99,111,110,110,101,99,116,105,111,110,32,102,97,105,108,117,114,101,46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,121,32,100,101,102,97,117,108,116,32,98,101,32,115,101,110,116,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,82,101,113,73,100,44,32,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,46,32,83,117,99,104,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,97,110,32>>,{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]},<<32,98,101,108,111,119,32,105,110,32,116,104,101,32,116,101,120,116,46,32,67,117,114,114,101,110,116,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,112,97,119,110,32,101,114,114,111,114,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<115,32,97,114,101,32,100,101,102,105,110,101,100,44,32,98,117,116,32,111,116,104,101,114,32,114,101,97,115,111,110,115,32,99,97,110,32,97,112,112,101,97,114,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,111,112,116>>]}]},{dd,[],[{p,[],[<<65,110,32,105,110,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<32,119,97,115,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46,32,78,111,116,101,32,116,104,97,116,32,100,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,115,32,109,97,121,32,115,117,112,112,111,114,116,32,100,105,102,102,101,114,101,110,116,32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,115,32,105,115,115,117,101,100,32,98,121,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<70,97,105,108,117,114,101,32,116,111,32,115,101,116,32,117,112,32,97,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,111,114,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,97,116,32,110,111,100,101,32,119,97,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,110,32,116,104,101,32,99,97,115,101,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,119,97,115,32,108,111,115,116,44,32,97,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<67,111,117,108,100,32,110,111,116,32,99,114,101,97,116,101,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,100,117,101,32,116,111,32,116,104,97,116,32,115,111,109,101,32,115,121,115,116,101,109,32,108,105,109,105,116,32,119,97,115,32,114,101,97,99,104,101,100,46,32,84,121,112,105,99,97,108,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,116,97,98,108,101,32,119,97,115,32,102,117,108,108,46>>]}]}]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<73,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,109,111,110,105,116,111,114,32,116,111,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,101,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<32,105,115,32,97,108,115,111,32,117,115,101,100,32,97,115,32,109,111,110,105,116,111,114,32,114,101,102,101,114,101,110,99,101,32,97,115,32,105,102,32,105,116,32,119,97,115,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]},<<46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,84,104,101,32,109,111,110,105,116,111,114,32,99,97,110,32,110,111,116,32,98,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<100,101,109,111,110,105,116,111,114,101,100>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,65,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,102,111,114,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,109,111,110,105,116,111,114,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,110,111,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,116,104,101,32,110,111,100,101,115,32,105,110,118,111,108,118,101,100,32,105,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,105,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46,32,65,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,44,32,77,111,110,105,116,111,114,79,112,116,115,125>>]}]},{dd,[],[{p,[],[<<73,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,109,111,110,105,116,111,114,32,116,111,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,44,32,77,111,110,105,116,111,114,79,112,116,115,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,83,101,101,32,116,104,101,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,111,112,116,105,111,110,32,97,98,111,118,101,32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,116,104,101,32,99,97,115,101,32,116,104,97,116,32,97,110,32,97,108,105,97,115,32,105,115,32,99,114,101,97,116,101,100,32,117,115,105,110,103,32,116,104,101,32,109,111,110,105,116,111,114,32,111,112,116,105,111,110,44,32,116,104,101,32,97,108,105,97,115,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,101,32,117,110,116,105,108,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,97,99,116,105,118,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<108,105,110,107>>]}]},{dd,[],[{p,[],[<<73,110,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,110,107,40,80,105,100,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<84,104,101,32,108,105,110,107,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,84,104,101,32,108,105,110,107,32,99,97,110,32,110,111,116,32,98,101,32,114,101,109,111,118,101,100,32,98,101,102,111,114,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,65,110,32,101,120,105,116,32,115,105,103,110,97,108,32,100,117,101,32,116,111,32,116,104,101,32,108,105,110,107,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,110,111,32,101,120,105,116,32,115,105,103,110,97,108,32,100,117,101,32,116,111,32,116,104,101,32,108,105,110,107,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,116,104,101,32,110,111,100,101,115,32,105,110,118,111,108,118,101,100,32,105,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,105,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46,32,65,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46,32,73,102,32,105,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,44,32,105,116,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,97,110,32,101,120,105,116,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,112,108,121,44,32,82,101,112,108,121,125>>]}]},{dd,[],[{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<82,101,112,108,121>>]},<<32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<121,101,115>>]}]},{dd,[],[{p,[],[<<65,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,32,111,114,32,110,111,116,46,32,73,102,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<32,114,101,116,117,114,110,115,32,119,105,116,104,111,117,116,32,114,97,105,115,105,110,103,32,97,110,32,101,120,99,101,112,116,105,111,110,32,97,110,100,32,116,104,101,32>>,{code,[],[<<114,101,112,108,121>>]},<<32,111,112,116,105,111,110,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<121,101,115>>]},<<44,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,101,105,116,104,101,114,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,111,114,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<114,101,112,108,121>>]},<<32,111,112,116,105,111,110,32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,115,101,116,32,116,111,32>>,{code,[],[<<121,101,115>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,111>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,119,104,101,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,99,111,109,112,108,101,116,101,115,46,32,84,104,105,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,32,111,114,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,114,114,111,114,95,111,110,108,121>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,98,117,116,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]}]},<<32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,46>>]}]},{dt,[],[{code,[],[<<115,117,99,99,101,115,115,95,111,110,108,121>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,98,117,116,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,46>>]}]}]}]},{dt,[],[{code,[],[<<123,114,101,112,108,121,95,116,97,103,44,32,82,101,112,108,121,84,97,103,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,114,101,112,108,121,32,116,97,103,32,116,111,32>>,{code,[],[<<82,101,112,108,121,84,97,103>>]},<<32,105,110,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,46,32,84,104,97,116,32,105,115,44,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114>>]}]},<<32,109,101,115,115,97,103,101,32,116,104,97,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,100,117,101,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,112,108,121,32,116,97,103,32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,112,97,119,110,95,114,101,112,108,121>>]},<<46>>]}]},{dt,[],[{code,[],[<<79,116,104,101,114,79,112,116,105,111,110>>]}]},{dd,[],[{p,[],[<<79,116,104,101,114,32,118,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,111,116,104,101,114,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]},{li,[],[{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,110,111,116,32,97,108,108,32,105,110,100,105,118,105,100,117,97,108,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,97,114,101,32,99,104,101,99,107,101,100,32,119,104,101,110,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,46,32,83,111,109,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,111,110,108,121,32,98,101,32,99,104,101,99,107,101,100,32,111,110,32,114,101,99,101,112,116,105,111,110,32,111,102,32,116,104,101,32,114,101,113,117,101,115,116,46,32,84,104,101,114,101,102,111,114,101,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,99,97,117,115,101,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,44,32,98,117,116,32,119,105,108,108,32,99,97,117,115,101,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,116,111,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<98,97,100,111,112,116>>]},<<46>>]},{p,[],[<<65,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,99,97,110,32,98,101,32,97,98,97,110,100,111,110,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,51,56>>,signature => [{attribute,3380,spec,{{spawn_request,5},[{type,3380,bounded_fun,[{type,3380,'fun',[{type,3380,product,[{var,3380,'Node'},{var,3380,'Module'},{var,3380,'Function'},{var,3380,'Args'},{var,3380,'Options'}]},{var,3381,'ReqId'}]},[{type,3382,constraint,[{atom,3382,is_subtype},[{var,3382,'Node'},{type,3382,node,[]}]]},{type,3383,constraint,[{atom,3383,is_subtype},[{var,3383,'Module'},{type,3383,module,[]}]]},{type,3384,constraint,[{atom,3384,is_subtype},[{var,3384,'Function'},{type,3384,atom,[]}]]},{type,3385,constraint,[{atom,3385,is_subtype},[{var,3385,'Args'},{type,3385,list,[{type,3385,term,[]}]}]]},{type,3386,constraint,[{atom,3386,is_subtype},[{var,3386,'Options'},{type,3386,list,[{var,3386,'Option'}]}]]},{type,3387,constraint,[{atom,3387,is_subtype},[{var,3387,'Option'},{type,3387,union,[{atom,3387,monitor},{type,3388,tuple,[{atom,3388,monitor},{type,3388,list,[{user_type,3388,monitor_option,[]}]}]},{atom,3389,link},{type,3390,tuple,[{atom,3390,reply_tag},{var,3390,'ReplyTag'}]},{type,3391,tuple,[{atom,3391,reply},{var,3391,'Reply'}]},{var,3392,'OtherOption'}]}]]},{type,3393,constraint,[{atom,3393,is_subtype},[{var,3393,'ReplyTag'},{type,3393,term,[]}]]},{type,3394,constraint,[{atom,3394,is_subtype},[{var,3394,'Reply'},{type,3394,union,[{atom,3394,yes},{atom,3394,no},{atom,3394,error_only},{atom,3394,success_only}]}]]},{type,3395,constraint,[{atom,3395,is_subtype},[{var,3395,'OtherOption'},{type,3395,term,[]}]]},{type,3396,constraint,[{atom,3396,is_subtype},[{var,3396,'ReqId'},{type,3396,reference,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request_abandon,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3413}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<65,98,97,110,100,111,110,32,97,32,112,114,101,118,105,111,117,115,108,121,32,105,115,115,117,101,100,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,97,32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]}]},<<32,105,110,32,97,32,99,97,108,108,32,102,114,111,109,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,109,97,100,101,32,116,104,101,32,114,101,113,117,101,115,116,32,99,97,110,32,97,98,97,110,100,111,110,32,116,104,101,32,114,101,113,117,101,115,116,46>>]},{p,[],[<<65,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,99,97,110,32,111,110,108,121,32,98,101,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,104,97,115,32,99,111,109,112,108,101,116,101,100,46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,110,111,116,32,98,101,32,101,102,102,101,99,116,101,100,32,98,121,32,102,117,116,117,114,101,32,100,105,114,101,99,116,32,101,102,102,101,99,116,115,32,111,102,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,116,115,101,108,102,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,119,105,108,108,32,110,111,116,32,114,101,99,101,105,118,101,32,97,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,46,32,84,104,101,32,114,101,113,117,101,115,116,32,105,115,32,104,111,119,101,118,101,114,32,110,111,116,32,119,105,116,104,100,114,97,119,110,44,32,115,111,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,116,104,101,32,114,101,113,117,101,115,116,46,32,73,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,99,114,101,97,116,101,100,32,97,102,116,101,114,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,97,98,97,110,100,111,110,101,100,44,32,110,111,32,109,111,110,105,116,111,114,115,32,110,111,114,32,108,105,110,107,115,32,119,105,108,108,32,98,101,32,115,101,116,32,117,112,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>]},<<32,100,117,101,32,116,111,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,110,99,108,117,100,101,100,32,116,104,101,32>>,{code,[],[<<108,105,110,107>>]},<<32,111,112,116,105,111,110,44,32,116,104,101,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,116,104,105,115,32,114,101,113,117,101,115,116,32,119,105,108,108,32,98,101,32,115,101,110,116,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,105,116,115,32,112,97,114,101,110,116,32,119,105,116,104,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<97,98,97,110,100,111,110,101,100>>]},<<32,119,104,101,110,32,105,116,32,105,115,32,100,101,116,101,99,116,101,100,32,116,104,97,116,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,97,98,97,110,100,111,110,101,100,32,109,97,121,32,99,111,109,109,117,110,105,99,97,116,101,32,119,105,116,104,32,105,116,115,32,112,97,114,101,110,116,32,97,115,32,97,110,121,32,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,73,116,32,105,115,32>>,{em,[],[<<111,110,108,121>>]},<<32,116,104,101,32,100,105,114,101,99,116,32,101,102,102,101,99,116,115,32,111,110,32,116,104,101,32,112,97,114,101,110,116,32,111,102,32,116,104,101,32,97,99,116,117,97,108,32,115,112,97,119,110,32,114,101,113,117,101,115,116,44,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,97,110,99,101,108,101,100,32,98,121,32,97,98,97,110,100,111,110,105,110,103,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46>>]}]},{p,[],[<<82,101,116,117,114,110,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,97,98,97,110,100,111,110,101,100,46,32,84,104,101,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32,100,105,100,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,97,110,32,111,117,116,115,116,97,110,100,105,110,103,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,115,115,117,101,100,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,101,105,116,104,101,114,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<82,101,113,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,112,114,101,118,105,111,117,108,115,121,32,109,97,100,101,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,99,111,109,112,108,101,116,101,100,32,97,110,100,32,97,32,115,112,97,119,110,32,114,101,112,108,121,32,104,97,115,32,97,108,114,101,97,100,121,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,108,101,115,115,32,116,104,101,32,115,112,97,119,110,32,114,101,112,108,121,32,119,97,115,32,100,105,115,97,98,108,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,46>>]}]},{li,[],[{p,[],[{code,[],[<<82,101,113,73,100>>]},<<32,100,111,101,115,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,109,97,100,101,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]}]}]}]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,102,101,114,101,110,99,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,57,53>>,signature => [{attribute,3413,spec,{{spawn_request_abandon,1},[{type,3413,'fun',[{type,3413,product,[{ann_type,3413,[{var,3413,'ReqId'},{type,3413,reference,[]}]}]},{type,3413,boolean,[]}]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,split_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1896}],[<<115,112,108,105,116,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,97,114,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,112,108,105,116,116,105,110,103,32>>,{code,[],[<<66,105,110>>]},<<32,105,110,116,111,32,116,119,111,32,112,97,114,116,115,32,97,116,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<80,111,115>>]},<<46,32,84,104,105,115,32,105,115,32,110,111,116,32,97,32,100,101,115,116,114,117,99,116,105,118,101,32,111,112,101,114,97,116,105,111,110,46,32,65,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,114,101,32,97,114,101,32,116,104,114,101,101,32,98,105,110,97,114,105,101,115,32,97,108,116,111,103,101,116,104,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,32,61,32,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,34,48,49,50,51,52,53,54,55,56,57,34,41,46,10,60,60,34,48,49,50,51,52,53,54,55,56,57,34,62,62,10,62,32,98,121,116,101,95,115,105,122,101,40,66,41,46,10,49,48,10,62,32,123,66,49,44,32,66,50,125,32,61,32,115,112,108,105,116,95,98,105,110,97,114,121,40,66,44,51,41,46,10,123,60,60,34,48,49,50,34,62,62,44,60,60,34,51,52,53,54,55,56,57,34,62,62,125,10,62,32,98,121,116,101,95,115,105,122,101,40,66,49,41,46,10,51,10,62,32,98,121,116,101,95,115,105,122,101,40,66,50,41,46,10,55>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,54,49>>,signature => [{attribute,1896,spec,{{split_binary,2},[{type,1896,bounded_fun,[{type,1896,'fun',[{type,1896,product,[{var,1896,'Bin'},{var,1896,'Pos'}]},{type,1896,tuple,[{type,1896,binary,[]},{type,1896,binary,[]}]}]},[{type,1897,constraint,[{atom,1897,is_subtype},[{var,1897,'Bin'},{type,1897,binary,[]}]]},{type,1898,constraint,[{atom,1898,is_subtype},[{var,1898,'Pos'},{type,1898,non_neg_integer,[]}]]}]]}]}}]}},{{function,start_timer,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1903}],[<<115,116,97,114,116,95,116,105,109,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,40,84,105,109,101,44,32,68,101,115,116,44,32,77,115,103,44,32,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,56,53>>,signature => [{attribute,1903,spec,{{erlang,start_timer,3},[{type,1903,bounded_fun,[{type,1903,'fun',[{type,1903,product,[{var,1903,'Time'},{var,1903,'Dest'},{var,1903,'Msg'}]},{var,1903,'TimerRef'}]},[{type,1904,constraint,[{atom,1904,is_subtype},[{var,1904,'Time'},{type,1904,non_neg_integer,[]}]]},{type,1905,constraint,[{atom,1905,is_subtype},[{var,1905,'Dest'},{type,1905,union,[{type,1905,pid,[]},{type,1905,atom,[]}]}]]},{type,1906,constraint,[{atom,1906,is_subtype},[{var,1906,'Msg'},{type,1906,term,[]}]]},{type,1907,constraint,[{atom,1907,is_subtype},[{var,1907,'TimerRef'},{type,1907,reference,[]}]]}]]}]}}]}},{{function,start_timer,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1913}],[<<115,116,97,114,116,95,116,105,109,101,114,47,52>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,87,104,101,110,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,84,105,109,101,114,82,101,102,44,32,77,115,103,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,101,115,116>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,98,115,44,32,102,97,108,115,101,125>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46,32,73,116,32,109,101,97,110,115,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32>>,{em,[],[<<114,101,108,97,116,105,118,101>>]},<<32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,98,115,44,32,116,114,117,101,125>>]}]},{dd,[],[{p,[],[<<65,98,115,111,108,117,116,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,46,32,84,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,110,32,97,98,115,111,108,117,116,101,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<84,104,101,32,97,98,115,111,108,117,116,101,32,112,111,105,110,116,32,105,110,32,116,105,109,101,44,32,116,104,101,32,116,105,109,101,114,32,105,115,32,115,101,116,32,116,111,32,101,120,112,105,114,101,32,111,110,44,32,109,117,115,116,32,98,101,32,105,110,32,116,104,101,32,105,110,116,101,114,118,97,108,32>>,{code,[],[<<91,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111>>]},{code,[],[<<40,115,116,97,114,116,95,116,105,109,101,41,44,32,110,97,116,105,118,101,44,32,109,105,108,108,105,115,101,99,111,110,100,41,44,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111>>]},{code,[],[<<40,101,110,100,95,116,105,109,101,41,44,32,110,97,116,105,118,101,44,32,109,105,108,108,105,115,101,99,111,110,100,41,32,93>>]},<<46,32,73,102,32,97,32,114,101,108,97,116,105,118,101,32,116,105,109,101,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,110,101,103,97,116,105,118,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,105,116,32,109,117,115,116,32,98,101,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,102,32,97,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,101,105,116,104,101,114,32,116,101,114,109,105,110,97,116,101,100,32,111,114,32,110,111,116,46,32,73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<44,32,105,116,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,108,111,99,97,108,108,121,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,46,32,84,104,101,32,112,114,111,99,101,115,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,116,104,101,32,110,97,109,101,32,105,115,32,108,111,111,107,101,100,32,117,112,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,105,109,101,114,32,101,120,112,105,114,97,116,105,111,110,46,32,78,111,32,101,114,114,111,114,32,105,115,32,114,101,116,117,114,110,101,100,32,105,102,32,116,104,101,32,110,97,109,101,32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,116,104,101,32,116,105,109,101,114,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,110,99,101,108,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,116,104,101,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,44,32,111,114,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,46,32,84,104,105,115,32,102,101,97,116,117,114,101,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,53,46,52,46,49,49,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,105,109,101,114,115,32,97,114,101,32,110,111,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,110,99,101,108,101,100,32,119,104,101,110,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,100,111,32,110,111,116,32,115,97,116,105,115,102,121,32,116,104,101,32,114,101,113,117,105,114,101,109,101,110,116,115,32,115,112,101,99,105,102,105,101,100,32,104,101,114,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,57,54>>,signature => [{attribute,1913,spec,{{erlang,start_timer,4},[{type,1913,bounded_fun,[{type,1913,'fun',[{type,1913,product,[{var,1913,'Time'},{var,1913,'Dest'},{var,1913,'Msg'},{var,1913,'Options'}]},{var,1913,'TimerRef'}]},[{type,1914,constraint,[{atom,1914,is_subtype},[{var,1914,'Time'},{type,1914,integer,[]}]]},{type,1915,constraint,[{atom,1915,is_subtype},[{var,1915,'Dest'},{type,1915,union,[{type,1915,pid,[]},{type,1915,atom,[]}]}]]},{type,1916,constraint,[{atom,1916,is_subtype},[{var,1916,'Msg'},{type,1916,term,[]}]]},{type,1917,constraint,[{atom,1917,is_subtype},[{var,1917,'Options'},{type,1917,list,[{var,1917,'Option'}]}]]},{type,1918,constraint,[{atom,1918,is_subtype},[{var,1918,'Abs'},{type,1918,boolean,[]}]]},{type,1919,constraint,[{atom,1919,is_subtype},[{var,1919,'Option'},{type,1919,tuple,[{atom,1919,abs},{var,1919,'Abs'}]}]]},{type,1920,constraint,[{atom,1920,is_subtype},[{var,1920,'TimerRef'},{type,1920,reference,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<32,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,116,97,115,107,115,32,116,104,97,116,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,32,97,114,101,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,53,54>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2528,bounded_fun,[{type,2528,'fun',[{type,2528,product,[{atom,2528,active_tasks}]},{type,2528,list,[{var,2528,'ActiveTasks'}]}]},[{type,2529,constraint,[{atom,2529,is_subtype},[{var,2529,'ActiveTasks'},{type,2529,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,97,99,116,105,118,101,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,111,110,32,101,97,99,104,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,116,104,97,116,32,97,114,101,32,114,101,97,100,121,32,116,111,32,114,117,110,44,32,111,114,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,114,117,110,110,105,110,103,46,32,86,97,108,117,101,115,32,102,111,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,97,110,100,32,116,104,101,105,114,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,108,111,99,97,116,101,100,32,102,105,114,115,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,115,99,104,101,100,117,108,101,114,32,110,117,109,98,101,114,32,49,32,97,110,100,32,115,111,32,111,110,46,32,73,102,32,115,117,112,112,111,114,116,32,102,111,114,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,44,32,97,110,32,101,108,101,109,101,110,116,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,102,111,108,108,111,119,32,97,110,100,32,116,104,101,110,32,97,115,32,108,97,115,116,32,101,108,101,109,101,110,116,32,116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,102,111,108,108,111,119,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,105,108,121,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,105,110,115,116,101,97,100,32,113,117,105,116,101,32,101,102,102,105,99,105,101,110,116,108,121,32,103,97,116,104,101,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<69,97,99,104,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,111,110,101,32,114,117,110,32,113,117,101,117,101,32,116,104,97,116,32,105,116,32,109,97,110,97,103,101,115,46,32,73,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,108,108,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,44,32,97,110,100,32,97,108,108,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,46,32,84,104,97,116,32,105,115,44,32,119,101,32,104,97,118,101,32,109,117,108,116,105,112,108,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,44,32,111,110,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,111,110,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,46,32,87,111,114,107,32,99,97,110,32>>,{em,[],[<<110,111,116>>]},<<32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,114,117,110,32,113,117,101,117,101,115,46,32,79,110,108,121,32,119,111,114,107,32,105,110,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,99,97,110,32,109,105,103,114,97,116,101,32,116,111,32,111,116,104,101,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,105,115,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,55,49>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2530,bounded_fun,[{type,2530,'fun',[{type,2530,product,[{atom,2530,active_tasks_all}]},{type,2530,list,[{var,2530,'ActiveTasks'}]}]},[{type,2531,constraint,[{atom,2531,is_subtype},[{var,2531,'ActiveTasks'},{type,2531,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,99,111,110,116,101,120,116,32,115,119,105,116,99,104,101,115,32,115,105,110,99,101,32,116,104,101,32,115,121,115,116,101,109,32,115,116,97,114,116,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,49,51>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2532,bounded_fun,[{type,2532,'fun',[{type,2532,product,[{atom,2532,context_switches}]},{type,2532,tuple,[{var,2532,'ContextSwitches'},{integer,2532,0}]}]},[{type,2533,constraint,[{atom,2533,is_subtype},[{var,2533,'ContextSwitches'},{type,2533,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,120,97,99,116,32,114,101,100,117,99,116,105,111,110,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115,41>>]},<<32,105,115,32,97,32,109,111,114,101,32,101,120,112,101,110,115,105,118,101,32,111,112,101,114,97,116,105,111,110,32,116,104,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,101,100,117,99,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,97,116,105,115,116,105,99,115,40,114,101,100,117,99,116,105,111,110,115,41>>]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,50,50>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2534,bounded_fun,[{type,2534,'fun',[{type,2534,product,[{atom,2534,exact_reductions}]},{type,2534,tuple,[{var,2534,'Total_Exact_Reductions'},{var,2535,'Exact_Reductions_Since_Last_Call'}]}]},[{type,2536,constraint,[{atom,2536,is_subtype},[{var,2536,'Total_Exact_Reductions'},{type,2536,non_neg_integer,[]}]]},{type,2537,constraint,[{atom,2537,is_subtype},[{var,2537,'Exact_Reductions_Since_Last_Call'},{type,2537,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,41,46,10,123,56,53,44,50,51,57,54,49,44,48,125>>]}]},{p,[],[<<84,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,105,110,118,97,108,105,100,32,102,111,114,32,115,111,109,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,51,55>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2538,bounded_fun,[{type,2538,'fun',[{type,2538,product,[{atom,2538,garbage_collection}]},{type,2538,tuple,[{var,2538,'Number_of_GCs'},{var,2538,'Words_Reclaimed'},{integer,2538,0}]}]},[{type,2539,constraint,[{atom,2539,is_subtype},[{var,2539,'Number_of_GCs'},{type,2539,non_neg_integer,[]}]]},{type,2540,constraint,[{atom,2540,is_subtype},[{var,2540,'Words_Reclaimed'},{type,2540,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<73,110,112,117,116>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,99,101,105,118,101,100,32,116,104,114,111,117,103,104,32,112,111,114,116,115,44,32,97,110,100,32>>,{code,[],[<<79,117,116,112,117,116>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,111,117,116,112,117,116,32,116,111,32,112,111,114,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,52,57>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2541,bounded_fun,[{type,2541,'fun',[{type,2541,product,[{atom,2541,io}]},{type,2541,tuple,[{type,2541,tuple,[{atom,2541,input},{var,2541,'Input'}]},{type,2541,tuple,[{atom,2541,output},{var,2541,'Output'}]}]}]},[{type,2542,constraint,[{atom,2542,is_subtype},[{var,2542,'Input'},{type,2542,non_neg_integer,[]}]]},{type,2543,constraint,[{atom,2543,is_subtype},[{var,2543,'Output'},{type,2543,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<77,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,101,97,115,117,114,101,32,104,111,119,32,109,117,99,104,32,116,105,109,101,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,112,101,110,100,115,32,100,111,105,110,103,32,118,97,114,105,111,117,115,32,116,97,115,107,115,46,32,73,116,32,105,115,32,100,101,115,105,103,110,101,100,32,116,111,32,98,101,32,97,115,32,108,105,103,104,116,119,101,105,103,104,116,32,97,115,32,112,111,115,115,105,98,108,101,44,32,98,117,116,32,115,111,109,101,32,111,118,101,114,104,101,97,100,32,101,120,105,115,116,115,32,119,104,101,110,32,116,104,105,115,32,105,115,32,101,110,97,98,108,101,100,46,32,77,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,105,115,32,109,101,97,110,116,32,116,111,32,98,101,32,97,32,112,114,111,102,105,108,105,110,103,32,116,111,111,108,32,116,111,32,104,101,108,112,32,102,105,110,100,105,110,103,32,112,101,114,102,111,114,109,97,110,99,101,32,98,111,116,116,108,101,110,101,99,107,115,46,32,84,111,32>>,{code,[],[<<115,116,97,114,116>>]},<<47>>,{code,[],[<<115,116,111,112>>]},<<47>>,{code,[],[<<114,101,115,101,116>>]},<<32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,44,32,117,115,101,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>]}]},<<46>>]},{p,[],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41>>]},<<32,114,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,109,97,112,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,115,111,109,101,32,111,102,32,116,104,101,32,79,83,32,116,104,114,101,97,100,115,32,119,105,116,104,105,110,32,69,82,84,83,46,32,69,97,99,104,32,109,97,112,32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<116,121,112,101>>]},<<32,97,110,100,32>>,{code,[],[<<105,100>>]},<<32,102,105,101,108,100,115,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,105,100,101,110,116,105,102,121,32,119,104,97,116,32,116,104,114,101,97,100,32,105,116,32,105,115,44,32,97,110,100,32,97,108,115,111,32,97,32,99,111,117,110,116,101,114,115,32,102,105,101,108,100,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,100,97,116,97,32,97,98,111,117,116,32,104,111,119,32,109,117,99,104,32,116,105,109,101,32,104,97,115,32,98,101,101,110,32,115,112,101,110,116,32,105,110,32,116,104,101,32,118,97,114,105,111,117,115,32,115,116,97,116,101,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41,46,10,91,35,123,99,111,117,110,116,101,114,115,32,61,62,32,35,123,97,117,120,32,61,62,32,49,56,57,57,49,56,50,57,49,52,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,104,101,99,107,95,105,111,32,61,62,32,50,54,48,53,56,54,51,54,48,50,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,109,117,108,97,116,111,114,32,61,62,32,52,53,55,51,49,56,56,48,52,54,51,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,103,99,32,61,62,32,49,53,49,50,50,48,54,57,49,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,111,116,104,101,114,32,61,62,32,53,52,50,49,51,51,56,52,53,54,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,111,114,116,32,61,62,32,50,50,49,54,51,49,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,108,101,101,112,32,61,62,32,53,49,53,48,50,57,52,49,48,48,125,44,10,32,32,32,105,100,32,61,62,32,49,44,10,32,32,32,116,121,112,101,32,61,62,32,115,99,104,101,100,117,108,101,114,125,124,46,46,46,93>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,117,110,105,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>]}]},<<46,32,83,111,44,32,116,111,32,99,111,110,118,101,114,116,32,105,116,32,116,111,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,121,111,117,32,99,97,110,32,100,111,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<108,105,115,116,115,58,109,97,112,40,10,32,32,102,117,110,40,35,123,32,99,111,117,110,116,101,114,115,32,58,61,32,67,110,116,32,125,32,61,32,77,41,32,45,62,10,32,32,32,32,32,32,32,32,32,32,77,115,67,110,116,32,61,32,109,97,112,115,58,109,97,112,40,102,117,110,40,95,75,44,32,80,101,114,102,67,111,117,110,116,41,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,40,80,101,114,102,67,111,117,110,116,44,32,112,101,114,102,95,99,111,117,110,116,101,114,44,32,49,48,48,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,110,100,44,32,67,110,116,41,44,10,32,32,32,32,32,32,32,32,32,77,35,123,32,99,111,117,110,116,101,114,115,32,58,61,32,77,115,67,110,116,32,125,10,32,32,101,110,100,44,32,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41,41,46>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,118,97,108,117,101,115,32,97,114,101,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,116,104,101,32,101,120,97,99,116,32,116,105,109,101,32,115,112,101,110,116,32,105,110,32,101,97,99,104,32,115,116,97,116,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,118,97,114,105,111,117,115,32,111,112,116,105,109,105,115,97,116,105,111,110,32,100,111,110,101,32,116,111,32,107,101,101,112,32,116,104,101,32,111,118,101,114,104,101,97,100,32,97,115,32,115,109,97,108,108,32,97,115,32,112,111,115,115,105,98,108,101,46>>]},{p,[],[{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,109,97,105,110,32,101,120,101,99,117,116,105,111,110,32,116,104,114,101,97,100,115,32,116,104,97,116,32,100,111,32,109,111,115,116,32,111,102,32,116,104,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,102,111,114,32,108,111,110,103,32,114,117,110,110,105,110,103,32,99,112,117,32,105,110,116,101,110,115,105,118,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83,68,99,112,117>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,102,111,114,32,108,111,110,103,32,114,117,110,110,105,110,103,32,73,47,79,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83,68,105,111>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<97,115,121,110,99>>]}]},{dd,[],[<<65,115,121,110,99,32,116,104,114,101,97,100,115,32,97,114,101,32,117,115,101,100,32,98,121,32,118,97,114,105,111,117,115,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,115,32,40,109,97,105,110,108,121,32,116,104,101,32,102,105,108,101,32,100,114,105,118,101,114,115,41,32,100,111,32,111,102,102,108,111,97,100,32,110,111,110,45,67,80,85,32,105,110,116,101,110,115,105,118,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,97,115,121,110,99,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,65>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<97,117,120>>]}]},{dd,[],[<<84,97,107,101,115,32,99,97,114,101,32,111,102,32,97,110,121,32,119,111,114,107,32,116,104,97,116,32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,99,97,108,108,121,32,97,115,115,105,103,110,101,100,32,116,111,32,97,32,115,99,104,101,100,117,108,101,114,46>>]},{dt,[],[{code,[],[<<112,111,108,108>>]}]},{dd,[],[<<68,111,101,115,32,116,104,101,32,73,79,32,112,111,108,108,105,110,103,32,102,111,114,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,73,79,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,73,79,116>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,83,116,97,116,101>>]},<<115,32,97,114,101,32,97,118,97,105,108,97,98,108,101,46,32,65,108,108,32,115,116,97,116,101,115,32,97,114,101,32,101,120,99,108,117,115,105,118,101,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,97,32,116,104,114,101,97,100,32,99,97,110,110,111,116,32,98,101,32,105,110,32,116,119,111,32,115,116,97,116,101,115,32,97,116,32,111,110,99,101,46,32,83,111,44,32,105,102,32,121,111,117,32,97,100,100,32,116,104,101,32,110,117,109,98,101,114,115,32,111,102,32,97,108,108,32,99,111,117,110,116,101,114,115,32,105,110,32,97,32,116,104,114,101,97,100,44,32,121,111,117,32,103,101,116,32,116,104,101,32,116,111,116,97,108,32,114,117,110,116,105,109,101,32,102,111,114,32,116,104,97,116,32,116,104,114,101,97,100,46>>]},{dl,[],[{dt,[],[{code,[],[<<97,117,120>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,104,97,110,100,108,105,110,103,32,97,117,120,105,108,105,97,114,121,32,106,111,98,115,46>>]},{dt,[],[{code,[],[<<99,104,101,99,107,95,105,111>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,99,104,101,99,107,105,110,103,32,102,111,114,32,110,101,119,32,73,47,79,32,101,118,101,110,116,115,46>>]},{dt,[],[{code,[],[<<101,109,117,108,97,116,111,114>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<103,99>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,101,120,116,114,97,32,115,116,97,116,101,115,32,97,114,101,32,101,110,97,98,108,101,100,32,116,104,105,115,32,105,115,32,116,104,101,32,116,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,110,111,110,45,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<111,116,104,101,114>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,117,110,97,99,99,111,117,110,116,101,100,32,116,104,105,110,103,115,46>>]},{dt,[],[{code,[],[<<112,111,114,116>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<115,108,101,101,112>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,115,108,101,101,112,105,110,103,46>>]}]},{p,[],[<<77,111,114,101,32,102,105,110,101,45,103,114,97,105,110,101,100,32>>,{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,83,116,97,116,101>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,116,104,114,111,117,103,104,32,99,111,110,102,105,103,117,114,101,32,40,115,117,99,104,32,97,115,32>>,{code,[],[<<46,47,99,111,110,102,105,103,117,114,101,32,45,45,119,105,116,104,45,109,105,99,114,111,115,116,97,116,101,45,97,99,99,111,117,110,116,105,110,103,61,101,120,116,114,97>>]},<<41,46,32,69,110,97,98,108,105,110,103,32,116,104,101,115,101,32,115,116,97,116,101,115,32,99,97,117,115,101,115,32,112,101,114,102,111,114,109,97,110,99,101,32,100,101,103,114,97,100,97,116,105,111,110,32,119,104,101,110,32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,32,97,110,100,32,105,110,99,114,101,97,115,101,115,32,116,104,101,32,111,118,101,114,104,101,97,100,32,119,104,101,110,32,105,116,32,105,115,32,116,117,114,110,101,100,32,111,110,46>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108,111,99>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,109,97,110,97,103,105,110,103,32,109,101,109,111,114,121,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,115,112,114,101,97,100,32,111,117,116,32,111,118,101,114,32,97,108,108,32,111,116,104,101,114,32,115,116,97,116,101,115,46>>]},{dt,[],[{code,[],[<<98,105,102>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,105,110,32,66,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<98,117,115,121,95,119,97,105,116>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,98,117,115,121,32,119,97,105,116,105,110,103,46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,115,116,97,116,101,32,119,104,101,114,101,32,97,32,115,99,104,101,100,117,108,101,114,32,110,111,32,108,111,110,103,101,114,32,114,101,112,111,114,116,115,32,116,104,97,116,32,105,116,32,105,115,32,97,99,116,105,118,101,32,119,104,101,110,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<46,32,83,111,44,32,105,102,32,121,111,117,32,97,100,100,32,97,108,108,32,111,116,104,101,114,32,115,116,97,116,101,115,32,98,117,116,32,116,104,105,115,32,97,110,100,32,115,108,101,101,112,44,32,97,110,100,32,116,104,101,110,32,100,105,118,105,100,101,32,116,104,97,116,32,98,121,32,97,108,108,32,116,105,109,101,32,105,110,32,116,104,101,32,116,104,114,101,97,100,44,32,121,111,117,32,115,104,111,117,108,100,32,103,101,116,32,115,111,109,101,116,104,105,110,103,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32,116,104,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,102,114,97,99,116,105,111,110,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<111,116,104,101,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<101,116,115>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,69,84,83,32,66,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<103,99,95,102,117,108,108>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<103,99>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<110,105,102>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,105,110,32,78,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<115,101,110,100>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,40,112,114,111,99,101,115,115,101,115,32,111,110,108,121,41,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<116,105,109,101,114,115>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,109,97,110,97,103,105,110,103,32,116,105,109,101,114,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<111,116,104,101,114>>]},<<32,115,116,97,116,101,46>>]}]},{p,[],[<<84,104,101,32,117,116,105,108,105,116,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,117,110,116,105,109,101,95,116,111,111,108,115,58,109,115,97,99,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,115,97,99,99,40,51,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,111,114,101,32,101,97,115,105,108,121,32,97,110,97,108,121,115,101,32,116,104,101,115,101,32,115,116,97,116,105,115,116,105,99,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>]}]},<<32,105,115,32,116,117,114,110,101,100,32,111,102,102,46>>]},{p,[],[<<84,104,101,32,108,105,115,116,32,111,102,32,116,104,114,101,97,100,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,115,111,114,116,101,100,32,97,110,100,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,100,105,102,102,101,114,101,110,116,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,99,97,108,108,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,97,110,100,32,115,116,97,116,101,115,32,97,114,101,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,119,105,116,104,111,117,116,32,97,110,121,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,54,48>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2544,bounded_fun,[{type,2544,'fun',[{type,2544,product,[{atom,2544,microstate_accounting}]},{type,2544,union,[{type,2544,list,[{var,2544,'MSAcc_Thread'}]},{atom,2544,undefined}]}]},[{type,2545,constraint,[{atom,2545,is_subtype},[{var,2545,'MSAcc_Thread'},{type,2545,map,[{type,2545,map_field_exact,[{atom,2545,type},{var,2545,'MSAcc_Thread_Type'}]},{type,2546,map_field_exact,[{atom,2546,id},{var,2546,'MSAcc_Thread_Id'}]},{type,2547,map_field_exact,[{atom,2547,counters},{var,2547,'MSAcc_Counters'}]}]}]]},{type,2548,constraint,[{atom,2548,is_subtype},[{var,2548,'MSAcc_Thread_Type'},{type,2548,union,[{atom,2548,async},{atom,2548,aux},{atom,2548,dirty_io_scheduler},{atom,2549,dirty_cpu_scheduler},{atom,2549,poll},{atom,2549,scheduler}]}]]},{type,2550,constraint,[{atom,2550,is_subtype},[{var,2550,'MSAcc_Thread_Id'},{type,2550,non_neg_integer,[]}]]},{type,2551,constraint,[{atom,2551,is_subtype},[{var,2551,'MSAcc_Counters'},{type,2551,map,[{type,2551,map_field_assoc,[{var,2551,'MSAcc_Thread_State'},{type,2551,non_neg_integer,[]}]}]}]]},{type,2552,constraint,[{atom,2552,is_subtype},[{var,2552,'MSAcc_Thread_State'},{type,2552,union,[{atom,2552,alloc},{atom,2552,aux},{atom,2552,bif},{atom,2552,busy_wait},{atom,2552,check_io},{atom,2553,emulator},{atom,2553,ets},{atom,2553,gc},{atom,2553,gc_fullsweep},{atom,2553,nif},{atom,2554,other},{atom,2554,port},{atom,2554,send},{atom,2554,sleep},{atom,2554,timers}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,114,101,100,117,99,116,105,111,110,115,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,114,101,100,117,99,116,105,111,110,115,41,46,10,123,50,48,52,54,44,49,49,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,53,32,40,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,41,44,32,116,104,105,115,32,118,97,108,117,101,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,114,101,100,117,99,116,105,111,110,115,32,112,101,114,102,111,114,109,101,100,32,105,110,32,99,117,114,114,101,110,116,32,116,105,109,101,32,115,108,105,99,101,115,32,111,102,32,99,117,114,114,101,110,116,108,121,32,115,99,104,101,100,117,108,101,100,32,112,114,111,99,101,115,115,101,115,46,32,73,102,32,97,110,32,101,120,97,99,116,32,118,97,108,117,101,32,105,115,32,119,97,110,116,101,100,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115,41>>]}]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,48,51>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2555,bounded_fun,[{type,2555,'fun',[{type,2555,product,[{atom,2555,reductions}]},{type,2555,tuple,[{var,2555,'Total_Reductions'},{var,2556,'Reductions_Since_Last_Call'}]}]},[{type,2557,constraint,[{atom,2557,is_subtype},[{var,2557,'Total_Reductions'},{type,2557,non_neg_integer,[]}]]},{type,2558,constraint,[{atom,2558,is_subtype},[{var,2558,'Reductions_Since_Last_Call'},{type,2558,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,111,116,97,108,32,108,101,110,103,116,104,32,111,102,32,97,108,108,32,110,111,114,109,97,108,32,97,110,100,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,97,116,32,105,115,44,32,113,117,101,117,101,100,32,119,111,114,107,32,116,104,97,116,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,105,115,32,109,117,99,104,32,109,111,114,101,32,101,120,112,101,110,115,105,118,101,32,99,111,109,112,97,114,101,100,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32,101,115,112,101,99,105,97,108,108,121,32,119,104,101,110,32,97,32,108,97,114,103,101,32,97,109,111,117,110,116,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,117,115,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,50,50>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2559,'fun',[{type,2559,product,[{atom,2559,run_queue}]},{type,2559,non_neg_integer,[]}]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<32,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,114,117,110,32,113,117,101,117,101,115,32,119,105,116,104,32,119,111,114,107,32,116,104,97,116,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,51,56>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2560,bounded_fun,[{type,2560,'fun',[{type,2560,product,[{atom,2560,run_queue_lengths}]},{type,2560,list,[{var,2560,'RunQueueLength'}]}]},[{type,2561,constraint,[{atom,2561,is_subtype},[{var,2561,'RunQueueLength'},{type,2561,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,114,101,97,100,121,32,116,111,32,114,117,110,32,102,111,114,32,101,97,99,104,32,114,117,110,32,113,117,101,117,101,46,32,86,97,108,117,101,115,32,102,111,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,97,114,101,32,108,111,99,97,116,101,100,32,102,105,114,115,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,32,111,102,32,115,99,104,101,100,117,108,101,114,32,110,117,109,98,101,114,32,49,32,97,110,100,32,115,111,32,111,110,46,32,73,102,32,115,117,112,112,111,114,116,32,102,111,114,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,44,32,118,97,108,117,101,115,32,102,111,114,32,116,104,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,102,111,108,108,111,119,32,40,105,110,32,116,104,97,116,32,111,114,100,101,114,41,32,97,116,32,116,104,101,32,101,110,100,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,105,108,121,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,105,110,115,116,101,97,100,32,113,117,105,116,101,32,101,102,102,105,99,105,101,110,116,108,121,32,103,97,116,104,101,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<69,97,99,104,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,111,110,101,32,114,117,110,32,113,117,101,117,101,32,116,104,97,116,32,105,116,32,109,97,110,97,103,101,115,46,32,73,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,108,108,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,44,32,97,110,100,32,97,108,108,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,46,32,84,104,97,116,32,105,115,44,32,119,101,32,104,97,118,101,32,109,117,108,116,105,112,108,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,44,32,111,110,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,111,110,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,46,32,87,111,114,107,32,99,97,110,32>>,{em,[],[<<110,111,116>>]},<<32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,114,117,110,32,113,117,101,117,101,115,46,32,79,110,108,121,32,119,111,114,107,32,105,110,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,99,97,110,32,109,105,103,114,97,116,101,32,116,111,32,111,116,104,101,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,105,115,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,53,51>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2562,bounded_fun,[{type,2562,'fun',[{type,2562,product,[{atom,2562,run_queue_lengths_all}]},{type,2562,list,[{var,2562,'RunQueueLength'}]}]},[{type,2563,constraint,[{atom,2563,is_subtype},[{var,2563,'RunQueueLength'},{type,2563,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,114,117,110,116,105,109,101,44,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]},{p,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,102,111,114,32,97,108,108,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,97,110,100,32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,119,97,108,108,32,99,108,111,99,107,32,116,105,109,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,109,105,103,104,116,32,119,114,97,112,32,100,117,101,32,116,111,32,108,105,109,105,116,97,116,105,111,110,115,32,105,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,112,114,111,118,105,100,101,100,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,116,104,97,116,32,105,115,32,117,115,101,100,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,114,117,110,116,105,109,101,41,46,10,123,49,54,57,48,44,49,54,50,48,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,57,54>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2564,bounded_fun,[{type,2564,'fun',[{type,2564,product,[{atom,2564,runtime}]},{type,2564,tuple,[{var,2564,'Total_Run_Time'},{var,2564,'Time_Since_Last_Call'}]}]},[{type,2565,constraint,[{atom,2565,is_subtype},[{var,2565,'Total_Run_Time'},{type,2565,non_neg_integer,[]}]]},{type,2566,constraint,[{atom,2566,is_subtype},[{var,2566,'Time_Since_Last_Call'},{type,2566,non_neg_integer,[]}]]}]]}]}}]}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<123,83,99,104,101,100,117,108,101,114,73,100,44,32,65,99,116,105,118,101,84,105,109,101,44,32,84,111,116,97,108,84,105,109,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,73,68,32,111,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,44,32>>,{code,[],[<<65,99,116,105,118,101,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,100,117,114,97,116,105,111,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,98,101,101,110,32,98,117,115,121,44,32,97,110,100,32>>,{code,[],[<<84,111,116,97,108,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,116,105,109,101,32,100,117,114,97,116,105,111,110,32,115,105,110,99,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]}]},<<32,97,99,116,105,118,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105,99,32,115,99,104,101,100,117,108,101,114,46,32,78,111,116,101,32,116,104,97,116,32,97,99,116,105,118,97,116,105,111,110,32,116,105,109,101,32,99,97,110,32,100,105,102,102,101,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,98,101,116,119,101,101,110,32,115,99,104,101,100,117,108,101,114,115,46,32,67,117,114,114,101,110,116,108,121,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,97,116,101,100,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,32,119,104,105,108,101,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,97,116,101,100,32,115,111,109,101,32,116,105,109,101,32,97,102,116,101,114,32,116,104,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,105,115,32,101,110,97,98,108,101,100,46,32,84,104,101,32,116,105,109,101,32,117,110,105,116,32,105,115,32,117,110,100,101,102,105,110,101,100,32,97,110,100,32,99,97,110,32,98,101,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,98,101,116,119,101,101,110,32,114,101,108,101,97,115,101,115,44,32,79,83,115,44,32,97,110,100,32,115,121,115,116,101,109,32,114,101,115,116,97,114,116,115,46,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,116,111,32,99,97,108,99,117,108,97,116,101,32,114,101,108,97,116,105,118,101,32,118,97,108,117,101,115,32,102,111,114,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,46,32>>,{code,[],[<<65,99,116,105,118,101,84,105,109,101>>]},<<32,99,97,110,32,110,101,118,101,114,32,101,120,99,101,101,100,32>>,{code,[],[<<84,111,116,97,108,84,105,109,101>>]},<<46>>]},{p,[],[<<84,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,98,117,115,121,32,115,99,104,101,100,117,108,101,114,32,105,115,32,119,104,101,110,32,105,116,32,105,115,32,110,111,116,32,105,100,108,101,32,97,110,100,32,105,115,32,110,111,116,32,115,99,104,101,100,117,108,105,110,103,32,40,115,101,108,101,99,116,105,110,103,41,32,97,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[<<69,120,101,99,117,116,105,110,103,32,112,114,111,99,101,115,115,32,99,111,100,101>>]},{li,[],[<<69,120,101,99,117,116,105,110,103,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,111,114,32,78,73,70,32,99,111,100,101>>]},{li,[],[<<69,120,101,99,117,116,105,110,103,32,66,73,70,115,44,32,111,114,32,97,110,121,32,111,116,104,101,114,32,114,117,110,116,105,109,101,32,104,97,110,100,108,105,110,103>>]},{li,[],[<<71,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,110,103>>]},{li,[],[<<72,97,110,100,108,105,110,103,32,97,110,121,32,111,116,104,101,114,32,109,101,109,111,114,121,32,109,97,110,97,103,101,109,101,110,116>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,115,99,104,101,100,117,108,101,114,32,99,97,110,32,97,108,115,111,32,98,101,32,98,117,115,121,32,101,118,101,110,32,105,102,32,116,104,101,32,79,83,32,104,97,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]}]},<<32,105,115,32,116,117,114,110,101,100,32,111,102,102,46>>]},{p,[],[<<84,104,101,32,108,105,115,116,32,111,102,32,115,99,104,101,100,117,108,101,114,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,115,111,114,116,101,100,32,97,110,100,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,100,105,102,102,101,114,101,110,116,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,99,97,108,108,115,46>>]},{p,[],[<<65,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,57,46,48,44,32,97,108,115,111,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46,32,84,104,97,116,32,105,115,44,32,97,108,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,116,104,97,116,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,104,97,110,100,108,101,32,67,80,85,32,98,111,117,110,100,32,119,111,114,107,46,32,73,102,32,121,111,117,32,97,108,115,111,32,119,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,95,97,108,108,41>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<78,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<49,32,61,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46,32,68,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,104,97,110,100,108,101,32,115,112,101,99,105,102,105,99,32,116,121,112,101,115,32,111,102,32,106,111,98,115,46,32,69,118,101,114,121,32,106,111,98,32,105,115,32,97,115,115,105,103,110,101,100,32,116,111,32,97,32,115,112,101,99,105,102,105,99,32,115,99,104,101,100,117,108,101,114,32,116,121,112,101,46,32,74,111,98,115,32,99,97,110,32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,100,105,102,102,101,114,101,110,116,32,115,99,104,101,100,117,108,101,114,115,32,111,102,32,116,104,101,32,115,97,109,101,32,116,121,112,101,44,32,98,117,116,32,110,101,118,101,114,32,98,101,116,119,101,101,110,32,115,99,104,101,100,117,108,101,114,115,32,111,102,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,46,32,84,104,105,115,32,102,97,99,116,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,117,110,100,101,114,32,99,111,110,115,105,100,101,114,97,116,105,111,110,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,46>>]}]},{p,[],[<<85,115,105,110,103,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,116,111,32,99,97,108,99,117,108,97,116,101,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,44,32,116,114,117,101,41,46,10,102,97,108,115,101,10,62,32,84,115,48,32,61,32,108,105,115,116,115,58,115,111,114,116,40,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41,41,44,32,111,107,46,10,111,107>>]}]},{p,[],[<<83,111,109,101,32,116,105,109,101,32,108,97,116,101,114,32,116,104,101,32,117,115,101,114,32,116,97,107,101,115,32,97,110,111,116,104,101,114,32,115,110,97,112,115,104,111,116,32,97,110,100,32,99,97,108,99,117,108,97,116,101,115,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,112,101,114,32,115,99,104,101,100,117,108,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,84,115,49,32,61,32,108,105,115,116,115,58,115,111,114,116,40,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41,41,44,32,111,107,46,10,111,107,10,62,32,108,105,115,116,115,58,109,97,112,40,102,117,110,40,123,123,73,44,32,65,48,44,32,84,48,125,44,32,123,73,44,32,65,49,44,32,84,49,125,125,41,32,45,62,10,9,123,73,44,32,40,65,49,32,45,32,65,48,41,47,40,84,49,32,45,32,84,48,41,125,32,101,110,100,44,32,108,105,115,116,115,58,122,105,112,40,84,115,48,44,84,115,49,41,41,46,10,91,123,49,44,48,46,57,55,52,51,52,55,52,55,51,48,49,55,55,53,52,56,125,44,10,32,123,50,44,48,46,57,55,52,52,56,52,51,55,56,50,55,53,49,52,52,52,125,44,10,32,123,51,44,48,46,57,57,57,53,57,48,50,51,54,49,54,54,57,48,52,53,125,44,10,32,123,52,44,48,46,57,55,51,56,48,49,50,53,57,54,53,55,50,49,54,49,125,44,10,32,123,53,44,48,46,57,55,49,55,57,53,54,54,54,55,48,49,56,49,48,51,125,44,10,32,123,54,44,48,46,57,55,51,57,50,51,53,56,52,54,52,50,48,55,52,49,125,44,10,32,123,55,44,48,46,57,55,51,50,51,55,48,51,51,48,55,55,56,55,54,125,44,10,32,123,56,44,48,46,57,55,52,49,50,57,55,50,57,51,50,52,56,54,53,54,125,93>>]}]},{p,[],[<<85,115,105,110,103,32,116,104,101,32,115,97,109,101,32,115,110,97,112,115,104,111,116,115,32,116,111,32,99,97,108,99,117,108,97,116,101,32,97,32,116,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<62,32,123,65,44,32,84,125,32,61,32,108,105,115,116,115,58,102,111,108,100,108,40,102,117,110,40,123,123,95,44,32,65,48,44,32,84,48,125,44,32,123,95,44,32,65,49,44,32,84,49,125,125,44,32,123,65,105,44,84,105,125,41,32,45,62,10,9,123,65,105,32,43,32,40,65,49,32,45,32,65,48,41,44,32,84,105,32,43,32,40,84,49,32,45,32,84,48,41,125,32,101,110,100,44,32,123,48,44,32,48,125,44,32,108,105,115,116,115,58,122,105,112,40,84,115,48,44,84,115,49,41,41,44,10,9,84,111,116,97,108,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,32,61,32,65,47,84,46,10,48,46,57,55,54,57,49,51,54,56,48,51,55,54,52,56,50,53>>]}]},{p,[],[<<84,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,105,108,108,32,101,113,117,97,108,32>>,{code,[],[<<49,46,48>>]},<<32,119,104,101,110,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,104,97,118,101,32,98,101,101,110,32,97,99,116,105,118,101,32,97,108,108,32,116,104,101,32,116,105,109,101,32,98,101,116,119,101,101,110,32,116,104,101,32,116,119,111,32,109,101,97,115,117,114,101,109,101,110,116,115,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,40,112,114,111,98,97,98,108,121,32,109,111,114,101,41,32,117,115,101,102,117,108,32,118,97,108,117,101,32,105,115,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,101,105,103,104,116,101,100,32,97,103,97,105,110,115,116,32,109,97,120,105,109,117,109,32,97,109,111,117,110,116,32,111,102,32,97,118,97,105,108,97,98,108,101,32,67,80,85,32,116,105,109,101,58>>]},{pre,[],[{code,[],[<<62,32,87,101,105,103,104,116,101,100,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,32,61,32,40,84,111,116,97,108,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,42,32,40,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41,41,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101,41,46,10,48,46,57,55,54,57,49,51,54,56,48,51,55,54,52,56,50,53>>]}]},{p,[],[<<84,104,105,115,32,119,101,105,103,104,116,101,100,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,105,108,108,32,114,101,97,99,104,32>>,{code,[],[<<49,46,48>>]},<<32,119,104,101,110,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,101,32,116,104,101,32,115,97,109,101,32,97,109,111,117,110,116,32,111,102,32,116,105,109,101,32,97,115,32,109,97,120,105,109,117,109,32,97,118,97,105,108,97,98,108,101,32,67,80,85,32,116,105,109,101,46,32,73,102,32,109,111,114,101,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,32,116,104,97,110,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,105,115,32,118,97,108,117,101,32,109,97,121,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<49,46,48>>]},<<46>>]},{p,[],[<<65,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,57,46,48,44,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,32,97,115,32,100,101,102,97,117,108,116,32,104,97,118,101,32,109,111,114,101,32,115,99,104,101,100,117,108,101,114,115,32,116,104,97,110,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,105,115,32,100,117,101,32,116,111,32,116,104,101,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,100,105,115,97,98,108,101,100,46,32,84,111,32,101,110,97,98,108,101,32,105,116,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,44,32,116,114,117,101,41>>]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,48,49,52>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2567,bounded_fun,[{type,2567,'fun',[{type,2567,product,[{atom,2567,scheduler_wall_time}]},{type,2567,union,[{type,2567,list,[{type,2567,tuple,[{var,2567,'SchedulerId'},{var,2567,'ActiveTime'},{var,2567,'TotalTime'}]}]},{atom,2567,undefined}]}]},[{type,2568,constraint,[{atom,2568,is_subtype},[{var,2568,'SchedulerId'},{type,2568,pos_integer,[]}]]},{type,2569,constraint,[{atom,2569,is_subtype},[{var,2569,'ActiveTime'},{type,2569,non_neg_integer,[]}]]},{type,2570,constraint,[{atom,2570,is_subtype},[{var,2570,'TotalTime'},{type,2570,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,97,108,115,111,32,105,110,99,108,117,100,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,108,108,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<68,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},{code,[],[<<32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},{code,[],[<<32,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,43,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41,32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,119,111,114,107,32,101,120,101,99,117,116,105,110,103,32,111,110,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,109,97,105,110,108,121,32,119,97,105,116,32,102,111,114,32,73,47,79,46,32,84,104,97,116,32,105,115,44,32,119,104,101,110,32,121,111,117,32,103,101,116,32,104,105,103,104,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,111,110,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,44,32,67,80,85,32,117,116,105,108,105,122,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,104,105,103,104,32,100,117,101,32,116,111,32,116,104,105,115,32,119,111,114,107,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,51,56>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2571,bounded_fun,[{type,2571,'fun',[{type,2571,product,[{atom,2571,scheduler_wall_time_all}]},{type,2571,union,[{type,2571,list,[{type,2571,tuple,[{var,2571,'SchedulerId'},{var,2571,'ActiveTime'},{var,2571,'TotalTime'}]}]},{atom,2571,undefined}]}]},[{type,2572,constraint,[{atom,2572,is_subtype},[{var,2572,'SchedulerId'},{type,2572,pos_integer,[]}]]},{type,2573,constraint,[{atom,2573,is_subtype},[{var,2573,'ActiveTime'},{type,2573,non_neg_integer,[]}]]},{type,2574,constraint,[{atom,2574,is_subtype},[{var,2574,'TotalTime'},{type,2574,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,54,54>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2575,bounded_fun,[{type,2575,'fun',[{type,2575,product,[{atom,2575,total_active_tasks}]},{var,2575,'ActiveTasks'}]},[{type,2576,constraint,[{atom,2576,is_subtype},[{var,2576,'ActiveTasks'},{type,2576,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,55,55>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2577,bounded_fun,[{type,2577,'fun',[{type,2577,product,[{atom,2577,total_active_tasks_all}]},{var,2577,'ActiveTasks'}]},[{type,2578,constraint,[{atom,2578,is_subtype},[{var,2578,'ActiveTasks'},{type,2578,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,56,56>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2579,bounded_fun,[{type,2579,'fun',[{type,2579,product,[{atom,2579,total_run_queue_lengths}]},{var,2579,'TotalRunQueueLengths'}]},[{type,2580,constraint,[{atom,2580,is_subtype},[{var,2580,'TotalRunQueueLengths'},{type,2580,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,57,57>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2581,bounded_fun,[{type,2581,'fun',[{type,2581,product,[{atom,2581,total_run_queue_lengths_all}]},{var,2581,'TotalRunQueueLengths'}]},[{type,2582,constraint,[{atom,2582,is_subtype},[{var,2582,'TotalRunQueueLengths'},{type,2582,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2528}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,119,97,108,108,32,99,108,111,99,107,46,32>>,{code,[],[<<119,97,108,108,95,99,108,111,99,107>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,32,116,104,101,32,115,97,109,101,32,109,97,110,110,101,114,32,97,115,32>>,{code,[],[<<114,117,110,116,105,109,101>>]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,114,101,97,108,32,116,105,109,101,32,105,115,32,109,101,97,115,117,114,101,100,32,97,115,32,111,112,112,111,115,101,100,32,116,111,32,114,117,110,116,105,109,101,32,111,114,32,67,80,85,32,116,105,109,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,49,48>>,signature => [{attribute,2528,spec,{{statistics,1},[{type,2583,bounded_fun,[{type,2583,'fun',[{type,2583,product,[{atom,2583,wall_clock}]},{type,2583,tuple,[{var,2583,'Total_Wallclock_Time'},{var,2584,'Wallclock_Time_Since_Last_Call'}]}]},[{type,2585,constraint,[{atom,2585,is_subtype},[{var,2585,'Total_Wallclock_Time'},{type,2585,non_neg_integer,[]}]]},{type,2586,constraint,[{atom,2586,is_subtype},[{var,2586,'Wallclock_Time_Since_Last_Call'},{type,2586,non_neg_integer,[]}]]}]]}]}}]}},{{function,suspend_process,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1942}],[<<115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>],#{<<101,110>> => [{p,[],[<<83,117,115,112,101,110,100,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,44,32,91,93,41>>]}]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,50,49>>,signature => [{attribute,1942,spec,{{erlang,suspend_process,1},[{type,1942,bounded_fun,[{type,1942,'fun',[{type,1942,product,[{var,1942,'Suspendee'}]},{atom,1942,true}]},[{type,1943,constraint,[{atom,1943,is_subtype},[{var,1943,'Suspendee'},{type,1943,pid,[]}]]}]]}]}}]}},{{function,suspend_process,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1926}],[<<115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>],#{<<101,110>> => [{p,[],[<<73,110,99,114,101,97,115,101,115,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,97,110,100,32,112,117,116,115,32,105,116,32,105,110,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,32,105,102,32,105,116,32,105,115,32,110,111,116,32,97,108,114,101,97,100,121,32,105,110,32,116,104,97,116,32,115,116,97,116,101,46,32,65,32,115,117,115,112,101,110,100,101,100,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,99,104,101,100,117,108,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,117,110,116,105,108,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,114,101,115,117,109,101,100,46>>]},{p,[],[<<65,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,115,117,115,112,101,110,100,101,100,32,98,121,32,109,117,108,116,105,112,108,101,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,99,97,110,32,98,101,32,115,117,115,112,101,110,100,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,98,121,32,97,32,115,105,110,103,108,101,32,112,114,111,99,101,115,115,46,32,65,32,115,117,115,112,101,110,100,101,100,32,112,114,111,99,101,115,115,32,100,111,101,115,32,110,111,116,32,108,101,97,118,101,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,32,117,110,116,105,108,32,105,116,115,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,114,101,97,99,104,101,115,32,122,101,114,111,46,32,84,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,100,101,99,114,101,97,115,101,100,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]}]},<<32,105,115,32,99,97,108,108,101,100,32,98,121,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<46,32,65,108,108,32,105,110,99,114,101,97,115,101,100,32,115,117,115,112,101,110,100,32,99,111,117,110,116,115,32,111,110,32,111,116,104,101,114,32,112,114,111,99,101,115,115,101,115,32,97,99,113,117,105,114,101,100,32,98,121,32,97,32,112,114,111,99,101,115,115,32,97,114,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,46>>]},{p,[],[<<79,112,116,105,111,110,115,32,40>>,{code,[],[<<79,112,116>>]},<<115,41,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]}]},{dd,[],[{p,[],[<<65,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,101,118,101,110,116,117,97,108,108,121,32,115,117,115,112,101,110,100,115,32,117,110,108,101,115,115,32,105,116,32,105,115,32,114,101,115,117,109,101,100,32,98,101,102,111,114,101,32,105,116,32,99,111,117,108,100,32,115,117,115,112,101,110,100,46,32,84,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,114,101,116,117,114,110,115,32,105,109,109,101,100,105,97,116,101,108,121,44,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,115,117,115,112,101,110,100,101,100,32,121,101,116,32,111,114,32,110,111,116,46,32,84,104,101,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,119,104,101,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,115,117,115,112,101,110,100,115,32,99,97,110,110,111,116,32,98,101,32,100,101,100,117,99,101,100,32,102,114,111,109,32,111,116,104,101,114,32,101,118,101,110,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,116,32,105,115,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32>>,{em,[],[<<101,118,101,110,116,117,97,108,108,121>>]},<<32,115,117,115,112,101,110,100,115,32,40,117,110,108,101,115,115,32,105,116,32,105,115,32,114,101,115,117,109,101,100,41,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,112,116,105,111,110,115,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,105,115,32,98,108,111,99,107,101,100,32,117,110,116,105,108,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,115,117,115,112,101,110,100,101,100,46>>]}]},{dt,[],[{code,[],[<<123,97,115,121,110,99,104,114,111,110,111,117,115,44,32,82,101,112,108,121,84,97,103,125>>]}]},{dd,[],[{p,[],[<<65,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,87,104,101,110,32,116,104,101,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,84,104,101,32,114,101,112,108,121,32,105,115,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,83,116,97,116,101,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<83,116,97,116,101>>]},<<32,105,115,32,101,105,116,104,101,114,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,105,116,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,101,120,105,116,101,100,46>>]}]},{dt,[],[{code,[],[<<115,117,115,112,101,110,100,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,119,32,115,117,115,112,101,110,100,101,100,46>>]}]},{dt,[],[{code,[],[<<110,111,116,95,115,117,115,112,101,110,100,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,46,32,84,104,105,115,32,99,97,110,32,111,110,108,121,32,104,97,112,112,101,110,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,115,115,117,101,100,32,116,104,105,115,32,114,101,113,117,101,115,116,44,32,104,97,118,101,32,99,97,108,108,101,100,32>>,{code,[],[<<114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<32,98,101,102,111,114,101,32,103,101,116,116,105,110,103,32,116,104,101,32,114,101,112,108,121,46>>]}]}]},{p,[],[<<65,112,112,97,114,116,32,102,114,111,109,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,44,32,116,104,101,32>>,{code,[],[<<123,97,115,121,110,99,104,114,111,110,111,117,115,44,32,82,101,112,108,121,84,97,103,125>>]},<<32,111,112,116,105,111,110,32,98,101,104,97,118,101,115,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,112,116,105,111,110,32,119,105,116,104,111,117,116,32,114,101,112,108,121,32,116,97,103,46>>]}]},{dt,[],[{code,[],[<<117,110,108,101,115,115,95,115,117,115,112,101,110,100,105,110,103>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,108,101,115,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,73,102,32>>,{code,[],[<<117,110,108,101,115,115,95,115,117,115,112,101,110,100,105,110,103>>]},<<32,105,115,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<44,32,97,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,117,110,108,101,115,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,111,114,32,105,102,32,97,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,97,108,114,101,97,100,121,32,104,97,115,32,98,101,101,110,32,115,101,110,116,32,97,110,100,32,105,115,32,105,110,32,116,114,97,110,115,105,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<44,32,111,114,32,105,102,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,97,110,100,32,97,32,115,101,110,100,32,114,101,113,117,101,115,116,32,97,108,114,101,97,100,121,32,105,115,32,105,110,32,116,114,97,110,115,105,116,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,109,97,105,110,115,32,117,110,99,104,97,110,103,101,100,46>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,105,110,99,114,101,97,115,101,100,44,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<89,111,117,32,99,97,110,32,101,97,115,105,108,121,32,99,114,101,97,116,101,32,100,101,97,100,108,111,99,107,115,32,105,102,32,112,114,111,99,101,115,115,101,115,32,115,117,115,112,101,110,100,115,32,101,97,99,104,32,111,116,104,101,114,32,40,100,105,114,101,99,116,108,121,32,111,114,32,105,110,32,99,105,114,99,108,101,115,41,46,32,73,110,32,69,82,84,83,32,118,101,114,115,105,111,110,115,32,112,114,105,111,114,32,116,111,32,69,82,84,83,32,118,101,114,115,105,111,110,32,49,48,46,48,44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,112,114,101,118,101,110,116,101,100,32,115,117,99,104,32,100,101,97,100,108,111,99,107,115,44,32,98,117,116,32,116,104,105,115,32,112,114,101,118,101,110,116,105,111,110,32,104,97,115,32,110,111,119,32,98,101,101,110,32,114,101,109,111,118,101,100,32,100,117,101,32,116,111,32,112,101,114,102,111,114,109,97,110,99,101,32,114,101,97,115,111,110,115,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,115,105,100,101,115,32,111,110,32,97,110,111,116,104,101,114,32,110,111,100,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116>>]},<<115,46>>]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,109,111,114,101,32,116,105,109,101,115,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,116,104,97,110,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,105,110,116,101,114,110,97,108,32,100,97,116,97,32,115,116,114,117,99,116,117,114,101,115,46,32,84,104,101,32,115,121,115,116,101,109,32,108,105,109,105,116,32,105,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,50,44,48,48,48,44,48,48,48,44,48,48,48,32,115,117,115,112,101,110,100,115,32,97,110,100,32,119,105,108,108,32,110,101,118,101,114,32,98,101,32,108,111,119,101,114,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,51,54>>,signature => [{attribute,1926,spec,{{erlang,suspend_process,2},[{type,1926,bounded_fun,[{type,1926,'fun',[{type,1926,product,[{var,1926,'Suspendee'},{var,1926,'OptList'}]},{type,1926,boolean,[]}]},[{type,1927,constraint,[{atom,1927,is_subtype},[{var,1927,'Suspendee'},{type,1927,pid,[]}]]},{type,1928,constraint,[{atom,1928,is_subtype},[{var,1928,'OptList'},{type,1928,list,[{var,1928,'Opt'}]}]]},{type,1929,constraint,[{atom,1929,is_subtype},[{var,1929,'Opt'},{type,1929,union,[{atom,1929,unless_suspending},{atom,1929,asynchronous},{type,1929,tuple,[{atom,1929,asynchronous},{type,1929,term,[]}]}]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,100,101,112,116,104,32,111,102,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,115,32,105,110,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<39,69,88,73,84,39>>]},<<32,116,117,112,108,101,115,46,32,84,104,101,32,102,108,97,103,32,97,108,115,111,32,108,105,109,105,116,115,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,32,100,101,112,116,104,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111>>]},<<32,105,116,101,109,32>>,{code,[],[<<99,117,114,114,101,110,116,95,115,116,97,99,107,116,114,97,99,101,46>>]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,51,56,50>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2606,bounded_fun,[{type,2606,'fun',[{type,2606,product,[{atom,2606,backtrace_depth},{var,2606,'Depth'}]},{var,2606,'OldDepth'}]},[{type,2607,constraint,[{atom,2607,is_subtype},[{var,2607,'Depth'},{type,2607,non_neg_integer,[]}]]},{type,2608,constraint,[{atom,2608,is_subtype},[{var,2608,'OldDepth'},{type,2608,non_neg_integer,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>}],[]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>}],[]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>}],[]},{li,[{name,<<115,117,98,95,108,101,118,101,108>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,73,110,115,116,101,97,100,32,111,102,32,117,115,105,110,103,32,116,104,105,115,32,97,114,103,117,109,101,110,116,44,32,117,115,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,114,101,109,111,118,101,100,44,32,97,32,102,105,110,97,108,32,67,80,85,32,116,111,112,111,108,111,103,121,32,116,111,32,117,115,101,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,46>>]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<46,32,84,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,118,101,114,114,105,100,101,115,32,97,110,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,46,32,66,121,32,112,97,115,115,105,110,103,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,97,115,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<44,32,116,104,101,32,115,121,115,116,101,109,32,114,101,118,101,114,116,115,32,116,111,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,101,113,117,97,108,115,32,116,104,101,32,118,97,108,117,101,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,99,112,117,95,116,111,112,111,108,111,103,121,41>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,99,104,97,110,103,101,32,119,97,115,32,109,97,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,98,105,110,100,105,110,103,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,73,102,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,108,114,101,97,100,121,32,98,111,117,110,100,32,119,104,101,110,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,99,104,97,110,103,101,100,44,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,101,110,116,32,97,32,114,101,113,117,101,115,116,32,116,111,32,114,101,98,105,110,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,110,101,119,32,67,80,85,32,116,111,112,111,108,111,103,121,46>>]},{p,[],[<<84,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,116,121,112,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,97,110,100,32,109,111,114,101,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,99,112,117,95,116,111,112,111,108,111,103,121,41>>]}]},<<32,97,115,32,119,101,108,108,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,51,57,52>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2609,bounded_fun,[{type,2609,'fun',[{type,2609,product,[{atom,2609,cpu_topology},{var,2609,'CpuTopology'}]},{var,2609,'OldCpuTopology'}]},[{type,2610,constraint,[{atom,2610,is_subtype},[{var,2610,'CpuTopology'},{user_type,2610,cpu_topology,[]}]]},{type,2611,constraint,[{atom,2611,is_subtype},[{var,2611,'OldCpuTopology'},{user_type,2611,cpu_topology,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,82,97,110,103,101,32,105,115,32>>,{code,[],[<<49,32,60,61,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,78>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,99,104,97,110,103,101,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,104,97,110,103,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,49,50,32,115,99,104,101,100,117,108,101,114,115,32,97,110,100,32,54,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,111,110,108,105,110,101,44,32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>]},<<32,105,115,32,117,115,101,100,32,116,111,32,115,101,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,116,111,32,54,44,32,116,104,101,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,98,121,32,104,97,108,102,32,97,115,32,119,101,108,108,44,32,100,111,119,110,32,116,111,32,51,46,32,83,105,109,105,108,97,114,108,121,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,110,99,114,101,97,115,101,115,32,112,114,111,112,111,114,116,105,111,110,97,108,108,121,32,116,111,32,105,110,99,114,101,97,115,101,115,32,105,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,52,52,50>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2612,bounded_fun,[{type,2612,'fun',[{type,2612,product,[{atom,2612,dirty_cpu_schedulers_online},{var,2612,'DirtyCPUSchedulersOnline'}]},{var,2613,'OldDirtyCPUSchedulersOnline'}]},[{type,2614,constraint,[{atom,2614,is_subtype},[{var,2614,'DirtyCPUSchedulersOnline'},{type,2614,pos_integer,[]}]]},{type,2615,constraint,[{atom,2615,is_subtype},[{var,2615,'OldDirtyCPUSchedulersOnline'},{type,2615,pos_integer,[]}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,102,108,97,103,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,116,104,101,32,97,108,108,111,99,97,116,111,114,32,116,111,32,97,102,102,101,99,116,44,32,102,111,114,32,101,120,97,109,112,108,101,32>>,{code,[],[<<98,105,110,97,114,121,95,97,108,108,111,99>>]},<<46,32>>,{code,[],[<<70>>]},<<32,105,115,32,116,104,101,32,102,108,97,103,32,116,111,32,99,104,97,110,103,101,32,97,110,100,32>>,{code,[],[<<86>>]},<<32,105,115,32,116,104,101,32,110,101,119,32,118,97,108,117,101,46>>]},{p,[],[<<79,110,108,121,32,97,32,115,117,98,115,101,116,32,111,102,32,97,108,108,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99>>]},<<32,102,108,97,103,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,114,117,110,32,116,105,109,101,46,32,84,104,105,115,32,115,117,98,115,101,116,32,105,115,32,99,117,114,114,101,110,116,108,121,32,111,110,108,121,32,116,104,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,77,95,115,98,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<115,98,99,116>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,102,108,97,103,32,119,97,115,32,115,101,116,32,111,114,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,105,102,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,52,55,49>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2616,bounded_fun,[{type,2616,'fun',[{type,2616,product,[{atom,2616,erts_alloc},{type,2616,tuple,[{var,2616,'Alloc'},{var,2616,'F'},{var,2616,'V'}]}]},{type,2616,union,[{atom,2616,ok},{atom,2616,notsup}]}]},[{type,2617,constraint,[{atom,2617,is_subtype},[{var,2617,'Alloc'},{type,2617,atom,[]}]]},{type,2618,constraint,[{atom,2618,is_subtype},[{var,2618,'F'},{type,2618,atom,[]}]]},{type,2619,constraint,[{atom,2619,is_subtype},[{var,2619,'V'},{type,2619,integer,[]}]]}]]}]}}],since => <<79,84,80,32,50,48,46,50,46,51>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<46,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,105,115,32,97,32,110,111,110,45,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,32,105,110,100,105,99,97,116,105,110,103,32,104,111,119,32,109,97,110,121,32,116,105,109,101,115,32,103,101,110,101,114,97,116,105,111,110,97,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,99,97,110,32,98,101,32,100,111,110,101,32,119,105,116,104,111,117,116,32,102,111,114,99,105,110,103,32,97,32,102,117,108,108,115,119,101,101,112,32,99,111,108,108,101,99,116,105,111,110,46,32,84,104,101,32,118,97,108,117,101,32,97,112,112,108,105,101,115,32,116,111,32,110,101,119,32,112,114,111,99,101,115,115,101,115,44,32,119,104,105,108,101,32,112,114,111,99,101,115,115,101,115,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,32,97,114,101,32,110,111,116,32,97,102,102,101,99,116,101,100,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<73,110,32,108,111,119,45,109,101,109,111,114,121,32,115,121,115,116,101,109,115,32,40,101,115,112,101,99,105,97,108,108,121,32,119,105,116,104,111,117,116,32,118,105,114,116,117,97,108,32,109,101,109,111,114,121,41,44,32,115,101,116,116,105,110,103,32,116,104,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<48>>]},<<32,99,97,110,32,104,101,108,112,32,116,111,32,99,111,110,115,101,114,118,101,32,109,101,109,111,114,121,46>>]},{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,116,104,114,111,117,103,104,32,40,79,83,41,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,32>>,{code,[],[<<69,82,76,95,70,85,76,76,83,87,69,69,80,95,65,70,84,69,82>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,52,56,56>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2620,bounded_fun,[{type,2620,'fun',[{type,2620,product,[{atom,2620,fullsweep_after},{var,2620,'Number'}]},{var,2620,'OldNumber'}]},[{type,2621,constraint,[{atom,2621,is_subtype},[{var,2621,'Number'},{type,2621,non_neg_integer,[]}]]},{type,2622,constraint,[{atom,2622,is_subtype},[{var,2622,'OldNumber'},{type,2622,non_neg_integer,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<84,117,114,110,115,32,111,110,47,111,102,102,32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,109,101,97,115,117,114,101,109,101,110,116,115,46,32,87,104,101,110,32,112,97,115,115,105,110,103,32,114,101,115,101,116,44,32,97,108,108,32,99,111,117,110,116,101,114,115,32,97,114,101,32,114,101,115,101,116,32,116,111,32,48,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,48,55>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2623,bounded_fun,[{type,2623,'fun',[{type,2623,product,[{atom,2623,microstate_accounting},{var,2623,'Action'}]},{var,2623,'OldState'}]},[{type,2624,constraint,[{atom,2624,is_subtype},[{var,2624,'Action'},{type,2624,union,[{atom,2624,true},{atom,2624,false},{atom,2624,reset}]}]]},{type,2625,constraint,[{atom,2625,is_subtype},[{var,2625,'OldState'},{type,2625,union,[{atom,2625,true},{atom,2625,false}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,97,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,50,49>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2626,bounded_fun,[{type,2626,'fun',[{type,2626,product,[{atom,2626,min_heap_size},{var,2626,'MinHeapSize'}]},{var,2626,'OldMinHeapSize'}]},[{type,2627,constraint,[{atom,2627,is_subtype},[{var,2627,'MinHeapSize'},{type,2627,non_neg_integer,[]}]]},{type,2628,constraint,[{atom,2628,is_subtype},[{var,2628,'OldMinHeapSize'},{type,2628,non_neg_integer,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,97,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,51,54>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2629,bounded_fun,[{type,2629,'fun',[{type,2629,product,[{atom,2629,min_bin_vheap_size},{var,2629,'MinBinVHeapSize'}]},{var,2630,'OldMinBinVHeapSize'}]},[{type,2631,constraint,[{atom,2631,is_subtype},[{var,2631,'MinBinVHeapSize'},{type,2631,non_neg_integer,[]}]]},{type,2632,constraint,[{atom,2632,is_subtype},[{var,2632,'OldMinBinVHeapSize'},{type,2632,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,115,101,116,116,105,110,103,115,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,101,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,53,51>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2633,bounded_fun,[{type,2633,'fun',[{type,2633,product,[{atom,2633,max_heap_size},{var,2633,'MaxHeapSize'}]},{var,2633,'OldMaxHeapSize'}]},[{type,2634,constraint,[{atom,2634,is_subtype},[{var,2634,'MaxHeapSize'},{user_type,2634,max_heap_size,[]}]]},{type,2635,constraint,[{atom,2635,is_subtype},[{var,2635,'OldMaxHeapSize'},{user_type,2635,max_heap_size,[]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,101,110,97,98,108,101,100,44,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,77,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,99,97,110,32,98,101,32,98,108,111,99,107,101,100,32,105,110,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,46,32,69,105,116,104,101,114,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,44,32,111,114,32,97,108,108,32>>,{em,[],[<<110,111,114,109,97,108>>]},<<32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,46,32,87,104,101,110,32,111,110,108,121,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,108,111,99,107,101,100,44,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,102,114,101,101,32,116,111,32,99,111,110,116,105,110,117,101,32,116,111,32,115,99,104,101,100,117,108,101,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,98,108,111,99,107>>]},<<44,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,101,32,97,110,100,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,119,105,108,108,32,101,120,101,99,117,116,101,46,32,73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,117,110,98,108,111,99,107>>]},<<32,97,110,100,32,110,111,32,111,110,101,32,101,108,115,101,32,98,108,111,99,107,115,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,44,32,97,110,100,32,116,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,111,110,108,121,32,111,110,99,101,44,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,117,110,98,108,111,99,107,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,98,108,111,99,107,95,110,111,114,109,97,108>>]},<<44,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,111,110,101,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,119,105,108,108,32,101,120,101,99,117,116,101,44,32,98,117,116,32,109,117,108,116,105,112,108,101,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,99,97,110,32,101,120,101,99,117,116,101,46,32,73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,117,110,98,108,111,99,107,95,110,111,114,109,97,108>>]},<<32,97,110,100,32,110,111,32,111,110,101,32,101,108,115,101,32,98,108,111,99,107,115,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,44,32,97,110,100,32,116,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,111,110,108,121,32,111,110,99,101,44,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,117,110,98,108,111,99,107,101,100,46>>]},{p,[],[<<79,110,101,32,112,114,111,99,101,115,115,32,99,97,110,32,98,108,111,99,107,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,44,32,105,116,32,109,117,115,116,32,117,110,98,108,111,99,107,32,101,120,97,99,116,108,121,32,97,115,32,109,97,110,121,32,116,105,109,101,115,32,97,115,32,105,116,32,104,97,115,32,98,108,111,99,107,101,100,32,98,101,102,111,114,101,32,105,116,32,104,97,115,32,114,101,108,101,97,115,101,100,32,105,116,115,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,98,108,111,99,107,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,111,114,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,101,120,105,116,115,44,32,105,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,108,101,97,115,101,115,32,105,116,115,32,98,108,111,99,107,105,110,103,32,111,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,97,114,101,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<44,32>>,{code,[],[<<98,108,111,99,107,101,100>>]},<<44,32>>,{code,[],[<<98,108,111,99,107,101,100,95,110,111,114,109,97,108>>]},<<44,32,111,114,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,100,101,115,99,114,105,98,101,115,32,116,104,101,32,115,116,97,116,101,32,106,117,115,116,32,97,102,116,101,114,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,108,111,99,107,105,110,103,32,111,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,110,111,114,109,97,108,108,121,32,110,111,116,32,110,101,101,100,101,100,46,32,73,102,32,121,111,117,32,102,101,101,108,32,116,104,97,116,32,121,111,117,32,110,101,101,100,32,116,111,32,117,115,101,32,116,104,101,115,101,32,102,101,97,116,117,114,101,115,44,32,99,111,110,115,105,100,101,114,32,105,116,32,97,32,102,101,119,32,109,111,114,101,32,116,105,109,101,115,32,97,103,97,105,110,46,32,66,108,111,99,107,105,110,103,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,97,115,32,97,32,108,97,115,116,32,114,101,115,111,114,116,44,32,97,115,32,105,116,32,105,115,32,109,111,115,116,32,108,105,107,101,108,121,32,97,32>>,{em,[],[<<118,101,114,121,32,105,110,101,102,102,105,99,105,101,110,116>>]},<<32,119,97,121,32,116,111,32,115,111,108,118,101,32,116,104,101,32,112,114,111,98,108,101,109,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,55,49>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2636,bounded_fun,[{type,2636,'fun',[{type,2636,product,[{atom,2636,multi_scheduling},{var,2636,'BlockState'}]},{var,2636,'OldBlockState'}]},[{type,2637,constraint,[{atom,2637,is_subtype},[{var,2637,'BlockState'},{type,2637,union,[{atom,2637,block},{atom,2637,unblock},{atom,2637,block_normal},{atom,2637,unblock_normal}]}]]},{type,2638,constraint,[{atom,2638,is_subtype},[{var,2638,'OldBlockState'},{type,2638,union,[{atom,2638,blocked},{atom,2638,disabled},{atom,2638,enabled}]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,73,110,115,116,101,97,100,32,111,102,32,117,115,105,110,103,32,116,104,105,115,32,97,114,103,117,109,101,110,116,44,32,117,115,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,87,104,101,110,32,116,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,114,101,109,111,118,101,100,44,32,97,32,102,105,110,97,108,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,32,116,121,112,101,32,116,111,32,117,115,101,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,46>>]}]},{p,[],[<<67,111,110,116,114,111,108,115,32,105,102,32,97,110,100,32,104,111,119,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{p,[],[<<87,104,101,110,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101,44,32,72,111,119,41>>]},<<32,105,115,32,99,97,108,108,101,100,44,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,44,32,99,97,117,115,105,110,103,32,116,104,101,109,32,116,111,32,116,114,121,32,116,111,32,98,105,110,100,32,111,114,32,117,110,98,105,110,100,32,97,115,32,114,101,113,117,101,115,116,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,115,99,104,101,100,117,108,101,114,32,102,97,105,108,115,32,116,111,32,98,105,110,100,44,32,116,104,105,115,32,105,115,32,111,102,116,101,110,32,115,105,108,101,110,116,108,121,32,105,103,110,111,114,101,100,44,32,97,115,32,105,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,112,111,115,115,105,98,108,101,32,116,111,32,118,101,114,105,102,121,32,118,97,108,105,100,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,115,46,32,73,102,32,97,110,32,101,114,114,111,114,32,105,115,32,114,101,112,111,114,116,101,100,44,32,97,110,32,101,114,114,111,114,32,101,118,101,110,116,32,105,115,32,108,111,103,103,101,100,46,32,84,111,32,118,101,114,105,102,121,32,116,104,97,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,104,97,118,101,32,98,111,117,110,100,32,97,115,32,114,101,113,117,101,115,116,101,100,44,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]}]},{p,[],[<<83,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,98,111,117,110,100,32,111,110,32,110,101,119,101,114,32,76,105,110,117,120,44,32,83,111,108,97,114,105,115,44,32,70,114,101,101,66,83,68,44,32,97,110,100,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,115,44,32,98,117,116,32,109,111,114,101,32,115,121,115,116,101,109,115,32,119,105,108,108,32,98,101,32,115,117,112,112,111,114,116,101,100,32,105,110,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,115,46>>]},{p,[],[<<73,110,32,111,114,100,101,114,32,102,111,114,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,111,32,98,101,32,97,98,108,101,32,116,111,32,98,105,110,100,32,115,99,104,101,100,117,108,101,114,115,44,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,109,117,115,116,32,98,101,32,107,110,111,119,110,46,32,73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,102,97,105,108,115,32,116,111,32,100,101,116,101,99,116,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,44,32,105,116,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,100,101,102,105,110,101,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,111,101,115,32,98,121,32,100,101,102,97,117,108,116,32>>,{em,[],[<<110,111,116>>]},<<32,98,105,110,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,116,104,101,32,111,110,108,121,32,79,83,32,112,114,111,99,101,115,115,32,98,105,110,100,105,110,103,32,116,104,114,101,97,100,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,105,115,32,105,109,112,114,111,118,101,115,32,116,104,101,32,112,101,114,102,111,114,109,97,110,99,101,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,116,104,101,114,32,79,83,32,112,114,111,99,101,115,115,101,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,110,111,116,104,101,114,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,108,115,111,32,98,105,110,100,32,116,104,114,101,97,100,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,101,114,101,32,99,97,110,32,98,101,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,112,101,110,97,108,116,121,32,105,110,115,116,101,97,100,46,32,83,111,109,101,116,105,109,101,115,32,116,104,105,115,32,112,101,114,102,111,114,109,97,110,99,101,32,112,101,110,97,108,116,121,32,99,97,110,32,98,101,32,115,101,118,101,114,101,46,32,73,102,32,115,111,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,110,111,116,32,98,105,110,100,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,46>>]}]},{p,[],[<<83,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,98,111,117,110,100,32,105,110,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,46,32,65,114,103,117,109,101,110,116,32>>,{code,[],[<<72,111,119>>]},<<32,100,101,116,101,114,109,105,110,101,115,32,104,111,119,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,32,97,110,100,32,99,97,110,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<117,110,98,111,117,110,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<116,104,114,101,97,100,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,116,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,110,111,100,101,95,116,104,114,101,97,100,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,110,116,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,110,111,100,101,95,112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,110,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<116,104,114,101,97,100,95,110,111,95,110,111,100,101,95,112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,116,110,110,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<100,101,102,97,117,108,116,95,98,105,110,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,100,98>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,101,113,117,97,108,115,32>>,{code,[],[<<72,111,119>>]},<<32,98,101,102,111,114,101,32,102,108,97,103,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]},<<32,119,97,115,32,99,104,97,110,103,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,98,105,110,100,105,110,103,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<72,111,119>>]},<<32,105,115,32,110,111,116,32,111,110,101,32,111,102,32,116,104,101,32,100,111,99,117,109,101,110,116,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,97,118,97,105,108,97,98,108,101,46>>]}]},{p,[],[<<84,104,101,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,32,116,121,112,101,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<44,32,97,115,32,119,101,108,108,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,54,50,55>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2639,bounded_fun,[{type,2639,'fun',[{type,2639,product,[{atom,2639,scheduler_bind_type},{var,2639,'How'}]},{var,2639,'OldBindType'}]},[{type,2640,constraint,[{atom,2640,is_subtype},[{var,2640,'How'},{type,2640,union,[{user_type,2640,scheduler_bind_type,[]},{atom,2640,default_bind}]}]]},{type,2641,constraint,[{atom,2641,is_subtype},[{var,2641,'OldBindType'},{user_type,2641,scheduler_bind_type,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,115,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,53,52>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2642,bounded_fun,[{type,2642,'fun',[{type,2642,product,[{atom,2642,scheduler_wall_time},{var,2642,'Boolean'}]},{var,2642,'OldBoolean'}]},[{type,2643,constraint,[{atom,2643,is_subtype},[{var,2643,'Boolean'},{type,2643,boolean,[]}]]},{type,2644,constraint,[{atom,2644,is_subtype},[{var,2644,'OldBoolean'},{type,2644,boolean,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,82,97,110,103,101,32,105,115,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<73,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,98,117,105,108,116,32,119,105,116,104,32,115,117,112,112,111,114,116,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115>>]},<<44,32,99,104,97,110,103,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,97,108,115,111,32,99,104,97,110,103,101,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,49,50,32,115,99,104,101,100,117,108,101,114,115,32,97,110,100,32,54,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,111,110,108,105,110,101,44,32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>]},<<32,105,115,32,117,115,101,100,32,116,111,32,115,101,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,116,111,32,54,44,32,116,104,101,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,98,121,32,104,97,108,102,32,97,115,32,119,101,108,108,44,32,100,111,119,110,32,116,111,32,51,46,32,83,105,109,105,108,97,114,108,121,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,110,99,114,101,97,115,101,115,32,112,114,111,112,111,114,116,105,111,110,97,108,108,121,32,116,111,32,105,110,99,114,101,97,115,101,115,32,105,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,54,55>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2645,bounded_fun,[{type,2645,'fun',[{type,2645,product,[{atom,2645,schedulers_online},{var,2645,'SchedulersOnline'}]},{var,2646,'OldSchedulersOnline'}]},[{type,2647,constraint,[{atom,2647,is_subtype},[{var,2647,'SchedulersOnline'},{type,2647,pos_integer,[]}]]},{type,2648,constraint,[{atom,2648,is_subtype},[{var,2648,'OldSchedulersOnline'},{type,2648,pos_integer,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,119,105,108,108,32,114,101,99,101,105,118,101,32,116,104,101,32,108,111,103,103,105,110,103,32,109,101,115,115,97,103,101,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,69,82,84,83,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,97,108,108,32,108,111,103,103,105,110,103,32,109,101,115,115,97,103,101,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,69,82,84,83,32,119,105,108,108,32,98,101,32,100,114,111,112,112,101,100,46,32,84,104,101,32,109,101,115,115,97,103,101,115,32,119,105,108,108,32,98,101,32,105,110,32,116,104,101,32,102,111,114,109,97,116,58>>]},{pre,[],[{code,[],[<<123,108,111,103,44,76,101,118,101,108,44,70,111,114,109,97,116,44,65,114,103,76,105,115,116,44,77,101,116,97,100,97,116,97,125,32,119,104,101,114,101,10,10,76,101,118,101,108,32,61,32,97,116,111,109,40,41,44,10,70,111,114,109,97,116,32,61,32,115,116,114,105,110,103,40,41,44,10,65,114,103,76,105,115,116,32,61,32,108,105,115,116,40,116,101,114,109,40,41,41,44,10,77,101,116,97,100,97,116,97,32,61,32,35,123,32,112,105,100,32,61,62,32,112,105,100,40,41,44,10,32,32,32,103,114,111,117,112,95,108,101,97,100,101,114,32,61,62,32,112,105,100,40,41,44,10,32,32,32,116,105,109,101,32,58,61,32,108,111,103,103,101,114,58,116,105,109,101,115,116,97,109,112,40,41,44,10,32,32,32,101,114,114,111,114,95,108,111,103,103,101,114,32,58,61,32,35,123,32,101,109,117,108,97,116,111,114,32,58,61,32,116,114,117,101,44,32,116,97,103,32,58,61,32,97,116,111,109,40,41,32,125,10,32,32,32,32,32,32,32,32>>]}]},{p,[],[<<73,102,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]},<<32,112,114,111,99,101,115,115,32,100,105,101,115,44,32,116,104,105,115,32,102,108,97,103,32,119,105,108,108,32,98,101,32,114,101,115,101,116,32,116,111,32>>,{code,[],[<<108,111,103,103,101,114>>]},<<46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,110,97,109,101,100,32>>,{code,[],[<<108,111,103,103,101,114>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,115,105,103,110,101,100,32,116,111,32,98,101,32,117,115,101,100,32,98,121,32,116,104,101,32,75,69,82,78,69,76,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,103,101,114>>]}]},<<46,32,66,101,32,99,97,114,101,102,117,108,32,105,102,32,121,111,117,32,99,104,97,110,103,101,32,105,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,97,115,32,108,111,103,32,109,101,115,115,97,103,101,115,32,109,97,121,32,98,101,32,108,111,115,116,46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,105,110,116,101,114,99,101,112,116,32,101,109,117,108,97,116,111,114,32,108,111,103,32,109,101,115,115,97,103,101,115,44,32,100,111,32,105,116,32,98,121,32,97,100,100,105,110,103,32,97,32,115,112,101,99,105,97,108,105,122,101,100,32,104,97,110,100,108,101,114,32,116,111,32,116,104,101,32,75,69,82,78,69,76,32,108,111,103,103,101,114,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,57,54>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2649,bounded_fun,[{type,2649,'fun',[{type,2649,product,[{atom,2649,system_logger},{var,2649,'Logger'}]},{var,2649,'PrevLogger'}]},[{type,2650,constraint,[{atom,2650,is_subtype},[{var,2650,'Logger'},{type,2650,union,[{atom,2650,logger},{atom,2650,undefined},{type,2650,pid,[]}]}]]},{type,2651,constraint,[{atom,2651,is_subtype},[{var,2651,'PrevLogger'},{type,2651,union,[{atom,2651,logger},{atom,2651,undefined},{type,2651,pid,[]}]}]]}]]}]}}],since => <<79,84,80,32,50,49,46,51>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,110,111,100,101,32,116,114,97,99,101,32,99,111,110,116,114,111,108,32,119,111,114,100,32,116,111,32>>,{code,[],[<<84,67,87>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,111,32,98,101,32,97,110,32,117,110,115,105,103,110,101,100,32,105,110,116,101,103,101,114,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99,35,115,101,116,95,116,99,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<115,101,116,95,116,99,119>>]}]},<<32,105,110,32,115,101,99,116,105,111,110,32,34,77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103,34,32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,56,50,56>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2652,bounded_fun,[{type,2652,'fun',[{type,2652,product,[{atom,2652,trace_control_word},{var,2652,'TCW'}]},{var,2652,'OldTCW'}]},[{type,2653,constraint,[{atom,2653,is_subtype},[{var,2653,'TCW'},{type,2653,non_neg_integer,[]}]]},{type,2654,constraint,[{atom,2654,is_subtype},[{var,2654,'OldTCW'},{type,2654,non_neg_integer,[]}]]}]]}]}}]}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2606}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<70,105,110,97,108,105,122,101,115,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,105,109,101,32,111,102,102,115,101,116>>]},<<32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46,32,73,102,32,97,110,111,116,104,101,114,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101,32,105,115,32,117,115,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,115,116,97,116,101,32,105,115,32,108,101,102,116,32,117,110,99,104,97,110,103,101,100,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,115,116,97,116,101,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<112,114,101,108,105,109,105,110,97,114,121>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,102,105,110,97,108,105,122,97,116,105,111,110,32,119,97,115,32,112,101,114,102,111,114,109,101,100,32,97,110,100,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,110,111,119,32,102,105,110,97,108,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<102,105,110,97,108>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,119,97,115,32,97,108,114,101,97,100,121,32,105,110,32,116,104,101,32,102,105,110,97,108,32,115,116,97,116,101,46,32,84,104,105,115,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,116,105,109,101,95,111,102,102,115,101,116,44,32,102,105,110,97,108,105,122,101,41>>]},<<32,99,97,108,108,32,111,114,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<118,111,108,97,116,105,108,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,99,97,110,110,111,116,32,98,101,32,102,105,110,97,108,105,122,101,100,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,56,52,50>>,signature => [{attribute,2606,spec,{{erlang,system_flag,2},[{type,2655,bounded_fun,[{type,2655,'fun',[{type,2655,product,[{atom,2655,time_offset},{atom,2655,finalize}]},{var,2655,'OldState'}]},[{type,2656,constraint,[{atom,2656,is_subtype},[{var,2656,'OldState'},{type,2656,union,[{atom,2656,preliminary},{atom,2656,final},{atom,2656,volatile}]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,46,32,84,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,98,114,111,107,101,110,32,105,110,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,105,110,32,111,114,100,101,114,32,116,111,32,109,97,107,101,32,105,116,32,101,97,115,105,101,114,32,116,111,32,110,97,118,105,103,97,116,101,46>>]},{dl,[],[{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<77,101,109,111,114,121,32,65,108,108,111,99,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,111,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<67,80,85,32,84,111,112,111,108,111,103,121>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<80,114,111,99,101,115,115,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,115,105,122,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,101,97,112,95,115,105,122,101,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,101,97,112,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,115>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,105,109,105,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,76,105,109,105,116,115>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,116,111,109,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,116,111,109,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,116,115,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,116,115,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,108,105,109,105,116>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,84,105,109,101>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,110,100,95,116,105,109,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,114,116,95,116,105,109,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,119,97,114,112,95,109,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,119,97,114,112,95,109,111,100,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,99,104,101,100,117,108,101,114,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,105,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,109,112,95,115,117,112,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,109,112,95,115,117,112,112,111,114,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,104,114,101,97,100,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<68,105,115,116,114,105,98,117,116,105,111,110,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,114,101,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,114,101,97,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,99,116,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116,95,99,116,114,108>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,115,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,104,101,99,107,95,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,104,101,99,107,95,105,111>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,111,109,112,97,116,95,114,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,109,112,97,116,95,114,101,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,98,117,103,95,99,111,109,112,105,108,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,98,117,103,95,99,111,109,112,105,108,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,114,105,118,101,114,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,114,105,118,101,114,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,102,108,97,118,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,109,117,95,102,108,97,118,111,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,109,117,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,102,111>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,107,101,114,110,101,108,95,112,111,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<107,101,114,110,101,108,95,112,111,108,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,97,100,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,97,100,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,97,99,104,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,99,104,105,110,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,105,102,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,105,102,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,116,112,95,114,101,108,101,97,115,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,119,111,114,100,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<119,111,114,100,115,105,122,101>>]}]}]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,56,55,50>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2866,'fun',[{type,2866,product,[{atom,2866,version}]},{type,2866,string,[]}]}]}}]}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,111,114,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>}],[]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>}],[]},{code,[],[<<97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,97,114,101,97,115,46>>]},{p,[],[<<69,97,99,104,32,116,117,112,108,101,32,99,111,110,116,97,105,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,116,121,112,101,32,111,102,32,109,101,109,111,114,121,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,97,110,100,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,105,110,32,98,121,116,101,115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,87,104,101,110,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,108,108,111,99,97,116,101,100,32,97,110,100,32,117,115,101,100,32,109,101,109,111,114,121,32,105,115,32,112,114,101,115,101,110,116,44,32,97,108,115,111,32,97,32,116,104,105,114,100,32,101,108,101,109,101,110,116,32,105,115,32,112,114,101,115,101,110,116,44,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,117,115,101,100,32,109,101,109,111,114,121,32,105,110,32,98,121,116,101,115,46>>]},{p,[],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115,41>>]},<<32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,44,32,97,110,100,32,116,104,101,32,99,111,110,116,101,110,116,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,115,32,116,104,101,114,101,102,111,114,101,32,99,104,97,110,103,101,115,32,119,104,101,110,32,110,101,101,100,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,115,101,32,118,97,108,117,101,115,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,111,109,101,32,118,97,108,117,101,115,32,97,114,101,32,112,97,114,116,32,111,102,32,111,116,104,101,114,32,118,97,108,117,101,115,44,32,97,110,100,32,115,111,109,101,32,109,101,109,111,114,121,32,97,114,101,97,115,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48,44,49>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>}],[]},{code,[],[<<97,108,108,111,99,97,116,111,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,65,108,108,111,99,97,116,111,114,44,32,86,101,114,115,105,111,110,44,32,70,101,97,116,117,114,101,115,44,32,83,101,116,116,105,110,103,115>>]},<<44,32,119,104,101,114,101,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<65,108,108,111,99,97,116,111,114>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99,97,116,111,114>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,32,99,97,110,110,111,116,32,98,101,32,105,100,101,110,116,105,102,105,101,100,46,32>>,{code,[],[<<103,108,105,98,99>>]},<<32,99,97,110,32,98,101,32,105,100,101,110,116,105,102,105,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<86,101,114,115,105,111,110>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,40,98,117,116,32,110,111,116,32,97,32,115,116,114,105,110,103,41,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,101,97,116,117,114,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,97,116,111,109,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,97,108,108,111,99,97,116,105,111,110,32,102,101,97,116,117,114,101,115,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<83,101,116,116,105,110,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,115,117,98,115,121,115,116,101,109,115,44,32,116,104,101,105,114,32,99,111,110,102,105,103,117,114,97,98,108,101,32,112,97,114,97,109,101,116,101,114,115,44,32,97,110,100,32,117,115,101,100,32,118,97,108,117,101,115,46,32,83,101,116,116,105,110,103,115,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,100,105,102,102,101,114,101,110,116,32,99,111,109,98,105,110,97,116,105,111,110,115,32,111,102,32,112,108,97,116,102,111,114,109,115,44,32,97,108,108,111,99,97,116,111,114,115,44,32,97,110,100,32,97,108,108,111,99,97,116,105,111,110,32,102,101,97,116,117,114,101,115,46,32,77,101,109,111,114,121,32,115,105,122,101,115,32,97,114,101,32,103,105,118,101,110,32,105,110,32,98,121,116,101,115,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32,34,83,121,115,116,101,109,32,70,108,97,103,115,32,69,102,102,101,99,116,105,110,103,32,101,114,116,115,95,97,108,108,111,99,34,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,102,108,97,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,117,112,108,101>>}],[]},{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,108,108,111,99,97,116,111,114,46,32,65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,49,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,105,110,115,116,97,110,99,101,44,32,73,110,115,116,97,110,99,101,78,111,44,32,73,110,115,116,97,110,99,101,73,110,102,111,125>>]},<<32,116,117,112,108,101,115,44,32,119,104,101,114,101,32>>,{code,[],[<<73,110,115,116,97,110,99,101,73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,115,112,101,99,105,102,105,99,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,97,108,108,111,99,97,116,111,114,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,99,111,103,110,105,122,101,100,32,97,108,108,111,99,97,116,111,114,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,100,105,115,97,98,108,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,73,116,32,119,97,115,32,105,110,105,116,105,97,108,108,121,32,105,110,116,101,110,100,101,100,32,97,115,32,97,32,116,111,111,108,32,119,104,101,110,32,100,101,118,101,108,111,112,105,110,103,32,110,101,119,32,97,108,108,111,99,97,116,111,114,115,44,32,98,117,116,32,97,115,32,105,116,32,99,97,110,32,98,101,32,111,102,32,105,110,116,101,114,101,115,116,32,102,111,114,32,111,116,104,101,114,115,32,105,116,32,104,97,115,32,98,101,101,110,32,98,114,105,101,102,108,121,32,100,111,99,117,109,101,110,116,101,100,46>>]},{p,[],[<<84,104,101,32,114,101,99,111,103,110,105,122,101,100,32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,108,105,115,116,101,100,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46,32,73,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,117,112,101,114,32,99,97,114,114,105,101,114,115,32,99,97,110,32,98,101,32,111,98,116,97,105,110,101,100,32,102,114,111,109,32,69,82,84,83,32,56,46,48,32,119,105,116,104,32>>,{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,101,114,116,115,95,109,109,97,112,125>>]},<<32,111,114,32,102,114,111,109,32,69,82,84,83,32,53,46,49,48,46,52,59,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32,119,105,116,104,32>>,{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,109,115,101,103,95,97,108,108,111,99,125>>]},<<32,97,108,115,111,32,105,110,99,108,117,100,101,115,32,97,110,32>>,{code,[],[<<123,101,114,116,115,95,109,109,97,112,44,32,95,125>>]},<<32,116,117,112,108,101,32,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,46>>]},{p,[],[<<65,102,116,101,114,32,114,101,97,100,105,110,103,32,116,104,101,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]},<<32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,109,111,114,101,32,111,114,32,108,101,115,115,32,115,112,101,97,107,115,32,102,111,114,32,105,116,115,101,108,102,44,32,98,117,116,32,105,116,32,99,97,110,32,98,101,32,119,111,114,116,104,32,101,120,112,108,97,105,110,105,110,103,32,115,111,109,101,32,116,104,105,110,103,115,46,32,67,97,108,108,32,99,111,117,110,116,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,119,111,32,118,97,108,117,101,115,44,32,116,104,101,32,102,105,114,115,116,32,118,97,108,117,101,32,105,115,32,103,105,103,97,32,99,97,108,108,115,44,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,118,97,108,117,101,32,105,115,32,99,97,108,108,115,46,32>>,{code,[],[<<109,98,99,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,98,99,115>>]},<<32,100,101,110,111,116,101,32,109,117,108,116,105,45,98,108,111,99,107,32,99,97,114,114,105,101,114,115,44,32,97,110,100,32,115,105,110,103,108,101,45,98,108,111,99,107,32,99,97,114,114,105,101,114,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,83,105,122,101,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,105,110,32,98,121,116,101,115,46,32,87,104,101,110,32,97,32,115,105,122,101,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,101,100,44,32,105,116,32,105,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,115,111,109,101,116,104,105,110,103,46,32,83,105,122,101,115,32,97,110,100,32,97,109,111,117,110,116,115,32,97,114,101,32,111,102,116,101,110,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,114,101,101,32,118,97,108,117,101,115,58>>]},{ul,[],[{li,[],[<<84,104,101,32,102,105,114,115,116,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,118,97,108,117,101,46>>]},{li,[],[<<84,104,101,32,115,101,99,111,110,100,32,105,115,32,116,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125,41>>]},<<46>>]},{li,[],[<<84,104,101,32,116,104,105,114,100,32,105,115,32,116,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,115,105,110,99,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,115,116,97,114,116,101,100,46>>]}]},{p,[],[<<73,102,32,111,110,108,121,32,111,110,101,32,118,97,108,117,101,32,105,115,32,112,114,101,115,101,110,116,44,32,105,116,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,118,97,108,117,101,46,32>>,{code,[],[<<102,105,120,95,97,108,108,111,99>>]},<<32,109,101,109,111,114,121,32,98,108,111,99,107,32,116,121,112,101,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,119,111,32,118,97,108,117,101,115,46,32,84,104,101,32,102,105,114,115,116,32,118,97,108,117,101,32,105,115,32,116,104,101,32,109,101,109,111,114,121,32,112,111,111,108,32,115,105,122,101,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,118,97,108,117,101,32,105,115,32,116,104,101,32,117,115,101,100,32,109,101,109,111,114,121,32,115,105,122,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>}],[]},{code,[],[<<97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,97,108,108,111,99,97,116,111,114,115,32,117,115,105,110,103,32,116,104,101,32,69,82,84,83,32,105,110,116,101,114,110,97,108,32>>,{code,[],[<<97,108,108,111,99,95,117,116,105,108>>]},<<32,102,114,97,109,101,119,111,114,107,32,97,115,32,97,116,111,109,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,97,108,108,111,99,95,117,116,105,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<84,104,101,32,97,108,108,111,99,95,117,116,105,108,32,102,114,97,109,101,119,111,114,107>>]},<<32,105,110,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>}],[]},{code,[],[<<123,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115,44,32,65,108,108,111,99,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,115,105,122,101,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,108,108,111,99,97,116,111,114,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125,41>>]}]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,48,48,53>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2767,'fun',[{type,2767,product,[{atom,2767,allocated_areas}]},{type,2767,list,[{type,2767,tuple,any}]}]},{type,2768,bounded_fun,[{type,2768,'fun',[{type,2768,product,[{atom,2768,allocator}]},{type,2769,tuple,[{var,2769,'Allocator'},{var,2769,'Version'},{var,2769,'Features'},{var,2769,'Settings'}]}]},[{type,2770,constraint,[{atom,2770,is_subtype},[{var,2770,'Allocator'},{type,2770,union,[{atom,2770,undefined},{atom,2770,glibc}]}]]},{type,2771,constraint,[{atom,2771,is_subtype},[{var,2771,'Version'},{type,2771,list,[{type,2771,non_neg_integer,[]}]}]]},{type,2772,constraint,[{atom,2772,is_subtype},[{var,2772,'Features'},{type,2772,list,[{type,2772,atom,[]}]}]]},{type,2773,constraint,[{atom,2773,is_subtype},[{var,2773,'Settings'},{type,2773,list,[{type,2773,tuple,[{ann_type,2773,[{var,2773,'Subsystem'},{type,2773,atom,[]}]},{type,2774,list,[{type,2774,tuple,[{ann_type,2774,[{var,2774,'Parameter'},{type,2774,atom,[]}]},{ann_type,2775,[{var,2775,'Value'},{type,2775,term,[]}]}]}]}]}]}]]}]]},{type,2776,bounded_fun,[{type,2776,'fun',[{type,2776,product,[{type,2776,tuple,[{atom,2776,allocator},{var,2776,'Alloc'}]}]},{type,2776,list,[{var,2776,'_'}]}]},[{type,2777,constraint,[{atom,2777,is_subtype},[{var,2777,'Alloc'},{type,2777,atom,[]}]]}]]},{type,2778,bounded_fun,[{type,2778,'fun',[{type,2778,product,[{atom,2778,alloc_util_allocators}]},{type,2778,list,[{var,2778,'Alloc'}]}]},[{type,2779,constraint,[{atom,2779,is_subtype},[{var,2779,'Alloc'},{type,2779,atom,[]}]]}]]},{type,2780,bounded_fun,[{type,2780,'fun',[{type,2780,product,[{type,2780,tuple,[{atom,2780,allocator_sizes},{var,2780,'Alloc'}]}]},{type,2780,list,[{var,2780,'_'}]}]},[{type,2781,constraint,[{atom,2781,is_subtype},[{var,2781,'Alloc'},{type,2781,atom,[]}]]}]]}]}}]}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,108,108,32>>,{code,[],[<<76,101,118,101,108,69,110,116,114,121>>]},<<115,32,111,102,32,97,32,108,105,115,116,32,109,117,115,116,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<76,101,118,101,108,84,97,103>>]},<<44,32,101,120,99,101,112,116,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,119,104,101,114,101,32,98,111,116,104,32>>,{code,[],[<<110,111,100,101>>]},<<32,97,110,100,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},{code,[],[<<76,101,118,101,108,84,97,103>>]},<<115,32,99,97,110,32,99,111,101,120,105,115,116,46>>]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>}],[]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<84,104,101,32>>,{code,[],[<<105,110,102,111,95,108,105,115,116,40,41>>]},<<32,99,97,110,32,98,101,32,101,120,116,101,110,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>}],[]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[{code,[],[<<123,76,101,118,101,108,84,97,103,44,32,83,117,98,76,101,118,101,108,125,32,61,61,32,123,76,101,118,101,108,84,97,103,44,32,91,93,44,32,83,117,98,76,101,118,101,108,125>>]}]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>}],[]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<77,111,114,101,32>>,{code,[],[<<76,101,118,101,108,84,97,103>>]},<<115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{li,[{name,<<115,117,98,95,108,101,118,101,108>>}],[]}]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,98,105,110,100,105,110,103,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,117,115,101,100,32,105,115,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,102,105,110,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<44,32,105,102,32,115,117,99,104,32,101,120,105,115,116,115,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<44,32,105,102,32,115,117,99,104,32,101,120,105,115,116,115,46,32,73,102,32,110,111,32,67,80,85,32,116,111,112,111,108,111,103,121,32,101,120,105,115,116,115,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<110,111,100,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,78,111,110,45,85,110,105,102,111,114,109,32,77,101,109,111,114,121,32,65,99,99,101,115,115,32,40,78,85,77,65,41,32,110,111,100,101,115,46,32>>,{code,[],[<<116,104,114,101,97,100>>]},<<32,114,101,102,101,114,115,32,116,111,32,104,97,114,100,119,97,114,101,32,116,104,114,101,97,100,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,73,110,116,101,108,32,104,121,112,101,114,45,116,104,114,101,97,100,115,41,46>>]},{p,[],[<<65,32,108,101,118,101,108,32,105,110,32,116,101,114,109,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,99,97,110,32,98,101,32,111,109,105,116,116,101,100,32,105,102,32,111,110,108,121,32,111,110,101,32,101,110,116,114,121,32,101,120,105,115,116,115,32,97,110,100,32>>,{code,[],[<<73,110,102,111,76,105,115,116>>]},<<32,105,115,32,101,109,112,116,121,46>>]},{p,[],[{code,[],[<<116,104,114,101,97,100>>]},<<32,99,97,110,32,111,110,108,121,32,98,101,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<99,111,114,101>>]},<<46,32>>,{code,[],[<<99,111,114,101>>]},<<32,99,97,110,32,98,101,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<32,111,114,32>>,{code,[],[<<110,111,100,101>>]},<<46,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<32,99,97,110,32,98,101,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,111,114,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<110,111,100,101>>]},<<46,32>>,{code,[],[<<110,111,100,101>>]},<<32,99,97,110,32,98,101,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,111,114,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<46,32,84,104,97,116,32,105,115,44,32,78,85,77,65,32,110,111,100,101,115,32,99,97,110,32,98,101,32,112,114,111,99,101,115,115,111,114,32,105,110,116,101,114,110,97,108,32,111,114,32,112,114,111,99,101,115,115,111,114,32,101,120,116,101,114,110,97,108,46,32,65,32,67,80,85,32,116,111,112,111,108,111,103,121,32,99,97,110,32,99,111,110,115,105,115,116,32,111,102,32,97,32,109,105,120,32,111,102,32,112,114,111,99,101,115,115,111,114,32,105,110,116,101,114,110,97,108,32,97,110,100,32,101,120,116,101,114,110,97,108,32,78,85,77,65,32,110,111,100,101,115,44,32,97,115,32,108,111,110,103,32,97,115,32,101,97,99,104,32,108,111,103,105,99,97,108,32,67,80,85,32,98,101,108,111,110,103,115,32,116,111,32>>,{em,[],[<<111,110,101>>]},<<32,78,85,77,65,32,110,111,100,101,46,32,67,97,99,104,101,32,104,105,101,114,97,114,99,104,121,32,105,115,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,116,121,112,101,44,32,98,117,116,32,119,105,108,108,32,98,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,79,116,104,101,114,32,116,104,105,110,103,115,32,99,97,110,32,97,108,115,111,32,109,97,107,101,32,105,116,32,105,110,116,111,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,83,111,44,32,101,120,112,101,99,116,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,116,121,112,101,32,116,111,32,99,104,97,110,103,101,46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,100,101,102,105,110,101,100,125>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,102,105,110,101,100>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,100,101,116,101,99,116,101,100,125>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121,121>>]},<<46,32,84,104,101,32,101,109,117,108,97,116,111,114,32,100,101,116,101,99,116,115,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,110,32,115,111,109,101,32,110,101,119,101,114,32,76,105,110,117,120,44,32,83,111,108,97,114,105,115,44,32,70,114,101,101,66,83,68,44,32,97,110,100,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,115,46,32,79,110,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,32,119,105,116,104,32,109,111,114,101,32,116,104,97,110,32,51,50,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,110,111,116,32,100,101,116,101,99,116,101,100,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,117,115,101,100,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,99,111,110,102,105,103,117,114,101,100,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,116,104,101,32,99,111,110,102,105,103,117,114,101,100,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,116,104,101,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,105,115,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,32,111,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,99,111,110,102,105,103,117,114,101,100>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,113,117,111,116,97>>}],[]},{code,[],[<<99,112,117,95,113,117,111,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,67,80,85,32,113,117,111,116,97,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,108,105,109,105,116,101,100,32,98,121,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,115,97,121,105,110,103,32,104,111,119,32,109,97,110,121,32,112,114,111,99,101,115,115,111,114,115,39,32,119,111,114,116,104,32,111,102,32,114,117,110,116,105,109,101,32,119,101,32,103,101,116,32,40,98,101,116,119,101,101,110,32,49,32,97,110,100,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,41,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,97,32,113,117,111,116,97,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>}],[]},{code,[],[<<117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,114,101,114,101,97,100,115,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,117,112,100,97,116,101,115,32,105,116,115,32,105,110,116,101,114,110,97,108,108,121,32,115,116,111,114,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<32,97,110,100,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,102,105,103,117,114,101,100>>]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,110,108,105,110,101>>]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,118,97,105,108,97,98,108,101>>]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,113,117,111,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,112,117,32,113,117,111,116,97>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,104,97,115,32,99,104,97,110,103,101,100,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,105,116,32,119,97,115,32,114,101,97,100,44,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,104,97,110,103,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,99,104,97,110,103,101,100>>]},<<46,32,73,102,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,104,97,115,32,99,104,97,110,103,101,100,44,32,121,111,117,32,112,114,111,98,97,98,108,121,32,119,97,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,100,106,117,115,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101>>]},<<46,32,89,111,117,32,116,121,112,105,99,97,108,108,121,32,119,97,110,116,32,116,111,32,104,97,118,101,32,97,115,32,109,97,110,121,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,97,118,97,105,108,97,98,108,101>>]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,49,53,52>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2789,bounded_fun,[{type,2789,'fun',[{type,2789,product,[{atom,2789,cpu_topology}]},{var,2789,'CpuTopology'}]},[{type,2790,constraint,[{atom,2790,is_subtype},[{var,2790,'CpuTopology'},{user_type,2790,cpu_topology,[]}]]}]]},{type,2791,bounded_fun,[{type,2791,'fun',[{type,2791,product,[{type,2791,tuple,[{atom,2791,cpu_topology},{type,2791,union,[{atom,2791,defined},{atom,2791,detected},{atom,2791,used}]}]}]},{var,2791,'CpuTopology'}]},[{type,2792,constraint,[{atom,2792,is_subtype},[{var,2792,'CpuTopology'},{user_type,2792,cpu_topology,[]}]]}]]},{type,2819,'fun',[{type,2819,product,[{type,2819,union,[{atom,2819,logical_processors},{atom,2820,logical_processors_available},{atom,2821,logical_processors_online}]}]},{type,2821,union,[{atom,2821,unknown},{type,2821,pos_integer,[]}]}]},{type,2865,'fun',[{type,2865,product,[{atom,2865,update_cpu_info}]},{type,2865,union,[{atom,2865,changed},{atom,2865,unchanged}]}]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]}]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,101,102,97,117,108,116,32,112,114,111,99,101,115,115,32,104,101,97,112,32,115,101,116,116,105,110,103,115,58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>}],[]},{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,32,117,115,101,100,32,98,121,32,100,101,102,97,117,108,116,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]},<<32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>}],[]},{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,100,101,102,97,117,108,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,115,46,32,65,32,112,114,111,99,101,115,115,32,115,112,97,119,110,101,100,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,98,121,32,97,32>>,{code,[],[<<115,112,97,119,110>>]},<<32,111,114,32>>,{code,[],[<<115,112,97,119,110,95,108,105,110,107>>]},<<32,117,115,101,115,32,116,104,101,115,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,115,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,101,116,116,105,110,103,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,47,50>>]}]},<<46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,99,97,110,32,115,112,97,119,110,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,117,115,101,32,116,104,101,32,100,101,102,97,117,108,116,32,115,101,116,116,105,110,103,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,115,105,122,101,115>>}],[]},{code,[],[<<104,101,97,112,95,115,105,122,101,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,118,97,108,105,100,32,104,101,97,112,32,115,105,122,101,115,32,105,110,32,119,111,114,100,115,46,32,65,108,108,32,69,114,108,97,110,103,32,104,101,97,112,115,32,97,114,101,32,115,105,122,101,100,32,102,114,111,109,32,115,105,122,101,115,32,105,110,32,116,104,105,115,32,108,105,115,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,116,121,112,101>>}],[]},{code,[],[<<104,101,97,112,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,104,101,97,112,32,116,121,112,101,32,117,115,101,100,32,98,121,32,116,104,101,32,99,117,114,114,101,110,116,32,101,109,117,108,97,116,111,114,46,32,79,110,101,32,104,101,97,112,32,116,121,112,101,32,101,120,105,115,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<112,114,105,118,97,116,101>>]}]},{dd,[],[<<69,97,99,104,32,112,114,111,99,101,115,115,32,104,97,115,32,97,32,104,101,97,112,32,114,101,115,101,114,118,101,100,32,102,111,114,32,105,116,115,32,117,115,101,32,97,110,100,32,110,111,32,114,101,102,101,114,101,110,99,101,115,32,98,101,116,119,101,101,110,32,104,101,97,112,115,32,111,102,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,97,108,108,111,119,101,100,46,32,77,101,115,115,97,103,101,115,32,112,97,115,115,101,100,32,98,101,116,119,101,101,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,99,111,112,105,101,100,32,98,101,116,119,101,101,110,32,104,101,97,112,115,46>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,97,120,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,115,101,116,116,105,110,103,115,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46,32,84,104,105,115,32,115,101,116,116,105,110,103,32,99,97,110,32,98,101,32,115,101,116,32,117,115,105,110,103,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120,107>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120,101,108>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,73,116,32,99,97,110,32,97,108,115,111,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,114,117,110,116,105,109,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,119,104,105,99,104,32,105,115,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,84,104,105,115,32,100,101,102,97,117,108,116,32,105,115,32,115,101,116,32,98,121,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,115,101,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,77,105,110,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,105,110,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,77,105,110,66,105,110,86,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,105,110,66,105,110,86,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,115>>}],[]},{code,[],[<<112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,112,114,111,99,101,115,115,32,97,110,100,32,112,111,114,116,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,51,49,57>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2812,'fun',[{type,2812,product,[{atom,2812,fullsweep_after}]},{type,2812,tuple,[{atom,2812,fullsweep_after},{type,2812,non_neg_integer,[]}]}]},{type,2813,'fun',[{type,2813,product,[{atom,2813,garbage_collection}]},{type,2813,list,[{type,2813,tuple,[{type,2813,atom,[]},{type,2813,integer,[]}]}]}]},{type,2814,'fun',[{type,2814,product,[{atom,2814,heap_sizes}]},{type,2814,list,[{type,2814,non_neg_integer,[]}]}]},{type,2815,'fun',[{type,2815,product,[{atom,2815,heap_type}]},{atom,2815,private}]},{type,2823,'fun',[{type,2823,product,[{atom,2823,max_heap_size}]},{type,2823,tuple,[{atom,2823,max_heap_size},{ann_type,2823,[{var,2823,'MaxHeapSize'},{user_type,2823,max_heap_size,[]}]}]}]},{type,2824,'fun',[{type,2824,product,[{atom,2824,message_queue_data}]},{user_type,2824,message_queue_data,[]}]},{type,2825,'fun',[{type,2825,product,[{atom,2825,min_heap_size}]},{type,2825,tuple,[{atom,2825,min_heap_size},{ann_type,2825,[{var,2825,'MinHeapSize'},{type,2825,pos_integer,[]}]}]}]},{type,2826,'fun',[{type,2826,product,[{atom,2826,min_bin_vheap_size}]},{type,2826,tuple,[{atom,2826,min_bin_vheap_size},{ann_type,2827,[{var,2827,'MinBinVHeapSize'},{type,2827,pos_integer,[]}]}]}]},{type,2841,'fun',[{type,2841,product,[{atom,2841,procs}]},{type,2841,binary,[]}]}]}}],since => <<79,84,80,32,49,57,46,48,44,79,84,80,32,82,49,51,66,48,52>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,105,109,105,116,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,108,105,109,105,116,115,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,99,111,117,110,116>>}],[]},{code,[],[<<97,116,111,109,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,108,105,109,105,116>>}],[]},{code,[],[<<97,116,111,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,97,108,108,111,119,101,100,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,105,110,99,114,101,97,115,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,99,111,117,110,116>>}],[]},{code,[],[<<101,116,115,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,69,84,83,32,116,97,98,108,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,108,105,109,105,116>>}],[]},{code,[],[<<101,116,115,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,105,109,105,116,32,102,111,114,32,110,117,109,98,101,114,32,111,102,32,69,84,83,32,116,97,98,108,101,115,46,32,84,104,105,115,32,108,105,109,105,116,32,105,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,109,97,120,95,101,116,115,95,116,97,98,108,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,97,108,108,121,32,111,98,115,111,108,101,116,101>>]},<<32,97,110,100,32,110,117,109,98,101,114,32,111,102,32,116,97,98,108,101,115,32,97,114,101,32,111,110,108,121,32,108,105,109,105,116,101,100,32,98,121,32,97,118,97,105,108,97,98,108,101,32,109,101,109,111,114,121,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,99,111,117,110,116>>}],[]},{code,[],[<<112,111,114,116,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,111,114,116,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<108,101,110,103,116,104,40,101,114,108,97,110,103,58,112,111,114,116,115,40,41,41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,108,105,109,105,116>>}],[]},{code,[],[<<112,111,114,116,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,115,105,109,117,108,116,97,110,101,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,81>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,81>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,99,111,117,110,116>>}],[]},{code,[],[<<112,114,111,99,101,115,115,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<108,101,110,103,116,104,40,112,114,111,99,101,115,115,101,115,40,41,41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,108,105,109,105,116>>}],[]},{code,[],[<<112,114,111,99,101,115,115,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,115,105,109,117,108,116,97,110,101,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,80>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,80>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,52,51,56>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2782,'fun',[{type,2782,product,[{atom,2782,atom_count}]},{type,2782,pos_integer,[]}]},{type,2783,'fun',[{type,2783,product,[{atom,2783,atom_limit}]},{type,2783,pos_integer,[]}]},{type,2810,'fun',[{type,2810,product,[{atom,2810,ets_count}]},{type,2810,pos_integer,[]}]},{type,2811,'fun',[{type,2811,product,[{atom,2811,ets_limit}]},{type,2811,pos_integer,[]}]},{type,2837,'fun',[{type,2837,product,[{atom,2837,port_count}]},{type,2837,non_neg_integer,[]}]},{type,2838,'fun',[{type,2838,product,[{atom,2838,port_limit}]},{type,2838,pos_integer,[]}]},{type,2839,'fun',[{type,2839,product,[{atom,2839,process_count}]},{type,2839,pos_integer,[]}]},{type,2840,'fun',[{type,2840,product,[{atom,2840,process_limit}]},{type,2840,pos_integer,[]}]}]}}],since => <<79,84,80,32,50,48,46,48,44,79,84,80,32,50,49,46,49,44,79,84,80,32,82,49,54,66,44,79,84,80,32,82,49,54,66,48,51>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,116,105,109,101,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>}],[]},{code,[],[<<101,110,100,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,105,110,116,101,114,110,97,108,108,121,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,101,32,116,105,109,101,32,98,101,116,119,101,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,97,114,116,32,116,105,109,101>>]},<<32,97,110,100,32,116,104,101,32,101,110,100,32,116,105,109,101,32,105,115,32,97,116,32,108,101,97,115,116,32,97,32,113,117,97,114,116,101,114,32,111,102,32,97,32,109,105,108,108,101,110,110,105,117,109,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>}],[]},{code,[],[<<111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,111,117,114,99,101,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,110,111,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,115,32,97,118,97,105,108,97,98,108,101,46,32,84,104,101,32,108,105,115,116,32,99,111,110,116,97,105,110,115,32,116,119,111,45,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<115,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,115,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,108,105,115,116,44,32,98,117,116,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,102,117,110,99,116,105,111,110,44,32,70,117,110,99,116,105,111,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,117,115,101,100,46,32,84,104,105,115,32,116,117,112,108,101,32,97,108,119,97,121,115,32,101,120,105,115,116,115,32,105,102,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]},{dt,[],[{code,[],[<<123,99,108,111,99,107,95,105,100,44,32,67,108,111,99,107,73,100,125>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,116,117,112,108,101,32,111,110,108,121,32,101,120,105,115,116,115,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,100,105,102,102,101,114,101,110,116,32,99,108,111,99,107,115,46,32>>,{code,[],[<<67,108,111,99,107,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,99,108,111,99,107,32,105,100,101,110,116,105,102,105,101,114,32,117,115,101,100,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,115,111,108,117,116,105,111,110,44,32,79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110,125>>]}]},{dd,[],[{p,[],[<<72,105,103,104,101,115,116,32,112,111,115,115,105,98,108,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,111,102,32,99,117,114,114,101,110,116,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,115,111,117,114,99,101,32,97,115,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,110,111,32,114,101,115,111,108,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,102,114,111,109,32,116,104,101,32,79,83,44,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<115,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,97,99,116,117,97,108,32,114,101,115,111,108,117,116,105,111,110,32,99,97,110,32,98,101,32,108,111,119,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,100,111,101,115,32,110,111,116,32,115,97,121,32,97,110,121,116,104,105,110,103,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,114,32,119,104,101,116,104,101,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,97,108,105,103,110,115,32,119,105,116,104,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,46,32,89,111,117,32,100,111,44,32,104,111,119,101,118,101,114,44,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,112,114,101,99,105,115,105,111,110,32,105,115,32,110,111,116,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,120,116,101,110,100,101,100,44,32,69,120,116,101,110,100,101,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<69,120,116,101,110,100,101,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,32,104,97,115,32,98,101,101,110,32,101,120,116,101,110,100,101,100,59,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<69,120,116,101,110,100,101,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46,32,84,104,101,32,114,97,110,103,101,32,109,117,115,116,32,98,101,32,101,120,116,101,110,100,101,100,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,114,101,116,117,114,110,115,32,118,97,108,117,101,115,32,116,104,97,116,32,119,114,97,112,32,102,97,115,116,46,32,84,104,105,115,32,116,121,112,105,99,97,108,108,121,32,105,115,32,116,104,101,32,99,97,115,101,32,119,104,101,110,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,32,51,50,45,98,105,116,32,118,97,108,117,101,46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,44,32,80,97,114,97,108,108,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,32,102,114,111,109,32,109,117,108,116,105,112,108,101,32,116,104,114,101,97,100,115,46,32,73,102,32,105,116,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,44,32,98,101,99,97,117,115,101,32,99,97,108,108,115,32,109,117,115,116,32,98,101,32,115,101,114,105,97,108,105,122,101,100,44,32>>,{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,105,109,101,44,32,79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101>>]},<<32,101,113,117,97,108,115,32,99,117,114,114,101,110,116,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>}],[]},{code,[],[<<111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,111,117,114,99,101,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32,108,105,115,116,32,99,111,110,116,97,105,110,115,32,116,119,111,45,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<115,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,115,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,108,105,115,116,44,32,98,117,116,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,102,117,110,99,116,105,111,110,44,32,70,117,110,99,116,105,111,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,117,110,99,105,111,110,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,99,108,111,99,107,95,105,100,44,32,67,108,111,99,107,73,100,125>>]}]},{dd,[],[{p,[],[<<69,120,105,115,116,115,32,111,110,108,121,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,100,105,102,102,101,114,101,110,116,32,99,108,111,99,107,115,46,32>>,{code,[],[<<67,108,111,99,107,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,99,108,111,99,107,32,105,100,101,110,116,105,102,105,101,114,32,117,115,101,100,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,115,111,108,117,116,105,111,110,44,32,79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110,125>>]}]},{dd,[],[{p,[],[<<72,105,103,104,101,115,116,32,112,111,115,115,105,98,108,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,111,102,32,99,117,114,114,101,110,116,32,79,83,32,115,121,115,116,101,109,32,116,105,109,101,32,115,111,117,114,99,101,32,97,115,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,110,111,32,114,101,115,111,108,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,102,114,111,109,32,116,104,101,32,79,83,44,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<115,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,97,99,116,117,97,108,32,114,101,115,111,108,117,116,105,111,110,32,99,97,110,32,98,101,32,108,111,119,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,100,111,101,115,32,110,111,116,32,115,97,121,32,97,110,121,116,104,105,110,103,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,114,32,119,104,101,116,104,101,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,100,111,32,97,108,105,103,110,32,119,105,116,104,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,46,32,89,111,117,32,100,111,44,32,104,111,119,101,118,101,114,44,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,112,114,101,99,105,115,105,111,110,32,105,115,32,110,111,116,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,44,32,80,97,114,97,108,108,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,32,102,114,111,109,32,109,117,108,116,105,112,108,101,32,116,104,114,101,97,100,115,46,32,73,102,32,105,116,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,44,32,98,101,99,97,117,115,101,32,99,97,108,108,115,32,110,101,101,100,115,32,116,111,32,98,101,32,115,101,114,105,97,108,105,122,101,100,44,32>>,{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,105,109,101,44,32,79,115,83,121,115,116,101,109,84,105,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101>>]},<<32,101,113,117,97,108,115,32,99,117,114,114,101,110,116,32,79,83,32,115,121,115,116,101,109,32,116,105,109,101,32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>}],[]},{code,[],[<<115,116,97,114,116,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<32,97,116,32,116,104,101,32,116,105,109,101,32,119,104,101,110,32,99,117,114,114,101,110,116,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,115,116,97,114,116,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,101,110,100,95,116,105,109,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>}],[]},{code,[],[<<116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,111,111,108,101,97,110,32,118,97,108,117,101,32,105,110,100,105,99,97,116,105,110,103,32,119,104,101,116,104,101,114,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,67,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,99,111,114,114,101,99,116,105,111,110>>]},<<32,105,115,32,101,110,97,98,108,101,100,32,111,114,32,110,111,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>}],[]},{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,58>>]},{dl,[],[{dt,[],[{code,[],[<<112,114,101,108,105,109,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,112,114,101,108,105,109,105,110,97,114,121,44,32,97,110,100,32,119,105,108,108,32,98,101,32,99,104,97,110,103,101,100,32,97,110,100,32,102,105,110,97,108,105,122,101,100,32,108,97,116,101,114,46,32,84,104,101,32,112,114,101,108,105,109,105,110,97,114,121,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,117,115,101,100,32,100,117,114,105,110,103,32,116,104,101,32,112,114,101,108,105,109,105,110,97,114,121,32,112,104,97,115,101,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,105,110,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,102,105,110,97,108,46,32,84,104,105,115,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,104,97,118,101,32,98,101,101,110,32,102,105,110,97,108,105,122,101,100,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<118,111,108,97,116,105,108,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,118,111,108,97,116,105,108,101,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,32,99,104,97,110,103,101,32,97,116,32,97,110,121,32,116,105,109,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,119,97,114,112,95,109,111,100,101>>}],[]},{code,[],[<<116,105,109,101,95,119,97,114,112,95,109,111,100,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,118,97,108,117,101,32,105,100,101,110,116,105,102,121,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]},{dt,[],[{code,[],[<<115,105,110,103,108,101,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]},{dt,[],[{code,[],[<<109,117,108,116,105,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>}],[]},{code,[],[<<116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,119,104,101,116,104,101,114,32,97,32,112,114,101,32,69,82,84,83,32,55,46,48,32,98,97,99,107,119,97,114,100,115,32,99,111,109,112,97,116,105,98,108,101,32,99,111,109,112,101,110,115,97,116,105,111,110,32,102,111,114,32,115,117,100,100,101,110,32,99,104,97,110,103,101,115,32,111,102,32,115,121,115,116,101,109,32,116,105,109,101,32,105,115,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<32,111,114,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<46,32,83,117,99,104,32,99,111,109,112,101,110,115,97,116,105,111,110,32,105,115,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,111,102,102,115,101,116>>]},<<32,105,115,32>>,{code,[],[<<102,105,110,97,108>>]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,99,111,114,114,101,99,116,105,111,110>>]},<<32,105,115,32,101,110,97,98,108,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,49,56>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2809,'fun',[{type,2809,product,[{atom,2809,end_time}]},{type,2809,non_neg_integer,[]}]},{type,2834,'fun',[{type,2834,product,[{atom,2834,os_monotonic_time_source}]},{type,2834,list,[{type,2834,tuple,[{type,2834,atom,[]},{type,2834,term,[]}]}]}]},{type,2835,'fun',[{type,2835,product,[{atom,2835,os_system_time_source}]},{type,2835,list,[{type,2835,tuple,[{type,2835,atom,[]},{type,2835,term,[]}]}]}]},{type,2854,'fun',[{type,2854,product,[{atom,2854,start_time}]},{type,2854,integer,[]}]},{type,2860,'fun',[{type,2860,product,[{atom,2860,time_correction}]},{type,2860,union,[{atom,2860,true},{atom,2860,false}]}]},{type,2861,'fun',[{type,2861,product,[{atom,2861,time_offset}]},{type,2861,union,[{atom,2861,preliminary},{atom,2861,final},{atom,2861,volatile}]}]},{type,2862,'fun',[{type,2862,product,[{atom,2862,time_warp_mode}]},{type,2862,union,[{atom,2862,no_time_warp},{atom,2862,single_time_warp},{atom,2862,multi_time_warp}]}]},{type,2863,'fun',[{type,2863,product,[{atom,2863,tolerant_timeofday}]},{type,2863,union,[{atom,2863,enabled},{atom,2863,disabled}]}]}]}}],since => <<79,84,80,32,49,55,46,49,44,79,84,80,32,49,56,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,99,104,101,100,117,108,101,114,115,44,32,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,68,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,101,120,101,99,117,116,101,32,67,80,85,45,98,111,117,110,100,32,110,97,116,105,118,101,32,102,117,110,99,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32,78,73,70,115,44,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,44,32,97,110,100,32,66,73,70,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,109,97,110,97,103,101,100,32,99,108,101,97,110,108,121,32,98,121,32,116,104,101,32,110,111,114,109,97,108,32,101,109,117,108,97,116,111,114,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,97,102,116,101,114,32,116,104,97,116,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,99,112,117>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,80,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,80,99,112,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,115,97,116,105,115,102,105,101,115,32>>,{code,[],[<<49,32,60,61,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,78>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,99,112,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,68,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,101,120,101,99,117,116,101,32,73,47,79,45,98,111,117,110,100,32,110,97,116,105,118,101,32,102,117,110,99,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32,78,73,70,115,32,97,110,100,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,44,32,119,104,105,99,104,32,99,97,110,110,111,116,32,98,101,32,109,97,110,97,103,101,100,32,99,108,101,97,110,108,121,32,98,121,32,116,104,101,32,110,111,114,109,97,108,32,101,109,117,108,97,116,111,114,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,105,111>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>}],[]},{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<100,105,115,97,98,108,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,115,116,97,114,116,101,100,32,119,105,116,104,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<98,108,111,99,107,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,98,117,116,32,97,108,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,101,120,99,101,112,116,32,111,110,101,32,97,114,101,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,115,99,104,101,100,117,108,101,115,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,115,32,69,114,108,97,110,103,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<98,108,111,99,107,101,100,95,110,111,114,109,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,98,117,116,32,97,108,108,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,101,120,99,101,112,116,32,111,110,101,32,97,114,101,32,98,108,111,99,107,101,100,46,32,78,111,116,105,99,101,32,116,104,97,116,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,110,111,116,32,98,108,111,99,107,101,100,44,32,97,110,100,32,99,97,110,32,115,99,104,101,100,117,108,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,32,110,97,116,105,118,101,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<101,110,97,98,108,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,97,110,100,32,110,111,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,97,114,101,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,97,108,108,32,97,118,97,105,108,97,98,108,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,115,99,104,101,100,117,108,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,32,69,114,108,97,110,103,32,99,111,100,101,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>}],[]},{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<115,32,119,104,101,110,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32>>,{code,[],[<<80,105,100>>]},<<115,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,98,108,111,99,107,105,110,103,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46,32,65,32>>,{code,[],[<<80,105,100>>]},<<32,111,99,99,117,114,115,32,111,110,108,121,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,101,118,101,110,32,105,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>}],[]},{code,[],[<<110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<115,32,119,104,101,110,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,32,40,116,104,97,116,32,105,115,44,32,97,108,108,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,41,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32>>,{code,[],[<<80,105,100>>]},<<115,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,98,108,111,99,107,105,110,103,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46,32,65,32>>,{code,[],[<<80,105,100>>]},<<32,111,99,99,117,114,115,32,111,110,108,121,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,101,118,101,110,32,105,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,104,111,119,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,113,117,101,115,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,98,101,32,98,111,117,110,100,32,111,114,32,110,111,116,32,98,111,117,110,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,108,116,104,111,117,103,104,32,97,32,117,115,101,114,32,104,97,115,32,114,101,113,117,101,115,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,98,101,32,98,111,117,110,100,44,32,116,104,101,121,32,99,97,110,32,115,105,108,101,110,116,108,121,32,104,97,118,101,32,102,97,105,108,101,100,32,116,111,32,98,105,110,100,46,32,84,111,32,105,110,115,112,101,99,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,105,110,103,115,44,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,105,110,103,115,46>>]},{p,[],[<<65,32,116,117,112,108,101,32,111,102,32,97,32,115,105,122,101,32,101,113,117,97,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,116,117,112,108,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,105,110,116,101,103,101,114,115,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,98,111,117,110,100>>]},<<46,32,76,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,115,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,105,110,116,101,103,101,114,115,46,32,84,104,101,32>>,{code,[],[<<78>>]},<<116,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,116,117,112,108,101,32,101,113,117,97,108,115,32,116,104,101,32,99,117,114,114,101,110,116,32,98,105,110,100,105,110,103,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,119,105,116,104,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<78>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,44,32>>,{code,[],[<<101,108,101,109,101,110,116,40,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,105,100,41,44,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41,41>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,110,108,121,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,98,111,117,110,100,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,105,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,73,68,32,40>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<41,32,111,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,44,32,119,104,101,114,101,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,73,100,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,111,110,108,105,110,101,32,115,99,104,101,100,117,108,101,115,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,69,114,108,97,110,103,32,112,111,114,116,115,44,32,97,110,100,32,101,120,101,99,117,116,101,32,69,114,108,97,110,103,32,99,111,100,101,32,97,110,100,32,69,114,108,97,110,103,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,108,97,116,101,114,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,105,100,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,115,97,116,105,115,102,121,32,116,104,101,32,114,101,108,97,116,105,111,110,115,104,105,112,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,73,100,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,109,112,95,115,117,112,112,111,114,116>>}],[]},{code,[],[<<115,109,112,95,115,117,112,112,111,114,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,115>>}],[]},{code,[],[<<116,104,114,101,97,100,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>}],[]},{code,[],[<<116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,115,121,110,99,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,97,115,121,110,99,32,116,104,114,101,97,100,32,112,111,111,108,32,117,115,101,100,32,102,111,114,32,97,115,121,110,99,104,114,111,110,111,117,115,32,100,114,105,118,101,114,32,99,97,108,108,115,32,40>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,100,114,105,118,101,114,95,97,115,121,110,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<32>>,{code,[],[<<101,114,108,95,100,114,105,118,101,114,58,100,114,105,118,101,114,95,97,115,121,110,99,40,41>>]}]},<<41,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,55,52,54>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2796,'fun',[{type,2796,product,[{atom,2796,dirty_cpu_schedulers}]},{type,2796,non_neg_integer,[]}]},{type,2797,'fun',[{type,2797,product,[{atom,2797,dirty_cpu_schedulers_online}]},{type,2797,non_neg_integer,[]}]},{type,2798,'fun',[{type,2798,product,[{atom,2798,dirty_io_schedulers}]},{type,2798,non_neg_integer,[]}]},{type,2829,'fun',[{type,2829,product,[{atom,2829,multi_scheduling}]},{type,2829,union,[{atom,2829,disabled},{atom,2829,blocked},{atom,2829,blocked_normal},{atom,2829,enabled}]}]},{type,2830,'fun',[{type,2830,product,[{atom,2830,multi_scheduling_blockers}]},{type,2830,list,[{ann_type,2830,[{var,2830,'Pid'},{type,2830,pid,[]}]}]}]},{type,2832,'fun',[{type,2832,product,[{atom,2832,normal_multi_scheduling_blockers}]},{type,2832,list,[{ann_type,2832,[{var,2832,'Pid'},{type,2832,pid,[]}]}]}]},{type,2842,'fun',[{type,2842,product,[{atom,2842,scheduler_bind_type}]},{type,2842,union,[{atom,2842,spread},{atom,2843,processor_spread},{atom,2844,thread_spread},{atom,2845,thread_no_node_processor_spread},{atom,2846,no_node_processor_spread},{atom,2847,no_node_thread_spread},{atom,2848,no_spread},{atom,2849,unbound}]}]},{type,2850,'fun',[{type,2850,product,[{atom,2850,scheduler_bindings}]},{type,2850,tuple,any}]},{type,2851,'fun',[{type,2851,product,[{atom,2851,scheduler_id}]},{ann_type,2851,[{var,2851,'SchedulerId'},{type,2851,pos_integer,[]}]}]},{type,2852,'fun',[{type,2852,product,[{type,2852,union,[{atom,2852,schedulers},{atom,2852,schedulers_online}]}]},{type,2852,pos_integer,[]}]},{type,2853,'fun',[{type,2853,product,[{atom,2853,smp_support}]},{type,2853,boolean,[]}]},{type,2858,'fun',[{type,2858,product,[{atom,2858,threads}]},{type,2858,boolean,[]}]},{type,2859,'fun',[{type,2859,product,[{atom,2859,thread_pool_size}]},{type,2859,non_neg_integer,[]}]}]}}],since => <<79,84,80,32,49,55,46,48,44,79,84,80,32,49,57,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,114,101,97,116,105,111,110>>}],[]},{code,[],[<<99,114,101,97,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,114,101,97,116,105,111,110,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,101,32,99,114,101,97,116,105,111,110,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,97,32,110,111,100,101,32,105,115,32,114,101,115,116,97,114,116,101,100,46,32,84,104,101,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,111,100,101,32,105,115,32,115,116,111,114,101,100,32,105,110,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,46,32,84,104,105,115,32,109,97,107,101,115,32,105,116,32,40,116,111,32,115,111,109,101,32,101,120,116,101,110,116,41,32,112,111,115,115,105,98,108,101,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,98,101,116,119,101,101,110,32,105,100,101,110,116,105,102,105,101,114,115,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,105,110,99,97,114,110,97,116,105,111,110,115,32,111,102,32,97,32,110,111,100,101,46,32,84,104,101,32,118,97,108,105,100,32,99,114,101,97,116,105,111,110,115,32,97,114,101,32,105,110,116,101,103,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,49,46,46,51,44,32,98,117,116,32,116,104,105,115,32,119,105,108,108,32,112,114,111,98,97,98,108,121,32,99,104,97,110,103,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,73,102,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<48>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>}],[]},{code,[],[<<100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,116,105,109,101,32,105,110,32,115,101,99,111,110,100,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,97,110,32,101,110,116,114,121,32,105,110,32,97,32,110,111,100,101,32,116,97,98,108,101,32,105,115,32,100,101,108,97,121,101,100,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,115,101,116,32,111,110,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,100,110,116,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,122,100,110,116,103,99>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>}],[]},{code,[],[<<100,105,115,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,100,105,115,116,114,105,98,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>}],[]},{code,[],[<<100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,98,117,102,102,101,114,32,98,117,115,121,32,108,105,109,105,116,32,105,110,32,98,121,116,101,115,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,100,98,98,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,122,100,98,98,108>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,99,116,114,108>>}],[]},{code,[],[<<100,105,115,116,95,99,116,114,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32>>,{code,[],[<<123,78,111,100,101,44,32,67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121,125>>]},<<44,32,111,110,101,32,101,110,116,114,121,32,102,111,114,32,101,97,99,104,32,99,111,110,110,101,99,116,101,100,32,114,101,109,111,116,101,32,110,111,100,101,46,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,97,110,100,32>>,{code,[],[<<67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121>>]},<<32,105,115,32,116,104,101,32,112,111,114,116,32,111,114,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,114,101,115,112,111,110,115,105,98,108,101,32,102,111,114,32,116,104,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,116,111,32,116,104,97,116,32,110,111,100,101,46,32,77,111,114,101,32,115,112,101,99,105,102,105,99,97,108,108,121,44,32>>,{code,[],[<<67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121>>]},<<32,102,111,114,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,104,114,111,117,103,104,32,84,67,80,47,73,80,32,40,116,104,101,32,110,111,114,109,97,108,32,99,97,115,101,41,32,105,115,32,116,104,101,32,115,111,99,107,101,116,32,117,115,101,100,32,105,110,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,99,32,110,111,100,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,48,52,54>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2793,'fun',[{type,2793,product,[{atom,2793,creation}]},{type,2793,integer,[]}]},{type,2795,'fun',[{type,2795,product,[{atom,2795,delayed_node_table_gc}]},{type,2795,union,[{atom,2795,infinity},{type,2795,non_neg_integer,[]}]}]},{type,2799,'fun',[{type,2799,product,[{atom,2799,dist}]},{type,2799,binary,[]}]},{type,2800,'fun',[{type,2800,product,[{atom,2800,dist_buf_busy_limit}]},{type,2800,non_neg_integer,[]}]},{type,2801,'fun',[{type,2801,product,[{atom,2801,dist_ctrl}]},{type,2801,tuple,[{ann_type,2801,[{var,2801,'Node'},{type,2801,node,[]}]},{ann_type,2802,[{var,2802,'ControllingEntity'},{type,2802,union,[{type,2802,port,[]},{type,2802,pid,[]}]}]}]}]}]}}],since => <<79,84,80,32,49,56,46,48,44,79,84,80,32,82,49,52,66,48,49>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2766}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,115,99,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,98,117,105,108,100,95,116,121,112,101>>}],[]},{code,[],[<<98,117,105,108,100,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<68,101,112,114,101,99,97,116,101,100,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,109,117,95,116,121,112,101>>]},<<32,105,110,115,116,101,97,100>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>}],[]},{code,[],[<<99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,119,111,45,116,117,112,108,101,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,67,32,99,111,109,112,105,108,101,114,32,117,115,101,100,32,119,104,101,110,32,99,111,109,112,105,108,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,117,110,107,110,111,119,110,46,32,84,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,101,114,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,117,110,107,110,111,119,110,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,104,101,99,107,95,105,111>>}],[]},{code,[],[<<99,104,101,99,107,95,105,111>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,101,109,117,108,97,116,111,114,115,32,105,110,116,101,114,110,97,108,32,73,47,79,32,99,104,101,99,107,105,110,103,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,118,97,114,121,32,98,101,116,119,101,101,110,32,112,108,97,116,102,111,114,109,115,32,97,110,100,32,111,118,101,114,32,116,105,109,101,46,32,73,116,32,105,115,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,111,109,112,97,116,95,114,101,108>>}],[]},{code,[],[<<99,111,109,112,97,116,95,114,101,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,109,111,100,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,101,32,105,110,116,101,103,101,114,32,114,101,116,117,114,110,101,100,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,69,114,108,97,110,103,47,79,84,80,32,114,101,108,101,97,115,101,32,116,104,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,115,101,116,32,116,111,32,98,101,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,46,32,84,104,101,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,109,111,100,101,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,99,111,109,112,97,116,95,114,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,82>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,101,98,117,103,95,99,111,109,112,105,108,101,100>>}],[]},{code,[],[<<100,101,98,117,103,95,99,111,109,112,105,108,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,101,98,117,103,45,99,111,109,112,105,108,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,114,105,118,101,114,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<100,114,105,118,101,114,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,100,114,105,118,101,114,32,118,101,114,115,105,111,110,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,73,116,32,104,97,115,32,116,104,101,32,102,111,114,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,118,101,114,115,105,111,110,95,109,97,110,97,103,101,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<34,60,109,97,106,111,114,32,118,101,114,62,46,60,109,105,110,111,114,32,118,101,114,62,34>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101>>}],[]},{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,100,121,110,97,109,105,99,32,116,114,97,99,101,32,102,114,97,109,101,119,111,114,107,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,46,32,73,116,32,99,97,110,32,98,101,32>>,{code,[],[<<100,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<44,32,111,114,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,70,111,114,32,97,32,99,111,109,109,101,114,99,105,97,108,32,111,114,32,115,116,97,110,100,97,114,100,32,98,117,105,108,100,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,84,104,101,32,111,116,104,101,114,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,105,110,100,105,99,97,116,101,32,97,32,99,117,115,116,111,109,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<46,47,99,111,110,102,105,103,117,114,101,32,45,45,119,105,116,104,45,100,121,110,97,109,105,99,45,116,114,97,99,101,61,100,116,114,97,99,101>>]},<<41,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,121,110,97,109,105,99,32,116,114,97,99,105,110,103,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,117,110,116,105,109,101,95,116,111,111,108,115,58,100,121,110,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,116,114,97,99,101,40,51,41>>]}]},<<32,109,97,110,117,97,108,32,112,97,103,101,32,97,110,100,32,116,104,101,32>>,{code,[],[<<82,69,65,68,77,69,46,100,116,114,97,99,101>>]},<<47>>,{code,[],[<<82,69,65,68,77,69,46,115,121,115,116,101,109,116,97,112>>]},<<32,102,105,108,101,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,115,111,117,114,99,101,32,99,111,100,101,32,116,111,112,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>}],[]},{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32>>,{code,[],[<<98,111,111,108,101,97,110,40,41>>]},<<32,105,110,100,105,99,97,116,105,110,103,32,105,102,32,100,121,110,97,109,105,99,32,116,114,97,99,101,32,112,114,111,98,101,115,32,40>>,{code,[],[<<100,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<41,32,97,114,101,32,98,117,105,108,116,32,105,110,116,111,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,84,104,105,115,32,99,97,110,32,111,110,108,121,32,98,101,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,119,97,115,32,98,117,105,108,116,32,102,111,114,32,100,121,110,97,109,105,99,32,116,114,97,99,105,110,103,32,40,116,104,97,116,32,105,115,44,32>>,{code,[],[<<115,121,115,116,101,109,95,105,110,102,111,40,100,121,110,97,109,105,99,95,116,114,97,99,101,41>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<100,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<41,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,102,108,97,118,111,114>>}],[]},{code,[],[<<101,109,117,95,102,108,97,118,111,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,102,108,97,118,111,114,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,105,115,32,119,105,108,108,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<101,109,117>>]},<<32,111,114,32>>,{code,[],[<<106,105,116>>]},<<46,32,80,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>}],[]},{code,[],[<<101,109,117,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,98,117,105,108,100,32,116,121,112,101,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,105,115,32,105,115,32,110,111,114,109,97,108,108,121,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,112,116>>]},<<32,102,111,114,32,111,112,116,105,109,105,122,101,100,46,32,79,116,104,101,114,32,112,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,97,114,101,32>>,{code,[],[<<100,101,98,117,103>>]},<<44,32>>,{code,[],[<<103,99,111,118>>]},<<44,32>>,{code,[],[<<118,97,108,103,114,105,110,100>>]},<<44,32>>,{code,[],[<<103,112,114,111,102>>]},<<44,32,97,110,100,32>>,{code,[],[<<108,99,110,116>>]},<<46,32,80,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,105,110,102,111>>}],[]},{code,[],[<<105,110,102,111>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,115,121,115,116,101,109,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,107,101,114,110,101,108,95,112,111,108,108>>}],[]},{code,[],[<<107,101,114,110,101,108,95,112,111,108,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,117,115,101,115,32,115,111,109,101,32,107,105,110,100,32,111,102,32,107,101,114,110,101,108,45,112,111,108,108,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,97,100,101,100>>}],[]},{code,[],[<<108,111,97,100,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,108,111,97,100,101,100,32,109,111,100,117,108,101,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,97,99,104,105,110,101>>}],[]},{code,[],[<<109,97,99,104,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,109,97,99,104,105,110,101,32,110,97,109,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>}],[]},{code,[],[<<109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,45,108,101,118,101,108,32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,102,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,32,105,115,32,101,110,97,98,108,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,84>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,84>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,110,105,102,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<110,105,102,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,78,73,70,32,105,110,116,101,114,102,97,99,101,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,73,116,32,105,115,32,111,110,32,116,104,101,32,102,111,114,109,32,34,60,109,97,106,111,114,32,118,101,114,62,46,60,109,105,110,111,114,32,118,101,114,62,34,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>}],[]},{code,[],[<<111,116,112,95,114,101,108,101,97,115,101>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,116,104,97,116,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,101,120,101,99,117,116,105,110,103,32,69,82,84,83,32,97,112,112,108,105,99,97,116,105,111,110,32,105,115,32,112,97,114,116,32,111,102,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,49,55,44,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,110,117,109,98,101,114,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,109,97,106,111,114,32,79,84,80,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,46,32,78,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,41>>]},<<32,97,114,103,117,109,101,110,116,32,103,105,118,101,115,32,116,104,101,32,101,120,97,99,116,32,79,84,80,32,118,101,114,115,105,111,110,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,101,120,97,99,116,32,79,84,80,32,118,101,114,115,105,111,110,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,32,105,115,32,100,105,102,102,105,99,117,108,116,32,116,111,32,100,101,116,101,114,109,105,110,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,101,114,115,105,111,110,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,115,121,115,116,101,109,95,112,114,105,110,99,105,112,108,101,115,58,118,101,114,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,121,115,116,101,109,32,112,114,105,110,99,105,112,108,101,115>>]},<<32,105,110,32,83,121,115,116,101,109,32,68,111,99,117,109,101,110,116,97,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>}],[]},{code,[],[<<112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,102,97,117,108,116,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,32,115,99,104,101,100,117,108,105,110,103,32,104,105,110,116,32,117,115,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,112,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,112,112>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>}],[]},{code,[],[<<115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,111,114,32,97,110,100,32,79,83,32,97,114,99,104,105,116,101,99,116,117,114,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,98,117,105,108,116,32,102,111,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,108,111,103,103,101,114>>}],[]},{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]},<<32,97,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,121,115,116,101,109,95,108,111,103,103,101,114,44,32,95,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<115,121,115,116,101,109,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,97,110,100,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,112,114,111,112,101,114,116,105,101,115,44,32,115,117,99,104,32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>}],[]},{code,[],[<<116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,110,111,100,101,32,116,114,97,99,101,32,99,111,110,116,114,111,108,32,119,111,114,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<103,101,116,95,116,99,119>>]},<<32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99,35,103,101,116,95,116,99,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,119,111,114,100,115,105,122,101>>}],[]},{code,[],[<<119,111,114,100,115,105,122,101>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,105,110,116,101,114,110,97,108,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,105,110,116,101,114,110,97,108,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,105,122,101,32,111,102,32,69,114,108,97,110,103,32,116,101,114,109,32,119,111,114,100,115,32,105,110,32,98,121,116,101,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,97,116,32,105,115,44,32,52,32,105,115,32,114,101,116,117,114,110,101,100,32,111,110,32,97,32,51,50,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,97,110,100,32,56,32,105,115,32,114,101,116,117,114,110,101,100,32,111,110,32,97,32,112,117,114,101,32,54,52,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,46,32,79,110,32,97,32,104,97,108,102,119,111,114,100,32,54,52,45,98,105,116,32,101,109,117,108,97,116,111,114,44,32,52,32,105,115,32,114,101,116,117,114,110,101,100,44,32,97,115,32,116,104,101,32,69,114,108,97,110,103,32,116,101,114,109,115,32,97,114,101,32,115,116,111,114,101,100,32,117,115,105,110,103,32,97,32,118,105,114,116,117,97,108,32,119,111,114,100,32,115,105,122,101,32,111,102,32,104,97,108,102,32,116,104,101,32,115,121,115,116,101,109,32,119,111,114,100,32,115,105,122,101,46>>]}]},{dt,[],[{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,101,120,116,101,114,110,97,108,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,114,117,101,32,119,111,114,100,32,115,105,122,101,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,115,105,122,101,32,111,102,32,97,32,112,111,105,110,116,101,114,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,105,110,32,98,121,116,101,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,79,110,32,97,32,112,117,114,101,32,51,50,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,52,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,110,32,98,111,116,104,32,97,32,104,97,108,102,32,119,111,114,100,32,97,110,100,32,111,110,32,97,32,112,117,114,101,32,54,52,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,56,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,49,49,55>>,signature => [{attribute,2766,spec,{{erlang,system_info,1},[{type,2786,'fun',[{type,2786,product,[{atom,2786,c_compiler_used}]},{type,2786,tuple,[{type,2786,atom,[]},{type,2786,term,[]}]}]},{type,2787,'fun',[{type,2787,product,[{atom,2787,check_io}]},{type,2787,list,[{var,2787,'_'}]}]},{type,2788,'fun',[{type,2788,product,[{atom,2788,compat_rel}]},{type,2788,integer,[]}]},{type,2794,'fun',[{type,2794,product,[{atom,2794,debug_compiled}]},{type,2794,boolean,[]}]},{type,2803,'fun',[{type,2803,product,[{atom,2803,driver_version}]},{type,2803,string,[]}]},{type,2804,'fun',[{type,2804,product,[{atom,2804,dynamic_trace}]},{type,2804,union,[{atom,2804,none},{atom,2804,dtrace},{atom,2804,systemtap}]}]},{type,2805,'fun',[{type,2805,product,[{atom,2805,dynamic_trace_probes}]},{type,2805,boolean,[]}]},{type,2807,'fun',[{type,2807,product,[{atom,2807,emu_flavor}]},{type,2807,union,[{atom,2807,emu},{atom,2807,jit}]}]},{type,2808,'fun',[{type,2808,product,[{atom,2808,emu_type}]},{type,2808,union,[{atom,2808,opt},{atom,2808,debug},{atom,2808,gcov},{atom,2808,valgrind},{atom,2808,gprof},{atom,2808,lcnt},{atom,2808,frmptr}]}]},{type,2816,'fun',[{type,2816,product,[{atom,2816,info}]},{type,2816,binary,[]}]},{type,2817,'fun',[{type,2817,product,[{atom,2817,kernel_poll}]},{type,2817,boolean,[]}]},{type,2818,'fun',[{type,2818,product,[{atom,2818,loaded}]},{type,2818,binary,[]}]},{type,2822,'fun',[{type,2822,product,[{atom,2822,machine}]},{type,2822,string,[]}]},{type,2828,'fun',[{type,2828,product,[{atom,2828,modified_timing_level}]},{type,2828,union,[{type,2828,integer,[]},{atom,2828,undefined}]}]},{type,2831,'fun',[{type,2831,product,[{atom,2831,nif_version}]},{type,2831,string,[]}]},{type,2833,'fun',[{type,2833,product,[{atom,2833,otp_release}]},{type,2833,string,[]}]},{type,2836,'fun',[{type,2836,product,[{atom,2836,port_parallelism}]},{type,2836,boolean,[]}]},{type,2855,'fun',[{type,2855,product,[{atom,2855,system_architecture}]},{type,2855,string,[]}]},{type,2856,'fun',[{type,2856,product,[{atom,2856,system_logger}]},{type,2856,union,[{atom,2856,logger},{atom,2856,undefined},{type,2856,pid,[]}]}]},{type,2857,'fun',[{type,2857,product,[{atom,2857,system_version}]},{type,2857,string,[]}]},{type,2864,'fun',[{type,2864,product,[{atom,2864,trace_control_word}]},{type,2864,non_neg_integer,[]}]},{type,2866,'fun',[{type,2866,product,[{atom,2866,version}]},{type,2866,string,[]}]},{type,2867,'fun',[{type,2867,product,[{type,2867,union,[{atom,2867,wordsize},{type,2867,tuple,[{atom,2867,wordsize},{atom,2867,internal}]},{type,2867,tuple,[{atom,2867,wordsize},{atom,2867,external}]}]}]},{type,2867,union,[{integer,2867,4},{integer,2867,8}]}]}]}}],since => <<79,84,80,32,49,55,46,52,44,79,84,80,32,50,49,46,51,44,79,84,80,32,50,52,46,48,44,79,84,80,32,82,49,53,66,48,49,44,79,84,80,32,82,49,54,66>>}},{{function,system_monitor,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1957}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,115,101,116,116,105,110,103,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>]}]},<<32,97,115,32>>,{code,[],[<<123,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,110,111,32,115,101,116,116,105,110,103,115,32,101,120,105,115,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,111,110,101,32,116,104,97,116,32,119,97,115,32,115,101,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,52,50,52>>,signature => [{attribute,1957,spec,{{erlang,system_monitor,0},[{type,1957,bounded_fun,[{type,1957,'fun',[{type,1957,product,[]},{var,1957,'MonSettings'}]},[{type,1958,constraint,[{atom,1958,is_subtype},[{var,1958,'MonSettings'},{type,1958,union,[{atom,1958,undefined},{type,1958,tuple,[{var,1958,'MonitorPid'},{var,1958,'Options'}]}]}]]},{type,1959,constraint,[{atom,1959,is_subtype},[{var,1959,'MonitorPid'},{type,1959,pid,[]}]]},{type,1960,constraint,[{atom,1960,is_subtype},[{var,1960,'Options'},{type,1960,list,[{user_type,1960,system_monitor_option,[]}]}]]}]]}]}}]}},{{function,system_monitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1965}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<87,104,101,110,32,99,97,108,108,101,100,32,119,105,116,104,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,97,108,108,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,32,109,111,110,105,116,111,114,105,110,103,32,115,101,116,116,105,110,103,115,32,97,114,101,32,99,108,101,97,114,101,100,46>>]},{p,[],[<<67,97,108,108,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<123,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<32,97,115,32,97,114,103,117,109,101,110,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,41>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,115,101,116,116,105,110,103,115,32,106,117,115,116,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,52,51,56>>,signature => [{attribute,1965,spec,{{erlang,system_monitor,1},[{type,1965,bounded_fun,[{type,1965,'fun',[{type,1965,product,[{var,1965,'Arg'}]},{var,1965,'MonSettings'}]},[{type,1966,constraint,[{atom,1966,is_subtype},[{var,1966,'Arg'},{type,1966,union,[{atom,1966,undefined},{type,1966,tuple,[{var,1966,'MonitorPid'},{var,1966,'Options'}]}]}]]},{type,1967,constraint,[{atom,1967,is_subtype},[{var,1967,'MonSettings'},{type,1967,union,[{atom,1967,undefined},{type,1967,tuple,[{var,1967,'MonitorPid'},{var,1967,'Options'}]}]}]]},{type,1968,constraint,[{atom,1968,is_subtype},[{var,1968,'MonitorPid'},{type,1968,pid,[]}]]},{type,1969,constraint,[{atom,1969,is_subtype},[{var,1969,'Options'},{type,1969,list,[{user_type,1969,system_monitor_option,[]}]}]]}]]}]}}]}},{{function,system_monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1974}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,32,109,111,110,105,116,111,114,105,110,103,32,111,112,116,105,111,110,115,46,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,114,101,99,101,105,118,105,110,103,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,109,111,110,105,116,111,114,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,108,111,110,103,95,103,99,44,32,84,105,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,116,97,107,101,115,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<84,105,109,101>>]},<<32,119,97,108,108,32,99,108,111,99,107,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,71,99,80,105,100,44,32,108,111,110,103,95,103,99,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<71,99,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,119,97,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<79,110,101,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,71,99,84,105,109,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<71,99,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,116,105,109,101,32,102,111,114,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46,32,84,104,101,32,111,116,104,101,114,32,116,117,112,108,101,115,32,97,114,101,32,116,97,103,103,101,100,32,119,105,116,104,32>>,{code,[],[<<104,101,97,112,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<109,98,117,102,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,115,105,122,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<46,32,84,104,101,115,101,32,116,117,112,108,101,115,32,97,114,101,32,101,120,112,108,97,105,110,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<41,46,32,78,101,119,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,44,32,97,110,100,32,116,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,108,105,115,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,108,111,110,103,95,115,99,104,101,100,117,108,101,44,32,84,105,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,114,117,110,115,32,117,110,105,110,116,101,114,114,117,112,116,101,100,32,102,111,114,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<84,105,109,101>>]},<<32,119,97,108,108,32,99,108,111,99,107,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,80,105,100,79,114,80,111,114,116,44,32,108,111,110,103,95,115,99,104,101,100,117,108,101,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,116,104,97,116,32,119,97,115,32,114,117,110,110,105,110,103,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,101,118,101,110,116,46>>]},{p,[],[<<73,102,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,116,104,101,32,116,117,112,108,101,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,77,105,108,108,105,115,125>>]},<<44,32>>,{code,[],[<<123,105,110,44,32,76,111,99,97,116,105,111,110,125>>]},<<44,32,97,110,100,32>>,{code,[],[<<123,111,117,116,44,32,76,111,99,97,116,105,111,110,125>>]},<<32,97,114,101,32,112,114,101,115,101,110,116,44,32,119,104,101,114,101,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,101,105,116,104,101,114,32,97,110,32,77,70,65,32,40>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<41,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,104,101,114,101,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,115,99,104,101,100,117,108,101,100,32,105,110,47,111,117,116,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<73,102,32,97,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<44,32,116,104,101,32,116,117,112,108,101,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,77,105,108,108,105,115,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,112,111,114,116,95,111,112,44,79,112,125>>]},<<32,97,114,101,32,112,114,101,115,101,110,116,46,32>>,{code,[],[<<79,112>>]},<<32,105,115,32,111,110,101,32,111,102,32>>,{code,[],[<<112,114,111,99,95,115,105,103>>]},<<44,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<44,32>>,{code,[],[<<105,110,112,117,116>>]},<<44,32>>,{code,[],[<<111,117,116,112,117,116>>]},<<44,32>>,{code,[],[<<101,118,101,110,116>>]},<<44,32,111,114,32>>,{code,[],[<<100,105,115,116,95,99,109,100>>]},<<44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,119,104,105,99,104,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,32,119,97,115,32,101,120,101,99,117,116,105,110,103,46>>]},{p,[],[{code,[],[<<112,114,111,99,95,115,105,103>>]},<<32,105,115,32,97,110,32,105,110,116,101,114,110,97,108,32,111,112,101,114,97,116,105,111,110,32,97,110,100,32,105,115,32,110,101,118,101,114,32,116,111,32,97,112,112,101,97,114,44,32,119,104,105,108,101,32,116,104,101,32,111,116,104,101,114,115,32,114,101,112,114,101,115,101,110,116,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,115,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<44,32>>,{code,[],[<<114,101,97,100,121,95,105,110,112,117,116>>]},<<44,32>>,{code,[],[<<114,101,97,100,121,95,111,117,116,112,117,116>>]},<<44,32>>,{code,[],[<<101,118,101,110,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<111,117,116,112,117,116,118>>]},<<32,40,119,104,101,110,32,116,104,101,32,112,111,114,116,32,105,115,32,117,115,101,100,32,98,121,32,100,105,115,116,114,105,98,117,116,105,111,110,41,46,32,86,97,108,117,101,32>>,{code,[],[<<77,105,108,108,105,115>>]},<<32,105,110,32,116,117,112,108,101,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,117,110,105,110,116,101,114,114,117,112,116,101,100,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,44,32,119,104,105,99,104,32,97,108,119,97,121,115,32,105,115,32,101,113,117,97,108,32,116,111,32,111,114,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,115,117,112,112,108,105,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,116,114,97,99,101,46,32,78,101,119,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,116,111,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,108,105,115,116,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32,108,105,115,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,116,101,99,116,32,112,114,111,98,108,101,109,115,32,119,105,116,104,32,78,73,70,115,32,111,114,32,100,114,105,118,101,114,115,32,116,104,97,116,32,116,97,107,101,32,116,111,111,32,108,111,110,103,32,116,111,32,101,120,101,99,117,116,101,46,32,49,32,109,115,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,32,103,111,111,100,32,109,97,120,105,109,117,109,32,116,105,109,101,32,102,111,114,32,97,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,32,111,114,32,97,32,78,73,70,46,32,72,111,119,101,118,101,114,44,32,97,32,116,105,109,101,45,115,104,97,114,105,110,103,32,115,121,115,116,101,109,32,105,115,32,117,115,117,97,108,108,121,32,116,111,32,99,111,110,115,105,100,101,114,32,101,118,101,114,121,116,104,105,110,103,32,60,32,49,48,48,32,109,115,32,97,115,32,34,112,111,115,115,105,98,108,101,34,32,97,110,100,32,102,97,105,114,108,121,32,34,110,111,114,109,97,108,34,46,32,72,111,119,101,118,101,114,44,32,108,111,110,103,101,114,32,115,99,104,101,100,117,108,101,32,116,105,109,101,115,32,99,97,110,32,105,110,100,105,99,97,116,101,32,115,119,97,112,112,105,110,103,32,111,114,32,97,32,109,105,115,98,101,104,97,118,105,110,103,32,78,73,70,47,100,114,105,118,101,114,46,32,77,105,115,98,101,104,97,118,105,110,103,32,78,73,70,115,32,97,110,100,32,100,114,105,118,101,114,115,32,99,97,110,32,99,97,117,115,101,32,98,97,100,32,114,101,115,111,117,114,99,101,32,117,116,105,108,105,122,97,116,105,111,110,32,97,110,100,32,98,97,100,32,111,118,101,114,97,108,108,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,46>>]}]},{dt,[],[{code,[],[<<123,108,97,114,103,101,95,104,101,97,112,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,114,101,115,117,108,116,115,32,105,110,32,116,104,101,32,97,108,108,111,99,97,116,101,100,32,115,105,122,101,32,111,102,32,97,32,104,101,97,112,32,98,101,105,110,103,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,119,111,114,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,71,99,80,105,100,44,32,108,97,114,103,101,95,104,101,97,112,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<71,99,80,105,100>>]},<<32,97,110,100,32>>,{code,[],[<<73,110,102,111>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,102,111,114,32>>,{code,[],[<<108,111,110,103,95,103,99>>]},<<32,101,97,114,108,105,101,114,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,116,117,112,108,101,32,116,97,103,103,101,100,32,119,105,116,104,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,115,105,122,101,115,32,111,102,32,97,108,108,32,109,101,109,111,114,121,32,98,108,111,99,107,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,97,108,108,32,104,101,97,112,32,103,101,110,101,114,97,116,105,111,110,115,32,97,102,116,101,114,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,101,113,117,97,108,32,116,111,32,111,114,32,104,105,103,104,101,114,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<46>>]},{p,[],[<<87,104,101,110,32,97,32,112,114,111,99,101,115,115,32,105,115,32,107,105,108,108,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32,105,116,32,105,115,32,107,105,108,108,101,100,32,98,101,102,111,114,101,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,99,111,109,112,108,101,116,101,32,97,110,100,32,116,104,117,115,32,110,111,32,108,97,114,103,101,32,104,101,97,112,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]}]},{dt,[],[{code,[],[<<98,117,115,121,95,112,111,114,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,103,101,116,115,32,115,117,115,112,101,110,100,101,100,32,98,101,99,97,117,115,101,32,105,116,32,115,101,110,100,115,32,116,111,32,97,32,98,117,115,121,32,112,111,114,116,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,83,117,115,80,105,100,44,32,98,117,115,121,95,112,111,114,116,44,32,80,111,114,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<83,117,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,103,111,116,32,115,117,115,112,101,110,100,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,111,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<98,117,115,121,95,100,105,115,116,95,112,111,114,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,103,101,116,115,32,115,117,115,112,101,110,100,101,100,32,98,101,99,97,117,115,101,32,105,116,32,115,101,110,100,115,32,116,111,32,97,32,112,114,111,99,101,115,115,32,111,110,32,97,32,114,101,109,111,116,101,32,110,111,100,101,32,119,104,111,115,101,32,105,110,116,101,114,45,110,111,100,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,97,115,32,104,97,110,100,108,101,100,32,98,121,32,97,32,98,117,115,121,32,112,111,114,116,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,83,117,115,80,105,100,44,32,98,117,115,121,95,100,105,115,116,95,112,111,114,116,44,32,80,111,114,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<83,117,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,103,111,116,32,115,117,115,112,101,110,100,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,32,105,110,116,101,114,45,110,111,100,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,112,111,114,116,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,115,101,116,116,105,110,103,115,32,106,117,115,116,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>]}]},<<46>>]},{p,[],[<<84,104,101,32,97,114,103,117,109,101,110,116,115,32,116,111,32>>,{code,[],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>]},<<32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,97,108,108,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,111,110,32,116,104,101,32,110,111,100,101,32,115,104,111,117,108,100,32,98,101,32,100,111,110,101,44,32,110,111,116,32,104,111,119,32,105,116,32,115,104,111,117,108,100,32,98,101,32,99,104,97,110,103,101,100,46,32,84,104,105,115,32,109,101,97,110,115,32,111,110,108,121,32,111,110,101,32,112,114,111,99,101,115,115,32,97,116,32,97,32,116,105,109,101,32,40>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<41,32,99,97,110,32,98,101,32,116,104,101,32,114,101,99,101,105,118,101,114,32,111,102,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,46,32,65,108,115,111,44,32,116,104,101,32,119,97,121,32,116,111,32,99,108,101,97,114,32,97,32,115,112,101,99,105,102,105,99,32,109,111,110,105,116,111,114,32,111,112,116,105,111,110,32,105,115,32,116,111,32,110,111,116,32,105,110,99,108,117,100,101,32,105,116,32,105,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<46,32,65,108,108,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,119,105,108,108,44,32,104,111,119,101,118,101,114,44,32,98,101,32,99,108,101,97,114,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,116,101,114,109,105,110,97,116,101,115,46>>]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,110,111,32,115,112,101,99,105,97,108,32,111,112,116,105,111,110,32,118,97,108,117,101,115,32,40,108,105,107,101,32,122,101,114,111,41,32,116,111,32,99,108,101,97,114,32,97,110,32,111,112,116,105,111,110,46,32,83,111,109,101,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,104,97,118,101,32,97,32,117,110,115,112,101,99,105,102,105,101,100,32,109,105,110,105,109,117,109,32,118,97,108,117,101,46,32,76,111,119,101,114,32,118,97,108,117,101,115,32,119,105,108,108,32,98,101,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,109,105,110,105,109,117,109,32,118,97,108,117,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,105,115,32,99,117,114,114,101,110,116,108,121,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,109,111,110,105,116,111,114,32,97,108,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,119,105,116,104,32>>,{code,[],[<<123,108,111,110,103,95,103,99,44,32,48,125>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,103,101,116,115,32,115,111,32,108,97,114,103,101,32,116,104,97,116,32,105,116,32,105,116,115,101,108,102,32,115,116,97,114,116,115,32,116,111,32,99,97,117,115,101,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,32,119,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,110,103,44,32,116,104,101,32,109,101,115,115,97,103,101,115,32,101,110,108,97,114,103,101,32,116,104,101,32,112,114,111,99,101,115,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,110,100,32,112,114,111,98,97,98,108,121,32,109,97,107,101,32,116,104,101,32,112,114,111,98,108,101,109,32,119,111,114,115,101,46>>]},{p,[],[<<75,101,101,112,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,110,101,97,116,32,97,110,100,32,100,111,32,110,111,116,32,115,101,116,32,116,104,101,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,108,105,109,105,116,115,32,116,111,111,32,116,105,103,104,116,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,52,53,54>>,signature => [{attribute,1974,spec,{{erlang,system_monitor,2},[{type,1974,bounded_fun,[{type,1974,'fun',[{type,1974,product,[{var,1974,'MonitorPid'},{var,1974,'Options'}]},{var,1974,'MonSettings'}]},[{type,1975,constraint,[{atom,1975,is_subtype},[{var,1975,'MonitorPid'},{type,1975,pid,[]}]]},{type,1976,constraint,[{atom,1976,is_subtype},[{var,1976,'Options'},{type,1976,list,[{user_type,1976,system_monitor_option,[]}]}]]},{type,1977,constraint,[{atom,1977,is_subtype},[{var,1977,'MonSettings'},{type,1977,union,[{atom,1977,undefined},{type,1977,tuple,[{var,1977,'OldMonitorPid'},{var,1977,'OldOptions'}]}]}]]},{type,1978,constraint,[{atom,1978,is_subtype},[{var,1978,'OldMonitorPid'},{type,1978,pid,[]}]]},{type,1979,constraint,[{atom,1979,is_subtype},[{var,1979,'OldOptions'},{type,1979,list,[{user_type,1979,system_monitor_option,[]}]}]]}]]}]}}]}},{{function,system_profile,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1984}],[<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,112,114,111,102,105,108,105,110,103,32,115,101,116,116,105,110,103,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>]}]},<<32,97,115,32>>,{code,[],[<<123,80,114,111,102,105,108,101,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,111,32,115,101,116,116,105,110,103,115,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,111,110,101,32,116,104,97,116,32,119,97,115,32,115,101,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,54,48,48>>,signature => [{attribute,1984,spec,{{erlang,system_profile,0},[{type,1984,bounded_fun,[{type,1984,'fun',[{type,1984,product,[]},{var,1984,'ProfilerSettings'}]},[{type,1985,constraint,[{atom,1985,is_subtype},[{var,1985,'ProfilerSettings'},{type,1985,union,[{atom,1985,undefined},{type,1985,tuple,[{var,1985,'ProfilerPid'},{var,1985,'Options'}]}]}]]},{type,1986,constraint,[{atom,1986,is_subtype},[{var,1986,'ProfilerPid'},{type,1986,union,[{type,1986,pid,[]},{type,1986,port,[]}]}]]},{type,1987,constraint,[{atom,1987,is_subtype},[{var,1987,'Options'},{type,1987,list,[{user_type,1987,system_profile_option,[]}]}]]}]]}]}}]}},{{function,system_profile,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1992}],[<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,112,114,111,102,105,108,101,114,32,111,112,116,105,111,110,115,46,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,114,32,112,111,114,116,32,114,101,99,101,105,118,105,110,103,32,112,114,111,102,105,108,105,110,103,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,114,101,99,101,105,118,101,114,32,105,115,32,101,120,99,108,117,100,101,100,32,102,114,111,109,32,97,108,108,32,112,114,111,102,105,108,105,110,103,46,32,84,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,102,105,108,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,99,108,117,115,105,118,101>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,97,108,108,32,116,111,32,97,32,112,111,114,116,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32,105,115,32,100,111,110,101,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,110,111,116,32,114,117,110,110,97,98,108,101,32,100,117,114,105,110,103,32,116,104,101,32,99,97,108,108,32,114,117,110,116,105,109,101,32,116,111,32,116,104,101,32,112,111,114,116,46,32,84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,105,102,105,101,100,32,97,115,32>>,{code,[],[<<105,110,97,99,116,105,118,101>>]},<<44,32,97,110,100,32,108,97,116,101,114,32>>,{code,[],[<<97,99,116,105,118,101>>]},<<32,119,104,101,110,32,116,104,101,32,112,111,114,116,32,99,97,108,108,98,97,99,107,32,114,101,116,117,114,110,115,46>>]}]},{dt,[],[{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,97,98,108,101,95,112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,115,32,112,117,116,32,105,110,116,111,32,111,114,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,114,117,110,32,113,117,101,117,101,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,80,105,100,44,32,83,116,97,116,101,44,32,77,102,97,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46,32,82,117,110,110,105,110,103,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,105,110,115,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32,114,117,110,32,113,117,101,117,101,32,97,102,116,101,114,32,104,97,118,105,110,103,32,98,101,101,110,32,112,114,101,45,101,109,112,116,101,100,32,100,111,32,110,111,116,32,116,114,105,103,103,101,114,32,116,104,105,115,32,109,101,115,115,97,103,101,46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,97,98,108,101,95,112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,111,114,116,32,105,115,32,112,117,116,32,105,110,116,111,32,111,114,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,114,117,110,32,113,117,101,117,101,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,80,111,114,116,44,32,83,116,97,116,101,44,32,48,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,115,99,104,101,100,117,108,101,114,32,105,115,32,112,117,116,32,116,111,32,115,108,101,101,112,32,111,114,32,97,119,111,107,101,110,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,115,99,104,101,100,117,108,101,114,44,32,73,100,44,32,83,116,97,116,101,44,32,78,111,83,99,104,101,100,115,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,99,111,110,115,105,115,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,105,110,116,101,103,101,114,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<123,101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41,44,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,105,110,99,108,117,100,101,32,97,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,116,104,97,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,40,41>>]},<<46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,100,101,102,97,117,108,116,32,105,102,32,110,111,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,73,102,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,104,97,115,32,98,101,101,110,32,101,110,97,98,108,101,100,32,116,104,114,111,117,103,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<44,32,116,104,105,115,32,97,108,115,111,32,101,102,102,101,99,116,115,32,116,104,101,32,116,105,109,101,32,115,116,97,109,112,32,112,114,111,100,117,99,101,100,32,105,110,32,112,114,111,102,105,108,105,110,103,32,109,101,115,115,97,103,101,115,32,119,104,101,110,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,101,110,97,98,108,101,100,46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101>>]},<<32,98,101,104,97,118,105,111,114,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,54,49,53>>,signature => [{attribute,1992,spec,{{erlang,system_profile,2},[{type,1992,bounded_fun,[{type,1992,'fun',[{type,1992,product,[{var,1992,'ProfilerPid'},{var,1992,'Options'}]},{var,1992,'ProfilerSettings'}]},[{type,1993,constraint,[{atom,1993,is_subtype},[{var,1993,'ProfilerPid'},{type,1993,union,[{type,1993,pid,[]},{type,1993,port,[]},{atom,1993,undefined}]}]]},{type,1994,constraint,[{atom,1994,is_subtype},[{var,1994,'Options'},{type,1994,list,[{user_type,1994,system_profile_option,[]}]}]]},{type,1995,constraint,[{atom,1995,is_subtype},[{var,1995,'ProfilerSettings'},{type,1995,union,[{atom,1995,undefined},{type,1995,tuple,[{type,1995,union,[{type,1995,pid,[]},{type,1995,port,[]}]},{type,1995,list,[{user_type,1995,system_profile_option,[]}]}]}]}]]}]]}]}}]}},{{function,system_time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1545}],[<<115,121,115,116,101,109,95,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,54,56,57>>,signature => [{attribute,1545,spec,{{erlang,system_time,0},[{type,1545,'fun',[{type,1545,product,[]},{type,1545,integer,[]}]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,system_time,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1550}],[<<115,121,115,116,101,109,95,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,85,110,105,116,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,55,49,49>>,signature => [{attribute,1550,spec,{{erlang,system_time,1},[{type,1550,bounded_fun,[{type,1550,'fun',[{type,1550,product,[{var,1550,'Unit'}]},{type,1550,integer,[]}]},[{type,1551,constraint,[{atom,1551,is_subtype},[{var,1551,'Unit'},{user_type,1551,time_unit,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,term_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2667}],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,101,110,99,111,100,105,110,103,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},{p,[],[<<84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,118,97,114,105,111,117,115,32,112,117,114,112,111,115,101,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,119,114,105,116,105,110,103,32,97,32,116,101,114,109,32,116,111,32,97,32,102,105,108,101,32,105,110,32,97,110,32,101,102,102,105,99,105,101,110,116,32,119,97,121,44,32,111,114,32,115,101,110,100,105,110,103,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,111,32,115,111,109,101,32,116,121,112,101,32,111,102,32,99,111,109,109,117,110,105,99,97,116,105,111,110,115,32,99,104,97,110,110,101,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,100,105,115,116,114,105,98,117,116,101,100,32,69,114,108,97,110,103,46>>]},{pre,[],[{code,[],[<<62,32,66,105,110,32,61,32,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,104,101,108,108,111,41,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,10,62,32,104,101,108,108,111,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,66,105,110,41,46,10,104,101,108,108,111>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,114,101,116,117,114,110,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,101,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,97,109,101,32,116,101,114,109,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,55,51,51>>,signature => [{attribute,2667,spec,{{term_to_binary,1},[{type,2667,bounded_fun,[{type,2667,'fun',[{type,2667,product,[{var,2667,'Term'}]},{user_type,2667,ext_binary,[]}]},[{type,2668,constraint,[{atom,2668,is_subtype},[{var,2668,'Term'},{type,2668,term,[]}]]}]]}]}}]}},{{function,term_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2672}],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,101,110,99,111,100,105,110,103,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,105,115,32,112,114,111,118,105,100,101,100,44,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,105,115,32,99,111,109,112,114,101,115,115,101,100,46,32,84,104,101,32,99,111,109,112,114,101,115,115,101,100,32,102,111,114,109,97,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<32,97,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,55,66,46>>]},{p,[],[<<65,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,103,105,118,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,99,111,109,112,114,101,115,115,101,100,44,32,76,101,118,101,108,125>>]},<<46,32>>,{code,[],[<<76,101,118,101,108>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,119,105,116,104,32,114,97,110,103,101,32,48,46,46,57,44,32,119,104,101,114,101,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<48>>]},<<32,45,32,78,111,32,99,111,109,112,114,101,115,115,105,111,110,32,105,115,32,100,111,110,101,32,40,105,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,103,105,118,105,110,103,32,110,111,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,111,112,116,105,111,110,41,46>>]}]},{li,[],[{p,[],[{code,[],[<<49>>]},<<32,45,32,84,97,107,101,115,32,108,101,97,115,116,32,116,105,109,101,32,98,117,116,32,109,97,121,32,110,111,116,32,99,111,109,112,114,101,115,115,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,115,46>>]}]},{li,[],[{p,[],[{code,[],[<<54>>]},<<32,45,32,68,101,102,97,117,108,116,32,108,101,118,101,108,32,119,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,105,115,32,112,114,111,118,105,100,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<57>>]},<<32,45,32,84,97,107,101,115,32,109,111,115,116,32,116,105,109,101,32,97,110,100,32,116,114,105,101,115,32,116,111,32,112,114,111,100,117,99,101,32,97,32,115,109,97,108,108,101,114,32,114,101,115,117,108,116,46,32,78,111,116,105,99,101,32,34,116,114,105,101,115,34,32,105,110,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,115,101,110,116,101,110,99,101,59,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,105,110,112,117,116,32,116,101,114,109,44,32,108,101,118,101,108,32,57,32,99,111,109,112,114,101,115,115,105,111,110,32,101,105,116,104,101,114,32,100,111,101,115,32,111,114,32,100,111,101,115,32,110,111,116,32,112,114,111,100,117,99,101,32,97,32,115,109,97,108,108,101,114,32,114,101,115,117,108,116,32,116,104,97,110,32,108,101,118,101,108,32,49,32,99,111,109,112,114,101,115,115,105,111,110,46>>]}]}]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<123,109,105,110,111,114,95,118,101,114,115,105,111,110,44,32,86,101,114,115,105,111,110,125>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,99,111,110,116,114,111,108,32,115,111,109,101,32,101,110,99,111,100,105,110,103,32,100,101,116,97,105,108,115,46,32,84,104,105,115,32,111,112,116,105,111,110,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,45,52,46,32,84,104,101,32,118,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<86,101,114,115,105,111,110>>]},<<32,97,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<48>>]}]},{dd,[],[{p,[],[<<70,108,111,97,116,115,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,97,32,116,101,120,116,117,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,117,115,101,102,117,108,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,114,101,108,101,97,115,101,115,32,98,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,45,52,32,99,97,110,32,100,101,99,111,100,101,32,114,101,115,117,108,116,105,110,103,32,98,105,110,97,114,121,46>>]},{p,[],[<<84,104,105,115,32,118,101,114,115,105,111,110,32,101,110,99,111,100,101,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,108,97,116,105,110,49,32,115,116,114,105,110,103,32,117,115,105,110,103,32,108,97,116,105,110,49,32,101,110,99,111,100,105,110,103,32,119,104,105,108,101,32,111,110,108,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,108,97,116,105,110,49,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,117,116,102,56,46>>]}]},{dt,[],[{code,[],[<<49>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,105,115,32,97,115,32,111,102,32,69,114,108,97,110,103,47,79,84,80,32,49,55,46,48,32,116,104,101,32,100,101,102,97,117,108,116,46,32,73,116,32,102,111,114,99,101,115,32,97,110,121,32,102,108,111,97,116,115,32,105,110,32,116,104,101,32,116,101,114,109,32,116,111,32,98,101,32,101,110,99,111,100,101,100,32,105,110,32,97,32,109,111,114,101,32,115,112,97,99,101,45,101,102,102,105,99,105,101,110,116,32,97,110,100,32,101,120,97,99,116,32,119,97,121,32,40,110,97,109,101,108,121,32,105,110,32,116,104,101,32,54,52,45,98,105,116,32,73,69,69,69,32,102,111,114,109,97,116,44,32,114,97,116,104,101,114,32,116,104,97,110,32,99,111,110,118,101,114,116,101,100,32,116,111,32,97,32,116,101,120,116,117,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,41,46,32,65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,45,52,44,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<32,99,97,110,32,100,101,99,111,100,101,32,116,104,105,115,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<84,104,105,115,32,118,101,114,115,105,111,110,32,101,110,99,111,100,101,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,108,97,116,105,110,49,32,115,116,114,105,110,103,32,117,115,105,110,103,32,108,97,116,105,110,49,32,101,110,99,111,100,105,110,103,32,119,104,105,108,101,32,111,110,108,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,108,97,116,105,110,49,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,117,116,102,56,46>>]}]},{dt,[],[{code,[],[<<50>>]}]},{dd,[],[{p,[],[<<68,114,111,112,115,32,117,115,97,103,101,32,111,102,32,116,104,101,32,108,97,116,105,110,49,32,97,116,111,109,32,101,110,99,111,100,105,110,103,32,97,110,100,32,117,110,99,111,110,100,105,116,105,111,110,97,108,108,121,32,117,115,101,32,117,116,102,56,32,101,110,99,111,100,105,110,103,32,102,111,114,32,97,108,108,32,97,116,111,109,115,46,32,84,104,105,115,32,119,105,108,108,32,98,101,32,99,104,97,110,103,101,100,32,116,111,32,116,104,101,32,100,101,102,97,117,108,116,32,105,110,32,97,32,102,117,116,117,114,101,32,109,97,106,111,114,32,114,101,108,101,97,115,101,32,111,102,32,69,114,108,97,110,103,47,79,84,80,46,32,69,114,108,97,110,103,47,79,84,80,32,115,121,115,116,101,109,115,32,97,115,32,111,102,32,82,49,54,66,32,99,97,110,32,100,101,99,111,100,101,32,116,104,105,115,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,55,54,49>>,signature => [{attribute,2672,spec,{{term_to_binary,2},[{type,2672,bounded_fun,[{type,2672,'fun',[{type,2672,product,[{var,2672,'Term'},{var,2672,'Options'}]},{user_type,2672,ext_binary,[]}]},[{type,2673,constraint,[{atom,2673,is_subtype},[{var,2673,'Term'},{type,2673,term,[]}]]},{type,2674,constraint,[{atom,2674,is_subtype},[{var,2674,'Options'},{type,2674,list,[{type,2674,union,[{atom,2674,compressed},{type,2675,tuple,[{atom,2675,compressed},{ann_type,2675,[{var,2675,'Level'},{type,2675,range,[{integer,2675,0},{integer,2675,9}]}]}]},{type,2676,tuple,[{atom,2676,minor_version},{ann_type,2676,[{var,2676,'Version'},{type,2676,range,[{integer,2676,0},{integer,2676,2}]}]}]}]}]}]]}]]}]}}]}},{{function,term_to_iovec,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2680}],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<101,120,116,95,105,111,118,101,99,40,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,105,110,103,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,110,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,46,32,84,104,101,32,99,97,108,108,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,116,101,114,109,95,116,111,95,105,111,118,101,99,40,84,101,114,109,41,41>>]},<<32,119,105,108,108,32,112,114,111,100,117,99,101,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,41>>]},<<46>>]},{p,[],[{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,105,115,32,97,32,112,117,114,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,41>>]},<<32,112,114,111,118,105,100,101,46,32>>,{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,114,101,102,101,114,32,100,105,114,101,99,116,108,121,32,116,111,32,111,102,102,32,104,101,97,112,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,99,111,112,121,105,110,103,32,116,104,101,32,98,105,110,97,114,121,32,100,97,116,97,32,105,110,116,111,32,116,104,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,56,50,54>>,signature => [{attribute,2680,spec,{{term_to_iovec,1},[{type,2680,bounded_fun,[{type,2680,'fun',[{type,2680,product,[{var,2680,'Term'}]},{user_type,2680,ext_iovec,[]}]},[{type,2681,constraint,[{atom,2681,is_subtype},[{var,2681,'Term'},{type,2681,term,[]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,term_to_iovec,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2685}],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<101,120,116,95,105,111,118,101,99,40,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,105,110,103,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,110,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,46,32,84,104,101,32,99,97,108,108,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,116,101,114,109,95,116,111,95,105,111,118,101,99,40,84,101,114,109,44,32,79,112,116,115,41,41>>]},<<32,119,105,108,108,32,112,114,111,100,117,99,101,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,44,32,79,112,116,115,41>>]},<<46>>]},{p,[],[<<67,117,114,114,101,110,116,108,121,32,114,101,99,111,103,110,105,115,101,100,32,111,112,116,105,111,110,115,32,97,114,101,32,97,108,108,32,111,112,116,105,111,110,115,32,114,101,99,111,103,110,105,115,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]},{p,[],[{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,105,115,32,97,32,112,117,114,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,41>>]},<<32,112,114,111,118,105,100,101,46,32>>,{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,114,101,102,101,114,32,100,105,114,101,99,116,108,121,32,116,111,32,111,102,102,32,104,101,97,112,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,99,111,112,121,105,110,103,32,116,104,101,32,98,105,110,97,114,121,32,100,97,116,97,32,105,110,116,111,32,116,104,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,56,53,49>>,signature => [{attribute,2685,spec,{{term_to_iovec,2},[{type,2685,bounded_fun,[{type,2685,'fun',[{type,2685,product,[{var,2685,'Term'},{var,2685,'Options'}]},{user_type,2685,ext_iovec,[]}]},[{type,2686,constraint,[{atom,2686,is_subtype},[{var,2686,'Term'},{type,2686,term,[]}]]},{type,2687,constraint,[{atom,2687,is_subtype},[{var,2687,'Options'},{type,2687,list,[{type,2687,union,[{atom,2687,compressed},{type,2688,tuple,[{atom,2688,compressed},{ann_type,2688,[{var,2688,'Level'},{type,2688,range,[{integer,2688,0},{integer,2688,9}]}]}]},{type,2689,tuple,[{atom,2689,minor_version},{ann_type,2689,[{var,2689,'Version'},{type,2689,range,[{integer,2689,0},{integer,2689,2}]}]}]}]}]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,throw,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2001}],[<<116,104,114,111,119,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<116,104,114,111,119>>]},<<46,32,73,110,116,101,110,100,101,100,32,116,111,32,98,101,32,117,115,101,100,32,116,111,32,100,111,32,110,111,110,45,108,111,99,97,108,32,114,101,116,117,114,110,115,32,102,114,111,109,32,102,117,110,99,116,105,111,110,115,46>>]},{p,[],[<<73,102,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,99,97,116,99,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,97,116,99,104,32,101,120,112,114,101,115,115,105,111,110>>]},<<44,32,116,104,101,32,99,97,116,99,104,32,101,120,112,114,101,115,115,105,111,110,32,114,101,116,117,114,110,115,32,118,97,108,117,101,32>>,{code,[],[<<65,110,121>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,97,116,99,104,32,116,104,114,111,119,40,123,104,101,108,108,111,44,32,116,104,101,114,101,125,41,46,10,32,32,32,32,32,32,32,32,123,104,101,108,108,111,44,116,104,101,114,101,125>>]}]},{p,[],[<<73,102,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,97,32>>,{code,[],[<<116,114,121>>]},<<45,98,108,111,99,107,32,111,102,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,114,121,32,101,120,112,114,101,115,115,105,111,110>>]},<<44,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<65,110,121>>]},<<32,99,97,110,32,98,101,32,99,97,117,103,104,116,32,119,105,116,104,105,110,32,116,104,101,32,99,97,116,99,104,32,98,108,111,99,107,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<116,114,121,10,32,32,32,32,116,104,114,111,119,40,123,109,121,95,101,120,99,101,112,116,105,111,110,44,32,34,83,111,109,101,116,104,105,110,103,32,104,97,112,112,101,110,101,100,34,125,41,10,99,97,116,99,104,10,32,32,32,32,116,104,114,111,119,58,123,109,121,95,101,120,99,101,112,116,105,111,110,44,32,68,101,115,99,125,32,45,62,10,32,32,32,32,32,32,32,32,105,111,58,102,111,114,109,97,116,40,115,116,97,110,100,97,114,100,95,101,114,114,111,114,44,32,34,69,114,114,111,114,58,32,126,115,126,110,34,44,32,91,68,101,115,99,93,41,10,101,110,100>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,99,97,116,99,104>>]},<<32,105,102,32,110,111,116,32,99,97,117,103,104,116,32,98,121,32,97,110,32,101,120,99,101,112,116,105,111,110,32,104,97,110,100,108,101,114,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,56,55,57>>,signature => [{attribute,2001,spec,{{throw,1},[{type,2001,bounded_fun,[{type,2001,'fun',[{type,2001,product,[{var,2001,'Any'}]},{type,2001,no_return,[]}]},[{type,2002,constraint,[{atom,2002,is_subtype},[{var,2002,'Any'},{type,2002,term,[]}]]}]]}]}}]}},{{function,time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2007}],[<<116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,97,115,32>>,{code,[],[<<123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125>>]},<<46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,105,109,101,40,41,46,10,123,57,44,52,50,44,52,52,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,57,48,55>>,signature => [{attribute,2007,spec,{{time,0},[{type,2007,bounded_fun,[{type,2007,'fun',[{type,2007,product,[]},{var,2007,'Time'}]},[{type,2008,constraint,[{atom,2008,is_subtype},[{var,2008,'Time'},{remote_type,2008,[{atom,2008,calendar},{atom,2008,time},[]]}]]}]]}]}}]}},{{function,time_offset,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1605}],[<<116,105,109,101,95,111,102,102,115,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46,32,67,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,97,100,100,101,100,32,116,111,32,97,110,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,103,105,118,101,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101,46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,99,104,97,110,103,101,32,100,117,114,105,110,103,32,111,112,101,114,97,116,105,111,110,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,117,115,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,99,104,97,110,103,101,32,105,110,32,116,105,109,101,32,111,102,102,115,101,116,32,99,97,110,32,98,101,32,111,98,115,101,114,118,101,100,32,97,116,32,115,108,105,103,104,116,108,121,32,100,105,102,102,101,114,101,110,116,32,112,111,105,110,116,115,32,105,110,32,116,105,109,101,32,98,121,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,101,116,101,99,116,115,32,116,104,97,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,104,97,115,32,99,104,97,110,103,101,100,46,32,84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,44,32,104,111,119,101,118,101,114,44,32,110,111,116,32,100,101,116,101,99,116,32,116,104,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,46,32,65,32,116,97,115,107,32,99,104,101,99,107,105,110,103,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,101,120,101,99,117,116,101,32,97,116,32,108,101,97,115,116,32,111,110,99,101,32,97,32,109,105,110,117,116,101,59,32,115,111,44,32,117,110,100,101,114,32,110,111,114,109,97,108,32,111,112,101,114,97,116,105,111,110,32,116,104,105,115,32,105,115,32,116,111,32,98,101,32,100,101,116,101,99,116,101,100,32,119,105,116,104,105,110,32,97,32,109,105,110,117,116,101,44,32,98,117,116,32,100,117,114,105,110,103,32,104,101,97,118,121,32,108,111,97,100,32,105,116,32,99,97,110,32,116,97,107,101,32,108,111,110,103,101,114,32,116,105,109,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,57,50,50>>,signature => [{attribute,1605,spec,{{erlang,time_offset,0},[{type,1605,'fun',[{type,1605,product,[]},{type,1605,integer,[]}]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,time_offset,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1610}],[<<116,105,109,101,95,111,102,102,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<83,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<32,104,111,119,101,118,101,114,32,111,112,116,105,109,105,122,101,100,32,102,111,114,32,99,111,109,109,111,110,108,121,32,117,115,101,100,32>>,{code,[],[<<85,110,105,116>>]},<<115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,57,53,52>>,signature => [{attribute,1610,spec,{{erlang,time_offset,1},[{type,1610,bounded_fun,[{type,1610,'fun',[{type,1610,product,[{var,1610,'Unit'}]},{type,1610,integer,[]}]},[{type,1611,constraint,[{atom,1611,is_subtype},[{var,1611,'Unit'},{user_type,1611,time_unit,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,timestamp,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1616}],[<<116,105,109,101,115,116,97,109,112,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,105,109,101,115,116,97,109,112>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,111,110,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125>>]},<<46,32,84,104,105,115,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,116,105,109,101,115,116,97,109,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,116,105,109,101,115,116,97,109,112,47,48>>]}]},<<32,97,110,100,32,116,104,101,32,100,101,112,114,101,99,97,116,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,119,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]}]},<<32,117,115,101,46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,101,32,101,120,105,115,116,101,110,99,101,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,40,41>>]},<<32,105,115,32,112,117,114,101,108,121,32,116,111,32,115,105,109,112,108,105,102,121,32,117,115,101,32,102,111,114,32,101,120,105,115,116,105,110,103,32,99,111,100,101,32,116,104,97,116,32,97,115,115,117,109,101,115,32,116,104,105,115,32,116,105,109,101,32,115,116,97,109,112,32,102,111,114,109,97,116,46,32,67,117,114,114,101,110,116,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101,32,99,97,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,108,121,32,98,101,32,114,101,116,114,105,101,118,101,100,32,105,110,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32,121,111,117,114,32,99,104,111,105,99,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,47,49>>]}]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,40,41>>]},<<32,66,73,70,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<116,105,109,101,115,116,97,109,112,40,41,32,45,62,10,32,32,32,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,109,105,99,114,111,115,101,99,111,110,100,41,44,10,32,32,32,32,77,101,103,97,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,100,105,118,32,49,48,48,48,95,48,48,48,95,48,48,48,95,48,48,48,44,10,32,32,32,32,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,100,105,118,32,49,48,48,48,95,48,48,48,32,45,32,77,101,103,97,83,101,99,115,42,49,48,48,48,95,48,48,48,44,10,32,32,32,32,77,105,99,114,111,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,114,101,109,32,49,48,48,48,95,48,48,48,44,10,32,32,32,32,123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125,46>>]}]},{p,[],[<<73,116,44,32,104,111,119,101,118,101,114,44,32,117,115,101,115,32,97,32,110,97,116,105,118,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,98,117,105,108,100,32,103,97,114,98,97,103,101,32,111,110,32,116,104,101,32,104,101,97,112,32,97,110,100,32,119,105,116,104,32,115,108,105,103,104,116,108,121,32,98,101,116,116,101,114,32,112,101,114,102,111,114,109,97,110,99,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,57,55,51>>,signature => [{attribute,1616,spec,{{erlang,timestamp,0},[{type,1616,bounded_fun,[{type,1616,'fun',[{type,1616,product,[]},{var,1616,'Timestamp'}]},[{type,1617,constraint,[{atom,1617,is_subtype},[{var,1617,'Timestamp'},{user_type,1617,timestamp,[]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,tl,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2694}],[<<116,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,97,105,108,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,108,105,115,116,32,109,105,110,117,115,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,44,32,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,93,41,46,10,91,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,93,41,46,10,91,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,44,32,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93,41,46,10,91,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93,41,46,10,105,109,112,114,111,112,101,114,95,101,110,100>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,105,115,116>>]},<<32,105,115,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,48,49,50>>,signature => [{attribute,2694,spec,{{tl,1},[{type,2694,bounded_fun,[{type,2694,'fun',[{type,2694,product,[{var,2694,'List'}]},{type,2694,term,[]}]},[{type,2695,constraint,[{atom,2695,is_subtype},[{var,2695,'List'},{type,2695,nonempty_maybe_improper_list,[]}]]}]]}]}}]}},{{function,trace,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2013}],[<<116,114,97,99,101,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,114,97,99,101,95,102,108,97,103>>}],[]}]},{p,[],[<<84,117,114,110,115,32,111,110,32,40,105,102,32>>,{code,[],[<<72,111,119,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,111,102,102,32,40,105,102,32>>,{code,[],[<<72,111,119,32,61,61,32,102,97,108,115,101>>]},<<41,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,105,110,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,114,111,99,101,115,115,101,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<46>>]},{p,[],[{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32,101,105,116,104,101,114,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,102,111,114,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,44,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103,95,112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<110,101,119>>]}]},{dd,[],[<<65,108,108,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<110,101,119,95,112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,112,111,114,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]}]},{p,[],[{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,108,97,103,115,32,40,116,104,101,32,34,109,101,115,115,97,103,101,32,116,97,103,115,34,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,108,105,115,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,114,97,99,101,32,109,101,115,115,97,103,101,115>>]}]},<<41,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,97,108,108,32,116,114,97,99,101,32,102,108,97,103,115,32,101,120,99,101,112,116,32>>,{code,[],[<<116,114,97,99,101,114>>]},<<32,97,110,100,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,119,104,105,99,104,32,97,114,101,32,105,110,32,116,104,101,105,114,32,110,97,116,117,114,101,32,100,105,102,102,101,114,101,110,116,32,116,104,97,110,32,116,104,101,32,111,116,104,101,114,115,46>>]}]},{dt,[],[{code,[],[<<115,101,110,100>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,101,110,100,105,110,103,32,111,102,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,110,100>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<39,114,101,99,101,105,118,101,39>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,114,101,99,101,105,118,105,110,103,32,111,102,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,99,101,105,118,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<39,114,101,99,101,105,118,101,39>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,99,101,114,116,97,105,110,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,83,112,101,99,105,102,121,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,116,111,32,116,114,97,99,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,97,108,108>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<115,105,108,101,110,116>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32,84,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]},<<44,32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,105,110,104,105,98,105,116,101,100,32,105,102,32,116,104,105,115,32,102,108,97,103,32,105,115,32,115,101,116,44,32,98,117,116,32,116,104,101,121,32,97,114,101,32,101,120,101,99,117,116,101,100,32,97,115,32,110,111,114,109,97,108,32,105,102,32,116,104,101,114,101,32,97,114,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46>>]},{p,[],[<<83,105,108,101,110,116,32,109,111,100,101,32,105,115,32,105,110,104,105,98,105,116,101,100,32,98,121,32,101,120,101,99,117,116,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,40,95,44,32,102,97,108,115,101,44,32,91,115,105,108,101,110,116,124,95,93,41>>]},<<44,32,111,114,32,98,121,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,101,120,101,99,117,116,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,115,105,108,101,110,116,44,32,102,97,108,115,101,125>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,97,99,105,108,105,116,97,116,101,115,32,115,101,116,116,105,110,103,32,117,112,32,97,32,116,114,97,99,101,32,111,110,32,109,97,110,121,32,111,114,32,101,118,101,110,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,116,114,97,99,101,32,99,97,110,32,116,104,101,110,32,98,101,32,97,99,116,105,118,97,116,101,100,32,97,110,100,32,100,101,97,99,116,105,118,97,116,101,100,32,117,115,105,110,103,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,115,105,108,101,110,116,44,66,111,111,108,125>>]},<<44,32,103,105,118,105,110,103,32,97,32,104,105,103,104,32,100,101,103,114,101,101,32,111,102,32,99,111,110,116,114,111,108,32,111,102,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,115,32,119,105,116,104,32,119,104,105,99,104,32,97,114,103,117,109,101,110,116,115,32,116,104,97,116,32,116,114,105,103,103,101,114,32,116,104,101,32,116,114,97,99,101,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,97,108,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},<<46,32,79,114,32,114,97,116,104,101,114,44,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,46>>]}]},{dt,[],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32,84,114,97,99,101,115,32,116,104,101,32,114,101,116,117,114,110,32,102,114,111,109,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,32,98,97,99,107,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46,32,79,110,108,121,32,119,111,114,107,115,32,102,111,114,32,102,117,110,99,116,105,111,110,115,32,116,114,97,99,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]},{p,[],[<<84,104,101,32,115,101,109,97,110,116,105,99,115,32,105,115,32,116,104,97,116,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,119,104,101,110,32,97,32,99,97,108,108,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,44,32,116,104,97,116,32,105,115,44,32,119,104,101,110,32,97,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,32,101,110,100,115,46,32,79,110,108,121,32,111,110,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,112,101,114,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,44,32,115,111,32,116,104,101,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,110,101,115,115,32,102,111,114,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,107,101,112,116,32,119,104,105,108,101,32,116,114,97,99,105,110,103,32,119,105,116,104,32,116,104,105,115,32,102,108,97,103,46,32,85,115,105,110,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,116,114,97,99,101,32,116,111,103,101,116,104,101,114,32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,107,110,111,119,32,101,120,97,99,116,108,121,32,105,110,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,32,97,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,97,116,32,97,110,121,32,116,105,109,101,46>>]},{p,[],[<<84,111,32,103,101,116,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,99,111,110,116,97,105,110,105,110,103,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,102,114,111,109,32,102,117,110,99,116,105,111,110,115,44,32,117,115,101,32,116,104,101,32>>,{code,[],[<<123,114,101,116,117,114,110,95,116,114,97,99,101,125>>]},<<32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,99,116,105,111,110,32,105,110,115,116,101,97,100,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,112,114,111,99,101,115,115,45,114,101,108,97,116,101,100,32,101,118,101,110,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,112,97,119,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,112,97,119,110,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,120,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,108,105,110,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,105,110,107>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,108,105,110,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,108,105,110,107>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,108,105,110,107,101,100>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,112,111,114,116,45,114,101,108,97,116,101,100,32,101,118,101,110,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,112,101,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,112,101,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,108,111,115,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,108,111,115,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,108,105,110,107,101,100>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<101,120,105,116,105,110,103>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,101,120,105,116,105,110,103,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,95,101,120,105,116,105,110,103>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,105,110,103,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116,95,101,120,105,116,105,110,103>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,101,100,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116,95,101,120,105,116,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103,95,112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,114,111,99,101,115,115,101,115,32,106,117,115,116,32,108,105,107,101,32>>,{code,[],[<<114,117,110,110,105,110,103>>]},<<46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,111,112,116,105,111,110,32,97,108,115,111,32,105,110,99,108,117,100,101,115,32,115,99,104,101,100,117,108,101,32,101,118,101,110,116,115,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,119,105,116,104,105,110,32,116,104,101,32,99,111,110,116,101,120,116,32,111,102,32,97,32,112,111,114,116,32,119,105,116,104,111,117,116,32,98,101,105,110,103,32,115,99,104,101,100,117,108,101,100,32,111,117,116,32,105,116,115,101,108,102,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103,95,112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,111,114,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,111,102,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,101,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,32,116,105,109,101,32,115,116,97,109,112,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,40,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<65,32,103,108,111,98,97,108,32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,110,111,100,101,32,116,104,97,116,32,109,97,107,101,115,32,97,108,108,32,116,114,97,99,101,32,116,105,109,101,32,115,116,97,109,112,115,32,117,115,105,110,103,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,116,111,32,98,101,32,105,110,32,67,80,85,32,116,105,109,101,44,32,110,111,116,32,119,97,108,108,32,99,108,111,99,107,32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,110,111,116,32,98,101,32,117,115,101,100,32,105,102,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,111,114,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,101,110,97,98,108,101,100,46,32,79,110,108,121,32,97,108,108,111,119,101,100,32,119,105,116,104,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99,61,61,97,108,108>>]},<<46,32,73,102,32,116,104,101,32,104,111,115,116,32,109,97,99,104,105,110,101,32,79,83,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,104,105,103,104,45,114,101,115,111,108,117,116,105,111,110,32,67,80,85,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,44,32>>,{code,[],[<<116,114,97,99,101,47,51>>]},<<32,101,120,105,116,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,115,116,32,79,83,32,100,111,32,110,111,116,32,115,121,110,99,104,114,111,110,105,122,101,32,116,104,105,115,32,118,97,108,117,101,32,97,99,114,111,115,115,32,99,111,114,101,115,44,32,115,111,32,98,101,32,112,114,101,112,97,114,101,100,32,116,104,97,116,32,116,105,109,101,32,99,97,110,32,115,101,101,109,32,116,111,32,103,111,32,98,97,99,107,119,97,114,100,115,32,119,104,101,110,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,116,105,109,101,32,115,116,97,109,112,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]}]},<<46,32,84,104,105,115,32,102,108,97,103,32,111,118,101,114,114,105,100,101,115,32,102,108,97,103,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,110,32,116,105,109,101,32,115,116,97,109,112,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,105,110,116,101,103,101,114,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<123>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]}]},{code,[],[<<44>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]}]},{code,[],[<<125>>]},<<46,32,84,104,105,115,32,102,108,97,103,32,111,118,101,114,114,105,100,101,115,32,102,108,97,103,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,114,105,116,121>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,105,116,121,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,103,115,125>>]},<<32,105,110,32,99,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,97,110,121,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,105,110,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,114,115,116,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,101,120,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,97,110,121,32,112,114,111,99,101,115,115,32,108,105,110,107,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,105,110,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,114,115,116,32,112,114,111,99,101,115,115,32,108,105,110,107,101,100,32,116,111,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,101,120,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,114,44,32,84,114,97,99,101,114,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,101,114,101,32,116,111,32,115,101,110,100,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32>>,{code,[],[<<84,114,97,99,101,114>>]},<<32,109,117,115,116,32,98,101,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,111,114,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,108,111,99,97,108,32,112,111,114,116,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,114,44,32,84,114,97,99,101,114,77,111,100,117,108,101,44,32,84,114,97,99,101,114,83,116,97,116,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,97,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,105,110,115,116,101,97,100,32,111,102,32,115,101,110,100,105,110,103,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,84,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,99,97,110,32,116,104,101,110,32,105,103,110,111,114,101,32,111,114,32,99,104,97,110,103,101,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,111,110,32,104,111,119,32,116,111,32,119,114,105,116,101,32,97,32,116,114,97,99,101,114,32,109,111,100,117,108,101,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,108,95,116,114,97,99,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,116,114,97,99,101,114,40,51,41>>]}]},<<46>>]}]}]},{p,[],[<<73,102,32,110,111,32>>,{code,[],[<<116,114,97,99,101,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,115,32,97,108,108,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<84,104,101,32,101,102,102,101,99,116,32,111,102,32,99,111,109,98,105,110,105,110,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<32,119,105,116,104,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<32,97,108,111,110,101,46,32,76,105,107,101,119,105,115,101,32,102,111,114,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<32,97,110,100,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<46>>]},{p,[],[<<84,104,101,32,116,114,97,99,105,110,103,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,115,32,116,104,101,32>>,{em,[],[<<116,114,97,99,101,32,109,101,115,115,97,103,101,115>>]},<<32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,108,105,115,116,46,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,32,119,104,105,99,104,32,116,104,101,32,116,114,97,99,101,100,32,101,118,101,110,116,32,104,97,115,32,111,99,99,117,114,114,101,100,46,32,84,104,101,32,116,104,105,114,100,32,116,117,112,108,101,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,97,103,46>>]},{p,[],[<<73,102,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,111,114,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,105,114,115,116,32,116,117,112,108,101,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<116,114,97,99,101,95,116,115>>]},<<32,105,110,115,116,101,97,100,44,32,97,110,100,32,116,104,101,32,116,105,109,101,32,115,116,97,109,112,32,105,115,32,97,100,100,101,100,32,97,115,32,97,110,32,101,120,116,114,97,32,101,108,101,109,101,110,116,32,108,97,115,116,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,116,117,112,108,101,46,32,73,102,32,109,117,108,116,105,112,108,101,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,115,32,97,114,101,32,112,97,115,115,101,100,44,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,104,97,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,119,104,105,99,104,32,105,110,32,116,117,114,110,32,104,97,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<46,32,65,108,108,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,115,32,97,114,101,32,114,101,109,101,109,98,101,114,101,100,44,32,115,111,32,105,102,32,116,119,111,32,97,114,101,32,112,97,115,115,101,100,32,97,110,100,32,116,104,101,32,111,110,101,32,119,105,116,104,32,104,105,103,104,101,115,116,32,112,114,101,99,101,100,101,110,99,101,32,108,97,116,101,114,32,105,115,32,100,105,115,97,98,108,101,100,44,32,116,104,101,32,111,116,104,101,114,32,111,110,101,32,98,101,99,111,109,101,115,32,97,99,116,105,118,101,46>>]},{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,40,97,112,112,108,105,99,97,98,108,101,32,111,110,108,121,32,102,111,114,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<115,101,110,100>>]},<<32,97,110,100,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,105,110,103,41,32,99,111,110,116,97,105,110,115,32,97,32>>,{code,[],[<<123,109,101,115,115,97,103,101,125>>]},<<32,97,99,116,105,111,110,32,102,117,110,99,116,105,111,110,32,119,105,116,104,32,97,32,110,111,110,45,98,111,111,108,101,97,110,32,118,97,108,117,101,44,32,116,104,97,116,32,118,97,108,117,101,32,105,115,32,97,100,100,101,100,32,97,115,32,97,110,32,101,120,116,114,97,32,101,108,101,109,101,110,116,32,116,111,32,116,104,101,32,109,101,115,115,97,103,101,32,116,117,112,108,101,32,101,105,116,104,101,114,32,105,110,32,116,104,101,32,108,97,115,116,32,112,111,115,105,116,105,111,110,32,111,114,32,98,101,102,111,114,101,32,116,104,101,32,116,105,109,101,115,116,97,109,112,32,40,105,102,32,105,116,32,105,115,32,112,114,101,115,101,110,116,41,46>>]},{p,[],[<<84,114,97,99,101,32,109,101,115,115,97,103,101,115,58>>]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115>>}],[]},{dl,[],[{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,115,101,110,100,44,32,77,115,103,44,32,84,111,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,115,101,110,100,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,116,111,32,112,114,111,99,101,115,115,32>>,{code,[],[<<84,111>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115,44,32,77,115,103,44,32,84,111,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,115,101,110,100,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,116,111,32,116,104,101,32,110,111,110,45,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,32>>,{code,[],[<<84,111>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,99,101,105,118,101>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,39,114,101,99,101,105,118,101,39,44,32,77,115,103,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,114,101,99,101,105,118,101,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<46,32,73,102,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,105,109,101,45,111,117,116,44,32,97,32,114,101,99,101,105,118,101,32,115,116,97,116,101,109,101,110,116,32,99,97,110,32,104,97,118,101,32,116,105,109,101,100,32,111,117,116,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,100,32,97,32,109,101,115,115,97,103,101,32,119,105,116,104,32,116,104,101,32,112,97,121,108,111,97,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,99,97,108,108,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,99,97,108,108,115,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32,99,97,108,108,115,32,97,114,101,32,110,101,118,101,114,32,115,117,112,112,108,105,101,100,44,32,111,110,108,121,32,116,104,101,32,99,97,108,108,32,97,110,100,32,105,116,115,32,97,114,103,117,109,101,110,116,115,46>>]},{p,[],[<<84,114,97,99,101,32,102,108,97,103,32>>,{code,[],[<<97,114,105,116,121>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,105,115,32,109,101,115,115,97,103,101,44,32,115,111,32,116,104,97,116,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,114,101,116,117,114,110,95,116,111,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,116,117,114,110,115,32>>,{em,[],[<<116,111>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,98,111,116,104,32,116,104,101,32,102,108,97,103,115,32>>,{code,[],[<<99,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,97,114,101,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,115,101,116,32,116,111,32,98,101,32,116,114,97,99,101,100,32,111,110,32>>,{em,[],[<<108,111,99,97,108>>]},<<32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,104,101,32,109,101,115,115,97,103,101,32,105,115,32,111,110,108,121,32,115,101,110,116,32,119,104,101,110,32,114,101,116,117,114,110,105,110,103,32,102,114,111,109,32,97,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,119,104,101,114,101,32,97,116,32,108,101,97,115,116,32,111,110,101,32,99,97,108,108,32,103,101,110,101,114,97,116,101,100,32,97,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,40,116,104,97,116,32,105,115,44,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,109,97,116,99,104,101,100,44,32,97,110,100,32>>,{code,[],[<<123,109,101,115,115,97,103,101,44,32,102,97,108,115,101,125>>]},<<32,119,97,115,32,110,111,116,32,97,110,32,97,99,116,105,111,110,41,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,114,101,116,117,114,110,95,102,114,111,109,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,44,32,82,101,116,117,114,110,86,97,108,117,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,116,117,114,110,115,32>>,{em,[],[<<102,114,111,109>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,102,108,97,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,119,105,116,104,32,97,32>>,{code,[],[<<114,101,116,117,114,110,95,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<101,120,99,101,112,116,105,111,110,95,116,114,97,99,101>>]},<<32,97,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,99,101,112,116,105,111,110,95,102,114,111,109>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,101,120,99,101,112,116,105,111,110,95,102,114,111,109,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,44,32,123,67,108,97,115,115,44,32,86,97,108,117,101,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,105,116,115,32>>,{em,[],[<<102,114,111,109>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,98,101,99,97,117,115,101,32,111,102,32,97,110,32,101,120,99,101,112,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,102,108,97,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,119,105,116,104,32,97,110,32>>,{code,[],[<<101,120,99,101,112,116,105,111,110,95,116,114,97,99,101>>]},<<32,97,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,115,112,97,119,110,44,32,80,105,100,50,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,115,112,97,119,110,115,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,97,114,103,117,109,101,110,116,32,108,105,115,116,44,32,98,117,116,32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,32,105,102,32,116,104,101,32,115,112,97,119,110,32,105,115,32,101,114,114,111,110,101,111,117,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,115,112,97,119,110,101,100,44,32,80,105,100,50,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,112,97,119,110,101,100,32,98,121,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,97,114,103,117,109,101,110,116,32,108,105,115,116,44,32,98,117,116,32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,32,105,102,32,116,104,101,32,115,112,97,119,110,32,105,115,32,101,114,114,111,110,101,111,117,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,105,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,101,120,105,116,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,114,101,103,105,115,116,101,114,44,32,82,101,103,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,114,101,103,105,115,116,101,114,101,100,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,117,110,114,101,103,105,115,116,101,114,44,32,82,101,103,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,117,110,114,101,103,105,115,116,101,114,101,100,46,32,84,104,105,115,32,105,115,32,100,111,110,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,119,104,101,110,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,101,120,105,116,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,108,105,110,107>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,108,105,110,107,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,108,105,110,107,115,32,116,111,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,108,105,110,107>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,117,110,108,105,110,107,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,109,111,118,101,115,32,116,104,101,32,108,105,110,107,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,103,101,116,116,105,110,103,95,108,105,110,107,101,100,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,108,105,110,107,101,100,32,116,111,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,117,110,108,105,110,107,101,100,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,105,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,101,120,105,116,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,112,101,110>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,111,112,101,110,44,32,80,105,100,44,32,68,114,105,118,101,114,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,111,112,101,110,115,32,97,32,110,101,119,32,112,111,114,116,32>>,{code,[],[<<80,111,114,116>>]},<<32,119,105,116,104,32,116,104,101,32,114,117,110,110,105,110,103,32>>,{code,[],[<<68,114,105,118,101,114>>]},<<46>>]},{p,[],[{code,[],[<<68,114,105,118,101,114>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,100,114,105,118,101,114,32,97,115,32,97,110,32,97,116,111,109,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,108,111,115,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,99,108,111,115,101,100,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,99,108,111,115,101,115,32,119,105,116,104,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,101,120,105,116,105,110,103,95,112,114,111,99>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,105,110,32,124,32,105,110,95,101,120,105,116,105,110,103,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,114,117,110,46,32,84,104,101,32,112,114,111,99,101,115,115,32,114,117,110,115,32,105,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,105,116,121,125>>]},<<46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,105,110,103,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,101,100,95,112,114,111,99>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,111,117,116,32,124,32,111,117,116,95,101,120,105,116,105,110,103,32,124,32,111,117,116,95,101,120,105,116,101,100,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,84,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,114,117,110,110,105,110,103,32,105,110,32,102,117,110,99,116,105,111,110,32,123,77,44,32,70,44,32,65,114,105,116,121,125,46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,111,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,105,110,44,32,67,111,109,109,97,110,100,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,114,117,110,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,116,104,101,32,102,105,114,115,116,32,116,104,105,110,103,32,116,104,101,32,112,111,114,116,32,119,105,108,108,32,101,120,101,99,117,116,101,44,32,105,116,32,99,97,110,32,104,111,119,101,118,101,114,32,114,117,110,32,115,101,118,101,114,97,108,32,99,111,109,109,97,110,100,115,32,98,101,102,111,114,101,32,98,101,105,110,103,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]},{p,[],[<<84,104,101,32,112,111,115,115,105,98,108,101,32,99,111,109,109,97,110,100,115,32,97,114,101,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<99,108,111,115,101>>]},<<44,32>>,{code,[],[<<99,111,109,109,97,110,100>>]},<<44,32>>,{code,[],[<<99,111,110,110,101,99,116>>]},<<44,32>>,{code,[],[<<99,111,110,116,114,111,108>>]},<<44,32>>,{code,[],[<<102,108,117,115,104>>]},<<44,32>>,{code,[],[<<105,110,102,111>>]},<<44,32>>,{code,[],[<<108,105,110,107>>]},<<44,32>>,{code,[],[<<111,112,101,110>>]},<<44,32,97,110,100,32>>,{code,[],[<<117,110,108,105,110,107>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,111,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,111,117,116,44,32,67,111,109,109,97,110,100,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,84,104,101,32,108,97,115,116,32,99,111,109,109,97,110,100,32,114,117,110,32,119,97,115,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,99,111,109,109,97,110,100,115,32,97,115,32>>,{code,[],[<<105,110>>]}]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,105,110,111,114,95,115,116,97,114,116,44,32,73,110,102,111,125>>]}]},{dd,[],[{a,[{id,<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>}],[]},{p,[],[<<83,101,110,116,32,119,104,101,110,32,97,32,121,111,117,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,98,111,117,116,32,116,111,32,98,101,32,115,116,97,114,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,44,32,119,104,101,114,101,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,107,101,121,44,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,105,115,32,116,104,101,32,118,97,108,117,101,46,32,68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,97,110,121,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,107,101,121,115,32,97,114,101,32,100,101,102,105,110,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,117,115,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,98,108,111,99,107,32,117,115,101,100,32,102,111,114,32,115,116,111,114,105,110,103,32,116,104,101,32,104,101,97,112,32,97,110,100,32,116,104,101,32,115,116,97,99,107,46>>]},{dt,[],[{code,[],[<<111,108,100,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,117,115,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,98,108,111,99,107,32,117,115,101,100,32,102,111,114,32,115,116,111,114,105,110,103,32,116,104,101,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,115,116,97,99,107,46>>]},{dt,[],[{code,[],[<<114,101,99,101,110,116,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,116,104,97,116,32,115,117,114,118,105,118,101,100,32,116,104,101,32,112,114,101,118,105,111,117,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{dt,[],[{code,[],[<<109,98,117,102,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,99,111,109,98,105,110,101,100,32,115,105,122,101,32,111,102,32,109,101,115,115,97,103,101,32,98,117,102,102,101,114,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{dt,[],[{code,[],[<<98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,117,110,105,113,117,101,32,111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<98,105,110,95,118,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,98,105,110,97,114,105,101,115,32,97,108,108,111,119,101,100,32,105,110,32,116,104,101,32,118,105,114,116,117,97,108,32,104,101,97,112,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,98,101,102,111,114,101,32,100,111,105,110,103,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{dt,[],[{code,[],[<<98,105,110,95,111,108,100,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,117,110,105,113,117,101,32,111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<98,105,110,95,111,108,100,95,118,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,98,105,110,97,114,105,101,115,32,97,108,108,111,119,101,100,32,105,110,32,116,104,101,32,118,105,114,116,117,97,108,32,111,108,100,32,104,101,97,112,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,98,101,102,111,114,101,32,100,111,105,110,103,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]},{p,[],[<<65,108,108,32,115,105,122,101,115,32,97,114,101,32,105,110,32,119,111,114,100,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<32,105,115,32,114,101,97,99,104,101,100,32,100,117,114,105,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,115,105,122,101,115,32,116,104,97,116,32,116,114,105,103,103,101,114,101,100,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,116,111,32,98,101,32,114,101,97,99,104,101,100,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,105,110,111,114,95,101,110,100,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,121,111,117,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,102,105,110,105,115,104,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,110,101,119,32,115,105,122,101,115,32,97,102,116,101,114,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,106,111,114,95,115,116,97,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,106,111,114,95,115,116,97,114,116,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,98,111,117,116,32,116,111,32,98,101,32,115,116,97,114,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,106,111,114,95,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,106,111,114,95,101,110,100,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,102,105,110,105,115,104,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,110,101,119,32,115,105,122,101,115,32,97,102,116,101,114,32,97,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,116,114,97,99,105,110,103,32,112,114,111,99,101,115,115,47,112,111,114,116,32,100,105,101,115,32,111,114,32,116,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<114,101,109,111,118,101>>]},<<44,32,116,104,101,32,102,108,97,103,115,32,97,114,101,32,115,105,108,101,110,116,108,121,32,114,101,109,111,118,101,100,46>>]},{p,[],[<<69,97,99,104,32,112,114,111,99,101,115,115,32,99,97,110,32,111,110,108,121,32,98,101,32,116,114,97,99,101,100,32,98,121,32,111,110,101,32,116,114,97,99,101,114,46,32,84,104,101,114,101,102,111,114,101,44,32,97,116,116,101,109,112,116,115,32,116,111,32,116,114,97,99,101,32,97,110,32,97,108,114,101,97,100,121,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,102,97,105,108,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,117,109,98,101,114,32,105,110,100,105,99,97,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,109,97,116,99,104,101,100,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<49>>]},<<46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32>>,{code,[],[<<97,108,108>>]},<<32,111,114,32>>,{code,[],[<<101,120,105,115,116,105,110,103>>]},<<44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,114,117,110,110,105,110,103,46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32>>,{code,[],[<<110,101,119>>]},<<44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,97,108,108,32,112,108,97,116,102,111,114,109,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,48,51,54>>,signature => [{attribute,2013,spec,{{erlang,trace,3},[{type,2013,bounded_fun,[{type,2013,'fun',[{type,2013,product,[{var,2013,'PidPortSpec'},{var,2013,'How'},{var,2013,'FlagList'}]},{type,2013,integer,[]}]},[{type,2014,constraint,[{atom,2014,is_subtype},[{var,2014,'PidPortSpec'},{type,2014,union,[{type,2014,pid,[]},{type,2014,port,[]},{atom,2015,all},{atom,2015,processes},{atom,2015,ports},{atom,2016,existing},{atom,2016,existing_processes},{atom,2016,existing_ports},{atom,2017,new},{atom,2017,new_processes},{atom,2017,new_ports}]}]]},{type,2018,constraint,[{atom,2018,is_subtype},[{var,2018,'How'},{type,2018,boolean,[]}]]},{type,2019,constraint,[{atom,2019,is_subtype},[{var,2019,'FlagList'},{type,2019,list,[{user_type,2019,trace_flag,[]}]}]]}]]}]}}]}},{{function,trace_delivered,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2028}],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,100,101,108,105,118,101,114,121,32,111,102,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,40,103,101,110,101,114,97,116,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,107,101,114,110,101,108,58,115,101,113,95,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,113,95,116,114,97,99,101,40,51,41>>]}]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>]}]},<<41,32,105,115,32,100,105,115,108,111,99,97,116,101,100,32,111,110,32,116,104,101,32,116,105,109,101,45,108,105,110,101,32,99,111,109,112,97,114,101,100,32,116,111,32,111,116,104,101,114,32,101,118,101,110,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,102,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,104,97,115,32,112,97,115,115,101,100,32,115,111,109,101,32,115,112,101,99,105,102,105,99,32,112,111,105,110,116,32,105,110,32,105,116,115,32,101,120,101,99,117,116,105,111,110,44,32,97,110,100,32,121,111,117,32,119,97,110,116,32,116,111,32,107,110,111,119,32,119,104,101,110,32,97,116,32,108,101,97,115,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,101,118,101,110,116,115,32,117,112,32,116,111,32,116,104,105,115,32,112,111,105,110,116,32,104,97,118,101,32,114,101,97,99,104,101,100,32,116,104,101,32,116,114,97,99,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<46>>]},{p,[],[<<87,104,101,110,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,116,114,97,99,101,114,32,117,112,32,116,111,32,116,104,101,32,112,111,105,110,116,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,114,101,97,99,104,101,100,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<44,32,116,104,101,110,32,97,32>>,{code,[],[<<123,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,44,32,84,114,97,99,101,101,44,32,82,101,102,125>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,109,101,115,115,97,103,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,105,109,112,108,121,32,116,104,97,116,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46,32,73,110,115,116,101,97,100,32,105,116,32,105,109,112,108,105,101,115,32,116,104,97,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,116,104,97,116,32>>,{em,[],[<<97,114,101,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100>>]},<<32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46,32,73,116,32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,105,115,32,110,111,116,44,32,97,110,100,32,104,97,115,32,110,111,116,32,98,101,101,110,32,116,114,97,99,101,100,32,98,121,32,115,111,109,101,111,110,101,44,32,98,117,116,32,105,102,32,116,104,105,115,32,105,115,32,116,104,101,32,99,97,115,101,44,32>>,{em,[],[<<110,111>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,109,101,115,115,97,103,101,32,97,114,114,105,118,101,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,109,117,115,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,99,117,114,114,101,110,116,108,121,32,111,114,32,112,114,101,118,105,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,114,101,115,105,100,101,115,32,111,110,46,32,84,104,101,32,115,112,101,99,105,97,108,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,97,116,111,109,32>>,{code,[],[<<97,108,108>>]},<<32,100,101,110,111,116,101,115,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,99,117,114,114,101,110,116,108,121,32,97,114,101,32,116,114,97,99,101,100,32,105,110,32,116,104,101,32,110,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,117,115,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,101,114,108,95,116,114,97,99,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<84,114,97,99,101,114,32,77,111,100,117,108,101>>]},<<44,32,97,110,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,105,110,32,116,104,101,32,116,114,97,99,101,32,99,97,108,108,98,97,99,107,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,104,97,118,101,32,114,101,97,99,104,101,100,32,105,116,115,32,114,101,99,105,112,105,101,110,116,32,98,101,102,111,114,101,32,116,104,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]},{p,[],[<<69,120,97,109,112,108,101,58,32,80,114,111,99,101,115,115,32>>,{code,[],[<<65>>]},<<32,105,115,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<44,32,112,111,114,116,32>>,{code,[],[<<66>>]},<<32,105,115,32,116,114,97,99,101,114,44,32,97,110,100,32,112,114,111,99,101,115,115,32>>,{code,[],[<<67>>]},<<32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,111,102,32>>,{code,[],[<<66>>]},<<46,32>>,{code,[],[<<67>>]},<<32,119,97,110,116,115,32,116,111,32,99,108,111,115,101,32>>,{code,[],[<<66>>]},<<32,119,104,101,110,32>>,{code,[],[<<65>>]},<<32,101,120,105,116,115,46,32,84,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,116,114,97,99,101,32,105,115,32,110,111,116,32,116,114,117,110,99,97,116,101,100,44,32>>,{code,[],[<<67>>]},<<32,99,97,110,32,99,97,108,108,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,65,41>>]},<<32,119,104,101,110,32>>,{code,[],[<<65>>]},<<32,101,120,105,116,115,44,32,97,110,100,32,119,97,105,116,32,102,111,114,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,44,32,65,44,32,82,101,102,125>>]},<<32,98,101,102,111,114,101,32,99,108,111,115,105,110,103,32>>,{code,[],[<<66>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,40,100,101,97,100,32,111,114,32,97,108,105,118,101,41,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,114,101,115,105,100,101,115,32,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,54,57,55>>,signature => [{attribute,2028,spec,{{erlang,trace_delivered,1},[{type,2028,bounded_fun,[{type,2028,'fun',[{type,2028,product,[{var,2028,'Tracee'}]},{var,2028,'Ref'}]},[{type,2029,constraint,[{atom,2029,is_subtype},[{var,2029,'Tracee'},{type,2029,union,[{type,2029,pid,[]},{atom,2029,all}]}]]},{type,2030,constraint,[{atom,2030,is_subtype},[{var,2030,'Ref'},{type,2030,reference,[]}]]}]]}]}}]}},{{function,trace_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2035}],[<<116,114,97,99,101,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,102,108,97,103>>}],[]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,105,116,101,109,95,114,101,115,117,108,116>>}],[]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,114,101,116,117,114,110>>}],[]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,114,97,99,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,112,111,114,116,44,32,112,114,111,99,101,115,115,44,32,102,117,110,99,116,105,111,110,44,32,111,114,32,101,118,101,110,116,46>>]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,112,111,114,116,32,111,114,32,112,114,111,99,101,115,115>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<110,101,119>>]},<<44,32>>,{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]},<<44,32,111,114,32>>,{code,[],[<<110,101,119,95,112,111,114,116,115>>]},<<46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<110,101,119>>]},<<32,111,114,32>>,{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]},<<32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,116,114,97,99,101,32,115,116,97,116,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,32,116,111,32,98,101,32,99,114,101,97,116,101,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<110,101,119,95,112,111,114,116,115>>]},<<32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,116,114,97,99,101,32,115,116,97,116,101,32,102,111,114,32,112,111,114,116,115,32,116,111,32,98,101,32,99,114,101,97,116,101,100,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,102,111,114,32,112,111,114,116,115,32,97,110,100,32,112,114,111,99,101,115,115,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,108,97,103,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,116,111,109,115,32,105,110,100,105,99,97,116,105,110,103,32,119,104,97,116,32,107,105,110,100,32,111,102,32,116,114,97,99,101,115,32,105,115,32,101,110,97,98,108,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,108,105,115,116,32,105,115,32,101,109,112,116,121,32,105,102,32,110,111,32,116,114,97,99,101,115,32,97,114,101,32,101,110,97,98,108,101,100,44,32,97,110,100,32,111,110,101,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,115,32,97,116,111,109,115,32,105,102,32,116,114,97,99,101,115,32,97,114,101,32,101,110,97,98,108,101,100,58,32>>,{code,[],[<<115,101,110,100>>]},<<44,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<44,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<44,32>>,{code,[],[<<112,114,111,99,115>>]},<<44,32>>,{code,[],[<<112,111,114,116,115>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103,95,112,114,111,99,115>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103,95,112,111,114,116,115>>]},<<44,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<44,32>>,{code,[],[<<101,120,105,116,105,110,103>>]},<<44,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<44,32,97,110,100,32>>,{code,[],[<<97,114,105,116,121>>]},<<46,32,84,104,101,32,111,114,100,101,114,32,105,115,32,97,114,98,105,116,114,97,114,121,46>>]}]},{dt,[],[{code,[],[<<116,114,97,99,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,102,111,114,32,112,114,111,99,101,115,115,44,32,112,111,114,116,44,32,111,114,32,97,32,116,117,112,108,101,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,97,110,100,32,116,114,97,99,101,114,32,115,116,97,116,101,32,116,114,97,99,105,110,103,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,105,115,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,114,97,99,101,100,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]}]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,102,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<46,32,78,111,32,119,105,108,100,99,97,114,100,115,32,97,114,101,32,97,108,108,111,119,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,111,114,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,116,114,97,99,101,100,46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<44,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32,99,111,100,101,32,116,104,97,116,32,119,105,108,108,32,98,101,32,108,111,97,100,101,100,46>>]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,102,111,114,32,102,117,110,99,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,97,99,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,114,97,99,101,100,32,111,110,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,114,97,99,101,100,32,111,110,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,40,116,104,97,116,32,105,115,44,32,108,111,99,97,108,32,97,110,100,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,41,44,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,108,111,99,97,108,32,111,114,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,110,111,116,32,116,114,97,99,101,100,46>>]}]},{dt,[],[{code,[],[<<109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,108,111,99,97,108,108,121,32,111,114,32,103,108,111,98,97,108,108,121,32,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,101,102,105,110,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,101,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,116,97,45,116,114,97,99,101,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,44,32,112,111,114,116,44,32,111,114,32,116,114,97,99,101,32,109,111,100,117,108,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,109,101,116,97,45,116,114,97,99,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,109,101,116,97,45,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,111,110,99,101,32,100,101,116,101,99,116,101,100,32,116,104,97,116,32,116,104,101,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,32,105,115,32,105,110,118,97,108,105,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,101,116,97,95,109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,116,97,45,116,114,97,99,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,109,101,116,97,45,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,101,102,105,110,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,97,108,108,32,99,111,117,110,116,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,116,104,101,32,112,115,101,117,100,111,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,105,102,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,97,108,108,32,116,105,109,101,32,118,97,108,117,101,115,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,116,104,101,32,112,115,101,117,100,111,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,105,102,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,99,97,108,108,32,116,105,109,101,32,118,97,108,117,101,115,32,114,101,116,117,114,110,101,100,44,32>>,{code,[],[<<91,123,80,105,100,44,32,67,111,117,110,116,44,32,83,44,32,85,115,125,93>>]},<<44,32,105,115,32,97,32,108,105,115,116,32,111,102,32,101,97,99,104,32,112,114,111,99,101,115,115,32,116,104,97,116,32,101,120,101,99,117,116,101,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,110,100,32,105,116,115,32,115,112,101,99,105,102,105,99,32,99,111,117,110,116,101,114,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32>>,{code,[],[<<123,73,116,101,109,44,32,86,97,108,117,101,125>>]},<<32,116,117,112,108,101,115,32,102,111,114,32,97,108,108,32,111,116,104,101,114,32,105,116,101,109,115,44,32,111,114,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,110,111,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]}]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,110,32,101,118,101,110,116>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<115,101,110,100>>]},<<32,111,114,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<46>>]},{p,[],[<<79,110,101,32,118,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,102,111,114,32,101,118,101,110,116,115,32,101,120,105,115,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,101,118,101,110,116,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,44,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,101,116,46>>]}]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,73,116,101,109,44,32,86,97,108,117,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46,32,73,102,32,97,32,112,105,100,32,102,111,114,32,97,32,100,101,97,100,32,112,114,111,99,101,115,115,32,119,97,115,32,115,112,101,99,105,102,105,101,100,44,32,111,114,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,110,111,110,45,101,120,105,115,116,105,110,103,32,102,117,110,99,116,105,111,110,44,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,55,53,50>>,signature => [{attribute,2035,spec,{{erlang,trace_info,2},[{type,2035,bounded_fun,[{type,2035,'fun',[{type,2035,product,[{var,2035,'PidPortFuncEvent'},{var,2035,'Item'}]},{var,2035,'Res'}]},[{type,2036,constraint,[{atom,2036,is_subtype},[{var,2036,'PidPortFuncEvent'},{type,2036,union,[{type,2036,pid,[]},{type,2036,port,[]},{atom,2036,new},{atom,2036,new_processes},{atom,2036,new_ports},{type,2037,tuple,[{var,2037,'Module'},{var,2037,'Function'},{var,2037,'Arity'}]},{atom,2037,on_load},{atom,2037,send},{atom,2037,'receive'}]}]]},{type,2038,constraint,[{atom,2038,is_subtype},[{var,2038,'Module'},{type,2038,module,[]}]]},{type,2039,constraint,[{atom,2039,is_subtype},[{var,2039,'Function'},{type,2039,atom,[]}]]},{type,2040,constraint,[{atom,2040,is_subtype},[{var,2040,'Arity'},{type,2040,arity,[]}]]},{type,2041,constraint,[{atom,2041,is_subtype},[{var,2041,'Item'},{type,2041,union,[{atom,2041,flags},{atom,2041,tracer},{atom,2041,traced},{atom,2041,match_spec},{atom,2042,meta},{atom,2042,meta_match_spec},{atom,2042,call_count},{atom,2042,call_time},{atom,2042,all}]}]]},{type,2043,constraint,[{atom,2043,is_subtype},[{var,2043,'Res'},{user_type,2043,trace_info_return,[]}]]}]]}]}}]}},{{function,trace_pattern,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2705}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,109,102,97>>}],[]}]},{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,69,118,101,110,116,44,32,77,97,116,99,104,83,112,101,99,44,32,91,93,41>>]}]},<<44,32,114,101,116,97,105,110,101,100,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,56,56>>,signature => [{attribute,2705,spec,{{erlang,trace_pattern,2},[{type,2705,bounded_fun,[{type,2705,'fun',[{type,2705,product,[{var,2705,'MFA'},{var,2705,'MatchSpec'}]},{type,2705,non_neg_integer,[]}]},[{type,2706,constraint,[{atom,2706,is_subtype},[{var,2706,'MFA'},{type,2706,union,[{user_type,2706,trace_pattern_mfa,[]},{atom,2706,send},{atom,2706,'receive'}]}]]},{type,2707,constraint,[{atom,2707,is_subtype},[{var,2707,'MatchSpec'},{type,2707,union,[{ann_type,2707,[{var,2707,'MatchSpecList'},{user_type,2707,trace_match_spec,[]}]},{type,2708,boolean,[]},{atom,2709,restart},{atom,2710,pause}]}]]}]]}]}}]}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2725}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<83,101,116,115,32,116,114,97,99,101,32,112,97,116,116,101,114,110,32,102,111,114,32>>,{em,[],[<<109,101,115,115,97,103,101,32,115,101,110,100,105,110,103>>]},<<46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46,32,66,121,32,100,101,102,97,117,108,116,32,97,108,108,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,102,114,111,109,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,116,114,97,99,101,100,46,32,84,111,32,108,105,109,105,116,32,116,114,97,99,101,100,32,115,101,110,100,32,101,118,101,110,116,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,109,101,115,115,97,103,101,32,99,111,110,116,101,110,116,44,32,116,104,101,32,115,101,110,100,101,114,32,97,110,100,47,111,114,32,116,104,101,32,114,101,99,101,105,118,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,100,111,110,101,32,111,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<91,82,101,99,101,105,118,101,114,44,32,77,115,103,93>>]},<<46,32>>,{code,[],[<<82,101,99,101,105,118,101,114>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,116,121,32,111,102,32,116,104,101,32,114,101,99,101,105,118,101,114,32,97,110,100,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,46,32,84,104,101,32,112,105,100,32,111,102,32,116,104,101,32,115,101,110,100,105,110,103,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,97,99,99,101,115,115,101,100,32,119,105,116,104,32,116,104,101,32,103,117,97,114,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<115,101,108,102,47,48>>]},<<46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,115,101,110,116,32,109,101,115,115,97,103,101,115,32,40,102,114,111,109,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,41,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,115,101,110,116,32,109,101,115,115,97,103,101,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]}]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<91,93>>]},<<32,102,111,114,32,115,101,110,100,32,116,114,97,99,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<49>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,116,111,32,97,32,115,112,101,99,105,102,105,99,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,80,105,100,44,32,39,95,39,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,109,97,116,99,104,105,110,103,32>>,{code,[],[<<123,114,101,112,108,121,44,32,95,125>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,95,39,44,32,123,114,101,112,108,121,44,39,95,39,125,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,116,111,32,116,104,101,32,115,101,110,100,101,114,32,105,116,115,101,108,102,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,36,49,39,44,32,39,95,39,93,44,91,123,39,61,58,61,39,44,39,36,49,39,44,123,115,101,108,102,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,116,111,32,111,116,104,101,114,32,110,111,100,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,36,49,39,44,32,39,95,39,93,44,91,123,39,61,47,61,39,44,123,110,111,100,101,44,39,36,49,39,125,44,123,110,111,100,101,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,32,99,97,110,32,117,115,101,32,97,108,108,32,103,117,97,114,100,32,97,110,100,32,98,111,100,121,32,102,117,110,99,116,105,111,110,115,32,101,120,99,101,112,116,32>>,{code,[],[<<99,97,108,108,101,114>>]},<<46>>]}]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,57,48,54>>,signature => [{attribute,2725,spec,{{erlang,trace_pattern,3},[{type,2725,bounded_fun,[{type,2725,'fun',[{type,2725,product,[{atom,2725,send},{var,2725,'MatchSpec'},{type,2725,nil,[]}]},{type,2725,non_neg_integer,[]}]},[{type,2726,constraint,[{atom,2726,is_subtype},[{var,2726,'MatchSpec'},{type,2726,union,[{ann_type,2726,[{var,2726,'MatchSpecList'},{user_type,2726,trace_match_spec,[]}]},{type,2727,boolean,[]}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2725}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<83,101,116,115,32,116,114,97,99,101,32,112,97,116,116,101,114,110,32,102,111,114,32>>,{em,[],[<<109,101,115,115,97,103,101,32,114,101,99,101,105,118,105,110,103>>]},<<46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46,32,66,121,32,100,101,102,97,117,108,116,32,97,108,108,32,109,101,115,115,97,103,101,115,32,114,101,99,101,105,118,101,100,32,98,121,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,116,114,97,99,101,100,46,32,84,111,32,108,105,109,105,116,32,116,114,97,99,101,100,32,114,101,99,101,105,118,101,32,101,118,101,110,116,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,109,101,115,115,97,103,101,32,99,111,110,116,101,110,116,44,32,116,104,101,32,115,101,110,100,101,114,32,97,110,100,47,111,114,32,116,104,101,32,114,101,99,101,105,118,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,100,111,110,101,32,111,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<91,78,111,100,101,44,32,83,101,110,100,101,114,44,32,77,115,103,93>>]},<<46,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,111,102,32,116,104,101,32,115,101,110,100,101,114,46,32>>,{code,[],[<<83,101,110,100,101,114>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,116,121,32,111,102,32,116,104,101,32,115,101,110,100,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,115,101,110,100,101,114,32,105,115,32,110,111,116,32,107,110,111,119,110,32,40,119,104,105,99,104,32,99,97,110,32,98,101,32,116,104,101,32,99,97,115,101,32,102,111,114,32,114,101,109,111,116,101,32,115,101,110,100,101,114,115,41,46,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,46,32,84,104,101,32,112,105,100,32,111,102,32,116,104,101,32,114,101,99,101,105,118,105,110,103,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,97,99,99,101,115,115,101,100,32,119,105,116,104,32,116,104,101,32,103,117,97,114,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<115,101,108,102,47,48>>]},<<46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,32,40,116,111,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,41,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]}]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<91,93>>]},<<32,102,111,114,32,114,101,99,101,105,118,101,32,116,114,97,99,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<49>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,102,114,111,109,32,97,32,115,112,101,99,105,102,105,99,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,95,39,44,80,105,100,44,32,39,95,39,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,109,97,116,99,104,105,110,103,32>>,{code,[],[<<123,114,101,112,108,121,44,32,95,125>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,95,39,44,39,95,39,44,32,123,114,101,112,108,121,44,39,95,39,125,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,102,114,111,109,32,111,116,104,101,114,32,110,111,100,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,36,49,39,44,32,39,95,39,44,32,39,95,39,93,44,91,123,39,61,47,61,39,44,39,36,49,39,44,123,110,111,100,101,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,32,99,97,110,32,117,115,101,32,97,108,108,32,103,117,97,114,100,32,97,110,100,32,98,111,100,121,32,102,117,110,99,116,105,111,110,115,32,101,120,99,101,112,116,32>>,{code,[],[<<99,97,108,108,101,114>>]},<<44,32>>,{code,[],[<<105,115,95,115,101,113,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<103,101,116,95,115,101,113,95,116,111,107,101,110>>]},<<44,32>>,{code,[],[<<115,101,116,95,115,101,113,95,116,111,107,101,110>>]},<<44,32>>,{code,[],[<<101,110,97,98,108,101,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<100,105,115,97,98,108,101,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<116,114,97,99,101>>]},<<44,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,114,111,99,101,115,115,95,100,117,109,112>>]},<<46>>]}]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,57,57,51>>,signature => [{attribute,2725,spec,{{erlang,trace_pattern,3},[{type,2728,bounded_fun,[{type,2728,'fun',[{type,2728,product,[{atom,2728,'receive'},{var,2728,'MatchSpec'},{type,2728,nil,[]}]},{type,2728,non_neg_integer,[]}]},[{type,2729,constraint,[{atom,2729,is_subtype},[{var,2729,'MatchSpec'},{type,2729,union,[{ann_type,2729,[{var,2729,'MatchSpecList'},{user_type,2729,trace_match_spec,[]}]},{type,2730,boolean,[]}]}]]}]]}]}}],since => <<79,84,80,32,49,57,46,48>>}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2725}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,102,108,97,103>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,109,102,97>>}],[]}]},{p,[],[<<69,110,97,98,108,101,115,32,111,114,32,100,105,115,97,98,108,101,115,32>>,{em,[],[<<99,97,108,108,32,116,114,97,99,105,110,103>>]},<<32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,102,117,110,99,116,105,111,110,115,46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<67,111,110,99,101,112,116,117,97,108,108,121,44,32,99,97,108,108,32,116,114,97,99,105,110,103,32,119,111,114,107,115,32,97,115,32,102,111,108,108,111,119,115,46,32,73,110,115,105,100,101,32,116,104,101,32,69,114,108,97,110,103,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,44,32,97,32,115,101,116,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,97,32,115,101,116,32,111,102,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,116,111,32,98,101,32,116,114,97,99,101,100,46,32,73,102,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,99,97,108,108,115,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,44,32,116,104,101,32,116,114,97,99,101,32,97,99,116,105,111,110,32,105,115,32,116,97,107,101,110,46,32,79,116,104,101,114,119,105,115,101,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46>>]},{p,[],[<<84,111,32,97,100,100,32,111,114,32,114,101,109,111,118,101,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,32,116,111,32,116,104,101,32,115,101,116,32,111,102,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<46>>]},{p,[],[<<84,111,32,97,100,100,32,111,114,32,114,101,109,111,118,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,116,104,101,32,115,101,116,32,111,102,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,115,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<84,104,101,32,66,73,70,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<32,99,97,110,32,97,108,115,111,32,97,100,100,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,32,116,111,32,97,32,102,117,110,99,116,105,111,110,46,32,65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,99,111,109,112,114,105,115,101,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,114,103,117,109,101,110,116,115,32,109,117,115,116,32,109,97,116,99,104,44,32,97,32,103,117,97,114,100,32,101,120,112,114,101,115,115,105,111,110,32,116,104,97,116,32,109,117,115,116,32,101,118,97,108,117,97,116,101,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,97,110,100,32,97,110,32,97,99,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,97,99,116,105,111,110,32,105,115,32,116,111,32,115,101,110,100,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,111,114,32,116,104,101,32,103,117,97,114,100,32,102,97,105,108,115,44,32,116,104,101,32,97,99,116,105,111,110,32,105,115,32,110,111,116,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,116,117,112,108,101,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,46,32,73,116,32,99,97,110,32,98,101,32,116,104,101,32,109,111,100,117,108,101,44,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,97,114,105,116,121,32,102,111,114,32,97,32,102,117,110,99,116,105,111,110,32,40,111,114,32,97,32,66,73,70,32,105,110,32,97,110,121,32,109,111,100,117,108,101,41,46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<39,95,39>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,32,119,105,108,100,99,97,114,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,119,97,121,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,111,102,32,97,110,121,32,97,114,105,116,121,32,110,97,109,101,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,77,111,100,117,108,101,44,39,95,39,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,39,95,39,44,39,95,39,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,97,108,108,32,108,111,97,100,101,100,32,109,111,100,117,108,101,115,46>>]}]}]},{p,[],[<<79,116,104,101,114,32,99,111,109,98,105,110,97,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,39,95,39,44,65,114,105,116,121,125>>]},<<44,32,97,114,101,32,110,111,116,32,97,108,108,111,119,101,100,46,32,76,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,119,105,108,100,99,97,114,100,115,32,111,110,108,121,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,105,115,32,105,110,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<46>>]},{p,[],[<<73,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<44,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,110,100,32,102,108,97,103,32,108,105,115,116,32,97,114,101,32,117,115,101,100,32,111,110,32,97,108,108,32,109,111,100,117,108,101,115,32,116,104,97,116,32,97,114,101,32,110,101,119,108,121,32,108,111,97,100,101,100,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]},{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,97,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<114,101,115,116,97,114,116>>]}]},{dd,[],[{p,[],[<<70,111,114,32,116,104,101,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<99,97,108,108,95,116,105,109,101>>]},<<58,32,114,101,115,116,97,114,116,115,32,116,104,101,32,101,120,105,115,116,105,110,103,32,99,111,117,110,116,101,114,115,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32,111,116,104,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<112,97,117,115,101>>]}]},{dd,[],[{p,[],[<<70,111,114,32,116,104,101,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<99,97,108,108,95,116,105,109,101>>]},<<58,32,112,97,117,115,101,115,32,116,104,101,32,101,120,105,115,116,105,110,103,32,99,111,117,110,116,101,114,115,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32,111,116,104,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,46>>]}]}]},{p,[],[<<80,97,114,97,109,101,116,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,118,97,108,105,100,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,99,97,108,108,32,116,114,97,99,105,110,103,32,102,111,114,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,40,116,104,97,116,32,105,115,44,32,99,97,108,108,115,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,109,111,100,117,108,101,32,101,120,112,108,105,99,105,116,108,121,41,46,32,79,110,108,121,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,97,110,100,32,111,110,108,121,32,103,108,111,98,97,108,32,99,97,108,108,115,32,103,101,110,101,114,97,116,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,99,97,108,108,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,119,104,101,110,101,118,101,114,32,97,110,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,44,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,104,111,119,32,116,104,101,121,32,97,114,101,32,99,97,108,108,101,100,46,32,73,102,32,102,108,97,103,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,105,115,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,97,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,97,108,115,111,32,115,101,110,116,32,119,104,101,110,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46>>]}]},{dt,[],[{code,[],[<<109,101,116,97,32,124,32,123,109,101,116,97,44,32,80,105,100,125,32,124,32,123,109,101,116,97,44,32,84,114,97,99,101,114,77,111,100,117,108,101,44,32,84,114,97,99,101,114,83,116,97,116,101,125>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,109,101,116,97,45,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,116,111,32,116,104,101,32,116,114,97,99,101,114,32,119,104,101,110,101,118,101,114,32,97,110,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,46,32,73,102,32,110,111,32,116,114,97,99,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,97,32,100,101,102,97,117,108,116,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<77,101,116,97,45,116,114,97,99,105,110,103,32,116,114,97,99,101,115,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,100,111,101,115,32,110,111,116,32,99,97,114,101,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,116,114,97,99,101,32,102,108,97,103,115,32,115,101,116,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]},<<44,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,97,114,101,32,105,110,115,116,101,97,100,32,102,105,120,101,100,32,116,111,32>>,{code,[],[<<91,99,97,108,108,44,32,116,105,109,101,115,116,97,109,112,93>>]},<<46>>]},{p,[],[<<84,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,114,101,116,117,114,110,95,116,114,97,99,101,125>>]},<<32,119,111,114,107,115,32,119,105,116,104,32,109,101,116,97,45,116,114,97,99,101,32,97,110,100,32,115,101,110,100,115,32,105,116,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,116,111,32,116,104,101,32,115,97,109,101,32,116,114,97,99,101,114,46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,115,116,111,112,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,102,97,108,115,101>>]},<<41,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,70,111,114,32,101,118,101,114,121,32,102,117,110,99,116,105,111,110,44,32,97,32,99,111,117,110,116,101,114,32,105,115,32,105,110,99,114,101,109,101,110,116,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,44,32,105,110,32,97,110,121,32,112,114,111,99,101,115,115,46,32,78,111,32,112,114,111,99,101,115,115,32,116,114,97,99,101,32,102,108,97,103,115,32,110,101,101,100,32,116,111,32,98,101,32,97,99,116,105,118,97,116,101,100,46>>]},{p,[],[<<73,102,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,105,115,32,115,116,97,114,116,101,100,32,119,104,105,108,101,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,44,32,116,104,101,32,99,111,117,110,116,32,105,115,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,46,32,84,111,32,112,97,117,115,101,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,44,32,117,115,101,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,112,97,117,115,101>>]},<<46,32,80,97,117,115,101,100,32,97,110,100,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,32,99,97,110,32,98,101,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,32,119,105,116,104,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,114,101,115,116,97,114,116>>]},<<46>>]},{p,[],[<<84,111,32,114,101,97,100,32,116,104,101,32,99,111,117,110,116,101,114,32,118,97,108,117,101,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,115,116,111,112,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,102,97,108,115,101>>]},<<41,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,70,111,114,32,101,118,101,114,121,32,102,117,110,99,116,105,111,110,44,32,97,32,99,111,117,110,116,101,114,32,105,115,32,105,110,99,114,101,109,101,110,116,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,46,32,84,105,109,101,32,115,112,101,110,116,32,105,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,97,99,99,117,109,117,108,97,116,101,100,32,105,110,32,116,119,111,32,111,116,104,101,114,32,99,111,117,110,116,101,114,115,44,32,115,101,99,111,110,100,115,32,97,110,100,32,109,105,99,114,111,115,101,99,111,110,100,115,46,32,84,104,101,32,99,111,117,110,116,101,114,115,32,97,114,101,32,115,116,111,114,101,100,32,102,111,114,32,101,97,99,104,32,99,97,108,108,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,105,115,32,115,116,97,114,116,101,100,32,119,104,105,108,101,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,44,32,116,104,101,32,99,111,117,110,116,32,97,110,100,32,116,105,109,101,32,114,101,115,116,97,114,116,32,102,114,111,109,32,122,101,114,111,46,32,84,111,32,112,97,117,115,101,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,44,32,117,115,101,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,112,97,117,115,101>>]},<<46,32,80,97,117,115,101,100,32,97,110,100,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,32,99,97,110,32,98,101,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,32,119,105,116,104,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,114,101,115,116,97,114,116>>]},<<46>>]},{p,[],[<<84,111,32,114,101,97,100,32,116,104,101,32,99,111,117,110,116,101,114,32,118,97,108,117,101,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,44,32,97,110,100,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,40,105,102,32,110,111,32,111,112,116,105,111,110,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,41,46,32,84,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<109,101,116,97>>]},<<32,112,101,114,102,111,114,109,32,97,32,107,105,110,100,32,111,102,32,108,111,99,97,108,32,116,114,97,99,105,110,103,44,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<46,32,65,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,103,108,111,98,97,108,108,121,32,111,114,32,108,111,99,97,108,108,121,32,116,114,97,99,101,100,46,32,73,102,32,103,108,111,98,97,108,32,116,114,97,99,105,110,103,32,105,115,32,115,112,101,99,105,102,105,101,100,32,102,111,114,32,97,32,115,101,116,32,111,102,32,102,117,110,99,116,105,111,110,115,44,32,116,104,101,110,32,108,111,99,97,108,44,32,109,101,116,97,44,32,99,97,108,108,32,116,105,109,101,44,32,97,110,100,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,101,116,32,111,102,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,105,115,32,100,105,115,97,98,108,101,100,44,32,97,110,100,32,99,111,110,118,101,114,115,101,108,121,46>>]},{p,[],[<<87,104,101,110,32,100,105,115,97,98,108,105,110,103,32,116,114,97,99,101,44,32,116,104,101,32,111,112,116,105,111,110,32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,116,121,112,101,32,111,102,32,116,114,97,99,101,32,115,101,116,32,111,110,32,116,104,101,32,102,117,110,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,108,111,99,97,108,32,116,114,97,99,105,110,103,32,109,117,115,116,32,98,101,32,100,105,115,97,98,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,97,110,100,32,103,108,111,98,97,108,32,116,114,97,99,105,110,103,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,40,111,114,32,110,111,32,111,112,116,105,111,110,41,44,32,97,110,100,32,115,111,32,111,110,46>>]},{p,[],[<<80,97,114,116,32,111,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,108,105,115,116,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,100,105,114,101,99,116,108,121,46,32,73,102,32,97,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,105,116,32,99,97,110,32,98,101,32,114,101,112,108,97,99,101,100,32,119,105,116,104,32,97,32,110,101,119,32,111,110,101,46,32,84,111,32,99,104,97,110,103,101,32,97,110,32,101,120,105,115,116,105,110,103,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,117,115,101,32,116,104,101,32,66,73,70,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<32,116,111,32,114,101,116,114,105,101,118,101,32,116,104,101,32,101,120,105,115,116,105,110,103,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,105,110,103,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<46,32,84,104,105,115,32,105,115,32,122,101,114,111,32,105,102,32,110,111,110,101,32,109,97,116,99,104,101,100,46>>]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,48,56,49>>,signature => [{attribute,2725,spec,{{erlang,trace_pattern,3},[{type,2731,bounded_fun,[{type,2731,'fun',[{type,2731,product,[{var,2731,'MFA'},{var,2731,'MatchSpec'},{var,2731,'FlagList'}]},{type,2731,non_neg_integer,[]}]},[{type,2732,constraint,[{atom,2732,is_subtype},[{var,2732,'MFA'},{user_type,2732,trace_pattern_mfa,[]}]]},{type,2733,constraint,[{atom,2733,is_subtype},[{var,2733,'MatchSpec'},{type,2733,union,[{ann_type,2733,[{var,2733,'MatchSpecList'},{user_type,2733,trace_match_spec,[]}]},{type,2734,boolean,[]},{atom,2735,restart},{atom,2736,pause}]}]]},{type,2737,constraint,[{atom,2737,is_subtype},[{var,2737,'FlagList'},{type,2737,list,[{user_type,2737,trace_pattern_flag,[]}]}]]}]]}]}}]}},{{function,trunc,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2049}],[<<116,114,117,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,117,110,99,97,116,101,115,32,116,104,101,32,100,101,99,105,109,97,108,115,32,111,102,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,53,46,55,41,46,10,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,45,53,46,55,41,46,10,45,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,53,41,46,10,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41,46,10,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<116,114,117,110,99,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,116,104,97,116,32,116,104,101,32,110,117,109,98,101,114,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,73,110,115,116,101,97,100,44,32,116,104,101,32,102,108,111,97,116,32,108,105,116,101,114,97,108,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56,46,48>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,99,108,111,115,101,115,116,32,110,117,109,98,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,50,56,56>>,signature => [{attribute,2049,spec,{{trunc,1},[{type,2049,bounded_fun,[{type,2049,'fun',[{type,2049,product,[{var,2049,'Number'}]},{type,2049,integer,[]}]},[{type,2050,constraint,[{atom,2050,is_subtype},[{var,2050,'Number'},{type,2050,number,[]}]]}]]}]}}]}},{{function,tuple_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2056}],[<<116,117,112,108,101,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<84,117,112,108,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,117,112,108,101,95,115,105,122,101,40,123,109,111,114,110,105,44,32,109,117,108,108,101,44,32,98,119,97,110,103,101,125,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,49,57>>,signature => [{attribute,2056,spec,{{tuple_size,1},[{type,2056,bounded_fun,[{type,2056,'fun',[{type,2056,product,[{var,2056,'Tuple'}]},{type,2056,non_neg_integer,[]}]},[{type,2057,constraint,[{atom,2057,is_subtype},[{var,2057,'Tuple'},{type,2057,tuple,any}]]}]]}]}}]}},{{function,tuple_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2747}],[<<116,117,112,108,101,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,117,112,108,101>>]},<<46,32>>,{code,[],[<<84,117,112,108,101>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,115,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,117,112,108,101,95,116,111,95,108,105,115,116,40,123,115,104,97,114,101,44,32,123,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,125,125,41,46,10,91,115,104,97,114,101,44,123,39,69,114,105,99,115,115,111,110,95,66,39,44,49,54,51,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,51,50>>,signature => [{attribute,2747,spec,{{tuple_to_list,1},[{type,2747,bounded_fun,[{type,2747,'fun',[{type,2747,product,[{var,2747,'Tuple'}]},{type,2747,list,[{type,2747,term,[]}]}]},[{type,2748,constraint,[{atom,2748,is_subtype},[{var,2748,'Tuple'},{type,2748,tuple,any}]]}]]}]}}]}},{{function,unalias,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,766}],[<<117,110,97,108,105,97,115,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,32>>,{code,[],[<<65,108,105,97,115>>]},<<32,112,114,101,118,105,111,117,115,108,121,32,99,114,101,97,116,101,100,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,65,110,32,97,108,105,97,115,32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,98,101,32,99,114,101,97,116,101,100,32,118,105,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,108,105,97,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,108,105,97,115,47,48>>]}]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,51>>]}]},<<46,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<32,119,105,108,108,32,97,108,119,97,121,115,32,100,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,111,112,116,105,111,110,115,32,117,115,101,100,32,119,104,101,110,32,99,114,101,97,116,105,110,103,32,116,104,101,32,97,108,105,97,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,114,117,101,32,105,102,32>>,{code,[],[<<65,108,105,97,115>>]},<<32,119,97,115,32,97,32,99,117,114,114,101,110,116,108,121,32,97,99,116,105,118,101,32,97,108,105,97,115,32,102,111,114,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,101,115,59,32,111,116,104,101,114,119,105,115,101,44,32,102,97,108,115,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,52,53>>,signature => [{attribute,766,spec,{{unalias,1},[{type,766,bounded_fun,[{type,766,'fun',[{type,766,product,[{var,766,'Alias'}]},{type,766,boolean,[]}]},[{type,767,constraint,[{atom,767,is_subtype},[{var,767,'Alias'},{type,767,reference,[]}]]}]]}]}}],since => <<79,84,80,32,64,79,84,80,45,49,54,55,49,56,64>>}},{{function,unique_integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1529}],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,48>>],#{<<101,110>> => [{p,[],[<<71,101,110,101,114,97,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,97,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<105,110,116,101,103,101,114,32,117,110,105,113,117,101,32,111,110,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101>>]},<<46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,93,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,54,53>>,signature => [{attribute,1529,spec,{{erlang,unique_integer,0},[{type,1529,'fun',[{type,1529,product,[]},{type,1529,integer,[]}]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,unique_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1522}],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<71,101,110,101,114,97,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,97,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<105,110,116,101,103,101,114,32,117,110,105,113,117,101,32,111,110,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101>>]},<<46,32,84,104,101,32,105,110,116,101,103,101,114,32,105,115,32,117,110,105,113,117,101,32,105,110,32,116,104,101,32,115,101,110,115,101,32,116,104,97,116,32,116,104,105,115,32,66,73,70,44,32,117,115,105,110,103,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,109,111,100,105,102,105,101,114,115,44,32,100,111,101,115,32,110,111,116,32,114,101,116,117,114,110,32,116,104,101,32,115,97,109,101,32,105,110,116,101,103,101,114,32,109,111,114,101,32,116,104,97,110,32,111,110,99,101,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,69,97,99,104,32,105,110,116,101,103,101,114,32,118,97,108,117,101,32,99,97,110,32,111,102,32,99,111,117,114,115,101,32,98,101,32,99,111,110,115,116,114,117,99,116,101,100,32,98,121,32,111,116,104,101,114,32,109,101,97,110,115,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,119,104,101,110,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,112,97,115,115,101,100,32,97,115,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<44,32,98,111,116,104,32,110,101,103,97,116,105,118,101,32,97,110,100,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,115,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,116,111,32,117,115,101,32,116,104,101,32,114,97,110,103,101,32,111,102,32,105,110,116,101,103,101,114,115,32,116,104,97,116,32,100,111,32,110,111,116,32,110,101,101,100,32,104,101,97,112,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,46,32,66,121,32,100,101,102,97,117,108,116,32,116,104,101,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,32,97,114,101,32,97,108,115,111,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,117,110,105,113,117,101,44,32,116,104,97,116,32,105,115,44,32,97,110,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,32,99,97,110,32,98,101,32,115,109,97,108,108,101,114,32,111,114,32,108,97,114,103,101,114,32,116,104,97,110,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,46>>]},{p,[],[{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,58>>]},{dl,[],[{dt,[],[<<112,111,115,105,116,105,118,101>>]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,111,110,108,121,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,98,121,32,112,97,115,115,105,110,103,32,116,104,101,32>>,{code,[],[<<112,111,115,105,116,105,118,101>>]},<<32,109,111,100,105,102,105,101,114,32,121,111,117,32,119,105,108,108,32,103,101,116,32,104,101,97,112,32,97,108,108,111,99,97,116,101,100,32,105,110,116,101,103,101,114,115,32,40,98,105,103,110,117,109,115,41,32,113,117,105,99,107,101,114,46>>]}]},{dt,[],[<<109,111,110,111,116,111,110,105,99>>]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,116,114,105,99,116,108,121,95,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,99,114,101,97,116,105,111,110,32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,105,110,116,101,103,101,114,32,114,101,116,117,114,110,101,100,32,105,115,32,97,108,119,97,121,115,32,108,97,114,103,101,114,32,116,104,97,110,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<84,104,101,115,101,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,101,118,101,110,116,115,32,111,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,97,116,32,105,115,44,32,105,102,32,98,111,116,104,32>>,{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,97,110,100,32>>,{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,97,114,101,32,101,120,101,99,117,116,101,100,32,98,121,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,32,40,111,114,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,41,32,111,110,32,116,104,101,32,115,97,109,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,97,110,100,32>>,{code,[],[<<88,32,60,32,89>>]},<<44,32,119,101,32,107,110,111,119,32,116,104,97,116,32>>,{code,[],[<<88>>]},<<32,119,97,115,32,99,114,101,97,116,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<89>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<83,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,32,97,114,101,32,105,110,104,101,114,101,110,116,108,121,32,113,117,105,116,101,32,101,120,112,101,110,115,105,118,101,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,100,32,115,99,97,108,101,115,32,112,111,111,114,108,121,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,118,97,108,117,101,115,32,110,101,101,100,32,116,111,32,98,101,32,115,121,110,99,104,114,111,110,105,122,101,100,32,98,101,116,119,101,101,110,32,67,80,85,32,99,111,114,101,115,46,32,84,104,97,116,32,105,115,44,32,100,111,32,110,111,116,32,112,97,115,115,32,116,104,101,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99>>]},<<32,109,111,100,105,102,105,101,114,32,117,110,108,101,115,115,32,121,111,117,32,114,101,97,108,108,121,32,110,101,101,100,32,115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,46>>]}]}]}]},{p,[],[<<65,108,108,32,118,97,108,105,100,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,46,32,82,101,112,101,97,116,101,100,32,40,118,97,108,105,100,41,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32,105,110,32,116,104,101,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<32,97,114,101,32,105,103,110,111,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,115,101,116,32,111,102,32,105,110,116,101,103,101,114,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>]},<<32,117,115,105,110,103,32,100,105,102,102,101,114,101,110,116,32,115,101,116,115,32,111,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32>>,{em,[],[<<119,105,108,108,32,111,118,101,114,108,97,112>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,98,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<44,32,97,110,100,32>>,{code,[],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,112,111,115,105,116,105,118,101,44,32,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,114,101,112,101,97,116,101,100,108,121,44,32,121,111,117,32,119,105,108,108,32,101,118,101,110,116,117,97,108,108,121,32,115,101,101,32,115,111,109,101,32,105,110,116,101,103,101,114,115,32,116,104,97,116,32,97,114,101,32,114,101,116,117,114,110,101,100,32,98,121,32,98,111,116,104,32,99,97,108,108,115,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<105,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<105,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<32,105,115,32,110,111,116,32,97,32,118,97,108,105,100,32,109,111,100,105,102,105,101,114,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,55,56>>,signature => [{attribute,1522,spec,{{erlang,unique_integer,1},[{type,1522,bounded_fun,[{type,1522,'fun',[{type,1522,product,[{var,1522,'ModifierList'}]},{type,1522,integer,[]}]},[{type,1523,constraint,[{atom,1523,is_subtype},[{var,1523,'ModifierList'},{type,1523,list,[{var,1523,'Modifier'}]}]]},{type,1524,constraint,[{atom,1524,is_subtype},[{var,1524,'Modifier'},{type,1524,union,[{atom,1524,positive},{atom,1524,monotonic}]}]]}]]}]}}],since => <<79,84,80,32,49,56,46,48>>}},{{function,universaltime,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2062}],[<<117,110,105,118,101,114,115,97,108,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,97,99,99,111,114,100,105,110,103,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,40,41>>]},<<46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,40,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,49,56,44,52,51,125,125>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,52,54,48>>,signature => [{attribute,2062,spec,{{erlang,universaltime,0},[{type,2062,bounded_fun,[{type,2062,'fun',[{type,2062,product,[]},{var,2062,'DateTime'}]},[{type,2063,constraint,[{atom,2063,is_subtype},[{var,2063,'DateTime'},{remote_type,2063,[{atom,2063,calendar},{atom,2063,datetime},[]]}]]}]]}]}}]}},{{function,universaltime_to_localtime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2874}],[<<117,110,105,118,101,114,115,97,108,116,105,109,101,95,116,111,95,108,111,99,97,108,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,110,111,32,99,111,110,118,101,114,115,105,111,110,32,105,115,32,100,111,110,101,44,32,97,110,100,32>>,{code,[],[<<85,110,105,118,101,114,115,97,108,116,105,109,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,95,116,111,95,108,111,99,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,49,56,44,52,51,125,125,41,46,10,123,123,49,57,57,54,44,49,49,44,55,125,44,123,49,53,44,49,56,44,52,51,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<85,110,105,118,101,114,115,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,52,55,57>>,signature => [{attribute,2874,spec,{{erlang,universaltime_to_localtime,1},[{type,2874,bounded_fun,[{type,2874,'fun',[{type,2874,product,[{var,2874,'Universaltime'}]},{var,2874,'Localtime'}]},[{type,2875,constraint,[{atom,2875,is_subtype},[{var,2875,'Localtime'},{remote_type,2875,[{atom,2875,calendar},{atom,2875,datetime},[]]}]]},{type,2876,constraint,[{atom,2876,is_subtype},[{var,2876,'Universaltime'},{remote_type,2876,[{atom,2876,calendar},{atom,2876,datetime},[]]}]]}]]}]}}]}},{{function,unlink,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2074}],[<<117,110,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,116,104,101,32,108,105,110,107,44,32,105,102,32,116,104,101,114,101,32,105,115,32,111,110,101,44,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32>>,{code,[],[<<73,100>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,97,110,100,32,100,111,101,115,32,110,111,116,32,102,97,105,108,44,32,101,118,101,110,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,108,105,110,107,32,116,111,32>>,{code,[],[<<73,100>>]},<<44,32,111,114,32,105,102,32>>,{code,[],[<<73,100>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]},{p,[],[<<79,110,99,101,32>>,{code,[],[<<117,110,108,105,110,107,40,73,100,41>>]},<<32,104,97,115,32,114,101,116,117,114,110,101,100,44,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,116,104,101,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,101,114,32,97,110,100,32,116,104,101,32,101,110,116,105,116,121,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32>>,{code,[],[<<73,100>>]},<<32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,111,110,32,116,104,101,32,99,97,108,108,101,114,32,105,110,32,116,104,101,32,102,117,116,117,114,101,32,40,117,110,108,101,115,115,32,116,104,101,32,108,105,110,107,32,105,115,32,115,101,116,117,112,32,97,103,97,105,110,41,46,32,73,102,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,44,32,97,110,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,73,100,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,32,102,114,111,109,32,116,104,101,32,108,105,110,107,32,99,97,110,32,104,97,118,101,32,98,101,101,110,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,99,97,108,108,101,114,39,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,73,100,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,32,99,97,110,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,108,105,110,107,44,32,98,117,116,32,99,97,110,32,97,108,115,111,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<73,100>>]},<<32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,120,105,116,47,50>>]},<<46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32>>,{em,[],[<<99,97,110>>]},<<32,98,101,32,97,112,112,114,111,112,114,105,97,116,101,32,116,111,32,99,108,101,97,110,32,117,112,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,104,101,110,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,32,97,102,116,101,114,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,108,105,110,107,40,73,100,41>>]},<<44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<117,110,108,105,110,107,40,73,100,41,44,10,114,101,99,101,105,118,101,10,32,32,32,32,123,39,69,88,73,84,39,44,32,73,100,44,32,95,125,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,97,102,116,101,114,32,48,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,101,110,100>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,32,40,69,82,84,83,32,53,46,53,41,32>>,{code,[],[<<117,110,108,105,110,107,47,49>>]},<<32,98,101,104,97,118,101,100,32,99,111,109,112,108,101,116,101,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,108,105,110,107,32,119,97,115,32,97,99,116,105,118,101,32,117,110,116,105,108,32,116,104,101,32,34,117,110,108,105,110,107,32,115,105,103,110,97,108,34,32,114,101,97,99,104,101,100,32,116,104,101,32,108,105,110,107,101,100,32,101,110,116,105,116,121,46,32,84,104,105,115,32,104,97,100,32,97,110,32,117,110,100,101,115,105,114,97,98,108,101,32,101,102,102,101,99,116,44,32,97,115,32,121,111,117,32,99,111,117,108,100,32,110,101,118,101,114,32,107,110,111,119,32,119,104,101,110,32,121,111,117,32,119,101,114,101,32,103,117,97,114,97,110,116,101,101,100,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,98,101,32,101,102,102,101,99,116,101,100,32,98,121,32,116,104,101,32,108,105,110,107,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,118,105,101,119,101,100,32,97,115,32,116,119,111,32,99,111,109,98,105,110,101,100,32,111,112,101,114,97,116,105,111,110,115,58,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,32,115,101,110,100,32,97,110,32,34,117,110,108,105,110,107,32,115,105,103,110,97,108,34,32,116,111,32,116,104,101,32,108,105,110,107,101,100,32,101,110,116,105,116,121,32,97,110,100,32,105,103,110,111,114,101,32,97,110,121,32,102,117,116,117,114,101,32,114,101,115,117,108,116,115,32,111,102,32,116,104,101,32,108,105,110,107,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,52,57,56>>,signature => [{attribute,2074,spec,{{unlink,1},[{type,2074,bounded_fun,[{type,2074,'fun',[{type,2074,product,[{var,2074,'Id'}]},{atom,2074,true}]},[{type,2075,constraint,[{atom,2075,is_subtype},[{var,2075,'Id'},{type,2075,union,[{type,2075,pid,[]},{type,2075,port,[]}]}]]}]]}]}}]}},{{function,unregister,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2080}],[<<117,110,114,101,103,105,115,116,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,117,110,114,101,103,105,115,116,101,114,40,100,98,41,46,10,116,114,117,101>>]}]},{p,[],[<<85,115,101,114,115,32,97,114,101,32,97,100,118,105,115,101,100,32,110,111,116,32,116,111,32,117,110,114,101,103,105,115,116,101,114,32,115,121,115,116,101,109,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,53,52,52>>,signature => [{attribute,2080,spec,{{unregister,1},[{type,2080,bounded_fun,[{type,2080,'fun',[{type,2080,product,[{var,2080,'RegName'}]},{atom,2080,true}]},[{type,2081,constraint,[{atom,2081,is_subtype},[{var,2081,'RegName'},{type,2081,atom,[]}]]}]]}]}}]}},{{function,whereis,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2086}],[<<119,104,101,114,101,105,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,119,105,116,104,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,110,97,109,101,32,105,115,32,110,111,116,32,114,101,103,105,115,116,101,114,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,119,104,101,114,101,105,115,40,100,98,41,46,10,60,48,46,52,51,46,48,62>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,53,54,48>>,signature => [{attribute,2086,spec,{{whereis,1},[{type,2086,bounded_fun,[{type,2086,'fun',[{type,2086,product,[{var,2086,'RegName'}]},{type,2086,union,[{type,2086,pid,[]},{type,2086,port,[]},{atom,2086,undefined}]}]},[{type,2087,constraint,[{atom,2087,is_subtype},[{var,2087,'RegName'},{type,2087,atom,[]}]]}]]}]}}]}},{{function,yield,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3418}],[<<121,105,101,108,100,47,48>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,103,105,118,101,32,111,116,104,101,114,32,112,114,111,99,101,115,115,101,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,111,114,32,104,105,103,104,101,114,32,112,114,105,111,114,105,116,121,32,40,105,102,32,97,110,121,41,32,97,32,99,104,97,110,99,101,32,116,111,32,101,120,101,99,117,116,101,32,98,101,102,111,114,101,32,114,101,116,117,114,110,105,110,103,46,32,84,104,101,114,101,32,105,115,32,110,111,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,97,110,121,32,111,116,104,101,114,32,112,114,111,99,101,115,115,32,114,117,110,115,32,98,101,116,119,101,101,110,32,116,104,101,32,105,110,118,111,99,97,116,105,111,110,32,97,110,100,32,114,101,116,117,114,110,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,121,105,101,108,100,47,48>>]},<<46>>]},{p,[],[<<83,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,102,111,114,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,114,101,99,101,105,118,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<114,101,99,101,105,118,101,45,97,102,116,101,114>>]},<<32,101,120,112,114,101,115,115,105,111,110,115>>]},<<32,102,111,114,32,104,111,119,32,116,111,32,109,97,107,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,115,108,101,101,112,32,102,111,114,32,97,32,115,112,101,99,105,102,105,99,32,110,117,109,98,101,114,32,111,102,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,115,101,108,100,111,109,32,111,114,32,110,101,118,101,114,32,97,110,121,32,110,101,101,100,32,116,111,32,117,115,101,32,116,104,105,115,32,66,73,70,46,32,85,115,105,110,103,32,116,104,105,115,32,66,73,70,32,119,105,116,104,111,117,116,32,97,32,116,104,111,114,111,117,103,104,32,103,114,97,115,112,32,111,102,32,104,111,119,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,119,111,114,107,115,32,99,97,110,32,99,97,117,115,101,32,112,101,114,102,111,114,109,97,110,99,101,32,100,101,103,114,97,100,97,116,105,111,110,46,32,84,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,112,117,116,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,108,97,115,116,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,99,104,101,100,117,108,101,114,39,115,32,113,117,101,117,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,32,111,102,32,116,104,101,32,115,97,109,101,32,112,114,105,111,114,105,116,121,32,97,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,53,55,52>>,signature => [{attribute,3418,spec,{{erlang,yield,0},[{type,3418,'fun',[{type,3418,product,[]},{atom,3418,true}]}]}}]}},{{type,ext_binary,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,87}],[<<45,116,121,112,101,32,101,120,116,95,98,105,110,97,114,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,44,32,115,116,114,117,99,116,117,114,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},#{signature => [{attribute,87,type,{ext_binary,{type,87,binary,[]},[]}}]}},{{type,ext_iovec,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,88}],[<<45,116,121,112,101,32,101,120,116,95,105,111,118,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,116,101,114,109,32,111,102,32,116,121,112,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<105,111,118,101,99,40,41>>]}]},<<44,32,115,116,114,117,99,116,117,114,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},#{signature => [{attribute,88,type,{ext_iovec,{user_type,88,iovec,[]},[]}}]}},{{type,iovec,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,119}],[<<45,116,121,112,101,32,105,111,118,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,108,105,115,116,32,111,102,32,98,105,110,97,114,105,101,115,46,32,84,104,105,115,32,100,97,116,97,116,121,112,101,32,105,115,32,117,115,101,102,117,108,32,116,111,32,117,115,101,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>]}]},<<46>>]}]},#{signature => [{attribute,119,type,{iovec,{type,119,list,[{type,119,binary,[]}]},[]}}]}},{{type,message_queue_data,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2353}],[<<45,116,121,112,101,32,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},#{signature => [{attribute,2353,type,{message_queue_data,{type,2354,union,[{atom,2354,off_heap},{atom,2354,on_heap}]},[]}}]}},{{type,monitor_option,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1397}],[<<45,116,121,112,101,32,109,111,110,105,116,111,114,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,1397,type,{monitor_option,{type,1397,union,[{type,1397,tuple,[{atom,1397,alias},{type,1397,union,[{atom,1397,explicit_unalias},{atom,1397,demonitor},{atom,1397,reply_demonitor}]}]},{type,1398,tuple,[{atom,1398,tag},{type,1398,term,[]}]}]},[]}}]}},{{type,timestamp,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,89}],[<<45,116,121,112,101,32,116,105,109,101,115,116,97,109,112,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,115,116,97,109,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,47,48>>]}]},<<46>>]}]},#{signature => [{attribute,89,type,{timestamp,{type,89,tuple,[{ann_type,89,[{var,89,'MegaSecs'},{type,89,non_neg_integer,[]}]},{ann_type,90,[{var,90,'Secs'},{type,90,non_neg_integer,[]}]},{ann_type,91,[{var,91,'MicroSecs'},{type,91,non_neg_integer,[]}]}]},[]}}]}},{{type,time_unit,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,93}],[<<45,116,121,112,101,32,116,105,109,101,95,117,110,105,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{a,[{id,<<116,121,112,101,95,116,105,109,101,95,117,110,105,116>>}],[]},{p,[],[<<83,117,112,112,111,114,116,101,100,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<80,97,114,116,115,80,101,114,83,101,99,111,110,100,32,58,58,32,105,110,116,101,103,101,114,40,41,32,62,61,32,49>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,117,110,105,116,32,101,120,112,114,101,115,115,101,100,32,105,110,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,101,113,117,97,108,115,32>>,{code,[],[<<49,47,80,97,114,116,115,80,101,114,83,101,99,111,110,100>>]},<<32,115,101,99,111,110,100,46>>]}]},{dt,[],[{code,[],[<<115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,108,108,105,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,99,114,111,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48,95,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,110,111,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48,95,48,48,48,95,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,116,105,118,101>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,110,97,116,105,118,101,32,116,105,109,101,32,117,110,105,116,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,44,32,97,110,100,32,114,101,109,97,105,110,115,32,116,104,101,32,115,97,109,101,32,117,110,116,105,108,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,101,114,109,105,110,97,116,101,115,46,32,73,102,32,97,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,115,116,111,112,112,101,100,32,97,110,100,32,116,104,101,110,32,115,116,97,114,116,101,100,32,97,103,97,105,110,32,40,101,118,101,110,32,111,110,32,116,104,101,32,115,97,109,101,32,109,97,99,104,105,110,101,41,44,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,111,102,32,116,104,101,32,110,101,119,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,99,97,110,32,100,105,102,102,101,114,32,102,114,111,109,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,111,102,32,116,104,101,32,111,108,100,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<79,110,101,32,99,97,110,32,103,101,116,32,97,110,32,97,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,40,49,44,32,115,101,99,111,110,100,44,32,110,97,116,105,118,101,41>>]}]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,101,113,117,97,108,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,119,104,111,108,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,115,32,112,101,114,32,115,101,99,111,110,100,32,100,111,101,115,32,110,111,116,32,97,100,100,32,117,112,32,116,111,32,97,32,119,104,111,108,101,32,110,117,109,98,101,114,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,114,111,117,110,100,101,100,32,100,111,119,110,119,97,114,100,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,103,105,118,101,115,32,121,111,117,32,109,111,114,101,32,111,114,32,108,101,115,115,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,113,117,97,108,105,116,121,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,46,32,73,116,32,115,101,116,115,32,97,32,108,105,109,105,116,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,97,110,100,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,44,32,98,117,116,32,105,116,32,103,105,118,101,115,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,46,32,84,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,97,110,100,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,32,99,97,110,32,100,105,102,102,101,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,46>>]}]}]},{dt,[],[{code,[],[<<112,101,114,102,95,99,111,117,110,116,101,114>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,112,101,114,102,111,114,109,97,110,99,101,32,99,111,117,110,116,101,114,32,116,105,109,101,32,117,110,105,116,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<112,101,114,102,95,99,111,117,110,116,101,114>>]},<<32,116,105,109,101,32,117,110,105,116,32,98,101,104,97,118,101,115,32,109,117,99,104,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,114,117,110,116,105,109,101,32,114,101,115,116,97,114,116,115,46,32,84,111,32,103,101,116,32,118,97,108,117,101,115,32,111,102,32,116,104,105,115,32,116,121,112,101,44,32,99,97,108,108,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>]}]},<<46>>]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116,40,41>>]}]}]},{dd,[],[{p,[],[<<68,101,112,114,101,99,97,116,101,100,32,115,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,115,45,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]}]},{p,[],[<<84,104,101,32>>,{code,[],[<<116,105,109,101,95,117,110,105,116,47,48>>]},<<32,116,121,112,101,32,99,97,110,32,98,101,32,101,120,116,101,110,100,101,100,46,32,84,111,32,99,111,110,118,101,114,116,32,116,105,109,101,32,118,97,108,117,101,115,32,98,101,116,119,101,101,110,32,116,105,109,101,32,117,110,105,116,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,93,type,{time_unit,{type,94,union,[{type,94,pos_integer,[]},{atom,95,second},{atom,96,millisecond},{atom,97,microsecond},{atom,98,nanosecond},{atom,99,native},{atom,100,perf_counter},{user_type,101,deprecated_time_unit,[]}]},[]}}]}},{{type,deprecated_time_unit,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,104}],[<<45,116,121,112,101,32,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{a,[{id,<<116,121,112,101,95,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116>>}],[]},{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,117,110,105,116,40,41>>]}]},<<32,116,121,112,101,32,97,108,115,111,32,99,111,110,115,105,115,116,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{em,[],[<<100,101,112,114,101,99,97,116,101,100>>]},<<32,115,121,109,98,111,108,105,99,32,116,105,109,101,32,117,110,105,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,108,108,105,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,108,108,105,115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,99,114,111,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,110,111,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,97,110,111,115,101,99,111,110,100>>]}]},<<46>>]}]}]}]},#{signature => [{attribute,104,type,{deprecated_time_unit,{type,105,union,[{atom,105,seconds},{atom,106,milli_seconds},{atom,107,micro_seconds},{atom,108,nano_seconds}]},[]}}]}},{{type,dist_handle,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,116}],[<<45,116,121,112,101,32,100,105,115,116,95,104,97,110,100,108,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,111,112,97,113,117,101,32,104,97,110,100,108,101,32,105,100,101,110,116,105,102,105,110,103,32,97,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,46>>]}]},#{signature => [{attribute,116,opaque,{dist_handle,{type,116,atom,[]},[]}}]}},{{type,nif_resource,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,113}],[<<45,116,121,112,101,32,110,105,102,95,114,101,115,111,117,114,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,111,112,97,113,117,101,32,104,97,110,100,108,101,32,105,100,101,110,116,105,102,105,110,103,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,114,101,115,111,117,114,99,101,95,111,98,106,101,99,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<78,73,70,32,114,101,115,111,117,114,99,101,32,111,98,106,101,99,116,32>>]},<<46>>]}]},#{signature => [{attribute,113,opaque,{nif_resource,{type,113,reference,[]},[]}}]}},{{type,spawn_opt_option,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2988}],[<<45,116,121,112,101,32,115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<79,112,116,105,111,110,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,40,41>>]}]},<<46>>]}]},#{signature => [{attribute,2988,type,{spawn_opt_option,{type,2989,union,[{atom,2989,link},{atom,2990,monitor},{type,2991,tuple,[{atom,2991,monitor},{ann_type,2991,[{var,2991,'MonitorOpts'},{type,2991,list,[{user_type,2991,monitor_option,[]}]}]}]},{type,2992,tuple,[{atom,2992,priority},{ann_type,2992,[{var,2992,'Level'},{user_type,2992,priority_level,[]}]}]},{type,2993,tuple,[{atom,2993,fullsweep_after},{ann_type,2993,[{var,2993,'Number'},{type,2993,non_neg_integer,[]}]}]},{type,2994,tuple,[{atom,2994,min_heap_size},{ann_type,2994,[{var,2994,'Size'},{type,2994,non_neg_integer,[]}]}]},{type,2995,tuple,[{atom,2995,min_bin_vheap_size},{ann_type,2995,[{var,2995,'VSize'},{type,2995,non_neg_integer,[]}]}]},{type,2996,tuple,[{atom,2996,max_heap_size},{ann_type,2996,[{var,2996,'Size'},{user_type,2996,max_heap_size,[]}]}]},{type,2997,tuple,[{atom,2997,message_queue_data},{ann_type,2997,[{var,2997,'MQD'},{user_type,2997,message_queue_data,[]}]}]}]},[]}}]}},{{type,priority_level,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2350}],[<<45,116,121,112,101,32,112,114,105,111,114,105,116,121,95,108,101,118,101,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]}]}]},#{signature => [{attribute,2350,type,{priority_level,{type,2351,union,[{atom,2351,low},{atom,2351,normal},{atom,2351,high},{atom,2351,max}]},[]}}]}},{{type,max_heap_size,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2981}],[<<45,116,121,112,101,32,109,97,120,95,104,101,97,112,95,115,105,122,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,109,97,120,32,104,101,97,112,32,115,105,122,101,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]}]}]},#{signature => [{attribute,2981,type,{max_heap_size,{ann_type,2982,[{var,2982,'Size'},{type,2982,union,[{type,2982,non_neg_integer,[]},{type,2984,map,[{type,2984,map_field_assoc,[{atom,2984,size},{type,2984,non_neg_integer,[]}]},{type,2985,map_field_assoc,[{atom,2985,kill},{type,2985,boolean,[]}]},{type,2986,map_field_assoc,[{atom,2986,error_logger},{type,2986,boolean,[]}]}]}]}]},[]}}]}},{{type,message_queue_data,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2353}],[<<45,116,121,112,101,32,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,100,97,116,97,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]}]}]},#{signature => [{attribute,2353,type,{message_queue_data,{type,2354,union,[{atom,2354,off_heap},{atom,2354,on_heap}]},[]}}]}}]}. \ No newline at end of file +{docs_v1,[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<66,121,32,99,111,110,118,101,110,116,105,111,110,44,32,109,111,115,116,32,66,117,105,108,116,45,73,110,32,70,117,110,99,116,105,111,110,115,32,40,66,73,70,115,41,32,97,110,100,32,97,108,108,32,112,114,101,100,101,102,105,110,101,100,32,116,121,112,101,115,32,97,114,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,46,32,83,111,109,101,32,111,102,32,116,104,101,32,66,73,70,115,32,97,110,100,32,97,108,108,32,111,102,32,116,104,101,32,112,114,101,100,101,102,105,110,101,100,32,116,121,112,101,115,32,97,114,101,32,118,105,101,119,101,100,32,109,111,114,101,32,111,114,32,108,101,115,115,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,32,97,110,100,32,97,114,101,32>>,{em,[],[<<97,117,116,111,45,105,109,112,111,114,116,101,100>>]},<<46,32,84,104,117,115,44,32,105,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,121,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,109,111,100,117,108,101,32,110,97,109,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,97,108,108,115,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,101,114,108,97,110,103,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,97,116,111,109,95,116,111,95,108,105,115,116,40,101,114,108,97,110,103,41>>]},<<32,97,114,101,32,105,100,101,110,116,105,99,97,108,46>>]},{p,[],[<<65,117,116,111,45,105,109,112,111,114,116,101,100,32,66,73,70,115,32,97,114,101,32,108,105,115,116,101,100,32,119,105,116,104,111,117,116,32,109,111,100,117,108,101,32,112,114,101,102,105,120,46,32,66,73,70,115,32,108,105,115,116,101,100,32,119,105,116,104,32,109,111,100,117,108,101,32,112,114,101,102,105,120,32,97,114,101,32,110,111,116,32,97,117,116,111,45,105,109,112,111,114,116,101,100,46>>]},{p,[],[<<80,114,101,100,101,102,105,110,101,100,32,116,121,112,101,115,32,97,114,101,32,108,105,115,116,101,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,80,114,101,100,101,102,105,110,101,100,32,100,97,116,97,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,114,101,100,101,102,105,110,101,100,32,100,97,116,97,116,121,112,101,115>>]},<<32,115,101,99,116,105,111,110,32,111,102,32,116,104,105,115,32,114,101,102,101,114,101,110,99,101,32,109,97,110,117,97,108,32,97,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,116,121,112,101,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<84,121,112,101,115,32,97,110,100,32,70,117,110,99,116,105,111,110,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115>>]},<<32,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,46>>]},{p,[],[<<66,73,70,115,32,99,97,110,32,102,97,105,108,32,102,111,114,32,118,97,114,105,111,117,115,32,114,101,97,115,111,110,115,46,32,65,108,108,32,66,73,70,115,32,102,97,105,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,121,32,97,114,101,32,99,97,108,108,101,100,32,119,105,116,104,32,97,114,103,117,109,101,110,116,115,32,111,102,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,46,32,84,104,101,32,111,116,104,101,114,32,114,101,97,115,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,101,97,99,104,32,105,110,100,105,118,105,100,117,97,108,32,66,73,70,46>>]},{p,[],[<<83,111,109,101,32,66,73,70,115,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,32,97,110,100,32,97,114,101,32,109,97,114,107,101,100,32,119,105,116,104,32,34,65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,34,46>>]}]},#{name => <<101,114,108,97,110,103>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,101,114,108,97,110,103,46,120,109,108],types => #{{non_neg_integer,0} => {attribute,{107,2},type,{non_neg_integer,{type,{107,28},non_neg_integer,[]},[]}},{trace_match_spec,0} => {attribute,{3009,2},type,{trace_match_spec,{type,{3010,7},list,[{type,{3010,8},tuple,[{type,{3010,9},union,[{type,{3010,9},list,[{type,{3010,10},term,[]}]},{atom,{3010,20},'_'},{user_type,{3010,26},match_variable,[]}]},{type,{3010,44},list,[{type,{3010,45},term,[]}]},{type,{3010,53},list,[{type,{3010,54},term,[]}]}]}]},[]}},{nonempty_binary,0} => {attribute,{109,2},type,{nonempty_binary,{type,{109,28},binary,[{integer,{109,32},8},{integer,{109,39},8}]},[]}},{stacktrace,0} => {attribute,{152,2},type,{stacktrace,{type,{152,23},list,[{type,{152,24},union,[{type,{152,24},tuple,[{type,{152,25},module,[]},{type,{152,35},atom,[]},{type,{152,43},union,[{type,{152,43},arity,[]},{type,{152,53},list,[{type,{152,54},term,[]}]}]},{type,{153,25},list,[{user_type,{153,26},stacktrace_extrainfo,[]}]}]},{type,{154,24},tuple,[{type,{154,25},function,[]},{type,{154,37},union,[{type,{154,37},arity,[]},{type,{154,47},list,[{type,{154,48},term,[]}]}]},{type,{154,57},list,[{user_type,{154,58},stacktrace_extrainfo,[]}]}]}]}]},[]}},{time_unit,0} => {attribute,{162,2},type,{time_unit,{type,{163,2},union,[{type,{163,2},pos_integer,[]},{atom,{164,9},second},{atom,{165,9},millisecond},{atom,{166,9},microsecond},{atom,{167,9},nanosecond},{atom,{168,9},native},{atom,{169,9},perf_counter},{user_type,{170,9},deprecated_time_unit,[]}]},[]}},{string,0} => {attribute,{122,2},type,{string,{type,{122,19},list,[{type,{122,20},char,[]}]},[]}},{trace_info_flag,0} => {attribute,{396,2},type,{trace_info_flag,{type,{397,7},union,[{atom,{397,7},send},{atom,{398,7},'receive'},{atom,{399,7},set_on_spawn},{atom,{400,7},call},{atom,{401,7},return_to},{atom,{402,7},procs},{atom,{403,7},set_on_first_spawn},{atom,{404,7},set_on_link},{atom,{405,7},running},{atom,{406,7},garbage_collection},{atom,{407,7},timestamp},{atom,{408,7},monotonic_timestamp},{atom,{409,7},strict_monotonic_timestamp},{atom,{410,7},arity}]},[]}},{mfa,0} => {attribute,{101,2},type,{mfa,{type,{101,16},tuple,[{type,{101,17},module,[]},{type,{101,26},atom,[]},{type,{101,33},arity,[]}]},[]}},{nonempty_bitstring,0} => {attribute,{110,2},type,{nonempty_bitstring,{type,{110,31},binary,[{integer,{110,35},1},{integer,{110,42},1}]},[]}},{dynamic,0} => {attribute,{89,2},type,{dynamic,{type,{89,20},dynamic,[]},[]}},{none,0} => {attribute,{108,2},type,{none,{type,{108,17},none,[]},[]}},{trace_info_item_result,0} => {attribute,{386,2},type,{trace_info_item_result,{type,{387,8},union,[{type,{387,8},tuple,[{atom,{387,9},traced},{type,{387,17},union,[{atom,{387,17},global},{atom,{387,26},local},{atom,{387,34},false},{atom,{387,42},undefined}]}]},{type,{388,8},tuple,[{atom,{388,9},match_spec},{type,{388,21},union,[{user_type,{388,21},trace_match_spec,[]},{atom,{388,42},false},{atom,{388,50},undefined}]}]},{type,{389,8},tuple,[{atom,{389,9},meta},{type,{389,15},union,[{type,{389,15},pid,[]},{type,{389,23},port,[]},{atom,{389,32},false},{atom,{389,40},undefined},{type,{389,52},nil,[]}]}]},{type,{390,8},tuple,[{atom,{390,9},meta},{type,{390,15},module,[]},{type,{390,25},term,[]}]},{type,{391,8},tuple,[{atom,{391,9},meta_match_spec},{type,{391,26},union,[{user_type,{391,26},trace_match_spec,[]},{atom,{391,47},false},{atom,{391,55},undefined}]}]},{type,{392,8},tuple,[{atom,{392,9},call_count},{type,{392,21},union,[{type,{392,21},non_neg_integer,[]},{type,{392,41},boolean,[]},{atom,{392,53},undefined}]}]},{type,{393,8},tuple,[{type,{393,9},union,[{atom,{393,9},call_time},{atom,{393,21},call_memory}]},{type,{393,34},union,[{type,{393,34},list,[{type,{393,35},tuple,[{type,{393,36},pid,[]},{type,{393,43},non_neg_integer,[]},{type,{394,8},non_neg_integer,[]},{type,{394,27},non_neg_integer,[]}]}]},{type,{394,49},boolean,[]},{atom,{394,61},undefined}]}]}]},[]}},{atom,0} => {attribute,{82,2},type,{atom,{type,{82,17},atom,[]},[]}},{trace_pattern_mfa,0} => {attribute,{3007,2},type,{trace_pattern_mfa,{type,{3008,7},union,[{type,{3008,7},tuple,[{type,{3008,8},atom,[]},{type,{3008,15},atom,[]},{type,{3008,22},union,[{type,{3008,22},arity,[]},{atom,{3008,32},'_'}]}]},{atom,{3008,39},on_load}]},[]}},{timestamp,0} => {attribute,{158,2},type,{timestamp,{type,{158,22},tuple,[{ann_type,{158,23},[{var,{158,23},'MegaSecs'},{type,{158,35},non_neg_integer,[]}]},{ann_type,{159,23},[{var,{159,23},'Secs'},{type,{159,31},non_neg_integer,[]}]},{ann_type,{160,23},[{var,{160,23},'MicroSecs'},{type,{160,36},non_neg_integer,[]}]}]},[]}},{char,0} => {attribute,{88,2},type,{char,{type,{88,17},range,[{integer,{88,17},0},{integer,{88,20},1114111}]},[]}},{list,1} => {attribute,{97,2},type,{list,{type,{97,28},list,[{var,{97,29},'ContentType'}]},[{var,{97,12},'ContentType'}]}},{any,0} => {attribute,{80,2},type,{any,{type,{80,16},any,[]},[]}},{function,0} => {attribute,{91,2},type,{function,{type,{91,21},'fun',[]},[]}},{deprecated_time_unit,0} => {attribute,{173,2},type,{deprecated_time_unit,{type,{174,7},union,[{atom,{174,7},seconds},{atom,{175,9},milli_seconds},{atom,{176,9},micro_seconds},{atom,{177,9},nano_seconds}]},[]}},{bitstring_list,0} => {attribute,{357,2},type,{bitstring_list,{type,{358,7},maybe_improper_list,[{type,{358,27},union,[{type,{358,27},byte,[]},{type,{358,36},bitstring,[]},{user_type,{358,50},bitstring_list,[]}]},{type,{358,68},union,[{type,{358,68},bitstring,[]},{type,{358,82},nil,[]}]}]},[]}},{nonempty_list,0} => {attribute,{112,2},type,{nonempty_list,{type,{112,26},nonempty_list,[{type,{112,40},any,[]}]},[]}},{neg_integer,0} => {attribute,{103,2},type,{neg_integer,{type,{103,24},neg_integer,[]},[]}},{monitor_process_identifier,0} => {attribute,{1687,2},type,{monitor_process_identifier,{type,{1687,39},union,[{type,{1687,39},pid,[]},{user_type,{1687,47},registered_process_identifier,[]}]},[]}},{sub_level,0} => {attribute,{3068,2},type,{sub_level,{type,{3068,22},union,[{type,{3068,22},list,[{ann_type,{3068,23},[{var,{3068,23},'LevelEntry'},{user_type,{3068,37},level_entry,[]}]}]},{ann_type,{3069,23},[{var,{3069,23},'LogicalCpuId'},{type,{3069,39},tuple,[{atom,{3069,40},logical},{type,{3069,49},non_neg_integer,[]}]}]}]},[]}},{scheduler_bind_type,0} => {attribute,{2894,2},type,{scheduler_bind_type,{type,{2895,7},union,[{atom,{2895,7},no_node_processor_spread},{atom,{2896,7},no_node_thread_spread},{atom,{2897,7},no_spread},{atom,{2898,7},processor_spread},{atom,{2899,7},spread},{atom,{2900,7},thread_spread},{atom,{2901,7},thread_no_node_processor_spread},{atom,{2902,7},unbound}]},[]}},{iovec,0} => {attribute,{188,2},type,{iovec,{type,{188,18},list,[{type,{188,19},binary,[]}]},[]}},{level_entry,0} => {attribute,{3062,2},type,{level_entry,{type,{3063,9},union,[{type,{3063,9},tuple,[{ann_type,{3063,10},[{var,{3063,10},'LevelTag'},{user_type,{3063,22},level_tag,[]}]},{ann_type,{3063,35},[{var,{3063,35},'SubLevel'},{user_type,{3063,47},sub_level,[]}]}]},{type,{3064,9},tuple,[{ann_type,{3064,10},[{var,{3064,10},'LevelTag'},{user_type,{3064,22},level_tag,[]}]},{ann_type,{3065,10},[{var,{3065,10},'InfoList'},{user_type,{3065,22},info_list,[]}]},{ann_type,{3066,10},[{var,{3066,10},'SubLevel'},{user_type,{3066,22},sub_level,[]}]}]}]},[]}},{process_info_item,0} => {attribute,{2684,2},type,{process_info_item,{type,{2685,7},union,[{atom,{2685,7},async_dist},{atom,{2686,7},backtrace},{atom,{2687,7},binary},{atom,{2688,7},catchlevel},{atom,{2689,7},current_function},{atom,{2690,7},current_location},{atom,{2691,7},current_stacktrace},{atom,{2692,7},dictionary},{atom,{2693,7},error_handler},{atom,{2694,7},garbage_collection},{atom,{2695,7},garbage_collection_info},{atom,{2696,7},group_leader},{atom,{2697,7},heap_size},{atom,{2698,7},initial_call},{atom,{2699,7},links},{atom,{2700,7},last_calls},{atom,{2701,7},memory},{atom,{2702,7},message_queue_len},{atom,{2703,7},messages},{atom,{2704,7},min_heap_size},{atom,{2705,7},min_bin_vheap_size},{atom,{2706,7},monitored_by},{atom,{2707,7},monitors},{atom,{2708,7},message_queue_data},{atom,{2709,7},parent},{atom,{2710,7},priority},{atom,{2711,7},reductions},{atom,{2712,7},registered_name},{atom,{2713,7},sequential_trace_token},{atom,{2714,7},stack_size},{atom,{2715,7},status},{atom,{2716,7},suspending},{atom,{2717,7},total_heap_size},{atom,{2718,7},trace},{atom,{2719,7},trap_exit}]},[]}},{iolist,0} => {attribute,{95,2},type,{iolist,{type,{95,19},maybe_improper_list,[{type,{95,39},union,[{type,{95,39},byte,[]},{type,{95,48},binary,[]},{type,{95,59},iolist,[]}]},{type,{95,69},union,[{type,{95,69},binary,[]},{type,{95,80},nil,[]}]}]},[]}},{integer,0} => {attribute,{93,2},type,{integer,{type,{93,20},integer,[]},[]}},{match_variable,0} => {attribute,{3006,2},type,{match_variable,{type,{3006,27},atom,[]},[]}},{nonempty_improper_list,2} => {attribute,{111,2},type,{nonempty_improper_list,{type,{111,63},nonempty_improper_list,[{var,{111,86},'ContentType'},{var,{111,99},'TerminationType'}]},[{var,{111,30},'ContentType'},{var,{111,43},'TerminationType'}]}},{bitstring,0} => {attribute,{84,2},type,{bitstring,{type,{84,22},binary,[{integer,84,0},{integer,{84,28},1}]},[]}},{max_heap_size,0} => {attribute,{3291,2},type,{max_heap_size,{ann_type,{3292,9},[{var,{3292,9},'Size'},{type,{3292,17},union,[{type,{3292,17},non_neg_integer,[]},{type,{3294,9},map,[{type,{3294,17},map_field_assoc,[{atom,{3294,12},size},{type,{3294,20},non_neg_integer,[]}]},{type,{3295,17},map_field_assoc,[{atom,{3295,12},kill},{type,{3295,20},boolean,[]}]},{type,{3296,25},map_field_assoc,[{atom,{3296,12},error_logger},{type,{3296,28},boolean,[]}]},{type,{3297,36},map_field_assoc,[{atom,{3297,12},include_shared_binaries},{type,{3297,39},boolean,[]}]}]}]}]},[]}},{system_monitor_option,0} => {attribute,{346,2},type,{system_monitor_option,{type,{347,7},union,[{atom,{347,7},busy_port},{atom,{348,7},busy_dist_port},{type,{349,7},tuple,[{atom,{349,8},long_gc},{type,{349,19},non_neg_integer,[]}]},{type,{350,7},tuple,[{atom,{350,8},long_schedule},{type,{350,25},non_neg_integer,[]}]},{type,{351,7},tuple,[{atom,{351,8},large_heap},{type,{351,22},non_neg_integer,[]}]}]},[]}},{number,0} => {attribute,{117,2},type,{number,{type,{117,19},union,[{type,{117,19},integer,[]},{type,{117,31},float,[]}]},[]}},{send_destination,0} => {attribute,{3737,2},type,{send_destination,{type,{3737,29},union,[{type,{3737,29},pid,[]},{type,{3738,29},reference,[]},{type,{3739,29},port,[]},{ann_type,{3740,30},[{var,{3740,30},'RegName'},{type,{3740,41},atom,[]}]},{type,{3741,29},tuple,[{ann_type,{3741,30},[{var,{3741,30},'RegName'},{type,{3741,41},atom,[]}]},{ann_type,{3741,49},[{var,{3741,49},'Node'},{type,{3741,57},node,[]}]}]}]},[]}},{ext_binary,0} => {attribute,{156,2},type,{ext_binary,{type,{156,23},binary,[]},[]}},{ext_iovec,0} => {attribute,{157,2},type,{ext_iovec,{user_type,{157,22},iovec,[]},[]}},{message_queue_data,0} => {attribute,{2641,2},type,{message_queue_data,{type,{2642,2},union,[{atom,{2642,2},off_heap},{atom,{2642,13},on_heap}]},[]}},{node,0} => {attribute,{106,2},type,{node,{type,{106,17},atom,[]},[]}},{list,0} => {attribute,{96,2},type,{list,{type,{96,17},list,[{type,{96,18},any,[]}]},[]}},{stacktrace_extrainfo,0} => {attribute,{147,2},type,{stacktrace_extrainfo,{type,{148,9},union,[{type,{148,9},tuple,[{atom,{148,10},line},{type,{148,16},pos_integer,[]}]},{type,{149,9},tuple,[{atom,{149,10},file},{remote_type,{149,16},[{atom,{149,16},unicode},{atom,{149,24},chardata},[]]}]},{type,{150,9},tuple,[{atom,{150,10},error_info},{type,{150,22},map,[{type,{150,32},map_field_assoc,[{atom,{150,25},module},{type,{150,35},module,[]}]},{type,{150,54},map_field_assoc,[{atom,{150,45},function},{type,{150,57},atom,[]}]},{type,{150,71},map_field_assoc,[{atom,{150,65},cause},{type,{150,74},term,[]}]}]}]},{type,{151,9},tuple,[{type,{151,10},atom,[]},{type,{151,18},term,[]}]}]},[]}},{pid,0} => {attribute,{118,2},type,{pid,{type,{118,16},pid,[]},[]}},{prepared_code,0} => {attribute,{179,2},opaque,{prepared_code,{type,{179,28},reference,[]},[]}},{nonempty_list,1} => {attribute,{113,2},type,{nonempty_list,{type,{113,37},nonempty_list,[{var,{113,38},'ContentType'}]},[{var,{113,21},'ContentType'}]}},{identifier,0} => {attribute,{92,2},type,{identifier,{type,{92,23},union,[{type,{92,23},pid,[]},{type,{92,31},port,[]},{type,{92,40},reference,[]}]},[]}},{registered_name,0} => {attribute,{1685,2},type,{registered_name,{type,{1685,28},atom,[]},[]}},{cpu_topology,0} => {attribute,{3060,2},type,{cpu_topology,{type,{3061,9},union,[{type,{3061,9},list,[{ann_type,{3061,10},[{var,{3061,10},'LevelEntry'},{user_type,{3061,24},level_entry,[]}]}]},{atom,{3061,41},undefined}]},[]}},{seq_trace_info_returns,0} => {attribute,{331,2},type,{seq_trace_info_returns,{type,{332,7},union,[{type,{332,7},tuple,[{type,{332,9},union,[{atom,{332,9},send},{atom,{332,18},'receive'},{atom,{332,30},print},{atom,{332,40},timestamp},{atom,{332,54},monotonic_timestamp},{atom,{332,78},strict_monotonic_timestamp}]},{type,{332,108},boolean,[]}]},{type,{333,7},tuple,[{atom,{333,9},label},{type,{333,18},term,[]}]},{type,{334,7},tuple,[{atom,{334,9},serial},{type,{334,19},tuple,[{type,{334,21},non_neg_integer,[]},{type,{334,40},non_neg_integer,[]}]}]},{type,{335,7},nil,[]}]},[]}},{info_list,0} => {attribute,{3070,2},type,{info_list,{type,{3070,22},nil,[]},[]}},{monitor_option,0} => {attribute,{1689,2},type,{monitor_option,{type,{1689,27},union,[{type,{1689,27},tuple,[{atom,{1689,28},alias},{type,{1689,37},union,[{atom,{1689,37},explicit_unalias},{atom,{1689,58},demonitor},{atom,{1689,72},reply_demonitor}]}]},{type,{1690,27},tuple,[{atom,{1690,28},tag},{type,{1690,35},term,[]}]}]},[]}},{boolean,0} => {attribute,{86,2},type,{boolean,{type,{86,20},union,[{atom,{86,20},true},{atom,{86,27},false}]},[]}},{trace_pattern_flag,0} => {attribute,{3025,2},type,{trace_pattern_flag,{type,{3026,7},union,[{atom,{3026,7},global},{atom,{3026,16},local},{atom,{3027,7},meta},{type,{3027,14},tuple,[{atom,{3027,15},meta},{ann_type,{3027,21},[{var,{3027,21},'Pid'},{type,{3027,28},pid,[]}]}]},{type,{3028,7},tuple,[{atom,{3028,8},meta},{ann_type,{3028,14},[{var,{3028,14},'TracerModule'},{type,{3028,30},module,[]}]},{ann_type,{3028,40},[{var,{3028,40},'TracerState'},{type,{3028,55},term,[]}]}]},{atom,{3029,7},call_count},{atom,{3030,7},call_time},{atom,{3031,7},call_memory}]},[]}},{priority_level,0} => {attribute,{2638,2},type,{priority_level,{type,{2639,7},union,[{atom,{2639,7},low},{atom,{2639,13},normal},{atom,{2639,22},high},{atom,{2639,29},max}]},[]}},{pos_integer,0} => {attribute,{120,2},type,{pos_integer,{type,{120,24},pos_integer,[]},[]}},{maybe_improper_list,0} => {attribute,{99,2},type,{maybe_improper_list,{type,{99,32},maybe_improper_list,[{type,{99,52},any,[]},{type,{99,59},any,[]}]},[]}},{dist_handle,0} => {attribute,{185,2},opaque,{dist_handle,{type,{185,26},atom,[]},[]}},{byte,0} => {attribute,{87,2},type,{byte,{type,{87,17},range,[{integer,{87,17},0},{integer,{87,20},255}]},[]}},{arity,0} => {attribute,{81,2},type,{arity,{type,{81,18},arity,[]},[]}},{term,0} => {attribute,{123,2},type,{term,{type,{123,17},any,[]},[]}},{nonempty_maybe_improper_list,2} => {attribute,{115,2},type,{nonempty_maybe_improper_list,{type,{115,69},nonempty_maybe_improper_list,[{var,{115,98},'ContentType'},{var,{115,111},'TerminationType'}]},[{var,{115,36},'ContentType'},{var,{115,49},'TerminationType'}]}},{nil,0} => {attribute,{104,2},type,{nil,{type,{104,16},nil,[]},[]}},{stack_item,0} => {attribute,{2770,2},type,{stack_item,{type,{2771,9},tuple,[{ann_type,{2771,10},[{var,{2771,10},'Module'},{type,{2771,20},module,[]}]},{ann_type,{2772,10},[{var,{2772,10},'Function'},{type,{2772,22},atom,[]}]},{ann_type,{2773,10},[{var,{2773,10},'Arity'},{type,{2773,19},union,[{type,{2773,19},arity,[]},{ann_type,{2773,30},[{var,{2773,30},'Args'},{type,{2773,38},list,[{type,{2773,39},term,[]}]}]}]}]},{ann_type,{2774,10},[{var,{2774,10},'Location'},{type,{2774,22},list,[{type,{2774,23},union,[{type,{2774,23},tuple,[{atom,{2774,24},file},{ann_type,{2774,30},[{var,{2774,30},'Filename'},{type,{2774,42},string,[]}]}]},{type,{2775,23},tuple,[{atom,{2775,24},line},{ann_type,{2775,30},[{var,{2775,30},'Line'},{type,{2775,38},pos_integer,[]}]}]}]}]}]}]},[]}},{tuple,0} => {attribute,{125,2},type,{tuple,{type,{125,18},tuple,any},[]}},{nif_resource,0} => {attribute,{182,2},opaque,{nif_resource,{type,{182,27},reference,[]},[]}},{spawn_opt_option,0} => {attribute,{3299,2},type,{spawn_opt_option,{type,{3300,2},union,[{atom,{3300,2},link},{atom,{3301,9},monitor},{type,{3302,9},tuple,[{atom,{3302,10},monitor},{ann_type,{3302,19},[{var,{3302,19},'MonitorOpts'},{type,{3302,34},list,[{user_type,{3302,35},monitor_option,[]}]}]}]},{type,{3303,9},tuple,[{atom,{3303,10},priority},{ann_type,{3303,20},[{var,{3303,20},'Level'},{user_type,{3303,29},priority_level,[]}]}]},{type,{3304,9},tuple,[{atom,{3304,10},fullsweep_after},{ann_type,{3304,27},[{var,{3304,27},'Number'},{type,{3304,37},non_neg_integer,[]}]}]},{type,{3305,9},tuple,[{atom,{3305,10},min_heap_size},{ann_type,{3305,25},[{var,{3305,25},'Size'},{type,{3305,33},non_neg_integer,[]}]}]},{type,{3306,9},tuple,[{atom,{3306,10},min_bin_vheap_size},{ann_type,{3306,30},[{var,{3306,30},'VSize'},{type,{3306,39},non_neg_integer,[]}]}]},{type,{3307,9},tuple,[{atom,{3307,10},max_heap_size},{ann_type,{3307,25},[{var,{3307,25},'Size'},{user_type,{3307,33},max_heap_size,[]}]}]},{type,{3308,9},tuple,[{atom,{3308,10},message_queue_data},{ann_type,{3308,30},[{var,{3308,30},'MQD'},{user_type,{3308,37},message_queue_data,[]}]}]},{type,{3309,9},tuple,[{atom,{3309,10},async_dist},{ann_type,{3309,22},[{var,{3309,22},'Enabled'},{type,{3309,33},boolean,[]}]}]}]},[]}},{halt_options,0} => {attribute,{1401,2},type,{halt_options,{type,{1402,9},list,[{type,{1402,10},tuple,[{atom,{1402,11},flush},{type,{1402,18},boolean,[]}]}]},[]}},{raise_stacktrace,0} => {attribute,{353,2},type,{raise_stacktrace,{type,{354,7},list,[{type,{354,8},union,[{type,{354,8},tuple,[{type,{354,9},module,[]},{type,{354,19},atom,[]},{type,{354,27},union,[{type,{354,27},arity,[]},{type,{354,37},list,[{type,{354,38},term,[]}]}]}]},{type,{355,8},tuple,[{type,{355,9},function,[]},{type,{355,21},union,[{type,{355,21},arity,[]},{type,{355,31},list,[{type,{355,32},term,[]}]}]}]}]}]},[]}},{module,0} => {attribute,{102,2},type,{module,{type,{102,19},atom,[]},[]}},{float,0} => {attribute,{90,2},type,{float,{type,{90,18},float,[]},[]}},{monitor_port_identifier,0} => {attribute,{1688,2},type,{monitor_port_identifier,{type,{1688,36},union,[{type,{1688,36},port,[]},{user_type,{1688,45},registered_name,[]}]},[]}},{memory_type,0} => {attribute,{4277,2},type,{memory_type,{type,{4277,24},union,[{atom,{4277,24},total},{atom,{4277,34},processes},{atom,{4277,48},processes_used},{atom,{4277,67},system},{atom,{4278,24},atom},{atom,{4278,33},atom_used},{atom,{4278,47},binary},{atom,{4278,58},code},{atom,{4278,67},ets}]},[]}},{timeout,0} => {attribute,{124,2},type,{timeout,{type,{124,20},union,[{atom,{124,20},infinity},{type,{124,33},non_neg_integer,[]}]},[]}},{maybe_improper_list,2} => {attribute,{100,2},type,{maybe_improper_list,{type,{100,60},maybe_improper_list,[{var,{100,80},'ContentType'},{var,{100,93},'TerminationType'}]},[{var,{100,27},'ContentType'},{var,{100,40},'TerminationType'}]}},{process_info_result_item,0} => {attribute,{2721,2},type,{process_info_result_item,{type,{2722,7},union,[{type,{2722,7},tuple,[{atom,{2722,8},async_dist},{ann_type,{2722,20},[{var,{2722,20},'Enabled'},{type,{2722,31},boolean,[]}]}]},{type,{2723,7},tuple,[{atom,{2723,8},backtrace},{ann_type,{2723,19},[{var,{2723,19},'Bin'},{type,{2723,26},binary,[]}]}]},{type,{2724,7},tuple,[{atom,{2724,8},binary},{ann_type,{2724,16},[{var,{2724,16},'BinInfo'},{type,{2724,27},list,[{type,{2724,28},tuple,[{type,{2724,29},non_neg_integer,[]},{type,{2725,29},non_neg_integer,[]},{type,{2726,29},non_neg_integer,[]}]}]}]}]},{type,{2727,7},tuple,[{atom,{2727,8},catchlevel},{ann_type,{2727,20},[{var,{2727,20},'CatchLevel'},{type,{2727,34},non_neg_integer,[]}]}]},{type,{2728,7},tuple,[{atom,{2728,8},current_function},{type,{2729,8},union,[{type,{2729,8},tuple,[{ann_type,{2729,9},[{var,{2729,9},'Module'},{type,{2729,19},module,[]}]},{ann_type,{2729,29},[{var,{2729,29},'Function'},{type,{2729,41},atom,[]}]},{ann_type,{2729,49},[{var,{2729,49},'Arity'},{type,{2729,58},arity,[]}]}]},{atom,{2729,69},undefined}]}]},{type,{2730,7},tuple,[{atom,{2730,8},current_location},{type,{2731,8},tuple,[{ann_type,{2731,9},[{var,{2731,9},'Module'},{type,{2731,19},module,[]}]},{ann_type,{2731,29},[{var,{2731,29},'Function'},{type,{2731,41},atom,[]}]},{ann_type,{2731,49},[{var,{2731,49},'Arity'},{type,{2731,58},arity,[]}]},{ann_type,{2732,9},[{var,{2732,9},'Location'},{type,{2732,21},list,[{type,{2732,22},union,[{type,{2732,22},tuple,[{atom,{2732,23},file},{ann_type,{2732,29},[{var,{2732,29},'Filename'},{type,{2732,41},string,[]}]}]},{type,{2733,22},tuple,[{atom,{2733,23},line},{ann_type,{2733,29},[{var,{2733,29},'Line'},{type,{2733,37},pos_integer,[]}]}]}]}]}]}]}]},{type,{2734,7},tuple,[{atom,{2734,8},current_stacktrace},{ann_type,{2734,28},[{var,{2734,28},'Stack'},{type,{2734,37},list,[{user_type,{2734,38},stack_item,[]}]}]}]},{type,{2735,7},tuple,[{atom,{2735,8},dictionary},{ann_type,{2735,20},[{var,{2735,20},'Dictionary'},{type,{2735,34},list,[{type,{2735,35},tuple,[{ann_type,{2735,36},[{var,{2735,36},'Key'},{type,{2735,43},term,[]}]},{ann_type,{2735,51},[{var,{2735,51},'Value'},{type,{2735,60},term,[]}]}]}]}]}]},{type,{2736,7},tuple,[{atom,{2736,8},error_handler},{ann_type,{2736,23},[{var,{2736,23},'Module'},{type,{2736,33},module,[]}]}]},{type,{2737,7},tuple,[{atom,{2737,8},garbage_collection},{ann_type,{2737,28},[{var,{2737,28},'GCInfo'},{type,{2737,38},list,[{type,{2737,39},tuple,[{type,{2737,40},atom,[]},{type,{2737,47},non_neg_integer,[]}]}]}]}]},{type,{2738,7},tuple,[{atom,{2738,8},garbage_collection_info},{ann_type,{2738,33},[{var,{2738,33},'GCInfo'},{type,{2738,43},list,[{type,{2738,44},tuple,[{type,{2738,45},atom,[]},{type,{2738,52},non_neg_integer,[]}]}]}]}]},{type,{2739,7},tuple,[{atom,{2739,8},group_leader},{ann_type,{2739,22},[{var,{2739,22},'GroupLeader'},{type,{2739,37},pid,[]}]}]},{type,{2740,7},tuple,[{atom,{2740,8},heap_size},{ann_type,{2740,19},[{var,{2740,19},'Size'},{type,{2740,27},non_neg_integer,[]}]}]},{type,{2741,7},tuple,[{atom,{2741,8},initial_call},{type,{2741,22},mfa,[]}]},{type,{2742,7},tuple,[{atom,{2742,8},links},{ann_type,{2742,15},[{var,{2742,15},'PidsAndPorts'},{type,{2742,31},list,[{type,{2742,32},union,[{type,{2742,32},pid,[]},{type,{2742,40},port,[]}]}]}]}]},{type,{2743,7},tuple,[{atom,{2743,8},last_calls},{type,{2743,20},union,[{atom,{2743,20},false},{ann_type,{2743,29},[{var,{2743,29},'Calls'},{type,{2743,38},list,[{type,{2743,39},mfa,[]}]}]}]}]},{type,{2744,7},tuple,[{atom,{2744,8},memory},{ann_type,{2744,16},[{var,{2744,16},'Size'},{type,{2744,24},non_neg_integer,[]}]}]},{type,{2745,7},tuple,[{atom,{2745,8},message_queue_len},{ann_type,{2745,27},[{var,{2745,27},'MessageQueueLen'},{type,{2745,46},non_neg_integer,[]}]}]},{type,{2746,7},tuple,[{atom,{2746,8},messages},{ann_type,{2746,18},[{var,{2746,18},'MessageQueue'},{type,{2746,34},list,[{type,{2746,35},term,[]}]}]}]},{type,{2747,7},tuple,[{atom,{2747,8},min_heap_size},{ann_type,{2747,23},[{var,{2747,23},'MinHeapSize'},{type,{2747,38},non_neg_integer,[]}]}]},{type,{2748,7},tuple,[{atom,{2748,8},min_bin_vheap_size},{ann_type,{2748,28},[{var,{2748,28},'MinBinVHeapSize'},{type,{2748,47},non_neg_integer,[]}]}]},{type,{2749,7},tuple,[{atom,{2749,8},max_heap_size},{ann_type,{2749,23},[{var,{2749,23},'MaxHeapSize'},{user_type,{2749,38},max_heap_size,[]}]}]},{type,{2750,7},tuple,[{atom,{2750,8},monitored_by},{ann_type,{2750,22},[{var,{2750,22},'MonitoredBy'},{type,{2750,37},list,[{type,{2750,38},union,[{type,{2750,38},pid,[]},{type,{2750,46},port,[]},{user_type,{2750,55},nif_resource,[]}]}]}]}]},{type,{2751,7},tuple,[{atom,{2751,8},monitors},{ann_type,{2752,8},[{var,{2752,8},'Monitors'},{type,{2752,20},list,[{type,{2752,21},tuple,[{type,{2752,22},union,[{atom,{2752,22},process},{atom,{2752,32},port}]},{ann_type,{2752,38},[{var,{2752,38},'Pid'},{type,{2752,45},union,[{type,{2752,45},pid,[]},{type,{2752,53},port,[]},{type,{2753,38},tuple,[{ann_type,{2753,39},[{var,{2753,39},'RegName'},{type,{2753,50},atom,[]}]},{ann_type,{2753,58},[{var,{2753,58},'Node'},{type,{2753,66},node,[]}]}]}]}]}]}]}]}]},{type,{2754,7},tuple,[{atom,{2754,8},message_queue_data},{ann_type,{2754,28},[{var,{2754,28},'MQD'},{user_type,{2754,35},message_queue_data,[]}]}]},{type,{2755,7},tuple,[{atom,{2755,8},parent},{type,{2755,16},union,[{type,{2755,16},pid,[]},{atom,{2755,24},undefined}]}]},{type,{2756,7},tuple,[{atom,{2756,8},priority},{ann_type,{2756,18},[{var,{2756,18},'Level'},{user_type,{2756,27},priority_level,[]}]}]},{type,{2757,7},tuple,[{atom,{2757,8},reductions},{ann_type,{2757,20},[{var,{2757,20},'Number'},{type,{2757,30},non_neg_integer,[]}]}]},{type,{2758,7},tuple,[{atom,{2758,8},registered_name},{type,{2758,25},union,[{type,{2758,25},nil,[]},{ann_type,{2758,31},[{var,{2758,31},'Atom'},{type,{2758,39},atom,[]}]}]}]},{type,{2759,7},tuple,[{atom,{2759,8},sequential_trace_token},{type,{2759,32},union,[{type,{2759,32},nil,[]},{ann_type,{2759,38},[{var,{2759,38},'SequentialTraceToken'},{type,{2759,62},term,[]}]}]}]},{type,{2760,7},tuple,[{atom,{2760,8},stack_size},{ann_type,{2760,20},[{var,{2760,20},'Size'},{type,{2760,28},non_neg_integer,[]}]}]},{type,{2761,7},tuple,[{atom,{2761,8},status},{ann_type,{2761,16},[{var,{2761,16},'Status'},{type,{2761,26},union,[{atom,{2761,26},exiting},{atom,{2761,36},garbage_collecting},{atom,{2761,57},waiting},{atom,{2761,67},running},{atom,{2761,77},runnable},{atom,{2761,88},suspended}]}]}]},{type,{2762,7},tuple,[{atom,{2762,8},suspending},{ann_type,{2763,8},[{var,{2763,8},'SuspendeeList'},{type,{2763,25},list,[{type,{2763,26},tuple,[{ann_type,{2763,27},[{var,{2763,27},'Suspendee'},{type,{2763,40},pid,[]}]},{ann_type,{2764,27},[{var,{2764,27},'ActiveSuspendCount'},{type,{2764,49},non_neg_integer,[]}]},{ann_type,{2765,27},[{var,{2765,27},'OutstandingSuspendCount'},{type,{2765,53},non_neg_integer,[]}]}]}]}]}]},{type,{2766,7},tuple,[{atom,{2766,8},total_heap_size},{ann_type,{2766,25},[{var,{2766,25},'Size'},{type,{2766,33},non_neg_integer,[]}]}]},{type,{2767,7},tuple,[{atom,{2767,8},trace},{ann_type,{2767,15},[{var,{2767,15},'InternalTraceFlags'},{type,{2767,37},non_neg_integer,[]}]}]},{type,{2768,7},tuple,[{atom,{2768,8},trap_exit},{ann_type,{2768,19},[{var,{2768,19},'Boolean'},{type,{2768,30},boolean,[]}]}]}]},[]}},{trace_flag,0} => {attribute,{360,2},type,{trace_flag,{type,{361,7},union,[{atom,{361,7},all},{atom,{362,7},send},{atom,{363,7},'receive'},{atom,{364,7},procs},{atom,{365,7},ports},{atom,{366,7},call},{atom,{367,7},arity},{atom,{368,7},return_to},{atom,{369,7},silent},{atom,{370,7},running},{atom,{371,7},exiting},{atom,{372,7},running_procs},{atom,{373,7},running_ports},{atom,{374,7},garbage_collection},{atom,{375,7},timestamp},{atom,{376,7},cpu_timestamp},{atom,{377,7},monotonic_timestamp},{atom,{378,7},strict_monotonic_timestamp},{atom,{379,7},set_on_spawn},{atom,{380,7},set_on_first_spawn},{atom,{381,7},set_on_link},{atom,{382,7},set_on_first_link},{type,{383,7},tuple,[{atom,{383,8},tracer},{type,{383,16},union,[{type,{383,16},pid,[]},{type,{383,24},port,[]}]}]},{type,{384,7},tuple,[{atom,{384,8},tracer},{type,{384,16},module,[]},{type,{384,26},term,[]}]}]},[]}},{trace_info_return,0} => {attribute,{412,2},type,{trace_info_return,{type,{413,7},union,[{atom,{413,7},undefined},{type,{414,7},tuple,[{atom,{414,8},flags},{type,{414,15},list,[{user_type,{414,16},trace_info_flag,[]}]}]},{type,{415,7},tuple,[{atom,{415,8},tracer},{type,{415,16},union,[{type,{415,16},pid,[]},{type,{415,24},port,[]},{type,{415,33},nil,[]}]}]},{type,{416,7},tuple,[{atom,{416,8},tracer},{type,{416,16},module,[]},{type,{416,26},term,[]}]},{user_type,{417,7},trace_info_item_result,[]},{type,{418,7},tuple,[{atom,{418,8},all},{type,{418,13},union,[{type,{418,13},list,[{user_type,{418,15},trace_info_item_result,[]}]},{atom,{418,44},false},{atom,{418,52},undefined}]}]}]},[]}},{fun_info_item,0} => {attribute,{319,2},type,{fun_info_item,{type,{320,7},union,[{atom,{320,7},arity},{atom,{321,7},env},{atom,{322,7},index},{atom,{323,7},name},{atom,{324,7},module},{atom,{325,7},new_index},{atom,{326,7},new_uniq},{atom,{327,7},pid},{atom,{328,7},type},{atom,{329,7},uniq}]},[]}},{registered_process_identifier,0} => {attribute,{1686,2},type,{registered_process_identifier,{type,{1686,42},union,[{user_type,{1686,42},registered_name,[]},{type,{1686,62},tuple,[{user_type,{1686,63},registered_name,[]},{type,{1686,82},node,[]}]}]},[]}},{system_profile_option,0} => {attribute,{337,2},type,{system_profile_option,{type,{338,7},union,[{atom,{338,7},exclusive},{atom,{339,7},runnable_ports},{atom,{340,7},runnable_procs},{atom,{341,7},scheduler},{atom,{342,7},timestamp},{atom,{343,7},monotonic_timestamp},{atom,{344,7},strict_monotonic_timestamp}]},[]}},{module_info_key,0} => {attribute,{2416,2},type,{module_info_key,{type,{2416,28},union,[{atom,{2416,28},attributes},{atom,{2416,41},compile},{atom,{2416,51},exports},{atom,{2416,61},functions},{atom,{2416,73},md5},{atom,{2417,28},module},{atom,{2417,37},native},{atom,{2417,46},native_addresses},{atom,{2417,65},nifs}]},[]}},{nonempty_string,0} => {attribute,{116,2},type,{nonempty_string,{type,{116,28},nonempty_list,[{type,{116,42},char,[]}]},[]}},{nonempty_maybe_improper_list,0} => {attribute,{114,2},type,{nonempty_maybe_improper_list,{type,{114,41},nonempty_maybe_improper_list,[{type,{114,70},any,[]},{type,{114,77},any,[]}]},[]}},{binary,0} => {attribute,{83,2},type,{binary,{type,{83,19},binary,[{integer,83,0},{integer,{83,25},8}]},[]}},{map,0} => {attribute,{98,2},type,{map,{type,{98,16},map,[{type,{98,25},map_field_assoc,[{type,{98,19},any,[]},{type,{98,28},any,[]}]}]},[]}},{level_tag,0} => {attribute,{3067,2},type,{level_tag,{type,{3067,22},union,[{atom,{3067,22},core},{atom,{3067,29},node},{atom,{3067,36},processor},{atom,{3067,48},thread}]},[]}},{port,0} => {attribute,{119,2},type,{port,{type,{119,17},port,[]},[]}},{iodata,0} => {attribute,{94,2},type,{iodata,{type,{94,19},union,[{type,{94,19},iolist,[]},{type,{94,30},binary,[]}]},[]}},{no_return,0} => {attribute,{105,2},type,{no_return,{type,{105,22},none,[]},[]}},{bool,0} => {attribute,{85,2},type,{bool,{type,{85,17},boolean,[]},[]}},{reference,0} => {attribute,{121,2},type,{reference,{type,{121,22},reference,[]},[]}}}},[{{function,'!',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,33,39,47,50>>],hidden,#{}},{{function,'*',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,42,39,47,50>>],hidden,#{}},{{function,'+',1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,43,39,47,49>>],hidden,#{}},{{function,'+',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,43,39,47,50>>],hidden,#{}},{{function,'++',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,43,43,39,47,50>>],hidden,#{}},{{function,'-',1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,45,39,47,49>>],hidden,#{}},{{function,'-',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,45,39,47,50>>],hidden,#{}},{{function,'--',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,45,45,39,47,50>>],hidden,#{}},{{function,'/',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,47,39,47,50>>],hidden,#{}},{{function,'/=',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,47,61,39,47,50>>],hidden,#{}},{{function,'<',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,60,39,47,50>>],hidden,#{}},{{function,'=/=',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,61,47,61,39,47,50>>],hidden,#{}},{{function,'=:=',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,61,58,61,39,47,50>>],hidden,#{}},{{function,'=<',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,61,60,39,47,50>>],hidden,#{}},{{function,'==',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,61,61,39,47,50>>],hidden,#{}},{{function,'>',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,62,39,47,50>>],hidden,#{}},{{function,'>=',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,62,61,39,47,50>>],hidden,#{}},{{function,alloc_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<97,108,108,111,99,95,105,110,102,111,47,49>>],hidden,#{}},{{function,alloc_sizes,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<97,108,108,111,99,95,115,105,122,101,115,47,49>>],hidden,#{}},{{function,'and',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,97,110,100,39,47,50>>],hidden,#{}},{{function,append,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<97,112,112,101,110,100,47,50>>],hidden,#{}},{{function,'band',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,97,110,100,39,47,50>>],hidden,#{}},{{function,'bnot',1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,110,111,116,39,47,49>>],hidden,#{}},{{function,'bor',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,111,114,39,47,50>>],hidden,#{}},{{function,'bsl',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,115,108,39,47,50>>],hidden,#{}},{{function,'bsr',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,115,114,39,47,50>>],hidden,#{}},{{function,'bxor',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,98,120,111,114,39,47,50>>],hidden,#{}},{{function,call_on_load_function,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<99,97,108,108,95,111,110,95,108,111,97,100,95,102,117,110,99,116,105,111,110,47,49>>],hidden,#{}},{{function,delay_trap,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,101,108,97,121,95,116,114,97,112,47,50>>],hidden,#{}},{{function,display_string,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,105,115,112,108,97,121,95,115,116,114,105,110,103,47,49>>],hidden,#{}},{{function,display_string,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,105,115,112,108,97,121,95,115,116,114,105,110,103,47,50>>],hidden,#{}},{{function,dist_get_stat,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,105,115,116,95,103,101,116,95,115,116,97,116,47,49>>],hidden,#{}},{{function,'div',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,100,105,118,39,47,50>>],hidden,#{}},{{function,dmonitor_node,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,109,111,110,105,116,111,114,95,110,111,100,101,47,51>>],hidden,#{}},{{function,dt_append_vm_tag_data,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,97,112,112,101,110,100,95,118,109,95,116,97,103,95,100,97,116,97,47,49>>],hidden,#{}},{{function,dt_get_tag,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,103,101,116,95,116,97,103,47,48>>],hidden,#{}},{{function,dt_get_tag_data,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,103,101,116,95,116,97,103,95,100,97,116,97,47,48>>],hidden,#{}},{{function,dt_prepend_vm_tag_data,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,112,114,101,112,101,110,100,95,118,109,95,116,97,103,95,100,97,116,97,47,49>>],hidden,#{}},{{function,dt_put_tag,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,112,117,116,95,116,97,103,47,49>>],hidden,#{}},{{function,dt_restore_tag,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,114,101,115,116,111,114,101,95,116,97,103,47,49>>],hidden,#{}},{{function,dt_spread_tag,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<100,116,95,115,112,114,101,97,100,95,116,97,103,47,49>>],hidden,#{}},{{function,exit_signal,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<101,120,105,116,95,115,105,103,110,97,108,47,50>>],hidden,#{}},{{function,finish_after_on_load,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<102,105,110,105,115,104,95,97,102,116,101,114,95,111,110,95,108,111,97,100,47,50>>],hidden,#{}},{{function,finish_loading,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<102,105,110,105,115,104,95,108,111,97,100,105,110,103,47,49>>],hidden,#{}},{{function,format_cpu_topology,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<102,111,114,109,97,116,95,99,112,117,95,116,111,112,111,108,111,103,121,47,49>>],hidden,#{}},{{function,fun_info_mfa,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<102,117,110,95,105,110,102,111,95,109,102,97,47,49>>],hidden,#{}},{{function,garbage_collect_message_area,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,95,109,101,115,115,97,103,101,95,97,114,101,97,47,48>>],hidden,#{}},{{function,gather_gc_info_result,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<103,97,116,104,101,114,95,103,99,95,105,110,102,111,95,114,101,115,117,108,116,47,49>>],hidden,#{}},{{function,get_module_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<103,101,116,95,109,111,100,117,108,101,95,105,110,102,111,47,49>>],hidden,#{}},{{function,get_module_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<103,101,116,95,109,111,100,117,108,101,95,105,110,102,111,47,50>>],hidden,#{}},{{function,has_prepared_code_on_load,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<104,97,115,95,112,114,101,112,97,114,101,100,95,99,111,100,101,95,111,110,95,108,111,97,100,47,49>>],hidden,#{}},{{function,make_fun,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<109,97,107,101,95,102,117,110,47,51>>],hidden,#{}},{{function,'not',1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,110,111,116,39,47,49>>],hidden,#{}},{{function,'or',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,111,114,39,47,50>>],hidden,#{}},{{function,port_call,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<112,111,114,116,95,99,97,108,108,47,50>>],hidden,#{}},{{function,port_get_data,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<112,111,114,116,95,103,101,116,95,100,97,116,97,47,49>>],hidden,#{}},{{function,port_set_data,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<112,111,114,116,95,115,101,116,95,100,97,116,97,47,50>>],hidden,#{}},{{function,posixtime_to_universaltime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<112,111,115,105,120,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,49>>],hidden,#{}},{{function,prepare_loading,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<112,114,101,112,97,114,101,95,108,111,97,100,105,110,103,47,50>>],hidden,#{}},{{function,'rem',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,114,101,109,39,47,50>>],hidden,#{}},{{function,seq_trace,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,113,95,116,114,97,99,101,47,50>>],hidden,#{}},{{function,seq_trace_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,113,95,116,114,97,99,101,95,105,110,102,111,47,49>>],hidden,#{}},{{function,seq_trace_print,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,113,95,116,114,97,99,101,95,112,114,105,110,116,47,49>>],hidden,#{}},{{function,seq_trace_print,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,113,95,116,114,97,99,101,95,112,114,105,110,116,47,50>>],hidden,#{}},{{function,set_cpu_topology,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,116,95,99,112,117,95,116,111,112,111,108,111,103,121,47,49>>],hidden,#{}},{{function,setnode,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,116,110,111,100,101,47,50>>],hidden,#{}},{{function,setnode,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,101,116,110,111,100,101,47,51>>],hidden,#{}},{{function,subtract,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<115,117,98,116,114,97,99,116,47,50>>],hidden,#{}},{{function,universaltime_to_posixtime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<117,110,105,118,101,114,115,97,108,116,105,109,101,95,116,111,95,112,111,115,105,120,116,105,109,101,47,49>>],hidden,#{}},{{function,'xor',2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,0}],[<<39,120,111,114,39,47,50>>],hidden,#{}},{{function,abs,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2393}],[<<97,98,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,111,114,32,102,108,111,97,116,32,116,104,97,116,32,105,115,32,116,104,101,32,97,114,105,116,104,109,101,116,105,99,97,108,32,97,98,115,111,108,117,116,101,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,111,114,32>>,{code,[],[<<73,110,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,98,115,40,45,51,46,51,51,41,46,10,51,46,51,51,10,62,32,97,98,115,40,45,51,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2393,2},spec,{{abs,1},[{type,{2393,10},bounded_fun,[{type,{2393,10},'fun',[{type,{2393,10},product,[{var,{2393,11},'Float'}]},{type,{2393,21},float,[]}]},[{type,{2394,7},constraint,[{atom,{2394,7},is_subtype},[{var,{2394,7},'Float'},{type,{2394,16},float,[]}]]}]]},{type,{2395,10},bounded_fun,[{type,{2395,10},'fun',[{type,{2395,10},product,[{var,{2395,11},'Int'}]},{type,{2395,19},non_neg_integer,[]}]},[{type,{2396,7},constraint,[{atom,{2396,7},is_subtype},[{var,{2396,7},'Int'},{type,{2396,14},integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,53>>}},{{function,adler32,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,422}],[<<97,100,108,101,114,51,50,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,32,102,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]}]},#{signature => [{attribute,{422,2},spec,{{erlang,adler32,1},[{type,{422,21},bounded_fun,[{type,{422,21},'fun',[{type,{422,21},product,[{var,{422,22},'Data'}]},{type,{422,31},non_neg_integer,[]}]},[{type,{423,7},constraint,[{atom,{423,7},is_subtype},[{var,{423,7},'Data'},{type,{423,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,57,50>>}},{{function,adler32,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,428}],[<<97,100,108,101,114,51,50,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,116,105,110,117,101,115,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,32,98,121,32,99,111,109,98,105,110,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,101,99,107,115,117,109,44,32>>,{code,[],[<<79,108,100,65,100,108,101,114>>]},<<44,32,119,105,116,104,32,116,104,101,32,99,104,101,99,107,115,117,109,32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,88,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<89>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,91,68,97,116,97,49,44,68,97,116,97,50,93,41,46>>]}]}]},#{signature => [{attribute,{428,2},spec,{{erlang,adler32,2},[{type,{428,21},bounded_fun,[{type,{428,21},'fun',[{type,{428,21},product,[{var,{428,22},'OldAdler'},{var,{428,32},'Data'}]},{type,{428,41},non_neg_integer,[]}]},[{type,{429,7},constraint,[{atom,{429,7},is_subtype},[{var,{429,7},'OldAdler'},{type,{429,19},non_neg_integer,[]}]]},{type,{430,7},constraint,[{atom,{430,7},is_subtype},[{var,{430,7},'Data'},{type,{430,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,49>>}},{{function,adler32_combine,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,435}],[<<97,100,108,101,114,51,50,95,99,111,109,98,105,110,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32,116,119,111,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,117,116,101,100,32,97,100,108,101,114,51,50,32,99,104,101,99,107,115,117,109,115,46,32,84,104,105,115,32,99,111,109,112,117,116,97,116,105,111,110,32,114,101,113,117,105,114,101,115,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,111,98,106,101,99,116,32,102,111,114,32,116,104,101,32,115,101,99,111,110,100,32,99,104,101,99,107,115,117,109,32,116,111,32,98,101,32,107,110,111,119,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,90,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,89,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<90>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,40,68,97,116,97,50,41,44,10,90,32,61,32,101,114,108,97,110,103,58,97,100,108,101,114,51,50,95,99,111,109,98,105,110,101,40,88,44,89,44,105,111,108,105,115,116,95,115,105,122,101,40,68,97,116,97,50,41,41,46>>]}]}]},#{signature => [{attribute,{435,2},spec,{{erlang,adler32_combine,3},[{type,{435,29},bounded_fun,[{type,{435,29},'fun',[{type,{435,29},product,[{var,{435,30},'FirstAdler'},{var,{435,42},'SecondAdler'},{var,{435,55},'SecondSize'}]},{type,{435,70},non_neg_integer,[]}]},[{type,{436,7},constraint,[{atom,{436,7},is_subtype},[{var,{436,7},'FirstAdler'},{type,{436,21},non_neg_integer,[]}]]},{type,{437,7},constraint,[{atom,{437,7},is_subtype},[{var,{437,7},'SecondAdler'},{type,{437,22},non_neg_integer,[]}]]},{type,{438,7},constraint,[{atom,{438,7},is_subtype},[{var,{438,7},'SecondSize'},{type,{438,21},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,56>>}},{{function,alias,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,994}],[<<97,108,105,97,115,47,49>>],#{},#{signature => [{attribute,{994,2},spec,{{alias,1},[{type,{994,12},bounded_fun,[{type,{994,12},'fun',[{type,{994,12},product,[{var,{994,13},'Opts'}]},{var,{994,22},'Alias'}]},[{type,{995,7},constraint,[{atom,{995,7},is_subtype},[{var,{995,7},'Alias'},{type,{995,16},reference,[]}]]},{type,{996,7},constraint,[{atom,{996,7},is_subtype},[{var,{996,7},'Opts'},{type,{996,15},list,[{type,{996,16},union,[{atom,{996,16},explicit_unalias},{atom,{996,37},reply}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,55>>,equiv => {function,alias,0},since => <<79,84,80,32,50,52,46,48>>}},{{function,alias,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,988}],[<<97,108,105,97,115,47,48>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,32,97,110,32,97,108,105,97,115,32,119,104,105,99,104,32,99,97,110,32,98,101,32,117,115,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,97,108,105,97,115,46,32,87,104,101,110,32,116,104,101,32,97,108,105,97,115,32,104,97,115,32,98,101,101,110,32,100,101,97,99,116,105,118,97,116,101,100,44,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,117,115,105,110,103,32,116,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,100,114,111,112,112,101,100,46,32,65,110,32,97,108,105,97,115,32,99,97,110,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,97,108,105,97,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,97,108,105,97,115,47,49>>]}]},<<46,32,67,117,114,114,101,110,116,108,121,32,97,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,32,102,111,114,32>>,{code,[],[<<97,108,105,97,115,47,49>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,112,108,105,99,105,116,95,117,110,97,108,105,97,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,99,97,110,32,111,110,108,121,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,117,114,32,105,102,32,110,111,32,111,112,116,105,111,110,115,32,97,114,101,32,112,97,115,115,101,100,32,111,114,32,105,102,32>>,{code,[],[<<97,108,105,97,115,47,48>>]},<<32,105,115,32,99,97,108,108,101,100,46>>]}]},{dt,[],[{code,[],[<<114,101,112,108,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,99,101,105,118,101,100,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<115,101,114,118,101,114,40,41,32,45,62,10,32,32,32,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,123,114,101,113,117,101,115,116,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,82,101,115,117,108,116,32,61,32,112,101,114,102,111,114,109,95,114,101,113,117,101,115,116,40,82,101,113,117,101,115,116,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,65,108,105,97,115,82,101,113,73,100,32,33,32,123,114,101,112,108,121,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,115,117,108,116,125,10,32,32,32,32,101,110,100,44,10,32,32,32,32,115,101,114,118,101,114,40,41,46,10,10,99,108,105,101,110,116,40,83,101,114,118,101,114,80,105,100,44,32,82,101,113,117,101,115,116,41,32,45,62,10,32,32,32,32,65,108,105,97,115,82,101,113,73,100,32,61,32,97,108,105,97,115,40,91,114,101,112,108,121,93,41,44,10,32,32,32,32,83,101,114,118,101,114,80,105,100,32,33,32,123,114,101,113,117,101,115,116,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,44,10,32,32,32,32,37,37,32,65,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,105,102,32,119,101,32,114,101,99,101,105,118,101,32,97,32,114,101,112,108,121,10,32,32,32,32,37,37,32,115,105,110,99,101,32,119,101,32,117,115,101,100,32,116,104,101,32,39,114,101,112,108,121,39,32,111,112,116,105,111,110,46,46,46,10,32,32,32,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,123,114,101,112,108,121,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,115,117,108,116,125,32,45,62,32,82,101,115,117,108,116,10,32,32,32,32,97,102,116,101,114,32,53,48,48,48,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,117,110,97,108,105,97,115,40,65,108,105,97,115,82,101,113,73,100,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,37,37,32,70,108,117,115,104,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,110,32,99,97,115,101,32,116,104,101,32,114,101,112,108,121,32,97,114,114,105,118,101,100,10,32,32,32,32,32,32,32,32,32,32,32,32,37,37,32,106,117,115,116,32,98,101,102,111,114,101,32,116,104,101,32,97,108,105,97,115,32,119,97,115,32,100,101,97,99,116,105,118,97,116,101,100,46,46,46,10,32,32,32,32,32,32,32,32,32,32,32,32,114,101,99,101,105,118,101,32,123,114,101,112,108,121,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,115,117,108,116,125,32,45,62,32,82,101,115,117,108,116,10,32,32,32,32,32,32,32,32,32,32,32,32,97,102,116,101,114,32,48,32,45,62,32,101,120,105,116,40,116,105,109,101,111,117,116,41,10,32,32,32,32,32,32,32,32,32,32,32,32,101,110,100,10,32,32,32,32,101,110,100,46,10,9>>]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,98,111,116,104,32,116,104,101,32,115,101,114,118,101,114,32,97,110,100,32,116,104,101,32,99,108,105,101,110,116,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,109,117,115,116,32,98,101,32,101,120,101,99,117,116,105,110,103,32,111,110,32,97,116,32,108,101,97,115,116,32,79,84,80,32,50,52,32,115,121,115,116,101,109,115,32,105,110,32,111,114,100,101,114,32,102,111,114,32,116,104,105,115,32,116,111,32,119,111,114,107,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,111,99,101,115,115,32,97,108,105,97,115,101,115,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,112,114,111,99,101,115,115,45,97,108,105,97,115,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<80,114,111,99,101,115,115,32,65,108,105,97,115,101,115>>]}]},<<32,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},#{signature => [{attribute,{988,2},spec,{{alias,0},[{type,{988,12},bounded_fun,[{type,{988,12},'fun',[{type,{988,12},product,[]},{var,{988,18},'Alias'}]},[{type,{989,7},constraint,[{atom,{989,7},is_subtype},[{var,{989,7},'Alias'},{type,{989,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,55>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,append_element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,443}],[<<97,112,112,101,110,100,95,101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,116,104,97,116,32,104,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,109,111,114,101,32,116,104,97,110,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<44,32,97,110,100,32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,115,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,46,32,83,101,109,97,110,116,105,99,97,108,108,121,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<108,105,115,116,95,116,111,95,116,117,112,108,101,40,116,117,112,108,101,95,116,111,95,108,105,115,116,40,84,117,112,108,101,49,41,32,43,43,32,91,84,101,114,109,93,41>>]},<<44,32,98,117,116,32,109,117,99,104,32,102,97,115,116,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,97,112,112,101,110,100,95,101,108,101,109,101,110,116,40,123,111,110,101,44,32,116,119,111,125,44,32,116,104,114,101,101,41,46,10,123,111,110,101,44,116,119,111,44,116,104,114,101,101,125>>]}]}]},#{signature => [{attribute,{443,2},spec,{{erlang,append_element,2},[{type,{443,28},bounded_fun,[{type,{443,28},'fun',[{type,{443,28},product,[{var,{443,29},'Tuple1'},{var,{443,37},'Term'}]},{var,{443,46},'Tuple2'}]},[{type,{444,7},constraint,[{atom,{444,7},is_subtype},[{var,{444,7},'Tuple1'},{type,{444,17},tuple,any}]]},{type,{445,7},constraint,[{atom,{445,7},is_subtype},[{var,{445,7},'Tuple2'},{type,{445,17},tuple,any}]]},{type,{446,7},constraint,[{atom,{446,7},is_subtype},[{var,{446,7},'Term'},{type,{446,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,48,54>>}},{{function,apply,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3198}],[<<97,112,112,108,121,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,108,108,115,32,97,32,102,117,110,44,32,112,97,115,115,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<65,114,103,115>>]},<<32,97,115,32,97,114,103,117,109,101,110,116,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,107,110,111,119,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,116,104,101,32,99,97,108,108,32,105,115,32,98,101,116,116,101,114,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<70,117,110,40,65,114,103,49,44,32,65,114,103,50,44,32,46,46,46,32,65,114,103,78,41>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<69,97,114,108,105,101,114,44,32>>,{code,[],[<<70,117,110>>]},<<32,99,111,117,108,100,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,125>>]},<<44,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<97,112,112,108,121,40,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,103,115,41>>]},<<46,32>>,{em,[],[<<84,104,105,115,32,117,115,101,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,110,100,32,119,105,108,108,32,115,116,111,112,32,119,111,114,107,105,110,103,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]}]}]},#{signature => [{attribute,{3198,2},spec,{{apply,2},[{type,{3198,12},bounded_fun,[{type,{3198,12},'fun',[{type,{3198,12},product,[{var,{3198,13},'Fun'},{var,{3198,18},'Args'}]},{type,{3198,27},term,[]}]},[{type,{3199,7},constraint,[{atom,{3199,7},is_subtype},[{var,{3199,7},'Fun'},{type,{3199,14},function,[]}]]},{type,{3200,7},constraint,[{atom,{3200,7},is_subtype},[{var,{3200,7},'Args'},{type,{3200,15},list,[{type,{3200,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,51>>}},{{function,apply,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3205}],[<<97,112,112,108,121,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,110,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,84,104,101,32,97,112,112,108,105,101,100,32,102,117,110,99,116,105,111,110,32,109,117,115,116,32,98,101,32,101,120,112,111,114,116,101,100,32,102,114,111,109,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,84,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,112,112,108,121,40,108,105,115,116,115,44,32,114,101,118,101,114,115,101,44,32,91,91,97,44,32,98,44,32,99,93,93,41,46,10,91,99,44,98,44,97,93,10,62,32,97,112,112,108,121,40,101,114,108,97,110,103,44,32,97,116,111,109,95,116,111,95,108,105,115,116,44,32,91,39,69,114,108,97,110,103,39,93,41,46,10,34,69,114,108,97,110,103,34>>]}]},{p,[],[<<73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,107,110,111,119,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,116,104,101,32,99,97,108,108,32,105,115,32,98,101,116,116,101,114,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,40,65,114,103,49,44,32,65,114,103,50,44,32,46,46,46,44,32,65,114,103,78,41>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{a,[{href,<<107,101,114,110,101,108,58,101,114,114,111,114,95,104,97,110,100,108,101,114,35,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114,58,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,47,51>>]}]},<<32,105,115,32,99,97,108,108,101,100,32,105,102,32,116,104,101,32,97,112,112,108,105,101,100,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,101,120,112,111,114,116,101,100,46,32,84,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,99,97,110,32,98,101,32,114,101,100,101,102,105,110,101,100,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<41,46,32,73,102,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,111,114,32,105,102,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,100,101,102,105,110,101,100,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,115,111,32,116,104,101,32,114,101,112,108,97,99,101,109,101,110,116,32,109,111,100,117,108,101,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,32,101,114,114,111,114,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<117,110,100,101,102>>]},<<32,105,115,32,103,101,110,101,114,97,116,101,100,46>>]}]},#{signature => [{attribute,{3205,2},spec,{{apply,3},[{type,{3205,12},bounded_fun,[{type,{3205,12},'fun',[{type,{3205,12},product,[{var,{3205,13},'Module'},{var,{3205,21},'Function'},{var,{3205,31},'Args'}]},{type,{3205,40},term,[]}]},[{type,{3206,7},constraint,[{atom,{3206,7},is_subtype},[{var,{3206,7},'Module'},{type,{3206,17},module,[]}]]},{type,{3207,7},constraint,[{atom,{3207,7},is_subtype},[{var,{3207,7},'Function'},{type,{3207,19},atom,[]}]]},{type,{3208,7},constraint,[{atom,{3208,7},is_subtype},[{var,{3208,7},'Args'},{type,{3208,15},list,[{type,{3208,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,49>>}},{{function,atom_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,451}],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121>>]},<<32>>]},{code,[],[<<40,65,116,111,109,44,32,117,116,102,56,41>>]},<<46>>]}]},#{signature => [{attribute,{451,2},spec,{{atom_to_binary,1},[{type,{451,21},bounded_fun,[{type,{451,21},'fun',[{type,{451,21},product,[{var,{451,22},'Atom'}]},{type,{451,31},binary,[]}]},[{type,{452,7},constraint,[{atom,{452,7},is_subtype},[{var,{452,7},'Atom'},{type,{452,15},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,49>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,atom_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,462}],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<65,116,111,109>>]},<<46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,98,121,116,101,32,101,120,105,115,116,115,32,102,111,114,32,101,97,99,104,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,111,114,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,85,84,70,45,56,32,119,104,101,114,101,32,99,104,97,114,97,99,116,101,114,115,32,109,97,121,32,114,101,113,117,105,114,101,32,109,117,108,116,105,112,108,101,32,98,121,116,101,115,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32,97,116,111,109,115,32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32>>,{code,[],[<<97,116,111,109,95,116,111,95,98,105,110,97,114,121,40,65,116,111,109,44,32,108,97,116,105,110,49,41>>]},<<32,109,97,121,32,102,97,105,108,32,105,102,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<65,116,111,109>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,62,32,50,53,53,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,98,105,110,97,114,121,40,39,69,114,108,97,110,103,39,44,32,108,97,116,105,110,49,41,46,10,60,60,34,69,114,108,97,110,103,34,62,62>>]}]}]},#{signature => [{attribute,{462,2},spec,{{atom_to_binary,2},[{type,{462,21},bounded_fun,[{type,{462,21},'fun',[{type,{462,21},product,[{var,{462,22},'Atom'},{var,{462,28},'Encoding'}]},{type,{462,41},binary,[]}]},[{type,{463,7},constraint,[{atom,{463,7},is_subtype},[{var,{463,7},'Atom'},{type,{463,15},atom,[]}]]},{type,{464,7},constraint,[{atom,{464,7},is_subtype},[{var,{464,7},'Encoding'},{type,{464,19},union,[{atom,{464,19},latin1},{atom,{464,28},unicode},{atom,{464,38},utf8}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,49>>}},{{function,atom_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,469}],[<<97,116,111,109,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,117,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<65,116,111,109>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,108,105,115,116,40,39,69,114,108,97,110,103,39,41,46,10,34,69,114,108,97,110,103,34>>]}]},{pre,[],[{code,[],[<<62,32,97,116,111,109,95,116,111,95,108,105,115,116,40,39,228,189,160,229,165,189,39,41,46,10,91,50,48,51,50,48,44,50,50,57,48,57,93>>]}]},{p,[],[<<83,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,105,99,111,100,101,40,51,41>>]}]},<<32,102,111,114,32,104,111,119,32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,32,116,111,32,100,105,102,102,101,114,101,110,116,32,102,111,114,109,97,116,115,46>>]}]},#{signature => [{attribute,{469,2},spec,{{atom_to_list,1},[{type,{469,19},bounded_fun,[{type,{469,19},'fun',[{type,{469,19},product,[{var,{469,20},'Atom'}]},{type,{469,29},string,[]}]},[{type,{470,7},constraint,[{atom,{470,7},is_subtype},[{var,{470,7},'Atom'},{type,{470,15},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,48,54>>}},{{function,binary_part,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,476}],[<<98,105,110,97,114,121,95,112,97,114,116,47,50>>],#{<<101,110>> => [{p,[],[<<69,120,116,114,97,99,116,115,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,100,101,115,99,114,105,98,101,100,32,98,121,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<46>>]},{p,[],[<<78,101,103,97,116,105,118,101,32,108,101,110,103,116,104,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,101,120,116,114,97,99,116,32,98,121,116,101,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,98,105,110,97,114,121,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<49,62,32,66,105,110,32,61,32,60,60,49,44,50,44,51,44,52,44,53,44,54,44,55,44,56,44,57,44,49,48,62,62,46,10,50,62,32,98,105,110,97,114,121,95,112,97,114,116,40,66,105,110,44,123,98,121,116,101,95,115,105,122,101,40,66,105,110,41,44,32,45,53,125,41,46,10,60,60,54,44,55,44,56,44,57,44,49,48,62,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<32,105,110,32,97,110,121,32,119,97,121,32,114,101,102,101,114,101,110,99,101,115,32,111,117,116,115,105,100,101,32,116,104,101,32,98,105,110,97,114,121,46>>]},{p,[],[{code,[],[<<83,116,97,114,116>>]},<<32,105,115,32,122,101,114,111,45,98,97,115,101,100,44,32,116,104,97,116,32,105,115,58>>]},{pre,[],[{code,[],[<<49,62,32,66,105,110,32,61,32,60,60,49,44,50,44,51,62,62,10,50,62,32,98,105,110,97,114,121,95,112,97,114,116,40,66,105,110,44,123,48,44,50,125,41,46,10,60,60,49,44,50,62,62>>]}]},{p,[],[<<70,111,114,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<80,111,115,76,101,110>>]},<<32,115,101,109,97,110,116,105,99,115,44,32,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,98,105,110,97,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<98,105,110,97,114,121,40,51,41>>]}]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{476,2},spec,{{binary_part,2},[{type,{476,18},bounded_fun,[{type,{476,18},'fun',[{type,{476,18},product,[{var,{476,19},'Subject'},{var,{476,28},'PosLen'}]},{type,{476,39},binary,[]}]},[{type,{477,7},constraint,[{atom,{477,7},is_subtype},[{var,{477,7},'Subject'},{type,{477,18},binary,[]}]]},{type,{478,7},constraint,[{atom,{478,7},is_subtype},[{var,{478,7},'PosLen'},{type,{478,17},tuple,[{ann_type,{478,18},[{var,{478,18},'Start'},{type,{478,27},non_neg_integer,[]}]},{ann_type,{478,46},[{var,{478,46},'Length'},{type,{478,56},integer,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,52>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,binary_part,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,484}],[<<98,105,110,97,114,121,95,112,97,114,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<98,105,110,97,114,121,95,112,97,114,116,40,83,117,98,106,101,99,116,44,32,123,83,116,97,114,116,44,32,76,101,110,103,116,104,125,41>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{484,2},spec,{{binary_part,3},[{type,{484,18},bounded_fun,[{type,{484,18},'fun',[{type,{484,18},product,[{var,{484,19},'Subject'},{var,{484,28},'Start'},{var,{484,35},'Length'}]},{type,{484,46},binary,[]}]},[{type,{485,7},constraint,[{atom,{485,7},is_subtype},[{var,{485,7},'Subject'},{type,{485,18},binary,[]}]]},{type,{486,7},constraint,[{atom,{486,7},is_subtype},[{var,{486,7},'Start'},{type,{486,16},non_neg_integer,[]}]]},{type,{487,7},constraint,[{atom,{487,7},is_subtype},[{var,{487,7},'Length'},{type,{487,17},integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,52,57>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,binary_to_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,492}],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109>>]},<<32>>]},{code,[],[<<40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<46>>]}]},#{signature => [{attribute,{492,2},spec,{{binary_to_atom,1},[{type,{492,21},bounded_fun,[{type,{492,21},'fun',[{type,{492,21},product,[{var,{492,22},'Binary'}]},{type,{492,33},atom,[]}]},[{type,{493,7},constraint,[{atom,{493,7},is_subtype},[{var,{493,7},'Binary'},{type,{493,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,57>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,binary_to_atom,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,502}],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46,32,73,102,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,111,114,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,98,105,110,97,114,121,32,109,117,115,116,32,99,111,110,116,97,105,110,32,118,97,108,105,100,32,85,84,70,45,56,32,115,101,113,117,101,110,99,101,115,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<32,105,115,32,99,97,112,97,98,108,101,32,111,102,32,100,101,99,111,100,105,110,103,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,46,32,69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,119,111,117,108,100,32,102,97,105,108,32,105,102,32,116,104,101,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,101,100,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,62,32,50,53,53,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,110,115,105,100,101,114,32,119,104,101,116,104,101,114,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>]},<<32,105,115,32,97,32,98,101,116,116,101,114,32,111,112,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,60,60,34,69,114,108,97,110,103,34,62,62,44,32,108,97,116,105,110,49,41,46,10,39,69,114,108,97,110,103,39>>]}]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,97,116,111,109,40,60,60,49,48,50,52,47,117,116,102,56,62,62,44,32,117,116,102,56,41,46,10,39,208,128,39>>]}]}]},#{signature => [{attribute,{502,2},spec,{{binary_to_atom,2},[{type,{502,21},bounded_fun,[{type,{502,21},'fun',[{type,{502,21},product,[{var,{502,22},'Binary'},{var,{502,30},'Encoding'}]},{type,{502,43},atom,[]}]},[{type,{503,7},constraint,[{atom,{503,7},is_subtype},[{var,{503,7},'Binary'},{type,{503,17},binary,[]}]]},{type,{504,7},constraint,[{atom,{504,7},is_subtype},[{var,{504,7},'Encoding'},{type,{504,19},union,[{atom,{504,19},latin1},{atom,{504,28},unicode},{atom,{504,38},utf8}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,54,57>>}},{{function,binary_to_existing_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,509}],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109>>]}]},<<32>>,{code,[],[<<40,66,105,110,97,114,121,44,32,117,116,102,56,41>>]},<<46>>]}]},#{signature => [{attribute,{509,2},spec,{{binary_to_existing_atom,1},[{type,{509,30},bounded_fun,[{type,{509,30},'fun',[{type,{509,30},product,[{var,{509,31},'Binary'}]},{type,{509,42},atom,[]}]},[{type,{510,7},constraint,[{atom,{510,7},is_subtype},[{var,{510,7},'Binary'},{type,{510,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,48,56>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,binary_to_existing_atom,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,519}],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,50>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]}]},<<44,32,98,117,116,32,116,104,101,32,97,116,111,109,32,109,117,115,116,32,101,120,105,115,116,46>>]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,104,97,115,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116>>]},<<32,102,111,114,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,44,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,110,111,116,32,115,97,102,101,32,116,111,32,99,114,101,97,116,101,32,109,97,110,121,32,97,116,111,109,115,32,102,114,111,109,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,99,111,109,101,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,105,108,101,32,102,101,116,99,104,101,100,32,102,114,111,109,32,116,104,101,32,73,110,116,101,114,110,101,116,41,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]}]},<<46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,117,115,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,111,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,105,110,112,117,116,32,98,105,110,97,114,121,32,99,111,109,101,115,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,46>>]},{p,[],[<<65,110,32,97,116,111,109,32,101,120,105,115,116,115,32,105,110,32,97,110,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,119,104,101,110,32,105,110,99,108,117,100,101,100,32,105,110,32,97,32,108,111,97,100,101,100,32,69,114,108,97,110,103,32,109,111,100,117,108,101,32,111,114,32,119,104,101,110,32,99,114,101,97,116,101,100,32,112,114,111,103,114,97,109,109,97,116,105,99,97,108,108,121,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,98,121,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,97,116,111,109,47,50>>]},<<41,46,32,83,101,101,32,116,104,101,32,110,101,120,116,32,110,111,116,101,32,102,111,114,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,119,104,101,110,32,97,110,32,97,116,111,109,32,101,120,105,115,116,115,32,105,110,32,116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,32,102,111,114,32,97,110,32,69,114,108,97,110,103,32,109,111,100,117,108,101,32,98,117,116,32,110,111,116,32,105,110,32,116,104,101,32,99,111,109,112,105,108,101,100,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,115,97,109,101,32,109,111,100,117,108,101,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,97,116,111,109,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,99,111,109,112,105,108,101,114,32,109,97,121,32,111,112,116,105,109,105,122,101,32,97,119,97,121,32,97,116,111,109,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,111,109,112,105,108,101,114,32,119,105,108,108,32,114,101,119,114,105,116,101,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,115,111,109,101,95,97,116,111,109,41>>]},<<32,116,111,32>>,{code,[],[<<34,115,111,109,101,95,97,116,111,109,34>>]},<<46,32,73,102,32,116,104,97,116,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,110,116,105,111,110,32,111,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,111,109,101,95,97,116,111,109>>]},<<32,105,110,32,116,104,101,32,99,111,110,116,97,105,110,105,110,103,32,109,111,100,117,108,101,44,32,116,104,101,32,97,116,111,109,32,119,105,108,108,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,108,111,97,100,101,100,44,32,97,110,100,32,97,32,115,117,98,115,101,113,117,101,110,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,40,60,60,34,115,111,109,101,95,97,116,111,109,34,62,62,44,32,117,116,102,56,41>>]},<<32,119,105,108,108,32,102,97,105,108,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]}]},#{signature => [{attribute,{519,2},spec,{{binary_to_existing_atom,2},[{type,{519,30},bounded_fun,[{type,{519,30},'fun',[{type,{519,30},product,[{var,{519,31},'Binary'},{var,{519,39},'Encoding'}]},{type,{519,52},atom,[]}]},[{type,{520,7},constraint,[{atom,{520,7},is_subtype},[{var,{520,7},'Binary'},{type,{520,17},binary,[]}]]},{type,{521,7},constraint,[{atom,{521,7},is_subtype},[{var,{521,7},'Encoding'},{type,{521,19},union,[{atom,{521,19},latin1},{atom,{521,28},unicode},{atom,{521,38},utf8}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,49,57>>}},{{function,binary_to_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,526}],[<<98,105,110,97,114,121,95,116,111,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,102,108,111,97,116,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,102,108,111,97,116,40,60,60,34,50,46,50,48,49,55,55,54,52,101,43,48,34,62,62,41,46,10,50,46,50,48,49,55,55,54,52>>]}]},{p,[],[<<84,104,101,32,102,108,111,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,102,111,114,109,97,116,32,102,111,114,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,102,108,111,97,116,32,108,105,116,101,114,97,108,115>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,97,116,32,117,110,100,101,114,115,99,111,114,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,102,108,111,97,116,46>>]}]},#{signature => [{attribute,{526,2},spec,{{binary_to_float,1},[{type,{526,22},bounded_fun,[{type,{526,22},'fun',[{type,{526,22},product,[{var,{526,23},'Binary'}]},{type,{526,34},float,[]}]},[{type,{527,7},constraint,[{atom,{527,7},is_subtype},[{var,{527,7},'Binary'},{type,{527,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,54,51>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,532}],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,40,60,60,34,49,50,51,34,62,62,41,46,10,49,50,51>>]}]},{p,[],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,49>>]},<<32,97,99,99,101,112,116,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,102,111,114,109,97,116,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{532,2},spec,{{binary_to_integer,1},[{type,{532,24},bounded_fun,[{type,{532,24},'fun',[{type,{532,24},product,[{var,{532,25},'Binary'}]},{type,{532,36},integer,[]}]},[{type,{533,7},constraint,[{atom,{533,7},is_subtype},[{var,{533,7},'Binary'},{type,{533,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,56,49>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_integer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,550}],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,40,60,60,34,51,70,70,34,62,62,44,32,49,54,41,46,10,49,48,50,51>>]}]},{p,[],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,105,110,116,101,103,101,114,47,50>>]},<<32,97,99,99,101,112,116,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,102,111,114,109,97,116,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{550,2},spec,{{binary_to_integer,2},[{type,{550,24},bounded_fun,[{type,{550,24},'fun',[{type,{550,24},product,[{var,{550,25},'Binary'},{var,{550,33},'Base'}]},{type,{550,42},integer,[]}]},[{type,{551,7},constraint,[{atom,{551,7},is_subtype},[{var,{551,7},'Binary'},{type,{551,17},binary,[]}]]},{type,{552,7},constraint,[{atom,{552,7},is_subtype},[{var,{552,7},'Base'},{type,{552,15},range,[{integer,{552,15},2},{integer,{552,18},36}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,57,56>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,binary_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,711}],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,111,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46>>]}]},#{signature => [{attribute,{711,2},spec,{{binary_to_list,1},[{type,{711,21},bounded_fun,[{type,{711,21},'fun',[{type,{711,21},product,[{var,{711,22},'Binary'}]},{type,{711,33},list,[{type,{711,34},byte,[]}]}]},[{type,{712,7},constraint,[{atom,{712,7},is_subtype},[{var,{712,7},'Binary'},{type,{712,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,49,54>>}},{{function,binary_to_list,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,717}],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>]},<<44,32,98,117,116,32,114,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,102,114,111,109,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<83,116,97,114,116>>]},<<32,116,111,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<83,116,111,112>>]},<<32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46,32,84,104,101,32,112,111,115,105,116,105,111,110,115,32,105,110,32,116,104,101,32,98,105,110,97,114,121,32,97,114,101,32,110,117,109,98,101,114,101,100,32,115,116,97,114,116,105,110,103,32,102,114,111,109,32,49,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{em,[],[<<84,104,101,32,111,110,101,45,98,97,115,101,100,32,105,110,100,101,120,105,110,103,32,102,111,114,32,98,105,110,97,114,105,101,115,32,117,115,101,100,32,98,121,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,78,101,119,32,99,111,100,101,32,105,115,32,116,111,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,98,105,110,97,114,121,35,98,105,110,95,116,111,95,108,105,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,58,98,105,110,95,116,111,95,108,105,115,116,47,51>>]}]},<<32,105,110,32,83,84,68,76,73,66,32,105,110,115,116,101,97,100,46,32,65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,99,111,110,115,105,115,116,101,110,116,108,121,32,117,115,101,32,122,101,114,111,45,98,97,115,101,100,32,105,110,100,101,120,105,110,103,46>>]}]}]},#{signature => [{attribute,{717,2},spec,{{binary_to_list,3},[{type,{717,21},bounded_fun,[{type,{717,21},'fun',[{type,{717,21},product,[{var,{717,22},'Binary'},{var,{717,30},'Start'},{var,{717,37},'Stop'}]},{type,{717,46},list,[{type,{717,47},byte,[]}]}]},[{type,{718,7},constraint,[{atom,{718,7},is_subtype},[{var,{718,7},'Binary'},{type,{718,17},binary,[]}]]},{type,{719,7},constraint,[{atom,{719,7},is_subtype},[{var,{719,7},'Start'},{type,{719,16},pos_integer,[]}]]},{type,{720,7},constraint,[{atom,{720,7},is_subtype},[{var,{720,7},'Stop'},{type,{720,15},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,50,53>>}},{{function,binary_to_term,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,725}],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,100,101,99,111,100,105,110,103,32,98,105,110,97,114,121,32,111,98,106,101,99,116,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<44,32,119,104,105,99,104,32,109,117,115,116,32,98,101,32,101,110,99,111,100,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116>>]},<<46>>]},{pre,[],[{code,[],[<<62,32,66,105,110,32,61,32,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,104,101,108,108,111,41,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,10,62,32,104,101,108,108,111,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,66,105,110,41,46,10,104,101,108,108,111>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<87,104,101,110,32,100,101,99,111,100,105,110,103,32,98,105,110,97,114,105,101,115,32,102,114,111,109,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,115,44,32,116,104,101,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,32,109,97,121,32,115,117,98,109,105,116,32,100,97,116,97,32,105,110,32,97,32,119,97,121,32,116,111,32,99,114,101,97,116,101,32,114,101,115,111,117,114,99,101,115,44,32,115,117,99,104,32,97,115,32,97,116,111,109,115,32,97,110,100,32,114,101,109,111,116,101,32,114,101,102,101,114,101,110,99,101,115,44,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,32,97,110,100,32,108,101,97,100,32,116,111,32,68,101,110,105,97,108,32,111,102,32,83,101,114,118,105,99,101,32,97,116,116,97,99,107,46,32,73,110,32,115,117,99,104,32,99,97,115,101,115,44,32,99,111,110,115,105,100,101,114,32,117,115,105,110,103,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>]},<<32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<115,97,102,101>>]},<<32,111,112,116,105,111,110,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{725,2},spec,{{binary_to_term,1},[{type,{725,21},bounded_fun,[{type,{725,21},'fun',[{type,{725,21},product,[{var,{725,22},'Binary'}]},{type,{725,33},term,[]}]},[{type,{726,7},constraint,[{atom,{726,7},is_subtype},[{var,{726,7},'Binary'},{user_type,{726,17},ext_binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,52,55>>}},{{function,binary_to_term,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,731}],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,50>>],#{<<101,110>> => [{p,[],[<<65,115,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<44,32,98,117,116,32,116,97,107,101,115,32,116,104,101,115,101,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,97,102,101>>]}]},{dd,[],[{p,[],[<<85,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,119,104,101,110,32,114,101,99,101,105,118,105,110,103,32,98,105,110,97,114,105,101,115,32,102,114,111,109,32,97,110,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,46>>]},{p,[],[<<87,104,101,110,32,101,110,97,98,108,101,100,44,32,105,116,32,112,114,101,118,101,110,116,115,32,100,101,99,111,100,105,110,103,32,100,97,116,97,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,116,116,97,99,107,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,46,32,73,110,32,116,104,101,32,101,118,101,110,116,32,111,102,32,114,101,99,101,105,118,105,110,103,32,117,110,115,97,102,101,32,100,97,116,97,44,32,100,101,99,111,100,105,110,103,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,114,114,111,114,46>>]},{p,[],[<<84,104,105,115,32,112,114,101,118,101,110,116,115,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,97,116,111,109,115,32,100,105,114,101,99,116,108,121,44,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,97,116,111,109,115,32,105,110,100,105,114,101,99,116,108,121,32,40,97,115,32,116,104,101,121,32,97,114,101,32,101,109,98,101,100,100,101,100,32,105,110,32,99,101,114,116,97,105,110,32,115,116,114,117,99,116,117,114,101,115,44,32,115,117,99,104,32,97,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,114,101,102,115,44,32,97,110,100,32,102,117,110,115,41,44,32,97,110,100,32,99,114,101,97,116,105,111,110,32,111,102,32,110,101,119,32,101,120,116,101,114,110,97,108,32,102,117,110,99,116,105,111,110,32,114,101,102,101,114,101,110,99,101,115,46,32,78,111,110,101,32,111,102,32,116,104,111,115,101,32,114,101,115,111,117,114,99,101,115,32,97,114,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,44,32,115,111,32,117,110,99,104,101,99,107,101,100,32,99,114,101,97,116,105,111,110,32,111,102,32,116,104,101,109,32,99,97,110,32,101,120,104,97,117,115,116,32,97,118,97,105,108,97,98,108,101,32,109,101,109,111,114,121,46>>]},{pre,[],[{code,[],[<<62,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,62,62,44,32,91,115,97,102,101,93,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,114,114,111,114,58,32,98,97,100,32,97,114,103,117,109,101,110,116,10,62,32,104,101,108,108,111,46,10,104,101,108,108,111,10,62,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,62,62,44,32,91,115,97,102,101,93,41,46,10,104,101,108,108,111>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,32>>,{code,[],[<<115,97,102,101>>]},<<32,111,112,116,105,111,110,32,101,110,115,117,114,101,115,32,116,104,101,32,100,97,116,97,32,105,115,32,115,97,102,101,108,121,32,112,114,111,99,101,115,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,98,117,116,32,105,116,32,100,111,101,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,32,116,104,101,32,100,97,116,97,32,105,115,32,115,97,102,101,32,116,111,32,121,111,117,114,32,97,112,112,108,105,99,97,116,105,111,110,46,32,89,111,117,32,109,117,115,116,32,97,108,119,97,121,115,32,118,97,108,105,100,97,116,101,32,100,97,116,97,32,102,114,111,109,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,115,46,32,73,102,32,116,104,101,32,98,105,110,97,114,121,32,105,115,32,115,116,111,114,101,100,32,111,114,32,116,114,97,110,115,105,116,115,32,116,104,114,111,117,103,104,32,117,110,116,114,117,115,116,101,100,32,115,111,117,114,99,101,115,44,32,121,111,117,32,115,104,111,117,108,100,32,97,108,115,111,32,99,111,110,115,105,100,101,114,32,99,114,121,112,116,111,103,114,97,112,104,105,99,97,108,108,121,32,115,105,103,110,105,110,103,32,105,116,46>>]}]}]},{dt,[],[{code,[],[<<117,115,101,100>>]}]},{dd,[],[{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<123,84,101,114,109,44,32,85,115,101,100,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<85,115,101,100>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,97,99,116,117,97,108,108,121,32,114,101,97,100,32,102,114,111,109,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<46>>]},{pre,[],[{code,[],[<<62,32,73,110,112,117,116,32,61,32,60,60,49,51,49,44,49,48,48,44,48,44,53,44,34,104,101,108,108,111,34,44,34,119,111,114,108,100,34,62,62,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,44,49,49,57,44,49,49,49,44,49,49,52,44,49,48,56,44,49,48,48,62,62,10,62,32,123,84,101,114,109,44,32,85,115,101,100,125,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,73,110,112,117,116,44,32,91,117,115,101,100,93,41,46,10,123,104,101,108,108,111,44,32,57,125,10,62,32,115,112,108,105,116,95,98,105,110,97,114,121,40,73,110,112,117,116,44,32,85,115,101,100,41,46,10,123,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,44,32,60,60,34,119,111,114,108,100,34,62,62,125>>]}]}]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<115,97,102,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,110,100,32,117,110,115,97,102,101,32,100,97,116,97,32,105,115,32,100,101,99,111,100,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{731,2},spec,{{binary_to_term,2},[{type,{731,21},bounded_fun,[{type,{731,21},'fun',[{type,{731,21},product,[{var,{731,22},'Binary'},{var,{731,30},'Opts'}]},{type,{731,39},union,[{type,{731,39},term,[]},{type,{731,48},tuple,[{type,{731,49},term,[]},{var,{731,57},'Used'}]}]}]},[{type,{732,7},constraint,[{atom,{732,7},is_subtype},[{var,{732,7},'Binary'},{user_type,{732,17},ext_binary,[]}]]},{type,{733,7},constraint,[{atom,{733,7},is_subtype},[{var,{733,7},'Opt'},{type,{733,14},union,[{atom,{733,14},safe},{atom,{733,21},used}]}]]},{type,{734,7},constraint,[{atom,{734,7},is_subtype},[{var,{734,7},'Opts'},{type,{734,15},list,[{var,{734,16},'Opt'}]}]]},{type,{735,7},constraint,[{atom,{735,7},is_subtype},[{var,{735,7},'Used'},{type,{735,15},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,55,54>>,since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,bit_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,741}],[<<98,105,116,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,105,116,115,32,111,102,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,98,105,116,95,115,105,122,101,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,49,57,10,62,32,98,105,116,95,115,105,122,101,40,60,60,49,44,50,44,51,62,62,41,46,10,50,52>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{741,2},spec,{{bit_size,1},[{type,{741,15},bounded_fun,[{type,{741,15},'fun',[{type,{741,15},product,[{var,{741,16},'Bitstring'}]},{type,{741,30},non_neg_integer,[]}]},[{type,{742,7},constraint,[{atom,{742,7},is_subtype},[{var,{742,7},'Bitstring'},{type,{742,20},bitstring,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,51,57>>}},{{function,bitstring_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,747}],[<<98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,121,116,101,115,32,111,102,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32,116,104,101,32,98,105,110,97,114,121,32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,108,105,115,116,32,105,115,32,97,32,98,105,116,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,49,45,55,32,98,105,116,115,46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,40,60,60,52,51,51,58,49,54,62,62,41,46,10,91,49,44,49,55,55,93>>]}]},{pre,[],[{code,[],[<<62,32,98,105,116,115,116,114,105,110,103,95,116,111,95,108,105,115,116,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,91,49,44,49,55,55,44,60,60,51,58,51,62,62,93>>]}]}]},#{signature => [{attribute,{747,2},spec,{{bitstring_to_list,1},[{type,{747,24},bounded_fun,[{type,{747,24},'fun',[{type,{747,24},product,[{var,{747,25},'Bitstring'}]},{type,{747,39},list,[{type,{747,40},union,[{type,{747,40},byte,[]},{type,{747,49},bitstring,[]}]}]}]},[{type,{748,7},constraint,[{atom,{748,7},is_subtype},[{var,{748,7},'Bitstring'},{type,{748,20},bitstring,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,53,52>>}},{{function,bump_reductions,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,753}],[<<98,117,109,112,95,114,101,100,117,99,116,105,111,110,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,105,115,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,99,114,101,109,101,110,116,115,32,116,104,101,32,114,101,100,117,99,116,105,111,110,32,99,111,117,110,116,101,114,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,73,110,32,116,104,101,32,66,101,97,109,32,101,109,117,108,97,116,111,114,44,32,116,104,101,32,114,101,100,117,99,116,105,111,110,32,99,111,117,110,116,101,114,32,105,115,32,110,111,114,109,97,108,108,121,32,105,110,99,114,101,109,101,110,116,101,100,32,98,121,32,111,110,101,32,102,111,114,32,101,97,99,104,32,102,117,110,99,116,105,111,110,32,97,110,100,32,66,73,70,32,99,97,108,108,46,32,65,32,99,111,110,116,101,120,116,32,115,119,105,116,99,104,32,105,115,32,102,111,114,99,101,100,32,119,104,101,110,32,116,104,101,32,99,111,117,110,116,101,114,32,114,101,97,99,104,101,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,102,111,114,32,97,32,112,114,111,99,101,115,115,32,40,52,48,48,48,32,114,101,100,117,99,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103,47,79,84,80,32,49,57,46,50,32,97,110,100,32,108,97,116,101,114,41,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,99,97,110,32,98,101,32,114,101,109,111,118,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,66,101,97,109,32,109,97,99,104,105,110,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,119,97,114,110,105,110,103,46,32,73,116,32,105,115,32,117,110,108,105,107,101,108,121,32,116,111,32,98,101,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,111,116,104,101,114,32,69,114,108,97,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,46>>]}]}]},#{signature => [{attribute,{753,2},spec,{{erlang,bump_reductions,1},[{type,{753,29},bounded_fun,[{type,{753,29},'fun',[{type,{753,29},product,[{var,{753,30},'Reductions'}]},{atom,{753,45},true}]},[{type,{754,7},constraint,[{atom,{754,7},is_subtype},[{var,{754,7},'Reductions'},{type,{754,21},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,55,49>>}},{{function,byte_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,760}],[<<98,121,116,101,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,110,101,101,100,101,100,32,116,111,32,99,111,110,116,97,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103>>]},<<32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,115,32,114,111,117,110,100,101,100,32>>,{em,[],[<<117,112>>]},<<46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,98,121,116,101,95,115,105,122,101,40,60,60,52,51,51,58,49,54,44,51,58,51,62,62,41,46,10,51,10,62,32,98,121,116,101,95,115,105,122,101,40,60,60,49,44,50,44,51,62,62,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{760,2},spec,{{byte_size,1},[{type,{760,16},bounded_fun,[{type,{760,16},'fun',[{type,{760,16},product,[{var,{760,17},'Bitstring'}]},{type,{760,31},non_neg_integer,[]}]},[{type,{761,7},constraint,[{atom,{761,7},is_subtype},[{var,{761,7},'Bitstring'},{type,{761,20},bitstring,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,57>>}},{{function,cancel_timer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,772}],[<<99,97,110,99,101,108,95,116,105,109,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<67,97,110,99,101,108,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,84,105,109,101,114,82,101,102,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{772,2},spec,{{erlang,cancel_timer,1},[{type,{772,26},bounded_fun,[{type,{772,26},'fun',[{type,{772,26},product,[{var,{772,27},'TimerRef'}]},{var,{772,40},'Result'}]},[{type,{773,7},constraint,[{atom,{773,7},is_subtype},[{var,{773,7},'TimerRef'},{type,{773,19},reference,[]}]]},{type,{774,7},constraint,[{atom,{774,7},is_subtype},[{var,{774,7},'Time'},{type,{774,15},non_neg_integer,[]}]]},{type,{775,7},constraint,[{atom,{775,7},is_subtype},[{var,{775,7},'Result'},{type,{775,17},union,[{var,{775,17},'Time'},{atom,{775,24},false}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,48,54>>}},{{function,cancel_timer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,781}],[<<99,97,110,99,101,108,95,116,105,109,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,110,99,101,108,115,32,97,32,116,105,109,101,114,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114>>]}]},<<46,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,105,100,101,110,116,105,102,105,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,119,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,66,73,70,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,116,105,109,101,114,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,65,115,121,110,99,125>>]}]},{dd,[],[{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,99,97,110,99,101,108,108,97,116,105,111,110,46,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,32,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,99,97,110,99,101,108,32,111,112,101,114,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<32,115,101,110,100,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,99,97,110,99,101,108,108,97,116,105,111,110,32,116,111,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,105,110,102,111,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<82,101,113,117,101,115,116,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,111,102,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,103,105,118,101,110,46,32,87,104,101,110,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,105,115,32,103,105,118,101,110,46>>]},{ul,[],[{li,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<58,32,105,102,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<46,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<111,107>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{li,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<58,32,105,102,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,99,97,110,99,101,108,95,116,105,109,101,114,44,32,84,105,109,101,114,82,101,102,44,32,82,101,115,117,108,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,40,41>>]},<<32,119,104,101,110,32,116,104,101,32,99,97,110,99,101,108,108,97,116,105,111,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,44,32,111,116,104,101,114,119,105,115,101,32,110,111,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]}]}]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,109,97,121,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,105,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32,108,101,102,116,32,117,110,116,105,108,32,116,104,101,32,99,97,110,99,101,108,101,100,32,116,105,109,101,114,32,119,111,117,108,100,32,104,97,118,101,32,101,120,112,105,114,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,97,32,116,105,109,101,114,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,102,111,117,110,100,46,32,84,104,105,115,32,99,97,110,32,98,101,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,97,108,114,101,97,100,121,32,104,97,100,32,98,101,101,110,32,99,97,110,99,101,108,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,110,101,118,101,114,32,99,111,114,114,101,115,112,111,110,100,101,100,32,116,111,32,97,32,116,105,109,101,114,46,32,69,118,101,110,32,105,102,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,108,108,32,121,111,117,32,105,102,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,32,104,97,115,32,97,114,114,105,118,101,100,32,97,116,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,32,121,101,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,32,99,97,110,32,98,101,32,99,111,45,108,111,99,97,116,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32,115,99,104,101,100,117,108,101,114,32,116,104,97,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32,73,102,32,115,111,44,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,116,105,109,101,32,116,104,97,110,32,105,102,32,105,116,32,105,115,32,108,111,99,97,116,101,100,32,108,111,99,97,108,108,121,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,105,110,32,99,114,105,116,105,99,97,108,32,112,97,116,104,44,32,97,110,100,32,99,97,110,32,100,111,32,111,116,104,101,114,32,116,104,105,110,103,115,32,119,104,105,108,101,32,119,97,105,116,105,110,103,32,102,111,114,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,44,32,111,114,32,105,115,32,110,111,116,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,116,114,117,101,125>>]},<<46,32,73,102,32,117,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,102,97,108,115,101,125>>]},<<44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,98,108,111,99,107,115,32,117,110,116,105,108,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{781,2},spec,{{erlang,cancel_timer,2},[{type,{781,26},bounded_fun,[{type,{781,26},'fun',[{type,{781,26},product,[{var,{781,27},'TimerRef'},{var,{781,37},'Options'}]},{type,{781,49},union,[{var,{781,49},'Result'},{atom,{781,58},ok}]}]},[{type,{782,7},constraint,[{atom,{782,7},is_subtype},[{var,{782,7},'TimerRef'},{type,{782,19},reference,[]}]]},{type,{783,7},constraint,[{atom,{783,7},is_subtype},[{var,{783,7},'Async'},{type,{783,16},boolean,[]}]]},{type,{784,7},constraint,[{atom,{784,7},is_subtype},[{var,{784,7},'Info'},{type,{784,15},boolean,[]}]]},{type,{785,7},constraint,[{atom,{785,7},is_subtype},[{var,{785,7},'Option'},{type,{785,17},union,[{type,{785,17},tuple,[{atom,{785,18},async},{var,{785,25},'Async'}]},{type,{785,34},tuple,[{atom,{785,35},info},{var,{785,41},'Info'}]}]}]]},{type,{786,7},constraint,[{atom,{786,7},is_subtype},[{var,{786,7},'Options'},{type,{786,18},list,[{var,{786,19},'Option'}]}]]},{type,{787,7},constraint,[{atom,{787,7},is_subtype},[{var,{787,7},'Time'},{type,{787,15},non_neg_integer,[]}]]},{type,{788,7},constraint,[{atom,{788,7},is_subtype},[{var,{788,7},'Result'},{type,{788,17},union,[{var,{788,17},'Time'},{atom,{788,24},false}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,49,54>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,ceil,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,795}],[<<99,101,105,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,105,110,116,101,103,101,114,32,110,111,116,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,101,105,108,40,53,46,53,41,46,10,54>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{795,2},spec,{{ceil,1},[{type,{795,11},bounded_fun,[{type,{795,11},'fun',[{type,{795,11},product,[{var,{795,12},'Number'}]},{type,{795,23},integer,[]}]},[{type,{796,7},constraint,[{atom,{796,7},is_subtype},[{var,{796,7},'Number'},{type,{796,17},number,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,57,56>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,check_old_code,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,801}],[<<99,104,101,99,107,95,111,108,100,95,99,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,104,97,115,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,99,111,100,101,95,108,111,97,100,105,110,103,35,99,111,100,101,45,114,101,112,108,97,99,101,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<111,108,100,32,99,111,100,101>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{801,2},spec,{{check_old_code,1},[{type,{801,21},bounded_fun,[{type,{801,21},'fun',[{type,{801,21},product,[{var,{801,22},'Module'}]},{type,{801,33},boolean,[]}]},[{type,{802,7},constraint,[{atom,{802,7},is_subtype},[{var,{802,7},'Module'},{type,{802,17},module,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,49,49>>,since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,check_process_code,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,807}],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,40,80,105,100,44,32,77,111,100,117,108,101,44,32,91,93,41>>]},<<32>>]},<<46>>]}]},#{signature => [{attribute,{807,2},spec,{{check_process_code,2},[{type,{807,25},bounded_fun,[{type,{807,25},'fun',[{type,{807,25},product,[{var,{807,26},'Pid'},{var,{807,31},'Module'}]},{var,{807,42},'CheckResult'}]},[{type,{808,7},constraint,[{atom,{808,7},is_subtype},[{var,{808,7},'Pid'},{type,{808,14},pid,[]}]]},{type,{809,7},constraint,[{atom,{809,7},is_subtype},[{var,{809,7},'Module'},{type,{809,17},module,[]}]]},{type,{810,7},constraint,[{atom,{810,7},is_subtype},[{var,{810,7},'CheckResult'},{type,{810,22},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,50,50>>}},{{function,check_process_code,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,819}],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,101,99,107,115,32,105,102,32,116,104,101,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,98,111,111,108,101,97,110,40,41,125>>]}]},{dd,[],[{p,[],[<<68,101,116,101,114,109,105,110,101,115,32,105,102,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,108,108,111,119,101,100,32,119,104,101,110,32,112,101,114,102,111,114,109,105,110,103,32,116,104,101,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,102,97,108,115,101,125>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,97,110,100,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,110,101,101,100,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,97,98,111,114,116,101,100,32,40,115,101,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32>>,{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,98,101,108,111,119,41,46,32,84,104,101,32,100,101,102,97,117,108,116,32,105,115,32,116,111,32,97,108,108,111,119,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,44,32,116,104,97,116,32,105,115,44,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,116,114,117,101,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,82,101,113,117,101,115,116,73,100,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,51>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,101,110,116,46,32,87,104,101,110,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,112,97,115,115,101,100,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,44,32,82,101,113,117,101,115,116,73,100,44,32,67,104,101,99,107,82,101,115,117,108,116,125>>]},<<46>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<44,32,97,110,100,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,116,32,111,110,99,101,46,32,79,116,104,101,114,119,105,115,101,32,97,32,114,101,113,117,101,115,116,32,102,111,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,110,100,32,105,115,32,104,97,110,100,108,101,100,32,119,104,101,110,32,97,112,112,114,111,112,114,105,97,116,101,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,98,108,111,99,107,115,32,117,110,116,105,108,32>>,{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,105,115,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<67,104,101,99,107,82,101,115,117,108,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,114,101,113,117,101,115,116,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,99,111,110,116,97,105,110,115,32,102,117,110,115,32,116,104,97,116,32,114,101,102,101,114,101,110,99,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,101,99,117,116,101,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,98,111,114,116,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,97,98,111,114,116,101,100,44,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,110,101,101,100,101,100,32,116,111,32,98,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,114,101,115,117,108,116,44,32,97,110,100,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,114,101,113,117,101,115,116,101,100,32,98,121,32,112,97,115,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,108,108,111,119,95,103,99,44,32,102,97,108,115,101,125>>]},<<46>>]}]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<85,112,32,117,110,116,105,108,32,69,82,84,83,32,118,101,114,115,105,111,110,32,56,46,42,44,32,116,104,101,32,99,104,101,99,107,32,112,114,111,99,101,115,115,32,99,111,100,101,32,111,112,101,114,97,116,105,111,110,32,99,104,101,99,107,115,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,111,108,100,32,99,111,100,101,46,32,84,104,97,116,32,105,115,44,32,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,40,101,46,103,46,32,114,101,116,117,114,110,32,97,100,100,114,101,115,115,101,115,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,41,44,32,105,110,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,40>>,{code,[],[<<102,117,110>>]},<<115,32,105,110,32,112,114,111,99,101,115,115,32,99,111,110,116,101,120,116,41,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,108,105,116,101,114,97,108,115,32,105,110,32,116,104,101,32,99,111,100,101,46>>]},{p,[],[<<65,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,57,46,48,44,32,116,104,101,32,99,104,101,99,107,32,112,114,111,99,101,115,115,32,99,111,100,101,32,111,112,101,114,97,116,105,111,110,32,111,110,108,121,32,99,104,101,99,107,115,32,102,111,114,32,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,99,111,100,101,46,32,73,110,100,105,114,101,99,116,32,114,101,102,101,114,101,110,99,101,115,32,118,105,97,32>>,{code,[],[<<102,117,110>>]},<<115,32,119,105,108,108,32,98,101,32,105,103,110,111,114,101,100,46,32,73,102,32,115,117,99,104,32>>,{code,[],[<<102,117,110>>]},<<115,32,101,120,105,115,116,32,97,110,100,32,97,114,101,32,117,115,101,100,32,97,102,116,101,114,32,97,32,112,117,114,103,101,32,111,102,32,116,104,101,32,111,108,100,32,99,111,100,101,44,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,105,108,108,32,98,101,32,114,97,105,115,101,100,32,117,112,111,110,32,117,115,97,103,101,32,40,115,97,109,101,32,97,115,32,116,104,101,32,99,97,115,101,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<102,117,110>>]},<<32,105,115,32,114,101,99,101,105,118,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,97,102,116,101,114,32,116,104,101,32,112,117,114,103,101,41,46,32,76,105,116,101,114,97,108,115,32,119,105,108,108,32,98,101,32,116,97,107,101,110,32,99,97,114,101,32,111,102,32,40,99,111,112,105,101,100,41,32,97,116,32,97,32,108,97,116,101,114,32,115,116,97,103,101,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,99,97,110,32,97,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,56,46,49,32,98,101,32,101,110,97,98,108,101,100,32,119,104,101,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,105,110,115,116,97,108,108,97,116,105,111,110,95,103,117,105,100,101,58,73,78,83,84,65,76,76,35,65,100,118,97,110,99,101,100,45,99,111,110,102,105,103,117,114,97,116,105,111,110,45,97,110,100,45,98,117,105,108,100,45,111,102,45,69,114,108,97,110,103,79,84,80,95,67,111,110,102,105,103,117,114,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<98,117,105,108,100,105,110,103,32,79,84,80>>]},<<44,32,97,110,100,32,119,105,108,108,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,98,101,32,101,110,97,98,108,101,100,32,105,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,32,115,117,112,112,111,114,116,32,105,115,32,101,110,97,98,108,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46>>]}]}]},#{signature => [{attribute,{819,2},spec,{{check_process_code,3},[{type,{819,25},bounded_fun,[{type,{819,25},'fun',[{type,{819,25},product,[{var,{819,26},'Pid'},{var,{819,31},'Module'},{var,{819,39},'OptionList'}]},{type,{819,54},union,[{var,{819,54},'CheckResult'},{atom,{819,68},async}]}]},[{type,{820,7},constraint,[{atom,{820,7},is_subtype},[{var,{820,7},'Pid'},{type,{820,14},pid,[]}]]},{type,{821,7},constraint,[{atom,{821,7},is_subtype},[{var,{821,7},'Module'},{type,{821,17},module,[]}]]},{type,{822,7},constraint,[{atom,{822,7},is_subtype},[{var,{822,7},'RequestId'},{type,{822,20},term,[]}]]},{type,{823,7},constraint,[{atom,{823,7},is_subtype},[{var,{823,7},'Option'},{type,{823,17},union,[{type,{823,17},tuple,[{atom,{823,18},async},{var,{823,25},'RequestId'}]},{type,{823,38},tuple,[{atom,{823,39},allow_gc},{type,{823,49},boolean,[]}]}]}]]},{type,{824,7},constraint,[{atom,{824,7},is_subtype},[{var,{824,7},'OptionList'},{type,{824,21},list,[{var,{824,22},'Option'}]}]]},{type,{825,7},constraint,[{atom,{825,7},is_subtype},[{var,{825,7},'CheckResult'},{type,{825,22},union,[{type,{825,22},boolean,[]},{atom,{825,34},aborted}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,51,51>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,convert_time_unit,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1848}],[<<99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,111,102,32,116,105,109,101,32,117,110,105,116,32>>,{code,[],[<<70,114,111,109,85,110,105,116>>]},<<32,116,111,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<67,111,110,118,101,114,116,101,100,84,105,109,101>>]},<<32,118,97,108,117,101,32,111,102,32,116,105,109,101,32,117,110,105,116,32>>,{code,[],[<<84,111,85,110,105,116>>]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,105,115,32,114,111,117,110,100,101,100,32,117,115,105,110,103,32,116,104,101,32,102,108,111,111,114,32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<89,111,117,32,99,97,110,32,108,111,115,101,32,97,99,99,117,114,97,99,121,32,97,110,100,32,112,114,101,99,105,115,105,111,110,32,119,104,101,110,32,99,111,110,118,101,114,116,105,110,103,32,98,101,116,119,101,101,110,32,116,105,109,101,32,117,110,105,116,115,46,32,84,111,32,109,105,110,105,109,105,122,101,32,115,117,99,104,32,108,111,115,115,44,32,99,111,108,108,101,99,116,32,97,108,108,32,100,97,116,97,32,97,116,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,97,110,100,32,100,111,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,111,110,32,116,104,101,32,101,110,100,32,114,101,115,117,108,116,46>>]}]}]},#{signature => [{attribute,{1848,2},spec,{{erlang,convert_time_unit,3},[{type,{1848,31},bounded_fun,[{type,{1848,31},'fun',[{type,{1848,31},product,[{var,{1848,32},'Time'},{var,{1848,38},'FromUnit'},{var,{1848,48},'ToUnit'}]},{var,{1848,59},'ConvertedTime'}]},[{type,{1849,7},constraint,[{atom,{1849,7},is_subtype},[{var,{1849,7},'Time'},{type,{1849,15},integer,[]}]]},{type,{1850,7},constraint,[{atom,{1850,7},is_subtype},[{var,{1850,7},'ConvertedTime'},{type,{1850,24},integer,[]}]]},{type,{1851,7},constraint,[{atom,{1851,7},is_subtype},[{var,{1851,7},'FromUnit'},{user_type,{1851,19},time_unit,[]}]]},{type,{1852,7},constraint,[{atom,{1852,7},is_subtype},[{var,{1852,7},'ToUnit'},{user_type,{1852,17},time_unit,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,51,54>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,crc32,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,837}],[<<99,114,99,51,50,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,99,114,99,51,50,32,40,73,69,69,69,32,56,48,50,46,51,32,115,116,121,108,101,41,32,99,104,101,99,107,115,117,109,32,102,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]}]},#{signature => [{attribute,{837,2},spec,{{erlang,crc32,1},[{type,{837,19},bounded_fun,[{type,{837,19},'fun',[{type,{837,19},product,[{var,{837,20},'Data'}]},{type,{837,29},non_neg_integer,[]}]},[{type,{838,7},constraint,[{atom,{838,7},is_subtype},[{var,{838,7},'Data'},{type,{838,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,53,52>>}},{{function,crc32,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,843}],[<<99,114,99,51,50,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,116,105,110,117,101,115,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,99,114,99,51,50,32,99,104,101,99,107,115,117,109,32,98,121,32,99,111,109,98,105,110,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,101,99,107,115,117,109,44,32>>,{code,[],[<<79,108,100,67,114,99>>]},<<44,32,119,105,116,104,32,116,104,101,32,99,104,101,99,107,115,117,109,32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,88,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<89>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,91,68,97,116,97,49,44,68,97,116,97,50,93,41,46>>]}]}]},#{signature => [{attribute,{843,2},spec,{{erlang,crc32,2},[{type,{843,19},bounded_fun,[{type,{843,19},'fun',[{type,{843,19},product,[{var,{843,20},'OldCrc'},{var,{843,28},'Data'}]},{type,{843,37},non_neg_integer,[]}]},[{type,{844,7},constraint,[{atom,{844,7},is_subtype},[{var,{844,7},'OldCrc'},{type,{844,17},non_neg_integer,[]}]]},{type,{845,7},constraint,[{atom,{845,7},is_subtype},[{var,{845,7},'Data'},{type,{845,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,54,51>>}},{{function,crc32_combine,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,850}],[<<99,114,99,51,50,95,99,111,109,98,105,110,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32,116,119,111,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,117,116,101,100,32,99,114,99,51,50,32,99,104,101,99,107,115,117,109,115,46,32,84,104,105,115,32,99,111,109,112,117,116,97,116,105,111,110,32,114,101,113,117,105,114,101,115,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,111,98,106,101,99,116,32,102,111,114,32,116,104,101,32,115,101,99,111,110,100,32,99,104,101,99,107,115,117,109,32,116,111,32,98,101,32,107,110,111,119,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,100,101,58>>]},{pre,[],[{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,90,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,89,44,68,97,116,97,50,41,46>>]}]},{p,[],[<<97,115,115,105,103,110,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<90>>]},<<32,97,115,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,49,41,44,10,89,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,40,68,97,116,97,50,41,44,10,90,32,61,32,101,114,108,97,110,103,58,99,114,99,51,50,95,99,111,109,98,105,110,101,40,88,44,89,44,105,111,108,105,115,116,95,115,105,122,101,40,68,97,116,97,50,41,41,46>>]}]}]},#{signature => [{attribute,{850,2},spec,{{erlang,crc32_combine,3},[{type,{850,27},bounded_fun,[{type,{850,27},'fun',[{type,{850,27},product,[{var,{850,28},'FirstCrc'},{var,{850,38},'SecondCrc'},{var,{850,49},'SecondSize'}]},{type,{850,64},non_neg_integer,[]}]},[{type,{851,7},constraint,[{atom,{851,7},is_subtype},[{var,{851,7},'FirstCrc'},{type,{851,19},non_neg_integer,[]}]]},{type,{852,7},constraint,[{atom,{852,7},is_subtype},[{var,{852,7},'SecondCrc'},{type,{852,20},non_neg_integer,[]}]]},{type,{853,7},constraint,[{atom,{853,7},is_subtype},[{var,{853,7},'SecondSize'},{type,{853,21},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,56,48>>}},{{function,date,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,858}],[<<100,97,116,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,100,97,116,101,32,97,115,32>>,{code,[],[<<123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125>>]},<<46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,100,97,116,101,40,41,46,10,123,49,57,57,53,44,50,44,49,57,125>>]}]}]},#{signature => [{attribute,{858,2},spec,{{date,0},[{type,{858,11},bounded_fun,[{type,{858,11},'fun',[{type,{858,11},product,[]},{var,{858,17},'Date'}]},[{type,{859,7},constraint,[{atom,{859,7},is_subtype},[{var,{859,7},'Date'},{remote_type,{859,15},[{atom,{859,15},calendar},{atom,{859,24},date},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,52,57,57>>}},{{function,decode_packet,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,864}],[<<100,101,99,111,100,101,95,112,97,99,107,101,116,47,51>>],#{<<101,110>> => [{p,[],[<<68,101,99,111,100,101,115,32,116,104,101,32,98,105,110,97,114,121,32>>,{code,[],[<<66,105,110>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,112,97,99,107,101,116,32,112,114,111,116,111,99,111,108,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<84,121,112,101>>]},<<46,32,83,105,109,105,108,97,114,32,116,111,32,116,104,101,32,112,97,99,107,101,116,32,104,97,110,100,108,105,110,103,32,100,111,110,101,32,98,121,32,115,111,99,107,101,116,115,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,112,97,99,107,101,116,44,84,121,112,101,125,46>>]}]},{p,[],[<<73,102,32,97,110,32,101,110,116,105,114,101,32,112,97,99,107,101,116,32,105,115,32,99,111,110,116,97,105,110,101,100,32,105,110,32>>,{code,[],[<<66,105,110>>]},<<44,32,105,116,32,105,115,32,114,101,116,117,114,110,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,97,115,32>>,{code,[],[<<123,111,107,44,80,97,99,107,101,116,44,82,101,115,116,125>>]},<<46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,105,110>>]},<<32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,116,104,101,32,101,110,116,105,114,101,32,112,97,99,107,101,116,44,32>>,{code,[],[<<123,109,111,114,101,44,76,101,110,103,116,104,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32>>,{code,[],[<<76,101,110,103,116,104>>]},<<32,105,115,32,101,105,116,104,101,114,32,116,104,101,32,101,120,112,101,99,116,101,100,32>>,{em,[],[<<116,111,116,97,108,32,115,105,122,101>>]},<<32,111,102,32,116,104,101,32,112,97,99,107,101,116,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,101,120,112,101,99,116,101,100,32,112,97,99,107,101,116,32,115,105,122,101,32,105,115,32,117,110,107,110,111,119,110,46,32>>,{code,[],[<<100,101,99,111,100,101,95,112,97,99,107,101,116>>]},<<32,99,97,110,32,116,104,101,110,32,98,101,32,99,97,108,108,101,100,32,97,103,97,105,110,32,119,105,116,104,32,109,111,114,101,32,100,97,116,97,32,97,100,100,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,97,99,107,101,116,32,100,111,101,115,32,110,111,116,32,99,111,110,102,111,114,109,32,116,111,32,116,104,101,32,112,114,111,116,111,99,111,108,32,102,111,114,109,97,116,44,32>>,{code,[],[<<123,101,114,114,111,114,44,82,101,97,115,111,110,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<114,97,119,32,124,32,48>>]}]},{dd,[],[{p,[],[<<78,111,32,112,97,99,107,101,116,32,104,97,110,100,108,105,110,103,32,105,115,32,100,111,110,101,46,32,84,104,101,32,101,110,116,105,114,101,32,98,105,110,97,114,121,32,105,115,32,114,101,116,117,114,110,101,100,32,117,110,108,101,115,115,32,105,116,32,105,115,32,101,109,112,116,121,46>>]}]},{dt,[],[{code,[],[<<49,32,124,32,50,32,124,32,52>>]}]},{dd,[],[{p,[],[<<80,97,99,107,101,116,115,32,99,111,110,115,105,115,116,32,111,102,32,97,32,104,101,97,100,101,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,110,32,116,104,101,32,112,97,99,107,101,116,44,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,97,116,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46,32,84,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,104,101,97,100,101,114,32,99,97,110,32,98,101,32,111,110,101,44,32,116,119,111,44,32,111,114,32,102,111,117,114,32,98,121,116,101,115,59,32,116,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,98,121,116,101,115,32,105,115,32,98,105,103,45,101,110,100,105,97,110,46,32,84,104,101,32,104,101,97,100,101,114,32,105,115,32,115,116,114,105,112,112,101,100,32,111,102,102,32,119,104,101,110,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{code,[],[<<108,105,110,101>>]}]},{dd,[],[{p,[],[<<65,32,112,97,99,107,101,116,32,105,115,32,97,32,108,105,110,101,45,116,101,114,109,105,110,97,116,101,100,32,98,121,32,97,32,100,101,108,105,109,105,116,101,114,32,98,121,116,101,44,32,100,101,102,97,117,108,116,32,105,115,32,116,104,101,32,108,97,116,105,110,45,49,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,100,101,108,105,109,105,116,101,114,32,98,121,116,101,32,105,115,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,112,97,99,107,101,116,32,117,110,108,101,115,115,32,116,104,101,32,108,105,110,101,32,119,97,115,32,116,114,117,110,99,97,116,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,111,112,116,105,111,110,32>>,{code,[],[<<108,105,110,101,95,108,101,110,103,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,115,110,49,32,124,32,99,100,114,32,124,32,115,117,110,114,109,32,124,32,102,99,103,105,32,124,32,116,112,107,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,104,101,97,100,101,114,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,116,114,105,112,112,101,100,32,111,102,102,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,116,121,112,101,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,115,110,49>>]},<<32,45,32,65,83,78,46,49,32,66,69,82>>]},{dd,[],[]},{dt,[],[{code,[],[<<115,117,110,114,109>>]},<<32,45,32,83,117,110,39,115,32,82,80,67,32,101,110,99,111,100,105,110,103>>]},{dd,[],[]},{dt,[],[{code,[],[<<99,100,114>>]},<<32,45,32,67,79,82,66,65,32,40,71,73,79,80,32,49,46,49,41>>]},{dd,[],[]},{dt,[],[{code,[],[<<102,99,103,105>>]},<<32,45,32,70,97,115,116,32,67,71,73>>]},{dd,[],[]},{dt,[],[{code,[],[<<116,112,107,116>>]},<<32,45,32,84,80,75,84,32,102,111,114,109,97,116,32,91,82,70,67,49,48,48,54,93>>]},{dd,[],[]}]}]},{dt,[],[{code,[],[<<104,116,116,112,32,124,32,104,116,116,112,104,32,124,32,104,116,116,112,95,98,105,110,32,124,32,104,116,116,112,104,95,98,105,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,72,121,112,101,114,116,101,120,116,32,84,114,97,110,115,102,101,114,32,80,114,111,116,111,99,111,108,46,32,84,104,101,32,112,97,99,107,101,116,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,119,105,116,104,32,116,104,101,32,102,111,114,109,97,116,32,97,99,99,111,114,100,105,110,103,32,116,111,32>>,{code,[],[<<72,116,116,112,80,97,99,107,101,116>>]},<<32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46,32,65,32,112,97,99,107,101,116,32,105,115,32,101,105,116,104,101,114,32,97,32,114,101,113,117,101,115,116,44,32,97,32,114,101,115,112,111,110,115,101,44,32,97,32,104,101,97,100,101,114,44,32,111,114,32,97,110,32,101,110,100,32,111,102,32,104,101,97,100,101,114,32,109,97,114,107,46,32,73,110,118,97,108,105,100,32,108,105,110,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32>>,{code,[],[<<72,116,116,112,69,114,114,111,114>>]},<<46>>]},{p,[],[<<82,101,99,111,103,110,105,122,101,100,32,114,101,113,117,101,115,116,32,109,101,116,104,111,100,115,32,97,110,100,32,104,101,97,100,101,114,32,102,105,101,108,100,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,97,116,111,109,115,46,32,79,116,104,101,114,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,115,116,114,105,110,103,115,46,32,83,116,114,105,110,103,115,32,111,102,32,117,110,114,101,99,111,103,110,105,122,101,100,32,104,101,97,100,101,114,32,102,105,101,108,100,115,32,97,114,101,32,102,111,114,109,97,116,116,101,100,32,119,105,116,104,32,111,110,108,121,32,99,97,112,105,116,97,108,32,108,101,116,116,101,114,115,32,102,105,114,115,116,32,97,110,100,32,97,102,116,101,114,32,104,121,112,104,101,110,32,99,104,97,114,97,99,116,101,114,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<34,83,101,99,45,87,101,98,115,111,99,107,101,116,45,75,101,121,34>>]},<<46,32,72,101,97,100,101,114,32,102,105,101,108,100,32,110,97,109,101,115,32,97,114,101,32,97,108,115,111,32,114,101,116,117,114,110,101,100,32,105,110,32>>,{code,[],[<<85,110,109,111,100,105,102,105,101,100,70,105,101,108,100>>]},<<32,97,115,32,115,116,114,105,110,103,115,44,32,119,105,116,104,111,117,116,32,97,110,121,32,99,111,110,118,101,114,115,105,111,110,32,111,114,32,102,111,114,109,97,116,116,105,110,103,46>>]},{p,[],[<<84,104,101,32,112,114,111,116,111,99,111,108,32,116,121,112,101,32>>,{code,[],[<<104,116,116,112>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,108,105,110,101,32,119,104,101,110,32,97,110,32>>,{code,[],[<<72,116,116,112,82,101,113,117,101,115,116>>]},<<32,111,114,32,97,110,32>>,{code,[],[<<72,116,116,112,82,101,115,112,111,110,115,101>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,97,114,101,32,116,111,32,117,115,101,32>>,{code,[],[<<104,116,116,112,104>>]},<<32,116,111,32,103,101,116,32>>,{code,[],[<<72,116,116,112,72,101,97,100,101,114>>]},<<115,32,117,110,116,105,108,32>>,{code,[],[<<104,116,116,112,95,101,111,104>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,119,104,105,99,104,32,109,97,114,107,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,104,101,97,100,101,114,115,32,97,110,100,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,110,121,32,102,111,108,108,111,119,105,110,103,32,109,101,115,115,97,103,101,32,98,111,100,121,46>>]},{p,[],[<<84,104,101,32,118,97,114,105,97,110,116,115,32>>,{code,[],[<<104,116,116,112,95,98,105,110>>]},<<32,97,110,100,32>>,{code,[],[<<104,116,116,112,104,95,98,105,110>>]},<<32,114,101,116,117,114,110,32,115,116,114,105,110,103,115,32,40>>,{code,[],[<<72,116,116,112,83,116,114,105,110,103>>]},<<41,32,97,115,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,108,105,115,116,115,46>>]},{p,[],[<<83,105,110,99,101,32,79,84,80,32,50,54,46,48,44,32>>,{code,[],[<<72,111,115,116>>]},<<32,109,97,121,32,98,101,32,97,110,32,73,80,118,54,32,97,100,100,114,101,115,115,32,101,110,99,108,111,115,101,100,32,105,110,32>>,{code,[],[<<91,93>>]},<<44,32,97,115,32,100,101,102,105,110,101,100,32,105,110,32>>,{a,[{href,<<104,116,116,112,115,58,47,47,119,119,119,46,105,101,116,102,46,111,114,103,47,114,102,99,47,114,102,99,50,55,51,50,46,116,120,116>>}],[<<82,70,67,50,55,51,50,32>>]},<<46>>]}]}]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,97,99,107,101,116,95,115,105,122,101,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,97,108,108,111,119,101,100,32,115,105,122,101,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,98,111,100,121,46,32,73,102,32,116,104,101,32,112,97,99,107,101,116,32,104,101,97,100,101,114,32,105,110,100,105,99,97,116,101,115,32,116,104,97,116,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,101,32,109,97,120,105,109,117,109,32,97,108,108,111,119,101,100,32,108,101,110,103,116,104,44,32,116,104,101,32,112,97,99,107,101,116,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,105,110,118,97,108,105,100,46,32,68,101,102,97,117,108,116,115,32,116,111,32,48,44,32,119,104,105,99,104,32,109,101,97,110,115,32,110,111,32,115,105,122,101,32,108,105,109,105,116,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,95,108,101,110,103,116,104,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<70,111,114,32,112,97,99,107,101,116,32,116,121,112,101,32>>,{code,[],[<<108,105,110,101>>]},<<44,32,108,105,110,101,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,101,32,105,110,100,105,99,97,116,101,100,32,108,101,110,103,116,104,32,97,114,101,32,116,114,117,110,99,97,116,101,100,46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<108,105,110,101,95,108,101,110,103,116,104>>]},<<32,97,108,115,111,32,97,112,112,108,105,101,115,32,116,111,32>>,{code,[],[<<104,116,116,112,42>>]},<<32,112,97,99,107,101,116,32,116,121,112,101,115,32,97,115,32,97,110,32,97,108,105,97,115,32,102,111,114,32,111,112,116,105,111,110,32>>,{code,[],[<<112,97,99,107,101,116,95,115,105,122,101>>]},<<32,105,102,32>>,{code,[],[<<112,97,99,107,101,116,95,115,105,122,101>>]},<<32,105,116,115,101,108,102,32,105,115,32,110,111,116,32,115,101,116,46,32,84,104,105,115,32,117,115,101,32,105,115,32,111,110,108,121,32,105,110,116,101,110,100,101,100,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,95,100,101,108,105,109,105,116,101,114,44,32,48,32,61,60,32,98,121,116,101,40,41,32,61,60,32,50,53,53,125>>]}]},{dd,[],[{p,[],[<<70,111,114,32,112,97,99,107,101,116,32,116,121,112,101,32>>,{code,[],[<<108,105,110,101>>]},<<44,32,115,101,116,115,32,116,104,101,32,100,101,108,105,109,105,116,105,110,103,32,98,121,116,101,46,32,68,101,102,97,117,108,116,32,105,115,32,116,104,101,32,108,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<36,92,110>>]},<<46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,100,101,99,111,100,101,95,112,97,99,107,101,116,40,49,44,60,60,51,44,34,97,98,99,100,34,62,62,44,91,93,41,46,10,123,111,107,44,60,60,34,97,98,99,34,62,62,44,60,60,34,100,34,62,62,125,10,62,32,101,114,108,97,110,103,58,100,101,99,111,100,101,95,112,97,99,107,101,116,40,49,44,60,60,53,44,34,97,98,99,100,34,62,62,44,91,93,41,46,10,123,109,111,114,101,44,54,125>>]}]}]},#{signature => [{attribute,{864,2},spec,{{erlang,decode_packet,3},[{type,{864,27},bounded_fun,[{type,{864,27},'fun',[{type,{864,27},product,[{var,{864,28},'Type'},{var,{864,34},'Bin'},{var,{864,39},'Options'}]},{type,{865,35},union,[{type,{865,35},tuple,[{atom,{865,36},ok},{var,{865,40},'Packet'},{var,{865,48},'Rest'}]},{type,{866,35},tuple,[{atom,{866,36},more},{var,{866,42},'Length'}]},{type,{867,35},tuple,[{atom,{867,36},error},{var,{867,43},'Reason'}]}]}]},[{type,{868,7},constraint,[{atom,{868,7},is_subtype},[{var,{868,7},'Type'},{type,{868,15},union,[{atom,{868,15},raw},{integer,{868,23},0},{integer,{868,27},1},{integer,{868,31},2},{integer,{868,35},4},{atom,{868,39},asn1},{atom,{868,48},cdr},{atom,{868,56},sunrm},{atom,{868,66},fcgi},{atom,{869,15},tpkt},{atom,{869,24},line},{atom,{869,33},http},{atom,{869,42},http_bin},{atom,{869,55},httph},{atom,{869,65},httph_bin}]}]]},{type,{870,7},constraint,[{atom,{870,7},is_subtype},[{var,{870,7},'Bin'},{type,{870,14},binary,[]}]]},{type,{871,7},constraint,[{atom,{871,7},is_subtype},[{var,{871,7},'Options'},{type,{871,18},list,[{var,{871,19},'Opt'}]}]]},{type,{872,7},constraint,[{atom,{872,7},is_subtype},[{var,{872,7},'Opt'},{type,{872,14},union,[{type,{872,14},tuple,[{atom,{872,15},packet_size},{type,{872,28},non_neg_integer,[]}]},{type,{873,14},tuple,[{atom,{873,15},line_length},{type,{873,28},non_neg_integer,[]}]}]}]]},{type,{874,7},constraint,[{atom,{874,7},is_subtype},[{var,{874,7},'Packet'},{type,{874,17},union,[{type,{874,17},binary,[]},{var,{874,28},'HttpPacket'}]}]]},{type,{875,7},constraint,[{atom,{875,7},is_subtype},[{var,{875,7},'Rest'},{type,{875,15},binary,[]}]]},{type,{876,7},constraint,[{atom,{876,7},is_subtype},[{var,{876,7},'Length'},{type,{876,17},union,[{type,{876,17},non_neg_integer,[]},{atom,{876,37},undefined}]}]]},{type,{877,7},constraint,[{atom,{877,7},is_subtype},[{var,{877,7},'Reason'},{type,{877,17},term,[]}]]},{type,{878,7},constraint,[{atom,{878,7},is_subtype},[{var,{878,7},'HttpPacket'},{type,{878,21},union,[{var,{878,21},'HttpRequest'},{var,{879,21},'HttpResponse'},{var,{880,21},'HttpHeader'},{atom,{881,21},http_eoh},{var,{882,21},'HttpError'}]}]]},{type,{883,7},constraint,[{atom,{883,7},is_subtype},[{var,{883,7},'HttpRequest'},{type,{883,22},tuple,[{atom,{883,23},http_request},{var,{883,39},'HttpMethod'},{var,{883,51},'HttpUri'},{var,{883,60},'HttpVersion'}]}]]},{type,{884,7},constraint,[{atom,{884,7},is_subtype},[{var,{884,7},'HttpResponse'},{type,{884,23},tuple,[{atom,{884,24},http_response},{var,{884,41},'HttpVersion'},{type,{884,54},integer,[]},{var,{884,65},'HttpString'}]}]]},{type,{885,7},constraint,[{atom,{885,7},is_subtype},[{var,{885,7},'HttpHeader'},{type,{885,21},tuple,[{atom,{885,22},http_header},{type,{886,22},integer,[]},{var,{887,22},'HttpField'},{ann_type,{888,22},[{var,{888,22},'UnmodifiedField'},{var,{888,41},'HttpString'}]},{ann_type,{889,22},[{var,{889,22},'Value'},{var,{889,31},'HttpString'}]}]}]]},{type,{890,7},constraint,[{atom,{890,7},is_subtype},[{var,{890,7},'HttpError'},{type,{890,20},tuple,[{atom,{890,21},http_error},{var,{890,35},'HttpString'}]}]]},{type,{891,7},constraint,[{atom,{891,7},is_subtype},[{var,{891,7},'HttpMethod'},{type,{891,21},union,[{atom,{891,21},'OPTIONS'},{atom,{891,33},'GET'},{atom,{891,41},'HEAD'},{atom,{891,50},'POST'},{atom,{891,59},'PUT'},{atom,{891,67},'DELETE'},{atom,{892,21},'TRACE'},{var,{892,31},'HttpString'}]}]]},{type,{893,7},constraint,[{atom,{893,7},is_subtype},[{var,{893,7},'HttpUri'},{type,{893,18},union,[{atom,{893,18},'*'},{type,{894,18},tuple,[{atom,{894,20},absoluteURI},{type,{895,20},union,[{atom,{895,20},http},{atom,{895,29},https}]},{ann_type,{896,20},[{var,{896,20},'Host'},{var,{896,28},'HttpString'}]},{ann_type,{897,20},[{var,{897,20},'Port'},{type,{897,28},union,[{remote_type,{897,28},[{atom,{897,28},inet},{atom,{897,33},port_number},[]]},{atom,{897,49},undefined}]}]},{ann_type,{898,20},[{var,{898,20},'Path'},{var,{898,28},'HttpString'}]}]},{type,{899,18},tuple,[{atom,{899,19},scheme},{ann_type,{899,29},[{var,{899,29},'Scheme'},{var,{899,39},'HttpString'}]},{var,{899,51},'HttpString'}]},{type,{900,18},tuple,[{atom,{900,19},abs_path},{var,{900,31},'HttpString'}]},{var,{901,18},'HttpString'}]}]]},{type,{902,7},constraint,[{atom,{902,7},is_subtype},[{var,{902,7},'HttpVersion'},{type,{902,22},tuple,[{ann_type,{902,23},[{var,{902,23},'Major'},{type,{902,32},non_neg_integer,[]}]},{ann_type,{902,51},[{var,{902,51},'Minor'},{type,{902,60},non_neg_integer,[]}]}]}]]},{type,{903,7},constraint,[{atom,{903,7},is_subtype},[{var,{903,7},'HttpField'},{type,{903,20},union,[{atom,{903,20},'Cache-Control'},{atom,{904,20},'Connection'},{atom,{905,20},'Date'},{atom,{906,20},'Pragma'},{atom,{907,20},'Transfer-Encoding'},{atom,{908,20},'Upgrade'},{atom,{909,20},'Via'},{atom,{910,20},'Accept'},{atom,{911,20},'Accept-Charset'},{atom,{912,20},'Accept-Encoding'},{atom,{913,20},'Accept-Language'},{atom,{914,20},'Authorization'},{atom,{915,20},'From'},{atom,{916,20},'Host'},{atom,{917,20},'If-Modified-Since'},{atom,{918,20},'If-Match'},{atom,{919,20},'If-None-Match'},{atom,{920,20},'If-Range'},{atom,{921,20},'If-Unmodified-Since'},{atom,{922,20},'Max-Forwards'},{atom,{923,20},'Proxy-Authorization'},{atom,{924,20},'Range'},{atom,{925,20},'Referer'},{atom,{926,20},'User-Agent'},{atom,{927,20},'Age'},{atom,{928,20},'Location'},{atom,{929,20},'Proxy-Authenticate'},{atom,{930,20},'Public'},{atom,{931,20},'Retry-After'},{atom,{932,20},'Server'},{atom,{933,20},'Vary'},{atom,{934,20},'Warning'},{atom,{935,19},'Www-Authenticate'},{atom,{936,20},'Allow'},{atom,{937,20},'Content-Base'},{atom,{938,20},'Content-Encoding'},{atom,{939,20},'Content-Language'},{atom,{940,20},'Content-Length'},{atom,{941,20},'Content-Location'},{atom,{942,20},'Content-Md5'},{atom,{943,20},'Content-Range'},{atom,{944,20},'Content-Type'},{atom,{945,20},'Etag'},{atom,{946,20},'Expires'},{atom,{947,20},'Last-Modified'},{atom,{948,20},'Accept-Ranges'},{atom,{949,20},'Set-Cookie'},{atom,{950,20},'Set-Cookie2'},{atom,{951,20},'X-Forwarded-For'},{atom,{952,20},'Cookie'},{atom,{953,20},'Keep-Alive'},{atom,{954,20},'Proxy-Connection'},{var,{955,20},'HttpString'}]}]]},{type,{956,7},constraint,[{atom,{956,7},is_subtype},[{var,{956,7},'HttpString'},{type,{956,21},union,[{type,{956,21},string,[]},{type,{956,32},binary,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,53,49,52>>}},{{function,delete_element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,961}],[<<100,101,108,101,116,101,95,101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,119,105,116,104,32,101,108,101,109,101,110,116,32,97,116,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,100,101,108,101,116,101,95,101,108,101,109,101,110,116,40,50,44,32,123,111,110,101,44,32,116,119,111,44,32,116,104,114,101,101,125,41,46,10,123,111,110,101,44,116,104,114,101,101,125>>]}]}]},#{signature => [{attribute,{961,2},spec,{{erlang,delete_element,2},[{type,{961,28},bounded_fun,[{type,{961,28},'fun',[{type,{961,28},product,[{var,{961,29},'Index'},{var,{961,36},'Tuple1'}]},{var,{961,47},'Tuple2'}]},[{type,{962,7},constraint,[{atom,{962,7},is_subtype},[{var,{962,7},'Index'},{type,{962,17},pos_integer,[]}]]},{type,{963,7},constraint,[{atom,{963,7},is_subtype},[{var,{963,7},'Tuple1'},{type,{963,17},tuple,any}]]},{type,{964,7},constraint,[{atom,{964,7},is_subtype},[{var,{964,7},'Tuple2'},{type,{964,17},tuple,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,51,48>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,delete_module,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,969}],[<<100,101,108,101,116,101,95,109,111,100,117,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<77,97,107,101,115,32,116,104,101,32,99,117,114,114,101,110,116,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,98,101,99,111,109,101,32,111,108,100,32,99,111,100,101,32,97,110,100,32,100,101,108,101,116,101,115,32,97,108,108,32,114,101,102,101,114,101,110,99,101,115,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,102,114,111,109,32,116,104,101,32,101,120,112,111,114,116,32,116,97,98,108,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,97,108,114,101,97,100,121,32,105,115,32,97,110,32,111,108,100,32,118,101,114,115,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{969,2},spec,{{delete_module,1},[{type,{969,20},bounded_fun,[{type,{969,20},'fun',[{type,{969,20},product,[{var,{969,21},'Module'}]},{type,{969,32},union,[{atom,{969,32},true},{atom,{969,39},undefined}]}]},[{type,{970,7},constraint,[{atom,{970,7},is_subtype},[{var,{970,7},'Module'},{type,{970,17},module,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,52,51>>}},{{function,demonitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,975}],[<<100,101,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,111,98,116,97,105,110,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,50>>]}]},<<44,32,116,104,105,115,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,46,32,73,102,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,97,108,114,101,97,100,121,32,116,117,114,110,101,100,32,111,102,102,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46>>]},{p,[],[<<79,110,99,101,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]},<<32,104,97,115,32,114,101,116,117,114,110,101,100,44,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,110,111,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,44,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,44,32,119,105,108,108,32,98,101,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46,32,72,111,119,101,118,101,114,44,32,97,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,32,99,97,110,32,104,97,118,101,32,98,101,101,110,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,46,32,73,116,32,105,115,32,116,104,101,114,101,102,111,114,101,32,117,115,117,97,108,108,121,32,97,100,118,105,115,97,98,108,101,32,116,111,32,114,101,109,111,118,101,32,115,117,99,104,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,102,114,111,109,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,102,116,101,114,32,109,111,110,105,116,111,114,105,110,103,32,104,97,115,32,98,101,101,110,32,115,116,111,112,112,101,100,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,102,108,117,115,104,93,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]},<<32,105,102,32,116,104,105,115,32,99,108,101,97,110,117,112,32,105,115,32,119,97,110,116,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,32,40,69,82,84,83,32,53,46,53,41,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]},<<32,98,101,104,97,118,101,100,32,99,111,109,112,108,101,116,101,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,97,99,116,105,118,101,32,117,110,116,105,108,32,116,104,101,32,34,100,101,109,111,110,105,116,111,114,32,115,105,103,110,97,108,34,32,114,101,97,99,104,101,100,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,46,32,84,104,105,115,32,104,97,100,32,111,110,101,32,117,110,100,101,115,105,114,97,98,108,101,32,101,102,102,101,99,116,46,32,89,111,117,32,99,111,117,108,100,32,110,101,118,101,114,32,107,110,111,119,32,119,104,101,110,32,121,111,117,32,119,101,114,101,32,103,117,97,114,97,110,116,101,101,100,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,114,101,99,101,105,118,101,32,97,32>>,{code,[],[<<68,79,87,78>>]},<<32,109,101,115,115,97,103,101,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,118,105,101,119,101,100,32,97,115,32,116,119,111,32,99,111,109,98,105,110,101,100,32,111,112,101,114,97,116,105,111,110,115,58,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,32,115,101,110,100,32,97,32,34,100,101,109,111,110,105,116,111,114,32,115,105,103,110,97,108,34,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,32,97,110,100,32,105,103,110,111,114,101,32,97,110,121,32,102,117,116,117,114,101,32,114,101,115,117,108,116,115,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32,73,116,32,105,115,32,97,110,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,109,111,110,105,116,111,114,105,110,103,32,115,116,97,114,116,101,100,32,98,121,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,78,111,116,32,97,108,108,32,115,117,99,104,32,99,97,115,101,115,32,97,114,101,32,99,104,101,97,112,32,116,111,32,99,104,101,99,107,46,32,73,102,32,99,104,101,99,107,105,110,103,32,105,115,32,99,104,101,97,112,44,32,116,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,32,105,102,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,105,115,32,97,32,114,101,109,111,116,101,32,114,101,102,101,114,101,110,99,101,46>>]}]},#{signature => [{attribute,{975,2},spec,{{demonitor,1},[{type,{975,16},bounded_fun,[{type,{975,16},'fun',[{type,{975,16},product,[{var,{975,17},'MonitorRef'}]},{atom,{975,32},true}]},[{type,{976,7},constraint,[{atom,{976,7},is_subtype},[{var,{976,7},'MonitorRef'},{type,{976,21},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,54,54,49>>}},{{function,demonitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,981}],[<<100,101,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,117,110,108,101,115,115,32>>,{code,[],[<<105,110,102,111>>]},<<32,105,115,32,112,97,114,116,32,111,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<46>>]},{p,[],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41>>]}]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,108,117,115,104>>]}]},{dd,[],[{p,[],[<<82,101,109,111,118,101,115,32,40,111,110,101,41,32>>,{code,[],[<<123,95,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125>>]},<<32,109,101,115,115,97,103,101,44,32,105,102,32,116,104,101,114,101,32,105,115,32,111,110,101,44,32,102,114,111,109,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,102,116,101,114,32,109,111,110,105,116,111,114,105,110,103,32,104,97,115,32,98,101,101,110,32,115,116,111,112,112,101,100,46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,44,32,91,102,108,117,115,104,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<100,101,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,82,101,102,41,44,10,114,101,99,101,105,118,101,10,32,32,32,32,123,95,44,32,77,111,110,105,116,111,114,82,101,102,44,32,95,44,32,95,44,32,95,125,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,97,102,116,101,114,32,48,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,101,110,100>>]}]}]},{dt,[],[{code,[],[<<105,110,102,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,102,111,117,110,100,32,97,110,100,32,114,101,109,111,118,101,100,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,110,111,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,105,115,32,109,111,110,105,116,111,114,32,104,97,115,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,97,110,100,32,119,105,108,108,32,110,111,116,32,98,101,32,100,101,108,105,118,101,114,101,100,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,97,115,32,110,111,116,32,102,111,117,110,100,32,97,110,100,32,99,111,117,108,100,32,110,111,116,32,98,101,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,112,114,111,98,97,98,108,121,32,98,101,99,97,117,115,101,32,115,111,109,101,111,110,101,32,97,108,114,101,97,100,121,32,104,97,115,32,112,108,97,99,101,100,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,105,115,32,109,111,110,105,116,111,114,32,105,110,32,116,104,101,32,99,97,108,108,101,114,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]}]}]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<105,110,102,111>>]},<<32,105,115,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<102,108,117,115,104>>]},<<44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,102,32,97,32,102,108,117,115,104,32,119,97,115,32,110,101,101,100,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<77,111,114,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<84,104,101,32,115,97,109,101,32,102,97,105,108,117,114,101,32,97,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]}]},<<46>>]}]}]},#{signature => [{attribute,{981,2},spec,{{demonitor,2},[{type,{981,16},bounded_fun,[{type,{981,16},'fun',[{type,{981,16},product,[{var,{981,17},'MonitorRef'},{var,{981,29},'OptionList'}]},{type,{981,44},boolean,[]}]},[{type,{982,7},constraint,[{atom,{982,7},is_subtype},[{var,{982,7},'MonitorRef'},{type,{982,21},reference,[]}]]},{type,{983,7},constraint,[{atom,{983,7},is_subtype},[{var,{983,7},'OptionList'},{type,{983,21},list,[{var,{983,22},'Option'}]}]]},{type,{984,7},constraint,[{atom,{984,7},is_subtype},[{var,{984,7},'Option'},{type,{984,17},union,[{atom,{984,17},flush},{atom,{984,25},info}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,48,57>>}},{{function,disconnect_node,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3714}],[<<100,105,115,99,111,110,110,101,99,116,95,110,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<70,111,114,99,101,115,32,116,104,101,32,100,105,115,99,111,110,110,101,99,116,105,111,110,32,111,102,32,97,32,110,111,100,101,46,32,84,104,105,115,32,97,112,112,101,97,114,115,32,116,111,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<32,97,115,32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,104,97,115,32,99,114,97,115,104,101,100,46,32,84,104,105,115,32,66,73,70,32,105,115,32,109,97,105,110,108,121,32,117,115,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,110,101,116,119,111,114,107,32,97,117,116,104,101,110,116,105,99,97,116,105,111,110,32,112,114,111,116,111,99,111,108,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,100,105,115,99,111,110,110,101,99,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<105,103,110,111,114,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,109,97,121,32,114,101,116,117,114,110,32,98,101,102,111,114,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,110,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,115>>]},<<32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46>>]}]}]},#{signature => [{attribute,{3714,2},spec,{{disconnect_node,1},[{type,{3714,22},bounded_fun,[{type,{3714,22},'fun',[{type,{3714,22},product,[{var,{3714,23},'Node'}]},{type,{3714,32},union,[{type,{3714,32},boolean,[]},{atom,{3714,44},ignored}]}]},[{type,{3715,7},constraint,[{atom,{3715,7},is_subtype},[{var,{3715,7},'Node'},{type,{3715,15},node,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,55,55>>}},{{function,display,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1008}],[<<100,105,115,112,108,97,121,47,49>>],#{<<101,110>> => [{p,[],[<<80,114,105,110,116,115,32,97,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,111,110,32,116,104,101,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46,32,84,104,101,32,112,114,105,110,116,101,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,114,110,97,108,32,100,101,116,97,105,108,115,32,116,104,97,116,32,100,111,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,104,105,103,104,45,108,101,118,101,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,101,114,109,32,105,110,32,69,114,108,97,110,103,46>>]}]}]},#{signature => [{attribute,{1008,2},spec,{{erlang,display,1},[{type,{1008,21},bounded_fun,[{type,{1008,21},'fun',[{type,{1008,21},product,[{var,{1008,22},'Term'}]},{atom,{1008,31},true}]},[{type,{1009,7},constraint,[{atom,{1009,7},is_subtype},[{var,{1009,7},'Term'},{type,{1009,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,55,57,54>>}},{{function,dist_ctrl_get_data,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3998}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>],#{<<101,110>> => [{p,[],[<<71,101,116,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,100,97,116,97,32,102,114,111,109,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,116,104,97,116,32,105,115,32,116,111,32,98,101,32,112,97,115,115,101,100,32,116,111,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,46,32,84,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,73,102,32,110,111,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,44,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,110,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,110,101,32,99,97,110,32,114,101,113,117,101,115,116,32,116,111,32,98,101,32,105,110,102,111,114,109,101,100,32,98,121,32,97,32,109,101,115,115,97,103,101,32,119,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,40,68,72,97,110,100,108,101,41>>]}]},<<46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,119,104,101,110,32,116,104,101,114,101,32,97,114,101,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,99,111,110,102,105,103,117,114,101,100,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>]}]},<<32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{3998,2},spec,{{erlang,dist_ctrl_get_data,1},[{type,{3998,32},bounded_fun,[{type,{3998,32},'fun',[{type,{3998,32},product,[{var,{3998,33},'DHandle'}]},{type,{3998,45},union,[{type,{3998,45},tuple,[{var,{3998,46},'Size'},{var,{3998,52},'Data'}]},{var,{3998,60},'Data'},{atom,{3998,67},none}]}]},[{type,{3999,7},constraint,[{atom,{3999,7},is_subtype},[{var,{3999,7},'Size'},{type,{3999,15},non_neg_integer,[]}]]},{type,{4000,7},constraint,[{atom,{4000,7},is_subtype},[{var,{4000,7},'DHandle'},{user_type,{4000,18},dist_handle,[]}]]},{type,{4001,7},constraint,[{atom,{4001,7},is_subtype},[{var,{4001,7},'Data'},{user_type,{4001,15},iovec,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,56,49,48>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_get_opt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4020}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,111,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>]}]},<<32,102,117,110,99,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{4020,2},spec,{{erlang,dist_ctrl_get_opt,2},[{type,{4020,31},bounded_fun,[{type,{4020,31},'fun',[{type,{4020,31},product,[{var,{4020,32},'DHandle'},{atom,{4020,41},get_size}]},{var,{4020,56},'Value'}]},[{type,{4021,7},constraint,[{atom,{4021,7},is_subtype},[{var,{4021,7},'DHandle'},{user_type,{4021,18},dist_handle,[]}]]},{type,{4022,7},constraint,[{atom,{4022,7},is_subtype},[{var,{4022,7},'Value'},{type,{4022,16},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,56,53,49>>,since => <<79,84,80,32,50,50,46,48>>}},{{function,dist_ctrl_get_data_notification,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4006}],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,113,117,101,115,116,32,110,111,116,105,102,105,99,97,116,105,111,110,32,119,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,102,101,116,99,104,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]}]},<<32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,87,104,101,110,32,109,111,114,101,32,100,97,116,97,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<46,32,79,110,99,101,32,97,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<32,109,101,115,115,97,103,101,115,32,104,97,115,32,98,101,101,110,32,115,101,110,116,44,32,110,111,32,109,111,114,101,32>>,{code,[],[<<100,105,115,116,95,100,97,116,97>>]},<<32,109,101,115,115,97,103,101,115,32,119,105,108,108,32,98,101,32,115,101,110,116,32,117,110,116,105,108,32,116,104,101,32>>,{code,[],[<<100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,95,110,111,116,105,102,105,99,97,116,105,111,110,47,49>>]},<<32,102,117,110,99,116,105,111,110,32,104,97,115,32,98,101,101,110,32,99,97,108,108,101,100,32,97,103,97,105,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{4006,2},spec,{{erlang,dist_ctrl_get_data_notification,1},[{type,{4006,45},bounded_fun,[{type,{4006,45},'fun',[{type,{4006,45},product,[{var,{4006,46},'DHandle'}]},{atom,{4006,58},ok}]},[{type,{4007,7},constraint,[{atom,{4007,7},is_subtype},[{var,{4007,7},'DHandle'},{user_type,{4007,18},dist_handle,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,56,56,48>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_input_handler,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3984}],[<<100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,103,105,115,116,101,114,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,79,110,99,101,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,104,97,115,32,98,101,101,110,32,99,97,108,108,101,100,44,32>>,{code,[],[<<73,110,112,117,116,72,97,110,100,108,101,114>>]},<<32,105,115,32,116,104,101,32,111,110,108,121,32,112,114,111,99,101,115,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,40,68,72,97,110,100,108,101,44,32,68,97,116,97,41>>]}]},<<32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,100,101,110,116,105,102,121,105,110,103,32,116,104,105,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{3984,2},spec,{{erlang,dist_ctrl_input_handler,2},[{type,{3984,37},bounded_fun,[{type,{3984,37},'fun',[{type,{3984,37},product,[{var,{3984,38},'DHandle'},{var,{3984,47},'InputHandler'}]},{atom,{3984,64},ok}]},[{type,{3985,7},constraint,[{atom,{3985,7},is_subtype},[{var,{3985,7},'DHandle'},{user_type,{3985,18},dist_handle,[]}]]},{type,{3986,7},constraint,[{atom,{3986,7},is_subtype},[{var,{3986,7},'InputHandler'},{type,{3986,23},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,49,54>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_put_data,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3991}],[<<100,105,115,116,95,99,116,114,108,95,112,117,116,95,100,97,116,97,47,50>>],#{<<101,110>> => [{p,[],[<<68,101,108,105,118,101,114,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,100,97,116,97,32,102,114,111,109,32,97,32,114,101,109,111,116,101,32,110,111,100,101,32,116,111,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,117,110,108,101,115,115,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,105,110,112,117,116,95,104,97,110,100,108,101,114,40,68,72,97,110,100,108,101,44,32,73,110,112,117,116,72,97,110,100,108,101,114,41>>]}]},<<46,32,73,102,32,97,110,32,97,108,116,101,114,110,97,116,101,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,104,97,115,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,44,32,111,110,108,121,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,105,110,112,117,116,32,104,97,110,100,108,101,114,32,112,114,111,99,101,115,115,32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{3991,2},spec,{{erlang,dist_ctrl_put_data,2},[{type,{3991,32},bounded_fun,[{type,{3991,32},'fun',[{type,{3991,32},product,[{var,{3991,33},'DHandle'},{var,{3991,42},'Data'}]},{atom,{3991,51},ok}]},[{type,{3992,7},constraint,[{atom,{3992,7},is_subtype},[{var,{3992,7},'DHandle'},{user_type,{3992,18},dist_handle,[]}]]},{type,{3993,7},constraint,[{atom,{3993,7},is_subtype},[{var,{3993,7},'Data'},{type,{3993,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,52,57>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,dist_ctrl_set_opt,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4012}],[<<100,105,115,116,95,99,116,114,108,95,115,101,116,95,111,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,111,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<46,32,84,104,105,115,32,111,112,116,105,111,110,32,99,111,110,116,114,111,108,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,99,97,108,108,115,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,117,115,101,100,32,119,104,101,110,32,115,101,116,116,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46,32,87,104,101,110,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[<<97,110,100,32,116,104,101,114,101,32,97,114,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,44,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,105,108,108,32,106,117,115,116,32,114,101,116,117,114,110,32>>,{code,[],[<<68,97,116,97>>]},<<32,116,111,32,112,97,115,115,32,111,118,101,114,32,116,104,101,32,99,104,97,110,110,101,108,46,32,84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<103,101,116,95,115,105,122,101>>]},<<32,111,112,116,105,111,110,46>>]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[<<97,110,100,32,116,104,101,114,101,32,97,114,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,44,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,100,105,115,116,95,99,116,114,108,95,103,101,116,95,100,97,116,97,40,68,72,97,110,100,108,101,41>>]},<<32,119,105,108,108,32,114,101,116,117,114,110,32>>,{code,[],[<<68,97,116,97>>]},<<32,116,111,32,112,97,115,115,32,111,118,101,114,32,116,104,101,32,99,104,97,110,110,101,108,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32>>,{code,[],[<<83,105,122,101>>]},<<32,111,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,110,32,98,121,116,101,115,46,32,84,104,105,115,32,105,115,32,114,101,116,117,114,110,101,100,32,97,115,32,97,32,116,117,112,108,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,83,105,122,101,44,32,68,97,116,97,125>>]},<<46>>]}]},{p,[],[<<65,108,108,32,111,112,116,105,111,110,115,32,97,114,101,32,115,101,116,32,116,111,32,100,101,102,97,117,108,116,32,119,104,101,110,32,97,32,99,104,97,110,110,101,108,32,105,115,32,99,108,111,115,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,103,105,115,116,101,114,101,100,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,99,97,108,108,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,119,104,101,110,32,105,109,112,108,101,109,101,110,116,105,110,103,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,114,114,105,101,114,32,117,115,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,115,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,111,110,116,114,111,108,108,101,114,115,46,32>>,{code,[],[<<68,72,97,110,100,108,101>>]},<<32,105,115,32,114,101,116,114,105,101,118,101,100,32,118,105,97,32,116,104,101,32,99,97,108,108,98,97,99,107,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,104,115,95,100,97,116,97,95,102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<102,95,104,97,110,100,115,104,97,107,101,95,99,111,109,112,108,101,116,101>>]}]},<<46,32,77,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,97,108,116,95,100,105,115,116,35,100,105,115,116,114,105,98,117,116,105,111,110,95,109,111,100,117,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,226,158,156,32,72,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,110,32,65,108,116,101,114,110,97,116,105,118,101,32,67,97,114,114,105,101,114,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,226,158,156,32,68,105,115,116,114,105,98,117,116,105,111,110,32,77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{4012,2},spec,{{erlang,dist_ctrl_set_opt,3},[{type,{4012,31},bounded_fun,[{type,{4012,31},'fun',[{type,{4012,31},product,[{var,{4012,32},'DHandle'},{atom,{4012,41},get_size},{var,{4012,53},'Value'}]},{var,{4012,63},'OldValue'}]},[{type,{4013,7},constraint,[{atom,{4013,7},is_subtype},[{var,{4013,7},'DHandle'},{user_type,{4013,18},dist_handle,[]}]]},{type,{4014,7},constraint,[{atom,{4014,7},is_subtype},[{var,{4014,7},'Value'},{type,{4014,16},boolean,[]}]]},{type,{4015,7},constraint,[{atom,{4015,7},is_subtype},[{var,{4015,7},'OldValue'},{type,{4015,19},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,57,56,50>>,since => <<79,84,80,32,50,50,46,48>>}},{{function,element,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2409}],[<<101,108,101,109,101,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{code,[],[<<78>>]},<<116,104,32,101,108,101,109,101,110,116,32,40,110,117,109,98,101,114,105,110,103,32,102,114,111,109,32,49,41,32,111,102,32>>,{code,[],[<<84,117,112,108,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,108,101,109,101,110,116,40,50,44,32,123,97,44,32,98,44,32,99,125,41,46,10,98>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2409,2},spec,{{element,2},[{type,{2409,14},bounded_fun,[{type,{2409,14},'fun',[{type,{2409,14},product,[{var,{2409,15},'N'},{var,{2409,18},'Tuple'}]},{type,{2409,28},term,[]}]},[{type,{2410,5},constraint,[{atom,{2410,5},is_subtype},[{var,{2410,5},'N'},{type,{2410,10},pos_integer,[]}]]},{type,{2411,5},constraint,[{atom,{2411,5},is_subtype},[{var,{2411,5},'Tuple'},{type,{2411,14},tuple,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,51,49>>}},{{function,erase,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1073}],[<<101,114,97,115,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,110,100,32,100,101,108,101,116,101,115,32,105,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,123,49,44,32,50,44,32,51,125,41,44,10,112,117,116,40,107,101,121,50,44,32,91,97,44,32,98,44,32,99,93,41,44,10,101,114,97,115,101,40,41,46,10,91,123,107,101,121,49,44,123,49,44,50,44,51,125,125,44,123,107,101,121,50,44,91,97,44,98,44,99,93,125,93>>]}]}]},#{signature => [{attribute,{1073,2},spec,{{erase,0},[{type,{1073,12},bounded_fun,[{type,{1073,12},'fun',[{type,{1073,12},product,[]},{type,{1073,18},list,[{type,{1073,19},tuple,[{var,{1073,20},'Key'},{var,{1073,25},'Val'}]}]}]},[{type,{1074,7},constraint,[{atom,{1074,7},is_subtype},[{var,{1074,7},'Key'},{type,{1074,14},term,[]}]]},{type,{1075,7},constraint,[{atom,{1075,7},is_subtype},[{var,{1075,7},'Val'},{type,{1075,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,52,53>>}},{{function,erase,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1080}],[<<101,114,97,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,97,110,100,32,100,101,108,101,116,101,115,32,105,116,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,110,111,32,118,97,108,117,101,32,105,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<46,32,84,104,101,32,97,118,101,114,97,103,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,123,109,101,114,114,121,44,32,108,97,109,98,115,44,32,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,88,32,61,32,101,114,97,115,101,40,107,101,121,49,41,44,10,123,88,44,32,101,114,97,115,101,40,107,101,121,49,41,125,46,10,123,123,109,101,114,114,121,44,108,97,109,98,115,44,97,114,101,44,112,108,97,121,105,110,103,125,44,117,110,100,101,102,105,110,101,100,125>>]}]}]},#{signature => [{attribute,{1080,2},spec,{{erase,1},[{type,{1080,12},bounded_fun,[{type,{1080,12},'fun',[{type,{1080,12},product,[{var,{1080,13},'Key'}]},{type,{1080,21},union,[{var,{1080,21},'Val'},{atom,{1080,27},undefined}]}]},[{type,{1081,7},constraint,[{atom,{1081,7},is_subtype},[{var,{1081,7},'Key'},{type,{1081,14},term,[]}]]},{type,{1082,7},constraint,[{atom,{1082,7},is_subtype},[{var,{1082,7},'Val'},{type,{1082,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,53,57>>}},{{function,error,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1088}],[<<101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,116,104,114,111,119,110,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,97,116,99,104,32,101,114,114,111,114,40,102,111,111,98,97,114,41,46,10,123,39,69,88,73,84,39,44,123,102,111,111,98,97,114,44,91,123,115,104,101,108,108,44,97,112,112,108,121,95,102,117,110,44,51,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,57,48,54,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,101,114,108,95,101,118,97,108,44,100,111,95,97,112,112,108,121,44,54,44,91,123,102,105,108,101,44,34,101,114,108,95,101,118,97,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,55,55,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,101,114,108,95,101,118,97,108,44,101,120,112,114,44,53,44,91,123,102,105,108,101,44,34,101,114,108,95,101,118,97,108,46,101,114,108,34,125,44,123,108,105,110,101,44,52,51,48,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,120,112,114,115,44,55,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,56,55,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,118,97,108,95,101,120,112,114,115,44,55,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,52,50,125,93,125,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,115,104,101,108,108,44,101,118,97,108,95,108,111,111,112,44,51,44,91,123,102,105,108,101,44,34,115,104,101,108,108,46,101,114,108,34,125,44,123,108,105,110,101,44,54,50,55,125,93,125,93,125,125>>]}]}]},#{signature => [{attribute,{1088,2},spec,{{error,1},[{type,{1088,12},bounded_fun,[{type,{1088,12},'fun',[{type,{1088,12},product,[{var,{1088,13},'Reason'}]},{type,{1088,24},no_return,[]}]},[{type,{1089,7},constraint,[{atom,{1089,7},is_subtype},[{var,{1089,7},'Reason'},{type,{1089,17},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,48,56,48>>}},{{function,error,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1095}],[<<101,114,114,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,116,104,101,32,108,105,115,116,32,111,102,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,73,102,32,105,116,32,105,115,32,97,32,108,105,115,116,44,32,105,116,32,105,115,32,117,115,101,100,32,116,111,32,112,114,111,118,105,100,101,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,101,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<110,111,110,101>>]},<<44,32,116,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,105,110,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46,32,69,120,97,109,112,108,101,58>>]},{p,[],[{code,[],[<<116,101,115,116,46,101,114,108>>]},<<58>>]},{pre,[],[{code,[],[<<45,109,111,100,117,108,101,40,116,101,115,116,41,46,10,45,101,120,112,111,114,116,40,91,101,120,97,109,112,108,101,95,102,117,110,47,50,93,41,46,10,10,101,120,97,109,112,108,101,95,102,117,110,40,65,49,44,32,65,50,41,32,45,62,10,32,32,32,32,101,114,108,97,110,103,58,101,114,114,111,114,40,109,121,95,101,114,114,111,114,44,32,91,65,49,44,32,65,50,93,41,46>>]}]},{p,[],[<<69,114,108,97,110,103,32,115,104,101,108,108,58>>]},{pre,[],[{code,[],[<<54,62,32,99,40,116,101,115,116,41,46,10,123,111,107,44,116,101,115,116,125,10,55,62,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,40,97,114,103,49,44,34,116,104,105,115,32,105,115,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,34,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,114,114,111,114,58,32,109,121,95,101,114,114,111,114,10,32,32,32,32,32,105,110,32,102,117,110,99,116,105,111,110,32,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,47,50,10,32,32,32,32,32,32,32,32,32,99,97,108,108,101,100,32,97,115,32,116,101,115,116,58,101,120,97,109,112,108,101,95,102,117,110,40,97,114,103,49,44,34,116,104,105,115,32,105,115,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,34,41,10,32>>]}]}]},#{signature => [{attribute,{1095,2},spec,{{error,2},[{type,{1095,12},bounded_fun,[{type,{1095,12},'fun',[{type,{1095,12},product,[{var,{1095,13},'Reason'},{var,{1095,21},'Args'}]},{type,{1095,30},no_return,[]}]},[{type,{1096,7},constraint,[{atom,{1096,7},is_subtype},[{var,{1096,7},'Reason'},{type,{1096,17},term,[]}]]},{type,{1097,7},constraint,[{atom,{1097,7},is_subtype},[{var,{1097,7},'Args'},{type,{1097,15},union,[{type,{1097,15},list,[{type,{1097,16},term,[]}]},{atom,{1097,26},none}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,49,48,54>>}},{{function,error,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1103}],[<<101,114,114,111,114,47,51>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,119,105,116,104,32,116,104,101,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,116,104,101,32,108,105,115,116,32,111,102,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,73,102,32,105,116,32,105,115,32,97,32,108,105,115,116,44,32,105,116,32,105,115,32,117,115,101,100,32,116,111,32,112,114,111,118,105,100,101,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,101,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<110,111,110,101>>]},<<44,32,116,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,100,32,105,110,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<73,102,32,116,104,101,32>>,{code,[],[<<101,114,114,111,114,95,105,110,102,111>>]},<<32,111,112,116,105,111,110,32,105,115,32,103,105,118,101,110,44,32,116,104,101,32>>,{code,[],[<<69,114,114,111,114,73,110,102,111,77,97,112>>]},<<32,119,105,108,108,32,98,101,32,105,110,115,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,103,105,118,101,110,32,105,110,32,116,104,101,32>>,{code,[],[<<69,114,114,111,114,73,110,102,111,77,97,112>>]},<<32,105,115,32,116,111,32,98,101,32,117,115,101,100,32,98,121,32,101,114,114,111,114,32,102,111,114,109,97,116,116,101,114,115,32,115,117,99,104,32,97,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,114,108,95,101,114,114,111,114,35,102,111,114,109,97,116,95,101,120,99,101,112,116,105,111,110,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,95,101,114,114,111,114>>]}]},<<32,116,111,32,112,114,111,118,105,100,101,32,109,111,114,101,32,99,111,110,116,101,120,116,32,97,114,111,117,110,100,32,97,110,32,101,114,114,111,114,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<109,111,100,117,108,101>>]},<<32,111,102,32,116,104,101,32>>,{code,[],[<<69,114,114,111,114,73,110,102,111,77,97,112>>]},<<32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,116,104,97,116,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,51>>]}]},<<32,105,115,32,109,97,100,101,46,32,84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<102,117,110,99,116,105,111,110>>]},<<32,105,115,32>>,{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114>>]},<<46,32,83,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,114,108,95,101,114,114,111,114,35,102,111,114,109,97,116,95,101,114,114,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,50>>]}]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,111,110,32,104,111,119,32,116,104,105,115,32,77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,50,32,105,115,32,116,111,32,98,101,32,117,115,101,100>>]},{p,[],[<<84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<32,105,115,32,116,111,32,115,105,103,110,97,108,32,116,104,97,116,32,97,110,32,117,110,101,120,112,101,99,116,101,100,32,101,114,114,111,114,32,104,97,115,32,104,97,112,112,101,110,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,119,105,116,104,32,97,32,112,97,114,97,109,101,116,101,114,32,116,104,97,116,32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,116,121,112,101,41,46,32,83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]}]},#{signature => [{attribute,{1103,2},spec,{{error,3},[{type,{1103,12},bounded_fun,[{type,{1103,12},'fun',[{type,{1103,12},product,[{var,{1103,13},'Reason'},{var,{1103,21},'Args'},{var,{1103,27},'Options'}]},{type,{1103,39},no_return,[]}]},[{type,{1104,7},constraint,[{atom,{1104,7},is_subtype},[{var,{1104,7},'Reason'},{type,{1104,17},term,[]}]]},{type,{1105,7},constraint,[{atom,{1105,7},is_subtype},[{var,{1105,7},'Args'},{type,{1105,15},union,[{type,{1105,15},list,[{type,{1105,16},term,[]}]},{atom,{1105,26},none}]}]]},{type,{1106,7},constraint,[{atom,{1106,7},is_subtype},[{var,{1106,7},'Options'},{type,{1106,18},list,[{var,{1106,19},'Option'}]}]]},{type,{1107,7},constraint,[{atom,{1107,7},is_subtype},[{var,{1107,7},'Option'},{type,{1107,17},tuple,[{atom,{1107,18},error_info},{var,{1107,32},'ErrorInfoMap'}]}]]},{type,{1108,7},constraint,[{atom,{1108,7},is_subtype},[{var,{1108,7},'ErrorInfoMap'},{type,{1108,23},map,[{type,{1108,33},map_field_assoc,[{atom,{1108,25},cause},{type,{1108,36},term,[]}]},{type,{1109,34},map_field_assoc,[{atom,{1109,25},module},{type,{1109,37},module,[]}]},{type,{1110,36},map_field_assoc,[{atom,{1110,25},function},{type,{1110,39},atom,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,49,52,51>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,exit,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1116}],[<<101,120,105,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<101,120,105,116>>]},<<32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46,32,65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<84,104,101,32,105,110,116,101,110,116,32,111,102,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,32>>,{code,[],[<<101,120,105,116>>]},<<32,105,115,32,116,104,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,115,104,111,117,108,100,32,98,101,32,115,116,111,112,112,101,100,32,40,102,111,114,32,101,120,97,109,112,108,101,32,119,104,101,110,32,97,32,109,101,115,115,97,103,101,32,116,101,108,108,105,110,103,32,97,32,112,114,111,99,101,115,115,32,116,111,32,115,116,111,112,32,105,115,32,114,101,99,101,105,118,101,100,41,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,100,105,102,102,101,114,32,102,114,111,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,49,44,50,44,51>>]}]},<<32,98,121,32,99,97,117,115,105,110,103,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,97,32,100,105,102,102,101,114,101,110,116,32,99,108,97,115,115,32,97,110,100,32,98,121,32,104,97,118,105,110,103,32,97,32,114,101,97,115,111,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,116,104,101,32,108,105,115,116,32,111,102,32,102,117,110,99,116,105,111,110,115,32,102,114,111,109,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,120,105,116,40,102,111,111,98,97,114,41,46,10,42,42,32,101,120,99,101,112,116,105,111,110,32,101,120,105,116,58,32,102,111,111,98,97,114,10,62,32,99,97,116,99,104,32,101,120,105,116,40,102,111,111,98,97,114,41,46,10,123,39,69,88,73,84,39,44,102,111,111,98,97,114,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,99,97,108,108,115,32>>,{code,[],[<<101,120,105,116,40,107,105,108,108,41>>]},<<32,97,110,100,32,100,111,101,115,32,110,111,116,32,99,97,116,99,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,44,32,105,116,32,119,105,108,108,32,116,101,114,109,105,110,97,116,101,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,97,110,100,32,97,108,115,111,32,101,109,105,116,32,101,120,105,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,40,110,111,116,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<41,32,116,111,32,97,108,108,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,83,117,99,104,32,101,120,105,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,99,97,110,32,98,101,32,116,114,97,112,112,101,100,32,98,121,32,116,104,101,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,115,105,103,110,97,108,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,98,101,104,97,118,101,32,100,105,102,102,101,114,101,110,116,108,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,121,32,97,114,101,32,115,101,110,116,32,98,101,99,97,117,115,101,32,116,104,101,32,115,105,103,110,97,108,32,119,105,108,108,32,98,101,32,117,110,116,114,97,112,112,97,98,108,101,32,105,102,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,115,117,99,104,32,97,32,115,105,103,110,97,108,32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]}]},<<46>>]}]}]},#{signature => [{attribute,{1116,2},spec,{{exit,1},[{type,{1116,11},bounded_fun,[{type,{1116,11},'fun',[{type,{1116,11},product,[{var,{1116,12},'Reason'}]},{type,{1116,23},no_return,[]}]},[{type,{1117,7},constraint,[{atom,{1117,7},is_subtype},[{var,{1117,7},'Reason'},{type,{1117,17},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,49,55,50>>}},{{function,exit,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1122}],[<<101,120,105,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,98,101,104,97,118,105,111,114,32,97,112,112,108,105,101,115,32,105,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,97,110,121,32,116,101,114,109,44,32,101,120,99,101,112,116,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,111,114,32>>,{code,[],[<<107,105,108,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<80>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32>>,{code,[],[<<80>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,115,101,110,116,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,102,32>>,{code,[],[<<80>>]},<<46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,98,101,104,97,118,105,111,114,32,97,112,112,108,105,101,115,32,105,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,116,101,114,109,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80>>]},<<32,119,104,105,99,104,32,105,115,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,110,118,111,107,101,100,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,40,80,105,100,44,32,110,111,114,109,97,108,41>>]},<<32,40,116,104,101,32,98,101,104,97,118,105,111,114,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,97,32,115,105,103,110,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,114,101,97,115,111,110,32,116,111,32,105,116,115,101,108,102,32,105,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,119,97,114,110,105,110,103,41,58>>]},{ul,[],[{li,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,110,111,114,109,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,115,101,110,116,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80>>]},<<39,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{li,[],[<<84,104,101,32,115,105,103,110,97,108,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,105,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,46>>]}]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<107,105,108,108>>]},<<44,32,116,104,97,116,32,105,115,44,32,105,102,32>>,{code,[],[<<101,120,105,116,40,80,105,100,44,32,107,105,108,108,41>>]},<<32,105,115,32,99,97,108,108,101,100,44,32,97,110,32,117,110,116,114,97,112,112,97,98,108,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,119,104,105,99,104,32,117,110,99,111,110,100,105,116,105,111,110,97,108,108,121,32,101,120,105,116,115,32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<46,32,84,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32>>,{code,[],[<<107,105,108,108>>]},<<32,116,111,32>>,{code,[],[<<107,105,108,108,101,100>>]},<<32,116,111,32,104,105,110,116,32,116,111,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,116,104,101,32,107,105,108,108,101,100,32,112,114,111,99,101,115,115,32,103,111,116,32,107,105,108,108,101,100,32,98,121,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,120,105,116,40,80,105,100,44,32,107,105,108,108,41>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]}]},<<32,97,114,101,32,110,97,109,101,100,32,115,105,109,105,108,97,114,108,121,32,98,117,116,32,112,114,111,118,105,100,101,32,118,101,114,121,32,100,105,102,102,101,114,101,110,116,32,102,117,110,99,116,105,111,110,97,108,105,116,105,101,115,46,32,84,104,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]},<<32,102,117,110,99,116,105,111,110,32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,105,110,116,101,110,116,32,105,115,32,116,111,32,115,116,111,112,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,119,104,105,108,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,105,110,116,101,110,116,32,105,115,32,116,111,32,115,101,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,78,111,116,101,32,97,108,115,111,32,116,104,97,116,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,49>>]},<<32,114,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,99,97,110,32,98,101,32,99,97,117,103,104,116,32,119,104,105,108,101,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,100,111,101,115,32,110,111,116,32,99,97,117,115,101,32,97,110,121,32,101,120,99,101,112,116,105,111,110,32,116,111,32,98,101,32,114,97,105,115,101,100,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,32,111,110,108,121,32,115,99,101,110,97,114,105,111,32,116,104,97,116,32,104,97,115,32,110,111,116,32,98,101,101,110,32,99,111,118,101,114,101,100,32,98,121,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,97,98,111,118,101,32,105,115,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80>>]},<<32,115,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,116,111,32,105,116,115,101,108,102,44,32,116,104,97,116,32,105,115,32>>,{code,[],[<<101,114,108,97,110,103,58,101,120,105,116,40,115,101,108,102,40,41,44,32,110,111,114,109,97,108,41>>]},<<46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,110,32,116,104,105,115,32,115,99,101,110,97,114,105,111,32,105,115,32,97,115,32,102,111,108,108,111,119,115,58>>]},{ul,[],[{li,[],[<<73,102,32>>,{code,[],[<<80>>]},<<32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,116,114,97,110,115,102,111,114,109,101,100,32,105,110,116,111,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,110,111,114,109,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,114,111,109>>]},<<32,105,115,32>>,{code,[],[<<80>>]},<<39,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,110,100,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80>>]},<<39,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{li,[],[{code,[],[<<80>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,105,102,32>>,{code,[],[<<80>>]},<<32,105,115,32,110,111,116,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,46>>]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,98,101,104,97,118,105,111,114,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,101,110,100,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,116,111,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,97,114,103,117,97,98,108,121,32,115,116,114,97,110,103,101,32,98,117,116,32,116,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,114,101,97,115,111,110,115,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]}]},#{signature => [{attribute,{1122,2},spec,{{exit,2},[{type,{1122,11},bounded_fun,[{type,{1122,11},'fun',[{type,{1122,11},product,[{var,{1122,12},'Pid'},{var,{1122,17},'Reason'}]},{atom,{1122,28},true}]},[{type,{1123,7},constraint,[{atom,{1123,7},is_subtype},[{var,{1123,7},'Pid'},{type,{1123,14},union,[{type,{1123,14},pid,[]},{type,{1123,22},port,[]}]}]]},{type,{1124,7},constraint,[{atom,{1124,7},is_subtype},[{var,{1124,7},'Reason'},{type,{1124,17},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,50,49,52>>}},{{function,external_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1136}],[<<101,120,116,101,114,110,97,108,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,97,108,99,117,108,97,116,101,115,44,32,119,105,116,104,111,117,116,32,100,111,105,110,103,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,109,97,120,105,109,117,109,32,98,121,116,101,32,115,105,122,101,32,102,111,114,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,110,100,105,116,105,111,110,32,97,112,112,108,105,101,115,32,97,108,119,97,121,115,58>>]},{pre,[],[{code,[],[<<62,32,83,105,122,101,49,32,61,32,98,121,116,101,95,115,105,122,101,40,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,41,41,44,10,62,32,83,105,122,101,50,32,61,32,101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,41,44,10,62,32,116,114,117,101,32,61,32,83,105,122,101,49,32,61,60,32,83,105,122,101,50,46,10,116,114,117,101>>]}]},{p,[],[<<84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,97,32,99,97,108,108,32,116,111,58>>]},{pre,[],[{code,[],[<<101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,44,32,91,93,41>>]}]}]},#{signature => [{attribute,{1136,2},spec,{{erlang,external_size,1},[{type,{1136,27},bounded_fun,[{type,{1136,27},'fun',[{type,{1136,27},product,[{var,{1136,28},'Term'}]},{type,{1136,37},non_neg_integer,[]}]},[{type,{1137,7},constraint,[{atom,{1137,7},is_subtype},[{var,{1137,7},'Term'},{type,{1137,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,48,54>>,since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,external_size,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1142}],[<<101,120,116,101,114,110,97,108,95,115,105,122,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,97,108,99,117,108,97,116,101,115,44,32,119,105,116,104,111,117,116,32,100,111,105,110,103,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,109,97,120,105,109,117,109,32,98,121,116,101,32,115,105,122,101,32,102,111,114,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,111,110,100,105,116,105,111,110,32,97,112,112,108,105,101,115,32,97,108,119,97,121,115,58>>]},{pre,[],[{code,[],[<<62,32,83,105,122,101,49,32,61,32,98,121,116,101,95,115,105,122,101,40,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,44,32,79,112,116,105,111,110,115,41,41,44,10,62,32,83,105,122,101,50,32,61,32,101,114,108,97,110,103,58,101,120,116,101,114,110,97,108,95,115,105,122,101,40,84,101,114,109,44,32,79,112,116,105,111,110,115,41,44,10,62,32,116,114,117,101,32,61,32,83,105,122,101,49,32,61,60,32,83,105,122,101,50,46,10,116,114,117,101>>]}]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<123,109,105,110,111,114,95,118,101,114,115,105,111,110,44,32,86,101,114,115,105,111,110,125>>]},<<32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,102,108,111,97,116,115,32,97,114,101,32,101,110,99,111,100,101,100,46,32,70,111,114,32,97,32,100,101,116,97,105,108,101,100,32,100,101,115,99,114,105,112,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1142,2},spec,{{erlang,external_size,2},[{type,{1142,27},bounded_fun,[{type,{1142,27},'fun',[{type,{1142,27},product,[{var,{1142,28},'Term'},{var,{1142,34},'Options'}]},{type,{1142,46},non_neg_integer,[]}]},[{type,{1143,7},constraint,[{atom,{1143,7},is_subtype},[{var,{1143,7},'Term'},{type,{1143,15},term,[]}]]},{type,{1144,7},constraint,[{atom,{1144,7},is_subtype},[{var,{1144,7},'Options'},{type,{1144,18},list,[{type,{1144,19},union,[{atom,{1144,19},compressed},{type,{1145,10},tuple,[{atom,{1145,11},compressed},{ann_type,{1145,23},[{var,{1145,23},'Level'},{type,{1145,32},range,[{integer,{1145,32},0},{integer,{1145,35},9}]}]}]},{atom,{1146,10},deterministic},{type,{1147,10},tuple,[{atom,{1147,11},minor_version},{ann_type,{1147,26},[{var,{1147,26},'Version'},{type,{1147,37},range,[{integer,{1147,37},0},{integer,{1147,40},2}]}]}]},{atom,{1148,10},local}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,50,53>>,since => <<79,84,80,32,82,49,52,66,48,52>>}},{{function,float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1170}],[<<102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,102,108,111,97,116,32,98,121,32,99,111,110,118,101,114,116,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,97,32,102,108,111,97,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,40,53,53,41,46,10,53,53,46,48>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,117,115,101,100,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,105,110,32,97,32,103,117,97,114,100,44,32,105,116,32,116,101,115,116,115,32,119,104,101,116,104,101,114,32,116,104,101,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,59,32,102,111,114,32,99,108,97,114,105,116,121,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,115,95,102,108,111,97,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,102,108,111,97,116,47,49>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<87,104,101,110,32>>,{code,[],[<<102,108,111,97,116,47,49>>]},<<32,105,115,32,117,115,101,100,32,105,110,32,97,110,32,101,120,112,114,101,115,115,105,111,110,32,105,110,32,97,32,103,117,97,114,100,44,32,115,117,99,104,32,97,115,32,39>>,{code,[],[<<102,108,111,97,116,40,65,41,32,61,61,32,52,46,48>>]},<<39,44,32,105,116,32,99,111,110,118,101,114,116,115,32,97,32,110,117,109,98,101,114,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46>>]}]}]},#{signature => [{attribute,{1170,2},spec,{{float,1},[{type,{1170,12},bounded_fun,[{type,{1170,12},'fun',[{type,{1170,12},product,[{var,{1170,13},'Number'}]},{type,{1170,24},float,[]}]},[{type,{1171,7},constraint,[{atom,{1171,7},is_subtype},[{var,{1171,7},'Number'},{type,{1171,17},number,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,52,53>>}},{{function,float_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1176}],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,70,108,111,97,116,44,91,123,115,99,105,101,110,116,105,102,105,99,44,50,48,125,93,41>>]},<<46>>]}]},#{signature => [{attribute,{1176,2},spec,{{float_to_binary,1},[{type,{1176,22},bounded_fun,[{type,{1176,22},'fun',[{type,{1176,22},product,[{var,{1176,23},'Float'}]},{type,{1176,33},binary,[]}]},[{type,{1177,7},constraint,[{atom,{1177,7},is_subtype},[{var,{1177,7},'Float'},{type,{1177,16},float,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,54,55>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,float_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1182}],[<<102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,117,115,105,110,103,32,102,105,120,101,100,32,100,101,99,105,109,97,108,32,112,111,105,110,116,32,102,111,114,109,97,116,116,105,110,103,46,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<32,98,101,104,97,118,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>]}]},<<46,32,69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,93,41,46,10,60,60,34,55,46,49,50,48,48,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,44,32,99,111,109,112,97,99,116,93,41,46,10,60,60,34,55,46,49,50,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,123,115,99,105,101,110,116,105,102,105,99,44,32,51,125,93,41,46,10,60,60,34,55,46,49,50,48,101,43,48,48,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,55,46,49,50,44,32,91,115,104,111,114,116,93,41,46,10,60,60,34,55,46,49,50,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,48,46,49,43,48,46,50,44,32,91,115,104,111,114,116,93,41,46,10,60,60,34,48,46,51,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,34,62,62,10,62,32,102,108,111,97,116,95,116,111,95,98,105,110,97,114,121,40,48,46,49,43,48,46,50,41,10,60,60,34,51,46,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,52,52,48,57,101,45,48,49,34,62,62>>]}]}]},#{signature => [{attribute,{1182,2},spec,{{float_to_binary,2},[{type,{1182,22},bounded_fun,[{type,{1182,22},'fun',[{type,{1182,22},product,[{var,{1182,23},'Float'},{var,{1182,30},'Options'}]},{type,{1182,42},binary,[]}]},[{type,{1183,7},constraint,[{atom,{1183,7},is_subtype},[{var,{1183,7},'Float'},{type,{1183,16},float,[]}]]},{type,{1184,7},constraint,[{atom,{1184,7},is_subtype},[{var,{1184,7},'Options'},{type,{1184,18},list,[{var,{1184,19},'Option'}]}]]},{type,{1185,7},constraint,[{atom,{1185,7},is_subtype},[{var,{1185,7},'Option'},{type,{1185,18},union,[{type,{1185,18},tuple,[{atom,{1185,19},decimals},{ann_type,{1185,29},[{var,{1185,29},'Decimals'},{type,{1185,41},range,[{integer,{1185,41},0},{integer,{1185,44},253}]}]}]},{type,{1186,18},tuple,[{atom,{1186,19},scientific},{ann_type,{1186,31},[{var,{1186,31},'Decimals'},{type,{1186,43},range,[{integer,{1186,43},0},{integer,{1186,46},249}]}]}]},{atom,{1187,18},compact},{atom,{1188,18},short}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,51,55,54>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,float_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1193}],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,40,70,108,111,97,116,44,91,123,115,99,105,101,110,116,105,102,105,99,44,50,48,125,93,41>>]},<<46>>]}]},#{signature => [{attribute,{1193,2},spec,{{float_to_list,1},[{type,{1193,20},bounded_fun,[{type,{1193,20},'fun',[{type,{1193,20},product,[{var,{1193,21},'Float'}]},{type,{1193,31},string,[]}]},[{type,{1194,7},constraint,[{atom,{1194,7},is_subtype},[{var,{1194,7},'Float'},{type,{1194,16},float,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,48,51>>}},{{function,float_to_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1199}],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,108,111,97,116>>]},<<32,117,115,105,110,103,32,102,105,120,101,100,32,100,101,99,105,109,97,108,32,112,111,105,110,116,32,102,111,114,109,97,116,116,105,110,103,46>>]},{p,[],[<<65,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,99,105,109,97,108,115>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,99,111,110,116,97,105,110,115,32,97,116,32,109,111,115,116,32>>,{code,[],[<<68,101,99,105,109,97,108,115>>]},<<32,110,117,109,98,101,114,32,111,102,32,100,105,103,105,116,115,32,112,97,115,116,32,116,104,101,32,100,101,99,105,109,97,108,32,112,111,105,110,116,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,100,111,101,115,32,110,111,116,32,102,105,116,32,105,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,115,116,97,116,105,99,32,98,117,102,102,101,114,32,111,102,32,50,53,54,32,98,121,116,101,115,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,104,114,111,119,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,97,99,116>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,116,114,97,105,108,105,110,103,32,122,101,114,111,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,108,105,115,116,32,97,114,101,32,116,114,117,110,99,97,116,101,100,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,109,101,97,110,105,110,103,102,117,108,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,99,105,109,97,108,115>>]},<<46>>]}]},{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<115,99,105,101,110,116,105,102,105,99>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,108,111,97,116,32,105,115,32,102,111,114,109,97,116,116,101,100,32,117,115,105,110,103,32,115,99,105,101,110,116,105,102,105,99,32,110,111,116,97,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<68,101,99,105,109,97,108,115>>]},<<32,100,105,103,105,116,115,32,111,102,32,112,114,101,99,105,115,105,111,110,46>>]}]},{li,[],[{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<115,104,111,114,116>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,108,111,97,116,32,105,115,32,102,111,114,109,97,116,116,101,100,32,119,105,116,104,32,116,104,101,32,115,109,97,108,108,101,115,116,32,110,117,109,98,101,114,32,111,102,32,100,105,103,105,116,115,32,116,104,97,116,32,115,116,105,108,108,32,103,117,97,114,97,110,116,101,101,115,32,116,104,97,116,32>>,{code,[],[<<70,32,61,58,61,32,108,105,115,116,95,116,111,95,102,108,111,97,116,40,102,108,111,97,116,95,116,111,95,108,105,115,116,40,70,44,32,91,115,104,111,114,116,93,41,41>>]},<<46,32,87,104,101,110,32,116,104,101,32,102,108,111,97,116,32,105,115,32,105,110,115,105,100,101,32,116,104,101,32,114,97,110,103,101,32,40,45,50,226,129,181,194,179,44,32,50,226,129,181,194,179,41,44,32,116,104,101,32,110,111,116,97,116,105,111,110,32,116,104,97,116,32,121,105,101,108,100,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,105,115,32,117,115,101,100,32,40,115,99,105,101,110,116,105,102,105,99,32,110,111,116,97,116,105,111,110,32,111,114,32,110,111,114,109,97,108,32,100,101,99,105,109,97,108,32,110,111,116,97,116,105,111,110,41,46,32,70,108,111,97,116,115,32,111,117,116,115,105,100,101,32,116,104,101,32,114,97,110,103,101,32,40,45,50,226,129,181,194,179,44,32,50,226,129,181,194,179,41,32,97,114,101,32,97,108,119,97,121,115,32,102,111,114,109,97,116,116,101,100,32,117,115,105,110,103,32,115,99,105,101,110,116,105,102,105,99,32,110,111,116,97,116,105,111,110,32,116,111,32,97,118,111,105,100,32,99,111,110,102,117,115,105,110,103,32,114,101,115,117,108,116,115,32,119,104,101,110,32,100,111,105,110,103,32,97,114,105,116,104,109,101,116,105,99,32,111,112,101,114,97,116,105,111,110,115,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32>>,{code,[],[<<91,93>>]},<<44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,98,101,104,97,118,101,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,47,49>>]}]},<<46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,93,41,46,10,34,55,46,49,50,48,48,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,100,101,99,105,109,97,108,115,44,32,52,125,44,32,99,111,109,112,97,99,116,93,41,46,10,34,55,46,49,50,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,123,115,99,105,101,110,116,105,102,105,99,44,32,51,125,93,41,46,10,34,55,46,49,50,48,101,43,48,48,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,55,46,49,50,44,32,91,115,104,111,114,116,93,41,46,10,34,55,46,49,50,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,48,46,49,43,48,46,50,44,32,91,115,104,111,114,116,93,41,46,10,34,48,46,51,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,34,10,62,32,102,108,111,97,116,95,116,111,95,108,105,115,116,40,48,46,49,43,48,46,50,41,10,34,51,46,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,52,52,48,57,101,45,48,49,34>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<102,108,111,97,116,95,116,111,95,108,105,115,116,40,48,46,49,43,48,46,50,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<34,51,46,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,52,52,52,48,57,101,45,48,49,34>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,101,120,112,108,97,105,110,101,100,32,105,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<46>>]}]},#{signature => [{attribute,{1199,2},spec,{{float_to_list,2},[{type,{1199,20},bounded_fun,[{type,{1199,20},'fun',[{type,{1199,20},product,[{var,{1199,21},'Float'},{var,{1199,28},'Options'}]},{type,{1199,40},string,[]}]},[{type,{1200,7},constraint,[{atom,{1200,7},is_subtype},[{var,{1200,7},'Float'},{type,{1200,16},float,[]}]]},{type,{1201,7},constraint,[{atom,{1201,7},is_subtype},[{var,{1201,7},'Options'},{type,{1201,18},list,[{var,{1201,19},'Option'}]}]]},{type,{1202,7},constraint,[{atom,{1202,7},is_subtype},[{var,{1202,7},'Option'},{type,{1202,18},union,[{type,{1202,18},tuple,[{atom,{1202,19},decimals},{ann_type,{1202,29},[{var,{1202,29},'Decimals'},{type,{1202,41},range,[{integer,{1202,41},0},{integer,{1202,44},253}]}]}]},{type,{1203,18},tuple,[{atom,{1203,19},scientific},{ann_type,{1203,31},[{var,{1203,31},'Decimals'},{type,{1203,43},range,[{integer,{1203,43},0},{integer,{1203,46},249}]}]}]},{atom,{1204,18},compact},{atom,{1205,18},short}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,49,50>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,floor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1211}],[<<102,108,111,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,97,114,103,101,115,116,32,105,110,116,101,103,101,114,32,110,111,116,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,102,108,111,111,114,40,45,49,48,46,53,41,46,10,45,49,49>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1211,2},spec,{{floor,1},[{type,{1211,12},bounded_fun,[{type,{1211,12},'fun',[{type,{1211,12},product,[{var,{1211,13},'Number'}]},{type,{1211,24},integer,[]}]},[{type,{1212,7},constraint,[{atom,{1212,7},is_subtype},[{var,{1212,7},'Number'},{type,{1212,17},number,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,55,50>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,fun_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3719}],[<<102,117,110,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,117,110,32>>,{code,[],[<<70,117,110>>]},<<46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,117,112,108,101,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,100,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,109,97,105,110,108,121,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,44,32,98,117,116,32,105,116,32,99,97,110,32,115,111,109,101,116,105,109,101,115,32,98,101,32,117,115,101,102,117,108,32,105,110,32,108,105,98,114,97,114,121,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,110,101,101,100,32,116,111,32,118,101,114,105,102,121,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,97,114,105,116,121,32,111,102,32,97,32,102,117,110,46>>]}]},{p,[],[<<84,119,111,32,116,121,112,101,115,32,111,102,32,102,117,110,115,32,104,97,118,101,32,115,108,105,103,104,116,108,121,32,100,105,102,102,101,114,101,110,116,32,115,101,109,97,110,116,105,99,115,58>>]},{ul,[],[{li,[],[{p,[],[<<65,32,102,117,110,32,99,114,101,97,116,101,100,32,98,121,32>>,{code,[],[<<102,117,110,32,77,58,70,47,65>>]},<<32,105,115,32,99,97,108,108,101,100,32,97,110,32>>,{em,[],[<<101,120,116,101,114,110,97,108>>]},<<32,102,117,110,46,32,67,97,108,108,105,110,103,32,105,116,32,119,105,108,108,32,97,108,119,97,121,115,32,99,97,108,108,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70>>]},<<32,119,105,116,104,32,97,114,105,116,121,32>>,{code,[],[<<65>>]},<<32,105,110,32,116,104,101,32,108,97,116,101,115,116,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,100,117,108,101,32>>,{code,[],[<<77>>]},<<32,100,111,101,115,32,110,111,116,32,101,118,101,110,32,110,101,101,100,32,116,111,32,98,101,32,108,111,97,100,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,32>>,{code,[],[<<102,117,110,32,77,58,70,47,65>>]},<<32,105,115,32,99,114,101,97,116,101,100,46>>]}]},{li,[],[{p,[],[<<65,108,108,32,111,116,104,101,114,32,102,117,110,115,32,97,114,101,32,99,97,108,108,101,100,32>>,{em,[],[<<108,111,99,97,108>>]},<<46,32,87,104,101,110,32,97,32,108,111,99,97,108,32,102,117,110,32,105,115,32,99,97,108,108,101,100,44,32,116,104,101,32,115,97,109,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,102,117,110,32,105,115,32,99,97,108,108,101,100,32,40,101,118,101,110,32,105,102,32,97,32,110,101,119,101,114,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,109,111,100,117,108,101,32,104,97,115,32,98,101,101,110,32,108,111,97,100,101,100,41,46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,108,101,109,101,110,116,115,32,97,114,101,32,97,108,119,97,121,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,32,102,111,114,32,98,111,116,104,32,108,111,99,97,108,32,97,110,100,32,101,120,116,101,114,110,97,108,32,102,117,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,116,121,112,101,44,32,84,121,112,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,114,32>>,{code,[],[<<101,120,116,101,114,110,97,108>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,111,100,117,108,101,44,32,77,111,100,117,108,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,40,97,110,32,97,116,111,109,41,32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,110,97,109,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,105,110,32,119,104,105,99,104,32,116,104,101,32,102,117,110,32,105,115,32,100,101,102,105,110,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,109,111,100,117,108,101,32,116,104,97,116,32,116,104,101,32,102,117,110,32,114,101,102,101,114,115,32,116,111,46>>]}]},{dt,[],[{code,[],[<<123,110,97,109,101,44,32,78,97,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,40,97,110,32,97,116,111,109,41,32,105,115,32,97,32,102,117,110,99,116,105,111,110,32,110,97,109,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,105,109,112,108,101,109,101,110,116,115,32,116,104,101,32,102,117,110,46,32,40,84,104,105,115,32,110,97,109,101,32,119,97,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,97,110,100,32,105,115,32,111,110,108,121,32,111,102,32,105,110,102,111,114,109,97,116,105,111,110,97,108,32,117,115,101,46,32,65,115,32,105,116,32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,99,97,108,108,101,100,32,100,105,114,101,99,116,108,121,46,41,32,73,102,32,110,111,32,99,111,100,101,32,105,115,32,99,117,114,114,101,110,116,108,121,32,108,111,97,100,101,100,32,102,111,114,32,116,104,101,32,102,117,110,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,97,110,32,97,116,111,109,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,116,104,101,32,102,117,110,32,114,101,102,101,114,115,32,116,111,46>>]}]},{dt,[],[{code,[],[<<123,97,114,105,116,121,44,32,65,114,105,116,121,125>>]}]},{dd,[],[{p,[],[{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,116,104,97,116,32,116,104,101,32,102,117,110,32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,119,105,116,104,46>>]}]},{dt,[],[{code,[],[<<123,101,110,118,44,32,69,110,118,125>>]}]},{dd,[],[{p,[],[{code,[],[<<69,110,118>>]},<<32,40,97,32,108,105,115,116,41,32,105,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,114,32,102,114,101,101,32,118,97,114,105,97,98,108,101,115,32,102,111,114,32,116,104,101,32,102,117,110,46,32,70,111,114,32,101,120,116,101,114,110,97,108,32,102,117,110,115,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,105,115,32,97,108,119,97,121,115,32,101,109,112,116,121,46>>]}]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,108,101,109,101,110,116,115,32,97,114,101,32,111,110,108,121,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,32,105,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,108,111,99,97,108,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,105,100,44,32,80,105,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,114,105,103,105,110,97,108,108,121,32,99,114,101,97,116,101,100,32,116,104,101,32,102,117,110,46>>]},{p,[],[<<73,116,32,109,105,103,104,116,32,112,111,105,110,116,32,116,111,32,116,104,101,32>>,{code,[],[<<105,110,105,116>>]},<<32,112,114,111,99,101,115,115,32,105,102,32,116,104,101,32>>,{code,[],[<<70,117,110>>]},<<32,119,97,115,32,115,116,97,116,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,119,104,101,110,32,109,111,100,117,108,101,32,119,97,115,32,108,111,97,100,101,100,32,40,116,104,105,115,32,111,112,116,105,109,105,115,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,102,111,114,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,100,111,32,110,111,116,32,99,97,112,116,117,114,101,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,41,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<73,110,32,69,114,108,97,110,103,47,79,84,80,32,50,55,44,32,119,101,32,112,108,97,110,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,115,111,32,116,104,97,116,32,105,116,32,97,108,119,97,121,115,32,112,111,105,110,116,115,32,116,111,32,116,104,101,32,108,111,99,97,108,32>>,{code,[],[<<105,110,105,116>>]},<<32,112,114,111,99,101,115,115,44,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,105,99,104,32,112,114,111,99,101,115,115,32,111,114,32,110,111,100,101,32,116,104,101,32,102,117,110,32,119,97,115,32,111,114,105,103,105,110,97,108,108,121,32,99,114,101,97,116,101,100,32,111,110,46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,103,101,110,101,114,97,108,95,105,110,102,111,58,117,112,99,111,109,105,110,103,95,105,110,99,111,109,112,97,116,105,98,105,108,105,116,105,101,115,35,102,117,110,95,99,114,101,97,116,111,114,95,112,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<85,112,99,111,109,105,110,103,32,80,111,116,101,110,116,105,97,108,32,73,110,99,111,109,112,97,116,105,98,105,108,105,116,105,101,115,32>>]},<<46>>]}]}]},{dt,[],[{code,[],[<<123,105,110,100,101,120,44,32,73,110,100,101,120,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,110,32,105,110,100,101,120,32,105,110,116,111,32,116,104,101,32,109,111,100,117,108,101,32,102,117,110,32,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,95,105,110,100,101,120,44,32,73,110,100,101,120,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,110,32,105,110,100,101,120,32,105,110,116,111,32,116,104,101,32,109,111,100,117,108,101,32,102,117,110,32,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,95,117,110,105,113,44,32,85,110,105,113,125>>]}]},{dd,[],[{p,[],[{code,[],[<<85,110,105,113>>]},<<32,40,97,32,98,105,110,97,114,121,41,32,105,115,32,97,32,117,110,105,113,117,101,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,46,32,73,116,32,105,115,32,99,97,108,99,117,108,97,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,109,111,100,117,108,101,46>>]}]},{dt,[],[{code,[],[<<123,117,110,105,113,44,32,85,110,105,113,125>>]}]},{dd,[],[{p,[],[{code,[],[<<85,110,105,113>>]},<<32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,115,32,97,32,117,110,105,113,117,101,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,46,32,65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,53,44,32,116,104,105,115,32,105,110,116,101,103,101,114,32,105,115,32,99,97,108,99,117,108,97,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,109,111,100,117,108,101,46,32,66,101,102,111,114,101,32,69,114,108,97,110,103,47,79,84,80,32,82,49,53,44,32,116,104,105,115,32,105,110,116,101,103,101,114,32,119,97,115,32,98,97,115,101,100,32,111,110,32,111,110,108,121,32,116,104,101,32,98,111,100,121,32,111,102,32,116,104,101,32,102,117,110,46>>]}]}]}]},#{signature => [{attribute,{3719,2},spec,{{erlang,fun_info,1},[{type,{3719,22},bounded_fun,[{type,{3719,22},'fun',[{type,{3719,22},product,[{var,{3719,23},'Fun'}]},{type,{3719,31},list,[{type,{3719,32},tuple,[{var,{3719,33},'Item'},{var,{3719,39},'Info'}]}]}]},[{type,{3720,7},constraint,[{atom,{3720,7},is_subtype},[{var,{3720,7},'Fun'},{type,{3720,14},function,[]}]]},{type,{3721,7},constraint,[{atom,{3721,7},is_subtype},[{var,{3721,7},'Item'},{type,{3721,15},union,[{atom,{3721,15},arity},{atom,{3721,23},env},{atom,{3721,29},index},{atom,{3721,37},name},{atom,{3722,15},module},{atom,{3722,24},new_index},{atom,{3722,36},new_uniq},{atom,{3722,47},pid},{atom,{3722,53},type},{atom,{3722,60},uniq}]}]]},{type,{3723,7},constraint,[{atom,{3723,7},is_subtype},[{var,{3723,7},'Info'},{type,{3723,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,52,56,54>>}},{{function,fun_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1217}],[<<102,117,110,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<102,117,110,95,105,110,102,111,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32>>,{code,[],[<<70,117,110>>]},<<32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,73,116,101,109,44,73,110,102,111,125>>]},<<46>>]},{p,[],[<<70,111,114,32,97,110,121,32,102,117,110,44,32>>,{code,[],[<<73,116,101,109>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<109,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<110,97,109,101>>]},<<44,32>>,{code,[],[<<97,114,105,116,121>>]},<<44,32>>,{code,[],[<<101,110,118>>]},<<44,32,111,114,32>>,{code,[],[<<116,121,112,101>>]},<<46>>]},{p,[],[<<70,111,114,32,97,32,108,111,99,97,108,32,102,117,110,44,32>>,{code,[],[<<73,116,101,109>>]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<44,32>>,{code,[],[<<110,101,119,95,105,110,100,101,120>>]},<<44,32>>,{code,[],[<<110,101,119,95,117,110,105,113>>]},<<44,32>>,{code,[],[<<117,110,105,113>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,105,100>>]},<<46,32,70,111,114,32,97,110,32,101,120,116,101,114,110,97,108,32,102,117,110,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,97,110,121,32,111,102,32,116,104,101,115,101,32,105,116,101,109,115,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{1217,2},spec,{{erlang,fun_info,2},[{type,{1217,22},bounded_fun,[{type,{1217,22},'fun',[{type,{1217,22},product,[{var,{1217,23},'Fun'},{var,{1217,28},'Item'}]},{type,{1217,37},tuple,[{var,{1217,38},'Item'},{var,{1217,44},'Info'}]}]},[{type,{1218,7},constraint,[{atom,{1218,7},is_subtype},[{var,{1218,7},'Fun'},{type,{1218,14},function,[]}]]},{type,{1219,7},constraint,[{atom,{1219,7},is_subtype},[{var,{1219,7},'Item'},{user_type,{1219,15},fun_info_item,[]}]]},{type,{1220,7},constraint,[{atom,{1220,7},is_subtype},[{var,{1220,7},'Info'},{type,{1220,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,48,48>>}},{{function,fun_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1234}],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,116,104,97,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,99,114,101,97,116,101,100,32>>,{code,[],[<<70,117,110>>]},<<46>>]},{p,[],[{code,[],[<<83,116,114,105,110,103>>]},<<32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,44,32,105,102,32>>,{code,[],[<<70,117,110>>]},<<32,119,97,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,102,117,110,45,101,120,112,114,101,115,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,117,110,32,101,120,112,114,101,115,115,105,111,110>>]},<<32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<102,117,110,32,77,111,100,117,108,101,78,97,109,101,58,70,117,110,99,78,97,109,101,47,65,114,105,116,121>>]},<<58>>]},{p,[],[{code,[],[<<34,102,117,110,32,77,111,100,117,108,101,78,97,109,101,58,70,117,110,99,78,97,109,101,47,65,114,105,116,121,34>>]}]},{p,[],[<<84,104,101,32,102,111,114,109,32,111,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,119,104,101,110,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,111,116,104,101,114,32,116,121,112,101,115,32,111,102,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,102,117,110,45,101,120,112,114,101,115,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,117,110,32,101,120,112,114,101,115,115,105,111,110,115>>]},<<32,100,105,102,102,101,114,115,32,100,101,112,101,110,100,105,110,103,32,111,110,32,105,102,32,116,104,101,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,101,120,101,99,117,116,101,100,32,119,104,105,108,101,32,101,120,101,99,117,116,105,110,103,32,99,111,109,112,105,108,101,100,32,99,111,100,101,32,111,114,32,105,102,32,116,104,101,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,101,120,101,99,117,116,101,100,32,119,104,105,108,101,32,101,120,101,99,117,116,105,110,103,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,40,117,110,99,111,109,112,105,108,101,100,32,101,115,99,114,105,112,116,115,44,32,116,104,101,32,69,114,108,97,110,103,32,115,104,101,108,108,44,32,97,110,100,32,111,116,104,101,114,32,99,111,100,101,32,101,120,101,99,117,116,101,100,32,98,121,32,116,104,101,32,101,114,108,95,101,118,97,108,32,109,111,100,117,108,101,41,58>>]},{dl,[],[{dt,[],[<<99,111,109,112,105,108,101,100,32,99,111,100,101>>]},{dd,[],[{p,[],[{code,[],[<<34,35,70,117,110,60,77,46,73,46,85,62,34>>]},<<44,32,119,104,101,114,101,32,77,44,32,73,32,97,110,100,32,85,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,116,104,101,32,118,97,108,117,101,115,32,110,97,109,101,100,32>>,{code,[],[<<109,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<105,110,100,101,120>>]},<<32,97,110,100,32>>,{code,[],[<<117,110,105,113>>]},<<32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,40,70,117,110,41>>]}]},<<46>>]}]},{dt,[],[<<117,110,99,111,109,112,105,108,101,100,32,99,111,100,101>>]},{dd,[],[<<65,108,108,32,102,117,110,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,97,114,105,116,121,32,97,114,101,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,98,121,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<71,101,110,101,114,97,108,108,121,44,32,111,110,101,32,99,97,110,32,110,111,116,32,117,115,101,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,116,111,32,99,104,101,99,107,32,105,102,32,116,119,111,32,102,117,110,115,32,97,114,101,32,101,113,117,97,108,32,97,115,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,100,111,101,115,32,110,111,116,32,116,97,107,101,32,116,104,101,32,102,117,110,39,115,32,101,110,118,105,114,111,110,109,101,110,116,32,105,110,116,111,32,97,99,99,111,117,110,116,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,102,117,110,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,102,117,110,95,105,110,102,111,47,49>>]}]},<<32,102,111,114,32,104,111,119,32,116,111,32,103,101,116,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,102,32,97,32,102,117,110,46>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<84,104,101,32,111,117,116,112,117,116,32,111,102,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,69,114,108,97,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,32,97,110,100,32,109,97,121,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,115,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<45,109,111,100,117,108,101,40,116,101,115,116,41,46,10,45,101,120,112,111,114,116,40,91,97,100,100,47,49,44,32,97,100,100,50,47,48,44,32,102,117,110,95,116,117,112,108,101,47,48,93,41,46,10,97,100,100,40,65,41,32,45,62,32,102,117,110,40,66,41,32,45,62,32,65,32,43,32,66,32,101,110,100,46,10,97,100,100,50,40,41,32,45,62,32,102,117,110,32,97,100,100,47,49,46,10,102,117,110,95,116,117,112,108,101,40,41,32,45,62,32,123,102,117,110,40,41,32,45,62,32,49,32,101,110,100,44,32,102,117,110,40,41,32,45,62,32,49,32,101,110,100,125,46,10,32,32,32,32,32,32,32,32>>]}]},{pre,[],[{code,[],[<<62,32,123,102,117,110,32,116,101,115,116,58,97,100,100,47,49,44,32,116,101,115,116,58,97,100,100,50,40,41,125,46,10,123,102,117,110,32,116,101,115,116,58,97,100,100,47,49,44,35,70,117,110,60,116,101,115,116,46,49,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32>>,{code,[],[<<102,117,110,32,116,101,115,116,58,97,100,100,47,49>>]},<<32,105,115,32,117,112,103,114,97,100,97,98,108,101,32,98,117,116,32>>,{code,[],[<<116,101,115,116,58,97,100,100,50,40,41>>]},<<32,105,115,32,110,111,116,32,117,112,103,114,97,100,97,98,108,101,46>>]},{pre,[],[{code,[],[<<62,32,123,116,101,115,116,58,97,100,100,40,49,41,44,32,116,101,115,116,58,97,100,100,40,52,50,41,125,46,10,123,35,70,117,110,60,116,101,115,116,46,48,46,49,48,55,55,51,56,57,56,51,62,44,35,70,117,110,60,116,101,115,116,46,48,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32>>,{code,[],[<<116,101,115,116,58,97,100,100,40,49,41>>]},<<32,97,110,100,32>>,{code,[],[<<116,101,115,116,58,97,100,100,40,52,50,41>>]},<<32,104,97,115,32,116,104,101,32,115,97,109,101,32,115,116,114,105,110,103,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,97,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,105,115,32,110,111,116,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,46>>]},{pre,[],[{code,[],[<<62,116,101,115,116,58,102,117,110,95,116,117,112,108,101,40,41,46,10,123,35,70,117,110,60,116,101,115,116,46,50,46,49,48,55,55,51,56,57,56,51,62,44,35,70,117,110,60,116,101,115,116,46,51,46,49,48,55,55,51,56,57,56,51,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32,84,104,101,32,115,116,114,105,110,103,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,32,100,105,102,102,101,114,32,98,101,99,97,117,115,101,32,116,104,101,32,102,117,110,115,32,99,111,109,101,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,115,46>>]},{pre,[],[{code,[],[<<62,32,123,102,117,110,40,41,32,45,62,32,49,32,101,110,100,44,32,102,117,110,40,41,32,45,62,32,49,32,101,110,100,125,46,32,62,32,10,123,35,70,117,110,60,101,114,108,95,101,118,97,108,46,52,53,46,57,55,50,56,51,48,57,53,62,44,35,70,117,110,60,101,114,108,95,101,118,97,108,46,52,53,46,57,55,50,56,51,48,57,53,62,125>>]}]},{p,[],[<<69,120,112,108,97,110,97,116,105,111,110,58,32,65,108,108,32,102,117,110,115,32,99,114,101,97,116,101,100,32,102,114,111,109,32,102,117,110,32,101,120,112,114,101,115,115,105,111,110,115,32,111,102,32,116,104,105,115,32,102,111,114,109,32,105,110,32,117,110,99,111,109,112,105,108,101,100,32,99,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,97,114,105,116,121,32,97,114,101,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,98,121,32>>,{code,[],[<<102,117,110,95,116,111,95,108,105,115,116,47,49>>]},<<46>>]}]},#{signature => [{attribute,{1234,2},spec,{{erlang,fun_to_list,1},[{type,{1234,25},bounded_fun,[{type,{1234,25},'fun',[{type,{1234,25},product,[{var,{1234,26},'Fun'}]},{ann_type,{1234,34},[{var,{1234,34},'String'},{type,{1234,44},string,[]}]}]},[{type,{1235,7},constraint,[{atom,{1235,7},is_subtype},[{var,{1235,7},'Fun'},{type,{1235,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,54,50,48>>}},{{function,function_exported,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1240}],[<<102,117,110,99,116,105,111,110,95,101,120,112,111,114,116,101,100,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,99,111,100,101,95,108,111,97,100,105,110,103,35,99,111,100,101,45,114,101,112,108,97,99,101,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,117,114,114,101,110,116>>]},<<32,97,110,100,32,99,111,110,116,97,105,110,115,32,97,110,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<44,32,111,114,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,66,73,70,32,40,97,32,98,117,105,108,116,45,105,110,32,102,117,110,99,116,105,111,110,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,67,41,32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,110,97,109,101,44,32,111,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{1240,2},spec,{{erlang,function_exported,3},[{type,{1240,31},bounded_fun,[{type,{1240,31},'fun',[{type,{1240,31},product,[{var,{1240,32},'Module'},{var,{1240,40},'Function'},{var,{1240,50},'Arity'}]},{type,{1240,60},boolean,[]}]},[{type,{1241,7},constraint,[{atom,{1241,7},is_subtype},[{var,{1241,7},'Module'},{type,{1241,17},module,[]}]]},{type,{1242,7},constraint,[{atom,{1242,7},is_subtype},[{var,{1242,7},'Function'},{type,{1242,19},atom,[]}]]},{type,{1243,7},constraint,[{atom,{1243,7},is_subtype},[{var,{1243,7},'Arity'},{type,{1243,16},arity,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,48,57>>}},{{function,garbage_collect,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1248}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>],#{<<101,110>> => [{p,[],[<<70,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,116,104,101,32,101,120,101,99,117,116,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,117,110,108,101,115,115,32,105,116,32,104,97,115,32,98,101,101,110,32,110,111,116,105,99,101,100,32,40,111,114,32,116,104,101,114,101,32,97,114,101,32,103,111,111,100,32,114,101,97,115,111,110,115,32,116,111,32,115,117,115,112,101,99,116,41,32,116,104,97,116,32,116,104,101,32,115,112,111,110,116,97,110,101,111,117,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,119,105,108,108,32,111,99,99,117,114,32,116,111,111,32,108,97,116,101,32,111,114,32,110,111,116,32,97,116,32,97,108,108,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,109,112,114,111,112,101,114,32,117,115,101,32,99,97,110,32,115,101,114,105,111,117,115,108,121,32,100,101,103,114,97,100,101,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,46>>]}]}]},#{signature => [{attribute,{1248,2},spec,{{garbage_collect,0},[{type,{1248,22},'fun',[{type,{1248,22},product,[]},{atom,{1248,28},true}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,50,49>>}},{{function,garbage_collect,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1253}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,40,80,105,100,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1253,2},spec,{{garbage_collect,1},[{type,{1253,22},bounded_fun,[{type,{1253,22},'fun',[{type,{1253,22},product,[{var,{1253,23},'Pid'}]},{var,{1253,31},'GCResult'}]},[{type,{1254,7},constraint,[{atom,{1254,7},is_subtype},[{var,{1254,7},'Pid'},{type,{1254,14},pid,[]}]]},{type,{1255,7},constraint,[{atom,{1255,7},is_subtype},[{var,{1255,7},'GCResult'},{type,{1255,19},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,51,55>>}},{{function,garbage_collect,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1269}],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<71,97,114,98,97,103,101,32,99,111,108,108,101,99,116,115,32,116,104,101,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,82,101,113,117,101,115,116,73,100,125>>]}]},{dd,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,50>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,101,110,116,46,32,87,104,101,110,32,116,104,101,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,112,97,115,115,101,100,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,44,32,82,101,113,117,101,115,116,73,100,44,32,71,67,82,101,115,117,108,116,125>>]},<<46>>]},{dt,[],[{code,[],[<<123,116,121,112,101,44,32,39,109,97,106,111,114,39,32,124,32,39,109,105,110,111,114,39,125>>]}]},{dd,[],[<<84,114,105,103,103,101,114,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,114,101,113,117,101,115,116,101,100,32,116,121,112,101,46,32,68,101,102,97,117,108,116,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<39,109,97,106,111,114,39>>]},<<44,32,119,104,105,99,104,32,119,111,117,108,100,32,116,114,105,103,103,101,114,32,97,32,102,117,108,108,115,119,101,101,112,32,71,67,46,32,84,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<39,109,105,110,111,114,39>>]},<<32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,32,104,105,110,116,32,97,110,100,32,109,97,121,32,108,101,97,100,32,116,111,32,101,105,116,104,101,114,32,109,105,110,111,114,32,111,114,32,109,97,106,111,114,32,71,67,32,114,117,110,46>>]}]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<44,32,97,110,100,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,116,32,111,110,99,101,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>]}]},<<46,32,79,116,104,101,114,119,105,115,101,32,97,32,114,101,113,117,101,115,116,32,102,111,114,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,110,100,32,119,105,108,108,32,98,101,32,104,97,110,100,108,101,100,32,119,104,101,110,32,97,112,112,114,111,112,114,105,97,116,101,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99>>]},<<32,111,112,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,98,108,111,99,107,115,32,117,110,116,105,108,32>>,{code,[],[<<71,67,82,101,115,117,108,116>>]},<<32,105,115,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<71,67,82,101,115,117,108,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,114,101,113,117,101,115,116,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,104,97,115,32,98,101,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46>>]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[<<78,111,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,119,97,115,32,112,101,114,102,111,114,109,101,100,44,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,116,101,114,109,105,110,97,116,101,100,32,98,101,102,111,114,101,32,116,104,101,32,114,101,113,117,101,115,116,32,99,111,117,108,100,32,98,101,32,115,97,116,105,115,102,105,101,100,46>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,97,109,101,32,99,97,118,101,97,116,115,32,97,112,112,108,121,32,97,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,47,48>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46>>]}]}]},#{signature => [{attribute,{1269,2},spec,{{garbage_collect,2},[{type,{1269,22},bounded_fun,[{type,{1269,22},'fun',[{type,{1269,22},product,[{var,{1269,23},'Pid'},{var,{1269,28},'OptionList'}]},{type,{1269,43},union,[{var,{1269,43},'GCResult'},{atom,{1269,54},async}]}]},[{type,{1270,7},constraint,[{atom,{1270,7},is_subtype},[{var,{1270,7},'Pid'},{type,{1270,14},pid,[]}]]},{type,{1271,7},constraint,[{atom,{1271,7},is_subtype},[{var,{1271,7},'RequestId'},{type,{1271,20},term,[]}]]},{type,{1272,7},constraint,[{atom,{1272,7},is_subtype},[{var,{1272,7},'Option'},{type,{1272,17},union,[{type,{1272,17},tuple,[{atom,{1272,18},async},{var,{1272,25},'RequestId'}]},{type,{1272,38},tuple,[{atom,{1272,39},type},{type,{1272,45},union,[{atom,{1272,45},major},{atom,{1272,55},minor}]}]}]}]]},{type,{1273,7},constraint,[{atom,{1273,7},is_subtype},[{var,{1273,7},'OptionList'},{type,{1273,21},list,[{var,{1273,22},'Option'}]}]]},{type,{1274,7},constraint,[{atom,{1274,7},is_subtype},[{var,{1274,7},'GCResult'},{type,{1274,19},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,55,52,55>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,get,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1319}],[<<103,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,75,101,121,44,32,86,97,108,125>>]},<<32,116,117,112,108,101,115,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,109,101,114,114,121,41,44,10,112,117,116,40,107,101,121,50,44,32,108,97,109,98,115,41,44,10,112,117,116,40,107,101,121,51,44,32,123,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,103,101,116,40,41,46,10,91,123,107,101,121,49,44,109,101,114,114,121,125,44,123,107,101,121,50,44,108,97,109,98,115,125,44,123,107,101,121,51,44,123,97,114,101,44,112,108,97,121,105,110,103,125,125,93>>]}]}]},#{signature => [{attribute,{1319,2},spec,{{get,0},[{type,{1319,10},bounded_fun,[{type,{1319,10},'fun',[{type,{1319,10},product,[]},{type,{1319,16},list,[{type,{1319,17},tuple,[{var,{1319,18},'Key'},{var,{1319,23},'Val'}]}]}]},[{type,{1320,7},constraint,[{atom,{1320,7},is_subtype},[{var,{1320,7},'Key'},{type,{1320,14},term,[]}]]},{type,{1321,7},constraint,[{atom,{1321,7},is_subtype},[{var,{1321,7},'Val'},{type,{1321,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,49,50>>}},{{function,get,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1326}],[<<103,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32>>,{code,[],[<<75,101,121>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,84,104,101,32,101,120,112,101,99,116,101,100,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,107,101,121,49,44,32,109,101,114,114,121,41,44,10,112,117,116,40,107,101,121,50,44,32,108,97,109,98,115,41,44,10,112,117,116,40,123,97,110,121,44,32,91,118,97,108,105,100,44,32,116,101,114,109,93,125,44,32,123,97,114,101,44,32,112,108,97,121,105,110,103,125,41,44,10,103,101,116,40,123,97,110,121,44,32,91,118,97,108,105,100,44,32,116,101,114,109,93,125,41,46,10,123,97,114,101,44,112,108,97,121,105,110,103,125>>]}]}]},#{signature => [{attribute,{1326,2},spec,{{get,1},[{type,{1326,10},bounded_fun,[{type,{1326,10},'fun',[{type,{1326,10},product,[{var,{1326,11},'Key'}]},{type,{1326,19},union,[{var,{1326,19},'Val'},{atom,{1326,25},undefined}]}]},[{type,{1327,7},constraint,[{atom,{1327,7},is_subtype},[{var,{1327,7},'Key'},{type,{1327,14},term,[]}]]},{type,{1328,7},constraint,[{atom,{1328,7},is_subtype},[{var,{1328,7},'Val'},{type,{1328,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,50,57>>}},{{function,get_cookie,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4079}],[<<103,101,116,95,99,111,111,107,105,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,102,32,116,104,101,32,110,111,100,101,32,105,115,32,97,108,105,118,101,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,99,111,111,107,105,101>>]},<<46,32,84,104,105,115,32,118,97,108,117,101,32,105,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,116,95,99,111,111,107,105,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,101,116,95,99,111,111,107,105,101,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{4079,2},spec,{{erlang,get_cookie,0},[{type,{4079,24},bounded_fun,[{type,{4079,24},'fun',[{type,{4079,24},product,[]},{type,{4079,30},union,[{var,{4079,30},'Cookie'},{atom,{4079,39},nocookie}]}]},[{type,{4080,7},constraint,[{atom,{4080,7},is_subtype},[{var,{4080,7},'Cookie'},{type,{4080,17},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,52,57>>}},{{function,get_cookie,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4084}],[<<103,101,116,95,99,111,111,107,105,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,102,111,114,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,97,108,105,118,101,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<110,111,99,111,111,107,105,101>>]},<<46,32,84,104,105,115,32,118,97,108,117,101,32,105,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,116,95,99,111,111,107,105,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,101,116,95,99,111,111,107,105,101,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{4084,2},spec,{{erlang,get_cookie,1},[{type,{4084,24},bounded_fun,[{type,{4084,24},'fun',[{type,{4084,24},product,[{var,{4084,25},'Node'}]},{type,{4084,34},union,[{var,{4084,34},'Cookie'},{atom,{4084,43},nocookie}]}]},[{type,{4085,7},constraint,[{atom,{4085,7},is_subtype},[{var,{4085,7},'Node'},{type,{4085,15},node,[]}]]},{type,{4086,7},constraint,[{atom,{4086,7},is_subtype},[{var,{4086,7},'Cookie'},{type,{4086,17},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,54,48>>,since => <<79,84,80,32,50,52,46,49>>}},{{function,get_keys,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1333}],[<<103,101,116,95,107,101,121,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,107,101,121,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,100,111,103,44,32,123,97,110,105,109,97,108,44,49,125,41,44,10,112,117,116,40,99,111,119,44,32,123,97,110,105,109,97,108,44,50,125,41,44,10,112,117,116,40,108,97,109,98,44,32,123,97,110,105,109,97,108,44,51,125,41,44,10,103,101,116,95,107,101,121,115,40,41,46,10,91,100,111,103,44,99,111,119,44,108,97,109,98,93>>]}]}]},#{signature => [{attribute,{1333,2},spec,{{get_keys,0},[{type,{1333,15},bounded_fun,[{type,{1333,15},'fun',[{type,{1333,15},product,[]},{type,{1333,21},list,[{var,{1333,22},'Key'}]}]},[{type,{1334,7},constraint,[{atom,{1334,7},is_subtype},[{var,{1334,7},'Key'},{type,{1334,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,55,49>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,get_keys,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1339}],[<<103,101,116,95,107,101,121,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,107,101,121,115,32,116,104,97,116,32,97,114,101,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,84,104,101,32,105,116,101,109,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,105,110,32,97,110,121,32,111,114,100,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,117,116,40,109,97,114,121,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,104,97,100,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,97,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,108,105,116,116,108,101,44,32,123,49,44,32,50,125,41,44,10,112,117,116,40,100,111,103,44,32,123,49,44,32,51,125,41,44,10,112,117,116,40,108,97,109,98,44,32,123,49,44,32,50,125,41,44,10,103,101,116,95,107,101,121,115,40,123,49,44,32,50,125,41,46,10,91,109,97,114,121,44,104,97,100,44,97,44,108,105,116,116,108,101,44,108,97,109,98,93>>]}]}]},#{signature => [{attribute,{1339,2},spec,{{get_keys,1},[{type,{1339,15},bounded_fun,[{type,{1339,15},'fun',[{type,{1339,15},product,[{var,{1339,16},'Val'}]},{type,{1339,24},list,[{var,{1339,25},'Key'}]}]},[{type,{1340,7},constraint,[{atom,{1340,7},is_subtype},[{var,{1340,7},'Val'},{type,{1340,14},term,[]}]]},{type,{1341,7},constraint,[{atom,{1341,7},is_subtype},[{var,{1341,7},'Key'},{type,{1341,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,56,56,56>>}},{{function,group_leader,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1353}],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<69,118,101,114,121,32,112,114,111,99,101,115,115,32,105,115,32,97,32,109,101,109,98,101,114,32,111,102,32,115,111,109,101,32,112,114,111,99,101,115,115,32,103,114,111,117,112,32,97,110,100,32,97,108,108,32,103,114,111,117,112,115,32,104,97,118,101,32,97,32>>,{em,[],[<<103,114,111,117,112,32,108,101,97,100,101,114>>]},<<46,32,65,108,108,32,73,47,79,32,102,114,111,109,32,116,104,101,32,103,114,111,117,112,32,105,115,32,99,104,97,110,110,101,108,101,100,32,116,111,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,46,32,87,104,101,110,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,112,97,119,110,101,100,44,32,105,116,32,103,101,116,115,32,116,104,101,32,115,97,109,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,97,115,32,116,104,101,32,115,112,97,119,110,105,110,103,32,112,114,111,99,101,115,115,46,32,73,110,105,116,105,97,108,108,121,44,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,117,112,44,32>>,{code,[],[<<105,110,105,116>>]},<<32,105,115,32,98,111,116,104,32,105,116,115,32,111,119,110,32,103,114,111,117,112,32,108,101,97,100,101,114,32,97,110,100,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32,97,108,108,32,112,114,111,99,101,115,115,101,115,46>>]}]},#{signature => [{attribute,{1353,2},spec,{{group_leader,0},[{type,{1353,19},'fun',[{type,{1353,19},product,[]},{type,{1353,25},pid,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,48,56>>}},{{function,group_leader,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1358}],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<32,116,111,32>>,{code,[],[<<71,114,111,117,112,76,101,97,100,101,114>>]},<<46,32,84,121,112,105,99,97,108,108,121,44,32,116,104,105,115,32,105,115,32,117,115,101,100,32,119,104,101,110,32,97,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,102,114,111,109,32,97,32,99,101,114,116,97,105,110,32,115,104,101,108,108,32,105,115,32,116,111,32,104,97,118,101,32,97,110,111,116,104,101,114,32,103,114,111,117,112,32,108,101,97,100,101,114,32,116,104,97,110,32>>,{code,[],[<<105,110,105,116>>]},<<46>>]},{p,[],[<<84,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,115,104,111,117,108,100,32,98,101,32,114,97,114,101,108,121,32,99,104,97,110,103,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,115,32,119,105,116,104,32,97,32,115,117,112,101,114,118,105,115,105,111,110,32,116,114,101,101,44,32,98,101,99,97,117,115,101,32,79,84,80,32,97,115,115,117,109,101,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,111,102,32,116,104,101,105,114,32,112,114,111,99,101,115,115,101,115,32,105,115,32,116,104,101,105,114,32,97,112,112,108,105,99,97,116,105,111,110,32,109,97,115,116,101,114,46>>]},{p,[],[<<83,101,116,116,105,110,103,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,102,111,108,108,111,119,115,32,116,104,101,32,115,105,103,110,97,108,32,111,114,100,101,114,105,110,103,32,103,117,97,114,97,110,116,101,101,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<80,114,111,99,101,115,115,101,115,32,67,104,97,112,116,101,114>>]},<<32,105,110,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,114,111,117,112,95,108,101,97,100,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,114,111,117,112,95,108,101,97,100,101,114,47,48>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,121,115,116,101,109,47,100,101,115,105,103,110,95,112,114,105,110,99,105,112,108,101,115,58,97,112,112,108,105,99,97,116,105,111,110,115,35,115,116,111,112,112,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,84,80,32,100,101,115,105,103,110,32,112,114,105,110,99,105,112,108,101,115>>]},<<32,114,101,108,97,116,101,100,32,116,111,32,115,116,97,114,116,105,110,103,32,97,110,100,32,115,116,111,112,112,105,110,103,32,97,112,112,108,105,99,97,116,105,111,110,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]}]},#{signature => [{attribute,{1358,2},spec,{{group_leader,2},[{type,{1358,19},bounded_fun,[{type,{1358,19},'fun',[{type,{1358,19},product,[{var,{1358,20},'GroupLeader'},{var,{1358,33},'Pid'}]},{atom,{1358,41},true}]},[{type,{1359,7},constraint,[{atom,{1359,7},is_subtype},[{var,{1359,7},'GroupLeader'},{type,{1359,22},pid,[]}]]},{type,{1360,7},constraint,[{atom,{1360,7},is_subtype},[{var,{1360,7},'Pid'},{type,{1360,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,50,51>>}},{{function,halt,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1378}],[<<104,97,108,116,47,48>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<104,97,108,116,40,48,44,32,91,93,41>>]}]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,104,97,108,116,40,41,46,10,111,115,95,112,114,111,109,112,116,37>>]}]}]},#{signature => [{attribute,{1378,2},spec,{{halt,0},[{type,{1378,11},'fun',[{type,{1378,11},product,[]},{type,{1378,17},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,53,52>>}},{{function,halt,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1384}],[<<104,97,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<104,97,108,116,40,83,116,97,116,117,115,44,32,91,93,41>>]}]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,104,97,108,116,40,49,55,41,46,10,111,115,95,112,114,111,109,112,116,37,32,101,99,104,111,32,36,63,10,49,55,10,111,115,95,112,114,111,109,112,116,37>>]}]}]},#{signature => [{attribute,{1384,2},spec,{{halt,1},[{type,{1384,11},'fun',[{type,{1384,11},product,[{ann_type,{1384,12},[{var,{1384,12},'Status'},{type,{1384,22},non_neg_integer,[]}]}]},{type,{1385,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,54,55>>}},{{function,halt,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1384}],[<<104,97,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,95,97,98,111,114,116,95,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,97,108,116,40,97,98,111,114,116,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1384,2},spec,{{halt,1},[{type,{1386,11},'fun',[{type,{1386,11},product,[{ann_type,{1386,12},[{var,{1386,12},'Abort'},{atom,{1386,21},abort}]}]},{type,{1387,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,56,50>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,halt,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1384}],[<<104,97,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,95,99,114,97,115,104,95,100,117,109,112,95,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,97,108,116,40,67,114,97,115,104,68,117,109,112,83,108,111,103,97,110,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1384,2},spec,{{halt,1},[{type,{1388,11},'fun',[{type,{1388,11},product,[{ann_type,{1388,12},[{var,{1388,12},'CrashDumpSlogan'},{type,{1388,31},string,[]}]}]},{type,{1389,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,50,57,57,52>>}},{{function,halt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1404}],[<<104,97,108,116,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<104,97,108,116,95,111,112,116,105,111,110,115>>}],[]}]},{p,[],[<<72,97,108,116,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,116,104,32,115,116,97,116,117,115,32,99,111,100,101,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,110,32,109,97,110,121,32,112,108,97,116,102,111,114,109,115,44,32,116,104,101,32,79,83,32,115,117,112,112,111,114,116,115,32,111,110,108,121,32,115,116,97,116,117,115,32,99,111,100,101,115,32,48,45,50,53,53,46,32,65,32,116,111,111,32,108,97,114,103,101,32,115,116,97,116,117,115,32,99,111,100,101,32,105,115,32,116,114,117,110,99,97,116,101,100,32,98,121,32,99,108,101,97,114,105,110,103,32,116,104,101,32,104,105,103,104,32,98,105,116,115,46>>]}]},{p,[],[<<67,117,114,114,101,110,116,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,32,97,114,101,32,118,97,108,105,100,58>>]},{dl,[],[{dt,[],[{a,[{id,<<104,97,108,116,95,102,108,117,115,104>>}],[]},{code,[],[<<123,102,108,117,115,104,44,32,69,110,97,98,108,101,70,108,117,115,104,105,110,103,125>>]}]},{dd,[],[{p,[],[<<73,102,32>>,{code,[],[<<69,110,97,98,108,101,70,108,117,115,104,105,110,103>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,119,104,105,99,104,32,97,108,115,111,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,32,112,101,114,102,111,114,109,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,101,114,97,116,105,111,110,115,32,98,101,102,111,114,101,32,116,101,114,109,105,110,97,116,105,110,103,58>>]},{ul,[],[{li,[],[{p,[],[<<70,108,117,115,104,32,97,108,108,32,111,117,116,115,116,97,110,100,105,110,103,32,111,117,116,112,117,116,46>>]}]},{li,[],[{p,[],[<<83,101,110,100,32,97,108,108,32,69,114,108,97,110,103,32,112,111,114,116,115,32,101,120,105,116,32,115,105,103,110,97,108,115,32,97,110,100,32,119,97,105,116,32,102,111,114,32,116,104,101,109,32,116,111,32,101,120,105,116,46>>]}]},{li,[],[{p,[],[<<87,97,105,116,32,102,111,114,32,97,108,108,32,97,115,121,110,99,32,116,104,114,101,97,100,115,32,116,111,32,99,111,109,112,108,101,116,101,32,97,108,108,32,111,117,116,115,116,97,110,100,105,110,103,32,97,115,121,110,99,32,106,111,98,115,46>>]}]},{li,[],[{p,[],[<<67,97,108,108,32,97,108,108,32,105,110,115,116,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,111,110,95,104,97,108,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<78,73,70,32>>,{i,[],[<<111,110,32,104,97,108,116>>]},<<32,99,97,108,108,98,97,99,107,115>>]},<<46>>]}]},{li,[],[{p,[],[<<87,97,105,116,32,102,111,114,32,97,108,108,32,111,110,103,111,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,100,101,108,97,121,95,104,97,108,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<78,73,70,32,99,97,108,108,115,32,119,105,116,104,32,116,104,101,32>>,{i,[],[<<100,101,108,97,121,32,104,97,108,116>>]},<<32,115,101,116,116,105,110,103>>]},<<32,101,110,97,98,108,101,100,32,116,111,32,114,101,116,117,114,110,46>>]}]},{li,[],[{p,[],[<<67,97,108,108,32,97,108,108,32,105,110,115,116,97,108,108,101,100,32>>,{code,[],[<<97,116,101,120,105,116>>]},<<47>>,{code,[],[<<111,110,95,101,120,105,116>>]},<<32,99,97,108,108,98,97,99,107,115,46>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<69,110,97,98,108,101,70,108,117,115,104,105,110,103>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,32,116,101,114,109,105,110,97,116,101,32,105,109,109,101,100,105,97,116,101,108,121,32,119,105,116,104,111,117,116,32,112,101,114,102,111,114,109,105,110,103,32,97,110,121,32,111,102,32,116,104,101,32,97,98,111,118,101,32,108,105,115,116,101,100,32,111,112,101,114,97,116,105,111,110,115,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<82,117,110,116,105,109,101,32,115,121,115,116,101,109,115,32,112,114,105,111,114,32,116,111,32,79,84,80,32,50,54,46,48,32,99,97,108,108,101,100,32,97,108,108,32,105,110,115,116,97,108,108,101,100,32>>,{code,[],[<<97,116,101,120,105,116>>]},<<47>>,{code,[],[<<111,110,95,101,120,105,116>>]},<<32,99,97,108,108,98,97,99,107,115,32,97,108,115,111,32,119,104,101,110,32>>,{code,[],[<<102,108,117,115,104>>]},<<32,119,97,115,32,100,105,115,97,98,108,101,100,44,32,98,117,116,32,97,115,32,111,102,32,79,84,80,32,50,54,46,48,32,116,104,105,115,32,105,115,32,110,111,32,108,111,110,103,101,114,32,116,104,101,32,99,97,115,101,46>>]}]}]}]}]},#{signature => [{attribute,{1404,2},spec,{{halt,2},[{type,{1404,11},'fun',[{type,{1404,11},product,[{ann_type,{1404,12},[{var,{1404,12},'Status'},{type,{1404,22},non_neg_integer,[]}]},{ann_type,{1404,41},[{var,{1404,41},'Options'},{user_type,{1404,52},halt_options,[]}]}]},{type,{1405,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,48,56>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,halt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1404}],[<<104,97,108,116,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<104,97,108,116,95,111,112,116,105,111,110,115>>}],[]}]},{p,[],[<<72,97,108,116,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,98,121,32,97,98,111,114,116,105,110,103,32,97,110,100,32,112,114,111,100,117,99,101,32,97,32,99,111,114,101,32,100,117,109,112,32,105,102,32,99,111,114,101,32,100,117,109,112,105,110,103,32,104,97,115,32,98,101,101,110,32,101,110,97,98,108,101,100,32,105,110,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,116,104,97,116,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,101,120,101,99,117,116,105,110,103,32,105,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,95,102,108,117,115,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<123,102,108,117,115,104,44,32,98,111,111,108,101,97,110,40,41,125>>]}]},<<32,111,112,116,105,111,110,32,119,105,108,108,32,98,101,32,105,103,110,111,114,101,100,44,32,97,110,100,32,102,108,117,115,104,105,110,103,32,119,105,108,108,32,98,101,32,100,105,115,97,98,108,101,100,46>>]}]}]},#{signature => [{attribute,{1404,2},spec,{{halt,2},[{type,{1406,11},'fun',[{type,{1406,11},product,[{ann_type,{1406,12},[{var,{1406,12},'Abort'},{atom,{1406,21},abort}]},{ann_type,{1406,28},[{var,{1406,28},'Options'},{user_type,{1406,39},halt_options,[]}]}]},{type,{1407,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,55,55>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,halt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1404}],[<<104,97,108,116,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<104,97,108,116,95,111,112,116,105,111,110,115>>}],[]}]},{p,[],[<<72,97,108,116,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,97,110,100,32,103,101,110,101,114,97,116,101,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112>>]},<<46,32,84,104,101,32,115,116,114,105,110,103,32>>,{code,[],[<<67,114,97,115,104,68,117,109,112,83,108,111,103,97,110>>]},<<32,119,105,108,108,32,98,101,32,117,115,101,100,32,97,115,32,115,108,111,103,97,110,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,32,99,114,101,97,116,101,100,46,32,84,104,101,32,115,108,111,103,97,110,32,119,105,108,108,32,98,101,32,116,114,117,110,107,97,116,101,100,32,105,102,32>>,{code,[],[<<67,114,97,115,104,68,117,109,112,83,108,111,103,97,110>>]},<<32,105,115,32,108,111,110,103,101,114,32,116,104,97,110,32,49,48,50,51,32,99,104,97,114,97,99,116,101,114,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,104,97,108,116,95,102,108,117,115,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<123,102,108,117,115,104,44,32,98,111,111,108,101,97,110,40,41,125>>]}]},<<32,111,112,116,105,111,110,32,119,105,108,108,32,98,101,32,105,103,110,111,114,101,100,44,32,97,110,100,32,102,108,117,115,104,105,110,103,32,119,105,108,108,32,98,101,32,100,105,115,97,98,108,101,100,46>>]}]},{p,[],[<<66,101,104,97,118,105,111,114,32,99,104,97,110,103,101,115,32,99,111,109,112,97,114,101,100,32,116,111,32,101,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,58>>]},{ul,[],[{li,[],[{p,[],[<<66,101,102,111,114,101,32,79,84,80,32,50,52,46,50,44,32,116,104,101,32,115,108,111,103,97,110,32,119,97,115,32,116,114,117,110,99,97,116,101,100,32,105,102,32>>,{code,[],[<<67,114,97,115,104,68,117,109,112,83,108,111,103,97,110>>]},<<32,119,97,115,32,108,111,110,103,101,114,32,116,104,97,110,32,50,48,48,32,99,104,97,114,97,99,116,101,114,115,46,32,78,111,119,32,105,116,32,119,105,108,108,32,98,101,32,116,114,117,110,99,97,116,101,100,32,105,102,32,108,111,110,103,101,114,32,116,104,97,110,32,49,48,50,51,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{li,[],[{p,[],[<<66,101,102,111,114,101,32,79,84,80,32,50,48,46,49,44,32,111,110,108,121,32,99,111,100,101,32,112,111,105,110,116,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,45,50,53,53,32,119,101,114,101,32,97,99,99,101,112,116,101,100,32,105,110,32,116,104,101,32,115,108,111,103,97,110,46,32,78,111,119,32,97,110,121,32,85,110,105,99,111,100,101,32,115,116,114,105,110,103,32,105,115,32,118,97,108,105,100,46>>]}]}]}]},#{signature => [{attribute,{1404,2},spec,{{halt,2},[{type,{1408,11},'fun',[{type,{1408,11},product,[{ann_type,{1408,12},[{var,{1408,12},'CrashDumpSlogan'},{type,{1408,31},string,[]}]},{ann_type,{1408,41},[{var,{1408,41},'Options'},{user_type,{1408,52},halt_options,[]}]}]},{type,{1409,11},no_return,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,48,57,53>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,hd,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2426}],[<<104,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,104,101,97,100,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,46>>]},{p,[],[<<73,116,32,119,111,114,107,115,32,119,105,116,104,32,105,109,112,114,111,112,101,114,32,108,105,115,116,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,104,100,40,91,49,44,50,44,51,44,52,44,53,93,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,104,100,40,91,102,105,114,115,116,44,32,115,101,99,111,110,100,44,32,116,104,105,114,100,44,32,115,111,95,111,110,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93,41,46,10,102,105,114,115,116>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,105,115,116>>]},<<32,105,115,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46>>]}]},#{signature => [{attribute,{2426,2},spec,{{hd,1},[{type,{2426,9},bounded_fun,[{type,{2426,9},'fun',[{type,{2426,9},product,[{var,{2426,10},'List'}]},{var,{2426,19},'Head'}]},[{type,{2427,7},constraint,[{atom,{2427,7},is_subtype},[{var,{2427,7},'List'},{type,{2427,15},nonempty_maybe_improper_list,[]}]]},{type,{2428,7},constraint,[{atom,{2428,7},is_subtype},[{var,{2428,7},'Head'},{type,{2428,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,51,54>>}},{{function,hibernate,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1422}],[<<104,105,98,101,114,110,97,116,101,47,51>>],#{<<101,110>> => [{p,[],[<<80,117,116,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,110,116,111,32,97,32,119,97,105,116,32,115,116,97,116,101,32,119,104,101,114,101,32,105,116,115,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,114,101,100,117,99,101,100,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,100,111,101,115,32,110,111,116,32,101,120,112,101,99,116,32,116,111,32,114,101,99,101,105,118,101,32,97,110,121,32,109,101,115,115,97,103,101,115,32,115,111,111,110,46>>]},{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,32,119,104,101,110,32,97,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,105,116,44,32,97,110,100,32,99,111,110,116,114,111,108,32,114,101,115,117,109,101,115,32,105,110,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,119,105,116,104,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<65,114,103,115>>]},<<32,119,105,116,104,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,101,109,112,116,105,101,100,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,116,104,101,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,32,119,104,101,110,32,116,104,97,116,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46,32,84,104,117,115,32>>,{code,[],[<<101,114,108,97,110,103,58,104,105,98,101,114,110,97,116,101,47,51>>]},<<32,110,101,118,101,114,32,114,101,116,117,114,110,115,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46,32,84,104,101,32,114,101,115,117,109,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,109,117,115,116,32,98,101,32,101,120,112,111,114,116,101,100,32,40>>,{code,[],[<<65,114,105,116,121>>]},<<32,61,58,61,32>>,{code,[],[<<108,101,110,103,116,104,40,65,114,103,115,41>>]},<<41,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,97,110,121,32,109,101,115,115,97,103,101,32,105,110,32,105,116,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,44,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,101,100,32,105,109,109,101,100,105,97,116,101,108,121,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46>>]},{p,[],[<<73,110,32,109,111,114,101,32,116,101,99,104,110,105,99,97,108,32,116,101,114,109,115,44,32>>,{code,[],[<<101,114,108,97,110,103,58,104,105,98,101,114,110,97,116,101,47,51>>]},<<32,100,105,115,99,97,114,100,115,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,97,110,100,32,116,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,115,32,116,104,101,32,112,114,111,99,101,115,115,46,32,65,102,116,101,114,32,116,104,105,115,44,32,97,108,108,32,108,105,118,101,32,100,97,116,97,32,105,115,32,105,110,32,111,110,101,32,99,111,110,116,105,110,117,111,117,115,32,104,101,97,112,46,32,84,104,101,32,104,101,97,112,32,105,115,32,116,104,101,110,32,115,104,114,117,110,107,101,110,32,116,111,32,116,104,101,32,101,120,97,99,116,32,115,97,109,101,32,115,105,122,101,32,97,115,32,116,104,101,32,108,105,118,101,32,100,97,116,97,32,116,104,97,116,32,105,116,32,104,111,108,100,115,32,40,101,118,101,110,32,105,102,32,116,104,97,116,32,115,105,122,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,41,46>>]},{p,[],[<<73,102,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,108,105,118,101,32,100,97,116,97,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,44,32,116,104,101,32,102,105,114,115,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,99,99,117,114,114,105,110,103,32,97,102,116,101,114,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,119,97,107,101,110,101,100,32,101,110,115,117,114,101,115,32,116,104,97,116,32,116,104,101,32,104,101,97,112,32,115,105,122,101,32,105,115,32,99,104,97,110,103,101,100,32,116,111,32,97,32,115,105,122,101,32,110,111,116,32,115,109,97,108,108,101,114,32,116,104,97,110,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,101,109,112,116,121,105,110,103,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,32,109,101,97,110,115,32,116,104,97,116,32,97,110,121,32,115,117,114,114,111,117,110,100,105,110,103,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,105,115,32,114,101,109,111,118,101,100,32,97,110,100,32,109,117,115,116,32,98,101,32,114,101,45,105,110,115,101,114,116,101,100,32,97,102,116,101,114,32,104,105,98,101,114,110,97,116,105,111,110,46,32,79,110,101,32,101,102,102,101,99,116,32,111,102,32,116,104,105,115,32,105,115,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,115,116,97,114,116,101,100,32,117,115,105,110,103,32>>,{code,[],[<<112,114,111,99,95,108,105,98>>]},<<32,40,97,108,115,111,32,105,110,100,105,114,101,99,116,108,121,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<103,101,110,95,115,101,114,118,101,114>>]},<<32,112,114,111,99,101,115,115,101,115,41,44,32,97,114,101,32,116,111,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,112,114,111,99,95,108,105,98,35,104,105,98,101,114,110,97,116,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,95,108,105,98,58,104,105,98,101,114,110,97,116,101,47,51>>]}]},<<32,105,110,115,116,101,97,100,44,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,104,97,110,100,108,101,114,32,99,111,110,116,105,110,117,101,115,32,116,111,32,119,111,114,107,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,107,101,115,32,117,112,46>>]}]},#{signature => [{attribute,{1422,2},spec,{{erlang,hibernate,3},[{type,{1422,23},bounded_fun,[{type,{1422,23},'fun',[{type,{1422,23},product,[{var,{1422,24},'Module'},{var,{1422,32},'Function'},{var,{1422,42},'Args'}]},{type,{1422,51},no_return,[]}]},[{type,{1423,7},constraint,[{atom,{1423,7},is_subtype},[{var,{1423,7},'Module'},{type,{1423,17},module,[]}]]},{type,{1424,7},constraint,[{atom,{1424,7},is_subtype},[{var,{1424,7},'Function'},{type,{1424,19},atom,[]}]]},{type,{1425,7},constraint,[{atom,{1425,7},is_subtype},[{var,{1425,7},'Args'},{type,{1425,15},list,[{type,{1425,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,49,53,54>>}},{{function,insert_element,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1430}],[<<105,110,115,101,114,116,95,101,108,101,109,101,110,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,101,119,32,116,117,112,108,101,32,119,105,116,104,32,101,108,101,109,101,110,116,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,110,115,101,114,116,101,100,32,97,116,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,105,110,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<46,32,65,108,108,32,101,108,101,109,101,110,116,115,32,102,114,111,109,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,97,110,100,32,117,112,119,97,114,100,115,32,97,114,101,32,112,117,115,104,101,100,32,111,110,101,32,115,116,101,112,32,104,105,103,104,101,114,32,105,110,32,116,104,101,32,110,101,119,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,50>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,105,110,115,101,114,116,95,101,108,101,109,101,110,116,40,50,44,32,123,111,110,101,44,32,116,119,111,44,32,116,104,114,101,101,125,44,32,110,101,119,41,46,10,123,111,110,101,44,110,101,119,44,116,119,111,44,116,104,114,101,101,125>>]}]}]},#{signature => [{attribute,{1430,2},spec,{{erlang,insert_element,3},[{type,{1430,28},bounded_fun,[{type,{1430,28},'fun',[{type,{1430,28},product,[{var,{1430,29},'Index'},{var,{1430,36},'Tuple1'},{var,{1430,44},'Term'}]},{var,{1430,53},'Tuple2'}]},[{type,{1431,7},constraint,[{atom,{1431,7},is_subtype},[{var,{1431,7},'Index'},{type,{1431,17},pos_integer,[]}]]},{type,{1432,7},constraint,[{atom,{1432,7},is_subtype},[{var,{1432,7},'Tuple1'},{type,{1432,17},tuple,any}]]},{type,{1433,7},constraint,[{atom,{1433,7},is_subtype},[{var,{1433,7},'Tuple2'},{type,{1433,17},tuple,any}]]},{type,{1434,7},constraint,[{atom,{1434,7},is_subtype},[{var,{1434,7},'Term'},{type,{1434,17},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,48,48>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1439}],[<<105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,40,55,55,41,46,10,60,60,34,55,55,34,62,62>>]}]}]},#{signature => [{attribute,{1439,2},spec,{{integer_to_binary,1},[{type,{1439,24},bounded_fun,[{type,{1439,24},'fun',[{type,{1439,24},product,[{var,{1439,25},'Integer'}]},{type,{1439,37},binary,[]}]},[{type,{1440,7},constraint,[{atom,{1440,7},is_subtype},[{var,{1440,7},'Integer'},{type,{1440,18},integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,49,56>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4099}],[<<105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,98,105,110,97,114,121,40,49,48,50,51,44,32,49,54,41,46,10,60,60,34,51,70,70,34,62,62>>]}]}]},#{signature => [{attribute,{4099,2},spec,{{integer_to_binary,2},[{type,{4099,24},bounded_fun,[{type,{4099,24},'fun',[{type,{4099,24},product,[{var,{4099,25},'Integer'},{var,{4099,34},'Base'}]},{type,{4099,43},binary,[]}]},[{type,{4100,7},constraint,[{atom,{4100,7},is_subtype},[{var,{4100,7},'Integer'},{type,{4100,18},integer,[]}]]},{type,{4101,7},constraint,[{atom,{4101,7},is_subtype},[{var,{4101,7},'Base'},{type,{4101,15},range,[{integer,{4101,15},2},{integer,{4101,18},36}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,51,48>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,integer_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1445}],[<<105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,40,55,55,41,46,10,34,55,55,34>>]}]}]},#{signature => [{attribute,{1445,2},spec,{{integer_to_list,1},[{type,{1445,22},bounded_fun,[{type,{1445,22},'fun',[{type,{1445,22},product,[{var,{1445,23},'Integer'}]},{type,{1445,35},string,[]}]},[{type,{1446,7},constraint,[{atom,{1446,7},is_subtype},[{var,{1446,7},'Integer'},{type,{1446,18},integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,52,51>>}},{{function,integer_to_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4093}],[<<105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<73,110,116,101,103,101,114>>]},<<32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,110,116,101,103,101,114,95,116,111,95,108,105,115,116,40,49,48,50,51,44,32,49,54,41,46,10,34,51,70,70,34>>]}]}]},#{signature => [{attribute,{4093,2},spec,{{integer_to_list,2},[{type,{4093,22},bounded_fun,[{type,{4093,22},'fun',[{type,{4093,22},product,[{var,{4093,23},'Integer'},{var,{4093,32},'Base'}]},{type,{4093,41},string,[]}]},[{type,{4094,7},constraint,[{atom,{4094,7},is_subtype},[{var,{4094,7},'Integer'},{type,{4094,18},integer,[]}]]},{type,{4095,7},constraint,[{atom,{4095,7},is_subtype},[{var,{4095,7},'Base'},{type,{4095,15},range,[{integer,{4095,15},2},{integer,{4095,18},36}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,53,53>>}},{{function,iolist_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1451}],[<<105,111,108,105,115,116,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,97,116,32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,121,116,101,115,44,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,116,104,97,116,32,119,111,117,108,100,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,73,116,101,109,41>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,105,111,108,105,115,116,95,115,105,122,101,40,91,49,44,50,124,60,60,51,44,52,62,62,93,41,46,10,52>>]}]}]},#{signature => [{attribute,{1451,2},spec,{{iolist_size,1},[{type,{1451,18},bounded_fun,[{type,{1451,18},'fun',[{type,{1451,18},product,[{var,{1451,19},'Item'}]},{type,{1451,28},non_neg_integer,[]}]},[{type,{1452,7},constraint,[{atom,{1452,7},is_subtype},[{var,{1452,7},'Item'},{type,{1452,15},union,[{type,{1452,15},iolist,[]},{type,{1452,26},binary,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,54,56>>}},{{function,iolist_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1457}],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116,79,114,66,105,110,97,114,121>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,62,62,46,10,60,60,54,62,62,10,62,32,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,62,62>>]}]}]},#{signature => [{attribute,{1457,2},spec,{{iolist_to_binary,1},[{type,{1457,23},bounded_fun,[{type,{1457,23},'fun',[{type,{1457,23},product,[{var,{1457,24},'IoListOrBinary'}]},{type,{1457,43},binary,[]}]},[{type,{1458,7},constraint,[{atom,{1458,7},is_subtype},[{var,{1458,7},'IoListOrBinary'},{type,{1458,25},union,[{type,{1458,25},iolist,[]},{type,{1458,36},binary,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,56,49>>}},{{function,iolist_to_iovec,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1463}],[<<105,111,108,105,115,116,95,116,111,95,105,111,118,101,99,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<105,111,118,101,99>>]},<<32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116,79,114,66,105,110,97,114,121>>]},<<46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,117,115,101,102,117,108,32,119,104,101,110,32,121,111,117,32,119,97,110,116,32,116,111,32,102,108,97,116,116,101,110,32,97,110,32,105,111,108,105,115,116,32,98,117,116,32,121,111,117,32,100,111,32,110,111,116,32,110,101,101,100,32,97,32,115,105,110,103,108,101,32,98,105,110,97,114,121,46,32,84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,102,111,114,32,112,97,115,115,105,110,103,32,116,104,101,32,100,97,116,97,32,116,111,32,110,105,102,32,102,117,110,99,116,105,111,110,115,32,115,117,99,104,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>]}]},<<32,111,114,32,100,111,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,109,101,115,115,97,103,101,32,112,97,115,115,105,110,103,46,32,84,104,101,32,97,100,118,97,110,116,97,103,101,32,111,102,32,117,115,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,111,118,101,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<32,105,115,32,116,104,97,116,32,105,116,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,116,111,32,99,111,112,121,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,98,105,110,97,114,121,104,97,110,100,108,105,110,103,35,114,101,102,99,95,98,105,110,97,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,62,62,46,10,60,60,54,62,62,10,37,37,32,73,102,32,121,111,117,32,112,97,115,115,32,115,109,97,108,108,32,98,105,110,97,114,105,101,115,32,97,110,100,32,105,110,116,101,103,101,114,115,32,105,116,32,119,111,114,107,115,32,97,115,32,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,10,62,32,101,114,108,97,110,103,58,105,111,108,105,115,116,95,116,111,95,105,111,118,101,99,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,91,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,62,62,93,10,37,37,32,73,102,32,121,111,117,32,112,97,115,115,32,108,97,114,103,101,114,32,98,105,110,97,114,105,101,115,44,32,116,104,101,121,32,97,114,101,32,115,112,108,105,116,32,97,110,100,32,114,101,116,117,114,110,101,100,32,105,110,32,97,32,102,111,114,109,10,37,37,32,111,112,116,105,109,105,122,101,100,32,102,111,114,32,99,97,108,108,105,110,103,32,116,104,101,32,67,32,102,117,110,99,116,105,111,110,32,119,114,105,116,101,118,46,10,62,32,101,114,108,97,110,103,58,105,111,108,105,115,116,95,116,111,95,105,111,118,101,99,40,91,60,60,49,62,62,44,60,60,50,58,56,48,57,54,62,62,44,60,60,51,58,56,48,57,54,62,62,93,41,46,10,91,60,60,49,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,10,32,32,32,48,44,46,46,46,62,62,44,10,32,60,60,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,10,32,32,32,46,46,46,62,62,44,10,32,60,60,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,46,46,46,62,62,93>>]}]}]},#{signature => [{attribute,{1463,2},spec,{{erlang,iolist_to_iovec,1},[{type,{1463,29},bounded_fun,[{type,{1463,29},'fun',[{type,{1463,29},product,[{var,{1463,30},'IoListOrBinary'}]},{user_type,{1463,49},iovec,[]}]},[{type,{1464,7},constraint,[{atom,{1464,7},is_subtype},[{var,{1464,7},'IoListOrBinary'},{type,{1464,25},union,[{type,{1464,25},iolist,[]},{type,{1464,36},binary,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,50,57,57>>,since => <<79,84,80,32,50,48,46,49>>}},{{function,is_alive,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1469}],[<<105,115,95,97,108,105,118,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,97,108,105,118,101,32,40,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,111,100,101,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,97,32,100,105,115,116,114,105,98,117,116,101,100,32,115,121,115,116,101,109,41,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,65,32,110,111,100,101,32,105,115,32,97,108,105,118,101,32,105,102,32,105,116,32,105,115,32,115,116,97,114,116,101,100,32,119,105,116,104,58>>]},{ol,[],[{li,[],[{a,[{href,<<101,114,116,115,58,101,114,108,35,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<34,101,114,108,32,45,110,97,109,101,32,76,79,78,71,78,65,77,69,34>>]}]},<<32,111,114,44>>]},{li,[],[{a,[{href,<<101,114,116,115,58,101,114,108,35,115,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<34,101,114,108,32,45,115,110,97,109,101,32,83,72,79,82,84,78,65,77,69,34>>]}]},<<46>>]}]},{p,[],[<<65,32,110,111,100,101,32,99,97,110,32,97,108,115,111,32,98,101,32,97,108,105,118,101,32,105,102,32,105,116,32,104,97,115,32,103,111,116,32,97,32,110,97,109,101,32,102,114,111,109,32,97,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,97,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,97,114,116,47,50>>]}]},<<32,97,110,100,32,104,97,115,32,110,111,116,32,98,101,101,110,32,115,116,111,112,112,101,100,32,98,121,32,97,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,111,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,111,112,47,48>>]}]},<<46>>]}]},#{signature => [{attribute,{1469,2},spec,{{is_alive,0},[{type,{1469,15},'fun',[{type,{1469,15},product,[]},{type,{1469,21},boolean,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,51,54>>}},{{function,is_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2435}],[<<105,115,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,97,116,111,109,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2435,2},spec,{{is_atom,1},[{type,{2435,14},bounded_fun,[{type,{2435,14},'fun',[{type,{2435,14},product,[{var,{2435,15},'Term'}]},{type,{2435,24},boolean,[]}]},[{type,{2436,7},constraint,[{atom,{2436,7},is_subtype},[{var,{2436,7},'Term'},{type,{2436,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,53,53>>}},{{function,is_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2441}],[<<105,115,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,32,98,105,110,97,114,121,32,97,108,119,97,121,115,32,99,111,110,116,97,105,110,115,32,97,32,99,111,109,112,108,101,116,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2441,2},spec,{{is_binary,1},[{type,{2441,16},bounded_fun,[{type,{2441,16},'fun',[{type,{2441,16},product,[{var,{2441,17},'Term'}]},{type,{2441,26},boolean,[]}]},[{type,{2442,7},constraint,[{atom,{2442,7},is_subtype},[{var,{2442,7},'Term'},{type,{2442,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,54,53>>}},{{function,is_bitstring,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2447}],[<<105,115,95,98,105,116,115,116,114,105,110,103,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,98,105,116,115,116,114,105,110,103,32,40,105,110,99,108,117,100,105,110,103,32,97,32,98,105,110,97,114,121,41,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2447,2},spec,{{is_bitstring,1},[{type,{2447,19},bounded_fun,[{type,{2447,19},'fun',[{type,{2447,19},product,[{var,{2447,20},'Term'}]},{type,{2447,29},boolean,[]}]},[{type,{2448,7},constraint,[{atom,{2448,7},is_subtype},[{var,{2448,7},'Term'},{type,{2448,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,55,54>>}},{{function,is_boolean,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2453}],[<<105,115,95,98,111,111,108,101,97,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<116,114,117,101>>]},<<32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,116,104,97,116,32,105,115,44,32,97,32,98,111,111,108,101,97,110,41,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2453,2},spec,{{is_boolean,1},[{type,{2453,17},bounded_fun,[{type,{2453,17},'fun',[{type,{2453,17},product,[{var,{2453,18},'Term'}]},{type,{2453,27},boolean,[]}]},[{type,{2454,7},constraint,[{atom,{2454,7},is_subtype},[{var,{2454,7},'Term'},{type,{2454,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,56,54>>}},{{function,is_builtin,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1474}],[<<105,115,95,98,117,105,108,116,105,110,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,117,115,101,102,117,108,32,102,111,114,32,98,117,105,108,100,101,114,115,32,111,102,32,99,114,111,115,115,45,114,101,102,101,114,101,110,99,101,32,116,111,111,108,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,105,115,32,97,32,66,73,70,32,105,109,112,108,101,109,101,110,116,101,100,32,105,110,32,67,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{1474,2},spec,{{erlang,is_builtin,3},[{type,{1474,24},bounded_fun,[{type,{1474,24},'fun',[{type,{1474,24},product,[{var,{1474,25},'Module'},{var,{1474,33},'Function'},{var,{1474,43},'Arity'}]},{type,{1474,53},boolean,[]}]},[{type,{1475,7},constraint,[{atom,{1475,7},is_subtype},[{var,{1475,7},'Module'},{type,{1475,17},module,[]}]]},{type,{1476,7},constraint,[{atom,{1476,7},is_subtype},[{var,{1476,7},'Function'},{type,{1476,19},atom,[]}]]},{type,{1477,7},constraint,[{atom,{1477,7},is_subtype},[{var,{1477,7},'Arity'},{type,{1477,16},arity,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,51,57,55>>}},{{function,is_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2459}],[<<105,115,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2459,2},spec,{{is_float,1},[{type,{2459,15},bounded_fun,[{type,{2459,15},'fun',[{type,{2459,15},product,[{var,{2459,16},'Term'}]},{type,{2459,25},boolean,[]}]},[{type,{2460,7},constraint,[{atom,{2460,7},is_subtype},[{var,{2460,7},'Term'},{type,{2460,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,48,56>>}},{{function,is_function,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2465}],[<<105,115,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,117,110,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2465,2},spec,{{is_function,1},[{type,{2465,18},bounded_fun,[{type,{2465,18},'fun',[{type,{2465,18},product,[{var,{2465,19},'Term'}]},{type,{2465,28},boolean,[]}]},[{type,{2466,7},constraint,[{atom,{2466,7},is_subtype},[{var,{2466,7},'Term'},{type,{2466,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,49,56>>}},{{function,is_function,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2471}],[<<105,115,95,102,117,110,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,102,117,110,32,116,104,97,116,32,99,97,110,32,98,101,32,97,112,112,108,105,101,100,32,119,105,116,104,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2471,2},spec,{{is_function,2},[{type,{2471,18},bounded_fun,[{type,{2471,18},'fun',[{type,{2471,18},product,[{var,{2471,19},'Term'},{var,{2471,25},'Arity'}]},{type,{2471,35},boolean,[]}]},[{type,{2472,7},constraint,[{atom,{2472,7},is_subtype},[{var,{2472,7},'Term'},{type,{2472,15},term,[]}]]},{type,{2473,7},constraint,[{atom,{2473,7},is_subtype},[{var,{2473,7},'Arity'},{type,{2473,16},arity,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,50,56>>}},{{function,is_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2478}],[<<105,115,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2478,2},spec,{{is_integer,1},[{type,{2478,17},bounded_fun,[{type,{2478,17},'fun',[{type,{2478,17},product,[{var,{2478,18},'Term'}]},{type,{2478,27},boolean,[]}]},[{type,{2479,7},constraint,[{atom,{2479,7},is_subtype},[{var,{2479,7},'Term'},{type,{2479,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,52,48>>}},{{function,is_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2484}],[<<105,115,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,108,105,115,116,32,119,105,116,104,32,122,101,114,111,32,111,114,32,109,111,114,101,32,101,108,101,109,101,110,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2484,2},spec,{{is_list,1},[{type,{2484,14},bounded_fun,[{type,{2484,14},'fun',[{type,{2484,14},product,[{var,{2484,15},'Term'}]},{type,{2484,24},boolean,[]}]},[{type,{2485,7},constraint,[{atom,{2485,7},is_subtype},[{var,{2485,7},'Term'},{type,{2485,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,53,48>>}},{{function,is_map,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2502}],[<<105,115,95,109,97,112,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,109,97,112,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2502,2},spec,{{is_map,1},[{type,{2502,13},bounded_fun,[{type,{2502,13},'fun',[{type,{2502,13},product,[{var,{2502,14},'Term'}]},{type,{2502,23},boolean,[]}]},[{type,{2503,7},constraint,[{atom,{2503,7},is_subtype},[{var,{2503,7},'Term'},{type,{2503,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,54,48>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,is_map_key,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1482}],[<<105,115,95,109,97,112,95,107,101,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,109,97,112,32>>,{code,[],[<<77,97,112>>]},<<32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<75,101,121>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,116,104,101,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,109,97,112,44,77,97,112,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,105,115,32,110,111,116,32,97,32,109,97,112,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<62,32,77,97,112,32,61,32,35,123,34,52,50,34,32,61,62,32,118,97,108,117,101,125,46,10,35,123,34,52,50,34,32,61,62,32,118,97,108,117,101,125,10,62,32,105,115,95,109,97,112,95,107,101,121,40,34,52,50,34,44,77,97,112,41,46,10,116,114,117,101,10,62,32,105,115,95,109,97,112,95,107,101,121,40,118,97,108,117,101,44,77,97,112,41,46,10,102,97,108,115,101>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1482,2},spec,{{is_map_key,2},[{type,{1482,17},bounded_fun,[{type,{1482,17},'fun',[{type,{1482,17},product,[{var,{1482,18},'Key'},{var,{1482,23},'Map'}]},{type,{1482,31},boolean,[]}]},[{type,{1483,5},constraint,[{atom,{1483,5},is_subtype},[{var,{1483,5},'Key'},{type,{1483,12},term,[]}]]},{type,{1484,5},constraint,[{atom,{1484,5},is_subtype},[{var,{1484,5},'Map'},{type,{1484,12},map,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,55,48>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,is_number,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2490}],[<<105,115,95,110,117,109,98,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,111,114,32,97,32,102,108,111,97,116,105,110,103,32,112,111,105,110,116,32,110,117,109,98,101,114,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2490,2},spec,{{is_number,1},[{type,{2490,16},bounded_fun,[{type,{2490,16},'fun',[{type,{2490,16},product,[{var,{2490,17},'Term'}]},{type,{2490,26},boolean,[]}]},[{type,{2491,7},constraint,[{atom,{2491,7},is_subtype},[{var,{2491,7},'Term'},{type,{2491,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,52,57,49>>}},{{function,is_pid,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2496}],[<<105,115,95,112,105,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2496,2},spec,{{is_pid,1},[{type,{2496,13},bounded_fun,[{type,{2496,13},'fun',[{type,{2496,13},product,[{var,{2496,14},'Term'}]},{type,{2496,23},boolean,[]}]},[{type,{2497,7},constraint,[{atom,{2497,7},is_subtype},[{var,{2497,7},'Term'},{type,{2497,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,48,49>>}},{{function,is_port,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2508}],[<<105,115,95,112,111,114,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2508,2},spec,{{is_port,1},[{type,{2508,14},bounded_fun,[{type,{2508,14},'fun',[{type,{2508,14},product,[{var,{2508,15},'Term'}]},{type,{2508,24},boolean,[]}]},[{type,{2509,7},constraint,[{atom,{2509,7},is_subtype},[{var,{2509,7},'Term'},{type,{2509,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,49,49>>}},{{function,is_process_alive,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1489}],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100>>]},<<32,109,117,115,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,115,116,115,32,97,110,100,32,105,115,32,97,108,105,118,101,44,32,116,104,97,116,32,105,115,44,32,105,115,32,110,111,116,32,101,120,105,116,105,110,103,32,97,110,100,32,104,97,115,32,110,111,116,32,101,120,105,116,101,100,46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<73,102,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,49>>]},<<32,99,97,108,108,115,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,40,80,50,80,105,100,41>>]},<<32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,108,108,32,115,105,103,110,97,108,115,44,32,115,101,110,116,32,102,114,111,109,32>>,{code,[],[<<80,49>>]},<<32,116,111,32>>,{code,[],[<<80,50>>]},<<32,40>>,{code,[],[<<80,50>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<80,50,80,105,100>>]},<<41,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,44,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32>>,{code,[],[<<80,50>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,97,108,105,118,101,110,101,115,115,32,111,102,32>>,{code,[],[<<80,50>>]},<<32,105,115,32,99,104,101,99,107,101,100,46,32,84,104,105,115,32,103,117,97,114,97,110,116,101,101,32,109,101,97,110,115,32,116,104,97,116,32,111,110,101,32,99,97,110,32,117,115,101,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>]},<<32,116,111,32,108,101,116,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,49>>]},<<32,119,97,105,116,32,117,110,116,105,108,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,50>>]},<<44,32,119,104,105,99,104,32,104,97,115,32,103,111,116,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,102,114,111,109,32,80,49,44,32,105,115,32,107,105,108,108,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<101,120,105,116,40,80,50,80,105,100,44,32,107,105,108,108,41,44,10,37,32,80,50,32,109,105,103,104,116,32,110,111,116,32,98,101,32,107,105,108,108,101,100,10,105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,40,80,50,80,105,100,41,44,10,37,32,80,50,32,105,115,32,110,111,116,32,97,108,105,118,101,32,40,116,104,101,32,99,97,108,108,32,97,98,111,118,101,32,97,108,119,97,121,115,32,114,101,116,117,114,110,32,102,97,108,115,101,41>>]}]},{p,[],[<<83,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,103,110,97,108,115>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,101,120,105,116,47,50>>]},<<32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,105,103,110,97,108,115,32,97,110,100,32,101,120,105,116,32,115,105,103,110,97,108,115,46>>]}]},#{signature => [{attribute,{1489,2},spec,{{is_process_alive,1},[{type,{1489,23},bounded_fun,[{type,{1489,23},'fun',[{type,{1489,23},product,[{var,{1489,24},'Pid'}]},{type,{1489,32},boolean,[]}]},[{type,{1490,7},constraint,[{atom,{1490,7},is_subtype},[{var,{1490,7},'Pid'},{type,{1490,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,50,49>>}},{{function,is_record,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2514}],[<<105,115,95,114,101,99,111,114,100,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,32,97,110,100,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,114,109,97,108,108,121,32,116,104,101,32,99,111,109,112,105,108,101,114,32,116,114,101,97,116,115,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,101,115,112,101,99,105,97,108,108,121,46,32,73,116,32,101,109,105,116,115,32,99,111,100,101,32,116,111,32,118,101,114,105,102,121,32,116,104,97,116,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,116,104,97,116,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,115,105,122,101,32,105,115,32,99,111,114,114,101,99,116,46,32,72,111,119,101,118,101,114,44,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,110,111,116,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,44,32,116,104,101,32,66,73,70,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,115,116,101,97,100,32,97,110,100,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,116,117,112,108,101,32,105,115,32,110,111,116,32,118,101,114,105,102,105,101,100,46>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,44,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{2514,2},spec,{{is_record,2},[{type,{2514,16},bounded_fun,[{type,{2514,16},'fun',[{type,{2514,16},product,[{var,{2514,17},'Term'},{var,{2514,22},'RecordTag'}]},{type,{2514,36},boolean,[]}]},[{type,{2515,7},constraint,[{atom,{2515,7},is_subtype},[{var,{2515,7},'Term'},{type,{2515,15},term,[]}]]},{type,{2516,7},constraint,[{atom,{2516,7},is_subtype},[{var,{2516,7},'RecordTag'},{type,{2516,20},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,53,51>>}},{{function,is_record,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2521}],[<<105,115,95,114,101,99,111,114,100,47,51>>],#{<<101,110>> => [{p,[],[{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,109,117,115,116,32,98,101,32,97,110,32,97,116,111,109,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<44,32,97,110,100,32,105,116,115,32,115,105,122,101,32,105,115,32>>,{code,[],[<<83,105,122,101>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,32,105,102,32>>,{code,[],[<<82,101,99,111,114,100,84,97,103>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,97,116,111,109,32,97,110,100,32>>,{code,[],[<<83,105,122,101>>]},<<32,105,115,32,97,32,108,105,116,101,114,97,108,32,105,110,116,101,103,101,114,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,100,111,99,117,109,101,110,116,101,100,32,102,111,114,32,99,111,109,112,108,101,116,101,110,101,115,115,46,32,85,115,117,97,108,108,121,32>>,{code,[],[<<105,115,95,114,101,99,111,114,100,47,50>>]},<<32,105,115,32,116,111,32,98,101,32,117,115,101,100,46>>]}]}]},#{signature => [{attribute,{2521,2},spec,{{is_record,3},[{type,{2521,16},bounded_fun,[{type,{2521,16},'fun',[{type,{2521,16},product,[{var,{2521,17},'Term'},{var,{2521,22},'RecordTag'},{var,{2521,32},'Size'}]},{type,{2521,41},boolean,[]}]},[{type,{2522,7},constraint,[{atom,{2522,7},is_subtype},[{var,{2522,7},'Term'},{type,{2522,15},term,[]}]]},{type,{2523,7},constraint,[{atom,{2523,7},is_subtype},[{var,{2523,7},'RecordTag'},{type,{2523,20},atom,[]}]]},{type,{2524,7},constraint,[{atom,{2524,7},is_subtype},[{var,{2524,7},'Size'},{type,{2524,15},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,55,52>>}},{{function,is_reference,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2529}],[<<105,115,95,114,101,102,101,114,101,110,99,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2529,2},spec,{{is_reference,1},[{type,{2529,19},bounded_fun,[{type,{2529,19},'fun',[{type,{2529,19},product,[{var,{2529,20},'Term'}]},{type,{2529,29},boolean,[]}]},[{type,{2530,7},constraint,[{atom,{2530,7},is_subtype},[{var,{2530,7},'Term'},{type,{2530,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,53,57,51>>}},{{function,is_tuple,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2535}],[<<105,115,95,116,117,112,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32,116,117,112,108,101,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2535,2},spec,{{is_tuple,1},[{type,{2535,15},bounded_fun,[{type,{2535,15},'fun',[{type,{2535,15},product,[{var,{2535,16},'Term'}]},{type,{2535,25},boolean,[]}]},[{type,{2536,7},constraint,[{atom,{2536,7},is_subtype},[{var,{2536,7},'Term'},{type,{2536,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,48,51>>}},{{function,length,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1496}],[<<108,101,110,103,116,104,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,101,110,103,116,104,40,91,49,44,50,44,51,44,52,44,53,44,54,44,55,44,56,44,57,93,41,46,10,57>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1496,2},spec,{{length,1},[{type,{1496,13},bounded_fun,[{type,{1496,13},'fun',[{type,{1496,13},product,[{var,{1496,14},'List'}]},{type,{1496,23},non_neg_integer,[]}]},[{type,{1497,7},constraint,[{atom,{1497,7},is_subtype},[{var,{1497,7},'List'},{type,{1497,15},list,[{type,{1497,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,49,51>>}},{{function,link,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1502}],[<<108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,117,112,32,97,110,100,32,97,99,116,105,118,97,116,101,115,32,97,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<46,32,87,101,32,119,105,108,108,32,102,114,111,109,32,104,101,114,101,32,111,110,32,99,97,108,108,32,116,104,101,32,105,100,101,110,116,105,102,105,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,108,105,110,107,101,101,46,32,73,102,32,116,104,101,32,108,105,110,107,101,101,32,105,115,32,97,32,112,111,114,116,44,32,105,116,32,109,117,115,116,32,114,101,115,105,100,101,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,101,114,46>>]},{p,[],[<<73,102,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,116,105,99,105,112,97,110,116,115,32,111,102,32,97,32,108,105,110,107,32,116,101,114,109,105,110,97,116,101,115,44,32,105,116,32,119,105,108,108,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,101,110,100,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,101,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108>>]},<<32,116,111,32,116,104,101,32,111,116,104,101,114,32,112,97,114,116,105,99,105,112,97,110,116,46,32,84,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,108,108,32,99,111,110,116,97,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,108,105,110,107,95,101,120,105,116,95,115,105,103,110,97,108,95,114,101,97,115,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,120,105,116,32,114,101,97,115,111,110>>]},<<32,111,102,32,116,104,101,32,116,101,114,109,105,110,97,116,101,100,32,112,97,114,116,105,99,105,112,97,110,116,46,32,79,116,104,101,114,32,99,97,115,101,115,32,119,104,101,110,32,101,120,105,116,32,115,105,103,110,97,108,115,32,97,114,101,32,116,114,105,103,103,101,114,101,100,32,100,117,101,32,116,111,32,97,32,108,105,110,107,32,97,114,101,32,119,104,101,110,32,110,111,32,108,105,110,107,101,101,32,101,120,105,115,116,32,40>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,101,120,105,116,32,114,101,97,115,111,110,41,32,97,110,100,32,119,104,101,110,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,32,111,110,32,100,105,102,102,101,114,101,110,116,32,110,111,100,101,115,32,105,115,32,108,111,115,116,32,111,114,32,99,97,110,110,111,116,32,98,101,32,101,115,116,97,98,108,105,115,104,101,100,32,40>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,101,120,105,116,32,114,101,97,115,111,110,41,46>>]},{p,[],[<<65,110,32,101,120,105,115,116,105,110,103,32,108,105,110,107,32,99,97,110,32,98,101,32,114,101,109,111,118,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,108,105,110,107,47,49>>]}]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,108,105,110,107,115,32,97,110,100,32,101,120,105,116,32,115,105,103,110,97,108,115,32,100,117,101,32,116,111,32,108,105,110,107,115,44,32,115,101,101,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,105,110,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<58>>]},{ul,[],[{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,108,105,110,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<76,105,110,107,115>>]}]},{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,101,110,100,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,101,110,100,105,110,103,32,69,120,105,116,32,83,105,103,110,97,108,115>>]}]},{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,114,101,99,101,105,118,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,99,101,105,118,105,110,103,32,69,120,105,116,32,83,105,103,110,97,108,115>>]}]}]},{p,[],[<<70,111,114,32,104,105,115,116,111,114,105,99,97,108,32,114,101,97,115,111,110,115,44,32>>,{code,[],[<<108,105,110,107,47,49>>]},<<32,104,97,115,32,97,32,115,116,114,97,110,103,101,32,115,101,109,105,45,115,121,110,99,104,114,111,110,111,117,115,32,98,101,104,97,118,105,111,114,32,119,104,101,110,32,105,116,32,105,115,32,34,99,104,101,97,112,34,32,116,111,32,99,104,101,99,107,32,105,102,32,116,104,101,32,108,105,110,107,101,101,32,101,120,105,115,116,115,32,111,114,32,110,111,116,44,32,97,110,100,32,116,104,101,32,99,97,108,108,101,114,32,100,111,101,115,32,110,111,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,116,114,97,112,95,101,120,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,114,97,112,32,101,120,105,116,115>>]},<<46,32,73,102,32,116,104,101,32,97,98,111,118,101,32,105,115,32,116,114,117,101,32,97,110,100,32,116,104,101,32,108,105,110,107,101,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32>>,{code,[],[<<108,105,110,107,47,49>>]},<<32,119,105,108,108,32,114,97,105,115,101,32,97,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,101,114,114,111,114,32>>,{em,[],[<<101,120,99,101,112,116,105,111,110>>]},<<46,32,84,104,101,32,101,120,112,101,99,116,101,100,32,98,101,104,97,118,105,111,114,32,119,111,117,108,100,32,105,110,115,116,101,97,100,32,104,97,118,101,32,98,101,101,110,32,116,104,97,116,32>>,{code,[],[<<108,105,110,107,47,49>>]},<<32,114,101,116,117,114,110,101,100,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,97,110,100,32,116,104,101,32,99,97,108,108,101,114,32,108,97,116,101,114,32,119,97,115,32,115,101,110,116,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,101,120,105,116,32,114,101,97,115,111,110,44,32,98,117,116,32,116,104,105,115,32,105,115,32,117,110,102,111,114,116,117,110,97,116,101,108,121,32,110,111,116,32,116,104,101,32,99,97,115,101,46,32,84,104,101,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115,35,101,120,99,101,112,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,120,99,101,112,116,105,111,110>>]},<<32,105,115,32,110,111,116,32,116,111,32,98,101,32,99,111,110,102,117,115,101,100,32,119,105,116,104,32,97,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,101,110,100,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,120,105,116,32,115,105,103,110,97,108>>]},<<32,119,105,116,104,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<46,32,67,117,114,114,101,110,116,108,121,32,105,116,32,105,115,32,34,99,104,101,97,112,34,32,116,111,32,99,104,101,99,107,32,105,102,32,116,104,101,32,108,105,110,107,101,101,32,101,120,105,115,116,115,32,119,104,101,110,32,105,116,32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,114,101,115,105,100,101,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<84,104,101,32,108,105,110,107,32,115,101,116,117,112,32,97,110,100,32,97,99,116,105,118,97,116,105,111,110,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,73,102,32,116,104,101,32,108,105,110,107,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,44,32,111,114,32,105,102,32,116,104,101,32,99,97,108,108,101,114,32,97,116,116,101,109,112,116,115,32,116,111,32,99,114,101,97,116,101,32,97,32,108,105,110,107,32,116,111,32,105,116,115,101,108,102,44,32,110,111,116,104,105,110,103,32,105,115,32,100,111,110,101,46,32,65,32,100,101,116,97,105,108,101,100,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,105,115,116,95,112,114,111,116,111,99,111,108,35,108,105,110,107,95,112,114,111,116,111,99,111,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,110,107,32,112,114,111,116,111,99,111,108>>]},<<32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{i,[],[<<68,105,115,116,114,105,98,117,116,105,111,110,32,80,114,111,116,111,99,111,108>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58>>]},{ul,[],[{li,[],[{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,105,100,101,110,116,105,102,121,32,97,32,112,114,111,99,101,115,115,32,111,114,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,111,114,116,46>>]},{li,[],[{code,[],[<<110,111,112,114,111,99>>]},<<32,108,105,110,107,101,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,97,110,100,32,105,116,32,105,115,32,34,99,104,101,97,112,34,32,116,111,32,99,104,101,99,107,32,105,102,32,105,116,32,101,120,105,115,116,115,32,97,115,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,46>>]}]}]},#{signature => [{attribute,{1502,2},spec,{{link,1},[{type,{1502,11},bounded_fun,[{type,{1502,11},'fun',[{type,{1502,11},product,[{var,{1502,12},'PidOrPort'}]},{atom,{1502,26},true}]},[{type,{1503,7},constraint,[{atom,{1503,7},is_subtype},[{var,{1503,7},'PidOrPort'},{type,{1503,20},union,[{type,{1503,20},pid,[]},{type,{1503,28},port,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,54,50,53>>}},{{function,list_to_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1508}],[<<108,105,115,116,95,116,111,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,48,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,97,121,32,99,111,110,116,97,105,110,32,97,110,121,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,46,32,69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,97,108,108,111,119,101,100,32,111,110,108,121,32,73,83,79,45,108,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,116,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,100,105,100,32,110,111,116,32,97,108,108,111,119,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,97,98,111,118,101,32,50,53,53,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,97,110,32,97,116,111,109,32,110,97,109,101,32,105,115,32,108,105,109,105,116,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,99,111,110,102,105,103,117,114,97,98,108,101,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,32,101,120,105,115,116,32,97,110,100,32,97,116,111,109,115,32,97,114,101,32,110,111,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,110,115,105,100,101,114,32,105,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>]}]},<<32,105,115,32,97,32,98,101,116,116,101,114,32,111,112,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<108,105,115,116,95,116,111,95,97,116,111,109,47,49>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,108,105,109,105,116,115,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,102,102,105,99,105,101,110,99,121,32,103,117,105,100,101,32,40,115,101,99,116,105,111,110,32,65,100,118,97,110,99,101,100,41>>]},<<46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,97,116,111,109,40,34,69,114,108,97,110,103,34,41,46,10,39,69,114,108,97,110,103,39>>]}]}]},#{signature => [{attribute,{1508,2},spec,{{list_to_atom,1},[{type,{1508,19},bounded_fun,[{type,{1508,19},'fun',[{type,{1508,19},product,[{var,{1508,20},'String'}]},{type,{1508,31},atom,[]}]},[{type,{1509,7},constraint,[{atom,{1509,7},is_subtype},[{var,{1509,7},'String'},{type,{1509,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,55,49,53>>}},{{function,list_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1514}],[<<108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,32,105,110,32>>,{code,[],[<<73,111,76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,62,62,46,10,60,60,54,62,62,10,62,32,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,62,62>>]}]}]},#{signature => [{attribute,{1514,2},spec,{{list_to_binary,1},[{type,{1514,21},bounded_fun,[{type,{1514,21},'fun',[{type,{1514,21},product,[{var,{1514,22},'IoList'}]},{type,{1514,33},binary,[]}]},[{type,{1515,7},constraint,[{atom,{1515,7},is_subtype},[{var,{1515,7},'IoList'},{type,{1515,17},iolist,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,55,52,56>>}},{{function,list_to_bitstring,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1520}],[<<108,105,115,116,95,116,111,95,98,105,116,115,116,114,105,110,103,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<98,105,116,115,116,114,105,110,103,95,108,105,115,116>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,116,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,116,115,116,114,105,110,103,115,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103,76,105,115,116>>]},<<46,32,40,84,104,101,32,108,97,115,116,32,116,97,105,108,32,105,110,32>>,{code,[],[<<66,105,116,115,116,114,105,110,103,76,105,115,116>>]},<<32,105,115,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,32,98,105,116,115,116,114,105,110,103,46,41,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,105,110,49,32,61,32,60,60,49,44,50,44,51,62,62,46,10,60,60,49,44,50,44,51,62,62,10,62,32,66,105,110,50,32,61,32,60,60,52,44,53,62,62,46,10,60,60,52,44,53,62,62,10,62,32,66,105,110,51,32,61,32,60,60,54,44,55,58,52,62,62,46,10,60,60,54,44,55,58,52,62,62,10,62,32,108,105,115,116,95,116,111,95,98,105,116,115,116,114,105,110,103,40,91,66,105,110,49,44,49,44,91,50,44,51,44,66,105,110,50,93,44,52,124,66,105,110,51,93,41,46,10,60,60,49,44,50,44,51,44,49,44,50,44,51,44,52,44,53,44,52,44,54,44,55,58,52,62,62>>]}]}]},#{signature => [{attribute,{1520,2},spec,{{list_to_bitstring,1},[{type,{1520,24},bounded_fun,[{type,{1520,24},'fun',[{type,{1520,24},product,[{var,{1520,25},'BitstringList'}]},{type,{1520,43},bitstring,[]}]},[{type,{1521,7},constraint,[{atom,{1521,7},is_subtype},[{var,{1521,7},'BitstringList'},{user_type,{1521,24},bitstring_list,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,55,54,54>>}},{{function,list_to_existing_atom,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1526}],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,98,117,116,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,32,115,117,99,104,32,97,116,111,109,46,32,65,110,32,97,116,111,109,32,101,120,105,115,116,115,32,105,102,32,105,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,32,98,121,32,116,104,101,32,114,117,110,45,116,105,109,101,32,115,121,115,116,101,109,32,98,121,32,101,105,116,104,101,114,32,108,111,97,100,105,110,103,32,99,111,100,101,32,111,114,32,99,114,101,97,116,105,110,103,32,97,32,116,101,114,109,32,105,110,32,119,104,105,99,104,32,116,104,101,32,97,116,111,109,32,105,115,32,112,97,114,116,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,100,111,101,115,32,110,111,116,32,97,108,114,101,97,100,121,32,101,120,105,115,116,32,97,110,32,97,116,111,109,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,99,111,109,112,105,108,101,114,32,109,97,121,32,111,112,116,105,109,105,122,101,32,97,119,97,121,32,97,116,111,109,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,111,109,112,105,108,101,114,32,119,105,108,108,32,114,101,119,114,105,116,101,32>>,{code,[],[<<97,116,111,109,95,116,111,95,108,105,115,116,40,115,111,109,101,95,97,116,111,109,41>>]},<<32,116,111,32>>,{code,[],[<<34,115,111,109,101,95,97,116,111,109,34>>]},<<46,32,73,102,32,116,104,97,116,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,110,116,105,111,110,32,111,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,111,109,101,95,97,116,111,109>>]},<<32,105,110,32,116,104,101,32,99,111,110,116,97,105,110,105,110,103,32,109,111,100,117,108,101,44,32,116,104,101,32,97,116,111,109,32,119,105,108,108,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,108,111,97,100,101,100,44,32,97,110,100,32,97,32,115,117,98,115,101,113,117,101,110,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,105,115,116,95,116,111,95,101,120,105,115,116,105,110,103,95,97,116,111,109,40,34,115,111,109,101,95,97,116,111,109,34,41>>]},<<32,119,105,108,108,32,102,97,105,108,46>>]}]}]},#{signature => [{attribute,{1526,2},spec,{{list_to_existing_atom,1},[{type,{1526,28},bounded_fun,[{type,{1526,28},'fun',[{type,{1526,28},product,[{var,{1526,29},'String'}]},{type,{1526,40},atom,[]}]},[{type,{1527,7},constraint,[{atom,{1527,7},is_subtype},[{var,{1527,7},'String'},{type,{1527,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,55,56,55>>}},{{function,list_to_float,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1532}],[<<108,105,115,116,95,116,111,95,102,108,111,97,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,102,108,111,97,116,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,102,108,111,97,116,40,34,50,46,50,48,49,55,55,54,52,101,43,48,34,41,46,10,50,46,50,48,49,55,55,54,52>>]}]},{p,[],[<<84,104,101,32,102,108,111,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,102,111,114,109,97,116,32,102,111,114,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,102,108,111,97,116,32,108,105,116,101,114,97,108,115>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,97,116,32,117,110,100,101,114,115,99,111,114,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,102,108,111,97,116,46>>]}]},#{signature => [{attribute,{1532,2},spec,{{list_to_float,1},[{type,{1532,20},bounded_fun,[{type,{1532,20},'fun',[{type,{1532,20},product,[{var,{1532,21},'String'}]},{type,{1532,32},float,[]}]},[{type,{1533,7},constraint,[{atom,{1533,7},is_subtype},[{var,{1533,7},'String'},{type,{1533,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,49,48>>}},{{function,list_to_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1538}],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,49,50,51,34,41,46,10,49,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,45,49,50,51,34,41,46,10,45,49,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,43,49,50,51,50,51,52,57,56,50,51,48,52,57,56,50,51,48,57,52,56,50,48,57,51,56,51,51,50,51,52,50,51,52,34,41,46,10,49,50,51,50,51,52,57,56,50,51,48,52,57,56,50,51,48,57,52,56,50,48,57,51,56,51,51,50,51,52,50,51,52>>]}]},{p,[],[{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,99,111,110,116,97,105,110,32,97,116,32,108,101,97,115,116,32,111,110,101,32,100,105,103,105,116,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32,99,97,110,32,104,97,118,101,32,97,110,32,111,112,116,105,111,110,97,108,32,112,114,101,102,105,120,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32,97,32,115,105,110,103,108,101,32,34>>,{code,[],[<<43>>]},<<34,32,111,114,32,34>>,{code,[],[<<45>>]},<<34,32,99,104,97,114,97,99,116,101,114,32,40,116,104,97,116,32,105,115,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<34,94,91,43,45,93,63,91,48,45,57,93,43,36,34>>]},<<41,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{1538,2},spec,{{list_to_integer,1},[{type,{1538,22},bounded_fun,[{type,{1538,22},'fun',[{type,{1538,22},product,[{var,{1538,23},'String'}]},{type,{1538,34},integer,[]}]},[{type,{1539,7},constraint,[{atom,{1539,7},is_subtype},[{var,{1539,7},'String'},{type,{1539,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,50,56>>}},{{function,list_to_integer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1563}],[<<108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,110,32,98,97,115,101,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,70,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,43,51,70,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,102,102,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,51,102,70,34,44,32,49,54,41,46,10,49,48,50,51>>]}]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,105,110,116,101,103,101,114,40,34,45,51,70,70,34,44,32,49,54,41,46,10,45,49,48,50,51>>]}]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32>>,{code,[],[<<66,97,115,101>>]},<<32,105,115,32,49,54,44,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<34,94,91,43,45,93,63,40,91,48,45,57,93,124,91,65,45,70,93,124,91,97,45,102,93,41,43,36,34>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{1563,2},spec,{{list_to_integer,2},[{type,{1563,22},bounded_fun,[{type,{1563,22},'fun',[{type,{1563,22},product,[{var,{1563,23},'String'},{var,{1563,31},'Base'}]},{type,{1563,40},integer,[]}]},[{type,{1564,7},constraint,[{atom,{1564,7},is_subtype},[{var,{1564,7},'String'},{type,{1564,17},string,[]}]]},{type,{1565,7},constraint,[{atom,{1565,7},is_subtype},[{var,{1565,7},'Base'},{type,{1565,15},range,[{integer,{1565,15},2},{integer,{1565,18},36}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,53,51>>}},{{function,list_to_pid,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1588}],[<<108,105,115,116,95,116,111,95,112,105,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,112,105,100,40,34,60,48,46,52,46,49,62,34,41,46,10,60,48,46,52,46,49,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{signature => [{attribute,{1588,2},spec,{{list_to_pid,1},[{type,{1588,18},bounded_fun,[{type,{1588,18},'fun',[{type,{1588,18},product,[{var,{1588,19},'String'}]},{type,{1588,30},pid,[]}]},[{type,{1589,7},constraint,[{atom,{1589,7},is_subtype},[{var,{1589,7},'String'},{type,{1589,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,56,56,51>>}},{{function,list_to_port,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1594}],[<<108,105,115,116,95,116,111,95,112,111,114,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,112,111,114,116,40,34,35,80,111,114,116,60,48,46,52,62,34,41,46,10,35,80,111,114,116,60,48,46,52,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{signature => [{attribute,{1594,2},spec,{{list_to_port,1},[{type,{1594,19},bounded_fun,[{type,{1594,19},'fun',[{type,{1594,19},product,[{var,{1594,20},'String'}]},{type,{1594,31},port,[]}]},[{type,{1595,7},constraint,[{atom,{1595,7},is_subtype},[{var,{1595,7},'String'},{type,{1595,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,57,48,49>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,list_to_ref,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1600}],[<<108,105,115,116,95,116,111,95,114,101,102,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,114,101,102,101,114,101,110,99,101,32,119,104,111,115,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,114,101,102,40,34,35,82,101,102,60,48,46,52,49,57,50,53,51,55,54,55,56,46,52,48,55,51,49,57,51,52,55,53,46,55,49,49,56,49,62,34,41,46,10,35,82,101,102,60,48,46,52,49,57,50,53,51,55,54,55,56,46,52,48,55,51,49,57,51,52,55,53,46,55,49,49,56,49,62>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<83,116,114,105,110,103>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,98,97,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32,114,101,102,101,114,101,110,99,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{signature => [{attribute,{1600,2},spec,{{list_to_ref,1},[{type,{1600,18},bounded_fun,[{type,{1600,18},'fun',[{type,{1600,18},product,[{var,{1600,19},'String'}]},{type,{1600,30},reference,[]}]},[{type,{1601,7},constraint,[{atom,{1601,7},is_subtype},[{var,{1601,7},'String'},{type,{1601,17},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,57,49,57>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,list_to_tuple,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1606}],[<<108,105,115,116,95,116,111,95,116,117,112,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101>>]},{pre,[],[{code,[],[<<62,32,108,105,115,116,95,116,111,95,116,117,112,108,101,40,91,115,104,97,114,101,44,32,91,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,93,93,41,46,10,123,115,104,97,114,101,44,32,91,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,93,125>>]}]},{p,[],[{code,[],[<<76,105,115,116>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,115,46>>]}]},#{signature => [{attribute,{1606,2},spec,{{list_to_tuple,1},[{type,{1606,20},bounded_fun,[{type,{1606,20},'fun',[{type,{1606,20},product,[{var,{1606,21},'List'}]},{type,{1606,30},tuple,any}]},[{type,{1607,7},constraint,[{atom,{1607,7},is_subtype},[{var,{1607,7},'List'},{type,{1607,15},list,[{type,{1607,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,57,51,55>>}},{{function,load_module,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2540}],[<<108,111,97,100,95,109,111,100,117,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<44,32,116,104,105,115,32,66,73,70,32,108,111,97,100,115,32,116,104,97,116,32,111,98,106,101,99,116,32,99,111,100,101,46,32,73,102,32,116,104,101,32,99,111,100,101,32,102,111,114,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,44,32,97,108,108,32,101,120,112,111,114,116,32,114,101,102,101,114,101,110,99,101,115,32,97,114,101,32,114,101,112,108,97,99,101,100,32,115,111,32,116,104,101,121,32,112,111,105,110,116,32,116,111,32,116,104,101,32,110,101,119,108,121,32,108,111,97,100,101,100,32,99,111,100,101,46,32,84,104,101,32,112,114,101,118,105,111,117,115,108,121,32,108,111,97,100,101,100,32,99,111,100,101,32,105,115,32,107,101,112,116,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,97,115,32,111,108,100,32,99,111,100,101,44,32,97,115,32,116,104,101,114,101,32,99,97,110,32,115,116,105,108,108,32,98,101,32,112,114,111,99,101,115,115,101,115,32,101,120,101,99,117,116,105,110,103,32,116,104,97,116,32,99,111,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,101,105,116,104,101,114,32>>,{code,[],[<<123,109,111,100,117,108,101,44,32,77,111,100,117,108,101,125>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,102,32,108,111,97,100,105,110,103,32,102,97,105,108,115,46,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,102,105,108,101>>]}]},{dd,[],[<<84,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,104,97,115,32,97,110,32,105,110,99,111,114,114,101,99,116,32,102,111,114,109,97,116,32>>,{em,[],[<<111,114>>]},<<32,116,104,101,32,111,98,106,101,99,116,32,99,111,100,101,32,99,111,110,116,97,105,110,115,32,99,111,100,101,32,102,111,114,32,97,110,111,116,104,101,114,32,109,111,100,117,108,101,32,116,104,97,110,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,116,95,112,117,114,103,101,100>>]}]},{dd,[],[{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,32,109,111,100,117,108,101,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,108,111,97,100,101,100,32,98,101,99,97,117,115,101,32,111,108,100,32,99,111,100,101,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]},{dt,[],[{code,[],[<<111,110,95,108,111,97,100>>]}]},{dd,[],[<<84,104,101,32,99,111,100,101,32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,111,110,116,97,105,110,115,32,97,110,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,100,101,99,108,97,114,97,116,105,111,110,32,116,104,97,116,32,109,117,115,116,32,98,101,32,101,120,101,99,117,116,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,99,97,110,32,98,101,99,111,109,101,32,116,104,101,32,99,117,114,114,101,110,116,32,99,111,100,101,46,32,65,110,121,32,112,114,101,118,105,111,117,115,32,99,117,114,114,101,110,116,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,119,105,108,108,32,114,101,109,97,105,110,32,117,110,116,105,108,32,116,104,101,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,99,97,108,108,32,104,97,115,32,102,105,110,105,115,104,101,100,46>>]},{dt,[],[<<110,111,116,95,97,108,108,111,119,101,100>>]},{dd,[],[<<84,104,101,32,99,111,100,101,32,105,110,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,104,97,115,32,98,101,101,110,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,102,101,97,116,117,114,101,115,32,116,104,97,116,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,110,111,116,32,101,110,97,98,108,101,100,32,105,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]}]},#{signature => [{attribute,{2540,2},spec,{{load_module,2},[{type,{2540,18},bounded_fun,[{type,{2540,18},'fun',[{type,{2540,18},product,[{var,{2540,19},'Module'},{var,{2540,27},'Binary'}]},{type,{2540,38},union,[{type,{2540,38},tuple,[{atom,{2540,39},module},{var,{2540,47},'Module'}]},{type,{2540,57},tuple,[{atom,{2540,58},error},{var,{2540,65},'Reason'}]}]}]},[{type,{2541,7},constraint,[{atom,{2541,7},is_subtype},[{var,{2541,7},'Module'},{type,{2541,17},module,[]}]]},{type,{2542,7},constraint,[{atom,{2542,7},is_subtype},[{var,{2542,7},'Binary'},{type,{2542,17},binary,[]}]]},{type,{2543,7},constraint,[{atom,{2543,7},is_subtype},[{var,{2543,7},'Reason'},{type,{2543,17},union,[{atom,{2543,17},badfile},{atom,{2543,27},not_purged},{atom,{2543,40},on_load},{type,{2544,17},tuple,[{atom,{2544,18},features_not_allowed},{type,{2544,40},list,[{type,{2544,41},atom,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,57,53,48>>}},{{function,load_nif,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2562}],[<<108,111,97,100,95,110,105,102,47,50>>],#{<<101,110>> => [{p,[],[<<76,111,97,100,115,32,97,110,100,32,108,105,110,107,115,32,97,32,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,110,97,116,105,118,101,32,105,109,112,108,101,109,101,110,116,101,100,32,102,117,110,99,116,105,111,110,115,32,40,78,73,70,115,41,32,102,111,114,32,97,32,109,111,100,117,108,101,46,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,97,32,102,105,108,101,32,112,97,116,104,32,116,111,32,116,104,101,32,115,104,97,114,101,97,98,108,101,32,111,98,106,101,99,116,47,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,32,102,105,108,101,32,109,105,110,117,115,32,116,104,101,32,79,83,45,100,101,112,101,110,100,101,110,116,32,102,105,108,101,32,101,120,116,101,110,115,105,111,110,32,40>>,{code,[],[<<46,115,111>>]},<<32,102,111,114,32,85,110,105,120,32,97,110,100,32>>,{code,[],[<<46,100,108,108>>]},<<32,102,111,114,32,87,105,110,100,111,119,115,41,46,32,78,111,116,105,99,101,32,116,104,97,116,32,111,110,32,109,111,115,116,32,79,83,115,32,116,104,101,32,108,105,98,114,97,114,121,32,104,97,115,32,116,111,32,104,97,118,101,32,97,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,32,111,110,32,100,105,115,99,32,119,104,101,110,32,97,110,32,117,112,103,114,97,100,101,32,111,102,32,116,104,101,32,110,105,102,32,105,115,32,100,111,110,101,46,32,73,102,32,116,104,101,32,110,97,109,101,32,105,115,32,116,104,101,32,115,97,109,101,44,32,98,117,116,32,116,104,101,32,99,111,110,116,101,110,116,115,32,100,105,102,102,101,114,44,32,116,104,101,32,111,108,100,32,108,105,98,114,97,114,121,32,109,97,121,32,98,101,32,108,111,97,100,101,100,32,105,110,115,116,101,97,100,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,105,109,112,108,101,109,101,110,116,32,97,32,78,73,70,32,108,105,98,114,97,114,121,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,110,105,102,40,51,41>>]}]},<<46>>]},{p,[],[{code,[],[<<76,111,97,100,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,46,32,73,116,32,105,115,32,112,97,115,115,101,100,32,111,110,32,116,111,32,116,104,101,32,108,105,98,114,97,114,121,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,105,110,105,116,105,97,108,105,122,97,116,105,111,110,46,32,65,32,103,111,111,100,32,112,114,97,99,116,105,99,101,32,105,115,32,116,111,32,105,110,99,108,117,100,101,32,97,32,109,111,100,117,108,101,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,116,111,32,115,117,112,112,111,114,116,32,102,117,116,117,114,101,32,99,111,100,101,32,117,112,103,114,97,100,101,32,115,99,101,110,97,114,105,111,115,46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,111,97,100,95,110,105,102,47,50>>]},<<32,109,117,115,116,32,98,101,32,109,97,100,101,32>>,{em,[],[<<100,105,114,101,99,116,108,121>>]},<<32,102,114,111,109,32,116,104,101,32,69,114,108,97,110,103,32,99,111,100,101,32,111,102,32,116,104,101,32,109,111,100,117,108,101,32,116,104,97,116,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,98,101,108,111,110,103,115,32,116,111,46,32,73,116,32,114,101,116,117,114,110,115,32,101,105,116,104,101,114,32>>,{code,[],[<<111,107>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,123,82,101,97,115,111,110,44,84,101,120,116,125,125>>]},<<32,105,102,32,108,111,97,100,105,110,103,32,102,97,105,108,115,46,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,32,119,104,105,108,101,32>>,{code,[],[<<84,101,120,116>>]},<<32,105,115,32,97,32,104,117,109,97,110,32,114,101,97,100,97,98,108,101,32,115,116,114,105,110,103,32,116,104,97,116,32,99,97,110,32,103,105,118,101,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,97,105,108,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,97,100,95,102,97,105,108,101,100>>]}]},{dd,[],[<<84,104,101,32,79,83,32,102,97,105,108,101,100,32,116,111,32,108,111,97,100,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,46>>]},{dt,[],[{code,[],[<<98,97,100,95,108,105,98>>]}]},{dd,[],[<<84,104,101,32,108,105,98,114,97,114,121,32,100,105,100,32,110,111,116,32,102,117,108,102,105,108,108,32,116,104,101,32,114,101,113,117,105,114,101,109,101,110,116,115,32,97,115,32,97,32,78,73,70,32,108,105,98,114,97,114,121,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,109,111,100,117,108,101,46>>]},{dt,[],[{code,[],[<<108,111,97,100,32,124,32,117,112,103,114,97,100,101>>]}]},{dd,[],[<<84,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,98,114,97,114,121,32,99,97,108,108,98,97,99,107,32,119,97,115,32,117,110,115,117,99,99,101,115,115,102,117,108,46>>]},{dt,[],[{code,[],[<<114,101,108,111,97,100>>]}]},{dd,[],[<<65,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,97,108,114,101,97,100,121,32,108,111,97,100,101,100,32,102,111,114,32,116,104,105,115,32,109,111,100,117,108,101,32,105,110,115,116,97,110,99,101,46,32,84,104,101,32,112,114,101,118,105,111,117,115,108,121,32,100,101,112,114,101,99,97,116,101,100,32>>,{code,[],[<<114,101,108,111,97,100>>]},<<32,102,101,97,116,117,114,101,32,119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,79,84,80,32,50,48,46>>]},{dt,[],[{code,[],[<<111,108,100,95,99,111,100,101>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<108,111,97,100,95,110,105,102,47,50>>]},<<32,119,97,115,32,109,97,100,101,32,102,114,111,109,32,116,104,101,32,111,108,100,32,99,111,100,101,32,111,102,32,97,32,109,111,100,117,108,101,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,117,112,103,114,97,100,101,100,59,32,116,104,105,115,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,46>>]}]},{p,[],[<<73,102,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,109,111,100,117,108,101,115,35,110,105,102,115,95,97,116,116,114,105,98,117,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<45,110,105,102,115,40,41>>]}]},<<32,97,116,116,114,105,98,117,116,101,32,105,115,32,117,115,101,100,32,40,119,104,105,99,104,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,41,44,32,97,108,108,32,78,73,70,115,32,105,110,32,116,104,101,32,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,32,109,117,99,104,32,98,101,32,100,101,99,108,97,114,101,100,32,97,115,32,115,117,99,104,32,102,111,114,32>>,{code,[],[<<108,111,97,100,95,110,105,102,47,50>>]},<<32,116,111,32,115,117,99,99,101,101,100,46,32,79,110,32,116,104,101,32,111,116,104,101,114,32,104,97,110,100,44,32,97,108,108,32,102,117,110,99,116,105,111,110,115,32,100,101,99,108,97,114,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<45,110,105,102,115,40,41>>]},<<32,97,116,116,114,105,98,117,116,101,32,100,111,32,110,111,116,32,104,97,118,101,32,116,111,32,98,101,32,105,109,112,108,101,109,101,110,116,101,100,32,98,121,32,116,104,101,32,100,121,110,97,109,105,99,32,108,105,98,114,97,114,121,46,32,84,104,105,115,32,97,108,108,111,119,115,32,97,32,116,97,114,103,101,116,32,105,110,100,101,112,101,110,100,101,110,116,32,69,114,108,97,110,103,32,102,105,108,101,32,116,111,32,99,111,110,116,97,105,110,32,102,97,108,108,98,97,99,107,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,32,102,111,114,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,109,97,121,32,108,97,99,107,32,78,73,70,32,115,117,112,112,111,114,116,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,97,114,103,101,116,32,79,83,47,104,97,114,100,119,97,114,101,32,112,108,97,116,102,111,114,109,46>>]}]},#{signature => [{attribute,{2562,2},spec,{{erlang,load_nif,2},[{type,{2562,22},bounded_fun,[{type,{2562,22},'fun',[{type,{2562,22},product,[{var,{2562,23},'Path'},{var,{2562,29},'LoadInfo'}]},{type,{2562,43},union,[{atom,{2562,43},ok},{var,{2562,48},'Error'}]}]},[{type,{2563,7},constraint,[{atom,{2563,7},is_subtype},[{var,{2563,7},'Path'},{type,{2563,15},string,[]}]]},{type,{2564,7},constraint,[{atom,{2564,7},is_subtype},[{var,{2564,7},'LoadInfo'},{type,{2564,19},term,[]}]]},{type,{2565,7},constraint,[{atom,{2565,7},is_subtype},[{var,{2565,7},'Error'},{type,{2565,16},tuple,[{atom,{2565,17},error},{type,{2565,24},tuple,[{var,{2565,25},'Reason'},{ann_type,{2565,33},[{var,{2565,33},'Text'},{type,{2565,41},string,[]}]}]}]}]]},{type,{2566,7},constraint,[{atom,{2566,7},is_subtype},[{var,{2566,7},'Reason'},{type,{2566,17},union,[{atom,{2566,17},load_failed},{atom,{2566,31},bad_lib},{atom,{2566,41},load},{atom,{2566,48},reload},{atom,{2566,57},upgrade},{atom,{2566,67},old_code}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,51,57,57,53>>}},{{function,loaded,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1612}],[<<108,111,97,100,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,108,111,97,100,101,100,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,40,99,117,114,114,101,110,116,32,97,110,100,32,111,108,100,32,99,111,100,101,41,44,32,105,110,99,108,117,100,105,110,103,32,112,114,101,108,111,97,100,101,100,32,109,111,100,117,108,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1612,2},spec,{{erlang,loaded,0},[{type,{1612,20},bounded_fun,[{type,{1612,20},'fun',[{type,{1612,20},product,[]},{type,{1612,26},list,[{var,{1612,27},'Module'}]}]},[{type,{1613,7},constraint,[{atom,{1613,7},is_subtype},[{var,{1613,7},'Module'},{type,{1613,17},module,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,48,53,52>>}},{{function,localtime,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1618}],[<<108,111,99,97,108,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,44,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,40,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46>>]}]},#{signature => [{attribute,{1618,2},spec,{{erlang,localtime,0},[{type,{1618,23},bounded_fun,[{type,{1618,23},'fun',[{type,{1618,23},product,[]},{var,{1618,29},'DateTime'}]},[{type,{1619,7},constraint,[{atom,{1619,7},is_subtype},[{var,{1619,7},'DateTime'},{remote_type,{1619,19},[{atom,{1619,19},calendar},{atom,{1619,28},datetime},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,48,54,53>>}},{{function,localtime_to_universaltime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3766}],[<<108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,44,32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,110,111,32,99,111,110,118,101,114,115,105,111,110,32,105,115,32,100,111,110,101,32,97,110,100,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{signature => [{attribute,{3766,2},spec,{{erlang,localtime_to_universaltime,1},[{type,{3766,40},bounded_fun,[{type,{3766,40},'fun',[{type,{3766,40},product,[{var,{3766,41},'Localtime'}]},{var,{3766,55},'Universaltime'}]},[{type,{3767,7},constraint,[{atom,{3767,7},is_subtype},[{var,{3767,7},'Localtime'},{remote_type,{3767,20},[{atom,{3767,20},calendar},{atom,{3767,29},datetime},[]]}]]},{type,{3768,7},constraint,[{atom,{3768,7},is_subtype},[{var,{3768,7},'Universaltime'},{remote_type,{3768,24},[{atom,{3768,24},calendar},{atom,{3768,33},datetime},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,48,56,50>>}},{{function,localtime_to_universaltime,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2570}],[<<108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,97,115,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,47,49>>]},<<44,32,98,117,116,32,116,104,101,32,99,97,108,108,101,114,32,100,101,99,105,100,101,115,32,105,102,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,105,115,32,97,99,116,105,118,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,116,114,117,101>>]},<<44,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,105,115,32,100,117,114,105,110,103,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,44,32,105,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,102,97,108,115,101>>]},<<32,105,116,32,105,115,32,110,111,116,46,32,73,102,32>>,{code,[],[<<73,115,68,115,116,32,61,61,32,117,110,100,101,102,105,110,101,100>>]},<<44,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,32,99,97,110,32,103,117,101,115,115,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,76,111,99,97,108,116,105,109,101,41>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,116,114,117,101,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,50,44,52,53,44,49,55,125,125,10,62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,102,97,108,115,101,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125,10,62,32,101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,95,116,111,95,117,110,105,118,101,114,115,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,52,53,44,49,55,125,125,44,32,117,110,100,101,102,105,110,101,100,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,51,44,52,53,44,49,55,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,111,99,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{signature => [{attribute,{2570,2},spec,{{erlang,localtime_to_universaltime,2},[{type,{2570,40},bounded_fun,[{type,{2570,40},'fun',[{type,{2570,40},product,[{var,{2570,41},'Localtime'},{var,{2570,52},'IsDst'}]},{var,{2570,62},'Universaltime'}]},[{type,{2571,7},constraint,[{atom,{2571,7},is_subtype},[{var,{2571,7},'Localtime'},{remote_type,{2571,20},[{atom,{2571,20},calendar},{atom,{2571,29},datetime},[]]}]]},{type,{2572,7},constraint,[{atom,{2572,7},is_subtype},[{var,{2572,7},'Universaltime'},{remote_type,{2572,24},[{atom,{2572,24},calendar},{atom,{2572,33},datetime},[]]}]]},{type,{2573,7},constraint,[{atom,{2573,7},is_subtype},[{var,{2573,7},'IsDst'},{type,{2573,16},union,[{atom,{2573,16},true},{atom,{2573,23},false},{atom,{2573,31},undefined}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,48,57,57>>}},{{function,make_ref,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1624}],[<<109,97,107,101,95,114,101,102,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,114,101,102,101,114,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<117,110,105,113,117,101,32,114,101,102,101,114,101,110,99,101>>]},<<46,32,84,104,101,32,114,101,102,101,114,101,110,99,101,32,105,115,32,117,110,105,113,117,101,32,97,109,111,110,103,32,99,111,110,110,101,99,116,101,100,32,110,111,100,101,115,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<66,101,102,111,114,101,32,79,84,80,45,50,51,32,119,104,101,110,32,97,32,110,111,100,101,32,105,115,32,114,101,115,116,97,114,116,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,110,97,109,101,44,32,114,101,102,101,114,101,110,99,101,115,32,99,114,101,97,116,101,100,32,111,110,32,97,32,110,101,119,101,114,32,110,111,100,101,32,99,97,110,32,98,101,32,109,105,115,116,97,107,101,110,32,102,111,114,32,97,32,114,101,102,101,114,101,110,99,101,32,99,114,101,97,116,101,100,32,111,110,32,97,110,32,111,108,100,101,114,32,110,111,100,101,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,110,97,109,101,46>>]}]}]},#{signature => [{attribute,{1624,2},spec,{{make_ref,0},[{type,{1624,15},'fun',[{type,{1624,15},product,[]},{type,{1624,21},reference,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,50,53>>}},{{function,make_tuple,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2589}],[<<109,97,107,101,95,116,117,112,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,110,101,119,32,116,117,112,108,101,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32>>,{code,[],[<<65,114,105,116,121>>]},<<44,32,119,104,101,114,101,32,97,108,108,32,101,108,101,109,101,110,116,115,32,97,114,101,32>>,{code,[],[<<73,110,105,116,105,97,108,86,97,108,117,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,109,97,107,101,95,116,117,112,108,101,40,52,44,32,91,93,41,46,10,123,91,93,44,91,93,44,91,93,44,91,93,125>>]}]}]},#{signature => [{attribute,{2589,2},spec,{{erlang,make_tuple,2},[{type,{2589,24},bounded_fun,[{type,{2589,24},'fun',[{type,{2589,24},product,[{var,{2589,25},'Arity'},{var,{2589,32},'InitialValue'}]},{type,{2589,49},tuple,any}]},[{type,{2590,7},constraint,[{atom,{2590,7},is_subtype},[{var,{2590,7},'Arity'},{type,{2590,16},arity,[]}]]},{type,{2591,7},constraint,[{atom,{2591,7},is_subtype},[{var,{2591,7},'InitialValue'},{type,{2591,23},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,52,50>>}},{{function,make_tuple,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2596}],[<<109,97,107,101,95,116,117,112,108,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,116,117,112,108,101,32,111,102,32,115,105,122,101,32>>,{code,[],[<<65,114,105,116,121>>]},<<44,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,104,97,115,32,118,97,108,117,101,32>>,{code,[],[<<68,101,102,97,117,108,116,86,97,108,117,101>>]},<<44,32,97,110,100,32,116,104,101,110,32,102,105,108,108,115,32,105,110,32,118,97,108,117,101,115,32,102,114,111,109,32>>,{code,[],[<<73,110,105,116,76,105,115,116>>]},<<46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<73,110,105,116,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32,97,32,116,119,111,45,116,117,112,108,101,44,32,119,104,101,114,101,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,116,117,112,108,101,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32,105,115,32,97,110,121,32,116,101,114,109,46,32,73,102,32,97,32,112,111,115,105,116,105,111,110,32,111,99,99,117,114,115,32,109,111,114,101,32,116,104,97,110,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,116,104,101,32,116,101,114,109,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,108,97,115,116,32,111,99,99,117,114,114,101,110,99,101,32,105,115,32,117,115,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,109,97,107,101,95,116,117,112,108,101,40,53,44,32,91,93,44,32,91,123,50,44,105,103,110,111,114,101,100,125,44,123,53,44,122,122,125,44,123,50,44,97,97,125,93,41,46,10,123,91,93,44,97,97,44,91,93,44,91,93,44,122,122,125>>]}]}]},#{signature => [{attribute,{2596,2},spec,{{erlang,make_tuple,3},[{type,{2596,24},bounded_fun,[{type,{2596,24},'fun',[{type,{2596,24},product,[{var,{2596,25},'Arity'},{var,{2596,32},'DefaultValue'},{var,{2596,46},'InitList'}]},{type,{2596,59},tuple,any}]},[{type,{2597,7},constraint,[{atom,{2597,7},is_subtype},[{var,{2597,7},'Arity'},{type,{2597,16},arity,[]}]]},{type,{2598,7},constraint,[{atom,{2598,7},is_subtype},[{var,{2598,7},'DefaultValue'},{type,{2598,23},term,[]}]]},{type,{2599,7},constraint,[{atom,{2599,7},is_subtype},[{var,{2599,7},'InitList'},{type,{2599,19},list,[{type,{2599,20},tuple,[{ann_type,{2599,21},[{var,{2599,21},'Position'},{type,{2599,33},pos_integer,[]}]},{type,{2599,48},term,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,53,52>>}},{{function,map_get,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1635}],[<<109,97,112,95,103,101,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[<<84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,109,97,112,44,77,97,112,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<77,97,112>>]},<<32,105,115,32,110,111,116,32,97,32,109,97,112,44,32,111,114,32,119,105,116,104,32,97,32>>,{code,[],[<<123,98,97,100,107,101,121,44,75,101,121,125>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32,110,111,32,118,97,108,117,101,32,105,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<62,32,75,101,121,32,61,32,49,51,51,55,44,10,32,32,77,97,112,32,61,32,35,123,52,50,32,61,62,32,118,97,108,117,101,95,116,119,111,44,49,51,51,55,32,61,62,32,34,118,97,108,117,101,32,111,110,101,34,44,34,97,34,32,61,62,32,49,125,44,10,32,32,109,97,112,95,103,101,116,40,75,101,121,44,77,97,112,41,46,10,34,118,97,108,117,101,32,111,110,101,34>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1635,2},spec,{{map_get,2},[{type,{1635,14},bounded_fun,[{type,{1635,14},'fun',[{type,{1635,14},product,[{var,{1635,15},'Key'},{var,{1635,20},'Map'}]},{var,{1635,28},'Value'}]},[{type,{1636,7},constraint,[{atom,{1636,7},is_subtype},[{var,{1636,7},'Map'},{type,{1636,14},map,any}]]},{type,{1637,7},constraint,[{atom,{1637,7},is_subtype},[{var,{1637,7},'Key'},{type,{1637,14},any,[]}]]},{type,{1638,7},constraint,[{atom,{1638,7},is_subtype},[{var,{1638,7},'Value'},{type,{1638,16},any,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,55,50>>,since => <<79,84,80,32,50,49,46,48>>}},{{function,map_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1629}],[<<109,97,112,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,107,101,121,45,118,97,108,117,101,32,112,97,105,114,115,32,105,110,32>>,{code,[],[<<77,97,112>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,109,97,112,95,115,105,122,101,40,35,123,97,61,62,49,44,32,98,61,62,50,44,32,99,61,62,51,125,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1629,2},spec,{{map_size,1},[{type,{1629,15},bounded_fun,[{type,{1629,15},'fun',[{type,{1629,15},product,[{var,{1629,16},'Map'}]},{type,{1629,24},non_neg_integer,[]}]},[{type,{1630,7},constraint,[{atom,{1630,7},is_subtype},[{var,{1630,7},'Map'},{type,{1630,14},map,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,49,57,50>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,match_spec_test,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1643}],[<<109,97,116,99,104,95,115,112,101,99,95,116,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,101,115,116,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,117,115,101,100,32,105,110,32,99,97,108,108,115,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,115,101,108,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,116,115,58,115,101,108,101,99,116,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,101,115,116,115,32,98,111,116,104,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,34,115,121,110,116,97,99,116,105,99,34,32,99,111,114,114,101,99,116,110,101,115,115,32,97,110,100,32,114,117,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,103,97,105,110,115,116,32,116,104,101,32,111,98,106,101,99,116,46,32,73,102,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,99,111,110,116,97,105,110,115,32,101,114,114,111,114,115,44,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,69,114,114,111,114,115,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,119,104,101,114,101,32>>,{code,[],[<<69,114,114,111,114,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,110,97,116,117,114,97,108,32,108,97,110,103,117,97,103,101,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,119,104,97,116,32,119,97,115,32,119,114,111,110,103,32,119,105,116,104,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<116,97,98,108,101>>]},<<44,32,116,104,101,32,111,98,106,101,99,116,32,116,111,32,109,97,116,99,104,32,97,103,97,105,110,115,116,32,105,115,32,116,111,32,98,101,32,97,32,116,117,112,108,101,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,82,101,115,117,108,116,44,91,93,44,87,97,114,110,105,110,103,115,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,119,104,97,116,32,119,111,117,108,100,32,104,97,118,101,32,98,101,101,110,32,116,104,101,32,114,101,115,117,108,116,32,105,110,32,97,32,114,101,97,108,32>>,{code,[],[<<101,116,115,58,115,101,108,101,99,116,47,50>>]},<<32,99,97,108,108,44,32,111,114,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,111,98,106,101,99,116,32,116,117,112,108,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<116,114,97,99,101>>]},<<44,32,116,104,101,32,111,98,106,101,99,116,32,116,111,32,109,97,116,99,104,32,97,103,97,105,110,115,116,32,105,115,32,116,111,32,98,101,32,97,32,108,105,115,116,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,82,101,115,117,108,116,44,32,70,108,97,103,115,44,32,87,97,114,110,105,110,103,115,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<116,114,117,101>>]},<<32,105,102,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,116,111,32,98,101,32,101,109,105,116,116,101,100>>]},{li,[],[{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,110,111,116,32,116,111,32,98,101,32,101,109,105,116,116,101,100>>]},{li,[],[<<84,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,32,116,111,32,98,101,32,97,112,112,101,110,100,101,100,32,116,111,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101>>]}]},{p,[],[{code,[],[<<70,108,97,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,116,111,32,98,101,32,101,110,97,98,108,101,100,44,32,99,117,114,114,101,110,116,108,121,32,116,104,105,115,32,105,115,32,111,110,108,121,32>>,{code,[],[<<114,101,116,117,114,110,95,116,114,97,99,101>>]},<<46>>]},{p,[],[<<84,104,105,115,32,105,115,32,97,32,117,115,101,102,117,108,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,116,101,115,116,32,116,111,111,108,44,32,101,115,112,101,99,105,97,108,108,121,32,119,104,101,110,32,119,114,105,116,105,110,103,32,99,111,109,112,108,105,99,97,116,101,100,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,116,101,115,116,95,109,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,116,115,58,116,101,115,116,95,109,115,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1643,2},spec,{{erlang,match_spec_test,3},[{type,{1643,29},bounded_fun,[{type,{1643,29},'fun',[{type,{1643,29},product,[{var,{1643,30},'MatchAgainst'},{var,{1643,44},'MatchSpec'},{var,{1643,55},'Type'}]},{var,{1643,64},'TestResult'}]},[{type,{1644,7},constraint,[{atom,{1644,7},is_subtype},[{var,{1644,7},'MatchAgainst'},{type,{1644,23},union,[{type,{1644,23},list,[{type,{1644,24},term,[]}]},{type,{1644,34},tuple,any}]}]]},{type,{1645,7},constraint,[{atom,{1645,7},is_subtype},[{var,{1645,7},'MatchSpec'},{type,{1645,20},term,[]}]]},{type,{1646,7},constraint,[{atom,{1646,7},is_subtype},[{var,{1646,7},'Type'},{type,{1646,15},union,[{atom,{1646,15},table},{atom,{1646,23},trace}]}]]},{type,{1647,7},constraint,[{atom,{1647,7},is_subtype},[{var,{1647,7},'TestResult'},{type,{1647,21},union,[{type,{1647,21},tuple,[{atom,{1647,22},ok},{type,{1647,26},term,[]},{type,{1647,34},list,[{atom,{1647,35},return_trace}]},{type,{1647,50},list,[{type,{1647,52},tuple,[{type,{1647,53},union,[{atom,{1647,53},error},{atom,{1647,61},warning}]},{type,{1647,70},string,[]}]}]}]},{type,{1647,85},tuple,[{atom,{1647,86},error},{type,{1647,93},list,[{type,{1647,95},tuple,[{type,{1647,96},union,[{atom,{1647,96},error},{atom,{1647,104},warning}]},{type,{1647,113},string,[]}]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,48,53>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,max,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4260}],[<<109,97,120,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,97,114,103,101,115,116,32,111,102,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,97,110,100,32>>,{code,[],[<<84,101,114,109,50>>]},<<46,32,73,102,32,116,104,101,32,116,101,114,109,115,32,99,111,109,112,97,114,101,32,101,113,117,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,44,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,101,114,109,45,99,111,109,112,97,114,105,115,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,120,112,114,101,115,115,105,111,110,115,32,115,101,99,116,105,111,110>>]},<<32,99,111,110,116,97,105,110,115,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,32,97,110,100,32,104,111,119,32,116,101,114,109,115,32,97,114,101,32,111,114,100,101,114,101,100,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,44,32,50,41,46,10,50>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,46,48,44,32,49,41,46,10,49,46,48>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,49,44,32,49,46,48,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,97,120,40,34,97,98,99,34,44,32,34,98,34,41,46,10,34,98,34>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,115,32,116,101,115,116,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,54,46>>]}]}]},#{signature => [{attribute,{4260,2},spec,{{max,2},[{type,{4260,10},bounded_fun,[{type,{4260,10},'fun',[{type,{4260,10},product,[{var,{4260,11},'Term1'},{var,{4260,18},'Term2'}]},{var,{4260,28},'Maximum'}]},[{type,{4261,7},constraint,[{atom,{4261,7},is_subtype},[{var,{4261,7},'Term1'},{type,{4261,16},term,[]}]]},{type,{4262,7},constraint,[{atom,{4262,7},is_subtype},[{var,{4262,7},'Term2'},{type,{4262,16},term,[]}]]},{type,{4263,7},constraint,[{atom,{4263,7},is_subtype},[{var,{4263,7},'Maximum'},{type,{4263,18},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,52,51>>}},{{function,md5,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1652}],[<<109,100,53,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,117,116,101,115,32,97,110,32,77,68,53,32,109,101,115,115,97,103,101,32,100,105,103,101,115,116,32,102,114,111,109,32>>,{code,[],[<<68,97,116,97>>]},<<44,32,119,104,101,114,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,100,105,103,101,115,116,32,105,115,32,49,50,56,32,98,105,116,115,32,40,49,54,32,98,121,116,101,115,41,46,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,111,114,32,97,32,108,105,115,116,32,111,102,32,115,109,97,108,108,32,105,110,116,101,103,101,114,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,77,68,53,44,32,115,101,101,32>>,{a,[{href,<<104,116,116,112,115,58,47,47,119,119,119,46,105,101,116,102,46,111,114,103,47,114,102,99,47,114,102,99,49,51,50,49,46,116,120,116>>}],[<<82,70,67,32,49,51,50,49,32,45,32,84,104,101,32,77,68,53,32,77,101,115,115,97,103,101,45,68,105,103,101,115,116,32,65,108,103,111,114,105,116,104,109>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,32,77,68,53,32,77,101,115,115,97,103,101,45,68,105,103,101,115,116,32,65,108,103,111,114,105,116,104,109,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,99,111,110,115,105,100,101,114,101,100,32,115,97,102,101,32,102,111,114,32,99,111,100,101,45,115,105,103,110,105,110,103,32,111,114,32,115,111,102,116,119,97,114,101,45,105,110,116,101,103,114,105,116,121,32,112,117,114,112,111,115,101,115,46>>]}]}]},#{signature => [{attribute,{1652,2},spec,{{erlang,md5,1},[{type,{1652,17},bounded_fun,[{type,{1652,17},'fun',[{type,{1652,17},product,[{var,{1652,18},'Data'}]},{var,{1652,27},'Digest'}]},[{type,{1653,7},constraint,[{atom,{1653,7},is_subtype},[{var,{1653,7},'Data'},{type,{1653,15},iodata,[]}]]},{type,{1654,7},constraint,[{atom,{1654,7},is_subtype},[{var,{1654,7},'Digest'},{type,{1654,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,55,52>>}},{{function,md5_final,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1659}],[<<109,100,53,95,102,105,110,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<70,105,110,105,115,104,101,115,32,116,104,101,32,117,112,100,97,116,101,32,111,102,32,97,110,32,77,68,53,32>>,{code,[],[<<67,111,110,116,101,120,116>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,99,111,109,112,117,116,101,100,32>>,{code,[],[<<77,68,53>>]},<<32,109,101,115,115,97,103,101,32,100,105,103,101,115,116,46>>]}]},#{signature => [{attribute,{1659,2},spec,{{erlang,md5_final,1},[{type,{1659,23},bounded_fun,[{type,{1659,23},'fun',[{type,{1659,23},product,[{var,{1659,24},'Context'}]},{var,{1659,36},'Digest'}]},[{type,{1660,7},constraint,[{atom,{1660,7},is_subtype},[{var,{1660,7},'Context'},{type,{1660,18},binary,[]}]]},{type,{1661,7},constraint,[{atom,{1661,7},is_subtype},[{var,{1661,7},'Digest'},{type,{1661,17},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,50,57,50>>}},{{function,md5_init,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1666}],[<<109,100,53,95,105,110,105,116,47,48>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,110,32,77,68,53,32,99,111,110,116,101,120,116,44,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,100,53,95,117,112,100,97,116,101,47,50>>]},<<46>>]}]},#{signature => [{attribute,{1666,2},spec,{{erlang,md5_init,0},[{type,{1666,22},bounded_fun,[{type,{1666,22},'fun',[{type,{1666,22},product,[]},{var,{1666,28},'Context'}]},[{type,{1667,7},constraint,[{atom,{1667,7},is_subtype},[{var,{1667,7},'Context'},{type,{1667,18},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,48,50>>}},{{function,md5_update,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1672}],[<<109,100,53,95,117,112,100,97,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<85,112,100,97,116,101,32,97,110,32,77,68,53,32>>,{code,[],[<<67,111,110,116,101,120,116>>]},<<32,119,105,116,104,32>>,{code,[],[<<68,97,116,97>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32,97,32>>,{code,[],[<<78,101,119,67,111,110,116,101,120,116>>]},<<46>>]}]},#{signature => [{attribute,{1672,2},spec,{{erlang,md5_update,2},[{type,{1672,24},bounded_fun,[{type,{1672,24},'fun',[{type,{1672,24},product,[{var,{1672,25},'Context'},{var,{1672,34},'Data'}]},{var,{1672,43},'NewContext'}]},[{type,{1673,7},constraint,[{atom,{1673,7},is_subtype},[{var,{1673,7},'Context'},{type,{1673,18},binary,[]}]]},{type,{1674,7},constraint,[{atom,{1674,7},is_subtype},[{var,{1674,7},'Data'},{type,{1674,15},iodata,[]}]]},{type,{1675,7},constraint,[{atom,{1675,7},is_subtype},[{var,{1675,7},'NewContext'},{type,{1675,21},binary,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,49,49>>}},{{function,memory,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4294}],[<<109,101,109,111,114,121,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,109,111,114,121,95,116,121,112,101>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,101,109,111,114,121,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,46,32,69,97,99,104,32,108,105,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,84,121,112,101,44,32,83,105,122,101,125>>]},<<46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,109,101,109,111,114,121,32,116,121,112,101,46,32,84,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,105,110,32,98,121,116,101,115,46>>]},{p,[],[<<77,101,109,111,114,121,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,111,116,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,102,111,114,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46,32,84,104,105,115,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,101,32,101,109,117,108,97,116,111,114,32,116,104,97,116,32,105,115,32,110,111,116,32,100,105,114,101,99,116,108,121,32,114,101,108,97,116,101,100,32,116,111,32,97,110,121,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46,32,77,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,105,115,32,109,101,109,111,114,121,46,32>>,{a,[{href,<<114,117,110,116,105,109,101,95,116,111,111,108,115,58,105,110,115,116,114,117,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,115,116,114,117,109,101,110,116,40,51,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,116,32,97,32,109,111,114,101,32,100,101,116,97,105,108,101,100,32,98,114,101,97,107,100,111,119,110,32,111,102,32,119,104,97,116,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,105,115,32,116,121,112,101,46>>]}]},{dt,[],[{code,[],[<<97,116,111,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,97,116,111,109,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<97,116,111,109,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,102,111,114,32,97,116,111,109,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<97,116,111,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,98,105,110,97,114,105,101,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<99,111,100,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,69,114,108,97,110,103,32,99,111,100,101,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,116,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,99,117,114,114,101,110,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,69,84,83,32,116,97,98,108,101,115,46,32,84,104,105,115,32,109,101,109,111,114,121,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,109,101,109,111,114,121,46>>]}]},{dt,[],[{code,[],[<<109,97,120,105,109,117,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,115,105,110,99,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,115,116,97,114,116,101,100,46,32,84,104,105,115,32,116,117,112,108,101,32,105,115,32,111,110,108,121,32,112,114,101,115,101,110,116,32,119,104,101,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,114,117,110,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,114,117,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<114,117,110,116,105,109,101,95,116,111,111,108,115,58,105,110,115,116,114,117,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,115,116,114,117,109,101,110,116,40,51,41>>]}]},<<32,97,110,100,47,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<101,114,108,40,49,41>>]}]},<<46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,32,105,115,32,110,111,116,32,99,111,109,112,108,101,116,101,46,32,83,111,109,101,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,105,115,32,118,97,108,117,101,32,105,115,32,110,111,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,114,117,110,32,119,105,116,104,32,105,110,115,116,114,117,109,101,110,116,97,116,105,111,110,44,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,32,105,115,32,109,111,114,101,32,97,99,99,117,114,97,116,101,44,32,98,117,116,32,109,101,109,111,114,121,32,100,105,114,101,99,116,108,121,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32>>,{code,[],[<<109,97,108,108,111,99>>]},<<32,40,97,110,100,32,102,114,105,101,110,100,115,41,32,105,115,32,115,116,105,108,108,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,118,97,108,117,101,46,32,68,105,114,101,99,116,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,97,108,108,111,99>>]},<<32,97,114,101,32,111,110,108,121,32,100,111,110,101,32,102,114,111,109,32,79,83,45,115,112,101,99,105,102,105,99,32,114,117,110,116,105,109,101,32,108,105,98,114,97,114,105,101,115,32,97,110,100,32,112,101,114,104,97,112,115,32,102,114,111,109,32,117,115,101,114,45,105,109,112,108,101,109,101,110,116,101,100,32,69,114,108,97,110,103,32,100,114,105,118,101,114,115,32,116,104,97,116,32,100,111,32,110,111,116,32,117,115,101,32,116,104,101,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,100,114,105,118,101,114,32,105,110,116,101,114,102,97,99,101,46>>]},{p,[],[<<65,115,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32,116,104,101,32,115,117,109,32,111,102,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<44,32,116,104,101,32,101,114,114,111,114,32,105,110,32>>,{code,[],[<<115,121,115,116,101,109>>]},<<32,112,114,111,112,97,103,97,116,101,115,32,116,111,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,46>>]},{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,97,109,111,117,110,116,115,32,111,102,32,109,101,109,111,114,121,32,116,104,97,116,32,97,114,101,32,115,117,109,109,101,100,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,44,32,119,104,105,99,104,32,105,110,116,114,111,100,117,99,101,115,32,97,110,32,101,114,114,111,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,118,97,108,117,101,115,32,104,97,118,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,108,97,116,105,111,110,32,116,111,32,101,97,99,104,32,111,116,104,101,114,46,32,86,97,108,117,101,115,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,97,110,32,117,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,32,105,115,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<116,111,116,97,108,32,32,32,32,32,32,61,32,112,114,111,99,101,115,115,101,115,32,43,32,115,121,115,116,101,109,10,112,114,111,99,101,115,115,101,115,32,32,61,32,112,114,111,99,101,115,115,101,115,95,117,115,101,100,32,43,32,80,114,111,99,101,115,115,101,115,78,111,116,85,115,101,100,10,115,121,115,116,101,109,32,32,32,32,32,61,32,97,116,111,109,32,43,32,98,105,110,97,114,121,32,43,32,99,111,100,101,32,43,32,101,116,115,32,43,32,79,116,104,101,114,83,121,115,116,101,109,10,97,116,111,109,32,32,32,32,32,32,32,61,32,97,116,111,109,95,117,115,101,100,32,43,32,65,116,111,109,78,111,116,85,115,101,100,10,82,101,97,108,84,111,116,97,108,32,32,61,32,112,114,111,99,101,115,115,101,115,32,43,32,82,101,97,108,83,121,115,116,101,109,10,82,101,97,108,83,121,115,116,101,109,32,61,32,115,121,115,116,101,109,32,43,32,77,105,115,115,101,100,83,121,115,116,101,109>>]}]},{p,[],[<<77,111,114,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,104,97,114,101,100,32,108,105,98,114,97,114,105,101,115,44,32,116,104,101,32,99,111,100,101,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,116,115,101,108,102,44,32,97,110,100,32,116,104,101,32,101,109,117,108,97,116,111,114,32,115,116,97,99,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,105,110,99,108,117,100,101,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32>>,{code,[],[<<116,111,116,97,108>>]},<<32,118,97,108,117,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,101,113,117,97,108,32,116,111,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,97,108,108,32,112,97,103,101,115,32,109,97,112,112,101,100,32,116,111,32,116,104,101,32,101,109,117,108,97,116,111,114,46>>]},{p,[],[<<65,108,115,111,44,32,98,101,99,97,117,115,101,32,111,102,32,102,114,97,103,109,101,110,116,97,116,105,111,110,32,97,110,100,32,112,114,101,114,101,115,101,114,118,97,116,105,111,110,32,111,102,32,109,101,109,111,114,121,32,97,114,101,97,115,44,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,115,101,103,109,101,110,116,115,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,98,108,111,99,107,115,32,99,97,110,32,98,101,32,109,117,99,104,32,108,97,114,103,101,114,32,116,104,97,110,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,116,104,101,32,100,121,110,97,109,105,99,97,108,108,121,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,98,108,111,99,107,115,46>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,52,44,32>>,{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]},<<32,114,101,113,117,105,114,101,115,32,116,104,97,116,32,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,101,110,97,98,108,101,100,32,40,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,41,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,105,102,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,105,115,97,98,108,101,100,46>>]}]},#{signature => [{attribute,{4294,2},spec,{{erlang,memory,0},[{type,{4294,20},bounded_fun,[{type,{4294,20},'fun',[{type,{4294,20},product,[]},{type,{4294,26},list,[{type,{4294,27},tuple,[{var,{4294,28},'Type'},{var,{4294,34},'Size'}]}]}]},[{type,{4295,7},constraint,[{atom,{4295,7},is_subtype},[{var,{4295,7},'Type'},{user_type,{4295,15},memory_type,[]}]]},{type,{4296,7},constraint,[{atom,{4296,7},is_subtype},[{var,{4296,7},'Size'},{type,{4296,15},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,51,50,50>>}},{{function,memory,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4313}],[<<109,101,109,111,114,121,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,109,111,114,121,95,116,121,112,101>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,109,111,114,121,32,115,105,122,101,32,105,110,32,98,121,116,101,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,109,101,109,111,114,121,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84,121,112,101>>]},<<46,32,84,104,101,32,97,114,103,117,109,101,110,116,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<109,101,109,111,114,121,95,116,121,112,101,40,41>>]},<<32,97,116,111,109,115,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,97,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,109,101,109,111,114,121,95,116,121,112,101,40,41,44,32,83,105,122,101,32,58,58,32,105,110,116,101,103,101,114,32,62,61,32,48,125>>]},<<32,116,117,112,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,52,44,32>>,{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,49>>]},<<32,114,101,113,117,105,114,101,115,32,116,104,97,116,32,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,101,110,97,98,108,101,100,32,40,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,41,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,110,111,116,32,111,110,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,116,121,112,101,115,32,108,105,115,116,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]}]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<109,97,120,105,109,117,109>>]},<<32,105,115,32,112,97,115,115,101,100,32,97,115,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,110,100,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,110,111,116,32,114,117,110,32,105,110,32,105,110,115,116,114,117,109,101,110,116,101,100,32,109,111,100,101,46>>]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<32,97,108,108,111,99,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,105,115,97,98,108,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48>>]}]},<<46>>]}]},#{signature => [{attribute,{4313,2},spec,{{erlang,memory,1},[{type,{4313,20},'fun',[{type,{4313,20},product,[{ann_type,{4313,21},[{var,{4313,21},'Type'},{user_type,{4313,29},memory_type,[]}]}]},{type,{4313,47},non_neg_integer,[]}]},{type,{4314,20},'fun',[{type,{4314,20},product,[{ann_type,{4314,21},[{var,{4314,21},'TypeList'},{type,{4314,33},list,[{user_type,{4314,34},memory_type,[]}]}]}]},{type,{4314,53},list,[{type,{4314,54},tuple,[{user_type,{4314,55},memory_type,[]},{type,{4314,70},non_neg_integer,[]}]}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,52,53,55>>}},{{function,min,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4250}],[<<109,105,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,97,110,100,32>>,{code,[],[<<84,101,114,109,50>>]},<<46,32,73,102,32,116,104,101,32,116,101,114,109,115,32,99,111,109,112,97,114,101,32,101,113,117,97,108,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,44,32>>,{code,[],[<<84,101,114,109,49>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,101,114,109,45,99,111,109,112,97,114,105,115,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,120,112,114,101,115,115,105,111,110,115,32,115,101,99,116,105,111,110>>]},<<32,99,111,110,116,97,105,110,115,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,116,104,101,32>>,{code,[],[<<61,61>>]},<<32,111,112,101,114,97,116,111,114,32,97,110,100,32,104,111,119,32,116,101,114,109,115,32,97,114,101,32,111,114,100,101,114,101,100,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,44,32,50,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,46,48,44,32,49,41,46,10,49,46,48>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,49,44,32,49,46,48,41,46,10,49>>]}]},{pre,[],[{code,[],[<<62,32,109,105,110,40,34,97,98,99,34,44,32,34,98,34,41,46,10,34,97,98,99,34>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,115,32,116,101,115,116,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,50,54,46>>]}]}]},#{signature => [{attribute,{4250,2},spec,{{min,2},[{type,{4250,10},bounded_fun,[{type,{4250,10},'fun',[{type,{4250,10},product,[{var,{4250,11},'Term1'},{var,{4250,18},'Term2'}]},{var,{4250,28},'Minimum'}]},[{type,{4251,7},constraint,[{atom,{4251,7},is_subtype},[{var,{4251,7},'Term1'},{type,{4251,16},term,[]}]]},{type,{4252,7},constraint,[{atom,{4252,7},is_subtype},[{var,{4252,7},'Term2'},{type,{4252,16},term,[]}]]},{type,{4253,7},constraint,[{atom,{4253,7},is_subtype},[{var,{4253,7},'Minimum'},{type,{4253,18},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,52,57,55>>}},{{function,module_loaded,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1680}],[<<109,111,100,117,108,101,95,108,111,97,100,101,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,108,111,97,100,101,100,32,97,115,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,99,111,100,101,95,108,111,97,100,105,110,103,35,99,111,100,101,45,114,101,112,108,97,99,101,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<99,117,114,114,101,110,116,32,99,111,100,101>>]}]},<<59,32,111,116,104,101,114,119,105,115,101,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,116,116,101,109,112,116,32,116,111,32,108,111,97,100,32,116,104,101,32,109,111,100,117,108,101,46>>]}]},#{signature => [{attribute,{1680,2},spec,{{module_loaded,1},[{type,{1680,20},bounded_fun,[{type,{1680,20},'fun',[{type,{1680,20},product,[{var,{1680,21},'Module'}]},{type,{1680,32},boolean,[]}]},[{type,{1681,7},constraint,[{atom,{1681,7},is_subtype},[{var,{1681,7},'Module'},{type,{1681,17},module,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,53,50,56>>}},{{function,monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1693}],[<<109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,111,110,105,116,111,114,95,112,111,114,116,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]}]},{p,[],[{a,[{id,<<109,111,110,105,116,111,114,95,109,101,115,115,97,103,101>>}],[]},<<83,101,110,100,115,32,97,32,109,111,110,105,116,111,114,32,114,101,113,117,101,115,116,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,116,111,32,116,104,101,32,101,110,116,105,116,121,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<46,32,73,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,111,114,32,105,116,32,99,104,97,110,103,101,115,32,109,111,110,105,116,111,114,101,100,32,115,116,97,116,101,44,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,105,115,32,110,111,116,105,102,105,101,100,32,98,121,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,97,116,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,84,97,103,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,79,98,106,101,99,116,44,32,73,110,102,111,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,114,101,113,117,101,115,116,32,105,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,115,105,103,110,97,108,46,32,84,104,97,116,32,105,115,44,32,105,116,32,116,97,107,101,115,32,116,105,109,101,32,98,101,102,111,114,101,32,116,104,101,32,115,105,103,110,97,108,32,114,101,97,99,104,101,115,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,46>>]}]},{p,[],[{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,58,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<44,32>>,{code,[],[<<112,111,114,116>>]},<<32,111,114,32>>,{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]},<<46>>]},{p,[],[<<65,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,111,110,108,121,32,111,110,99,101,44,32,97,102,116,101,114,32,116,104,97,116,32,105,116,32,105,115,32,114,101,109,111,118,101,100,32,102,114,111,109,32,98,111,116,104,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,46,32,77,111,110,105,116,111,114,115,32,97,114,101,32,102,105,114,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,116,101,114,109,105,110,97,116,101,115,44,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,97,116,32,116,104,101,32,109,111,109,101,110,116,32,111,102,32,99,114,101,97,116,105,111,110,44,32,111,114,32,105,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,105,116,32,105,115,32,108,111,115,116,46,32,73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,105,116,32,105,115,32,108,111,115,116,44,32,119,101,32,100,111,32,110,111,116,32,107,110,111,119,32,105,102,32,105,116,32,115,116,105,108,108,32,101,120,105,115,116,115,46,32,84,104,101,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,97,108,115,111,32,116,117,114,110,101,100,32,111,102,102,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<100,101,109,111,110,105,116,111,114,47,49>>]},<<32,105,115,32,99,97,108,108,101,100,46>>]},{p,[],[<<65,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,98,121,32,110,97,109,101,32,114,101,115,111,108,118,101,115,32,116,104,101,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,116,111,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,111,110,108,121,32,111,110,99,101,32,97,116,32,116,104,101,32,109,111,109,101,110,116,32,111,102,32,109,111,110,105,116,111,114,32,105,110,115,116,97,110,116,105,97,116,105,111,110,44,32,108,97,116,101,114,32,99,104,97,110,103,101,115,32,116,111,32,116,104,101,32,110,97,109,101,32,114,101,103,105,115,116,114,97,116,105,111,110,32,119,105,108,108,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,101,120,105,115,116,105,110,103,32,109,111,110,105,116,111,114,46>>]},{p,[],[<<87,104,101,110,32,97,32>>,{code,[],[<<112,114,111,99,101,115,115>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116>>]},<<32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,44,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,104,97,116,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,39,68,79,87,78,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,79,98,106,101,99,116,44,32,73,110,102,111,125>>]}]},{p,[],[<<73,110,32,116,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<32,97,110,100,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,44,32,97,110,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<79,98,106,101,99,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,101,100,32,101,110,116,105,116,121,44,32,119,104,105,99,104,32,116,114,105,103,103,101,114,101,100,32,116,104,101,32,101,118,101,110,116,46,32,87,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,97,32,112,114,111,99,101,115,115,32,111,114,32,97,32,108,111,99,97,108,32,112,111,114,116,44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<32,119,105,108,108,32,98,101,32,101,113,117,97,108,32,116,111,32,116,104,101,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,116,104,97,116,32,119,97,115,32,98,101,105,110,103,32,109,111,110,105,116,111,114,101,100,46,32,87,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,98,121,32,110,97,109,101,44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<32,119,105,108,108,32,104,97,118,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,119,104,105,99,104,32,104,97,115,32,98,101,101,110,32,117,115,101,100,32,119,105,116,104,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,99,97,108,108,32,97,110,100,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,108,111,99,97,108,32,111,114,32,114,101,109,111,116,101,32,110,111,100,101,32,110,97,109,101,32,40,102,111,114,32,112,111,114,116,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,44,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,97,108,119,97,121,115,32,108,111,99,97,108,32,110,111,100,101,32,110,97,109,101,41,46>>]}]},{dt,[],[{code,[],[<<73,110,102,111>>]}]},{dd,[],[{p,[],[<<69,105,116,104,101,114,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,44,32>>,{code,[],[<<110,111,112,114,111,99>>]},<<32,40,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,100,105,100,32,110,111,116,32,101,120,105,115,116,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,109,111,110,105,116,111,114,32,99,114,101,97,116,105,111,110,41,44,32,111,114,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,40,110,111,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,110,111,100,101,32,119,104,101,114,101,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,114,101,115,105,100,101,115,41,46>>]}]}]},{dl,[],[{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115>>}],[]},{code,[],[<<112,114,111,99,101,115,115>>]}]},{dd,[],[{p,[],[<<67,114,101,97,116,101,115,32,109,111,110,105,116,111,114,32,98,101,116,119,101,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,97,110,100,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,40,108,111,99,97,108,32,111,114,32,114,101,109,111,116,101,41,44,32,97,110,32,97,116,111,109,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,44,32,108,111,99,97,116,101,100,32,101,108,115,101,119,104,101,114,101,46>>]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<66,101,102,111,114,101,32,69,82,84,83,32,49,48,46,48,32,40,79,84,80,32,50,49,46,48,41,44,32,109,111,110,105,116,111,114,105,110,103,32,97,32,112,114,111,99,101,115,115,32,99,111,117,108,100,32,102,97,105,108,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,32,114,101,115,105,100,101,100,32,111,110,32,97,32,112,114,105,109,105,116,105,118,101,32,110,111,100,101,32,40,115,117,99,104,32,97,115,32,101,114,108,95,105,110,116,101,114,102,97,99,101,32,111,114,32,106,105,110,116,101,114,102,97,99,101,41,44,32,119,104,101,114,101,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,46>>]},{p,[],[<<78,111,119,44,32,115,117,99,104,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,119,105,108,108,32,105,110,115,116,101,97,100,32,115,117,99,99,101,101,100,32,97,110,100,32,97,32,109,111,110,105,116,111,114,32,105,115,32,99,114,101,97,116,101,100,46,32,66,117,116,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,111,110,108,121,32,115,117,112,101,114,118,105,115,101,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,97,32>>,{code,[],[<<123,39,68,79,87,78,39,44,32,95,44,32,112,114,111,99,101,115,115,44,32,95,44,32,110,111,99,111,110,110,101,99,116,105,111,110,125>>]},<<32,105,115,32,116,104,101,32,111,110,108,121,32,109,101,115,115,97,103,101,32,116,104,97,116,32,109,97,121,32,98,101,32,114,101,99,101,105,118,101,100,44,32,97,115,32,116,104,101,32,112,114,105,109,105,116,105,118,101,32,110,111,100,101,32,104,97,118,101,32,110,111,32,119,97,121,32,111,102,32,114,101,112,111,114,116,105,110,103,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,109,111,110,105,116,111,114,101,100,32,112,114,111,99,101,115,115,46>>]}]}]},{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,112,111,114,116>>}],[]},{code,[],[<<112,111,114,116>>]}]},{dd,[],[{p,[],[<<67,114,101,97,116,101,115,32,109,111,110,105,116,111,114,32,98,101,116,119,101,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,97,110,100,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,97,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<32,40,111,110,108,121,32,108,111,99,97,108,41,44,32,97,110,32,97,116,111,109,32>>,{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,105,115,116,101,114,101,100,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,111,114,116,44,32,108,111,99,97,116,101,100,32,111,110,32,116,104,105,115,32,110,111,100,101,46,32,78,111,116,101,44,32,116,104,97,116,32,97,116,116,101,109,112,116,32,116,111,32,109,111,110,105,116,111,114,32,97,32,114,101,109,111,116,101,32,112,111,114,116,32,119,105,108,108,32,114,101,115,117,108,116,32,105,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46>>]}]},{dt,[],[<<77,111,110,105,116,111,114,105,110,103,32,97,32>>,{a,[{id,<<109,111,110,105,116,111,114,95,116,105,109,101,95,111,102,102,115,101,116>>}],[]},{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,99,104,97,110,103,101,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,105,109,101,32,111,102,102,115,101,116>>]}]},<<32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<46,32,79,110,101,32,118,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,101,120,105,115,116,115,32,105,110,32,99,111,109,98,105,110,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<116,105,109,101,95,111,102,102,115,101,116,32,84,121,112,101>>]},<<44,32,110,97,109,101,108,121,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,108,111,99,107,95,115,101,114,118,105,99,101>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,108,111,99,107,95,115,101,114,118,105,99,101>>]},<<32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,32,112,114,111,99,101,115,115,46,32,73,110,32,116,104,105,115,32,99,97,115,101,32,105,116,32,115,101,114,118,101,115,32,97,115,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,116,101,114,110,97,108,32,99,108,111,99,107,32,115,101,114,118,105,99,101,32,97,116,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,119,104,101,110,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,46,32,84,104,105,115,32,101,105,116,104,101,114,32,105,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,118,97,108,117,101,32,105,115,32,99,104,97,110,103,101,100,44,32,111,114,32,105,102,32,116,104,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32,112,114,101,108,105,109,105,110,97,114,121,32,116,111,32,102,105,110,97,108,32,100,117,114,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,110,97,108,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116>>]},<<32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46,32,87,104,101,110,32,97,32,99,104,97,110,103,101,32,102,114,111,109,32,112,114,101,108,105,109,105,110,97,114,121,32,116,111,32,102,105,110,97,108,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,109,97,100,101,44,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,111,110,99,101,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,118,97,108,117,101,32,119,97,115,32,99,104,97,110,103,101,100,32,111,114,32,110,111,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,101,116,101,99,116,115,32,116,104,97,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,104,97,115,32,99,104,97,110,103,101,100,46,32,84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,111,101,115,44,32,104,111,119,101,118,101,114,44,32,110,111,116,32,100,101,116,101,99,116,32,116,104,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,46,32,65,32,116,97,115,107,32,99,104,101,99,107,105,110,103,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,101,120,101,99,117,116,101,32,97,116,32,108,101,97,115,116,32,111,110,99,101,32,97,32,109,105,110,117,116,101,44,32,115,111,32,117,110,100,101,114,32,110,111,114,109,97,108,32,111,112,101,114,97,116,105,111,110,32,116,104,105,115,32,105,115,32,116,111,32,98,101,32,100,101,116,101,99,116,101,100,32,119,105,116,104,105,110,32,97,32,109,105,110,117,116,101,44,32,98,117,116,32,100,117,114,105,110,103,32,104,101,97,118,121,32,108,111,97,100,32,105,116,32,99,97,110,32,116,97,107,101,32,108,111,110,103,101,114,32,116,105,109,101,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,97,102,116,101,114,32,105,116,32,104,97,115,32,98,101,101,110,32,116,114,105,103,103,101,114,101,100,46,32,84,104,97,116,32,105,115,44,32,114,101,112,101,97,116,101,100,32,99,104,97,110,103,101,115,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,116,114,105,103,103,101,114,32,116,104,101,32,109,111,110,105,116,111,114,32,114,101,112,101,97,116,101,100,108,121,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,32,97,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,46,32,65,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<123,39,67,72,65,78,71,69,39,44,32,77,111,110,105,116,111,114,82,101,102,44,32,84,121,112,101,44,32,73,116,101,109,44,32,78,101,119,84,105,109,101,79,102,102,115,101,116,125>>]}]},{p,[],[<<119,104,101,114,101,32>>,{code,[],[<<77,111,110,105,116,111,114,82,101,102>>]},<<44,32>>,{code,[],[<<84,121,112,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,44,32,97,110,100,32>>,{code,[],[<<78,101,119,84,105,109,101,79,102,102,115,101,116>>]},<<32,105,115,32,116,104,101,32,110,101,119,32,116,105,109,101,32,111,102,102,115,101,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,32,104,97,115,32,98,101,101,110,32,114,101,99,101,105,118,101,100,32,121,111,117,32,97,114,101,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,114,101,116,114,105,101,118,101,32,116,104,101,32,111,108,100,32,116,105,109,101,32,111,102,102,115,101,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,121,111,117,32,99,97,110,32,111,98,115,101,114,118,101,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]},<<32,98,101,102,111,114,101,32,121,111,117,32,103,101,116,32,116,104,101,32>>,{code,[],[<<39,67,72,65,78,71,69,39>>]},<<32,109,101,115,115,97,103,101,46>>]}]}]},{p,[],[<<77,97,107,105,110,103,32,115,101,118,101,114,97,108,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,102,111,114,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,110,100,47,111,114,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,59,32,105,116,32,114,101,115,117,108,116,115,32,105,110,32,97,115,32,109,97,110,121,32,105,110,100,101,112,101,110,100,101,110,116,32,109,111,110,105,116,111,114,105,110,103,32,105,110,115,116,97,110,99,101,115,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,101,120,116,101,110,100,101,100,46,32,84,104,97,116,32,105,115,44,32,111,116,104,101,114,32>>,{code,[],[<<84,121,112,101>>]},<<115,32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,115,117,112,112,111,114,116,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,111,114,32,119,104,101,110,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<32,105,115,32,101,120,116,101,110,100,101,100,44,32,111,116,104,101,114,32,112,111,115,115,105,98,108,101,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<84,97,103>>]},<<44,32>>,{code,[],[<<79,98,106,101,99,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,110,32,116,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,105,110,116,114,111,100,117,99,101,100,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]}]},#{signature => [{attribute,{1693,2},spec,{{monitor,2},[{type,{1694,7},bounded_fun,[{type,{1694,7},'fun',[{type,{1694,7},product,[{atom,{1694,8},process},{user_type,{1694,17},monitor_process_identifier,[]}]},{var,{1694,50},'MonitorRef'}]},[{type,{1695,9},constraint,[{atom,{1695,9},is_subtype},[{var,{1695,9},'MonitorRef'},{type,{1695,23},reference,[]}]]}]]},{type,{1696,7},bounded_fun,[{type,{1696,7},'fun',[{type,{1696,7},product,[{atom,{1696,8},port},{user_type,{1696,14},monitor_port_identifier,[]}]},{var,{1696,44},'MonitorRef'}]},[{type,{1697,9},constraint,[{atom,{1697,9},is_subtype},[{var,{1697,9},'MonitorRef'},{type,{1697,23},reference,[]}]]}]]},{type,{1698,7},bounded_fun,[{type,{1698,7},'fun',[{type,{1698,7},product,[{atom,{1698,8},time_offset},{atom,{1698,21},clock_service}]},{var,{1698,39},'MonitorRef'}]},[{type,{1699,9},constraint,[{atom,{1699,9},is_subtype},[{var,{1699,9},'MonitorRef'},{type,{1699,23},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,53,52,50>>,since => <<79,84,80,32,49,56,46,48,44,79,84,80,32,49,57,46,48>>}},{{function,monitor,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1705}],[<<109,111,110,105,116,111,114,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,111,110,105,116,111,114,95,112,111,114,116,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<109,111,110,105,116,111,114,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>}],[]},{li,[{name,<<114,101,103,105,115,116,101,114,101,100,95,112,114,111,99,101,115,115,95,105,100,101,110,116,105,102,105,101,114>>}],[]}]},{p,[],[<<80,114,111,118,105,100,101,115,32,97,110,32,111,112,116,105,111,110,32,108,105,115,116,32,102,111,114,32,109,111,100,105,102,105,99,97,116,105,111,110,32,111,102,32,109,111,110,105,116,111,114,105,110,103,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,112,114,111,118,105,100,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,50>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,97,110,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,97,114,103,117,109,101,110,116,115,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,109,101,97,110,105,110,103,32,97,115,32,119,104,101,110,32,112,97,115,115,101,100,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<46,32,67,117,114,114,101,110,116,108,121,32,97,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,108,105,97,115,44,32,85,110,97,108,105,97,115,79,112,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,109,111,110,105,116,111,114,32,114,101,102,101,114,101,110,99,101,32,119,105,108,108,32,97,108,115,111,32,98,101,99,111,109,101,32,97,110,32,97,108,105,97,115,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,108,105,97,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,108,105,97,115,47,48>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<85,110,97,108,105,97,115,79,112,116>>]},<<32,100,101,116,101,114,109,105,110,101,115,32,104,111,119,32,116,104,101,32,97,108,105,97,115,32,115,104,111,117,108,100,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,46>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,112,108,105,99,105,116,95,117,110,97,108,105,97,115>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,97,110,32,101,120,112,108,105,99,105,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,97,108,105,97,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,97,108,105,97,115,47,49>>]}]},<<32,119,105,108,108,32,100,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,46>>]}]},{dt,[],[{code,[],[<<100,101,109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,101,105,116,104,101,114,32,118,105,97,32,97,110,32,101,120,112,108,105,99,105,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,101,109,111,110,105,116,111,114,47,49>>]}]},<<32,111,114,32,119,104,101,110,32,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,97,115,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,100,101,108,105,118,101,114,101,100,32,100,117,101,32,116,111,32,116,104,101,32,109,111,110,105,116,111,114,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46>>]}]},{dt,[],[{code,[],[<<114,101,112,108,121,95,100,101,109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,97,108,105,97,115,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,114,101,109,111,118,101,100,32,40,115,101,101,32>>,{code,[],[<<100,101,109,111,110,105,116,111,114>>]},<<32,111,112,116,105,111,110,32,97,98,111,118,101,41,32,111,114,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,99,101,105,118,101,100,46,32,87,104,101,110,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,115,32,114,101,99,101,105,118,101,100,32,118,105,97,32,116,104,101,32,97,108,105,97,115,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,97,108,115,111,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,110,32,99,108,105,101,110,116,47,115,101,114,118,101,114,32,115,99,101,110,97,114,105,111,115,32,119,104,101,110,32,97,32,99,108,105,101,110,116,32,109,111,110,105,116,111,114,115,32,116,104,101,32,115,101,114,118,101,114,32,97,110,100,32,119,105,108,108,32,103,101,116,32,116,104,101,32,114,101,112,108,121,32,118,105,97,32,116,104,101,32,97,108,105,97,115,46,32,79,110,99,101,32,116,104,101,32,114,101,115,112,111,110,115,101,32,105,115,32,114,101,99,101,105,118,101,100,32,98,111,116,104,32,116,104,101,32,97,108,105,97,115,32,97,110,100,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,109,111,118,101,100,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,114,101,115,112,111,110,115,101,32,105,115,32,97,32,114,101,112,108,121,32,111,114,32,97,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,46,32,84,104,101,32,97,108,105,97,115,32,99,97,110,32,97,108,115,111,32,115,116,105,108,108,32,98,101,32,100,101,97,99,116,105,118,97,116,101,100,32,118,105,97,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<46,32,78,111,116,101,32,116,104,97,116,32,105,102,32,116,104,101,32,97,108,105,97,115,32,105,115,32,114,101,109,111,118,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<32,66,73,70,44,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,115,116,105,108,108,32,98,101,32,108,101,102,116,32,97,99,116,105,118,101,46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<115,101,114,118,101,114,40,41,32,45,62,10,32,32,32,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,123,114,101,113,117,101,115,116,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,82,101,115,117,108,116,32,61,32,112,101,114,102,111,114,109,95,114,101,113,117,101,115,116,40,82,101,113,117,101,115,116,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,65,108,105,97,115,82,101,113,73,100,32,33,32,123,114,101,112,108,121,44,32,65,108,105,97,115,82,101,113,73,100,44,32,82,101,115,117,108,116,125,10,32,32,32,32,101,110,100,44,10,32,32,32,32,115,101,114,118,101,114,40,41,46,10,10,99,108,105,101,110,116,40,83,101,114,118,101,114,80,105,100,44,32,82,101,113,117,101,115,116,41,32,45,62,10,32,32,32,32,65,108,105,97,115,77,111,110,82,101,113,73,100,32,61,32,109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,83,101,114,118,101,114,80,105,100,44,32,91,123,97,108,105,97,115,44,32,114,101,112,108,121,95,100,101,109,111,110,105,116,111,114,125,93,41,44,10,32,32,32,32,83,101,114,118,101,114,80,105,100,32,33,32,123,114,101,113,117,101,115,116,44,32,65,108,105,97,115,77,111,110,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,44,10,32,32,32,32,37,37,32,65,108,105,97,115,32,97,115,32,119,101,108,108,32,97,115,32,109,111,110,105,116,111,114,32,119,105,108,108,32,98,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,97,99,116,105,118,97,116,101,100,32,105,102,32,119,101,10,32,32,32,32,37,37,32,114,101,99,101,105,118,101,32,97,32,114,101,112,108,121,32,111,114,32,97,32,39,68,79,87,78,39,32,109,101,115,115,97,103,101,32,115,105,110,99,101,32,119,101,32,117,115,101,100,32,39,114,101,112,108,121,95,100,101,109,111,110,105,116,111,114,39,10,32,32,32,32,37,37,32,97,115,32,117,110,97,108,105,97,115,32,111,112,116,105,111,110,46,46,46,10,32,32,32,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,123,114,101,112,108,121,44,32,65,108,105,97,115,77,111,110,82,101,113,73,100,44,32,82,101,115,117,108,116,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,82,101,115,117,108,116,59,10,32,32,32,32,32,32,32,32,123,39,68,79,87,78,39,44,32,65,108,105,97,115,77,111,110,82,101,113,73,100,44,32,112,114,111,99,101,115,115,44,32,83,101,114,118,101,114,80,105,100,44,32,69,120,105,116,82,101,97,115,111,110,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,101,114,114,111,114,40,69,120,105,116,82,101,97,115,111,110,41,10,32,32,32,32,101,110,100,46,10,9,32,32,32,32>>]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,98,111,116,104,32,116,104,101,32,115,101,114,118,101,114,32,97,110,100,32,116,104,101,32,99,108,105,101,110,116,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,109,117,115,116,32,98,101,32,101,120,101,99,117,116,105,110,103,32,111,110,32,97,116,32,108,101,97,115,116,32,79,84,80,32,50,52,32,115,121,115,116,101,109,115,32,105,110,32,111,114,100,101,114,32,102,111,114,32,116,104,105,115,32,116,111,32,119,111,114,107,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,111,99,101,115,115,32,97,108,105,97,115,101,115,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,112,114,111,99,101,115,115,45,97,108,105,97,115,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<80,114,111,99,101,115,115,32,65,108,105,97,115,101,115>>]}]},<<32,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,97,103,44,32,85,115,101,114,68,101,102,105,110,101,100,84,97,103,125>>]}]},{dd,[],[{p,[],[<<82,101,112,108,97,99,101,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<84,97,103>>]},<<32,119,105,116,104,32>>,{code,[],[<<85,115,101,114,68,101,102,105,110,101,100,84,97,103>>]},<<32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,111,110,105,116,111,114,32,109,101,115,115,97,103,101>>]},<<32,100,101,108,105,118,101,114,101,100,32,119,104,101,110,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,116,114,105,103,103,101,114,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,109,111,110,105,116,111,114,105,110,103,32,97,32,112,114,111,99,101,115,115,44,32,116,104,101,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,116,97,103,32,105,110,32,116,104,101,32,100,111,119,110,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,114,101,112,108,97,99,101,100,32,98,121,32>>,{code,[],[<<85,115,101,114,68,101,102,105,110,101,100,84,97,103>>]},<<46>>]},{p,[],[<<65,110,32,101,120,97,109,112,108,101,32,111,102,32,104,111,119,32,116,104,101,32>>,{code,[],[<<123,116,97,103,44,32,85,115,101,114,68,101,102,105,110,101,100,84,97,103,125>>]},<<32,111,112,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,32,111,114,100,101,114,32,116,111,32,101,110,97,98,108,101,32,116,104,101,32,110,101,119,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,112,114,111,99,101,115,115,101,115,35,114,101,99,101,105,118,105,110,103,45,109,101,115,115,97,103,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,101,108,101,99,116,105,118,101,32,114,101,99,101,105,118,101,32,111,112,116,105,109,105,122,97,116,105,111,110>>]},<<44,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,79,84,80,32,50,52,44,32,119,104,101,110,32,109,97,107,105,110,103,32,109,117,108,116,105,112,108,101,32,114,101,113,117,101,115,116,115,32,116,111,32,100,105,102,102,101,114,101,110,116,32,115,101,114,118,101,114,115,58>>]},{pre,[],[{code,[],[<<115,101,114,118,101,114,40,41,32,45,62,10,32,32,32,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,123,114,101,113,117,101,115,116,44,32,70,114,111,109,44,32,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,82,101,115,117,108,116,32,61,32,112,101,114,102,111,114,109,95,114,101,113,117,101,115,116,40,82,101,113,117,101,115,116,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,70,114,111,109,32,33,32,123,114,101,112,108,121,44,32,115,101,108,102,40,41,44,32,82,101,113,73,100,44,32,82,101,115,117,108,116,125,10,32,32,32,32,101,110,100,44,10,32,32,32,32,115,101,114,118,101,114,40,41,46,10,10,99,108,105,101,110,116,40,83,101,114,118,101,114,80,105,100,115,44,32,82,101,113,117,101,115,116,41,32,119,104,101,110,32,105,115,95,108,105,115,116,40,83,101,114,118,101,114,80,105,100,115,41,32,45,62,10,32,32,32,32,82,101,113,73,100,32,61,32,109,97,107,101,95,114,101,102,40,41,44,10,32,32,32,32,108,105,115,116,115,58,102,111,114,101,97,99,104,40,102,117,110,32,40,83,101,114,118,101,114,80,105,100,41,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,95,32,61,32,109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,83,101,114,118,101,114,80,105,100,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,91,123,116,97,103,44,32,123,39,68,79,87,78,39,44,32,82,101,113,73,100,125,125,93,41,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,83,101,114,118,101,114,80,105,100,32,33,32,123,114,101,113,117,101,115,116,44,32,115,101,108,102,40,41,44,32,82,101,113,73,100,44,32,82,101,113,117,101,115,116,125,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,110,100,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,83,101,114,118,101,114,80,105,100,115,41,44,10,32,32,32,32,114,101,99,101,105,118,101,95,114,101,112,108,105,101,115,40,82,101,113,73,100,44,32,108,101,110,103,116,104,40,83,101,114,118,101,114,80,105,100,115,41,44,32,91,93,41,46,10,10,114,101,99,101,105,118,101,95,114,101,112,108,105,101,115,40,95,82,101,113,73,100,44,32,48,44,32,65,99,99,41,32,45,62,10,32,32,32,32,65,99,99,59,10,114,101,99,101,105,118,101,95,114,101,112,108,105,101,115,40,82,101,113,73,100,44,32,78,44,32,65,99,99,41,32,45,62,10,32,32,32,32,37,37,32,84,104,101,32,99,111,109,112,105,108,101,114,32,119,105,108,108,32,100,101,116,101,99,116,32,116,104,97,116,32,119,101,32,109,97,116,99,104,32,111,110,32,116,104,101,32,39,82,101,113,73,100,39,10,32,32,32,32,37,37,32,114,101,102,101,114,101,110,99,101,32,105,110,32,97,108,108,32,99,108,97,117,115,101,115,44,32,97,110,100,32,119,105,108,108,32,101,110,97,98,108,101,32,116,104,101,32,115,101,108,101,99,116,105,118,101,10,32,32,32,32,37,37,32,114,101,99,101,105,118,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,119,104,105,99,104,32,109,97,107,101,115,32,116,104,101,32,114,101,99,101,105,118,101,32,97,98,108,101,32,116,111,10,32,32,32,32,37,37,32,115,107,105,112,32,112,97,115,116,32,97,108,108,32,109,101,115,115,97,103,101,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,116,10,32,32,32,32,37,37,32,116,104,101,32,116,105,109,101,32,119,104,101,110,32,116,104,101,32,39,82,101,113,73,100,39,32,114,101,102,101,114,101,110,99,101,32,119,97,115,32,99,114,101,97,116,101,100,46,46,46,10,32,32,32,32,82,101,115,32,61,32,114,101,99,101,105,118,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,114,101,112,108,121,44,32,83,101,114,118,101,114,80,105,100,44,32,82,101,113,73,100,44,32,82,101,115,117,108,116,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,37,37,32,72,101,114,101,32,119,101,32,116,121,112,105,99,97,108,108,121,32,119,111,117,108,100,32,104,97,118,101,32,100,101,97,99,116,105,118,97,116,101,100,32,116,104,101,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,37,37,32,109,111,110,105,116,111,114,32,98,121,32,97,32,99,97,108,108,32,116,111,32,100,101,109,111,110,105,116,111,114,40,77,111,110,44,32,91,102,108,117,115,104,93,41,32,98,117,116,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,37,37,32,119,101,32,105,103,110,111,114,101,32,116,104,105,115,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,102,111,114,32,115,105,109,112,108,105,99,105,116,121,46,46,46,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,111,107,44,32,83,101,114,118,101,114,80,105,100,44,32,82,101,115,117,108,116,125,59,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,123,39,68,79,87,78,39,44,32,82,101,113,73,100,125,44,32,95,77,111,110,44,32,112,114,111,99,101,115,115,44,32,83,101,114,118,101,114,80,105,100,44,32,69,120,105,116,82,101,97,115,111,110,125,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,123,101,114,114,111,114,44,32,83,101,114,118,101,114,80,105,100,44,32,69,120,105,116,82,101,97,115,111,110,125,10,32,32,32,32,32,32,32,32,32,32,101,110,100,44,10,32,32,32,32,114,101,99,101,105,118,101,95,114,101,112,108,105,101,115,40,82,101,113,73,100,44,32,78,45,49,44,32,91,82,101,115,32,124,32,65,99,99,93,41,46,10,9,32,32,32,32>>]}]},{p,[],[<<73,110,32,111,114,100,101,114,32,102,111,114,32,116,104,105,115,32,101,120,97,109,112,108,101,32,116,111,32,119,111,114,107,32,97,115,32,105,110,116,101,110,100,101,100,44,32,116,104,101,32,99,108,105,101,110,116,32,109,117,115,116,32,98,101,32,101,120,101,99,117,116,105,110,103,32,111,110,32,97,116,32,108,101,97,115,116,32,97,110,32,79,84,80,32,50,52,32,115,121,115,116,101,109,44,32,98,117,116,32,116,104,101,32,115,101,114,118,101,114,115,32,109,97,121,32,101,120,101,99,117,116,101,32,111,110,32,111,108,100,101,114,32,115,121,115,116,101,109,115,46>>]}]}]}]},#{signature => [{attribute,{1705,2},spec,{{monitor,3},[{type,{1706,7},bounded_fun,[{type,{1706,7},'fun',[{type,{1706,7},product,[{atom,{1706,8},process},{user_type,{1706,17},monitor_process_identifier,[]},{type,{1706,47},list,[{user_type,{1706,48},monitor_option,[]}]}]},{var,{1706,70},'MonitorRef'}]},[{type,{1707,9},constraint,[{atom,{1707,9},is_subtype},[{var,{1707,9},'MonitorRef'},{type,{1707,23},reference,[]}]]}]]},{type,{1708,7},bounded_fun,[{type,{1708,7},'fun',[{type,{1708,7},product,[{atom,{1708,8},port},{user_type,{1708,14},monitor_port_identifier,[]},{type,{1708,41},list,[{user_type,{1708,42},monitor_option,[]}]}]},{var,{1708,64},'MonitorRef'}]},[{type,{1709,9},constraint,[{atom,{1709,9},is_subtype},[{var,{1709,9},'MonitorRef'},{type,{1709,23},reference,[]}]]}]]},{type,{1710,7},bounded_fun,[{type,{1710,7},'fun',[{type,{1710,7},product,[{atom,{1710,8},time_offset},{atom,{1710,21},clock_service},{type,{1710,36},list,[{user_type,{1710,37},monitor_option,[]}]}]},{var,{1710,59},'MonitorRef'}]},[{type,{1711,9},constraint,[{atom,{1711,9},is_subtype},[{var,{1711,9},'MonitorRef'},{type,{1711,23},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,55,50,52>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,monitor_node,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1717}],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<77,111,110,105,116,111,114,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,110,46,32,73,102,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,109,111,110,105,116,111,114,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,46>>]},{p,[],[<<77,97,107,105,110,103,32,115,101,118,101,114,97,108,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,40,78,111,100,101,44,32,116,114,117,101,41>>]},<<32,102,111,114,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,59,32,105,116,32,114,101,115,117,108,116,115,32,105,110,32,97,115,32,109,97,110,121,32,105,110,100,101,112,101,110,100,101,110,116,32,109,111,110,105,116,111,114,105,110,103,32,105,110,115,116,97,110,99,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,102,97,105,108,115,32,111,114,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,110,111,100,101,100,111,119,110,44,32,78,111,100,101,125>>]},<<32,105,115,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,109,97,100,101,32,116,119,111,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,40,78,111,100,101,44,32,116,114,117,101,41>>]},<<32,97,110,100,32>>,{code,[],[<<78,111,100,101>>]},<<32,116,101,114,109,105,110,97,116,101,115,44,32,116,119,111,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,114,101,32,105,115,32,110,111,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32>>,{code,[],[<<78,111,100,101>>]},<<44,32,97,110,32,97,116,116,101,109,112,116,32,105,115,32,109,97,100,101,32,116,111,32,99,114,101,97,116,101,32,111,110,101,46,32,73,102,32,116,104,105,115,32,102,97,105,108,115,44,32,97,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,100,101,108,105,118,101,114,101,100,46>>]},{p,[],[<<84,104,101,32,100,101,108,105,118,101,114,121,32,111,102,32,116,104,101,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,115,105,103,110,97,108,32,105,115,32,110,111,116,32,111,114,100,101,114,101,100,32,119,105,116,104,32,114,101,115,112,101,99,116,32,116,111,32,111,116,104,101,114,32,108,105,110,107,32,111,114,32,109,111,110,105,116,111,114,32,115,105,103,110,97,108,115,32,102,114,111,109,32,116,104,101,32,110,111,100,101,32,116,104,97,116,32,103,111,101,115,32,100,111,119,110,46,32,73,102,32,121,111,117,32,110,101,101,100,32,97,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,97,108,108,32,115,105,103,110,97,108,115,32,102,114,111,109,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,32,104,97,115,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,101,32>>,{code,[],[<<110,111,100,101,100,111,119,110>>]},<<32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,44,32,121,111,117,32,115,104,111,117,108,100,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,109,111,110,105,116,111,114,95,110,111,100,101,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,109,111,110,105,116,111,114,95,110,111,100,101,115,47,49>>]}]},<<46>>]},{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,104,114,111,117,103,104,32,104,105,100,100,101,110,32,99,111,110,110,101,99,116,105,111,110,115,32,99,97,110,32,98,101,32,109,111,110,105,116,111,114,101,100,32,97,115,32,97,110,121,32,111,116,104,101,114,32,110,111,100,101,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,116,97,108,105,118,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]},#{signature => [{attribute,{1717,2},spec,{{monitor_node,2},[{type,{1717,19},bounded_fun,[{type,{1717,19},'fun',[{type,{1717,19},product,[{var,{1717,20},'Node'},{var,{1717,26},'Flag'}]},{atom,{1717,35},true}]},[{type,{1718,7},constraint,[{atom,{1718,7},is_subtype},[{var,{1718,7},'Node'},{type,{1718,15},node,[]}]]},{type,{1719,7},constraint,[{atom,{1719,7},is_subtype},[{var,{1719,7},'Flag'},{type,{1719,15},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,56,57,48>>}},{{function,monitor_node,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1724}],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,51>>],#{<<101,110>> => [{p,[],[<<66,101,104,97,118,101,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,95,110,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,95,110,111,100,101,47,50>>]}]},<<32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,97,108,108,111,119,115,32,97,110,32,101,120,116,114,97,32,111,112,116,105,111,110,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,44,32,110,97,109,101,108,121,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<46,32,84,104,105,115,32,111,112,116,105,111,110,32,97,108,108,111,119,115,32,116,104,101,32,66,73,70,32,116,111,32,119,97,105,116,32,116,104,101,32,110,111,114,109,97,108,32,110,101,116,119,111,114,107,32,99,111,110,110,101,99,116,105,111,110,32,116,105,109,101,45,111,117,116,32,102,111,114,32,116,104,101,32>>,{em,[],[<<109,111,110,105,116,111,114,101,100,32,110,111,100,101>>]},<<32,116,111,32,99,111,110,110,101,99,116,32,105,116,115,101,108,102,44,32,101,118,101,110,32,105,102,32,105,116,32,99,97,110,110,111,116,32,98,101,32,97,99,116,105,118,101,108,121,32,99,111,110,110,101,99,116,101,100,32,102,114,111,109,32,116,104,105,115,32,110,111,100,101,32,40,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,98,108,111,99,107,101,100,41,46,32,84,104,101,32,115,116,97,116,101,32,119,104,101,114,101,32,116,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,99,97,110,32,111,110,108,121,32,98,101,32,97,99,104,105,101,118,101,100,32,98,121,32,117,115,105,110,103,32,116,104,101,32,75,101,114,110,101,108,32,111,112,116,105,111,110,32>>,{code,[],[<<100,105,115,116,95,97,117,116,111,95,99,111,110,110,101,99,116,32,111,110,99,101>>]},<<46,32,73,102,32,116,104,97,116,32,111,112,116,105,111,110,32,105,115,32,110,111,116,32,117,115,101,100,44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<97,108,108,111,119,95,112,97,115,115,105,118,101,95,99,111,110,110,101,99,116>>]},<<32,105,115,32,117,115,101,100,32,105,110,116,101,114,110,97,108,108,121,32,97,110,100,32,105,115,32,115,101,108,100,111,109,32,110,101,101,100,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,115,32,119,104,101,114,101,32,116,104,101,32,110,101,116,119,111,114,107,32,116,111,112,111,108,111,103,121,32,97,110,100,32,116,104,101,32,75,101,114,110,101,108,32,111,112,116,105,111,110,115,32,105,110,32,101,102,102,101,99,116,32,97,114,101,32,107,110,111,119,110,32,105,110,32,97,100,118,97,110,99,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,32,111,114,32,116,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,105,115,32,109,97,108,102,111,114,109,101,100,46>>]}]},#{signature => [{attribute,{1724,2},spec,{{erlang,monitor_node,3},[{type,{1724,26},bounded_fun,[{type,{1724,26},'fun',[{type,{1724,26},product,[{var,{1724,27},'Node'},{var,{1724,33},'Flag'},{var,{1724,39},'Options'}]},{atom,{1724,51},true}]},[{type,{1725,7},constraint,[{atom,{1725,7},is_subtype},[{var,{1725,7},'Node'},{type,{1725,15},node,[]}]]},{type,{1726,7},constraint,[{atom,{1726,7},is_subtype},[{var,{1726,7},'Flag'},{type,{1726,15},boolean,[]}]]},{type,{1727,7},constraint,[{atom,{1727,7},is_subtype},[{var,{1727,7},'Options'},{type,{1727,18},list,[{var,{1727,19},'Option'}]}]]},{type,{1728,7},constraint,[{atom,{1728,7},is_subtype},[{var,{1728,7},'Option'},{atom,{1728,17},allow_passive_connect}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,50,48>>}},{{function,monotonic_time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1826}],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46,32,84,104,105,115,32,105,115,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,115,105,110,99,101,32,115,111,109,101,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,32,105,110,32,116,105,109,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,105,115,32,97,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,116,105,109,101,44,32,98,117,116,32>>,{em,[],[<<110,111,116>>]},<<32,97,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,116,114,105,99,116,108,121,95,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32,99,111,110,115,101,99,117,116,105,118,101,32,99,97,108,108,115,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>]},<<32,99,97,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<68,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,32,119,105,108,108,32,117,115,101,32,100,105,102,102,101,114,101,110,116,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,115,32,105,110,32,116,105,109,101,32,97,115,32,98,97,115,101,32,102,111,114,32,116,104,101,105,114,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,99,108,111,99,107,115,46,32,84,104,97,116,32,105,115,44,32,105,116,32,105,115,32>>,{em,[],[<<112,111,105,110,116,108,101,115,115>>]},<<32,99,111,109,112,97,114,105,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,115,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,46,32,68,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,115,32,99,97,110,32,97,108,115,111,32,112,108,97,99,101,32,116,104,105,115,32,117,110,115,112,101,99,105,102,105,101,100,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,100,105,102,102,101,114,101,110,116,32,114,101,108,97,116,105,118,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,46,32,73,116,32,99,97,110,32,98,101,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,97,32,110,101,103,97,116,105,118,101,32,118,97,108,117,101,41,44,32,116,104,101,32,112,97,115,116,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,118,97,108,117,101,41,44,32,111,114,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,32,40,116,105,109,101,32,97,116,32,115,116,97,114,116,32,105,115,32,122,101,114,111,41,46,32,84,104,101,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,97,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,116,97,114,116,95,116,105,109,101,41>>]}]},<<46>>]}]}]},#{signature => [{attribute,{1826,2},spec,{{erlang,monotonic_time,0},[{type,{1826,28},'fun',[{type,{1826,28},product,[]},{type,{1826,34},integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,52,54>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,monotonic_time,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1831}],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<83,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<44,32,104,111,119,101,118,101,114,32,111,112,116,105,109,105,122,101,100,32,102,111,114,32,99,111,109,109,111,110,108,121,32,117,115,101,100,32>>,{code,[],[<<85,110,105,116>>]},<<115,46>>]}]},#{signature => [{attribute,{1831,2},spec,{{erlang,monotonic_time,1},[{type,{1831,28},bounded_fun,[{type,{1831,28},'fun',[{type,{1831,28},product,[{var,{1831,29},'Unit'}]},{type,{1831,38},integer,[]}]},[{type,{1832,7},constraint,[{atom,{1832,7},is_subtype},[{var,{1832,7},'Unit'},{user_type,{1832,15},time_unit,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,56,48>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,nif_error,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1734}],[<<110,105,102,95,101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,101,120,97,99,116,108,121,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,49>>]}]},<<44,32,98,117,116,32,68,105,97,108,121,122,101,114,32,116,104,105,110,107,115,32,116,104,97,116,32,116,104,105,115,32,66,73,70,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32,97,114,98,105,116,114,97,114,121,32,116,101,114,109,46,32,87,104,101,110,32,117,115,101,100,32,105,110,32,97,32,115,116,117,98,32,102,117,110,99,116,105,111,110,32,102,111,114,32,97,32,78,73,70,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,110,111,116,32,108,111,97,100,101,100,44,32,68,105,97,108,121,122,101,114,32,100,111,101,115,32,110,111,116,32,103,101,110,101,114,97,116,101,32,102,97,108,115,101,32,119,97,114,110,105,110,103,115,46>>]}]},#{signature => [{attribute,{1734,2},spec,{{erlang,nif_error,1},[{type,{1734,23},bounded_fun,[{type,{1734,23},'fun',[{type,{1734,23},product,[{var,{1734,24},'Reason'}]},{type,{1734,35},no_return,[]}]},[{type,{1735,7},constraint,[{atom,{1735,7},is_subtype},[{var,{1735,7},'Reason'},{type,{1735,17},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,52,57,57,56>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,nif_error,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1741}],[<<110,105,102,95,101,114,114,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,101,120,97,99,116,108,121,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,114,114,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,114,111,114,47,50>>]}]},<<44,32,98,117,116,32,68,105,97,108,121,122,101,114,32,116,104,105,110,107,115,32,116,104,97,116,32,116,104,105,115,32,66,73,70,32,119,105,108,108,32,114,101,116,117,114,110,32,97,110,32,97,114,98,105,116,114,97,114,121,32,116,101,114,109,46,32,87,104,101,110,32,117,115,101,100,32,105,110,32,97,32,115,116,117,98,32,102,117,110,99,116,105,111,110,32,102,111,114,32,97,32,78,73,70,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,116,104,101,32,78,73,70,32,108,105,98,114,97,114,121,32,105,115,32,110,111,116,32,108,111,97,100,101,100,44,32,68,105,97,108,121,122,101,114,32,100,111,101,115,32,110,111,116,32,103,101,110,101,114,97,116,101,32,102,97,108,115,101,32,119,97,114,110,105,110,103,115,46>>]}]},#{signature => [{attribute,{1741,2},spec,{{erlang,nif_error,2},[{type,{1741,23},bounded_fun,[{type,{1741,23},'fun',[{type,{1741,23},product,[{var,{1741,24},'Reason'},{var,{1741,32},'Args'}]},{type,{1741,41},no_return,[]}]},[{type,{1742,7},constraint,[{atom,{1742,7},is_subtype},[{var,{1742,7},'Reason'},{type,{1742,17},term,[]}]]},{type,{1743,7},constraint,[{atom,{1743,7},is_subtype},[{var,{1743,7},'Args'},{type,{1743,15},list,[{type,{1743,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,49,49>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,node,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1749}],[<<110,111,100,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,73,102,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<110,111,110,111,100,101,64,110,111,104,111,115,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1749,2},spec,{{node,0},[{type,{1749,11},bounded_fun,[{type,{1749,11},'fun',[{type,{1749,11},product,[]},{var,{1749,17},'Node'}]},[{type,{1750,7},constraint,[{atom,{1750,7},is_subtype},[{var,{1750,7},'Node'},{type,{1750,15},node,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,50,52>>}},{{function,node,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1756}],[<<110,111,100,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,111,100,101,32,119,104,101,114,101,32>>,{code,[],[<<65,114,103>>]},<<32,111,114,105,103,105,110,97,116,101,115,46,32>>,{code,[],[<<65,114,103>>]},<<32,99,97,110,32,98,101,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,97,32,112,111,114,116,46,32,73,102,32>>,{code,[],[<<65,114,103>>]},<<32,111,114,105,103,105,110,97,116,101,115,32,102,114,111,109,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,110,100,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<110,111,110,111,100,101,64,110,111,104,111,115,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{1756,2},spec,{{node,1},[{type,{1756,11},bounded_fun,[{type,{1756,11},'fun',[{type,{1756,11},product,[{var,{1756,12},'Arg'}]},{var,{1756,20},'Node'}]},[{type,{1757,7},constraint,[{atom,{1757,7},is_subtype},[{var,{1757,7},'Arg'},{type,{1757,14},union,[{type,{1757,14},pid,[]},{type,{1757,22},port,[]},{type,{1757,31},reference,[]}]}]]},{type,{1758,7},constraint,[{atom,{1758,7},is_subtype},[{var,{1758,7},'Node'},{type,{1758,15},node,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,51,52>>}},{{function,nodes,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3688}],[<<110,111,100,101,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,108,108,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,110,111,114,109,97,108,32,99,111,110,110,101,99,116,105,111,110,115,32,40,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100,35,104,105,100,100,101,110,45,110,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<104,105,100,100,101,110,32,110,111,100,101,115>>]},<<32,97,114,101,32,110,111,116,32,108,105,115,116,101,100,41,46,32,83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,100,101,115,95,118,105,115,105,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,111,100,101,115,40,118,105,115,105,98,108,101,41>>]},<<46>>]}]},#{signature => [{attribute,{3688,2},spec,{{nodes,0},[{type,{3688,12},bounded_fun,[{type,{3688,12},'fun',[{type,{3688,12},product,[]},{var,{3688,18},'Nodes'}]},[{type,{3689,7},constraint,[{atom,{3689,7},is_subtype},[{var,{3689,7},'Nodes'},{type,{3689,16},list,[{type,{3689,17},node,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,52,55>>}},{{function,nodes,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3693}],[<<110,111,100,101,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,110,111,100,101,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,97,114,103,117,109,101,110,116,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,114,101,115,117,108,116,44,32,119,104,101,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,44,32,105,115,32,116,104,101,32,108,105,115,116,32,111,102,32,110,111,100,101,115,32,115,97,116,105,115,102,121,105,110,103,32,116,104,101,32,100,105,115,106,117,110,99,116,105,111,110,40,115,41,32,111,102,32,116,104,101,32,108,105,115,116,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[{code,[],[<<78,111,100,101,84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{a,[{id,<<110,111,100,101,115,95,118,105,115,105,98,108,101>>}],[]},{code,[],[<<118,105,115,105,98,108,101>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,110,111,114,109,97,108,32,99,111,110,110,101,99,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<104,105,100,100,101,110>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,32,116,104,114,111,117,103,104,32,104,105,100,100,101,110,32,99,111,110,110,101,99,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<99,111,110,110,101,99,116,101,100>>]}]},{dd,[],[{p,[],[<<65,108,108,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,105,115,32,110,111,100,101,46>>]}]},{dt,[],[{code,[],[<<116,104,105,115>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,110,111,100,101,46>>]}]},{dt,[],[{code,[],[<<107,110,111,119,110>>]}]},{dd,[],[{p,[],[<<78,111,100,101,115,32,116,104,97,116,32,97,114,101,32,107,110,111,119,110,32,116,111,32,116,104,105,115,32,110,111,100,101,46,32,84,104,97,116,32,105,115,44,32,99,111,110,110,101,99,116,101,100,32,110,111,100,101,115,32,97,110,100,32,110,111,100,101,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,32,108,111,99,97,116,101,100,32,111,110,32,116,104,105,115,32,110,111,100,101,46,32,84,104,101,32,115,101,116,32,111,102,32,107,110,111,119,110,32,110,111,100,101,115,32,105,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,99,97,110,32,98,101,32,100,101,108,97,121,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99,41>>]}]},<<46>>]}]}]},{p,[],[<<83,111,109,101,32,101,113,117,97,108,105,116,105,101,115,58,32>>,{code,[],[<<91,110,111,100,101,40,41,93,32,61,32,110,111,100,101,115,40,116,104,105,115,41>>]},<<44,32>>,{code,[],[<<110,111,100,101,115,40,99,111,110,110,101,99,116,101,100,41,32,61,32,110,111,100,101,115,40,91,118,105,115,105,98,108,101,44,32,104,105,100,100,101,110,93,41>>]},<<44,32,97,110,100,32>>,{code,[],[<<110,111,100,101,115,40,41,32,61,32,110,111,100,101,115,40,118,105,115,105,98,108,101,41>>]},<<46>>]}]},#{signature => [{attribute,{3693,2},spec,{{nodes,1},[{type,{3693,12},bounded_fun,[{type,{3693,12},'fun',[{type,{3693,12},product,[{var,{3693,13},'Arg'}]},{var,{3693,21},'Nodes'}]},[{type,{3694,7},constraint,[{atom,{3694,7},is_subtype},[{var,{3694,7},'Arg'},{type,{3694,14},union,[{var,{3694,14},'NodeType'},{type,{3694,25},list,[{var,{3694,26},'NodeType'}]}]}]]},{type,{3695,7},constraint,[{atom,{3695,7},is_subtype},[{var,{3695,7},'NodeType'},{type,{3695,19},union,[{atom,{3695,19},visible},{atom,{3695,29},hidden},{atom,{3695,38},connected},{atom,{3695,50},this},{atom,{3695,57},known}]}]]},{type,{3696,7},constraint,[{atom,{3696,7},is_subtype},[{var,{3696,7},'Nodes'},{type,{3696,16},list,[{type,{3696,17},node,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,48,53,57>>}},{{function,nodes,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3700}],[<<110,111,100,101,115,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<78,111,100,101,73,110,102,111>>]},<<32,116,117,112,108,101,115,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,110,111,100,101,32,110,97,109,101,46,32,78,111,100,101,115,32,116,111,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,108,105,115,116,32,97,114,101,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,116,104,101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<65,114,103>>]},<<32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,100,101,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,111,100,101,115,40,65,114,103,41>>]}]},<<46,32,84,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<78,111,100,101,73,110,102,111>>]},<<32,116,117,112,108,101,115,32,105,115,32,97,32,109,97,112,32,99,111,110,116,97,105,110,105,110,103,32,102,117,114,116,104,101,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,112,114,101,115,101,110,116,32,105,110,32,116,104,105,115,32,109,97,112,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,116,104,101,32>>,{code,[],[<<73,110,102,111,79,112,116,115>>]},<<32,109,97,112,32,112,97,115,115,101,100,32,97,115,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,46,32,67,117,114,114,101,110,116,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,115,115,111,99,105,97,116,105,111,110,115,32,97,114,101,32,97,108,108,111,119,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<73,110,102,111,79,112,116,115>>]},<<32,109,97,112,58>>]},{dl,[],[{dt,[],[{code,[],[<<99,111,110,110,101,99,116,105,111,110,95,105,100,32,61,62,32,98,111,111,108,101,97,110,40,41>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,97,115,115,111,99,105,97,116,105,111,110,32,101,113,117,97,108,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,109,97,112,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,115,117,108,116,32,119,105,108,108,32,99,111,110,116,97,105,110,32,116,104,101,32,107,101,121,32>>,{code,[],[<<99,111,110,110,101,99,116,105,111,110,95,105,100>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<67,111,110,110,101,99,116,105,111,110,73,100>>]},<<46,32,73,102,32>>,{code,[],[<<67,111,110,110,101,99,116,105,111,110,73,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,110,111,100,101,32,119,104,105,99,104,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,44,32,111,114,32,105,115,32,116,104,101,32,110,111,100,101,32,119,104,105,99,104,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32,73,102,32>>,{code,[],[<<67,111,110,110,101,99,116,105,111,110,73,100>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,101,32,110,111,100,101,32,105,115,32,99,117,114,114,101,110,116,108,121,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,110,111,100,101,32,119,104,105,99,104,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46>>]},{p,[],[{a,[{id,<<99,111,110,110,101,99,116,105,111,110,95,105,100>>}],[]},<<84,104,101,32,105,110,116,101,103,101,114,32,99,111,110,110,101,99,116,105,111,110,32,105,100,101,110,116,105,102,105,101,114,32,118,97,108,117,101,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,97,32,110,111,100,101,32,110,97,109,101,32,105,100,101,110,116,105,102,105,101,115,32,97,32,115,112,101,99,105,102,105,99,32,99,111,110,110,101,99,116,105,111,110,32,105,110,115,116,97,110,99,101,32,116,111,32,116,104,101,32,110,111,100,101,32,119,105,116,104,32,116,104,97,116,32,110,111,100,101,32,110,97,109,101,46,32,84,104,101,32,99,111,110,110,101,99,116,105,111,110,32,105,100,101,110,116,105,102,105,101,114,32,118,97,108,117,101,32,105,115,32,110,111,100,101,32,108,111,99,97,108,46,32,84,104,97,116,32,105,115,44,32,111,110,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,105,100,101,110,116,105,102,105,101,114,32,119,105,108,108,32>>,{i,[],[<<110,111,116>>]},<<32,98,101,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,46,32,73,102,32,97,32,99,111,110,110,101,99,116,105,111,110,32,105,115,32,116,97,107,101,110,32,100,111,119,110,32,97,110,100,32,116,104,101,110,32,116,97,107,101,110,32,117,112,32,97,103,97,105,110,44,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,105,100,101,110,116,105,102,105,101,114,32,118,97,108,117,101,32,119,105,108,108,32,99,104,97,110,103,101,32,102,111,114,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,97,116,32,110,111,100,101,46,32,84,104,101,32,97,109,111,117,110,116,32,111,102,32,118,97,108,117,101,115,32,102,111,114,32,99,111,110,110,101,99,116,105,111,110,32,105,100,101,110,116,105,102,105,101,114,115,32,97,114,101,32,108,105,109,105,116,101,100,44,32,115,111,32,105,116,32,105,115,32,112,111,115,115,105,98,108,101,32,116,111,32,115,101,101,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,102,111,114,32,100,105,102,102,101,114,101,110,116,32,105,110,115,116,97,110,99,101,115,44,32,98,117,116,32,113,117,105,116,101,32,117,110,108,105,107,101,108,121,46,32,73,116,32,105,115,32,117,110,100,101,102,105,110,101,100,32,104,111,119,32,116,104,101,32,118,97,108,117,101,32,99,104,97,110,103,101,32,98,101,116,119,101,101,110,32,116,119,111,32,99,111,110,115,101,99,117,116,105,118,101,32,99,111,110,110,101,99,116,105,111,110,32,105,110,115,116,97,110,99,101,115,46>>]}]},{dt,[],[{code,[],[<<110,111,100,101,95,116,121,112,101,32,61,62,32,98,111,111,108,101,97,110,40,41>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,97,115,115,111,99,105,97,116,105,111,110,32,101,113,117,97,108,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,109,97,112,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,115,117,108,116,32,119,105,108,108,32,99,111,110,116,97,105,110,32,116,104,101,32,107,101,121,32>>,{code,[],[<<110,111,100,101,95,116,121,112,101>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<78,111,100,101,84,121,112,101,73,110,102,111>>]},<<46,32,67,117,114,114,101,110,116,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,110,111,100,101,32,116,121,112,101,115,32,101,120,105,115,116,58>>]},{dl,[],[{dt,[],[{code,[],[<<118,105,115,105,98,108,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,111,100,101,32,105,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,110,111,100,101,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,116,104,114,111,117,103,104,32,97,110,32,111,114,100,105,110,97,114,121,32,118,105,115,105,98,108,101,32,99,111,110,110,101,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,119,111,117,108,100,32,97,112,112,101,97,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,100,101,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,111,100,101,115,47,48>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<104,105,100,100,101,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,111,100,101,32,105,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,110,111,100,101,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,116,104,114,111,117,103,104,32,97,32,104,105,100,100,101,110,32,99,111,110,110,101,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,119,111,117,108,100,32>>,{i,[],[<<110,111,116>>]},<<32,97,112,112,101,97,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,100,101,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,111,100,101,115,47,48>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<116,104,105,115>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,110,111,100,101,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<107,110,111,119,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,99,111,110,110,101,99,116,101,100,32,98,117,116,32,107,110,111,119,110,32,116,111,32,116,104,101,32,110,111,100,101,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]}]}]}]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[{type,<<101,114,108>>}],[<<40,97,64,108,111,99,97,108,104,111,115,116,41,49,62,32,110,111,100,101,115,40,91,116,104,105,115,44,32,99,111,110,110,101,99,116,101,100,93,44,32,35,123,99,111,110,110,101,99,116,105,111,110,95,105,100,61,62,116,114,117,101,44,32,110,111,100,101,95,116,121,112,101,61,62,116,114,117,101,125,41,46,32,10,91,123,99,64,108,111,99,97,108,104,111,115,116,44,35,123,99,111,110,110,101,99,116,105,111,110,95,105,100,32,61,62,32,49,51,56,57,50,49,48,56,44,110,111,100,101,95,116,121,112,101,32,61,62,32,104,105,100,100,101,110,125,125,44,10,32,123,98,64,108,111,99,97,108,104,111,115,116,44,35,123,99,111,110,110,101,99,116,105,111,110,95,105,100,32,61,62,32,51,48,54,55,53,53,51,44,110,111,100,101,95,116,121,112,101,32,61,62,32,118,105,115,105,98,108,101,125,125,44,10,32,123,97,64,108,111,99,97,108,104,111,115,116,44,35,123,99,111,110,110,101,99,116,105,111,110,95,105,100,32,61,62,32,117,110,100,101,102,105,110,101,100,44,110,111,100,101,95,116,121,112,101,32,61,62,32,116,104,105,115,125,125,93,10,40,97,64,108,111,99,97,108,104,111,115,116,41,50,62,32,10,32,32,32,32,32,32,32,32>>]}]}]},#{signature => [{attribute,{3700,2},spec,{{nodes,2},[{type,{3700,12},bounded_fun,[{type,{3700,12},'fun',[{type,{3700,12},product,[{var,{3700,13},'Arg'},{var,{3700,18},'InfoOpts'}]},{type,{3700,31},list,[{var,{3700,32},'NodeInfo'}]}]},[{type,{3701,7},constraint,[{atom,{3701,7},is_subtype},[{var,{3701,7},'NodeType'},{type,{3701,19},union,[{atom,{3701,19},visible},{atom,{3701,29},hidden},{atom,{3701,38},connected},{atom,{3701,50},this},{atom,{3701,57},known}]}]]},{type,{3702,7},constraint,[{atom,{3702,7},is_subtype},[{var,{3702,7},'Arg'},{type,{3702,14},union,[{var,{3702,14},'NodeType'},{type,{3702,25},list,[{var,{3702,26},'NodeType'}]}]}]]},{type,{3703,7},constraint,[{atom,{3703,7},is_subtype},[{var,{3703,7},'InfoOpts'},{type,{3703,19},map,[{type,{3703,35},map_field_assoc,[{atom,{3703,21},connection_id},{type,{3703,38},boolean,[]}]},{type,{3704,31},map_field_assoc,[{atom,{3704,21},node_type},{type,{3704,34},boolean,[]}]}]}]]},{type,{3705,7},constraint,[{atom,{3705,7},is_subtype},[{var,{3705,7},'NodeTypeInfo'},{type,{3705,23},union,[{atom,{3705,23},visible},{atom,{3705,33},hidden},{atom,{3705,42},this},{atom,{3705,49},known}]}]]},{type,{3706,7},constraint,[{atom,{3706,7},is_subtype},[{var,{3706,7},'ConnectionId'},{type,{3706,23},union,[{atom,{3706,23},undefined},{type,{3706,35},integer,[]}]}]]},{type,{3707,7},constraint,[{atom,{3707,7},is_subtype},[{var,{3707,7},'Info'},{type,{3707,15},map,[{type,{3707,31},map_field_assoc,[{atom,{3707,17},connection_id},{var,{3707,34},'ConnectionId'}]},{type,{3708,27},map_field_assoc,[{atom,{3708,17},node_type},{var,{3708,30},'NodeTypeInfo'}]}]}]]},{type,{3709,7},constraint,[{atom,{3709,7},is_subtype},[{var,{3709,7},'NodeInfo'},{type,{3709,19},tuple,[{type,{3709,20},node,[]},{var,{3709,28},'Info'}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,49,48,50>>,since => <<79,84,80,32,50,53,46,49>>}},{{function,now,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1763}],[<<110,111,119,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,105,109,101,115,116,97,109,112>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,68,111,32,110,111,116,32,117,115,101,32,105,116,46>>]}]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<84,105,109,101,32,97,110,100,32,84,105,109,101,32,67,111,114,114,101,99,116,105,111,110>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46,32,83,112,101,99,105,102,105,99,97,108,108,121,44,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,68,111,115,95,97,110,100,95,68,111,110,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,111,115,32,97,110,100,32,68,111,110,116,39,115>>]},<<32,100,101,115,99,114,105,98,101,115,32,119,104,97,116,32,116,111,32,117,115,101,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]},<<46>>]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,101,108,97,112,115,101,100,32,116,105,109,101,32,115,105,110,99,101,32,48,48,58,48,48,32,71,77,84,44,32,74,97,110,117,97,114,121,32,49,44,32,49,57,55,48,32,40,122,101,114,111,32,104,111,117,114,41,44,32,105,102,32,112,114,111,118,105,100,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,115,111,109,101,32,111,116,104,101,114,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,105,115,32,99,104,111,115,101,110,46,32,73,116,32,105,115,32,97,108,115,111,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,115,32,116,111,32,116,104,105,115,32,66,73,70,32,114,101,116,117,114,110,32,99,111,110,116,105,110,117,111,117,115,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,46,32,72,101,110,99,101,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,110,101,114,97,116,101,32,117,110,105,113,117,101,32,116,105,109,101,32,115,116,97,109,112,115,46,32,73,102,32,105,116,32,105,115,32,99,97,108,108,101,100,32,105,110,32,97,32,116,105,103,104,116,32,108,111,111,112,32,111,110,32,97,32,102,97,115,116,32,109,97,99,104,105,110,101,44,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,110,111,100,101,32,99,97,110,32,98,101,99,111,109,101,32,115,107,101,119,101,100,46>>]},{p,[],[<<67,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,116,111,32,99,104,101,99,107,32,116,104,101,32,108,111,99,97,108,32,116,105,109,101,32,111,102,32,100,97,121,32,105,102,32,116,104,101,32,116,105,109,101,45,122,111,110,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,102,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,32,105,115,32,112,114,111,112,101,114,108,121,32,99,111,110,102,105,103,117,114,101,100,46>>]}]},#{deprecated => <<101,114,108,97,110,103,58,110,111,119,47,48,32,105,115,32,100,101,112,114,101,99,97,116,101,100,59,32,115,101,101,32,116,104,101,32,34,84,105,109,101,32,97,110,100,32,84,105,109,101,32,67,111,114,114,101,99,116,105,111,110,32,105,110,32,69,114,108,97,110,103,34,32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32,69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101,32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110>>,signature => [{attribute,{1763,2},spec,{{now,0},[{type,{1763,10},bounded_fun,[{type,{1763,10},'fun',[{type,{1763,10},product,[]},{var,{1763,16},'Timestamp'}]},[{type,{1764,7},constraint,[{atom,{1764,7},is_subtype},[{var,{1764,7},'Timestamp'},{user_type,{1764,20},timestamp,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,49,56,55>>}},{{function,open_port,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2603}],[<<111,112,101,110,95,112,111,114,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,111,112,101,110,105,110,103,32,97,32,110,101,119,32,69,114,108,97,110,103,32,112,111,114,116,46,32,65,32,112,111,114,116,32,99,97,110,32,98,101,32,115,101,101,110,32,97,115,32,97,110,32,101,120,116,101,114,110,97,108,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<84,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32>>,{code,[],[<<99,100>>]},<<44,32>>,{code,[],[<<101,110,118>>]},<<44,32>>,{code,[],[<<97,114,103,115>>]},<<44,32,97,110,100,32>>,{code,[],[<<97,114,103,48>>]},<<32,97,114,101,32,115,117,98,106,101,99,116,32,116,111,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,116,114,97,110,115,108,97,116,105,111,110,32,105,102,32,116,104,101,32,115,121,115,116,101,109,32,105,115,32,114,117,110,110,105,110,103,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,46,32,84,111,32,97,118,111,105,100,32,116,114,97,110,115,108,97,116,105,111,110,32,111,114,32,116,111,32,102,111,114,99,101,44,32,102,111,114,32,101,120,97,109,112,108,101,32,85,84,70,45,56,44,32,115,117,112,112,108,121,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,97,110,100,47,111,114,32,97,114,103,117,109,101,110,116,115,32,97,115,32,97,32,98,105,110,97,114,121,32,105,110,32,116,104,101,32,99,111,114,114,101,99,116,32,101,110,99,111,100,105,110,103,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32,116,104,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,40,51,41>>]}]},<<44,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,105,108,101,58,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>]}]},<<32,105,110,32,75,101,114,110,101,108,44,32,97,110,100,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,95,117,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<85,115,105,110,103,32,85,110,105,99,111,100,101,32,105,110,32,69,114,108,97,110,103>>]}]},<<32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,110,97,109,101,32,40,105,102,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,108,105,115,116,41,32,99,97,110,32,111,110,108,121,32,98,101,32,62,32,50,53,53,32,105,102,32,116,104,101,32,69,114,108,97,110,103,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,105,115,32,115,116,97,114,116,101,100,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,116,114,97,110,115,108,97,116,105,111,110,32,109,111,100,101,46,32,79,116,104,101,114,119,105,115,101,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,105,115,32,108,105,109,105,116,101,100,32,116,111,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]}]},{p,[],[{code,[],[<<80,111,114,116,78,97,109,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,97,110,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,116,111,32,98,101,32,114,117,110,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,114,117,110,115,32,111,117,116,115,105,100,101,32,116,104,101,32,69,114,108,97,110,103,32,119,111,114,107,32,115,112,97,99,101,32,117,110,108,101,115,115,32,97,110,32,69,114,108,97,110,103,32,100,114,105,118,101,114,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32,102,111,117,110,100,44,32,116,104,97,116,32,100,114,105,118,101,114,32,105,115,32,115,116,97,114,116,101,100,46,32,65,32,100,114,105,118,101,114,32,114,117,110,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,119,111,114,107,32,115,112,97,99,101,44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,104,97,116,32,105,116,32,105,115,32,108,105,110,107,101,100,32,119,105,116,104,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<70,111,114,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,44,32>>,{code,[],[<<80,65,84,72>>]},<<32,105,115,32,115,101,97,114,99,104,101,100,32,40,111,114,32,97,110,32,101,113,117,105,118,97,108,101,110,116,32,109,101,116,104,111,100,32,105,115,32,117,115,101,100,32,116,111,32,102,105,110,100,32,112,114,111,103,114,97,109,115,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,79,83,41,46,32,84,104,105,115,32,105,115,32,100,111,110,101,32,98,121,32,105,110,118,111,107,105,110,103,32,116,104,101,32,115,104,101,108,108,32,111,110,32,99,101,114,116,97,105,110,32,112,108,97,116,102,111,114,109,115,46,32,84,104,101,32,102,105,114,115,116,32,115,112,97,99,101,45,115,101,112,97,114,97,116,101,100,32,116,111,107,101,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,32,40,111,114,32,100,114,105,118,101,114,41,46,32,84,104,105,115,32,40,97,109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,41,32,109,97,107,101,115,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,115,117,105,116,97,98,108,101,32,102,111,114,32,114,117,110,110,105,110,103,32,112,114,111,103,114,97,109,115,32,119,105,116,104,32,115,112,97,99,101,115,32,105,110,32,102,105,108,101,110,97,109,101,115,32,111,114,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,46,32,73,102,32,115,112,97,99,101,115,32,105,110,32,101,120,101,99,117,116,97,98,108,101,32,102,105,108,101,110,97,109,101,115,32,97,114,101,32,100,101,115,105,114,101,100,44,32,117,115,101,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125>>]},<<32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,115,112,97,119,110,95,100,114,105,118,101,114,44,32,67,111,109,109,97,110,100,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,98,117,116,32,100,101,109,97,110,100,115,32,116,104,101,32,102,105,114,115,116,32,40,115,112,97,99,101,45,115,101,112,97,114,97,116,101,100,41,32,116,111,107,101,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,32,116,111,32,98,101,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,108,111,97,100,101,100,32,100,114,105,118,101,114,46,32,73,102,32,110,111,32,100,114,105,118,101,114,32,119,105,116,104,32,116,104,97,116,32,110,97,109,101,32,105,115,32,108,111,97,100,101,100,44,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,114,114,111,114,32,105,115,32,114,97,105,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<123,115,112,97,119,110,44,32,70,105,108,101,78,97,109,101,125>>]},<<44,32,98,117,116,32,111,110,108,121,32,114,117,110,115,32,101,120,116,101,114,110,97,108,32,101,120,101,99,117,116,97,98,108,101,115,46,32>>,{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,105,110,32,105,116,115,32,119,104,111,108,101,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,44,32,105,110,99,108,117,100,105,110,103,32,97,110,121,32,115,112,97,99,101,115,46,32,73,102,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,116,111,32,98,101,32,112,97,115,115,101,100,44,32,116,104,101,32>>,{code,[],[<<80,111,114,116,83,101,116,116,105,110,103,115>>]},<<32>>,{code,[],[<<97,114,103,115>>]},<<32,97,110,100,32>>,{code,[],[<<97,114,103,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,115,104,101,108,108,32,105,115,32,117,115,117,97,108,108,121,32,110,111,116,32,105,110,118,111,107,101,100,32,116,111,32,115,116,97,114,116,32,116,104,101,32,112,114,111,103,114,97,109,44,32,105,116,32,105,115,32,101,120,101,99,117,116,101,100,32,100,105,114,101,99,116,108,121,46,32>>,{code,[],[<<80,65,84,72>>]},<<32,40,111,114,32,101,113,117,105,118,97,108,101,110,116,41,32,105,115,32,110,111,116,32,115,101,97,114,99,104,101,100,46,32,84,111,32,102,105,110,100,32,97,32,112,114,111,103,114,97,109,32,105,110,32>>,{code,[],[<<80,65,84,72>>]},<<32,116,111,32,101,120,101,99,117,116,101,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,102,105,110,100,95,101,120,101,99,117,116,97,98,108,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,102,105,110,100,95,101,120,101,99,117,116,97,98,108,101,47,49>>]}]},<<46>>]},{p,[],[<<79,110,108,121,32,105,102,32,97,32,115,104,101,108,108,32,115,99,114,105,112,116,32,111,114,32>>,{code,[],[<<46,98,97,116>>]},<<32,102,105,108,101,32,105,115,32,101,120,101,99,117,116,101,100,44,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,99,111,109,109,97,110,100,32,105,110,116,101,114,112,114,101,116,101,114,32,105,115,32,105,110,118,111,107,101,100,32,105,109,112,108,105,99,105,116,108,121,44,32,98,117,116,32,116,104,101,114,101,32,105,115,32,115,116,105,108,108,32,110,111,32,99,111,109,109,97,110,100,45,97,114,103,117,109,101,110,116,32,101,120,112,97,110,115,105,111,110,32,111,114,32,105,109,112,108,105,99,105,116,32>>,{code,[],[<<80,65,84,72>>]},<<32,115,101,97,114,99,104,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,117,110,44,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,105,115,32,114,97,105,115,101,100,44,32,119,105,116,104,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,32,97,115,32,116,104,101,32,114,101,97,115,111,110,46,32,84,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,79,83,115,46,32,84,121,112,105,99,97,108,108,121,32,116,104,101,32,101,114,114,111,114,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,97,105,115,101,100,32,119,104,101,110,32,97,110,32,97,116,116,101,109,112,116,32,105,115,32,109,97,100,101,32,116,111,32,114,117,110,32,97,32,112,114,111,103,114,97,109,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,117,110,100,32,97,110,100,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,105,115,32,114,97,105,115,101,100,32,119,104,101,110,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,105,108,101,32,105,115,32,110,111,116,32,101,120,101,99,117,116,97,98,108,101,46>>]}]},{dt,[],[{code,[],[<<123,102,100,44,32,73,110,44,32,79,117,116,125>>]}]},{dd,[],[{p,[],[<<65,108,108,111,119,115,32,97,110,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,116,111,32,97,99,99,101,115,115,32,97,110,121,32,99,117,114,114,101,110,116,108,121,32,111,112,101,110,101,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,117,115,101,100,32,98,121,32,69,114,108,97,110,103,46,32,84,104,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32>>,{code,[],[<<73,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,44,32,97,110,100,32,116,104,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32>>,{code,[],[<<79,117,116>>]},<<32,102,111,114,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,46,32,73,116,32,105,115,32,111,110,108,121,32,117,115,101,100,32,102,111,114,32,118,97,114,105,111,117,115,32,115,101,114,118,101,114,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,79,83,32,40>>,{code,[],[<<115,104,101,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<117,115,101,114>>]},<<41,46,32,72,101,110,99,101,44,32,105,116,115,32,117,115,101,32,105,115,32,108,105,109,105,116,101,100,46>>]}]}]},{p,[],[{code,[],[<<80,111,114,116,83,101,116,116,105,110,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,115,101,116,116,105,110,103,115,32,102,111,114,32,116,104,101,32,112,111,114,116,46,32,84,104,101,32,118,97,108,105,100,32,115,101,116,116,105,110,103,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,97,99,107,101,116,44,32,78,125>>]}]},{dd,[],[{p,[],[<<77,101,115,115,97,103,101,115,32,97,114,101,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,101,105,114,32,108,101,110,103,116,104,44,32,115,101,110,116,32,105,110,32>>,{code,[],[<<78>>]},<<32,98,121,116,101,115,44,32,119,105,116,104,32,116,104,101,32,109,111,115,116,32,115,105,103,110,105,102,105,99,97,110,116,32,98,121,116,101,32,102,105,114,115,116,46,32,84,104,101,32,118,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<78>>]},<<32,97,114,101,32,49,44,32,50,44,32,97,110,100,32,52,46>>]}]},{dt,[],[{code,[],[<<115,116,114,101,97,109>>]}]},{dd,[],[{p,[],[<<79,117,116,112,117,116,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,119,105,116,104,111,117,116,32,112,97,99,107,101,116,32,108,101,110,103,116,104,115,46,32,65,32,117,115,101,114,45,100,101,102,105,110,101,100,32,112,114,111,116,111,99,111,108,32,109,117,115,116,32,98,101,32,117,115,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,101,120,116,101,114,110,97,108,32,111,98,106,101,99,116,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,101,44,32,76,125>>]}]},{dd,[],[{p,[],[<<77,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,111,110,32,97,32,112,101,114,32,108,105,110,101,32,98,97,115,105,115,46,32,69,97,99,104,32,108,105,110,101,32,40,100,101,108,105,109,105,116,101,100,32,98,121,32,116,104,101,32,79,83,45,100,101,112,101,110,100,101,110,116,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,41,32,105,115,32,100,101,108,105,118,101,114,101,100,32,105,110,32,97,32,115,105,110,103,108,101,32,109,101,115,115,97,103,101,46,32,84,104,101,32,109,101,115,115,97,103,101,32,100,97,116,97,32,102,111,114,109,97,116,32,105,115,32>>,{code,[],[<<123,70,108,97,103,44,32,76,105,110,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<70,108,97,103>>]},<<32,105,115,32>>,{code,[],[<<101,111,108>>]},<<32,111,114,32>>,{code,[],[<<110,111,101,111,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<76,105,110,101>>]},<<32,105,115,32,116,104,101,32,100,97,116,97,32,100,101,108,105,118,101,114,101,100,32,40,119,105,116,104,111,117,116,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,41,46>>]},{p,[],[{code,[],[<<76>>]},<<32,115,112,101,99,105,102,105,101,115,32,116,104,101,32,109,97,120,105,109,117,109,32,108,105,110,101,32,108,101,110,103,116,104,32,105,110,32,98,121,116,101,115,46,32,76,105,110,101,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,105,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,105,110,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,109,101,115,115,97,103,101,44,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<110,111,101,111,108>>]},<<32,102,111,114,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,109,101,115,115,97,103,101,46,32,73,102,32,101,110,100,32,111,102,32,102,105,108,101,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,32,97,110,121,119,104,101,114,101,32,101,108,115,101,32,116,104,97,110,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,105,110,103,32,97,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,44,32,116,104,101,32,108,97,115,116,32,108,105,110,101,32,105,115,32,97,108,115,111,32,100,101,108,105,118,101,114,101,100,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<110,111,101,111,108>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,108,105,110,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,119,105,116,104,32>>,{code,[],[<<70,108,97,103>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<101,111,108>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<123,112,97,99,107,101,116,44,32,78,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,108,105,110,101,44,32,76,125>>]},<<32,115,101,116,116,105,110,103,115,32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,46>>]}]},{dt,[],[{code,[],[<<123,99,100,44,32,68,105,114,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,84,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,115,116,97,114,116,115,32,117,115,105,110,103,32>>,{code,[],[<<68,105,114>>]},<<32,97,115,32,105,116,115,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,46,32>>,{code,[],[<<68,105,114>>]},<<32,109,117,115,116,32,98,101,32,97,32,115,116,114,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,101,110,118,44,32,69,110,118,125>>]}]},{dd,[],[{p,[],[<<84,121,112,101,115,58>>,{br,[],[]},<<194,160,194,160>>,{code,[],[<<78,97,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,111,115,35,101,110,118,95,118,97,114,95,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<111,115,58,101,110,118,95,118,97,114,95,110,97,109,101,40,41>>]}]},{br,[],[]},<<194,160,194,160>>,{code,[],[<<86,97,108,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,111,115,35,101,110,118,95,118,97,114,95,118,97,108,117,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<111,115,58,101,110,118,95,118,97,114,95,118,97,108,117,101,40,41>>]}]},{code,[],[<<32,124,32,102,97,108,115,101>>]},{br,[],[]},<<194,160,194,160>>,{code,[],[<<69,110,118,32,61,32,91,123,78,97,109,101,44,32,86,97,108,125,93>>]}]},{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,84,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,111,102,32,116,104,101,32,115,116,97,114,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,101,120,116,101,110,100,101,100,32,117,115,105,110,103,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32>>,{code,[],[<<69,110,118>>]},<<46>>]},{p,[],[{code,[],[<<69,110,118>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32>>,{code,[],[<<123,78,97,109,101,44,32,86,97,108,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,97,110,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,44,32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<32,105,115,32,116,104,101,32,118,97,108,117,101,32,105,116,32,105,115,32,116,111,32,104,97,118,101,32,105,110,32,116,104,101,32,115,112,97,119,110,101,100,32,112,111,114,116,32,112,114,111,99,101,115,115,46,32,66,111,116,104,32>>,{code,[],[<<78,97,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<32,109,117,115,116,32,98,101,32,115,116,114,105,110,103,115,46,32,84,104,101,32,111,110,101,32,101,120,99,101,112,116,105,111,110,32,105,115,32>>,{code,[],[<<86,97,108>>]},<<32,98,101,105,110,103,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,105,110,32,97,110,97,108,111,103,121,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,103,101,116,101,110,118,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,103,101,116,101,110,118,47,49>>]}]},<<41,44,32,119,104,105,99,104,32,114,101,109,111,118,101,115,32,116,104,101,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,101,110,99,111,100,105,110,103,32,114,101,113,117,105,114,101,109,101,110,116,115,44,32,115,101,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,121,112,101,115,32,102,111,114,32>>,{code,[],[<<78,97,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<86,97,108>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,114,103,115,44,32,91,32,115,116,114,105,110,103,40,41,32,124,32,98,105,110,97,114,121,40,41,32,93,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,97,110,100,32,115,112,101,99,105,102,105,101,115,32,97,114,103,117,109,101,110,116,115,32,116,111,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,46,32,69,97,99,104,32,97,114,103,117,109,101,110,116,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,115,101,112,97,114,97,116,101,32,115,116,114,105,110,103,32,97,110,100,32,40,111,110,32,85,110,105,120,41,32,101,118,101,110,116,117,97,108,108,121,32,101,110,100,115,32,117,112,32,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,101,97,99,104,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,118,101,99,116,111,114,46,32,79,110,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,44,32,97,32,115,105,109,105,108,97,114,32,98,101,104,97,118,105,111,114,32,105,115,32,109,105,109,105,99,107,101,100,46>>]},{p,[],[<<84,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,110,111,116,32,101,120,112,97,110,100,101,100,32,98,121,32,116,104,101,32,115,104,101,108,108,32,98,101,102,111,114,101,32,116,104,101,121,32,97,114,101,32,115,117,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,120,101,99,117,116,97,98,108,101,46,32,77,111,115,116,32,110,111,116,97,98,108,121,32,116,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,102,105,108,101,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,46,32,84,111,32,101,120,112,97,110,100,32,119,105,108,100,99,97,114,100,115,32,102,111,114,32,116,104,101,32,97,114,103,117,109,101,110,116,115,44,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,102,105,108,101,108,105,98,35,119,105,108,100,99,97,114,100,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,105,108,101,108,105,98,58,119,105,108,100,99,97,114,100,47,49>>]}]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,101,118,101,110,32,105,102,32,116,104,101,32,112,114,111,103,114,97,109,32,105,115,32,97,32,85,110,105,120,32,115,104,101,108,108,32,115,99,114,105,112,116,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,116,104,101,32,115,104,101,108,108,32,117,108,116,105,109,97,116,101,108,121,32,105,115,32,105,110,118,111,107,101,100,44,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,44,32,97,110,100,32,116,104,101,32,115,99,114,105,112,116,32,105,115,32,112,114,111,118,105,100,101,100,32,119,105,116,104,32,116,104,101,32,117,110,116,111,117,99,104,101,100,32,97,114,103,117,109,101,110,116,115,46,32,79,110,32,87,105,110,100,111,119,115,44,32,119,105,108,100,99,97,114,100,32,101,120,112,97,110,115,105,111,110,32,105,115,32,97,108,119,97,121,115,32,117,112,32,116,111,32,116,104,101,32,112,114,111,103,114,97,109,32,105,116,115,101,108,102,44,32,116,104,101,114,101,102,111,114,101,32,116,104,105,115,32,105,115,32,110,111,116,32,97,110,32,105,115,115,117,101,46>>]},{p,[],[<<84,104,101,32,101,120,101,99,117,116,97,98,108,101,32,110,97,109,101,32,40,97,108,115,111,32,107,110,111,119,110,32,97,115,32>>,{code,[],[<<97,114,103,118,91,48,93>>]},<<41,32,105,115,32,110,111,116,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,105,115,32,108,105,115,116,46,32,84,104,101,32,112,114,111,112,101,114,32,101,120,101,99,117,116,97,98,108,101,32,110,97,109,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,117,115,101,100,32,97,115,32>>,{code,[],[<<97,114,103,118,91,48,93>>]},<<44,32,119,104,101,114,101,32,97,112,112,108,105,99,97,98,108,101,46>>]},{p,[],[<<73,102,32,121,111,117,32,101,120,112,108,105,99,105,116,108,121,32,119,97,110,116,32,116,111,32,115,101,116,32,116,104,101,32,112,114,111,103,114,97,109,32,110,97,109,101,32,105,110,32,116,104,101,32,97,114,103,117,109,101,110,116,32,118,101,99,116,111,114,44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,114,103,48>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,97,114,103,48,44,32,115,116,114,105,110,103,40,41,32,124,32,98,105,110,97,114,121,40,41,125>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,97,110,100,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,115,32,116,104,101,32,112,114,111,103,114,97,109,32,110,97,109,101,32,97,114,103,117,109,101,110,116,32,119,104,101,110,32,114,117,110,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,46,32,84,104,105,115,32,99,97,110,32,105,110,32,115,111,109,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,44,32,111,110,32,115,111,109,101,32,79,83,115,44,32,98,101,32,100,101,115,105,114,97,98,108,101,46,32,72,111,119,32,116,104,101,32,112,114,111,103,114,97,109,32,114,101,115,112,111,110,100,115,32,116,111,32,116,104,105,115,32,105,115,32,104,105,103,104,108,121,32,115,121,115,116,101,109,45,100,101,112,101,110,100,101,110,116,32,97,110,100,32,110,111,32,115,112,101,99,105,102,105,99,32,101,102,102,101,99,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,46>>]}]},{dt,[],[{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,110,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,44,32,97,110,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,99,101,115,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,101,120,105,116,115,44,32,97,32,109,101,115,115,97,103,101,32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,80,111,114,116,44,123,101,120,105,116,95,115,116,97,116,117,115,44,83,116,97,116,117,115,125,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,44,32,119,104,101,114,101,32>>,{code,[],[<<83,116,97,116,117,115>>]},<<32,105,115,32,116,104,101,32,101,120,105,116,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,32,112,114,111,103,114,97,109,32,97,98,111,114,116,115,32,111,110,32,85,110,105,120,44,32,116,104,101,32,115,97,109,101,32,99,111,110,118,101,110,116,105,111,110,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,115,104,101,108,108,115,32,100,111,32,40,116,104,97,116,32,105,115,44,32,49,50,56,43,115,105,103,110,97,108,41,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<101,111,102>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,108,115,111,44,32,116,104,101,32,109,101,115,115,97,103,101,115,32>>,{code,[],[<<101,111,102>>]},<<32,97,110,100,32>>,{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]},<<32,97,112,112,101,97,114,32,105,110,32,97,110,32,117,110,115,112,101,99,105,102,105,101,100,32,111,114,100,101,114,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,99,108,111,115,101,115,32,105,116,115,32>>,{code,[],[<<115,116,100,111,117,116>>]},<<32,119,105,116,104,111,117,116,32,101,120,105,116,105,110,103,44,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,105,116,95,115,116,97,116,117,115>>]},<<32,100,111,101,115,32,110,111,116,32,119,111,114,107,46>>]}]},{dt,[],[{code,[],[<<117,115,101,95,115,116,100,105,111>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32>>,{code,[],[<<123,115,112,97,119,110,44,32,67,111,109,109,97,110,100,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<46,32,73,116,32,97,108,108,111,119,115,32,116,104,101,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,32,97,110,100,32,111,117,116,112,117,116,32,40,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,48,32,97,110,100,32,49,41,32,111,102,32,116,104,101,32,115,112,97,119,110,101,100,32,40,85,110,105,120,41,32,112,114,111,99,101,115,115,32,102,111,114,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,69,114,108,97,110,103,46>>]}]},{dt,[],[{code,[],[<<110,111,117,115,101,95,115,116,100,105,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,112,111,115,105,116,101,32,111,102,32>>,{code,[],[<<117,115,101,95,115,116,100,105,111>>]},<<46,32,73,116,32,117,115,101,115,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,51,32,97,110,100,32,52,32,102,111,114,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,69,114,108,97,110,103,46>>]}]},{dt,[],[{code,[],[<<115,116,100,101,114,114,95,116,111,95,115,116,100,111,117,116>>]}]},{dd,[],[{p,[],[<<65,102,102,101,99,116,115,32,112,111,114,116,115,32,116,111,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,46,32,84,104,101,32,101,120,101,99,117,116,101,100,32,112,114,111,103,114,97,109,32,103,101,116,115,32,105,116,115,32,115,116,97,110,100,97,114,100,32,101,114,114,111,114,32,102,105,108,101,32,114,101,100,105,114,101,99,116,101,100,32,116,111,32,105,116,115,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,32,102,105,108,101,46,32>>,{code,[],[<<115,116,100,101,114,114,95,116,111,95,115,116,100,111,117,116>>]},<<32,97,110,100,32>>,{code,[],[<<110,111,117,115,101,95,115,116,100,105,111>>]},<<32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,46>>]}]},{dt,[],[{code,[],[<<111,118,101,114,108,97,112,112,101,100,95,105,111>>]}]},{dd,[],[{p,[],[<<65,102,102,101,99,116,115,32,112,111,114,116,115,32,116,111,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,115,32,111,110,32,87,105,110,100,111,119,115,32,111,110,108,121,46,32,84,104,101,32,115,116,97,110,100,97,114,100,32,105,110,112,117,116,32,97,110,100,32,115,116,97,110,100,97,114,100,32,111,117,116,112,117,116,32,104,97,110,100,108,101,115,32,111,102,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,97,114,101,44,32,105,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,117,112,112,108,105,101,100,44,32,111,112,101,110,101,100,32,119,105,116,104,32,102,108,97,103,32>>,{code,[],[<<70,73,76,69,95,70,76,65,71,95,79,86,69,82,76,65,80,80,69,68>>]},<<44,32,115,111,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,32,99,97,110,32,40,97,110,100,32,109,117,115,116,41,32,100,111,32,111,118,101,114,108,97,112,112,101,100,32,73,47,79,32,111,110,32,105,116,115,32,115,116,97,110,100,97,114,100,32,104,97,110,100,108,101,115,46,32,84,104,105,115,32,105,115,32,110,111,116,32,110,111,114,109,97,108,108,121,32,116,104,101,32,99,97,115,101,32,102,111,114,32,115,105,109,112,108,101,32,112,111,114,116,32,112,114,111,103,114,97,109,115,44,32,98,117,116,32,97,110,32,111,112,116,105,111,110,32,111,102,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,101,120,112,101,114,105,101,110,99,101,100,32,87,105,110,100,111,119,115,32,112,114,111,103,114,97,109,109,101,114,46,32>>,{em,[],[<<79,110,32,97,108,108,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,105,108,101,110,116,108,121,32,100,105,115,99,97,114,100,101,100,46>>]}]}]},{dt,[],[{code,[],[<<105,110>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,102,111,114,32,105,110,112,117,116,46>>]}]},{dt,[],[{code,[],[<<111,117,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,102,111,114,32,111,117,116,112,117,116,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,32,73,47,79,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,115,32,97,115,32,111,112,112,111,115,101,100,32,116,111,32,108,105,115,116,115,32,111,102,32,98,121,116,101,115,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,99,108,111,115,101,100,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,32,97,110,100,32,100,111,101,115,32,110,111,116,32,112,114,111,100,117,99,101,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,46,32,73,110,115,116,101,97,100,44,32,105,116,32,114,101,109,97,105,110,115,32,111,112,101,110,32,97,110,100,32,97,32>>,{code,[],[<<123,80,111,114,116,44,32,101,111,102,125>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,104,111,108,100,105,110,103,32,116,104,101,32,112,111,114,116,46>>]}]},{dt,[],[{code,[],[<<104,105,100,101>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,114,117,110,110,105,110,103,32,111,110,32,87,105,110,100,111,119,115,44,32,115,117,112,112,114,101,115,115,101,115,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,101,119,32,99,111,110,115,111,108,101,32,119,105,110,100,111,119,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,116,104,101,32,112,111,114,116,32,112,114,111,103,114,97,109,46,32,40,84,104,105,115,32,111,112,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,111,110,32,111,116,104,101,114,32,112,108,97,116,102,111,114,109,115,46,41>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,105,115,109,44,32,66,111,111,108,101,97,110,125>>]}]},{dd,[],[{a,[{id,<<111,112,101,110,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>}],[]},{p,[],[<<83,101,116,115,32,115,99,104,101,100,117,108,101,114,32,104,105,110,116,32,102,111,114,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,115,99,104,101,100,117,108,101,115,32,112,111,114,116,32,116,97,115,107,115,59,32,119,104,101,110,32,100,111,105,110,103,32,115,111,44,32,105,116,32,105,109,112,114,111,118,101,115,32,112,97,114,97,108,108,101,108,105,115,109,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,116,114,105,101,115,32,116,111,32,112,101,114,102,111,114,109,32,112,111,114,116,32,116,97,115,107,115,32,105,109,109,101,100,105,97,116,101,108,121,44,32,105,109,112,114,111,118,105,110,103,32,108,97,116,101,110,99,121,32,97,116,32,116,104,101,32,101,120,112,101,110,115,101,32,111,102,32,112,97,114,97,108,108,101,108,105,115,109,46,32,84,104,101,32,100,101,102,97,117,108,116,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,112,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,112,112>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,98,117,115,121,95,108,105,109,105,116,115,95,112,111,114,116,44,32,123,76,111,119,44,32,72,105,103,104,125,32,124,32,100,105,115,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,108,105,109,105,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,111,110,116,114,111,108,108,105,110,103,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,32,111,102,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,112,111,114,116,115,32,105,110,116,101,114,110,97,108,32,111,117,116,112,117,116,32,113,117,101,117,101,32,115,105,122,101,32,98,101,99,111,109,101,115,32,108,97,114,103,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<72,105,103,104>>]},<<32,98,121,116,101,115,44,32,105,116,32,101,110,116,101,114,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,105,116,32,98,101,99,111,109,101,115,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<76,111,119>>]},<<32,98,121,116,101,115,32,105,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,116,104,101,32,112,111,114,116,32,105,115,32,105,110,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,44,32,112,114,111,99,101,115,115,101,115,32,115,101,110,100,105,110,103,32,99,111,109,109,97,110,100,115,32,116,111,32,105,116,32,119,105,108,108,32,98,101,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,67,111,109,109,97,110,100,115,32,97,114,101,32,105,110,32,116,104,105,115,32,99,111,110,116,101,120,116,32,101,105,116,104,101,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,91,50,44,51,93>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<76,111,119>>]},<<32,108,105,109,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,102,32,105,116,32,105,115,32,115,101,116,32,108,97,114,103,101,114,32,116,104,101,110,32>>,{code,[],[<<72,105,103,104>>]},<<46,32,86,97,108,105,100,32,114,97,110,103,101,32,111,102,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<76,111,119>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,115,32>>,{code,[],[<<91,49,44,32,40,49,32,98,115,108,32,40,56,42,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,119,111,114,100,115,105,122,101,41,41,41,45,50,93>>]},<<46,32,73,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,116,104,101,32,112,111,114,116,32,119,105,108,108,32,110,101,118,101,114,32,101,110,116,101,114,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,115,32,97,114,101,32>>,{code,[],[<<76,111,119,32,61,32,52,48,57,54>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104,32,61,32,56,49,57,50>>]},<<46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,118,97,108,105,100,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,32,40,112,111,114,116,32,112,114,111,103,114,97,109,41,32,98,121,32,111,112,101,110,105,110,103,32,116,104,101,32,115,112,97,119,110,32,100,114,105,118,101,114,32,97,110,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32>>,{code,[],[<<102,100>>]},<<32,100,114,105,118,101,114,46,32,84,104,105,115,32,111,112,116,105,111,110,32,119,105,108,108,32,99,97,117,115,101,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,119,104,101,110,32,111,112,101,110,105,110,103,32,111,116,104,101,114,32,100,114,105,118,101,114,115,46>>]}]},{dt,[],[{code,[],[<<123,98,117,115,121,95,108,105,109,105,116,115,95,109,115,103,113,44,32,123,76,111,119,44,32,72,105,103,104,125,32,124,32,100,105,115,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,108,105,109,105,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,111,110,116,114,111,108,108,105,110,103,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,32,111,102,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,112,111,114,116,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,115,105,122,101,32,98,101,99,111,109,101,115,32,108,97,114,103,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<72,105,103,104>>]},<<32,98,121,116,101,115,32,105,116,32,101,110,116,101,114,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,105,116,32,98,101,99,111,109,101,115,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<76,111,119>>]},<<32,98,121,116,101,115,32,105,116,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,87,104,101,110,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,105,115,32,105,110,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,44,32,112,114,111,99,101,115,115,101,115,32,115,101,110,100,105,110,103,32,99,111,109,109,97,110,100,115,32,116,111,32,105,116,32,119,105,108,108,32,98,101,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,108,101,97,118,101,115,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46,32,67,111,109,109,97,110,100,115,32,97,114,101,32,105,110,32,116,104,105,115,32,99,111,110,116,101,120,116,32,101,105,116,104,101,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,114,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,91,50,44,51,93>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<76,111,119>>]},<<32,108,105,109,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,102,32,105,116,32,105,115,32,115,101,116,32,108,97,114,103,101,114,32,116,104,101,110,32>>,{code,[],[<<72,105,103,104>>]},<<46,32,86,97,108,105,100,32,114,97,110,103,101,32,111,102,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<76,111,119>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104>>]},<<32,105,115,32>>,{code,[],[<<91,49,44,32,40,49,32,98,115,108,32,40,56,42,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,119,111,114,100,115,105,122,101,41,41,41,45,50,93>>]},<<46,32,73,102,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<32,105,115,32,112,97,115,115,101,100,44,32,116,104,101,32,112,111,114,116,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,110,101,118,101,114,32,101,110,116,101,114,32,116,104,101,32,98,117,115,121,32,115,116,97,116,101,46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,105,102,32,116,104,101,32,100,114,105,118,101,114,32,115,116,97,116,105,99,97,108,108,121,32,104,97,115,32,100,105,115,97,98,108,101,100,32,116,104,101,32,117,115,101,32,111,102,32,116,104,105,115,32,102,101,97,116,117,114,101,44,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,119,105,108,108,32,98,101,32,114,97,105,115,101,100,32,117,110,108,101,115,115,32,116,104,105,115,32,111,112,116,105,111,110,32,97,108,115,111,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<100,105,115,97,98,108,101>>]},<<32,111,114,32,110,111,116,32,112,97,115,115,101,100,32,97,116,32,97,108,108,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,115,32,97,114,101,32>>,{code,[],[<<76,111,119,32,61,32,52,48,57,54>>]},<<32,97,110,100,32>>,{code,[],[<<72,105,103,104,32,61,32,56,49,57,50>>]},<<32,117,110,108,101,115,115,32,116,104,101,32,100,114,105,118,101,114,32,105,116,115,101,108,102,32,100,111,101,115,32,109,111,100,105,102,105,99,97,116,105,111,110,115,32,111,102,32,116,104,101,115,101,32,118,97,108,117,101,115,46>>]},{p,[],[{em,[],[<<78,111,116,101>>]},<<32,116,104,97,116,32,116,104,101,32,100,114,105,118,101,114,32,109,105,103,104,116,32,102,97,105,108,32,105,102,32,105,116,32,97,108,115,111,32,97,100,106,117,115,116,32,116,104,101,115,101,32,108,105,109,105,116,115,32,98,121,32,105,116,115,101,108,102,32,97,110,100,32,121,111,117,32,104,97,118,101,32,100,105,115,97,98,108,101,100,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]},{p,[],[<<84,104,101,32,115,112,97,119,110,32,100,114,105,118,101,114,32,40,117,115,101,100,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,97,110,32,101,120,101,99,117,116,97,98,108,101,41,32,97,110,100,32,116,104,101,32>>,{code,[],[<<102,100>>]},<<32,100,114,105,118,101,114,32,100,111,32,110,111,116,32,100,105,115,97,98,108,101,32,116,104,105,115,32,102,101,97,116,117,114,101,32,97,110,100,32,100,111,32,110,111,116,32,97,100,106,117,115,116,32,116,104,101,115,101,32,108,105,109,105,116,115,32,98,121,32,116,104,101,109,115,101,108,118,101,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,101,114,108,95,100,114,118,95,98,117,115,121,95,109,115,103,113,95,108,105,109,105,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,100,114,118,95,98,117,115,121,95,109,115,103,113,95,108,105,109,105,116,115,40,41>>]}]},<<46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<115,116,114,101,97,109>>]},<<32,102,111,114,32,97,108,108,32,112,111,114,116,32,116,121,112,101,115,32,97,110,100,32>>,{code,[],[<<117,115,101,95,115,116,100,105,111>>]},<<32,102,111,114,32,115,112,97,119,110,101,100,32,112,111,114,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32,105,102,32,116,104,101,32,112,111,114,116,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,44,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32>>,{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]},<<44,32,111,114,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,32,116,104,97,116,32,109,111,115,116,32,99,108,111,115,101,108,121,32,100,101,115,99,114,105,98,101,115,32,116,104,101,32,101,114,114,111,114,44,32,111,114,32>>,{code,[],[<<101,105,110,118,97,108>>]},<<32,105,102,32,110,111,32,80,79,83,73,88,32,99,111,100,101,32,105,115,32,97,112,112,114,111,112,114,105,97,116,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<66,97,100,32,105,110,112,117,116,32,97,114,103,117,109,101,110,116,115,32,116,111,32>>,{code,[],[<<111,112,101,110,95,112,111,114,116>>]},<<46>>]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[<<65,108,108,32,97,118,97,105,108,97,98,108,101,32,112,111,114,116,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,32,97,114,101,32,105,110,32,117,115,101,46>>]},{dt,[],[{code,[],[<<101,110,111,109,101,109>>]}]},{dd,[],[<<78,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,32,116,111,32,99,114,101,97,116,101,32,116,104,101,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<101,97,103,97,105,110>>]}]},{dd,[],[<<78,111,32,109,111,114,101,32,97,118,97,105,108,97,98,108,101,32,79,83,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<101,110,97,109,101,116,111,111,108,111,110,103>>]}]},{dd,[],[<<84,111,111,32,108,111,110,103,32,101,120,116,101,114,110,97,108,32,99,111,109,109,97,110,100,46>>]},{dt,[],[{code,[],[<<101,109,102,105,108,101>>]}]},{dd,[],[<<78,111,32,109,111,114,101,32,97,118,97,105,108,97,98,108,101,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,40,102,111,114,32,116,104,101,32,79,83,32,112,114,111,99,101,115,115,32,116,104,97,116,32,116,104,101,32,69,114,108,97,110,103,32,101,109,117,108,97,116,111,114,32,114,117,110,115,32,105,110,41,46>>]},{dt,[],[{code,[],[<<101,110,102,105,108,101>>]}]},{dd,[],[<<70,117,108,108,32,102,105,108,101,32,116,97,98,108,101,32,40,102,111,114,32,116,104,101,32,101,110,116,105,114,101,32,79,83,41,46>>]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{code,[],[<<67,111,109,109,97,110,100>>]},<<32,115,112,101,99,105,102,105,101,100,32,105,110,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125>>]},<<32,100,111,101,115,32,110,111,116,32,112,111,105,110,116,32,111,117,116,32,97,110,32,101,120,101,99,117,116,97,98,108,101,32,102,105,108,101,46>>]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{code,[],[<<70,105,108,101,78,97,109,101>>]},<<32,115,112,101,99,105,102,105,101,100,32,105,110,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,70,105,108,101,78,97,109,101,125>>]},<<32,100,111,101,115,32,110,111,116,32,112,111,105,110,116,32,111,117,116,32,97,110,32,101,120,105,115,116,105,110,103,32,102,105,108,101,46>>]}]},{p,[],[<<68,117,114,105,110,103,32,117,115,101,32,111,102,32,97,32,112,111,114,116,32,111,112,101,110,101,100,32,117,115,105,110,103,32>>,{code,[],[<<123,115,112,97,119,110,44,32,78,97,109,101,125>>]},<<44,32>>,{code,[],[<<123,115,112,97,119,110,95,100,114,105,118,101,114,44,32,78,97,109,101,125>>]},<<44,32,111,114,32>>,{code,[],[<<123,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,78,97,109,101,125>>]},<<44,32,101,114,114,111,114,115,32,97,114,105,115,105,110,103,32,119,104,101,110,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,105,116,32,97,114,101,32,114,101,112,111,114,116,101,100,32,116,111,32,116,104,101,32,111,119,110,105,110,103,32,112,114,111,99,101,115,115,32,117,115,105,110,103,32,115,105,103,110,97,108,115,32,111,102,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,80,111,114,116,44,32,80,111,115,105,120,67,111,100,101,125>>]},<<46,32,70,111,114,32,116,104,101,32,112,111,115,115,105,98,108,101,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<80,111,115,105,120,67,111,100,101>>]},<<44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,40,51,41>>]}]},<<46>>]},{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,111,114,116,115,32,116,104,97,116,32,99,97,110,32,98,101,32,111,112,101,110,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,109,97,120,95,112,111,114,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,81>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{signature => [{attribute,{2603,2},spec,{{open_port,2},[{type,{2603,16},bounded_fun,[{type,{2603,16},'fun',[{type,{2603,16},product,[{var,{2603,17},'PortName'},{var,{2603,27},'PortSettings'}]},{type,{2603,44},port,[]}]},[{type,{2604,7},constraint,[{atom,{2604,7},is_subtype},[{var,{2604,7},'PortName'},{type,{2604,19},union,[{type,{2604,19},tuple,[{atom,{2604,20},spawn},{ann_type,{2604,27},[{var,{2604,27},'Command'},{type,{2604,38},union,[{type,{2604,38},string,[]},{type,{2604,49},binary,[]}]}]}]},{type,{2605,19},tuple,[{atom,{2605,20},spawn_driver},{ann_type,{2605,34},[{var,{2605,34},'Command'},{type,{2605,45},union,[{type,{2605,45},string,[]},{type,{2605,56},binary,[]}]}]}]},{type,{2606,19},tuple,[{atom,{2606,20},spawn_executable},{ann_type,{2606,38},[{var,{2606,38},'FileName'},{remote_type,{2606,50},[{atom,{2606,50},file},{atom,{2606,55},name_all},[]]}]}]},{type,{2607,19},tuple,[{atom,{2607,20},fd},{ann_type,{2607,24},[{var,{2607,24},'In'},{type,{2607,30},non_neg_integer,[]}]},{ann_type,{2607,49},[{var,{2607,49},'Out'},{type,{2607,56},non_neg_integer,[]}]}]}]}]]},{type,{2608,7},constraint,[{atom,{2608,7},is_subtype},[{var,{2608,7},'PortSettings'},{type,{2608,23},list,[{var,{2608,24},'Opt'}]}]]},{type,{2609,7},constraint,[{atom,{2609,7},is_subtype},[{var,{2609,7},'Opt'},{type,{2609,14},union,[{type,{2609,14},tuple,[{atom,{2609,15},packet},{ann_type,{2609,23},[{var,{2609,23},'N'},{type,{2609,28},union,[{integer,{2609,28},1},{integer,{2609,32},2},{integer,{2609,36},4}]}]}]},{atom,{2610,14},stream},{type,{2611,14},tuple,[{atom,{2611,15},line},{ann_type,{2611,21},[{var,{2611,21},'L'},{type,{2611,26},non_neg_integer,[]}]}]},{type,{2612,14},tuple,[{atom,{2612,15},cd},{ann_type,{2612,19},[{var,{2612,19},'Dir'},{type,{2612,26},union,[{type,{2612,26},string,[]},{type,{2612,37},binary,[]}]}]}]},{type,{2613,14},tuple,[{atom,{2613,15},env},{ann_type,{2613,20},[{var,{2613,20},'Env'},{type,{2613,27},list,[{type,{2613,28},tuple,[{ann_type,{2613,29},[{var,{2613,29},'Name'},{remote_type,{2613,37},[{atom,{2613,37},os},{atom,{2613,40},env_var_name},[]]}]},{ann_type,{2613,56},[{var,{2613,56},'Val'},{type,{2613,63},union,[{remote_type,{2613,63},[{atom,{2613,63},os},{atom,{2613,66},env_var_value},[]]},{atom,{2613,84},false}]}]}]}]}]}]},{type,{2614,14},tuple,[{atom,{2614,15},args},{type,{2614,21},list,[{type,{2614,22},union,[{type,{2614,22},string,[]},{type,{2614,33},binary,[]}]}]}]},{type,{2615,14},tuple,[{atom,{2615,15},arg0},{type,{2615,21},union,[{type,{2615,21},string,[]},{type,{2615,32},binary,[]}]}]},{atom,{2616,14},exit_status},{atom,{2617,14},use_stdio},{atom,{2618,14},nouse_stdio},{atom,{2619,14},stderr_to_stdout},{atom,{2620,14},in},{atom,{2621,14},out},{atom,{2622,14},binary},{atom,{2623,14},eof},{type,{2624,7},tuple,[{atom,{2624,8},parallelism},{ann_type,{2624,21},[{var,{2624,21},'Boolean'},{type,{2624,32},boolean,[]}]}]},{atom,{2625,7},hide},{type,{2626,14},tuple,[{atom,{2626,15},busy_limits_port},{type,{2626,33},union,[{type,{2626,33},tuple,[{type,{2626,34},non_neg_integer,[]},{type,{2626,53},non_neg_integer,[]}]},{atom,{2626,74},disabled}]}]},{type,{2627,14},tuple,[{atom,{2627,15},busy_limits_msgq},{type,{2627,33},union,[{type,{2627,33},tuple,[{type,{2627,34},non_neg_integer,[]},{type,{2627,53},non_neg_integer,[]}]},{atom,{2627,74},disabled}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,50,49,54>>}},{{function,phash,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1769}],[<<112,104,97,115,104,47,50>>],#{<<101,110>> => [{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,104,97,115,104,50,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,50,47,50>>]}]},<<32,115,104,111,117,108,100,32,98,101,32,117,115,101,100,32,102,111,114,32,110,101,119,32,99,111,100,101,46,32,78,111,116,101,32,116,104,97,116,32>>,{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,40,88,44,78,41>>]},<<32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,121,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,112,104,97,115,104,50,40,88,44,78,41>>]}]}]},{p,[],[<<80,111,114,116,97,98,108,101,32,104,97,115,104,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,104,97,115,104,32,102,111,114,32,116,104,101,32,115,97,109,101,32,69,114,108,97,110,103,32,116,101,114,109,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,109,97,99,104,105,110,101,32,97,114,99,104,105,116,101,99,116,117,114,101,32,97,110,100,32,69,82,84,83,32,118,101,114,115,105,111,110,32,40,116,104,101,32,66,73,70,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,52,46,57,46,49,46,49,41,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,97,32,104,97,115,104,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<84,101,114,109>>]},<<32,119,105,116,104,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<49,46,46,82,97,110,103,101>>]},<<46,32,84,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<82,97,110,103,101>>]},<<32,105,115,32,50,94,51,50,46>>]}]},#{deprecated => <<101,114,108,97,110,103,58,112,104,97,115,104,47,50,32,105,115,32,100,101,112,114,101,99,97,116,101,100,59,32,117,115,101,32,101,114,108,97,110,103,58,112,104,97,115,104,50,47,50,32,105,110,115,116,101,97,100>>,signature => [{attribute,{1769,2},spec,{{erlang,phash,2},[{type,{1769,19},bounded_fun,[{type,{1769,19},'fun',[{type,{1769,19},product,[{var,{1769,20},'Term'},{var,{1769,26},'Range'}]},{var,{1769,36},'Hash'}]},[{type,{1770,7},constraint,[{atom,{1770,7},is_subtype},[{var,{1770,7},'Term'},{type,{1770,15},term,[]}]]},{type,{1771,7},constraint,[{atom,{1771,7},is_subtype},[{var,{1771,7},'Range'},{type,{1771,16},pos_integer,[]}]]},{type,{1772,7},constraint,[{atom,{1772,7},is_subtype},[{var,{1772,7},'Hash'},{type,{1772,15},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,50,50>>}},{{function,phash2,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1784}],[<<112,104,97,115,104,50,47,50>>],#{},#{signature => [{attribute,{1784,2},spec,{{erlang,phash2,2},[{type,{1784,20},bounded_fun,[{type,{1784,20},'fun',[{type,{1784,20},product,[{var,{1784,21},'Term'},{var,{1784,27},'Range'}]},{var,{1784,37},'Hash'}]},[{type,{1785,7},constraint,[{atom,{1785,7},is_subtype},[{var,{1785,7},'Term'},{type,{1785,15},term,[]}]]},{type,{1786,7},constraint,[{atom,{1786,7},is_subtype},[{var,{1786,7},'Range'},{type,{1786,16},pos_integer,[]}]]},{type,{1787,7},constraint,[{atom,{1787,7},is_subtype},[{var,{1787,7},'Hash'},{type,{1787,15},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,52,52>>,equiv => {function,phash2,1}}},{{function,phash2,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1777}],[<<112,104,97,115,104,50,47,49>>],#{<<101,110>> => [{p,[],[<<80,111,114,116,97,98,108,101,32,104,97,115,104,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,104,97,115,104,32,102,111,114,32,116,104,101,32,115,97,109,101,32,69,114,108,97,110,103,32,116,101,114,109,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,109,97,99,104,105,110,101,32,97,114,99,104,105,116,101,99,116,117,114,101,32,97,110,100,32,69,82,84,83,32,118,101,114,115,105,111,110,32,40,116,104,101,32,66,73,70,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,53,46,50,41,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,97,32,104,97,115,104,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<84,101,114,109>>]},<<32,119,105,116,104,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<48,46,46,82,97,110,103,101,45,49>>]},<<46,32,84,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<82,97,110,103,101>>]},<<32,105,115,32,50,94,51,50,46,32,87,104,101,110,32,119,105,116,104,111,117,116,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<82,97,110,103,101>>]},<<44,32,97,32,118,97,108,117,101,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,46,46,50,94,50,55,45,49,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,97,108,119,97,121,115,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,104,97,115,104,105,110,103,32,116,101,114,109,115,46,32,73,116,32,100,105,115,116,114,105,98,117,116,101,115,32,115,109,97,108,108,32,105,110,116,101,103,101,114,115,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<112,104,97,115,104,47,50>>]},<<44,32,97,110,100,32,105,116,32,105,115,32,102,97,115,116,101,114,32,102,111,114,32,98,105,103,110,117,109,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<48,46,46,82,97,110,103,101,45,49>>]},<<32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,114,97,110,103,101,32,111,102,32>>,{code,[],[<<112,104,97,115,104,47,50>>]},<<44,32,119,104,105,99,104,32,105,115,32>>,{code,[],[<<49,46,46,82,97,110,103,101>>]},<<46>>]}]},#{signature => [{attribute,{1777,2},spec,{{erlang,phash2,1},[{type,{1777,20},bounded_fun,[{type,{1777,20},'fun',[{type,{1777,20},product,[{var,{1777,21},'Term'}]},{var,{1777,30},'Hash'}]},[{type,{1778,7},constraint,[{atom,{1778,7},is_subtype},[{var,{1778,7},'Term'},{type,{1778,15},term,[]}]]},{type,{1779,7},constraint,[{atom,{1779,7},is_subtype},[{var,{1779,7},'Hash'},{type,{1779,15},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,52,52>>}},{{function,pid_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1792}],[<<112,105,100,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,112,105,100,95,116,111,95,108,105,115,116,40,115,101,108,102,40,41,41,46,10,34,60,48,46,56,53,46,48,62,34>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,105,115,116,95,112,114,111,116,111,99,111,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,114,101,97,116,105,111,110>>]},<<32,102,111,114,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,105,110,32,100,105,102,102,101,114,101,110,116,32,105,110,99,97,114,110,97,116,105,111,110,115,32,111,102,32,97,32,110,111,100,101,32,119,105,116,104,32,97,32,115,112,101,99,105,102,105,99,32,110,97,109,101,32,99,97,110,32,103,101,116,32,116,104,101,32,115,97,109,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]}]}]},#{signature => [{attribute,{1792,2},spec,{{pid_to_list,1},[{type,{1792,18},bounded_fun,[{type,{1792,18},'fun',[{type,{1792,18},product,[{var,{1792,19},'Pid'}]},{type,{1792,27},string,[]}]},[{type,{1793,7},constraint,[{atom,{1793,7},is_subtype},[{var,{1793,7},'Pid'},{type,{1793,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,54,57>>}},{{function,port_call,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3879}],[<<112,111,114,116,95,99,97,108,108,47,51>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,97,108,108,32,116,111,32,97,32,112,111,114,116,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,97,110,100,32>>,{code,[],[<<68,97,116,97>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,44,32,116,104,97,116,32,105,115,44,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,78,111,116,32,97,108,108,32,112,111,114,116,32,100,114,105,118,101,114,115,32,115,117,112,112,111,114,116,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]},{p,[],[{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,114,101,102,101,114,114,105,110,103,32,116,111,32,97,32,100,114,105,118,101,114,46>>]},{p,[],[{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,119,104,105,99,104,32,105,115,32,112,97,115,115,101,100,32,111,110,32,116,111,32,116,104,101,32,100,114,105,118,101,114,46>>]},{p,[],[{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,46,32,84,104,105,115,32,100,97,116,97,32,105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,98,105,110,97,114,121,32,116,101,114,109,32,102,111,114,109,97,116,32,97,110,100,32,115,101,110,116,32,116,111,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,101,114,109,32,102,114,111,109,32,116,104,101,32,100,114,105,118,101,114,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,100,97,116,97,32,97,108,115,111,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,100,111,101,115,32,110,111,116,32,102,105,116,32,105,110,32,97,32,51,50,45,98,105,116,32,105,110,116,101,103,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,115,111,32,100,101,99,105,100,101,115,32,102,111,114,32,97,110,121,32,114,101,97,115,111,110,32,40,112,114,111,98,97,98,108,121,32,115,111,109,101,116,104,105,110,103,32,119,114,111,110,103,32,119,105,116,104,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<41,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,99,97,108,108,32>>,{code,[],[<<112,111,114,116,95,99,97,108,108>>]},<<32,119,105,116,104,32,97,110,32,117,110,107,110,111,119,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,101,120,112,101,99,116,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,115,117,112,112,108,105,101,100,32,97,114,103,117,109,101,110,116,115,46>>]}]}]}]}]},#{signature => [{attribute,{3879,2},spec,{{erlang,port_call,3},[{type,{3879,23},bounded_fun,[{type,{3879,23},'fun',[{type,{3879,23},product,[{var,{3879,24},'Port'},{var,{3879,30},'Operation'},{var,{3879,41},'Data'}]},{type,{3879,50},term,[]}]},[{type,{3880,7},constraint,[{atom,{3880,7},is_subtype},[{var,{3880,7},'Port'},{type,{3880,15},union,[{type,{3880,15},port,[]},{type,{3880,24},atom,[]}]}]]},{type,{3881,7},constraint,[{atom,{3881,7},is_subtype},[{var,{3881,7},'Operation'},{type,{3881,20},integer,[]}]]},{type,{3882,7},constraint,[{atom,{3882,7},is_subtype},[{var,{3882,7},'Data'},{type,{3882,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,54,56,56>>}},{{function,port_close,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3840}],[<<112,111,114,116,95,99,108,111,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,108,111,115,101,115,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,82,111,117,103,104,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,99,108,111,115,101,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,40,115,101,101,32,98,101,108,111,119,41,44,32,98,101,105,110,103,32,115,121,110,99,104,114,111,110,111,117,115,44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,114,101,112,108,121,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,108,111,115,101,100,125>>]},<<46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,99,108,111,115,101,32,97,32,112,111,114,116,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<44,32,110,111,116,32,111,110,108,121,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,41,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<32,114,101,116,117,114,110,115,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,99,108,111,115,101,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32,112,111,114,116,32,114,101,112,108,105,101,115,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,108,111,115,101,100,125>>]},<<32,119,104,101,110,32,97,108,108,32,98,117,102,102,101,114,115,32,104,97,118,101,32,98,101,101,110,32,102,108,117,115,104,101,100,32,97,110,100,32,116,104,101,32,112,111,114,116,32,114,101,97,108,108,121,32,99,108,111,115,101,115,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,99,108,111,115,101,32,97,32,112,111,114,116,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,99,108,111,115,101,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,98,117,116,32,116,104,101,32,114,101,112,108,121,32,97,108,119,97,121,115,32,103,111,101,115,32,116,111,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,99,108,111,115,101,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,108,111,115,101,47,49>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]}]},#{signature => [{attribute,{3840,2},spec,{{port_close,1},[{type,{3840,17},bounded_fun,[{type,{3840,17},'fun',[{type,{3840,17},product,[{var,{3840,18},'Port'}]},{atom,{3840,27},true}]},[{type,{3841,7},constraint,[{atom,{3841,7},is_subtype},[{var,{3841,7},'Port'},{type,{3841,15},union,[{type,{3841,15},port,[]},{type,{3841,24},atom,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,52,48>>}},{{function,port_command,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3798}],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,46,32,83,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,97,110,100,32,98,101,105,110,103,32,115,121,110,99,104,114,111,110,111,117,115,32,40,115,101,101,32,98,101,108,111,119,41,46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]},<<44,32,110,111,116,32,111,110,108,121,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,114,111,99,101,115,115,41,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,116,104,101,32,100,97,116,97,32,109,101,115,115,97,103,101,32,100,105,115,97,112,112,101,97,114,115,32,119,105,116,104,111,117,116,32,97,32,115,111,117,110,100,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,111,112,101,110,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46,32,84,104,101,32,112,111,114,116,32,111,119,110,101,114,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<32,97,108,115,111,32,105,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,110,100,32,116,111,32,97,32,112,111,114,116,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,98,117,115,121,32,97,110,121,32,109,111,114,101,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]}]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,110,32,117,110,107,110,111,119,110,32,112,111,114,116,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,100,97,116,97,46>>]}]}]},#{signature => [{attribute,{3798,2},spec,{{port_command,2},[{type,{3798,19},bounded_fun,[{type,{3798,19},'fun',[{type,{3798,19},product,[{var,{3798,20},'Port'},{var,{3798,26},'Data'}]},{atom,{3798,35},true}]},[{type,{3799,7},constraint,[{atom,{3799,7},is_subtype},[{var,{3799,7},'Port'},{type,{3799,15},union,[{type,{3799,15},port,[]},{type,{3799,24},atom,[]}]}]]},{type,{3800,7},constraint,[{atom,{3800,7},is_subtype},[{var,{3800,7},'Data'},{type,{3800,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,55,56,48>>}},{{function,port_command,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3811}],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,100,97,116,97,32,116,111,32,97,32,112,111,114,116,46,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,40,80,111,114,116,44,32,68,97,116,97,44,32,91,93,41>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,40,80,111,114,116,44,32,68,97,116,97,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,97,98,111,114,116,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,116,105,108,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,98,117,115,121,32,97,110,121,109,111,114,101,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,111,114,99,101>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,102,111,114,99,101,100,32,116,104,114,111,117,103,104,46,32,84,104,101,32,99,97,108,108,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32,116,104,101,32,100,114,105,118,101,114,32,111,102,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,100,114,105,118,101,114,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,100,114,105,118,101,114,95,101,110,116,114,121,35,100,114,105,118,101,114,95,102,108,97,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<69,82,76,95,68,82,86,95,70,76,65,71,95,83,79,70,84,95,66,85,83,89>>]}]},<<46>>]},{dt,[],[{code,[],[<<110,111,115,117,115,112,101,110,100>>]}]},{dd,[],[<<84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,98,117,115,121,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,111,114,116,32,99,111,109,109,97,110,100,32,105,115,32,97,98,111,114,116,101,100,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<77,111,114,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<68,97,116,97>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,73,47,79,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,105,111,110,76,105,115,116>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<102,111,114,99,101>>]},<<32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,98,117,116,32,116,104,101,32,100,114,105,118,101,114,32,111,102,32,116,104,101,32,112,111,114,116,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,102,111,114,99,105,110,103,32,116,104,114,111,117,103,104,32,97,32,98,117,115,121,32,112,111,114,116,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,115,101,110,100,32,100,97,116,97,32,116,111,32,97,110,32,117,110,107,110,111,119,110,32,112,111,114,116,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,100,97,116,97,46>>]}]}]},#{signature => [{attribute,{3811,2},spec,{{port_command,3},[{type,{3811,19},bounded_fun,[{type,{3811,19},'fun',[{type,{3811,19},product,[{var,{3811,20},'Port'},{var,{3811,26},'Data'},{var,{3811,32},'OptionList'}]},{type,{3811,47},boolean,[]}]},[{type,{3812,7},constraint,[{atom,{3812,7},is_subtype},[{var,{3812,7},'Port'},{type,{3812,15},union,[{type,{3812,15},port,[]},{type,{3812,24},atom,[]}]}]]},{type,{3813,7},constraint,[{atom,{3813,7},is_subtype},[{var,{3813,7},'Data'},{type,{3813,15},iodata,[]}]]},{type,{3814,7},constraint,[{atom,{3814,7},is_subtype},[{var,{3814,7},'Option'},{type,{3814,17},union,[{atom,{3814,17},force},{atom,{3814,25},nosuspend}]}]]},{type,{3815,7},constraint,[{atom,{3815,7},is_subtype},[{var,{3815,7},'OptionList'},{type,{3815,21},list,[{var,{3815,22},'Option'}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,56,51,50>>}},{{function,port_connect,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3827}],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,40,116,104,101,32,99,111,110,110,101,99,116,101,100,32,112,111,114,116,41,32,116,111,32>>,{code,[],[<<80,105,100>>]},<<46,32,82,111,117,103,104,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,32,100,105,102,102,101,114,115,44,32,115,101,101,32,98,101,108,111,119,46>>]}]},{li,[],[{p,[],[<<84,104,101,32,112,111,114,116,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,114,101,112,108,121,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,99,111,110,110,101,99,116,101,100,125>>]},<<46>>]}]},{li,[],[{p,[],[{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,49>>]},<<32,105,115,32,115,121,110,99,104,114,111,110,111,117,115,44,32,115,101,101,32,98,101,108,111,119,46>>]}]},{li,[],[{p,[],[<<84,104,101,32,110,101,119,32,112,111,114,116,32,111,119,110,101,114,32,103,101,116,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,46>>]}]}]},{p,[],[<<84,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,32,115,116,97,121,115,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,32,97,110,100,32,109,117,115,116,32,99,97,108,108,32>>,{code,[],[<<117,110,108,105,110,107,40,80,111,114,116,41>>]},<<32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,100,101,115,105,114,101,100,46,32,65,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,116,111,32,98,101,32,97,110,121,32,112,114,111,99,101,115,115,32,119,105,116,104,32>>,{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>]},<<46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,114,105,115,111,110,58,32>>,{code,[],[<<80,111,114,116,32,33,32,123,115,101,108,102,40,41,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,111,110,108,121,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,111,114,116,32,111,114,32,97,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,32,99,108,111,115,101,100,32,112,111,114,116,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32,112,111,114,116,32,114,101,112,108,105,101,115,32,119,105,116,104,32>>,{code,[],[<<123,80,111,114,116,44,32,99,111,110,110,101,99,116,101,100,125>>]},<<32,116,111,32,116,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,111,108,100,32,112,111,114,116,32,111,119,110,101,114,32,105,115,32,115,116,105,108,108,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,119,104,105,108,101,32,116,104,101,32,110,101,119,32,105,115,32,110,111,116,46,32,73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,97,110,32,111,112,101,110,32,112,111,114,116,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,116,104,101,32>>,{em,[],[<<112,111,114,116,32,111,119,110,101,114>>]},<<32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<46,32,84,104,101,32,112,111,114,116,32,111,119,110,101,114,32,102,97,105,108,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,115,105,103>>]},<<32,97,108,115,111,32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,121,32,112,114,111,99,101,115,115,32,99,97,110,32,115,101,116,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,117,115,105,110,103,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,97,115,32,105,102,32,105,116,32,105,116,115,101,108,102,32,119,97,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,44,32,98,117,116,32,116,104,101,32,114,101,112,108,121,32,97,108,119,97,121,115,32,103,111,101,115,32,116,111,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,54,44,32>>,{code,[],[<<80,111,114,116,32,33,32,123,80,111,114,116,79,119,110,101,114,44,32,123,99,111,110,110,101,99,116,44,32,80,105,100,125,125>>]},<<32,105,115,32,116,114,117,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,97,108,119,97,121,115,32,98,101,101,110,32,100,111,99,117,109,101,110,116,101,100,32,97,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,108,101,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,121,110,99,104,114,111,110,111,117,115,46,32>>,{code,[],[<<112,111,114,116,95,99,111,110,110,101,99,116,47,50>>]},<<32,105,115,32,104,111,119,101,118,101,114,32,115,116,105,108,108,32,102,117,108,108,121,32,115,121,110,99,104,114,111,110,111,117,115,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,32,101,114,114,111,114,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,44,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,99,108,111,115,101,100,32,112,111,114,116,44,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,116,104,105,115,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,111,99,99,117,114,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]}]},#{signature => [{attribute,{3827,2},spec,{{port_connect,2},[{type,{3827,19},bounded_fun,[{type,{3827,19},'fun',[{type,{3827,19},product,[{var,{3827,20},'Port'},{var,{3827,26},'Pid'}]},{atom,{3827,34},true}]},[{type,{3828,7},constraint,[{atom,{3828,7},is_subtype},[{var,{3828,7},'Port'},{type,{3828,15},union,[{type,{3828,15},port,[]},{type,{3828,24},atom,[]}]}]]},{type,{3829,7},constraint,[{atom,{3829,7},is_subtype},[{var,{3829,7},'Pid'},{type,{3829,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,56,57,54>>}},{{function,port_control,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3852}],[<<112,111,114,116,95,99,111,110,116,114,111,108,47,51>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,32,111,110,32,97,32,112,111,114,116,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,97,110,100,32>>,{code,[],[<<68,97,116,97>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,44,32,116,104,97,116,32,105,115,44,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,78,111,116,32,97,108,108,32,112,111,114,116,32,100,114,105,118,101,114,115,32,115,117,112,112,111,114,116,32,116,104,105,115,32,99,111,110,116,114,111,108,32,102,101,97,116,117,114,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,46,46,50,53,53,44,32,111,114,32,97,32,98,105,110,97,114,121,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46,32,84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,100,97,116,97,32,97,108,115,111,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,111,112,101,110,32,112,111,114,116,32,111,114,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,97,110,32,111,112,101,110,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,99,97,110,110,111,116,32,102,105,116,32,105,110,32,97,32,51,50,45,98,105,116,32,105,110,116,101,103,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,110,99,104,114,111,110,111,117,115,32,99,111,110,116,114,111,108,32,111,112,101,114,97,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,115,111,32,100,101,99,105,100,101,115,32,102,111,114,32,97,110,121,32,114,101,97,115,111,110,32,40,112,114,111,98,97,98,108,121,32,115,111,109,101,116,104,105,110,103,32,119,114,111,110,103,32,119,105,116,104,32>>,{code,[],[<<79,112,101,114,97,116,105,111,110>>]},<<32,111,114,32>>,{code,[],[<<68,97,116,97>>]},<<41,46>>,{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<68,111,32,110,111,116,32,99,97,108,108,32>>,{code,[],[<<112,111,114,116,95,99,111,110,116,114,111,108,47,51>>]},<<32,119,105,116,104,32,97,110,32,117,110,107,110,111,119,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,101,120,112,101,99,116,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32,65,110,121,32,117,110,100,101,102,105,110,101,100,32,98,101,104,97,118,105,111,114,32,105,115,32,112,111,115,115,105,98,108,101,32,40,105,110,99,108,117,100,105,110,103,32,110,111,100,101,32,99,114,97,115,104,41,32,100,101,112,101,110,100,105,110,103,32,111,110,32,104,111,119,32,116,104,101,32,112,111,114,116,32,100,114,105,118,101,114,32,105,110,116,101,114,112,114,101,116,115,32,116,104,101,32,115,117,112,112,108,105,101,100,32,97,114,103,117,109,101,110,116,115,46>>]}]}]}]}]},#{signature => [{attribute,{3852,2},spec,{{port_control,3},[{type,{3852,19},bounded_fun,[{type,{3852,19},'fun',[{type,{3852,19},product,[{var,{3852,20},'Port'},{var,{3852,26},'Operation'},{var,{3852,37},'Data'}]},{type,{3852,46},union,[{type,{3852,46},iodata,[]},{type,{3852,57},binary,[]}]}]},[{type,{3853,7},constraint,[{atom,{3853,7},is_subtype},[{var,{3853,7},'Port'},{type,{3853,15},union,[{type,{3853,15},port,[]},{type,{3853,24},atom,[]}]}]]},{type,{3854,7},constraint,[{atom,{3854,7},is_subtype},[{var,{3854,7},'Operation'},{type,{3854,20},integer,[]}]]},{type,{3855,7},constraint,[{atom,{3855,7},is_subtype},[{var,{3855,7},'Data'},{type,{3855,15},iodata,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,53,57,54,53>>}},{{function,port_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3893}],[<<112,111,114,116,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,117,112,108,101,115,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32>>,{code,[],[<<80,111,114,116>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,111,112,101,110,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,110,100,32,97,108,108,32,116,104,101,32,116,117,112,108,101,115,32,97,114,101,32,110,111,116,32,109,97,110,100,97,116,111,114,121,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,49>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,99,111,110,116,97,105,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,58>>]},{ul,[],[{li,[],[{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,40,105,102,32,116,104,101,32,112,111,114,116,32,104,97,115,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,41>>]},{li,[],[{code,[],[<<105,100>>]}]},{li,[],[{code,[],[<<99,111,110,110,101,99,116,101,100>>]}]},{li,[],[{code,[],[<<108,105,110,107,115>>]}]},{li,[],[{code,[],[<<110,97,109,101>>]}]},{li,[],[{code,[],[<<105,110,112,117,116>>]}]},{li,[],[{code,[],[<<111,117,116,112,117,116>>]}]}]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32>>,{code,[],[<<73,116,101,109>>]},<<115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3893,2},spec,{{erlang,port_info,1},[{type,{3893,23},bounded_fun,[{type,{3893,23},'fun',[{type,{3893,23},product,[{var,{3893,24},'Port'}]},{var,{3893,33},'Result'}]},[{type,{3894,7},constraint,[{atom,{3894,7},is_subtype},[{var,{3894,7},'Port'},{type,{3894,15},union,[{type,{3894,15},port,[]},{type,{3894,24},atom,[]}]}]]},{type,{3895,7},constraint,[{atom,{3895,7},is_subtype},[{var,{3895,7},'ResultItem'},{type,{3895,21},union,[{type,{3895,21},tuple,[{atom,{3895,22},registered_name},{ann_type,{3895,39},[{var,{3895,39},'RegisteredName'},{type,{3895,57},atom,[]}]}]},{type,{3896,7},tuple,[{atom,{3896,8},id},{ann_type,{3896,12},[{var,{3896,12},'Index'},{type,{3896,21},non_neg_integer,[]}]}]},{type,{3897,7},tuple,[{atom,{3897,8},connected},{ann_type,{3897,19},[{var,{3897,19},'Pid'},{type,{3897,26},pid,[]}]}]},{type,{3898,7},tuple,[{atom,{3898,8},links},{ann_type,{3898,15},[{var,{3898,15},'Pids'},{type,{3898,23},list,[{type,{3898,24},pid,[]}]}]}]},{type,{3899,7},tuple,[{atom,{3899,8},name},{ann_type,{3899,14},[{var,{3899,14},'String'},{type,{3899,24},string,[]}]}]},{type,{3900,7},tuple,[{atom,{3900,8},input},{ann_type,{3900,15},[{var,{3900,15},'Bytes'},{type,{3900,24},non_neg_integer,[]}]}]},{type,{3901,7},tuple,[{atom,{3901,8},output},{ann_type,{3901,16},[{var,{3901,16},'Bytes'},{type,{3901,25},non_neg_integer,[]}]}]},{type,{3902,7},tuple,[{atom,{3902,8},os_pid},{ann_type,{3902,16},[{var,{3902,16},'OsPid'},{type,{3902,25},union,[{type,{3902,25},non_neg_integer,[]},{atom,{3902,45},undefined}]}]}]}]}]]},{type,{3903,7},constraint,[{atom,{3903,7},is_subtype},[{var,{3903,7},'Result'},{type,{3903,17},union,[{type,{3903,17},list,[{var,{3903,18},'ResultItem'}]},{atom,{3903,32},undefined}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,48,57>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,99,111,110,110,101,99,116,101,100,32,116,111,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3914,23},bounded_fun,[{type,{3914,23},'fun',[{type,{3914,23},product,[{var,{3914,24},'Port'},{atom,{3914,30},connected}]},{type,{3914,44},union,[{type,{3914,44},tuple,[{atom,{3914,45},connected},{var,{3914,56},'Pid'}]},{atom,{3914,63},undefined}]}]},[{type,{3915,7},constraint,[{atom,{3915,7},is_subtype},[{var,{3915,7},'Port'},{type,{3915,15},union,[{type,{3915,15},port,[]},{type,{3915,24},atom,[]}]}]]},{type,{3916,7},constraint,[{atom,{3916,7},is_subtype},[{var,{3916,7},'Pid'},{type,{3916,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,52,48>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<73,110,100,101,120>>]},<<32,105,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,105,110,100,101,120,32,111,102,32,116,104,101,32,112,111,114,116,46,32,84,104,105,115,32,105,110,100,101,120,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,101,112,97,114,97,116,101,32,112,111,114,116,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3917,9},bounded_fun,[{type,{3917,9},'fun',[{type,{3917,9},product,[{var,{3917,10},'Port'},{atom,{3917,16},id}]},{type,{3917,23},union,[{type,{3917,23},tuple,[{atom,{3917,24},id},{var,{3917,28},'Index'}]},{atom,{3917,37},undefined}]}]},[{type,{3918,7},constraint,[{atom,{3918,7},is_subtype},[{var,{3918,7},'Port'},{type,{3918,15},union,[{type,{3918,15},port,[]},{type,{3918,24},atom,[]}]}]]},{type,{3919,7},constraint,[{atom,{3919,7},is_subtype},[{var,{3919,7},'Index'},{type,{3919,16},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,53,54>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3920,9},bounded_fun,[{type,{3920,9},'fun',[{type,{3920,9},product,[{var,{3920,10},'Port'},{atom,{3920,16},input}]},{type,{3920,26},union,[{type,{3920,26},tuple,[{atom,{3920,27},input},{var,{3920,34},'Bytes'}]},{atom,{3920,43},undefined}]}]},[{type,{3921,7},constraint,[{atom,{3921,7},is_subtype},[{var,{3921,7},'Port'},{type,{3921,15},union,[{type,{3921,15},port,[]},{type,{3921,24},atom,[]}]}]]},{type,{3922,7},constraint,[{atom,{3922,7},is_subtype},[{var,{3922,7},'Bytes'},{type,{3922,16},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,55,50>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<80,105,100,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,116,104,101,32,112,111,114,116,32,105,115,32,108,105,110,107,101,100,32,116,111,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3923,9},bounded_fun,[{type,{3923,9},'fun',[{type,{3923,9},product,[{var,{3923,10},'Port'},{atom,{3923,16},links}]},{type,{3923,26},union,[{type,{3923,26},tuple,[{atom,{3923,27},links},{var,{3923,34},'Pids'}]},{atom,{3923,42},undefined}]}]},[{type,{3924,7},constraint,[{atom,{3924,7},is_subtype},[{var,{3924,7},'Port'},{type,{3924,15},union,[{type,{3924,15},port,[]},{type,{3924,24},atom,[]}]}]]},{type,{3925,7},constraint,[{atom,{3925,7},is_subtype},[{var,{3925,7},'Pids'},{type,{3925,15},list,[{type,{3925,16},pid,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,48,56,56>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<76,111,99,107,105,110,103>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<112,111,114,116,95,108,101,118,101,108>>]},<<32,40,112,111,114,116,45,115,112,101,99,105,102,105,99,32,108,111,99,107,105,110,103,41>>]},{li,[],[{code,[],[<<100,114,105,118,101,114,95,108,101,118,101,108>>]},<<32,40,100,114,105,118,101,114,45,115,112,101,99,105,102,105,99,32,108,111,99,107,105,110,103,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,114,101,115,117,108,116,115,32,97,114,101,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3926,9},bounded_fun,[{type,{3926,9},'fun',[{type,{3926,9},product,[{var,{3926,10},'Port'},{atom,{3926,16},locking}]},{type,{3926,28},union,[{type,{3926,28},tuple,[{atom,{3926,29},locking},{var,{3926,38},'Locking'}]},{atom,{3926,49},undefined}]}]},[{type,{3927,7},constraint,[{atom,{3927,7},is_subtype},[{var,{3927,7},'Port'},{type,{3927,15},union,[{type,{3927,15},port,[]},{type,{3927,24},atom,[]}]}]]},{type,{3928,7},constraint,[{atom,{3928,7},is_subtype},[{var,{3928,7},'Locking'},{type,{3928,18},union,[{atom,{3928,18},false},{atom,{3928,28},port_level},{atom,{3928,43},driver_level}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,48,52>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{a,[{id,<<112,111,114,116,95,105,110,102,111,95,109,101,109,111,114,121>>}],[]},{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,116,104,105,115,32,112,111,114,116,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,112,111,114,116,32,105,116,115,101,108,102,32,99,97,110,32,104,97,118,101,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,110,111,116,32,105,110,99,108,117,100,101,100,32,105,110,32>>,{code,[],[<<66,121,116,101,115>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3929,9},bounded_fun,[{type,{3929,9},'fun',[{type,{3929,9},product,[{var,{3929,10},'Port'},{atom,{3929,16},memory}]},{type,{3929,27},union,[{type,{3929,27},tuple,[{atom,{3929,28},memory},{var,{3929,36},'Bytes'}]},{atom,{3929,45},undefined}]}]},[{type,{3930,7},constraint,[{atom,{3930,7},is_subtype},[{var,{3930,7},'Port'},{type,{3930,15},union,[{type,{3930,15},port,[]},{type,{3930,24},atom,[]}]}]]},{type,{3931,7},constraint,[{atom,{3931,7},is_subtype},[{var,{3931,7},'Bytes'},{type,{3931,16},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,50,53>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<77,111,110,105,116,111,114,115>>]},<<32,114,101,112,114,101,115,101,110,116,32,112,114,111,99,101,115,115,101,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,116,104,105,115,32,112,111,114,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3932,9},bounded_fun,[{type,{3932,9},'fun',[{type,{3932,9},product,[{var,{3932,10},'Port'},{atom,{3932,16},monitors}]},{type,{3932,29},union,[{type,{3932,29},tuple,[{atom,{3932,30},monitors},{var,{3932,40},'Monitors'}]},{atom,{3932,52},undefined}]}]},[{type,{3933,7},constraint,[{atom,{3933,7},is_subtype},[{var,{3933,7},'Port'},{type,{3933,15},union,[{type,{3933,15},port,[]},{type,{3933,24},atom,[]}]}]]},{type,{3934,7},constraint,[{atom,{3934,7},is_subtype},[{var,{3934,7},'Monitors'},{type,{3934,19},list,[{type,{3934,20},tuple,[{atom,{3934,21},process},{type,{3934,30},pid,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,52,52>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,108,105,115,116,32,111,102,32,112,105,100,115,32,116,104,97,116,32,97,114,101,32,109,111,110,105,116,111,114,105,110,103,32,103,105,118,101,110,32,112,111,114,116,32,97,116,32,116,104,101,32,109,111,109,101,110,116,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3935,9},bounded_fun,[{type,{3935,9},'fun',[{type,{3935,9},product,[{var,{3935,10},'Port'},{atom,{3935,16},monitored_by}]},{type,{3935,33},union,[{type,{3935,33},tuple,[{atom,{3935,34},monitored_by},{var,{3935,48},'MonitoredBy'}]},{atom,{3935,63},undefined}]}]},[{type,{3936,7},constraint,[{atom,{3936,7},is_subtype},[{var,{3936,7},'Port'},{type,{3936,15},union,[{type,{3936,15},port,[]},{type,{3936,24},atom,[]}]}]]},{type,{3937,7},constraint,[{atom,{3937,7},is_subtype},[{var,{3937,7},'MonitoredBy'},{type,{3937,22},list,[{type,{3937,23},pid,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,54,48>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<78,97,109,101>>]},<<32,105,115,32,116,104,101,32,99,111,109,109,97,110,100,32,110,97,109,101,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,47,50>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3938,9},bounded_fun,[{type,{3938,9},'fun',[{type,{3938,9},product,[{var,{3938,10},'Port'},{atom,{3938,16},name}]},{type,{3938,25},union,[{type,{3938,25},tuple,[{atom,{3938,26},name},{var,{3938,32},'Name'}]},{atom,{3938,40},undefined}]}]},[{type,{3939,7},constraint,[{atom,{3939,7},is_subtype},[{var,{3939,7},'Port'},{type,{3939,15},union,[{type,{3939,15},port,[]},{type,{3939,24},atom,[]}]}]]},{type,{3940,7},constraint,[{atom,{3940,7},is_subtype},[{var,{3940,7},'Name'},{type,{3940,15},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,55,54>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<79,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,111,114,32,101,113,117,105,118,97,108,101,110,116,41,32,111,102,32,97,110,32,79,83,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,40,123,115,112,97,119,110,32,124,32,115,112,97,119,110,95,101,120,101,99,117,116,97,98,108,101,44,32,67,111,109,109,97,110,100,125,44,32,79,112,116,105,111,110,115,41>>]}]},<<46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,110,111,116,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,112,97,119,110,105,110,103,32,97,110,32,79,83,32,112,114,111,99,101,115,115,44,32,116,104,101,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3941,9},bounded_fun,[{type,{3941,9},'fun',[{type,{3941,9},product,[{var,{3941,10},'Port'},{atom,{3941,16},os_pid}]},{type,{3941,27},union,[{type,{3941,27},tuple,[{atom,{3941,28},os_pid},{var,{3941,36},'OsPid'}]},{atom,{3941,45},undefined}]}]},[{type,{3942,7},constraint,[{atom,{3942,7},is_subtype},[{var,{3942,7},'Port'},{type,{3942,15},union,[{type,{3942,15},port,[]},{type,{3942,24},atom,[]}]}]]},{type,{3943,7},constraint,[{atom,{3943,7},is_subtype},[{var,{3943,7},'OsPid'},{type,{3943,16},union,[{type,{3943,16},non_neg_integer,[]},{atom,{3943,36},undefined}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,49,57,50>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,112,111,114,116,32,102,114,111,109,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,99,111,109,109,97,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,50>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116,95,99,111,109,109,97,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,114,116,95,99,111,109,109,97,110,100,47,51>>]}]},<<44,32,111,114,32>>,{code,[],[<<80,111,114,116,32,33,32,123,79,119,110,101,114,44,32,123,99,111,109,109,97,110,100,44,32,68,97,116,97,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3944,9},bounded_fun,[{type,{3944,9},'fun',[{type,{3944,9},product,[{var,{3944,10},'Port'},{atom,{3944,16},output}]},{type,{3944,27},union,[{type,{3944,27},tuple,[{atom,{3944,28},output},{var,{3944,36},'Bytes'}]},{atom,{3944,45},undefined}]}]},[{type,{3945,7},constraint,[{atom,{3945,7},is_subtype},[{var,{3945,7},'Port'},{type,{3945,15},union,[{type,{3945,15},port,[]},{type,{3945,24},atom,[]}]}]]},{type,{3946,7},constraint,[{atom,{3946,7},is_subtype},[{var,{3946,7},'Bytes'},{type,{3946,16},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,49,49>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,111,111,108,101,97,110>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,32,104,105,110,116,32,117,115,101,100,32,98,121,32,116,104,105,115,32,112,111,114,116,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,97,114,97,108,108,101,108,105,115,109>>]}]},<<32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,111,112,101,110,95,112,111,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,95,112,111,114,116,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3947,9},bounded_fun,[{type,{3947,9},'fun',[{type,{3947,9},product,[{var,{3947,10},'Port'},{atom,{3947,16},parallelism}]},{type,{3947,32},union,[{type,{3947,32},tuple,[{atom,{3947,33},parallelism},{var,{3947,46},'Boolean'}]},{atom,{3947,57},undefined}]}]},[{type,{3948,7},constraint,[{atom,{3948,7},is_subtype},[{var,{3948,7},'Port'},{type,{3948,15},union,[{type,{3948,15},port,[]},{type,{3948,24},atom,[]}]}]]},{type,{3949,7},constraint,[{atom,{3949,7},is_subtype},[{var,{3949,7},'Boolean'},{type,{3949,18},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,51,48>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,113,117,101,117,101,100,32,98,121,32,116,104,101,32,112,111,114,116,32,117,115,105,110,103,32,116,104,101,32,69,82,84,83,32,100,114,105,118,101,114,32,113,117,101,117,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3950,9},bounded_fun,[{type,{3950,9},'fun',[{type,{3950,9},product,[{var,{3950,10},'Port'},{atom,{3950,16},queue_size}]},{type,{3950,31},union,[{type,{3950,31},tuple,[{atom,{3950,32},queue_size},{var,{3950,44},'Bytes'}]},{atom,{3950,53},undefined}]}]},[{type,{3951,7},constraint,[{atom,{3951,7},is_subtype},[{var,{3951,7},'Port'},{type,{3951,15},union,[{type,{3951,15},port,[]},{type,{3951,24},atom,[]}]}]]},{type,{3952,7},constraint,[{atom,{3952,7},is_subtype},[{var,{3952,7},'Bytes'},{type,{3952,16},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,52,49>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,port_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3914}],[<<112,111,114,116,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<82,101,103,105,115,116,101,114,101,100,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,111,102,32,116,104,101,32,112,111,114,116,46,32,73,102,32,116,104,101,32,112,111,114,116,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,111,112,101,110,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32,116,104,101,32,112,111,114,116,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,108,105,110,107,101,100,32,116,111,32,116,104,101,32,112,111,114,116,44,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,116,104,101,32,112,111,114,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<112,111,114,116,95,105,110,102,111,47,50>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{3914,2},spec,{{erlang,port_info,2},[{type,{3953,9},bounded_fun,[{type,{3953,9},'fun',[{type,{3953,9},product,[{var,{3953,10},'Port'},{atom,{3953,16},registered_name}]},{type,{3953,36},union,[{type,{3953,36},tuple,[{atom,{3953,37},registered_name},{var,{3953,54},'RegisteredName'}]},{type,{3953,72},nil,[]},{atom,{3953,77},undefined}]}]},[{type,{3954,7},constraint,[{atom,{3954,7},is_subtype},[{var,{3954,7},'Port'},{type,{3954,15},union,[{type,{3954,15},port,[]},{type,{3954,24},atom,[]}]}]]},{type,{3955,7},constraint,[{atom,{3955,7},is_subtype},[{var,{3955,7},'RegisteredName'},{type,{3955,25},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,53,56>>}},{{function,port_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1798}],[<<112,111,114,116,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]},#{signature => [{attribute,{1798,2},spec,{{port_to_list,1},[{type,{1798,19},bounded_fun,[{type,{1798,19},'fun',[{type,{1798,19},product,[{var,{1798,20},'Port'}]},{type,{1798,29},string,[]}]},[{type,{1799,7},constraint,[{atom,{1799,7},is_subtype},[{var,{1799,7},'Port'},{type,{1799,15},port,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,55,53>>}},{{function,ports,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1804}],[<<112,111,114,116,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,97,108,108,32,116,104,101,32,112,111,114,116,115,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,32,101,120,105,116,105,110,103,32,112,111,114,116,32,101,120,105,115,116,115,44,32,98,117,116,32,105,115,32,110,111,116,32,111,112,101,110,46>>]}]},#{signature => [{attribute,{1804,2},spec,{{erlang,ports,0},[{type,{1804,19},'fun',[{type,{1804,19},product,[]},{type,{1804,25},list,[{type,{1804,26},port,[]}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,56,52>>}},{{function,pre_loaded,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1950}],[<<112,114,101,95,108,111,97,100,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,116,104,97,116,32,97,114,101,32,112,114,101,108,111,97,100,101,100,32,105,110,32,116,104,101,32,114,117,110,45,116,105,109,101,32,115,121,115,116,101,109,46,32,80,114,101,45,108,111,97,100,101,100,32,109,111,100,117,108,101,115,32,97,114,101,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,116,104,97,116,32,97,114,101,32,110,101,101,100,101,100,32,116,111,32,98,111,111,116,115,116,114,97,112,32,116,104,101,32,115,121,115,116,101,109,32,116,111,32,108,111,97,100,32,116,104,101,32,102,105,114,115,116,32,69,114,108,97,110,103,32,109,111,100,117,108,101,115,32,102,114,111,109,32,101,105,116,104,101,114,32,100,105,115,107,32,111,114,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,101,114,108,95,98,111,111,116,95,115,101,114,118,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,98,111,111,116,95,115,101,114,118,101,114>>]}]},<<46>>]}]},#{signature => [{attribute,{1950,2},spec,{{pre_loaded,0},[{type,{1950,17},'fun',[{type,{1950,17},product,[]},{type,{1950,23},list,[{type,{1950,24},module,[]}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,50,57,52>>}},{{function,process_display,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1955}],[<<112,114,111,99,101,115,115,95,100,105,115,112,108,97,121,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<32,111,110,32,115,116,97,110,100,97,114,100,32,101,114,114,111,114,46,32,84,104,101,32,111,110,108,121,32,97,108,108,111,119,101,100,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<98,97,99,107,116,114,97,99,101>>]},<<44,32,119,104,105,99,104,32,115,104,111,119,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,99,97,108,108,32,115,116,97,99,107,44,32,105,110,99,108,117,100,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,97,108,108,32,99,104,97,105,110,44,32,119,105,116,104,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,112,114,105,110,116,101,100,32,102,105,114,115,116,46,32,84,104,101,32,102,111,114,109,97,116,32,111,102,32,116,104,101,32,111,117,116,112,117,116,32,105,115,32,110,111,116,32,102,117,114,116,104,101,114,32,100,101,102,105,110,101,100,46>>]}]},#{signature => [{attribute,{1955,2},spec,{{erlang,process_display,2},[{type,{1955,29},bounded_fun,[{type,{1955,29},'fun',[{type,{1955,29},product,[{var,{1955,30},'Pid'},{var,{1955,35},'Type'}]},{atom,{1955,44},true}]},[{type,{1956,7},constraint,[{atom,{1956,7},is_subtype},[{var,{1956,7},'Pid'},{type,{1956,14},pid,[]}]]},{type,{1957,7},constraint,[{atom,{1957,7},is_subtype},[{var,{1957,7},'Type'},{atom,{1957,15},backtrace}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,48,54>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<69,110,97,98,108,101,32,111,114,32,100,105,115,97,98,108,101,32>>,{i,[],[<<102,117,108,108,121,32,97,115,121,110,99,104,114,111,110,111,117,115,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,105,110,103>>]},<<32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,87,104,101,110,32,100,105,115,97,98,108,101,100,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,44,32,116,104,101,32,112,114,111,99,101,115,115,32,115,101,110,100,105,110,103,32,97,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,32,119,105,108,108,32,98,108,111,99,107,32,105,110,32,116,104,101,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,32,105,102,32,116,104,101,32,98,117,102,102,101,114,32,102,111,114,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,114,101,97,99,104,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,100,98,98,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<100,105,115,116,114,105,98,117,116,105,111,110,32,98,117,102,102,101,114,32,98,117,115,121,32,108,105,109,105,116>>]},<<46,32,84,104,101,32,112,114,111,99,101,115,115,32,119,105,108,108,32,114,101,109,97,105,110,32,98,108,111,99,107,101,100,32,117,110,116,105,108,32,116,104,101,32,98,117,102,102,101,114,32,115,104,114,105,110,107,115,32,101,110,111,117,103,104,46,32,84,104,105,115,32,109,105,103,104,116,32,105,110,32,115,111,109,101,32,99,97,115,101,115,32,116,97,107,101,32,97,32,115,117,98,115,116,97,110,116,105,97,108,32,97,109,111,117,110,116,32,111,102,32,116,105,109,101,46,32,87,104,101,110,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,105,115,32,101,110,97,98,108,101,100,44,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,115,32,111,102,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,32,119,105,108,108,32,97,108,119,97,121,115,32,98,117,102,102,101,114,32,116,104,101,32,115,105,103,110,97,108,32,111,110,32,116,104,101,32,111,117,116,103,111,105,110,103,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,32,97,110,100,32,116,104,101,110,32,105,109,109,101,100,105,97,116,101,108,121,32,114,101,116,117,114,110,46,32,84,104,97,116,32,105,115,44,32,116,104,101,115,101,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,115,32,119,105,108,108,32>>,{em,[],[<<110,101,118,101,114>>]},<<32,98,108,111,99,107,32,116,104,101,32,115,101,110,100,105,110,103,32,112,114,111,99,101,115,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<83,105,110,99,101,32,110,111,32,102,108,111,119,32,99,111,110,116,114,111,108,32,105,115,32,101,110,102,111,114,99,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,104,101,110,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,105,115,32,101,110,97,98,108,101,100,44,32,121,111,117,32,110,101,101,100,32,116,111,32,109,97,107,101,32,115,117,114,101,32,116,104,97,116,32,102,108,111,119,32,99,111,110,116,114,111,108,32,102,111,114,32,115,117,99,104,32,100,97,116,97,32,105,115,32,105,109,112,108,101,109,101,110,116,101,100,44,32,111,114,32,116,104,97,116,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,115,117,99,104,32,100,97,116,97,32,105,115,32,107,110,111,119,110,32,116,111,32,97,108,119,97,121,115,32,98,101,32,108,105,109,105,116,101,100,46,32,85,110,108,105,109,105,116,101,100,32,115,105,103,110,97,108,105,110,103,32,119,105,116,104,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,101,110,97,98,108,101,100,32,105,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,102,108,111,119,32,99,111,110,116,114,111,108,32,119,105,108,108,32,116,121,112,105,99,97,108,108,121,32,99,97,117,115,101,32,116,104,101,32,115,101,110,100,105,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,111,32,99,114,97,115,104,32,111,110,32,97,110,32,111,117,116,32,111,102,32,109,101,109,111,114,121,32,99,111,110,100,105,116,105,111,110,46>>]}]},{p,[],[<<66,108,111,99,107,105,110,103,32,100,117,101,32,116,111,32,100,105,115,97,98,108,101,100,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,99,97,110,32,98,101,32,109,111,110,105,116,111,114,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,40,41>>]}]},<<32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,117,115,121,95,100,105,115,116,95,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<98,117,115,121,95,100,105,115,116,95,112,111,114,116>>]}]},<<32,111,112,116,105,111,110,46,32,79,110,108,121,32,100,97,116,97,32,98,117,102,102,101,114,101,100,32,98,121,32,112,114,111,99,101,115,115,101,115,32,119,104,105,99,104,32,40,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,115,101,110,100,105,110,103,32,97,32,115,105,103,110,97,108,41,32,104,97,118,101,32,100,105,115,97,98,108,101,100,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,119,105,108,108,32,98,101,32,99,111,117,110,116,101,100,32,119,104,101,110,32,100,101,116,101,114,109,105,110,105,110,103,32,119,104,101,116,104,101,114,32,111,114,32,110,111,116,32,97,110,32,111,112,101,114,97,116,105,111,110,32,115,104,111,117,108,100,32,98,108,111,99,107,32,116,104,101,32,99,97,108,108,101,114,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,102,108,97,103,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,111,110,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,119,104,101,110,32,115,112,97,119,110,105,110,103,32,105,116,32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,40,41>>]}]},<<32,66,73,70,32,119,105,116,104,32,116,104,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<123,97,115,121,110,99,95,100,105,115,116,44,32,69,110,97,98,108,101,125>>]}]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,102,108,97,103,32,116,111,32,117,115,101,32,111,110,32,110,101,119,108,121,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,116,104,101,32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,112,97,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,112,97,100,32,60,98,111,111,108,101,97,110,62>>]}]},<<32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,73,102,32,116,104,101,32>>,{code,[],[<<43,112,97,100,32,60,98,111,111,108,101,97,110,62>>]},<<32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,32,105,115,32,110,111,116,32,112,97,115,115,101,100,44,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,102,108,97,103,32,119,105,108,108,32,98,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<89,111,117,32,99,97,110,32,105,110,115,112,101,99,116,32,116,104,101,32,115,116,97,116,101,32,111,102,32,116,104,101,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,111,102,32,97,32,112,114,111,99,101,115,115,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,97,115,121,110,99,95,100,105,115,116,41>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]},<<32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2644,19},bounded_fun,[{type,{2644,19},'fun',[{type,{2644,19},product,[{atom,{2644,20},async_dist},{var,{2644,32},'Boolean'}]},{var,{2644,44},'OldBoolean'}]},[{type,{2645,7},constraint,[{atom,{2645,7},is_subtype},[{var,{2645,7},'Boolean'},{type,{2645,18},boolean,[]}]]},{type,{2646,7},constraint,[{atom,{2646,7},is_subtype},[{var,{2646,7},'OldBoolean'},{type,{2646,21},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,50,48>>,since => <<79,84,80,32,50,53,46,51>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<87,104,101,110,32>>,{code,[],[<<116,114,97,112,95,101,120,105,116>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,101,120,105,116,32,115,105,103,110,97,108,115,32,97,114,114,105,118,105,110,103,32,116,111,32,97,32,112,114,111,99,101,115,115,32,97,114,101,32,99,111,110,118,101,114,116,101,100,32,116,111,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,70,114,111,109,44,32,82,101,97,115,111,110,125>>]},<<32,109,101,115,115,97,103,101,115,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,114,101,99,101,105,118,101,100,32,97,115,32,111,114,100,105,110,97,114,121,32,109,101,115,115,97,103,101,115,46,32,73,102,32>>,{code,[],[<<116,114,97,112,95,101,120,105,116>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,105,102,32,105,116,32,114,101,99,101,105,118,101,115,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,111,116,104,101,114,32,116,104,97,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32,116,104,101,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,112,114,111,112,97,103,97,116,101,100,32,116,111,32,105,116,115,32,108,105,110,107,101,100,32,112,114,111,99,101,115,115,101,115,46,32,65,112,112,108,105,99,97,116,105,111,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,110,111,114,109,97,108,108,121,32,110,111,116,32,116,111,32,116,114,97,112,32,101,120,105,116,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,120,105,116,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2647,19},bounded_fun,[{type,{2647,19},'fun',[{type,{2647,19},product,[{atom,{2647,20},trap_exit},{var,{2647,31},'Boolean'}]},{var,{2647,43},'OldBoolean'}]},[{type,{2648,7},constraint,[{atom,{2648,7},is_subtype},[{var,{2648,7},'Boolean'},{type,{2648,18},boolean,[]}]]},{type,{2649,7},constraint,[{atom,{2649,7},is_subtype},[{var,{2649,7},'OldBoolean'},{type,{2649,21},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,51,56,50>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<85,115,101,100,32,98,121,32,97,32,112,114,111,99,101,115,115,32,116,111,32,114,101,100,101,102,105,110,101,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,102,111,114,32,117,110,100,101,102,105,110,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,110,100,32,117,110,100,101,102,105,110,101,100,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,101,115,46,32,73,110,101,120,112,101,114,105,101,110,99,101,100,32,117,115,101,114,115,32,97,114,101,32,110,111,116,32,116,111,32,117,115,101,32,116,104,105,115,32,102,108,97,103,44,32,97,115,32,99,111,100,101,32,97,117,116,111,45,108,111,97,100,105,110,103,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,99,111,114,114,101,99,116,32,111,112,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,32,109,111,100,117,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2650,19},bounded_fun,[{type,{2650,19},'fun',[{type,{2650,19},product,[{atom,{2650,20},error_handler},{var,{2650,35},'Module'}]},{var,{2650,46},'OldModule'}]},[{type,{2651,7},constraint,[{atom,{2651,7},is_subtype},[{var,{2651,7},'Module'},{type,{2651,17},atom,[]}]]},{type,{2652,7},constraint,[{atom,{2652,7},is_subtype},[{var,{2652,7},'OldModule'},{type,{2652,20},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,48,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,103,101,110,101,114,97,116,105,111,110,97,108,32,99,111,108,108,101,99,116,105,111,110,115,32,98,101,102,111,114,101,32,102,111,114,99,105,110,103,32,97,32,102,117,108,108,115,119,101,101,112,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2653,19},bounded_fun,[{type,{2653,19},'fun',[{type,{2653,19},product,[{atom,{2653,20},fullsweep_after},{var,{2653,37},'FullsweepAfter'}]},{var,{2653,56},'OldFullsweepAfter'}]},[{type,{2654,7},constraint,[{atom,{2654,7},is_subtype},[{var,{2654,7},'FullsweepAfter'},{type,{2654,25},non_neg_integer,[]}]]},{type,{2655,7},constraint,[{atom,{2655,7},is_subtype},[{var,{2655,7},'OldFullsweepAfter'},{type,{2655,28},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,49,52>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2656,19},bounded_fun,[{type,{2656,19},'fun',[{type,{2656,19},product,[{atom,{2656,20},min_heap_size},{var,{2656,35},'MinHeapSize'}]},{var,{2656,51},'OldMinHeapSize'}]},[{type,{2657,7},constraint,[{atom,{2657,7},is_subtype},[{var,{2657,7},'MinHeapSize'},{type,{2657,22},non_neg_integer,[]}]]},{type,{2658,7},constraint,[{atom,{2658,7},is_subtype},[{var,{2658,7},'OldMinHeapSize'},{type,{2658,25},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,50,53>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2659,19},bounded_fun,[{type,{2659,19},'fun',[{type,{2659,19},product,[{atom,{2659,20},min_bin_vheap_size},{var,{2659,40},'MinBinVHeapSize'}]},{var,{2659,60},'OldMinBinVHeapSize'}]},[{type,{2660,7},constraint,[{atom,{2660,7},is_subtype},[{var,{2660,7},'MinBinVHeapSize'},{type,{2660,26},non_neg_integer,[]}]]},{type,{2661,7},constraint,[{atom,{2661,7},is_subtype},[{var,{2661,7},'OldMinBinVHeapSize'},{type,{2661,29},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,51,54>>,since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]}]},{p,[],[<<84,104,105,115,32,102,108,97,103,32,115,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,73,102,32>>,{code,[],[<<77,97,120,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<107,105,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]},<<32,97,114,101,32,117,115,101,100,46>>]},{p,[],[<<70,111,114,32,100,101,116,97,105,108,115,32,111,110,32,104,111,119,32,116,104,101,32,104,101,97,112,32,103,114,111,119,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,71,97,114,98,97,103,101,67,111,108,108,101,99,116,105,111,110,35,115,105,122,105,110,103,45,116,104,101,45,104,101,97,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,105,122,105,110,103,32,116,104,101,32,104,101,97,112>>]},<<32,105,110,32,116,104,101,32,69,82,84,83,32,105,110,116,101,114,110,97,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,46>>]},{dl,[],[{dt,[],[{code,[],[<<115,105,122,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,115,105,122,101,32,105,110,32,119,111,114,100,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,73,102,32,115,101,116,32,116,111,32,122,101,114,111,44,32,116,104,101,32,104,101,97,112,32,115,105,122,101,32,108,105,109,105,116,32,105,115,32,100,105,115,97,98,108,101,100,46,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,115,32,98,101,32,116,104,114,111,119,110,32,105,102,32,116,104,101,32,118,97,108,117,101,32,105,115,32,115,109,97,108,108,101,114,32,116,104,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},<<46,32,84,104,101,32,115,105,122,101,32,99,104,101,99,107,32,105,115,32,111,110,108,121,32,100,111,110,101,32,119,104,101,110,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,116,114,105,103,103,101,114,101,100,46>>]},{p,[],[{code,[],[<<115,105,122,101>>]},<<32,105,115,32,116,104,101,32,101,110,116,105,114,101,32,104,101,97,112,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,119,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,116,114,105,103,103,101,114,101,100,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,97,108,108,32,103,101,110,101,114,97,116,105,111,110,97,108,32,104,101,97,112,115,44,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,44,32,97,110,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,101,115,115,97,103,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112>>]},<<44,32,97,110,100,32,97,110,121,32,101,120,116,114,97,32,109,101,109,111,114,121,32,116,104,97,116,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,111,114,32,110,101,101,100,115,32,100,117,114,105,110,103,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[{code,[],[<<115,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,95,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101,41>>]}]},<<44,32,111,114,32,98,121,32,97,100,100,105,110,103,32>>,{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<32,97,110,100,32>>,{code,[],[<<109,98,117,102,95,115,105,122,101>>]},<<32,102,114,111,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<107,105,108,108>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,101,110,100,115,32,97,110,32,117,110,116,114,97,112,112,97,98,108,101,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<107,105,108,108>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,102,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,105,115,32,114,101,97,99,104,101,100,46,32,84,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,116,104,97,116,32,116,114,105,103,103,101,114,101,100,32,116,104,101,32>>,{code,[],[<<107,105,108,108>>]},<<32,105,115,32,110,111,116,32,99,111,109,112,108,101,116,101,100,44,32,105,110,115,116,101,97,100,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,97,115,32,115,111,111,110,32,97,115,32,112,111,115,115,105,98,108,101,46,32,87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,110,111,32,101,120,105,116,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,44,32,105,110,115,116,101,97,100,32,105,116,32,99,111,110,116,105,110,117,101,115,32,101,120,101,99,117,116,105,110,103,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<107,105,108,108>>]},<<32,105,115,32,110,111,116,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,109,97,112,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,119,105,108,108,32,98,101,32,117,115,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,101,105,116,104,101,114,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,104,109,97,120,107>>]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,108,111,103,115,32,97,110,32,101,114,114,111,114,32,101,118,101,110,116,32,118,105,97,32>>,{a,[{href,<<107,101,114,110,101,108,58,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,103,101,114>>]}]},<<44,32,99,111,110,116,97,105,110,105,110,103,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,119,104,101,110,32,116,104,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,105,115,32,114,101,97,99,104,101,100,46,32,79,110,101,32,108,111,103,32,101,118,101,110,116,32,105,115,32,115,101,110,116,32,101,97,99,104,32,116,105,109,101,32,116,104,101,32,108,105,109,105,116,32,105,115,32,114,101,97,99,104,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<101,114,114,111,114,95,108,111,103,103,101,114>>]},<<32,105,115,32,110,111,116,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,109,97,112,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32,117,115,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,101,105,116,104,101,114,32,116,104,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,104,109,97,120,101,108>>]},<<32,105,110,116,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<105,110,99,108,117,100,101,95,115,104,97,114,101,100,95,98,105,110,97,114,105,101,115>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32,115,101,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,97,114,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,116,111,116,97,108,32,115,117,109,32,99,111,109,112,97,114,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32>>,{code,[],[<<115,105,122,101>>]},<<32,108,105,109,105,116,46,32,79,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,97,114,101,32,116,121,112,105,99,97,108,108,121,32,108,97,114,103,101,114,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,109,97,121,32,98,101,32,115,104,97,114,101,100,32,98,101,116,119,101,101,110,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,111,102,32,97,32,115,104,97,114,101,100,32,98,105,110,97,114,121,32,105,115,32,105,110,99,108,117,100,101,100,32,98,121,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,114,105,110,103,32,105,116,46,32,65,108,115,111,44,32,116,104,101,32,101,110,116,105,114,101,32,115,105,122,101,32,111,102,32,97,32,108,97,114,103,101,32,98,105,110,97,114,121,32,109,97,121,32,98,101,32,105,110,99,108,117,100,101,100,32,101,118,101,110,32,105,102,32,111,110,108,121,32,97,32,115,109,97,108,108,101,114,32,112,97,114,116,32,111,102,32,105,116,32,105,115,32,114,101,102,101,114,114,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<105,110,99,108,117,100,101,95,115,104,97,114,101,100,95,98,105,110,97,114,105,101,115>>]},<<32,105,115,32,110,111,116,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,109,97,112,44,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32,117,115,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,101,105,116,104,101,114,32,116,104,101,32,111,112,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,105,98>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,104,109,97,120,105,98>>]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,104,101,97,112,32,115,105,122,101,32,111,102,32,97,32,112,114,111,99,101,115,115,32,105,115,32,113,117,105,116,101,32,104,97,114,100,32,116,111,32,112,114,101,100,105,99,116,44,32,101,115,112,101,99,105,97,108,108,121,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,116,104,97,116,32,105,115,32,117,115,101,100,32,100,117,114,105,110,103,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,99,111,110,116,101,109,112,108,97,116,105,110,103,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,102,105,114,115,116,32,114,117,110,32,105,116,32,105,110,32,112,114,111,100,117,99,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<107,105,108,108>>]},<<32,115,101,116,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,97,110,100,32,105,110,115,112,101,99,116,32,116,104,101,32,108,111,103,32,101,118,101,110,116,115,32,116,111,32,115,101,101,32,119,104,97,116,32,116,104,101,32,110,111,114,109,97,108,32,112,101,97,107,32,115,105,122,101,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,105,115,32,97,110,100,32,116,104,101,110,32,116,117,110,101,32,116,104,101,32,118,97,108,117,101,32,97,99,99,111,114,100,105,110,103,108,121,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2662,19},bounded_fun,[{type,{2662,19},'fun',[{type,{2662,19},product,[{atom,{2662,20},max_heap_size},{var,{2662,35},'MaxHeapSize'}]},{var,{2662,51},'OldMaxHeapSize'}]},[{type,{2663,7},constraint,[{atom,{2663,7},is_subtype},[{var,{2663,7},'MaxHeapSize'},{user_type,{2663,22},max_heap_size,[]}]]},{type,{2664,7},constraint,[{atom,{2664,7},is_subtype},[{var,{2664,7},'OldMaxHeapSize'},{user_type,{2664,25},max_heap_size,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,52,52,55>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]}]},{p,[],[<<68,101,116,101,114,109,105,110,101,115,32,104,111,119,32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,114,101,32,115,116,111,114,101,100,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,102,102,95,104,101,97,112>>]}]},{dd,[],[{p,[],[{em,[],[<<65,108,108>>]},<<32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,98,101,32,115,116,111,114,101,100,32,111,117,116,115,105,100,101,32,116,104,101,32,112,114,111,99,101,115,115,32,104,101,97,112,46,32,84,104,105,115,32,105,109,112,108,105,101,115,32,116,104,97,116,32>>,{em,[],[<<110,111>>]},<<32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,98,101,32,112,97,114,116,32,111,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<111,110,95,104,101,97,112>>]}]},{dd,[],[{p,[],[<<65,108,108,32,109,101,115,115,97,103,101,115,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,119,105,108,108,32,101,118,101,110,116,117,97,108,108,121,32,98,101,32,112,108,97,99,101,100,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,104,101,97,112,46,32,84,104,101,121,32,99,97,110,44,32,104,111,119,101,118,101,114,44,32,98,101,32,116,101,109,112,111,114,97,114,105,108,121,32,115,116,111,114,101,100,32,111,102,102,32,116,104,101,32,104,101,97,112,46,32,84,104,105,115,32,105,115,32,104,111,119,32,109,101,115,115,97,103,101,115,32,104,97,118,101,32,97,108,119,97,121,115,32,98,101,101,110,32,115,116,111,114,101,100,32,117,112,32,117,110,116,105,108,32,69,82,84,83,32,56,46,48,46>>]}]}]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,109,97,121,32,112,111,116,101,110,116,105,97,108,108,121,32,97,99,99,117,109,117,108,97,116,101,32,97,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,109,101,115,115,97,103,101,115,32,105,110,32,105,116,115,32,113,117,101,117,101,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,115,101,116,32,116,104,101,32,102,108,97,103,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<46,32,84,104,105,115,32,105,115,32,100,117,101,32,116,111,32,116,104,101,32,102,97,99,116,32,116,104,97,116,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,97,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,109,101,115,115,97,103,101,115,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,104,101,97,112,32,99,97,110,32,98,101,99,111,109,101,32,101,120,116,114,101,109,101,108,121,32,101,120,112,101,110,115,105,118,101,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,110,32,99,111,110,115,117,109,101,32,108,97,114,103,101,32,97,109,111,117,110,116,115,32,111,102,32,109,101,109,111,114,121,46,32,84,104,101,32,112,101,114,102,111,114,109,97,110,99,101,32,111,102,32,116,104,101,32,97,99,116,117,97,108,32,109,101,115,115,97,103,101,32,112,97,115,115,105,110,103,32,105,115,44,32,104,111,119,101,118,101,114,44,32,103,101,110,101,114,97,108,108,121,32,98,101,116,116,101,114,32,119,104,101,110,32,116,104,101,32,102,108,97,103,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46>>]},{p,[],[<<67,104,97,110,103,105,110,103,32,116,104,101,32,102,108,97,103,32,118,97,108,117,101,32,99,97,117,115,101,115,32,97,110,121,32,101,120,105,115,116,105,110,103,32,109,101,115,115,97,103,101,115,32,116,111,32,98,101,32,109,111,118,101,100,46,32,84,104,101,32,109,111,118,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,105,110,105,116,105,97,116,101,100,44,32,98,117,116,32,110,111,116,32,110,101,99,101,115,115,97,114,105,108,121,32,99,111,109,112,108,101,116,101,100,44,32,98,121,32,116,104,101,32,116,105,109,101,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2665,19},bounded_fun,[{type,{2665,19},'fun',[{type,{2665,19},product,[{atom,{2665,20},message_queue_data},{var,{2665,40},'MQD'}]},{var,{2665,48},'OldMQD'}]},[{type,{2666,7},constraint,[{atom,{2666,7},is_subtype},[{var,{2666,7},'MQD'},{user_type,{2666,14},message_queue_data,[]}]]},{type,{2667,7},constraint,[{atom,{2667,7},is_subtype},[{var,{2667,7},'OldMQD'},{user_type,{2667,17},message_queue_data,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,52,54>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,112,114,105,111,114,105,116,121,46,32>>,{code,[],[<<76,101,118,101,108>>]},<<32,105,115,32,97,110,32,97,116,111,109,46,32,70,111,117,114,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,115,32,101,120,105,115,116,58,32>>,{code,[],[<<108,111,119>>]},<<44,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<44,32>>,{code,[],[<<104,105,103,104>>]},<<44,32,97,110,100,32>>,{code,[],[<<109,97,120>>]},<<46,32,68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<80,114,105,111,114,105,116,121,32,108,101,118,101,108,32>>,{code,[],[<<109,97,120>>]},<<32,105,115,32,114,101,115,101,114,118,101,100,32,102,111,114,32,105,110,116,101,114,110,97,108,32,117,115,101,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,44,32,97,110,100,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,98,101,32,117,115,101,100,32,98,121,32,111,116,104,101,114,115,46>>]}]},{p,[],[<<73,110,116,101,114,110,97,108,108,121,32,105,110,32,101,97,99,104,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,44,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,115,99,104,101,100,117,108,101,100,32,105,110,32,97,32,114,111,117,110,100,32,114,111,98,105,110,32,102,97,115,104,105,111,110,46>>]},{p,[],[<<69,120,101,99,117,116,105,111,110,32,111,102,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<108,111,119>>]},<<32,97,114,101,32,105,110,116,101,114,108,101,97,118,101,100,46,32,80,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,108,101,115,115,32,102,114,101,113,117,101,110,116,108,121,32,116,104,97,110,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,97,98,108,101,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<32,101,120,105,115,116,44,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,111,114,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46,32,78,111,116,105,99,101,32,104,111,119,101,118,101,114,32,116,104,97,116,32,116,104,105,115,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,109,101,97,110,32,116,104,97,116,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<32,111,114,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,99,97,110,32,114,117,110,32,119,104,101,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,114,117,110,110,105,110,103,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,87,104,101,110,32,117,115,105,110,103,32,109,117,108,116,105,112,108,101,32,115,99,104,101,100,117,108,101,114,115,44,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,32,99,97,110,32,98,101,32,114,117,110,110,105,110,103,32,105,110,32,112,97,114,97,108,108,101,108,32,116,104,97,110,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,84,104,97,116,32,105,115,44,32,97,32>>,{code,[],[<<108,111,119>>]},<<32,97,110,100,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,99,97,110,32,101,120,101,99,117,116,101,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,97,98,108,101,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<109,97,120>>]},<<32,101,120,105,115,116,44,32,110,111,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<108,111,119>>]},<<44,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<44,32,111,114,32>>,{code,[],[<<104,105,103,104>>]},<<32,97,114,101,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46,32,65,115,32,119,105,116,104,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<44,32,112,114,111,99,101,115,115,101,115,32,111,110,32,108,111,119,101,114,32,112,114,105,111,114,105,116,105,101,115,32,99,97,110,32,101,120,101,99,117,116,101,32,105,110,32,112,97,114,97,108,108,101,108,32,119,105,116,104,32,112,114,111,99,101,115,115,101,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<109,97,120>>]},<<46>>]},{p,[],[<<83,99,104,101,100,117,108,105,110,103,32,105,115,32,112,114,101,45,101,109,112,116,105,118,101,46,32,82,101,103,97,114,100,108,101,115,115,32,111,102,32,112,114,105,111,114,105,116,121,44,32,97,32,112,114,111,99,101,115,115,32,105,115,32,112,114,101,45,101,109,112,116,101,100,32,119,104,101,110,32,105,116,32,104,97,115,32,99,111,110,115,117,109,101,100,32,109,111,114,101,32,116,104,97,110,32,97,32,99,101,114,116,97,105,110,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,105,116,32,119,97,115,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,115,99,104,101,100,117,108,105,110,103,32,116,111,32,114,101,109,97,105,110,32,101,120,97,99,116,108,121,32,97,115,32,105,116,32,105,115,32,116,111,100,97,121,46,32,83,99,104,101,100,117,108,105,110,103,32,105,115,32,108,105,107,101,108,121,32,116,111,32,98,101,32,99,104,97,110,103,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,32,116,111,32,117,115,101,32,97,118,97,105,108,97,98,108,101,32,112,114,111,99,101,115,115,111,114,32,99,111,114,101,115,32,98,101,116,116,101,114,46>>]}]},{p,[],[<<84,104,101,114,101,32,105,115,32>>,{em,[],[<<110,111>>]},<<32,97,117,116,111,109,97,116,105,99,32,109,101,99,104,97,110,105,115,109,32,102,111,114,32,97,118,111,105,100,105,110,103,32,112,114,105,111,114,105,116,121,32,105,110,118,101,114,115,105,111,110,44,32,115,117,99,104,32,97,115,32,112,114,105,111,114,105,116,121,32,105,110,104,101,114,105,116,97,110,99,101,32,111,114,32,112,114,105,111,114,105,116,121,32,99,101,105,108,105,110,103,115,46,32,87,104,101,110,32,117,115,105,110,103,32,112,114,105,111,114,105,116,105,101,115,44,32,116,97,107,101,32,116,104,105,115,32,105,110,116,111,32,97,99,99,111,117,110,116,32,97,110,100,32,104,97,110,100,108,101,32,115,117,99,104,32,115,99,101,110,97,114,105,111,115,32,98,121,32,121,111,117,114,115,101,108,102,46>>]},{p,[],[<<77,97,107,105,110,103,32,99,97,108,108,115,32,102,114,111,109,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,105,110,116,111,32,99,111,100,101,32,116,104,97,116,32,121,111,117,32,104,97,115,32,110,111,32,99,111,110,116,114,111,108,32,111,118,101,114,32,99,97,110,32,99,97,117,115,101,32,116,104,101,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,116,111,32,119,97,105,116,32,102,111,114,32,97,32,112,114,111,99,101,115,115,32,119,105,116,104,32,108,111,119,101,114,32,112,114,105,111,114,105,116,121,46,32,84,104,97,116,32,105,115,44,32,101,102,102,101,99,116,105,118,101,108,121,32,100,101,99,114,101,97,115,105,110,103,32,116,104,101,32,112,114,105,111,114,105,116,121,32,111,102,32,116,104,101,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,100,117,114,105,110,103,32,116,104,101,32,99,97,108,108,46,32,69,118,101,110,32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,116,104,101,32,99,97,115,101,32,119,105,116,104,32,111,110,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,100,101,32,116,104,97,116,32,121,111,117,32,104,97,118,101,32,110,111,32,99,111,110,116,114,111,108,32,111,118,101,114,44,32,105,116,32,99,97,110,32,98,101,32,116,104,101,32,99,97,115,101,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,105,116,46,32,84,104,105,115,32,99,97,110,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,111,99,99,117,114,32,105,102,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,116,114,105,103,103,101,114,115,32,99,111,100,101,32,108,111,97,100,105,110,103,44,32,97,115,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,114,117,110,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<79,116,104,101,114,32,112,114,105,111,114,105,116,105,101,115,32,116,104,97,110,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<32,97,114,101,32,110,111,114,109,97,108,108,121,32,110,111,116,32,110,101,101,100,101,100,46,32,87,104,101,110,32,111,116,104,101,114,32,112,114,105,111,114,105,116,105,101,115,32,97,114,101,32,117,115,101,100,44,32,117,115,101,32,116,104,101,109,32,119,105,116,104,32,99,97,114,101,44,32>>,{em,[],[<<101,115,112,101,99,105,97,108,108,121>>]},<<32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<46,32,65,32,112,114,111,99,101,115,115,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<104,105,103,104>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,112,101,114,102,111,114,109,32,119,111,114,107,32,102,111,114,32,115,104,111,114,116,32,112,101,114,105,111,100,115,46,32,66,117,115,121,32,108,111,111,112,105,110,103,32,102,111,114,32,108,111,110,103,32,112,101,114,105,111,100,115,32,105,110,32,97,32>>,{code,[],[<<104,105,103,104>>]},<<32,112,114,105,111,114,105,116,121,32,112,114,111,99,101,115,115,32,99,97,117,115,101,115,32,109,111,115,116,32,108,105,107,101,108,121,32,112,114,111,98,108,101,109,115,44,32,97,115,32,105,109,112,111,114,116,97,110,116,32,79,84,80,32,115,101,114,118,101,114,115,32,114,117,110,32,111,110,32,112,114,105,111,114,105,116,121,32>>,{code,[],[<<110,111,114,109,97,108>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2668,19},bounded_fun,[{type,{2668,19},'fun',[{type,{2668,19},product,[{atom,{2668,20},priority},{var,{2668,30},'Level'}]},{var,{2668,40},'OldLevel'}]},[{type,{2669,7},constraint,[{atom,{2669,7},is_subtype},[{var,{2669,7},'Level'},{user_type,{2669,16},priority_level,[]}]]},{type,{2670,7},constraint,[{atom,{2670,7},is_subtype},[{var,{2670,7},'OldLevel'},{user_type,{2670,19},priority_level,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,53,56,56>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[{code,[],[<<78>>]},<<32,109,117,115,116,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,116,104,101,32,105,110,116,101,114,118,97,108,32,48,46,46,49,48,48,48,48,46,32,73,102,32>>,{code,[],[<<78>>]},<<32,62,32,48,44,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,109,97,100,101,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<78>>]},<<32,109,111,115,116,32,114,101,99,101,110,116,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,66,73,70,32,99,97,108,108,115,44,32,115,101,110,100,115,44,32,97,110,100,32,114,101,99,101,105,118,101,115,32,109,97,100,101,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,97,114,101,32,115,97,118,101,100,32,105,110,32,97,32,108,105,115,116,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,119,105,116,104,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,40,80,105,100,44,32,108,97,115,116,95,99,97,108,108,115,41>>]},<<46,32,65,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,105,115,32,111,110,101,32,105,110,32,119,104,105,99,104,32,116,104,101,32,109,111,100,117,108,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,109,101,110,116,105,111,110,101,100,46,32,79,110,108,121,32,97,32,102,105,120,101,100,32,97,109,111,117,110,116,32,111,102,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,115,97,118,101,100,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{ul,[],[{li,[],[{p,[],[<<65,32,116,117,112,108,101,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<32,102,111,114,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115>>]}]},{li,[],[{p,[],[<<84,104,101,32,97,116,111,109,115,32>>,{code,[],[<<115,101,110,100>>]},<<44,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<44,32,97,110,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,102,111,114,32,115,101,110,100,115,32,97,110,100,32,114,101,99,101,105,118,101,115,32,40>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,119,104,101,110,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,99,101,105,118,101,100,32,97,110,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,119,104,101,110,32,97,32,114,101,99,101,105,118,101,32,116,105,109,101,115,32,111,117,116,41>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<78>>]},<<32,61,32,48,44,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,100,105,115,97,98,108,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46,32,87,104,101,110,101,118,101,114,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,32,105,115,32,115,101,116,44,32,105,116,115,32,99,111,110,116,101,110,116,115,32,97,114,101,32,114,101,115,101,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2671,19},bounded_fun,[{type,{2671,19},'fun',[{type,{2671,19},product,[{atom,{2671,20},save_calls},{var,{2671,32},'N'}]},{var,{2671,38},'OldN'}]},[{type,{2672,7},constraint,[{atom,{2672,7},is_subtype},[{var,{2672,7},'N'},{type,{2672,12},range,[{integer,{2672,12},0},{integer,{2672,15},10000}]}]]},{type,{2673,7},constraint,[{atom,{2673,7},is_subtype},[{var,{2673,7},'OldN'},{type,{2673,15},range,[{integer,{2673,15},0},{integer,{2673,18},10000}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,54,49>>}},{{function,process_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2644}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,111,114,32,99,108,101,97,114,115,32,102,108,97,103,32>>,{code,[],[<<115,101,110,115,105,116,105,118,101>>]},<<32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,87,104,101,110,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,109,97,114,107,101,100,32,97,115,32,115,101,110,115,105,116,105,118,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,115,101,110,115,105,116,105,118,101,44,32,116,114,117,101,41>>]},<<44,32,102,101,97,116,117,114,101,115,32,105,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,101,120,97,109,105,110,105,110,103,32,116,104,101,32,100,97,116,97,32,111,114,32,105,110,110,101,114,32,119,111,114,107,105,110,103,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,97,114,101,32,115,105,108,101,110,116,108,121,32,100,105,115,97,98,108,101,100,46>>]},{p,[],[<<70,101,97,116,117,114,101,115,32,116,104,97,116,32,97,114,101,32,100,105,115,97,98,108,101,100,32,105,110,99,108,117,100,101,32,40,98,117,116,32,97,114,101,32,110,111,116,32,108,105,109,105,116,101,100,32,116,111,41,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{p,[],[<<84,114,97,99,105,110,103,46,32,84,114,97,99,101,32,102,108,97,103,115,32,99,97,110,32,115,116,105,108,108,32,98,101,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,98,117,116,32,110,111,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,111,102,32,97,110,121,32,107,105,110,100,32,97,114,101,32,103,101,110,101,114,97,116,101,100,46,32,40,73,102,32,102,108,97,103,32>>,{code,[],[<<115,101,110,115,105,116,105,118,101>>]},<<32,105,115,32,116,117,114,110,101,100,32,111,102,102,44,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,97,103,97,105,110,32,103,101,110,101,114,97,116,101,100,32,105,102,32,97,110,121,32,116,114,97,99,101,32,102,108,97,103,115,32,97,114,101,32,115,101,116,46,41>>]}]},{li,[],[{p,[],[<<83,101,113,117,101,110,116,105,97,108,32,116,114,97,99,105,110,103,46,32,84,104,101,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,116,111,107,101,110,32,105,115,32,112,114,111,112,97,103,97,116,101,100,32,97,115,32,117,115,117,97,108,44,32,98,117,116,32,110,111,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,103,101,110,101,114,97,116,101,100,46>>]}]}]},{p,[],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49,44,50>>]},<<32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,32,116,111,32,114,101,97,100,32,111,117,116,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,40,98,111,116,104,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,101,109,112,116,121,32,108,105,115,116,115,41,46>>]},{p,[],[<<83,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,115,32,99,97,110,110,111,116,32,98,101,32,100,105,115,112,108,97,121,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,110,32,99,114,97,115,104,32,100,117,109,112,115,44,32,116,104,101,32,115,116,97,99,107,44,32,109,101,115,115,97,103,101,115,44,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,32,97,114,101,32,111,109,105,116,116,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<123,115,97,118,101,95,99,97,108,108,115,44,78,125>>]},<<32,104,97,115,32,98,101,101,110,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,110,111,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,115,97,118,101,100,32,116,111,32,116,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,46,32,40,84,104,101,32,99,97,108,108,32,115,97,118,105,110,103,32,108,105,115,116,32,105,115,32,110,111,116,32,99,108,101,97,114,101,100,46,32,65,108,115,111,44,32,115,101,110,100,44,32,114,101,99,101,105,118,101,44,32,97,110,100,32,116,105,109,101,45,111,117,116,32,101,118,101,110,116,115,32,97,114,101,32,115,116,105,108,108,32,97,100,100,101,100,32,116,111,32,116,104,101,32,108,105,115,116,46,41>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2644,2},spec,{{process_flag,2},[{type,{2674,19},bounded_fun,[{type,{2674,19},'fun',[{type,{2674,19},product,[{atom,{2674,20},sensitive},{var,{2674,31},'Boolean'}]},{var,{2674,43},'OldBoolean'}]},[{type,{2675,7},constraint,[{atom,{2675,7},is_subtype},[{var,{2675,7},'Boolean'},{type,{2675,18},boolean,[]}]]},{type,{2676,7},constraint,[{atom,{2676,7},is_subtype},[{var,{2676,7},'OldBoolean'},{type,{2676,21},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,54,57,50>>}},{{function,process_flag,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1977}],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,99,101,114,116,97,105,110,32,102,108,97,103,115,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<44,32,105,110,32,116,104,101,32,115,97,109,101,32,109,97,110,110,101,114,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46,32,82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46,32,84,104,101,32,118,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<70,108,97,103>>]},<<32,97,114,101,32,111,110,108,121,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,111,115,101,32,97,108,108,111,119,101,100,32,105,110,32>>,{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]},<<44,32,110,97,109,101,108,121,32>>,{code,[],[<<115,97,118,101,95,99,97,108,108,115>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]},#{signature => [{attribute,{1977,2},spec,{{process_flag,3},[{type,{1977,19},bounded_fun,[{type,{1977,19},'fun',[{type,{1977,19},product,[{var,{1977,20},'Pid'},{var,{1977,25},'Flag'},{var,{1977,31},'Value'}]},{var,{1977,41},'OldValue'}]},[{type,{1978,7},constraint,[{atom,{1978,7},is_subtype},[{var,{1978,7},'Pid'},{type,{1978,14},pid,[]}]]},{type,{1979,7},constraint,[{atom,{1979,7},is_subtype},[{var,{1979,7},'Flag'},{atom,{1979,15},save_calls}]]},{type,{1980,7},constraint,[{atom,{1980,7},is_subtype},[{var,{1980,7},'Value'},{type,{1980,16},non_neg_integer,[]}]]},{type,{1981,7},constraint,[{atom,{1981,7},is_subtype},[{var,{1981,7},'OldValue'},{type,{1981,19},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,50,54>>}},{{function,process_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1994}],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,114,101,115,117,108,116,95,105,116,101,109>>}],[]},{li,[{name,<<115,116,97,99,107,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{p,[],[<<84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,105,115,32,117,110,100,101,102,105,110,101,100,32,97,110,100,32,97,108,108,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,97,114,101,32,110,111,116,32,109,97,110,100,97,116,111,114,121,46,32,84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,116,101,109,115,32,97,114,101,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,58>>]},{ul,[],[{li,[],[{code,[],[<<99,117,114,114,101,110,116,95,102,117,110,99,116,105,111,110>>]}]},{li,[],[{code,[],[<<105,110,105,116,105,97,108,95,99,97,108,108>>]}]},{li,[],[{code,[],[<<115,116,97,116,117,115>>]}]},{li,[],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,108,101,110>>]}]},{li,[],[{code,[],[<<108,105,110,107,115>>]}]},{li,[],[{code,[],[<<100,105,99,116,105,111,110,97,114,121>>]}]},{li,[],[{code,[],[<<116,114,97,112,95,101,120,105,116>>]}]},{li,[],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]}]},{li,[],[{code,[],[<<112,114,105,111,114,105,116,121>>]}]},{li,[],[{code,[],[<<103,114,111,117,112,95,108,101,97,100,101,114>>]}]},{li,[],[{code,[],[<<116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<104,101,97,112,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]}]},{li,[],[{code,[],[<<114,101,100,117,99,116,105,111,110,115>>]}]},{li,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,104,97,115,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,97,108,115,111,32,97,110,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,119,105,116,104,32,105,116,101,109,32>>,{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,105,110,99,108,117,100,101,100,46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,112,101,99,105,102,105,99,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>]}]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32>>,{em,[],[<<100,101,98,117,103,103,105,110,103,32,111,110,108,121>>]},<<46,32,70,111,114,32,97,108,108,32,111,116,104,101,114,32,112,117,114,112,111,115,101,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>]}]},<<46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]},#{signature => [{attribute,{1994,2},spec,{{process_info,1},[{type,{1994,19},bounded_fun,[{type,{1994,19},'fun',[{type,{1994,19},product,[{var,{1994,20},'Pid'}]},{var,{1994,28},'Info'}]},[{type,{1995,7},constraint,[{atom,{1995,7},is_subtype},[{var,{1995,7},'Pid'},{type,{1995,14},pid,[]}]]},{type,{1996,7},constraint,[{atom,{1996,7},is_subtype},[{var,{1996,7},'Info'},{type,{1996,15},union,[{type,{1996,15},list,[{var,{1996,16},'InfoTuple'}]},{atom,{1996,29},undefined}]}]]},{type,{1997,7},constraint,[{atom,{1997,7},is_subtype},[{var,{1997,7},'InfoTuple'},{user_type,{1997,20},process_info_result_item,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,52,49>>}},{{function,process_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2777}],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,105,116,101,109>>}],[]},{li,[{name,<<112,114,111,99,101,115,115,95,105,110,102,111,95,114,101,115,117,108,116,95,105,116,101,109>>}],[]},{li,[{name,<<115,116,97,99,107,95,105,116,101,109>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<32,111,114,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,97,108,105,118,101,32,97,110,100,32,97,32,115,105,110,103,108,101,32>>,{code,[],[<<73,116,101,109>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<44,32,117,110,108,101,115,115,32>>,{code,[],[<<73,116,101,109,32,61,58,61,32,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,115,116,114,97,110,103,101,32,98,101,104,97,118,105,111,114,32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,104,105,115,116,111,114,105,99,97,108,32,114,101,97,115,111,110,115,44,32,97,110,100,32,105,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<46,32,84,104,101,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,105,110,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<32,97,114,101,32,105,110,99,108,117,100,101,100,32,119,105,116,104,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,105,110,32,116,104,101,32,115,97,109,101,32,111,114,100,101,114,32,97,115,32,116,104,101,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,119,101,114,101,32,105,110,99,108,117,100,101,100,32,105,110,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46,32,86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,105,110,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<46>>]},{p,[],[<<71,101,116,116,105,110,103,32,112,114,111,99,101,115,115,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,108,108,111,119,115,32,116,104,101,32,115,105,103,110,97,108,32,111,114,100,101,114,105,110,103,32,103,117,97,114,97,110,116,101,101,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<80,114,111,99,101,115,115,101,115,32,67,104,97,112,116,101,114>>]},<<32,105,110,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32>>,{code,[],[<<114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,112,97,114,116,32,111,102,32>>,{code,[],[<<73,116,101,109,76,105,115,116>>]},<<32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,110,97,109,101,32,114,101,103,105,115,116,101,114,101,100,44,32,97,32>>,{code,[],[<<123,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101,44,32,91,93,125>>]},<<44,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32>>,{em,[],[<<119,105,108,108>>]},<<32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101,76,105,115,116>>]},<<46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,100,105,102,102,101,114,101,110,116,32,119,104,101,110,32,97,32,115,105,110,103,108,101,32>>,{code,[],[<<73,116,101,109,32,61,58,61,32,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,97,110,100,32,119,104,101,110,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111,47,49>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<115,32,119,105,116,104,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<73,116,101,109>>]},<<115,58>>]},{dl,[],[{dt,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,97,115,121,110,99,95,100,105,115,116>>}],[]},{code,[],[<<123,97,115,121,110,99,95,100,105,115,116,44,32,69,110,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,105,110,99,101,58,32,79,84,80,32,50,53,46,51>>]},{p,[],[<<67,117,114,114,101,110,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]}]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,46>>]}]},{dt,[],[{code,[],[<<123,98,97,99,107,116,114,97,99,101,44,32,66,105,110,125>>]}]},{dd,[],[{p,[],[<<66,105,110,97,114,121,32>>,{code,[],[<<66,105,110>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,115,32,116,104,101,32,111,117,116,112,117,116,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,112,114,111,99,101,115,115,95,100,105,115,112,108,97,121,40,80,105,100,44,32,98,97,99,107,116,114,97,99,101,41>>]},<<46,32,85,115,101,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,108,105,115,116,47,49>>]},<<32,116,111,32,111,98,116,97,105,110,32,116,104,101,32,115,116,114,105,110,103,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,98,105,110,97,114,121,46>>]}]},{dt,[],[{code,[],[<<123,98,105,110,97,114,121,44,32,66,105,110,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<66,105,110,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,98,105,110,97,114,105,101,115,32,111,110,32,116,104,101,32,104,101,97,112,32,111,102,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,73,110,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32>>,{code,[],[<<66,105,110,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,46,32,84,104,101,32,116,117,112,108,101,115,32,99,111,110,116,97,105,110,59,32>>,{code,[],[<<66,105,110,97,114,121,73,100>>]},<<44,32>>,{code,[],[<<66,105,110,97,114,121,83,105,122,101>>]},<<44,32>>,{code,[],[<<66,105,110,97,114,121,82,101,102,99,67,111,117,110,116>>]},<<46>>]},{p,[],[<<68,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,109,97,121,32,98,101,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,104,101,97,112,46>>]}]},{dt,[],[{code,[],[<<123,99,97,116,99,104,108,101,118,101,108,44,32,67,97,116,99,104,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<67,97,116,99,104,76,101,118,101,108>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,99,117,114,114,101,110,116,108,121,32,97,99,116,105,118,101,32,99,97,116,99,104,101,115,32,105,110,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,102,117,110,99,116,105,111,110,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125,32,124,32,117,110,100,101,102,105,110,101,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,118,97,108,117,101,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,99,117,114,114,101,110,116,108,121,32,101,120,101,99,117,116,105,110,103,32,110,97,116,105,118,101,32,99,111,109,112,105,108,101,100,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,108,111,99,97,116,105,111,110,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,44,32,76,111,99,97,116,105,111,110,125,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,108,111,99,97,116,105,111,110,32,105,110,32,116,104,101,32,115,111,117,114,99,101,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,114,101,110,116,95,115,116,97,99,107,116,114,97,99,101,44,32,83,116,97,99,107,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,32,40>>,{em,[],[<<115,116,97,99,107,116,114,97,99,101>>]},<<41,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,115,116,97,99,107,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,115,32,105,110,32,116,104,101,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,112,97,114,116,32,111,102,32,97,32>>,{code,[],[<<116,114,121>>]},<<46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115,35,115,116,97,99,107,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<84,104,101,32,99,97,108,108,45,115,116,97,99,107,32,98,97,99,107,32,116,114,97,99,101,32,40,115,116,97,99,107,116,114,97,99,101,41>>]},<<46,32,84,104,101,32,100,101,112,116,104,32,111,102,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,32,105,115,32,116,114,117,110,99,97,116,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{code,[],[<<98,97,99,107,116,114,97,99,101,95,100,101,112,116,104>>]},<<32,115,121,115,116,101,109,32,102,108,97,103,32,115,101,116,116,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,100,105,99,116,105,111,110,97,114,121,44,32,68,105,99,116,105,111,110,97,114,121,125>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,99,116,105,111,110,97,114,121>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,95,104,97,110,100,108,101,114,44,32,77,111,100,117,108,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,109,111,100,117,108,101,32,117,115,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,40,102,111,114,32,117,110,100,101,102,105,110,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,102,111,114,32,101,120,97,109,112,108,101,41,46>>]}]},{dt,[],[{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,44,32,71,67,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,67,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32>>,{code,[],[<<71,67,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111>>}],[]},{code,[],[<<123,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,95,105,110,102,111,44,32,71,67,73,110,102,111,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,67,73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,100,101,116,97,105,108,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32>>,{code,[],[<<71,67,73,110,102,111>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,70,111,114,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,101,97,99,104,32,105,116,101,109,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,103,114,111,117,112,95,108,101,97,100,101,114,44,32,71,114,111,117,112,76,101,97,100,101,114,125>>]}]},{dd,[],[{p,[],[{code,[],[<<71,114,111,117,112,76,101,97,100,101,114>>]},<<32,105,115,32,116,104,101,32,103,114,111,117,112,32,108,101,97,100,101,114,32,102,111,114,32,116,104,101,32,73,47,79,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,119,111,114,100,115,32,111,102,32,116,104,101,32,121,111,117,110,103,101,115,116,32,104,101,97,112,32,103,101,110,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,103,101,110,101,114,97,116,105,111,110,32,105,110,99,108,117,100,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,46,32,84,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,44,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,102,32,116,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,99,104,97,110,103,101,115,46>>]}]},{dt,[],[{code,[],[<<123,105,110,105,116,105,97,108,95,99,97,108,108,44,32,123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<44,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,105,110,105,116,105,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,119,105,116,104,32,119,104,105,99,104,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,115,112,97,119,110,101,100,46>>]}]},{dt,[],[{code,[],[<<123,108,105,110,107,115,44,32,80,105,100,115,65,110,100,80,111,114,116,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,105,100,115,65,110,100,80,111,114,116,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,97,110,100,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,119,105,116,104,32,112,114,111,99,101,115,115,101,115,32,111,114,32,112,111,114,116,115,32,116,111,32,119,104,105,99,104,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,97,32,108,105,110,107,46>>]}]},{dt,[],[{code,[],[<<123,108,97,115,116,95,99,97,108,108,115,44,32,102,97,108,115,101,124,67,97,108,108,115,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,110,111,116,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,51>>]}]},<<41,46,32,73,102,32,99,97,108,108,32,115,97,118,105,110,103,32,105,115,32,97,99,116,105,118,101,44,32,97,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,44,32,105,110,32,119,104,105,99,104,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,99,97,108,108,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,101,109,111,114,121,44,32,83,105,122,101,125>>]}]},{dd,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,109,101,109,111,114,121>>}],[]},{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,105,122,101,32,105,110,32,98,121,116,101,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,99,97,108,108,32,115,116,97,99,107,44,32,104,101,97,112,44,32,97,110,100,32,105,110,116,101,114,110,97,108,32,115,116,114,117,99,116,117,114,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,108,101,110,44,32,77,101,115,115,97,103,101,81,117,101,117,101,76,101,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101,76,101,110>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,109,101,115,115,97,103,101,115,32,99,117,114,114,101,110,116,108,121,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101>>]},<<32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,116,101,109,32>>,{code,[],[<<109,101,115,115,97,103,101,115>>]},<<32,40,115,101,101,32,98,101,108,111,119,41,46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,115,44,32,77,101,115,115,97,103,101,81,117,101,117,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,101,115,115,97,103,101,81,117,101,117,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,109,101,115,115,97,103,101,115,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,44,32,119,104,105,99,104,32,104,97,118,101,32,110,111,116,32,121,101,116,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,77,105,110,72,101,97,112,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,105,110,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,77,105,110,66,105,110,86,72,101,97,112,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,105,110,66,105,110,86,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,101,100,95,98,121,44,32,77,111,110,105,116,111,114,101,100,66,121,125>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,105,100,101,110,116,105,102,105,101,114,115,32,102,111,114,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,44,32,112,111,114,116,115,32,97,110,100,32,78,73,70,32,114,101,115,111,117,114,99,101,115,44,32,116,104,97,116,32,97,114,101,32,109,111,110,105,116,111,114,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,115,44,32,77,111,110,105,116,111,114,115,125>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,111,110,105,116,111,114,115,32,40,115,116,97,114,116,101,100,32,98,121,32>>,{code,[],[<<109,111,110,105,116,111,114,47,50>>]},<<41,32,116,104,97,116,32,97,114,101,32,97,99,116,105,118,101,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,70,111,114,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,32,111,114,32,97,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,32,98,121,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,101,32,108,105,115,116,32,99,111,110,115,105,115,116,115,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,112,114,111,99,101,115,115,44,32,80,105,100,125>>]}]},{dd,[],[<<80,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,112,105,100,46>>]},{dt,[],[{code,[],[<<123,112,114,111,99,101,115,115,44,32,123,82,101,103,78,97,109,101,44,32,78,111,100,101,125,125>>]}]},{dd,[],[<<76,111,99,97,108,32,111,114,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,46>>]},{dt,[],[{code,[],[<<123,112,111,114,116,44,32,80,111,114,116,73,100,125>>]}]},{dd,[],[<<76,111,99,97,108,32,112,111,114,116,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,112,111,114,116,32,105,100,46>>]},{dt,[],[{code,[],[<<123,112,111,114,116,44,32,123,82,101,103,78,97,109,101,44,32,78,111,100,101,125,125>>]}]},{dd,[],[<<76,111,99,97,108,32,112,111,114,116,32,105,115,32,109,111,110,105,116,111,114,101,100,32,98,121,32,110,97,109,101,46,32,80,108,101,97,115,101,32,110,111,116,101,44,32,116,104,97,116,32,114,101,109,111,116,101,32,112,111,114,116,32,109,111,110,105,116,111,114,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,44,32,115,111,32>>,{code,[],[<<78,111,100,101>>]},<<32,119,105,108,108,32,97,108,119,97,121,115,32,98,101,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,110,97,109,101,46>>]}]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,125>>]}]},{dd,[],[{p,[],[{code,[],[<<77,81,68>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,101,110,116,44,32,80,105,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,112,114,111,99,101,115,115,44,32,116,104,101,32,111,110,101,32,116,104,97,116,32,115,112,97,119,110,101,100,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,87,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,97,32,112,97,114,101,110,116,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,110,108,121,32,116,104,101,32,105,110,105,116,105,97,108,32,112,114,111,99,101,115,115,32,40>>,{code,[],[<<105,110,105,116>>]},<<41,32,111,110,32,97,32,110,111,100,101,32,108,97,99,107,115,32,97,32,112,97,114,101,110,116,44,32,116,104,111,117,103,104,46>>]}]},{dt,[],[{code,[],[<<123,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<76,101,118,101,108>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,105,111,114,105,116,105,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,100,117,99,116,105,111,110,115,44,32,78,117,109,98,101,114,125>>]}]},{dd,[],[{p,[],[{code,[],[<<78,117,109,98,101,114>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,114,101,100,117,99,116,105,111,110,115,32,101,120,101,99,117,116,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,114,101,103,105,115,116,101,114,101,100,95,110,97,109,101,44,32,65,116,111,109,125>>]}]},{dd,[],[{p,[],[{code,[],[<<65,116,111,109>>]},<<32,105,115,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,32,110,97,109,101,46,32,73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,110,111,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,116,104,105,115,32,116,117,112,108,101,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,46>>]}]},{dt,[],[{code,[],[<<123,115,101,113,117,101,110,116,105,97,108,95,116,114,97,99,101,95,116,111,107,101,110,44,32,91,93,32,124,32,83,101,113,117,101,110,116,105,97,108,84,114,97,99,101,84,111,107,101,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,101,113,117,101,110,116,105,97,108,84,114,97,99,101,84,111,107,101,110>>]},<<32,105,115,32,116,104,101,32,115,101,113,117,101,110,116,105,97,108,32,116,114,97,99,101,32,116,111,107,101,110,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,115,116,97,99,107,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,115,116,97,99,107,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,44,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46>>]}]},{dt,[],[{code,[],[<<123,115,116,97,116,117,115,44,32,83,116,97,116,117,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,116,97,116,117,115>>]},<<32,105,115,32,116,104,101,32,115,116,97,116,117,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,97,110,100,32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{ul,[],[{li,[],[{code,[],[<<101,120,105,116,105,110,103>>]}]},{li,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,110,103>>]}]},{li,[],[{code,[],[<<119,97,105,116,105,110,103>>]},<<32,40,102,111,114,32,97,32,109,101,115,115,97,103,101,41>>]},{li,[],[{code,[],[<<114,117,110,110,105,110,103>>]}]},{li,[],[{code,[],[<<114,117,110,110,97,98,108,101>>]},<<32,40,114,101,97,100,121,32,116,111,32,114,117,110,44,32,98,117,116,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,105,115,32,114,117,110,110,105,110,103,41>>]},{li,[],[{code,[],[<<115,117,115,112,101,110,100,101,100>>]},<<32,40,115,117,115,112,101,110,100,101,100,32,111,110,32,97,32,34,98,117,115,121,34,32,112,111,114,116,32,111,114,32,98,121,32,116,104,101,32,66,73,70,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49,44,50>>]},<<41>>]}]}]},{dt,[],[{code,[],[<<123,115,117,115,112,101,110,100,105,110,103,44,32,83,117,115,112,101,110,100,101,101,76,105,115,116,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101,76,105,115,116>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,83,117,115,112,101,110,100,101,101,44,32,65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116,44,32,79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116,125>>]},<<32,116,117,112,108,101,115,46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,98,101,101,110,44,32,111,114,32,105,115,32,116,111,32,98,101,44,32,115,117,115,112,101,110,100,101,100,32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<32,116,104,114,111,117,103,104,32,116,104,101,32,66,73,70,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>]}]},<<46>>]},{p,[],[{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,110,111,116,32,121,101,116,32,99,111,109,112,108,101,116,101,100,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,115,32,115,101,110,116,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116,32,61,47,61,32,48>>]},<<44,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,99,117,114,114,101,110,116,108,121,32,105,110,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116,32,61,47,61,32,48>>]},<<44,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,104,97,115,32,98,101,101,110,32,117,115,101,100,32,97,110,100,32,116,104,101,32,115,117,115,112,101,110,100,101,101,32,104,97,115,32,110,111,116,32,121,101,116,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<65,99,116,105,118,101,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<79,117,116,115,116,97,110,100,105,110,103,83,117,115,112,101,110,100,67,111,117,110,116>>]},<<32,97,114,101,32,110,111,116,32,116,104,101,32,116,111,116,97,108,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<44,32,111,110,108,121,32,116,104,101,32,112,97,114,116,115,32,99,111,110,116,114,105,98,117,116,101,100,32,98,121,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{a,[{id,<<112,114,111,99,101,115,115,95,105,110,102,111,95,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<123,116,111,116,97,108,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<83,105,122,101>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,44,32,111,102,32,97,108,108,32,104,101,97,112,32,102,114,97,103,109,101,110,116,115,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,110,99,108,117,100,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,115,116,97,99,107,32,97,110,100,32,97,110,121,32,117,110,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,44,32,73,110,116,101,114,110,97,108,84,114,97,99,101,70,108,97,103,115,125>>]}]},{dd,[],[{p,[],[{code,[],[<<73,110,116,101,114,110,97,108,84,114,97,99,101,70,108,97,103,115>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,105,110,116,101,114,110,97,108,32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32>>,{code,[],[<<73,110,102,111,84,117,112,108,101>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,112,95,101,120,105,116,44,32,66,111,111,108,101,97,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<66,111,111,108,101,97,110>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,110,111,116,32,97,108,108,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,32,115,117,112,112,111,114,116,32,97,108,108,32,116,104,101,115,101,32>>,{code,[],[<<73,116,101,109>>]},<<115,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<73,116,101,109>>]},<<32,105,115,32,97,110,32,105,110,118,97,108,105,100,32,105,116,101,109,46>>]}]}]},#{signature => [{attribute,{2777,2},spec,{{process_info,2},[{type,{2777,19},bounded_fun,[{type,{2777,19},'fun',[{type,{2777,19},product,[{var,{2777,20},'Pid'},{var,{2777,25},'Item'}]},{type,{2778,27},union,[{var,{2778,27},'InfoTuple'},{type,{2778,39},nil,[]},{atom,{2778,44},undefined}]}]},[{type,{2779,7},constraint,[{atom,{2779,7},is_subtype},[{var,{2779,7},'Pid'},{type,{2779,14},pid,[]}]]},{type,{2780,7},constraint,[{atom,{2780,7},is_subtype},[{var,{2780,7},'Item'},{user_type,{2780,15},process_info_item,[]}]]},{type,{2781,7},constraint,[{atom,{2781,7},is_subtype},[{var,{2781,7},'InfoTuple'},{user_type,{2781,20},process_info_result_item,[]}]]}]]},{type,{2782,19},bounded_fun,[{type,{2782,19},'fun',[{type,{2782,19},product,[{var,{2782,20},'Pid'},{var,{2782,25},'ItemList'}]},{type,{2782,38},union,[{var,{2782,38},'InfoTupleList'},{type,{2782,54},nil,[]},{atom,{2782,59},undefined}]}]},[{type,{2783,7},constraint,[{atom,{2783,7},is_subtype},[{var,{2783,7},'Pid'},{type,{2783,14},pid,[]}]]},{type,{2784,7},constraint,[{atom,{2784,7},is_subtype},[{var,{2784,7},'ItemList'},{type,{2784,19},list,[{var,{2784,20},'Item'}]}]]},{type,{2785,7},constraint,[{atom,{2785,7},is_subtype},[{var,{2785,7},'Item'},{user_type,{2785,15},process_info_item,[]}]]},{type,{2786,7},constraint,[{atom,{2786,7},is_subtype},[{var,{2786,7},'InfoTupleList'},{type,{2786,24},list,[{var,{2786,25},'InfoTuple'}]}]]},{type,{2787,7},constraint,[{atom,{2787,7},is_subtype},[{var,{2787,7},'InfoTuple'},{user_type,{2787,20},process_info_result_item,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,54,55,57,50>>}},{{function,processes,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2002}],[<<112,114,111,99,101,115,115,101,115,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,110,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,32,101,120,105,115,116,115,44,32,98,117,116,32,105,115,32,110,111,116,32,97,108,105,118,101,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<105,115,95,112,114,111,99,101,115,115,95,97,108,105,118,101,47,49>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,102,111,114,32,97,110,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,44,32,98,117,116,32,105,116,115,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<112,114,111,99,101,115,115,101,115,47,48>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,112,114,111,99,101,115,115,101,115,40,41,46,10,91,60,48,46,48,46,48,62,44,60,48,46,50,46,48,62,44,60,48,46,52,46,48,62,44,60,48,46,53,46,48,62,44,60,48,46,55,46,48,62,44,60,48,46,56,46,48,62,93>>]}]}]},#{signature => [{attribute,{2002,2},spec,{{processes,0},[{type,{2002,16},'fun',[{type,{2002,16},product,[]},{type,{2002,22},list,[{type,{2002,23},pid,[]}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,53,53>>}},{{function,purge_module,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2007}],[<<112,117,114,103,101,95,109,111,100,117,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46,32,66,101,102,111,114,101,32,116,104,105,115,32,66,73,70,32,105,115,32,117,115,101,100,44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,104,101,99,107,95,112,114,111,99,101,115,115,95,99,111,100,101,47,50>>]}]},<<32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,116,111,32,99,104,101,99,107,32,116,104,97,116,32,110,111,32,112,114,111,99,101,115,115,101,115,32,101,120,101,99,117,116,101,32,111,108,100,32,99,111,100,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,116,104,101,32,99,111,100,101,32,115,101,114,118,101,114,32,40,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,100,101,40,51,41>>]}]},<<41,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,101,108,115,101,119,104,101,114,101,46>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,56,46,48,32,40,69,114,108,97,110,103,47,79,84,80,32,49,57,41,44,32,97,110,121,32,108,105,110,103,101,114,105,110,103,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,115,116,105,108,108,32,101,120,101,99,117,116,101,32,116,104,101,32,111,108,100,32,99,111,100,101,32,105,115,32,107,105,108,108,101,100,32,98,121,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,73,110,32,101,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,44,32,115,117,99,104,32,105,110,99,111,114,114,101,99,116,32,117,115,101,32,99,111,117,108,100,32,99,97,117,115,101,32,109,117,99,104,32,109,111,114,101,32,102,97,116,97,108,32,102,97,105,108,117,114,101,115,44,32,108,105,107,101,32,101,109,117,108,97,116,111,114,32,99,114,97,115,104,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,111,108,100,32,99,111,100,101,32,102,111,114,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},#{signature => [{attribute,{2007,2},spec,{{purge_module,1},[{type,{2007,19},bounded_fun,[{type,{2007,19},'fun',[{type,{2007,19},product,[{var,{2007,20},'Module'}]},{atom,{2007,31},true}]},[{type,{2008,7},constraint,[{atom,{2008,7},is_subtype},[{var,{2008,7},'Module'},{type,{2008,17},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,55,50>>}},{{function,put,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2021}],[<<112,117,116,47,50>>],#{<<101,110>> => [{p,[],[<<65,100,100,115,32,97,32,110,101,119,32>>,{code,[],[<<75,101,121>>]},<<32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,44,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<86,97,108>>]},<<44,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46,32,73,102,32>>,{code,[],[<<75,101,121>>]},<<32,101,120,105,115,116,115,44,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,105,115,32,100,101,108,101,116,101,100,32,97,110,100,32,114,101,112,108,97,99,101,100,32,98,121,32>>,{code,[],[<<86,97,108>>]},<<44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,46,32,84,104,101,32,97,118,101,114,97,103,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,79,40>>,{code,[],[<<49>>]},<<41,32,97,110,100,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,116,105,109,101,32,99,111,109,112,108,101,120,105,116,121,32,105,115,32,79,40>>,{code,[],[<<78>>]},<<41,44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,105,116,101,109,115,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,100,105,99,116,105,111,110,97,114,121,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,88,32,61,32,112,117,116,40,110,97,109,101,44,32,119,97,108,114,117,115,41,44,32,89,32,61,32,112,117,116,40,110,97,109,101,44,32,99,97,114,112,101,110,116,101,114,41,44,10,90,32,61,32,103,101,116,40,110,97,109,101,41,44,10,123,88,44,32,89,44,32,90,125,46,10,123,117,110,100,101,102,105,110,101,100,44,119,97,108,114,117,115,44,99,97,114,112,101,110,116,101,114,125>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,118,97,108,117,101,115,32,115,116,111,114,101,100,32,119,104,101,110,32>>,{code,[],[<<112,117,116>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,116,104,101,32,115,99,111,112,101,32,111,102,32,97,32>>,{code,[],[<<99,97,116,99,104>>]},<<32,97,114,101,32,110,111,116,32,114,101,116,114,97,99,116,101,100,32,105,102,32,97,32>>,{code,[],[<<116,104,114,111,119>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,44,32,111,114,32,105,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]}]}]},#{signature => [{attribute,{2021,2},spec,{{put,2},[{type,{2021,10},bounded_fun,[{type,{2021,10},'fun',[{type,{2021,10},product,[{var,{2021,11},'Key'},{var,{2021,16},'Val'}]},{type,{2021,24},term,[]}]},[{type,{2022,7},constraint,[{atom,{2022,7},is_subtype},[{var,{2022,7},'Key'},{type,{2022,14},term,[]}]]},{type,{2023,7},constraint,[{atom,{2023,7},is_subtype},[{var,{2023,7},'Val'},{type,{2023,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,49,57,55>>}},{{function,raise,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2029}],[<<114,97,105,115,101,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<114,97,105,115,101,95,115,116,97,99,107,116,114,97,99,101>>}],[]}]},{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,99,108,97,115,115,44,32,114,101,97,115,111,110,44,32,97,110,100,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,116,114,97,99,101,32,40>>,{em,[],[<<115,116,97,99,107,116,114,97,99,101>>]},<<41,46>>]},{p,[],[{code,[],[<<67,108,97,115,115>>]},<<32,105,115,32>>,{code,[],[<<101,114,114,111,114>>]},<<44,32>>,{code,[],[<<101,120,105,116>>]},<<44,32,111,114,32>>,{code,[],[<<116,104,114,111,119>>]},<<46,32,83,111,44,32,105,102,32,105,116,32,119,101,114,101,32,110,111,116,32,102,111,114,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,44,32>>,{code,[],[<<101,114,108,97,110,103,58,114,97,105,115,101,40,67,108,97,115,115,44,32,82,101,97,115,111,110,44,32,83,116,97,99,107,116,114,97,99,101,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,67,108,97,115,115,40,82,101,97,115,111,110,41>>]},<<32,40,103,105,118,101,110,32,116,104,97,116,32>>,{code,[],[<<67,108,97,115,115>>]},<<32,105,115,32,97,32,118,97,108,105,100,32,99,108,97,115,115,41,46>>]},{p,[],[{code,[],[<<82,101,97,115,111,110>>]},<<32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,46>>]},{p,[],[{code,[],[<<83,116,97,99,107,116,114,97,99,101>>]},<<32,105,115,32,97,32,108,105,115,116,32,97,115,32,112,114,111,118,105,100,101,100,32,105,110,32,97,32,116,114,121,45,99,97,116,99,104,32,99,108,97,117,115,101,46>>]},{pre,[],[{code,[],[<<116,114,121,10,32,32,32,32,46,46,46,10,99,97,116,99,104,32,67,108,97,115,115,58,82,101,97,115,111,110,58,83,116,97,99,107,116,114,97,99,101,32,45,62,10,32,32,32,32,46,46,46,10,101,110,100>>]}]},{p,[],[<<84,104,97,116,32,105,115,44,32,97,32,108,105,115,116,32,111,102,32,102,111,117,114,45,116,117,112,108,101,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,32,124,32,65,114,103,115,44,32,69,120,116,114,97,73,110,102,111,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<32,97,110,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,97,114,101,32,97,116,111,109,115,44,32,97,110,100,32,116,104,101,32,116,104,105,114,100,32,101,108,101,109,101,110,116,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,97,114,105,116,121,32,111,114,32,97,110,32,97,114,103,117,109,101,110,116,32,108,105,115,116,46,32,84,104,101,32,115,116,97,99,107,116,114,97,99,101,32,99,97,110,32,97,108,115,111,32,99,111,110,116,97,105,110,32>>,{code,[],[<<123,70,117,110,44,32,65,114,103,115,44,32,69,120,116,114,97,73,110,102,111,125>>]},<<32,116,117,112,108,101,115,44,32,119,104,101,114,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,102,117,110,32,97,110,100,32>>,{code,[],[<<65,114,103,115>>]},<<32,105,115,32,97,110,32,97,114,103,117,109,101,110,116,32,108,105,115,116,46>>]},{p,[],[<<69,108,101,109,101,110,116,32>>,{code,[],[<<69,120,116,114,97,73,110,102,111>>]},<<32,97,116,32,116,104,101,32,101,110,100,32,105,115,32,111,112,116,105,111,110,97,108,46,32,79,109,105,116,116,105,110,103,32,105,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,112,101,99,105,102,121,105,110,103,32,97,110,32,101,109,112,116,121,32,108,105,115,116,46>>]},{p,[],[<<84,104,101,32,115,116,97,99,107,116,114,97,99,101,32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,115,116,97,99,107,116,114,97,99,101,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,59,32,105,116,32,105,115,32,116,114,117,110,99,97,116,101,100,32,116,111,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,120,105,109,117,109,32,115,116,97,99,107,116,114,97,99,101,32,100,101,112,116,104,46>>]},{p,[],[<<65,115,32,101,118,97,108,117,97,116,105,110,103,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,117,115,101,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,111,32,116,101,114,109,105,110,97,116,101,44,32,105,116,32,104,97,115,32,110,111,32,114,101,116,117,114,110,32,118,97,108,117,101,32,117,110,108,101,115,115,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,105,110,118,97,108,105,100,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{em,[],[<<114,101,116,117,114,110,115,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110>>]},<<32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,98,101,32,115,117,114,101,32,110,111,116,32,116,111,32,114,101,116,117,114,110,44,32,121,111,117,32,99,97,110,32,99,97,108,108,32>>,{code,[],[<<101,114,114,111,114,40,101,114,108,97,110,103,58,114,97,105,115,101,40,67,108,97,115,115,44,32,82,101,97,115,111,110,44,32,83,116,97,99,107,116,114,97,99,101,41,41>>]},<<32,97,110,100,32,104,111,112,101,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,101,120,99,101,112,116,105,111,110,115,32,108,97,116,101,114,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,109,97,110,117,97,108,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,101,120,99,101,112,116,105,111,110,32,99,108,97,115,115,101,115,32,97,110,100,32,104,111,119,32,116,111,32,99,97,116,99,104,32,101,120,99,101,112,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{2029,2},spec,{{erlang,raise,3},[{type,{2029,19},bounded_fun,[{type,{2029,19},'fun',[{type,{2029,19},product,[{var,{2029,20},'Class'},{var,{2029,27},'Reason'},{var,{2029,35},'Stacktrace'}]},{atom,{2029,50},badarg}]},[{type,{2030,7},constraint,[{atom,{2030,7},is_subtype},[{var,{2030,7},'Class'},{type,{2030,16},union,[{atom,{2030,16},error},{atom,{2030,26},exit},{atom,{2030,35},throw}]}]]},{type,{2031,7},constraint,[{atom,{2031,7},is_subtype},[{var,{2031,7},'Reason'},{type,{2031,17},term,[]}]]},{type,{2032,7},constraint,[{atom,{2032,7},is_subtype},[{var,{2032,7},'Stacktrace'},{type,{2032,21},union,[{user_type,{2032,21},raise_stacktrace,[]},{user_type,{2032,42},stacktrace,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,50,51>>}},{{function,read_timer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2037}],[<<114,101,97,100,95,116,105,109,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,40,84,105,109,101,114,82,101,102,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2037,2},spec,{{erlang,read_timer,1},[{type,{2037,24},bounded_fun,[{type,{2037,24},'fun',[{type,{2037,24},product,[{var,{2037,25},'TimerRef'}]},{var,{2037,38},'Result'}]},[{type,{2038,7},constraint,[{atom,{2038,7},is_subtype},[{var,{2038,7},'TimerRef'},{type,{2038,19},reference,[]}]]},{type,{2039,7},constraint,[{atom,{2039,7},is_subtype},[{var,{2039,7},'Time'},{type,{2039,15},non_neg_integer,[]}]]},{type,{2040,7},constraint,[{atom,{2040,7},is_subtype},[{var,{2040,7},'Result'},{type,{2040,17},union,[{var,{2040,17},'Time'},{atom,{2040,24},false}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,55,51>>}},{{function,read_timer,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2046}],[<<114,101,97,100,95,116,105,109,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,97,32,116,105,109,101,114,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,32,98,121,32,101,105,116,104,101,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114>>]}]},<<46,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,105,100,101,110,116,105,102,105,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,119,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,66,73,70,32,116,104,97,116,32,99,114,101,97,116,101,100,32,116,104,101,32,116,105,109,101,114,46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,115,121,110,99,44,32,65,115,121,110,99,125>>]}]},{dd,[],[{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,115,116,97,116,101,32,105,110,102,111,114,109,97,116,105,111,110,46,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,32,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<46,32,87,104,101,110,32>>,{code,[],[<<65,115,121,110,99>>]},<<32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<44,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<32,115,101,110,100,115,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,114,101,113,117,101,115,116,32,102,111,114,32,116,104,101,32,115,116,97,116,101,32,105,110,102,111,114,109,97,116,105,111,110,32,116,111,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,44,32,97,110,100,32,116,104,101,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<46,32,65,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,114,101,97,100,95,116,105,109,101,114,44,32,84,105,109,101,114,82,101,102,44,32,82,101,115,117,108,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114>>]},<<32,119,104,101,110,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,46>>]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,44,32,105,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32,108,101,102,116,32,117,110,116,105,108,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<82,101,115,117,108,116>>]},<<32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<44,32,97,32,116,105,109,101,114,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,102,111,117,110,100,46,32,84,104,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,114,32,104,97,100,32,101,120,112,105,114,101,100,44,32,111,114,32,98,101,101,110,32,99,97,110,99,101,108,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32>>,{code,[],[<<84,105,109,101,114,82,101,102>>]},<<32,110,101,118,101,114,32,104,97,115,32,99,111,114,114,101,115,112,111,110,100,101,100,32,116,111,32,97,32,116,105,109,101,114,46,32,69,118,101,110,32,105,102,32,116,104,101,32,116,105,109,101,114,32,104,97,115,32,101,120,112,105,114,101,100,44,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,108,108,32,121,111,117,32,119,104,101,116,104,101,114,32,111,114,32,110,111,116,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,32,104,97,115,32,97,114,114,105,118,101,100,32,97,116,32,105,116,115,32,100,101,115,116,105,110,97,116,105,111,110,32,121,101,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,104,97,116,32,109,97,110,97,103,101,115,32,116,104,101,32,116,105,109,101,114,32,99,97,110,32,98,101,32,99,111,45,108,111,99,97,116,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32,115,99,104,101,100,117,108,101,114,32,116,104,97,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32,73,102,32,115,111,44,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,116,105,109,101,114,32,115,101,114,118,105,99,101,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,116,105,109,101,32,116,104,97,110,32,105,102,32,105,116,32,105,115,32,108,111,99,97,116,101,100,32,108,111,99,97,108,108,121,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,105,110,32,97,32,99,114,105,116,105,99,97,108,32,112,97,116,104,44,32,97,110,100,32,99,97,110,32,100,111,32,111,116,104,101,114,32,116,104,105,110,103,115,32,119,104,105,108,101,32,119,97,105,116,105,110,103,32,102,111,114,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,44,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,116,114,117,101,125>>]},<<46,32,73,102,32,117,115,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<123,97,115,121,110,99,44,32,102,97,108,115,101,125>>]},<<44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,98,108,111,99,107,101,100,32,117,110,116,105,108,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,112,101,114,102,111,114,109,101,100,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{2046,2},spec,{{erlang,read_timer,2},[{type,{2046,24},bounded_fun,[{type,{2046,24},'fun',[{type,{2046,24},product,[{var,{2046,25},'TimerRef'},{var,{2046,35},'Options'}]},{type,{2046,47},union,[{var,{2046,47},'Result'},{atom,{2046,56},ok}]}]},[{type,{2047,7},constraint,[{atom,{2047,7},is_subtype},[{var,{2047,7},'TimerRef'},{type,{2047,19},reference,[]}]]},{type,{2048,7},constraint,[{atom,{2048,7},is_subtype},[{var,{2048,7},'Async'},{type,{2048,16},boolean,[]}]]},{type,{2049,7},constraint,[{atom,{2049,7},is_subtype},[{var,{2049,7},'Option'},{type,{2049,17},tuple,[{atom,{2049,18},async},{var,{2049,25},'Async'}]}]]},{type,{2050,7},constraint,[{atom,{2050,7},is_subtype},[{var,{2050,7},'Options'},{type,{2050,18},list,[{var,{2050,19},'Option'}]}]]},{type,{2051,7},constraint,[{atom,{2051,7},is_subtype},[{var,{2051,7},'Time'},{type,{2051,15},non_neg_integer,[]}]]},{type,{2052,7},constraint,[{atom,{2052,7},is_subtype},[{var,{2052,7},'Result'},{type,{2052,17},union,[{var,{2052,17},'Time'},{atom,{2052,24},false}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,50,56,51>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,ref_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2058}],[<<114,101,102,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,116,101,120,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32>>,{code,[],[<<82,101,102>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,97,110,100,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,97,112,112,108,105,99,97,116,105,111,110,32,112,114,111,103,114,97,109,115,46>>]}]}]},#{signature => [{attribute,{2058,2},spec,{{ref_to_list,1},[{type,{2058,18},bounded_fun,[{type,{2058,18},'fun',[{type,{2058,18},product,[{var,{2058,19},'Ref'}]},{type,{2058,27},string,[]}]},[{type,{2059,7},constraint,[{atom,{2059,7},is_subtype},[{var,{2059,7},'Ref'},{type,{2059,14},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,51,51,57>>}},{{function,register,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2064}],[<<114,101,103,105,115,116,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,103,105,115,116,101,114,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,119,105,116,104,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,105,110,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,114,117,110,116,105,109,101,45,115,101,114,118,105,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<110,97,109,101,32,114,101,103,105,115,116,114,121>>]}]},<<46,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<44,32,119,104,105,99,104,32,109,117,115,116,32,98,101,32,97,110,32,97,116,111,109,44,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,112,105,100,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,105,110,32,115,101,110,100,32,111,112,101,114,97,116,111,114,32,40>>,{code,[],[<<82,101,103,78,97,109,101,32,33,32,77,101,115,115,97,103,101>>]},<<41,32,97,110,100,32,109,111,115,116,32,111,116,104,101,114,32,66,73,70,115,32,116,104,97,116,32,116,97,107,101,32,97,32,112,105,100,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,115,32,97,115,32,97,110,32,97,114,103,117,109,101,110,116,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,114,101,103,105,115,116,101,114,40,100,98,44,32,80,105,100,41,46,10,116,114,117,101>>]}]},{p,[],[<<84,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,118,105,115,105,98,108,101,45,114,101,115,111,117,114,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,105,114,101,99,116,108,121,32,86,105,115,105,98,108,101,32,69,114,108,97,110,103,32,82,101,115,111,117,114,99,101>>]},<<32,97,110,100,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,117,110,114,101,103,105,115,116,101,114,101,100,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,120,105,115,116,105,110,103,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,97,108,114,101,97,100,121,32,105,110,32,117,115,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,115,32,97,108,114,101,97,100,121,32,114,101,103,105,115,116,101,114,101,100,32,40,97,108,114,101,97,100,121,32,104,97,115,32,97,32,110,97,109,101,41,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]}]}]},#{signature => [{attribute,{2064,2},spec,{{register,2},[{type,{2064,15},bounded_fun,[{type,{2064,15},'fun',[{type,{2064,15},product,[{var,{2064,16},'RegName'},{var,{2064,25},'PidOrPort'}]},{atom,{2064,39},true}]},[{type,{2065,7},constraint,[{atom,{2065,7},is_subtype},[{var,{2065,7},'RegName'},{type,{2065,18},atom,[]}]]},{type,{2066,7},constraint,[{atom,{2066,7},is_subtype},[{var,{2066,7},'PidOrPort'},{type,{2066,20},union,[{type,{2066,20},port,[]},{type,{2066,29},pid,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,51,53,50>>}},{{function,registered,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2071}],[<<114,101,103,105,115,116,101,114,101,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,110,97,109,101,115,32,116,104,97,116,32,104,97,118,101,32,98,101,101,110,32,114,101,103,105,115,116,101,114,101,100,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,103,105,115,116,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,103,105,115,116,101,114,47,50>>]}]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,114,101,103,105,115,116,101,114,101,100,40,41,46,10,91,99,111,100,101,95,115,101,114,118,101,114,44,32,102,105,108,101,95,115,101,114,118,101,114,44,32,105,110,105,116,44,32,117,115,101,114,44,32,109,121,95,100,98,93>>]}]}]},#{signature => [{attribute,{2071,2},spec,{{registered,0},[{type,{2071,17},bounded_fun,[{type,{2071,17},'fun',[{type,{2071,17},product,[]},{type,{2071,23},list,[{var,{2071,24},'RegName'}]}]},[{type,{2072,7},constraint,[{atom,{2072,7},is_subtype},[{var,{2072,7},'RegName'},{type,{2072,18},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,51,56,56>>}},{{function,resume_process,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2077}],[<<114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,99,114,101,97,115,101,115,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,112,114,101,118,105,111,117,115,108,121,32,116,111,32,104,97,118,101,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,116,104,114,111,117,103,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>]}]},<<32,98,121,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<46,32,87,104,101,110,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,97,99,104,101,115,32,122,101,114,111,44,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,114,101,115,117,109,101,100,44,32,116,104,97,116,32,105,115,44,32,105,116,115,32,115,116,97,116,101,32,105,115,32,99,104,97,110,103,101,100,32,102,114,111,109,32,115,117,115,112,101,110,100,101,100,32,105,110,116,111,32,116,104,101,32,115,116,97,116,101,32,105,116,32,104,97,100,32,98,101,102,111,114,101,32,105,116,32,119,97,115,32,115,117,115,112,101,110,100,101,100,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>]},<<32,104,97,100,32,110,111,116,32,112,114,101,118,105,111,117,115,108,121,32,105,110,99,114,101,97,115,101,100,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]}]},#{signature => [{attribute,{2077,2},spec,{{erlang,resume_process,1},[{type,{2077,28},bounded_fun,[{type,{2077,28},'fun',[{type,{2077,28},product,[{var,{2077,29},'Suspendee'}]},{atom,{2077,43},true}]},[{type,{2078,7},constraint,[{atom,{2078,7},is_subtype},[{var,{2078,7},'Suspendee'},{type,{2078,20},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,48,49>>}},{{function,round,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2084}],[<<114,111,117,110,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,98,121,32,114,111,117,110,100,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,111,117,110,100,40,52,50,46,49,41,46,10,52,50>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,53,46,53,41,46,10,54>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,45,53,46,53,41,46,10,45,54>>]}]},{pre,[],[{code,[],[<<114,111,117,110,100,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41,46,10,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<114,111,117,110,100,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,116,104,97,116,32,116,104,101,32,110,117,109,98,101,114,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,73,110,115,116,101,97,100,44,32,116,104,101,32,102,108,111,97,116,32,108,105,116,101,114,97,108,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56,46,48>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,99,108,111,115,101,115,116,32,110,117,109,98,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2084,2},spec,{{round,1},[{type,{2084,12},bounded_fun,[{type,{2084,12},'fun',[{type,{2084,12},product,[{var,{2084,13},'Number'}]},{type,{2084,24},integer,[]}]},[{type,{2085,7},constraint,[{atom,{2085,7},is_subtype},[{var,{2085,7},'Number'},{type,{2085,17},number,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,52,50>>}},{{function,self,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2091}],[<<115,101,108,102,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,101,108,102,40,41,46,10,60,48,46,50,54,46,48,62>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2091,2},spec,{{self,0},[{type,{2091,11},'fun',[{type,{2091,11},product,[]},{type,{2091,17},pid,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,55,51>>}},{{function,send,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2791}],[<<115,101,110,100,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,97,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<77,115,103>>]},<<46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,115,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,101,110,100,32,111,112,101,114,97,116,111,114>>]},<<58,32>>,{code,[],[<<68,101,115,116,32,33,32,77,115,103>>]},<<46>>]},{p,[],[{code,[],[<<68,101,115,116>>]},<<32,99,97,110,32,98,101,32,97,32,114,101,109,111,116,101,32,111,114,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,110,32,97,108,105,97,115,44,32,97,32,40,108,111,99,97,108,41,32,112,111,114,116,44,32,97,32,108,111,99,97,108,108,121,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,97,116,32,97,110,111,116,104,101,114,32,110,111,100,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,102,97,105,108,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,114,117,110,45,116,105,109,101,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32,97,116,111,109,32,110,97,109,101,44,32,98,117,116,32,116,104,105,115,32,110,97,109,101,32,105,115,32,110,111,116,32,114,101,103,105,115,116,101,114,101,100,46,32,84,104,105,115,32,105,115,32,116,104,101,32,111,110,108,121,32,99,97,115,101,32,119,104,101,110,32>>,{code,[],[<<115,101,110,100>>]},<<32,102,97,105,108,115,32,102,111,114,32,97,110,32,117,110,114,101,97,99,104,97,98,108,101,32,100,101,115,116,105,110,97,116,105,111,110,32>>,{code,[],[<<68,101,115,116>>]},<<32,40,111,102,32,99,111,114,114,101,99,116,32,116,121,112,101,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]}]},#{signature => [{attribute,{2791,2},spec,{{erlang,send,2},[{type,{2791,18},bounded_fun,[{type,{2791,18},'fun',[{type,{2791,18},product,[{var,{2791,19},'Dest'},{var,{2791,25},'Msg'}]},{var,{2791,33},'Msg'}]},[{type,{2792,7},constraint,[{atom,{2792,7},is_subtype},[{var,{2792,7},'Dest'},{user_type,{2792,15},send_destination,[]}]]},{type,{2793,7},constraint,[{atom,{2793,7},is_subtype},[{var,{2793,7},'Msg'},{type,{2793,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,52,56,54>>}},{{function,send,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2797}],[<<115,101,110,100,47,51>>],#{<<101,110>> => [{p,[],[<<69,105,116,104,101,114,32,115,101,110,100,115,32,97,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<44,32,111,114,32,100,111,101,115,32,110,111,116,32,115,101,110,100,32,116,104,101,32,109,101,115,115,97,103,101,32,98,117,116,32,114,101,116,117,114,110,115,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,40,115,101,101,32,98,101,108,111,119,41,46,32,79,116,104,101,114,119,105,115,101,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,47,50>>]}]},<<46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,101,100,32,101,120,112,108,97,110,97,116,105,111,110,32,97,110,100,32,119,97,114,110,105,110,103,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50,44,51>>]}]},<<46>>]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,115,117,115,112,101,110,100>>]}]},{dd,[],[<<73,102,32,116,104,101,32,115,101,110,100,101,114,32,119,111,117,108,100,32,104,97,118,101,32,116,111,32,98,101,32,115,117,115,112,101,110,100,101,100,32,116,111,32,100,111,32,116,104,101,32,115,101,110,100,44,32>>,{code,[],[<<110,111,115,117,115,112,101,110,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]},{dt,[],[{code,[],[<<110,111,99,111,110,110,101,99,116>>]}]},{dd,[],[<<73,102,32,116,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,110,111,100,101,32,119,111,117,108,100,32,104,97,118,101,32,116,111,32,98,101,32,97,117,116,111,45,99,111,110,110,101,99,116,101,100,32,116,111,32,100,111,32,116,104,101,32,115,101,110,100,44,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<65,115,32,119,105,116,104,32>>,{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50,44,51>>]},<<58,32,117,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{signature => [{attribute,{2797,2},spec,{{erlang,send,3},[{type,{2797,18},bounded_fun,[{type,{2797,18},'fun',[{type,{2797,18},product,[{var,{2797,19},'Dest'},{var,{2797,25},'Msg'},{var,{2797,30},'Options'}]},{var,{2797,42},'Res'}]},[{type,{2798,7},constraint,[{atom,{2798,7},is_subtype},[{var,{2798,7},'Dest'},{user_type,{2798,15},send_destination,[]}]]},{type,{2799,7},constraint,[{atom,{2799,7},is_subtype},[{var,{2799,7},'Msg'},{type,{2799,14},term,[]}]]},{type,{2800,7},constraint,[{atom,{2800,7},is_subtype},[{var,{2800,7},'Options'},{type,{2800,18},list,[{type,{2800,19},union,[{atom,{2800,19},nosuspend},{atom,{2800,31},noconnect}]}]}]]},{type,{2801,7},constraint,[{atom,{2801,7},is_subtype},[{var,{2801,7},'Res'},{type,{2801,14},union,[{atom,{2801,14},ok},{atom,{2801,19},nosuspend},{atom,{2801,31},noconnect}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,49,48>>}},{{function,send_after,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2096}],[<<115,101,110,100,95,97,102,116,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,40,84,105,109,101,44,32,68,101,115,116,44,32,77,115,103,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2096,2},spec,{{erlang,send_after,3},[{type,{2096,24},bounded_fun,[{type,{2096,24},'fun',[{type,{2096,24},product,[{var,{2096,25},'Time'},{var,{2096,31},'Dest'},{var,{2096,37},'Msg'}]},{var,{2096,45},'TimerRef'}]},[{type,{2097,7},constraint,[{atom,{2097,7},is_subtype},[{var,{2097,7},'Time'},{type,{2097,15},non_neg_integer,[]}]]},{type,{2098,7},constraint,[{atom,{2098,7},is_subtype},[{var,{2098,7},'Dest'},{type,{2098,15},union,[{type,{2098,15},pid,[]},{type,{2098,23},atom,[]}]}]]},{type,{2099,7},constraint,[{atom,{2099,7},is_subtype},[{var,{2099,7},'Msg'},{type,{2099,14},term,[]}]]},{type,{2100,7},constraint,[{atom,{2100,7},is_subtype},[{var,{2100,7},'TimerRef'},{type,{2100,19},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,52,55>>}},{{function,send_after,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2106}],[<<115,101,110,100,95,97,102,116,101,114,47,52>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,87,104,101,110,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,101,115,116>>]},<<46,32,65,112,97,114,116,32,102,114,111,109,32,116,104,101,32,102,111,114,109,97,116,32,111,102,32,116,104,101,32,116,105,109,101,45,111,117,116,32,109,101,115,115,97,103,101,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,111,114,107,115,32,101,120,97,99,116,108,121,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,47,52>>]}]},<<46>>]}]},#{signature => [{attribute,{2106,2},spec,{{erlang,send_after,4},[{type,{2106,24},bounded_fun,[{type,{2106,24},'fun',[{type,{2106,24},product,[{var,{2106,25},'Time'},{var,{2106,31},'Dest'},{var,{2106,37},'Msg'},{var,{2106,42},'Options'}]},{var,{2106,54},'TimerRef'}]},[{type,{2107,7},constraint,[{atom,{2107,7},is_subtype},[{var,{2107,7},'Time'},{type,{2107,15},integer,[]}]]},{type,{2108,7},constraint,[{atom,{2108,7},is_subtype},[{var,{2108,7},'Dest'},{type,{2108,15},union,[{type,{2108,15},pid,[]},{type,{2108,23},atom,[]}]}]]},{type,{2109,7},constraint,[{atom,{2109,7},is_subtype},[{var,{2109,7},'Msg'},{type,{2109,14},term,[]}]]},{type,{2110,7},constraint,[{atom,{2110,7},is_subtype},[{var,{2110,7},'Options'},{type,{2110,18},list,[{var,{2110,19},'Option'}]}]]},{type,{2111,7},constraint,[{atom,{2111,7},is_subtype},[{var,{2111,7},'Abs'},{type,{2111,14},boolean,[]}]]},{type,{2112,7},constraint,[{atom,{2112,7},is_subtype},[{var,{2112,7},'Option'},{type,{2112,17},tuple,[{atom,{2112,18},abs},{var,{2112,23},'Abs'}]}]]},{type,{2113,7},constraint,[{atom,{2113,7},is_subtype},[{var,{2113,7},'TimerRef'},{type,{2113,19},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,53,56>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,send_nosuspend,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3743}],[<<115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,40,68,101,115,116,44,32,77,115,103,44,32,91,110,111,115,117,115,112,101,110,100,93,41>>]}]},<<44,32,98,117,116,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,109,101,115,115,97,103,101,32,119,97,115,32,115,101,110,116,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,109,101,115,115,97,103,101,32,119,97,115,32,110,111,116,32,115,101,110,116,32,98,101,99,97,117,115,101,32,116,104,101,32,115,101,110,100,101,114,32,119,111,117,108,100,32,104,97,118,101,32,104,97,100,32,116,111,32,98,101,32,115,117,115,112,101,110,100,101,100,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,97,110,32,117,110,114,101,108,105,97,98,108,101,32,114,101,109,111,116,101,32,110,111,100,101,32,119,105,116,104,111,117,116,32,101,118,101,114,32,98,108,111,99,107,105,110,103,32,116,104,101,32,115,101,110,100,105,110,103,32,40,69,114,108,97,110,103,41,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,32,40,117,115,117,97,108,108,121,32,110,111,116,32,97,32,114,101,97,108,32,69,114,108,97,110,103,32,110,111,100,101,44,32,98,117,116,32,97,32,110,111,100,101,32,119,114,105,116,116,101,110,32,105,110,32,67,32,111,114,32,74,97,118,97,41,32,105,115,32,111,118,101,114,108,111,97,100,101,100,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32>>,{em,[],[<<100,111,101,115,32,110,111,116,32,115,101,110,100,32,116,104,101,32,109,101,115,115,97,103,101>>]},<<32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<84,104,101,32,115,97,109,101,32,111,99,99,117,114,115,32,105,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,108,111,99,97,108,32,112,111,114,116,32,116,104,97,116,32,105,115,32,98,117,115,121,46,32,70,111,114,32,97,108,108,32,111,116,104,101,114,32,100,101,115,116,105,110,97,116,105,111,110,115,32,40,97,108,108,111,119,101,100,32,102,111,114,32,116,104,101,32,111,114,100,105,110,97,114,121,32,115,101,110,100,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<39,33,39>>]},<<41,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,115,101,110,100,115,32,116,104,101,32,109,101,115,115,97,103,101,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,114,97,114,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,32,119,104,101,114,101,32,97,32,112,114,111,99,101,115,115,32,99,111,109,109,117,110,105,99,97,116,101,115,32,119,105,116,104,32,69,114,108,97,110,103,32,110,111,100,101,115,32,116,104,97,116,32,99,97,110,32,100,105,115,97,112,112,101,97,114,32,119,105,116,104,111,117,116,32,97,110,121,32,116,114,97,99,101,44,32,99,97,117,115,105,110,103,32,116,104,101,32,84,67,80,32,98,117,102,102,101,114,115,32,97,110,100,32,116,104,101,32,100,114,105,118,101,114,115,32,113,117,101,117,101,32,116,111,32,98,101,32,111,118,101,114,45,102,117,108,108,32,98,101,102,111,114,101,32,116,104,101,32,110,111,100,101,32,105,115,32,115,104,117,116,32,100,111,119,110,32,40,98,101,99,97,117,115,101,32,111,102,32,116,105,99,107,32,116,105,109,101,45,111,117,116,115,41,32,98,121,32>>,{code,[],[<<110,101,116,95,107,101,114,110,101,108>>]},<<46,32,84,104,101,32,110,111,114,109,97,108,32,114,101,97,99,116,105,111,110,32,116,111,32,116,97,107,101,32,119,104,101,110,32,116,104,105,115,32,111,99,99,117,114,115,32,105,115,32,115,111,109,101,32,107,105,110,100,32,111,102,32,112,114,101,109,97,116,117,114,101,32,115,104,117,116,100,111,119,110,32,111,102,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,103,110,111,114,105,110,103,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,111,117,108,100,32,114,101,115,117,108,116,32,105,110,32,97,110,32>>,{em,[],[<<117,110,114,101,108,105,97,98,108,101>>]},<<32,109,101,115,115,97,103,101,32,112,97,115,115,105,110,103,44,32,119,104,105,99,104,32,105,115,32,99,111,110,116,114,97,100,105,99,116,111,114,121,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,105,110,103,32,109,111,100,101,108,46,32,84,104,101,32,109,101,115,115,97,103,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,115,101,110,116,32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<73,110,32,109,97,110,121,32,115,121,115,116,101,109,115,44,32,116,114,97,110,115,105,101,110,116,32,115,116,97,116,101,115,32,111,102,32,111,118,101,114,108,111,97,100,101,100,32,113,117,101,117,101,115,32,97,114,101,32,110,111,114,109,97,108,46,32,65,108,116,104,111,117,103,104,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,100,111,101,115,32,110,111,116,32,109,101,97,110,32,116,104,97,116,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,110,111,110,45,114,101,115,112,111,110,115,105,118,101,44,32,105,116,32,99,111,117,108,100,32,98,101,32,97,32,116,101,109,112,111,114,97,114,121,32,111,118,101,114,108,111,97,100,46,32,65,108,115,111,44,32,97,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<116,114,117,101>>]},<<32,100,111,101,115,32,111,110,108,121,32,109,101,97,110,32,116,104,97,116,32,116,104,101,32,109,101,115,115,97,103,101,32,99,97,110,32,98,101,32,115,101,110,116,32,111,110,32,116,104,101,32,40,84,67,80,41,32,99,104,97,110,110,101,108,32,119,105,116,104,111,117,116,32,98,108,111,99,107,105,110,103,59,32,116,104,101,32,109,101,115,115,97,103,101,32,105,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,97,114,114,105,118,101,32,97,116,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,46,32,70,111,114,32,97,32,100,105,115,99,111,110,110,101,99,116,101,100,32,110,111,110,45,114,101,115,112,111,110,115,105,118,101,32,110,111,100,101,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,40,109,105,109,105,99,115,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<33>>]},<<41,46,32,84,104,101,32,101,120,112,101,99,116,101,100,32,98,101,104,97,118,105,111,114,32,97,110,100,32,116,104,101,32,97,99,116,105,111,110,115,32,116,111,32,116,97,107,101,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,97,114,101,32,97,112,112,108,105,99,97,116,105,111,110,45,32,97,110,100,32,104,97,114,100,119,97,114,101,45,115,112,101,99,105,102,105,99,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<85,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{signature => [{attribute,{3743,2},spec,{{erlang,send_nosuspend,2},[{type,{3743,28},bounded_fun,[{type,{3743,28},'fun',[{type,{3743,28},product,[{var,{3743,29},'Dest'},{var,{3743,35},'Msg'}]},{type,{3743,43},boolean,[]}]},[{type,{3744,7},constraint,[{atom,{3744,7},is_subtype},[{var,{3744,7},'Dest'},{user_type,{3744,15},send_destination,[]}]]},{type,{3745,7},constraint,[{atom,{3745,7},is_subtype},[{var,{3745,7},'Msg'},{type,{3745,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,53,55,49>>}},{{function,send_nosuspend,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3753}],[<<115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,40,68,101,115,116,44,32,77,115,103,44,32,91,110,111,115,117,115,112,101,110,100,32,124,32,79,112,116,105,111,110,115,93,41>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,32,66,111,111,108,101,97,110,32,114,101,116,117,114,110,32,118,97,108,117,101,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,98,101,104,97,118,101,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,110,111,115,117,115,112,101,110,100,47,50>>]}]},<<44,32,98,117,116,32,116,97,107,101,115,32,97,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,44,32,97,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46,32,84,104,101,32,111,110,108,121,32,111,112,116,105,111,110,32,105,115,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<44,32,119,104,105,99,104,32,109,97,107,101,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,114,101,109,111,116,101,32,110,111,100,101,32,105,115,32,110,111,116,32,99,117,114,114,101,110,116,108,121,32,114,101,97,99,104,97,98,108,101,32,98,121,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,110,111,114,109,97,108,32,98,101,104,97,118,105,111,114,32,105,115,32,116,111,32,116,114,121,32,116,111,32,99,111,110,110,101,99,116,32,116,111,32,116,104,101,32,110,111,100,101,44,32,119,104,105,99,104,32,99,97,110,32,115,116,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,32,100,117,114,105,110,103,32,97,32,115,104,111,114,116,32,112,101,114,105,111,100,46,32,84,104,101,32,117,115,101,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,98,101,32,115,117,114,101,32,110,111,116,32,116,111,32,103,101,116,32,116,104,101,32,115,108,105,103,104,116,101,115,116,32,100,101,108,97,121,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,111,32,97,32,114,101,109,111,116,101,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,105,115,32,101,115,112,101,99,105,97,108,108,121,32,117,115,101,102,117,108,32,119,104,101,110,32,99,111,109,109,117,110,105,99,97,116,105,110,103,32,119,105,116,104,32,110,111,100,101,115,32,116,104,97,116,32,101,120,112,101,99,116,32,116,111,32,97,108,119,97,121,115,32,98,101,32,116,104,101,32,99,111,110,110,101,99,116,105,110,103,32,112,97,114,116,32,40,116,104,97,116,32,105,115,44,32,110,111,100,101,115,32,119,114,105,116,116,101,110,32,105,110,32,67,32,111,114,32,74,97,118,97,41,46>>]},{p,[],[<<87,104,101,110,101,118,101,114,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,40,101,105,116,104,101,114,32,119,104,101,110,32,97,32,115,117,115,112,101,110,100,32,119,111,117,108,100,32,111,99,99,117,114,32,111,114,32,119,104,101,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116>>]},<<32,119,97,115,32,115,112,101,99,105,102,105,101,100,32,97,110,100,32,116,104,101,32,110,111,100,101,32,119,97,115,32,110,111,116,32,97,108,114,101,97,100,121,32,99,111,110,110,101,99,116,101,100,41,44,32,116,104,101,32,109,101,115,115,97,103,101,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32>>,{em,[],[<<110,111,116>>]},<<32,116,111,32,104,97,118,101,32,98,101,101,110,32,115,101,110,116,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<85,115,101,32,119,105,116,104,32,101,120,116,114,101,109,101,32,99,97,114,101,46>>]}]}]},#{signature => [{attribute,{3753,2},spec,{{erlang,send_nosuspend,3},[{type,{3753,28},bounded_fun,[{type,{3753,28},'fun',[{type,{3753,28},product,[{var,{3753,29},'Dest'},{var,{3753,35},'Msg'},{var,{3753,40},'Options'}]},{type,{3753,52},boolean,[]}]},[{type,{3754,7},constraint,[{atom,{3754,7},is_subtype},[{var,{3754,7},'Dest'},{user_type,{3754,15},send_destination,[]}]]},{type,{3755,7},constraint,[{atom,{3755,7},is_subtype},[{var,{3755,7},'Msg'},{type,{3755,14},term,[]}]]},{type,{3756,7},constraint,[{atom,{3756,7},is_subtype},[{var,{3756,7},'Options'},{type,{3756,18},list,[{atom,{3756,19},noconnect}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,50,48>>}},{{function,set_cookie,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4062}],[<<115,101,116,95,99,111,111,107,105,101,47,49>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,116,111,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<67,111,111,107,105,101>>]},<<44,32,119,104,105,99,104,32,105,115,32,97,108,115,111,32,116,104,101,32,99,111,111,107,105,101,32,102,111,114,32,97,108,108,32,110,111,100,101,115,32,116,104,97,116,32,104,97,118,101,32,110,111,32,101,120,112,108,105,99,105,116,32,99,111,111,107,105,101,32,115,101,116,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,116,95,99,111,111,107,105,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,101,116,95,99,111,111,107,105,101,47,50>>]}]},<<32>>,{code,[],[<<67,111,111,107,105,101>>]},<<32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,105,115,116,114,105,98,117,116,101,100,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,32,105,110,32,83,121,115,116,101,109,32,68,111,99,117,109,101,110,116,97,116,105,111,110,41,46>>]},{p,[],[<<89,111,117,32,99,97,110,32,103,101,116,32,116,104,105,115,32,118,97,108,117,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,101,116,95,99,111,111,107,105,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,116,95,99,111,111,107,105,101,47,48>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<102,117,110,99,116,105,111,110,95,99,108,97,117,115,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]},#{signature => [{attribute,{4062,2},spec,{{erlang,set_cookie,1},[{type,{4062,24},bounded_fun,[{type,{4062,24},'fun',[{type,{4062,24},product,[{var,{4062,25},'Cookie'}]},{atom,{4062,36},true}]},[{type,{4063,7},constraint,[{atom,{4063,7},is_subtype},[{var,{4063,7},'Cookie'},{type,{4063,17},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,53,50>>,since => <<79,84,80,32,50,52,46,49>>}},{{function,set_cookie,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,4069}],[<<115,101,116,95,99,111,111,107,105,101,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,103,105,99,32,99,111,111,107,105,101,32,102,111,114,32>>,{code,[],[<<78,111,100,101>>]},<<32,116,111,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<67,111,111,107,105,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,115,101,116,115,32,116,104,101,32,99,111,111,107,105,101,32,111,102,32,97,108,108,32,111,116,104,101,114,32,110,111,100,101,115,32,40,116,104,97,116,32,104,97,118,101,32,110,111,32,101,120,112,108,105,99,105,116,32,99,111,111,107,105,101,32,115,101,116,32,119,105,116,104,32,116,104,105,115,32,102,117,110,99,116,105,111,110,41,32,116,111,32>>,{code,[],[<<67,111,111,107,105,101>>]},<<32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<68,105,115,116,114,105,98,117,116,101,100,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,32,105,110,32,83,121,115,116,101,109,32,68,111,99,117,109,101,110,116,97,116,105,111,110,41,46>>]},{p,[],[<<89,111,117,32,99,97,110,32,103,101,116,32,116,104,105,115,32,118,97,108,117,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,101,116,95,99,111,111,107,105,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,116,95,99,111,111,107,105,101,47,49>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<102,117,110,99,116,105,111,110,95,99,108,97,117,115,101>>]},<<32,105,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]}]},#{signature => [{attribute,{4069,2},spec,{{erlang,set_cookie,2},[{type,{4069,24},bounded_fun,[{type,{4069,24},'fun',[{type,{4069,24},product,[{var,{4069,25},'Node'},{var,{4069,31},'Cookie'}]},{atom,{4069,42},true}]},[{type,{4070,7},constraint,[{atom,{4070,7},is_subtype},[{var,{4070,7},'Node'},{type,{4070,15},node,[]}]]},{type,{4071,7},constraint,[{atom,{4071,7},is_subtype},[{var,{4071,7},'Cookie'},{type,{4071,17},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,55,49>>}},{{function,setelement,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2818}],[<<115,101,116,101,108,101,109,101,110,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,116,104,97,116,32,105,115,32,97,32,99,111,112,121,32,111,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<84,117,112,108,101,49>>]},<<32,119,105,116,104,32,116,104,101,32,101,108,101,109,101,110,116,32,115,112,101,99,105,102,105,101,100,32,98,121,32,105,110,116,101,103,101,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<73,110,100,101,120>>]},<<32,40,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,101,108,101,109,101,110,116,32,119,105,116,104,32,105,110,100,101,120,32,49,41,32,114,101,112,108,97,99,101,100,32,98,121,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<86,97,108,117,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,101,116,101,108,101,109,101,110,116,40,50,44,32,123,49,48,44,32,103,114,101,101,110,44,32,98,111,116,116,108,101,115,125,44,32,114,101,100,41,46,10,123,49,48,44,114,101,100,44,98,111,116,116,108,101,115,125>>]}]}]},#{signature => [{attribute,{2818,2},spec,{{setelement,3},[{type,{2818,17},bounded_fun,[{type,{2818,17},'fun',[{type,{2818,17},product,[{var,{2818,18},'Index'},{var,{2818,25},'Tuple1'},{var,{2818,33},'Value'}]},{var,{2818,43},'Tuple2'}]},[{type,{2819,7},constraint,[{atom,{2819,7},is_subtype},[{var,{2819,7},'Index'},{type,{2819,16},pos_integer,[]}]]},{type,{2820,7},constraint,[{atom,{2820,7},is_subtype},[{var,{2820,7},'Tuple1'},{type,{2820,17},tuple,any}]]},{type,{2821,7},constraint,[{atom,{2821,7},is_subtype},[{var,{2821,7},'Tuple2'},{type,{2821,17},tuple,any}]]},{type,{2822,7},constraint,[{atom,{2822,7},is_subtype},[{var,{2822,7},'Value'},{type,{2822,16},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,54,57,48>>}},{{function,size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2167}],[<<115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32,97,32,116,117,112,108,101,32,111,114,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,110,32,97,32,98,105,110,97,114,121,32,111,114,32,98,105,116,115,116,114,105,110,103,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,105,122,101,40,123,109,111,114,110,105,44,32,109,117,108,108,101,44,32,98,119,97,110,103,101,125,41,46,10,51,10,62,32,115,105,122,101,40,60,60,49,49,44,32,50,50,44,32,51,51,62,62,41,46,10,51>>]}]},{p,[],[<<70,111,114,32,98,105,116,115,116,114,105,110,103,115,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,119,104,111,108,101,32,98,121,116,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,105,116,115,32,105,110,32,116,104,101,32,98,105,116,115,116,114,105,110,103,32,105,115,32,110,111,116,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,44,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,105,115,32,114,111,117,110,100,101,100,32>>,{em,[],[<<100,111,119,110>>]},<<46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,117,112,108,101,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,117,112,108,101,95,115,105,122,101,47,49>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,121,116,101,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,121,116,101,95,115,105,122,101,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,116,95,115,105,122,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,116,95,115,105,122,101,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{2167,2},spec,{{size,1},[{type,{2167,11},bounded_fun,[{type,{2167,11},'fun',[{type,{2167,11},product,[{var,{2167,12},'Item'}]},{type,{2167,21},non_neg_integer,[]}]},[{type,{2168,7},constraint,[{atom,{2168,7},is_subtype},[{var,{2168,7},'Item'},{type,{2168,15},union,[{type,{2168,15},tuple,any},{type,{2168,25},binary,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,48,55>>}},{{function,spawn,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3214}],[<<115,112,97,119,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3214,2},spec,{{spawn,1},[{type,{3214,12},bounded_fun,[{type,{3214,12},'fun',[{type,{3214,12},product,[{var,{3214,13},'Fun'}]},{type,{3214,21},pid,[]}]},[{type,{3215,7},constraint,[{atom,{3215,7},is_subtype},[{var,{3215,7},'Fun'},{type,{3215,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,51,48>>}},{{function,spawn,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3223}],[<<115,112,97,119,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3223,2},spec,{{spawn,2},[{type,{3223,12},bounded_fun,[{type,{3223,12},'fun',[{type,{3223,12},product,[{var,{3223,13},'Node'},{var,{3223,19},'Fun'}]},{type,{3223,27},pid,[]}]},[{type,{3224,7},constraint,[{atom,{3224,7},is_subtype},[{var,{3224,7},'Node'},{type,{3224,15},node,[]}]]},{type,{3225,7},constraint,[{atom,{3225,7},is_subtype},[{var,{3225,7},'Fun'},{type,{3225,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,52,49>>}},{{function,spawn,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2173}],[<<115,112,97,119,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]},{p,[],[{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114,58,117,110,100,101,102,105,110,101,100,95,102,117,110,99,116,105,111,110,40,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,103,115,41>>]},<<32,105,115,32,101,118,97,108,117,97,116,101,100,32,98,121,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,105,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,40,119,104,101,114,101,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<41,46,32,84,104,101,32,101,114,114,111,114,32,104,97,110,100,108,101,114,32,99,97,110,32,98,101,32,114,101,100,101,102,105,110,101,100,32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<41,46,32,73,102,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,111,114,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,100,101,102,105,110,101,100,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<101,114,114,111,114,95,104,97,110,100,108,101,114>>]},<<32,97,110,100,32,105,116,115,32,114,101,112,108,97,99,101,109,101,110,116,32,105,115,32,117,110,100,101,102,105,110,101,100,44,32,97,32,102,97,105,108,117,114,101,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<117,110,100,101,102>>]},<<32,111,99,99,117,114,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,112,97,119,110,40,115,112,101,101,100,44,32,114,101,103,117,108,97,116,111,114,44,32,91,104,105,103,104,95,115,112,101,101,100,44,32,116,104,105,110,95,99,117,116,93,41,46,10,60,48,46,49,51,46,49,62>>]}]}]},#{signature => [{attribute,{2173,2},spec,{{spawn,3},[{type,{2173,12},bounded_fun,[{type,{2173,12},'fun',[{type,{2173,12},product,[{var,{2173,13},'Module'},{var,{2173,21},'Function'},{var,{2173,31},'Args'}]},{type,{2173,40},pid,[]}]},[{type,{2174,7},constraint,[{atom,{2174,7},is_subtype},[{var,{2174,7},'Module'},{type,{2174,17},module,[]}]]},{type,{2175,7},constraint,[{atom,{2175,7},is_subtype},[{var,{2175,7},'Function'},{type,{2175,19},atom,[]}]]},{type,{2176,7},constraint,[{atom,{2176,7},is_subtype},[{var,{2176,7},'Args'},{type,{2176,15},list,[{type,{2176,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,53,53>>}},{{function,spawn,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3354}],[<<115,112,97,119,110,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3354,2},spec,{{spawn,4},[{type,{3354,12},bounded_fun,[{type,{3354,12},'fun',[{type,{3354,12},product,[{var,{3354,13},'Node'},{var,{3354,19},'Module'},{var,{3354,27},'Function'},{var,{3354,37},'Args'}]},{type,{3354,46},pid,[]}]},[{type,{3355,7},constraint,[{atom,{3355,7},is_subtype},[{var,{3355,7},'Node'},{type,{3355,15},node,[]}]]},{type,{3356,7},constraint,[{atom,{3356,7},is_subtype},[{var,{3356,7},'Module'},{type,{3356,17},module,[]}]]},{type,{3357,7},constraint,[{atom,{3357,7},is_subtype},[{var,{3357,7},'Function'},{type,{3357,19},atom,[]}]]},{type,{3358,7},constraint,[{atom,{3358,7},is_subtype},[{var,{3358,7},'Args'},{type,{3358,15},list,[{type,{3358,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,56,48>>}},{{function,spawn_link,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3235}],[<<115,112,97,119,110,95,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3235,2},spec,{{spawn_link,1},[{type,{3235,17},bounded_fun,[{type,{3235,17},'fun',[{type,{3235,17},product,[{var,{3235,18},'Fun'}]},{type,{3235,26},pid,[]}]},[{type,{3236,7},constraint,[{atom,{3236,7},is_subtype},[{var,{3236,7},'Fun'},{type,{3236,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,55,57,53>>}},{{function,spawn_link,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3244}],[<<115,112,97,119,110,95,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3244,2},spec,{{spawn_link,2},[{type,{3244,17},bounded_fun,[{type,{3244,17},'fun',[{type,{3244,17},product,[{var,{3244,18},'Node'},{var,{3244,24},'Fun'}]},{type,{3244,32},pid,[]}]},[{type,{3245,7},constraint,[{atom,{3245,7},is_subtype},[{var,{3245,7},'Node'},{type,{3245,15},node,[]}]]},{type,{3246,7},constraint,[{atom,{3246,7},is_subtype},[{var,{3246,7},'Fun'},{type,{3246,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,48,57>>}},{{function,spawn_link,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2181}],[<<115,112,97,119,110,95,108,105,110,107,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{2181,2},spec,{{spawn_link,3},[{type,{2181,17},bounded_fun,[{type,{2181,17},'fun',[{type,{2181,17},product,[{var,{2181,18},'Module'},{var,{2181,26},'Function'},{var,{2181,36},'Args'}]},{type,{2181,45},pid,[]}]},[{type,{2182,7},constraint,[{atom,{2182,7},is_subtype},[{var,{2182,7},'Module'},{type,{2182,17},module,[]}]]},{type,{2183,7},constraint,[{atom,{2183,7},is_subtype},[{var,{2183,7},'Function'},{type,{2183,19},atom,[]}]]},{type,{2184,7},constraint,[{atom,{2184,7},is_subtype},[{var,{2184,7},'Args'},{type,{2184,15},list,[{type,{2184,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,50,54>>}},{{function,spawn_link,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3376}],[<<115,112,97,119,110,95,108,105,110,107,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,108,105,110,107,32,105,115,32,99,114,101,97,116,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,97,116,111,109,105,99,97,108,108,121,46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3376,2},spec,{{spawn_link,4},[{type,{3376,17},bounded_fun,[{type,{3376,17},'fun',[{type,{3376,17},product,[{var,{3376,18},'Node'},{var,{3376,24},'Module'},{var,{3376,32},'Function'},{var,{3376,42},'Args'}]},{type,{3376,51},pid,[]}]},[{type,{3377,7},constraint,[{atom,{3377,7},is_subtype},[{var,{3377,7},'Node'},{type,{3377,15},node,[]}]]},{type,{3378,7},constraint,[{atom,{3378,7},is_subtype},[{var,{3378,7},'Module'},{type,{3378,17},module,[]}]]},{type,{3379,7},constraint,[{atom,{3379,7},is_subtype},[{var,{3379,7},'Function'},{type,{3379,19},atom,[]}]]},{type,{3380,7},constraint,[{atom,{3380,7},is_subtype},[{var,{3380,7},'Args'},{type,{3380,15},list,[{type,{3380,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,52,48>>}},{{function,spawn_monitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3258}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,44,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<44,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,97,32,109,111,110,105,116,111,114,32,99,114,101,97,116,101,100,32,116,111,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3258,2},spec,{{spawn_monitor,1},[{type,{3258,20},bounded_fun,[{type,{3258,20},'fun',[{type,{3258,20},product,[{var,{3258,21},'Fun'}]},{type,{3258,29},tuple,[{type,{3258,30},pid,[]},{type,{3258,37},reference,[]}]}]},[{type,{3259,7},constraint,[{atom,{3259,7},is_subtype},[{var,{3259,7},'Fun'},{type,{3259,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,53,56>>}},{{function,spawn_monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3265}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,44,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<44,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,97,32,109,111,110,105,116,111,114,32,99,114,101,97,116,101,100,32,116,111,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,100,105,115,116,114,105,98,117,116,101,100,32>>,{code,[],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,40,41>>]},<<44,32,116,104,101,32,99,97,108,108,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,46>>]}]},#{signature => [{attribute,{3265,2},spec,{{spawn_monitor,2},[{type,{3265,20},bounded_fun,[{type,{3265,20},'fun',[{type,{3265,20},product,[{var,{3265,21},'Node'},{var,{3265,27},'Fun'}]},{type,{3265,35},tuple,[{type,{3265,36},pid,[]},{type,{3265,43},reference,[]}]}]},[{type,{3266,7},constraint,[{atom,{3266,7},is_subtype},[{var,{3266,7},'Node'},{type,{3266,15},node,[]}]]},{type,{3267,7},constraint,[{atom,{3267,7},is_subtype},[{var,{3267,7},'Fun'},{type,{3267,14},function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,55,50>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_monitor,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3279}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,51>>],#{<<101,110>> => [{p,[],[<<65,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46,32,84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{3279,2},spec,{{spawn_monitor,3},[{type,{3279,20},bounded_fun,[{type,{3279,20},'fun',[{type,{3279,20},product,[{var,{3279,21},'Module'},{var,{3279,29},'Function'},{var,{3279,39},'Args'}]},{type,{3279,48},tuple,[{type,{3279,49},pid,[]},{type,{3279,56},reference,[]}]}]},[{type,{3280,7},constraint,[{atom,{3280,7},is_subtype},[{var,{3280,7},'Module'},{type,{3280,17},module,[]}]]},{type,{3281,7},constraint,[{atom,{3281,7},is_subtype},[{var,{3281,7},'Function'},{type,{3281,19},atom,[]}]]},{type,{3282,7},constraint,[{atom,{3282,7},is_subtype},[{var,{3282,7},'Args'},{type,{3282,15},list,[{type,{3282,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,56,56,57>>}},{{function,spawn_monitor,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3398}],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,47,52>>],#{<<101,110>> => [{p,[],[<<65,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32,116,104,101,32,110,111,100,101,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,84,104,101,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,97,110,100,32,97,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,100,105,115,116,114,105,98,117,116,101,100,32>>,{code,[],[<<115,112,97,119,110,95,109,111,110,105,116,111,114,40,41>>]},<<44,32,116,104,101,32,99,97,108,108,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,101,120,99,101,112,116,105,111,110,46>>]}]},#{signature => [{attribute,{3398,2},spec,{{spawn_monitor,4},[{type,{3398,20},bounded_fun,[{type,{3398,20},'fun',[{type,{3398,20},product,[{var,{3398,21},'Node'},{var,{3398,27},'Module'},{var,{3398,35},'Function'},{var,{3398,45},'Args'}]},{type,{3398,54},tuple,[{type,{3398,55},pid,[]},{type,{3398,62},reference,[]}]}]},[{type,{3399,7},constraint,[{atom,{3399,7},is_subtype},[{var,{3399,7},'Node'},{type,{3399,15},node,[]}]]},{type,{3400,7},constraint,[{atom,{3400,7},is_subtype},[{var,{3400,7},'Module'},{type,{3400,17},module,[]}]]},{type,{3401,7},constraint,[{atom,{3401,7},is_subtype},[{var,{3401,7},'Function'},{type,{3401,19},atom,[]}]]},{type,{3402,7},constraint,[{atom,{3402,7},is_subtype},[{var,{3402,7},'Args'},{type,{3402,15},list,[{type,{3402,16},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,48,51>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_opt,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3311}],[<<115,112,97,119,110,95,111,112,116,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,44,32,97,110,100,32,98,111,116,104,32,116,104,101,32,112,105,100,32,97,110,100,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,32,97,114,101,32,114,101,116,117,114,110,101,100,46>>]}]},#{signature => [{attribute,{3311,2},spec,{{spawn_opt,2},[{type,{3311,16},bounded_fun,[{type,{3311,16},'fun',[{type,{3311,16},product,[{var,{3311,17},'Fun'},{var,{3311,22},'Options'}]},{type,{3311,34},union,[{type,{3311,34},pid,[]},{type,{3311,42},tuple,[{type,{3311,43},pid,[]},{type,{3311,50},reference,[]}]}]}]},[{type,{3312,7},constraint,[{atom,{3312,7},is_subtype},[{var,{3312,7},'Fun'},{type,{3312,14},function,[]}]]},{type,{3313,7},constraint,[{atom,{3313,7},is_subtype},[{var,{3313,7},'Options'},{type,{3313,18},list,[{user_type,{3313,19},spawn_opt_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,50,48>>}},{{function,spawn_opt,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3326}],[<<115,112,97,119,110,95,111,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<70,117,110>>]},<<32,116,111,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<86,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]},#{signature => [{attribute,{3326,2},spec,{{spawn_opt,3},[{type,{3326,16},bounded_fun,[{type,{3326,16},'fun',[{type,{3326,16},product,[{var,{3326,17},'Node'},{var,{3326,23},'Fun'},{var,{3326,28},'Options'}]},{type,{3326,40},union,[{type,{3326,40},pid,[]},{type,{3326,48},tuple,[{type,{3326,49},pid,[]},{type,{3326,56},reference,[]}]}]}]},[{type,{3327,7},constraint,[{atom,{3327,7},is_subtype},[{var,{3327,7},'Node'},{type,{3327,15},node,[]}]]},{type,{3328,7},constraint,[{atom,{3328,7},is_subtype},[{var,{3328,7},'Fun'},{type,{3328,14},function,[]}]]},{type,{3329,7},constraint,[{atom,{3329,7},is_subtype},[{var,{3329,7},'Options'},{type,{3329,18},list,[{type,{3329,19},union,[{atom,{3329,19},monitor},{type,{3330,19},tuple,[{atom,{3330,20},monitor},{type,{3330,29},list,[{user_type,{3330,30},monitor_option,[]}]}]},{atom,{3331,19},link},{var,{3332,19},'OtherOption'}]}]}]]},{type,{3333,7},constraint,[{atom,{3333,7},is_subtype},[{var,{3333,7},'OtherOption'},{type,{3333,22},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,51,56>>}},{{function,spawn_opt,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3443}],[<<115,112,97,119,110,95,111,112,116,47,52>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{li,[{name,<<112,114,105,111,114,105,116,121,95,108,101,118,101,108>>}],[]},{li,[{name,<<115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<87,111,114,107,115,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,47,51>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,97,110,32,101,120,116,114,97,32,111,112,116,105,111,110,32,108,105,115,116,32,105,115,32,115,112,101,99,105,102,105,101,100,32,119,104,101,110,32,99,114,101,97,116,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,32,105,115,32,109,111,110,105,116,111,114,101,100,44,32,97,110,100,32,98,111,116,104,32,116,104,101,32,112,105,100,32,97,110,100,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,116,104,101,32,109,111,110,105,116,111,114,32,97,114,101,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,105,110,107>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,97,32,108,105,110,107,32,116,111,32,116,104,101,32,112,97,114,101,110,116,32,112,114,111,99,101,115,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,108,105,110,107,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,108,105,110,107,47,51>>]}]},<<32,100,111,101,115,41,46>>]}]},{dt,[],[{code,[],[<<109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]}]},<<32,100,111,101,115,41,46,32,65,32>>,{code,[],[<<123,80,105,100,44,32,77,111,110,105,116,111,114,82,101,102,125>>]},<<32,116,117,112,108,101,32,119,105,108,108,32,98,101,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,106,117,115,116,32,97,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,44,32,77,111,110,105,116,111,114,79,112,116,115,125>>]}]},{dd,[],[{p,[],[<<77,111,110,105,116,111,114,115,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,119,105,116,104,32,111,112,116,105,111,110,115,32,40,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,44,32,77,111,110,105,116,111,114,79,112,116,115,41>>]}]},<<32,100,111,101,115,41,46,32,65,32>>,{code,[],[<<123,80,105,100,44,32,77,111,110,105,116,111,114,82,101,102,125>>]},<<32,116,117,112,108,101,32,119,105,108,108,32,98,101,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,32,111,102,32,106,117,115,116,32,97,32>>,{code,[],[<<80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,105,111,114,105,116,121,32,111,102,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,46,32,69,113,117,105,118,97,108,101,110,116,32,116,111,32,101,120,101,99,117,116,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<32,105,110,32,116,104,101,32,115,116,97,114,116,32,102,117,110,99,116,105,111,110,32,111,102,32,116,104,101,32,110,101,119,32,112,114,111,99,101,115,115,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,112,114,105,111,114,105,116,121,32,105,115,32,115,101,116,32,98,101,102,111,114,101,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,32,115,101,108,101,99,116,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,105,111,114,105,116,105,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114,44,32,78,117,109,98,101,114,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,117,115,101,115,32,97,32,103,101,110,101,114,97,116,105,111,110,97,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,99,104,101,109,101,44,32,117,115,105,110,103,32,97,110,32,34,111,108,100,32,104,101,97,112,34,32,102,111,114,32,100,97,116,97,32,116,104,97,116,32,104,97,115,32,115,117,114,118,105,118,101,100,32,97,116,32,108,101,97,115,116,32,111,110,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,116,104,101,114,101,32,105,115,32,110,111,32,109,111,114,101,32,114,111,111,109,32,111,110,32,116,104,101,32,111,108,100,32,104,101,97,112,44,32,97,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,103,101,110,101,114,97,116,105,111,110,97,108,32,99,111,108,108,101,99,116,105,111,110,115,32,98,101,102,111,114,101,32,102,111,114,99,105,110,103,32,97,32,102,117,108,108,115,119,101,101,112,44,32,101,118,101,110,32,105,102,32,116,104,101,114,101,32,105,115,32,114,111,111,109,32,111,110,32,116,104,101,32,111,108,100,32,104,101,97,112,46,32,83,101,116,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,116,111,32,122,101,114,111,32,100,105,115,97,98,108,101,115,32,116,104,101,32,103,101,110,101,114,97,108,32,99,111,108,108,101,99,116,105,111,110,32,97,108,103,111,114,105,116,104,109,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,108,105,118,101,32,100,97,116,97,32,105,115,32,99,111,112,105,101,100,32,97,116,32,101,118,101,114,121,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<65,32,102,101,119,32,99,97,115,101,115,32,119,104,101,110,32,105,116,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,116,111,32,99,104,97,110,103,101,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,97,114,101,32,110,111,32,108,111,110,103,101,114,32,117,115,101,100,32,97,114,101,32,116,111,32,98,101,32,116,104,114,111,119,110,32,97,119,97,121,32,97,115,32,115,111,111,110,32,97,115,32,112,111,115,115,105,98,108,101,46,32,40,83,101,116,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,122,101,114,111,46,41>>]}]},{li,[],[{p,[],[<<65,32,112,114,111,99,101,115,115,32,116,104,97,116,32,109,111,115,116,108,121,32,104,97,118,101,32,115,104,111,114,116,45,108,105,118,101,100,32,100,97,116,97,32,105,115,32,102,117,108,108,115,119,101,101,112,101,100,32,115,101,108,100,111,109,32,111,114,32,110,101,118,101,114,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,111,108,100,32,104,101,97,112,32,99,111,110,116,97,105,110,115,32,109,111,115,116,108,121,32,103,97,114,98,97,103,101,46,32,84,111,32,101,110,115,117,114,101,32,97,32,102,117,108,108,115,119,101,101,112,32,111,99,99,97,115,105,111,110,97,108,108,121,44,32,115,101,116,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,97,32,115,117,105,116,97,98,108,101,32,118,97,108,117,101,44,32,115,117,99,104,32,97,115,32,49,48,32,111,114,32,50,48,46>>]}]},{li,[],[<<73,110,32,101,109,98,101,100,100,101,100,32,115,121,115,116,101,109,115,32,119,105,116,104,32,97,32,108,105,109,105,116,101,100,32,97,109,111,117,110,116,32,111,102,32,82,65,77,32,97,110,100,32,110,111,32,118,105,114,116,117,97,108,32,109,101,109,111,114,121,44,32,121,111,117,32,109,105,103,104,116,32,119,97,110,116,32,116,111,32,112,114,101,115,101,114,118,101,32,109,101,109,111,114,121,32,98,121,32,115,101,116,116,105,110,103,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,116,111,32,122,101,114,111,46,32,40,84,104,101,32,118,97,108,117,101,32,99,97,110,32,98,101,32,115,101,116,32,103,108,111,98,97,108,108,121,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,47,50>>]}]},<<46,41>>]}]}]},{dt,[],[{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<71,105,118,101,115,32,97,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,118,97,108,117,101,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,99,97,110,32,115,112,101,101,100,32,117,112,32,115,111,109,101,32,112,114,111,99,101,115,115,101,115,32,98,101,99,97,117,115,101,32,108,101,115,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46,32,72,111,119,101,118,101,114,44,32,115,101,116,116,105,110,103,32,97,32,116,111,111,32,104,105,103,104,32,118,97,108,117,101,32,99,97,110,32,119,97,115,116,101,32,109,101,109,111,114,121,32,97,110,100,32,115,108,111,119,32,100,111,119,110,32,116,104,101,32,115,121,115,116,101,109,32,98,101,99,97,117,115,101,32,111,102,32,119,111,114,115,101,32,100,97,116,97,32,108,111,99,97,108,105,116,121,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,102,111,114,32,102,105,110,101,45,116,117,110,105,110,103,32,97,110,32,97,112,112,108,105,99,97,116,105,111,110,32,97,110,100,32,116,111,32,109,101,97,115,117,114,101,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,119,105,116,104,32,118,97,114,105,111,117,115,32>>,{code,[],[<<83,105,122,101>>]},<<32,118,97,108,117,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,86,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<85,115,101,102,117,108,32,111,110,108,121,32,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,116,117,110,105,110,103,46,32,68,111,32,110,111,116,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,112,114,111,98,108,101,109,32,119,105,116,104,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,115,32,111,114,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,44,32,97,110,100,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,111,112,116,105,111,110,32,105,109,112,114,111,118,101,115,32,109,97,116,116,101,114,115,46>>]},{p,[],[<<71,105,118,101,115,32,97,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,44,32,105,110,32,119,111,114,100,115,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,118,97,108,117,101,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32,115,121,115,116,101,109,32,100,101,102,97,117,108,116,32,99,97,110,32,115,112,101,101,100,32,117,112,32,115,111,109,101,32,112,114,111,99,101,115,115,101,115,32,98,101,99,97,117,115,101,32,108,101,115,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,100,111,110,101,46,32,72,111,119,101,118,101,114,44,32,115,101,116,116,105,110,103,32,97,32,116,111,111,32,104,105,103,104,32,118,97,108,117,101,32,99,97,110,32,119,97,115,116,101,32,109,101,109,111,114,121,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,101,32,116,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,102,111,114,32,102,105,110,101,45,116,117,110,105,110,103,32,97,110,32,97,112,112,108,105,99,97,116,105,111,110,32,97,110,100,32,116,111,32,109,101,97,115,117,114,101,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,119,105,116,104,32,118,97,114,105,111,117,115,32>>,{code,[],[<<86,83,105,122,101>>]},<<32,118,97,108,117,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,46,32,84,104,101,32,100,101,102,97,117,108,116,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,46,32>>,{code,[],[<<77,81,68>>]},<<32,99,97,110,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,112,97,119,110,95,111,112,116,95,97,115,121,110,99,95,100,105,115,116>>}],[]},{code,[],[<<123,97,115,121,110,99,95,100,105,115,116,44,32,69,110,97,98,108,101,100,125>>]}]},{dd,[],[{p,[],[<<83,105,110,99,101,58,32,79,84,80,32,50,53,46,51>>]},{p,[],[<<83,101,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]}]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,32,111,102,32,116,104,101,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,46,32,84,104,105,115,32,111,112,116,105,111,110,32,119,105,108,108,32,111,118,101,114,114,105,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,115,101,116,32,98,121,32,116,104,101,32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,112,97,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,112,97,100,32,60,98,111,111,108,101,97,110,62>>]}]},<<46>>]}]}]}]},#{signature => [{attribute,{3443,2},spec,{{spawn_opt,4},[{type,{3443,16},bounded_fun,[{type,{3443,16},'fun',[{type,{3443,16},product,[{var,{3443,17},'Module'},{var,{3443,25},'Function'},{var,{3443,35},'Args'},{var,{3443,41},'Options'}]},{type,{3444,11},union,[{var,{3444,11},'Pid'},{type,{3444,17},tuple,[{var,{3444,18},'Pid'},{var,{3444,23},'MonitorRef'}]}]}]},[{type,{3445,7},constraint,[{atom,{3445,7},is_subtype},[{var,{3445,7},'Module'},{type,{3445,17},module,[]}]]},{type,{3446,7},constraint,[{atom,{3446,7},is_subtype},[{var,{3446,7},'Function'},{type,{3446,19},atom,[]}]]},{type,{3447,7},constraint,[{atom,{3447,7},is_subtype},[{var,{3447,7},'Args'},{type,{3447,15},list,[{type,{3447,16},term,[]}]}]]},{type,{3448,7},constraint,[{atom,{3448,7},is_subtype},[{var,{3448,7},'Options'},{type,{3448,18},list,[{user_type,{3448,19},spawn_opt_option,[]}]}]]},{type,{3449,7},constraint,[{atom,{3449,7},is_subtype},[{var,{3449,7},'Pid'},{type,{3449,14},pid,[]}]]},{type,{3450,7},constraint,[{atom,{3450,7},is_subtype},[{var,{3450,7},'MonitorRef'},{type,{3450,21},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,55,57,54,49>>}},{{function,spawn_opt,5},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3455}],[<<115,112,97,119,110,95,111,112,116,47,53>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<32,111,110,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,73,102,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,97,32,117,115,101,108,101,115,115,32,112,105,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,116,104,101,114,119,105,115,101,32,119,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]},{p,[],[<<86,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]},#{signature => [{attribute,{3455,2},spec,{{spawn_opt,5},[{type,{3455,16},bounded_fun,[{type,{3455,16},'fun',[{type,{3455,16},product,[{var,{3455,17},'Node'},{var,{3455,23},'Module'},{var,{3455,31},'Function'},{var,{3455,41},'Args'},{var,{3455,47},'Options'}]},{type,{3456,24},union,[{type,{3456,24},pid,[]},{type,{3456,32},tuple,[{type,{3456,33},pid,[]},{type,{3456,40},reference,[]}]}]}]},[{type,{3457,7},constraint,[{atom,{3457,7},is_subtype},[{var,{3457,7},'Node'},{type,{3457,15},node,[]}]]},{type,{3458,7},constraint,[{atom,{3458,7},is_subtype},[{var,{3458,7},'Module'},{type,{3458,17},module,[]}]]},{type,{3459,7},constraint,[{atom,{3459,7},is_subtype},[{var,{3459,7},'Function'},{type,{3459,19},atom,[]}]]},{type,{3460,7},constraint,[{atom,{3460,7},is_subtype},[{var,{3460,7},'Args'},{type,{3460,15},list,[{type,{3460,16},term,[]}]}]]},{type,{3461,7},constraint,[{atom,{3461,7},is_subtype},[{var,{3461,7},'Options'},{type,{3461,18},list,[{type,{3461,19},union,[{atom,{3461,19},monitor},{type,{3462,19},tuple,[{atom,{3462,20},monitor},{type,{3462,29},list,[{user_type,{3462,30},monitor_option,[]}]}]},{atom,{3463,19},link},{var,{3464,19},'OtherOption'}]}]}]]},{type,{3465,7},constraint,[{atom,{3465,7},is_subtype},[{var,{3465,7},'OtherOption'},{type,{3465,22},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,50,52>>}},{{function,spawn_request,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3510}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,70,117,110,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{3510,2},spec,{{spawn_request,1},[{type,{3510,20},bounded_fun,[{type,{3510,20},'fun',[{type,{3510,20},product,[{var,{3510,21},'Fun'}]},{var,{3510,29},'ReqId'}]},[{type,{3511,7},constraint,[{atom,{3511,7},is_subtype},[{var,{3511,7},'Fun'},{type,{3511,14},function,[]}]]},{type,{3512,7},constraint,[{atom,{3512,7},is_subtype},[{var,{3512,7},'ReqId'},{type,{3512,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,52,56>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3528}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,70,117,110,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},#{signature => [{attribute,{3528,2},spec,{{spawn_request,2},[{type,{3528,20},bounded_fun,[{type,{3528,20},'fun',[{type,{3528,20},product,[{var,{3528,21},'Fun'},{var,{3528,26},'Options'}]},{var,{3528,38},'ReqId'}]},[{type,{3529,7},constraint,[{atom,{3529,7},is_subtype},[{var,{3529,7},'Fun'},{type,{3529,14},function,[]}]]},{type,{3530,7},constraint,[{atom,{3530,7},is_subtype},[{var,{3530,7},'Option'},{type,{3530,17},union,[{type,{3530,17},tuple,[{atom,{3530,18},reply_tag},{var,{3530,29},'ReplyTag'}]},{type,{3531,17},tuple,[{atom,{3531,18},reply},{var,{3531,25},'Reply'}]},{user_type,{3532,17},spawn_opt_option,[]}]}]]},{type,{3533,7},constraint,[{atom,{3533,7},is_subtype},[{var,{3533,7},'ReplyTag'},{type,{3533,19},term,[]}]]},{type,{3534,7},constraint,[{atom,{3534,7},is_subtype},[{var,{3534,7},'Reply'},{type,{3534,16},union,[{atom,{3534,16},yes},{atom,{3534,22},no},{atom,{3534,27},error_only},{atom,{3534,40},success_only}]}]]},{type,{3535,7},constraint,[{atom,{3535,7},is_subtype},[{var,{3535,7},'Options'},{type,{3535,18},list,[{var,{3535,19},'Option'}]}]]},{type,{3536,7},constraint,[{atom,{3536,7},is_subtype},[{var,{3536,7},'ReqId'},{type,{3536,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,54,48>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3528}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,70,117,110,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{3528,2},spec,{{spawn_request,2},[{type,{3537,20},bounded_fun,[{type,{3537,20},'fun',[{type,{3537,20},product,[{var,{3537,21},'Node'},{var,{3537,27},'Fun'}]},{var,{3537,35},'ReqId'}]},[{type,{3538,7},constraint,[{atom,{3538,7},is_subtype},[{var,{3538,7},'Node'},{type,{3538,15},node,[]}]]},{type,{3539,7},constraint,[{atom,{3539,7},is_subtype},[{var,{3539,7},'Fun'},{type,{3539,14},function,[]}]]},{type,{3540,7},constraint,[{atom,{3540,7},is_subtype},[{var,{3540,7},'ReqId'},{type,{3540,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,55,50>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3563}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,101,114,108,97,110,103,44,97,112,112,108,121,44,91,70,117,110,44,91,93,93,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,117,115,105,110,103,32,116,104,101,32,102,117,110,32>>,{code,[],[<<70,117,110>>]},<<32,111,102,32,97,114,105,116,121,32,122,101,114,111,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,117,110>>]},<<32,105,115,32,110,111,116,32,97,32,102,117,110,32,111,102,32,97,114,105,116,121,32,122,101,114,111,46>>]}]},{li,[],[{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]}]}]},#{signature => [{attribute,{3563,2},spec,{{spawn_request,3},[{type,{3563,20},bounded_fun,[{type,{3563,20},'fun',[{type,{3563,20},product,[{var,{3563,21},'Node'},{var,{3563,27},'Fun'},{var,{3563,32},'Options'}]},{var,{3563,44},'ReqId'}]},[{type,{3564,7},constraint,[{atom,{3564,7},is_subtype},[{var,{3564,7},'Node'},{type,{3564,15},node,[]}]]},{type,{3565,7},constraint,[{atom,{3565,7},is_subtype},[{var,{3565,7},'Fun'},{type,{3565,14},function,[]}]]},{type,{3566,7},constraint,[{atom,{3566,7},is_subtype},[{var,{3566,7},'Options'},{type,{3566,18},list,[{var,{3566,19},'Option'}]}]]},{type,{3567,7},constraint,[{atom,{3567,7},is_subtype},[{var,{3567,7},'Option'},{type,{3567,17},union,[{atom,{3567,17},monitor},{type,{3568,17},tuple,[{atom,{3568,18},monitor},{type,{3568,27},list,[{user_type,{3568,28},monitor_option,[]}]}]},{atom,{3569,17},link},{type,{3570,17},tuple,[{atom,{3570,18},reply_tag},{var,{3570,29},'ReplyTag'}]},{type,{3571,17},tuple,[{atom,{3571,18},reply},{var,{3571,25},'Reply'}]},{var,{3572,17},'OtherOption'}]}]]},{type,{3573,7},constraint,[{atom,{3573,7},is_subtype},[{var,{3573,7},'ReplyTag'},{type,{3573,19},term,[]}]]},{type,{3574,7},constraint,[{atom,{3574,7},is_subtype},[{var,{3574,7},'Reply'},{type,{3574,16},union,[{atom,{3574,16},yes},{atom,{3574,22},no},{atom,{3574,27},error_only},{atom,{3574,40},success_only}]}]]},{type,{3575,7},constraint,[{atom,{3575,7},is_subtype},[{var,{3575,7},'OtherOption'},{type,{3575,22},term,[]}]]},{type,{3576,7},constraint,[{atom,{3576,7},is_subtype},[{var,{3576,7},'ReqId'},{type,{3576,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,49,56,52>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3563}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{3563,2},spec,{{spawn_request,3},[{type,{3577,20},bounded_fun,[{type,{3577,20},'fun',[{type,{3577,20},product,[{var,{3577,21},'Module'},{var,{3577,29},'Function'},{var,{3577,39},'Args'}]},{var,{3578,28},'ReqId'}]},[{type,{3579,7},constraint,[{atom,{3579,7},is_subtype},[{var,{3579,7},'Module'},{type,{3579,17},module,[]}]]},{type,{3580,7},constraint,[{atom,{3580,7},is_subtype},[{var,{3580,7},'Function'},{type,{3580,19},atom,[]}]]},{type,{3581,7},constraint,[{atom,{3581,7},is_subtype},[{var,{3581,7},'Args'},{type,{3581,15},list,[{type,{3581,16},term,[]}]}]]},{type,{3582,7},constraint,[{atom,{3582,7},is_subtype},[{var,{3582,7},'ReqId'},{type,{3582,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,48,52>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3603}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,52>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,78,111,100,101,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,91,93,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,105,116,104,32,110,111,32,111,112,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{3603,2},spec,{{spawn_request,4},[{type,{3603,20},bounded_fun,[{type,{3603,20},'fun',[{type,{3603,20},product,[{var,{3603,21},'Node'},{var,{3603,27},'Module'},{var,{3603,35},'Function'},{var,{3603,45},'Args'}]},{var,{3604,28},'ReqId'}]},[{type,{3605,7},constraint,[{atom,{3605,7},is_subtype},[{var,{3605,7},'Node'},{type,{3605,15},node,[]}]]},{type,{3606,7},constraint,[{atom,{3606,7},is_subtype},[{var,{3606,7},'Module'},{type,{3606,17},module,[]}]]},{type,{3607,7},constraint,[{atom,{3607,7},is_subtype},[{var,{3607,7},'Function'},{type,{3607,19},atom,[]}]]},{type,{3608,7},constraint,[{atom,{3608,7},is_subtype},[{var,{3608,7},'Args'},{type,{3608,15},list,[{type,{3608,16},term,[]}]}]]},{type,{3609,7},constraint,[{atom,{3609,7},is_subtype},[{var,{3609,7},'ReqId'},{type,{3609,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,49,54>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3603}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,52>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,110,111,100,101,40,41,44,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,65,114,103,115,44,79,112,116,105,111,110,115,41>>]}]},<<46,32,84,104,97,116,32,105,115,44,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},#{signature => [{attribute,{3603,2},spec,{{spawn_request,4},[{type,{3610,20},bounded_fun,[{type,{3610,20},'fun',[{type,{3610,20},product,[{var,{3610,21},'Module'},{var,{3610,29},'Function'},{var,{3610,39},'Args'},{var,{3610,45},'Options'}]},{var,{3611,28},'ReqId'}]},[{type,{3612,7},constraint,[{atom,{3612,7},is_subtype},[{var,{3612,7},'Module'},{type,{3612,17},module,[]}]]},{type,{3613,7},constraint,[{atom,{3613,7},is_subtype},[{var,{3613,7},'Function'},{type,{3613,19},atom,[]}]]},{type,{3614,7},constraint,[{atom,{3614,7},is_subtype},[{var,{3614,7},'Args'},{type,{3614,15},list,[{type,{3614,16},term,[]}]}]]},{type,{3615,7},constraint,[{atom,{3615,7},is_subtype},[{var,{3615,7},'Option'},{type,{3615,17},union,[{type,{3615,17},tuple,[{atom,{3615,18},reply_tag},{var,{3615,29},'ReplyTag'}]},{type,{3616,17},tuple,[{atom,{3616,18},reply},{var,{3616,25},'Reply'}]},{user_type,{3617,17},spawn_opt_option,[]}]}]]},{type,{3618,7},constraint,[{atom,{3618,7},is_subtype},[{var,{3618,7},'ReplyTag'},{type,{3618,19},term,[]}]]},{type,{3619,7},constraint,[{atom,{3619,7},is_subtype},[{var,{3619,7},'Reply'},{type,{3619,16},union,[{atom,{3619,16},yes},{atom,{3619,22},no},{atom,{3619,27},error_only},{atom,{3619,40},success_only}]}]]},{type,{3620,7},constraint,[{atom,{3620,7},is_subtype},[{var,{3620,7},'Options'},{type,{3620,18},list,[{var,{3620,19},'Option'}]}]]},{type,{3621,7},constraint,[{atom,{3621,7},is_subtype},[{var,{3621,7},'ReqId'},{type,{3621,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,50,56>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request,5},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3644}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>],#{<<101,110>> => [{p,[],[<<65,115,121,110,99,104,114,111,110,111,117,115,108,121,32,115,101,110,100,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32,82,101,116,117,114,110,115,32,97,32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32>>,{code,[],[<<82,101,113,73,100>>]},<<46>>]},{a,[{id,<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>}],[]},{p,[],[<<73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,99,114,101,97,116,101,100,32,111,110,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,121,32,100,101,102,97,117,108,116,32,98,101,32,115,101,110,116,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,82,101,113,73,100,44,32,111,107,44,32,80,105,100,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,83,117,99,104,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,97,32>>,{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]},<<32,98,101,108,111,119,32,105,110,32,116,104,101,32,116,101,120,116,46,32>>,{code,[],[<<82,101,112,108,121,84,97,103>>]},<<32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,112,97,119,110,95,114,101,112,108,121>>]},<<32,117,110,108,101,115,115,32,109,111,100,105,102,105,101,100,32,98,121,32,116,104,101,32>>,{code,[],[<<123,114,101,112,108,121,95,116,97,103,44,32,82,101,112,108,121,84,97,103,125>>]},<<32,111,112,116,105,111,110,46,32,84,104,101,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,115,116,97,114,116,101,100,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,111,102,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110>>]},<<32,116,111,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]},{a,[{id,<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>}],[]},{p,[],[<<84,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,32,101,105,116,104,101,114,32,105,102,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,102,97,105,108,101,100,32,111,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,97,115,32,105,110,116,101,114,114,117,112,116,101,100,32,98,121,32,97,32,99,111,110,110,101,99,116,105,111,110,32,102,97,105,108,117,114,101,46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,98,121,32,100,101,102,97,117,108,116,32,98,101,32,115,101,110,116,32,97,32,109,101,115,115,97,103,101,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,82,101,113,73,100,44,32,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<32,105,115,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,46,32,83,117,99,104,32,97,32,109,101,115,115,97,103,101,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,97,110,32>>,{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]},<<32,98,101,108,111,119,32,105,110,32,116,104,101,32,116,101,120,116,46,32,67,117,114,114,101,110,116,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,112,97,119,110,32,101,114,114,111,114,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<115,32,97,114,101,32,100,101,102,105,110,101,100,44,32,98,117,116,32,111,116,104,101,114,32,114,101,97,115,111,110,115,32,99,97,110,32,97,112,112,101,97,114,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,111,112,116>>]}]},{dd,[],[{p,[],[<<65,110,32,105,110,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<32,119,97,115,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46,32,78,111,116,101,32,116,104,97,116,32,100,105,102,102,101,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,115,32,109,97,121,32,115,117,112,112,111,114,116,32,100,105,102,102,101,114,101,110,116,32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,115,32,105,115,115,117,101,100,32,98,121,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<70,97,105,108,117,114,101,32,116,111,32,115,101,116,32,117,112,32,97,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<32,111,114,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,116,111,32,116,104,97,116,32,110,111,100,101,32,119,97,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,110,32,116,104,101,32,99,97,115,101,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,119,97,115,32,108,111,115,116,44,32,97,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<67,111,117,108,100,32,110,111,116,32,99,114,101,97,116,101,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,100,117,101,32,116,111,32,116,104,97,116,32,115,111,109,101,32,115,121,115,116,101,109,32,108,105,109,105,116,32,119,97,115,32,114,101,97,99,104,101,100,46,32,84,121,112,105,99,97,108,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,116,97,98,108,101,32,119,97,115,32,102,117,108,108,46>>]}]}]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,111,110,105,116,111,114>>]}]},{dd,[],[{p,[],[<<73,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,109,111,110,105,116,111,114,32,116,111,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,101,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<32,105,115,32,97,108,115,111,32,117,115,101,100,32,97,115,32,109,111,110,105,116,111,114,32,114,101,102,101,114,101,110,99,101,32,97,115,32,105,102,32,105,116,32,119,97,115,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,41>>]},<<46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,84,104,101,32,109,111,110,105,116,111,114,32,99,97,110,32,110,111,116,32,98,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,100,101,109,111,110,105,116,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<100,101,109,111,110,105,116,111,114,101,100>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,65,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,102,111,114,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,109,111,110,105,116,111,114,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,110,111,32>>,{code,[],[<<39,68,79,87,78,39>>]},<<32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,116,104,101,32,110,111,100,101,115,32,105,110,118,111,108,118,101,100,32,105,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,105,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46,32,65,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<123,109,111,110,105,116,111,114,44,32,77,111,110,105,116,111,114,79,112,116,115,125>>]}]},{dd,[],[{p,[],[<<73,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,109,111,110,105,116,111,114,32,116,111,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,40,112,114,111,99,101,115,115,44,32,80,105,100,44,32,77,111,110,105,116,111,114,79,112,116,115,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,83,101,101,32,116,104,101,32>>,{code,[],[<<109,111,110,105,116,111,114>>]},<<32,111,112,116,105,111,110,32,97,98,111,118,101,32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,116,104,101,32,109,111,110,105,116,111,114,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,116,104,101,32,99,97,115,101,32,116,104,97,116,32,97,110,32,97,108,105,97,115,32,105,115,32,99,114,101,97,116,101,100,32,117,115,105,110,103,32,116,104,101,32,109,111,110,105,116,111,114,32,111,112,116,105,111,110,44,32,116,104,101,32,97,108,105,97,115,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,101,32,117,110,116,105,108,32,116,104,101,32,109,111,110,105,116,111,114,32,105,115,32,97,99,116,105,118,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<108,105,110,107>>]}]},{dd,[],[{p,[],[<<73,110,32,97,98,115,101,110,99,101,32,111,102,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,117,114,101,115,44,32,97,116,111,109,105,99,97,108,108,121,32,115,101,116,115,32,117,112,32,97,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,97,115,32,105,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,104,97,100,32,99,97,108,108,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,110,107,40,80,105,100,41>>]}]},<<32,119,104,101,114,101,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<84,104,101,32,108,105,110,107,32,119,105,108,108,32,110,111,116,32,98,101,32,97,99,116,105,118,97,116,101,100,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,84,104,101,32,108,105,110,107,32,99,97,110,32,110,111,116,32,98,101,32,114,101,109,111,118,101,100,32,98,101,102,111,114,101,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46,32,65,110,32,101,120,105,116,32,115,105,103,110,97,108,32,100,117,101,32,116,111,32,116,104,101,32,108,105,110,107,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,110,111,116,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,110,111,32,101,120,105,116,32,115,105,103,110,97,108,32,100,117,101,32,116,111,32,116,104,101,32,108,105,110,107,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,110,101,99,116,105,111,110,32,98,101,116,119,101,101,110,32,116,104,101,32,110,111,100,101,115,32,105,110,118,111,108,118,101,100,32,105,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,105,115,32,108,111,115,116,32,100,117,114,105,110,103,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46,32,65,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,104,97,118,101,32,98,101,101,110,32,99,114,101,97,116,101,100,46,32,73,102,32,105,116,32,104,97,115,32,98,101,101,110,32,99,114,101,97,116,101,100,44,32,105,116,32,119,105,108,108,32,98,101,32,100,101,108,105,118,101,114,101,100,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,119,105,116,104,32,97,110,32,101,120,105,116,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<110,111,99,111,110,110,101,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,112,108,121,44,32,82,101,112,108,121,125>>]}]},{dd,[],[{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<82,101,112,108,121>>]},<<32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<121,101,115>>]}]},{dd,[],[{p,[],[<<65,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,32,111,114,32,110,111,116,46,32,73,102,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]},<<32,114,101,116,117,114,110,115,32,119,105,116,104,111,117,116,32,114,97,105,115,105,110,103,32,97,110,32,101,120,99,101,112,116,105,111,110,32,97,110,100,32,116,104,101,32>>,{code,[],[<<114,101,112,108,121>>]},<<32,111,112,116,105,111,110,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<121,101,115>>]},<<44,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,101,105,116,104,101,114,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,111,114,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]}]},<<46,32,84,104,101,32>>,{code,[],[<<114,101,112,108,121>>]},<<32,111,112,116,105,111,110,32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,115,101,116,32,116,111,32>>,{code,[],[<<121,101,115>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,111>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,119,104,101,110,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,99,111,109,112,108,101,116,101,115,46,32,84,104,105,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,32,111,114,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,114,114,111,114,95,111,110,108,121>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,44,32,98,117,116,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114,32,109,101,115,115,97,103,101>>]}]},<<32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,46>>]}]},{dt,[],[{code,[],[<<115,117,99,99,101,115,115,95,111,110,108,121>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32,98,117,116,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115,32,109,101,115,115,97,103,101>>]}]},<<32,119,105,108,108,32,98,101,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,105,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,115,117,99,99,101,101,100,115,46>>]}]}]}]},{dt,[],[{code,[],[<<123,114,101,112,108,121,95,116,97,103,44,32,82,101,112,108,121,84,97,103,125>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,116,104,101,32,114,101,112,108,121,32,116,97,103,32,116,111,32>>,{code,[],[<<82,101,112,108,121,84,97,103>>]},<<32,105,110,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,46,32,84,104,97,116,32,105,115,44,32,105,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,115,117,99,99,101,115,115,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<115,117,99,99,101,115,115>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,101,114,114,111,114,95,109,101,115,115,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{i,[],[<<101,114,114,111,114>>]}]},<<32,109,101,115,115,97,103,101,32,116,104,97,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,100,117,101,32,116,111,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,112,108,121,32,116,97,103,32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<115,112,97,119,110,95,114,101,112,108,121>>]},<<46>>]}]},{dt,[],[{code,[],[<<79,116,104,101,114,79,112,116,105,111,110>>]}]},{dd,[],[{p,[],[<<79,116,104,101,114,32,118,97,108,105,100,32,111,112,116,105,111,110,115,32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116,32,111,112,116,105,111,110,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,110,111,100,101,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<78,111,100,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,111,116,104,101,114,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,102,111,114,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,111,102,32,99,117,114,114,101,110,116,32,79,84,80,32,118,101,114,115,105,111,110,32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<46>>]}]}]},{p,[],[<<73,102,32,97,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,115,32,100,101,108,105,118,101,114,101,100,44,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100,32,98,101,102,111,114,101,32,97,110,121,32,111,116,104,101,114,32,115,105,103,110,97,108,115,32,102,114,111,109,32,116,104,101,32,110,101,119,108,121,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,115,115,117,105,110,103,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<78,111,100,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<77,111,100,117,108,101>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,110,111,116,32,97,110,32,97,116,111,109,46>>]}]},{li,[],[{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]},{li,[],[{p,[],[{code,[],[<<79,112,116,105,111,110,115>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,116,101,114,109,115,46>>]}]}]},{p,[],[<<78,111,116,101,32,116,104,97,116,32,110,111,116,32,97,108,108,32,105,110,100,105,118,105,100,117,97,108,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,97,114,101,32,99,104,101,99,107,101,100,32,119,104,101,110,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,46,32,83,111,109,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,111,110,108,121,32,98,101,32,99,104,101,99,107,101,100,32,111,110,32,114,101,99,101,112,116,105,111,110,32,111,102,32,116,104,101,32,114,101,113,117,101,115,116,46,32,84,104,101,114,101,102,111,114,101,32,97,110,32,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,99,97,117,115,101,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,44,32,98,117,116,32,119,105,108,108,32,99,97,117,115,101,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,116,111,32,102,97,105,108,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,32>>,{code,[],[<<98,97,100,111,112,116>>]},<<46>>]},{p,[],[<<65,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,99,97,110,32,98,101,32,97,98,97,110,100,111,110,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]}]},#{signature => [{attribute,{3644,2},spec,{{spawn_request,5},[{type,{3644,20},bounded_fun,[{type,{3644,20},'fun',[{type,{3644,20},product,[{var,{3644,21},'Node'},{var,{3644,27},'Module'},{var,{3644,35},'Function'},{var,{3644,45},'Args'},{var,{3644,51},'Options'}]},{var,{3645,28},'ReqId'}]},[{type,{3646,7},constraint,[{atom,{3646,7},is_subtype},[{var,{3646,7},'Node'},{type,{3646,15},node,[]}]]},{type,{3647,7},constraint,[{atom,{3647,7},is_subtype},[{var,{3647,7},'Module'},{type,{3647,17},module,[]}]]},{type,{3648,7},constraint,[{atom,{3648,7},is_subtype},[{var,{3648,7},'Function'},{type,{3648,19},atom,[]}]]},{type,{3649,7},constraint,[{atom,{3649,7},is_subtype},[{var,{3649,7},'Args'},{type,{3649,15},list,[{type,{3649,16},term,[]}]}]]},{type,{3650,7},constraint,[{atom,{3650,7},is_subtype},[{var,{3650,7},'Options'},{type,{3650,18},list,[{var,{3650,19},'Option'}]}]]},{type,{3651,7},constraint,[{atom,{3651,7},is_subtype},[{var,{3651,7},'Option'},{type,{3651,17},union,[{atom,{3651,17},monitor},{type,{3652,17},tuple,[{atom,{3652,18},monitor},{type,{3652,27},list,[{user_type,{3652,28},monitor_option,[]}]}]},{atom,{3653,17},link},{type,{3654,17},tuple,[{atom,{3654,18},reply_tag},{var,{3654,29},'ReplyTag'}]},{type,{3655,17},tuple,[{atom,{3655,18},reply},{var,{3655,25},'Reply'}]},{var,{3656,17},'OtherOption'}]}]]},{type,{3657,7},constraint,[{atom,{3657,7},is_subtype},[{var,{3657,7},'ReplyTag'},{type,{3657,19},term,[]}]]},{type,{3658,7},constraint,[{atom,{3658,7},is_subtype},[{var,{3658,7},'Reply'},{type,{3658,16},union,[{atom,{3658,16},yes},{atom,{3658,22},no},{atom,{3658,27},error_only},{atom,{3658,40},success_only}]}]]},{type,{3659,7},constraint,[{atom,{3659,7},is_subtype},[{var,{3659,7},'OtherOption'},{type,{3659,22},term,[]}]]},{type,{3660,7},constraint,[{atom,{3660,7},is_subtype},[{var,{3660,7},'ReqId'},{type,{3660,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,50,52,48>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,spawn_request_abandon,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3677}],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<65,98,97,110,100,111,110,32,97,32,112,114,101,118,105,111,117,115,108,121,32,105,115,115,117,101,100,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,97,32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,114,101,113,117,101,115,116,47,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,40,41>>]}]},<<32,105,110,32,97,32,99,97,108,108,32,102,114,111,109,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,109,97,100,101,32,116,104,101,32,114,101,113,117,101,115,116,32,99,97,110,32,97,98,97,110,100,111,110,32,116,104,101,32,114,101,113,117,101,115,116,46>>]},{p,[],[<<65,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,99,97,110,32,111,110,108,121,32,98,101,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,32,117,110,116,105,108,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,104,97,115,32,99,111,109,112,108,101,116,101,100,46,32,87,104,101,110,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,119,105,108,108,32,110,111,116,32,98,101,32,101,102,102,101,99,116,101,100,32,98,121,32,102,117,116,117,114,101,32,100,105,114,101,99,116,32,101,102,102,101,99,116,115,32,111,102,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,116,115,101,108,102,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,119,105,108,108,32,110,111,116,32,114,101,99,101,105,118,101,32,97,32,115,112,97,119,110,32,114,101,112,108,121,32,109,101,115,115,97,103,101,46,32,84,104,101,32,114,101,113,117,101,115,116,32,105,115,32,104,111,119,101,118,101,114,32,110,111,116,32,119,105,116,104,100,114,97,119,110,44,32,115,111,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,98,101,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,116,104,101,32,114,101,113,117,101,115,116,46,32,73,102,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32,105,115,32,99,114,101,97,116,101,100,32,97,102,116,101,114,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,97,98,97,110,100,111,110,101,100,44,32,110,111,32,109,111,110,105,116,111,114,115,32,110,111,114,32,108,105,110,107,115,32,119,105,108,108,32,98,101,32,115,101,116,32,117,112,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<115,112,97,119,110,95,114,101,113,117,101,115,116,95,97,98,97,110,100,111,110,47,49>>]},<<32,100,117,101,32,116,111,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46,32,73,102,32,116,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,110,99,108,117,100,101,100,32,116,104,101,32>>,{code,[],[<<108,105,110,107>>]},<<32,111,112,116,105,111,110,44,32,116,104,101,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,116,104,105,115,32,114,101,113,117,101,115,116,32,119,105,108,108,32,98,101,32,115,101,110,116,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,102,114,111,109,32,105,116,115,32,112,97,114,101,110,116,32,119,105,116,104,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32>>,{code,[],[<<97,98,97,110,100,111,110,101,100>>]},<<32,119,104,101,110,32,105,116,32,105,115,32,100,101,116,101,99,116,101,100,32,116,104,97,116,32,116,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,115,117,99,99,101,101,100,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,100,117,101,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,97,98,97,110,100,111,110,101,100,32,109,97,121,32,99,111,109,109,117,110,105,99,97,116,101,32,119,105,116,104,32,105,116,115,32,112,97,114,101,110,116,32,97,115,32,97,110,121,32,111,116,104,101,114,32,112,114,111,99,101,115,115,46,32,73,116,32,105,115,32>>,{em,[],[<<111,110,108,121>>]},<<32,116,104,101,32,100,105,114,101,99,116,32,101,102,102,101,99,116,115,32,111,110,32,116,104,101,32,112,97,114,101,110,116,32,111,102,32,116,104,101,32,97,99,116,117,97,108,32,115,112,97,119,110,32,114,101,113,117,101,115,116,44,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,97,110,99,101,108,101,100,32,98,121,32,97,98,97,110,100,111,110,105,110,103,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,46>>]}]},{p,[],[<<82,101,116,117,114,110,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,97,98,97,110,100,111,110,101,100,46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,119,97,115,32,97,98,97,110,100,111,110,101,100,46,32,84,104,101,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,114,101,113,117,101,115,116,32,105,100,101,110,116,105,102,105,101,114,32,100,105,100,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,97,110,32,111,117,116,115,116,97,110,100,105,110,103,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,105,115,115,117,101,100,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,101,105,116,104,101,114,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<82,101,113,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,112,114,101,118,105,111,117,108,115,121,32,109,97,100,101,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,84,104,101,32,115,112,97,119,110,32,111,112,101,114,97,116,105,111,110,32,104,97,115,32,99,111,109,112,108,101,116,101,100,32,97,110,100,32,97,32,115,112,97,119,110,32,114,101,112,108,121,32,104,97,115,32,97,108,114,101,97,100,121,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,117,110,108,101,115,115,32,116,104,101,32,115,112,97,119,110,32,114,101,112,108,121,32,119,97,115,32,100,105,115,97,98,108,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,46>>]}]},{li,[],[{p,[],[{code,[],[<<82,101,113,73,100>>]},<<32,100,111,101,115,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,97,32,115,112,97,119,110,32,114,101,113,117,101,115,116,32,116,104,97,116,32,104,97,115,32,98,101,101,110,32,109,97,100,101,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46>>]}]}]}]}]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,102,97,105,108,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,105,102,32>>,{code,[],[<<82,101,113,73,100>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,102,101,114,101,110,99,101,46>>]}]},#{signature => [{attribute,{3677,2},spec,{{spawn_request_abandon,1},[{type,{3677,28},'fun',[{type,{3677,28},product,[{ann_type,{3677,29},[{var,{3677,29},'ReqId'},{type,{3677,38},reference,[]}]}]},{type,{3677,54},boolean,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,48,56>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,split_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2189}],[<<115,112,108,105,116,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,117,112,108,101,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,98,105,110,97,114,105,101,115,32,116,104,97,116,32,97,114,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,112,108,105,116,116,105,110,103,32>>,{code,[],[<<66,105,110>>]},<<32,105,110,116,111,32,116,119,111,32,112,97,114,116,115,32,97,116,32,112,111,115,105,116,105,111,110,32>>,{code,[],[<<80,111,115>>]},<<46,32,84,104,105,115,32,105,115,32,110,111,116,32,97,32,100,101,115,116,114,117,99,116,105,118,101,32,111,112,101,114,97,116,105,111,110,46,32,65,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,44,32,116,104,101,114,101,32,97,114,101,32,116,104,114,101,101,32,98,105,110,97,114,105,101,115,32,97,108,116,111,103,101,116,104,101,114,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,66,32,61,32,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,34,48,49,50,51,52,53,54,55,56,57,34,41,46,10,60,60,34,48,49,50,51,52,53,54,55,56,57,34,62,62,10,62,32,98,121,116,101,95,115,105,122,101,40,66,41,46,10,49,48,10,62,32,123,66,49,44,32,66,50,125,32,61,32,115,112,108,105,116,95,98,105,110,97,114,121,40,66,44,51,41,46,10,123,60,60,34,48,49,50,34,62,62,44,60,60,34,51,52,53,54,55,56,57,34,62,62,125,10,62,32,98,121,116,101,95,115,105,122,101,40,66,49,41,46,10,51,10,62,32,98,121,116,101,95,115,105,122,101,40,66,50,41,46,10,55>>]}]}]},#{signature => [{attribute,{2189,2},spec,{{split_binary,2},[{type,{2189,19},bounded_fun,[{type,{2189,19},'fun',[{type,{2189,19},product,[{var,{2189,20},'Bin'},{var,{2189,25},'Pos'}]},{type,{2189,33},tuple,[{type,{2189,34},binary,[]},{type,{2189,44},binary,[]}]}]},[{type,{2190,7},constraint,[{atom,{2190,7},is_subtype},[{var,{2190,7},'Bin'},{type,{2190,14},binary,[]}]]},{type,{2191,7},constraint,[{atom,{2191,7},is_subtype},[{var,{2191,7},'Pos'},{type,{2191,14},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,55,52>>}},{{function,start_timer,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2196}],[<<115,116,97,114,116,95,116,105,109,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,114,116,95,116,105,109,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,116,97,114,116,95,116,105,109,101,114,40,84,105,109,101,44,32,68,101,115,116,44,32,77,115,103,44,32,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2196,2},spec,{{erlang,start_timer,3},[{type,{2196,25},bounded_fun,[{type,{2196,25},'fun',[{type,{2196,25},product,[{var,{2196,26},'Time'},{var,{2196,32},'Dest'},{var,{2196,38},'Msg'}]},{var,{2196,46},'TimerRef'}]},[{type,{2197,7},constraint,[{atom,{2197,7},is_subtype},[{var,{2197,7},'Time'},{type,{2197,15},non_neg_integer,[]}]]},{type,{2198,7},constraint,[{atom,{2198,7},is_subtype},[{var,{2198,7},'Dest'},{type,{2198,15},union,[{type,{2198,15},pid,[]},{type,{2198,23},atom,[]}]}]]},{type,{2199,7},constraint,[{atom,{2199,7},is_subtype},[{var,{2199,7},'Msg'},{type,{2199,14},term,[]}]]},{type,{2200,7},constraint,[{atom,{2200,7},is_subtype},[{var,{2200,7},'TimerRef'},{type,{2200,19},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,53,57,56>>}},{{function,start_timer,4},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2206}],[<<115,116,97,114,116,95,116,105,109,101,114,47,52>>],#{<<101,110>> => [{p,[],[<<83,116,97,114,116,115,32,97,32,116,105,109,101,114,46,32,87,104,101,110,32,116,104,101,32,116,105,109,101,114,32,101,120,112,105,114,101,115,44,32,116,104,101,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,84,105,109,101,114,82,101,102,44,32,77,115,103,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<68,101,115,116>>]},<<46>>]},{p,[],[{code,[],[<<79,112,116,105,111,110>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,97,98,115,44,32,102,97,108,115,101,125>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46,32,73,116,32,109,101,97,110,115,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,32>>,{em,[],[<<114,101,108,97,116,105,118,101>>]},<<32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,97,98,115,44,32,116,114,117,101,125>>]}]},{dd,[],[{p,[],[<<65,98,115,111,108,117,116,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,46,32,84,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,110,32,97,98,115,111,108,117,116,101,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]}]}]},{p,[],[<<77,111,114,101,32>>,{code,[],[<<79,112,116,105,111,110>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{p,[],[<<84,104,101,32,97,98,115,111,108,117,116,101,32,112,111,105,110,116,32,105,110,32,116,105,109,101,44,32,116,104,101,32,116,105,109,101,114,32,105,115,32,115,101,116,32,116,111,32,101,120,112,105,114,101,32,111,110,44,32,109,117,115,116,32,98,101,32,105,110,32,116,104,101,32,105,110,116,101,114,118,97,108,32>>,{code,[],[<<91,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111>>]},{code,[],[<<40,115,116,97,114,116,95,116,105,109,101,41,44,32,110,97,116,105,118,101,44,32,109,105,108,108,105,115,101,99,111,110,100,41,44,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111>>]},{code,[],[<<40,101,110,100,95,116,105,109,101,41,44,32,110,97,116,105,118,101,44,32,109,105,108,108,105,115,101,99,111,110,100,41,32,93>>]},<<46,32,73,102,32,97,32,114,101,108,97,116,105,118,101,32,116,105,109,101,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,110,101,103,97,116,105,118,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,105,116,32,109,117,115,116,32,98,101,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,111,102,32,97,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,101,105,116,104,101,114,32,116,101,114,109,105,110,97,116,101,100,32,111,114,32,110,111,116,46,32,73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<44,32,105,116,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,108,111,99,97,108,108,121,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,46,32,84,104,101,32,112,114,111,99,101,115,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,116,104,101,32,110,97,109,101,32,105,115,32,108,111,111,107,101,100,32,117,112,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,105,109,101,114,32,101,120,112,105,114,97,116,105,111,110,46,32,78,111,32,101,114,114,111,114,32,105,115,32,114,101,116,117,114,110,101,100,32,105,102,32,116,104,101,32,110,97,109,101,32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,116,104,101,32,116,105,109,101,114,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,110,99,101,108,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,102,101,114,114,101,100,32,116,111,32,98,121,32,116,104,101,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,44,32,111,114,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,46,32,84,104,105,115,32,102,101,97,116,117,114,101,32,119,97,115,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,69,82,84,83,32,53,46,52,46,49,49,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,105,109,101,114,115,32,97,114,101,32,110,111,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,110,99,101,108,101,100,32,119,104,101,110,32>>,{code,[],[<<68,101,115,116>>]},<<32,105,115,32,97,110,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,101,110,100,95,97,102,116,101,114,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,101,110,100,95,97,102,116,101,114,47,52>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,97,110,99,101,108,95,116,105,109,101,114,47,50>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,97,100,95,116,105,109,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,97,100,95,116,105,109,101,114,47,50>>]}]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,100,111,32,110,111,116,32,115,97,116,105,115,102,121,32,116,104,101,32,114,101,113,117,105,114,101,109,101,110,116,115,32,115,112,101,99,105,102,105,101,100,32,104,101,114,101,46>>]}]},#{signature => [{attribute,{2206,2},spec,{{erlang,start_timer,4},[{type,{2206,25},bounded_fun,[{type,{2206,25},'fun',[{type,{2206,25},product,[{var,{2206,26},'Time'},{var,{2206,32},'Dest'},{var,{2206,38},'Msg'},{var,{2206,43},'Options'}]},{var,{2206,55},'TimerRef'}]},[{type,{2207,7},constraint,[{atom,{2207,7},is_subtype},[{var,{2207,7},'Time'},{type,{2207,15},integer,[]}]]},{type,{2208,7},constraint,[{atom,{2208,7},is_subtype},[{var,{2208,7},'Dest'},{type,{2208,15},union,[{type,{2208,15},pid,[]},{type,{2208,23},atom,[]}]}]]},{type,{2209,7},constraint,[{atom,{2209,7},is_subtype},[{var,{2209,7},'Msg'},{type,{2209,14},term,[]}]]},{type,{2210,7},constraint,[{atom,{2210,7},is_subtype},[{var,{2210,7},'Options'},{type,{2210,18},list,[{var,{2210,19},'Option'}]}]]},{type,{2211,7},constraint,[{atom,{2211,7},is_subtype},[{var,{2211,7},'Abs'},{type,{2211,14},boolean,[]}]]},{type,{2212,7},constraint,[{atom,{2212,7},is_subtype},[{var,{2212,7},'Option'},{type,{2212,17},tuple,[{atom,{2212,18},abs},{var,{2212,23},'Abs'}]}]]},{type,{2213,7},constraint,[{atom,{2213,7},is_subtype},[{var,{2213,7},'TimerRef'},{type,{2213,19},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,54,48,57>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<32,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,116,97,115,107,115,32,116,104,97,116,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,32,97,114,101,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2826,17},bounded_fun,[{type,{2826,17},'fun',[{type,{2826,17},product,[{atom,{2826,18},active_tasks}]},{type,{2826,35},list,[{var,{2826,36},'ActiveTasks'}]}]},[{type,{2827,7},constraint,[{atom,{2827,7},is_subtype},[{var,{2827,7},'ActiveTasks'},{type,{2827,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,54,54,57>>,since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,97,99,116,105,118,101,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,111,110,32,101,97,99,104,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,116,104,97,116,32,97,114,101,32,114,101,97,100,121,32,116,111,32,114,117,110,44,32,111,114,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,114,117,110,110,105,110,103,46,32,86,97,108,117,101,115,32,102,111,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,97,110,100,32,116,104,101,105,114,32,97,115,115,111,99,105,97,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,108,111,99,97,116,101,100,32,102,105,114,115,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,115,99,104,101,100,117,108,101,114,32,110,117,109,98,101,114,32,49,32,97,110,100,32,115,111,32,111,110,46,32,73,102,32,115,117,112,112,111,114,116,32,102,111,114,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,44,32,97,110,32,101,108,101,109,101,110,116,32,119,105,116,104,32,116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,102,111,108,108,111,119,32,97,110,100,32,116,104,101,110,32,97,115,32,108,97,115,116,32,101,108,101,109,101,110,116,32,116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,105,116,115,32,97,115,115,111,99,105,97,116,101,100,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,102,111,108,108,111,119,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,105,108,121,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,105,110,115,116,101,97,100,32,113,117,105,116,101,32,101,102,102,105,99,105,101,110,116,108,121,32,103,97,116,104,101,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<69,97,99,104,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,111,110,101,32,114,117,110,32,113,117,101,117,101,32,116,104,97,116,32,105,116,32,109,97,110,97,103,101,115,46,32,73,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,108,108,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,44,32,97,110,100,32,97,108,108,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,46,32,84,104,97,116,32,105,115,44,32,119,101,32,104,97,118,101,32,109,117,108,116,105,112,108,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,44,32,111,110,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,111,110,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,46,32,87,111,114,107,32,99,97,110,32>>,{em,[],[<<110,111,116>>]},<<32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,114,117,110,32,113,117,101,117,101,115,46,32,79,110,108,121,32,119,111,114,107,32,105,110,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,99,97,110,32,109,105,103,114,97,116,101,32,116,111,32,111,116,104,101,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,105,115,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2828,3},bounded_fun,[{type,{2828,3},'fun',[{type,{2828,3},product,[{atom,{2828,4},active_tasks_all}]},{type,{2828,25},list,[{var,{2828,26},'ActiveTasks'}]}]},[{type,{2829,7},constraint,[{atom,{2829,7},is_subtype},[{var,{2829,7},'ActiveTasks'},{type,{2829,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,54,56,52>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,99,111,110,116,101,120,116,32,115,119,105,116,99,104,101,115,32,115,105,110,99,101,32,116,104,101,32,115,121,115,116,101,109,32,115,116,97,114,116,101,100,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2830,3},bounded_fun,[{type,{2830,3},'fun',[{type,{2830,3},product,[{atom,{2830,4},context_switches}]},{type,{2830,25},tuple,[{var,{2830,26},'ContextSwitches'},{integer,{2830,42},0}]}]},[{type,{2831,7},constraint,[{atom,{2831,7},is_subtype},[{var,{2831,7},'ContextSwitches'},{type,{2831,26},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,50,54>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,120,97,99,116,32,114,101,100,117,99,116,105,111,110,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115,41>>]},<<32,105,115,32,97,32,109,111,114,101,32,101,120,112,101,110,115,105,118,101,32,111,112,101,114,97,116,105,111,110,32,116,104,97,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,101,100,117,99,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,97,116,105,115,116,105,99,115,40,114,101,100,117,99,116,105,111,110,115,41>>]},<<46>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2832,17},bounded_fun,[{type,{2832,17},'fun',[{type,{2832,17},product,[{atom,{2832,18},exact_reductions}]},{type,{2832,39},tuple,[{var,{2832,40},'Total_Exact_Reductions'},{var,{2833,40},'Exact_Reductions_Since_Last_Call'}]}]},[{type,{2834,7},constraint,[{atom,{2834,7},is_subtype},[{var,{2834,7},'Total_Exact_Reductions'},{type,{2834,33},non_neg_integer,[]}]]},{type,{2835,7},constraint,[{atom,{2835,7},is_subtype},[{var,{2835,7},'Exact_Reductions_Since_Last_Call'},{type,{2835,43},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,51,53>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110,41,46,10,123,56,53,44,50,51,57,54,49,44,48,125>>]}]},{p,[],[<<84,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,105,110,118,97,108,105,100,32,102,111,114,32,115,111,109,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2836,17},bounded_fun,[{type,{2836,17},'fun',[{type,{2836,17},product,[{atom,{2836,18},garbage_collection}]},{type,{2836,41},tuple,[{var,{2836,42},'Number_of_GCs'},{var,{2836,57},'Words_Reclaimed'},{integer,{2836,74},0}]}]},[{type,{2837,7},constraint,[{atom,{2837,7},is_subtype},[{var,{2837,7},'Number_of_GCs'},{type,{2837,24},non_neg_integer,[]}]]},{type,{2838,7},constraint,[{atom,{2838,7},is_subtype},[{var,{2838,7},'Words_Reclaimed'},{type,{2838,26},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,53,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<73,110,112,117,116>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,99,101,105,118,101,100,32,116,104,114,111,117,103,104,32,112,111,114,116,115,44,32,97,110,100,32>>,{code,[],[<<79,117,116,112,117,116>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,111,117,116,112,117,116,32,116,111,32,112,111,114,116,115,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2839,17},bounded_fun,[{type,{2839,17},'fun',[{type,{2839,17},product,[{atom,{2839,18},io}]},{type,{2839,25},tuple,[{type,{2839,26},tuple,[{atom,{2839,27},input},{var,{2839,34},'Input'}]},{type,{2839,42},tuple,[{atom,{2839,43},output},{var,{2839,51},'Output'}]}]}]},[{type,{2840,7},constraint,[{atom,{2840,7},is_subtype},[{var,{2840,7},'Input'},{type,{2840,16},non_neg_integer,[]}]]},{type,{2841,7},constraint,[{atom,{2841,7},is_subtype},[{var,{2841,7},'Output'},{type,{2841,17},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,54,50>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<77,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,101,97,115,117,114,101,32,104,111,119,32,109,117,99,104,32,116,105,109,101,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,112,101,110,100,115,32,100,111,105,110,103,32,118,97,114,105,111,117,115,32,116,97,115,107,115,46,32,73,116,32,105,115,32,100,101,115,105,103,110,101,100,32,116,111,32,98,101,32,97,115,32,108,105,103,104,116,119,101,105,103,104,116,32,97,115,32,112,111,115,115,105,98,108,101,44,32,98,117,116,32,115,111,109,101,32,111,118,101,114,104,101,97,100,32,101,120,105,115,116,115,32,119,104,101,110,32,116,104,105,115,32,105,115,32,101,110,97,98,108,101,100,46,32,77,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,105,115,32,109,101,97,110,116,32,116,111,32,98,101,32,97,32,112,114,111,102,105,108,105,110,103,32,116,111,111,108,32,116,111,32,104,101,108,112,32,102,105,110,100,105,110,103,32,112,101,114,102,111,114,109,97,110,99,101,32,98,111,116,116,108,101,110,101,99,107,115,46,32,84,111,32>>,{code,[],[<<115,116,97,114,116>>]},<<47>>,{code,[],[<<115,116,111,112>>]},<<47>>,{code,[],[<<114,101,115,101,116>>]},<<32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,44,32,117,115,101,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>]}]},<<46>>]},{p,[],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41>>]},<<32,114,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,109,97,112,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,115,111,109,101,32,111,102,32,116,104,101,32,79,83,32,116,104,114,101,97,100,115,32,119,105,116,104,105,110,32,69,82,84,83,46,32,69,97,99,104,32,109,97,112,32,99,111,110,116,97,105,110,115,32>>,{code,[],[<<116,121,112,101>>]},<<32,97,110,100,32>>,{code,[],[<<105,100>>]},<<32,102,105,101,108,100,115,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,105,100,101,110,116,105,102,121,32,119,104,97,116,32,116,104,114,101,97,100,32,105,116,32,105,115,44,32,97,110,100,32,97,108,115,111,32,97,32,99,111,117,110,116,101,114,115,32,102,105,101,108,100,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,100,97,116,97,32,97,98,111,117,116,32,104,111,119,32,109,117,99,104,32,116,105,109,101,32,104,97,115,32,98,101,101,110,32,115,112,101,110,116,32,105,110,32,116,104,101,32,118,97,114,105,111,117,115,32,115,116,97,116,101,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41,46,10,91,35,123,99,111,117,110,116,101,114,115,32,61,62,32,35,123,97,117,120,32,61,62,32,49,56,57,57,49,56,50,57,49,52,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,99,104,101,99,107,95,105,111,32,61,62,32,50,54,48,53,56,54,51,54,48,50,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,109,117,108,97,116,111,114,32,61,62,32,52,53,55,51,49,56,56,48,52,54,51,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,103,99,32,61,62,32,49,53,49,50,50,48,54,57,49,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,111,116,104,101,114,32,61,62,32,53,52,50,49,51,51,56,52,53,54,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,112,111,114,116,32,61,62,32,50,50,49,54,51,49,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,115,108,101,101,112,32,61,62,32,53,49,53,48,50,57,52,49,48,48,125,44,10,32,32,32,105,100,32,61,62,32,49,44,10,32,32,32,116,121,112,101,32,61,62,32,115,99,104,101,100,117,108,101,114,125,124,46,46,46,93>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,117,110,105,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>]}]},<<46,32,83,111,44,32,116,111,32,99,111,110,118,101,114,116,32,105,116,32,116,111,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,121,111,117,32,99,97,110,32,100,111,32,115,111,109,101,116,104,105,110,103,32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<108,105,115,116,115,58,109,97,112,40,10,32,32,102,117,110,40,35,123,32,99,111,117,110,116,101,114,115,32,58,61,32,67,110,116,32,125,32,61,32,77,41,32,45,62,10,32,32,32,32,32,32,32,32,32,32,77,115,67,110,116,32,61,32,109,97,112,115,58,109,97,112,40,102,117,110,40,95,75,44,32,80,101,114,102,67,111,117,110,116,41,32,45,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,40,80,101,114,102,67,111,117,110,116,44,32,112,101,114,102,95,99,111,117,110,116,101,114,44,32,49,48,48,48,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,101,110,100,44,32,67,110,116,41,44,10,32,32,32,32,32,32,32,32,32,77,35,123,32,99,111,117,110,116,101,114,115,32,58,61,32,77,115,67,110,116,32,125,10,32,32,101,110,100,44,32,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41,41,46>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,118,97,108,117,101,115,32,97,114,101,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,116,104,101,32,101,120,97,99,116,32,116,105,109,101,32,115,112,101,110,116,32,105,110,32,101,97,99,104,32,115,116,97,116,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,118,97,114,105,111,117,115,32,111,112,116,105,109,105,115,97,116,105,111,110,32,100,111,110,101,32,116,111,32,107,101,101,112,32,116,104,101,32,111,118,101,114,104,101,97,100,32,97,115,32,115,109,97,108,108,32,97,115,32,112,111,115,115,105,98,108,101,46>>]},{p,[],[{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,84,121,112,101>>]},<<115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,109,97,105,110,32,101,120,101,99,117,116,105,111,110,32,116,104,114,101,97,100,115,32,116,104,97,116,32,100,111,32,109,111,115,116,32,111,102,32,116,104,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,102,111,114,32,108,111,110,103,32,114,117,110,110,105,110,103,32,99,112,117,32,105,110,116,101,110,115,105,118,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83,68,99,112,117>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,102,111,114,32,108,111,110,103,32,114,117,110,110,105,110,103,32,73,47,79,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,83,68,105,111>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<97,115,121,110,99>>]}]},{dd,[],[<<65,115,121,110,99,32,116,104,114,101,97,100,115,32,97,114,101,32,117,115,101,100,32,98,121,32,118,97,114,105,111,117,115,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,115,32,40,109,97,105,110,108,121,32,116,104,101,32,102,105,108,101,32,100,114,105,118,101,114,115,41,32,100,111,32,111,102,102,108,111,97,100,32,110,111,110,45,67,80,85,32,105,110,116,101,110,115,105,118,101,32,119,111,114,107,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,97,115,121,110,99,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,65>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]},{dt,[],[{code,[],[<<97,117,120>>]}]},{dd,[],[<<84,97,107,101,115,32,99,97,114,101,32,111,102,32,97,110,121,32,119,111,114,107,32,116,104,97,116,32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,99,97,108,108,121,32,97,115,115,105,103,110,101,100,32,116,111,32,97,32,115,99,104,101,100,117,108,101,114,46>>]},{dt,[],[{code,[],[<<112,111,108,108>>]}]},{dd,[],[<<68,111,101,115,32,116,104,101,32,73,79,32,112,111,108,108,105,110,103,32,102,111,114,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,73,79,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<101,114,108,32,43,73,79,116>>]},<<32,102,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,83,116,97,116,101>>]},<<115,32,97,114,101,32,97,118,97,105,108,97,98,108,101,46,32,65,108,108,32,115,116,97,116,101,115,32,97,114,101,32,101,120,99,108,117,115,105,118,101,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,97,32,116,104,114,101,97,100,32,99,97,110,110,111,116,32,98,101,32,105,110,32,116,119,111,32,115,116,97,116,101,115,32,97,116,32,111,110,99,101,46,32,83,111,44,32,105,102,32,121,111,117,32,97,100,100,32,116,104,101,32,110,117,109,98,101,114,115,32,111,102,32,97,108,108,32,99,111,117,110,116,101,114,115,32,105,110,32,97,32,116,104,114,101,97,100,44,32,121,111,117,32,103,101,116,32,116,104,101,32,116,111,116,97,108,32,114,117,110,116,105,109,101,32,102,111,114,32,116,104,97,116,32,116,104,114,101,97,100,46>>]},{dl,[],[{dt,[],[{code,[],[<<97,117,120>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,104,97,110,100,108,105,110,103,32,97,117,120,105,108,105,97,114,121,32,106,111,98,115,46>>]},{dt,[],[{code,[],[<<99,104,101,99,107,95,105,111>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,99,104,101,99,107,105,110,103,32,102,111,114,32,110,101,119,32,73,47,79,32,101,118,101,110,116,115,46>>]},{dt,[],[{code,[],[<<101,109,117,108,97,116,111,114>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<103,99>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,104,101,110,32,101,120,116,114,97,32,115,116,97,116,101,115,32,97,114,101,32,101,110,97,98,108,101,100,32,116,104,105,115,32,105,115,32,116,104,101,32,116,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,110,111,110,45,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,46>>]},{dt,[],[{code,[],[<<111,116,104,101,114>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,117,110,97,99,99,111,117,110,116,101,100,32,116,104,105,110,103,115,46>>]},{dt,[],[{code,[],[<<112,111,114,116>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<115,108,101,101,112>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,115,108,101,101,112,105,110,103,46>>]}]},{p,[],[<<77,111,114,101,32,102,105,110,101,45,103,114,97,105,110,101,100,32>>,{code,[],[<<77,83,65,99,99,95,84,104,114,101,97,100,95,83,116,97,116,101>>]},<<115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,116,104,114,111,117,103,104,32,99,111,110,102,105,103,117,114,101,32,40,115,117,99,104,32,97,115,32>>,{code,[],[<<46,47,99,111,110,102,105,103,117,114,101,32,45,45,119,105,116,104,45,109,105,99,114,111,115,116,97,116,101,45,97,99,99,111,117,110,116,105,110,103,61,101,120,116,114,97>>]},<<41,46,32,69,110,97,98,108,105,110,103,32,116,104,101,115,101,32,115,116,97,116,101,115,32,99,97,117,115,101,115,32,112,101,114,102,111,114,109,97,110,99,101,32,100,101,103,114,97,100,97,116,105,111,110,32,119,104,101,110,32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,105,115,32,116,117,114,110,101,100,32,111,102,102,32,97,110,100,32,105,110,99,114,101,97,115,101,115,32,116,104,101,32,111,118,101,114,104,101,97,100,32,119,104,101,110,32,105,116,32,105,115,32,116,117,114,110,101,100,32,111,110,46>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108,111,99>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,109,97,110,97,103,105,110,103,32,109,101,109,111,114,121,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,115,112,114,101,97,100,32,111,117,116,32,111,118,101,114,32,97,108,108,32,111,116,104,101,114,32,115,116,97,116,101,115,46>>]},{dt,[],[{code,[],[<<98,105,102>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,105,110,32,66,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<98,117,115,121,95,119,97,105,116>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,98,117,115,121,32,119,97,105,116,105,110,103,46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,115,116,97,116,101,32,119,104,101,114,101,32,97,32,115,99,104,101,100,117,108,101,114,32,110,111,32,108,111,110,103,101,114,32,114,101,112,111,114,116,115,32,116,104,97,116,32,105,116,32,105,115,32,97,99,116,105,118,101,32,119,104,101,110,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<46,32,83,111,44,32,105,102,32,121,111,117,32,97,100,100,32,97,108,108,32,111,116,104,101,114,32,115,116,97,116,101,115,32,98,117,116,32,116,104,105,115,32,97,110,100,32,115,108,101,101,112,44,32,97,110,100,32,116,104,101,110,32,100,105,118,105,100,101,32,116,104,97,116,32,98,121,32,97,108,108,32,116,105,109,101,32,105,110,32,116,104,101,32,116,104,114,101,97,100,44,32,121,111,117,32,115,104,111,117,108,100,32,103,101,116,32,115,111,109,101,116,104,105,110,103,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32,116,104,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,102,114,97,99,116,105,111,110,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<111,116,104,101,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<101,116,115>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,101,120,101,99,117,116,105,110,103,32,69,84,83,32,66,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<103,99,95,102,117,108,108>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,100,111,105,110,103,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<103,99>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<110,105,102>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,105,110,32,78,73,70,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<115,101,110,100>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,115,101,110,100,105,110,103,32,109,101,115,115,97,103,101,115,32,40,112,114,111,99,101,115,115,101,115,32,111,110,108,121,41,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<101,109,117,108,97,116,111,114>>]},<<32,115,116,97,116,101,46>>]},{dt,[],[{code,[],[<<116,105,109,101,114,115>>]}]},{dd,[],[<<84,105,109,101,32,115,112,101,110,116,32,109,97,110,97,103,105,110,103,32,116,105,109,101,114,115,46,32,87,105,116,104,111,117,116,32,101,120,116,114,97,32,115,116,97,116,101,115,32,116,104,105,115,32,116,105,109,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<111,116,104,101,114>>]},<<32,115,116,97,116,101,46>>]}]},{p,[],[<<84,104,101,32,117,116,105,108,105,116,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<114,117,110,116,105,109,101,95,116,111,111,108,115,58,109,115,97,99,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,115,97,99,99,40,51,41>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,111,114,101,32,101,97,115,105,108,121,32,97,110,97,108,121,115,101,32,116,104,101,115,101,32,115,116,97,116,105,115,116,105,99,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>]}]},<<32,105,115,32,116,117,114,110,101,100,32,111,102,102,46>>]},{p,[],[<<84,104,101,32,108,105,115,116,32,111,102,32,116,104,114,101,97,100,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,115,111,114,116,101,100,32,97,110,100,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,100,105,102,102,101,114,101,110,116,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,99,97,108,108,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,116,104,114,101,97,100,115,32,97,110,100,32,115,116,97,116,101,115,32,97,114,101,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,119,105,116,104,111,117,116,32,97,110,121,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2842,17},bounded_fun,[{type,{2842,17},'fun',[{type,{2842,17},product,[{atom,{2842,18},microstate_accounting}]},{type,{2842,44},union,[{type,{2842,44},list,[{var,{2842,45},'MSAcc_Thread'}]},{atom,{2842,61},undefined}]}]},[{type,{2843,7},constraint,[{atom,{2843,7},is_subtype},[{var,{2843,7},'MSAcc_Thread'},{type,{2843,23},map,[{type,{2843,31},map_field_exact,[{atom,{2843,26},type},{var,{2843,34},'MSAcc_Thread_Type'}]},{type,{2844,28},map_field_exact,[{atom,{2844,25},id},{var,{2844,31},'MSAcc_Thread_Id'}]},{type,{2845,34},map_field_exact,[{atom,{2845,25},counters},{var,{2845,37},'MSAcc_Counters'}]}]}]]},{type,{2846,7},constraint,[{atom,{2846,7},is_subtype},[{var,{2846,7},'MSAcc_Thread_Type'},{type,{2846,28},union,[{atom,{2846,28},async},{atom,{2846,36},aux},{atom,{2846,42},dirty_io_scheduler},{atom,{2847,28},dirty_cpu_scheduler},{atom,{2847,50},poll},{atom,{2847,57},scheduler}]}]]},{type,{2848,7},constraint,[{atom,{2848,7},is_subtype},[{var,{2848,7},'MSAcc_Thread_Id'},{type,{2848,26},non_neg_integer,[]}]]},{type,{2849,7},constraint,[{atom,{2849,7},is_subtype},[{var,{2849,7},'MSAcc_Counters'},{type,{2849,25},map,[{type,{2849,47},map_field_assoc,[{var,{2849,28},'MSAcc_Thread_State'},{type,{2849,50},non_neg_integer,[]}]}]}]]},{type,{2850,7},constraint,[{atom,{2850,7},is_subtype},[{var,{2850,7},'MSAcc_Thread_State'},{type,{2850,29},union,[{atom,{2850,29},alloc},{atom,{2850,37},aux},{atom,{2850,43},bif},{atom,{2850,49},busy_wait},{atom,{2850,61},check_io},{atom,{2851,29},emulator},{atom,{2851,40},ets},{atom,{2851,46},gc},{atom,{2851,51},gc_fullsweep},{atom,{2851,66},nif},{atom,{2852,29},other},{atom,{2852,37},port},{atom,{2852,44},send},{atom,{2852,51},sleep},{atom,{2852,59},timers}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,55,55,51>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,114,101,100,117,99,116,105,111,110,115,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,114,101,100,117,99,116,105,111,110,115,41,46,10,123,50,48,52,54,44,49,49,125>>]}]},{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,53,32,40,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,41,44,32,116,104,105,115,32,118,97,108,117,101,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,114,101,100,117,99,116,105,111,110,115,32,112,101,114,102,111,114,109,101,100,32,105,110,32,99,117,114,114,101,110,116,32,116,105,109,101,32,115,108,105,99,101,115,32,111,102,32,99,117,114,114,101,110,116,108,121,32,115,99,104,101,100,117,108,101,100,32,112,114,111,99,101,115,115,101,115,46,32,73,102,32,97,110,32,101,120,97,99,116,32,118,97,108,117,101,32,105,115,32,119,97,110,116,101,100,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,101,120,97,99,116,95,114,101,100,117,99,116,105,111,110,115,41>>]}]},<<46>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2853,17},bounded_fun,[{type,{2853,17},'fun',[{type,{2853,17},product,[{atom,{2853,18},reductions}]},{type,{2853,33},tuple,[{var,{2853,34},'Total_Reductions'},{var,{2854,34},'Reductions_Since_Last_Call'}]}]},[{type,{2855,7},constraint,[{atom,{2855,7},is_subtype},[{var,{2855,7},'Total_Reductions'},{type,{2855,27},non_neg_integer,[]}]]},{type,{2856,7},constraint,[{atom,{2856,7},is_subtype},[{var,{2856,7},'Reductions_Since_Last_Call'},{type,{2856,37},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,57,49,54>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,111,116,97,108,32,108,101,110,103,116,104,32,111,102,32,97,108,108,32,110,111,114,109,97,108,32,97,110,100,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,97,116,32,105,115,44,32,113,117,101,117,101,100,32,119,111,114,107,32,116,104,97,116,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,116,104,105,115,32,111,112,101,114,97,116,105,111,110,32,105,115,32,109,117,99,104,32,109,111,114,101,32,101,120,112,101,110,115,105,118,101,32,99,111,109,112,97,114,101,100,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32,101,115,112,101,99,105,97,108,108,121,32,119,104,101,110,32,97,32,108,97,114,103,101,32,97,109,111,117,110,116,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,117,115,101,100,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2857,17},'fun',[{type,{2857,17},product,[{atom,{2857,18},run_queue}]},{type,{2857,32},non_neg_integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,57,51,53>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<32,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105,111,110,32,116,104,97,116,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,114,117,110,32,113,117,101,117,101,115,32,119,105,116,104,32,119,111,114,107,32,116,104,97,116,32,105,115,32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,67,80,85,32,98,111,117,110,100,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2858,17},bounded_fun,[{type,{2858,17},'fun',[{type,{2858,17},product,[{atom,{2858,18},run_queue_lengths}]},{type,{2858,40},list,[{var,{2858,41},'RunQueueLength'}]}]},[{type,{2859,7},constraint,[{atom,{2859,7},is_subtype},[{var,{2859,7},'RunQueueLength'},{type,{2859,25},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,57,53,49>>,since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,119,104,101,114,101,32,101,97,99,104,32,101,108,101,109,101,110,116,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,114,101,97,100,121,32,116,111,32,114,117,110,32,102,111,114,32,101,97,99,104,32,114,117,110,32,113,117,101,117,101,46,32,86,97,108,117,101,115,32,102,111,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,97,114,101,32,108,111,99,97,116,101,100,32,102,105,114,115,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,32,111,102,32,115,99,104,101,100,117,108,101,114,32,110,117,109,98,101,114,32,49,32,97,110,100,32,115,111,32,111,110,46,32,73,102,32,115,117,112,112,111,114,116,32,102,111,114,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,44,32,118,97,108,117,101,115,32,102,111,114,32,116,104,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,116,104,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,32,102,111,108,108,111,119,32,40,105,110,32,116,104,97,116,32,111,114,100,101,114,41,32,97,116,32,116,104,101,32,101,110,100,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,103,97,116,104,101,114,101,100,32,97,116,111,109,105,99,97,108,108,121,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,110,111,116,32,110,101,99,101,115,115,97,114,105,108,121,32,97,32,99,111,110,115,105,115,116,101,110,116,32,115,110,97,112,115,104,111,116,32,111,102,32,116,104,101,32,115,116,97,116,101,44,32,98,117,116,32,105,110,115,116,101,97,100,32,113,117,105,116,101,32,101,102,102,105,99,105,101,110,116,108,121,32,103,97,116,104,101,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<69,97,99,104,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,111,110,101,32,114,117,110,32,113,117,101,117,101,32,116,104,97,116,32,105,116,32,109,97,110,97,103,101,115,46,32,73,102,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,108,108,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,44,32,97,110,100,32,97,108,108,32,100,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,115,104,97,114,101,32,111,110,101,32,114,117,110,32,113,117,101,117,101,46,32,84,104,97,116,32,105,115,44,32,119,101,32,104,97,118,101,32,109,117,108,116,105,112,108,101,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,44,32,111,110,101,32,100,105,114,116,121,32,67,80,85,32,114,117,110,32,113,117,101,117,101,32,97,110,100,32,111,110,101,32,100,105,114,116,121,32,73,79,32,114,117,110,32,113,117,101,117,101,46,32,87,111,114,107,32,99,97,110,32>>,{em,[],[<<110,111,116>>]},<<32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,116,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,114,117,110,32,113,117,101,117,101,115,46,32,79,110,108,121,32,119,111,114,107,32,105,110,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,32,99,97,110,32,109,105,103,114,97,116,101,32,116,111,32,111,116,104,101,114,32,110,111,114,109,97,108,32,114,117,110,32,113,117,101,117,101,115,46,32,84,104,105,115,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,105,110,116,111,32,97,99,99,111,117,110,116,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,116,111,116,97,108,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2860,17},bounded_fun,[{type,{2860,17},'fun',[{type,{2860,17},product,[{atom,{2860,18},run_queue_lengths_all}]},{type,{2860,44},list,[{var,{2860,45},'RunQueueLength'}]}]},[{type,{2861,7},constraint,[{atom,{2861,7},is_subtype},[{var,{2861,7},'RunQueueLength'},{type,{2861,25},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,56,57,54,54>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,114,117,110,116,105,109,101,44,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]},{p,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,102,111,114,32,97,108,108,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,97,110,100,32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,119,97,108,108,32,99,108,111,99,107,32,116,105,109,101,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,109,105,103,104,116,32,119,114,97,112,32,100,117,101,32,116,111,32,108,105,109,105,116,97,116,105,111,110,115,32,105,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,112,114,111,118,105,100,101,100,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,116,104,97,116,32,105,115,32,117,115,101,100,46>>]}]},{p,[],[<<69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,115,116,97,116,105,115,116,105,99,115,40,114,117,110,116,105,109,101,41,46,10,123,49,54,57,48,44,49,54,50,48,125>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2862,17},bounded_fun,[{type,{2862,17},'fun',[{type,{2862,17},product,[{atom,{2862,18},runtime}]},{type,{2862,30},tuple,[{var,{2862,31},'Total_Run_Time'},{var,{2862,47},'Time_Since_Last_Call'}]}]},[{type,{2863,7},constraint,[{atom,{2863,7},is_subtype},[{var,{2863,7},'Total_Run_Time'},{type,{2863,25},non_neg_integer,[]}]]},{type,{2864,7},constraint,[{atom,{2864,7},is_subtype},[{var,{2864,7},'Time_Since_Last_Call'},{type,{2864,31},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,48,48,57>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,100,101,115,99,114,105,98,105,110,103,32,104,111,119,32,109,117,99,104,32,116,105,109,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,111,114,109,97,108>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,114,116,121,32,67,80,85>>]},<<32,115,99,104,101,100,117,108,101,114,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,104,97,118,101,32,98,101,101,110,32,98,117,115,121,46,32,84,104,105,115,32,118,97,108,117,101,32,105,115,32,110,111,114,109,97,108,108,121,32,97,32,98,101,116,116,101,114,32,105,110,100,105,99,97,116,111,114,32,111,102,32,104,111,119,32,109,117,99,104,32,108,111,97,100,32,97,110,32,69,114,108,97,110,103,32,110,111,100,101,32,105,115,32,117,110,100,101,114,32,105,110,115,116,101,97,100,32,111,102,32,108,111,111,107,105,110,103,32,97,116,32,116,104,101,32,67,80,85,32,117,116,105,108,105,122,97,116,105,111,110,32,112,114,111,118,105,100,101,100,32,98,121,32,116,111,111,108,115,32,115,117,99,104,32,97,115,32>>,{code,[],[<<116,111,112>>]},<<32,111,114,32>>,{code,[],[<<115,121,115,115,116,97,116>>]},<<46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,97,108,115,111,32,105,110,99,108,117,100,101,115,32,116,105,109,101,32,119,104,101,114,101,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,105,115,32,119,97,105,116,105,110,103,32,102,111,114,32,115,111,109,101,32,111,116,104,101,114,32,114,101,97,115,111,117,114,99,101,32,40,115,117,99,104,32,97,115,32,97,110,32,105,110,116,101,114,110,97,108,32,109,117,116,101,120,41,32,116,111,32,98,101,32,97,118,97,105,108,97,98,108,101,32,98,117,116,32,100,111,101,115,32,110,111,116,32,117,115,101,32,116,104,101,32,67,80,85,46,32,73,110,32,111,114,100,101,114,32,116,111,32,98,101,116,116,101,114,32,117,110,100,101,114,115,116,97,110,100,32,119,104,97,116,32,97,32,115,99,104,101,100,117,108,101,114,32,105,115,32,98,117,115,121,32,100,111,105,110,103,32,121,111,117,32,99,97,110,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103>>]},<<46>>]},{p,[],[<<84,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,98,117,115,121,32,115,99,104,101,100,117,108,101,114,32,105,115,32,119,104,101,110,32,105,116,32,105,115,32,110,111,116,32,105,100,108,101,32,97,110,100,32,110,111,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,119,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<98,117,115,121,32,119,97,105,116,105,110,103>>]},<<32,102,111,114,32,110,101,119,32,119,111,114,107,44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[<<69,120,101,99,117,116,105,110,103,32,112,114,111,99,101,115,115,32,99,111,100,101>>]},{li,[],[<<69,120,101,99,117,116,105,110,103,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,111,114,32,78,73,70,32,99,111,100,101>>]},{li,[],[<<69,120,101,99,117,116,105,110,103,32,66,73,70,115,44,32,111,114,32,97,110,121,32,111,116,104,101,114,32,114,117,110,116,105,109,101,32,104,97,110,100,108,105,110,103>>]},{li,[],[<<71,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,110,103>>]},{li,[],[<<72,97,110,100,108,105,110,103,32,97,110,121,32,111,116,104,101,114,32,109,101,109,111,114,121,32,109,97,110,97,103,101,109,101,110,116>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,115,99,104,101,100,117,108,101,114,32,99,97,110,32,97,108,115,111,32,98,101,32,98,117,115,121,32,101,118,101,110,32,105,102,32,116,104,101,32,79,83,32,104,97,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,117,115,101,32,116,104,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<114,117,110,116,105,109,101,95,116,111,111,108,115,58,115,99,104,101,100,117,108,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114>>]}]},<<32,105,110,115,116,101,97,100,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,100,105,114,101,99,116,108,121,32,97,115,32,105,116,32,112,114,111,118,105,100,101,115,32,97,110,32,101,97,115,105,101,114,32,119,97,121,32,116,111,32,103,101,116,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,116,104,97,116,32,121,111,117,32,117,115,117,97,108,108,121,32,119,97,110,116,46>>]}]},{p,[],[<<73,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,110,97,98,108,101,100>>]},<<32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<123,83,99,104,101,100,117,108,101,114,73,100,44,32,65,99,116,105,118,101,84,105,109,101,44,32,84,111,116,97,108,84,105,109,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,73,68,32,111,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,44,32>>,{code,[],[<<65,99,116,105,118,101,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,100,117,114,97,116,105,111,110,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,104,97,115,32,98,101,101,110,32,98,117,115,121,44,32,97,110,100,32>>,{code,[],[<<84,111,116,97,108,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,116,111,116,97,108,32,116,105,109,101,32,100,117,114,97,116,105,111,110,32,115,105,110,99,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]}]},<<32,97,99,116,105,118,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105,99,32,115,99,104,101,100,117,108,101,114,46,32,84,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,116,117,114,110,101,100,32,105,115,32,117,110,100,101,102,105,110,101,100,32,97,110,100,32,99,97,110,32,98,101,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,98,101,116,119,101,101,110,32,114,101,108,101,97,115,101,115,44,32,79,83,115,44,32,97,110,100,32,115,121,115,116,101,109,32,114,101,115,116,97,114,116,115,46,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,116,111,32,99,97,108,99,117,108,97,116,101,32,114,101,108,97,116,105,118,101,32,118,97,108,117,101,115,32,102,111,114,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,46,32,84,104,101,32>>,{code,[],[<<65,99,116,105,118,101,84,105,109,101>>]},<<32,99,97,110,32,110,101,118,101,114,32,101,120,99,101,101,100,32>>,{code,[],[<<84,111,116,97,108,84,105,109,101>>]},<<46,32,84,104,101,32,108,105,115,116,32,111,102,32,115,99,104,101,100,117,108,101,114,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,115,111,114,116,101,100,32,97,110,100,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,100,105,102,102,101,114,101,110,116,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,99,97,108,108,115,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,115,97,98,108,101,100>>]},<<32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<84,104,101,32,97,99,116,105,118,97,116,105,111,110,32,116,105,109,101,32,99,97,110,32,100,105,102,102,101,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,98,101,116,119,101,101,110,32,115,99,104,101,100,117,108,101,114,115,46,32,67,117,114,114,101,110,116,108,121,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,97,116,101,100,32,97,116,32,115,121,115,116,101,109,32,115,116,97,114,116,32,119,104,105,108,101,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,97,116,101,100,32,115,111,109,101,32,116,105,109,101,32,97,102,116,101,114,32,116,104,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,105,115,32,101,110,97,98,108,101,100,46>>]},{p,[],[<<79,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,99,104,101,100,117,108,101,114,115,32,116,104,97,116,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,104,97,110,100,108,101,32,67,80,85,32,98,111,117,110,100,32,119,111,114,107,32,105,115,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,102,114,111,109,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,73,102,32,121,111,117,32,97,108,115,111,32,119,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115>>]},<<44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,95,97,108,108,41>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<78,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<49,32,61,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46,32,68,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,104,97,110,100,108,101,32,115,112,101,99,105,102,105,99,32,116,121,112,101,115,32,111,102,32,106,111,98,115,46,32,69,118,101,114,121,32,106,111,98,32,105,115,32,97,115,115,105,103,110,101,100,32,116,111,32,97,32,115,112,101,99,105,102,105,99,32,115,99,104,101,100,117,108,101,114,32,116,121,112,101,46,32,74,111,98,115,32,99,97,110,32,109,105,103,114,97,116,101,32,98,101,116,119,101,101,110,32,100,105,102,102,101,114,101,110,116,32,115,99,104,101,100,117,108,101,114,115,32,111,102,32,116,104,101,32,115,97,109,101,32,116,121,112,101,44,32,98,117,116,32,110,101,118,101,114,32,98,101,116,119,101,101,110,32,115,99,104,101,100,117,108,101,114,115,32,111,102,32,100,105,102,102,101,114,101,110,116,32,116,121,112,101,115,46,32,84,104,105,115,32,102,97,99,116,32,104,97,115,32,116,111,32,98,101,32,116,97,107,101,110,32,117,110,100,101,114,32,99,111,110,115,105,100,101,114,97,116,105,111,110,32,119,104,101,110,32,101,118,97,108,117,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,114,101,116,117,114,110,101,100,46>>]}]},{p,[],[<<89,111,117,32,99,97,110,32,117,115,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,116,111,32,99,97,108,99,117,108,97,116,101,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,46,32,70,105,114,115,116,32,121,111,117,32,116,97,107,101,32,97,32,115,97,109,112,108,101,32,111,102,32,116,104,101,32,118,97,108,117,101,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]},<<46>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,44,32,116,114,117,101,41,46,10,102,97,108,115,101,10,62,32,84,115,48,32,61,32,108,105,115,116,115,58,115,111,114,116,40,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41,41,44,32,111,107,46,10,111,107>>]}]},{p,[],[<<83,111,109,101,32,116,105,109,101,32,108,97,116,101,114,32,116,104,101,32,117,115,101,114,32,116,97,107,101,115,32,97,110,111,116,104,101,114,32,115,110,97,112,115,104,111,116,32,97,110,100,32,99,97,108,99,117,108,97,116,101,115,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,112,101,114,32,115,99,104,101,100,117,108,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,84,115,49,32,61,32,108,105,115,116,115,58,115,111,114,116,40,101,114,108,97,110,103,58,115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41,41,44,32,111,107,46,10,111,107,10,62,32,108,105,115,116,115,58,109,97,112,40,102,117,110,40,123,123,73,44,32,65,48,44,32,84,48,125,44,32,123,73,44,32,65,49,44,32,84,49,125,125,41,32,45,62,10,9,123,73,44,32,40,65,49,32,45,32,65,48,41,47,40,84,49,32,45,32,84,48,41,125,32,101,110,100,44,32,108,105,115,116,115,58,122,105,112,40,84,115,48,44,84,115,49,41,41,46,10,91,123,49,44,48,46,57,55,52,51,52,55,52,55,51,48,49,55,55,53,52,56,125,44,10,32,123,50,44,48,46,57,55,52,52,56,52,51,55,56,50,55,53,49,52,52,52,125,44,10,32,123,51,44,48,46,57,57,57,53,57,48,50,51,54,49,54,54,57,48,52,53,125,44,10,32,123,52,44,48,46,57,55,51,56,48,49,50,53,57,54,53,55,50,49,54,49,125,44,10,32,123,53,44,48,46,57,55,49,55,57,53,54,54,54,55,48,49,56,49,48,51,125,44,10,32,123,54,44,48,46,57,55,51,57,50,51,53,56,52,54,52,50,48,55,52,49,125,44,10,32,123,55,44,48,46,57,55,51,50,51,55,48,51,51,48,55,55,56,55,54,125,44,10,32,123,56,44,48,46,57,55,52,49,50,57,55,50,57,51,50,52,56,54,53,54,125,93>>]}]},{p,[],[<<85,115,105,110,103,32,116,104,101,32,115,97,109,101,32,115,110,97,112,115,104,111,116,115,32,116,111,32,99,97,108,99,117,108,97,116,101,32,97,32,116,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<62,32,123,65,44,32,84,125,32,61,32,108,105,115,116,115,58,102,111,108,100,108,40,102,117,110,40,123,123,95,44,32,65,48,44,32,84,48,125,44,32,123,95,44,32,65,49,44,32,84,49,125,125,44,32,123,65,105,44,84,105,125,41,32,45,62,10,9,123,65,105,32,43,32,40,65,49,32,45,32,65,48,41,44,32,84,105,32,43,32,40,84,49,32,45,32,84,48,41,125,32,101,110,100,44,32,123,48,44,32,48,125,44,32,108,105,115,116,115,58,122,105,112,40,84,115,48,44,84,115,49,41,41,44,10,9,84,111,116,97,108,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,32,61,32,65,47,84,46,10,48,46,57,55,54,57,49,51,54,56,48,51,55,54,52,56,50,53>>]}]},{p,[],[<<84,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,105,108,108,32,101,113,117,97,108,32>>,{code,[],[<<49,46,48>>]},<<32,119,104,101,110,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,104,97,118,101,32,98,101,101,110,32,97,99,116,105,118,101,32,97,108,108,32,116,104,101,32,116,105,109,101,32,98,101,116,119,101,101,110,32,116,104,101,32,116,119,111,32,109,101,97,115,117,114,101,109,101,110,116,115,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,40,112,114,111,98,97,98,108,121,32,109,111,114,101,41,32,117,115,101,102,117,108,32,118,97,108,117,101,32,105,115,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,111,116,97,108,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,101,105,103,104,116,101,100,32,97,103,97,105,110,115,116,32,109,97,120,105,109,117,109,32,97,109,111,117,110,116,32,111,102,32,97,118,97,105,108,97,98,108,101,32,67,80,85,32,116,105,109,101,58>>]},{pre,[],[{code,[],[<<62,32,87,101,105,103,104,116,101,100,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,32,61,32,40,84,111,116,97,108,83,99,104,101,100,117,108,101,114,85,116,105,108,105,122,97,116,105,111,110,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,42,32,40,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41,41,41,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,47,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101,41,46,10,48,46,57,55,54,57,49,51,54,56,48,51,55,54,52,56,50,53>>]}]},{p,[],[<<84,104,105,115,32,119,101,105,103,104,116,101,100,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,119,105,108,108,32,114,101,97,99,104,32>>,{code,[],[<<49,46,48>>]},<<32,119,104,101,110,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,99,116,105,118,101,32,116,104,101,32,115,97,109,101,32,97,109,111,117,110,116,32,111,102,32,116,105,109,101,32,97,115,32,109,97,120,105,109,117,109,32,97,118,97,105,108,97,98,108,101,32,67,80,85,32,116,105,109,101,46,32,73,102,32,109,111,114,101,32,115,99,104,101,100,117,108,101,114,115,32,101,120,105,115,116,32,116,104,97,110,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,105,115,32,118,97,108,117,101,32,109,97,121,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<49,46,48>>]},<<46>>]},{p,[],[<<65,115,32,111,102,32,69,82,84,83,32,118,101,114,115,105,111,110,32,57,46,48,44,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,32,97,115,32,100,101,102,97,117,108,116,32,104,97,118,101,32,109,111,114,101,32,115,99,104,101,100,117,108,101,114,115,32,116,104,97,110,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,105,115,32,100,117,101,32,116,111,32,116,104,101,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,105,115,32,98,121,32,100,101,102,97,117,108,116,32,100,105,115,97,98,108,101,100,46,32,84,111,32,101,110,97,98,108,101,32,105,116,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,44,32,116,114,117,101,41>>]}]},<<46>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2865,17},bounded_fun,[{type,{2865,17},'fun',[{type,{2865,17},product,[{atom,{2865,18},scheduler_wall_time}]},{type,{2865,42},union,[{type,{2865,42},list,[{type,{2865,43},tuple,[{var,{2865,44},'SchedulerId'},{var,{2865,57},'ActiveTime'},{var,{2865,69},'TotalTime'}]}]},{atom,{2865,83},undefined}]}]},[{type,{2866,7},constraint,[{atom,{2866,7},is_subtype},[{var,{2866,7},'SchedulerId'},{type,{2866,22},pos_integer,[]}]]},{type,{2867,7},constraint,[{atom,{2867,7},is_subtype},[{var,{2867,7},'ActiveTime'},{type,{2867,22},non_neg_integer,[]}]]},{type,{2868,7},constraint,[{atom,{2868,7},is_subtype},[{var,{2868,7},'TotalTime'},{type,{2868,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,48,50,55>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,97,108,115,111,32,105,110,99,108,117,100,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,108,108,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<68,105,114,116,121,32,73,79,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},{code,[],[<<32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},{code,[],[<<32,60,32,83,99,104,101,100,117,108,101,114,73,100,32,61,60,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41,32,43,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41,32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,119,111,114,107,32,101,120,101,99,117,116,105,110,103,32,111,110,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,101,120,112,101,99,116,101,100,32,116,111,32,109,97,105,110,108,121,32,119,97,105,116,32,102,111,114,32,73,47,79,46,32,84,104,97,116,32,105,115,44,32,119,104,101,110,32,121,111,117,32,103,101,116,32,104,105,103,104,32,115,99,104,101,100,117,108,101,114,32,117,116,105,108,105,122,97,116,105,111,110,32,111,110,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,44,32,67,80,85,32,117,116,105,108,105,122,97,116,105,111,110,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,101,120,112,101,99,116,101,100,32,116,111,32,98,101,32,104,105,103,104,32,100,117,101,32,116,111,32,116,104,105,115,32,119,111,114,107,46>>]}]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2869,17},bounded_fun,[{type,{2869,17},'fun',[{type,{2869,17},product,[{atom,{2869,18},scheduler_wall_time_all}]},{type,{2869,46},union,[{type,{2869,46},list,[{type,{2869,47},tuple,[{var,{2869,48},'SchedulerId'},{var,{2869,61},'ActiveTime'},{var,{2869,73},'TotalTime'}]}]},{atom,{2869,87},undefined}]}]},[{type,{2870,7},constraint,[{atom,{2870,7},is_subtype},[{var,{2870,7},'SchedulerId'},{type,{2870,22},pos_integer,[]}]]},{type,{2871,7},constraint,[{atom,{2871,7},is_subtype},[{var,{2871,7},'ActiveTime'},{type,{2871,22},non_neg_integer,[]}]]},{type,{2872,7},constraint,[{atom,{2872,7},is_subtype},[{var,{2872,7},'TotalTime'},{type,{2872,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,49,55,50>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2873,3},bounded_fun,[{type,{2873,3},'fun',[{type,{2873,3},product,[{atom,{2873,4},total_active_tasks}]},{var,{2873,27},'ActiveTasks'}]},[{type,{2874,7},constraint,[{atom,{2874,7},is_subtype},[{var,{2874,7},'ActiveTasks'},{type,{2874,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,48,48>>,since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,97,99,116,105,118,101,95,116,97,115,107,115,95,97,108,108,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2875,3},bounded_fun,[{type,{2875,3},'fun',[{type,{2875,3},product,[{atom,{2875,4},total_active_tasks_all}]},{var,{2875,31},'ActiveTasks'}]},[{type,{2876,7},constraint,[{atom,{2876,7},is_subtype},[{var,{2876,7},'ActiveTasks'},{type,{2876,22},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,49,49>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2877,17},bounded_fun,[{type,{2877,17},'fun',[{type,{2877,17},product,[{atom,{2877,18},total_run_queue_lengths}]},{var,{2877,46},'TotalRunQueueLengths'}]},[{type,{2878,7},constraint,[{atom,{2878,7},is_subtype},[{var,{2878,7},'TotalRunQueueLengths'},{type,{2878,31},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,50,50>>,since => <<79,84,80,32,49,56,46,51>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<108,105,115,116,115,58,115,117,109,40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,114,117,110,95,113,117,101,117,101,95,108,101,110,103,116,104,115,95,97,108,108,41>>]}]},{code,[],[<<41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2879,17},bounded_fun,[{type,{2879,17},'fun',[{type,{2879,17},product,[{atom,{2879,18},total_run_queue_lengths_all}]},{var,{2879,50},'TotalRunQueueLengths'}]},[{type,{2880,7},constraint,[{atom,{2880,7},is_subtype},[{var,{2880,7},'TotalRunQueueLengths'},{type,{2880,31},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,51,51>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,statistics,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2826}],[<<115,116,97,116,105,115,116,105,99,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,119,97,108,108,32,99,108,111,99,107,46,32>>,{code,[],[<<119,97,108,108,95,99,108,111,99,107>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,32,116,104,101,32,115,97,109,101,32,109,97,110,110,101,114,32,97,115,32>>,{code,[],[<<114,117,110,116,105,109,101>>]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,114,101,97,108,32,116,105,109,101,32,105,115,32,109,101,97,115,117,114,101,100,32,97,115,32,111,112,112,111,115,101,100,32,116,111,32,114,117,110,116,105,109,101,32,111,114,32,67,80,85,32,116,105,109,101,46>>]}]},#{signature => [{attribute,{2826,2},spec,{{statistics,1},[{type,{2881,17},bounded_fun,[{type,{2881,17},'fun',[{type,{2881,17},product,[{atom,{2881,18},wall_clock}]},{type,{2881,33},tuple,[{var,{2881,34},'Total_Wallclock_Time'},{var,{2882,34},'Wallclock_Time_Since_Last_Call'}]}]},[{type,{2883,7},constraint,[{atom,{2883,7},is_subtype},[{var,{2883,7},'Total_Wallclock_Time'},{type,{2883,31},non_neg_integer,[]}]]},{type,{2884,7},constraint,[{atom,{2884,7},is_subtype},[{var,{2884,7},'Wallclock_Time_Since_Last_Call'},{type,{2884,41},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,52,52>>}},{{function,suspend_process,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2235}],[<<115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,49>>],#{<<101,110>> => [{p,[],[<<83,117,115,112,101,110,100,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,44,32,91,93,41>>]}]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]}]},#{signature => [{attribute,{2235,2},spec,{{erlang,suspend_process,1},[{type,{2235,29},bounded_fun,[{type,{2235,29},'fun',[{type,{2235,29},product,[{var,{2235,30},'Suspendee'}]},{atom,{2235,44},true}]},[{type,{2236,7},constraint,[{atom,{2236,7},is_subtype},[{var,{2236,7},'Suspendee'},{type,{2236,20},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,53,53>>}},{{function,suspend_process,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2219}],[<<115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>],#{<<101,110>> => [{p,[],[<<73,110,99,114,101,97,115,101,115,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,97,110,100,32,112,117,116,115,32,105,116,32,105,110,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,32,105,102,32,105,116,32,105,115,32,110,111,116,32,97,108,114,101,97,100,121,32,105,110,32,116,104,97,116,32,115,116,97,116,101,46,32,65,32,115,117,115,112,101,110,100,101,100,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,115,99,104,101,100,117,108,101,100,32,102,111,114,32,101,120,101,99,117,116,105,111,110,32,117,110,116,105,108,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,115,32,98,101,101,110,32,114,101,115,117,109,101,100,46>>]},{p,[],[<<65,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,115,117,115,112,101,110,100,101,100,32,98,121,32,109,117,108,116,105,112,108,101,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,99,97,110,32,98,101,32,115,117,115,112,101,110,100,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,98,121,32,97,32,115,105,110,103,108,101,32,112,114,111,99,101,115,115,46,32,65,32,115,117,115,112,101,110,100,101,100,32,112,114,111,99,101,115,115,32,100,111,101,115,32,110,111,116,32,108,101,97,118,101,32,116,104,101,32,115,117,115,112,101,110,100,101,100,32,115,116,97,116,101,32,117,110,116,105,108,32,105,116,115,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,114,101,97,99,104,101,115,32,122,101,114,111,46,32,84,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,100,101,99,114,101,97,115,101,100,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,115,117,109,101,95,112,114,111,99,101,115,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]}]},<<32,105,115,32,99,97,108,108,101,100,32,98,121,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,99,97,108,108,101,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<46,32,65,108,108,32,105,110,99,114,101,97,115,101,100,32,115,117,115,112,101,110,100,32,99,111,117,110,116,115,32,111,110,32,111,116,104,101,114,32,112,114,111,99,101,115,115,101,115,32,97,99,113,117,105,114,101,100,32,98,121,32,97,32,112,114,111,99,101,115,115,32,97,114,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,46>>]},{p,[],[<<79,112,116,105,111,110,115,32,40>>,{code,[],[<<79,112,116>>]},<<115,41,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]}]},{dd,[],[{p,[],[<<65,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,101,118,101,110,116,117,97,108,108,121,32,115,117,115,112,101,110,100,115,32,117,110,108,101,115,115,32,105,116,32,105,115,32,114,101,115,117,109,101,100,32,98,101,102,111,114,101,32,105,116,32,99,111,117,108,100,32,115,117,115,112,101,110,100,46,32,84,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,114,101,116,117,114,110,115,32,105,109,109,101,100,105,97,116,101,108,121,44,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,116,104,101,114,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,115,117,115,112,101,110,100,101,100,32,121,101,116,32,111,114,32,110,111,116,46,32,84,104,101,32,112,111,105,110,116,32,105,110,32,116,105,109,101,32,119,104,101,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,115,117,115,112,101,110,100,115,32,99,97,110,110,111,116,32,98,101,32,100,101,100,117,99,101,100,32,102,114,111,109,32,111,116,104,101,114,32,101,118,101,110,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,116,32,105,115,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32>>,{em,[],[<<101,118,101,110,116,117,97,108,108,121>>]},<<32,115,117,115,112,101,110,100,115,32,40,117,110,108,101,115,115,32,105,116,32,105,115,32,114,101,115,117,109,101,100,41,46,32,73,102,32,110,111,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,112,116,105,111,110,115,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<32,105,115,32,98,108,111,99,107,101,100,32,117,110,116,105,108,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,115,117,115,112,101,110,100,101,100,46>>]}]},{dt,[],[{code,[],[<<123,97,115,121,110,99,104,114,111,110,111,117,115,44,32,82,101,112,108,121,84,97,103,125>>]}]},{dd,[],[{p,[],[<<65,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,87,104,101,110,32,116,104,101,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,104,97,115,32,98,101,101,110,32,112,114,111,99,101,115,115,101,100,44,32,97,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,84,104,101,32,114,101,112,108,121,32,105,115,32,111,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,82,101,112,108,121,84,97,103,44,32,83,116,97,116,101,125>>]},<<32,119,104,101,114,101,32>>,{code,[],[<<83,116,97,116,101>>]},<<32,105,115,32,101,105,116,104,101,114,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,105,116,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,101,120,105,116,101,100,46>>]}]},{dt,[],[{code,[],[<<115,117,115,112,101,110,100,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,119,32,115,117,115,112,101,110,100,101,100,46>>]}]},{dt,[],[{code,[],[<<110,111,116,95,115,117,115,112,101,110,100,101,100>>]}]},{dd,[],[{p,[],[{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,115,117,115,112,101,110,100,101,100,46,32,84,104,105,115,32,99,97,110,32,111,110,108,121,32,104,97,112,112,101,110,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,105,115,115,117,101,100,32,116,104,105,115,32,114,101,113,117,101,115,116,44,32,104,97,118,101,32,99,97,108,108,101,100,32>>,{code,[],[<<114,101,115,117,109,101,95,112,114,111,99,101,115,115,40,83,117,115,112,101,110,100,101,101,41>>]},<<32,98,101,102,111,114,101,32,103,101,116,116,105,110,103,32,116,104,101,32,114,101,112,108,121,46>>]}]}]},{p,[],[<<65,112,97,114,116,32,102,114,111,109,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,44,32,116,104,101,32>>,{code,[],[<<123,97,115,121,110,99,104,114,111,110,111,117,115,44,32,82,101,112,108,121,84,97,103,125>>]},<<32,111,112,116,105,111,110,32,98,101,104,97,118,101,115,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,111,112,116,105,111,110,32,119,105,116,104,111,117,116,32,114,101,112,108,121,32,116,97,103,46>>]}]},{dt,[],[{code,[],[<<117,110,108,101,115,115,95,115,117,115,112,101,110,100,105,110,103>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,115,117,115,112,101,110,100,101,100,32,117,110,108,101,115,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<46,32,73,102,32>>,{code,[],[<<117,110,108,101,115,115,95,115,117,115,112,101,110,100,105,110,103>>]},<<32,105,115,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<44,32,97,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,105,115,32,115,101,110,116,32,117,110,108,101,115,115,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,111,114,32,105,102,32,97,32,115,117,115,112,101,110,100,32,114,101,113,117,101,115,116,32,97,108,114,101,97,100,121,32,104,97,115,32,98,101,101,110,32,115,101,110,116,32,97,110,100,32,105,115,32,105,110,32,116,114,97,110,115,105,116,46,32,73,102,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,108,114,101,97,100,121,32,105,115,32,115,117,115,112,101,110,100,105,110,103,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<44,32,111,114,32,105,102,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<97,115,121,110,99,104,114,111,110,111,117,115>>]},<<32,97,110,100,32,97,32,115,101,110,100,32,114,101,113,117,101,115,116,32,97,108,114,101,97,100,121,32,105,115,32,105,110,32,116,114,97,110,115,105,116,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,97,110,100,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,109,97,105,110,115,32,117,110,99,104,97,110,103,101,100,46>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,115,112,101,110,100,32,99,111,117,110,116,32,111,110,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,105,110,99,114,101,97,115,101,100,44,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,66,73,70,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<89,111,117,32,99,97,110,32,101,97,115,105,108,121,32,99,114,101,97,116,101,32,100,101,97,100,108,111,99,107,115,32,105,102,32,112,114,111,99,101,115,115,101,115,32,115,117,115,112,101,110,100,115,32,101,97,99,104,32,111,116,104,101,114,32,40,100,105,114,101,99,116,108,121,32,111,114,32,105,110,32,99,105,114,99,108,101,115,41,46,32,73,110,32,69,82,84,83,32,118,101,114,115,105,111,110,115,32,112,114,105,111,114,32,116,111,32,69,82,84,83,32,118,101,114,115,105,111,110,32,49,48,46,48,44,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,112,114,101,118,101,110,116,101,100,32,115,117,99,104,32,100,101,97,100,108,111,99,107,115,44,32,98,117,116,32,116,104,105,115,32,112,114,101,118,101,110,116,105,111,110,32,104,97,115,32,110,111,119,32,98,101,101,110,32,114,101,109,111,118,101,100,32,100,117,101,32,116,111,32,112,101,114,102,111,114,109,97,110,99,101,32,114,101,97,115,111,110,115,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,32,97,115,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,117,115,112,101,110,100,95,112,114,111,99,101,115,115,47,50>>]},<<46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,105,115,32,110,111,116,32,97,108,105,118,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,114,101,115,105,100,101,115,32,111,110,32,97,110,111,116,104,101,114,32,110,111,100,101,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<79,112,116,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,32,111,102,32,118,97,108,105,100,32>>,{code,[],[<<79,112,116>>]},<<115,46>>]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[<<73,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<83,117,115,112,101,110,100,101,101>>]},<<32,104,97,115,32,98,101,101,110,32,115,117,115,112,101,110,100,101,100,32,109,111,114,101,32,116,105,109,101,115,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,116,104,97,110,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,105,110,116,101,114,110,97,108,32,100,97,116,97,32,115,116,114,117,99,116,117,114,101,115,46,32,84,104,101,32,115,121,115,116,101,109,32,108,105,109,105,116,32,105,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,50,44,48,48,48,44,48,48,48,44,48,48,48,32,115,117,115,112,101,110,100,115,32,97,110,100,32,119,105,108,108,32,110,101,118,101,114,32,98,101,32,108,111,119,101,114,46>>]}]}]},#{signature => [{attribute,{2219,2},spec,{{erlang,suspend_process,2},[{type,{2219,29},bounded_fun,[{type,{2219,29},'fun',[{type,{2219,29},product,[{var,{2219,30},'Suspendee'},{var,{2219,41},'OptList'}]},{type,{2219,53},boolean,[]}]},[{type,{2220,7},constraint,[{atom,{2220,7},is_subtype},[{var,{2220,7},'Suspendee'},{type,{2220,20},pid,[]}]]},{type,{2221,7},constraint,[{atom,{2221,7},is_subtype},[{var,{2221,7},'OptList'},{type,{2221,18},list,[{var,{2221,19},'Opt'}]}]]},{type,{2222,7},constraint,[{atom,{2222,7},is_subtype},[{var,{2222,7},'Opt'},{type,{2222,14},union,[{atom,{2222,14},unless_suspending},{atom,{2222,34},asynchronous},{type,{2222,49},tuple,[{atom,{2222,50},asynchronous},{type,{2222,64},term,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,50,55,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,109,97,120,105,109,117,109,32,100,101,112,116,104,32,111,102,32,99,97,108,108,32,115,116,97,99,107,32,98,97,99,107,45,116,114,97,99,101,115,32,105,110,32,116,104,101,32,101,120,105,116,32,114,101,97,115,111,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<39,69,88,73,84,39>>]},<<32,116,117,112,108,101,115,46,32,84,104,101,32,102,108,97,103,32,97,108,115,111,32,108,105,109,105,116,115,32,116,104,101,32,115,116,97,99,107,116,114,97,99,101,32,100,101,112,116,104,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<112,114,111,99,101,115,115,95,105,110,102,111>>]},<<32,105,116,101,109,32>>,{code,[],[<<99,117,114,114,101,110,116,95,115,116,97,99,107,116,114,97,99,101,46>>]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2904,25},bounded_fun,[{type,{2904,25},'fun',[{type,{2904,25},product,[{atom,{2904,26},backtrace_depth},{var,{2904,43},'Depth'}]},{var,{2904,53},'OldDepth'}]},[{type,{2905,7},constraint,[{atom,{2905,7},is_subtype},[{var,{2905,7},'Depth'},{type,{2905,16},non_neg_integer,[]}]]},{type,{2906,7},constraint,[{atom,{2906,7},is_subtype},[{var,{2906,7},'OldDepth'},{type,{2906,19},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,52,49,54>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>}],[]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>}],[]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>}],[]},{li,[{name,<<115,117,98,95,108,101,118,101,108>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,73,110,115,116,101,97,100,32,111,102,32,117,115,105,110,103,32,116,104,105,115,32,97,114,103,117,109,101,110,116,44,32,117,115,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,114,101,109,111,118,101,100,44,32,97,32,102,105,110,97,108,32,67,80,85,32,116,111,112,111,108,111,103,121,32,116,111,32,117,115,101,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,46>>]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<46,32,84,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,118,101,114,114,105,100,101,115,32,97,110,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,46,32,66,121,32,112,97,115,115,105,110,103,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,97,115,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<44,32,116,104,101,32,115,121,115,116,101,109,32,114,101,118,101,114,116,115,32,116,111,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,101,113,117,97,108,115,32,116,104,101,32,118,97,108,117,101,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,99,112,117,95,116,111,112,111,108,111,103,121,41>>]},<<32,98,101,102,111,114,101,32,116,104,101,32,99,104,97,110,103,101,32,119,97,115,32,109,97,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,98,105,110,100,105,110,103,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,73,102,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,97,108,114,101,97,100,121,32,98,111,117,110,100,32,119,104,101,110,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,99,104,97,110,103,101,100,44,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,115,101,110,116,32,97,32,114,101,113,117,101,115,116,32,116,111,32,114,101,98,105,110,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,110,101,119,32,67,80,85,32,116,111,112,111,108,111,103,121,46>>]},{p,[],[<<84,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,116,121,112,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,97,110,100,32,109,111,114,101,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,99,112,117,95,116,111,112,111,108,111,103,121,41>>]}]},<<32,97,115,32,119,101,108,108,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2907,25},bounded_fun,[{type,{2907,25},'fun',[{type,{2907,25},product,[{atom,{2907,26},cpu_topology},{var,{2907,40},'CpuTopology'}]},{var,{2907,56},'OldCpuTopology'}]},[{type,{2908,7},constraint,[{atom,{2908,7},is_subtype},[{var,{2908,7},'CpuTopology'},{user_type,{2908,22},cpu_topology,[]}]]},{type,{2909,7},constraint,[{atom,{2909,7},is_subtype},[{var,{2909,7},'OldCpuTopology'},{user_type,{2909,25},cpu_topology,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,52,50,56>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,82,97,110,103,101,32,105,115,32>>,{code,[],[<<49,32,60,61,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,78>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,99,104,97,110,103,101,32,105,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,104,97,110,103,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,49,50,32,115,99,104,101,100,117,108,101,114,115,32,97,110,100,32,54,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,111,110,108,105,110,101,44,32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>]},<<32,105,115,32,117,115,101,100,32,116,111,32,115,101,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,116,111,32,54,44,32,116,104,101,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,98,121,32,104,97,108,102,32,97,115,32,119,101,108,108,44,32,100,111,119,110,32,116,111,32,51,46,32,83,105,109,105,108,97,114,108,121,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,110,99,114,101,97,115,101,115,32,112,114,111,112,111,114,116,105,111,110,97,108,108,121,32,116,111,32,105,110,99,114,101,97,115,101,115,32,105,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2910,25},bounded_fun,[{type,{2910,25},'fun',[{type,{2910,25},product,[{atom,{2910,26},dirty_cpu_schedulers_online},{var,{2910,55},'DirtyCPUSchedulersOnline'}]},{var,{2911,33},'OldDirtyCPUSchedulersOnline'}]},[{type,{2912,7},constraint,[{atom,{2912,7},is_subtype},[{var,{2912,7},'DirtyCPUSchedulersOnline'},{type,{2912,35},pos_integer,[]}]]},{type,{2913,7},constraint,[{atom,{2913,7},is_subtype},[{var,{2913,7},'OldDirtyCPUSchedulersOnline'},{type,{2913,38},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,52,55,54>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,102,108,97,103,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,116,104,101,32,97,108,108,111,99,97,116,111,114,32,116,111,32,97,102,102,101,99,116,44,32,102,111,114,32,101,120,97,109,112,108,101,32>>,{code,[],[<<98,105,110,97,114,121,95,97,108,108,111,99>>]},<<46,32>>,{code,[],[<<70>>]},<<32,105,115,32,116,104,101,32,102,108,97,103,32,116,111,32,99,104,97,110,103,101,32,97,110,100,32>>,{code,[],[<<86>>]},<<32,105,115,32,116,104,101,32,110,101,119,32,118,97,108,117,101,46>>]},{p,[],[<<79,110,108,121,32,97,32,115,117,98,115,101,116,32,111,102,32,97,108,108,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99>>]},<<32,102,108,97,103,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,114,117,110,32,116,105,109,101,46,32,84,104,105,115,32,115,117,98,115,101,116,32,105,115,32,99,117,114,114,101,110,116,108,121,32,111,110,108,121,32,116,104,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,77,95,115,98,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<115,98,99,116>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,102,108,97,103,32,119,97,115,32,115,101,116,32,111,114,32>>,{code,[],[<<110,111,116,115,117,112>>]},<<32,105,102,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99>>]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2914,25},bounded_fun,[{type,{2914,25},'fun',[{type,{2914,25},product,[{atom,{2914,26},erts_alloc},{type,{2914,38},tuple,[{var,{2914,39},'Alloc'},{var,{2914,46},'F'},{var,{2914,49},'V'}]}]},{type,{2914,56},union,[{atom,{2914,56},ok},{atom,{2914,61},notsup}]}]},[{type,{2915,7},constraint,[{atom,{2915,7},is_subtype},[{var,{2915,7},'Alloc'},{type,{2915,16},atom,[]}]]},{type,{2916,7},constraint,[{atom,{2916,7},is_subtype},[{var,{2916,7},'F'},{type,{2916,12},atom,[]}]]},{type,{2917,7},constraint,[{atom,{2917,7},is_subtype},[{var,{2917,7},'V'},{type,{2917,12},integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,48,53>>,since => <<79,84,80,32,50,48,46,50,46,51>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,102,108,97,103,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<46,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,105,115,32,97,32,110,111,110,45,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,32,105,110,100,105,99,97,116,105,110,103,32,104,111,119,32,109,97,110,121,32,116,105,109,101,115,32,103,101,110,101,114,97,116,105,111,110,97,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,99,97,110,32,98,101,32,100,111,110,101,32,119,105,116,104,111,117,116,32,102,111,114,99,105,110,103,32,97,32,102,117,108,108,115,119,101,101,112,32,99,111,108,108,101,99,116,105,111,110,46,32,84,104,101,32,118,97,108,117,101,32,97,112,112,108,105,101,115,32,116,111,32,110,101,119,32,112,114,111,99,101,115,115,101,115,44,32,119,104,105,108,101,32,112,114,111,99,101,115,115,101,115,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,32,97,114,101,32,110,111,116,32,97,102,102,101,99,116,101,100,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<73,110,32,108,111,119,45,109,101,109,111,114,121,32,115,121,115,116,101,109,115,32,40,101,115,112,101,99,105,97,108,108,121,32,119,105,116,104,111,117,116,32,118,105,114,116,117,97,108,32,109,101,109,111,114,121,41,44,32,115,101,116,116,105,110,103,32,116,104,101,32,118,97,108,117,101,32,116,111,32>>,{code,[],[<<48>>]},<<32,99,97,110,32,104,101,108,112,32,116,111,32,99,111,110,115,101,114,118,101,32,109,101,109,111,114,121,46>>]},{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,116,104,114,111,117,103,104,32,40,79,83,41,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,32>>,{code,[],[<<69,82,76,95,70,85,76,76,83,87,69,69,80,95,65,70,84,69,82>>]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2918,25},bounded_fun,[{type,{2918,25},'fun',[{type,{2918,25},product,[{atom,{2918,26},fullsweep_after},{var,{2918,43},'Number'}]},{var,{2918,54},'OldNumber'}]},[{type,{2919,7},constraint,[{atom,{2919,7},is_subtype},[{var,{2919,7},'Number'},{type,{2919,17},non_neg_integer,[]}]]},{type,{2920,7},constraint,[{atom,{2920,7},is_subtype},[{var,{2920,7},'OldNumber'},{type,{2920,20},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,50,50>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<84,117,114,110,115,32,111,110,47,111,102,102,32,109,105,99,114,111,115,116,97,116,101,32,97,99,99,111,117,110,116,105,110,103,32,109,101,97,115,117,114,101,109,101,110,116,115,46,32,87,104,101,110,32,112,97,115,115,105,110,103,32,114,101,115,101,116,44,32,97,108,108,32,99,111,117,110,116,101,114,115,32,97,114,101,32,114,101,115,101,116,32,116,111,32,48,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,109,105,99,114,111,115,116,97,116,101,95,97,99,99,111,117,110,116,105,110,103,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2921,25},bounded_fun,[{type,{2921,25},'fun',[{type,{2921,25},product,[{atom,{2921,26},microstate_accounting},{var,{2921,49},'Action'}]},{var,{2921,60},'OldState'}]},[{type,{2922,7},constraint,[{atom,{2922,7},is_subtype},[{var,{2922,7},'Action'},{type,{2922,17},union,[{atom,{2922,17},true},{atom,{2922,24},false},{atom,{2922,32},reset}]}]]},{type,{2923,7},constraint,[{atom,{2923,7},is_subtype},[{var,{2923,7},'OldState'},{type,{2923,19},union,[{atom,{2923,19},true},{atom,{2923,26},false}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,52,49>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,97,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2924,25},bounded_fun,[{type,{2924,25},'fun',[{type,{2924,25},product,[{atom,{2924,26},min_heap_size},{var,{2924,41},'MinHeapSize'}]},{var,{2924,57},'OldMinHeapSize'}]},[{type,{2925,7},constraint,[{atom,{2925,7},is_subtype},[{var,{2925,7},'MinHeapSize'},{type,{2925,22},non_neg_integer,[]}]]},{type,{2926,7},constraint,[{atom,{2926,7},is_subtype},[{var,{2926,7},'OldMinHeapSize'},{type,{2926,25},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,53,53>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,97,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2927,25},bounded_fun,[{type,{2927,25},'fun',[{type,{2927,25},product,[{atom,{2927,26},min_bin_vheap_size},{var,{2927,46},'MinBinVHeapSize'}]},{var,{2928,33},'OldMinBinVHeapSize'}]},[{type,{2929,7},constraint,[{atom,{2929,7},is_subtype},[{var,{2929,7},'MinBinVHeapSize'},{type,{2929,26},non_neg_integer,[]}]]},{type,{2930,7},constraint,[{atom,{2930,7},is_subtype},[{var,{2930,7},'OldMinBinVHeapSize'},{type,{2930,29},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,55,48>>,since => <<79,84,80,32,82,49,51,66,48,52>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,115,101,116,116,105,110,103,115,32,102,111,114,32,112,114,111,99,101,115,115,101,115,46,32,84,104,101,32,115,105,122,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,119,111,114,100,115,46,32,84,104,101,32,110,101,119,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,101,102,102,101,99,116,115,32,111,110,108,121,32,112,114,111,99,101,115,115,101,115,32,115,112,97,119,110,101,100,32,97,102,116,101,114,32,116,104,101,32,99,104,97,110,103,101,32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,112,114,111,99,101,115,115,101,115,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,47,50>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<70,111,114,32,100,101,116,97,105,108,115,32,111,110,32,104,111,119,32,116,104,101,32,104,101,97,112,32,103,114,111,119,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,71,97,114,98,97,103,101,67,111,108,108,101,99,116,105,111,110,35,115,105,122,105,110,103,45,116,104,101,45,104,101,97,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,105,122,105,110,103,32,116,104,101,32,104,101,97,112>>]},<<32,105,110,32,116,104,101,32,69,82,84,83,32,105,110,116,101,114,110,97,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2931,25},bounded_fun,[{type,{2931,25},'fun',[{type,{2931,25},product,[{atom,{2931,26},max_heap_size},{var,{2931,41},'MaxHeapSize'}]},{var,{2931,57},'OldMaxHeapSize'}]},[{type,{2932,7},constraint,[{atom,{2932,7},is_subtype},[{var,{2932,7},'MaxHeapSize'},{user_type,{2932,22},max_heap_size,[]}]]},{type,{2933,7},constraint,[{atom,{2933,7},is_subtype},[{var,{2933,7},'OldMaxHeapSize'},{user_type,{2933,25},max_heap_size,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,53,56,55>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,101,110,97,98,108,101,100,44,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,77,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,99,97,110,32,98,101,32,98,108,111,99,107,101,100,32,105,110,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,46,32,69,105,116,104,101,114,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,44,32,111,114,32,97,108,108,32>>,{em,[],[<<110,111,114,109,97,108>>]},<<32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,46,32,87,104,101,110,32,111,110,108,121,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,108,111,99,107,101,100,44,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,102,114,101,101,32,116,111,32,99,111,110,116,105,110,117,101,32,116,111,32,115,99,104,101,100,117,108,101,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,98,108,111,99,107>>]},<<44,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,101,32,97,110,100,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,119,105,108,108,32,101,120,101,99,117,116,101,46,32,73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,117,110,98,108,111,99,107>>]},<<32,97,110,100,32,110,111,32,111,110,101,32,101,108,115,101,32,98,108,111,99,107,115,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,44,32,97,110,100,32,116,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,111,110,108,121,32,111,110,99,101,44,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,117,110,98,108,111,99,107,101,100,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,98,108,111,99,107,95,110,111,114,109,97,108>>]},<<44,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,111,110,101,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,119,105,108,108,32,101,120,101,99,117,116,101,44,32,98,117,116,32,109,117,108,116,105,112,108,101,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,99,97,110,32,101,120,101,99,117,116,101,46,32,73,102,32>>,{code,[],[<<66,108,111,99,107,83,116,97,116,101,32,61,58,61,32,117,110,98,108,111,99,107,95,110,111,114,109,97,108>>]},<<32,97,110,100,32,110,111,32,111,110,101,32,101,108,115,101,32,98,108,111,99,107,115,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,44,32,97,110,100,32,116,104,105,115,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,111,110,108,121,32,111,110,99,101,44,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,117,110,98,108,111,99,107,101,100,46>>]},{p,[],[<<79,110,101,32,112,114,111,99,101,115,115,32,99,97,110,32,98,108,111,99,107,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,44,32,105,116,32,109,117,115,116,32,117,110,98,108,111,99,107,32,101,120,97,99,116,108,121,32,97,115,32,109,97,110,121,32,116,105,109,101,115,32,97,115,32,105,116,32,104,97,115,32,98,108,111,99,107,101,100,32,98,101,102,111,114,101,32,105,116,32,104,97,115,32,114,101,108,101,97,115,101,100,32,105,116,115,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,98,108,111,99,107,46,32,73,102,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,111,114,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,101,120,105,116,115,44,32,105,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,108,101,97,115,101,115,32,105,116,115,32,98,108,111,99,107,105,110,103,32,111,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,97,114,101,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<44,32>>,{code,[],[<<98,108,111,99,107,101,100>>]},<<44,32>>,{code,[],[<<98,108,111,99,107,101,100,95,110,111,114,109,97,108>>]},<<44,32,111,114,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,100,101,115,99,114,105,98,101,115,32,116,104,101,32,115,116,97,116,101,32,106,117,115,116,32,97,102,116,101,114,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]},<<32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<66,108,111,99,107,105,110,103,32,111,102,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,110,111,114,109,97,108,108,121,32,110,111,116,32,110,101,101,100,101,100,46,32,73,102,32,121,111,117,32,102,101,101,108,32,116,104,97,116,32,121,111,117,32,110,101,101,100,32,116,111,32,117,115,101,32,116,104,101,115,101,32,102,101,97,116,117,114,101,115,44,32,99,111,110,115,105,100,101,114,32,105,116,32,97,32,102,101,119,32,109,111,114,101,32,116,105,109,101,115,32,97,103,97,105,110,46,32,66,108,111,99,107,105,110,103,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,97,115,32,97,32,108,97,115,116,32,114,101,115,111,114,116,44,32,97,115,32,105,116,32,105,115,32,109,111,115,116,32,108,105,107,101,108,121,32,97,32>>,{em,[],[<<118,101,114,121,32,105,110,101,102,102,105,99,105,101,110,116>>]},<<32,119,97,121,32,116,111,32,115,111,108,118,101,32,116,104,101,32,112,114,111,98,108,101,109,46>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2934,25},bounded_fun,[{type,{2934,25},'fun',[{type,{2934,25},product,[{atom,{2934,26},multi_scheduling},{var,{2934,44},'BlockState'}]},{var,{2934,59},'OldBlockState'}]},[{type,{2935,7},constraint,[{atom,{2935,7},is_subtype},[{var,{2935,7},'BlockState'},{type,{2935,21},union,[{atom,{2935,21},block},{atom,{2935,29},unblock},{atom,{2935,39},block_normal},{atom,{2935,54},unblock_normal}]}]]},{type,{2936,7},constraint,[{atom,{2936,7},is_subtype},[{var,{2936,7},'OldBlockState'},{type,{2936,24},union,[{atom,{2936,24},blocked},{atom,{2936,34},disabled},{atom,{2936,45},enabled}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,54,49,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,97,32,108,105,109,105,116,32,111,110,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,111,117,116,115,116,97,110,100,105,110,103,32,114,101,113,117,101,115,116,115,32,109,97,100,101,32,98,121,32,97,32,115,121,115,116,101,109,32,112,114,111,99,101,115,115,32,111,114,99,104,101,115,116,114,97,116,105,110,103,32,115,121,115,116,101,109,32,119,105,100,101,32,99,104,97,110,103,101,115,46,32,67,117,114,114,101,110,116,108,121,32,116,104,101,114,101,32,97,114,101,32,116,119,111,32,115,117,99,104,32,112,114,111,99,101,115,115,101,115,58>>]},{dl,[],[{dt,[],[<<84,104,101,32,67,111,100,101,32,80,117,114,103,101,114>>]},{dd,[],[{p,[],[<<84,104,101,32,99,111,100,101,32,112,117,114,103,101,114,32,111,114,99,104,101,115,116,114,97,116,101,115,32,99,104,101,99,107,105,110,103,32,111,102,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,111,108,100,32,99,111,100,101,32,98,101,102,111,114,101,32,111,108,100,32,99,111,100,101,32,105,115,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,115,121,115,116,101,109,46>>]}]},{dt,[],[<<84,104,101,32,76,105,116,101,114,97,108,32,65,114,101,97,32,67,111,108,108,101,99,116,111,114>>]},{dd,[],[{p,[],[<<84,104,101,32,108,105,116,101,114,97,108,32,97,114,101,97,32,99,111,108,108,101,99,116,111,114,32,111,114,99,104,101,115,116,114,97,116,101,115,32,99,111,112,121,105,110,103,32,111,102,32,114,101,102,101,114,101,110,99,101,115,32,102,114,111,109,32,111,108,100,32,108,105,116,101,114,97,108,32,97,114,101,97,115,32,98,101,102,111,114,101,32,114,101,109,111,118,97,108,32,111,102,32,115,117,99,104,32,97,114,101,97,115,32,102,114,111,109,32,116,104,101,32,115,121,115,116,101,109,46>>]}]}]},{p,[],[<<69,97,99,104,32,111,102,32,116,104,101,115,101,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,97,108,108,111,119,101,100,32,116,111,32,104,97,118,101,32,97,115,32,109,97,110,121,32,111,117,116,115,116,97,110,100,105,110,103,32,114,101,113,117,101,115,116,115,32,97,115,32,116,104,105,115,32,108,105,109,105,116,32,105,115,32,115,101,116,32,116,111,46,32,66,121,32,100,101,102,97,117,108,116,32,116,104,105,115,32,108,105,109,105,116,32,105,115,32,115,101,116,32,116,111,32,116,119,105,99,101,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,99,104,101,100,117,108,101,114,115>>]},<<32,111,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,105,115,32,119,105,108,108,32,101,110,115,117,114,101,32,116,104,97,116,32,115,99,104,101,100,117,108,101,114,115,32,119,105,108,108,32,104,97,118,101,32,101,110,111,117,103,104,32,119,111,114,107,32,115,99,104,101,100,117,108,101,100,32,116,111,32,112,101,114,102,111,114,109,32,116,104,101,115,101,32,111,112,101,114,97,116,105,111,110,115,32,97,115,32,113,117,105,99,107,108,121,32,97,115,32,112,111,115,115,105,98,108,101,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,97,115,32,111,116,104,101,114,32,119,111,114,107,32,119,105,108,108,32,98,101,32,105,110,116,101,114,108,101,97,118,101,100,32,119,105,116,104,32,116,104,105,115,32,119,111,114,107,46,32,67,117,114,114,101,110,116,108,121,32,117,115,101,100,32,108,105,109,105,116,32,99,97,110,32,98,101,32,99,104,101,99,107,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,116,104,101,32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,111,115,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,122,111,115,114,108,32,60,76,105,109,105,116,62>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108>>]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2937,25},bounded_fun,[{type,{2937,25},'fun',[{type,{2937,25},product,[{atom,{2937,26},outstanding_system_requests_limit},{var,{2937,61},'NewLimit'}]},{var,{2938,11},'OldLimit'}]},[{type,{2939,7},constraint,[{atom,{2939,7},is_subtype},[{var,{2939,7},'NewLimit'},{type,{2939,19},range,[{integer,{2939,19},1},{integer,{2939,22},134217727}]}]]},{type,{2940,7},constraint,[{atom,{2940,7},is_subtype},[{var,{2940,7},'OldLimit'},{type,{2940,19},range,[{integer,{2940,19},1},{integer,{2940,22},134217727}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,54,54,54>>,since => <<79,84,80,32,50,52,46,50>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>}],[]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[{em,[],[<<84,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,100,101,112,114,101,99,97,116,101,100,46>>]},<<32,73,110,115,116,101,97,100,32,111,102,32,117,115,105,110,103,32,116,104,105,115,32,97,114,103,117,109,101,110,116,44,32,117,115,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,87,104,101,110,32,116,104,105,115,32,97,114,103,117,109,101,110,116,32,105,115,32,114,101,109,111,118,101,100,44,32,97,32,102,105,110,97,108,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,32,116,121,112,101,32,116,111,32,117,115,101,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,46>>]}]},{p,[],[<<67,111,110,116,114,111,108,115,32,105,102,32,97,110,100,32,104,111,119,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{p,[],[<<87,104,101,110,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101,44,32,72,111,119,41>>]},<<32,105,115,32,99,97,108,108,101,100,44,32,97,110,32,97,115,121,110,99,104,114,111,110,111,117,115,32,115,105,103,110,97,108,32,105,115,32,115,101,110,116,32,116,111,32,97,108,108,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,44,32,99,97,117,115,105,110,103,32,116,104,101,109,32,116,111,32,116,114,121,32,116,111,32,98,105,110,100,32,111,114,32,117,110,98,105,110,100,32,97,115,32,114,101,113,117,101,115,116,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,115,99,104,101,100,117,108,101,114,32,102,97,105,108,115,32,116,111,32,98,105,110,100,44,32,116,104,105,115,32,105,115,32,111,102,116,101,110,32,115,105,108,101,110,116,108,121,32,105,103,110,111,114,101,100,44,32,97,115,32,105,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,112,111,115,115,105,98,108,101,32,116,111,32,118,101,114,105,102,121,32,118,97,108,105,100,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,115,46,32,73,102,32,97,110,32,101,114,114,111,114,32,105,115,32,114,101,112,111,114,116,101,100,44,32,97,110,32,101,114,114,111,114,32,101,118,101,110,116,32,105,115,32,108,111,103,103,101,100,46,32,84,111,32,118,101,114,105,102,121,32,116,104,97,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,104,97,118,101,32,98,111,117,110,100,32,97,115,32,114,101,113,117,101,115,116,101,100,44,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]}]},{p,[],[<<83,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,98,111,117,110,100,32,111,110,32,110,101,119,101,114,32,76,105,110,117,120,44,32,83,111,108,97,114,105,115,44,32,70,114,101,101,66,83,68,44,32,97,110,100,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,115,44,32,98,117,116,32,109,111,114,101,32,115,121,115,116,101,109,115,32,119,105,108,108,32,98,101,32,115,117,112,112,111,114,116,101,100,32,105,110,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,115,46>>]},{p,[],[<<73,110,32,111,114,100,101,114,32,102,111,114,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,111,32,98,101,32,97,98,108,101,32,116,111,32,98,105,110,100,32,115,99,104,101,100,117,108,101,114,115,44,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,109,117,115,116,32,98,101,32,107,110,111,119,110,46,32,73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,102,97,105,108,115,32,116,111,32,100,101,116,101,99,116,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,97,117,116,111,109,97,116,105,99,97,108,108,121,44,32,105,116,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111,119,32,116,111,32,100,101,102,105,110,101,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,111,101,115,32,98,121,32,100,101,102,97,117,108,116,32>>,{em,[],[<<110,111,116>>]},<<32,98,105,110,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,116,104,101,32,111,110,108,121,32,79,83,32,112,114,111,99,101,115,115,32,98,105,110,100,105,110,103,32,116,104,114,101,97,100,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,105,115,32,105,109,112,114,111,118,101,115,32,116,104,101,32,112,101,114,102,111,114,109,97,110,99,101,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,116,104,101,114,32,79,83,32,112,114,111,99,101,115,115,101,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,110,111,116,104,101,114,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,108,115,111,32,98,105,110,100,32,116,104,114,101,97,100,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,101,114,101,32,99,97,110,32,98,101,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,112,101,110,97,108,116,121,32,105,110,115,116,101,97,100,46,32,83,111,109,101,116,105,109,101,115,32,116,104,105,115,32,112,101,114,102,111,114,109,97,110,99,101,32,112,101,110,97,108,116,121,32,99,97,110,32,98,101,32,115,101,118,101,114,101,46,32,73,102,32,115,111,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,110,111,116,32,98,105,110,100,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,46>>]}]},{p,[],[<<83,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,98,111,117,110,100,32,105,110,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,46,32,65,114,103,117,109,101,110,116,32>>,{code,[],[<<72,111,119>>]},<<32,100,101,116,101,114,109,105,110,101,115,32,104,111,119,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,32,97,110,100,32,99,97,110,32,98,101,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<117,110,98,111,117,110,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<116,104,114,101,97,100,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,116,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,110,111,100,101,95,116,104,114,101,97,100,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,110,116,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<110,111,95,110,111,100,101,95,112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,110,110,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<116,104,114,101,97,100,95,110,111,95,110,111,100,101,95,112,114,111,99,101,115,115,111,114,95,115,112,114,101,97,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,116,110,110,112,115>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{dt,[],[{code,[],[<<100,101,102,97,117,108,116,95,98,105,110,100>>]}]},{dd,[],[<<83,97,109,101,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116,32,100,98>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,101,113,117,97,108,115,32>>,{code,[],[<<72,111,119>>]},<<32,98,101,102,111,114,101,32,102,108,97,103,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]},<<32,119,97,115,32,99,104,97,110,103,101,100,46>>]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,116,115,117,112>>]}]},{dd,[],[<<73,102,32,98,105,110,100,105,110,103,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<72,111,119>>]},<<32,105,115,32,110,111,116,32,111,110,101,32,111,102,32,116,104,101,32,100,111,99,117,109,101,110,116,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,117,110,97,118,97,105,108,97,98,108,101,46>>]}]},{p,[],[<<84,104,101,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,32,116,121,112,101,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<44,32,97,115,32,119,101,108,108,32,97,115,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2941,25},bounded_fun,[{type,{2941,25},'fun',[{type,{2941,25},product,[{atom,{2941,26},scheduler_bind_type},{var,{2941,47},'How'}]},{var,{2941,55},'OldBindType'}]},[{type,{2942,7},constraint,[{atom,{2942,7},is_subtype},[{var,{2942,7},'How'},{type,{2942,14},union,[{user_type,{2942,14},scheduler_bind_type,[]},{atom,{2942,38},default_bind}]}]]},{type,{2943,7},constraint,[{atom,{2943,7},is_subtype},[{var,{2943,7},'OldBindType'},{user_type,{2943,22},scheduler_bind_type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,55,49,48>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<84,114,121,32,101,110,97,98,108,101,32,111,114,32,100,105,115,97,98,108,101,32,115,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,32,98,121,32,112,97,115,115,105,110,103,32>>,{code,[],[<<66,111,111,108,101,97,110>>]},<<32,97,115,32,101,105,116,104,101,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,111,114,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,104,111,119,32,116,111,32,117,115,101,32,115,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,97,116,105,115,116,105,99,115,95,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,116,105,115,116,105,99,115,40,115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101,41>>]}]},<<46>>]},{p,[],[<<83,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,32,104,97,115,32,97,32,110,111,100,101,32,103,108,111,98,97,108,32,115,116,97,116,101,46,32,73,116,32,105,115,32,101,105,116,104,101,114,32,101,110,97,98,108,101,100,32,102,111,114,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,111,110,32,116,104,101,32,110,111,100,101,32,111,114,32,100,105,115,97,98,108,101,100,32,102,111,114,32,97,108,108,32,112,114,111,99,101,115,115,101,115,46,32,69,97,99,104,32,112,114,111,99,101,115,115,32,104,97,115,32,97,32,108,111,103,105,99,97,108,32,99,111,117,110,116,101,114,32,105,110,105,116,105,97,108,105,122,101,100,32,97,115,32,122,101,114,111,46,32,65,32,99,97,108,108,32,119,105,116,104,32>>,{code,[],[<<66,111,111,108,101,97,110>>]},<<32,97,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,119,105,108,108,32,105,110,99,114,101,97,115,101,32,116,104,97,116,32,99,111,117,110,116,101,114,32,111,110,101,32,115,116,101,112,32,102,111,114,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,65,32,99,97,108,108,32,119,105,116,104,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,119,105,108,108,32,100,101,99,114,101,97,115,101,32,105,116,32,111,110,101,32,115,116,101,112,32,117,110,108,101,115,115,32,105,116,32,97,108,114,101,97,100,121,32,105,115,32,122,101,114,111,46,32,84,104,101,32,110,111,100,101,32,103,108,111,98,97,108,32,115,116,97,116,101,32,102,111,114,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,119,105,108,108,32,98,101,32,101,110,97,98,108,101,100,32,97,115,32,108,111,110,103,32,97,115,32,116,104,101,114,101,32,105,115,32,97,116,32,108,101,97,115,116,32,111,110,101,32,112,114,111,99,101,115,115,32,97,108,105,118,101,32,119,105,116,104,32,97,32,99,111,117,110,116,101,114,32,118,97,108,117,101,32,108,97,114,103,101,114,32,116,104,97,110,32,122,101,114,111,46,32,87,104,101,110,32,97,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,44,32,105,116,115,32,99,111,117,110,116,101,114,32,119,105,108,108,32,97,108,115,111,32,100,105,115,97,112,112,101,97,114,46,32,84,111,32,101,110,115,117,114,101,32>>,{code,[],[<<115,99,104,101,100,117,108,101,114,95,119,97,108,108,95,116,105,109,101>>]},<<32,105,115,32,107,101,112,116,32,101,110,97,98,108,101,100,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,101,110,97,98,108,101,100,32,105,116,32,109,117,115,116,32,116,104,101,114,101,102,111,114,101,32,98,101,32,107,101,112,116,32,97,108,105,118,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,110,111,100,101,32,103,108,111,98,97,108,32,115,116,97,116,101,44,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,115,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,32,119,101,114,101,32,101,110,97,98,108,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,105,116,32,119,101,114,101,32,100,105,115,97,98,108,101,100,46>>]},{p,[],[<<83,99,104,101,100,117,108,101,114,32,119,97,108,108,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,32,100,111,32,99,111,110,115,117,109,101,32,115,111,109,101,32,99,112,117,32,111,118,101,114,104,101,97,100,32,97,110,100,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,102,116,32,116,117,114,110,101,100,32,111,110,32,117,110,108,101,115,115,32,117,115,101,100,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2944,25},bounded_fun,[{type,{2944,25},'fun',[{type,{2944,25},product,[{atom,{2944,26},scheduler_wall_time},{var,{2944,47},'Boolean'}]},{var,{2944,60},'OldBoolean'}]},[{type,{2945,7},constraint,[{atom,{2945,7},is_subtype},[{var,{2945,7},'Boolean'},{type,{2945,18},boolean,[]}]]},{type,{2946,7},constraint,[{atom,{2946,7},is_subtype},[{var,{2946,7},'OldBoolean'},{type,{2946,21},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,56,51,55>>,since => <<79,84,80,32,82,49,53,66,48,49>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,82,97,110,103,101,32,105,115,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{p,[],[<<73,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,98,117,105,108,116,32,119,105,116,104,32,115,117,112,112,111,114,116,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115>>]},<<44,32,99,104,97,110,103,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,97,108,115,111,32,99,104,97,110,103,101,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,49,50,32,115,99,104,101,100,117,108,101,114,115,32,97,110,100,32,54,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,111,110,108,105,110,101,44,32,97,110,100,32>>,{code,[],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>]},<<32,105,115,32,117,115,101,100,32,116,111,32,115,101,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,116,111,32,54,44,32,116,104,101,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,99,114,101,97,115,101,100,32,98,121,32,104,97,108,102,32,97,115,32,119,101,108,108,44,32,100,111,119,110,32,116,111,32,51,46,32,83,105,109,105,108,97,114,108,121,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,105,110,99,114,101,97,115,101,115,32,112,114,111,112,111,114,116,105,111,110,97,108,108,121,32,116,111,32,105,110,99,114,101,97,115,101,115,32,105,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2947,25},bounded_fun,[{type,{2947,25},'fun',[{type,{2947,25},product,[{atom,{2947,26},schedulers_online},{var,{2947,45},'SchedulersOnline'}]},{var,{2948,33},'OldSchedulersOnline'}]},[{type,{2949,7},constraint,[{atom,{2949,7},is_subtype},[{var,{2949,7},'SchedulersOnline'},{type,{2949,27},pos_integer,[]}]]},{type,{2950,7},constraint,[{atom,{2950,7},is_subtype},[{var,{2950,7},'OldSchedulersOnline'},{type,{2950,30},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,56,55,54>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,119,105,108,108,32,114,101,99,101,105,118,101,32,116,104,101,32,108,111,103,103,105,110,103,32,109,101,115,115,97,103,101,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,69,82,84,83,46,32,73,102,32,115,101,116,32,116,111,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,97,108,108,32,108,111,103,103,105,110,103,32,109,101,115,115,97,103,101,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,69,82,84,83,32,119,105,108,108,32,98,101,32,100,114,111,112,112,101,100,46,32,84,104,101,32,109,101,115,115,97,103,101,115,32,119,105,108,108,32,98,101,32,105,110,32,116,104,101,32,102,111,114,109,97,116,58>>]},{pre,[],[{code,[],[<<123,108,111,103,44,76,101,118,101,108,44,70,111,114,109,97,116,44,65,114,103,76,105,115,116,44,77,101,116,97,100,97,116,97,125,32,119,104,101,114,101,10,10,76,101,118,101,108,32,61,32,97,116,111,109,40,41,44,10,70,111,114,109,97,116,32,61,32,115,116,114,105,110,103,40,41,44,10,65,114,103,76,105,115,116,32,61,32,108,105,115,116,40,116,101,114,109,40,41,41,44,10,77,101,116,97,100,97,116,97,32,61,32,35,123,32,112,105,100,32,61,62,32,112,105,100,40,41,44,10,32,32,32,103,114,111,117,112,95,108,101,97,100,101,114,32,61,62,32,112,105,100,40,41,44,10,32,32,32,116,105,109,101,32,58,61,32,108,111,103,103,101,114,58,116,105,109,101,115,116,97,109,112,40,41,44,10,32,32,32,101,114,114,111,114,95,108,111,103,103,101,114,32,58,61,32,35,123,32,101,109,117,108,97,116,111,114,32,58,61,32,116,114,117,101,44,32,116,97,103,32,58,61,32,97,116,111,109,40,41,32,125,10,32,32,32,32,32,32,32,32>>]}]},{p,[],[<<73,102,32,116,104,101,32>>,{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]},<<32,112,114,111,99,101,115,115,32,100,105,101,115,44,32,116,104,105,115,32,102,108,97,103,32,119,105,108,108,32,98,101,32,114,101,115,101,116,32,116,111,32>>,{code,[],[<<108,111,103,103,101,114>>]},<<46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,110,97,109,101,100,32>>,{code,[],[<<108,111,103,103,101,114>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,115,105,103,110,101,100,32,116,111,32,98,101,32,117,115,101,100,32,98,121,32,116,104,101,32,75,69,82,78,69,76,32>>,{a,[{href,<<107,101,114,110,101,108,58,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,103,101,114>>]}]},<<46,32,66,101,32,99,97,114,101,102,117,108,32,105,102,32,121,111,117,32,99,104,97,110,103,101,32,105,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,97,115,32,108,111,103,32,109,101,115,115,97,103,101,115,32,109,97,121,32,98,101,32,108,111,115,116,46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,105,110,116,101,114,99,101,112,116,32,101,109,117,108,97,116,111,114,32,108,111,103,32,109,101,115,115,97,103,101,115,44,32,100,111,32,105,116,32,98,121,32,97,100,100,105,110,103,32,97,32,115,112,101,99,105,97,108,105,122,101,100,32,104,97,110,100,108,101,114,32,116,111,32,116,104,101,32,75,69,82,78,69,76,32,108,111,103,103,101,114,46>>]}]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2951,25},bounded_fun,[{type,{2951,25},'fun',[{type,{2951,25},product,[{atom,{2951,26},system_logger},{var,{2951,41},'Logger'}]},{var,{2951,52},'PrevLogger'}]},[{type,{2952,7},constraint,[{atom,{2952,7},is_subtype},[{var,{2952,7},'Logger'},{type,{2952,17},union,[{atom,{2952,17},logger},{atom,{2952,26},undefined},{type,{2952,38},pid,[]}]}]]},{type,{2953,7},constraint,[{atom,{2953,7},is_subtype},[{var,{2953,7},'PrevLogger'},{type,{2953,21},union,[{atom,{2953,21},logger},{atom,{2953,30},undefined},{type,{2953,42},pid,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,57,48,53>>,since => <<79,84,80,32,50,49,46,51>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,110,111,100,101,32,116,114,97,99,101,32,99,111,110,116,114,111,108,32,119,111,114,100,32,116,111,32>>,{code,[],[<<84,67,87>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,111,32,98,101,32,97,110,32,117,110,115,105,103,110,101,100,32,105,110,116,101,103,101,114,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99,35,115,101,116,95,116,99,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<115,101,116,95,116,99,119>>]}]},<<32,105,110,32,115,101,99,116,105,111,110,32,34,77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103,34,32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,108,97,103,46>>]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2954,25},bounded_fun,[{type,{2954,25},'fun',[{type,{2954,25},product,[{atom,{2954,26},trace_control_word},{var,{2954,46},'TCW'}]},{var,{2954,54},'OldTCW'}]},[{type,{2955,7},constraint,[{atom,{2955,7},is_subtype},[{var,{2955,7},'TCW'},{type,{2955,14},non_neg_integer,[]}]]},{type,{2956,7},constraint,[{atom,{2956,7},is_subtype},[{var,{2956,7},'OldTCW'},{type,{2956,17},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,57,51,55>>}},{{function,system_flag,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2904}],[<<115,121,115,116,101,109,95,102,108,97,103,47,50>>],#{<<101,110>> => [{p,[],[<<70,105,110,97,108,105,122,101,115,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<116,105,109,101,32,111,102,102,115,101,116>>]},<<32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46,32,73,102,32,97,110,111,116,104,101,114,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101,32,105,115,32,117,115,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,115,116,97,116,101,32,105,115,32,108,101,102,116,32,117,110,99,104,97,110,103,101,100,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,111,108,100,32,115,116,97,116,101,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,97,116,32,105,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<112,114,101,108,105,109,105,110,97,114,121>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,102,105,110,97,108,105,122,97,116,105,111,110,32,119,97,115,32,112,101,114,102,111,114,109,101,100,32,97,110,100,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,110,111,119,32,102,105,110,97,108,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<102,105,110,97,108>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,119,97,115,32,97,108,114,101,97,100,121,32,105,110,32,116,104,101,32,102,105,110,97,108,32,115,116,97,116,101,46,32,84,104,105,115,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,116,105,109,101,95,111,102,102,115,101,116,44,32,102,105,110,97,108,105,122,101,41>>]},<<32,99,97,108,108,32,111,114,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[<<73,102,32>>,{code,[],[<<118,111,108,97,116,105,108,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,99,97,110,110,111,116,32,98,101,32,102,105,110,97,108,105,122,101,100,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]}]},#{signature => [{attribute,{2904,2},spec,{{erlang,system_flag,2},[{type,{2957,4},bounded_fun,[{type,{2957,4},'fun',[{type,{2957,4},product,[{atom,{2957,5},time_offset},{atom,{2957,18},finalize}]},{var,{2957,31},'OldState'}]},[{type,{2958,7},constraint,[{atom,{2958,7},is_subtype},[{var,{2958,7},'OldState'},{type,{2958,19},union,[{atom,{2958,19},preliminary},{atom,{2958,33},final},{atom,{2958,41},volatile}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,57,53,49>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,46,32,84,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,98,114,111,107,101,110,32,105,110,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,105,110,32,111,114,100,101,114,32,116,111,32,109,97,107,101,32,105,116,32,101,97,115,105,101,114,32,116,111,32,110,97,118,105,103,97,116,101,46>>]},{dl,[],[{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<77,101,109,111,114,121,32,65,108,108,111,99,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,111,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<67,80,85,32,84,111,112,111,108,111,103,121>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,113,117,111,116,97>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<80,114,111,99,101,115,115,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,115,105,122,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,101,97,112,95,115,105,122,101,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<104,101,97,112,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,115>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,105,109,105,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,76,105,109,105,116,115>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,116,111,109,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,116,111,109,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,116,115,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,116,115,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,99,111,117,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,99,111,117,110,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,108,105,109,105,116>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,84,105,109,101>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,110,100,95,116,105,109,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,116,97,114,116,95,116,105,109,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,119,97,114,112,95,109,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,119,97,114,112,95,109,111,100,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,99,104,101,100,117,108,101,114,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,95,105,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,99,104,101,100,117,108,101,114,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,109,112,95,115,117,112,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,109,112,95,115,117,112,112,111,114,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,104,114,101,97,100,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<68,105,115,116,114,105,98,117,116,105,111,110,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,114,101,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,114,101,97,116,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,99,116,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,115,116,95,99,116,114,108>>]}]}]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,105,115,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<83,121,115,116,101,109,32,73,110,102,111,114,109,97,116,105,111,110>>]}]}]},{dd,[],[{p,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,104,101,99,107,95,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,104,101,99,107,95,105,111>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,111,109,112,97,116,95,114,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,111,109,112,97,116,95,114,101,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,101,98,117,103,95,99,111,109,112,105,108,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,98,117,103,95,99,111,109,112,105,108,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,114,105,118,101,114,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,114,105,118,101,114,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,102,108,97,118,111,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,109,117,95,102,108,97,118,111,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,109,117,95,116,121,112,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,105,110,102,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,102,111>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,107,101,114,110,101,108,95,112,111,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<107,101,114,110,101,108,95,112,111,108,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,97,100,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,111,97,100,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,97,99,104,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,99,104,105,110,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,105,102,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,105,102,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,116,112,95,114,101,108,101,97,115,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,108,111,103,103,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,121,115,116,101,109,95,118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<118,101,114,115,105,111,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,119,111,114,100,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<119,111,114,100,115,105,122,101>>]}]}]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3180,10},'fun',[{type,{3180,10},product,[{atom,{3180,11},sequential_tracer}]},{type,{3180,33},tuple,[{atom,{3180,34},sequential_tracer},{type,{3180,53},union,[{type,{3180,53},pid,[]},{type,{3180,61},port,[]},{type,{3180,70},tuple,[{type,{3180,71},module,[]},{type,{3180,80},term,[]}]},{atom,{3180,90},false}]}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,57,57,56,49>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,111,114,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>}],[]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>}],[]},{code,[],[<<97,108,108,111,99,97,116,101,100,95,97,114,101,97,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32,119,105,116,104,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,97,114,101,97,115,46>>]},{p,[],[<<69,97,99,104,32,116,117,112,108,101,32,99,111,110,116,97,105,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,116,121,112,101,32,111,102,32,109,101,109,111,114,121,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,97,110,100,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,97,108,108,111,99,97,116,101,100,32,109,101,109,111,114,121,32,105,110,32,98,121,116,101,115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,87,104,101,110,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,108,108,111,99,97,116,101,100,32,97,110,100,32,117,115,101,100,32,109,101,109,111,114,121,32,105,115,32,112,114,101,115,101,110,116,44,32,97,108,115,111,32,97,32,116,104,105,114,100,32,101,108,101,109,101,110,116,32,105,115,32,112,114,101,115,101,110,116,44,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,117,115,101,100,32,109,101,109,111,114,121,32,105,110,32,98,121,116,101,115,46>>]},{p,[],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,97,108,108,111,99,97,116,101,100,95,97,114,101,97,115,41>>]},<<32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,44,32,97,110,100,32,116,104,101,32,99,111,110,116,101,110,116,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,46,32,84,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,115,32,116,104,101,114,101,102,111,114,101,32,99,104,97,110,103,101,115,32,119,104,101,110,32,110,101,101,100,101,100,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,115,101,32,118,97,108,117,101,115,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,111,109,101,32,118,97,108,117,101,115,32,97,114,101,32,112,97,114,116,32,111,102,32,111,116,104,101,114,32,118,97,108,117,101,115,44,32,97,110,100,32,115,111,109,101,32,109,101,109,111,114,121,32,97,114,101,97,115,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,115,117,108,116,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,116,111,116,97,108,32,97,109,111,117,110,116,32,111,102,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,101,109,111,114,121,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,101,109,111,114,121,47,48,44,49>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114>>}],[]},{code,[],[<<97,108,108,111,99,97,116,111,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,65,108,108,111,99,97,116,111,114,44,32,86,101,114,115,105,111,110,44,32,70,101,97,116,117,114,101,115,44,32,83,101,116,116,105,110,103,115>>]},<<44,32,119,104,101,114,101,58>>]},{ul,[],[{li,[],[{p,[],[{code,[],[<<65,108,108,111,99,97,116,111,114>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99,97,116,111,114>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,32,99,97,110,110,111,116,32,98,101,32,105,100,101,110,116,105,102,105,101,100,46,32>>,{code,[],[<<103,108,105,98,99>>]},<<32,99,97,110,32,98,101,32,105,100,101,110,116,105,102,105,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<86,101,114,115,105,111,110>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,40,98,117,116,32,110,111,116,32,97,32,115,116,114,105,110,103,41,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<109,97,108,108,111,99,40,41>>]},<<32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<70,101,97,116,117,114,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,97,116,111,109,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,116,104,101,32,97,108,108,111,99,97,116,105,111,110,32,102,101,97,116,117,114,101,115,32,117,115,101,100,46>>]}]},{li,[],[{p,[],[{code,[],[<<83,101,116,116,105,110,103,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,115,117,98,115,121,115,116,101,109,115,44,32,116,104,101,105,114,32,99,111,110,102,105,103,117,114,97,98,108,101,32,112,97,114,97,109,101,116,101,114,115,44,32,97,110,100,32,117,115,101,100,32,118,97,108,117,101,115,46,32,83,101,116,116,105,110,103,115,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,100,105,102,102,101,114,101,110,116,32,99,111,109,98,105,110,97,116,105,111,110,115,32,111,102,32,112,108,97,116,102,111,114,109,115,44,32,97,108,108,111,99,97,116,111,114,115,44,32,97,110,100,32,97,108,108,111,99,97,116,105,111,110,32,102,101,97,116,117,114,101,115,46,32,77,101,109,111,114,121,32,115,105,122,101,115,32,97,114,101,32,103,105,118,101,110,32,105,110,32,98,121,116,101,115,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32,34,83,121,115,116,101,109,32,70,108,97,103,115,32,69,102,102,101,99,116,105,110,103,32,101,114,116,115,95,97,108,108,111,99,34,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,102,108,97,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,117,112,108,101>>}],[]},{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,108,108,111,99,97,116,111,114,46,32,65,115,32,102,114,111,109,32,69,82,84,83,32,53,46,54,46,49,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<123,105,110,115,116,97,110,99,101,44,32,73,110,115,116,97,110,99,101,78,111,44,32,73,110,115,116,97,110,99,101,73,110,102,111,125>>]},<<32,116,117,112,108,101,115,44,32,119,104,101,114,101,32>>,{code,[],[<<73,110,115,116,97,110,99,101,73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,115,112,101,99,105,102,105,99,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,97,108,108,111,99,97,116,111,114,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,99,111,103,110,105,122,101,100,32,97,108,108,111,99,97,116,111,114,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,73,102,32>>,{code,[],[<<65,108,108,111,99>>]},<<32,105,115,32,100,105,115,97,98,108,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,105,115,32,104,105,103,104,108,121,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,100,101,112,101,110,100,101,110,116,32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46,32,73,116,32,119,97,115,32,105,110,105,116,105,97,108,108,121,32,105,110,116,101,110,100,101,100,32,97,115,32,97,32,116,111,111,108,32,119,104,101,110,32,100,101,118,101,108,111,112,105,110,103,32,110,101,119,32,97,108,108,111,99,97,116,111,114,115,44,32,98,117,116,32,97,115,32,105,116,32,99,97,110,32,98,101,32,111,102,32,105,110,116,101,114,101,115,116,32,102,111,114,32,111,116,104,101,114,115,32,105,116,32,104,97,115,32,98,101,101,110,32,98,114,105,101,102,108,121,32,100,111,99,117,109,101,110,116,101,100,46>>]},{p,[],[<<84,104,101,32,114,101,99,111,103,110,105,122,101,100,32,97,108,108,111,99,97,116,111,114,115,32,97,114,101,32,108,105,115,116,101,100,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]}]},<<46,32,73,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,117,112,101,114,32,99,97,114,114,105,101,114,115,32,99,97,110,32,98,101,32,111,98,116,97,105,110,101,100,32,102,114,111,109,32,69,82,84,83,32,56,46,48,32,119,105,116,104,32>>,{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,101,114,116,115,95,109,109,97,112,125>>]},<<32,111,114,32,102,114,111,109,32,69,82,84,83,32,53,46,49,48,46,52,59,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,119,104,101,110,32,99,97,108,108,105,110,103,32,119,105,116,104,32>>,{code,[],[<<123,97,108,108,111,99,97,116,111,114,44,32,109,115,101,103,95,97,108,108,111,99,125>>]},<<32,97,108,115,111,32,105,110,99,108,117,100,101,115,32,97,110,32>>,{code,[],[<<123,101,114,116,115,95,109,109,97,112,44,32,95,125>>]},<<32,116,117,112,108,101,32,97,115,32,111,110,101,32,101,108,101,109,101,110,116,32,105,110,32,116,104,101,32,108,105,115,116,46>>]},{p,[],[<<65,102,116,101,114,32,114,101,97,100,105,110,103,32,116,104,101,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]},<<32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,109,111,114,101,32,111,114,32,108,101,115,115,32,115,112,101,97,107,115,32,102,111,114,32,105,116,115,101,108,102,44,32,98,117,116,32,105,116,32,99,97,110,32,98,101,32,119,111,114,116,104,32,101,120,112,108,97,105,110,105,110,103,32,115,111,109,101,32,116,104,105,110,103,115,46,32,67,97,108,108,32,99,111,117,110,116,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,119,111,32,118,97,108,117,101,115,44,32,116,104,101,32,102,105,114,115,116,32,118,97,108,117,101,32,105,115,32,103,105,103,97,32,99,97,108,108,115,44,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,118,97,108,117,101,32,105,115,32,99,97,108,108,115,46,32>>,{code,[],[<<109,98,99,115>>]},<<32,97,110,100,32>>,{code,[],[<<115,98,99,115>>]},<<32,100,101,110,111,116,101,32,109,117,108,116,105,45,98,108,111,99,107,32,99,97,114,114,105,101,114,115,44,32,97,110,100,32,115,105,110,103,108,101,45,98,108,111,99,107,32,99,97,114,114,105,101,114,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,83,105,122,101,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,105,110,32,98,121,116,101,115,46,32,87,104,101,110,32,97,32,115,105,122,101,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,101,100,44,32,105,116,32,105,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,115,111,109,101,116,104,105,110,103,46,32,83,105,122,101,115,32,97,110,100,32,97,109,111,117,110,116,115,32,97,114,101,32,111,102,116,101,110,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,114,101,101,32,118,97,108,117,101,115,58>>]},{ul,[],[{li,[],[<<84,104,101,32,102,105,114,115,116,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,118,97,108,117,101,46>>]},{li,[],[<<84,104,101,32,115,101,99,111,110,100,32,105,115,32,116,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125,41>>]},<<46>>]},{li,[],[<<84,104,101,32,116,104,105,114,100,32,105,115,32,116,104,101,32,109,97,120,105,109,117,109,32,118,97,108,117,101,32,115,105,110,99,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,119,97,115,32,115,116,97,114,116,101,100,46>>]}]},{p,[],[<<73,102,32,111,110,108,121,32,111,110,101,32,118,97,108,117,101,32,105,115,32,112,114,101,115,101,110,116,44,32,105,116,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,118,97,108,117,101,46,32>>,{code,[],[<<102,105,120,95,97,108,108,111,99>>]},<<32,109,101,109,111,114,121,32,98,108,111,99,107,32,116,121,112,101,115,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,98,121,32,116,119,111,32,118,97,108,117,101,115,46,32,84,104,101,32,102,105,114,115,116,32,118,97,108,117,101,32,105,115,32,116,104,101,32,109,101,109,111,114,121,32,112,111,111,108,32,115,105,122,101,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,118,97,108,117,101,32,105,115,32,116,104,101,32,117,115,101,100,32,109,101,109,111,114,121,32,115,105,122,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>}],[]},{code,[],[<<97,108,108,111,99,95,117,116,105,108,95,97,108,108,111,99,97,116,111,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,97,108,108,111,99,97,116,111,114,115,32,117,115,105,110,103,32,116,104,101,32,69,82,84,83,32,105,110,116,101,114,110,97,108,32>>,{code,[],[<<97,108,108,111,99,95,117,116,105,108>>]},<<32,102,114,97,109,101,119,111,114,107,32,97,115,32,97,116,111,109,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,101,114,116,115,95,97,108,108,111,99,35,97,108,108,111,99,95,117,116,105,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<84,104,101,32,97,108,108,111,99,95,117,116,105,108,32,102,114,97,109,101,119,111,114,107>>]},<<32,105,110,32>>,{code,[],[<<101,114,116,115,95,97,108,108,111,99,40,51,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115>>}],[]},{code,[],[<<123,97,108,108,111,99,97,116,111,114,95,115,105,122,101,115,44,32,65,108,108,111,99,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,115,105,122,101,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,108,108,111,99,97,116,111,114,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,97,108,108,111,99,97,116,111,114,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,123,97,108,108,111,99,97,116,111,114,44,32,65,108,108,111,99,125,41>>]}]},<<46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3075,10},'fun',[{type,{3075,10},product,[{atom,{3075,11},allocated_areas}]},{type,{3075,31},list,[{type,{3075,33},tuple,any}]}]},{type,{3076,10},bounded_fun,[{type,{3076,10},'fun',[{type,{3076,10},product,[{atom,{3076,11},allocator}]},{type,{3077,18},tuple,[{var,{3077,19},'Allocator'},{var,{3077,30},'Version'},{var,{3077,39},'Features'},{var,{3077,49},'Settings'}]}]},[{type,{3078,7},constraint,[{atom,{3078,7},is_subtype},[{var,{3078,7},'Allocator'},{type,{3078,20},union,[{atom,{3078,20},undefined},{atom,{3078,32},glibc}]}]]},{type,{3079,7},constraint,[{atom,{3079,7},is_subtype},[{var,{3079,7},'Version'},{type,{3079,18},list,[{type,{3079,19},non_neg_integer,[]}]}]]},{type,{3080,7},constraint,[{atom,{3080,7},is_subtype},[{var,{3080,7},'Features'},{type,{3080,19},list,[{type,{3080,20},atom,[]}]}]]},{type,{3081,7},constraint,[{atom,{3081,7},is_subtype},[{var,{3081,7},'Settings'},{type,{3081,19},list,[{type,{3081,20},tuple,[{ann_type,{3081,21},[{var,{3081,21},'Subsystem'},{type,{3081,34},atom,[]}]},{type,{3082,21},list,[{type,{3082,22},tuple,[{ann_type,{3082,23},[{var,{3082,23},'Parameter'},{type,{3082,36},atom,[]}]},{ann_type,{3083,23},[{var,{3083,23},'Value'},{type,{3083,32},term,[]}]}]}]}]}]}]]}]]},{type,{3084,10},bounded_fun,[{type,{3084,10},'fun',[{type,{3084,10},product,[{type,{3084,11},tuple,[{atom,{3084,12},allocator},{var,{3084,23},'Alloc'}]}]},{type,{3084,34},list,[{var,{3084,35},'_'}]}]},[{type,{3085,7},constraint,[{atom,{3085,7},is_subtype},[{var,{3085,7},'Alloc'},{type,{3085,16},atom,[]}]]}]]},{type,{3086,10},bounded_fun,[{type,{3086,10},'fun',[{type,{3086,10},product,[{atom,{3086,11},alloc_util_allocators}]},{type,{3086,37},list,[{var,{3086,38},'Alloc'}]}]},[{type,{3087,7},constraint,[{atom,{3087,7},is_subtype},[{var,{3087,7},'Alloc'},{type,{3087,16},atom,[]}]]}]]},{type,{3088,10},bounded_fun,[{type,{3088,10},'fun',[{type,{3088,10},product,[{type,{3088,11},tuple,[{atom,{3088,12},allocator_sizes},{var,{3088,29},'Alloc'}]}]},{type,{3088,40},list,[{var,{3088,41},'_'}]}]},[{type,{3089,7},constraint,[{atom,{3089,7},is_subtype},[{var,{3089,7},'Alloc'},{type,{3089,16},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,49,49,55>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{li,[{name,<<99,112,117,95,116,111,112,111,108,111,103,121>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,108,108,32>>,{code,[],[<<76,101,118,101,108,69,110,116,114,121>>]},<<115,32,111,102,32,97,32,108,105,115,116,32,109,117,115,116,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32>>,{code,[],[<<76,101,118,101,108,84,97,103>>]},<<44,32,101,120,99,101,112,116,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,119,104,101,114,101,32,98,111,116,104,32>>,{code,[],[<<110,111,100,101>>]},<<32,97,110,100,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},{code,[],[<<76,101,118,101,108,84,97,103>>]},<<115,32,99,97,110,32,99,111,101,120,105,115,116,46>>]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>}],[]},{li,[{name,<<105,110,102,111,95,108,105,115,116>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<84,104,101,32>>,{code,[],[<<105,110,102,111,95,108,105,115,116,40,41>>]},<<32,99,97,110,32,98,101,32,101,120,116,101,110,100,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>}],[]},{li,[{name,<<108,101,118,101,108,95,101,110,116,114,121>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[{code,[],[<<123,76,101,118,101,108,84,97,103,44,32,83,117,98,76,101,118,101,108,125,32,61,61,32,123,76,101,118,101,108,84,97,103,44,32,91,93,44,32,83,117,98,76,101,118,101,108,125>>]}]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>}],[]},{li,[{name,<<108,101,118,101,108,95,116,97,103>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<77,111,114,101,32>>,{code,[],[<<76,101,118,101,108,84,97,103>>]},<<115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]},{li,[{name,<<115,117,98,95,108,101,118,101,108>>}],[]}]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>}],[]},{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,98,105,110,100,105,110,103,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,117,115,101,100,32,105,115,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,102,105,110,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,115,101,114,45,100,101,102,105,110,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<44,32,105,102,32,115,117,99,104,32,101,120,105,115,116,115,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<44,32,105,102,32,115,117,99,104,32,101,120,105,115,116,115,46,32,73,102,32,110,111,32,67,80,85,32,116,111,112,111,108,111,103,121,32,101,120,105,115,116,115,44,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[{code,[],[<<110,111,100,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,78,111,110,45,85,110,105,102,111,114,109,32,77,101,109,111,114,121,32,65,99,99,101,115,115,32,40,78,85,77,65,41,32,110,111,100,101,115,46,32>>,{code,[],[<<116,104,114,101,97,100>>]},<<32,114,101,102,101,114,115,32,116,111,32,104,97,114,100,119,97,114,101,32,116,104,114,101,97,100,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,73,110,116,101,108,32,104,121,112,101,114,45,116,104,114,101,97,100,115,41,46>>]},{p,[],[<<65,32,108,101,118,101,108,32,105,110,32,116,101,114,109,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,99,97,110,32,98,101,32,111,109,105,116,116,101,100,32,105,102,32,111,110,108,121,32,111,110,101,32,101,110,116,114,121,32,101,120,105,115,116,115,32,97,110,100,32>>,{code,[],[<<73,110,102,111,76,105,115,116>>]},<<32,105,115,32,101,109,112,116,121,46>>]},{p,[],[{code,[],[<<116,104,114,101,97,100>>]},<<32,99,97,110,32,111,110,108,121,32,98,101,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<99,111,114,101>>]},<<46,32>>,{code,[],[<<99,111,114,101>>]},<<32,99,97,110,32,98,101,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<32,111,114,32>>,{code,[],[<<110,111,100,101>>]},<<46,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<32,99,97,110,32,98,101,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,111,114,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<110,111,100,101>>]},<<46,32>>,{code,[],[<<110,111,100,101>>]},<<32,99,97,110,32,98,101,32,111,110,32,116,104,101,32,116,111,112,32,108,101,118,101,108,32,111,114,32,97,32,115,117,98,108,101,118,101,108,32,116,111,32>>,{code,[],[<<112,114,111,99,101,115,115,111,114>>]},<<46,32,84,104,97,116,32,105,115,44,32,78,85,77,65,32,110,111,100,101,115,32,99,97,110,32,98,101,32,112,114,111,99,101,115,115,111,114,32,105,110,116,101,114,110,97,108,32,111,114,32,112,114,111,99,101,115,115,111,114,32,101,120,116,101,114,110,97,108,46,32,65,32,67,80,85,32,116,111,112,111,108,111,103,121,32,99,97,110,32,99,111,110,115,105,115,116,32,111,102,32,97,32,109,105,120,32,111,102,32,112,114,111,99,101,115,115,111,114,32,105,110,116,101,114,110,97,108,32,97,110,100,32,101,120,116,101,114,110,97,108,32,78,85,77,65,32,110,111,100,101,115,44,32,97,115,32,108,111,110,103,32,97,115,32,101,97,99,104,32,108,111,103,105,99,97,108,32,67,80,85,32,98,101,108,111,110,103,115,32,116,111,32>>,{em,[],[<<111,110,101>>]},<<32,78,85,77,65,32,110,111,100,101,46,32,67,97,99,104,101,32,104,105,101,114,97,114,99,104,121,32,105,115,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,116,121,112,101,44,32,98,117,116,32,119,105,108,108,32,98,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,79,116,104,101,114,32,116,104,105,110,103,115,32,99,97,110,32,97,108,115,111,32,109,97,107,101,32,105,116,32,105,110,116,111,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,83,111,44,32,101,120,112,101,99,116,32,116,104,101,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,116,121,112,101,32,116,111,32,99,104,97,110,103,101,46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,100,101,102,105,110,101,100,125>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,102,105,110,101,100>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,117,115,101,114,45,100,101,102,105,110,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,99,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,100,101,116,101,99,116,101,100,125>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,100,101,116,101,99,116,101,100,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121,121>>]},<<46,32,84,104,101,32,101,109,117,108,97,116,111,114,32,100,101,116,101,99,116,115,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,111,110,32,115,111,109,101,32,110,101,119,101,114,32,76,105,110,117,120,44,32,83,111,108,97,114,105,115,44,32,70,114,101,101,66,83,68,44,32,97,110,100,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,115,46,32,79,110,32,87,105,110,100,111,119,115,32,115,121,115,116,101,109,32,119,105,116,104,32,109,111,114,101,32,116,104,97,110,32,51,50,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,44,32,116,104,101,32,67,80,85,32,116,111,112,111,108,111,103,121,32,105,115,32,110,111,116,32,100,101,116,101,99,116,101,100,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,99,112,117,95,116,111,112,111,108,111,103,121,44,32,117,115,101,100,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<67,112,117,84,111,112,111,108,111,103,121>>]},<<32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,112,117,95,116,111,112,111,108,111,103,121>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,99,111,110,102,105,103,117,114,101,100,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,116,104,101,32,99,111,110,102,105,103,117,114,101,100,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,116,104,101,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,97,118,97,105,108,97,98,108,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,105,115,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,32,111,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,101,105,116,104,101,114,32,97,110,32,105,110,116,101,103,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,111,110,108,105,110,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,99,111,110,102,105,103,117,114,101,100>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,113,117,111,116,97>>}],[]},{code,[],[<<99,112,117,95,113,117,111,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,116,101,99,116,101,100,32,67,80,85,32,113,117,111,116,97,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,108,105,109,105,116,101,100,32,98,121,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,115,97,121,105,110,103,32,104,111,119,32,109,97,110,121,32,112,114,111,99,101,115,115,111,114,115,39,32,119,111,114,116,104,32,111,102,32,114,117,110,116,105,109,101,32,119,101,32,103,101,116,32,40,98,101,116,119,101,101,110,32,49,32,97,110,100,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,41,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,107,110,111,119,110>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,99,97,110,110,111,116,32,100,101,116,101,99,116,32,97,32,113,117,111,116,97,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>}],[]},{code,[],[<<117,112,100,97,116,101,95,99,112,117,95,105,110,102,111>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,114,101,114,101,97,100,115,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,97,118,97,105,108,97,98,108,101,32,97,110,100,32,117,112,100,97,116,101,115,32,105,116,115,32,105,110,116,101,114,110,97,108,108,121,32,115,116,111,114,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,116,111,112,111,108,111,103,121,95,100,101,116,101,99,116,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,101,116,101,99,116,101,100,32,67,80,85,32,116,111,112,111,108,111,103,121>>]},<<32,97,110,100,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,102,105,103,117,114,101,100>>]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,110,108,105,110,101>>]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,118,97,105,108,97,98,108,101>>]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,112,117,95,113,117,111,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,112,117,32,113,117,111,116,97>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,104,97,115,32,99,104,97,110,103,101,100,32,115,105,110,99,101,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,105,116,32,119,97,115,32,114,101,97,100,44,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<99,104,97,110,103,101,100>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,99,104,97,110,103,101,100>>]},<<46,32,73,102,32,116,104,101,32,67,80,85,32,105,110,102,111,114,109,97,116,105,111,110,32,104,97,115,32,99,104,97,110,103,101,100,44,32,121,111,117,32,112,114,111,98,97,98,108,121,32,119,97,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<97,100,106,117,115,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101>>]},<<46,32,89,111,117,32,116,121,112,105,99,97,108,108,121,32,119,97,110,116,32,116,111,32,104,97,118,101,32,97,115,32,109,97,110,121,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,108,111,103,105,99,97,108,95,112,114,111,99,101,115,115,111,114,115,95,97,118,97,105,108,97,98,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,32,97,118,97,105,108,97,98,108,101>>]},<<46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3097,10},bounded_fun,[{type,{3097,10},'fun',[{type,{3097,10},product,[{atom,{3097,11},cpu_topology}]},{var,{3097,29},'CpuTopology'}]},[{type,{3098,7},constraint,[{atom,{3098,7},is_subtype},[{var,{3098,7},'CpuTopology'},{user_type,{3098,22},cpu_topology,[]}]]}]]},{type,{3099,10},bounded_fun,[{type,{3099,10},'fun',[{type,{3099,10},product,[{type,{3099,11},tuple,[{atom,{3099,12},cpu_topology},{type,{3099,26},union,[{atom,{3099,26},defined},{atom,{3099,36},detected},{atom,{3099,47},used}]}]}]},{var,{3099,57},'CpuTopology'}]},[{type,{3100,7},constraint,[{atom,{3100,7},is_subtype},[{var,{3100,7},'CpuTopology'},{user_type,{3100,22},cpu_topology,[]}]]}]]},{type,{3101,10},'fun',[{type,{3101,10},product,[{atom,{3101,11},creation}]},{type,{3101,24},integer,[]}]},{type,{3130,10},'fun',[{type,{3130,10},product,[{atom,{3130,11},machine}]},{type,{3130,23},string,[]}]},{type,{3175,10},'fun',[{type,{3175,10},product,[{atom,{3175,11},version}]},{type,{3175,23},string,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,50,54,54>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{li,[{name,<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]}]},{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,100,101,102,97,117,108,116,32,112,114,111,99,101,115,115,32,104,101,97,112,32,115,101,116,116,105,110,103,115,58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>}],[]},{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,102,117,108,108,115,119,101,101,112,95,97,102,116,101,114,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32>>,{code,[],[<<102,117,108,108,115,119,101,101,112,95,97,102,116,101,114>>]},<<32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,32,117,115,101,100,32,98,121,32,100,101,102,97,117,108,116,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]},<<32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>}],[]},{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,100,101,102,97,117,108,116,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,115,46,32,65,32,112,114,111,99,101,115,115,32,115,112,97,119,110,101,100,32,111,110,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,98,121,32,97,32>>,{code,[],[<<115,112,97,119,110>>]},<<32,111,114,32>>,{code,[],[<<115,112,97,119,110,95,108,105,110,107>>]},<<32,117,115,101,115,32,116,104,101,115,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,115,101,116,116,105,110,103,115,46,32,84,104,101,32,100,101,102,97,117,108,116,32,115,101,116,116,105,110,103,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,47,50>>]}]},<<46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,47,50,44,51,44,52>>]}]},<<32,99,97,110,32,115,112,97,119,110,32,97,32,112,114,111,99,101,115,115,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,117,115,101,32,116,104,101,32,100,101,102,97,117,108,116,32,115,101,116,116,105,110,103,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,115,105,122,101,115>>}],[]},{code,[],[<<104,101,97,112,95,115,105,122,101,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,118,97,108,105,100,32,104,101,97,112,32,115,105,122,101,115,32,105,110,32,119,111,114,100,115,46,32,65,108,108,32,69,114,108,97,110,103,32,104,101,97,112,115,32,97,114,101,32,115,105,122,101,100,32,102,114,111,109,32,115,105,122,101,115,32,105,110,32,116,104,105,115,32,108,105,115,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,104,101,97,112,95,116,121,112,101>>}],[]},{code,[],[<<104,101,97,112,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,104,101,97,112,32,116,121,112,101,32,117,115,101,100,32,98,121,32,116,104,101,32,99,117,114,114,101,110,116,32,101,109,117,108,97,116,111,114,46,32,79,110,101,32,104,101,97,112,32,116,121,112,101,32,101,120,105,115,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<112,114,105,118,97,116,101>>]}]},{dd,[],[<<69,97,99,104,32,112,114,111,99,101,115,115,32,104,97,115,32,97,32,104,101,97,112,32,114,101,115,101,114,118,101,100,32,102,111,114,32,105,116,115,32,117,115,101,32,97,110,100,32,110,111,32,114,101,102,101,114,101,110,99,101,115,32,98,101,116,119,101,101,110,32,104,101,97,112,115,32,111,102,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,97,108,108,111,119,101,100,46,32,77,101,115,115,97,103,101,115,32,112,97,115,115,101,100,32,98,101,116,119,101,101,110,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,99,111,112,105,101,100,32,98,101,116,119,101,101,110,32,104,101,97,112,115,46>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,97,120,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,97,120,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,115,101,116,116,105,110,103,115,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46,32,84,104,105,115,32,115,101,116,116,105,110,103,32,99,97,110,32,98,101,32,115,101,116,32,117,115,105,110,103,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120,107>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120,101,108>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,97,120,105,98>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,97,120,105,98,108>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,73,116,32,99,97,110,32,97,108,115,111,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,114,117,110,116,105,109,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,97,98,111,117,116,32,116,104,101,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>}],[]},{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>]},<<32,112,114,111,99,101,115,115,32,102,108,97,103,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<111,102,102,95,104,101,97,112>>]},<<32,111,114,32>>,{code,[],[<<111,110,95,104,101,97,112>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,105,115,32,115,101,116,32,98,121,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,104,109,113,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,104,109,113,100>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,105,110,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,105,110,95,104,101,97,112,95,115,105,122,101,44,32,77,105,110,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,105,110,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,105,110,105,109,117,109,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,109,105,110,95,98,105,110,95,118,104,101,97,112,95,115,105,122,101,44,32,77,105,110,66,105,110,86,72,101,97,112,83,105,122,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<77,105,110,66,105,110,86,72,101,97,112,83,105,122,101>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,45,119,105,100,101,32,109,105,110,105,109,117,109,32,98,105,110,97,114,121,32,118,105,114,116,117,97,108,32,104,101,97,112,32,115,105,122,101,32,102,111,114,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,115>>}],[]},{code,[],[<<112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,112,114,111,99,101,115,115,32,97,110,100,32,112,111,114,116,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3121,10},'fun',[{type,{3121,10},product,[{atom,{3121,11},garbage_collection}]},{type,{3121,34},list,[{type,{3121,35},tuple,[{type,{3121,36},atom,[]},{type,{3121,44},integer,[]}]}]}]},{type,{3122,10},'fun',[{type,{3122,10},product,[{atom,{3122,11},heap_sizes}]},{type,{3122,26},list,[{type,{3122,27},non_neg_integer,[]}]}]},{type,{3123,10},'fun',[{type,{3123,10},product,[{atom,{3123,11},heap_type}]},{atom,{3123,25},private}]},{type,{3124,10},'fun',[{type,{3124,10},product,[{atom,{3124,11},info}]},{type,{3124,20},binary,[]}]},{type,{3132,10},'fun',[{type,{3132,10},product,[{atom,{3132,11},message_queue_data}]},{user_type,{3132,34},message_queue_data,[]}]},{type,{3133,10},'fun',[{type,{3133,10},product,[{atom,{3133,11},min_heap_size}]},{type,{3133,29},tuple,[{atom,{3133,30},min_heap_size},{ann_type,{3133,45},[{var,{3133,45},'MinHeapSize'},{type,{3133,60},pos_integer,[]}]}]}]},{type,{3134,10},'fun',[{type,{3134,10},product,[{atom,{3134,11},min_bin_vheap_size}]},{type,{3134,34},tuple,[{atom,{3134,35},min_bin_vheap_size},{ann_type,{3135,35},[{var,{3135,35},'MinBinVHeapSize'},{type,{3135,54},pos_integer,[]}]}]}]},{type,{3136,10},'fun',[{type,{3136,10},product,[{atom,{3136,11},modified_timing_level}]},{type,{3136,37},union,[{type,{3136,37},integer,[]},{atom,{3136,49},undefined}]}]},{type,{3151,10},'fun',[{type,{3151,10},product,[{atom,{3151,11},scheduler_bind_type}]},{type,{3151,35},union,[{atom,{3151,35},spread},{atom,{3152,35},processor_spread},{atom,{3153,35},thread_spread},{atom,{3154,35},thread_no_node_processor_spread},{atom,{3155,35},no_node_processor_spread},{atom,{3156,35},no_node_thread_spread},{atom,{3157,35},no_spread},{atom,{3158,35},unbound}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,52,51,50>>,since => <<79,84,80,32,49,57,46,48,44,79,84,80,32,82,49,51,66,48,52>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,105,109,105,116,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,108,105,109,105,116,115,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,99,111,117,110,116>>}],[]},{code,[],[<<97,116,111,109,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,116,111,109,95,108,105,109,105,116>>}],[]},{code,[],[<<97,116,111,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,97,116,111,109,115,32,97,108,108,111,119,101,100,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,105,110,99,114,101,97,115,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,116>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,99,111,117,110,116>>}],[]},{code,[],[<<101,116,115,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,69,84,83,32,116,97,98,108,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,116,115,95,108,105,109,105,116>>}],[]},{code,[],[<<101,116,115,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,105,109,105,116,32,102,111,114,32,110,117,109,98,101,114,32,111,102,32,69,84,83,32,116,97,98,108,101,115,46,32,84,104,105,115,32,108,105,109,105,116,32,105,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,116,115,35,109,97,120,95,101,116,115,95,116,97,98,108,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,97,108,108,121,32,111,98,115,111,108,101,116,101>>]},<<32,97,110,100,32,110,117,109,98,101,114,32,111,102,32,116,97,98,108,101,115,32,97,114,101,32,111,110,108,121,32,108,105,109,105,116,101,100,32,98,121,32,97,118,97,105,108,97,98,108,101,32,109,101,109,111,114,121,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,99,111,117,110,116>>}],[]},{code,[],[<<112,111,114,116,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,111,114,116,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<108,101,110,103,116,104,40,101,114,108,97,110,103,58,112,111,114,116,115,40,41,41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,108,105,109,105,116>>}],[]},{code,[],[<<112,111,114,116,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,115,105,109,117,108,116,97,110,101,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,81>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,81>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,99,111,117,110,116>>}],[]},{code,[],[<<112,114,111,99,101,115,115,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<108,101,110,103,116,104,40,112,114,111,99,101,115,115,101,115,40,41,41>>]},<<44,32,98,117,116,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,114,111,99,101,115,115,95,108,105,109,105,116>>}],[]},{code,[],[<<112,114,111,99,101,115,115,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,115,105,109,117,108,116,97,110,101,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,116,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,80>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,80>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3090,10},'fun',[{type,{3090,10},product,[{atom,{3090,11},atom_count}]},{type,{3090,26},pos_integer,[]}]},{type,{3091,10},'fun',[{type,{3091,10},product,[{atom,{3091,11},atom_limit}]},{type,{3091,26},pos_integer,[]}]},{type,{3119,10},'fun',[{type,{3119,10},product,[{atom,{3119,11},ets_limit}]},{type,{3119,25},pos_integer,[]}]},{type,{3120,10},'fun',[{type,{3120,10},product,[{atom,{3120,11},fullsweep_after}]},{type,{3120,31},tuple,[{atom,{3120,32},fullsweep_after},{type,{3120,49},non_neg_integer,[]}]}]},{type,{3146,10},'fun',[{type,{3146,10},product,[{atom,{3146,11},port_count}]},{type,{3146,26},non_neg_integer,[]}]},{type,{3147,10},'fun',[{type,{3147,10},product,[{atom,{3147,11},port_limit}]},{type,{3147,26},pos_integer,[]}]},{type,{3148,10},'fun',[{type,{3148,10},product,[{atom,{3148,11},process_count}]},{type,{3148,29},pos_integer,[]}]},{type,{3149,10},'fun',[{type,{3149,10},product,[{atom,{3149,11},process_limit}]},{type,{3149,29},pos_integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,53,53,50>>,since => <<79,84,80,32,50,48,46,48,44,79,84,80,32,50,49,46,49,44,79,84,80,32,82,49,54,66,44,79,84,80,32,82,49,54,66,48,51>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,116,105,109,101,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>}],[]},{code,[],[<<101,110,100,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,105,110,116,101,114,110,97,108,108,121,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,101,32,116,105,109,101,32,98,101,116,119,101,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,97,114,116,32,116,105,109,101>>]},<<32,97,110,100,32,116,104,101,32,101,110,100,32,116,105,109,101,32,105,115,32,97,116,32,108,101,97,115,116,32,97,32,113,117,97,114,116,101,114,32,111,102,32,97,32,109,105,108,108,101,110,110,105,117,109,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>}],[]},{code,[],[<<111,115,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,111,117,114,99,101,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,110,111,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,115,32,97,118,97,105,108,97,98,108,101,46,32,84,104,101,32,108,105,115,116,32,99,111,110,116,97,105,110,115,32,116,119,111,45,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<115,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,115,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,108,105,115,116,44,32,98,117,116,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,102,117,110,99,116,105,111,110,44,32,70,117,110,99,116,105,111,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,117,115,101,100,46,32,84,104,105,115,32,116,117,112,108,101,32,97,108,119,97,121,115,32,101,120,105,115,116,115,32,105,102,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,115,32,97,118,97,105,108,97,98,108,101,32,116,111,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]},{dt,[],[{code,[],[<<123,99,108,111,99,107,95,105,100,44,32,67,108,111,99,107,73,100,125>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,116,117,112,108,101,32,111,110,108,121,32,101,120,105,115,116,115,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,100,105,102,102,101,114,101,110,116,32,99,108,111,99,107,115,46,32>>,{code,[],[<<67,108,111,99,107,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,99,108,111,99,107,32,105,100,101,110,116,105,102,105,101,114,32,117,115,101,100,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,115,111,108,117,116,105,111,110,44,32,79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110,125>>]}]},{dd,[],[{p,[],[<<72,105,103,104,101,115,116,32,112,111,115,115,105,98,108,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,111,102,32,99,117,114,114,101,110,116,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,115,111,117,114,99,101,32,97,115,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,110,111,32,114,101,115,111,108,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,102,114,111,109,32,116,104,101,32,79,83,44,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<115,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,97,99,116,117,97,108,32,114,101,115,111,108,117,116,105,111,110,32,99,97,110,32,98,101,32,108,111,119,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,100,111,101,115,32,110,111,116,32,115,97,121,32,97,110,121,116,104,105,110,103,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,114,32,119,104,101,116,104,101,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,97,108,105,103,110,115,32,119,105,116,104,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,46,32,89,111,117,32,100,111,44,32,104,111,119,101,118,101,114,44,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,112,114,101,99,105,115,105,111,110,32,105,115,32,110,111,116,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,120,116,101,110,100,101,100,44,32,69,120,116,101,110,100,101,100,125>>]}]},{dd,[],[{p,[],[{code,[],[<<69,120,116,101,110,100,101,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,32,104,97,115,32,98,101,101,110,32,101,120,116,101,110,100,101,100,59,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<69,120,116,101,110,100,101,100>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46,32,84,104,101,32,114,97,110,103,101,32,109,117,115,116,32,98,101,32,101,120,116,101,110,100,101,100,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,114,101,116,117,114,110,115,32,118,97,108,117,101,115,32,116,104,97,116,32,119,114,97,112,32,102,97,115,116,46,32,84,104,105,115,32,116,121,112,105,99,97,108,108,121,32,105,115,32,116,104,101,32,99,97,115,101,32,119,104,101,110,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,32,51,50,45,98,105,116,32,118,97,108,117,101,46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,44,32,80,97,114,97,108,108,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,32,102,114,111,109,32,109,117,108,116,105,112,108,101,32,116,104,114,101,97,100,115,46,32,73,102,32,105,116,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,44,32,98,101,99,97,117,115,101,32,99,97,108,108,115,32,109,117,115,116,32,98,101,32,115,101,114,105,97,108,105,122,101,100,44,32>>,{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,105,109,101,44,32,79,115,77,111,110,111,116,111,110,105,99,84,105,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<79,115,77,111,110,111,116,111,110,105,99,84,105,109,101>>]},<<32,101,113,117,97,108,115,32,99,117,114,114,101,110,116,32,79,83,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>}],[]},{code,[],[<<111,115,95,115,121,115,116,101,109,95,116,105,109,101,95,115,111,117,114,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,115,111,117,114,99,101,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32,108,105,115,116,32,99,111,110,116,97,105,110,115,32,116,119,111,45,116,117,112,108,101,115,32,119,105,116,104,32>>,{code,[],[<<75,101,121>>]},<<115,32,97,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<115,32,97,115,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,115,101,32,116,117,112,108,101,115,32,105,115,32,117,110,100,101,102,105,110,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,112,97,114,116,32,111,102,32,116,104,101,32,108,105,115,116,44,32,98,117,116,32,109,111,114,101,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,102,117,110,99,116,105,111,110,44,32,70,117,110,99,116,105,111,110,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<123,99,108,111,99,107,95,105,100,44,32,67,108,111,99,107,73,100,125>>]}]},{dd,[],[{p,[],[<<69,120,105,115,116,115,32,111,110,108,121,32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,100,105,102,102,101,114,101,110,116,32,99,108,111,99,107,115,46,32>>,{code,[],[<<67,108,111,99,107,73,100>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,99,108,111,99,107,32,105,100,101,110,116,105,102,105,101,114,32,117,115,101,100,32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,114,101,115,111,108,117,116,105,111,110,44,32,79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110,125>>]}]},{dd,[],[{p,[],[<<72,105,103,104,101,115,116,32,112,111,115,115,105,98,108,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,111,102,32,99,117,114,114,101,110,116,32,79,83,32,115,121,115,116,101,109,32,116,105,109,101,32,115,111,117,114,99,101,32,97,115,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,110,111,32,114,101,115,111,108,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,99,97,110,32,98,101,32,114,101,116,114,105,101,118,101,100,32,102,114,111,109,32,116,104,101,32,79,83,44,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<115,32,114,101,116,117,114,110,32,118,97,108,117,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,97,99,116,117,97,108,32,114,101,115,111,108,117,116,105,111,110,32,99,97,110,32,98,101,32,108,111,119,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,100,111,101,115,32,110,111,116,32,115,97,121,32,97,110,121,116,104,105,110,103,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,114,32,119,104,101,116,104,101,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,100,111,32,97,108,105,103,110,32,119,105,116,104,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,46,32,89,111,117,32,100,111,44,32,104,111,119,101,118,101,114,44,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,112,114,101,99,105,115,105,111,110,32,105,115,32,110,111,116,32,98,101,116,116,101,114,32,116,104,97,110,32>>,{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101,82,101,115,111,108,117,116,105,111,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,97,108,108,101,108,44,32,80,97,114,97,108,108,101,108,125>>]}]},{dd,[],[{p,[],[{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<121,101,115>>]},<<32,105,102,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,115,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,32,102,114,111,109,32,109,117,108,116,105,112,108,101,32,116,104,114,101,97,100,115,46,32,73,102,32,105,116,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,105,110,32,112,97,114,97,108,108,101,108,44,32,98,101,99,97,117,115,101,32,99,97,108,108,115,32,110,101,101,100,115,32,116,111,32,98,101,32,115,101,114,105,97,108,105,122,101,100,44,32>>,{code,[],[<<80,97,114,97,108,108,101,108>>]},<<32,101,113,117,97,108,115,32>>,{code,[],[<<110,111>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,105,109,101,44,32,79,115,83,121,115,116,101,109,84,105,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<79,115,83,121,115,116,101,109,84,105,109,101>>]},<<32,101,113,117,97,108,115,32,99,117,114,114,101,110,116,32,79,83,32,115,121,115,116,101,109,32,116,105,109,101,32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,116,97,114,116,95,116,105,109,101>>}],[]},{code,[],[<<115,116,97,114,116,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<32,97,116,32,116,104,101,32,116,105,109,101,32,119,104,101,110,32,99,117,114,114,101,110,116,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,115,116,97,114,116,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,110,100,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,101,110,100,95,116,105,109,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>}],[]},{code,[],[<<116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,111,111,108,101,97,110,32,118,97,108,117,101,32,105,110,100,105,99,97,116,105,110,103,32,119,104,101,116,104,101,114,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,67,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,99,111,114,114,101,99,116,105,111,110>>]},<<32,105,115,32,101,110,97,98,108,101,100,32,111,114,32,110,111,116,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>}],[]},{code,[],[<<116,105,109,101,95,111,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,116,97,116,101,32,111,102,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,58>>]},{dl,[],[{dt,[],[{code,[],[<<112,114,101,108,105,109,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,112,114,101,108,105,109,105,110,97,114,121,44,32,97,110,100,32,119,105,108,108,32,98,101,32,99,104,97,110,103,101,100,32,97,110,100,32,102,105,110,97,108,105,122,101,100,32,108,97,116,101,114,46,32,84,104,101,32,112,114,101,108,105,109,105,110,97,114,121,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,117,115,101,100,32,100,117,114,105,110,103,32,116,104,101,32,112,114,101,108,105,109,105,110,97,114,121,32,112,104,97,115,101,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,105,110,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,102,105,110,97,108,46,32,84,104,105,115,32,101,105,116,104,101,114,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,44,32,111,114,32,98,101,99,97,117,115,101,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,104,97,118,101,32,98,101,101,110,32,102,105,110,97,108,105,122,101,100,32,119,104,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]},{dt,[],[{code,[],[<<118,111,108,97,116,105,108,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,118,111,108,97,116,105,108,101,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,32,99,104,97,110,103,101,32,97,116,32,97,110,121,32,116,105,109,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,119,97,114,112,95,109,111,100,101>>}],[]},{code,[],[<<116,105,109,101,95,119,97,114,112,95,109,111,100,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,118,97,108,117,101,32,105,100,101,110,116,105,102,121,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,116,104,97,116,32,105,115,32,117,115,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<110,111,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,78,111,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]},{dt,[],[{code,[],[<<115,105,110,103,108,101,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,105,110,103,108,101,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,105,110,103,108,101,32,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]},{dt,[],[{code,[],[<<109,117,108,116,105,95,116,105,109,101,95,119,97,114,112>>]}]},{dd,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,105,115,32,117,115,101,100,46>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>}],[]},{code,[],[<<116,111,108,101,114,97,110,116,95,116,105,109,101,111,102,100,97,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,119,104,101,116,104,101,114,32,97,32,112,114,101,32,69,82,84,83,32,55,46,48,32,98,97,99,107,119,97,114,100,115,32,99,111,109,112,97,116,105,98,108,101,32,99,111,109,112,101,110,115,97,116,105,111,110,32,102,111,114,32,115,117,100,100,101,110,32,99,104,97,110,103,101,115,32,111,102,32,115,121,115,116,101,109,32,116,105,109,101,32,105,115,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<32,111,114,32>>,{code,[],[<<100,105,115,97,98,108,101,100>>]},<<46,32,83,117,99,104,32,99,111,109,112,101,110,115,97,116,105,111,110,32,105,115,32>>,{code,[],[<<101,110,97,98,108,101,100>>]},<<32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,111,102,102,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,111,102,102,115,101,116>>]},<<32,105,115,32>>,{code,[],[<<102,105,110,97,108>>]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,99,111,114,114,101,99,116,105,111,110>>]},<<32,105,115,32,101,110,97,98,108,101,100,46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3118,10},'fun',[{type,{3118,10},product,[{atom,{3118,11},ets_count}]},{type,{3118,25},pos_integer,[]}]},{type,{3143,10},'fun',[{type,{3143,10},product,[{atom,{3143,11},os_system_time_source}]},{type,{3143,37},list,[{type,{3143,38},tuple,[{type,{3143,39},atom,[]},{type,{3143,46},term,[]}]}]}]},{type,{3144,10},'fun',[{type,{3144,10},product,[{atom,{3144,11},outstanding_system_requests_limit}]},{type,{3144,49},range,[{integer,{3144,49},1},{integer,{3144,52},134217727}]}]},{type,{3164,10},'fun',[{type,{3164,10},product,[{atom,{3164,11},system_architecture}]},{type,{3164,35},string,[]}]},{type,{3170,10},'fun',[{type,{3170,10},product,[{atom,{3170,11},time_offset}]},{type,{3170,27},union,[{atom,{3170,27},preliminary},{atom,{3170,41},final},{atom,{3170,49},volatile}]}]},{type,{3171,10},'fun',[{type,{3171,10},product,[{atom,{3171,11},time_warp_mode}]},{type,{3171,30},union,[{atom,{3171,30},no_time_warp},{atom,{3171,45},single_time_warp},{atom,{3171,64},multi_time_warp}]}]},{type,{3172,10},'fun',[{type,{3172,10},product,[{atom,{3172,11},tolerant_timeofday}]},{type,{3172,34},union,[{atom,{3172,34},enabled},{atom,{3172,44},disabled}]}]},{type,{3173,10},'fun',[{type,{3173,10},product,[{atom,{3173,11},trace_control_word}]},{type,{3173,34},non_neg_integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,54,51,50>>,since => <<79,84,80,32,49,55,46,49,44,79,84,80,32,49,56,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,115,99,104,101,100,117,108,101,114,115,44,32,115,99,104,101,100,117,108,105,110,103,32,97,110,100,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,68,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,101,120,101,99,117,116,101,32,67,80,85,45,98,111,117,110,100,32,110,97,116,105,118,101,32,102,117,110,99,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32,78,73,70,115,44,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,44,32,97,110,100,32,66,73,70,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,109,97,110,97,103,101,100,32,99,108,101,97,110,108,121,32,98,121,32,116,104,101,32,110,111,114,109,97,108,32,101,109,117,108,97,116,111,114,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,97,102,116,101,114,32,116,104,97,116,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,46,32,84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,99,112,117>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,80,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,80,99,112,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,115,97,116,105,115,102,105,101,115,32>>,{code,[],[<<49,32,60,61,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,32,60,61,32,78>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]},<<32,97,110,100,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,67,80,85,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,99,112,117>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,99,112,117>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<100,105,114,116,121,95,105,111,95,115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,68,105,114,116,121,32,73,47,79,32,115,99,104,101,100,117,108,101,114,115,32,101,120,101,99,117,116,101,32,73,47,79,45,98,111,117,110,100,32,110,97,116,105,118,101,32,102,117,110,99,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32,78,73,70,115,32,97,110,100,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,44,32,119,104,105,99,104,32,99,97,110,110,111,116,32,98,101,32,109,97,110,97,103,101,100,32,99,108,101,97,110,108,121,32,98,121,32,116,104,101,32,110,111,114,109,97,108,32,101,109,117,108,97,116,111,114,32,115,99,104,101,100,117,108,101,114,115,46>>]},{p,[],[<<84,104,105,115,32,118,97,108,117,101,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,83,68,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,83,68,105,111>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,100,105,114,116,121,95,99,112,117,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,68,105,114,116,121,67,80,85,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>}],[]},{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<100,105,115,97,98,108,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,115,116,97,114,116,101,100,32,119,105,116,104,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<98,108,111,99,107,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,98,117,116,32,97,108,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,101,120,99,101,112,116,32,111,110,101,32,97,114,101,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,111,110,108,121,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,115,99,104,101,100,117,108,101,115,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,115,32,69,114,108,97,110,103,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<98,108,111,99,107,101,100,95,110,111,114,109,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,98,117,116,32,97,108,108,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,101,120,99,101,112,116,32,111,110,101,32,97,114,101,32,98,108,111,99,107,101,100,46,32,78,111,116,105,99,101,32,116,104,97,116,32,100,105,114,116,121,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,110,111,116,32,98,108,111,99,107,101,100,44,32,97,110,100,32,99,97,110,32,115,99,104,101,100,117,108,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,32,110,97,116,105,118,101,32,99,111,100,101,46>>]}]},{dt,[],[{code,[],[<<101,110,97,98,108,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,44,32,97,110,100,32,110,111,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,97,114,101,32,98,108,111,99,107,101,100,46,32,84,104,97,116,32,105,115,44,32,97,108,108,32,97,118,97,105,108,97,98,108,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,115,99,104,101,100,117,108,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,101,120,101,99,117,116,101,32,69,114,108,97,110,103,32,99,111,100,101,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>}],[]},{code,[],[<<109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<115,32,119,104,101,110,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32>>,{code,[],[<<80,105,100>>]},<<115,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,98,108,111,99,107,105,110,103,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46,32,65,32>>,{code,[],[<<80,105,100>>]},<<32,111,99,99,117,114,115,32,111,110,108,121,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,101,118,101,110,32,105,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>}],[]},{code,[],[<<110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32>>,{code,[],[<<80,105,100>>]},<<115,32,119,104,101,110,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,32,105,115,32,98,108,111,99,107,101,100,32,40,116,104,97,116,32,105,115,44,32,97,108,108,32,110,111,114,109,97,108,32,115,99,104,101,100,117,108,101,114,115,32,98,117,116,32,111,110,101,32,105,115,32,98,108,111,99,107,101,100,41,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32>>,{code,[],[<<80,105,100>>]},<<115,32,105,110,32,116,104,101,32,108,105,115,116,32,114,101,112,114,101,115,101,110,116,32,97,108,108,32,116,104,101,32,112,114,111,99,101,115,115,101,115,32,99,117,114,114,101,110,116,108,121,32,98,108,111,99,107,105,110,103,32,110,111,114,109,97,108,32,109,117,108,116,105,45,115,99,104,101,100,117,108,105,110,103,46,32,65,32>>,{code,[],[<<80,105,100>>]},<<32,111,99,99,117,114,115,32,111,110,108,121,32,111,110,99,101,32,105,110,32,116,104,101,32,108,105,115,116,44,32,101,118,101,110,32,105,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,112,114,111,99,101,115,115,32,104,97,115,32,98,108,111,99,107,101,100,32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,104,111,119,32,116,104,101,32,117,115,101,114,32,104,97,115,32,114,101,113,117,101,115,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,98,101,32,98,111,117,110,100,32,111,114,32,110,111,116,32,98,111,117,110,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,108,116,104,111,117,103,104,32,97,32,117,115,101,114,32,104,97,115,32,114,101,113,117,101,115,116,101,100,32,115,99,104,101,100,117,108,101,114,115,32,116,111,32,98,101,32,98,111,117,110,100,44,32,116,104,101,121,32,99,97,110,32,115,105,108,101,110,116,108,121,32,104,97,118,101,32,102,97,105,108,101,100,32,116,111,32,98,105,110,100,46,32,84,111,32,105,110,115,112,101,99,116,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,105,110,103,115,44,32,99,97,108,108,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,117,115,101,100,32,115,99,104,101,100,117,108,101,114,32,98,105,110,100,105,110,103,115,46>>]},{p,[],[<<65,32,116,117,112,108,101,32,111,102,32,97,32,115,105,122,101,32,101,113,117,97,108,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,116,117,112,108,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,105,110,116,101,103,101,114,115,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,98,111,117,110,100>>]},<<46,32,76,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,115,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,105,110,116,101,103,101,114,115,46,32,84,104,101,32>>,{code,[],[<<78>>]},<<116,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,116,117,112,108,101,32,101,113,117,97,108,115,32,116,104,101,32,99,117,114,114,101,110,116,32,98,105,110,100,105,110,103,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,119,105,116,104,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,32,101,113,117,97,108,32,116,111,32>>,{code,[],[<<78>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,115,32,97,114,101,32,98,111,117,110,100,44,32>>,{code,[],[<<101,108,101,109,101,110,116,40,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,105,100,41,44,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,98,105,110,100,105,110,103,115,41,41>>]},<<32,114,101,116,117,114,110,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,110,108,121,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,98,111,117,110,100,32,116,111,32,108,111,103,105,99,97,108,32,112,114,111,99,101,115,115,111,114,115,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,98,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,98,116>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,95,105,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,73,68,32,40>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<41,32,111,102,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{code,[],[<<83,99,104,101,100,117,108,101,114,73,100>>]},<<32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,44,32,119,104,101,114,101,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,73,100,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,117,115,101,100,32,98,121,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,83,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,111,110,108,105,110,101,32,115,99,104,101,100,117,108,101,115,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,69,114,108,97,110,103,32,112,111,114,116,115,44,32,97,110,100,32,101,120,101,99,117,116,101,32,69,114,108,97,110,103,32,99,111,100,101,32,97,110,100,32,69,114,108,97,110,103,32,108,105,110,107,101,100,45,105,110,32,100,114,105,118,101,114,32,99,111,100,101,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,32,116,104,114,101,97,100,115,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,101,109,117,108,97,116,111,114,32,98,111,111,116,32,116,105,109,101,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,108,97,116,101,114,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,95,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,95,105,100,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,44,32,66,108,111,99,107,83,116,97,116,101,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,41>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,110,111,114,109,97,108,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,109,117,108,116,105,95,115,99,104,101,100,117,108,105,110,103,95,98,108,111,99,107,101,114,115,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>}],[]},{code,[],[<<115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,46,32,84,104,101,32,115,99,104,101,100,117,108,101,114,32,105,100,101,110,116,105,102,105,101,114,115,32,111,102,32,115,99,104,101,100,117,108,101,114,115,32,111,110,108,105,110,101,32,115,97,116,105,115,102,121,32,116,104,101,32,114,101,108,97,116,105,111,110,115,104,105,112,32>>,{code,[],[<<49,32,60,61,32,83,99,104,101,100,117,108,101,114,73,100,32,60,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,41>>]},<<46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,115,99,104,101,100,117,108,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,115,99,104,101,100,117,108,101,114,115,41>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,99,104,101,100,117,108,101,114,115,95,111,110,108,105,110,101,44,32,83,99,104,101,100,117,108,101,114,115,79,110,108,105,110,101,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,109,112,95,115,117,112,112,111,114,116>>}],[]},{code,[],[<<115,109,112,95,115,117,112,112,111,114,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,115>>}],[]},{code,[],[<<116,104,114,101,97,100,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>}],[]},{code,[],[<<116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,104,114,101,97,100,95,112,111,111,108,95,115,105,122,101>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,115,121,110,99,32,116,104,114,101,97,100,115,32,105,110,32,116,104,101,32,97,115,121,110,99,32,116,104,114,101,97,100,32,112,111,111,108,32,117,115,101,100,32,102,111,114,32,97,115,121,110,99,104,114,111,110,111,117,115,32,100,114,105,118,101,114,32,99,97,108,108,115,32,40>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,100,114,105,118,101,114,95,97,115,121,110,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<32>>,{code,[],[<<101,114,108,95,100,114,105,118,101,114,58,100,114,105,118,101,114,95,97,115,121,110,99,40,41>>]}]},<<41,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3105,10},'fun',[{type,{3105,10},product,[{atom,{3105,11},dirty_cpu_schedulers_online}]},{type,{3105,43},non_neg_integer,[]}]},{type,{3106,10},'fun',[{type,{3106,10},product,[{atom,{3106,11},dirty_io_schedulers}]},{type,{3106,35},non_neg_integer,[]}]},{type,{3107,10},'fun',[{type,{3107,10},product,[{atom,{3107,11},dist}]},{type,{3107,20},binary,[]}]},{type,{3138,10},'fun',[{type,{3138,10},product,[{atom,{3138,11},multi_scheduling_blockers}]},{type,{3138,41},list,[{ann_type,{3138,42},[{var,{3138,42},'Pid'},{type,{3138,49},pid,[]}]}]}]},{type,{3139,10},'fun',[{type,{3139,10},product,[{atom,{3139,11},nif_version}]},{type,{3139,27},string,[]}]},{type,{3141,10},'fun',[{type,{3141,10},product,[{atom,{3141,11},otp_release}]},{type,{3141,27},string,[]}]},{type,{3159,10},'fun',[{type,{3159,10},product,[{atom,{3159,11},scheduler_bindings}]},{type,{3159,35},tuple,any}]},{type,{3160,10},'fun',[{type,{3160,10},product,[{atom,{3160,11},scheduler_id}]},{ann_type,{3160,28},[{var,{3160,28},'SchedulerId'},{type,{3160,43},pos_integer,[]}]}]},{type,{3161,10},'fun',[{type,{3161,10},product,[{type,{3161,11},union,[{atom,{3161,11},schedulers},{atom,{3161,24},schedulers_online}]}]},{type,{3161,46},pos_integer,[]}]},{type,{3162,10},'fun',[{type,{3162,10},product,[{atom,{3162,11},smp_support}]},{type,{3162,27},boolean,[]}]},{type,{3163,10},'fun',[{type,{3163,10},product,[{atom,{3163,11},start_time}]},{type,{3163,26},integer,[]}]},{type,{3168,10},'fun',[{type,{3168,10},product,[{atom,{3168,11},thread_pool_size}]},{type,{3168,32},non_neg_integer,[]}]},{type,{3169,10},'fun',[{type,{3169,10},product,[{atom,{3169,11},time_correction}]},{type,{3169,31},union,[{atom,{3169,31},true},{atom,{3169,38},false}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,48,56,54,48>>,since => <<79,84,80,32,49,55,46,48,44,79,84,80,32,49,57,46,48>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,69,114,108,97,110,103,32,68,105,115,116,114,105,98,117,116,105,111,110,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,97,115,121,110,99,95,100,105,115,116>>}],[]},{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]}]},{dd,[],[{p,[],[<<83,105,110,99,101,58,32,79,84,80,32,50,53,46,51>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,112,97,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<43,112,97,100,32,60,98,111,111,108,101,97,110,62>>]},<<32,119,104,105,99,104,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,117,115,101,46,32,84,104,105,115,32,118,97,108,117,101,32,100,101,116,101,114,109,105,110,101,115,32,116,104,101,32,100,101,102,97,117,108,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,97,115,121,110,99,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<97,115,121,110,99,95,100,105,115,116>>]}]},<<32,118,97,108,117,101,32,102,111,114,32,110,101,119,108,121,32,115,112,97,119,110,101,100,32,112,114,111,99,101,115,115,101,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,114,101,97,116,105,111,110>>}],[]},{code,[],[<<99,114,101,97,116,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,34,99,114,101,97,116,105,111,110,34,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,101,32,99,114,101,97,116,105,111,110,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,97,32,110,111,100,101,32,105,115,32,114,101,115,116,97,114,116,101,100,46,32,84,104,101,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,110,111,100,101,32,105,115,32,115,116,111,114,101,100,32,105,110,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,115,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,115,44,32,97,110,100,32,114,101,102,101,114,101,110,99,101,115,46,32,84,104,105,115,32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,98,101,116,119,101,101,110,32,105,100,101,110,116,105,102,105,101,114,115,32,102,114,111,109,32,100,105,102,102,101,114,101,110,116,32,105,110,99,97,114,110,97,116,105,111,110,115,32,111,102,32,97,32,110,111,100,101,46,32,67,114,101,97,116,105,111,110,32,118,97,108,117,101,115,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,51,50,45,98,105,116,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,115,44,32,98,117,116,32,116,104,105,115,32,109,97,121,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,115,46,32,73,102,32,116,104,101,32,110,111,100,101,32,105,115,32,110,111,116,32,97,108,105,118,101,44,32>>,{code,[],[<<48>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>}],[]},{code,[],[<<100,101,108,97,121,101,100,95,110,111,100,101,95,116,97,98,108,101,95,103,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,116,105,109,101,32,105,110,32,115,101,99,111,110,100,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,97,110,32,101,110,116,114,121,32,105,110,32,97,32,110,111,100,101,32,116,97,98,108,101,32,105,115,32,100,101,108,97,121,101,100,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,115,101,116,32,111,110,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,100,110,116,103,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,122,100,110,116,103,99>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116>>}],[]},{code,[],[<<100,105,115,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,100,105,115,116,114,105,98,117,116,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>}],[]},{code,[],[<<100,105,115,116,95,98,117,102,95,98,117,115,121,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,98,117,102,102,101,114,32,98,117,115,121,32,108,105,109,105,116,32,105,110,32,98,121,116,101,115,46,32,84,104,105,115,32,108,105,109,105,116,32,99,97,110,32,98,101,32,115,101,116,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,112,97,115,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,122,100,98,98,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,122,100,98,98,108>>]}]},<<32,116,111,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,105,115,116,95,99,116,114,108>>}],[]},{code,[],[<<100,105,115,116,95,99,116,114,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,116,117,112,108,101,115,32>>,{code,[],[<<123,78,111,100,101,44,32,67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121,125>>]},<<44,32,111,110,101,32,101,110,116,114,121,32,102,111,114,32,101,97,99,104,32,99,111,110,110,101,99,116,101,100,32,114,101,109,111,116,101,32,110,111,100,101,46,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,97,110,100,32>>,{code,[],[<<67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121>>]},<<32,105,115,32,116,104,101,32,112,111,114,116,32,111,114,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,114,101,115,112,111,110,115,105,98,108,101,32,102,111,114,32,116,104,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,116,111,32,116,104,97,116,32,110,111,100,101,46,32,77,111,114,101,32,115,112,101,99,105,102,105,99,97,108,108,121,44,32>>,{code,[],[<<67,111,110,116,114,111,108,108,105,110,103,69,110,116,105,116,121>>]},<<32,102,111,114,32,110,111,100,101,115,32,99,111,110,110,101,99,116,101,100,32,116,104,114,111,117,103,104,32,84,67,80,47,73,80,32,40,116,104,101,32,110,111,114,109,97,108,32,99,97,115,101,41,32,105,115,32,116,104,101,32,115,111,99,107,101,116,32,117,115,101,100,32,105,110,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,99,32,110,111,100,101,46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3102,10},'fun',[{type,{3102,10},product,[{atom,{3102,11},debug_compiled}]},{type,{3102,30},boolean,[]}]},{type,{3104,10},'fun',[{type,{3104,10},product,[{atom,{3104,11},dirty_cpu_schedulers}]},{type,{3104,36},non_neg_integer,[]}]},{type,{3108,10},'fun',[{type,{3108,10},product,[{atom,{3108,11},dist_buf_busy_limit}]},{type,{3108,35},non_neg_integer,[]}]},{type,{3109,10},'fun',[{type,{3109,10},product,[{atom,{3109,11},dist_ctrl}]},{type,{3109,25},list,[{type,{3109,26},tuple,[{ann_type,{3109,27},[{var,{3109,27},'Node'},{type,{3109,35},node,[]}]},{ann_type,{3110,27},[{var,{3110,27},'ControllingEntity'},{type,{3110,48},union,[{type,{3110,48},port,[]},{type,{3110,57},pid,[]}]}]}]}]}]},{type,{3111,10},'fun',[{type,{3111,10},product,[{atom,{3111,11},driver_version}]},{type,{3111,30},string,[]}]},{type,{3178,10},'fun',[{type,{3178,10},product,[{atom,{3178,11},overview}]},{type,{3178,24},boolean,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,49,54,48>>,since => <<79,84,80,32,49,56,46,48,44,79,84,80,32,50,53,46,51,44,79,84,80,32,82,49,52,66,48,49>>}},{{function,system_info,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3074}],[<<115,121,115,116,101,109,95,105,110,102,111,47,49>>],#{<<101,110>> => [{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,105,115,99,95,116,97,103,115>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,118,97,114,105,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,40,101,109,117,108,97,116,111,114,41,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,116,101,109>>]},<<58>>]},{dl,[],[{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,98,117,105,108,100,95,116,121,112,101>>}],[]},{code,[],[<<98,117,105,108,100,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<68,101,112,114,101,99,97,116,101,100,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,109,117,95,116,121,112,101>>]},<<32,105,110,115,116,101,97,100>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>}],[]},{code,[],[<<99,95,99,111,109,112,105,108,101,114,95,117,115,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,119,111,45,116,117,112,108,101,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,67,32,99,111,109,112,105,108,101,114,32,117,115,101,100,32,119,104,101,110,32,99,111,109,112,105,108,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,117,110,107,110,111,119,110,46,32,84,104,101,32,115,101,99,111,110,100,32,101,108,101,109,101,110,116,32,105,115,32,97,32,116,101,114,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,99,111,109,112,105,108,101,114,44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,117,110,107,110,111,119,110,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,104,101,99,107,95,105,111>>}],[]},{code,[],[<<99,104,101,99,107,95,105,111>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,101,109,117,108,97,116,111,114,115,32,105,110,116,101,114,110,97,108,32,73,47,79,32,99,104,101,99,107,105,110,103,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,32,99,97,110,32,118,97,114,121,32,98,101,116,119,101,101,110,32,112,108,97,116,102,111,114,109,115,32,97,110,100,32,111,118,101,114,32,116,105,109,101,46,32,73,116,32,105,115,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,32,108,105,115,116,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,99,111,109,112,97,116,95,114,101,108>>}],[]},{code,[],[<<99,111,109,112,97,116,95,114,101,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,109,111,100,101,32,111,102,32,116,104,101,32,108,111,99,97,108,32,110,111,100,101,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,84,104,101,32,105,110,116,101,103,101,114,32,114,101,116,117,114,110,101,100,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,69,114,108,97,110,103,47,79,84,80,32,114,101,108,101,97,115,101,32,116,104,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,115,101,116,32,116,111,32,98,101,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,46,32,84,104,101,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,109,111,100,101,32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,97,116,32,115,116,97,114,116,117,112,32,98,121,32,117,115,105,110,103,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,99,111,109,112,97,116,95,114,101,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,82>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,101,98,117,103,95,99,111,109,112,105,108,101,100>>}],[]},{code,[],[<<100,101,98,117,103,95,99,111,109,112,105,108,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,104,97,115,32,98,101,101,110,32,100,101,98,117,103,45,99,111,109,112,105,108,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,114,105,118,101,114,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<100,114,105,118,101,114,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,100,114,105,118,101,114,32,118,101,114,115,105,111,110,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,73,116,32,104,97,115,32,116,104,101,32,102,111,114,109,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,118,101,114,115,105,111,110,95,109,97,110,97,103,101,109,101,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<34,60,109,97,106,111,114,32,118,101,114,62,46,60,109,105,110,111,114,32,118,101,114,62,34>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101>>}],[]},{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,100,121,110,97,109,105,99,32,116,114,97,99,101,32,102,114,97,109,101,119,111,114,107,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,46,32,73,116,32,99,97,110,32,98,101,32>>,{code,[],[<<100,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<44,32,111,114,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,70,111,114,32,97,32,99,111,109,109,101,114,99,105,97,108,32,111,114,32,115,116,97,110,100,97,114,100,32,98,117,105,108,100,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<110,111,110,101>>]},<<46,32,84,104,101,32,111,116,104,101,114,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,105,110,100,105,99,97,116,101,32,97,32,99,117,115,116,111,109,32,99,111,110,102,105,103,117,114,97,116,105,111,110,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<46,47,99,111,110,102,105,103,117,114,101,32,45,45,119,105,116,104,45,100,121,110,97,109,105,99,45,116,114,97,99,101,61,100,116,114,97,99,101>>]},<<41,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,121,110,97,109,105,99,32,116,114,97,99,105,110,103,44,32,115,101,101,32>>,{a,[{href,<<114,117,110,116,105,109,101,95,116,111,111,108,115,58,100,121,110,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,121,110,116,114,97,99,101,40,51,41>>]}]},<<32,109,97,110,117,97,108,32,112,97,103,101,32,97,110,100,32,116,104,101,32>>,{code,[],[<<82,69,65,68,77,69,46,100,116,114,97,99,101>>]},<<47>>,{code,[],[<<82,69,65,68,77,69,46,115,121,115,116,101,109,116,97,112>>]},<<32,102,105,108,101,115,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,115,111,117,114,99,101,32,99,111,100,101,32,116,111,112,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>}],[]},{code,[],[<<100,121,110,97,109,105,99,95,116,114,97,99,101,95,112,114,111,98,101,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32>>,{code,[],[<<98,111,111,108,101,97,110,40,41>>]},<<32,105,110,100,105,99,97,116,105,110,103,32,105,102,32,100,121,110,97,109,105,99,32,116,114,97,99,101,32,112,114,111,98,101,115,32,40>>,{code,[],[<<100,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<41,32,97,114,101,32,98,117,105,108,116,32,105,110,116,111,32,116,104,101,32,101,109,117,108,97,116,111,114,46,32,84,104,105,115,32,99,97,110,32,111,110,108,121,32,98,101,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,32,119,97,115,32,98,117,105,108,116,32,102,111,114,32,100,121,110,97,109,105,99,32,116,114,97,99,105,110,103,32,40,116,104,97,116,32,105,115,44,32>>,{code,[],[<<115,121,115,116,101,109,95,105,110,102,111,40,100,121,110,97,109,105,99,95,116,114,97,99,101,41>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<100,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<115,121,115,116,101,109,116,97,112>>]},<<41,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,102,108,97,118,111,114>>}],[]},{code,[],[<<101,109,117,95,102,108,97,118,111,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,102,108,97,118,111,114,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,105,115,32,119,105,108,108,32,98,101,32,101,105,116,104,101,114,32>>,{code,[],[<<101,109,117>>]},<<32,111,114,32>>,{code,[],[<<106,105,116>>]},<<46,32,80,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,101,109,117,95,116,121,112,101>>}],[]},{code,[],[<<101,109,117,95,116,121,112,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,98,117,105,108,100,32,116,121,112,101,32,111,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,84,104,105,115,32,105,115,32,110,111,114,109,97,108,108,121,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,112,116>>]},<<32,102,111,114,32,111,112,116,105,109,105,122,101,100,46,32,79,116,104,101,114,32,112,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,97,114,101,32>>,{code,[],[<<100,101,98,117,103>>]},<<44,32>>,{code,[],[<<103,99,111,118>>]},<<44,32>>,{code,[],[<<118,97,108,103,114,105,110,100>>]},<<44,32>>,{code,[],[<<103,112,114,111,102>>]},<<44,32,97,110,100,32>>,{code,[],[<<108,99,110,116>>]},<<46,32,80,111,115,115,105,98,108,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,111,114,32,114,101,109,111,118,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,105,110,102,111>>}],[]},{code,[],[<<105,110,102,111>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,109,105,115,99,101,108,108,97,110,101,111,117,115,32,115,121,115,116,101,109,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,107,101,114,110,101,108,95,112,111,108,108>>}],[]},{code,[],[<<107,101,114,110,101,108,95,112,111,108,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,101,109,117,108,97,116,111,114,32,117,115,101,115,32,115,111,109,101,32,107,105,110,100,32,111,102,32,107,101,114,110,101,108,45,112,111,108,108,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,108,111,97,100,101,100>>}],[]},{code,[],[<<108,111,97,100,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,99,111,110,116,97,105,110,105,110,103,32,97,32,115,116,114,105,110,103,32,111,102,32,108,111,97,100,101,100,32,109,111,100,117,108,101,32,105,110,102,111,114,109,97,116,105,111,110,32,102,111,114,109,97,116,116,101,100,32,97,115,32,105,110,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,99,114,97,115,104,95,100,117,109,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<72,111,119,32,116,111,32,105,110,116,101,114,112,114,101,116,32,116,104,101,32,69,114,108,97,110,103,32,99,114,97,115,104,32,100,117,109,112,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,97,99,104,105,110,101>>}],[]},{code,[],[<<109,97,99,104,105,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,109,97,99,104,105,110,101,32,110,97,109,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>}],[]},{code,[],[<<109,111,100,105,102,105,101,100,95,116,105,109,105,110,103,95,108,101,118,101,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,45,108,101,118,101,108,32,40,97,110,32,105,110,116,101,103,101,114,41,32,105,102,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,32,105,115,32,101,110,97,98,108,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,109,111,100,105,102,105,101,100,32,116,105,109,105,110,103,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,102,108,97,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,84>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,84>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]}]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,110,105,102,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<110,105,102,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,78,73,70,32,105,110,116,101,114,102,97,99,101,32,117,115,101,100,32,98,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46,32,73,116,32,105,115,32,111,110,32,116,104,101,32,102,111,114,109,32,34,60,109,97,106,111,114,32,118,101,114,62,46,60,109,105,110,111,114,32,118,101,114,62,34,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>}],[]},{code,[],[<<111,116,112,95,114,101,108,101,97,115,101>>]}]},{dd,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,116,112,95,114,101,108,101,97,115,101>>}],[]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,116,104,97,116,32,116,104,101,32,99,117,114,114,101,110,116,108,121,32,101,120,101,99,117,116,105,110,103,32,69,82,84,83,32,97,112,112,108,105,99,97,116,105,111,110,32,105,115,32,112,97,114,116,32,111,102,46>>]},{p,[],[<<65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,49,55,44,32,116,104,101,32,79,84,80,32,114,101,108,101,97,115,101,32,110,117,109,98,101,114,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,109,97,106,111,114,32,79,84,80,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,46,32,78,111,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,105,110,102,111,40,41>>]},<<32,97,114,103,117,109,101,110,116,32,103,105,118,101,115,32,116,104,101,32,101,120,97,99,116,32,79,84,80,32,118,101,114,115,105,111,110,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,101,120,97,99,116,32,79,84,80,32,118,101,114,115,105,111,110,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,32,105,115,32,100,105,102,102,105,99,117,108,116,32,116,111,32,100,101,116,101,114,109,105,110,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,118,101,114,115,105,111,110,115,32,105,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,115,121,115,116,101,109,95,112,114,105,110,99,105,112,108,101,115,58,118,101,114,115,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,121,115,116,101,109,32,112,114,105,110,99,105,112,108,101,115>>]},<<32,105,110,32,83,121,115,116,101,109,32,68,111,99,117,109,101,110,116,97,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>}],[]},{code,[],[<<111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,108,105,109,105,116,32,111,110,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,111,117,116,115,116,97,110,100,105,110,103,32,114,101,113,117,101,115,116,115,32,109,97,100,101,32,98,121,32,97,32,115,121,115,116,101,109,32,112,114,111,99,101,115,115,32,111,114,99,104,101,115,116,114,97,116,105,110,103,32,115,121,115,116,101,109,32,119,105,100,101,32,99,104,97,110,103,101,115,46,32,83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,95,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,111,117,116,115,116,97,110,100,105,110,103,95,115,121,115,116,101,109,95,114,101,113,117,101,115,116,115,95,108,105,109,105,116,44,32,76,105,109,105,116,41>>]}]},<<32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>}],[]},{code,[],[<<112,111,114,116,95,112,97,114,97,108,108,101,108,105,115,109>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,101,102,97,117,108,116,32,112,111,114,116,32,112,97,114,97,108,108,101,108,105,115,109,32,115,99,104,101,100,117,108,105,110,103,32,104,105,110,116,32,117,115,101,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,99,111,109,109,97,110,100,45,108,105,110,101,32,97,114,103,117,109,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,43,115,112,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<43,115,112,112>>]}]},<<32,105,110,32>>,{code,[],[<<101,114,108,40,49,41>>]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>}],[]},{code,[],[<<115,121,115,116,101,109,95,97,114,99,104,105,116,101,99,116,117,114,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,112,114,111,99,101,115,115,111,114,32,97,110,100,32,79,83,32,97,114,99,104,105,116,101,99,116,117,114,101,32,116,104,101,32,101,109,117,108,97,116,111,114,32,105,115,32,98,117,105,108,116,32,102,111,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,108,111,103,103,101,114>>}],[]},{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32>>,{code,[],[<<115,121,115,116,101,109,95,108,111,103,103,101,114>>]},<<32,97,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,102,108,97,103,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,102,108,97,103,40,115,121,115,116,101,109,95,108,111,103,103,101,114,44,32,95,41>>]}]},<<46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,115,121,115,116,101,109,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<115,121,115,116,101,109,95,118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,97,110,100,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,112,114,111,112,101,114,116,105,101,115,44,32,115,117,99,104,32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,99,104,101,100,117,108,101,114,115,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>}],[]},{code,[],[<<116,114,97,99,101,95,99,111,110,116,114,111,108,95,119,111,114,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,110,111,100,101,32,116,114,97,99,101,32,99,111,110,116,114,111,108,32,119,111,114,100,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<103,101,116,95,116,99,119>>]},<<32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99,35,103,101,116,95,116,99,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,118,101,114,115,105,111,110>>}],[]},{code,[],[<<118,101,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,46>>]}]},{dt,[],[{a,[{id,<<115,121,115,116,101,109,95,105,110,102,111,95,119,111,114,100,115,105,122,101>>}],[]},{code,[],[<<119,111,114,100,115,105,122,101>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,105,110,116,101,114,110,97,108,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,105,110,116,101,114,110,97,108,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,105,122,101,32,111,102,32,69,114,108,97,110,103,32,116,101,114,109,32,119,111,114,100,115,32,105,110,32,98,121,116,101,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,44,32,116,104,97,116,32,105,115,44,32,52,32,105,115,32,114,101,116,117,114,110,101,100,32,111,110,32,97,32,51,50,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,97,110,100,32,56,32,105,115,32,114,101,116,117,114,110,101,100,32,111,110,32,97,32,54,52,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,46>>]}]},{dt,[],[{code,[],[<<123,119,111,114,100,115,105,122,101,44,32,101,120,116,101,114,110,97,108,125>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,114,117,101,32,119,111,114,100,32,115,105,122,101,32,111,102,32,116,104,101,32,101,109,117,108,97,116,111,114,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,115,105,122,101,32,111,102,32,97,32,112,111,105,110,116,101,114,46,32,84,104,101,32,118,97,108,117,101,32,105,115,32,103,105,118,101,110,32,105,110,32,98,121,116,101,115,32,97,115,32,97,110,32,105,110,116,101,103,101,114,46,32,79,110,32,97,32,112,117,114,101,32,51,50,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,52,32,105,115,32,114,101,116,117,114,110,101,100,46,32,79,110,32,97,32,54,52,45,98,105,116,32,97,114,99,104,105,116,101,99,116,117,114,101,44,32,56,32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]}]}]},#{signature => [{attribute,{3074,2},spec,{{erlang,system_info,1},[{type,{3094,10},'fun',[{type,{3094,10},product,[{atom,{3094,11},c_compiler_used}]},{type,{3094,31},tuple,[{type,{3094,32},atom,[]},{type,{3094,40},term,[]}]}]},{type,{3095,10},'fun',[{type,{3095,10},product,[{atom,{3095,11},check_io}]},{type,{3095,24},list,[{var,{3095,25},'_'}]}]},{type,{3096,10},'fun',[{type,{3096,10},product,[{atom,{3096,11},compat_rel}]},{type,{3096,26},integer,[]}]},{type,{3103,10},'fun',[{type,{3103,10},product,[{atom,{3103,11},delayed_node_table_gc}]},{type,{3103,37},union,[{atom,{3103,37},infinity},{type,{3103,48},non_neg_integer,[]}]}]},{type,{3112,10},'fun',[{type,{3112,10},product,[{atom,{3112,11},dynamic_trace}]},{type,{3112,29},union,[{atom,{3112,29},none},{atom,{3112,36},dtrace},{atom,{3112,45},systemtap}]}]},{type,{3113,10},'fun',[{type,{3113,10},product,[{atom,{3113,11},dynamic_trace_probes}]},{type,{3113,36},boolean,[]}]},{type,{3114,10},'fun',[{type,{3114,10},product,[{atom,{3114,11},eager_check_io}]},{type,{3114,30},boolean,[]}]},{type,{3116,10},'fun',[{type,{3116,10},product,[{atom,{3116,11},emu_type}]},{type,{3116,24},union,[{atom,{3116,24},opt},{atom,{3116,30},debug},{atom,{3116,38},gcov},{atom,{3116,45},valgrind},{atom,{3116,56},gprof},{atom,{3116,64},lcnt},{atom,{3116,71},frmptr}]}]},{type,{3117,10},'fun',[{type,{3117,10},product,[{atom,{3117,11},end_time}]},{type,{3117,24},non_neg_integer,[]}]},{type,{3125,10},'fun',[{type,{3125,10},product,[{atom,{3125,11},kernel_poll}]},{type,{3125,27},boolean,[]}]},{type,{3126,10},'fun',[{type,{3126,10},product,[{atom,{3126,11},loaded}]},{type,{3126,22},binary,[]}]},{type,{3127,10},'fun',[{type,{3127,10},product,[{type,{3127,11},union,[{atom,{3127,11},logical_processors},{atom,{3128,11},logical_processors_available},{atom,{3129,11},logical_processors_online}]}]},{type,{3129,41},union,[{atom,{3129,41},unknown},{type,{3129,51},pos_integer,[]}]}]},{type,{3131,10},'fun',[{type,{3131,10},product,[{atom,{3131,11},max_heap_size}]},{type,{3131,29},tuple,[{atom,{3131,30},max_heap_size},{ann_type,{3131,45},[{var,{3131,45},'MaxHeapSize'},{user_type,{3131,60},max_heap_size,[]}]}]}]},{type,{3137,10},'fun',[{type,{3137,10},product,[{atom,{3137,11},multi_scheduling}]},{type,{3137,32},union,[{atom,{3137,32},disabled},{atom,{3137,43},blocked},{atom,{3137,53},blocked_normal},{atom,{3137,70},enabled}]}]},{type,{3140,10},'fun',[{type,{3140,10},product,[{atom,{3140,11},normal_multi_scheduling_blockers}]},{type,{3140,48},list,[{ann_type,{3140,49},[{var,{3140,49},'Pid'},{type,{3140,56},pid,[]}]}]}]},{type,{3142,10},'fun',[{type,{3142,10},product,[{atom,{3142,11},os_monotonic_time_source}]},{type,{3142,40},list,[{type,{3142,41},tuple,[{type,{3142,42},atom,[]},{type,{3142,49},term,[]}]}]}]},{type,{3145,10},'fun',[{type,{3145,10},product,[{atom,{3145,11},port_parallelism}]},{type,{3145,32},boolean,[]}]},{type,{3146,10},'fun',[{type,{3146,10},product,[{atom,{3146,11},port_count}]},{type,{3146,26},non_neg_integer,[]}]},{type,{3165,10},'fun',[{type,{3165,10},product,[{atom,{3165,11},system_logger}]},{type,{3165,29},union,[{atom,{3165,29},logger},{atom,{3165,38},undefined},{type,{3165,50},pid,[]}]}]},{type,{3166,10},'fun',[{type,{3166,10},product,[{atom,{3166,11},system_version}]},{type,{3166,30},string,[]}]},{type,{3167,10},'fun',[{type,{3167,10},product,[{atom,{3167,11},threads}]},{type,{3167,23},boolean,[]}]},{type,{3174,10},'fun',[{type,{3174,10},product,[{atom,{3174,11},update_cpu_info}]},{type,{3174,31},union,[{atom,{3174,31},changed},{atom,{3174,41},unchanged}]}]},{type,{3176,10},'fun',[{type,{3176,10},product,[{type,{3176,11},union,[{atom,{3176,11},wordsize},{type,{3176,22},tuple,[{atom,{3176,23},wordsize},{atom,{3176,33},internal}]},{type,{3176,45},tuple,[{atom,{3176,46},wordsize},{atom,{3176,56},external}]}]}]},{type,{3176,70},union,[{integer,{3176,70},4},{integer,{3176,74},8}]}]},{type,{3177,10},'fun',[{type,{3177,10},product,[{atom,{3177,11},async_dist}]},{type,{3177,26},boolean,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,50,52,51>>,since => <<79,84,80,32,49,55,46,52,44,79,84,80,32,50,49,46,51,44,79,84,80,32,50,52,46,48,44,79,84,80,32,50,52,46,50,44,79,84,80,32,82,49,53,66,48,49,44,79,84,80,32,82,49,54,66>>}},{{function,system_monitor,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2250}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,115,101,116,116,105,110,103,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>]}]},<<32,97,115,32>>,{code,[],[<<123,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,110,111,32,115,101,116,116,105,110,103,115,32,101,120,105,115,116,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,111,110,101,32,116,104,97,116,32,119,97,115,32,115,101,116,46>>]}]},#{signature => [{attribute,{2250,2},spec,{{erlang,system_monitor,0},[{type,{2250,28},bounded_fun,[{type,{2250,28},'fun',[{type,{2250,28},product,[]},{var,{2250,34},'MonSettings'}]},[{type,{2251,7},constraint,[{atom,{2251,7},is_subtype},[{var,{2251,7},'MonSettings'},{type,{2251,22},union,[{atom,{2251,22},undefined},{type,{2251,34},tuple,[{var,{2251,36},'MonitorPid'},{var,{2251,48},'Options'}]}]}]]},{type,{2252,7},constraint,[{atom,{2252,7},is_subtype},[{var,{2252,7},'MonitorPid'},{type,{2252,21},pid,[]}]]},{type,{2253,7},constraint,[{atom,{2253,7},is_subtype},[{var,{2253,7},'Options'},{type,{2253,18},list,[{user_type,{2253,20},system_monitor_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,53,54,49>>}},{{function,system_monitor,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2258}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<87,104,101,110,32,99,97,108,108,101,100,32,119,105,116,104,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<44,32,97,108,108,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,32,109,111,110,105,116,111,114,105,110,103,32,115,101,116,116,105,110,103,115,32,97,114,101,32,99,108,101,97,114,101,100,46>>]},{p,[],[<<67,97,108,108,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,105,116,104,32>>,{code,[],[<<123,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<32,97,115,32,97,114,103,117,109,101,110,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,40,77,111,110,105,116,111,114,80,105,100,44,32,79,112,116,105,111,110,115,41>>]}]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,115,101,116,116,105,110,103,115,32,106,117,115,116,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>]}]},<<46>>]}]},#{signature => [{attribute,{2258,2},spec,{{erlang,system_monitor,1},[{type,{2258,28},bounded_fun,[{type,{2258,28},'fun',[{type,{2258,28},product,[{var,{2258,29},'Arg'}]},{var,{2258,37},'MonSettings'}]},[{type,{2259,7},constraint,[{atom,{2259,7},is_subtype},[{var,{2259,7},'Arg'},{type,{2259,14},union,[{atom,{2259,14},undefined},{type,{2259,26},tuple,[{var,{2259,28},'MonitorPid'},{var,{2259,40},'Options'}]}]}]]},{type,{2260,7},constraint,[{atom,{2260,7},is_subtype},[{var,{2260,7},'MonSettings'},{type,{2260,22},union,[{atom,{2260,22},undefined},{type,{2260,34},tuple,[{var,{2260,36},'MonitorPid'},{var,{2260,48},'Options'}]}]}]]},{type,{2261,7},constraint,[{atom,{2261,7},is_subtype},[{var,{2261,7},'MonitorPid'},{type,{2261,21},pid,[]}]]},{type,{2262,7},constraint,[{atom,{2262,7},is_subtype},[{var,{2262,7},'Options'},{type,{2262,18},list,[{user_type,{2262,20},system_monitor_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,53,55,53>>}},{{function,system_monitor,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2267}],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,116,115,32,116,104,101,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,32,109,111,110,105,116,111,114,105,110,103,32,111,112,116,105,111,110,115,46,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,114,101,99,101,105,118,105,110,103,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,109,111,110,105,116,111,114,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,108,111,110,103,95,103,99,44,32,84,105,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,116,97,107,101,115,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<84,105,109,101>>]},<<32,119,97,108,108,32,99,108,111,99,107,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,71,99,80,105,100,44,32,108,111,110,103,95,103,99,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<71,99,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,119,97,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<79,110,101,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,71,99,84,105,109,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<71,99,84,105,109,101>>]},<<32,105,115,32,116,104,101,32,116,105,109,101,32,102,111,114,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,109,105,108,108,105,115,101,99,111,110,100,115,46,32,84,104,101,32,111,116,104,101,114,32,116,117,112,108,101,115,32,97,114,101,32,116,97,103,103,101,100,32,119,105,116,104,32>>,{code,[],[<<104,101,97,112,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<109,98,117,102,95,115,105,122,101>>]},<<44,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,115,105,122,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]},<<46,32,84,104,101,115,101,32,116,117,112,108,101,115,32,97,114,101,32,101,120,112,108,97,105,110,101,100,32,105,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<32,40,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<41,46,32,78,101,119,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,44,32,97,110,100,32,116,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,108,105,115,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]}]},{dt,[],[{code,[],[<<123,108,111,110,103,95,115,99,104,101,100,117,108,101,44,32,84,105,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,114,117,110,115,32,117,110,105,110,116,101,114,114,117,112,116,101,100,32,102,111,114,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<84,105,109,101>>]},<<32,119,97,108,108,32,99,108,111,99,107,32,109,105,108,108,105,115,101,99,111,110,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,80,105,100,79,114,80,111,114,116,44,32,108,111,110,103,95,115,99,104,101,100,117,108,101,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<80,105,100,79,114,80,111,114,116>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,116,104,97,116,32,119,97,115,32,114,117,110,110,105,110,103,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,101,118,101,110,116,46>>]},{p,[],[<<73,102,32,97,32>>,{code,[],[<<112,105,100,40,41>>]},<<44,32,116,104,101,32,116,117,112,108,101,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,77,105,108,108,105,115,125>>]},<<44,32>>,{code,[],[<<123,105,110,44,32,76,111,99,97,116,105,111,110,125>>]},<<44,32,97,110,100,32>>,{code,[],[<<123,111,117,116,44,32,76,111,99,97,116,105,111,110,125>>]},<<32,97,114,101,32,112,114,101,115,101,110,116,44,32,119,104,101,114,101,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,101,105,116,104,101,114,32,97,110,32,77,70,65,32,40>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<41,32,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,104,101,114,101,32,116,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,115,99,104,101,100,117,108,101,100,32,105,110,47,111,117,116,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]},{p,[],[<<73,102,32,97,32>>,{code,[],[<<112,111,114,116,40,41>>]},<<44,32,116,104,101,32,116,117,112,108,101,115,32>>,{code,[],[<<123,116,105,109,101,111,117,116,44,32,77,105,108,108,105,115,125>>]},<<32,97,110,100,32>>,{code,[],[<<123,112,111,114,116,95,111,112,44,79,112,125>>]},<<32,97,114,101,32,112,114,101,115,101,110,116,46,32>>,{code,[],[<<79,112>>]},<<32,105,115,32,111,110,101,32,111,102,32>>,{code,[],[<<112,114,111,99,95,115,105,103>>]},<<44,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<44,32>>,{code,[],[<<105,110,112,117,116>>]},<<44,32>>,{code,[],[<<111,117,116,112,117,116>>]},<<44,32>>,{code,[],[<<101,118,101,110,116>>]},<<44,32,111,114,32>>,{code,[],[<<100,105,115,116,95,99,109,100>>]},<<44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,119,104,105,99,104,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,32,119,97,115,32,101,120,101,99,117,116,105,110,103,46>>]},{p,[],[{code,[],[<<112,114,111,99,95,115,105,103>>]},<<32,105,115,32,97,110,32,105,110,116,101,114,110,97,108,32,111,112,101,114,97,116,105,111,110,32,97,110,100,32,105,115,32,110,101,118,101,114,32,116,111,32,97,112,112,101,97,114,44,32,119,104,105,108,101,32,116,104,101,32,111,116,104,101,114,115,32,114,101,112,114,101,115,101,110,116,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,115,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<44,32>>,{code,[],[<<114,101,97,100,121,95,105,110,112,117,116>>]},<<44,32>>,{code,[],[<<114,101,97,100,121,95,111,117,116,112,117,116>>]},<<44,32>>,{code,[],[<<101,118,101,110,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<111,117,116,112,117,116,118>>]},<<32,40,119,104,101,110,32,116,104,101,32,112,111,114,116,32,105,115,32,117,115,101,100,32,98,121,32,100,105,115,116,114,105,98,117,116,105,111,110,41,46,32,86,97,108,117,101,32>>,{code,[],[<<77,105,108,108,105,115>>]},<<32,105,110,32,116,117,112,108,101,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,105,110,102,111,114,109,115,32,97,98,111,117,116,32,116,104,101,32,117,110,105,110,116,101,114,114,117,112,116,101,100,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,44,32,119,104,105,99,104,32,97,108,119,97,121,115,32,105,115,32,101,113,117,97,108,32,116,111,32,111,114,32,104,105,103,104,101,114,32,116,104,97,110,32,116,104,101,32>>,{code,[],[<<84,105,109,101>>]},<<32,118,97,108,117,101,32,115,117,112,112,108,105,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,116,114,97,99,101,46,32,78,101,119,32,116,117,112,108,101,115,32,99,97,110,32,98,101,32,97,100,100,101,100,32,116,111,32,116,104,101,32>>,{code,[],[<<73,110,102,111>>]},<<32,108,105,115,116,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,32,105,110,32,116,104,101,32,108,105,115,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,97,116,32,97,110,121,32,116,105,109,101,32,119,105,116,104,111,117,116,32,112,114,105,111,114,32,110,111,116,105,99,101,46>>]},{p,[],[<<84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,116,101,99,116,32,112,114,111,98,108,101,109,115,32,119,105,116,104,32,78,73,70,115,32,111,114,32,100,114,105,118,101,114,115,32,116,104,97,116,32,116,97,107,101,32,116,111,111,32,108,111,110,103,32,116,111,32,101,120,101,99,117,116,101,46,32,49,32,109,115,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,97,32,103,111,111,100,32,109,97,120,105,109,117,109,32,116,105,109,101,32,102,111,114,32,97,32,100,114,105,118,101,114,32,99,97,108,108,98,97,99,107,32,111,114,32,97,32,78,73,70,46,32,72,111,119,101,118,101,114,44,32,97,32,116,105,109,101,45,115,104,97,114,105,110,103,32,115,121,115,116,101,109,32,105,115,32,117,115,117,97,108,108,121,32,116,111,32,99,111,110,115,105,100,101,114,32,101,118,101,114,121,116,104,105,110,103,32,60,32,49,48,48,32,109,115,32,97,115,32,34,112,111,115,115,105,98,108,101,34,32,97,110,100,32,102,97,105,114,108,121,32,34,110,111,114,109,97,108,34,46,32,72,111,119,101,118,101,114,44,32,108,111,110,103,101,114,32,115,99,104,101,100,117,108,101,32,116,105,109,101,115,32,99,97,110,32,105,110,100,105,99,97,116,101,32,115,119,97,112,112,105,110,103,32,111,114,32,97,32,109,105,115,98,101,104,97,118,105,110,103,32,78,73,70,47,100,114,105,118,101,114,46,32,77,105,115,98,101,104,97,118,105,110,103,32,78,73,70,115,32,97,110,100,32,100,114,105,118,101,114,115,32,99,97,110,32,99,97,117,115,101,32,98,97,100,32,114,101,115,111,117,114,99,101,32,117,116,105,108,105,122,97,116,105,111,110,32,97,110,100,32,98,97,100,32,111,118,101,114,97,108,108,32,115,121,115,116,101,109,32,112,101,114,102,111,114,109,97,110,99,101,46>>]}]},{dt,[],[{code,[],[<<123,108,97,114,103,101,95,104,101,97,112,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,114,101,115,117,108,116,115,32,105,110,32,116,104,101,32,97,108,108,111,99,97,116,101,100,32,115,105,122,101,32,111,102,32,97,32,104,101,97,112,32,98,101,105,110,103,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,119,111,114,100,115,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,71,99,80,105,100,44,32,108,97,114,103,101,95,104,101,97,112,44,32,73,110,102,111,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<71,99,80,105,100>>]},<<32,97,110,100,32>>,{code,[],[<<73,110,102,111>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,102,111,114,32>>,{code,[],[<<108,111,110,103,95,103,99>>]},<<32,101,97,114,108,105,101,114,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,116,117,112,108,101,32,116,97,103,103,101,100,32,119,105,116,104,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,46>>]},{p,[],[<<84,104,101,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,115,105,122,101,115,32,111,102,32,97,108,108,32,109,101,109,111,114,121,32,98,108,111,99,107,115,32,97,108,108,111,99,97,116,101,100,32,102,111,114,32,97,108,108,32,104,101,97,112,32,103,101,110,101,114,97,116,105,111,110,115,32,97,102,116,101,114,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,101,113,117,97,108,32,116,111,32,111,114,32,104,105,103,104,101,114,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<46>>]},{p,[],[<<87,104,101,110,32,97,32,112,114,111,99,101,115,115,32,105,115,32,107,105,108,108,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32,105,116,32,105,115,32,107,105,108,108,101,100,32,98,101,102,111,114,101,32,116,104,101,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,99,111,109,112,108,101,116,101,32,97,110,100,32,116,104,117,115,32,110,111,32,108,97,114,103,101,32,104,101,97,112,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]}]},{dt,[],[{code,[],[<<98,117,115,121,95,112,111,114,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,103,101,116,115,32,115,117,115,112,101,110,100,101,100,32,98,101,99,97,117,115,101,32,105,116,32,115,101,110,100,115,32,116,111,32,97,32,98,117,115,121,32,112,111,114,116,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,83,117,115,80,105,100,44,32,98,117,115,121,95,112,111,114,116,44,32,80,111,114,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<83,117,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,103,111,116,32,115,117,115,112,101,110,100,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,111,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<98,117,115,121,95,100,105,115,116,95,112,111,114,116>>]},{a,[{id,<<98,117,115,121,95,100,105,115,116,95,112,111,114,116>>}],[]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,32,103,101,116,115,32,115,117,115,112,101,110,100,101,100,32,98,101,99,97,117,115,101,32,105,116,32,115,101,110,100,115,32,116,111,32,97,32,112,114,111,99,101,115,115,32,111,110,32,97,32,114,101,109,111,116,101,32,110,111,100,101,32,119,104,111,115,101,32,105,110,116,101,114,45,110,111,100,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,119,97,115,32,104,97,110,100,108,101,100,32,98,121,32,97,32,98,117,115,121,32,112,111,114,116,44,32,97,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,109,111,110,105,116,111,114,44,32,83,117,115,80,105,100,44,32,98,117,115,121,95,100,105,115,116,95,112,111,114,116,44,32,80,111,114,116,125>>]},<<32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<46,32>>,{code,[],[<<83,117,115,80,105,100>>]},<<32,105,115,32,116,104,101,32,112,105,100,32,116,104,97,116,32,103,111,116,32,115,117,115,112,101,110,100,101,100,32,119,104,101,110,32,115,101,110,100,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,32,105,110,116,101,114,45,110,111,100,101,32,99,111,109,109,117,110,105,99,97,116,105,111,110,32,112,111,114,116,32>>,{code,[],[<<80,111,114,116>>]},<<46>>]}]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,115,101,116,116,105,110,103,115,32,106,117,115,116,32,108,105,107,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,48>>]}]},<<46>>]},{p,[],[<<84,104,101,32,97,114,103,117,109,101,110,116,115,32,116,111,32>>,{code,[],[<<115,121,115,116,101,109,95,109,111,110,105,116,111,114,47,50>>]},<<32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,97,108,108,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,111,110,32,116,104,101,32,110,111,100,101,32,115,104,111,117,108,100,32,98,101,32,100,111,110,101,44,32,110,111,116,32,104,111,119,32,105,116,32,115,104,111,117,108,100,32,98,101,32,99,104,97,110,103,101,100,46,32,84,104,105,115,32,109,101,97,110,115,32,111,110,108,121,32,111,110,101,32,112,114,111,99,101,115,115,32,97,116,32,97,32,116,105,109,101,32,40>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<41,32,99,97,110,32,98,101,32,116,104,101,32,114,101,99,101,105,118,101,114,32,111,102,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,46,32,65,108,115,111,44,32,116,104,101,32,119,97,121,32,116,111,32,99,108,101,97,114,32,97,32,115,112,101,99,105,102,105,99,32,109,111,110,105,116,111,114,32,111,112,116,105,111,110,32,105,115,32,116,111,32,110,111,116,32,105,110,99,108,117,100,101,32,105,116,32,105,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<79,112,116,105,111,110,115>>]},<<46,32,65,108,108,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,105,110,103,32,119,105,108,108,44,32,104,111,119,101,118,101,114,44,32,98,101,32,99,108,101,97,114,101,100,32,105,102,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,116,101,114,109,105,110,97,116,101,115,46>>]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,110,111,32,115,112,101,99,105,97,108,32,111,112,116,105,111,110,32,118,97,108,117,101,115,32,40,108,105,107,101,32,122,101,114,111,41,32,116,111,32,99,108,101,97,114,32,97,110,32,111,112,116,105,111,110,46,32,83,111,109,101,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,104,97,118,101,32,97,32,117,110,115,112,101,99,105,102,105,101,100,32,109,105,110,105,109,117,109,32,118,97,108,117,101,46,32,76,111,119,101,114,32,118,97,108,117,101,115,32,119,105,108,108,32,98,101,32,97,100,106,117,115,116,101,100,32,116,111,32,116,104,101,32,109,105,110,105,109,117,109,32,118,97,108,117,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,105,115,32,99,117,114,114,101,110,116,108,121,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,109,111,110,105,116,111,114,32,97,108,108,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,119,105,116,104,32>>,{code,[],[<<123,108,111,110,103,95,103,99,44,32,48,125>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,102,32,97,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,103,101,116,115,32,115,111,32,108,97,114,103,101,32,116,104,97,116,32,105,116,32,105,116,115,101,108,102,32,115,116,97,114,116,115,32,116,111,32,99,97,117,115,101,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,109,101,115,115,97,103,101,115,32,119,104,101,110,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,110,103,44,32,116,104,101,32,109,101,115,115,97,103,101,115,32,101,110,108,97,114,103,101,32,116,104,101,32,112,114,111,99,101,115,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,110,100,32,112,114,111,98,97,98,108,121,32,109,97,107,101,32,116,104,101,32,112,114,111,98,108,101,109,32,119,111,114,115,101,46>>]},{p,[],[<<75,101,101,112,32,116,104,101,32,109,111,110,105,116,111,114,105,110,103,32,112,114,111,99,101,115,115,32,110,101,97,116,32,97,110,100,32,100,111,32,110,111,116,32,115,101,116,32,116,104,101,32,115,121,115,116,101,109,32,109,111,110,105,116,111,114,32,108,105,109,105,116,115,32,116,111,111,32,116,105,103,104,116,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<73,102,32>>,{code,[],[<<77,111,110,105,116,111,114,80,105,100>>]},<<32,105,115,32,110,111,116,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,46>>]}]}]},#{signature => [{attribute,{2267,2},spec,{{erlang,system_monitor,2},[{type,{2267,28},bounded_fun,[{type,{2267,28},'fun',[{type,{2267,28},product,[{var,{2267,29},'MonitorPid'},{var,{2267,41},'Options'}]},{var,{2267,53},'MonSettings'}]},[{type,{2268,7},constraint,[{atom,{2268,7},is_subtype},[{var,{2268,7},'MonitorPid'},{type,{2268,21},pid,[]}]]},{type,{2269,7},constraint,[{atom,{2269,7},is_subtype},[{var,{2269,7},'Options'},{type,{2269,18},list,[{user_type,{2269,20},system_monitor_option,[]}]}]]},{type,{2270,7},constraint,[{atom,{2270,7},is_subtype},[{var,{2270,7},'MonSettings'},{type,{2270,22},union,[{atom,{2270,22},undefined},{type,{2270,34},tuple,[{var,{2270,36},'OldMonitorPid'},{var,{2270,51},'OldOptions'}]}]}]]},{type,{2271,7},constraint,[{atom,{2271,7},is_subtype},[{var,{2271,7},'OldMonitorPid'},{type,{2271,24},pid,[]}]]},{type,{2272,7},constraint,[{atom,{2272,7},is_subtype},[{var,{2272,7},'OldOptions'},{type,{2272,21},list,[{user_type,{2272,23},system_monitor_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,53,57,51>>}},{{function,system_profile,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2277}],[<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,112,114,111,102,105,108,105,110,103,32,115,101,116,116,105,110,103,115,32,115,101,116,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>]}]},<<32,97,115,32>>,{code,[],[<<123,80,114,111,102,105,108,101,114,80,105,100,44,32,79,112,116,105,111,110,115,125>>]},<<44,32,111,114,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,111,32,115,101,116,116,105,110,103,115,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,111,110,101,32,116,104,97,116,32,119,97,115,32,115,101,116,46>>]}]},#{signature => [{attribute,{2277,2},spec,{{erlang,system_profile,0},[{type,{2277,28},bounded_fun,[{type,{2277,28},'fun',[{type,{2277,28},product,[]},{var,{2277,34},'ProfilerSettings'}]},[{type,{2278,7},constraint,[{atom,{2278,7},is_subtype},[{var,{2278,7},'ProfilerSettings'},{type,{2278,27},union,[{atom,{2278,27},undefined},{type,{2278,39},tuple,[{var,{2278,41},'ProfilerPid'},{var,{2278,54},'Options'}]}]}]]},{type,{2279,7},constraint,[{atom,{2279,7},is_subtype},[{var,{2279,7},'ProfilerPid'},{type,{2279,22},union,[{type,{2279,22},pid,[]},{type,{2279,30},port,[]}]}]]},{type,{2280,7},constraint,[{atom,{2280,7},is_subtype},[{var,{2280,7},'Options'},{type,{2280,18},list,[{user_type,{2280,20},system_profile_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,55,51,55>>}},{{function,system_profile,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2285}],[<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,121,115,116,101,109,95,112,114,111,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,116,115,32,115,121,115,116,101,109,32,112,114,111,102,105,108,101,114,32,111,112,116,105,111,110,115,46,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<32,105,115,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,111,114,32,112,111,114,116,32,114,101,99,101,105,118,105,110,103,32,112,114,111,102,105,108,105,110,103,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,114,101,99,101,105,118,101,114,32,105,115,32,101,120,99,108,117,100,101,100,32,102,114,111,109,32,97,108,108,32,112,114,111,102,105,108,105,110,103,46,32,84,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,114,111,102,105,108,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,120,99,108,117,115,105,118,101>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,115,121,110,99,104,114,111,110,111,117,115,32,99,97,108,108,32,116,111,32,97,32,112,111,114,116,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32,105,115,32,100,111,110,101,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,99,111,110,115,105,100,101,114,101,100,32,110,111,116,32,114,117,110,110,97,98,108,101,32,100,117,114,105,110,103,32,116,104,101,32,99,97,108,108,32,114,117,110,116,105,109,101,32,116,111,32,116,104,101,32,112,111,114,116,46,32,84,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,105,102,105,101,100,32,97,115,32>>,{code,[],[<<105,110,97,99,116,105,118,101>>]},<<44,32,97,110,100,32,108,97,116,101,114,32>>,{code,[],[<<97,99,116,105,118,101>>]},<<32,119,104,101,110,32,116,104,101,32,112,111,114,116,32,99,97,108,108,98,97,99,107,32,114,101,116,117,114,110,115,46>>]}]},{dt,[],[{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,97,98,108,101,95,112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,114,111,99,101,115,115,32,105,115,32,112,117,116,32,105,110,116,111,32,111,114,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,114,117,110,32,113,117,101,117,101,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,80,105,100,44,32,83,116,97,116,101,44,32,77,102,97,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46,32,82,117,110,110,105,110,103,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,105,110,115,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32,114,117,110,32,113,117,101,117,101,32,97,102,116,101,114,32,104,97,118,105,110,103,32,98,101,101,110,32,112,114,101,45,101,109,112,116,101,100,32,100,111,32,110,111,116,32,116,114,105,103,103,101,114,32,116,104,105,115,32,109,101,115,115,97,103,101,46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,97,98,108,101,95,112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,112,111,114,116,32,105,115,32,112,117,116,32,105,110,116,111,32,111,114,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,114,117,110,32,113,117,101,117,101,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,80,111,114,116,44,32,83,116,97,116,101,44,32,48,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,99,104,101,100,117,108,101,114>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,115,99,104,101,100,117,108,101,114,32,105,115,32,112,117,116,32,116,111,32,115,108,101,101,112,32,111,114,32,97,119,111,107,101,110,44,32,97,32,109,101,115,115,97,103,101,44,32>>,{code,[],[<<123,112,114,111,102,105,108,101,44,32,115,99,104,101,100,117,108,101,114,44,32,73,100,44,32,83,116,97,116,101,44,32,78,111,83,99,104,101,100,115,44,32,84,115,125>>]},<<44,32,105,115,32,115,101,110,116,32,116,111,32>>,{code,[],[<<80,114,111,102,105,108,101,114,80,105,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,99,111,110,115,105,115,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,105,110,116,101,103,101,114,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<123,101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41,44,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,115,116,97,109,112,115,32,105,110,32,112,114,111,102,105,108,101,32,109,101,115,115,97,103,101,115,32,105,110,99,108,117,100,101,32,97,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,116,104,97,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,40,41>>]},<<46,32,84,104,105,115,32,105,115,32,97,108,115,111,32,116,104,101,32,100,101,102,97,117,108,116,32,105,102,32,110,111,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,73,102,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,104,97,115,32,98,101,101,110,32,101,110,97,98,108,101,100,32,116,104,114,111,117,103,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<44,32,116,104,105,115,32,97,108,115,111,32,101,102,102,101,99,116,115,32,116,104,101,32,116,105,109,101,32,115,116,97,109,112,32,112,114,111,100,117,99,101,100,32,105,110,32,112,114,111,102,105,108,105,110,103,32,109,101,115,115,97,103,101,115,32,119,104,101,110,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,101,110,97,98,108,101,100,46>>]}]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101>>]},<<32,98,101,104,97,118,105,111,114,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]}]},#{signature => [{attribute,{2285,2},spec,{{erlang,system_profile,2},[{type,{2285,28},bounded_fun,[{type,{2285,28},'fun',[{type,{2285,28},product,[{var,{2285,29},'ProfilerPid'},{var,{2285,42},'Options'}]},{var,{2285,54},'ProfilerSettings'}]},[{type,{2286,7},constraint,[{atom,{2286,7},is_subtype},[{var,{2286,7},'ProfilerPid'},{type,{2286,22},union,[{type,{2286,22},pid,[]},{type,{2286,30},port,[]},{atom,{2286,39},undefined}]}]]},{type,{2287,7},constraint,[{atom,{2287,7},is_subtype},[{var,{2287,7},'Options'},{type,{2287,18},list,[{user_type,{2287,20},system_profile_option,[]}]}]]},{type,{2288,7},constraint,[{atom,{2288,7},is_subtype},[{var,{2288,7},'ProfilerSettings'},{type,{2288,27},union,[{atom,{2288,27},undefined},{type,{2288,39},tuple,[{type,{2288,41},union,[{type,{2288,41},pid,[]},{type,{2288,49},port,[]}]},{type,{2288,57},list,[{user_type,{2288,59},system_profile_option,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,55,53,50>>}},{{function,system_time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1837}],[<<115,121,115,116,101,109,95,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,43,32>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{signature => [{attribute,{1837,2},spec,{{erlang,system_time,0},[{type,{1837,25},'fun',[{type,{1837,25},product,[]},{type,{1837,31},integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,50,54>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,system_time,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1842}],[<<115,121,115,116,101,109,95,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<67,97,108,108,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,85,110,105,116,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,116,105,109,101,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{signature => [{attribute,{1842,2},spec,{{erlang,system_time,1},[{type,{1842,25},bounded_fun,[{type,{1842,25},'fun',[{type,{1842,25},product,[{var,{1842,26},'Unit'}]},{type,{1842,35},integer,[]}]},[{type,{1843,7},constraint,[{atom,{1843,7},is_subtype},[{var,{1843,7},'Unit'},{user_type,{1843,15},time_unit,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,52,56>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,term_to_binary,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2969}],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,101,110,99,111,100,105,110,103,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},{p,[],[<<84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,118,97,114,105,111,117,115,32,112,117,114,112,111,115,101,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,119,114,105,116,105,110,103,32,97,32,116,101,114,109,32,116,111,32,97,32,102,105,108,101,32,105,110,32,97,110,32,101,102,102,105,99,105,101,110,116,32,119,97,121,44,32,111,114,32,115,101,110,100,105,110,103,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,111,32,115,111,109,101,32,116,121,112,101,32,111,102,32,99,111,109,109,117,110,105,99,97,116,105,111,110,115,32,99,104,97,110,110,101,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,100,105,115,116,114,105,98,117,116,101,100,32,69,114,108,97,110,103,46>>]},{pre,[],[{code,[],[<<62,32,66,105,110,32,61,32,116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,104,101,108,108,111,41,46,10,60,60,49,51,49,44,49,48,48,44,48,44,53,44,49,48,52,44,49,48,49,44,49,48,56,44,49,48,56,44,49,49,49,62,62,10,62,32,104,101,108,108,111,32,61,32,98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,66,105,110,41,46,10,104,101,108,108,111>>]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,114,101,116,117,114,110,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,101,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,97,109,101,32,116,101,114,109,46>>]}]}]},#{signature => [{attribute,{2969,2},spec,{{term_to_binary,1},[{type,{2969,21},bounded_fun,[{type,{2969,21},'fun',[{type,{2969,21},product,[{var,{2969,22},'Term'}]},{user_type,{2969,31},ext_binary,[]}]},[{type,{2970,7},constraint,[{atom,{2970,7},is_subtype},[{var,{2970,7},'Term'},{type,{2970,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,55,48>>}},{{function,term_to_binary,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2974}],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,101,110,99,111,100,105,110,103,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]},{p,[],[<<67,117,114,114,101,110,116,108,121,32,115,117,112,112,111,114,116,101,100,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]}]},{dd,[],[{p,[],[<<67,111,109,112,114,101,115,115,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,84,104,101,32,99,111,109,112,114,101,115,115,101,100,32,102,111,114,109,97,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<32,97,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,55,66,46>>]}]},{dt,[],[{code,[],[<<123,99,111,109,112,114,101,115,115,101,100,44,32,76,101,118,101,108,125>>]}]},{dd,[],[{p,[],[<<67,111,109,112,114,101,115,115,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,116,111,32,97,32,103,105,118,101,110,32,108,101,118,101,108,46,32,84,104,101,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108,32,105,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32>>,{code,[],[<<76,101,118,101,108>>]},<<32,119,104,105,99,104,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,116,104,101,32,114,97,110,103,101,32,48,46,46,57,44,32,119,104,101,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<48>>]}]},{dd,[],[{p,[],[<<78,111,32,99,111,109,112,114,101,115,115,105,111,110,32,105,115,32,100,111,110,101,32,40,105,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,103,105,118,105,110,103,32,110,111,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,111,112,116,105,111,110,41,46>>]}]},{dt,[],[{code,[],[<<49>>]}]},{dd,[],[{p,[],[<<84,97,107,101,115,32,108,101,97,115,116,32,116,105,109,101,32,98,117,116,32,109,97,121,32,110,111,116,32,99,111,109,112,114,101,115,115,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,115,46>>]}]},{dt,[],[{code,[],[<<54>>]}]},{dd,[],[{p,[],[<<68,101,102,97,117,108,116,32,108,101,118,101,108,32,119,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,105,115,32,112,114,111,118,105,100,101,100,46>>]}]},{dt,[],[{code,[],[<<57>>]}]},{dd,[],[{p,[],[<<84,97,107,101,115,32,109,111,115,116,32,116,105,109,101,32,97,110,100,32,116,114,105,101,115,32,116,111,32,112,114,111,100,117,99,101,32,97,32,115,109,97,108,108,101,114,32,114,101,115,117,108,116,46,32,78,111,116,105,99,101,32,34,116,114,105,101,115,34,32,105,110,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,115,101,110,116,101,110,99,101,59,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,105,110,112,117,116,32,116,101,114,109,44,32,108,101,118,101,108,32,57,32,99,111,109,112,114,101,115,115,105,111,110,32,101,105,116,104,101,114,32,100,111,101,115,32,111,114,32,100,111,101,115,32,110,111,116,32,112,114,111,100,117,99,101,32,97,32,115,109,97,108,108,101,114,32,114,101,115,117,108,116,32,116,104,97,110,32,108,101,118,101,108,32,49,32,99,111,109,112,114,101,115,115,105,111,110,46>>]}]}]}]},{dt,[{since,<<82,49,49,66,45,52>>}],[{code,[],[<<123,109,105,110,111,114,95,118,101,114,115,105,111,110,44,32,86,101,114,115,105,111,110,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,99,111,110,116,114,111,108,32,115,111,109,101,32,101,110,99,111,100,105,110,103,32,100,101,116,97,105,108,115,46,32,86,97,108,105,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<86,101,114,115,105,111,110>>]},<<32,97,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<48>>]}]},{dd,[],[{p,[],[<<70,108,111,97,116,115,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,97,32,116,101,120,116,117,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<65,116,111,109,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,108,97,116,105,110,49,32,115,116,114,105,110,103,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,108,97,116,105,110,49,32,119,104,105,108,101,32,111,110,108,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,108,97,116,105,110,49,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,117,116,102,56,46>>]}]},{dt,[],[{code,[],[<<49>>]}]},{dd,[],[{p,[],[<<70,108,111,97,116,115,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,97,32,109,111,114,101,32,115,112,97,99,101,45,101,102,102,105,99,105,101,110,116,32,97,110,100,32,101,120,97,99,116,32,119,97,121,32,40,110,97,109,101,108,121,32,105,110,32,116,104,101,32,54,52,45,98,105,116,32,73,69,69,69,32,102,111,114,109,97,116,44,32,114,97,116,104,101,114,32,116,104,97,110,32,99,111,110,118,101,114,116,101,100,32,116,111,32,97,32,116,101,120,116,117,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,41,46,32,65,115,32,102,114,111,109,32,69,114,108,97,110,103,47,79,84,80,32,82,49,49,66,45,52,44,32>>,{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]},<<32,99,97,110,32,100,101,99,111,100,101,32,116,104,105,115,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]},{p,[],[<<65,116,111,109,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,108,97,116,105,110,49,32,115,116,114,105,110,103,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,108,97,116,105,110,49,32,119,104,105,108,101,32,111,110,108,121,32,97,116,111,109,115,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,108,97,116,105,110,49,32,97,114,101,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,117,116,102,56,46>>]}]},{dt,[],[{code,[],[<<50>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,105,115,32,97,115,32,111,102,32,69,114,108,97,110,103,47,79,84,80,32,50,54,46,48,32,116,104,101,32>>,{em,[],[<<100,101,102,97,117,108,116>>]},<<46,32,65,116,111,109,115,32,97,114,101,32,117,110,99,111,110,100,105,116,105,111,110,97,108,108,121,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,117,116,102,56,46,32,69,114,108,97,110,103,47,79,84,80,32,115,121,115,116,101,109,115,32,97,115,32,111,102,32,82,49,54,66,32,99,97,110,32,100,101,99,111,100,101,32,116,104,105,115,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,46>>]}]}]}]},{dt,[{since,<<79,84,80,32,50,52,46,49>>}],[{code,[],[<<100,101,116,101,114,109,105,110,105,115,116,105,99>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,44,32,119,105,116,104,105,110,32,116,104,101,32,115,97,109,101,32,109,97,106,111,114,32,114,101,108,101,97,115,101,32,111,102,32,69,114,108,97,110,103,47,79,84,80,44,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,101,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,114,101,116,117,114,110,101,100,32,102,111,114,32,116,104,101,32,115,97,109,101,32,116,101,114,109,46,32,84,104,101,114,101,32,105,115,32,115,116,105,108,108,32,110,111,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,116,104,101,32,101,110,99,111,100,101,100,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,114,101,109,97,105,110,115,32,116,104,101,32,115,97,109,101,32,98,101,116,119,101,101,110,32,109,97,106,111,114,32,114,101,108,101,97,115,101,115,32,111,102,32,69,114,108,97,110,103,47,79,84,80,46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,46>>]}]},{dt,[{since,<<79,84,80,32,50,54,46,48>>}],[{code,[],[<<108,111,99,97,108>>]},{a,[{id,<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,95,108,111,99,97,108>>}],[]}]},{dd,[],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,119,105,108,108,32,99,97,117,115,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,116,111,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,108,111,99,97,108,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,119,104,105,99,104,32,119,104,101,110,32,100,101,99,111,100,101,100,32,98,121,32,116,104,101,32,115,97,109,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,119,105,108,108,32,112,114,111,100,117,99,101,32,97,32,116,101,114,109,32,105,100,101,110,116,105,99,97,108,32,116,111,32,116,104,101,32,101,110,99,111,100,101,100,32,116,101,114,109,32,101,118,101,110,32,119,104,101,110,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,97,110,100,47,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,105,110,102,111,95,99,114,101,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,114,101,97,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,104,97,118,101,32,99,104,97,110,103,101,100,32,98,101,116,119,101,101,110,32,101,110,99,111,100,105,110,103,32,97,110,100,32,100,101,99,111,100,105,110,103,46,32,87,104,101,110,32,101,110,99,111,100,105,110,103,32,119,105,116,104,111,117,116,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,44,32,108,111,99,97,108,32,105,100,101,110,116,105,102,105,101,114,115,32,115,117,99,104,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<112,105,100,115>>]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<112,111,114,116,115>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<114,101,102,101,114,101,110,99,101,115>>]},<<32,119,105,108,108,32,110,111,116,32,98,101,32,116,104,101,32,115,97,109,101,32,105,102,32,110,111,100,101,32,110,97,109,101,32,97,110,100,47,111,114,32,99,114,101,97,116,105,111,110,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,99,104,97,110,103,101,100,32,98,101,116,119,101,101,110,32,101,110,99,111,100,105,110,103,32,97,110,100,32,100,101,99,111,100,105,110,103,46,32,84,104,105,115,32,115,105,110,99,101,32,115,117,99,104,32,105,100,101,110,116,105,102,105,101,114,115,32,114,101,102,101,114,32,116,111,32,97,32,115,112,101,99,105,102,105,99,32,110,111,100,101,32,98,121,32,110,111,100,101,32,110,97,109,101,32,97,110,100,32,99,114,101,97,116,105,111,110,46>>]},{p,[],[<<78,111,100,101,32,110,97,109,101,32,97,110,100,32,99,114,101,97,116,105,111,110,32,111,102,32,97,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,99,104,97,110,103,101,32,119,104,101,110,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,105,115,32,115,116,97,114,116,101,100,32,111,114,32,115,116,111,112,112,101,100,46,32,84,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,105,115,32,115,116,97,114,116,101,100,32,119,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,115,116,97,114,116,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<45,110,97,109,101>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<45,115,110,97,109,101>>]}]},<<32,99,111,109,109,97,110,100,32,108,105,110,101,32,97,114,103,117,109,101,110,116,115,46,32,78,111,116,101,32,116,104,97,116,32,116,104,101,32,97,99,116,117,97,108,32,115,116,97,114,116,32,111,102,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,104,97,112,112,101,110,115,32,97,102,116,101,114,32,111,116,104,101,114,32,99,111,100,101,32,105,110,32,116,104,101,32,115,116,97,114,116,117,112,32,112,104,97,115,101,32,104,97,115,32,98,101,103,117,110,32,101,120,101,99,117,116,105,110,103,46,32,84,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,97,110,32,97,108,115,111,32,98,101,32,115,116,97,114,116,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,97,114,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,97,114,116,47,50>>]}]},<<32,97,110,100,32,115,116,111,112,112,101,100,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,110,101,116,95,107,101,114,110,101,108,35,115,116,111,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,101,116,95,107,101,114,110,101,108,58,115,116,111,112,47,49>>]}]},<<32,105,102,32,105,116,32,104,97,115,32,110,111,116,32,98,101,101,110,32,115,116,97,114,116,101,100,32,118,105,97,32,116,104,101,32,99,111,109,109,97,110,100,32,108,105,110,101,46>>]},{p,[],[<<84,104,101,32,100,101,99,111,100,105,110,103,32,111,102,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,44,32,117,115,105,110,103,32,102,111,114,32,101,120,97,109,112,108,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,40,41>>]}]},<<44,32,119,105,108,108,32,116,114,121,32,116,111,32,118,101,114,105,102,121,32,116,104,97,116,32,116,104,101,32,116,101,114,109,32,97,99,116,117,97,108,108,121,32,119,97,115,32,101,110,99,111,100,101,100,32,98,121,32,116,104,101,32,115,97,109,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,44,32,97,110,100,32,119,105,108,108,32,105,110,32,116,104,101,32,118,97,115,116,32,109,97,106,111,114,105,116,121,32,111,102,32,99,97,115,101,115,32,102,97,105,108,32,105,102,32,116,104,101,32,101,110,99,111,100,105,110,103,32,119,97,115,32,112,101,114,102,111,114,109,101,100,32,98,121,32,97,110,111,116,104,101,114,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,89,111,117,32,115,104,111,117,108,100,32,104,111,119,101,118,101,114,32>>,{em,[],[<<110,111,116>>]},<<32,116,114,117,115,116,32,116,104,97,116,32,116,104,105,115,32,118,101,114,105,102,105,99,97,116,105,111,110,32,119,105,108,108,32,119,111,114,107,32,105,110,32,97,108,108,32,99,97,115,101,115,46,32,89,111,117,32>>,{em,[],[<<115,104,111,117,108,100>>]},<<32,109,97,107,101,32,115,117,114,101,32,116,111,32>>,{em,[],[<<111,110,108,121>>]},<<32,100,101,99,111,100,101,32,116,101,114,109,115,32,101,110,99,111,100,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,32,111,110,32,116,104,101,32,115,97,109,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,97,115,32,116,104,101,32,111,110,101,32,116,104,97,116,32,101,110,99,111,100,101,100,32,116,104,101,32,116,101,114,109,115,46>>]},{p,[],[<<83,105,110,99,101,32,105,116,32,105,115,32,111,110,108,121,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,104,97,116,32,101,110,99,111,100,101,100,32,97,32,116,101,114,109,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,32,116,104,97,116,32,99,97,110,32,100,101,99,111,100,101,32,105,116,44,32,116,104,101,32,108,111,99,97,108,32,101,110,99,111,100,105,110,103,32,105,115,32,116,121,112,105,99,97,108,108,121,32,112,105,101,99,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,111,32,112,114,111,100,117,99,101,32,97,32,114,101,112,108,121,32,116,111,32,119,104,101,114,101,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,101,110,99,111,100,105,110,103,32,111,114,105,103,105,110,97,116,101,115,32,102,114,111,109,46,32,73,102,32,97,32,116,101,114,109,32,101,110,99,111,100,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,32,105,115,32,115,116,114,105,112,112,101,100,32,111,102,32,105,116,115,32,108,101,97,100,105,110,103,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,44,32,105,116,32,99,97,110,32,98,101,32,97,100,100,101,100,32,97,115,32,112,97,114,116,32,111,102,32,97,32,108,97,114,103,101,114,32,116,101,114,109,32,40,102,111,114,32,101,120,97,109,112,108,101,32,97,115,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32,97,32,116,117,112,108,101,41,32,119,104,101,110,32,101,110,99,111,100,105,110,103,32,111,110,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,117,115,105,110,103,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{a,[{href,<<101,114,108,95,105,110,116,101,114,102,97,99,101,58,101,105>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<101,105>>]},<<46,32,73,110,32,116,104,101,32>>,{code,[],[<<101,105>>]},<<32,99,97,115,101,44,32,121,111,117,32,119,111,117,108,100,32,115,116,114,105,112,32,105,116,32,111,102,32,116,104,101,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,108,95,105,110,116,101,114,102,97,99,101,58,101,105,35,101,105,95,100,101,99,111,100,101,95,118,101,114,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,105,95,100,101,99,111,100,101,95,118,101,114,115,105,111,110,40,41>>]}]},<<32,97,110,100,32,116,104,101,110,32,97,100,100,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,108,111,99,97,108,32,101,110,99,111,100,105,110,103,32,116,111,32,119,104,97,116,32,121,111,117,32,97,114,101,32,101,110,99,111,100,105,110,103,32,117,115,105,110,103,32,102,111,114,32,101,120,97,109,112,108,101,32>>,{a,[{href,<<101,114,108,95,105,110,116,101,114,102,97,99,101,58,101,105,35,101,105,95,120,95,97,112,112,101,110,100,95,98,117,102>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,105,95,120,95,97,112,112,101,110,100,95,98,117,102,40,41>>]}]},<<46>>]},{p,[],[<<65,32,103,111,111,100,32,101,120,97,109,112,108,101,32,111,102,32,119,104,101,110,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,44,32,105,115,32,119,104,101,110,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,107,101,32,97,32,114,101,113,117,101,115,116,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32,116,111,32,97,32,112,111,114,116,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<100,114,105,118,101,114>>]},<<32,97,110,100,32,117,116,105,108,105,122,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,112,114,111,99,101,115,115,101,115,35,114,101,99,101,105,118,105,110,103,45,109,101,115,115,97,103,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,101,108,101,99,116,105,118,101,32,114,101,99,101,105,118,101,32,111,112,116,105,109,105,122,97,116,105,111,110>>]},<<32,119,104,101,110,32,114,101,99,101,105,118,105,110,103,32,116,104,101,32,114,101,112,108,121,46,32,73,110,32,116,104,105,115,32,115,99,101,110,97,114,105,111,32,121,111,117,32,119,97,110,116,32,116,111,32,99,114,101,97,116,101,32,97,32,114,101,102,101,114,101,110,99,101,44,32,115,101,114,105,97,108,105,122,101,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,111,110,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,44,32,112,97,115,115,32,116,104,105,115,32,116,111,32,116,104,101,32,100,114,105,118,101,114,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,44,32,97,110,100,32,116,104,101,110,32,119,97,105,116,32,102,111,114,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,105,110,32,97,32,115,101,108,101,99,116,105,118,101,32,114,101,99,101,105,118,101,32,109,97,116,99,104,105,110,103,32,111,110,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46,32,84,104,101,32,100,114,105,118,101,114,32,115,104,111,117,108,100,32,115,101,110,100,32,116,104,101,32,114,101,112,108,121,32,117,115,105,110,103,32,101,105,116,104,101,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,101,114,108,95,100,114,118,95,111,117,116,112,117,116,95,116,101,114,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,100,114,118,95,111,117,116,112,117,116,95,116,101,114,109,40,41>>]}]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,101,114,108,95,100,114,118,95,115,101,110,100,95,116,101,114,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,114,108,95,100,114,118,95,115,101,110,100,95,116,101,114,109,40,41>>]}]},<<32,117,115,105,110,103,32,116,104,101,32,116,101,114,109,32,116,121,112,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,114,105,118,101,114,35,69,82,76,95,68,82,86,95,69,88,84,50,84,69,82,77>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<69,82,76,95,68,82,86,95,69,88,84,50,84,69,82,77>>]}]},<<32,102,111,114,32,116,104,101,44,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,44,32,112,114,101,118,105,111,117,115,108,121,32,114,101,99,101,105,118,101,100,32,114,101,102,101,114,101,110,99,101,32,111,110,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46,32,78,111,116,101,32,116,104,97,116,32,121,111,117,32,115,104,111,117,108,100,32,110,111,116,32,115,116,114,105,112,32,116,104,101,32,108,101,97,100,105,110,103,32,118,101,114,115,105,111,110,32,110,117,109,98,101,114,32,102,114,111,109,32,116,104,101,32,108,111,99,97,108,32,101,110,99,111,100,105,110,103,32,119,104,101,110,32,117,115,105,110,103,32,116,104,101,32,116,101,114,109,32,116,121,112,101,32>>,{code,[],[<<69,82,76,95,68,82,86,95,69,88,84,50,84,69,82,77>>]},<<32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,97,108,105,116,121,46,32,73,102,32,121,111,117,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,100,111,32,110,111,116,32,101,110,99,111,100,101,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,111,112,116,105,111,110,44,32,97,110,100,32,116,104,101,32,100,105,115,116,114,105,98,117,116,105,111,110,32,105,115,32,115,116,97,114,116,101,100,32,111,114,32,115,116,111,112,112,101,100,32,119,104,105,108,101,32,116,104,101,32,114,101,113,117,101,115,116,32,105,115,32,111,110,103,111,105,110,103,44,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,109,97,100,101,32,116,104,101,32,114,101,113,117,101,115,116,32,119,105,108,108,32,104,97,110,103,32,105,110,100,101,102,105,110,105,116,101,108,121,32,115,105,110,99,101,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,105,110,32,116,104,101,32,114,101,112,108,121,32,109,101,115,115,97,103,101,32,119,105,108,108,32,110,101,118,101,114,32,109,97,116,99,104,46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<100,101,116,101,114,109,105,110,105,115,116,105,99>>]},<<32,111,112,116,105,111,110,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,101,120,116,95,100,105,115,116,35,76,79,67,65,76,95,69,88,84>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<76,79,67,65,76,95,69,88,84>>]}]},<<32,116,97,103,32,105,110,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]}]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<98,105,110,97,114,121,95,116,111,95,116,101,114,109,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{2974,2},spec,{{term_to_binary,2},[{type,{2974,21},bounded_fun,[{type,{2974,21},'fun',[{type,{2974,21},product,[{var,{2974,22},'Term'},{var,{2974,28},'Options'}]},{user_type,{2974,40},ext_binary,[]}]},[{type,{2975,7},constraint,[{atom,{2975,7},is_subtype},[{var,{2975,7},'Term'},{type,{2975,15},term,[]}]]},{type,{2976,7},constraint,[{atom,{2976,7},is_subtype},[{var,{2976,7},'Options'},{type,{2976,18},list,[{type,{2976,19},union,[{atom,{2976,19},compressed},{type,{2977,10},tuple,[{atom,{2977,11},compressed},{ann_type,{2977,23},[{var,{2977,23},'Level'},{type,{2977,32},range,[{integer,{2977,32},0},{integer,{2977,35},9}]}]}]},{atom,{2978,10},deterministic},{type,{2979,10},tuple,[{atom,{2979,11},minor_version},{ann_type,{2979,26},[{var,{2979,26},'Version'},{type,{2979,37},range,[{integer,{2979,37},0},{integer,{2979,40},2}]}]}]},{atom,{2980,10},local}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,49,56,57,56>>}},{{function,term_to_iovec,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2984}],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<101,120,116,95,105,111,118,101,99,40,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,105,110,103,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,110,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,46,32,84,104,101,32,99,97,108,108,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,116,101,114,109,95,116,111,95,105,111,118,101,99,40,84,101,114,109,41,41>>]},<<32,119,105,108,108,32,112,114,111,100,117,99,101,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,99,97,108,108,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,41>>]},<<46>>]},{p,[],[{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,105,115,32,97,32,112,117,114,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,41>>]},<<32,112,114,111,118,105,100,101,46,32>>,{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,114,101,102,101,114,32,100,105,114,101,99,116,108,121,32,116,111,32,111,102,102,32,104,101,97,112,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,99,111,112,121,105,110,103,32,116,104,101,32,98,105,110,97,114,121,32,100,97,116,97,32,105,110,116,111,32,116,104,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<46>>]}]},#{signature => [{attribute,{2984,2},spec,{{term_to_iovec,1},[{type,{2984,20},bounded_fun,[{type,{2984,20},'fun',[{type,{2984,20},product,[{var,{2984,21},'Term'}]},{user_type,{2984,30},ext_iovec,[]}]},[{type,{2985,7},constraint,[{atom,{2985,7},is_subtype},[{var,{2985,7},'Term'},{type,{2985,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,48,57,54>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,term_to_iovec,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2989}],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<101,120,116,95,105,111,118,101,99,40,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,112,114,111,100,117,99,101,32,116,104,101,32,115,97,109,101,32,101,110,99,111,100,105,110,103,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<44,32,98,117,116,32,119,105,116,104,32,97,110,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,46,32,84,104,101,32,99,97,108,108,32>>,{code,[],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,40,116,101,114,109,95,116,111,95,105,111,118,101,99,40,84,101,114,109,44,32,79,112,116,115,41,41>>]},<<32,119,105,108,108,32,112,114,111,100,117,99,101,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,84,101,114,109,44,32,79,112,116,115,41>>]},<<46>>]},{p,[],[<<67,117,114,114,101,110,116,108,121,32,114,101,99,111,103,110,105,115,101,100,32,111,112,116,105,111,110,115,32,97,114,101,32,97,108,108,32,111,112,116,105,111,110,115,32,114,101,99,111,103,110,105,115,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]},{p,[],[{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,105,115,32,97,32,112,117,114,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32>>,{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,40,41>>]},<<32,112,114,111,118,105,100,101,46,32>>,{code,[],[<<116,101,114,109,95,116,111,95,105,111,118,101,99,40,41>>]},<<32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,114,101,102,101,114,32,100,105,114,101,99,116,108,121,32,116,111,32,111,102,102,32,104,101,97,112,32,98,105,110,97,114,105,101,115,32,105,110,115,116,101,97,100,32,111,102,32,99,111,112,121,105,110,103,32,116,104,101,32,98,105,110,97,114,121,32,100,97,116,97,32,105,110,116,111,32,116,104,101,32,114,101,115,117,108,116,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,101,114,109,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{2989,2},spec,{{term_to_iovec,2},[{type,{2989,20},bounded_fun,[{type,{2989,20},'fun',[{type,{2989,20},product,[{var,{2989,21},'Term'},{var,{2989,27},'Options'}]},{user_type,{2989,39},ext_iovec,[]}]},[{type,{2990,7},constraint,[{atom,{2990,7},is_subtype},[{var,{2990,7},'Term'},{type,{2990,15},term,[]}]]},{type,{2991,7},constraint,[{atom,{2991,7},is_subtype},[{var,{2991,7},'Options'},{type,{2991,18},list,[{type,{2991,19},union,[{atom,{2991,19},compressed},{type,{2992,10},tuple,[{atom,{2992,11},compressed},{ann_type,{2992,23},[{var,{2992,23},'Level'},{type,{2992,32},range,[{integer,{2992,32},0},{integer,{2992,35},9}]}]}]},{atom,{2993,10},deterministic},{type,{2994,10},tuple,[{atom,{2994,11},minor_version},{ann_type,{2994,26},[{var,{2994,26},'Version'},{type,{2994,37},range,[{integer,{2994,37},0},{integer,{2994,40},2}]}]}]},{atom,{2995,10},local}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,49,50,49>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,throw,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2294}],[<<116,104,114,111,119,47,49>>],#{<<101,110>> => [{p,[],[<<82,97,105,115,101,115,32,97,110,32,101,120,99,101,112,116,105,111,110,32,111,102,32,99,108,97,115,115,32>>,{code,[],[<<116,104,114,111,119>>]},<<46,32,73,110,116,101,110,100,101,100,32,116,111,32,98,101,32,117,115,101,100,32,116,111,32,100,111,32,110,111,110,45,108,111,99,97,108,32,114,101,116,117,114,110,115,32,102,114,111,109,32,102,117,110,99,116,105,111,110,115,46>>]},{p,[],[<<73,102,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,99,97,116,99,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<99,97,116,99,104,32,101,120,112,114,101,115,115,105,111,110>>]},<<44,32,116,104,101,32,99,97,116,99,104,32,101,120,112,114,101,115,115,105,111,110,32,114,101,116,117,114,110,115,32,118,97,108,117,101,32>>,{code,[],[<<65,110,121>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,99,97,116,99,104,32,116,104,114,111,119,40,123,104,101,108,108,111,44,32,116,104,101,114,101,125,41,46,10,32,32,32,32,32,32,32,32,123,104,101,108,108,111,44,116,104,101,114,101,125>>]}]},{p,[],[<<73,102,32,101,118,97,108,117,97,116,101,100,32,119,105,116,104,105,110,32,97,32>>,{code,[],[<<116,114,121>>]},<<45,98,108,111,99,107,32,111,102,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,116,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,114,121,32,101,120,112,114,101,115,115,105,111,110>>]},<<44,32,116,104,101,32,118,97,108,117,101,32>>,{code,[],[<<65,110,121>>]},<<32,99,97,110,32,98,101,32,99,97,117,103,104,116,32,119,105,116,104,105,110,32,116,104,101,32,99,97,116,99,104,32,98,108,111,99,107,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<116,114,121,10,32,32,32,32,116,104,114,111,119,40,123,109,121,95,101,120,99,101,112,116,105,111,110,44,32,34,83,111,109,101,116,104,105,110,103,32,104,97,112,112,101,110,101,100,34,125,41,10,99,97,116,99,104,10,32,32,32,32,116,104,114,111,119,58,123,109,121,95,101,120,99,101,112,116,105,111,110,44,32,68,101,115,99,125,32,45,62,10,32,32,32,32,32,32,32,32,105,111,58,102,111,114,109,97,116,40,115,116,97,110,100,97,114,100,95,101,114,114,111,114,44,32,34,69,114,114,111,114,58,32,126,115,126,110,34,44,32,91,68,101,115,99,93,41,10,101,110,100>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<110,111,99,97,116,99,104>>]},<<32,105,102,32,110,111,116,32,99,97,117,103,104,116,32,98,121,32,97,110,32,101,120,99,101,112,116,105,111,110,32,104,97,110,100,108,101,114,46>>]},{p,[],[<<83,101,101,32,116,104,101,32,103,117,105,100,101,32,97,98,111,117,116,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<101,114,114,111,114,115,32,97,110,100,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]}]},#{signature => [{attribute,{2294,2},spec,{{throw,1},[{type,{2294,12},bounded_fun,[{type,{2294,12},'fun',[{type,{2294,12},product,[{var,{2294,13},'Any'}]},{type,{2294,21},no_return,[]}]},[{type,{2295,7},constraint,[{atom,{2295,7},is_subtype},[{var,{2295,7},'Any'},{type,{2295,14},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,49,52,57>>}},{{function,time,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2300}],[<<116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,97,115,32>>,{code,[],[<<123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125>>]},<<46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,122,111,110,101,32,97,110,100,32,68,97,121,108,105,103,104,116,32,83,97,118,105,110,103,32,84,105,109,101,32,99,111,114,114,101,99,116,105,111,110,32,100,101,112,101,110,100,32,111,110,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,105,109,101,40,41,46,10,123,57,44,52,50,44,52,52,125>>]}]}]},#{signature => [{attribute,{2300,2},spec,{{time,0},[{type,{2300,11},bounded_fun,[{type,{2300,11},'fun',[{type,{2300,11},product,[]},{var,{2300,17},'Time'}]},[{type,{2301,7},constraint,[{atom,{2301,7},is_subtype},[{var,{2301,7},'Time'},{remote_type,{2301,15},[{atom,{2301,15},calendar},{atom,{2301,24},time},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,49,55,55>>}},{{function,time_offset,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1897}],[<<116,105,109,101,95,111,102,102,115,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,105,110,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,105,109,101,32,117,110,105,116>>]},<<46,32,67,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,97,100,100,101,100,32,116,111,32,97,110,32,69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101,32,103,105,118,101,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101,46>>]},{p,[],[<<84,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,99,104,97,110,103,101,32,100,117,114,105,110,103,32,111,112,101,114,97,116,105,111,110,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<32,117,115,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,99,104,97,110,103,101,32,105,110,32,116,105,109,101,32,111,102,102,115,101,116,32,99,97,110,32,98,101,32,111,98,115,101,114,118,101,100,32,97,116,32,115,108,105,103,104,116,108,121,32,100,105,102,102,101,114,101,110,116,32,112,111,105,110,116,115,32,105,110,32,116,105,109,101,32,98,121,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,105,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,77,117,108,116,105,95,84,105,109,101,95,87,97,114,112,95,77,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,117,108,116,105,45,116,105,109,101,32,119,97,114,112,32,109,111,100,101>>]},<<44,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,99,104,97,110,103,101,100,32,119,104,101,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,100,101,116,101,99,116,115,32,116,104,97,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,79,83,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,104,97,115,32,99,104,97,110,103,101,100,46,32,84,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,119,105,108,108,44,32,104,111,119,101,118,101,114,44,32,110,111,116,32,100,101,116,101,99,116,32,116,104,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,46,32,65,32,116,97,115,107,32,99,104,101,99,107,105,110,103,32,116,104,101,32,116,105,109,101,32,111,102,102,115,101,116,32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,101,120,101,99,117,116,101,32,97,116,32,108,101,97,115,116,32,111,110,99,101,32,97,32,109,105,110,117,116,101,59,32,115,111,44,32,117,110,100,101,114,32,110,111,114,109,97,108,32,111,112,101,114,97,116,105,111,110,32,116,104,105,115,32,105,115,32,116,111,32,98,101,32,100,101,116,101,99,116,101,100,32,119,105,116,104,105,110,32,97,32,109,105,110,117,116,101,44,32,98,117,116,32,100,117,114,105,110,103,32,104,101,97,118,121,32,108,111,97,100,32,105,116,32,99,97,110,32,116,97,107,101,32,108,111,110,103,101,114,32,116,105,109,101,46>>]}]}]},#{signature => [{attribute,{1897,2},spec,{{erlang,time_offset,0},[{type,{1897,25},'fun',[{type,{1897,25},product,[]},{type,{1897,31},integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,49,57,50>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,time_offset,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1902}],[<<116,105,109,101,95,111,102,102,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,32,111,102,102,115,101,116,32,98,101,116,119,101,101,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,99,111,110,118,101,114,116,101,100,32,105,110,116,111,32,116,104,101,32>>,{code,[],[<<85,110,105,116>>]},<<32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{p,[],[<<83,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116>>]}]},{code,[],[<<40>>]},{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,95,111,102,102,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,95,111,102,102,115,101,116,40,41>>]}]},{code,[],[<<44,32,110,97,116,105,118,101,44,32,85,110,105,116,41>>]},<<32,104,111,119,101,118,101,114,32,111,112,116,105,109,105,122,101,100,32,102,111,114,32,99,111,109,109,111,110,108,121,32,117,115,101,100,32>>,{code,[],[<<85,110,105,116>>]},<<115,46>>]}]},#{signature => [{attribute,{1902,2},spec,{{erlang,time_offset,1},[{type,{1902,25},bounded_fun,[{type,{1902,25},'fun',[{type,{1902,25},product,[{var,{1902,26},'Unit'}]},{type,{1902,35},integer,[]}]},[{type,{1903,7},constraint,[{atom,{1903,7},is_subtype},[{var,{1903,7},'Unit'},{user_type,{1903,15},time_unit,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,50,50,52>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,timestamp,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1908}],[<<116,105,109,101,115,116,97,109,112,47,48>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,105,109,101,115,116,97,109,112>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,99,117,114,114,101,110,116,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,83,121,115,116,101,109,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101>>]},<<32,111,110,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125>>]},<<46,32,84,104,105,115,32,102,111,114,109,97,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,116,105,109,101,115,116,97,109,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,116,105,109,101,115,116,97,109,112,47,48>>]}]},<<32,97,110,100,32,116,104,101,32,100,101,112,114,101,99,97,116,101,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,111,119,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,110,111,119,47,48>>]}]},<<32,117,115,101,46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,101,32,101,120,105,115,116,101,110,99,101,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,40,41>>]},<<32,105,115,32,112,117,114,101,108,121,32,116,111,32,115,105,109,112,108,105,102,121,32,117,115,101,32,102,111,114,32,101,120,105,115,116,105,110,103,32,99,111,100,101,32,116,104,97,116,32,97,115,115,117,109,101,115,32,116,104,105,115,32,116,105,109,101,32,115,116,97,109,112,32,102,111,114,109,97,116,46,32,67,117,114,114,101,110,116,32,69,114,108,97,110,103,32,115,121,115,116,101,109,32,116,105,109,101,32,99,97,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,108,121,32,98,101,32,114,101,116,114,105,101,118,101,100,32,105,110,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,111,102,32,121,111,117,114,32,99,104,111,105,99,101,32,117,115,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,47,49>>]}]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,40,41>>]},<<32,66,73,70,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<116,105,109,101,115,116,97,109,112,40,41,32,45,62,10,32,32,32,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,61,32,101,114,108,97,110,103,58,115,121,115,116,101,109,95,116,105,109,101,40,109,105,99,114,111,115,101,99,111,110,100,41,44,10,32,32,32,32,77,101,103,97,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,100,105,118,32,49,48,48,48,95,48,48,48,95,48,48,48,95,48,48,48,44,10,32,32,32,32,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,100,105,118,32,49,48,48,48,95,48,48,48,32,45,32,77,101,103,97,83,101,99,115,42,49,48,48,48,95,48,48,48,44,10,32,32,32,32,77,105,99,114,111,83,101,99,115,32,61,32,69,114,108,97,110,103,83,121,115,116,101,109,84,105,109,101,32,114,101,109,32,49,48,48,48,95,48,48,48,44,10,32,32,32,32,123,77,101,103,97,83,101,99,115,44,32,83,101,99,115,44,32,77,105,99,114,111,83,101,99,115,125,46>>]}]},{p,[],[<<73,116,44,32,104,111,119,101,118,101,114,44,32,117,115,101,115,32,97,32,110,97,116,105,118,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,98,117,105,108,100,32,103,97,114,98,97,103,101,32,111,110,32,116,104,101,32,104,101,97,112,32,97,110,100,32,119,105,116,104,32,115,108,105,103,104,116,108,121,32,98,101,116,116,101,114,32,112,101,114,102,111,114,109,97,110,99,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,116,105,109,101,32,105,115,32>>,{em,[],[<<110,111,116>>]},<<32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,116,105,109,101,32,105,110,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,115,101,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,87,97,114,112,95,77,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,105,109,101,32,119,97,114,112,32,109,111,100,101,115>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]}]},#{signature => [{attribute,{1908,2},spec,{{erlang,timestamp,0},[{type,{1908,23},bounded_fun,[{type,{1908,23},'fun',[{type,{1908,23},product,[]},{var,{1908,29},'Timestamp'}]},[{type,{1909,7},constraint,[{atom,{1909,7},is_subtype},[{var,{1909,7},'Timestamp'},{user_type,{1909,20},timestamp,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,50,52,51>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,tl,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3000}],[<<116,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,116,97,105,108,32,111,102,32>>,{code,[],[<<76,105,115,116>>]},<<44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,108,105,115,116,32,109,105,110,117,115,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116>>]},{p,[],[<<73,116,32,119,111,114,107,115,32,119,105,116,104,32,105,109,112,114,111,112,101,114,32,108,105,115,116,115,46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,44,32,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,93,41,46,10,91,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,93,41,46,10,91,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,44,32,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93,41,46,10,91,103,117,105,108,105,101,115,44,32,98,101,97,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93>>]}]},{pre,[],[{code,[],[<<62,32,116,108,40,91,103,101,101,115,116,105,101,115,32,124,32,105,109,112,114,111,112,101,114,95,101,110,100,93,41,46,10,105,109,112,114,111,112,101,114,95,101,110,100>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<76,105,115,116>>]},<<32,105,115,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32>>,{code,[],[<<91,93>>]},<<46>>]}]},#{signature => [{attribute,{3000,2},spec,{{tl,1},[{type,{3000,9},bounded_fun,[{type,{3000,9},'fun',[{type,{3000,9},product,[{var,{3000,10},'List'}]},{var,{3000,19},'Tail'}]},[{type,{3001,7},constraint,[{atom,{3001,7},is_subtype},[{var,{3001,7},'List'},{type,{3001,15},nonempty_maybe_improper_list,[]}]]},{type,{3002,7},constraint,[{atom,{3002,7},is_subtype},[{var,{3002,7},'Tail'},{type,{3002,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,50,56,50>>}},{{function,trace,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2306}],[<<116,114,97,99,101,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<116,114,97,99,101,95,102,108,97,103>>}],[]}]},{p,[],[<<84,117,114,110,115,32,111,110,32,40,105,102,32>>,{code,[],[<<72,111,119,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,111,102,102,32,40,105,102,32>>,{code,[],[<<72,111,119,32,61,61,32,102,97,108,115,101>>]},<<41,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,105,110,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,114,111,99,101,115,115,101,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<46>>]},{p,[],[{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32,101,105,116,104,101,114,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,32,102,111,114,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,44,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,32,97,110,100,32,97,108,108,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{dt,[],[{code,[],[<<101,120,105,115,116,105,110,103,95,112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,99,117,114,114,101,110,116,108,121,32,101,120,105,115,116,105,110,103,32,112,111,114,116,115,46>>]},{dt,[],[{code,[],[<<110,101,119>>]}]},{dd,[],[<<65,108,108,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,112,111,114,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]}]},{dd,[],[<<65,108,108,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]},{dt,[],[{code,[],[<<110,101,119,95,112,111,114,116,115>>]}]},{dd,[],[<<65,108,108,32,112,111,114,116,115,32,116,104,97,116,32,119,105,108,108,32,98,101,32,99,114,101,97,116,101,100,32,105,110,32,116,104,101,32,102,117,116,117,114,101,46>>]}]},{p,[],[{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,108,97,103,115,32,40,116,104,101,32,34,109,101,115,115,97,103,101,32,116,97,103,115,34,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,108,105,115,116,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,114,97,99,101,32,109,101,115,115,97,103,101,115>>]}]},<<41,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<83,101,116,115,32,97,108,108,32,116,114,97,99,101,32,102,108,97,103,115,32,101,120,99,101,112,116,32>>,{code,[],[<<116,114,97,99,101,114>>]},<<32,97,110,100,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,119,104,105,99,104,32,97,114,101,32,105,110,32,116,104,101,105,114,32,110,97,116,117,114,101,32,100,105,102,102,101,114,101,110,116,32,116,104,97,110,32,116,104,101,32,111,116,104,101,114,115,46>>]}]},{dt,[],[{code,[],[<<115,101,110,100>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,101,110,100,105,110,103,32,111,102,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,110,100>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<39,114,101,99,101,105,118,101,39>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,114,101,99,101,105,118,105,110,103,32,111,102,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,99,101,105,118,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<39,114,101,99,101,105,118,101,39>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,99,101,114,116,97,105,110,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,83,112,101,99,105,102,121,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,116,111,32,116,114,97,99,101,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,97,108,108>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<115,105,108,101,110,116>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32,84,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]},<<44,32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,105,110,104,105,98,105,116,101,100,32,105,102,32,116,104,105,115,32,102,108,97,103,32,105,115,32,115,101,116,44,32,98,117,116,32,116,104,101,121,32,97,114,101,32,101,120,101,99,117,116,101,100,32,97,115,32,110,111,114,109,97,108,32,105,102,32,116,104,101,114,101,32,97,114,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46>>]},{p,[],[<<83,105,108,101,110,116,32,109,111,100,101,32,105,115,32,105,110,104,105,98,105,116,101,100,32,98,121,32,101,120,101,99,117,116,105,110,103,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,40,95,44,32,102,97,108,115,101,44,32,91,115,105,108,101,110,116,124,95,93,41>>]},<<44,32,111,114,32,98,121,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,101,120,101,99,117,116,105,110,103,32,116,104,101,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,115,105,108,101,110,116,44,32,102,97,108,115,101,125>>]},<<46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,97,99,105,108,105,116,97,116,101,115,32,115,101,116,116,105,110,103,32,117,112,32,97,32,116,114,97,99,101,32,111,110,32,109,97,110,121,32,111,114,32,101,118,101,110,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,84,104,101,32,116,114,97,99,101,32,99,97,110,32,116,104,101,110,32,98,101,32,97,99,116,105,118,97,116,101,100,32,97,110,100,32,100,101,97,99,116,105,118,97,116,101,100,32,117,115,105,110,103,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,115,105,108,101,110,116,44,66,111,111,108,125>>]},<<44,32,103,105,118,105,110,103,32,97,32,104,105,103,104,32,100,101,103,114,101,101,32,111,102,32,99,111,110,116,114,111,108,32,111,102,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,115,32,119,105,116,104,32,119,104,105,99,104,32,97,114,103,117,109,101,110,116,115,32,116,104,97,116,32,116,114,105,103,103,101,114,32,116,104,101,32,116,114,97,99,101,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,97,108,108>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,102,114,111,109>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},<<46,32,79,114,32,114,97,116,104,101,114,44,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,46>>]}]},{dt,[],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32,84,114,97,99,101,115,32,116,104,101,32,114,101,116,117,114,110,32,102,114,111,109,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,32,98,97,99,107,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46,32,79,110,108,121,32,119,111,114,107,115,32,102,111,114,32,102,117,110,99,116,105,111,110,115,32,116,114,97,99,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,116,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]},{p,[],[<<84,104,101,32,115,101,109,97,110,116,105,99,115,32,105,115,32,116,104,97,116,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,119,104,101,110,32,97,32,99,97,108,108,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,44,32,116,104,97,116,32,105,115,44,32,119,104,101,110,32,97,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,32,101,110,100,115,46,32,79,110,108,121,32,111,110,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,112,101,114,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,44,32,115,111,32,116,104,101,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,110,101,115,115,32,102,111,114,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,107,101,112,116,32,119,104,105,108,101,32,116,114,97,99,105,110,103,32,119,105,116,104,32,116,104,105,115,32,102,108,97,103,46,32,85,115,105,110,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,116,114,97,99,101,32,116,111,103,101,116,104,101,114,32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,107,110,111,119,32,101,120,97,99,116,108,121,32,105,110,32,119,104,105,99,104,32,102,117,110,99,116,105,111,110,32,97,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,97,116,32,97,110,121,32,116,105,109,101,46>>]},{p,[],[<<84,111,32,103,101,116,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,99,111,110,116,97,105,110,105,110,103,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,102,114,111,109,32,102,117,110,99,116,105,111,110,115,44,32,117,115,101,32,116,104,101,32>>,{code,[],[<<123,114,101,116,117,114,110,95,116,114,97,99,101,125>>]},<<32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,99,116,105,111,110,32,105,110,115,116,101,97,100,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,116,117,114,110,95,116,111>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,112,114,111,99,101,115,115,45,114,101,108,97,116,101,100,32,101,118,101,110,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,112,97,119,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,112,97,119,110,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,120,105,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,108,105,110,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,105,110,107>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,108,105,110,107>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,108,105,110,107>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,108,105,110,107,101,100>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,112,111,114,116,45,114,101,108,97,116,101,100,32,101,118,101,110,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,112,101,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,112,101,110>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,108,111,115,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<99,108,111,115,101,100>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,114,101,103,105,115,116,101,114>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,108,105,110,107,101,100>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<101,120,105,116,105,110,103>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,101,120,105,116,105,110,103,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,101,120,105,116,105,110,103,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110,95,101,120,105,116,105,110,103>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,105,110,103,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116,95,101,120,105,116,105,110,103>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,101,100,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116,95,101,120,105,116,101,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103,95,112,114,111,99,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,114,111,99,101,115,115,101,115,32,106,117,115,116,32,108,105,107,101,32>>,{code,[],[<<114,117,110,110,105,110,103>>]},<<46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,111,112,116,105,111,110,32,97,108,115,111,32,105,110,99,108,117,100,101,115,32,115,99,104,101,100,117,108,101,32,101,118,101,110,116,115,32,119,104,101,110,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,101,99,117,116,101,115,32,119,105,116,104,105,110,32,116,104,101,32,99,111,110,116,101,120,116,32,111,102,32,97,32,112,111,114,116,32,119,105,116,104,111,117,116,32,98,101,105,110,103,32,115,99,104,101,100,117,108,101,100,32,111,117,116,32,105,116,115,101,108,102,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<114,117,110,110,105,110,103,95,112,111,114,116,115>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,115,99,104,101,100,117,108,105,110,103,32,111,102,32,112,111,114,116,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,110>>]}]},<<32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,111,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,117,116>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]}]},{dd,[],[{p,[],[<<84,114,97,99,101,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,115,32,111,102,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<77,101,115,115,97,103,101,32,116,97,103,115,58,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]}]},<<44,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,101,110,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<103,99,95,109,105,110,111,114,95,101,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,32,116,105,109,101,32,115,116,97,109,112,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,32,97,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,110,111,119,40,41>>]},<<46>>]}]},{dt,[],[{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<65,32,103,108,111,98,97,108,32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,116,104,101,32,69,114,108,97,110,103,32,110,111,100,101,32,116,104,97,116,32,109,97,107,101,115,32,97,108,108,32,116,114,97,99,101,32,116,105,109,101,32,115,116,97,109,112,115,32,117,115,105,110,103,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,116,111,32,98,101,32,105,110,32,67,80,85,32,116,105,109,101,44,32,110,111,116,32,119,97,108,108,32,99,108,111,99,107,32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,110,111,116,32,98,101,32,117,115,101,100,32,105,102,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,111,114,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,101,110,97,98,108,101,100,46,32,79,110,108,121,32,97,108,108,111,119,101,100,32,119,105,116,104,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99,61,61,97,108,108>>]},<<46,32,73,102,32,116,104,101,32,104,111,115,116,32,109,97,99,104,105,110,101,32,79,83,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,104,105,103,104,45,114,101,115,111,108,117,116,105,111,110,32,67,80,85,32,116,105,109,101,32,109,101,97,115,117,114,101,109,101,110,116,115,44,32>>,{code,[],[<<116,114,97,99,101,47,51>>]},<<32,101,120,105,116,115,32,119,105,116,104,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,115,116,32,79,83,32,100,111,32,110,111,116,32,115,121,110,99,104,114,111,110,105,122,101,32,116,104,105,115,32,118,97,108,117,101,32,97,99,114,111,115,115,32,99,111,114,101,115,44,32,115,111,32,98,101,32,112,114,101,112,97,114,101,100,32,116,104,97,116,32,116,105,109,101,32,99,97,110,32,115,101,101,109,32,116,111,32,103,111,32,98,97,99,107,119,97,114,100,115,32,119,104,101,110,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,110,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,116,105,109,101,32,115,116,97,109,112,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]}]},<<46,32,84,104,105,115,32,102,108,97,103,32,111,118,101,114,114,105,100,101,115,32,102,108,97,103,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]}]},{dd,[],[{p,[],[<<73,110,99,108,117,100,101,115,32,97,110,32,116,105,109,101,32,115,116,97,109,112,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,69,114,108,97,110,103,95,77,111,110,111,116,111,110,105,99,95,84,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,108,97,110,103,32,109,111,110,111,116,111,110,105,99,32,116,105,109,101>>]},<<32,97,110,100,32,97,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,105,110,116,101,103,101,114,32,105,110,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32,84,104,101,32,116,105,109,101,32,115,116,97,109,112,32,40,84,115,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,102,111,114,109,97,116,32,97,110,100,32,118,97,108,117,101,32,97,115,32,112,114,111,100,117,99,101,100,32,98,121,32>>,{code,[],[<<123>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,111,116,111,110,105,99,95,116,105,109,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,109,111,110,111,116,111,110,105,99,95,116,105,109,101,40,110,97,110,111,115,101,99,111,110,100,41>>]}]},{code,[],[<<44>>]},<<32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]}]},{code,[],[<<125>>]},<<46,32,84,104,105,115,32,102,108,97,103,32,111,118,101,114,114,105,100,101,115,32,102,108,97,103,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,114,105,116,121>>]}]},{dd,[],[{p,[],[<<85,115,101,100,32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,46,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,105,116,121,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,103,115,125>>]},<<32,105,110,32,99,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,97,110,121,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,105,110,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,114,115,116,32,112,114,111,99,101,115,115,32,99,114,101,97,116,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,101,120,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,97,110,121,32,112,114,111,99,101,115,115,32,108,105,110,107,101,100,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,105,110,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,114,115,116,32,112,114,111,99,101,115,115,32,108,105,110,107,101,100,32,116,111,32,98,121,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,104,101,114,105,116,32,105,116,115,32,116,114,97,99,101,32,102,108,97,103,115,44,32,101,120,99,108,117,100,105,110,103,32,102,108,97,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,114,44,32,84,114,97,99,101,114,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,101,114,101,32,116,111,32,115,101,110,100,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32>>,{code,[],[<<84,114,97,99,101,114>>]},<<32,109,117,115,116,32,98,101,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,111,114,32,116,104,101,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,97,32,108,111,99,97,108,32,112,111,114,116,46>>]}]},{dt,[],[{code,[],[<<123,116,114,97,99,101,114,44,32,84,114,97,99,101,114,77,111,100,117,108,101,44,32,84,114,97,99,101,114,83,116,97,116,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,97,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,105,115,32,116,111,32,98,101,32,99,97,108,108,101,100,32,105,110,115,116,101,97,100,32,111,102,32,115,101,110,100,105,110,103,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,84,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,99,97,110,32,116,104,101,110,32,105,103,110,111,114,101,32,111,114,32,99,104,97,110,103,101,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,111,110,32,104,111,119,32,116,111,32,119,114,105,116,101,32,97,32,116,114,97,99,101,114,32,109,111,100,117,108,101,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,116,114,97,99,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,116,114,97,99,101,114,40,51,41>>]}]},<<46>>]}]}]},{p,[],[<<73,102,32,110,111,32>>,{code,[],[<<116,114,97,99,101,114>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,115,32,97,108,108,32,116,104,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46>>]},{p,[],[<<84,104,101,32,101,102,102,101,99,116,32,111,102,32,99,111,109,98,105,110,105,110,103,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<32,119,105,116,104,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,108,105,110,107>>]},<<32,97,108,111,110,101,46,32,76,105,107,101,119,105,115,101,32,102,111,114,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<32,97,110,100,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<46>>]},{p,[],[<<84,104,101,32,116,114,97,99,105,110,103,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,115,32,116,104,101,32>>,{em,[],[<<116,114,97,99,101,32,109,101,115,115,97,103,101,115>>]},<<32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,108,105,115,116,46,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,102,32,116,104,101,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,105,110,32,119,104,105,99,104,32,116,104,101,32,116,114,97,99,101,100,32,101,118,101,110,116,32,104,97,115,32,111,99,99,117,114,114,101,100,46,32,84,104,101,32,116,104,105,114,100,32,116,117,112,108,101,32,101,108,101,109,101,110,116,32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,97,103,46>>]},{p,[],[<<73,102,32,102,108,97,103,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,111,114,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,105,114,115,116,32,116,117,112,108,101,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<116,114,97,99,101,95,116,115>>]},<<32,105,110,115,116,101,97,100,44,32,97,110,100,32,116,104,101,32,116,105,109,101,32,115,116,97,109,112,32,105,115,32,97,100,100,101,100,32,97,115,32,97,110,32,101,120,116,114,97,32,101,108,101,109,101,110,116,32,108,97,115,116,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,116,117,112,108,101,46,32,73,102,32,109,117,108,116,105,112,108,101,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,115,32,97,114,101,32,112,97,115,115,101,100,44,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<32,104,97,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32,119,104,105,99,104,32,105,110,32,116,117,114,110,32,104,97,115,32,112,114,101,99,101,100,101,110,99,101,32,111,118,101,114,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<46,32,65,108,108,32,116,105,109,101,32,115,116,97,109,112,32,102,108,97,103,115,32,97,114,101,32,114,101,109,101,109,98,101,114,101,100,44,32,115,111,32,105,102,32,116,119,111,32,97,114,101,32,112,97,115,115,101,100,32,97,110,100,32,116,104,101,32,111,110,101,32,119,105,116,104,32,104,105,103,104,101,115,116,32,112,114,101,99,101,100,101,110,99,101,32,108,97,116,101,114,32,105,115,32,100,105,115,97,98,108,101,100,44,32,116,104,101,32,111,116,104,101,114,32,111,110,101,32,98,101,99,111,109,101,115,32,97,99,116,105,118,101,46>>]},{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,40,97,112,112,108,105,99,97,98,108,101,32,111,110,108,121,32,102,111,114,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<115,101,110,100>>]},<<32,97,110,100,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,105,110,103,41,32,99,111,110,116,97,105,110,115,32,97,32>>,{code,[],[<<123,109,101,115,115,97,103,101,125>>]},<<32,97,99,116,105,111,110,32,102,117,110,99,116,105,111,110,32,119,105,116,104,32,97,32,110,111,110,45,98,111,111,108,101,97,110,32,118,97,108,117,101,44,32,116,104,97,116,32,118,97,108,117,101,32,105,115,32,97,100,100,101,100,32,97,115,32,97,110,32,101,120,116,114,97,32,101,108,101,109,101,110,116,32,116,111,32,116,104,101,32,109,101,115,115,97,103,101,32,116,117,112,108,101,32,101,105,116,104,101,114,32,105,110,32,116,104,101,32,108,97,115,116,32,112,111,115,105,116,105,111,110,32,111,114,32,98,101,102,111,114,101,32,116,104,101,32,116,105,109,101,115,116,97,109,112,32,40,105,102,32,105,116,32,105,115,32,112,114,101,115,101,110,116,41,46>>]},{p,[],[<<84,114,97,99,101,32,109,101,115,115,97,103,101,115,58>>]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115>>}],[]},{dl,[],[{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,115,101,110,100,44,32,77,115,103,44,32,84,111,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,115,101,110,100,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,116,111,32,112,114,111,99,101,115,115,32>>,{code,[],[<<84,111>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,115,101,110,100,95,116,111,95,110,111,110,95,101,120,105,115,116,105,110,103,95,112,114,111,99,101,115,115,44,32,77,115,103,44,32,84,111,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,115,101,110,100,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<32,116,111,32,116,104,101,32,110,111,110,45,101,120,105,115,116,105,110,103,32,112,114,111,99,101,115,115,32>>,{code,[],[<<84,111>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,99,101,105,118,101>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,39,114,101,99,101,105,118,101,39,44,32,77,115,103,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,114,101,99,101,105,118,101,115,32,109,101,115,115,97,103,101,32>>,{code,[],[<<77,115,103>>]},<<46,32,73,102,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,116,105,109,101,45,111,117,116,44,32,97,32,114,101,99,101,105,118,101,32,115,116,97,116,101,109,101,110,116,32,99,97,110,32,104,97,118,101,32,116,105,109,101,100,32,111,117,116,44,32,111,114,32,116,104,101,32,112,114,111,99,101,115,115,32,114,101,99,101,105,118,101,100,32,97,32,109,101,115,115,97,103,101,32,119,105,116,104,32,116,104,101,32,112,97,121,108,111,97,100,32>>,{code,[],[<<116,105,109,101,111,117,116>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,97,108,108>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,99,97,108,108,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,99,97,108,108,115,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,111,102,32,99,97,108,108,115,32,97,114,101,32,110,101,118,101,114,32,115,117,112,112,108,105,101,100,44,32,111,110,108,121,32,116,104,101,32,99,97,108,108,32,97,110,100,32,105,116,115,32,97,114,103,117,109,101,110,116,115,46>>]},{p,[],[<<84,114,97,99,101,32,102,108,97,103,32>>,{code,[],[<<97,114,105,116,121>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,105,115,32,109,101,115,115,97,103,101,44,32,115,111,32,116,104,97,116,32>>,{code,[],[<<65,114,105,116,121>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,115,116,101,97,100,32,111,102,32>>,{code,[],[<<65,114,103,115>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,116,111>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,114,101,116,117,114,110,95,116,111,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,116,117,114,110,115,32>>,{em,[],[<<116,111>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,98,111,116,104,32,116,104,101,32,102,108,97,103,115,32>>,{code,[],[<<99,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,97,114,101,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,115,101,116,32,116,111,32,98,101,32,116,114,97,99,101,100,32,111,110,32>>,{em,[],[<<108,111,99,97,108>>]},<<32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,104,101,32,109,101,115,115,97,103,101,32,105,115,32,111,110,108,121,32,115,101,110,116,32,119,104,101,110,32,114,101,116,117,114,110,105,110,103,32,102,114,111,109,32,97,32,99,104,97,105,110,32,111,102,32,116,97,105,108,32,114,101,99,117,114,115,105,118,101,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32,119,104,101,114,101,32,97,116,32,108,101,97,115,116,32,111,110,101,32,99,97,108,108,32,103,101,110,101,114,97,116,101,100,32,97,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,40,116,104,97,116,32,105,115,44,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,109,97,116,99,104,101,100,44,32,97,110,100,32>>,{code,[],[<<123,109,101,115,115,97,103,101,44,32,102,97,108,115,101,125>>]},<<32,119,97,115,32,110,111,116,32,97,110,32,97,99,116,105,111,110,41,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,116,117,114,110,95,102,114,111,109>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,114,101,116,117,114,110,95,102,114,111,109,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,44,32,82,101,116,117,114,110,86,97,108,117,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,116,117,114,110,115,32>>,{em,[],[<<102,114,111,109>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,102,108,97,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,119,105,116,104,32,97,32>>,{code,[],[<<114,101,116,117,114,110,95,116,114,97,99,101>>]},<<32,111,114,32>>,{code,[],[<<101,120,99,101,112,116,105,111,110,95,116,114,97,99,101>>]},<<32,97,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,99,101,112,116,105,111,110,95,102,114,111,109>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,101,120,99,101,112,116,105,111,110,95,102,114,111,109,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,44,32,123,67,108,97,115,115,44,32,86,97,108,117,101,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,105,116,115,32>>,{em,[],[<<102,114,111,109>>]},<<32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,98,101,99,97,117,115,101,32,111,102,32,97,110,32,101,120,99,101,112,116,105,111,110,46,32,84,104,105,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,105,102,32,102,108,97,103,32>>,{code,[],[<<99,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,119,105,116,104,32,97,110,32>>,{code,[],[<<101,120,99,101,112,116,105,111,110,95,116,114,97,99,101>>]},<<32,97,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,115,112,97,119,110,44,32,80,105,100,50,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,115,112,97,119,110,115,32,97,32,110,101,119,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,97,114,103,117,109,101,110,116,32,108,105,115,116,44,32,98,117,116,32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,32,105,102,32,116,104,101,32,115,112,97,119,110,32,105,115,32,101,114,114,111,110,101,111,117,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,115,112,97,119,110,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,115,112,97,119,110,101,100,44,32,80,105,100,50,44,32,123,77,44,32,70,44,32,65,114,103,115,125,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,112,97,119,110,101,100,32,98,121,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<32,119,105,116,104,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,32,99,97,108,108,32,97,115,32,101,110,116,114,121,32,112,111,105,110,116,46>>]},{p,[],[{code,[],[<<65,114,103,115>>]},<<32,105,115,32,115,117,112,112,111,115,101,100,32,116,111,32,98,101,32,116,104,101,32,97,114,103,117,109,101,110,116,32,108,105,115,116,44,32,98,117,116,32,99,97,110,32,98,101,32,97,110,121,32,116,101,114,109,32,105,102,32,116,104,101,32,115,112,97,119,110,32,105,115,32,101,114,114,111,110,101,111,117,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,101,120,105,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,101,120,105,116,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,101,120,105,116,115,32,119,105,116,104,32,114,101,97,115,111,110,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,114,101,103,105,115,116,101,114>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,114,101,103,105,115,116,101,114,44,32,82,101,103,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,114,101,103,105,115,116,101,114,101,100,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,114,101,103,105,115,116,101,114>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,117,110,114,101,103,105,115,116,101,114,44,32,82,101,103,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,116,104,101,32,110,97,109,101,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,117,110,114,101,103,105,115,116,101,114,101,100,46,32,84,104,105,115,32,105,115,32,100,111,110,101,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,119,104,101,110,32,97,32,114,101,103,105,115,116,101,114,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,101,120,105,116,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,108,105,110,107>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,108,105,110,107,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,108,105,110,107,115,32,116,111,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,117,110,108,105,110,107>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,117,110,108,105,110,107,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,114,101,109,111,118,101,115,32,116,104,101,32,108,105,110,107,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,108,105,110,107,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,103,101,116,116,105,110,103,95,108,105,110,107,101,100,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,108,105,110,107,101,100,32,116,111,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,80,111,114,116,44,32,103,101,116,116,105,110,103,95,117,110,108,105,110,107,101,100,44,32,80,105,100,50,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100,80,111,114,116>>]},<<32,103,101,116,115,32,117,110,108,105,110,107,101,100,32,102,114,111,109,32,97,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100,50>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,112,101,110>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,111,112,101,110,44,32,80,105,100,44,32,68,114,105,118,101,114,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,111,112,101,110,115,32,97,32,110,101,119,32,112,111,114,116,32>>,{code,[],[<<80,111,114,116>>]},<<32,119,105,116,104,32,116,104,101,32,114,117,110,110,105,110,103,32>>,{code,[],[<<68,114,105,118,101,114>>]},<<46>>]},{p,[],[{code,[],[<<68,114,105,118,101,114>>]},<<32,105,115,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,100,114,105,118,101,114,32,97,115,32,97,110,32,97,116,111,109,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,99,108,111,115,101,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,99,108,111,115,101,100,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,99,108,111,115,101,115,32,119,105,116,104,32>>,{code,[],[<<82,101,97,115,111,110>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,101,120,105,116,105,110,103,95,112,114,111,99>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,105,110,32,124,32,105,110,95,101,120,105,116,105,110,103,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,114,117,110,46,32,84,104,101,32,112,114,111,99,101,115,115,32,114,117,110,115,32,105,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,77,44,32,70,44,32,65,114,105,116,121,125>>]},<<46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,105,110,103,95,112,114,111,99>>}],[]},{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,101,120,105,116,101,100,95,112,114,111,99>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,111,117,116,32,124,32,111,117,116,95,101,120,105,116,105,110,103,32,124,32,111,117,116,95,101,120,105,116,101,100,44,32,123,77,44,32,70,44,32,65,114,105,116,121,125,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,84,104,101,32,112,114,111,99,101,115,115,32,119,97,115,32,114,117,110,110,105,110,103,32,105,110,32,102,117,110,99,116,105,111,110,32,123,77,44,32,70,44,32,65,114,105,116,121,125,46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,105,110,95,112,111,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,105,110,44,32,67,111,109,109,97,110,100,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,116,111,32,114,117,110,46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,105,115,32,116,104,101,32,102,105,114,115,116,32,116,104,105,110,103,32,116,104,101,32,112,111,114,116,32,119,105,108,108,32,101,120,101,99,117,116,101,44,32,105,116,32,99,97,110,32,104,111,119,101,118,101,114,32,114,117,110,32,115,101,118,101,114,97,108,32,99,111,109,109,97,110,100,115,32,98,101,102,111,114,101,32,98,101,105,110,103,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]},{p,[],[<<84,104,101,32,112,111,115,115,105,98,108,101,32,99,111,109,109,97,110,100,115,32,97,114,101,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<99,108,111,115,101>>]},<<44,32>>,{code,[],[<<99,111,109,109,97,110,100>>]},<<44,32>>,{code,[],[<<99,111,110,110,101,99,116>>]},<<44,32>>,{code,[],[<<99,111,110,116,114,111,108>>]},<<44,32>>,{code,[],[<<102,108,117,115,104>>]},<<44,32>>,{code,[],[<<105,110,102,111>>]},<<44,32>>,{code,[],[<<108,105,110,107>>]},<<44,32>>,{code,[],[<<111,112,101,110>>]},<<44,32,97,110,100,32>>,{code,[],[<<117,110,108,105,110,107>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,111,117,116,95,112,111,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,111,114,116,44,32,111,117,116,44,32,67,111,109,109,97,110,100,32,124,32,48,125>>]}]},{dd,[],[{p,[],[<<87,104,101,110,32>>,{code,[],[<<80,111,114,116>>]},<<32,105,115,32,115,99,104,101,100,117,108,101,100,32,111,117,116,46,32,84,104,101,32,108,97,115,116,32,99,111,109,109,97,110,100,32,114,117,110,32,119,97,115,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<46,32,79,110,32,115,111,109,101,32,114,97,114,101,32,111,99,99,97,115,105,111,110,115,44,32,116,104,101,32,99,117,114,114,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,100,101,116,101,114,109,105,110,101,100,44,32,116,104,101,110,32,116,104,101,32,108,97,115,116,32,101,108,101,109,101,110,116,32,105,115,32>>,{code,[],[<<48>>]},<<46,32>>,{code,[],[<<67,111,109,109,97,110,100>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,99,111,109,109,97,110,100,115,32,97,115,32>>,{code,[],[<<105,110>>]}]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,115,116,97,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,105,110,111,114,95,115,116,97,114,116,44,32,73,110,102,111,125>>]}]},{dd,[],[{a,[{id,<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>}],[]},{p,[],[<<83,101,110,116,32,119,104,101,110,32,97,32,121,111,117,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,98,111,117,116,32,116,111,32,98,101,32,115,116,97,114,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,119,111,45,101,108,101,109,101,110,116,32,116,117,112,108,101,115,44,32,119,104,101,114,101,32,116,104,101,32,102,105,114,115,116,32,101,108,101,109,101,110,116,32,105,115,32,97,32,107,101,121,44,32,97,110,100,32,116,104,101,32,115,101,99,111,110,100,32,105,115,32,116,104,101,32,118,97,108,117,101,46,32,68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,97,110,121,32,111,114,100,101,114,32,111,102,32,116,104,101,32,116,117,112,108,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,107,101,121,115,32,97,114,101,32,100,101,102,105,110,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,117,115,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,98,108,111,99,107,32,117,115,101,100,32,102,111,114,32,115,116,111,114,105,110,103,32,116,104,101,32,104,101,97,112,32,97,110,100,32,116,104,101,32,115,116,97,99,107,46>>]},{dt,[],[{code,[],[<<111,108,100,95,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,117,115,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<111,108,100,95,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,101,109,111,114,121,32,98,108,111,99,107,32,117,115,101,100,32,102,111,114,32,115,116,111,114,105,110,103,32,116,104,101,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<115,116,97,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,115,116,97,99,107,46>>]},{dt,[],[{code,[],[<<114,101,99,101,110,116,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,100,97,116,97,32,116,104,97,116,32,115,117,114,118,105,118,101,100,32,116,104,101,32,112,114,101,118,105,111,117,115,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{dt,[],[{code,[],[<<109,98,117,102,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,99,111,109,98,105,110,101,100,32,115,105,122,101,32,111,102,32,109,101,115,115,97,103,101,32,98,117,102,102,101,114,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,112,114,111,99,101,115,115,46>>]},{dt,[],[{code,[],[<<98,105,110,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,117,110,105,113,117,101,32,111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<98,105,110,95,118,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,98,105,110,97,114,105,101,115,32,97,108,108,111,119,101,100,32,105,110,32,116,104,101,32,118,105,114,116,117,97,108,32,104,101,97,112,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,98,101,102,111,114,101,32,100,111,105,110,103,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{dt,[],[{code,[],[<<98,105,110,95,111,108,100,95,118,104,101,97,112,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,117,110,105,113,117,101,32,111,102,102,45,104,101,97,112,32,98,105,110,97,114,105,101,115,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,116,104,101,32,112,114,111,99,101,115,115,32,111,108,100,32,104,101,97,112,46>>]},{dt,[],[{code,[],[<<98,105,110,95,111,108,100,95,118,104,101,97,112,95,98,108,111,99,107,95,115,105,122,101>>]}]},{dd,[],[<<84,104,101,32,116,111,116,97,108,32,115,105,122,101,32,111,102,32,98,105,110,97,114,105,101,115,32,97,108,108,111,119,101,100,32,105,110,32,116,104,101,32,118,105,114,116,117,97,108,32,111,108,100,32,104,101,97,112,32,105,110,32,116,104,101,32,112,114,111,99,101,115,115,32,98,101,102,111,114,101,32,100,111,105,110,103,32,97,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{dt,[],[{code,[],[<<119,111,114,100,115,105,122,101>>]}]},{dd,[],[<<70,111,114,32,116,104,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<32,101,118,101,110,116,32,105,116,32,105,115,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,110,101,101,100,32,116,104,97,116,32,116,114,105,103,103,101,114,101,100,32,116,104,101,32,71,67,46,32,70,111,114,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,101,110,100>>]},<<32,101,118,101,110,116,32,105,116,32,105,115,32,116,104,101,32,115,105,122,101,32,111,102,32,114,101,99,108,97,105,109,101,100,32,109,101,109,111,114,121,32,61,32,115,116,97,114,116,32>>,{code,[],[<<104,101,97,112,95,115,105,122,101>>]},<<32,45,32,101,110,100,32>>,{code,[],[<<104,101,97,112,95,115,105,122,101>>]},<<46>>]}]},{p,[],[<<65,108,108,32,115,105,122,101,115,32,97,114,101,32,105,110,32,119,111,114,100,115,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]}]},<<32,105,115,32,114,101,97,99,104,101,100,32,100,117,114,105,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,115,105,122,101,115,32,116,104,97,116,32,116,114,105,103,103,101,114,101,100,32>>,{code,[],[<<109,97,120,95,104,101,97,112,95,115,105,122,101>>]},<<32,116,111,32,98,101,32,114,101,97,99,104,101,100,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,105,110,111,114,95,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,105,110,111,114,95,101,110,100,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,121,111,117,110,103,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,102,105,110,105,115,104,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,110,101,119,32,115,105,122,101,115,32,97,102,116,101,114,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,106,111,114,95,115,116,97,114,116>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,106,111,114,95,115,116,97,114,116,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,97,98,111,117,116,32,116,111,32,98,101,32,115,116,97,114,116,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<46>>]}]},{dt,[],[{a,[{id,<<116,114,97,99,101,95,51,95,116,114,97,99,101,95,109,101,115,115,97,103,101,115,95,103,99,95,109,97,106,111,114,95,101,110,100>>}],[]},{code,[],[<<123,116,114,97,99,101,44,32,80,105,100,44,32,103,99,95,109,97,106,111,114,95,101,110,100,44,32,73,110,102,111,125>>]}]},{dd,[],[{p,[],[<<83,101,110,116,32,119,104,101,110,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,32,105,115,32,102,105,110,105,115,104,101,100,46,32>>,{code,[],[<<73,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,115,97,109,101,32,107,105,110,100,32,111,102,32,108,105,115,116,32,97,115,32,105,110,32,109,101,115,115,97,103,101,32>>,{code,[],[<<103,99,95,109,105,110,111,114,95,115,116,97,114,116>>]},<<44,32,98,117,116,32,116,104,101,32,115,105,122,101,115,32,114,101,102,108,101,99,116,32,116,104,101,32,110,101,119,32,115,105,122,101,115,32,97,102,116,101,114,32,97,32,102,117,108,108,115,119,101,101,112,32,103,97,114,98,97,103,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]}]},{p,[],[<<73,102,32,116,104,101,32,116,114,97,99,105,110,103,32,112,114,111,99,101,115,115,47,112,111,114,116,32,100,105,101,115,32,111,114,32,116,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,114,101,116,117,114,110,115,32>>,{code,[],[<<114,101,109,111,118,101>>]},<<44,32,116,104,101,32,102,108,97,103,115,32,97,114,101,32,115,105,108,101,110,116,108,121,32,114,101,109,111,118,101,100,46>>]},{p,[],[<<69,97,99,104,32,112,114,111,99,101,115,115,32,99,97,110,32,111,110,108,121,32,98,101,32,116,114,97,99,101,100,32,98,121,32,111,110,101,32,116,114,97,99,101,114,46,32,84,104,101,114,101,102,111,114,101,44,32,97,116,116,101,109,112,116,115,32,116,111,32,116,114,97,99,101,32,97,110,32,97,108,114,101,97,100,121,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,102,97,105,108,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,97,32,110,117,109,98,101,114,32,105,110,100,105,99,97,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,109,97,116,99,104,101,100,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<49>>]},<<46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32>>,{code,[],[<<97,108,108>>]},<<32,111,114,32>>,{code,[],[<<101,120,105,115,116,105,110,103>>]},<<44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,114,111,99,101,115,115,101,115,32,114,117,110,110,105,110,103,46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,83,112,101,99>>]},<<32,105,115,32>>,{code,[],[<<110,101,119>>]},<<44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<48>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,97,114,103,117,109,101,110,116,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<99,112,117,95,116,105,109,101,115,116,97,109,112>>]},<<32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,97,108,108,32,112,108,97,116,102,111,114,109,115,46>>]}]},#{signature => [{attribute,{2306,2},spec,{{erlang,trace,3},[{type,{2306,19},bounded_fun,[{type,{2306,19},'fun',[{type,{2306,19},product,[{var,{2306,20},'PidPortSpec'},{var,{2306,33},'How'},{var,{2306,38},'FlagList'}]},{type,{2306,51},integer,[]}]},[{type,{2307,7},constraint,[{atom,{2307,7},is_subtype},[{var,{2307,7},'PidPortSpec'},{type,{2307,22},union,[{type,{2307,22},pid,[]},{type,{2307,30},port,[]},{atom,{2308,22},all},{atom,{2308,28},processes},{atom,{2308,40},ports},{atom,{2309,22},existing},{atom,{2309,33},existing_processes},{atom,{2309,54},existing_ports},{atom,{2310,22},new},{atom,{2310,28},new_processes},{atom,{2310,44},new_ports}]}]]},{type,{2311,7},constraint,[{atom,{2311,7},is_subtype},[{var,{2311,7},'How'},{type,{2311,14},boolean,[]}]]},{type,{2312,7},constraint,[{atom,{2312,7},is_subtype},[{var,{2312,7},'FlagList'},{type,{2312,19},list,[{user_type,{2312,20},trace_flag,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,51,48,56>>}},{{function,trace_delivered,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2321}],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,100,101,108,105,118,101,114,121,32,111,102,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,40,103,101,110,101,114,97,116,101,100,32,98,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<44,32>>,{a,[{href,<<107,101,114,110,101,108,58,115,101,113,95,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,113,95,116,114,97,99,101,40,51,41>>]}]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,115,121,115,116,101,109,95,112,114,111,102,105,108,101,47,50>>]}]},<<41,32,105,115,32,100,105,115,108,111,99,97,116,101,100,32,111,110,32,116,104,101,32,116,105,109,101,45,108,105,110,101,32,99,111,109,112,97,114,101,100,32,116,111,32,111,116,104,101,114,32,101,118,101,110,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,46,32,73,102,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,104,97,115,32,112,97,115,115,101,100,32,115,111,109,101,32,115,112,101,99,105,102,105,99,32,112,111,105,110,116,32,105,110,32,105,116,115,32,101,120,101,99,117,116,105,111,110,44,32,97,110,100,32,121,111,117,32,119,97,110,116,32,116,111,32,107,110,111,119,32,119,104,101,110,32,97,116,32,108,101,97,115,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,101,118,101,110,116,115,32,117,112,32,116,111,32,116,104,105,115,32,112,111,105,110,116,32,104,97,118,101,32,114,101,97,99,104,101,100,32,116,104,101,32,116,114,97,99,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<46>>]},{p,[],[<<87,104,101,110,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,100,101,108,105,118,101,114,101,100,32,116,111,32,116,104,101,32,116,114,97,99,101,114,32,117,112,32,116,111,32,116,104,101,32,112,111,105,110,116,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,114,101,97,99,104,101,100,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,99,97,108,108,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<44,32,116,104,101,110,32,97,32>>,{code,[],[<<123,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,44,32,84,114,97,99,101,101,44,32,82,101,102,125>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,109,101,115,115,97,103,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,105,109,112,108,121,32,116,104,97,116,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46,32,73,110,115,116,101,97,100,32,105,116,32,105,109,112,108,105,101,115,32,116,104,97,116,32,97,108,108,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,116,104,97,116,32>>,{em,[],[<<97,114,101,32,116,111,32,98,101,32,100,101,108,105,118,101,114,101,100>>]},<<32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,46,32,73,116,32,105,115,32,110,111,116,32,97,110,32,101,114,114,111,114,32,105,102,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,105,115,32,110,111,116,44,32,97,110,100,32,104,97,115,32,110,111,116,32,98,101,101,110,32,116,114,97,99,101,100,32,98,121,32,115,111,109,101,111,110,101,44,32,98,117,116,32,105,102,32,116,104,105,115,32,105,115,32,116,104,101,32,99,97,115,101,44,32>>,{em,[],[<<110,111>>]},<<32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,104,97,118,101,32,98,101,101,110,32,100,101,108,105,118,101,114,101,100,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,109,101,115,115,97,103,101,32,97,114,114,105,118,101,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,109,117,115,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,99,117,114,114,101,110,116,108,121,32,111,114,32,112,114,101,118,105,111,117,115,108,121,32,101,120,105,115,116,105,110,103,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,114,101,115,105,100,101,115,32,111,110,46,32,84,104,101,32,115,112,101,99,105,97,108,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,97,116,111,109,32>>,{code,[],[<<97,108,108>>]},<<32,100,101,110,111,116,101,115,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,116,104,97,116,32,99,117,114,114,101,110,116,108,121,32,97,114,101,32,116,114,97,99,101,100,32,105,110,32,116,104,101,32,110,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,117,115,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,116,114,97,99,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<84,114,97,99,101,114,32,77,111,100,117,108,101>>]},<<44,32,97,110,121,32,109,101,115,115,97,103,101,32,115,101,110,116,32,105,110,32,116,104,101,32,116,114,97,99,101,32,99,97,108,108,98,97,99,107,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,104,97,118,101,32,114,101,97,99,104,101,100,32,105,116,115,32,114,101,99,105,112,105,101,110,116,32,98,101,102,111,114,101,32,116,104,101,32>>,{code,[],[<<116,114,97,99,101,95,100,101,108,105,118,101,114,101,100>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,115,101,110,116,46>>]},{p,[],[<<69,120,97,109,112,108,101,58,32,80,114,111,99,101,115,115,32>>,{code,[],[<<65>>]},<<32,105,115,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<44,32,112,111,114,116,32>>,{code,[],[<<66>>]},<<32,105,115,32,116,114,97,99,101,114,44,32,97,110,100,32,112,114,111,99,101,115,115,32>>,{code,[],[<<67>>]},<<32,105,115,32,116,104,101,32,112,111,114,116,32,111,119,110,101,114,32,111,102,32>>,{code,[],[<<66>>]},<<46,32>>,{code,[],[<<67>>]},<<32,119,97,110,116,115,32,116,111,32,99,108,111,115,101,32>>,{code,[],[<<66>>]},<<32,119,104,101,110,32>>,{code,[],[<<65>>]},<<32,101,120,105,116,115,46,32,84,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,116,114,97,99,101,32,105,115,32,110,111,116,32,116,114,117,110,99,97,116,101,100,44,32>>,{code,[],[<<67>>]},<<32,99,97,110,32,99,97,108,108,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,65,41>>]},<<32,119,104,101,110,32>>,{code,[],[<<65>>]},<<32,101,120,105,116,115,44,32,97,110,100,32,119,97,105,116,32,102,111,114,32,109,101,115,115,97,103,101,32>>,{code,[],[<<123,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,44,32,65,44,32,82,101,102,125>>]},<<32,98,101,102,111,114,101,32,99,108,111,115,105,110,103,32>>,{code,[],[<<66>>]},<<46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<84,114,97,99,101,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,112,114,111,99,101,115,115,32,40,100,101,97,100,32,111,114,32,97,108,105,118,101,41,32,111,110,32,116,104,101,32,115,97,109,101,32,110,111,100,101,32,97,115,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,100,101,108,105,118,101,114,101,100,40,84,114,97,99,101,101,41>>]},<<32,114,101,115,105,100,101,115,32,111,110,46>>]}]},#{signature => [{attribute,{2321,2},spec,{{erlang,trace_delivered,1},[{type,{2321,29},bounded_fun,[{type,{2321,29},'fun',[{type,{2321,29},product,[{var,{2321,30},'Tracee'}]},{var,{2321,41},'Ref'}]},[{type,{2322,7},constraint,[{atom,{2322,7},is_subtype},[{var,{2322,7},'Tracee'},{type,{2322,17},union,[{type,{2322,17},pid,[]},{atom,{2322,25},all}]}]]},{type,{2323,7},constraint,[{atom,{2323,7},is_subtype},[{var,{2323,7},'Ref'},{type,{2323,14},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,50,57,54,56>>}},{{function,trace_info,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2328}],[<<116,114,97,99,101,95,105,110,102,111,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,102,108,97,103>>}],[]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,105,116,101,109,95,114,101,115,117,108,116>>}],[]},{li,[{name,<<116,114,97,99,101,95,105,110,102,111,95,114,101,116,117,114,110>>}],[]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<82,101,116,117,114,110,115,32,116,114,97,99,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,112,111,114,116,44,32,112,114,111,99,101,115,115,44,32,102,117,110,99,116,105,111,110,44,32,111,114,32,101,118,101,110,116,46>>]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,112,111,114,116,32,111,114,32,112,114,111,99,101,115,115>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,40,112,105,100,41,44,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<110,101,119>>]},<<44,32>>,{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]},<<44,32,111,114,32>>,{code,[],[<<110,101,119,95,112,111,114,116,115>>]},<<46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<110,101,119>>]},<<32,111,114,32>>,{code,[],[<<110,101,119,95,112,114,111,99,101,115,115,101,115>>]},<<32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,116,114,97,99,101,32,115,116,97,116,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,32,116,111,32,98,101,32,99,114,101,97,116,101,100,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<110,101,119,95,112,111,114,116,115>>]},<<32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,116,114,97,99,101,32,115,116,97,116,101,32,102,111,114,32,112,111,114,116,115,32,116,111,32,98,101,32,99,114,101,97,116,101,100,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,102,111,114,32,112,111,114,116,115,32,97,110,100,32,112,114,111,99,101,115,115,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,108,97,103,115>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,111,102,32,97,116,111,109,115,32,105,110,100,105,99,97,116,105,110,103,32,119,104,97,116,32,107,105,110,100,32,111,102,32,116,114,97,99,101,115,32,105,115,32,101,110,97,98,108,101,100,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,46,32,84,104,101,32,108,105,115,116,32,105,115,32,101,109,112,116,121,32,105,102,32,110,111,32,116,114,97,99,101,115,32,97,114,101,32,101,110,97,98,108,101,100,44,32,97,110,100,32,111,110,101,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,97,116,111,109,115,32,105,102,32,116,114,97,99,101,115,32,97,114,101,32,101,110,97,98,108,101,100,58,32>>,{code,[],[<<115,101,110,100>>]},<<44,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,115,112,97,119,110>>]},<<44,32>>,{code,[],[<<99,97,108,108>>]},<<44,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<44,32>>,{code,[],[<<112,114,111,99,115>>]},<<44,32>>,{code,[],[<<112,111,114,116,115>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,102,105,114,115,116,95,115,112,97,119,110>>]},<<44,32>>,{code,[],[<<115,101,116,95,111,110,95,108,105,110,107>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103,95,112,114,111,99,115>>]},<<44,32>>,{code,[],[<<114,117,110,110,105,110,103,95,112,111,114,116,115>>]},<<44,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<44,32>>,{code,[],[<<101,120,105,116,105,110,103>>]},<<44,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<115,116,114,105,99,116,95,109,111,110,111,116,111,110,105,99,95,116,105,109,101,115,116,97,109,112>>]},<<44,32>>,{code,[],[<<103,97,114,98,97,103,101,95,99,111,108,108,101,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<116,105,109,101,115,116,97,109,112>>]},<<44,32,97,110,100,32>>,{code,[],[<<97,114,105,116,121>>]},<<46,32,84,104,101,32,111,114,100,101,114,32,105,115,32,97,114,98,105,116,114,97,114,121,46>>]}]},{dt,[],[{code,[],[<<116,114,97,99,101,114>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,105,100,101,110,116,105,102,105,101,114,32,102,111,114,32,112,114,111,99,101,115,115,44,32,112,111,114,116,44,32,111,114,32,97,32,116,117,112,108,101,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,116,114,97,99,101,114,32,109,111,100,117,108,101,32,97,110,100,32,116,114,97,99,101,114,32,115,116,97,116,101,32,116,114,97,99,105,110,103,32,116,104,105,115,32,112,114,111,99,101,115,115,46,32,73,102,32,116,104,105,115,32,112,114,111,99,101,115,115,32,105,115,32,110,111,116,32,116,114,97,99,101,100,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]}]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,102,117,110,99,116,105,111,110>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<46,32,78,111,32,119,105,108,100,99,97,114,100,115,32,97,114,101,32,97,108,108,111,119,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,111,114,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,116,114,97,99,101,100,46,32,73,102,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<44,32,116,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,114,101,116,117,114,110,101,100,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32,99,111,100,101,32,116,104,97,116,32,119,105,108,108,32,98,101,32,108,111,97,100,101,100,46>>]},{p,[],[<<86,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<115,32,102,111,114,32,102,117,110,99,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<116,114,97,99,101,100>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,114,97,99,101,100,32,111,110,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,44,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,105,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,114,97,99,101,100,32,111,110,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,40,116,104,97,116,32,105,115,44,32,108,111,99,97,108,32,97,110,100,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,41,44,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,108,111,99,97,108,32,111,114,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,97,114,101,32,110,111,116,32,116,114,97,99,101,100,46>>]}]},{dt,[],[{code,[],[<<109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,108,111,99,97,108,108,121,32,111,114,32,103,108,111,98,97,108,108,121,32,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,101,102,105,110,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,101,116,97>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,116,97,45,116,114,97,99,101,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,44,32,112,111,114,116,44,32,111,114,32,116,114,97,99,101,32,109,111,100,117,108,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,109,101,116,97,45,116,114,97,99,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,109,101,116,97,45,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,111,110,99,101,32,100,101,116,101,99,116,101,100,32,116,104,97,116,32,116,104,101,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,32,105,115,32,105,110,118,97,108,105,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,101,116,97,95,109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,101,116,97,45,116,114,97,99,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,46,32,73,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,109,101,116,97,45,116,114,97,99,101,100,32,98,117,116,32,104,97,115,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,100,101,102,105,110,101,100,44,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<91,93>>]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,97,108,108,32,99,111,117,110,116,32,118,97,108,117,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,116,104,101,32,112,115,101,117,100,111,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,105,102,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,97,108,108,32,116,105,109,101,32,118,97,108,117,101,115,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,116,104,101,32,112,115,101,117,100,111,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,105,102,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,99,97,108,108,32,116,105,109,101,32,118,97,108,117,101,115,32,114,101,116,117,114,110,101,100,44,32>>,{code,[],[<<91,123,80,105,100,44,32,67,111,117,110,116,44,32,83,44,32,85,115,125,93>>]},<<44,32,105,115,32,97,32,108,105,115,116,32,111,102,32,101,97,99,104,32,112,114,111,99,101,115,115,32,116,104,97,116,32,101,120,101,99,117,116,101,100,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,110,100,32,105,116,115,32,115,112,101,99,105,102,105,99,32,99,111,117,110,116,101,114,115,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,109,101,109,111,114,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,97,99,99,117,109,117,108,97,116,101,100,32,110,117,109,98,101,114,32,111,102,32,119,111,114,100,115,32,97,108,108,111,99,97,116,101,100,32,98,121,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46,32,65,99,99,117,109,117,108,97,116,105,111,110,32,115,116,111,112,115,32,97,116,32,116,104,101,32,110,101,120,116,32,109,101,109,111,114,121,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,58,32,105,102,32,116,104,101,114,101,32,97,114,101,32>>,{code,[],[<<111,117,116,101,114>>]},<<44,32>>,{code,[],[<<109,105,100,100,108,101>>]},<<32,97,110,100,32>>,{code,[],[<<105,110,110,101,114>>]},<<32,102,117,110,99,116,105,111,110,115,32,101,97,99,104,32,97,108,108,111,99,97,116,105,110,103,32,51,32,119,111,114,100,115,44,32,98,117,116,32,111,110,108,121,32>>,{code,[],[<<111,117,116,101,114>>]},<<32,105,115,32,116,114,97,99,101,100,44,32,105,116,32,119,105,108,108,32,114,101,112,111,114,116,32,57,32,97,108,108,111,99,97,116,101,100,32,119,111,114,100,115,46,32,73,102,32>>,{code,[],[<<111,117,116,101,114>>]},<<32,97,110,100,32>>,{code,[],[<<105,110,110,101,114>>]},<<32,97,114,101,32,116,114,97,99,101,100,44,32,54,32,119,111,114,100,115,32,97,114,101,32,114,101,112,111,114,116,101,100,32,102,111,114,32>>,{code,[],[<<111,117,116,101,114>>]},<<32,97,110,100,32,51,32,102,111,114,32>>,{code,[],[<<105,110,110,101,114>>]},<<46,32,87,104,101,110,32,102,117,110,99,116,105,111,110,32,105,115,32,110,111,116,32,116,114,97,99,101,100,44,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,82,101,116,117,114,110,101,100,32,116,117,112,108,101,32,105,115,32>>,{code,[],[<<91,123,80,105,100,44,32,67,111,117,110,116,44,32,87,111,114,100,115,125,93>>]},<<44,32,102,111,114,32,101,97,99,104,32,112,114,111,99,101,115,115,32,116,104,97,116,32,101,120,101,99,117,116,101,100,32,116,104,101,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32>>,{code,[],[<<123,73,116,101,109,44,32,86,97,108,117,101,125>>]},<<32,116,117,112,108,101,115,32,102,111,114,32,97,108,108,32,111,116,104,101,114,32,105,116,101,109,115,44,32,111,114,32,114,101,116,117,114,110,115,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32,110,111,32,116,114,97,99,105,110,103,32,105,115,32,97,99,116,105,118,101,32,102,111,114,32,116,104,105,115,32,102,117,110,99,116,105,111,110,46>>]}]}]},{p,[],[{em,[],[<<84,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,110,32,101,118,101,110,116>>]},<<44,32>>,{code,[],[<<80,105,100,80,111,114,116,70,117,110,99,69,118,101,110,116>>]},<<32,105,115,32,116,111,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<115,101,110,100>>]},<<32,111,114,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<46>>]},{p,[],[<<79,110,101,32,118,97,108,105,100,32>>,{code,[],[<<73,116,101,109>>]},<<32,102,111,114,32,101,118,101,110,116,115,32,101,120,105,115,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,97,116,99,104,95,115,112,101,99>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32,116,104,105,115,32,101,118,101,110,116,44,32,105,102,32,105,116,32,104,97,115,32,111,110,101,44,32,111,114,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,110,111,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,104,97,115,32,98,101,101,110,32,115,101,116,46>>]}]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,73,116,101,109,44,32,86,97,108,117,101,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,105,110,102,111,114,109,97,116,105,111,110,32,97,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,46,32,73,102,32,97,32,112,105,100,32,102,111,114,32,97,32,100,101,97,100,32,112,114,111,99,101,115,115,32,119,97,115,32,115,112,101,99,105,102,105,101,100,44,32,111,114,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,110,111,110,45,101,120,105,115,116,105,110,103,32,102,117,110,99,116,105,111,110,44,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<46>>]}]},#{signature => [{attribute,{2328,2},spec,{{erlang,trace_info,2},[{type,{2328,24},bounded_fun,[{type,{2328,24},'fun',[{type,{2328,24},product,[{var,{2328,25},'PidPortFuncEvent'},{var,{2328,43},'Item'}]},{var,{2328,52},'Res'}]},[{type,{2329,7},constraint,[{atom,{2329,7},is_subtype},[{var,{2329,7},'PidPortFuncEvent'},{type,{2329,27},union,[{type,{2329,27},pid,[]},{type,{2329,35},port,[]},{atom,{2329,44},new},{atom,{2329,50},new_processes},{atom,{2329,66},new_ports},{type,{2330,24},tuple,[{var,{2330,25},'Module'},{var,{2330,33},'Function'},{var,{2330,43},'Arity'}]},{atom,{2330,52},on_load},{atom,{2330,62},send},{atom,{2330,69},'receive'}]}]]},{type,{2331,7},constraint,[{atom,{2331,7},is_subtype},[{var,{2331,7},'Module'},{type,{2331,17},module,[]}]]},{type,{2332,7},constraint,[{atom,{2332,7},is_subtype},[{var,{2332,7},'Function'},{type,{2332,19},atom,[]}]]},{type,{2333,7},constraint,[{atom,{2333,7},is_subtype},[{var,{2333,7},'Arity'},{type,{2333,16},arity,[]}]]},{type,{2334,7},constraint,[{atom,{2334,7},is_subtype},[{var,{2334,7},'Item'},{type,{2334,15},union,[{atom,{2334,15},flags},{atom,{2334,23},tracer},{atom,{2334,32},traced},{atom,{2334,41},match_spec},{atom,{2335,15},meta},{atom,{2335,22},meta_match_spec},{atom,{2335,40},call_count},{atom,{2335,53},call_time},{atom,{2335,65},call_memory},{atom,{2335,79},all}]}]]},{type,{2336,7},constraint,[{atom,{2336,7},is_subtype},[{var,{2336,7},'Res'},{user_type,{2336,14},trace_info_return,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,48,50,51>>}},{{function,trace_pattern,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3012}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,50>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,109,102,97>>}],[]}]},{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,69,118,101,110,116,44,32,77,97,116,99,104,83,112,101,99,44,32,91,93,41>>]}]},<<44,32,114,101,116,97,105,110,101,100,32,102,111,114,32,98,97,99,107,119,97,114,100,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]},#{signature => [{attribute,{3012,2},spec,{{erlang,trace_pattern,2},[{type,{3012,27},bounded_fun,[{type,{3012,27},'fun',[{type,{3012,27},product,[{var,{3012,28},'MFA'},{var,{3012,33},'MatchSpec'}]},{type,{3012,47},non_neg_integer,[]}]},[{type,{3013,7},constraint,[{atom,{3013,7},is_subtype},[{var,{3013,7},'MFA'},{type,{3013,14},union,[{user_type,{3013,14},trace_pattern_mfa,[]},{atom,{3013,36},send},{atom,{3013,43},'receive'}]}]]},{type,{3014,7},constraint,[{atom,{3014,7},is_subtype},[{var,{3014,7},'MatchSpec'},{type,{3014,21},union,[{ann_type,{3014,21},[{var,{3014,21},'MatchSpecList'},{user_type,{3014,38},trace_match_spec,[]}]},{type,{3015,20},boolean,[]},{atom,{3016,20},restart},{atom,{3017,20},pause}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,49,55,52>>}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3033}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<83,101,116,115,32,116,114,97,99,101,32,112,97,116,116,101,114,110,32,102,111,114,32>>,{em,[],[<<109,101,115,115,97,103,101,32,115,101,110,100,105,110,103>>]},<<46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46,32,66,121,32,100,101,102,97,117,108,116,32,97,108,108,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,102,114,111,109,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,116,114,97,99,101,100,46,32,84,111,32,108,105,109,105,116,32,116,114,97,99,101,100,32,115,101,110,100,32,101,118,101,110,116,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,109,101,115,115,97,103,101,32,99,111,110,116,101,110,116,44,32,116,104,101,32,115,101,110,100,101,114,32,97,110,100,47,111,114,32,116,104,101,32,114,101,99,101,105,118,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,100,111,110,101,32,111,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<91,82,101,99,101,105,118,101,114,44,32,77,115,103,93>>]},<<46,32>>,{code,[],[<<82,101,99,101,105,118,101,114>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,116,121,32,111,102,32,116,104,101,32,114,101,99,101,105,118,101,114,32,97,110,100,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,46,32,84,104,101,32,112,105,100,32,111,102,32,116,104,101,32,115,101,110,100,105,110,103,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,97,99,99,101,115,115,101,100,32,119,105,116,104,32,116,104,101,32,103,117,97,114,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<115,101,108,102,47,48>>]},<<46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,115,101,110,116,32,109,101,115,115,97,103,101,115,32,40,102,114,111,109,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,41,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,115,101,110,116,32,109,101,115,115,97,103,101,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]}]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<91,93>>]},<<32,102,111,114,32,115,101,110,100,32,116,114,97,99,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<49>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,116,111,32,97,32,115,112,101,99,105,102,105,99,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,80,105,100,44,32,39,95,39,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,109,97,116,99,104,105,110,103,32>>,{code,[],[<<123,114,101,112,108,121,44,32,95,125>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,95,39,44,32,123,114,101,112,108,121,44,39,95,39,125,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,116,111,32,116,104,101,32,115,101,110,100,101,114,32,105,116,115,101,108,102,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,36,49,39,44,32,39,95,39,93,44,91,123,39,61,58,61,39,44,39,36,49,39,44,123,115,101,108,102,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,115,101,110,116,32,116,111,32,111,116,104,101,114,32,110,111,100,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,115,101,110,100,44,32,91,123,91,39,36,49,39,44,32,39,95,39,93,44,91,123,39,61,47,61,39,44,123,110,111,100,101,44,39,36,49,39,125,44,123,110,111,100,101,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<115,101,110,100>>]},<<32,116,114,97,99,101,32,99,97,110,32,117,115,101,32,97,108,108,32,103,117,97,114,100,32,97,110,100,32,98,111,100,121,32,102,117,110,99,116,105,111,110,115,32,101,120,99,101,112,116,32>>,{code,[],[<<99,97,108,108,101,114>>]},<<46>>]}]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{signature => [{attribute,{3033,2},spec,{{erlang,trace_pattern,3},[{type,{3033,27},bounded_fun,[{type,{3033,27},'fun',[{type,{3033,27},product,[{atom,{3033,28},send},{var,{3033,34},'MatchSpec'},{type,{3033,45},nil,[]}]},{type,{3033,52},non_neg_integer,[]}]},[{type,{3034,7},constraint,[{atom,{3034,7},is_subtype},[{var,{3034,7},'MatchSpec'},{type,{3034,21},union,[{ann_type,{3034,21},[{var,{3034,21},'MatchSpecList'},{user_type,{3034,38},trace_match_spec,[]}]},{type,{3035,20},boolean,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,49,57,50>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3033}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]}]},{p,[],[<<83,101,116,115,32,116,114,97,99,101,32,112,97,116,116,101,114,110,32,102,111,114,32>>,{em,[],[<<109,101,115,115,97,103,101,32,114,101,99,101,105,118,105,110,103>>]},<<46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46,32,66,121,32,100,101,102,97,117,108,116,32,97,108,108,32,109,101,115,115,97,103,101,115,32,114,101,99,101,105,118,101,100,32,98,121,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,32,97,114,101,32,116,114,97,99,101,100,46,32,84,111,32,108,105,109,105,116,32,116,114,97,99,101,100,32,114,101,99,101,105,118,101,32,101,118,101,110,116,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,109,101,115,115,97,103,101,32,99,111,110,116,101,110,116,44,32,116,104,101,32,115,101,110,100,101,114,32,97,110,100,47,111,114,32,116,104,101,32,114,101,99,101,105,118,101,114,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,100,111,110,101,32,111,110,32,116,104,101,32,108,105,115,116,32>>,{code,[],[<<91,78,111,100,101,44,32,83,101,110,100,101,114,44,32,77,115,103,93>>]},<<46,32>>,{code,[],[<<78,111,100,101>>]},<<32,105,115,32,116,104,101,32,110,111,100,101,32,110,97,109,101,32,111,102,32,116,104,101,32,115,101,110,100,101,114,46,32>>,{code,[],[<<83,101,110,100,101,114>>]},<<32,105,115,32,116,104,101,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,116,121,32,111,102,32,116,104,101,32,115,101,110,100,101,114,44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,115,101,110,100,101,114,32,105,115,32,110,111,116,32,107,110,111,119,110,32,40,119,104,105,99,104,32,99,97,110,32,98,101,32,116,104,101,32,99,97,115,101,32,102,111,114,32,114,101,109,111,116,101,32,115,101,110,100,101,114,115,41,46,32>>,{code,[],[<<77,115,103>>]},<<32,105,115,32,116,104,101,32,109,101,115,115,97,103,101,32,116,101,114,109,46,32,84,104,101,32,112,105,100,32,111,102,32,116,104,101,32,114,101,99,101,105,118,105,110,103,32,112,114,111,99,101,115,115,32,99,97,110,32,98,101,32,97,99,99,101,115,115,101,100,32,119,105,116,104,32,116,104,101,32,103,117,97,114,100,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<115,101,108,102,47,48>>]},<<46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,32,40,116,111,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,41,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,114,101,99,101,105,118,101,100,32,109,101,115,115,97,103,101,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]}]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<91,93>>]},<<32,102,111,114,32,114,101,99,101,105,118,101,32,116,114,97,99,105,110,103,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,108,119,97,121,115,32>>,{code,[],[<<49>>]},<<46>>]},{p,[],[<<69,120,97,109,112,108,101,115,58>>]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,102,114,111,109,32,97,32,115,112,101,99,105,102,105,99,32,112,114,111,99,101,115,115,32>>,{code,[],[<<80,105,100>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,95,39,44,80,105,100,44,32,39,95,39,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,109,97,116,99,104,105,110,103,32>>,{code,[],[<<123,114,101,112,108,121,44,32,95,125>>]},<<58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,95,39,44,39,95,39,44,32,123,114,101,112,108,121,44,39,95,39,125,93,44,91,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{p,[],[<<79,110,108,121,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,32,102,114,111,109,32,111,116,104,101,114,32,110,111,100,101,115,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,40,39,114,101,99,101,105,118,101,39,44,32,91,123,91,39,36,49,39,44,32,39,95,39,44,32,39,95,39,93,44,91,123,39,61,47,61,39,44,39,36,49,39,44,123,110,111,100,101,125,125,93,44,91,93,125,93,44,32,91,93,41,46,10,49>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,111,114,32>>,{code,[],[<<39,114,101,99,101,105,118,101,39>>]},<<32,116,114,97,99,101,32,99,97,110,32,117,115,101,32,97,108,108,32,103,117,97,114,100,32,97,110,100,32,98,111,100,121,32,102,117,110,99,116,105,111,110,115,32,101,120,99,101,112,116,32>>,{code,[],[<<99,97,108,108,101,114>>]},<<44,32>>,{code,[],[<<105,115,95,115,101,113,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<103,101,116,95,115,101,113,95,116,111,107,101,110>>]},<<44,32>>,{code,[],[<<115,101,116,95,115,101,113,95,116,111,107,101,110>>]},<<44,32>>,{code,[],[<<101,110,97,98,108,101,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<100,105,115,97,98,108,101,95,116,114,97,99,101>>]},<<44,32>>,{code,[],[<<116,114,97,99,101>>]},<<44,32>>,{code,[],[<<115,105,108,101,110,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,114,111,99,101,115,115,95,100,117,109,112>>]},<<46>>]}]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{signature => [{attribute,{3033,2},spec,{{erlang,trace_pattern,3},[{type,{3036,6},bounded_fun,[{type,{3036,6},'fun',[{type,{3036,6},product,[{atom,{3036,7},'receive'},{var,{3036,18},'MatchSpec'},{type,{3036,29},nil,[]}]},{type,{3036,36},non_neg_integer,[]}]},[{type,{3037,7},constraint,[{atom,{3037,7},is_subtype},[{var,{3037,7},'MatchSpec'},{type,{3037,21},union,[{ann_type,{3037,21},[{var,{3037,21},'MatchSpecList'},{user_type,{3037,38},trace_match_spec,[]}]},{type,{3038,20},boolean,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,50,55,57>>,since => <<79,84,80,32,49,57,46,48>>}},{{function,trace_pattern,3},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3033}],[<<116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>}],[]},{li,[{name,<<109,97,116,99,104,95,118,97,114,105,97,98,108,101>>},{class,<<100,101,115,99,114,105,112,116,105,111,110>>}],[<<65,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,39,36,49,39,32,124,32,39,36,50,39,32,124,32,39,36,51,39,32,124,32,46,46,46>>]},{li,[{name,<<116,114,97,99,101,95,109,97,116,99,104,95,115,112,101,99>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,102,108,97,103>>}],[]},{li,[{name,<<116,114,97,99,101,95,112,97,116,116,101,114,110,95,109,102,97>>}],[]}]},{p,[],[<<69,110,97,98,108,101,115,32,111,114,32,100,105,115,97,98,108,101,115,32>>,{em,[],[<<99,97,108,108,32,116,114,97,99,105,110,103>>]},<<32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,102,117,110,99,116,105,111,110,115,46,32,77,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<32,116,111,32,115,101,116,32,116,104,101,32>>,{code,[],[<<99,97,108,108>>]},<<32,116,114,97,99,101,32,102,108,97,103,32,102,111,114,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<67,111,110,99,101,112,116,117,97,108,108,121,44,32,99,97,108,108,32,116,114,97,99,105,110,103,32,119,111,114,107,115,32,97,115,32,102,111,108,108,111,119,115,46,32,73,110,115,105,100,101,32,116,104,101,32,69,114,108,97,110,103,32,118,105,114,116,117,97,108,32,109,97,99,104,105,110,101,44,32,97,32,115,101,116,32,111,102,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,97,32,115,101,116,32,111,102,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,116,111,32,98,101,32,116,114,97,99,101,100,46,32,73,102,32,97,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,32,99,97,108,108,115,32,97,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,44,32,116,104,101,32,116,114,97,99,101,32,97,99,116,105,111,110,32,105,115,32,116,97,107,101,110,46,32,79,116,104,101,114,119,105,115,101,44,32,110,111,116,104,105,110,103,32,104,97,112,112,101,110,115,46>>]},{p,[],[<<84,111,32,97,100,100,32,111,114,32,114,101,109,111,118,101,32,111,110,101,32,111,114,32,109,111,114,101,32,112,114,111,99,101,115,115,101,115,32,116,111,32,116,104,101,32,115,101,116,32,111,102,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,101,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]}]},<<46>>]},{p,[],[<<84,111,32,97,100,100,32,111,114,32,114,101,109,111,118,101,32,102,117,110,99,116,105,111,110,115,32,116,111,32,116,104,101,32,115,101,116,32,111,102,32,116,114,97,99,101,100,32,102,117,110,99,116,105,111,110,115,44,32,117,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<46>>]},{p,[],[<<84,104,101,32,66,73,70,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,112,97,116,116,101,114,110,47,51>>]},<<32,99,97,110,32,97,108,115,111,32,97,100,100,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,32,116,111,32,97,32,102,117,110,99,116,105,111,110,46,32,65,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,99,111,109,112,114,105,115,101,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,114,103,117,109,101,110,116,115,32,109,117,115,116,32,109,97,116,99,104,44,32,97,32,103,117,97,114,100,32,101,120,112,114,101,115,115,105,111,110,32,116,104,97,116,32,109,117,115,116,32,101,118,97,108,117,97,116,101,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<44,32,97,110,100,32,97,110,32,97,99,116,105,111,110,32,116,111,32,98,101,32,112,101,114,102,111,114,109,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,97,99,116,105,111,110,32,105,115,32,116,111,32,115,101,110,100,32,97,32,116,114,97,99,101,32,109,101,115,115,97,103,101,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,111,114,32,116,104,101,32,103,117,97,114,100,32,102,97,105,108,115,44,32,116,104,101,32,97,99,116,105,111,110,32,105,115,32,110,111,116,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<32,105,115,32,116,111,32,98,101,32,97,32,116,117,112,108,101,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,32,70,117,110,99,116,105,111,110,44,32,65,114,105,116,121,125>>]},<<44,32,111,114,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,46,32,73,116,32,99,97,110,32,98,101,32,116,104,101,32,109,111,100,117,108,101,44,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,97,114,105,116,121,32,102,111,114,32,97,32,102,117,110,99,116,105,111,110,32,40,111,114,32,97,32,66,73,70,32,105,110,32,97,110,121,32,109,111,100,117,108,101,41,46,32,84,104,101,32,97,116,111,109,32>>,{code,[],[<<39,95,39>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,32,119,105,108,100,99,97,114,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,119,97,121,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,77,111,100,117,108,101,44,70,117,110,99,116,105,111,110,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,111,102,32,97,110,121,32,97,114,105,116,121,32,110,97,109,101,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110>>]},<<32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,77,111,100,117,108,101,44,39,95,39,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,109,111,100,117,108,101,32>>,{code,[],[<<77,111,100,117,108,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,39,95,39,44,39,95,39,44,39,95,39,125>>]}]},{dd,[],[{p,[],[<<65,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,97,108,108,32,108,111,97,100,101,100,32,109,111,100,117,108,101,115,46>>]}]}]},{p,[],[<<79,116,104,101,114,32,99,111,109,98,105,110,97,116,105,111,110,115,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,77,111,100,117,108,101,44,39,95,39,44,65,114,105,116,121,125>>]},<<44,32,97,114,101,32,110,111,116,32,97,108,108,111,119,101,100,46,32,76,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,119,105,108,100,99,97,114,100,115,32,111,110,108,121,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,105,115,32,105,110,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<46>>]},{p,[],[<<73,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<32,105,115,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<111,110,95,108,111,97,100>>]},<<44,32,116,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,110,100,32,102,108,97,103,32,108,105,115,116,32,97,114,101,32,117,115,101,100,32,111,110,32,97,108,108,32,109,111,100,117,108,101,115,32,116,104,97,116,32,97,114,101,32,110,101,119,108,121,32,108,111,97,100,101,100,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99>>]},<<32,99,97,110,32,116,97,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<102,97,108,115,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]},{dt,[],[{code,[],[<<116,114,117,101>>]}]},{dd,[],[{p,[],[<<69,110,97,98,108,101,115,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,46,32,65,110,121,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,105,115,32,114,101,109,111,118,101,100,46>>]}]},{dt,[],[{code,[],[<<77,97,116,99,104,83,112,101,99,76,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,108,105,115,116,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,46,32,65,110,32,101,109,112,116,121,32,108,105,115,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,70,111,114,32,97,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,115,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<101,114,116,115,58,109,97,116,99,104,95,115,112,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<77,97,116,99,104,32,83,112,101,99,105,102,105,99,97,116,105,111,110,115,32,105,110,32,69,114,108,97,110,103>>]},<<32,105,110,32,116,104,101,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]}]},{dt,[],[{code,[],[<<114,101,115,116,97,114,116>>]}]},{dd,[],[{p,[],[<<70,111,114,32,116,104,101,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<44,32>>,{code,[],[<<99,97,108,108,95,116,105,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<99,97,108,108,95,109,101,109,111,114,121>>]},<<58,32,114,101,115,116,97,114,116,115,32,116,104,101,32,101,120,105,115,116,105,110,103,32,99,111,117,110,116,101,114,115,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32,111,116,104,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[{code,[],[<<112,97,117,115,101>>]}]},{dd,[],[{p,[],[<<70,111,114,32,116,104,101,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<44,32>>,{code,[],[<<99,97,108,108,95,116,105,109,101>>]},<<32,97,110,100,32>>,{code,[],[<<99,97,108,108,95,109,101,109,111,114,121>>]},<<58,32,112,97,117,115,101,115,32,116,104,101,32,101,120,105,115,116,105,110,103,32,99,111,117,110,116,101,114,115,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32,111,116,104,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,111,112,116,105,111,110,115,46>>]}]}]},{p,[],[<<80,97,114,97,109,101,116,101,114,32>>,{code,[],[<<70,108,97,103,76,105,115,116>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,111,112,116,105,111,110,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,118,97,108,105,100,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,99,97,108,108,32,116,114,97,99,105,110,103,32,102,111,114,32,103,108,111,98,97,108,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,32,40,116,104,97,116,32,105,115,44,32,99,97,108,108,115,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,109,111,100,117,108,101,32,101,120,112,108,105,99,105,116,108,121,41,46,32,79,110,108,121,32,101,120,112,111,114,116,101,100,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,32,97,110,100,32,111,110,108,121,32,103,108,111,98,97,108,32,99,97,108,108,115,32,103,101,110,101,114,97,116,101,32,116,114,97,99,101,32,109,101,115,115,97,103,101,115,46,32>>,{em,[],[<<84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116>>]},<<46>>]}]},{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,99,97,108,108,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,119,104,101,110,101,118,101,114,32,97,110,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,44,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,104,111,119,32,116,104,101,121,32,97,114,101,32,99,97,108,108,101,100,46,32,73,102,32,102,108,97,103,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,105,115,32,115,101,116,32,102,111,114,32,116,104,101,32,112,114,111,99,101,115,115,44,32,97,32>>,{code,[],[<<114,101,116,117,114,110,95,116,111>>]},<<32,109,101,115,115,97,103,101,32,105,115,32,97,108,115,111,32,115,101,110,116,32,119,104,101,110,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,111,32,105,116,115,32,99,97,108,108,101,114,46>>]}]},{dt,[],[{code,[],[<<109,101,116,97,32,124,32,123,109,101,116,97,44,32,80,105,100,125,32,124,32,123,109,101,116,97,44,32,84,114,97,99,101,114,77,111,100,117,108,101,44,32,84,114,97,99,101,114,83,116,97,116,101,125>>]}]},{dd,[],[{p,[],[<<84,117,114,110,115,32,111,110,32,111,114,32,111,102,102,32,109,101,116,97,45,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,84,114,97,99,101,32,109,101,115,115,97,103,101,115,32,97,114,101,32,115,101,110,116,32,116,111,32,116,104,101,32,116,114,97,99,101,114,32,119,104,101,110,101,118,101,114,32,97,110,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,46,32,73,102,32,110,111,32,116,114,97,99,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<115,101,108,102,40,41>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,97,32,100,101,102,97,117,108,116,32,116,114,97,99,101,114,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<77,101,116,97,45,116,114,97,99,105,110,103,32,116,114,97,99,101,115,32,97,108,108,32,112,114,111,99,101,115,115,101,115,32,97,110,100,32,100,111,101,115,32,110,111,116,32,99,97,114,101,32,97,98,111,117,116,32,116,104,101,32,112,114,111,99,101,115,115,32,116,114,97,99,101,32,102,108,97,103,115,32,115,101,116,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,47,51>>]},<<44,32,116,104,101,32,116,114,97,99,101,32,102,108,97,103,115,32,97,114,101,32,105,110,115,116,101,97,100,32,102,105,120,101,100,32,116,111,32>>,{code,[],[<<91,99,97,108,108,44,32,116,105,109,101,115,116,97,109,112,93>>]},<<46>>]},{p,[],[<<84,104,101,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<123,114,101,116,117,114,110,95,116,114,97,99,101,125>>]},<<32,119,111,114,107,115,32,119,105,116,104,32,109,101,116,97,45,116,114,97,99,101,32,97,110,100,32,115,101,110,100,115,32,105,116,115,32,116,114,97,99,101,32,109,101,115,115,97,103,101,32,116,111,32,116,104,101,32,115,97,109,101,32,116,114,97,99,101,114,46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,115,116,111,112,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,102,97,108,115,101>>]},<<41,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,70,111,114,32,101,118,101,114,121,32,102,117,110,99,116,105,111,110,44,32,97,32,99,111,117,110,116,101,114,32,105,115,32,105,110,99,114,101,109,101,110,116,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,44,32,105,110,32,97,110,121,32,112,114,111,99,101,115,115,46,32,78,111,32,112,114,111,99,101,115,115,32,116,114,97,99,101,32,102,108,97,103,115,32,110,101,101,100,32,116,111,32,98,101,32,97,99,116,105,118,97,116,101,100,46>>]},{p,[],[<<73,102,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,105,115,32,115,116,97,114,116,101,100,32,119,104,105,108,101,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,44,32,116,104,101,32,99,111,117,110,116,32,105,115,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,46,32,84,111,32,112,97,117,115,101,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,44,32,117,115,101,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,112,97,117,115,101>>]},<<46,32,80,97,117,115,101,100,32,97,110,100,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,32,99,97,110,32,98,101,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,32,119,105,116,104,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,114,101,115,116,97,114,116>>]},<<46>>]},{p,[],[<<84,111,32,114,101,97,100,32,116,104,101,32,99,111,117,110,116,101,114,32,118,97,108,117,101,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,116,105,109,101>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,115,116,111,112,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,102,97,108,115,101>>]},<<41,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46,32,70,111,114,32,101,118,101,114,121,32,102,117,110,99,116,105,111,110,44,32,97,32,99,111,117,110,116,101,114,32,105,115,32,105,110,99,114,101,109,101,110,116,101,100,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,46,32,84,105,109,101,32,115,112,101,110,116,32,105,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,97,99,99,117,109,117,108,97,116,101,100,32,105,110,32,116,119,111,32,111,116,104,101,114,32,99,111,117,110,116,101,114,115,44,32,115,101,99,111,110,100,115,32,97,110,100,32,109,105,99,114,111,115,101,99,111,110,100,115,46,32,84,104,101,32,99,111,117,110,116,101,114,115,32,97,114,101,32,115,116,111,114,101,100,32,102,111,114,32,101,97,99,104,32,99,97,108,108,32,116,114,97,99,101,100,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<73,102,32,99,97,108,108,32,116,105,109,101,32,116,114,97,99,105,110,103,32,105,115,32,115,116,97,114,116,101,100,32,119,104,105,108,101,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,44,32,116,104,101,32,99,111,117,110,116,32,97,110,100,32,116,105,109,101,32,114,101,115,116,97,114,116,32,102,114,111,109,32,122,101,114,111,46,32,84,111,32,112,97,117,115,101,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,44,32,117,115,101,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,112,97,117,115,101>>]},<<46,32,80,97,117,115,101,100,32,97,110,100,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,32,99,97,110,32,98,101,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,32,119,105,116,104,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,114,101,115,116,97,114,116>>]},<<46>>]},{p,[],[<<84,111,32,114,101,97,100,32,116,104,101,32,99,111,117,110,116,101,114,32,118,97,108,117,101,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<99,97,108,108,95,109,101,109,111,114,121>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,116,114,117,101>>]},<<41,32,111,114,32,115,116,111,112,115,32,40>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,102,97,108,115,101>>]},<<41,32,99,97,108,108,32,109,101,109,111,114,121,32,116,114,97,99,105,110,103,32,102,111,114,32,97,108,108,32,116,121,112,101,115,32,111,102,32,102,117,110,99,116,105,111,110,32,99,97,108,108,115,46>>]},{p,[],[<<73,102,32,99,97,108,108,32,109,101,109,111,114,121,32,116,114,97,99,105,110,103,32,105,115,32,115,116,97,114,116,101,100,32,119,104,105,108,101,32,97,108,114,101,97,100,121,32,114,117,110,110,105,110,103,44,32,99,111,117,110,116,101,114,115,32,97,110,100,32,97,108,108,111,99,97,116,105,111,110,115,32,114,101,115,116,97,114,116,32,102,114,111,109,32,122,101,114,111,46,32,84,111,32,112,97,117,115,101,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,44,32,117,115,101,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,112,97,117,115,101>>]},<<46,32,80,97,117,115,101,100,32,97,110,100,32,114,117,110,110,105,110,103,32,99,111,117,110,116,101,114,115,32,99,97,110,32,98,101,32,114,101,115,116,97,114,116,101,100,32,102,114,111,109,32,122,101,114,111,32,119,105,116,104,32>>,{code,[],[<<77,97,116,99,104,83,112,101,99,32,61,61,32,114,101,115,116,97,114,116>>]},<<46>>]},{p,[],[<<84,111,32,114,101,97,100,32,116,104,101,32,99,111,117,110,116,101,114,32,118,97,108,117,101,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,97,110,100,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,97,114,101,32,109,117,116,117,97,108,108,121,32,101,120,99,108,117,115,105,118,101,44,32,97,110,100,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,40,105,102,32,110,111,32,111,112,116,105,111,110,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,41,46,32,84,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,108,108,95,99,111,117,110,116>>]},<<32,97,110,100,32>>,{code,[],[<<109,101,116,97>>]},<<32,112,101,114,102,111,114,109,32,97,32,107,105,110,100,32,111,102,32,108,111,99,97,108,32,116,114,97,99,105,110,103,44,32,97,110,100,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<46,32,65,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,103,108,111,98,97,108,108,121,32,111,114,32,108,111,99,97,108,108,121,32,116,114,97,99,101,100,46,32,73,102,32,103,108,111,98,97,108,32,116,114,97,99,105,110,103,32,105,115,32,115,112,101,99,105,102,105,101,100,32,102,111,114,32,97,32,115,101,116,32,111,102,32,102,117,110,99,116,105,111,110,115,44,32,116,104,101,110,32,108,111,99,97,108,44,32,109,101,116,97,44,32,99,97,108,108,32,116,105,109,101,44,32,97,110,100,32,99,97,108,108,32,99,111,117,110,116,32,116,114,97,99,105,110,103,32,102,111,114,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,101,116,32,111,102,32,108,111,99,97,108,32,102,117,110,99,116,105,111,110,115,32,105,115,32,100,105,115,97,98,108,101,100,44,32,97,110,100,32,99,111,110,118,101,114,115,101,108,121,46>>]},{p,[],[<<87,104,101,110,32,100,105,115,97,98,108,105,110,103,32,116,114,97,99,101,44,32,116,104,101,32,111,112,116,105,111,110,32,109,117,115,116,32,109,97,116,99,104,32,116,104,101,32,116,121,112,101,32,111,102,32,116,114,97,99,101,32,115,101,116,32,111,110,32,116,104,101,32,102,117,110,99,116,105,111,110,46,32,84,104,97,116,32,105,115,44,32,108,111,99,97,108,32,116,114,97,99,105,110,103,32,109,117,115,116,32,98,101,32,100,105,115,97,98,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<108,111,99,97,108>>]},<<32,97,110,100,32,103,108,111,98,97,108,32,116,114,97,99,105,110,103,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,40,111,114,32,110,111,32,111,112,116,105,111,110,41,44,32,97,110,100,32,115,111,32,111,110,46>>]},{p,[],[<<80,97,114,116,32,111,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,108,105,115,116,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,100,105,114,101,99,116,108,121,46,32,73,102,32,97,32,102,117,110,99,116,105,111,110,32,104,97,115,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,105,116,32,99,97,110,32,98,101,32,114,101,112,108,97,99,101,100,32,119,105,116,104,32,97,32,110,101,119,32,111,110,101,46,32,84,111,32,99,104,97,110,103,101,32,97,110,32,101,120,105,115,116,105,110,103,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,117,115,101,32,116,104,101,32,66,73,70,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,114,97,99,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,114,97,99,101,95,105,110,102,111,47,50>>]}]},<<32,116,111,32,114,101,116,114,105,101,118,101,32,116,104,101,32,101,120,105,115,116,105,110,103,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,102,117,110,99,116,105,111,110,115,32,109,97,116,99,104,105,110,103,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,70,65>>]},<<46,32,84,104,105,115,32,105,115,32,122,101,114,111,32,105,102,32,110,111,110,101,32,109,97,116,99,104,101,100,46>>]},{p,[],[<<70,97,105,108,115,32,98,121,32,114,97,105,115,105,110,103,32,97,110,32,101,114,114,111,114,32,101,120,99,101,112,116,105,111,110,32,119,105,116,104,32,97,110,32,101,114,114,111,114,32,114,101,97,115,111,110,32,111,102,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[<<73,102,32,97,110,32,97,114,103,117,109,101,110,116,32,105,115,32,105,110,118,97,108,105,100,46>>]}]},{dt,[],[{code,[],[<<115,121,115,116,101,109,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<73,102,32,97,32,109,97,116,99,104,32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,112,97,115,115,101,100,32,97,115,32,97,114,103,117,109,101,110,116,32,104,97,115,32,101,120,99,101,115,115,105,118,101,32,110,101,115,116,105,110,103,32,119,104,105,99,104,32,99,97,117,115,101,115,32,115,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,101,120,104,97,117,115,116,105,111,110,32,102,111,114,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,116,104,97,116,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,105,115,32,101,120,101,99,117,116,105,110,103,32,111,110,46,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,35,115,99,104,101,100,95,116,104,114,101,97,100,95,115,116,97,99,107,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[<<83,99,104,101,100,117,108,101,114,32,115,116,97,99,107,32,115,105,122,101>>]},<<32,99,97,110,32,98,101,32,99,111,110,102,105,103,117,114,101,100,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]}]}]}]},#{signature => [{attribute,{3033,2},spec,{{erlang,trace_pattern,3},[{type,{3039,6},bounded_fun,[{type,{3039,6},'fun',[{type,{3039,6},product,[{var,{3039,7},'MFA'},{var,{3039,12},'MatchSpec'},{var,{3039,23},'FlagList'}]},{type,{3039,36},non_neg_integer,[]}]},[{type,{3040,7},constraint,[{atom,{3040,7},is_subtype},[{var,{3040,7},'MFA'},{user_type,{3040,14},trace_pattern_mfa,[]}]]},{type,{3041,7},constraint,[{atom,{3041,7},is_subtype},[{var,{3041,7},'MatchSpec'},{type,{3041,21},union,[{ann_type,{3041,21},[{var,{3041,21},'MatchSpecList'},{user_type,{3041,38},trace_match_spec,[]}]},{type,{3042,20},boolean,[]},{atom,{3043,20},restart},{atom,{3044,20},pause}]}]]},{type,{3045,7},constraint,[{atom,{3045,7},is_subtype},[{var,{3045,7},'FlagList'},{type,{3045,19},list,[{user_type,{3045,21},trace_pattern_flag,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,51,54,55>>}},{{function,trunc,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2342}],[<<116,114,117,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,117,110,99,97,116,101,115,32,116,104,101,32,100,101,99,105,109,97,108,115,32,111,102,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,53,46,55,41,46,10,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,45,53,46,55,41,46,10,45,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,53,41,46,10,53>>]}]},{pre,[],[{code,[],[<<62,32,116,114,117,110,99,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41,46,10,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]}]},{p,[],[<<73,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<116,114,117,110,99,40,51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48,41>>]},<<32,101,118,97,108,117,97,116,101,115,32,116,111,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56>>]},<<46,32,84,104,101,32,114,101,97,115,111,110,32,102,111,114,32,116,104,105,115,32,105,115,32,116,104,97,116,32,116,104,101,32,110,117,109,98,101,114,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,57,46,48>>]},<<32,99,97,110,110,111,116,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,73,110,115,116,101,97,100,44,32,116,104,101,32,102,108,111,97,116,32,108,105,116,101,114,97,108,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32>>,{code,[],[<<51,54,48,50,56,55,57,55,48,49,56,57,54,51,57,54,56,46,48>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,99,108,111,115,101,115,116,32,110,117,109,98,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,101,120,97,99,116,108,121,32,97,115,32,97,32,102,108,111,97,116,32,118,97,108,117,101,46,32,83,101,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,108,111,97,116,95,114,101,112,114,101,115,101,110,116,97,116,105,111,110,95,112,114,111,98,108,101,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,70,108,111,97,116,105,110,103,32,80,111,105,110,116,32,78,117,109,98,101,114,115>>]},<<32,102,111,114,32,97,100,100,105,116,105,111,110,97,108,32,105,110,102,111,114,109,97,116,105,111,110,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2342,2},spec,{{trunc,1},[{type,{2342,12},bounded_fun,[{type,{2342,12},'fun',[{type,{2342,12},product,[{var,{2342,13},'Number'}]},{type,{2342,24},integer,[]}]},[{type,{2343,7},constraint,[{atom,{2343,7},is_subtype},[{var,{2343,7},'Number'},{type,{2343,17},number,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,53,56,56>>}},{{function,tuple_size,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2349}],[<<116,117,112,108,101,95,115,105,122,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,110,32,105,110,116,101,103,101,114,32,116,104,97,116,32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,105,110,32>>,{code,[],[<<84,117,112,108,101>>]},<<44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,117,112,108,101,95,115,105,122,101,40,123,109,111,114,110,105,44,32,109,117,108,108,101,44,32,98,119,97,110,103,101,125,41,46,10,51>>]}]},{p,[],[<<65,108,108,111,119,101,100,32,105,110,32,103,117,97,114,100,32,116,101,115,116,115,46>>]}]},#{signature => [{attribute,{2349,2},spec,{{tuple_size,1},[{type,{2349,17},bounded_fun,[{type,{2349,17},'fun',[{type,{2349,17},product,[{var,{2349,18},'Tuple'}]},{type,{2349,28},non_neg_integer,[]}]},[{type,{2350,7},constraint,[{atom,{2350,7},is_subtype},[{var,{2350,7},'Tuple'},{type,{2350,16},tuple,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,54,49,57>>}},{{function,tuple_to_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3055}],[<<116,117,112,108,101,95,116,111,95,108,105,115,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,108,105,115,116,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32>>,{code,[],[<<84,117,112,108,101>>]},<<46,32>>,{code,[],[<<84,117,112,108,101>>]},<<32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,69,114,108,97,110,103,32,116,101,114,109,115,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,116,117,112,108,101,95,116,111,95,108,105,115,116,40,123,115,104,97,114,101,44,32,123,39,69,114,105,99,115,115,111,110,95,66,39,44,32,49,54,51,125,125,41,46,10,91,115,104,97,114,101,44,123,39,69,114,105,99,115,115,111,110,95,66,39,44,49,54,51,125,93>>]}]}]},#{signature => [{attribute,{3055,2},spec,{{tuple_to_list,1},[{type,{3055,20},bounded_fun,[{type,{3055,20},'fun',[{type,{3055,20},product,[{var,{3055,21},'Tuple'}]},{type,{3055,31},list,[{type,{3055,32},term,[]}]}]},[{type,{3056,7},constraint,[{atom,{3056,7},is_subtype},[{var,{3056,7},'Tuple'},{type,{3056,16},tuple,any}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,54,51,50>>}},{{function,unalias,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1001}],[<<117,110,97,108,105,97,115,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,32>>,{code,[],[<<65,108,105,97,115>>]},<<32,112,114,101,118,105,111,117,115,108,121,32,99,114,101,97,116,101,100,32,98,121,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,46,32,65,110,32,97,108,105,97,115,32,99,97,110,32,102,111,114,32,101,120,97,109,112,108,101,32,98,101,32,99,114,101,97,116,101,100,32,118,105,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,97,108,105,97,115,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,108,105,97,115,47,48>>]}]},<<44,32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,51>>]}]},<<46,32>>,{code,[],[<<117,110,97,108,105,97,115,47,49>>]},<<32,119,105,108,108,32,97,108,119,97,121,115,32,100,101,97,99,116,105,118,97,116,101,32,116,104,101,32,97,108,105,97,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,111,112,116,105,111,110,115,32,117,115,101,100,32,119,104,101,110,32,99,114,101,97,116,105,110,103,32,116,104,101,32,97,108,105,97,115,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,116,114,117,101,32,105,102,32>>,{code,[],[<<65,108,105,97,115>>]},<<32,119,97,115,32,97,32,99,117,114,114,101,110,116,108,121,32,97,99,116,105,118,101,32,97,108,105,97,115,32,102,111,114,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,101,115,59,32,111,116,104,101,114,119,105,115,101,44,32,102,97,108,115,101,46>>]},{p,[],[<<70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,112,114,111,99,101,115,115,32,97,108,105,97,115,101,115,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,112,114,111,99,101,115,115,45,97,108,105,97,115,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<80,114,111,99,101,115,115,32,65,108,105,97,115,101,115>>]}]},<<32,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},#{signature => [{attribute,{1001,2},spec,{{unalias,1},[{type,{1001,14},bounded_fun,[{type,{1001,14},'fun',[{type,{1001,14},product,[{var,{1001,15},'Alias'}]},{type,{1001,25},boolean,[]}]},[{type,{1002,7},constraint,[{atom,{1002,7},is_subtype},[{var,{1002,7},'Alias'},{type,{1002,16},reference,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,54,52,53>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,unique_integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1821}],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,48>>],#{<<101,110>> => [{p,[],[<<71,101,110,101,114,97,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,97,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<105,110,116,101,103,101,114,32,117,110,105,113,117,101,32,111,110,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101>>]},<<46,32,84,104,101,32,115,97,109,101,32,97,115,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,93,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1821,2},spec,{{erlang,unique_integer,0},[{type,{1821,28},'fun',[{type,{1821,28},product,[]},{type,{1821,34},integer,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,54,55,49>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,unique_integer,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1814}],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<71,101,110,101,114,97,116,101,115,32,97,110,100,32,114,101,116,117,114,110,115,32,97,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,101,102,102,105,99,105,101,110,99,121,95,103,117,105,100,101,58,97,100,118,97,110,99,101,100,35,117,110,105,113,117,101,95,105,110,116,101,103,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<105,110,116,101,103,101,114,32,117,110,105,113,117,101,32,111,110,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101>>]},<<46,32,84,104,101,32,105,110,116,101,103,101,114,32,105,115,32,117,110,105,113,117,101,32,105,110,32,116,104,101,32,115,101,110,115,101,32,116,104,97,116,32,116,104,105,115,32,66,73,70,44,32,117,115,105,110,103,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,109,111,100,105,102,105,101,114,115,44,32,100,111,101,115,32,110,111,116,32,114,101,116,117,114,110,32,116,104,101,32,115,97,109,101,32,105,110,116,101,103,101,114,32,109,111,114,101,32,116,104,97,110,32,111,110,99,101,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,69,97,99,104,32,105,110,116,101,103,101,114,32,118,97,108,117,101,32,99,97,110,32,111,102,32,99,111,117,114,115,101,32,98,101,32,99,111,110,115,116,114,117,99,116,101,100,32,98,121,32,111,116,104,101,114,32,109,101,97,110,115,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,119,104,101,110,32>>,{code,[],[<<91,93>>]},<<32,105,115,32,112,97,115,115,101,100,32,97,115,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<44,32,98,111,116,104,32,110,101,103,97,116,105,118,101,32,97,110,100,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,115,32,99,97,110,32,98,101,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,116,111,32,117,115,101,32,116,104,101,32,114,97,110,103,101,32,111,102,32,105,110,116,101,103,101,114,115,32,116,104,97,116,32,100,111,32,110,111,116,32,110,101,101,100,32,104,101,97,112,32,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,46,32,66,121,32,100,101,102,97,117,108,116,32,116,104,101,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,32,97,114,101,32,97,108,115,111,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,117,110,105,113,117,101,44,32,116,104,97,116,32,105,115,44,32,97,110,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,32,99,97,110,32,98,101,32,115,109,97,108,108,101,114,32,111,114,32,108,97,114,103,101,114,32,116,104,97,110,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,46>>]},{p,[],[{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,58>>]},{dl,[],[{dt,[],[<<112,111,115,105,116,105,118,101>>]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,111,110,108,121,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,115,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,98,121,32,112,97,115,115,105,110,103,32,116,104,101,32>>,{code,[],[<<112,111,115,105,116,105,118,101>>]},<<32,109,111,100,105,102,105,101,114,32,121,111,117,32,119,105,108,108,32,103,101,116,32,104,101,97,112,32,97,108,108,111,99,97,116,101,100,32,105,110,116,101,103,101,114,115,32,40,98,105,103,110,117,109,115,41,32,113,117,105,99,107,101,114,46>>]}]},{dt,[],[<<109,111,110,111,116,111,110,105,99>>]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,83,116,114,105,99,116,108,121,95,77,111,110,111,116,111,110,105,99,97,108,108,121,95,73,110,99,114,101,97,115,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103>>]},<<32,105,110,116,101,103,101,114,115,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,99,114,101,97,116,105,111,110,32,116,105,109,101,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,105,110,116,101,103,101,114,32,114,101,116,117,114,110,101,100,32,105,115,32,97,108,119,97,121,115,32,108,97,114,103,101,114,32,116,104,97,110,32,112,114,101,118,105,111,117,115,108,121,32,114,101,116,117,114,110,101,100,32,105,110,116,101,103,101,114,115,32,111,110,32,116,104,101,32,99,117,114,114,101,110,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<84,104,101,115,101,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,111,114,100,101,114,32,98,101,116,119,101,101,110,32,101,118,101,110,116,115,32,111,110,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46,32,84,104,97,116,32,105,115,44,32,105,102,32,98,111,116,104,32>>,{code,[],[<<88,32,61,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,97,110,100,32>>,{code,[],[<<89,32,61,32,101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,97,114,101,32,101,120,101,99,117,116,101,100,32,98,121,32,100,105,102,102,101,114,101,110,116,32,112,114,111,99,101,115,115,101,115,32,40,111,114,32,116,104,101,32,115,97,109,101,32,112,114,111,99,101,115,115,41,32,111,110,32,116,104,101,32,115,97,109,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,97,110,100,32>>,{code,[],[<<88,32,60,32,89>>]},<<44,32,119,101,32,107,110,111,119,32,116,104,97,116,32>>,{code,[],[<<88>>]},<<32,119,97,115,32,99,114,101,97,116,101,100,32,98,101,102,111,114,101,32>>,{code,[],[<<89>>]},<<46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<83,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,32,97,114,101,32,105,110,104,101,114,101,110,116,108,121,32,113,117,105,116,101,32,101,120,112,101,110,115,105,118,101,32,116,111,32,103,101,110,101,114,97,116,101,32,97,110,100,32,115,99,97,108,101,115,32,112,111,111,114,108,121,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,118,97,108,117,101,115,32,110,101,101,100,32,116,111,32,98,101,32,115,121,110,99,104,114,111,110,105,122,101,100,32,98,101,116,119,101,101,110,32,67,80,85,32,99,111,114,101,115,46,32,84,104,97,116,32,105,115,44,32,100,111,32,110,111,116,32,112,97,115,115,32,116,104,101,32>>,{code,[],[<<109,111,110,111,116,111,110,105,99>>]},<<32,109,111,100,105,102,105,101,114,32,117,110,108,101,115,115,32,121,111,117,32,114,101,97,108,108,121,32,110,101,101,100,32,115,116,114,105,99,116,108,121,32,109,111,110,111,116,111,110,105,99,97,108,108,121,32,105,110,99,114,101,97,115,105,110,103,32,118,97,108,117,101,115,46>>]}]}]}]},{p,[],[<<65,108,108,32,118,97,108,105,100,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,46,32,82,101,112,101,97,116,101,100,32,40,118,97,108,105,100,41,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32,105,110,32,116,104,101,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<32,97,114,101,32,105,103,110,111,114,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,115,101,116,32,111,102,32,105,110,116,101,103,101,114,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<101,114,108,97,110,103,58,117,110,105,113,117,101,95,105,110,116,101,103,101,114,47,49>>]},<<32,117,115,105,110,103,32,100,105,102,102,101,114,101,110,116,32,115,101,116,115,32,111,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<115,32>>,{em,[],[<<119,105,108,108,32,111,118,101,114,108,97,112>>]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,98,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,109,111,110,111,116,111,110,105,99,93,41>>]},<<44,32,97,110,100,32>>,{code,[],[<<117,110,105,113,117,101,95,105,110,116,101,103,101,114,40,91,112,111,115,105,116,105,118,101,44,32,109,111,110,111,116,111,110,105,99,93,41>>]},<<32,114,101,112,101,97,116,101,100,108,121,44,32,121,111,117,32,119,105,108,108,32,101,118,101,110,116,117,97,108,108,121,32,115,101,101,32,115,111,109,101,32,105,110,116,101,103,101,114,115,32,116,104,97,116,32,97,114,101,32,114,101,116,117,114,110,101,100,32,98,121,32,98,111,116,104,32,99,97,108,108,115,46>>]}]},{p,[],[<<70,97,105,108,117,114,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<105,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114,76,105,115,116>>]},<<32,105,115,32,110,111,116,32,97,32,112,114,111,112,101,114,32,108,105,115,116,46>>]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[<<105,102,32>>,{code,[],[<<77,111,100,105,102,105,101,114>>]},<<32,105,115,32,110,111,116,32,97,32,118,97,108,105,100,32,109,111,100,105,102,105,101,114,46>>]}]}]},#{signature => [{attribute,{1814,2},spec,{{erlang,unique_integer,1},[{type,{1814,28},bounded_fun,[{type,{1814,28},'fun',[{type,{1814,28},product,[{var,{1814,29},'ModifierList'}]},{type,{1814,46},integer,[]}]},[{type,{1815,7},constraint,[{atom,{1815,7},is_subtype},[{var,{1815,7},'ModifierList'},{type,{1815,23},list,[{var,{1815,24},'Modifier'}]}]]},{type,{1816,7},constraint,[{atom,{1816,7},is_subtype},[{var,{1816,7},'Modifier'},{type,{1816,19},union,[{atom,{1816,19},positive},{atom,{1816,30},monotonic}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,54,56,52>>,since => <<79,84,80,32,49,56,46,48>>}},{{function,universaltime,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2355}],[<<117,110,105,118,101,114,115,97,108,116,105,109,101,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,99,117,114,114,101,110,116,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,97,99,99,111,114,100,105,110,103,32,116,111,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32>>,{code,[],[<<101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<101,114,108,97,110,103,58,108,111,99,97,108,116,105,109,101,40,41>>]},<<46,32,84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,111,115,45,115,121,115,116,101,109,45,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<79,83,32,83,121,115,116,101,109,32,84,105,109,101>>]},<<46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,40,41,46,10,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,49,56,44,52,51,125,125>>]}]}]},#{signature => [{attribute,{2355,2},spec,{{erlang,universaltime,0},[{type,{2355,27},bounded_fun,[{type,{2355,27},'fun',[{type,{2355,27},product,[]},{var,{2355,33},'DateTime'}]},[{type,{2356,7},constraint,[{atom,{2356,7},is_subtype},[{var,{2356,7},'DateTime'},{remote_type,{2356,19},[{atom,{2356,19},calendar},{atom,{2356,28},datetime},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,55,54,54>>}},{{function,universaltime_to_localtime,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3184}],[<<117,110,105,118,101,114,115,97,108,116,105,109,101,95,116,111,95,108,111,99,97,108,116,105,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,111,110,118,101,114,116,115,32,85,110,105,118,101,114,115,97,108,32,84,105,109,101,32,67,111,111,114,100,105,110,97,116,101,100,32,40,85,84,67,41,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,116,111,32,108,111,99,97,108,32,100,97,116,101,32,97,110,100,32,116,105,109,101,32,105,110,32,116,104,101,32,102,111,114,109,32>>,{code,[],[<<123,123,89,101,97,114,44,32,77,111,110,116,104,44,32,68,97,121,125,44,32,123,72,111,117,114,44,32,77,105,110,117,116,101,44,32,83,101,99,111,110,100,125,125>>]},<<32,105,102,32,115,117,112,112,111,114,116,101,100,32,98,121,32,116,104,101,32,117,110,100,101,114,108,121,105,110,103,32,79,83,46,32,79,116,104,101,114,119,105,115,101,32,110,111,32,99,111,110,118,101,114,115,105,111,110,32,105,115,32,100,111,110,101,44,32,97,110,100,32>>,{code,[],[<<85,110,105,118,101,114,115,97,108,116,105,109,101>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,101,114,108,97,110,103,58,117,110,105,118,101,114,115,97,108,116,105,109,101,95,116,111,95,108,111,99,97,108,116,105,109,101,40,123,123,49,57,57,54,44,49,49,44,54,125,44,123,49,52,44,49,56,44,52,51,125,125,41,46,10,123,123,49,57,57,54,44,49,49,44,55,125,44,123,49,53,44,49,56,44,52,51,125,125>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<85,110,105,118,101,114,115,97,108,116,105,109,101>>]},<<32,100,101,110,111,116,101,115,32,97,110,32,105,110,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{signature => [{attribute,{3184,2},spec,{{erlang,universaltime_to_localtime,1},[{type,{3184,40},bounded_fun,[{type,{3184,40},'fun',[{type,{3184,40},product,[{var,{3184,41},'Universaltime'}]},{var,{3184,60},'Localtime'}]},[{type,{3185,7},constraint,[{atom,{3185,7},is_subtype},[{var,{3185,7},'Localtime'},{remote_type,{3185,20},[{atom,{3185,20},calendar},{atom,{3185,29},datetime},[]]}]]},{type,{3186,7},constraint,[{atom,{3186,7},is_subtype},[{var,{3186,7},'Universaltime'},{remote_type,{3186,24},[{atom,{3186,24},calendar},{atom,{3186,33},datetime},[]]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,55,56,53>>}},{{function,unlink,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2367}],[<<117,110,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,97,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,105,110,103,32,112,114,111,99,101,115,115,32,97,110,100,32,97,110,111,116,104,101,114,32,112,114,111,99,101,115,115,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,100,32,98,121,32>>,{code,[],[<<73,100>>]},<<46,32,87,101,32,119,105,108,108,32,102,114,111,109,32,104,101,114,101,32,111,110,32,99,97,108,108,32,116,104,101,32,105,100,101,110,116,105,102,105,101,100,32,112,114,111,99,101,115,115,32,111,114,32,112,111,114,116,32,117,110,108,105,110,107,101,101,46>>]},{p,[],[<<65,32,108,105,110,107,32,99,97,110,32,98,101,32,115,101,116,32,117,112,32,117,115,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,110,107,47,49>>]}]},<<32,66,73,70,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,108,105,110,107,115,32,97,110,100,32,101,120,105,116,32,115,105,103,110,97,108,115,32,100,117,101,32,116,111,32,108,105,110,107,115,44,32,115,101,101,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,105,110,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<58>>]},{ul,[],[{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,108,105,110,107,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<76,105,110,107,115>>]}]},{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,115,101,110,100,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<83,101,110,100,105,110,103,32,69,120,105,116,32,83,105,103,110,97,108,115>>]}]},{li,[],[{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,114,101,99,101,105,118,105,110,103,95,101,120,105,116,95,115,105,103,110,97,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<82,101,99,101,105,118,105,110,103,32,69,120,105,116,32,83,105,103,110,97,108,115>>]}]}]},{p,[],[<<79,110,99,101,32>>,{code,[],[<<117,110,108,105,110,107,40,73,100,41>>]},<<32,104,97,115,32,114,101,116,117,114,110,101,100,44,32,105,116,32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,104,97,116,32,116,104,101,32,108,105,110,107,32,98,101,116,119,101,101,110,32,116,104,101,32,99,97,108,108,101,114,32,97,110,100,32,116,104,101,32,117,110,108,105,110,107,101,101,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,111,110,32,116,104,101,32,99,97,108,108,101,114,32,105,110,32,116,104,101,32,102,117,116,117,114,101,32,40,117,110,108,101,115,115,32,116,104,101,32,108,105,110,107,32,105,115,32,115,101,116,117,112,32,97,103,97,105,110,41,46,32,78,111,116,101,32,116,104,97,116,32,105,102,32,116,104,101,32,99,97,108,108,101,114,32,105,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,116,114,97,112,95,101,120,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,114,97,112,112,105,110,103,32,101,120,105,116,115>>]},<<44,32,97,110,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,73,100,44,32,69,120,105,116,82,101,97,115,111,110,125>>]},<<32,109,101,115,115,97,103,101,32,100,117,101,32,116,111,32,116,104,101,32,108,105,110,107,32,109,97,121,32,104,97,118,101,32,98,101,101,110,32,112,108,97,99,101,100,32,105,110,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,111,102,32,116,104,101,32,99,97,108,108,101,114,32,98,101,102,111,114,101,32,116,104,101,32>>,{code,[],[<<117,110,108,105,110,107,40,73,100,41>>]},<<32,99,97,108,108,32,99,111,109,112,108,101,116,101,100,46,32,65,108,115,111,32,110,111,116,101,32,116,104,97,116,32,116,104,101,32>>,{code,[],[<<123,39,69,88,73,84,39,44,32,73,100,44,32,69,120,105,116,82,101,97,115,111,110,125>>]},<<32,109,101,115,115,97,103,101,32,109,97,121,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,108,105,110,107,44,32,98,117,116,32,109,97,121,32,97,108,115,111,32,98,101,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,117,110,108,105,107,101,101,32,115,101,110,100,105,110,103,32,116,104,101,32,99,97,108,108,101,114,32,97,110,32,101,120,105,116,32,115,105,103,110,97,108,32,98,121,32,99,97,108,108,105,110,103,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,101,120,105,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,120,105,116,47,50>>]}]},<<32,66,73,70,46,32,84,104,101,114,101,102,111,114,101,44,32,105,116,32,109,97,121,32,111,114,32,109,97,121,32,110,111,116,32,98,101,32,97,112,112,114,111,112,114,105,97,116,101,32,116,111,32,99,108,101,97,110,32,117,112,32,116,104,101,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,97,102,116,101,114,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<117,110,108,105,110,107,40,73,100,41>>]},<<32,97,115,32,102,111,108,108,111,119,115,44,32,119,104,101,110,32,116,114,97,112,112,105,110,103,32,101,120,105,116,115,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<117,110,108,105,110,107,40,73,100,41,44,10,114,101,99,101,105,118,101,10,32,32,32,32,123,39,69,88,73,84,39,44,32,73,100,44,32,95,125,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,97,102,116,101,114,32,48,32,45,62,10,32,32,32,32,32,32,32,32,116,114,117,101,10,101,110,100>>]}]},{p,[],[<<84,104,101,32,108,105,110,107,32,114,101,109,111,118,97,108,32,105,115,32,112,101,114,102,111,114,109,101,100,32,97,115,121,110,99,104,114,111,110,111,117,115,108,121,46,32,73,102,32,115,117,99,104,32,97,32,108,105,110,107,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,44,32,110,111,116,104,105,110,103,32,105,115,32,100,111,110,101,46,32,65,32,100,101,116,97,105,108,101,100,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,100,105,115,116,95,112,114,111,116,111,99,111,108,35,108,105,110,107,95,112,114,111,116,111,99,111,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,110,107,32,112,114,111,116,111,99,111,108>>]},<<32,99,97,110,32,98,101,32,102,111,117,110,100,32,105,110,32,116,104,101,32>>,{i,[],[<<68,105,115,116,114,105,98,117,116,105,111,110,32,80,114,111,116,111,99,111,108>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,82,84,83,32,85,115,101,114,39,115,32,71,117,105,100,101>>]},<<46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,111,114,32,115,111,109,101,32,105,109,112,111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,100,105,115,116,114,105,98,117,116,101,100,32,115,105,103,110,97,108,115,44,32,115,101,101,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,98,108,111,99,107,105,110,103,45,115,105,103,110,97,108,105,110,103,45,111,118,101,114,45,100,105,115,116,114,105,98,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{i,[],[<<66,108,111,99,107,105,110,103,32,83,105,103,110,97,108,105,110,103,32,79,118,101,114,32,68,105,115,116,114,105,98,117,116,105,111,110>>]}]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32>>,{i,[],[<<80,114,111,99,101,115,115,101,115>>]},<<32,99,104,97,112,116,101,114,32,111,102,32,116,104,101,32>>,{i,[],[<<69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108>>]},<<46>>]}]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<73,100>>]},<<32,100,111,101,115,32,110,111,116,32,105,100,101,110,116,105,102,121,32,97,32,112,114,111,99,101,115,115,32,111,114,32,97,32,110,111,100,101,32,108,111,99,97,108,32,112,111,114,116,46>>]}]},#{signature => [{attribute,{2367,2},spec,{{unlink,1},[{type,{2367,13},bounded_fun,[{type,{2367,13},'fun',[{type,{2367,13},product,[{var,{2367,14},'Id'}]},{atom,{2367,21},true}]},[{type,{2368,7},constraint,[{atom,{2368,7},is_subtype},[{var,{2368,7},'Id'},{type,{2368,13},union,[{type,{2368,13},pid,[]},{type,{2368,21},port,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,56,48,52>>}},{{function,unregister,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2373}],[<<117,110,114,101,103,105,115,116,101,114,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,109,111,118,101,115,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,103,105,115,116,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,103,105,115,116,101,114,101,100,32,110,97,109,101>>]}]},<<32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,97,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,114,32,97,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,102,114,111,109,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,114,117,110,116,105,109,101,45,115,101,114,118,105,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<110,97,109,101,32,114,101,103,105,115,116,114,121>>]}]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,117,110,114,101,103,105,115,116,101,114,40,100,98,41,46,10,116,114,117,101>>]}]},{p,[],[<<75,101,101,112,32,105,110,32,109,105,110,100,32,116,104,97,116,32,121,111,117,32,99,97,110,32,115,116,105,108,108,32,114,101,99,101,105,118,101,32,115,105,103,110,97,108,115,32,97,115,115,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,97,102,116,101,114,32,105,116,32,104,97,115,32,98,101,101,110,32,117,110,114,101,103,105,115,116,101,114,101,100,32,97,115,32,116,104,101,32,115,101,110,100,101,114,32,109,97,121,32,104,97,118,101,32,108,111,111,107,101,100,32,117,112,32,116,104,101,32,110,97,109,101,32,98,101,102,111,114,101,32,115,101,110,100,105,110,103,32,116,111,32,105,116,46>>]},{p,[],[<<85,115,101,114,115,32,97,114,101,32,97,100,118,105,115,101,100,32,110,111,116,32,116,111,32,117,110,114,101,103,105,115,116,101,114,32,115,121,115,116,101,109,32,112,114,111,99,101,115,115,101,115,46>>]},{p,[],[<<70,97,105,108,117,114,101,58,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,102,32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,105,115,32,110,111,116,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,46>>]}]},#{signature => [{attribute,{2373,2},spec,{{unregister,1},[{type,{2373,17},bounded_fun,[{type,{2373,17},'fun',[{type,{2373,17},product,[{var,{2373,18},'RegName'}]},{atom,{2373,30},true}]},[{type,{2374,7},constraint,[{atom,{2374,7},is_subtype},[{var,{2374,7},'RegName'},{type,{2374,18},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,56,56,49>>}},{{function,whereis,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2379}],[<<119,104,101,114,101,105,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,32,111,114,32,112,111,114,116,32,105,100,101,110,116,105,102,105,101,114,32,119,105,116,104,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,114,101,103,105,115,116,101,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,103,105,115,116,101,114,101,100,32,110,97,109,101>>]}]},<<32>>,{code,[],[<<82,101,103,78,97,109,101>>]},<<32,102,114,111,109,32,116,104,101,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115,35,114,117,110,116,105,109,101,45,115,101,114,118,105,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<110,97,109,101,32,114,101,103,105,115,116,114,121>>]}]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<117,110,100,101,102,105,110,101,100>>]},<<32,105,102,32,116,104,101,32,110,97,109,101,32,105,115,32,110,111,116,32,114,101,103,105,115,116,101,114,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<62,32,119,104,101,114,101,105,115,40,100,98,41,46,10,60,48,46,52,51,46,48,62>>]}]}]},#{signature => [{attribute,{2379,2},spec,{{whereis,1},[{type,{2379,14},bounded_fun,[{type,{2379,14},'fun',[{type,{2379,14},product,[{var,{2379,15},'RegName'}]},{type,{2379,27},union,[{type,{2379,27},pid,[]},{type,{2379,35},port,[]},{atom,{2379,44},undefined}]}]},[{type,{2380,7},constraint,[{atom,{2380,7},is_subtype},[{var,{2380,7},'RegName'},{type,{2380,18},atom,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,57,48,50>>}},{{function,yield,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3682}],[<<121,105,101,108,100,47,48>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,103,105,118,101,32,111,116,104,101,114,32,112,114,111,99,101,115,115,101,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,111,114,32,104,105,103,104,101,114,32,112,114,105,111,114,105,116,121,32,40,105,102,32,97,110,121,41,32,97,32,99,104,97,110,99,101,32,116,111,32,101,120,101,99,117,116,101,32,98,101,102,111,114,101,32,114,101,116,117,114,110,105,110,103,46,32,84,104,101,114,101,32,105,115,32,110,111,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,97,110,121,32,111,116,104,101,114,32,112,114,111,99,101,115,115,32,114,117,110,115,32,98,101,116,119,101,101,110,32,116,104,101,32,105,110,118,111,99,97,116,105,111,110,32,97,110,100,32,114,101,116,117,114,110,32,111,102,32>>,{code,[],[<<101,114,108,97,110,103,58,121,105,101,108,100,47,48>>]},<<46>>]},{p,[],[<<83,101,101,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,102,111,114,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,114,101,99,101,105,118,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[{code,[],[<<114,101,99,101,105,118,101,45,97,102,116,101,114>>]},<<32,101,120,112,114,101,115,115,105,111,110,115>>]},<<32,102,111,114,32,104,111,119,32,116,111,32,109,97,107,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,115,108,101,101,112,32,102,111,114,32,97,32,115,112,101,99,105,102,105,99,32,110,117,109,98,101,114,32,111,102,32,109,105,108,108,105,115,101,99,111,110,100,115,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,101,114,101,32,105,115,32,115,101,108,100,111,109,32,111,114,32,110,101,118,101,114,32,97,110,121,32,110,101,101,100,32,116,111,32,117,115,101,32,116,104,105,115,32,66,73,70,46,32,85,115,105,110,103,32,116,104,105,115,32,66,73,70,32,119,105,116,104,111,117,116,32,97,32,116,104,111,114,111,117,103,104,32,103,114,97,115,112,32,111,102,32,104,111,119,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,119,111,114,107,115,32,99,97,110,32,99,97,117,115,101,32,112,101,114,102,111,114,109,97,110,99,101,32,100,101,103,114,97,100,97,116,105,111,110,46,32,84,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,112,117,116,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,32,108,97,115,116,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,99,104,101,100,117,108,101,114,39,115,32,113,117,101,117,101,32,102,111,114,32,112,114,111,99,101,115,115,101,115,32,111,102,32,116,104,101,32,115,97,109,101,32,112,114,105,111,114,105,116,121,32,97,115,32,116,104,101,32,99,117,114,114,101,110,116,32,112,114,111,99,101,115,115,46>>]}]}]},#{signature => [{attribute,{3682,2},spec,{{erlang,yield,0},[{type,{3682,19},'fun',[{type,{3682,19},product,[]},{atom,{3682,25},true}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,101,114,116,115,47,100,111,99,47,115,114,99,47,101,114,108,97,110,103,46,120,109,108,35,76,49,51,57,49,57>>}},{{type,any,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,80}],[<<45,116,121,112,101,32,97,110,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,108,108,32,112,111,115,115,105,98,108,101,32,69,114,108,97,110,103,32,116,101,114,109,115,46,32,83,121,110,111,110,121,109,32,102,111,114,32>>,{code,[],[<<116,101,114,109,40,41>>]},<<46>>]}]},#{signature => [{attribute,{80,2},type,{any,{type,{80,16},any,[]},[]}}]}},{{type,arity,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,81}],[<<45,116,121,112,101,32,97,114,105,116,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,97,114,105,116,121,32,111,102,32,97,32,102,117,110,99,116,105,111,110,32,111,114,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{81,2},type,{arity,{type,{81,18},arity,[]},[]}}]}},{{type,atom,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,82}],[<<45,116,121,112,101,32,97,116,111,109,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,97,116,111,109>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,116,111,109>>]},<<46>>]}]},#{signature => [{attribute,{82,2},type,{atom,{type,{82,17},atom,[]},[]}}]}},{{type,binary,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,83}],[<<45,116,121,112,101,32,98,105,110,97,114,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,98,105,116,45,115,116,114,105,110,103,115,45,97,110,100,45,98,105,110,97,114,105,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<98,105,110,97,114,121>>]},<<44,32,116,104,97,116,32,105,115,44,32,97,32,98,105,116,115,116,114,105,110,103,32,119,105,116,104,32,97,32,115,105,122,101,32,100,105,118,105,115,105,98,108,101,32,98,121,32,56,46>>]}]},#{signature => [{attribute,{83,2},type,{binary,{type,{83,19},binary,[{integer,83,0},{integer,{83,25},8}]},[]}}]}},{{type,bitstring,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,84}],[<<45,116,121,112,101,32,98,105,116,115,116,114,105,110,103,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,98,105,116,45,115,116,114,105,110,103,115,45,97,110,100,45,98,105,110,97,114,105,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<98,105,116,115,116,114,105,110,103>>]},<<46>>]}]},#{signature => [{attribute,{84,2},type,{bitstring,{type,{84,22},binary,[{integer,84,0},{integer,{84,28},1}]},[]}}]}},{{type,boolean,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,86}],[<<45,116,121,112,101,32,98,111,111,108,101,97,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,98,111,111,108,101,97,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<98,111,111,108,101,97,110>>]},<<32,118,97,108,117,101,46>>]}]},#{signature => [{attribute,{86,2},type,{boolean,{type,{86,20},union,[{atom,{86,20},true},{atom,{86,27},false}]},[]}}]}},{{type,byte,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,87}],[<<45,116,121,112,101,32,98,121,116,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,98,121,116,101,32,111,102,32,100,97,116,97,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{87,2},type,{byte,{type,{87,17},range,[{integer,{87,17},0},{integer,{87,20},255}]},[]}}]}},{{type,char,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,88}],[<<45,116,121,112,101,32,99,104,97,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,32,111,114,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,99,111,100,101>>]},<<32,99,111,100,101,112,111,105,110,116,32,112,114,101,115,101,110,116,101,100,32,98,121,32,97,110,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{88,2},type,{char,{type,{88,17},range,[{integer,{88,17},0},{integer,{88,20},1114111}]},[]}}]}},{{type,float,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,90}],[<<45,116,121,112,101,32,102,108,111,97,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,117,109,98,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,108,111,97,116>>]},<<46>>]}]},#{signature => [{attribute,{90,2},type,{float,{type,{90,18},float,[]},[]}}]}},{{type,function,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,91}],[<<45,116,121,112,101,32,102,117,110,99,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,102,117,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<102,117,110>>]},<<46>>]}]},#{signature => [{attribute,{91,2},type,{function,{type,{91,21},'fun',[]},[]}}]}},{{type,identifier,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,92}],[<<45,116,121,112,101,32,105,100,101,110,116,105,102,105,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,117,110,105,113,117,101,32,105,100,101,110,116,105,102,105,101,114,32,102,111,114,32,115,111,109,101,32,101,110,116,105,116,121,44,32,102,111,114,32,101,120,97,109,112,108,101,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,114,111,99,101,115,115,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,111,99,101,115,115>>]},<<44,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,112,111,114,116,115,35,112,111,114,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,111,114,116>>]},<<32,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<109,111,110,105,116,111,114>>]},<<46>>]}]},#{signature => [{attribute,{92,2},type,{identifier,{type,{92,23},union,[{type,{92,23},pid,[]},{type,{92,31},port,[]},{type,{92,40},reference,[]}]},[]}}]}},{{type,integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,93}],[<<45,116,121,112,101,32,105,110,116,101,103,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,117,109,98,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<105,110,116,101,103,101,114>>]},<<46>>]}]},#{signature => [{attribute,{93,2},type,{integer,{type,{93,20},integer,[]},[]}}]}},{{type,iodata,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,94}],[<<45,116,121,112,101,32,105,111,100,97,116,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,98,105,110,97,114,121,32,111,114,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,98,121,116,101,115,32,97,110,100,47,111,114,32,105,111,100,97,116,97,46,32,84,104,105,115,32,100,97,116,97,116,121,112,101,32,105,115,32,117,115,101,100,32,116,111,32,114,101,112,114,101,115,101,110,116,32,100,97,116,97,32,116,104,97,116,32,105,115,32,109,101,97,110,116,32,116,111,32,98,101,32,111,117,116,112,117,116,32,117,115,105,110,103,32,97,110,121,32,73,47,79,32,109,111,100,117,108,101,46,32,70,111,114,32,101,120,97,109,112,108,101,58,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<102,105,108,101,58,119,114,105,116,101,47,50>>]},<<32,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<103,101,110,95,116,99,112,58,115,101,110,100,47,50>>]},<<46>>]},{p,[],[<<84,111,32,99,111,110,118,101,114,116,32,97,110,32,105,111,100,97,116,97,40,41,32,116,101,114,109,32,116,111,32,98,105,110,97,114,121,40,41,32,121,111,117,32,99,97,110,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,50>>]},<<46,32,84,111,32,116,114,97,110,115,99,111,100,101,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,114,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<115,116,114,105,110,103,40,41>>]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<117,110,105,99,111,100,101,58,99,104,97,114,100,97,116,97,40,41>>]},<<32,116,111,32,105,111,100,97,116,97,40,41,32,121,111,117,32,99,97,110,32,117,115,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<117,110,105,99,111,100,101,58,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,49>>]},<<46>>]}]},#{signature => [{attribute,{94,2},type,{iodata,{type,{94,19},union,[{type,{94,19},iolist,[]},{type,{94,30},binary,[]}]},[]}}]}},{{type,iolist,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,95}],[<<45,116,121,112,101,32,105,111,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,98,121,116,101,115,32,97,110,100,47,111,114,32,105,111,100,97,116,97,46,32,84,104,105,115,32,100,97,116,97,116,121,112,101,32,105,115,32,117,115,101,100,32,116,111,32,114,101,112,114,101,115,101,110,116,32,100,97,116,97,32,116,104,97,116,32,105,115,32,109,101,97,110,116,32,116,111,32,98,101,32,111,117,116,112,117,116,32,117,115,105,110,103,32,97,110,121,32,73,47,79,32,109,111,100,117,108,101,46,32,70,111,114,32,101,120,97,109,112,108,101,58,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<102,105,108,101,58,119,114,105,116,101,47,50>>]},<<32,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<103,101,110,95,116,99,112,58,115,101,110,100,47,50>>]},<<46>>]},{p,[],[<<73,110,32,109,111,115,116,32,117,115,101,32,99,97,115,101,115,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<105,111,100,97,116,97,40,41>>]},<<32,105,110,115,116,101,97,100,32,111,102,32,116,104,105,115,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{95,2},type,{iolist,{type,{95,19},maybe_improper_list,[{type,{95,39},union,[{type,{95,39},byte,[]},{type,{95,48},binary,[]},{type,{95,59},iolist,[]}]},{type,{95,69},union,[{type,{95,69},binary,[]},{type,{95,80},nil,[]}]}]},[]}}]}},{{type,list,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,96}],[<<45,116,121,112,101,32,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,115,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,101,114,109,115,32,111,102,32,97,110,121,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{96,2},type,{list,{type,{96,17},list,[{type,{96,18},any,[]}]},[]}}]}},{{type,list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,97}],[<<45,116,121,112,101,32,108,105,115,116,40,65,114,103,49,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,115,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,101,114,109,115,32,111,102,32,116,104,101,32,116,121,112,101,32>>,{code,[],[<<67,111,110,116,101,110,116,84,121,112,101>>]},<<46>>]}]},#{signature => [{attribute,{97,2},type,{list,{type,{97,28},list,[{var,{97,29},'ContentType'}]},[{var,{97,12},'ContentType'}]}}]}},{{type,map,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,98}],[<<45,116,121,112,101,32,109,97,112,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,109,97,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<109,97,112>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,107,101,121,32,97,110,100,32,118,97,108,117,101,32,97,115,115,111,99,105,97,116,105,111,110,115,46>>]}]},#{signature => [{attribute,{98,2},type,{map,{type,{98,16},map,[{type,{98,25},map_field_assoc,[{type,{98,19},any,[]},{type,{98,28},any,[]}]}]},[]}}]}},{{type,maybe_improper_list,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,99}],[<<45,116,121,112,101,32,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,115,116>>]},<<32,116,104,97,116,32,105,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,101,110,100,32,119,105,116,104,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,105,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<91,93>>]},<<44,32,97,110,100,32,119,104,101,114,101,32,116,104,101,32,108,105,115,116,32,101,108,101,109,101,110,116,115,32,99,97,110,32,98,101,32,111,102,32,97,110,121,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{99,2},type,{maybe_improper_list,{type,{99,32},maybe_improper_list,[{type,{99,52},any,[]},{type,{99,59},any,[]}]},[]}}]}},{{type,maybe_improper_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,100}],[<<45,116,121,112,101,32,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,65,114,103,49,44,65,114,103,50,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<108,105,115,116>>]},<<44,32,116,104,97,116,32,105,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,101,110,100,32,119,105,116,104,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,110,105,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<91,93>>]},<<44,32,97,110,100,32,119,104,101,114,101,32,116,104,101,32,108,105,115,116,32,101,108,101,109,101,110,116,115,32,97,114,101,32,111,102,32,116,104,101,32,116,121,112,101,32>>,{code,[],[<<67,111,110,116,101,110,116,84,121,112,101>>]},<<46>>]}]},#{signature => [{attribute,{100,2},type,{maybe_improper_list,{type,{100,60},maybe_improper_list,[{var,{100,80},'ContentType'},{var,{100,93},'TerminationType'}]},[{var,{100,27},'ContentType'},{var,{100,40},'TerminationType'}]}}]}},{{type,mfa,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,101}],[<<45,116,121,112,101,32,109,102,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,116,104,114,101,101,45,116,117,112,108,101,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32>>,{code,[],[<<77,111,100,117,108,101,58,70,117,110,99,116,105,111,110,47,65,114,105,116,121>>]},<<32,102,117,110,99,116,105,111,110,32,115,105,103,110,97,116,117,114,101,46>>]}]},#{signature => [{attribute,{101,2},type,{mfa,{type,{101,16},tuple,[{type,{101,17},module,[]},{type,{101,26},atom,[]},{type,{101,33},arity,[]}]},[]}}]}},{{type,module,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,102}],[<<45,116,121,112,101,32,109,111,100,117,108,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32,109,111,100,117,108,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{102,2},type,{module,{type,{102,19},atom,[]},[]}}]}},{{type,neg_integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,103}],[<<45,116,121,112,101,32,110,101,103,95,105,110,116,101,103,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,46>>]}]},#{signature => [{attribute,{103,2},type,{neg_integer,{type,{103,24},neg_integer,[]},[]}}]}},{{type,nil,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,104}],[<<45,116,121,112,101,32,110,105,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,101,109,112,116,121,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<108,105,115,116,40,41>>]},<<46>>]}]},#{signature => [{attribute,{104,2},type,{nil,{type,{104,16},nil,[]},[]}}]}},{{type,no_return,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,105}],[<<45,116,121,112,101,32,110,111,95,114,101,116,117,114,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,116,121,112,101,32,117,115,101,100,32,116,111,32,115,104,111,119,32,116,104,97,116,32,97,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32>>,{em,[],[<<110,101,118,101,114>>]},<<32,114,101,116,117,114,110,32,97,32,118,97,108,117,101,44,32,116,104,97,116,32,105,115,32,105,116,32,119,105,108,108,32>>,{em,[],[<<97,108,119,97,121,115>>]},<<32,116,104,114,111,119,32,97,110,32,101,120,99,101,112,116,105,111,110,46>>]}]},#{signature => [{attribute,{105,2},type,{no_return,{type,{105,22},none,[]},[]}}]}},{{type,node,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,106}],[<<45,116,121,112,101,32,110,111,100,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,105,115,116,114,105,98,117,116,101,100,35,110,111,100,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,111,100,101>>]},<<32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,110,32,97,116,111,109,46>>]}]},#{signature => [{attribute,{106,2},type,{node,{type,{106,17},atom,[]},[]}}]}},{{type,non_neg_integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,107}],[<<45,116,121,112,101,32,110,111,110,95,110,101,103,95,105,110,116,101,103,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,110,111,110,45,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,44,32,116,104,97,116,32,105,115,32,97,110,121,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,32,111,114,32,48,46>>]}]},#{signature => [{attribute,{107,2},type,{non_neg_integer,{type,{107,28},non_neg_integer,[]},[]}}]}},{{type,none,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,108}],[<<45,116,121,112,101,32,110,111,110,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<84,104,105,115,32,116,121,112,101,32,105,115,32,117,115,101,100,32,116,111,32,115,104,111,119,32,116,104,97,116,32,97,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32>>,{em,[],[<<110,101,118,101,114>>]},<<32,114,101,116,117,114,110,32,97,32,118,97,108,117,101,59,32,116,104,97,116,32,105,115,32,105,116,32,119,105,108,108,32>>,{em,[],[<<97,108,119,97,121,115>>]},<<32,116,104,114,111,119,32,97,110,32,101,120,99,101,112,116,105,111,110,46,32,73,110,32,97,32,115,112,101,99,44,32,117,115,101,32>>,{code,[],[<<110,111,95,114,101,116,117,114,110,40,41>>]},<<32,102,111,114,32,116,104,101,32,115,97,107,101,32,111,102,32,99,108,97,114,105,116,121,46>>]}]},#{signature => [{attribute,{108,2},type,{none,{type,{108,17},none,[]},[]}}]}},{{type,nonempty_binary,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,109}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,98,105,110,97,114,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,110,97,114,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<98,105,110,97,114,121,40,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,100,97,116,97,46>>]}]},#{signature => [{attribute,{109,2},type,{nonempty_binary,{type,{109,28},binary,[{integer,{109,32},8},{integer,{109,39},8}]},[]}}]}},{{type,nonempty_bitstring,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,110}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,98,105,116,115,116,114,105,110,103,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,98,105,116,115,116,114,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<98,105,116,115,116,114,105,110,103,40,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,100,97,116,97,46>>]}]},#{signature => [{attribute,{110,2},type,{nonempty_bitstring,{type,{110,31},binary,[{integer,{110,35},1},{integer,{110,42},1}]},[]}}]}},{{type,nonempty_improper_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,111}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,65,114,103,49,44,65,114,103,50,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,47,50>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,105,116,101,109,115,46>>]}]},#{signature => [{attribute,{111,2},type,{nonempty_improper_list,{type,{111,63},nonempty_improper_list,[{var,{111,86},'ContentType'},{var,{111,99},'TerminationType'}]},[{var,{111,30},'ContentType'},{var,{111,43},'TerminationType'}]}}]}},{{type,nonempty_list,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,112}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<108,105,115,116,40,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,105,116,101,109,115,46>>]}]},#{signature => [{attribute,{112,2},type,{nonempty_list,{type,{112,26},nonempty_list,[{type,{112,40},any,[]}]},[]}}]}},{{type,nonempty_list,1},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,113}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,108,105,115,116,40,65,114,103,49,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<108,105,115,116,40,67,111,110,116,101,110,116,84,121,112,101,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,105,116,101,109,115,46>>]}]},#{signature => [{attribute,{113,2},type,{nonempty_list,{type,{113,37},nonempty_list,[{var,{113,38},'ContentType'}]},[{var,{113,21},'ContentType'}]}}]}},{{type,nonempty_maybe_improper_list,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,114}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,105,116,101,109,115,46>>]}]},#{signature => [{attribute,{114,2},type,{nonempty_maybe_improper_list,{type,{114,41},nonempty_maybe_improper_list,[{type,{114,70},any,[]},{type,{114,77},any,[]}]},[]}}]}},{{type,nonempty_maybe_improper_list,2},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,115}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,65,114,103,49,44,65,114,103,50,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<109,97,121,98,101,95,105,109,112,114,111,112,101,114,95,108,105,115,116,40,67,111,110,116,101,110,116,84,121,112,101,44,32,84,101,114,109,105,110,97,116,105,111,110,84,121,112,101,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,105,116,101,109,115,46>>]}]},#{signature => [{attribute,{115,2},type,{nonempty_maybe_improper_list,{type,{115,69},nonempty_maybe_improper_list,[{var,{115,98},'ContentType'},{var,{115,111},'TerminationType'}]},[{var,{115,36},'ContentType'},{var,{115,49},'TerminationType'}]}}]}},{{type,nonempty_string,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,116}],[<<45,116,121,112,101,32,110,111,110,101,109,112,116,121,95,115,116,114,105,110,103,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,116,114,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<115,116,114,105,110,103,40,41>>]},<<32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},#{signature => [{attribute,{116,2},type,{nonempty_string,{type,{116,28},nonempty_list,[{type,{116,42},char,[]}]},[]}}]}},{{type,number,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,117}],[<<45,116,121,112,101,32,110,117,109,98,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,117,109,98,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<110,117,109,98,101,114>>]},<<46>>]}]},#{signature => [{attribute,{117,2},type,{number,{type,{117,19},union,[{type,{117,19},integer,[]},{type,{117,31},float,[]}]},[]}}]}},{{type,pid,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,118}],[<<45,116,121,112,101,32,112,105,100,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,112,105,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114>>]},<<46>>]}]},#{signature => [{attribute,{118,2},type,{pid,{type,{118,16},pid,[]},[]}}]}},{{type,port,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,119}],[<<45,116,121,112,101,32,112,111,114,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,112,111,114,116,45,105,100,101,110,116,105,102,105,101,114>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,111,114,116,32,105,100,101,110,116,105,102,105,101,114>>]},<<46>>]}]},#{signature => [{attribute,{119,2},type,{port,{type,{119,17},port,[]},[]}}]}},{{type,pos_integer,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,120}],[<<45,116,121,112,101,32,112,111,115,95,105,110,116,101,103,101,114,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,105,110,116,101,103,101,114,32,103,114,101,97,116,101,114,32,116,104,97,110,32,122,101,114,111,46>>]}]},#{signature => [{attribute,{120,2},type,{pos_integer,{type,{120,24},pos_integer,[]},[]}}]}},{{type,reference,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,121}],[<<45,116,121,112,101,32,114,101,102,101,114,101,110,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,114,101,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,102,101,114,101,110,99,101>>]},<<46>>]}]},#{signature => [{attribute,{121,2},type,{reference,{type,{121,22},reference,[]},[]}}]}},{{type,string,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,122}],[<<45,116,121,112,101,32,115,116,114,105,110,103,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,115,116,114,105,110,103,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,108,105,115,116,32,111,102,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,111,114,32,117,110,105,99,111,100,101,32,99,111,100,101,112,111,105,110,116,115,46>>]}]},#{signature => [{attribute,{122,2},type,{string,{type,{122,19},list,[{type,{122,20},char,[]}]},[]}}]}},{{type,term,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,123}],[<<45,116,121,112,101,32,116,101,114,109,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,108,108,32,112,111,115,115,105,98,108,101,32,69,114,108,97,110,103,32,116,101,114,109,115,46,32,83,121,110,111,110,121,109,32,102,111,114,32>>,{code,[],[<<97,110,121,40,41>>]},<<46>>]}]},#{signature => [{attribute,{123,2},type,{term,{type,{123,17},any,[]},[]}}]}},{{type,timeout,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,124}],[<<45,116,121,112,101,32,116,105,109,101,111,117,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,116,105,109,101,111,117,116,32,118,97,108,117,101,32,116,104,97,116,32,99,97,110,32,98,101,32,112,97,115,115,101,100,32,116,111,32,97,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,120,112,114,101,115,115,105,111,110,115,35,114,101,99,101,105,118,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,99,101,105,118,101,32,101,120,112,114,101,115,115,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,{124,2},type,{timeout,{type,{124,20},union,[{atom,{124,20},infinity},{type,{124,33},non_neg_integer,[]}]},[]}}]}},{{type,tuple,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,125}],[<<45,116,121,112,101,32,116,117,112,108,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<116,117,112,108,101>>]},<<46>>]}]},#{signature => [{attribute,{125,2},type,{tuple,{type,{125,18},tuple,any},[]}}]}},{{type,ext_binary,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,156}],[<<45,116,121,112,101,32,101,120,116,95,98,105,110,97,114,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,44,32,115,116,114,117,99,116,117,114,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},#{signature => [{attribute,{156,2},type,{ext_binary,{type,{156,23},binary,[]},[]}}]}},{{type,ext_iovec,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,157}],[<<45,116,121,112,101,32,101,120,116,95,105,111,118,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,116,101,114,109,32,111,102,32,116,121,112,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<105,111,118,101,99,40,41>>]}]},<<44,32,115,116,114,117,99,116,117,114,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,101,120,116,101,114,110,97,108,32,116,101,114,109,32,102,111,114,109,97,116,46>>]}]},#{signature => [{attribute,{157,2},type,{ext_iovec,{user_type,{157,22},iovec,[]},[]}}]}},{{type,iovec,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,188}],[<<45,116,121,112,101,32,105,111,118,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32,108,105,115,116,32,111,102,32,98,105,110,97,114,105,101,115,46,32,84,104,105,115,32,100,97,116,97,116,121,112,101,32,105,115,32,117,115,101,102,117,108,32,116,111,32,117,115,101,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[{code,[],[<<101,110,105,102,95,105,110,115,112,101,99,116,95,105,111,118,101,99>>]}]},<<46>>]}]},#{signature => [{attribute,{188,2},type,{iovec,{type,{188,18},list,[{type,{188,19},binary,[]}]},[]}}]}},{{type,message_queue_data,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2641}],[<<45,116,121,112,101,32,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]},<<46>>]}]},#{signature => [{attribute,{2641,2},type,{message_queue_data,{type,{2642,2},union,[{atom,{2642,2},off_heap},{atom,{2642,13},on_heap}]},[]}}]}},{{type,monitor_option,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,1689}],[<<45,116,121,112,101,32,109,111,110,105,116,111,114,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,109,111,110,105,116,111,114,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<109,111,110,105,116,111,114,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{1689,2},type,{monitor_option,{type,{1689,27},union,[{type,{1689,27},tuple,[{atom,{1689,28},alias},{type,{1689,37},union,[{atom,{1689,37},explicit_unalias},{atom,{1689,58},demonitor},{atom,{1689,72},reply_demonitor}]}]},{type,{1690,27},tuple,[{atom,{1690,28},tag},{type,{1690,35},term,[]}]}]},[]}}]}},{{type,timestamp,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,158}],[<<45,116,121,112,101,32,116,105,109,101,115,116,97,109,112,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,105,109,101,115,116,97,109,112,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,116,105,109,101,115,116,97,109,112,47,48>>]}]},<<46>>]}]},#{signature => [{attribute,{158,2},type,{timestamp,{type,{158,22},tuple,[{ann_type,{158,23},[{var,{158,23},'MegaSecs'},{type,{158,35},non_neg_integer,[]}]},{ann_type,{159,23},[{var,{159,23},'Secs'},{type,{159,31},non_neg_integer,[]}]},{ann_type,{160,23},[{var,{160,23},'MicroSecs'},{type,{160,36},non_neg_integer,[]}]}]},[]}}]}},{{type,time_unit,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,162}],[<<45,116,121,112,101,32,116,105,109,101,95,117,110,105,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{a,[{id,<<116,121,112,101,95,116,105,109,101,95,117,110,105,116>>}],[]},{p,[],[<<83,117,112,112,111,114,116,101,100,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<80,97,114,116,115,80,101,114,83,101,99,111,110,100,32,58,58,32,105,110,116,101,103,101,114,40,41,32,62,61,32,49>>]}]},{dd,[],[{p,[],[<<84,105,109,101,32,117,110,105,116,32,101,120,112,114,101,115,115,101,100,32,105,110,32,112,97,114,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,101,113,117,97,108,115,32>>,{code,[],[<<49,47,80,97,114,116,115,80,101,114,83,101,99,111,110,100>>]},<<32,115,101,99,111,110,100,46>>]}]},{dt,[],[{code,[],[<<115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,108,108,105,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,99,114,111,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48,95,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,110,111,115,101,99,111,110,100>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,116,105,109,101,32,117,110,105,116,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,116,104,101,32,105,110,116,101,103,101,114,32>>,{code,[],[<<49,48,48,48,95,48,48,48,95,48,48,48>>]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,116,105,118,101>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,110,97,116,105,118,101,32,116,105,109,101,32,117,110,105,116,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,105,115,32,100,101,116,101,114,109,105,110,101,100,32,97,116,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,115,116,97,114,116,44,32,97,110,100,32,114,101,109,97,105,110,115,32,116,104,101,32,115,97,109,101,32,117,110,116,105,108,32,116,104,101,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,116,101,114,109,105,110,97,116,101,115,46,32,73,102,32,97,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,115,32,115,116,111,112,112,101,100,32,97,110,100,32,116,104,101,110,32,115,116,97,114,116,101,100,32,97,103,97,105,110,32,40,101,118,101,110,32,111,110,32,116,104,101,32,115,97,109,101,32,109,97,99,104,105,110,101,41,44,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,111,102,32,116,104,101,32,110,101,119,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,32,99,97,110,32,100,105,102,102,101,114,32,102,114,111,109,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,111,102,32,116,104,101,32,111,108,100,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,32,105,110,115,116,97,110,99,101,46>>]},{p,[],[<<79,110,101,32,99,97,110,32,103,101,116,32,97,110,32,97,112,112,114,111,120,105,109,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,98,121,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,40,49,44,32,115,101,99,111,110,100,44,32,110,97,116,105,118,101,41>>]}]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,101,113,117,97,108,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,119,104,111,108,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,115,32,112,101,114,32,115,101,99,111,110,100,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,115,32,112,101,114,32,115,101,99,111,110,100,32,100,111,101,115,32,110,111,116,32,97,100,100,32,117,112,32,116,111,32,97,32,119,104,111,108,101,32,110,117,109,98,101,114,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,114,111,117,110,100,101,100,32,100,111,119,110,119,97,114,100,115,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,103,105,118,101,115,32,121,111,117,32,109,111,114,101,32,111,114,32,108,101,115,115,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,113,117,97,108,105,116,121,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,46,32,73,116,32,115,101,116,115,32,97,32,108,105,109,105,116,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,82,101,115,111,108,117,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<114,101,115,111,108,117,116,105,111,110>>]},<<32,97,110,100,32,102,111,114,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,80,114,101,99,105,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<112,114,101,99,105,115,105,111,110>>]},<<32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,44,32,98,117,116,32,105,116,32,103,105,118,101,115,32,110,111,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32>>,{a,[{href,<<101,114,116,115,58,116,105,109,101,95,99,111,114,114,101,99,116,105,111,110,35,84,105,109,101,95,65,99,99,117,114,97,99,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<97,99,99,117,114,97,99,121>>]},<<32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,46,32,84,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,32,97,110,100,32,116,104,101,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,105,109,101,32,118,97,108,117,101,115,32,99,97,110,32,100,105,102,102,101,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,46>>]}]}]},{dt,[],[{code,[],[<<112,101,114,102,95,99,111,117,110,116,101,114>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32,112,101,114,102,111,114,109,97,110,99,101,32,99,111,117,110,116,101,114,32,116,105,109,101,32,117,110,105,116,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<112,101,114,102,95,99,111,117,110,116,101,114>>]},<<32,116,105,109,101,32,117,110,105,116,32,98,101,104,97,118,101,115,32,109,117,99,104,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,116,104,101,32>>,{code,[],[<<110,97,116,105,118,101>>]},<<32,116,105,109,101,32,117,110,105,116,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,32,100,105,102,102,101,114,32,98,101,116,119,101,101,110,32,114,117,110,116,105,109,101,32,114,101,115,116,97,114,116,115,46,32,84,111,32,103,101,116,32,118,97,108,117,101,115,32,111,102,32,116,104,105,115,32,116,121,112,101,44,32,99,97,108,108,32>>,{a,[{href,<<107,101,114,110,101,108,58,111,115,35,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,115,58,112,101,114,102,95,99,111,117,110,116,101,114,47,48>>]}]},<<46>>]}]},{dt,[],[{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116,40,41>>]}]}]},{dd,[],[{p,[],[<<68,101,112,114,101,99,97,116,101,100,32,115,121,109,98,111,108,105,99,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,115,32,107,101,112,116,32,102,111,114,32,98,97,99,107,119,97,114,100,115,45,99,111,109,112,97,116,105,98,105,108,105,116,121,46>>]}]}]},{p,[],[<<84,104,101,32>>,{code,[],[<<116,105,109,101,95,117,110,105,116,47,48>>]},<<32,116,121,112,101,32,99,97,110,32,98,101,32,101,120,116,101,110,100,101,100,46,32,84,111,32,99,111,110,118,101,114,116,32,116,105,109,101,32,118,97,108,117,101,115,32,98,101,116,119,101,101,110,32,116,105,109,101,32,117,110,105,116,115,44,32,117,115,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,99,111,110,118,101,114,116,95,116,105,109,101,95,117,110,105,116,47,51>>]}]},<<46>>]}]},#{signature => [{attribute,{162,2},type,{time_unit,{type,{163,2},union,[{type,{163,2},pos_integer,[]},{atom,{164,9},second},{atom,{165,9},millisecond},{atom,{166,9},microsecond},{atom,{167,9},nanosecond},{atom,{168,9},native},{atom,{169,9},perf_counter},{user_type,{170,9},deprecated_time_unit,[]}]},[]}}]}},{{type,deprecated_time_unit,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,173}],[<<45,116,121,112,101,32,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{a,[{id,<<116,121,112,101,95,100,101,112,114,101,99,97,116,101,100,95,116,105,109,101,95,117,110,105,116>>}],[]},{p,[],[<<84,104,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<116,105,109,101,95,117,110,105,116,40,41>>]}]},<<32,116,121,112,101,32,97,108,115,111,32,99,111,110,115,105,115,116,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32>>,{em,[],[<<100,101,112,114,101,99,97,116,101,100>>]},<<32,115,121,109,98,111,108,105,99,32,116,105,109,101,32,117,110,105,116,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,108,108,105,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,108,108,105,115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<109,105,99,114,111,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<109,105,99,114,111,115,101,99,111,110,100>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<110,97,110,111,95,115,101,99,111,110,100,115>>]}]},{dd,[],[{p,[],[<<83,97,109,101,32,97,115,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,116,121,112,101,95,116,105,109,101,95,117,110,105,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<110,97,110,111,115,101,99,111,110,100>>]}]},<<46>>]}]}]}]},#{signature => [{attribute,{173,2},type,{deprecated_time_unit,{type,{174,7},union,[{atom,{174,7},seconds},{atom,{175,9},milli_seconds},{atom,{176,9},micro_seconds},{atom,{177,9},nano_seconds}]},[]}}]}},{{type,dist_handle,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,185}],[<<45,116,121,112,101,32,100,105,115,116,95,104,97,110,100,108,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,111,112,97,113,117,101,32,104,97,110,100,108,101,32,105,100,101,110,116,105,102,121,105,110,103,32,97,32,100,105,115,116,114,105,98,117,116,105,111,110,32,99,104,97,110,110,101,108,46>>]}]},#{signature => [{attribute,{185,2},opaque,{dist_handle,{type,{185,26},atom,[]},[]}}]}},{{type,nif_resource,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,182}],[<<45,116,121,112,101,32,110,105,102,95,114,101,115,111,117,114,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,111,112,97,113,117,101,32,104,97,110,100,108,101,32,105,100,101,110,116,105,102,121,105,110,103,32,97,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,95,110,105,102,35,114,101,115,111,117,114,99,101,95,111,98,106,101,99,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,114,101,102>>}],[<<78,73,70,32,114,101,115,111,117,114,99,101,32,111,98,106,101,99,116,32>>]},<<46>>]}]},#{signature => [{attribute,{182,2},opaque,{nif_resource,{type,{182,27},reference,[]},[]}}]}},{{type,spawn_opt_option,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3299}],[<<45,116,121,112,101,32,115,112,97,119,110,95,111,112,116,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<79,112,116,105,111,110,115,32,102,111,114,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,115,112,97,119,110,95,111,112,116,47,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,112,97,119,110,95,111,112,116,40,41>>]}]},<<46>>]}]},#{signature => [{attribute,{3299,2},type,{spawn_opt_option,{type,{3300,2},union,[{atom,{3300,2},link},{atom,{3301,9},monitor},{type,{3302,9},tuple,[{atom,{3302,10},monitor},{ann_type,{3302,19},[{var,{3302,19},'MonitorOpts'},{type,{3302,34},list,[{user_type,{3302,35},monitor_option,[]}]}]}]},{type,{3303,9},tuple,[{atom,{3303,10},priority},{ann_type,{3303,20},[{var,{3303,20},'Level'},{user_type,{3303,29},priority_level,[]}]}]},{type,{3304,9},tuple,[{atom,{3304,10},fullsweep_after},{ann_type,{3304,27},[{var,{3304,27},'Number'},{type,{3304,37},non_neg_integer,[]}]}]},{type,{3305,9},tuple,[{atom,{3305,10},min_heap_size},{ann_type,{3305,25},[{var,{3305,25},'Size'},{type,{3305,33},non_neg_integer,[]}]}]},{type,{3306,9},tuple,[{atom,{3306,10},min_bin_vheap_size},{ann_type,{3306,30},[{var,{3306,30},'VSize'},{type,{3306,39},non_neg_integer,[]}]}]},{type,{3307,9},tuple,[{atom,{3307,10},max_heap_size},{ann_type,{3307,25},[{var,{3307,25},'Size'},{user_type,{3307,33},max_heap_size,[]}]}]},{type,{3308,9},tuple,[{atom,{3308,10},message_queue_data},{ann_type,{3308,30},[{var,{3308,30},'MQD'},{user_type,{3308,37},message_queue_data,[]}]}]},{type,{3309,9},tuple,[{atom,{3309,10},async_dist},{ann_type,{3309,22},[{var,{3309,22},'Enabled'},{type,{3309,33},boolean,[]}]}]}]},[]}}]}},{{type,priority_level,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2638}],[<<45,116,121,112,101,32,112,114,105,111,114,105,116,121,95,108,101,118,101,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,112,114,105,111,114,105,116,121,32,108,101,118,101,108,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,112,114,105,111,114,105,116,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,112,114,105,111,114,105,116,121,44,32,76,101,118,101,108,41>>]}]}]}]},#{signature => [{attribute,{2638,2},type,{priority_level,{type,{2639,7},union,[{atom,{2639,7},low},{atom,{2639,13},normal},{atom,{2639,22},high},{atom,{2639,29},max}]},[]}}]}},{{type,max_heap_size,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3291}],[<<45,116,121,112,101,32,109,97,120,95,104,101,97,112,95,115,105,122,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,109,97,120,32,104,101,97,112,32,115,105,122,101,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,97,120,95,104,101,97,112,95,115,105,122,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,97,120,95,104,101,97,112,95,115,105,122,101,44,32,77,97,120,72,101,97,112,83,105,122,101,41>>]}]}]}]},#{signature => [{attribute,{3291,2},type,{max_heap_size,{ann_type,{3292,9},[{var,{3292,9},'Size'},{type,{3292,17},union,[{type,{3292,17},non_neg_integer,[]},{type,{3294,9},map,[{type,{3294,17},map_field_assoc,[{atom,{3294,12},size},{type,{3294,20},non_neg_integer,[]}]},{type,{3295,17},map_field_assoc,[{atom,{3295,12},kill},{type,{3295,20},boolean,[]}]},{type,{3296,25},map_field_assoc,[{atom,{3296,12},error_logger},{type,{3296,28},boolean,[]}]},{type,{3297,36},map_field_assoc,[{atom,{3297,12},include_shared_binaries},{type,{3297,39},boolean,[]}]}]}]}]},[]}}]}},{{type,message_queue_data,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,2641}],[<<45,116,121,112,101,32,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<80,114,111,99,101,115,115,32,109,101,115,115,97,103,101,32,113,117,101,117,101,32,100,97,116,97,32,99,111,110,102,105,103,117,114,97,116,105,111,110,46,32,70,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,115,101,101,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,112,114,111,99,101,115,115,95,102,108,97,103,95,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<112,114,111,99,101,115,115,95,102,108,97,103,40,109,101,115,115,97,103,101,95,113,117,101,117,101,95,100,97,116,97,44,32,77,81,68,41>>]}]}]}]},#{signature => [{attribute,{2641,2},type,{message_queue_data,{type,{2642,2},union,[{atom,{2642,2},off_heap},{atom,{2642,13},on_heap}]},[]}}]}},{{type,stacktrace_extrainfo,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,147}],[<<45,116,121,112,101,32,115,116,97,99,107,116,114,97,99,101,95,101,120,116,114,97,105,110,102,111,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32,115,116,97,99,107,116,114,97,99,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,98,121,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115,35,115,116,97,99,107,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,114,111,114,115,32,97,110,100,32,69,114,114,111,114,32,72,97,110,100,108,105,110,103>>]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,46>>]}]},#{signature => [{attribute,{147,2},type,{stacktrace_extrainfo,{type,{148,9},union,[{type,{148,9},tuple,[{atom,{148,10},line},{type,{148,16},pos_integer,[]}]},{type,{149,9},tuple,[{atom,{149,10},file},{remote_type,{149,16},[{atom,{149,16},unicode},{atom,{149,24},chardata},[]]}]},{type,{150,9},tuple,[{atom,{150,10},error_info},{type,{150,22},map,[{type,{150,32},map_field_assoc,[{atom,{150,25},module},{type,{150,35},module,[]}]},{type,{150,54},map_field_assoc,[{atom,{150,45},function},{type,{150,57},atom,[]}]},{type,{150,71},map_field_assoc,[{atom,{150,65},cause},{type,{150,74},term,[]}]}]}]},{type,{151,9},tuple,[{type,{151,10},atom,[]},{type,{151,18},term,[]}]}]},[]}}]}},{{type,stacktrace,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,152}],[<<45,116,121,112,101,32,115,116,97,99,107,116,114,97,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,69,114,108,97,110,103,32,115,116,97,99,107,116,114,97,99,101,32,97,115,32,100,101,115,99,114,105,98,101,100,32,98,121,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,101,114,114,111,114,115,35,115,116,97,99,107,116,114,97,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<69,114,114,111,114,115,32,97,110,100,32,69,114,114,111,114,32,72,97,110,100,108,105,110,103>>]},<<32,115,101,99,116,105,111,110,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,82,101,102,101,114,101,110,99,101,32,77,97,110,117,97,108,46>>]}]},#{signature => [{attribute,{152,2},type,{stacktrace,{type,{152,23},list,[{type,{152,24},union,[{type,{152,24},tuple,[{type,{152,25},module,[]},{type,{152,35},atom,[]},{type,{152,43},union,[{type,{152,43},arity,[]},{type,{152,53},list,[{type,{152,54},term,[]}]}]},{type,{153,25},list,[{user_type,{153,26},stacktrace_extrainfo,[]}]}]},{type,{154,24},tuple,[{type,{154,25},function,[]},{type,{154,37},union,[{type,{154,37},arity,[]},{type,{154,47},list,[{type,{154,48},term,[]}]}]},{type,{154,57},list,[{user_type,{154,58},stacktrace_extrainfo,[]}]}]}]}]},[]}}]}},{{type,send_destination,0},[{file,[101,114,108,97,110,103,46,101,114,108]},{location,3737}],[<<45,116,121,112,101,32,115,101,110,100,95,100,101,115,116,105,110,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,102,111,114,32,97,32,115,101,110,100,32,111,112,101,114,97,116,105,111,110,44,32,99,97,110,32,98,101,32,97,32,114,101,109,111,116,101,32,111,114,32,108,111,99,97,108,32,112,114,111,99,101,115,115,32,105,100,101,110,116,105,102,105,101,114,44,32,97,32,40,108,111,99,97,108,41,32,112,111,114,116,44,32,97,32,114,101,102,101,114,101,110,99,101,32,100,101,110,111,116,105,110,103,32,97,32,112,114,111,99,101,115,115,32,97,108,105,97,115,44,32,97,32,108,111,99,97,108,108,121,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,44,32,111,114,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,82,101,103,78,97,109,101,44,32,78,111,100,101,125>>]},<<32,102,111,114,32,97,32,114,101,103,105,115,116,101,114,101,100,32,110,97,109,101,32,97,116,32,97,110,111,116,104,101,114,32,110,111,100,101,46>>]}]},#{signature => [{attribute,{3737,2},type,{send_destination,{type,{3737,29},union,[{type,{3737,29},pid,[]},{type,{3738,29},reference,[]},{type,{3739,29},port,[]},{ann_type,{3740,30},[{var,{3740,30},'RegName'},{type,{3740,41},atom,[]}]},{type,{3741,29},tuple,[{ann_type,{3741,30},[{var,{3741,30},'RegName'},{type,{3741,41},atom,[]}]},{ann_type,{3741,49},[{var,{3741,49},'Node'},{type,{3741,57},node,[]}]}]}]},[]}}]}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/shell_docs_SUITE_data/file.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/file.docs_v1 index 9c88ce7723c1..db53fb587bfd 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/file.docs_v1 +++ b/lib/stdlib/test/shell_docs_SUITE_data/file.docs_v1 @@ -1 +1 @@ -{docs_v1,[{file,[102,105,108,101,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,112,114,111,118,105,100,101,115,32,97,110,32,105,110,116,101,114,102,97,99,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<70,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,97,114,101,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,97,112,112,101,97,114,32,97,116,111,109,105,99,32,119,104,101,110,32,103,111,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,32,115,97,109,101,32,102,105,108,101,32,115,101,114,118,101,114,46,32,65,32,78,73,70,32,111,114,32,111,116,104,101,114,32,79,83,32,112,114,111,99,101,115,115,32,109,97,121,32,111,98,115,101,114,118,101,32,105,110,116,101,114,109,101,100,105,97,116,101,32,115,116,101,112,115,32,111,110,32,99,101,114,116,97,105,110,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,115,111,109,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,44,32,101,103,46,32,114,101,110,97,109,105,110,103,32,97,110,32,101,120,105,115,116,105,110,103,32,102,105,108,101,32,111,110,32,87,105,110,100,111,119,115,44,32,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]},<<32>>]},<<111,110,32,97,110,121,32,79,83,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,119,114,105,116,105,110,103,46>>]}]},{p,[],[<<82,101,103,97,114,100,105,110,103,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,99,97,110,32,111,112,101,114,97,116,101,32,105,110,32,116,119,111,32,109,111,100,101,115,46,32,84,104,101,32,99,117,114,114,101,110,116,32,109,111,100,101,32,99,97,110,32,98,101,32,113,117,101,114,105,101,100,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>]}]},<<46,32,73,116,32,114,101,116,117,114,110,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,111,114,32>>,{code,[],[<<117,116,102,56>>]},<<46>>]},{p,[],[<<73,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,109,111,100,101,44,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,100,111,101,115,32,110,111,116,32,99,104,97,110,103,101,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32,102,105,108,101,110,97,109,101,115,46,32,73,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,44,32,102,105,108,101,110,97,109,101,115,32,99,97,110,32,99,111,110,116,97,105,110,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,50,53,53,32,97,110,100,32,116,104,101,32,86,77,32,99,111,110,118,101,114,116,115,32,102,105,108,101,110,97,109,101,115,32,98,97,99,107,32,97,110,100,32,102,111,114,116,104,32,116,111,32,116,104,101,32,110,97,116,105,118,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,40,117,115,117,97,108,108,121,32,85,84,70,45,56,44,32,98,117,116,32,85,84,70,45,49,54,32,111,110,32,87,105,110,100,111,119,115,41,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,109,111,100,101,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,46,32,87,105,110,100,111,119,115,44,32,77,97,99,79,83,32,88,32,97,110,100,32,65,110,100,114,111,105,100,32,101,110,102,111,114,99,101,32,99,111,110,115,105,115,116,101,110,116,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,116,104,101,32,86,77,32,117,115,101,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,46>>]},{p,[],[<<79,110,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,108,108,32,85,110,105,120,32,115,121,115,116,101,109,115,32,101,120,99,101,112,116,32,77,97,99,79,83,32,88,41,44,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,105,102,32,116,104,101,32,116,101,114,109,105,110,97,108,32,115,117,112,112,111,114,116,115,32,85,84,70,45,56,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,99,97,110,32,98,101,32,111,118,101,114,114,105,100,100,101,110,32,117,115,105,110,103,32>>,{code,[],[<<43,102,110,108>>]},<<32,40,116,111,32,102,111,114,99,101,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,109,111,100,101,41,32,111,114,32>>,{code,[],[<<43,102,110,117>>]},<<32,40,116,111,32,102,111,114,99,101,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,41,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,101,114,116,115,58,101,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<101,114,108>>]}]},<<46>>]},{p,[],[<<79,110,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,44,32,102,105,108,101,115,32,99,97,110,32,98,101,32,105,110,99,111,110,115,105,115,116,101,110,116,108,121,32,110,97,109,101,100,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,115,111,109,101,32,102,105,108,101,115,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,85,84,70,45,56,32,119,104,105,108,101,32,111,116,104,101,114,115,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,73,83,79,32,76,97,116,105,110,45,49,46,32,84,104,101,32,99,111,110,99,101,112,116,32,111,102,32>>,{em,[],[<<114,97,119,32,102,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,105,110,116,114,111,100,117,99,101,100,32,116,111,32,104,97,110,100,108,101,32,102,105,108,101,32,115,121,115,116,101,109,115,32,119,105,116,104,32,105,110,99,111,110,115,105,115,116,101,110,116,32,110,97,109,105,110,103,32,119,104,101,110,32,114,117,110,110,105,110,103,32,105,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,46>>]},{p,[],[<<65,32>>,{em,[],[<<114,97,119,32,102,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32,102,105,108,101,110,97,109,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,105,110,97,114,121,46,32,84,104,101,32,69,114,108,97,110,103,32,86,77,32,100,111,101,115,32,110,111,116,32,116,114,97,110,115,108,97,116,101,32,97,32,102,105,108,101,110,97,109,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,105,110,97,114,121,32,111,110,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,105,110,103,32,105,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,44,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,108,105,115,116,95,100,105,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,100,105,114,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,107,47,49>>]}]},<<32,110,101,118,101,114,32,114,101,116,117,114,110,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,84,111,32,114,101,116,117,114,110,32,97,108,108,32,102,105,108,101,110,97,109,101,115,32,105,110,99,108,117,100,105,110,103,32,114,97,119,32,102,105,108,101,110,97,109,101,115,44,32,117,115,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,108,105,115,116,95,100,105,114,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,105,115,116,95,100,105,114,95,97,108,108,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,107,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,97,100,95,108,105,110,107,95,97,108,108,47,49>>]}]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,95,117,115,97,103,101,35,110,111,116,101,115,45,97,98,111,117,116,45,114,97,119,45,102,105,108,101,110,97,109,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<78,111,116,101,115,32,65,98,111,117,116,32,82,97,119,32,70,105,108,101,110,97,109,101,115>>]},<<32,105,110,32,116,104,101,32,83,84,68,76,73,66,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,117,115,101,100,32,116,111,32,97,99,99,101,112,116,32,102,105,108,101,110,97,109,101,115,32,99,111,110,116,97,105,110,105,110,103,32,110,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,116,101,103,101,114,32,118,97,108,117,101,32,122,101,114,111,41,46,32,84,104,105,115,32,99,97,117,115,101,100,32,116,104,101,32,110,97,109,101,32,116,111,32,98,101,32,116,114,117,110,99,97,116,101,100,32,97,110,100,32,105,110,32,115,111,109,101,32,99,97,115,101,115,32,97,114,103,117,109,101,110,116,115,32,116,111,32,112,114,105,109,105,116,105,118,101,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,98,101,32,109,105,120,101,100,32,117,112,46,32,70,105,108,101,110,97,109,101,115,32,99,111,110,116,97,105,110,105,110,103,32,110,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,105,110,115,105,100,101,32,116,104,101,32,102,105,108,101,110,97,109,101,32,97,114,101,32,110,111,119,32>>,{em,[],[<<114,101,106,101,99,116,101,100>>]},<<32,97,110,100,32,119,105,108,108,32,99,97,117,115,101,32,112,114,105,109,105,116,105,118,101,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,102,97,105,108,46>>]}]},{h2,[],[<<80,79,83,73,88,32,69,114,114,111,114,32,67,111,100,101,115>>]},{ul,[],[{li,[],[{code,[],[<<101,97,99,99,101,115>>]},<<32,45,32,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100>>]},{li,[],[{code,[],[<<101,97,103,97,105,110>>]},<<32,45,32,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101>>]},{li,[],[{code,[],[<<101,98,97,100,102>>]},<<32,45,32,66,97,100,32,102,105,108,101,32,110,117,109,98,101,114>>]},{li,[],[{code,[],[<<101,98,117,115,121>>]},<<32,45,32,70,105,108,101,32,98,117,115,121>>]},{li,[],[{code,[],[<<101,100,113,117,111,116>>]},<<32,45,32,68,105,115,107,32,113,117,111,116,97,32,101,120,99,101,101,100,101,100>>]},{li,[],[{code,[],[<<101,101,120,105,115,116>>]},<<32,45,32,70,105,108,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115>>]},{li,[],[{code,[],[<<101,102,97,117,108,116>>]},<<32,45,32,66,97,100,32,97,100,100,114,101,115,115,32,105,110,32,115,121,115,116,101,109,32,99,97,108,108,32,97,114,103,117,109,101,110,116>>]},{li,[],[{code,[],[<<101,102,98,105,103>>]},<<32,45,32,70,105,108,101,32,116,111,111,32,108,97,114,103,101>>]},{li,[],[{code,[],[<<101,105,110,116,114>>]},<<32,45,32,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108>>]},{li,[],[{code,[],[<<101,105,110,118,97,108>>]},<<32,45,32,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116>>]},{li,[],[{code,[],[<<101,105,111>>]},<<32,45,32,73,47,79,32,101,114,114,111,114>>]},{li,[],[{code,[],[<<101,105,115,100,105,114>>]},<<32,45,32,73,108,108,101,103,97,108,32,111,112,101,114,97,116,105,111,110,32,111,110,32,97,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,108,111,111,112>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,108,101,118,101,108,115,32,111,102,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115>>]},{li,[],[{code,[],[<<101,109,102,105,108,101>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115>>]},{li,[],[{code,[],[<<101,109,108,105,110,107>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,108,105,110,107,115>>]},{li,[],[{code,[],[<<101,110,97,109,101,116,111,111,108,111,110,103>>]},<<32,45,32,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103>>]},{li,[],[{code,[],[<<101,110,102,105,108,101>>]},<<32,45,32,70,105,108,101,32,116,97,98,108,101,32,111,118,101,114,102,108,111,119>>]},{li,[],[{code,[],[<<101,110,111,100,101,118>>]},<<32,45,32,78,111,32,115,117,99,104,32,100,101,118,105,99,101>>]},{li,[],[{code,[],[<<101,110,111,101,110,116>>]},<<32,45,32,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,109,101,109>>]},<<32,45,32,78,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,115,112,99>>]},<<32,45,32,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101>>]},{li,[],[{code,[],[<<101,110,111,116,98,108,107>>]},<<32,45,32,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100>>]},{li,[],[{code,[],[<<101,110,111,116,100,105,114>>]},<<32,45,32,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,116,115,117,112>>]},<<32,45,32,79,112,101,114,97,116,105,111,110,32,110,111,116,32,115,117,112,112,111,114,116,101,100>>]},{li,[],[{code,[],[<<101,110,120,105,111>>]},<<32,45,32,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115>>]},{li,[],[{code,[],[<<101,112,101,114,109>>]},<<32,45,32,78,111,116,32,111,119,110,101,114>>]},{li,[],[{code,[],[<<101,112,105,112,101>>]},<<32,45,32,66,114,111,107,101,110,32,112,105,112,101>>]},{li,[],[{code,[],[<<101,114,111,102,115>>]},<<32,45,32,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109>>]},{li,[],[{code,[],[<<101,115,112,105,112,101>>]},<<32,45,32,73,110,118,97,108,105,100,32,115,101,101,107>>]},{li,[],[{code,[],[<<101,115,114,99,104>>]},<<32,45,32,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115>>]},{li,[],[{code,[],[<<101,115,116,97,108,101>>]},<<32,45,32,83,116,97,108,101,32,114,101,109,111,116,101,32,102,105,108,101,32,104,97,110,100,108,101>>]},{li,[],[{code,[],[<<101,120,100,101,118>>]},<<32,45,32,67,114,111,115,115,45,100,111,109,97,105,110,32,108,105,110,107>>]}]},{h2,[],[<<80,101,114,102,111,114,109,97,110,99,101>>]},{p,[],[<<70,111,114,32,105,110,99,114,101,97,115,101,100,32,112,101,114,102,111,114,109,97,110,99,101,44,32,114,97,119,32,102,105,108,101,115,32,97,114,101,32,114,101,99,111,109,109,101,110,100,101,100,46>>]},{p,[],[<<65,32,110,111,114,109,97,108,32,102,105,108,101,32,105,115,32,114,101,97,108,108,121,32,97,32,112,114,111,99,101,115,115,32,115,111,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,110,32,73,47,79,32,100,101,118,105,99,101,32,40,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111>>]}]},<<41,46,32,84,104,101,114,101,102,111,114,101,44,32,119,104,101,110,32,100,97,116,97,32,105,115,32,119,114,105,116,116,101,110,32,116,111,32,97,32,110,111,114,109,97,108,32,102,105,108,101,44,32,116,104,101,32,115,101,110,100,105,110,103,32,111,102,32,116,104,101,32,100,97,116,97,32,116,111,32,116,104,101,32,102,105,108,101,32,112,114,111,99,101,115,115,44,32,99,111,112,105,101,115,32,97,108,108,32,100,97,116,97,32,116,104,97,116,32,97,114,101,32,110,111,116,32,98,105,110,97,114,105,101,115,46,32,79,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,32,97,110,100,32,119,114,105,116,105,110,103,32,98,105,110,97,114,105,101,115,32,105,115,32,116,104,101,114,101,102,111,114,101,32,114,101,99,111,109,109,101,110,100,101,100,46,32,73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,111,110,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,111,114,32,105,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,114,117,110,115,32,97,115,32,115,108,97,118,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,97,108,115,111,32,98,105,110,97,114,105,101,115,32,97,114,101,32,99,111,112,105,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<82,97,119,32,102,105,108,101,115,32,117,115,101,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,111,102,32,116,104,101,32,104,111,115,116,32,109,97,99,104,105,110,101,32,111,102,32,116,104,101,32,110,111,100,101,46,32,70,111,114,32,110,111,114,109,97,108,32,102,105,108,101,115,32,40,110,111,110,45,114,97,119,41,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,117,115,101,100,32,116,111,32,102,105,110,100,32,116,104,101,32,102,105,108,101,115,44,32,97,110,100,32,105,102,32,116,104,101,32,110,111,100,101,32,105,115,32,114,117,110,110,105,110,103,32,105,116,115,32,102,105,108,101,32,115,101,114,118,101,114,32,97,115,32,115,108,97,118,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,32,114,117,110,115,32,111,110,32,115,111,109,101,32,111,116,104,101,114,32,104,111,115,116,32,109,97,99,104,105,110,101,44,32,116,104,101,121,32,99,97,110,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,102,105,108,101,32,115,121,115,116,101,109,115,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,105,115,32,115,101,108,100,111,109,32,97,32,112,114,111,98,108,101,109,46>>]}]},{p,[],[{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,99,97,110,32,98,101,32,103,105,118,101,110,32,116,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]},<<32,116,111,32,116,117,114,110,32,111,110,32,99,97,99,104,105,110,103,44,32,119,104,105,99,104,32,119,105,108,108,32,114,101,100,117,99,101,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,32,97,110,100,32,103,114,101,97,116,108,121,32,105,109,112,114,111,118,101,32,112,101,114,102,111,114,109,97,110,99,101,32,102,111,114,32,115,109,97,108,108,32,114,101,97,100,115,32,97,110,100,32,119,114,105,116,101,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,111,118,101,114,104,101,97,100,32,119,111,110,39,116,32,100,105,115,97,112,112,101,97,114,32,99,111,109,112,108,101,116,101,108,121,32,97,110,100,32,105,116,39,115,32,98,101,115,116,32,116,111,32,107,101,101,112,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,97,32,109,105,110,105,109,117,109,46,32,65,115,32,97,32,99,111,110,116,114,105,118,101,100,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,32,119,114,105,116,101,115,32,52,77,66,32,105,110,32,50,46,53,32,115,101,99,111,110,100,115,32,119,104,101,110,32,116,101,115,116,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,40,78,97,109,101,41,32,45,62,10,32,32,32,32,123,111,107,44,32,70,100,125,32,61,32,102,105,108,101,58,111,112,101,110,40,78,97,109,101,44,32,91,114,97,119,44,32,119,114,105,116,101,44,32,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,98,105,110,97,114,121,93,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,52,32,98,115,108,32,50,48,41,44,10,32,32,32,32,102,105,108,101,58,99,108,111,115,101,40,70,100,41,46,10,10,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,95,70,100,44,32,48,41,32,45,62,10,32,32,32,32,111,107,59,10,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,77,41,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,77,32,45,32,49,41,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,97,108,108,121,32,101,113,117,105,118,97,108,101,110,116,32,99,111,100,101,32,119,114,105,116,101,115,32,49,50,56,32,98,121,116,101,115,32,112,101,114,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,97,110,100,32,115,111,32,100,111,101,115,32,116,104,101,32,115,97,109,101,32,119,111,114,107,32,105,110,32,48,46,48,56,32,115,101,99,111,110,100,115,44,32,119,104,105,99,104,32,105,115,32,114,111,117,103,104,108,121,32,51,48,32,116,105,109,101,115,32,102,97,115,116,101,114,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<99,114,101,97,116,101,95,102,105,108,101,40,78,97,109,101,41,32,45,62,10,32,32,32,32,123,111,107,44,32,70,100,125,32,61,32,102,105,108,101,58,111,112,101,110,40,78,97,109,101,44,32,91,114,97,119,44,32,119,114,105,116,101,44,32,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,98,105,110,97,114,121,93,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,52,32,98,115,108,32,50,48,41,44,10,32,32,32,32,102,105,108,101,58,99,108,111,115,101,40,70,100,41,44,10,32,32,32,32,111,107,46,10,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,95,70,100,44,32,48,41,32,45,62,10,32,32,32,32,111,107,59,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,41,32,119,104,101,110,32,77,32,62,61,32,49,50,56,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,58,40,49,50,56,41,47,117,110,105,116,58,56,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,32,45,32,49,50,56,41,59,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,41,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,58,40,77,41,47,117,110,105,116,58,56,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,32,45,32,49,41,46>>]}]},{p,[],[<<87,104,101,110,32,119,114,105,116,105,110,103,32,100,97,116,97,32,105,116,39,115,32,103,101,110,101,114,97,108,108,121,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,111,32,119,114,105,116,101,32,97,32,108,105,115,116,32,111,102,32,98,105,110,97,114,105,101,115,32,114,97,116,104,101,114,32,116,104,97,110,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,46,32,73,116,32,105,115,32,110,111,116,32,110,101,101,100,101,100,32,116,111,32,102,108,97,116,116,101,110,32,97,32,100,101,101,112,32,108,105,115,116,32,98,101,102,111,114,101,32,119,114,105,116,105,110,103,46,32,79,110,32,85,110,105,120,32,104,111,115,116,115,44,32,115,99,97,116,116,101,114,32,111,117,116,112,117,116,44,32,119,104,105,99,104,32,119,114,105,116,101,115,32,97,32,115,101,116,32,111,102,32,98,117,102,102,101,114,115,32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,105,115,32,117,115,101,100,32,119,104,101,110,32,112,111,115,115,105,98,108,101,46,32,73,110,32,116,104,105,115,32,119,97,121,32>>,{code,[],[<<119,114,105,116,101,40,70,68,44,32,91,66,105,110,49,44,32,66,105,110,50,32,124,32,66,105,110,51,93,41>>]},<<32,119,114,105,116,101,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,98,105,110,97,114,105,101,115,32,119,105,116,104,111,117,116,32,99,111,112,121,105,110,103,32,116,104,101,32,100,97,116,97,32,97,116,32,97,108,108,44,32,101,120,99,101,112,116,32,102,111,114,32,112,101,114,104,97,112,115,32,100,101,101,112,32,100,111,119,110,32,105,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,107,101,114,110,101,108,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,97,110,32,111,112,101,110,32,102,105,108,101,32,119,105,116,104,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111>>]}]},<<44,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,110,100,108,105,110,103,32,116,104,101,32,102,105,108,101,32,101,120,105,116,115,46,32,84,104,101,32,100,101,97,100,32,102,105,108,101,32,112,114,111,99,101,115,115,32,99,97,110,32,104,97,110,103,32,105,102,32,97,32,112,114,111,99,101,115,115,32,116,114,105,101,115,32,116,111,32,97,99,99,101,115,115,32,105,116,32,108,97,116,101,114,46,32,84,104,105,115,32,119,105,108,108,32,98,101,32,102,105,120,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{h2,[],[<<83,101,101,32,65,108,115,111>>]},{p,[],[{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,102,105,108,101,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,110,97,109,101,40,51,41>>]}]}]}]},#{name => <<102,105,108,101>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,102,105,108,101,46,120,109,108],types => #{{date_time,0} => {attribute,123,type,{date_time,{remote_type,123,[{atom,123,calendar},{atom,123,datetime},[]]},[]}},{deep_list,0} => {attribute,101,type,{deep_list,{type,101,list,[{type,101,union,[{type,101,char,[]},{type,101,atom,[]},{user_type,101,deep_list,[]}]}]},[]}},{delete_option,0} => {attribute,126,type,{delete_option,{atom,126,raw},[]}},{fd,0} => {attribute,87,type,{fd,{type,87,record,[{atom,87,file_descriptor}]},[]}},{file_info,0} => {attribute,86,type,{file_info,{type,86,record,[{atom,86,file_info}]},[]}},{file_info_option,0} => {attribute,129,type,{file_info_option,{type,129,union,[{type,129,tuple,[{atom,129,time},{atom,129,local}]},{type,129,tuple,[{atom,129,time},{atom,129,universal}]},{type,130,tuple,[{atom,130,time},{atom,130,posix}]},{atom,130,raw}]},[]}},{filename,0} => {attribute,84,type,{filename,{type,84,string,[]},[]}},{filename_all,0} => {attribute,85,type,{filename_all,{type,85,union,[{type,85,string,[]},{type,85,binary,[]}]},[]}},{io_device,0} => {attribute,88,type,{io_device,{type,88,union,[{type,88,pid,[]},{user_type,88,fd,[]}]},[]}},{location,0} => {attribute,89,type,{location,{type,89,union,[{type,89,integer,[]},{type,89,tuple,[{atom,89,bof},{ann_type,89,[{var,89,'Offset'},{type,89,integer,[]}]}]},{type,90,tuple,[{atom,90,cur},{ann_type,90,[{var,90,'Offset'},{type,90,integer,[]}]}]},{type,91,tuple,[{atom,91,eof},{ann_type,91,[{var,91,'Offset'},{type,91,integer,[]}]}]},{atom,91,bof},{atom,91,cur},{atom,91,eof}]},[]}},{mode,0} => {attribute,92,type,{mode,{type,92,union,[{atom,92,read},{atom,92,write},{atom,92,append},{atom,93,exclusive},{atom,93,raw},{atom,93,binary},{type,94,tuple,[{atom,94,delayed_write},{ann_type,95,[{var,95,'Size'},{type,95,non_neg_integer,[]}]},{ann_type,96,[{var,96,'Delay'},{type,96,non_neg_integer,[]}]}]},{atom,97,delayed_write},{type,97,tuple,[{atom,97,read_ahead},{ann_type,97,[{var,97,'Size'},{type,97,pos_integer,[]}]}]},{atom,98,read_ahead},{atom,98,compressed},{type,99,tuple,[{atom,99,encoding},{remote_type,99,[{atom,99,unicode},{atom,99,encoding},[]]}]},{atom,100,sync}]},[]}},{name,0} => {attribute,102,type,{name,{type,102,union,[{type,102,string,[]},{type,102,atom,[]},{user_type,102,deep_list,[]}]},[]}},{name_all,0} => {attribute,103,type,{name_all,{type,103,union,[{type,103,string,[]},{type,103,atom,[]},{user_type,103,deep_list,[]},{ann_type,103,[{var,103,'RawFilename'},{type,103,binary,[]}]}]},[]}},{posix,0} => {attribute,104,type,{posix,{type,105,union,[{atom,105,eacces},{atom,105,eagain},{atom,106,ebadf},{atom,106,ebadmsg},{atom,106,ebusy},{atom,107,edeadlk},{atom,107,edeadlock},{atom,107,edquot},{atom,108,eexist},{atom,109,efault},{atom,109,efbig},{atom,109,eftype},{atom,110,eintr},{atom,110,einval},{atom,110,eio},{atom,110,eisdir},{atom,111,eloop},{atom,112,emfile},{atom,112,emlink},{atom,112,emultihop},{atom,113,enametoolong},{atom,113,enfile},{atom,114,enobufs},{atom,114,enodev},{atom,114,enolck},{atom,114,enolink},{atom,114,enoent},{atom,115,enomem},{atom,115,enospc},{atom,115,enosr},{atom,115,enostr},{atom,115,enosys},{atom,116,enotblk},{atom,116,enotdir},{atom,116,enotsup},{atom,116,enxio},{atom,117,eopnotsupp},{atom,117,eoverflow},{atom,118,eperm},{atom,118,epipe},{atom,119,erange},{atom,119,erofs},{atom,120,espipe},{atom,120,esrch},{atom,120,estale},{atom,121,etxtbsy},{atom,122,exdev}]},[]}},{posix_file_advise,0} => {attribute,124,type,{posix_file_advise,{type,124,union,[{atom,124,normal},{atom,124,sequential},{atom,124,random},{atom,125,no_reuse},{atom,125,will_need},{atom,125,dont_need}]},[]}},{sendfile_option,0} => {attribute,127,type,{sendfile_option,{type,127,union,[{type,127,tuple,[{atom,127,chunk_size},{type,127,non_neg_integer,[]}]},{type,128,tuple,[{atom,128,use_threads},{type,128,boolean,[]}]}]},[]}}}},[{{function,advise,4},[{file,[102,105,108,101,46,101,114,108]},{location,565}],[<<97,100,118,105,115,101,47,52>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<112,111,115,105,120,95,102,105,108,101,95,97,100,118,105,115,101>>}],[]}]},{p,[],[{code,[],[<<97,100,118,105,115,101,47,52>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,110,110,111,117,110,99,101,32,97,110,32,105,110,116,101,110,116,105,111,110,32,116,111,32,97,99,99,101,115,115,32,102,105,108,101,32,100,97,116,97,32,105,110,32,97,32,115,112,101,99,105,102,105,99,32,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,102,117,116,117,114,101,44,32,116,104,117,115,32,97,108,108,111,119,105,110,103,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,116,111,32,112,101,114,102,111,114,109,32,97,112,112,114,111,112,114,105,97,116,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,46>>]},{p,[],[<<79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,109,105,103,104,116,32,104,97,118,101,32,110,111,32,101,102,102,101,99,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,56>>,signature => [{attribute,565,spec,{{advise,4},[{type,565,bounded_fun,[{type,565,'fun',[{type,565,product,[{var,565,'IoDevice'},{var,565,'Offset'},{var,565,'Length'},{var,565,'Advise'}]},{type,565,union,[{atom,565,ok},{type,565,tuple,[{atom,565,error},{var,565,'Reason'}]}]}]},[{type,566,constraint,[{atom,566,is_subtype},[{var,566,'IoDevice'},{user_type,566,io_device,[]}]]},{type,567,constraint,[{atom,567,is_subtype},[{var,567,'Offset'},{type,567,integer,[]}]]},{type,568,constraint,[{atom,568,is_subtype},[{var,568,'Length'},{type,568,integer,[]}]]},{type,569,constraint,[{atom,569,is_subtype},[{var,569,'Advise'},{user_type,569,posix_file_advise,[]}]]},{type,570,constraint,[{atom,570,is_subtype},[{var,570,'Reason'},{type,570,union,[{user_type,570,posix,[]},{atom,570,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,allocate,3},[{file,[102,105,108,101,46,101,114,108]},{location,579}],[<<97,108,108,111,99,97,116,101,47,51>>],#{<<101,110>> => [{p,[],[{code,[],[<<97,108,108,111,99,97,116,101,47,51>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,112,114,101,97,108,108,111,99,97,116,101,32,115,112,97,99,101,32,102,111,114,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,111,110,108,121,32,115,117,99,99,101,101,100,115,32,105,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,112,114,111,118,105,100,101,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,57>>,signature => [{attribute,579,spec,{{allocate,3},[{type,579,bounded_fun,[{type,579,'fun',[{type,579,product,[{var,579,'File'},{var,579,'Offset'},{var,579,'Length'}]},{type,580,union,[{atom,580,ok},{type,580,tuple,[{atom,580,error},{user_type,580,posix,[]}]}]}]},[{type,581,constraint,[{atom,581,is_subtype},[{var,581,'File'},{user_type,581,io_device,[]}]]},{type,582,constraint,[{atom,582,is_subtype},[{var,582,'Offset'},{type,582,non_neg_integer,[]}]]},{type,583,constraint,[{atom,583,is_subtype},[{var,583,'Length'},{type,583,non_neg_integer,[]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,change_group,2},[{file,[102,105,108,101,46,101,114,108]},{location,1249}],[<<99,104,97,110,103,101,95,103,114,111,117,112,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,103,114,111,117,112,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,56>>,signature => [{attribute,1249,spec,{{change_group,2},[{type,1249,bounded_fun,[{type,1249,'fun',[{type,1249,product,[{var,1249,'Filename'},{var,1249,'Gid'}]},{type,1249,union,[{atom,1249,ok},{type,1249,tuple,[{atom,1249,error},{var,1249,'Reason'}]}]}]},[{type,1250,constraint,[{atom,1250,is_subtype},[{var,1250,'Filename'},{user_type,1250,name_all,[]}]]},{type,1251,constraint,[{atom,1251,is_subtype},[{var,1251,'Gid'},{type,1251,integer,[]}]]},{type,1252,constraint,[{atom,1252,is_subtype},[{var,1252,'Reason'},{type,1252,union,[{user_type,1252,posix,[]},{atom,1252,badarg}]}]]}]]}]}}]}},{{function,change_mode,2},[{file,[102,105,108,101,46,101,114,108]},{location,1221}],[<<99,104,97,110,103,101,95,109,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,112,101,114,109,105,115,115,105,111,110,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,49,54>>,signature => [{attribute,1221,spec,{{change_mode,2},[{type,1221,bounded_fun,[{type,1221,'fun',[{type,1221,product,[{var,1221,'Filename'},{var,1221,'Mode'}]},{type,1221,union,[{atom,1221,ok},{type,1221,tuple,[{atom,1221,error},{var,1221,'Reason'}]}]}]},[{type,1222,constraint,[{atom,1222,is_subtype},[{var,1222,'Filename'},{user_type,1222,name_all,[]}]]},{type,1223,constraint,[{atom,1223,is_subtype},[{var,1223,'Mode'},{type,1223,integer,[]}]]},{type,1224,constraint,[{atom,1224,is_subtype},[{var,1224,'Reason'},{type,1224,union,[{user_type,1224,posix,[]},{atom,1224,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,change_owner,2},[{file,[102,105,108,101,46,101,114,108]},{location,1230}],[<<99,104,97,110,103,101,95,111,119,110,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,111,119,110,101,114,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,50,52>>,signature => [{attribute,1230,spec,{{change_owner,2},[{type,1230,bounded_fun,[{type,1230,'fun',[{type,1230,product,[{var,1230,'Filename'},{var,1230,'Uid'}]},{type,1230,union,[{atom,1230,ok},{type,1230,tuple,[{atom,1230,error},{var,1230,'Reason'}]}]}]},[{type,1231,constraint,[{atom,1231,is_subtype},[{var,1231,'Filename'},{user_type,1231,name_all,[]}]]},{type,1232,constraint,[{atom,1232,is_subtype},[{var,1232,'Uid'},{type,1232,integer,[]}]]},{type,1233,constraint,[{atom,1233,is_subtype},[{var,1233,'Reason'},{type,1233,union,[{user_type,1233,posix,[]},{atom,1233,badarg}]}]]}]]}]}}]}},{{function,change_owner,3},[{file,[102,105,108,101,46,101,114,108]},{location,1239}],[<<99,104,97,110,103,101,95,111,119,110,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,111,119,110,101,114,32,97,110,100,32,103,114,111,117,112,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,51,50>>,signature => [{attribute,1239,spec,{{change_owner,3},[{type,1239,bounded_fun,[{type,1239,'fun',[{type,1239,product,[{var,1239,'Filename'},{var,1239,'Uid'},{var,1239,'Gid'}]},{type,1239,union,[{atom,1239,ok},{type,1239,tuple,[{atom,1239,error},{var,1239,'Reason'}]}]}]},[{type,1240,constraint,[{atom,1240,is_subtype},[{var,1240,'Filename'},{user_type,1240,name_all,[]}]]},{type,1241,constraint,[{atom,1241,is_subtype},[{var,1241,'Uid'},{type,1241,integer,[]}]]},{type,1242,constraint,[{atom,1242,is_subtype},[{var,1242,'Gid'},{type,1242,integer,[]}]]},{type,1243,constraint,[{atom,1243,is_subtype},[{var,1243,'Reason'},{type,1243,union,[{user_type,1243,posix,[]},{atom,1243,badarg}]}]]}]]}]}}]}},{{function,change_time,2},[{file,[102,105,108,101,46,101,114,108]},{location,1258}],[<<99,104,97,110,103,101,95,116,105,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,97,110,100,32,97,99,99,101,115,115,32,116,105,109,101,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,52,48>>,signature => [{attribute,1258,spec,{{change_time,2},[{type,1258,bounded_fun,[{type,1258,'fun',[{type,1258,product,[{var,1258,'Filename'},{var,1258,'Mtime'}]},{type,1258,union,[{atom,1258,ok},{type,1258,tuple,[{atom,1258,error},{var,1258,'Reason'}]}]}]},[{type,1259,constraint,[{atom,1259,is_subtype},[{var,1259,'Filename'},{user_type,1259,name_all,[]}]]},{type,1260,constraint,[{atom,1260,is_subtype},[{var,1260,'Mtime'},{user_type,1260,date_time,[]}]]},{type,1261,constraint,[{atom,1261,is_subtype},[{var,1261,'Reason'},{type,1261,union,[{user_type,1261,posix,[]},{atom,1261,badarg}]}]]}]]}]}}]}},{{function,change_time,3},[{file,[102,105,108,101,46,101,114,108]},{location,1268}],[<<99,104,97,110,103,101,95,116,105,109,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,97,110,100,32,108,97,115,116,32,97,99,99,101,115,115,32,116,105,109,101,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,52,56>>,signature => [{attribute,1268,spec,{{change_time,3},[{type,1268,bounded_fun,[{type,1268,'fun',[{type,1268,product,[{var,1268,'Filename'},{var,1268,'Atime'},{var,1268,'Mtime'}]},{type,1268,union,[{atom,1268,ok},{type,1268,tuple,[{atom,1268,error},{var,1268,'Reason'}]}]}]},[{type,1269,constraint,[{atom,1269,is_subtype},[{var,1269,'Filename'},{user_type,1269,name_all,[]}]]},{type,1270,constraint,[{atom,1270,is_subtype},[{var,1270,'Atime'},{user_type,1270,date_time,[]}]]},{type,1271,constraint,[{atom,1271,is_subtype},[{var,1271,'Mtime'},{user_type,1271,date_time,[]}]]},{type,1272,constraint,[{atom,1272,is_subtype},[{var,1272,'Reason'},{type,1272,union,[{user_type,1272,posix,[]},{atom,1272,badarg}]}]]}]]}]}}]}},{{function,close,1},[{file,[102,105,108,101,46,101,114,108]},{location,546}],[<<99,108,111,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,108,111,115,101,115,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,73,116,32,109,111,115,116,108,121,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<44,32,101,120,99,101,112,116,32,102,111,114,32,115,111,109,101,32,115,101,118,101,114,101,32,101,114,114,111,114,115,32,115,117,99,104,32,97,115,32,111,117,116,32,111,102,32,109,101,109,111,114,121,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,119,97,115,32,117,115,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,44,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,99,97,110,32,114,101,116,117,114,110,32,97,110,32,111,108,100,32,119,114,105,116,101,32,101,114,114,111,114,32,97,110,100,32,110,111,116,32,101,118,101,110,32,116,114,121,32,116,111,32,99,108,111,115,101,32,116,104,101,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,53,54>>,signature => [{attribute,546,spec,{{close,1},[{type,546,bounded_fun,[{type,546,'fun',[{type,546,product,[{var,546,'IoDevice'}]},{type,546,union,[{atom,546,ok},{type,546,tuple,[{atom,546,error},{var,546,'Reason'}]}]}]},[{type,547,constraint,[{atom,547,is_subtype},[{var,547,'IoDevice'},{user_type,547,io_device,[]}]]},{type,548,constraint,[{atom,548,is_subtype},[{var,548,'Reason'},{type,548,union,[{user_type,548,posix,[]},{atom,548,badarg},{atom,548,terminated}]}]]}]]}]}}]}},{{function,consult,1},[{file,[102,105,108,101,46,101,114,108]},{location,1025}],[<<99,111,110,115,117,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,69,114,108,97,110,103,32,116,101,114,109,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,44,32,102,114,111,109,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,84,101,114,109,115,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,116,101,114,109,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,84,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<46>>]}]}]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<102,46,116,120,116,58,32,32,123,112,101,114,115,111,110,44,32,34,107,97,108,108,101,34,44,32,50,53,125,46,10,32,32,32,32,32,32,32,32,123,112,101,114,115,111,110,44,32,34,112,101,108,108,101,34,44,32,51,48,125,46>>]}]},{pre,[],[{code,[],[<<49,62,32,102,105,108,101,58,99,111,110,115,117,108,116,40,34,102,46,116,120,116,34,41,46,10,123,111,107,44,91,123,112,101,114,115,111,110,44,34,107,97,108,108,101,34,44,50,53,125,44,123,112,101,114,115,111,110,44,34,112,101,108,108,101,34,44,51,48,125,93,125>>]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,54,57>>,signature => [{attribute,1025,spec,{{consult,1},[{type,1025,bounded_fun,[{type,1025,'fun',[{type,1025,product,[{var,1025,'Filename'}]},{type,1025,union,[{type,1025,tuple,[{atom,1025,ok},{var,1025,'Terms'}]},{type,1025,tuple,[{atom,1025,error},{var,1025,'Reason'}]}]}]},[{type,1026,constraint,[{atom,1026,is_subtype},[{var,1026,'Filename'},{user_type,1026,name_all,[]}]]},{type,1027,constraint,[{atom,1027,is_subtype},[{var,1027,'Terms'},{type,1027,list,[{type,1027,term,[]}]}]]},{type,1028,constraint,[{atom,1028,is_subtype},[{var,1028,'Reason'},{type,1028,union,[{user_type,1028,posix,[]},{atom,1028,badarg},{atom,1028,terminated},{atom,1028,system_limit},{type,1029,tuple,[{ann_type,1029,[{var,1029,'Line'},{type,1029,integer,[]}]},{ann_type,1029,[{var,1029,'Mod'},{type,1029,module,[]}]},{ann_type,1029,[{var,1029,'Term'},{type,1029,term,[]}]}]}]}]]}]]}]}}]}},{{function,copy,3},[{file,[102,105,108,101,46,101,114,108]},{location,788}],[<<99,111,112,121,47,51>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,48,55>>,equiv => {function,copy,2},signature => [{attribute,788,spec,{{copy,3},[{type,788,bounded_fun,[{type,788,'fun',[{type,788,product,[{var,788,'Source'},{var,788,'Destination'},{var,788,'ByteCount'}]},{type,789,union,[{type,789,tuple,[{atom,789,ok},{var,789,'BytesCopied'}]},{type,789,tuple,[{atom,789,error},{var,789,'Reason'}]}]}]},[{type,790,constraint,[{atom,790,is_subtype},[{var,790,'Source'},{type,790,union,[{user_type,790,io_device,[]},{var,790,'Filename'},{type,790,tuple,[{var,790,'Filename'},{var,790,'Modes'}]}]}]]},{type,791,constraint,[{atom,791,is_subtype},[{var,791,'Destination'},{type,791,union,[{user_type,791,io_device,[]},{var,791,'Filename'},{type,791,tuple,[{var,791,'Filename'},{var,791,'Modes'}]}]}]]},{type,792,constraint,[{atom,792,is_subtype},[{var,792,'Filename'},{user_type,792,name_all,[]}]]},{type,793,constraint,[{atom,793,is_subtype},[{var,793,'Modes'},{type,793,list,[{user_type,793,mode,[]}]}]]},{type,794,constraint,[{atom,794,is_subtype},[{var,794,'ByteCount'},{type,794,union,[{type,794,non_neg_integer,[]},{atom,794,infinity}]}]]},{type,795,constraint,[{atom,795,is_subtype},[{var,795,'BytesCopied'},{type,795,non_neg_integer,[]}]]},{type,796,constraint,[{atom,796,is_subtype},[{var,796,'Reason'},{type,796,union,[{user_type,796,posix,[]},{atom,796,badarg},{atom,796,terminated}]}]]}]]}]}}]}},{{function,copy,2},[{file,[102,105,108,101,46,101,114,108]},{location,777}],[<<99,111,112,121,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,112,105,101,115,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,98,121,116,101,115,32,102,114,111,109,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,116,111,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,32,116,111,32,101,105,116,104,101,114,32,102,105,108,101,110,97,109,101,115,32,111,114,32,73,79,32,100,101,118,105,99,101,115,32,102,114,111,109,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<111,112,101,110,47,50>>]},<<46,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<105,110,102,105,110,105,116,121>>]},<<44,32,100,101,110,111,116,105,110,103,32,97,110,32,105,110,102,105,110,105,116,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,111,100,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,111,115,115,105,98,108,101,32,109,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<44,32,97,110,100,32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<91,93>>]},<<46>>]},{p,[],[<<73,102,32,98,111,116,104,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,32,116,111,32,102,105,108,101,110,97,109,101,115,44,32,116,104,101,32,102,105,108,101,115,32,97,114,101,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<91,114,101,97,100,44,32,98,105,110,97,114,121,93>>]},<<32,97,110,100,32>>,{code,[],[<<91,119,114,105,116,101,44,32,98,105,110,97,114,121,93>>]},<<32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,105,114,32,109,111,100,101,32,108,105,115,116,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,116,111,32,111,112,116,105,109,105,122,101,32,116,104,101,32,99,111,112,121,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,102,105,108,101,110,97,109,101,44,32,105,116,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<32,109,111,100,101,32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,32,109,111,100,101,32,108,105,115,116,32,98,101,102,111,114,101,32,116,104,101,32,99,111,112,121,44,32,97,110,100,32,99,108,111,115,101,100,32,119,104,101,110,32,100,111,110,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,102,105,108,101,110,97,109,101,44,32,105,116,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,109,111,100,101,32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,32,109,111,100,101,32,108,105,115,116,32,98,101,102,111,114,101,32,116,104,101,32,99,111,112,121,44,32,97,110,100,32,99,108,111,115,101,100,32,119,104,101,110,32,100,111,110,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,67,111,112,105,101,100,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<66,121,116,101,115,67,111,112,105,101,100>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,116,104,97,116,32,119,97,115,32,99,111,112,105,101,100,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,32,111,110,32,116,104,101,32,115,111,117,114,99,101,46,32,73,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58,32,97,115,32,102,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,105,102,32,97,32,102,105,108,101,32,104,97,100,32,116,111,32,98,101,32,111,112,101,110,101,100,44,32,97,110,100,32,97,115,32,102,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,48,55>>,signature => [{attribute,777,spec,{{copy,2},[{type,777,bounded_fun,[{type,777,'fun',[{type,777,product,[{var,777,'Source'},{var,777,'Destination'}]},{type,777,union,[{type,777,tuple,[{atom,777,ok},{var,777,'BytesCopied'}]},{type,777,tuple,[{atom,777,error},{var,777,'Reason'}]}]}]},[{type,778,constraint,[{atom,778,is_subtype},[{var,778,'Source'},{type,778,union,[{user_type,778,io_device,[]},{var,778,'Filename'},{type,778,tuple,[{var,778,'Filename'},{var,778,'Modes'}]}]}]]},{type,779,constraint,[{atom,779,is_subtype},[{var,779,'Destination'},{type,779,union,[{user_type,779,io_device,[]},{var,779,'Filename'},{type,779,tuple,[{var,779,'Filename'},{var,779,'Modes'}]}]}]]},{type,780,constraint,[{atom,780,is_subtype},[{var,780,'Filename'},{user_type,780,name_all,[]}]]},{type,781,constraint,[{atom,781,is_subtype},[{var,781,'Modes'},{type,781,list,[{user_type,781,mode,[]}]}]]},{type,782,constraint,[{atom,782,is_subtype},[{var,782,'BytesCopied'},{type,782,non_neg_integer,[]}]]},{type,783,constraint,[{atom,783,is_subtype},[{var,783,'Reason'},{type,783,union,[{user_type,783,posix,[]},{atom,783,badarg},{atom,783,terminated}]}]]}]]}]}}]}},{{function,datasync,1},[{file,[102,105,108,101,46,101,114,108]},{location,731}],[<<100,97,116,97,115,121,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<69,110,115,117,114,101,115,32,116,104,97,116,32,97,110,121,32,98,117,102,102,101,114,115,32,107,101,112,116,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,40,110,111,116,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,73,110,32,109,97,110,121,32,119,97,121,115,32,105,116,32,114,101,115,101,109,98,108,101,115,32>>,{code,[],[<<102,115,121,110,99>>]},<<32,98,117,116,32,105,116,32,100,111,101,115,32,110,111,116,32,117,112,100,97,116,101,32,115,111,109,101,32,111,102,32,116,104,101,32,109,101,116,97,100,97,116,97,32,111,102,32,116,104,101,32,102,105,108,101,44,32,115,117,99,104,32,97,115,32,116,104,101,32,97,99,99,101,115,115,32,116,105,109,101,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]},{p,[],[<<65,112,112,108,105,99,97,116,105,111,110,115,32,116,104,97,116,32,97,99,99,101,115,115,32,100,97,116,97,98,97,115,101,115,32,111,114,32,108,111,103,32,102,105,108,101,115,32,111,102,116,101,110,32,119,114,105,116,101,32,97,32,116,105,110,121,32,100,97,116,97,32,102,114,97,103,109,101,110,116,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,111,110,101,32,108,105,110,101,32,105,110,32,97,32,108,111,103,32,102,105,108,101,41,32,97,110,100,32,116,104,101,110,32,99,97,108,108,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,119,114,105,116,116,101,110,32,100,97,116,97,32,105,115,32,112,104,121,115,105,99,97,108,108,121,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,104,97,114,100,32,100,105,115,107,46,32,85,110,102,111,114,116,117,110,97,116,101,108,121,44,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<32,97,108,119,97,121,115,32,105,110,105,116,105,97,116,101,115,32,116,119,111,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,115,58,32,111,110,101,32,102,111,114,32,116,104,101,32,110,101,119,108,121,32,119,114,105,116,116,101,110,32,100,97,116,97,32,97,110,100,32,97,110,111,116,104,101,114,32,111,110,101,32,116,111,32,117,112,100,97,116,101,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,105,109,101,32,115,116,111,114,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<46,32,73,102,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,105,109,101,32,105,115,32,110,111,116,32,97,32,112,97,114,116,32,111,102,32,116,104,101,32,116,114,97,110,115,97,99,116,105,111,110,32,99,111,110,99,101,112,116,44,32>>,{code,[],[<<102,100,97,116,97,115,121,110,99,40,41>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,118,111,105,100,32,117,110,110,101,99,101,115,115,97,114,121,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,100,105,115,107,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,115,46>>]},{p,[],[<<65,118,97,105,108,97,98,108,101,32,111,110,108,121,32,105,110,32,115,111,109,101,32,80,79,83,73,88,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,99,97,108,108,32,114,101,115,117,108,116,115,32,105,110,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<44,32,111,114,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,105,110,32,115,121,115,116,101,109,115,32,110,111,116,32,112,114,111,118,105,100,105,110,103,32,116,104,101,32>>,{code,[],[<<102,100,97,116,97,115,121,110,99,40,41>>]},<<32,115,121,115,99,97,108,108,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,52,53>>,signature => [{attribute,731,spec,{{datasync,1},[{type,731,bounded_fun,[{type,731,'fun',[{type,731,product,[{var,731,'IoDevice'}]},{type,731,union,[{atom,731,ok},{type,731,tuple,[{atom,731,error},{var,731,'Reason'}]}]}]},[{type,732,constraint,[{atom,732,is_subtype},[{var,732,'IoDevice'},{user_type,732,io_device,[]}]]},{type,733,constraint,[{atom,733,is_subtype},[{var,733,'Reason'},{type,733,union,[{user_type,733,posix,[]},{atom,733,badarg},{atom,733,terminated}]}]]}]]}]}}],since => <<79,84,80,32,82,49,52,66>>}},{{function,del_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,256}],[<<100,101,108,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,100,101,108,101,116,101,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<68,105,114>>]},<<46,32,84,104,101,32,100,105,114,101,99,116,111,114,121,32,109,117,115,116,32,98,101,32,101,109,112,116,121,32,98,101,102,111,114,101,32,105,116,32,99,97,110,32,98,101,32,100,101,108,101,116,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,105,115,32,110,111,116,32,101,109,112,116,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<65,116,116,101,109,112,116,32,116,111,32,100,101,108,101,116,101,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,54,56>>,signature => [{attribute,256,spec,{{del_dir,1},[{type,256,bounded_fun,[{type,256,'fun',[{type,256,product,[{var,256,'Dir'}]},{type,256,union,[{atom,256,ok},{type,256,tuple,[{atom,256,error},{var,256,'Reason'}]}]}]},[{type,257,constraint,[{atom,257,is_subtype},[{var,257,'Dir'},{user_type,257,name_all,[]}]]},{type,258,constraint,[{atom,258,is_subtype},[{var,258,'Reason'},{type,258,union,[{user_type,258,posix,[]},{atom,258,badarg}]}]]}]]}]}}]}},{{function,del_dir_r,1},[{file,[102,105,108,101,46,101,114,108]},{location,263}],[<<100,101,108,95,100,105,114,95,114,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,108,101,116,101,115,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<70,105,108,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,105,108,101>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,105,116,115,32,99,111,110,116,101,110,116,115,32,105,115,32,102,105,114,115,116,32,114,101,99,117,114,115,105,118,101,108,121,32,100,101,108,101,116,101,100,46,32,82,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,107>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,111,110,32,99,111,109,112,108,101,116,101,100,32,119,105,116,104,111,117,116,32,101,114,114,111,114,115,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,112,111,115,105,120,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,111,114,32,100,101,108,101,116,105,110,103,32>>,{code,[],[<<70,105,108,101>>]},<<46,32,73,102,32,115,111,109,101,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32,117,110,100,101,114,32>>,{code,[],[<<70,105,108,101>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,100,101,108,101,116,101,100,44,32>>,{code,[],[<<70,105,108,101>>]},<<32,99,97,110,110,111,116,32,98,101,32,100,101,108,101,116,101,100,32,97,115,32,105,116,32,105,115,32,110,111,110,45,101,109,112,116,121,44,32,97,110,100,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,101,120,105,115,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,48,52>>,signature => [{attribute,263,spec,{{del_dir_r,1},[{type,263,bounded_fun,[{type,263,'fun',[{type,263,product,[{var,263,'File'}]},{type,263,union,[{atom,263,ok},{type,263,tuple,[{atom,263,error},{var,263,'Reason'}]}]}]},[{type,264,constraint,[{atom,264,is_subtype},[{var,264,'File'},{user_type,264,name_all,[]}]]},{type,265,constraint,[{atom,265,is_subtype},[{var,265,'Reason'},{type,265,union,[{user_type,265,posix,[]},{atom,265,badarg}]}]]}]]}]}}],since => <<79,84,80,32,50,51,46,48>>}},{{function,delete,2},[{file,[102,105,108,101,46,101,114,108]},{location,221}],[<<100,101,108,101,116,101,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,50,54>>,equiv => {function,delete,1},signature => [{attribute,221,spec,{{delete,2},[{type,221,bounded_fun,[{type,221,'fun',[{type,221,product,[{var,221,'Filename'},{var,221,'Opts'}]},{type,221,union,[{atom,221,ok},{type,221,tuple,[{atom,221,error},{var,221,'Reason'}]}]}]},[{type,222,constraint,[{atom,222,is_subtype},[{var,222,'Filename'},{user_type,222,name_all,[]}]]},{type,223,constraint,[{atom,223,is_subtype},[{var,223,'Opts'},{type,223,list,[{user_type,223,delete_option,[]}]}]]},{type,224,constraint,[{atom,224,is_subtype},[{var,224,'Reason'},{type,224,union,[{user_type,224,posix,[]},{atom,224,badarg}]}]]}]]}]}}]}},{{function,delete,1},[{file,[102,105,108,101,46,101,114,108]},{location,214}],[<<100,101,108,101,116,101,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,101,108,101,116,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<84,114,105,101,115,32,116,111,32,100,101,108,101,116,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,46,32,84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,105,110,32,112,97,114,116,105,99,117,108,97,114,32,100,117,114,105,110,103,32,116,104,101,32,101,97,114,108,121,32,98,111,111,116,32,115,116,97,103,101,32,119,104,101,110,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,121,101,116,32,114,101,103,105,115,116,101,114,101,100,44,32,116,111,32,115,116,105,108,108,32,98,101,32,97,98,108,101,32,116,111,32,100,101,108,101,116,101,32,108,111,99,97,108,32,102,105,108,101,115,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,116,104,101,32,102,105,108,101,32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,115,46>>]}]},{dt,[],[{code,[],[<<101,112,101,114,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,32,97,110,100,32,116,104,101,32,117,115,101,114,32,105,115,32,110,111,116,32,115,117,112,101,114,117,115,101,114,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,104,97,115,32,97,110,32,105,109,112,114,111,112,101,114,32,116,121,112,101,44,32,115,117,99,104,32,97,115,32,116,117,112,108,101,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,44,32,97,32,98,97,100,32,116,121,112,101,32,102,111,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,119,105,108,108,32,112,114,111,98,97,98,108,121,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,50,54>>,signature => [{attribute,214,spec,{{delete,1},[{type,214,bounded_fun,[{type,214,'fun',[{type,214,product,[{var,214,'Filename'}]},{type,214,union,[{atom,214,ok},{type,214,tuple,[{atom,214,error},{var,214,'Reason'}]}]}]},[{type,215,constraint,[{atom,215,is_subtype},[{var,215,'Filename'},{user_type,215,name_all,[]}]]},{type,216,constraint,[{atom,216,is_subtype},[{var,216,'Reason'},{type,216,union,[{user_type,216,posix,[]},{atom,216,badarg}]}]]}]]}]}}]}},{{function,eval,1},[{file,[102,105,108,101,46,101,114,108]},{location,1065}],[<<101,118,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,32,102,114,111,109,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,32,105,115,32,110,111,116,32,114,101,116,117,114,110,101,100,59,32,97,110,121,32,101,120,112,114,101,115,115,105,111,110,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,102,105,108,101,32,109,117,115,116,32,98,101,32,116,104,101,114,101,32,102,111,114,32,105,116,115,32,115,105,100,101,32,101,102,102,101,99,116,46,32,82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,107>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,84,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,54,57>>,signature => [{attribute,1065,spec,{{eval,1},[{type,1065,bounded_fun,[{type,1065,'fun',[{type,1065,product,[{var,1065,'Filename'}]},{type,1065,union,[{atom,1065,ok},{type,1065,tuple,[{atom,1065,error},{var,1065,'Reason'}]}]}]},[{type,1066,constraint,[{atom,1066,is_subtype},[{var,1066,'Filename'},{user_type,1066,name_all,[]}]]},{type,1067,constraint,[{atom,1067,is_subtype},[{var,1067,'Reason'},{type,1067,union,[{user_type,1067,posix,[]},{atom,1067,badarg},{atom,1067,terminated},{atom,1067,system_limit},{type,1068,tuple,[{ann_type,1068,[{var,1068,'Line'},{type,1068,integer,[]}]},{ann_type,1068,[{var,1068,'Mod'},{type,1068,module,[]}]},{ann_type,1068,[{var,1068,'Term'},{type,1068,term,[]}]}]}]}]]}]]}]}}]}},{{function,eval,2},[{file,[102,105,108,101,46,101,114,108]},{location,1073}],[<<101,118,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<101,118,97,108,47,49>>]},<<44,32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,48,51>>,signature => [{attribute,1073,spec,{{eval,2},[{type,1073,bounded_fun,[{type,1073,'fun',[{type,1073,product,[{var,1073,'Filename'},{var,1073,'Bindings'}]},{type,1073,union,[{atom,1073,ok},{type,1073,tuple,[{atom,1073,error},{var,1073,'Reason'}]}]}]},[{type,1074,constraint,[{atom,1074,is_subtype},[{var,1074,'Filename'},{user_type,1074,name_all,[]}]]},{type,1075,constraint,[{atom,1075,is_subtype},[{var,1075,'Bindings'},{remote_type,1075,[{atom,1075,erl_eval},{atom,1075,binding_struct},[]]}]]},{type,1076,constraint,[{atom,1076,is_subtype},[{var,1076,'Reason'},{type,1076,union,[{user_type,1076,posix,[]},{atom,1076,badarg},{atom,1076,terminated},{atom,1076,system_limit},{type,1077,tuple,[{ann_type,1077,[{var,1077,'Line'},{type,1077,integer,[]}]},{ann_type,1077,[{var,1077,'Mod'},{type,1077,module,[]}]},{ann_type,1077,[{var,1077,'Term'},{type,1077,term,[]}]}]}]}]]}]]}]}}]}},{{function,format_error,1},[{file,[102,105,108,101,46,101,114,108]},{location,146}],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<71,105,118,101,110,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,114,101,116,117,114,110,101,100,32,98,121,32,97,110,121,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,114,101,116,117,114,110,115,32,97,32,100,101,115,99,114,105,112,116,105,118,101,32,115,116,114,105,110,103,32,111,102,32,116,104,101,32,101,114,114,111,114,32,105,110,32,69,110,103,108,105,115,104,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,49,51>>,signature => [{attribute,146,spec,{{format_error,1},[{type,146,bounded_fun,[{type,146,'fun',[{type,146,product,[{var,146,'Reason'}]},{var,146,'Chars'}]},[{type,147,constraint,[{atom,147,is_subtype},[{var,147,'Reason'},{type,147,union,[{user_type,147,posix,[]},{atom,147,badarg},{atom,147,terminated},{atom,147,system_limit},{type,148,tuple,[{ann_type,148,[{var,148,'Line'},{type,148,integer,[]}]},{ann_type,148,[{var,148,'Mod'},{type,148,module,[]}]},{ann_type,148,[{var,148,'Term'},{type,148,term,[]}]}]}]}]]},{type,149,constraint,[{atom,149,is_subtype},[{var,149,'Chars'},{type,149,string,[]}]]}]]}]}}]}},{{function,get_cwd,0},[{file,[102,105,108,101,46,101,114,108]},{location,191}],[<<103,101,116,95,99,119,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,68,105,114,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,114,97,114,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,110,32,102,97,105,108,32,111,110,32,85,110,105,120,46,32,73,116,32,99,97,110,32,111,99,99,117,114,32,105,102,32,114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46>>]}]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,50,49>>,signature => [{attribute,191,spec,{{get_cwd,0},[{type,191,bounded_fun,[{type,191,'fun',[{type,191,product,[]},{type,191,union,[{type,191,tuple,[{atom,191,ok},{var,191,'Dir'}]},{type,191,tuple,[{atom,191,error},{var,191,'Reason'}]}]}]},[{type,192,constraint,[{atom,192,is_subtype},[{var,192,'Dir'},{user_type,192,filename,[]}]]},{type,193,constraint,[{atom,193,is_subtype},[{var,193,'Reason'},{user_type,193,posix,[]}]]}]]}]}}]}},{{function,get_cwd,1},[{file,[102,105,108,101,46,101,114,108]},{location,198}],[<<103,101,116,95,99,119,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,68,105,114,125>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,100,114,105,118,101,46>>]},{p,[],[{code,[],[<<68,114,105,118,101>>]},<<32,105,115,32,116,111,32,98,101,32,111,102,32,116,104,101,32,102,111,114,109,32,34>>,{code,[],[<<76,101,116,116,101,114>>]},{code,[],[<<58>>]},<<34,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,34,99,58,34,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,104,97,118,101,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,99,117,114,114,101,110,116,32,100,114,105,118,101,32,40,85,110,105,120,44,32,102,111,114,32,101,120,97,109,112,108,101,41,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,104,97,115,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,100,114,105,118,101,115,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,114,105,118,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,111,114,109,97,116,32,111,102,32>>,{code,[],[<<68,114,105,118,101>>]},<<32,105,115,32,105,110,118,97,108,105,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,52,51>>,signature => [{attribute,198,spec,{{get_cwd,1},[{type,198,bounded_fun,[{type,198,'fun',[{type,198,product,[{var,198,'Drive'}]},{type,198,union,[{type,198,tuple,[{atom,198,ok},{var,198,'Dir'}]},{type,198,tuple,[{atom,198,error},{var,198,'Reason'}]}]}]},[{type,199,constraint,[{atom,199,is_subtype},[{var,199,'Drive'},{type,199,string,[]}]]},{type,200,constraint,[{atom,200,is_subtype},[{var,200,'Dir'},{user_type,200,filename,[]}]]},{type,201,constraint,[{atom,201,is_subtype},[{var,201,'Reason'},{type,201,union,[{user_type,201,posix,[]},{atom,201,badarg}]}]]}]]}]}}]}},{{function,list_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,401}],[<<108,105,115,116,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<76,105,115,116,115,32,97,108,108,32,102,105,108,101,115,32,105,110,32,97,32,100,105,114,101,99,116,111,114,121,44,32>>,{em,[],[<<101,120,99,101,112,116>>]},<<32,102,105,108,101,115,32,119,105,116,104,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,115,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121,46,32,84,104,101,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,115,111,114,116,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32>>,{code,[],[<<68,105,114>>]},<<32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,70,105,108,101,110,97,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32>>,{code,[],[<<98,105,110,97,114,121,40,41>>]},<<32,119,105,116,104,32,99,104,97,114,97,99,116,101,114,115,32,99,111,100,101,100,32,105,110,32,73,83,79,32,76,97,116,105,110,45,49,32,97,110,100,32,116,104,101,32,86,77,32,119,97,115,32,115,116,97,114,116,101,100,32,119,105,116,104,32,112,97,114,97,109,101,116,101,114,32>>,{code,[],[<<43,102,110,117,101>>]},<<46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,55,52>>,signature => [{attribute,401,spec,{{list_dir,1},[{type,401,bounded_fun,[{type,401,'fun',[{type,401,product,[{var,401,'Dir'}]},{type,401,union,[{type,401,tuple,[{atom,401,ok},{var,401,'Filenames'}]},{type,401,tuple,[{atom,401,error},{var,401,'Reason'}]}]}]},[{type,402,constraint,[{atom,402,is_subtype},[{var,402,'Dir'},{user_type,402,name_all,[]}]]},{type,403,constraint,[{atom,403,is_subtype},[{var,403,'Filenames'},{type,403,list,[{user_type,403,filename,[]}]}]]},{type,404,constraint,[{atom,404,is_subtype},[{var,404,'Reason'},{type,404,union,[{user_type,404,posix,[]},{atom,405,badarg},{type,406,tuple,[{atom,406,no_translation},{ann_type,406,[{var,406,'Filename'},{remote_type,406,[{atom,406,unicode},{atom,406,latin1_binary},[]]}]}]}]}]]}]]}]}}]}},{{function,list_dir_all,1},[{file,[102,105,108,101,46,101,114,108]},{location,411}],[<<108,105,115,116,95,100,105,114,95,97,108,108,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<108,105,115,116,95,100,105,114,95,97,108,108>>}],[]},<<76,105,115,116,115,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,97,32,100,105,114,101,99,116,111,114,121,44,32,105,110,99,108,117,100,105,110,103,32,102,105,108,101,115,32,119,105,116,104,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,115,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121,46,32,84,104,101,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,115,111,114,116,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32>>,{code,[],[<<68,105,114>>]},<<32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,48,53>>,signature => [{attribute,411,spec,{{list_dir_all,1},[{type,411,bounded_fun,[{type,411,'fun',[{type,411,product,[{var,411,'Dir'}]},{type,411,union,[{type,411,tuple,[{atom,411,ok},{var,411,'Filenames'}]},{type,411,tuple,[{atom,411,error},{var,411,'Reason'}]}]}]},[{type,412,constraint,[{atom,412,is_subtype},[{var,412,'Dir'},{user_type,412,name_all,[]}]]},{type,413,constraint,[{atom,413,is_subtype},[{var,413,'Filenames'},{type,413,list,[{user_type,413,filename_all,[]}]}]]},{type,414,constraint,[{atom,414,is_subtype},[{var,414,'Reason'},{type,414,union,[{user_type,414,posix,[]},{atom,414,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,make_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,249}],[<<109,97,107,101,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,99,114,101,97,116,101,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<68,105,114>>]},<<46,32,77,105,115,115,105,110,103,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,99,114,101,97,116,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,100,32>>,{code,[],[<<68,105,114>>]},<<32,101,120,105,115,116,115,32,97,108,114,101,97,100,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,51,48>>,signature => [{attribute,249,spec,{{make_dir,1},[{type,249,bounded_fun,[{type,249,'fun',[{type,249,product,[{var,249,'Dir'}]},{type,249,union,[{atom,249,ok},{type,249,tuple,[{atom,249,error},{var,249,'Reason'}]}]}]},[{type,250,constraint,[{atom,250,is_subtype},[{var,250,'Dir'},{user_type,250,name_all,[]}]]},{type,251,constraint,[{atom,251,is_subtype},[{var,251,'Reason'},{type,251,union,[{user_type,251,posix,[]},{atom,251,badarg}]}]]}]]}]}}]}},{{function,make_link,2},[{file,[102,105,108,101,46,101,114,108]},{location,427}],[<<109,97,107,101,95,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<77,97,107,101,115,32,97,32,104,97,114,100,32,108,105,110,107,32,102,114,111,109,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,116,111,32>>,{code,[],[<<78,101,119>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,108,105,110,107,115,32,40,85,110,105,120,32,97,110,100,32,87,105,110,100,111,119,115,41,46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,108,105,110,107,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,114,101,97,116,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32,108,105,110,107,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,114,32>>,{code,[],[<<78,101,119>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<78,101,119>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<72,97,114,100,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,54,52>>,signature => [{attribute,427,spec,{{make_link,2},[{type,427,bounded_fun,[{type,427,'fun',[{type,427,product,[{var,427,'Existing'},{var,427,'New'}]},{type,427,union,[{atom,427,ok},{type,427,tuple,[{atom,427,error},{var,427,'Reason'}]}]}]},[{type,428,constraint,[{atom,428,is_subtype},[{var,428,'Existing'},{user_type,428,name_all,[]}]]},{type,429,constraint,[{atom,429,is_subtype},[{var,429,'New'},{user_type,429,name_all,[]}]]},{type,430,constraint,[{atom,430,is_subtype},[{var,430,'Reason'},{type,430,union,[{user_type,430,posix,[]},{atom,430,badarg}]}]]}]]}]}}]}},{{function,make_symlink,2},[{file,[102,105,108,101,46,101,114,108]},{location,435}],[<<109,97,107,101,95,115,121,109,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32>>,{code,[],[<<78,101,119>>]},<<32,116,111,32,116,104,101,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,32,40,109,111,115,116,32,85,110,105,120,32,115,121,115,116,101,109,115,32,97,110,100,32,87,105,110,100,111,119,115,44,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,86,105,115,116,97,41,46,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,100,111,101,115,32,110,111,116,32,110,101,101,100,32,116,111,32,101,120,105,115,116,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,108,105,110,107,32,105,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,114,101,97,116,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,114,32>>,{code,[],[<<78,101,119>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<78,101,119>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]},{dt,[],[{code,[],[<<101,112,101,114,109>>]}]},{dd,[],[{p,[],[<<85,115,101,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,105,118,105,108,101,103,101,115,32,116,111,32,99,114,101,97,116,101,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,32,40>>,{code,[],[<<83,101,67,114,101,97,116,101,83,121,109,98,111,108,105,99,76,105,110,107,80,114,105,118,105,108,101,103,101>>]},<<32,111,110,32,87,105,110,100,111,119,115,41,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,57,51>>,signature => [{attribute,435,spec,{{make_symlink,2},[{type,435,bounded_fun,[{type,435,'fun',[{type,435,product,[{var,435,'Existing'},{var,435,'New'}]},{type,435,union,[{atom,435,ok},{type,435,tuple,[{atom,435,error},{var,435,'Reason'}]}]}]},[{type,436,constraint,[{atom,436,is_subtype},[{var,436,'Existing'},{user_type,436,name_all,[]}]]},{type,437,constraint,[{atom,437,is_subtype},[{var,437,'New'},{user_type,437,name_all,[]}]]},{type,438,constraint,[{atom,438,is_subtype},[{var,438,'Reason'},{type,438,union,[{user_type,438,posix,[]},{atom,438,badarg}]}]]}]]}]}}]}},{{function,native_name_encoding,0},[{file,[102,105,108,101,46,101,114,108]},{location,135}],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>],#{<<101,110>> => [{p,[],[{a,[{id,<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103>>}],[]},<<82,101,116,117,114,110,115,32,116,104,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,109,111,100,101,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32,115,121,115,116,101,109,32,116,114,97,110,115,108,97,116,101,115,32,110,111,32,102,105,108,101,110,97,109,101,115,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<44,32,102,105,108,101,110,97,109,101,115,32,97,114,101,32,99,111,110,118,101,114,116,101,100,32,98,97,99,107,32,97,110,100,32,102,111,114,116,104,32,116,111,32,116,104,101,32,110,97,116,105,118,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,40,117,115,117,97,108,108,121,32,85,84,70,45,56,44,32,98,117,116,32,85,84,70,45,49,54,32,111,110,32,87,105,110,100,111,119,115,41,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,55,50,57>>,signature => [{attribute,135,spec,{{native_name_encoding,0},[{type,135,'fun',[{type,135,product,[]},{type,135,union,[{atom,135,latin1},{atom,135,utf8}]}]}]}}],since => <<79,84,80,32,82,49,52,66,48,49>>}},{{function,open,2},[{file,[102,105,108,101,46,101,114,108]},{location,510}],[<<111,112,101,110,47,50>>],#{<<101,110>> => [{p,[],[<<79,112,101,110,115,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101>>]},<<32,105,110,32,116,104,101,32,109,111,100,101,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32>>,{code,[],[<<77,111,100,101,115>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,99,111,110,116,97,105,110,32,111,110,101,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<114,101,97,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,44,32,119,104,105,99,104,32,109,117,115,116,32,101,120,105,115,116,44,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<119,114,105,116,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,116,104,101,32,102,105,108,101,32,101,120,105,115,116,115,32,97,110,100,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,105,115,32,110,111,116,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<44,32,116,104,101,32,102,105,108,101,32,105,115,32,116,114,117,110,99,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<97,112,112,101,110,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,69,118,101,114,121,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,32,116,111,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<97,112,112,101,110,100>>]},<<32,116,97,107,101,115,32,112,108,97,99,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,120,99,108,117,115,105,118,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,116,104,101,32,102,105,108,101,32,101,120,105,115,116,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,101,120,105,115,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,100,111,101,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,32,101,120,99,108,117,115,105,118,101,110,101,115,115,32,111,110,32,102,105,108,101,32,115,121,115,116,101,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32>>,{code,[],[<<79,95,69,88,67,76>>]},<<32,112,114,111,112,101,114,108,121,44,32,115,117,99,104,32,97,115,32,78,70,83,46,32,68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,115,117,112,112,111,114,116,115,32,105,116,32,40,105,110,32,103,101,110,101,114,97,108,44,32,108,111,99,97,108,32,102,105,108,101,32,115,121,115,116,101,109,115,32,97,114,101,32,115,97,102,101,41,46>>]}]}]},{dt,[],[{code,[],[<<114,97,119>>]}]},{dd,[],[{p,[],[{a,[{id,<<114,97,119>>}],[]},<<65,108,108,111,119,115,32,102,97,115,116,101,114,32,97,99,99,101,115,115,32,116,111,32,97,32,102,105,108,101,44,32,97,115,32,110,111,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,101,101,100,101,100,32,116,111,32,104,97,110,100,108,101,32,116,104,101,32,102,105,108,101,46,32,72,111,119,101,118,101,114,44,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32,116,104,105,115,32,119,97,121,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,108,105,109,105,116,97,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32>>,{code,[],[<<105,111>>]},<<32,109,111,100,117,108,101,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,44,32,97,115,32,116,104,101,121,32,99,97,110,32,111,110,108,121,32,116,97,108,107,32,116,111,32,97,110,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46,32,73,110,115,116,101,97,100,44,32,117,115,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<46>>]}]},{li,[],[{p,[],[<<69,115,112,101,99,105,97,108,108,121,32,105,102,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,105,115,32,116,111,32,98,101,32,117,115,101,100,32,111,110,32,97,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,109,98,105,110,101,32,116,104,105,115,32,111,112,116,105,111,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,97,115,32,108,105,110,101,45,111,114,105,101,110,116,101,100,32,73,47,79,32,105,115,32,105,110,101,102,102,105,99,105,101,110,116,32,119,105,116,104,111,117,116,32,98,117,102,102,101,114,105,110,103,46>>]}]},{li,[],[{p,[],[<<79,110,108,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,112,101,110,101,100,32,116,104,101,32,102,105,108,101,32,99,97,110,32,117,115,101,32,105,116,46>>]}]},{li,[],[{p,[],[<<65,32,114,101,109,111,116,101,32,69,114,108,97,110,103,32,102,105,108,101,32,115,101,114,118,101,114,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,46,32,84,104,101,32,99,111,109,112,117,116,101,114,32,111,110,32,119,104,105,99,104,32,116,104,101,32,69,114,108,97,110,103,32,110,111,100,101,32,105,115,32,114,117,110,110,105,110,103,32,109,117,115,116,32,104,97,118,101,32,97,99,99,101,115,115,32,116,111,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,40,100,105,114,101,99,116,108,121,32,111,114,32,116,104,114,111,117,103,104,32,78,70,83,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,116,104,101,32,102,105,108,101,32,114,101,116,117,114,110,32,98,105,110,97,114,105,101,115,32,114,97,116,104,101,114,32,116,104,97,110,32,108,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<123,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,83,105,122,101,44,32,68,101,108,97,121,125>>]}]},{dd,[],[{p,[],[<<68,97,116,97,32,105,110,32,115,117,98,115,101,113,117,101,110,116,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,105,115,32,98,117,102,102,101,114,101,100,32,117,110,116,105,108,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,32,97,114,101,32,98,117,102,102,101,114,101,100,44,32,111,114,32,117,110,116,105,108,32,116,104,101,32,111,108,100,101,115,116,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32>>,{code,[],[<<68,101,108,97,121>>]},<<32,109,105,108,108,105,115,101,99,111,110,100,115,32,111,108,100,46,32,84,104,101,110,32,97,108,108,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32,119,114,105,116,116,101,110,32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,46,32,84,104,101,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32,97,108,115,111,32,102,108,117,115,104,101,100,32,98,101,102,111,114,101,32,115,111,109,101,32,111,116,104,101,114,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,105,115,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<84,104,101,32,112,117,114,112,111,115,101,32,111,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,116,111,32,105,110,99,114,101,97,115,101,32,112,101,114,102,111,114,109,97,110,99,101,32,98,121,32,114,101,100,117,99,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,46,32,84,104,117,115,44,32,116,104,101,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,109,117,115,116,32,98,101,32,102,111,114,32,115,105,122,101,115,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<44,32,97,110,100,32,110,111,116,32,105,110,116,101,114,115,112,101,114,115,101,100,32,98,121,32,116,111,111,32,109,97,110,121,32,111,116,104,101,114,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,117,115,101,100,44,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,99,97,110,32,112,114,101,109,97,116,117,114,101,108,121,32,98,101,32,114,101,112,111,114,116,101,100,32,97,115,32,115,117,99,99,101,115,115,102,117,108,44,32,97,110,100,32,105,102,32,97,32,119,114,105,116,101,32,101,114,114,111,114,32,111,99,99,117,114,115,44,32,116,104,101,32,101,114,114,111,114,32,105,115,32,114,101,112,111,114,116,101,100,32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,110,101,120,116,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,110,111,116,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,105,115,32,117,115,101,100,44,32,97,102,116,101,114,32,97,32,110,117,109,98,101,114,32,111,102,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,44,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,99,97,110,32,114,101,116,117,114,110,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,115,112,99,125>>]},<<44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,116,32,101,110,111,117,103,104,32,115,112,97,99,101,32,111,110,32,116,104,101,32,100,105,115,99,32,102,111,114,32,112,114,101,118,105,111,117,115,108,121,32,119,114,105,116,116,101,110,32,100,97,116,97,46,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,109,117,115,116,32,112,114,111,98,97,98,108,121,32,98,101,32,99,97,108,108,101,100,32,97,103,97,105,110,44,32,97,115,32,116,104,101,32,102,105,108,101,32,105,115,32,115,116,105,108,108,32,111,112,101,110,46>>]}]},{dt,[],[{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,83,105,122,101,44,32,68,101,108,97,121,125>>]},<<32,119,105,116,104,32,114,101,97,115,111,110,97,98,108,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<83,105,122,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,108,97,121>>]},<<32,40,114,111,117,103,104,108,121,32,115,111,109,101,32,54,52,32,75,66,44,32,50,32,115,101,99,111,110,100,115,41,46>>]}]},{dt,[],[{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<65,99,116,105,118,97,116,101,115,32,114,101,97,100,32,100,97,116,97,32,98,117,102,102,101,114,105,110,103,46,32,73,102,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,32,97,114,101,32,102,111,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,44,32,114,101,97,100,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,97,114,101,32,115,116,105,108,108,32,112,101,114,102,111,114,109,101,100,32,102,111,114,32,98,108,111,99,107,115,32,111,102,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,46,32,84,104,101,32,101,120,116,114,97,32,100,97,116,97,32,105,115,32,98,117,102,102,101,114,101,100,32,97,110,100,32,114,101,116,117,114,110,101,100,32,105,110,32,115,117,98,115,101,113,117,101,110,116,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,44,32,103,105,118,105,110,103,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,103,97,105,110,32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,32,105,115,32,114,101,100,117,99,101,100,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]},<<32,98,117,102,102,101,114,32,105,115,32,97,108,115,111,32,104,105,103,104,108,121,32,117,115,101,100,32,98,121,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,44,32,116,104,101,114,101,102,111,114,101,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,40,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,114,101,97,115,111,110,115,41,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,114,97,119,32,102,105,108,101,115,32,117,115,105,110,103,32,116,104,97,116,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,32,97,114,101,32,102,111,114,32,115,105,122,101,115,32,110,111,116,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,44,32,111,114,32,101,118,101,110,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,44,32,110,111,32,112,101,114,102,111,114,109,97,110,99,101,32,103,97,105,110,32,99,97,110,32,98,101,32,101,120,112,101,99,116,101,100,46>>]}]},{dt,[],[{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,119,105,116,104,32,97,32,114,101,97,115,111,110,97,98,108,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<83,105,122,101>>]},<<32,40,114,111,117,103,104,108,121,32,115,111,109,101,32,54,52,32,75,66,41,46>>]}]},{dt,[],[{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,103,122,105,112,32,99,111,109,112,114,101,115,115,101,100,32,102,105,108,101,115,46,32,79,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,109,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<32,111,114,32>>,{code,[],[<<119,114,105,116,101>>]},<<44,32,98,117,116,32,110,111,116,32,98,111,116,104,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,115,105,122,101,32,111,98,116,97,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]}]},<<32,100,111,101,115,32,112,114,111,98,97,98,108,121,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,97,100,32,102,114,111,109,32,97,32,99,111,109,112,114,101,115,115,101,100,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,110,99,111,100,105,110,103,44,32,69,110,99,111,100,105,110,103,125>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,108,101,32,112,101,114,102,111,114,109,32,97,117,116,111,109,97,116,105,99,32,116,114,97,110,115,108,97,116,105,111,110,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,97,110,100,32,102,114,111,109,32,97,32,115,112,101,99,105,102,105,99,32,40,85,110,105,99,111,100,101,41,32,101,110,99,111,100,105,110,103,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,100,97,116,97,32,115,117,112,112,108,105,101,100,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,111,114,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,115,116,105,108,108,32,105,115,32,98,121,116,101,45,111,114,105,101,110,116,101,100,59,32,116,104,105,115,32,111,112,116,105,111,110,32,100,101,110,111,116,101,115,32,111,110,108,121,32,104,111,119,32,100,97,116,97,32,105,115,32,115,116,111,114,101,100,32,105,110,32,116,104,101,32,100,105,115,107,32,102,105,108,101,46>>]},{p,[],[<<68,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,100,105,102,102,101,114,101,110,116,32,109,101,116,104,111,100,115,32,111,102,32,114,101,97,100,105,110,103,32,97,110,100,32,119,114,105,116,105,110,103,32,100,97,116,97,32,105,115,32,112,114,101,102,101,114,114,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,105,109,112,108,105,101,115,32,117,115,105,110,103,32,116,104,105,115,32,109,111,100,117,108,101,32,40>>,{code,[],[<<102,105,108,101>>]},<<41,32,102,111,114,32,114,101,97,100,105,110,103,32,97,110,100,32,119,114,105,116,105,110,103,32,100,97,116,97,32,97,115,32,116,104,101,32,105,110,116,101,114,102,97,99,101,115,32,112,114,111,118,105,100,101,100,32,104,101,114,101,32,119,111,114,107,32,119,105,116,104,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,46,32,85,115,105,110,103,32,111,116,104,101,114,32,40,85,110,105,99,111,100,101,41,32,101,110,99,111,100,105,110,103,115,32,109,97,107,101,115,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,102,117,110,99,116,105,111,110,115,32>>,{code,[],[<<103,101,116,95,99,104,97,114,115>>]},<<44,32>>,{code,[],[<<103,101,116,95,108,105,110,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,117,116,95,99,104,97,114,115>>]},<<32,109,111,114,101,32,115,117,105,116,97,98,108,101,44,32,97,115,32,116,104,101,121,32,99,97,110,32,119,111,114,107,32,119,105,116,104,32,116,104,101,32,102,117,108,108,32,85,110,105,99,111,100,101,32,114,97,110,103,101,46>>]},{p,[],[<<73,102,32,100,97,116,97,32,105,115,32,115,101,110,116,32,116,111,32,97,110,32>>,{code,[],[<<105,111,95,100,101,118,105,99,101,40,41>>]},<<32,105,110,32,97,32,102,111,114,109,97,116,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,99,111,110,118,101,114,116,101,100,32,116,111,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,101,110,99,111,100,105,110,103,44,32,111,114,32,105,102,32,100,97,116,97,32,105,115,32,114,101,97,100,32,98,121,32,97,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,114,101,116,117,114,110,115,32,100,97,116,97,32,105,110,32,97,32,102,111,114,109,97,116,32,116,104,97,116,32,99,97,110,110,111,116,32,99,111,112,101,32,119,105,116,104,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,114,97,110,103,101,32,111,102,32,116,104,101,32,100,97,116,97,44,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,97,110,100,32,116,104,101,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<108,97,116,105,110,49>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,101,110,99,111,100,105,110,103,46,32,66,121,116,101,115,32,115,117,112,112,108,105,101,100,32,116,111,32,116,104,101,32,102,105,108,101,44,32,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,97,114,101,32,119,114,105,116,116,101,110,32,34,97,115,32,105,115,34,32,111,110,32,116,104,101,32,102,105,108,101,46,32,76,105,107,101,119,105,115,101,44,32,98,121,116,101,115,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,44,32,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,114,101,32,114,101,116,117,114,110,101,100,32,34,97,115,32,105,115,34,46,32,73,102,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,117,115,101,100,32,102,111,114,32,119,114,105,116,105,110,103,44,32,116,104,101,32,102,105,108,101,32,99,97,110,32,111,110,108,121,32,99,111,112,101,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,117,112,32,116,111,32,99,111,100,101,32,112,111,105,110,116,32,50,53,53,32,40,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,41,46>>]}]},{dt,[],[{code,[],[<<117,110,105,99,111,100,101,32,111,114,32,117,116,102,56>>]}]},{dd,[],[{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,97,114,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,97,110,100,32,102,114,111,109,32,85,84,70,45,56,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,116,104,101,121,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,111,114,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46,32,65,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32,116,104,105,115,32,119,97,121,32,99,97,110,32,98,101,32,114,101,97,100,97,98,108,101,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32,97,115,32,108,111,110,103,32,97,115,32,110,111,32,100,97,116,97,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,102,105,108,101,32,108,105,101,115,32,98,101,121,111,110,100,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,32,40,48,46,46,50,53,53,41,44,32,98,117,116,32,102,97,105,108,117,114,101,32,111,99,99,117,114,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,85,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,98,101,121,111,110,100,32,116,104,97,116,32,114,97,110,103,101,46,32,84,104,101,32,102,105,108,101,32,105,115,32,98,101,115,116,32,114,101,97,100,32,119,105,116,104,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,97,119,97,114,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<46>>]},{p,[],[<<66,121,116,101,115,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,102,105,108,101,32,98,121,32,97,110,121,32,109,101,97,110,115,32,97,114,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,85,84,70,45,56,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,98,101,105,110,103,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,100,105,115,107,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<117,116,102,49,54,32,111,114,32,123,117,116,102,49,54,44,98,105,103,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,98,105,103,32,101,110,100,105,97,110,32,85,84,70,45,49,54,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<123,117,116,102,49,54,44,108,105,116,116,108,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,108,105,116,116,108,101,32,101,110,100,105,97,110,32,85,84,70,45,49,54,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<117,116,102,51,50,32,111,114,32,123,117,116,102,51,50,44,98,105,103,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,98,105,103,32,101,110,100,105,97,110,32,85,84,70,45,51,50,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<123,117,116,102,51,50,44,108,105,116,116,108,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,108,105,116,116,108,101,32,101,110,100,105,97,110,32,85,84,70,45,51,50,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]}]},{p,[],[<<84,104,101,32,69,110,99,111,100,105,110,103,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,102,111,114,32,97,32,102,105,108,101,32,34,111,110,32,116,104,101,32,102,108,121,34,32,98,121,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111,35,115,101,116,111,112,116,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,111,58,115,101,116,111,112,116,115,47,50>>]}]},<<46,32,83,111,32,97,32,102,105,108,101,32,99,97,110,32,98,101,32,97,110,97,108,121,122,101,100,32,105,110,32,108,97,116,105,110,49,32,101,110,99,111,100,105,110,103,32,102,111,114,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,66,79,77,44,32,112,111,115,105,116,105,111,110,101,100,32,98,101,121,111,110,100,32,116,104,101,32,66,79,77,32,97,110,100,32,116,104,101,110,32,98,101,32,115,101,116,32,102,111,114,32,116,104,101,32,114,105,103,104,116,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,102,117,114,116,104,101,114,32,114,101,97,100,105,110,103,46,32,70,111,114,32,102,117,110,99,116,105,111,110,115,32,105,100,101,110,116,105,102,121,105,110,103,32,66,79,77,115,44,32,115,101,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,117,110,105,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,105,99,111,100,101,40,51,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,115,46>>]}]},{dt,[],[{code,[],[<<114,97,109>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<46,32,82,101,116,117,114,110,115,32,97,110,32>>,{code,[],[<<102,100,40,41>>]},<<44,32,119,104,105,99,104,32,108,101,116,115,32,109,111,100,117,108,101,32>>,{code,[],[<<102,105,108,101>>]},<<32,111,112,101,114,97,116,101,32,111,110,32,116,104,101,32,100,97,116,97,32,105,110,45,109,101,109,111,114,121,32,97,115,32,105,102,32,105,116,32,105,115,32,97,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<115,121,110,99>>]}]},{dd,[],[{p,[],[<<79,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,105,116,44,32,101,110,97,98,108,101,115,32,116,104,101,32,80,79,83,73,88,32>>,{code,[],[<<79,95,83,89,78,67>>]},<<32,115,121,110,99,104,114,111,110,111,117,115,32,73,47,79,32,102,108,97,103,32,111,114,32,105,116,115,32,112,108,97,116,102,111,114,109,45,100,101,112,101,110,100,101,110,116,32,101,113,117,105,118,97,108,101,110,116,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<70,73,76,69,95,70,76,65,71,95,87,82,73,84,69,95,84,72,82,79,85,71,72>>]},<<32,111,110,32,87,105,110,100,111,119,115,41,32,115,111,32,116,104,97,116,32,119,114,105,116,101,115,32,116,111,32,116,104,101,32,102,105,108,101,32,98,108,111,99,107,32,117,110,116,105,108,32,116,104,101,32,100,97,116,97,32,105,115,32,112,104,121,115,105,99,97,108,108,121,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,72,111,119,101,118,101,114,44,32,98,101,32,97,119,97,114,101,32,116,104,97,116,32,116,104,101,32,101,120,97,99,116,32,115,101,109,97,110,116,105,99,115,32,111,102,32,116,104,105,115,32,102,108,97,103,32,100,105,102,102,101,114,32,102,114,111,109,32,112,108,97,116,102,111,114,109,32,116,111,32,112,108,97,116,102,111,114,109,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,110,111,110,101,32,111,102,32,76,105,110,117,120,32,111,114,32,87,105,110,100,111,119,115,32,103,117,97,114,97,110,116,101,101,115,32,116,104,97,116,32,97,108,108,32,102,105,108,101,32,109,101,116,97,100,97,116,97,32,97,114,101,32,97,108,115,111,32,119,114,105,116,116,101,110,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,32,114,101,116,117,114,110,115,46,32,70,111,114,32,112,114,101,99,105,115,101,32,115,101,109,97,110,116,105,99,115,44,32,99,104,101,99,107,32,116,104,101,32,100,101,116,97,105,108,115,32,111,102,32,121,111,117,114,32,112,108,97,116,102,111,114,109,32,100,111,99,117,109,101,110,116,97,116,105,111,110,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,119,105,116,104,32,110,111,32,115,117,112,112,111,114,116,32,102,111,114,32,80,79,83,73,88,32>>,{code,[],[<<79,95,83,89,78,67>>]},<<32,111,114,32,101,113,117,105,118,97,108,101,110,116,44,32,117,115,101,32,111,102,32,116,104,101,32>>,{code,[],[<<115,121,110,99>>]},<<32,102,108,97,103,32,99,97,117,115,101,115,32>>,{code,[],[<<111,112,101,110>>]},<<32,116,111,32,114,101,116,117,114,110,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<100,105,114,101,99,116,111,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,111,119,115,32>>,{code,[],[<<111,112,101,110>>]},<<32,116,111,32,119,111,114,107,32,111,110,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]}]},{p,[],[<<82,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,73,111,68,101,118,105,99,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,109,111,100,101,46,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,46>>]}]}]},{p,[],[{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,114,101,97,108,108,121,32,116,104,101,32,112,105,100,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,110,100,108,101,115,32,116,104,101,32,102,105,108,101,46,32,84,104,105,115,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,114,105,103,105,110,97,108,108,121,32,111,112,101,110,101,100,32,116,104,101,32,102,105,108,101,32,40,116,104,101,32,111,119,110,101,114,32,112,114,111,99,101,115,115,41,46,32,73,102,32,116,104,101,32,111,119,110,101,114,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,44,32,116,104,101,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,105,116,115,101,108,102,32,116,101,114,109,105,110,97,116,101,115,32,116,111,111,46,32,65,110,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,114,101,116,117,114,110,101,100,32,102,114,111,109,32,116,104,105,115,32,99,97,108,108,32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,110,32,97,114,103,117,109,101,110,116,32,116,111,32,116,104,101,32,73,47,79,32,102,117,110,99,116,105,111,110,115,32,40,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,112,114,101,118,105,111,117,115,32,118,101,114,115,105,111,110,115,32,111,102,32>>,{code,[],[<<102,105,108,101>>]},<<44,32,109,111,100,101,115,32,119,101,114,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<114,101,97,100>>]},<<44,32>>,{code,[],[<<119,114,105,116,101>>]},<<44,32,111,114,32>>,{code,[],[<<114,101,97,100,95,119,114,105,116,101>>]},<<32,105,110,115,116,101,97,100,32,111,102,32,97,32,108,105,115,116,46,32,84,104,105,115,32,105,115,32,115,116,105,108,108,32,97,108,108,111,119,101,100,32,102,111,114,32,114,101,97,115,111,110,115,32,111,102,32,98,97,99,107,119,97,114,100,115,32,99,111,109,112,97,116,105,98,105,108,105,116,121,44,32,98,117,116,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,110,101,119,32,99,111,100,101,46,32,65,108,115,111,32,110,111,116,101,32,116,104,97,116,32>>,{code,[],[<<114,101,97,100,95,119,114,105,116,101>>]},<<32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,105,110,32,97,32,109,111,100,101,32,108,105,115,116,46>>]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,114,101,97,100,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,44,32,111,114,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,116,115,101,108,102,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,32,105,102,32>>,{code,[],[<<100,105,114,101,99,116,111,114,121>>]},<<32,109,111,100,101,32,119,97,115,32,115,112,101,99,105,102,105,101,100,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,32,40,105,102,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,97,99,99,101,115,115,32,119,97,115,32,115,112,101,99,105,102,105,101,100,41,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,55,52,49>>,signature => [{attribute,510,spec,{{open,2},[{type,510,bounded_fun,[{type,510,'fun',[{type,510,product,[{var,510,'File'},{var,510,'Modes'}]},{type,510,union,[{type,510,tuple,[{atom,510,ok},{var,510,'IoDevice'}]},{type,510,tuple,[{atom,510,error},{var,510,'Reason'}]}]}]},[{type,511,constraint,[{atom,511,is_subtype},[{var,511,'File'},{type,511,union,[{var,511,'Filename'},{type,511,iodata,[]}]}]]},{type,512,constraint,[{atom,512,is_subtype},[{var,512,'Filename'},{user_type,512,name_all,[]}]]},{type,513,constraint,[{atom,513,is_subtype},[{var,513,'Modes'},{type,513,list,[{type,513,union,[{user_type,513,mode,[]},{atom,513,ram},{atom,513,directory}]}]}]]},{type,514,constraint,[{atom,514,is_subtype},[{var,514,'IoDevice'},{user_type,514,io_device,[]}]]},{type,515,constraint,[{atom,515,is_subtype},[{var,515,'Reason'},{type,515,union,[{user_type,515,posix,[]},{atom,515,badarg},{atom,515,system_limit}]}]]}]]}]}}]}},{{function,path_consult,2},[{file,[102,105,108,101,46,101,114,108]},{location,1041}],[<<112,97,116,104,95,99,111,110,115,117,108,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,69,114,108,97,110,103,32,116,101,114,109,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,84,101,114,109,115,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,114,101,97,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,116,101,114,109,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,48,50,57>>,signature => [{attribute,1041,spec,{{path_consult,2},[{type,1041,bounded_fun,[{type,1041,'fun',[{type,1041,product,[{var,1041,'Path'},{var,1041,'Filename'}]},{type,1041,union,[{type,1041,tuple,[{atom,1041,ok},{var,1041,'Terms'},{var,1041,'FullName'}]},{type,1041,tuple,[{atom,1041,error},{var,1041,'Reason'}]}]}]},[{type,1042,constraint,[{atom,1042,is_subtype},[{var,1042,'Path'},{type,1042,list,[{var,1042,'Dir'}]}]]},{type,1043,constraint,[{atom,1043,is_subtype},[{var,1043,'Dir'},{user_type,1043,name_all,[]}]]},{type,1044,constraint,[{atom,1044,is_subtype},[{var,1044,'Filename'},{user_type,1044,name_all,[]}]]},{type,1045,constraint,[{atom,1045,is_subtype},[{var,1045,'Terms'},{type,1045,list,[{type,1045,term,[]}]}]]},{type,1046,constraint,[{atom,1046,is_subtype},[{var,1046,'FullName'},{user_type,1046,filename_all,[]}]]},{type,1047,constraint,[{atom,1047,is_subtype},[{var,1047,'Reason'},{type,1047,union,[{user_type,1047,posix,[]},{atom,1047,badarg},{atom,1047,terminated},{atom,1047,system_limit},{type,1048,tuple,[{ann_type,1048,[{var,1048,'Line'},{type,1048,integer,[]}]},{ann_type,1048,[{var,1048,'Mod'},{type,1048,module,[]}]},{ann_type,1048,[{var,1048,'Term'},{type,1048,term,[]}]}]}]}]]}]]}]}}]}},{{function,path_eval,2},[{file,[102,105,108,101,46,101,114,108]},{location,1089}],[<<112,97,116,104,95,101,118,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46,32,84,104,101,32,114,101,115,117,108,116,32,111,102,32,101,118,97,108,117,97,116,105,111,110,32,105,115,32,110,111,116,32,114,101,116,117,114,110,101,100,59,32,97,110,121,32,101,120,112,114,101,115,115,105,111,110,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,102,105,108,101,32,109,117,115,116,32,98,101,32,116,104,101,114,101,32,102,111,114,32,105,116,115,32,115,105,100,101,32,101,102,102,101,99,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,48,55,49>>,signature => [{attribute,1089,spec,{{path_eval,2},[{type,1089,bounded_fun,[{type,1089,'fun',[{type,1089,product,[{var,1089,'Path'},{var,1089,'Filename'}]},{type,1089,union,[{type,1089,tuple,[{atom,1089,ok},{var,1089,'FullName'}]},{type,1089,tuple,[{atom,1089,error},{var,1089,'Reason'}]}]}]},[{type,1090,constraint,[{atom,1090,is_subtype},[{var,1090,'Path'},{type,1090,list,[{ann_type,1090,[{var,1090,'Dir'},{user_type,1090,name_all,[]}]}]}]]},{type,1091,constraint,[{atom,1091,is_subtype},[{var,1091,'Filename'},{user_type,1091,name_all,[]}]]},{type,1092,constraint,[{atom,1092,is_subtype},[{var,1092,'FullName'},{user_type,1092,filename_all,[]}]]},{type,1093,constraint,[{atom,1093,is_subtype},[{var,1093,'Reason'},{type,1093,union,[{user_type,1093,posix,[]},{atom,1093,badarg},{atom,1093,terminated},{atom,1093,system_limit},{type,1094,tuple,[{ann_type,1094,[{var,1094,'Line'},{type,1094,integer,[]}]},{ann_type,1094,[{var,1094,'Mod'},{type,1094,module,[]}]},{ann_type,1094,[{var,1094,'Term'},{type,1094,term,[]}]}]}]}]]}]]}]}}]}},{{function,path_open,3},[{file,[102,105,108,101,46,101,114,108]},{location,1194}],[<<112,97,116,104,95,111,112,101,110,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,111,112,101,110,115,32,116,104,101,32,102,105,108,101,32,105,110,32,116,104,101,32,109,111,100,101,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32>>,{code,[],[<<77,111,100,101,115>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,73,111,68,101,118,105,99,101,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,109,111,100,101,46,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,49,49,55>>,signature => [{attribute,1194,spec,{{path_open,3},[{type,1194,bounded_fun,[{type,1194,'fun',[{type,1194,product,[{var,1194,'Path'},{var,1194,'Filename'},{var,1194,'Modes'}]},{type,1195,union,[{type,1195,tuple,[{atom,1195,ok},{var,1195,'IoDevice'},{var,1195,'FullName'}]},{type,1195,tuple,[{atom,1195,error},{var,1195,'Reason'}]}]}]},[{type,1196,constraint,[{atom,1196,is_subtype},[{var,1196,'Path'},{type,1196,list,[{ann_type,1196,[{var,1196,'Dir'},{user_type,1196,name_all,[]}]}]}]]},{type,1197,constraint,[{atom,1197,is_subtype},[{var,1197,'Filename'},{user_type,1197,name_all,[]}]]},{type,1198,constraint,[{atom,1198,is_subtype},[{var,1198,'Modes'},{type,1198,list,[{type,1198,union,[{user_type,1198,mode,[]},{atom,1198,directory}]}]}]]},{type,1199,constraint,[{atom,1199,is_subtype},[{var,1199,'IoDevice'},{user_type,1199,io_device,[]}]]},{type,1200,constraint,[{atom,1200,is_subtype},[{var,1200,'FullName'},{user_type,1200,filename_all,[]}]]},{type,1201,constraint,[{atom,1201,is_subtype},[{var,1201,'Reason'},{type,1201,union,[{user_type,1201,posix,[]},{atom,1201,badarg},{atom,1201,system_limit}]}]]}]]}]}}]}},{{function,path_script,2},[{file,[102,105,108,101,46,101,114,108]},{location,1149}],[<<112,97,116,104,95,115,99,114,105,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,86,97,108,117,101,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,49,52,54>>,signature => [{attribute,1149,spec,{{path_script,2},[{type,1149,bounded_fun,[{type,1149,'fun',[{type,1149,product,[{var,1149,'Path'},{var,1149,'Filename'}]},{type,1150,union,[{type,1150,tuple,[{atom,1150,ok},{var,1150,'Value'},{var,1150,'FullName'}]},{type,1150,tuple,[{atom,1150,error},{var,1150,'Reason'}]}]}]},[{type,1151,constraint,[{atom,1151,is_subtype},[{var,1151,'Path'},{type,1151,list,[{ann_type,1151,[{var,1151,'Dir'},{user_type,1151,name_all,[]}]}]}]]},{type,1152,constraint,[{atom,1152,is_subtype},[{var,1152,'Filename'},{user_type,1152,name_all,[]}]]},{type,1153,constraint,[{atom,1153,is_subtype},[{var,1153,'Value'},{type,1153,term,[]}]]},{type,1154,constraint,[{atom,1154,is_subtype},[{var,1154,'FullName'},{user_type,1154,filename_all,[]}]]},{type,1155,constraint,[{atom,1155,is_subtype},[{var,1155,'Reason'},{type,1155,union,[{user_type,1155,posix,[]},{atom,1155,badarg},{atom,1155,terminated},{atom,1155,system_limit},{type,1156,tuple,[{ann_type,1156,[{var,1156,'Line'},{type,1156,integer,[]}]},{ann_type,1156,[{var,1156,'Mod'},{type,1156,module,[]}]},{ann_type,1156,[{var,1156,'Term'},{type,1156,term,[]}]}]}]}]]}]]}]}}]}},{{function,path_script,3},[{file,[102,105,108,101,46,101,114,108]},{location,1161}],[<<112,97,116,104,95,115,99,114,105,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<112,97,116,104,95,115,99,114,105,112,116,47,50>>]},<<32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<32,97,98,111,117,116,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,49,57,48>>,signature => [{attribute,1161,spec,{{path_script,3},[{type,1161,bounded_fun,[{type,1161,'fun',[{type,1161,product,[{var,1161,'Path'},{var,1161,'Filename'},{var,1161,'Bindings'}]},{type,1162,union,[{type,1162,tuple,[{atom,1162,ok},{var,1162,'Value'},{var,1162,'FullName'}]},{type,1162,tuple,[{atom,1162,error},{var,1162,'Reason'}]}]}]},[{type,1163,constraint,[{atom,1163,is_subtype},[{var,1163,'Path'},{type,1163,list,[{ann_type,1163,[{var,1163,'Dir'},{user_type,1163,name_all,[]}]}]}]]},{type,1164,constraint,[{atom,1164,is_subtype},[{var,1164,'Filename'},{user_type,1164,name_all,[]}]]},{type,1165,constraint,[{atom,1165,is_subtype},[{var,1165,'Bindings'},{remote_type,1165,[{atom,1165,erl_eval},{atom,1165,binding_struct},[]]}]]},{type,1166,constraint,[{atom,1166,is_subtype},[{var,1166,'Value'},{type,1166,term,[]}]]},{type,1167,constraint,[{atom,1167,is_subtype},[{var,1167,'FullName'},{user_type,1167,filename_all,[]}]]},{type,1168,constraint,[{atom,1168,is_subtype},[{var,1168,'Reason'},{type,1168,union,[{user_type,1168,posix,[]},{atom,1168,badarg},{atom,1168,terminated},{atom,1168,system_limit},{type,1169,tuple,[{ann_type,1169,[{var,1169,'Line'},{type,1169,integer,[]}]},{ann_type,1169,[{var,1169,'Mod'},{type,1169,module,[]}]},{ann_type,1169,[{var,1169,'Term'},{type,1169,term,[]}]}]}]}]]}]]}]}}]}},{{function,pid2name,1},[{file,[102,105,108,101,46,101,114,108]},{location,170}],[<<112,105,100,50,110,97,109,101,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,97,110,32,73,47,79,32,100,101,118,105,99,101,44,32,116,104,97,116,32,105,115,44,32,97,32,112,105,100,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<111,112,101,110,47,50>>]},<<44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,102,105,108,101,110,97,109,101,44,32,111,114,32,114,97,116,104,101,114,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,116,104,105,115,32,110,111,100,101,32,105,115,32,110,111,116,32,97,32,115,108,97,118,101,44,32,116,104,101,32,102,105,108,101,32,119,97,115,32,111,112,101,110,101,100,32,98,121,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,116,104,105,115,32,110,111,100,101,32,40,116,104,105,115,32,105,109,112,108,105,101,115,32,116,104,97,116,32>>,{code,[],[<<80,105,100>>]},<<32,109,117,115,116,32,98,101,32,97,32,108,111,99,97,108,32,112,105,100,41,32,97,110,100,32,116,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,99,108,111,115,101,100,46,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,110,32,102,108,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,46>>]}]},{dt,[],[{code,[],[<<117,110,100,101,102,105,110,101,100>>]}]},{dd,[],[{p,[],[<<73,110,32,97,108,108,32,111,116,104,101,114,32,99,97,115,101,115,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,48,48>>,signature => [{attribute,170,spec,{{pid2name,1},[{type,170,bounded_fun,[{type,170,'fun',[{type,170,product,[{var,170,'Pid'}]},{type,170,union,[{type,170,tuple,[{atom,170,ok},{var,170,'Filename'}]},{atom,170,undefined}]}]},[{type,171,constraint,[{atom,171,is_subtype},[{var,171,'Filename'},{user_type,171,filename_all,[]}]]},{type,172,constraint,[{atom,172,is_subtype},[{var,172,'Pid'},{type,172,pid,[]}]]}]]}]}}]}},{{function,position,2},[{file,[102,105,108,101,46,101,114,108]},{location,753}],[<<112,111,115,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,116,111,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,78,101,119,80,111,115,105,116,105,111,110,125>>]},<<32,40,97,115,32,97,98,115,111,108,117,116,101,32,111,102,102,115,101,116,41,32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<79,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,98,111,102,44,32,79,102,102,115,101,116,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,98,111,102,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<65,98,115,111,108,117,116,101,32,111,102,102,115,101,116,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<79,102,102,115,101,116,32,102,114,111,109,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,111,102,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<79,102,102,115,101,116,32,102,114,111,109,32,116,104,101,32,101,110,100,32,111,102,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<98,111,102,32,124,32,99,117,114,32,124,32,101,111,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,97,98,111,118,101,32,119,105,116,104,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,48,46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,102,102,115,101,116,115,32,97,114,101,32,99,111,117,110,116,101,100,32,105,110,32,98,121,116,101,115,44,32,110,111,116,32,105,110,32,99,104,97,114,97,99,116,101,114,115,46,32,73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,117,115,105,110,103,32,115,111,109,101,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,98,121,116,101,32,100,111,101,115,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46,32,80,111,115,105,116,105,111,110,105,110,103,32,105,110,32,115,117,99,104,32,97,32,102,105,108,101,32,99,97,110,32,111,110,108,121,32,98,101,32,100,111,110,101,32,116,111,32,107,110,111,119,110,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,105,101,115,46,32,84,104,97,116,32,105,115,44,32,116,111,32,97,32,112,111,115,105,116,105,111,110,32,101,97,114,108,105,101,114,32,114,101,116,114,105,101,118,101,100,32,98,121,32,103,101,116,116,105,110,103,32,97,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,44,32,116,111,32,116,104,101,32,98,101,103,105,110,110,105,110,103,47,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,32,111,114,32,116,111,32,115,111,109,101,32,111,116,104,101,114,32,112,111,115,105,116,105,111,110,32>>,{em,[],[<<107,110,111,119,110>>]},<<32,116,111,32,98,101,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,98,121,32,115,111,109,101,32,111,116,104,101,114,32,109,101,97,110,115,32,40,116,121,112,105,99,97,108,108,121,32,98,101,121,111,110,100,32,97,32,98,121,116,101,32,111,114,100,101,114,32,109,97,114,107,32,105,110,32,116,104,101,32,102,105,108,101,44,32,119,104,105,99,104,32,104,97,115,32,97,32,107,110,111,119,110,32,98,121,116,101,45,115,105,122,101,41,46>>]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<69,105,116,104,101,114,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,105,108,108,101,103,97,108,44,32,111,114,32,105,116,32,105,115,32,101,118,97,108,117,97,116,101,100,32,116,111,32,97,32,110,101,103,97,116,105,118,101,32,111,102,102,115,101,116,32,105,110,32,116,104,101,32,102,105,108,101,46,32,78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,110,101,103,97,116,105,118,101,32,118,97,108,117,101,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,110,32,101,114,114,111,114,44,32,97,110,100,32,97,102,116,101,114,32,116,104,101,32,99,97,108,108,32,116,104,101,32,102,105,108,101,32,112,111,115,105,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,50,53>>,signature => [{attribute,753,spec,{{position,2},[{type,753,bounded_fun,[{type,753,'fun',[{type,753,product,[{var,753,'IoDevice'},{var,753,'Location'}]},{type,753,union,[{type,753,tuple,[{atom,753,ok},{var,753,'NewPosition'}]},{type,753,tuple,[{atom,753,error},{var,753,'Reason'}]}]}]},[{type,754,constraint,[{atom,754,is_subtype},[{var,754,'IoDevice'},{user_type,754,io_device,[]}]]},{type,755,constraint,[{atom,755,is_subtype},[{var,755,'Location'},{user_type,755,location,[]}]]},{type,756,constraint,[{atom,756,is_subtype},[{var,756,'NewPosition'},{type,756,integer,[]}]]},{type,757,constraint,[{atom,757,is_subtype},[{var,757,'Reason'},{type,757,union,[{user_type,757,posix,[]},{atom,757,badarg},{atom,757,terminated}]}]]}]]}]}}]}},{{function,pread,2},[{file,[102,105,108,101,46,101,114,108]},{location,632}],[<<112,114,101,97,100,47,50>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32>>,{code,[],[<<112,114,101,97,100,47,51>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,91,68,97,116,97,44,32,46,46,46,93,125>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32,101,97,99,104,32>>,{code,[],[<<68,97,116,97>>]},<<44,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<112,114,101,97,100>>]},<<44,32,105,115,32,101,105,116,104,101,114,32,97,32,108,105,115,116,32,111,114,32,97,32,98,105,110,97,114,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,109,111,100,101,32,111,102,32,116,104,101,32,102,105,108,101,44,32,111,114,32>>,{code,[],[<<101,111,102>>]},<<32,105,102,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,112,111,115,105,116,105,111,110,32,105,115,32,98,101,121,111,110,100,32,101,110,100,32,111,102,32,102,105,108,101,46>>]},{p,[],[<<65,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,121,116,101,45,111,102,102,115,101,116,44,32,116,97,107,101,32,115,112,101,99,105,97,108,32,99,97,117,116,105,111,110,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,97,115,32,110,111,116,32,101,118,101,114,121,32,98,121,116,101,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,118,97,108,105,100,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,111,110,32,115,117,99,104,32,97,32,102,105,108,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,55,55>>,signature => [{attribute,632,spec,{{pread,2},[{type,632,bounded_fun,[{type,632,'fun',[{type,632,product,[{var,632,'IoDevice'},{var,632,'LocNums'}]},{type,632,union,[{type,632,tuple,[{atom,632,ok},{var,632,'DataL'}]},{atom,632,eof},{type,632,tuple,[{atom,632,error},{var,632,'Reason'}]}]}]},[{type,633,constraint,[{atom,633,is_subtype},[{var,633,'IoDevice'},{user_type,633,io_device,[]}]]},{type,634,constraint,[{atom,634,is_subtype},[{var,634,'LocNums'},{type,634,list,[{type,634,tuple,[{ann_type,634,[{var,634,'Location'},{user_type,634,location,[]}]},{ann_type,634,[{var,634,'Number'},{type,634,non_neg_integer,[]}]}]}]}]]},{type,635,constraint,[{atom,635,is_subtype},[{var,635,'DataL'},{type,635,list,[{var,635,'Data'}]}]]},{type,636,constraint,[{atom,636,is_subtype},[{var,636,'Data'},{type,636,union,[{type,636,string,[]},{type,636,binary,[]},{atom,636,eof}]}]]},{type,637,constraint,[{atom,637,is_subtype},[{var,637,'Reason'},{type,637,union,[{user_type,637,posix,[]},{atom,637,badarg},{atom,637,terminated}]}]]}]]}]}}]}},{{function,pread,3},[{file,[102,105,108,101,46,101,114,108]},{location,660}],[<<112,114,101,97,100,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32>>,{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46>>]},{p,[],[{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,108,121,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,97,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,97,110,100,32,117,110,99,104,97,110,103,101,100,32,102,111,114,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,46>>]},{p,[],[<<65,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,121,116,101,45,111,102,102,115,101,116,44,32,116,97,107,101,32,115,112,101,99,105,97,108,32,99,97,117,116,105,111,110,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,97,115,32,110,111,116,32,101,118,101,114,121,32,98,121,116,101,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,118,97,108,105,100,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,111,110,32,115,117,99,104,32,97,32,102,105,108,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,57,53>>,signature => [{attribute,660,spec,{{pread,3},[{type,660,bounded_fun,[{type,660,'fun',[{type,660,product,[{var,660,'IoDevice'},{var,660,'Location'},{var,660,'Number'}]},{type,661,union,[{type,661,tuple,[{atom,661,ok},{var,661,'Data'}]},{atom,661,eof},{type,661,tuple,[{atom,661,error},{var,661,'Reason'}]}]}]},[{type,662,constraint,[{atom,662,is_subtype},[{var,662,'IoDevice'},{user_type,662,io_device,[]}]]},{type,663,constraint,[{atom,663,is_subtype},[{var,663,'Location'},{user_type,663,location,[]}]]},{type,664,constraint,[{atom,664,is_subtype},[{var,664,'Number'},{type,664,non_neg_integer,[]}]]},{type,665,constraint,[{atom,665,is_subtype},[{var,665,'Data'},{type,665,union,[{type,665,string,[]},{type,665,binary,[]}]}]]},{type,666,constraint,[{atom,666,is_subtype},[{var,666,'Reason'},{type,666,union,[{user_type,666,posix,[]},{atom,666,badarg},{atom,666,terminated}]}]]}]]}]}}]}},{{function,pwrite,2},[{file,[102,105,108,101,46,101,114,108]},{location,693}],[<<112,119,114,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32>>,{code,[],[<<112,119,114,105,116,101,47,51>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,123,78,44,32,82,101,97,115,111,110,125,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,117,99,99,101,115,115,102,117,108,32,119,114,105,116,101,115,32,100,111,110,101,32,98,101,102,111,114,101,32,116,104,101,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<87,104,101,110,32,112,111,115,105,116,105,111,110,105,110,103,32,105,110,32,97,32,102,105,108,101,32,119,105,116,104,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,99,97,117,116,105,111,110,32,109,117,115,116,32,98,101,32,116,97,107,101,110,32,116,111,32,115,101,116,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,111,115,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,49,50>>,signature => [{attribute,693,spec,{{pwrite,2},[{type,693,bounded_fun,[{type,693,'fun',[{type,693,product,[{var,693,'IoDevice'},{var,693,'LocBytes'}]},{type,693,union,[{atom,693,ok},{type,693,tuple,[{atom,693,error},{type,693,tuple,[{var,693,'N'},{var,693,'Reason'}]}]}]}]},[{type,694,constraint,[{atom,694,is_subtype},[{var,694,'IoDevice'},{user_type,694,io_device,[]}]]},{type,695,constraint,[{atom,695,is_subtype},[{var,695,'LocBytes'},{type,695,list,[{type,695,tuple,[{ann_type,695,[{var,695,'Location'},{user_type,695,location,[]}]},{ann_type,695,[{var,695,'Bytes'},{type,695,iodata,[]}]}]}]}]]},{type,696,constraint,[{atom,696,is_subtype},[{var,696,'N'},{type,696,non_neg_integer,[]}]]},{type,697,constraint,[{atom,697,is_subtype},[{var,697,'Reason'},{type,697,union,[{user_type,697,posix,[]},{atom,697,badarg},{atom,697,terminated}]}]]}]]}]}}]}},{{function,pwrite,3},[{file,[102,105,108,101,46,101,114,108]},{location,718}],[<<112,119,114,105,116,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32>>,{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]},<<32,97,110,100,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46>>]},{p,[],[{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,108,121,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,97,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,97,110,100,32,117,110,99,104,97,110,103,101,100,32,102,111,114,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,112,111,115,105,116,105,111,110,105,110,103,32,105,110,32,97,32,102,105,108,101,32,119,105,116,104,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,99,97,117,116,105,111,110,32,109,117,115,116,32,98,101,32,116,97,107,101,110,32,116,111,32,115,101,116,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,111,115,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,50,55>>,signature => [{attribute,718,spec,{{pwrite,3},[{type,718,bounded_fun,[{type,718,'fun',[{type,718,product,[{var,718,'IoDevice'},{var,718,'Location'},{var,718,'Bytes'}]},{type,718,union,[{atom,718,ok},{type,718,tuple,[{atom,718,error},{var,718,'Reason'}]}]}]},[{type,719,constraint,[{atom,719,is_subtype},[{var,719,'IoDevice'},{user_type,719,io_device,[]}]]},{type,720,constraint,[{atom,720,is_subtype},[{var,720,'Location'},{user_type,720,location,[]}]]},{type,721,constraint,[{atom,721,is_subtype},[{var,721,'Bytes'},{type,721,iodata,[]}]]},{type,722,constraint,[{atom,722,is_subtype},[{var,722,'Reason'},{type,722,union,[{user_type,722,posix,[]},{atom,722,badarg},{atom,722,terminated}]}]]}]]}]}}]}},{{function,read,2},[{file,[102,105,108,101,46,101,114,108]},{location,590}],[<<114,101,97,100,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,98,121,116,101,115,47,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,84,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,114,101,97,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,101,97,100,47,51>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]}]},<<32,97,114,101,32,116,104,101,32,111,110,108,121,32,119,97,121,115,32,116,111,32,114,101,97,100,32,102,114,111,109,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,40,97,108,116,104,111,117,103,104,32,116,104,101,121,32,119,111,114,107,32,102,111,114,32,110,111,114,109,97,108,108,121,32,111,112,101,110,101,100,32,102,105,108,101,115,44,32,116,111,111,41,46>>]},{p,[],[<<70,111,114,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,121,116,101,32,111,110,32,116,104,101,32,102,105,108,101,46,32,84,104,101,32,112,97,114,97,109,101,116,101,114,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,97,108,119,97,121,115,32,100,101,110,111,116,101,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{em,[],[<<99,104,97,114,97,99,116,101,114,115>>]},<<32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,44,32,119,104,105,108,101,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,102,105,108,101,32,99,97,110,32,98,101,32,109,111,118,101,100,32,109,117,99,104,32,109,111,114,101,32,116,104,97,110,32,116,104,105,115,32,110,117,109,98,101,114,32,119,104,101,110,32,114,101,97,100,105,110,103,32,97,32,85,110,105,99,111,100,101,32,102,105,108,101,46>>]},{p,[],[<<65,108,115,111,44,32,105,102,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32>>,{code,[],[<<114,101,97,100,47,51>>]},<<32,99,97,108,108,32,102,97,105,108,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,99,104,97,114,97,99,116,101,114,115,32,108,97,114,103,101,114,32,116,104,97,110,32,50,53,53,44,32,119,104,105,99,104,32,105,115,32,119,104,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,32,119,104,101,110,32,114,101,97,100,105,110,103,32,115,117,99,104,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,68,97,116,97,125>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,119,97,115,32,111,112,101,110,101,100,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,44,32,116,104,101,32,114,101,97,100,32,98,121,116,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32,105,110,32,97,32,108,105,115,116,46,32,84,104,101,32,108,105,115,116,32,111,114,32,98,105,110,97,114,121,32,105,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,113,117,101,115,116,101,100,32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,101,100,32,105,102,32>>,{code,[],[<<78,117,109,98,101,114,62,48>>]},<<32,97,110,100,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,32,98,101,102,111,114,101,32,97,110,121,116,104,105,110,103,32,97,116,32,97,108,108,32,99,111,117,108,100,32,98,101,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,117,110,105,99,111,100,101,44,32,108,97,116,105,110,49,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,97,110,100,32,116,104,101,32,100,97,116,97,32,105,110,32,116,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,116,104,101,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,52,52>>,signature => [{attribute,590,spec,{{read,2},[{type,590,bounded_fun,[{type,590,'fun',[{type,590,product,[{var,590,'IoDevice'},{var,590,'Number'}]},{type,590,union,[{type,590,tuple,[{atom,590,ok},{var,590,'Data'}]},{atom,590,eof},{type,590,tuple,[{atom,590,error},{var,590,'Reason'}]}]}]},[{type,591,constraint,[{atom,591,is_subtype},[{var,591,'IoDevice'},{type,591,union,[{user_type,591,io_device,[]},{type,591,atom,[]}]}]]},{type,592,constraint,[{atom,592,is_subtype},[{var,592,'Number'},{type,592,non_neg_integer,[]}]]},{type,593,constraint,[{atom,593,is_subtype},[{var,593,'Data'},{type,593,union,[{type,593,string,[]},{type,593,binary,[]}]}]]},{type,594,constraint,[{atom,594,is_subtype},[{var,594,'Reason'},{type,594,union,[{user_type,594,posix,[]},{atom,595,badarg},{atom,596,terminated},{type,597,tuple,[{atom,597,no_translation},{atom,597,unicode},{atom,597,latin1}]}]}]]}]]}]}}]}},{{function,read_file,1},[{file,[102,105,108,101,46,101,114,108]},{location,419}],[<<114,101,97,100,95,102,105,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,105,110,97,114,121,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,114,101,97,100,105,110,103,32,116,104,101,32,102,105,108,101,44,32,111,114,32,102,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,109,101,109>>]}]},{dd,[],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,32,102,111,114,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,57,56>>,signature => [{attribute,419,spec,{{read_file,1},[{type,419,bounded_fun,[{type,419,'fun',[{type,419,product,[{var,419,'Filename'}]},{type,419,union,[{type,419,tuple,[{atom,419,ok},{var,419,'Binary'}]},{type,419,tuple,[{atom,419,error},{var,419,'Reason'}]}]}]},[{type,420,constraint,[{atom,420,is_subtype},[{var,420,'Filename'},{user_type,420,name_all,[]}]]},{type,421,constraint,[{atom,421,is_subtype},[{var,421,'Binary'},{type,421,binary,[]}]]},{type,422,constraint,[{atom,422,is_subtype},[{var,422,'Reason'},{type,422,union,[{user_type,422,posix,[]},{atom,422,badarg},{atom,422,terminated},{atom,422,system_limit}]}]]}]]}]}}]}},{{function,read_file_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,294}],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,52,51,52>>,equiv => {function,read_file_info,1},signature => [{attribute,294,spec,{{read_file_info,2},[{type,294,bounded_fun,[{type,294,'fun',[{type,294,product,[{var,294,'File'},{var,294,'Opts'}]},{type,294,union,[{type,294,tuple,[{atom,294,ok},{var,294,'FileInfo'}]},{type,294,tuple,[{atom,294,error},{var,294,'Reason'}]}]}]},[{type,295,constraint,[{atom,295,is_subtype},[{var,295,'File'},{type,295,union,[{user_type,295,name_all,[]},{user_type,295,io_device,[]}]}]]},{type,296,constraint,[{atom,296,is_subtype},[{var,296,'Opts'},{type,296,list,[{user_type,296,file_info_option,[]}]}]]},{type,297,constraint,[{atom,297,is_subtype},[{var,297,'FileInfo'},{user_type,297,file_info,[]}]]},{type,298,constraint,[{atom,298,is_subtype},[{var,298,'Reason'},{type,298,union,[{user_type,298,posix,[]},{atom,298,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,read_file_info,1},[{file,[102,105,108,101,46,101,114,108]},{location,282}],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,114,105,101,118,101,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,102,105,108,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,73,110,102,111,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,73,110,102,111>>]},<<32,105,115,32,97,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<44,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,75,101,114,110,101,108,32,105,110,99,108,117,100,101,32,102,105,108,101,32>>,{code,[],[<<102,105,108,101,46,104,114,108>>]},<<46,32,73,110,99,108,117,100,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,100,105,114,101,99,116,105,118,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32,102,114,111,109,32,119,104,105,99,104,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<32,45,105,110,99,108,117,100,101,95,108,105,98,40,34,107,101,114,110,101,108,47,105,110,99,108,117,100,101,47,102,105,108,101,46,104,114,108,34,41,46>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,116,121,112,101,32,114,101,116,117,114,110,101,100,32,105,110,32>>,{code,[],[<<97,116,105,109,101>>]},<<44,32>>,{code,[],[<<109,116,105,109,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<99,116,105,109,101>>]},<<32,105,115,32,100,101,112,101,110,100,101,110,116,32,111,110,32,116,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<79,112,116,115,32,58,58,32,123,116,105,109,101,44,32,84,121,112,101,125>>]},<<32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,108,111,99,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<117,110,105,118,101,114,115,97,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,117,110,105,118,101,114,115,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<112,111,115,105,120>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,115,101,99,111,110,100,115,32,115,105,110,99,101,32,111,114,32,98,101,102,111,114,101,32,85,110,105,120,32,116,105,109,101,32,101,112,111,99,104,44,32,119,104,105,99,104,32,105,115,32,49,57,55,48,45,48,49,45,48,49,32,48,48,58,48,48,32,85,84,67,46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,116,105,109,101,44,32,108,111,99,97,108,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,119,105,108,108,32,98,114,101,97,107,32,116,104,105,115,32,109,111,100,117,108,101,39,115,32,97,116,111,109,105,99,105,116,121,32,103,117,97,114,97,110,116,101,101,115,32,97,115,32,105,116,32,99,97,110,32,114,97,99,101,32,119,105,116,104,32,97,32,99,111,110,99,117,114,114,101,110,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]},<<32>>]},<<46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,103,105,118,101,110,32,97,110,32,73,47,79,32,100,101,118,105,99,101,32,105,110,115,116,101,97,100,32,111,102,32,97,32,102,105,108,101,32,110,97,109,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,116,111,32,111,98,116,97,105,110,32,97,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,102,105,114,115,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,105,108,101,32,116,105,109,101,115,32,97,114,101,32,115,116,111,114,101,100,32,105,110,32,80,79,83,73,88,32,116,105,109,101,32,111,110,32,109,111,115,116,32,79,83,44,32,105,116,32,105,115,32,102,97,115,116,101,114,32,116,111,32,113,117,101,114,121,32,102,105,108,101,32,105,110,102,111,114,109,97,116,105,111,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<112,111,115,105,120>>]},<<46>>]}]},{p,[],[<<84,104,101,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,101,108,100,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,105,122,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<83,105,122,101,32,111,102,32,102,105,108,101,32,105,110,32,98,121,116,101,115,46>>]}]},{dt,[],[{code,[],[<<116,121,112,101,32,61,32,100,101,118,105,99,101,32,124,32,100,105,114,101,99,116,111,114,121,32,124,32,111,116,104,101,114,32,124,32,114,101,103,117,108,97,114,32,124,32,115,121,109,108,105,110,107>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<97,99,99,101,115,115,32,61,32,114,101,97,100,32,124,32,119,114,105,116,101,32,124,32,114,101,97,100,95,119,114,105,116,101,32,124,32,110,111,110,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,99,99,101,115,115,32,116,111,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<97,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<109,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,119,114,105,116,116,101,110,46>>]}]},{dt,[],[{code,[],[<<99,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,116,105,109,101,32,102,105,101,108,100,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,46,32,79,110,32,85,110,105,120,44,32,105,116,32,105,115,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,111,114,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,119,97,115,32,99,104,97,110,103,101,100,46,32,73,110,32,87,105,110,100,111,119,115,44,32,105,116,32,105,115,32,116,104,101,32,99,114,101,97,116,101,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<109,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,112,101,114,109,105,115,115,105,111,110,115,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,98,105,116,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<56,35,48,48,52,48,48>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,50,48,48>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,49,48,48>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,52,48>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,50,48>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,49,48>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,52>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,50>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,49>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<49,54,35,56,48,48>>]}]},{dd,[],[{p,[],[<<115,101,116,32,117,115,101,114,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]},{dt,[],[{code,[],[<<49,54,35,52,48,48>>]}]},{dd,[],[{p,[],[<<115,101,116,32,103,114,111,117,112,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]}]},{p,[],[<<79,110,32,85,110,105,120,32,112,108,97,116,102,111,114,109,115,44,32,111,116,104,101,114,32,98,105,116,115,32,116,104,97,110,32,116,104,111,115,101,32,108,105,115,116,101,100,32,97,98,111,118,101,32,109,97,121,32,98,101,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<108,105,110,107,115,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<78,117,109,98,101,114,32,111,102,32,108,105,110,107,115,32,116,111,32,116,104,101,32,102,105,108,101,32,40,116,104,105,115,32,105,115,32,97,108,119,97,121,115,32,49,32,102,111,114,32,102,105,108,101,32,115,121,115,116,101,109,115,32,116,104,97,116,32,104,97,118,101,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,108,105,110,107,115,41,46>>]}]},{dt,[],[{code,[],[<<109,97,106,111,114,95,100,101,118,105,99,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,100,101,110,116,105,102,105,101,115,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,119,104,101,114,101,32,116,104,101,32,102,105,108,101,32,105,115,32,108,111,99,97,116,101,100,46,32,73,110,32,87,105,110,100,111,119,115,44,32,116,104,101,32,110,117,109,98,101,114,32,105,110,100,105,99,97,116,101,115,32,97,32,100,114,105,118,101,32,97,115,32,102,111,108,108,111,119,115,58,32,48,32,109,101,97,110,115,32,65,58,44,32,49,32,109,101,97,110,115,32,66,58,44,32,97,110,100,32,115,111,32,111,110,46>>]}]},{dt,[],[{code,[],[<<109,105,110,111,114,95,100,101,118,105,99,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32,99,104,97,114,97,99,116,101,114,32,100,101,118,105,99,101,115,32,111,110,32,85,110,105,120,46,32,73,110,32,97,108,108,32,111,116,104,101,114,32,99,97,115,101,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<105,110,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,110,117,109,98,101,114,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<117,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,110,100,105,99,97,116,101,115,32,116,104,101,32,111,119,110,101,114,32,111,102,32,116,104,101,32,102,105,108,101,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<103,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,32,111,119,110,101,114,32,111,102,32,116,104,101,32,102,105,108,101,32,98,101,108,111,110,103,115,32,116,111,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,52,51,52>>,signature => [{attribute,282,spec,{{read_file_info,1},[{type,282,bounded_fun,[{type,282,'fun',[{type,282,product,[{var,282,'File'}]},{type,282,union,[{type,282,tuple,[{atom,282,ok},{var,282,'FileInfo'}]},{type,282,tuple,[{atom,282,error},{var,282,'Reason'}]}]}]},[{type,283,constraint,[{atom,283,is_subtype},[{var,283,'File'},{type,283,union,[{user_type,283,name_all,[]},{user_type,283,io_device,[]}]}]]},{type,284,constraint,[{atom,284,is_subtype},[{var,284,'FileInfo'},{user_type,284,file_info,[]}]]},{type,285,constraint,[{atom,285,is_subtype},[{var,285,'Reason'},{type,285,union,[{user_type,285,posix,[]},{atom,285,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,read_line,1},[{file,[102,105,108,101,46,101,114,108]},{location,612}],[<<114,101,97,100,95,108,105,110,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,32,108,105,110,101,32,111,102,32,98,121,116,101,115,47,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,76,105,110,101,115,32,97,114,101,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,100,101,108,105,109,105,116,101,100,32,98,121,32,116,104,101,32,108,105,110,101,102,101,101,100,32,40,76,70,44,32>>,{code,[],[<<92,110>>]},<<41,32,99,104,97,114,97,99,116,101,114,44,32,98,117,116,32,97,110,121,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,67,82,44,32>>,{code,[],[<<92,114>>]},<<41,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,101,119,108,105,110,101,32,105,115,32,97,108,115,111,32,116,114,101,97,116,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,76,70,32,99,104,97,114,97,99,116,101,114,32,40,116,104,101,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,105,115,32,115,105,108,101,110,116,108,121,32,105,103,110,111,114,101,100,41,46,32,84,104,101,32,108,105,110,101,32,105,115,32,114,101,116,117,114,110,101,100,32>>,{em,[],[<<105,110,99,108,117,100,105,110,103>>]},<<32,116,104,101,32,76,70,44,32,98,117,116,32,101,120,99,108,117,100,105,110,103,32,97,110,121,32,67,82,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,76,70,46,32,84,104,105,115,32,98,101,104,97,118,105,111,117,114,32,105,115,32,99,111,110,115,105,115,116,101,110,116,32,119,105,116,104,32,116,104,101,32,98,101,104,97,118,105,111,117,114,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111,35,103,101,116,95,108,105,110,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,111,58,103,101,116,95,108,105,110,101,47,50>>]}]},<<46,32,73,102,32,101,110,100,32,111,102,32,102,105,108,101,32,105,115,32,114,101,97,99,104,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,76,70,32,101,110,100,105,110,103,32,116,104,101,32,108,97,115,116,32,108,105,110,101,44,32,97,32,108,105,110,101,32,119,105,116,104,32,110,111,32,116,114,97,105,108,105,110,103,32,76,70,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,111,110,32,102,105,108,101,115,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,46,32,72,111,119,101,118,101,114,44,32,105,116,32,105,115,32,105,110,101,102,102,105,99,105,101,110,116,32,116,111,32,117,115,101,32,105,116,32,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,115,32,105,102,32,116,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,115,112,101,99,105,102,105,101,100,46,32,84,104,117,115,44,32,99,111,109,98,105,110,105,110,103,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,105,115,32,104,105,103,104,108,121,32,114,101,99,111,109,109,101,110,100,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,97,32,116,101,120,116,32,102,105,108,101,32,102,111,114,32,114,97,119,32,108,105,110,101,45,111,114,105,101,110,116,101,100,32,114,101,97,100,105,110,103,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,99,97,108,108,32,102,97,105,108,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,99,104,97,114,97,99,116,101,114,115,32,108,97,114,103,101,114,32,116,104,97,110,32,50,53,53,44,32,119,104,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,32,119,104,101,110,32,114,101,97,100,105,110,103,32,115,117,99,104,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,68,97,116,97,125>>]}]},{dd,[],[{p,[],[<<79,110,101,32,108,105,110,101,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,105,115,32,114,101,116,117,114,110,101,100,44,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,116,114,97,105,108,105,110,103,32,76,70,44,32,98,117,116,32,119,105,116,104,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,32,114,101,112,108,97,99,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,76,70,32,40,115,101,101,32,97,98,111,118,101,41,46>>]},{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,44,32,116,104,101,32,114,101,97,100,32,98,121,116,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32,105,110,32,97,32,108,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,101,100,32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,32,98,101,102,111,114,101,32,97,110,121,116,104,105,110,103,32,97,116,32,97,108,108,32,99,111,117,108,100,32,98,101,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,117,110,105,99,111,100,101,44,32,108,97,116,105,110,49,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,97,110,100,32,116,104,101,32,100,97,116,97,32,111,110,32,116,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,116,104,101,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,53,57,51>>,signature => [{attribute,612,spec,{{read_line,1},[{type,612,bounded_fun,[{type,612,'fun',[{type,612,product,[{var,612,'IoDevice'}]},{type,612,union,[{type,612,tuple,[{atom,612,ok},{var,612,'Data'}]},{atom,612,eof},{type,612,tuple,[{atom,612,error},{var,612,'Reason'}]}]}]},[{type,613,constraint,[{atom,613,is_subtype},[{var,613,'IoDevice'},{type,613,union,[{user_type,613,io_device,[]},{type,613,atom,[]}]}]]},{type,614,constraint,[{atom,614,is_subtype},[{var,614,'Data'},{type,614,union,[{type,614,string,[]},{type,614,binary,[]}]}]]},{type,615,constraint,[{atom,615,is_subtype},[{var,615,'Reason'},{type,615,union,[{user_type,615,posix,[]},{atom,616,badarg},{atom,617,terminated},{type,618,tuple,[{atom,618,no_translation},{atom,618,unicode},{atom,618,latin1}]}]}]]}]]}]}}]}},{{function,read_link,1},[{file,[102,105,108,101,46,101,114,108]},{location,356}],[<<114,101,97,100,95,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<114,101,97,100,95,108,105,110,107,95,97,108,108>>}],[]},<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]},<<32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,114,97,119,32,102,105,108,101,110,97,109,101,44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,111,114,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,32,116,104,97,116,32,105,116,32,114,101,102,101,114,115,32,116,111,32,100,111,101,115,32,110,111,116,32,99,111,110,102,111,114,109,32,116,111,32,116,104,101,32,101,120,112,101,99,116,101,100,32,101,110,99,111,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,54,53,48>>,signature => [{attribute,356,spec,{{read_link,1},[{type,356,bounded_fun,[{type,356,'fun',[{type,356,product,[{var,356,'Name'}]},{type,356,union,[{type,356,tuple,[{atom,356,ok},{var,356,'Filename'}]},{type,356,tuple,[{atom,356,error},{var,356,'Reason'}]}]}]},[{type,357,constraint,[{atom,357,is_subtype},[{var,357,'Name'},{user_type,357,name_all,[]}]]},{type,358,constraint,[{atom,358,is_subtype},[{var,358,'Filename'},{user_type,358,filename,[]}]]},{type,359,constraint,[{atom,359,is_subtype},[{var,359,'Reason'},{type,359,union,[{user_type,359,posix,[]},{atom,359,badarg}]}]]}]]}]}}]}},{{function,read_link_all,1},[{file,[102,105,108,101,46,101,114,108]},{location,364}],[<<114,101,97,100,95,108,105,110,107,95,97,108,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]},<<32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,101,105,116,104,101,114,32,97,32,108,105,115,116,32,111,114,32,97,32,98,105,110,97,114,121,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,54,56,48>>,signature => [{attribute,364,spec,{{read_link_all,1},[{type,364,bounded_fun,[{type,364,'fun',[{type,364,product,[{var,364,'Name'}]},{type,364,union,[{type,364,tuple,[{atom,364,ok},{var,364,'Filename'}]},{type,364,tuple,[{atom,364,error},{var,364,'Reason'}]}]}]},[{type,365,constraint,[{atom,365,is_subtype},[{var,365,'Name'},{user_type,365,name_all,[]}]]},{type,366,constraint,[{atom,366,is_subtype},[{var,366,'Filename'},{user_type,366,filename_all,[]}]]},{type,367,constraint,[{atom,367,is_subtype},[{var,367,'Reason'},{type,367,union,[{user_type,367,posix,[]},{atom,367,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,54,66>>}},{{function,read_link_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,334}],[<<114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,48,56>>,equiv => {function,read_link_info,1},signature => [{attribute,334,spec,{{read_link_info,2},[{type,334,bounded_fun,[{type,334,'fun',[{type,334,product,[{var,334,'Name'},{var,334,'Opts'}]},{type,334,union,[{type,334,tuple,[{atom,334,ok},{var,334,'FileInfo'}]},{type,334,tuple,[{atom,334,error},{var,334,'Reason'}]}]}]},[{type,335,constraint,[{atom,335,is_subtype},[{var,335,'Name'},{user_type,335,name_all,[]}]]},{type,336,constraint,[{atom,336,is_subtype},[{var,336,'Opts'},{type,336,list,[{user_type,336,file_info_option,[]}]}]]},{type,337,constraint,[{atom,337,is_subtype},[{var,337,'FileInfo'},{user_type,337,file_info,[]}]]},{type,338,constraint,[{atom,338,is_subtype},[{var,338,'Reason'},{type,338,union,[{user_type,338,posix,[]},{atom,338,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,read_link_info,1},[{file,[102,105,108,101,46,101,114,108]},{location,326}],[<<114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]}]},<<32,101,120,99,101,112,116,32,116,104,97,116,32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,44,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,105,110,107,32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<32,114,101,99,111,114,100,32,97,110,100,32,116,104,101,32>>,{code,[],[<<116,121,112,101>>]},<<32,102,105,101,108,100,32,111,102,32,116,104,101,32,114,101,99,111,114,100,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<115,121,109,108,105,110,107>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,119,105,108,108,32,98,114,101,97,107,32,116,104,105,115,32,109,111,100,117,108,101,39,115,32,97,116,111,109,105,99,105,116,121,32,103,117,97,114,97,110,116,101,101,115,32,97,115,32,105,116,32,99,97,110,32,114,97,99,101,32,119,105,116,104,32,97,32,99,111,110,99,117,114,114,101,110,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,110,111,116,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32>>,{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,97,108,119,97,121,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,48,56>>,signature => [{attribute,326,spec,{{read_link_info,1},[{type,326,bounded_fun,[{type,326,'fun',[{type,326,product,[{var,326,'Name'}]},{type,326,union,[{type,326,tuple,[{atom,326,ok},{var,326,'FileInfo'}]},{type,326,tuple,[{atom,326,error},{var,326,'Reason'}]}]}]},[{type,327,constraint,[{atom,327,is_subtype},[{var,327,'Name'},{user_type,327,name_all,[]}]]},{type,328,constraint,[{atom,328,is_subtype},[{var,328,'FileInfo'},{user_type,328,file_info,[]}]]},{type,329,constraint,[{atom,329,is_subtype},[{var,329,'Reason'},{type,329,union,[{user_type,329,posix,[]},{atom,329,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,rename,2},[{file,[102,105,108,101,46,101,114,108]},{location,241}],[<<114,101,110,97,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,114,101,110,97,109,101,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,116,111,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,111,118,101,32,102,105,108,101,115,32,40,97,110,100,32,100,105,114,101,99,116,111,114,105,101,115,41,32,98,101,116,119,101,101,110,32,100,105,114,101,99,116,111,114,105,101,115,44,32,98,117,116,32,105,116,32,105,115,32,110,111,116,32,115,117,102,102,105,99,105,101,110,116,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,111,110,108,121,46,32,84,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,102,105,108,101,110,97,109,101,32,109,117,115,116,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32>>,{code,[],[<<98,97,114>>]},<<32,105,115,32,97,32,110,111,114,109,97,108,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<102,111,111>>]},<<32,97,110,100,32>>,{code,[],[<<98,97,122>>]},<<32,97,114,101,32,100,105,114,101,99,116,111,114,105,101,115,44,32>>,{code,[],[<<114,101,110,97,109,101,40,34,102,111,111,47,98,97,114,34,44,32,34,98,97,122,34,41>>]},<<32,114,101,116,117,114,110,115,32,97,110,32,101,114,114,111,114,44,32,98,117,116,32>>,{code,[],[<<114,101,110,97,109,101,40,34,102,111,111,47,98,97,114,34,44,32,34,98,97,122,47,98,97,114,34,41>>]},<<32,115,117,99,99,101,101,100,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,105,116,32,105,115,32,115,117,99,99,101,115,115,102,117,108,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<82,101,110,97,109,105,110,103,32,111,102,32,111,112,101,110,32,102,105,108,101,115,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,111,110,32,109,111,115,116,32,112,108,97,116,102,111,114,109,115,32,40,115,101,101,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,98,101,108,111,119,41,46>>]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,105,102,32,101,105,116,104,101,114,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,111,112,101,110,46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,109,112,116,121,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,97,108,115,111,32,103,105,118,101,110,32,119,104,101,110,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,97,114,101,32,110,111,116,32,111,102,32,116,104,101,32,115,97,109,101,32,116,121,112,101,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,97,32,114,111,111,116,32,100,105,114,101,99,116,111,114,121,44,32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,97,32,115,117,98,100,105,114,101,99,116,111,114,121,32,111,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,98,117,116,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,98,117,116,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,120,100,101,118>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,97,114,101,32,111,110,32,100,105,102,102,101,114,101,110,116,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,51,48>>,signature => [{attribute,241,spec,{{rename,2},[{type,241,bounded_fun,[{type,241,'fun',[{type,241,product,[{var,241,'Source'},{var,241,'Destination'}]},{type,241,union,[{atom,241,ok},{type,241,tuple,[{atom,241,error},{var,241,'Reason'}]}]}]},[{type,242,constraint,[{atom,242,is_subtype},[{var,242,'Source'},{user_type,242,name_all,[]}]]},{type,243,constraint,[{atom,243,is_subtype},[{var,243,'Destination'},{user_type,243,name_all,[]}]]},{type,244,constraint,[{atom,244,is_subtype},[{var,244,'Reason'},{type,244,union,[{user_type,244,posix,[]},{atom,244,badarg}]}]]}]]}]}}]}},{{function,script,1},[{file,[102,105,108,101,46,101,114,108]},{location,1123}],[<<115,99,114,105,112,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,86,97,108,117,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,57,51>>,signature => [{attribute,1123,spec,{{script,1},[{type,1123,bounded_fun,[{type,1123,'fun',[{type,1123,product,[{var,1123,'Filename'}]},{type,1123,union,[{type,1123,tuple,[{atom,1123,ok},{var,1123,'Value'}]},{type,1123,tuple,[{atom,1123,error},{var,1123,'Reason'}]}]}]},[{type,1124,constraint,[{atom,1124,is_subtype},[{var,1124,'Filename'},{user_type,1124,name_all,[]}]]},{type,1125,constraint,[{atom,1125,is_subtype},[{var,1125,'Value'},{type,1125,term,[]}]]},{type,1126,constraint,[{atom,1126,is_subtype},[{var,1126,'Reason'},{type,1126,union,[{user_type,1126,posix,[]},{atom,1126,badarg},{atom,1126,terminated},{atom,1126,system_limit},{type,1127,tuple,[{ann_type,1127,[{var,1127,'Line'},{type,1127,integer,[]}]},{ann_type,1127,[{var,1127,'Mod'},{type,1127,module,[]}]},{ann_type,1127,[{var,1127,'Term'},{type,1127,term,[]}]}]}]}]]}]]}]}}]}},{{function,script,2},[{file,[102,105,108,101,46,101,114,108]},{location,1132}],[<<115,99,114,105,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<115,99,114,105,112,116,47,49>>]},<<32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<32,97,98,111,117,116,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,50,56>>,signature => [{attribute,1132,spec,{{script,2},[{type,1132,bounded_fun,[{type,1132,'fun',[{type,1132,product,[{var,1132,'Filename'},{var,1132,'Bindings'}]},{type,1132,union,[{type,1132,tuple,[{atom,1132,ok},{var,1132,'Value'}]},{type,1132,tuple,[{atom,1132,error},{var,1132,'Reason'}]}]}]},[{type,1133,constraint,[{atom,1133,is_subtype},[{var,1133,'Filename'},{user_type,1133,name_all,[]}]]},{type,1134,constraint,[{atom,1134,is_subtype},[{var,1134,'Bindings'},{remote_type,1134,[{atom,1134,erl_eval},{atom,1134,binding_struct},[]]}]]},{type,1135,constraint,[{atom,1135,is_subtype},[{var,1135,'Value'},{type,1135,term,[]}]]},{type,1136,constraint,[{atom,1136,is_subtype},[{var,1136,'Reason'},{type,1136,union,[{user_type,1136,posix,[]},{atom,1136,badarg},{atom,1136,terminated},{atom,1136,system_limit},{type,1137,tuple,[{ann_type,1137,[{var,1137,'Line'},{type,1137,integer,[]}]},{ann_type,1137,[{var,1137,'Mod'},{type,1137,module,[]}]},{ann_type,1137,[{var,1137,'Term'},{type,1137,term,[]}]}]}]}]]}]]}]}}]}},{{function,sendfile,2},[{file,[102,105,108,101,46,101,114,108]},{location,1316}],[<<115,101,110,100,102,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,116,111,32>>,{code,[],[<<83,111,99,107,101,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,83,101,110,116,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,51,56>>,signature => [{attribute,1316,spec,{{sendfile,2},[{type,1316,bounded_fun,[{type,1316,'fun',[{type,1316,product,[{var,1316,'Filename'},{var,1316,'Socket'}]},{type,1317,union,[{type,1317,tuple,[{atom,1317,ok},{type,1317,non_neg_integer,[]}]},{type,1317,tuple,[{atom,1317,error},{type,1317,union,[{remote_type,1317,[{atom,1317,inet},{atom,1317,posix},[]]},{atom,1318,closed},{atom,1318,badarg},{atom,1318,not_owner}]}]}]}]},[{type,1319,constraint,[{atom,1319,is_subtype},[{var,1319,'Filename'},{user_type,1319,name_all,[]}]]},{type,1320,constraint,[{atom,1320,is_subtype},[{var,1320,'Socket'},{remote_type,1320,[{atom,1320,inet},{atom,1320,socket},[]]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,sendfile,5},[{file,[102,105,108,101,46,101,114,108]},{location,1289}],[<<115,101,110,100,102,105,108,101,47,53>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,101,110,100,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,110,100,115,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<82,97,119,70,105,108,101>>]},<<32,98,101,103,105,110,110,105,110,103,32,97,116,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,116,111,32>>,{code,[],[<<83,111,99,107,101,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,83,101,110,116,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,73,102,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<48>>]},<<32,97,108,108,32,100,97,116,97,32,97,102,116,101,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,105,115,32,115,101,110,116,46>>]},{p,[],[<<84,104,101,32,102,105,108,101,32,117,115,101,100,32,109,117,115,116,32,98,101,32,111,112,101,110,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<114,97,119>>]},<<32,102,108,97,103,44,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<115,101,110,100,102,105,108,101>>]},<<32,109,117,115,116,32,98,101,32,116,104,101,32,99,111,110,116,114,111,108,108,105,110,103,32,112,114,111,99,101,115,115,32,111,102,32,116,104,101,32,115,111,99,107,101,116,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,99,111,110,116,114,111,108,108,105,110,103,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,110,95,116,99,112,58,99,111,110,116,114,111,108,108,105,110,103,95,112,114,111,99,101,115,115,47,50>>]}]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,79,83,32,117,115,101,100,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,110,111,110,45,98,108,111,99,107,105,110,103,32>>,{code,[],[<<115,101,110,100,102,105,108,101>>]},<<44,32,97,110,32,69,114,108,97,110,103,32,102,97,108,108,98,97,99,107,32,117,115,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,110,95,116,99,112,58,115,101,110,100,47,50>>]}]},<<32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<99,104,117,110,107,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,99,104,117,110,107,32,115,105,122,101,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,102,97,108,108,98,97,99,107,32,116,111,32,115,101,110,100,32,100,97,116,97,46,32,73,102,32,117,115,105,110,103,32,116,104,101,32,102,97,108,108,98,97,99,107,44,32,115,101,116,32,116,104,105,115,32,116,111,32,97,32,118,97,108,117,101,32,116,104,97,116,32,99,111,109,102,111,114,116,97,98,108,121,32,102,105,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,115,32,109,101,109,111,114,121,46,32,68,101,102,97,117,108,116,32,105,115,32,50,48,32,77,66,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,52,55>>,signature => [{attribute,1289,spec,{{sendfile,5},[{type,1289,bounded_fun,[{type,1289,'fun',[{type,1289,product,[{var,1289,'RawFile'},{var,1289,'Socket'},{var,1289,'Offset'},{var,1289,'Bytes'},{var,1289,'Opts'}]},{type,1290,union,[{type,1290,tuple,[{atom,1290,ok},{type,1290,non_neg_integer,[]}]},{type,1290,tuple,[{atom,1290,error},{type,1290,union,[{remote_type,1290,[{atom,1290,inet},{atom,1290,posix},[]]},{atom,1291,closed},{atom,1291,badarg},{atom,1291,not_owner}]}]}]}]},[{type,1292,constraint,[{atom,1292,is_subtype},[{var,1292,'RawFile'},{user_type,1292,fd,[]}]]},{type,1293,constraint,[{atom,1293,is_subtype},[{var,1293,'Socket'},{remote_type,1293,[{atom,1293,inet},{atom,1293,socket},[]]}]]},{type,1294,constraint,[{atom,1294,is_subtype},[{var,1294,'Offset'},{type,1294,non_neg_integer,[]}]]},{type,1295,constraint,[{atom,1295,is_subtype},[{var,1295,'Bytes'},{type,1295,non_neg_integer,[]}]]},{type,1296,constraint,[{atom,1296,is_subtype},[{var,1296,'Opts'},{type,1296,list,[{user_type,1296,sendfile_option,[]}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,set_cwd,1},[{file,[102,105,108,101,46,101,114,108]},{location,206}],[<<115,101,116,95,99,119,100,47,49>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,116,111,32>>,{code,[],[<<68,105,114>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<102,105,108,101>>]},<<32,117,115,117,97,108,108,121,32,116,114,101,97,116,32,98,105,110,97,114,105,101,115,32,97,115,32,114,97,119,32,102,105,108,101,110,97,109,101,115,44,32,116,104,97,116,32,105,115,44,32,116,104,101,121,32,97,114,101,32,112,97,115,115,101,100,32,34,97,115,32,105,115,34,32,101,118,101,110,32,119,104,101,110,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,100,111,101,115,32,110,111,116,32,97,103,114,101,101,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,40,41>>]}]},<<46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,101,120,112,101,99,116,115,32,98,105,110,97,114,105,101,115,32,116,111,32,98,101,32,101,110,99,111,100,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,118,97,108,117,101,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,40,41>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,32,97,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,116,104,101,32,100,105,114,101,99,116,111,114,121,32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,115,46>>]}]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,114>>]},<<32,104,97,115,32,97,110,32,105,109,112,114,111,112,101,114,32,116,121,112,101,44,32,115,117,99,104,32,97,115,32,116,117,112,108,101,46>>]}]},{dt,[],[{code,[],[<<110,111,95,116,114,97,110,115,108,97,116,105,111,110>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,114>>]},<<32,105,115,32,97,32>>,{code,[],[<<98,105,110,97,114,121,40,41>>]},<<32,119,105,116,104,32,99,104,97,114,97,99,116,101,114,115,32,99,111,100,101,100,32,105,110,32,73,83,79,45,108,97,116,105,110,45,49,32,97,110,100,32,116,104,101,32,86,77,32,105,115,32,111,112,101,114,97,116,105,110,103,32,119,105,116,104,32,117,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,44,32,97,32,98,97,100,32,116,121,112,101,32,102,111,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<68,105,114>>]},<<32,119,105,108,108,32,112,114,111,98,97,98,108,121,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,55,52>>,signature => [{attribute,206,spec,{{set_cwd,1},[{type,206,bounded_fun,[{type,206,'fun',[{type,206,product,[{var,206,'Dir'}]},{type,206,union,[{atom,206,ok},{type,206,tuple,[{atom,206,error},{var,206,'Reason'}]}]}]},[{type,207,constraint,[{atom,207,is_subtype},[{var,207,'Dir'},{type,207,union,[{user_type,207,name,[]},{var,207,'EncodedBinary'}]}]]},{type,208,constraint,[{atom,208,is_subtype},[{var,208,'EncodedBinary'},{type,208,binary,[]}]]},{type,209,constraint,[{atom,209,is_subtype},[{var,209,'Reason'},{type,209,union,[{user_type,209,posix,[]},{atom,209,badarg},{atom,209,no_translation}]}]]}]]}]}}]}},{{function,sync,1},[{file,[102,105,108,101,46,101,114,108]},{location,742}],[<<115,121,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<69,110,115,117,114,101,115,32,116,104,97,116,32,97,110,121,32,98,117,102,102,101,114,115,32,107,101,112,116,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,40,110,111,116,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,109,105,103,104,116,32,104,97,118,101,32,110,111,32,101,102,102,101,99,116,46>>]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,116,32,101,110,111,117,103,104,32,115,112,97,99,101,32,108,101,102,116,32,116,111,32,119,114,105,116,101,32,116,104,101,32,102,105,108,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,50,49>>,signature => [{attribute,742,spec,{{sync,1},[{type,742,bounded_fun,[{type,742,'fun',[{type,742,product,[{var,742,'IoDevice'}]},{type,742,union,[{atom,742,ok},{type,742,tuple,[{atom,742,error},{var,742,'Reason'}]}]}]},[{type,743,constraint,[{atom,743,is_subtype},[{var,743,'IoDevice'},{user_type,743,io_device,[]}]]},{type,744,constraint,[{atom,744,is_subtype},[{var,744,'Reason'},{type,744,union,[{user_type,744,posix,[]},{atom,744,badarg},{atom,744,terminated}]}]]}]]}]}}]}},{{function,truncate,1},[{file,[102,105,108,101,46,101,114,108]},{location,766}],[<<116,114,117,110,99,97,116,101,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,117,110,99,97,116,101,115,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,51,55>>,signature => [{attribute,766,spec,{{truncate,1},[{type,766,bounded_fun,[{type,766,'fun',[{type,766,product,[{var,766,'IoDevice'}]},{type,766,union,[{atom,766,ok},{type,766,tuple,[{atom,766,error},{var,766,'Reason'}]}]}]},[{type,767,constraint,[{atom,767,is_subtype},[{var,767,'IoDevice'},{user_type,767,io_device,[]}]]},{type,768,constraint,[{atom,768,is_subtype},[{var,768,'Reason'},{type,768,union,[{user_type,768,posix,[]},{atom,768,badarg},{atom,768,terminated}]}]]}]]}]}}]}},{{function,write,2},[{file,[102,105,108,101,46,101,114,108]},{location,676}],[<<119,114,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,116,111,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,111,32,119,114,105,116,101,32,116,111,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,40,97,108,116,104,111,117,103,104,32,105,116,32,119,111,114,107,115,32,102,111,114,32,110,111,114,109,97,108,108,121,32,111,112,101,110,101,100,32,102,105,108,101,115,32,116,111,111,41,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,97,110,100,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,101,97,99,104,32,98,121,116,101,32,119,114,105,116,116,101,110,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,109,97,110,121,32,98,121,116,101,115,32,98,101,105,110,103,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,102,105,108,101,44,32,97,115,32,116,104,101,32,98,121,116,101,32,114,97,110,103,101,32,48,46,46,50,53,53,32,99,97,110,32,114,101,112,114,101,115,101,110,116,32,97,110,121,116,104,105,110,103,32,98,101,116,119,101,101,110,32,111,110,101,32,97,110,100,32,102,111,117,114,32,98,121,116,101,115,32,100,101,112,101,110,100,105,110,103,32,111,110,32,118,97,108,117,101,32,97,110,100,32,85,84,70,32,101,110,99,111,100,105,110,103,32,116,121,112,101,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,52,54>>,signature => [{attribute,676,spec,{{write,2},[{type,676,bounded_fun,[{type,676,'fun',[{type,676,product,[{var,676,'IoDevice'},{var,676,'Bytes'}]},{type,676,union,[{atom,676,ok},{type,676,tuple,[{atom,676,error},{var,676,'Reason'}]}]}]},[{type,677,constraint,[{atom,677,is_subtype},[{var,677,'IoDevice'},{type,677,union,[{user_type,677,io_device,[]},{type,677,atom,[]}]}]]},{type,678,constraint,[{atom,678,is_subtype},[{var,678,'Bytes'},{type,678,iodata,[]}]]},{type,679,constraint,[{atom,679,is_subtype},[{var,679,'Reason'},{type,679,union,[{user_type,679,posix,[]},{atom,679,badarg},{atom,679,terminated}]}]]}]]}]}}]}},{{function,write_file,2},[{file,[102,105,108,101,46,101,114,108]},{location,443}],[<<119,114,105,116,101,95,102,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<32,116,101,114,109,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,116,111,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,84,104,101,32,102,105,108,101,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,105,116,32,101,120,105,115,116,115,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,111,110,116,101,110,116,115,32,97,114,101,32,111,118,101,114,119,114,105,116,116,101,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,119,114,105,116,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,55,50>>,signature => [{attribute,443,spec,{{write_file,2},[{type,443,bounded_fun,[{type,443,'fun',[{type,443,product,[{var,443,'Filename'},{var,443,'Bytes'}]},{type,443,union,[{atom,443,ok},{type,443,tuple,[{atom,443,error},{var,443,'Reason'}]}]}]},[{type,444,constraint,[{atom,444,is_subtype},[{var,444,'Filename'},{user_type,444,name_all,[]}]]},{type,445,constraint,[{atom,445,is_subtype},[{var,445,'Bytes'},{type,445,iodata,[]}]]},{type,446,constraint,[{atom,446,is_subtype},[{var,446,'Reason'},{type,446,union,[{user_type,446,posix,[]},{atom,446,badarg},{atom,446,terminated},{atom,446,system_limit}]}]]}]]}]}}]}},{{function,write_file,3},[{file,[102,105,108,101,46,101,114,108]},{location,455}],[<<119,114,105,116,101,95,102,105,108,101,47,51>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<119,114,105,116,101,95,102,105,108,101,47,50>>]},<<44,32,98,117,116,32,116,97,107,101,115,32,97,32,116,104,105,114,100,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,111,100,101,115>>]},<<44,32,97,32,108,105,115,116,32,111,102,32,112,111,115,115,105,98,108,101,32,109,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46,32,84,104,101,32,109,111,100,101,32,102,108,97,103,115,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,97,110,100,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,97,114,101,32,105,109,112,108,105,99,105,116,44,32,115,111,32,116,104,101,121,32,97,114,101,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,48,57>>,signature => [{attribute,455,spec,{{write_file,3},[{type,455,bounded_fun,[{type,455,'fun',[{type,455,product,[{var,455,'Filename'},{var,455,'Bytes'},{var,455,'Modes'}]},{type,455,union,[{atom,455,ok},{type,455,tuple,[{atom,455,error},{var,455,'Reason'}]}]}]},[{type,456,constraint,[{atom,456,is_subtype},[{var,456,'Filename'},{user_type,456,name_all,[]}]]},{type,457,constraint,[{atom,457,is_subtype},[{var,457,'Bytes'},{type,457,iodata,[]}]]},{type,458,constraint,[{atom,458,is_subtype},[{var,458,'Modes'},{type,458,list,[{user_type,458,mode,[]}]}]]},{type,459,constraint,[{atom,459,is_subtype},[{var,459,'Reason'},{type,459,union,[{user_type,459,posix,[]},{atom,459,badarg},{atom,459,terminated},{atom,459,system_limit}]}]]}]]}]}}]}},{{function,write_file_info,3},[{file,[102,105,108,101,46,101,114,108]},{location,380}],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,51>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,50,48>>,equiv => {function,write_file_info,2},signature => [{attribute,380,spec,{{write_file_info,3},[{type,380,bounded_fun,[{type,380,'fun',[{type,380,product,[{var,380,'Filename'},{var,380,'FileInfo'},{var,380,'Opts'}]},{type,380,union,[{atom,380,ok},{type,380,tuple,[{atom,380,error},{var,380,'Reason'}]}]}]},[{type,381,constraint,[{atom,381,is_subtype},[{var,381,'Filename'},{user_type,381,name_all,[]}]]},{type,382,constraint,[{atom,382,is_subtype},[{var,382,'Opts'},{type,382,list,[{user_type,382,file_info_option,[]}]}]]},{type,383,constraint,[{atom,383,is_subtype},[{var,383,'FileInfo'},{user_type,383,file_info,[]}]]},{type,384,constraint,[{atom,384,is_subtype},[{var,384,'Reason'},{type,384,union,[{user_type,384,posix,[]},{atom,384,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{function,write_file_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,372}],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,102,105,108,101,32,105,110,102,111,114,109,97,116,105,111,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,73,110,102,111>>]},<<32,105,115,32,97,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<44,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,75,101,114,110,101,108,32,105,110,99,108,117,100,101,32,102,105,108,101,32>>,{code,[],[<<102,105,108,101,46,104,114,108>>]},<<46,32,73,110,99,108,117,100,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,100,105,114,101,99,116,105,118,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32,102,114,111,109,32,119,104,105,99,104,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<32,45,105,110,99,108,117,100,101,95,108,105,98,40,34,107,101,114,110,101,108,47,105,110,99,108,117,100,101,47,102,105,108,101,46,104,114,108,34,41,46>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<97,116,105,109,101>>]},<<44,32>>,{code,[],[<<109,116,105,109,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<99,116,105,109,101>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<79,112,116,115,32,58,58,32,123,116,105,109,101,44,32,84,121,112,101,125>>]},<<32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<73,110,116,101,114,112,114,101,116,115,32,116,104,101,32,116,105,109,101,32,115,101,116,32,97,115,32,108,111,99,97,108,46>>]}]},{dt,[],[{code,[],[<<117,110,105,118,101,114,115,97,108>>]}]},{dd,[],[{p,[],[<<73,110,116,101,114,112,114,101,116,115,32,105,116,32,97,115,32,117,110,105,118,101,114,115,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<112,111,115,105,120>>]}]},{dd,[],[{p,[],[<<77,117,115,116,32,98,101,32,115,101,99,111,110,100,115,32,115,105,110,99,101,32,111,114,32,98,101,102,111,114,101,32,85,110,105,120,32,116,105,109,101,32,101,112,111,99,104,44,32,119,104,105,99,104,32,105,115,32,49,57,55,48,45,48,49,45,48,49,32,48,48,58,48,48,32,85,84,67,46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,116,105,109,101,44,32,108,111,99,97,108,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,101,108,100,115,32,97,114,101,32,117,115,101,100,32,102,114,111,109,32,116,104,101,32,114,101,99,111,114,100,44,32,105,102,32,116,104,101,121,32,97,114,101,32,115,112,101,99,105,102,105,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<109,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,119,114,105,116,116,101,110,46>>]}]},{dt,[],[{code,[],[<<99,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<79,110,32,85,110,105,120,44,32,97,110,121,32,118,97,108,117,101,32,115,112,101,99,105,102,105,101,100,32,102,111,114,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,105,103,110,111,114,101,100,32,40,116,104,101,32,34,99,116,105,109,101,34,32,102,111,114,32,116,104,101,32,102,105,108,101,32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,41,46,32,79,110,32,87,105,110,100,111,119,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,116,104,101,32,110,101,119,32,99,114,101,97,116,105,111,110,32,116,105,109,101,32,116,111,32,115,101,116,32,102,111,114,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<109,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,112,101,114,109,105,115,115,105,111,110,115,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,98,105,116,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<56,35,48,48,52,48,48>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,50,48,48>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,49,48,48>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,52,48>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,50,48>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,49,48>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,52>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,50>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,49>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<49,54,35,56,48,48>>]}]},{dd,[],[{p,[],[<<83,101,116,32,117,115,101,114,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]},{dt,[],[{code,[],[<<49,54,35,52,48,48>>]}]},{dd,[],[{p,[],[<<83,101,116,32,103,114,111,117,112,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]}]},{p,[],[<<79,110,32,85,110,105,120,32,112,108,97,116,102,111,114,109,115,44,32,111,116,104,101,114,32,98,105,116,115,32,116,104,97,110,32,116,104,111,115,101,32,108,105,115,116,101,100,32,97,98,111,118,101,32,109,97,121,32,98,101,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<117,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,110,100,105,99,97,116,101,115,32,116,104,101,32,102,105,108,101,32,111,119,110,101,114,46,32,73,103,110,111,114,101,100,32,102,111,114,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]},{dt,[],[{code,[],[<<103,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,111,119,110,101,114,32,98,101,108,111,110,103,115,32,116,111,46,32,73,103,110,111,114,101,100,32,102,111,114,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,50,48>>,signature => [{attribute,372,spec,{{write_file_info,2},[{type,372,bounded_fun,[{type,372,'fun',[{type,372,product,[{var,372,'Filename'},{var,372,'FileInfo'}]},{type,372,union,[{atom,372,ok},{type,372,tuple,[{atom,372,error},{var,372,'Reason'}]}]}]},[{type,373,constraint,[{atom,373,is_subtype},[{var,373,'Filename'},{user_type,373,name_all,[]}]]},{type,374,constraint,[{atom,374,is_subtype},[{var,374,'FileInfo'},{user_type,374,file_info,[]}]]},{type,375,constraint,[{atom,375,is_subtype},[{var,375,'Reason'},{type,375,union,[{user_type,375,posix,[]},{atom,375,badarg}]}]]}]]}]}}],since => <<79,84,80,32,82,49,53,66>>}},{{type,deep_list,0},[{file,[102,105,108,101,46,101,114,108]},{location,101}],[<<45,116,121,112,101,32,100,101,101,112,95,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,101,type,{deep_list,{type,101,list,[{type,101,union,[{type,101,char,[]},{type,101,atom,[]},{user_type,101,deep_list,[]}]}]},[]}}]}},{{type,fd,0},[{file,[102,105,108,101,46,101,114,108]},{location,87}],[<<102,100,40,41>>],#{<<101,110>> => [{p,[],[<<65,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,97,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,97,119>>]}]},<<32,109,111,100,101,46>>]}]},#{signature => [{attribute,87,type,{fd,{type,87,record,[{atom,87,file_descriptor}]},[]}}]}},{{type,filename,0},[{file,[102,105,108,101,46,101,114,108]},{location,84}],[<<45,116,121,112,101,32,102,105,108,101,110,97,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,84,type,{filename,{type,84,string,[]},[]}}]}},{{type,filename_all,0},[{file,[102,105,108,101,46,101,114,108]},{location,85}],[<<45,116,121,112,101,32,102,105,108,101,110,97,109,101,95,97,108,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,85,type,{filename_all,{type,85,union,[{type,85,string,[]},{type,85,binary,[]}]},[]}}]}},{{type,io_device,0},[{file,[102,105,108,101,46,101,114,108]},{location,88}],[<<45,116,121,112,101,32,105,111,95,100,101,118,105,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<59,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,104,97,110,100,108,105,110,103,32,73,47,79,45,112,114,111,116,111,99,111,108,115,46>>]}]},#{signature => [{attribute,88,type,{io_device,{type,88,union,[{type,88,pid,[]},{user_type,88,fd,[]}]},[]}}]}},{{type,name,0},[{file,[102,105,108,101,46,101,114,108]},{location,102}],[<<45,116,121,112,101,32,110,97,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<73,102,32,86,77,32,105,115,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,44,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<32,97,110,100,32>>,{code,[],[<<99,104,97,114,40,41>>]},<<32,97,114,101,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,62,32,50,53,53,46,32,83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,102,type,{name,{type,102,union,[{type,102,string,[]},{type,102,atom,[]},{user_type,102,deep_list,[]}]},[]}}]}},{{type,name_all,0},[{file,[102,105,108,101,46,101,114,108]},{location,103}],[<<45,116,121,112,101,32,110,97,109,101,95,97,108,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<73,102,32,86,77,32,105,115,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,62,32,50,53,53,46,32>>,{code,[],[<<82,97,119,70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32,102,105,108,101,110,97,109,101,32,110,111,116,32,115,117,98,106,101,99,116,32,116,111,32,85,110,105,99,111,100,101,32,116,114,97,110,115,108,97,116,105,111,110,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,105,116,32,99,97,110,32,99,111,110,116,97,105,110,32,99,104,97,114,97,99,116,101,114,115,32,110,111,116,32,99,111,110,102,111,114,109,105,110,103,32,116,111,32,116,104,101,32,85,110,105,99,111,100,101,32,101,110,99,111,100,105,110,103,32,101,120,112,101,99,116,101,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,40,116,104,97,116,32,105,115,44,32,110,111,110,45,85,84,70,45,56,32,99,104,97,114,97,99,116,101,114,115,32,97,108,116,104,111,117,103,104,32,116,104,101,32,86,77,32,105,115,32,115,116,97,114,116,101,100,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,41,46,32,78,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,116,101,103,101,114,32,118,97,108,117,101,32,122,101,114,111,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,97,108,108,111,119,101,100,32,105,110,32,102,105,108,101,110,97,109,101,115,32,40,110,111,116,32,101,118,101,110,32,97,116,32,116,104,101,32,101,110,100,41,46>>]}]},#{signature => [{attribute,103,type,{name_all,{type,103,union,[{type,103,string,[]},{type,103,atom,[]},{user_type,103,deep_list,[]},{ann_type,103,[{var,103,'RawFilename'},{type,103,binary,[]}]}]},[]}}]}},{{type,posix,0},[{file,[102,105,108,101,46,101,114,108]},{location,104}],[<<45,116,121,112,101,32,112,111,115,105,120,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,97,116,111,109,32,116,104,97,116,32,105,115,32,110,97,109,101,100,32,102,114,111,109,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,115,32,117,115,101,100,32,105,110,32,85,110,105,120,44,32,97,110,100,32,105,110,32,116,104,101,32,114,117,110,116,105,109,101,32,108,105,98,114,97,114,105,101,115,32,111,102,32,109,111,115,116,32,67,32,99,111,109,112,105,108,101,114,115,46>>]}]},#{signature => [{attribute,104,type,{posix,{type,105,union,[{atom,105,eacces},{atom,105,eagain},{atom,106,ebadf},{atom,106,ebadmsg},{atom,106,ebusy},{atom,107,edeadlk},{atom,107,edeadlock},{atom,107,edquot},{atom,108,eexist},{atom,109,efault},{atom,109,efbig},{atom,109,eftype},{atom,110,eintr},{atom,110,einval},{atom,110,eio},{atom,110,eisdir},{atom,111,eloop},{atom,112,emfile},{atom,112,emlink},{atom,112,emultihop},{atom,113,enametoolong},{atom,113,enfile},{atom,114,enobufs},{atom,114,enodev},{atom,114,enolck},{atom,114,enolink},{atom,114,enoent},{atom,115,enomem},{atom,115,enospc},{atom,115,enosr},{atom,115,enostr},{atom,115,enosys},{atom,116,enotblk},{atom,116,enotdir},{atom,116,enotsup},{atom,116,enxio},{atom,117,eopnotsupp},{atom,117,eoverflow},{atom,118,eperm},{atom,118,epipe},{atom,119,erange},{atom,119,erofs},{atom,120,espipe},{atom,120,esrch},{atom,120,estale},{atom,121,etxtbsy},{atom,122,exdev}]},[]}}]}},{{type,date_time,0},[{file,[102,105,108,101,46,101,114,108]},{location,123}],[<<45,116,121,112,101,32,100,97,116,101,95,116,105,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<77,117,115,116,32,100,101,110,111,116,101,32,97,32,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{signature => [{attribute,123,type,{date_time,{remote_type,123,[{atom,123,calendar},{atom,123,datetime},[]]},[]}}]}},{{type,file_info,0},[{file,[102,105,108,101,46,101,114,108]},{location,86}],[<<45,116,121,112,101,32,102,105,108,101,95,105,110,102,111,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,86,type,{file_info,{type,86,record,[{atom,86,file_info}]},[]}}]}},{{type,location,0},[{file,[102,105,108,101,46,101,114,108]},{location,89}],[<<45,116,121,112,101,32,108,111,99,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,89,type,{location,{type,89,union,[{type,89,integer,[]},{type,89,tuple,[{atom,89,bof},{ann_type,89,[{var,89,'Offset'},{type,89,integer,[]}]}]},{type,90,tuple,[{atom,90,cur},{ann_type,90,[{var,90,'Offset'},{type,90,integer,[]}]}]},{type,91,tuple,[{atom,91,eof},{ann_type,91,[{var,91,'Offset'},{type,91,integer,[]}]}]},{atom,91,bof},{atom,91,cur},{atom,91,eof}]},[]}}]}},{{type,mode,0},[{file,[102,105,108,101,46,101,114,108]},{location,92}],[<<45,116,121,112,101,32,109,111,100,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,92,type,{mode,{type,92,union,[{atom,92,read},{atom,92,write},{atom,92,append},{atom,93,exclusive},{atom,93,raw},{atom,93,binary},{type,94,tuple,[{atom,94,delayed_write},{ann_type,95,[{var,95,'Size'},{type,95,non_neg_integer,[]}]},{ann_type,96,[{var,96,'Delay'},{type,96,non_neg_integer,[]}]}]},{atom,97,delayed_write},{type,97,tuple,[{atom,97,read_ahead},{ann_type,97,[{var,97,'Size'},{type,97,pos_integer,[]}]}]},{atom,98,read_ahead},{atom,98,compressed},{type,99,tuple,[{atom,99,encoding},{remote_type,99,[{atom,99,unicode},{atom,99,encoding},[]]}]},{atom,100,sync}]},[]}}]}},{{type,file_info_option,0},[{file,[102,105,108,101,46,101,114,108]},{location,129}],[<<45,116,121,112,101,32,102,105,108,101,95,105,110,102,111,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,129,type,{file_info_option,{type,129,union,[{type,129,tuple,[{atom,129,time},{atom,129,local}]},{type,129,tuple,[{atom,129,time},{atom,129,universal}]},{type,130,tuple,[{atom,130,time},{atom,130,posix}]},{atom,130,raw}]},[]}}]}}]}. \ No newline at end of file +{docs_v1,[{file,[102,105,108,101,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,112,114,111,118,105,100,101,115,32,97,110,32,105,110,116,101,114,102,97,99,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<70,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,97,114,101,32,111,110,108,121,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,97,112,112,101,97,114,32,97,116,111,109,105,99,32,119,104,101,110,32,103,111,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,32,115,97,109,101,32,102,105,108,101,32,115,101,114,118,101,114,46,32,65,32,78,73,70,32,111,114,32,111,116,104,101,114,32,79,83,32,112,114,111,99,101,115,115,32,109,97,121,32,111,98,115,101,114,118,101,32,105,110,116,101,114,109,101,100,105,97,116,101,32,115,116,101,112,115,32,111,110,32,99,101,114,116,97,105,110,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,115,111,109,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,44,32,101,103,46,32,114,101,110,97,109,105,110,103,32,97,110,32,101,120,105,115,116,105,110,103,32,102,105,108,101,32,111,110,32,87,105,110,100,111,119,115,44,32,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]},<<32>>]},<<111,110,32,97,110,121,32,79,83,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,119,114,105,116,105,110,103,46>>]}]},{p,[],[<<82,101,103,97,114,100,105,110,103,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,44,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,99,97,110,32,111,112,101,114,97,116,101,32,105,110,32,116,119,111,32,109,111,100,101,115,46,32,84,104,101,32,99,117,114,114,101,110,116,32,109,111,100,101,32,99,97,110,32,98,101,32,113,117,101,114,105,101,100,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>]}]},<<46,32,73,116,32,114,101,116,117,114,110,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,111,114,32>>,{code,[],[<<117,116,102,56>>]},<<46>>]},{p,[],[<<73,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,109,111,100,101,44,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,100,111,101,115,32,110,111,116,32,99,104,97,110,103,101,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32,102,105,108,101,110,97,109,101,115,46,32,73,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,44,32,102,105,108,101,110,97,109,101,115,32,99,97,110,32,99,111,110,116,97,105,110,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,50,53,53,32,97,110,100,32,116,104,101,32,86,77,32,99,111,110,118,101,114,116,115,32,102,105,108,101,110,97,109,101,115,32,98,97,99,107,32,97,110,100,32,102,111,114,116,104,32,116,111,32,116,104,101,32,110,97,116,105,118,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,40,117,115,117,97,108,108,121,32,85,84,70,45,56,44,32,98,117,116,32,85,84,70,45,49,54,32,111,110,32,87,105,110,100,111,119,115,41,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,109,111,100,101,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,46,32,87,105,110,100,111,119,115,44,32,77,97,99,79,83,32,88,32,97,110,100,32,65,110,100,114,111,105,100,32,101,110,102,111,114,99,101,32,99,111,110,115,105,115,116,101,110,116,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,116,104,101,32,86,77,32,117,115,101,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,46>>]},{p,[],[<<79,110,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,97,108,108,32,85,110,105,120,32,115,121,115,116,101,109,115,32,101,120,99,101,112,116,32,77,97,99,79,83,32,88,41,44,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<32,105,102,32,116,104,101,32,116,101,114,109,105,110,97,108,32,115,117,112,112,111,114,116,115,32,85,84,70,45,56,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<46,32,84,104,101,32,100,101,102,97,117,108,116,32,99,97,110,32,98,101,32,111,118,101,114,114,105,100,100,101,110,32,117,115,105,110,103,32>>,{code,[],[<<43,102,110,108>>]},<<32,40,116,111,32,102,111,114,99,101,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,109,111,100,101,41,32,111,114,32>>,{code,[],[<<43,102,110,117>>]},<<32,40,116,111,32,102,111,114,99,101,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,41,32,119,104,101,110,32,115,116,97,114,116,105,110,103,32>>,{a,[{href,<<101,114,116,115,58,101,114,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,99,111,109>>}],[{code,[],[<<101,114,108>>]}]},<<46>>]},{p,[],[<<79,110,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,44,32,102,105,108,101,115,32,99,97,110,32,98,101,32,105,110,99,111,110,115,105,115,116,101,110,116,108,121,32,110,97,109,101,100,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,115,111,109,101,32,102,105,108,101,115,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,85,84,70,45,56,32,119,104,105,108,101,32,111,116,104,101,114,115,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,73,83,79,32,76,97,116,105,110,45,49,46,32,84,104,101,32,99,111,110,99,101,112,116,32,111,102,32>>,{em,[],[<<114,97,119,32,102,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,105,110,116,114,111,100,117,99,101,100,32,116,111,32,104,97,110,100,108,101,32,102,105,108,101,32,115,121,115,116,101,109,115,32,119,105,116,104,32,105,110,99,111,110,115,105,115,116,101,110,116,32,110,97,109,105,110,103,32,119,104,101,110,32,114,117,110,110,105,110,103,32,105,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,46>>]},{p,[],[<<65,32>>,{em,[],[<<114,97,119,32,102,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32,102,105,108,101,110,97,109,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,105,110,97,114,121,46,32,84,104,101,32,69,114,108,97,110,103,32,86,77,32,100,111,101,115,32,110,111,116,32,116,114,97,110,115,108,97,116,101,32,97,32,102,105,108,101,110,97,109,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,105,110,97,114,121,32,111,110,32,115,121,115,116,101,109,115,32,119,105,116,104,32,116,114,97,110,115,112,97,114,101,110,116,32,110,97,109,105,110,103,46>>]},{p,[],[<<87,104,101,110,32,114,117,110,110,105,110,103,32,105,110,32>>,{code,[],[<<117,116,102,56>>]},<<32,109,111,100,101,44,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,108,105,115,116,95,100,105,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<108,105,115,116,95,100,105,114,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,107,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,107,47,49>>]}]},<<32,110,101,118,101,114,32,114,101,116,117,114,110,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,84,111,32,114,101,116,117,114,110,32,97,108,108,32,102,105,108,101,110,97,109,101,115,32,105,110,99,108,117,100,105,110,103,32,114,97,119,32,102,105,108,101,110,97,109,101,115,44,32,117,115,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,108,105,115,116,95,100,105,114,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<108,105,115,116,95,100,105,114,95,97,108,108,47,49>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,107,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,101,97,100,95,108,105,110,107,95,97,108,108,47,49>>]}]},<<46>>]},{p,[],[<<83,101,101,32,97,108,115,111,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,95,117,115,97,103,101,35,110,111,116,101,115,45,97,98,111,117,116,45,114,97,119,45,102,105,108,101,110,97,109,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<78,111,116,101,115,32,65,98,111,117,116,32,82,97,119,32,70,105,108,101,110,97,109,101,115>>]},<<32,105,110,32,116,104,101,32,83,84,68,76,73,66,32,85,115,101,114,39,115,32,71,117,105,100,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<70,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,117,115,101,100,32,116,111,32,97,99,99,101,112,116,32,102,105,108,101,110,97,109,101,115,32,99,111,110,116,97,105,110,105,110,103,32,110,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,116,101,103,101,114,32,118,97,108,117,101,32,122,101,114,111,41,46,32,84,104,105,115,32,99,97,117,115,101,100,32,116,104,101,32,110,97,109,101,32,116,111,32,98,101,32,116,114,117,110,99,97,116,101,100,32,97,110,100,32,105,110,32,115,111,109,101,32,99,97,115,101,115,32,97,114,103,117,109,101,110,116,115,32,116,111,32,112,114,105,109,105,116,105,118,101,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,98,101,32,109,105,120,101,100,32,117,112,46,32,70,105,108,101,110,97,109,101,115,32,99,111,110,116,97,105,110,105,110,103,32,110,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,105,110,115,105,100,101,32,116,104,101,32,102,105,108,101,110,97,109,101,32,97,114,101,32,110,111,119,32>>,{em,[],[<<114,101,106,101,99,116,101,100>>]},<<32,97,110,100,32,119,105,108,108,32,99,97,117,115,101,32,112,114,105,109,105,116,105,118,101,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,102,97,105,108,46>>]}]},{h2,[],[<<80,79,83,73,88,32,69,114,114,111,114,32,67,111,100,101,115>>]},{ul,[],[{li,[],[{code,[],[<<101,97,99,99,101,115>>]},<<32,45,32,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100>>]},{li,[],[{code,[],[<<101,97,103,97,105,110>>]},<<32,45,32,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101>>]},{li,[],[{code,[],[<<101,98,97,100,102>>]},<<32,45,32,66,97,100,32,102,105,108,101,32,110,117,109,98,101,114>>]},{li,[],[{code,[],[<<101,98,117,115,121>>]},<<32,45,32,70,105,108,101,32,98,117,115,121>>]},{li,[],[{code,[],[<<101,100,113,117,111,116>>]},<<32,45,32,68,105,115,107,32,113,117,111,116,97,32,101,120,99,101,101,100,101,100>>]},{li,[],[{code,[],[<<101,101,120,105,115,116>>]},<<32,45,32,70,105,108,101,32,97,108,114,101,97,100,121,32,101,120,105,115,116,115>>]},{li,[],[{code,[],[<<101,102,97,117,108,116>>]},<<32,45,32,66,97,100,32,97,100,100,114,101,115,115,32,105,110,32,115,121,115,116,101,109,32,99,97,108,108,32,97,114,103,117,109,101,110,116>>]},{li,[],[{code,[],[<<101,102,98,105,103>>]},<<32,45,32,70,105,108,101,32,116,111,111,32,108,97,114,103,101>>]},{li,[],[{code,[],[<<101,105,110,116,114>>]},<<32,45,32,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108>>]},{li,[],[{code,[],[<<101,105,110,118,97,108>>]},<<32,45,32,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116>>]},{li,[],[{code,[],[<<101,105,111>>]},<<32,45,32,73,47,79,32,101,114,114,111,114>>]},{li,[],[{code,[],[<<101,105,115,100,105,114>>]},<<32,45,32,73,108,108,101,103,97,108,32,111,112,101,114,97,116,105,111,110,32,111,110,32,97,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,108,111,111,112>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,108,101,118,101,108,115,32,111,102,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115>>]},{li,[],[{code,[],[<<101,109,102,105,108,101>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115>>]},{li,[],[{code,[],[<<101,109,108,105,110,107>>]},<<32,45,32,84,111,111,32,109,97,110,121,32,108,105,110,107,115>>]},{li,[],[{code,[],[<<101,110,97,109,101,116,111,111,108,111,110,103>>]},<<32,45,32,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103>>]},{li,[],[{code,[],[<<101,110,102,105,108,101>>]},<<32,45,32,70,105,108,101,32,116,97,98,108,101,32,111,118,101,114,102,108,111,119>>]},{li,[],[{code,[],[<<101,110,111,100,101,118>>]},<<32,45,32,78,111,32,115,117,99,104,32,100,101,118,105,99,101>>]},{li,[],[{code,[],[<<101,110,111,101,110,116>>]},<<32,45,32,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,109,101,109>>]},<<32,45,32,78,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,115,112,99>>]},<<32,45,32,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101>>]},{li,[],[{code,[],[<<101,110,111,116,98,108,107>>]},<<32,45,32,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100>>]},{li,[],[{code,[],[<<101,110,111,116,100,105,114>>]},<<32,45,32,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121>>]},{li,[],[{code,[],[<<101,110,111,116,115,117,112>>]},<<32,45,32,79,112,101,114,97,116,105,111,110,32,110,111,116,32,115,117,112,112,111,114,116,101,100>>]},{li,[],[{code,[],[<<101,110,120,105,111>>]},<<32,45,32,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115>>]},{li,[],[{code,[],[<<101,112,101,114,109>>]},<<32,45,32,78,111,116,32,111,119,110,101,114>>]},{li,[],[{code,[],[<<101,112,105,112,101>>]},<<32,45,32,66,114,111,107,101,110,32,112,105,112,101>>]},{li,[],[{code,[],[<<101,114,111,102,115>>]},<<32,45,32,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109>>]},{li,[],[{code,[],[<<101,115,112,105,112,101>>]},<<32,45,32,73,110,118,97,108,105,100,32,115,101,101,107>>]},{li,[],[{code,[],[<<101,115,114,99,104>>]},<<32,45,32,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115>>]},{li,[],[{code,[],[<<101,115,116,97,108,101>>]},<<32,45,32,83,116,97,108,101,32,114,101,109,111,116,101,32,102,105,108,101,32,104,97,110,100,108,101>>]},{li,[],[{code,[],[<<101,120,100,101,118>>]},<<32,45,32,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107>>]}]},{h2,[],[<<80,101,114,102,111,114,109,97,110,99,101>>]},{p,[],[<<70,111,114,32,105,110,99,114,101,97,115,101,100,32,112,101,114,102,111,114,109,97,110,99,101,44,32,114,97,119,32,102,105,108,101,115,32,97,114,101,32,114,101,99,111,109,109,101,110,100,101,100,46>>]},{p,[],[<<65,32,110,111,114,109,97,108,32,102,105,108,101,32,105,115,32,114,101,97,108,108,121,32,97,32,112,114,111,99,101,115,115,32,115,111,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,110,32,73,47,79,32,100,101,118,105,99,101,32,40,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111>>]}]},<<41,46,32,84,104,101,114,101,102,111,114,101,44,32,119,104,101,110,32,100,97,116,97,32,105,115,32,119,114,105,116,116,101,110,32,116,111,32,97,32,110,111,114,109,97,108,32,102,105,108,101,44,32,116,104,101,32,115,101,110,100,105,110,103,32,111,102,32,116,104,101,32,100,97,116,97,32,116,111,32,116,104,101,32,102,105,108,101,32,112,114,111,99,101,115,115,44,32,99,111,112,105,101,115,32,97,108,108,32,100,97,116,97,32,116,104,97,116,32,97,114,101,32,110,111,116,32,98,105,110,97,114,105,101,115,46,32,79,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,32,97,110,100,32,119,114,105,116,105,110,103,32,98,105,110,97,114,105,101,115,32,105,115,32,116,104,101,114,101,102,111,114,101,32,114,101,99,111,109,109,101,110,100,101,100,46,32,73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,111,110,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,111,114,32,105,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,114,117,110,115,32,97,115,32,115,108,97,118,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,97,108,115,111,32,98,105,110,97,114,105,101,115,32,97,114,101,32,99,111,112,105,101,100,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<82,97,119,32,102,105,108,101,115,32,117,115,101,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,111,102,32,116,104,101,32,104,111,115,116,32,109,97,99,104,105,110,101,32,111,102,32,116,104,101,32,110,111,100,101,46,32,70,111,114,32,110,111,114,109,97,108,32,102,105,108,101,115,32,40,110,111,110,45,114,97,119,41,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,117,115,101,100,32,116,111,32,102,105,110,100,32,116,104,101,32,102,105,108,101,115,44,32,97,110,100,32,105,102,32,116,104,101,32,110,111,100,101,32,105,115,32,114,117,110,110,105,110,103,32,105,116,115,32,102,105,108,101,32,115,101,114,118,101,114,32,97,115,32,115,108,97,118,101,32,116,111,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,97,110,111,116,104,101,114,32,110,111,100,101,44,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,110,111,100,101,32,114,117,110,115,32,111,110,32,115,111,109,101,32,111,116,104,101,114,32,104,111,115,116,32,109,97,99,104,105,110,101,44,32,116,104,101,121,32,99,97,110,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,102,105,108,101,32,115,121,115,116,101,109,115,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,105,115,32,115,101,108,100,111,109,32,97,32,112,114,111,98,108,101,109,46>>]}]},{p,[],[{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,99,97,110,32,98,101,32,103,105,118,101,110,32,116,104,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]},<<32,116,111,32,116,117,114,110,32,111,110,32,99,97,99,104,105,110,103,44,32,119,104,105,99,104,32,119,105,108,108,32,114,101,100,117,99,101,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,32,97,110,100,32,103,114,101,97,116,108,121,32,105,109,112,114,111,118,101,32,112,101,114,102,111,114,109,97,110,99,101,32,102,111,114,32,115,109,97,108,108,32,114,101,97,100,115,32,97,110,100,32,119,114,105,116,101,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,111,118,101,114,104,101,97,100,32,119,111,110,39,116,32,100,105,115,97,112,112,101,97,114,32,99,111,109,112,108,101,116,101,108,121,32,97,110,100,32,105,116,39,115,32,98,101,115,116,32,116,111,32,107,101,101,112,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,97,32,109,105,110,105,109,117,109,46,32,65,115,32,97,32,99,111,110,116,114,105,118,101,100,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,32,119,114,105,116,101,115,32,52,77,66,32,105,110,32,50,46,53,32,115,101,99,111,110,100,115,32,119,104,101,110,32,116,101,115,116,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,40,78,97,109,101,41,32,45,62,10,32,32,32,32,123,111,107,44,32,70,100,125,32,61,32,102,105,108,101,58,111,112,101,110,40,78,97,109,101,44,32,91,114,97,119,44,32,119,114,105,116,101,44,32,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,98,105,110,97,114,121,93,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,52,32,98,115,108,32,50,48,41,44,10,32,32,32,32,102,105,108,101,58,99,108,111,115,101,40,70,100,41,46,10,10,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,95,70,100,44,32,48,41,32,45,62,10,32,32,32,32,111,107,59,10,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,77,41,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,115,108,111,119,95,49,40,70,100,44,32,77,32,45,32,49,41,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,97,108,108,121,32,101,113,117,105,118,97,108,101,110,116,32,99,111,100,101,32,119,114,105,116,101,115,32,49,50,56,32,98,121,116,101,115,32,112,101,114,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,97,110,100,32,115,111,32,100,111,101,115,32,116,104,101,32,115,97,109,101,32,119,111,114,107,32,105,110,32,48,46,48,56,32,115,101,99,111,110,100,115,44,32,119,104,105,99,104,32,105,115,32,114,111,117,103,104,108,121,32,51,48,32,116,105,109,101,115,32,102,97,115,116,101,114,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<99,114,101,97,116,101,95,102,105,108,101,40,78,97,109,101,41,32,45,62,10,32,32,32,32,123,111,107,44,32,70,100,125,32,61,32,102,105,108,101,58,111,112,101,110,40,78,97,109,101,44,32,91,114,97,119,44,32,119,114,105,116,101,44,32,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,98,105,110,97,114,121,93,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,52,32,98,115,108,32,50,48,41,44,10,32,32,32,32,102,105,108,101,58,99,108,111,115,101,40,70,100,41,44,10,32,32,32,32,111,107,46,10,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,95,70,100,44,32,48,41,32,45,62,10,32,32,32,32,111,107,59,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,41,32,119,104,101,110,32,77,32,62,61,32,49,50,56,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,58,40,49,50,56,41,47,117,110,105,116,58,56,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,32,45,32,49,50,56,41,59,10,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,41,32,45,62,10,32,32,32,32,111,107,32,61,32,102,105,108,101,58,119,114,105,116,101,40,70,100,44,32,60,60,48,58,40,77,41,47,117,110,105,116,58,56,62,62,41,44,10,32,32,32,32,99,114,101,97,116,101,95,102,105,108,101,95,49,40,70,100,44,32,77,32,45,32,49,41,46>>]}]},{p,[],[<<87,104,101,110,32,119,114,105,116,105,110,103,32,100,97,116,97,32,105,116,39,115,32,103,101,110,101,114,97,108,108,121,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,111,32,119,114,105,116,101,32,97,32,108,105,115,116,32,111,102,32,98,105,110,97,114,105,101,115,32,114,97,116,104,101,114,32,116,104,97,110,32,97,32,108,105,115,116,32,111,102,32,105,110,116,101,103,101,114,115,46,32,73,116,32,105,115,32,110,111,116,32,110,101,101,100,101,100,32,116,111,32,102,108,97,116,116,101,110,32,97,32,100,101,101,112,32,108,105,115,116,32,98,101,102,111,114,101,32,119,114,105,116,105,110,103,46,32,79,110,32,85,110,105,120,32,104,111,115,116,115,44,32,115,99,97,116,116,101,114,32,111,117,116,112,117,116,44,32,119,104,105,99,104,32,119,114,105,116,101,115,32,97,32,115,101,116,32,111,102,32,98,117,102,102,101,114,115,32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,105,115,32,117,115,101,100,32,119,104,101,110,32,112,111,115,115,105,98,108,101,46,32,73,110,32,116,104,105,115,32,119,97,121,32>>,{code,[],[<<119,114,105,116,101,40,70,68,44,32,91,66,105,110,49,44,32,66,105,110,50,32,124,32,66,105,110,51,93,41>>]},<<32,119,114,105,116,101,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,98,105,110,97,114,105,101,115,32,119,105,116,104,111,117,116,32,99,111,112,121,105,110,103,32,116,104,101,32,100,97,116,97,32,97,116,32,97,108,108,44,32,101,120,99,101,112,116,32,102,111,114,32,112,101,114,104,97,112,115,32,100,101,101,112,32,100,111,119,110,32,105,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,107,101,114,110,101,108,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,97,110,32,111,112,101,110,32,102,105,108,101,32,119,105,116,104,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111>>]}]},<<44,32,116,104,101,32,112,114,111,99,101,115,115,32,104,97,110,100,108,105,110,103,32,116,104,101,32,102,105,108,101,32,101,120,105,116,115,46,32,84,104,101,32,100,101,97,100,32,102,105,108,101,32,112,114,111,99,101,115,115,32,99,97,110,32,104,97,110,103,32,105,102,32,97,32,112,114,111,99,101,115,115,32,116,114,105,101,115,32,116,111,32,97,99,99,101,115,115,32,105,116,32,108,97,116,101,114,46,32,84,104,105,115,32,119,105,108,108,32,98,101,32,102,105,120,101,100,32,105,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,46>>]}]},{h2,[],[<<83,101,101,32,65,108,115,111>>]},{p,[],[{a,[{href,<<115,116,100,108,105,98,58,102,105,108,101,110,97,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<102,105,108,101,110,97,109,101,40,51,41>>]}]}]}]},#{name => <<102,105,108,101>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,102,105,108,101,46,120,109,108],types => #{{date_time,0} => {attribute,{124,2},type,{date_time,{remote_type,{124,22},[{atom,{124,22},calendar},{atom,{124,31},datetime},[]]},[]}},{deep_list,0} => {attribute,{102,2},type,{deep_list,{type,{102,22},list,[{type,{102,23},union,[{type,{102,23},char,[]},{type,{102,32},atom,[]},{user_type,{102,41},deep_list,[]}]}]},[]}},{delete_option,0} => {attribute,{127,2},type,{delete_option,{atom,{127,26},raw},[]}},{fd,0} => {attribute,{88,2},type,{fd,{type,{88,22},record,[{atom,{88,23},file_descriptor}]},[]}},{file_info,0} => {attribute,{87,2},type,{file_info,{type,{87,22},record,[{atom,{87,23},file_info}]},[]}},{file_info_option,0} => {attribute,{130,2},type,{file_info_option,{type,{130,29},union,[{type,{130,29},tuple,[{atom,{130,30},time},{atom,{130,38},local}]},{type,{130,49},tuple,[{atom,{130,50},time},{atom,{130,58},universal}]},{type,{131,8},tuple,[{atom,{131,9},time},{atom,{131,17},posix}]},{atom,{131,28},raw}]},[]}},{filename,0} => {attribute,{85,2},type,{filename,{type,{85,22},string,[]},[]}},{filename_all,0} => {attribute,{86,2},type,{filename_all,{type,{86,25},union,[{type,{86,25},string,[]},{type,{86,36},binary,[]}]},[]}},{io_device,0} => {attribute,{89,2},type,{io_device,{type,{89,22},union,[{type,{89,22},pid,[]},{user_type,{89,30},fd,[]}]},[]}},{location,0} => {attribute,{90,2},type,{location,{type,{90,22},union,[{type,{90,22},integer,[]},{type,{90,34},tuple,[{atom,{90,35},bof},{ann_type,{90,42},[{var,{90,42},'Offset'},{type,{90,52},integer,[]}]}]},{type,{91,22},tuple,[{atom,{91,23},cur},{ann_type,{91,30},[{var,{91,30},'Offset'},{type,{91,40},integer,[]}]}]},{type,{92,8},tuple,[{atom,{92,9},eof},{ann_type,{92,16},[{var,{92,16},'Offset'},{type,{92,26},integer,[]}]}]},{atom,{92,39},bof},{atom,{92,47},cur},{atom,{92,55},eof}]},[]}},{mode,0} => {attribute,{93,2},type,{mode,{type,{93,22},union,[{atom,{93,22},read},{atom,{93,31},write},{atom,{93,41},append},{atom,{94,22},exclusive},{atom,{94,36},raw},{atom,{94,44},binary},{type,{95,8},tuple,[{atom,{95,9},delayed_write},{ann_type,{96,23},[{var,{96,23},'Size'},{type,{96,31},non_neg_integer,[]}]},{ann_type,{97,23},[{var,{97,23},'Delay'},{type,{97,32},non_neg_integer,[]}]}]},{atom,{98,8},delayed_write},{type,{98,26},tuple,[{atom,{98,27},read_ahead},{ann_type,{98,41},[{var,{98,41},'Size'},{type,{98,49},pos_integer,[]}]}]},{atom,{99,8},read_ahead},{atom,{99,23},compressed},{atom,{99,38},compressed_one},{type,{100,8},tuple,[{atom,{100,9},encoding},{remote_type,{100,21},[{atom,{100,21},unicode},{atom,{100,29},encoding},[]]}]},{atom,{101,8},sync}]},[]}},{name,0} => {attribute,{103,2},type,{name,{type,{103,22},union,[{type,{103,22},string,[]},{type,{103,33},atom,[]},{user_type,{103,42},deep_list,[]}]},[]}},{name_all,0} => {attribute,{104,2},type,{name_all,{type,{104,22},union,[{type,{104,22},string,[]},{type,{104,33},atom,[]},{user_type,{104,42},deep_list,[]},{ann_type,{104,57},[{var,{104,57},'RawFilename'},{type,{104,72},binary,[]}]}]},[]}},{posix,0} => {attribute,{105,2},type,{posix,{type,{106,9},union,[{atom,{106,9},eacces},{atom,{106,20},eagain},{atom,{107,9},ebadf},{atom,{107,19},ebadmsg},{atom,{107,31},ebusy},{atom,{108,9},edeadlk},{atom,{108,21},edeadlock},{atom,{108,35},edquot},{atom,{109,9},eexist},{atom,{110,9},efault},{atom,{110,20},efbig},{atom,{110,30},eftype},{atom,{111,9},eintr},{atom,{111,19},einval},{atom,{111,30},eio},{atom,{111,38},eisdir},{atom,{112,9},eloop},{atom,{113,9},emfile},{atom,{113,20},emlink},{atom,{113,31},emultihop},{atom,{114,9},enametoolong},{atom,{114,26},enfile},{atom,{115,9},enobufs},{atom,{115,21},enodev},{atom,{115,32},enolck},{atom,{115,43},enolink},{atom,{115,55},enoent},{atom,{116,9},enomem},{atom,{116,20},enospc},{atom,{116,31},enosr},{atom,{116,41},enostr},{atom,{116,52},enosys},{atom,{117,9},enotblk},{atom,{117,21},enotdir},{atom,{117,33},enotsup},{atom,{117,45},enxio},{atom,{118,9},eopnotsupp},{atom,{118,24},eoverflow},{atom,{119,9},eperm},{atom,{119,19},epipe},{atom,{120,9},erange},{atom,{120,20},erofs},{atom,{121,9},espipe},{atom,{121,21},esrch},{atom,{121,32},estale},{atom,{122,9},etxtbsy},{atom,{123,9},exdev}]},[]}},{posix_file_advise,0} => {attribute,{125,2},type,{posix_file_advise,{type,{125,30},union,[{atom,{125,30},normal},{atom,{125,41},sequential},{atom,{125,56},random},{atom,{126,30},no_reuse},{atom,{126,43},will_need},{atom,{126,57},dont_need}]},[]}},{sendfile_option,0} => {attribute,{128,2},type,{sendfile_option,{type,{128,28},union,[{type,{128,28},tuple,[{atom,{128,29},chunk_size},{type,{128,41},non_neg_integer,[]}]},{type,{129,7},tuple,[{atom,{129,8},use_threads},{type,{129,21},boolean,[]}]}]},[]}}}},[{{function,altname,1},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<97,108,116,110,97,109,101,47,49>>],hidden,#{}},{{function,copy_opened,3},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<99,111,112,121,95,111,112,101,110,101,100,47,51>>],hidden,#{}},{{function,ipread_s32bu_p32bu,3},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<105,112,114,101,97,100,95,115,51,50,98,117,95,112,51,50,98,117,47,51>>],hidden,#{}},{{function,ipread_s32bu_p32bu_int,3},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<105,112,114,101,97,100,95,115,51,50,98,117,95,112,51,50,98,117,95,105,110,116,47,51>>],hidden,#{}},{{function,path_eval,3},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<112,97,116,104,95,101,118,97,108,47,51>>],hidden,#{}},{{function,raw_read_file_info,1},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<114,97,119,95,114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>],hidden,#{}},{{function,raw_write_file_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<114,97,119,95,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>],hidden,#{}},{{function,advise,4},[{file,[102,105,108,101,46,101,114,108]},{location,559}],[<<97,100,118,105,115,101,47,52>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<112,111,115,105,120,95,102,105,108,101,95,97,100,118,105,115,101>>}],[]}]},{p,[],[{code,[],[<<97,100,118,105,115,101,47,52>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,110,110,111,117,110,99,101,32,97,110,32,105,110,116,101,110,116,105,111,110,32,116,111,32,97,99,99,101,115,115,32,102,105,108,101,32,100,97,116,97,32,105,110,32,97,32,115,112,101,99,105,102,105,99,32,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,102,117,116,117,114,101,44,32,116,104,117,115,32,97,108,108,111,119,105,110,103,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,116,111,32,112,101,114,102,111,114,109,32,97,112,112,114,111,112,114,105,97,116,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,46>>]},{p,[],[<<79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,109,105,103,104,116,32,104,97,118,101,32,110,111,32,101,102,102,101,99,116,46>>]}]},#{signature => [{attribute,{559,2},spec,{{advise,4},[{type,{559,13},bounded_fun,[{type,{559,13},'fun',[{type,{559,13},product,[{var,{559,14},'IoDevice'},{var,{559,24},'Offset'},{var,{559,32},'Length'},{var,{559,40},'Advise'}]},{type,{559,51},union,[{atom,{559,51},ok},{type,{559,56},tuple,[{atom,{559,57},error},{var,{559,64},'Reason'}]}]}]},[{type,{560,7},constraint,[{atom,{560,7},is_subtype},[{var,{560,7},'IoDevice'},{user_type,{560,19},io_device,[]}]]},{type,{561,7},constraint,[{atom,{561,7},is_subtype},[{var,{561,7},'Offset'},{type,{561,17},integer,[]}]]},{type,{562,7},constraint,[{atom,{562,7},is_subtype},[{var,{562,7},'Length'},{type,{562,17},integer,[]}]]},{type,{563,7},constraint,[{atom,{563,7},is_subtype},[{var,{563,7},'Advise'},{user_type,{563,17},posix_file_advise,[]}]]},{type,{564,7},constraint,[{atom,{564,7},is_subtype},[{var,{564,7},'Reason'},{type,{564,17},union,[{user_type,{564,17},posix,[]},{atom,{564,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,56>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,allocate,3},[{file,[102,105,108,101,46,101,114,108]},{location,573}],[<<97,108,108,111,99,97,116,101,47,51>>],#{<<101,110>> => [{p,[],[{code,[],[<<97,108,108,111,99,97,116,101,47,51>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,112,114,101,97,108,108,111,99,97,116,101,32,115,112,97,99,101,32,102,111,114,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,111,110,108,121,32,115,117,99,99,101,101,100,115,32,105,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,112,114,111,118,105,100,101,32,116,104,105,115,32,102,101,97,116,117,114,101,46>>]}]},#{signature => [{attribute,{573,2},spec,{{allocate,3},[{type,{573,15},bounded_fun,[{type,{573,15},'fun',[{type,{573,15},product,[{var,{573,16},'File'},{var,{573,22},'Offset'},{var,{573,30},'Length'}]},{type,{574,2},union,[{atom,{574,2},ok},{type,{574,9},tuple,[{atom,{574,10},error},{user_type,{574,19},posix,[]}]}]}]},[{type,{575,7},constraint,[{atom,{575,7},is_subtype},[{var,{575,7},'File'},{user_type,{575,15},io_device,[]}]]},{type,{576,7},constraint,[{atom,{576,7},is_subtype},[{var,{576,7},'Offset'},{type,{576,17},non_neg_integer,[]}]]},{type,{577,7},constraint,[{atom,{577,7},is_subtype},[{var,{577,7},'Length'},{type,{577,17},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,57>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,change_group,2},[{file,[102,105,108,101,46,101,114,108]},{location,1243}],[<<99,104,97,110,103,101,95,103,114,111,117,112,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,103,114,111,117,112,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1243,2},spec,{{change_group,2},[{type,{1243,19},bounded_fun,[{type,{1243,19},'fun',[{type,{1243,19},product,[{var,{1243,20},'Filename'},{var,{1243,30},'Gid'}]},{type,{1243,38},union,[{atom,{1243,38},ok},{type,{1243,43},tuple,[{atom,{1243,44},error},{var,{1243,51},'Reason'}]}]}]},[{type,{1244,7},constraint,[{atom,{1244,7},is_subtype},[{var,{1244,7},'Filename'},{user_type,{1244,19},name_all,[]}]]},{type,{1245,7},constraint,[{atom,{1245,7},is_subtype},[{var,{1245,7},'Gid'},{type,{1245,14},integer,[]}]]},{type,{1246,7},constraint,[{atom,{1246,7},is_subtype},[{var,{1246,7},'Reason'},{type,{1246,17},union,[{user_type,{1246,17},posix,[]},{atom,{1246,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,56>>}},{{function,change_mode,2},[{file,[102,105,108,101,46,101,114,108]},{location,1215}],[<<99,104,97,110,103,101,95,109,111,100,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,112,101,114,109,105,115,115,105,111,110,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1215,2},spec,{{change_mode,2},[{type,{1215,18},bounded_fun,[{type,{1215,18},'fun',[{type,{1215,18},product,[{var,{1215,19},'Filename'},{var,{1215,29},'Mode'}]},{type,{1215,38},union,[{atom,{1215,38},ok},{type,{1215,43},tuple,[{atom,{1215,44},error},{var,{1215,51},'Reason'}]}]}]},[{type,{1216,7},constraint,[{atom,{1216,7},is_subtype},[{var,{1216,7},'Filename'},{user_type,{1216,19},name_all,[]}]]},{type,{1217,7},constraint,[{atom,{1217,7},is_subtype},[{var,{1217,7},'Mode'},{type,{1217,15},integer,[]}]]},{type,{1218,7},constraint,[{atom,{1218,7},is_subtype},[{var,{1218,7},'Reason'},{type,{1218,17},union,[{user_type,{1218,17},posix,[]},{atom,{1218,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,49,54>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,change_owner,2},[{file,[102,105,108,101,46,101,114,108]},{location,1224}],[<<99,104,97,110,103,101,95,111,119,110,101,114,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,111,119,110,101,114,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1224,2},spec,{{change_owner,2},[{type,{1224,19},bounded_fun,[{type,{1224,19},'fun',[{type,{1224,19},product,[{var,{1224,20},'Filename'},{var,{1224,30},'Uid'}]},{type,{1224,38},union,[{atom,{1224,38},ok},{type,{1224,43},tuple,[{atom,{1224,44},error},{var,{1224,51},'Reason'}]}]}]},[{type,{1225,7},constraint,[{atom,{1225,7},is_subtype},[{var,{1225,7},'Filename'},{user_type,{1225,19},name_all,[]}]]},{type,{1226,7},constraint,[{atom,{1226,7},is_subtype},[{var,{1226,7},'Uid'},{type,{1226,14},integer,[]}]]},{type,{1227,7},constraint,[{atom,{1227,7},is_subtype},[{var,{1227,7},'Reason'},{type,{1227,17},union,[{user_type,{1227,17},posix,[]},{atom,{1227,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,50,52>>}},{{function,change_owner,3},[{file,[102,105,108,101,46,101,114,108]},{location,1233}],[<<99,104,97,110,103,101,95,111,119,110,101,114,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,111,119,110,101,114,32,97,110,100,32,103,114,111,117,112,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1233,2},spec,{{change_owner,3},[{type,{1233,19},bounded_fun,[{type,{1233,19},'fun',[{type,{1233,19},product,[{var,{1233,20},'Filename'},{var,{1233,30},'Uid'},{var,{1233,35},'Gid'}]},{type,{1233,43},union,[{atom,{1233,43},ok},{type,{1233,48},tuple,[{atom,{1233,49},error},{var,{1233,56},'Reason'}]}]}]},[{type,{1234,7},constraint,[{atom,{1234,7},is_subtype},[{var,{1234,7},'Filename'},{user_type,{1234,19},name_all,[]}]]},{type,{1235,7},constraint,[{atom,{1235,7},is_subtype},[{var,{1235,7},'Uid'},{type,{1235,14},integer,[]}]]},{type,{1236,7},constraint,[{atom,{1236,7},is_subtype},[{var,{1236,7},'Gid'},{type,{1236,14},integer,[]}]]},{type,{1237,7},constraint,[{atom,{1237,7},is_subtype},[{var,{1237,7},'Reason'},{type,{1237,17},union,[{user_type,{1237,17},posix,[]},{atom,{1237,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,51,50>>}},{{function,change_time,2},[{file,[102,105,108,101,46,101,114,108]},{location,1252}],[<<99,104,97,110,103,101,95,116,105,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,97,110,100,32,97,99,99,101,115,115,32,116,105,109,101,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1252,2},spec,{{change_time,2},[{type,{1252,18},bounded_fun,[{type,{1252,18},'fun',[{type,{1252,18},product,[{var,{1252,19},'Filename'},{var,{1252,29},'Mtime'}]},{type,{1252,39},union,[{atom,{1252,39},ok},{type,{1252,44},tuple,[{atom,{1252,45},error},{var,{1252,52},'Reason'}]}]}]},[{type,{1253,7},constraint,[{atom,{1253,7},is_subtype},[{var,{1253,7},'Filename'},{user_type,{1253,19},name_all,[]}]]},{type,{1254,7},constraint,[{atom,{1254,7},is_subtype},[{var,{1254,7},'Mtime'},{user_type,{1254,16},date_time,[]}]]},{type,{1255,7},constraint,[{atom,{1255,7},is_subtype},[{var,{1255,7},'Reason'},{type,{1255,17},union,[{user_type,{1255,17},posix,[]},{atom,{1255,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,52,48>>}},{{function,change_time,3},[{file,[102,105,108,101,46,101,114,108]},{location,1262}],[<<99,104,97,110,103,101,95,116,105,109,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,97,110,100,32,108,97,115,116,32,97,99,99,101,115,115,32,116,105,109,101,115,32,111,102,32,97,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{1262,2},spec,{{change_time,3},[{type,{1262,18},bounded_fun,[{type,{1262,18},'fun',[{type,{1262,18},product,[{var,{1262,19},'Filename'},{var,{1262,29},'Atime'},{var,{1262,36},'Mtime'}]},{type,{1262,46},union,[{atom,{1262,46},ok},{type,{1262,51},tuple,[{atom,{1262,52},error},{var,{1262,59},'Reason'}]}]}]},[{type,{1263,7},constraint,[{atom,{1263,7},is_subtype},[{var,{1263,7},'Filename'},{user_type,{1263,19},name_all,[]}]]},{type,{1264,7},constraint,[{atom,{1264,7},is_subtype},[{var,{1264,7},'Atime'},{user_type,{1264,16},date_time,[]}]]},{type,{1265,7},constraint,[{atom,{1265,7},is_subtype},[{var,{1265,7},'Mtime'},{user_type,{1265,16},date_time,[]}]]},{type,{1266,7},constraint,[{atom,{1266,7},is_subtype},[{var,{1266,7},'Reason'},{type,{1266,17},union,[{user_type,{1266,17},posix,[]},{atom,{1266,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,52,56>>}},{{function,close,1},[{file,[102,105,108,101,46,101,114,108]},{location,540}],[<<99,108,111,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<67,108,111,115,101,115,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,73,116,32,109,111,115,116,108,121,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<44,32,101,120,99,101,112,116,32,102,111,114,32,115,111,109,101,32,115,101,118,101,114,101,32,101,114,114,111,114,115,32,115,117,99,104,32,97,115,32,111,117,116,32,111,102,32,109,101,109,111,114,121,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,119,97,115,32,117,115,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,44,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,99,97,110,32,114,101,116,117,114,110,32,97,110,32,111,108,100,32,119,114,105,116,101,32,101,114,114,111,114,32,97,110,100,32,110,111,116,32,101,118,101,110,32,116,114,121,32,116,111,32,99,108,111,115,101,32,116,104,101,32,102,105,108,101,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{540,2},spec,{{close,1},[{type,{540,12},bounded_fun,[{type,{540,12},'fun',[{type,{540,12},product,[{var,{540,13},'IoDevice'}]},{type,{540,26},union,[{atom,{540,26},ok},{type,{540,31},tuple,[{atom,{540,32},error},{var,{540,39},'Reason'}]}]}]},[{type,{541,7},constraint,[{atom,{541,7},is_subtype},[{var,{541,7},'IoDevice'},{user_type,{541,19},io_device,[]}]]},{type,{542,7},constraint,[{atom,{542,7},is_subtype},[{var,{542,7},'Reason'},{type,{542,17},union,[{user_type,{542,17},posix,[]},{atom,{542,27},badarg},{atom,{542,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,53,54>>}},{{function,consult,1},[{file,[102,105,108,101,46,101,114,108]},{location,1019}],[<<99,111,110,115,117,108,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,69,114,108,97,110,103,32,116,101,114,109,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,44,32,102,114,111,109,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,84,101,114,109,115,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,116,101,114,109,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,84,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<46>>]}]}]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<102,46,116,120,116,58,32,32,123,112,101,114,115,111,110,44,32,34,107,97,108,108,101,34,44,32,50,53,125,46,10,32,32,32,32,32,32,32,32,123,112,101,114,115,111,110,44,32,34,112,101,108,108,101,34,44,32,51,48,125,46>>]}]},{pre,[],[{code,[],[<<49,62,32,102,105,108,101,58,99,111,110,115,117,108,116,40,34,102,46,116,120,116,34,41,46,10,123,111,107,44,91,123,112,101,114,115,111,110,44,34,107,97,108,108,101,34,44,50,53,125,44,123,112,101,114,115,111,110,44,34,112,101,108,108,101,34,44,51,48,125,93,125>>]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1019,2},spec,{{consult,1},[{type,{1019,14},bounded_fun,[{type,{1019,14},'fun',[{type,{1019,14},product,[{var,{1019,15},'Filename'}]},{type,{1019,28},union,[{type,{1019,28},tuple,[{atom,{1019,29},ok},{var,{1019,33},'Terms'}]},{type,{1019,42},tuple,[{atom,{1019,43},error},{var,{1019,50},'Reason'}]}]}]},[{type,{1020,7},constraint,[{atom,{1020,7},is_subtype},[{var,{1020,7},'Filename'},{user_type,{1020,19},name_all,[]}]]},{type,{1021,7},constraint,[{atom,{1021,7},is_subtype},[{var,{1021,7},'Terms'},{type,{1021,16},list,[{type,{1021,17},term,[]}]}]]},{type,{1022,7},constraint,[{atom,{1022,7},is_subtype},[{var,{1022,7},'Reason'},{type,{1022,17},union,[{user_type,{1022,17},posix,[]},{atom,{1022,27},badarg},{atom,{1022,36},terminated},{atom,{1022,49},system_limit},{type,{1023,17},tuple,[{ann_type,{1023,18},[{var,{1023,18},'Line'},{type,{1023,26},integer,[]}]},{ann_type,{1023,37},[{var,{1023,37},'Mod'},{type,{1023,44},module,[]}]},{ann_type,{1023,54},[{var,{1023,54},'Term'},{type,{1023,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,54,57>>}},{{function,copy,3},[{file,[102,105,108,101,46,101,114,108]},{location,782}],[<<99,111,112,121,47,51>>],#{},#{signature => [{attribute,{782,2},spec,{{copy,3},[{type,{782,11},bounded_fun,[{type,{782,11},'fun',[{type,{782,11},product,[{var,{782,12},'Source'},{var,{782,20},'Destination'},{var,{782,33},'ByteCount'}]},{type,{783,14},union,[{type,{783,14},tuple,[{atom,{783,15},ok},{var,{783,19},'BytesCopied'}]},{type,{783,34},tuple,[{atom,{783,35},error},{var,{783,42},'Reason'}]}]}]},[{type,{784,7},constraint,[{atom,{784,7},is_subtype},[{var,{784,7},'Source'},{type,{784,17},union,[{user_type,{784,17},io_device,[]},{var,{784,31},'Filename'},{type,{784,42},tuple,[{var,{784,43},'Filename'},{var,{784,53},'Modes'}]}]}]]},{type,{785,7},constraint,[{atom,{785,7},is_subtype},[{var,{785,7},'Destination'},{type,{785,22},union,[{user_type,{785,22},io_device,[]},{var,{785,36},'Filename'},{type,{785,47},tuple,[{var,{785,48},'Filename'},{var,{785,58},'Modes'}]}]}]]},{type,{786,7},constraint,[{atom,{786,7},is_subtype},[{var,{786,7},'Filename'},{user_type,{786,19},name_all,[]}]]},{type,{787,7},constraint,[{atom,{787,7},is_subtype},[{var,{787,7},'Modes'},{type,{787,16},list,[{user_type,{787,17},mode,[]}]}]]},{type,{788,7},constraint,[{atom,{788,7},is_subtype},[{var,{788,7},'ByteCount'},{type,{788,20},union,[{type,{788,20},non_neg_integer,[]},{atom,{788,40},infinity}]}]]},{type,{789,7},constraint,[{atom,{789,7},is_subtype},[{var,{789,7},'BytesCopied'},{type,{789,22},non_neg_integer,[]}]]},{type,{790,7},constraint,[{atom,{790,7},is_subtype},[{var,{790,7},'Reason'},{type,{790,17},union,[{user_type,{790,17},posix,[]},{atom,{790,27},badarg},{atom,{790,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,48,55>>,equiv => {function,copy,2}}},{{function,copy,2},[{file,[102,105,108,101,46,101,114,108]},{location,771}],[<<99,111,112,121,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,112,105,101,115,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,98,121,116,101,115,32,102,114,111,109,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,116,111,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,32,116,111,32,101,105,116,104,101,114,32,102,105,108,101,110,97,109,101,115,32,111,114,32,73,79,32,100,101,118,105,99,101,115,32,102,114,111,109,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<111,112,101,110,47,50>>]},<<46,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<105,110,102,105,110,105,116,121>>]},<<44,32,100,101,110,111,116,105,110,103,32,97,110,32,105,110,102,105,110,105,116,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,46>>]},{p,[],[<<65,114,103,117,109,101,110,116,32>>,{code,[],[<<77,111,100,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,112,111,115,115,105,98,108,101,32,109,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<44,32,97,110,100,32,100,101,102,97,117,108,116,115,32,116,111,32>>,{code,[],[<<91,93>>]},<<46>>]},{p,[],[<<73,102,32,98,111,116,104,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,32,116,111,32,102,105,108,101,110,97,109,101,115,44,32,116,104,101,32,102,105,108,101,115,32,97,114,101,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<91,114,101,97,100,44,32,98,105,110,97,114,121,93>>]},<<32,97,110,100,32>>,{code,[],[<<91,119,114,105,116,101,44,32,98,105,110,97,114,121,93>>]},<<32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,105,114,32,109,111,100,101,32,108,105,115,116,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,116,111,32,111,112,116,105,109,105,122,101,32,116,104,101,32,99,111,112,121,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,102,105,108,101,110,97,109,101,44,32,105,116,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<32,109,111,100,101,32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,32,109,111,100,101,32,108,105,115,116,32,98,101,102,111,114,101,32,116,104,101,32,99,111,112,121,44,32,97,110,100,32,99,108,111,115,101,100,32,119,104,101,110,32,100,111,110,101,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,102,105,108,101,110,97,109,101,44,32,105,116,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,109,111,100,101,32,112,114,101,112,101,110,100,101,100,32,116,111,32,116,104,101,32,109,111,100,101,32,108,105,115,116,32,98,101,102,111,114,101,32,116,104,101,32,99,111,112,121,44,32,97,110,100,32,99,108,111,115,101,100,32,119,104,101,110,32,100,111,110,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,67,111,112,105,101,100,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<66,121,116,101,115,67,111,112,105,101,100>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,116,104,97,116,32,119,97,115,32,99,111,112,105,101,100,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<66,121,116,101,67,111,117,110,116>>]},<<32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,32,111,110,32,116,104,101,32,115,111,117,114,99,101,46,32,73,102,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,102,97,105,108,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58,32,97,115,32,102,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,105,102,32,97,32,102,105,108,101,32,104,97,100,32,116,111,32,98,101,32,111,112,101,110,101,100,44,32,97,110,100,32,97,115,32,102,111,114,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{771,2},spec,{{copy,2},[{type,{771,11},bounded_fun,[{type,{771,11},'fun',[{type,{771,11},product,[{var,{771,12},'Source'},{var,{771,20},'Destination'}]},{type,{771,36},union,[{type,{771,36},tuple,[{atom,{771,37},ok},{var,{771,41},'BytesCopied'}]},{type,{771,56},tuple,[{atom,{771,57},error},{var,{771,64},'Reason'}]}]}]},[{type,{772,7},constraint,[{atom,{772,7},is_subtype},[{var,{772,7},'Source'},{type,{772,17},union,[{user_type,{772,17},io_device,[]},{var,{772,31},'Filename'},{type,{772,42},tuple,[{var,{772,43},'Filename'},{var,{772,53},'Modes'}]}]}]]},{type,{773,7},constraint,[{atom,{773,7},is_subtype},[{var,{773,7},'Destination'},{type,{773,22},union,[{user_type,{773,22},io_device,[]},{var,{773,36},'Filename'},{type,{773,47},tuple,[{var,{773,48},'Filename'},{var,{773,58},'Modes'}]}]}]]},{type,{774,7},constraint,[{atom,{774,7},is_subtype},[{var,{774,7},'Filename'},{user_type,{774,19},name_all,[]}]]},{type,{775,7},constraint,[{atom,{775,7},is_subtype},[{var,{775,7},'Modes'},{type,{775,16},list,[{user_type,{775,17},mode,[]}]}]]},{type,{776,7},constraint,[{atom,{776,7},is_subtype},[{var,{776,7},'BytesCopied'},{type,{776,22},non_neg_integer,[]}]]},{type,{777,7},constraint,[{atom,{777,7},is_subtype},[{var,{777,7},'Reason'},{type,{777,17},union,[{user_type,{777,17},posix,[]},{atom,{777,27},badarg},{atom,{777,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,48,55>>}},{{function,datasync,1},[{file,[102,105,108,101,46,101,114,108]},{location,725}],[<<100,97,116,97,115,121,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<69,110,115,117,114,101,115,32,116,104,97,116,32,97,110,121,32,98,117,102,102,101,114,115,32,107,101,112,116,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,40,110,111,116,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,73,110,32,109,97,110,121,32,119,97,121,115,32,105,116,32,114,101,115,101,109,98,108,101,115,32>>,{code,[],[<<102,115,121,110,99>>]},<<32,98,117,116,32,105,116,32,100,111,101,115,32,110,111,116,32,117,112,100,97,116,101,32,115,111,109,101,32,111,102,32,116,104,101,32,109,101,116,97,100,97,116,97,32,111,102,32,116,104,101,32,102,105,108,101,44,32,115,117,99,104,32,97,115,32,116,104,101,32,97,99,99,101,115,115,32,116,105,109,101,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]},{p,[],[<<65,112,112,108,105,99,97,116,105,111,110,115,32,116,104,97,116,32,97,99,99,101,115,115,32,100,97,116,97,98,97,115,101,115,32,111,114,32,108,111,103,32,102,105,108,101,115,32,111,102,116,101,110,32,119,114,105,116,101,32,97,32,116,105,110,121,32,100,97,116,97,32,102,114,97,103,109,101,110,116,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,111,110,101,32,108,105,110,101,32,105,110,32,97,32,108,111,103,32,102,105,108,101,41,32,97,110,100,32,116,104,101,110,32,99,97,108,108,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<32,105,109,109,101,100,105,97,116,101,108,121,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,116,104,101,32,119,114,105,116,116,101,110,32,100,97,116,97,32,105,115,32,112,104,121,115,105,99,97,108,108,121,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,104,97,114,100,32,100,105,115,107,46,32,85,110,102,111,114,116,117,110,97,116,101,108,121,44,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<32,97,108,119,97,121,115,32,105,110,105,116,105,97,116,101,115,32,116,119,111,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,115,58,32,111,110,101,32,102,111,114,32,116,104,101,32,110,101,119,108,121,32,119,114,105,116,116,101,110,32,100,97,116,97,32,97,110,100,32,97,110,111,116,104,101,114,32,111,110,101,32,116,111,32,117,112,100,97,116,101,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,105,109,101,32,115,116,111,114,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<46,32,73,102,32,116,104,101,32,109,111,100,105,102,105,99,97,116,105,111,110,32,116,105,109,101,32,105,115,32,110,111,116,32,97,32,112,97,114,116,32,111,102,32,116,104,101,32,116,114,97,110,115,97,99,116,105,111,110,32,99,111,110,99,101,112,116,44,32>>,{code,[],[<<102,100,97,116,97,115,121,110,99,40,41>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,97,118,111,105,100,32,117,110,110,101,99,101,115,115,97,114,121,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,100,105,115,107,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,115,46>>]},{p,[],[<<65,118,97,105,108,97,98,108,101,32,111,110,108,121,32,105,110,32,115,111,109,101,32,80,79,83,73,88,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,99,97,108,108,32,114,101,115,117,108,116,115,32,105,110,32,97,32,99,97,108,108,32,116,111,32>>,{code,[],[<<102,115,121,110,99,40,41>>]},<<44,32,111,114,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,105,110,32,115,121,115,116,101,109,115,32,110,111,116,32,112,114,111,118,105,100,105,110,103,32,116,104,101,32>>,{code,[],[<<102,100,97,116,97,115,121,110,99,40,41>>]},<<32,115,121,115,99,97,108,108,46>>]}]},#{signature => [{attribute,{725,2},spec,{{datasync,1},[{type,{725,15},bounded_fun,[{type,{725,15},'fun',[{type,{725,15},product,[{var,{725,16},'IoDevice'}]},{type,{725,29},union,[{atom,{725,29},ok},{type,{725,34},tuple,[{atom,{725,35},error},{var,{725,42},'Reason'}]}]}]},[{type,{726,7},constraint,[{atom,{726,7},is_subtype},[{var,{726,7},'IoDevice'},{user_type,{726,19},io_device,[]}]]},{type,{727,7},constraint,[{atom,{727,7},is_subtype},[{var,{727,7},'Reason'},{type,{727,17},union,[{user_type,{727,17},posix,[]},{atom,{727,27},badarg},{atom,{727,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,52,53>>,since => <<79,84,80,32,82,49,52,66>>}},{{function,del_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,250}],[<<100,101,108,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,100,101,108,101,116,101,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<68,105,114>>]},<<46,32,84,104,101,32,100,105,114,101,99,116,111,114,121,32,109,117,115,116,32,98,101,32,101,109,112,116,121,32,98,101,102,111,114,101,32,105,116,32,99,97,110,32,98,101,32,100,101,108,101,116,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,105,115,32,110,111,116,32,101,109,112,116,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<65,116,116,101,109,112,116,32,116,111,32,100,101,108,101,116,101,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{signature => [{attribute,{250,2},spec,{{del_dir,1},[{type,{250,14},bounded_fun,[{type,{250,14},'fun',[{type,{250,14},product,[{var,{250,15},'Dir'}]},{type,{250,23},union,[{atom,{250,23},ok},{type,{250,28},tuple,[{atom,{250,29},error},{var,{250,36},'Reason'}]}]}]},[{type,{251,7},constraint,[{atom,{251,7},is_subtype},[{var,{251,7},'Dir'},{user_type,{251,14},name_all,[]}]]},{type,{252,7},constraint,[{atom,{252,7},is_subtype},[{var,{252,7},'Reason'},{type,{252,17},union,[{user_type,{252,17},posix,[]},{atom,{252,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,51,54,56>>}},{{function,del_dir_r,1},[{file,[102,105,108,101,46,101,114,108]},{location,257}],[<<100,101,108,95,100,105,114,95,114,47,49>>],#{<<101,110>> => [{p,[],[<<68,101,108,101,116,101,115,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<70,105,108,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,105,108,101>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,105,116,115,32,99,111,110,116,101,110,116,115,32,105,115,32,102,105,114,115,116,32,114,101,99,117,114,115,105,118,101,108,121,32,100,101,108,101,116,101,100,46,32,82,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,107>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,111,110,32,99,111,109,112,108,101,116,101,100,32,119,105,116,104,111,117,116,32,101,114,114,111,114,115,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,112,111,115,105,120,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,111,114,32,100,101,108,101,116,105,110,103,32>>,{code,[],[<<70,105,108,101>>]},<<46,32,73,102,32,115,111,109,101,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32,117,110,100,101,114,32>>,{code,[],[<<70,105,108,101>>]},<<32,99,111,117,108,100,32,110,111,116,32,98,101,32,100,101,108,101,116,101,100,44,32>>,{code,[],[<<70,105,108,101>>]},<<32,99,97,110,110,111,116,32,98,101,32,100,101,108,101,116,101,100,32,97,115,32,105,116,32,105,115,32,110,111,110,45,101,109,112,116,121,44,32,97,110,100,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,101,120,105,115,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]}]}]},#{signature => [{attribute,{257,2},spec,{{del_dir_r,1},[{type,{257,16},bounded_fun,[{type,{257,16},'fun',[{type,{257,16},product,[{var,{257,17},'File'}]},{type,{257,26},union,[{atom,{257,26},ok},{type,{257,31},tuple,[{atom,{257,32},error},{var,{257,39},'Reason'}]}]}]},[{type,{258,7},constraint,[{atom,{258,7},is_subtype},[{var,{258,7},'File'},{user_type,{258,15},name_all,[]}]]},{type,{259,7},constraint,[{atom,{259,7},is_subtype},[{var,{259,7},'Reason'},{type,{259,17},union,[{user_type,{259,17},posix,[]},{atom,{259,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,48,52>>,since => <<79,84,80,32,50,51,46,48>>}},{{function,delete,2},[{file,[102,105,108,101,46,101,114,108]},{location,215}],[<<100,101,108,101,116,101,47,50>>],#{},#{signature => [{attribute,{215,2},spec,{{delete,2},[{type,{215,13},bounded_fun,[{type,{215,13},'fun',[{type,{215,13},product,[{var,{215,14},'Filename'},{var,{215,24},'Opts'}]},{type,{215,33},union,[{atom,{215,33},ok},{type,{215,38},tuple,[{atom,{215,39},error},{var,{215,46},'Reason'}]}]}]},[{type,{216,7},constraint,[{atom,{216,7},is_subtype},[{var,{216,7},'Filename'},{user_type,{216,19},name_all,[]}]]},{type,{217,7},constraint,[{atom,{217,7},is_subtype},[{var,{217,7},'Opts'},{type,{217,15},list,[{user_type,{217,16},delete_option,[]}]}]]},{type,{218,7},constraint,[{atom,{218,7},is_subtype},[{var,{218,7},'Reason'},{type,{218,17},union,[{user_type,{218,17},posix,[]},{atom,{218,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,50,54>>,equiv => {function,delete,1},since => <<79,84,80,32,50,52,46,48>>}},{{function,delete,1},[{file,[102,105,108,101,46,101,114,108]},{location,208}],[<<100,101,108,101,116,101,47,49>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<100,101,108,101,116,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<84,114,105,101,115,32,116,111,32,100,101,108,101,116,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,46,32,84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,105,110,32,112,97,114,116,105,99,117,108,97,114,32,100,117,114,105,110,103,32,116,104,101,32,101,97,114,108,121,32,98,111,111,116,32,115,116,97,103,101,32,119,104,101,110,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,121,101,116,32,114,101,103,105,115,116,101,114,101,100,44,32,116,111,32,115,116,105,108,108,32,98,101,32,97,98,108,101,32,116,111,32,100,101,108,101,116,101,32,108,111,99,97,108,32,102,105,108,101,115,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,116,104,101,32,102,105,108,101,32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,115,46>>]}]},{dt,[],[{code,[],[<<101,112,101,114,109>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,32,97,110,100,32,116,104,101,32,117,115,101,114,32,105,115,32,110,111,116,32,115,117,112,101,114,117,115,101,114,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,104,97,115,32,97,110,32,105,109,112,114,111,112,101,114,32,116,121,112,101,44,32,115,117,99,104,32,97,115,32,116,117,112,108,101,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,44,32,97,32,98,97,100,32,116,121,112,101,32,102,111,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,119,105,108,108,32,112,114,111,98,97,98,108,121,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,46>>]}]}]},#{signature => [{attribute,{208,2},spec,{{delete,1},[{type,{208,13},bounded_fun,[{type,{208,13},'fun',[{type,{208,13},product,[{var,{208,14},'Filename'}]},{type,{208,27},union,[{atom,{208,27},ok},{type,{208,32},tuple,[{atom,{208,33},error},{var,{208,40},'Reason'}]}]}]},[{type,{209,7},constraint,[{atom,{209,7},is_subtype},[{var,{209,7},'Filename'},{user_type,{209,19},name_all,[]}]]},{type,{210,7},constraint,[{atom,{210,7},is_subtype},[{var,{210,7},'Reason'},{type,{210,17},union,[{user_type,{210,17},posix,[]},{atom,{210,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,50,54>>,since => <<79,84,80,32,50,52,46,48>>}},{{function,eval,1},[{file,[102,105,108,101,46,101,114,108]},{location,1059}],[<<101,118,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,32,102,114,111,109,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,84,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,32,105,115,32,110,111,116,32,114,101,116,117,114,110,101,100,59,32,97,110,121,32,101,120,112,114,101,115,115,105,111,110,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,102,105,108,101,32,109,117,115,116,32,98,101,32,116,104,101,114,101,32,102,111,114,32,105,116,115,32,115,105,100,101,32,101,102,102,101,99,116,46,32,82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<111,107>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,84,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,44,32,117,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1059,2},spec,{{eval,1},[{type,{1059,11},bounded_fun,[{type,{1059,11},'fun',[{type,{1059,11},product,[{var,{1059,12},'Filename'}]},{type,{1059,25},union,[{atom,{1059,25},ok},{type,{1059,30},tuple,[{atom,{1059,31},error},{var,{1059,38},'Reason'}]}]}]},[{type,{1060,7},constraint,[{atom,{1060,7},is_subtype},[{var,{1060,7},'Filename'},{user_type,{1060,19},name_all,[]}]]},{type,{1061,7},constraint,[{atom,{1061,7},is_subtype},[{var,{1061,7},'Reason'},{type,{1061,17},union,[{user_type,{1061,17},posix,[]},{atom,{1061,27},badarg},{atom,{1061,36},terminated},{atom,{1061,49},system_limit},{type,{1062,17},tuple,[{ann_type,{1062,18},[{var,{1062,18},'Line'},{type,{1062,26},integer,[]}]},{ann_type,{1062,37},[{var,{1062,37},'Mod'},{type,{1062,44},module,[]}]},{ann_type,{1062,54},[{var,{1062,54},'Term'},{type,{1062,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,52,54,57>>}},{{function,eval,2},[{file,[102,105,108,101,46,101,114,108]},{location,1067}],[<<101,118,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<101,118,97,108,47,49>>]},<<44,32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,70,111,114,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,44,32,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1067,2},spec,{{eval,2},[{type,{1067,11},bounded_fun,[{type,{1067,11},'fun',[{type,{1067,11},product,[{var,{1067,12},'Filename'},{var,{1067,22},'Bindings'}]},{type,{1067,35},union,[{atom,{1067,35},ok},{type,{1067,40},tuple,[{atom,{1067,41},error},{var,{1067,48},'Reason'}]}]}]},[{type,{1068,7},constraint,[{atom,{1068,7},is_subtype},[{var,{1068,7},'Filename'},{user_type,{1068,19},name_all,[]}]]},{type,{1069,7},constraint,[{atom,{1069,7},is_subtype},[{var,{1069,7},'Bindings'},{remote_type,{1069,19},[{atom,{1069,19},erl_eval},{atom,{1069,28},binding_struct},[]]}]]},{type,{1070,7},constraint,[{atom,{1070,7},is_subtype},[{var,{1070,7},'Reason'},{type,{1070,17},union,[{user_type,{1070,17},posix,[]},{atom,{1070,27},badarg},{atom,{1070,36},terminated},{atom,{1070,49},system_limit},{type,{1071,17},tuple,[{ann_type,{1071,18},[{var,{1071,18},'Line'},{type,{1071,26},integer,[]}]},{ann_type,{1071,37},[{var,{1071,37},'Mod'},{type,{1071,44},module,[]}]},{ann_type,{1071,54},[{var,{1071,54},'Term'},{type,{1071,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,48,51>>}},{{function,format_error,1},[{file,[102,105,108,101,46,101,114,108]},{location,147}],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>],#{<<101,110>> => [{p,[],[<<71,105,118,101,110,32,116,104,101,32,101,114,114,111,114,32,114,101,97,115,111,110,32,114,101,116,117,114,110,101,100,32,98,121,32,97,110,121,32,102,117,110,99,116,105,111,110,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,114,101,116,117,114,110,115,32,97,32,100,101,115,99,114,105,112,116,105,118,101,32,115,116,114,105,110,103,32,111,102,32,116,104,101,32,101,114,114,111,114,32,105,110,32,69,110,103,108,105,115,104,46>>]}]},#{signature => [{attribute,{147,2},spec,{{format_error,1},[{type,{147,19},bounded_fun,[{type,{147,19},'fun',[{type,{147,19},product,[{var,{147,20},'Reason'}]},{var,{147,31},'Chars'}]},[{type,{148,7},constraint,[{atom,{148,7},is_subtype},[{var,{148,7},'Reason'},{type,{148,17},union,[{user_type,{148,17},posix,[]},{atom,{148,27},badarg},{atom,{148,36},terminated},{atom,{148,49},system_limit},{type,{149,17},tuple,[{ann_type,{149,18},[{var,{149,18},'Line'},{type,{149,26},integer,[]}]},{ann_type,{149,37},[{var,{149,37},'Mod'},{type,{149,44},module,[]}]},{ann_type,{149,54},[{var,{149,54},'Term'},{type,{149,62},term,[]}]}]}]}]]},{type,{150,7},constraint,[{atom,{150,7},is_subtype},[{var,{150,7},'Chars'},{type,{150,16},string,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,49,51>>}},{{function,get_cwd,0},[{file,[102,105,108,101,46,101,114,108]},{location,185}],[<<103,101,116,95,99,119,100,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,68,105,114,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,114,97,114,101,32,99,105,114,99,117,109,115,116,97,110,99,101,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,110,32,102,97,105,108,32,111,110,32,85,110,105,120,46,32,73,116,32,99,97,110,32,111,99,99,117,114,32,105,102,32,114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46>>]}]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,115,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,100,105,114,101,99,116,111,114,121,46>>]}]}]}]},#{signature => [{attribute,{185,2},spec,{{get_cwd,0},[{type,{185,14},bounded_fun,[{type,{185,14},'fun',[{type,{185,14},product,[]},{type,{185,20},union,[{type,{185,20},tuple,[{atom,{185,21},ok},{var,{185,25},'Dir'}]},{type,{185,32},tuple,[{atom,{185,33},error},{var,{185,40},'Reason'}]}]}]},[{type,{186,7},constraint,[{atom,{186,7},is_subtype},[{var,{186,7},'Dir'},{user_type,{186,14},filename,[]}]]},{type,{187,7},constraint,[{atom,{187,7},is_subtype},[{var,{187,7},'Reason'},{user_type,{187,17},posix,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,50,49>>}},{{function,get_cwd,1},[{file,[102,105,108,101,46,101,114,108]},{location,192}],[<<103,101,116,95,99,119,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,68,105,114,125>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,100,114,105,118,101,46>>]},{p,[],[{code,[],[<<68,114,105,118,101>>]},<<32,105,115,32,116,111,32,98,101,32,111,102,32,116,104,101,32,102,111,114,109,32,34>>,{code,[],[<<76,101,116,116,101,114>>]},{code,[],[<<58>>]},<<34,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,34,99,58,34,46>>]},{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,104,97,118,101,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,99,117,114,114,101,110,116,32,100,114,105,118,101,32,40,85,110,105,120,44,32,102,111,114,32,101,120,97,109,112,108,101,41,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<84,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,104,97,115,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,100,114,105,118,101,115,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,114,105,118,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,111,114,109,97,116,32,111,102,32>>,{code,[],[<<68,114,105,118,101>>]},<<32,105,115,32,105,110,118,97,108,105,100,46>>]}]}]}]},#{signature => [{attribute,{192,2},spec,{{get_cwd,1},[{type,{192,14},bounded_fun,[{type,{192,14},'fun',[{type,{192,14},product,[{var,{192,15},'Drive'}]},{type,{192,25},union,[{type,{192,25},tuple,[{atom,{192,26},ok},{var,{192,30},'Dir'}]},{type,{192,37},tuple,[{atom,{192,38},error},{var,{192,45},'Reason'}]}]}]},[{type,{193,7},constraint,[{atom,{193,7},is_subtype},[{var,{193,7},'Drive'},{type,{193,16},string,[]}]]},{type,{194,7},constraint,[{atom,{194,7},is_subtype},[{var,{194,7},'Dir'},{user_type,{194,14},filename,[]}]]},{type,{195,7},constraint,[{atom,{195,7},is_subtype},[{var,{195,7},'Reason'},{type,{195,17},union,[{user_type,{195,17},posix,[]},{atom,{195,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,52,51>>}},{{function,list_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,395}],[<<108,105,115,116,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<76,105,115,116,115,32,97,108,108,32,102,105,108,101,115,32,105,110,32,97,32,100,105,114,101,99,116,111,114,121,44,32>>,{em,[],[<<101,120,99,101,112,116>>]},<<32,102,105,108,101,115,32,119,105,116,104,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,115,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121,46,32,84,104,101,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,115,111,114,116,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32>>,{code,[],[<<68,105,114>>]},<<32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,70,105,108,101,110,97,109,101,125>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32>>,{code,[],[<<98,105,110,97,114,121,40,41>>]},<<32,119,105,116,104,32,99,104,97,114,97,99,116,101,114,115,32,99,111,100,101,100,32,105,110,32,73,83,79,32,76,97,116,105,110,45,49,32,97,110,100,32,116,104,101,32,86,77,32,119,97,115,32,115,116,97,114,116,101,100,32,119,105,116,104,32,112,97,114,97,109,101,116,101,114,32>>,{code,[],[<<43,102,110,117,101>>]},<<46>>]}]}]}]},#{signature => [{attribute,{395,2},spec,{{list_dir,1},[{type,{395,15},bounded_fun,[{type,{395,15},'fun',[{type,{395,15},product,[{var,{395,16},'Dir'}]},{type,{395,24},union,[{type,{395,24},tuple,[{atom,{395,25},ok},{var,{395,29},'Filenames'}]},{type,{395,42},tuple,[{atom,{395,43},error},{var,{395,50},'Reason'}]}]}]},[{type,{396,7},constraint,[{atom,{396,7},is_subtype},[{var,{396,7},'Dir'},{user_type,{396,14},name_all,[]}]]},{type,{397,7},constraint,[{atom,{397,7},is_subtype},[{var,{397,7},'Filenames'},{type,{397,20},list,[{user_type,{397,21},filename,[]}]}]]},{type,{398,7},constraint,[{atom,{398,7},is_subtype},[{var,{398,7},'Reason'},{type,{398,17},union,[{user_type,{398,17},posix,[]},{atom,{399,17},badarg},{type,{400,17},tuple,[{atom,{400,18},no_translation},{ann_type,{400,34},[{var,{400,34},'Filename'},{remote_type,{400,46},[{atom,{400,46},unicode},{atom,{400,54},latin1_binary},[]]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,53,55,52>>}},{{function,list_dir_all,1},[{file,[102,105,108,101,46,101,114,108]},{location,405}],[<<108,105,115,116,95,100,105,114,95,97,108,108,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<108,105,115,116,95,100,105,114,95,97,108,108>>}],[]},<<76,105,115,116,115,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,97,32,100,105,114,101,99,116,111,114,121,44,32,105,110,99,108,117,100,105,110,103,32,102,105,108,101,115,32,119,105,116,104,32,114,97,119,32,102,105,108,101,110,97,109,101,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,115,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,110,97,109,101,115>>]},<<32,105,115,32,97,32,108,105,115,116,32,111,102,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,116,104,101,32,102,105,108,101,115,32,105,110,32,116,104,101,32,100,105,114,101,99,116,111,114,121,46,32,84,104,101,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,115,111,114,116,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32>>,{code,[],[<<68,105,114>>]},<<32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]}]}]},#{signature => [{attribute,{405,2},spec,{{list_dir_all,1},[{type,{405,19},bounded_fun,[{type,{405,19},'fun',[{type,{405,19},product,[{var,{405,20},'Dir'}]},{type,{405,28},union,[{type,{405,28},tuple,[{atom,{405,29},ok},{var,{405,33},'Filenames'}]},{type,{405,46},tuple,[{atom,{405,47},error},{var,{405,54},'Reason'}]}]}]},[{type,{406,7},constraint,[{atom,{406,7},is_subtype},[{var,{406,7},'Dir'},{user_type,{406,14},name_all,[]}]]},{type,{407,7},constraint,[{atom,{407,7},is_subtype},[{var,{407,7},'Filenames'},{type,{407,20},list,[{user_type,{407,21},filename_all,[]}]}]]},{type,{408,7},constraint,[{atom,{408,7},is_subtype},[{var,{408,7},'Reason'},{type,{408,17},union,[{user_type,{408,17},posix,[]},{atom,{408,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,48,53>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,make_dir,1},[{file,[102,105,108,101,46,101,114,108]},{location,243}],[<<109,97,107,101,95,100,105,114,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,99,114,101,97,116,101,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<68,105,114>>]},<<46,32,77,105,115,115,105,110,103,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,99,114,101,97,116,101,100,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[<<65,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,100,32>>,{code,[],[<<68,105,114>>]},<<32,101,120,105,115,116,115,32,97,108,114,101,97,100,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{signature => [{attribute,{243,2},spec,{{make_dir,1},[{type,{243,15},bounded_fun,[{type,{243,15},'fun',[{type,{243,15},product,[{var,{243,16},'Dir'}]},{type,{243,24},union,[{atom,{243,24},ok},{type,{243,29},tuple,[{atom,{243,30},error},{var,{243,37},'Reason'}]}]}]},[{type,{244,7},constraint,[{atom,{244,7},is_subtype},[{var,{244,7},'Dir'},{user_type,{244,14},name_all,[]}]]},{type,{245,7},constraint,[{atom,{245,7},is_subtype},[{var,{245,7},'Reason'},{type,{245,17},union,[{user_type,{245,17},posix,[]},{atom,{245,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,51,48>>}},{{function,make_link,2},[{file,[102,105,108,101,46,101,114,108]},{location,421}],[<<109,97,107,101,95,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<77,97,107,101,115,32,97,32,104,97,114,100,32,108,105,110,107,32,102,114,111,109,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,116,111,32>>,{code,[],[<<78,101,119>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,108,105,110,107,115,32,40,85,110,105,120,32,97,110,100,32,87,105,110,100,111,119,115,41,46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,108,105,110,107,32,119,97,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,114,101,97,116,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32,108,105,110,107,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,114,32>>,{code,[],[<<78,101,119>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<78,101,119>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<72,97,114,100,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{signature => [{attribute,{421,2},spec,{{make_link,2},[{type,{421,16},bounded_fun,[{type,{421,16},'fun',[{type,{421,16},product,[{var,{421,17},'Existing'},{var,{421,27},'New'}]},{type,{421,35},union,[{atom,{421,35},ok},{type,{421,40},tuple,[{atom,{421,41},error},{var,{421,48},'Reason'}]}]}]},[{type,{422,7},constraint,[{atom,{422,7},is_subtype},[{var,{422,7},'Existing'},{user_type,{422,19},name_all,[]}]]},{type,{423,7},constraint,[{atom,{423,7},is_subtype},[{var,{423,7},'New'},{user_type,{423,14},name_all,[]}]]},{type,{424,7},constraint,[{atom,{424,7},is_subtype},[{var,{424,7},'Reason'},{type,{424,17},union,[{user_type,{424,17},posix,[]},{atom,{424,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,54,52>>}},{{function,make_symlink,2},[{file,[102,105,108,101,46,101,114,108]},{location,429}],[<<109,97,107,101,95,115,121,109,108,105,110,107,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32>>,{code,[],[<<78,101,119>>]},<<32,116,111,32,116,104,101,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,32,40,109,111,115,116,32,85,110,105,120,32,115,121,115,116,101,109,115,32,97,110,100,32,87,105,110,100,111,119,115,44,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,86,105,115,116,97,41,46,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,100,111,101,115,32,110,111,116,32,110,101,101,100,32,116,111,32,101,120,105,115,116,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,116,104,101,32,108,105,110,107,32,105,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,114,101,97,116,101,100,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<69,120,105,115,116,105,110,103>>]},<<32,111,114,32>>,{code,[],[<<78,101,119>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<78,101,119>>]},<<32,97,108,114,101,97,100,121,32,101,120,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]},{dt,[],[{code,[],[<<101,112,101,114,109>>]}]},{dd,[],[{p,[],[<<85,115,101,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,105,118,105,108,101,103,101,115,32,116,111,32,99,114,101,97,116,101,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,32,40>>,{code,[],[<<83,101,67,114,101,97,116,101,83,121,109,98,111,108,105,99,76,105,110,107,80,114,105,118,105,108,101,103,101>>]},<<32,111,110,32,87,105,110,100,111,119,115,41,46>>]}]}]}]},#{signature => [{attribute,{429,2},spec,{{make_symlink,2},[{type,{429,19},bounded_fun,[{type,{429,19},'fun',[{type,{429,19},product,[{var,{429,20},'Existing'},{var,{429,30},'New'}]},{type,{429,38},union,[{atom,{429,38},ok},{type,{429,43},tuple,[{atom,{429,44},error},{var,{429,51},'Reason'}]}]}]},[{type,{430,7},constraint,[{atom,{430,7},is_subtype},[{var,{430,7},'Existing'},{user_type,{430,19},name_all,[]}]]},{type,{431,7},constraint,[{atom,{431,7},is_subtype},[{var,{431,7},'New'},{user_type,{431,14},name_all,[]}]]},{type,{432,7},constraint,[{atom,{432,7},is_subtype},[{var,{432,7},'Reason'},{type,{432,17},union,[{user_type,{432,17},posix,[]},{atom,{432,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,54,57,51>>}},{{function,native_name_encoding,0},[{file,[102,105,108,101,46,101,114,108]},{location,136}],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>],#{<<101,110>> => [{p,[],[{a,[{id,<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103>>}],[]},<<82,101,116,117,114,110,115,32,116,104,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,109,111,100,101,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32,115,121,115,116,101,109,32,116,114,97,110,115,108,97,116,101,115,32,110,111,32,102,105,108,101,110,97,109,101,115,46,32,73,102,32,105,116,32,105,115,32>>,{code,[],[<<117,116,102,56>>]},<<44,32,102,105,108,101,110,97,109,101,115,32,97,114,101,32,99,111,110,118,101,114,116,101,100,32,98,97,99,107,32,97,110,100,32,102,111,114,116,104,32,116,111,32,116,104,101,32,110,97,116,105,118,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,32,40,117,115,117,97,108,108,121,32,85,84,70,45,56,44,32,98,117,116,32,85,84,70,45,49,54,32,111,110,32,87,105,110,100,111,119,115,41,46>>]}]},#{signature => [{attribute,{136,2},spec,{{native_name_encoding,0},[{type,{136,27},'fun',[{type,{136,27},product,[]},{type,{136,33},union,[{atom,{136,33},latin1},{atom,{136,42},utf8}]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,55,50,57>>,since => <<79,84,80,32,82,49,52,66,48,49>>}},{{function,open,2},[{file,[102,105,108,101,46,101,114,108]},{location,504}],[<<111,112,101,110,47,50>>],#{<<101,110>> => [{p,[],[<<79,112,101,110,115,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101>>]},<<32,105,110,32,116,104,101,32,109,111,100,101,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32>>,{code,[],[<<77,111,100,101,115>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,99,111,110,116,97,105,110,32,111,110,101,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<114,101,97,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,44,32,119,104,105,99,104,32,109,117,115,116,32,101,120,105,115,116,44,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<119,114,105,116,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,116,104,101,32,102,105,108,101,32,101,120,105,115,116,115,32,97,110,100,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,105,115,32,110,111,116,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<44,32,116,104,101,32,102,105,108,101,32,105,115,32,116,114,117,110,99,97,116,101,100,46>>]}]},{dt,[],[{code,[],[<<97,112,112,101,110,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,69,118,101,114,121,32,119,114,105,116,101,32,111,112,101,114,97,116,105,111,110,32,116,111,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<97,112,112,101,110,100>>]},<<32,116,97,107,101,115,32,112,108,97,99,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,120,99,108,117,115,105,118,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46,32,73,116,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,116,104,101,32,102,105,108,101,32,101,120,105,115,116,115,44,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,101,120,105,115,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,100,111,101,115,32,110,111,116,32,103,117,97,114,97,110,116,101,101,32,101,120,99,108,117,115,105,118,101,110,101,115,115,32,111,110,32,102,105,108,101,32,115,121,115,116,101,109,115,32,110,111,116,32,115,117,112,112,111,114,116,105,110,103,32>>,{code,[],[<<79,95,69,88,67,76>>]},<<32,112,114,111,112,101,114,108,121,44,32,115,117,99,104,32,97,115,32,78,70,83,46,32,68,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,116,104,105,115,32,111,112,116,105,111,110,32,117,110,108,101,115,115,32,121,111,117,32,107,110,111,119,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,115,117,112,112,111,114,116,115,32,105,116,32,40,105,110,32,103,101,110,101,114,97,108,44,32,108,111,99,97,108,32,102,105,108,101,32,115,121,115,116,101,109,115,32,97,114,101,32,115,97,102,101,41,46>>]}]}]},{dt,[],[{code,[],[<<114,97,119>>]}]},{dd,[],[{p,[],[{a,[{id,<<114,97,119>>}],[]},<<65,108,108,111,119,115,32,102,97,115,116,101,114,32,97,99,99,101,115,115,32,116,111,32,97,32,102,105,108,101,44,32,97,115,32,110,111,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,105,115,32,110,101,101,100,101,100,32,116,111,32,104,97,110,100,108,101,32,116,104,101,32,102,105,108,101,46,32,72,111,119,101,118,101,114,44,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32,116,104,105,115,32,119,97,121,32,104,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,108,105,109,105,116,97,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32>>,{code,[],[<<105,111>>]},<<32,109,111,100,117,108,101,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,44,32,97,115,32,116,104,101,121,32,99,97,110,32,111,110,108,121,32,116,97,108,107,32,116,111,32,97,110,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,46,32,73,110,115,116,101,97,100,44,32,117,115,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<46>>]}]},{li,[],[{p,[],[<<69,115,112,101,99,105,97,108,108,121,32,105,102,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,105,115,32,116,111,32,98,101,32,117,115,101,100,32,111,110,32,97,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,44,32,105,116,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,116,111,32,99,111,109,98,105,110,101,32,116,104,105,115,32,111,112,116,105,111,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,97,115,32,108,105,110,101,45,111,114,105,101,110,116,101,100,32,73,47,79,32,105,115,32,105,110,101,102,102,105,99,105,101,110,116,32,119,105,116,104,111,117,116,32,98,117,102,102,101,114,105,110,103,46>>]}]},{li,[],[{p,[],[<<79,110,108,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,112,101,110,101,100,32,116,104,101,32,102,105,108,101,32,99,97,110,32,117,115,101,32,105,116,46>>]}]},{li,[],[{p,[],[<<65,32,114,101,109,111,116,101,32,69,114,108,97,110,103,32,102,105,108,101,32,115,101,114,118,101,114,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,46,32,84,104,101,32,99,111,109,112,117,116,101,114,32,111,110,32,119,104,105,99,104,32,116,104,101,32,69,114,108,97,110,103,32,110,111,100,101,32,105,115,32,114,117,110,110,105,110,103,32,109,117,115,116,32,104,97,118,101,32,97,99,99,101,115,115,32,116,111,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,40,100,105,114,101,99,116,108,121,32,111,114,32,116,104,114,111,117,103,104,32,78,70,83,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,116,104,101,32,102,105,108,101,32,114,101,116,117,114,110,32,98,105,110,97,114,105,101,115,32,114,97,116,104,101,114,32,116,104,97,110,32,108,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<123,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,83,105,122,101,44,32,68,101,108,97,121,125>>]}]},{dd,[],[{p,[],[<<68,97,116,97,32,105,110,32,115,117,98,115,101,113,117,101,110,116,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,105,115,32,98,117,102,102,101,114,101,100,32,117,110,116,105,108,32,97,116,32,108,101,97,115,116,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,32,97,114,101,32,98,117,102,102,101,114,101,100,44,32,111,114,32,117,110,116,105,108,32,116,104,101,32,111,108,100,101,115,116,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32>>,{code,[],[<<68,101,108,97,121>>]},<<32,109,105,108,108,105,115,101,99,111,110,100,115,32,111,108,100,46,32,84,104,101,110,32,97,108,108,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32,119,114,105,116,116,101,110,32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,46,32,84,104,101,32,98,117,102,102,101,114,101,100,32,100,97,116,97,32,105,115,32,97,108,115,111,32,102,108,117,115,104,101,100,32,98,101,102,111,114,101,32,115,111,109,101,32,111,116,104,101,114,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,32,116,104,97,110,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,105,115,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<84,104,101,32,112,117,114,112,111,115,101,32,111,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,116,111,32,105,110,99,114,101,97,115,101,32,112,101,114,102,111,114,109,97,110,99,101,32,98,121,32,114,101,100,117,99,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,46,32,84,104,117,115,44,32,116,104,101,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,109,117,115,116,32,98,101,32,102,111,114,32,115,105,122,101,115,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<44,32,97,110,100,32,110,111,116,32,105,110,116,101,114,115,112,101,114,115,101,100,32,98,121,32,116,111,111,32,109,97,110,121,32,111,116,104,101,114,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,115,46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,117,115,101,100,44,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,32,99,97,110,32,112,114,101,109,97,116,117,114,101,108,121,32,98,101,32,114,101,112,111,114,116,101,100,32,97,115,32,115,117,99,99,101,115,115,102,117,108,44,32,97,110,100,32,105,102,32,97,32,119,114,105,116,101,32,101,114,114,111,114,32,111,99,99,117,114,115,44,32,116,104,101,32,101,114,114,111,114,32,105,115,32,114,101,112,111,114,116,101,100,32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,110,101,120,116,32,102,105,108,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,110,111,116,32,101,120,101,99,117,116,101,100,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32>>,{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]},<<32,105,115,32,117,115,101,100,44,32,97,102,116,101,114,32,97,32,110,117,109,98,101,114,32,111,102,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,99,97,108,108,115,44,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,99,97,110,32,114,101,116,117,114,110,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,115,112,99,125>>]},<<44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,116,32,101,110,111,117,103,104,32,115,112,97,99,101,32,111,110,32,116,104,101,32,100,105,115,99,32,102,111,114,32,112,114,101,118,105,111,117,115,108,121,32,119,114,105,116,116,101,110,32,100,97,116,97,46,32>>,{code,[],[<<99,108,111,115,101,47,49>>]},<<32,109,117,115,116,32,112,114,111,98,97,98,108,121,32,98,101,32,99,97,108,108,101,100,32,97,103,97,105,110,44,32,97,115,32,116,104,101,32,102,105,108,101,32,105,115,32,115,116,105,108,108,32,111,112,101,110,46>>]}]},{dt,[],[{code,[],[<<100,101,108,97,121,101,100,95,119,114,105,116,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,100,101,108,97,121,101,100,95,119,114,105,116,101,44,32,83,105,122,101,44,32,68,101,108,97,121,125>>]},<<32,119,105,116,104,32,114,101,97,115,111,110,97,98,108,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<83,105,122,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,108,97,121>>]},<<32,40,114,111,117,103,104,108,121,32,115,111,109,101,32,54,52,32,75,66,44,32,50,32,115,101,99,111,110,100,115,41,46>>]}]},{dt,[],[{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]}]},{dd,[],[{p,[],[<<65,99,116,105,118,97,116,101,115,32,114,101,97,100,32,100,97,116,97,32,98,117,102,102,101,114,105,110,103,46,32,73,102,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,32,97,114,101,32,102,111,114,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,44,32,114,101,97,100,32,111,112,101,114,97,116,105,111,110,115,32,116,111,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,97,114,101,32,115,116,105,108,108,32,112,101,114,102,111,114,109,101,100,32,102,111,114,32,98,108,111,99,107,115,32,111,102,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,46,32,84,104,101,32,101,120,116,114,97,32,100,97,116,97,32,105,115,32,98,117,102,102,101,114,101,100,32,97,110,100,32,114,101,116,117,114,110,101,100,32,105,110,32,115,117,98,115,101,113,117,101,110,116,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,44,32,103,105,118,105,110,103,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,103,97,105,110,32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,99,97,108,108,115,32,105,115,32,114,101,100,117,99,101,100,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]},<<32,98,117,102,102,101,114,32,105,115,32,97,108,115,111,32,104,105,103,104,108,121,32,117,115,101,100,32,98,121,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,44,32,116,104,101,114,101,102,111,114,101,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,40,102,111,114,32,112,101,114,102,111,114,109,97,110,99,101,32,114,101,97,115,111,110,115,41,32,119,104,101,110,32,97,99,99,101,115,115,105,110,103,32,114,97,119,32,102,105,108,101,115,32,117,115,105,110,103,32,116,104,97,116,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,99,97,108,108,115,32,97,114,101,32,102,111,114,32,115,105,122,101,115,32,110,111,116,32,115,105,103,110,105,102,105,99,97,110,116,108,121,32,108,101,115,115,32,116,104,97,110,44,32,111,114,32,101,118,101,110,32,103,114,101,97,116,101,114,32,116,104,97,110,32>>,{code,[],[<<83,105,122,101>>]},<<32,98,121,116,101,115,44,32,110,111,32,112,101,114,102,111,114,109,97,110,99,101,32,103,97,105,110,32,99,97,110,32,98,101,32,101,120,112,101,99,116,101,100,46>>]}]},{dt,[],[{code,[],[<<114,101,97,100,95,97,104,101,97,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,119,105,116,104,32,97,32,114,101,97,115,111,110,97,98,108,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32>>,{code,[],[<<83,105,122,101>>]},<<32,40,114,111,117,103,104,108,121,32,115,111,109,101,32,54,52,32,75,66,41,46>>]}]},{dt,[],[{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,103,122,105,112,32,99,111,109,112,114,101,115,115,101,100,32,102,105,108,101,115,46,32,79,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100>>]},<<32,109,117,115,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<32,111,114,32>>,{code,[],[<<119,114,105,116,101>>]},<<44,32,98,117,116,32,110,111,116,32,98,111,116,104,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,115,105,122,101,32,111,98,116,97,105,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]}]},<<32,100,111,101,115,32,112,114,111,98,97,98,108,121,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,97,100,32,102,114,111,109,32,97,32,99,111,109,112,114,101,115,115,101,100,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<99,111,109,112,114,101,115,115,101,100,95,111,110,101>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,111,110,101,32,109,101,109,98,101,114,32,111,102,32,97,32,103,122,105,112,32,99,111,109,112,114,101,115,115,101,100,32,102,105,108,101,46,32,79,112,116,105,111,110,32>>,{code,[],[<<99,111,109,112,114,101,115,115,101,100,95,111,110,101>>]},<<32,99,97,110,32,111,110,108,121,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32>>,{code,[],[<<114,101,97,100>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,110,99,111,100,105,110,103,44,32,69,110,99,111,100,105,110,103,125>>]}]},{dd,[],[{p,[],[<<77,97,107,101,115,32,116,104,101,32,102,105,108,101,32,112,101,114,102,111,114,109,32,97,117,116,111,109,97,116,105,99,32,116,114,97,110,115,108,97,116,105,111,110,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,97,110,100,32,102,114,111,109,32,97,32,115,112,101,99,105,102,105,99,32,40,85,110,105,99,111,100,101,41,32,101,110,99,111,100,105,110,103,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,100,97,116,97,32,115,117,112,112,108,105,101,100,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,111,114,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,115,116,105,108,108,32,105,115,32,98,121,116,101,45,111,114,105,101,110,116,101,100,59,32,116,104,105,115,32,111,112,116,105,111,110,32,100,101,110,111,116,101,115,32,111,110,108,121,32,104,111,119,32,100,97,116,97,32,105,115,32,115,116,111,114,101,100,32,105,110,32,116,104,101,32,100,105,115,107,32,102,105,108,101,46>>]},{p,[],[<<68,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,101,110,99,111,100,105,110,103,44,32,100,105,102,102,101,114,101,110,116,32,109,101,116,104,111,100,115,32,111,102,32,114,101,97,100,105,110,103,32,97,110,100,32,119,114,105,116,105,110,103,32,100,97,116,97,32,105,115,32,112,114,101,102,101,114,114,101,100,46,32,84,104,101,32,100,101,102,97,117,108,116,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,105,109,112,108,105,101,115,32,117,115,105,110,103,32,116,104,105,115,32,109,111,100,117,108,101,32,40>>,{code,[],[<<102,105,108,101>>]},<<41,32,102,111,114,32,114,101,97,100,105,110,103,32,97,110,100,32,119,114,105,116,105,110,103,32,100,97,116,97,32,97,115,32,116,104,101,32,105,110,116,101,114,102,97,99,101,115,32,112,114,111,118,105,100,101,100,32,104,101,114,101,32,119,111,114,107,32,119,105,116,104,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,46,32,85,115,105,110,103,32,111,116,104,101,114,32,40,85,110,105,99,111,100,101,41,32,101,110,99,111,100,105,110,103,115,32,109,97,107,101,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,102,117,110,99,116,105,111,110,115,32>>,{code,[],[<<103,101,116,95,99,104,97,114,115>>]},<<44,32>>,{code,[],[<<103,101,116,95,108,105,110,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<112,117,116,95,99,104,97,114,115>>]},<<32,109,111,114,101,32,115,117,105,116,97,98,108,101,44,32,97,115,32,116,104,101,121,32,99,97,110,32,119,111,114,107,32,119,105,116,104,32,116,104,101,32,102,117,108,108,32,85,110,105,99,111,100,101,32,114,97,110,103,101,46>>]},{p,[],[<<73,102,32,100,97,116,97,32,105,115,32,115,101,110,116,32,116,111,32,97,110,32>>,{code,[],[<<105,111,95,100,101,118,105,99,101,40,41>>]},<<32,105,110,32,97,32,102,111,114,109,97,116,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,99,111,110,118,101,114,116,101,100,32,116,111,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,101,110,99,111,100,105,110,103,44,32,111,114,32,105,102,32,100,97,116,97,32,105,115,32,114,101,97,100,32,98,121,32,97,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,114,101,116,117,114,110,115,32,100,97,116,97,32,105,110,32,97,32,102,111,114,109,97,116,32,116,104,97,116,32,99,97,110,110,111,116,32,99,111,112,101,32,119,105,116,104,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,114,97,110,103,101,32,111,102,32,116,104,101,32,100,97,116,97,44,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,97,110,100,32,116,104,101,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,46>>]},{p,[],[<<65,108,108,111,119,101,100,32,118,97,108,117,101,115,32,102,111,114,32>>,{code,[],[<<69,110,99,111,100,105,110,103>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<108,97,116,105,110,49>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,101,110,99,111,100,105,110,103,46,32,66,121,116,101,115,32,115,117,112,112,108,105,101,100,32,116,111,32,116,104,101,32,102,105,108,101,44,32,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,47,50>>]}]},<<32,97,114,101,32,119,114,105,116,116,101,110,32,34,97,115,32,105,115,34,32,111,110,32,116,104,101,32,102,105,108,101,46,32,76,105,107,101,119,105,115,101,44,32,98,121,116,101,115,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,44,32,116,104,97,116,32,105,115,44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,114,101,32,114,101,116,117,114,110,101,100,32,34,97,115,32,105,115,34,46,32,73,102,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,117,115,101,100,32,102,111,114,32,119,114,105,116,105,110,103,44,32,116,104,101,32,102,105,108,101,32,99,97,110,32,111,110,108,121,32,99,111,112,101,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,117,112,32,116,111,32,99,111,100,101,32,112,111,105,110,116,32,50,53,53,32,40,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,41,46>>]}]},{dt,[],[{code,[],[<<117,110,105,99,111,100,101,32,111,114,32,117,116,102,56>>]}]},{dd,[],[{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,97,114,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,97,110,100,32,102,114,111,109,32,85,84,70,45,56,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,116,104,101,121,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,111,114,32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46,32,65,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32,116,104,105,115,32,119,97,121,32,99,97,110,32,98,101,32,114,101,97,100,97,98,108,101,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32,97,115,32,108,111,110,103,32,97,115,32,110,111,32,100,97,116,97,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,102,105,108,101,32,108,105,101,115,32,98,101,121,111,110,100,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,32,40,48,46,46,50,53,53,41,44,32,98,117,116,32,102,97,105,108,117,114,101,32,111,99,99,117,114,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,85,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,98,101,121,111,110,100,32,116,104,97,116,32,114,97,110,103,101,46,32,84,104,101,32,102,105,108,101,32,105,115,32,98,101,115,116,32,114,101,97,100,32,119,105,116,104,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,97,119,97,114,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<46>>]},{p,[],[<<66,121,116,101,115,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,102,105,108,101,32,98,121,32,97,110,121,32,109,101,97,110,115,32,97,114,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,85,84,70,45,56,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,98,101,105,110,103,32,115,116,111,114,101,100,32,111,110,32,116,104,101,32,100,105,115,107,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<117,116,102,49,54,32,111,114,32,123,117,116,102,49,54,44,98,105,103,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,98,105,103,32,101,110,100,105,97,110,32,85,84,70,45,49,54,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<123,117,116,102,49,54,44,108,105,116,116,108,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,108,105,116,116,108,101,32,101,110,100,105,97,110,32,85,84,70,45,49,54,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<117,116,102,51,50,32,111,114,32,123,117,116,102,51,50,44,98,105,103,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,98,105,103,32,101,110,100,105,97,110,32,85,84,70,45,51,50,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]},{dt,[],[{code,[],[<<123,117,116,102,51,50,44,108,105,116,116,108,101,125>>]}]},{dd,[],[{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,98,117,116,32,116,114,97,110,115,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,116,111,32,97,110,100,32,102,114,111,109,32,108,105,116,116,108,101,32,101,110,100,105,97,110,32,85,84,70,45,51,50,32,105,110,115,116,101,97,100,32,111,102,32,85,84,70,45,56,46>>]}]}]},{p,[],[<<84,104,101,32,69,110,99,111,100,105,110,103,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,102,111,114,32,97,32,102,105,108,101,32,34,111,110,32,116,104,101,32,102,108,121,34,32,98,121,32,117,115,105,110,103,32,102,117,110,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111,35,115,101,116,111,112,116,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,111,58,115,101,116,111,112,116,115,47,50>>]}]},<<46,32,83,111,32,97,32,102,105,108,101,32,99,97,110,32,98,101,32,97,110,97,108,121,122,101,100,32,105,110,32,108,97,116,105,110,49,32,101,110,99,111,100,105,110,103,32,102,111,114,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,66,79,77,44,32,112,111,115,105,116,105,111,110,101,100,32,98,101,121,111,110,100,32,116,104,101,32,66,79,77,32,97,110,100,32,116,104,101,110,32,98,101,32,115,101,116,32,102,111,114,32,116,104,101,32,114,105,103,104,116,32,101,110,99,111,100,105,110,103,32,98,101,102,111,114,101,32,102,117,114,116,104,101,114,32,114,101,97,100,105,110,103,46,32,70,111,114,32,102,117,110,99,116,105,111,110,115,32,105,100,101,110,116,105,102,121,105,110,103,32,66,79,77,115,44,32,115,101,101,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<117,110,105,99,111,100,101,40,51,41>>]}]},<<46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,115,46>>]}]},{dt,[],[{code,[],[<<114,97,109>>]}]},{dd,[],[{p,[],[{code,[],[<<70,105,108,101>>]},<<32,109,117,115,116,32,98,101,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<46,32,82,101,116,117,114,110,115,32,97,110,32>>,{code,[],[<<102,100,40,41>>]},<<44,32,119,104,105,99,104,32,108,101,116,115,32,109,111,100,117,108,101,32>>,{code,[],[<<102,105,108,101>>]},<<32,111,112,101,114,97,116,101,32,111,110,32,116,104,101,32,100,97,116,97,32,105,110,45,109,101,109,111,114,121,32,97,115,32,105,102,32,105,116,32,105,115,32,97,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<115,121,110,99>>]}]},{dd,[],[{p,[],[<<79,110,32,112,108,97,116,102,111,114,109,115,32,115,117,112,112,111,114,116,105,110,103,32,105,116,44,32,101,110,97,98,108,101,115,32,116,104,101,32,80,79,83,73,88,32>>,{code,[],[<<79,95,83,89,78,67>>]},<<32,115,121,110,99,104,114,111,110,111,117,115,32,73,47,79,32,102,108,97,103,32,111,114,32,105,116,115,32,112,108,97,116,102,111,114,109,45,100,101,112,101,110,100,101,110,116,32,101,113,117,105,118,97,108,101,110,116,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<70,73,76,69,95,70,76,65,71,95,87,82,73,84,69,95,84,72,82,79,85,71,72>>]},<<32,111,110,32,87,105,110,100,111,119,115,41,32,115,111,32,116,104,97,116,32,119,114,105,116,101,115,32,116,111,32,116,104,101,32,102,105,108,101,32,98,108,111,99,107,32,117,110,116,105,108,32,116,104,101,32,100,97,116,97,32,105,115,32,112,104,121,115,105,99,97,108,108,121,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,72,111,119,101,118,101,114,44,32,98,101,32,97,119,97,114,101,32,116,104,97,116,32,116,104,101,32,101,120,97,99,116,32,115,101,109,97,110,116,105,99,115,32,111,102,32,116,104,105,115,32,102,108,97,103,32,100,105,102,102,101,114,32,102,114,111,109,32,112,108,97,116,102,111,114,109,32,116,111,32,112,108,97,116,102,111,114,109,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,110,111,110,101,32,111,102,32,76,105,110,117,120,32,111,114,32,87,105,110,100,111,119,115,32,103,117,97,114,97,110,116,101,101,115,32,116,104,97,116,32,97,108,108,32,102,105,108,101,32,109,101,116,97,100,97,116,97,32,97,114,101,32,97,108,115,111,32,119,114,105,116,116,101,110,32,98,101,102,111,114,101,32,116,104,101,32,99,97,108,108,32,114,101,116,117,114,110,115,46,32,70,111,114,32,112,114,101,99,105,115,101,32,115,101,109,97,110,116,105,99,115,44,32,99,104,101,99,107,32,116,104,101,32,100,101,116,97,105,108,115,32,111,102,32,121,111,117,114,32,112,108,97,116,102,111,114,109,32,100,111,99,117,109,101,110,116,97,116,105,111,110,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,119,105,116,104,32,110,111,32,115,117,112,112,111,114,116,32,102,111,114,32,80,79,83,73,88,32>>,{code,[],[<<79,95,83,89,78,67>>]},<<32,111,114,32,101,113,117,105,118,97,108,101,110,116,44,32,117,115,101,32,111,102,32,116,104,101,32>>,{code,[],[<<115,121,110,99>>]},<<32,102,108,97,103,32,99,97,117,115,101,115,32>>,{code,[],[<<111,112,101,110>>]},<<32,116,111,32,114,101,116,117,114,110,32>>,{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,116,115,117,112,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<100,105,114,101,99,116,111,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,111,119,115,32>>,{code,[],[<<111,112,101,110>>]},<<32,116,111,32,119,111,114,107,32,111,110,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]}]},{p,[],[<<82,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,73,111,68,101,118,105,99,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,109,111,100,101,46,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,46>>]}]}]},{p,[],[{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,114,101,97,108,108,121,32,116,104,101,32,112,105,100,32,111,102,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,104,97,110,100,108,101,115,32,116,104,101,32,102,105,108,101,46,32,84,104,105,115,32,112,114,111,99,101,115,115,32,109,111,110,105,116,111,114,115,32,116,104,101,32,112,114,111,99,101,115,115,32,116,104,97,116,32,111,114,105,103,105,110,97,108,108,121,32,111,112,101,110,101,100,32,116,104,101,32,102,105,108,101,32,40,116,104,101,32,111,119,110,101,114,32,112,114,111,99,101,115,115,41,46,32,73,102,32,116,104,101,32,111,119,110,101,114,32,112,114,111,99,101,115,115,32,116,101,114,109,105,110,97,116,101,115,44,32,116,104,101,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,105,116,115,101,108,102,32,116,101,114,109,105,110,97,116,101,115,32,116,111,111,46,32,65,110,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,114,101,116,117,114,110,101,100,32,102,114,111,109,32,116,104,105,115,32,99,97,108,108,32,99,97,110,32,98,101,32,117,115,101,100,32,97,115,32,97,110,32,97,114,103,117,109,101,110,116,32,116,111,32,116,104,101,32,73,47,79,32,102,117,110,99,116,105,111,110,115,32,40,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<41,46>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<87,104,105,108,101,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,111,112,101,110,32,97,110,121,32,102,105,108,101,44,32,119,101,32,114,101,99,111,109,109,101,110,100,32,97,103,97,105,110,115,116,32,117,115,105,110,103,32,105,116,32,102,111,114,32,78,70,83,45,109,111,117,110,116,101,100,32,102,105,108,101,115,44,32,70,73,70,79,115,44,32,100,101,118,105,99,101,115,44,32,111,114,32,115,105,109,105,108,97,114,32,115,105,110,99,101,32,116,104,101,121,32,99,97,110,32,99,97,117,115,101,32,73,79,32,116,104,114,101,97,100,115,32,116,111,32,104,97,110,103,32,102,111,114,101,118,101,114,46>>]},{p,[],[<<73,102,32,121,111,117,114,32,97,112,112,108,105,99,97,116,105,111,110,32,110,101,101,100,115,32,116,111,32,105,110,116,101,114,97,99,116,32,119,105,116,104,32,116,104,101,115,101,32,107,105,110,100,115,32,111,102,32,102,105,108,101,115,32,119,101,32,114,101,99,111,109,109,101,110,100,32,98,114,101,97,107,105,110,103,32,111,117,116,32,116,104,111,115,101,32,112,97,114,116,115,32,116,111,32,97,32,112,111,114,116,32,112,114,111,103,114,97,109,32,105,110,115,116,101,97,100,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,112,114,101,118,105,111,117,115,32,118,101,114,115,105,111,110,115,32,111,102,32>>,{code,[],[<<102,105,108,101>>]},<<44,32,109,111,100,101,115,32,119,101,114,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,111,110,101,32,111,102,32,116,104,101,32,97,116,111,109,115,32>>,{code,[],[<<114,101,97,100>>]},<<44,32>>,{code,[],[<<119,114,105,116,101>>]},<<44,32,111,114,32>>,{code,[],[<<114,101,97,100,95,119,114,105,116,101>>]},<<32,105,110,115,116,101,97,100,32,111,102,32,97,32,108,105,115,116,46,32,84,104,105,115,32,105,115,32,115,116,105,108,108,32,97,108,108,111,119,101,100,32,102,111,114,32,114,101,97,115,111,110,115,32,111,102,32,98,97,99,107,119,97,114,100,115,32,99,111,109,112,97,116,105,98,105,108,105,116,121,44,32,98,117,116,32,105,115,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,32,102,111,114,32,110,101,119,32,99,111,100,101,46,32,65,108,115,111,32,110,111,116,101,32,116,104,97,116,32>>,{code,[],[<<114,101,97,100,95,119,114,105,116,101>>]},<<32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,105,110,32,97,32,109,111,100,101,32,108,105,115,116,46>>]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,114,101,97,100,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,44,32,111,114,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,116,115,101,108,102,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,32,105,102,32>>,{code,[],[<<100,105,114,101,99,116,111,114,121>>]},<<32,109,111,100,101,32,119,97,115,32,115,112,101,99,105,102,105,101,100,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,32,40,105,102,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,97,99,99,101,115,115,32,119,97,115,32,115,112,101,99,105,102,105,101,100,41,46>>]}]}]}]},#{signature => [{attribute,{504,2},spec,{{open,2},[{type,{504,11},bounded_fun,[{type,{504,11},'fun',[{type,{504,11},product,[{var,{504,12},'File'},{var,{504,18},'Modes'}]},{type,{504,28},union,[{type,{504,28},tuple,[{atom,{504,29},ok},{var,{504,33},'IoDevice'}]},{type,{504,45},tuple,[{atom,{504,46},error},{var,{504,53},'Reason'}]}]}]},[{type,{505,7},constraint,[{atom,{505,7},is_subtype},[{var,{505,7},'File'},{type,{505,15},union,[{var,{505,15},'Filename'},{type,{505,26},iodata,[]}]}]]},{type,{506,7},constraint,[{atom,{506,7},is_subtype},[{var,{506,7},'Filename'},{user_type,{506,19},name_all,[]}]]},{type,{507,7},constraint,[{atom,{507,7},is_subtype},[{var,{507,7},'Modes'},{type,{507,16},list,[{type,{507,17},union,[{user_type,{507,17},mode,[]},{atom,{507,26},ram},{atom,{507,32},directory}]}]}]]},{type,{508,7},constraint,[{atom,{508,7},is_subtype},[{var,{508,7},'IoDevice'},{user_type,{508,19},io_device,[]}]]},{type,{509,7},constraint,[{atom,{509,7},is_subtype},[{var,{509,7},'Reason'},{type,{509,17},union,[{user_type,{509,17},posix,[]},{atom,{509,27},badarg},{atom,{509,36},system_limit}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,55,52,49>>}},{{function,path_consult,2},[{file,[102,105,108,101,46,101,114,108]},{location,1035}],[<<112,97,116,104,95,99,111,110,115,117,108,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,69,114,108,97,110,103,32,116,101,114,109,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,84,101,114,109,115,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,115,117,99,99,101,115,115,102,117,108,108,121,32,114,101,97,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,116,101,114,109,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1035,2},spec,{{path_consult,2},[{type,{1035,19},bounded_fun,[{type,{1035,19},'fun',[{type,{1035,19},product,[{var,{1035,20},'Path'},{var,{1035,26},'Filename'}]},{type,{1035,39},union,[{type,{1035,39},tuple,[{atom,{1035,40},ok},{var,{1035,44},'Terms'},{var,{1035,51},'FullName'}]},{type,{1035,63},tuple,[{atom,{1035,64},error},{var,{1035,71},'Reason'}]}]}]},[{type,{1036,7},constraint,[{atom,{1036,7},is_subtype},[{var,{1036,7},'Path'},{type,{1036,15},list,[{var,{1036,16},'Dir'}]}]]},{type,{1037,7},constraint,[{atom,{1037,7},is_subtype},[{var,{1037,7},'Dir'},{user_type,{1037,14},name_all,[]}]]},{type,{1038,7},constraint,[{atom,{1038,7},is_subtype},[{var,{1038,7},'Filename'},{user_type,{1038,19},name_all,[]}]]},{type,{1039,7},constraint,[{atom,{1039,7},is_subtype},[{var,{1039,7},'Terms'},{type,{1039,16},list,[{type,{1039,17},term,[]}]}]]},{type,{1040,7},constraint,[{atom,{1040,7},is_subtype},[{var,{1040,7},'FullName'},{user_type,{1040,19},filename_all,[]}]]},{type,{1041,7},constraint,[{atom,{1041,7},is_subtype},[{var,{1041,7},'Reason'},{type,{1041,17},union,[{user_type,{1041,17},posix,[]},{atom,{1041,27},badarg},{atom,{1041,36},terminated},{atom,{1041,49},system_limit},{type,{1042,17},tuple,[{ann_type,{1042,18},[{var,{1042,18},'Line'},{type,{1042,26},integer,[]}]},{ann_type,{1042,37},[{var,{1042,37},'Mod'},{type,{1042,44},module,[]}]},{ann_type,{1042,54},[{var,{1042,54},'Term'},{type,{1042,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,48,52,50>>}},{{function,path_eval,2},[{file,[102,105,108,101,46,101,114,108]},{location,1083}],[<<112,97,116,104,95,101,118,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46,32,84,104,101,32,114,101,115,117,108,116,32,111,102,32,101,118,97,108,117,97,116,105,111,110,32,105,115,32,110,111,116,32,114,101,116,117,114,110,101,100,59,32,97,110,121,32,101,120,112,114,101,115,115,105,111,110,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,102,105,108,101,32,109,117,115,116,32,98,101,32,116,104,101,114,101,32,102,111,114,32,105,116,115,32,115,105,100,101,32,101,102,102,101,99,116,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1083,2},spec,{{path_eval,2},[{type,{1083,16},bounded_fun,[{type,{1083,16},'fun',[{type,{1083,16},product,[{var,{1083,17},'Path'},{var,{1083,23},'Filename'}]},{type,{1083,36},union,[{type,{1083,36},tuple,[{atom,{1083,37},ok},{var,{1083,41},'FullName'}]},{type,{1083,53},tuple,[{atom,{1083,54},error},{var,{1083,61},'Reason'}]}]}]},[{type,{1084,7},constraint,[{atom,{1084,7},is_subtype},[{var,{1084,7},'Path'},{type,{1084,15},list,[{ann_type,{1084,16},[{var,{1084,16},'Dir'},{user_type,{1084,23},name_all,[]}]}]}]]},{type,{1085,7},constraint,[{atom,{1085,7},is_subtype},[{var,{1085,7},'Filename'},{user_type,{1085,19},name_all,[]}]]},{type,{1086,7},constraint,[{atom,{1086,7},is_subtype},[{var,{1086,7},'FullName'},{user_type,{1086,19},filename_all,[]}]]},{type,{1087,7},constraint,[{atom,{1087,7},is_subtype},[{var,{1087,7},'Reason'},{type,{1087,17},union,[{user_type,{1087,17},posix,[]},{atom,{1087,27},badarg},{atom,{1087,36},terminated},{atom,{1087,49},system_limit},{type,{1088,17},tuple,[{ann_type,{1088,18},[{var,{1088,18},'Line'},{type,{1088,26},integer,[]}]},{ann_type,{1088,37},[{var,{1088,37},'Mod'},{type,{1088,44},module,[]}]},{ann_type,{1088,54},[{var,{1088,54},'Term'},{type,{1088,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,48,56,52>>}},{{function,path_open,3},[{file,[102,105,108,101,46,101,114,108]},{location,1188}],[<<112,97,116,104,95,111,112,101,110,47,51>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,111,112,101,110,115,32,116,104,101,32,102,105,108,101,32,105,110,32,116,104,101,32,109,111,100,101,32,100,101,116,101,114,109,105,110,101,100,32,98,121,32>>,{code,[],[<<77,111,100,101,115>>]},<<46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,73,111,68,101,118,105,99,101,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,109,111,100,101,46,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,111,112,101,110,101,100,46>>]}]}]}]},#{signature => [{attribute,{1188,2},spec,{{path_open,3},[{type,{1188,16},bounded_fun,[{type,{1188,16},'fun',[{type,{1188,16},product,[{var,{1188,17},'Path'},{var,{1188,23},'Filename'},{var,{1188,33},'Modes'}]},{type,{1189,14},union,[{type,{1189,14},tuple,[{atom,{1189,15},ok},{var,{1189,19},'IoDevice'},{var,{1189,29},'FullName'}]},{type,{1189,41},tuple,[{atom,{1189,42},error},{var,{1189,49},'Reason'}]}]}]},[{type,{1190,7},constraint,[{atom,{1190,7},is_subtype},[{var,{1190,7},'Path'},{type,{1190,15},list,[{ann_type,{1190,16},[{var,{1190,16},'Dir'},{user_type,{1190,23},name_all,[]}]}]}]]},{type,{1191,7},constraint,[{atom,{1191,7},is_subtype},[{var,{1191,7},'Filename'},{user_type,{1191,19},name_all,[]}]]},{type,{1192,7},constraint,[{atom,{1192,7},is_subtype},[{var,{1192,7},'Modes'},{type,{1192,16},list,[{type,{1192,17},union,[{user_type,{1192,17},mode,[]},{atom,{1192,26},directory}]}]}]]},{type,{1193,7},constraint,[{atom,{1193,7},is_subtype},[{var,{1193,7},'IoDevice'},{user_type,{1193,19},io_device,[]}]]},{type,{1194,7},constraint,[{atom,{1194,7},is_subtype},[{var,{1194,7},'FullName'},{user_type,{1194,19},filename_all,[]}]]},{type,{1195,7},constraint,[{atom,{1195,7},is_subtype},[{var,{1195,7},'Reason'},{type,{1195,17},union,[{user_type,{1195,17},posix,[]},{atom,{1195,27},badarg},{atom,{1195,36},system_limit}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,49,51,48>>}},{{function,path_script,2},[{file,[102,105,108,101,46,101,114,108]},{location,1143}],[<<112,97,116,104,95,115,99,114,105,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,97,114,99,104,101,115,32,116,104,101,32,112,97,116,104,32>>,{code,[],[<<80,97,116,104>>]},<<32,40,97,32,108,105,115,116,32,111,102,32,100,105,114,101,99,116,111,114,121,32,110,97,109,101,115,41,32,117,110,116,105,108,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,102,111,117,110,100,46,32,73,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,102,105,108,101,110,97,109,101,44,32>>,{code,[],[<<80,97,116,104>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,110,32,114,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,86,97,108,117,101,44,32,70,117,108,108,78,97,109,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<70,117,108,108,78,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,101,110,111,101,110,116,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,102,111,117,110,100,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,100,105,114,101,99,116,111,114,105,101,115,32,105,110,32>>,{code,[],[<<80,97,116,104>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1143,2},spec,{{path_script,2},[{type,{1143,18},bounded_fun,[{type,{1143,18},'fun',[{type,{1143,18},product,[{var,{1143,19},'Path'},{var,{1143,25},'Filename'}]},{type,{1144,14},union,[{type,{1144,14},tuple,[{atom,{1144,15},ok},{var,{1144,19},'Value'},{var,{1144,26},'FullName'}]},{type,{1144,38},tuple,[{atom,{1144,39},error},{var,{1144,46},'Reason'}]}]}]},[{type,{1145,7},constraint,[{atom,{1145,7},is_subtype},[{var,{1145,7},'Path'},{type,{1145,15},list,[{ann_type,{1145,16},[{var,{1145,16},'Dir'},{user_type,{1145,23},name_all,[]}]}]}]]},{type,{1146,7},constraint,[{atom,{1146,7},is_subtype},[{var,{1146,7},'Filename'},{user_type,{1146,19},name_all,[]}]]},{type,{1147,7},constraint,[{atom,{1147,7},is_subtype},[{var,{1147,7},'Value'},{type,{1147,16},term,[]}]]},{type,{1148,7},constraint,[{atom,{1148,7},is_subtype},[{var,{1148,7},'FullName'},{user_type,{1148,19},filename_all,[]}]]},{type,{1149,7},constraint,[{atom,{1149,7},is_subtype},[{var,{1149,7},'Reason'},{type,{1149,17},union,[{user_type,{1149,17},posix,[]},{atom,{1149,27},badarg},{atom,{1149,36},terminated},{atom,{1149,49},system_limit},{type,{1150,17},tuple,[{ann_type,{1150,18},[{var,{1150,18},'Line'},{type,{1150,26},integer,[]}]},{ann_type,{1150,37},[{var,{1150,37},'Mod'},{type,{1150,44},module,[]}]},{ann_type,{1150,54},[{var,{1150,54},'Term'},{type,{1150,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,49,53,57>>}},{{function,path_script,3},[{file,[102,105,108,101,46,101,114,108]},{location,1155}],[<<112,97,116,104,95,115,99,114,105,112,116,47,51>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<112,97,116,104,95,115,99,114,105,112,116,47,50>>]},<<32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,83,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<32,97,98,111,117,116,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,46>>]}]},#{signature => [{attribute,{1155,2},spec,{{path_script,3},[{type,{1155,18},bounded_fun,[{type,{1155,18},'fun',[{type,{1155,18},product,[{var,{1155,19},'Path'},{var,{1155,25},'Filename'},{var,{1155,35},'Bindings'}]},{type,{1156,11},union,[{type,{1156,11},tuple,[{atom,{1156,12},ok},{var,{1156,16},'Value'},{var,{1156,23},'FullName'}]},{type,{1156,35},tuple,[{atom,{1156,36},error},{var,{1156,43},'Reason'}]}]}]},[{type,{1157,7},constraint,[{atom,{1157,7},is_subtype},[{var,{1157,7},'Path'},{type,{1157,15},list,[{ann_type,{1157,16},[{var,{1157,16},'Dir'},{user_type,{1157,23},name_all,[]}]}]}]]},{type,{1158,7},constraint,[{atom,{1158,7},is_subtype},[{var,{1158,7},'Filename'},{user_type,{1158,19},name_all,[]}]]},{type,{1159,7},constraint,[{atom,{1159,7},is_subtype},[{var,{1159,7},'Bindings'},{remote_type,{1159,19},[{atom,{1159,19},erl_eval},{atom,{1159,28},binding_struct},[]]}]]},{type,{1160,7},constraint,[{atom,{1160,7},is_subtype},[{var,{1160,7},'Value'},{type,{1160,16},term,[]}]]},{type,{1161,7},constraint,[{atom,{1161,7},is_subtype},[{var,{1161,7},'FullName'},{user_type,{1161,19},filename_all,[]}]]},{type,{1162,7},constraint,[{atom,{1162,7},is_subtype},[{var,{1162,7},'Reason'},{type,{1162,17},union,[{user_type,{1162,17},posix,[]},{atom,{1162,27},badarg},{atom,{1162,36},terminated},{atom,{1162,49},system_limit},{type,{1163,17},tuple,[{ann_type,{1163,18},[{var,{1163,18},'Line'},{type,{1163,26},integer,[]}]},{ann_type,{1163,37},[{var,{1163,37},'Mod'},{type,{1163,44},module,[]}]},{ann_type,{1163,54},[{var,{1163,54},'Term'},{type,{1163,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,48,51>>}},{{function,pid2name,1},[{file,[102,105,108,101,46,101,114,108]},{location,171}],[<<112,105,100,50,110,97,109,101,47,49>>],#{<<101,110>> => [{'div',[{class,<<99,104,97,110,103,101>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,110,100,32,119,105,108,108,32,98,101,32,114,101,109,111,118,101,100,32,105,110,32,69,114,108,97,110,103,47,79,84,80,32,50,55,46>>]}]},{p,[],[<<73,102,32>>,{code,[],[<<80,105,100>>]},<<32,105,115,32,97,110,32,73,47,79,32,100,101,118,105,99,101,44,32,116,104,97,116,32,105,115,44,32,97,32,112,105,100,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{code,[],[<<111,112,101,110,47,50>>]},<<44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,102,105,108,101,110,97,109,101,44,32,111,114,32,114,97,116,104,101,114,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,116,104,105,115,32,110,111,100,101,32,105,115,32,110,111,116,32,97,32,115,108,97,118,101,44,32,116,104,101,32,102,105,108,101,32,119,97,115,32,111,112,101,110,101,100,32,98,121,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,111,102,32,116,104,105,115,32,110,111,100,101,32,40,116,104,105,115,32,105,109,112,108,105,101,115,32,116,104,97,116,32>>,{code,[],[<<80,105,100>>]},<<32,109,117,115,116,32,98,101,32,97,32,108,111,99,97,108,32,112,105,100,41,32,97,110,100,32,116,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,99,108,111,115,101,100,46,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,105,115,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,110,32,102,108,97,116,32,115,116,114,105,110,103,32,102,111,114,109,97,116,46>>]}]},{dt,[],[{code,[],[<<117,110,100,101,102,105,110,101,100>>]}]},{dd,[],[{p,[],[<<73,110,32,97,108,108,32,111,116,104,101,114,32,99,97,115,101,115,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,102,111,114,32,100,101,98,117,103,103,105,110,103,32,111,110,108,121,46>>]}]}]},#{deprecated => <<102,105,108,101,58,112,105,100,50,110,97,109,101,47,49,32,105,115,32,100,101,112,114,101,99,97,116,101,100,32,97,110,100,32,119,105,108,108,32,98,101,32,114,101,109,111,118,101,100,32,105,110,32,79,84,80,32,50,55,59,32,116,104,105,115,32,102,117,110,99,116,105,111,110,97,108,105,116,121,32,105,115,32,110,111,32,108,111,110,103,101,114,32,115,117,112,112,111,114,116,101,100>>,signature => [{attribute,{171,2},spec,{{pid2name,1},[{type,{171,15},bounded_fun,[{type,{171,15},'fun',[{type,{171,15},product,[{var,{171,16},'Pid'}]},{type,{171,24},union,[{type,{171,24},tuple,[{atom,{171,25},ok},{var,{171,29},'Filename'}]},{atom,{171,41},undefined}]}]},[{type,{172,7},constraint,[{atom,{172,7},is_subtype},[{var,{172,7},'Filename'},{user_type,{172,19},filename_all,[]}]]},{type,{173,7},constraint,[{atom,{173,7},is_subtype},[{var,{173,7},'Pid'},{type,{173,14},pid,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,49,51>>}},{{function,position,2},[{file,[102,105,108,101,46,101,114,108]},{location,747}],[<<112,111,115,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,116,111,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,78,101,119,80,111,115,105,116,105,111,110,125>>]},<<32,40,97,115,32,97,98,115,111,108,117,116,101,32,111,102,102,115,101,116,41,32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<79,102,102,115,101,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<123,98,111,102,44,32,79,102,102,115,101,116,125>>]},<<46>>]}]},{dt,[],[{code,[],[<<123,98,111,102,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<65,98,115,111,108,117,116,101,32,111,102,102,115,101,116,46>>]}]},{dt,[],[{code,[],[<<123,99,117,114,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<79,102,102,115,101,116,32,102,114,111,109,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,111,102,44,32,79,102,102,115,101,116,125>>]}]},{dd,[],[{p,[],[<<79,102,102,115,101,116,32,102,114,111,109,32,116,104,101,32,101,110,100,32,111,102,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<98,111,102,32,124,32,99,117,114,32,124,32,101,111,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32,97,98,111,118,101,32,119,105,116,104,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,48,46>>]}]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,102,102,115,101,116,115,32,97,114,101,32,99,111,117,110,116,101,100,32,105,110,32,98,121,116,101,115,44,32,110,111,116,32,105,110,32,99,104,97,114,97,99,116,101,114,115,46,32,73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,117,115,105,110,103,32,115,111,109,101,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,98,121,116,101,32,100,111,101,115,32,110,111,116,32,99,111,114,114,101,115,112,111,110,100,32,116,111,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46,32,80,111,115,105,116,105,111,110,105,110,103,32,105,110,32,115,117,99,104,32,97,32,102,105,108,101,32,99,97,110,32,111,110,108,121,32,98,101,32,100,111,110,101,32,116,111,32,107,110,111,119,110,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,105,101,115,46,32,84,104,97,116,32,105,115,44,32,116,111,32,97,32,112,111,115,105,116,105,111,110,32,101,97,114,108,105,101,114,32,114,101,116,114,105,101,118,101,100,32,98,121,32,103,101,116,116,105,110,103,32,97,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,44,32,116,111,32,116,104,101,32,98,101,103,105,110,110,105,110,103,47,101,110,100,32,111,102,32,116,104,101,32,102,105,108,101,32,111,114,32,116,111,32,115,111,109,101,32,111,116,104,101,114,32,112,111,115,105,116,105,111,110,32>>,{em,[],[<<107,110,111,119,110>>]},<<32,116,111,32,98,101,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,98,121,32,115,111,109,101,32,111,116,104,101,114,32,109,101,97,110,115,32,40,116,121,112,105,99,97,108,108,121,32,98,101,121,111,110,100,32,97,32,98,121,116,101,32,111,114,100,101,114,32,109,97,114,107,32,105,110,32,116,104,101,32,102,105,108,101,44,32,119,104,105,99,104,32,104,97,115,32,97,32,107,110,111,119,110,32,98,121,116,101,45,115,105,122,101,41,46>>]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[<<69,105,116,104,101,114,32>>,{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,105,108,108,101,103,97,108,44,32,111,114,32,105,116,32,105,115,32,101,118,97,108,117,97,116,101,100,32,116,111,32,97,32,110,101,103,97,116,105,118,101,32,111,102,102,115,101,116,32,105,110,32,116,104,101,32,102,105,108,101,46,32,78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,110,101,103,97,116,105,118,101,32,118,97,108,117,101,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,110,32,101,114,114,111,114,44,32,97,110,100,32,97,102,116,101,114,32,116,104,101,32,99,97,108,108,32,116,104,101,32,102,105,108,101,32,112,111,115,105,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,46>>]}]}]}]},#{signature => [{attribute,{747,2},spec,{{position,2},[{type,{747,15},bounded_fun,[{type,{747,15},'fun',[{type,{747,15},product,[{var,{747,16},'IoDevice'},{var,{747,26},'Location'}]},{type,{747,39},union,[{type,{747,39},tuple,[{atom,{747,40},ok},{var,{747,44},'NewPosition'}]},{type,{747,59},tuple,[{atom,{747,60},error},{var,{747,67},'Reason'}]}]}]},[{type,{748,7},constraint,[{atom,{748,7},is_subtype},[{var,{748,7},'IoDevice'},{user_type,{748,19},io_device,[]}]]},{type,{749,7},constraint,[{atom,{749,7},is_subtype},[{var,{749,7},'Location'},{user_type,{749,19},location,[]}]]},{type,{750,7},constraint,[{atom,{750,7},is_subtype},[{var,{750,7},'NewPosition'},{type,{750,22},integer,[]}]]},{type,{751,7},constraint,[{atom,{751,7},is_subtype},[{var,{751,7},'Reason'},{type,{751,17},union,[{user_type,{751,17},posix,[]},{atom,{751,27},badarg},{atom,{751,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,52,49>>}},{{function,pread,2},[{file,[102,105,108,101,46,101,114,108]},{location,626}],[<<112,114,101,97,100,47,50>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32>>,{code,[],[<<112,114,101,97,100,47,51>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,91,68,97,116,97,44,32,46,46,46,93,125>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<44,32,119,104,101,114,101,32,101,97,99,104,32>>,{code,[],[<<68,97,116,97>>]},<<44,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32>>,{code,[],[<<112,114,101,97,100>>]},<<44,32,105,115,32,101,105,116,104,101,114,32,97,32,108,105,115,116,32,111,114,32,97,32,98,105,110,97,114,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,109,111,100,101,32,111,102,32,116,104,101,32,102,105,108,101,44,32,111,114,32>>,{code,[],[<<101,111,102>>]},<<32,105,102,32,116,104,101,32,114,101,113,117,101,115,116,101,100,32,112,111,115,105,116,105,111,110,32,105,115,32,98,101,121,111,110,100,32,101,110,100,32,111,102,32,102,105,108,101,46>>]},{p,[],[<<65,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,121,116,101,45,111,102,102,115,101,116,44,32,116,97,107,101,32,115,112,101,99,105,97,108,32,99,97,117,116,105,111,110,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,97,115,32,110,111,116,32,101,118,101,114,121,32,98,121,116,101,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,118,97,108,105,100,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,111,110,32,115,117,99,104,32,97,32,102,105,108,101,46>>]}]},#{signature => [{attribute,{626,2},spec,{{pread,2},[{type,{626,12},bounded_fun,[{type,{626,12},'fun',[{type,{626,12},product,[{var,{626,13},'IoDevice'},{var,{626,23},'LocNums'}]},{type,{626,35},union,[{type,{626,35},tuple,[{atom,{626,36},ok},{var,{626,40},'DataL'}]},{atom,{626,49},eof},{type,{626,55},tuple,[{atom,{626,56},error},{var,{626,63},'Reason'}]}]}]},[{type,{627,7},constraint,[{atom,{627,7},is_subtype},[{var,{627,7},'IoDevice'},{user_type,{627,19},io_device,[]}]]},{type,{628,7},constraint,[{atom,{628,7},is_subtype},[{var,{628,7},'LocNums'},{type,{628,18},list,[{type,{628,19},tuple,[{ann_type,{628,20},[{var,{628,20},'Location'},{user_type,{628,32},location,[]}]},{ann_type,{628,44},[{var,{628,44},'Number'},{type,{628,54},non_neg_integer,[]}]}]}]}]]},{type,{629,7},constraint,[{atom,{629,7},is_subtype},[{var,{629,7},'DataL'},{type,{629,16},list,[{var,{629,17},'Data'}]}]]},{type,{630,7},constraint,[{atom,{630,7},is_subtype},[{var,{630,7},'Data'},{type,{630,15},union,[{type,{630,15},string,[]},{type,{630,26},binary,[]},{atom,{630,37},eof}]}]]},{type,{631,7},constraint,[{atom,{631,7},is_subtype},[{var,{631,7},'Reason'},{type,{631,17},union,[{user_type,{631,17},posix,[]},{atom,{631,27},badarg},{atom,{631,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,50,57,51>>}},{{function,pread,3},[{file,[102,105,108,101,46,101,114,108]},{location,654}],[<<112,114,101,97,100,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32>>,{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]},<<32,97,110,100,32>>,{code,[],[<<114,101,97,100,47,50>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46>>]},{p,[],[{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,108,121,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,97,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,97,110,100,32,117,110,99,104,97,110,103,101,100,32,102,111,114,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,46>>]},{p,[],[<<65,115,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,98,121,116,101,45,111,102,102,115,101,116,44,32,116,97,107,101,32,115,112,101,99,105,97,108,32,99,97,117,116,105,111,110,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,97,115,32,110,111,116,32,101,118,101,114,121,32,98,121,116,101,32,112,111,115,105,116,105,111,110,32,105,115,32,97,32,118,97,108,105,100,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,32,111,110,32,115,117,99,104,32,97,32,102,105,108,101,46>>]}]},#{signature => [{attribute,{654,2},spec,{{pread,3},[{type,{654,12},bounded_fun,[{type,{654,12},'fun',[{type,{654,12},product,[{var,{654,13},'IoDevice'},{var,{654,23},'Location'},{var,{654,33},'Number'}]},{type,{655,14},union,[{type,{655,14},tuple,[{atom,{655,15},ok},{var,{655,19},'Data'}]},{atom,{655,27},eof},{type,{655,33},tuple,[{atom,{655,34},error},{var,{655,41},'Reason'}]}]}]},[{type,{656,7},constraint,[{atom,{656,7},is_subtype},[{var,{656,7},'IoDevice'},{user_type,{656,19},io_device,[]}]]},{type,{657,7},constraint,[{atom,{657,7},is_subtype},[{var,{657,7},'Location'},{user_type,{657,19},location,[]}]]},{type,{658,7},constraint,[{atom,{658,7},is_subtype},[{var,{658,7},'Number'},{type,{658,17},non_neg_integer,[]}]]},{type,{659,7},constraint,[{atom,{659,7},is_subtype},[{var,{659,7},'Data'},{type,{659,15},union,[{type,{659,15},string,[]},{type,{659,26},binary,[]}]}]]},{type,{660,7},constraint,[{atom,{660,7},is_subtype},[{var,{660,7},'Reason'},{type,{660,17},union,[{user_type,{660,17},posix,[]},{atom,{660,27},badarg},{atom,{660,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,49,49>>}},{{function,pwrite,2},[{file,[102,105,108,101,46,101,114,108]},{location,687}],[<<112,119,114,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<80,101,114,102,111,114,109,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32>>,{code,[],[<<112,119,114,105,116,101,47,51>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,123,78,44,32,82,101,97,115,111,110,125,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<78>>]},<<32,105,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,115,117,99,99,101,115,115,102,117,108,32,119,114,105,116,101,115,32,100,111,110,101,32,98,101,102,111,114,101,32,116,104,101,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<87,104,101,110,32,112,111,115,105,116,105,111,110,105,110,103,32,105,110,32,97,32,102,105,108,101,32,119,105,116,104,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,99,97,117,116,105,111,110,32,109,117,115,116,32,98,101,32,116,97,107,101,110,32,116,111,32,115,101,116,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,111,115,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{687,2},spec,{{pwrite,2},[{type,{687,13},bounded_fun,[{type,{687,13},'fun',[{type,{687,13},product,[{var,{687,14},'IoDevice'},{var,{687,24},'LocBytes'}]},{type,{687,37},union,[{atom,{687,37},ok},{type,{687,42},tuple,[{atom,{687,43},error},{type,{687,50},tuple,[{var,{687,51},'N'},{var,{687,54},'Reason'}]}]}]}]},[{type,{688,7},constraint,[{atom,{688,7},is_subtype},[{var,{688,7},'IoDevice'},{user_type,{688,19},io_device,[]}]]},{type,{689,7},constraint,[{atom,{689,7},is_subtype},[{var,{689,7},'LocBytes'},{type,{689,19},list,[{type,{689,20},tuple,[{ann_type,{689,21},[{var,{689,21},'Location'},{user_type,{689,33},location,[]}]},{ann_type,{689,45},[{var,{689,45},'Bytes'},{type,{689,54},iodata,[]}]}]}]}]]},{type,{690,7},constraint,[{atom,{690,7},is_subtype},[{var,{690,7},'N'},{type,{690,12},non_neg_integer,[]}]]},{type,{691,7},constraint,[{atom,{691,7},is_subtype},[{var,{691,7},'Reason'},{type,{691,17},union,[{user_type,{691,17},posix,[]},{atom,{691,27},badarg},{atom,{691,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,50,56>>}},{{function,pwrite,3},[{file,[102,105,108,101,46,101,114,108]},{location,712}],[<<112,119,114,105,116,101,47,51>>],#{<<101,110>> => [{p,[],[<<67,111,109,98,105,110,101,115,32>>,{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]},<<32,97,110,100,32>>,{code,[],[<<119,114,105,116,101,47,50>>]},<<32,105,110,32,111,110,101,32,111,112,101,114,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,97,108,108,105,110,103,32,116,104,101,109,32,111,110,101,32,97,116,32,97,32,116,105,109,101,46>>]},{p,[],[{code,[],[<<76,111,99,97,116,105,111,110>>]},<<32,105,115,32,111,110,108,121,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,97,110,32,105,110,116,101,103,101,114,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,111,102,32,116,104,101,32,102,105,108,101,32,97,102,116,101,114,32,116,104,101,32,111,112,101,114,97,116,105,111,110,32,105,115,32,117,110,100,101,102,105,110,101,100,32,102,111,114,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,97,110,100,32,117,110,99,104,97,110,103,101,100,32,102,111,114,32>>,{code,[],[<<114,97,109>>]},<<32,109,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,112,111,115,105,116,105,111,110,105,110,103,32,105,110,32,97,32,102,105,108,101,32,119,105,116,104,32,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,99,97,117,116,105,111,110,32,109,117,115,116,32,98,101,32,116,97,107,101,110,32,116,111,32,115,101,116,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,110,32,97,32,99,111,114,114,101,99,116,32,99,104,97,114,97,99,116,101,114,32,98,111,117,110,100,97,114,121,46,32,70,111,114,32,100,101,116,97,105,108,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,111,115,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,111,115,105,116,105,111,110,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{712,2},spec,{{pwrite,3},[{type,{712,13},bounded_fun,[{type,{712,13},'fun',[{type,{712,13},product,[{var,{712,14},'IoDevice'},{var,{712,24},'Location'},{var,{712,34},'Bytes'}]},{type,{712,44},union,[{atom,{712,44},ok},{type,{712,49},tuple,[{atom,{712,50},error},{var,{712,57},'Reason'}]}]}]},[{type,{713,7},constraint,[{atom,{713,7},is_subtype},[{var,{713,7},'IoDevice'},{user_type,{713,19},io_device,[]}]]},{type,{714,7},constraint,[{atom,{714,7},is_subtype},[{var,{714,7},'Location'},{user_type,{714,19},location,[]}]]},{type,{715,7},constraint,[{atom,{715,7},is_subtype},[{var,{715,7},'Bytes'},{type,{715,16},iodata,[]}]]},{type,{716,7},constraint,[{atom,{716,7},is_subtype},[{var,{716,7},'Reason'},{type,{716,17},union,[{user_type,{716,17},posix,[]},{atom,{716,27},badarg},{atom,{716,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,52,51>>}},{{function,read,2},[{file,[102,105,108,101,46,101,114,108]},{location,584}],[<<114,101,97,100,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,98,121,116,101,115,47,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,84,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<44,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,112,114,101,97,100,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,101,97,100,47,51>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]}]},<<32,97,114,101,32,116,104,101,32,111,110,108,121,32,119,97,121,115,32,116,111,32,114,101,97,100,32,102,114,111,109,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,40,97,108,116,104,111,117,103,104,32,116,104,101,121,32,119,111,114,107,32,102,111,114,32,110,111,114,109,97,108,108,121,32,111,112,101,110,101,100,32,102,105,108,101,115,44,32,116,111,111,41,46>>]},{p,[],[<<70,111,114,32,102,105,108,101,115,32,119,104,101,114,101,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,111,110,101,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,121,116,101,32,111,110,32,116,104,101,32,102,105,108,101,46,32,84,104,101,32,112,97,114,97,109,101,116,101,114,32>>,{code,[],[<<78,117,109,98,101,114>>]},<<32,97,108,119,97,121,115,32,100,101,110,111,116,101,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32>>,{em,[],[<<99,104,97,114,97,99,116,101,114,115>>]},<<32,114,101,97,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,44,32,119,104,105,108,101,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,102,105,108,101,32,99,97,110,32,98,101,32,109,111,118,101,100,32,109,117,99,104,32,109,111,114,101,32,116,104,97,110,32,116,104,105,115,32,110,117,109,98,101,114,32,119,104,101,110,32,114,101,97,100,105,110,103,32,97,32,85,110,105,99,111,100,101,32,102,105,108,101,46>>]},{p,[],[<<65,108,115,111,44,32,105,102,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32>>,{code,[],[<<114,101,97,100,47,51>>]},<<32,99,97,108,108,32,102,97,105,108,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,99,104,97,114,97,99,116,101,114,115,32,108,97,114,103,101,114,32,116,104,97,110,32,50,53,53,44,32,119,104,105,99,104,32,105,115,32,119,104,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,32,119,104,101,110,32,114,101,97,100,105,110,103,32,115,117,99,104,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,68,97,116,97,125>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,119,97,115,32,111,112,101,110,101,100,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,44,32,116,104,101,32,114,101,97,100,32,98,121,116,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32,105,110,32,97,32,108,105,115,116,46,32,84,104,101,32,108,105,115,116,32,111,114,32,98,105,110,97,114,121,32,105,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,98,121,116,101,115,32,114,101,113,117,101,115,116,101,100,32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,101,100,32,105,102,32>>,{code,[],[<<78,117,109,98,101,114,62,48>>]},<<32,97,110,100,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,32,98,101,102,111,114,101,32,97,110,121,116,104,105,110,103,32,97,116,32,97,108,108,32,99,111,117,108,100,32,98,101,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,117,110,105,99,111,100,101,44,32,108,97,116,105,110,49,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,97,110,100,32,116,104,101,32,100,97,116,97,32,105,110,32,116,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,116,104,101,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46>>]}]}]}]},#{signature => [{attribute,{584,2},spec,{{read,2},[{type,{584,11},bounded_fun,[{type,{584,11},'fun',[{type,{584,11},product,[{var,{584,12},'IoDevice'},{var,{584,22},'Number'}]},{type,{584,33},union,[{type,{584,33},tuple,[{atom,{584,34},ok},{var,{584,38},'Data'}]},{atom,{584,46},eof},{type,{584,52},tuple,[{atom,{584,53},error},{var,{584,60},'Reason'}]}]}]},[{type,{585,7},constraint,[{atom,{585,7},is_subtype},[{var,{585,7},'IoDevice'},{type,{585,19},union,[{user_type,{585,19},io_device,[]},{type,{585,33},atom,[]}]}]]},{type,{586,7},constraint,[{atom,{586,7},is_subtype},[{var,{586,7},'Number'},{type,{586,17},non_neg_integer,[]}]]},{type,{587,7},constraint,[{atom,{587,7},is_subtype},[{var,{587,7},'Data'},{type,{587,15},union,[{type,{587,15},string,[]},{type,{587,26},binary,[]}]}]]},{type,{588,7},constraint,[{atom,{588,7},is_subtype},[{var,{588,7},'Reason'},{type,{588,17},union,[{user_type,{588,17},posix,[]},{atom,{589,17},badarg},{atom,{590,17},terminated},{type,{591,17},tuple,[{atom,{591,18},no_translation},{atom,{591,34},unicode},{atom,{591,43},latin1}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,51,54,48>>}},{{function,read_file,1},[{file,[102,105,108,101,46,101,114,108]},{location,413}],[<<114,101,97,100,95,102,105,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,105,110,97,114,121,125>>]},<<44,32,119,104,101,114,101,32>>,{code,[],[<<66,105,110,97,114,121>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,100,97,116,97,32,111,98,106,101,99,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,105,102,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,114,101,97,100,105,110,103,32,116,104,101,32,102,105,108,101,44,32,111,114,32,102,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,109,101,109>>]}]},{dd,[],[{p,[],[<<84,104,101,114,101,32,105,115,32,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,32,102,111,114,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]}]}]},#{signature => [{attribute,{413,2},spec,{{read_file,1},[{type,{413,16},bounded_fun,[{type,{413,16},'fun',[{type,{413,16},product,[{var,{413,17},'Filename'}]},{type,{413,30},union,[{type,{413,30},tuple,[{atom,{413,31},ok},{var,{413,35},'Binary'}]},{type,{413,45},tuple,[{atom,{413,46},error},{var,{413,53},'Reason'}]}]}]},[{type,{414,7},constraint,[{atom,{414,7},is_subtype},[{var,{414,7},'Filename'},{user_type,{414,19},name_all,[]}]]},{type,{415,7},constraint,[{atom,{415,7},is_subtype},[{var,{415,7},'Binary'},{type,{415,17},binary,[]}]]},{type,{416,7},constraint,[{atom,{416,7},is_subtype},[{var,{416,7},'Reason'},{type,{416,17},union,[{user_type,{416,17},posix,[]},{atom,{416,27},badarg},{atom,{416,36},terminated},{atom,{416,49},system_limit}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,52,49,52>>}},{{function,read_file_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,288}],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,50>>],#{},#{signature => [{attribute,{288,2},spec,{{read_file_info,2},[{type,{288,21},bounded_fun,[{type,{288,21},'fun',[{type,{288,21},product,[{var,{288,22},'File'},{var,{288,28},'Opts'}]},{type,{288,37},union,[{type,{288,37},tuple,[{atom,{288,38},ok},{var,{288,42},'FileInfo'}]},{type,{288,54},tuple,[{atom,{288,55},error},{var,{288,62},'Reason'}]}]}]},[{type,{289,7},constraint,[{atom,{289,7},is_subtype},[{var,{289,7},'File'},{type,{289,15},union,[{user_type,{289,15},name_all,[]},{user_type,{289,28},io_device,[]}]}]]},{type,{290,7},constraint,[{atom,{290,7},is_subtype},[{var,{290,7},'Opts'},{type,{290,15},list,[{user_type,{290,16},file_info_option,[]}]}]]},{type,{291,7},constraint,[{atom,{291,7},is_subtype},[{var,{291,7},'FileInfo'},{user_type,{291,19},file_info,[]}]]},{type,{292,7},constraint,[{atom,{292,7},is_subtype},[{var,{292,7},'Reason'},{type,{292,17},union,[{user_type,{292,17},posix,[]},{atom,{292,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,52,53,48>>,equiv => {function,read_file_info,1},since => <<79,84,80,32,82,49,53,66>>}},{{function,read_file_info,1},[{file,[102,105,108,101,46,101,114,108]},{location,276}],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,114,105,101,118,101,115,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,97,32,102,105,108,101,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,73,110,102,111,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,73,110,102,111>>]},<<32,105,115,32,97,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<44,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,75,101,114,110,101,108,32,105,110,99,108,117,100,101,32,102,105,108,101,32>>,{code,[],[<<102,105,108,101,46,104,114,108>>]},<<46,32,73,110,99,108,117,100,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,100,105,114,101,99,116,105,118,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32,102,114,111,109,32,119,104,105,99,104,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<32,45,105,110,99,108,117,100,101,95,108,105,98,40,34,107,101,114,110,101,108,47,105,110,99,108,117,100,101,47,102,105,108,101,46,104,114,108,34,41,46>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,116,121,112,101,32,114,101,116,117,114,110,101,100,32,105,110,32>>,{code,[],[<<97,116,105,109,101>>]},<<44,32>>,{code,[],[<<109,116,105,109,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<99,116,105,109,101>>]},<<32,105,115,32,100,101,112,101,110,100,101,110,116,32,111,110,32,116,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<79,112,116,115,32,58,58,32,123,116,105,109,101,44,32,84,121,112,101,125>>]},<<32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,108,111,99,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<117,110,105,118,101,114,115,97,108>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,117,110,105,118,101,114,115,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<112,111,115,105,120>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,115,101,99,111,110,100,115,32,115,105,110,99,101,32,111,114,32,98,101,102,111,114,101,32,85,110,105,120,32,116,105,109,101,32,101,112,111,99,104,44,32,119,104,105,99,104,32,105,115,32,49,57,55,48,45,48,49,45,48,49,32,48,48,58,48,48,32,85,84,67,46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,116,105,109,101,44,32,108,111,99,97,108,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,119,105,108,108,32,98,114,101,97,107,32,116,104,105,115,32,109,111,100,117,108,101,39,115,32,97,116,111,109,105,99,105,116,121,32,103,117,97,114,97,110,116,101,101,115,32,97,115,32,105,116,32,99,97,110,32,114,97,99,101,32,119,105,116,104,32,97,32,99,111,110,99,117,114,114,101,110,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]},<<32>>]},<<46>>]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,104,97,115,32,110,111,32,101,102,102,101,99,116,32,119,104,101,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,103,105,118,101,110,32,97,110,32,73,47,79,32,100,101,118,105,99,101,32,105,110,115,116,101,97,100,32,111,102,32,97,32,102,105,108,101,32,110,97,109,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<32,119,105,116,104,32,116,104,101,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,116,111,32,111,98,116,97,105,110,32,97,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,102,105,114,115,116,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<65,115,32,102,105,108,101,32,116,105,109,101,115,32,97,114,101,32,115,116,111,114,101,100,32,105,110,32,80,79,83,73,88,32,116,105,109,101,32,111,110,32,109,111,115,116,32,79,83,44,32,105,116,32,105,115,32,102,97,115,116,101,114,32,116,111,32,113,117,101,114,121,32,102,105,108,101,32,105,110,102,111,114,109,97,116,105,111,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<112,111,115,105,120>>]},<<46>>]}]},{p,[],[<<84,104,101,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,101,108,100,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<115,105,122,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<83,105,122,101,32,111,102,32,102,105,108,101,32,105,110,32,98,121,116,101,115,46>>]}]},{dt,[],[{code,[],[<<116,121,112,101,32,61,32,100,101,118,105,99,101,32,124,32,100,105,114,101,99,116,111,114,121,32,124,32,111,116,104,101,114,32,124,32,114,101,103,117,108,97,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,102,105,108,101,46,32,67,97,110,32,97,108,115,111,32,99,111,110,116,97,105,110,32>>,{code,[],[<<115,121,109,108,105,110,107>>]},<<32,119,104,101,110,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[<<114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,49,44,50>>]},<<46>>]}]},{dt,[],[{code,[],[<<97,99,99,101,115,115,32,61,32,114,101,97,100,32,124,32,119,114,105,116,101,32,124,32,114,101,97,100,95,119,114,105,116,101,32,124,32,110,111,110,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,99,117,114,114,101,110,116,32,115,121,115,116,101,109,32,97,99,99,101,115,115,32,116,111,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<97,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<109,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,119,114,105,116,116,101,110,46>>]}]},{dt,[],[{code,[],[<<99,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,116,104,105,115,32,116,105,109,101,32,102,105,101,108,100,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,46,32,79,110,32,85,110,105,120,44,32,105,116,32,105,115,32,116,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,111,114,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,119,97,115,32,99,104,97,110,103,101,100,46,32,73,110,32,87,105,110,100,111,119,115,44,32,105,116,32,105,115,32,116,104,101,32,99,114,101,97,116,101,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<109,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,112,101,114,109,105,115,115,105,111,110,115,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,98,105,116,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<56,35,48,48,52,48,48>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,50,48,48>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,49,48,48>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,52,48>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,50,48>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,49,48>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,52>>]}]},{dd,[],[{p,[],[<<114,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,50>>]}]},{dd,[],[{p,[],[<<119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,49>>]}]},{dd,[],[{p,[],[<<101,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<49,54,35,56,48,48>>]}]},{dd,[],[{p,[],[<<115,101,116,32,117,115,101,114,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]},{dt,[],[{code,[],[<<49,54,35,52,48,48>>]}]},{dd,[],[{p,[],[<<115,101,116,32,103,114,111,117,112,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]}]},{p,[],[<<79,110,32,85,110,105,120,32,112,108,97,116,102,111,114,109,115,44,32,111,116,104,101,114,32,98,105,116,115,32,116,104,97,110,32,116,104,111,115,101,32,108,105,115,116,101,100,32,97,98,111,118,101,32,109,97,121,32,98,101,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<108,105,110,107,115,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<78,117,109,98,101,114,32,111,102,32,108,105,110,107,115,32,116,111,32,116,104,101,32,102,105,108,101,32,40,116,104,105,115,32,105,115,32,97,108,119,97,121,115,32,49,32,102,111,114,32,102,105,108,101,32,115,121,115,116,101,109,115,32,116,104,97,116,32,104,97,118,101,32,110,111,32,99,111,110,99,101,112,116,32,111,102,32,108,105,110,107,115,41,46>>]}]},{dt,[],[{code,[],[<<109,97,106,111,114,95,100,101,118,105,99,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,100,101,110,116,105,102,105,101,115,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,119,104,101,114,101,32,116,104,101,32,102,105,108,101,32,105,115,32,108,111,99,97,116,101,100,46,32,73,110,32,87,105,110,100,111,119,115,44,32,116,104,101,32,110,117,109,98,101,114,32,105,110,100,105,99,97,116,101,115,32,97,32,100,114,105,118,101,32,97,115,32,102,111,108,108,111,119,115,58,32,48,32,109,101,97,110,115,32,65,58,44,32,49,32,109,101,97,110,115,32,66,58,44,32,97,110,100,32,115,111,32,111,110,46>>]}]},{dt,[],[{code,[],[<<109,105,110,111,114,95,100,101,118,105,99,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,118,97,108,105,100,32,102,111,114,32,99,104,97,114,97,99,116,101,114,32,100,101,118,105,99,101,115,32,111,110,32,85,110,105,120,46,32,73,110,32,97,108,108,32,111,116,104,101,114,32,99,97,115,101,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<105,110,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32>>,{code,[],[<<105,110,111,100,101>>]},<<32,110,117,109,98,101,114,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<117,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,110,100,105,99,97,116,101,115,32,116,104,101,32,111,119,110,101,114,32,111,102,32,116,104,101,32,102,105,108,101,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]},{dt,[],[{code,[],[<<103,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,32,111,119,110,101,114,32,111,102,32,116,104,101,32,102,105,108,101,32,98,101,108,111,110,103,115,32,116,111,46,32,79,110,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,122,101,114,111,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{signature => [{attribute,{276,2},spec,{{read_file_info,1},[{type,{276,21},bounded_fun,[{type,{276,21},'fun',[{type,{276,21},product,[{var,{276,22},'File'}]},{type,{276,31},union,[{type,{276,31},tuple,[{atom,{276,32},ok},{var,{276,36},'FileInfo'}]},{type,{276,48},tuple,[{atom,{276,49},error},{var,{276,56},'Reason'}]}]}]},[{type,{277,7},constraint,[{atom,{277,7},is_subtype},[{var,{277,7},'File'},{type,{277,15},union,[{user_type,{277,15},name_all,[]},{user_type,{277,28},io_device,[]}]}]]},{type,{278,7},constraint,[{atom,{278,7},is_subtype},[{var,{278,7},'FileInfo'},{user_type,{278,19},file_info,[]}]]},{type,{279,7},constraint,[{atom,{279,7},is_subtype},[{var,{279,7},'Reason'},{type,{279,17},union,[{user_type,{279,17},posix,[]},{atom,{279,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,52,53,48>>,since => <<79,84,80,32,82,49,53,66>>}},{{function,read_line,1},[{file,[102,105,108,101,46,101,114,108]},{location,606}],[<<114,101,97,100,95,108,105,110,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,32,108,105,110,101,32,111,102,32,98,121,116,101,115,47,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,76,105,110,101,115,32,97,114,101,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,100,101,108,105,109,105,116,101,100,32,98,121,32,116,104,101,32,108,105,110,101,102,101,101,100,32,40,76,70,44,32>>,{code,[],[<<92,110>>]},<<41,32,99,104,97,114,97,99,116,101,114,44,32,98,117,116,32,97,110,121,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,67,82,44,32>>,{code,[],[<<92,114>>]},<<41,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,101,119,108,105,110,101,32,105,115,32,97,108,115,111,32,116,114,101,97,116,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,76,70,32,99,104,97,114,97,99,116,101,114,32,40,116,104,101,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,105,115,32,115,105,108,101,110,116,108,121,32,105,103,110,111,114,101,100,41,46,32,84,104,101,32,108,105,110,101,32,105,115,32,114,101,116,117,114,110,101,100,32>>,{em,[],[<<105,110,99,108,117,100,105,110,103>>]},<<32,116,104,101,32,76,70,44,32,98,117,116,32,101,120,99,108,117,100,105,110,103,32,97,110,121,32,67,82,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,76,70,46,32,84,104,105,115,32,98,101,104,97,118,105,111,117,114,32,105,115,32,99,111,110,115,105,115,116,101,110,116,32,119,105,116,104,32,116,104,101,32,98,101,104,97,118,105,111,117,114,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111,35,103,101,116,95,108,105,110,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,111,58,103,101,116,95,108,105,110,101,47,50>>]}]},<<46,32,73,102,32,101,110,100,32,111,102,32,102,105,108,101,32,105,115,32,114,101,97,99,104,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,76,70,32,101,110,100,105,110,103,32,116,104,101,32,108,97,115,116,32,108,105,110,101,44,32,97,32,108,105,110,101,32,119,105,116,104,32,110,111,32,116,114,97,105,108,105,110,103,32,76,70,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,111,110,32,102,105,108,101,115,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,46,32,72,111,119,101,118,101,114,44,32,105,116,32,105,115,32,105,110,101,102,102,105,99,105,101,110,116,32,116,111,32,117,115,101,32,105,116,32,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,102,105,108,101,115,32,105,102,32,116,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,115,112,101,99,105,102,105,101,100,46,32,84,104,117,115,44,32,99,111,109,98,105,110,105,110,103,32>>,{code,[],[<<114,97,119>>]},<<32,97,110,100,32>>,{code,[],[<<123,114,101,97,100,95,97,104,101,97,100,44,32,83,105,122,101,125>>]},<<32,105,115,32,104,105,103,104,108,121,32,114,101,99,111,109,109,101,110,100,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,97,32,116,101,120,116,32,102,105,108,101,32,102,111,114,32,114,97,119,32,108,105,110,101,45,111,114,105,101,110,116,101,100,32,114,101,97,100,105,110,103,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,105,115,32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,116,104,101,32>>,{code,[],[<<114,101,97,100,95,108,105,110,101,47,49>>]},<<32,99,97,108,108,32,102,97,105,108,115,32,105,102,32,116,104,101,32,100,97,116,97,32,99,111,110,116,97,105,110,115,32,99,104,97,114,97,99,116,101,114,115,32,108,97,114,103,101,114,32,116,104,97,110,32,50,53,53,44,32,119,104,121,32,109,111,100,117,108,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,105,111>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<105,111,40,51,41>>]}]},<<32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,32,119,104,101,110,32,114,101,97,100,105,110,103,32,115,117,99,104,32,97,32,102,105,108,101,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,68,97,116,97,125>>]}]},{dd,[],[{p,[],[<<79,110,101,32,108,105,110,101,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,105,115,32,114,101,116,117,114,110,101,100,44,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,116,114,97,105,108,105,110,103,32,76,70,44,32,98,117,116,32,119,105,116,104,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,32,114,101,112,108,97,99,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,76,70,32,40,115,101,101,32,97,98,111,118,101,41,46>>]},{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,105,110,32,98,105,110,97,114,121,32,109,111,100,101,44,32,116,104,101,32,114,101,97,100,32,98,121,116,101,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,97,32,98,105,110,97,114,121,44,32,111,116,104,101,114,119,105,115,101,32,105,110,32,97,32,108,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,111,102>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,101,100,32,105,102,32,101,110,100,32,111,102,32,102,105,108,101,32,119,97,115,32,114,101,97,99,104,101,100,32,98,101,102,111,114,101,32,97,110,121,116,104,105,110,103,32,97,116,32,97,108,108,32,99,111,117,108,100,32,98,101,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,114,101,97,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<123,110,111,95,116,114,97,110,115,108,97,116,105,111,110,44,32,117,110,105,99,111,100,101,44,32,108,97,116,105,110,49,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32,97,110,111,116,104,101,114,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<32,97,110,100,32,116,104,101,32,100,97,116,97,32,111,110,32,116,104,101,32,102,105,108,101,32,99,97,110,110,111,116,32,98,101,32,116,114,97,110,115,108,97,116,101,100,32,116,111,32,116,104,101,32,98,121,116,101,45,111,114,105,101,110,116,101,100,32,100,97,116,97,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,46>>]}]}]}]},#{signature => [{attribute,{606,2},spec,{{read_line,1},[{type,{606,16},bounded_fun,[{type,{606,16},'fun',[{type,{606,16},product,[{var,{606,17},'IoDevice'}]},{type,{606,30},union,[{type,{606,30},tuple,[{atom,{606,31},ok},{var,{606,35},'Data'}]},{atom,{606,43},eof},{type,{606,49},tuple,[{atom,{606,50},error},{var,{606,57},'Reason'}]}]}]},[{type,{607,7},constraint,[{atom,{607,7},is_subtype},[{var,{607,7},'IoDevice'},{type,{607,19},union,[{user_type,{607,19},io_device,[]},{type,{607,33},atom,[]}]}]]},{type,{608,7},constraint,[{atom,{608,7},is_subtype},[{var,{608,7},'Data'},{type,{608,15},union,[{type,{608,15},string,[]},{type,{608,26},binary,[]}]}]]},{type,{609,7},constraint,[{atom,{609,7},is_subtype},[{var,{609,7},'Reason'},{type,{609,17},union,[{user_type,{609,17},posix,[]},{atom,{610,17},badarg},{atom,{611,17},terminated},{type,{612,17},tuple,[{atom,{612,18},no_translation},{atom,{612,34},unicode},{atom,{612,43},latin1}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,54,49,48>>}},{{function,read_link,1},[{file,[102,105,108,101,46,101,114,108]},{location,350}],[<<114,101,97,100,95,108,105,110,107,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<114,101,97,100,95,108,105,110,107,95,97,108,108>>}],[]},<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]},<<32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,114,97,119,32,102,105,108,101,110,97,109,101,44,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,111,114,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,102,105,108,101,32,116,104,97,116,32,105,116,32,114,101,102,101,114,115,32,116,111,32,100,111,101,115,32,110,111,116,32,99,111,110,102,111,114,109,32,116,111,32,116,104,101,32,101,120,112,101,99,116,101,100,32,101,110,99,111,100,105,110,103,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{signature => [{attribute,{350,2},spec,{{read_link,1},[{type,{350,16},bounded_fun,[{type,{350,16},'fun',[{type,{350,16},product,[{var,{350,17},'Name'}]},{type,{350,26},union,[{type,{350,26},tuple,[{atom,{350,27},ok},{var,{350,31},'Filename'}]},{type,{350,43},tuple,[{atom,{350,44},error},{var,{350,51},'Reason'}]}]}]},[{type,{351,7},constraint,[{atom,{351,7},is_subtype},[{var,{351,7},'Name'},{user_type,{351,15},name_all,[]}]]},{type,{352,7},constraint,[{atom,{352,7},is_subtype},[{var,{352,7},'Filename'},{user_type,{352,19},filename,[]}]]},{type,{353,7},constraint,[{atom,{353,7},is_subtype},[{var,{353,7},'Reason'},{type,{353,17},union,[{user_type,{353,17},posix,[]},{atom,{353,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,54,54,55>>}},{{function,read_link_all,1},[{file,[102,105,108,101,46,101,114,108]},{location,358}],[<<114,101,97,100,95,108,105,110,107,95,97,108,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,70,105,108,101,110,97,109,101,125>>]},<<32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,114,101,102,101,114,115,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,32,111,114,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32>>,{code,[],[<<123,101,114,114,111,114,44,101,110,111,116,115,117,112,125>>]},<<46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,101,105,116,104,101,114,32,97,32,108,105,115,116,32,111,114,32,97,32,98,105,110,97,114,121,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<78,97,109,101>>]},<<32,100,111,101,115,32,110,111,116,32,114,101,102,101,114,32,116,111,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,115,117,112>>]}]},{dd,[],[{p,[],[<<83,121,109,98,111,108,105,99,32,108,105,110,107,115,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,111,110,32,116,104,105,115,32,112,108,97,116,102,111,114,109,46>>]}]}]}]},#{signature => [{attribute,{358,2},spec,{{read_link_all,1},[{type,{358,20},bounded_fun,[{type,{358,20},'fun',[{type,{358,20},product,[{var,{358,21},'Name'}]},{type,{358,30},union,[{type,{358,30},tuple,[{atom,{358,31},ok},{var,{358,35},'Filename'}]},{type,{358,47},tuple,[{atom,{358,48},error},{var,{358,55},'Reason'}]}]}]},[{type,{359,7},constraint,[{atom,{359,7},is_subtype},[{var,{359,7},'Name'},{user_type,{359,15},name_all,[]}]]},{type,{360,7},constraint,[{atom,{360,7},is_subtype},[{var,{360,7},'Filename'},{user_type,{360,19},filename_all,[]}]]},{type,{361,7},constraint,[{atom,{361,7},is_subtype},[{var,{361,7},'Reason'},{type,{361,17},union,[{user_type,{361,17},posix,[]},{atom,{361,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,54,57,55>>,since => <<79,84,80,32,82,49,54,66>>}},{{function,read_link_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,328}],[<<114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,50>>],#{},#{signature => [{attribute,{328,2},spec,{{read_link_info,2},[{type,{328,21},bounded_fun,[{type,{328,21},'fun',[{type,{328,21},product,[{var,{328,22},'Name'},{var,{328,28},'Opts'}]},{type,{328,37},union,[{type,{328,37},tuple,[{atom,{328,38},ok},{var,{328,42},'FileInfo'}]},{type,{328,54},tuple,[{atom,{328,55},error},{var,{328,62},'Reason'}]}]}]},[{type,{329,7},constraint,[{atom,{329,7},is_subtype},[{var,{329,7},'Name'},{user_type,{329,15},name_all,[]}]]},{type,{330,7},constraint,[{atom,{330,7},is_subtype},[{var,{330,7},'Opts'},{type,{330,15},list,[{user_type,{330,16},file_info_option,[]}]}]]},{type,{331,7},constraint,[{atom,{331,7},is_subtype},[{var,{331,7},'FileInfo'},{user_type,{331,19},file_info,[]}]]},{type,{332,7},constraint,[{atom,{332,7},is_subtype},[{var,{332,7},'Reason'},{type,{332,17},union,[{user_type,{332,17},posix,[]},{atom,{332,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,50,53>>,equiv => {function,read_link_info,1},since => <<79,84,80,32,82,49,53,66>>}},{{function,read_link_info,1},[{file,[102,105,108,101,46,101,114,108]},{location,320}],[<<114,101,97,100,95,108,105,110,107,95,105,110,102,111,47,49>>],#{<<101,110>> => [{p,[],[<<87,111,114,107,115,32,108,105,107,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]}]},<<32,101,120,99,101,112,116,32,116,104,97,116,32,105,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,44,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,105,110,107,32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<32,114,101,99,111,114,100,32,97,110,100,32,116,104,101,32>>,{code,[],[<<116,121,112,101>>]},<<32,102,105,101,108,100,32,111,102,32,116,104,101,32,114,101,99,111,114,100,32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<115,121,109,108,105,110,107>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,119,105,108,108,32,98,114,101,97,107,32,116,104,105,115,32,109,111,100,117,108,101,39,115,32,97,116,111,109,105,99,105,116,121,32,103,117,97,114,97,110,116,101,101,115,32,97,115,32,105,116,32,99,97,110,32,114,97,99,101,32,119,105,116,104,32,97,32,99,111,110,99,117,114,114,101,110,116,32,99,97,108,108,32,116,111,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,49,44,50>>]}]}]},{p,[],[<<73,102,32>>,{code,[],[<<78,97,109,101>>]},<<32,105,115,32,110,111,116,32,97,32,115,121,109,98,111,108,105,99,32,108,105,110,107,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32>>,{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]},<<46,32,79,110,32,112,108,97,116,102,111,114,109,115,32,116,104,97,116,32,100,111,32,110,111,116,32,115,117,112,112,111,114,116,32,115,121,109,98,111,108,105,99,32,108,105,110,107,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,97,108,119,97,121,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,97,100,95,102,105,108,101,95,105,110,102,111,47,49>>]},<<46>>]}]},#{signature => [{attribute,{320,2},spec,{{read_link_info,1},[{type,{320,21},bounded_fun,[{type,{320,21},'fun',[{type,{320,21},product,[{var,{320,22},'Name'}]},{type,{320,31},union,[{type,{320,31},tuple,[{atom,{320,32},ok},{var,{320,36},'FileInfo'}]},{type,{320,48},tuple,[{atom,{320,49},error},{var,{320,56},'Reason'}]}]}]},[{type,{321,7},constraint,[{atom,{321,7},is_subtype},[{var,{321,7},'Name'},{user_type,{321,15},name_all,[]}]]},{type,{322,7},constraint,[{atom,{322,7},is_subtype},[{var,{322,7},'FileInfo'},{user_type,{322,19},file_info,[]}]]},{type,{323,7},constraint,[{atom,{323,7},is_subtype},[{var,{323,7},'Reason'},{type,{323,17},union,[{user_type,{323,17},posix,[]},{atom,{323,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,50,53>>,since => <<79,84,80,32,82,49,53,66>>}},{{function,rename,2},[{file,[102,105,108,101,46,101,114,108]},{location,235}],[<<114,101,110,97,109,101,47,50>>],#{<<101,110>> => [{p,[],[<<84,114,105,101,115,32,116,111,32,114,101,110,97,109,101,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,116,111,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32,73,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,111,118,101,32,102,105,108,101,115,32,40,97,110,100,32,100,105,114,101,99,116,111,114,105,101,115,41,32,98,101,116,119,101,101,110,32,100,105,114,101,99,116,111,114,105,101,115,44,32,98,117,116,32,105,116,32,105,115,32,110,111,116,32,115,117,102,102,105,99,105,101,110,116,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,111,110,108,121,46,32,84,104,101,32,100,101,115,116,105,110,97,116,105,111,110,32,102,105,108,101,110,97,109,101,32,109,117,115,116,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32>>,{code,[],[<<98,97,114>>]},<<32,105,115,32,97,32,110,111,114,109,97,108,32,102,105,108,101,32,97,110,100,32>>,{code,[],[<<102,111,111>>]},<<32,97,110,100,32>>,{code,[],[<<98,97,122>>]},<<32,97,114,101,32,100,105,114,101,99,116,111,114,105,101,115,44,32>>,{code,[],[<<114,101,110,97,109,101,40,34,102,111,111,47,98,97,114,34,44,32,34,98,97,122,34,41>>]},<<32,114,101,116,117,114,110,115,32,97,110,32,101,114,114,111,114,44,32,98,117,116,32>>,{code,[],[<<114,101,110,97,109,101,40,34,102,111,111,47,98,97,114,34,44,32,34,98,97,122,47,98,97,114,34,41>>]},<<32,115,117,99,99,101,101,100,115,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,105,116,32,105,115,32,115,117,99,99,101,115,115,102,117,108,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<82,101,110,97,109,105,110,103,32,111,102,32,111,112,101,110,32,102,105,108,101,115,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,111,110,32,109,111,115,116,32,112,108,97,116,102,111,114,109,115,32,40,115,101,101,32>>,{code,[],[<<101,97,99,99,101,115>>]},<<32,98,101,108,111,119,41,46>>]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,114,101,97,100,32,111,114,32,119,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,115,32,102,111,114,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,105,102,32,101,105,116,104,101,114,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,111,112,101,110,46>>]}]},{dt,[],[{code,[],[<<101,101,120,105,115,116>>]}]},{dd,[],[{p,[],[{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,110,111,116,32,97,110,32,101,109,112,116,121,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,97,108,115,111,32,103,105,118,101,110,32,119,104,101,110,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,97,114,101,32,110,111,116,32,111,102,32,116,104,101,32,115,97,109,101,32,116,121,112,101,46>>]}]},{dt,[],[{code,[],[<<101,105,110,118,97,108>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,97,32,114,111,111,116,32,100,105,114,101,99,116,111,114,121,44,32,111,114,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,97,32,115,117,98,100,105,114,101,99,116,111,114,121,32,111,102,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,98,117,116,32>>,{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,44,32,98,117,116,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,105,115,32,110,111,116,46>>]}]},{dt,[],[{code,[],[<<101,120,100,101,118>>]}]},{dd,[],[{p,[],[{code,[],[<<83,111,117,114,99,101>>]},<<32,97,110,100,32>>,{code,[],[<<68,101,115,116,105,110,97,116,105,111,110>>]},<<32,97,114,101,32,111,110,32,100,105,102,102,101,114,101,110,116,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]}]}]},#{signature => [{attribute,{235,2},spec,{{rename,2},[{type,{235,13},bounded_fun,[{type,{235,13},'fun',[{type,{235,13},product,[{var,{235,14},'Source'},{var,{235,22},'Destination'}]},{type,{235,38},union,[{atom,{235,38},ok},{type,{235,43},tuple,[{atom,{235,44},error},{var,{235,51},'Reason'}]}]}]},[{type,{236,7},constraint,[{atom,{236,7},is_subtype},[{var,{236,7},'Source'},{user_type,{236,17},name_all,[]}]]},{type,{237,7},constraint,[{atom,{237,7},is_subtype},[{var,{237,7},'Destination'},{user_type,{237,22},name_all,[]}]]},{type,{238,7},constraint,[{atom,{238,7},is_subtype},[{var,{238,7},'Reason'},{type,{238,17},union,[{user_type,{238,17},posix,[]},{atom,{238,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,55,52,55>>}},{{function,script,1},[{file,[102,105,108,101,46,101,114,108]},{location,1117}],[<<115,99,114,105,112,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,97,100,115,32,97,110,100,32,101,118,97,108,117,97,116,101,115,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,39,46,39,32,40,111,114,32,39,44,39,44,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,97,108,115,111,32,97,110,32,101,120,112,114,101,115,115,105,111,110,41,44,32,102,114,111,109,32,116,104,101,32,102,105,108,101,46>>]},{p,[],[<<82,101,116,117,114,110,115,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<123,111,107,44,32,86,97,108,117,101,125>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,114,101,97,100,32,97,110,100,32,101,118,97,108,117,97,116,101,100,46,32>>,{code,[],[<<86,97,108,117,101>>]},<<32,105,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,97,116,111,109,40,41,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,111,112,101,110,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,114,101,97,100,105,110,103,32,105,116,46,32,70,111,114,32,97,32,108,105,115,116,32,111,102,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,99,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<123,101,114,114,111,114,44,32,123,76,105,110,101,44,32,77,111,100,44,32,84,101,114,109,125,125>>]}]},{dd,[],[{p,[],[<<65,110,32,101,114,114,111,114,32,111,99,99,117,114,114,101,100,32,119,104,101,110,32,105,110,116,101,114,112,114,101,116,105,110,103,32,116,104,101,32,69,114,108,97,110,103,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,102,105,108,101,46,32,85,115,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,102,111,114,109,97,116,95,101,114,114,111,114,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,111,114,109,97,116,95,101,114,114,111,114,47,49>>]}]},<<32,116,111,32,99,111,110,118,101,114,116,32,116,104,101,32,116,104,114,101,101,45,101,108,101,109,101,110,116,32,116,117,112,108,101,32,116,111,32,97,110,32,69,110,103,108,105,115,104,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,97,32,99,111,109,109,101,110,116,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,112,112,35,101,110,99,111,100,105,110,103>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,112,112,40,51,41>>]}]},<<46>>]}]},#{signature => [{attribute,{1117,2},spec,{{script,1},[{type,{1117,13},bounded_fun,[{type,{1117,13},'fun',[{type,{1117,13},product,[{var,{1117,14},'Filename'}]},{type,{1117,27},union,[{type,{1117,27},tuple,[{atom,{1117,28},ok},{var,{1117,32},'Value'}]},{type,{1117,41},tuple,[{atom,{1117,42},error},{var,{1117,49},'Reason'}]}]}]},[{type,{1118,7},constraint,[{atom,{1118,7},is_subtype},[{var,{1118,7},'Filename'},{user_type,{1118,19},name_all,[]}]]},{type,{1119,7},constraint,[{atom,{1119,7},is_subtype},[{var,{1119,7},'Value'},{type,{1119,16},term,[]}]]},{type,{1120,7},constraint,[{atom,{1120,7},is_subtype},[{var,{1120,7},'Reason'},{type,{1120,17},union,[{user_type,{1120,17},posix,[]},{atom,{1120,27},badarg},{atom,{1120,36},terminated},{atom,{1120,49},system_limit},{type,{1121,17},tuple,[{ann_type,{1121,18},[{var,{1121,18},'Line'},{type,{1121,26},integer,[]}]},{ann_type,{1121,37},[{var,{1121,37},'Mod'},{type,{1121,44},module,[]}]},{ann_type,{1121,54},[{var,{1121,54},'Term'},{type,{1121,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,49,48>>}},{{function,script,2},[{file,[102,105,108,101,46,101,114,108]},{location,1126}],[<<115,99,114,105,112,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<115,99,114,105,112,116,47,49>>]},<<32,98,117,116,32,116,104,101,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,32>>,{code,[],[<<66,105,110,100,105,110,103,115>>]},<<32,97,114,101,32,117,115,101,100,32,105,110,32,116,104,101,32,101,118,97,108,117,97,116,105,111,110,46,32,83,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,101,114,108,95,101,118,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<101,114,108,95,101,118,97,108,40,51,41>>]}]},<<32,97,98,111,117,116,32,118,97,114,105,97,98,108,101,32,98,105,110,100,105,110,103,115,46>>]}]},#{signature => [{attribute,{1126,2},spec,{{script,2},[{type,{1126,13},bounded_fun,[{type,{1126,13},'fun',[{type,{1126,13},product,[{var,{1126,14},'Filename'},{var,{1126,24},'Bindings'}]},{type,{1126,37},union,[{type,{1126,37},tuple,[{atom,{1126,38},ok},{var,{1126,42},'Value'}]},{type,{1126,51},tuple,[{atom,{1126,52},error},{var,{1126,59},'Reason'}]}]}]},[{type,{1127,7},constraint,[{atom,{1127,7},is_subtype},[{var,{1127,7},'Filename'},{user_type,{1127,19},name_all,[]}]]},{type,{1128,7},constraint,[{atom,{1128,7},is_subtype},[{var,{1128,7},'Bindings'},{remote_type,{1128,19},[{atom,{1128,19},erl_eval},{atom,{1128,28},binding_struct},[]]}]]},{type,{1129,7},constraint,[{atom,{1129,7},is_subtype},[{var,{1129,7},'Value'},{type,{1129,16},term,[]}]]},{type,{1130,7},constraint,[{atom,{1130,7},is_subtype},[{var,{1130,7},'Reason'},{type,{1130,17},union,[{user_type,{1130,17},posix,[]},{atom,{1130,27},badarg},{atom,{1130,36},terminated},{atom,{1130,49},system_limit},{type,{1131,17},tuple,[{ann_type,{1131,18},[{var,{1131,18},'Line'},{type,{1131,26},integer,[]}]},{ann_type,{1131,37},[{var,{1131,37},'Mod'},{type,{1131,44},module,[]}]},{ann_type,{1131,54},[{var,{1131,54},'Term'},{type,{1131,62},term,[]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,52,53>>}},{{function,sendfile,2},[{file,[102,105,108,101,46,101,114,108]},{location,1311}],[<<115,101,110,100,102,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<83,101,110,100,115,32,116,104,101,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<32,116,111,32>>,{code,[],[<<83,111,99,107,101,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,83,101,110,116,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]}]},#{signature => [{attribute,{1311,2},spec,{{sendfile,2},[{type,{1311,15},bounded_fun,[{type,{1311,15},'fun',[{type,{1311,15},product,[{var,{1311,16},'Filename'},{var,{1311,26},'Socket'}]},{type,{1312,4},union,[{type,{1312,4},tuple,[{atom,{1312,5},ok},{type,{1312,11},non_neg_integer,[]}]},{type,{1312,32},tuple,[{atom,{1312,33},error},{type,{1312,42},union,[{remote_type,{1312,42},[{atom,{1312,42},inet},{atom,{1312,47},posix},[]]},{atom,{1313,5},closed},{atom,{1313,14},badarg},{atom,{1313,23},not_owner}]}]}]}]},[{type,{1314,7},constraint,[{atom,{1314,7},is_subtype},[{var,{1314,7},'Filename'},{user_type,{1314,19},name_all,[]}]]},{type,{1315,7},constraint,[{atom,{1315,7},is_subtype},[{var,{1315,7},'Socket'},{type,{1315,17},union,[{remote_type,{1315,17},[{atom,{1315,17},inet},{atom,{1315,22},socket},[]]},{remote_type,{1315,33},[{atom,{1315,33},socket},{atom,{1315,40},socket},[]]},{type,{1316,22},'fun',[{type,{1316,22},product,[{type,{1316,23},iolist,[]}]},{type,{1316,36},union,[{atom,{1316,36},ok},{type,{1316,41},tuple,[{atom,{1316,42},error},{type,{1316,49},union,[{remote_type,{1316,49},[{atom,{1316,49},inet},{atom,{1316,54},posix},[]]},{atom,{1316,64},closed}]}]}]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,53,53>>,since => <<79,84,80,32,82,49,53,66>>}},{{function,sendfile,5},[{file,[102,105,108,101,46,101,114,108]},{location,1283}],[<<115,101,110,100,102,105,108,101,47,53>>],#{<<101,110>> => [{ul,[{class,<<116,121,112,101,115>>}],[{li,[{name,<<115,101,110,100,102,105,108,101,95,111,112,116,105,111,110>>}],[]}]},{p,[],[<<83,101,110,100,115,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<82,97,119,70,105,108,101>>]},<<32,98,101,103,105,110,110,105,110,103,32,97,116,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,116,111,32>>,{code,[],[<<83,111,99,107,101,116>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<123,111,107,44,32,66,121,116,101,115,83,101,110,116,125>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32,73,102,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,105,115,32,115,101,116,32,116,111,32>>,{code,[],[<<48>>]},<<32,97,108,108,32,100,97,116,97,32,97,102,116,101,114,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32>>,{code,[],[<<79,102,102,115,101,116>>]},<<32,105,115,32,115,101,110,116,46>>]},{p,[],[<<84,104,101,32,102,105,108,101,32,117,115,101,100,32,109,117,115,116,32,98,101,32,111,112,101,110,101,100,32,117,115,105,110,103,32,116,104,101,32>>,{code,[],[<<114,97,119>>]},<<32,102,108,97,103,44,32,97,110,100,32,116,104,101,32,112,114,111,99,101,115,115,32,99,97,108,108,105,110,103,32>>,{code,[],[<<115,101,110,100,102,105,108,101>>]},<<32,109,117,115,116,32,98,101,32,116,104,101,32,99,111,110,116,114,111,108,108,105,110,103,32,112,114,111,99,101,115,115,32,111,102,32,116,104,101,32,115,111,99,107,101,116,46,32,83,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,99,111,110,116,114,111,108,108,105,110,103,95,112,114,111,99,101,115,115,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,110,95,116,99,112,58,99,111,110,116,114,111,108,108,105,110,103,95,112,114,111,99,101,115,115,47,50>>]}]},<<32,111,114,32,109,111,100,117,108,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,115,111,99,107,101,116,35,115,101,116,111,112,116,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,111,99,107,101,116>>]},<<39,115>>]},<<32>>,{a,[{href,<<107,101,114,110,101,108,58,115,111,99,107,101,116,35,111,116,112,95,115,111,99,107,101,116,95,111,112,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[<<108,101,118,101,108,32>>,{code,[],[<<111,116,112>>]},<<32,115,111,99,107,101,116,32,111,112,116,105,111,110,32>>]},{code,[],[<<99,111,110,116,114,111,108,108,105,110,103,95,112,114,111,99,101,115,115>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,79,83,32,117,115,101,100,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,110,111,110,45,98,108,111,99,107,105,110,103,32>>,{code,[],[<<115,101,110,100,102,105,108,101>>]},<<44,32,97,110,32,69,114,108,97,110,103,32,102,97,108,108,98,97,99,107,32,117,115,105,110,103,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,101,97,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,97,100,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<107,101,114,110,101,108,58,103,101,110,95,116,99,112,35,115,101,110,100,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<103,101,110,95,116,99,112,58,115,101,110,100,47,50>>]}]},<<32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<99,104,117,110,107,95,115,105,122,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,99,104,117,110,107,32,115,105,122,101,32,117,115,101,100,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,102,97,108,108,98,97,99,107,32,116,111,32,115,101,110,100,32,100,97,116,97,46,32,73,102,32,117,115,105,110,103,32,116,104,101,32,102,97,108,108,98,97,99,107,44,32,115,101,116,32,116,104,105,115,32,116,111,32,97,32,118,97,108,117,101,32,116,104,97,116,32,99,111,109,102,111,114,116,97,98,108,121,32,102,105,116,115,32,105,110,32,116,104,101,32,115,121,115,116,101,109,115,32,109,101,109,111,114,121,46,32,68,101,102,97,117,108,116,32,105,115,32,50,48,32,77,66,46>>]}]}]}]},#{signature => [{attribute,{1283,2},spec,{{sendfile,5},[{type,{1283,15},bounded_fun,[{type,{1283,15},'fun',[{type,{1283,15},product,[{var,{1283,16},'RawFile'},{var,{1283,25},'Socket'},{var,{1283,33},'Offset'},{var,{1283,41},'Bytes'},{var,{1283,48},'Opts'}]},{type,{1284,4},union,[{type,{1284,4},tuple,[{atom,{1284,5},ok},{type,{1284,11},non_neg_integer,[]}]},{type,{1284,32},tuple,[{atom,{1284,33},error},{type,{1284,42},union,[{remote_type,{1284,42},[{atom,{1284,42},inet},{atom,{1284,47},posix},[]]},{atom,{1285,5},closed},{atom,{1285,14},badarg},{atom,{1285,23},not_owner}]}]}]}]},[{type,{1286,7},constraint,[{atom,{1286,7},is_subtype},[{var,{1286,7},'RawFile'},{user_type,{1286,18},fd,[]}]]},{type,{1287,7},constraint,[{atom,{1287,7},is_subtype},[{var,{1287,7},'Socket'},{type,{1287,17},union,[{remote_type,{1287,17},[{atom,{1287,17},inet},{atom,{1287,22},socket},[]]},{remote_type,{1287,33},[{atom,{1287,33},socket},{atom,{1287,40},socket},[]]},{type,{1288,22},'fun',[{type,{1288,22},product,[{type,{1288,23},iolist,[]}]},{type,{1288,36},union,[{atom,{1288,36},ok},{type,{1288,41},tuple,[{atom,{1288,42},error},{type,{1288,49},union,[{remote_type,{1288,49},[{atom,{1288,49},inet},{atom,{1288,54},posix},[]]},{atom,{1288,64},closed}]}]}]}]}]}]]},{type,{1289,7},constraint,[{atom,{1289,7},is_subtype},[{var,{1289,7},'Offset'},{type,{1289,17},non_neg_integer,[]}]]},{type,{1290,7},constraint,[{atom,{1290,7},is_subtype},[{var,{1290,7},'Bytes'},{type,{1290,16},non_neg_integer,[]}]]},{type,{1291,7},constraint,[{atom,{1291,7},is_subtype},[{var,{1291,7},'Opts'},{type,{1291,15},list,[{user_type,{1291,16},sendfile_option,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,54,52>>,since => <<79,84,80,32,82,49,53,66>>}},{{function,set_cwd,1},[{file,[102,105,108,101,46,101,114,108]},{location,200}],[<<115,101,116,95,99,119,100,47,49>>],#{<<101,110>> => [{p,[],[<<83,101,116,115,32,116,104,101,32,99,117,114,114,101,110,116,32,119,111,114,107,105,110,103,32,100,105,114,101,99,116,111,114,121,32,111,102,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,116,111,32>>,{code,[],[<<68,105,114>>]},<<46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32>>,{code,[],[<<102,105,108,101>>]},<<32,117,115,117,97,108,108,121,32,116,114,101,97,116,32,98,105,110,97,114,105,101,115,32,97,115,32,114,97,119,32,102,105,108,101,110,97,109,101,115,44,32,116,104,97,116,32,105,115,44,32,116,104,101,121,32,97,114,101,32,112,97,115,115,101,100,32,34,97,115,32,105,115,34,32,101,118,101,110,32,119,104,101,110,32,116,104,101,32,101,110,99,111,100,105,110,103,32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,100,111,101,115,32,110,111,116,32,97,103,114,101,101,32,119,105,116,104,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,40,41>>]}]},<<46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,101,120,112,101,99,116,115,32,98,105,110,97,114,105,101,115,32,116,111,32,98,101,32,101,110,99,111,100,101,100,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,118,97,108,117,101,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{code,[],[<<110,97,116,105,118,101,95,110,97,109,101,95,101,110,99,111,100,105,110,103,40,41>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,32,97,114,101,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,100,105,114,101,99,116,111,114,121,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32>>,{code,[],[<<68,105,114>>]},<<32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,116,104,101,32,100,105,114,101,99,116,111,114,121,32,111,114,32,111,110,101,32,111,102,32,105,116,115,32,112,97,114,101,110,116,115,46>>]}]},{dt,[],[{code,[],[<<98,97,100,97,114,103>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,114>>]},<<32,104,97,115,32,97,110,32,105,109,112,114,111,112,101,114,32,116,121,112,101,44,32,115,117,99,104,32,97,115,32,116,117,112,108,101,46>>]}]},{dt,[],[{code,[],[<<110,111,95,116,114,97,110,115,108,97,116,105,111,110>>]}]},{dd,[],[{p,[],[{code,[],[<<68,105,114>>]},<<32,105,115,32,97,32>>,{code,[],[<<98,105,110,97,114,121,40,41>>]},<<32,119,105,116,104,32,99,104,97,114,97,99,116,101,114,115,32,99,111,100,101,100,32,105,110,32,73,83,79,45,108,97,116,105,110,45,49,32,97,110,100,32,116,104,101,32,86,77,32,105,115,32,111,112,101,114,97,116,105,110,103,32,119,105,116,104,32,117,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,101,110,99,111,100,105,110,103,46>>]}]}]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,110,32,97,32,102,117,116,117,114,101,32,114,101,108,101,97,115,101,44,32,97,32,98,97,100,32,116,121,112,101,32,102,111,114,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<68,105,114>>]},<<32,119,105,108,108,32,112,114,111,98,97,98,108,121,32,103,101,110,101,114,97,116,101,32,97,110,32,101,120,99,101,112,116,105,111,110,46>>]}]}]},#{signature => [{attribute,{200,2},spec,{{set_cwd,1},[{type,{200,14},bounded_fun,[{type,{200,14},'fun',[{type,{200,14},product,[{var,{200,15},'Dir'}]},{type,{200,23},union,[{atom,{200,23},ok},{type,{200,28},tuple,[{atom,{200,29},error},{var,{200,36},'Reason'}]}]}]},[{type,{201,7},constraint,[{atom,{201,7},is_subtype},[{var,{201,7},'Dir'},{type,{201,14},union,[{user_type,{201,14},name,[]},{var,{201,23},'EncodedBinary'}]}]]},{type,{202,7},constraint,[{atom,{202,7},is_subtype},[{var,{202,7},'EncodedBinary'},{type,{202,24},binary,[]}]]},{type,{203,7},constraint,[{atom,{203,7},is_subtype},[{var,{203,7},'Reason'},{type,{203,17},union,[{user_type,{203,17},posix,[]},{atom,{203,27},badarg},{atom,{203,36},no_translation}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,56,57,55>>}},{{function,sync,1},[{file,[102,105,108,101,46,101,114,108]},{location,736}],[<<115,121,110,99,47,49>>],#{<<101,110>> => [{p,[],[<<69,110,115,117,114,101,115,32,116,104,97,116,32,97,110,121,32,98,117,102,102,101,114,115,32,107,101,112,116,32,98,121,32,116,104,101,32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,109,32,40,110,111,116,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,114,117,110,116,105,109,101,32,115,121,115,116,101,109,41,32,97,114,101,32,119,114,105,116,116,101,110,32,116,111,32,100,105,115,107,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,109,105,103,104,116,32,104,97,118,101,32,110,111,32,101,102,102,101,99,116,46>>]},{p,[],[<<65,32,116,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,32,105,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,116,32,101,110,111,117,103,104,32,115,112,97,99,101,32,108,101,102,116,32,116,111,32,119,114,105,116,101,32,116,104,101,32,102,105,108,101,46>>]}]}]}]},#{signature => [{attribute,{736,2},spec,{{sync,1},[{type,{736,11},bounded_fun,[{type,{736,11},'fun',[{type,{736,11},product,[{var,{736,12},'IoDevice'}]},{type,{736,25},union,[{atom,{736,25},ok},{type,{736,30},tuple,[{atom,{736,31},error},{var,{736,38},'Reason'}]}]}]},[{type,{737,7},constraint,[{atom,{737,7},is_subtype},[{var,{737,7},'IoDevice'},{user_type,{737,19},io_device,[]}]]},{type,{738,7},constraint,[{atom,{738,7},is_subtype},[{var,{738,7},'Reason'},{type,{738,17},union,[{user_type,{738,17},posix,[]},{atom,{738,27},badarg},{atom,{738,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,52,52>>}},{{function,truncate,1},[{file,[102,105,108,101,46,101,114,108]},{location,760}],[<<116,114,117,110,99,97,116,101,47,49>>],#{<<101,110>> => [{p,[],[<<84,114,117,110,99,97,116,101,115,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]}]},#{signature => [{attribute,{760,2},spec,{{truncate,1},[{type,{760,15},bounded_fun,[{type,{760,15},'fun',[{type,{760,15},product,[{var,{760,16},'IoDevice'}]},{type,{760,29},union,[{atom,{760,29},ok},{type,{760,34},tuple,[{atom,{760,35},error},{var,{760,42},'Reason'}]}]}]},[{type,{761,7},constraint,[{atom,{761,7},is_subtype},[{var,{761,7},'IoDevice'},{user_type,{761,19},io_device,[]}]]},{type,{762,7},constraint,[{atom,{762,7},is_subtype},[{var,{762,7},'Reason'},{type,{762,17},union,[{user_type,{762,17},posix,[]},{atom,{762,27},badarg},{atom,{762,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,54,48>>}},{{function,write,2},[{file,[102,105,108,101,46,101,114,108]},{location,670}],[<<119,114,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,116,111,32,116,104,101,32,102,105,108,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32>>,{code,[],[<<73,111,68,101,118,105,99,101>>]},<<46,32,84,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,111,32,119,114,105,116,101,32,116,111,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{code,[],[<<114,97,119>>]},<<32,109,111,100,101,32,40,97,108,116,104,111,117,103,104,32,105,116,32,119,111,114,107,115,32,102,111,114,32,110,111,114,109,97,108,108,121,32,111,112,101,110,101,100,32,102,105,108,101,115,32,116,111,111,41,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,97,110,100,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<32,111,116,104,101,114,119,105,115,101,46>>]},{p,[],[<<73,102,32,116,104,101,32,102,105,108,101,32,105,115,32,111,112,101,110,101,100,32,119,105,116,104,32>>,{code,[],[<<101,110,99,111,100,105,110,103>>]},<<32,115,101,116,32,116,111,32,115,111,109,101,116,104,105,110,103,32,101,108,115,101,32,116,104,97,110,32>>,{code,[],[<<108,97,116,105,110,49>>]},<<44,32,101,97,99,104,32,98,121,116,101,32,119,114,105,116,116,101,110,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,109,97,110,121,32,98,121,116,101,115,32,98,101,105,110,103,32,119,114,105,116,116,101,110,32,116,111,32,116,104,101,32,102,105,108,101,44,32,97,115,32,116,104,101,32,98,121,116,101,32,114,97,110,103,101,32,48,46,46,50,53,53,32,99,97,110,32,114,101,112,114,101,115,101,110,116,32,97,110,121,116,104,105,110,103,32,98,101,116,119,101,101,110,32,111,110,101,32,97,110,100,32,102,111,117,114,32,98,121,116,101,115,32,100,101,112,101,110,100,105,110,103,32,111,110,32,118,97,108,117,101,32,97,110,100,32,85,84,70,32,101,110,99,111,100,105,110,103,32,116,121,112,101,46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,98,97,100,102>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,105,115,32,110,111,116,32,111,112,101,110,101,100,32,102,111,114,32,119,114,105,116,105,110,103,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]}]}]},#{signature => [{attribute,{670,2},spec,{{write,2},[{type,{670,12},bounded_fun,[{type,{670,12},'fun',[{type,{670,12},product,[{var,{670,13},'IoDevice'},{var,{670,23},'Bytes'}]},{type,{670,33},union,[{atom,{670,33},ok},{type,{670,38},tuple,[{atom,{670,39},error},{var,{670,46},'Reason'}]}]}]},[{type,{671,7},constraint,[{atom,{671,7},is_subtype},[{var,{671,7},'IoDevice'},{type,{671,19},union,[{user_type,{671,19},io_device,[]},{type,{671,33},atom,[]}]}]]},{type,{672,7},constraint,[{atom,{672,7},is_subtype},[{var,{672,7},'Bytes'},{type,{672,16},iodata,[]}]]},{type,{673,7},constraint,[{atom,{673,7},is_subtype},[{var,{673,7},'Reason'},{type,{673,17},union,[{user_type,{673,17},posix,[]},{atom,{673,27},badarg},{atom,{673,36},terminated}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,54,57>>}},{{function,write_file,2},[{file,[102,105,108,101,46,101,114,108]},{location,437}],[<<119,114,105,116,101,95,102,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<87,114,105,116,101,115,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,116,104,101,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<32,116,101,114,109,32>>,{code,[],[<<66,121,116,101,115>>]},<<32,116,111,32,102,105,108,101,32>>,{code,[],[<<70,105,108,101,110,97,109,101>>]},<<46,32,84,104,101,32,102,105,108,101,32,105,115,32,99,114,101,97,116,101,100,32,105,102,32,105,116,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46,32,73,102,32,105,116,32,101,120,105,115,116,115,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,111,110,116,101,110,116,115,32,97,114,101,32,111,118,101,114,119,114,105,116,116,101,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46>>]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]},{dt,[],[{code,[],[<<101,110,111,115,112,99>>]}]},{dd,[],[{p,[],[<<78,111,32,115,112,97,99,101,32,105,115,32,108,101,102,116,32,111,110,32,116,104,101,32,100,101,118,105,99,101,46>>]}]},{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,119,114,105,116,105,110,103,32,116,104,101,32,102,105,108,101,32,111,114,32,115,101,97,114,99,104,105,110,103,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<101,105,115,100,105,114>>]}]},{dd,[],[{p,[],[<<84,104,101,32,110,97,109,101,100,32,102,105,108,101,32,105,115,32,97,32,100,105,114,101,99,116,111,114,121,46>>]}]}]}]},#{signature => [{attribute,{437,2},spec,{{write_file,2},[{type,{437,17},bounded_fun,[{type,{437,17},'fun',[{type,{437,17},product,[{var,{437,18},'Filename'},{var,{437,28},'Bytes'}]},{type,{437,38},union,[{atom,{437,38},ok},{type,{437,43},tuple,[{atom,{437,44},error},{var,{437,51},'Reason'}]}]}]},[{type,{438,7},constraint,[{atom,{438,7},is_subtype},[{var,{438,7},'Filename'},{user_type,{438,19},name_all,[]}]]},{type,{439,7},constraint,[{atom,{439,7},is_subtype},[{var,{439,7},'Bytes'},{type,{439,16},iodata,[]}]]},{type,{440,7},constraint,[{atom,{440,7},is_subtype},[{var,{440,7},'Reason'},{type,{440,17},union,[{user_type,{440,17},posix,[]},{atom,{440,27},badarg},{atom,{440,36},terminated},{atom,{440,49},system_limit}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,49,57,57,53>>}},{{function,write_file,3},[{file,[102,105,108,101,46,101,114,108]},{location,449}],[<<119,114,105,116,101,95,102,105,108,101,47,51>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<119,114,105,116,101,95,102,105,108,101,47,50>>]},<<44,32,98,117,116,32,116,97,107,101,115,32,97,32,116,104,105,114,100,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<77,111,100,101,115>>]},<<44,32,97,32,108,105,115,116,32,111,102,32,112,111,115,115,105,98,108,101,32,109,111,100,101,115,44,32,115,101,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<46,32,84,104,101,32,109,111,100,101,32,102,108,97,103,115,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,97,110,100,32>>,{code,[],[<<119,114,105,116,101>>]},<<32,97,114,101,32,105,109,112,108,105,99,105,116,44,32,115,111,32,116,104,101,121,32,97,114,101,32,110,111,116,32,116,111,32,98,101,32,117,115,101,100,46>>]}]},#{signature => [{attribute,{449,2},spec,{{write_file,3},[{type,{449,17},bounded_fun,[{type,{449,17},'fun',[{type,{449,17},product,[{var,{449,18},'Filename'},{var,{449,28},'Bytes'},{var,{449,35},'Modes'}]},{type,{449,45},union,[{atom,{449,45},ok},{type,{449,50},tuple,[{atom,{449,51},error},{var,{449,58},'Reason'}]}]}]},[{type,{450,7},constraint,[{atom,{450,7},is_subtype},[{var,{450,7},'Filename'},{user_type,{450,19},name_all,[]}]]},{type,{451,7},constraint,[{atom,{451,7},is_subtype},[{var,{451,7},'Bytes'},{type,{451,16},iodata,[]}]]},{type,{452,7},constraint,[{atom,{452,7},is_subtype},[{var,{452,7},'Modes'},{type,{452,16},list,[{user_type,{452,17},mode,[]}]}]]},{type,{453,7},constraint,[{atom,{453,7},is_subtype},[{var,{453,7},'Reason'},{type,{453,17},union,[{user_type,{453,17},posix,[]},{atom,{453,27},badarg},{atom,{453,36},terminated},{atom,{453,49},system_limit}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,51,50>>}},{{function,write_file_info,3},[{file,[102,105,108,101,46,101,114,108]},{location,374}],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,51>>],#{},#{signature => [{attribute,{374,2},spec,{{write_file_info,3},[{type,{374,22},bounded_fun,[{type,{374,22},'fun',[{type,{374,22},product,[{var,{374,23},'Filename'},{var,{374,33},'FileInfo'},{var,{374,43},'Opts'}]},{type,{374,52},union,[{atom,{374,52},ok},{type,{374,57},tuple,[{atom,{374,58},error},{var,{374,65},'Reason'}]}]}]},[{type,{375,7},constraint,[{atom,{375,7},is_subtype},[{var,{375,7},'Filename'},{user_type,{375,19},name_all,[]}]]},{type,{376,7},constraint,[{atom,{376,7},is_subtype},[{var,{376,7},'Opts'},{type,{376,15},list,[{user_type,{376,16},file_info_option,[]}]}]]},{type,{377,7},constraint,[{atom,{377,7},is_subtype},[{var,{377,7},'FileInfo'},{user_type,{377,19},file_info,[]}]]},{type,{378,7},constraint,[{atom,{378,7},is_subtype},[{var,{378,7},'Reason'},{type,{378,17},union,[{user_type,{378,17},posix,[]},{atom,{378,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,52,51>>,equiv => {function,write_file_info,2},since => <<79,84,80,32,82,49,53,66>>}},{{function,write_file_info,2},[{file,[102,105,108,101,46,101,114,108]},{location,366}],[<<119,114,105,116,101,95,102,105,108,101,95,105,110,102,111,47,50>>],#{<<101,110>> => [{p,[],[<<67,104,97,110,103,101,115,32,102,105,108,101,32,105,110,102,111,114,109,97,116,105,111,110,46,32,82,101,116,117,114,110,115,32>>,{code,[],[<<111,107>>]},<<32,105,102,32,115,117,99,99,101,115,115,102,117,108,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<123,101,114,114,111,114,44,32,82,101,97,115,111,110,125>>]},<<46,32>>,{code,[],[<<70,105,108,101,73,110,102,111>>]},<<32,105,115,32,97,32,114,101,99,111,114,100,32>>,{code,[],[<<102,105,108,101,95,105,110,102,111>>]},<<44,32,100,101,102,105,110,101,100,32,105,110,32,116,104,101,32,75,101,114,110,101,108,32,105,110,99,108,117,100,101,32,102,105,108,101,32>>,{code,[],[<<102,105,108,101,46,104,114,108>>]},<<46,32,73,110,99,108,117,100,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,100,105,114,101,99,116,105,118,101,32,105,110,32,116,104,101,32,109,111,100,117,108,101,32,102,114,111,109,32,119,104,105,99,104,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<32,45,105,110,99,108,117,100,101,95,108,105,98,40,34,107,101,114,110,101,108,47,105,110,99,108,117,100,101,47,102,105,108,101,46,104,114,108,34,41,46>>]}]},{p,[],[<<84,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<97,116,105,109,101>>]},<<44,32>>,{code,[],[<<109,116,105,109,101>>]},<<44,32,97,110,100,32>>,{code,[],[<<99,116,105,109,101>>]},<<32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,116,105,109,101,32,116,121,112,101,32,115,101,116,32,105,110,32>>,{code,[],[<<79,112,116,115,32,58,58,32,123,116,105,109,101,44,32,84,121,112,101,125>>]},<<32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<108,111,99,97,108>>]}]},{dd,[],[{p,[],[<<73,110,116,101,114,112,114,101,116,115,32,116,104,101,32,116,105,109,101,32,115,101,116,32,97,115,32,108,111,99,97,108,46>>]}]},{dt,[],[{code,[],[<<117,110,105,118,101,114,115,97,108>>]}]},{dd,[],[{p,[],[<<73,110,116,101,114,112,114,101,116,115,32,105,116,32,97,115,32,117,110,105,118,101,114,115,97,108,32,116,105,109,101,46>>]}]},{dt,[],[{code,[],[<<112,111,115,105,120>>]}]},{dd,[],[{p,[],[<<77,117,115,116,32,98,101,32,115,101,99,111,110,100,115,32,115,105,110,99,101,32,111,114,32,98,101,102,111,114,101,32,85,110,105,120,32,116,105,109,101,32,101,112,111,99,104,44,32,119,104,105,99,104,32,105,115,32,49,57,55,48,45,48,49,45,48,49,32,48,48,58,48,48,32,85,84,67,46>>]}]}]},{p,[],[<<68,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,116,105,109,101,44,32,108,111,99,97,108,125>>]},<<46>>]},{p,[],[<<73,102,32,116,104,101,32,111,112,116,105,111,110,32>>,{code,[],[<<114,97,119>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,102,105,108,101,32,115,101,114,118,101,114,32,105,115,32,110,111,116,32,99,97,108,108,101,100,32,97,110,100,32,111,110,108,121,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,108,111,99,97,108,32,102,105,108,101,115,32,105,115,32,114,101,116,117,114,110,101,100,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,101,108,100,115,32,97,114,101,32,117,115,101,100,32,102,114,111,109,32,116,104,101,32,114,101,99,111,114,100,44,32,105,102,32,116,104,101,121,32,97,114,101,32,115,112,101,99,105,102,105,101,100,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,114,101,97,100,46>>]}]},{dt,[],[{code,[],[<<109,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,108,97,115,116,32,116,105,109,101,32,116,104,101,32,102,105,108,101,32,119,97,115,32,119,114,105,116,116,101,110,46>>]}]},{dt,[],[{code,[],[<<99,116,105,109,101,32,61,32>>]},{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,100,97,116,101,95,116,105,109,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<100,97,116,101,95,116,105,109,101,40,41>>]}]},{code,[],[<<32,124,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<79,110,32,85,110,105,120,44,32,97,110,121,32,118,97,108,117,101,32,115,112,101,99,105,102,105,101,100,32,102,111,114,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,105,103,110,111,114,101,100,32,40,116,104,101,32,34,99,116,105,109,101,34,32,102,111,114,32,116,104,101,32,102,105,108,101,32,105,115,32,115,101,116,32,116,111,32,116,104,101,32,99,117,114,114,101,110,116,32,116,105,109,101,41,46,32,79,110,32,87,105,110,100,111,119,115,44,32,116,104,105,115,32,102,105,101,108,100,32,105,115,32,116,104,101,32,110,101,119,32,99,114,101,97,116,105,111,110,32,116,105,109,101,32,116,111,32,115,101,116,32,102,111,114,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<109,111,100,101,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,112,101,114,109,105,115,115,105,111,110,115,32,97,115,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,98,105,116,32,118,97,108,117,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<56,35,48,48,52,48,48>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,50,48,48>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,49,48,48>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,119,110,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,52,48>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,50,48>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,49,48>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,103,114,111,117,112>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,52>>]}]},{dd,[],[{p,[],[<<82,101,97,100,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,50>>]}]},{dd,[],[{p,[],[<<87,114,105,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<56,35,48,48,48,48,49>>]}]},{dd,[],[{p,[],[<<69,120,101,99,117,116,101,32,112,101,114,109,105,115,115,105,111,110,58,32,111,116,104,101,114>>]}]},{dt,[],[{code,[],[<<49,54,35,56,48,48>>]}]},{dd,[],[{p,[],[<<83,101,116,32,117,115,101,114,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]},{dt,[],[{code,[],[<<49,54,35,52,48,48>>]}]},{dd,[],[{p,[],[<<83,101,116,32,103,114,111,117,112,32,105,100,32,111,110,32,101,120,101,99,117,116,105,111,110>>]}]}]},{p,[],[<<79,110,32,85,110,105,120,32,112,108,97,116,102,111,114,109,115,44,32,111,116,104,101,114,32,98,105,116,115,32,116,104,97,110,32,116,104,111,115,101,32,108,105,115,116,101,100,32,97,98,111,118,101,32,109,97,121,32,98,101,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<117,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<73,110,100,105,99,97,116,101,115,32,116,104,101,32,102,105,108,101,32,111,119,110,101,114,46,32,73,103,110,111,114,101,100,32,102,111,114,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]},{dt,[],[{code,[],[<<103,105,100,32,61,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,32,102,105,108,101,32,111,119,110,101,114,32,98,101,108,111,110,103,115,32,116,111,46,32,73,103,110,111,114,101,100,32,102,111,114,32,110,111,110,45,85,110,105,120,32,102,105,108,101,32,115,121,115,116,101,109,115,46>>]}]}]},{p,[],[<<84,121,112,105,99,97,108,32,101,114,114,111,114,32,114,101,97,115,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<101,97,99,99,101,115>>]}]},{dd,[],[{p,[],[<<77,105,115,115,105,110,103,32,115,101,97,114,99,104,32,112,101,114,109,105,115,115,105,111,110,32,102,111,114,32,111,110,101,32,111,102,32,116,104,101,32,112,97,114,101,110,116,32,100,105,114,101,99,116,111,114,105,101,115,32,111,102,32,116,104,101,32,102,105,108,101,46>>]}]},{dt,[],[{code,[],[<<101,110,111,101,110,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,102,105,108,101,32,100,111,101,115,32,110,111,116,32,101,120,105,115,116,46>>]}]},{dt,[],[{code,[],[<<101,110,111,116,100,105,114>>]}]},{dd,[],[{p,[],[<<65,32,99,111,109,112,111,110,101,110,116,32,111,102,32,116,104,101,32,102,105,108,101,110,97,109,101,32,105,115,32,110,111,116,32,97,32,100,105,114,101,99,116,111,114,121,46,32,79,110,32,115,111,109,101,32,112,108,97,116,102,111,114,109,115,44,32>>,{code,[],[<<101,110,111,101,110,116>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,105,110,115,116,101,97,100,46>>]}]}]}]},#{signature => [{attribute,{366,2},spec,{{write_file_info,2},[{type,{366,22},bounded_fun,[{type,{366,22},'fun',[{type,{366,22},product,[{var,{366,23},'Filename'},{var,{366,33},'FileInfo'}]},{type,{366,46},union,[{atom,{366,46},ok},{type,{366,51},tuple,[{atom,{366,52},error},{var,{366,59},'Reason'}]}]}]},[{type,{367,7},constraint,[{atom,{367,7},is_subtype},[{var,{367,7},'Filename'},{user_type,{367,19},name_all,[]}]]},{type,{368,7},constraint,[{atom,{368,7},is_subtype},[{var,{368,7},'FileInfo'},{user_type,{368,19},file_info,[]}]]},{type,{369,7},constraint,[{atom,{369,7},is_subtype},[{var,{369,7},'Reason'},{type,{369,17},union,[{user_type,{369,17},posix,[]},{atom,{369,27},badarg}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,107,101,114,110,101,108,47,100,111,99,47,115,114,99,47,102,105,108,101,46,120,109,108,35,76,50,48,52,51>>,since => <<79,84,80,32,82,49,53,66>>}},{{type,deep_list,0},[{file,[102,105,108,101,46,101,114,108]},{location,102}],[<<45,116,121,112,101,32,100,101,101,112,95,108,105,115,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{102,2},type,{deep_list,{type,{102,22},list,[{type,{102,23},union,[{type,{102,23},char,[]},{type,{102,32},atom,[]},{user_type,{102,41},deep_list,[]}]}]},[]}}]}},{{type,fd,0},[{file,[102,105,108,101,46,101,114,108]},{location,0}],[<<102,100,40,41>>],#{<<101,110>> => [{p,[],[<<65,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,102,105,108,101,32,111,112,101,110,101,100,32,105,110,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,114,97,119>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<114,97,119>>]}]},<<32,109,111,100,101,46>>]}]},#{}},{{type,filename,0},[{file,[102,105,108,101,46,101,114,108]},{location,85}],[<<45,116,121,112,101,32,102,105,108,101,110,97,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,{85,2},type,{filename,{type,{85,22},string,[]},[]}}]}},{{type,filename_all,0},[{file,[102,105,108,101,46,101,114,108]},{location,86}],[<<45,116,121,112,101,32,102,105,108,101,110,97,109,101,95,97,108,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,{86,2},type,{filename_all,{type,{86,25},union,[{type,{86,25},string,[]},{type,{86,36},binary,[]}]},[]}}]}},{{type,io_device,0},[{file,[102,105,108,101,46,101,114,108]},{location,89}],[<<45,116,121,112,101,32,105,111,95,100,101,118,105,99,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,115,32,114,101,116,117,114,110,101,100,32,98,121,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,111,112,101,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<111,112,101,110,47,50>>]}]},<<59,32>>,{code,[],[<<112,105,100,40,41>>]},<<32,105,115,32,97,32,112,114,111,99,101,115,115,32,104,97,110,100,108,105,110,103,32,73,47,79,45,112,114,111,116,111,99,111,108,115,46>>]}]},#{signature => [{attribute,{89,2},type,{io_device,{type,{89,22},union,[{type,{89,22},pid,[]},{user_type,{89,30},fd,[]}]},[]}}]}},{{type,name,0},[{file,[102,105,108,101,46,101,114,108]},{location,103}],[<<45,116,121,112,101,32,110,97,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<73,102,32,86,77,32,105,115,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,44,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<32,97,110,100,32>>,{code,[],[<<99,104,97,114,40,41>>]},<<32,97,114,101,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,62,32,50,53,53,46,32,83,101,101,32,97,108,115,111,32,116,104,101,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,111,102,32,116,104,101,32>>,{a,[{href,<<107,101,114,110,101,108,58,102,105,108,101,35,110,97,109,101,95,97,108,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,116,121,112,101>>}],[{code,[],[<<110,97,109,101,95,97,108,108,40,41>>]}]},<<32,116,121,112,101,46>>]}]},#{signature => [{attribute,{103,2},type,{name,{type,{103,22},union,[{type,{103,22},string,[]},{type,{103,33},atom,[]},{user_type,{103,42},deep_list,[]}]},[]}}]}},{{type,name_all,0},[{file,[102,105,108,101,46,101,114,108]},{location,104}],[<<45,116,121,112,101,32,110,97,109,101,95,97,108,108,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<73,102,32,86,77,32,105,115,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,108,108,111,119,101,100,32,116,111,32,98,101,32,62,32,50,53,53,46,32>>,{code,[],[<<82,97,119,70,105,108,101,110,97,109,101>>]},<<32,105,115,32,97,32,102,105,108,101,110,97,109,101,32,110,111,116,32,115,117,98,106,101,99,116,32,116,111,32,85,110,105,99,111,100,101,32,116,114,97,110,115,108,97,116,105,111,110,44,32,109,101,97,110,105,110,103,32,116,104,97,116,32,105,116,32,99,97,110,32,99,111,110,116,97,105,110,32,99,104,97,114,97,99,116,101,114,115,32,110,111,116,32,99,111,110,102,111,114,109,105,110,103,32,116,111,32,116,104,101,32,85,110,105,99,111,100,101,32,101,110,99,111,100,105,110,103,32,101,120,112,101,99,116,101,100,32,102,114,111,109,32,116,104,101,32,102,105,108,101,32,115,121,115,116,101,109,32,40,116,104,97,116,32,105,115,44,32,110,111,110,45,85,84,70,45,56,32,99,104,97,114,97,99,116,101,114,115,32,97,108,116,104,111,117,103,104,32,116,104,101,32,86,77,32,105,115,32,115,116,97,114,116,101,100,32,105,110,32,85,110,105,99,111,100,101,32,102,105,108,101,110,97,109,101,32,109,111,100,101,41,46,32,78,117,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,116,101,103,101,114,32,118,97,108,117,101,32,122,101,114,111,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,97,108,108,111,119,101,100,32,105,110,32,102,105,108,101,110,97,109,101,115,32,40,110,111,116,32,101,118,101,110,32,97,116,32,116,104,101,32,101,110,100,41,46>>]}]},#{signature => [{attribute,{104,2},type,{name_all,{type,{104,22},union,[{type,{104,22},string,[]},{type,{104,33},atom,[]},{user_type,{104,42},deep_list,[]},{ann_type,{104,57},[{var,{104,57},'RawFilename'},{type,{104,72},binary,[]}]}]},[]}}]}},{{type,posix,0},[{file,[102,105,108,101,46,101,114,108]},{location,105}],[<<45,116,121,112,101,32,112,111,115,105,120,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32,97,116,111,109,32,116,104,97,116,32,105,115,32,110,97,109,101,100,32,102,114,111,109,32,116,104,101,32,80,79,83,73,88,32,101,114,114,111,114,32,99,111,100,101,115,32,117,115,101,100,32,105,110,32,85,110,105,120,44,32,97,110,100,32,105,110,32,116,104,101,32,114,117,110,116,105,109,101,32,108,105,98,114,97,114,105,101,115,32,111,102,32,109,111,115,116,32,67,32,99,111,109,112,105,108,101,114,115,46>>]}]},#{signature => [{attribute,{105,2},type,{posix,{type,{106,9},union,[{atom,{106,9},eacces},{atom,{106,20},eagain},{atom,{107,9},ebadf},{atom,{107,19},ebadmsg},{atom,{107,31},ebusy},{atom,{108,9},edeadlk},{atom,{108,21},edeadlock},{atom,{108,35},edquot},{atom,{109,9},eexist},{atom,{110,9},efault},{atom,{110,20},efbig},{atom,{110,30},eftype},{atom,{111,9},eintr},{atom,{111,19},einval},{atom,{111,30},eio},{atom,{111,38},eisdir},{atom,{112,9},eloop},{atom,{113,9},emfile},{atom,{113,20},emlink},{atom,{113,31},emultihop},{atom,{114,9},enametoolong},{atom,{114,26},enfile},{atom,{115,9},enobufs},{atom,{115,21},enodev},{atom,{115,32},enolck},{atom,{115,43},enolink},{atom,{115,55},enoent},{atom,{116,9},enomem},{atom,{116,20},enospc},{atom,{116,31},enosr},{atom,{116,41},enostr},{atom,{116,52},enosys},{atom,{117,9},enotblk},{atom,{117,21},enotdir},{atom,{117,33},enotsup},{atom,{117,45},enxio},{atom,{118,9},eopnotsupp},{atom,{118,24},eoverflow},{atom,{119,9},eperm},{atom,{119,19},epipe},{atom,{120,9},erange},{atom,{120,20},erofs},{atom,{121,9},espipe},{atom,{121,21},esrch},{atom,{121,32},estale},{atom,{122,9},etxtbsy},{atom,{123,9},exdev}]},[]}}]}},{{type,date_time,0},[{file,[102,105,108,101,46,101,114,108]},{location,124}],[<<45,116,121,112,101,32,100,97,116,101,95,116,105,109,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<77,117,115,116,32,100,101,110,111,116,101,32,97,32,118,97,108,105,100,32,100,97,116,101,32,97,110,100,32,116,105,109,101,46>>]}]},#{signature => [{attribute,{124,2},type,{date_time,{remote_type,{124,22},[{atom,{124,22},calendar},{atom,{124,31},datetime},[]]},[]}}]}},{{type,file_info,0},[{file,[102,105,108,101,46,101,114,108]},{location,87}],[<<45,116,121,112,101,32,102,105,108,101,95,105,110,102,111,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{87,2},type,{file_info,{type,{87,22},record,[{atom,{87,23},file_info}]},[]}}]}},{{type,location,0},[{file,[102,105,108,101,46,101,114,108]},{location,90}],[<<45,116,121,112,101,32,108,111,99,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{90,2},type,{location,{type,{90,22},union,[{type,{90,22},integer,[]},{type,{90,34},tuple,[{atom,{90,35},bof},{ann_type,{90,42},[{var,{90,42},'Offset'},{type,{90,52},integer,[]}]}]},{type,{91,22},tuple,[{atom,{91,23},cur},{ann_type,{91,30},[{var,{91,30},'Offset'},{type,{91,40},integer,[]}]}]},{type,{92,8},tuple,[{atom,{92,9},eof},{ann_type,{92,16},[{var,{92,16},'Offset'},{type,{92,26},integer,[]}]}]},{atom,{92,39},bof},{atom,{92,47},cur},{atom,{92,55},eof}]},[]}}]}},{{type,mode,0},[{file,[102,105,108,101,46,101,114,108]},{location,93}],[<<45,116,121,112,101,32,109,111,100,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{93,2},type,{mode,{type,{93,22},union,[{atom,{93,22},read},{atom,{93,31},write},{atom,{93,41},append},{atom,{94,22},exclusive},{atom,{94,36},raw},{atom,{94,44},binary},{type,{95,8},tuple,[{atom,{95,9},delayed_write},{ann_type,{96,23},[{var,{96,23},'Size'},{type,{96,31},non_neg_integer,[]}]},{ann_type,{97,23},[{var,{97,23},'Delay'},{type,{97,32},non_neg_integer,[]}]}]},{atom,{98,8},delayed_write},{type,{98,26},tuple,[{atom,{98,27},read_ahead},{ann_type,{98,41},[{var,{98,41},'Size'},{type,{98,49},pos_integer,[]}]}]},{atom,{99,8},read_ahead},{atom,{99,23},compressed},{atom,{99,38},compressed_one},{type,{100,8},tuple,[{atom,{100,9},encoding},{remote_type,{100,21},[{atom,{100,21},unicode},{atom,{100,29},encoding},[]]}]},{atom,{101,8},sync}]},[]}}]}},{{type,file_info_option,0},[{file,[102,105,108,101,46,101,114,108]},{location,130}],[<<45,116,121,112,101,32,102,105,108,101,95,105,110,102,111,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{130,2},type,{file_info_option,{type,{130,29},union,[{type,{130,29},tuple,[{atom,{130,30},time},{atom,{130,38},local}]},{type,{130,49},tuple,[{atom,{130,50},time},{atom,{130,58},universal}]},{type,{131,8},tuple,[{atom,{131,9},time},{atom,{131,17},posix}]},{atom,{131,28},raw}]},[]}}]}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file.txt index 647b56c5c547..56a005e28080 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file.txt @@ -120,7 +120,7 @@ • estale - Stale remote file handle - • exdev - Cross-domain link + • exdev - Cross-device link Performance diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_altname_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_altname_1_func.txt new file mode 100644 index 000000000000..7082445a7877 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_altname_1_func.txt @@ -0,0 +1,5 @@ + +  altname/1 + + The documentation for altname/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_copy_opened_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_copy_opened_3_func.txt new file mode 100644 index 000000000000..142c86eff48f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_copy_opened_3_func.txt @@ -0,0 +1,6 @@ + +  copy_opened/3 + + The documentation for copy_opened/3 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_1_func.txt index 88be4438f6c6..5b66b4ba6719 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_1_func.txt @@ -2,6 +2,9 @@ -spec delete(Filename) -> ok | {error, Reason}  when Filename :: name_all(), Reason :: posix() | badarg. +Since: + OTP 24.0 + Types: -type delete_option() :: raw. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_2_func.txt index 53c318502775..d8cc8befc7bb 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_delete_2_func.txt @@ -5,6 +5,9 @@  Opts :: [delete_option()],  Reason :: posix() | badarg. +Since: + OTP 24.0 + Types: -type delete_option() :: raw. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_fd_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_fd_0_type.txt index f08c589b484e..5c9f9fae53a9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_fd_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_fd_0_type.txt @@ -1,4 +1,4 @@ - -type fd() :: #file_descriptor{}. +  fd() A file descriptor representing a file opened in raw mode. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_3_func.txt new file mode 100644 index 000000000000..85a88fa38f0b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_3_func.txt @@ -0,0 +1,6 @@ + +  ipread_s32bu_p32bu/3 + + The documentation for ipread_s32bu_p32bu/3 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_int_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_int_3_func.txt new file mode 100644 index 000000000000..de346114dd31 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_ipread_s32bu_p32bu_int_3_func.txt @@ -0,0 +1,6 @@ + +  ipread_s32bu_p32bu_int/3 + + The documentation for ipread_s32bu_p32bu_int/3 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_mode_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_mode_0_type.txt index 662b060153af..7ff959d515c4 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_mode_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_mode_0_type.txt @@ -6,7 +6,7 @@  Delay :: non_neg_integer()} |  delayed_write |  {read_ahead, Size :: pos_integer()} | -  read_ahead | compressed | +  read_ahead | compressed | compressed_one |  {encoding, unicode:encoding()} |  sync. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_open_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_open_2_func.txt index 24ca2b24d623..45bc221cfeb1 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_open_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_open_2_func.txt @@ -113,6 +113,10 @@ read_file_info/1 does probably not match the number of bytes that can be read from a compressed file. + compressed_one: + Read one member of a gzip compressed file. Option  + compressed_one can only be combined with read. + {encoding, Encoding}: Makes the file perform automatic translation of characters to and from a specific (Unicode) encoding. Notice that the data @@ -217,6 +221,15 @@ returned from this call can be used as an argument to the I/O functions (see io(3)). + Warning: + While this function can be used to open any file, we recommend + against using it for NFS-mounted files, FIFOs, devices, or + similar since they can cause IO threads to hang forever. + + If your application needs to interact with these kinds of + files we recommend breaking out those parts to a port program + instead. + Note: In previous versions of file, modes were specified as one of the atoms read, write, or read_write instead of a list. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_path_eval_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_path_eval_3_func.txt new file mode 100644 index 000000000000..828e8cf9f80b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_path_eval_3_func.txt @@ -0,0 +1,5 @@ + +  path_eval/3 + + The documentation for path_eval/3 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_pid2name_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_pid2name_1_func.txt index 425cf1df4020..796759482234 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_pid2name_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_pid2name_1_func.txt @@ -2,6 +2,14 @@ -spec pid2name(Pid) -> {ok, Filename} | undefined  when Filename :: filename_all(), Pid :: pid(). +Deprecated: + file:pid2name/1 is deprecated and will be removed in OTP 27; this + functionality is no longer supported + + Change: + This function is deprecated and will be removed in Erlang/OTP + 27. + If Pid is an I/O device, that is, a pid returned from open/2, this function returns the filename, or rather: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_read_file_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_read_file_info_1_func.txt new file mode 100644 index 000000000000..88576426f9b0 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_read_file_info_1_func.txt @@ -0,0 +1,6 @@ + +  raw_read_file_info/1 + + The documentation for raw_read_file_info/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_write_file_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_write_file_info_2_func.txt new file mode 100644 index 000000000000..5b9650666c81 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_raw_write_file_info_2_func.txt @@ -0,0 +1,6 @@ + +  raw_write_file_info/2 + + The documentation for raw_write_file_info/2 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_1_func.txt index d997bdf4f100..c5d25d6581ff 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_1_func.txt @@ -50,8 +50,9 @@ size = integer() >= 0: Size of file in bytes. - type = device | directory | other | regular | symlink: - The type of the file. + type = device | directory | other | regular: + The type of the file. Can also contain symlink when returned + from read_link_info/1,2. access = read | write | read_write | none: The current system access to the file. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_2_func.txt index c8ad4f7215c4..53a644dea1f0 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_read_file_info_2_func.txt @@ -51,8 +51,9 @@ size = integer() >= 0: Size of file in bytes. - type = device | directory | other | regular | symlink: - The type of the file. + type = device | directory | other | regular: + The type of the file. Can also contain symlink when returned + from read_link_info/1,2. access = read | write | read_write | none: The current system access to the file. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_2_func.txt index d22adad04f97..0ccfaf7e01cd 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_2_func.txt @@ -2,7 +2,13 @@ -spec sendfile(Filename, Socket) ->  {ok, non_neg_integer()} |  {error, inet:posix() | closed | badarg | not_owner} -  when Filename :: name_all(), Socket :: inet:socket(). +  when +  Filename :: name_all(), +  Socket :: +  inet:socket() | +  socket:socket() | +  fun((iolist()) -> +  ok | {error, inet:posix() | closed}). Since: OTP R15B diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_5_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_5_func.txt index ae2cc2957816..991f012cb5f0 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_5_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_sendfile_5_func.txt @@ -4,7 +4,11 @@  {error, inet:posix() | closed | badarg | not_owner}  when  RawFile :: fd(), -  Socket :: inet:socket(), +  Socket :: +  inet:socket() | +  socket:socket() | +  fun((iolist()) -> +  ok | {error, inet:posix() | closed}),  Offset :: non_neg_integer(),  Bytes :: non_neg_integer(),  Opts :: [sendfile_option()]. @@ -23,7 +27,8 @@ The file used must be opened using the raw flag, and the process calling sendfile must be the controlling process of the socket. - See gen_tcp:controlling_process/2. + See gen_tcp:controlling_process/2 or module socket's level  + otp socket option controlling_process. If the OS used does not support non-blocking sendfile, an Erlang fallback using read/2 and gen_tcp:send/2 is used. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_type.txt index 130858a8f3cc..2f8f0c2009ac 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_file_type.txt @@ -4,7 +4,7 @@ These types are documented in this module: -type deep_list() :: [char() | atom() | deep_list()]. - -type fd() :: #file_descriptor{}. +  fd() -type filename() :: string(). @@ -45,7 +45,7 @@ These types are documented in this module:  Delay :: non_neg_integer()} |  delayed_write |  {read_ahead, Size :: pos_integer()} | -  read_ahead | compressed | +  read_ahead | compressed | compressed_one |  {encoding, unicode:encoding()} |  sync. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv.txt new file mode 100644 index 000000000000..2392dee3c358 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv.txt @@ -0,0 +1,5 @@ + + user_drv + + The documentation for user_drv is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_callback_mode_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_callback_mode_0_func.txt new file mode 100644 index 000000000000..b999236eb592 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_callback_mode_0_func.txt @@ -0,0 +1,6 @@ + +  callback_mode/0 + + The documentation for callback_mode/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_cb.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_cb.txt new file mode 100644 index 000000000000..d6ddedfc1af6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_cb.txt @@ -0,0 +1,3 @@ + user_drv + +There are no callbacks in this module diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_1_func.txt new file mode 100644 index 000000000000..f64397f84a9b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_1_func.txt @@ -0,0 +1,5 @@ + +  init/1 + + The documentation for init/1 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_3_func.txt new file mode 100644 index 000000000000..3a0345f03092 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_init_3_func.txt @@ -0,0 +1,5 @@ + +  init/3 + + The documentation for init/3 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_interfaces_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_interfaces_1_func.txt new file mode 100644 index 000000000000..f693b6761736 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_interfaces_1_func.txt @@ -0,0 +1,6 @@ + +  interfaces/1 + + The documentation for interfaces/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_2_func.txt new file mode 100644 index 000000000000..a9c626e643b2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_2_func.txt @@ -0,0 +1,5 @@ + +  server/2 + + The documentation for server/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_3_func.txt new file mode 100644 index 000000000000..372628b87964 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_server_3_func.txt @@ -0,0 +1,5 @@ + +  server/3 + + The documentation for server/3 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_0_func.txt new file mode 100644 index 000000000000..7b934422574f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_0_func.txt @@ -0,0 +1,5 @@ + +  start/0 + + The documentation for start/0 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_1_func.txt new file mode 100644 index 000000000000..123e70566ad2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_1_func.txt @@ -0,0 +1,5 @@ + +  start/1 + + The documentation for start/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_2_func.txt new file mode 100644 index 000000000000..cb801a2351ad --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_2_func.txt @@ -0,0 +1,5 @@ + +  start/2 + + The documentation for start/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_3_func.txt new file mode 100644 index 000000000000..91d7dae25a6e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_3_func.txt @@ -0,0 +1,5 @@ + +  start/3 + + The documentation for start/3 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_0_func.txt new file mode 100644 index 000000000000..e8e5eed9bc6d --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_0_func.txt @@ -0,0 +1,6 @@ + +  start_shell/0 + + The documentation for start_shell/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_1_func.txt new file mode 100644 index 000000000000..54a4c7d9614c --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_start_shell_1_func.txt @@ -0,0 +1,6 @@ + +  start_shell/1 + + The documentation for start_shell/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_switch_loop_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_switch_loop_3_func.txt new file mode 100644 index 000000000000..7f54185896ab --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_switch_loop_3_func.txt @@ -0,0 +1,6 @@ + +  switch_loop/3 + + The documentation for switch_loop/3 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_type.txt new file mode 100644 index 000000000000..5d7d0ce01221 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_type.txt @@ -0,0 +1,3 @@ + user_drv + +There are no types in this module diff --git a/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_whereis_group_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_whereis_group_0_func.txt new file mode 100644 index 000000000000..a13da7c1841e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/kernel_user_drv_whereis_group_0_func.txt @@ -0,0 +1,6 @@ + +  whereis_group/0 + + The documentation for whereis_group/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/re.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/re.docs_v1 index 3d2107fdcf16..511c24152dbd 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/re.docs_v1 +++ b/lib/stdlib/test/shell_docs_SUITE_data/re.docs_v1 @@ -1 +1 @@ -{docs_v1,[{file,[114,101,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,99,111,110,116,97,105,110,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,32,102,111,114,32,115,116,114,105,110,103,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110>>]},<<32,115,121,110,116,97,120,32,97,110,100,32,115,101,109,97,110,116,105,99,115,32,114,101,115,101,109,98,108,101,32,116,104,97,116,32,111,102,32,80,101,114,108,46>>]},{p,[],[<<84,104,101,32,109,97,116,99,104,105,110,103,32,97,108,103,111,114,105,116,104,109,115,32,111,102,32,116,104,101,32,108,105,98,114,97,114,121,32,97,114,101,32,98,97,115,101,100,32,111,110,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,44,32,98,117,116,32,110,111,116,32,97,108,108,32,111,102,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,105,115,32,105,110,116,101,114,102,97,99,101,100,32,97,110,100,32,115,111,109,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,108,105,98,114,97,114,121,32,103,111,32,98,101,121,111,110,100,32,119,104,97,116,32,80,67,82,69,32,111,102,102,101,114,115,46,32,67,117,114,114,101,110,116,108,121,32,80,67,82,69,32,118,101,114,115,105,111,110,32,56,46,52,48,32,40,114,101,108,101,97,115,101,32,100,97,116,101,32,50,48,49,55,45,48,49,45,49,49,41,32,105,115,32,117,115,101,100,46,32,84,104,101,32,115,101,99,116,105,111,110,115,32,111,102,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,116,104,97,116,32,97,114,101,32,114,101,108,101,118,97,110,116,32,116,111,32,116,104,105,115,32,109,111,100,117,108,101,32,97,114,101,32,105,110,99,108,117,100,101,100,32,104,101,114,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,108,105,116,101,114,97,108,32,115,121,110,116,97,120,32,102,111,114,32,115,116,114,105,110,103,115,32,117,115,101,115,32,116,104,101,32,34,92,34,32,40,98,97,99,107,115,108,97,115,104,41,32,99,104,97,114,97,99,116,101,114,32,97,115,32,97,110,32,101,115,99,97,112,101,32,99,111,100,101,46,32,89,111,117,32,110,101,101,100,32,116,111,32,101,115,99,97,112,101,32,98,97,99,107,115,108,97,115,104,101,115,32,105,110,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,115,44,32,98,111,116,104,32,105,110,32,121,111,117,114,32,99,111,100,101,32,97,110,100,32,105,110,32,116,104,101,32,115,104,101,108,108,44,32,119,105,116,104,32,97,110,32,101,120,116,114,97,32,98,97,99,107,115,108,97,115,104,44,32,116,104,97,116,32,105,115,44,32,34,92,92,34,46>>]}]},{a,[{id,<<114,101,103,101,120,112,95,115,121,110,116,97,120>>}],[]},{h2,[],[<<80,101,114,108,45,76,105,107,101,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,83,121,110,116,97,120>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,99,111,110,116,97,105,110,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,32,102,111,114,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,117,115,101,100,32,98,121,32,116,104,105,115,32,109,111,100,117,108,101,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,119,105,116,104,32,99,104,97,110,103,101,115,32,119,104,101,114,101,32,116,104,105,115,32,109,111,100,117,108,101,32,98,101,104,97,118,101,115,32,100,105,102,102,101,114,101,110,116,108,121,32,116,111,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,46>>]},{a,[{id,<<114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>}],[]},{h2,[],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},{p,[],[<<84,104,101,32,115,121,110,116,97,120,32,97,110,100,32,115,101,109,97,110,116,105,99,115,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,100,101,116,97,105,108,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,46,32,80,101,114,108,39,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,105,116,115,32,111,119,110,32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,97,110,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,103,101,110,101,114,97,108,32,97,114,101,32,99,111,118,101,114,101,100,32,105,110,32,109,97,110,121,32,98,111,111,107,115,44,32,115,111,109,101,32,119,105,116,104,32,99,111,112,105,111,117,115,32,101,120,97,109,112,108,101,115,46,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,39,115,32,34,77,97,115,116,101,114,105,110,103,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,115,34,44,32,112,117,98,108,105,115,104,101,100,32,98,121,32,79,39,82,101,105,108,108,121,44,32,99,111,118,101,114,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,103,114,101,97,116,32,100,101,116,97,105,108,46,32,84,104,105,115,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,80,67,82,69,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,105,110,116,101,110,100,101,100,32,97,115,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,46>>]},{p,[],[<<84,104,101,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,32,105,115,32,100,105,118,105,100,101,100,32,105,110,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,112,101,99,105,97,108,32,83,116,97,114,116,45,111,102,45,80,97,116,116,101,114,110,32,73,116,101,109,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,104,97,114,97,99,116,101,114,115,32,97,110,100,32,77,101,116,97,99,104,97,114,97,99,116,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,115,108,97,115,104>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,105,114,99,117,109,102,108,101,120,32,97,110,100,32,68,111,108,108,97,114>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<70,117,108,108,32,83,116,111,112,32,40,80,101,114,105,111,100,44,32,68,111,116,41,32,97,110,100,32,92,78>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,54>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<77,97,116,99,104,105,110,103,32,97,32,83,105,110,103,108,101,32,68,97,116,97,32,85,110,105,116>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,55>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,113,117,97,114,101,32,66,114,97,99,107,101,116,115,32,97,110,100,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,56>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,111,115,105,120,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<86,101,114,116,105,99,97,108,32,66,97,114>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<73,110,116,101,114,110,97,108,32,79,112,116,105,111,110,32,83,101,116,116,105,110,103>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,97,109,101,100,32,83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<82,101,112,101,116,105,116,105,111,110>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<65,116,111,109,105,99,32,71,114,111,117,112,105,110,103,32,97,110,100,32,80,111,115,115,101,115,115,105,118,101,32,81,117,97,110,116,105,102,105,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,54>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,55>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<65,115,115,101,114,116,105,111,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,56>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,110,100,105,116,105,111,110,97,108,32,83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,109,109,101,110,116,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<82,101,99,117,114,115,105,118,101,32,80,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<79,110,105,103,117,114,117,109,97,32,83,117,98,114,111,117,116,105,110,101,32,83,121,110,116,97,120>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108>>]}]}]},{a,[{id,<<115,101,99,116,49>>}],[]},{h2,[],[<<83,112,101,99,105,97,108,32,83,116,97,114,116,45,111,102,45,80,97,116,116,101,114,110,32,73,116,101,109,115>>]},{p,[],[<<83,111,109,101,32,111,112,116,105,111,110,115,32,116,104,97,116,32,99,97,110,32,98,101,32,112,97,115,115,101,100,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,115,112,101,99,105,97,108,32,105,116,101,109,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,46,32,84,104,101,115,101,32,97,114,101,32,110,111,116,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,44,32,98,117,116,32,97,114,101,32,112,114,111,118,105,100,101,100,32,116,111,32,109,97,107,101,32,116,104,101,115,101,32,111,112,116,105,111,110,115,32,97,99,99,101,115,115,105,98,108,101,32,116,111,32,112,97,116,116,101,114,110,32,119,114,105,116,101,114,115,32,119,104,111,32,97,114,101,32,110,111,116,32,97,98,108,101,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,112,114,111,103,114,97,109,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,115,101,32,105,116,101,109,115,32,99,97,110,32,97,112,112,101,97,114,44,32,98,117,116,32,116,104,101,121,32,109,117,115,116,32,97,108,108,32,98,101,32,116,111,103,101,116,104,101,114,32,114,105,103,104,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,101,32,108,101,116,116,101,114,115,32,109,117,115,116,32,98,101,32,105,110,32,117,112,112,101,114,32,99,97,115,101,46>>]},{p,[],[{em,[],[<<85,84,70,32,83,117,112,112,111,114,116>>]}]},{p,[],[<<85,110,105,99,111,100,101,32,115,117,112,112,111,114,116,32,105,115,32,98,97,115,105,99,97,108,108,121,32,85,84,70,45,56,32,98,97,115,101,100,46,32,84,111,32,117,115,101,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,44,32,121,111,117,32,101,105,116,104,101,114,32,99,97,108,108,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,111,114,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,115,58>>]},{pre,[],[{code,[],[<<40,42,85,84,70,56,41,10,40,42,85,84,70,41>>]}]},{p,[],[<<66,111,116,104,32,111,112,116,105,111,110,115,32,103,105,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,44,32,116,104,101,32,105,110,112,117,116,32,115,116,114,105,110,103,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,85,84,70,45,56,46,32,78,111,116,105,99,101,32,116,104,97,116,32,119,105,116,104,32,116,104,101,115,101,32,105,110,115,116,114,117,99,116,105,111,110,115,44,32,116,104,101,32,97,117,116,111,109,97,116,105,99,32,99,111,110,118,101,114,115,105,111,110,32,111,102,32,108,105,115,116,115,32,116,111,32,85,84,70,45,56,32,105,115,32,110,111,116,32,112,101,114,102,111,114,109,101,100,32,98,121,32,116,104,101,32>>,{code,[],[<<114,101>>]},<<32,102,117,110,99,116,105,111,110,115,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,105,110,103,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,105,115,32,110,111,116,32,114,101,99,111,109,109,101,110,100,101,100,46,32,65,100,100,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,119,104,101,110,32,114,117,110,110,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<83,111,109,101,32,97,112,112,108,105,99,97,116,105,111,110,115,32,116,104,97,116,32,97,108,108,111,119,32,116,104,101,105,114,32,117,115,101,114,115,32,116,111,32,115,117,112,112,108,121,32,112,97,116,116,101,114,110,115,32,99,97,110,32,119,105,115,104,32,116,111,32,114,101,115,116,114,105,99,116,32,116,104,101,109,32,116,111,32,110,111,110,45,85,84,70,32,100,97,116,97,32,102,111,114,32,115,101,99,117,114,105,116,121,32,114,101,97,115,111,110,115,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<110,101,118,101,114,95,117,116,102>>]},<<32,105,115,32,115,101,116,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,40,42,85,84,70,41,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,110,111,116,32,97,108,108,111,119,101,100,44,32,97,110,100,32,116,104,101,105,114,32,97,112,112,101,97,114,97,110,99,101,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,46>>]},{p,[],[{em,[],[<<85,110,105,99,111,100,101,32,80,114,111,112,101,114,116,121,32,83,117,112,112,111,114,116>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,97,110,111,116,104,101,114,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32,116,104,97,116,32,99,97,110,32,97,112,112,101,97,114,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,42,85,67,80,41>>]}]},{p,[],[<<84,104,105,115,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<58,32,105,116,32,99,97,117,115,101,115,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32,92,100,32,97,110,100,32,92,119,32,116,111,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,116,111,32,100,101,116,101,114,109,105,110,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,44,32,105,110,115,116,101,97,100,32,111,102,32,114,101,99,111,103,110,105,122,105,110,103,32,111,110,108,121,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,115,32,60,32,50,53,54,32,116,104,114,111,117,103,104,32,97,32,108,111,111,107,117,112,32,116,97,98,108,101,46>>]},{p,[],[{em,[],[<<68,105,115,97,98,108,105,110,103,32,83,116,97,114,116,117,112,32,79,112,116,105,109,105,122,97,116,105,111,110,115>>]}]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32>>,{code,[],[<<40,42,78,79,95,83,84,65,82,84,95,79,80,84,41>>]},<<44,32,105,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46>>]},{p,[],[{em,[],[<<78,101,119,108,105,110,101,32,67,111,110,118,101,110,116,105,111,110,115>>]}]},{a,[{id,<<110,101,119,108,105,110,101,95,99,111,110,118,101,110,116,105,111,110,115>>}],[]},{p,[],[<<80,67,82,69,32,115,117,112,112,111,114,116,115,32,102,105,118,101,32,99,111,110,118,101,110,116,105,111,110,115,32,102,111,114,32,105,110,100,105,99,97,116,105,110,103,32,108,105,110,101,32,98,114,101,97,107,115,32,105,110,32,115,116,114,105,110,103,115,58,32,97,32,115,105,110,103,108,101,32,67,82,32,40,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,41,32,99,104,97,114,97,99,116,101,114,44,32,97,32,115,105,110,103,108,101,32,76,70,32,40,108,105,110,101,32,102,101,101,100,41,32,99,104,97,114,97,99,116,101,114,44,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,44,32,97,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,44,32,97,110,100,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,46>>]},{p,[],[<<65,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,115,116,97,114,116,105,110,103,32,97,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,118,101,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<40,42,67,82,41>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110>>]},{dt,[],[<<40,42,76,70,41>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100>>]},{dt,[],[<<40,42,67,82,76,70,41>>]},{dd,[],[<<62,67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,102,111,108,108,111,119,101,100,32,98,121,32,108,105,110,101,32,102,101,101,100>>]},{dt,[],[<<40,42,65,78,89,67,82,76,70,41>>]},{dd,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,97,98,111,118,101>>]},{dt,[],[<<40,42,65,78,89,41>>]},{dd,[],[<<65,108,108,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115>>]}]},{p,[],[<<84,104,101,115,101,32,111,118,101,114,114,105,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,97,110,100,32,116,104,101,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,99,104,97,110,103,101,115,32,116,104,101,32,99,111,110,118,101,110,116,105,111,110,32,116,111,32,67,82,58>>]},{pre,[],[{code,[],[<<40,42,67,82,41,97,46,98>>]}]},{p,[],[<<84,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32>>,{code,[],[<<97,92,110,98>>]},<<44,32,97,115,32,76,70,32,105,115,32,110,111,32,108,111,110,103,101,114,32,97,32,110,101,119,108,105,110,101,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,108,97,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,97,102,102,101,99,116,115,32,119,104,101,114,101,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,116,114,117,101,46,32,73,116,32,97,108,115,111,32,97,102,102,101,99,116,115,32,116,104,101,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,116,104,101,32,100,111,116,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,119,104,101,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,110,111,116,32,115,101,116,44,32,97,110,100,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,92,78,46,32,72,111,119,101,118,101,114,44,32,105,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,119,104,97,116,32,116,104,101,32,92,82,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,109,97,116,99,104,101,115,46,32,66,121,32,100,101,102,97,117,108,116,44,32,116,104,105,115,32,105,115,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,59,32,115,101,101,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,92,82,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]},<<46,32,65,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,92,82,32,115,101,116,116,105,110,103,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,97,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,46>>]},{p,[],[{em,[],[<<83,101,116,116,105,110,103,32,77,97,116,99,104,32,97,110,100,32,82,101,99,117,114,115,105,111,110,32,76,105,109,105,116,115>>]}]},{p,[],[<<84,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,99,97,110,32,115,101,116,32,97,32,108,105,109,105,116,32,111,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,40,41,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,97,110,100,32,111,110,32,116,104,101,32,109,97,120,105,109,117,109,32,100,101,112,116,104,32,111,102,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,46,32,84,104,101,115,101,32,102,97,99,105,108,105,116,105,101,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,116,111,32,99,97,116,99,104,32,114,117,110,97,119,97,121,32,109,97,116,99,104,101,115,32,116,104,97,116,32,97,114,101,32,112,114,111,118,111,107,101,100,32,98,121,32,112,97,116,116,101,114,110,115,32,119,105,116,104,32,104,117,103,101,32,109,97,116,99,104,105,110,103,32,116,114,101,101,115,32,40,97,32,116,121,112,105,99,97,108,32,101,120,97,109,112,108,101,32,105,115,32,97,32,112,97,116,116,101,114,110,32,119,105,116,104,32,110,101,115,116,101,100,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,41,32,97,110,100,32,116,111,32,97,118,111,105,100,32,114,117,110,110,105,110,103,32,111,117,116,32,111,102,32,115,121,115,116,101,109,32,115,116,97,99,107,32,98,121,32,116,111,111,32,109,117,99,104,32,114,101,99,117,114,115,105,111,110,46,32,87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,108,105,109,105,116,115,32,105,115,32,114,101,97,99,104,101,100,44,32>>,{code,[],[<<112,99,114,101,95,101,120,101,99,40,41>>]},<<32,103,105,118,101,115,32,97,110,32,101,114,114,111,114,32,114,101,116,117,114,110,46,32,84,104,101,32,108,105,109,105,116,115,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,105,116,101,109,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{pre,[],[{code,[],[<<40,42,76,73,77,73,84,95,77,65,84,67,72,61,100,41,10,40,42,76,73,77,73,84,95,82,69,67,85,82,83,73,79,78,61,100,41>>]}]},{p,[],[<<72,101,114,101,32,100,32,105,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,100,101,99,105,109,97,108,32,100,105,103,105,116,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,115,101,116,116,105,110,103,32,109,117,115,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,118,97,108,117,101,32,115,101,116,32,98,121,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,102,111,114,32,105,116,32,116,111,32,104,97,118,101,32,97,110,121,32,101,102,102,101,99,116,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,119,114,105,116,101,114,32,99,97,110,32,108,111,119,101,114,32,116,104,101,32,108,105,109,105,116,32,115,101,116,32,98,121,32,116,104,101,32,112,114,111,103,114,97,109,109,101,114,44,32,98,117,116,32,110,111,116,32,114,97,105,115,101,32,105,116,46,32,73,102,32,116,104,101,114,101,32,105,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,101,116,116,105,110,103,32,111,102,32,111,110,101,32,111,102,32,116,104,101,115,101,32,108,105,109,105,116,115,44,32,116,104,101,32,108,111,119,101,114,32,118,97,108,117,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32,98,111,116,104,32,116,104,101,32,108,105,109,105,116,115,32,105,115,32,49,48,44,48,48,48,44,48,48,48,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,86,77,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,108,105,109,105,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,115,116,97,99,107,32,100,101,112,116,104,32,111,102,32,116,104,101,32,86,77,44,32,97,115,32,80,67,82,69,32,102,111,114,32,69,114,108,97,110,103,32,105,115,32,99,111,109,112,105,108,101,100,32,105,110,32,115,117,99,104,32,97,32,119,97,121,32,116,104,97,116,32,116,104,101,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,110,101,118,101,114,32,100,111,101,115,32,114,101,99,117,114,115,105,111,110,32,111,110,32,116,104,101,32,67,32,115,116,97,99,107,46>>]},{p,[],[<<78,111,116,101,32,116,104,97,116,32>>,{code,[],[<<76,73,77,73,84,95,77,65,84,67,72>>]},<<32,97,110,100,32>>,{code,[],[<<76,73,77,73,84,95,82,69,67,85,82,83,73,79,78>>]},<<32,99,97,110,32,111,110,108,121,32,114,101,100,117,99,101,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,105,109,105,116,115,32,115,101,116,32,98,121,32,116,104,101,32,99,97,108,108,101,114,44,32,110,111,116,32,105,110,99,114,101,97,115,101,32,116,104,101,109,46>>]},{a,[{id,<<115,101,99,116,50>>}],[]},{h2,[],[<<67,104,97,114,97,99,116,101,114,115,32,97,110,100,32,77,101,116,97,99,104,97,114,97,99,116,101,114,115>>]},{p,[],[<<65,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,46,32,77,111,115,116,32,99,104,97,114,97,99,116,101,114,115,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,32,97,110,100,32,109,97,116,99,104,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,65,115,32,97,32,116,114,105,118,105,97,108,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,112,111,114,116,105,111,110,32,111,102,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,105,100,101,110,116,105,99,97,108,32,116,111,32,105,116,115,101,108,102,58>>]},{pre,[],[{code,[],[<<84,104,101,32,113,117,105,99,107,32,98,114,111,119,110,32,102,111,120>>]}]},{p,[],[<<87,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,112,101,99,105,102,105,101,100,32,40,111,112,116,105,111,110,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<41,44,32,108,101,116,116,101,114,115,32,97,114,101,32,109,97,116,99,104,101,100,32,105,110,100,101,112,101,110,100,101,110,116,108,121,32,111,102,32,99,97,115,101,46>>]},{p,[],[<<84,104,101,32,112,111,119,101,114,32,111,102,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,99,111,109,101,115,32,102,114,111,109,32,116,104,101,32,97,98,105,108,105,116,121,32,116,111,32,105,110,99,108,117,100,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,114,101,112,101,116,105,116,105,111,110,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,115,101,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,121,32,116,104,101,32,117,115,101,32,111,102,32>>,{em,[],[<<109,101,116,97,99,104,97,114,97,99,116,101,114,115>>]},<<44,32,119,104,105,99,104,32,100,111,32,110,111,116,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,32,98,117,116,32,105,110,115,116,101,97,100,32,97,114,101,32,105,110,116,101,114,112,114,101,116,101,100,32,105,110,32,115,111,109,101,32,115,112,101,99,105,97,108,32,119,97,121,46>>]},{p,[],[<<84,119,111,32,115,101,116,115,32,111,102,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,101,120,105,115,116,58,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,97,110,121,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,101,120,99,101,112,116,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,44,32,97,110,100,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,46,32,79,117,116,115,105,100,101,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,44,32,116,104,101,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<92>>]},{dd,[],[<<71,101,110,101,114,97,108,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,109,97,110,121,32,117,115,101,115>>]},{dt,[],[<<94>>]},{dd,[],[<<65,115,115,101,114,116,32,115,116,97,114,116,32,111,102,32,115,116,114,105,110,103,32,40,111,114,32,108,105,110,101,44,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41>>]},{dt,[],[<<36>>]},{dd,[],[<<65,115,115,101,114,116,32,101,110,100,32,111,102,32,115,116,114,105,110,103,32,40,111,114,32,108,105,110,101,44,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41>>]},{dt,[],[<<46>>]},{dd,[],[<<77,97,116,99,104,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,101,120,99,101,112,116,32,110,101,119,108,105,110,101,32,40,98,121,32,100,101,102,97,117,108,116,41>>]},{dt,[],[<<91>>]},{dd,[],[<<83,116,97,114,116,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,100,101,102,105,110,105,116,105,111,110>>]},{dt,[],[<<124>>]},{dd,[],[<<83,116,97,114,116,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104>>]},{dt,[],[<<40>>]},{dd,[],[<<83,116,97,114,116,32,115,117,98,112,97,116,116,101,114,110>>]},{dt,[],[<<41>>]},{dd,[],[<<69,110,100,32,115,117,98,112,97,116,116,101,114,110>>]},{dt,[],[<<63>>]},{dd,[],[<<69,120,116,101,110,100,115,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,40,44,32,97,108,115,111,32,48,32,111,114,32,49,32,113,117,97,110,116,105,102,105,101,114,44,32,97,108,115,111,32,113,117,97,110,116,105,102,105,101,114,32,109,105,110,105,109,105,122,101,114>>]},{dt,[],[<<42>>]},{dd,[],[<<48,32,111,114,32,109,111,114,101,32,113,117,97,110,116,105,102,105,101,114,115>>]},{dt,[],[<<43>>]},{dd,[],[<<49,32,111,114,32,109,111,114,101,32,113,117,97,110,116,105,102,105,101,114,44,32,97,108,115,111,32,34,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,34>>]},{dt,[],[<<123>>]},{dd,[],[<<83,116,97,114,116,32,109,105,110,47,109,97,120,32,113,117,97,110,116,105,102,105,101,114>>]}]},{p,[],[<<80,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,32,105,115,32,99,97,108,108,101,100,32,97,32,34,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,34,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,111,110,108,121,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,58>>]},{dl,[],[{dt,[],[<<92>>]},{dd,[],[<<71,101,110,101,114,97,108,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<94>>]},{dd,[],[<<78,101,103,97,116,101,32,116,104,101,32,99,108,97,115,115,44,32,98,117,116,32,111,110,108,121,32,105,102,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<45>>]},{dd,[],[<<73,110,100,105,99,97,116,101,115,32,99,104,97,114,97,99,116,101,114,32,114,97,110,103,101>>]},{dt,[],[<<91>>]},{dd,[],[<<80,111,115,105,120,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,40,111,110,108,121,32,105,102,32,102,111,108,108,111,119,101,100,32,98,121,32,80,111,115,105,120,32,115,121,110,116,97,120,41>>]},{dt,[],[<<93>>]},{dd,[],[<<84,101,114,109,105,110,97,116,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,100,101,115,99,114,105,98,101,32,116,104,101,32,117,115,101,32,111,102,32,101,97,99,104,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46>>]},{a,[{id,<<115,101,99,116,51>>}],[]},{h2,[],[<<66,97,99,107,115,108,97,115,104>>]},{p,[],[<<84,104,101,32,98,97,99,107,115,108,97,115,104,32,99,104,97,114,97,99,116,101,114,32,104,97,115,32,109,97,110,121,32,117,115,101,115,46,32,70,105,114,115,116,44,32,105,102,32,105,116,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,110,117,109,98,101,114,32,111,114,32,97,32,108,101,116,116,101,114,44,32,105,116,32,116,97,107,101,115,32,97,119,97,121,32,97,110,121,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,116,104,97,116,32,97,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,104,97,118,101,46,32,84,104,105,115,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,97,115,32,97,110,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114,32,97,112,112,108,105,101,115,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,97,32,42,32,99,104,97,114,97,99,116,101,114,44,32,121,111,117,32,119,114,105,116,101,32,92,42,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,105,115,32,101,115,99,97,112,105,110,103,32,97,99,116,105,111,110,32,97,112,112,108,105,101,115,32,105,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,32,119,111,117,108,100,32,111,116,104,101,114,119,105,115,101,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,109,101,116,97,99,104,97,114,97,99,116,101,114,44,32,115,111,32,105,116,32,105,115,32,97,108,119,97,121,115,32,115,97,102,101,32,116,111,32,112,114,101,99,101,100,101,32,97,32,110,111,110,45,97,108,112,104,97,110,117,109,101,114,105,99,32,119,105,116,104,32,98,97,99,107,115,108,97,115,104,32,116,111,32,115,112,101,99,105,102,121,32,116,104,97,116,32,105,116,32,115,116,97,110,100,115,32,102,111,114,32,105,116,115,101,108,102,46,32,73,110,32,112,97,114,116,105,99,117,108,97,114,44,32,105,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,97,32,98,97,99,107,115,108,97,115,104,44,32,119,114,105,116,101,32,92,92,46>>]},{p,[],[<<73,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,109,111,100,101,44,32,111,110,108,121,32,65,83,67,73,73,32,110,117,109,98,101,114,115,32,97,110,100,32,108,101,116,116,101,114,115,32,104,97,118,101,32,97,110,121,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,97,102,116,101,114,32,97,32,98,97,99,107,115,108,97,115,104,46,32,65,108,108,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,32,112,97,114,116,105,99,117,108,97,114,44,32,116,104,111,115,101,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,62,32,49,50,55,41,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,108,105,116,101,114,97,108,115,46>>]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<44,32,119,104,105,116,101,115,112,97,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,40,111,116,104,101,114,32,116,104,97,110,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,41,32,97,110,100,32,99,104,97,114,97,99,116,101,114,115,32,98,101,116,119,101,101,110,32,97,32,35,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,97,110,100,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,32,97,114,101,32,105,103,110,111,114,101,100,46,32,65,110,32,101,115,99,97,112,105,110,103,32,98,97,99,107,115,108,97,115,104,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,105,110,99,108,117,100,101,32,97,32,119,104,105,116,101,115,112,97,99,101,32,111,114,32,35,32,99,104,97,114,97,99,116,101,114,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<84,111,32,114,101,109,111,118,101,32,116,104,101,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,102,114,111,109,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,112,117,116,32,116,104,101,109,32,98,101,116,119,101,101,110,32,92,81,32,97,110,100,32,92,69,46,32,84,104,105,115,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,80,101,114,108,32,105,110,32,116,104,97,116,32,36,32,97,110,100,32,64,32,97,114,101,32,104,97,110,100,108,101,100,32,97,115,32,108,105,116,101,114,97,108,115,32,105,110,32,92,81,46,46,46,92,69,32,115,101,113,117,101,110,99,101,115,32,105,110,32,80,67,82,69,44,32,119,104,105,108,101,32,36,32,97,110,100,32,64,32,99,97,117,115,101,32,118,97,114,105,97,98,108,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,105,110,32,80,101,114,108,46,32,78,111,116,105,99,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<80,97,116,116,101,114,110,32,32,32,32,32,32,32,32,32,32,32,32,80,67,82,69,32,109,97,116,99,104,101,115,32,32,32,80,101,114,108,32,109,97,116,99,104,101,115,10,10,92,81,97,98,99,36,120,121,122,92,69,32,32,32,32,32,32,32,32,97,98,99,36,120,121,122,32,32,32,32,32,32,32,32,97,98,99,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,36,120,121,122,10,92,81,97,98,99,92,36,120,121,122,92,69,32,32,32,32,32,32,32,97,98,99,92,36,120,121,122,32,32,32,32,32,32,32,97,98,99,92,36,120,121,122,10,92,81,97,98,99,92,69,92,36,92,81,120,121,122,92,69,32,32,32,97,98,99,36,120,121,122,32,32,32,32,32,32,32,32,97,98,99,36,120,121,122>>]}]},{p,[],[<<84,104,101,32,92,81,46,46,46,92,69,32,115,101,113,117,101,110,99,101,32,105,115,32,114,101,99,111,103,110,105,122,101,100,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,65,110,32,105,115,111,108,97,116,101,100,32,92,69,32,116,104,97,116,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,92,81,32,105,115,32,105,103,110,111,114,101,100,46,32,73,102,32,92,81,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,92,69,32,108,97,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,116,104,101,32,108,105,116,101,114,97,108,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,99,111,110,116,105,110,117,101,115,32,116,111,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,40,116,104,97,116,32,105,115,44,32,92,69,32,105,115,32,97,115,115,117,109,101,100,32,97,116,32,116,104,101,32,101,110,100,41,46,32,73,102,32,116,104,101,32,105,115,111,108,97,116,101,100,32,92,81,32,105,115,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,105,115,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,44,32,97,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,105,115,32,110,111,116,32,116,101,114,109,105,110,97,116,101,100,46>>]},{p,[],[{em,[],[<<78,111,110,45,80,114,105,110,116,105,110,103,32,67,104,97,114,97,99,116,101,114,115>>]}]},{a,[{id,<<110,111,110,95,112,114,105,110,116,105,110,103,95,99,104,97,114,97,99,116,101,114,115>>}],[]},{p,[],[<<65,32,115,101,99,111,110,100,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,112,114,111,118,105,100,101,115,32,97,32,119,97,121,32,111,102,32,101,110,99,111,100,105,110,103,32,110,111,110,45,112,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,112,97,116,116,101,114,110,115,32,105,110,32,97,32,118,105,115,105,98,108,101,32,109,97,110,110,101,114,46,32,84,104,101,114,101,32,105,115,32,110,111,32,114,101,115,116,114,105,99,116,105,111,110,32,111,110,32,116,104,101,32,97,112,112,101,97,114,97,110,99,101,32,111,102,32,110,111,110,45,112,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,97,112,97,114,116,32,102,114,111,109,32,116,104,101,32,98,105,110,97,114,121,32,122,101,114,111,32,116,104,97,116,32,116,101,114,109,105,110,97,116,101,115,32,97,32,112,97,116,116,101,114,110,46,32,87,104,101,110,32,97,32,112,97,116,116,101,114,110,32,105,115,32,112,114,101,112,97,114,101,100,32,98,121,32,116,101,120,116,32,101,100,105,116,105,110,103,44,32,105,116,32,105,115,32,111,102,116,101,110,32,101,97,115,105,101,114,32,116,111,32,117,115,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,110,32,116,104,101,32,98,105,110,97,114,121,32,99,104,97,114,97,99,116,101,114,32,105,116,32,114,101,112,114,101,115,101,110,116,115,58>>]},{dl,[],[{dt,[],[<<92,97>>]},{dd,[],[<<65,108,97,114,109,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,66,69,76,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,48,55,41>>]},{dt,[],[<<92,99,120>>]},{dd,[],[<<34,67,111,110,116,114,111,108,45,120,34,44,32,119,104,101,114,101,32,120,32,105,115,32,97,110,121,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,101>>]},{dd,[],[<<69,115,99,97,112,101,32,40,104,101,120,32,49,66,41>>]},{dt,[],[<<92,102>>]},{dd,[],[<<70,111,114,109,32,102,101,101,100,32,40,104,101,120,32,48,67,41>>]},{dt,[],[<<92,110>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100,32,40,104,101,120,32,48,65,41>>]},{dt,[],[<<92,114>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,104,101,120,32,48,68,41>>]},{dt,[],[<<92,116>>]},{dd,[],[<<84,97,98,32,40,104,101,120,32,48,57,41>>]},{dt,[],[<<92,48,100,100>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,48,100,100>>]},{dt,[],[<<92,100,100,100>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,100,100,100,44,32,111,114,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},{dt,[],[<<92,111,123,100,100,100,46,46,125>>]},{dd,[],[<<99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,100,100,100,46,46>>]},{dt,[],[<<92,120,104,104>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,104,101,120,32,99,111,100,101,32,104,104>>]},{dt,[],[<<92,120,123,104,104,104,46,46,125>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,104,101,120,32,99,111,100,101,32,104,104,104,46,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,92,48,100,100,32,105,115,32,97,108,119,97,121,115,32,97,110,32,111,99,116,97,108,32,99,111,100,101,44,32,97,110,100,32,116,104,97,116,32,92,56,32,97,110,100,32,92,57,32,97,114,101,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,57,34,46>>]}]},{p,[],[<<84,104,101,32,112,114,101,99,105,115,101,32,101,102,102,101,99,116,32,111,102,32,92,99,120,32,111,110,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,105,115,32,97,115,32,102,111,108,108,111,119,115,58,32,105,102,32,120,32,105,115,32,97,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,44,32,105,116,32,105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,117,112,112,101,114,32,99,97,115,101,46,32,84,104,101,110,32,98,105,116,32,54,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,52,48,41,32,105,115,32,105,110,118,101,114,116,101,100,46,32,84,104,117,115,32,92,99,65,32,116,111,32,92,99,90,32,98,101,99,111,109,101,32,104,101,120,32,48,49,32,116,111,32,104,101,120,32,49,65,32,40,65,32,105,115,32,52,49,44,32,90,32,105,115,32,53,65,41,44,32,98,117,116,32,92,99,123,32,98,101,99,111,109,101,115,32,104,101,120,32,51,66,32,40,123,32,105,115,32,55,66,41,44,32,97,110,100,32,92,99,59,32,98,101,99,111,109,101,115,32,104,101,120,32,55,66,32,40,59,32,105,115,32,51,66,41,46,32,73,102,32,116,104,101,32,100,97,116,97,32,105,116,101,109,32,40,98,121,116,101,32,111,114,32,49,54,45,98,105,116,32,118,97,108,117,101,41,32,102,111,108,108,111,119,105,110,103,32,92,99,32,104,97,115,32,97,32,118,97,108,117,101,32,62,32,49,50,55,44,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,84,104,105,115,32,108,111,99,107,115,32,111,117,116,32,110,111,110,45,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,108,108,32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,92,99,32,102,97,99,105,108,105,116,121,32,119,97,115,32,100,101,115,105,103,110,101,100,32,102,111,114,32,117,115,101,32,119,105,116,104,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,44,32,98,117,116,32,119,105,116,104,32,116,104,101,32,101,120,116,101,110,115,105,111,110,32,116,111,32,85,110,105,99,111,100,101,32,105,116,32,105,115,32,101,118,101,110,32,108,101,115,115,32,117,115,101,102,117,108,32,116,104,97,110,32,105,116,32,111,110,99,101,32,119,97,115,46>>]},{p,[],[<<65,102,116,101,114,32,92,48,32,117,112,32,116,111,32,116,119,111,32,102,117,114,116,104,101,114,32,111,99,116,97,108,32,100,105,103,105,116,115,32,97,114,101,32,114,101,97,100,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,102,101,119,101,114,32,116,104,97,110,32,116,119,111,32,100,105,103,105,116,115,44,32,106,117,115,116,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,112,114,101,115,101,110,116,32,97,114,101,32,117,115,101,100,46,32,84,104,117,115,32,116,104,101,32,115,101,113,117,101,110,99,101,32,92,48,92,120,92,48,49,53,32,115,112,101,99,105,102,105,101,115,32,116,119,111,32,98,105,110,97,114,121,32,122,101,114,111,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,67,82,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,118,97,108,117,101,32,49,51,41,46,32,77,97,107,101,32,115,117,114,101,32,121,111,117,32,115,117,112,112,108,121,32,116,119,111,32,100,105,103,105,116,115,32,97,102,116,101,114,32,116,104,101,32,105,110,105,116,105,97,108,32,122,101,114,111,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,102,111,108,108,111,119,115,32,105,115,32,105,116,115,101,108,102,32,97,110,32,111,99,116,97,108,32,100,105,103,105,116,46>>]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,92,111,32,109,117,115,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,111,99,116,97,108,32,100,105,103,105,116,115,44,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,46,32,65,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,116,104,101,32,99,97,115,101,46,32,84,104,105,115,32,101,115,99,97,112,101,32,105,115,32,97,32,114,101,99,101,110,116,32,97,100,100,105,116,105,111,110,32,116,111,32,80,101,114,108,59,32,105,116,32,112,114,111,118,105,100,101,115,32,119,97,121,32,111,102,32,115,112,101,99,105,102,121,105,110,103,32,99,104,97,114,97,99,116,101,114,32,99,111,100,101,32,112,111,105,110,116,115,32,97,115,32,111,99,116,97,108,32,110,117,109,98,101,114,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,48,55,55,55,44,32,97,110,100,32,105,116,32,97,108,115,111,32,97,108,108,111,119,115,32,111,99,116,97,108,32,110,117,109,98,101,114,115,32,97,110,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,98,101,32,117,110,97,109,98,105,103,117,111,117,115,108,121,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<70,111,114,32,103,114,101,97,116,101,114,32,99,108,97,114,105,116,121,32,97,110,100,32,117,110,97,109,98,105,103,117,105,116,121,44,32,105,116,32,105,115,32,98,101,115,116,32,116,111,32,97,118,111,105,100,32,102,111,108,108,111,119,105,110,103,32,92,32,98,121,32,97,32,100,105,103,105,116,32,103,114,101,97,116,101,114,32,116,104,97,110,32,122,101,114,111,46,32,73,110,115,116,101,97,100,44,32,117,115,101,32,92,111,123,125,32,111,114,32,92,120,123,125,32,116,111,32,115,112,101,99,105,102,121,32,99,104,97,114,97,99,116,101,114,32,110,117,109,98,101,114,115,44,32,97,110,100,32,92,103,123,125,32,116,111,32,115,112,101,99,105,102,121,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,114,97,103,114,97,112,104,115,32,100,101,115,99,114,105,98,101,32,116,104,101,32,111,108,100,44,32,97,109,98,105,103,117,111,117,115,32,115,121,110,116,97,120,46>>]},{p,[],[<<84,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,97,32,98,97,99,107,115,108,97,115,104,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,100,105,103,105,116,32,111,116,104,101,114,32,116,104,97,110,32,48,32,105,115,32,99,111,109,112,108,105,99,97,116,101,100,44,32,97,110,100,32,80,101,114,108,32,104,97,115,32,99,104,97,110,103,101,100,32,105,110,32,114,101,99,101,110,116,32,114,101,108,101,97,115,101,115,44,32,99,97,117,115,105,110,103,32,80,67,82,69,32,97,108,115,111,32,116,111,32,99,104,97,110,103,101,46,32,79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,80,67,82,69,32,114,101,97,100,115,32,116,104,101,32,100,105,103,105,116,32,97,110,100,32,97,110,121,32,102,111,108,108,111,119,105,110,103,32,100,105,103,105,116,115,32,97,115,32,97,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,105,115,32,60,32,56,44,32,111,114,32,105,102,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,32,97,116,32,108,101,97,115,116,32,116,104,97,116,32,109,97,110,121,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,44,32,116,104,101,32,101,110,116,105,114,101,32,115,101,113,117,101,110,99,101,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32>>,{em,[],[<<98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,104,111,119,32,116,104,105,115,32,119,111,114,107,115,32,105,115,32,112,114,111,118,105,100,101,100,32,108,97,116,101,114,44,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46>>]},{p,[],[<<73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,111,114,32,105,102,32,116,104,101,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,32,102,111,108,108,111,119,105,110,103,32,92,32,105,115,32,62,32,55,32,97,110,100,32,116,104,101,114,101,32,104,97,118,101,32,110,111,116,32,98,101,101,110,32,116,104,97,116,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,80,67,82,69,32,104,97,110,100,108,101,115,32,92,56,32,97,110,100,32,92,57,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,57,34,44,32,97,110,100,32,111,116,104,101,114,119,105,115,101,32,114,101,45,114,101,97,100,115,32,117,112,32,116,111,32,116,104,114,101,101,32,111,99,116,97,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,44,32,97,110,100,32,117,115,105,110,103,32,116,104,101,109,32,116,111,32,103,101,110,101,114,97,116,101,32,97,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,46,32,65,110,121,32,115,117,98,115,101,113,117,101,110,116,32,100,105,103,105,116,115,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{dl,[],[{dt,[],[<<92,48,52,48>>]},{dd,[],[<<65,110,111,116,104,101,114,32,119,97,121,32,111,102,32,119,114,105,116,105,110,103,32,97,110,32,65,83,67,73,73,32,115,112,97,99,101>>]},{dt,[],[<<92,52,48>>]},{dd,[],[<<84,104,101,32,115,97,109,101,44,32,112,114,111,118,105,100,101,100,32,116,104,101,114,101,32,97,114,101,32,60,32,52,48,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115>>]},{dt,[],[<<92,55>>]},{dd,[],[<<65,108,119,97,121,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},{dt,[],[<<92,49,49>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,97,110,111,116,104,101,114,32,119,97,121,32,111,102,32,119,114,105,116,105,110,103,32,97,32,116,97,98>>]},{dt,[],[<<92,48,49,49>>]},{dd,[],[<<65,108,119,97,121,115,32,97,32,116,97,98>>]},{dt,[],[<<92,48,49,49,51>>]},{dd,[],[<<65,32,116,97,98,32,102,111,108,108,111,119,101,100,32,98,121,32,99,104,97,114,97,99,116,101,114,32,34,51,34>>]},{dt,[],[<<92,49,49,51>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,49,49,51>>]},{dt,[],[<<92,51,55,55>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32,118,97,108,117,101,32,50,53,53,32,40,100,101,99,105,109,97,108,41>>]},{dt,[],[<<92,56,49>>]},{dd,[],[<<69,105,116,104,101,114,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,116,104,101,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,49,34>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,99,116,97,108,32,118,97,108,117,101,115,32,62,61,32,49,48,48,32,116,104,97,116,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,98,121,32,97,32,108,101,97,100,105,110,103,32,122,101,114,111,44,32,97,115,32,110,111,32,109,111,114,101,32,116,104,97,110,32,116,104,114,101,101,32,111,99,116,97,108,32,100,105,103,105,116,115,32,97,114,101,32,101,118,101,114,32,114,101,97,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,102,116,101,114,32,92,120,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,123,44,32,102,114,111,109,32,122,101,114,111,32,116,111,32,116,119,111,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115,32,97,114,101,32,114,101,97,100,32,40,108,101,116,116,101,114,115,32,99,97,110,32,98,101,32,105,110,32,117,112,112,101,114,32,111,114,32,108,111,119,101,114,32,99,97,115,101,41,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115,32,109,97,121,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,92,120,123,32,97,110,100,32,125,46,32,73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,111,116,104,101,114,32,116,104,97,110,32,97,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,32,97,112,112,101,97,114,115,32,98,101,116,119,101,101,110,32,92,120,123,32,97,110,100,32,125,44,32,111,114,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,116,101,114,109,105,110,97,116,105,110,103,32,125,44,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,118,97,108,117,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,50,53,54,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,32,98,121,32,101,105,116,104,101,114,32,111,102,32,116,104,101,32,116,119,111,32,115,121,110,116,97,120,101,115,32,102,111,114,32,92,120,46,32,84,104,101,114,101,32,105,115,32,110,111,32,100,105,102,102,101,114,101,110,99,101,32,105,110,32,116,104,101,32,119,97,121,32,116,104,101,121,32,97,114,101,32,104,97,110,100,108,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,120,100,99,32,105,115,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32,92,120,123,100,99,125,46>>]},{p,[],[{em,[],[<<67,111,110,115,116,114,97,105,110,116,115,32,111,110,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,115>>]}]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,117,115,105,110,103,32,111,99,116,97,108,32,111,114,32,104,101,120,97,100,101,99,105,109,97,108,32,110,117,109,98,101,114,115,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,99,101,114,116,97,105,110,32,118,97,108,117,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<56,45,98,105,116,32,110,111,110,45,85,84,70,32,109,111,100,101>>]},{dd,[],[{p,[],[<<60,32,48,120,49,48,48>>]}]},{dt,[],[<<56,45,98,105,116,32,85,84,70,45,56,32,109,111,100,101>>]},{dd,[],[{p,[],[<<60,32,48,120,49,48,102,102,102,102,32,97,110,100,32,97,32,118,97,108,105,100,32,99,111,100,101,112,111,105,110,116>>]}]}]},{p,[],[<<73,110,118,97,108,105,100,32,85,110,105,99,111,100,101,32,99,111,100,101,112,111,105,110,116,115,32,97,114,101,32,116,104,101,32,114,97,110,103,101,32,48,120,100,56,48,48,32,116,111,32,48,120,100,102,102,102,32,40,116,104,101,32,115,111,45,99,97,108,108,101,100,32,34,115,117,114,114,111,103,97,116,101,34,32,99,111,100,101,112,111,105,110,116,115,41,44,32,97,110,100,32,48,120,102,102,101,102,46>>]},{p,[],[{em,[],[<<69,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,105,110,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115>>]}]},{p,[],[<<65,108,108,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,100,101,102,105,110,101,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,32,99,97,110,32,98,101,32,117,115,101,100,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,65,108,115,111,44,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,98,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,48,56,41,46>>]},{p,[],[<<92,78,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,92,66,44,32,92,82,44,32,97,110,100,32,92,88,32,97,114,101,32,110,111,116,32,115,112,101,99,105,97,108,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,76,105,107,101,32,111,116,104,101,114,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,116,104,101,121,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,66,34,44,32,34,82,34,44,32,97,110,100,32,34,88,34,46,32,79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,115,46>>]},{p,[],[{em,[],[<<85,110,115,117,112,112,111,114,116,101,100,32,69,115,99,97,112,101,32,83,101,113,117,101,110,99,101,115>>]}]},{p,[],[<<73,110,32,80,101,114,108,44,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,92,108,44,32,92,76,44,32,92,117,44,32,97,110,100,32,92,85,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32,105,116,115,32,115,116,114,105,110,103,32,104,97,110,100,108,101,114,32,97,110,100,32,117,115,101,100,32,116,111,32,109,111,100,105,102,121,32,116,104,101,32,99,97,115,101,32,111,102,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,46>>]},{p,[],[{em,[],[<<65,98,115,111,108,117,116,101,32,97,110,100,32,82,101,108,97,116,105,118,101,32,66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,117,110,115,105,103,110,101,100,32,111,114,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,44,32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,111,114,32,114,101,108,97,116,105,118,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,97,109,101,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,99,111,100,101,100,32,97,115,32,92,103,123,110,97,109,101,125,46,32,66,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,97,114,101,32,100,105,115,99,117,115,115,101,100,32,108,97,116,101,114,44,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46>>]},{p,[],[{em,[],[<<65,98,115,111,108,117,116,101,32,97,110,100,32,82,101,108,97,116,105,118,101,32,83,117,98,114,111,117,116,105,110,101,32,67,97,108,108,115>>]}]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,79,110,105,103,117,114,117,109,97,44,32,116,104,101,32,110,111,110,45,80,101,114,108,32,115,121,110,116,97,120,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,32,111,114,32,97,32,110,117,109,98,101,114,32,101,110,99,108,111,115,101,100,32,101,105,116,104,101,114,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,32,111,114,32,115,105,110,103,108,101,32,113,117,111,116,101,115,44,32,105,115,32,97,108,116,101,114,110,97,116,105,118,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,102,101,114,101,110,99,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,34,115,117,98,114,111,117,116,105,110,101,34,46,32,68,101,116,97,105,108,115,32,97,114,101,32,100,105,115,99,117,115,115,101,100,32,108,97,116,101,114,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,103,123,46,46,46,125,32,40,80,101,114,108,32,115,121,110,116,97,120,41,32,97,110,100,32,92,103,60,46,46,46,62,32,40,79,110,105,103,117,114,117,109,97,32,115,121,110,116,97,120,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,115,121,110,111,110,121,109,111,117,115,46,32,84,104,101,32,102,111,114,109,101,114,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,97,110,100,32,116,104,101,32,108,97,116,116,101,114,32,105,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]},{p,[],[{em,[],[<<71,101,110,101,114,105,99,32,67,104,97,114,97,99,116,101,114,32,84,121,112,101,115>>]}]},{a,[{id,<<103,101,110,101,114,105,99,95,99,104,97,114,97,99,116,101,114,95,116,121,112,101,115>>}],[]},{p,[],[<<65,110,111,116,104,101,114,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,105,115,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,103,101,110,101,114,105,99,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[<<92,100>>]},{dd,[],[<<65,110,121,32,100,101,99,105,109,97,108,32,100,105,103,105,116>>]},{dt,[],[<<92,68>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,100,101,99,105,109,97,108,32,100,105,103,105,116>>]},{dt,[],[<<92,104>>]},{dd,[],[<<65,110,121,32,104,111,114,105,122,111,110,116,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,72>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,104,111,114,105,122,111,110,116,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,115>>]},{dd,[],[<<65,110,121,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,83>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,118>>]},{dd,[],[<<65,110,121,32,118,101,114,116,105,99,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,86>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,118,101,114,116,105,99,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,119>>]},{dd,[],[<<65,110,121,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,87>>]},{dd,[],[<<65,110,121,32,34,110,111,110,45,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114>>]}]},{p,[],[<<84,104,101,114,101,32,105,115,32,97,108,115,111,32,116,104,101,32,115,105,110,103,108,101,32,115,101,113,117,101,110,99,101,32,92,78,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,32,110,111,110,45,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,34,46,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,119,104,101,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,110,111,116,32,115,101,116,46,32,80,101,114,108,32,97,108,115,111,32,117,115,101,115,32,92,78,32,116,111,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,110,97,109,101,44,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46>>]},{p,[],[<<69,97,99,104,32,112,97,105,114,32,111,102,32,108,111,119,101,114,99,97,115,101,32,97,110,100,32,117,112,112,101,114,99,97,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,112,97,114,116,105,116,105,111,110,115,32,116,104,101,32,99,111,109,112,108,101,116,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,105,110,116,111,32,116,119,111,32,100,105,115,106,111,105,110,116,32,115,101,116,115,46,32,65,110,121,32,103,105,118,101,110,32,99,104,97,114,97,99,116,101,114,32,109,97,116,99,104,101,115,32,111,110,101,44,32,97,110,100,32,111,110,108,121,32,111,110,101,44,32,111,102,32,101,97,99,104,32,112,97,105,114,46,32,84,104,101,32,115,101,113,117,101,110,99,101,115,32,99,97,110,32,97,112,112,101,97,114,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,84,104,101,121,32,101,97,99,104,32,109,97,116,99,104,32,111,110,101,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,116,121,112,101,46,32,73,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,108,108,32,102,97,105,108,44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,99,104,97,114,97,99,116,101,114,32,116,111,32,109,97,116,99,104,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,92,115,32,100,105,100,32,110,111,116,32,117,115,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,49,49,41,44,32,119,104,105,99,104,32,109,97,100,101,32,105,116,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,116,104,101,32,80,79,83,73,88,32,34,115,112,97,99,101,34,32,99,108,97,115,115,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,97,100,100,101,100,32,86,84,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,97,110,100,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,115,117,105,116,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,84,104,101,32,100,101,102,97,117,108,116,32,92,115,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,119,32,72,84,32,40,57,41,44,32,76,70,32,40,49,48,41,44,32,86,84,32,40,49,49,41,44,32,70,70,32,40,49,50,41,44,32,67,82,32,40,49,51,41,44,32,97,110,100,32,115,112,97,99,101,32,40,51,50,41,44,32,119,104,105,99,104,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,32,105,110,32,116,104,101,32,34,67,34,32,108,111,99,97,108,101,46,32,84,104,105,115,32,108,105,115,116,32,109,97,121,32,118,97,114,121,32,105,102,32,108,111,99,97,108,101,45,115,112,101,99,105,102,105,99,32,109,97,116,99,104,105,110,103,32,105,115,32,116,97,107,105,110,103,32,112,108,97,99,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,115,111,109,101,32,108,111,99,97,108,101,115,32,116,104,101,32,34,110,111,110,45,98,114,101,97,107,105,110,103,32,115,112,97,99,101,34,32,99,104,97,114,97,99,116,101,114,32,40,92,120,65,48,41,32,105,115,32,114,101,99,111,103,110,105,122,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,44,32,97,110,100,32,105,110,32,111,116,104,101,114,115,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,46>>]},{p,[],[<<65,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,117,110,100,101,114,115,99,111,114,101,32,111,114,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,97,32,108,101,116,116,101,114,32,111,114,32,97,32,100,105,103,105,116,46,32,66,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,108,101,116,116,101,114,115,32,97,110,100,32,100,105,103,105,116,115,32,105,115,32,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,32,80,67,82,69,32,108,111,119,45,118,97,108,117,101,100,32,99,104,97,114,97,99,116,101,114,32,116,97,98,108,101,115,44,32,105,110,32,69,114,108,97,110,103,39,115,32,99,97,115,101,32,40,97,110,100,32,119,105,116,104,111,117,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<41,44,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,105,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,111,117,116,115,105,100,101,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,44,32,110,101,118,101,114,32,109,97,116,99,104,32,92,100,44,32,92,115,44,32,111,114,32,92,119,44,32,97,110,100,32,97,108,119,97,121,115,32,109,97,116,99,104,32,92,68,44,32,92,83,44,32,97,110,100,32,92,87,46,32,84,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,114,101,116,97,105,110,32,116,104,101,105,114,32,111,114,105,103,105,110,97,108,32,109,101,97,110,105,110,103,115,32,102,114,111,109,32,98,101,102,111,114,101,32,85,84,70,32,115,117,112,112,111,114,116,32,119,97,115,32,97,118,97,105,108,97,98,108,101,44,32,109,97,105,110,108,121,32,102,111,114,32,101,102,102,105,99,105,101,110,99,121,32,114,101,97,115,111,110,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<92,100>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,92,112,123,78,100,125,32,109,97,116,99,104,101,115,32,40,100,101,99,105,109,97,108,32,100,105,103,105,116,41>>]},{dt,[],[<<92,115>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,92,112,123,90,125,32,111,114,32,92,104,32,111,114,32,92,118>>]},{dt,[],[<<92,119>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,109,97,116,99,104,101,115,32,92,112,123,76,125,32,111,114,32,92,112,123,78,125,32,109,97,116,99,104,101,115,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101>>]}]},{p,[],[<<84,104,101,32,117,112,112,101,114,99,97,115,101,32,101,115,99,97,112,101,115,32,109,97,116,99,104,32,116,104,101,32,105,110,118,101,114,115,101,32,115,101,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,100,32,109,97,116,99,104,101,115,32,111,110,108,121,32,100,101,99,105,109,97,108,32,100,105,103,105,116,115,44,32,119,104,105,108,101,32,92,119,32,109,97,116,99,104,101,115,32,97,110,121,32,85,110,105,99,111,100,101,32,100,105,103,105,116,44,32,97,110,121,32,85,110,105,99,111,100,101,32,108,101,116,116,101,114,44,32,97,110,100,32,117,110,100,101,114,115,99,111,114,101,46,32,78,111,116,105,99,101,32,97,108,115,111,32,116,104,97,116,32>>,{code,[],[<<117,99,112>>]},<<32,97,102,102,101,99,116,115,32,92,98,32,97,110,100,32,92,66,44,32,97,115,32,116,104,101,121,32,97,114,101,32,100,101,102,105,110,101,100,32,105,110,32,116,101,114,109,115,32,111,102,32,92,119,32,97,110,100,32,92,87,46,32,77,97,116,99,104,105,110,103,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,105,115,32,110,111,116,105,99,101,97,98,108,121,32,115,108,111,119,101,114,32,119,104,101,110,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,115,32,92,104,44,32,92,72,44,32,92,118,44,32,97,110,100,32,92,86,32,97,114,101,32,102,101,97,116,117,114,101,115,32,116,104,97,116,32,119,101,114,101,32,97,100,100,101,100,32,116,111,32,80,101,114,108,32,105,110,32,114,101,108,101,97,115,101,32,53,46,49,48,46,32,73,110,32,99,111,110,116,114,97,115,116,32,116,111,32,116,104,101,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,115,44,32,119,104,105,99,104,32,109,97,116,99,104,32,111,110,108,121,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,100,101,102,97,117,108,116,44,32,116,104,101,115,101,32,97,108,119,97,121,115,32,109,97,116,99,104,32,99,101,114,116,97,105,110,32,104,105,103,104,45,118,97,108,117,101,100,32,99,111,100,101,32,112,111,105,110,116,115,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,104,111,114,105,122,111,110,116,97,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,58>>]},{dl,[],[{dt,[],[<<85,43,48,48,48,57>>]},{dd,[],[<<72,111,114,105,122,111,110,116,97,108,32,116,97,98,32,40,72,84,41>>]},{dt,[],[<<85,43,48,48,50,48>>]},{dd,[],[<<83,112,97,99,101>>]},{dt,[],[<<85,43,48,48,65,48>>]},{dd,[],[<<78,111,110,45,98,114,101,97,107,32,115,112,97,99,101>>]},{dt,[],[<<85,43,49,54,56,48>>]},{dd,[],[<<79,103,104,97,109,32,115,112,97,99,101,32,109,97,114,107>>]},{dt,[],[<<85,43,49,56,48,69>>]},{dd,[],[<<77,111,110,103,111,108,105,97,110,32,118,111,119,101,108,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<85,43,50,48,48,48>>]},{dd,[],[<<69,110,32,113,117,97,100>>]},{dt,[],[<<85,43,50,48,48,49>>]},{dd,[],[<<69,109,32,113,117,97,100>>]},{dt,[],[<<85,43,50,48,48,50>>]},{dd,[],[<<69,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,51>>]},{dd,[],[<<69,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,52>>]},{dd,[],[<<84,104,114,101,101,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,53>>]},{dd,[],[<<70,111,117,114,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,54>>]},{dd,[],[<<83,105,120,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,55>>]},{dd,[],[<<70,105,103,117,114,101,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,56>>]},{dd,[],[<<80,117,110,99,116,117,97,116,105,111,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,57>>]},{dd,[],[<<84,104,105,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,65>>]},{dd,[],[<<72,97,105,114,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,50,70>>]},{dd,[],[<<78,97,114,114,111,119,32,110,111,45,98,114,101,97,107,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,53,70>>]},{dd,[],[<<77,101,100,105,117,109,32,109,97,116,104,101,109,97,116,105,99,97,108,32,115,112,97,99,101>>]},{dt,[],[<<85,43,51,48,48,48>>]},{dd,[],[<<73,100,101,111,103,114,97,112,104,105,99,32,115,112,97,99,101>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,118,101,114,116,105,99,97,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,58>>]},{dl,[],[{dt,[],[<<85,43,48,48,48,65>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100,32,40,76,70,41>>]},{dt,[],[<<85,43,48,48,48,66>>]},{dd,[],[<<86,101,114,116,105,99,97,108,32,116,97,98,32,40,86,84,41>>]},{dt,[],[<<85,43,48,48,48,67>>]},{dd,[],[<<70,111,114,109,32,102,101,101,100,32,40,70,70,41>>]},{dt,[],[<<85,43,48,48,48,68>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,67,82,41>>]},{dt,[],[<<85,43,48,48,56,53>>]},{dd,[],[<<78,101,120,116,32,108,105,110,101,32,40,78,69,76,41>>]},{dt,[],[<<85,43,50,48,50,56>>]},{dd,[],[<<76,105,110,101,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<85,43,50,48,50,57>>]},{dd,[],[<<80,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114>>]}]},{p,[],[<<73,110,32,56,45,98,105,116,44,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,111,110,108,121,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,32,112,111,105,110,116,115,32,60,32,50,53,54,32,97,114,101,32,114,101,108,101,118,97,110,116,46>>]},{p,[],[{em,[],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]}]},{a,[{id,<<110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>}],[]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,98,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,82,32,109,97,116,99,104,101,115,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,46,32,73,110,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,92,82,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{pre,[],[{code,[],[<<40,63,62,92,114,92,110,124,92,110,124,92,120,48,98,124,92,102,124,92,114,124,92,120,56,53,41>>]}]},{p,[],[<<84,104,105,115,32,105,115,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,97,110,32,34,97,116,111,109,105,99,32,103,114,111,117,112,34,44,32,100,101,116,97,105,108,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,98,101,108,111,119,46>>]},{p,[],[<<84,104,105,115,32,112,97,114,116,105,99,117,108,97,114,32,103,114,111,117,112,32,109,97,116,99,104,101,115,32,101,105,116,104,101,114,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,32,102,111,108,108,111,119,101,100,32,98,121,32,76,70,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,115,32,76,70,32,40,108,105,110,101,32,102,101,101,100,44,32,85,43,48,48,48,65,41,44,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,32,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,67,82,32,40,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,85,43,48,48,48,68,41,44,32,111,114,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,46,32,84,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,117,110,105,116,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,115,112,108,105,116,46>>]},{p,[],[<<73,110,32,85,110,105,99,111,100,101,32,109,111,100,101,44,32,116,119,111,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,62,32,50,53,53,32,97,114,101,32,97,100,100,101,100,58,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,32,105,115,32,110,111,116,32,110,101,101,100,101,100,32,102,111,114,32,116,104,101,115,101,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]},{p,[],[<<92,82,32,99,97,110,32,98,101,32,114,101,115,116,114,105,99,116,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,40,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,99,111,109,112,108,101,116,101,32,115,101,116,32,111,102,32,85,110,105,99,111,100,101,32,108,105,110,101,32,101,110,100,105,110,103,115,41,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]},<<32,101,105,116,104,101,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,46,32,40,66,83,82,32,105,115,32,97,110,32,97,99,114,111,110,121,109,32,102,111,114,32,34,98,97,99,107,115,108,97,115,104,32,82,34,46,41,32,84,104,105,115,32,99,97,110,32,98,101,32,109,97,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,119,104,101,110,32,80,67,82,69,32,105,115,32,98,117,105,108,116,59,32,105,102,32,115,111,44,32,116,104,101,32,111,116,104,101,114,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,114,101,113,117,101,115,116,101,100,32,116,104,114,111,117,103,104,32,111,112,116,105,111,110,32>>,{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]},<<46,32,84,104,101,115,101,32,115,101,116,116,105,110,103,115,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,115,116,97,114,116,105,110,103,32,97,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<40,42,66,83,82,95,65,78,89,67,82,76,70,41>>]},{dd,[],[<<67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,111,110,108,121>>]},{dt,[],[<<40,42,66,83,82,95,85,78,73,67,79,68,69,41>>]},{dd,[],[<<65,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101>>]}]},{p,[],[<<84,104,101,115,101,32,111,118,101,114,114,105,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,97,110,100,32,116,104,101,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,101,32,99,111,109,112,105,108,105,110,103,32,102,117,110,99,116,105,111,110,44,32,98,117,116,32,116,104,101,121,32,99,97,110,32,116,104,101,109,115,101,108,118,101,115,32,98,101,32,111,118,101,114,114,105,100,100,101,110,32,98,121,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,97,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,115,101,116,116,105,110,103,115,44,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,44,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,111,110,108,121,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,44,32,97,110,100,32,116,104,97,116,32,116,104,101,121,32,109,117,115,116,32,98,101,32,105,110,32,117,112,112,101,114,32,99,97,115,101,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,108,97,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46,32,84,104,101,121,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,97,32,99,104,97,110,103,101,32,111,102,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,59,32,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,112,97,116,116,101,114,110,32,99,97,110,32,115,116,97,114,116,32,119,105,116,104,58>>]},{pre,[],[{code,[],[<<40,42,65,78,89,41,40,42,66,83,82,95,65,78,89,67,82,76,70,41>>]}]},{p,[],[<<84,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,116,104,101,32,40,42,85,84,70,56,41,44,32,40,42,85,84,70,41,44,32,111,114,32,40,42,85,67,80,41,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,115,46,32,73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,82,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,44,32,97,110,100,32,115,111,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,32,34,82,34,32,98,121,32,100,101,102,97,117,108,116,46>>]},{p,[],[{em,[],[<<85,110,105,99,111,100,101,32,67,104,97,114,97,99,116,101,114,32,80,114,111,112,101,114,116,105,101,115>>]}]},{p,[],[<<84,104,114,101,101,32,109,111,114,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,115,112,101,99,105,102,105,99,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,97,118,97,105,108,97,98,108,101,46,32,87,104,101,110,32,105,110,32,56,45,98,105,116,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,116,101,115,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,60,32,50,53,54,44,32,98,117,116,32,116,104,101,121,32,100,111,32,119,111,114,107,32,105,110,32,116,104,105,115,32,109,111,100,101,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,101,120,116,114,97,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<92,112,123>>,{em,[],[<<120,120>>]},<<125>>]},{dd,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,112,114,111,112,101,114,116,121,32>>,{em,[],[<<120,120>>]}]},{dt,[],[<<92,80,123>>,{em,[],[<<120,120>>]},<<125>>]},{dd,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,111,117,116,32,112,114,111,112,101,114,116,121,32>>,{em,[],[<<120,120>>]}]},{dt,[],[<<92,88>>]},{dd,[],[<<65,32,85,110,105,99,111,100,101,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114>>]}]},{p,[],[<<84,104,101,32,112,114,111,112,101,114,116,121,32,110,97,109,101,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32>>,{em,[],[<<120,120>>]},<<32,97,98,111,118,101,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,116,104,101,32,85,110,105,99,111,100,101,32,115,99,114,105,112,116,32,110,97,109,101,115,44,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,105,101,115,44,32,34,65,110,121,34,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,40,105,110,99,108,117,100,105,110,103,32,110,101,119,108,105,110,101,41,44,32,97,110,100,32,115,111,109,101,32,115,112,101,99,105,97,108,32,80,67,82,69,32,112,114,111,112,101,114,116,105,101,115,32,40,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,46,32,79,116,104,101,114,32,80,101,114,108,32,112,114,111,112,101,114,116,105,101,115,44,32,115,117,99,104,32,97,115,32,34,73,110,77,117,115,105,99,97,108,83,121,109,98,111,108,115,34,44,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,80,123,65,110,121,125,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,97,108,119,97,121,115,32,99,97,117,115,101,115,32,97,32,109,97,116,99,104,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<83,101,116,115,32,111,102,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,98,101,108,111,110,103,105,110,103,32,116,111,32,99,101,114,116,97,105,110,32,115,99,114,105,112,116,115,46,32,65,32,99,104,97,114,97,99,116,101,114,32,102,114,111,109,32,111,110,101,32,111,102,32,116,104,101,115,101,32,115,101,116,115,32,99,97,110,32,98,101,32,109,97,116,99,104,101,100,32,117,115,105,110,103,32,97,32,115,99,114,105,112,116,32,110,97,109,101,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<92,112,123,71,114,101,101,107,125,32,92,80,123,72,97,110,125>>]}]},{p,[],[<<84,104,111,115,101,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,97,110,32,105,100,101,110,116,105,102,105,101,100,32,115,99,114,105,112,116,32,97,114,101,32,108,117,109,112,101,100,32,116,111,103,101,116,104,101,114,32,97,115,32,34,67,111,109,109,111,110,34,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,108,105,115,116,32,111,102,32,115,99,114,105,112,116,115,58>>]},{ul,[],[{li,[],[<<65,114,97,98,105,99>>]},{li,[],[<<65,114,109,101,110,105,97,110>>]},{li,[],[<<65,118,101,115,116,97,110>>]},{li,[],[<<66,97,108,105,110,101,115,101>>]},{li,[],[<<66,97,109,117,109>>]},{li,[],[<<66,97,115,115,97,95,86,97,104>>]},{li,[],[<<66,97,116,97,107>>]},{li,[],[<<66,101,110,103,97,108,105>>]},{li,[],[<<66,111,112,111,109,111,102,111>>]},{li,[],[<<66,114,97,105,108,108,101>>]},{li,[],[<<66,117,103,105,110,101,115,101>>]},{li,[],[<<66,117,104,105,100>>]},{li,[],[<<67,97,110,97,100,105,97,110,95,65,98,111,114,105,103,105,110,97,108>>]},{li,[],[<<67,97,114,105,97,110>>]},{li,[],[<<67,97,117,99,97,115,105,97,110,95,65,108,98,97,110,105,97,110>>]},{li,[],[<<67,104,97,107,109,97>>]},{li,[],[<<67,104,97,109>>]},{li,[],[<<67,104,101,114,111,107,101,101>>]},{li,[],[<<67,111,109,109,111,110>>]},{li,[],[<<67,111,112,116,105,99>>]},{li,[],[<<67,117,110,101,105,102,111,114,109>>]},{li,[],[<<67,121,112,114,105,111,116>>]},{li,[],[<<67,121,114,105,108,108,105,99>>]},{li,[],[<<68,101,115,101,114,101,116>>]},{li,[],[<<68,101,118,97,110,97,103,97,114,105>>]},{li,[],[<<68,117,112,108,111,121,97,110>>]},{li,[],[<<69,103,121,112,116,105,97,110,95,72,105,101,114,111,103,108,121,112,104,115>>]},{li,[],[<<69,108,98,97,115,97,110>>]},{li,[],[<<69,116,104,105,111,112,105,99>>]},{li,[],[<<71,101,111,114,103,105,97,110>>]},{li,[],[<<71,108,97,103,111,108,105,116,105,99>>]},{li,[],[<<71,111,116,104,105,99>>]},{li,[],[<<71,114,97,110,116,104,97>>]},{li,[],[<<71,114,101,101,107>>]},{li,[],[<<71,117,106,97,114,97,116,105>>]},{li,[],[<<71,117,114,109,117,107,104,105>>]},{li,[],[<<72,97,110>>]},{li,[],[<<72,97,110,103,117,108>>]},{li,[],[<<72,97,110,117,110,111,111>>]},{li,[],[<<72,101,98,114,101,119>>]},{li,[],[<<72,105,114,97,103,97,110,97>>]},{li,[],[<<73,109,112,101,114,105,97,108,95,65,114,97,109,97,105,99>>]},{li,[],[<<73,110,104,101,114,105,116,101,100>>]},{li,[],[<<73,110,115,99,114,105,112,116,105,111,110,97,108,95,80,97,104,108,97,118,105>>]},{li,[],[<<73,110,115,99,114,105,112,116,105,111,110,97,108,95,80,97,114,116,104,105,97,110>>]},{li,[],[<<74,97,118,97,110,101,115,101>>]},{li,[],[<<75,97,105,116,104,105>>]},{li,[],[<<75,97,110,110,97,100,97>>]},{li,[],[<<75,97,116,97,107,97,110,97>>]},{li,[],[<<75,97,121,97,104,95,76,105>>]},{li,[],[<<75,104,97,114,111,115,104,116,104,105>>]},{li,[],[<<75,104,109,101,114>>]},{li,[],[<<75,104,111,106,107,105>>]},{li,[],[<<75,104,117,100,97,119,97,100,105>>]},{li,[],[<<76,97,111>>]},{li,[],[<<76,97,116,105,110>>]},{li,[],[<<76,101,112,99,104,97>>]},{li,[],[<<76,105,109,98,117>>]},{li,[],[<<76,105,110,101,97,114,95,65>>]},{li,[],[<<76,105,110,101,97,114,95,66>>]},{li,[],[<<76,105,115,117>>]},{li,[],[<<76,121,99,105,97,110>>]},{li,[],[<<76,121,100,105,97,110>>]},{li,[],[<<77,97,104,97,106,97,110,105>>]},{li,[],[<<77,97,108,97,121,97,108,97,109>>]},{li,[],[<<77,97,110,100,97,105,99>>]},{li,[],[<<77,97,110,105,99,104,97,101,97,110>>]},{li,[],[<<77,101,101,116,101,105,95,77,97,121,101,107>>]},{li,[],[<<77,101,110,100,101,95,75,105,107,97,107,117,105>>]},{li,[],[<<77,101,114,111,105,116,105,99,95,67,117,114,115,105,118,101>>]},{li,[],[<<77,101,114,111,105,116,105,99,95,72,105,101,114,111,103,108,121,112,104,115>>]},{li,[],[<<77,105,97,111>>]},{li,[],[<<77,111,100,105>>]},{li,[],[<<77,111,110,103,111,108,105,97,110>>]},{li,[],[<<77,114,111>>]},{li,[],[<<77,121,97,110,109,97,114>>]},{li,[],[<<78,97,98,97,116,97,101,97,110>>]},{li,[],[<<78,101,119,95,84,97,105,95,76,117,101>>]},{li,[],[<<78,107,111>>]},{li,[],[<<79,103,104,97,109>>]},{li,[],[<<79,108,95,67,104,105,107,105>>]},{li,[],[<<79,108,100,95,73,116,97,108,105,99>>]},{li,[],[<<79,108,100,95,78,111,114,116,104,95,65,114,97,98,105,97,110>>]},{li,[],[<<79,108,100,95,80,101,114,109,105,99>>]},{li,[],[<<79,108,100,95,80,101,114,115,105,97,110>>]},{li,[],[<<79,114,105,121,97>>]},{li,[],[<<79,108,100,95,83,111,117,116,104,95,65,114,97,98,105,97,110>>]},{li,[],[<<79,108,100,95,84,117,114,107,105,99>>]},{li,[],[<<79,115,109,97,110,121,97>>]},{li,[],[<<80,97,104,97,119,104,95,72,109,111,110,103>>]},{li,[],[<<80,97,108,109,121,114,101,110,101>>]},{li,[],[<<80,97,117,95,67,105,110,95,72,97,117>>]},{li,[],[<<80,104,97,103,115,95,80,97>>]},{li,[],[<<80,104,111,101,110,105,99,105,97,110>>]},{li,[],[<<80,115,97,108,116,101,114,95,80,97,104,108,97,118,105>>]},{li,[],[<<82,101,106,97,110,103>>]},{li,[],[<<82,117,110,105,99>>]},{li,[],[<<83,97,109,97,114,105,116,97,110>>]},{li,[],[<<83,97,117,114,97,115,104,116,114,97>>]},{li,[],[<<83,104,97,114,97,100,97>>]},{li,[],[<<83,104,97,118,105,97,110>>]},{li,[],[<<83,105,100,100,104,97,109>>]},{li,[],[<<83,105,110,104,97,108,97>>]},{li,[],[<<83,111,114,97,95,83,111,109,112,101,110,103>>]},{li,[],[<<83,117,110,100,97,110,101,115,101>>]},{li,[],[<<83,121,108,111,116,105,95,78,97,103,114,105>>]},{li,[],[<<83,121,114,105,97,99>>]},{li,[],[<<84,97,103,97,108,111,103>>]},{li,[],[<<84,97,103,98,97,110,119,97>>]},{li,[],[<<84,97,105,95,76,101>>]},{li,[],[<<84,97,105,95,84,104,97,109>>]},{li,[],[<<84,97,105,95,86,105,101,116>>]},{li,[],[<<84,97,107,114,105>>]},{li,[],[<<84,97,109,105,108>>]},{li,[],[<<84,101,108,117,103,117>>]},{li,[],[<<84,104,97,97,110,97>>]},{li,[],[<<84,104,97,105>>]},{li,[],[<<84,105,98,101,116,97,110>>]},{li,[],[<<84,105,102,105,110,97,103,104>>]},{li,[],[<<84,105,114,104,117,116,97>>]},{li,[],[<<85,103,97,114,105,116,105,99>>]},{li,[],[<<86,97,105>>]},{li,[],[<<87,97,114,97,110,103,95,67,105,116,105>>]},{li,[],[<<89,105>>]}]},{p,[],[<<69,97,99,104,32,99,104,97,114,97,99,116,101,114,32,104,97,115,32,101,120,97,99,116,108,121,32,111,110,101,32,85,110,105,99,111,100,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,121,44,32,115,112,101,99,105,102,105,101,100,32,98,121,32,97,32,116,119,111,45,108,101,116,116,101,114,32,97,99,114,111,110,121,109,46,32,70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,110,101,103,97,116,105,111,110,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,105,110,99,108,117,100,105,110,103,32,97,32,99,105,114,99,117,109,102,108,101,120,32,98,101,116,119,101,101,110,32,116,104,101,32,111,112,101,110,105,110,103,32,98,114,97,99,101,32,97,110,100,32,116,104,101,32,112,114,111,112,101,114,116,121,32,110,97,109,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,112,123,94,76,117,125,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,92,80,123,76,117,125,46>>]},{p,[],[<<73,102,32,111,110,108,121,32,111,110,101,32,108,101,116,116,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,32,119,105,116,104,32,92,112,32,111,114,32,92,80,44,32,105,116,32,105,110,99,108,117,100,101,115,32,97,108,108,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,105,101,115,32,116,104,97,116,32,115,116,97,114,116,32,119,105,116,104,32,116,104,97,116,32,108,101,116,116,101,114,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,105,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,110,101,103,97,116,105,111,110,44,32,116,104,101,32,99,117,114,108,121,32,98,114,97,99,107,101,116,115,32,105,110,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,97,114,101,32,111,112,116,105,111,110,97,108,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,119,111,32,101,120,97,109,112,108,101,115,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,58>>]},{pre,[],[{code,[],[<<92,112,123,76,125,10,92,112,76>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,121,32,99,111,100,101,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,58>>]},{dl,[],[{dt,[],[<<67>>]},{dd,[],[<<79,116,104,101,114>>]},{dt,[],[<<67,99>>]},{dd,[],[<<67,111,110,116,114,111,108>>]},{dt,[],[<<67,102>>]},{dd,[],[<<70,111,114,109,97,116>>]},{dt,[],[<<67,110>>]},{dd,[],[<<85,110,97,115,115,105,103,110,101,100>>]},{dt,[],[<<67,111>>]},{dd,[],[<<80,114,105,118,97,116,101,32,117,115,101>>]},{dt,[],[<<67,115>>]},{dd,[],[<<83,117,114,114,111,103,97,116,101>>]},{dt,[],[<<76>>]},{dd,[],[<<76,101,116,116,101,114>>]},{dt,[],[<<76,108>>]},{dd,[],[<<76,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<76,109>>]},{dd,[],[<<77,111,100,105,102,105,101,114,32,108,101,116,116,101,114>>]},{dt,[],[<<76,111>>]},{dd,[],[<<79,116,104,101,114,32,108,101,116,116,101,114>>]},{dt,[],[<<76,116>>]},{dd,[],[<<84,105,116,108,101,32,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<76,117>>]},{dd,[],[<<85,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<77>>]},{dd,[],[<<77,97,114,107>>]},{dt,[],[<<77,99>>]},{dd,[],[<<83,112,97,99,105,110,103,32,109,97,114,107>>]},{dt,[],[<<77,101>>]},{dd,[],[<<69,110,99,108,111,115,105,110,103,32,109,97,114,107>>]},{dt,[],[<<77,110>>]},{dd,[],[<<78,111,110,45,115,112,97,99,105,110,103,32,109,97,114,107>>]},{dt,[],[<<78>>]},{dd,[],[<<78,117,109,98,101,114>>]},{dt,[],[<<78,100>>]},{dd,[],[<<68,101,99,105,109,97,108,32,110,117,109,98,101,114>>]},{dt,[],[<<78,108>>]},{dd,[],[<<76,101,116,116,101,114,32,110,117,109,98,101,114>>]},{dt,[],[<<78,111>>]},{dd,[],[<<79,116,104,101,114,32,110,117,109,98,101,114>>]},{dt,[],[<<80>>]},{dd,[],[<<80,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,99>>]},{dd,[],[<<67,111,110,110,101,99,116,111,114,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,100>>]},{dd,[],[<<68,97,115,104,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,101>>]},{dd,[],[<<67,108,111,115,101,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,102>>]},{dd,[],[<<70,105,110,97,108,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,105>>]},{dd,[],[<<73,110,105,116,105,97,108,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,111>>]},{dd,[],[<<79,116,104,101,114,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,115>>]},{dd,[],[<<79,112,101,110,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<83>>]},{dd,[],[<<83,121,109,98,111,108>>]},{dt,[],[<<83,99>>]},{dd,[],[<<67,117,114,114,101,110,99,121,32,115,121,109,98,111,108>>]},{dt,[],[<<83,107>>]},{dd,[],[<<77,111,100,105,102,105,101,114,32,115,121,109,98,111,108>>]},{dt,[],[<<83,109>>]},{dd,[],[<<77,97,116,104,101,109,97,116,105,99,97,108,32,115,121,109,98,111,108>>]},{dt,[],[<<83,111>>]},{dd,[],[<<79,116,104,101,114,32,115,121,109,98,111,108>>]},{dt,[],[<<90>>]},{dd,[],[<<83,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,108>>]},{dd,[],[<<76,105,110,101,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,112>>]},{dd,[],[<<80,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,115>>]},{dd,[],[<<83,112,97,99,101,32,115,101,112,97,114,97,116,111,114>>]}]},{p,[],[<<84,104,101,32,115,112,101,99,105,97,108,32,112,114,111,112,101,114,116,121,32,76,38,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,73,116,32,109,97,116,99,104,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,76,117,44,32,76,108,44,32,111,114,32,76,116,32,112,114,111,112,101,114,116,121,44,32,116,104,97,116,32,105,115,44,32,97,32,108,101,116,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,99,108,97,115,115,105,102,105,101,100,32,97,115,32,97,32,109,111,100,105,102,105,101,114,32,111,114,32,34,111,116,104,101,114,34,46>>]},{p,[],[<<84,104,101,32,67,115,32,40,83,117,114,114,111,103,97,116,101,41,32,112,114,111,112,101,114,116,121,32,97,112,112,108,105,101,115,32,111,110,108,121,32,116,111,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,85,43,68,56,48,48,32,116,111,32,85,43,68,70,70,70,46,32,83,117,99,104,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,105,110,118,97,108,105,100,32,105,110,32,85,110,105,99,111,100,101,32,115,116,114,105,110,103,115,32,97,110,100,32,115,111,32,99,97,110,110,111,116,32,98,101,32,116,101,115,116,101,100,32,98,121,32,80,67,82,69,46,32,80,101,114,108,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,32,67,115,32,112,114,111,112,101,114,116,121,46>>]},{p,[],[<<84,104,101,32,108,111,110,103,32,115,121,110,111,110,121,109,115,32,102,111,114,32,112,114,111,112,101,114,116,121,32,110,97,109,101,115,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,101,114,108,32,40,115,117,99,104,32,97,115,32,92,112,123,76,101,116,116,101,114,125,41,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,46,32,73,116,32,105,115,32,110,111,116,32,112,101,114,109,105,116,116,101,100,32,116,111,32,112,114,101,102,105,120,32,97,110,121,32,111,102,32,116,104,101,115,101,32,112,114,111,112,101,114,116,105,101,115,32,119,105,116,104,32,34,73,115,34,46>>]},{p,[],[<<78,111,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,116,97,98,108,101,32,104,97,115,32,116,104,101,32,67,110,32,40,117,110,97,115,115,105,103,110,101,100,41,32,112,114,111,112,101,114,116,121,46,32,84,104,105,115,32,112,114,111,112,101,114,116,121,32,105,115,32,105,110,115,116,101,97,100,32,97,115,115,117,109,101,100,32,102,111,114,32,97,110,121,32,99,111,100,101,32,112,111,105,110,116,32,116,104,97,116,32,105,115,32,110,111,116,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,116,97,98,108,101,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,112,123,76,117,125,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,111,110,108,121,32,117,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,115,46,32,84,104,105,115,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,99,117,114,114,101,110,116,32,118,101,114,115,105,111,110,115,32,111,102,32,80,101,114,108,46>>]},{p,[],[<<77,97,116,99,104,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,105,115,32,110,111,116,32,102,97,115,116,44,32,97,115,32,80,67,82,69,32,109,117,115,116,32,100,111,32,97,32,109,117,108,116,105,115,116,97,103,101,32,116,97,98,108,101,32,108,111,111,107,117,112,32,116,111,32,102,105,110,100,32,97,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,121,46,32,84,104,97,116,32,105,115,32,119,104,121,32,116,104,101,32,116,114,97,100,105,116,105,111,110,97,108,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32,92,100,32,97,110,100,32,92,119,32,100,111,32,110,111,116,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,105,110,32,80,67,82,69,32,98,121,32,100,101,102,97,117,108,116,46,32,72,111,119,101,118,101,114,44,32,121,111,117,32,99,97,110,32,109,97,107,101,32,116,104,101,109,32,100,111,32,115,111,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,111,114,32,98,121,32,115,116,97,114,116,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,40,42,85,67,80,41,46>>]},{p,[],[{em,[],[<<69,120,116,101,110,100,101,100,32,71,114,97,112,104,101,109,101,32,67,108,117,115,116,101,114,115>>]}]},{p,[],[<<84,104,101,32,92,88,32,101,115,99,97,112,101,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,102,111,114,109,32,97,110,32,34,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,34,44,32,97,110,100,32,116,114,101,97,116,115,32,116,104,101,32,115,101,113,117,101,110,99,101,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,40,115,101,101,32,98,101,108,111,119,41,46,32,85,112,32,116,111,32,97,110,100,32,105,110,99,108,117,100,105,110,103,32,114,101,108,101,97,115,101,32,56,46,51,49,44,32,80,67,82,69,32,109,97,116,99,104,101,100,32,97,110,32,101,97,114,108,105,101,114,44,32,115,105,109,112,108,101,114,32,100,101,102,105,110,105,116,105,111,110,32,116,104,97,116,32,119,97,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<40,63,62,92,80,77,92,112,77,42,41>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,116,32,109,97,116,99,104,101,100,32,97,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,111,117,116,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,44,32,102,111,108,108,111,119,101,100,32,98,121,32,122,101,114,111,32,111,114,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,46,32,67,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,32,97,114,101,32,116,121,112,105,99,97,108,108,121,32,110,111,110,45,115,112,97,99,105,110,103,32,97,99,99,101,110,116,115,32,116,104,97,116,32,97,102,102,101,99,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,99,104,97,114,97,99,116,101,114,46>>]},{p,[],[<<84,104,105,115,32,115,105,109,112,108,101,32,100,101,102,105,110,105,116,105,111,110,32,119,97,115,32,101,120,116,101,110,100,101,100,32,105,110,32,85,110,105,99,111,100,101,32,116,111,32,105,110,99,108,117,100,101,32,109,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,107,105,110,100,115,32,111,102,32,99,111,109,112,111,115,105,116,101,32,99,104,97,114,97,99,116,101,114,32,98,121,32,103,105,118,105,110,103,32,101,97,99,104,32,99,104,97,114,97,99,116,101,114,32,97,32,103,114,97,112,104,101,109,101,32,98,114,101,97,107,105,110,103,32,112,114,111,112,101,114,116,121,44,32,97,110,100,32,99,114,101,97,116,105,110,103,32,114,117,108,101,115,32,116,104,97,116,32,117,115,101,32,116,104,101,115,101,32,112,114,111,112,101,114,116,105,101,115,32,116,111,32,100,101,102,105,110,101,32,116,104,101,32,98,111,117,110,100,97,114,105,101,115,32,111,102,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,115,46,32,73,110,32,80,67,82,69,32,114,101,108,101,97,115,101,115,32,108,97,116,101,114,32,116,104,97,110,32,56,46,51,49,44,32,92,88,32,109,97,116,99,104,101,115,32,111,110,101,32,111,102,32,116,104,101,115,101,32,99,108,117,115,116,101,114,115,46>>]},{p,[],[<<92,88,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,97,116,32,108,101,97,115,116,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,110,32,105,116,32,100,101,99,105,100,101,115,32,119,104,101,116,104,101,114,32,116,111,32,97,100,100,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,117,108,101,115,32,102,111,114,32,101,110,100,105,110,103,32,97,32,99,108,117,115,116,101,114,58>>]},{ol,[],[{li,[],[{p,[],[<<69,110,100,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,98,101,116,119,101,101,110,32,67,82,32,97,110,100,32,76,70,59,32,111,116,104,101,114,119,105,115,101,32,101,110,100,32,97,102,116,101,114,32,97,110,121,32,99,111,110,116,114,111,108,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,98,114,101,97,107,32,72,97,110,103,117,108,32,40,97,32,75,111,114,101,97,110,32,115,99,114,105,112,116,41,32,115,121,108,108,97,98,108,101,32,115,101,113,117,101,110,99,101,115,46,32,72,97,110,103,117,108,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,111,102,32,102,105,118,101,32,116,121,112,101,115,58,32,76,44,32,86,44,32,84,44,32,76,86,44,32,97,110,100,32,76,86,84,46,32,65,110,32,76,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,76,44,32,86,44,32,76,86,44,32,111,114,32,76,86,84,32,99,104,97,114,97,99,116,101,114,46,32,65,110,32,76,86,32,111,114,32,86,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,86,32,111,114,32,84,32,99,104,97,114,97,99,116,101,114,46,32,65,110,32,76,86,84,32,111,114,32,84,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,111,110,108,121,32,98,121,32,97,32,84,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,98,101,102,111,114,101,32,101,120,116,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,111,114,32,115,112,97,99,105,110,103,32,109,97,114,107,115,46,32,67,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,32,97,108,119,97,121,115,32,104,97,118,101,32,116,104,101,32,34,101,120,116,101,110,100,34,32,103,114,97,112,104,101,109,101,32,98,114,101,97,107,105,110,103,32,112,114,111,112,101,114,116,121,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,97,102,116,101,114,32,112,114,101,112,101,110,100,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{li,[],[{p,[],[<<79,116,104,101,114,119,105,115,101,44,32,101,110,100,32,116,104,101,32,99,108,117,115,116,101,114,46>>]}]}]},{p,[],[{em,[],[<<80,67,82,69,32,65,100,100,105,116,105,111,110,97,108,32,80,114,111,112,101,114,116,105,101,115>>]}]},{p,[],[<<73,110,32,97,100,100,105,116,105,111,110,32,116,111,32,116,104,101,32,115,116,97,110,100,97,114,100,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,102,111,117,114,32,109,111,114,101,32,116,104,97,116,32,109,97,107,101,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,99,111,110,118,101,114,116,32,116,114,97,100,105,116,105,111,110,97,108,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,115,117,99,104,32,97,115,32,92,119,32,97,110,100,32,92,115,32,116,111,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,46,32,80,67,82,69,32,117,115,101,115,32,116,104,101,115,101,32,110,111,110,45,115,116,97,110,100,97,114,100,44,32,110,111,110,45,80,101,114,108,32,112,114,111,112,101,114,116,105,101,115,32,105,110,116,101,114,110,97,108,108,121,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<117,99,112>>]},<<32,111,112,116,105,111,110,32,105,115,32,112,97,115,115,101,100,46,32,72,111,119,101,118,101,114,44,32,116,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,101,120,112,108,105,99,105,116,108,121,46,32,84,104,101,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<88,97,110>>]},{dd,[],[{p,[],[<<65,110,121,32,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,101,105,116,104,101,114,32,116,104,101,32,76,32,40,108,101,116,116,101,114,41,32,111,114,32,116,104,101,32,78,32,40,110,117,109,98,101,114,41,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<88,112,115>>]},{dd,[],[{p,[],[<<65,110,121,32,80,111,115,105,120,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,97,98,44,32,108,105,110,101,32,102,101,101,100,44,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,109,32,102,101,101,100,44,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,97,110,100,32,97,110,121,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,90,32,40,115,101,112,97,114,97,116,111,114,41,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<88,115,112>>]},{dd,[],[{p,[],[<<65,110,121,32,80,101,114,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,97,115,32,88,112,115,44,32,101,120,99,101,112,116,32,116,104,97,116,32,118,101,114,116,105,99,97,108,32,116,97,98,32,105,115,32,101,120,99,108,117,100,101,100,46>>]}]},{dt,[],[<<88,119,100>>]},{dd,[],[{p,[],[<<65,110,121,32,80,101,114,108,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,88,97,110,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101,46>>]}]}]},{p,[],[<<80,101,114,108,32,97,110,100,32,80,79,83,73,88,32,115,112,97,99,101,32,97,114,101,32,110,111,119,32,116,104,101,32,115,97,109,101,46,32,80,101,114,108,32,97,100,100,101,100,32,86,84,32,116,111,32,105,116,115,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,32,115,101,116,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,32,97,110,100,32,80,67,82,69,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46>>]},{p,[],[<<88,97,110,32,109,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,101,105,116,104,101,114,32,116,104,101,32,76,32,40,108,101,116,116,101,114,41,32,111,114,32,116,104,101,32,78,32,40,110,117,109,98,101,114,41,32,112,114,111,112,101,114,116,121,46,32,88,112,115,32,109,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,97,98,44,32,108,105,110,101,102,101,101,100,44,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,109,32,102,101,101,100,44,32,111,114,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,97,110,100,32,97,110,121,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,90,32,40,115,101,112,97,114,97,116,111,114,41,32,112,114,111,112,101,114,116,121,46,32,88,115,112,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,88,112,115,59,32,105,116,32,117,115,101,100,32,116,111,32,101,120,99,108,117,100,101,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,44,32,98,117,116,32,80,101,114,108,32,99,104,97,110,103,101,100,44,32,97,110,100,32,115,111,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,88,119,100,32,109,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,88,97,110,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101,46>>]},{p,[],[<<84,104,101,114,101,32,105,115,32,97,110,111,116,104,101,114,32,110,111,110,45,115,116,97,110,100,97,114,100,32,112,114,111,112,101,114,116,121,44,32,88,117,99,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,85,110,105,118,101,114,115,97,108,32,67,104,97,114,97,99,116,101,114,32,78,97,109,101,32,105,110,32,67,43,43,32,97,110,100,32,111,116,104,101,114,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,115,46,32,84,104,101,115,101,32,97,114,101,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,36,44,32,64,44,32,96,32,40,103,114,97,118,101,32,97,99,99,101,110,116,41,44,32,97,110,100,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,62,61,32,85,43,48,48,65,48,44,32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,115,117,114,114,111,103,97,116,101,115,32,85,43,68,56,48,48,32,116,111,32,85,43,68,70,70,70,46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,115,116,32,98,97,115,101,32,40,65,83,67,73,73,41,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,101,120,99,108,117,100,101,100,46,32,40,85,110,105,118,101,114,115,97,108,32,67,104,97,114,97,99,116,101,114,32,78,97,109,101,115,32,97,114,101,32,111,102,32,116,104,101,32,102,111,114,109,32,92,117,72,72,72,72,32,111,114,32,92,85,72,72,72,72,72,72,72,72,44,32,119,104,101,114,101,32,72,32,105,115,32,97,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,88,117,99,32,112,114,111,112,101,114,116,121,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,98,117,116,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,116,104,101,121,32,114,101,112,114,101,115,101,110,116,46,41>>]},{p,[],[{em,[],[<<82,101,115,101,116,116,105,110,103,32,116,104,101,32,77,97,116,99,104,32,83,116,97,114,116>>]}]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,75,32,99,97,117,115,101,115,32,97,110,121,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,32,99,104,97,114,97,99,116,101,114,115,32,110,111,116,32,116,111,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,102,105,110,97,108,32,109,97,116,99,104,101,100,32,115,101,113,117,101,110,99,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,98,97,114,34,44,32,98,117,116,32,114,101,112,111,114,116,115,32,116,104,97,116,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,32,34,98,97,114,34,58>>]},{pre,[],[{code,[],[<<102,111,111,92,75,98,97,114>>]}]},{p,[],[<<84,104,105,115,32,102,101,97,116,117,114,101,32,105,115,32,115,105,109,105,108,97,114,32,116,111,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,46,32,72,111,119,101,118,101,114,44,32,105,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,98,101,102,111,114,101,32,116,104,101,32,114,101,97,108,32,109,97,116,99,104,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,116,111,32,98,101,32,111,102,32,102,105,120,101,100,32,108,101,110,103,116,104,44,32,97,115,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,100,111,46,32,84,104,101,32,117,115,101,32,111,102,32,92,75,32,100,111,101,115,32,110,111,116,32,105,110,116,101,114,102,101,114,101,32,119,105,116,104,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,98,97,114,34,44,32,116,104,101,32,102,105,114,115,116,32,115,117,98,115,116,114,105,110,103,32,105,115,32,115,116,105,108,108,32,115,101,116,32,116,111,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,102,111,111,41,92,75,98,97,114>>]}]},{p,[],[<<80,101,114,108,32,100,111,99,117,109,101,110,116,115,32,116,104,97,116,32,116,104,101,32,117,115,101,32,111,102,32,92,75,32,119,105,116,104,105,110,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,34,110,111,116,32,119,101,108,108,32,100,101,102,105,110,101,100,34,46,32,73,110,32,80,67,82,69,44,32,92,75,32,105,115,32,97,99,116,101,100,32,117,112,111,110,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,44,32,98,117,116,32,105,115,32,105,103,110,111,114,101,100,32,105,110,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,78,111,116,101,32,116,104,97,116,32,119,104,101,110,32,97,32,112,97,116,116,101,114,110,32,115,117,99,104,32,97,115,32,40,63,61,97,98,92,75,41,32,109,97,116,99,104,101,115,44,32,116,104,101,32,114,101,112,111,114,116,101,100,32,115,116,97,114,116,32,111,102,32,116,104,101,32,109,97,116,99,104,32,99,97,110,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,109,97,116,99,104,46>>]},{p,[],[{em,[],[<<83,105,109,112,108,101,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<84,104,101,32,102,105,110,97,108,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,105,115,32,102,111,114,32,99,101,114,116,97,105,110,32,115,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,112,101,99,105,102,105,101,115,32,97,32,99,111,110,100,105,116,105,111,110,32,116,104,97,116,32,109,117,115,116,32,98,101,32,109,101,116,32,97,116,32,97,32,112,97,114,116,105,99,117,108,97,114,32,112,111,105,110,116,32,105,110,32,97,32,109,97,116,99,104,44,32,119,105,116,104,111,117,116,32,99,111,110,115,117,109,105,110,103,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,101,32,117,115,101,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,109,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,98,97,99,107,115,108,97,115,104,101,100,32,97,115,115,101,114,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[<<92,98>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,46>>]},{dt,[],[<<92,66>>]},{dd,[],[<<77,97,116,99,104,101,115,32,119,104,101,110,32,110,111,116,32,97,116,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,46>>]},{dt,[],[<<92,65>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,90>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,110,100,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,122>>]},{dd,[],[<<77,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,71>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46>>]}]},{p,[],[<<73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,98,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,59,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,73,102,32,97,110,121,32,111,116,104,101,114,32,111,102,32,116,104,101,115,101,32,97,115,115,101,114,116,105,111,110,115,32,97,112,112,101,97,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,98,121,32,100,101,102,97,117,108,116,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,92,66,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,32,66,41,46>>]},{p,[],[<<65,32,119,111,114,100,32,98,111,117,110,100,97,114,121,32,105,115,32,97,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,104,101,114,101,32,116,104,101,32,99,117,114,114,101,110,116,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,97,114,97,99,116,101,114,32,100,111,32,110,111,116,32,98,111,116,104,32,109,97,116,99,104,32,92,119,32,111,114,32,92,87,32,40,116,104,97,116,32,105,115,44,32,111,110,101,32,109,97,116,99,104,101,115,32,92,119,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,109,97,116,99,104,101,115,32,92,87,41,44,32,111,114,32,116,104,101,32,115,116,97,114,116,32,111,114,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,105,102,32,116,104,101,32,102,105,114,115,116,32,111,114,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,109,97,116,99,104,101,115,32,92,119,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,73,110,32,85,84,70,32,109,111,100,101,44,32,116,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,92,119,32,97,110,100,32,92,87,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<46,32,87,104,101,110,32,116,104,105,115,32,105,115,32,100,111,110,101,44,32,105,116,32,97,108,115,111,32,97,102,102,101,99,116,115,32,92,98,32,97,110,100,32,92,66,46,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,100,111,32,110,111,116,32,104,97,118,101,32,97,32,115,101,112,97,114,97,116,101,32,34,115,116,97,114,116,32,111,102,32,119,111,114,100,34,32,111,114,32,34,101,110,100,32,111,102,32,119,111,114,100,34,32,109,101,116,97,115,101,113,117,101,110,99,101,46,32,72,111,119,101,118,101,114,44,32,119,104,97,116,101,118,101,114,32,102,111,108,108,111,119,115,32,92,98,32,110,111,114,109,97,108,108,121,32,100,101,116,101,114,109,105,110,101,115,32,119,104,105,99,104,32,105,116,32,105,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,114,97,103,109,101,110,116,32,92,98,97,32,109,97,116,99,104,101,115,32,34,97,34,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,119,111,114,100,46>>]},{p,[],[<<84,104,101,32,92,65,44,32,92,90,44,32,97,110,100,32,92,122,32,97,115,115,101,114,116,105,111,110,115,32,100,105,102,102,101,114,32,102,114,111,109,32,116,104,101,32,116,114,97,100,105,116,105,111,110,97,108,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,40,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,32,105,110,32,116,104,97,116,32,116,104,101,121,32,111,110,108,121,32,101,118,101,114,32,109,97,116,99,104,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,97,110,100,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,97,116,101,118,101,114,32,111,112,116,105,111,110,115,32,97,114,101,32,115,101,116,46,32,84,104,117,115,44,32,116,104,101,121,32,97,114,101,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,46,32,84,104,101,115,101,32,116,104,114,101,101,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,110,111,116,32,97,102,102,101,99,116,101,100,32,98,121,32,111,112,116,105,111,110,115,32>>,{code,[],[<<110,111,116,98,111,108>>]},<<32,111,114,32>>,{code,[],[<<110,111,116,101,111,108>>]},<<44,32,119,104,105,99,104,32,97,102,102,101,99,116,32,111,110,108,121,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,105,115,32,110,111,110,45,122,101,114,111,44,32,105,110,100,105,99,97,116,105,110,103,32,116,104,97,116,32,109,97,116,99,104,105,110,103,32,105,115,32,116,111,32,115,116,97,114,116,32,97,116,32,97,32,112,111,105,110,116,32,111,116,104,101,114,32,116,104,97,110,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,92,65,32,99,97,110,32,110,101,118,101,114,32,109,97,116,99,104,46,32,84,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32,92,90,32,97,110,100,32,92,122,32,105,115,32,116,104,97,116,32,92,90,32,109,97,116,99,104,101,115,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,97,110,100,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,44,32,119,104,105,108,101,32,92,122,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,46>>]},{p,[],[<<84,104,101,32,92,71,32,97,115,115,101,114,116,105,111,110,32,105,115,32,116,114,117,101,32,111,110,108,121,32,119,104,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,105,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,112,111,105,110,116,32,111,102,32,116,104,101,32,109,97,116,99,104,44,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<46,32,73,116,32,100,105,102,102,101,114,115,32,102,114,111,109,32,92,65,32,119,104,101,110,32,116,104,101,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,105,115,32,110,111,110,45,122,101,114,111,46,32,66,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,119,105,116,104,32,97,112,112,114,111,112,114,105,97,116,101,32,97,114,103,117,109,101,110,116,115,44,32,121,111,117,32,99,97,110,32,109,105,109,105,99,32,116,104,101,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,103>>]},<<44,32,97,110,100,32,105,116,32,105,115,32,105,110,32,116,104,105,115,32,107,105,110,100,32,111,102,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,119,104,101,114,101,32,92,71,32,99,97,110,32,98,101,32,117,115,101,102,117,108,46>>]},{p,[],[<<78,111,116,105,99,101,44,32,104,111,119,101,118,101,114,44,32,116,104,97,116,32,116,104,101,32,80,67,82,69,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,92,71,44,32,97,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,44,32,105,115,32,115,117,98,116,108,121,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,80,101,114,108,44,32,119,104,105,99,104,32,100,101,102,105,110,101,115,32,105,116,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,109,97,116,99,104,46,32,73,110,32,80,101,114,108,44,32,116,104,101,115,101,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,119,104,101,110,32,116,104,101,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,32,115,116,114,105,110,103,32,119,97,115,32,101,109,112,116,121,46,32,65,115,32,80,67,82,69,32,100,111,101,115,32,111,110,108,121,32,111,110,101,32,109,97,116,99,104,32,97,116,32,97,32,116,105,109,101,44,32,105,116,32,99,97,110,110,111,116,32,114,101,112,114,111,100,117,99,101,32,116,104,105,115,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<73,102,32,97,108,108,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,111,102,32,97,32,112,97,116,116,101,114,110,32,98,101,103,105,110,32,119,105,116,104,32,92,71,44,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,110,99,104,111,114,101,100,32,116,111,32,116,104,101,32,115,116,97,114,116,105,110,103,32,109,97,116,99,104,32,112,111,115,105,116,105,111,110,44,32,97,110,100,32,116,104,101,32,34,97,110,99,104,111,114,101,100,34,32,102,108,97,103,32,105,115,32,115,101,116,32,105,110,32,116,104,101,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{a,[{id,<<115,101,99,116,52>>}],[]},{h2,[],[<<67,105,114,99,117,109,102,108,101,120,32,97,110,100,32,68,111,108,108,97,114>>]},{p,[],[<<84,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,122,101,114,111,45,119,105,100,116,104,32,97,115,115,101,114,116,105,111,110,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,121,32,116,101,115,116,32,102,111,114,32,97,32,112,97,114,116,105,99,117,108,97,114,32,99,111,110,100,105,116,105,111,110,32,116,111,32,98,101,32,116,114,117,101,32,119,105,116,104,111,117,116,32,99,111,110,115,117,109,105,110,103,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,105,110,32,116,104,101,32,100,101,102,97,117,108,116,32,109,97,116,99,104,105,110,103,32,109,111,100,101,44,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,32,111,110,108,121,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,73,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,105,115,32,110,111,110,45,122,101,114,111,44,32,99,105,114,99,117,109,102,108,101,120,32,99,97,110,32,110,101,118,101,114,32,109,97,116,99,104,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,117,110,115,101,116,46,32,73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,99,105,114,99,117,109,102,108,101,120,32,104,97,115,32,97,110,32,101,110,116,105,114,101,108,121,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,32,40,115,101,101,32,98,101,108,111,119,41,46>>]},{p,[],[<<67,105,114,99,117,109,102,108,101,120,32,110,101,101,100,115,32,110,111,116,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,102,32,115,111,109,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,118,111,108,118,101,100,44,32,98,117,116,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,116,104,105,110,103,32,105,110,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,101,118,101,114,32,116,111,32,109,97,116,99,104,32,116,104,97,116,32,98,114,97,110,99,104,46,32,73,102,32,97,108,108,32,112,111,115,115,105,98,108,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,115,116,97,114,116,32,119,105,116,104,32,97,32,99,105,114,99,117,109,102,108,101,120,44,32,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,99,111,110,115,116,114,97,105,110,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,105,116,32,105,115,32,115,97,105,100,32,116,111,32,98,101,32,97,110,32,34,97,110,99,104,111,114,101,100,34,32,112,97,116,116,101,114,110,46,32,40,84,104,101,114,101,32,97,114,101,32,97,108,115,111,32,111,116,104,101,114,32,99,111,110,115,116,114,117,99,116,115,32,116,104,97,116,32,99,97,110,32,99,97,117,115,101,32,97,32,112,97,116,116,101,114,110,32,116,111,32,98,101,32,97,110,99,104,111,114,101,100,46,41>>]},{p,[],[<<84,104,101,32,100,111,108,108,97,114,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,32,111,110,108,121,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,40,98,121,32,100,101,102,97,117,108,116,41,46,32,78,111,116,105,99,101,32,104,111,119,101,118,101,114,32,116,104,97,116,32,105,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,110,101,119,108,105,110,101,46,32,68,111,108,108,97,114,32,110,101,101,100,115,32,110,111,116,32,116,111,32,98,101,32,116,104,101,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,102,32,115,111,109,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,118,111,108,118,101,100,44,32,98,117,116,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,105,110,32,97,110,121,32,98,114,97,110,99,104,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,46,32,68,111,108,108,97,114,32,104,97,115,32,110,111,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,100,111,108,108,97,114,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,105,116,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,84,104,105,115,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,92,90,32,97,115,115,101,114,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,99,104,97,110,103,101,100,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46,32,87,104,101,110,32,116,104,105,115,32,105,115,32,116,104,101,32,99,97,115,101,44,32,97,32,99,105,114,99,117,109,102,108,101,120,32,109,97,116,99,104,101,115,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,105,110,116,101,114,110,97,108,32,110,101,119,108,105,110,101,115,32,97,110,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,73,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,97,102,116,101,114,32,97,32,110,101,119,108,105,110,101,32,116,104,97,116,32,101,110,100,115,32,116,104,101,32,115,116,114,105,110,103,46,32,65,32,100,111,108,108,97,114,32,109,97,116,99,104,101,115,32,98,101,102,111,114,101,32,97,110,121,32,110,101,119,108,105,110,101,115,32,105,110,32,116,104,101,32,115,116,114,105,110,103,44,32,97,110,100,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,44,32,119,104,101,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46,32,87,104,101,110,32,110,101,119,108,105,110,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,44,32,105,115,111,108,97,116,101,100,32,67,82,32,97,110,100,32,76,70,32,99,104,97,114,97,99,116,101,114,115,32,100,111,32,110,111,116,32,105,110,100,105,99,97,116,101,32,110,101,119,108,105,110,101,115,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,112,97,116,116,101,114,110,32,47,94,97,98,99,36,47,32,109,97,116,99,104,101,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,34,100,101,102,92,110,97,98,99,34,32,40,119,104,101,114,101,32,92,110,32,114,101,112,114,101,115,101,110,116,115,32,97,32,110,101,119,108,105,110,101,41,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,44,32,98,117,116,32,110,111,116,32,111,116,104,101,114,119,105,115,101,46,32,83,111,44,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,97,110,99,104,111,114,101,100,32,105,110,32,115,105,110,103,108,101,45,108,105,110,101,32,109,111,100,101,32,98,101,99,97,117,115,101,32,97,108,108,32,98,114,97,110,99,104,101,115,32,115,116,97,114,116,32,119,105,116,104,32,94,32,97,114,101,32,110,111,116,32,97,110,99,104,111,114,101,100,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,44,32,97,110,100,32,97,32,109,97,116,99,104,32,102,111,114,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,112,111,115,115,105,98,108,101,32,119,104,101,110,32,97,114,103,117,109,101,110,116,32>>,{em,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,105,115,32,110,111,110,45,122,101,114,111,46,32,79,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,105,115,32,105,103,110,111,114,101,100,32,105,102,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,92,65,44,32,92,90,44,32,97,110,100,32,92,122,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,115,116,97,114,116,32,97,110,100,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,110,32,98,111,116,104,32,109,111,100,101,115,46,32,73,102,32,97,108,108,32,98,114,97,110,99,104,101,115,32,111,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,32,119,105,116,104,32,92,65,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32,97,110,99,104,111,114,101,100,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46>>]},{a,[{id,<<115,101,99,116,53>>}],[]},{h2,[],[<<70,117,108,108,32,83,116,111,112,32,40,80,101,114,105,111,100,44,32,68,111,116,41,32,97,110,100,32,92,78>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,32,100,111,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,101,120,99,101,112,116,32,40,98,121,32,100,101,102,97,117,108,116,41,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,115,105,103,110,105,102,105,101,115,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,46>>]},{p,[],[<<87,104,101,110,32,97,32,108,105,110,101,32,101,110,100,105,110,103,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,100,111,116,32,110,101,118,101,114,32,109,97,116,99,104,101,115,32,116,104,97,116,32,99,104,97,114,97,99,116,101,114,46,32,87,104,101,110,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,32,105,115,32,117,115,101,100,44,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,67,82,32,105,102,32,105,116,32,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,76,70,44,32,111,116,104,101,114,119,105,115,101,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,105,115,111,108,97,116,101,100,32,67,82,115,32,97,110,100,32,76,70,115,41,46,32,87,104,101,110,32,97,110,121,32,85,110,105,99,111,100,101,32,108,105,110,101,32,101,110,100,105,110,103,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,44,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,67,82,44,32,76,70,44,32,111,114,32,97,110,121,32,111,102,32,116,104,101,32,111,116,104,101,114,32,108,105,110,101,45,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,100,111,116,32,114,101,103,97,114,100,105,110,103,32,110,101,119,108,105,110,101,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,32,100,111,116,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,44,32,119,105,116,104,111,117,116,32,101,120,99,101,112,116,105,111,110,46,32,73,102,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,116,97,107,101,115,32,116,119,111,32,100,111,116,115,32,116,111,32,109,97,116,99,104,32,105,116,46>>]},{p,[],[<<84,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,100,111,116,32,105,115,32,101,110,116,105,114,101,108,121,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,44,32,116,104,101,32,111,110,108,121,32,114,101,108,97,116,105,111,110,115,104,105,112,32,105,115,32,116,104,97,116,32,98,111,116,104,32,105,110,118,111,108,118,101,32,110,101,119,108,105,110,101,115,46,32,68,111,116,32,104,97,115,32,110,111,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46>>]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,78,32,98,101,104,97,118,101,115,32,108,105,107,101,32,97,32,100,111,116,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,105,115,32,110,111,116,32,97,102,102,101,99,116,101,100,32,98,121,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,68,79,84,65,76,76>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,116,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,101,120,99,101,112,116,32,111,110,101,32,116,104,97,116,32,115,105,103,110,105,102,105,101,115,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,46,32,80,101,114,108,32,97,108,115,111,32,117,115,101,115,32,92,78,32,116,111,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,110,97,109,101,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46>>]},{a,[{id,<<115,101,99,116,54>>}],[]},{h2,[],[<<77,97,116,99,104,105,110,103,32,97,32,83,105,110,103,108,101,32,68,97,116,97,32,85,110,105,116>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,67,32,109,97,116,99,104,101,115,32,97,110,121,32,100,97,116,97,32,117,110,105,116,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,97,32,85,84,70,32,109,111,100,101,32,105,115,32,115,101,116,46,32,79,110,101,32,100,97,116,97,32,117,110,105,116,32,105,115,32,111,110,101,32,98,121,116,101,46,32,85,110,108,105,107,101,32,97,32,100,111,116,44,32,92,67,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,108,105,110,101,45,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,102,101,97,116,117,114,101,32,105,115,32,112,114,111,118,105,100,101,100,32,105,110,32,80,101,114,108,32,116,111,32,109,97,116,99,104,32,105,110,100,105,118,105,100,117,97,108,32,98,121,116,101,115,32,105,110,32,85,84,70,45,56,32,109,111,100,101,44,32,98,117,116,32,105,116,32,105,115,32,117,110,99,108,101,97,114,32,104,111,119,32,105,116,32,99,97,110,32,117,115,101,102,117,108,108,121,32,98,101,32,117,115,101,100,46,32,65,115,32,92,67,32,98,114,101,97,107,115,32,117,112,32,99,104,97,114,97,99,116,101,114,115,32,105,110,116,111,32,105,110,100,105,118,105,100,117,97,108,32,100,97,116,97,32,117,110,105,116,115,44,32,109,97,116,99,104,105,110,103,32,111,110,101,32,117,110,105,116,32,119,105,116,104,32,92,67,32,105,110,32,97,32,85,84,70,32,109,111,100,101,32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,116,114,105,110,103,32,99,97,110,32,115,116,97,114,116,32,119,105,116,104,32,97,32,109,97,108,102,111,114,109,101,100,32,85,84,70,32,99,104,97,114,97,99,116,101,114,46,32,84,104,105,115,32,104,97,115,32,117,110,100,101,102,105,110,101,100,32,114,101,115,117,108,116,115,44,32,97,115,32,80,67,82,69,32,97,115,115,117,109,101,115,32,116,104,97,116,32,105,116,32,100,101,97,108,115,32,119,105,116,104,32,118,97,108,105,100,32,85,84,70,32,115,116,114,105,110,103,115,46>>]},{p,[],[<<80,67,82,69,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,92,67,32,116,111,32,97,112,112,101,97,114,32,105,110,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,32,105,110,32,97,32,85,84,70,32,109,111,100,101,44,32,97,115,32,116,104,105,115,32,119,111,117,108,100,32,109,97,107,101,32,105,116,32,105,109,112,111,115,115,105,98,108,101,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,111,111,107,98,101,104,105,110,100,46>>]},{p,[],[<<84,104,101,32,92,67,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,105,115,32,98,101,115,116,32,97,118,111,105,100,101,100,46,32,72,111,119,101,118,101,114,44,32,111,110,101,32,119,97,121,32,111,102,32,117,115,105,110,103,32,105,116,32,116,104,97,116,32,97,118,111,105,100,115,32,116,104,101,32,112,114,111,98,108,101,109,32,111,102,32,109,97,108,102,111,114,109,101,100,32,85,84,70,32,99,104,97,114,97,99,116,101,114,115,32,105,115,32,116,111,32,117,115,101,32,97,32,108,111,111,107,97,104,101,97,100,32,116,111,32,99,104,101,99,107,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,44,32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,32,85,84,70,45,56,32,115,116,114,105,110,103,32,40,105,103,110,111,114,101,32,119,104,105,116,101,115,112,97,99,101,32,97,110,100,32,108,105,110,101,32,98,114,101,97,107,115,41,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,124,32,40,63,61,91,92,120,48,48,45,92,120,55,102,93,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,56,48,45,92,120,123,55,102,102,125,93,41,40,92,67,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,123,56,48,48,125,45,92,120,123,102,102,102,102,125,93,41,40,92,67,41,40,92,67,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,123,49,48,48,48,48,125,45,92,120,123,49,102,102,102,102,102,125,93,41,40,92,67,41,40,92,67,41,40,92,67,41,40,92,67,41,41>>]}]},{p,[],[<<65,32,103,114,111,117,112,32,116,104,97,116,32,115,116,97,114,116,115,32,119,105,116,104,32,40,63,124,32,114,101,115,101,116,115,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,110,117,109,98,101,114,115,32,105,110,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},<<41,46,32,84,104,101,32,97,115,115,101,114,116,105,111,110,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,98,114,97,110,99,104,32,99,104,101,99,107,32,116,104,101,32,110,101,120,116,32,85,84,70,45,56,32,99,104,97,114,97,99,116,101,114,32,102,111,114,32,118,97,108,117,101,115,32,119,104,111,115,101,32,101,110,99,111,100,105,110,103,32,117,115,101,115,32,49,44,32,50,44,32,51,44,32,111,114,32,52,32,98,121,116,101,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,84,104,101,32,105,110,100,105,118,105,100,117,97,108,32,98,121,116,101,115,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,97,114,101,32,116,104,101,110,32,99,97,112,116,117,114,101,100,32,98,121,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,110,117,109,98,101,114,32,111,102,32,103,114,111,117,112,115,46>>]},{a,[{id,<<115,101,99,116,55>>}],[]},{h2,[],[<<83,113,117,97,114,101,32,66,114,97,99,107,101,116,115,32,97,110,100,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]},{p,[],[<<65,110,32,111,112,101,110,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,101,114,109,105,110,97,116,101,100,32,98,121,32,97,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,46,32,65,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,111,110,32,105,116,115,32,111,119,110,32,105,115,32,110,111,116,32,115,112,101,99,105,97,108,32,98,121,32,100,101,102,97,117,108,116,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,74,65,86,65,83,67,82,73,80,84,95,67,79,77,80,65,84>>]},<<32,105,115,32,115,101,116,44,32,97,32,108,111,110,101,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,99,97,117,115,101,115,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,46,32,73,102,32,97,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,105,115,32,114,101,113,117,105,114,101,100,32,97,115,32,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,99,108,97,115,115,44,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,32,40,97,102,116,101,114,32,97,110,32,105,110,105,116,105,97,108,32,99,105,114,99,117,109,102,108,101,120,44,32,105,102,32,112,114,101,115,101,110,116,41,32,111,114,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,46>>]},{p,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,100,97,116,97,32,117,110,105,116,32,108,111,110,103,46,32,65,32,109,97,116,99,104,101,100,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,98,101,32,105,110,32,116,104,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,100,101,102,105,110,101,100,32,98,121,32,116,104,101,32,99,108,97,115,115,44,32,117,110,108,101,115,115,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,32,100,101,102,105,110,105,116,105,111,110,32,105,115,32,97,32,99,105,114,99,117,109,102,108,101,120,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,115,117,98,106,101,99,116,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,32,116,104,101,32,115,101,116,32,100,101,102,105,110,101,100,32,98,121,32,116,104,101,32,99,108,97,115,115,46,32,73,102,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,114,101,113,117,105,114,101,100,32,97,115,32,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,99,108,97,115,115,44,32,101,110,115,117,114,101,32,116,104,97,116,32,105,116,32,105,115,32,110,111,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,101,115,99,97,112,101,32,105,116,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32>>,{code,[],[<<91,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,97,110,121,32,108,111,119,101,114,99,97,115,101,32,118,111,119,101,108,44,32,119,104,105,108,101,32>>,{code,[],[<<91,94,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,108,111,119,101,114,99,97,115,101,32,118,111,119,101,108,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,106,117,115,116,32,97,32,99,111,110,118,101,110,105,101,110,116,32,110,111,116,97,116,105,111,110,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,105,110,32,116,104,101,32,99,108,97,115,115,32,98,121,32,101,110,117,109,101,114,97,116,105,110,103,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,110,111,116,46,32,65,32,99,108,97,115,115,32,116,104,97,116,32,115,116,97,114,116,115,32,119,105,116,104,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,110,111,116,32,97,110,32,97,115,115,101,114,116,105,111,110,59,32,105,116,32,115,116,105,108,108,32,99,111,110,115,117,109,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,105,116,32,102,97,105,108,115,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,105,110,116,101,114,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,46>>]},{p,[],[<<73,110,32,85,84,70,45,56,32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,40,48,120,102,102,102,102,41,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,97,32,99,108,97,115,115,32,97,115,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,111,102,32,100,97,116,97,32,117,110,105,116,115,44,32,111,114,32,98,121,32,117,115,105,110,103,32,116,104,101,32,92,120,123,32,101,115,99,97,112,105,110,103,32,109,101,99,104,97,110,105,115,109,46>>]},{p,[],[<<87,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,101,116,44,32,97,110,121,32,108,101,116,116,101,114,115,32,105,110,32,97,32,99,108,97,115,115,32,114,101,112,114,101,115,101,110,116,32,98,111,116,104,32,116,104,101,105,114,32,117,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,118,101,114,115,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,32,99,97,115,101,108,101,115,115,32>>,{code,[],[<<91,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,34,65,34,32,97,110,100,32,34,97,34,44,32,97,110,100,32,97,32,99,97,115,101,108,101,115,115,32>>,{code,[],[<<91,94,97,101,105,111,117,93>>]},<<32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,34,65,34,44,32,98,117,116,32,97,32,99,97,115,101,102,117,108,32,118,101,114,115,105,111,110,32,119,111,117,108,100,46,32,73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,80,67,82,69,32,97,108,119,97,121,115,32,117,110,100,101,114,115,116,97,110,100,115,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,118,97,108,117,101,115,32,97,114,101,32,60,32,50,53,54,44,32,115,111,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,97,108,119,97,121,115,32,112,111,115,115,105,98,108,101,46,32,70,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,104,105,103,104,101,114,32,118,97,108,117,101,115,44,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,105,115,32,115,117,112,112,111,114,116,101,100,32,111,110,108,121,32,105,102,32,80,67,82,69,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,110,32,97,32,85,84,70,32,109,111,100,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,62,61,44,32,101,110,115,117,114,101,32,116,104,97,116,32,80,67,82,69,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,32,97,110,100,32,119,105,116,104,32,85,84,70,32,115,117,112,112,111,114,116,46>>]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,99,97,110,32,105,110,100,105,99,97,116,101,32,108,105,110,101,32,98,114,101,97,107,115,32,97,114,101,32,110,101,118,101,114,32,116,114,101,97,116,101,100,32,105,110,32,97,110,121,32,115,112,101,99,105,97,108,32,119,97,121,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,44,32,119,104,97,116,101,118,101,114,32,108,105,110,101,45,101,110,100,105,110,103,32,115,101,113,117,101,110,99,101,32,105,115,32,105,110,32,117,115,101,44,32,97,110,100,32,119,104,97,116,101,118,101,114,32,115,101,116,116,105,110,103,32,111,102,32,111,112,116,105,111,110,115,32>>,{code,[],[<<80,67,82,69,95,68,79,84,65,76,76>>]},<<32,97,110,100,32>>,{code,[],[<<80,67,82,69,95,77,85,76,84,73,76,73,78,69>>]},<<32,105,115,32,117,115,101,100,46,32,65,32,99,108,97,115,115,32,115,117,99,104,32,97,115,32,91,94,97,93,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,111,110,101,32,111,102,32,116,104,101,115,101,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,109,105,110,117,115,32,40,104,121,112,104,101,110,41,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,112,101,99,105,102,121,32,97,32,114,97,110,103,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,100,45,109,93,32,109,97,116,99,104,101,115,32,97,110,121,32,108,101,116,116,101,114,32,98,101,116,119,101,101,110,32,100,32,97,110,100,32,109,44,32,105,110,99,108,117,115,105,118,101,46,32,73,102,32,97,32,109,105,110,117,115,32,99,104,97,114,97,99,116,101,114,32,105,115,32,114,101,113,117,105,114,101,100,32,105,110,32,97,32,99,108,97,115,115,44,32,105,116,32,109,117,115,116,32,98,101,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,32,111,114,32,97,112,112,101,97,114,32,105,110,32,97,32,112,111,115,105,116,105,111,110,32,119,104,101,114,101,32,105,116,32,99,97,110,110,111,116,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,105,110,100,105,99,97,116,105,110,103,32,97,32,114,97,110,103,101,44,32,116,121,112,105,99,97,108,108,121,32,97,115,32,116,104,101,32,102,105,114,115,116,32,111,114,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,44,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,97,32,114,97,110,103,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,98,45,100,45,122,93,32,109,97,116,99,104,101,115,32,108,101,116,116,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,98,32,116,111,32,100,44,32,97,32,104,121,112,104,101,110,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,122,46>>]},{p,[],[<<84,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,32,34,93,34,32,99,97,110,110,111,116,32,98,101,32,116,104,101,32,101,110,100,32,99,104,97,114,97,99,116,101,114,32,111,102,32,97,32,114,97,110,103,101,46,32,65,32,112,97,116,116,101,114,110,32,115,117,99,104,32,97,115,32,91,87,45,93,52,54,93,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,108,97,115,115,32,111,102,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,40,34,87,34,32,97,110,100,32,34,45,34,41,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,34,52,54,93,34,44,32,115,111,32,105,116,32,119,111,117,108,100,32,109,97,116,99,104,32,34,87,52,54,93,34,32,111,114,32,34,45,52,54,93,34,46,32,72,111,119,101,118,101,114,44,32,105,102,32,34,93,34,32,105,115,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,44,32,105,116,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,114,97,110,103,101,44,32,115,111,32,91,87,45,92,93,52,54,93,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,108,97,115,115,32,99,111,110,116,97,105,110,105,110,103,32,97,32,114,97,110,103,101,32,102,111,108,108,111,119,101,100,32,98,121,32,116,119,111,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,111,99,116,97,108,32,111,114,32,104,101,120,97,100,101,99,105,109,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,34,93,34,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,116,111,32,101,110,100,32,97,32,114,97,110,103,101,46>>]},{p,[],[<<65,110,32,101,114,114,111,114,32,105,115,32,103,101,110,101,114,97,116,101,100,32,105,102,32,97,32,80,79,83,73,88,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,40,115,101,101,32,98,101,108,111,119,41,32,111,114,32,97,110,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,111,116,104,101,114,32,116,104,97,110,32,111,110,101,32,116,104,97,116,32,100,101,102,105,110,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,97,112,112,101,97,114,115,32,97,116,32,97,32,112,111,105,110,116,32,119,104,101,114,101,32,97,32,114,97,110,103,101,32,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,32,105,115,32,101,120,112,101,99,116,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,122,45,92,120,102,102,93,32,105,115,32,118,97,108,105,100,44,32,98,117,116,32,91,65,45,92,100,93,32,97,110,100,32,91,65,45,91,58,100,105,103,105,116,58,93,93,32,97,114,101,32,110,111,116,46>>]},{p,[],[<<82,97,110,103,101,115,32,111,112,101,114,97,116,101,32,105,110,32,116,104,101,32,99,111,108,108,97,116,105,110,103,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,115,46,32,84,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,115,112,101,99,105,102,105,101,100,32,110,117,109,101,114,105,99,97,108,108,121,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,91,92,48,48,48,45,92,48,51,55,93,46,32,82,97,110,103,101,115,32,99,97,110,32,105,110,99,108,117,100,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,118,97,108,105,100,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,109,111,100,101,46>>]},{p,[],[<<73,102,32,97,32,114,97,110,103,101,32,116,104,97,116,32,105,110,99,108,117,100,101,115,32,108,101,116,116,101,114,115,32,105,115,32,117,115,101,100,32,119,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,101,116,44,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,115,32,105,110,32,101,105,116,104,101,114,32,99,97,115,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,87,45,99,93,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,91,93,91,92,92,94,95,96,119,120,121,122,97,98,99,93,44,32,109,97,116,99,104,101,100,32,99,97,115,101,108,101,115,115,108,121,46,32,73,110,32,97,32,110,111,110,45,85,84,70,32,109,111,100,101,44,32,105,102,32,99,104,97,114,97,99,116,101,114,32,116,97,98,108,101,115,32,102,111,114,32,97,32,70,114,101,110,99,104,32,108,111,99,97,108,101,32,97,114,101,32,105,110,32,117,115,101,44,32,91,92,120,99,56,45,92,120,99,98,93,32,109,97,116,99,104,101,115,32,97,99,99,101,110,116,101,100,32,69,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,98,111,116,104,32,99,97,115,101,115,46,32,73,110,32,85,84,70,32,109,111,100,101,115,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,111,110,108,121,32,119,104,101,110,32,105,116,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,46>>]},{p,[],[<<84,104,101,32,99,104,97,114,97,99,116,101,114,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,92,100,44,32,92,68,44,32,92,104,44,32,92,72,44,32,92,112,44,32,92,80,44,32,92,115,44,32,92,83,44,32,92,118,44,32,92,86,44,32,92,119,44,32,97,110,100,32,92,87,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,110,100,32,97,100,100,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,116,104,101,121,32,109,97,116,99,104,32,116,111,32,116,104,101,32,99,108,97,115,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,92,100,65,66,67,68,69,70,93,32,109,97,116,99,104,101,115,32,97,110,121,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,46,32,73,110,32,85,84,70,32,109,111,100,101,115,44,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,97,102,102,101,99,116,115,32,116,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,92,100,44,32,92,115,44,32,92,119,32,97,110,100,32,116,104,101,105,114,32,117,112,112,101,114,99,97,115,101,32,112,97,114,116,110,101,114,115,44,32,106,117,115,116,32,97,115,32,105,116,32,100,111,101,115,32,119,104,101,110,32,116,104,101,121,32,97,112,112,101,97,114,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,103,101,110,101,114,105,99,95,99,104,97,114,97,99,116,101,114,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<71,101,110,101,114,105,99,32,67,104,97,114,97,99,116,101,114,32,84,121,112,101,115>>]},<<32,101,97,114,108,105,101,114,46,32,84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,98,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,59,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,115,101,113,117,101,110,99,101,115,32,92,66,44,32,92,78,44,32,92,82,44,32,97,110,100,32,92,88,32,97,114,101,32,110,111,116,32,115,112,101,99,105,97,108,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,76,105,107,101,32,97,110,121,32,111,116,104,101,114,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,116,104,101,121,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,66,34,44,32,34,78,34,44,32,34,82,34,44,32,97,110,100,32,34,88,34,46>>]},{p,[],[<<65,32,99,105,114,99,117,109,102,108,101,120,32,99,97,110,32,99,111,110,118,101,110,105,101,110,116,108,121,32,98,101,32,117,115,101,100,32,119,105,116,104,32,116,104,101,32,117,112,112,101,114,99,97,115,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,32,116,111,32,115,112,101,99,105,102,121,32,97,32,109,111,114,101,32,114,101,115,116,114,105,99,116,101,100,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,110,32,116,104,101,32,109,97,116,99,104,105,110,103,32,108,111,119,101,114,99,97,115,101,32,116,121,112,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,108,97,115,115,32,91,94,92,87,95,93,32,109,97,116,99,104,101,115,32,97,110,121,32,108,101,116,116,101,114,32,111,114,32,100,105,103,105,116,44,32,98,117,116,32,110,111,116,32,117,110,100,101,114,115,99,111,114,101,44,32,119,104,105,108,101,32,91,92,119,93,32,105,110,99,108,117,100,101,115,32,117,110,100,101,114,115,99,111,114,101,46,32,65,32,112,111,115,105,116,105,118,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,105,115,32,116,111,32,98,101,32,114,101,97,100,32,97,115,32,34,115,111,109,101,116,104,105,110,103,32,79,82,32,115,111,109,101,116,104,105,110,103,32,79,82,32,46,46,46,34,32,97,110,100,32,97,32,110,101,103,97,116,105,118,101,32,99,108,97,115,115,32,97,115,32,34,78,79,84,32,115,111,109,101,116,104,105,110,103,32,65,78,68,32,78,79,84,32,115,111,109,101,116,104,105,110,103,32,65,78,68,32,78,79,84,32,46,46,46,34,46>>]},{p,[],[<<79,110,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,105,110,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,58>>]},{ul,[],[{li,[],[<<66,97,99,107,115,108,97,115,104>>]},{li,[],[<<72,121,112,104,101,110,32,40,111,110,108,121,32,119,104,101,114,101,32,105,116,32,99,97,110,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32,97,32,114,97,110,103,101,41>>]},{li,[],[<<67,105,114,99,117,109,102,108,101,120,32,40,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,41>>]},{li,[],[<<79,112,101,110,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,40,111,110,108,121,32,119,104,101,110,32,105,116,32,99,97,110,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,105,110,116,114,111,100,117,99,105,110,103,32,97,32,80,111,115,105,120,32,99,108,97,115,115,32,110,97,109,101,44,32,111,114,32,102,111,114,32,97,32,115,112,101,99,105,97,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,102,101,97,116,117,114,101,59,32,115,101,101,32,116,104,101,32,110,101,120,116,32,116,119,111,32,115,101,99,116,105,111,110,115,41>>]},{li,[],[<<84,101,114,109,105,110,97,116,105,110,103,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116>>]}]},{p,[],[<<72,111,119,101,118,101,114,44,32,101,115,99,97,112,105,110,103,32,111,116,104,101,114,32,110,111,110,45,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,115,32,100,111,101,115,32,110,111,32,104,97,114,109,46>>]},{a,[{id,<<115,101,99,116,56>>}],[]},{h2,[],[<<80,111,115,105,120,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]},{p,[],[<<80,101,114,108,32,115,117,112,112,111,114,116,115,32,116,104,101,32,80,111,115,105,120,32,110,111,116,97,116,105,111,110,32,102,111,114,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,84,104,105,115,32,117,115,101,115,32,110,97,109,101,115,32,101,110,99,108,111,115,101,100,32,98,121,32,91,58,32,97,110,100,32,58,93,32,119,105,116,104,105,110,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,46,32,80,67,82,69,32,97,108,115,111,32,115,117,112,112,111,114,116,115,32,116,104,105,115,32,110,111,116,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,48,34,44,32,34,49,34,44,32,97,110,121,32,97,108,112,104,97,98,101,116,105,99,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,34,37,34,58>>]},{pre,[],[{code,[],[<<91,48,49,91,58,97,108,112,104,97,58,93,37,93>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,115,117,112,112,111,114,116,101,100,32,99,108,97,115,115,32,110,97,109,101,115,58>>]},{dl,[],[{dt,[],[<<97,108,110,117,109>>]},{dd,[],[<<76,101,116,116,101,114,115,32,97,110,100,32,100,105,103,105,116,115>>]},{dt,[],[<<97,108,112,104,97>>]},{dd,[],[<<76,101,116,116,101,114,115>>]},{dt,[],[<<97,115,99,105,105>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,99,111,100,101,115,32,48,45,49,50,55>>]},{dt,[],[<<98,108,97,110,107>>]},{dd,[],[<<83,112,97,99,101,32,111,114,32,116,97,98,32,111,110,108,121>>]},{dt,[],[<<99,110,116,114,108>>]},{dd,[],[<<67,111,110,116,114,111,108,32,99,104,97,114,97,99,116,101,114,115>>]},{dt,[],[<<100,105,103,105,116>>]},{dd,[],[<<68,101,99,105,109,97,108,32,100,105,103,105,116,115,32,40,115,97,109,101,32,97,115,32,92,100,41>>]},{dt,[],[<<103,114,97,112,104>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,101,120,99,108,117,100,105,110,103,32,115,112,97,99,101>>]},{dt,[],[<<108,111,119,101,114>>]},{dd,[],[<<76,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115>>]},{dt,[],[<<112,114,105,110,116>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,99,108,117,100,105,110,103,32,115,112,97,99,101>>]},{dt,[],[<<112,117,110,99,116>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,101,120,99,108,117,100,105,110,103,32,108,101,116,116,101,114,115,44,32,100,105,103,105,116,115,44,32,97,110,100,32,115,112,97,99,101>>]},{dt,[],[<<115,112,97,99,101>>]},{dd,[],[<<87,104,105,116,101,115,112,97,99,101,32,40,116,104,101,32,115,97,109,101,32,97,115,32,92,115,32,102,114,111,109,32,80,67,82,69,32,56,46,51,52,41>>]},{dt,[],[<<117,112,112,101,114>>]},{dd,[],[<<85,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,115>>]},{dt,[],[<<119,111,114,100>>]},{dd,[],[<<34,87,111,114,100,34,32,99,104,97,114,97,99,116,101,114,115,32,40,115,97,109,101,32,97,115,32,92,119,41>>]},{dt,[],[<<120,100,105,103,105,116>>]},{dd,[],[<<72,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115>>]}]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,34,115,112,97,99,101,34,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,72,84,32,40,57,41,44,32,76,70,32,40,49,48,41,44,32,86,84,32,40,49,49,41,44,32,70,70,32,40,49,50,41,44,32,67,82,32,40,49,51,41,44,32,97,110,100,32,115,112,97,99,101,32,40,51,50,41,46,32,73,102,32,108,111,99,97,108,101,45,115,112,101,99,105,102,105,99,32,109,97,116,99,104,105,110,103,32,105,115,32,116,97,107,105,110,103,32,112,108,97,99,101,44,32,116,104,101,32,108,105,115,116,32,111,102,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,109,97,121,32,98,101,32,100,105,102,102,101,114,101,110,116,59,32,116,104,101,114,101,32,109,97,121,32,98,101,32,102,101,119,101,114,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,109,46,32,34,83,112,97,99,101,34,32,117,115,101,100,32,116,111,32,98,101,32,100,105,102,102,101,114,101,110,116,32,116,111,32,92,115,44,32,119,104,105,99,104,32,100,105,100,32,110,111,116,32,105,110,99,108,117,100,101,32,86,84,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,97,110,100,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,34,83,112,97,99,101,34,32,97,110,100,32,92,115,32,110,111,119,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,110,97,109,101,32,34,119,111,114,100,34,32,105,115,32,97,32,80,101,114,108,32,101,120,116,101,110,115,105,111,110,44,32,97,110,100,32,34,98,108,97,110,107,34,32,105,115,32,97,32,71,78,85,32,101,120,116,101,110,115,105,111,110,32,102,114,111,109,32,80,101,114,108,32,53,46,56,46,32,65,110,111,116,104,101,114,32,80,101,114,108,32,101,120,116,101,110,115,105,111,110,32,105,115,32,110,101,103,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,94,32,99,104,97,114,97,99,116,101,114,32,97,102,116,101,114,32,116,104,101,32,99,111,108,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,49,34,44,32,34,50,34,44,32,111,114,32,97,110,121,32,110,111,110,45,100,105,103,105,116,58>>]},{pre,[],[{code,[],[<<91,49,50,91,58,94,100,105,103,105,116,58,93,93>>]}]},{p,[],[<<80,67,82,69,32,40,97,110,100,32,80,101,114,108,41,32,97,108,115,111,32,114,101,99,111,103,110,105,122,101,32,116,104,101,32,80,111,115,105,120,32,115,121,110,116,97,120,32,91,46,99,104,46,93,32,97,110,100,32,91,61,99,104,61,93,32,119,104,101,114,101,32,34,99,104,34,32,105,115,32,97,32,34,99,111,108,108,97,116,105,110,103,32,101,108,101,109,101,110,116,34,44,32,98,117,116,32,116,104,101,115,101,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,44,32,97,110,100,32,97,110,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,105,102,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,100,111,32,110,111,116,32,109,97,116,99,104,32,97,110,121,32,111,102,32,116,104,101,32,80,111,115,105,120,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,85,67,80>>]},<<32,105,115,32,112,97,115,115,101,100,32,116,111,32>>,{code,[],[<<112,99,114,101,95,99,111,109,112,105,108,101,40,41>>]},<<44,32,115,111,109,101,32,111,102,32,116,104,101,32,99,108,97,115,115,101,115,32,97,114,101,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,46,32,84,104,105,115,32,105,115,32,97,99,104,105,101,118,101,100,32,98,121,32,114,101,112,108,97,99,105,110,103,32,99,101,114,116,97,105,110,32,80,111,115,105,120,32,99,108,97,115,115,101,115,32,98,121,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<91,58,97,108,110,117,109,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,97,110,125>>]}]},{dt,[],[<<91,58,97,108,112,104,97,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,125>>]}]},{dt,[],[<<91,58,98,108,97,110,107,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,104>>]}]},{dt,[],[<<91,58,100,105,103,105,116,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,78,100,125>>]}]},{dt,[],[<<91,58,108,111,119,101,114,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,108,125>>]}]},{dt,[],[<<91,58,115,112,97,99,101,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,112,115,125>>]}]},{dt,[],[<<91,58,117,112,112,101,114,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,117,125>>]}]},{dt,[],[<<91,58,119,111,114,100,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,119,100,125>>]}]}]},{p,[],[<<78,101,103,97,116,101,100,32,118,101,114,115,105,111,110,115,44,32,115,117,99,104,32,97,115,32,91,58,94,97,108,112,104,97,58,93,44,32,117,115,101,32,92,80,32,105,110,115,116,101,97,100,32,111,102,32,92,112,46,32,84,104,114,101,101,32,111,116,104,101,114,32,80,79,83,73,88,32,99,108,97,115,115,101,115,32,97,114,101,32,104,97,110,100,108,101,100,32,115,112,101,99,105,97,108,108,121,32,105,110,32,85,67,80,32,109,111,100,101,58>>]},{dl,[],[{dt,[],[<<91,58,103,114,97,112,104,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,103,108,121,112,104,115,32,116,104,97,116,32,109,97,114,107,32,116,104,101,32,112,97,103,101,32,119,104,101,110,32,112,114,105,110,116,101,100,46,32,73,110,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,116,101,114,109,115,44,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,76,44,32,77,44,32,78,44,32,80,44,32,83,44,32,111,114,32,67,102,32,112,114,111,112,101,114,116,105,101,115,44,32,101,120,99,101,112,116,32,102,111,114,58>>]},{dl,[],[{dt,[],[<<85,43,48,54,49,67>>]},{dd,[],[{p,[],[<<65,114,97,98,105,99,32,76,101,116,116,101,114,32,77,97,114,107>>]}]},{dt,[],[<<85,43,49,56,48,69>>]},{dd,[],[{p,[],[<<77,111,110,103,111,108,105,97,110,32,86,111,119,101,108,32,83,101,112,97,114,97,116,111,114>>]}]},{dt,[],[<<85,43,50,48,54,54,32,45,32,85,43,50,48,54,57>>]},{dd,[],[{p,[],[<<86,97,114,105,111,117,115,32,34,105,115,111,108,97,116,101,34,115>>]}]}]}]},{dt,[],[<<91,58,112,114,105,110,116,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,91,58,103,114,97,112,104,58,93,32,112,108,117,115,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,99,111,110,116,114,111,108,115,44,32,116,104,97,116,32,105,115,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,90,115,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<91,58,112,117,110,99,116,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,116,104,101,32,85,110,105,99,111,100,101,32,80,32,40,112,117,110,99,116,117,97,116,105,111,110,41,32,112,114,111,112,101,114,116,121,44,32,112,108,117,115,32,116,104,111,115,101,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,108,101,115,115,32,116,104,97,110,32,49,50,56,32,116,104,97,116,32,104,97,118,101,32,116,104,101,32,83,32,40,83,121,109,98,111,108,41,32,112,114,111,112,101,114,116,121,46>>]}]}]},{p,[],[<<84,104,101,32,111,116,104,101,114,32,80,79,83,73,88,32,99,108,97,115,115,101,115,32,97,114,101,32,117,110,99,104,97,110,103,101,100,44,32,97,110,100,32,109,97,116,99,104,32,111,110,108,121,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,32,112,111,105,110,116,115,32,108,101,115,115,32,116,104,97,110,32,49,50,56,46>>]},{p,[],[{em,[],[<<67,111,109,112,97,116,105,98,105,108,105,116,121,32,70,101,97,116,117,114,101,32,102,111,114,32,87,111,114,100,32,66,111,117,110,100,97,114,105,101,115>>]}]},{p,[],[<<73,110,32,116,104,101,32,80,79,83,73,88,46,50,32,99,111,109,112,108,105,97,110,116,32,108,105,98,114,97,114,121,32,116,104,97,116,32,119,97,115,32,105,110,99,108,117,100,101,100,32,105,110,32,52,46,52,66,83,68,32,85,110,105,120,44,32,116,104,101,32,117,103,108,121,32,115,121,110,116,97,120,32,91,91,58,60,58,93,93,32,97,110,100,32,91,91,58,62,58,93,93,32,105,115,32,117,115,101,100,32,102,111,114,32,109,97,116,99,104,105,110,103,32,34,115,116,97,114,116,32,111,102,32,119,111,114,100,34,32,97,110,100,32,34,101,110,100,32,111,102,32,119,111,114,100,34,46,32,80,67,82,69,32,116,114,101,97,116,115,32,116,104,101,115,101,32,105,116,101,109,115,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<91,91,58,60,58,93,93>>]},{dd,[],[{p,[],[<<105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,92,98,40,63,61,92,119,41>>]}]},{dt,[],[<<91,91,58,62,58,93,93>>]},{dd,[],[{p,[],[<<105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,92,98,40,63,60,61,92,119,41>>]}]}]},{p,[],[<<79,110,108,121,32,116,104,101,115,101,32,101,120,97,99,116,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,46,32,65,32,115,101,113,117,101,110,99,101,32,115,117,99,104,32,97,115,32,91,97,91,58,60,58,93,98,93,32,112,114,111,118,111,107,101,115,32,101,114,114,111,114,32,102,111,114,32,97,110,32,117,110,114,101,99,111,103,110,105,122,101,100,32,80,79,83,73,88,32,99,108,97,115,115,32,110,97,109,101,46,32,84,104,105,115,32,115,117,112,112,111,114,116,32,105,115,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,32,80,101,114,108,46,32,73,116,32,105,115,32,112,114,111,118,105,100,101,100,32,116,111,32,104,101,108,112,32,109,105,103,114,97,116,105,111,110,115,32,102,114,111,109,32,111,116,104,101,114,32,101,110,118,105,114,111,110,109,101,110,116,115,44,32,97,110,100,32,105,115,32,98,101,115,116,32,110,111,116,32,117,115,101,100,32,105,110,32,97,110,121,32,110,101,119,32,112,97,116,116,101,114,110,115,46,32,78,111,116,101,32,116,104,97,116,32,92,98,32,109,97,116,99,104,101,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,97,110,100,32,116,104,101,32,101,110,100,32,111,102,32,97,32,119,111,114,100,32,40,115,101,101,32,34,83,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,34,32,97,98,111,118,101,41,44,32,97,110,100,32,105,110,32,97,32,80,101,114,108,45,115,116,121,108,101,32,112,97,116,116,101,114,110,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,111,114,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,32,110,111,114,109,97,108,108,121,32,115,104,111,119,115,32,119,104,105,99,104,32,105,115,32,119,97,110,116,101,100,44,32,119,105,116,104,111,117,116,32,116,104,101,32,110,101,101,100,32,102,111,114,32,116,104,101,32,97,115,115,101,114,116,105,111,110,115,32,116,104,97,116,32,97,114,101,32,117,115,101,100,32,97,98,111,118,101,32,105,110,32,111,114,100,101,114,32,116,111,32,103,105,118,101,32,101,120,97,99,116,108,121,32,116,104,101,32,80,79,83,73,88,32,98,101,104,97,118,105,111,117,114,46>>]},{a,[{id,<<115,101,99,116,57>>}],[]},{h2,[],[<<86,101,114,116,105,99,97,108,32,66,97,114>>]},{p,[],[<<86,101,114,116,105,99,97,108,32,98,97,114,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,117,115,101,100,32,116,111,32,115,101,112,97,114,97,116,101,32,97,108,116,101,114,110,97,116,105,118,101,32,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,101,105,116,104,101,114,32,34,103,105,108,98,101,114,116,34,32,111,114,32,34,115,117,108,108,105,118,97,110,34,58>>]},{pre,[],[{code,[],[<<103,105,108,98,101,114,116,124,115,117,108,108,105,118,97,110>>]}]},{p,[],[<<65,110,121,32,110,117,109,98,101,114,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,115,32,99,97,110,32,97,112,112,101,97,114,44,32,97,110,100,32,97,110,32,101,109,112,116,121,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,112,101,114,109,105,116,116,101,100,32,40,109,97,116,99,104,105,110,103,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,41,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,32,116,114,105,101,115,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,117,114,110,44,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,97,110,100,32,116,104,101,32,102,105,114,115,116,32,116,104,97,116,32,115,117,99,99,101,101,100,115,32,105,115,32,117,115,101,100,46,32,73,102,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,119,105,116,104,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,100,101,102,105,110,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]},<<41,44,32,34,115,117,99,99,101,101,100,115,34,32,109,101,97,110,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,109,97,105,110,32,112,97,116,116,101,114,110,32,97,110,100,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,46>>]},{a,[{id,<<115,101,99,116,49,48>>}],[]},{h2,[],[<<73,110,116,101,114,110,97,108,32,79,112,116,105,111,110,32,83,101,116,116,105,110,103>>]},{p,[],[<<84,104,101,32,115,101,116,116,105,110,103,115,32,111,102,32,116,104,101,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<44,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<44,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,102,114,111,109,32,119,105,116,104,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,121,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,80,101,114,108,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,101,110,99,108,111,115,101,100,32,98,101,116,119,101,101,110,32,34,40,63,34,32,97,110,100,32,34,41,34,46,32,84,104,101,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<105>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]}]},{dt,[],[<<109>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]}]},{dt,[],[<<115>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<100,111,116,97,108,108>>]}]},{dt,[],[<<120>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]}]}]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<40,63,105,109,41>>]},<<32,115,101,116,115,32,99,97,115,101,108,101,115,115,44,32,109,117,108,116,105,108,105,110,101,32,109,97,116,99,104,105,110,103,46,32,84,104,101,115,101,32,111,112,116,105,111,110,115,32,99,97,110,32,97,108,115,111,32,98,101,32,117,110,115,101,116,32,98,121,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,108,101,116,116,101,114,32,119,105,116,104,32,97,32,104,121,112,104,101,110,46,32,65,32,99,111,109,98,105,110,101,100,32,115,101,116,116,105,110,103,32,97,110,100,32,117,110,115,101,116,116,105,110,103,32,115,117,99,104,32,97,115,32>>,{code,[],[<<40,63,105,109,45,115,120,41>>]},<<44,32,119,104,105,99,104,32,115,101,116,115,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<32,97,110,100,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<44,32,119,104,105,108,101,32,117,110,115,101,116,116,105,110,103,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<44,32,105,115,32,97,108,115,111,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,97,32,108,101,116,116,101,114,32,97,112,112,101,97,114,115,32,98,111,116,104,32,98,101,102,111,114,101,32,97,110,100,32,97,102,116,101,114,32,116,104,101,32,104,121,112,104,101,110,44,32,116,104,101,32,111,112,116,105,111,110,32,105,115,32,117,110,115,101,116,46>>]},{p,[],[<<84,104,101,32,80,67,82,69,45,115,112,101,99,105,102,105,99,32,111,112,116,105,111,110,115,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<44,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<44,32,97,110,100,32>>,{code,[],[<<101,120,116,114,97>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,116,104,101,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,32,111,112,116,105,111,110,115,32,98,121,32,117,115,105,110,103,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,74,44,32,85,44,32,97,110,100,32,88,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]},{p,[],[<<87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,111,112,116,105,111,110,32,99,104,97,110,103,101,115,32,111,99,99,117,114,115,32,97,116,32,116,111,112,45,108,101,118,101,108,32,40,116,104,97,116,32,105,115,44,32,110,111,116,32,105,110,115,105,100,101,32,115,117,98,112,97,116,116,101,114,110,32,112,97,114,101,110,116,104,101,115,101,115,41,44,32,116,104,101,32,99,104,97,110,103,101,32,97,112,112,108,105,101,115,32,116,111,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,116,104,97,116,32,102,111,108,108,111,119,115,46>>]},{p,[],[<<65,110,32,111,112,116,105,111,110,32,99,104,97,110,103,101,32,119,105,116,104,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]},<<41,32,97,102,102,101,99,116,115,32,111,110,108,121,32,116,104,97,116,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,102,111,108,108,111,119,115,32,105,116,46,32,83,111,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,98,99,32,97,110,100,32,97,66,99,32,97,110,100,32,110,111,32,111,116,104,101,114,32,115,116,114,105,110,103,115,32,40,97,115,115,117,109,105,110,103,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<32,105,115,32,110,111,116,32,117,115,101,100,41,58>>]},{pre,[],[{code,[],[<<40,97,40,63,105,41,98,41,99>>]}]},{p,[],[<<66,121,32,116,104,105,115,32,109,101,97,110,115,44,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,109,97,100,101,32,116,111,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,115,101,116,116,105,110,103,115,32,105,110,32,100,105,102,102,101,114,101,110,116,32,112,97,114,116,115,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,99,104,97,110,103,101,115,32,109,97,100,101,32,105,110,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,32,100,111,32,99,97,114,114,121,32,111,110,32,105,110,116,111,32,115,117,98,115,101,113,117,101,110,116,32,98,114,97,110,99,104,101,115,32,119,105,116,104,105,110,32,116,104,101,32,115,97,109,101,32,115,117,98,112,97,116,116,101,114,110,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,40,63,105,41,98,124,99,41>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,34,97,98,34,44,32,34,97,66,34,44,32,34,99,34,44,32,97,110,100,32,34,67,34,44,32,97,108,116,104,111,117,103,104,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,34,67,34,32,116,104,101,32,102,105,114,115,116,32,98,114,97,110,99,104,32,105,115,32,97,98,97,110,100,111,110,101,100,32,98,101,102,111,114,101,32,116,104,101,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,101,102,102,101,99,116,115,32,111,102,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,115,32,111,99,99,117,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,84,104,101,114,101,32,119,111,117,108,100,32,98,101,32,115,111,109,101,32,119,101,105,114,100,32,98,101,104,97,118,105,111,114,32,111,116,104,101,114,119,105,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,116,104,101,114,32,80,67,82,69,45,115,112,101,99,105,102,105,99,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,119,104,101,110,32,116,104,101,32,99,111,109,112,105,108,105,110,103,32,111,114,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,46,32,83,111,109,101,116,105,109,101,115,32,116,104,101,32,112,97,116,116,101,114,110,32,99,97,110,32,99,111,110,116,97,105,110,32,115,112,101,99,105,97,108,32,108,101,97,100,105,110,103,32,115,101,113,117,101,110,99,101,115,44,32,115,117,99,104,32,97,115,32,40,42,67,82,76,70,41,44,32,116,111,32,111,118,101,114,114,105,100,101,32,119,104,97,116,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,104,97,115,32,115,101,116,32,111,114,32,119,104,97,116,32,104,97,115,32,98,101,101,110,32,100,101,102,97,117,108,116,101,100,46,32,68,101,116,97,105,108,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]},<<32,101,97,114,108,105,101,114,46>>]},{p,[],[<<84,104,101,32,40,42,85,84,70,56,41,32,97,110,100,32,40,42,85,67,80,41,32,108,101,97,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,101,116,32,85,84,70,32,97,110,100,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,109,111,100,101,115,46,32,84,104,101,121,32,97,114,101,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,115,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,97,110,100,32>>,{code,[],[<<117,99,112>>]},<<44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,84,104,101,32,40,42,85,84,70,41,32,115,101,113,117,101,110,99,101,32,105,115,32,97,32,103,101,110,101,114,105,99,32,118,101,114,115,105,111,110,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,110,121,32,111,102,32,116,104,101,32,108,105,98,114,97,114,105,101,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,99,97,110,32,115,101,116,32,111,112,116,105,111,110,32>>,{code,[],[<<110,101,118,101,114,95,117,116,102>>]},<<44,32,119,104,105,99,104,32,108,111,99,107,115,32,111,117,116,32,116,104,101,32,117,115,101,32,111,102,32,116,104,101,32,40,42,85,84,70,41,32,115,101,113,117,101,110,99,101,115,46>>]}]},{a,[{id,<<115,101,99,116,49,49>>}],[]},{h2,[],[<<83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,100,101,108,105,109,105,116,101,100,32,98,121,32,112,97,114,101,110,116,104,101,115,101,115,32,40,114,111,117,110,100,32,98,114,97,99,107,101,116,115,41,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,110,101,115,116,101,100,46,32,84,117,114,110,105,110,103,32,112,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,105,110,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,100,111,101,115,32,116,119,111,32,116,104,105,110,103,115,58>>]},{dl,[],[{dt,[],[<<49,46>>]},{dd,[],[{p,[],[<<73,116,32,108,111,99,97,108,105,122,101,115,32,97,32,115,101,116,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,99,97,116,97,114,97,99,116,34,44,32,34,99,97,116,101,114,112,105,108,108,97,114,34,44,32,111,114,32,34,99,97,116,34,58>>]},{pre,[],[{code,[],[<<99,97,116,40,97,114,97,99,116,124,101,114,112,105,108,108,97,114,124,41>>]}]},{p,[],[<<87,105,116,104,111,117,116,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,44,32,105,116,32,119,111,117,108,100,32,109,97,116,99,104,32,34,99,97,116,97,114,97,99,116,34,44,32,34,101,114,112,105,108,108,97,114,34,44,32,111,114,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,46>>]}]},{dt,[],[<<50,46>>]},{dd,[],[{p,[],[<<73,116,32,115,101,116,115,32,117,112,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,46,32,84,104,97,116,32,105,115,44,32,119,104,101,110,32,116,104,101,32,99,111,109,112,108,101,116,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,116,104,97,116,32,112,111,114,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,116,104,97,116,32,109,97,116,99,104,101,100,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,116,104,114,111,117,103,104,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46>>]}]}]},{p,[],[<<79,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,99,111,117,110,116,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,32,40,115,116,97,114,116,105,110,103,32,102,114,111,109,32,49,41,32,116,111,32,111,98,116,97,105,110,32,110,117,109,98,101,114,115,32,102,111,114,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,116,114,105,110,103,32,34,116,104,101,32,114,101,100,32,107,105,110,103,34,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,34,114,101,100,32,107,105,110,103,34,44,32,34,114,101,100,34,44,32,97,110,100,32,34,107,105,110,103,34,44,32,97,110,100,32,97,114,101,32,110,117,109,98,101,114,101,100,32,49,44,32,50,44,32,97,110,100,32,51,44,32,114,101,115,112,101,99,116,105,118,101,108,121,58>>]},{pre,[],[{code,[],[<<116,104,101,32,40,40,114,101,100,124,119,104,105,116,101,41,32,40,107,105,110,103,124,113,117,101,101,110,41,41>>]}]},{p,[],[<<73,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,104,101,108,112,102,117,108,32,116,104,97,116,32,112,108,97,105,110,32,112,97,114,101,110,116,104,101,115,101,115,32,102,117,108,102,105,108,108,32,116,119,111,32,102,117,110,99,116,105,111,110,115,46,32,79,102,116,101,110,32,97,32,103,114,111,117,112,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,113,117,105,114,101,100,32,119,105,116,104,111,117,116,32,97,32,99,97,112,116,117,114,105,110,103,32,114,101,113,117,105,114,101,109,101,110,116,46,32,73,102,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,32,97,110,100,32,97,32,99,111,108,111,110,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,100,111,32,97,110,121,32,99,97,112,116,117,114,105,110,103,44,32,97,110,100,32,105,115,32,110,111,116,32,99,111,117,110,116,101,100,32,119,104,101,110,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,110,121,32,115,117,98,115,101,113,117,101,110,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,116,114,105,110,103,32,34,116,104,101,32,119,104,105,116,101,32,113,117,101,101,110,34,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,34,119,104,105,116,101,32,113,117,101,101,110,34,32,97,110,100,32,34,113,117,101,101,110,34,44,32,97,110,100,32,97,114,101,32,110,117,109,98,101,114,101,100,32,49,32,97,110,100,32,50,58>>]},{pre,[],[{code,[],[<<116,104,101,32,40,40,63,58,114,101,100,124,119,104,105,116,101,41,32,40,107,105,110,103,124,113,117,101,101,110,41,41>>]}]},{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,115,32,54,53,53,51,53,46>>]},{p,[],[<<65,115,32,97,32,99,111,110,118,101,110,105,101,110,116,32,115,104,111,114,116,104,97,110,100,44,32,105,102,32,97,110,121,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,115,32,97,114,101,32,114,101,113,117,105,114,101,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,110,111,110,45,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,101,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,99,97,110,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,34,63,34,32,97,110,100,32,34,58,34,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,116,119,111,32,112,97,116,116,101,114,110,115,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<40,63,105,58,115,97,116,117,114,100,97,121,124,115,117,110,100,97,121,41,10,40,63,58,40,63,105,41,115,97,116,117,114,100,97,121,124,115,117,110,100,97,121,41>>]}]},{p,[],[<<65,115,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104,101,115,32,97,114,101,32,116,114,105,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,97,110,100,32,111,112,116,105,111,110,115,32,97,114,101,32,110,111,116,32,114,101,115,101,116,32,117,110,116,105,108,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,97,99,104,101,100,44,32,97,110,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,32,105,110,32,111,110,101,32,98,114,97,110,99,104,32,100,111,101,115,32,97,102,102,101,99,116,32,115,117,98,115,101,113,117,101,110,116,32,98,114,97,110,99,104,101,115,44,32,115,111,32,116,104,101,32,97,98,111,118,101,32,112,97,116,116,101,114,110,115,32,109,97,116,99,104,32,98,111,116,104,32,34,83,85,78,68,65,89,34,32,97,110,100,32,34,83,97,116,117,114,100,97,121,34,46>>]},{a,[{id,<<115,101,99,116,49,50>>}],[]},{h2,[],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},{p,[],[<<80,101,114,108,32,53,46,49,48,32,105,110,116,114,111,100,117,99,101,100,32,97,32,102,101,97,116,117,114,101,32,119,104,101,114,101,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,117,115,101,115,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,115,32,102,111,114,32,105,116,115,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,46,32,83,117,99,104,32,97,32,115,117,98,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32>>,{code,[],[<<40,63,124>>]},<<32,97,110,100,32,105,115,32,105,116,115,101,108,102,32,97,32,110,111,110,45,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,124,40,83,97,116,41,117,114,124,40,83,117,110,41,41,100,97,121>>]}]},{p,[],[<<65,115,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,115,105,100,101,32,97,32>>,{code,[],[<<40,63,124>>]},<<32,103,114,111,117,112,44,32,98,111,116,104,32,115,101,116,115,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,117,109,98,101,114,101,100,32,111,110,101,46,32,84,104,117,115,44,32,119,104,101,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,121,111,117,32,99,97,110,32,108,111,111,107,32,97,116,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,110,117,109,98,101,114,32,111,110,101,44,32,119,104,105,99,104,101,118,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,109,97,116,99,104,101,100,46,32,84,104,105,115,32,99,111,110,115,116,114,117,99,116,32,105,115,32,117,115,101,102,117,108,32,119,104,101,110,32,121,111,117,32,119,97,110,116,32,116,111,32,99,97,112,116,117,114,101,32,97,32,112,97,114,116,44,32,98,117,116,32,110,111,116,32,97,108,108,44,32,111,102,32,111,110,101,32,111,102,32,109,97,110,121,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,73,110,115,105,100,101,32,97,32>>,{code,[],[<<40,63,124>>]},<<32,103,114,111,117,112,44,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,117,109,98,101,114,101,100,32,97,115,32,117,115,117,97,108,44,32,98,117,116,32,116,104,101,32,110,117,109,98,101,114,32,105,115,32,114,101,115,101,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,98,114,97,110,99,104,46,32,84,104,101,32,110,117,109,98,101,114,115,32,111,102,32,97,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,102,111,108,108,111,119,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,115,116,97,114,116,32,97,102,116,101,114,32,116,104,101,32,104,105,103,104,101,115,116,32,110,117,109,98,101,114,32,117,115,101,100,32,105,110,32,97,110,121,32,98,114,97,110,99,104,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,105,115,32,102,114,111,109,32,116,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,59,32,116,104,101,32,110,117,109,98,101,114,115,32,117,110,100,101,114,110,101,97,116,104,32,115,104,111,119,32,105,110,32,119,104,105,99,104,32,98,117,102,102,101,114,32,116,104,101,32,99,97,112,116,117,114,101,100,32,99,111,110,116,101,110,116,32,105,115,32,115,116,111,114,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<35,32,98,101,102,111,114,101,32,32,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,98,114,97,110,99,104,45,114,101,115,101,116,45,45,45,45,45,45,45,45,45,45,45,32,97,102,116,101,114,10,47,32,40,32,97,32,41,32,32,40,63,124,32,120,32,40,32,121,32,41,32,122,32,124,32,40,112,32,40,113,41,32,114,41,32,124,32,40,116,41,32,117,32,40,118,41,32,41,32,40,32,122,32,41,32,47,120,10,35,32,49,32,32,32,32,32,32,32,32,32,32,32,32,50,32,32,32,32,32,32,32,32,32,50,32,32,51,32,32,32,32,32,32,32,32,50,32,32,32,32,32,51,32,32,32,32,32,52>>]}]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,117,115,101,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,118,97,108,117,101,32,116,104,97,116,32,105,115,32,115,101,116,32,102,111,114,32,116,104,97,116,32,110,117,109,98,101,114,32,98,121,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,111,114,32,34,100,101,102,100,101,102,34,58>>]},{pre,[],[{code,[],[<<47,40,63,124,40,97,98,99,41,124,40,100,101,102,41,41,92,49,47>>]}]},{p,[],[<<73,110,32,99,111,110,116,114,97,115,116,44,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,116,111,32,97,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,102,105,114,115,116,32,111,110,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,103,105,118,101,110,32,110,117,109,98,101,114,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,111,114,32,34,100,101,102,97,98,99,34,58>>]},{pre,[],[{code,[],[<<47,40,63,124,40,97,98,99,41,124,40,100,101,102,41,41,40,63,49,41,47>>]}]},{p,[],[<<73,102,32,97,32,99,111,110,100,105,116,105,111,110,32,116,101,115,116,32,102,111,114,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,118,105,110,103,32,109,97,116,99,104,101,100,32,114,101,102,101,114,115,32,116,111,32,97,32,110,111,110,45,117,110,105,113,117,101,32,110,117,109,98,101,114,44,32,116,104,101,32,116,101,115,116,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,97,116,32,110,117,109,98,101,114,32,104,97,118,101,32,109,97,116,99,104,101,100,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,97,112,112,114,111,97,99,104,32,117,115,105,110,103,32,116,104,105,115,32,34,98,114,97,110,99,104,32,114,101,115,101,116,34,32,102,101,97,116,117,114,101,32,105,115,32,116,111,32,117,115,101,32,100,117,112,108,105,99,97,116,101,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46>>]},{a,[{id,<<115,101,99,116,49,51>>}],[]},{h2,[],[<<78,97,109,101,100,32,83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<73,100,101,110,116,105,102,121,105,110,103,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,98,121,32,110,117,109,98,101,114,32,105,115,32,115,105,109,112,108,101,44,32,98,117,116,32,105,116,32,99,97,110,32,98,101,32,104,97,114,100,32,116,111,32,107,101,101,112,32,116,114,97,99,107,32,111,102,32,116,104,101,32,110,117,109,98,101,114,115,32,105,110,32,99,111,109,112,108,105,99,97,116,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,46,32,65,108,115,111,44,32,105,102,32,97,110,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,109,111,100,105,102,105,101,100,44,32,116,104,101,32,110,117,109,98,101,114,115,32,99,97,110,32,99,104,97,110,103,101,46,32,84,111,32,104,101,108,112,32,119,105,116,104,32,116,104,105,115,32,100,105,102,102,105,99,117,108,116,121,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,116,104,101,32,110,97,109,105,110,103,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,105,115,32,102,101,97,116,117,114,101,32,119,97,115,32,110,111,116,32,97,100,100,101,100,32,116,111,32,80,101,114,108,32,117,110,116,105,108,32,114,101,108,101,97,115,101,32,53,46,49,48,46,32,80,121,116,104,111,110,32,104,97,100,32,116,104,101,32,102,101,97,116,117,114,101,32,101,97,114,108,105,101,114,44,32,97,110,100,32,80,67,82,69,32,105,110,116,114,111,100,117,99,101,100,32,105,116,32,97,116,32,114,101,108,101,97,115,101,32,52,46,48,44,32,117,115,105,110,103,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,46,32,80,67,82,69,32,110,111,119,32,115,117,112,112,111,114,116,115,32,98,111,116,104,32,116,104,101,32,80,101,114,108,32,97,110,100,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,46,32,80,101,114,108,32,97,108,108,111,119,115,32,105,100,101,110,116,105,99,97,108,108,121,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,44,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,46>>]},{p,[],[<<73,110,32,80,67,82,69,44,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,98,101,32,110,97,109,101,100,32,105,110,32,111,110,101,32,111,102,32,116,104,114,101,101,32,119,97,121,115,58,32>>,{code,[],[<<40,63,60,110,97,109,101,62,46,46,46,41>>]},<<32,111,114,32>>,{code,[],[<<40,63,39,110,97,109,101,39,46,46,46,41>>]},<<32,97,115,32,105,110,32,80,101,114,108,44,32,111,114,32>>,{code,[],[<<40,63,80,60,110,97,109,101,62,46,46,46,41>>]},<<32,97,115,32,105,110,32,80,121,116,104,111,110,46,32,82,101,102,101,114,101,110,99,101,115,32,116,111,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,102,114,111,109,32,111,116,104,101,114,32,112,97,114,116,115,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,115,117,99,104,32,97,115,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,44,32,114,101,99,117,114,115,105,111,110,44,32,97,110,100,32,99,111,110,100,105,116,105,111,110,115,44,32,99,97,110,32,98,101,32,109,97,100,101,32,98,121,32,110,97,109,101,32,97,110,100,32,98,121,32,110,117,109,98,101,114,46>>]},{p,[],[<<78,97,109,101,115,32,99,111,110,115,105,115,116,32,111,102,32,117,112,32,116,111,32,51,50,32,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,117,110,100,101,114,115,99,111,114,101,115,44,32,98,117,116,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,97,32,110,111,110,45,100,105,103,105,116,46,32,78,97,109,101,100,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,115,116,105,108,108,32,97,108,108,111,99,97,116,101,100,32,110,117,109,98,101,114,115,32,97,115,32,119,101,108,108,32,97,115,32,110,97,109,101,115,44,32,101,120,97,99,116,108,121,32,97,115,32,105,102,32,116,104,101,32,110,97,109,101,115,32,119,101,114,101,32,110,111,116,32,112,114,101,115,101,110,116,46,32,84,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,99,97,110,32,117,115,101,32,110,97,109,101,100,32,118,97,108,117,101,115,32,105,102,32,116,104,101,121,32,97,114,101,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,32,110,97,109,101,32,109,117,115,116,32,98,101,32,117,110,105,113,117,101,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,44,32,98,117,116,32,116,104,105,115,32,99,111,110,115,116,114,97,105,110,116,32,99,97,110,32,98,101,32,114,101,108,97,120,101,100,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,40,68,117,112,108,105,99,97,116,101,32,110,97,109,101,115,32,97,114,101,32,97,108,115,111,32,97,108,119,97,121,115,32,112,101,114,109,105,116,116,101,100,32,102,111,114,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,115,101,116,32,117,112,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,46,41,32,68,117,112,108,105,99,97,116,101,32,110,97,109,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,102,111,114,32,112,97,116,116,101,114,110,115,32,119,104,101,114,101,32,111,110,108,121,32,111,110,101,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,109,97,116,99,104,46,32,83,117,112,112,111,115,101,32,116,104,97,116,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,119,101,101,107,100,97,121,44,32,101,105,116,104,101,114,32,97,115,32,97,32,51,45,108,101,116,116,101,114,32,97,98,98,114,101,118,105,97,116,105,111,110,32,111,114,32,97,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,44,32,97,110,100,32,105,110,32,98,111,116,104,32,99,97,115,101,115,32,121,111,117,32,119,97,110,116,32,116,111,32,101,120,116,114,97,99,116,32,116,104,101,32,97,98,98,114,101,118,105,97,116,105,111,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,40,105,103,110,111,114,105,110,103,32,116,104,101,32,108,105,110,101,32,98,114,101,97,107,115,41,32,100,111,101,115,32,116,104,101,32,106,111,98,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,60,68,78,62,77,111,110,124,70,114,105,124,83,117,110,41,40,63,58,100,97,121,41,63,124,10,40,63,60,68,78,62,84,117,101,41,40,63,58,115,100,97,121,41,63,124,10,40,63,60,68,78,62,87,101,100,41,40,63,58,110,101,115,100,97,121,41,63,124,10,40,63,60,68,78,62,84,104,117,41,40,63,58,114,115,100,97,121,41,63,124,10,40,63,60,68,78,62,83,97,116,41,40,63,58,117,114,100,97,121,41,63>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,102,105,118,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,115,116,114,105,110,103,115,44,32,98,117,116,32,111,110,108,121,32,111,110,101,32,105,115,32,101,118,101,114,32,115,101,116,32,97,102,116,101,114,32,97,32,109,97,116,99,104,46,32,40,65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,119,97,121,32,111,102,32,115,111,108,118,105,110,103,32,116,104,105,115,32,112,114,111,98,108,101,109,32,105,115,32,116,111,32,117,115,101,32,97,32,34,98,114,97,110,99,104,32,114,101,115,101,116,34,32,115,117,98,112,97,116,116,101,114,110,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,46,41>>]},{p,[],[<<70,111,114,32,99,97,112,116,117,114,105,110,103,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,119,104,105,99,104,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,117,110,105,113,117,101,44,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,111,99,99,117,114,114,101,110,99,101,32,40,99,111,117,110,116,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,41,32,105,115,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,105,102,32,116,104,101,32,110,97,109,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<118,97,108,117,101,115>>]},<<32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,116,97,116,101,109,101,110,116,46,32,84,104,101,32>>,{code,[],[<<97,108,108,95,110,97,109,101,115>>]},<<32,99,97,112,116,117,114,105,110,103,32,118,97,108,117,101,32,109,97,116,99,104,101,115,32,97,108,108,32,116,104,101,32,110,97,109,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<89,111,117,32,99,97,110,110,111,116,32,117,115,101,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,98,101,116,119,101,101,110,32,116,119,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,97,115,32,80,67,82,69,32,117,115,101,115,32,111,110,108,121,32,116,104,101,32,110,117,109,98,101,114,115,32,119,104,101,110,32,109,97,116,99,104,105,110,103,46,32,70,111,114,32,116,104,105,115,32,114,101,97,115,111,110,44,32,97,110,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,105,102,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,46,32,72,111,119,101,118,101,114,44,32,121,111,117,32,99,97,110,32,115,112,101,99,105,102,121,32,116,104,101,32,115,97,109,101,32,110,97,109,101,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,101,118,101,110,32,119,104,101,110,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<32,105,115,32,110,111,116,32,115,101,116,46>>]}]},{a,[{id,<<115,101,99,116,49,52>>}],[]},{h2,[],[<<82,101,112,101,116,105,116,105,111,110>>]},{p,[],[<<82,101,112,101,116,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,113,117,97,110,116,105,102,105,101,114,115,44,32,119,104,105,99,104,32,99,97,110,32,102,111,108,108,111,119,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,116,101,109,115,58>>]},{ul,[],[{li,[],[<<65,32,108,105,116,101,114,97,108,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<84,104,101,32,100,111,116,32,109,101,116,97,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<84,104,101,32,92,67,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<84,104,101,32,92,88,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<84,104,101,32,92,82,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<65,110,32,101,115,99,97,112,101,32,115,117,99,104,32,97,115,32,92,100,32,111,114,32,92,112,76,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115>>]},{li,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,40,115,101,101,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41>>]},{li,[],[<<65,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,32,40,105,110,99,108,117,100,105,110,103,32,97,115,115,101,114,116,105,111,110,115,41>>]},{li,[],[<<65,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,114,101,99,117,114,115,105,118,101,32,111,114,32,111,116,104,101,114,119,105,115,101,41>>]}]},{p,[],[<<84,104,101,32,103,101,110,101,114,97,108,32,114,101,112,101,116,105,116,105,111,110,32,113,117,97,110,116,105,102,105,101,114,32,115,112,101,99,105,102,105,101,115,32,97,32,109,105,110,105,109,117,109,32,97,110,100,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,101,114,109,105,116,116,101,100,32,109,97,116,99,104,101,115,44,32,98,121,32,103,105,118,105,110,103,32,116,104,101,32,116,119,111,32,110,117,109,98,101,114,115,32,105,110,32,99,117,114,108,121,32,98,114,97,99,107,101,116,115,32,40,98,114,97,99,101,115,41,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,97,32,99,111,109,109,97,46,32,84,104,101,32,110,117,109,98,101,114,115,32,109,117,115,116,32,98,101,32,60,32,54,53,53,51,54,44,32,97,110,100,32,116,104,101,32,102,105,114,115,116,32,109,117,115,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,115,101,99,111,110,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,122,122,34,44,32,34,122,122,122,34,44,32,111,114,32,34,122,122,122,122,34,58>>]},{pre,[],[{code,[],[<<122,123,50,44,52,125>>]}]},{p,[],[<<65,32,99,108,111,115,105,110,103,32,98,114,97,99,101,32,111,110,32,105,116,115,32,111,119,110,32,105,115,32,110,111,116,32,97,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,46,32,73,102,32,116,104,101,32,115,101,99,111,110,100,32,110,117,109,98,101,114,32,105,115,32,111,109,105,116,116,101,100,44,32,98,117,116,32,116,104,101,32,99,111,109,109,97,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,114,101,32,105,115,32,110,111,32,117,112,112,101,114,32,108,105,109,105,116,46,32,73,102,32,116,104,101,32,115,101,99,111,110,100,32,110,117,109,98,101,114,32,97,110,100,32,116,104,101,32,99,111,109,109,97,32,97,114,101,32,98,111,116,104,32,111,109,105,116,116,101,100,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,115,112,101,99,105,102,105,101,115,32,97,110,32,101,120,97,99,116,32,110,117,109,98,101,114,32,111,102,32,114,101,113,117,105,114,101,100,32,109,97,116,99,104,101,115,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,116,32,108,101,97,115,116,32,116,104,114,101,101,32,115,117,99,99,101,115,115,105,118,101,32,118,111,119,101,108,115,44,32,98,117,116,32,99,97,110,32,109,97,116,99,104,32,109,97,110,121,32,109,111,114,101,58>>]},{pre,[],[{code,[],[<<91,97,101,105,111,117,93,123,51,44,125>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,101,120,97,99,116,108,121,32,101,105,103,104,116,32,100,105,103,105,116,115,58>>]},{pre,[],[{code,[],[<<92,100,123,56,125>>]}]},{p,[],[<<65,110,32,111,112,101,110,105,110,103,32,99,117,114,108,121,32,98,114,97,99,107,101,116,32,116,104,97,116,32,97,112,112,101,97,114,115,32,105,110,32,97,32,112,111,115,105,116,105,111,110,32,119,104,101,114,101,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,44,32,111,114,32,111,110,101,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,115,121,110,116,97,120,32,111,102,32,97,32,113,117,97,110,116,105,102,105,101,114,44,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,123,44,54,125,32,105,115,32,110,111,116,32,97,32,113,117,97,110,116,105,102,105,101,114,44,32,98,117,116,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,111,102,32,102,111,117,114,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<73,110,32,85,110,105,99,111,100,101,32,109,111,100,101,44,32,113,117,97,110,116,105,102,105,101,114,115,32,97,112,112,108,121,32,116,111,32,99,104,97,114,97,99,116,101,114,115,32,114,97,116,104,101,114,32,116,104,97,110,32,116,111,32,105,110,100,105,118,105,100,117,97,108,32,100,97,116,97,32,117,110,105,116,115,46,32,84,104,117,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,92,120,123,49,48,48,125,123,50,125,32,109,97,116,99,104,101,115,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,44,32,101,97,99,104,32,111,102,32,119,104,105,99,104,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,50,45,98,121,116,101,32,115,101,113,117,101,110,99,101,32,105,110,32,97,32,85,84,70,45,56,32,115,116,114,105,110,103,46,32,83,105,109,105,108,97,114,108,121,44,32,92,88,123,51,125,32,109,97,116,99,104,101,115,32,116,104,114,101,101,32,85,110,105,99,111,100,101,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,115,44,32,101,97,99,104,32,111,102,32,119,104,105,99,104,32,99,97,110,32,98,101,32,109,97,110,121,32,100,97,116,97,32,117,110,105,116,115,32,108,111,110,103,32,40,97,110,100,32,116,104,101,121,32,99,97,110,32,98,101,32,111,102,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,115,41,46>>]},{p,[],[<<84,104,101,32,113,117,97,110,116,105,102,105,101,114,32,123,48,125,32,105,115,32,112,101,114,109,105,116,116,101,100,44,32,99,97,117,115,105,110,103,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,116,111,32,98,101,104,97,118,101,32,97,115,32,105,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,105,116,101,109,32,97,110,100,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,119,101,114,101,32,110,111,116,32,112,114,101,115,101,110,116,46,32,84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,102,111,114,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,32,97,115,32,115,117,98,114,111,117,116,105,110,101,115,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,40,98,117,116,32,115,101,101,32,97,108,115,111,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,100,101,102,105,110,105,110,103,95,115,117,98,112,97,116,116,101,114,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,101,102,105,110,105,110,103,32,83,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,85,115,101,32,98,121,32,82,101,102,101,114,101,110,99,101,32,79,110,108,121>>]},<<41,46,32,73,116,101,109,115,32,111,116,104,101,114,32,116,104,97,110,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,104,97,118,101,32,97,32,123,48,125,32,113,117,97,110,116,105,102,105,101,114,32,97,114,101,32,111,109,105,116,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<70,111,114,32,99,111,110,118,101,110,105,101,110,99,101,44,32,116,104,101,32,116,104,114,101,101,32,109,111,115,116,32,99,111,109,109,111,110,32,113,117,97,110,116,105,102,105,101,114,115,32,104,97,118,101,32,115,105,110,103,108,101,45,99,104,97,114,97,99,116,101,114,32,97,98,98,114,101,118,105,97,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[<<42>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,48,44,125>>]},{dt,[],[<<43>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,49,44,125>>]},{dt,[],[<<63>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,48,44,49,125>>]}]},{p,[],[<<73,110,102,105,110,105,116,101,32,108,111,111,112,115,32,99,97,110,32,98,101,32,99,111,110,115,116,114,117,99,116,101,100,32,98,121,32,102,111,108,108,111,119,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,99,97,110,32,109,97,116,99,104,32,110,111,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,97,32,113,117,97,110,116,105,102,105,101,114,32,116,104,97,116,32,104,97,115,32,110,111,32,117,112,112,101,114,32,108,105,109,105,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,63,41,42>>]}]},{p,[],[<<69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,111,102,32,80,101,114,108,32,97,110,100,32,80,67,82,69,32,117,115,101,100,32,116,111,32,103,105,118,101,32,97,110,32,101,114,114,111,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,102,111,114,32,115,117,99,104,32,112,97,116,116,101,114,110,115,46,32,72,111,119,101,118,101,114,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,99,97,115,101,115,32,119,104,101,114,101,32,116,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,44,32,115,117,99,104,32,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,119,32,97,99,99,101,112,116,101,100,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,110,121,32,114,101,112,101,116,105,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,110,111,32,99,104,97,114,97,99,116,101,114,115,44,32,116,104,101,32,108,111,111,112,32,105,115,32,102,111,114,99,105,98,108,121,32,98,114,111,107,101,110,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,34,103,114,101,101,100,121,34,44,32,116,104,97,116,32,105,115,44,32,116,104,101,121,32,109,97,116,99,104,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,32,40,117,112,32,116,111,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,101,114,109,105,116,116,101,100,32,116,105,109,101,115,41,44,32,119,105,116,104,111,117,116,32,99,97,117,115,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,116,111,32,102,97,105,108,46,32,84,104,101,32,99,108,97,115,115,105,99,32,101,120,97,109,112,108,101,32,111,102,32,119,104,101,114,101,32,116,104,105,115,32,103,105,118,101,115,32,112,114,111,98,108,101,109,115,32,105,115,32,105,110,32,116,114,121,105,110,103,32,116,111,32,109,97,116,99,104,32,99,111,109,109,101,110,116,115,32,105,110,32,67,32,112,114,111,103,114,97,109,115,46,32,84,104,101,115,101,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,47,42,32,97,110,100,32,42,47,46,32,87,105,116,104,105,110,32,116,104,101,32,99,111,109,109,101,110,116,44,32,105,110,100,105,118,105,100,117,97,108,32,42,32,97,110,100,32,47,32,99,104,97,114,97,99,116,101,114,115,32,99,97,110,32,97,112,112,101,97,114,46,32,65,110,32,97,116,116,101,109,112,116,32,116,111,32,109,97,116,99,104,32,67,32,99,111,109,109,101,110,116,115,32,98,121,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<47,92,42,46,42,92,42,47>>]}]},{p,[],[<<116,111,32,116,104,101,32,115,116,114,105,110,103>>]},{pre,[],[{code,[],[<<47,42,32,102,105,114,115,116,32,99,111,109,109,101,110,116,32,42,47,32,32,110,111,116,32,99,111,109,109,101,110,116,32,32,47,42,32,115,101,99,111,110,100,32,99,111,109,109,101,110,116,32,42,47>>]}]},{p,[],[<<102,97,105,108,115,44,32,97,115,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,32,111,119,105,110,103,32,116,111,32,116,104,101,32,103,114,101,101,100,105,110,101,115,115,32,111,102,32,116,104,101,32,46,42,32,105,116,101,109,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,102,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,44,32,105,116,32,99,101,97,115,101,115,32,116,111,32,98,101,32,103,114,101,101,100,121,44,32,97,110,100,32,105,110,115,116,101,97,100,32,109,97,116,99,104,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,112,111,115,115,105,98,108,101,44,32,115,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,100,111,101,115,32,116,104,101,32,114,105,103,104,116,32,116,104,105,110,103,32,119,105,116,104,32,116,104,101,32,67,32,99,111,109,109,101,110,116,115,58>>]},{pre,[],[{code,[],[<<47,92,42,46,42,63,92,42,47>>]}]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,118,97,114,105,111,117,115,32,113,117,97,110,116,105,102,105,101,114,115,32,105,115,32,110,111,116,32,111,116,104,101,114,119,105,115,101,32,99,104,97,110,103,101,100,44,32,111,110,108,121,32,116,104,101,32,112,114,101,102,101,114,114,101,100,32,110,117,109,98,101,114,32,111,102,32,109,97,116,99,104,101,115,46,32,68,111,32,110,111,116,32,99,111,110,102,117,115,101,32,116,104,105,115,32,117,115,101,32,111,102,32,113,117,101,115,116,105,111,110,32,109,97,114,107,32,119,105,116,104,32,105,116,115,32,117,115,101,32,97,115,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,110,32,105,116,115,32,111,119,110,32,114,105,103,104,116,46,32,65,115,32,105,116,32,104,97,115,32,116,119,111,32,117,115,101,115,44,32,105,116,32,99,97,110,32,115,111,109,101,116,105,109,101,115,32,97,112,112,101,97,114,32,100,111,117,98,108,101,100,44,32,97,115,32,105,110>>]},{pre,[],[{code,[],[<<92,100,63,63,92,100>>]}]},{p,[],[<<119,104,105,99,104,32,109,97,116,99,104,101,115,32,111,110,101,32,100,105,103,105,116,32,98,121,32,112,114,101,102,101,114,101,110,99,101,44,32,98,117,116,32,99,97,110,32,109,97,116,99,104,32,116,119,111,32,105,102,32,116,104,97,116,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<32,105,115,32,115,101,116,32,40,97,110,32,111,112,116,105,111,110,32,116,104,97,116,32,105,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,32,105,110,32,80,101,114,108,41,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,110,111,116,32,103,114,101,101,100,121,32,98,121,32,100,101,102,97,117,108,116,44,32,98,117,116,32,105,110,100,105,118,105,100,117,97,108,32,111,110,101,115,32,99,97,110,32,98,101,32,109,97,100,101,32,103,114,101,101,100,121,32,98,121,32,102,111,108,108,111,119,105,110,103,32,116,104,101,109,32,119,105,116,104,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,46,32,84,104,97,116,32,105,115,44,32,105,116,32,105,110,118,101,114,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<87,104,101,110,32,97,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,113,117,97,110,116,105,102,105,101,100,32,119,105,116,104,32,97,32,109,105,110,105,109,117,109,32,114,101,112,101,97,116,32,99,111,117,110,116,32,116,104,97,116,32,105,115,32,62,32,49,32,111,114,32,119,105,116,104,32,97,32,108,105,109,105,116,101,100,32,109,97,120,105,109,117,109,44,32,109,111,114,101,32,109,101,109,111,114,121,32,105,115,32,114,101,113,117,105,114,101,100,32,102,111,114,32,116,104,101,32,99,111,109,112,105,108,101,100,32,112,97,116,116,101,114,110,44,32,105,110,32,112,114,111,112,111,114,116,105,111,110,32,116,111,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,105,110,105,109,117,109,32,111,114,32,109,97,120,105,109,117,109,46>>]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32,46,42,32,111,114,32,46,123,48,44,125,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,40,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,115>>]},<<41,32,105,115,32,115,101,116,44,32,116,104,117,115,32,97,108,108,111,119,105,110,103,32,116,104,101,32,100,111,116,32,116,111,32,109,97,116,99,104,32,110,101,119,108,105,110,101,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,105,109,112,108,105,99,105,116,108,121,32,97,110,99,104,111,114,101,100,44,32,98,101,99,97,117,115,101,32,119,104,97,116,101,118,101,114,32,102,111,108,108,111,119,115,32,105,115,32,116,114,105,101,100,32,97,103,97,105,110,115,116,32,101,118,101,114,121,32,99,104,97,114,97,99,116,101,114,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,83,111,44,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,114,101,116,114,121,105,110,103,32,116,104,101,32,111,118,101,114,97,108,108,32,109,97,116,99,104,32,97,116,32,97,110,121,32,112,111,115,105,116,105,111,110,32,97,102,116,101,114,32,116,104,101,32,102,105,114,115,116,46,32,80,67,82,69,32,110,111,114,109,97,108,108,121,32,116,114,101,97,116,115,32,115,117,99,104,32,97,32,112,97,116,116,101,114,110,32,97,115,32,105,102,32,105,116,32,119,97,115,32,112,114,101,99,101,100,101,100,32,98,121,32,92,65,46>>]},{p,[],[<<73,110,32,99,97,115,101,115,32,119,104,101,114,101,32,105,116,32,105,115,32,107,110,111,119,110,32,116,104,97,116,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,115,32,110,111,32,110,101,119,108,105,110,101,115,44,32,105,116,32,105,115,32,119,111,114,116,104,32,115,101,116,116,105,110,103,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,116,111,32,111,98,116,97,105,110,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,44,32,111,114,32,97,108,116,101,114,110,97,116,105,118,101,108,121,32,117,115,105,110,103,32,94,32,116,111,32,105,110,100,105,99,97,116,101,32,97,110,99,104,111,114,105,110,103,32,101,120,112,108,105,99,105,116,108,121,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,116,104,101,114,101,32,97,114,101,32,115,111,109,101,32,99,97,115,101,115,32,119,104,101,114,101,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,46,32,87,104,101,110,32,46,42,32,105,115,32,105,110,115,105,100,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,116,104,101,32,115,117,98,106,101,99,116,32,111,102,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,101,108,115,101,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,115,116,97,114,116,32,99,97,110,32,102,97,105,108,32,119,104,101,114,101,32,97,32,108,97,116,101,114,32,111,110,101,32,115,117,99,99,101,101,100,115,46,32,67,111,110,115,105,100,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,46,42,41,97,98,99,92,49>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,120,121,122,49,50,51,97,98,99,49,50,51,34,44,32,116,104,101,32,109,97,116,99,104,32,112,111,105,110,116,32,105,115,32,116,104,101,32,102,111,117,114,116,104,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,114,101,102,111,114,101,44,32,115,117,99,104,32,97,32,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,105,109,112,108,105,99,105,116,108,121,32,97,110,99,104,111,114,101,100,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,99,97,115,101,32,119,104,101,114,101,32,105,109,112,108,105,99,105,116,32,97,110,99,104,111,114,105,110,103,32,105,115,32,110,111,116,32,97,112,112,108,105,101,100,32,105,115,32,119,104,101,110,32,116,104,101,32,108,101,97,100,105,110,103,32,46,42,32,105,115,32,105,110,115,105,100,101,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,79,110,99,101,32,97,103,97,105,110,44,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,115,116,97,114,116,32,99,97,110,32,102,97,105,108,32,119,104,101,114,101,32,97,32,108,97,116,101,114,32,111,110,101,32,115,117,99,99,101,101,100,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,62,46,42,63,97,41,98>>]}]},{p,[],[<<73,116,32,109,97,116,99,104,101,115,32,34,97,98,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,34,97,97,98,34,46,32,84,104,101,32,117,115,101,32,111,102,32,116,104,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,111,110,116,114,111,108,32,118,101,114,98,115,32,40,42,80,82,85,78,69,41,32,97,110,100,32,40,42,83,75,73,80,41,32,97,108,115,111,32,100,105,115,97,98,108,101,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,46>>]},{p,[],[<<87,104,101,110,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,112,101,97,116,101,100,44,32,116,104,101,32,118,97,108,117,101,32,99,97,112,116,117,114,101,100,32,105,115,32,116,104,101,32,115,117,98,115,116,114,105,110,103,32,116,104,97,116,32,109,97,116,99,104,101,100,32,116,104,101,32,102,105,110,97,108,32,105,116,101,114,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,102,116,101,114>>]},{pre,[],[{code,[],[<<40,116,119,101,101,100,108,101,91,100,117,109,101,93,123,51,125,92,115,42,41,43>>]}]},{p,[],[<<104,97,115,32,109,97,116,99,104,101,100,32,34,116,119,101,101,100,108,101,100,117,109,32,116,119,101,101,100,108,101,100,101,101,34,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,105,115,32,34,116,119,101,101,100,108,101,100,101,101,34,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,101,115,116,101,100,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,115,32,99,97,110,32,104,97,118,101,32,98,101,101,110,32,115,101,116,32,105,110,32,112,114,101,118,105,111,117,115,32,105,116,101,114,97,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,102,116,101,114>>]},{pre,[],[{code,[],[<<47,40,97,124,40,98,41,41,43,47>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,34,97,98,97,34,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,115,101,99,111,110,100,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,105,115,32,34,98,34,46>>]},{a,[{id,<<115,101,99,116,49,53>>}],[]},{h2,[],[<<65,116,111,109,105,99,32,71,114,111,117,112,105,110,103,32,97,110,100,32,80,111,115,115,101,115,115,105,118,101,32,81,117,97,110,116,105,102,105,101,114,115>>]},{p,[],[<<87,105,116,104,32,98,111,116,104,32,109,97,120,105,109,105,122,105,110,103,32,40,34,103,114,101,101,100,121,34,41,32,97,110,100,32,109,105,110,105,109,105,122,105,110,103,32,40,34,117,110,103,114,101,101,100,121,34,32,111,114,32,34,108,97,122,121,34,41,32,114,101,112,101,116,105,116,105,111,110,44,32,102,97,105,108,117,114,101,32,111,102,32,119,104,97,116,32,102,111,108,108,111,119,115,32,110,111,114,109,97,108,108,121,32,99,97,117,115,101,115,32,116,104,101,32,114,101,112,101,97,116,101,100,32,105,116,101,109,32,116,111,32,98,101,32,114,101,45,101,118,97,108,117,97,116,101,100,32,116,111,32,115,101,101,32,105,102,32,97,32,100,105,102,102,101,114,101,110,116,32,110,117,109,98,101,114,32,111,102,32,114,101,112,101,97,116,115,32,97,108,108,111,119,115,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,116,111,32,109,97,116,99,104,46,32,83,111,109,101,116,105,109,101,115,32,105,116,32,105,115,32,117,115,101,102,117,108,32,116,111,32,112,114,101,118,101,110,116,32,116,104,105,115,44,32,101,105,116,104,101,114,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,110,97,116,117,114,101,32,111,102,32,116,104,101,32,109,97,116,99,104,44,32,111,114,32,116,111,32,99,97,117,115,101,32,105,116,32,116,111,32,102,97,105,108,32,101,97,114,108,105,101,114,32,116,104,97,110,32,105,116,32,111,116,104,101,114,119,105,115,101,32,109,105,103,104,116,44,32,119,104,101,110,32,116,104,101,32,97,117,116,104,111,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,107,110,111,119,115,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,99,97,114,114,121,105,110,103,32,111,110,46>>]},{p,[],[<<67,111,110,115,105,100,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,112,97,116,116,101,114,110,32,92,100,43,102,111,111,32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,117,98,106,101,99,116,32,108,105,110,101,58>>]},{pre,[],[{code,[],[<<49,50,51,52,53,54,98,97,114>>]}]},{p,[],[<<65,102,116,101,114,32,109,97,116,99,104,105,110,103,32,97,108,108,32,115,105,120,32,100,105,103,105,116,115,32,97,110,100,32,116,104,101,110,32,102,97,105,108,105,110,103,32,116,111,32,109,97,116,99,104,32,34,102,111,111,34,44,32,116,104,101,32,110,111,114,109,97,108,32,97,99,116,105,111,110,32,111,102,32,116,104,101,32,109,97,116,99,104,101,114,32,105,115,32,116,111,32,116,114,121,32,97,103,97,105,110,32,119,105,116,104,32,111,110,108,121,32,102,105,118,101,32,100,105,103,105,116,115,32,109,97,116,99,104,105,110,103,32,105,116,101,109,32,92,100,43,44,32,97,110,100,32,116,104,101,110,32,119,105,116,104,32,102,111,117,114,44,32,97,110,100,32,115,111,32,111,110,44,32,98,101,102,111,114,101,32,117,108,116,105,109,97,116,101,108,121,32,102,97,105,108,105,110,103,46,32,34,65,116,111,109,105,99,32,103,114,111,117,112,105,110,103,34,32,40,97,32,116,101,114,109,32,116,97,107,101,110,32,102,114,111,109,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,39,115,32,98,111,111,107,41,32,112,114,111,118,105,100,101,115,32,116,104,101,32,109,101,97,110,115,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,97,116,32,111,110,99,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,109,97,116,99,104,101,100,44,32,105,116,32,105,115,32,110,111,116,32,116,111,32,98,101,32,114,101,45,101,118,97,108,117,97,116,101,100,32,105,110,32,116,104,105,115,32,119,97,121,46>>]},{p,[],[<<73,102,32,97,116,111,109,105,99,32,103,114,111,117,112,105,110,103,32,105,115,32,117,115,101,100,32,102,111,114,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,44,32,116,104,101,32,109,97,116,99,104,101,114,32,103,105,118,101,115,32,117,112,32,105,109,109,101,100,105,97,116,101,108,121,32,111,110,32,102,97,105,108,105,110,103,32,116,111,32,109,97,116,99,104,32,34,102,111,111,34,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,46,32,84,104,101,32,110,111,116,97,116,105,111,110,32,105,115,32,97,32,107,105,110,100,32,111,102,32,115,112,101,99,105,97,108,32,112,97,114,101,110,116,104,101,115,105,115,44,32,115,116,97,114,116,105,110,103,32,119,105,116,104,32>>,{code,[],[<<40,63,62>>]},<<32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,63,62,92,100,43,41,102,111,111>>]}]},{p,[],[<<84,104,105,115,32,107,105,110,100,32,111,102,32,112,97,114,101,110,116,104,101,115,105,115,32,34,108,111,99,107,115,32,117,112,34,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,32,99,111,110,116,97,105,110,115,32,111,110,99,101,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,44,32,97,110,100,32,97,32,102,97,105,108,117,114,101,32,102,117,114,116,104,101,114,32,105,110,116,111,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,112,114,101,118,101,110,116,101,100,32,102,114,111,109,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,105,116,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,112,97,115,116,32,105,116,32,116,111,32,112,114,101,118,105,111,117,115,32,105,116,101,109,115,44,32,104,111,119,101,118,101,114,44,32,119,111,114,107,115,32,97,115,32,110,111,114,109,97,108,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,101,115,99,114,105,112,116,105,111,110,32,105,115,32,116,104,97,116,32,97,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,105,115,32,116,121,112,101,32,109,97,116,99,104,101,115,32,116,104,101,32,115,116,114,105,110,103,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,110,32,105,100,101,110,116,105,99,97,108,32,115,116,97,110,100,97,108,111,110,101,32,112,97,116,116,101,114,110,32,119,111,117,108,100,32,109,97,116,99,104,44,32,105,102,32,97,110,99,104,111,114,101,100,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]},{p,[],[<<65,116,111,109,105,99,32,103,114,111,117,112,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,83,105,109,112,108,101,32,99,97,115,101,115,32,115,117,99,104,32,97,115,32,116,104,101,32,97,98,111,118,101,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,97,32,109,97,120,105,109,105,122,105,110,103,32,114,101,112,101,97,116,32,116,104,97,116,32,109,117,115,116,32,115,119,97,108,108,111,119,32,101,118,101,114,121,116,104,105,110,103,32,105,116,32,99,97,110,46,32,83,111,44,32,119,104,105,108,101,32,98,111,116,104,32,92,100,43,32,97,110,100,32,92,100,43,63,32,97,114,101,32,112,114,101,112,97,114,101,100,32,116,111,32,97,100,106,117,115,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,103,105,116,115,32,116,104,101,121,32,109,97,116,99,104,32,116,111,32,109,97,107,101,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,44,32>>,{code,[],[<<40,63,62,92,100,43,41>>]},<<32,99,97,110,32,111,110,108,121,32,109,97,116,99,104,32,97,110,32,101,110,116,105,114,101,32,115,101,113,117,101,110,99,101,32,111,102,32,100,105,103,105,116,115,46>>]},{p,[],[<<65,116,111,109,105,99,32,103,114,111,117,112,115,32,105,110,32,103,101,110,101,114,97,108,32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,99,111,109,112,108,105,99,97,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,97,110,100,32,99,97,110,32,98,101,32,110,101,115,116,101,100,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,102,111,114,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,105,115,32,106,117,115,116,32,97,32,115,105,110,103,108,101,32,114,101,112,101,97,116,101,100,32,105,116,101,109,44,32,97,115,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,97,98,111,118,101,44,32,97,32,115,105,109,112,108,101,114,32,110,111,116,97,116,105,111,110,44,32,99,97,108,108,101,100,32,97,32,34,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,34,32,99,97,110,32,98,101,32,117,115,101,100,46,32,84,104,105,115,32,99,111,110,115,105,115,116,115,32,111,102,32,97,110,32,101,120,116,114,97,32,43,32,99,104,97,114,97,99,116,101,114,32,102,111,108,108,111,119,105,110,103,32,97,32,113,117,97,110,116,105,102,105,101,114,46,32,85,115,105,110,103,32,116,104,105,115,32,110,111,116,97,116,105,111,110,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,114,101,119,114,105,116,116,101,110,32,97,115>>]},{pre,[],[{code,[],[<<92,100,43,43,102,111,111>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,110,32,101,110,116,105,114,101,32,103,114,111,117,112,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,124,120,121,122,41,123,50,44,51,125,43>>]}]},{p,[],[<<80,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,97,108,119,97,121,115,32,103,114,101,101,100,121,59,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,121,32,97,114,101,32,97,32,99,111,110,118,101,110,105,101,110,116,32,110,111,116,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,105,109,112,108,101,114,32,102,111,114,109,115,32,111,102,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,72,111,119,101,118,101,114,44,32,116,104,101,114,101,32,105,115,32,110,111,32,100,105,102,102,101,114,101,110,99,101,32,105,110,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,116,104,101,32,101,113,117,105,118,97,108,101,110,116,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,98,117,116,32,116,104,101,114,101,32,99,97,110,32,98,101,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,100,105,102,102,101,114,101,110,99,101,59,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,112,114,111,98,97,98,108,121,32,115,108,105,103,104,116,108,121,32,102,97,115,116,101,114,46>>]},{p,[],[<<84,104,101,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,115,121,110,116,97,120,32,105,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,116,111,32,116,104,101,32,80,101,114,108,32,53,46,56,32,115,121,110,116,97,120,46,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,32,111,114,105,103,105,110,97,116,101,100,32,116,104,101,32,105,100,101,97,32,40,97,110,100,32,116,104,101,32,110,97,109,101,41,32,105,110,32,116,104,101,32,102,105,114,115,116,32,101,100,105,116,105,111,110,32,111,102,32,104,105,115,32,98,111,111,107,46,32,77,105,107,101,32,77,99,67,108,111,115,107,101,121,32,108,105,107,101,100,32,105,116,44,32,115,111,32,105,109,112,108,101,109,101,110,116,101,100,32,105,116,32,119,104,101,110,32,104,101,32,98,117,105,108,116,32,116,104,101,32,83,117,110,32,74,97,118,97,32,112,97,99,107,97,103,101,44,32,97,110,100,32,80,67,82,69,32,99,111,112,105,101,100,32,105,116,32,102,114,111,109,32,116,104,101,114,101,46,32,73,116,32,117,108,116,105,109,97,116,101,108,121,32,102,111,117,110,100,32,105,116,115,32,119,97,121,32,105,110,116,111,32,80,101,114,108,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,48,46>>]},{p,[],[<<80,67,82,69,32,104,97,115,32,97,110,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,34,112,111,115,115,101,115,115,105,102,105,101,115,34,32,99,101,114,116,97,105,110,32,115,105,109,112,108,101,32,112,97,116,116,101,114,110,32,99,111,110,115,116,114,117,99,116,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,115,101,113,117,101,110,99,101,32,65,43,66,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,65,43,43,66,44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,65,58,115,32,119,104,101,110,32,66,32,109,117,115,116,32,102,111,108,108,111,119,46>>]},{p,[],[<<87,104,101,110,32,97,32,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,115,32,97,110,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,32,105,110,115,105,100,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,99,97,110,32,105,116,115,101,108,102,32,98,101,32,114,101,112,101,97,116,101,100,32,97,110,32,117,110,108,105,109,105,116,101,100,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,44,32,116,104,101,32,117,115,101,32,111,102,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,111,32,97,118,111,105,100,32,115,111,109,101,32,102,97,105,108,105,110,103,32,109,97,116,99,104,101,115,32,116,97,107,105,110,103,32,97,32,108,111,110,103,32,116,105,109,101,46,32,84,104,101,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<40,92,68,43,124,60,92,100,43,62,41,42,91,33,63,93>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,97,110,32,117,110,108,105,109,105,116,101,100,32,110,117,109,98,101,114,32,111,102,32,115,117,98,115,116,114,105,110,103,115,32,116,104,97,116,32,101,105,116,104,101,114,32,99,111,110,115,105,115,116,32,111,102,32,110,111,110,45,100,105,103,105,116,115,44,32,111,114,32,100,105,103,105,116,115,32,101,110,99,108,111,115,101,100,32,105,110,32,60,62,44,32,102,111,108,108,111,119,101,100,32,98,121,32,33,32,111,114,32,63,46,32,87,104,101,110,32,105,116,32,109,97,116,99,104,101,115,44,32,105,116,32,114,117,110,115,32,113,117,105,99,107,108,121,46,32,72,111,119,101,118,101,114,44,32,105,102,32,105,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111>>]},{pre,[],[{code,[],[<<97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97>>]}]},{p,[],[<<105,116,32,116,97,107,101,115,32,97,32,108,111,110,103,32,116,105,109,101,32,98,101,102,111,114,101,32,114,101,112,111,114,116,105,110,103,32,102,97,105,108,117,114,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,115,116,114,105,110,103,32,99,97,110,32,98,101,32,100,105,118,105,100,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,92,68,43,32,114,101,112,101,97,116,32,97,110,100,32,116,104,101,32,101,120,116,101,114,110,97,108,32,42,32,114,101,112,101,97,116,32,105,110,32,109,97,110,121,32,119,97,121,115,44,32,97,110,100,32,97,108,108,32,109,117,115,116,32,98,101,32,116,114,105,101,100,46,32,40,84,104,101,32,101,120,97,109,112,108,101,32,117,115,101,115,32,91,33,63,93,32,114,97,116,104,101,114,32,116,104,97,110,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,97,116,32,116,104,101,32,101,110,100,44,32,97,115,32,98,111,116,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,104,97,118,101,32,97,110,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,97,108,108,111,119,115,32,102,111,114,32,102,97,115,116,32,102,97,105,108,117,114,101,32,119,104,101,110,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,105,115,32,117,115,101,100,46,32,84,104,101,121,32,114,101,109,101,109,98,101,114,32,116,104,101,32,108,97,115,116,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,114,101,113,117,105,114,101,100,32,102,111,114,32,97,32,109,97,116,99,104,44,32,97,110,100,32,102,97,105,108,32,101,97,114,108,121,32,105,102,32,105,116,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,46,41,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,105,116,32,117,115,101,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,108,105,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,100,105,103,105,116,115,32,99,97,110,110,111,116,32,98,101,32,98,114,111,107,101,110,44,32,97,110,100,32,102,97,105,108,117,114,101,32,104,97,112,112,101,110,115,32,113,117,105,99,107,108,121,58>>]},{pre,[],[{code,[],[<<40,40,63,62,92,68,43,41,124,60,92,100,43,62,41,42,91,33,63,93>>]}]},{a,[{id,<<115,101,99,116,49,54>>}],[]},{h2,[],[<<66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,32,98,97,99,107,115,108,97,115,104,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,100,105,103,105,116,32,62,32,48,32,40,97,110,100,32,112,111,115,115,105,98,108,121,32,102,117,114,116,104,101,114,32,100,105,103,105,116,115,41,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,101,97,114,108,105,101,114,32,40,116,104,97,116,32,105,115,44,32,116,111,32,105,116,115,32,108,101,102,116,41,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,112,114,111,118,105,100,101,100,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,32,116,104,97,116,32,109,97,110,121,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,32,105,115,32,60,32,49,48,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32,116,97,107,101,110,32,97,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,97,110,100,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,111,116,32,116,104,97,116,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,32,100,111,32,110,101,101,100,32,110,111,116,32,98,101,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,110,117,109,98,101,114,115,32,60,32,49,48,46,32,65,32,34,102,111,114,119,97,114,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,34,32,111,102,32,116,104,105,115,32,116,121,112,101,32,99,97,110,32,109,97,107,101,32,115,101,110,115,101,32,119,104,101,110,32,97,32,114,101,112,101,116,105,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,32,97,110,100,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,114,105,103,104,116,32,104,97,115,32,112,97,114,116,105,99,105,112,97,116,101,100,32,105,110,32,97,110,32,101,97,114,108,105,101,114,32,105,116,101,114,97,116,105,111,110,46>>]},{p,[],[<<73,116,32,105,115,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,118,101,32,97,32,110,117,109,101,114,105,99,97,108,32,34,102,111,114,119,97,114,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,34,32,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,119,104,111,115,101,32,110,117,109,98,101,114,32,105,115,32,49,48,32,111,114,32,109,111,114,101,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,44,32,97,115,32,97,32,115,101,113,117,101,110,99,101,32,115,117,99,104,32,97,115,32,92,53,48,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,104,97,114,97,99,116,101,114,32,100,101,102,105,110,101,100,32,105,110,32,111,99,116,97,108,46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,111,102,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,97,32,98,97,99,107,115,108,97,115,104,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,111,110,95,112,114,105,110,116,105,110,103,95,99,104,97,114,97,99,116,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,111,110,45,80,114,105,110,116,105,110,103,32,67,104,97,114,97,99,116,101,114,115>>]},<<32,101,97,114,108,105,101,114,46,32,84,104,101,114,101,32,105,115,32,110,111,32,115,117,99,104,32,112,114,111,98,108,101,109,32,119,104,101,110,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,117,115,101,100,46,32,65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,111,115,115,105,98,108,101,32,117,115,105,110,103,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,40,115,101,101,32,98,101,108,111,119,41,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,119,97,121,32,116,111,32,97,118,111,105,100,32,116,104,101,32,97,109,98,105,103,117,105,116,121,32,105,110,104,101,114,101,110,116,32,105,110,32,116,104,101,32,117,115,101,32,111,102,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,97,32,98,97,99,107,115,108,97,115,104,32,105,115,32,116,111,32,117,115,101,32,116,104,101,32,92,103,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,46,32,84,104,105,115,32,101,115,99,97,112,101,32,109,117,115,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,117,110,115,105,103,110,101,100,32,110,117,109,98,101,114,32,111,114,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,32,97,114,101,32,105,100,101,110,116,105,99,97,108,58>>]},{pre,[],[{code,[],[<<40,114,105,110,103,41,44,32,92,49,10,40,114,105,110,103,41,44,32,92,103,49,10,40,114,105,110,103,41,44,32,92,103,123,49,125>>]}]},{p,[],[<<65,110,32,117,110,115,105,103,110,101,100,32,110,117,109,98,101,114,32,115,112,101,99,105,102,105,101,115,32,97,110,32,97,98,115,111,108,117,116,101,32,114,101,102,101,114,101,110,99,101,32,119,105,116,104,111,117,116,32,116,104,101,32,97,109,98,105,103,117,105,116,121,32,116,104,97,116,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,111,108,100,101,114,32,115,121,110,116,97,120,46,32,73,116,32,105,115,32,97,108,115,111,32,117,115,101,102,117,108,32,119,104,101,110,32,108,105,116,101,114,97,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,105,115,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,40,100,101,102,41,103,104,105,41,92,103,123,45,49,125>>]}]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,92,103,123,45,49,125,32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,115,116,97,114,116,101,100,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,98,101,102,111,114,101,32,92,103,44,32,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,92,50,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,46,32,83,105,109,105,108,97,114,108,121,44,32,92,103,123,45,50,125,32,119,111,117,108,100,32,98,101,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,92,49,46,32,84,104,101,32,117,115,101,32,111,102,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,115,32,99,97,110,32,98,101,32,104,101,108,112,102,117,108,32,105,110,32,108,111,110,103,32,112,97,116,116,101,114,110,115,44,32,97,110,100,32,97,108,115,111,32,105,110,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,99,114,101,97,116,101,100,32,98,121,32,106,111,105,110,105,110,103,32,102,114,97,103,109,101,110,116,115,32,99,111,110,116,97,105,110,105,110,103,32,114,101,102,101,114,101,110,99,101,115,32,119,105,116,104,105,110,32,116,104,101,109,115,101,108,118,101,115,46>>]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,109,97,116,99,104,101,115,32,119,104,97,116,101,118,101,114,32,109,97,116,99,104,101,100,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,114,97,116,104,101,114,32,116,104,97,110,32,97,110,121,116,104,105,110,103,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,116,115,101,108,102,32,40,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]},<<32,100,101,115,99,114,105,98,101,115,32,97,32,119,97,121,32,111,102,32,100,111,105,110,103,32,116,104,97,116,41,46,32,83,111,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,115,101,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,34,114,101,115,112,111,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,44,32,98,117,116,32,110,111,116,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,49,105,98,105,108,105,116,121>>]}]},{p,[],[<<73,102,32,99,97,115,101,102,117,108,32,109,97,116,99,104,105,110,103,32,105,115,32,105,110,32,102,111,114,99,101,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,116,104,101,32,99,97,115,101,32,111,102,32,108,101,116,116,101,114,115,32,105,115,32,114,101,108,101,118,97,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,114,97,104,32,114,97,104,34,32,97,110,100,32,34,82,65,72,32,82,65,72,34,44,32,98,117,116,32,110,111,116,32,34,82,65,72,32,114,97,104,34,44,32,97,108,116,104,111,117,103,104,32,116,104,101,32,111,114,105,103,105,110,97,108,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,32,99,97,115,101,108,101,115,115,108,121,58>>]},{pre,[],[{code,[],[<<40,40,63,105,41,114,97,104,41,92,115,43,92,49>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,32,111,102,32,119,114,105,116,105,110,103,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,101,32,46,78,69,84,32,115,121,110,116,97,120,32>>,{code,[],[<<92,107,123,110,97,109,101,125>>]},<<32,97,110,100,32,116,104,101,32,80,101,114,108,32,115,121,110,116,97,120,32>>,{code,[],[<<92,107,60,110,97,109,101,62>>]},<<32,111,114,32>>,{code,[],[<<92,107,39,110,97,109,101,39>>]},<<32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,115,32,105,115,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,32>>,{code,[],[<<40,63,80,61,110,97,109,101,41>>]},<<46,32,84,104,101,32,117,110,105,102,105,101,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,115,121,110,116,97,120,32,105,110,32,80,101,114,108,32,53,46,49,48,44,32,105,110,32,119,104,105,99,104,32,92,103,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,98,111,116,104,32,110,117,109,101,114,105,99,32,97,110,100,32,110,97,109,101,100,32,114,101,102,101,114,101,110,99,101,115,44,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,84,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,114,101,119,114,105,116,116,101,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,119,97,121,115,58>>]},{pre,[],[{code,[],[<<40,63,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,92,107,60,112,49,62,10,40,63,39,112,49,39,40,63,105,41,114,97,104,41,92,115,43,92,107,123,112,49,125,10,40,63,80,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,40,63,80,61,112,49,41,10,40,63,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,92,103,123,112,49,125>>]}]},{p,[],[<<65,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32,110,97,109,101,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,101,102,111,114,101,32,111,114,32,97,102,116,101,114,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46>>]},{p,[],[<<84,104,101,114,101,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,115,97,109,101,32,115,117,98,112,97,116,116,101,114,110,46,32,73,102,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,110,111,116,32,98,101,101,110,32,117,115,101,100,32,105,110,32,97,32,112,97,114,116,105,99,117,108,97,114,32,109,97,116,99,104,44,32,97,110,121,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,105,116,32,97,108,119,97,121,115,32,102,97,105,108,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,102,97,105,108,115,32,105,102,32,105,116,32,115,116,97,114,116,115,32,116,111,32,109,97,116,99,104,32,34,97,34,32,114,97,116,104,101,114,32,116,104,97,110,32,34,98,99,34,58>>]},{pre,[],[{code,[],[<<40,97,124,40,98,99,41,41,92,50>>]}]},{p,[],[<<65,115,32,116,104,101,114,101,32,99,97,110,32,98,101,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,108,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,32,97,114,101,32,116,97,107,101,110,32,97,115,32,112,97,114,116,32,111,102,32,97,32,112,111,116,101,110,116,105,97,108,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,110,117,109,98,101,114,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,111,110,116,105,110,117,101,115,32,119,105,116,104,32,97,32,100,105,103,105,116,32,99,104,97,114,97,99,116,101,114,44,32,115,111,109,101,32,100,101,108,105,109,105,116,101,114,32,109,117,115,116,32,98,101,32,117,115,101,100,32,116,111,32,116,101,114,109,105,110,97,116,101,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,44,32,116,104,105,115,32,99,97,110,32,98,101,32,119,104,105,116,101,115,112,97,99,101,46,32,79,116,104,101,114,119,105,115,101,32,97,110,32,101,109,112,116,121,32,99,111,109,109,101,110,116,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,109,109,101,110,116,115>>]},<<41,32,99,97,110,32,98,101,32,117,115,101,100,46>>]},{p,[],[{em,[],[<<82,101,99,117,114,115,105,118,101,32,66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,104,97,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,119,104,105,99,104,32,105,116,32,114,101,102,101,114,115,32,102,97,105,108,115,32,119,104,101,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,102,105,114,115,116,32,117,115,101,100,44,32,115,111,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,40,97,92,49,41,32,110,101,118,101,114,32,109,97,116,99,104,101,115,46,32,72,111,119,101,118,101,114,44,32,115,117,99,104,32,114,101,102,101,114,101,110,99,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,105,110,115,105,100,101,32,114,101,112,101,97,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,34,97,34,115,32,97,110,100,32,97,108,115,111,32,34,97,98,97,34,44,32,34,97,98,97,98,98,97,97,34,44,32,97,110,100,32,115,111,32,111,110,58>>]},{pre,[],[{code,[],[<<40,97,124,98,92,49,41,43>>]}]},{p,[],[<<65,116,32,101,97,99,104,32,105,116,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,109,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,112,114,101,118,105,111,117,115,32,105,116,101,114,97,116,105,111,110,46,32,73,110,32,111,114,100,101,114,32,102,111,114,32,116,104,105,115,32,116,111,32,119,111,114,107,44,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,98,101,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,105,116,101,114,97,116,105,111,110,32,100,111,101,115,32,110,111,116,32,110,101,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,100,111,110,101,32,117,115,105,110,103,32,97,108,116,101,114,110,97,116,105,111,110,44,32,97,115,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,97,98,111,118,101,44,32,111,114,32,98,121,32,97,32,113,117,97,110,116,105,102,105,101,114,32,119,105,116,104,32,97,32,109,105,110,105,109,117,109,32,111,102,32,122,101,114,111,46>>]},{p,[],[<<66,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,111,102,32,116,104,105,115,32,116,121,112,101,32,99,97,117,115,101,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,121,32,114,101,102,101,114,101,110,99,101,32,116,111,32,98,101,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,79,110,99,101,32,116,104,101,32,119,104,111,108,101,32,103,114,111,117,112,32,104,97,115,32,98,101,101,110,32,109,97,116,99,104,101,100,44,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,99,97,110,110,111,116,32,99,97,117,115,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,116,104,101,32,103,114,111,117,112,46>>]},{a,[{id,<<115,101,99,116,49,55>>}],[]},{h2,[],[<<65,115,115,101,114,116,105,111,110,115>>]},{p,[],[<<65,110,32,97,115,115,101,114,116,105,111,110,32,105,115,32,97,32,116,101,115,116,32,111,110,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,102,111,108,108,111,119,105,110,103,32,111,114,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,99,111,110,115,117,109,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,115,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,32,99,111,100,101,100,32,97,115,32,92,98,44,32,92,66,44,32,92,65,44,32,92,71,44,32,92,90,44,32,92,122,44,32,94,44,32,97,110,100,32,36,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,115,46>>]},{p,[],[<<77,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,99,111,100,101,100,32,97,115,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,101,114,101,32,97,114,101,32,116,119,111,32,107,105,110,100,115,58,32,116,104,111,115,101,32,116,104,97,116,32,108,111,111,107,32,97,104,101,97,100,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,111,115,101,32,116,104,97,116,32,108,111,111,107,32,98,101,104,105,110,100,32,105,116,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,32,105,110,32,116,104,101,32,110,111,114,109,97,108,32,119,97,121,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,100,111,101,115,32,110,111,116,32,99,97,117,115,101,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,116,111,32,98,101,32,99,104,97,110,103,101,100,46>>]},{p,[],[<<65,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,73,102,32,115,117,99,104,32,97,110,32,97,115,115,101,114,116,105,111,110,32,99,111,110,116,97,105,110,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,105,110,32,105,116,44,32,116,104,101,115,101,32,97,114,101,32,99,111,117,110,116,101,100,32,102,111,114,32,116,104,101,32,112,117,114,112,111,115,101,115,32,111,102,32,110,117,109,98,101,114,105,110,103,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,46,32,72,111,119,101,118,101,114,44,32,115,117,98,115,116,114,105,110,103,32,99,97,112,116,117,114,105,110,103,32,105,115,32,100,111,110,101,32,111,110,108,121,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,40,80,101,114,108,32,115,111,109,101,116,105,109,101,115,44,32,98,117,116,32,110,111,116,32,97,108,119,97,121,115,44,32,112,101,114,102,111,114,109,115,32,99,97,112,116,117,114,105,110,103,32,105,110,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,41>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,102,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,111,110,101,32,111,114,32,109,111,114,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,115,117,99,99,101,101,100,115,44,32,98,117,116,32,102,97,105,108,117,114,101,32,116,111,32,109,97,116,99,104,32,108,97,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,111,118,101,114,32,116,104,105,115,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,99,97,112,116,117,114,101,115,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,97,114,101,32,114,101,115,101,116,32,111,110,108,121,32,105,102,32,110,111,32,104,105,103,104,101,114,32,110,117,109,98,101,114,101,100,32,99,97,112,116,117,114,101,115,32,97,114,101,32,97,108,114,101,97,100,121,32,115,101,116,46,32,84,104,105,115,32,105,115,44,32,117,110,102,111,114,116,117,110,97,116,101,108,121,44,32,97,32,102,117,110,100,97,109,101,110,116,97,108,32,108,105,109,105,116,97,116,105,111,110,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,44,32,97,110,100,32,97,115,32,80,67,82,69,49,32,105,115,32,110,111,119,32,105,110,32,109,97,105,110,116,101,110,97,110,99,101,45,111,110,108,121,32,115,116,97,116,117,115,44,32,105,116,32,105,115,32,117,110,108,105,107,101,108,121,32,101,118,101,114,32,116,111,32,99,104,97,110,103,101,46>>]}]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,97,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,115,32,99,97,110,32,98,101,32,114,101,112,101,97,116,101,100,46,32,72,111,119,101,118,101,114,44,32,105,116,32,109,97,107,101,115,32,110,111,32,115,101,110,115,101,32,116,111,32,97,115,115,101,114,116,32,116,104,101,32,115,97,109,101,32,116,104,105,110,103,32,109,97,110,121,32,116,105,109,101,115,44,32,116,104,101,32,115,105,100,101,32,101,102,102,101,99,116,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,111,99,99,97,115,105,111,110,97,108,108,121,32,98,101,32,117,115,101,102,117,108,46,32,73,110,32,112,114,97,99,116,105,99,101,44,32,116,104,101,114,101,32,97,114,101,32,111,110,108,121,32,116,104,114,101,101,32,99,97,115,101,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,123,48,125,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,105,115,32,110,101,118,101,114,32,111,98,101,121,101,100,32,100,117,114,105,110,103,32,109,97,116,99,104,105,110,103,46,32,72,111,119,101,118,101,114,44,32,105,116,32,99,97,110,32,99,111,110,116,97,105,110,32,105,110,116,101,114,110,97,108,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,103,114,111,117,112,115,32,116,104,97,116,32,97,114,101,32,99,97,108,108,101,100,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,32,116,104,114,111,117,103,104,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,101,99,104,97,110,105,115,109,46>>]}]},{li,[],[{p,[],[<<73,102,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,123,48,44,110,125,44,32,119,104,101,114,101,32,110,32,62,32,48,44,32,105,116,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,105,102,32,105,116,32,119,97,115,32,123,48,44,49,125,46,32,65,116,32,114,117,110,116,105,109,101,44,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,105,115,32,116,114,105,101,100,32,119,105,116,104,32,97,110,100,32,119,105,116,104,111,117,116,32,116,104,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,111,114,100,101,114,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,103,114,101,101,100,105,110,101,115,115,32,111,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,46>>]}]},{li,[],[{p,[],[<<73,102,32,116,104,101,32,109,105,110,105,109,117,109,32,114,101,112,101,116,105,116,105,111,110,32,105,115,32,62,32,48,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,32,97,115,115,101,114,116,105,111,110,32,105,115,32,111,98,101,121,101,100,32,111,110,108,121,32,111,110,99,101,32,119,104,101,110,32,101,110,99,111,117,110,116,101,114,101,100,32,100,117,114,105,110,103,32,109,97,116,99,104,105,110,103,46>>]}]}]},{p,[],[{em,[],[<<76,111,111,107,97,104,101,97,100,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<76,111,111,107,97,104,101,97,100,32,97,115,115,101,114,116,105,111,110,115,32,115,116,97,114,116,32,119,105,116,104,32,40,63,61,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,110,100,32,40,63,33,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,32,119,111,114,100,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,115,101,109,105,99,111,108,111,110,44,32,98,117,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,116,104,101,32,115,101,109,105,99,111,108,111,110,32,105,110,32,116,104,101,32,109,97,116,99,104,58>>]},{pre,[],[{code,[],[<<92,119,43,40,63,61,59,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,110,121,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,102,111,111,34,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,34,98,97,114,34,58>>]},{pre,[],[{code,[],[<<102,111,111,40,63,33,98,97,114,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,97,112,112,97,114,101,110,116,108,121,32,115,105,109,105,108,97,114,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<40,63,33,102,111,111,41,98,97,114>>]}]},{p,[],[<<100,111,101,115,32,110,111,116,32,102,105,110,100,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,116,104,97,116,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,115,111,109,101,116,104,105,110,103,32,111,116,104,101,114,32,116,104,97,110,32,34,102,111,111,34,46,32,73,116,32,102,105,110,100,115,32,97,110,121,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,119,104,97,116,115,111,101,118,101,114,44,32,97,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,40,63,33,102,111,111,41,32,105,115,32,97,108,119,97,121,115,32,116,114,117,101,32,119,104,101,110,32,116,104,101,32,110,101,120,116,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,34,98,97,114,34,46,32,65,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,105,115,32,110,101,101,100,101,100,32,116,111,32,97,99,104,105,101,118,101,32,116,104,101,32,111,116,104,101,114,32,101,102,102,101,99,116,46>>]},{p,[],[<<73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,102,111,114,99,101,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,97,116,32,115,111,109,101,32,112,111,105,110,116,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,116,104,101,32,109,111,115,116,32,99,111,110,118,101,110,105,101,110,116,32,119,97,121,32,116,111,32,100,111,32,105,116,32,105,115,32,119,105,116,104,32,40,63,33,41,44,32,97,115,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,46,32,83,111,44,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,114,101,113,117,105,114,101,115,32,116,104,101,114,101,32,105,115,32,110,111,116,32,116,111,32,98,101,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,109,117,115,116,32,97,108,119,97,121,115,32,102,97,105,108,46,32,84,104,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,111,110,116,114,111,108,32,118,101,114,98,32,40,42,70,65,73,76,41,32,111,114,32,40,42,70,41,32,105,115,32,97,32,115,121,110,111,110,121,109,32,102,111,114,32,40,63,33,41,46>>]},{p,[],[{em,[],[<<76,111,111,107,98,101,104,105,110,100,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<76,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,115,116,97,114,116,32,119,105,116,104,32,40,63,60,61,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,110,100,32,40,63,60,33,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,110,100,115,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,116,104,97,116,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,63,60,33,102,111,111,41,98,97,114>>]}]},{p,[],[<<84,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,97,114,101,32,114,101,115,116,114,105,99,116,101,100,32,115,117,99,104,32,116,104,97,116,32,97,108,108,32,116,104,101,32,115,116,114,105,110,103,115,32,105,116,32,109,97,116,99,104,101,115,32,109,117,115,116,32,104,97,118,101,32,97,32,102,105,120,101,100,32,108,101,110,103,116,104,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,114,101,32,97,114,101,32,109,97,110,121,32,116,111,112,45,108,101,118,101,108,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,116,104,101,121,32,100,111,32,110,111,116,32,97,108,108,32,104,97,118,101,32,116,111,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,102,105,120,101,100,32,108,101,110,103,116,104,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,112,101,114,109,105,116,116,101,100,58>>]},{pre,[],[{code,[],[<<40,63,60,61,98,117,108,108,111,99,107,124,100,111,110,107,101,121,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,58>>]},{pre,[],[{code,[],[<<40,63,60,33,100,111,103,115,63,124,99,97,116,115,63,41>>]}]},{p,[],[<<66,114,97,110,99,104,101,115,32,116,104,97,116,32,109,97,116,99,104,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,32,115,116,114,105,110,103,115,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,111,110,108,121,32,97,116,32,116,104,101,32,116,111,112,45,108,101,118,101,108,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,46,32,84,104,105,115,32,105,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,99,111,109,112,97,114,101,100,32,119,105,116,104,32,80,101,114,108,44,32,119,104,105,99,104,32,114,101,113,117,105,114,101,115,32,97,108,108,32,98,114,97,110,99,104,101,115,32,116,111,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,108,101,110,103,116,104,32,111,102,32,115,116,114,105,110,103,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,117,99,104,32,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,110,111,116,32,112,101,114,109,105,116,116,101,100,44,32,97,115,32,105,116,115,32,115,105,110,103,108,101,32,116,111,112,45,108,101,118,101,108,32,98,114,97,110,99,104,32,99,97,110,32,109,97,116,99,104,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,115,58>>]},{pre,[],[{code,[],[<<40,63,60,61,97,98,40,99,124,100,101,41,41>>]}]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,116,32,105,115,32,97,99,99,101,112,116,97,98,108,101,32,116,111,32,80,67,82,69,32,105,102,32,114,101,119,114,105,116,116,101,110,32,116,111,32,117,115,101,32,116,119,111,32,116,111,112,45,108,101,118,101,108,32,98,114,97,110,99,104,101,115,58>>]},{pre,[],[{code,[],[<<40,63,60,61,97,98,99,124,97,98,100,101,41>>]}]},{p,[],[<<83,111,109,101,116,105,109,101,115,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,75,32,40,115,101,101,32,97,98,111,118,101,41,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,116,111,32,103,101,116,32,114,111,117,110,100,32,116,104,101,32,102,105,120,101,100,45,108,101,110,103,116,104,32,114,101,115,116,114,105,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,105,115,44,32,102,111,114,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,44,32,116,111,32,109,111,118,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,98,97,99,107,32,116,101,109,112,111,114,97,114,105,108,121,32,98,121,32,116,104,101,32,102,105,120,101,100,32,108,101,110,103,116,104,32,97,110,100,32,116,104,101,110,32,116,114,121,32,116,111,32,109,97,116,99,104,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,105,110,115,117,102,102,105,99,105,101,110,116,32,99,104,97,114,97,99,116,101,114,115,32,98,101,102,111,114,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,102,97,105,108,115,46>>]},{p,[],[<<73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,116,104,101,32,92,67,32,101,115,99,97,112,101,32,40,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,100,97,116,97,32,117,110,105,116,32,101,118,101,110,32,105,110,32,97,32,85,84,70,32,109,111,100,101,41,32,116,111,32,97,112,112,101,97,114,32,105,110,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,44,32,97,115,32,105,116,32,109,97,107,101,115,32,105,116,32,105,109,112,111,115,115,105,98,108,101,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,111,111,107,98,101,104,105,110,100,46,32,84,104,101,32,92,88,32,97,110,100,32,92,82,32,101,115,99,97,112,101,115,44,32,119,104,105,99,104,32,99,97,110,32,109,97,116,99,104,32,100,105,102,102,101,114,101,110,116,32,110,117,109,98,101,114,115,32,111,102,32,100,97,116,97,32,117,110,105,116,115,44,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,32,101,105,116,104,101,114,46>>]},{p,[],[<<34,83,117,98,114,111,117,116,105,110,101,34,32,99,97,108,108,115,32,40,115,101,101,32,98,101,108,111,119,41,44,32,115,117,99,104,32,97,115,32,40,63,50,41,32,111,114,32,40,63,38,88,41,44,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,108,111,111,107,98,101,104,105,110,100,115,44,32,97,115,32,108,111,110,103,32,97,115,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,102,105,120,101,100,45,108,101,110,103,116,104,32,115,116,114,105,110,103,46,32,82,101,99,117,114,115,105,111,110,44,32,104,111,119,101,118,101,114,44,32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46>>]},{p,[],[<<80,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,116,111,32,115,112,101,99,105,102,121,32,101,102,102,105,99,105,101,110,116,32,109,97,116,99,104,105,110,103,32,111,102,32,102,105,120,101,100,45,108,101,110,103,116,104,32,115,116,114,105,110,103,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,105,109,112,108,101,32,112,97,116,116,101,114,110,32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,97,32,108,111,110,103,32,115,116,114,105,110,103,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,58>>]},{pre,[],[{code,[],[<<97,98,99,100,36>>]}]},{p,[],[<<65,115,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,101,100,115,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,80,67,82,69,32,108,111,111,107,115,32,102,111,114,32,101,97,99,104,32,34,97,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,97,110,100,32,116,104,101,110,32,115,101,101,115,32,105,102,32,119,104,97,116,32,102,111,108,108,111,119,115,32,109,97,116,99,104,101,115,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115>>]},{pre,[],[{code,[],[<<94,46,42,97,98,99,100,36>>]}]},{p,[],[<<116,104,101,32,105,110,105,116,105,97,108,32,46,42,32,109,97,116,99,104,101,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,32,97,116,32,102,105,114,115,116,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,116,104,105,115,32,102,97,105,108,115,32,40,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,102,111,108,108,111,119,105,110,103,32,34,97,34,41,44,32,105,116,32,98,97,99,107,116,114,97,99,107,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,44,32,116,104,101,110,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,44,32,97,110,100,32,115,111,32,111,110,46,32,79,110,99,101,32,97,103,97,105,110,32,116,104,101,32,115,101,97,114,99,104,32,102,111,114,32,34,97,34,32,99,111,118,101,114,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,44,32,102,114,111,109,32,114,105,103,104,116,32,116,111,32,108,101,102,116,44,32,115,111,32,119,101,32,97,114,101,32,110,111,32,98,101,116,116,101,114,32,111,102,102,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,119,114,105,116,116,101,110,32,97,115>>]},{pre,[],[{code,[],[<<94,46,42,43,40,63,60,61,97,98,99,100,41>>]}]},{p,[],[<<116,104,101,114,101,32,99,97,110,32,98,101,32,110,111,32,98,97,99,107,116,114,97,99,107,105,110,103,32,102,111,114,32,116,104,101,32,46,42,43,32,105,116,101,109,59,32,105,116,32,99,97,110,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,46,32,84,104,101,32,115,117,98,115,101,113,117,101,110,116,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,100,111,101,115,32,97,32,115,105,110,103,108,101,32,116,101,115,116,32,111,110,32,116,104,101,32,108,97,115,116,32,102,111,117,114,32,99,104,97,114,97,99,116,101,114,115,46,32,73,102,32,105,116,32,102,97,105,108,115,44,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,32,105,109,109,101,100,105,97,116,101,108,121,46,32,70,111,114,32,108,111,110,103,32,115,116,114,105,110,103,115,44,32,116,104,105,115,32,97,112,112,114,111,97,99,104,32,109,97,107,101,115,32,97,32,115,105,103,110,105,102,105,99,97,110,116,32,100,105,102,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,105,110,103,32,116,105,109,101,46>>]},{p,[],[{em,[],[<<85,115,105,110,103,32,77,117,108,116,105,112,108,101,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<77,97,110,121,32,97,115,115,101,114,116,105,111,110,115,32,40,111,102,32,97,110,121,32,115,111,114,116,41,32,99,97,110,32,111,99,99,117,114,32,105,110,32,115,117,99,99,101,115,115,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,114,101,101,32,100,105,103,105,116,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,34,57,57,57,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,41,40,63,60,33,57,57,57,41,102,111,111>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,101,97,99,104,32,111,102,32,116,104,101,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,97,112,112,108,105,101,100,32,105,110,100,101,112,101,110,100,101,110,116,108,121,32,97,116,32,116,104,101,32,115,97,109,101,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,70,105,114,115,116,32,116,104,101,114,101,32,105,115,32,97,32,99,104,101,99,107,32,116,104,97,116,32,116,104,101,32,112,114,101,118,105,111,117,115,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,108,108,32,100,105,103,105,116,115,44,32,97,110,100,32,116,104,101,110,32,116,104,101,114,101,32,105,115,32,97,32,99,104,101,99,107,32,116,104,97,116,32,116,104,101,32,115,97,109,101,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46,32,84,104,105,115,32,112,97,116,116,101,114,110,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,109,97,116,99,104,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,115,105,120,32,99,104,97,114,97,99,116,101,114,115,44,32,116,104,101,32,102,105,114,115,116,32,111,102,32,119,104,105,99,104,32,97,114,101,32,100,105,103,105,116,115,32,97,110,100,32,116,104,101,32,108,97,115,116,32,116,104,114,101,101,32,111,102,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,34,49,50,51,97,98,99,102,111,111,34,46,32,65,32,112,97,116,116,101,114,110,32,116,111,32,100,111,32,116,104,97,116,32,105,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,46,46,46,41,40,63,60,33,57,57,57,41,102,111,111>>]}]},{p,[],[<<84,104,105,115,32,116,105,109,101,32,116,104,101,32,102,105,114,115,116,32,97,115,115,101,114,116,105,111,110,32,108,111,111,107,115,32,97,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,115,105,120,32,99,104,97,114,97,99,116,101,114,115,44,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,116,104,114,101,101,32,97,114,101,32,100,105,103,105,116,115,44,32,97,110,100,32,116,104,101,110,32,116,104,101,32,115,101,99,111,110,100,32,97,115,115,101,114,116,105,111,110,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46>>]},{p,[],[<<65,115,115,101,114,116,105,111,110,115,32,99,97,110,32,98,101,32,110,101,115,116,101,100,32,105,110,32,97,110,121,32,99,111,109,98,105,110,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,122,34,32,116,104,97,116,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,34,98,97,114,34,44,32,119,104,105,99,104,32,105,110,32,116,117,114,110,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,40,63,60,33,102,111,111,41,98,97,114,41,98,97,122>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,114,101,101,32,100,105,103,105,116,115,32,97,110,100,32,97,110,121,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,34,57,57,57,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,40,63,33,57,57,57,41,46,46,46,41,102,111,111>>]}]},{a,[{id,<<115,101,99,116,49,56>>}],[]},{h2,[],[<<67,111,110,100,105,116,105,111,110,97,108,32,83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<73,116,32,105,115,32,112,111,115,115,105,98,108,101,32,116,111,32,99,97,117,115,101,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,32,116,111,32,111,98,101,121,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,111,110,100,105,116,105,111,110,97,108,108,121,32,111,114,32,116,111,32,99,104,111,111,115,101,32,98,101,116,119,101,101,110,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,32,115,117,98,112,97,116,116,101,114,110,115,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,110,32,97,115,115,101,114,116,105,111,110,44,32,111,114,32,119,104,101,116,104,101,114,32,97,32,115,112,101,99,105,102,105,99,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,97,108,114,101,97,100,121,32,98,101,101,110,32,109,97,116,99,104,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,116,119,111,32,112,111,115,115,105,98,108,101,32,102,111,114,109,115,32,111,102,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,40,99,111,110,100,105,116,105,111,110,41,121,101,115,45,112,97,116,116,101,114,110,41,10,40,63,40,99,111,110,100,105,116,105,111,110,41,121,101,115,45,112,97,116,116,101,114,110,124,110,111,45,112,97,116,116,101,114,110,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,115,97,116,105,115,102,105,101,100,44,32,116,104,101,32,121,101,115,45,112,97,116,116,101,114,110,32,105,115,32,117,115,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,110,111,45,112,97,116,116,101,114,110,32,40,105,102,32,112,114,101,115,101,110,116,41,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,101,120,105,115,116,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,69,97,99,104,32,111,102,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,99,97,110,32,105,116,115,101,108,102,32,99,111,110,116,97,105,110,32,110,101,115,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,97,110,121,32,102,111,114,109,44,32,105,110,99,108,117,100,105,110,103,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,115,59,32,116,104,101,32,114,101,115,116,114,105,99,116,105,111,110,32,116,111,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,112,112,108,105,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,108,101,118,101,108,32,111,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,32,105,115,32,97,110,32,101,120,97,109,112,108,101,32,119,104,101,114,101,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,99,111,109,112,108,101,120,58>>]},{pre,[],[{code,[],[<<40,63,40,49,41,32,40,65,124,66,124,67,41,32,124,32,40,68,32,124,32,40,63,40,50,41,69,124,70,41,32,124,32,69,41,32,41>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,102,111,117,114,32,107,105,110,100,115,32,111,102,32,99,111,110,100,105,116,105,111,110,58,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,44,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,114,101,99,117,114,115,105,111,110,44,32,97,32,112,115,101,117,100,111,45,99,111,110,100,105,116,105,111,110,32,99,97,108,108,101,100,32,68,69,70,73,78,69,44,32,97,110,100,32,97,115,115,101,114,116,105,111,110,115,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,97,32,85,115,101,100,32,83,117,98,112,97,116,116,101,114,110,32,66,121,32,78,117,109,98,101,114>>]}]},{p,[],[<<73,102,32,116,104,101,32,116,101,120,116,32,98,101,116,119,101,101,110,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,99,111,110,115,105,115,116,115,32,111,102,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,100,105,103,105,116,115,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,97,116,32,110,117,109,98,101,114,32,104,97,115,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,32,101,120,105,115,116,115,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},<<32,101,97,114,108,105,101,114,41,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,102,32,116,104,101,109,32,104,97,118,101,32,109,97,116,99,104,101,100,46,32,65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,110,111,116,97,116,105,111,110,32,105,115,32,116,111,32,112,114,101,99,101,100,101,32,116,104,101,32,100,105,103,105,116,115,32,119,105,116,104,32,97,32,112,108,117,115,32,111,114,32,109,105,110,117,115,32,115,105,103,110,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,110,117,109,98,101,114,32,105,115,32,114,101,108,97,116,105,118,101,32,114,97,116,104,101,114,32,116,104,97,110,32,97,98,115,111,108,117,116,101,46,32,84,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32,40,63,40,45,49,41,44,32,116,104,101,32,110,101,120,116,32,109,111,115,116,32,114,101,99,101,110,116,32,98,121,32,40,63,40,45,50,41,44,32,97,110,100,32,115,111,32,111,110,46,32,73,110,115,105,100,101,32,108,111,111,112,115,44,32,105,116,32,99,97,110,32,97,108,115,111,32,109,97,107,101,32,115,101,110,115,101,32,116,111,32,114,101,102,101,114,32,116,111,32,115,117,98,115,101,113,117,101,110,116,32,103,114,111,117,112,115,46,32,84,104,101,32,110,101,120,116,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,98,101,32,111,112,101,110,101,100,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,97,115,32,40,63,40,43,49,41,44,32,97,110,100,32,115,111,32,111,110,46,32,40,84,104,101,32,118,97,108,117,101,32,122,101,114,111,32,105,110,32,97,110,121,32,111,102,32,116,104,101,115,101,32,102,111,114,109,115,32,105,115,32,110,111,116,32,117,115,101,100,59,32,105,116,32,112,114,111,118,111,107,101,115,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,46,41>>]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,99,111,110,116,97,105,110,115,32,110,111,110,45,115,105,103,110,105,102,105,99,97,110,116,32,119,104,105,116,101,115,112,97,99,101,32,116,111,32,109,97,107,101,32,105,116,32,109,111,114,101,32,114,101,97,100,97,98,108,101,32,40,97,115,115,117,109,101,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<41,32,97,110,100,32,116,111,32,100,105,118,105,100,101,32,105,116,32,105,110,116,111,32,116,104,114,101,101,32,112,97,114,116,115,32,102,111,114,32,101,97,115,101,32,111,102,32,100,105,115,99,117,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<40,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,49,41,32,92,41,32,41>>]}]},{p,[],[<<84,104,101,32,102,105,114,115,116,32,112,97,114,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,116,105,111,110,97,108,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,44,32,97,110,100,32,105,102,32,116,104,97,116,32,99,104,97,114,97,99,116,101,114,32,105,115,32,112,114,101,115,101,110,116,44,32,115,101,116,115,32,105,116,32,97,115,32,116,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,46,32,84,104,101,32,115,101,99,111,110,100,32,112,97,114,116,32,109,97,116,99,104,101,115,32,111,110,101,32,111,114,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,97,114,101,110,116,104,101,115,101,115,46,32,84,104,101,32,116,104,105,114,100,32,112,97,114,116,32,105,115,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,116,101,115,116,115,32,119,104,101,116,104,101,114,32,116,104,101,32,102,105,114,115,116,32,115,101,116,32,111,102,32,112,97,114,101,110,116,104,101,115,101,115,32,109,97,116,99,104,101,100,32,111,114,32,110,111,116,46,32,73,102,32,116,104,101,121,32,100,105,100,44,32,116,104,97,116,32,105,115,44,32,105,102,32,115,117,98,106,101,99,116,32,115,116,97,114,116,101,100,32,119,105,116,104,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,44,32,97,110,100,32,115,111,32,116,104,101,32,121,101,115,45,112,97,116,116,101,114,110,32,105,115,32,101,120,101,99,117,116,101,100,32,97,110,100,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,114,101,113,117,105,114,101,100,46,32,79,116,104,101,114,119,105,115,101,44,32,97,115,32,110,111,45,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,110,111,116,104,105,110,103,46,32,84,104,97,116,32,105,115,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,105,115,32,112,97,116,116,101,114,110,32,105,115,32,101,109,98,101,100,100,101,100,32,105,110,32,97,32,108,97,114,103,101,114,32,111,110,101,44,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,117,115,101,100,58>>]},{pre,[],[{code,[],[<<46,46,46,111,116,104,101,114,32,115,116,117,102,102,46,46,46,32,40,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,45,49,41,32,92,41,32,41,32,46,46,46>>]}]},{p,[],[<<84,104,105,115,32,109,97,107,101,115,32,116,104,101,32,102,114,97,103,109,101,110,116,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,97,32,85,115,101,100,32,83,117,98,112,97,116,116,101,114,110,32,66,121,32,78,97,109,101>>]}]},{p,[],[<<80,101,114,108,32,117,115,101,115,32,116,104,101,32,115,121,110,116,97,120,32,40,63,40,60,110,97,109,101,62,41,46,46,46,41,32,111,114,32,40,63,40,39,110,97,109,101,39,41,46,46,46,41,32,116,111,32,116,101,115,116,32,102,111,114,32,97,32,117,115,101,100,32,115,117,98,112,97,116,116,101,114,110,32,98,121,32,110,97,109,101,46,32,70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,101,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,111,102,32,80,67,82,69,44,32,119,104,105,99,104,32,104,97,100,32,116,104,105,115,32,102,97,99,105,108,105,116,121,32,98,101,102,111,114,101,32,80,101,114,108,44,32,116,104,101,32,115,121,110,116,97,120,32,40,63,40,110,97,109,101,41,46,46,46,41,32,105,115,32,97,108,115,111,32,114,101,99,111,103,110,105,122,101,100,46>>]},{p,[],[<<82,101,119,114,105,116,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,116,111,32,117,115,101,32,97,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,32,103,105,118,101,115,58>>]},{pre,[],[{code,[],[<<40,63,60,79,80,69,78,62,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,60,79,80,69,78,62,41,32,92,41,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,110,97,109,101,32,117,115,101,100,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,32,111,102,32,116,104,105,115,32,107,105,110,100,32,105,115,32,97,32,100,117,112,108,105,99,97,116,101,44,32,116,104,101,32,116,101,115,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,108,108,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,97,110,100,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,110,101,32,111,102,32,116,104,101,109,32,104,97,115,32,109,97,116,99,104,101,100,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,80,97,116,116,101,114,110,32,82,101,99,117,114,115,105,111,110>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,104,101,32,115,116,114,105,110,103,32,40,82,41,44,32,97,110,100,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32,82,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,116,111,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,32,111,114,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32,73,102,32,100,105,103,105,116,115,32,111,114,32,97,32,110,97,109,101,32,112,114,101,99,101,100,101,100,32,98,121,32,97,109,112,101,114,115,97,110,100,32,102,111,108,108,111,119,32,116,104,101,32,108,101,116,116,101,114,32,82,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,63,40,82,51,41,46,46,46,41,32,111,114,32,40,63,40,82,38,110,97,109,101,41,46,46,46,41>>]}]},{p,[],[<<116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,114,101,99,117,114,115,105,111,110,32,105,115,32,105,110,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,119,104,111,115,101,32,110,117,109,98,101,114,32,111,114,32,110,97,109,101,32,105,115,32,103,105,118,101,110,46,32,84,104,105,115,32,99,111,110,100,105,116,105,111,110,32,100,111,101,115,32,110,111,116,32,99,104,101,99,107,32,116,104,101,32,101,110,116,105,114,101,32,114,101,99,117,114,115,105,111,110,32,115,116,97,99,107,46,32,73,102,32,116,104,101,32,110,97,109,101,32,117,115,101,100,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,32,111,102,32,116,104,105,115,32,107,105,110,100,32,105,115,32,97,32,100,117,112,108,105,99,97,116,101,44,32,116,104,101,32,116,101,115,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,108,108,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,97,110,100,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,114,101,99,117,114,115,105,111,110,46>>]},{p,[],[<<65,116,32,34,116,111,112,45,108,101,118,101,108,34,44,32,97,108,108,32,116,104,101,115,101,32,114,101,99,117,114,115,105,111,110,32,116,101,115,116,32,99,111,110,100,105,116,105,111,110,115,32,97,114,101,32,102,97,108,115,101,46,32,84,104,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,99,117,114,115,105,118,101,32,112,97,116,116,101,114,110,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]},{p,[],[{em,[],[<<68,101,102,105,110,105,110,103,32,83,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,85,115,101,32,66,121,32,82,101,102,101,114,101,110,99,101,32,79,110,108,121>>]}]},{a,[{id,<<100,101,102,105,110,105,110,103,95,115,117,98,112,97,116,116,101,114,110,115>>}],[]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,104,101,32,115,116,114,105,110,103,32,40,68,69,70,73,78,69,41,44,32,97,110,100,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32,68,69,70,73,78,69,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,97,108,119,97,121,115,32,102,97,108,115,101,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,114,101,32,99,97,110,32,98,101,32,111,110,108,121,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,46,32,73,116,32,105,115,32,97,108,119,97,121,115,32,115,107,105,112,112,101,100,32,105,102,32,99,111,110,116,114,111,108,32,114,101,97,99,104,101,115,32,116,104,105,115,32,112,111,105,110,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,32,105,100,101,97,32,111,102,32,68,69,70,73,78,69,32,105,115,32,116,104,97,116,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,102,105,110,101,32,34,115,117,98,114,111,117,116,105,110,101,115,34,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,46,32,40,84,104,101,32,117,115,101,32,111,102,32,115,117,98,114,111,117,116,105,110,101,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46,41,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,32,112,97,116,116,101,114,110,32,116,111,32,109,97,116,99,104,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,44,32,115,117,99,104,32,97,115,32,34,49,57,50,46,49,54,56,46,50,51,46,50,52,53,34,44,32,99,97,110,32,98,101,32,119,114,105,116,116,101,110,32,108,105,107,101,32,116,104,105,115,32,40,105,103,110,111,114,101,32,119,104,105,116,101,115,112,97,99,101,32,97,110,100,32,108,105,110,101,32,98,114,101,97,107,115,41,58>>]},{pre,[],[{code,[],[<<40,63,40,68,69,70,73,78,69,41,32,40,63,60,98,121,116,101,62,32,50,91,48,45,52,93,92,100,32,124,32,50,53,91,48,45,53,93,32,124,32,49,92,100,92,100,32,124,32,91,49,45,57,93,63,92,100,41,32,41,32,92,98,32,40,63,38,98,121,116,101,41,32,40,92,46,40,63,38,98,121,116,101,41,41,123,51,125,32,92,98>>]}]},{p,[],[<<84,104,101,32,102,105,114,115,116,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,32,68,69,70,73,78,69,32,103,114,111,117,112,32,105,110,115,105,100,101,32,119,104,105,99,104,32,105,115,32,97,32,97,110,111,116,104,101,114,32,103,114,111,117,112,32,110,97,109,101,100,32,34,98,121,116,101,34,32,105,115,32,100,101,102,105,110,101,100,46,32,84,104,105,115,32,109,97,116,99,104,101,115,32,97,110,32,105,110,100,105,118,105,100,117,97,108,32,99,111,109,112,111,110,101,110,116,32,111,102,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,32,40,97,32,110,117,109,98,101,114,32,60,32,50,53,54,41,46,32,87,104,101,110,32,109,97,116,99,104,105,110,103,32,116,97,107,101,115,32,112,108,97,99,101,44,32,116,104,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,107,105,112,112,101,100,44,32,97,115,32,68,69,70,73,78,69,32,97,99,116,115,32,108,105,107,101,32,97,32,102,97,108,115,101,32,99,111,110,100,105,116,105,111,110,46,32,84,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,117,115,101,115,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,110,97,109,101,100,32,103,114,111,117,112,32,116,111,32,109,97,116,99,104,32,116,104,101,32,102,111,117,114,32,100,111,116,45,115,101,112,97,114,97,116,101,100,32,99,111,109,112,111,110,101,110,116,115,32,111,102,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,44,32,105,110,115,105,115,116,105,110,103,32,111,110,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,32,97,116,32,101,97,99,104,32,101,110,100,46>>]},{p,[],[{em,[],[<<65,115,115,101,114,116,105,111,110,32,67,111,110,100,105,116,105,111,110,115>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,110,111,116,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,97,98,111,118,101,32,102,111,114,109,97,116,115,44,32,105,116,32,109,117,115,116,32,98,101,32,97,110,32,97,115,115,101,114,116,105,111,110,46,32,84,104,105,115,32,99,97,110,32,98,101,32,97,32,112,111,115,105,116,105,118,101,32,111,114,32,110,101,103,97,116,105,118,101,32,108,111,111,107,97,104,101,97,100,32,111,114,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,99,111,110,116,97,105,110,105,110,103,32,110,111,110,45,115,105,103,110,105,102,105,99,97,110,116,32,119,104,105,116,101,115,112,97,99,101,44,32,97,110,100,32,119,105,116,104,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,111,110,32,116,104,101,32,115,101,99,111,110,100,32,108,105,110,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,40,63,61,91,94,97,45,122,93,42,91,97,45,122,93,41,10,92,100,123,50,125,45,91,97,45,122,93,123,51,125,45,92,100,123,50,125,32,32,124,32,32,92,100,123,50,125,45,92,100,123,50,125,45,92,100,123,50,125,32,41>>]}]},{p,[],[<<84,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,108,111,111,107,97,104,101,97,100,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,116,105,111,110,97,108,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,108,101,116,116,101,114,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,108,101,116,116,101,114,46,32,84,104,97,116,32,105,115,44,32,105,116,32,116,101,115,116,115,32,102,111,114,32,116,104,101,32,112,114,101,115,101,110,99,101,32,111,102,32,97,116,32,108,101,97,115,116,32,111,110,101,32,108,101,116,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,73,102,32,97,32,108,101,116,116,101,114,32,105,115,32,102,111,117,110,100,44,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,105,114,115,116,32,97,108,116,101,114,110,97,116,105,118,101,44,32,111,116,104,101,114,119,105,115,101,32,105,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,115,101,99,111,110,100,46,32,84,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,115,116,114,105,110,103,115,32,105,110,32,111,110,101,32,111,102,32,116,104,101,32,116,119,111,32,102,111,114,109,115,32,100,100,45,97,97,97,45,100,100,32,111,114,32,100,100,45,100,100,45,100,100,44,32,119,104,101,114,101,32,97,97,97,32,97,114,101,32,108,101,116,116,101,114,115,32,97,110,100,32,100,100,32,97,114,101,32,100,105,103,105,116,115,46>>]},{a,[{id,<<115,101,99,116,49,57>>}],[]},{h2,[],[<<67,111,109,109,101,110,116,115>>]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,116,119,111,32,119,97,121,115,32,116,111,32,105,110,99,108,117,100,101,32,99,111,109,109,101,110,116,115,32,105,110,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,112,114,111,99,101,115,115,101,100,32,98,121,32,80,67,82,69,46,32,73,110,32,98,111,116,104,32,99,97,115,101,115,44,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,99,111,109,109,101,110,116,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,111,114,32,105,110,32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,97,110,121,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,32,111,102,32,114,101,108,97,116,101,100,32,99,104,97,114,97,99,116,101,114,115,32,115,117,99,104,32,97,115,32,40,63,58,32,111,114,32,97,32,115,117,98,112,97,116,116,101,114,110,32,110,97,109,101,32,111,114,32,110,117,109,98,101,114,46,32,84,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,109,97,107,101,32,117,112,32,97,32,99,111,109,109,101,110,116,32,112,108,97,121,32,110,111,32,112,97,114,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,105,110,103,46>>]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,40,63,35,32,109,97,114,107,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,99,111,109,109,101,110,116,32,116,104,97,116,32,99,111,110,116,105,110,117,101,115,32,117,112,32,116,111,32,116,104,101,32,110,101,120,116,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,78,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,111,112,116,105,111,110,32,80,67,82,69,95,69,88,84,69,78,68,69,68,32,105,115,32,115,101,116,44,32,97,110,32,117,110,101,115,99,97,112,101,100,32,35,32,99,104,97,114,97,99,116,101,114,32,97,108,115,111,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,111,109,109,101,110,116,44,32,119,104,105,99,104,32,105,110,32,116,104,105,115,32,99,97,115,101,32,99,111,110,116,105,110,117,101,115,32,116,111,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,32,111,114,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,87,104,105,99,104,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,110,101,119,108,105,110,101,115,32,105,115,32,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,32,111,112,116,105,111,110,115,32,112,97,115,115,101,100,32,116,111,32,97,32,99,111,109,112,105,108,105,110,103,32,102,117,110,99,116,105,111,110,32,111,114,32,98,121,32,97,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,99,111,110,118,101,110,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,67,111,110,118,101,110,116,105,111,110,115>>]},<<32,101,97,114,108,105,101,114,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,105,115,32,116,121,112,101,32,111,102,32,99,111,109,109,101,110,116,32,105,115,32,97,32,108,105,116,101,114,97,108,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,59,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,104,97,112,112,101,110,32,116,111,32,114,101,112,114,101,115,101,110,116,32,97,32,110,101,119,108,105,110,101,32,100,111,32,110,111,116,32,99,111,117,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,119,104,101,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,100,101,102,97,117,108,116,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,105,115,32,105,110,32,102,111,114,99,101,58>>]},{pre,[],[{code,[],[<<97,98,99,32,35,99,111,109,109,101,110,116,32,92,110,32,115,116,105,108,108,32,99,111,109,109,101,110,116>>]}]},{p,[],[<<79,110,32,101,110,99,111,117,110,116,101,114,105,110,103,32,99,104,97,114,97,99,116,101,114,32,35,44,32>>,{code,[],[<<112,99,114,101,95,99,111,109,112,105,108,101,40,41>>]},<<32,115,107,105,112,115,32,97,108,111,110,103,44,32,108,111,111,107,105,110,103,32,102,111,114,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,32,115,101,113,117,101,110,99,101,32,92,110,32,105,115,32,115,116,105,108,108,32,108,105,116,101,114,97,108,32,97,116,32,116,104,105,115,32,115,116,97,103,101,44,32,115,111,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,114,109,105,110,97,116,101,32,116,104,101,32,99,111,109,109,101,110,116,46,32,79,110,108,121,32,97,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,99,111,100,101,32,118,97,108,117,101,32,48,120,48,97,32,40,116,104,101,32,100,101,102,97,117,108,116,32,110,101,119,108,105,110,101,41,32,100,111,101,115,32,115,111,46>>]},{a,[{id,<<115,101,99,116,50,48>>}],[]},{h2,[],[<<82,101,99,117,114,115,105,118,101,32,80,97,116,116,101,114,110,115>>]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,112,114,111,98,108,101,109,32,111,102,32,109,97,116,99,104,105,110,103,32,97,32,115,116,114,105,110,103,32,105,110,32,112,97,114,101,110,116,104,101,115,101,115,44,32,97,108,108,111,119,105,110,103,32,102,111,114,32,117,110,108,105,109,105,116,101,100,32,110,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,46,32,87,105,116,104,111,117,116,32,116,104,101,32,117,115,101,32,111,102,32,114,101,99,117,114,115,105,111,110,44,32,116,104,101,32,98,101,115,116,32,116,104,97,116,32,99,97,110,32,98,101,32,100,111,110,101,32,105,115,32,116,111,32,117,115,101,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,117,112,32,116,111,32,115,111,109,101,32,102,105,120,101,100,32,100,101,112,116,104,32,111,102,32,110,101,115,116,105,110,103,46,32,73,116,32,105,115,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,110,100,108,101,32,97,110,32,97,114,98,105,116,114,97,114,121,32,110,101,115,116,105,110,103,32,100,101,112,116,104,46>>]},{p,[],[<<70,111,114,32,115,111,109,101,32,116,105,109,101,44,32,80,101,114,108,32,104,97,115,32,112,114,111,118,105,100,101,100,32,97,32,102,97,99,105,108,105,116,121,32,116,104,97,116,32,97,108,108,111,119,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,116,111,32,114,101,99,117,114,115,101,32,40,97,109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,41,46,32,73,116,32,100,111,101,115,32,116,104,105,115,32,98,121,32,105,110,116,101,114,112,111,108,97,116,105,110,103,32,80,101,114,108,32,99,111,100,101,32,105,110,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,97,116,32,114,117,110,116,105,109,101,44,32,97,110,100,32,116,104,101,32,99,111,100,101,32,99,97,110,32,114,101,102,101,114,32,116,111,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,105,116,115,101,108,102,46,32,65,32,80,101,114,108,32,112,97,116,116,101,114,110,32,117,115,105,110,103,32,99,111,100,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,116,111,32,115,111,108,118,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,111,98,108,101,109,32,99,97,110,32,98,101,32,99,114,101,97,116,101,100,32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<36,114,101,32,61,32,113,114,123,92,40,32,40,63,58,32,40,63,62,91,94,40,41,93,43,41,32,124,32,40,63,112,123,36,114,101,125,41,32,41,42,32,92,41,125,120,59>>]}]},{p,[],[<<73,116,101,109,32,40,63,112,123,46,46,46,125,41,32,105,110,116,101,114,112,111,108,97,116,101,115,32,80,101,114,108,32,99,111,100,101,32,97,116,32,114,117,110,116,105,109,101,44,32,97,110,100,32,105,110,32,116,104,105,115,32,99,97,115,101,32,114,101,102,101,114,115,32,114,101,99,117,114,115,105,118,101,108,121,32,116,111,32,116,104,101,32,112,97,116,116,101,114,110,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,46>>]},{p,[],[<<79,98,118,105,111,117,115,108,121,44,32,80,67,82,69,32,99,97,110,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,111,102,32,80,101,114,108,32,99,111,100,101,46,32,73,110,115,116,101,97,100,44,32,105,116,32,115,117,112,112,111,114,116,115,32,115,112,101,99,105,97,108,32,115,121,110,116,97,120,32,102,111,114,32,114,101,99,117,114,115,105,111,110,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,115,117,98,112,97,116,116,101,114,110,32,114,101,99,117,114,115,105,111,110,46,32,65,102,116,101,114,32,105,116,115,32,105,110,116,114,111,100,117,99,116,105,111,110,32,105,110,32,80,67,82,69,32,97,110,100,32,80,121,116,104,111,110,44,32,116,104,105,115,32,107,105,110,100,32,111,102,32,114,101,99,117,114,115,105,111,110,32,119,97,115,32,108,97,116,101,114,32,105,110,116,114,111,100,117,99,101,100,32,105,110,116,111,32,80,101,114,108,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,48,46>>]},{p,[],[<<65,32,115,112,101,99,105,97,108,32,105,116,101,109,32,116,104,97,116,32,99,111,110,115,105,115,116,115,32,111,102,32,40,63,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,117,109,98,101,114,32,62,32,48,32,97,110,100,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,101,32,103,105,118,101,110,32,110,117,109,98,101,114,44,32,105,102,32,105,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,116,104,97,116,32,115,117,98,112,97,116,116,101,114,110,46,32,40,73,102,32,110,111,116,44,32,105,116,32,105,115,32,97,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,44,32,119,104,105,99,104,32,105,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46,41,32,84,104,101,32,115,112,101,99,105,97,108,32,105,116,101,109,32,40,63,82,41,32,111,114,32,40,63,48,41,32,105,115,32,97,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,105,115,32,80,67,82,69,32,112,97,116,116,101,114,110,32,115,111,108,118,101,115,32,116,104,101,32,110,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,111,98,108,101,109,32,40,97,115,115,117,109,101,32,116,104,97,116,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,32,115,111,32,116,104,97,116,32,119,104,105,116,101,115,112,97,99,101,32,105,115,32,105,103,110,111,114,101,100,41,58>>]},{pre,[],[{code,[],[<<92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,82,41,32,41,42,32,92,41>>]}]},{p,[],[<<70,105,114,115,116,32,105,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,84,104,101,110,32,105,116,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,115,117,98,115,116,114,105,110,103,115,44,32,119,104,105,99,104,32,99,97,110,32,101,105,116,104,101,114,32,98,101,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,32,111,114,32,97,32,114,101,99,117,114,115,105,118,101,32,109,97,116,99,104,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,115,101,108,102,32,40,116,104,97,116,32,105,115,44,32,97,32,99,111,114,114,101,99,116,108,121,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,115,116,114,105,110,103,41,46,32,70,105,110,97,108,108,121,32,116,104,101,114,101,32,105,115,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,78,111,116,105,99,101,32,116,104,101,32,117,115,101,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,116,111,32,97,118,111,105,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,105,115,32,119,97,115,32,112,97,114,116,32,111,102,32,97,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,44,32,121,111,117,32,119,111,117,108,100,32,110,111,116,32,119,97,110,116,32,116,111,32,114,101,99,117,114,115,101,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,44,32,115,111,32,105,110,115,116,101,97,100,32,121,111,117,32,99,97,110,32,117,115,101,58>>]},{pre,[],[{code,[],[<<40,32,92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,49,41,32,41,42,32,92,41,32,41>>]}]},{p,[],[<<84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,104,101,114,101,32,119,105,116,104,105,110,32,112,97,114,101,110,116,104,101,115,101,115,32,115,111,32,116,104,97,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,114,101,102,101,114,115,32,116,111,32,116,104,101,109,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<73,110,32,97,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,44,32,107,101,101,112,105,110,103,32,116,114,97,99,107,32,111,102,32,112,97,114,101,110,116,104,101,115,105,115,32,110,117,109,98,101,114,115,32,99,97,110,32,98,101,32,116,114,105,99,107,121,46,32,84,104,105,115,32,105,115,32,109,97,100,101,32,101,97,115,105,101,114,32,98,121,32,116,104,101,32,117,115,101,32,111,102,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,115,46,32,73,110,115,116,101,97,100,32,111,102,32,40,63,49,41,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,97,98,111,118,101,44,32,121,111,117,32,99,97,110,32,119,114,105,116,101,32,40,63,45,50,41,32,116,111,32,114,101,102,101,114,32,116,111,32,116,104,101,32,115,101,99,111,110,100,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,32,84,104,97,116,32,105,115,44,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,99,111,117,110,116,115,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,108,101,102,116,119,97,114,100,115,32,102,114,111,109,32,116,104,101,32,112,111,105,110,116,32,97,116,32,119,104,105,99,104,32,105,116,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{p,[],[<<73,116,32,105,115,32,97,108,115,111,32,112,111,115,115,105,98,108,101,32,116,111,32,114,101,102,101,114,32,116,111,32,108,97,116,101,114,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,44,32,98,121,32,119,114,105,116,105,110,103,32,114,101,102,101,114,101,110,99,101,115,32,115,117,99,104,32,97,115,32,40,63,43,50,41,46,32,72,111,119,101,118,101,114,44,32,116,104,101,115,101,32,99,97,110,110,111,116,32,98,101,32,114,101,99,117,114,115,105,118,101,44,32,97,115,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,105,115,32,110,111,116,32,105,110,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,46,32,84,104,101,121,32,97,114,101,32,97,108,119,97,121,115,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,97,112,112,114,111,97,99,104,32,105,115,32,116,111,32,117,115,101,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,115,116,101,97,100,46,32,84,104,101,32,80,101,114,108,32,115,121,110,116,97,120,32,102,111,114,32,116,104,105,115,32,105,115,32,40,63,38,110,97,109,101,41,46,32,84,104,101,32,101,97,114,108,105,101,114,32,80,67,82,69,32,115,121,110,116,97,120,32,40,63,80,62,110,97,109,101,41,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,87,101,32,99,97,110,32,114,101,119,114,105,116,101,32,116,104,101,32,97,98,111,118,101,32,101,120,97,109,112,108,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{pre,[],[{code,[],[<<40,63,60,112,110,62,32,92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,38,112,110,41,32,41,42,32,92,41,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,114,101,32,105,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,116,104,101,32,101,97,114,108,105,101,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,105,115,32,112,97,114,116,105,99,117,108,97,114,32,101,120,97,109,112,108,101,32,112,97,116,116,101,114,110,32,116,104,97,116,32,119,101,32,104,97,118,101,32,115,116,117,100,105,101,100,32,99,111,110,116,97,105,110,115,32,110,101,115,116,101,100,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,44,32,97,110,100,32,115,111,32,116,104,101,32,117,115,101,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,102,111,114,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,115,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,32,105,115,32,105,109,112,111,114,116,97,110,116,32,119,104,101,110,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,115,116,114,105,110,103,115,32,116,104,97,116,32,100,111,32,110,111,116,32,109,97,116,99,104,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,116,104,105,115,32,112,97,116,116,101,114,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111>>]},{pre,[],[{code,[],[<<40,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,40,41>>]}]},{p,[],[<<105,116,32,103,105,118,101,115,32,34,110,111,32,109,97,116,99,104,34,32,113,117,105,99,107,108,121,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,110,111,116,32,117,115,101,100,44,32,116,104,101,32,109,97,116,99,104,32,114,117,110,115,32,102,111,114,32,97,32,108,111,110,103,32,116,105,109,101,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,115,111,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,32,116,104,101,32,43,32,97,110,100,32,42,32,114,101,112,101,97,116,115,32,99,97,110,32,99,97,114,118,101,32,117,112,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,110,100,32,97,108,108,32,109,117,115,116,32,98,101,32,116,101,115,116,101,100,32,98,101,102,111,114,101,32,102,97,105,108,117,114,101,32,99,97,110,32,98,101,32,114,101,112,111,114,116,101,100,46>>]},{p,[],[<<65,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,109,97,116,99,104,44,32,116,104,101,32,118,97,108,117,101,115,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,116,104,111,115,101,32,102,114,111,109,32,116,104,101,32,111,117,116,101,114,109,111,115,116,32,108,101,118,101,108,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,97,98,111,118,101,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116>>]},{pre,[],[{code,[],[<<40,97,98,40,99,100,41,101,102,41>>]}]},{p,[],[<<116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,105,110,110,101,114,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,40,110,117,109,98,101,114,101,100,32,50,41,32,105,115,32,34,101,102,34,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,108,97,115,116,32,118,97,108,117,101,32,116,97,107,101,110,32,111,110,32,97,116,32,116,104,101,32,116,111,112,45,108,101,118,101,108,46,32,73,102,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,109,97,116,99,104,101,100,32,97,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,105,116,115,32,102,105,110,97,108,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,32,105,115,32,117,110,115,101,116,44,32,101,118,101,110,32,105,102,32,105,116,32,119,97,115,32,40,116,101,109,112,111,114,97,114,105,108,121,41,32,115,101,116,32,97,116,32,97,32,100,101,101,112,101,114,32,108,101,118,101,108,32,100,117,114,105,110,103,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<68,111,32,110,111,116,32,99,111,110,102,117,115,101,32,105,116,101,109,32,40,63,82,41,32,119,105,116,104,32,99,111,110,100,105,116,105,111,110,32,40,82,41,44,32,119,104,105,99,104,32,116,101,115,116,115,32,102,111,114,32,114,101,99,117,114,115,105,111,110,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,116,101,120,116,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,44,32,97,108,108,111,119,105,110,103,32,102,111,114,32,97,114,98,105,116,114,97,114,121,32,110,101,115,116,105,110,103,46,32,79,110,108,121,32,100,105,103,105,116,115,32,97,114,101,32,97,108,108,111,119,101,100,32,105,110,32,110,101,115,116,101,100,32,98,114,97,99,107,101,116,115,32,40,116,104,97,116,32,105,115,44,32,119,104,101,110,32,114,101,99,117,114,115,105,110,103,41,44,32,119,104,105,108,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,97,116,32,116,104,101,32,111,117,116,101,114,32,108,101,118,101,108,46>>]},{pre,[],[{code,[],[<<60,32,40,63,58,32,40,63,40,82,41,32,92,100,43,43,32,32,124,32,91,94,60,62,93,42,43,41,32,124,32,40,63,82,41,41,32,42,32,62>>]}]},{p,[],[<<72,101,114,101,32,40,63,40,82,41,32,105,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,44,32,119,105,116,104,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,97,108,116,101,114,110,97,116,105,118,101,115,32,102,111,114,32,116,104,101,32,114,101,99,117,114,115,105,118,101,32,97,110,100,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,99,97,115,101,115,46,32,73,116,101,109,32,40,63,82,41,32,105,115,32,116,104,101,32,97,99,116,117,97,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,46>>]},{p,[],[{em,[],[<<68,105,102,102,101,114,101,110,99,101,115,32,105,110,32,82,101,99,117,114,115,105,111,110,32,80,114,111,99,101,115,115,105,110,103,32,98,101,116,119,101,101,110,32,80,67,82,69,32,97,110,100,32,80,101,114,108>>]}]},{p,[],[<<82,101,99,117,114,115,105,111,110,32,112,114,111,99,101,115,115,105,110,103,32,105,110,32,80,67,82,69,32,100,105,102,102,101,114,115,32,102,114,111,109,32,80,101,114,108,32,105,110,32,116,119,111,32,105,109,112,111,114,116,97,110,116,32,119,97,121,115,46,32,73,110,32,80,67,82,69,32,40,108,105,107,101,32,80,121,116,104,111,110,44,32,98,117,116,32,117,110,108,105,107,101,32,80,101,114,108,41,44,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,32,105,115,32,97,108,119,97,121,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,84,104,97,116,32,105,115,44,32,111,110,99,101,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,32,115,111,109,101,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,105,115,32,110,101,118,101,114,32,114,101,45,101,110,116,101,114,101,100,44,32,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,117,110,116,114,105,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,116,104,101,114,101,32,105,115,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,105,108,108,117,115,116,114,97,116,101,100,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,111,32,109,97,116,99,104,32,97,32,112,97,108,105,110,100,114,111,109,105,99,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,97,110,32,111,100,100,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,34,97,34,44,32,34,97,98,97,34,44,32,34,97,98,99,98,97,34,44,32,34,97,98,99,100,99,98,97,34,41,58>>]},{pre,[],[{code,[],[<<94,40,46,124,40,46,41,40,63,49,41,92,50,41,36>>]}]},{p,[],[<<84,104,101,32,105,100,101,97,32,105,115,32,116,104,97,116,32,105,116,32,101,105,116,104,101,114,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,116,119,111,32,105,100,101,110,116,105,99,97,108,32,99,104,97,114,97,99,116,101,114,115,32,115,117,114,114,111,117,110,100,105,110,103,32,97,32,115,117,98,112,97,108,105,110,100,114,111,109,101,46,32,73,110,32,80,101,114,108,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,119,111,114,107,115,59,32,105,110,32,80,67,82,69,32,105,116,32,100,111,101,115,32,110,111,116,32,119,111,114,107,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,34,97,98,99,98,97,34,46>>]},{p,[],[<<65,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,115,32,109,97,116,99,104,101,100,44,32,98,117,116,32,97,115,32,105,116,32,105,115,32,110,111,116,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,116,104,101,32,102,105,114,115,116,32,97,108,116,101,114,110,97,116,105,118,101,32,102,97,105,108,115,44,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,116,97,107,101,110,44,32,97,110,100,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,107,105,99,107,115,32,105,110,46,32,84,104,101,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,116,111,32,115,117,98,112,97,116,116,101,114,110,32,49,32,115,117,99,99,101,115,115,102,117,108,108,121,32,109,97,116,99,104,101,115,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,34,98,34,41,46,32,40,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,97,110,100,32,101,110,100,32,111,102,32,108,105,110,101,32,116,101,115,116,115,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,41>>]},{p,[],[<<66,97,99,107,32,97,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,34,99,34,41,32,105,115,32,99,111,109,112,97,114,101,100,32,119,105,116,104,32,119,104,97,116,32,115,117,98,112,97,116,116,101,114,110,32,50,32,109,97,116,99,104,101,100,44,32,119,104,105,99,104,32,119,97,115,32,34,97,34,46,32,84,104,105,115,32,102,97,105,108,115,46,32,65,115,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,116,104,101,114,101,32,97,114,101,32,110,111,119,32,110,111,32,98,97,99,107,116,114,97,99,107,105,110,103,32,112,111,105,110,116,115,44,32,97,110,100,32,115,111,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46,32,40,80,101,114,108,32,99,97,110,32,110,111,119,32,114,101,45,101,110,116,101,114,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,97,110,100,32,116,114,121,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,46,41,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,119,114,105,116,116,101,110,32,119,105,116,104,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,105,110,32,116,104,101,32,111,116,104,101,114,32,111,114,100,101,114,44,32,116,104,105,110,103,115,32,97,114,101,32,100,105,102,102,101,114,101,110,116,58>>]},{pre,[],[{code,[],[<<94,40,40,46,41,40,63,49,41,92,50,124,46,41,36>>]}]},{p,[],[<<84,104,105,115,32,116,105,109,101,44,32,116,104,101,32,114,101,99,117,114,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,116,114,105,101,100,32,102,105,114,115,116,44,32,97,110,100,32,99,111,110,116,105,110,117,101,115,32,116,111,32,114,101,99,117,114,115,101,32,117,110,116,105,108,32,105,116,32,114,117,110,115,32,111,117,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,97,116,32,119,104,105,99,104,32,112,111,105,110,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,102,97,105,108,115,46,32,66,117,116,32,116,104,105,115,32,116,105,109,101,32,119,101,32,104,97,118,101,32,97,110,111,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,116,111,32,116,114,121,32,97,116,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,46,32,84,104,97,116,32,105,115,32,116,104,101,32,115,105,103,110,105,102,105,99,97,110,116,32,100,105,102,102,101,114,101,110,99,101,58,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,97,115,101,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,97,116,32,97,32,100,101,101,112,101,114,32,114,101,99,117,114,115,105,111,110,32,108,101,118,101,108,44,32,119,104,105,99,104,32,80,67,82,69,32,99,97,110,110,111,116,32,117,115,101,46>>]},{p,[],[<<84,111,32,99,104,97,110,103,101,32,116,104,101,32,112,97,116,116,101,114,110,32,115,111,32,116,104,97,116,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,112,97,108,105,110,100,114,111,109,105,99,32,115,116,114,105,110,103,115,44,32,110,111,116,32,111,110,108,121,32,116,104,111,115,101,32,119,105,116,104,32,97,110,32,111,100,100,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,105,116,32,105,115,32,116,101,109,112,116,105,110,103,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<94,40,40,46,41,40,63,49,41,92,50,124,46,63,41,36>>]}]},{p,[],[<<65,103,97,105,110,44,32,116,104,105,115,32,119,111,114,107,115,32,105,110,32,80,101,114,108,44,32,98,117,116,32,110,111,116,32,105,110,32,80,67,82,69,44,32,97,110,100,32,102,111,114,32,116,104,101,32,115,97,109,101,32,114,101,97,115,111,110,46,32,87,104,101,110,32,97,32,100,101,101,112,101,114,32,114,101,99,117,114,115,105,111,110,32,104,97,115,32,109,97,116,99,104,101,100,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,101,110,116,101,114,101,100,32,97,103,97,105,110,32,116,111,32,109,97,116,99,104,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,46,32,84,104,101,32,115,111,108,117,116,105,111,110,32,105,115,32,116,111,32,115,101,112,97,114,97,116,101,32,116,104,101,32,116,119,111,32,99,97,115,101,115,44,32,97,110,100,32,119,114,105,116,101,32,111,117,116,32,116,104,101,32,111,100,100,32,97,110,100,32,101,118,101,110,32,99,97,115,101,115,32,97,115,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,116,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,58>>]},{pre,[],[{code,[],[<<94,40,63,58,40,40,46,41,40,63,49,41,92,50,124,41,124,40,40,46,41,40,63,51,41,92,52,124,46,41,41>>]}]},{p,[],[<<73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,116,121,112,105,99,97,108,32,112,97,108,105,110,100,114,111,109,105,99,32,112,104,114,97,115,101,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,105,103,110,111,114,101,32,97,108,108,32,110,111,110,45,119,111,114,100,32,99,104,97,114,97,99,116,101,114,115,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,100,111,110,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{pre,[],[{code,[],[<<94,92,87,42,43,40,63,58,40,40,46,41,92,87,42,43,40,63,49,41,92,87,42,43,92,50,124,41,124,40,40,46,41,92,87,42,43,40,63,51,41,92,87,42,43,92,52,124,92,87,42,43,46,92,87,42,43,41,41,92,87,42,43,36>>]}]},{p,[],[<<73,102,32,114,117,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,112,104,114,97,115,101,115,32,115,117,99,104,32,97,115,32,34,65,32,109,97,110,44,32,97,32,112,108,97,110,44,32,97,32,99,97,110,97,108,58,32,80,97,110,97,109,97,33,34,32,97,110,100,32,105,116,32,119,111,114,107,115,32,119,101,108,108,32,105,110,32,98,111,116,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,46,32,78,111,116,105,99,101,32,116,104,101,32,117,115,101,32,111,102,32,116,104,101,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,42,43,32,116,111,32,97,118,111,105,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,119,111,114,100,32,99,104,97,114,97,99,116,101,114,115,46,32,87,105,116,104,111,117,116,32,116,104,105,115,44,32,80,67,82,69,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,40,49,48,32,116,105,109,101,115,32,111,114,32,109,111,114,101,41,32,116,111,32,109,97,116,99,104,32,116,121,112,105,99,97,108,32,112,104,114,97,115,101,115,44,32,97,110,100,32,80,101,114,108,32,116,97,107,101,115,32,115,111,32,108,111,110,103,32,116,104,97,116,32,121,111,117,32,116,104,105,110,107,32,105,116,32,104,97,115,32,103,111,110,101,32,105,110,116,111,32,97,32,108,111,111,112,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,112,97,108,105,110,100,114,111,109,101,45,109,97,116,99,104,105,110,103,32,112,97,116,116,101,114,110,115,32,97,98,111,118,101,32,119,111,114,107,32,111,110,108,121,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,100,111,101,115,32,110,111,116,32,115,116,97,114,116,32,119,105,116,104,32,97,32,112,97,108,105,110,100,114,111,109,101,32,116,104,97,116,32,105,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,108,116,104,111,117,103,104,32,34,97,98,99,98,97,34,32,105,115,32,99,111,114,114,101,99,116,108,121,32,109,97,116,99,104,101,100,44,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,98,97,98,97,34,44,32,80,67,82,69,32,102,105,110,100,115,32,112,97,108,105,110,100,114,111,109,101,32,34,97,98,97,34,32,97,116,32,116,104,101,32,115,116,97,114,116,44,32,97,110,100,32,116,104,101,110,32,102,97,105,108,115,32,97,116,32,116,111,112,32,108,101,118,101,108,44,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,100,111,101,115,32,110,111,116,32,102,111,108,108,111,119,46,32,79,110,99,101,32,97,103,97,105,110,44,32,105,116,32,99,97,110,110,111,116,32,106,117,109,112,32,98,97,99,107,32,105,110,116,111,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,116,111,32,116,114,121,32,111,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,115,111,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46>>]}]},{p,[],[<<84,104,101,32,115,101,99,111,110,100,32,119,97,121,32,105,110,32,119,104,105,99,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,100,105,102,102,101,114,32,105,110,32,116,104,101,105,114,32,114,101,99,117,114,115,105,111,110,32,112,114,111,99,101,115,115,105,110,103,32,105,115,32,105,110,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,115,46,32,73,110,32,80,101,114,108,44,32,119,104,101,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,99,97,108,108,101,100,32,114,101,99,117,114,115,105,118,101,108,121,32,111,114,32,97,115,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,115,101,101,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,44,32,105,116,32,104,97,115,32,110,111,32,97,99,99,101,115,115,32,116,111,32,97,110,121,32,118,97,108,117,101,115,32,116,104,97,116,32,119,101,114,101,32,99,97,112,116,117,114,101,100,32,111,117,116,115,105,100,101,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,32,73,110,32,80,67,82,69,32,116,104,101,115,101,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<94,40,46,41,40,92,49,124,97,40,63,50,41,41>>]}]},{p,[],[<<73,110,32,80,67,82,69,44,32,105,116,32,109,97,116,99,104,101,115,32,34,98,97,98,34,46,32,84,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,110,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,103,114,111,117,112,44,32,119,104,101,110,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,92,49,32,102,97,105,108,115,32,116,111,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,109,97,116,99,104,101,115,32,34,97,34,44,32,97,110,100,32,116,104,101,110,32,114,101,99,117,114,115,101,115,46,32,73,110,32,116,104,101,32,114,101,99,117,114,115,105,111,110,44,32,92,49,32,100,111,101,115,32,110,111,119,32,109,97,116,99,104,32,34,98,34,32,97,110,100,32,115,111,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,32,115,117,99,99,101,101,100,115,46,32,73,110,32,80,101,114,108,44,32,116,104,101,32,112,97,116,116,101,114,110,32,102,97,105,108,115,32,116,111,32,109,97,116,99,104,32,98,101,99,97,117,115,101,32,105,110,115,105,100,101,32,116,104,101,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,92,49,32,99,97,110,110,111,116,32,97,99,99,101,115,115,32,116,104,101,32,101,120,116,101,114,110,97,108,108,121,32,115,101,116,32,118,97,108,117,101,46>>]},{a,[{id,<<115,101,99,116,50,49>>}],[]},{h2,[],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]},{p,[],[<<73,102,32,116,104,101,32,115,121,110,116,97,120,32,102,111,114,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,32,40,101,105,116,104,101,114,32,98,121,32,110,117,109,98,101,114,32,111,114,32,98,121,32,110,97,109,101,41,32,105,115,32,117,115,101,100,32,111,117,116,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,119,104,105,99,104,32,105,116,32,114,101,102,101,114,115,44,32,105,116,32,111,112,101,114,97,116,101,115,32,108,105,107,101,32,97,32,115,117,98,114,111,117,116,105,110,101,32,105,110,32,97,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,46,32,84,104,101,32,99,97,108,108,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,32,98,101,102,111,114,101,32,111,114,32,97,102,116,101,114,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,117,109,98,101,114,101,100,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,97,98,115,111,108,117,116,101,32,111,114,32,114,101,108,97,116,105,118,101,44,32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<40,46,46,46,40,97,98,115,111,108,117,116,101,41,46,46,46,41,46,46,46,40,63,50,41,46,46,46,10,40,46,46,46,40,114,101,108,97,116,105,118,101,41,46,46,46,41,46,46,46,40,63,45,49,41,46,46,46,10,40,46,46,46,40,63,43,49,41,46,46,46,40,114,101,108,97,116,105,118,101,41,46,46,46>>]}]},{p,[],[<<65,110,32,101,97,114,108,105,101,114,32,101,120,97,109,112,108,101,32,112,111,105,110,116,101,100,32,111,117,116,32,116,104,97,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,115,101,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,34,114,101,115,112,111,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,44,32,98,117,116,32,110,111,116,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,49,105,98,105,108,105,116,121>>]}]},{p,[],[<<73,102,32,105,110,115,116,101,97,100,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,105,115,32,117,115,101,100,44,32,105,116,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,116,119,111,32,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,40,63,49,41,105,98,105,108,105,116,121>>]}]},{p,[],[<<65,110,111,116,104,101,114,32,101,120,97,109,112,108,101,32,105,115,32,112,114,111,118,105,100,101,100,32,105,110,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,68,69,70,73,78,69,32,101,97,114,108,105,101,114,46>>]},{p,[],[<<65,108,108,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,44,32,114,101,99,117,114,115,105,118,101,32,111,114,32,110,111,116,44,32,97,114,101,32,97,108,119,97,121,115,32,116,114,101,97,116,101,100,32,97,115,32,97,116,111,109,105,99,32,103,114,111,117,112,115,46,32,84,104,97,116,32,105,115,44,32,111,110,99,101,32,97,32,115,117,98,114,111,117,116,105,110,101,32,104,97,115,32,109,97,116,99,104,101,100,32,115,111,109,101,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,105,115,32,110,101,118,101,114,32,114,101,45,101,110,116,101,114,101,100,44,32,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,117,110,116,114,105,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,116,104,101,114,101,32,105,115,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,46,32,65,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,115,101,116,32,100,117,114,105,110,103,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,114,101,118,101,114,116,32,116,111,32,116,104,101,105,114,32,112,114,101,118,105,111,117,115,32,118,97,108,117,101,115,32,97,102,116,101,114,119,97,114,100,115,46>>]},{p,[],[<<80,114,111,99,101,115,115,105,110,103,32,111,112,116,105,111,110,115,32,115,117,99,104,32,97,115,32,99,97,115,101,45,105,110,100,101,112,101,110,100,101,110,99,101,32,97,114,101,32,102,105,120,101,100,32,119,104,101,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,100,101,102,105,110,101,100,44,32,115,111,32,105,102,32,105,116,32,105,115,32,117,115,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,115,117,99,104,32,111,112,116,105,111,110,115,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,102,111,114,32,100,105,102,102,101,114,101,110,116,32,99,97,108,108,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,98,117,116,32,110,111,116,32,34,97,98,99,65,66,67,34,44,32,97,115,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32,112,114,111,99,101,115,115,105,110,103,32,111,112,116,105,111,110,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,99,97,108,108,101,100,32,115,117,98,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,97,98,99,41,40,63,105,58,40,63,45,49,41,41>>]}]},{a,[{id,<<115,101,99,116,50,50>>}],[]},{h2,[],[<<79,110,105,103,117,114,117,109,97,32,83,117,98,114,111,117,116,105,110,101,32,83,121,110,116,97,120>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,79,110,105,103,117,114,117,109,97,44,32,116,104,101,32,110,111,110,45,80,101,114,108,32,115,121,110,116,97,120,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,32,111,114,32,97,32,110,117,109,98,101,114,32,101,110,99,108,111,115,101,100,32,101,105,116,104,101,114,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,32,111,114,32,115,105,110,103,108,101,32,113,117,111,116,101,115,44,32,105,115,32,97,108,116,101,114,110,97,116,105,118,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,102,101,114,101,110,99,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,112,111,115,115,105,98,108,121,32,114,101,99,117,114,115,105,118,101,108,121,46,32,72,101,114,101,32,102,111,108,108,111,119,115,32,116,119,111,32,111,102,32,116,104,101,32,101,120,97,109,112,108,101,115,32,117,115,101,100,32,97,98,111,118,101,44,32,114,101,119,114,105,116,116,101,110,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,58>>]},{pre,[],[{code,[],[<<40,63,60,112,110,62,32,92,40,32,40,32,40,63,62,91,94,40,41,93,43,41,32,124,32,92,103,60,112,110,62,32,41,42,32,92,41,32,41,10,40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,103,39,49,39,105,98,105,108,105,116,121>>]}]},{p,[],[<<80,67,82,69,32,115,117,112,112,111,114,116,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,116,111,32,79,110,105,103,117,114,117,109,97,58,32,105,102,32,97,32,110,117,109,98,101,114,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,97,32,112,108,117,115,32,111,114,32,109,105,110,117,115,32,115,105,103,110,44,32,105,116,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,41,40,63,105,58,92,103,60,45,49,62,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,92,103,123,46,46,46,125,32,40,80,101,114,108,32,115,121,110,116,97,120,41,32,97,110,100,32,92,103,60,46,46,46,62,32,40,79,110,105,103,117,114,117,109,97,32,115,121,110,116,97,120,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,115,121,110,111,110,121,109,111,117,115,46,32,84,104,101,32,102,111,114,109,101,114,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,59,32,116,104,101,32,108,97,116,116,101,114,32,105,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]},{a,[{id,<<115,101,99,116,50,51>>}],[]},{h2,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108>>]},{p,[],[<<80,101,114,108,32,53,46,49,48,32,105,110,116,114,111,100,117,99,101,100,32,115,111,109,101,32,34,83,112,101,99,105,97,108,32,66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108,32,86,101,114,98,115,34,44,32,119,104,105,99,104,32,97,114,101,32,115,116,105,108,108,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,97,115,32,34,101,120,112,101,114,105,109,101,110,116,97,108,32,97,110,100,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,111,114,32,114,101,109,111,118,97,108,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,80,101,114,108,34,46,32,73,116,32,103,111,101,115,32,111,110,32,116,111,32,115,97,121,58,32,34,84,104,101,105,114,32,117,115,97,103,101,32,105,110,32,112,114,111,100,117,99,116,105,111,110,32,99,111,100,101,32,115,104,111,117,108,100,32,98,101,32,110,111,116,101,100,32,116,111,32,97,118,111,105,100,32,112,114,111,98,108,101,109,115,32,100,117,114,105,110,103,32,117,112,103,114,97,100,101,115,46,34,32,84,104,101,32,115,97,109,101,32,114,101,109,97,114,107,115,32,97,112,112,108,121,32,116,111,32,116,104,101,32,80,67,82,69,32,102,101,97,116,117,114,101,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,105,115,32,115,101,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,110,101,119,32,118,101,114,98,115,32,109,97,107,101,32,117,115,101,32,111,102,32,119,104,97,116,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,105,110,118,97,108,105,100,32,115,121,110,116,97,120,58,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,97,115,116,101,114,105,115,107,46,32,84,104,101,121,32,97,114,101,32,103,101,110,101,114,97,108,108,121,32,111,102,32,116,104,101,32,102,111,114,109,32,40,42,86,69,82,66,41,32,111,114,32,40,42,86,69,82,66,58,78,65,77,69,41,46,32,83,111,109,101,32,99,97,110,32,116,97,107,101,32,101,105,116,104,101,114,32,102,111,114,109,44,32,112,111,115,115,105,98,108,121,32,98,101,104,97,118,105,110,103,32,100,105,102,102,101,114,101,110,116,108,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,119,104,101,116,104,101,114,32,97,32,110,97,109,101,32,105,115,32,112,114,101,115,101,110,116,46,32,65,32,110,97,109,101,32,105,115,32,97,110,121,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,84,104,101,32,109,97,120,105,109,117,109,32,110,97,109,101,32,108,101,110,103,116,104,32,105,115,32,50,53,53,32,105,110,32,116,104,101,32,56,45,98,105,116,32,108,105,98,114,97,114,121,32,97,110,100,32,54,53,53,51,53,32,105,110,32,116,104,101,32,49,54,45,98,105,116,32,97,110,100,32,51,50,45,98,105,116,32,108,105,98,114,97,114,105,101,115,46,32,73,102,32,116,104,101,32,110,97,109,101,32,105,115,32,101,109,112,116,121,44,32,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,115,32,116,104,101,32,99,111,108,111,110,44,32,116,104,101,32,101,102,102,101,99,116,32,105,115,32,97,115,32,105,102,32,116,104,101,32,99,111,108,111,110,32,119,97,115,32,110,111,116,32,116,104,101,114,101,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,99,97,110,32,111,99,99,117,114,32,105,110,32,97,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,105,110,32,114,101,112,101,97,116,101,100,32,103,114,111,117,112,115,44,32,97,115,115,101,114,116,105,111,110,115,44,32,97,110,100,32,105,110,32,115,117,98,112,97,116,116,101,114,110,115,32,99,97,108,108,101,100,32,97,115,32,115,117,98,114,111,117,116,105,110,101,115,32,40,119,104,101,116,104,101,114,32,111,114,32,110,111,116,32,114,101,99,117,114,115,105,118,101,108,121,41,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]},{p,[],[{em,[],[<<79,112,116,105,109,105,122,97,116,105,111,110,115,32,84,104,97,116,32,65,102,102,101,99,116,32,66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115>>]}]},{p,[],[<<80,67,82,69,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,116,104,97,116,32,97,114,101,32,117,115,101,100,32,116,111,32,115,112,101,101,100,32,117,112,32,109,97,116,99,104,105,110,103,32,98,121,32,114,117,110,110,105,110,103,32,115,111,109,101,32,99,104,101,99,107,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,109,97,116,99,104,32,97,116,116,101,109,112,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,99,97,110,32,107,110,111,119,32,116,104,101,32,109,105,110,105,109,117,109,32,108,101,110,103,116,104,32,111,102,32,109,97,116,99,104,105,110,103,32,115,117,98,106,101,99,116,44,32,111,114,32,116,104,97,116,32,97,32,112,97,114,116,105,99,117,108,97,114,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,98,101,32,112,114,101,115,101,110,116,46,32,87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,98,121,112,97,115,115,101,115,32,116,104,101,32,114,117,110,110,105,110,103,32,111,102,32,97,32,109,97,116,99,104,44,32,97,110,121,32,105,110,99,108,117,100,101,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,114,101,32,110,111,116,32,112,114,111,99,101,115,115,101,100,46,32,112,114,111,99,101,115,115,101,100,46,32,89,111,117,32,99,97,110,32,115,117,112,112,114,101,115,115,32,116,104,101,32,115,116,97,114,116,45,111,102,45,109,97,116,99,104,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,111,114,32,98,121,32,115,116,97,114,116,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,40,42,78,79,95,83,84,65,82,84,95,79,80,84,41,46>>]},{p,[],[<<69,120,112,101,114,105,109,101,110,116,115,32,119,105,116,104,32,80,101,114,108,32,115,117,103,103,101,115,116,32,116,104,97,116,32,105,116,32,116,111,111,32,104,97,115,32,115,105,109,105,108,97,114,32,111,112,116,105,109,105,122,97,116,105,111,110,115,44,32,115,111,109,101,116,105,109,101,115,32,108,101,97,100,105,110,103,32,116,111,32,97,110,111,109,97,108,111,117,115,32,114,101,115,117,108,116,115,46>>]},{p,[],[{em,[],[<<86,101,114,98,115,32,84,104,97,116,32,65,99,116,32,73,109,109,101,100,105,97,116,101,108,121>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,115,32,97,99,116,32,97,115,32,115,111,111,110,32,97,115,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46,32,84,104,101,121,32,109,117,115,116,32,110,111,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,46>>]},{pre,[],[{code,[],[<<40,42,65,67,67,69,80,84,41>>]}]},{p,[],[<<84,104,105,115,32,118,101,114,98,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,101,110,100,32,115,117,99,99,101,115,115,102,117,108,108,121,44,32,115,107,105,112,112,105,110,103,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,105,116,32,105,115,32,105,110,115,105,100,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,111,110,108,121,32,116,104,97,116,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,101,110,100,101,100,32,115,117,99,99,101,115,115,102,117,108,108,121,46,32,77,97,116,99,104,105,110,103,32,116,104,101,110,32,99,111,110,116,105,110,117,101,115,32,97,116,32,116,104,101,32,111,117,116,101,114,32,108,101,118,101,108,46,32,73,102,32,40,42,65,67,67,69,80,84,41,32,105,115,32,116,114,105,103,103,101,114,101,100,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,115,117,99,99,101,101,100,115,59,32,105,110,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,102,97,105,108,115,46>>]},{p,[],[<<73,102,32,40,42,65,67,67,69,80,84,41,32,105,115,32,105,110,115,105,100,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,44,32,116,104,101,32,100,97,116,97,32,115,111,32,102,97,114,32,105,115,32,99,97,112,116,117,114,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,65,66,34,44,32,34,65,65,68,34,44,32,111,114,32,34,65,67,68,34,46,32,87,104,101,110,32,105,116,32,109,97,116,99,104,101,115,32,34,65,66,34,44,32,34,66,34,32,105,115,32,99,97,112,116,117,114,101,100,32,98,121,32,116,104,101,32,111,117,116,101,114,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{pre,[],[{code,[],[<<65,40,40,63,58,65,124,66,40,42,65,67,67,69,80,84,41,124,67,41,68,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,44,32,102,111,114,99,105,110,103,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,111,99,99,117,114,46,32,73,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,40,63,33,41,32,98,117,116,32,101,97,115,105,101,114,32,116,111,32,114,101,97,100,46>>]},{pre,[],[{code,[],[<<40,42,70,65,73,76,41,32,111,114,32,40,42,70,41>>]}]},{p,[],[<<84,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,115,116,97,116,101,115,32,116,104,97,116,32,105,116,32,105,115,32,112,114,111,98,97,98,108,121,32,117,115,101,102,117,108,32,111,110,108,121,32,119,104,101,110,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,40,63,123,125,41,32,111,114,32,40,63,63,123,125,41,46,32,84,104,111,115,101,32,97,114,101,32,80,101,114,108,32,102,101,97,116,117,114,101,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,80,67,82,69,46>>]},{p,[],[<<65,32,109,97,116,99,104,32,119,105,116,104,32,116,104,101,32,115,116,114,105,110,103,32,34,97,97,97,97,34,32,97,108,119,97,121,115,32,102,97,105,108,115,44,32,98,117,116,32,116,104,101,32,99,97,108,108,111,117,116,32,105,115,32,116,97,107,101,110,32,98,101,102,111,114,101,32,101,97,99,104,32,98,97,99,107,116,114,97,99,107,32,111,99,99,117,114,115,32,40,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,44,32,49,48,32,116,105,109,101,115,41,46>>]},{p,[],[{em,[],[<<82,101,99,111,114,100,105,110,103,32,87,104,105,99,104,32,80,97,116,104,32,87,97,115,32,84,97,107,101,110>>]}]},{p,[],[<<84,104,101,32,109,97,105,110,32,112,117,114,112,111,115,101,32,111,102,32,116,104,105,115,32,118,101,114,98,32,105,115,32,116,111,32,116,114,97,99,107,32,104,111,119,32,97,32,109,97,116,99,104,32,119,97,115,32,97,114,114,105,118,101,100,32,97,116,44,32,97,108,116,104,111,117,103,104,32,105,116,32,97,108,115,111,32,104,97,115,32,97,32,115,101,99,111,110,100,97,114,121,32,117,115,101,32,105,110,32,119,105,116,104,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,109,97,116,99,104,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,40,115,101,101,32,40,42,83,75,73,80,41,32,98,101,108,111,119,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,69,114,108,97,110,103,44,32,116,104,101,114,101,32,105,115,32,110,111,32,105,110,116,101,114,102,97,99,101,32,116,111,32,114,101,116,114,105,101,118,101,32,97,32,109,97,114,107,32,119,105,116,104,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50,44,51>>]}]},<<44,32,115,111,32,111,110,108,121,32,116,104,101,32,115,101,99,111,110,100,97,114,121,32,112,117,114,112,111,115,101,32,105,115,32,114,101,108,101,118,97,110,116,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,46>>]},{p,[],[<<84,104,101,32,114,101,115,116,32,111,102,32,116,104,105,115,32,115,101,99,116,105,111,110,32,105,115,32,116,104,101,114,101,102,111,114,101,32,100,101,108,105,98,101,114,97,116,101,108,121,32,110,111,116,32,97,100,97,112,116,101,100,32,102,111,114,32,114,101,97,100,105,110,103,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,98,117,116,32,116,104,101,32,101,120,97,109,112,108,101,115,32,99,97,110,32,104,101,108,112,32,105,110,32,117,110,100,101,114,115,116,97,110,100,105,110,103,32,78,65,77,69,83,32,97,115,32,116,104,101,121,32,99,97,110,32,98,101,32,117,115,101,100,32,98,121,32,40,42,83,75,73,80,41,46>>]}]},{pre,[],[{code,[],[<<40,42,77,65,82,75,58,78,65,77,69,41,32,111,114,32,40,42,58,78,65,77,69,41>>]}]},{p,[],[<<65,32,110,97,109,101,32,105,115,32,97,108,119,97,121,115,32,114,101,113,117,105,114,101,100,32,119,105,116,104,32,116,104,105,115,32,118,101,114,98,46,32,84,104,101,114,101,32,99,97,110,32,98,101,32,97,115,32,109,97,110,121,32,105,110,115,116,97,110,99,101,115,32,111,102,32,40,42,77,65,82,75,41,32,97,115,32,121,111,117,32,108,105,107,101,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,110,100,32,116,104,101,105,114,32,110,97,109,101,115,32,100,111,32,110,111,116,32,104,97,118,101,32,116,111,32,98,101,32,117,110,105,113,117,101,46>>]},{p,[],[<<87,104,101,110,32,97,32,109,97,116,99,104,32,115,117,99,99,101,101,100,115,44,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,32,40,42,77,65,82,75,58,78,65,77,69,41,44,32,40,42,80,82,85,78,69,58,78,65,77,69,41,44,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41,32,111,110,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,116,104,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32,34,69,120,116,114,97,32,100,97,116,97,32,102,111,114,32>>,{code,[],[<<112,99,114,101,95,101,120,101,99,40,41>>]},<<34,32,105,110,32,116,104,101,32>>,{code,[],[<<112,99,114,101,97,112,105>>]},<<32,100,111,99,117,109,101,110,116,97,116,105,111,110,46,32,73,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,111,102,32>>,{code,[],[<<112,99,114,101,116,101,115,116>>]},<<32,111,117,116,112,117,116,44,32,116,104,101,32,47,75,32,109,111,100,105,102,105,101,114,32,114,101,113,117,101,115,116,115,32,116,104,101,32,114,101,116,114,105,101,118,97,108,32,97,110,100,32,111,117,116,112,117,116,116,105,110,103,32,111,102,32,40,42,77,65,82,75,41,32,100,97,116,97,58>>]},{pre,[],[{code,[],[<<32,32,114,101,62,32,47,88,40,42,77,65,82,75,58,65,41,89,124,88,40,42,77,65,82,75,58,66,41,90,47,75,10,100,97,116,97,62,32,88,89,10,32,48,58,32,88,89,10,77,75,58,32,65,10,88,90,10,32,48,58,32,88,90,10,77,75,58,32,66>>]}]},{p,[],[<<84,104,101,32,40,42,77,65,82,75,41,32,110,97,109,101,32,105,115,32,116,97,103,103,101,100,32,119,105,116,104,32,34,77,75,58,34,32,105,110,32,116,104,105,115,32,111,117,116,112,117,116,44,32,97,110,100,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,105,116,32,105,110,100,105,99,97,116,101,115,32,119,104,105,99,104,32,111,102,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,109,97,116,99,104,101,100,46,32,84,104,105,115,32,105,115,32,97,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,119,97,121,32,111,102,32,111,98,116,97,105,110,105,110,103,32,116,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,116,104,97,110,32,112,117,116,116,105,110,103,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,105,116,115,32,111,119,110,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,97,32,118,101,114,98,32,119,105,116,104,32,97,32,110,97,109,101,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,44,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,99,111,114,100,101,100,32,97,110,100,32,112,97,115,115,101,100,32,98,97,99,107,32,105,102,32,105,116,32,105,115,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,46,32,84,104,105,115,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,111,114,32,102,97,105,108,105,110,103,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46>>]},{p,[],[<<65,102,116,101,114,32,97,32,112,97,114,116,105,97,108,32,109,97,116,99,104,32,111,114,32,97,32,102,97,105,108,101,100,32,109,97,116,99,104,44,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,32,110,97,109,101,32,105,110,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,112,114,111,99,101,115,115,32,105,115,32,114,101,116,117,114,110,101,100,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<32,32,114,101,62,32,47,88,40,42,77,65,82,75,58,65,41,89,124,88,40,42,77,65,82,75,58,66,41,90,47,75,10,100,97,116,97,62,32,88,80,10,78,111,32,109,97,116,99,104,44,32,109,97,114,107,32,61,32,66>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,110,32,116,104,105,115,32,117,110,97,110,99,104,111,114,101,100,32,101,120,97,109,112,108,101,44,32,116,104,101,32,109,97,114,107,32,105,115,32,114,101,116,97,105,110,101,100,32,102,114,111,109,32,116,104,101,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,116,104,97,116,32,115,116,97,114,116,101,100,32,97,116,32,108,101,116,116,101,114,32,34,88,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,83,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,115,32,115,116,97,114,116,105,110,103,32,97,116,32,34,80,34,32,97,110,100,32,116,104,101,110,32,119,105,116,104,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,100,111,32,110,111,116,32,103,101,116,32,97,115,32,102,97,114,32,97,115,32,116,104,101,32,40,42,77,65,82,75,41,32,105,116,101,109,44,32,110,101,118,101,114,116,104,101,108,101,115,115,32,100,111,32,110,111,116,32,114,101,115,101,116,32,105,116,46>>]},{p,[],[{em,[],[<<86,101,114,98,115,32,84,104,97,116,32,65,99,116,32,97,102,116,101,114,32,66,97,99,107,116,114,97,99,107,105,110,103>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,115,32,100,111,32,110,111,116,104,105,110,103,32,119,104,101,110,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46,32,77,97,116,99,104,105,110,103,32,99,111,110,116,105,110,117,101,115,32,119,105,116,104,32,119,104,97,116,32,102,111,108,108,111,119,115,44,32,98,117,116,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,44,32,99,97,117,115,105,110,103,32,97,32,98,97,99,107,116,114,97,99,107,32,116,111,32,116,104,101,32,118,101,114,98,44,32,97,32,102,97,105,108,117,114,101,32,105,115,32,102,111,114,99,101,100,46,32,84,104,97,116,32,105,115,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,110,111,116,32,112,97,115,115,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,118,101,114,98,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,97,112,112,101,97,114,115,32,105,110,115,105,100,101,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,44,32,105,116,115,32,101,102,102,101,99,116,32,105,115,32,99,111,110,102,105,110,101,100,32,116,111,32,116,104,97,116,32,103,114,111,117,112,44,32,97,115,32,111,110,99,101,32,116,104,101,32,103,114,111,117,112,32,104,97,115,32,98,101,101,110,32,109,97,116,99,104,101,100,44,32,116,104,101,114,101,32,105,115,32,110,101,118,101,114,32,97,110,121,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,105,116,46,32,73,110,32,116,104,105,115,32,115,105,116,117,97,116,105,111,110,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,32,34,106,117,109,112,32,98,97,99,107,34,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,97,115,115,101,114,116,105,111,110,46,32,40,82,101,109,101,109,98,101,114,32,97,108,115,111,44,32,97,115,32,115,116,97,116,101,100,32,97,98,111,118,101,44,32,116,104,97,116,32,116,104,105,115,32,108,111,99,97,108,105,122,97,116,105,111,110,32,97,108,115,111,32,97,112,112,108,105,101,115,32,105,110,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,46,41>>]},{p,[],[<<84,104,101,115,101,32,118,101,114,98,115,32,100,105,102,102,101,114,32,105,110,32,101,120,97,99,116,108,121,32,119,104,97,116,32,107,105,110,100,32,111,102,32,102,97,105,108,117,114,101,32,111,99,99,117,114,115,32,119,104,101,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,114,101,97,99,104,101,115,32,116,104,101,109,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,32,105,115,32,119,104,97,116,32,111,99,99,117,114,115,32,119,104,101,110,32,116,104,101,32,118,101,114,98,32,105,115,32,110,111,116,32,105,110,32,97,32,115,117,98,114,111,117,116,105,110,101,32,111,114,32,97,110,32,97,115,115,101,114,116,105,111,110,46,32,83,117,98,115,101,113,117,101,110,116,32,115,101,99,116,105,111,110,115,32,99,111,118,101,114,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,99,97,115,101,115,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,44,32,119,104,105,99,104,32,109,117,115,116,32,110,111,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,44,32,99,97,117,115,101,115,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,111,117,116,114,105,103,104,116,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,108,97,116,101,114,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,104,97,116,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,114,101,97,99,104,32,105,116,46,32,69,118,101,110,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,110,111,32,102,117,114,116,104,101,114,32,97,116,116,101,109,112,116,115,32,116,111,32,102,105,110,100,32,97,32,109,97,116,99,104,32,98,121,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,116,97,107,101,32,112,108,97,99,101,46>>]},{pre,[],[{code,[],[<<40,42,67,79,77,77,73,84,41>>]}]},{p,[],[<<73,102,32,40,42,67,79,77,77,73,84,41,32,105,115,32,116,104,101,32,111,110,108,121,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,116,104,97,116,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,44,32,111,110,99,101,32,105,116,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50,44,51>>]}]},<<32,105,115,32,99,111,109,109,105,116,116,101,100,32,116,111,32,102,105,110,100,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,44,32,111,114,32,110,111,116,32,97,116,32,97,108,108,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<97,43,40,42,67,79,77,77,73,84,41,98>>]}]},{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,34,120,120,97,97,98,34,32,98,117,116,32,110,111,116,32,34,97,97,99,97,97,98,34,46,32,73,116,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,97,32,107,105,110,100,32,111,102,32,100,121,110,97,109,105,99,32,97,110,99,104,111,114,44,32,111,114,32,34,73,39,118,101,32,115,116,97,114,116,101,100,44,32,115,111,32,73,32,109,117,115,116,32,102,105,110,105,115,104,34,46,32,84,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,112,97,115,115,101,100,32,40,42,77,65,82,75,41,32,105,110,32,116,104,101,32,112,97,116,104,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,119,104,101,110,32,40,42,67,79,77,77,73,84,41,32,102,111,114,99,101,115,32,97,32,109,97,116,99,104,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,101,120,105,115,116,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,32,100,105,102,102,101,114,101,110,116,32,111,110,101,32,116,104,97,116,32,102,111,108,108,111,119,115,32,40,42,67,79,77,77,73,84,41,32,99,97,110,32,98,101,32,116,114,105,103,103,101,114,101,100,32,102,105,114,115,116,44,32,115,111,32,109,101,114,101,108,121,32,112,97,115,115,105,110,103,32,40,42,67,79,77,77,73,84,41,32,100,117,114,105,110,103,32,97,32,109,97,116,99,104,32,100,111,101,115,32,110,111,116,32,97,108,119,97,121,115,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,97,32,109,97,116,99,104,32,109,117,115,116,32,98,101,32,97,116,32,116,104,105,115,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,40,42,67,79,77,77,73,84,41,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,97,110,32,97,110,99,104,111,114,44,32,117,110,108,101,115,115,32,116,104,101,32,80,67,82,69,32,115,116,97,114,116,45,111,102,45,109,97,116,99,104,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,97,114,101,32,116,117,114,110,101,100,32,111,102,102,44,32,97,115,32,115,104,111,119,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,114,101,58,114,117,110,40,34,120,121,122,97,98,99,34,44,34,40,42,67,79,77,77,73,84,41,97,98,99,34,44,91,123,99,97,112,116,117,114,101,44,97,108,108,44,108,105,115,116,125,93,41,46,10,123,109,97,116,99,104,44,91,34,97,98,99,34,93,125,10,50,62,32,114,101,58,114,117,110,40,34,120,121,122,97,98,99,34,44,34,40,42,67,79,77,77,73,84,41,97,98,99,34,44,91,123,99,97,112,116,117,114,101,44,97,108,108,44,108,105,115,116,125,44,110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101,93,41,46,10,110,111,109,97,116,99,104>>]}]},{p,[],[<<70,111,114,32,116,104,105,115,32,112,97,116,116,101,114,110,44,32,80,67,82,69,32,107,110,111,119,115,32,116,104,97,116,32,97,110,121,32,109,97,116,99,104,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,34,97,34,44,32,115,111,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,115,107,105,112,115,32,97,108,111,110,103,32,116,104,101,32,115,117,98,106,101,99,116,32,116,111,32,34,97,34,32,98,101,102,111,114,101,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,102,105,114,115,116,32,115,101,116,32,111,102,32,100,97,116,97,46,32,84,104,101,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,116,104,101,110,32,115,117,99,99,101,101,100,115,46,32,73,110,32,116,104,101,32,115,101,99,111,110,100,32,99,97,108,108,32,116,104,101,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,100,105,115,97,98,108,101,115,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,115,107,105,112,115,32,97,108,111,110,103,32,116,111,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,110,111,119,32,97,112,112,108,105,101,100,32,115,116,97,114,116,105,110,103,32,97,116,32,34,120,34,44,32,97,110,100,32,115,111,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,119,105,116,104,111,117,116,32,116,114,121,105,110,103,32,97,110,121,32,111,116,104,101,114,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,115,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,108,97,116,101,114,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,104,97,116,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,114,101,97,99,104,32,105,116,58>>]},{pre,[],[{code,[],[<<40,42,80,82,85,78,69,41,32,111,114,32,40,42,80,82,85,78,69,58,78,65,77,69,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,116,104,101,32,110,111,114,109,97,108,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,115,116,97,114,116,105,110,103,32,99,104,97,114,97,99,116,101,114,32,116,104,101,110,32,111,99,99,117,114,115,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,32,111,99,99,117,114,32,97,115,32,117,115,117,97,108,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,40,42,80,82,85,78,69,41,44,32,98,101,102,111,114,101,32,105,116,32,105,115,32,114,101,97,99,104,101,100,44,32,111,114,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,116,111,32,116,104,101,32,114,105,103,104,116,32,111,102,32,40,42,80,82,85,78,69,41,44,32,98,117,116,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,109,97,116,99,104,32,116,111,32,116,104,101,32,114,105,103,104,116,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,110,111,116,32,99,114,111,115,115,32,40,42,80,82,85,78,69,41,46,32,73,110,32,115,105,109,112,108,101,32,99,97,115,101,115,44,32,116,104,101,32,117,115,101,32,111,102,32,40,42,80,82,85,78,69,41,32,105,115,32,106,117,115,116,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,116,111,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,44,32,98,117,116,32,116,104,101,114,101,32,97,114,101,32,115,111,109,101,32,117,115,101,115,32,111,102,32,40,42,80,82,85,78,69,41,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,101,120,112,114,101,115,115,101,100,32,105,110,32,97,110,121,32,111,116,104,101,114,32,119,97,121,46,32,73,110,32,97,110,32,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,44,32,40,42,80,82,85,78,69,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,40,42,67,79,77,77,73,84,41,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,105,115,32,116,104,101,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,40,42,77,65,82,75,58,78,65,77,69,41,40,42,80,82,85,78,69,41,46,32,73,116,32,105,115,32,108,105,107,101,32,40,42,77,65,82,75,58,78,65,77,69,41,32,105,110,32,116,104,97,116,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,109,101,109,98,101,114,101,100,32,102,111,114,32,112,97,115,115,105,110,103,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,46,32,72,111,119,101,118,101,114,44,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,119,105,116,104,32,40,42,77,65,82,75,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,114,101,109,101,109,98,101,114,115,32,116,104,101,32,110,97,109,101,32,105,115,32,117,115,101,108,101,115,115,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,97,115,32,110,97,109,101,115,32,99,97,110,110,111,116,32,98,101,32,114,101,116,114,105,101,118,101,100,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,44,32,119,104,101,110,32,115,112,101,99,105,102,105,101,100,32,119,105,116,104,111,117,116,32,97,32,110,97,109,101,44,32,105,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,116,104,101,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,105,115,32,110,111,116,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,44,32,98,117,116,32,116,111,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,119,104,101,114,101,32,40,42,83,75,73,80,41,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{pre,[],[{code,[],[<<40,42,83,75,73,80,41>>]}]},{p,[],[<<40,42,83,75,73,80,41,32,115,105,103,110,105,102,105,101,115,32,116,104,97,116,32,119,104,97,116,101,118,101,114,32,116,101,120,116,32,119,97,115,32,109,97,116,99,104,101,100,32,108,101,97,100,105,110,103,32,117,112,32,116,111,32,105,116,32,99,97,110,110,111,116,32,98,101,32,112,97,114,116,32,111,102,32,97,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,46,32,67,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<97,43,40,42,83,75,73,80,41,98>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,97,97,97,99,46,46,46,34,44,32,97,102,116,101,114,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,102,97,105,108,115,32,40,115,116,97,114,116,105,110,103,32,97,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,114,105,110,103,41,44,32,116,104,101,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,115,107,105,112,115,32,111,110,32,116,111,32,115,116,97,114,116,32,116,104,101,32,110,101,120,116,32,97,116,116,101,109,112,116,32,97,116,32,34,99,34,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,116,104,105,115,32,101,120,97,109,112,108,101,59,32,97,108,116,104,111,117,103,104,32,105,116,32,119,111,117,108,100,32,115,117,112,112,114,101,115,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,100,117,114,105,110,103,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,44,32,116,104,101,32,115,101,99,111,110,100,32,97,116,116,101,109,112,116,32,119,111,117,108,100,32,115,116,97,114,116,32,97,116,32,116,104,101,32,115,101,99,111,110,100,32,99,104,97,114,97,99,116,101,114,32,105,110,115,116,101,97,100,32,111,102,32,115,107,105,112,112,105,110,103,32,111,110,32,116,111,32,34,99,34,46>>]},{p,[],[<<87,104,101,110,32,40,42,83,75,73,80,41,32,104,97,115,32,97,110,32,97,115,115,111,99,105,97,116,101,100,32,110,97,109,101,44,32,105,116,115,32,98,101,104,97,118,105,111,114,32,105,115,32,109,111,100,105,102,105,101,100,58>>]},{pre,[],[{code,[],[<<40,42,83,75,73,80,58,78,65,77,69,41>>]}]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,105,115,32,116,114,105,103,103,101,114,101,100,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,112,97,116,104,32,116,104,114,111,117,103,104,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,101,97,114,99,104,101,100,32,102,111,114,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,40,42,77,65,82,75,41,32,116,104,97,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,110,97,109,101,46,32,73,102,32,111,110,101,32,105,115,32,102,111,117,110,100,44,32,116,104,101,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,105,115,32,116,111,32,116,104,101,32,115,117,98,106,101,99,116,32,112,111,115,105,116,105,111,110,32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,97,116,32,40,42,77,65,82,75,41,32,105,110,115,116,101,97,100,32,111,102,32,116,111,32,119,104,101,114,101,32,40,42,83,75,73,80,41,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,46,32,73,102,32,110,111,32,40,42,77,65,82,75,41,32,119,105,116,104,32,97,32,109,97,116,99,104,105,110,103,32,110,97,109,101,32,105,115,32,102,111,117,110,100,44,32,40,42,83,75,73,80,41,32,105,115,32,105,103,110,111,114,101,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,98,121,32,40,42,77,65,82,75,58,78,65,77,69,41,46,32,73,116,32,105,103,110,111,114,101,115,32,110,97,109,101,115,32,116,104,97,116,32,97,114,101,32,115,101,116,32,98,121,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,97,32,115,107,105,112,32,116,111,32,116,104,101,32,110,101,120,116,32,105,110,110,101,114,109,111,115,116,32,97,108,116,101,114,110,97,116,105,118,101,32,119,104,101,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,114,101,97,99,104,101,115,32,105,116,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,99,101,108,115,32,97,110,121,32,102,117,114,116,104,101,114,32,98,97,99,107,116,114,97,99,107,105,110,103,32,119,105,116,104,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,97,108,116,101,114,110,97,116,105,118,101,46>>]},{pre,[],[{code,[],[<<40,42,84,72,69,78,41,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41>>]}]},{p,[],[<<84,104,101,32,118,101,114,98,32,110,97,109,101,32,99,111,109,101,115,32,102,114,111,109,32,116,104,101,32,111,98,115,101,114,118,97,116,105,111,110,32,116,104,97,116,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,97,32,112,97,116,116,101,114,110,45,98,97,115,101,100,32,105,102,45,116,104,101,110,45,101,108,115,101,32,98,108,111,99,107,58>>]},{pre,[],[{code,[],[<<40,32,67,79,78,68,49,32,40,42,84,72,69,78,41,32,70,79,79,32,124,32,67,79,78,68,50,32,40,42,84,72,69,78,41,32,66,65,82,32,124,32,67,79,78,68,51,32,40,42,84,72,69,78,41,32,66,65,90,32,41,32,46,46,46>>]}]},{p,[],[<<73,102,32,116,104,101,32,67,79,78,68,49,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,70,79,79,32,105,115,32,116,114,105,101,100,32,40,97,110,100,32,112,111,115,115,105,98,108,121,32,102,117,114,116,104,101,114,32,105,116,101,109,115,32,97,102,116,101,114,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,103,114,111,117,112,32,105,102,32,70,79,79,32,115,117,99,99,101,101,100,115,41,46,32,79,110,32,102,97,105,108,117,114,101,44,32,116,104,101,32,109,97,116,99,104,101,114,32,115,107,105,112,115,32,116,111,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,97,110,100,32,116,114,105,101,115,32,67,79,78,68,50,44,32,119,105,116,104,111,117,116,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,67,79,78,68,49,46,32,73,102,32,116,104,97,116,32,115,117,99,99,101,101,100,115,32,97,110,100,32,66,65,82,32,102,97,105,108,115,44,32,67,79,78,68,51,32,105,115,32,116,114,105,101,100,46,32,73,102,32,66,65,90,32,116,104,101,110,32,102,97,105,108,115,44,32,116,104,101,114,101,32,97,114,101,32,110,111,32,109,111,114,101,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,115,111,32,116,104,101,114,101,32,105,115,32,97,32,98,97,99,107,116,114,97,99,107,32,116,111,32,119,104,97,116,101,118,101,114,32,99,97,109,101,32,98,101,102,111,114,101,32,116,104,101,32,101,110,116,105,114,101,32,103,114,111,117,112,46,32,73,102,32,40,42,84,72,69,78,41,32,105,115,32,110,111,116,32,105,110,115,105,100,101,32,97,110,32,97,108,116,101,114,110,97,116,105,111,110,44,32,105,116,32,97,99,116,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,40,42,84,72,69,78,58,78,65,77,69,41,32,105,115,32,116,104,101,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,40,42,77,65,82,75,58,78,65,77,69,41,40,42,84,72,69,78,41,46,32,73,116,32,105,115,32,108,105,107,101,32,40,42,77,65,82,75,58,78,65,77,69,41,32,105,110,32,116,104,97,116,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,109,101,109,98,101,114,101,100,32,102,111,114,32,112,97,115,115,105,110,103,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,46,32,72,111,119,101,118,101,114,44,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,119,105,116,104,32,40,42,77,65,82,75,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,42,84,72,69,78,58,78,65,77,69,41,32,114,101,109,101,109,98,101,114,115,32,116,104,101,32,110,97,109,101,32,105,115,32,117,115,101,108,101,115,115,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,97,115,32,110,97,109,101,115,32,99,97,110,110,111,116,32,98,101,32,114,101,116,114,105,101,118,101,100,46>>]}]},{p,[],[<<65,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,97,32,124,32,99,104,97,114,97,99,116,101,114,32,105,115,32,106,117,115,116,32,97,32,112,97,114,116,32,111,102,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,59,32,105,116,32,105,115,32,110,111,116,32,97,32,110,101,115,116,101,100,32,97,108,116,101,114,110,97,116,105,111,110,32,119,105,116,104,32,111,110,108,121,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,46,32,84,104,101,32,101,102,102,101,99,116,32,111,102,32,40,42,84,72,69,78,41,32,101,120,116,101,110,100,115,32,98,101,121,111,110,100,32,115,117,99,104,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,101,114,101,32,65,44,32,66,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,99,111,109,112,108,101,120,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,115,32,116,104,97,116,32,100,111,32,110,111,116,32,99,111,110,116,97,105,110,32,97,110,121,32,124,32,99,104,97,114,97,99,116,101,114,115,32,97,116,32,116,104,105,115,32,108,101,118,101,108,58>>]},{pre,[],[{code,[],[<<65,32,40,66,40,42,84,72,69,78,41,67,41,32,124,32,68>>]}]},{p,[],[<<73,102,32,65,32,97,110,100,32,66,32,97,114,101,32,109,97,116,99,104,101,100,44,32,98,117,116,32,116,104,101,114,101,32,105,115,32,97,32,102,97,105,108,117,114,101,32,105,110,32,67,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,65,59,32,105,110,115,116,101,97,100,32,105,116,32,109,111,118,101,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,44,32,116,104,97,116,32,105,115,44,32,68,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,105,110,103,32,40,42,84,72,69,78,41,32,105,115,32,103,105,118,101,110,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,44,32,105,116,32,98,101,104,97,118,101,115,32,100,105,102,102,101,114,101,110,116,108,121,58>>]},{pre,[],[{code,[],[<<65,32,40,66,40,42,84,72,69,78,41,67,32,124,32,40,42,70,65,73,76,41,41,32,124,32,68>>]}]},{p,[],[<<84,104,101,32,101,102,102,101,99,116,32,111,102,32,40,42,84,72,69,78,41,32,105,115,32,110,111,119,32,99,111,110,102,105,110,101,100,32,116,111,32,116,104,101,32,105,110,110,101,114,32,115,117,98,112,97,116,116,101,114,110,46,32,65,102,116,101,114,32,97,32,102,97,105,108,117,114,101,32,105,110,32,67,44,32,109,97,116,99,104,105,110,103,32,109,111,118,101,115,32,116,111,32,40,42,70,65,73,76,41,44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,119,104,111,108,101,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,102,97,105,108,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,110,111,32,109,111,114,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,116,111,32,116,114,121,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,119,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,65,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,99,111,110,115,105,100,101,114,101,100,32,97,115,32,104,97,118,105,110,103,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,97,115,32,111,110,108,121,32,111,110,101,32,105,115,32,101,118,101,114,32,117,115,101,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,124,32,99,104,97,114,97,99,116,101,114,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,46,32,73,103,110,111,114,105,110,103,32,119,104,105,116,101,115,112,97,99,101,44,32,99,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<94,46,42,63,32,40,63,40,63,61,97,41,32,97,32,124,32,98,40,42,84,72,69,78,41,99,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,98,97,34,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,46,32,65,115,32,46,42,63,32,105,115,32,117,110,103,114,101,101,100,121,44,32,105,116,32,105,110,105,116,105,97,108,108,121,32,109,97,116,99,104,101,115,32,122,101,114,111,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,99,111,110,100,105,116,105,111,110,32,40,63,61,97,41,32,116,104,101,110,32,102,97,105,108,115,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,34,98,34,32,105,115,32,109,97,116,99,104,101,100,44,32,98,117,116,32,34,99,34,32,105,115,32,110,111,116,46,32,65,116,32,116,104,105,115,32,112,111,105,110,116,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,98,97,99,107,116,114,97,99,107,32,116,111,32,46,42,63,32,97,115,32,99,97,110,32,112,101,114,104,97,112,115,32,98,101,32,101,120,112,101,99,116,101,100,32,102,114,111,109,32,116,104,101,32,112,114,101,115,101,110,99,101,32,111,102,32,116,104,101,32,124,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,115,105,110,103,108,101,32,97,108,116,101,114,110,97,116,105,118,101,32,116,104,97,116,32,99,111,109,112,114,105,115,101,115,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,115,111,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,46,32,40,73,102,32,116,104,101,114,101,32,119,97,115,32,97,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,46,42,63,44,32,97,108,108,111,119,105,110,103,32,105,116,32,116,111,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,32,109,97,116,99,104,32,119,111,117,108,100,32,115,117,99,99,101,101,100,46,41>>]},{p,[],[<<84,104,101,32,118,101,114,98,115,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,32,112,114,111,118,105,100,101,32,102,111,117,114,32,100,105,102,102,101,114,101,110,116,32,34,115,116,114,101,110,103,116,104,115,34,32,111,102,32,99,111,110,116,114,111,108,32,119,104,101,110,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,115,58>>]},{ul,[],[{li,[],[{p,[],[<<40,42,84,72,69,78,41,32,105,115,32,116,104,101,32,119,101,97,107,101,115,116,44,32,99,97,114,114,121,105,110,103,32,111,110,32,116,104,101,32,109,97,116,99,104,32,97,116,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,46>>]}]},{li,[],[{p,[],[<<40,42,80,82,85,78,69,41,32,99,111,109,101,115,32,110,101,120,116,44,32,102,97,105,108,115,32,116,104,101,32,109,97,116,99,104,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,115,105,116,105,111,110,44,32,98,117,116,32,97,108,108,111,119,115,32,97,110,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,102,111,114,32,97,110,32,117,110,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,41,46>>]}]},{li,[],[{p,[],[<<40,42,83,75,73,80,41,32,105,115,32,115,105,109,105,108,97,114,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,97,100,118,97,110,99,101,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<40,42,67,79,77,77,73,84,41,32,105,115,32,116,104,101,32,115,116,114,111,110,103,101,115,116,44,32,99,97,117,115,105,110,103,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]}]},{p,[],[{em,[],[<<77,111,114,101,32,116,104,97,110,32,79,110,101,32,66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98>>]}]},{p,[],[<<73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,116,104,101,32,111,110,101,32,116,104,97,116,32,105,115,32,98,97,99,107,116,114,97,99,107,101,100,32,111,110,116,111,32,102,105,114,115,116,32,97,99,116,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,101,114,101,32,65,44,32,66,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,99,111,109,112,108,101,120,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,115,58>>]},{pre,[],[{code,[],[<<40,65,40,42,67,79,77,77,73,84,41,66,40,42,84,72,69,78,41,67,124,65,66,68,41>>]}]},{p,[],[<<73,102,32,65,32,109,97,116,99,104,101,115,32,98,117,116,32,66,32,102,97,105,108,115,44,32,116,104,101,32,98,97,99,107,116,114,97,99,107,32,116,111,32,40,42,67,79,77,77,73,84,41,32,99,97,117,115,101,115,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46,32,72,111,119,101,118,101,114,44,32,105,102,32,65,32,97,110,100,32,66,32,109,97,116,99,104,44,32,98,117,116,32,67,32,102,97,105,108,115,44,32,116,104,101,32,98,97,99,107,116,114,97,99,107,32,116,111,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,40,65,66,68,41,32,116,111,32,98,101,32,116,114,105,101,100,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,99,111,110,115,105,115,116,101,110,116,44,32,98,117,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,116,104,101,32,115,97,109,101,32,97,115,32,105,110,32,80,101,114,108,46,32,73,116,32,109,101,97,110,115,32,116,104,97,116,32,105,102,32,116,119,111,32,111,114,32,109,111,114,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,112,112,101,97,114,32,105,110,32,115,117,99,99,101,115,115,105,111,110,44,32,116,104,101,32,108,97,115,116,32,111,102,32,116,104,101,109,32,104,97,115,32,110,111,32,101,102,102,101,99,116,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<46,46,46,40,42,67,79,77,77,73,84,41,40,42,80,82,85,78,69,41,46,46,46>>]}]},{p,[],[<<73,102,32,116,104,101,114,101,32,105,115,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,111,32,116,104,101,32,114,105,103,104,116,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,111,110,116,111,32,40,42,80,82,85,78,69,41,32,99,97,117,115,101,115,32,105,116,32,116,111,32,98,101,32,116,114,105,103,103,101,114,101,100,44,32,97,110,100,32,105,116,115,32,97,99,116,105,111,110,32,105,115,32,116,97,107,101,110,46,32,84,104,101,114,101,32,99,97,110,32,110,101,118,101,114,32,98,101,32,97,32,98,97,99,107,116,114,97,99,107,32,111,110,116,111,32,40,42,67,79,77,77,73,84,41,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,82,101,112,101,97,116,101,100,32,71,114,111,117,112,115>>]}]},{p,[],[<<80,67,82,69,32,100,105,102,102,101,114,115,32,102,114,111,109,32,80,101,114,108,32,105,110,32,105,116,115,32,104,97,110,100,108,105,110,103,32,111,102,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,105,110,32,114,101,112,101,97,116,101,100,32,103,114,111,117,112,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<47,40,97,40,42,67,79,77,77,73,84,41,98,41,43,97,99,47>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,98,97,99,34,44,32,80,101,114,108,32,109,97,116,99,104,101,115,44,32,98,117,116,32,80,67,82,69,32,102,97,105,108,115,32,98,101,99,97,117,115,101,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,114,101,112,101,97,116,32,111,102,32,116,104,101,32,103,114,111,117,112,32,97,99,116,115,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<40,42,70,65,73,76,41,32,105,110,32,97,110,32,97,115,115,101,114,116,105,111,110,32,104,97,115,32,105,116,115,32,110,111,114,109,97,108,32,101,102,102,101,99,116,58,32,105,116,32,102,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,98,97,99,107,116,114,97,99,107,46>>]},{p,[],[<<40,42,65,67,67,69,80,84,41,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,97,117,115,101,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,115,117,99,99,101,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46,32,73,110,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,40,42,65,67,67,69,80,84,41,32,99,97,117,115,101,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,102,97,105,108,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46>>]},{p,[],[<<84,104,101,32,111,116,104,101,114,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,114,101,32,110,111,116,32,116,114,101,97,116,101,100,32,115,112,101,99,105,97,108,108,121,32,105,102,32,116,104,101,121,32,97,112,112,101,97,114,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,46,32,73,110,32,112,97,114,116,105,99,117,108,97,114,44,32,40,42,84,72,69,78,41,32,115,107,105,112,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,105,110,110,101,114,109,111,115,116,32,101,110,99,108,111,115,105,110,103,32,103,114,111,117,112,32,116,104,97,116,32,104,97,115,32,97,108,116,101,114,110,97,116,105,111,110,115,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,116,104,105,115,32,105,115,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,46>>]},{p,[],[<<78,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,44,32,104,111,119,101,118,101,114,44,32,100,105,102,102,101,114,101,110,116,44,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,99,104,97,110,103,105,110,103,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,105,110,116,111,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,104,97,110,103,101,115,32,105,116,115,32,114,101,115,117,108,116,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,40,42,67,79,77,77,73,84,41,44,32,40,42,83,75,73,80,41,44,32,111,114,32,40,42,80,82,85,78,69,41,32,99,97,117,115,101,115,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,98,101,32,116,114,117,101,44,32,119,105,116,104,111,117,116,32,99,111,110,115,105,100,101,114,105,110,103,32,97,110,121,32,102,117,114,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104,101,115,32,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,105,116,32,116,111,32,115,107,105,112,32,116,111,32,116,104,101,32,110,101,120,116,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,40,116,104,101,32,110,111,114,109,97,108,32,98,101,104,97,118,105,111,114,41,44,32,98,117,116,32,105,102,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,115,117,99,104,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,44,32,40,42,84,72,69,78,41,32,98,101,104,97,118,101,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,83,117,98,114,111,117,116,105,110,101,115>>]}]},{p,[],[<<84,104,101,115,101,32,98,101,104,97,118,105,111,114,115,32,111,99,99,117,114,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,99,97,108,108,101,100,32,114,101,99,117,114,115,105,118,101,108,121,46,32,84,104,101,32,116,114,101,97,116,109,101,110,116,32,111,102,32,115,117,98,114,111,117,116,105,110,101,115,32,105,110,32,80,101,114,108,32,105,115,32,100,105,102,102,101,114,101,110,116,32,105,110,32,115,111,109,101,32,99,97,115,101,115,46>>]},{ul,[],[{li,[],[{p,[],[<<40,42,70,65,73,76,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,104,97,115,32,105,116,115,32,110,111,114,109,97,108,32,101,102,102,101,99,116,58,32,105,116,32,102,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,98,97,99,107,116,114,97,99,107,46>>]}]},{li,[],[{p,[],[<<40,42,65,67,67,69,80,84,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,117,115,101,115,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,115,117,99,99,101,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46,32,77,97,116,99,104,105,110,103,32,116,104,101,110,32,99,111,110,116,105,110,117,101,115,32,97,102,116,101,114,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]}]},{li,[],[{p,[],[<<40,42,67,79,77,77,73,84,41,44,32,40,42,83,75,73,80,41,44,32,97,110,100,32,40,42,80,82,85,78,69,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,117,115,101,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]},{li,[],[{p,[],[<<40,42,84,72,69,78,41,32,115,107,105,112,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,105,110,110,101,114,109,111,115,116,32,101,110,99,108,111,115,105,110,103,32,103,114,111,117,112,32,119,105,116,104,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,104,97,115,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,73,102,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,99,104,32,103,114,111,117,112,32,119,105,116,104,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]}]}]},#{name => <<114,101>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,114,101,46,120,109,108],types => #{{compile_option,0} => {attribute,27,type,{compile_option,{type,27,union,[{atom,27,unicode},{atom,27,anchored},{atom,27,caseless},{atom,27,dollar_endonly},{atom,28,dotall},{atom,28,extended},{atom,28,firstline},{atom,28,multiline},{atom,29,no_auto_capture},{atom,29,dupnames},{atom,29,ungreedy},{type,30,tuple,[{atom,30,newline},{user_type,30,nl_spec,[]}]},{atom,31,bsr_anycrlf},{atom,31,bsr_unicode},{atom,32,no_start_optimize},{atom,32,ucp},{atom,32,never_utf}]},[]}},{mp,0} => {attribute,23,type,{mp,{type,23,tuple,[{atom,23,re_pattern},{var,23,'_'},{var,23,'_'},{var,23,'_'},{var,23,'_'}]},[]}},{nl_spec,0} => {attribute,25,type,{nl_spec,{type,25,union,[{atom,25,cr},{atom,25,crlf},{atom,25,lf},{atom,25,anycrlf},{atom,25,any}]},[]}}}},[{{function,version,0},[{file,[114,101,46,101,114,108]},{location,40}],[<<118,101,114,115,105,111,110,47,48>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,97,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,80,67,82,69,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,115,121,115,116,101,109,32,116,104,97,116,32,119,97,115,32,117,115,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,47,79,84,80,32,99,111,109,112,105,108,97,116,105,111,110,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,56,49>>,signature => [{attribute,40,spec,{{version,0},[{type,40,'fun',[{type,40,product,[]},{type,40,binary,[]}]}]}}],since => <<79,84,80,32,50,48,46,48>>}},{{function,compile,1},[{file,[114,101,46,101,114,108]},{location,49}],[<<99,111,109,112,105,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<99,111,109,112,105,108,101,40,82,101,103,101,120,112,44,91,93,41>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,56,57>>,signature => [{attribute,49,spec,{{compile,1},[{type,49,bounded_fun,[{type,49,'fun',[{type,49,product,[{var,49,'Regexp'}]},{type,49,union,[{type,49,tuple,[{atom,49,ok},{var,49,'MP'}]},{type,49,tuple,[{atom,49,error},{var,49,'ErrSpec'}]}]}]},[{type,50,constraint,[{atom,50,is_subtype},[{var,50,'Regexp'},{type,50,iodata,[]}]]},{type,51,constraint,[{atom,51,is_subtype},[{var,51,'MP'},{user_type,51,mp,[]}]]},{type,52,constraint,[{atom,52,is_subtype},[{var,52,'ErrSpec'},{type,52,tuple,[{ann_type,52,[{var,52,'ErrString'},{type,52,string,[]}]},{ann_type,52,[{var,52,'Position'},{type,52,non_neg_integer,[]}]}]}]]}]]}]}}]}},{{function,compile,2},[{file,[114,101,46,101,114,108]},{location,57}],[<<99,111,109,112,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,105,108,101,115,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,119,105,116,104,32,116,104,101,32,115,121,110,116,97,120,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,44,32,105,110,116,111,32,97,110,32,105,110,116,101,114,110,97,108,32,102,111,114,109,97,116,32,116,111,32,98,101,32,117,115,101,100,32,108,97,116,101,114,32,97,115,32,97,32,112,97,114,97,109,101,116,101,114,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46>>]},{p,[],[<<67,111,109,112,105,108,105,110,103,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,98,101,102,111,114,101,32,109,97,116,99,104,105,110,103,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,115,97,109,101,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,109,97,116,99,104,105,110,103,32,97,103,97,105,110,115,116,32,109,117,108,116,105,112,108,101,32,115,117,98,106,101,99,116,115,32,100,117,114,105,110,103,32,116,104,101,32,108,105,102,101,116,105,109,101,32,111,102,32,116,104,101,32,112,114,111,103,114,97,109,46,32,67,111,109,112,105,108,105,110,103,32,111,110,99,101,32,97,110,100,32,101,120,101,99,117,116,105,110,103,32,109,97,110,121,32,116,105,109,101,115,32,105,115,32,102,97,114,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,111,109,112,105,108,105,110,103,32,101,97,99,104,32,116,105,109,101,32,111,110,101,32,119,97,110,116,115,32,116,111,32,109,97,116,99,104,46>>]},{p,[],[<<87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,97,115,32,97,110,121,32,118,97,108,105,100,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<46>>]},{a,[{id,<<99,111,109,112,105,108,101,95,111,112,116,105,111,110,115>>}],[]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,111,100,101,32,105,115,32,116,111,32,98,101,32,114,117,110,32,97,103,97,105,110,115,116,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<32,115,117,98,106,101,99,116,46,32,65,108,115,111,32,99,111,110,115,105,100,101,114,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,119,104,101,110,32,117,115,105,110,103,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{dt,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,102,111,114,99,101,100,32,116,111,32,98,101,32,34,97,110,99,104,111,114,101,100,34,44,32,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,99,111,110,115,116,114,97,105,110,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,115,101,97,114,99,104,101,100,32,40,116,104,101,32,34,115,117,98,106,101,99,116,32,115,116,114,105,110,103,34,41,46,32,84,104,105,115,32,101,102,102,101,99,116,32,99,97,110,32,97,108,115,111,32,98,101,32,97,99,104,105,101,118,101,100,32,98,121,32,97,112,112,114,111,112,114,105,97,116,101,32,99,111,110,115,116,114,117,99,116,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,115,101,108,102,46>>]}]},{dt,[],[{code,[],[<<99,97,115,101,108,101,115,115>>]}]},{dd,[],[{p,[],[<<76,101,116,116,101,114,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,98,111,116,104,32,117,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115,46,32,73,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,105>>]},<<32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,105,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,85,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,105,110,32,116,104,101,32,73,83,79,32,56,56,53,57,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]}]},{dd,[],[{p,[],[<<65,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,87,105,116,104,111,117,116,32,116,104,105,115,32,111,112,116,105,111,110,44,32,97,32,100,111,108,108,97,114,32,97,108,115,111,32,109,97,116,99,104,101,115,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,40,98,117,116,32,110,111,116,32,98,101,102,111,114,101,32,97,110,121,32,111,116,104,101,114,32,110,101,119,108,105,110,101,115,41,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,105,103,110,111,114,101,100,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,114,101,32,105,115,32,110,111,32,101,113,117,105,118,97,108,101,110,116,32,111,112,116,105,111,110,32,105,110,32,80,101,114,108,44,32,97,110,100,32,105,116,32,99,97,110,110,111,116,32,98,101,32,115,101,116,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<100,111,116,97,108,108>>]}]},{dd,[],[{p,[],[<<65,32,100,111,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,99,108,117,100,105,110,103,32,116,104,111,115,101,32,105,110,100,105,99,97,116,105,110,103,32,110,101,119,108,105,110,101,46,32,87,105,116,104,111,117,116,32,105,116,44,32,97,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,119,104,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,105,115,32,97,116,32,97,32,110,101,119,108,105,110,101,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,115>>]},<<32,97,110,100,32,105,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,115,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,65,32,110,101,103,97,116,105,118,101,32,99,108,97,115,115,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<91,94,97,93>>]},<<44,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,116,104,105,115,32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<101,120,116,101,110,100,101,100>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,101,116,44,32,109,111,115,116,32,119,104,105,116,101,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,97,114,101,32,116,111,116,97,108,108,121,32,105,103,110,111,114,101,100,32,101,120,99,101,112,116,32,119,104,101,110,32,101,115,99,97,112,101,100,32,111,114,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,72,111,119,101,118,101,114,44,32,119,104,105,116,101,32,115,112,97,99,101,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,119,105,116,104,105,110,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32>>,{code,[],[<<40,63,62>>]},<<32,116,104,97,116,32,105,110,116,114,111,100,117,99,101,32,118,97,114,105,111,117,115,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,110,111,114,32,119,105,116,104,105,110,32,97,32,110,117,109,101,114,105,99,97,108,32,113,117,97,110,116,105,102,105,101,114,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,49,44,51,125>>]},<<46,32,72,111,119,101,118,101,114,44,32,105,103,110,111,114,97,98,108,101,32,119,104,105,116,101,32,115,112,97,99,101,32,105,115,32,112,101,114,109,105,116,116,101,100,32,98,101,116,119,101,101,110,32,97,110,32,105,116,101,109,32,97,110,100,32,97,32,102,111,108,108,111,119,105,110,103,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,98,101,116,119,101,101,110,32,97,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,97,32,102,111,108,108,111,119,105,110,103,32,43,32,116,104,97,116,32,105,110,100,105,99,97,116,101,115,32,112,111,115,115,101,115,115,105,118,101,110,101,115,115,46>>]},{p,[],[<<87,104,105,116,101,32,115,112,97,99,101,32,100,105,100,32,110,111,116,32,117,115,101,100,32,116,111,32,105,110,99,108,117,100,101,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,49,49,41,44,32,98,101,99,97,117,115,101,32,80,101,114,108,32,100,105,100,32,110,111,116,32,116,114,101,97,116,32,116,104,105,115,32,99,104,97,114,97,99,116,101,114,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,115,111,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,44,32,97,110,100,32,86,84,32,105,115,32,110,111,119,32,116,114,101,97,116,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,46>>]},{p,[],[<<84,104,105,115,32,97,108,115,111,32,99,97,117,115,101,115,32,99,104,97,114,97,99,116,101,114,115,32,98,101,116,119,101,101,110,32,97,110,32,117,110,101,115,99,97,112,101,100,32,35,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,97,110,100,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,44,32,105,110,99,108,117,115,105,118,101,44,32,116,111,32,98,101,32,105,103,110,111,114,101,100,46,32,84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,39,115,32>>,{code,[],[<<47,120>>]},<<32,111,112,116,105,111,110,44,32,97,110,100,32,105,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,120,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46>>]},{p,[],[<<87,105,116,104,32,116,104,105,115,32,111,112,116,105,111,110,44,32,99,111,109,109,101,110,116,115,32,105,110,115,105,100,101,32,99,111,109,112,108,105,99,97,116,101,100,32,112,97,116,116,101,114,110,115,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,46,32,72,111,119,101,118,101,114,44,32,110,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,97,112,112,108,105,101,115,32,111,110,108,121,32,116,111,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,115,46,32,87,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,99,97,110,32,110,101,118,101,114,32,97,112,112,101,97,114,32,119,105,116,104,105,110,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,102,111,114,32,101,120,97,109,112,108,101,32,119,105,116,104,105,110,32,115,101,113,117,101,110,99,101,32>>,{code,[],[<<40,63,40>>]},<<32,116,104,97,116,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<102,105,114,115,116,108,105,110,101>>]}]},{dd,[],[{p,[],[<<65,110,32,117,110,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,32,105,115,32,114,101,113,117,105,114,101,100,32,116,111,32,109,97,116,99,104,32,98,101,102,111,114,101,32,111,114,32,97,116,32,116,104,101,32,102,105,114,115,116,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,108,116,104,111,117,103,104,32,116,104,101,32,109,97,116,99,104,101,100,32,116,101,120,116,32,99,97,110,32,99,111,110,116,105,110,117,101,32,111,118,101,114,32,116,104,101,32,110,101,119,108,105,110,101,46>>]}]},{dt,[],[{code,[],[<<109,117,108,116,105,108,105,110,101>>]}]},{dd,[],[{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,80,67,82,69,32,116,114,101,97,116,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,97,115,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32,97,32,115,105,110,103,108,101,32,108,105,110,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,110,101,119,108,105,110,101,115,41,46,32,84,104,101,32,34,115,116,97,114,116,32,111,102,32,108,105,110,101,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<94>>]},<<41,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,119,104,105,108,101,32,116,104,101,32,34,101,110,100,32,111,102,32,108,105,110,101,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<36>>]},<<41,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,111,114,32,98,101,102,111,114,101,32,97,32,116,101,114,109,105,110,97,116,105,110,103,32,110,101,119,108,105,110,101,32,40,117,110,108,101,115,115,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,41,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,105,110,32,80,101,114,108,46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,34,115,116,97,114,116,32,111,102,32,108,105,110,101,34,32,97,110,100,32,34,101,110,100,32,111,102,32,108,105,110,101,34,32,99,111,110,115,116,114,117,99,116,115,32,109,97,116,99,104,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,105,110,103,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,105,110,116,101,114,110,97,108,32,110,101,119,108,105,110,101,115,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,97,115,32,119,101,108,108,32,97,115,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,97,110,100,32,101,110,100,46,32,84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,109>>]},<<32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,109,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,110,111,32,110,101,119,108,105,110,101,115,32,105,110,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,111,114,32,110,111,32,111,99,99,117,114,114,101,110,99,101,115,32,111,102,32>>,{code,[],[<<94>>]},<<32,111,114,32>>,{code,[],[<<36>>]},<<32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,115,101,116,116,105,110,103,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]}]},{dt,[],[{code,[],[<<110,111,95,97,117,116,111,95,99,97,112,116,117,114,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,104,101,32,117,115,101,32,111,102,32,110,117,109,98,101,114,101,100,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<63>>]},<<32,98,101,104,97,118,101,115,32,97,115,32,105,102,32,105,116,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<63,58>>]},<<46,32,78,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,115,116,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,97,112,116,117,114,105,110,103,32,40,97,110,100,32,116,104,101,121,32,97,99,113,117,105,114,101,32,110,117,109,98,101,114,115,32,105,110,32,116,104,101,32,117,115,117,97,108,32,119,97,121,41,46,32,84,104,101,114,101,32,105,115,32,110,111,32,101,113,117,105,118,97,108,101,110,116,32,111,112,116,105,111,110,32,105,110,32,80,101,114,108,46>>]}]},{dt,[],[{code,[],[<<100,117,112,110,97,109,101,115>>]}]},{dd,[],[{p,[],[<<78,97,109,101,115,32,117,115,101,100,32,116,111,32,105,100,101,110,116,105,102,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,110,101,101,100,32,110,111,116,32,98,101,32,117,110,105,113,117,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,104,101,108,112,102,117,108,32,102,111,114,32,99,101,114,116,97,105,110,32,116,121,112,101,115,32,111,102,32,112,97,116,116,101,114,110,32,119,104,101,110,32,105,116,32,105,115,32,107,110,111,119,110,32,116,104,97,116,32,111,110,108,121,32,111,110,101,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,101,118,101,114,32,98,101,32,109,97,116,99,104,101,100,46,32,77,111,114,101,32,100,101,116,97,105,108,115,32,111,102,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,98,101,108,111,119,46>>]}]},{dt,[],[{code,[],[<<117,110,103,114,101,101,100,121>>]}]},{dd,[],[{p,[],[<<73,110,118,101,114,116,115,32,116,104,101,32,34,103,114,101,101,100,105,110,101,115,115,34,32,111,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,115,111,32,116,104,97,116,32,116,104,101,121,32,97,114,101,32,110,111,116,32,103,114,101,101,100,121,32,98,121,32,100,101,102,97,117,108,116,44,32,98,117,116,32,98,101,99,111,109,101,32,103,114,101,101,100,121,32,105,102,32,102,111,108,108,111,119,101,100,32,98,121,32,34,63,34,46,32,73,116,32,105,115,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,32,80,101,114,108,46,32,73,116,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,97,32>>,{code,[],[<<40,63,85,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,32,119,105,116,104,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{dd,[],[{p,[],[<<79,118,101,114,114,105,100,101,115,32,116,104,101,32,100,101,102,97,117,108,116,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,105,99,104,32,105,115,32,76,70,32,40,65,83,67,73,73,32,49,48,41,32,105,110,32,69,114,108,97,110,103,46>>]},{dl,[],[{dt,[],[{code,[],[<<99,114>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<99,114>>]},<<32,40,65,83,67,73,73,32,49,51,41,46>>]}]},{dt,[],[{code,[],[<<108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,76,70,32,40,65,83,67,73,73,32,49,48,41,44,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<99,114,108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,67,82,76,70,32,40,65,83,67,73,73,32,49,51,32,102,111,108,108,111,119,101,100,32,98,121,32,65,83,67,73,73,32,49,48,41,32,115,101,113,117,101,110,99,101,46>>]}]},{dt,[],[{code,[],[<<97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,105,115,32,116,111,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]}]},{dt,[],[{code,[],[<<97,110,121>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115,32,97,98,111,118,101,44,32,97,110,100,32,116,104,101,32,85,110,105,99,111,100,101,32,115,101,113,117,101,110,99,101,115,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,44,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,44,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,44,32,110,111,116,32,116,104,101,32,85,110,105,99,111,100,101,45,115,112,101,99,105,102,105,99,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{dt,[],[{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,116,104,101,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,67,82,76,70,44,32,97,110,100,32,115,111,32,111,110,44,32,116,104,101,32,100,101,102,97,117,108,116,41,46>>]}]},{dt,[],[{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,99,97,110,32,109,97,108,102,117,110,99,116,105,111,110,32,105,102,32,34,83,112,101,99,105,97,108,32,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,32,97,114,101,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,65,32,116,121,112,105,99,97,108,32,101,120,97,109,112,108,101,32,119,111,117,108,100,32,98,101,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,34,68,69,70,65,66,67,34,32,97,103,97,105,110,115,116,32,34,40,42,67,79,77,77,73,84,41,65,66,67,34,44,32,119,104,101,114,101,32,116,104,101,32,115,116,97,114,116,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,80,67,82,69,32,119,111,117,108,100,32,115,107,105,112,32,116,104,101,32,115,117,98,106,101,99,116,32,117,112,32,116,111,32,34,65,34,32,97,110,100,32,110,101,118,101,114,32,114,101,97,108,105,122,101,32,116,104,97,116,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,105,110,115,116,114,117,99,116,105,111,110,32,105,115,32,116,111,32,104,97,118,101,32,109,97,100,101,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,97,105,108,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,114,101,108,101,118,97,110,116,32,105,102,32,121,111,117,32,117,115,101,32,34,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,44,32,97,115,32,100,105,115,99,117,115,115,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},<<46>>]}]},{dt,[],[{code,[],[<<117,99,112>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,116,111,32,98,101,32,117,115,101,100,32,119,104,101,110,32,114,101,115,111,108,118,105,110,103,32,92,66,44,32,92,98,44,32,92,68,44,32,92,100,44,32,92,83,44,32,92,115,44,32,92,87,32,97,110,100,32,92,119,46,32,87,105,116,104,111,117,116,32,116,104,105,115,32,102,108,97,103,44,32,111,110,108,121,32,73,83,79,32,76,97,116,105,110,45,49,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,46,32,85,115,105,110,103,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,104,117,114,116,115,32,112,101,114,102,111,114,109,97,110,99,101,44,32,98,117,116,32,105,115,32,115,101,109,97,110,116,105,99,97,108,108,121,32,99,111,114,114,101,99,116,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,98,101,121,111,110,100,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,46>>]}]},{dt,[],[{code,[],[<<110,101,118,101,114,95,117,116,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,40,42,85,84,70,41,32,97,110,100,47,111,114,32,40,42,85,84,70,56,41,32,34,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,32,97,114,101,32,102,111,114,98,105,100,100,101,110,46,32,84,104,105,115,32,102,108,97,103,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<46,32,85,115,101,102,117,108,32,105,102,32,73,83,79,32,76,97,116,105,110,45,49,32,112,97,116,116,101,114,110,115,32,102,114,111,109,32,97,110,32,101,120,116,101,114,110,97,108,32,115,111,117,114,99,101,32,97,114,101,32,116,111,32,98,101,32,99,111,109,112,105,108,101,100,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,57,55>>,signature => [{attribute,57,spec,{{compile,2},[{type,57,bounded_fun,[{type,57,'fun',[{type,57,product,[{var,57,'Regexp'},{var,57,'Options'}]},{type,57,union,[{type,57,tuple,[{atom,57,ok},{var,57,'MP'}]},{type,57,tuple,[{atom,57,error},{var,57,'ErrSpec'}]}]}]},[{type,58,constraint,[{atom,58,is_subtype},[{var,58,'Regexp'},{type,58,union,[{type,58,iodata,[]},{remote_type,58,[{atom,58,unicode},{atom,58,charlist},[]]}]}]]},{type,59,constraint,[{atom,59,is_subtype},[{var,59,'Options'},{type,59,list,[{var,59,'Option'}]}]]},{type,60,constraint,[{atom,60,is_subtype},[{var,60,'Option'},{user_type,60,compile_option,[]}]]},{type,61,constraint,[{atom,61,is_subtype},[{var,61,'MP'},{user_type,61,mp,[]}]]},{type,62,constraint,[{atom,62,is_subtype},[{var,62,'ErrSpec'},{type,62,tuple,[{ann_type,62,[{var,62,'ErrString'},{type,62,string,[]}]},{ann_type,62,[{var,62,'Position'},{type,62,non_neg_integer,[]}]}]}]]}]]}]}}]}},{{function,inspect,2},[{file,[114,101,46,101,114,108]},{location,143}],[<<105,110,115,112,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,97,107,101,115,32,97,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32,97,110,32,105,116,101,109,44,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,114,101,108,101,118,97,110,116,32,100,97,116,97,32,102,114,111,109,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,84,104,101,32,111,110,108,121,32,115,117,112,112,111,114,116,101,100,32,105,116,101,109,32,105,115,32>>,{code,[],[<<110,97,109,101,108,105,115,116>>]},<<44,32,119,104,105,99,104,32,114,101,116,117,114,110,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,110,97,109,101,108,105,115,116,44,32,91,98,105,110,97,114,121,40,41,93,125>>]},<<44,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,40,117,110,105,113,117,101,41,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,123,111,107,44,77,80,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,65,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,50,62,32,114,101,58,105,110,115,112,101,99,116,40,77,80,44,110,97,109,101,108,105,115,116,41,46,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,65,34,62,62,44,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125,10,51,62,32,123,111,107,44,77,80,68,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,67,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,44,91,100,117,112,110,97,109,101,115,93,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,56,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,52,62,32,114,101,58,105,110,115,112,101,99,116,40,77,80,68,44,110,97,109,101,108,105,115,116,41,46,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125>>]}]},{p,[],[<<78,111,116,105,99,101,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,101,120,97,109,112,108,101,32,116,104,97,116,32,116,104,101,32,100,117,112,108,105,99,97,116,101,32,110,97,109,101,32,111,110,108,121,32,111,99,99,117,114,115,32,111,110,99,101,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,108,105,115,116,32,105,115,32,105,110,32,97,108,112,104,97,98,101,116,105,99,97,108,32,111,114,100,101,114,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,114,101,32,116,104,101,32,110,97,109,101,115,32,97,114,101,32,112,111,115,105,116,105,111,110,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,110,97,109,101,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,111,114,100,101,114,32,111,102,32,99,97,112,116,117,114,101,100,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,105,102,32>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,97,108,108,95,110,97,109,101,115,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,110,32,111,112,116,105,111,110,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46,32,89,111,117,32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,99,114,101,97,116,101,32,97,32,110,97,109,101,45,116,111,45,118,97,108,117,101,32,109,97,112,112,105,110,103,32,102,114,111,109,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<49,62,32,123,111,107,44,77,80,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,65,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,50,62,32,123,110,97,109,101,108,105,115,116,44,32,78,125,32,61,32,114,101,58,105,110,115,112,101,99,116,40,77,80,44,110,97,109,101,108,105,115,116,41,46,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,65,34,62,62,44,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125,10,51,62,32,123,109,97,116,99,104,44,76,125,32,61,32,114,101,58,114,117,110,40,34,65,65,34,44,77,80,44,91,123,99,97,112,116,117,114,101,44,97,108,108,95,110,97,109,101,115,44,98,105,110,97,114,121,125,93,41,46,10,123,109,97,116,99,104,44,91,60,60,34,65,34,62,62,44,60,60,62,62,44,60,60,62,62,93,125,10,52,62,32,78,97,109,101,77,97,112,32,61,32,108,105,115,116,115,58,122,105,112,40,78,44,76,41,46,10,91,123,60,60,34,65,34,62,62,44,60,60,34,65,34,62,62,125,44,123,60,60,34,66,34,62,62,44,60,60,62,62,125,44,123,60,60,34,67,34,62,62,44,60,60,62,62,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,48,54>>,signature => [{attribute,143,spec,{{inspect,2},[{type,143,bounded_fun,[{type,143,'fun',[{type,143,product,[{var,143,'MP'},{var,143,'Item'}]},{type,143,tuple,[{atom,143,namelist},{type,143,list,[{type,143,binary,[]}]}]}]},[{type,144,constraint,[{atom,144,is_subtype},[{var,144,'MP'},{user_type,144,mp,[]}]]},{type,145,constraint,[{atom,145,is_subtype},[{var,145,'Item'},{atom,145,namelist}]]}]]}]}}],since => <<79,84,80,32,49,55,46,48>>}},{{function,replace,3},[{file,[114,101,46,101,114,108]},{location,353}],[<<114,101,112,108,97,99,101,47,51>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<114,101,112,108,97,99,101,40,83,117,98,106,101,99,116,44,32,82,69,44,32,82,101,112,108,97,99,101,109,101,110,116,44,32,91,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,53,48>>,signature => [{attribute,353,spec,{{replace,3},[{type,353,bounded_fun,[{type,353,'fun',[{type,353,product,[{var,353,'Subject'},{var,353,'RE'},{var,353,'Replacement'}]},{type,353,union,[{type,353,iodata,[]},{remote_type,353,[{atom,353,unicode},{atom,353,charlist},[]]}]}]},[{type,354,constraint,[{atom,354,is_subtype},[{var,354,'Subject'},{type,354,union,[{type,354,iodata,[]},{remote_type,354,[{atom,354,unicode},{atom,354,charlist},[]]}]}]]},{type,355,constraint,[{atom,355,is_subtype},[{var,355,'RE'},{type,355,union,[{user_type,355,mp,[]},{type,355,iodata,[]}]}]]},{type,356,constraint,[{atom,356,is_subtype},[{var,356,'Replacement'},{type,356,union,[{type,356,iodata,[]},{remote_type,356,[{atom,356,unicode},{atom,356,charlist},[]]}]}]]}]]}]}}]}},{{function,replace,4},[{file,[114,101,46,101,114,108]},{location,366}],[<<114,101,112,108,97,99,101,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,112,108,97,99,101,115,32,116,104,101,32,109,97,116,99,104,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32>>,{code,[],[<<82,101,112,108,97,99,101,109,101,110,116>>]},<<46>>]},{p,[],[<<84,104,101,32,112,101,114,109,105,115,115,105,98,108,101,32,111,112,116,105,111,110,115,32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,102,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,111,112,116,105,111,110>>,{code,[],[<<32,99,97,112,116,117,114,101>>]},<<32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,46,32,73,110,115,116,101,97,100,32,97,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,82,101,116,117,114,110,84,121,112,101,125>>]},<<32,105,115,32,112,114,101,115,101,110,116,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<44,32,99,111,110,115,116,114,117,99,116,101,100,32,105,110,32,97,32,119,97,121,32,116,111,32,109,105,110,105,109,105,122,101,32,99,111,112,121,105,110,103,46,32,84,104,101,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<32,114,101,115,117,108,116,32,99,97,110,32,98,101,32,117,115,101,100,32,100,105,114,101,99,116,108,121,32,105,110,32,109,97,110,121,32,73,47,79,32,111,112,101,114,97,116,105,111,110,115,46,32,73,102,32,97,32,102,108,97,116,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,105,115,32,100,101,115,105,114,101,100,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,108,105,115,116,125>>]},<<46,32,73,102,32,97,32,98,105,110,97,114,121,32,105,115,32,100,101,115,105,114,101,100,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,98,105,110,97,114,121,125>>]},<<46>>]},{p,[],[<<65,115,32,105,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<44,32,97,110,32>>,{code,[],[<<109,112,40,41>>]},<<32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,113,117,105,114,101,115,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,116,111,32,98,101,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,105,109,112,108,105,99,105,116,108,121,32,97,110,100,32,116,104,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,98,111,116,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,114,101,32,116,111,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<115,46>>]},{p,[],[<<84,104,101,32,114,101,112,108,97,99,101,109,101,110,116,32,115,116,114,105,110,103,32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<38>>]},<<44,32,119,104,105,99,104,32,105,110,115,101,114,116,115,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,105,110,103,32,101,120,112,114,101,115,115,105,111,110,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,97,110,100,32,116,104,101,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32>>,{code,[],[<<92>>]},<<78,32,40,119,104,101,114,101,32,78,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,62,32,48,41,44,32>>,{code,[],[<<92,103>>]},<<78,44,32,111,114,32>>,{code,[],[<<92,103,123>>]},<<78>>,{code,[],[<<125>>]},<<44,32,114,101,115,117,108,116,105,110,103,32,105,110,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,110,117,109,98,101,114,32,78,44,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46,32,73,102,32,110,111,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,119,105,116,104,32,116,104,97,116,32,110,117,109,98,101,114,32,105,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,110,111,116,104,105,110,103,32,105,115,32,105,110,115,101,114,116,101,100,46>>]},{p,[],[<<84,111,32,105,110,115,101,114,116,32,97,110,32,38,32,111,114,32,97,32,92,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,112,114,101,99,101,100,101,32,105,116,32,119,105,116,104,32,97,32,92,46,32,78,111,116,105,99,101,32,116,104,97,116,32,69,114,108,97,110,103,32,97,108,114,101,97,100,121,32,103,105,118,101,115,32,97,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,116,111,32,92,32,105,110,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,115,44,32,115,111,32,97,32,115,105,110,103,108,101,32,92,32,109,117,115,116,32,98,101,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<34,92,92,34>>]},<<32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,97,32,100,111,117,98,108,101,32,92,32,97,115,32>>,{code,[],[<<34,92,92,92,92,34>>]},<<46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[],[<<114,101,58,114,101,112,108,97,99,101,40,34,97,98,99,100,34,44,34,99,34,44,34,91,38,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<34,97,98,91,99,93,100,34>>]}]},{p,[],[<<119,104,105,108,101>>]},{pre,[],[{code,[],[<<114,101,58,114,101,112,108,97,99,101,40,34,97,98,99,100,34,44,34,99,34,44,34,91,92,92,38,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<34,97,98,91,38,93,100,34>>]}]},{p,[],[<<65,115,32,119,105,116,104,32>>,{code,[],[<<114,117,110,47,51>>]},<<44,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,114,97,105,115,101,32,116,104,101,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,116,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,101,114,114,111,114,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,54,48>>,signature => [{attribute,366,spec,{{replace,4},[{type,366,bounded_fun,[{type,366,'fun',[{type,366,product,[{var,366,'Subject'},{var,366,'RE'},{var,366,'Replacement'},{var,366,'Options'}]},{type,366,union,[{type,366,iodata,[]},{remote_type,366,[{atom,366,unicode},{atom,366,charlist},[]]}]}]},[{type,367,constraint,[{atom,367,is_subtype},[{var,367,'Subject'},{type,367,union,[{type,367,iodata,[]},{remote_type,367,[{atom,367,unicode},{atom,367,charlist},[]]}]}]]},{type,368,constraint,[{atom,368,is_subtype},[{var,368,'RE'},{type,368,union,[{user_type,368,mp,[]},{type,368,iodata,[]},{remote_type,368,[{atom,368,unicode},{atom,368,charlist},[]]}]}]]},{type,369,constraint,[{atom,369,is_subtype},[{var,369,'Replacement'},{type,369,union,[{type,369,iodata,[]},{remote_type,369,[{atom,369,unicode},{atom,369,charlist},[]]}]}]]},{type,370,constraint,[{atom,370,is_subtype},[{var,370,'Options'},{type,370,list,[{var,370,'Option'}]}]]},{type,371,constraint,[{atom,371,is_subtype},[{var,371,'Option'},{type,371,union,[{atom,371,anchored},{atom,371,global},{atom,371,notbol},{atom,371,noteol},{atom,371,notempty},{atom,372,notempty_atstart},{type,373,tuple,[{atom,373,offset},{type,373,non_neg_integer,[]}]},{type,373,tuple,[{atom,373,newline},{var,373,'NLSpec'}]},{atom,373,bsr_anycrlf},{type,374,tuple,[{atom,374,match_limit},{type,374,non_neg_integer,[]}]},{type,375,tuple,[{atom,375,match_limit_recursion},{type,375,non_neg_integer,[]}]},{atom,376,bsr_unicode},{type,376,tuple,[{atom,376,return},{var,376,'ReturnType'}]},{var,376,'CompileOpt'}]}]]},{type,377,constraint,[{atom,377,is_subtype},[{var,377,'ReturnType'},{type,377,union,[{atom,377,iodata},{atom,377,list},{atom,377,binary}]}]]},{type,378,constraint,[{atom,378,is_subtype},[{var,378,'CompileOpt'},{user_type,378,compile_option,[]}]]},{type,379,constraint,[{atom,379,is_subtype},[{var,379,'NLSpec'},{type,379,union,[{atom,379,cr},{atom,379,crlf},{atom,379,lf},{atom,379,anycrlf},{atom,379,any}]}]]}]]}]}}]}},{{function,run,2},[{file,[114,101,46,101,114,108]},{location,67}],[<<114,117,110,47,50>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<114,117,110,40,83,117,98,106,101,99,116,44,82,69,44,91,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,52,49,48>>,signature => [{attribute,67,spec,{{run,2},[{type,67,bounded_fun,[{type,67,'fun',[{type,67,product,[{var,67,'Subject'},{var,67,'RE'}]},{type,67,union,[{type,67,tuple,[{atom,67,match},{var,67,'Captured'}]},{atom,67,nomatch}]}]},[{type,68,constraint,[{atom,68,is_subtype},[{var,68,'Subject'},{type,68,union,[{type,68,iodata,[]},{remote_type,68,[{atom,68,unicode},{atom,68,charlist},[]]}]}]]},{type,69,constraint,[{atom,69,is_subtype},[{var,69,'RE'},{type,69,union,[{user_type,69,mp,[]},{type,69,iodata,[]}]}]]},{type,70,constraint,[{atom,70,is_subtype},[{var,70,'Captured'},{type,70,list,[{var,70,'CaptureData'}]}]]},{type,71,constraint,[{atom,71,is_subtype},[{var,71,'CaptureData'},{type,71,tuple,[{type,71,integer,[]},{type,71,integer,[]}]}]]}]]}]}}]}},{{function,run,3},[{file,[114,101,46,101,114,108]},{location,76}],[<<114,117,110,47,51>>],#{<<101,110>> => [{p,[],[<<69,120,101,99,117,116,101,115,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,105,110,103,44,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<109,97,116,99,104,47,123,109,97,116,99,104,44,32,67,97,112,116,117,114,101,100,125>>]},<<32,111,114,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<46,32,84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,101,105,116,104,101,114,32,97,115,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,111,109,112,105,108,101,100,32,40,97,115,32,98,121,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<41,32,97,110,100,32,101,120,101,99,117,116,101,100,44,32,111,114,32,97,115,32,97,32,112,114,101,99,111,109,112,105,108,101,100,32>>,{code,[],[<<109,112,40,41>>]},<<32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,105,116,32,105,115,32,101,120,101,99,117,116,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,115,117,98,106,101,99,116,32,100,105,114,101,99,116,108,121,46>>]},{p,[],[<<87,104,101,110,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,44,32,101,120,99,101,112,116,105,111,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,115,32,116,104,114,111,119,110,32,105,102,32,97,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,67,97,108,108,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<32,116,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,111,99,97,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,105,108,101,100,44,32,116,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,99,97,110,32,111,110,108,121,32,99,111,110,116,97,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{li,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125,47,123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]}]},{li,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{li,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{li,[],[{code,[],[<<110,111,116,98,111,108>>]}]},{li,[],[{code,[],[<<110,111,116,101,109,112,116,121>>]}]},{li,[],[{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]}]},{li,[],[{code,[],[<<110,111,116,101,111,108>>]}]},{li,[],[{code,[],[<<123,111,102,102,115,101,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]}]}]},{p,[],[<<79,116,104,101,114,119,105,115,101,32,97,108,108,32,111,112,116,105,111,110,115,32,118,97,108,105,100,32,102,111,114,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<32,97,114,101,32,97,108,115,111,32,97,108,108,111,119,101,100,46,32,79,112,116,105,111,110,115,32,97,108,108,111,119,101,100,32,98,111,116,104,32,102,111,114,32,99,111,109,112,105,108,97,116,105,111,110,32,97,110,100,32,101,120,101,99,117,116,105,111,110,32,111,102,32,97,32,109,97,116,99,104,44,32,110,97,109,101,108,121,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<32,97,110,100,32>>,{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]},<<44,32,97,102,102,101,99,116,32,98,111,116,104,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,97,110,100,32,101,120,101,99,117,116,105,111,110,32,105,102,32,112,114,101,115,101,110,116,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,97,32,110,111,110,45,112,114,101,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,105,115,32,116,111,32,98,101,32,112,114,111,118,105,100,101,100,32,97,115,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,97,110,121,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,119,105,108,108,32,100,111,46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,98,111,116,104,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,110,100,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,114,101,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,115,40,41>>]},<<46>>]},{p,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125,47,123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]},<<32,100,101,102,105,110,101,115,32,119,104,97,116,32,116,111,32,114,101,116,117,114,110,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,32,117,112,111,110,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,105,110,103,46,32,84,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,116,117,112,108,101,32,99,97,110,32,99,111,110,116,97,105,110,32,98,111,116,104,32,97,32,118,97,108,117,101,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,116,101,108,108,105,110,103,32,119,104,105,99,104,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,44,32,97,110,100,32,97,32,116,121,112,101,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,116,101,108,108,105,110,103,32,104,111,119,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,32,40,97,115,32,105,110,100,101,120,32,116,117,112,108,101,115,44,32,108,105,115,116,115,44,32,111,114,32,98,105,110,97,114,105,101,115,41,46,32,84,104,101,32,111,112,116,105,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,100,101,116,97,105,108,32,98,101,108,111,119,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,97,112,116,117,114,101,32,111,112,116,105,111,110,115,32,100,101,115,99,114,105,98,101,32,116,104,97,116,32,110,111,32,115,117,98,115,116,114,105,110,103,32,99,97,112,116,117,114,105,110,103,32,105,115,32,116,111,32,98,101,32,100,111,110,101,32,40>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,110,111,110,101,125>>]},<<41,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,115,105,110,103,108,101,32,97,116,111,109,32>>,{code,[],[<<109,97,116,99,104>>]},<<32,117,112,111,110,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,105,110,103,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,109,97,116,99,104,44,32,86,97,108,117,101,76,105,115,116,125>>]},<<46,32,68,105,115,97,98,108,105,110,103,32,99,97,112,116,117,114,105,110,103,32,99,97,110,32,98,101,32,100,111,110,101,32,101,105,116,104,101,114,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<110,111,110,101>>]},<<32,111,114,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32,97,115,32>>,{code,[],[<<86,97,108,117,101,83,112,101,99>>]},<<46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<32,97,100,100,115,32,116,104,101,32,112,111,115,115,105,98,105,108,105,116,121,32,116,104,97,116,32,97,110,32,101,114,114,111,114,32,116,117,112,108,101,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,116,117,112,108,101,32,101,105,116,104,101,114,32,105,110,100,105,99,97,116,101,115,32,97,32,109,97,116,99,104,105,110,103,32,101,114,114,111,114,32,40>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,111,114,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<41,44,32,111,114,32,97,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,44,32,119,104,101,114,101,32,116,104,101,32,101,114,114,111,114,32,116,117,112,108,101,32,104,97,115,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,101,114,114,111,114,44,32,123,99,111,109,112,105,108,101,44,32,67,111,109,112,105,108,101,69,114,114,125,125>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,110,101,118,101,114,32,114,101,116,117,114,110,115,32,101,114,114,111,114,32,116,117,112,108,101,115,44,32,98,117,116,32,114,101,112,111,114,116,115,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,97,115,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,97,110,100,32,102,97,105,108,101,100,32,109,97,116,99,104,101,115,32,98,101,99,97,117,115,101,32,111,102,32,101,120,99,101,101,100,101,100,32,109,97,116,99,104,32,108,105,109,105,116,115,32,115,105,109,112,108,121,32,97,115,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,32,97,114,101,32,114,101,108,101,118,97,110,116,32,102,111,114,32,101,120,101,99,117,116,105,111,110,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,116,111,32,109,97,116,99,104,105,110,103,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,46,32,73,102,32,97,32,112,97,116,116,101,114,110,32,119,97,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<44,32,111,114,32,116,117,114,110,101,100,32,111,117,116,32,116,111,32,98,101,32,97,110,99,104,111,114,101,100,32,98,121,32,118,105,114,116,117,101,32,111,102,32,105,116,115,32,99,111,110,116,101,110,116,115,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,109,97,100,101,32,117,110,97,110,99,104,111,114,101,100,32,97,116,32,109,97,116,99,104,105,110,103,32,116,105,109,101,44,32,104,101,110,99,101,32,116,104,101,114,101,32,105,115,32,110,111,32>>,{code,[],[<<117,110,97,110,99,104,111,114,101,100>>]},<<32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{dd,[],[{p,[],[<<73,109,112,108,101,109,101,110,116,115,32,103,108,111,98,97,108,32,40,114,101,112,101,116,105,116,105,118,101,41,32,115,101,97,114,99,104,32,40,102,108,97,103,32>>,{code,[],[<<103>>]},<<32,105,110,32,80,101,114,108,41,46,32,69,97,99,104,32,109,97,116,99,104,32,105,115,32,114,101,116,117,114,110,101,100,32,97,115,32,97,32,115,101,112,97,114,97,116,101,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,112,101,99,105,102,105,99,32,109,97,116,99,104,32,97,110,100,32,97,110,121,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,40,111,114,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,111,112,116,105,111,110,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<46,32,84,104,101,32>>,{code,[],[<<67,97,112,116,117,114,101,100>>]},<<32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,104,101,110,99,101,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<115,32,119,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<84,104,101,32,105,110,116,101,114,97,99,116,105,111,110,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,119,105,116,104,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,115,117,114,112,114,105,115,101,115,32,115,111,109,101,32,117,115,101,114,115,46,32,87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,104,97,110,100,108,101,115,32,101,109,112,116,121,32,109,97,116,99,104,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,80,101,114,108,58,32,97,32,122,101,114,111,45,108,101,110,103,116,104,32,109,97,116,99,104,32,97,116,32,97,110,121,32,112,111,105,110,116,32,105,115,32,97,108,115,111,32,114,101,116,114,105,101,100,32,119,105,116,104,32,111,112,116,105,111,110,115,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]},<<46,32,73,102,32,116,104,97,116,32,115,101,97,114,99,104,32,103,105,118,101,115,32,97,32,114,101,115,117,108,116,32,111,102,32,108,101,110,103,116,104,32,62,32,48,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,105,110,99,108,117,100,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,99,97,116,34,44,34,40,124,97,116,41,34,44,91,103,108,111,98,97,108,93,41,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,105,110,103,115,32,97,114,101,32,112,101,114,102,111,114,109,101,100,58>>]},{dl,[],[{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<40,124,97,116,41>>]},<<32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,32,116,104,101,32,105,110,105,116,105,97,108,32,112,111,115,105,116,105,111,110,32,111,102,32,115,116,114,105,110,103,32>>,{code,[],[<<99,97,116>>]},<<44,32,103,105,118,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,115,101,116,32>>,{code,[],[<<91,123,48,44,48,125,44,123,48,44,48,125,93>>]},<<32,40,116,104,101,32,115,101,99,111,110,100,32>>,{code,[],[<<123,48,44,48,125>>]},<<32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,109,97,114,107,101,100,32,98,121,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,41,46,32,65,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,109,97,116,99,104,32,105,115,32,48,44,32,119,101,32,100,111,32,110,111,116,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,112,111,115,105,116,105,111,110,32,121,101,116,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<48>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,105,115,32,114,101,116,114,105,101,100,32,119,105,116,104,32,111,112,116,105,111,110,115,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]},<<32,97,116,32,116,104,101,32,115,97,109,101,32,112,111,115,105,116,105,111,110,44,32,119,104,105,99,104,32,100,111,101,115,32,110,111,116,32,103,105,118,101,32,97,110,121,32,105,110,116,101,114,101,115,116,105,110,103,32,114,101,115,117,108,116,32,111,102,32,108,111,110,103,101,114,32,108,101,110,103,116,104,44,32,115,111,32,116,104,101,32,115,101,97,114,99,104,32,112,111,115,105,116,105,111,110,32,105,115,32,97,100,118,97,110,99,101,100,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<97>>]},<<41,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,114,101,115,117,108,116,115,32,105,110,32>>,{code,[],[<<91,123,49,44,48,125,44,123,49,44,48,125,93>>]},<<44,32,115,111,32,116,104,105,115,32,115,101,97,114,99,104,32,105,115,32,97,108,115,111,32,114,101,112,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,101,120,116,114,97,32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<65,108,116,101,114,110,97,116,105,118,101,32>>,{code,[],[<<97,98>>]},<<32,105,115,32,102,111,117,110,100,32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,91,123,49,44,50,125,44,123,49,44,50,125,93,46,32,84,104,101,32,114,101,115,117,108,116,32,105,115,32,97,100,100,101,100,32,116,111,32,116,104,101,32,108,105,115,116,32,111,102,32,114,101,115,117,108,116,115,32,97,110,100,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,101,97,114,99,104,32,115,116,114,105,110,103,32,105,115,32,97,100,118,97,110,99,101,100,32,116,119,111,32,115,116,101,112,115,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<51>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,111,110,99,101,32,97,103,97,105,110,32,109,97,116,99,104,101,115,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,44,32,103,105,118,105,110,103,32>>,{code,[],[<<91,123,51,44,48,125,44,123,51,44,48,125,93>>]},<<46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,103,105,118,101,115,32,110,111,32,114,101,115,117,108,116,32,111,102,32,108,101,110,103,116,104,32,62,32,48,32,97,110,100,32,119,101,32,97,114,101,32,97,116,32,116,104,101,32,108,97,115,116,32,112,111,115,105,116,105,111,110,44,32,115,111,32,116,104,101,32,103,108,111,98,97,108,32,115,101,97,114,99,104,32,105,115,32,99,111,109,112,108,101,116,101,46>>]}]}]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,97,108,108,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,91,123,48,44,48,125,44,123,48,44,48,125,93,44,91,123,49,44,48,125,44,123,49,44,48,125,93,44,91,123,49,44,50,125,44,123,49,44,50,125,93,44,91,123,51,44,48,125,44,123,51,44,48,125,93,93,125>>]}]}]},{dt,[],[{code,[],[<<110,111,116,101,109,112,116,121>>]}]},{dd,[],[{p,[],[<<65,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,97,32,118,97,108,105,100,32,109,97,116,99,104,32,105,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,73,102,32,97,108,116,101,114,110,97,116,105,118,101,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,101,120,105,115,116,44,32,116,104,101,121,32,97,114,101,32,116,114,105,101,100,46,32,73,102,32,97,108,108,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,109,97,116,99,104,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,44,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{p,[],[<<73,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,32,115,116,114,105,110,103,32,110,111,116,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,34,97,34,32,111,114,32,34,98,34,44,32,105,116,32,119,111,117,108,100,32,110,111,114,109,97,108,108,121,32,109,97,116,99,104,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,58>>]},{pre,[],[{code,[],[<<97,63,98,63>>]}]},{p,[],[<<87,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<44,32,116,104,105,115,32,109,97,116,99,104,32,105,115,32,105,110,118,97,108,105,100,44,32,115,111,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,115,101,97,114,99,104,101,115,32,102,117,114,116,104,101,114,32,105,110,116,111,32,116,104,101,32,115,116,114,105,110,103,32,102,111,114,32,111,99,99,117,114,114,101,110,99,101,115,32,111,102,32,34,97,34,32,111,114,32,34,98,34,46>>]}]},{dt,[],[{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]}]},{dd,[],[{p,[],[<<76,105,107,101,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,109,97,116,99,104,32,116,104,97,116,32,105,115,32,110,111,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,110,99,104,111,114,101,100,44,32,115,117,99,104,32,97,32,109,97,116,99,104,32,99,97,110,32,111,99,99,117,114,32,111,110,108,121,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,115,32,92,75,46>>]},{p,[],[<<80,101,114,108,32,104,97,115,32,110,111,32,100,105,114,101,99,116,32,101,113,117,105,118,97,108,101,110,116,32,111,102,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<32,111,114,32>>,{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]},<<44,32,98,117,116,32,105,116,32,100,111,101,115,32,109,97,107,101,32,97,32,115,112,101,99,105,97,108,32,99,97,115,101,32,111,102,32,97,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,111,102,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,32,119,105,116,104,105,110,32,105,116,115,32,115,112,108,105,116,40,41,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,119,104,101,110,32,117,115,105,110,103,32,109,111,100,105,102,105,101,114,32>>,{code,[],[<<47,103>>]},<<46,32,84,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,101,109,117,108,97,116,101,100,32,97,102,116,101,114,32,109,97,116,99,104,105,110,103,32,97,32,110,117,108,108,32,115,116,114,105,110,103,32,98,121,32,102,105,114,115,116,32,116,114,121,105,110,103,32,116,104,101,32,109,97,116,99,104,32,97,103,97,105,110,32,97,116,32,116,104,101,32,115,97,109,101,32,111,102,102,115,101,116,32,119,105,116,104,32>>,{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]},<<32,97,110,100,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<44,32,97,110,100,32,116,104,101,110,44,32,105,102,32,116,104,97,116,32,102,97,105,108,115,44,32,98,121,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,115,116,97,114,116,105,110,103,32,111,102,102,115,101,116,32,40,115,101,101,32,98,101,108,111,119,41,32,97,110,100,32,116,114,121,105,110,103,32,97,110,32,111,114,100,105,110,97,114,121,32,109,97,116,99,104,32,97,103,97,105,110,46>>]}]},{dt,[],[{code,[],[<<110,111,116,98,111,108>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,32,108,105,110,101,44,32,115,111,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,32,116,111,32,109,97,116,99,104,32,98,101,102,111,114,101,32,105,116,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,119,105,116,104,111,117,116,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,40,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,41,32,99,97,117,115,101,115,32,99,105,114,99,117,109,102,108,101,120,32,110,101,118,101,114,32,116,111,32,109,97,116,99,104,46,32,84,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,97,102,102,101,99,116,115,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,92,65,46>>]}]},{dt,[],[{code,[],[<<110,111,116,101,111,108>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,44,32,115,111,32,116,104,101,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,32,116,111,32,109,97,116,99,104,32,105,116,32,110,111,114,32,40,101,120,99,101,112,116,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41,32,97,32,110,101,119,108,105,110,101,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,105,116,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,119,105,116,104,111,117,116,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,40,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,41,32,99,97,117,115,101,115,32,100,111,108,108,97,114,32,110,101,118,101,114,32,116,111,32,109,97,116,99,104,46,32,84,104,105,115,32,111,112,116,105,111,110,32,97,102,102,101,99,116,115,32,111,110,108,121,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,92,90,32,111,114,32,92,122,46>>]}]},{dt,[],[{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,98,101,116,116,101,114,32,99,111,110,116,114,111,108,32,111,102,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,32,105,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<46,32,87,104,101,110,32,115,112,101,99,105,102,105,101,100,44,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,40,105,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,110,111,116,32,97,108,114,101,97,100,121,32,99,111,109,112,105,108,101,100,41,32,97,110,100,32,114,117,110,116,105,109,101,32,101,114,114,111,114,115,32,97,114,101,32,101,120,112,108,105,99,105,116,108,121,32,114,101,116,117,114,110,101,100,32,97,115,32,97,110,32,101,114,114,111,114,32,116,117,112,108,101,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,112,111,115,115,105,98,108,101,32,114,117,110,116,105,109,101,32,101,114,114,111,114,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,115,101,116,115,32,97,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,116,105,109,101,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,99,97,108,108,101,100,46,32,68,101,102,97,117,108,116,115,32,116,111,32,49,48,44,48,48,48,44,48,48,48,32,105,110,32,116,104,101,32,108,105,98,114,97,114,121,32,99,111,109,112,105,108,101,100,32,102,111,114,32,69,114,108,97,110,103,46,32,73,102,32>>,{code,[],[<<123,101,114,114,111,114,44,32,109,97,116,99,104,95,108,105,109,105,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,104,97,115,32,114,101,97,99,104,101,100,32,116,104,105,115,32,108,105,109,105,116,46,32,84,104,105,115,32,105,115,32,110,111,114,109,97,108,108,121,32,116,111,32,98,101,32,114,101,103,97,114,100,101,100,32,97,115,32,97,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,119,104,101,110,32,116,104,105,115,32,111,99,99,117,114,115,44,32,98,117,116,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<44,32,121,111,117,32,97,114,101,32,105,110,102,111,114,109,101,100,32,119,104,101,110,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,32,98,101,99,97,117,115,101,32,111,102,32,116,111,111,32,109,97,110,121,32,105,110,116,101,114,110,97,108,32,99,97,108,108,115,46>>]}]},{dt,[],[{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,101,114,114,111,114,32,105,115,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<44,32,98,117,116,32,111,99,99,117,114,115,32,119,104,101,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,111,102,32,80,67,82,69,32,105,115,32,34,114,101,99,117,114,115,105,118,101,108,121,34,32,99,97,108,108,101,100,32,109,111,114,101,32,116,105,109,101,115,32,116,104,97,110,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<32,108,105,109,105,116,44,32,119,104,105,99,104,32,100,101,102,97,117,108,116,115,32,116,111,32,49,48,44,48,48,48,44,48,48,48,32,97,115,32,119,101,108,108,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,115,32,108,111,110,103,32,97,115,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,97,110,100,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,100,101,102,97,117,108,116>>]},<<32,118,97,108,117,101,115,32,97,114,101,32,107,101,112,116,32,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,44,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<32,101,114,114,111,114,32,99,97,110,110,111,116,32,111,99,99,117,114,44,32,97,115,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,101,114,114,111,114,32,111,99,99,117,114,115,32,98,101,102,111,114,101,32,116,104,97,116,32,40,101,97,99,104,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,105,115,32,97,108,115,111,32,97,32,99,97,108,108,44,32,98,117,116,32,110,111,116,32,99,111,110,118,101,114,115,101,108,121,41,46,32,66,111,116,104,32,108,105,109,105,116,115,32,99,97,110,32,104,111,119,101,118,101,114,32,98,101,32,99,104,97,110,103,101,100,44,32,101,105,116,104,101,114,32,98,121,32,115,101,116,116,105,110,103,32,108,105,109,105,116,115,32,100,105,114,101,99,116,108,121,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,115,116,114,105,110,103,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,101,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},<<41,32,111,114,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32,111,112,116,105,111,110,115,32,116,111,32>>,{code,[],[<<114,117,110,47,51>>]},<<46>>]}]}]},{p,[],[<<73,116,32,105,115,32,105,109,112,111,114,116,97,110,116,32,116,111,32,117,110,100,101,114,115,116,97,110,100,32,116,104,97,116,32,119,104,97,116,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,34,114,101,99,117,114,115,105,111,110,34,32,119,104,101,110,32,108,105,109,105,116,105,110,103,32,109,97,116,99,104,101,115,32,105,115,32,110,111,116,32,114,101,99,117,114,115,105,111,110,32,111,110,32,116,104,101,32,67,32,115,116,97,99,107,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,109,97,99,104,105,110,101,32,111,114,32,111,110,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,115,116,97,99,107,46,32,84,104,101,32,80,67,82,69,32,118,101,114,115,105,111,110,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,117,115,101,115,32,109,97,99,104,105,110,101,32,34,104,101,97,112,34,32,109,101,109,111,114,121,32,116,111,32,115,116,111,114,101,32,118,97,108,117,101,115,32,116,104,97,116,32,109,117,115,116,32,98,101,32,107,101,112,116,32,111,118,101,114,32,114,101,99,117,114,115,105,111,110,32,105,110,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,97,32,109,97,116,99,104,32,105,110,32,97,110,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,119,97,121,46,32,73,116,32,105,115,32,100,101,115,99,114,105,98,101,100,32,97,115,32,102,111,108,108,111,119,115,32,98,121,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<84,104,101,32,109,97,116,99,104,95,108,105,109,105,116,32,102,105,101,108,100,32,112,114,111,118,105,100,101,115,32,97,32,109,101,97,110,115,32,111,102,32,112,114,101,118,101,110,116,105,110,103,32,80,67,82,69,32,102,114,111,109,32,117,115,105,110,103,10,117,112,32,97,32,118,97,115,116,32,97,109,111,117,110,116,32,111,102,32,114,101,115,111,117,114,99,101,115,32,119,104,101,110,32,114,117,110,110,105,110,103,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,103,111,105,110,103,10,116,111,32,109,97,116,99,104,44,32,98,117,116,32,119,104,105,99,104,32,104,97,118,101,32,97,32,118,101,114,121,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,112,111,115,115,105,98,105,108,105,116,105,101,115,32,105,110,32,116,104,101,105,114,10,115,101,97,114,99,104,32,116,114,101,101,115,46,32,84,104,101,32,99,108,97,115,115,105,99,32,101,120,97,109,112,108,101,32,105,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,117,115,101,115,32,110,101,115,116,101,100,10,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,46,10,10,73,110,116,101,114,110,97,108,108,121,44,32,112,99,114,101,95,101,120,101,99,40,41,32,117,115,101,115,32,97,32,102,117,110,99,116,105,111,110,32,99,97,108,108,101,100,32,109,97,116,99,104,40,41,44,32,119,104,105,99,104,32,105,116,32,99,97,108,108,115,10,114,101,112,101,97,116,101,100,108,121,32,40,115,111,109,101,116,105,109,101,115,32,114,101,99,117,114,115,105,118,101,108,121,41,46,32,84,104,101,32,108,105,109,105,116,32,115,101,116,32,98,121,32,109,97,116,99,104,95,108,105,109,105,116,32,105,115,10,105,109,112,111,115,101,100,32,111,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,100,117,114,105,110,103,32,97,32,109,97,116,99,104,44,10,119,104,105,99,104,32,104,97,115,32,116,104,101,32,101,102,102,101,99,116,32,111,102,32,108,105,109,105,116,105,110,103,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,104,97,116,32,99,97,110,10,116,97,107,101,32,112,108,97,99,101,46,32,70,111,114,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,97,110,99,104,111,114,101,100,44,32,116,104,101,32,99,111,117,110,116,32,114,101,115,116,97,114,116,115,10,102,114,111,109,32,122,101,114,111,32,102,111,114,32,101,97,99,104,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]}]},{p,[],[<<84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,114,117,110,97,119,97,121,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,99,97,110,32,102,97,105,108,32,102,97,115,116,101,114,32,105,102,32,116,104,101,32,108,105,109,105,116,32,105,115,32,108,111,119,101,114,101,100,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46,32,84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,49,48,44,48,48,48,44,48,48,48,32,105,115,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,69,114,108,97,110,103,32,86,77,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,100,111,101,115,32,105,110,32,110,111,32,119,97,121,32,97,102,102,101,99,116,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,105,110,32,116,101,114,109,115,32,111,102,32,34,108,111,110,103,32,114,117,110,110,105,110,103,32,66,73,70,115,34,46,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,97,108,119,97,121,115,32,103,105,118,101,115,32,99,111,110,116,114,111,108,32,98,97,99,107,32,116,111,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,111,102,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,116,32,105,110,116,101,114,118,97,108,115,32,116,104,97,116,32,101,110,115,117,114,101,115,32,116,104,101,32,114,101,97,108,45,116,105,109,101,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,115,121,115,116,101,109,46>>]}]}]},{dt,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,97,110,100,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,32,111,102,32,97,32,109,97,116,99,104,32,105,110,32,97,110,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,119,97,121,44,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<46,32,73,116,32,105,115,32,100,101,115,99,114,105,98,101,100,32,97,115,32,102,111,108,108,111,119,115,32,98,121,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<84,104,101,32,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,32,102,105,101,108,100,32,105,115,32,115,105,109,105,108,97,114,32,116,111,32,109,97,116,99,104,95,108,105,109,105,116,44,32,98,117,116,32,105,110,115,116,101,97,100,10,111,102,32,108,105,109,105,116,105,110,103,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,97,116,32,109,97,116,99,104,40,41,32,105,115,32,99,97,108,108,101,100,44,32,105,116,10,108,105,109,105,116,115,32,116,104,101,32,100,101,112,116,104,32,111,102,32,114,101,99,117,114,115,105,111,110,46,32,84,104,101,32,114,101,99,117,114,115,105,111,110,32,100,101,112,116,104,32,105,115,32,97,32,115,109,97,108,108,101,114,32,110,117,109,98,101,114,10,116,104,97,110,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,99,97,108,108,115,44,32,98,101,99,97,117,115,101,32,110,111,116,32,97,108,108,32,99,97,108,108,115,32,116,111,32,109,97,116,99,104,40,41,32,97,114,101,10,114,101,99,117,114,115,105,118,101,46,32,84,104,105,115,32,108,105,109,105,116,32,105,115,32,111,102,32,117,115,101,32,111,110,108,121,32,105,102,32,105,116,32,105,115,32,115,101,116,32,115,109,97,108,108,101,114,32,116,104,97,110,10,109,97,116,99,104,95,108,105,109,105,116,46,10,10,76,105,109,105,116,105,110,103,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,100,101,112,116,104,32,108,105,109,105,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,109,97,99,104,105,110,101,32,115,116,97,99,107,32,116,104,97,116,10,99,97,110,32,98,101,32,117,115,101,100,44,32,111,114,44,32,119,104,101,110,32,80,67,82,69,32,104,97,115,32,98,101,101,110,32,99,111,109,112,105,108,101,100,32,116,111,32,117,115,101,32,109,101,109,111,114,121,32,111,110,32,116,104,101,32,104,101,97,112,10,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,115,116,97,99,107,44,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,104,101,97,112,32,109,101,109,111,114,121,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,46>>]}]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,86,77,32,117,115,101,115,32,97,32,80,67,82,69,32,108,105,98,114,97,114,121,32,119,104,101,114,101,32,104,101,97,112,32,109,101,109,111,114,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,32,114,101,99,117,114,115,105,111,110,32,111,99,99,117,114,115,46,32,84,104,105,115,32,116,104,101,114,101,102,111,114,101,32,108,105,109,105,116,115,32,116,104,101,32,117,115,101,32,111,102,32,109,97,99,104,105,110,101,32,104,101,97,112,44,32,110,111,116,32,67,32,115,116,97,99,107,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,97,32,108,111,119,101,114,32,118,97,108,117,101,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,109,97,116,99,104,101,115,32,119,105,116,104,32,100,101,101,112,32,114,101,99,117,114,115,105,111,110,32,102,97,105,108,105,110,103,44,32,119,104,101,110,32,116,104,101,121,32,115,104,111,117,108,100,32,104,97,118,101,32,109,97,116,99,104,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,41,46,10,123,109,97,116,99,104,44,91,123,48,44,49,52,125,44,123,48,44,49,51,125,93,125,10,50,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,44,91,123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,53,125,93,41,46,10,110,111,109,97,116,99,104,10,51,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,44,91,123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,53,125,44,114,101,112,111,114,116,95,101,114,114,111,114,115,93,41,46,10,123,101,114,114,111,114,44,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,125>>]}]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,97,114,101,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,114,97,114,101,32,99,97,115,101,115,46,32,85,110,100,101,114,115,116,97,110,100,105,110,103,32,111,102,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,105,110,116,101,114,110,97,108,115,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,98,101,102,111,114,101,32,116,97,109,112,101,114,105,110,103,32,119,105,116,104,32,116,104,101,115,101,32,108,105,109,105,116,115,46>>]}]},{dt,[],[{code,[],[<<123,111,102,102,115,101,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,32,109,97,116,99,104,105,110,103,32,97,116,32,116,104,101,32,111,102,102,115,101,116,32,40,112,111,115,105,116,105,111,110,41,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,101,32,111,102,102,115,101,116,32,105,115,32,122,101,114,111,45,98,97,115,101,100,44,32,115,111,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,111,102,102,115,101,116,44,48,125>>]},<<32,40,97,108,108,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,41,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{dd,[],[{p,[],[<<79,118,101,114,114,105,100,101,115,32,116,104,101,32,100,101,102,97,117,108,116,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,105,99,104,32,105,115,32,76,70,32,40,65,83,67,73,73,32,49,48,41,32,105,110,32,69,114,108,97,110,103,46>>]},{dl,[],[{dt,[],[{code,[],[<<99,114>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,67,82,32,40,65,83,67,73,73,32,49,51,41,46>>]}]},{dt,[],[{code,[],[<<108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,76,70,32,40,65,83,67,73,73,32,49,48,41,44,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<99,114,108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,67,82,76,70,32,40,65,83,67,73,73,32,49,51,32,102,111,108,108,111,119,101,100,32,98,121,32,65,83,67,73,73,32,49,48,41,32,115,101,113,117,101,110,99,101,46>>]}]},{dt,[],[{code,[],[<<97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,105,115,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]}]},{dt,[],[{code,[],[<<97,110,121>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115,32,97,98,111,118,101,44,32,97,110,100,32,116,104,101,32,85,110,105,99,111,100,101,32,115,101,113,117,101,110,99,101,115,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,44,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,44,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,67,82,32,76,70,44,32,111,114,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,44,32,110,111,116,32,116,104,101,32,85,110,105,99,111,100,101,45,115,112,101,99,105,102,105,99,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,46,32,40,79,118,101,114,114,105,100,101,115,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,46,41>>]}]},{dt,[],[{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,116,104,101,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,67,82,76,70,44,32,97,110,100,32,115,111,32,111,110,44,32,116,104,101,32,100,101,102,97,117,108,116,41,46,32,40,79,118,101,114,114,105,100,101,115,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,46,41>>]}]},{dt,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125>>]},<<47>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,105,99,104,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,110,100,32,105,110,32,119,104,97,116,32,102,111,114,109,97,116,46,32,66,121,32,100,101,102,97,117,108,116,44,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,99,97,112,116,117,114,101,115,32,97,108,108,32,111,102,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,115,116,114,105,110,103,32,97,110,100,32,97,108,108,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,40,97,108,108,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,112,116,117,114,101,100,41,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32,40,122,101,114,111,45,98,97,115,101,100,41,32,105,110,100,101,120,101,115,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,115,112,101,99,105,102,105,101,100,32,97,115,32>>,{code,[],[<<123,79,102,102,115,101,116,44,76,101,110,103,116,104,125>>]},<<32,112,97,105,114,115,32,40,116,104,101,32>>,{code,[],[<<105,110,100,101,120>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<32,111,102,32,99,97,112,116,117,114,105,110,103,41,46>>]},{p,[],[<<65,115,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,32,114,101,116,117,114,110,115,44,32,97,115,32,102,105,114,115,116,32,97,110,100,32,111,110,108,121,32,99,97,112,116,117,114,101,100,32,115,116,114,105,110,103,44,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,40,34,97,98,99,100,34,32,105,110,32,116,104,101,32,109,105,100,100,108,101,41,32,97,115,32,97,110,32,105,110,100,101,120,32,112,97,105,114,32>>,{code,[],[<<123,51,44,52,125>>]},<<44,32,119,104,101,114,101,32,99,104,97,114,97,99,116,101,114,32,112,111,115,105,116,105,111,110,115,32,97,114,101,32,122,101,114,111,45,98,97,115,101,100,44,32,106,117,115,116,32,97,115,32,105,110,32,111,102,102,115,101,116,115,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,97,98,99,100,34,44,91,93,41,46>>]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,116,104,105,115,32,99,97,108,108,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<65,110,111,116,104,101,114,32,40,97,110,100,32,113,117,105,116,101,32,99,111,109,109,111,110,41,32,99,97,115,101,32,105,115,32,119,104,101,114,101,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,97,108,108,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,97,98,99,100,46,42,34,44,91,93,41,46>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,108,121,32,112,111,105,110,116,115,32,111,117,116,32,97,108,108,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,98,101,103,105,110,110,105,110,103,32,97,116,32,105,110,100,101,120,32,48,44,32,97,110,100,32,105,116,32,105,115,32,49,48,32,99,104,97,114,97,99,116,101,114,115,32,108,111,110,103,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,93,125>>]}]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,111,110,116,97,105,110,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,108,105,107,101,32,105,110,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,97,98,99,100,41,46,42,34,44,91,93,41,46>>]}]},{p,[],[<<97,108,108,32,111,102,32,116,104,101,32,109,97,116,99,104,101,100,32,115,117,98,106,101,99,116,32,105,115,32,99,97,112,116,117,114,101,100,44,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,44,123,51,44,52,125,93,125>>]}]},{p,[],[<<84,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,103,105,118,101,115,32,116,104,101,32,102,105,114,115,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,110,32,116,104,101,32,108,105,115,116,32,97,110,100,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,111,114,100,101,114,32,116,104,101,121,32,111,99,99,117,114,114,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,101,32,99,97,112,116,117,114,101,32,116,117,112,108,101,32,105,115,32,98,117,105,108,116,32,117,112,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<86,97,108,117,101,83,112,101,99>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,105,99,104,32,99,97,112,116,117,114,101,100,32,40,115,117,98,41,112,97,116,116,101,114,110,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32>>,{code,[],[<<86,97,108,117,101,83,112,101,99>>]},<<32,99,97,110,32,101,105,116,104,101,114,32,98,101,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,97,32,112,114,101,100,101,102,105,110,101,100,32,115,101,116,32,111,102,32,114,101,116,117,114,110,32,118,97,108,117,101,115,44,32,111,114,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,105,110,100,101,120,101,115,32,111,114,32,116,104,101,32,110,97,109,101,115,32,111,102,32,115,112,101,99,105,102,105,99,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,114,101,116,117,114,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,112,114,101,100,101,102,105,110,101,100,32,115,101,116,115,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<65,108,108,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,46,32,84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<97,108,108,95,110,97,109,101,115>>]}]},{dd,[],[{p,[],[<<65,108,108,32>>,{em,[],[<<110,97,109,101,100>>]},<<32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,115,32,105,102,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32,97,108,108,32,116,104,101,32,110,97,109,101,115,32>>,{em,[],[<<105,110,32,97,108,112,104,97,98,101,116,105,99,97,108,32,111,114,100,101,114>>]},<<32,119,97,115,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,32,108,105,115,116,32,111,102,32,97,108,108,32,110,97,109,101,115,32,99,97,110,32,97,108,115,111,32,98,101,32,114,101,116,114,105,101,118,101,100,32,119,105,116,104,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,105,110,115,112,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,110,115,112,101,99,116,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<102,105,114,115,116>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,116,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46,32,65,108,108,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,100,105,115,99,97,114,100,101,100,46>>]}]},{dt,[],[{code,[],[<<97,108,108,95,98,117,116,95,102,105,114,115,116>>]}]},{dd,[],[{p,[],[<<65,108,108,32,98,117,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,98,117,116,32,110,111,116,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,115,32,97,32,119,104,111,108,101,32,109,97,116,99,104,101,115,32,97,32,108,97,114,103,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,98,117,116,32,116,104,101,32,112,97,114,116,32,121,111,117,32,97,114,101,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,105,115,32,105,110,32,97,110,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,46,32,73,102,32,116,104,101,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32>>,{code,[],[<<108,105,115,116>>]},<<32,111,114,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<44,32,110,111,116,32,114,101,116,117,114,110,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,121,111,117,32,97,114,101,32,110,111,116,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,105,115,32,97,32,103,111,111,100,32,119,97,121,32,116,111,32,111,112,116,105,109,105,122,101,46>>]}]},{dt,[],[{code,[],[<<110,111,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,110,111,32,109,97,116,99,104,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,103,105,118,101,115,32,116,104,101,32,115,105,110,103,108,101,32,97,116,111,109,32>>,{code,[],[<<109,97,116,99,104>>]},<<32,97,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,115,117,99,99,101,115,115,102,117,108,108,121,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32>>,{code,[],[<<123,109,97,116,99,104,44,32,108,105,115,116,40,41,125>>]},<<32,114,101,116,117,114,110,46,32,83,112,101,99,105,102,121,105,110,103,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,98,101,104,97,118,105,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,118,97,108,117,101,32,108,105,115,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,105,110,100,101,120,101,115,32,102,111,114,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,114,101,116,117,114,110,44,32,119,104,101,114,101,32,105,110,100,101,120,32,48,32,105,115,32,102,111,114,32,97,108,108,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,49,32,105,115,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,110,100,32,115,111,32,111,110,46,32,87,104,101,110,32,117,115,105,110,103,32,110,97,109,101,100,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,40,115,101,101,32,98,101,108,111,119,41,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,111,110,101,32,99,97,110,32,117,115,101,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<115,32,111,114,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<115,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<34,46,42,40,97,98,99,100,41,46,42,34>>]}]},{p,[],[<<109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,115,116,114,105,110,103,32,34,65,66,67,97,98,99,100,65,66,67,34,44,32,99,97,112,116,117,114,105,110,103,32,111,110,108,121,32,116,104,101,32,34,97,98,99,100,34,32,112,97,114,116,32,40,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,32,115,117,98,112,97,116,116,101,114,110,41,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,49,93,125,93,41,46>>]}]},{p,[],[<<84,104,101,32,99,97,108,108,32,103,105,118,101,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,115,117,108,116,44,32,97,115,32,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,34,40,97,98,99,100,41,34,44,32,109,97,116,99,104,105,110,103,32,34,97,98,99,100,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,116,32,40,122,101,114,111,45,98,97,115,101,100,41,32,112,111,115,105,116,105,111,110,32,51,44,32,111,102,32,108,101,110,103,116,104,32,52,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,115,97,109,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,98,117,116,32,119,105,116,104,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,101,120,112,108,105,99,105,116,108,121,32,110,97,109,101,100,32,39,70,79,79,39,58>>]},{pre,[],[{code,[],[<<34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34>>]}]},{p,[],[<<87,105,116,104,32,116,104,105,115,32,101,120,112,114,101,115,115,105,111,110,44,32,119,101,32,99,111,117,108,100,32,115,116,105,108,108,32,103,105,118,101,32,116,104,101,32,105,110,100,101,120,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,49,93,125,93,41,46>>]}]},{p,[],[<<103,105,118,105,110,103,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,98,101,102,111,114,101,46,32,66,117,116,44,32,97,115,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,97,109,101,100,44,32,119,101,32,99,97,110,32,97,108,115,111,32,115,112,101,99,105,102,121,32,105,116,115,32,110,97,109,101,32,105,110,32,116,104,101,32,118,97,108,117,101,32,108,105,115,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,39,70,79,79,39,93,125,93,41,46>>]}]},{p,[],[<<84,104,105,115,32,119,111,117,108,100,32,103,105,118,101,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,101,97,114,108,105,101,114,32,101,120,97,109,112,108,101,115,44,32,110,97,109,101,108,121,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<84,104,101,32,118,97,108,117,101,115,32,108,105,115,116,32,99,97,110,32,115,112,101,99,105,102,121,32,105,110,100,101,120,101,115,32,111,114,32,110,97,109,101,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,118,97,114,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,116,121,112,101,46,32,73,102,32,116,104,101,32,116,121,112,101,32,105,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<44,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,45,49,44,48,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,102,111,114,32,118,97,108,117,101,115,32,119,105,116,104,32,110,111,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,98,117,116,32,102,111,114,32,116,104,101,32,111,116,104,101,114,32,116,121,112,101,115,32,40>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,97,110,100,32>>,{code,[],[<<108,105,115,116>>]},<<41,44,32,116,104,101,32,118,97,108,117,101,115,32,97,114,101,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,111,114,32,108,105,115,116,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]}]},{dt,[],[{code,[],[<<84,121,112,101>>]}]},{dd,[],[{p,[],[<<79,112,116,105,111,110,97,108,108,121,32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,73,102,32,111,109,105,116,116,101,100,44,32,116,104,101,32,100,101,102,97,117,108,116,32,111,102,32>>,{code,[],[<<105,110,100,101,120>>]},<<32,105,115,32,117,115,101,100,46>>]},{p,[],[{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<105,110,100,101,120>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,112,97,105,114,115,32,111,102,32,98,121,116,101,32,105,110,100,101,120,101,115,32,105,110,116,111,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,97,110,100,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,40,97,115,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,97,115,32,102,108,97,116,116,101,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,99,111,100,101,58,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<32,98,101,102,111,114,101,32,109,97,116,99,104,105,110,103,41,46,32,78,111,116,105,99,101,32,116,104,97,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,115,117,108,116,115,32,105,110,32>>,{em,[],[<<98,121,116,101,45,111,114,105,101,110,116,101,100>>]},<<32,105,110,100,101,120,101,115,32,105,110,32,97,32,40,112,111,115,115,105,98,108,121,32,118,105,114,116,117,97,108,41,32>>,{em,[],[<<85,84,70,45,56,32,101,110,99,111,100,101,100>>]},<<32,98,105,110,97,114,121,46,32,65,32,98,121,116,101,32,105,110,100,101,120,32,116,117,112,108,101,32>>,{code,[],[<<123,48,44,50,125>>]},<<32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,114,101,112,114,101,115,101,110,116,32,111,110,101,32,111,114,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,119,104,101,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,105,110,32,101,102,102,101,99,116,46,32,84,104,105,115,32,99,97,110,32,115,101,101,109,32,99,111,117,110,116,101,114,45,105,110,116,117,105,116,105,118,101,44,32,98,117,116,32,104,97,115,32,98,101,101,110,32,100,101,101,109,101,100,32,116,104,101,32,109,111,115,116,32,101,102,102,101,99,116,105,118,101,32,97,110,100,32,117,115,101,102,117,108,32,119,97,121,32,116,111,32,100,111,32,105,116,46,32,84,111,32,114,101,116,117,114,110,32,108,105,115,116,115,32,105,110,115,116,101,97,100,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,115,105,109,112,108,101,114,32,99,111,100,101,32,105,102,32,116,104,97,116,32,105,115,32,100,101,115,105,114,101,100,46,32,84,104,105,115,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<108,105,115,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,109,97,116,99,104,105,110,103,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,108,105,115,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,69,114,108,97,110,103,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<115,41,46,32,73,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,117,115,101,100,32,105,110,32,99,111,109,98,105,110,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,99,111,110,116,97,105,110,32,98,121,116,101,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,118,97,108,105,100,32,85,84,70,45,56,32,40,92,67,32,109,97,116,99,104,101,115,32,98,121,116,101,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,99,104,97,114,97,99,116,101,114,32,101,110,99,111,100,105,110,103,41,46,32,73,110,32,116,104,97,116,32,99,97,115,101,32,116,104,101,32>>,{code,[],[<<108,105,115,116>>]},<<32,99,97,112,116,117,114,105,110,103,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,116,104,101,32,115,97,109,101,32,116,121,112,101,115,32,111,102,32,116,117,112,108,101,115,32,116,104,97,116,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,97,99,116,101,114,115,95,116,111,95,108,105,115,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,99,111,100,101,58,99,104,97,114,97,99,116,101,114,115,95,116,111,95,108,105,115,116,47,50>>]}]},<<32,99,97,110,32,114,101,116,117,114,110,44,32,110,97,109,101,108,121,32,116,104,114,101,101,45,116,117,112,108,101,115,32,119,105,116,104,32,116,97,103,32>>,{code,[],[<<105,110,99,111,109,112,108,101,116,101>>]},<<32,111,114,32>>,{code,[],[<<101,114,114,111,114>>]},<<44,32,116,104,101,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,111,110,118,101,114,116,101,100,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,116,104,101,32,105,110,118,97,108,105,100,32,85,84,70,45,56,32,116,97,105,108,32,111,102,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,97,115,32,97,32,98,105,110,97,114,121,46,32,84,104,101,32,98,101,115,116,32,115,116,114,97,116,101,103,121,32,105,115,32,116,111,32,97,118,111,105,100,32,117,115,105,110,103,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,119,104,101,110,32,99,97,112,116,117,114,105,110,103,32,108,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,109,97,116,99,104,105,110,103,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,98,105,110,97,114,105,101,115,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,117,115,101,100,44,32,116,104,101,115,101,32,98,105,110,97,114,105,101,115,32,97,114,101,32,105,110,32,85,84,70,45,56,46,32,73,102,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,105,115,32,117,115,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,98,105,110,97,114,105,101,115,32,99,97,110,32,98,101,32,105,110,118,97,108,105,100,32,85,84,70,45,56,46>>]}]}]}]}]},{p,[],[<<73,110,32,103,101,110,101,114,97,108,44,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,119,101,114,101,32,110,111,116,32,97,115,115,105,103,110,101,100,32,97,32,118,97,108,117,101,32,105,110,32,116,104,101,32,109,97,116,99,104,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,45,49,44,48,125>>]},<<32,119,104,101,110,32>>,{code,[],[<<116,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<46,32,85,110,97,115,115,105,103,110,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,111,114,32,108,105,115,116,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,102,111,114,32,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<34,46,42,40,40,63,60,70,79,79,62,97,98,100,100,41,124,97,40,46,46,100,41,41,46,42,34>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,116,104,114,101,101,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,119,104,101,114,101,32,116,104,101,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,112,111,115,105,116,105,111,110,32,100,101,116,101,114,109,105,110,101,115,32,116,104,101,32,111,114,100,101,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,104,101,110,99,101,32>>,{code,[],[<<40,40,63,60,70,79,79,62,97,98,100,100,41,124,97,40,46,46,100,41,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,49,44,32>>,{code,[],[<<40,63,60,70,79,79,62,97,98,100,100,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,50,44,32,97,110,100,32>>,{code,[],[<<40,46,46,100,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,51,46,32,87,104,101,110,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,116,114,105,110,103,58>>]},{pre,[],[{code,[],[<<34,65,66,67,97,98,99,100,65,66,67,34>>]}]},{p,[],[<<116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,116,32,105,110,100,101,120,32,50,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,44,32,97,115,32,34,97,98,100,100,34,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,44,32,98,117,116,32,116,104,101,32,99,111,109,112,108,101,116,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,40,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,32>>,{code,[],[<<97,40,46,46,100,41>>]},<<41,46,32,84,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,116,32,105,110,100,101,120,32,50,32,105,115,32,116,104,101,114,101,102,111,114,101,32,117,110,97,115,115,105,103,110,101,100,32,97,110,100,32,116,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,44,123,51,44,52,125,44,123,45,49,44,48,125,44,123,52,44,51,125,93,125>>]}]},{p,[],[<<83,101,116,116,105,110,103,32,116,104,101,32,99,97,112,116,117,114,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,116,111,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,103,105,118,101,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,60,60,34,65,66,67,97,98,99,100,65,66,67,34,62,62,44,60,60,34,97,98,99,100,34,62,62,44,60,60,62,62,44,60,60,34,98,99,100,34,62,62,93,125>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,40>>,{code,[],[<<60,60,62,62>>]},<<41,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,117,110,97,115,115,105,103,110,101,100,32,115,117,98,112,97,116,116,101,114,110,46,32,73,110,32,116,104,101,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,99,97,115,101,44,32,115,111,109,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,116,104,101,114,101,102,111,114,101,32,108,111,115,116,44,32,97,115,32>>,{code,[],[<<60,60,62,62>>]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,99,97,112,116,117,114,101,100,46>>]},{p,[],[<<73,102,32,100,105,102,102,101,114,101,110,116,105,97,116,105,111,110,32,98,101,116,119,101,101,110,32,101,109,112,116,121,32,109,97,116,99,104,101,115,32,97,110,100,32,110,111,110,45,101,120,105,115,116,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,115,32,110,101,99,101,115,115,97,114,121,44,32,117,115,101,32,116,104,101,32>>,{code,[],[<<116,121,112,101>>]},<<32>>,{code,[],[<<105,110,100,101,120>>]},<<32,97,110,100,32,100,111,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,116,111,32,116,104,101,32,102,105,110,97,108,32,116,121,112,101,32,105,110,32,69,114,108,97,110,103,32,99,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,115,112,101,99,105,105,102,105,101,100,44,32,116,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,102,102,101,99,116,115,32,101,97,99,104,32,109,97,116,99,104,32,115,101,112,97,114,97,116,101,108,121,44,32,115,111,32,116,104,97,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,99,97,99,98,34,44,34,99,40,97,124,98,41,34,44,91,103,108,111,98,97,108,44,123,99,97,112,116,117,114,101,44,91,49,93,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,91,34,97,34,93,44,91,34,98,34,93,93,125>>]}]}]}]},{p,[],[<<70,111,114,32,97,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,111,112,116,105,111,110,115,32,111,110,108,121,32,97,102,102,101,99,116,105,110,103,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,115,116,101,112,44,32,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,52,49,57>>,signature => [{attribute,76,spec,{{run,3},[{type,76,bounded_fun,[{type,76,'fun',[{type,76,product,[{var,76,'Subject'},{var,76,'RE'},{var,76,'Options'}]},{type,76,union,[{type,76,tuple,[{atom,76,match},{var,76,'Captured'}]},{atom,77,match},{atom,78,nomatch},{type,79,tuple,[{atom,79,error},{var,79,'ErrType'}]}]}]},[{type,80,constraint,[{atom,80,is_subtype},[{var,80,'Subject'},{type,80,union,[{type,80,iodata,[]},{remote_type,80,[{atom,80,unicode},{atom,80,charlist},[]]}]}]]},{type,81,constraint,[{atom,81,is_subtype},[{var,81,'RE'},{type,81,union,[{user_type,81,mp,[]},{type,81,iodata,[]},{remote_type,81,[{atom,81,unicode},{atom,81,charlist},[]]}]}]]},{type,82,constraint,[{atom,82,is_subtype},[{var,82,'Options'},{type,82,list,[{var,82,'Option'}]}]]},{type,83,constraint,[{atom,83,is_subtype},[{var,83,'Option'},{type,83,union,[{atom,83,anchored},{atom,83,global},{atom,83,notbol},{atom,83,noteol},{atom,83,notempty},{atom,84,notempty_atstart},{atom,84,report_errors},{type,85,tuple,[{atom,85,offset},{type,85,non_neg_integer,[]}]},{type,86,tuple,[{atom,86,match_limit},{type,86,non_neg_integer,[]}]},{type,87,tuple,[{atom,87,match_limit_recursion},{type,87,non_neg_integer,[]}]},{type,88,tuple,[{atom,88,newline},{ann_type,88,[{var,88,'NLSpec'},{user_type,88,nl_spec,[]}]}]},{atom,89,bsr_anycrlf},{atom,89,bsr_unicode},{type,89,tuple,[{atom,89,capture},{var,89,'ValueSpec'}]},{type,90,tuple,[{atom,90,capture},{var,90,'ValueSpec'},{var,90,'Type'}]},{var,90,'CompileOpt'}]}]]},{type,91,constraint,[{atom,91,is_subtype},[{var,91,'Type'},{type,91,union,[{atom,91,index},{atom,91,list},{atom,91,binary}]}]]},{type,92,constraint,[{atom,92,is_subtype},[{var,92,'ValueSpec'},{type,92,union,[{atom,92,all},{atom,92,all_but_first},{atom,92,all_names},{atom,92,first},{atom,92,none},{var,92,'ValueList'}]}]]},{type,93,constraint,[{atom,93,is_subtype},[{var,93,'ValueList'},{type,93,list,[{var,93,'ValueID'}]}]]},{type,94,constraint,[{atom,94,is_subtype},[{var,94,'ValueID'},{type,94,union,[{type,94,integer,[]},{type,94,string,[]},{type,94,atom,[]}]}]]},{type,95,constraint,[{atom,95,is_subtype},[{var,95,'CompileOpt'},{user_type,95,compile_option,[]}]]},{type,96,constraint,[{atom,96,is_subtype},[{var,96,'Captured'},{type,96,union,[{type,96,list,[{var,96,'CaptureData'}]},{type,96,list,[{type,96,list,[{var,96,'CaptureData'}]}]}]}]]},{type,97,constraint,[{atom,97,is_subtype},[{var,97,'CaptureData'},{type,97,union,[{type,97,tuple,[{type,97,integer,[]},{type,97,integer,[]}]},{var,98,'ListConversionData'},{type,99,binary,[]}]}]]},{type,100,constraint,[{atom,100,is_subtype},[{var,100,'ListConversionData'},{type,100,union,[{type,100,string,[]},{type,101,tuple,[{atom,101,error},{type,101,string,[]},{type,101,binary,[]}]},{type,102,tuple,[{atom,102,incomplete},{type,102,string,[]},{type,102,binary,[]}]}]}]]},{type,103,constraint,[{atom,103,is_subtype},[{var,103,'ErrType'},{type,103,union,[{atom,103,match_limit},{atom,103,match_limit_recursion},{type,103,tuple,[{atom,103,compile},{var,103,'CompileErr'}]}]}]]},{type,104,constraint,[{atom,104,is_subtype},[{var,104,'CompileErr'},{type,104,tuple,[{ann_type,104,[{var,104,'ErrString'},{type,104,string,[]}]},{ann_type,104,[{var,104,'Position'},{type,104,non_neg_integer,[]}]}]}]]}]]}]}}]}},{{function,split,2},[{file,[114,101,46,101,114,108]},{location,153}],[<<115,112,108,105,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<115,112,108,105,116,40,83,117,98,106,101,99,116,44,32,82,69,44,32,91,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,57,57,52>>,signature => [{attribute,153,spec,{{split,2},[{type,153,bounded_fun,[{type,153,'fun',[{type,153,product,[{var,153,'Subject'},{var,153,'RE'}]},{var,153,'SplitList'}]},[{type,154,constraint,[{atom,154,is_subtype},[{var,154,'Subject'},{type,154,union,[{type,154,iodata,[]},{remote_type,154,[{atom,154,unicode},{atom,154,charlist},[]]}]}]]},{type,155,constraint,[{atom,155,is_subtype},[{var,155,'RE'},{type,155,union,[{user_type,155,mp,[]},{type,155,iodata,[]}]}]]},{type,156,constraint,[{atom,156,is_subtype},[{var,156,'SplitList'},{type,156,list,[{type,156,union,[{type,156,iodata,[]},{remote_type,156,[{atom,156,unicode},{atom,156,charlist},[]]}]}]}]]}]]}]}}]}},{{function,split,3},[{file,[114,101,46,101,114,108]},{location,166}],[<<115,112,108,105,116,47,51>>],#{<<101,110>> => [{p,[],[<<83,112,108,105,116,115,32,116,104,101,32,105,110,112,117,116,32,105,110,116,111,32,112,97,114,116,115,32,98,121,32,102,105,110,100,105,110,103,32,116,111,107,101,110,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,115,117,112,112,108,105,101,100,46,32,84,104,101,32,115,112,108,105,116,116,105,110,103,32,105,115,32,98,97,115,105,99,97,108,108,121,32,100,111,110,101,32,98,121,32,114,117,110,110,105,110,103,32,97,32,103,108,111,98,97,108,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,32,97,110,100,32,100,105,118,105,100,105,110,103,32,116,104,101,32,105,110,105,116,105,97,108,32,115,116,114,105,110,103,32,119,104,101,114,101,118,101,114,32,97,32,109,97,116,99,104,32,111,99,99,117,114,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,105,115,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,111,117,116,112,117,116,46>>]},{p,[],[<<65,115,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,97,110,32>>,{code,[],[<<109,112,40,41>>]},<<32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,113,117,105,114,101,115,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,116,111,32,98,101,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,105,109,112,108,105,99,105,116,108,121,32,97,110,100,32,116,104,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,98,111,116,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,114,101,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<115,46>>]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,105,115,32,103,105,118,101,110,32,97,115,32,97,32,108,105,115,116,32,111,102,32,34,115,116,114,105,110,103,115,34,44,32,116,104,101,32,112,114,101,102,101,114,114,101,100,32,100,97,116,97,32,116,121,112,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,111,112,116,105,111,110,32>>,{code,[],[<<114,101,116,117,114,110>>]},<<32,40,100,101,102,97,117,108,116,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<41,46>>]},{p,[],[<<73,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,32,97,115,32,119,101,108,108,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,110,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,34,44,34,103,34,93>>]}]},{p,[],[<<119,104,105,108,101>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,40,91,108,110,93,41,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,108,34,44,34,97,34,44,34,110,34,44,34,103,34,93>>]}]},{p,[],[<<84,104,101,32,116,101,120,116,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,40,109,97,114,107,101,100,32,98,121,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,41,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,32,119,104,101,114,101,32,105,116,32,119,97,115,32,102,111,117,110,100,46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,99,111,110,99,97,116,101,110,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,32,115,112,108,105,116,32,119,104,101,114,101,32,116,104,101,32,119,104,111,108,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,32,115,105,110,103,108,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,40,97,115,32,105,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,41,32,97,108,119,97,121,115,32,114,101,115,117,108,116,115,32,105,110,32,116,104,101,32,111,114,105,103,105,110,97,108,32,115,116,114,105,110,103,46>>]},{p,[],[<<65,115,32,116,104,101,114,101,32,105,115,32,110,111,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,102,111,114,32,116,104,101,32,108,97,115,116,32,112,97,114,116,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,40,116,104,101,32,34,103,34,41,44,32,110,111,116,104,105,110,103,32,105,115,32,105,110,115,101,114,116,101,100,32,97,102,116,101,114,32,116,104,97,116,46,32,84,111,32,109,97,107,101,32,116,104,101,32,103,114,111,117,112,32,111,102,32,115,116,114,105,110,103,115,32,97,110,100,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,109,111,114,101,32,111,98,118,105,111,117,115,44,32,111,110,101,32,99,97,110,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<103,114,111,117,112>>]},<<44,32,119,104,105,99,104,32,103,114,111,117,112,115,32,116,111,103,101,116,104,101,114,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,119,104,101,110,32,116,104,101,32,115,116,114,105,110,103,32,119,97,115,32,115,112,108,105,116,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,40,91,108,110,93,41,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,103,114,111,117,112,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,91,34,69,114,34,44,34,108,34,93,44,91,34,97,34,44,34,110,34,93,44,91,34,103,34,93,93>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,102,105,114,115,116,32,109,97,116,99,104,101,100,32,116,104,101,32,34,108,34,44,32,99,97,117,115,105,110,103,32,34,69,114,34,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,112,97,114,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46,32,87,104,101,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,100,44,32,116,104,101,32,40,111,110,108,121,41,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,98,111,117,110,100,32,116,111,32,116,104,101,32,34,108,34,44,32,115,111,32,116,104,101,32,34,108,34,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,103,114,111,117,112,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,34,69,114,34,46,32,84,104,101,32,110,101,120,116,32,109,97,116,99,104,32,105,115,32,111,102,32,116,104,101,32,34,110,34,44,32,109,97,107,105,110,103,32,34,97,34,32,116,104,101,32,110,101,120,116,32,112,97,114,116,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,65,115,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,105,115,32,98,111,117,110,100,32,116,111,32,115,117,98,115,116,114,105,110,103,32,34,110,34,32,105,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,34,110,34,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,116,111,32,116,104,105,115,32,103,114,111,117,112,46,32,84,104,101,32,108,97,115,116,32,103,114,111,117,112,32,99,111,110,115,105,115,116,115,32,111,102,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,116,114,105,110,103,44,32,97,115,32,110,111,32,109,111,114,101,32,109,97,116,99,104,101,115,32,97,114,101,32,102,111,117,110,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,108,108,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,115,44,32,97,114,101,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,34,44,91,93,93>>]}]},{p,[],[<<97,115,32,116,104,101,32,109,97,116,99,104,105,110,103,32,111,102,32,116,104,101,32,34,103,34,32,105,110,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,108,101,97,118,101,115,32,97,110,32,101,109,112,116,121,32,114,101,115,116,44,32,119,104,105,99,104,32,105,115,32,97,108,115,111,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,100,105,102,102,101,114,115,32,102,114,111,109,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,115,112,108,105,116,32,102,117,110,99,116,105,111,110,32,105,110,32,80,101,114,108,44,32,119,104,101,114,101,32,101,109,112,116,121,32,115,116,114,105,110,103,115,32,97,116,32,116,104,101,32,101,110,100,32,97,114,101,32,98,121,32,100,101,102,97,117,108,116,32,114,101,109,111,118,101,100,46,32,84,111,32,103,101,116,32,116,104,101,32,34,116,114,105,109,109,105,110,103,34,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,80,101,114,108,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<116,114,105,109>>]},<<32,97,115,32,97,110,32,111,112,116,105,111,110,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,116,114,105,109,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,34,93>>]}]},{p,[],[<<84,104,101,32,34,116,114,105,109,34,32,111,112,116,105,111,110,32,115,97,121,115,59,32,34,103,105,118,101,32,109,101,32,97,115,32,109,97,110,121,32,112,97,114,116,115,32,97,115,32,112,111,115,115,105,98,108,101,32,101,120,99,101,112,116,32,116,104,101,32,101,109,112,116,121,32,111,110,101,115,34,44,32,119,104,105,99,104,32,115,111,109,101,116,105,109,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,46,32,89,111,117,32,99,97,110,32,97,108,115,111,32,115,112,101,99,105,102,121,32,104,111,119,32,109,97,110,121,32,112,97,114,116,115,32,121,111,117,32,119,97,110,116,44,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44>>]},<<78>>,{code,[],[<<125>>]},<<58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,123,112,97,114,116,115,44,50,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,103,34,93>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,108,97,115,116,32,112,97,114,116,32,105,115,32,34,97,110,103,34,44,32,110,111,116,32,34,97,110,34,44,32,97,115,32,115,112,108,105,116,116,105,110,103,32,119,97,115,32,115,112,101,99,105,102,105,101,100,32,105,110,116,111,32,116,119,111,32,112,97,114,116,115,44,32,97,110,100,32,116,104,101,32,115,112,108,105,116,116,105,110,103,32,115,116,111,112,115,32,119,104,101,110,32,101,110,111,117,103,104,32,112,97,114,116,115,32,97,114,101,32,103,105,118,101,110,44,32,119,104,105,99,104,32,105,115,32,119,104,121,32,116,104,101,32,114,101,115,117,108,116,32,100,105,102,102,101,114,115,32,102,114,111,109,32,116,104,97,116,32,111,102,32>>,{code,[],[<<116,114,105,109>>]},<<46>>]},{p,[],[<<77,111,114,101,32,116,104,97,110,32,116,104,114,101,101,32,112,97,114,116,115,32,97,114,101,32,110,111,116,32,112,111,115,115,105,98,108,101,32,119,105,116,104,32,116,104,105,115,32,105,110,100,97,116,97,44,32,115,111>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,123,112,97,114,116,115,44,52,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,100,101,102,97,117,108,116,44,32,119,104,105,99,104,32,105,115,32,116,111,32,98,101,32,118,105,101,119,101,100,32,97,115,32,34,97,110,32,105,110,102,105,110,105,116,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,34,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<48>>]},<<32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,111,112,116,105,111,110,32>>,{code,[],[<<116,114,105,109>>]},<<46,32,73,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,99,97,112,116,117,114,101,100,44,32,101,109,112,116,121,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,109,97,116,99,104,101,100,32,97,116,32,116,104,101,32,101,110,100,32,97,114,101,32,97,108,115,111,32,115,116,114,105,112,112,101,100,32,102,114,111,109,32,116,104,101,32,114,101,115,117,108,116,32,105,102,32>>,{code,[],[<<116,114,105,109>>]},<<32,111,114,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<116,114,105,109>>]},<<32,98,101,104,97,118,105,111,114,32,99,111,114,114,101,115,112,111,110,100,115,32,101,120,97,99,116,108,121,32,116,111,32,116,104,101,32,80,101,114,108,32,100,101,102,97,117,108,116,46,32>>,{code,[],[<<123,112,97,114,116,115,44,78,125>>]},<<44,32,119,104,101,114,101,32,78,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,44,32,99,111,114,114,101,115,112,111,110,100,115,32,101,120,97,99,116,108,121,32,116,111,32,116,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,119,105,116,104,32,97,32,112,111,115,105,116,105,118,101,32,110,117,109,101,114,105,99,97,108,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,46,32,84,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32>>,{code,[],[<<115,112,108,105,116,47,51>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,119,104,101,110,32,97,32,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,116,104,101,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,32,102,111,114,32,116,104,101,32,80,101,114,108,32,114,111,117,116,105,110,101,46>>]},{p,[],[<<83,117,109,109,97,114,121,32,111,102,32,111,112,116,105,111,110,115,32,110,111,116,32,112,114,101,118,105,111,117,115,108,121,32,100,101,115,99,114,105,98,101,100,32,102,111,114,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,114,101,116,117,114,110,44,82,101,116,117,114,110,84,121,112,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,104,111,119,32,116,104,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,111,114,105,103,105,110,97,108,32,115,116,114,105,110,103,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,46,32,86,97,108,105,100,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<105,111,100,97,116,97>>]}]},{dd,[],[{p,[],[<<84,104,101,32,118,97,114,105,97,110,116,32,111,102,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,108,101,97,115,116,32,99,111,112,121,105,110,103,32,111,102,32,100,97,116,97,32,119,105,116,104,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,40,111,102,116,101,110,32,97,32,98,105,110,97,114,121,44,32,98,117,116,32,100,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,105,116,41,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,32,112,97,114,116,115,32,114,101,116,117,114,110,101,100,32,97,115,32,98,105,110,97,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<108,105,115,116>>]}]},{dd,[],[{p,[],[<<65,108,108,32,112,97,114,116,115,32,114,101,116,117,114,110,101,100,32,97,115,32,108,105,115,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,34,115,116,114,105,110,103,115,34,41,46>>]}]}]}]},{dt,[],[{code,[],[<<103,114,111,117,112>>]}]},{dd,[],[{p,[],[<<71,114,111,117,112,115,32,116,111,103,101,116,104,101,114,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,32,116,104,105,115,32,99,97,115,101,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<115,46,32,69,97,99,104,32,115,117,98,108,105,115,116,32,98,101,103,105,110,115,32,119,105,116,104,32,116,104,101,32,115,116,114,105,110,103,32,112,105,99,107,101,100,32,111,117,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,101,97,99,104,32,111,102,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,111,114,100,101,114,32,111,102,32,111,99,99,117,114,114,101,110,99,101,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,116,115,44,78,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,116,111,32,98,101,32,115,112,108,105,116,32,105,110,116,111,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,105,115,32,116,111,32,98,101,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,32,102,111,114,32,97,32,115,112,101,99,105,102,105,99,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,44,32,97,110,100,32>>,{code,[],[<<105,110,102,105,110,105,116,121>>]},<<32,102,111,114,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,112,111,115,115,105,98,108,101,32,40,116,104,101,32,100,101,102,97,117,108,116,41,46,32,83,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<32,103,105,118,101,115,32,97,115,32,109,97,110,121,32,112,97,114,116,115,32,97,115,32,112,111,115,115,105,98,108,101,32,100,105,115,114,101,103,97,114,100,105,110,103,32,101,109,112,116,121,32,112,97,114,116,115,32,97,116,32,116,104,101,32,101,110,100,44,32,116,104,101,32,115,97,109,101,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<116,114,105,109>>]},<<46>>]}]},{dt,[],[{code,[],[<<116,114,105,109>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,101,109,112,116,121,32,112,97,114,116,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,32,97,114,101,32,116,111,32,98,101,32,100,105,115,114,101,103,97,114,100,101,100,46,32,84,104,101,32,115,97,109,101,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<46,32,84,104,105,115,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32>>,{code,[],[<<115,112,108,105,116>>]},<<32,98,117,105,108,116,45,105,110,32,102,117,110,99,116,105,111,110,32,105,110,32,80,101,114,108,46>>]}]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,49,48,48,51>>,signature => [{attribute,166,spec,{{split,3},[{type,166,bounded_fun,[{type,166,'fun',[{type,166,product,[{var,166,'Subject'},{var,166,'RE'},{var,166,'Options'}]},{var,166,'SplitList'}]},[{type,167,constraint,[{atom,167,is_subtype},[{var,167,'Subject'},{type,167,union,[{type,167,iodata,[]},{remote_type,167,[{atom,167,unicode},{atom,167,charlist},[]]}]}]]},{type,168,constraint,[{atom,168,is_subtype},[{var,168,'RE'},{type,168,union,[{user_type,168,mp,[]},{type,168,iodata,[]},{remote_type,168,[{atom,168,unicode},{atom,168,charlist},[]]}]}]]},{type,169,constraint,[{atom,169,is_subtype},[{var,169,'Options'},{type,169,list,[{var,169,'Option'}]}]]},{type,170,constraint,[{atom,170,is_subtype},[{var,170,'Option'},{type,170,union,[{atom,170,anchored},{atom,170,notbol},{atom,170,noteol},{atom,170,notempty},{atom,170,notempty_atstart},{type,171,tuple,[{atom,171,offset},{type,171,non_neg_integer,[]}]},{type,171,tuple,[{atom,171,newline},{user_type,171,nl_spec,[]}]},{type,172,tuple,[{atom,172,match_limit},{type,172,non_neg_integer,[]}]},{type,173,tuple,[{atom,173,match_limit_recursion},{type,173,non_neg_integer,[]}]},{atom,174,bsr_anycrlf},{atom,174,bsr_unicode},{type,174,tuple,[{atom,174,return},{var,174,'ReturnType'}]},{type,175,tuple,[{atom,175,parts},{var,175,'NumParts'}]},{atom,175,group},{atom,175,trim},{var,175,'CompileOpt'}]}]]},{type,176,constraint,[{atom,176,is_subtype},[{var,176,'NumParts'},{type,176,union,[{type,176,non_neg_integer,[]},{atom,176,infinity}]}]]},{type,177,constraint,[{atom,177,is_subtype},[{var,177,'ReturnType'},{type,177,union,[{atom,177,iodata},{atom,177,list},{atom,177,binary}]}]]},{type,178,constraint,[{atom,178,is_subtype},[{var,178,'CompileOpt'},{user_type,178,compile_option,[]}]]},{type,179,constraint,[{atom,179,is_subtype},[{var,179,'SplitList'},{type,179,union,[{type,179,list,[{var,179,'RetData'}]},{type,179,list,[{var,179,'GroupedRetData'}]}]}]]},{type,180,constraint,[{atom,180,is_subtype},[{var,180,'GroupedRetData'},{type,180,list,[{var,180,'RetData'}]}]]},{type,181,constraint,[{atom,181,is_subtype},[{var,181,'RetData'},{type,181,union,[{type,181,iodata,[]},{remote_type,181,[{atom,181,unicode},{atom,181,charlist},[]]},{type,181,binary,[]},{type,181,list,[]}]}]]}]]}]}}]}},{{type,mp,0},[{file,[114,101,46,101,114,108]},{location,23}],[<<45,116,121,112,101,32,109,112,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<79,112,97,113,117,101,32,100,97,116,97,32,116,121,112,101,32,99,111,110,116,97,105,110,105,110,103,32,97,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32>>,{code,[],[<<109,112,40,41>>]},<<32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,97,32,116,117,112,108,101,40,41,32,104,97,118,105,110,103,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<114,101,95,112,97,116,116,101,114,110>>]},<<32,97,115,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,116,111,32,97,108,108,111,119,32,102,111,114,32,109,97,116,99,104,105,110,103,32,105,110,32,103,117,97,114,100,115,46,32,84,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,116,117,112,108,101,32,111,114,32,116,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,111,116,104,101,114,32,102,105,101,108,100,115,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,69,114,108,97,110,103,47,79,84,80,32,114,101,108,101,97,115,101,115,46>>]}]},#{signature => [{attribute,23,type,{mp,{type,23,tuple,[{atom,23,re_pattern},{var,23,'_'},{var,23,'_'},{var,23,'_'},{var,23,'_'}]},[]}}]}},{{type,nl_spec,0},[{file,[114,101,46,101,114,108]},{location,25}],[<<45,116,121,112,101,32,110,108,95,115,112,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,25,type,{nl_spec,{type,25,union,[{atom,25,cr},{atom,25,crlf},{atom,25,lf},{atom,25,anycrlf},{atom,25,any}]},[]}}]}},{{type,compile_option,0},[{file,[114,101,46,101,114,108]},{location,27}],[<<45,116,121,112,101,32,99,111,109,112,105,108,101,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,27,type,{compile_option,{type,27,union,[{atom,27,unicode},{atom,27,anchored},{atom,27,caseless},{atom,27,dollar_endonly},{atom,28,dotall},{atom,28,extended},{atom,28,firstline},{atom,28,multiline},{atom,29,no_auto_capture},{atom,29,dupnames},{atom,29,ungreedy},{type,30,tuple,[{atom,30,newline},{user_type,30,nl_spec,[]}]},{atom,31,bsr_anycrlf},{atom,31,bsr_unicode},{atom,32,no_start_optimize},{atom,32,ucp},{atom,32,never_utf}]},[]}}]}}]}. \ No newline at end of file +{docs_v1,[{file,[114,101,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,99,111,110,116,97,105,110,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,32,102,111,114,32,115,116,114,105,110,103,115,32,97,110,100,32,98,105,110,97,114,105,101,115,46>>]},{p,[],[<<84,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110>>]},<<32,115,121,110,116,97,120,32,97,110,100,32,115,101,109,97,110,116,105,99,115,32,114,101,115,101,109,98,108,101,32,116,104,97,116,32,111,102,32,80,101,114,108,46>>]},{p,[],[<<84,104,101,32,109,97,116,99,104,105,110,103,32,97,108,103,111,114,105,116,104,109,115,32,111,102,32,116,104,101,32,108,105,98,114,97,114,121,32,97,114,101,32,98,97,115,101,100,32,111,110,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,44,32,98,117,116,32,110,111,116,32,97,108,108,32,111,102,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,105,115,32,105,110,116,101,114,102,97,99,101,100,32,97,110,100,32,115,111,109,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,108,105,98,114,97,114,121,32,103,111,32,98,101,121,111,110,100,32,119,104,97,116,32,80,67,82,69,32,111,102,102,101,114,115,46,32,67,117,114,114,101,110,116,108,121,32,80,67,82,69,32,118,101,114,115,105,111,110,32,56,46,52,48,32,40,114,101,108,101,97,115,101,32,100,97,116,101,32,50,48,49,55,45,48,49,45,49,49,41,32,105,115,32,117,115,101,100,46,32,84,104,101,32,115,101,99,116,105,111,110,115,32,111,102,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,116,104,97,116,32,97,114,101,32,114,101,108,101,118,97,110,116,32,116,111,32,116,104,105,115,32,109,111,100,117,108,101,32,97,114,101,32,105,110,99,108,117,100,101,100,32,104,101,114,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,108,105,116,101,114,97,108,32,115,121,110,116,97,120,32,102,111,114,32,115,116,114,105,110,103,115,32,117,115,101,115,32,116,104,101,32,34,92,34,32,40,98,97,99,107,115,108,97,115,104,41,32,99,104,97,114,97,99,116,101,114,32,97,115,32,97,110,32,101,115,99,97,112,101,32,99,111,100,101,46,32,89,111,117,32,110,101,101,100,32,116,111,32,101,115,99,97,112,101,32,98,97,99,107,115,108,97,115,104,101,115,32,105,110,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,115,44,32,98,111,116,104,32,105,110,32,121,111,117,114,32,99,111,100,101,32,97,110,100,32,105,110,32,116,104,101,32,115,104,101,108,108,44,32,119,105,116,104,32,97,110,32,101,120,116,114,97,32,98,97,99,107,115,108,97,115,104,44,32,116,104,97,116,32,105,115,44,32,34,92,92,34,46>>]}]},{a,[{id,<<114,101,103,101,120,112,95,115,121,110,116,97,120>>}],[]},{h2,[],[<<80,101,114,108,45,76,105,107,101,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,83,121,110,116,97,120>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,99,111,110,116,97,105,110,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,32,102,111,114,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,117,115,101,100,32,98,121,32,116,104,105,115,32,109,111,100,117,108,101,46,32,84,104,101,32,105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,98,97,115,101,100,32,111,110,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,119,105,116,104,32,99,104,97,110,103,101,115,32,119,104,101,114,101,32,116,104,105,115,32,109,111,100,117,108,101,32,98,101,104,97,118,101,115,32,100,105,102,102,101,114,101,110,116,108,121,32,116,111,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,46>>]},{a,[{id,<<114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>}],[]},{h2,[],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},{p,[],[<<84,104,101,32,115,121,110,116,97,120,32,97,110,100,32,115,101,109,97,110,116,105,99,115,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,100,101,116,97,105,108,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,46,32,80,101,114,108,39,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,105,116,115,32,111,119,110,32,100,111,99,117,109,101,110,116,97,116,105,111,110,44,32,97,110,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,103,101,110,101,114,97,108,32,97,114,101,32,99,111,118,101,114,101,100,32,105,110,32,109,97,110,121,32,98,111,111,107,115,44,32,115,111,109,101,32,119,105,116,104,32,99,111,112,105,111,117,115,32,101,120,97,109,112,108,101,115,46,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,39,115,32,34,77,97,115,116,101,114,105,110,103,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,115,34,44,32,112,117,98,108,105,115,104,101,100,32,98,121,32,79,39,82,101,105,108,108,121,44,32,99,111,118,101,114,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,103,114,101,97,116,32,100,101,116,97,105,108,46,32,84,104,105,115,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,116,104,101,32,80,67,82,69,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,105,115,32,105,110,116,101,110,100,101,100,32,97,115,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,46>>]},{p,[],[<<84,104,101,32,114,101,102,101,114,101,110,99,101,32,109,97,116,101,114,105,97,108,32,105,115,32,100,105,118,105,100,101,100,32,105,110,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,112,101,99,105,97,108,32,83,116,97,114,116,45,111,102,45,80,97,116,116,101,114,110,32,73,116,101,109,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,104,97,114,97,99,116,101,114,115,32,97,110,100,32,77,101,116,97,99,104,97,114,97,99,116,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,115,108,97,115,104>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,105,114,99,117,109,102,108,101,120,32,97,110,100,32,68,111,108,108,97,114>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<70,117,108,108,32,83,116,111,112,32,40,80,101,114,105,111,100,44,32,68,111,116,41,32,97,110,100,32,92,78>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,54>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<77,97,116,99,104,105,110,103,32,97,32,83,105,110,103,108,101,32,68,97,116,97,32,85,110,105,116>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,55>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,113,117,97,114,101,32,66,114,97,99,107,101,116,115,32,97,110,100,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,56>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,111,115,105,120,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<86,101,114,116,105,99,97,108,32,66,97,114>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<73,110,116,101,114,110,97,108,32,79,112,116,105,111,110,32,83,101,116,116,105,110,103>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,97,109,101,100,32,83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,52>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<82,101,112,101,116,105,116,105,111,110>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,53>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<65,116,111,109,105,99,32,71,114,111,117,112,105,110,103,32,97,110,100,32,80,111,115,115,101,115,115,105,118,101,32,81,117,97,110,116,105,102,105,101,114,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,54>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,55>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<65,115,115,101,114,116,105,111,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,56>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,110,100,105,116,105,111,110,97,108,32,83,117,98,112,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,109,109,101,110,116,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<82,101,99,117,114,115,105,118,101,32,80,97,116,116,101,114,110,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<79,110,105,103,117,114,117,109,97,32,83,117,98,114,111,117,116,105,110,101,32,83,121,110,116,97,120>>]}]},{li,[],[{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108>>]}]}]},{a,[{id,<<115,101,99,116,49>>}],[]},{h2,[],[<<83,112,101,99,105,97,108,32,83,116,97,114,116,45,111,102,45,80,97,116,116,101,114,110,32,73,116,101,109,115>>]},{p,[],[<<83,111,109,101,32,111,112,116,105,111,110,115,32,116,104,97,116,32,99,97,110,32,98,101,32,112,97,115,115,101,100,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,115,112,101,99,105,97,108,32,105,116,101,109,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,46,32,84,104,101,115,101,32,97,114,101,32,110,111,116,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,44,32,98,117,116,32,97,114,101,32,112,114,111,118,105,100,101,100,32,116,111,32,109,97,107,101,32,116,104,101,115,101,32,111,112,116,105,111,110,115,32,97,99,99,101,115,115,105,98,108,101,32,116,111,32,112,97,116,116,101,114,110,32,119,114,105,116,101,114,115,32,119,104,111,32,97,114,101,32,110,111,116,32,97,98,108,101,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,112,114,111,103,114,97,109,32,116,104,97,116,32,112,114,111,99,101,115,115,101,115,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,115,101,32,105,116,101,109,115,32,99,97,110,32,97,112,112,101,97,114,44,32,98,117,116,32,116,104,101,121,32,109,117,115,116,32,97,108,108,32,98,101,32,116,111,103,101,116,104,101,114,32,114,105,103,104,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,101,32,108,101,116,116,101,114,115,32,109,117,115,116,32,98,101,32,105,110,32,117,112,112,101,114,32,99,97,115,101,46>>]},{p,[],[{em,[],[<<85,84,70,32,83,117,112,112,111,114,116>>]}]},{p,[],[<<85,110,105,99,111,100,101,32,115,117,112,112,111,114,116,32,105,115,32,98,97,115,105,99,97,108,108,121,32,85,84,70,45,56,32,98,97,115,101,100,46,32,84,111,32,117,115,101,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,44,32,121,111,117,32,101,105,116,104,101,114,32,99,97,108,108,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,111,114,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,115,58>>]},{pre,[],[{code,[],[<<40,42,85,84,70,56,41,10,40,42,85,84,70,41>>]}]},{p,[],[<<66,111,116,104,32,111,112,116,105,111,110,115,32,103,105,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,44,32,116,104,101,32,105,110,112,117,116,32,115,116,114,105,110,103,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,85,84,70,45,56,46,32,78,111,116,105,99,101,32,116,104,97,116,32,119,105,116,104,32,116,104,101,115,101,32,105,110,115,116,114,117,99,116,105,111,110,115,44,32,116,104,101,32,97,117,116,111,109,97,116,105,99,32,99,111,110,118,101,114,115,105,111,110,32,111,102,32,108,105,115,116,115,32,116,111,32,85,84,70,45,56,32,105,115,32,110,111,116,32,112,101,114,102,111,114,109,101,100,32,98,121,32,116,104,101,32>>,{code,[],[<<114,101>>]},<<32,102,117,110,99,116,105,111,110,115,46,32,84,104,101,114,101,102,111,114,101,44,32,117,115,105,110,103,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,105,115,32,110,111,116,32,114,101,99,111,109,109,101,110,100,101,100,46,32,65,100,100,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,119,104,101,110,32,114,117,110,110,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<83,111,109,101,32,97,112,112,108,105,99,97,116,105,111,110,115,32,116,104,97,116,32,97,108,108,111,119,32,116,104,101,105,114,32,117,115,101,114,115,32,116,111,32,115,117,112,112,108,121,32,112,97,116,116,101,114,110,115,32,99,97,110,32,119,105,115,104,32,116,111,32,114,101,115,116,114,105,99,116,32,116,104,101,109,32,116,111,32,110,111,110,45,85,84,70,32,100,97,116,97,32,102,111,114,32,115,101,99,117,114,105,116,121,32,114,101,97,115,111,110,115,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<110,101,118,101,114,95,117,116,102>>]},<<32,105,115,32,115,101,116,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,44,32,40,42,85,84,70,41,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,110,111,116,32,97,108,108,111,119,101,100,44,32,97,110,100,32,116,104,101,105,114,32,97,112,112,101,97,114,97,110,99,101,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,46>>]},{p,[],[{em,[],[<<85,110,105,99,111,100,101,32,80,114,111,112,101,114,116,121,32,83,117,112,112,111,114,116>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,97,110,111,116,104,101,114,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32,116,104,97,116,32,99,97,110,32,97,112,112,101,97,114,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,42,85,67,80,41>>]}]},{p,[],[<<84,104,105,115,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<58,32,105,116,32,99,97,117,115,101,115,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32,92,100,32,97,110,100,32,92,119,32,116,111,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,116,111,32,100,101,116,101,114,109,105,110,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,44,32,105,110,115,116,101,97,100,32,111,102,32,114,101,99,111,103,110,105,122,105,110,103,32,111,110,108,121,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,115,32,60,32,50,53,54,32,116,104,114,111,117,103,104,32,97,32,108,111,111,107,117,112,32,116,97,98,108,101,46>>]},{p,[],[{em,[],[<<68,105,115,97,98,108,105,110,103,32,83,116,97,114,116,117,112,32,79,112,116,105,109,105,122,97,116,105,111,110,115>>]}]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32>>,{code,[],[<<40,42,78,79,95,83,84,65,82,84,95,79,80,84,41>>]},<<44,32,105,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46>>]},{p,[],[{em,[],[<<78,101,119,108,105,110,101,32,67,111,110,118,101,110,116,105,111,110,115>>]}]},{a,[{id,<<110,101,119,108,105,110,101,95,99,111,110,118,101,110,116,105,111,110,115>>}],[]},{p,[],[<<80,67,82,69,32,115,117,112,112,111,114,116,115,32,102,105,118,101,32,99,111,110,118,101,110,116,105,111,110,115,32,102,111,114,32,105,110,100,105,99,97,116,105,110,103,32,108,105,110,101,32,98,114,101,97,107,115,32,105,110,32,115,116,114,105,110,103,115,58,32,97,32,115,105,110,103,108,101,32,67,82,32,40,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,41,32,99,104,97,114,97,99,116,101,114,44,32,97,32,115,105,110,103,108,101,32,76,70,32,40,108,105,110,101,32,102,101,101,100,41,32,99,104,97,114,97,99,116,101,114,44,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,44,32,97,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,44,32,97,110,100,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,46>>]},{p,[],[<<65,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,115,116,97,114,116,105,110,103,32,97,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,118,101,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<40,42,67,82,41>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110>>]},{dt,[],[<<40,42,76,70,41>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100>>]},{dt,[],[<<40,42,67,82,76,70,41>>]},{dd,[],[<<62,67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,102,111,108,108,111,119,101,100,32,98,121,32,108,105,110,101,32,102,101,101,100>>]},{dt,[],[<<40,42,65,78,89,67,82,76,70,41>>]},{dd,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,97,98,111,118,101>>]},{dt,[],[<<40,42,65,78,89,41>>]},{dd,[],[<<65,108,108,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115>>]}]},{p,[],[<<84,104,101,115,101,32,111,118,101,114,114,105,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,97,110,100,32,116,104,101,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,99,104,97,110,103,101,115,32,116,104,101,32,99,111,110,118,101,110,116,105,111,110,32,116,111,32,67,82,58>>]},{pre,[],[{code,[],[<<40,42,67,82,41,97,46,98>>]}]},{p,[],[<<84,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32>>,{code,[],[<<97,92,110,98>>]},<<44,32,97,115,32,76,70,32,105,115,32,110,111,32,108,111,110,103,101,114,32,97,32,110,101,119,108,105,110,101,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,108,97,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,97,102,102,101,99,116,115,32,119,104,101,114,101,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,116,114,117,101,46,32,73,116,32,97,108,115,111,32,97,102,102,101,99,116,115,32,116,104,101,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,116,104,101,32,100,111,116,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,119,104,101,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,110,111,116,32,115,101,116,44,32,97,110,100,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,92,78,46,32,72,111,119,101,118,101,114,44,32,105,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,119,104,97,116,32,116,104,101,32,92,82,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,109,97,116,99,104,101,115,46,32,66,121,32,100,101,102,97,117,108,116,44,32,116,104,105,115,32,105,115,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,59,32,115,101,101,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,92,82,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]},<<46,32,65,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,92,82,32,115,101,116,116,105,110,103,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,97,32,99,104,97,110,103,101,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,46>>]},{p,[],[{em,[],[<<83,101,116,116,105,110,103,32,77,97,116,99,104,32,97,110,100,32,82,101,99,117,114,115,105,111,110,32,76,105,109,105,116,115>>]}]},{p,[],[<<84,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,99,97,110,32,115,101,116,32,97,32,108,105,109,105,116,32,111,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,40,41,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,97,110,100,32,111,110,32,116,104,101,32,109,97,120,105,109,117,109,32,100,101,112,116,104,32,111,102,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,115,46,32,84,104,101,115,101,32,102,97,99,105,108,105,116,105,101,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,116,111,32,99,97,116,99,104,32,114,117,110,97,119,97,121,32,109,97,116,99,104,101,115,32,116,104,97,116,32,97,114,101,32,112,114,111,118,111,107,101,100,32,98,121,32,112,97,116,116,101,114,110,115,32,119,105,116,104,32,104,117,103,101,32,109,97,116,99,104,105,110,103,32,116,114,101,101,115,32,40,97,32,116,121,112,105,99,97,108,32,101,120,97,109,112,108,101,32,105,115,32,97,32,112,97,116,116,101,114,110,32,119,105,116,104,32,110,101,115,116,101,100,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,41,32,97,110,100,32,116,111,32,97,118,111,105,100,32,114,117,110,110,105,110,103,32,111,117,116,32,111,102,32,115,121,115,116,101,109,32,115,116,97,99,107,32,98,121,32,116,111,111,32,109,117,99,104,32,114,101,99,117,114,115,105,111,110,46,32,87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,108,105,109,105,116,115,32,105,115,32,114,101,97,99,104,101,100,44,32>>,{code,[],[<<112,99,114,101,95,101,120,101,99,40,41>>]},<<32,103,105,118,101,115,32,97,110,32,101,114,114,111,114,32,114,101,116,117,114,110,46,32,84,104,101,32,108,105,109,105,116,115,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,105,116,101,109,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,111,114,109,115,58>>]},{pre,[],[{code,[],[<<40,42,76,73,77,73,84,95,77,65,84,67,72,61,100,41,10,40,42,76,73,77,73,84,95,82,69,67,85,82,83,73,79,78,61,100,41>>]}]},{p,[],[<<72,101,114,101,32,100,32,105,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,100,101,99,105,109,97,108,32,100,105,103,105,116,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,115,101,116,116,105,110,103,32,109,117,115,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,116,104,101,32,118,97,108,117,101,32,115,101,116,32,98,121,32,116,104,101,32,99,97,108,108,101,114,32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,102,111,114,32,105,116,32,116,111,32,104,97,118,101,32,97,110,121,32,101,102,102,101,99,116,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,119,114,105,116,101,114,32,99,97,110,32,108,111,119,101,114,32,116,104,101,32,108,105,109,105,116,32,115,101,116,32,98,121,32,116,104,101,32,112,114,111,103,114,97,109,109,101,114,44,32,98,117,116,32,110,111,116,32,114,97,105,115,101,32,105,116,46,32,73,102,32,116,104,101,114,101,32,105,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,101,116,116,105,110,103,32,111,102,32,111,110,101,32,111,102,32,116,104,101,115,101,32,108,105,109,105,116,115,44,32,116,104,101,32,108,111,119,101,114,32,118,97,108,117,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,102,111,114,32,98,111,116,104,32,116,104,101,32,108,105,109,105,116,115,32,105,115,32,49,48,44,48,48,48,44,48,48,48,32,105,110,32,116,104,101,32,69,114,108,97,110,103,32,86,77,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,108,105,109,105,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,115,116,97,99,107,32,100,101,112,116,104,32,111,102,32,116,104,101,32,86,77,44,32,97,115,32,80,67,82,69,32,102,111,114,32,69,114,108,97,110,103,32,105,115,32,99,111,109,112,105,108,101,100,32,105,110,32,115,117,99,104,32,97,32,119,97,121,32,116,104,97,116,32,116,104,101,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,110,101,118,101,114,32,100,111,101,115,32,114,101,99,117,114,115,105,111,110,32,111,110,32,116,104,101,32,67,32,115,116,97,99,107,46>>]},{p,[],[<<78,111,116,101,32,116,104,97,116,32>>,{code,[],[<<76,73,77,73,84,95,77,65,84,67,72>>]},<<32,97,110,100,32>>,{code,[],[<<76,73,77,73,84,95,82,69,67,85,82,83,73,79,78>>]},<<32,99,97,110,32,111,110,108,121,32,114,101,100,117,99,101,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,108,105,109,105,116,115,32,115,101,116,32,98,121,32,116,104,101,32,99,97,108,108,101,114,44,32,110,111,116,32,105,110,99,114,101,97,115,101,32,116,104,101,109,46>>]},{a,[{id,<<115,101,99,116,50>>}],[]},{h2,[],[<<67,104,97,114,97,99,116,101,114,115,32,97,110,100,32,77,101,116,97,99,104,97,114,97,99,116,101,114,115>>]},{p,[],[<<65,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,46,32,77,111,115,116,32,99,104,97,114,97,99,116,101,114,115,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,32,97,110,100,32,109,97,116,99,104,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,65,115,32,97,32,116,114,105,118,105,97,108,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,112,111,114,116,105,111,110,32,111,102,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,105,100,101,110,116,105,99,97,108,32,116,111,32,105,116,115,101,108,102,58>>]},{pre,[],[{code,[],[<<84,104,101,32,113,117,105,99,107,32,98,114,111,119,110,32,102,111,120>>]}]},{p,[],[<<87,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,112,101,99,105,102,105,101,100,32,40,111,112,116,105,111,110,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<41,44,32,108,101,116,116,101,114,115,32,97,114,101,32,109,97,116,99,104,101,100,32,105,110,100,101,112,101,110,100,101,110,116,108,121,32,111,102,32,99,97,115,101,46>>]},{p,[],[<<84,104,101,32,112,111,119,101,114,32,111,102,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,99,111,109,101,115,32,102,114,111,109,32,116,104,101,32,97,98,105,108,105,116,121,32,116,111,32,105,110,99,108,117,100,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,114,101,112,101,116,105,116,105,111,110,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,115,101,32,97,114,101,32,101,110,99,111,100,101,100,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,121,32,116,104,101,32,117,115,101,32,111,102,32>>,{em,[],[<<109,101,116,97,99,104,97,114,97,99,116,101,114,115>>]},<<44,32,119,104,105,99,104,32,100,111,32,110,111,116,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,32,98,117,116,32,105,110,115,116,101,97,100,32,97,114,101,32,105,110,116,101,114,112,114,101,116,101,100,32,105,110,32,115,111,109,101,32,115,112,101,99,105,97,108,32,119,97,121,46>>]},{p,[],[<<84,119,111,32,115,101,116,115,32,111,102,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,101,120,105,115,116,58,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,97,110,121,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,101,120,99,101,112,116,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,44,32,97,110,100,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,46,32,79,117,116,115,105,100,101,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,44,32,116,104,101,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<92>>]},{dd,[],[<<71,101,110,101,114,97,108,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,109,97,110,121,32,117,115,101,115>>]},{dt,[],[<<94>>]},{dd,[],[<<65,115,115,101,114,116,32,115,116,97,114,116,32,111,102,32,115,116,114,105,110,103,32,40,111,114,32,108,105,110,101,44,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41>>]},{dt,[],[<<36>>]},{dd,[],[<<65,115,115,101,114,116,32,101,110,100,32,111,102,32,115,116,114,105,110,103,32,40,111,114,32,108,105,110,101,44,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41>>]},{dt,[],[<<46>>]},{dd,[],[<<77,97,116,99,104,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,101,120,99,101,112,116,32,110,101,119,108,105,110,101,32,40,98,121,32,100,101,102,97,117,108,116,41>>]},{dt,[],[<<91>>]},{dd,[],[<<83,116,97,114,116,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,100,101,102,105,110,105,116,105,111,110>>]},{dt,[],[<<124>>]},{dd,[],[<<83,116,97,114,116,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104>>]},{dt,[],[<<40>>]},{dd,[],[<<83,116,97,114,116,32,115,117,98,112,97,116,116,101,114,110>>]},{dt,[],[<<41>>]},{dd,[],[<<69,110,100,32,115,117,98,112,97,116,116,101,114,110>>]},{dt,[],[<<63>>]},{dd,[],[<<69,120,116,101,110,100,115,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,40,44,32,97,108,115,111,32,48,32,111,114,32,49,32,113,117,97,110,116,105,102,105,101,114,44,32,97,108,115,111,32,113,117,97,110,116,105,102,105,101,114,32,109,105,110,105,109,105,122,101,114>>]},{dt,[],[<<42>>]},{dd,[],[<<48,32,111,114,32,109,111,114,101,32,113,117,97,110,116,105,102,105,101,114,115>>]},{dt,[],[<<43>>]},{dd,[],[<<49,32,111,114,32,109,111,114,101,32,113,117,97,110,116,105,102,105,101,114,44,32,97,108,115,111,32,34,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,34>>]},{dt,[],[<<123>>]},{dd,[],[<<83,116,97,114,116,32,109,105,110,47,109,97,120,32,113,117,97,110,116,105,102,105,101,114>>]}]},{p,[],[<<80,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,119,105,116,104,105,110,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,32,105,115,32,99,97,108,108,101,100,32,97,32,34,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,34,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,111,110,108,121,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,58>>]},{dl,[],[{dt,[],[<<92>>]},{dd,[],[<<71,101,110,101,114,97,108,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<94>>]},{dd,[],[<<78,101,103,97,116,101,32,116,104,101,32,99,108,97,115,115,44,32,98,117,116,32,111,110,108,121,32,105,102,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<45>>]},{dd,[],[<<73,110,100,105,99,97,116,101,115,32,99,104,97,114,97,99,116,101,114,32,114,97,110,103,101>>]},{dt,[],[<<91>>]},{dd,[],[<<80,111,115,105,120,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,40,111,110,108,121,32,105,102,32,102,111,108,108,111,119,101,100,32,98,121,32,80,111,115,105,120,32,115,121,110,116,97,120,41>>]},{dt,[],[<<93>>]},{dd,[],[<<84,101,114,109,105,110,97,116,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,99,116,105,111,110,115,32,100,101,115,99,114,105,98,101,32,116,104,101,32,117,115,101,32,111,102,32,101,97,99,104,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46>>]},{a,[{id,<<115,101,99,116,51>>}],[]},{h2,[],[<<66,97,99,107,115,108,97,115,104>>]},{p,[],[<<84,104,101,32,98,97,99,107,115,108,97,115,104,32,99,104,97,114,97,99,116,101,114,32,104,97,115,32,109,97,110,121,32,117,115,101,115,46,32,70,105,114,115,116,44,32,105,102,32,105,116,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,110,117,109,98,101,114,32,111,114,32,97,32,108,101,116,116,101,114,44,32,105,116,32,116,97,107,101,115,32,97,119,97,121,32,97,110,121,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,116,104,97,116,32,97,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,104,97,118,101,46,32,84,104,105,115,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,97,115,32,97,110,32,101,115,99,97,112,101,32,99,104,97,114,97,99,116,101,114,32,97,112,112,108,105,101,115,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,97,32,42,32,99,104,97,114,97,99,116,101,114,44,32,121,111,117,32,119,114,105,116,101,32,92,42,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,105,115,32,101,115,99,97,112,105,110,103,32,97,99,116,105,111,110,32,97,112,112,108,105,101,115,32,105,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,32,119,111,117,108,100,32,111,116,104,101,114,119,105,115,101,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,109,101,116,97,99,104,97,114,97,99,116,101,114,44,32,115,111,32,105,116,32,105,115,32,97,108,119,97,121,115,32,115,97,102,101,32,116,111,32,112,114,101,99,101,100,101,32,97,32,110,111,110,45,97,108,112,104,97,110,117,109,101,114,105,99,32,119,105,116,104,32,98,97,99,107,115,108,97,115,104,32,116,111,32,115,112,101,99,105,102,121,32,116,104,97,116,32,105,116,32,115,116,97,110,100,115,32,102,111,114,32,105,116,115,101,108,102,46,32,73,110,32,112,97,114,116,105,99,117,108,97,114,44,32,105,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,97,32,98,97,99,107,115,108,97,115,104,44,32,119,114,105,116,101,32,92,92,46>>]},{p,[],[<<73,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,109,111,100,101,44,32,111,110,108,121,32,65,83,67,73,73,32,110,117,109,98,101,114,115,32,97,110,100,32,108,101,116,116,101,114,115,32,104,97,118,101,32,97,110,121,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,97,102,116,101,114,32,97,32,98,97,99,107,115,108,97,115,104,46,32,65,108,108,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,32,112,97,114,116,105,99,117,108,97,114,44,32,116,104,111,115,101,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,62,32,49,50,55,41,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,108,105,116,101,114,97,108,115,46>>]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<44,32,119,104,105,116,101,115,112,97,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,40,111,116,104,101,114,32,116,104,97,110,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,41,32,97,110,100,32,99,104,97,114,97,99,116,101,114,115,32,98,101,116,119,101,101,110,32,97,32,35,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,97,110,100,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,32,97,114,101,32,105,103,110,111,114,101,100,46,32,65,110,32,101,115,99,97,112,105,110,103,32,98,97,99,107,115,108,97,115,104,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,105,110,99,108,117,100,101,32,97,32,119,104,105,116,101,115,112,97,99,101,32,111,114,32,35,32,99,104,97,114,97,99,116,101,114,32,97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<84,111,32,114,101,109,111,118,101,32,116,104,101,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,102,114,111,109,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,112,117,116,32,116,104,101,109,32,98,101,116,119,101,101,110,32,92,81,32,97,110,100,32,92,69,46,32,84,104,105,115,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,80,101,114,108,32,105,110,32,116,104,97,116,32,36,32,97,110,100,32,64,32,97,114,101,32,104,97,110,100,108,101,100,32,97,115,32,108,105,116,101,114,97,108,115,32,105,110,32,92,81,46,46,46,92,69,32,115,101,113,117,101,110,99,101,115,32,105,110,32,80,67,82,69,44,32,119,104,105,108,101,32,36,32,97,110,100,32,64,32,99,97,117,115,101,32,118,97,114,105,97,98,108,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,105,110,32,80,101,114,108,46,32,78,111,116,105,99,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<80,97,116,116,101,114,110,32,32,32,32,32,32,32,32,32,32,32,32,80,67,82,69,32,109,97,116,99,104,101,115,32,32,32,80,101,114,108,32,109,97,116,99,104,101,115,10,10,92,81,97,98,99,36,120,121,122,92,69,32,32,32,32,32,32,32,32,97,98,99,36,120,121,122,32,32,32,32,32,32,32,32,97,98,99,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,36,120,121,122,10,92,81,97,98,99,92,36,120,121,122,92,69,32,32,32,32,32,32,32,97,98,99,92,36,120,121,122,32,32,32,32,32,32,32,97,98,99,92,36,120,121,122,10,92,81,97,98,99,92,69,92,36,92,81,120,121,122,92,69,32,32,32,97,98,99,36,120,121,122,32,32,32,32,32,32,32,32,97,98,99,36,120,121,122>>]}]},{p,[],[<<84,104,101,32,92,81,46,46,46,92,69,32,115,101,113,117,101,110,99,101,32,105,115,32,114,101,99,111,103,110,105,122,101,100,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,65,110,32,105,115,111,108,97,116,101,100,32,92,69,32,116,104,97,116,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,92,81,32,105,115,32,105,103,110,111,114,101,100,46,32,73,102,32,92,81,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,92,69,32,108,97,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,116,104,101,32,108,105,116,101,114,97,108,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,99,111,110,116,105,110,117,101,115,32,116,111,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,40,116,104,97,116,32,105,115,44,32,92,69,32,105,115,32,97,115,115,117,109,101,100,32,97,116,32,116,104,101,32,101,110,100,41,46,32,73,102,32,116,104,101,32,105,115,111,108,97,116,101,100,32,92,81,32,105,115,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,105,115,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,44,32,97,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,105,115,32,110,111,116,32,116,101,114,109,105,110,97,116,101,100,46>>]},{p,[],[{em,[],[<<78,111,110,45,80,114,105,110,116,105,110,103,32,67,104,97,114,97,99,116,101,114,115>>]}]},{a,[{id,<<110,111,110,95,112,114,105,110,116,105,110,103,95,99,104,97,114,97,99,116,101,114,115>>}],[]},{p,[],[<<65,32,115,101,99,111,110,100,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,112,114,111,118,105,100,101,115,32,97,32,119,97,121,32,111,102,32,101,110,99,111,100,105,110,103,32,110,111,110,45,112,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,112,97,116,116,101,114,110,115,32,105,110,32,97,32,118,105,115,105,98,108,101,32,109,97,110,110,101,114,46,32,84,104,101,114,101,32,105,115,32,110,111,32,114,101,115,116,114,105,99,116,105,111,110,32,111,110,32,116,104,101,32,97,112,112,101,97,114,97,110,99,101,32,111,102,32,110,111,110,45,112,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,97,112,97,114,116,32,102,114,111,109,32,116,104,101,32,98,105,110,97,114,121,32,122,101,114,111,32,116,104,97,116,32,116,101,114,109,105,110,97,116,101,115,32,97,32,112,97,116,116,101,114,110,46,32,87,104,101,110,32,97,32,112,97,116,116,101,114,110,32,105,115,32,112,114,101,112,97,114,101,100,32,98,121,32,116,101,120,116,32,101,100,105,116,105,110,103,44,32,105,116,32,105,115,32,111,102,116,101,110,32,101,97,115,105,101,114,32,116,111,32,117,115,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,110,32,116,104,101,32,98,105,110,97,114,121,32,99,104,97,114,97,99,116,101,114,32,105,116,32,114,101,112,114,101,115,101,110,116,115,58>>]},{dl,[],[{dt,[],[<<92,97>>]},{dd,[],[<<65,108,97,114,109,44,32,116,104,97,116,32,105,115,44,32,116,104,101,32,66,69,76,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,48,55,41>>]},{dt,[],[<<92,99,120>>]},{dd,[],[<<34,67,111,110,116,114,111,108,45,120,34,44,32,119,104,101,114,101,32,120,32,105,115,32,97,110,121,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,101>>]},{dd,[],[<<69,115,99,97,112,101,32,40,104,101,120,32,49,66,41>>]},{dt,[],[<<92,102>>]},{dd,[],[<<70,111,114,109,32,102,101,101,100,32,40,104,101,120,32,48,67,41>>]},{dt,[],[<<92,110>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100,32,40,104,101,120,32,48,65,41>>]},{dt,[],[<<92,114>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,104,101,120,32,48,68,41>>]},{dt,[],[<<92,116>>]},{dd,[],[<<84,97,98,32,40,104,101,120,32,48,57,41>>]},{dt,[],[<<92,48,100,100>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,48,100,100>>]},{dt,[],[<<92,100,100,100>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,100,100,100,44,32,111,114,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},{dt,[],[<<92,111,123,100,100,100,46,46,125>>]},{dd,[],[<<99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,100,100,100,46,46>>]},{dt,[],[<<92,120,104,104>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,104,101,120,32,99,111,100,101,32,104,104>>]},{dt,[],[<<92,120,123,104,104,104,46,46,125>>]},{dd,[],[<<67,104,97,114,97,99,116,101,114,32,119,105,116,104,32,104,101,120,32,99,111,100,101,32,104,104,104,46,46>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,116,101,32,116,104,97,116,32,92,48,100,100,32,105,115,32,97,108,119,97,121,115,32,97,110,32,111,99,116,97,108,32,99,111,100,101,44,32,97,110,100,32,116,104,97,116,32,92,56,32,97,110,100,32,92,57,32,97,114,101,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,57,34,46>>]}]},{p,[],[<<84,104,101,32,112,114,101,99,105,115,101,32,101,102,102,101,99,116,32,111,102,32,92,99,120,32,111,110,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,105,115,32,97,115,32,102,111,108,108,111,119,115,58,32,105,102,32,120,32,105,115,32,97,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,44,32,105,116,32,105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,117,112,112,101,114,32,99,97,115,101,46,32,84,104,101,110,32,98,105,116,32,54,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,52,48,41,32,105,115,32,105,110,118,101,114,116,101,100,46,32,84,104,117,115,32,92,99,65,32,116,111,32,92,99,90,32,98,101,99,111,109,101,32,104,101,120,32,48,49,32,116,111,32,104,101,120,32,49,65,32,40,65,32,105,115,32,52,49,44,32,90,32,105,115,32,53,65,41,44,32,98,117,116,32,92,99,123,32,98,101,99,111,109,101,115,32,104,101,120,32,51,66,32,40,123,32,105,115,32,55,66,41,44,32,97,110,100,32,92,99,59,32,98,101,99,111,109,101,115,32,104,101,120,32,55,66,32,40,59,32,105,115,32,51,66,41,46,32,73,102,32,116,104,101,32,100,97,116,97,32,105,116,101,109,32,40,98,121,116,101,32,111,114,32,49,54,45,98,105,116,32,118,97,108,117,101,41,32,102,111,108,108,111,119,105,110,103,32,92,99,32,104,97,115,32,97,32,118,97,108,117,101,32,62,32,49,50,55,44,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,84,104,105,115,32,108,111,99,107,115,32,111,117,116,32,110,111,110,45,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,108,108,32,109,111,100,101,115,46>>]},{p,[],[<<84,104,101,32,92,99,32,102,97,99,105,108,105,116,121,32,119,97,115,32,100,101,115,105,103,110,101,100,32,102,111,114,32,117,115,101,32,119,105,116,104,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,44,32,98,117,116,32,119,105,116,104,32,116,104,101,32,101,120,116,101,110,115,105,111,110,32,116,111,32,85,110,105,99,111,100,101,32,105,116,32,105,115,32,101,118,101,110,32,108,101,115,115,32,117,115,101,102,117,108,32,116,104,97,110,32,105,116,32,111,110,99,101,32,119,97,115,46>>]},{p,[],[<<65,102,116,101,114,32,92,48,32,117,112,32,116,111,32,116,119,111,32,102,117,114,116,104,101,114,32,111,99,116,97,108,32,100,105,103,105,116,115,32,97,114,101,32,114,101,97,100,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,102,101,119,101,114,32,116,104,97,110,32,116,119,111,32,100,105,103,105,116,115,44,32,106,117,115,116,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,112,114,101,115,101,110,116,32,97,114,101,32,117,115,101,100,46,32,84,104,117,115,32,116,104,101,32,115,101,113,117,101,110,99,101,32,92,48,92,120,92,48,49,53,32,115,112,101,99,105,102,105,101,115,32,116,119,111,32,98,105,110,97,114,121,32,122,101,114,111,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,67,82,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,118,97,108,117,101,32,49,51,41,46,32,77,97,107,101,32,115,117,114,101,32,121,111,117,32,115,117,112,112,108,121,32,116,119,111,32,100,105,103,105,116,115,32,97,102,116,101,114,32,116,104,101,32,105,110,105,116,105,97,108,32,122,101,114,111,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,102,111,108,108,111,119,115,32,105,115,32,105,116,115,101,108,102,32,97,110,32,111,99,116,97,108,32,100,105,103,105,116,46>>]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,92,111,32,109,117,115,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,111,99,116,97,108,32,100,105,103,105,116,115,44,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,46,32,65,110,32,101,114,114,111,114,32,111,99,99,117,114,115,32,105,102,32,116,104,105,115,32,105,115,32,110,111,116,32,116,104,101,32,99,97,115,101,46,32,84,104,105,115,32,101,115,99,97,112,101,32,105,115,32,97,32,114,101,99,101,110,116,32,97,100,100,105,116,105,111,110,32,116,111,32,80,101,114,108,59,32,105,116,32,112,114,111,118,105,100,101,115,32,119,97,121,32,111,102,32,115,112,101,99,105,102,121,105,110,103,32,99,104,97,114,97,99,116,101,114,32,99,111,100,101,32,112,111,105,110,116,115,32,97,115,32,111,99,116,97,108,32,110,117,109,98,101,114,115,32,103,114,101,97,116,101,114,32,116,104,97,110,32,48,55,55,55,44,32,97,110,100,32,105,116,32,97,108,115,111,32,97,108,108,111,119,115,32,111,99,116,97,108,32,110,117,109,98,101,114,115,32,97,110,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,98,101,32,117,110,97,109,98,105,103,117,111,117,115,108,121,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<70,111,114,32,103,114,101,97,116,101,114,32,99,108,97,114,105,116,121,32,97,110,100,32,117,110,97,109,98,105,103,117,105,116,121,44,32,105,116,32,105,115,32,98,101,115,116,32,116,111,32,97,118,111,105,100,32,102,111,108,108,111,119,105,110,103,32,92,32,98,121,32,97,32,100,105,103,105,116,32,103,114,101,97,116,101,114,32,116,104,97,110,32,122,101,114,111,46,32,73,110,115,116,101,97,100,44,32,117,115,101,32,92,111,123,125,32,111,114,32,92,120,123,125,32,116,111,32,115,112,101,99,105,102,121,32,99,104,97,114,97,99,116,101,114,32,110,117,109,98,101,114,115,44,32,97,110,100,32,92,103,123,125,32,116,111,32,115,112,101,99,105,102,121,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,114,97,103,114,97,112,104,115,32,100,101,115,99,114,105,98,101,32,116,104,101,32,111,108,100,44,32,97,109,98,105,103,117,111,117,115,32,115,121,110,116,97,120,46>>]},{p,[],[<<84,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,97,32,98,97,99,107,115,108,97,115,104,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,100,105,103,105,116,32,111,116,104,101,114,32,116,104,97,110,32,48,32,105,115,32,99,111,109,112,108,105,99,97,116,101,100,44,32,97,110,100,32,80,101,114,108,32,104,97,115,32,99,104,97,110,103,101,100,32,105,110,32,114,101,99,101,110,116,32,114,101,108,101,97,115,101,115,44,32,99,97,117,115,105,110,103,32,80,67,82,69,32,97,108,115,111,32,116,111,32,99,104,97,110,103,101,46,32,79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,80,67,82,69,32,114,101,97,100,115,32,116,104,101,32,100,105,103,105,116,32,97,110,100,32,97,110,121,32,102,111,108,108,111,119,105,110,103,32,100,105,103,105,116,115,32,97,115,32,97,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,46,32,73,102,32,116,104,101,32,110,117,109,98,101,114,32,105,115,32,60,32,56,44,32,111,114,32,105,102,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,32,97,116,32,108,101,97,115,116,32,116,104,97,116,32,109,97,110,121,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,44,32,116,104,101,32,101,110,116,105,114,101,32,115,101,113,117,101,110,99,101,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32>>,{em,[],[<<98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},<<46,32,65,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102,32,104,111,119,32,116,104,105,115,32,119,111,114,107,115,32,105,115,32,112,114,111,118,105,100,101,100,32,108,97,116,101,114,44,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46>>]},{p,[],[<<73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,111,114,32,105,102,32,116,104,101,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,32,102,111,108,108,111,119,105,110,103,32,92,32,105,115,32,62,32,55,32,97,110,100,32,116,104,101,114,101,32,104,97,118,101,32,110,111,116,32,98,101,101,110,32,116,104,97,116,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,80,67,82,69,32,104,97,110,100,108,101,115,32,92,56,32,97,110,100,32,92,57,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,57,34,44,32,97,110,100,32,111,116,104,101,114,119,105,115,101,32,114,101,45,114,101,97,100,115,32,117,112,32,116,111,32,116,104,114,101,101,32,111,99,116,97,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,44,32,97,110,100,32,117,115,105,110,103,32,116,104,101,109,32,116,111,32,103,101,110,101,114,97,116,101,32,97,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,46,32,65,110,121,32,115,117,98,115,101,113,117,101,110,116,32,100,105,103,105,116,115,32,115,116,97,110,100,32,102,111,114,32,116,104,101,109,115,101,108,118,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{dl,[],[{dt,[],[<<92,48,52,48>>]},{dd,[],[<<65,110,111,116,104,101,114,32,119,97,121,32,111,102,32,119,114,105,116,105,110,103,32,97,110,32,65,83,67,73,73,32,115,112,97,99,101>>]},{dt,[],[<<92,52,48>>]},{dd,[],[<<84,104,101,32,115,97,109,101,44,32,112,114,111,118,105,100,101,100,32,116,104,101,114,101,32,97,114,101,32,60,32,52,48,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115>>]},{dt,[],[<<92,55>>]},{dd,[],[<<65,108,119,97,121,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101>>]},{dt,[],[<<92,49,49>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,97,110,111,116,104,101,114,32,119,97,121,32,111,102,32,119,114,105,116,105,110,103,32,97,32,116,97,98>>]},{dt,[],[<<92,48,49,49>>]},{dd,[],[<<65,108,119,97,121,115,32,97,32,116,97,98>>]},{dt,[],[<<92,48,49,49,51>>]},{dd,[],[<<65,32,116,97,98,32,102,111,108,108,111,119,101,100,32,98,121,32,99,104,97,114,97,99,116,101,114,32,34,51,34>>]},{dt,[],[<<92,49,49,51>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,111,99,116,97,108,32,99,111,100,101,32,49,49,51>>]},{dt,[],[<<92,51,55,55>>]},{dd,[],[<<67,97,110,32,98,101,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,116,104,101,114,119,105,115,101,32,118,97,108,117,101,32,50,53,53,32,40,100,101,99,105,109,97,108,41>>]},{dt,[],[<<92,56,49>>]},{dd,[],[<<69,105,116,104,101,114,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,111,114,32,116,104,101,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,34,56,34,32,97,110,100,32,34,49,34>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,111,99,116,97,108,32,118,97,108,117,101,115,32,62,61,32,49,48,48,32,116,104,97,116,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,116,114,111,100,117,99,101,100,32,98,121,32,97,32,108,101,97,100,105,110,103,32,122,101,114,111,44,32,97,115,32,110,111,32,109,111,114,101,32,116,104,97,110,32,116,104,114,101,101,32,111,99,116,97,108,32,100,105,103,105,116,115,32,97,114,101,32,101,118,101,114,32,114,101,97,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,102,116,101,114,32,92,120,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,123,44,32,102,114,111,109,32,122,101,114,111,32,116,111,32,116,119,111,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115,32,97,114,101,32,114,101,97,100,32,40,108,101,116,116,101,114,115,32,99,97,110,32,98,101,32,105,110,32,117,112,112,101,114,32,111,114,32,108,111,119,101,114,32,99,97,115,101,41,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115,32,109,97,121,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,92,120,123,32,97,110,100,32,125,46,32,73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,111,116,104,101,114,32,116,104,97,110,32,97,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,32,97,112,112,101,97,114,115,32,98,101,116,119,101,101,110,32,92,120,123,32,97,110,100,32,125,44,32,111,114,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,116,101,114,109,105,110,97,116,105,110,103,32,125,44,32,97,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46>>]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,118,97,108,117,101,32,105,115,32,108,101,115,115,32,116,104,97,110,32,50,53,54,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,32,98,121,32,101,105,116,104,101,114,32,111,102,32,116,104,101,32,116,119,111,32,115,121,110,116,97,120,101,115,32,102,111,114,32,92,120,46,32,84,104,101,114,101,32,105,115,32,110,111,32,100,105,102,102,101,114,101,110,99,101,32,105,110,32,116,104,101,32,119,97,121,32,116,104,101,121,32,97,114,101,32,104,97,110,100,108,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,120,100,99,32,105,115,32,101,120,97,99,116,108,121,32,116,104,101,32,115,97,109,101,32,97,115,32,92,120,123,100,99,125,46>>]},{p,[],[{em,[],[<<67,111,110,115,116,114,97,105,110,116,115,32,111,110,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,115>>]}]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,117,115,105,110,103,32,111,99,116,97,108,32,111,114,32,104,101,120,97,100,101,99,105,109,97,108,32,110,117,109,98,101,114,115,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,99,101,114,116,97,105,110,32,118,97,108,117,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<56,45,98,105,116,32,110,111,110,45,85,84,70,32,109,111,100,101>>]},{dd,[],[{p,[],[<<60,32,48,120,49,48,48>>]}]},{dt,[],[<<56,45,98,105,116,32,85,84,70,45,56,32,109,111,100,101>>]},{dd,[],[{p,[],[<<60,32,48,120,49,48,102,102,102,102,32,97,110,100,32,97,32,118,97,108,105,100,32,99,111,100,101,112,111,105,110,116>>]}]}]},{p,[],[<<73,110,118,97,108,105,100,32,85,110,105,99,111,100,101,32,99,111,100,101,112,111,105,110,116,115,32,97,114,101,32,116,104,101,32,114,97,110,103,101,32,48,120,100,56,48,48,32,116,111,32,48,120,100,102,102,102,32,40,116,104,101,32,115,111,45,99,97,108,108,101,100,32,34,115,117,114,114,111,103,97,116,101,34,32,99,111,100,101,112,111,105,110,116,115,41,44,32,97,110,100,32,48,120,102,102,101,102,46>>]},{p,[],[{em,[],[<<69,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,105,110,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115>>]}]},{p,[],[<<65,108,108,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,100,101,102,105,110,101,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,32,99,97,110,32,98,101,32,117,115,101,100,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,65,108,115,111,44,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,98,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,32,40,104,101,120,32,48,56,41,46>>]},{p,[],[<<92,78,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,92,66,44,32,92,82,44,32,97,110,100,32,92,88,32,97,114,101,32,110,111,116,32,115,112,101,99,105,97,108,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,76,105,107,101,32,111,116,104,101,114,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,116,104,101,121,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,66,34,44,32,34,82,34,44,32,97,110,100,32,34,88,34,46,32,79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,115,46>>]},{p,[],[{em,[],[<<85,110,115,117,112,112,111,114,116,101,100,32,69,115,99,97,112,101,32,83,101,113,117,101,110,99,101,115>>]}]},{p,[],[<<73,110,32,80,101,114,108,44,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,92,108,44,32,92,76,44,32,92,117,44,32,97,110,100,32,92,85,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32,105,116,115,32,115,116,114,105,110,103,32,104,97,110,100,108,101,114,32,97,110,100,32,117,115,101,100,32,116,111,32,109,111,100,105,102,121,32,116,104,101,32,99,97,115,101,32,111,102,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,46>>]},{p,[],[{em,[],[<<65,98,115,111,108,117,116,101,32,97,110,100,32,82,101,108,97,116,105,118,101,32,66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,117,110,115,105,103,110,101,100,32,111,114,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,44,32,105,115,32,97,110,32,97,98,115,111,108,117,116,101,32,111,114,32,114,101,108,97,116,105,118,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,97,109,101,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,99,111,100,101,100,32,97,115,32,92,103,123,110,97,109,101,125,46,32,66,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,97,114,101,32,100,105,115,99,117,115,115,101,100,32,108,97,116,101,114,44,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46>>]},{p,[],[{em,[],[<<65,98,115,111,108,117,116,101,32,97,110,100,32,82,101,108,97,116,105,118,101,32,83,117,98,114,111,117,116,105,110,101,32,67,97,108,108,115>>]}]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,79,110,105,103,117,114,117,109,97,44,32,116,104,101,32,110,111,110,45,80,101,114,108,32,115,121,110,116,97,120,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,32,111,114,32,97,32,110,117,109,98,101,114,32,101,110,99,108,111,115,101,100,32,101,105,116,104,101,114,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,32,111,114,32,115,105,110,103,108,101,32,113,117,111,116,101,115,44,32,105,115,32,97,108,116,101,114,110,97,116,105,118,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,102,101,114,101,110,99,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,34,115,117,98,114,111,117,116,105,110,101,34,46,32,68,101,116,97,105,108,115,32,97,114,101,32,100,105,115,99,117,115,115,101,100,32,108,97,116,101,114,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,103,123,46,46,46,125,32,40,80,101,114,108,32,115,121,110,116,97,120,41,32,97,110,100,32,92,103,60,46,46,46,62,32,40,79,110,105,103,117,114,117,109,97,32,115,121,110,116,97,120,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,115,121,110,111,110,121,109,111,117,115,46,32,84,104,101,32,102,111,114,109,101,114,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,97,110,100,32,116,104,101,32,108,97,116,116,101,114,32,105,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]},{p,[],[{em,[],[<<71,101,110,101,114,105,99,32,67,104,97,114,97,99,116,101,114,32,84,121,112,101,115>>]}]},{a,[{id,<<103,101,110,101,114,105,99,95,99,104,97,114,97,99,116,101,114,95,116,121,112,101,115>>}],[]},{p,[],[<<65,110,111,116,104,101,114,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,105,115,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,103,101,110,101,114,105,99,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[<<92,100>>]},{dd,[],[<<65,110,121,32,100,101,99,105,109,97,108,32,100,105,103,105,116>>]},{dt,[],[<<92,68>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,100,101,99,105,109,97,108,32,100,105,103,105,116>>]},{dt,[],[<<92,104>>]},{dd,[],[<<65,110,121,32,104,111,114,105,122,111,110,116,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,72>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,104,111,114,105,122,111,110,116,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,115>>]},{dd,[],[<<65,110,121,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,83>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,118>>]},{dd,[],[<<65,110,121,32,118,101,114,116,105,99,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,86>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,118,101,114,116,105,99,97,108,32,119,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,119>>]},{dd,[],[<<65,110,121,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114>>]},{dt,[],[<<92,87>>]},{dd,[],[<<65,110,121,32,34,110,111,110,45,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114>>]}]},{p,[],[<<84,104,101,114,101,32,105,115,32,97,108,115,111,32,116,104,101,32,115,105,110,103,108,101,32,115,101,113,117,101,110,99,101,32,92,78,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,32,110,111,110,45,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,34,46,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,119,104,101,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,110,111,116,32,115,101,116,46,32,80,101,114,108,32,97,108,115,111,32,117,115,101,115,32,92,78,32,116,111,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,110,97,109,101,44,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46>>]},{p,[],[<<69,97,99,104,32,112,97,105,114,32,111,102,32,108,111,119,101,114,99,97,115,101,32,97,110,100,32,117,112,112,101,114,99,97,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,112,97,114,116,105,116,105,111,110,115,32,116,104,101,32,99,111,109,112,108,101,116,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,105,110,116,111,32,116,119,111,32,100,105,115,106,111,105,110,116,32,115,101,116,115,46,32,65,110,121,32,103,105,118,101,110,32,99,104,97,114,97,99,116,101,114,32,109,97,116,99,104,101,115,32,111,110,101,44,32,97,110,100,32,111,110,108,121,32,111,110,101,44,32,111,102,32,101,97,99,104,32,112,97,105,114,46,32,84,104,101,32,115,101,113,117,101,110,99,101,115,32,99,97,110,32,97,112,112,101,97,114,32,98,111,116,104,32,105,110,115,105,100,101,32,97,110,100,32,111,117,116,115,105,100,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,84,104,101,121,32,101,97,99,104,32,109,97,116,99,104,32,111,110,101,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,116,121,112,101,46,32,73,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,108,108,32,102,97,105,108,44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,99,104,97,114,97,99,116,101,114,32,116,111,32,109,97,116,99,104,46>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,92,115,32,100,105,100,32,110,111,116,32,117,115,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,49,49,41,44,32,119,104,105,99,104,32,109,97,100,101,32,105,116,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,116,104,101,32,80,79,83,73,88,32,34,115,112,97,99,101,34,32,99,108,97,115,115,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,97,100,100,101,100,32,86,84,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,97,110,100,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,115,117,105,116,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,84,104,101,32,100,101,102,97,117,108,116,32,92,115,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,119,32,72,84,32,40,57,41,44,32,76,70,32,40,49,48,41,44,32,86,84,32,40,49,49,41,44,32,70,70,32,40,49,50,41,44,32,67,82,32,40,49,51,41,44,32,97,110,100,32,115,112,97,99,101,32,40,51,50,41,44,32,119,104,105,99,104,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,32,105,110,32,116,104,101,32,34,67,34,32,108,111,99,97,108,101,46,32,84,104,105,115,32,108,105,115,116,32,109,97,121,32,118,97,114,121,32,105,102,32,108,111,99,97,108,101,45,115,112,101,99,105,102,105,99,32,109,97,116,99,104,105,110,103,32,105,115,32,116,97,107,105,110,103,32,112,108,97,99,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,115,111,109,101,32,108,111,99,97,108,101,115,32,116,104,101,32,34,110,111,110,45,98,114,101,97,107,105,110,103,32,115,112,97,99,101,34,32,99,104,97,114,97,99,116,101,114,32,40,92,120,65,48,41,32,105,115,32,114,101,99,111,103,110,105,122,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,44,32,97,110,100,32,105,110,32,111,116,104,101,114,115,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,46>>]},{p,[],[<<65,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,117,110,100,101,114,115,99,111,114,101,32,111,114,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,97,32,108,101,116,116,101,114,32,111,114,32,97,32,100,105,103,105,116,46,32,66,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,108,101,116,116,101,114,115,32,97,110,100,32,100,105,103,105,116,115,32,105,115,32,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,32,80,67,82,69,32,108,111,119,45,118,97,108,117,101,100,32,99,104,97,114,97,99,116,101,114,32,116,97,98,108,101,115,44,32,105,110,32,69,114,108,97,110,103,39,115,32,99,97,115,101,32,40,97,110,100,32,119,105,116,104,111,117,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<41,44,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,105,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,111,117,116,115,105,100,101,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,44,32,110,101,118,101,114,32,109,97,116,99,104,32,92,100,44,32,92,115,44,32,111,114,32,92,119,44,32,97,110,100,32,97,108,119,97,121,115,32,109,97,116,99,104,32,92,68,44,32,92,83,44,32,97,110,100,32,92,87,46,32,84,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,114,101,116,97,105,110,32,116,104,101,105,114,32,111,114,105,103,105,110,97,108,32,109,101,97,110,105,110,103,115,32,102,114,111,109,32,98,101,102,111,114,101,32,85,84,70,32,115,117,112,112,111,114,116,32,119,97,115,32,97,118,97,105,108,97,98,108,101,44,32,109,97,105,110,108,121,32,102,111,114,32,101,102,102,105,99,105,101,110,99,121,32,114,101,97,115,111,110,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,44,32,116,104,101,32,98,101,104,97,118,105,111,114,32,105,115,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,100,101,116,101,114,109,105,110,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<92,100>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,92,112,123,78,100,125,32,109,97,116,99,104,101,115,32,40,100,101,99,105,109,97,108,32,100,105,103,105,116,41>>]},{dt,[],[<<92,115>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,92,112,123,90,125,32,111,114,32,92,104,32,111,114,32,92,118>>]},{dt,[],[<<92,119>>]},{dd,[],[<<65,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,109,97,116,99,104,101,115,32,92,112,123,76,125,32,111,114,32,92,112,123,78,125,32,109,97,116,99,104,101,115,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101>>]}]},{p,[],[<<84,104,101,32,117,112,112,101,114,99,97,115,101,32,101,115,99,97,112,101,115,32,109,97,116,99,104,32,116,104,101,32,105,110,118,101,114,115,101,32,115,101,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,100,32,109,97,116,99,104,101,115,32,111,110,108,121,32,100,101,99,105,109,97,108,32,100,105,103,105,116,115,44,32,119,104,105,108,101,32,92,119,32,109,97,116,99,104,101,115,32,97,110,121,32,85,110,105,99,111,100,101,32,100,105,103,105,116,44,32,97,110,121,32,85,110,105,99,111,100,101,32,108,101,116,116,101,114,44,32,97,110,100,32,117,110,100,101,114,115,99,111,114,101,46,32,78,111,116,105,99,101,32,97,108,115,111,32,116,104,97,116,32>>,{code,[],[<<117,99,112>>]},<<32,97,102,102,101,99,116,115,32,92,98,32,97,110,100,32,92,66,44,32,97,115,32,116,104,101,121,32,97,114,101,32,100,101,102,105,110,101,100,32,105,110,32,116,101,114,109,115,32,111,102,32,92,119,32,97,110,100,32,92,87,46,32,77,97,116,99,104,105,110,103,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,105,115,32,110,111,116,105,99,101,97,98,108,121,32,115,108,111,119,101,114,32,119,104,101,110,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,115,32,92,104,44,32,92,72,44,32,92,118,44,32,97,110,100,32,92,86,32,97,114,101,32,102,101,97,116,117,114,101,115,32,116,104,97,116,32,119,101,114,101,32,97,100,100,101,100,32,116,111,32,80,101,114,108,32,105,110,32,114,101,108,101,97,115,101,32,53,46,49,48,46,32,73,110,32,99,111,110,116,114,97,115,116,32,116,111,32,116,104,101,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,115,44,32,119,104,105,99,104,32,109,97,116,99,104,32,111,110,108,121,32,65,83,67,73,73,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,100,101,102,97,117,108,116,44,32,116,104,101,115,101,32,97,108,119,97,121,115,32,109,97,116,99,104,32,99,101,114,116,97,105,110,32,104,105,103,104,45,118,97,108,117,101,100,32,99,111,100,101,32,112,111,105,110,116,115,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32>>,{code,[],[<<117,99,112>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,104,111,114,105,122,111,110,116,97,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,58>>]},{dl,[],[{dt,[],[<<85,43,48,48,48,57>>]},{dd,[],[<<72,111,114,105,122,111,110,116,97,108,32,116,97,98,32,40,72,84,41>>]},{dt,[],[<<85,43,48,48,50,48>>]},{dd,[],[<<83,112,97,99,101>>]},{dt,[],[<<85,43,48,48,65,48>>]},{dd,[],[<<78,111,110,45,98,114,101,97,107,32,115,112,97,99,101>>]},{dt,[],[<<85,43,49,54,56,48>>]},{dd,[],[<<79,103,104,97,109,32,115,112,97,99,101,32,109,97,114,107>>]},{dt,[],[<<85,43,49,56,48,69>>]},{dd,[],[<<77,111,110,103,111,108,105,97,110,32,118,111,119,101,108,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<85,43,50,48,48,48>>]},{dd,[],[<<69,110,32,113,117,97,100>>]},{dt,[],[<<85,43,50,48,48,49>>]},{dd,[],[<<69,109,32,113,117,97,100>>]},{dt,[],[<<85,43,50,48,48,50>>]},{dd,[],[<<69,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,51>>]},{dd,[],[<<69,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,52>>]},{dd,[],[<<84,104,114,101,101,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,53>>]},{dd,[],[<<70,111,117,114,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,54>>]},{dd,[],[<<83,105,120,45,112,101,114,45,101,109,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,55>>]},{dd,[],[<<70,105,103,117,114,101,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,56>>]},{dd,[],[<<80,117,110,99,116,117,97,116,105,111,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,57>>]},{dd,[],[<<84,104,105,110,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,48,65>>]},{dd,[],[<<72,97,105,114,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,50,70>>]},{dd,[],[<<78,97,114,114,111,119,32,110,111,45,98,114,101,97,107,32,115,112,97,99,101>>]},{dt,[],[<<85,43,50,48,53,70>>]},{dd,[],[<<77,101,100,105,117,109,32,109,97,116,104,101,109,97,116,105,99,97,108,32,115,112,97,99,101>>]},{dt,[],[<<85,43,51,48,48,48>>]},{dd,[],[<<73,100,101,111,103,114,97,112,104,105,99,32,115,112,97,99,101>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,118,101,114,116,105,99,97,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,58>>]},{dl,[],[{dt,[],[<<85,43,48,48,48,65>>]},{dd,[],[<<76,105,110,101,32,102,101,101,100,32,40,76,70,41>>]},{dt,[],[<<85,43,48,48,48,66>>]},{dd,[],[<<86,101,114,116,105,99,97,108,32,116,97,98,32,40,86,84,41>>]},{dt,[],[<<85,43,48,48,48,67>>]},{dd,[],[<<70,111,114,109,32,102,101,101,100,32,40,70,70,41>>]},{dt,[],[<<85,43,48,48,48,68>>]},{dd,[],[<<67,97,114,114,105,97,103,101,32,114,101,116,117,114,110,32,40,67,82,41>>]},{dt,[],[<<85,43,48,48,56,53>>]},{dd,[],[<<78,101,120,116,32,108,105,110,101,32,40,78,69,76,41>>]},{dt,[],[<<85,43,50,48,50,56>>]},{dd,[],[<<76,105,110,101,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<85,43,50,48,50,57>>]},{dd,[],[<<80,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114>>]}]},{p,[],[<<73,110,32,56,45,98,105,116,44,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,111,110,108,121,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,32,112,111,105,110,116,115,32,60,32,50,53,54,32,97,114,101,32,114,101,108,101,118,97,110,116,46>>]},{p,[],[{em,[],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]}]},{a,[{id,<<110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>}],[]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,98,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,82,32,109,97,116,99,104,101,115,32,97,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,46,32,73,110,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,92,82,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{pre,[],[{code,[],[<<40,63,62,92,114,92,110,124,92,110,124,92,120,48,98,124,92,102,124,92,114,124,92,120,56,53,41>>]}]},{p,[],[<<84,104,105,115,32,105,115,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,97,110,32,34,97,116,111,109,105,99,32,103,114,111,117,112,34,44,32,100,101,116,97,105,108,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,98,101,108,111,119,46>>]},{p,[],[<<84,104,105,115,32,112,97,114,116,105,99,117,108,97,114,32,103,114,111,117,112,32,109,97,116,99,104,101,115,32,101,105,116,104,101,114,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,32,102,111,108,108,111,119,101,100,32,98,121,32,76,70,44,32,111,114,32,111,110,101,32,111,102,32,116,104,101,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,115,32,76,70,32,40,108,105,110,101,32,102,101,101,100,44,32,85,43,48,48,48,65,41,44,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,32,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,67,82,32,40,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,85,43,48,48,48,68,41,44,32,111,114,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,46,32,84,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,117,110,105,116,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,115,112,108,105,116,46>>]},{p,[],[<<73,110,32,85,110,105,99,111,100,101,32,109,111,100,101,44,32,116,119,111,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,62,32,50,53,53,32,97,114,101,32,97,100,100,101,100,58,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,32,105,115,32,110,111,116,32,110,101,101,100,101,100,32,102,111,114,32,116,104,101,115,101,32,99,104,97,114,97,99,116,101,114,115,32,116,111,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]},{p,[],[<<92,82,32,99,97,110,32,98,101,32,114,101,115,116,114,105,99,116,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,40,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,99,111,109,112,108,101,116,101,32,115,101,116,32,111,102,32,85,110,105,99,111,100,101,32,108,105,110,101,32,101,110,100,105,110,103,115,41,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]},<<32,101,105,116,104,101,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,111,114,32,119,104,101,110,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,46,32,40,66,83,82,32,105,115,32,97,110,32,97,99,114,111,110,121,109,32,102,111,114,32,34,98,97,99,107,115,108,97,115,104,32,82,34,46,41,32,84,104,105,115,32,99,97,110,32,98,101,32,109,97,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,119,104,101,110,32,80,67,82,69,32,105,115,32,98,117,105,108,116,59,32,105,102,32,115,111,44,32,116,104,101,32,111,116,104,101,114,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,114,101,113,117,101,115,116,101,100,32,116,104,114,111,117,103,104,32,111,112,116,105,111,110,32>>,{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]},<<46,32,84,104,101,115,101,32,115,101,116,116,105,110,103,115,32,99,97,110,32,97,108,115,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,115,116,97,114,116,105,110,103,32,97,32,112,97,116,116,101,114,110,32,115,116,114,105,110,103,32,119,105,116,104,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<40,42,66,83,82,95,65,78,89,67,82,76,70,41>>]},{dd,[],[<<67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,111,110,108,121>>]},{dt,[],[<<40,42,66,83,82,95,85,78,73,67,79,68,69,41>>]},{dd,[],[<<65,110,121,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101>>]}]},{p,[],[<<84,104,101,115,101,32,111,118,101,114,114,105,100,101,32,116,104,101,32,100,101,102,97,117,108,116,32,97,110,100,32,116,104,101,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,101,32,99,111,109,112,105,108,105,110,103,32,102,117,110,99,116,105,111,110,44,32,98,117,116,32,116,104,101,121,32,99,97,110,32,116,104,101,109,115,101,108,118,101,115,32,98,101,32,111,118,101,114,114,105,100,100,101,110,32,98,121,32,111,112,116,105,111,110,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,97,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,115,101,116,116,105,110,103,115,44,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,44,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,111,110,108,121,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,44,32,97,110,100,32,116,104,97,116,32,116,104,101,121,32,109,117,115,116,32,98,101,32,105,110,32,117,112,112,101,114,32,99,97,115,101,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,32,108,97,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46,32,84,104,101,121,32,99,97,110,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,97,32,99,104,97,110,103,101,32,111,102,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,59,32,102,111,114,32,101,120,97,109,112,108,101,44,32,97,32,112,97,116,116,101,114,110,32,99,97,110,32,115,116,97,114,116,32,119,105,116,104,58>>]},{pre,[],[{code,[],[<<40,42,65,78,89,41,40,42,66,83,82,95,65,78,89,67,82,76,70,41>>]}]},{p,[],[<<84,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,116,104,101,32,40,42,85,84,70,56,41,44,32,40,42,85,84,70,41,44,32,111,114,32,40,42,85,67,80,41,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,115,46,32,73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,82,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,44,32,97,110,100,32,115,111,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,32,34,82,34,32,98,121,32,100,101,102,97,117,108,116,46>>]},{p,[],[{em,[],[<<85,110,105,99,111,100,101,32,67,104,97,114,97,99,116,101,114,32,80,114,111,112,101,114,116,105,101,115>>]}]},{p,[],[<<84,104,114,101,101,32,109,111,114,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,115,112,101,99,105,102,105,99,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,97,118,97,105,108,97,98,108,101,46,32,87,104,101,110,32,105,110,32,56,45,98,105,116,32,110,111,110,45,85,84,70,45,56,32,109,111,100,101,44,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,116,101,115,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,60,32,50,53,54,44,32,98,117,116,32,116,104,101,121,32,100,111,32,119,111,114,107,32,105,110,32,116,104,105,115,32,109,111,100,101,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,101,120,116,114,97,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,58>>]},{dl,[],[{dt,[],[<<92,112,123>>,{em,[],[<<120,120>>]},<<125>>]},{dd,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,112,114,111,112,101,114,116,121,32>>,{em,[],[<<120,120>>]}]},{dt,[],[<<92,80,123>>,{em,[],[<<120,120>>]},<<125>>]},{dd,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,111,117,116,32,112,114,111,112,101,114,116,121,32>>,{em,[],[<<120,120>>]}]},{dt,[],[<<92,88>>]},{dd,[],[<<65,32,85,110,105,99,111,100,101,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114>>]}]},{p,[],[<<84,104,101,32,112,114,111,112,101,114,116,121,32,110,97,109,101,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32>>,{em,[],[<<120,120>>]},<<32,97,98,111,118,101,32,97,114,101,32,108,105,109,105,116,101,100,32,116,111,32,116,104,101,32,85,110,105,99,111,100,101,32,115,99,114,105,112,116,32,110,97,109,101,115,44,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,105,101,115,44,32,34,65,110,121,34,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,40,105,110,99,108,117,100,105,110,103,32,110,101,119,108,105,110,101,41,44,32,97,110,100,32,115,111,109,101,32,115,112,101,99,105,97,108,32,80,67,82,69,32,112,114,111,112,101,114,116,105,101,115,32,40,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,46,32,79,116,104,101,114,32,80,101,114,108,32,112,114,111,112,101,114,116,105,101,115,44,32,115,117,99,104,32,97,115,32,34,73,110,77,117,115,105,99,97,108,83,121,109,98,111,108,115,34,44,32,97,114,101,32,99,117,114,114,101,110,116,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,46,32,78,111,116,105,99,101,32,116,104,97,116,32,92,80,123,65,110,121,125,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,97,108,119,97,121,115,32,99,97,117,115,101,115,32,97,32,109,97,116,99,104,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<83,101,116,115,32,111,102,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,98,101,108,111,110,103,105,110,103,32,116,111,32,99,101,114,116,97,105,110,32,115,99,114,105,112,116,115,46,32,65,32,99,104,97,114,97,99,116,101,114,32,102,114,111,109,32,111,110,101,32,111,102,32,116,104,101,115,101,32,115,101,116,115,32,99,97,110,32,98,101,32,109,97,116,99,104,101,100,32,117,115,105,110,103,32,97,32,115,99,114,105,112,116,32,110,97,109,101,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<92,112,123,71,114,101,101,107,125,32,92,80,123,72,97,110,125>>]}]},{p,[],[<<84,104,111,115,101,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,97,110,32,105,100,101,110,116,105,102,105,101,100,32,115,99,114,105,112,116,32,97,114,101,32,108,117,109,112,101,100,32,116,111,103,101,116,104,101,114,32,97,115,32,34,67,111,109,109,111,110,34,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,116,104,101,32,99,117,114,114,101,110,116,32,108,105,115,116,32,111,102,32,115,99,114,105,112,116,115,58>>]},{ul,[],[{li,[],[<<65,114,97,98,105,99>>]},{li,[],[<<65,114,109,101,110,105,97,110>>]},{li,[],[<<65,118,101,115,116,97,110>>]},{li,[],[<<66,97,108,105,110,101,115,101>>]},{li,[],[<<66,97,109,117,109>>]},{li,[],[<<66,97,115,115,97,95,86,97,104>>]},{li,[],[<<66,97,116,97,107>>]},{li,[],[<<66,101,110,103,97,108,105>>]},{li,[],[<<66,111,112,111,109,111,102,111>>]},{li,[],[<<66,114,97,105,108,108,101>>]},{li,[],[<<66,117,103,105,110,101,115,101>>]},{li,[],[<<66,117,104,105,100>>]},{li,[],[<<67,97,110,97,100,105,97,110,95,65,98,111,114,105,103,105,110,97,108>>]},{li,[],[<<67,97,114,105,97,110>>]},{li,[],[<<67,97,117,99,97,115,105,97,110,95,65,108,98,97,110,105,97,110>>]},{li,[],[<<67,104,97,107,109,97>>]},{li,[],[<<67,104,97,109>>]},{li,[],[<<67,104,101,114,111,107,101,101>>]},{li,[],[<<67,111,109,109,111,110>>]},{li,[],[<<67,111,112,116,105,99>>]},{li,[],[<<67,117,110,101,105,102,111,114,109>>]},{li,[],[<<67,121,112,114,105,111,116>>]},{li,[],[<<67,121,114,105,108,108,105,99>>]},{li,[],[<<68,101,115,101,114,101,116>>]},{li,[],[<<68,101,118,97,110,97,103,97,114,105>>]},{li,[],[<<68,117,112,108,111,121,97,110>>]},{li,[],[<<69,103,121,112,116,105,97,110,95,72,105,101,114,111,103,108,121,112,104,115>>]},{li,[],[<<69,108,98,97,115,97,110>>]},{li,[],[<<69,116,104,105,111,112,105,99>>]},{li,[],[<<71,101,111,114,103,105,97,110>>]},{li,[],[<<71,108,97,103,111,108,105,116,105,99>>]},{li,[],[<<71,111,116,104,105,99>>]},{li,[],[<<71,114,97,110,116,104,97>>]},{li,[],[<<71,114,101,101,107>>]},{li,[],[<<71,117,106,97,114,97,116,105>>]},{li,[],[<<71,117,114,109,117,107,104,105>>]},{li,[],[<<72,97,110>>]},{li,[],[<<72,97,110,103,117,108>>]},{li,[],[<<72,97,110,117,110,111,111>>]},{li,[],[<<72,101,98,114,101,119>>]},{li,[],[<<72,105,114,97,103,97,110,97>>]},{li,[],[<<73,109,112,101,114,105,97,108,95,65,114,97,109,97,105,99>>]},{li,[],[<<73,110,104,101,114,105,116,101,100>>]},{li,[],[<<73,110,115,99,114,105,112,116,105,111,110,97,108,95,80,97,104,108,97,118,105>>]},{li,[],[<<73,110,115,99,114,105,112,116,105,111,110,97,108,95,80,97,114,116,104,105,97,110>>]},{li,[],[<<74,97,118,97,110,101,115,101>>]},{li,[],[<<75,97,105,116,104,105>>]},{li,[],[<<75,97,110,110,97,100,97>>]},{li,[],[<<75,97,116,97,107,97,110,97>>]},{li,[],[<<75,97,121,97,104,95,76,105>>]},{li,[],[<<75,104,97,114,111,115,104,116,104,105>>]},{li,[],[<<75,104,109,101,114>>]},{li,[],[<<75,104,111,106,107,105>>]},{li,[],[<<75,104,117,100,97,119,97,100,105>>]},{li,[],[<<76,97,111>>]},{li,[],[<<76,97,116,105,110>>]},{li,[],[<<76,101,112,99,104,97>>]},{li,[],[<<76,105,109,98,117>>]},{li,[],[<<76,105,110,101,97,114,95,65>>]},{li,[],[<<76,105,110,101,97,114,95,66>>]},{li,[],[<<76,105,115,117>>]},{li,[],[<<76,121,99,105,97,110>>]},{li,[],[<<76,121,100,105,97,110>>]},{li,[],[<<77,97,104,97,106,97,110,105>>]},{li,[],[<<77,97,108,97,121,97,108,97,109>>]},{li,[],[<<77,97,110,100,97,105,99>>]},{li,[],[<<77,97,110,105,99,104,97,101,97,110>>]},{li,[],[<<77,101,101,116,101,105,95,77,97,121,101,107>>]},{li,[],[<<77,101,110,100,101,95,75,105,107,97,107,117,105>>]},{li,[],[<<77,101,114,111,105,116,105,99,95,67,117,114,115,105,118,101>>]},{li,[],[<<77,101,114,111,105,116,105,99,95,72,105,101,114,111,103,108,121,112,104,115>>]},{li,[],[<<77,105,97,111>>]},{li,[],[<<77,111,100,105>>]},{li,[],[<<77,111,110,103,111,108,105,97,110>>]},{li,[],[<<77,114,111>>]},{li,[],[<<77,121,97,110,109,97,114>>]},{li,[],[<<78,97,98,97,116,97,101,97,110>>]},{li,[],[<<78,101,119,95,84,97,105,95,76,117,101>>]},{li,[],[<<78,107,111>>]},{li,[],[<<79,103,104,97,109>>]},{li,[],[<<79,108,95,67,104,105,107,105>>]},{li,[],[<<79,108,100,95,73,116,97,108,105,99>>]},{li,[],[<<79,108,100,95,78,111,114,116,104,95,65,114,97,98,105,97,110>>]},{li,[],[<<79,108,100,95,80,101,114,109,105,99>>]},{li,[],[<<79,108,100,95,80,101,114,115,105,97,110>>]},{li,[],[<<79,114,105,121,97>>]},{li,[],[<<79,108,100,95,83,111,117,116,104,95,65,114,97,98,105,97,110>>]},{li,[],[<<79,108,100,95,84,117,114,107,105,99>>]},{li,[],[<<79,115,109,97,110,121,97>>]},{li,[],[<<80,97,104,97,119,104,95,72,109,111,110,103>>]},{li,[],[<<80,97,108,109,121,114,101,110,101>>]},{li,[],[<<80,97,117,95,67,105,110,95,72,97,117>>]},{li,[],[<<80,104,97,103,115,95,80,97>>]},{li,[],[<<80,104,111,101,110,105,99,105,97,110>>]},{li,[],[<<80,115,97,108,116,101,114,95,80,97,104,108,97,118,105>>]},{li,[],[<<82,101,106,97,110,103>>]},{li,[],[<<82,117,110,105,99>>]},{li,[],[<<83,97,109,97,114,105,116,97,110>>]},{li,[],[<<83,97,117,114,97,115,104,116,114,97>>]},{li,[],[<<83,104,97,114,97,100,97>>]},{li,[],[<<83,104,97,118,105,97,110>>]},{li,[],[<<83,105,100,100,104,97,109>>]},{li,[],[<<83,105,110,104,97,108,97>>]},{li,[],[<<83,111,114,97,95,83,111,109,112,101,110,103>>]},{li,[],[<<83,117,110,100,97,110,101,115,101>>]},{li,[],[<<83,121,108,111,116,105,95,78,97,103,114,105>>]},{li,[],[<<83,121,114,105,97,99>>]},{li,[],[<<84,97,103,97,108,111,103>>]},{li,[],[<<84,97,103,98,97,110,119,97>>]},{li,[],[<<84,97,105,95,76,101>>]},{li,[],[<<84,97,105,95,84,104,97,109>>]},{li,[],[<<84,97,105,95,86,105,101,116>>]},{li,[],[<<84,97,107,114,105>>]},{li,[],[<<84,97,109,105,108>>]},{li,[],[<<84,101,108,117,103,117>>]},{li,[],[<<84,104,97,97,110,97>>]},{li,[],[<<84,104,97,105>>]},{li,[],[<<84,105,98,101,116,97,110>>]},{li,[],[<<84,105,102,105,110,97,103,104>>]},{li,[],[<<84,105,114,104,117,116,97>>]},{li,[],[<<85,103,97,114,105,116,105,99>>]},{li,[],[<<86,97,105>>]},{li,[],[<<87,97,114,97,110,103,95,67,105,116,105>>]},{li,[],[<<89,105>>]}]},{p,[],[<<69,97,99,104,32,99,104,97,114,97,99,116,101,114,32,104,97,115,32,101,120,97,99,116,108,121,32,111,110,101,32,85,110,105,99,111,100,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,121,44,32,115,112,101,99,105,102,105,101,100,32,98,121,32,97,32,116,119,111,45,108,101,116,116,101,114,32,97,99,114,111,110,121,109,46,32,70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,110,101,103,97,116,105,111,110,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,105,110,99,108,117,100,105,110,103,32,97,32,99,105,114,99,117,109,102,108,101,120,32,98,101,116,119,101,101,110,32,116,104,101,32,111,112,101,110,105,110,103,32,98,114,97,99,101,32,97,110,100,32,116,104,101,32,112,114,111,112,101,114,116,121,32,110,97,109,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,112,123,94,76,117,125,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,92,80,123,76,117,125,46>>]},{p,[],[<<73,102,32,111,110,108,121,32,111,110,101,32,108,101,116,116,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,32,119,105,116,104,32,92,112,32,111,114,32,92,80,44,32,105,116,32,105,110,99,108,117,100,101,115,32,97,108,108,32,116,104,101,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,105,101,115,32,116,104,97,116,32,115,116,97,114,116,32,119,105,116,104,32,116,104,97,116,32,108,101,116,116,101,114,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,105,110,32,116,104,101,32,97,98,115,101,110,99,101,32,111,102,32,110,101,103,97,116,105,111,110,44,32,116,104,101,32,99,117,114,108,121,32,98,114,97,99,107,101,116,115,32,105,110,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,97,114,101,32,111,112,116,105,111,110,97,108,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,116,119,111,32,101,120,97,109,112,108,101,115,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,58>>]},{pre,[],[{code,[],[<<92,112,123,76,125,10,92,112,76>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,103,101,110,101,114,97,108,32,99,97,116,101,103,111,114,121,32,112,114,111,112,101,114,116,121,32,99,111,100,101,115,32,97,114,101,32,115,117,112,112,111,114,116,101,100,58>>]},{dl,[],[{dt,[],[<<67>>]},{dd,[],[<<79,116,104,101,114>>]},{dt,[],[<<67,99>>]},{dd,[],[<<67,111,110,116,114,111,108>>]},{dt,[],[<<67,102>>]},{dd,[],[<<70,111,114,109,97,116>>]},{dt,[],[<<67,110>>]},{dd,[],[<<85,110,97,115,115,105,103,110,101,100>>]},{dt,[],[<<67,111>>]},{dd,[],[<<80,114,105,118,97,116,101,32,117,115,101>>]},{dt,[],[<<67,115>>]},{dd,[],[<<83,117,114,114,111,103,97,116,101>>]},{dt,[],[<<76>>]},{dd,[],[<<76,101,116,116,101,114>>]},{dt,[],[<<76,108>>]},{dd,[],[<<76,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<76,109>>]},{dd,[],[<<77,111,100,105,102,105,101,114,32,108,101,116,116,101,114>>]},{dt,[],[<<76,111>>]},{dd,[],[<<79,116,104,101,114,32,108,101,116,116,101,114>>]},{dt,[],[<<76,116>>]},{dd,[],[<<84,105,116,108,101,32,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<76,117>>]},{dd,[],[<<85,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114>>]},{dt,[],[<<77>>]},{dd,[],[<<77,97,114,107>>]},{dt,[],[<<77,99>>]},{dd,[],[<<83,112,97,99,105,110,103,32,109,97,114,107>>]},{dt,[],[<<77,101>>]},{dd,[],[<<69,110,99,108,111,115,105,110,103,32,109,97,114,107>>]},{dt,[],[<<77,110>>]},{dd,[],[<<78,111,110,45,115,112,97,99,105,110,103,32,109,97,114,107>>]},{dt,[],[<<78>>]},{dd,[],[<<78,117,109,98,101,114>>]},{dt,[],[<<78,100>>]},{dd,[],[<<68,101,99,105,109,97,108,32,110,117,109,98,101,114>>]},{dt,[],[<<78,108>>]},{dd,[],[<<76,101,116,116,101,114,32,110,117,109,98,101,114>>]},{dt,[],[<<78,111>>]},{dd,[],[<<79,116,104,101,114,32,110,117,109,98,101,114>>]},{dt,[],[<<80>>]},{dd,[],[<<80,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,99>>]},{dd,[],[<<67,111,110,110,101,99,116,111,114,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,100>>]},{dd,[],[<<68,97,115,104,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,101>>]},{dd,[],[<<67,108,111,115,101,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,102>>]},{dd,[],[<<70,105,110,97,108,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,105>>]},{dd,[],[<<73,110,105,116,105,97,108,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,111>>]},{dd,[],[<<79,116,104,101,114,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<80,115>>]},{dd,[],[<<79,112,101,110,32,112,117,110,99,116,117,97,116,105,111,110>>]},{dt,[],[<<83>>]},{dd,[],[<<83,121,109,98,111,108>>]},{dt,[],[<<83,99>>]},{dd,[],[<<67,117,114,114,101,110,99,121,32,115,121,109,98,111,108>>]},{dt,[],[<<83,107>>]},{dd,[],[<<77,111,100,105,102,105,101,114,32,115,121,109,98,111,108>>]},{dt,[],[<<83,109>>]},{dd,[],[<<77,97,116,104,101,109,97,116,105,99,97,108,32,115,121,109,98,111,108>>]},{dt,[],[<<83,111>>]},{dd,[],[<<79,116,104,101,114,32,115,121,109,98,111,108>>]},{dt,[],[<<90>>]},{dd,[],[<<83,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,108>>]},{dd,[],[<<76,105,110,101,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,112>>]},{dd,[],[<<80,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114>>]},{dt,[],[<<90,115>>]},{dd,[],[<<83,112,97,99,101,32,115,101,112,97,114,97,116,111,114>>]}]},{p,[],[<<84,104,101,32,115,112,101,99,105,97,108,32,112,114,111,112,101,114,116,121,32,76,38,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,73,116,32,109,97,116,99,104,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,76,117,44,32,76,108,44,32,111,114,32,76,116,32,112,114,111,112,101,114,116,121,44,32,116,104,97,116,32,105,115,44,32,97,32,108,101,116,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,99,108,97,115,115,105,102,105,101,100,32,97,115,32,97,32,109,111,100,105,102,105,101,114,32,111,114,32,34,111,116,104,101,114,34,46>>]},{p,[],[<<84,104,101,32,67,115,32,40,83,117,114,114,111,103,97,116,101,41,32,112,114,111,112,101,114,116,121,32,97,112,112,108,105,101,115,32,111,110,108,121,32,116,111,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,85,43,68,56,48,48,32,116,111,32,85,43,68,70,70,70,46,32,83,117,99,104,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,105,110,118,97,108,105,100,32,105,110,32,85,110,105,99,111,100,101,32,115,116,114,105,110,103,115,32,97,110,100,32,115,111,32,99,97,110,110,111,116,32,98,101,32,116,101,115,116,101,100,32,98,121,32,80,67,82,69,46,32,80,101,114,108,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,32,67,115,32,112,114,111,112,101,114,116,121,46>>]},{p,[],[<<84,104,101,32,108,111,110,103,32,115,121,110,111,110,121,109,115,32,102,111,114,32,112,114,111,112,101,114,116,121,32,110,97,109,101,115,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,101,114,108,32,40,115,117,99,104,32,97,115,32,92,112,123,76,101,116,116,101,114,125,41,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,80,67,82,69,46,32,73,116,32,105,115,32,110,111,116,32,112,101,114,109,105,116,116,101,100,32,116,111,32,112,114,101,102,105,120,32,97,110,121,32,111,102,32,116,104,101,115,101,32,112,114,111,112,101,114,116,105,101,115,32,119,105,116,104,32,34,73,115,34,46>>]},{p,[],[<<78,111,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,116,97,98,108,101,32,104,97,115,32,116,104,101,32,67,110,32,40,117,110,97,115,115,105,103,110,101,100,41,32,112,114,111,112,101,114,116,121,46,32,84,104,105,115,32,112,114,111,112,101,114,116,121,32,105,115,32,105,110,115,116,101,97,100,32,97,115,115,117,109,101,100,32,102,111,114,32,97,110,121,32,99,111,100,101,32,112,111,105,110,116,32,116,104,97,116,32,105,115,32,110,111,116,32,105,110,32,116,104,101,32,85,110,105,99,111,100,101,32,116,97,98,108,101,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,115,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,92,112,123,76,117,125,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,111,110,108,121,32,117,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,115,46,32,84,104,105,115,32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,99,117,114,114,101,110,116,32,118,101,114,115,105,111,110,115,32,111,102,32,80,101,114,108,46>>]},{p,[],[<<77,97,116,99,104,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,105,115,32,110,111,116,32,102,97,115,116,44,32,97,115,32,80,67,82,69,32,109,117,115,116,32,100,111,32,97,32,109,117,108,116,105,115,116,97,103,101,32,116,97,98,108,101,32,108,111,111,107,117,112,32,116,111,32,102,105,110,100,32,97,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,121,46,32,84,104,97,116,32,105,115,32,119,104,121,32,116,104,101,32,116,114,97,100,105,116,105,111,110,97,108,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32,92,100,32,97,110,100,32,92,119,32,100,111,32,110,111,116,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,105,110,32,80,67,82,69,32,98,121,32,100,101,102,97,117,108,116,46,32,72,111,119,101,118,101,114,44,32,121,111,117,32,99,97,110,32,109,97,107,101,32,116,104,101,109,32,100,111,32,115,111,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,111,114,32,98,121,32,115,116,97,114,116,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,40,42,85,67,80,41,46>>]},{p,[],[{em,[],[<<69,120,116,101,110,100,101,100,32,71,114,97,112,104,101,109,101,32,67,108,117,115,116,101,114,115>>]}]},{p,[],[<<84,104,101,32,92,88,32,101,115,99,97,112,101,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,102,111,114,109,32,97,110,32,34,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,34,44,32,97,110,100,32,116,114,101,97,116,115,32,116,104,101,32,115,101,113,117,101,110,99,101,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,40,115,101,101,32,98,101,108,111,119,41,46,32,85,112,32,116,111,32,97,110,100,32,105,110,99,108,117,100,105,110,103,32,114,101,108,101,97,115,101,32,56,46,51,49,44,32,80,67,82,69,32,109,97,116,99,104,101,100,32,97,110,32,101,97,114,108,105,101,114,44,32,115,105,109,112,108,101,114,32,100,101,102,105,110,105,116,105,111,110,32,116,104,97,116,32,119,97,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<40,63,62,92,80,77,92,112,77,42,41>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,116,32,109,97,116,99,104,101,100,32,97,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,111,117,116,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,44,32,102,111,108,108,111,119,101,100,32,98,121,32,122,101,114,111,32,111,114,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,46,32,67,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,32,97,114,101,32,116,121,112,105,99,97,108,108,121,32,110,111,110,45,115,112,97,99,105,110,103,32,97,99,99,101,110,116,115,32,116,104,97,116,32,97,102,102,101,99,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,99,104,97,114,97,99,116,101,114,46>>]},{p,[],[<<84,104,105,115,32,115,105,109,112,108,101,32,100,101,102,105,110,105,116,105,111,110,32,119,97,115,32,101,120,116,101,110,100,101,100,32,105,110,32,85,110,105,99,111,100,101,32,116,111,32,105,110,99,108,117,100,101,32,109,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,107,105,110,100,115,32,111,102,32,99,111,109,112,111,115,105,116,101,32,99,104,97,114,97,99,116,101,114,32,98,121,32,103,105,118,105,110,103,32,101,97,99,104,32,99,104,97,114,97,99,116,101,114,32,97,32,103,114,97,112,104,101,109,101,32,98,114,101,97,107,105,110,103,32,112,114,111,112,101,114,116,121,44,32,97,110,100,32,99,114,101,97,116,105,110,103,32,114,117,108,101,115,32,116,104,97,116,32,117,115,101,32,116,104,101,115,101,32,112,114,111,112,101,114,116,105,101,115,32,116,111,32,100,101,102,105,110,101,32,116,104,101,32,98,111,117,110,100,97,114,105,101,115,32,111,102,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,115,46,32,73,110,32,80,67,82,69,32,114,101,108,101,97,115,101,115,32,108,97,116,101,114,32,116,104,97,110,32,56,46,51,49,44,32,92,88,32,109,97,116,99,104,101,115,32,111,110,101,32,111,102,32,116,104,101,115,101,32,99,108,117,115,116,101,114,115,46>>]},{p,[],[<<92,88,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,97,116,32,108,101,97,115,116,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,110,32,105,116,32,100,101,99,105,100,101,115,32,119,104,101,116,104,101,114,32,116,111,32,97,100,100,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,117,108,101,115,32,102,111,114,32,101,110,100,105,110,103,32,97,32,99,108,117,115,116,101,114,58>>]},{ol,[],[{li,[],[{p,[],[<<69,110,100,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,98,101,116,119,101,101,110,32,67,82,32,97,110,100,32,76,70,59,32,111,116,104,101,114,119,105,115,101,32,101,110,100,32,97,102,116,101,114,32,97,110,121,32,99,111,110,116,114,111,108,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,98,114,101,97,107,32,72,97,110,103,117,108,32,40,97,32,75,111,114,101,97,110,32,115,99,114,105,112,116,41,32,115,121,108,108,97,98,108,101,32,115,101,113,117,101,110,99,101,115,46,32,72,97,110,103,117,108,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,111,102,32,102,105,118,101,32,116,121,112,101,115,58,32,76,44,32,86,44,32,84,44,32,76,86,44,32,97,110,100,32,76,86,84,46,32,65,110,32,76,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,76,44,32,86,44,32,76,86,44,32,111,114,32,76,86,84,32,99,104,97,114,97,99,116,101,114,46,32,65,110,32,76,86,32,111,114,32,86,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,86,32,111,114,32,84,32,99,104,97,114,97,99,116,101,114,46,32,65,110,32,76,86,84,32,111,114,32,84,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,102,111,108,108,111,119,101,100,32,111,110,108,121,32,98,121,32,97,32,84,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,98,101,102,111,114,101,32,101,120,116,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,32,111,114,32,115,112,97,99,105,110,103,32,109,97,114,107,115,46,32,67,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,34,109,97,114,107,34,32,112,114,111,112,101,114,116,121,32,97,108,119,97,121,115,32,104,97,118,101,32,116,104,101,32,34,101,120,116,101,110,100,34,32,103,114,97,112,104,101,109,101,32,98,114,101,97,107,105,110,103,32,112,114,111,112,101,114,116,121,46>>]}]},{li,[],[{p,[],[<<68,111,32,110,111,116,32,101,110,100,32,97,102,116,101,114,32,112,114,101,112,101,110,100,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{li,[],[{p,[],[<<79,116,104,101,114,119,105,115,101,44,32,101,110,100,32,116,104,101,32,99,108,117,115,116,101,114,46>>]}]}]},{p,[],[{em,[],[<<80,67,82,69,32,65,100,100,105,116,105,111,110,97,108,32,80,114,111,112,101,114,116,105,101,115>>]}]},{p,[],[<<73,110,32,97,100,100,105,116,105,111,110,32,116,111,32,116,104,101,32,115,116,97,110,100,97,114,100,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,100,101,115,99,114,105,98,101,100,32,101,97,114,108,105,101,114,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,102,111,117,114,32,109,111,114,101,32,116,104,97,116,32,109,97,107,101,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,99,111,110,118,101,114,116,32,116,114,97,100,105,116,105,111,110,97,108,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,115,117,99,104,32,97,115,32,92,119,32,97,110,100,32,92,115,32,116,111,32,117,115,101,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,46,32,80,67,82,69,32,117,115,101,115,32,116,104,101,115,101,32,110,111,110,45,115,116,97,110,100,97,114,100,44,32,110,111,110,45,80,101,114,108,32,112,114,111,112,101,114,116,105,101,115,32,105,110,116,101,114,110,97,108,108,121,32,119,104,101,110,32,116,104,101,32>>,{code,[],[<<117,99,112>>]},<<32,111,112,116,105,111,110,32,105,115,32,112,97,115,115,101,100,46,32,72,111,119,101,118,101,114,44,32,116,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,101,120,112,108,105,99,105,116,108,121,46,32,84,104,101,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<88,97,110>>]},{dd,[],[{p,[],[<<65,110,121,32,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,101,105,116,104,101,114,32,116,104,101,32,76,32,40,108,101,116,116,101,114,41,32,111,114,32,116,104,101,32,78,32,40,110,117,109,98,101,114,41,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<88,112,115>>]},{dd,[],[{p,[],[<<65,110,121,32,80,111,115,105,120,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,97,98,44,32,108,105,110,101,32,102,101,101,100,44,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,109,32,102,101,101,100,44,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,97,110,100,32,97,110,121,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,90,32,40,115,101,112,97,114,97,116,111,114,41,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<88,115,112>>]},{dd,[],[{p,[],[<<65,110,121,32,80,101,114,108,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,97,115,32,88,112,115,44,32,101,120,99,101,112,116,32,116,104,97,116,32,118,101,114,116,105,99,97,108,32,116,97,98,32,105,115,32,101,120,99,108,117,100,101,100,46>>]}]},{dt,[],[<<88,119,100>>]},{dd,[],[{p,[],[<<65,110,121,32,80,101,114,108,32,34,119,111,114,100,34,32,99,104,97,114,97,99,116,101,114,46,32,77,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,88,97,110,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101,46>>]}]}]},{p,[],[<<80,101,114,108,32,97,110,100,32,80,79,83,73,88,32,115,112,97,99,101,32,97,114,101,32,110,111,119,32,116,104,101,32,115,97,109,101,46,32,80,101,114,108,32,97,100,100,101,100,32,86,84,32,116,111,32,105,116,115,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,32,115,101,116,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,32,97,110,100,32,80,67,82,69,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46>>]},{p,[],[<<88,97,110,32,109,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,101,105,116,104,101,114,32,116,104,101,32,76,32,40,108,101,116,116,101,114,41,32,111,114,32,116,104,101,32,78,32,40,110,117,109,98,101,114,41,32,112,114,111,112,101,114,116,121,46,32,88,112,115,32,109,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,97,98,44,32,108,105,110,101,102,101,101,100,44,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,109,32,102,101,101,100,44,32,111,114,32,99,97,114,114,105,97,103,101,32,114,101,116,117,114,110,44,32,97,110,100,32,97,110,121,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,104,97,115,32,116,104,101,32,90,32,40,115,101,112,97,114,97,116,111,114,41,32,112,114,111,112,101,114,116,121,46,32,88,115,112,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,88,112,115,59,32,105,116,32,117,115,101,100,32,116,111,32,101,120,99,108,117,100,101,32,118,101,114,116,105,99,97,108,32,116,97,98,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,44,32,98,117,116,32,80,101,114,108,32,99,104,97,110,103,101,100,44,32,97,110,100,32,115,111,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,88,119,100,32,109,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,88,97,110,44,32,112,108,117,115,32,117,110,100,101,114,115,99,111,114,101,46>>]},{p,[],[<<84,104,101,114,101,32,105,115,32,97,110,111,116,104,101,114,32,110,111,110,45,115,116,97,110,100,97,114,100,32,112,114,111,112,101,114,116,121,44,32,88,117,99,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,85,110,105,118,101,114,115,97,108,32,67,104,97,114,97,99,116,101,114,32,78,97,109,101,32,105,110,32,67,43,43,32,97,110,100,32,111,116,104,101,114,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,115,46,32,84,104,101,115,101,32,97,114,101,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,36,44,32,64,44,32,96,32,40,103,114,97,118,101,32,97,99,99,101,110,116,41,44,32,97,110,100,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,111,100,101,32,112,111,105,110,116,115,32,62,61,32,85,43,48,48,65,48,44,32,101,120,99,101,112,116,32,102,111,114,32,116,104,101,32,115,117,114,114,111,103,97,116,101,115,32,85,43,68,56,48,48,32,116,111,32,85,43,68,70,70,70,46,32,78,111,116,105,99,101,32,116,104,97,116,32,109,111,115,116,32,98,97,115,101,32,40,65,83,67,73,73,41,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,101,120,99,108,117,100,101,100,46,32,40,85,110,105,118,101,114,115,97,108,32,67,104,97,114,97,99,116,101,114,32,78,97,109,101,115,32,97,114,101,32,111,102,32,116,104,101,32,102,111,114,109,32,92,117,72,72,72,72,32,111,114,32,92,85,72,72,72,72,72,72,72,72,44,32,119,104,101,114,101,32,72,32,105,115,32,97,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,46,32,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,88,117,99,32,112,114,111,112,101,114,116,121,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,115,101,32,115,101,113,117,101,110,99,101,115,32,98,117,116,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,116,104,101,121,32,114,101,112,114,101,115,101,110,116,46,41>>]},{p,[],[{em,[],[<<82,101,115,101,116,116,105,110,103,32,116,104,101,32,77,97,116,99,104,32,83,116,97,114,116>>]}]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,75,32,99,97,117,115,101,115,32,97,110,121,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,32,99,104,97,114,97,99,116,101,114,115,32,110,111,116,32,116,111,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,102,105,110,97,108,32,109,97,116,99,104,101,100,32,115,101,113,117,101,110,99,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,98,97,114,34,44,32,98,117,116,32,114,101,112,111,114,116,115,32,116,104,97,116,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,32,34,98,97,114,34,58>>]},{pre,[],[{code,[],[<<102,111,111,92,75,98,97,114>>]}]},{p,[],[<<84,104,105,115,32,102,101,97,116,117,114,101,32,105,115,32,115,105,109,105,108,97,114,32,116,111,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,46,32,72,111,119,101,118,101,114,44,32,105,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,98,101,102,111,114,101,32,116,104,101,32,114,101,97,108,32,109,97,116,99,104,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,116,111,32,98,101,32,111,102,32,102,105,120,101,100,32,108,101,110,103,116,104,44,32,97,115,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,100,111,46,32,84,104,101,32,117,115,101,32,111,102,32,92,75,32,100,111,101,115,32,110,111,116,32,105,110,116,101,114,102,101,114,101,32,119,105,116,104,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,98,97,114,34,44,32,116,104,101,32,102,105,114,115,116,32,115,117,98,115,116,114,105,110,103,32,105,115,32,115,116,105,108,108,32,115,101,116,32,116,111,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,102,111,111,41,92,75,98,97,114>>]}]},{p,[],[<<80,101,114,108,32,100,111,99,117,109,101,110,116,115,32,116,104,97,116,32,116,104,101,32,117,115,101,32,111,102,32,92,75,32,119,105,116,104,105,110,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,34,110,111,116,32,119,101,108,108,32,100,101,102,105,110,101,100,34,46,32,73,110,32,80,67,82,69,44,32,92,75,32,105,115,32,97,99,116,101,100,32,117,112,111,110,32,119,104,101,110,32,105,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,44,32,98,117,116,32,105,115,32,105,103,110,111,114,101,100,32,105,110,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,78,111,116,101,32,116,104,97,116,32,119,104,101,110,32,97,32,112,97,116,116,101,114,110,32,115,117,99,104,32,97,115,32,40,63,61,97,98,92,75,41,32,109,97,116,99,104,101,115,44,32,116,104,101,32,114,101,112,111,114,116,101,100,32,115,116,97,114,116,32,111,102,32,116,104,101,32,109,97,116,99,104,32,99,97,110,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,109,97,116,99,104,46>>]},{p,[],[{em,[],[<<83,105,109,112,108,101,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<84,104,101,32,102,105,110,97,108,32,117,115,101,32,111,102,32,98,97,99,107,115,108,97,115,104,32,105,115,32,102,111,114,32,99,101,114,116,97,105,110,32,115,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,112,101,99,105,102,105,101,115,32,97,32,99,111,110,100,105,116,105,111,110,32,116,104,97,116,32,109,117,115,116,32,98,101,32,109,101,116,32,97,116,32,97,32,112,97,114,116,105,99,117,108,97,114,32,112,111,105,110,116,32,105,110,32,97,32,109,97,116,99,104,44,32,119,105,116,104,111,117,116,32,99,111,110,115,117,109,105,110,103,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,101,32,117,115,101,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,109,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,98,97,99,107,115,108,97,115,104,101,100,32,97,115,115,101,114,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[<<92,98>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,46>>]},{dt,[],[<<92,66>>]},{dd,[],[<<77,97,116,99,104,101,115,32,119,104,101,110,32,110,111,116,32,97,116,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,46>>]},{dt,[],[<<92,65>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,90>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,110,100,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,122>>]},{dd,[],[<<77,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46>>]},{dt,[],[<<92,71>>]},{dd,[],[<<77,97,116,99,104,101,115,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46>>]}]},{p,[],[<<73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,92,98,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,59,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,73,102,32,97,110,121,32,111,116,104,101,114,32,111,102,32,116,104,101,115,101,32,97,115,115,101,114,116,105,111,110,115,32,97,112,112,101,97,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,98,121,32,100,101,102,97,117,108,116,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,92,66,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,32,66,41,46>>]},{p,[],[<<65,32,119,111,114,100,32,98,111,117,110,100,97,114,121,32,105,115,32,97,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,104,101,114,101,32,116,104,101,32,99,117,114,114,101,110,116,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,104,97,114,97,99,116,101,114,32,100,111,32,110,111,116,32,98,111,116,104,32,109,97,116,99,104,32,92,119,32,111,114,32,92,87,32,40,116,104,97,116,32,105,115,44,32,111,110,101,32,109,97,116,99,104,101,115,32,92,119,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,109,97,116,99,104,101,115,32,92,87,41,44,32,111,114,32,116,104,101,32,115,116,97,114,116,32,111,114,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,105,102,32,116,104,101,32,102,105,114,115,116,32,111,114,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,109,97,116,99,104,101,115,32,92,119,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,73,110,32,85,84,70,32,109,111,100,101,44,32,116,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,92,119,32,97,110,100,32,92,87,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<46,32,87,104,101,110,32,116,104,105,115,32,105,115,32,100,111,110,101,44,32,105,116,32,97,108,115,111,32,97,102,102,101,99,116,115,32,92,98,32,97,110,100,32,92,66,46,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,100,111,32,110,111,116,32,104,97,118,101,32,97,32,115,101,112,97,114,97,116,101,32,34,115,116,97,114,116,32,111,102,32,119,111,114,100,34,32,111,114,32,34,101,110,100,32,111,102,32,119,111,114,100,34,32,109,101,116,97,115,101,113,117,101,110,99,101,46,32,72,111,119,101,118,101,114,44,32,119,104,97,116,101,118,101,114,32,102,111,108,108,111,119,115,32,92,98,32,110,111,114,109,97,108,108,121,32,100,101,116,101,114,109,105,110,101,115,32,119,104,105,99,104,32,105,116,32,105,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,114,97,103,109,101,110,116,32,92,98,97,32,109,97,116,99,104,101,115,32,34,97,34,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,119,111,114,100,46>>]},{p,[],[<<84,104,101,32,92,65,44,32,92,90,44,32,97,110,100,32,92,122,32,97,115,115,101,114,116,105,111,110,115,32,100,105,102,102,101,114,32,102,114,111,109,32,116,104,101,32,116,114,97,100,105,116,105,111,110,97,108,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,40,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,32,105,110,32,116,104,97,116,32,116,104,101,121,32,111,110,108,121,32,101,118,101,114,32,109,97,116,99,104,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,97,110,100,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,97,116,101,118,101,114,32,111,112,116,105,111,110,115,32,97,114,101,32,115,101,116,46,32,84,104,117,115,44,32,116,104,101,121,32,97,114,101,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,46,32,84,104,101,115,101,32,116,104,114,101,101,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,110,111,116,32,97,102,102,101,99,116,101,100,32,98,121,32,111,112,116,105,111,110,115,32>>,{code,[],[<<110,111,116,98,111,108>>]},<<32,111,114,32>>,{code,[],[<<110,111,116,101,111,108>>]},<<44,32,119,104,105,99,104,32,97,102,102,101,99,116,32,111,110,108,121,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,105,115,32,110,111,110,45,122,101,114,111,44,32,105,110,100,105,99,97,116,105,110,103,32,116,104,97,116,32,109,97,116,99,104,105,110,103,32,105,115,32,116,111,32,115,116,97,114,116,32,97,116,32,97,32,112,111,105,110,116,32,111,116,104,101,114,32,116,104,97,110,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,92,65,32,99,97,110,32,110,101,118,101,114,32,109,97,116,99,104,46,32,84,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32,92,90,32,97,110,100,32,92,122,32,105,115,32,116,104,97,116,32,92,90,32,109,97,116,99,104,101,115,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,97,110,100,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,44,32,119,104,105,108,101,32,92,122,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,46>>]},{p,[],[<<84,104,101,32,92,71,32,97,115,115,101,114,116,105,111,110,32,105,115,32,116,114,117,101,32,111,110,108,121,32,119,104,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,105,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,112,111,105,110,116,32,111,102,32,116,104,101,32,109,97,116,99,104,44,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<46,32,73,116,32,100,105,102,102,101,114,115,32,102,114,111,109,32,92,65,32,119,104,101,110,32,116,104,101,32,118,97,108,117,101,32,111,102,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,105,115,32,110,111,110,45,122,101,114,111,46,32,66,121,32,99,97,108,108,105,110,103,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,109,117,108,116,105,112,108,101,32,116,105,109,101,115,32,119,105,116,104,32,97,112,112,114,111,112,114,105,97,116,101,32,97,114,103,117,109,101,110,116,115,44,32,121,111,117,32,99,97,110,32,109,105,109,105,99,32,116,104,101,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,103>>]},<<44,32,97,110,100,32,105,116,32,105,115,32,105,110,32,116,104,105,115,32,107,105,110,100,32,111,102,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,119,104,101,114,101,32,92,71,32,99,97,110,32,98,101,32,117,115,101,102,117,108,46>>]},{p,[],[<<78,111,116,105,99,101,44,32,104,111,119,101,118,101,114,44,32,116,104,97,116,32,116,104,101,32,80,67,82,69,32,105,110,116,101,114,112,114,101,116,97,116,105,111,110,32,111,102,32,92,71,44,32,97,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,44,32,105,115,32,115,117,98,116,108,121,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32,80,101,114,108,44,32,119,104,105,99,104,32,100,101,102,105,110,101,115,32,105,116,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,109,97,116,99,104,46,32,73,110,32,80,101,114,108,44,32,116,104,101,115,101,32,99,97,110,32,98,101,32,100,105,102,102,101,114,101,110,116,32,119,104,101,110,32,116,104,101,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,32,115,116,114,105,110,103,32,119,97,115,32,101,109,112,116,121,46,32,65,115,32,80,67,82,69,32,100,111,101,115,32,111,110,108,121,32,111,110,101,32,109,97,116,99,104,32,97,116,32,97,32,116,105,109,101,44,32,105,116,32,99,97,110,110,111,116,32,114,101,112,114,111,100,117,99,101,32,116,104,105,115,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<73,102,32,97,108,108,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,111,102,32,97,32,112,97,116,116,101,114,110,32,98,101,103,105,110,32,119,105,116,104,32,92,71,44,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,110,99,104,111,114,101,100,32,116,111,32,116,104,101,32,115,116,97,114,116,105,110,103,32,109,97,116,99,104,32,112,111,115,105,116,105,111,110,44,32,97,110,100,32,116,104,101,32,34,97,110,99,104,111,114,101,100,34,32,102,108,97,103,32,105,115,32,115,101,116,32,105,110,32,116,104,101,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{a,[{id,<<115,101,99,116,52>>}],[]},{h2,[],[<<67,105,114,99,117,109,102,108,101,120,32,97,110,100,32,68,111,108,108,97,114>>]},{p,[],[<<84,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,122,101,114,111,45,119,105,100,116,104,32,97,115,115,101,114,116,105,111,110,115,46,32,84,104,97,116,32,105,115,44,32,116,104,101,121,32,116,101,115,116,32,102,111,114,32,97,32,112,97,114,116,105,99,117,108,97,114,32,99,111,110,100,105,116,105,111,110,32,116,111,32,98,101,32,116,114,117,101,32,119,105,116,104,111,117,116,32,99,111,110,115,117,109,105,110,103,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,105,110,32,116,104,101,32,100,101,102,97,117,108,116,32,109,97,116,99,104,105,110,103,32,109,111,100,101,44,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,32,111,110,108,121,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,73,102,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,105,115,32,110,111,110,45,122,101,114,111,44,32,99,105,114,99,117,109,102,108,101,120,32,99,97,110,32,110,101,118,101,114,32,109,97,116,99,104,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,117,110,115,101,116,46,32,73,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,99,105,114,99,117,109,102,108,101,120,32,104,97,115,32,97,110,32,101,110,116,105,114,101,108,121,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,32,40,115,101,101,32,98,101,108,111,119,41,46>>]},{p,[],[<<67,105,114,99,117,109,102,108,101,120,32,110,101,101,100,115,32,110,111,116,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,102,32,115,111,109,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,118,111,108,118,101,100,44,32,98,117,116,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,116,104,105,110,103,32,105,110,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,101,118,101,114,32,116,111,32,109,97,116,99,104,32,116,104,97,116,32,98,114,97,110,99,104,46,32,73,102,32,97,108,108,32,112,111,115,115,105,98,108,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,115,116,97,114,116,32,119,105,116,104,32,97,32,99,105,114,99,117,109,102,108,101,120,44,32,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,99,111,110,115,116,114,97,105,110,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,105,116,32,105,115,32,115,97,105,100,32,116,111,32,98,101,32,97,110,32,34,97,110,99,104,111,114,101,100,34,32,112,97,116,116,101,114,110,46,32,40,84,104,101,114,101,32,97,114,101,32,97,108,115,111,32,111,116,104,101,114,32,99,111,110,115,116,114,117,99,116,115,32,116,104,97,116,32,99,97,110,32,99,97,117,115,101,32,97,32,112,97,116,116,101,114,110,32,116,111,32,98,101,32,97,110,99,104,111,114,101,100,46,41>>]},{p,[],[<<84,104,101,32,100,111,108,108,97,114,32,99,104,97,114,97,99,116,101,114,32,105,115,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,32,111,110,108,121,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,40,98,121,32,100,101,102,97,117,108,116,41,46,32,78,111,116,105,99,101,32,104,111,119,101,118,101,114,32,116,104,97,116,32,105,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,110,101,119,108,105,110,101,46,32,68,111,108,108,97,114,32,110,101,101,100,115,32,110,111,116,32,116,111,32,98,101,32,116,104,101,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,102,32,115,111,109,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,118,111,108,118,101,100,44,32,98,117,116,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,105,110,32,97,110,121,32,98,114,97,110,99,104,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,46,32,68,111,108,108,97,114,32,104,97,115,32,110,111,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,100,111,108,108,97,114,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,105,116,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,84,104,105,115,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,92,90,32,97,115,115,101,114,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,99,104,97,110,103,101,100,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46,32,87,104,101,110,32,116,104,105,115,32,105,115,32,116,104,101,32,99,97,115,101,44,32,97,32,99,105,114,99,117,109,102,108,101,120,32,109,97,116,99,104,101,115,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,105,110,116,101,114,110,97,108,32,110,101,119,108,105,110,101,115,32,97,110,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,73,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,97,102,116,101,114,32,97,32,110,101,119,108,105,110,101,32,116,104,97,116,32,101,110,100,115,32,116,104,101,32,115,116,114,105,110,103,46,32,65,32,100,111,108,108,97,114,32,109,97,116,99,104,101,115,32,98,101,102,111,114,101,32,97,110,121,32,110,101,119,108,105,110,101,115,32,105,110,32,116,104,101,32,115,116,114,105,110,103,44,32,97,110,100,32,97,116,32,116,104,101,32,118,101,114,121,32,101,110,100,44,32,119,104,101,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46,32,87,104,101,110,32,110,101,119,108,105,110,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,44,32,105,115,111,108,97,116,101,100,32,67,82,32,97,110,100,32,76,70,32,99,104,97,114,97,99,116,101,114,115,32,100,111,32,110,111,116,32,105,110,100,105,99,97,116,101,32,110,101,119,108,105,110,101,115,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,112,97,116,116,101,114,110,32,47,94,97,98,99,36,47,32,109,97,116,99,104,101,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,34,100,101,102,92,110,97,98,99,34,32,40,119,104,101,114,101,32,92,110,32,114,101,112,114,101,115,101,110,116,115,32,97,32,110,101,119,108,105,110,101,41,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,44,32,98,117,116,32,110,111,116,32,111,116,104,101,114,119,105,115,101,46,32,83,111,44,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,97,110,99,104,111,114,101,100,32,105,110,32,115,105,110,103,108,101,45,108,105,110,101,32,109,111,100,101,32,98,101,99,97,117,115,101,32,97,108,108,32,98,114,97,110,99,104,101,115,32,115,116,97,114,116,32,119,105,116,104,32,94,32,97,114,101,32,110,111,116,32,97,110,99,104,111,114,101,100,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,44,32,97,110,100,32,97,32,109,97,116,99,104,32,102,111,114,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,112,111,115,115,105,98,108,101,32,119,104,101,110,32,97,114,103,117,109,101,110,116,32>>,{em,[],[<<115,116,97,114,116,111,102,102,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,105,115,32,110,111,110,45,122,101,114,111,46,32,79,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,105,115,32,105,103,110,111,114,101,100,32,105,102,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,115,101,113,117,101,110,99,101,115,32,92,65,44,32,92,90,44,32,97,110,100,32,92,122,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,115,116,97,114,116,32,97,110,100,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,110,32,98,111,116,104,32,109,111,100,101,115,46,32,73,102,32,97,108,108,32,98,114,97,110,99,104,101,115,32,111,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,32,119,105,116,104,32,92,65,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32,97,110,99,104,111,114,101,100,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,101,116,46>>]},{a,[{id,<<115,101,99,116,53>>}],[]},{h2,[],[<<70,117,108,108,32,83,116,111,112,32,40,80,101,114,105,111,100,44,32,68,111,116,41,32,97,110,100,32,92,78>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,32,100,111,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,101,120,99,101,112,116,32,40,98,121,32,100,101,102,97,117,108,116,41,32,97,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,115,105,103,110,105,102,105,101,115,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,46>>]},{p,[],[<<87,104,101,110,32,97,32,108,105,110,101,32,101,110,100,105,110,103,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,100,111,116,32,110,101,118,101,114,32,109,97,116,99,104,101,115,32,116,104,97,116,32,99,104,97,114,97,99,116,101,114,46,32,87,104,101,110,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,32,105,115,32,117,115,101,100,44,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,67,82,32,105,102,32,105,116,32,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,76,70,44,32,111,116,104,101,114,119,105,115,101,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,105,115,111,108,97,116,101,100,32,67,82,115,32,97,110,100,32,76,70,115,41,46,32,87,104,101,110,32,97,110,121,32,85,110,105,99,111,100,101,32,108,105,110,101,32,101,110,100,105,110,103,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,44,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,67,82,44,32,76,70,44,32,111,114,32,97,110,121,32,111,102,32,116,104,101,32,111,116,104,101,114,32,108,105,110,101,45,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,100,111,116,32,114,101,103,97,114,100,105,110,103,32,110,101,119,108,105,110,101,115,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,105,115,32,115,101,116,44,32,97,32,100,111,116,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,44,32,119,105,116,104,111,117,116,32,101,120,99,101,112,116,105,111,110,46,32,73,102,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,67,82,76,70,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,116,97,107,101,115,32,116,119,111,32,100,111,116,115,32,116,111,32,109,97,116,99,104,32,105,116,46>>]},{p,[],[<<84,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,100,111,116,32,105,115,32,101,110,116,105,114,101,108,121,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,99,105,114,99,117,109,102,108,101,120,32,97,110,100,32,100,111,108,108,97,114,44,32,116,104,101,32,111,110,108,121,32,114,101,108,97,116,105,111,110,115,104,105,112,32,105,115,32,116,104,97,116,32,98,111,116,104,32,105,110,118,111,108,118,101,32,110,101,119,108,105,110,101,115,46,32,68,111,116,32,104,97,115,32,110,111,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46>>]},{p,[],[<<84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,78,32,98,101,104,97,118,101,115,32,108,105,107,101,32,97,32,100,111,116,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,105,115,32,110,111,116,32,97,102,102,101,99,116,101,100,32,98,121,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,68,79,84,65,76,76>>]},<<46,32,84,104,97,116,32,105,115,44,32,105,116,32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,101,120,99,101,112,116,32,111,110,101,32,116,104,97,116,32,115,105,103,110,105,102,105,101,115,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,46,32,80,101,114,108,32,97,108,115,111,32,117,115,101,115,32,92,78,32,116,111,32,109,97,116,99,104,32,99,104,97,114,97,99,116,101,114,115,32,98,121,32,110,97,109,101,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,115,117,112,112,111,114,116,32,116,104,105,115,46>>]},{a,[{id,<<115,101,99,116,54>>}],[]},{h2,[],[<<77,97,116,99,104,105,110,103,32,97,32,83,105,110,103,108,101,32,68,97,116,97,32,85,110,105,116>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,67,32,109,97,116,99,104,101,115,32,97,110,121,32,100,97,116,97,32,117,110,105,116,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,97,32,85,84,70,32,109,111,100,101,32,105,115,32,115,101,116,46,32,79,110,101,32,100,97,116,97,32,117,110,105,116,32,105,115,32,111,110,101,32,98,121,116,101,46,32,85,110,108,105,107,101,32,97,32,100,111,116,44,32,92,67,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,108,105,110,101,45,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,102,101,97,116,117,114,101,32,105,115,32,112,114,111,118,105,100,101,100,32,105,110,32,80,101,114,108,32,116,111,32,109,97,116,99,104,32,105,110,100,105,118,105,100,117,97,108,32,98,121,116,101,115,32,105,110,32,85,84,70,45,56,32,109,111,100,101,44,32,98,117,116,32,105,116,32,105,115,32,117,110,99,108,101,97,114,32,104,111,119,32,105,116,32,99,97,110,32,117,115,101,102,117,108,108,121,32,98,101,32,117,115,101,100,46,32,65,115,32,92,67,32,98,114,101,97,107,115,32,117,112,32,99,104,97,114,97,99,116,101,114,115,32,105,110,116,111,32,105,110,100,105,118,105,100,117,97,108,32,100,97,116,97,32,117,110,105,116,115,44,32,109,97,116,99,104,105,110,103,32,111,110,101,32,117,110,105,116,32,119,105,116,104,32,92,67,32,105,110,32,97,32,85,84,70,32,109,111,100,101,32,109,101,97,110,115,32,116,104,97,116,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,116,114,105,110,103,32,99,97,110,32,115,116,97,114,116,32,119,105,116,104,32,97,32,109,97,108,102,111,114,109,101,100,32,85,84,70,32,99,104,97,114,97,99,116,101,114,46,32,84,104,105,115,32,104,97,115,32,117,110,100,101,102,105,110,101,100,32,114,101,115,117,108,116,115,44,32,97,115,32,80,67,82,69,32,97,115,115,117,109,101,115,32,116,104,97,116,32,105,116,32,100,101,97,108,115,32,119,105,116,104,32,118,97,108,105,100,32,85,84,70,32,115,116,114,105,110,103,115,46>>]},{p,[],[<<80,67,82,69,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,92,67,32,116,111,32,97,112,112,101,97,114,32,105,110,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,40,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,41,32,105,110,32,97,32,85,84,70,32,109,111,100,101,44,32,97,115,32,116,104,105,115,32,119,111,117,108,100,32,109,97,107,101,32,105,116,32,105,109,112,111,115,115,105,98,108,101,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,111,111,107,98,101,104,105,110,100,46>>]},{p,[],[<<84,104,101,32,92,67,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,105,115,32,98,101,115,116,32,97,118,111,105,100,101,100,46,32,72,111,119,101,118,101,114,44,32,111,110,101,32,119,97,121,32,111,102,32,117,115,105,110,103,32,105,116,32,116,104,97,116,32,97,118,111,105,100,115,32,116,104,101,32,112,114,111,98,108,101,109,32,111,102,32,109,97,108,102,111,114,109,101,100,32,85,84,70,32,99,104,97,114,97,99,116,101,114,115,32,105,115,32,116,111,32,117,115,101,32,97,32,108,111,111,107,97,104,101,97,100,32,116,111,32,99,104,101,99,107,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,44,32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,32,85,84,70,45,56,32,115,116,114,105,110,103,32,40,105,103,110,111,114,101,32,119,104,105,116,101,115,112,97,99,101,32,97,110,100,32,108,105,110,101,32,98,114,101,97,107,115,41,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,124,32,40,63,61,91,92,120,48,48,45,92,120,55,102,93,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,56,48,45,92,120,123,55,102,102,125,93,41,40,92,67,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,123,56,48,48,125,45,92,120,123,102,102,102,102,125,93,41,40,92,67,41,40,92,67,41,40,92,67,41,32,124,10,32,32,32,32,40,63,61,91,92,120,123,49,48,48,48,48,125,45,92,120,123,49,102,102,102,102,102,125,93,41,40,92,67,41,40,92,67,41,40,92,67,41,40,92,67,41,41>>]}]},{p,[],[<<65,32,103,114,111,117,112,32,116,104,97,116,32,115,116,97,114,116,115,32,119,105,116,104,32,40,63,124,32,114,101,115,101,116,115,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,110,117,109,98,101,114,115,32,105,110,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},<<41,46,32,84,104,101,32,97,115,115,101,114,116,105,111,110,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,98,114,97,110,99,104,32,99,104,101,99,107,32,116,104,101,32,110,101,120,116,32,85,84,70,45,56,32,99,104,97,114,97,99,116,101,114,32,102,111,114,32,118,97,108,117,101,115,32,119,104,111,115,101,32,101,110,99,111,100,105,110,103,32,117,115,101,115,32,49,44,32,50,44,32,51,44,32,111,114,32,52,32,98,121,116,101,115,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,84,104,101,32,105,110,100,105,118,105,100,117,97,108,32,98,121,116,101,115,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,97,114,101,32,116,104,101,110,32,99,97,112,116,117,114,101,100,32,98,121,32,116,104,101,32,97,112,112,114,111,112,114,105,97,116,101,32,110,117,109,98,101,114,32,111,102,32,103,114,111,117,112,115,46>>]},{a,[{id,<<115,101,99,116,55>>}],[]},{h2,[],[<<83,113,117,97,114,101,32,66,114,97,99,107,101,116,115,32,97,110,100,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]},{p,[],[<<65,110,32,111,112,101,110,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,116,101,114,109,105,110,97,116,101,100,32,98,121,32,97,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,46,32,65,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,111,110,32,105,116,115,32,111,119,110,32,105,115,32,110,111,116,32,115,112,101,99,105,97,108,32,98,121,32,100,101,102,97,117,108,116,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,74,65,86,65,83,67,82,73,80,84,95,67,79,77,80,65,84>>]},<<32,105,115,32,115,101,116,44,32,97,32,108,111,110,101,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,99,97,117,115,101,115,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,46,32,73,102,32,97,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,105,115,32,114,101,113,117,105,114,101,100,32,97,115,32,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,99,108,97,115,115,44,32,105,116,32,105,115,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,32,40,97,102,116,101,114,32,97,110,32,105,110,105,116,105,97,108,32,99,105,114,99,117,109,102,108,101,120,44,32,105,102,32,112,114,101,115,101,110,116,41,32,111,114,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,46>>]},{p,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,100,97,116,97,32,117,110,105,116,32,108,111,110,103,46,32,65,32,109,97,116,99,104,101,100,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,98,101,32,105,110,32,116,104,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,100,101,102,105,110,101,100,32,98,121,32,116,104,101,32,99,108,97,115,115,44,32,117,110,108,101,115,115,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,32,100,101,102,105,110,105,116,105,111,110,32,105,115,32,97,32,99,105,114,99,117,109,102,108,101,120,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,115,117,98,106,101,99,116,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,32,116,104,101,32,115,101,116,32,100,101,102,105,110,101,100,32,98,121,32,116,104,101,32,99,108,97,115,115,46,32,73,102,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,114,101,113,117,105,114,101,100,32,97,115,32,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,99,108,97,115,115,44,32,101,110,115,117,114,101,32,116,104,97,116,32,105,116,32,105,115,32,110,111,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,101,115,99,97,112,101,32,105,116,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,46>>]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32>>,{code,[],[<<91,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,97,110,121,32,108,111,119,101,114,99,97,115,101,32,118,111,119,101,108,44,32,119,104,105,108,101,32>>,{code,[],[<<91,94,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,97,110,121,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,110,111,116,32,97,32,108,111,119,101,114,99,97,115,101,32,118,111,119,101,108,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,106,117,115,116,32,97,32,99,111,110,118,101,110,105,101,110,116,32,110,111,116,97,116,105,111,110,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,105,110,32,116,104,101,32,99,108,97,115,115,32,98,121,32,101,110,117,109,101,114,97,116,105,110,103,32,116,104,111,115,101,32,116,104,97,116,32,97,114,101,32,110,111,116,46,32,65,32,99,108,97,115,115,32,116,104,97,116,32,115,116,97,114,116,115,32,119,105,116,104,32,97,32,99,105,114,99,117,109,102,108,101,120,32,105,115,32,110,111,116,32,97,110,32,97,115,115,101,114,116,105,111,110,59,32,105,116,32,115,116,105,108,108,32,99,111,110,115,117,109,101,115,32,97,32,99,104,97,114,97,99,116,101,114,32,102,114,111,109,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,105,116,32,102,97,105,108,115,32,105,102,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,105,110,116,101,114,32,105,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,46>>]},{p,[],[<<73,110,32,85,84,70,45,56,32,109,111,100,101,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,40,48,120,102,102,102,102,41,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,97,32,99,108,97,115,115,32,97,115,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,111,102,32,100,97,116,97,32,117,110,105,116,115,44,32,111,114,32,98,121,32,117,115,105,110,103,32,116,104,101,32,92,120,123,32,101,115,99,97,112,105,110,103,32,109,101,99,104,97,110,105,115,109,46>>]},{p,[],[<<87,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,101,116,44,32,97,110,121,32,108,101,116,116,101,114,115,32,105,110,32,97,32,99,108,97,115,115,32,114,101,112,114,101,115,101,110,116,32,98,111,116,104,32,116,104,101,105,114,32,117,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,118,101,114,115,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,32,99,97,115,101,108,101,115,115,32>>,{code,[],[<<91,97,101,105,111,117,93>>]},<<32,109,97,116,99,104,101,115,32,34,65,34,32,97,110,100,32,34,97,34,44,32,97,110,100,32,97,32,99,97,115,101,108,101,115,115,32>>,{code,[],[<<91,94,97,101,105,111,117,93>>]},<<32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,34,65,34,44,32,98,117,116,32,97,32,99,97,115,101,102,117,108,32,118,101,114,115,105,111,110,32,119,111,117,108,100,46,32,73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,80,67,82,69,32,97,108,119,97,121,115,32,117,110,100,101,114,115,116,97,110,100,115,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,118,97,108,117,101,115,32,97,114,101,32,60,32,50,53,54,44,32,115,111,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,97,108,119,97,121,115,32,112,111,115,115,105,98,108,101,46,32,70,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,104,105,103,104,101,114,32,118,97,108,117,101,115,44,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,105,115,32,115,117,112,112,111,114,116,101,100,32,111,110,108,121,32,105,102,32,80,67,82,69,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,46,32,73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,117,115,101,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,110,32,97,32,85,84,70,32,109,111,100,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,62,61,44,32,101,110,115,117,114,101,32,116,104,97,116,32,80,67,82,69,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,32,97,110,100,32,119,105,116,104,32,85,84,70,32,115,117,112,112,111,114,116,46>>]},{p,[],[<<67,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,99,97,110,32,105,110,100,105,99,97,116,101,32,108,105,110,101,32,98,114,101,97,107,115,32,97,114,101,32,110,101,118,101,114,32,116,114,101,97,116,101,100,32,105,110,32,97,110,121,32,115,112,101,99,105,97,108,32,119,97,121,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,44,32,119,104,97,116,101,118,101,114,32,108,105,110,101,45,101,110,100,105,110,103,32,115,101,113,117,101,110,99,101,32,105,115,32,105,110,32,117,115,101,44,32,97,110,100,32,119,104,97,116,101,118,101,114,32,115,101,116,116,105,110,103,32,111,102,32,111,112,116,105,111,110,115,32>>,{code,[],[<<80,67,82,69,95,68,79,84,65,76,76>>]},<<32,97,110,100,32>>,{code,[],[<<80,67,82,69,95,77,85,76,84,73,76,73,78,69>>]},<<32,105,115,32,117,115,101,100,46,32,65,32,99,108,97,115,115,32,115,117,99,104,32,97,115,32,91,94,97,93,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,111,110,101,32,111,102,32,116,104,101,115,101,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,109,105,110,117,115,32,40,104,121,112,104,101,110,41,32,99,104,97,114,97,99,116,101,114,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,112,101,99,105,102,121,32,97,32,114,97,110,103,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,100,45,109,93,32,109,97,116,99,104,101,115,32,97,110,121,32,108,101,116,116,101,114,32,98,101,116,119,101,101,110,32,100,32,97,110,100,32,109,44,32,105,110,99,108,117,115,105,118,101,46,32,73,102,32,97,32,109,105,110,117,115,32,99,104,97,114,97,99,116,101,114,32,105,115,32,114,101,113,117,105,114,101,100,32,105,110,32,97,32,99,108,97,115,115,44,32,105,116,32,109,117,115,116,32,98,101,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,32,111,114,32,97,112,112,101,97,114,32,105,110,32,97,32,112,111,115,105,116,105,111,110,32,119,104,101,114,101,32,105,116,32,99,97,110,110,111,116,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,105,110,100,105,99,97,116,105,110,103,32,97,32,114,97,110,103,101,44,32,116,121,112,105,99,97,108,108,121,32,97,115,32,116,104,101,32,102,105,114,115,116,32,111,114,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,99,108,97,115,115,44,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,97,32,114,97,110,103,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,98,45,100,45,122,93,32,109,97,116,99,104,101,115,32,108,101,116,116,101,114,115,32,105,110,32,116,104,101,32,114,97,110,103,101,32,98,32,116,111,32,100,44,32,97,32,104,121,112,104,101,110,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,122,46>>]},{p,[],[<<84,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,32,34,93,34,32,99,97,110,110,111,116,32,98,101,32,116,104,101,32,101,110,100,32,99,104,97,114,97,99,116,101,114,32,111,102,32,97,32,114,97,110,103,101,46,32,65,32,112,97,116,116,101,114,110,32,115,117,99,104,32,97,115,32,91,87,45,93,52,54,93,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,108,97,115,115,32,111,102,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,40,34,87,34,32,97,110,100,32,34,45,34,41,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,34,52,54,93,34,44,32,115,111,32,105,116,32,119,111,117,108,100,32,109,97,116,99,104,32,34,87,52,54,93,34,32,111,114,32,34,45,52,54,93,34,46,32,72,111,119,101,118,101,114,44,32,105,102,32,34,93,34,32,105,115,32,101,115,99,97,112,101,100,32,119,105,116,104,32,97,32,98,97,99,107,115,108,97,115,104,44,32,105,116,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,114,97,110,103,101,44,32,115,111,32,91,87,45,92,93,52,54,93,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,108,97,115,115,32,99,111,110,116,97,105,110,105,110,103,32,97,32,114,97,110,103,101,32,102,111,108,108,111,119,101,100,32,98,121,32,116,119,111,32,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,111,99,116,97,108,32,111,114,32,104,101,120,97,100,101,99,105,109,97,108,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,34,93,34,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,116,111,32,101,110,100,32,97,32,114,97,110,103,101,46>>]},{p,[],[<<65,110,32,101,114,114,111,114,32,105,115,32,103,101,110,101,114,97,116,101,100,32,105,102,32,97,32,80,79,83,73,88,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,40,115,101,101,32,98,101,108,111,119,41,32,111,114,32,97,110,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,111,116,104,101,114,32,116,104,97,110,32,111,110,101,32,116,104,97,116,32,100,101,102,105,110,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,97,112,112,101,97,114,115,32,97,116,32,97,32,112,111,105,110,116,32,119,104,101,114,101,32,97,32,114,97,110,103,101,32,101,110,100,105,110,103,32,99,104,97,114,97,99,116,101,114,32,105,115,32,101,120,112,101,99,116,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,122,45,92,120,102,102,93,32,105,115,32,118,97,108,105,100,44,32,98,117,116,32,91,65,45,92,100,93,32,97,110,100,32,91,65,45,91,58,100,105,103,105,116,58,93,93,32,97,114,101,32,110,111,116,46>>]},{p,[],[<<82,97,110,103,101,115,32,111,112,101,114,97,116,101,32,105,110,32,116,104,101,32,99,111,108,108,97,116,105,110,103,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,32,118,97,108,117,101,115,46,32,84,104,101,121,32,99,97,110,32,97,108,115,111,32,98,101,32,117,115,101,100,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,115,112,101,99,105,102,105,101,100,32,110,117,109,101,114,105,99,97,108,108,121,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,91,92,48,48,48,45,92,48,51,55,93,46,32,82,97,110,103,101,115,32,99,97,110,32,105,110,99,108,117,100,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,118,97,108,105,100,32,102,111,114,32,116,104,101,32,99,117,114,114,101,110,116,32,109,111,100,101,46>>]},{p,[],[<<73,102,32,97,32,114,97,110,103,101,32,116,104,97,116,32,105,110,99,108,117,100,101,115,32,108,101,116,116,101,114,115,32,105,115,32,117,115,101,100,32,119,104,101,110,32,99,97,115,101,108,101,115,115,32,109,97,116,99,104,105,110,103,32,105,115,32,115,101,116,44,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,108,101,116,116,101,114,115,32,105,110,32,101,105,116,104,101,114,32,99,97,115,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,87,45,99,93,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,91,93,91,92,92,94,95,96,119,120,121,122,97,98,99,93,44,32,109,97,116,99,104,101,100,32,99,97,115,101,108,101,115,115,108,121,46,32,73,110,32,97,32,110,111,110,45,85,84,70,32,109,111,100,101,44,32,105,102,32,99,104,97,114,97,99,116,101,114,32,116,97,98,108,101,115,32,102,111,114,32,97,32,70,114,101,110,99,104,32,108,111,99,97,108,101,32,97,114,101,32,105,110,32,117,115,101,44,32,91,92,120,99,56,45,92,120,99,98,93,32,109,97,116,99,104,101,115,32,97,99,99,101,110,116,101,100,32,69,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,98,111,116,104,32,99,97,115,101,115,46,32,73,110,32,85,84,70,32,109,111,100,101,115,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,116,104,101,32,99,111,110,99,101,112,116,32,111,102,32,99,97,115,101,32,102,111,114,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,111,110,108,121,32,119,104,101,110,32,105,116,32,105,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,115,117,112,112,111,114,116,46>>]},{p,[],[<<84,104,101,32,99,104,97,114,97,99,116,101,114,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,92,100,44,32,92,68,44,32,92,104,44,32,92,72,44,32,92,112,44,32,92,80,44,32,92,115,44,32,92,83,44,32,92,118,44,32,92,86,44,32,92,119,44,32,97,110,100,32,92,87,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,110,100,32,97,100,100,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,116,104,101,121,32,109,97,116,99,104,32,116,111,32,116,104,101,32,99,108,97,115,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,91,92,100,65,66,67,68,69,70,93,32,109,97,116,99,104,101,115,32,97,110,121,32,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,46,32,73,110,32,85,84,70,32,109,111,100,101,115,44,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,97,102,102,101,99,116,115,32,116,104,101,32,109,101,97,110,105,110,103,115,32,111,102,32,92,100,44,32,92,115,44,32,92,119,32,97,110,100,32,116,104,101,105,114,32,117,112,112,101,114,99,97,115,101,32,112,97,114,116,110,101,114,115,44,32,106,117,115,116,32,97,115,32,105,116,32,100,111,101,115,32,119,104,101,110,32,116,104,101,121,32,97,112,112,101,97,114,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,103,101,110,101,114,105,99,95,99,104,97,114,97,99,116,101,114,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<71,101,110,101,114,105,99,32,67,104,97,114,97,99,116,101,114,32,84,121,112,101,115>>]},<<32,101,97,114,108,105,101,114,46,32,84,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,98,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,59,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,98,97,99,107,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,115,101,113,117,101,110,99,101,115,32,92,66,44,32,92,78,44,32,92,82,44,32,97,110,100,32,92,88,32,97,114,101,32,110,111,116,32,115,112,101,99,105,97,108,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,76,105,107,101,32,97,110,121,32,111,116,104,101,114,32,117,110,114,101,99,111,103,110,105,122,101,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,44,32,116,104,101,121,32,97,114,101,32,116,114,101,97,116,101,100,32,97,115,32,116,104,101,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,115,32,34,66,34,44,32,34,78,34,44,32,34,82,34,44,32,97,110,100,32,34,88,34,46>>]},{p,[],[<<65,32,99,105,114,99,117,109,102,108,101,120,32,99,97,110,32,99,111,110,118,101,110,105,101,110,116,108,121,32,98,101,32,117,115,101,100,32,119,105,116,104,32,116,104,101,32,117,112,112,101,114,99,97,115,101,32,99,104,97,114,97,99,116,101,114,32,116,121,112,101,115,32,116,111,32,115,112,101,99,105,102,121,32,97,32,109,111,114,101,32,114,101,115,116,114,105,99,116,101,100,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,110,32,116,104,101,32,109,97,116,99,104,105,110,103,32,108,111,119,101,114,99,97,115,101,32,116,121,112,101,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,108,97,115,115,32,91,94,92,87,95,93,32,109,97,116,99,104,101,115,32,97,110,121,32,108,101,116,116,101,114,32,111,114,32,100,105,103,105,116,44,32,98,117,116,32,110,111,116,32,117,110,100,101,114,115,99,111,114,101,44,32,119,104,105,108,101,32,91,92,119,93,32,105,110,99,108,117,100,101,115,32,117,110,100,101,114,115,99,111,114,101,46,32,65,32,112,111,115,105,116,105,118,101,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,105,115,32,116,111,32,98,101,32,114,101,97,100,32,97,115,32,34,115,111,109,101,116,104,105,110,103,32,79,82,32,115,111,109,101,116,104,105,110,103,32,79,82,32,46,46,46,34,32,97,110,100,32,97,32,110,101,103,97,116,105,118,101,32,99,108,97,115,115,32,97,115,32,34,78,79,84,32,115,111,109,101,116,104,105,110,103,32,65,78,68,32,78,79,84,32,115,111,109,101,116,104,105,110,103,32,65,78,68,32,78,79,84,32,46,46,46,34,46>>]},{p,[],[<<79,110,108,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,101,116,97,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,32,105,110,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,58>>]},{ul,[],[{li,[],[<<66,97,99,107,115,108,97,115,104>>]},{li,[],[<<72,121,112,104,101,110,32,40,111,110,108,121,32,119,104,101,114,101,32,105,116,32,99,97,110,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32,97,32,114,97,110,103,101,41>>]},{li,[],[<<67,105,114,99,117,109,102,108,101,120,32,40,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,41>>]},{li,[],[<<79,112,101,110,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,32,40,111,110,108,121,32,119,104,101,110,32,105,116,32,99,97,110,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,105,110,116,114,111,100,117,99,105,110,103,32,97,32,80,111,115,105,120,32,99,108,97,115,115,32,110,97,109,101,44,32,111,114,32,102,111,114,32,97,32,115,112,101,99,105,97,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,102,101,97,116,117,114,101,59,32,115,101,101,32,116,104,101,32,110,101,120,116,32,116,119,111,32,115,101,99,116,105,111,110,115,41>>]},{li,[],[<<84,101,114,109,105,110,97,116,105,110,103,32,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116>>]}]},{p,[],[<<72,111,119,101,118,101,114,44,32,101,115,99,97,112,105,110,103,32,111,116,104,101,114,32,110,111,110,45,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,115,32,100,111,101,115,32,110,111,32,104,97,114,109,46>>]},{a,[{id,<<115,101,99,116,56>>}],[]},{h2,[],[<<80,111,115,105,120,32,67,104,97,114,97,99,116,101,114,32,67,108,97,115,115,101,115>>]},{p,[],[<<80,101,114,108,32,115,117,112,112,111,114,116,115,32,116,104,101,32,80,111,115,105,120,32,110,111,116,97,116,105,111,110,32,102,111,114,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,84,104,105,115,32,117,115,101,115,32,110,97,109,101,115,32,101,110,99,108,111,115,101,100,32,98,121,32,91,58,32,97,110,100,32,58,93,32,119,105,116,104,105,110,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,115,113,117,97,114,101,32,98,114,97,99,107,101,116,115,46,32,80,67,82,69,32,97,108,115,111,32,115,117,112,112,111,114,116,115,32,116,104,105,115,32,110,111,116,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,48,34,44,32,34,49,34,44,32,97,110,121,32,97,108,112,104,97,98,101,116,105,99,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,34,37,34,58>>]},{pre,[],[{code,[],[<<91,48,49,91,58,97,108,112,104,97,58,93,37,93>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,115,117,112,112,111,114,116,101,100,32,99,108,97,115,115,32,110,97,109,101,115,58>>]},{dl,[],[{dt,[],[<<97,108,110,117,109>>]},{dd,[],[<<76,101,116,116,101,114,115,32,97,110,100,32,100,105,103,105,116,115>>]},{dt,[],[<<97,108,112,104,97>>]},{dd,[],[<<76,101,116,116,101,114,115>>]},{dt,[],[<<98,108,97,110,107>>]},{dd,[],[<<83,112,97,99,101,32,111,114,32,116,97,98,32,111,110,108,121>>]},{dt,[],[<<99,110,116,114,108>>]},{dd,[],[<<67,111,110,116,114,111,108,32,99,104,97,114,97,99,116,101,114,115>>]},{dt,[],[<<100,105,103,105,116>>]},{dd,[],[<<68,101,99,105,109,97,108,32,100,105,103,105,116,115,32,40,115,97,109,101,32,97,115,32,92,100,41>>]},{dt,[],[<<103,114,97,112,104>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,101,120,99,108,117,100,105,110,103,32,115,112,97,99,101>>]},{dt,[],[<<108,111,119,101,114>>]},{dd,[],[<<76,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115>>]},{dt,[],[<<112,114,105,110,116>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,99,108,117,100,105,110,103,32,115,112,97,99,101>>]},{dt,[],[<<112,117,110,99,116>>]},{dd,[],[<<80,114,105,110,116,105,110,103,32,99,104,97,114,97,99,116,101,114,115,44,32,101,120,99,108,117,100,105,110,103,32,108,101,116,116,101,114,115,44,32,100,105,103,105,116,115,44,32,97,110,100,32,115,112,97,99,101>>]},{dt,[],[<<115,112,97,99,101>>]},{dd,[],[<<87,104,105,116,101,115,112,97,99,101,32,40,116,104,101,32,115,97,109,101,32,97,115,32,92,115,32,102,114,111,109,32,80,67,82,69,32,56,46,51,52,41>>]},{dt,[],[<<117,112,112,101,114>>]},{dd,[],[<<85,112,112,101,114,99,97,115,101,32,108,101,116,116,101,114,115>>]},{dt,[],[<<119,111,114,100>>]},{dd,[],[<<34,87,111,114,100,34,32,99,104,97,114,97,99,116,101,114,115,32,40,115,97,109,101,32,97,115,32,92,119,41>>]},{dt,[],[<<120,100,105,103,105,116>>]},{dd,[],[<<72,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,115>>]}]},{p,[],[<<84,104,101,114,101,32,105,115,32,97,110,111,116,104,101,114,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32>>,{code,[],[<<97,115,99,105,105>>]},<<44,32,116,104,97,116,32,101,114,114,111,110,101,111,117,115,108,121,32,109,97,116,99,104,101,115,32,76,97,116,105,110,45,49,32,99,104,97,114,97,99,116,101,114,115,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,48,45,49,50,55,32,114,97,110,103,101,32,115,112,101,99,105,102,105,101,100,32,98,121,32,80,79,83,73,88,46,32,84,104,105,115,32,99,97,110,110,111,116,32,98,101,32,102,105,120,101,100,32,119,105,116,104,111,117,116,32,97,108,116,101,114,105,110,103,32,116,104,101,32,98,101,104,97,118,105,111,117,114,32,111,102,32,111,116,104,101,114,32,99,108,97,115,115,101,115,44,32,115,111,32,119,101,32,114,101,99,111,109,109,101,110,100,32,109,97,116,99,104,105,110,103,32,116,104,101,32,114,97,110,103,101,32,119,105,116,104,32>>,{code,[],[<<91,92,92,48,45,92,120,55,102,93>>]},<<32,105,110,115,116,101,97,100,46>>]},{p,[],[<<84,104,101,32,100,101,102,97,117,108,116,32,34,115,112,97,99,101,34,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,72,84,32,40,57,41,44,32,76,70,32,40,49,48,41,44,32,86,84,32,40,49,49,41,44,32,70,70,32,40,49,50,41,44,32,67,82,32,40,49,51,41,44,32,97,110,100,32,115,112,97,99,101,32,40,51,50,41,46,32,73,102,32,108,111,99,97,108,101,45,115,112,101,99,105,102,105,99,32,109,97,116,99,104,105,110,103,32,105,115,32,116,97,107,105,110,103,32,112,108,97,99,101,44,32,116,104,101,32,108,105,115,116,32,111,102,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,109,97,121,32,98,101,32,100,105,102,102,101,114,101,110,116,59,32,116,104,101,114,101,32,109,97,121,32,98,101,32,102,101,119,101,114,32,111,114,32,109,111,114,101,32,111,102,32,116,104,101,109,46,32,34,83,112,97,99,101,34,32,117,115,101,100,32,116,111,32,98,101,32,100,105,102,102,101,114,101,110,116,32,116,111,32,92,115,44,32,119,104,105,99,104,32,100,105,100,32,110,111,116,32,105,110,99,108,117,100,101,32,86,84,44,32,102,111,114,32,80,101,114,108,32,99,111,109,112,97,116,105,98,105,108,105,116,121,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,97,110,100,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,46,32,34,83,112,97,99,101,34,32,97,110,100,32,92,115,32,110,111,119,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<84,104,101,32,110,97,109,101,32,34,119,111,114,100,34,32,105,115,32,97,32,80,101,114,108,32,101,120,116,101,110,115,105,111,110,44,32,97,110,100,32,34,98,108,97,110,107,34,32,105,115,32,97,32,71,78,85,32,101,120,116,101,110,115,105,111,110,32,102,114,111,109,32,80,101,114,108,32,53,46,56,46,32,65,110,111,116,104,101,114,32,80,101,114,108,32,101,120,116,101,110,115,105,111,110,32,105,115,32,110,101,103,97,116,105,111,110,44,32,119,104,105,99,104,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,94,32,99,104,97,114,97,99,116,101,114,32,97,102,116,101,114,32,116,104,101,32,99,111,108,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,49,34,44,32,34,50,34,44,32,111,114,32,97,110,121,32,110,111,110,45,100,105,103,105,116,58>>]},{pre,[],[{code,[],[<<91,49,50,91,58,94,100,105,103,105,116,58,93,93>>]}]},{p,[],[<<80,67,82,69,32,40,97,110,100,32,80,101,114,108,41,32,97,108,115,111,32,114,101,99,111,103,110,105,122,101,32,116,104,101,32,80,111,115,105,120,32,115,121,110,116,97,120,32,91,46,99,104,46,93,32,97,110,100,32,91,61,99,104,61,93,32,119,104,101,114,101,32,34,99,104,34,32,105,115,32,97,32,34,99,111,108,108,97,116,105,110,103,32,101,108,101,109,101,110,116,34,44,32,98,117,116,32,116,104,101,115,101,32,97,114,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,44,32,97,110,100,32,97,110,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,105,102,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,118,97,108,117,101,115,32,62,32,50,53,53,32,100,111,32,110,111,116,32,109,97,116,99,104,32,97,110,121,32,111,102,32,116,104,101,32,80,111,115,105,120,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,101,115,46,32,72,111,119,101,118,101,114,44,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<80,67,82,69,95,85,67,80>>]},<<32,105,115,32,112,97,115,115,101,100,32,116,111,32>>,{code,[],[<<112,99,114,101,95,99,111,109,112,105,108,101,40,41>>]},<<44,32,115,111,109,101,32,111,102,32,116,104,101,32,99,108,97,115,115,101,115,32,97,114,101,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,46,32,84,104,105,115,32,105,115,32,97,99,104,105,101,118,101,100,32,98,121,32,114,101,112,108,97,99,105,110,103,32,99,101,114,116,97,105,110,32,80,111,115,105,120,32,99,108,97,115,115,101,115,32,98,121,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,115,44,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<91,58,97,108,110,117,109,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,97,110,125>>]}]},{dt,[],[<<91,58,97,108,112,104,97,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,125>>]}]},{dt,[],[<<91,58,98,108,97,110,107,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,104>>]}]},{dt,[],[<<91,58,100,105,103,105,116,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,78,100,125>>]}]},{dt,[],[<<91,58,108,111,119,101,114,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,108,125>>]}]},{dt,[],[<<91,58,115,112,97,99,101,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,112,115,125>>]}]},{dt,[],[<<91,58,117,112,112,101,114,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,76,117,125>>]}]},{dt,[],[<<91,58,119,111,114,100,58,93>>]},{dd,[],[<<66,101,99,111,109,101,115,32>>,{em,[],[<<92,112,123,88,119,100,125>>]}]}]},{p,[],[<<78,101,103,97,116,101,100,32,118,101,114,115,105,111,110,115,44,32,115,117,99,104,32,97,115,32,91,58,94,97,108,112,104,97,58,93,44,32,117,115,101,32,92,80,32,105,110,115,116,101,97,100,32,111,102,32,92,112,46,32,84,104,114,101,101,32,111,116,104,101,114,32,80,79,83,73,88,32,99,108,97,115,115,101,115,32,97,114,101,32,104,97,110,100,108,101,100,32,115,112,101,99,105,97,108,108,121,32,105,110,32,85,67,80,32,109,111,100,101,58>>]},{dl,[],[{dt,[],[<<91,58,103,114,97,112,104,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,103,108,121,112,104,115,32,116,104,97,116,32,109,97,114,107,32,116,104,101,32,112,97,103,101,32,119,104,101,110,32,112,114,105,110,116,101,100,46,32,73,110,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,116,101,114,109,115,44,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,76,44,32,77,44,32,78,44,32,80,44,32,83,44,32,111,114,32,67,102,32,112,114,111,112,101,114,116,105,101,115,44,32,101,120,99,101,112,116,32,102,111,114,58>>]},{dl,[],[{dt,[],[<<85,43,48,54,49,67>>]},{dd,[],[{p,[],[<<65,114,97,98,105,99,32,76,101,116,116,101,114,32,77,97,114,107>>]}]},{dt,[],[<<85,43,49,56,48,69>>]},{dd,[],[{p,[],[<<77,111,110,103,111,108,105,97,110,32,86,111,119,101,108,32,83,101,112,97,114,97,116,111,114>>]}]},{dt,[],[<<85,43,50,48,54,54,32,45,32,85,43,50,48,54,57>>]},{dd,[],[{p,[],[<<86,97,114,105,111,117,115,32,34,105,115,111,108,97,116,101,34,115>>]}]}]}]},{dt,[],[<<91,58,112,114,105,110,116,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,116,104,101,32,115,97,109,101,32,99,104,97,114,97,99,116,101,114,115,32,97,115,32,91,58,103,114,97,112,104,58,93,32,112,108,117,115,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,99,111,110,116,114,111,108,115,44,32,116,104,97,116,32,105,115,44,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,116,104,101,32,90,115,32,112,114,111,112,101,114,116,121,46>>]}]},{dt,[],[<<91,58,112,117,110,99,116,58,93>>]},{dd,[],[{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,104,97,118,101,32,116,104,101,32,85,110,105,99,111,100,101,32,80,32,40,112,117,110,99,116,117,97,116,105,111,110,41,32,112,114,111,112,101,114,116,121,44,32,112,108,117,115,32,116,104,111,115,101,32,99,104,97,114,97,99,116,101,114,115,32,119,104,111,115,101,32,99,111,100,101,32,112,111,105,110,116,115,32,97,114,101,32,108,101,115,115,32,116,104,97,110,32,49,50,56,32,116,104,97,116,32,104,97,118,101,32,116,104,101,32,83,32,40,83,121,109,98,111,108,41,32,112,114,111,112,101,114,116,121,46>>]}]}]},{p,[],[<<84,104,101,32,111,116,104,101,114,32,80,79,83,73,88,32,99,108,97,115,115,101,115,32,97,114,101,32,117,110,99,104,97,110,103,101,100,44,32,97,110,100,32,109,97,116,99,104,32,111,110,108,121,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,99,111,100,101,32,112,111,105,110,116,115,32,108,101,115,115,32,116,104,97,110,32,49,50,56,46>>]},{p,[],[{em,[],[<<67,111,109,112,97,116,105,98,105,108,105,116,121,32,70,101,97,116,117,114,101,32,102,111,114,32,87,111,114,100,32,66,111,117,110,100,97,114,105,101,115>>]}]},{p,[],[<<73,110,32,116,104,101,32,80,79,83,73,88,46,50,32,99,111,109,112,108,105,97,110,116,32,108,105,98,114,97,114,121,32,116,104,97,116,32,119,97,115,32,105,110,99,108,117,100,101,100,32,105,110,32,52,46,52,66,83,68,32,85,110,105,120,44,32,116,104,101,32,117,103,108,121,32,115,121,110,116,97,120,32,91,91,58,60,58,93,93,32,97,110,100,32,91,91,58,62,58,93,93,32,105,115,32,117,115,101,100,32,102,111,114,32,109,97,116,99,104,105,110,103,32,34,115,116,97,114,116,32,111,102,32,119,111,114,100,34,32,97,110,100,32,34,101,110,100,32,111,102,32,119,111,114,100,34,46,32,80,67,82,69,32,116,114,101,97,116,115,32,116,104,101,115,101,32,105,116,101,109,115,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<91,91,58,60,58,93,93>>]},{dd,[],[{p,[],[<<105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,92,98,40,63,61,92,119,41>>]}]},{dt,[],[<<91,91,58,62,58,93,93>>]},{dd,[],[{p,[],[<<105,115,32,99,111,110,118,101,114,116,101,100,32,116,111,32,92,98,40,63,60,61,92,119,41>>]}]}]},{p,[],[<<79,110,108,121,32,116,104,101,115,101,32,101,120,97,99,116,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,115,32,97,114,101,32,114,101,99,111,103,110,105,122,101,100,46,32,65,32,115,101,113,117,101,110,99,101,32,115,117,99,104,32,97,115,32,91,97,91,58,60,58,93,98,93,32,112,114,111,118,111,107,101,115,32,101,114,114,111,114,32,102,111,114,32,97,110,32,117,110,114,101,99,111,103,110,105,122,101,100,32,80,79,83,73,88,32,99,108,97,115,115,32,110,97,109,101,46,32,84,104,105,115,32,115,117,112,112,111,114,116,32,105,115,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,32,80,101,114,108,46,32,73,116,32,105,115,32,112,114,111,118,105,100,101,100,32,116,111,32,104,101,108,112,32,109,105,103,114,97,116,105,111,110,115,32,102,114,111,109,32,111,116,104,101,114,32,101,110,118,105,114,111,110,109,101,110,116,115,44,32,97,110,100,32,105,115,32,98,101,115,116,32,110,111,116,32,117,115,101,100,32,105,110,32,97,110,121,32,110,101,119,32,112,97,116,116,101,114,110,115,46,32,78,111,116,101,32,116,104,97,116,32,92,98,32,109,97,116,99,104,101,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,97,110,100,32,116,104,101,32,101,110,100,32,111,102,32,97,32,119,111,114,100,32,40,115,101,101,32,34,83,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,34,32,97,98,111,118,101,41,44,32,97,110,100,32,105,110,32,97,32,80,101,114,108,45,115,116,121,108,101,32,112,97,116,116,101,114,110,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,111,114,32,102,111,108,108,111,119,105,110,103,32,99,104,97,114,97,99,116,101,114,32,110,111,114,109,97,108,108,121,32,115,104,111,119,115,32,119,104,105,99,104,32,105,115,32,119,97,110,116,101,100,44,32,119,105,116,104,111,117,116,32,116,104,101,32,110,101,101,100,32,102,111,114,32,116,104,101,32,97,115,115,101,114,116,105,111,110,115,32,116,104,97,116,32,97,114,101,32,117,115,101,100,32,97,98,111,118,101,32,105,110,32,111,114,100,101,114,32,116,111,32,103,105,118,101,32,101,120,97,99,116,108,121,32,116,104,101,32,80,79,83,73,88,32,98,101,104,97,118,105,111,117,114,46>>]},{a,[{id,<<115,101,99,116,57>>}],[]},{h2,[],[<<86,101,114,116,105,99,97,108,32,66,97,114>>]},{p,[],[<<86,101,114,116,105,99,97,108,32,98,97,114,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,117,115,101,100,32,116,111,32,115,101,112,97,114,97,116,101,32,97,108,116,101,114,110,97,116,105,118,101,32,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,101,105,116,104,101,114,32,34,103,105,108,98,101,114,116,34,32,111,114,32,34,115,117,108,108,105,118,97,110,34,58>>]},{pre,[],[{code,[],[<<103,105,108,98,101,114,116,124,115,117,108,108,105,118,97,110>>]}]},{p,[],[<<65,110,121,32,110,117,109,98,101,114,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,115,32,99,97,110,32,97,112,112,101,97,114,44,32,97,110,100,32,97,110,32,101,109,112,116,121,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,112,101,114,109,105,116,116,101,100,32,40,109,97,116,99,104,105,110,103,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,41,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,32,116,114,105,101,115,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,117,114,110,44,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,97,110,100,32,116,104,101,32,102,105,114,115,116,32,116,104,97,116,32,115,117,99,99,101,101,100,115,32,105,115,32,117,115,101,100,46,32,73,102,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,119,105,116,104,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,100,101,102,105,110,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]},<<41,44,32,34,115,117,99,99,101,101,100,115,34,32,109,101,97,110,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,109,97,105,110,32,112,97,116,116,101,114,110,32,97,110,100,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,46>>]},{a,[{id,<<115,101,99,116,49,48>>}],[]},{h2,[],[<<73,110,116,101,114,110,97,108,32,79,112,116,105,111,110,32,83,101,116,116,105,110,103>>]},{p,[],[<<84,104,101,32,115,101,116,116,105,110,103,115,32,111,102,32,116,104,101,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,32,111,112,116,105,111,110,115,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<44,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<44,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,102,114,111,109,32,119,105,116,104,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,121,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,80,101,114,108,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,101,110,99,108,111,115,101,100,32,98,101,116,119,101,101,110,32,34,40,63,34,32,97,110,100,32,34,41,34,46,32,84,104,101,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,97,114,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[<<105>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]}]},{dt,[],[<<109>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]}]},{dt,[],[<<115>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<100,111,116,97,108,108>>]}]},{dt,[],[<<120>>]},{dd,[],[<<70,111,114,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]}]}]},{p,[],[<<70,111,114,32,101,120,97,109,112,108,101,44,32>>,{code,[],[<<40,63,105,109,41>>]},<<32,115,101,116,115,32,99,97,115,101,108,101,115,115,44,32,109,117,108,116,105,108,105,110,101,32,109,97,116,99,104,105,110,103,46,32,84,104,101,115,101,32,111,112,116,105,111,110,115,32,99,97,110,32,97,108,115,111,32,98,101,32,117,110,115,101,116,32,98,121,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,108,101,116,116,101,114,32,119,105,116,104,32,97,32,104,121,112,104,101,110,46,32,65,32,99,111,109,98,105,110,101,100,32,115,101,116,116,105,110,103,32,97,110,100,32,117,110,115,101,116,116,105,110,103,32,115,117,99,104,32,97,115,32>>,{code,[],[<<40,63,105,109,45,115,120,41>>]},<<44,32,119,104,105,99,104,32,115,101,116,115,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<32,97,110,100,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<44,32,119,104,105,108,101,32,117,110,115,101,116,116,105,110,103,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,97,110,100,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<44,32,105,115,32,97,108,115,111,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,97,32,108,101,116,116,101,114,32,97,112,112,101,97,114,115,32,98,111,116,104,32,98,101,102,111,114,101,32,97,110,100,32,97,102,116,101,114,32,116,104,101,32,104,121,112,104,101,110,44,32,116,104,101,32,111,112,116,105,111,110,32,105,115,32,117,110,115,101,116,46>>]},{p,[],[<<84,104,101,32,80,67,82,69,45,115,112,101,99,105,102,105,99,32,111,112,116,105,111,110,115,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<44,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<44,32,97,110,100,32>>,{code,[],[<<101,120,116,114,97>>]},<<32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,116,104,101,32,80,101,114,108,45,99,111,109,112,97,116,105,98,108,101,32,111,112,116,105,111,110,115,32,98,121,32,117,115,105,110,103,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,74,44,32,85,44,32,97,110,100,32,88,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]},{p,[],[<<87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,111,112,116,105,111,110,32,99,104,97,110,103,101,115,32,111,99,99,117,114,115,32,97,116,32,116,111,112,45,108,101,118,101,108,32,40,116,104,97,116,32,105,115,44,32,110,111,116,32,105,110,115,105,100,101,32,115,117,98,112,97,116,116,101,114,110,32,112,97,114,101,110,116,104,101,115,101,115,41,44,32,116,104,101,32,99,104,97,110,103,101,32,97,112,112,108,105,101,115,32,116,111,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,116,104,97,116,32,102,111,108,108,111,119,115,46>>]},{p,[],[<<65,110,32,111,112,116,105,111,110,32,99,104,97,110,103,101,32,119,105,116,104,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,115>>]},<<41,32,97,102,102,101,99,116,115,32,111,110,108,121,32,116,104,97,116,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,102,111,108,108,111,119,115,32,105,116,46,32,83,111,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,98,99,32,97,110,100,32,97,66,99,32,97,110,100,32,110,111,32,111,116,104,101,114,32,115,116,114,105,110,103,115,32,40,97,115,115,117,109,105,110,103,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<32,105,115,32,110,111,116,32,117,115,101,100,41,58>>]},{pre,[],[{code,[],[<<40,97,40,63,105,41,98,41,99>>]}]},{p,[],[<<66,121,32,116,104,105,115,32,109,101,97,110,115,44,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,109,97,100,101,32,116,111,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,115,101,116,116,105,110,103,115,32,105,110,32,100,105,102,102,101,114,101,110,116,32,112,97,114,116,115,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,99,104,97,110,103,101,115,32,109,97,100,101,32,105,110,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,32,100,111,32,99,97,114,114,121,32,111,110,32,105,110,116,111,32,115,117,98,115,101,113,117,101,110,116,32,98,114,97,110,99,104,101,115,32,119,105,116,104,105,110,32,116,104,101,32,115,97,109,101,32,115,117,98,112,97,116,116,101,114,110,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,40,63,105,41,98,124,99,41>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,34,97,98,34,44,32,34,97,66,34,44,32,34,99,34,44,32,97,110,100,32,34,67,34,44,32,97,108,116,104,111,117,103,104,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,34,67,34,32,116,104,101,32,102,105,114,115,116,32,98,114,97,110,99,104,32,105,115,32,97,98,97,110,100,111,110,101,100,32,98,101,102,111,114,101,32,116,104,101,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,101,102,102,101,99,116,115,32,111,102,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,115,32,111,99,99,117,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,84,104,101,114,101,32,119,111,117,108,100,32,98,101,32,115,111,109,101,32,119,101,105,114,100,32,98,101,104,97,118,105,111,114,32,111,116,104,101,114,119,105,115,101,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<79,116,104,101,114,32,80,67,82,69,45,115,112,101,99,105,102,105,99,32,111,112,116,105,111,110,115,32,99,97,110,32,98,101,32,115,101,116,32,98,121,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,119,104,101,110,32,116,104,101,32,99,111,109,112,105,108,105,110,103,32,111,114,32,109,97,116,99,104,105,110,103,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,99,97,108,108,101,100,46,32,83,111,109,101,116,105,109,101,115,32,116,104,101,32,112,97,116,116,101,114,110,32,99,97,110,32,99,111,110,116,97,105,110,32,115,112,101,99,105,97,108,32,108,101,97,100,105,110,103,32,115,101,113,117,101,110,99,101,115,44,32,115,117,99,104,32,97,115,32,40,42,67,82,76,70,41,44,32,116,111,32,111,118,101,114,114,105,100,101,32,119,104,97,116,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,104,97,115,32,115,101,116,32,111,114,32,119,104,97,116,32,104,97,115,32,98,101,101,110,32,100,101,102,97,117,108,116,101,100,46,32,68,101,116,97,105,108,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,115,101,113,117,101,110,99,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,83,101,113,117,101,110,99,101,115>>]},<<32,101,97,114,108,105,101,114,46>>]},{p,[],[<<84,104,101,32,40,42,85,84,70,56,41,32,97,110,100,32,40,42,85,67,80,41,32,108,101,97,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,115,101,116,32,85,84,70,32,97,110,100,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,121,32,109,111,100,101,115,46,32,84,104,101,121,32,97,114,101,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,115,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,97,110,100,32>>,{code,[],[<<117,99,112>>]},<<44,32,114,101,115,112,101,99,116,105,118,101,108,121,46,32,84,104,101,32,40,42,85,84,70,41,32,115,101,113,117,101,110,99,101,32,105,115,32,97,32,103,101,110,101,114,105,99,32,118,101,114,115,105,111,110,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,110,121,32,111,102,32,116,104,101,32,108,105,98,114,97,114,105,101,115,46,32,72,111,119,101,118,101,114,44,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,32,99,97,110,32,115,101,116,32,111,112,116,105,111,110,32>>,{code,[],[<<110,101,118,101,114,95,117,116,102>>]},<<44,32,119,104,105,99,104,32,108,111,99,107,115,32,111,117,116,32,116,104,101,32,117,115,101,32,111,102,32,116,104,101,32,40,42,85,84,70,41,32,115,101,113,117,101,110,99,101,115,46>>]}]},{a,[{id,<<115,101,99,116,49,49>>}],[]},{h2,[],[<<83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,100,101,108,105,109,105,116,101,100,32,98,121,32,112,97,114,101,110,116,104,101,115,101,115,32,40,114,111,117,110,100,32,98,114,97,99,107,101,116,115,41,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,110,101,115,116,101,100,46,32,84,117,114,110,105,110,103,32,112,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,105,110,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,100,111,101,115,32,116,119,111,32,116,104,105,110,103,115,58>>]},{dl,[],[{dt,[],[<<49,46>>]},{dd,[],[{p,[],[<<73,116,32,108,111,99,97,108,105,122,101,115,32,97,32,115,101,116,32,111,102,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,99,97,116,97,114,97,99,116,34,44,32,34,99,97,116,101,114,112,105,108,108,97,114,34,44,32,111,114,32,34,99,97,116,34,58>>]},{pre,[],[{code,[],[<<99,97,116,40,97,114,97,99,116,124,101,114,112,105,108,108,97,114,124,41>>]}]},{p,[],[<<87,105,116,104,111,117,116,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,44,32,105,116,32,119,111,117,108,100,32,109,97,116,99,104,32,34,99,97,116,97,114,97,99,116,34,44,32,34,101,114,112,105,108,108,97,114,34,44,32,111,114,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,46>>]}]},{dt,[],[<<50,46>>]},{dd,[],[{p,[],[<<73,116,32,115,101,116,115,32,117,112,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,46,32,84,104,97,116,32,105,115,44,32,119,104,101,110,32,116,104,101,32,99,111,109,112,108,101,116,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,116,104,97,116,32,112,111,114,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,116,104,97,116,32,109,97,116,99,104,101,100,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,116,104,114,111,117,103,104,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46>>]}]}]},{p,[],[<<79,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,99,111,117,110,116,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,32,40,115,116,97,114,116,105,110,103,32,102,114,111,109,32,49,41,32,116,111,32,111,98,116,97,105,110,32,110,117,109,98,101,114,115,32,102,111,114,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,116,114,105,110,103,32,34,116,104,101,32,114,101,100,32,107,105,110,103,34,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,34,114,101,100,32,107,105,110,103,34,44,32,34,114,101,100,34,44,32,97,110,100,32,34,107,105,110,103,34,44,32,97,110,100,32,97,114,101,32,110,117,109,98,101,114,101,100,32,49,44,32,50,44,32,97,110,100,32,51,44,32,114,101,115,112,101,99,116,105,118,101,108,121,58>>]},{pre,[],[{code,[],[<<116,104,101,32,40,40,114,101,100,124,119,104,105,116,101,41,32,40,107,105,110,103,124,113,117,101,101,110,41,41>>]}]},{p,[],[<<73,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,104,101,108,112,102,117,108,32,116,104,97,116,32,112,108,97,105,110,32,112,97,114,101,110,116,104,101,115,101,115,32,102,117,108,102,105,108,108,32,116,119,111,32,102,117,110,99,116,105,111,110,115,46,32,79,102,116,101,110,32,97,32,103,114,111,117,112,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,113,117,105,114,101,100,32,119,105,116,104,111,117,116,32,97,32,99,97,112,116,117,114,105,110,103,32,114,101,113,117,105,114,101,109,101,110,116,46,32,73,102,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,32,97,110,100,32,97,32,99,111,108,111,110,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,100,111,32,97,110,121,32,99,97,112,116,117,114,105,110,103,44,32,97,110,100,32,105,115,32,110,111,116,32,99,111,117,110,116,101,100,32,119,104,101,110,32,99,111,109,112,117,116,105,110,103,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,97,110,121,32,115,117,98,115,101,113,117,101,110,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,116,104,101,32,115,116,114,105,110,103,32,34,116,104,101,32,119,104,105,116,101,32,113,117,101,101,110,34,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,34,119,104,105,116,101,32,113,117,101,101,110,34,32,97,110,100,32,34,113,117,101,101,110,34,44,32,97,110,100,32,97,114,101,32,110,117,109,98,101,114,101,100,32,49,32,97,110,100,32,50,58>>]},{pre,[],[{code,[],[<<116,104,101,32,40,40,63,58,114,101,100,124,119,104,105,116,101,41,32,40,107,105,110,103,124,113,117,101,101,110,41,41>>]}]},{p,[],[<<84,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,115,32,54,53,53,51,53,46>>]},{p,[],[<<65,115,32,97,32,99,111,110,118,101,110,105,101,110,116,32,115,104,111,114,116,104,97,110,100,44,32,105,102,32,97,110,121,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,115,32,97,114,101,32,114,101,113,117,105,114,101,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,110,111,110,45,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,101,32,111,112,116,105,111,110,32,108,101,116,116,101,114,115,32,99,97,110,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,34,63,34,32,97,110,100,32,34,58,34,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,116,119,111,32,112,97,116,116,101,114,110,115,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,115,101,116,32,111,102,32,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<40,63,105,58,115,97,116,117,114,100,97,121,124,115,117,110,100,97,121,41,10,40,63,58,40,63,105,41,115,97,116,117,114,100,97,121,124,115,117,110,100,97,121,41>>]}]},{p,[],[<<65,115,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104,101,115,32,97,114,101,32,116,114,105,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,97,110,100,32,111,112,116,105,111,110,115,32,97,114,101,32,110,111,116,32,114,101,115,101,116,32,117,110,116,105,108,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,97,99,104,101,100,44,32,97,110,32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,32,105,110,32,111,110,101,32,98,114,97,110,99,104,32,100,111,101,115,32,97,102,102,101,99,116,32,115,117,98,115,101,113,117,101,110,116,32,98,114,97,110,99,104,101,115,44,32,115,111,32,116,104,101,32,97,98,111,118,101,32,112,97,116,116,101,114,110,115,32,109,97,116,99,104,32,98,111,116,104,32,34,83,85,78,68,65,89,34,32,97,110,100,32,34,83,97,116,117,114,100,97,121,34,46>>]},{a,[{id,<<115,101,99,116,49,50>>}],[]},{h2,[],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},{p,[],[<<80,101,114,108,32,53,46,49,48,32,105,110,116,114,111,100,117,99,101,100,32,97,32,102,101,97,116,117,114,101,32,119,104,101,114,101,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,117,115,101,115,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,115,32,102,111,114,32,105,116,115,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,46,32,83,117,99,104,32,97,32,115,117,98,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32>>,{code,[],[<<40,63,124>>]},<<32,97,110,100,32,105,115,32,105,116,115,101,108,102,32,97,32,110,111,110,45,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,124,40,83,97,116,41,117,114,124,40,83,117,110,41,41,100,97,121>>]}]},{p,[],[<<65,115,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,105,110,115,105,100,101,32,97,32>>,{code,[],[<<40,63,124>>]},<<32,103,114,111,117,112,44,32,98,111,116,104,32,115,101,116,115,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,117,109,98,101,114,101,100,32,111,110,101,46,32,84,104,117,115,44,32,119,104,101,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,121,111,117,32,99,97,110,32,108,111,111,107,32,97,116,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,110,117,109,98,101,114,32,111,110,101,44,32,119,104,105,99,104,101,118,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,109,97,116,99,104,101,100,46,32,84,104,105,115,32,99,111,110,115,116,114,117,99,116,32,105,115,32,117,115,101,102,117,108,32,119,104,101,110,32,121,111,117,32,119,97,110,116,32,116,111,32,99,97,112,116,117,114,101,32,97,32,112,97,114,116,44,32,98,117,116,32,110,111,116,32,97,108,108,44,32,111,102,32,111,110,101,32,111,102,32,109,97,110,121,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,73,110,115,105,100,101,32,97,32>>,{code,[],[<<40,63,124>>]},<<32,103,114,111,117,112,44,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,117,109,98,101,114,101,100,32,97,115,32,117,115,117,97,108,44,32,98,117,116,32,116,104,101,32,110,117,109,98,101,114,32,105,115,32,114,101,115,101,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,98,114,97,110,99,104,46,32,84,104,101,32,110,117,109,98,101,114,115,32,111,102,32,97,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,102,111,108,108,111,119,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,115,116,97,114,116,32,97,102,116,101,114,32,116,104,101,32,104,105,103,104,101,115,116,32,110,117,109,98,101,114,32,117,115,101,100,32,105,110,32,97,110,121,32,98,114,97,110,99,104,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,105,115,32,102,114,111,109,32,116,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,59,32,116,104,101,32,110,117,109,98,101,114,115,32,117,110,100,101,114,110,101,97,116,104,32,115,104,111,119,32,105,110,32,119,104,105,99,104,32,98,117,102,102,101,114,32,116,104,101,32,99,97,112,116,117,114,101,100,32,99,111,110,116,101,110,116,32,105,115,32,115,116,111,114,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<35,32,98,101,102,111,114,101,32,32,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,98,114,97,110,99,104,45,114,101,115,101,116,45,45,45,45,45,45,45,45,45,45,45,32,97,102,116,101,114,10,47,32,40,32,97,32,41,32,32,40,63,124,32,120,32,40,32,121,32,41,32,122,32,124,32,40,112,32,40,113,41,32,114,41,32,124,32,40,116,41,32,117,32,40,118,41,32,41,32,40,32,122,32,41,32,47,120,10,35,32,49,32,32,32,32,32,32,32,32,32,32,32,32,50,32,32,32,32,32,32,32,32,32,50,32,32,51,32,32,32,32,32,32,32,32,50,32,32,32,32,32,51,32,32,32,32,32,52>>]}]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,117,115,101,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,118,97,108,117,101,32,116,104,97,116,32,105,115,32,115,101,116,32,102,111,114,32,116,104,97,116,32,110,117,109,98,101,114,32,98,121,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,111,114,32,34,100,101,102,100,101,102,34,58>>]},{pre,[],[{code,[],[<<47,40,63,124,40,97,98,99,41,124,40,100,101,102,41,41,92,49,47>>]}]},{p,[],[<<73,110,32,99,111,110,116,114,97,115,116,44,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,116,111,32,97,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,114,101,102,101,114,115,32,116,111,32,116,104,101,32,102,105,114,115,116,32,111,110,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,103,105,118,101,110,32,110,117,109,98,101,114,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,111,114,32,34,100,101,102,97,98,99,34,58>>]},{pre,[],[{code,[],[<<47,40,63,124,40,97,98,99,41,124,40,100,101,102,41,41,40,63,49,41,47>>]}]},{p,[],[<<73,102,32,97,32,99,111,110,100,105,116,105,111,110,32,116,101,115,116,32,102,111,114,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,118,105,110,103,32,109,97,116,99,104,101,100,32,114,101,102,101,114,115,32,116,111,32,97,32,110,111,110,45,117,110,105,113,117,101,32,110,117,109,98,101,114,44,32,116,104,101,32,116,101,115,116,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,97,116,32,110,117,109,98,101,114,32,104,97,118,101,32,109,97,116,99,104,101,100,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,97,112,112,114,111,97,99,104,32,117,115,105,110,103,32,116,104,105,115,32,34,98,114,97,110,99,104,32,114,101,115,101,116,34,32,102,101,97,116,117,114,101,32,105,115,32,116,111,32,117,115,101,32,100,117,112,108,105,99,97,116,101,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46>>]},{a,[{id,<<115,101,99,116,49,51>>}],[]},{h2,[],[<<78,97,109,101,100,32,83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<73,100,101,110,116,105,102,121,105,110,103,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,98,121,32,110,117,109,98,101,114,32,105,115,32,115,105,109,112,108,101,44,32,98,117,116,32,105,116,32,99,97,110,32,98,101,32,104,97,114,100,32,116,111,32,107,101,101,112,32,116,114,97,99,107,32,111,102,32,116,104,101,32,110,117,109,98,101,114,115,32,105,110,32,99,111,109,112,108,105,99,97,116,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,46,32,65,108,115,111,44,32,105,102,32,97,110,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,109,111,100,105,102,105,101,100,44,32,116,104,101,32,110,117,109,98,101,114,115,32,99,97,110,32,99,104,97,110,103,101,46,32,84,111,32,104,101,108,112,32,119,105,116,104,32,116,104,105,115,32,100,105,102,102,105,99,117,108,116,121,44,32,80,67,82,69,32,115,117,112,112,111,114,116,115,32,116,104,101,32,110,97,109,105,110,103,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,105,115,32,102,101,97,116,117,114,101,32,119,97,115,32,110,111,116,32,97,100,100,101,100,32,116,111,32,80,101,114,108,32,117,110,116,105,108,32,114,101,108,101,97,115,101,32,53,46,49,48,46,32,80,121,116,104,111,110,32,104,97,100,32,116,104,101,32,102,101,97,116,117,114,101,32,101,97,114,108,105,101,114,44,32,97,110,100,32,80,67,82,69,32,105,110,116,114,111,100,117,99,101,100,32,105,116,32,97,116,32,114,101,108,101,97,115,101,32,52,46,48,44,32,117,115,105,110,103,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,46,32,80,67,82,69,32,110,111,119,32,115,117,112,112,111,114,116,115,32,98,111,116,104,32,116,104,101,32,80,101,114,108,32,97,110,100,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,46,32,80,101,114,108,32,97,108,108,111,119,115,32,105,100,101,110,116,105,99,97,108,108,121,32,110,117,109,98,101,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,104,97,118,101,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,44,32,98,117,116,32,80,67,82,69,32,100,111,101,115,32,110,111,116,46>>]},{p,[],[<<73,110,32,80,67,82,69,44,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,98,101,32,110,97,109,101,100,32,105,110,32,111,110,101,32,111,102,32,116,104,114,101,101,32,119,97,121,115,58,32>>,{code,[],[<<40,63,60,110,97,109,101,62,46,46,46,41>>]},<<32,111,114,32>>,{code,[],[<<40,63,39,110,97,109,101,39,46,46,46,41>>]},<<32,97,115,32,105,110,32,80,101,114,108,44,32,111,114,32>>,{code,[],[<<40,63,80,60,110,97,109,101,62,46,46,46,41>>]},<<32,97,115,32,105,110,32,80,121,116,104,111,110,46,32,82,101,102,101,114,101,110,99,101,115,32,116,111,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,102,114,111,109,32,111,116,104,101,114,32,112,97,114,116,115,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,115,117,99,104,32,97,115,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,44,32,114,101,99,117,114,115,105,111,110,44,32,97,110,100,32,99,111,110,100,105,116,105,111,110,115,44,32,99,97,110,32,98,101,32,109,97,100,101,32,98,121,32,110,97,109,101,32,97,110,100,32,98,121,32,110,117,109,98,101,114,46>>]},{p,[],[<<78,97,109,101,115,32,99,111,110,115,105,115,116,32,111,102,32,117,112,32,116,111,32,51,50,32,97,108,112,104,97,110,117,109,101,114,105,99,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,117,110,100,101,114,115,99,111,114,101,115,44,32,98,117,116,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,97,32,110,111,110,45,100,105,103,105,116,46,32,78,97,109,101,100,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,115,116,105,108,108,32,97,108,108,111,99,97,116,101,100,32,110,117,109,98,101,114,115,32,97,115,32,119,101,108,108,32,97,115,32,110,97,109,101,115,44,32,101,120,97,99,116,108,121,32,97,115,32,105,102,32,116,104,101,32,110,97,109,101,115,32,119,101,114,101,32,110,111,116,32,112,114,101,115,101,110,116,46,32,84,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<32,99,97,110,32,117,115,101,32,110,97,109,101,100,32,118,97,108,117,101,115,32,105,102,32,116,104,101,121,32,97,114,101,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,32,110,97,109,101,32,109,117,115,116,32,98,101,32,117,110,105,113,117,101,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,44,32,98,117,116,32,116,104,105,115,32,99,111,110,115,116,114,97,105,110,116,32,99,97,110,32,98,101,32,114,101,108,97,120,101,100,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,46,32,40,68,117,112,108,105,99,97,116,101,32,110,97,109,101,115,32,97,114,101,32,97,108,115,111,32,97,108,119,97,121,115,32,112,101,114,109,105,116,116,101,100,32,102,111,114,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,115,101,116,32,117,112,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,46,41,32,68,117,112,108,105,99,97,116,101,32,110,97,109,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,102,111,114,32,112,97,116,116,101,114,110,115,32,119,104,101,114,101,32,111,110,108,121,32,111,110,101,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,109,97,116,99,104,46,32,83,117,112,112,111,115,101,32,116,104,97,116,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,116,104,101,32,110,97,109,101,32,111,102,32,97,32,119,101,101,107,100,97,121,44,32,101,105,116,104,101,114,32,97,115,32,97,32,51,45,108,101,116,116,101,114,32,97,98,98,114,101,118,105,97,116,105,111,110,32,111,114,32,97,115,32,116,104,101,32,102,117,108,108,32,110,97,109,101,44,32,97,110,100,32,105,110,32,98,111,116,104,32,99,97,115,101,115,32,121,111,117,32,119,97,110,116,32,116,111,32,101,120,116,114,97,99,116,32,116,104,101,32,97,98,98,114,101,118,105,97,116,105,111,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,40,105,103,110,111,114,105,110,103,32,116,104,101,32,108,105,110,101,32,98,114,101,97,107,115,41,32,100,111,101,115,32,116,104,101,32,106,111,98,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,60,68,78,62,77,111,110,124,70,114,105,124,83,117,110,41,40,63,58,100,97,121,41,63,124,10,40,63,60,68,78,62,84,117,101,41,40,63,58,115,100,97,121,41,63,124,10,40,63,60,68,78,62,87,101,100,41,40,63,58,110,101,115,100,97,121,41,63,124,10,40,63,60,68,78,62,84,104,117,41,40,63,58,114,115,100,97,121,41,63,124,10,40,63,60,68,78,62,83,97,116,41,40,63,58,117,114,100,97,121,41,63>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,102,105,118,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,115,116,114,105,110,103,115,44,32,98,117,116,32,111,110,108,121,32,111,110,101,32,105,115,32,101,118,101,114,32,115,101,116,32,97,102,116,101,114,32,97,32,109,97,116,99,104,46,32,40,65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,119,97,121,32,111,102,32,115,111,108,118,105,110,103,32,116,104,105,115,32,112,114,111,98,108,101,109,32,105,115,32,116,111,32,117,115,101,32,97,32,34,98,114,97,110,99,104,32,114,101,115,101,116,34,32,115,117,98,112,97,116,116,101,114,110,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,46,41>>]},{p,[],[<<70,111,114,32,99,97,112,116,117,114,105,110,103,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,119,104,105,99,104,32,110,97,109,101,115,32,97,114,101,32,110,111,116,32,117,110,105,113,117,101,44,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,111,99,99,117,114,114,101,110,99,101,32,40,99,111,117,110,116,101,100,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,41,32,105,115,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,105,102,32,116,104,101,32,110,97,109,101,32,105,115,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32>>,{code,[],[<<118,97,108,117,101,115>>]},<<32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,116,97,116,101,109,101,110,116,46,32,84,104,101,32>>,{code,[],[<<97,108,108,95,110,97,109,101,115>>]},<<32,99,97,112,116,117,114,105,110,103,32,118,97,108,117,101,32,109,97,116,99,104,101,115,32,97,108,108,32,116,104,101,32,110,97,109,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<89,111,117,32,99,97,110,110,111,116,32,117,115,101,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,32,116,111,32,100,105,115,116,105,110,103,117,105,115,104,32,98,101,116,119,101,101,110,32,116,119,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,97,115,32,80,67,82,69,32,117,115,101,115,32,111,110,108,121,32,116,104,101,32,110,117,109,98,101,114,115,32,119,104,101,110,32,109,97,116,99,104,105,110,103,46,32,70,111,114,32,116,104,105,115,32,114,101,97,115,111,110,44,32,97,110,32,101,114,114,111,114,32,105,115,32,103,105,118,101,110,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,105,102,32,100,105,102,102,101,114,101,110,116,32,110,97,109,101,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,46,32,72,111,119,101,118,101,114,44,32,121,111,117,32,99,97,110,32,115,112,101,99,105,102,121,32,116,104,101,32,115,97,109,101,32,110,97,109,101,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,44,32,101,118,101,110,32,119,104,101,110,32>>,{code,[],[<<100,117,112,110,97,109,101,115>>]},<<32,105,115,32,110,111,116,32,115,101,116,46>>]}]},{a,[{id,<<115,101,99,116,49,52>>}],[]},{h2,[],[<<82,101,112,101,116,105,116,105,111,110>>]},{p,[],[<<82,101,112,101,116,105,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,113,117,97,110,116,105,102,105,101,114,115,44,32,119,104,105,99,104,32,99,97,110,32,102,111,108,108,111,119,32,97,110,121,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,116,101,109,115,58>>]},{ul,[],[{li,[],[<<65,32,108,105,116,101,114,97,108,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<84,104,101,32,100,111,116,32,109,101,116,97,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<84,104,101,32,92,67,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<84,104,101,32,92,88,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<84,104,101,32,92,82,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101>>]},{li,[],[<<65,110,32,101,115,99,97,112,101,32,115,117,99,104,32,97,115,32,92,100,32,111,114,32,92,112,76,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114>>]},{li,[],[<<65,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115>>]},{li,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,40,115,101,101,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41>>]},{li,[],[<<65,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,32,40,105,110,99,108,117,100,105,110,103,32,97,115,115,101,114,116,105,111,110,115,41>>]},{li,[],[<<65,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,114,101,99,117,114,115,105,118,101,32,111,114,32,111,116,104,101,114,119,105,115,101,41>>]}]},{p,[],[<<84,104,101,32,103,101,110,101,114,97,108,32,114,101,112,101,116,105,116,105,111,110,32,113,117,97,110,116,105,102,105,101,114,32,115,112,101,99,105,102,105,101,115,32,97,32,109,105,110,105,109,117,109,32,97,110,100,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,101,114,109,105,116,116,101,100,32,109,97,116,99,104,101,115,44,32,98,121,32,103,105,118,105,110,103,32,116,104,101,32,116,119,111,32,110,117,109,98,101,114,115,32,105,110,32,99,117,114,108,121,32,98,114,97,99,107,101,116,115,32,40,98,114,97,99,101,115,41,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,97,32,99,111,109,109,97,46,32,84,104,101,32,110,117,109,98,101,114,115,32,109,117,115,116,32,98,101,32,60,32,54,53,53,51,54,44,32,97,110,100,32,116,104,101,32,102,105,114,115,116,32,109,117,115,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116,104,101,32,115,101,99,111,110,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,122,122,34,44,32,34,122,122,122,34,44,32,111,114,32,34,122,122,122,122,34,58>>]},{pre,[],[{code,[],[<<122,123,50,44,52,125>>]}]},{p,[],[<<65,32,99,108,111,115,105,110,103,32,98,114,97,99,101,32,111,110,32,105,116,115,32,111,119,110,32,105,115,32,110,111,116,32,97,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,46,32,73,102,32,116,104,101,32,115,101,99,111,110,100,32,110,117,109,98,101,114,32,105,115,32,111,109,105,116,116,101,100,44,32,98,117,116,32,116,104,101,32,99,111,109,109,97,32,105,115,32,112,114,101,115,101,110,116,44,32,116,104,101,114,101,32,105,115,32,110,111,32,117,112,112,101,114,32,108,105,109,105,116,46,32,73,102,32,116,104,101,32,115,101,99,111,110,100,32,110,117,109,98,101,114,32,97,110,100,32,116,104,101,32,99,111,109,109,97,32,97,114,101,32,98,111,116,104,32,111,109,105,116,116,101,100,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,115,112,101,99,105,102,105,101,115,32,97,110,32,101,120,97,99,116,32,110,117,109,98,101,114,32,111,102,32,114,101,113,117,105,114,101,100,32,109,97,116,99,104,101,115,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,116,32,108,101,97,115,116,32,116,104,114,101,101,32,115,117,99,99,101,115,115,105,118,101,32,118,111,119,101,108,115,44,32,98,117,116,32,99,97,110,32,109,97,116,99,104,32,109,97,110,121,32,109,111,114,101,58>>]},{pre,[],[{code,[],[<<91,97,101,105,111,117,93,123,51,44,125>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,101,120,97,99,116,108,121,32,101,105,103,104,116,32,100,105,103,105,116,115,58>>]},{pre,[],[{code,[],[<<92,100,123,56,125>>]}]},{p,[],[<<65,110,32,111,112,101,110,105,110,103,32,99,117,114,108,121,32,98,114,97,99,107,101,116,32,116,104,97,116,32,97,112,112,101,97,114,115,32,105,110,32,97,32,112,111,115,105,116,105,111,110,32,119,104,101,114,101,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,44,32,111,114,32,111,110,101,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101,32,115,121,110,116,97,120,32,111,102,32,97,32,113,117,97,110,116,105,102,105,101,114,44,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32,108,105,116,101,114,97,108,32,99,104,97,114,97,99,116,101,114,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,123,44,54,125,32,105,115,32,110,111,116,32,97,32,113,117,97,110,116,105,102,105,101,114,44,32,98,117,116,32,97,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,32,111,102,32,102,111,117,114,32,99,104,97,114,97,99,116,101,114,115,46>>]},{p,[],[<<73,110,32,85,110,105,99,111,100,101,32,109,111,100,101,44,32,113,117,97,110,116,105,102,105,101,114,115,32,97,112,112,108,121,32,116,111,32,99,104,97,114,97,99,116,101,114,115,32,114,97,116,104,101,114,32,116,104,97,110,32,116,111,32,105,110,100,105,118,105,100,117,97,108,32,100,97,116,97,32,117,110,105,116,115,46,32,84,104,117,115,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,92,120,123,49,48,48,125,123,50,125,32,109,97,116,99,104,101,115,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,44,32,101,97,99,104,32,111,102,32,119,104,105,99,104,32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,50,45,98,121,116,101,32,115,101,113,117,101,110,99,101,32,105,110,32,97,32,85,84,70,45,56,32,115,116,114,105,110,103,46,32,83,105,109,105,108,97,114,108,121,44,32,92,88,123,51,125,32,109,97,116,99,104,101,115,32,116,104,114,101,101,32,85,110,105,99,111,100,101,32,101,120,116,101,110,100,101,100,32,103,114,97,112,104,101,109,101,32,99,108,117,115,116,101,114,115,44,32,101,97,99,104,32,111,102,32,119,104,105,99,104,32,99,97,110,32,98,101,32,109,97,110,121,32,100,97,116,97,32,117,110,105,116,115,32,108,111,110,103,32,40,97,110,100,32,116,104,101,121,32,99,97,110,32,98,101,32,111,102,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,115,41,46>>]},{p,[],[<<84,104,101,32,113,117,97,110,116,105,102,105,101,114,32,123,48,125,32,105,115,32,112,101,114,109,105,116,116,101,100,44,32,99,97,117,115,105,110,103,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,116,111,32,98,101,104,97,118,101,32,97,115,32,105,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,105,116,101,109,32,97,110,100,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,119,101,114,101,32,110,111,116,32,112,114,101,115,101,110,116,46,32,84,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,102,111,114,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,32,97,115,32,115,117,98,114,111,117,116,105,110,101,115,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,40,98,117,116,32,115,101,101,32,97,108,115,111,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,100,101,102,105,110,105,110,103,95,115,117,98,112,97,116,116,101,114,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,101,102,105,110,105,110,103,32,83,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,85,115,101,32,98,121,32,82,101,102,101,114,101,110,99,101,32,79,110,108,121>>]},<<41,46,32,73,116,101,109,115,32,111,116,104,101,114,32,116,104,97,110,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,104,97,118,101,32,97,32,123,48,125,32,113,117,97,110,116,105,102,105,101,114,32,97,114,101,32,111,109,105,116,116,101,100,32,102,114,111,109,32,116,104,101,32,99,111,109,112,105,108,101,100,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<70,111,114,32,99,111,110,118,101,110,105,101,110,99,101,44,32,116,104,101,32,116,104,114,101,101,32,109,111,115,116,32,99,111,109,109,111,110,32,113,117,97,110,116,105,102,105,101,114,115,32,104,97,118,101,32,115,105,110,103,108,101,45,99,104,97,114,97,99,116,101,114,32,97,98,98,114,101,118,105,97,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[<<42>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,48,44,125>>]},{dt,[],[<<43>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,49,44,125>>]},{dt,[],[<<63>>]},{dd,[],[<<69,113,117,105,118,97,108,101,110,116,32,116,111,32,123,48,44,49,125>>]}]},{p,[],[<<73,110,102,105,110,105,116,101,32,108,111,111,112,115,32,99,97,110,32,98,101,32,99,111,110,115,116,114,117,99,116,101,100,32,98,121,32,102,111,108,108,111,119,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,99,97,110,32,109,97,116,99,104,32,110,111,32,99,104,97,114,97,99,116,101,114,115,32,119,105,116,104,32,97,32,113,117,97,110,116,105,102,105,101,114,32,116,104,97,116,32,104,97,115,32,110,111,32,117,112,112,101,114,32,108,105,109,105,116,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,63,41,42>>]}]},{p,[],[<<69,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,111,102,32,80,101,114,108,32,97,110,100,32,80,67,82,69,32,117,115,101,100,32,116,111,32,103,105,118,101,32,97,110,32,101,114,114,111,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,32,102,111,114,32,115,117,99,104,32,112,97,116,116,101,114,110,115,46,32,72,111,119,101,118,101,114,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,99,97,115,101,115,32,119,104,101,114,101,32,116,104,105,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,44,32,115,117,99,104,32,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,119,32,97,99,99,101,112,116,101,100,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,110,121,32,114,101,112,101,116,105,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,110,111,32,99,104,97,114,97,99,116,101,114,115,44,32,116,104,101,32,108,111,111,112,32,105,115,32,102,111,114,99,105,98,108,121,32,98,114,111,107,101,110,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,34,103,114,101,101,100,121,34,44,32,116,104,97,116,32,105,115,44,32,116,104,101,121,32,109,97,116,99,104,32,97,115,32,109,117,99,104,32,97,115,32,112,111,115,115,105,98,108,101,32,40,117,112,32,116,111,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,101,114,109,105,116,116,101,100,32,116,105,109,101,115,41,44,32,119,105,116,104,111,117,116,32,99,97,117,115,105,110,103,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,116,111,32,102,97,105,108,46,32,84,104,101,32,99,108,97,115,115,105,99,32,101,120,97,109,112,108,101,32,111,102,32,119,104,101,114,101,32,116,104,105,115,32,103,105,118,101,115,32,112,114,111,98,108,101,109,115,32,105,115,32,105,110,32,116,114,121,105,110,103,32,116,111,32,109,97,116,99,104,32,99,111,109,109,101,110,116,115,32,105,110,32,67,32,112,114,111,103,114,97,109,115,46,32,84,104,101,115,101,32,97,112,112,101,97,114,32,98,101,116,119,101,101,110,32,47,42,32,97,110,100,32,42,47,46,32,87,105,116,104,105,110,32,116,104,101,32,99,111,109,109,101,110,116,44,32,105,110,100,105,118,105,100,117,97,108,32,42,32,97,110,100,32,47,32,99,104,97,114,97,99,116,101,114,115,32,99,97,110,32,97,112,112,101,97,114,46,32,65,110,32,97,116,116,101,109,112,116,32,116,111,32,109,97,116,99,104,32,67,32,99,111,109,109,101,110,116,115,32,98,121,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<47,92,42,46,42,92,42,47>>]}]},{p,[],[<<116,111,32,116,104,101,32,115,116,114,105,110,103>>]},{pre,[],[{code,[],[<<47,42,32,102,105,114,115,116,32,99,111,109,109,101,110,116,32,42,47,32,32,110,111,116,32,99,111,109,109,101,110,116,32,32,47,42,32,115,101,99,111,110,100,32,99,111,109,109,101,110,116,32,42,47>>]}]},{p,[],[<<102,97,105,108,115,44,32,97,115,32,105,116,32,109,97,116,99,104,101,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,32,111,119,105,110,103,32,116,111,32,116,104,101,32,103,114,101,101,100,105,110,101,115,115,32,111,102,32,116,104,101,32,46,42,32,105,116,101,109,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,102,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,44,32,105,116,32,99,101,97,115,101,115,32,116,111,32,98,101,32,103,114,101,101,100,121,44,32,97,110,100,32,105,110,115,116,101,97,100,32,109,97,116,99,104,101,115,32,116,104,101,32,109,105,110,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,112,111,115,115,105,98,108,101,44,32,115,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,100,111,101,115,32,116,104,101,32,114,105,103,104,116,32,116,104,105,110,103,32,119,105,116,104,32,116,104,101,32,67,32,99,111,109,109,101,110,116,115,58>>]},{pre,[],[{code,[],[<<47,92,42,46,42,63,92,42,47>>]}]},{p,[],[<<84,104,101,32,109,101,97,110,105,110,103,32,111,102,32,116,104,101,32,118,97,114,105,111,117,115,32,113,117,97,110,116,105,102,105,101,114,115,32,105,115,32,110,111,116,32,111,116,104,101,114,119,105,115,101,32,99,104,97,110,103,101,100,44,32,111,110,108,121,32,116,104,101,32,112,114,101,102,101,114,114,101,100,32,110,117,109,98,101,114,32,111,102,32,109,97,116,99,104,101,115,46,32,68,111,32,110,111,116,32,99,111,110,102,117,115,101,32,116,104,105,115,32,117,115,101,32,111,102,32,113,117,101,115,116,105,111,110,32,109,97,114,107,32,119,105,116,104,32,105,116,115,32,117,115,101,32,97,115,32,97,32,113,117,97,110,116,105,102,105,101,114,32,105,110,32,105,116,115,32,111,119,110,32,114,105,103,104,116,46,32,65,115,32,105,116,32,104,97,115,32,116,119,111,32,117,115,101,115,44,32,105,116,32,99,97,110,32,115,111,109,101,116,105,109,101,115,32,97,112,112,101,97,114,32,100,111,117,98,108,101,100,44,32,97,115,32,105,110>>]},{pre,[],[{code,[],[<<92,100,63,63,92,100>>]}]},{p,[],[<<119,104,105,99,104,32,109,97,116,99,104,101,115,32,111,110,101,32,100,105,103,105,116,32,98,121,32,112,114,101,102,101,114,101,110,99,101,44,32,98,117,116,32,99,97,110,32,109,97,116,99,104,32,116,119,111,32,105,102,32,116,104,97,116,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,46>>]},{p,[],[<<73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<32,105,115,32,115,101,116,32,40,97,110,32,111,112,116,105,111,110,32,116,104,97,116,32,105,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,32,105,110,32,80,101,114,108,41,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,110,111,116,32,103,114,101,101,100,121,32,98,121,32,100,101,102,97,117,108,116,44,32,98,117,116,32,105,110,100,105,118,105,100,117,97,108,32,111,110,101,115,32,99,97,110,32,98,101,32,109,97,100,101,32,103,114,101,101,100,121,32,98,121,32,102,111,108,108,111,119,105,110,103,32,116,104,101,109,32,119,105,116,104,32,97,32,113,117,101,115,116,105,111,110,32,109,97,114,107,46,32,84,104,97,116,32,105,115,44,32,105,116,32,105,110,118,101,114,116,115,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,46>>]},{p,[],[<<87,104,101,110,32,97,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,113,117,97,110,116,105,102,105,101,100,32,119,105,116,104,32,97,32,109,105,110,105,109,117,109,32,114,101,112,101,97,116,32,99,111,117,110,116,32,116,104,97,116,32,105,115,32,62,32,49,32,111,114,32,119,105,116,104,32,97,32,108,105,109,105,116,101,100,32,109,97,120,105,109,117,109,44,32,109,111,114,101,32,109,101,109,111,114,121,32,105,115,32,114,101,113,117,105,114,101,100,32,102,111,114,32,116,104,101,32,99,111,109,112,105,108,101,100,32,112,97,116,116,101,114,110,44,32,105,110,32,112,114,111,112,111,114,116,105,111,110,32,116,111,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,109,105,110,105,109,117,109,32,111,114,32,109,97,120,105,109,117,109,46>>]},{p,[],[<<73,102,32,97,32,112,97,116,116,101,114,110,32,115,116,97,114,116,115,32,119,105,116,104,32,46,42,32,111,114,32,46,123,48,44,125,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,40,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,115>>]},<<41,32,105,115,32,115,101,116,44,32,116,104,117,115,32,97,108,108,111,119,105,110,103,32,116,104,101,32,100,111,116,32,116,111,32,109,97,116,99,104,32,110,101,119,108,105,110,101,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,105,109,112,108,105,99,105,116,108,121,32,97,110,99,104,111,114,101,100,44,32,98,101,99,97,117,115,101,32,119,104,97,116,101,118,101,114,32,102,111,108,108,111,119,115,32,105,115,32,116,114,105,101,100,32,97,103,97,105,110,115,116,32,101,118,101,114,121,32,99,104,97,114,97,99,116,101,114,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,83,111,44,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,114,101,116,114,121,105,110,103,32,116,104,101,32,111,118,101,114,97,108,108,32,109,97,116,99,104,32,97,116,32,97,110,121,32,112,111,115,105,116,105,111,110,32,97,102,116,101,114,32,116,104,101,32,102,105,114,115,116,46,32,80,67,82,69,32,110,111,114,109,97,108,108,121,32,116,114,101,97,116,115,32,115,117,99,104,32,97,32,112,97,116,116,101,114,110,32,97,115,32,105,102,32,105,116,32,119,97,115,32,112,114,101,99,101,100,101,100,32,98,121,32,92,65,46>>]},{p,[],[<<73,110,32,99,97,115,101,115,32,119,104,101,114,101,32,105,116,32,105,115,32,107,110,111,119,110,32,116,104,97,116,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,115,32,110,111,32,110,101,119,108,105,110,101,115,44,32,105,116,32,105,115,32,119,111,114,116,104,32,115,101,116,116,105,110,103,32>>,{code,[],[<<100,111,116,97,108,108>>]},<<32,116,111,32,111,98,116,97,105,110,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,44,32,111,114,32,97,108,116,101,114,110,97,116,105,118,101,108,121,32,117,115,105,110,103,32,94,32,116,111,32,105,110,100,105,99,97,116,101,32,97,110,99,104,111,114,105,110,103,32,101,120,112,108,105,99,105,116,108,121,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,116,104,101,114,101,32,97,114,101,32,115,111,109,101,32,99,97,115,101,115,32,119,104,101,114,101,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,99,97,110,110,111,116,32,98,101,32,117,115,101,100,46,32,87,104,101,110,32,46,42,32,105,115,32,105,110,115,105,100,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,116,104,101,32,115,117,98,106,101,99,116,32,111,102,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,101,108,115,101,119,104,101,114,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,115,116,97,114,116,32,99,97,110,32,102,97,105,108,32,119,104,101,114,101,32,97,32,108,97,116,101,114,32,111,110,101,32,115,117,99,99,101,101,100,115,46,32,67,111,110,115,105,100,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,46,42,41,97,98,99,92,49>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,120,121,122,49,50,51,97,98,99,49,50,51,34,44,32,116,104,101,32,109,97,116,99,104,32,112,111,105,110,116,32,105,115,32,116,104,101,32,102,111,117,114,116,104,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,114,101,102,111,114,101,44,32,115,117,99,104,32,97,32,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,105,109,112,108,105,99,105,116,108,121,32,97,110,99,104,111,114,101,100,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,99,97,115,101,32,119,104,101,114,101,32,105,109,112,108,105,99,105,116,32,97,110,99,104,111,114,105,110,103,32,105,115,32,110,111,116,32,97,112,112,108,105,101,100,32,105,115,32,119,104,101,110,32,116,104,101,32,108,101,97,100,105,110,103,32,46,42,32,105,115,32,105,110,115,105,100,101,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,79,110,99,101,32,97,103,97,105,110,44,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,115,116,97,114,116,32,99,97,110,32,102,97,105,108,32,119,104,101,114,101,32,97,32,108,97,116,101,114,32,111,110,101,32,115,117,99,99,101,101,100,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,62,46,42,63,97,41,98>>]}]},{p,[],[<<73,116,32,109,97,116,99,104,101,115,32,34,97,98,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,34,97,97,98,34,46,32,84,104,101,32,117,115,101,32,111,102,32,116,104,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,111,110,116,114,111,108,32,118,101,114,98,115,32,40,42,80,82,85,78,69,41,32,97,110,100,32,40,42,83,75,73,80,41,32,97,108,115,111,32,100,105,115,97,98,108,101,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,46>>]},{p,[],[<<87,104,101,110,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,114,101,112,101,97,116,101,100,44,32,116,104,101,32,118,97,108,117,101,32,99,97,112,116,117,114,101,100,32,105,115,32,116,104,101,32,115,117,98,115,116,114,105,110,103,32,116,104,97,116,32,109,97,116,99,104,101,100,32,116,104,101,32,102,105,110,97,108,32,105,116,101,114,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,102,116,101,114>>]},{pre,[],[{code,[],[<<40,116,119,101,101,100,108,101,91,100,117,109,101,93,123,51,125,92,115,42,41,43>>]}]},{p,[],[<<104,97,115,32,109,97,116,99,104,101,100,32,34,116,119,101,101,100,108,101,100,117,109,32,116,119,101,101,100,108,101,100,101,101,34,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,105,115,32,34,116,119,101,101,100,108,101,100,101,101,34,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,101,115,116,101,100,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,116,104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,115,32,99,97,110,32,104,97,118,101,32,98,101,101,110,32,115,101,116,32,105,110,32,112,114,101,118,105,111,117,115,32,105,116,101,114,97,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,102,116,101,114>>]},{pre,[],[{code,[],[<<47,40,97,124,40,98,41,41,43,47>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,34,97,98,97,34,44,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,115,101,99,111,110,100,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,32,105,115,32,34,98,34,46>>]},{a,[{id,<<115,101,99,116,49,53>>}],[]},{h2,[],[<<65,116,111,109,105,99,32,71,114,111,117,112,105,110,103,32,97,110,100,32,80,111,115,115,101,115,115,105,118,101,32,81,117,97,110,116,105,102,105,101,114,115>>]},{p,[],[<<87,105,116,104,32,98,111,116,104,32,109,97,120,105,109,105,122,105,110,103,32,40,34,103,114,101,101,100,121,34,41,32,97,110,100,32,109,105,110,105,109,105,122,105,110,103,32,40,34,117,110,103,114,101,101,100,121,34,32,111,114,32,34,108,97,122,121,34,41,32,114,101,112,101,116,105,116,105,111,110,44,32,102,97,105,108,117,114,101,32,111,102,32,119,104,97,116,32,102,111,108,108,111,119,115,32,110,111,114,109,97,108,108,121,32,99,97,117,115,101,115,32,116,104,101,32,114,101,112,101,97,116,101,100,32,105,116,101,109,32,116,111,32,98,101,32,114,101,45,101,118,97,108,117,97,116,101,100,32,116,111,32,115,101,101,32,105,102,32,97,32,100,105,102,102,101,114,101,110,116,32,110,117,109,98,101,114,32,111,102,32,114,101,112,101,97,116,115,32,97,108,108,111,119,115,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,116,111,32,109,97,116,99,104,46,32,83,111,109,101,116,105,109,101,115,32,105,116,32,105,115,32,117,115,101,102,117,108,32,116,111,32,112,114,101,118,101,110,116,32,116,104,105,115,44,32,101,105,116,104,101,114,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,110,97,116,117,114,101,32,111,102,32,116,104,101,32,109,97,116,99,104,44,32,111,114,32,116,111,32,99,97,117,115,101,32,105,116,32,116,111,32,102,97,105,108,32,101,97,114,108,105,101,114,32,116,104,97,110,32,105,116,32,111,116,104,101,114,119,105,115,101,32,109,105,103,104,116,44,32,119,104,101,110,32,116,104,101,32,97,117,116,104,111,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,107,110,111,119,115,32,116,104,97,116,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,99,97,114,114,121,105,110,103,32,111,110,46>>]},{p,[],[<<67,111,110,115,105,100,101,114,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,112,97,116,116,101,114,110,32,92,100,43,102,111,111,32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,117,98,106,101,99,116,32,108,105,110,101,58>>]},{pre,[],[{code,[],[<<49,50,51,52,53,54,98,97,114>>]}]},{p,[],[<<65,102,116,101,114,32,109,97,116,99,104,105,110,103,32,97,108,108,32,115,105,120,32,100,105,103,105,116,115,32,97,110,100,32,116,104,101,110,32,102,97,105,108,105,110,103,32,116,111,32,109,97,116,99,104,32,34,102,111,111,34,44,32,116,104,101,32,110,111,114,109,97,108,32,97,99,116,105,111,110,32,111,102,32,116,104,101,32,109,97,116,99,104,101,114,32,105,115,32,116,111,32,116,114,121,32,97,103,97,105,110,32,119,105,116,104,32,111,110,108,121,32,102,105,118,101,32,100,105,103,105,116,115,32,109,97,116,99,104,105,110,103,32,105,116,101,109,32,92,100,43,44,32,97,110,100,32,116,104,101,110,32,119,105,116,104,32,102,111,117,114,44,32,97,110,100,32,115,111,32,111,110,44,32,98,101,102,111,114,101,32,117,108,116,105,109,97,116,101,108,121,32,102,97,105,108,105,110,103,46,32,34,65,116,111,109,105,99,32,103,114,111,117,112,105,110,103,34,32,40,97,32,116,101,114,109,32,116,97,107,101,110,32,102,114,111,109,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,39,115,32,98,111,111,107,41,32,112,114,111,118,105,100,101,115,32,116,104,101,32,109,101,97,110,115,32,102,111,114,32,115,112,101,99,105,102,121,105,110,103,32,116,104,97,116,32,111,110,99,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,109,97,116,99,104,101,100,44,32,105,116,32,105,115,32,110,111,116,32,116,111,32,98,101,32,114,101,45,101,118,97,108,117,97,116,101,100,32,105,110,32,116,104,105,115,32,119,97,121,46>>]},{p,[],[<<73,102,32,97,116,111,109,105,99,32,103,114,111,117,112,105,110,103,32,105,115,32,117,115,101,100,32,102,111,114,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,44,32,116,104,101,32,109,97,116,99,104,101,114,32,103,105,118,101,115,32,117,112,32,105,109,109,101,100,105,97,116,101,108,121,32,111,110,32,102,97,105,108,105,110,103,32,116,111,32,109,97,116,99,104,32,34,102,111,111,34,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,46,32,84,104,101,32,110,111,116,97,116,105,111,110,32,105,115,32,97,32,107,105,110,100,32,111,102,32,115,112,101,99,105,97,108,32,112,97,114,101,110,116,104,101,115,105,115,44,32,115,116,97,114,116,105,110,103,32,119,105,116,104,32>>,{code,[],[<<40,63,62>>]},<<32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,63,62,92,100,43,41,102,111,111>>]}]},{p,[],[<<84,104,105,115,32,107,105,110,100,32,111,102,32,112,97,114,101,110,116,104,101,115,105,115,32,34,108,111,99,107,115,32,117,112,34,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,32,99,111,110,116,97,105,110,115,32,111,110,99,101,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,44,32,97,110,100,32,97,32,102,97,105,108,117,114,101,32,102,117,114,116,104,101,114,32,105,110,116,111,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,112,114,101,118,101,110,116,101,100,32,102,114,111,109,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,105,116,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,112,97,115,116,32,105,116,32,116,111,32,112,114,101,118,105,111,117,115,32,105,116,101,109,115,44,32,104,111,119,101,118,101,114,44,32,119,111,114,107,115,32,97,115,32,110,111,114,109,97,108,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,100,101,115,99,114,105,112,116,105,111,110,32,105,115,32,116,104,97,116,32,97,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,105,115,32,116,121,112,101,32,109,97,116,99,104,101,115,32,116,104,101,32,115,116,114,105,110,103,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,110,32,105,100,101,110,116,105,99,97,108,32,115,116,97,110,100,97,108,111,110,101,32,112,97,116,116,101,114,110,32,119,111,117,108,100,32,109,97,116,99,104,44,32,105,102,32,97,110,99,104,111,114,101,100,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]},{p,[],[<<65,116,111,109,105,99,32,103,114,111,117,112,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,83,105,109,112,108,101,32,99,97,115,101,115,32,115,117,99,104,32,97,115,32,116,104,101,32,97,98,111,118,101,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,97,32,109,97,120,105,109,105,122,105,110,103,32,114,101,112,101,97,116,32,116,104,97,116,32,109,117,115,116,32,115,119,97,108,108,111,119,32,101,118,101,114,121,116,104,105,110,103,32,105,116,32,99,97,110,46,32,83,111,44,32,119,104,105,108,101,32,98,111,116,104,32,92,100,43,32,97,110,100,32,92,100,43,63,32,97,114,101,32,112,114,101,112,97,114,101,100,32,116,111,32,97,100,106,117,115,116,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,100,105,103,105,116,115,32,116,104,101,121,32,109,97,116,99,104,32,116,111,32,109,97,107,101,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,44,32>>,{code,[],[<<40,63,62,92,100,43,41>>]},<<32,99,97,110,32,111,110,108,121,32,109,97,116,99,104,32,97,110,32,101,110,116,105,114,101,32,115,101,113,117,101,110,99,101,32,111,102,32,100,105,103,105,116,115,46>>]},{p,[],[<<65,116,111,109,105,99,32,103,114,111,117,112,115,32,105,110,32,103,101,110,101,114,97,108,32,99,97,110,32,99,111,110,116,97,105,110,32,97,110,121,32,99,111,109,112,108,105,99,97,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,97,110,100,32,99,97,110,32,98,101,32,110,101,115,116,101,100,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,102,111,114,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,105,115,32,106,117,115,116,32,97,32,115,105,110,103,108,101,32,114,101,112,101,97,116,101,100,32,105,116,101,109,44,32,97,115,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,97,98,111,118,101,44,32,97,32,115,105,109,112,108,101,114,32,110,111,116,97,116,105,111,110,44,32,99,97,108,108,101,100,32,97,32,34,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,34,32,99,97,110,32,98,101,32,117,115,101,100,46,32,84,104,105,115,32,99,111,110,115,105,115,116,115,32,111,102,32,97,110,32,101,120,116,114,97,32,43,32,99,104,97,114,97,99,116,101,114,32,102,111,108,108,111,119,105,110,103,32,97,32,113,117,97,110,116,105,102,105,101,114,46,32,85,115,105,110,103,32,116,104,105,115,32,110,111,116,97,116,105,111,110,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,114,101,119,114,105,116,116,101,110,32,97,115>>]},{pre,[],[{code,[],[<<92,100,43,43,102,111,111>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,97,110,32,101,110,116,105,114,101,32,103,114,111,117,112,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,124,120,121,122,41,123,50,44,51,125,43>>]}]},{p,[],[<<80,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,97,108,119,97,121,115,32,103,114,101,101,100,121,59,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,103,114,101,101,100,121>>]},<<32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,121,32,97,114,101,32,97,32,99,111,110,118,101,110,105,101,110,116,32,110,111,116,97,116,105,111,110,32,102,111,114,32,116,104,101,32,115,105,109,112,108,101,114,32,102,111,114,109,115,32,111,102,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,72,111,119,101,118,101,114,44,32,116,104,101,114,101,32,105,115,32,110,111,32,100,105,102,102,101,114,101,110,99,101,32,105,110,32,116,104,101,32,109,101,97,110,105,110,103,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,116,104,101,32,101,113,117,105,118,97,108,101,110,116,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,98,117,116,32,116,104,101,114,101,32,99,97,110,32,98,101,32,97,32,112,101,114,102,111,114,109,97,110,99,101,32,100,105,102,102,101,114,101,110,99,101,59,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,97,114,101,32,112,114,111,98,97,98,108,121,32,115,108,105,103,104,116,108,121,32,102,97,115,116,101,114,46>>]},{p,[],[<<84,104,101,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,115,121,110,116,97,120,32,105,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,116,111,32,116,104,101,32,80,101,114,108,32,53,46,56,32,115,121,110,116,97,120,46,32,74,101,102,102,114,101,121,32,70,114,105,101,100,108,32,111,114,105,103,105,110,97,116,101,100,32,116,104,101,32,105,100,101,97,32,40,97,110,100,32,116,104,101,32,110,97,109,101,41,32,105,110,32,116,104,101,32,102,105,114,115,116,32,101,100,105,116,105,111,110,32,111,102,32,104,105,115,32,98,111,111,107,46,32,77,105,107,101,32,77,99,67,108,111,115,107,101,121,32,108,105,107,101,100,32,105,116,44,32,115,111,32,105,109,112,108,101,109,101,110,116,101,100,32,105,116,32,119,104,101,110,32,104,101,32,98,117,105,108,116,32,116,104,101,32,83,117,110,32,74,97,118,97,32,112,97,99,107,97,103,101,44,32,97,110,100,32,80,67,82,69,32,99,111,112,105,101,100,32,105,116,32,102,114,111,109,32,116,104,101,114,101,46,32,73,116,32,117,108,116,105,109,97,116,101,108,121,32,102,111,117,110,100,32,105,116,115,32,119,97,121,32,105,110,116,111,32,80,101,114,108,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,48,46>>]},{p,[],[<<80,67,82,69,32,104,97,115,32,97,110,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,34,112,111,115,115,101,115,115,105,102,105,101,115,34,32,99,101,114,116,97,105,110,32,115,105,109,112,108,101,32,112,97,116,116,101,114,110,32,99,111,110,115,116,114,117,99,116,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,115,101,113,117,101,110,99,101,32,65,43,66,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,65,43,43,66,44,32,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,112,111,105,110,116,32,105,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,65,58,115,32,119,104,101,110,32,66,32,109,117,115,116,32,102,111,108,108,111,119,46>>]},{p,[],[<<87,104,101,110,32,97,32,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,115,32,97,110,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,32,105,110,115,105,100,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,99,97,110,32,105,116,115,101,108,102,32,98,101,32,114,101,112,101,97,116,101,100,32,97,110,32,117,110,108,105,109,105,116,101,100,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,44,32,116,104,101,32,117,115,101,32,111,102,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,105,115,32,116,104,101,32,111,110,108,121,32,119,97,121,32,116,111,32,97,118,111,105,100,32,115,111,109,101,32,102,97,105,108,105,110,103,32,109,97,116,99,104,101,115,32,116,97,107,105,110,103,32,97,32,108,111,110,103,32,116,105,109,101,46,32,84,104,101,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<40,92,68,43,124,60,92,100,43,62,41,42,91,33,63,93>>]}]},{p,[],[<<109,97,116,99,104,101,115,32,97,110,32,117,110,108,105,109,105,116,101,100,32,110,117,109,98,101,114,32,111,102,32,115,117,98,115,116,114,105,110,103,115,32,116,104,97,116,32,101,105,116,104,101,114,32,99,111,110,115,105,115,116,32,111,102,32,110,111,110,45,100,105,103,105,116,115,44,32,111,114,32,100,105,103,105,116,115,32,101,110,99,108,111,115,101,100,32,105,110,32,60,62,44,32,102,111,108,108,111,119,101,100,32,98,121,32,33,32,111,114,32,63,46,32,87,104,101,110,32,105,116,32,109,97,116,99,104,101,115,44,32,105,116,32,114,117,110,115,32,113,117,105,99,107,108,121,46,32,72,111,119,101,118,101,114,44,32,105,102,32,105,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111>>]},{pre,[],[{code,[],[<<97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97>>]}]},{p,[],[<<105,116,32,116,97,107,101,115,32,97,32,108,111,110,103,32,116,105,109,101,32,98,101,102,111,114,101,32,114,101,112,111,114,116,105,110,103,32,102,97,105,108,117,114,101,46,32,84,104,105,115,32,105,115,32,98,101,99,97,117,115,101,32,116,104,101,32,115,116,114,105,110,103,32,99,97,110,32,98,101,32,100,105,118,105,100,101,100,32,98,101,116,119,101,101,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,92,68,43,32,114,101,112,101,97,116,32,97,110,100,32,116,104,101,32,101,120,116,101,114,110,97,108,32,42,32,114,101,112,101,97,116,32,105,110,32,109,97,110,121,32,119,97,121,115,44,32,97,110,100,32,97,108,108,32,109,117,115,116,32,98,101,32,116,114,105,101,100,46,32,40,84,104,101,32,101,120,97,109,112,108,101,32,117,115,101,115,32,91,33,63,93,32,114,97,116,104,101,114,32,116,104,97,110,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,97,116,32,116,104,101,32,101,110,100,44,32,97,115,32,98,111,116,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,104,97,118,101,32,97,110,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,97,108,108,111,119,115,32,102,111,114,32,102,97,115,116,32,102,97,105,108,117,114,101,32,119,104,101,110,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,105,115,32,117,115,101,100,46,32,84,104,101,121,32,114,101,109,101,109,98,101,114,32,116,104,101,32,108,97,115,116,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,116,104,97,116,32,105,115,32,114,101,113,117,105,114,101,100,32,102,111,114,32,97,32,109,97,116,99,104,44,32,97,110,100,32,102,97,105,108,32,101,97,114,108,121,32,105,102,32,105,116,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,46,41,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,99,104,97,110,103,101,100,32,115,111,32,116,104,97,116,32,105,116,32,117,115,101,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,108,105,107,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,100,105,103,105,116,115,32,99,97,110,110,111,116,32,98,101,32,98,114,111,107,101,110,44,32,97,110,100,32,102,97,105,108,117,114,101,32,104,97,112,112,101,110,115,32,113,117,105,99,107,108,121,58>>]},{pre,[],[{code,[],[<<40,40,63,62,92,68,43,41,124,60,92,100,43,62,41,42,91,33,63,93>>]}]},{a,[{id,<<115,101,99,116,49,54>>}],[]},{h2,[],[<<66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]},{p,[],[<<79,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,97,32,98,97,99,107,115,108,97,115,104,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,100,105,103,105,116,32,62,32,48,32,40,97,110,100,32,112,111,115,115,105,98,108,121,32,102,117,114,116,104,101,114,32,100,105,103,105,116,115,41,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,101,97,114,108,105,101,114,32,40,116,104,97,116,32,105,115,44,32,116,111,32,105,116,115,32,108,101,102,116,41,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,44,32,112,114,111,118,105,100,101,100,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,32,116,104,97,116,32,109,97,110,121,32,112,114,101,118,105,111,117,115,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,100,101,99,105,109,97,108,32,110,117,109,98,101,114,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,32,105,115,32,60,32,49,48,44,32,105,116,32,105,115,32,97,108,119,97,121,115,32,116,97,107,101,110,32,97,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,97,110,100,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,97,114,101,32,110,111,116,32,116,104,97,116,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,108,101,102,116,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,32,100,111,32,110,101,101,100,32,110,111,116,32,98,101,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,102,111,114,32,110,117,109,98,101,114,115,32,60,32,49,48,46,32,65,32,34,102,111,114,119,97,114,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,34,32,111,102,32,116,104,105,115,32,116,121,112,101,32,99,97,110,32,109,97,107,101,32,115,101,110,115,101,32,119,104,101,110,32,97,32,114,101,112,101,116,105,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,32,97,110,100,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,114,105,103,104,116,32,104,97,115,32,112,97,114,116,105,99,105,112,97,116,101,100,32,105,110,32,97,110,32,101,97,114,108,105,101,114,32,105,116,101,114,97,116,105,111,110,46>>]},{p,[],[<<73,116,32,105,115,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,118,101,32,97,32,110,117,109,101,114,105,99,97,108,32,34,102,111,114,119,97,114,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,34,32,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,119,104,111,115,101,32,110,117,109,98,101,114,32,105,115,32,49,48,32,111,114,32,109,111,114,101,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,44,32,97,115,32,97,32,115,101,113,117,101,110,99,101,32,115,117,99,104,32,97,115,32,92,53,48,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,97,32,99,104,97,114,97,99,116,101,114,32,100,101,102,105,110,101,100,32,105,110,32,111,99,116,97,108,46,32,70,111,114,32,109,111,114,101,32,100,101,116,97,105,108,115,32,111,102,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,97,32,98,97,99,107,115,108,97,115,104,44,32,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,111,110,95,112,114,105,110,116,105,110,103,95,99,104,97,114,97,99,116,101,114,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,111,110,45,80,114,105,110,116,105,110,103,32,67,104,97,114,97,99,116,101,114,115>>]},<<32,101,97,114,108,105,101,114,46,32,84,104,101,114,101,32,105,115,32,110,111,32,115,117,99,104,32,112,114,111,98,108,101,109,32,119,104,101,110,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,117,115,101,100,46,32,65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,111,115,115,105,98,108,101,32,117,115,105,110,103,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,40,115,101,101,32,98,101,108,111,119,41,46>>]},{p,[],[<<65,110,111,116,104,101,114,32,119,97,121,32,116,111,32,97,118,111,105,100,32,116,104,101,32,97,109,98,105,103,117,105,116,121,32,105,110,104,101,114,101,110,116,32,105,110,32,116,104,101,32,117,115,101,32,111,102,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,97,32,98,97,99,107,115,108,97,115,104,32,105,115,32,116,111,32,117,115,101,32,116,104,101,32,92,103,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,46,32,84,104,105,115,32,101,115,99,97,112,101,32,109,117,115,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,117,110,115,105,103,110,101,100,32,110,117,109,98,101,114,32,111,114,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,98,114,97,99,101,115,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,32,97,114,101,32,105,100,101,110,116,105,99,97,108,58>>]},{pre,[],[{code,[],[<<40,114,105,110,103,41,44,32,92,49,10,40,114,105,110,103,41,44,32,92,103,49,10,40,114,105,110,103,41,44,32,92,103,123,49,125>>]}]},{p,[],[<<65,110,32,117,110,115,105,103,110,101,100,32,110,117,109,98,101,114,32,115,112,101,99,105,102,105,101,115,32,97,110,32,97,98,115,111,108,117,116,101,32,114,101,102,101,114,101,110,99,101,32,119,105,116,104,111,117,116,32,116,104,101,32,97,109,98,105,103,117,105,116,121,32,116,104,97,116,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,111,108,100,101,114,32,115,121,110,116,97,120,46,32,73,116,32,105,115,32,97,108,115,111,32,117,115,101,102,117,108,32,119,104,101,110,32,108,105,116,101,114,97,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,105,115,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,40,100,101,102,41,103,104,105,41,92,103,123,45,49,125>>]}]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,92,103,123,45,49,125,32,105,115,32,97,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,115,116,97,114,116,101,100,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,98,101,102,111,114,101,32,92,103,44,32,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,92,50,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,46,32,83,105,109,105,108,97,114,108,121,44,32,92,103,123,45,50,125,32,119,111,117,108,100,32,98,101,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,92,49,46,32,84,104,101,32,117,115,101,32,111,102,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,115,32,99,97,110,32,98,101,32,104,101,108,112,102,117,108,32,105,110,32,108,111,110,103,32,112,97,116,116,101,114,110,115,44,32,97,110,100,32,97,108,115,111,32,105,110,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,99,114,101,97,116,101,100,32,98,121,32,106,111,105,110,105,110,103,32,102,114,97,103,109,101,110,116,115,32,99,111,110,116,97,105,110,105,110,103,32,114,101,102,101,114,101,110,99,101,115,32,119,105,116,104,105,110,32,116,104,101,109,115,101,108,118,101,115,46>>]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,109,97,116,99,104,101,115,32,119,104,97,116,101,118,101,114,32,109,97,116,99,104,101,100,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,114,97,116,104,101,114,32,116,104,97,110,32,97,110,121,116,104,105,110,103,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,116,115,101,108,102,32,40,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,50,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,117,98,112,97,116,116,101,114,110,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]},<<32,100,101,115,99,114,105,98,101,115,32,97,32,119,97,121,32,111,102,32,100,111,105,110,103,32,116,104,97,116,41,46,32,83,111,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,115,101,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,34,114,101,115,112,111,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,44,32,98,117,116,32,110,111,116,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,49,105,98,105,108,105,116,121>>]}]},{p,[],[<<73,102,32,99,97,115,101,102,117,108,32,109,97,116,99,104,105,110,103,32,105,115,32,105,110,32,102,111,114,99,101,32,97,116,32,116,104,101,32,116,105,109,101,32,111,102,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,44,32,116,104,101,32,99,97,115,101,32,111,102,32,108,101,116,116,101,114,115,32,105,115,32,114,101,108,101,118,97,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,114,97,104,32,114,97,104,34,32,97,110,100,32,34,82,65,72,32,82,65,72,34,44,32,98,117,116,32,110,111,116,32,34,82,65,72,32,114,97,104,34,44,32,97,108,116,104,111,117,103,104,32,116,104,101,32,111,114,105,103,105,110,97,108,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,32,99,97,115,101,108,101,115,115,108,121,58>>]},{pre,[],[{code,[],[<<40,40,63,105,41,114,97,104,41,92,115,43,92,49>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,32,111,102,32,119,114,105,116,105,110,103,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,101,32,46,78,69,84,32,115,121,110,116,97,120,32>>,{code,[],[<<92,107,123,110,97,109,101,125>>]},<<32,97,110,100,32,116,104,101,32,80,101,114,108,32,115,121,110,116,97,120,32>>,{code,[],[<<92,107,60,110,97,109,101,62>>]},<<32,111,114,32>>,{code,[],[<<92,107,39,110,97,109,101,39>>]},<<32,97,114,101,32,115,117,112,112,111,114,116,101,100,44,32,97,115,32,105,115,32,116,104,101,32,80,121,116,104,111,110,32,115,121,110,116,97,120,32>>,{code,[],[<<40,63,80,61,110,97,109,101,41>>]},<<46,32,84,104,101,32,117,110,105,102,105,101,100,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,115,121,110,116,97,120,32,105,110,32,80,101,114,108,32,53,46,49,48,44,32,105,110,32,119,104,105,99,104,32,92,103,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,98,111,116,104,32,110,117,109,101,114,105,99,32,97,110,100,32,110,97,109,101,100,32,114,101,102,101,114,101,110,99,101,115,44,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,84,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,99,97,110,32,98,101,32,114,101,119,114,105,116,116,101,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,119,97,121,115,58>>]},{pre,[],[{code,[],[<<40,63,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,92,107,60,112,49,62,10,40,63,39,112,49,39,40,63,105,41,114,97,104,41,92,115,43,92,107,123,112,49,125,10,40,63,80,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,40,63,80,61,112,49,41,10,40,63,60,112,49,62,40,63,105,41,114,97,104,41,92,115,43,92,103,123,112,49,125>>]}]},{p,[],[<<65,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32,110,97,109,101,32,99,97,110,32,97,112,112,101,97,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,98,101,102,111,114,101,32,111,114,32,97,102,116,101,114,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46>>]},{p,[],[<<84,104,101,114,101,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,115,97,109,101,32,115,117,98,112,97,116,116,101,114,110,46,32,73,102,32,97,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,110,111,116,32,98,101,101,110,32,117,115,101,100,32,105,110,32,97,32,112,97,114,116,105,99,117,108,97,114,32,109,97,116,99,104,44,32,97,110,121,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,105,116,32,97,108,119,97,121,115,32,102,97,105,108,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,102,97,105,108,115,32,105,102,32,105,116,32,115,116,97,114,116,115,32,116,111,32,109,97,116,99,104,32,34,97,34,32,114,97,116,104,101,114,32,116,104,97,110,32,34,98,99,34,58>>]},{pre,[],[{code,[],[<<40,97,124,40,98,99,41,41,92,50>>]}]},{p,[],[<<65,115,32,116,104,101,114,101,32,99,97,110,32,98,101,32,109,97,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,108,108,32,100,105,103,105,116,115,32,102,111,108,108,111,119,105,110,103,32,116,104,101,32,98,97,99,107,115,108,97,115,104,32,97,114,101,32,116,97,107,101,110,32,97,115,32,112,97,114,116,32,111,102,32,97,32,112,111,116,101,110,116,105,97,108,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,110,117,109,98,101,114,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,111,110,116,105,110,117,101,115,32,119,105,116,104,32,97,32,100,105,103,105,116,32,99,104,97,114,97,99,116,101,114,44,32,115,111,109,101,32,100,101,108,105,109,105,116,101,114,32,109,117,115,116,32,98,101,32,117,115,101,100,32,116,111,32,116,101,114,109,105,110,97,116,101,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,44,32,116,104,105,115,32,99,97,110,32,98,101,32,119,104,105,116,101,115,112,97,99,101,46,32,79,116,104,101,114,119,105,115,101,32,97,110,32,101,109,112,116,121,32,99,111,109,109,101,110,116,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,57>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,111,109,109,101,110,116,115>>]},<<41,32,99,97,110,32,98,101,32,117,115,101,100,46>>]},{p,[],[{em,[],[<<82,101,99,117,114,115,105,118,101,32,66,97,99,107,32,82,101,102,101,114,101,110,99,101,115>>]}]},{p,[],[<<65,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,116,104,97,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,119,104,105,99,104,32,105,116,32,114,101,102,101,114,115,32,102,97,105,108,115,32,119,104,101,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,102,105,114,115,116,32,117,115,101,100,44,32,115,111,44,32,102,111,114,32,101,120,97,109,112,108,101,44,32,40,97,92,49,41,32,110,101,118,101,114,32,109,97,116,99,104,101,115,46,32,72,111,119,101,118,101,114,44,32,115,117,99,104,32,114,101,102,101,114,101,110,99,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,32,105,110,115,105,100,101,32,114,101,112,101,97,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,34,97,34,115,32,97,110,100,32,97,108,115,111,32,34,97,98,97,34,44,32,34,97,98,97,98,98,97,97,34,44,32,97,110,100,32,115,111,32,111,110,58>>]},{pre,[],[{code,[],[<<40,97,124,98,92,49,41,43>>]}]},{p,[],[<<65,116,32,101,97,99,104,32,105,116,101,114,97,116,105,111,110,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,109,97,116,99,104,101,115,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,115,116,114,105,110,103,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,112,114,101,118,105,111,117,115,32,105,116,101,114,97,116,105,111,110,46,32,73,110,32,111,114,100,101,114,32,102,111,114,32,116,104,105,115,32,116,111,32,119,111,114,107,44,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,98,101,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,105,116,101,114,97,116,105,111,110,32,100,111,101,115,32,110,111,116,32,110,101,101,100,32,116,111,32,109,97,116,99,104,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,100,111,110,101,32,117,115,105,110,103,32,97,108,116,101,114,110,97,116,105,111,110,44,32,97,115,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,97,98,111,118,101,44,32,111,114,32,98,121,32,97,32,113,117,97,110,116,105,102,105,101,114,32,119,105,116,104,32,97,32,109,105,110,105,109,117,109,32,111,102,32,122,101,114,111,46>>]},{p,[],[<<66,97,99,107,32,114,101,102,101,114,101,110,99,101,115,32,111,102,32,116,104,105,115,32,116,121,112,101,32,99,97,117,115,101,32,116,104,101,32,103,114,111,117,112,32,116,104,97,116,32,116,104,101,121,32,114,101,102,101,114,101,110,99,101,32,116,111,32,98,101,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,79,110,99,101,32,116,104,101,32,119,104,111,108,101,32,103,114,111,117,112,32,104,97,115,32,98,101,101,110,32,109,97,116,99,104,101,100,44,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,99,97,110,110,111,116,32,99,97,117,115,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,116,104,101,32,103,114,111,117,112,46>>]},{a,[{id,<<115,101,99,116,49,55>>}],[]},{h2,[],[<<65,115,115,101,114,116,105,111,110,115>>]},{p,[],[<<65,110,32,97,115,115,101,114,116,105,111,110,32,105,115,32,97,32,116,101,115,116,32,111,110,32,116,104,101,32,99,104,97,114,97,99,116,101,114,115,32,102,111,108,108,111,119,105,110,103,32,111,114,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,99,111,110,115,117,109,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,115,105,109,112,108,101,32,97,115,115,101,114,116,105,111,110,115,32,99,111,100,101,100,32,97,115,32,92,98,44,32,92,66,44,32,92,65,44,32,92,71,44,32,92,90,44,32,92,122,44,32,94,44,32,97,110,100,32,36,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,115,101,99,116,105,111,110,115,46>>]},{p,[],[<<77,111,114,101,32,99,111,109,112,108,105,99,97,116,101,100,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,32,99,111,100,101,100,32,97,115,32,115,117,98,112,97,116,116,101,114,110,115,46,32,84,104,101,114,101,32,97,114,101,32,116,119,111,32,107,105,110,100,115,58,32,116,104,111,115,101,32,116,104,97,116,32,108,111,111,107,32,97,104,101,97,100,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,110,100,32,116,104,111,115,101,32,116,104,97,116,32,108,111,111,107,32,98,101,104,105,110,100,32,105,116,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,109,97,116,99,104,101,100,32,105,110,32,116,104,101,32,110,111,114,109,97,108,32,119,97,121,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,116,32,100,111,101,115,32,110,111,116,32,99,97,117,115,101,32,116,104,101,32,99,117,114,114,101,110,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,32,116,111,32,98,101,32,99,104,97,110,103,101,100,46>>]},{p,[],[<<65,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,110,111,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,46,32,73,102,32,115,117,99,104,32,97,110,32,97,115,115,101,114,116,105,111,110,32,99,111,110,116,97,105,110,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,119,105,116,104,105,110,32,105,116,44,32,116,104,101,115,101,32,97,114,101,32,99,111,117,110,116,101,100,32,102,111,114,32,116,104,101,32,112,117,114,112,111,115,101,115,32,111,102,32,110,117,109,98,101,114,105,110,103,32,116,104,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,46,32,72,111,119,101,118,101,114,44,32,115,117,98,115,116,114,105,110,103,32,99,97,112,116,117,114,105,110,103,32,105,115,32,100,111,110,101,32,111,110,108,121,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,40,80,101,114,108,32,115,111,109,101,116,105,109,101,115,44,32,98,117,116,32,110,111,116,32,97,108,119,97,121,115,44,32,112,101,114,102,111,114,109,115,32,99,97,112,116,117,114,105,110,103,32,105,110,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,41>>]},{'div',[{class,<<119,97,114,110,105,110,103>>}],[{p,[],[<<73,102,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,111,110,101,32,111,114,32,109,111,114,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,115,117,99,99,101,101,100,115,44,32,98,117,116,32,102,97,105,108,117,114,101,32,116,111,32,109,97,116,99,104,32,108,97,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,111,118,101,114,32,116,104,105,115,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,99,97,112,116,117,114,101,115,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,97,114,101,32,114,101,115,101,116,32,111,110,108,121,32,105,102,32,110,111,32,104,105,103,104,101,114,32,110,117,109,98,101,114,101,100,32,99,97,112,116,117,114,101,115,32,97,114,101,32,97,108,114,101,97,100,121,32,115,101,116,46,32,84,104,105,115,32,105,115,44,32,117,110,102,111,114,116,117,110,97,116,101,108,121,44,32,97,32,102,117,110,100,97,109,101,110,116,97,108,32,108,105,109,105,116,97,116,105,111,110,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,44,32,97,110,100,32,97,115,32,80,67,82,69,49,32,105,115,32,110,111,119,32,105,110,32,109,97,105,110,116,101,110,97,110,99,101,45,111,110,108,121,32,115,116,97,116,117,115,44,32,105,116,32,105,115,32,117,110,108,105,107,101,108,121,32,101,118,101,114,32,116,111,32,99,104,97,110,103,101,46>>]}]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,80,101,114,108,44,32,97,115,115,101,114,116,105,111,110,32,115,117,98,112,97,116,116,101,114,110,115,32,99,97,110,32,98,101,32,114,101,112,101,97,116,101,100,46,32,72,111,119,101,118,101,114,44,32,105,116,32,109,97,107,101,115,32,110,111,32,115,101,110,115,101,32,116,111,32,97,115,115,101,114,116,32,116,104,101,32,115,97,109,101,32,116,104,105,110,103,32,109,97,110,121,32,116,105,109,101,115,44,32,116,104,101,32,115,105,100,101,32,101,102,102,101,99,116,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,111,99,99,97,115,105,111,110,97,108,108,121,32,98,101,32,117,115,101,102,117,108,46,32,73,110,32,112,114,97,99,116,105,99,101,44,32,116,104,101,114,101,32,97,114,101,32,111,110,108,121,32,116,104,114,101,101,32,99,97,115,101,115,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,123,48,125,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,105,115,32,110,101,118,101,114,32,111,98,101,121,101,100,32,100,117,114,105,110,103,32,109,97,116,99,104,105,110,103,46,32,72,111,119,101,118,101,114,44,32,105,116,32,99,97,110,32,99,111,110,116,97,105,110,32,105,110,116,101,114,110,97,108,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,103,114,111,117,112,115,32,116,104,97,116,32,97,114,101,32,99,97,108,108,101,100,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,32,116,104,114,111,117,103,104,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,101,99,104,97,110,105,115,109,46>>]}]},{li,[],[{p,[],[<<73,102,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,123,48,44,110,125,44,32,119,104,101,114,101,32,110,32,62,32,48,44,32,105,116,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,105,102,32,105,116,32,119,97,115,32,123,48,44,49,125,46,32,65,116,32,114,117,110,116,105,109,101,44,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,105,115,32,116,114,105,101,100,32,119,105,116,104,32,97,110,100,32,119,105,116,104,111,117,116,32,116,104,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,111,114,100,101,114,32,100,101,112,101,110,100,115,32,111,110,32,116,104,101,32,103,114,101,101,100,105,110,101,115,115,32,111,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,46>>]}]},{li,[],[{p,[],[<<73,102,32,116,104,101,32,109,105,110,105,109,117,109,32,114,101,112,101,116,105,116,105,111,110,32,105,115,32,62,32,48,44,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,105,103,110,111,114,101,100,46,32,84,104,101,32,97,115,115,101,114,116,105,111,110,32,105,115,32,111,98,101,121,101,100,32,111,110,108,121,32,111,110,99,101,32,119,104,101,110,32,101,110,99,111,117,110,116,101,114,101,100,32,100,117,114,105,110,103,32,109,97,116,99,104,105,110,103,46>>]}]}]},{p,[],[{em,[],[<<76,111,111,107,97,104,101,97,100,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<76,111,111,107,97,104,101,97,100,32,97,115,115,101,114,116,105,111,110,115,32,115,116,97,114,116,32,119,105,116,104,32,40,63,61,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,110,100,32,40,63,33,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,32,119,111,114,100,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,115,101,109,105,99,111,108,111,110,44,32,98,117,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,116,104,101,32,115,101,109,105,99,111,108,111,110,32,105,110,32,116,104,101,32,109,97,116,99,104,58>>]},{pre,[],[{code,[],[<<92,119,43,40,63,61,59,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,110,121,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,102,111,111,34,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32,34,98,97,114,34,58>>]},{pre,[],[{code,[],[<<102,111,111,40,63,33,98,97,114,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,97,112,112,97,114,101,110,116,108,121,32,115,105,109,105,108,97,114,32,112,97,116,116,101,114,110>>]},{pre,[],[{code,[],[<<40,63,33,102,111,111,41,98,97,114>>]}]},{p,[],[<<100,111,101,115,32,110,111,116,32,102,105,110,100,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,116,104,97,116,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,115,111,109,101,116,104,105,110,103,32,111,116,104,101,114,32,116,104,97,110,32,34,102,111,111,34,46,32,73,116,32,102,105,110,100,115,32,97,110,121,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,119,104,97,116,115,111,101,118,101,114,44,32,97,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,40,63,33,102,111,111,41,32,105,115,32,97,108,119,97,121,115,32,116,114,117,101,32,119,104,101,110,32,116,104,101,32,110,101,120,116,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,34,98,97,114,34,46,32,65,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,105,115,32,110,101,101,100,101,100,32,116,111,32,97,99,104,105,101,118,101,32,116,104,101,32,111,116,104,101,114,32,101,102,102,101,99,116,46>>]},{p,[],[<<73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,102,111,114,99,101,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,97,116,32,115,111,109,101,32,112,111,105,110,116,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,116,104,101,32,109,111,115,116,32,99,111,110,118,101,110,105,101,110,116,32,119,97,121,32,116,111,32,100,111,32,105,116,32,105,115,32,119,105,116,104,32,40,63,33,41,44,32,97,115,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,46,32,83,111,44,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,114,101,113,117,105,114,101,115,32,116,104,101,114,101,32,105,115,32,110,111,116,32,116,111,32,98,101,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,109,117,115,116,32,97,108,119,97,121,115,32,102,97,105,108,46,32,84,104,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,111,110,116,114,111,108,32,118,101,114,98,32,40,42,70,65,73,76,41,32,111,114,32,40,42,70,41,32,105,115,32,97,32,115,121,110,111,110,121,109,32,102,111,114,32,40,63,33,41,46>>]},{p,[],[{em,[],[<<76,111,111,107,98,101,104,105,110,100,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<76,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,115,116,97,114,116,32,119,105,116,104,32,40,63,60,61,32,102,111,114,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,110,100,32,40,63,60,33,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,105,110,100,115,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,114,34,32,116,104,97,116,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,63,60,33,102,111,111,41,98,97,114>>]}]},{p,[],[<<84,104,101,32,99,111,110,116,101,110,116,115,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,97,114,101,32,114,101,115,116,114,105,99,116,101,100,32,115,117,99,104,32,116,104,97,116,32,97,108,108,32,116,104,101,32,115,116,114,105,110,103,115,32,105,116,32,109,97,116,99,104,101,115,32,109,117,115,116,32,104,97,118,101,32,97,32,102,105,120,101,100,32,108,101,110,103,116,104,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,114,101,32,97,114,101,32,109,97,110,121,32,116,111,112,45,108,101,118,101,108,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,116,104,101,121,32,100,111,32,110,111,116,32,97,108,108,32,104,97,118,101,32,116,111,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,102,105,120,101,100,32,108,101,110,103,116,104,46,32,84,104,117,115,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,112,101,114,109,105,116,116,101,100,58>>]},{pre,[],[{code,[],[<<40,63,60,61,98,117,108,108,111,99,107,124,100,111,110,107,101,121,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,117,115,101,115,32,97,110,32,101,114,114,111,114,32,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,58>>]},{pre,[],[{code,[],[<<40,63,60,33,100,111,103,115,63,124,99,97,116,115,63,41>>]}]},{p,[],[<<66,114,97,110,99,104,101,115,32,116,104,97,116,32,109,97,116,99,104,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,32,115,116,114,105,110,103,115,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,111,110,108,121,32,97,116,32,116,104,101,32,116,111,112,45,108,101,118,101,108,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,46,32,84,104,105,115,32,105,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,99,111,109,112,97,114,101,100,32,119,105,116,104,32,80,101,114,108,44,32,119,104,105,99,104,32,114,101,113,117,105,114,101,115,32,97,108,108,32,98,114,97,110,99,104,101,115,32,116,111,32,109,97,116,99,104,32,116,104,101,32,115,97,109,101,32,108,101,110,103,116,104,32,111,102,32,115,116,114,105,110,103,46,32,65,110,32,97,115,115,101,114,116,105,111,110,32,115,117,99,104,32,97,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,105,115,32,110,111,116,32,112,101,114,109,105,116,116,101,100,44,32,97,115,32,105,116,115,32,115,105,110,103,108,101,32,116,111,112,45,108,101,118,101,108,32,98,114,97,110,99,104,32,99,97,110,32,109,97,116,99,104,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,108,101,110,103,116,104,115,58>>]},{pre,[],[{code,[],[<<40,63,60,61,97,98,40,99,124,100,101,41,41>>]}]},{p,[],[<<72,111,119,101,118,101,114,44,32,105,116,32,105,115,32,97,99,99,101,112,116,97,98,108,101,32,116,111,32,80,67,82,69,32,105,102,32,114,101,119,114,105,116,116,101,110,32,116,111,32,117,115,101,32,116,119,111,32,116,111,112,45,108,101,118,101,108,32,98,114,97,110,99,104,101,115,58>>]},{pre,[],[{code,[],[<<40,63,60,61,97,98,99,124,97,98,100,101,41>>]}]},{p,[],[<<83,111,109,101,116,105,109,101,115,32,116,104,101,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,32,92,75,32,40,115,101,101,32,97,98,111,118,101,41,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,111,102,32,97,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,116,111,32,103,101,116,32,114,111,117,110,100,32,116,104,101,32,102,105,120,101,100,45,108,101,110,103,116,104,32,114,101,115,116,114,105,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,111,102,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,105,115,44,32,102,111,114,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,44,32,116,111,32,109,111,118,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,98,97,99,107,32,116,101,109,112,111,114,97,114,105,108,121,32,98,121,32,116,104,101,32,102,105,120,101,100,32,108,101,110,103,116,104,32,97,110,100,32,116,104,101,110,32,116,114,121,32,116,111,32,109,97,116,99,104,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,105,110,115,117,102,102,105,99,105,101,110,116,32,99,104,97,114,97,99,116,101,114,115,32,98,101,102,111,114,101,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,102,97,105,108,115,46>>]},{p,[],[<<73,110,32,97,32,85,84,70,32,109,111,100,101,44,32,80,67,82,69,32,100,111,101,115,32,110,111,116,32,97,108,108,111,119,32,116,104,101,32,92,67,32,101,115,99,97,112,101,32,40,119,104,105,99,104,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,100,97,116,97,32,117,110,105,116,32,101,118,101,110,32,105,110,32,97,32,85,84,70,32,109,111,100,101,41,32,116,111,32,97,112,112,101,97,114,32,105,110,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,44,32,97,115,32,105,116,32,109,97,107,101,115,32,105,116,32,105,109,112,111,115,115,105,98,108,101,32,116,111,32,99,97,108,99,117,108,97,116,101,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,108,111,111,107,98,101,104,105,110,100,46,32,84,104,101,32,92,88,32,97,110,100,32,92,82,32,101,115,99,97,112,101,115,44,32,119,104,105,99,104,32,99,97,110,32,109,97,116,99,104,32,100,105,102,102,101,114,101,110,116,32,110,117,109,98,101,114,115,32,111,102,32,100,97,116,97,32,117,110,105,116,115,44,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,32,101,105,116,104,101,114,46>>]},{p,[],[<<34,83,117,98,114,111,117,116,105,110,101,34,32,99,97,108,108,115,32,40,115,101,101,32,98,101,108,111,119,41,44,32,115,117,99,104,32,97,115,32,40,63,50,41,32,111,114,32,40,63,38,88,41,44,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,105,110,32,108,111,111,107,98,101,104,105,110,100,115,44,32,97,115,32,108,111,110,103,32,97,115,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,102,105,120,101,100,45,108,101,110,103,116,104,32,115,116,114,105,110,103,46,32,82,101,99,117,114,115,105,111,110,44,32,104,111,119,101,118,101,114,44,32,105,115,32,110,111,116,32,115,117,112,112,111,114,116,101,100,46>>]},{p,[],[<<80,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,115,32,99,97,110,32,98,101,32,117,115,101,100,32,119,105,116,104,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,115,32,116,111,32,115,112,101,99,105,102,121,32,101,102,102,105,99,105,101,110,116,32,109,97,116,99,104,105,110,103,32,111,102,32,102,105,120,101,100,45,108,101,110,103,116,104,32,115,116,114,105,110,103,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,105,109,112,108,101,32,112,97,116,116,101,114,110,32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,97,32,108,111,110,103,32,115,116,114,105,110,103,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,58>>]},{pre,[],[{code,[],[<<97,98,99,100,36>>]}]},{p,[],[<<65,115,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,101,100,115,32,102,114,111,109,32,108,101,102,116,32,116,111,32,114,105,103,104,116,44,32,80,67,82,69,32,108,111,111,107,115,32,102,111,114,32,101,97,99,104,32,34,97,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,97,110,100,32,116,104,101,110,32,115,101,101,115,32,105,102,32,119,104,97,116,32,102,111,108,108,111,119,115,32,109,97,116,99,104,101,115,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115>>]},{pre,[],[{code,[],[<<94,46,42,97,98,99,100,36>>]}]},{p,[],[<<116,104,101,32,105,110,105,116,105,97,108,32,46,42,32,109,97,116,99,104,101,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,32,97,116,32,102,105,114,115,116,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,116,104,105,115,32,102,97,105,108,115,32,40,97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,102,111,108,108,111,119,105,110,103,32,34,97,34,41,44,32,105,116,32,98,97,99,107,116,114,97,99,107,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,99,104,97,114,97,99,116,101,114,44,32,116,104,101,110,32,97,108,108,32,98,117,116,32,116,104,101,32,108,97,115,116,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,44,32,97,110,100,32,115,111,32,111,110,46,32,79,110,99,101,32,97,103,97,105,110,32,116,104,101,32,115,101,97,114,99,104,32,102,111,114,32,34,97,34,32,99,111,118,101,114,115,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,44,32,102,114,111,109,32,114,105,103,104,116,32,116,111,32,108,101,102,116,44,32,115,111,32,119,101,32,97,114,101,32,110,111,32,98,101,116,116,101,114,32,111,102,102,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,119,114,105,116,116,101,110,32,97,115>>]},{pre,[],[{code,[],[<<94,46,42,43,40,63,60,61,97,98,99,100,41>>]}]},{p,[],[<<116,104,101,114,101,32,99,97,110,32,98,101,32,110,111,32,98,97,99,107,116,114,97,99,107,105,110,103,32,102,111,114,32,116,104,101,32,46,42,43,32,105,116,101,109,59,32,105,116,32,99,97,110,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,46,32,84,104,101,32,115,117,98,115,101,113,117,101,110,116,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,32,100,111,101,115,32,97,32,115,105,110,103,108,101,32,116,101,115,116,32,111,110,32,116,104,101,32,108,97,115,116,32,102,111,117,114,32,99,104,97,114,97,99,116,101,114,115,46,32,73,102,32,105,116,32,102,97,105,108,115,44,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,32,105,109,109,101,100,105,97,116,101,108,121,46,32,70,111,114,32,108,111,110,103,32,115,116,114,105,110,103,115,44,32,116,104,105,115,32,97,112,112,114,111,97,99,104,32,109,97,107,101,115,32,97,32,115,105,103,110,105,102,105,99,97,110,116,32,100,105,102,102,101,114,101,110,99,101,32,116,111,32,116,104,101,32,112,114,111,99,101,115,115,105,110,103,32,116,105,109,101,46>>]},{p,[],[{em,[],[<<85,115,105,110,103,32,77,117,108,116,105,112,108,101,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<77,97,110,121,32,97,115,115,101,114,116,105,111,110,115,32,40,111,102,32,97,110,121,32,115,111,114,116,41,32,99,97,110,32,111,99,99,117,114,32,105,110,32,115,117,99,99,101,115,115,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,114,101,101,32,100,105,103,105,116,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,34,57,57,57,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,41,40,63,60,33,57,57,57,41,102,111,111>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,101,97,99,104,32,111,102,32,116,104,101,32,97,115,115,101,114,116,105,111,110,115,32,105,115,32,97,112,112,108,105,101,100,32,105,110,100,101,112,101,110,100,101,110,116,108,121,32,97,116,32,116,104,101,32,115,97,109,101,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,70,105,114,115,116,32,116,104,101,114,101,32,105,115,32,97,32,99,104,101,99,107,32,116,104,97,116,32,116,104,101,32,112,114,101,118,105,111,117,115,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,97,108,108,32,100,105,103,105,116,115,44,32,97,110,100,32,116,104,101,110,32,116,104,101,114,101,32,105,115,32,97,32,99,104,101,99,107,32,116,104,97,116,32,116,104,101,32,115,97,109,101,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46,32,84,104,105,115,32,112,97,116,116,101,114,110,32,100,111,101,115,32>>,{em,[],[<<110,111,116>>]},<<32,109,97,116,99,104,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,115,105,120,32,99,104,97,114,97,99,116,101,114,115,44,32,116,104,101,32,102,105,114,115,116,32,111,102,32,119,104,105,99,104,32,97,114,101,32,100,105,103,105,116,115,32,97,110,100,32,116,104,101,32,108,97,115,116,32,116,104,114,101,101,32,111,102,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,34,49,50,51,97,98,99,102,111,111,34,46,32,65,32,112,97,116,116,101,114,110,32,116,111,32,100,111,32,116,104,97,116,32,105,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,46,46,46,41,40,63,60,33,57,57,57,41,102,111,111>>]}]},{p,[],[<<84,104,105,115,32,116,105,109,101,32,116,104,101,32,102,105,114,115,116,32,97,115,115,101,114,116,105,111,110,32,108,111,111,107,115,32,97,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,115,105,120,32,99,104,97,114,97,99,116,101,114,115,44,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,116,104,114,101,101,32,97,114,101,32,100,105,103,105,116,115,44,32,97,110,100,32,116,104,101,110,32,116,104,101,32,115,101,99,111,110,100,32,97,115,115,101,114,116,105,111,110,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,112,114,101,99,101,100,105,110,103,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,110,111,116,32,34,57,57,57,34,46>>]},{p,[],[<<65,115,115,101,114,116,105,111,110,115,32,99,97,110,32,98,101,32,110,101,115,116,101,100,32,105,110,32,97,110,121,32,99,111,109,98,105,110,97,116,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,97,110,32,111,99,99,117,114,114,101,110,99,101,32,111,102,32,34,98,97,122,34,32,116,104,97,116,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,34,98,97,114,34,44,32,119,104,105,99,104,32,105,110,32,116,117,114,110,32,105,115,32,110,111,116,32,112,114,101,99,101,100,101,100,32,98,121,32,34,102,111,111,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,40,63,60,33,102,111,111,41,98,97,114,41,98,97,122>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,102,111,111,34,32,112,114,101,99,101,100,101,100,32,98,121,32,116,104,114,101,101,32,100,105,103,105,116,115,32,97,110,100,32,97,110,121,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,34,57,57,57,34,58>>]},{pre,[],[{code,[],[<<40,63,60,61,92,100,123,51,125,40,63,33,57,57,57,41,46,46,46,41,102,111,111>>]}]},{a,[{id,<<115,101,99,116,49,56>>}],[]},{h2,[],[<<67,111,110,100,105,116,105,111,110,97,108,32,83,117,98,112,97,116,116,101,114,110,115>>]},{p,[],[<<73,116,32,105,115,32,112,111,115,115,105,98,108,101,32,116,111,32,99,97,117,115,101,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,32,116,111,32,111,98,101,121,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,111,110,100,105,116,105,111,110,97,108,108,121,32,111,114,32,116,111,32,99,104,111,111,115,101,32,98,101,116,119,101,101,110,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,32,115,117,98,112,97,116,116,101,114,110,115,44,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,110,32,97,115,115,101,114,116,105,111,110,44,32,111,114,32,119,104,101,116,104,101,114,32,97,32,115,112,101,99,105,102,105,99,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,97,108,114,101,97,100,121,32,98,101,101,110,32,109,97,116,99,104,101,100,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,116,119,111,32,112,111,115,115,105,98,108,101,32,102,111,114,109,115,32,111,102,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,63,40,99,111,110,100,105,116,105,111,110,41,121,101,115,45,112,97,116,116,101,114,110,41,10,40,63,40,99,111,110,100,105,116,105,111,110,41,121,101,115,45,112,97,116,116,101,114,110,124,110,111,45,112,97,116,116,101,114,110,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,115,97,116,105,115,102,105,101,100,44,32,116,104,101,32,121,101,115,45,112,97,116,116,101,114,110,32,105,115,32,117,115,101,100,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,110,111,45,112,97,116,116,101,114,110,32,40,105,102,32,112,114,101,115,101,110,116,41,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,101,120,105,115,116,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,69,97,99,104,32,111,102,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,99,97,110,32,105,116,115,101,108,102,32,99,111,110,116,97,105,110,32,110,101,115,116,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,97,110,121,32,102,111,114,109,44,32,105,110,99,108,117,100,105,110,103,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,115,59,32,116,104,101,32,114,101,115,116,114,105,99,116,105,111,110,32,116,111,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,112,112,108,105,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,108,101,118,101,108,32,111,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,32,105,115,32,97,110,32,101,120,97,109,112,108,101,32,119,104,101,114,101,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,114,101,32,99,111,109,112,108,101,120,58>>]},{pre,[],[{code,[],[<<40,63,40,49,41,32,40,65,124,66,124,67,41,32,124,32,40,68,32,124,32,40,63,40,50,41,69,124,70,41,32,124,32,69,41,32,41>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,102,111,117,114,32,107,105,110,100,115,32,111,102,32,99,111,110,100,105,116,105,111,110,58,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,115,117,98,112,97,116,116,101,114,110,115,44,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,114,101,99,117,114,115,105,111,110,44,32,97,32,112,115,101,117,100,111,45,99,111,110,100,105,116,105,111,110,32,99,97,108,108,101,100,32,68,69,70,73,78,69,44,32,97,110,100,32,97,115,115,101,114,116,105,111,110,115,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,97,32,85,115,101,100,32,83,117,98,112,97,116,116,101,114,110,32,66,121,32,78,117,109,98,101,114>>]}]},{p,[],[<<73,102,32,116,104,101,32,116,101,120,116,32,98,101,116,119,101,101,110,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,99,111,110,115,105,115,116,115,32,111,102,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,100,105,103,105,116,115,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,97,116,32,110,117,109,98,101,114,32,104,97,115,32,112,114,101,118,105,111,117,115,108,121,32,109,97,116,99,104,101,100,46,32,73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,32,101,120,105,115,116,115,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,115,101,99,116,49,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<68,117,112,108,105,99,97,116,101,32,83,117,98,112,97,116,116,101,114,110,32,78,117,109,98,101,114,115>>]},<<32,101,97,114,108,105,101,114,41,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,102,32,116,104,101,109,32,104,97,118,101,32,109,97,116,99,104,101,100,46,32,65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,110,111,116,97,116,105,111,110,32,105,115,32,116,111,32,112,114,101,99,101,100,101,32,116,104,101,32,100,105,103,105,116,115,32,119,105,116,104,32,97,32,112,108,117,115,32,111,114,32,109,105,110,117,115,32,115,105,103,110,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,110,117,109,98,101,114,32,105,115,32,114,101,108,97,116,105,118,101,32,114,97,116,104,101,114,32,116,104,97,110,32,97,98,115,111,108,117,116,101,46,32,84,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,98,121,32,40,63,40,45,49,41,44,32,116,104,101,32,110,101,120,116,32,109,111,115,116,32,114,101,99,101,110,116,32,98,121,32,40,63,40,45,50,41,44,32,97,110,100,32,115,111,32,111,110,46,32,73,110,115,105,100,101,32,108,111,111,112,115,44,32,105,116,32,99,97,110,32,97,108,115,111,32,109,97,107,101,32,115,101,110,115,101,32,116,111,32,114,101,102,101,114,32,116,111,32,115,117,98,115,101,113,117,101,110,116,32,103,114,111,117,112,115,46,32,84,104,101,32,110,101,120,116,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,98,101,32,111,112,101,110,101,100,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,97,115,32,40,63,40,43,49,41,44,32,97,110,100,32,115,111,32,111,110,46,32,40,84,104,101,32,118,97,108,117,101,32,122,101,114,111,32,105,110,32,97,110,121,32,111,102,32,116,104,101,115,101,32,102,111,114,109,115,32,105,115,32,110,111,116,32,117,115,101,100,59,32,105,116,32,112,114,111,118,111,107,101,115,32,97,32,99,111,109,112,105,108,101,45,116,105,109,101,32,101,114,114,111,114,46,41>>]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,99,111,110,116,97,105,110,115,32,110,111,110,45,115,105,103,110,105,102,105,99,97,110,116,32,119,104,105,116,101,115,112,97,99,101,32,116,111,32,109,97,107,101,32,105,116,32,109,111,114,101,32,114,101,97,100,97,98,108,101,32,40,97,115,115,117,109,101,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<41,32,97,110,100,32,116,111,32,100,105,118,105,100,101,32,105,116,32,105,110,116,111,32,116,104,114,101,101,32,112,97,114,116,115,32,102,111,114,32,101,97,115,101,32,111,102,32,100,105,115,99,117,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<40,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,49,41,32,92,41,32,41>>]}]},{p,[],[<<84,104,101,32,102,105,114,115,116,32,112,97,114,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,116,105,111,110,97,108,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,44,32,97,110,100,32,105,102,32,116,104,97,116,32,99,104,97,114,97,99,116,101,114,32,105,115,32,112,114,101,115,101,110,116,44,32,115,101,116,115,32,105,116,32,97,115,32,116,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,46,32,84,104,101,32,115,101,99,111,110,100,32,112,97,114,116,32,109,97,116,99,104,101,115,32,111,110,101,32,111,114,32,109,111,114,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,97,114,101,110,116,104,101,115,101,115,46,32,84,104,101,32,116,104,105,114,100,32,112,97,114,116,32,105,115,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,116,101,115,116,115,32,119,104,101,116,104,101,114,32,116,104,101,32,102,105,114,115,116,32,115,101,116,32,111,102,32,112,97,114,101,110,116,104,101,115,101,115,32,109,97,116,99,104,101,100,32,111,114,32,110,111,116,46,32,73,102,32,116,104,101,121,32,100,105,100,44,32,116,104,97,116,32,105,115,44,32,105,102,32,115,117,98,106,101,99,116,32,115,116,97,114,116,101,100,32,119,105,116,104,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,44,32,97,110,100,32,115,111,32,116,104,101,32,121,101,115,45,112,97,116,116,101,114,110,32,105,115,32,101,120,101,99,117,116,101,100,32,97,110,100,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,114,101,113,117,105,114,101,100,46,32,79,116,104,101,114,119,105,115,101,44,32,97,115,32,110,111,45,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,44,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,110,111,116,104,105,110,103,46,32,84,104,97,116,32,105,115,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,44,32,111,112,116,105,111,110,97,108,108,121,32,101,110,99,108,111,115,101,100,32,105,110,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,105,115,32,112,97,116,116,101,114,110,32,105,115,32,101,109,98,101,100,100,101,100,32,105,110,32,97,32,108,97,114,103,101,114,32,111,110,101,44,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,117,115,101,100,58>>]},{pre,[],[{code,[],[<<46,46,46,111,116,104,101,114,32,115,116,117,102,102,46,46,46,32,40,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,45,49,41,32,92,41,32,41,32,46,46,46>>]}]},{p,[],[<<84,104,105,115,32,109,97,107,101,115,32,116,104,101,32,102,114,97,103,109,101,110,116,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,97,32,85,115,101,100,32,83,117,98,112,97,116,116,101,114,110,32,66,121,32,78,97,109,101>>]}]},{p,[],[<<80,101,114,108,32,117,115,101,115,32,116,104,101,32,115,121,110,116,97,120,32,40,63,40,60,110,97,109,101,62,41,46,46,46,41,32,111,114,32,40,63,40,39,110,97,109,101,39,41,46,46,46,41,32,116,111,32,116,101,115,116,32,102,111,114,32,97,32,117,115,101,100,32,115,117,98,112,97,116,116,101,114,110,32,98,121,32,110,97,109,101,46,32,70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,101,97,114,108,105,101,114,32,118,101,114,115,105,111,110,115,32,111,102,32,80,67,82,69,44,32,119,104,105,99,104,32,104,97,100,32,116,104,105,115,32,102,97,99,105,108,105,116,121,32,98,101,102,111,114,101,32,80,101,114,108,44,32,116,104,101,32,115,121,110,116,97,120,32,40,63,40,110,97,109,101,41,46,46,46,41,32,105,115,32,97,108,115,111,32,114,101,99,111,103,110,105,122,101,100,46>>]},{p,[],[<<82,101,119,114,105,116,105,110,103,32,116,104,101,32,112,114,101,118,105,111,117,115,32,101,120,97,109,112,108,101,32,116,111,32,117,115,101,32,97,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,32,103,105,118,101,115,58>>]},{pre,[],[{code,[],[<<40,63,60,79,80,69,78,62,32,92,40,32,41,63,32,32,32,32,91,94,40,41,93,43,32,32,32,32,40,63,40,60,79,80,69,78,62,41,32,92,41,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,110,97,109,101,32,117,115,101,100,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,32,111,102,32,116,104,105,115,32,107,105,110,100,32,105,115,32,97,32,100,117,112,108,105,99,97,116,101,44,32,116,104,101,32,116,101,115,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,108,108,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,97,110,100,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,110,101,32,111,102,32,116,104,101,109,32,104,97,115,32,109,97,116,99,104,101,100,46>>]},{p,[],[{em,[],[<<67,104,101,99,107,105,110,103,32,102,111,114,32,80,97,116,116,101,114,110,32,82,101,99,117,114,115,105,111,110>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,104,101,32,115,116,114,105,110,103,32,40,82,41,44,32,97,110,100,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32,82,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,97,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,116,111,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,32,111,114,32,97,110,121,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,98,101,101,110,32,109,97,100,101,46,32,73,102,32,100,105,103,105,116,115,32,111,114,32,97,32,110,97,109,101,32,112,114,101,99,101,100,101,100,32,98,121,32,97,109,112,101,114,115,97,110,100,32,102,111,108,108,111,119,32,116,104,101,32,108,101,116,116,101,114,32,82,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,63,40,82,51,41,46,46,46,41,32,111,114,32,40,63,40,82,38,110,97,109,101,41,46,46,46,41>>]}]},{p,[],[<<116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,114,117,101,32,105,102,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,114,101,99,117,114,115,105,111,110,32,105,115,32,105,110,116,111,32,97,32,115,117,98,112,97,116,116,101,114,110,32,119,104,111,115,101,32,110,117,109,98,101,114,32,111,114,32,110,97,109,101,32,105,115,32,103,105,118,101,110,46,32,84,104,105,115,32,99,111,110,100,105,116,105,111,110,32,100,111,101,115,32,110,111,116,32,99,104,101,99,107,32,116,104,101,32,101,110,116,105,114,101,32,114,101,99,117,114,115,105,111,110,32,115,116,97,99,107,46,32,73,102,32,116,104,101,32,110,97,109,101,32,117,115,101,100,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,32,111,102,32,116,104,105,115,32,107,105,110,100,32,105,115,32,97,32,100,117,112,108,105,99,97,116,101,44,32,116,104,101,32,116,101,115,116,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,108,108,32,115,117,98,112,97,116,116,101,114,110,115,32,111,102,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,97,110,100,32,105,115,32,116,114,117,101,32,105,102,32,97,110,121,32,111,110,101,32,111,102,32,116,104,101,109,32,105,115,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,114,101,99,117,114,115,105,111,110,46>>]},{p,[],[<<65,116,32,34,116,111,112,45,108,101,118,101,108,34,44,32,97,108,108,32,116,104,101,115,101,32,114,101,99,117,114,115,105,111,110,32,116,101,115,116,32,99,111,110,100,105,116,105,111,110,115,32,97,114,101,32,102,97,108,115,101,46,32,84,104,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,99,117,114,115,105,118,101,32,112,97,116,116,101,114,110,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]},{p,[],[{em,[],[<<68,101,102,105,110,105,110,103,32,83,117,98,112,97,116,116,101,114,110,115,32,102,111,114,32,85,115,101,32,66,121,32,82,101,102,101,114,101,110,99,101,32,79,110,108,121>>]}]},{a,[{id,<<100,101,102,105,110,105,110,103,95,115,117,98,112,97,116,116,101,114,110,115>>}],[]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,116,104,101,32,115,116,114,105,110,103,32,40,68,69,70,73,78,69,41,44,32,97,110,100,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,110,97,109,101,32,68,69,70,73,78,69,44,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,97,108,119,97,121,115,32,102,97,108,115,101,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,114,101,32,99,97,110,32,98,101,32,111,110,108,121,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,46,32,73,116,32,105,115,32,97,108,119,97,121,115,32,115,107,105,112,112,101,100,32,105,102,32,99,111,110,116,114,111,108,32,114,101,97,99,104,101,115,32,116,104,105,115,32,112,111,105,110,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,32,105,100,101,97,32,111,102,32,68,69,70,73,78,69,32,105,115,32,116,104,97,116,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,100,101,102,105,110,101,32,34,115,117,98,114,111,117,116,105,110,101,115,34,32,116,104,97,116,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,32,102,114,111,109,32,101,108,115,101,119,104,101,114,101,46,32,40,84,104,101,32,117,115,101,32,111,102,32,115,117,98,114,111,117,116,105,110,101,115,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46,41,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,32,112,97,116,116,101,114,110,32,116,111,32,109,97,116,99,104,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,44,32,115,117,99,104,32,97,115,32,34,49,57,50,46,49,54,56,46,50,51,46,50,52,53,34,44,32,99,97,110,32,98,101,32,119,114,105,116,116,101,110,32,108,105,107,101,32,116,104,105,115,32,40,105,103,110,111,114,101,32,119,104,105,116,101,115,112,97,99,101,32,97,110,100,32,108,105,110,101,32,98,114,101,97,107,115,41,58>>]},{pre,[],[{code,[],[<<40,63,40,68,69,70,73,78,69,41,32,40,63,60,98,121,116,101,62,32,50,91,48,45,52,93,92,100,32,124,32,50,53,91,48,45,53,93,32,124,32,49,92,100,92,100,32,124,32,91,49,45,57,93,63,92,100,41,32,41,32,92,98,32,40,63,38,98,121,116,101,41,32,40,92,46,40,63,38,98,121,116,101,41,41,123,51,125,32,92,98>>]}]},{p,[],[<<84,104,101,32,102,105,114,115,116,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,32,68,69,70,73,78,69,32,103,114,111,117,112,32,105,110,115,105,100,101,32,119,104,105,99,104,32,105,115,32,97,32,97,110,111,116,104,101,114,32,103,114,111,117,112,32,110,97,109,101,100,32,34,98,121,116,101,34,32,105,115,32,100,101,102,105,110,101,100,46,32,84,104,105,115,32,109,97,116,99,104,101,115,32,97,110,32,105,110,100,105,118,105,100,117,97,108,32,99,111,109,112,111,110,101,110,116,32,111,102,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,32,40,97,32,110,117,109,98,101,114,32,60,32,50,53,54,41,46,32,87,104,101,110,32,109,97,116,99,104,105,110,103,32,116,97,107,101,115,32,112,108,97,99,101,44,32,116,104,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,107,105,112,112,101,100,44,32,97,115,32,68,69,70,73,78,69,32,97,99,116,115,32,108,105,107,101,32,97,32,102,97,108,115,101,32,99,111,110,100,105,116,105,111,110,46,32,84,104,101,32,114,101,109,97,105,110,105,110,103,32,112,97,116,116,101,114,110,32,117,115,101,115,32,114,101,102,101,114,101,110,99,101,115,32,116,111,32,116,104,101,32,110,97,109,101,100,32,103,114,111,117,112,32,116,111,32,109,97,116,99,104,32,116,104,101,32,102,111,117,114,32,100,111,116,45,115,101,112,97,114,97,116,101,100,32,99,111,109,112,111,110,101,110,116,115,32,111,102,32,97,110,32,73,80,118,52,32,97,100,100,114,101,115,115,44,32,105,110,115,105,115,116,105,110,103,32,111,110,32,97,32,119,111,114,100,32,98,111,117,110,100,97,114,121,32,97,116,32,101,97,99,104,32,101,110,100,46>>]},{p,[],[{em,[],[<<65,115,115,101,114,116,105,111,110,32,67,111,110,100,105,116,105,111,110,115>>]}]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,110,111,116,32,105,110,32,97,110,121,32,111,102,32,116,104,101,32,97,98,111,118,101,32,102,111,114,109,97,116,115,44,32,105,116,32,109,117,115,116,32,98,101,32,97,110,32,97,115,115,101,114,116,105,111,110,46,32,84,104,105,115,32,99,97,110,32,98,101,32,97,32,112,111,115,105,116,105,118,101,32,111,114,32,110,101,103,97,116,105,118,101,32,108,111,111,107,97,104,101,97,100,32,111,114,32,108,111,111,107,98,101,104,105,110,100,32,97,115,115,101,114,116,105,111,110,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,99,111,110,116,97,105,110,105,110,103,32,110,111,110,45,115,105,103,110,105,102,105,99,97,110,116,32,119,104,105,116,101,115,112,97,99,101,44,32,97,110,100,32,119,105,116,104,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,111,110,32,116,104,101,32,115,101,99,111,110,100,32,108,105,110,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<40,63,40,63,61,91,94,97,45,122,93,42,91,97,45,122,93,41,10,92,100,123,50,125,45,91,97,45,122,93,123,51,125,45,92,100,123,50,125,32,32,124,32,32,92,100,123,50,125,45,92,100,123,50,125,45,92,100,123,50,125,32,41>>]}]},{p,[],[<<84,104,101,32,99,111,110,100,105,116,105,111,110,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,108,111,111,107,97,104,101,97,100,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,116,105,111,110,97,108,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,108,101,116,116,101,114,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,108,101,116,116,101,114,46,32,84,104,97,116,32,105,115,44,32,105,116,32,116,101,115,116,115,32,102,111,114,32,116,104,101,32,112,114,101,115,101,110,99,101,32,111,102,32,97,116,32,108,101,97,115,116,32,111,110,101,32,108,101,116,116,101,114,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,73,102,32,97,32,108,101,116,116,101,114,32,105,115,32,102,111,117,110,100,44,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,105,114,115,116,32,97,108,116,101,114,110,97,116,105,118,101,44,32,111,116,104,101,114,119,105,115,101,32,105,116,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,115,101,99,111,110,100,46,32,84,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,115,116,114,105,110,103,115,32,105,110,32,111,110,101,32,111,102,32,116,104,101,32,116,119,111,32,102,111,114,109,115,32,100,100,45,97,97,97,45,100,100,32,111,114,32,100,100,45,100,100,45,100,100,44,32,119,104,101,114,101,32,97,97,97,32,97,114,101,32,108,101,116,116,101,114,115,32,97,110,100,32,100,100,32,97,114,101,32,100,105,103,105,116,115,46>>]},{a,[{id,<<115,101,99,116,49,57>>}],[]},{h2,[],[<<67,111,109,109,101,110,116,115>>]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,116,119,111,32,119,97,121,115,32,116,111,32,105,110,99,108,117,100,101,32,99,111,109,109,101,110,116,115,32,105,110,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,112,114,111,99,101,115,115,101,100,32,98,121,32,80,67,82,69,46,32,73,110,32,98,111,116,104,32,99,97,115,101,115,44,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,99,111,109,109,101,110,116,32,109,117,115,116,32,110,111,116,32,98,101,32,105,110,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,44,32,111,114,32,105,110,32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,97,110,121,32,111,116,104,101,114,32,115,101,113,117,101,110,99,101,32,111,102,32,114,101,108,97,116,101,100,32,99,104,97,114,97,99,116,101,114,115,32,115,117,99,104,32,97,115,32,40,63,58,32,111,114,32,97,32,115,117,98,112,97,116,116,101,114,110,32,110,97,109,101,32,111,114,32,110,117,109,98,101,114,46,32,84,104,101,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,109,97,107,101,32,117,112,32,97,32,99,111,109,109,101,110,116,32,112,108,97,121,32,110,111,32,112,97,114,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,105,110,103,46>>]},{p,[],[<<84,104,101,32,115,101,113,117,101,110,99,101,32,40,63,35,32,109,97,114,107,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,99,111,109,109,101,110,116,32,116,104,97,116,32,99,111,110,116,105,110,117,101,115,32,117,112,32,116,111,32,116,104,101,32,110,101,120,116,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,78,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,110,111,116,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,111,112,116,105,111,110,32,80,67,82,69,95,69,88,84,69,78,68,69,68,32,105,115,32,115,101,116,44,32,97,110,32,117,110,101,115,99,97,112,101,100,32,35,32,99,104,97,114,97,99,116,101,114,32,97,108,115,111,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,111,109,109,101,110,116,44,32,119,104,105,99,104,32,105,110,32,116,104,105,115,32,99,97,115,101,32,99,111,110,116,105,110,117,101,115,32,116,111,32,105,109,109,101,100,105,97,116,101,108,121,32,97,102,116,101,114,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,32,111,114,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,87,104,105,99,104,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,110,101,119,108,105,110,101,115,32,105,115,32,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,32,111,112,116,105,111,110,115,32,112,97,115,115,101,100,32,116,111,32,97,32,99,111,109,112,105,108,105,110,103,32,102,117,110,99,116,105,111,110,32,111,114,32,98,121,32,97,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,110,101,119,108,105,110,101,95,99,111,110,118,101,110,116,105,111,110,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<78,101,119,108,105,110,101,32,67,111,110,118,101,110,116,105,111,110,115>>]},<<32,101,97,114,108,105,101,114,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,105,115,32,116,121,112,101,32,111,102,32,99,111,109,109,101,110,116,32,105,115,32,97,32,108,105,116,101,114,97,108,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,59,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,115,32,116,104,97,116,32,104,97,112,112,101,110,32,116,111,32,114,101,112,114,101,115,101,110,116,32,97,32,110,101,119,108,105,110,101,32,100,111,32,110,111,116,32,99,111,117,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,119,104,101,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,44,32,97,110,100,32,116,104,101,32,100,101,102,97,117,108,116,32,110,101,119,108,105,110,101,32,99,111,110,118,101,110,116,105,111,110,32,105,115,32,105,110,32,102,111,114,99,101,58>>]},{pre,[],[{code,[],[<<97,98,99,32,35,99,111,109,109,101,110,116,32,92,110,32,115,116,105,108,108,32,99,111,109,109,101,110,116>>]}]},{p,[],[<<79,110,32,101,110,99,111,117,110,116,101,114,105,110,103,32,99,104,97,114,97,99,116,101,114,32,35,44,32>>,{code,[],[<<112,99,114,101,95,99,111,109,112,105,108,101,40,41>>]},<<32,115,107,105,112,115,32,97,108,111,110,103,44,32,108,111,111,107,105,110,103,32,102,111,114,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,84,104,101,32,115,101,113,117,101,110,99,101,32,92,110,32,105,115,32,115,116,105,108,108,32,108,105,116,101,114,97,108,32,97,116,32,116,104,105,115,32,115,116,97,103,101,44,32,115,111,32,105,116,32,100,111,101,115,32,110,111,116,32,116,101,114,109,105,110,97,116,101,32,116,104,101,32,99,111,109,109,101,110,116,46,32,79,110,108,121,32,97,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104,32,99,111,100,101,32,118,97,108,117,101,32,48,120,48,97,32,40,116,104,101,32,100,101,102,97,117,108,116,32,110,101,119,108,105,110,101,41,32,100,111,101,115,32,115,111,46>>]},{a,[{id,<<115,101,99,116,50,48>>}],[]},{h2,[],[<<82,101,99,117,114,115,105,118,101,32,80,97,116,116,101,114,110,115>>]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,112,114,111,98,108,101,109,32,111,102,32,109,97,116,99,104,105,110,103,32,97,32,115,116,114,105,110,103,32,105,110,32,112,97,114,101,110,116,104,101,115,101,115,44,32,97,108,108,111,119,105,110,103,32,102,111,114,32,117,110,108,105,109,105,116,101,100,32,110,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,46,32,87,105,116,104,111,117,116,32,116,104,101,32,117,115,101,32,111,102,32,114,101,99,117,114,115,105,111,110,44,32,116,104,101,32,98,101,115,116,32,116,104,97,116,32,99,97,110,32,98,101,32,100,111,110,101,32,105,115,32,116,111,32,117,115,101,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,117,112,32,116,111,32,115,111,109,101,32,102,105,120,101,100,32,100,101,112,116,104,32,111,102,32,110,101,115,116,105,110,103,46,32,73,116,32,105,115,32,110,111,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,110,100,108,101,32,97,110,32,97,114,98,105,116,114,97,114,121,32,110,101,115,116,105,110,103,32,100,101,112,116,104,46>>]},{p,[],[<<70,111,114,32,115,111,109,101,32,116,105,109,101,44,32,80,101,114,108,32,104,97,115,32,112,114,111,118,105,100,101,100,32,97,32,102,97,99,105,108,105,116,121,32,116,104,97,116,32,97,108,108,111,119,115,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,115,32,116,111,32,114,101,99,117,114,115,101,32,40,97,109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,41,46,32,73,116,32,100,111,101,115,32,116,104,105,115,32,98,121,32,105,110,116,101,114,112,111,108,97,116,105,110,103,32,80,101,114,108,32,99,111,100,101,32,105,110,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,97,116,32,114,117,110,116,105,109,101,44,32,97,110,100,32,116,104,101,32,99,111,100,101,32,99,97,110,32,114,101,102,101,114,32,116,111,32,116,104,101,32,101,120,112,114,101,115,115,105,111,110,32,105,116,115,101,108,102,46,32,65,32,80,101,114,108,32,112,97,116,116,101,114,110,32,117,115,105,110,103,32,99,111,100,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,116,111,32,115,111,108,118,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,111,98,108,101,109,32,99,97,110,32,98,101,32,99,114,101,97,116,101,100,32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<36,114,101,32,61,32,113,114,123,92,40,32,40,63,58,32,40,63,62,91,94,40,41,93,43,41,32,124,32,40,63,112,123,36,114,101,125,41,32,41,42,32,92,41,125,120,59>>]}]},{p,[],[<<73,116,101,109,32,40,63,112,123,46,46,46,125,41,32,105,110,116,101,114,112,111,108,97,116,101,115,32,80,101,114,108,32,99,111,100,101,32,97,116,32,114,117,110,116,105,109,101,44,32,97,110,100,32,105,110,32,116,104,105,115,32,99,97,115,101,32,114,101,102,101,114,115,32,114,101,99,117,114,115,105,118,101,108,121,32,116,111,32,116,104,101,32,112,97,116,116,101,114,110,32,105,110,32,119,104,105,99,104,32,105,116,32,97,112,112,101,97,114,115,46>>]},{p,[],[<<79,98,118,105,111,117,115,108,121,44,32,80,67,82,69,32,99,97,110,110,111,116,32,115,117,112,112,111,114,116,32,116,104,101,32,105,110,116,101,114,112,111,108,97,116,105,111,110,32,111,102,32,80,101,114,108,32,99,111,100,101,46,32,73,110,115,116,101,97,100,44,32,105,116,32,115,117,112,112,111,114,116,115,32,115,112,101,99,105,97,108,32,115,121,110,116,97,120,32,102,111,114,32,114,101,99,117,114,115,105,111,110,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,102,111,114,32,105,110,100,105,118,105,100,117,97,108,32,115,117,98,112,97,116,116,101,114,110,32,114,101,99,117,114,115,105,111,110,46,32,65,102,116,101,114,32,105,116,115,32,105,110,116,114,111,100,117,99,116,105,111,110,32,105,110,32,80,67,82,69,32,97,110,100,32,80,121,116,104,111,110,44,32,116,104,105,115,32,107,105,110,100,32,111,102,32,114,101,99,117,114,115,105,111,110,32,119,97,115,32,108,97,116,101,114,32,105,110,116,114,111,100,117,99,101,100,32,105,110,116,111,32,80,101,114,108,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,48,46>>]},{p,[],[<<65,32,115,112,101,99,105,97,108,32,105,116,101,109,32,116,104,97,116,32,99,111,110,115,105,115,116,115,32,111,102,32,40,63,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,117,109,98,101,114,32,62,32,48,32,97,110,100,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,115,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,111,102,32,116,104,101,32,103,105,118,101,110,32,110,117,109,98,101,114,44,32,105,102,32,105,116,32,111,99,99,117,114,115,32,105,110,115,105,100,101,32,116,104,97,116,32,115,117,98,112,97,116,116,101,114,110,46,32,40,73,102,32,110,111,116,44,32,105,116,32,105,115,32,97,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,44,32,119,104,105,99,104,32,105,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46,41,32,84,104,101,32,115,112,101,99,105,97,108,32,105,116,101,109,32,40,63,82,41,32,111,114,32,40,63,48,41,32,105,115,32,97,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,105,115,32,80,67,82,69,32,112,97,116,116,101,114,110,32,115,111,108,118,101,115,32,116,104,101,32,110,101,115,116,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,111,98,108,101,109,32,40,97,115,115,117,109,101,32,116,104,97,116,32,111,112,116,105,111,110,32>>,{code,[],[<<101,120,116,101,110,100,101,100>>]},<<32,105,115,32,115,101,116,32,115,111,32,116,104,97,116,32,119,104,105,116,101,115,112,97,99,101,32,105,115,32,105,103,110,111,114,101,100,41,58>>]},{pre,[],[{code,[],[<<92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,82,41,32,41,42,32,92,41>>]}]},{p,[],[<<70,105,114,115,116,32,105,116,32,109,97,116,99,104,101,115,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,84,104,101,110,32,105,116,32,109,97,116,99,104,101,115,32,97,110,121,32,110,117,109,98,101,114,32,111,102,32,115,117,98,115,116,114,105,110,103,115,44,32,119,104,105,99,104,32,99,97,110,32,101,105,116,104,101,114,32,98,101,32,97,32,115,101,113,117,101,110,99,101,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,32,111,114,32,97,32,114,101,99,117,114,115,105,118,101,32,109,97,116,99,104,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,115,101,108,102,32,40,116,104,97,116,32,105,115,44,32,97,32,99,111,114,114,101,99,116,108,121,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,115,116,114,105,110,103,41,46,32,70,105,110,97,108,108,121,32,116,104,101,114,101,32,105,115,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,78,111,116,105,99,101,32,116,104,101,32,117,115,101,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,116,111,32,97,118,111,105,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,116,104,105,115,32,119,97,115,32,112,97,114,116,32,111,102,32,97,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,44,32,121,111,117,32,119,111,117,108,100,32,110,111,116,32,119,97,110,116,32,116,111,32,114,101,99,117,114,115,101,32,116,104,101,32,101,110,116,105,114,101,32,112,97,116,116,101,114,110,44,32,115,111,32,105,110,115,116,101,97,100,32,121,111,117,32,99,97,110,32,117,115,101,58>>]},{pre,[],[{code,[],[<<40,32,92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,49,41,32,41,42,32,92,41,32,41>>]}]},{p,[],[<<84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,104,101,114,101,32,119,105,116,104,105,110,32,112,97,114,101,110,116,104,101,115,101,115,32,115,111,32,116,104,97,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,114,101,102,101,114,115,32,116,111,32,116,104,101,109,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<73,110,32,97,32,108,97,114,103,101,114,32,112,97,116,116,101,114,110,44,32,107,101,101,112,105,110,103,32,116,114,97,99,107,32,111,102,32,112,97,114,101,110,116,104,101,115,105,115,32,110,117,109,98,101,114,115,32,99,97,110,32,98,101,32,116,114,105,99,107,121,46,32,84,104,105,115,32,105,115,32,109,97,100,101,32,101,97,115,105,101,114,32,98,121,32,116,104,101,32,117,115,101,32,111,102,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,115,46,32,73,110,115,116,101,97,100,32,111,102,32,40,63,49,41,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,97,98,111,118,101,44,32,121,111,117,32,99,97,110,32,119,114,105,116,101,32,40,63,45,50,41,32,116,111,32,114,101,102,101,114,32,116,111,32,116,104,101,32,115,101,99,111,110,100,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,112,114,101,99,101,100,105,110,103,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,32,84,104,97,116,32,105,115,44,32,97,32,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,99,111,117,110,116,115,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,108,101,102,116,119,97,114,100,115,32,102,114,111,109,32,116,104,101,32,112,111,105,110,116,32,97,116,32,119,104,105,99,104,32,105,116,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{p,[],[<<73,116,32,105,115,32,97,108,115,111,32,112,111,115,115,105,98,108,101,32,116,111,32,114,101,102,101,114,32,116,111,32,108,97,116,101,114,32,111,112,101,110,101,100,32,112,97,114,101,110,116,104,101,115,101,115,44,32,98,121,32,119,114,105,116,105,110,103,32,114,101,102,101,114,101,110,99,101,115,32,115,117,99,104,32,97,115,32,40,63,43,50,41,46,32,72,111,119,101,118,101,114,44,32,116,104,101,115,101,32,99,97,110,110,111,116,32,98,101,32,114,101,99,117,114,115,105,118,101,44,32,97,115,32,116,104,101,32,114,101,102,101,114,101,110,99,101,32,105,115,32,110,111,116,32,105,110,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,114,101,102,101,114,101,110,99,101,100,46,32,84,104,101,121,32,97,114,101,32,97,108,119,97,121,115,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,44,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,46>>]},{p,[],[<<65,110,32,97,108,116,101,114,110,97,116,105,118,101,32,97,112,112,114,111,97,99,104,32,105,115,32,116,111,32,117,115,101,32,110,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,115,116,101,97,100,46,32,84,104,101,32,80,101,114,108,32,115,121,110,116,97,120,32,102,111,114,32,116,104,105,115,32,105,115,32,40,63,38,110,97,109,101,41,46,32,84,104,101,32,101,97,114,108,105,101,114,32,80,67,82,69,32,115,121,110,116,97,120,32,40,63,80,62,110,97,109,101,41,32,105,115,32,97,108,115,111,32,115,117,112,112,111,114,116,101,100,46,32,87,101,32,99,97,110,32,114,101,119,114,105,116,101,32,116,104,101,32,97,98,111,118,101,32,101,120,97,109,112,108,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{pre,[],[{code,[],[<<40,63,60,112,110,62,32,92,40,32,40,32,91,94,40,41,93,43,43,32,124,32,40,63,38,112,110,41,32,41,42,32,92,41,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,114,101,32,105,115,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,110,97,109,101,44,32,116,104,101,32,101,97,114,108,105,101,115,116,32,111,110,101,32,105,115,32,117,115,101,100,46>>]},{p,[],[<<84,104,105,115,32,112,97,114,116,105,99,117,108,97,114,32,101,120,97,109,112,108,101,32,112,97,116,116,101,114,110,32,116,104,97,116,32,119,101,32,104,97,118,101,32,115,116,117,100,105,101,100,32,99,111,110,116,97,105,110,115,32,110,101,115,116,101,100,32,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,44,32,97,110,100,32,115,111,32,116,104,101,32,117,115,101,32,111,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,102,111,114,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,115,32,111,102,32,110,111,110,45,112,97,114,101,110,116,104,101,115,101,115,32,105,115,32,105,109,112,111,114,116,97,110,116,32,119,104,101,110,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,115,116,114,105,110,103,115,32,116,104,97,116,32,100,111,32,110,111,116,32,109,97,116,99,104,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,119,104,101,110,32,116,104,105,115,32,112,97,116,116,101,114,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111>>]},{pre,[],[{code,[],[<<40,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,40,41>>]}]},{p,[],[<<105,116,32,103,105,118,101,115,32,34,110,111,32,109,97,116,99,104,34,32,113,117,105,99,107,108,121,46,32,72,111,119,101,118,101,114,44,32,105,102,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,105,115,32,110,111,116,32,117,115,101,100,44,32,116,104,101,32,109,97,116,99,104,32,114,117,110,115,32,102,111,114,32,97,32,108,111,110,103,32,116,105,109,101,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,115,111,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,119,97,121,115,32,116,104,101,32,43,32,97,110,100,32,42,32,114,101,112,101,97,116,115,32,99,97,110,32,99,97,114,118,101,32,117,112,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,110,100,32,97,108,108,32,109,117,115,116,32,98,101,32,116,101,115,116,101,100,32,98,101,102,111,114,101,32,102,97,105,108,117,114,101,32,99,97,110,32,98,101,32,114,101,112,111,114,116,101,100,46>>]},{p,[],[<<65,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,109,97,116,99,104,44,32,116,104,101,32,118,97,108,117,101,115,32,111,102,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,116,104,111,115,101,32,102,114,111,109,32,116,104,101,32,111,117,116,101,114,109,111,115,116,32,108,101,118,101,108,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,97,98,111,118,101,32,105,115,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116>>]},{pre,[],[{code,[],[<<40,97,98,40,99,100,41,101,102,41>>]}]},{p,[],[<<116,104,101,32,118,97,108,117,101,32,102,111,114,32,116,104,101,32,105,110,110,101,114,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,40,110,117,109,98,101,114,101,100,32,50,41,32,105,115,32,34,101,102,34,44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,108,97,115,116,32,118,97,108,117,101,32,116,97,107,101,110,32,111,110,32,97,116,32,116,104,101,32,116,111,112,45,108,101,118,101,108,46,32,73,102,32,97,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,109,97,116,99,104,101,100,32,97,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,105,116,115,32,102,105,110,97,108,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,32,105,115,32,117,110,115,101,116,44,32,101,118,101,110,32,105,102,32,105,116,32,119,97,115,32,40,116,101,109,112,111,114,97,114,105,108,121,41,32,115,101,116,32,97,116,32,97,32,100,101,101,112,101,114,32,108,101,118,101,108,32,100,117,114,105,110,103,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,114,111,99,101,115,115,46>>]},{p,[],[<<68,111,32,110,111,116,32,99,111,110,102,117,115,101,32,105,116,101,109,32,40,63,82,41,32,119,105,116,104,32,99,111,110,100,105,116,105,111,110,32,40,82,41,44,32,119,104,105,99,104,32,116,101,115,116,115,32,102,111,114,32,114,101,99,117,114,115,105,111,110,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,109,97,116,99,104,101,115,32,116,101,120,116,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,44,32,97,108,108,111,119,105,110,103,32,102,111,114,32,97,114,98,105,116,114,97,114,121,32,110,101,115,116,105,110,103,46,32,79,110,108,121,32,100,105,103,105,116,115,32,97,114,101,32,97,108,108,111,119,101,100,32,105,110,32,110,101,115,116,101,100,32,98,114,97,99,107,101,116,115,32,40,116,104,97,116,32,105,115,44,32,119,104,101,110,32,114,101,99,117,114,115,105,110,103,41,44,32,119,104,105,108,101,32,97,110,121,32,99,104,97,114,97,99,116,101,114,115,32,97,114,101,32,112,101,114,109,105,116,116,101,100,32,97,116,32,116,104,101,32,111,117,116,101,114,32,108,101,118,101,108,46>>]},{pre,[],[{code,[],[<<60,32,40,63,58,32,40,63,40,82,41,32,92,100,43,43,32,32,124,32,91,94,60,62,93,42,43,41,32,124,32,40,63,82,41,41,32,42,32,62>>]}]},{p,[],[<<72,101,114,101,32,40,63,40,82,41,32,105,115,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,44,32,119,105,116,104,32,116,119,111,32,100,105,102,102,101,114,101,110,116,32,97,108,116,101,114,110,97,116,105,118,101,115,32,102,111,114,32,116,104,101,32,114,101,99,117,114,115,105,118,101,32,97,110,100,32,110,111,110,45,114,101,99,117,114,115,105,118,101,32,99,97,115,101,115,46,32,73,116,101,109,32,40,63,82,41,32,105,115,32,116,104,101,32,97,99,116,117,97,108,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,46>>]},{p,[],[{em,[],[<<68,105,102,102,101,114,101,110,99,101,115,32,105,110,32,82,101,99,117,114,115,105,111,110,32,80,114,111,99,101,115,115,105,110,103,32,98,101,116,119,101,101,110,32,80,67,82,69,32,97,110,100,32,80,101,114,108>>]}]},{p,[],[<<82,101,99,117,114,115,105,111,110,32,112,114,111,99,101,115,115,105,110,103,32,105,110,32,80,67,82,69,32,100,105,102,102,101,114,115,32,102,114,111,109,32,80,101,114,108,32,105,110,32,116,119,111,32,105,109,112,111,114,116,97,110,116,32,119,97,121,115,46,32,73,110,32,80,67,82,69,32,40,108,105,107,101,32,80,121,116,104,111,110,44,32,98,117,116,32,117,110,108,105,107,101,32,80,101,114,108,41,44,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,32,105,115,32,97,108,119,97,121,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,46,32,84,104,97,116,32,105,115,44,32,111,110,99,101,32,105,116,32,104,97,115,32,109,97,116,99,104,101,100,32,115,111,109,101,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,105,115,32,110,101,118,101,114,32,114,101,45,101,110,116,101,114,101,100,44,32,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,117,110,116,114,105,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,116,104,101,114,101,32,105,115,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,105,108,108,117,115,116,114,97,116,101,100,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,109,101,97,110,115,32,116,111,32,109,97,116,99,104,32,97,32,112,97,108,105,110,100,114,111,109,105,99,32,115,116,114,105,110,103,32,99,111,110,116,97,105,110,105,110,103,32,97,110,32,111,100,100,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,102,111,114,32,101,120,97,109,112,108,101,44,32,34,97,34,44,32,34,97,98,97,34,44,32,34,97,98,99,98,97,34,44,32,34,97,98,99,100,99,98,97,34,41,58>>]},{pre,[],[{code,[],[<<94,40,46,124,40,46,41,40,63,49,41,92,50,41,36>>]}]},{p,[],[<<84,104,101,32,105,100,101,97,32,105,115,32,116,104,97,116,32,105,116,32,101,105,116,104,101,114,32,109,97,116,99,104,101,115,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,111,114,32,116,119,111,32,105,100,101,110,116,105,99,97,108,32,99,104,97,114,97,99,116,101,114,115,32,115,117,114,114,111,117,110,100,105,110,103,32,97,32,115,117,98,112,97,108,105,110,100,114,111,109,101,46,32,73,110,32,80,101,114,108,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,119,111,114,107,115,59,32,105,110,32,80,67,82,69,32,105,116,32,100,111,101,115,32,110,111,116,32,119,111,114,107,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,108,111,110,103,101,114,32,116,104,97,110,32,116,104,114,101,101,32,99,104,97,114,97,99,116,101,114,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,34,97,98,99,98,97,34,46>>]},{p,[],[<<65,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,115,32,109,97,116,99,104,101,100,44,32,98,117,116,32,97,115,32,105,116,32,105,115,32,110,111,116,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,116,104,101,32,102,105,114,115,116,32,97,108,116,101,114,110,97,116,105,118,101,32,102,97,105,108,115,44,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,116,97,107,101,110,44,32,97,110,100,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,107,105,99,107,115,32,105,110,46,32,84,104,101,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,116,111,32,115,117,98,112,97,116,116,101,114,110,32,49,32,115,117,99,99,101,115,115,102,117,108,108,121,32,109,97,116,99,104,101,115,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,34,98,34,41,46,32,40,78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,97,110,100,32,101,110,100,32,111,102,32,108,105,110,101,32,116,101,115,116,115,32,97,114,101,32,110,111,116,32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,41>>]},{p,[],[<<66,97,99,107,32,97,116,32,116,104,101,32,116,111,112,32,108,101,118,101,108,44,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,34,99,34,41,32,105,115,32,99,111,109,112,97,114,101,100,32,119,105,116,104,32,119,104,97,116,32,115,117,98,112,97,116,116,101,114,110,32,50,32,109,97,116,99,104,101,100,44,32,119,104,105,99,104,32,119,97,115,32,34,97,34,46,32,84,104,105,115,32,102,97,105,108,115,46,32,65,115,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,105,115,32,116,114,101,97,116,101,100,32,97,115,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,44,32,116,104,101,114,101,32,97,114,101,32,110,111,119,32,110,111,32,98,97,99,107,116,114,97,99,107,105,110,103,32,112,111,105,110,116,115,44,32,97,110,100,32,115,111,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46,32,40,80,101,114,108,32,99,97,110,32,110,111,119,32,114,101,45,101,110,116,101,114,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,97,110,100,32,116,114,121,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,46,41,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,119,114,105,116,116,101,110,32,119,105,116,104,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,105,110,32,116,104,101,32,111,116,104,101,114,32,111,114,100,101,114,44,32,116,104,105,110,103,115,32,97,114,101,32,100,105,102,102,101,114,101,110,116,58>>]},{pre,[],[{code,[],[<<94,40,40,46,41,40,63,49,41,92,50,124,46,41,36>>]}]},{p,[],[<<84,104,105,115,32,116,105,109,101,44,32,116,104,101,32,114,101,99,117,114,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,116,114,105,101,100,32,102,105,114,115,116,44,32,97,110,100,32,99,111,110,116,105,110,117,101,115,32,116,111,32,114,101,99,117,114,115,101,32,117,110,116,105,108,32,105,116,32,114,117,110,115,32,111,117,116,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,97,116,32,119,104,105,99,104,32,112,111,105,110,116,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,102,97,105,108,115,46,32,66,117,116,32,116,104,105,115,32,116,105,109,101,32,119,101,32,104,97,118,101,32,97,110,111,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,116,111,32,116,114,121,32,97,116,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,46,32,84,104,97,116,32,105,115,32,116,104,101,32,115,105,103,110,105,102,105,99,97,110,116,32,100,105,102,102,101,114,101,110,99,101,58,32,105,110,32,116,104,101,32,112,114,101,118,105,111,117,115,32,99,97,115,101,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,105,115,32,97,116,32,97,32,100,101,101,112,101,114,32,114,101,99,117,114,115,105,111,110,32,108,101,118,101,108,44,32,119,104,105,99,104,32,80,67,82,69,32,99,97,110,110,111,116,32,117,115,101,46>>]},{p,[],[<<84,111,32,99,104,97,110,103,101,32,116,104,101,32,112,97,116,116,101,114,110,32,115,111,32,116,104,97,116,32,105,116,32,109,97,116,99,104,101,115,32,97,108,108,32,112,97,108,105,110,100,114,111,109,105,99,32,115,116,114,105,110,103,115,44,32,110,111,116,32,111,110,108,121,32,116,104,111,115,101,32,119,105,116,104,32,97,110,32,111,100,100,32,110,117,109,98,101,114,32,111,102,32,99,104,97,114,97,99,116,101,114,115,44,32,105,116,32,105,115,32,116,101,109,112,116,105,110,103,32,116,111,32,99,104,97,110,103,101,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<94,40,40,46,41,40,63,49,41,92,50,124,46,63,41,36>>]}]},{p,[],[<<65,103,97,105,110,44,32,116,104,105,115,32,119,111,114,107,115,32,105,110,32,80,101,114,108,44,32,98,117,116,32,110,111,116,32,105,110,32,80,67,82,69,44,32,97,110,100,32,102,111,114,32,116,104,101,32,115,97,109,101,32,114,101,97,115,111,110,46,32,87,104,101,110,32,97,32,100,101,101,112,101,114,32,114,101,99,117,114,115,105,111,110,32,104,97,115,32,109,97,116,99,104,101,100,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,101,110,116,101,114,101,100,32,97,103,97,105,110,32,116,111,32,109,97,116,99,104,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,46,32,84,104,101,32,115,111,108,117,116,105,111,110,32,105,115,32,116,111,32,115,101,112,97,114,97,116,101,32,116,104,101,32,116,119,111,32,99,97,115,101,115,44,32,97,110,100,32,119,114,105,116,101,32,111,117,116,32,116,104,101,32,111,100,100,32,97,110,100,32,101,118,101,110,32,99,97,115,101,115,32,97,115,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,116,32,116,104,101,32,104,105,103,104,101,114,32,108,101,118,101,108,58>>]},{pre,[],[{code,[],[<<94,40,63,58,40,40,46,41,40,63,49,41,92,50,124,41,124,40,40,46,41,40,63,51,41,92,52,124,46,41,41>>]}]},{p,[],[<<73,102,32,121,111,117,32,119,97,110,116,32,116,111,32,109,97,116,99,104,32,116,121,112,105,99,97,108,32,112,97,108,105,110,100,114,111,109,105,99,32,112,104,114,97,115,101,115,44,32,116,104,101,32,112,97,116,116,101,114,110,32,109,117,115,116,32,105,103,110,111,114,101,32,97,108,108,32,110,111,110,45,119,111,114,100,32,99,104,97,114,97,99,116,101,114,115,44,32,119,104,105,99,104,32,99,97,110,32,98,101,32,100,111,110,101,32,97,115,32,102,111,108,108,111,119,115,58>>]},{pre,[],[{code,[],[<<94,92,87,42,43,40,63,58,40,40,46,41,92,87,42,43,40,63,49,41,92,87,42,43,92,50,124,41,124,40,40,46,41,92,87,42,43,40,63,51,41,92,87,42,43,92,52,124,92,87,42,43,46,92,87,42,43,41,41,92,87,42,43,36>>]}]},{p,[],[<<73,102,32,114,117,110,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<99,97,115,101,108,101,115,115>>]},<<44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,112,104,114,97,115,101,115,32,115,117,99,104,32,97,115,32,34,65,32,109,97,110,44,32,97,32,112,108,97,110,44,32,97,32,99,97,110,97,108,58,32,80,97,110,97,109,97,33,34,32,97,110,100,32,105,116,32,119,111,114,107,115,32,119,101,108,108,32,105,110,32,98,111,116,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,46,32,78,111,116,105,99,101,32,116,104,101,32,117,115,101,32,111,102,32,116,104,101,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,42,43,32,116,111,32,97,118,111,105,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,115,101,113,117,101,110,99,101,115,32,111,102,32,110,111,110,45,119,111,114,100,32,99,104,97,114,97,99,116,101,114,115,46,32,87,105,116,104,111,117,116,32,116,104,105,115,44,32,80,67,82,69,32,116,97,107,101,115,32,109,117,99,104,32,108,111,110,103,101,114,32,40,49,48,32,116,105,109,101,115,32,111,114,32,109,111,114,101,41,32,116,111,32,109,97,116,99,104,32,116,121,112,105,99,97,108,32,112,104,114,97,115,101,115,44,32,97,110,100,32,80,101,114,108,32,116,97,107,101,115,32,115,111,32,108,111,110,103,32,116,104,97,116,32,121,111,117,32,116,104,105,110,107,32,105,116,32,104,97,115,32,103,111,110,101,32,105,110,116,111,32,97,32,108,111,111,112,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,112,97,108,105,110,100,114,111,109,101,45,109,97,116,99,104,105,110,103,32,112,97,116,116,101,114,110,115,32,97,98,111,118,101,32,119,111,114,107,32,111,110,108,121,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,100,111,101,115,32,110,111,116,32,115,116,97,114,116,32,119,105,116,104,32,97,32,112,97,108,105,110,100,114,111,109,101,32,116,104,97,116,32,105,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,101,110,116,105,114,101,32,115,116,114,105,110,103,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,97,108,116,104,111,117,103,104,32,34,97,98,99,98,97,34,32,105,115,32,99,111,114,114,101,99,116,108,121,32,109,97,116,99,104,101,100,44,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,98,97,98,97,34,44,32,80,67,82,69,32,102,105,110,100,115,32,112,97,108,105,110,100,114,111,109,101,32,34,97,98,97,34,32,97,116,32,116,104,101,32,115,116,97,114,116,44,32,97,110,100,32,116,104,101,110,32,102,97,105,108,115,32,97,116,32,116,111,112,32,108,101,118,101,108,44,32,97,115,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,100,111,101,115,32,110,111,116,32,102,111,108,108,111,119,46,32,79,110,99,101,32,97,103,97,105,110,44,32,105,116,32,99,97,110,110,111,116,32,106,117,109,112,32,98,97,99,107,32,105,110,116,111,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,116,111,32,116,114,121,32,111,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,115,111,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46>>]}]},{p,[],[<<84,104,101,32,115,101,99,111,110,100,32,119,97,121,32,105,110,32,119,104,105,99,104,32,80,67,82,69,32,97,110,100,32,80,101,114,108,32,100,105,102,102,101,114,32,105,110,32,116,104,101,105,114,32,114,101,99,117,114,115,105,111,110,32,112,114,111,99,101,115,115,105,110,103,32,105,115,32,105,110,32,116,104,101,32,104,97,110,100,108,105,110,103,32,111,102,32,99,97,112,116,117,114,101,100,32,118,97,108,117,101,115,46,32,73,110,32,80,101,114,108,44,32,119,104,101,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,99,97,108,108,101,100,32,114,101,99,117,114,115,105,118,101,108,121,32,111,114,32,97,115,32,97,32,115,117,98,112,97,116,116,101,114,110,32,40,115,101,101,32,116,104,101,32,110,101,120,116,32,115,101,99,116,105,111,110,41,44,32,105,116,32,104,97,115,32,110,111,32,97,99,99,101,115,115,32,116,111,32,97,110,121,32,118,97,108,117,101,115,32,116,104,97,116,32,119,101,114,101,32,99,97,112,116,117,114,101,100,32,111,117,116,115,105,100,101,32,116,104,101,32,114,101,99,117,114,115,105,111,110,46,32,73,110,32,80,67,82,69,32,116,104,101,115,101,32,118,97,108,117,101,115,32,99,97,110,32,98,101,32,114,101,102,101,114,101,110,99,101,100,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<94,40,46,41,40,92,49,124,97,40,63,50,41,41>>]}]},{p,[],[<<73,110,32,80,67,82,69,44,32,105,116,32,109,97,116,99,104,101,115,32,34,98,97,98,34,46,32,84,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,110,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,103,114,111,117,112,44,32,119,104,101,110,32,116,104,101,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,32,92,49,32,102,97,105,108,115,32,116,111,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,109,97,116,99,104,101,115,32,34,97,34,44,32,97,110,100,32,116,104,101,110,32,114,101,99,117,114,115,101,115,46,32,73,110,32,116,104,101,32,114,101,99,117,114,115,105,111,110,44,32,92,49,32,100,111,101,115,32,110,111,119,32,109,97,116,99,104,32,34,98,34,32,97,110,100,32,115,111,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,32,115,117,99,99,101,101,100,115,46,32,73,110,32,80,101,114,108,44,32,116,104,101,32,112,97,116,116,101,114,110,32,102,97,105,108,115,32,116,111,32,109,97,116,99,104,32,98,101,99,97,117,115,101,32,105,110,115,105,100,101,32,116,104,101,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,92,49,32,99,97,110,110,111,116,32,97,99,99,101,115,115,32,116,104,101,32,101,120,116,101,114,110,97,108,108,121,32,115,101,116,32,118,97,108,117,101,46>>]},{a,[{id,<<115,101,99,116,50,49>>}],[]},{h2,[],[<<83,117,98,112,97,116,116,101,114,110,115,32,97,115,32,83,117,98,114,111,117,116,105,110,101,115>>]},{p,[],[<<73,102,32,116,104,101,32,115,121,110,116,97,120,32,102,111,114,32,97,32,114,101,99,117,114,115,105,118,101,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,32,40,101,105,116,104,101,114,32,98,121,32,110,117,109,98,101,114,32,111,114,32,98,121,32,110,97,109,101,41,32,105,115,32,117,115,101,100,32,111,117,116,115,105,100,101,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,116,111,32,119,104,105,99,104,32,105,116,32,114,101,102,101,114,115,44,32,105,116,32,111,112,101,114,97,116,101,115,32,108,105,107,101,32,97,32,115,117,98,114,111,117,116,105,110,101,32,105,110,32,97,32,112,114,111,103,114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,46,32,84,104,101,32,99,97,108,108,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,98,101,32,100,101,102,105,110,101,100,32,98,101,102,111,114,101,32,111,114,32,97,102,116,101,114,32,116,104,101,32,114,101,102,101,114,101,110,99,101,46,32,65,32,110,117,109,98,101,114,101,100,32,114,101,102,101,114,101,110,99,101,32,99,97,110,32,98,101,32,97,98,115,111,108,117,116,101,32,111,114,32,114,101,108,97,116,105,118,101,44,32,97,115,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,115,58>>]},{pre,[],[{code,[],[<<40,46,46,46,40,97,98,115,111,108,117,116,101,41,46,46,46,41,46,46,46,40,63,50,41,46,46,46,10,40,46,46,46,40,114,101,108,97,116,105,118,101,41,46,46,46,41,46,46,46,40,63,45,49,41,46,46,46,10,40,46,46,46,40,63,43,49,41,46,46,46,40,114,101,108,97,116,105,118,101,41,46,46,46>>]}]},{p,[],[<<65,110,32,101,97,114,108,105,101,114,32,101,120,97,109,112,108,101,32,112,111,105,110,116,101,100,32,111,117,116,32,116,104,97,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,115,101,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,34,114,101,115,112,111,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,44,32,98,117,116,32,110,111,116,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,49,105,98,105,108,105,116,121>>]}]},{p,[],[<<73,102,32,105,110,115,116,101,97,100,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,105,115,32,117,115,101,100,44,32,105,116,32,109,97,116,99,104,101,115,32,34,115,101,110,115,101,32,97,110,100,32,114,101,115,112,111,110,115,105,98,105,108,105,116,121,34,32,97,110,100,32,116,104,101,32,111,116,104,101,114,32,116,119,111,32,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,40,63,49,41,105,98,105,108,105,116,121>>]}]},{p,[],[<<65,110,111,116,104,101,114,32,101,120,97,109,112,108,101,32,105,115,32,112,114,111,118,105,100,101,100,32,105,110,32,116,104,101,32,100,105,115,99,117,115,115,105,111,110,32,111,102,32,68,69,70,73,78,69,32,101,97,114,108,105,101,114,46>>]},{p,[],[<<65,108,108,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,44,32,114,101,99,117,114,115,105,118,101,32,111,114,32,110,111,116,44,32,97,114,101,32,97,108,119,97,121,115,32,116,114,101,97,116,101,100,32,97,115,32,97,116,111,109,105,99,32,103,114,111,117,112,115,46,32,84,104,97,116,32,105,115,44,32,111,110,99,101,32,97,32,115,117,98,114,111,117,116,105,110,101,32,104,97,115,32,109,97,116,99,104,101,100,32,115,111,109,101,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,105,116,32,105,115,32,110,101,118,101,114,32,114,101,45,101,110,116,101,114,101,100,44,32,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,117,110,116,114,105,101,100,32,97,108,116,101,114,110,97,116,105,118,101,115,32,97,110,100,32,116,104,101,114,101,32,105,115,32,97,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,46,32,65,110,121,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,116,104,97,116,32,97,114,101,32,115,101,116,32,100,117,114,105,110,103,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,32,114,101,118,101,114,116,32,116,111,32,116,104,101,105,114,32,112,114,101,118,105,111,117,115,32,118,97,108,117,101,115,32,97,102,116,101,114,119,97,114,100,115,46>>]},{p,[],[<<80,114,111,99,101,115,115,105,110,103,32,111,112,116,105,111,110,115,32,115,117,99,104,32,97,115,32,99,97,115,101,45,105,110,100,101,112,101,110,100,101,110,99,101,32,97,114,101,32,102,105,120,101,100,32,119,104,101,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,100,101,102,105,110,101,100,44,32,115,111,32,105,102,32,105,116,32,105,115,32,117,115,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,115,117,99,104,32,111,112,116,105,111,110,115,32,99,97,110,110,111,116,32,98,101,32,99,104,97,110,103,101,100,32,102,111,114,32,100,105,102,102,101,114,101,110,116,32,99,97,108,108,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,34,97,98,99,97,98,99,34,32,98,117,116,32,110,111,116,32,34,97,98,99,65,66,67,34,44,32,97,115,32,116,104,101,32,99,104,97,110,103,101,32,111,102,32,112,114,111,99,101,115,115,105,110,103,32,111,112,116,105,111,110,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,116,104,101,32,99,97,108,108,101,100,32,115,117,98,112,97,116,116,101,114,110,58>>]},{pre,[],[{code,[],[<<40,97,98,99,41,40,63,105,58,40,63,45,49,41,41>>]}]},{a,[{id,<<115,101,99,116,50,50>>}],[]},{h2,[],[<<79,110,105,103,117,114,117,109,97,32,83,117,98,114,111,117,116,105,110,101,32,83,121,110,116,97,120>>]},{p,[],[<<70,111,114,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,119,105,116,104,32,79,110,105,103,117,114,117,109,97,44,32,116,104,101,32,110,111,110,45,80,101,114,108,32,115,121,110,116,97,120,32,92,103,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,32,111,114,32,97,32,110,117,109,98,101,114,32,101,110,99,108,111,115,101,100,32,101,105,116,104,101,114,32,105,110,32,97,110,103,108,101,32,98,114,97,99,107,101,116,115,32,111,114,32,115,105,110,103,108,101,32,113,117,111,116,101,115,44,32,105,115,32,97,108,116,101,114,110,97,116,105,118,101,32,115,121,110,116,97,120,32,102,111,114,32,114,101,102,101,114,101,110,99,105,110,103,32,97,32,115,117,98,112,97,116,116,101,114,110,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,112,111,115,115,105,98,108,121,32,114,101,99,117,114,115,105,118,101,108,121,46,32,72,101,114,101,32,102,111,108,108,111,119,115,32,116,119,111,32,111,102,32,116,104,101,32,101,120,97,109,112,108,101,115,32,117,115,101,100,32,97,98,111,118,101,44,32,114,101,119,114,105,116,116,101,110,32,117,115,105,110,103,32,116,104,105,115,32,115,121,110,116,97,120,58>>]},{pre,[],[{code,[],[<<40,63,60,112,110,62,32,92,40,32,40,32,40,63,62,91,94,40,41,93,43,41,32,124,32,92,103,60,112,110,62,32,41,42,32,92,41,32,41,10,40,115,101,110,115,124,114,101,115,112,111,110,115,41,101,32,97,110,100,32,92,103,39,49,39,105,98,105,108,105,116,121>>]}]},{p,[],[<<80,67,82,69,32,115,117,112,112,111,114,116,115,32,97,110,32,101,120,116,101,110,115,105,111,110,32,116,111,32,79,110,105,103,117,114,117,109,97,58,32,105,102,32,97,32,110,117,109,98,101,114,32,105,115,32,112,114,101,99,101,100,101,100,32,98,121,32,97,32,112,108,117,115,32,111,114,32,109,105,110,117,115,32,115,105,103,110,44,32,105,116,32,105,115,32,116,97,107,101,110,32,97,115,32,97,32,114,101,108,97,116,105,118,101,32,114,101,102,101,114,101,110,99,101,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<40,97,98,99,41,40,63,105,58,92,103,60,45,49,62,41>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,92,103,123,46,46,46,125,32,40,80,101,114,108,32,115,121,110,116,97,120,41,32,97,110,100,32,92,103,60,46,46,46,62,32,40,79,110,105,103,117,114,117,109,97,32,115,121,110,116,97,120,41,32,97,114,101,32>>,{em,[],[<<110,111,116>>]},<<32,115,121,110,111,110,121,109,111,117,115,46,32,84,104,101,32,102,111,114,109,101,114,32,105,115,32,97,32,98,97,99,107,32,114,101,102,101,114,101,110,99,101,59,32,116,104,101,32,108,97,116,116,101,114,32,105,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]},{a,[{id,<<115,101,99,116,50,51>>}],[]},{h2,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108>>]},{p,[],[<<80,101,114,108,32,53,46,49,48,32,105,110,116,114,111,100,117,99,101,100,32,115,111,109,101,32,34,83,112,101,99,105,97,108,32,66,97,99,107,116,114,97,99,107,105,110,103,32,67,111,110,116,114,111,108,32,86,101,114,98,115,34,44,32,119,104,105,99,104,32,97,114,101,32,115,116,105,108,108,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,97,115,32,34,101,120,112,101,114,105,109,101,110,116,97,108,32,97,110,100,32,115,117,98,106,101,99,116,32,116,111,32,99,104,97,110,103,101,32,111,114,32,114,101,109,111,118,97,108,32,105,110,32,97,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,32,111,102,32,80,101,114,108,34,46,32,73,116,32,103,111,101,115,32,111,110,32,116,111,32,115,97,121,58,32,34,84,104,101,105,114,32,117,115,97,103,101,32,105,110,32,112,114,111,100,117,99,116,105,111,110,32,99,111,100,101,32,115,104,111,117,108,100,32,98,101,32,110,111,116,101,100,32,116,111,32,97,118,111,105,100,32,112,114,111,98,108,101,109,115,32,100,117,114,105,110,103,32,117,112,103,114,97,100,101,115,46,34,32,84,104,101,32,115,97,109,101,32,114,101,109,97,114,107,115,32,97,112,112,108,121,32,116,111,32,116,104,101,32,80,67,82,69,32,102,101,97,116,117,114,101,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,116,104,105,115,32,115,101,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32,110,101,119,32,118,101,114,98,115,32,109,97,107,101,32,117,115,101,32,111,102,32,119,104,97,116,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,105,110,118,97,108,105,100,32,115,121,110,116,97,120,58,32,97,110,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32,97,110,32,97,115,116,101,114,105,115,107,46,32,84,104,101,121,32,97,114,101,32,103,101,110,101,114,97,108,108,121,32,111,102,32,116,104,101,32,102,111,114,109,32,40,42,86,69,82,66,41,32,111,114,32,40,42,86,69,82,66,58,78,65,77,69,41,46,32,83,111,109,101,32,99,97,110,32,116,97,107,101,32,101,105,116,104,101,114,32,102,111,114,109,44,32,112,111,115,115,105,98,108,121,32,98,101,104,97,118,105,110,103,32,100,105,102,102,101,114,101,110,116,108,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,119,104,101,116,104,101,114,32,97,32,110,97,109,101,32,105,115,32,112,114,101,115,101,110,116,46,32,65,32,110,97,109,101,32,105,115,32,97,110,121,32,115,101,113,117,101,110,99,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,105,110,99,108,117,100,101,32,97,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,46,32,84,104,101,32,109,97,120,105,109,117,109,32,110,97,109,101,32,108,101,110,103,116,104,32,105,115,32,50,53,53,32,105,110,32,116,104,101,32,56,45,98,105,116,32,108,105,98,114,97,114,121,32,97,110,100,32,54,53,53,51,53,32,105,110,32,116,104,101,32,49,54,45,98,105,116,32,97,110,100,32,51,50,45,98,105,116,32,108,105,98,114,97,114,105,101,115,46,32,73,102,32,116,104,101,32,110,97,109,101,32,105,115,32,101,109,112,116,121,44,32,116,104,97,116,32,105,115,44,32,105,102,32,116,104,101,32,99,108,111,115,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,115,32,116,104,101,32,99,111,108,111,110,44,32,116,104,101,32,101,102,102,101,99,116,32,105,115,32,97,115,32,105,102,32,116,104,101,32,99,111,108,111,110,32,119,97,115,32,110,111,116,32,116,104,101,114,101,46,32,65,110,121,32,110,117,109,98,101,114,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,99,97,110,32,111,99,99,117,114,32,105,110,32,97,32,112,97,116,116,101,114,110,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,105,110,32,114,101,112,101,97,116,101,100,32,103,114,111,117,112,115,44,32,97,115,115,101,114,116,105,111,110,115,44,32,97,110,100,32,105,110,32,115,117,98,112,97,116,116,101,114,110,115,32,99,97,108,108,101,100,32,97,115,32,115,117,98,114,111,117,116,105,110,101,115,32,40,119,104,101,116,104,101,114,32,111,114,32,110,111,116,32,114,101,99,117,114,115,105,118,101,108,121,41,32,105,115,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,46>>]},{p,[],[{em,[],[<<79,112,116,105,109,105,122,97,116,105,111,110,115,32,84,104,97,116,32,65,102,102,101,99,116,32,66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115>>]}]},{p,[],[<<80,67,82,69,32,99,111,110,116,97,105,110,115,32,115,111,109,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,116,104,97,116,32,97,114,101,32,117,115,101,100,32,116,111,32,115,112,101,101,100,32,117,112,32,109,97,116,99,104,105,110,103,32,98,121,32,114,117,110,110,105,110,103,32,115,111,109,101,32,99,104,101,99,107,115,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,101,97,99,104,32,109,97,116,99,104,32,97,116,116,101,109,112,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,116,32,99,97,110,32,107,110,111,119,32,116,104,101,32,109,105,110,105,109,117,109,32,108,101,110,103,116,104,32,111,102,32,109,97,116,99,104,105,110,103,32,115,117,98,106,101,99,116,44,32,111,114,32,116,104,97,116,32,97,32,112,97,114,116,105,99,117,108,97,114,32,99,104,97,114,97,99,116,101,114,32,109,117,115,116,32,98,101,32,112,114,101,115,101,110,116,46,32,87,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,98,121,112,97,115,115,101,115,32,116,104,101,32,114,117,110,110,105,110,103,32,111,102,32,97,32,109,97,116,99,104,44,32,97,110,121,32,105,110,99,108,117,100,101,100,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,114,101,32,110,111,116,32,112,114,111,99,101,115,115,101,100,46,32,112,114,111,99,101,115,115,101,100,46,32,89,111,117,32,99,97,110,32,115,117,112,112,114,101,115,115,32,116,104,101,32,115,116,97,114,116,45,111,102,45,109,97,116,99,104,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,98,121,32,115,101,116,116,105,110,103,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,119,104,101,110,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,111,114,32,98,121,32,115,116,97,114,116,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,119,105,116,104,32,40,42,78,79,95,83,84,65,82,84,95,79,80,84,41,46>>]},{p,[],[<<69,120,112,101,114,105,109,101,110,116,115,32,119,105,116,104,32,80,101,114,108,32,115,117,103,103,101,115,116,32,116,104,97,116,32,105,116,32,116,111,111,32,104,97,115,32,115,105,109,105,108,97,114,32,111,112,116,105,109,105,122,97,116,105,111,110,115,44,32,115,111,109,101,116,105,109,101,115,32,108,101,97,100,105,110,103,32,116,111,32,97,110,111,109,97,108,111,117,115,32,114,101,115,117,108,116,115,46>>]},{p,[],[{em,[],[<<86,101,114,98,115,32,84,104,97,116,32,65,99,116,32,73,109,109,101,100,105,97,116,101,108,121>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,115,32,97,99,116,32,97,115,32,115,111,111,110,32,97,115,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46,32,84,104,101,121,32,109,117,115,116,32,110,111,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,46>>]},{pre,[],[{code,[],[<<40,42,65,67,67,69,80,84,41>>]}]},{p,[],[<<84,104,105,115,32,118,101,114,98,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,101,110,100,32,115,117,99,99,101,115,115,102,117,108,108,121,44,32,115,107,105,112,112,105,110,103,32,116,104,101,32,114,101,109,97,105,110,100,101,114,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,105,116,32,105,115,32,105,110,115,105,100,101,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,105,115,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,44,32,111,110,108,121,32,116,104,97,116,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,101,110,100,101,100,32,115,117,99,99,101,115,115,102,117,108,108,121,46,32,77,97,116,99,104,105,110,103,32,116,104,101,110,32,99,111,110,116,105,110,117,101,115,32,97,116,32,116,104,101,32,111,117,116,101,114,32,108,101,118,101,108,46,32,73,102,32,40,42,65,67,67,69,80,84,41,32,105,115,32,116,114,105,103,103,101,114,101,100,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,115,117,99,99,101,101,100,115,59,32,105,110,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,102,97,105,108,115,46>>]},{p,[],[<<73,102,32,40,42,65,67,67,69,80,84,41,32,105,115,32,105,110,115,105,100,101,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,44,32,116,104,101,32,100,97,116,97,32,115,111,32,102,97,114,32,105,115,32,99,97,112,116,117,114,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,101,115,32,34,65,66,34,44,32,34,65,65,68,34,44,32,111,114,32,34,65,67,68,34,46,32,87,104,101,110,32,105,116,32,109,97,116,99,104,101,115,32,34,65,66,34,44,32,34,66,34,32,105,115,32,99,97,112,116,117,114,101,100,32,98,121,32,116,104,101,32,111,117,116,101,114,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{pre,[],[{code,[],[<<65,40,40,63,58,65,124,66,40,42,65,67,67,69,80,84,41,124,67,41,68,41>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,44,32,102,111,114,99,105,110,103,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,111,99,99,117,114,46,32,73,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,40,63,33,41,32,98,117,116,32,101,97,115,105,101,114,32,116,111,32,114,101,97,100,46>>]},{pre,[],[{code,[],[<<40,42,70,65,73,76,41,32,111,114,32,40,42,70,41>>]}]},{p,[],[<<84,104,101,32,80,101,114,108,32,100,111,99,117,109,101,110,116,97,116,105,111,110,32,115,116,97,116,101,115,32,116,104,97,116,32,105,116,32,105,115,32,112,114,111,98,97,98,108,121,32,117,115,101,102,117,108,32,111,110,108,121,32,119,104,101,110,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,40,63,123,125,41,32,111,114,32,40,63,63,123,125,41,46,32,84,104,111,115,101,32,97,114,101,32,80,101,114,108,32,102,101,97,116,117,114,101,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,80,67,82,69,46>>]},{p,[],[<<65,32,109,97,116,99,104,32,119,105,116,104,32,116,104,101,32,115,116,114,105,110,103,32,34,97,97,97,97,34,32,97,108,119,97,121,115,32,102,97,105,108,115,44,32,98,117,116,32,116,104,101,32,99,97,108,108,111,117,116,32,105,115,32,116,97,107,101,110,32,98,101,102,111,114,101,32,101,97,99,104,32,98,97,99,107,116,114,97,99,107,32,111,99,99,117,114,115,32,40,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,44,32,49,48,32,116,105,109,101,115,41,46>>]},{p,[],[{em,[],[<<82,101,99,111,114,100,105,110,103,32,87,104,105,99,104,32,80,97,116,104,32,87,97,115,32,84,97,107,101,110>>]}]},{p,[],[<<84,104,101,32,109,97,105,110,32,112,117,114,112,111,115,101,32,111,102,32,116,104,105,115,32,118,101,114,98,32,105,115,32,116,111,32,116,114,97,99,107,32,104,111,119,32,97,32,109,97,116,99,104,32,119,97,115,32,97,114,114,105,118,101,100,32,97,116,44,32,97,108,116,104,111,117,103,104,32,105,116,32,97,108,115,111,32,104,97,115,32,97,32,115,101,99,111,110,100,97,114,121,32,117,115,101,32,105,110,32,119,105,116,104,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,109,97,116,99,104,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,40,115,101,101,32,40,42,83,75,73,80,41,32,98,101,108,111,119,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<73,110,32,69,114,108,97,110,103,44,32,116,104,101,114,101,32,105,115,32,110,111,32,105,110,116,101,114,102,97,99,101,32,116,111,32,114,101,116,114,105,101,118,101,32,97,32,109,97,114,107,32,119,105,116,104,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50,44,51>>]}]},<<44,32,115,111,32,111,110,108,121,32,116,104,101,32,115,101,99,111,110,100,97,114,121,32,112,117,114,112,111,115,101,32,105,115,32,114,101,108,101,118,97,110,116,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,46>>]},{p,[],[<<84,104,101,32,114,101,115,116,32,111,102,32,116,104,105,115,32,115,101,99,116,105,111,110,32,105,115,32,116,104,101,114,101,102,111,114,101,32,100,101,108,105,98,101,114,97,116,101,108,121,32,110,111,116,32,97,100,97,112,116,101,100,32,102,111,114,32,114,101,97,100,105,110,103,32,98,121,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,98,117,116,32,116,104,101,32,101,120,97,109,112,108,101,115,32,99,97,110,32,104,101,108,112,32,105,110,32,117,110,100,101,114,115,116,97,110,100,105,110,103,32,78,65,77,69,83,32,97,115,32,116,104,101,121,32,99,97,110,32,98,101,32,117,115,101,100,32,98,121,32,40,42,83,75,73,80,41,46>>]}]},{pre,[],[{code,[],[<<40,42,77,65,82,75,58,78,65,77,69,41,32,111,114,32,40,42,58,78,65,77,69,41>>]}]},{p,[],[<<65,32,110,97,109,101,32,105,115,32,97,108,119,97,121,115,32,114,101,113,117,105,114,101,100,32,119,105,116,104,32,116,104,105,115,32,118,101,114,98,46,32,84,104,101,114,101,32,99,97,110,32,98,101,32,97,115,32,109,97,110,121,32,105,110,115,116,97,110,99,101,115,32,111,102,32,40,42,77,65,82,75,41,32,97,115,32,121,111,117,32,108,105,107,101,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,110,100,32,116,104,101,105,114,32,110,97,109,101,115,32,100,111,32,110,111,116,32,104,97,118,101,32,116,111,32,98,101,32,117,110,105,113,117,101,46>>]},{p,[],[<<87,104,101,110,32,97,32,109,97,116,99,104,32,115,117,99,99,101,101,100,115,44,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,32,40,42,77,65,82,75,58,78,65,77,69,41,44,32,40,42,80,82,85,78,69,58,78,65,77,69,41,44,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41,32,111,110,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,116,104,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,32,97,115,32,100,101,115,99,114,105,98,101,100,32,105,110,32,115,101,99,116,105,111,110,32,34,69,120,116,114,97,32,100,97,116,97,32,102,111,114,32>>,{code,[],[<<112,99,114,101,95,101,120,101,99,40,41>>]},<<34,32,105,110,32,116,104,101,32>>,{code,[],[<<112,99,114,101,97,112,105>>]},<<32,100,111,99,117,109,101,110,116,97,116,105,111,110,46,32,73,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,111,102,32>>,{code,[],[<<112,99,114,101,116,101,115,116>>]},<<32,111,117,116,112,117,116,44,32,116,104,101,32,47,75,32,109,111,100,105,102,105,101,114,32,114,101,113,117,101,115,116,115,32,116,104,101,32,114,101,116,114,105,101,118,97,108,32,97,110,100,32,111,117,116,112,117,116,116,105,110,103,32,111,102,32,40,42,77,65,82,75,41,32,100,97,116,97,58>>]},{pre,[],[{code,[],[<<32,32,114,101,62,32,47,88,40,42,77,65,82,75,58,65,41,89,124,88,40,42,77,65,82,75,58,66,41,90,47,75,10,100,97,116,97,62,32,88,89,10,32,48,58,32,88,89,10,77,75,58,32,65,10,88,90,10,32,48,58,32,88,90,10,77,75,58,32,66>>]}]},{p,[],[<<84,104,101,32,40,42,77,65,82,75,41,32,110,97,109,101,32,105,115,32,116,97,103,103,101,100,32,119,105,116,104,32,34,77,75,58,34,32,105,110,32,116,104,105,115,32,111,117,116,112,117,116,44,32,97,110,100,32,105,110,32,116,104,105,115,32,101,120,97,109,112,108,101,32,105,116,32,105,110,100,105,99,97,116,101,115,32,119,104,105,99,104,32,111,102,32,116,104,101,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,32,109,97,116,99,104,101,100,46,32,84,104,105,115,32,105,115,32,97,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,119,97,121,32,111,102,32,111,98,116,97,105,110,105,110,103,32,116,104,105,115,32,105,110,102,111,114,109,97,116,105,111,110,32,116,104,97,110,32,112,117,116,116,105,110,103,32,101,97,99,104,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,105,116,115,32,111,119,110,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,46>>]},{p,[],[<<73,102,32,97,32,118,101,114,98,32,119,105,116,104,32,97,32,110,97,109,101,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,44,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,99,111,114,100,101,100,32,97,110,100,32,112,97,115,115,101,100,32,98,97,99,107,32,105,102,32,105,116,32,105,115,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,46,32,84,104,105,115,32,100,111,101,115,32,110,111,116,32,111,99,99,117,114,32,102,111,114,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,111,114,32,102,97,105,108,105,110,103,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,46>>]},{p,[],[<<65,102,116,101,114,32,97,32,112,97,114,116,105,97,108,32,109,97,116,99,104,32,111,114,32,97,32,102,97,105,108,101,100,32,109,97,116,99,104,44,32,116,104,101,32,108,97,115,116,32,101,110,99,111,117,110,116,101,114,101,100,32,110,97,109,101,32,105,110,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,112,114,111,99,101,115,115,32,105,115,32,114,101,116,117,114,110,101,100,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<32,32,114,101,62,32,47,88,40,42,77,65,82,75,58,65,41,89,124,88,40,42,77,65,82,75,58,66,41,90,47,75,10,100,97,116,97,62,32,88,80,10,78,111,32,109,97,116,99,104,44,32,109,97,114,107,32,61,32,66>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,105,110,32,116,104,105,115,32,117,110,97,110,99,104,111,114,101,100,32,101,120,97,109,112,108,101,44,32,116,104,101,32,109,97,114,107,32,105,115,32,114,101,116,97,105,110,101,100,32,102,114,111,109,32,116,104,101,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,116,104,97,116,32,115,116,97,114,116,101,100,32,97,116,32,108,101,116,116,101,114,32,34,88,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,46,32,83,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,115,32,115,116,97,114,116,105,110,103,32,97,116,32,34,80,34,32,97,110,100,32,116,104,101,110,32,119,105,116,104,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,100,111,32,110,111,116,32,103,101,116,32,97,115,32,102,97,114,32,97,115,32,116,104,101,32,40,42,77,65,82,75,41,32,105,116,101,109,44,32,110,101,118,101,114,116,104,101,108,101,115,115,32,100,111,32,110,111,116,32,114,101,115,101,116,32,105,116,46>>]},{p,[],[{em,[],[<<86,101,114,98,115,32,84,104,97,116,32,65,99,116,32,97,102,116,101,114,32,66,97,99,107,116,114,97,99,107,105,110,103>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,115,32,100,111,32,110,111,116,104,105,110,103,32,119,104,101,110,32,116,104,101,121,32,97,114,101,32,101,110,99,111,117,110,116,101,114,101,100,46,32,77,97,116,99,104,105,110,103,32,99,111,110,116,105,110,117,101,115,32,119,105,116,104,32,119,104,97,116,32,102,111,108,108,111,119,115,44,32,98,117,116,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,44,32,99,97,117,115,105,110,103,32,97,32,98,97,99,107,116,114,97,99,107,32,116,111,32,116,104,101,32,118,101,114,98,44,32,97,32,102,97,105,108,117,114,101,32,105,115,32,102,111,114,99,101,100,46,32,84,104,97,116,32,105,115,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,110,111,116,32,112,97,115,115,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,118,101,114,98,46,32,72,111,119,101,118,101,114,44,32,119,104,101,110,32,111,110,101,32,111,102,32,116,104,101,115,101,32,118,101,114,98,115,32,97,112,112,101,97,114,115,32,105,110,115,105,100,101,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,97,110,32,97,115,115,101,114,116,105,111,110,32,116,104,97,116,32,105,115,32,116,114,117,101,44,32,105,116,115,32,101,102,102,101,99,116,32,105,115,32,99,111,110,102,105,110,101,100,32,116,111,32,116,104,97,116,32,103,114,111,117,112,44,32,97,115,32,111,110,99,101,32,116,104,101,32,103,114,111,117,112,32,104,97,115,32,98,101,101,110,32,109,97,116,99,104,101,100,44,32,116,104,101,114,101,32,105,115,32,110,101,118,101,114,32,97,110,121,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,105,116,46,32,73,110,32,116,104,105,115,32,115,105,116,117,97,116,105,111,110,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,32,34,106,117,109,112,32,98,97,99,107,34,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,116,104,101,32,101,110,116,105,114,101,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,97,115,115,101,114,116,105,111,110,46,32,40,82,101,109,101,109,98,101,114,32,97,108,115,111,44,32,97,115,32,115,116,97,116,101,100,32,97,98,111,118,101,44,32,116,104,97,116,32,116,104,105,115,32,108,111,99,97,108,105,122,97,116,105,111,110,32,97,108,115,111,32,97,112,112,108,105,101,115,32,105,110,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,115,46,41>>]},{p,[],[<<84,104,101,115,101,32,118,101,114,98,115,32,100,105,102,102,101,114,32,105,110,32,101,120,97,99,116,108,121,32,119,104,97,116,32,107,105,110,100,32,111,102,32,102,97,105,108,117,114,101,32,111,99,99,117,114,115,32,119,104,101,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,114,101,97,99,104,101,115,32,116,104,101,109,46,32,84,104,101,32,98,101,104,97,118,105,111,114,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,32,105,115,32,119,104,97,116,32,111,99,99,117,114,115,32,119,104,101,110,32,116,104,101,32,118,101,114,98,32,105,115,32,110,111,116,32,105,110,32,97,32,115,117,98,114,111,117,116,105,110,101,32,111,114,32,97,110,32,97,115,115,101,114,116,105,111,110,46,32,83,117,98,115,101,113,117,101,110,116,32,115,101,99,116,105,111,110,115,32,99,111,118,101,114,32,116,104,101,115,101,32,115,112,101,99,105,97,108,32,99,97,115,101,115,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,44,32,119,104,105,99,104,32,109,117,115,116,32,110,111,116,32,98,101,32,102,111,108,108,111,119,101,100,32,98,121,32,97,32,110,97,109,101,44,32,99,97,117,115,101,115,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,111,117,116,114,105,103,104,116,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,108,97,116,101,114,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,104,97,116,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,114,101,97,99,104,32,105,116,46,32,69,118,101,110,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,110,111,32,102,117,114,116,104,101,114,32,97,116,116,101,109,112,116,115,32,116,111,32,102,105,110,100,32,97,32,109,97,116,99,104,32,98,121,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,116,97,107,101,32,112,108,97,99,101,46>>]},{pre,[],[{code,[],[<<40,42,67,79,77,77,73,84,41>>]}]},{p,[],[<<73,102,32,40,42,67,79,77,77,73,84,41,32,105,115,32,116,104,101,32,111,110,108,121,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,116,104,97,116,32,105,115,32,101,110,99,111,117,110,116,101,114,101,100,44,32,111,110,99,101,32,105,116,32,104,97,115,32,98,101,101,110,32,112,97,115,115,101,100,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50,44,51>>]}]},<<32,105,115,32,99,111,109,109,105,116,116,101,100,32,116,111,32,102,105,110,100,32,97,32,109,97,116,99,104,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,44,32,111,114,32,110,111,116,32,97,116,32,97,108,108,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<97,43,40,42,67,79,77,77,73,84,41,98>>]}]},{p,[],[<<84,104,105,115,32,109,97,116,99,104,101,115,32,34,120,120,97,97,98,34,32,98,117,116,32,110,111,116,32,34,97,97,99,97,97,98,34,46,32,73,116,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,97,32,107,105,110,100,32,111,102,32,100,121,110,97,109,105,99,32,97,110,99,104,111,114,44,32,111,114,32,34,73,39,118,101,32,115,116,97,114,116,101,100,44,32,115,111,32,73,32,109,117,115,116,32,102,105,110,105,115,104,34,46,32,84,104,101,32,110,97,109,101,32,111,102,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,108,121,32,112,97,115,115,101,100,32,40,42,77,65,82,75,41,32,105,110,32,116,104,101,32,112,97,116,104,32,105,115,32,112,97,115,115,101,100,32,98,97,99,107,32,119,104,101,110,32,40,42,67,79,77,77,73,84,41,32,102,111,114,99,101,115,32,97,32,109,97,116,99,104,32,102,97,105,108,117,114,101,46>>]},{p,[],[<<73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,101,120,105,115,116,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,97,32,100,105,102,102,101,114,101,110,116,32,111,110,101,32,116,104,97,116,32,102,111,108,108,111,119,115,32,40,42,67,79,77,77,73,84,41,32,99,97,110,32,98,101,32,116,114,105,103,103,101,114,101,100,32,102,105,114,115,116,44,32,115,111,32,109,101,114,101,108,121,32,112,97,115,115,105,110,103,32,40,42,67,79,77,77,73,84,41,32,100,117,114,105,110,103,32,97,32,109,97,116,99,104,32,100,111,101,115,32,110,111,116,32,97,108,119,97,121,115,32,103,117,97,114,97,110,116,101,101,32,116,104,97,116,32,97,32,109,97,116,99,104,32,109,117,115,116,32,98,101,32,97,116,32,116,104,105,115,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,40,42,67,79,77,77,73,84,41,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,97,32,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,97,110,32,97,110,99,104,111,114,44,32,117,110,108,101,115,115,32,116,104,101,32,80,67,82,69,32,115,116,97,114,116,45,111,102,45,109,97,116,99,104,32,111,112,116,105,109,105,122,97,116,105,111,110,115,32,97,114,101,32,116,117,114,110,101,100,32,111,102,102,44,32,97,115,32,115,104,111,119,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,114,101,58,114,117,110,40,34,120,121,122,97,98,99,34,44,34,40,42,67,79,77,77,73,84,41,97,98,99,34,44,91,123,99,97,112,116,117,114,101,44,97,108,108,44,108,105,115,116,125,93,41,46,10,123,109,97,116,99,104,44,91,34,97,98,99,34,93,125,10,50,62,32,114,101,58,114,117,110,40,34,120,121,122,97,98,99,34,44,34,40,42,67,79,77,77,73,84,41,97,98,99,34,44,91,123,99,97,112,116,117,114,101,44,97,108,108,44,108,105,115,116,125,44,110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101,93,41,46,10,110,111,109,97,116,99,104>>]}]},{p,[],[<<70,111,114,32,116,104,105,115,32,112,97,116,116,101,114,110,44,32,80,67,82,69,32,107,110,111,119,115,32,116,104,97,116,32,97,110,121,32,109,97,116,99,104,32,109,117,115,116,32,115,116,97,114,116,32,119,105,116,104,32,34,97,34,44,32,115,111,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,115,107,105,112,115,32,97,108,111,110,103,32,116,104,101,32,115,117,98,106,101,99,116,32,116,111,32,34,97,34,32,98,101,102,111,114,101,32,97,112,112,108,121,105,110,103,32,116,104,101,32,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,102,105,114,115,116,32,115,101,116,32,111,102,32,100,97,116,97,46,32,84,104,101,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,116,104,101,110,32,115,117,99,99,101,101,100,115,46,32,73,110,32,116,104,101,32,115,101,99,111,110,100,32,99,97,108,108,32,116,104,101,32>>,{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]},<<32,100,105,115,97,98,108,101,115,32,116,104,101,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,115,107,105,112,115,32,97,108,111,110,103,32,116,111,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,110,111,119,32,97,112,112,108,105,101,100,32,115,116,97,114,116,105,110,103,32,97,116,32,34,120,34,44,32,97,110,100,32,115,111,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,119,105,116,104,111,117,116,32,116,114,121,105,110,103,32,97,110,121,32,111,116,104,101,114,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,115,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,116,104,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,105,102,32,116,104,101,114,101,32,105,115,32,97,32,108,97,116,101,114,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,104,97,116,32,99,97,117,115,101,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,111,32,114,101,97,99,104,32,105,116,58>>]},{pre,[],[{code,[],[<<40,42,80,82,85,78,69,41,32,111,114,32,40,42,80,82,85,78,69,58,78,65,77,69,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,116,104,101,32,110,111,114,109,97,108,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,115,116,97,114,116,105,110,103,32,99,104,97,114,97,99,116,101,114,32,116,104,101,110,32,111,99,99,117,114,115,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,32,111,99,99,117,114,32,97,115,32,117,115,117,97,108,32,116,111,32,116,104,101,32,108,101,102,116,32,111,102,32,40,42,80,82,85,78,69,41,44,32,98,101,102,111,114,101,32,105,116,32,105,115,32,114,101,97,99,104,101,100,44,32,111,114,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,116,111,32,116,104,101,32,114,105,103,104,116,32,111,102,32,40,42,80,82,85,78,69,41,44,32,98,117,116,32,105,102,32,116,104,101,114,101,32,105,115,32,110,111,32,109,97,116,99,104,32,116,111,32,116,104,101,32,114,105,103,104,116,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,99,97,110,110,111,116,32,99,114,111,115,115,32,40,42,80,82,85,78,69,41,46,32,73,110,32,115,105,109,112,108,101,32,99,97,115,101,115,44,32,116,104,101,32,117,115,101,32,111,102,32,40,42,80,82,85,78,69,41,32,105,115,32,106,117,115,116,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,32,116,111,32,97,110,32,97,116,111,109,105,99,32,103,114,111,117,112,32,111,114,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,44,32,98,117,116,32,116,104,101,114,101,32,97,114,101,32,115,111,109,101,32,117,115,101,115,32,111,102,32,40,42,80,82,85,78,69,41,32,116,104,97,116,32,99,97,110,110,111,116,32,98,101,32,101,120,112,114,101,115,115,101,100,32,105,110,32,97,110,121,32,111,116,104,101,114,32,119,97,121,46,32,73,110,32,97,110,32,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,44,32,40,42,80,82,85,78,69,41,32,104,97,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,40,42,67,79,77,77,73,84,41,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,105,115,32,116,104,101,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,40,42,77,65,82,75,58,78,65,77,69,41,40,42,80,82,85,78,69,41,46,32,73,116,32,105,115,32,108,105,107,101,32,40,42,77,65,82,75,58,78,65,77,69,41,32,105,110,32,116,104,97,116,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,109,101,109,98,101,114,101,100,32,102,111,114,32,112,97,115,115,105,110,103,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,46,32,72,111,119,101,118,101,114,44,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,119,105,116,104,32,40,42,77,65,82,75,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,114,101,109,101,109,98,101,114,115,32,116,104,101,32,110,97,109,101,32,105,115,32,117,115,101,108,101,115,115,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,97,115,32,110,97,109,101,115,32,99,97,110,110,111,116,32,98,101,32,114,101,116,114,105,101,118,101,100,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,44,32,119,104,101,110,32,115,112,101,99,105,102,105,101,100,32,119,105,116,104,111,117,116,32,97,32,110,97,109,101,44,32,105,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,44,32,101,120,99,101,112,116,32,116,104,97,116,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,117,110,97,110,99,104,111,114,101,100,44,32,116,104,101,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,105,115,32,110,111,116,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,44,32,98,117,116,32,116,111,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,119,104,101,114,101,32,40,42,83,75,73,80,41,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,46>>]},{pre,[],[{code,[],[<<40,42,83,75,73,80,41>>]}]},{p,[],[<<40,42,83,75,73,80,41,32,115,105,103,110,105,102,105,101,115,32,116,104,97,116,32,119,104,97,116,101,118,101,114,32,116,101,120,116,32,119,97,115,32,109,97,116,99,104,101,100,32,108,101,97,100,105,110,103,32,117,112,32,116,111,32,105,116,32,99,97,110,110,111,116,32,98,101,32,112,97,114,116,32,111,102,32,97,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,46,32,67,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<97,43,40,42,83,75,73,80,41,98>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,97,97,97,99,46,46,46,34,44,32,97,102,116,101,114,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,32,102,97,105,108,115,32,40,115,116,97,114,116,105,110,103,32,97,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,114,105,110,103,41,44,32,116,104,101,32,115,116,97,114,116,105,110,103,32,112,111,105,110,116,32,115,107,105,112,115,32,111,110,32,116,111,32,115,116,97,114,116,32,116,104,101,32,110,101,120,116,32,97,116,116,101,109,112,116,32,97,116,32,34,99,34,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,32,112,111,115,115,101,115,115,105,118,101,32,113,117,97,110,116,105,102,105,101,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,116,104,105,115,32,101,120,97,109,112,108,101,59,32,97,108,116,104,111,117,103,104,32,105,116,32,119,111,117,108,100,32,115,117,112,112,114,101,115,115,32,98,97,99,107,116,114,97,99,107,105,110,103,32,100,117,114,105,110,103,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,116,101,109,112,116,44,32,116,104,101,32,115,101,99,111,110,100,32,97,116,116,101,109,112,116,32,119,111,117,108,100,32,115,116,97,114,116,32,97,116,32,116,104,101,32,115,101,99,111,110,100,32,99,104,97,114,97,99,116,101,114,32,105,110,115,116,101,97,100,32,111,102,32,115,107,105,112,112,105,110,103,32,111,110,32,116,111,32,34,99,34,46>>]},{p,[],[<<87,104,101,110,32,40,42,83,75,73,80,41,32,104,97,115,32,97,110,32,97,115,115,111,99,105,97,116,101,100,32,110,97,109,101,44,32,105,116,115,32,98,101,104,97,118,105,111,114,32,105,115,32,109,111,100,105,102,105,101,100,58>>]},{pre,[],[{code,[],[<<40,42,83,75,73,80,58,78,65,77,69,41>>]}]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,105,115,32,116,114,105,103,103,101,114,101,100,44,32,116,104,101,32,112,114,101,118,105,111,117,115,32,112,97,116,104,32,116,104,114,111,117,103,104,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,115,101,97,114,99,104,101,100,32,102,111,114,32,116,104,101,32,109,111,115,116,32,114,101,99,101,110,116,32,40,42,77,65,82,75,41,32,116,104,97,116,32,104,97,115,32,116,104,101,32,115,97,109,101,32,110,97,109,101,46,32,73,102,32,111,110,101,32,105,115,32,102,111,117,110,100,44,32,116,104,101,32,34,98,117,109,112,97,108,111,110,103,34,32,97,100,118,97,110,99,101,32,105,115,32,116,111,32,116,104,101,32,115,117,98,106,101,99,116,32,112,111,115,105,116,105,111,110,32,116,104,97,116,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,97,116,32,40,42,77,65,82,75,41,32,105,110,115,116,101,97,100,32,111,102,32,116,111,32,119,104,101,114,101,32,40,42,83,75,73,80,41,32,119,97,115,32,101,110,99,111,117,110,116,101,114,101,100,46,32,73,102,32,110,111,32,40,42,77,65,82,75,41,32,119,105,116,104,32,97,32,109,97,116,99,104,105,110,103,32,110,97,109,101,32,105,115,32,102,111,117,110,100,44,32,40,42,83,75,73,80,41,32,105,115,32,105,103,110,111,114,101,100,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,98,121,32,40,42,77,65,82,75,58,78,65,77,69,41,46,32,73,116,32,105,103,110,111,114,101,115,32,110,97,109,101,115,32,116,104,97,116,32,97,114,101,32,115,101,116,32,98,121,32,40,42,80,82,85,78,69,58,78,65,77,69,41,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,118,101,114,98,32,99,97,117,115,101,115,32,97,32,115,107,105,112,32,116,111,32,116,104,101,32,110,101,120,116,32,105,110,110,101,114,109,111,115,116,32,97,108,116,101,114,110,97,116,105,118,101,32,119,104,101,110,32,98,97,99,107,116,114,97,99,107,105,110,103,32,114,101,97,99,104,101,115,32,105,116,46,32,84,104,97,116,32,105,115,44,32,105,116,32,99,97,110,99,101,108,115,32,97,110,121,32,102,117,114,116,104,101,114,32,98,97,99,107,116,114,97,99,107,105,110,103,32,119,105,116,104,105,110,32,116,104,101,32,99,117,114,114,101,110,116,32,97,108,116,101,114,110,97,116,105,118,101,46>>]},{pre,[],[{code,[],[<<40,42,84,72,69,78,41,32,111,114,32,40,42,84,72,69,78,58,78,65,77,69,41>>]}]},{p,[],[<<84,104,101,32,118,101,114,98,32,110,97,109,101,32,99,111,109,101,115,32,102,114,111,109,32,116,104,101,32,111,98,115,101,114,118,97,116,105,111,110,32,116,104,97,116,32,105,116,32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,97,32,112,97,116,116,101,114,110,45,98,97,115,101,100,32,105,102,45,116,104,101,110,45,101,108,115,101,32,98,108,111,99,107,58>>]},{pre,[],[{code,[],[<<40,32,67,79,78,68,49,32,40,42,84,72,69,78,41,32,70,79,79,32,124,32,67,79,78,68,50,32,40,42,84,72,69,78,41,32,66,65,82,32,124,32,67,79,78,68,51,32,40,42,84,72,69,78,41,32,66,65,90,32,41,32,46,46,46>>]}]},{p,[],[<<73,102,32,116,104,101,32,67,79,78,68,49,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,44,32,70,79,79,32,105,115,32,116,114,105,101,100,32,40,97,110,100,32,112,111,115,115,105,98,108,121,32,102,117,114,116,104,101,114,32,105,116,101,109,115,32,97,102,116,101,114,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,103,114,111,117,112,32,105,102,32,70,79,79,32,115,117,99,99,101,101,100,115,41,46,32,79,110,32,102,97,105,108,117,114,101,44,32,116,104,101,32,109,97,116,99,104,101,114,32,115,107,105,112,115,32,116,111,32,116,104,101,32,115,101,99,111,110,100,32,97,108,116,101,114,110,97,116,105,118,101,32,97,110,100,32,116,114,105,101,115,32,67,79,78,68,50,44,32,119,105,116,104,111,117,116,32,98,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,67,79,78,68,49,46,32,73,102,32,116,104,97,116,32,115,117,99,99,101,101,100,115,32,97,110,100,32,66,65,82,32,102,97,105,108,115,44,32,67,79,78,68,51,32,105,115,32,116,114,105,101,100,46,32,73,102,32,66,65,90,32,116,104,101,110,32,102,97,105,108,115,44,32,116,104,101,114,101,32,97,114,101,32,110,111,32,109,111,114,101,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,115,111,32,116,104,101,114,101,32,105,115,32,97,32,98,97,99,107,116,114,97,99,107,32,116,111,32,119,104,97,116,101,118,101,114,32,99,97,109,101,32,98,101,102,111,114,101,32,116,104,101,32,101,110,116,105,114,101,32,103,114,111,117,112,46,32,73,102,32,40,42,84,72,69,78,41,32,105,115,32,110,111,116,32,105,110,115,105,100,101,32,97,110,32,97,108,116,101,114,110,97,116,105,111,110,44,32,105,116,32,97,99,116,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,46>>]},{p,[],[<<84,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,40,42,84,72,69,78,58,78,65,77,69,41,32,105,115,32,116,104,101,32,110,111,116,32,116,104,101,32,115,97,109,101,32,97,115,32,40,42,77,65,82,75,58,78,65,77,69,41,40,42,84,72,69,78,41,46,32,73,116,32,105,115,32,108,105,107,101,32,40,42,77,65,82,75,58,78,65,77,69,41,32,105,110,32,116,104,97,116,32,116,104,101,32,110,97,109,101,32,105,115,32,114,101,109,101,109,98,101,114,101,100,32,102,111,114,32,112,97,115,115,105,110,103,32,98,97,99,107,32,116,111,32,116,104,101,32,99,97,108,108,101,114,46,32,72,111,119,101,118,101,114,44,32,40,42,83,75,73,80,58,78,65,77,69,41,32,115,101,97,114,99,104,101,115,32,111,110,108,121,32,102,111,114,32,110,97,109,101,115,32,115,101,116,32,119,105,116,104,32,40,42,77,65,82,75,41,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,42,84,72,69,78,58,78,65,77,69,41,32,114,101,109,101,109,98,101,114,115,32,116,104,101,32,110,97,109,101,32,105,115,32,117,115,101,108,101,115,115,32,116,111,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,103,114,97,109,109,101,114,44,32,97,115,32,110,97,109,101,115,32,99,97,110,110,111,116,32,98,101,32,114,101,116,114,105,101,118,101,100,46>>]}]},{p,[],[<<65,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,99,111,110,116,97,105,110,32,97,32,124,32,99,104,97,114,97,99,116,101,114,32,105,115,32,106,117,115,116,32,97,32,112,97,114,116,32,111,102,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,59,32,105,116,32,105,115,32,110,111,116,32,97,32,110,101,115,116,101,100,32,97,108,116,101,114,110,97,116,105,111,110,32,119,105,116,104,32,111,110,108,121,32,111,110,101,32,97,108,116,101,114,110,97,116,105,118,101,46,32,84,104,101,32,101,102,102,101,99,116,32,111,102,32,40,42,84,72,69,78,41,32,101,120,116,101,110,100,115,32,98,101,121,111,110,100,32,115,117,99,104,32,97,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,116,104,101,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,101,114,101,32,65,44,32,66,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,99,111,109,112,108,101,120,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,115,32,116,104,97,116,32,100,111,32,110,111,116,32,99,111,110,116,97,105,110,32,97,110,121,32,124,32,99,104,97,114,97,99,116,101,114,115,32,97,116,32,116,104,105,115,32,108,101,118,101,108,58>>]},{pre,[],[{code,[],[<<65,32,40,66,40,42,84,72,69,78,41,67,41,32,124,32,68>>]}]},{p,[],[<<73,102,32,65,32,97,110,100,32,66,32,97,114,101,32,109,97,116,99,104,101,100,44,32,98,117,116,32,116,104,101,114,101,32,105,115,32,97,32,102,97,105,108,117,114,101,32,105,110,32,67,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,65,59,32,105,110,115,116,101,97,100,32,105,116,32,109,111,118,101,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,44,32,116,104,97,116,32,105,115,44,32,68,46,32,72,111,119,101,118,101,114,44,32,105,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,105,110,103,32,40,42,84,72,69,78,41,32,105,115,32,103,105,118,101,110,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,44,32,105,116,32,98,101,104,97,118,101,115,32,100,105,102,102,101,114,101,110,116,108,121,58>>]},{pre,[],[{code,[],[<<65,32,40,66,40,42,84,72,69,78,41,67,32,124,32,40,42,70,65,73,76,41,41,32,124,32,68>>]}]},{p,[],[<<84,104,101,32,101,102,102,101,99,116,32,111,102,32,40,42,84,72,69,78,41,32,105,115,32,110,111,119,32,99,111,110,102,105,110,101,100,32,116,111,32,116,104,101,32,105,110,110,101,114,32,115,117,98,112,97,116,116,101,114,110,46,32,65,102,116,101,114,32,97,32,102,97,105,108,117,114,101,32,105,110,32,67,44,32,109,97,116,99,104,105,110,103,32,109,111,118,101,115,32,116,111,32,40,42,70,65,73,76,41,44,32,119,104,105,99,104,32,99,97,117,115,101,115,32,116,104,101,32,119,104,111,108,101,32,115,117,98,112,97,116,116,101,114,110,32,116,111,32,102,97,105,108,44,32,97,115,32,116,104,101,114,101,32,97,114,101,32,110,111,32,109,111,114,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,116,111,32,116,114,121,46,32,73,110,32,116,104,105,115,32,99,97,115,101,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,119,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,65,46>>]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,111,116,32,99,111,110,115,105,100,101,114,101,100,32,97,115,32,104,97,118,105,110,103,32,116,119,111,32,97,108,116,101,114,110,97,116,105,118,101,115,44,32,97,115,32,111,110,108,121,32,111,110,101,32,105,115,32,101,118,101,114,32,117,115,101,100,46,32,84,104,97,116,32,105,115,44,32,116,104,101,32,124,32,99,104,97,114,97,99,116,101,114,32,105,110,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,104,97,115,32,97,32,100,105,102,102,101,114,101,110,116,32,109,101,97,110,105,110,103,46,32,73,103,110,111,114,105,110,103,32,119,104,105,116,101,115,112,97,99,101,44,32,99,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<94,46,42,63,32,40,63,40,63,61,97,41,32,97,32,124,32,98,40,42,84,72,69,78,41,99,32,41>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,98,97,34,44,32,116,104,105,115,32,112,97,116,116,101,114,110,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,46,32,65,115,32,46,42,63,32,105,115,32,117,110,103,114,101,101,100,121,44,32,105,116,32,105,110,105,116,105,97,108,108,121,32,109,97,116,99,104,101,115,32,122,101,114,111,32,99,104,97,114,97,99,116,101,114,115,46,32,84,104,101,32,99,111,110,100,105,116,105,111,110,32,40,63,61,97,41,32,116,104,101,110,32,102,97,105,108,115,44,32,116,104,101,32,99,104,97,114,97,99,116,101,114,32,34,98,34,32,105,115,32,109,97,116,99,104,101,100,44,32,98,117,116,32,34,99,34,32,105,115,32,110,111,116,46,32,65,116,32,116,104,105,115,32,112,111,105,110,116,44,32,109,97,116,99,104,105,110,103,32,100,111,101,115,32,110,111,116,32,98,97,99,107,116,114,97,99,107,32,116,111,32,46,42,63,32,97,115,32,99,97,110,32,112,101,114,104,97,112,115,32,98,101,32,101,120,112,101,99,116,101,100,32,102,114,111,109,32,116,104,101,32,112,114,101,115,101,110,99,101,32,111,102,32,116,104,101,32,124,32,99,104,97,114,97,99,116,101,114,46,32,84,104,101,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,112,97,114,116,32,111,102,32,116,104,101,32,115,105,110,103,108,101,32,97,108,116,101,114,110,97,116,105,118,101,32,116,104,97,116,32,99,111,109,112,114,105,115,101,115,32,116,104,101,32,119,104,111,108,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,115,111,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,46,32,40,73,102,32,116,104,101,114,101,32,119,97,115,32,97,32,98,97,99,107,116,114,97,99,107,32,105,110,116,111,32,46,42,63,44,32,97,108,108,111,119,105,110,103,32,105,116,32,116,111,32,109,97,116,99,104,32,34,98,34,44,32,116,104,101,32,109,97,116,99,104,32,119,111,117,108,100,32,115,117,99,99,101,101,100,46,41>>]},{p,[],[<<84,104,101,32,118,101,114,98,115,32,100,101,115,99,114,105,98,101,100,32,97,98,111,118,101,32,112,114,111,118,105,100,101,32,102,111,117,114,32,100,105,102,102,101,114,101,110,116,32,34,115,116,114,101,110,103,116,104,115,34,32,111,102,32,99,111,110,116,114,111,108,32,119,104,101,110,32,115,117,98,115,101,113,117,101,110,116,32,109,97,116,99,104,105,110,103,32,102,97,105,108,115,58>>]},{ul,[],[{li,[],[{p,[],[<<40,42,84,72,69,78,41,32,105,115,32,116,104,101,32,119,101,97,107,101,115,116,44,32,99,97,114,114,121,105,110,103,32,111,110,32,116,104,101,32,109,97,116,99,104,32,97,116,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,46>>]}]},{li,[],[{p,[],[<<40,42,80,82,85,78,69,41,32,99,111,109,101,115,32,110,101,120,116,44,32,102,97,105,108,115,32,116,104,101,32,109,97,116,99,104,32,97,116,32,116,104,101,32,99,117,114,114,101,110,116,32,115,116,97,114,116,105,110,103,32,112,111,115,105,116,105,111,110,44,32,98,117,116,32,97,108,108,111,119,115,32,97,110,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40,102,111,114,32,97,110,32,117,110,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,41,46>>]}]},{li,[],[{p,[],[<<40,42,83,75,73,80,41,32,105,115,32,115,105,109,105,108,97,114,44,32,101,120,99,101,112,116,32,116,104,97,116,32,116,104,101,32,97,100,118,97,110,99,101,32,99,97,110,32,98,101,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,99,104,97,114,97,99,116,101,114,46>>]}]},{li,[],[{p,[],[<<40,42,67,79,77,77,73,84,41,32,105,115,32,116,104,101,32,115,116,114,111,110,103,101,115,116,44,32,99,97,117,115,105,110,103,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]}]},{p,[],[{em,[],[<<77,111,114,101,32,116,104,97,110,32,79,110,101,32,66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98>>]}]},{p,[],[<<73,102,32,109,111,114,101,32,116,104,97,110,32,111,110,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,32,105,115,32,112,114,101,115,101,110,116,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,116,104,101,32,111,110,101,32,116,104,97,116,32,105,115,32,98,97,99,107,116,114,97,99,107,101,100,32,111,110,116,111,32,102,105,114,115,116,32,97,99,116,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,44,32,119,104,101,114,101,32,65,44,32,66,44,32,97,110,100,32,115,111,32,111,110,44,32,97,114,101,32,99,111,109,112,108,101,120,32,112,97,116,116,101,114,110,32,102,114,97,103,109,101,110,116,115,58>>]},{pre,[],[{code,[],[<<40,65,40,42,67,79,77,77,73,84,41,66,40,42,84,72,69,78,41,67,124,65,66,68,41>>]}]},{p,[],[<<73,102,32,65,32,109,97,116,99,104,101,115,32,98,117,116,32,66,32,102,97,105,108,115,44,32,116,104,101,32,98,97,99,107,116,114,97,99,107,32,116,111,32,40,42,67,79,77,77,73,84,41,32,99,97,117,115,101,115,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46,32,72,111,119,101,118,101,114,44,32,105,102,32,65,32,97,110,100,32,66,32,109,97,116,99,104,44,32,98,117,116,32,67,32,102,97,105,108,115,44,32,116,104,101,32,98,97,99,107,116,114,97,99,107,32,116,111,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,40,65,66,68,41,32,116,111,32,98,101,32,116,114,105,101,100,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,105,115,32,99,111,110,115,105,115,116,101,110,116,44,32,98,117,116,32,105,115,32,110,111,116,32,97,108,119,97,121,115,32,116,104,101,32,115,97,109,101,32,97,115,32,105,110,32,80,101,114,108,46,32,73,116,32,109,101,97,110,115,32,116,104,97,116,32,105,102,32,116,119,111,32,111,114,32,109,111,114,101,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,112,112,101,97,114,32,105,110,32,115,117,99,99,101,115,115,105,111,110,44,32,116,104,101,32,108,97,115,116,32,111,102,32,116,104,101,109,32,104,97,115,32,110,111,32,101,102,102,101,99,116,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<46,46,46,40,42,67,79,77,77,73,84,41,40,42,80,82,85,78,69,41,46,46,46>>]}]},{p,[],[<<73,102,32,116,104,101,114,101,32,105,115,32,97,32,109,97,116,99,104,105,110,103,32,102,97,105,108,117,114,101,32,116,111,32,116,104,101,32,114,105,103,104,116,44,32,98,97,99,107,116,114,97,99,107,105,110,103,32,111,110,116,111,32,40,42,80,82,85,78,69,41,32,99,97,117,115,101,115,32,105,116,32,116,111,32,98,101,32,116,114,105,103,103,101,114,101,100,44,32,97,110,100,32,105,116,115,32,97,99,116,105,111,110,32,105,115,32,116,97,107,101,110,46,32,84,104,101,114,101,32,99,97,110,32,110,101,118,101,114,32,98,101,32,97,32,98,97,99,107,116,114,97,99,107,32,111,110,116,111,32,40,42,67,79,77,77,73,84,41,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,82,101,112,101,97,116,101,100,32,71,114,111,117,112,115>>]}]},{p,[],[<<80,67,82,69,32,100,105,102,102,101,114,115,32,102,114,111,109,32,80,101,114,108,32,105,110,32,105,116,115,32,104,97,110,100,108,105,110,103,32,111,102,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,105,110,32,114,101,112,101,97,116,101,100,32,103,114,111,117,112,115,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,58>>]},{pre,[],[{code,[],[<<47,40,97,40,42,67,79,77,77,73,84,41,98,41,43,97,99,47>>]}]},{p,[],[<<73,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,34,97,98,97,99,34,44,32,80,101,114,108,32,109,97,116,99,104,101,115,44,32,98,117,116,32,80,67,82,69,32,102,97,105,108,115,32,98,101,99,97,117,115,101,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,114,101,112,101,97,116,32,111,102,32,116,104,101,32,103,114,111,117,112,32,97,99,116,115,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,65,115,115,101,114,116,105,111,110,115>>]}]},{p,[],[<<40,42,70,65,73,76,41,32,105,110,32,97,110,32,97,115,115,101,114,116,105,111,110,32,104,97,115,32,105,116,115,32,110,111,114,109,97,108,32,101,102,102,101,99,116,58,32,105,116,32,102,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,98,97,99,107,116,114,97,99,107,46>>]},{p,[],[<<40,42,65,67,67,69,80,84,41,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,97,117,115,101,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,115,117,99,99,101,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46,32,73,110,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,44,32,40,42,65,67,67,69,80,84,41,32,99,97,117,115,101,115,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,102,97,105,108,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46>>]},{p,[],[<<84,104,101,32,111,116,104,101,114,32,98,97,99,107,116,114,97,99,107,105,110,103,32,118,101,114,98,115,32,97,114,101,32,110,111,116,32,116,114,101,97,116,101,100,32,115,112,101,99,105,97,108,108,121,32,105,102,32,116,104,101,121,32,97,112,112,101,97,114,32,105,110,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,46,32,73,110,32,112,97,114,116,105,99,117,108,97,114,44,32,40,42,84,72,69,78,41,32,115,107,105,112,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,105,110,110,101,114,109,111,115,116,32,101,110,99,108,111,115,105,110,103,32,103,114,111,117,112,32,116,104,97,116,32,104,97,115,32,97,108,116,101,114,110,97,116,105,111,110,115,44,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,116,104,105,115,32,105,115,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,46>>]},{p,[],[<<78,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,115,32,97,114,101,44,32,104,111,119,101,118,101,114,44,32,100,105,102,102,101,114,101,110,116,44,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,99,104,97,110,103,105,110,103,32,97,32,112,111,115,105,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,105,110,116,111,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,99,104,97,110,103,101,115,32,105,116,115,32,114,101,115,117,108,116,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,40,42,67,79,77,77,73,84,41,44,32,40,42,83,75,73,80,41,44,32,111,114,32,40,42,80,82,85,78,69,41,32,99,97,117,115,101,115,32,97,32,110,101,103,97,116,105,118,101,32,97,115,115,101,114,116,105,111,110,32,116,111,32,98,101,32,116,114,117,101,44,32,119,105,116,104,111,117,116,32,99,111,110,115,105,100,101,114,105,110,103,32,97,110,121,32,102,117,114,116,104,101,114,32,97,108,116,101,114,110,97,116,105,118,101,32,98,114,97,110,99,104,101,115,32,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,46,32,66,97,99,107,116,114,97,99,107,105,110,103,32,105,110,116,111,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,105,116,32,116,111,32,115,107,105,112,32,116,111,32,116,104,101,32,110,101,120,116,32,101,110,99,108,111,115,105,110,103,32,97,108,116,101,114,110,97,116,105,118,101,32,119,105,116,104,105,110,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,40,116,104,101,32,110,111,114,109,97,108,32,98,101,104,97,118,105,111,114,41,44,32,98,117,116,32,105,102,32,116,104,101,32,97,115,115,101,114,116,105,111,110,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,115,117,99,104,32,97,110,32,97,108,116,101,114,110,97,116,105,118,101,44,32,40,42,84,72,69,78,41,32,98,101,104,97,118,101,115,32,108,105,107,101,32,40,42,80,82,85,78,69,41,46>>]},{p,[],[{em,[],[<<66,97,99,107,116,114,97,99,107,105,110,103,32,86,101,114,98,115,32,105,110,32,83,117,98,114,111,117,116,105,110,101,115>>]}]},{p,[],[<<84,104,101,115,101,32,98,101,104,97,118,105,111,114,115,32,111,99,99,117,114,32,114,101,103,97,114,100,108,101,115,115,32,105,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,99,97,108,108,101,100,32,114,101,99,117,114,115,105,118,101,108,121,46,32,84,104,101,32,116,114,101,97,116,109,101,110,116,32,111,102,32,115,117,98,114,111,117,116,105,110,101,115,32,105,110,32,80,101,114,108,32,105,115,32,100,105,102,102,101,114,101,110,116,32,105,110,32,115,111,109,101,32,99,97,115,101,115,46>>]},{ul,[],[{li,[],[{p,[],[<<40,42,70,65,73,76,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,104,97,115,32,105,116,115,32,110,111,114,109,97,108,32,101,102,102,101,99,116,58,32,105,116,32,102,111,114,99,101,115,32,97,110,32,105,109,109,101,100,105,97,116,101,32,98,97,99,107,116,114,97,99,107,46>>]}]},{li,[],[{p,[],[<<40,42,65,67,67,69,80,84,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,117,115,101,115,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,115,117,99,99,101,101,100,32,119,105,116,104,111,117,116,32,97,110,121,32,102,117,114,116,104,101,114,32,112,114,111,99,101,115,115,105,110,103,46,32,77,97,116,99,104,105,110,103,32,116,104,101,110,32,99,111,110,116,105,110,117,101,115,32,97,102,116,101,114,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,99,97,108,108,46>>]}]},{li,[],[{p,[],[<<40,42,67,79,77,77,73,84,41,44,32,40,42,83,75,73,80,41,44,32,97,110,100,32,40,42,80,82,85,78,69,41,32,105,110,32,97,32,115,117,98,112,97,116,116,101,114,110,32,99,97,108,108,101,100,32,97,115,32,97,32,115,117,98,114,111,117,116,105,110,101,32,99,97,117,115,101,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]},{li,[],[{p,[],[<<40,42,84,72,69,78,41,32,115,107,105,112,115,32,116,111,32,116,104,101,32,110,101,120,116,32,97,108,116,101,114,110,97,116,105,118,101,32,105,110,32,116,104,101,32,105,110,110,101,114,109,111,115,116,32,101,110,99,108,111,115,105,110,103,32,103,114,111,117,112,32,119,105,116,104,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,116,104,97,116,32,104,97,115,32,97,108,116,101,114,110,97,116,105,118,101,115,46,32,73,102,32,116,104,101,114,101,32,105,115,32,110,111,32,115,117,99,104,32,103,114,111,117,112,32,119,105,116,104,105,110,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,44,32,40,42,84,72,69,78,41,32,99,97,117,115,101,115,32,116,104,101,32,115,117,98,114,111,117,116,105,110,101,32,109,97,116,99,104,32,116,111,32,102,97,105,108,46>>]}]}]}]},#{name => <<114,101>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,114,101,46,120,109,108],types => #{{compile_option,0} => {attribute,{27,2},type,{compile_option,{type,{27,27},union,[{atom,{27,27},unicode},{atom,{27,37},anchored},{atom,{27,48},caseless},{atom,{27,59},dollar_endonly},{atom,{28,27},dotall},{atom,{28,36},extended},{atom,{28,47},firstline},{atom,{28,59},multiline},{atom,{29,27},no_auto_capture},{atom,{29,45},dupnames},{atom,{29,56},ungreedy},{type,{30,27},tuple,[{atom,{30,28},newline},{user_type,{30,37},nl_spec,[]}]},{atom,{31,27},bsr_anycrlf},{atom,{31,41},bsr_unicode},{atom,{32,27},no_start_optimize},{atom,{32,47},ucp},{atom,{32,53},never_utf}]},[]}},{mp,0} => {attribute,{23,2},type,{mp,{type,{23,15},tuple,[{atom,{23,16},re_pattern},{var,{23,28},'_'},{var,{23,31},'_'},{var,{23,34},'_'},{var,{23,37},'_'}]},[]}},{nl_spec,0} => {attribute,{25,2},type,{nl_spec,{type,{25,20},union,[{atom,{25,20},cr},{atom,{25,25},crlf},{atom,{25,32},lf},{atom,{25,37},anycrlf},{atom,{25,47},any}]},[]}},{replace_fun,0} => {attribute,{34,2},type,{replace_fun,{type,{34,28},'fun',[{type,{34,28},product,[{type,{34,29},binary,[]},{type,{34,39},list,[{type,{34,40},binary,[]}]}]},{type,{34,54},union,[{type,{34,54},iodata,[]},{remote_type,{34,65},[{atom,{34,65},unicode},{atom,{34,73},charlist},[]]}]}]},[]}}}},[{{function,grun,3},[{file,[114,101,46,101,114,108]},{location,0}],[<<103,114,117,110,47,51>>],hidden,#{}},{{function,internal_run,4},[{file,[114,101,46,101,114,108]},{location,0}],[<<105,110,116,101,114,110,97,108,95,114,117,110,47,52>>],hidden,#{}},{{function,ucompile,2},[{file,[114,101,46,101,114,108]},{location,0}],[<<117,99,111,109,112,105,108,101,47,50>>],hidden,#{}},{{function,urun,3},[{file,[114,101,46,101,114,108]},{location,0}],[<<117,114,117,110,47,51>>],hidden,#{}},{{function,version,0},[{file,[114,101,46,101,114,108]},{location,42}],[<<118,101,114,115,105,111,110,47,48>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,111,102,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,97,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,80,67,82,69,32,118,101,114,115,105,111,110,32,111,102,32,116,104,101,32,115,121,115,116,101,109,32,116,104,97,116,32,119,97,115,32,117,115,101,100,32,105,110,32,116,104,101,32,69,114,108,97,110,103,47,79,84,80,32,99,111,109,112,105,108,97,116,105,111,110,46>>]}]},#{signature => [{attribute,{42,2},spec,{{version,0},[{type,{42,14},'fun',[{type,{42,14},product,[]},{type,{42,20},binary,[]}]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,56,52>>,since => <<79,84,80,32,50,48,46,48>>}},{{function,compile,1},[{file,[114,101,46,101,114,108]},{location,51}],[<<99,111,109,112,105,108,101,47,49>>],#{<<101,110>> => [{p,[],[<<84,104,101,32,115,97,109,101,32,97,115,32>>,{code,[],[<<99,111,109,112,105,108,101,40,82,101,103,101,120,112,44,91,93,41>>]}]}]},#{signature => [{attribute,{51,2},spec,{{compile,1},[{type,{51,14},bounded_fun,[{type,{51,14},'fun',[{type,{51,14},product,[{var,{51,15},'Regexp'}]},{type,{51,26},union,[{type,{51,26},tuple,[{atom,{51,27},ok},{var,{51,31},'MP'}]},{type,{51,37},tuple,[{atom,{51,38},error},{var,{51,45},'ErrSpec'}]}]}]},[{type,{52,7},constraint,[{atom,{52,7},is_subtype},[{var,{52,7},'Regexp'},{type,{52,17},iodata,[]}]]},{type,{53,7},constraint,[{atom,{53,7},is_subtype},[{var,{53,7},'MP'},{user_type,{53,13},mp,[]}]]},{type,{54,7},constraint,[{atom,{54,7},is_subtype},[{var,{54,7},'ErrSpec'},{type,{54,18},tuple,[{ann_type,{54,19},[{var,{54,19},'ErrString'},{type,{54,32},string,[]}]},{ann_type,{54,42},[{var,{54,42},'Position'},{type,{54,54},non_neg_integer,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,57,50>>}},{{function,compile,2},[{file,[114,101,46,101,114,108]},{location,59}],[<<99,111,109,112,105,108,101,47,50>>],#{<<101,110>> => [{p,[],[<<67,111,109,112,105,108,101,115,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,119,105,116,104,32,116,104,101,32,115,121,110,116,97,120,32,100,101,115,99,114,105,98,101,100,32,98,101,108,111,119,44,32,105,110,116,111,32,97,110,32,105,110,116,101,114,110,97,108,32,102,111,114,109,97,116,32,116,111,32,98,101,32,117,115,101,100,32,108,97,116,101,114,32,97,115,32,97,32,112,97,114,97,109,101,116,101,114,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46>>]},{p,[],[<<67,111,109,112,105,108,105,110,103,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,98,101,102,111,114,101,32,109,97,116,99,104,105,110,103,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,115,97,109,101,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,109,97,116,99,104,105,110,103,32,97,103,97,105,110,115,116,32,109,117,108,116,105,112,108,101,32,115,117,98,106,101,99,116,115,32,100,117,114,105,110,103,32,116,104,101,32,108,105,102,101,116,105,109,101,32,111,102,32,116,104,101,32,112,114,111,103,114,97,109,46,32,67,111,109,112,105,108,105,110,103,32,111,110,99,101,32,97,110,100,32,101,120,101,99,117,116,105,110,103,32,109,97,110,121,32,116,105,109,101,115,32,105,115,32,102,97,114,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,99,111,109,112,105,108,105,110,103,32,101,97,99,104,32,116,105,109,101,32,111,110,101,32,119,97,110,116,115,32,116,111,32,109,97,116,99,104,46>>]},{p,[],[<<87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,97,115,32,97,110,121,32,118,97,108,105,100,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<46>>]},{a,[{id,<<99,111,109,112,105,108,101,95,111,112,116,105,111,110,115>>}],[]},{p,[],[<<79,112,116,105,111,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,111,100,101,32,105,115,32,116,111,32,98,101,32,114,117,110,32,97,103,97,105,110,115,116,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<32,115,117,98,106,101,99,116,46,32,65,108,115,111,32,99,111,110,115,105,100,101,114,32,111,112,116,105,111,110,32>>,{code,[],[<<117,99,112>>]},<<32,119,104,101,110,32,117,115,105,110,103,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{dt,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{dd,[],[{p,[],[<<84,104,101,32,112,97,116,116,101,114,110,32,105,115,32,102,111,114,99,101,100,32,116,111,32,98,101,32,34,97,110,99,104,111,114,101,100,34,44,32,116,104,97,116,32,105,115,44,32,105,116,32,105,115,32,99,111,110,115,116,114,97,105,110,101,100,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,105,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,32,116,104,97,116,32,105,115,32,115,101,97,114,99,104,101,100,32,40,116,104,101,32,34,115,117,98,106,101,99,116,32,115,116,114,105,110,103,34,41,46,32,84,104,105,115,32,101,102,102,101,99,116,32,99,97,110,32,97,108,115,111,32,98,101,32,97,99,104,105,101,118,101,100,32,98,121,32,97,112,112,114,111,112,114,105,97,116,101,32,99,111,110,115,116,114,117,99,116,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,105,116,115,101,108,102,46>>]}]},{dt,[],[{code,[],[<<99,97,115,101,108,101,115,115>>]}]},{dd,[],[{p,[],[<<76,101,116,116,101,114,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,98,111,116,104,32,117,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115,46,32,73,116,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,105>>]},<<32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,105,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,85,112,112,101,114,99,97,115,101,32,97,110,100,32,108,111,119,101,114,99,97,115,101,32,108,101,116,116,101,114,115,32,97,114,101,32,100,101,102,105,110,101,100,32,97,115,32,105,110,32,116,104,101,32,73,83,79,32,56,56,53,57,45,49,32,99,104,97,114,97,99,116,101,114,32,115,101,116,46>>]}]},{dt,[],[{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]}]},{dd,[],[{p,[],[<<65,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,87,105,116,104,111,117,116,32,116,104,105,115,32,111,112,116,105,111,110,44,32,97,32,100,111,108,108,97,114,32,97,108,115,111,32,109,97,116,99,104,101,115,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,97,32,110,101,119,108,105,110,101,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,40,98,117,116,32,110,111,116,32,98,101,102,111,114,101,32,97,110,121,32,111,116,104,101,114,32,110,101,119,108,105,110,101,115,41,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,105,103,110,111,114,101,100,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,114,101,32,105,115,32,110,111,32,101,113,117,105,118,97,108,101,110,116,32,111,112,116,105,111,110,32,105,110,32,80,101,114,108,44,32,97,110,100,32,105,116,32,99,97,110,110,111,116,32,98,101,32,115,101,116,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<100,111,116,97,108,108>>]}]},{dd,[],[{p,[],[<<65,32,100,111,116,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,97,108,108,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,99,108,117,100,105,110,103,32,116,104,111,115,101,32,105,110,100,105,99,97,116,105,110,103,32,110,101,119,108,105,110,101,46,32,87,105,116,104,111,117,116,32,105,116,44,32,97,32,100,111,116,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,119,104,101,110,32,116,104,101,32,99,117,114,114,101,110,116,32,112,111,115,105,116,105,111,110,32,105,115,32,97,116,32,97,32,110,101,119,108,105,110,101,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,115>>]},<<32,97,110,100,32,105,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,115,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,65,32,110,101,103,97,116,105,118,101,32,99,108,97,115,115,44,32,115,117,99,104,32,97,115,32>>,{code,[],[<<91,94,97,93>>]},<<44,32,97,108,119,97,121,115,32,109,97,116,99,104,101,115,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,44,32,105,110,100,101,112,101,110,100,101,110,116,32,111,102,32,116,104,101,32,115,101,116,116,105,110,103,32,111,102,32,116,104,105,115,32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<101,120,116,101,110,100,101,100>>]}]},{dd,[],[{p,[],[<<73,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,101,116,44,32,109,111,115,116,32,119,104,105,116,101,32,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,97,114,101,32,116,111,116,97,108,108,121,32,105,103,110,111,114,101,100,32,101,120,99,101,112,116,32,119,104,101,110,32,101,115,99,97,112,101,100,32,111,114,32,105,110,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,46,32,72,111,119,101,118,101,114,44,32,119,104,105,116,101,32,115,112,97,99,101,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,32,119,105,116,104,105,110,32,115,101,113,117,101,110,99,101,115,32,115,117,99,104,32,97,115,32>>,{code,[],[<<40,63,62>>]},<<32,116,104,97,116,32,105,110,116,114,111,100,117,99,101,32,118,97,114,105,111,117,115,32,112,97,114,101,110,116,104,101,115,105,122,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,110,111,114,32,119,105,116,104,105,110,32,97,32,110,117,109,101,114,105,99,97,108,32,113,117,97,110,116,105,102,105,101,114,32,115,117,99,104,32,97,115,32>>,{code,[],[<<123,49,44,51,125>>]},<<46,32,72,111,119,101,118,101,114,44,32,105,103,110,111,114,97,98,108,101,32,119,104,105,116,101,32,115,112,97,99,101,32,105,115,32,112,101,114,109,105,116,116,101,100,32,98,101,116,119,101,101,110,32,97,110,32,105,116,101,109,32,97,110,100,32,97,32,102,111,108,108,111,119,105,110,103,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,98,101,116,119,101,101,110,32,97,32,113,117,97,110,116,105,102,105,101,114,32,97,110,100,32,97,32,102,111,108,108,111,119,105,110,103,32,43,32,116,104,97,116,32,105,110,100,105,99,97,116,101,115,32,112,111,115,115,101,115,115,105,118,101,110,101,115,115,46>>]},{p,[],[<<87,104,105,116,101,32,115,112,97,99,101,32,100,105,100,32,110,111,116,32,117,115,101,100,32,116,111,32,105,110,99,108,117,100,101,32,116,104,101,32,86,84,32,99,104,97,114,97,99,116,101,114,32,40,99,111,100,101,32,49,49,41,44,32,98,101,99,97,117,115,101,32,80,101,114,108,32,100,105,100,32,110,111,116,32,116,114,101,97,116,32,116,104,105,115,32,99,104,97,114,97,99,116,101,114,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,46,32,72,111,119,101,118,101,114,44,32,80,101,114,108,32,99,104,97,110,103,101,100,32,97,116,32,114,101,108,101,97,115,101,32,53,46,49,56,44,32,115,111,32,80,67,82,69,32,102,111,108,108,111,119,101,100,32,97,116,32,114,101,108,101,97,115,101,32,56,46,51,52,44,32,97,110,100,32,86,84,32,105,115,32,110,111,119,32,116,114,101,97,116,101,100,32,97,115,32,119,104,105,116,101,32,115,112,97,99,101,46>>]},{p,[],[<<84,104,105,115,32,97,108,115,111,32,99,97,117,115,101,115,32,99,104,97,114,97,99,116,101,114,115,32,98,101,116,119,101,101,110,32,97,110,32,117,110,101,115,99,97,112,101,100,32,35,32,111,117,116,115,105,100,101,32,97,32,99,104,97,114,97,99,116,101,114,32,99,108,97,115,115,32,97,110,100,32,116,104,101,32,110,101,120,116,32,110,101,119,108,105,110,101,44,32,105,110,99,108,117,115,105,118,101,44,32,116,111,32,98,101,32,105,103,110,111,114,101,100,46,32,84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,39,115,32>>,{code,[],[<<47,120>>]},<<32,111,112,116,105,111,110,44,32,97,110,100,32,105,116,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,120,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46>>]},{p,[],[<<87,105,116,104,32,116,104,105,115,32,111,112,116,105,111,110,44,32,99,111,109,109,101,110,116,115,32,105,110,115,105,100,101,32,99,111,109,112,108,105,99,97,116,101,100,32,112,97,116,116,101,114,110,115,32,99,97,110,32,98,101,32,105,110,99,108,117,100,101,100,46,32,72,111,119,101,118,101,114,44,32,110,111,116,105,99,101,32,116,104,97,116,32,116,104,105,115,32,97,112,112,108,105,101,115,32,111,110,108,121,32,116,111,32,100,97,116,97,32,99,104,97,114,97,99,116,101,114,115,46,32,87,104,105,116,101,115,112,97,99,101,32,99,104,97,114,97,99,116,101,114,115,32,99,97,110,32,110,101,118,101,114,32,97,112,112,101,97,114,32,119,105,116,104,105,110,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,32,115,101,113,117,101,110,99,101,115,32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,102,111,114,32,101,120,97,109,112,108,101,32,119,105,116,104,105,110,32,115,101,113,117,101,110,99,101,32>>,{code,[],[<<40,63,40>>]},<<32,116,104,97,116,32,105,110,116,114,111,100,117,99,101,115,32,97,32,99,111,110,100,105,116,105,111,110,97,108,32,115,117,98,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<102,105,114,115,116,108,105,110,101>>]}]},{dd,[],[{p,[],[<<65,110,32,117,110,97,110,99,104,111,114,101,100,32,112,97,116,116,101,114,110,32,105,115,32,114,101,113,117,105,114,101,100,32,116,111,32,109,97,116,99,104,32,98,101,102,111,114,101,32,111,114,32,97,116,32,116,104,101,32,102,105,114,115,116,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,97,108,116,104,111,117,103,104,32,116,104,101,32,109,97,116,99,104,101,100,32,116,101,120,116,32,99,97,110,32,99,111,110,116,105,110,117,101,32,111,118,101,114,32,116,104,101,32,110,101,119,108,105,110,101,46>>]}]},{dt,[],[{code,[],[<<109,117,108,116,105,108,105,110,101>>]}]},{dd,[],[{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,80,67,82,69,32,116,114,101,97,116,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,97,115,32,99,111,110,115,105,115,116,105,110,103,32,111,102,32,97,32,115,105,110,103,108,101,32,108,105,110,101,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,101,118,101,110,32,105,102,32,105,116,32,99,111,110,116,97,105,110,115,32,110,101,119,108,105,110,101,115,41,46,32,84,104,101,32,34,115,116,97,114,116,32,111,102,32,108,105,110,101,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<94>>]},<<41,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,119,104,105,108,101,32,116,104,101,32,34,101,110,100,32,111,102,32,108,105,110,101,34,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<36>>]},<<41,32,109,97,116,99,104,101,115,32,111,110,108,121,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,111,114,32,98,101,102,111,114,101,32,97,32,116,101,114,109,105,110,97,116,105,110,103,32,110,101,119,108,105,110,101,32,40,117,110,108,101,115,115,32,111,112,116,105,111,110,32>>,{code,[],[<<100,111,108,108,97,114,95,101,110,100,111,110,108,121>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,41,46,32,84,104,105,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,105,110,32,80,101,114,108,46>>]},{p,[],[<<87,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,34,115,116,97,114,116,32,111,102,32,108,105,110,101,34,32,97,110,100,32,34,101,110,100,32,111,102,32,108,105,110,101,34,32,99,111,110,115,116,114,117,99,116,115,32,109,97,116,99,104,32,105,109,109,101,100,105,97,116,101,108,121,32,102,111,108,108,111,119,105,110,103,32,111,114,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,105,110,116,101,114,110,97,108,32,110,101,119,108,105,110,101,115,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,97,115,32,119,101,108,108,32,97,115,32,97,116,32,116,104,101,32,118,101,114,121,32,115,116,97,114,116,32,97,110,100,32,101,110,100,46,32,84,104,105,115,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,80,101,114,108,32,111,112,116,105,111,110,32>>,{code,[],[<<47,109>>]},<<32,97,110,100,32,99,97,110,32,98,101,32,99,104,97,110,103,101,100,32,119,105,116,104,105,110,32,97,32,112,97,116,116,101,114,110,32,98,121,32,97,32>>,{code,[],[<<40,63,109,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,46,32,73,102,32,116,104,101,114,101,32,97,114,101,32,110,111,32,110,101,119,108,105,110,101,115,32,105,110,32,97,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,111,114,32,110,111,32,111,99,99,117,114,114,101,110,99,101,115,32,111,102,32>>,{code,[],[<<94>>]},<<32,111,114,32>>,{code,[],[<<36>>]},<<32,105,110,32,97,32,112,97,116,116,101,114,110,44,32,115,101,116,116,105,110,103,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,104,97,115,32,110,111,32,101,102,102,101,99,116,46>>]}]},{dt,[],[{code,[],[<<110,111,95,97,117,116,111,95,99,97,112,116,117,114,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,116,104,101,32,117,115,101,32,111,102,32,110,117,109,98,101,114,101,100,32,99,97,112,116,117,114,105,110,103,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46,32,65,110,121,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,116,104,97,116,32,105,115,32,110,111,116,32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<63>>]},<<32,98,101,104,97,118,101,115,32,97,115,32,105,102,32,105,116,32,105,115,32,102,111,108,108,111,119,101,100,32,98,121,32>>,{code,[],[<<63,58>>]},<<46,32,78,97,109,101,100,32,112,97,114,101,110,116,104,101,115,101,115,32,99,97,110,32,115,116,105,108,108,32,98,101,32,117,115,101,100,32,102,111,114,32,99,97,112,116,117,114,105,110,103,32,40,97,110,100,32,116,104,101,121,32,97,99,113,117,105,114,101,32,110,117,109,98,101,114,115,32,105,110,32,116,104,101,32,117,115,117,97,108,32,119,97,121,41,46,32,84,104,101,114,101,32,105,115,32,110,111,32,101,113,117,105,118,97,108,101,110,116,32,111,112,116,105,111,110,32,105,110,32,80,101,114,108,46>>]}]},{dt,[],[{code,[],[<<100,117,112,110,97,109,101,115>>]}]},{dd,[],[{p,[],[<<78,97,109,101,115,32,117,115,101,100,32,116,111,32,105,100,101,110,116,105,102,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,110,101,101,100,32,110,111,116,32,98,101,32,117,110,105,113,117,101,46,32,84,104,105,115,32,99,97,110,32,98,101,32,104,101,108,112,102,117,108,32,102,111,114,32,99,101,114,116,97,105,110,32,116,121,112,101,115,32,111,102,32,112,97,116,116,101,114,110,32,119,104,101,110,32,105,116,32,105,115,32,107,110,111,119,110,32,116,104,97,116,32,111,110,108,121,32,111,110,101,32,105,110,115,116,97,110,99,101,32,111,102,32,116,104,101,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,101,118,101,114,32,98,101,32,109,97,116,99,104,101,100,46,32,77,111,114,101,32,100,101,116,97,105,108,115,32,111,102,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,112,114,111,118,105,100,101,100,32,98,101,108,111,119,46>>]}]},{dt,[],[{code,[],[<<117,110,103,114,101,101,100,121>>]}]},{dd,[],[{p,[],[<<73,110,118,101,114,116,115,32,116,104,101,32,34,103,114,101,101,100,105,110,101,115,115,34,32,111,102,32,116,104,101,32,113,117,97,110,116,105,102,105,101,114,115,32,115,111,32,116,104,97,116,32,116,104,101,121,32,97,114,101,32,110,111,116,32,103,114,101,101,100,121,32,98,121,32,100,101,102,97,117,108,116,44,32,98,117,116,32,98,101,99,111,109,101,32,103,114,101,101,100,121,32,105,102,32,102,111,108,108,111,119,101,100,32,98,121,32,34,63,34,46,32,73,116,32,105,115,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,32,80,101,114,108,46,32,73,116,32,99,97,110,32,97,108,115,111,32,98,101,32,115,101,116,32,98,121,32,97,32>>,{code,[],[<<40,63,85,41>>]},<<32,111,112,116,105,111,110,32,115,101,116,116,105,110,103,32,119,105,116,104,105,110,32,116,104,101,32,112,97,116,116,101,114,110,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{dd,[],[{p,[],[<<79,118,101,114,114,105,100,101,115,32,116,104,101,32,100,101,102,97,117,108,116,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,105,99,104,32,105,115,32,76,70,32,40,65,83,67,73,73,32,49,48,41,32,105,110,32,69,114,108,97,110,103,46>>]},{dl,[],[{dt,[],[{code,[],[<<99,114>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<99,114>>]},<<32,40,65,83,67,73,73,32,49,51,41,46>>]}]},{dt,[],[{code,[],[<<108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,76,70,32,40,65,83,67,73,73,32,49,48,41,44,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<99,114,108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,67,82,76,70,32,40,65,83,67,73,73,32,49,51,32,102,111,108,108,111,119,101,100,32,98,121,32,65,83,67,73,73,32,49,48,41,32,115,101,113,117,101,110,99,101,46>>]}]},{dt,[],[{code,[],[<<97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,105,115,32,116,111,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]}]},{dt,[],[{code,[],[<<97,110,121>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115,32,97,98,111,118,101,44,32,97,110,100,32,116,104,101,32,85,110,105,99,111,100,101,32,115,101,113,117,101,110,99,101,115,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,44,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,44,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,67,82,44,32,76,70,44,32,111,114,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,44,32,110,111,116,32,116,104,101,32,85,110,105,99,111,100,101,45,115,112,101,99,105,102,105,99,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,46>>]}]},{dt,[],[{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,116,104,101,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,67,82,76,70,44,32,97,110,100,32,115,111,32,111,110,44,32,116,104,101,32,100,101,102,97,117,108,116,41,46>>]}]},{dt,[],[{code,[],[<<110,111,95,115,116,97,114,116,95,111,112,116,105,109,105,122,101>>]}]},{dd,[],[{p,[],[<<68,105,115,97,98,108,101,115,32,111,112,116,105,109,105,122,97,116,105,111,110,32,116,104,97,116,32,99,97,110,32,109,97,108,102,117,110,99,116,105,111,110,32,105,102,32,34,83,112,101,99,105,97,108,32,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,32,97,114,101,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,65,32,116,121,112,105,99,97,108,32,101,120,97,109,112,108,101,32,119,111,117,108,100,32,98,101,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,34,68,69,70,65,66,67,34,32,97,103,97,105,110,115,116,32,34,40,42,67,79,77,77,73,84,41,65,66,67,34,44,32,119,104,101,114,101,32,116,104,101,32,115,116,97,114,116,32,111,112,116,105,109,105,122,97,116,105,111,110,32,111,102,32,80,67,82,69,32,119,111,117,108,100,32,115,107,105,112,32,116,104,101,32,115,117,98,106,101,99,116,32,117,112,32,116,111,32,34,65,34,32,97,110,100,32,110,101,118,101,114,32,114,101,97,108,105,122,101,32,116,104,97,116,32,116,104,101,32,40,42,67,79,77,77,73,84,41,32,105,110,115,116,114,117,99,116,105,111,110,32,105,115,32,116,111,32,104,97,118,101,32,109,97,100,101,32,116,104,101,32,109,97,116,99,104,105,110,103,32,102,97,105,108,46,32,84,104,105,115,32,111,112,116,105,111,110,32,105,115,32,111,110,108,121,32,114,101,108,101,118,97,110,116,32,105,102,32,121,111,117,32,117,115,101,32,34,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,44,32,97,115,32,100,105,115,99,117,115,115,101,100,32,105,110,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},<<46>>]}]},{dt,[],[{code,[],[<<117,99,112>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,116,111,32,98,101,32,117,115,101,100,32,119,104,101,110,32,114,101,115,111,108,118,105,110,103,32,92,66,44,32,92,98,44,32,92,68,44,32,92,100,44,32,92,83,44,32,92,115,44,32,92,87,32,97,110,100,32,92,119,46,32,87,105,116,104,111,117,116,32,116,104,105,115,32,102,108,97,103,44,32,111,110,108,121,32,73,83,79,32,76,97,116,105,110,45,49,32,112,114,111,112,101,114,116,105,101,115,32,97,114,101,32,117,115,101,100,46,32,85,115,105,110,103,32,85,110,105,99,111,100,101,32,112,114,111,112,101,114,116,105,101,115,32,104,117,114,116,115,32,112,101,114,102,111,114,109,97,110,99,101,44,32,98,117,116,32,105,115,32,115,101,109,97,110,116,105,99,97,108,108,121,32,99,111,114,114,101,99,116,32,119,104,101,110,32,119,111,114,107,105,110,103,32,119,105,116,104,32,85,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,115,32,98,101,121,111,110,100,32,116,104,101,32,73,83,79,32,76,97,116,105,110,45,49,32,114,97,110,103,101,46>>]}]},{dt,[],[{code,[],[<<110,101,118,101,114,95,117,116,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,40,42,85,84,70,41,32,97,110,100,47,111,114,32,40,42,85,84,70,56,41,32,34,115,116,97,114,116,45,111,102,45,112,97,116,116,101,114,110,32,105,116,101,109,115,34,32,97,114,101,32,102,111,114,98,105,100,100,101,110,46,32,84,104,105,115,32,102,108,97,103,32,99,97,110,110,111,116,32,98,101,32,99,111,109,98,105,110,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<46,32,85,115,101,102,117,108,32,105,102,32,73,83,79,32,76,97,116,105,110,45,49,32,112,97,116,116,101,114,110,115,32,102,114,111,109,32,97,110,32,101,120,116,101,114,110,97,108,32,115,111,117,114,99,101,32,97,114,101,32,116,111,32,98,101,32,99,111,109,112,105,108,101,100,46>>]}]}]}]},#{signature => [{attribute,{59,2},spec,{{compile,2},[{type,{59,14},bounded_fun,[{type,{59,14},'fun',[{type,{59,14},product,[{var,{59,15},'Regexp'},{var,{59,23},'Options'}]},{type,{59,35},union,[{type,{59,35},tuple,[{atom,{59,36},ok},{var,{59,40},'MP'}]},{type,{59,46},tuple,[{atom,{59,47},error},{var,{59,54},'ErrSpec'}]}]}]},[{type,{60,7},constraint,[{atom,{60,7},is_subtype},[{var,{60,7},'Regexp'},{type,{60,17},union,[{type,{60,17},iodata,[]},{remote_type,{60,28},[{atom,{60,28},unicode},{atom,{60,36},charlist},[]]}]}]]},{type,{61,7},constraint,[{atom,{61,7},is_subtype},[{var,{61,7},'Options'},{type,{61,18},list,[{var,{61,19},'Option'}]}]]},{type,{62,7},constraint,[{atom,{62,7},is_subtype},[{var,{62,7},'Option'},{user_type,{62,17},compile_option,[]}]]},{type,{63,7},constraint,[{atom,{63,7},is_subtype},[{var,{63,7},'MP'},{user_type,{63,13},mp,[]}]]},{type,{64,7},constraint,[{atom,{64,7},is_subtype},[{var,{64,7},'ErrSpec'},{type,{64,18},tuple,[{ann_type,{64,19},[{var,{64,19},'ErrString'},{type,{64,32},string,[]}]},{ann_type,{64,42},[{var,{64,42},'Position'},{type,{64,54},non_neg_integer,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,49,48,48>>}},{{function,inspect,2},[{file,[114,101,46,101,114,108]},{location,145}],[<<105,110,115,112,101,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<84,97,107,101,115,32,97,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32,97,110,32,105,116,101,109,44,32,97,110,100,32,114,101,116,117,114,110,115,32,116,104,101,32,114,101,108,101,118,97,110,116,32,100,97,116,97,32,102,114,111,109,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,84,104,101,32,111,110,108,121,32,115,117,112,112,111,114,116,101,100,32,105,116,101,109,32,105,115,32>>,{code,[],[<<110,97,109,101,108,105,115,116>>]},<<44,32,119,104,105,99,104,32,114,101,116,117,114,110,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,110,97,109,101,108,105,115,116,44,32,91,98,105,110,97,114,121,40,41,93,125>>]},<<44,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,110,97,109,101,115,32,111,102,32,97,108,108,32,40,117,110,105,113,117,101,41,32,110,97,109,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,123,111,107,44,77,80,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,65,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,50,62,32,114,101,58,105,110,115,112,101,99,116,40,77,80,44,110,97,109,101,108,105,115,116,41,46,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,65,34,62,62,44,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125,10,51,62,32,123,111,107,44,77,80,68,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,67,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,44,91,100,117,112,110,97,109,101,115,93,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,56,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,52,62,32,114,101,58,105,110,115,112,101,99,116,40,77,80,68,44,110,97,109,101,108,105,115,116,41,46,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125>>]}]},{p,[],[<<78,111,116,105,99,101,32,105,110,32,116,104,101,32,115,101,99,111,110,100,32,101,120,97,109,112,108,101,32,116,104,97,116,32,116,104,101,32,100,117,112,108,105,99,97,116,101,32,110,97,109,101,32,111,110,108,121,32,111,99,99,117,114,115,32,111,110,99,101,32,105,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,108,105,115,116,44,32,97,110,100,32,116,104,97,116,32,116,104,101,32,108,105,115,116,32,105,115,32,105,110,32,97,108,112,104,97,98,101,116,105,99,97,108,32,111,114,100,101,114,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119,104,101,114,101,32,116,104,101,32,110,97,109,101,115,32,97,114,101,32,112,111,115,105,116,105,111,110,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,84,104,101,32,111,114,100,101,114,32,111,102,32,116,104,101,32,110,97,109,101,115,32,105,115,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,111,114,100,101,114,32,111,102,32,99,97,112,116,117,114,101,100,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,105,102,32>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,97,108,108,95,110,97,109,101,115,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,110,32,111,112,116,105,111,110,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<46,32,89,111,117,32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,99,114,101,97,116,101,32,97,32,110,97,109,101,45,116,111,45,118,97,108,117,101,32,109,97,112,112,105,110,103,32,102,114,111,109,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,108,105,107,101,32,116,104,105,115,58>>]},{pre,[],[{code,[],[<<49,62,32,123,111,107,44,77,80,125,32,61,32,114,101,58,99,111,109,112,105,108,101,40,34,40,63,60,65,62,65,41,124,40,63,60,66,62,66,41,124,40,63,60,67,62,67,41,34,41,46,10,123,111,107,44,123,114,101,95,112,97,116,116,101,114,110,44,51,44,48,44,48,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,60,54,57,44,56,50,44,54,55,44,56,48,44,49,49,57,44,48,44,48,44,48,44,48,44,48,44,48,44,48,44,49,44,48,44,48,44,48,44,50,53,53,44,50,53,53,44,50,53,53,44,50,53,53,44,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,50,53,53,44,50,53,53,44,46,46,46,62,62,125,125,10,50,62,32,123,110,97,109,101,108,105,115,116,44,32,78,125,32,61,32,114,101,58,105,110,115,112,101,99,116,40,77,80,44,110,97,109,101,108,105,115,116,41,46,10,123,110,97,109,101,108,105,115,116,44,91,60,60,34,65,34,62,62,44,60,60,34,66,34,62,62,44,60,60,34,67,34,62,62,93,125,10,51,62,32,123,109,97,116,99,104,44,76,125,32,61,32,114,101,58,114,117,110,40,34,65,65,34,44,77,80,44,91,123,99,97,112,116,117,114,101,44,97,108,108,95,110,97,109,101,115,44,98,105,110,97,114,121,125,93,41,46,10,123,109,97,116,99,104,44,91,60,60,34,65,34,62,62,44,60,60,62,62,44,60,60,62,62,93,125,10,52,62,32,78,97,109,101,77,97,112,32,61,32,108,105,115,116,115,58,122,105,112,40,78,44,76,41,46,10,91,123,60,60,34,65,34,62,62,44,60,60,34,65,34,62,62,125,44,123,60,60,34,66,34,62,62,44,60,60,62,62,125,44,123,60,60,34,67,34,62,62,44,60,60,62,62,125,93>>]}]}]},#{signature => [{attribute,{145,2},spec,{{inspect,2},[{type,{145,14},bounded_fun,[{type,{145,14},'fun',[{type,{145,14},product,[{var,{145,15},'MP'},{var,{145,18},'Item'}]},{type,{145,27},tuple,[{atom,{145,28},namelist},{type,{145,38},list,[{type,{145,40},binary,[]}]}]}]},[{type,{146,7},constraint,[{atom,{146,7},is_subtype},[{var,{146,7},'MP'},{user_type,{146,13},mp,[]}]]},{type,{147,7},constraint,[{atom,{147,7},is_subtype},[{var,{147,7},'Item'},{atom,{147,15},namelist}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,48,57>>,since => <<79,84,80,32,49,55,46,48>>}},{{function,replace,3},[{file,[114,101,46,101,114,108]},{location,355}],[<<114,101,112,108,97,99,101,47,51>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<114,101,112,108,97,99,101,40,83,117,98,106,101,99,116,44,32,82,69,44,32,82,101,112,108,97,99,101,109,101,110,116,44,32,91,93,41>>]},<<46>>]}]},#{signature => [{attribute,{355,2},spec,{{replace,3},[{type,{355,14},bounded_fun,[{type,{355,14},'fun',[{type,{355,14},product,[{var,{355,15},'Subject'},{var,{355,24},'RE'},{var,{355,28},'Replacement'}]},{type,{355,44},union,[{type,{355,44},iodata,[]},{remote_type,{355,55},[{atom,{355,55},unicode},{atom,{355,63},charlist},[]]}]}]},[{type,{356,7},constraint,[{atom,{356,7},is_subtype},[{var,{356,7},'Subject'},{type,{356,18},union,[{type,{356,18},iodata,[]},{remote_type,{356,29},[{atom,{356,29},unicode},{atom,{356,37},charlist},[]]}]}]]},{type,{357,7},constraint,[{atom,{357,7},is_subtype},[{var,{357,7},'RE'},{type,{357,13},union,[{user_type,{357,13},mp,[]},{type,{357,20},iodata,[]}]}]]},{type,{358,7},constraint,[{atom,{358,7},is_subtype},[{var,{358,7},'Replacement'},{type,{358,22},union,[{type,{358,22},iodata,[]},{remote_type,{358,33},[{atom,{358,33},unicode},{atom,{358,41},charlist},[]]},{user_type,{358,54},replace_fun,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,53,51>>}},{{function,replace,4},[{file,[114,101,46,101,114,108]},{location,368}],[<<114,101,112,108,97,99,101,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,112,108,97,99,101,115,32,116,104,101,32,109,97,116,99,104,101,100,32,112,97,114,116,32,111,102,32,116,104,101,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,115,116,114,105,110,103,32,119,105,116,104,32>>,{code,[],[<<82,101,112,108,97,99,101,109,101,110,116>>]},<<46>>]},{p,[],[<<84,104,101,32,112,101,114,109,105,115,115,105,98,108,101,32,111,112,116,105,111,110,115,32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,102,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,111,112,116,105,111,110>>,{code,[],[<<32,99,97,112,116,117,114,101>>]},<<32,105,115,32,110,111,116,32,97,108,108,111,119,101,100,46,32,73,110,115,116,101,97,100,32,97,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,82,101,116,117,114,110,84,121,112,101,125>>]},<<32,105,115,32,112,114,101,115,101,110,116,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<44,32,99,111,110,115,116,114,117,99,116,101,100,32,105,110,32,97,32,119,97,121,32,116,111,32,109,105,110,105,109,105,122,101,32,99,111,112,121,105,110,103,46,32,84,104,101,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<32,114,101,115,117,108,116,32,99,97,110,32,98,101,32,117,115,101,100,32,100,105,114,101,99,116,108,121,32,105,110,32,109,97,110,121,32,73,47,79,32,111,112,101,114,97,116,105,111,110,115,46,32,73,102,32,97,32,102,108,97,116,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,105,115,32,100,101,115,105,114,101,100,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,108,105,115,116,125>>]},<<46,32,73,102,32,97,32,98,105,110,97,114,121,32,105,115,32,100,101,115,105,114,101,100,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<123,114,101,116,117,114,110,44,32,98,105,110,97,114,121,125>>]},<<46>>]},{p,[],[<<65,115,32,105,110,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<44,32,97,110,32>>,{code,[],[<<109,112,40,41>>]},<<32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,113,117,105,114,101,115,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,116,111,32,98,101,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,105,109,112,108,105,99,105,116,108,121,32,97,110,100,32,116,104,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,98,111,116,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,114,101,32,116,111,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<115,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,101,112,108,97,99,101,109,101,110,116,32,105,115,32,103,105,118,101,110,32,97,115,32,97,32,115,116,114,105,110,103,44,32,105,116,32,99,97,110,32,99,111,110,116,97,105,110,32,116,104,101,32,115,112,101,99,105,97,108,32,99,104,97,114,97,99,116,101,114,32>>,{code,[],[<<38>>]},<<44,32,119,104,105,99,104,32,105,110,115,101,114,116,115,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,105,110,103,32,101,120,112,114,101,115,115,105,111,110,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,97,110,100,32,116,104,101,32,115,112,101,99,105,97,108,32,115,101,113,117,101,110,99,101,32>>,{code,[],[<<92>>]},<<78,32,40,119,104,101,114,101,32,78,32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,62,32,48,41,44,32>>,{code,[],[<<92,103>>]},<<78,44,32,111,114,32>>,{code,[],[<<92,103,123>>]},<<78>>,{code,[],[<<125>>]},<<44,32,114,101,115,117,108,116,105,110,103,32,105,110,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,110,117,109,98,101,114,32,78,44,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46,32,73,102,32,110,111,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,119,105,116,104,32,116,104,97,116,32,110,117,109,98,101,114,32,105,115,32,103,101,110,101,114,97,116,101,100,32,98,121,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,110,111,116,104,105,110,103,32,105,115,32,105,110,115,101,114,116,101,100,46>>]},{p,[],[<<84,111,32,105,110,115,101,114,116,32,97,110,32,38,32,111,114,32,97,32,92,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,112,114,101,99,101,100,101,32,105,116,32,119,105,116,104,32,97,32,92,46,32,78,111,116,105,99,101,32,116,104,97,116,32,69,114,108,97,110,103,32,97,108,114,101,97,100,121,32,103,105,118,101,115,32,97,32,115,112,101,99,105,97,108,32,109,101,97,110,105,110,103,32,116,111,32,92,32,105,110,32,108,105,116,101,114,97,108,32,115,116,114,105,110,103,115,44,32,115,111,32,97,32,115,105,110,103,108,101,32,92,32,109,117,115,116,32,98,101,32,119,114,105,116,116,101,110,32,97,115,32>>,{code,[],[<<34,92,92,34>>]},<<32,97,110,100,32,116,104,101,114,101,102,111,114,101,32,97,32,100,111,117,98,108,101,32,92,32,97,115,32>>,{code,[],[<<34,92,92,92,92,34>>]},<<46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[],[<<114,101,58,114,101,112,108,97,99,101,40,34,97,98,99,100,34,44,34,99,34,44,34,91,38,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<34,97,98,91,99,93,100,34>>]}]},{p,[],[<<119,104,105,108,101>>]},{pre,[],[{code,[],[<<114,101,58,114,101,112,108,97,99,101,40,34,97,98,99,100,34,44,34,99,34,44,34,91,92,92,38,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<34,97,98,91,38,93,100,34>>]}]},{p,[],[<<73,102,32,116,104,101,32,114,101,112,108,97,99,101,109,101,110,116,32,105,115,32,103,105,118,101,110,32,97,115,32,97,32,102,117,110,44,32,105,116,32,119,105,108,108,32,98,101,32,99,97,108,108,101,100,32,119,105,116,104,32,116,104,101,32,119,104,111,108,101,32,109,97,116,99,104,105,110,103,32,101,120,112,114,101,115,115,105,111,110,32,97,115,32,116,104,101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,32,97,110,100,32,97,32,108,105,115,116,32,111,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,105,110,32,116,104,101,32,111,114,100,101,114,32,105,110,32,119,104,105,99,104,32,116,104,101,121,32,97,112,112,101,97,114,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32,84,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,32,119,105,108,108,32,98,101,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{pre,[],[{code,[],[<<114,101,58,114,101,112,108,97,99,101,40,34,97,98,99,100,34,44,32,34,46,40,46,41,34,44,32,102,117,110,40,87,104,111,108,101,44,32,91,60,60,67,62,62,93,41,32,45,62,32,60,60,36,35,44,32,87,104,111,108,101,47,98,105,110,97,114,121,44,32,36,45,44,32,40,67,32,45,32,36,97,32,43,32,36,65,41,44,32,36,35,62,62,32,101,110,100,44,32,91,123,114,101,116,117,114,110,44,32,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<34,35,97,98,45,66,35,99,100,34>>]}]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<78,111,110,45,109,97,116,99,104,105,110,103,32,111,112,116,105,111,110,97,108,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,119,105,108,108,32,110,111,116,32,98,101,32,105,110,99,108,117,100,101,100,32,105,110,32,116,104,101,32,108,105,115,116,32,111,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,105,102,32,116,104,101,121,32,97,114,101,32,116,104,101,32,108,97,115,116,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{p,[],[<<84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<34,40,97,41,40,98,41,63,40,99,41,63,34>>]},<<32,40,34,97,34,44,32,111,112,116,105,111,110,97,108,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,34,98,34,44,32,111,112,116,105,111,110,97,108,108,121,32,102,111,108,108,111,119,101,100,32,98,121,32,34,99,34,41,32,119,105,108,108,32,99,114,101,97,116,101,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,108,105,115,116,115,58>>]},{ul,[],[{li,[],[{code,[],[<<91,60,60,34,97,34,62,62,44,32,60,60,34,98,34,62,62,44,32,60,60,34,99,34,62,62,93>>]},<<32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,115,116,114,105,110,103,32>>,{code,[],[<<34,97,98,99,34>>]}]},{li,[],[{code,[],[<<91,60,60,34,97,34,62,62,44,32,60,60,62,62,44,32,60,60,34,99,34,62,62,93>>]},<<32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,115,116,114,105,110,103,32>>,{code,[],[<<34,97,99,120,34>>]}]},{li,[],[{code,[],[<<91,60,60,34,97,34,62,62,44,32,60,60,34,98,34,62,62,93>>]},<<32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,115,116,114,105,110,103,32>>,{code,[],[<<34,97,98,120,34>>]}]},{li,[],[{code,[],[<<91,60,60,34,97,34,62,62,93>>]},<<32,119,104,101,110,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,115,116,114,105,110,103,32>>,{code,[],[<<34,97,120,120,34>>]}]}]}]},{p,[],[<<65,115,32,119,105,116,104,32>>,{code,[],[<<114,117,110,47,51>>]},<<44,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,114,97,105,115,101,32,116,104,101,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,46,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,103,101,116,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,101,114,114,111,114,46>>]}]},#{signature => [{attribute,{368,2},spec,{{replace,4},[{type,{368,14},bounded_fun,[{type,{368,14},'fun',[{type,{368,14},product,[{var,{368,15},'Subject'},{var,{368,24},'RE'},{var,{368,28},'Replacement'},{var,{368,41},'Options'}]},{type,{368,53},union,[{type,{368,53},iodata,[]},{remote_type,{368,64},[{atom,{368,64},unicode},{atom,{368,72},charlist},[]]}]}]},[{type,{369,7},constraint,[{atom,{369,7},is_subtype},[{var,{369,7},'Subject'},{type,{369,18},union,[{type,{369,18},iodata,[]},{remote_type,{369,29},[{atom,{369,29},unicode},{atom,{369,37},charlist},[]]}]}]]},{type,{370,7},constraint,[{atom,{370,7},is_subtype},[{var,{370,7},'RE'},{type,{370,13},union,[{user_type,{370,13},mp,[]},{type,{370,20},iodata,[]},{remote_type,{370,31},[{atom,{370,31},unicode},{atom,{370,39},charlist},[]]}]}]]},{type,{371,7},constraint,[{atom,{371,7},is_subtype},[{var,{371,7},'Replacement'},{type,{371,22},union,[{type,{371,22},iodata,[]},{remote_type,{371,33},[{atom,{371,33},unicode},{atom,{371,41},charlist},[]]},{user_type,{371,54},replace_fun,[]}]}]]},{type,{372,7},constraint,[{atom,{372,7},is_subtype},[{var,{372,7},'Options'},{type,{372,18},list,[{var,{372,19},'Option'}]}]]},{type,{373,7},constraint,[{atom,{373,7},is_subtype},[{var,{373,7},'Option'},{type,{373,17},union,[{atom,{373,17},anchored},{atom,{373,28},global},{atom,{373,37},notbol},{atom,{373,46},noteol},{atom,{373,55},notempty},{atom,{374,10},notempty_atstart},{type,{375,17},tuple,[{atom,{375,18},offset},{type,{375,26},non_neg_integer,[]}]},{type,{375,47},tuple,[{atom,{375,48},newline},{var,{375,57},'NLSpec'}]},{atom,{375,67},bsr_anycrlf},{type,{376,17},tuple,[{atom,{376,18},match_limit},{type,{376,31},non_neg_integer,[]}]},{type,{377,17},tuple,[{atom,{377,18},match_limit_recursion},{type,{377,41},non_neg_integer,[]}]},{atom,{378,17},bsr_unicode},{type,{378,31},tuple,[{atom,{378,32},return},{var,{378,40},'ReturnType'}]},{var,{378,54},'CompileOpt'}]}]]},{type,{379,7},constraint,[{atom,{379,7},is_subtype},[{var,{379,7},'ReturnType'},{type,{379,21},union,[{atom,{379,21},iodata},{atom,{379,30},list},{atom,{379,37},binary}]}]]},{type,{380,7},constraint,[{atom,{380,7},is_subtype},[{var,{380,7},'CompileOpt'},{user_type,{380,21},compile_option,[]}]]},{type,{381,7},constraint,[{atom,{381,7},is_subtype},[{var,{381,7},'NLSpec'},{type,{381,17},union,[{atom,{381,17},cr},{atom,{381,22},crlf},{atom,{381,29},lf},{atom,{381,34},anycrlf},{atom,{381,44},any}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,51,54,51>>}},{{function,run,2},[{file,[114,101,46,101,114,108]},{location,69}],[<<114,117,110,47,50>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<114,117,110,40,83,117,98,106,101,99,116,44,82,69,44,91,93,41>>]},<<46>>]}]},#{signature => [{attribute,{69,2},spec,{{run,2},[{type,{69,10},bounded_fun,[{type,{69,10},'fun',[{type,{69,10},product,[{var,{69,11},'Subject'},{var,{69,20},'RE'}]},{type,{69,27},union,[{type,{69,27},tuple,[{atom,{69,28},match},{var,{69,35},'Captured'}]},{atom,{69,47},nomatch}]}]},[{type,{70,7},constraint,[{atom,{70,7},is_subtype},[{var,{70,7},'Subject'},{type,{70,18},union,[{type,{70,18},iodata,[]},{remote_type,{70,29},[{atom,{70,29},unicode},{atom,{70,37},charlist},[]]}]}]]},{type,{71,7},constraint,[{atom,{71,7},is_subtype},[{var,{71,7},'RE'},{type,{71,13},union,[{user_type,{71,13},mp,[]},{type,{71,20},iodata,[]}]}]]},{type,{72,7},constraint,[{atom,{72,7},is_subtype},[{var,{72,7},'Captured'},{type,{72,19},list,[{var,{72,20},'CaptureData'}]}]]},{type,{73,7},constraint,[{atom,{73,7},is_subtype},[{var,{73,7},'CaptureData'},{type,{73,22},tuple,[{type,{73,23},integer,[]},{type,{73,34},integer,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,52,52,50>>}},{{function,run,3},[{file,[114,101,46,101,114,108]},{location,78}],[<<114,117,110,47,51>>],#{<<101,110>> => [{p,[],[<<69,120,101,99,117,116,101,115,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,105,110,103,44,32,97,110,100,32,114,101,116,117,114,110,115,32>>,{code,[],[<<109,97,116,99,104,47,123,109,97,116,99,104,44,32,67,97,112,116,117,114,101,100,125>>]},<<32,111,114,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<46,32,84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,101,105,116,104,101,114,32,97,115,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,105,116,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,111,109,112,105,108,101,100,32,40,97,115,32,98,121,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<41,32,97,110,100,32,101,120,101,99,117,116,101,100,44,32,111,114,32,97,115,32,97,32,112,114,101,99,111,109,112,105,108,101,100,32>>,{code,[],[<<109,112,40,41>>]},<<32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,105,116,32,105,115,32,101,120,101,99,117,116,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,115,117,98,106,101,99,116,32,100,105,114,101,99,116,108,121,46>>]},{p,[],[<<87,104,101,110,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,44,32,101,120,99,101,112,116,105,111,110,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,105,115,32,116,104,114,111,119,110,32,105,102,32,97,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,32,111,99,99,117,114,115,46,32,67,97,108,108,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<32,116,111,32,103,101,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,108,111,99,97,116,105,111,110,32,111,102,32,116,104,101,32,101,114,114,111,114,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,105,108,101,100,44,32,116,104,101,32,111,112,116,105,111,110,32,108,105,115,116,32,99,97,110,32,111,110,108,121,32,99,111,110,116,97,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,58>>]},{ul,[],[{li,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{li,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125,47,123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]}]},{li,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{li,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{li,[],[{code,[],[<<110,111,116,98,111,108>>]}]},{li,[],[{code,[],[<<110,111,116,101,109,112,116,121>>]}]},{li,[],[{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]}]},{li,[],[{code,[],[<<110,111,116,101,111,108>>]}]},{li,[],[{code,[],[<<123,111,102,102,115,101,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{li,[],[{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]}]}]},{p,[],[<<79,116,104,101,114,119,105,115,101,32,97,108,108,32,111,112,116,105,111,110,115,32,118,97,108,105,100,32,102,111,114,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<99,111,109,112,105,108,101,47,50>>]},<<32,97,114,101,32,97,108,115,111,32,97,108,108,111,119,101,100,46,32,79,112,116,105,111,110,115,32,97,108,108,111,119,101,100,32,98,111,116,104,32,102,111,114,32,99,111,109,112,105,108,97,116,105,111,110,32,97,110,100,32,101,120,101,99,117,116,105,111,110,32,111,102,32,97,32,109,97,116,99,104,44,32,110,97,109,101,108,121,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<32,97,110,100,32>>,{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]},<<44,32,97,102,102,101,99,116,32,98,111,116,104,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,97,110,100,32,101,120,101,99,117,116,105,111,110,32,105,102,32,112,114,101,115,101,110,116,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,97,32,110,111,110,45,112,114,101,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,112,114,101,118,105,111,117,115,108,121,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,105,115,32,116,111,32,98,101,32,112,114,111,118,105,100,101,100,32,97,115,32,97,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,97,110,121,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,119,105,108,108,32,100,111,46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,105,110,118,111,108,118,101,100,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32,98,111,116,104,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,110,100,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,114,101,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,115,40,41>>]},<<46>>]},{p,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125,47,123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]},<<32,100,101,102,105,110,101,115,32,119,104,97,116,32,116,111,32,114,101,116,117,114,110,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,32,117,112,111,110,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,105,110,103,46,32,84,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,116,117,112,108,101,32,99,97,110,32,99,111,110,116,97,105,110,32,98,111,116,104,32,97,32,118,97,108,117,101,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,116,101,108,108,105,110,103,32,119,104,105,99,104,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,44,32,97,110,100,32,97,32,116,121,112,101,32,115,112,101,99,105,102,105,99,97,116,105,111,110,44,32,116,101,108,108,105,110,103,32,104,111,119,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,32,40,97,115,32,105,110,100,101,120,32,116,117,112,108,101,115,44,32,108,105,115,116,115,44,32,111,114,32,98,105,110,97,114,105,101,115,41,46,32,84,104,101,32,111,112,116,105,111,110,115,32,97,114,101,32,100,101,115,99,114,105,98,101,100,32,105,110,32,100,101,116,97,105,108,32,98,101,108,111,119,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,97,112,116,117,114,101,32,111,112,116,105,111,110,115,32,100,101,115,99,114,105,98,101,32,116,104,97,116,32,110,111,32,115,117,98,115,116,114,105,110,103,32,99,97,112,116,117,114,105,110,103,32,105,115,32,116,111,32,98,101,32,100,111,110,101,32,40>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,110,111,110,101,125>>]},<<41,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,114,101,116,117,114,110,115,32,116,104,101,32,115,105,110,103,108,101,32,97,116,111,109,32>>,{code,[],[<<109,97,116,99,104>>]},<<32,117,112,111,110,32,115,117,99,99,101,115,115,102,117,108,32,109,97,116,99,104,105,110,103,44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,109,97,116,99,104,44,32,86,97,108,117,101,76,105,115,116,125>>]},<<46,32,68,105,115,97,98,108,105,110,103,32,99,97,112,116,117,114,105,110,103,32,99,97,110,32,98,101,32,100,111,110,101,32,101,105,116,104,101,114,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<110,111,110,101>>]},<<32,111,114,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32,97,115,32>>,{code,[],[<<86,97,108,117,101,83,112,101,99>>]},<<46>>]},{p,[],[<<79,112,116,105,111,110,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<32,97,100,100,115,32,116,104,101,32,112,111,115,115,105,98,105,108,105,116,121,32,116,104,97,116,32,97,110,32,101,114,114,111,114,32,116,117,112,108,101,32,105,115,32,114,101,116,117,114,110,101,100,46,32,84,104,101,32,116,117,112,108,101,32,101,105,116,104,101,114,32,105,110,100,105,99,97,116,101,115,32,97,32,109,97,116,99,104,105,110,103,32,101,114,114,111,114,32,40>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,111,114,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<41,44,32,111,114,32,97,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,44,32,119,104,101,114,101,32,116,104,101,32,101,114,114,111,114,32,116,117,112,108,101,32,104,97,115,32,116,104,101,32,102,111,114,109,97,116,32>>,{code,[],[<<123,101,114,114,111,114,44,32,123,99,111,109,112,105,108,101,44,32,67,111,109,112,105,108,101,69,114,114,125,125>>]},<<46,32,78,111,116,105,99,101,32,116,104,97,116,32,105,102,32,111,112,116,105,111,110,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,110,101,118,101,114,32,114,101,116,117,114,110,115,32,101,114,114,111,114,32,116,117,112,108,101,115,44,32,98,117,116,32,114,101,112,111,114,116,115,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,97,115,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,101,120,99,101,112,116,105,111,110,32,97,110,100,32,102,97,105,108,101,100,32,109,97,116,99,104,101,115,32,98,101,99,97,117,115,101,32,111,102,32,101,120,99,101,101,100,101,100,32,109,97,116,99,104,32,108,105,109,105,116,115,32,115,105,109,112,108,121,32,97,115,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,111,112,116,105,111,110,115,32,97,114,101,32,114,101,108,101,118,97,110,116,32,102,111,114,32,101,120,101,99,117,116,105,111,110,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,110,99,104,111,114,101,100>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,116,111,32,109,97,116,99,104,105,110,103,32,97,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,112,111,115,105,116,105,111,110,46,32,73,102,32,97,32,112,97,116,116,101,114,110,32,119,97,115,32,99,111,109,112,105,108,101,100,32,119,105,116,104,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<44,32,111,114,32,116,117,114,110,101,100,32,111,117,116,32,116,111,32,98,101,32,97,110,99,104,111,114,101,100,32,98,121,32,118,105,114,116,117,101,32,111,102,32,105,116,115,32,99,111,110,116,101,110,116,115,44,32,105,116,32,99,97,110,110,111,116,32,98,101,32,109,97,100,101,32,117,110,97,110,99,104,111,114,101,100,32,97,116,32,109,97,116,99,104,105,110,103,32,116,105,109,101,44,32,104,101,110,99,101,32,116,104,101,114,101,32,105,115,32,110,111,32>>,{code,[],[<<117,110,97,110,99,104,111,114,101,100>>]},<<32,111,112,116,105,111,110,46>>]}]},{dt,[],[{code,[],[<<103,108,111,98,97,108>>]}]},{dd,[],[{p,[],[<<73,109,112,108,101,109,101,110,116,115,32,103,108,111,98,97,108,32,40,114,101,112,101,116,105,116,105,118,101,41,32,115,101,97,114,99,104,32,40,102,108,97,103,32>>,{code,[],[<<103>>]},<<32,105,110,32,80,101,114,108,41,46,32,69,97,99,104,32,109,97,116,99,104,32,105,115,32,114,101,116,117,114,110,101,100,32,97,115,32,97,32,115,101,112,97,114,97,116,101,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,112,101,99,105,102,105,99,32,109,97,116,99,104,32,97,110,100,32,97,110,121,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,40,111,114,32,97,115,32,115,112,101,99,105,102,105,101,100,32,98,121,32,111,112,116,105,111,110,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<46,32,84,104,101,32>>,{code,[],[<<67,97,112,116,117,114,101,100>>]},<<32,112,97,114,116,32,111,102,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,104,101,110,99,101,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<115,32,119,104,101,110,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<84,104,101,32,105,110,116,101,114,97,99,116,105,111,110,32,111,102,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,119,105,116,104,32,97,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,116,104,97,116,32,109,97,116,99,104,101,115,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,115,117,114,112,114,105,115,101,115,32,115,111,109,101,32,117,115,101,114,115,46,32,87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,104,97,110,100,108,101,115,32,101,109,112,116,121,32,109,97,116,99,104,101,115,32,105,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,97,115,32,80,101,114,108,58,32,97,32,122,101,114,111,45,108,101,110,103,116,104,32,109,97,116,99,104,32,97,116,32,97,110,121,32,112,111,105,110,116,32,105,115,32,97,108,115,111,32,114,101,116,114,105,101,100,32,119,105,116,104,32,111,112,116,105,111,110,115,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]},<<46,32,73,102,32,116,104,97,116,32,115,101,97,114,99,104,32,103,105,118,101,115,32,97,32,114,101,115,117,108,116,32,111,102,32,108,101,110,103,116,104,32,62,32,48,44,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,105,110,99,108,117,100,101,100,46,32,69,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,99,97,116,34,44,34,40,124,97,116,41,34,44,91,103,108,111,98,97,108,93,41,46>>]}]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,109,97,116,99,104,105,110,103,115,32,97,114,101,32,112,101,114,102,111,114,109,101,100,58>>]},{dl,[],[{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<48>>]}]},{dd,[],[{p,[],[<<84,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32>>,{code,[],[<<40,124,97,116,41>>]},<<32,102,105,114,115,116,32,109,97,116,99,104,32,97,116,32,116,104,101,32,105,110,105,116,105,97,108,32,112,111,115,105,116,105,111,110,32,111,102,32,115,116,114,105,110,103,32>>,{code,[],[<<99,97,116>>]},<<44,32,103,105,118,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,115,101,116,32>>,{code,[],[<<91,123,48,44,48,125,44,123,48,44,48,125,93>>]},<<32,40,116,104,101,32,115,101,99,111,110,100,32>>,{code,[],[<<123,48,44,48,125>>]},<<32,105,115,32,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,109,97,114,107,101,100,32,98,121,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,41,46,32,65,115,32,116,104,101,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,109,97,116,99,104,32,105,115,32,48,44,32,119,101,32,100,111,32,110,111,116,32,97,100,118,97,110,99,101,32,116,111,32,116,104,101,32,110,101,120,116,32,112,111,115,105,116,105,111,110,32,121,101,116,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<48>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,105,115,32,114,101,116,114,105,101,100,32,119,105,116,104,32,111,112,116,105,111,110,115,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]},<<32,97,116,32,116,104,101,32,115,97,109,101,32,112,111,115,105,116,105,111,110,44,32,119,104,105,99,104,32,100,111,101,115,32,110,111,116,32,103,105,118,101,32,97,110,121,32,105,110,116,101,114,101,115,116,105,110,103,32,114,101,115,117,108,116,32,111,102,32,108,111,110,103,101,114,32,108,101,110,103,116,104,44,32,115,111,32,116,104,101,32,115,101,97,114,99,104,32,112,111,115,105,116,105,111,110,32,105,115,32,97,100,118,97,110,99,101,100,32,116,111,32,116,104,101,32,110,101,120,116,32,99,104,97,114,97,99,116,101,114,32,40>>,{code,[],[<<97>>]},<<41,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,114,101,115,117,108,116,115,32,105,110,32>>,{code,[],[<<91,123,49,44,48,125,44,123,49,44,48,125,93>>]},<<44,32,115,111,32,116,104,105,115,32,115,101,97,114,99,104,32,105,115,32,97,108,115,111,32,114,101,112,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,101,120,116,114,97,32,111,112,116,105,111,110,115,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<65,108,116,101,114,110,97,116,105,118,101,32>>,{code,[],[<<97,98>>]},<<32,105,115,32,102,111,117,110,100,32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,91,123,49,44,50,125,44,123,49,44,50,125,93,46,32,84,104,101,32,114,101,115,117,108,116,32,105,115,32,97,100,100,101,100,32,116,111,32,116,104,101,32,108,105,115,116,32,111,102,32,114,101,115,117,108,116,115,32,97,110,100,32,116,104,101,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,101,97,114,99,104,32,115,116,114,105,110,103,32,105,115,32,97,100,118,97,110,99,101,100,32,116,119,111,32,115,116,101,112,115,46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<51>>]}]},{dd,[],[{p,[],[<<84,104,101,32,115,101,97,114,99,104,32,111,110,99,101,32,97,103,97,105,110,32,109,97,116,99,104,101,115,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,44,32,103,105,118,105,110,103,32>>,{code,[],[<<91,123,51,44,48,125,44,123,51,44,48,125,93>>]},<<46>>]}]},{dt,[],[<<65,116,32,111,102,102,115,101,116,32>>,{code,[],[<<49>>]},<<32,119,105,116,104,32>>,{code,[],[<<91,97,110,99,104,111,114,101,100,44,32,110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116,93>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,103,105,118,101,115,32,110,111,32,114,101,115,117,108,116,32,111,102,32,108,101,110,103,116,104,32,62,32,48,32,97,110,100,32,119,101,32,97,114,101,32,97,116,32,116,104,101,32,108,97,115,116,32,112,111,115,105,116,105,111,110,44,32,115,111,32,116,104,101,32,103,108,111,98,97,108,32,115,101,97,114,99,104,32,105,115,32,99,111,109,112,108,101,116,101,46>>]}]}]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,111,102,32,116,104,101,32,99,97,108,108,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,91,123,48,44,48,125,44,123,48,44,48,125,93,44,91,123,49,44,48,125,44,123,49,44,48,125,93,44,91,123,49,44,50,125,44,123,49,44,50,125,93,44,91,123,51,44,48,125,44,123,51,44,48,125,93,93,125>>]}]}]},{dt,[],[{code,[],[<<110,111,116,101,109,112,116,121>>]}]},{dd,[],[{p,[],[<<65,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,32,97,32,118,97,108,105,100,32,109,97,116,99,104,32,105,102,32,116,104,105,115,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,46,32,73,102,32,97,108,116,101,114,110,97,116,105,118,101,115,32,105,110,32,116,104,101,32,112,97,116,116,101,114,110,32,101,120,105,115,116,44,32,116,104,101,121,32,97,114,101,32,116,114,105,101,100,46,32,73,102,32,97,108,108,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,115,32,109,97,116,99,104,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,44,32,116,104,101,32,101,110,116,105,114,101,32,109,97,116,99,104,32,102,97,105,108,115,46>>]},{p,[],[{em,[],[<<69,120,97,109,112,108,101,58>>]}]},{p,[],[<<73,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,112,97,116,116,101,114,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,97,32,115,116,114,105,110,103,32,110,111,116,32,98,101,103,105,110,110,105,110,103,32,119,105,116,104,32,34,97,34,32,111,114,32,34,98,34,44,32,105,116,32,119,111,117,108,100,32,110,111,114,109,97,108,108,121,32,109,97,116,99,104,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,58>>]},{pre,[],[{code,[],[<<97,63,98,63>>]}]},{p,[],[<<87,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<44,32,116,104,105,115,32,109,97,116,99,104,32,105,115,32,105,110,118,97,108,105,100,44,32,115,111,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,115,101,97,114,99,104,101,115,32,102,117,114,116,104,101,114,32,105,110,116,111,32,116,104,101,32,115,116,114,105,110,103,32,102,111,114,32,111,99,99,117,114,114,101,110,99,101,115,32,111,102,32,34,97,34,32,111,114,32,34,98,34,46>>]}]},{dt,[],[{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]}]},{dd,[],[{p,[],[<<76,105,107,101,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<44,32,101,120,99,101,112,116,32,116,104,97,116,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,109,97,116,99,104,32,116,104,97,116,32,105,115,32,110,111,116,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,105,115,32,112,101,114,109,105,116,116,101,100,46,32,73,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,110,99,104,111,114,101,100,44,32,115,117,99,104,32,97,32,109,97,116,99,104,32,99,97,110,32,111,99,99,117,114,32,111,110,108,121,32,105,102,32,116,104,101,32,112,97,116,116,101,114,110,32,99,111,110,116,97,105,110,115,32,92,75,46>>]},{p,[],[<<80,101,114,108,32,104,97,115,32,110,111,32,100,105,114,101,99,116,32,101,113,117,105,118,97,108,101,110,116,32,111,102,32>>,{code,[],[<<110,111,116,101,109,112,116,121>>]},<<32,111,114,32>>,{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]},<<44,32,98,117,116,32,105,116,32,100,111,101,115,32,109,97,107,101,32,97,32,115,112,101,99,105,97,108,32,99,97,115,101,32,111,102,32,97,32,112,97,116,116,101,114,110,32,109,97,116,99,104,32,111,102,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,32,119,105,116,104,105,110,32,105,116,115,32,115,112,108,105,116,40,41,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,119,104,101,110,32,117,115,105,110,103,32,109,111,100,105,102,105,101,114,32>>,{code,[],[<<47,103>>]},<<46,32,84,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,99,97,110,32,98,101,32,101,109,117,108,97,116,101,100,32,97,102,116,101,114,32,109,97,116,99,104,105,110,103,32,97,32,110,117,108,108,32,115,116,114,105,110,103,32,98,121,32,102,105,114,115,116,32,116,114,121,105,110,103,32,116,104,101,32,109,97,116,99,104,32,97,103,97,105,110,32,97,116,32,116,104,101,32,115,97,109,101,32,111,102,102,115,101,116,32,119,105,116,104,32>>,{code,[],[<<110,111,116,101,109,112,116,121,95,97,116,115,116,97,114,116>>]},<<32,97,110,100,32>>,{code,[],[<<97,110,99,104,111,114,101,100>>]},<<44,32,97,110,100,32,116,104,101,110,44,32,105,102,32,116,104,97,116,32,102,97,105,108,115,44,32,98,121,32,97,100,118,97,110,99,105,110,103,32,116,104,101,32,115,116,97,114,116,105,110,103,32,111,102,102,115,101,116,32,40,115,101,101,32,98,101,108,111,119,41,32,97,110,100,32,116,114,121,105,110,103,32,97,110,32,111,114,100,105,110,97,114,121,32,109,97,116,99,104,32,97,103,97,105,110,46>>]}]},{dt,[],[{code,[],[<<110,111,116,98,111,108>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,102,105,114,115,116,32,99,104,97,114,97,99,116,101,114,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,32,108,105,110,101,44,32,115,111,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,32,116,111,32,109,97,116,99,104,32,98,101,102,111,114,101,32,105,116,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,119,105,116,104,111,117,116,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,40,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,41,32,99,97,117,115,101,115,32,99,105,114,99,117,109,102,108,101,120,32,110,101,118,101,114,32,116,111,32,109,97,116,99,104,46,32,84,104,105,115,32,111,112,116,105,111,110,32,111,110,108,121,32,97,102,102,101,99,116,115,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,99,105,114,99,117,109,102,108,101,120,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,92,65,46>>]}]},{dt,[],[{code,[],[<<110,111,116,101,111,108>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,110,111,116,32,116,104,101,32,101,110,100,32,111,102,32,97,32,108,105,110,101,44,32,115,111,32,116,104,101,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,32,105,115,32,110,111,116,32,116,111,32,109,97,116,99,104,32,105,116,32,110,111,114,32,40,101,120,99,101,112,116,32,105,110,32,109,117,108,116,105,108,105,110,101,32,109,111,100,101,41,32,97,32,110,101,119,108,105,110,101,32,105,109,109,101,100,105,97,116,101,108,121,32,98,101,102,111,114,101,32,105,116,46,32,83,101,116,116,105,110,103,32,116,104,105,115,32,119,105,116,104,111,117,116,32>>,{code,[],[<<109,117,108,116,105,108,105,110,101>>]},<<32,40,97,116,32,99,111,109,112,105,108,101,32,116,105,109,101,41,32,99,97,117,115,101,115,32,100,111,108,108,97,114,32,110,101,118,101,114,32,116,111,32,109,97,116,99,104,46,32,84,104,105,115,32,111,112,116,105,111,110,32,97,102,102,101,99,116,115,32,111,110,108,121,32,116,104,101,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,100,111,108,108,97,114,32,109,101,116,97,99,104,97,114,97,99,116,101,114,46,32,73,116,32,100,111,101,115,32,110,111,116,32,97,102,102,101,99,116,32,92,90,32,111,114,32,92,122,46>>]}]},{dt,[],[{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]}]},{dd,[],[{p,[],[<<71,105,118,101,115,32,98,101,116,116,101,114,32,99,111,110,116,114,111,108,32,111,102,32,116,104,101,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,32,105,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<46,32,87,104,101,110,32,115,112,101,99,105,102,105,101,100,44,32,99,111,109,112,105,108,97,116,105,111,110,32,101,114,114,111,114,115,32,40,105,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,110,111,116,32,97,108,114,101,97,100,121,32,99,111,109,112,105,108,101,100,41,32,97,110,100,32,114,117,110,116,105,109,101,32,101,114,114,111,114,115,32,97,114,101,32,101,120,112,108,105,99,105,116,108,121,32,114,101,116,117,114,110,101,100,32,97,115,32,97,110,32,101,114,114,111,114,32,116,117,112,108,101,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,112,111,115,115,105,98,108,101,32,114,117,110,116,105,109,101,32,101,114,114,111,114,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]}]},{dd,[],[{p,[],[<<84,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,115,101,116,115,32,97,32,108,105,109,105,116,32,111,110,32,104,111,119,32,109,97,110,121,32,116,105,109,101,115,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,99,97,108,108,101,100,46,32,68,101,102,97,117,108,116,115,32,116,111,32,49,48,44,48,48,48,44,48,48,48,32,105,110,32,116,104,101,32,108,105,98,114,97,114,121,32,99,111,109,112,105,108,101,100,32,102,111,114,32,69,114,108,97,110,103,46,32,73,102,32>>,{code,[],[<<123,101,114,114,111,114,44,32,109,97,116,99,104,95,108,105,109,105,116,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,44,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,104,97,115,32,114,101,97,99,104,101,100,32,116,104,105,115,32,108,105,109,105,116,46,32,84,104,105,115,32,105,115,32,110,111,114,109,97,108,108,121,32,116,111,32,98,101,32,114,101,103,97,114,100,101,100,32,97,115,32,97,32>>,{code,[],[<<110,111,109,97,116,99,104>>]},<<44,32,119,104,105,99,104,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,119,104,101,110,32,116,104,105,115,32,111,99,99,117,114,115,44,32,98,117,116,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<114,101,112,111,114,116,95,101,114,114,111,114,115>>]},<<44,32,121,111,117,32,97,114,101,32,105,110,102,111,114,109,101,100,32,119,104,101,110,32,116,104,101,32,109,97,116,99,104,32,102,97,105,108,115,32,98,101,99,97,117,115,101,32,111,102,32,116,111,111,32,109,97,110,121,32,105,110,116,101,114,110,97,108,32,99,97,108,108,115,46>>]}]},{dt,[],[{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]}]},{dd,[],[{p,[],[<<84,104,105,115,32,101,114,114,111,114,32,105,115,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<44,32,98,117,116,32,111,99,99,117,114,115,32,119,104,101,110,32,116,104,101,32,105,110,116,101,114,110,97,108,32,109,97,116,99,104,32,102,117,110,99,116,105,111,110,32,111,102,32,80,67,82,69,32,105,115,32,34,114,101,99,117,114,115,105,118,101,108,121,34,32,99,97,108,108,101,100,32,109,111,114,101,32,116,105,109,101,115,32,116,104,97,110,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<32,108,105,109,105,116,44,32,119,104,105,99,104,32,100,101,102,97,117,108,116,115,32,116,111,32,49,48,44,48,48,48,44,48,48,48,32,97,115,32,119,101,108,108,46,32,78,111,116,105,99,101,32,116,104,97,116,32,97,115,32,108,111,110,103,32,97,115,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,97,110,100,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,100,101,102,97,117,108,116>>]},<<32,118,97,108,117,101,115,32,97,114,101,32,107,101,112,116,32,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,115,44,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110>>]},<<32,101,114,114,111,114,32,99,97,110,110,111,116,32,111,99,99,117,114,44,32,97,115,32,116,104,101,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,101,114,114,111,114,32,111,99,99,117,114,115,32,98,101,102,111,114,101,32,116,104,97,116,32,40,101,97,99,104,32,114,101,99,117,114,115,105,118,101,32,99,97,108,108,32,105,115,32,97,108,115,111,32,97,32,99,97,108,108,44,32,98,117,116,32,110,111,116,32,99,111,110,118,101,114,115,101,108,121,41,46,32,66,111,116,104,32,108,105,109,105,116,115,32,99,97,110,32,104,111,119,101,118,101,114,32,98,101,32,99,104,97,110,103,101,100,44,32,101,105,116,104,101,114,32,98,121,32,115,101,116,116,105,110,103,32,108,105,109,105,116,115,32,100,105,114,101,99,116,108,121,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,115,116,114,105,110,103,32,40,115,101,101,32,115,101,99,116,105,111,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,101,103,101,120,112,95,115,121,110,116,97,120,95,100,101,116,97,105,108,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<80,67,82,69,32,82,101,103,117,108,97,114,32,69,101,120,112,114,101,115,115,105,111,110,32,68,101,116,97,105,108,115>>]},<<41,32,111,114,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32,111,112,116,105,111,110,115,32,116,111,32>>,{code,[],[<<114,117,110,47,51>>]},<<46>>]}]}]},{p,[],[<<73,116,32,105,115,32,105,109,112,111,114,116,97,110,116,32,116,111,32,117,110,100,101,114,115,116,97,110,100,32,116,104,97,116,32,119,104,97,116,32,105,115,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32,34,114,101,99,117,114,115,105,111,110,34,32,119,104,101,110,32,108,105,109,105,116,105,110,103,32,109,97,116,99,104,101,115,32,105,115,32,110,111,116,32,114,101,99,117,114,115,105,111,110,32,111,110,32,116,104,101,32,67,32,115,116,97,99,107,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,109,97,99,104,105,110,101,32,111,114,32,111,110,32,116,104,101,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,32,115,116,97,99,107,46,32,84,104,101,32,80,67,82,69,32,118,101,114,115,105,111,110,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,117,115,101,115,32,109,97,99,104,105,110,101,32,34,104,101,97,112,34,32,109,101,109,111,114,121,32,116,111,32,115,116,111,114,101,32,118,97,108,117,101,115,32,116,104,97,116,32,109,117,115,116,32,98,101,32,107,101,112,116,32,111,118,101,114,32,114,101,99,117,114,115,105,111,110,32,105,110,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,46>>]}]},{dt,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,97,32,109,97,116,99,104,32,105,110,32,97,110,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,119,97,121,46,32,73,116,32,105,115,32,100,101,115,99,114,105,98,101,100,32,97,115,32,102,111,108,108,111,119,115,32,98,121,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<84,104,101,32,109,97,116,99,104,95,108,105,109,105,116,32,102,105,101,108,100,32,112,114,111,118,105,100,101,115,32,97,32,109,101,97,110,115,32,111,102,32,112,114,101,118,101,110,116,105,110,103,32,80,67,82,69,32,102,114,111,109,32,117,115,105,110,103,10,117,112,32,97,32,118,97,115,116,32,97,109,111,117,110,116,32,111,102,32,114,101,115,111,117,114,99,101,115,32,119,104,101,110,32,114,117,110,110,105,110,103,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,103,111,105,110,103,10,116,111,32,109,97,116,99,104,44,32,98,117,116,32,119,104,105,99,104,32,104,97,118,101,32,97,32,118,101,114,121,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,112,111,115,115,105,98,105,108,105,116,105,101,115,32,105,110,32,116,104,101,105,114,10,115,101,97,114,99,104,32,116,114,101,101,115,46,32,84,104,101,32,99,108,97,115,115,105,99,32,101,120,97,109,112,108,101,32,105,115,32,97,32,112,97,116,116,101,114,110,32,116,104,97,116,32,117,115,101,115,32,110,101,115,116,101,100,10,117,110,108,105,109,105,116,101,100,32,114,101,112,101,97,116,115,46,10,10,73,110,116,101,114,110,97,108,108,121,44,32,112,99,114,101,95,101,120,101,99,40,41,32,117,115,101,115,32,97,32,102,117,110,99,116,105,111,110,32,99,97,108,108,101,100,32,109,97,116,99,104,40,41,44,32,119,104,105,99,104,32,105,116,32,99,97,108,108,115,10,114,101,112,101,97,116,101,100,108,121,32,40,115,111,109,101,116,105,109,101,115,32,114,101,99,117,114,115,105,118,101,108,121,41,46,32,84,104,101,32,108,105,109,105,116,32,115,101,116,32,98,121,32,109,97,116,99,104,95,108,105,109,105,116,32,105,115,10,105,109,112,111,115,101,100,32,111,110,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,100,117,114,105,110,103,32,97,32,109,97,116,99,104,44,10,119,104,105,99,104,32,104,97,115,32,116,104,101,32,101,102,102,101,99,116,32,111,102,32,108,105,109,105,116,105,110,103,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,98,97,99,107,116,114,97,99,107,105,110,103,32,116,104,97,116,32,99,97,110,10,116,97,107,101,32,112,108,97,99,101,46,32,70,111,114,32,112,97,116,116,101,114,110,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,97,110,99,104,111,114,101,100,44,32,116,104,101,32,99,111,117,110,116,32,114,101,115,116,97,114,116,115,10,102,114,111,109,32,122,101,114,111,32,102,111,114,32,101,97,99,104,32,112,111,115,105,116,105,111,110,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46>>]}]},{p,[],[<<84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,114,117,110,97,119,97,121,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,99,97,110,32,102,97,105,108,32,102,97,115,116,101,114,32,105,102,32,116,104,101,32,108,105,109,105,116,32,105,115,32,108,111,119,101,114,101,100,32,117,115,105,110,103,32,116,104,105,115,32,111,112,116,105,111,110,46,32,84,104,101,32,100,101,102,97,117,108,116,32,118,97,108,117,101,32,49,48,44,48,48,48,44,48,48,48,32,105,115,32,99,111,109,112,105,108,101,100,32,105,110,116,111,32,116,104,101,32,69,114,108,97,110,103,32,86,77,46>>]},{'div',[{class,<<110,111,116,101>>}],[{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,100,111,101,115,32,105,110,32,110,111,32,119,97,121,32,97,102,102,101,99,116,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,86,77,32,105,110,32,116,101,114,109,115,32,111,102,32,34,108,111,110,103,32,114,117,110,110,105,110,103,32,66,73,70,115,34,46,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,97,108,119,97,121,115,32,103,105,118,101,115,32,99,111,110,116,114,111,108,32,98,97,99,107,32,116,111,32,116,104,101,32,115,99,104,101,100,117,108,101,114,32,111,102,32,69,114,108,97,110,103,32,112,114,111,99,101,115,115,101,115,32,97,116,32,105,110,116,101,114,118,97,108,115,32,116,104,97,116,32,101,110,115,117,114,101,115,32,116,104,101,32,114,101,97,108,45,116,105,109,101,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,116,104,101,32,69,114,108,97,110,103,32,115,121,115,116,101,109,46>>]}]}]},{dt,[],[{code,[],[<<123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<76,105,109,105,116,115,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,97,110,100,32,109,101,109,111,114,121,32,99,111,110,115,117,109,112,116,105,111,110,32,111,102,32,97,32,109,97,116,99,104,32,105,110,32,97,110,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,45,115,112,101,99,105,102,105,99,32,119,97,121,44,32,118,101,114,121,32,115,105,109,105,108,97,114,32,116,111,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<46,32,73,116,32,105,115,32,100,101,115,99,114,105,98,101,100,32,97,115,32,102,111,108,108,111,119,115,32,98,121,32,116,104,101,32,80,67,82,69,32,100,111,99,117,109,101,110,116,97,116,105,111,110,58>>]},{pre,[],[{code,[],[<<84,104,101,32,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,32,102,105,101,108,100,32,105,115,32,115,105,109,105,108,97,114,32,116,111,32,109,97,116,99,104,95,108,105,109,105,116,44,32,98,117,116,32,105,110,115,116,101,97,100,10,111,102,32,108,105,109,105,116,105,110,103,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,116,105,109,101,115,32,116,104,97,116,32,109,97,116,99,104,40,41,32,105,115,32,99,97,108,108,101,100,44,32,105,116,10,108,105,109,105,116,115,32,116,104,101,32,100,101,112,116,104,32,111,102,32,114,101,99,117,114,115,105,111,110,46,32,84,104,101,32,114,101,99,117,114,115,105,111,110,32,100,101,112,116,104,32,105,115,32,97,32,115,109,97,108,108,101,114,32,110,117,109,98,101,114,10,116,104,97,110,32,116,104,101,32,116,111,116,97,108,32,110,117,109,98,101,114,32,111,102,32,99,97,108,108,115,44,32,98,101,99,97,117,115,101,32,110,111,116,32,97,108,108,32,99,97,108,108,115,32,116,111,32,109,97,116,99,104,40,41,32,97,114,101,10,114,101,99,117,114,115,105,118,101,46,32,84,104,105,115,32,108,105,109,105,116,32,105,115,32,111,102,32,117,115,101,32,111,110,108,121,32,105,102,32,105,116,32,105,115,32,115,101,116,32,115,109,97,108,108,101,114,32,116,104,97,110,10,109,97,116,99,104,95,108,105,109,105,116,46,10,10,76,105,109,105,116,105,110,103,32,116,104,101,32,114,101,99,117,114,115,105,111,110,32,100,101,112,116,104,32,108,105,109,105,116,115,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,109,97,99,104,105,110,101,32,115,116,97,99,107,32,116,104,97,116,10,99,97,110,32,98,101,32,117,115,101,100,44,32,111,114,44,32,119,104,101,110,32,80,67,82,69,32,104,97,115,32,98,101,101,110,32,99,111,109,112,105,108,101,100,32,116,111,32,117,115,101,32,109,101,109,111,114,121,32,111,110,32,116,104,101,32,104,101,97,112,10,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32,115,116,97,99,107,44,32,116,104,101,32,97,109,111,117,110,116,32,111,102,32,104,101,97,112,32,109,101,109,111,114,121,32,116,104,97,116,32,99,97,110,32,98,101,32,117,115,101,100,46>>]}]},{p,[],[<<84,104,101,32,69,114,108,97,110,103,32,86,77,32,117,115,101,115,32,97,32,80,67,82,69,32,108,105,98,114,97,114,121,32,119,104,101,114,101,32,104,101,97,112,32,109,101,109,111,114,121,32,105,115,32,117,115,101,100,32,119,104,101,110,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,32,114,101,99,117,114,115,105,111,110,32,111,99,99,117,114,115,46,32,84,104,105,115,32,116,104,101,114,101,102,111,114,101,32,108,105,109,105,116,115,32,116,104,101,32,117,115,101,32,111,102,32,109,97,99,104,105,110,101,32,104,101,97,112,44,32,110,111,116,32,67,32,115,116,97,99,107,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,97,32,108,111,119,101,114,32,118,97,108,117,101,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,109,97,116,99,104,101,115,32,119,105,116,104,32,100,101,101,112,32,114,101,99,117,114,115,105,111,110,32,102,97,105,108,105,110,103,44,32,119,104,101,110,32,116,104,101,121,32,115,104,111,117,108,100,32,104,97,118,101,32,109,97,116,99,104,101,100,58>>]},{pre,[],[{code,[{type,<<110,111,110,101>>}],[<<49,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,41,46,10,123,109,97,116,99,104,44,91,123,48,44,49,52,125,44,123,48,44,49,51,125,93,125,10,50,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,44,91,123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,53,125,93,41,46,10,110,111,109,97,116,99,104,10,51,62,32,114,101,58,114,117,110,40,34,97,97,97,97,97,97,97,97,97,97,97,97,97,122,34,44,34,40,97,43,41,42,122,34,44,91,123,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,44,53,125,44,114,101,112,111,114,116,95,101,114,114,111,114,115,93,41,46,10,123,101,114,114,111,114,44,109,97,116,99,104,95,108,105,109,105,116,95,114,101,99,117,114,115,105,111,110,125>>]}]},{p,[],[<<84,104,105,115,32,111,112,116,105,111,110,32,97,110,100,32,111,112,116,105,111,110,32>>,{code,[],[<<109,97,116,99,104,95,108,105,109,105,116>>]},<<32,97,114,101,32,111,110,108,121,32,116,111,32,98,101,32,117,115,101,100,32,105,110,32,114,97,114,101,32,99,97,115,101,115,46,32,85,110,100,101,114,115,116,97,110,100,105,110,103,32,111,102,32,116,104,101,32,80,67,82,69,32,108,105,98,114,97,114,121,32,105,110,116,101,114,110,97,108,115,32,105,115,32,114,101,99,111,109,109,101,110,100,101,100,32,98,101,102,111,114,101,32,116,97,109,112,101,114,105,110,103,32,119,105,116,104,32,116,104,101,115,101,32,108,105,109,105,116,115,46>>]}]},{dt,[],[{code,[],[<<123,111,102,102,115,101,116,44,32,105,110,116,101,103,101,114,40,41,32,62,61,32,48,125>>]}]},{dd,[],[{p,[],[<<83,116,97,114,116,32,109,97,116,99,104,105,110,103,32,97,116,32,116,104,101,32,111,102,102,115,101,116,32,40,112,111,115,105,116,105,111,110,41,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,101,32,111,102,102,115,101,116,32,105,115,32,122,101,114,111,45,98,97,115,101,100,44,32,115,111,32,116,104,97,116,32,116,104,101,32,100,101,102,97,117,108,116,32,105,115,32>>,{code,[],[<<123,111,102,102,115,101,116,44,48,125>>]},<<32,40,97,108,108,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,41,46>>]}]},{dt,[],[{code,[],[<<123,110,101,119,108,105,110,101,44,32,78,76,83,112,101,99,125>>]}]},{dd,[],[{p,[],[<<79,118,101,114,114,105,100,101,115,32,116,104,101,32,100,101,102,97,117,108,116,32,100,101,102,105,110,105,116,105,111,110,32,111,102,32,97,32,110,101,119,108,105,110,101,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,119,104,105,99,104,32,105,115,32,76,70,32,40,65,83,67,73,73,32,49,48,41,32,105,110,32,69,114,108,97,110,103,46>>]},{dl,[],[{dt,[],[{code,[],[<<99,114>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,67,82,32,40,65,83,67,73,73,32,49,51,41,46>>]}]},{dt,[],[{code,[],[<<108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,97,32,115,105,110,103,108,101,32,99,104,97,114,97,99,116,101,114,32,76,70,32,40,65,83,67,73,73,32,49,48,41,44,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<99,114,108,102>>]}]},{dd,[],[{p,[],[<<78,101,119,108,105,110,101,32,105,115,32,105,110,100,105,99,97,116,101,100,32,98,121,32,116,104,101,32,116,119,111,45,99,104,97,114,97,99,116,101,114,32,67,82,76,70,32,40,65,83,67,73,73,32,49,51,32,102,111,108,108,111,119,101,100,32,98,121,32,65,83,67,73,73,32,49,48,41,32,115,101,113,117,101,110,99,101,46>>]}]},{dt,[],[{code,[],[<<97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,116,104,114,101,101,32,112,114,101,99,101,100,105,110,103,32,115,101,113,117,101,110,99,101,115,32,105,115,32,98,101,32,114,101,99,111,103,110,105,122,101,100,46>>]}]},{dt,[],[{code,[],[<<97,110,121>>]}]},{dd,[],[{p,[],[<<65,110,121,32,111,102,32,116,104,101,32,110,101,119,108,105,110,101,32,115,101,113,117,101,110,99,101,115,32,97,98,111,118,101,44,32,97,110,100,32,116,104,101,32,85,110,105,99,111,100,101,32,115,101,113,117,101,110,99,101,115,32,86,84,32,40,118,101,114,116,105,99,97,108,32,116,97,98,44,32,85,43,48,48,48,66,41,44,32,70,70,32,40,102,111,114,109,102,101,101,100,44,32,85,43,48,48,48,67,41,44,32,78,69,76,32,40,110,101,120,116,32,108,105,110,101,44,32,85,43,48,48,56,53,41,44,32,76,83,32,40,108,105,110,101,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,56,41,44,32,97,110,100,32,80,83,32,40,112,97,114,97,103,114,97,112,104,32,115,101,112,97,114,97,116,111,114,44,32,85,43,50,48,50,57,41,46>>]}]}]}]},{dt,[],[{code,[],[<<98,115,114,95,97,110,121,99,114,108,102>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,111,110,108,121,32,116,104,101,32,67,82,32,76,70,44,32,111,114,32,67,82,76,70,32,115,101,113,117,101,110,99,101,115,44,32,110,111,116,32,116,104,101,32,85,110,105,99,111,100,101,45,115,112,101,99,105,102,105,99,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,46,32,40,79,118,101,114,114,105,100,101,115,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,46,41>>]}]},{dt,[],[{code,[],[<<98,115,114,95,117,110,105,99,111,100,101>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,104,97,116,32,92,82,32,105,115,32,116,111,32,109,97,116,99,104,32,97,108,108,32,116,104,101,32,85,110,105,99,111,100,101,32,110,101,119,108,105,110,101,32,99,104,97,114,97,99,116,101,114,115,32,40,105,110,99,108,117,100,105,110,103,32,67,82,76,70,44,32,97,110,100,32,115,111,32,111,110,44,32,116,104,101,32,100,101,102,97,117,108,116,41,46,32,40,79,118,101,114,114,105,100,101,115,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,46,41>>]}]},{dt,[],[{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,125>>]},<<47>>,{code,[],[<<123,99,97,112,116,117,114,101,44,32,86,97,108,117,101,83,112,101,99,44,32,84,121,112,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,105,99,104,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,110,100,32,105,110,32,119,104,97,116,32,102,111,114,109,97,116,46,32,66,121,32,100,101,102,97,117,108,116,44,32>>,{code,[],[<<114,117,110,47,51>>]},<<32,99,97,112,116,117,114,101,115,32,97,108,108,32,111,102,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,115,116,114,105,110,103,32,97,110,100,32,97,108,108,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,40,97,108,108,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,32,105,115,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32,99,97,112,116,117,114,101,100,41,46,32,84,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32,40,122,101,114,111,45,98,97,115,101,100,41,32,105,110,100,101,120,101,115,32,111,102,32,116,104,101,32,99,97,112,116,117,114,101,100,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,115,112,101,99,105,102,105,101,100,32,97,115,32>>,{code,[],[<<123,79,102,102,115,101,116,44,76,101,110,103,116,104,125>>]},<<32,112,97,105,114,115,32,40,116,104,101,32>>,{code,[],[<<105,110,100,101,120>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<32,111,102,32,99,97,112,116,117,114,105,110,103,41,46>>]},{p,[],[<<65,115,32,97,110,32,101,120,97,109,112,108,101,32,111,102,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,44,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,32,114,101,116,117,114,110,115,44,32,97,115,32,102,105,114,115,116,32,97,110,100,32,111,110,108,121,32,99,97,112,116,117,114,101,100,32,115,116,114,105,110,103,44,32,116,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,40,34,97,98,99,100,34,32,105,110,32,116,104,101,32,109,105,100,100,108,101,41,32,97,115,32,97,110,32,105,110,100,101,120,32,112,97,105,114,32>>,{code,[],[<<123,51,44,52,125>>]},<<44,32,119,104,101,114,101,32,99,104,97,114,97,99,116,101,114,32,112,111,115,105,116,105,111,110,115,32,97,114,101,32,122,101,114,111,45,98,97,115,101,100,44,32,106,117,115,116,32,97,115,32,105,110,32,111,102,102,115,101,116,115,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,97,98,99,100,34,44,91,93,41,46>>]}]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,116,104,105,115,32,99,97,108,108,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<65,110,111,116,104,101,114,32,40,97,110,100,32,113,117,105,116,101,32,99,111,109,109,111,110,41,32,99,97,115,101,32,105,115,32,119,104,101,114,101,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,115,32,97,108,108,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,97,98,99,100,46,42,34,44,91,93,41,46>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103,108,121,32,112,111,105,110,116,115,32,111,117,116,32,97,108,108,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,98,101,103,105,110,110,105,110,103,32,97,116,32,105,110,100,101,120,32,48,44,32,97,110,100,32,105,116,32,105,115,32,49,48,32,99,104,97,114,97,99,116,101,114,115,32,108,111,110,103,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,93,125>>]}]},{p,[],[<<73,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,99,111,110,116,97,105,110,115,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,108,105,107,101,32,105,110,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,97,98,99,100,41,46,42,34,44,91,93,41,46>>]}]},{p,[],[<<97,108,108,32,111,102,32,116,104,101,32,109,97,116,99,104,101,100,32,115,117,98,106,101,99,116,32,105,115,32,99,97,112,116,117,114,101,100,44,32,97,115,32,119,101,108,108,32,97,115,32,116,104,101,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,44,123,51,44,52,125,93,125>>]}]},{p,[],[<<84,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,116,116,101,114,110,32,97,108,119,97,121,115,32,103,105,118,101,115,32,116,104,101,32,102,105,114,115,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,110,32,116,104,101,32,108,105,115,116,32,97,110,100,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,97,100,100,101,100,32,105,110,32,116,104,101,32,111,114,100,101,114,32,116,104,101,121,32,111,99,99,117,114,114,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,101,32,99,97,112,116,117,114,101,32,116,117,112,108,101,32,105,115,32,98,117,105,108,116,32,117,112,32,97,115,32,102,111,108,108,111,119,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<86,97,108,117,101,83,112,101,99>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,119,104,105,99,104,32,99,97,112,116,117,114,101,100,32,40,115,117,98,41,112,97,116,116,101,114,110,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32>>,{code,[],[<<86,97,108,117,101,83,112,101,99>>]},<<32,99,97,110,32,101,105,116,104,101,114,32,98,101,32,97,110,32,97,116,111,109,32,100,101,115,99,114,105,98,105,110,103,32,97,32,112,114,101,100,101,102,105,110,101,100,32,115,101,116,32,111,102,32,114,101,116,117,114,110,32,118,97,108,117,101,115,44,32,111,114,32,97,32,108,105,115,116,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,105,110,100,101,120,101,115,32,111,114,32,116,104,101,32,110,97,109,101,115,32,111,102,32,115,112,101,99,105,102,105,99,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,114,101,116,117,114,110,46>>]},{p,[],[<<84,104,101,32,102,111,108,108,111,119,105,110,103,32,97,114,101,32,116,104,101,32,112,114,101,100,101,102,105,110,101,100,32,115,101,116,115,32,111,102,32,115,117,98,112,97,116,116,101,114,110,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<97,108,108>>]}]},{dd,[],[{p,[],[<<65,108,108,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,46,32,84,104,105,115,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<97,108,108,95,110,97,109,101,115>>]}]},{dd,[],[{p,[],[<<65,108,108,32>>,{em,[],[<<110,97,109,101,100>>]},<<32,115,117,98,112,97,116,116,101,114,110,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,115,32,105,102,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32,97,108,108,32,116,104,101,32,110,97,109,101,115,32>>,{em,[],[<<105,110,32,97,108,112,104,97,98,101,116,105,99,97,108,32,111,114,100,101,114>>]},<<32,119,97,115,32,115,112,101,99,105,102,105,101,100,46,32,84,104,101,32,108,105,115,116,32,111,102,32,97,108,108,32,110,97,109,101,115,32,99,97,110,32,97,108,115,111,32,98,101,32,114,101,116,114,105,101,118,101,100,32,119,105,116,104,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,105,110,115,112,101,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,110,115,112,101,99,116,47,50>>]}]},<<46>>]}]},{dt,[],[{code,[],[<<102,105,114,115,116>>]}]},{dd,[],[{p,[],[<<79,110,108,121,32,116,104,101,32,102,105,114,115,116,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,44,32,119,104,105,99,104,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,46,32,65,108,108,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,100,105,115,99,97,114,100,101,100,46>>]}]},{dt,[],[{code,[],[<<97,108,108,95,98,117,116,95,102,105,114,115,116>>]}]},{dd,[],[{p,[],[<<65,108,108,32,98,117,116,32,116,104,101,32,102,105,114,115,116,32,109,97,116,99,104,105,110,103,32,115,117,98,112,97,116,116,101,114,110,44,32,116,104,97,116,32,105,115,44,32,97,108,108,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,44,32,98,117,116,32,110,111,116,32,116,104,101,32,99,111,109,112,108,101,116,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,46,32,84,104,105,115,32,105,115,32,117,115,101,102,117,108,32,105,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,115,32,97,32,119,104,111,108,101,32,109,97,116,99,104,101,115,32,97,32,108,97,114,103,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,44,32,98,117,116,32,116,104,101,32,112,97,114,116,32,121,111,117,32,97,114,101,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,105,115,32,105,110,32,97,110,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,46,32,73,102,32,116,104,101,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32>>,{code,[],[<<108,105,115,116>>]},<<32,111,114,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<44,32,110,111,116,32,114,101,116,117,114,110,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,121,111,117,32,97,114,101,32,110,111,116,32,105,110,116,101,114,101,115,116,101,100,32,105,110,32,105,115,32,97,32,103,111,111,100,32,119,97,121,32,116,111,32,111,112,116,105,109,105,122,101,46>>]}]},{dt,[],[{code,[],[<<110,111,110,101>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,110,111,32,109,97,116,99,104,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,103,105,118,101,115,32,116,104,101,32,115,105,110,103,108,101,32,97,116,111,109,32>>,{code,[],[<<109,97,116,99,104>>]},<<32,97,115,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,119,104,101,110,32,109,97,116,99,104,105,110,103,32,115,117,99,99,101,115,115,102,117,108,108,121,32,105,110,115,116,101,97,100,32,111,102,32,116,104,101,32>>,{code,[],[<<123,109,97,116,99,104,44,32,108,105,115,116,40,41,125>>]},<<32,114,101,116,117,114,110,46,32,83,112,101,99,105,102,121,105,110,103,32,97,110,32,101,109,112,116,121,32,108,105,115,116,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,98,101,104,97,118,105,111,114,46>>]}]}]},{p,[],[<<84,104,101,32,118,97,108,117,101,32,108,105,115,116,32,105,115,32,97,32,108,105,115,116,32,111,102,32,105,110,100,101,120,101,115,32,102,111,114,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,114,101,116,117,114,110,44,32,119,104,101,114,101,32,105,110,100,101,120,32,48,32,105,115,32,102,111,114,32,97,108,108,32,111,102,32,116,104,101,32,112,97,116,116,101,114,110,44,32,97,110,100,32,49,32,105,115,32,102,111,114,32,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,110,100,32,115,111,32,111,110,46,32,87,104,101,110,32,117,115,105,110,103,32,110,97,109,101,100,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,40,115,101,101,32,98,101,108,111,119,41,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,111,110,101,32,99,97,110,32,117,115,101,32>>,{code,[],[<<97,116,111,109,40,41>>]},<<115,32,111,114,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<115,32,116,111,32,115,112,101,99,105,102,121,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,115,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<34,46,42,40,97,98,99,100,41,46,42,34>>]}]},{p,[],[<<109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,115,116,114,105,110,103,32,34,65,66,67,97,98,99,100,65,66,67,34,44,32,99,97,112,116,117,114,105,110,103,32,111,110,108,121,32,116,104,101,32,34,97,98,99,100,34,32,112,97,114,116,32,40,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,32,115,117,98,112,97,116,116,101,114,110,41,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,49,93,125,93,41,46>>]}]},{p,[],[<<84,104,101,32,99,97,108,108,32,103,105,118,101,115,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,115,117,108,116,44,32,97,115,32,116,104,101,32,102,105,114,115,116,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,34,40,97,98,99,100,41,34,44,32,109,97,116,99,104,105,110,103,32,34,97,98,99,100,34,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,44,32,97,116,32,40,122,101,114,111,45,98,97,115,101,100,41,32,112,111,115,105,116,105,111,110,32,51,44,32,111,102,32,108,101,110,103,116,104,32,52,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<67,111,110,115,105,100,101,114,32,116,104,101,32,115,97,109,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,98,117,116,32,119,105,116,104,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,101,120,112,108,105,99,105,116,108,121,32,110,97,109,101,100,32,39,70,79,79,39,58>>]},{pre,[],[{code,[],[<<34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34>>]}]},{p,[],[<<87,105,116,104,32,116,104,105,115,32,101,120,112,114,101,115,115,105,111,110,44,32,119,101,32,99,111,117,108,100,32,115,116,105,108,108,32,103,105,118,101,32,116,104,101,32,105,110,100,101,120,32,111,102,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,119,105,116,104,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,99,97,108,108,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,49,93,125,93,41,46>>]}]},{p,[],[<<103,105,118,105,110,103,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,98,101,102,111,114,101,46,32,66,117,116,44,32,97,115,32,116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,105,115,32,110,97,109,101,100,44,32,119,101,32,99,97,110,32,97,108,115,111,32,115,112,101,99,105,102,121,32,105,116,115,32,110,97,109,101,32,105,110,32,116,104,101,32,118,97,108,117,101,32,108,105,115,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,65,66,67,97,98,99,100,65,66,67,34,44,34,46,42,40,63,60,70,79,79,62,97,98,99,100,41,46,42,34,44,91,123,99,97,112,116,117,114,101,44,91,39,70,79,79,39,93,125,93,41,46>>]}]},{p,[],[<<84,104,105,115,32,119,111,117,108,100,32,103,105,118,101,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,101,97,114,108,105,101,114,32,101,120,97,109,112,108,101,115,44,32,110,97,109,101,108,121,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,51,44,52,125,93,125>>]}]},{p,[],[<<84,104,101,32,118,97,108,117,101,115,32,108,105,115,116,32,99,97,110,32,115,112,101,99,105,102,121,32,105,110,100,101,120,101,115,32,111,114,32,110,97,109,101,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,105,110,32,119,104,105,99,104,32,99,97,115,101,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,115,32,118,97,114,121,32,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,116,121,112,101,46,32,73,102,32,116,104,101,32,116,121,112,101,32,105,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<44,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,45,49,44,48,125>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,102,111,114,32,118,97,108,117,101,115,32,119,105,116,104,32,110,111,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,115,117,98,112,97,116,116,101,114,110,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,98,117,116,32,102,111,114,32,116,104,101,32,111,116,104,101,114,32,116,121,112,101,115,32,40>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,97,110,100,32>>,{code,[],[<<108,105,115,116>>]},<<41,44,32,116,104,101,32,118,97,108,117,101,115,32,97,114,101,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,111,114,32,108,105,115,116,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]}]},{dt,[],[{code,[],[<<84,121,112,101>>]}]},{dd,[],[{p,[],[<<79,112,116,105,111,110,97,108,108,121,32,115,112,101,99,105,102,105,101,115,32,104,111,119,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,114,101,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,73,102,32,111,109,105,116,116,101,100,44,32,116,104,101,32,100,101,102,97,117,108,116,32,111,102,32>>,{code,[],[<<105,110,100,101,120>>]},<<32,105,115,32,117,115,101,100,46>>]},{p,[],[{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,111,110,101,32,111,102,32,116,104,101,32,102,111,108,108,111,119,105,110,103,58>>]},{dl,[],[{dt,[],[{code,[],[<<105,110,100,101,120>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,99,97,112,116,117,114,101,100,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,112,97,105,114,115,32,111,102,32,98,121,116,101,32,105,110,100,101,120,101,115,32,105,110,116,111,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,97,110,100,32,108,101,110,103,116,104,32,111,102,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,116,114,105,110,103,32,105,110,32,116,104,101,32,115,117,98,106,101,99,116,32,40,97,115,32,105,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,97,115,32,102,108,97,116,116,101,110,101,100,32,119,105,116,104,32>>,{a,[{href,<<101,114,116,115,58,101,114,108,97,110,103,35,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,114,108,97,110,103,58,105,111,108,105,115,116,95,116,111,95,98,105,110,97,114,121,47,49>>]}]},<<32,111,114,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,99,111,100,101,58,99,104,97,114,97,99,116,101,114,115,95,116,111,95,98,105,110,97,114,121,47,50>>]}]},<<32,98,101,102,111,114,101,32,109,97,116,99,104,105,110,103,41,46,32,78,111,116,105,99,101,32,116,104,97,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,115,117,108,116,115,32,105,110,32>>,{em,[],[<<98,121,116,101,45,111,114,105,101,110,116,101,100>>]},<<32,105,110,100,101,120,101,115,32,105,110,32,97,32,40,112,111,115,115,105,98,108,121,32,118,105,114,116,117,97,108,41,32>>,{em,[],[<<85,84,70,45,56,32,101,110,99,111,100,101,100>>]},<<32,98,105,110,97,114,121,46,32,65,32,98,121,116,101,32,105,110,100,101,120,32,116,117,112,108,101,32>>,{code,[],[<<123,48,44,50,125>>]},<<32,99,97,110,32,116,104,101,114,101,102,111,114,101,32,114,101,112,114,101,115,101,110,116,32,111,110,101,32,111,114,32,116,119,111,32,99,104,97,114,97,99,116,101,114,115,32,119,104,101,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,105,110,32,101,102,102,101,99,116,46,32,84,104,105,115,32,99,97,110,32,115,101,101,109,32,99,111,117,110,116,101,114,45,105,110,116,117,105,116,105,118,101,44,32,98,117,116,32,104,97,115,32,98,101,101,110,32,100,101,101,109,101,100,32,116,104,101,32,109,111,115,116,32,101,102,102,101,99,116,105,118,101,32,97,110,100,32,117,115,101,102,117,108,32,119,97,121,32,116,111,32,100,111,32,105,116,46,32,84,111,32,114,101,116,117,114,110,32,108,105,115,116,115,32,105,110,115,116,101,97,100,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,115,105,109,112,108,101,114,32,99,111,100,101,32,105,102,32,116,104,97,116,32,105,115,32,100,101,115,105,114,101,100,46,32,84,104,105,115,32,114,101,116,117,114,110,32,116,121,112,101,32,105,115,32,116,104,101,32,100,101,102,97,117,108,116,46>>]}]},{dt,[],[{code,[],[<<108,105,115,116>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,109,97,116,99,104,105,110,103,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,108,105,115,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,69,114,108,97,110,103,32>>,{code,[],[<<115,116,114,105,110,103,40,41>>]},<<115,41,46,32,73,116,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,117,115,101,100,32,105,110,32,99,111,109,98,105,110,97,116,105,111,110,32,119,105,116,104,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,97,32,99,97,112,116,117,114,101,100,32,115,117,98,112,97,116,116,101,114,110,32,99,97,110,32,99,111,110,116,97,105,110,32,98,121,116,101,115,32,116,104,97,116,32,97,114,101,32,110,111,116,32,118,97,108,105,100,32,85,84,70,45,56,32,40,92,67,32,109,97,116,99,104,101,115,32,98,121,116,101,115,32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,99,104,97,114,97,99,116,101,114,32,101,110,99,111,100,105,110,103,41,46,32,73,110,32,116,104,97,116,32,99,97,115,101,32,116,104,101,32>>,{code,[],[<<108,105,115,116>>]},<<32,99,97,112,116,117,114,105,110,103,32,99,97,110,32,114,101,115,117,108,116,32,105,110,32,116,104,101,32,115,97,109,101,32,116,121,112,101,115,32,111,102,32,116,117,112,108,101,115,32,116,104,97,116,32>>,{a,[{href,<<115,116,100,108,105,98,58,117,110,105,99,111,100,101,35,99,104,97,114,97,99,116,101,114,115,95,116,111,95,108,105,115,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,99,111,100,101,58,99,104,97,114,97,99,116,101,114,115,95,116,111,95,108,105,115,116,47,50>>]}]},<<32,99,97,110,32,114,101,116,117,114,110,44,32,110,97,109,101,108,121,32,116,104,114,101,101,45,116,117,112,108,101,115,32,119,105,116,104,32,116,97,103,32>>,{code,[],[<<105,110,99,111,109,112,108,101,116,101>>]},<<32,111,114,32>>,{code,[],[<<101,114,114,111,114>>]},<<44,32,116,104,101,32,115,117,99,99,101,115,115,102,117,108,108,121,32,99,111,110,118,101,114,116,101,100,32,99,104,97,114,97,99,116,101,114,115,32,97,110,100,32,116,104,101,32,105,110,118,97,108,105,100,32,85,84,70,45,56,32,116,97,105,108,32,111,102,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,97,115,32,97,32,98,105,110,97,114,121,46,32,84,104,101,32,98,101,115,116,32,115,116,114,97,116,101,103,121,32,105,115,32,116,111,32,97,118,111,105,100,32,117,115,105,110,103,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,119,104,101,110,32,99,97,112,116,117,114,105,110,103,32,108,105,115,116,115,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<82,101,116,117,114,110,115,32,109,97,116,99,104,105,110,103,32,115,117,98,115,116,114,105,110,103,115,32,97,115,32,98,105,110,97,114,105,101,115,46,32,73,102,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,105,115,32,117,115,101,100,44,32,116,104,101,115,101,32,98,105,110,97,114,105,101,115,32,97,114,101,32,105,110,32,85,84,70,45,56,46,32,73,102,32,116,104,101,32,92,67,32,115,101,113,117,101,110,99,101,32,105,115,32,117,115,101,100,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<44,32,116,104,101,32,98,105,110,97,114,105,101,115,32,99,97,110,32,98,101,32,105,110,118,97,108,105,100,32,85,84,70,45,56,46>>]}]}]}]}]},{p,[],[<<73,110,32,103,101,110,101,114,97,108,44,32,115,117,98,112,97,116,116,101,114,110,115,32,116,104,97,116,32,119,101,114,101,32,110,111,116,32,97,115,115,105,103,110,101,100,32,97,32,118,97,108,117,101,32,105,110,32,116,104,101,32,109,97,116,99,104,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,116,117,112,108,101,32>>,{code,[],[<<123,45,49,44,48,125>>]},<<32,119,104,101,110,32>>,{code,[],[<<116,121,112,101>>]},<<32,105,115,32>>,{code,[],[<<105,110,100,101,120>>]},<<46,32,85,110,97,115,115,105,103,110,101,100,32,115,117,98,112,97,116,116,101,114,110,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,97,115,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,111,114,32,108,105,115,116,44,32,114,101,115,112,101,99,116,105,118,101,108,121,44,32,102,111,114,32,111,116,104,101,114,32,114,101,116,117,114,110,32,116,121,112,101,115,46,32,67,111,110,115,105,100,101,114,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,58>>]},{pre,[],[{code,[],[<<34,46,42,40,40,63,60,70,79,79,62,97,98,100,100,41,124,97,40,46,46,100,41,41,46,42,34>>]}]},{p,[],[<<84,104,101,114,101,32,97,114,101,32,116,104,114,101,101,32,101,120,112,108,105,99,105,116,108,121,32,99,97,112,116,117,114,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,44,32,119,104,101,114,101,32,116,104,101,32,111,112,101,110,105,110,103,32,112,97,114,101,110,116,104,101,115,105,115,32,112,111,115,105,116,105,111,110,32,100,101,116,101,114,109,105,110,101,115,32,116,104,101,32,111,114,100,101,114,32,105,110,32,116,104,101,32,114,101,115,117,108,116,44,32,104,101,110,99,101,32>>,{code,[],[<<40,40,63,60,70,79,79,62,97,98,100,100,41,124,97,40,46,46,100,41,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,49,44,32>>,{code,[],[<<40,63,60,70,79,79,62,97,98,100,100,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,50,44,32,97,110,100,32>>,{code,[],[<<40,46,46,100,41>>]},<<32,105,115,32,115,117,98,112,97,116,116,101,114,110,32,105,110,100,101,120,32,51,46,32,87,104,101,110,32,109,97,116,99,104,101,100,32,97,103,97,105,110,115,116,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,115,116,114,105,110,103,58>>]},{pre,[],[{code,[],[<<34,65,66,67,97,98,99,100,65,66,67,34>>]}]},{p,[],[<<116,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,116,32,105,110,100,101,120,32,50,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,44,32,97,115,32,34,97,98,100,100,34,32,105,115,32,110,111,116,32,112,114,101,115,101,110,116,32,105,110,32,116,104,101,32,115,116,114,105,110,103,44,32,98,117,116,32,116,104,101,32,99,111,109,112,108,101,116,101,32,112,97,116,116,101,114,110,32,109,97,116,99,104,101,115,32,40,98,101,99,97,117,115,101,32,111,102,32,116,104,101,32,97,108,116,101,114,110,97,116,105,118,101,32>>,{code,[],[<<97,40,46,46,100,41>>]},<<41,46,32,84,104,101,32,115,117,98,112,97,116,116,101,114,110,32,97,116,32,105,110,100,101,120,32,50,32,105,115,32,116,104,101,114,101,102,111,114,101,32,117,110,97,115,115,105,103,110,101,100,32,97,110,100,32,116,104,101,32,100,101,102,97,117,108,116,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,123,48,44,49,48,125,44,123,51,44,52,125,44,123,45,49,44,48,125,44,123,52,44,51,125,93,125>>]}]},{p,[],[<<83,101,116,116,105,110,103,32,116,104,101,32,99,97,112,116,117,114,101,32>>,{code,[],[<<84,121,112,101>>]},<<32,116,111,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,103,105,118,101,115,58>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,60,60,34,65,66,67,97,98,99,100,65,66,67,34,62,62,44,60,60,34,97,98,99,100,34,62,62,44,60,60,62,62,44,60,60,34,98,99,100,34,62,62,93,125>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,101,109,112,116,121,32,98,105,110,97,114,121,32,40>>,{code,[],[<<60,60,62,62>>]},<<41,32,114,101,112,114,101,115,101,110,116,115,32,116,104,101,32,117,110,97,115,115,105,103,110,101,100,32,115,117,98,112,97,116,116,101,114,110,46,32,73,110,32,116,104,101,32>>,{code,[],[<<98,105,110,97,114,121>>]},<<32,99,97,115,101,44,32,115,111,109,101,32,105,110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,32,116,104,101,32,109,97,116,99,104,105,110,103,32,105,115,32,116,104,101,114,101,102,111,114,101,32,108,111,115,116,44,32,97,115,32>>,{code,[],[<<60,60,62,62>>]},<<32,99,97,110,32,97,108,115,111,32,98,101,32,97,110,32,101,109,112,116,121,32,115,116,114,105,110,103,32,99,97,112,116,117,114,101,100,46>>]},{p,[],[<<73,102,32,100,105,102,102,101,114,101,110,116,105,97,116,105,111,110,32,98,101,116,119,101,101,110,32,101,109,112,116,121,32,109,97,116,99,104,101,115,32,97,110,100,32,110,111,110,45,101,120,105,115,116,105,110,103,32,115,117,98,112,97,116,116,101,114,110,115,32,105,115,32,110,101,99,101,115,115,97,114,121,44,32,117,115,101,32,116,104,101,32>>,{code,[],[<<116,121,112,101>>]},<<32>>,{code,[],[<<105,110,100,101,120>>]},<<32,97,110,100,32,100,111,32,116,104,101,32,99,111,110,118,101,114,115,105,111,110,32,116,111,32,116,104,101,32,102,105,110,97,108,32,116,121,112,101,32,105,110,32,69,114,108,97,110,103,32,99,111,100,101,46>>]},{p,[],[<<87,104,101,110,32,111,112,116,105,111,110,32>>,{code,[],[<<103,108,111,98,97,108>>]},<<32,105,115,32,115,112,101,99,105,105,102,105,101,100,44,32,116,104,101,32>>,{code,[],[<<99,97,112,116,117,114,101>>]},<<32,115,112,101,99,105,102,105,99,97,116,105,111,110,32,97,102,102,101,99,116,115,32,101,97,99,104,32,109,97,116,99,104,32,115,101,112,97,114,97,116,101,108,121,44,32,115,111,32,116,104,97,116,58>>]},{pre,[],[{code,[],[<<114,101,58,114,117,110,40,34,99,97,99,98,34,44,34,99,40,97,124,98,41,34,44,91,103,108,111,98,97,108,44,123,99,97,112,116,117,114,101,44,91,49,93,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<123,109,97,116,99,104,44,91,91,34,97,34,93,44,91,34,98,34,93,93,125>>]}]}]}]},{p,[],[<<70,111,114,32,97,32,100,101,115,99,114,105,112,116,105,111,110,115,32,111,102,32,111,112,116,105,111,110,115,32,111,110,108,121,32,97,102,102,101,99,116,105,110,103,32,116,104,101,32,99,111,109,112,105,108,97,116,105,111,110,32,115,116,101,112,44,32,115,101,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,99,111,109,112,105,108,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<99,111,109,112,105,108,101,47,50>>]}]},<<46>>]}]},#{signature => [{attribute,{78,2},spec,{{run,3},[{type,{78,10},bounded_fun,[{type,{78,10},'fun',[{type,{78,10},product,[{var,{78,11},'Subject'},{var,{78,20},'RE'},{var,{78,24},'Options'}]},{type,{78,36},union,[{type,{78,36},tuple,[{atom,{78,37},match},{var,{78,44},'Captured'}]},{atom,{79,36},match},{atom,{80,36},nomatch},{type,{81,8},tuple,[{atom,{81,9},error},{var,{81,16},'ErrType'}]}]}]},[{type,{82,7},constraint,[{atom,{82,7},is_subtype},[{var,{82,7},'Subject'},{type,{82,18},union,[{type,{82,18},iodata,[]},{remote_type,{82,29},[{atom,{82,29},unicode},{atom,{82,37},charlist},[]]}]}]]},{type,{83,7},constraint,[{atom,{83,7},is_subtype},[{var,{83,7},'RE'},{type,{83,13},union,[{user_type,{83,13},mp,[]},{type,{83,20},iodata,[]},{remote_type,{83,31},[{atom,{83,31},unicode},{atom,{83,39},charlist},[]]}]}]]},{type,{84,7},constraint,[{atom,{84,7},is_subtype},[{var,{84,7},'Options'},{type,{84,18},list,[{var,{84,19},'Option'}]}]]},{type,{85,7},constraint,[{atom,{85,7},is_subtype},[{var,{85,7},'Option'},{type,{85,17},union,[{atom,{85,17},anchored},{atom,{85,28},global},{atom,{85,37},notbol},{atom,{85,46},noteol},{atom,{85,55},notempty},{atom,{86,10},notempty_atstart},{atom,{86,29},report_errors},{type,{87,17},tuple,[{atom,{87,18},offset},{type,{87,26},non_neg_integer,[]}]},{type,{88,3},tuple,[{atom,{88,4},match_limit},{type,{88,17},non_neg_integer,[]}]},{type,{89,3},tuple,[{atom,{89,4},match_limit_recursion},{type,{89,27},non_neg_integer,[]}]},{type,{90,17},tuple,[{atom,{90,18},newline},{ann_type,{90,27},[{var,{90,27},'NLSpec'},{user_type,{90,37},nl_spec,[]}]}]},{atom,{91,17},bsr_anycrlf},{atom,{91,31},bsr_unicode},{type,{91,45},tuple,[{atom,{91,46},capture},{var,{91,55},'ValueSpec'}]},{type,{92,17},tuple,[{atom,{92,18},capture},{var,{92,27},'ValueSpec'},{var,{92,38},'Type'}]},{var,{92,46},'CompileOpt'}]}]]},{type,{93,7},constraint,[{atom,{93,7},is_subtype},[{var,{93,7},'Type'},{type,{93,15},union,[{atom,{93,15},index},{atom,{93,23},list},{atom,{93,30},binary}]}]]},{type,{94,7},constraint,[{atom,{94,7},is_subtype},[{var,{94,7},'ValueSpec'},{type,{94,20},union,[{atom,{94,20},all},{atom,{94,26},all_but_first},{atom,{94,42},all_names},{atom,{94,54},first},{atom,{94,62},none},{var,{94,69},'ValueList'}]}]]},{type,{95,7},constraint,[{atom,{95,7},is_subtype},[{var,{95,7},'ValueList'},{type,{95,20},list,[{var,{95,21},'ValueID'}]}]]},{type,{96,7},constraint,[{atom,{96,7},is_subtype},[{var,{96,7},'ValueID'},{type,{96,18},union,[{type,{96,18},integer,[]},{type,{96,30},string,[]},{type,{96,41},atom,[]}]}]]},{type,{97,7},constraint,[{atom,{97,7},is_subtype},[{var,{97,7},'CompileOpt'},{user_type,{97,21},compile_option,[]}]]},{type,{98,7},constraint,[{atom,{98,7},is_subtype},[{var,{98,7},'Captured'},{type,{98,19},union,[{type,{98,19},list,[{var,{98,20},'CaptureData'}]},{type,{98,35},list,[{type,{98,36},list,[{var,{98,37},'CaptureData'}]}]}]}]]},{type,{99,7},constraint,[{atom,{99,7},is_subtype},[{var,{99,7},'CaptureData'},{type,{99,22},union,[{type,{99,22},tuple,[{type,{99,23},integer,[]},{type,{99,34},integer,[]}]},{var,{100,22},'ListConversionData'},{type,{101,22},binary,[]}]}]]},{type,{102,7},constraint,[{atom,{102,7},is_subtype},[{var,{102,7},'ListConversionData'},{type,{102,29},union,[{type,{102,29},string,[]},{type,{103,29},tuple,[{atom,{103,30},error},{type,{103,37},string,[]},{type,{103,47},binary,[]}]},{type,{104,29},tuple,[{atom,{104,30},incomplete},{type,{104,42},string,[]},{type,{104,52},binary,[]}]}]}]]},{type,{105,7},constraint,[{atom,{105,7},is_subtype},[{var,{105,7},'ErrType'},{type,{105,18},union,[{atom,{105,18},match_limit},{atom,{105,32},match_limit_recursion},{type,{105,56},tuple,[{atom,{105,57},compile},{var,{105,67},'CompileErr'}]}]}]]},{type,{106,7},constraint,[{atom,{106,7},is_subtype},[{var,{106,7},'CompileErr'},{type,{106,21},tuple,[{ann_type,{106,22},[{var,{106,22},'ErrString'},{type,{106,35},string,[]}]},{ann_type,{106,45},[{var,{106,45},'Position'},{type,{106,57},non_neg_integer,[]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,52,53,49>>}},{{function,split,2},[{file,[114,101,46,101,114,108]},{location,155}],[<<115,112,108,105,116,47,50>>],#{<<101,110>> => [{p,[],[<<83,97,109,101,32,97,115,32>>,{code,[],[<<115,112,108,105,116,40,83,117,98,106,101,99,116,44,32,82,69,44,32,91,93,41>>]},<<46>>]}]},#{signature => [{attribute,{155,2},spec,{{split,2},[{type,{155,12},bounded_fun,[{type,{155,12},'fun',[{type,{155,12},product,[{var,{155,13},'Subject'},{var,{155,22},'RE'}]},{var,{155,29},'SplitList'}]},[{type,{156,7},constraint,[{atom,{156,7},is_subtype},[{var,{156,7},'Subject'},{type,{156,18},union,[{type,{156,18},iodata,[]},{remote_type,{156,29},[{atom,{156,29},unicode},{atom,{156,37},charlist},[]]}]}]]},{type,{157,7},constraint,[{atom,{157,7},is_subtype},[{var,{157,7},'RE'},{type,{157,13},union,[{user_type,{157,13},mp,[]},{type,{157,20},iodata,[]}]}]]},{type,{158,7},constraint,[{atom,{158,7},is_subtype},[{var,{158,7},'SplitList'},{type,{158,20},list,[{type,{158,21},union,[{type,{158,21},iodata,[]},{remote_type,{158,32},[{atom,{158,32},unicode},{atom,{158,40},charlist},[]]}]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,49,48,50,54>>}},{{function,split,3},[{file,[114,101,46,101,114,108]},{location,168}],[<<115,112,108,105,116,47,51>>],#{<<101,110>> => [{p,[],[<<83,112,108,105,116,115,32,116,104,101,32,105,110,112,117,116,32,105,110,116,111,32,112,97,114,116,115,32,98,121,32,102,105,110,100,105,110,103,32,116,111,107,101,110,115,32,97,99,99,111,114,100,105,110,103,32,116,111,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,115,117,112,112,108,105,101,100,46,32,84,104,101,32,115,112,108,105,116,116,105,110,103,32,105,115,32,98,97,115,105,99,97,108,108,121,32,100,111,110,101,32,98,121,32,114,117,110,110,105,110,103,32,97,32,103,108,111,98,97,108,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,32,97,110,100,32,100,105,118,105,100,105,110,103,32,116,104,101,32,105,110,105,116,105,97,108,32,115,116,114,105,110,103,32,119,104,101,114,101,118,101,114,32,97,32,109,97,116,99,104,32,111,99,99,117,114,115,46,32,84,104,101,32,109,97,116,99,104,105,110,103,32,112,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,105,115,32,114,101,109,111,118,101,100,32,102,114,111,109,32,116,104,101,32,111,117,116,112,117,116,46>>]},{p,[],[<<65,115,32,105,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,114,101,35,114,117,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,117,110,47,51>>]}]},<<44,32,97,110,32>>,{code,[],[<<109,112,40,41>>]},<<32,99,111,109,112,105,108,101,100,32,119,105,116,104,32,111,112,116,105,111,110,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,114,101,113,117,105,114,101,115,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,116,111,32,98,101,32,97,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<46,32,73,102,32,99,111,109,112,105,108,97,116,105,111,110,32,105,115,32,100,111,110,101,32,105,109,112,108,105,99,105,116,108,121,32,97,110,100,32,116,104,101,32>>,{code,[],[<<117,110,105,99,111,100,101>>]},<<32,99,111,109,112,105,108,97,116,105,111,110,32,111,112,116,105,111,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,116,111,32,116,104,105,115,32,102,117,110,99,116,105,111,110,44,32,98,111,116,104,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,97,110,100,32>>,{code,[],[<<83,117,98,106,101,99,116>>]},<<32,97,114,101,32,116,111,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,118,97,108,105,100,32,85,110,105,99,111,100,101,32>>,{code,[],[<<99,104,97,114,108,105,115,116,40,41>>]},<<115,46>>]},{p,[],[<<84,104,101,32,114,101,115,117,108,116,32,105,115,32,103,105,118,101,110,32,97,115,32,97,32,108,105,115,116,32,111,102,32,34,115,116,114,105,110,103,115,34,44,32,116,104,101,32,112,114,101,102,101,114,114,101,100,32,100,97,116,97,32,116,121,112,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,111,112,116,105,111,110,32>>,{code,[],[<<114,101,116,117,114,110>>]},<<32,40,100,101,102,97,117,108,116,32>>,{code,[],[<<105,111,100,97,116,97>>]},<<41,46>>]},{p,[],[<<73,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,115,112,101,99,105,102,105,101,100,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,44,32,116,104,101,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,114,101,116,117,114,110,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,105,110,103,32,108,105,115,116,32,97,115,32,119,101,108,108,46,32,70,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,110,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,34,44,34,103,34,93>>]}]},{p,[],[<<119,104,105,108,101>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,40,91,108,110,93,41,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,108,34,44,34,97,34,44,34,110,34,44,34,103,34,93>>]}]},{p,[],[<<84,104,101,32,116,101,120,116,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,40,109,97,114,107,101,100,32,98,121,32,116,104,101,32,112,97,114,101,110,116,104,101,115,101,115,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,41,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,32,119,104,101,114,101,32,105,116,32,119,97,115,32,102,111,117,110,100,46,32,84,104,105,115,32,109,101,97,110,115,32,116,104,97,116,32,99,111,110,99,97,116,101,110,97,116,105,110,103,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,32,115,112,108,105,116,32,119,104,101,114,101,32,116,104,101,32,119,104,111,108,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,105,115,32,97,32,115,105,110,103,108,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,40,97,115,32,105,110,32,116,104,101,32,108,97,115,116,32,101,120,97,109,112,108,101,41,32,97,108,119,97,121,115,32,114,101,115,117,108,116,115,32,105,110,32,116,104,101,32,111,114,105,103,105,110,97,108,32,115,116,114,105,110,103,46>>]},{p,[],[<<65,115,32,116,104,101,114,101,32,105,115,32,110,111,32,109,97,116,99,104,105,110,103,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,102,111,114,32,116,104,101,32,108,97,115,116,32,112,97,114,116,32,105,110,32,116,104,101,32,101,120,97,109,112,108,101,32,40,116,104,101,32,34,103,34,41,44,32,110,111,116,104,105,110,103,32,105,115,32,105,110,115,101,114,116,101,100,32,97,102,116,101,114,32,116,104,97,116,46,32,84,111,32,109,97,107,101,32,116,104,101,32,103,114,111,117,112,32,111,102,32,115,116,114,105,110,103,115,32,97,110,100,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,109,111,114,101,32,111,98,118,105,111,117,115,44,32,111,110,101,32,99,97,110,32,117,115,101,32,111,112,116,105,111,110,32>>,{code,[],[<<103,114,111,117,112>>]},<<44,32,119,104,105,99,104,32,103,114,111,117,112,115,32,116,111,103,101,116,104,101,114,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,119,104,101,110,32,116,104,101,32,115,116,114,105,110,103,32,119,97,115,32,115,112,108,105,116,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,40,91,108,110,93,41,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,103,114,111,117,112,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,91,34,69,114,34,44,34,108,34,93,44,91,34,97,34,44,34,110,34,93,44,91,34,103,34,93,93>>]}]},{p,[],[<<72,101,114,101,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,102,105,114,115,116,32,109,97,116,99,104,101,100,32,116,104,101,32,34,108,34,44,32,99,97,117,115,105,110,103,32,34,69,114,34,32,116,111,32,98,101,32,116,104,101,32,102,105,114,115,116,32,112,97,114,116,32,105,110,32,116,104,101,32,114,101,115,117,108,116,46,32,87,104,101,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,32,109,97,116,99,104,101,100,44,32,116,104,101,32,40,111,110,108,121,41,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,119,97,115,32,98,111,117,110,100,32,116,111,32,116,104,101,32,34,108,34,44,32,115,111,32,116,104,101,32,34,108,34,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,32,116,104,101,32,103,114,111,117,112,32,116,111,103,101,116,104,101,114,32,119,105,116,104,32,34,69,114,34,46,32,84,104,101,32,110,101,120,116,32,109,97,116,99,104,32,105,115,32,111,102,32,116,104,101,32,34,110,34,44,32,109,97,107,105,110,103,32,34,97,34,32,116,104,101,32,110,101,120,116,32,112,97,114,116,32,116,111,32,98,101,32,114,101,116,117,114,110,101,100,46,32,65,115,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,32,105,115,32,98,111,117,110,100,32,116,111,32,115,117,98,115,116,114,105,110,103,32,34,110,34,32,105,110,32,116,104,105,115,32,99,97,115,101,44,32,116,104,101,32,34,110,34,32,105,115,32,105,110,115,101,114,116,101,100,32,105,110,116,111,32,116,104,105,115,32,103,114,111,117,112,46,32,84,104,101,32,108,97,115,116,32,103,114,111,117,112,32,99,111,110,115,105,115,116,115,32,111,102,32,116,104,101,32,114,101,109,97,105,110,105,110,103,32,115,116,114,105,110,103,44,32,97,115,32,110,111,32,109,111,114,101,32,109,97,116,99,104,101,115,32,97,114,101,32,102,111,117,110,100,46>>]},{p,[],[<<66,121,32,100,101,102,97,117,108,116,44,32,97,108,108,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,44,32,105,110,99,108,117,100,105,110,103,32,116,104,101,32,101,109,112,116,121,32,115,116,114,105,110,103,115,44,32,97,114,101,32,114,101,116,117,114,110,101,100,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,34,44,91,93,93>>]}]},{p,[],[<<97,115,32,116,104,101,32,109,97,116,99,104,105,110,103,32,111,102,32,116,104,101,32,34,103,34,32,105,110,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,108,101,97,118,101,115,32,97,110,32,101,109,112,116,121,32,114,101,115,116,44,32,119,104,105,99,104,32,105,115,32,97,108,115,111,32,114,101,116,117,114,110,101,100,46,32,84,104,105,115,32,98,101,104,97,118,105,111,114,32,100,105,102,102,101,114,115,32,102,114,111,109,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32,115,112,108,105,116,32,102,117,110,99,116,105,111,110,32,105,110,32,80,101,114,108,44,32,119,104,101,114,101,32,101,109,112,116,121,32,115,116,114,105,110,103,115,32,97,116,32,116,104,101,32,101,110,100,32,97,114,101,32,98,121,32,100,101,102,97,117,108,116,32,114,101,109,111,118,101,100,46,32,84,111,32,103,101,116,32,116,104,101,32,34,116,114,105,109,109,105,110,103,34,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,80,101,114,108,44,32,115,112,101,99,105,102,121,32>>,{code,[],[<<116,114,105,109>>]},<<32,97,115,32,97,110,32,111,112,116,105,111,110,58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,116,114,105,109,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,34,93>>]}]},{p,[],[<<84,104,101,32,34,116,114,105,109,34,32,111,112,116,105,111,110,32,115,97,121,115,59,32,34,103,105,118,101,32,109,101,32,97,115,32,109,97,110,121,32,112,97,114,116,115,32,97,115,32,112,111,115,115,105,98,108,101,32,101,120,99,101,112,116,32,116,104,101,32,101,109,112,116,121,32,111,110,101,115,34,44,32,119,104,105,99,104,32,115,111,109,101,116,105,109,101,115,32,99,97,110,32,98,101,32,117,115,101,102,117,108,46,32,89,111,117,32,99,97,110,32,97,108,115,111,32,115,112,101,99,105,102,121,32,104,111,119,32,109,97,110,121,32,112,97,114,116,115,32,121,111,117,32,119,97,110,116,44,32,98,121,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44>>]},<<78>>,{code,[],[<<125>>]},<<58>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,123,112,97,114,116,115,44,50,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115>>]},{pre,[],[{code,[],[<<91,34,69,114,34,44,34,97,110,103,34,93>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32,116,104,101,32,108,97,115,116,32,112,97,114,116,32,105,115,32,34,97,110,103,34,44,32,110,111,116,32,34,97,110,34,44,32,97,115,32,115,112,108,105,116,116,105,110,103,32,119,97,115,32,115,112,101,99,105,102,105,101,100,32,105,110,116,111,32,116,119,111,32,112,97,114,116,115,44,32,97,110,100,32,116,104,101,32,115,112,108,105,116,116,105,110,103,32,115,116,111,112,115,32,119,104,101,110,32,101,110,111,117,103,104,32,112,97,114,116,115,32,97,114,101,32,103,105,118,101,110,44,32,119,104,105,99,104,32,105,115,32,119,104,121,32,116,104,101,32,114,101,115,117,108,116,32,100,105,102,102,101,114,115,32,102,114,111,109,32,116,104,97,116,32,111,102,32>>,{code,[],[<<116,114,105,109>>]},<<46>>]},{p,[],[<<77,111,114,101,32,116,104,97,110,32,116,104,114,101,101,32,112,97,114,116,115,32,97,114,101,32,110,111,116,32,112,111,115,115,105,98,108,101,32,119,105,116,104,32,116,104,105,115,32,105,110,100,97,116,97,44,32,115,111>>]},{pre,[],[{code,[],[<<114,101,58,115,112,108,105,116,40,34,69,114,108,97,110,103,34,44,34,91,108,103,93,34,44,91,123,114,101,116,117,114,110,44,108,105,115,116,125,44,123,112,97,114,116,115,44,52,125,93,41,46>>]}]},{p,[],[<<103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,114,101,115,117,108,116,32,97,115,32,116,104,101,32,100,101,102,97,117,108,116,44,32,119,104,105,99,104,32,105,115,32,116,111,32,98,101,32,118,105,101,119,101,100,32,97,115,32,34,97,110,32,105,110,102,105,110,105,116,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,34,46>>]},{p,[],[<<83,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<48>>]},<<32,97,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,103,105,118,101,115,32,116,104,101,32,115,97,109,101,32,101,102,102,101,99,116,32,97,115,32,111,112,116,105,111,110,32>>,{code,[],[<<116,114,105,109>>]},<<46,32,73,102,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,97,114,101,32,99,97,112,116,117,114,101,100,44,32,101,109,112,116,121,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,109,97,116,99,104,101,100,32,97,116,32,116,104,101,32,101,110,100,32,97,114,101,32,97,108,115,111,32,115,116,114,105,112,112,101,100,32,102,114,111,109,32,116,104,101,32,114,101,115,117,108,116,32,105,102,32>>,{code,[],[<<116,114,105,109>>]},<<32,111,114,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<32,105,115,32,115,112,101,99,105,102,105,101,100,46>>]},{p,[],[<<84,104,101,32>>,{code,[],[<<116,114,105,109>>]},<<32,98,101,104,97,118,105,111,114,32,99,111,114,114,101,115,112,111,110,100,115,32,101,120,97,99,116,108,121,32,116,111,32,116,104,101,32,80,101,114,108,32,100,101,102,97,117,108,116,46,32>>,{code,[],[<<123,112,97,114,116,115,44,78,125>>]},<<44,32,119,104,101,114,101,32,78,32,105,115,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,44,32,99,111,114,114,101,115,112,111,110,100,115,32,101,120,97,99,116,108,121,32,116,111,32,116,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,119,105,116,104,32,97,32,112,111,115,105,116,105,118,101,32,110,117,109,101,114,105,99,97,108,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,46,32,84,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32>>,{code,[],[<<115,112,108,105,116,47,51>>]},<<32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,80,101,114,108,32,98,101,104,97,118,105,111,114,32,119,104,101,110,32,97,32,110,101,103,97,116,105,118,101,32,105,110,116,101,103,101,114,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,116,104,101,32,116,104,105,114,100,32,112,97,114,97,109,101,116,101,114,32,102,111,114,32,116,104,101,32,80,101,114,108,32,114,111,117,116,105,110,101,46>>]},{p,[],[<<83,117,109,109,97,114,121,32,111,102,32,111,112,116,105,111,110,115,32,110,111,116,32,112,114,101,118,105,111,117,115,108,121,32,100,101,115,99,114,105,98,101,100,32,102,111,114,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<114,117,110,47,51>>]},<<58>>]},{dl,[],[{dt,[],[{code,[],[<<123,114,101,116,117,114,110,44,82,101,116,117,114,110,84,121,112,101,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,104,111,119,32,116,104,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,111,114,105,103,105,110,97,108,32,115,116,114,105,110,103,32,97,114,101,32,112,114,101,115,101,110,116,101,100,32,105,110,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,46,32,86,97,108,105,100,32,116,121,112,101,115,58>>]},{dl,[],[{dt,[],[{code,[],[<<105,111,100,97,116,97>>]}]},{dd,[],[{p,[],[<<84,104,101,32,118,97,114,105,97,110,116,32,111,102,32>>,{code,[],[<<105,111,100,97,116,97,40,41>>]},<<32,116,104,97,116,32,103,105,118,101,115,32,116,104,101,32,108,101,97,115,116,32,99,111,112,121,105,110,103,32,111,102,32,100,97,116,97,32,119,105,116,104,32,116,104,101,32,99,117,114,114,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,40,111,102,116,101,110,32,97,32,98,105,110,97,114,121,44,32,98,117,116,32,100,111,32,110,111,116,32,100,101,112,101,110,100,32,111,110,32,105,116,41,46>>]}]},{dt,[],[{code,[],[<<98,105,110,97,114,121>>]}]},{dd,[],[{p,[],[<<65,108,108,32,112,97,114,116,115,32,114,101,116,117,114,110,101,100,32,97,115,32,98,105,110,97,114,105,101,115,46>>]}]},{dt,[],[{code,[],[<<108,105,115,116>>]}]},{dd,[],[{p,[],[<<65,108,108,32,112,97,114,116,115,32,114,101,116,117,114,110,101,100,32,97,115,32,108,105,115,116,115,32,111,102,32,99,104,97,114,97,99,116,101,114,115,32,40,34,115,116,114,105,110,103,115,34,41,46>>]}]}]}]},{dt,[],[{code,[],[<<103,114,111,117,112>>]}]},{dd,[],[{p,[],[<<71,114,111,117,112,115,32,116,111,103,101,116,104,101,114,32,116,104,101,32,112,97,114,116,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,119,105,116,104,32,116,104,101,32,112,97,114,116,115,32,111,102,32,116,104,101,32,115,116,114,105,110,103,32,109,97,116,99,104,105,110,103,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,111,102,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]},{p,[],[<<84,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,102,114,111,109,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,105,110,32,116,104,105,115,32,99,97,115,101,32,97,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<32,111,102,32>>,{code,[],[<<108,105,115,116,40,41>>]},<<115,46,32,69,97,99,104,32,115,117,98,108,105,115,116,32,98,101,103,105,110,115,32,119,105,116,104,32,116,104,101,32,115,116,114,105,110,103,32,112,105,99,107,101,100,32,111,117,116,32,111,102,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,44,32,102,111,108,108,111,119,101,100,32,98,121,32,116,104,101,32,112,97,114,116,115,32,109,97,116,99,104,105,110,103,32,101,97,99,104,32,111,102,32,116,104,101,32,115,117,98,101,120,112,114,101,115,115,105,111,110,115,32,105,110,32,111,114,100,101,114,32,111,102,32,111,99,99,117,114,114,101,110,99,101,32,105,110,32,116,104,101,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46>>]}]},{dt,[],[{code,[],[<<123,112,97,114,116,115,44,78,125>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,116,104,101,32,115,117,98,106,101,99,116,32,115,116,114,105,110,103,32,105,115,32,116,111,32,98,101,32,115,112,108,105,116,32,105,110,116,111,46>>]},{p,[],[<<84,104,101,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,105,115,32,116,111,32,98,101,32,97,32,112,111,115,105,116,105,118,101,32,105,110,116,101,103,101,114,32,102,111,114,32,97,32,115,112,101,99,105,102,105,99,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,44,32,97,110,100,32>>,{code,[],[<<105,110,102,105,110,105,116,121>>]},<<32,102,111,114,32,116,104,101,32,109,97,120,105,109,117,109,32,110,117,109,98,101,114,32,111,102,32,112,97,114,116,115,32,112,111,115,115,105,98,108,101,32,40,116,104,101,32,100,101,102,97,117,108,116,41,46,32,83,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<32,103,105,118,101,115,32,97,115,32,109,97,110,121,32,112,97,114,116,115,32,97,115,32,112,111,115,115,105,98,108,101,32,100,105,115,114,101,103,97,114,100,105,110,103,32,101,109,112,116,121,32,112,97,114,116,115,32,97,116,32,116,104,101,32,101,110,100,44,32,116,104,101,32,115,97,109,101,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<116,114,105,109>>]},<<46>>]}]},{dt,[],[{code,[],[<<116,114,105,109>>]}]},{dd,[],[{p,[],[<<83,112,101,99,105,102,105,101,115,32,116,104,97,116,32,101,109,112,116,121,32,112,97,114,116,115,32,97,116,32,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,114,101,115,117,108,116,32,108,105,115,116,32,97,114,101,32,116,111,32,98,101,32,100,105,115,114,101,103,97,114,100,101,100,46,32,84,104,101,32,115,97,109,101,32,97,115,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,112,97,114,116,115,44,48,125>>]},<<46,32,84,104,105,115,32,99,111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,101,32,100,101,102,97,117,108,116,32,98,101,104,97,118,105,111,114,32,111,102,32,116,104,101,32>>,{code,[],[<<115,112,108,105,116>>]},<<32,98,117,105,108,116,45,105,110,32,102,117,110,99,116,105,111,110,32,105,110,32,80,101,114,108,46>>]}]}]}]},#{signature => [{attribute,{168,2},spec,{{split,3},[{type,{168,12},bounded_fun,[{type,{168,12},'fun',[{type,{168,12},product,[{var,{168,13},'Subject'},{var,{168,22},'RE'},{var,{168,26},'Options'}]},{var,{168,38},'SplitList'}]},[{type,{169,7},constraint,[{atom,{169,7},is_subtype},[{var,{169,7},'Subject'},{type,{169,18},union,[{type,{169,18},iodata,[]},{remote_type,{169,29},[{atom,{169,29},unicode},{atom,{169,37},charlist},[]]}]}]]},{type,{170,7},constraint,[{atom,{170,7},is_subtype},[{var,{170,7},'RE'},{type,{170,13},union,[{user_type,{170,13},mp,[]},{type,{170,20},iodata,[]},{remote_type,{170,31},[{atom,{170,31},unicode},{atom,{170,39},charlist},[]]}]}]]},{type,{171,7},constraint,[{atom,{171,7},is_subtype},[{var,{171,7},'Options'},{type,{171,18},list,[{var,{171,20},'Option'}]}]]},{type,{172,7},constraint,[{atom,{172,7},is_subtype},[{var,{172,7},'Option'},{type,{172,17},union,[{atom,{172,17},anchored},{atom,{172,28},notbol},{atom,{172,37},noteol},{atom,{172,46},notempty},{atom,{172,57},notempty_atstart},{type,{173,17},tuple,[{atom,{173,18},offset},{type,{173,26},non_neg_integer,[]}]},{type,{173,47},tuple,[{atom,{173,48},newline},{user_type,{173,57},nl_spec,[]}]},{type,{174,17},tuple,[{atom,{174,18},match_limit},{type,{174,31},non_neg_integer,[]}]},{type,{175,17},tuple,[{atom,{175,18},match_limit_recursion},{type,{175,41},non_neg_integer,[]}]},{atom,{176,17},bsr_anycrlf},{atom,{176,31},bsr_unicode},{type,{176,45},tuple,[{atom,{176,46},return},{var,{176,54},'ReturnType'}]},{type,{177,17},tuple,[{atom,{177,18},parts},{var,{177,25},'NumParts'}]},{atom,{177,37},group},{atom,{177,45},trim},{var,{177,52},'CompileOpt'}]}]]},{type,{178,7},constraint,[{atom,{178,7},is_subtype},[{var,{178,7},'NumParts'},{type,{178,19},union,[{type,{178,19},non_neg_integer,[]},{atom,{178,39},infinity}]}]]},{type,{179,7},constraint,[{atom,{179,7},is_subtype},[{var,{179,7},'ReturnType'},{type,{179,21},union,[{atom,{179,21},iodata},{atom,{179,30},list},{atom,{179,37},binary}]}]]},{type,{180,7},constraint,[{atom,{180,7},is_subtype},[{var,{180,7},'CompileOpt'},{user_type,{180,21},compile_option,[]}]]},{type,{181,7},constraint,[{atom,{181,7},is_subtype},[{var,{181,7},'SplitList'},{type,{181,20},union,[{type,{181,20},list,[{var,{181,21},'RetData'}]},{type,{181,32},list,[{var,{181,33},'GroupedRetData'}]}]}]]},{type,{182,7},constraint,[{atom,{182,7},is_subtype},[{var,{182,7},'GroupedRetData'},{type,{182,25},list,[{var,{182,26},'RetData'}]}]]},{type,{183,7},constraint,[{atom,{183,7},is_subtype},[{var,{183,7},'RetData'},{type,{183,18},union,[{type,{183,18},iodata,[]},{remote_type,{183,29},[{atom,{183,29},unicode},{atom,{183,37},charlist},[]]},{type,{183,50},binary,[]},{type,{183,61},list,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,114,101,46,120,109,108,35,76,49,48,51,53>>}},{{type,mp,0},[{file,[114,101,46,101,114,108]},{location,23}],[<<45,116,121,112,101,32,109,112,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<79,112,97,113,117,101,32,100,97,116,97,32,116,121,112,101,32,99,111,110,116,97,105,110,105,110,103,32,97,32,99,111,109,112,105,108,101,100,32,114,101,103,117,108,97,114,32,101,120,112,114,101,115,115,105,111,110,46,32>>,{code,[],[<<109,112,40,41>>]},<<32,105,115,32,103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,32,97,32,116,117,112,108,101,40,41,32,104,97,118,105,110,103,32,116,104,101,32,97,116,111,109,32>>,{code,[],[<<114,101,95,112,97,116,116,101,114,110>>]},<<32,97,115,32,105,116,115,32,102,105,114,115,116,32,101,108,101,109,101,110,116,44,32,116,111,32,97,108,108,111,119,32,102,111,114,32,109,97,116,99,104,105,110,103,32,105,110,32,103,117,97,114,100,115,46,32,84,104,101,32,97,114,105,116,121,32,111,102,32,116,104,101,32,116,117,112,108,101,32,111,114,32,116,104,101,32,99,111,110,116,101,110,116,32,111,102,32,116,104,101,32,111,116,104,101,114,32,102,105,101,108,100,115,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,69,114,108,97,110,103,47,79,84,80,32,114,101,108,101,97,115,101,115,46>>]}]},#{signature => [{attribute,{23,2},type,{mp,{type,{23,15},tuple,[{atom,{23,16},re_pattern},{var,{23,28},'_'},{var,{23,31},'_'},{var,{23,34},'_'},{var,{23,37},'_'}]},[]}}]}},{{type,nl_spec,0},[{file,[114,101,46,101,114,108]},{location,25}],[<<45,116,121,112,101,32,110,108,95,115,112,101,99,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{25,2},type,{nl_spec,{type,{25,20},union,[{atom,{25,20},cr},{atom,{25,25},crlf},{atom,{25,32},lf},{atom,{25,37},anycrlf},{atom,{25,47},any}]},[]}}]}},{{type,compile_option,0},[{file,[114,101,46,101,114,108]},{location,27}],[<<45,116,121,112,101,32,99,111,109,112,105,108,101,95,111,112,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{27,2},type,{compile_option,{type,{27,27},union,[{atom,{27,27},unicode},{atom,{27,37},anchored},{atom,{27,48},caseless},{atom,{27,59},dollar_endonly},{atom,{28,27},dotall},{atom,{28,36},extended},{atom,{28,47},firstline},{atom,{28,59},multiline},{atom,{29,27},no_auto_capture},{atom,{29,45},dupnames},{atom,{29,56},ungreedy},{type,{30,27},tuple,[{atom,{30,28},newline},{user_type,{30,37},nl_spec,[]}]},{atom,{31,27},bsr_anycrlf},{atom,{31,41},bsr_unicode},{atom,{32,27},no_start_optimize},{atom,{32,47},ucp},{atom,{32,53},never_utf}]},[]}}]}},{{type,replace_fun,0},[{file,[114,101,46,101,114,108]},{location,34}],[<<45,116,121,112,101,32,114,101,112,108,97,99,101,95,102,117,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{34,2},type,{replace_fun,{type,{34,28},'fun',[{type,{34,28},product,[{type,{34,29},binary,[]},{type,{34,39},list,[{type,{34,40},binary,[]}]}]},{type,{34,54},union,[{type,{34,54},iodata,[]},{remote_type,{34,65},[{atom,{34,65},unicode},{atom,{34,73},charlist},[]]}]}]},[]}}]}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/shell_docs_SUITE_data/shell_docs_SUITE.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/shell_docs_SUITE.docs_v1 new file mode 100644 index 000000000000..4c3f53de9d4a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/shell_docs_SUITE.docs_v1 @@ -0,0 +1 @@ +{docs_v1,0,erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,none,#{generated => true,otp_doc_vsn => {1,0,0}},[{{function,suite,0},{32,1},[<<115,117,105,116,101,47,48>>],none,#{}},{{function,all,0},{35,1},[<<97,108,108,47,48>>],none,#{}},{{function,groups,0},{38,1},[<<103,114,111,117,112,115,47,48>>],none,#{}},{{function,init_per_suite,1},{46,1},[<<105,110,105,116,95,112,101,114,95,115,117,105,116,101,47,49>>],none,#{signature => [{attribute,{43,2},spec,{{init_per_suite,1},[{type,{43,21},bounded_fun,[{type,{43,21},'fun',[{type,{43,21},product,[{var,{43,22},'Config1'}]},{var,{43,34},'Config2'}]},[{type,{44,7},constraint,[{atom,{44,7},is_subtype},[{var,{44,7},'Config1'},{type,{44,18},list,[{type,{44,23},tuple,[{type,{44,24},atom,[]},{type,{44,31},term,[]}]}]}]]},{type,{45,7},constraint,[{atom,{45,7},is_subtype},[{var,{45,7},'Config2'},{type,{45,18},list,[{type,{45,23},tuple,[{type,{45,24},atom,[]},{type,{45,31},term,[]}]}]}]]}]]}]}}]}},{{function,end_per_suite,1},{50,1},[<<101,110,100,95,112,101,114,95,115,117,105,116,101,47,49>>],none,#{}},{{function,init_per_group,2},{53,1},[<<105,110,105,116,95,112,101,114,95,103,114,111,117,112,47,50>>],none,#{}},{{function,end_per_group,2},{58,1},[<<101,110,100,95,112,101,114,95,103,114,111,117,112,47,50>>],none,#{}},{{function,render,1},{76,1},[<<114,101,110,100,101,114,47,49>>],none,#{}},{{function,update_render,0},{101,1},[<<117,112,100,97,116,101,95,114,101,110,100,101,114,47,48>>],none,#{}},{{function,update_render,1},{105,1},[<<117,112,100,97,116,101,95,114,101,110,100,101,114,47,49>>],none,#{}},{{function,render_smoke,1},{122,1},[<<114,101,110,100,101,114,95,115,109,111,107,101,47,49>>],none,#{}},{{function,render_prop,1},{175,1},[<<114,101,110,100,101,114,95,112,114,111,112,47,49>>],none,#{}},{{function,links,1},{180,1},[<<108,105,110,107,115,47,49>>],none,#{}},{{function,check_links,2},{199,1},[<<99,104,101,99,107,95,108,105,110,107,115,47,50>>],none,#{}},{{function,normalize,1},{233,1},[<<110,111,114,109,97,108,105,122,101,47,49>>],none,#{}},{{function,b2a,1},{245,1},[<<98,50,97,47,49>>],none,#{}},{{function,render_non_native,1},{252,1},[<<114,101,110,100,101,114,95,110,111,110,95,110,97,116,105,118,101,47,49>>],none,#{}},{{function,render_all,1},{270,1},[<<114,101,110,100,101,114,95,97,108,108,47,49>>],none,#{}},{{function,render_module,2},{289,1},[<<114,101,110,100,101,114,95,109,111,100,117,108,101,47,50>>],none,#{}},{{function,sanitize,1},{324,1},[<<115,97,110,105,116,105,122,101,47,49>>],none,#{}},{{function,docsmap,1},{331,1},[<<100,111,99,115,109,97,112,47,49>>],none,#{}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/shell_docs_SUITE_data/sofs.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/sofs.docs_v1 index e4a4c4cfb77d..28a344709025 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/sofs.docs_v1 +++ b/lib/stdlib/test/shell_docs_SUITE_data/sofs.docs_v1 @@ -1 +1 @@ -{docs_v1,[{file,[115,111,102,115,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,112,114,111,118,105,100,101,115,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,102,105,110,105,116,101,32,115,101,116,115,32,97,110,100,32,114,101,108,97,116,105,111,110,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,115,101,116,115,46,32,73,110,116,117,105,116,105,118,101,108,121,44,32,97,32,115,101,116,32,105,115,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,101,108,101,109,101,110,116,115,59,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32,116,104,101,32,115,101,116,44,32,97,110,100,32,116,104,101,32,115,101,116,32,99,111,110,116,97,105,110,115,32,101,118,101,114,121,32,101,108,101,109,101,110,116,46>>]},{p,[],[<<71,105,118,101,110,32,97,32,115,101,116,32,65,32,97,110,100,32,97,32,115,101,110,116,101,110,99,101,32,83,40,120,41,44,32,119,104,101,114,101,32,120,32,105,115,32,97,32,102,114,101,101,32,118,97,114,105,97,98,108,101,44,32,97,32,110,101,119,32,115,101,116,32,66,32,119,104,111,115,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,101,120,97,99,116,108,121,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,102,111,114,32,119,104,105,99,104,32,83,40,120,41,32,104,111,108,100,115,32,99,97,110,32,98,101,32,102,111,114,109,101,100,44,32,116,104,105,115,32,105,115,32,100,101,110,111,116,101,100,32,66,194,160,61,32,123,120,194,160,105,110,194,160,65,194,160,58,32,83,40,120,41,125,46,32,83,101,110,116,101,110,99,101,115,32,97,114,101,32,101,120,112,114,101,115,115,101,100,32,117,115,105,110,103,32,116,104,101,32,108,111,103,105,99,97,108,32,111,112,101,114,97,116,111,114,115,32,34,102,111,114,32,115,111,109,101,34,32,40,111,114,32,34,116,104,101,114,101,32,101,120,105,115,116,115,34,41,44,32,34,102,111,114,32,97,108,108,34,44,32,34,97,110,100,34,44,32,34,111,114,34,44,32,34,110,111,116,34,46,32,73,102,32,116,104,101,32,101,120,105,115,116,101,110,99,101,32,111,102,32,97,32,115,101,116,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,101,108,101,109,101,110,116,115,32,105,115,32,107,110,111,119,110,32,40,97,115,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,99,97,115,101,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,41,44,32,116,104,105,115,32,105,115,32,100,101,110,111,116,101,100,32,66,194,160,61,32,123,120,194,160,58,32,83,40,120,41,125,46>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32>>,{em,[],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,97,44,32,98,44,32,97,110,100,32,99,32,105,115,32,100,101,110,111,116,101,100,32,123,97,44,194,160,98,44,194,160,99,125,46,32,84,104,105,115,32,110,111,116,97,116,105,111,110,32,105,115,32,110,111,116,32,116,111,32,98,101,32,99,111,110,102,117,115,101,100,32,119,105,116,104,32,116,117,112,108,101,115,46>>]},{p,[],[<<84,104,101,32>>,{em,[],[<<111,114,100,101,114,101,100,32,112,97,105,114>>]},<<32,111,102,32,97,32,97,110,100,32,98,44,32,119,105,116,104,32,102,105,114,115,116,32>>,{em,[],[<<99,111,111,114,100,105,110,97,116,101>>]},<<32,97,32,97,110,100,32,115,101,99,111,110,100,32,99,111,111,114,100,105,110,97,116,101,32,98,44,32,105,115,32,100,101,110,111,116,101,100,32,40,97,44,194,160,98,41,46,32,65,110,32,111,114,100,101,114,101,100,32,112,97,105,114,32,105,115,32,97,110,32>>,{em,[],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<32,111,102,32,116,119,111,32,101,108,101,109,101,110,116,115,46,32,73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,100,101,114,101,100,32,115,101,116,115,32,99,97,110,32,99,111,110,116,97,105,110,32,111,110,101,44,32,116,119,111,44,32,111,114,32,109,111,114,101,32,101,108,101,109,101,110,116,115,44,32,97,110,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,101,110,99,108,111,115,101,32,116,104,101,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[<<85,110,111,114,100,101,114,101,100,32,115,101,116,115,32,97,110,100,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,111,114,116,104,111,103,111,110,97,108,44,32,97,103,97,105,110,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,59,32,116,104,101,114,101,32,105,115,32,110,111,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,101,113,117,97,108,32,116,111,32,97,110,121,32,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},{li,[],[{p,[],[<<84,104,101,32>>,{em,[],[<<101,109,112,116,121,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,115,32,110,111,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[<<83,101,116,32,65,32,105,115,32>>,{a,[{id,<<101,113,117,97,108>>}],[]},{em,[],[<<101,113,117,97,108>>]},<<32,116,111,32,115,101,116,32,66,32,105,102,32,116,104,101,121,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,101,108,101,109,101,110,116,115,44,32,119,104,105,99,104,32,105,115,32,100,101,110,111,116,101,100,32,65,194,160,61,194,160,66,46,32,84,119,111,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,101,113,117,97,108,32,105,102,32,116,104,101,121,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,97,110,100,32,104,97,118,101,32,101,113,117,97,108,32,101,108,101,109,101,110,116,115,32,97,116,32,101,97,99,104,32,99,111,111,114,100,105,110,97,116,101,46>>]},{p,[],[<<83,101,116,32,66,32,105,115,32,97,32>>,{a,[{id,<<115,117,98,115,101,116>>}],[]},{em,[],[<<115,117,98,115,101,116>>]},<<32,111,102,32,115,101,116,32,65,32,105,102,32,65,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,66,32,99,111,110,116,97,105,110,115,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<117,110,105,111,110>>}],[]},{em,[],[<<117,110,105,111,110>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,97,110,100,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,66,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<105,110,116,101,114,115,101,99,116,105,111,110>>}],[]},{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,66,46>>]},{p,[],[<<84,119,111,32,115,101,116,115,32,97,114,101,32>>,{a,[{id,<<100,105,115,106,111,105,110,116>>}],[]},{em,[],[<<100,105,115,106,111,105,110,116>>]},<<32,105,102,32,116,104,101,105,114,32,105,110,116,101,114,115,101,99,116,105,111,110,32,105,115,32,116,104,101,32,101,109,112,116,121,32,115,101,116,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<100,105,102,102,101,114,101,110,99,101>>}],[]},{em,[],[<<100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32,66,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<115,121,109,109,101,116,114,105,99,95,100,105,102,102,101,114,101,110,99,101>>}],[]},{em,[],[<<115,121,109,109,101,116,114,105,99,32,100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,116,104,111,115,101,32,101,108,101,109,101,110,116,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,101,105,116,104,101,114,32,111,102,32,116,104,101,32,116,119,111,32,115,101,116,115,44,32,98,117,116,32,110,111,116,32,98,111,116,104,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<117,110,105,111,110,95,110>>}],[]},{em,[],[<<117,110,105,111,110>>]},<<32,111,102,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,115,101,116,115,32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,116,104,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,97,116,32,108,101,97,115,116,32,111,110,101,32,115,101,116,32,111,102,32,116,104,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<105,110,116,101,114,115,101,99,116,105,111,110,95,110>>}],[]},{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,97,32,110,111,110,45,101,109,112,116,121,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,115,101,116,115,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,101,118,101,114,121,32,115,101,116,32,111,102,32,116,104,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]},{li,[],[{p,[],[<<84,104,101,32>>,{a,[{id,<<67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,88,32,97,110,100,32,89,44,32,100,101,110,111,116,101,100,32,88,194,160,195,151,194,160,89,44,32,105,115,32,116,104,101,32,115,101,116,32,123,97,194,160,58,32,97,194,160,61,32,40,120,44,194,160,121,41,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,88,32,97,110,100,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,89,125,46>>]},{p,[],[<<65,32>>,{a,[{id,<<114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<114,101,108,97,116,105,111,110>>]},<<32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,88,194,160,195,151,194,160,89,46,32,76,101,116,32,82,32,98,101,32,97,32,114,101,108,97,116,105,111,110,46,32,84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,120,44,194,160,121,41,32,98,101,108,111,110,103,115,32,116,111,32,82,32,105,115,32,119,114,105,116,116,101,110,32,97,115,32,120,194,160,82,194,160,121,46,32,65,115,32,114,101,108,97,116,105,111,110,115,32,97,114,101,32,115,101,116,115,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,115,32,111,102,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,40,115,117,98,115,101,116,44,32,117,110,105,111,110,44,32,97,110,100,32,115,111,32,111,110,41,32,97,112,112,108,121,32,116,111,32,114,101,108,97,116,105,111,110,115,32,97,115,32,119,101,108,108,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<100,111,109,97,105,110>>}],[]},{em,[],[<<100,111,109,97,105,110>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,120,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,89,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<114,97,110,103,101>>}],[]},{em,[],[<<114,97,110,103,101>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,121,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,88,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<99,111,110,118,101,114,115,101>>}],[]},{em,[],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,97,194,160,58,32,97,194,160,61,32,40,121,44,194,160,120,41,32,102,111,114,32,115,111,109,101,32,40,120,44,194,160,121,41,194,160,105,110,194,160,82,125,46>>]},{p,[],[<<73,102,32,65,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,88,44,32,116,104,101,32>>,{a,[{id,<<105,109,97,103,101>>}],[]},{em,[],[<<105,109,97,103,101>>]},<<32,111,102,32,65,32,117,110,100,101,114,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,121,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,65,125,46,32,73,102,32,66,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,89,44,32,116,104,101,32>>,{a,[{id,<<105,110,118,101,114,115,101,95,105,109,97,103,101>>}],[]},{em,[],[<<105,110,118,101,114,115,101,32,105,109,97,103,101>>]},<<32,111,102,32,66,32,105,115,32,116,104,101,32,115,101,116,32,123,120,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,66,125,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,88,32,116,111,32,89,44,32,97,110,100,32,83,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,89,32,116,111,32,90,44,32,116,104,101,32>>,{a,[{id,<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,82,32,97,110,100,32,83,32,105,115,32,116,104,101,32,114,101,108,97,116,105,111,110,32,84,32,102,114,111,109,32,88,32,116,111,32,90,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,84,194,160,122,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,121,32,105,110,32,89,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,194,160,121,32,97,110,100,32,121,194,160,83,194,160,122,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<114,101,115,116,114,105,99,116,105,111,110>>}],[]},{em,[],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32,82,32,116,111,32,65,32,105,115,32,116,104,101,32,115,101,116,32,83,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,83,194,160,121,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,120,32,105,110,32,65,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,194,160,121,46>>]},{p,[],[<<73,102,32,83,32,105,115,32,97,32,114,101,115,116,114,105,99,116,105,111,110,32,111,102,32,82,32,116,111,32,65,44,32,116,104,101,110,32,82,32,105,115,32,97,110,32>>,{a,[{id,<<101,120,116,101,110,115,105,111,110>>}],[]},{em,[],[<<101,120,116,101,110,115,105,111,110>>]},<<32,111,102,32,83,32,116,111,32,88,46>>]},{p,[],[<<73,102,32,88,194,160,61,194,160,89,44,32,116,104,101,110,32,82,32,105,115,32,99,97,108,108,101,100,32,97,32,114,101,108,97,116,105,111,110,32>>,{em,[],[<<105,110>>]},<<32,88,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<102,105,101,108,100>>}],[]},{em,[],[<<102,105,101,108,100>>]},<<32,111,102,32,97,32,114,101,108,97,116,105,111,110,32,82,32,105,110,32,88,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,82,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,111,102,32,82,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,105,102,32,83,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,83,194,160,121,32,105,102,32,120,194,160,82,194,160,121,32,97,110,100,32,110,111,116,32,120,194,160,61,194,160,121,44,32,116,104,101,110,32,83,32,105,115,32,116,104,101,32>>,{a,[{id,<<115,116,114,105,99,116,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<115,116,114,105,99,116>>]},<<32,114,101,108,97,116,105,111,110,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,82,46,32,67,111,110,118,101,114,115,101,108,121,44,32,105,102,32,83,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,105,102,32,82,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,82,194,160,121,32,105,102,32,120,194,160,83,194,160,121,32,111,114,32,120,194,160,61,194,160,121,44,32,116,104,101,110,32,82,32,105,115,32,116,104,101,32>>,{a,[{id,<<119,101,97,107,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<119,101,97,107>>]},<<32,114,101,108,97,116,105,111,110,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,83,46>>]},{p,[],[<<65,32,114,101,108,97,116,105,111,110,32,82,32,105,110,32,88,32,105,115,32>>,{em,[],[<<114,101,102,108,101,120,105,118,101>>]},<<32,105,102,32,120,194,160,82,194,160,120,32,102,111,114,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,120,32,111,102,32,88,44,32,105,116,32,105,115,32>>,{em,[],[<<115,121,109,109,101,116,114,105,99>>]},<<32,105,102,32,120,194,160,82,194,160,121,32,105,109,112,108,105,101,115,32,116,104,97,116,32,121,194,160,82,194,160,120,44,32,97,110,100,32,105,116,32,105,115,32>>,{em,[],[<<116,114,97,110,115,105,116,105,118,101>>]},<<32,105,102,32,120,194,160,82,194,160,121,32,97,110,100,32,121,194,160,82,194,160,122,32,105,109,112,108,121,32,116,104,97,116,32,120,194,160,82,194,160,122,46>>]}]},{li,[],[{p,[],[<<65,32>>,{a,[{id,<<102,117,110,99,116,105,111,110>>}],[]},{em,[],[<<102,117,110,99,116,105,111,110>>]},<<32,70,32,105,115,32,97,32,114,101,108,97,116,105,111,110,44,32,97,32,115,117,98,115,101,116,32,111,102,32,88,194,160,195,151,194,160,89,44,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,32,105,115,32,101,113,117,97,108,32,116,111,32,88,32,97,110,100,32,115,117,99,104,32,116,104,97,116,32,102,111,114,32,101,118,101,114,121,32,120,32,105,110,32,88,32,116,104,101,114,101,32,105,115,32,97,32,117,110,105,113,117,101,32,101,108,101,109,101,110,116,32,121,32,105,110,32,89,32,119,105,116,104,32,40,120,44,194,160,121,41,32,105,110,32,70,46,32,84,104,101,32,108,97,116,116,101,114,32,99,111,110,100,105,116,105,111,110,32,99,97,110,32,98,101,32,102,111,114,109,117,108,97,116,101,100,32,97,115,32,102,111,108,108,111,119,115,58,32,105,102,32,120,194,160,70,194,160,121,32,97,110,100,32,120,194,160,70,194,160,122,44,32,116,104,101,110,32,121,194,160,61,194,160,122,46,32,73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,105,116,32,105,115,32,110,111,116,32,114,101,113,117,105,114,101,100,32,116,104,97,116,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,32,105,115,32,101,113,117,97,108,32,116,111,32,88,32,102,111,114,32,97,32,114,101,108,97,116,105,111,110,32,116,111,32,98,101,32,99,111,110,115,105,100,101,114,101,100,32,97,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<73,110,115,116,101,97,100,32,111,102,32,119,114,105,116,105,110,103,32,40,120,44,194,160,121,41,194,160,105,110,194,160,70,32,111,114,32,120,194,160,70,194,160,121,44,32,119,101,32,119,114,105,116,101,32,70,40,120,41,194,160,61,194,160,121,32,119,104,101,110,32,70,32,105,115,32,97,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,115,97,121,32,116,104,97,116,32,70,32,109,97,112,115,32,120,32,111,110,116,111,32,121,44,32,111,114,32,116,104,97,116,32,116,104,101,32,118,97,108,117,101,32,111,102,32,70,32,97,116,32,120,32,105,115,32,121,46>>]},{p,[],[<<65,115,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,114,101,108,97,116,105,111,110,115,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,115,32,111,102,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,40,100,111,109,97,105,110,44,32,114,97,110,103,101,44,32,97,110,100,32,115,111,32,111,110,41,32,97,112,112,108,121,32,116,111,32,102,117,110,99,116,105,111,110,115,32,97,115,32,119,101,108,108,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,118,101,114,115,101,32,111,102,32,97,32,102,117,110,99,116,105,111,110,32,70,32,105,115,32,97,32,102,117,110,99,116,105,111,110,32,70,39,44,32,116,104,101,110,32,70,39,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{a,[{id,<<105,110,118,101,114,115,101>>}],[]},{em,[],[<<105,110,118,101,114,115,101>>]},<<32,111,102,32,70,46>>]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,116,119,111,32,102,117,110,99,116,105,111,110,115,32,70,49,32,97,110,100,32,70,50,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{a,[{id,<<99,111,109,112,111,115,105,116,101>>}],[]},{em,[],[<<99,111,109,112,111,115,105,116,101>>]},<<32,111,102,32,70,49,32,97,110,100,32,70,50,32,105,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,70,49,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,50,46>>]}]},{li,[],[{p,[],[<<83,111,109,101,116,105,109,101,115,44,32,119,104,101,110,32,116,104,101,32,114,97,110,103,101,32,111,102,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,109,111,114,101,32,105,109,112,111,114,116,97,110,116,32,116,104,97,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,116,115,101,108,102,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,97,32>>,{em,[],[<<102,97,109,105,108,121>>]},<<46>>]},{p,[],[<<84,104,101,32,100,111,109,97,105,110,32,111,102,32,97,32,102,97,109,105,108,121,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<105,110,100,101,120,32,115,101,116>>]},<<44,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<105,110,100,101,120,101,100,32,115,101,116>>]},<<46>>]},{p,[],[<<73,102,32,120,32,105,115,32,97,32,102,97,109,105,108,121,32,102,114,111,109,32,73,32,116,111,32,88,44,32,116,104,101,110,32,120,91,105,93,32,100,101,110,111,116,101,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,116,32,105,110,100,101,120,32,105,46,32,84,104,101,32,110,111,116,97,116,105,111,110,32,34,97,32,102,97,109,105,108,121,32,105,110,32,88,34,32,105,115,32,117,115,101,100,32,102,111,114,32,115,117,99,104,32,97,32,102,97,109,105,108,121,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,105,110,100,101,120,101,100,32,115,101,116,32,105,115,32,97,32,115,101,116,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,97,32,115,101,116,32,88,44,32,119,101,32,99,97,108,108,32,120,32,97,32>>,{a,[{id,<<102,97,109,105,108,121>>}],[]},{em,[],[<<102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115>>]},<<32,111,102,32,88,46>>]},{p,[],[<<73,102,32,120,32,105,115,32,97,32,102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,88,44,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,120,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<117,110,105,111,110,32,111,102,32,116,104,101,32,102,97,109,105,108,121>>]},<<32,120,46>>]},{p,[],[<<73,102,32,120,32,105,115,32,110,111,110,45,101,109,112,116,121,32,40,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,110,111,110,45,101,109,112,116,121,41,44,32,116,104,101,32>>,{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32,102,97,109,105,108,121>>]},<<32,120,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,120,46>>]},{p,[],[<<73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,116,104,101,32,111,110,108,121,32,102,97,109,105,108,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,97,114,101,32,102,97,109,105,108,105,101,115,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,115,111,109,101,32,115,101,116,32,88,59,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,116,104,101,32,119,111,114,100,32,34,102,97,109,105,108,121,34,32,105,115,32,117,115,101,100,32,102,111,114,32,115,117,99,104,32,102,97,109,105,108,105,101,115,32,111,102,32,115,117,98,115,101,116,115,46>>]}]},{li,[],[{p,[],[<<65,32>>,{a,[{id,<<112,97,114,116,105,116,105,111,110>>}],[]},{em,[],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,97,32,115,101,116,32,88,32,105,115,32,97,32,99,111,108,108,101,99,116,105,111,110,32,83,32,111,102,32,110,111,110,45,101,109,112,116,121,32,115,117,98,115,101,116,115,32,111,102,32,88,32,119,104,111,115,101,32,117,110,105,111,110,32,105,115,32,88,32,97,110,100,32,119,104,111,115,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,112,97,105,114,119,105,115,101,32,100,105,115,106,111,105,110,116,46>>]},{p,[],[<<65,32,114,101,108,97,116,105,111,110,32,105,110,32,97,32,115,101,116,32,105,115,32,97,110,32>>,{em,[],[<<101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110>>]},<<32,105,102,32,105,116,32,105,115,32,114,101,102,108,101,120,105,118,101,44,32,115,121,109,109,101,116,114,105,99,44,32,97,110,100,32,116,114,97,110,115,105,116,105,118,101,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,120,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,88,44,32,116,104,101,32>>,{a,[{id,<<101,113,117,105,118,97,108,101,110,99,101,95,99,108,97,115,115>>}],[]},{em,[],[<<101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115>>]},<<32,111,102,32,120,32,119,105,116,104,32,114,101,115,112,101,99,116,32,116,111,32,82,32,105,115,32,116,104,101,32,115,101,116,32,111,102,32,97,108,108,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,121,32,111,102,32,88,32,102,111,114,32,119,104,105,99,104,32,120,194,160,82,194,160,121,32,104,111,108,100,115,46,32,84,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,101,115,32,99,111,110,115,116,105,116,117,116,101,32,97,32,112,97,114,116,105,116,105,111,110,105,110,103,32,111,102,32,88,46,32,67,111,110,118,101,114,115,101,108,121,44,32,105,102,32,67,32,105,115,32,97,32,112,97,114,116,105,116,105,111,110,32,111,102,32,88,44,32,116,104,101,32,114,101,108,97,116,105,111,110,32,116,104,97,116,32,104,111,108,100,115,32,102,111,114,32,97,110,121,32,116,119,111,32,101,108,101,109,101,110,116,115,32,111,102,32,88,32,105,102,32,116,104,101,121,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32,115,97,109,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,44,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,100,117,99,101,100,32,98,121,32,116,104,101,32,112,97,114,116,105,116,105,111,110,32,67,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,116,104,101,32>>,{a,[{id,<<99,97,110,111,110,105,99,97,108,95,109,97,112>>}],[]},{em,[],[<<99,97,110,111,110,105,99,97,108,32,109,97,112>>]},<<32,105,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,109,97,112,115,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,111,102,32,88,32,111,110,116,111,32,105,116,115,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,46>>]}]},{li,[],[{p,[],[{a,[{id,<<98,105,110,97,114,121,95,114,101,108,97,116,105,111,110>>}],[]},<<82,101,108,97,116,105,111,110,115,32,97,115,32,100,101,102,105,110,101,100,32,97,98,111,118,101,32,40,97,115,32,115,101,116,115,32,111,102,32,111,114,100,101,114,101,100,32,112,97,105,114,115,41,32,97,114,101,32,102,114,111,109,32,110,111,119,32,111,110,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32>>,{em,[],[<<98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115>>]},<<46>>]},{p,[],[<<87,101,32,99,97,108,108,32,97,32,115,101,116,32,111,102,32,111,114,100,101,114,101,100,32,115,101,116,115,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,97,110,32>>,{a,[{id,<<110,95,97,114,121,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<40,110,45,97,114,121,41,32,114,101,108,97,116,105,111,110>>]},<<44,32,97,110,100,32,115,97,121,32,116,104,97,116,32,116,104,101,32,114,101,108,97,116,105,111,110,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32>>,{a,[{id,<<67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>}],[]},<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116,32,88,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,88,91,110,93,44,32,119,104,101,114,101,32,120,91,105,93,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,88,91,105,93,44,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<112,114,111,106,101,99,116,105,111,110>>}],[]},{em,[],[<<112,114,111,106,101,99,116,105,111,110>>]},<<32,111,102,32,97,110,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,111,110,116,111,32,99,111,111,114,100,105,110,97,116,101,32,105,32,105,115,32,116,104,101,32,115,101,116,32,123,120,91,105,93,194,160,58,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,105,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,105,110,32,82,32,102,111,114,32,115,111,109,101,32,120,91,106,93,194,160,105,110,194,160,88,91,106,93,44,32,49,194,160,60,61,194,160,106,194,160,60,61,194,160,110,32,97,110,100,32,110,111,116,32,105,194,160,61,194,160,106,125,46,32,84,104,101,32,112,114,111,106,101,99,116,105,111,110,115,32,111,102,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,111,110,116,111,32,116,104,101,32,102,105,114,115,116,32,97,110,100,32,115,101,99,111,110,100,32,99,111,111,114,100,105,110,97,116,101,115,32,97,114,101,32,116,104,101,32,100,111,109,97,105,110,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,111,102,32,82,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,99,97,110,32,98,101,32,103,101,110,101,114,97,108,105,122,101,100,32,116,111,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,115,32,102,111,108,108,111,119,115,46,32,76,101,116,32,84,82,32,98,101,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,102,114,111,109,32,88,32,116,111,32,89,91,105,93,32,97,110,100,32,83,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,40,89,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,89,91,110,93,41,32,116,111,32,90,46,32,84,104,101,32>>,{a,[{id,<<116,117,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,84,82,32,97,110,100,32,83,32,105,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,84,32,102,114,111,109,32,88,32,116,111,32,90,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,84,194,160,122,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,121,91,105,93,32,105,110,32,89,91,105,93,32,102,111,114,32,101,97,99,104,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,91,105,93,194,160,121,91,105,93,32,97,110,100,32,40,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,110,93,41,194,160,83,194,160,122,46,32,78,111,119,32,108,101,116,32,84,82,32,98,101,32,97,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,102,114,111,109,32,88,91,105,93,32,116,111,32,89,91,105,93,32,97,110,100,32,83,32,97,32,115,117,98,115,101,116,32,111,102,32,88,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,88,91,110,93,46,32,84,104,101,32>>,{a,[{id,<<109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<109,117,108,116,105,112,108,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,84,82,32,97,110,100,32,83,32,105,115,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,116,104,101,32,115,101,116,32,123,122,194,160,58,32,122,194,160,61,32,40,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,44,32,40,121,91,49,93,44,46,46,46,44,121,91,110,93,41,41,32,102,111,114,32,115,111,109,101,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,194,160,105,110,194,160,83,32,97,110,100,32,102,111,114,32,115,111,109,101,32,40,120,91,105,93,44,194,160,121,91,105,93,41,32,105,110,32,82,91,105,93,44,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<110,97,116,117,114,97,108,95,106,111,105,110>>}],[]},{em,[],[<<110,97,116,117,114,97,108,32,106,111,105,110>>]},<<32,111,102,32,97,110,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,97,110,100,32,97,110,32,109,45,97,114,121,32,114,101,108,97,116,105,111,110,32,83,32,111,110,32,99,111,111,114,100,105,110,97,116,101,32,105,32,97,110,100,32,106,32,105,115,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,116,104,101,32,115,101,116,32,123,122,194,160,58,32,122,194,160,61,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,44,194,160,32,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,106,45,49,93,44,194,160,121,91,106,43,49,93,44,194,160,46,46,46,44,194,160,121,91,109,93,41,32,102,111,114,32,115,111,109,101,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,194,160,105,110,194,160,82,32,97,110,100,32,102,111,114,32,115,111,109,101,32,40,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,109,93,41,194,160,105,110,194,160,83,32,115,117,99,104,32,116,104,97,116,32,120,91,105,93,194,160,61,194,160,121,91,106,93,125,46>>]}]},{li,[],[{p,[],[{a,[{id,<<115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>}],[]},<<84,104,101,32,115,101,116,115,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32,116,104,105,115,32,109,111,100,117,108,101,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,32,83,101,116,115,44,32,119,104,105,99,104,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,115,117,99,104,32,116,104,97,116,58>>]},{ul,[],[{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,97,116,111,109,32,84,44,32,101,120,99,101,112,116,32,39,95,39,44,32,97,110,100,32,102,111,114,32,101,118,101,114,121,32,116,101,114,109,32,88,44,32,40,84,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<97,116,111,109,105,99,32,115,101,116,115>>]},<<41,46>>]}]},{li,[],[{p,[],[<<40,91,39,95,39,93,44,194,160,91,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40,116,104,101,32>>,{em,[],[<<117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116>>]},<<41,46>>]}]},{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,116,117,112,108,101,32,84,194,160,61,32,123,84,91,49,93,44,194,160,46,46,46,44,194,160,84,91,110,93,125,32,97,110,100,32,102,111,114,32,101,118,101,114,121,32,116,117,112,108,101,32,88,194,160,61,32,123,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,125,44,32,105,102,32,40,84,91,105,93,44,194,160,88,91,105,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,102,111,114,32,101,118,101,114,121,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,44,32,116,104,101,110,32,40,84,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<111,114,100,101,114,101,100,32,115,101,116,115>>]},<<41,46>>]}]},{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,116,101,114,109,32,84,44,32,105,102,32,88,32,105,115,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,111,114,32,97,32,110,111,110,45,101,109,112,116,121,32,115,111,114,116,101,100,32,108,105,115,116,32,91,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,93,32,119,105,116,104,111,117,116,32,100,117,112,108,105,99,97,116,101,115,32,115,117,99,104,32,116,104,97,116,32,40,84,44,194,160,88,91,105,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,102,111,114,32,101,118,101,114,121,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,44,32,116,104,101,110,32,40,91,84,93,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<116,121,112,101,100,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115>>]},<<41,46>>]}]}]},{p,[],[<<65,110,32>>,{a,[{id,<<101,120,116,101,114,110,97,108,95,115,101,116>>}],[]},{em,[],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,83,101,116,115,46>>]},{p,[],[<<65,32>>,{a,[{id,<<116,121,112,101>>}],[]},{em,[],[<<116,121,112,101>>]},<<32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,83,101,116,115,46>>]},{p,[],[<<73,102,32,83,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,40,84,44,194,160,88,41,32,111,102,32,83,101,116,115,44,32,116,104,101,110,32,84,32,105,115,32,97,32>>,{a,[{id,<<118,97,108,105,100,95,116,121,112,101>>}],[]},{em,[],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32,88,44,32,84,32,105,115,32,116,104,101,32,116,121,112,101,32,111,102,32,83,44,32,97,110,100,32,88,32,105,115,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,83,46,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,116,101,114,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,116,101,114,109,47,50>>]}]},<<32,99,114,101,97,116,101,115,32,97,32,115,101,116,32,102,114,111,109,32,97,32,116,121,112,101,32,97,110,100,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,117,114,110,101,100,32,105,110,116,111,32,97,110,32,101,120,116,101,114,110,97,108,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,115,101,116,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,83,101,116,115,32,97,114,101,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,102,117,110,99,116,105,111,110,32,83,101,116,32,102,114,111,109,32,83,101,116,115,32,116,111,32,69,114,108,97,110,103,32,116,101,114,109,115,32,97,110,100,32,115,101,116,115,32,111,102,32,69,114,108,97,110,103,32,116,101,114,109,115,58>>]},{ul,[],[{li,[],[<<83,101,116,40,84,44,84,101,114,109,41,194,160,61,32,84,101,114,109,44,32,119,104,101,114,101,32,84,32,105,115,32,97,110,32,97,116,111,109>>]},{li,[],[<<83,101,116,40,123,84,91,49,93,44,194,160,46,46,46,44,194,160,84,91,110,93,125,44,194,160,123,88,91,49,93,44,194,160,46,46,46,44,32,194,160,88,91,110,93,125,41,194,160,61,32,40,83,101,116,40,84,91,49,93,44,194,160,88,91,49,93,41,44,194,160,46,46,46,44,194,160,32,83,101,116,40,84,91,110,93,44,194,160,88,91,110,93,41,41>>]},{li,[],[<<83,101,116,40,91,84,93,44,194,160,91,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,93,41,194,160,61,32,123,83,101,116,40,84,44,194,160,88,91,49,93,41,44,194,160,46,46,46,44,194,160,83,101,116,40,84,44,194,160,88,91,110,93,41,125>>]},{li,[],[<<83,101,116,40,91,84,93,44,194,160,91,93,41,194,160,61,32,123,125>>]}]},{p,[],[<<87,104,101,110,32,116,104,101,114,101,32,105,115,32,110,111,32,114,105,115,107,32,111,102,32,99,111,110,102,117,115,105,111,110,44,32,101,108,101,109,101,110,116,115,32,111,102,32,83,101,116,115,32,97,114,101,32,105,100,101,110,116,105,102,105,101,100,32,119,105,116,104,32,116,104,101,32,115,101,116,115,32,116,104,101,121,32,114,101,112,114,101,115,101,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,85,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,111,110,47,50>>]}]},<<32,119,105,116,104,32,83,49,32,97,110,100,32,83,50,32,97,115,32,97,114,103,117,109,101,110,116,115,44,32,116,104,101,110,32,85,32,105,115,32,115,97,105,100,32,116,111,32,98,101,32,116,104,101,32,117,110,105,111,110,32,111,102,32,83,49,32,97,110,100,32,83,50,46,32,65,32,109,111,114,101,32,112,114,101,99,105,115,101,32,102,111,114,109,117,108,97,116,105,111,110,32,105,115,32,116,104,97,116,32,83,101,116,40,85,41,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32,83,101,116,40,83,49,41,32,97,110,100,32,83,101,116,40,83,50,41,46>>]}]}]},{p,[],[<<84,104,101,32,116,121,112,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,105,109,112,108,101,109,101,110,116,32,116,104,101,32,118,97,114,105,111,117,115,32,99,111,110,100,105,116,105,111,110,115,32,116,104,97,116,32,115,101,116,115,32,109,117,115,116,32,102,117,108,102,105,108,108,46,32,65,115,32,97,110,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,116,119,111,32,115,101,116,115,32,82,32,97,110,100,32,83,44,32,97,110,100,32,114,101,99,97,108,108,32,116,104,97,116,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,82,32,97,110,100,32,83,32,105,115,32,100,101,102,105,110,101,100,32,105,102,32,82,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,116,111,32,89,32,97,110,100,32,83,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,89,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,105,109,112,108,101,109,101,110,116,115,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>]}]},<<44,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,114,101,112,114,101,115,101,110,116,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,98,121,32,109,97,116,99,104,105,110,103,32,91,123,65,44,66,125,93,32,97,103,97,105,110,115,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,32,40,65,114,103,49,32,115,97,121,41,44,32,97,110,100,32,91,123,67,44,68,125,93,32,97,103,97,105,110,115,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,40,65,114,103,50,32,115,97,121,41,46,32,84,104,101,32,102,97,99,116,32,116,104,97,116,32,91,123,65,44,66,125,93,32,109,97,116,99,104,101,115,32,116,104,101,32,116,121,112,101,32,111,102,32,65,114,103,49,32,105,115,32,116,111,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,65,114,103,49,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,88,32,116,111,32,89,44,32,119,104,101,114,101,32,88,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,97,108,108,32,115,101,116,115,32,83,101,116,40,120,41,32,102,111,114,32,115,111,109,101,32,101,108,101,109,101,110,116,32,120,32,105,110,32,83,101,116,115,32,116,104,101,32,116,121,112,101,32,111,102,32,119,104,105,99,104,32,105,115,32,65,44,32,97,110,100,32,115,105,109,105,108,97,114,108,121,32,102,111,114,32,89,46,32,73,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,65,114,103,50,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,87,32,116,111,32,90,46,32,70,105,110,97,108,108,121,32,105,116,32,105,115,32,99,104,101,99,107,101,100,32,116,104,97,116,32,66,32,109,97,116,99,104,101,115,32,67,44,32,119,104,105,99,104,32,105,115,32,115,117,102,102,105,99,105,101,110,116,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,87,32,105,115,32,101,113,117,97,108,32,116,111,32,89,46,32,84,104,101,32,117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116,32,105,115,32,104,97,110,100,108,101,100,32,115,101,112,97,114,97,116,101,108,121,58,32,105,116,115,32,116,121,112,101,44,32,91,39,95,39,93,44,32,109,97,116,99,104,101,115,32,116,104,101,32,116,121,112,101,32,111,102,32,97,110,121,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]},{p,[],[<<65,32,102,101,119,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,40>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,114,101,115,116,114,105,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,51>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,97,114,116,105,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,114,111,106,101,99,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,106,101,99,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,115,116,114,105,99,116,105,111,110,47,51>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,117,98,115,116,105,116,117,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,117,98,115,116,105,116,117,116,105,111,110,47,50>>]}]},<<41,32,97,99,99,101,112,116,32,97,110,32,69,114,108,97,110,103,32,102,117,110,99,116,105,111,110,32,97,115,32,97,32,109,101,97,110,115,32,116,111,32,109,111,100,105,102,121,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,97,32,103,105,118,101,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32>>,{a,[{id,<<115,101,116,95,102,117,110>>}],[]},<<83,117,99,104,32,97,32,102,117,110,99,116,105,111,110,44,32,99,97,108,108,101,100,32,83,101,116,70,117,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,102,117,110,99,116,105,111,110,97,108,32,111,98,106,101,99,116,32,40,102,117,110,41,44,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,125>>]},<<44,32,111,114,32,97,110,32,105,110,116,101,103,101,114,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,83,101,116,70,117,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,102,117,110,44,32,116,104,101,32,102,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,115,115,117,109,101,100,32,116,111,32,98,101,32,97,32,115,101,116,46>>]}]},{li,[],[{p,[],[<<73,102,32,83,101,116,70,117,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,32,70,117,110,125>>]},<<44,32,70,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,115,115,117,109,101,100,32,116,111,32,98,101,32,97,110,32,101,120,116,101,114,110,97,108,32,115,101,116,46,32,83,101,108,101,99,116,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,97,115,32,101,120,116,101,114,110,97,108,32,115,101,116,115,32,97,110,100,32,97,115,115,101,109,98,108,105,110,103,32,97,32,110,101,119,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,102,114,111,109,32,97,32,108,105,115,116,32,111,102,32,101,120,116,101,114,110,97,108,32,115,101,116,115,32,105,115,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,109,111,100,105,102,121,105,110,103,32,101,97,99,104,32,101,108,101,109,101,110,116,32,97,115,32,97,32,115,101,116,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,97,114,101,32,97,116,111,109,105,99,32,111,114,32,111,114,100,101,114,101,100,32,115,101,116,115,46,32,73,116,32,109,117,115,116,32,97,108,115,111,32,98,101,32,116,104,101,32,99,97,115,101,32,116,104,97,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,101,108,101,109,101,110,116,115,32,109,97,116,99,104,101,115,32,115,111,109,101,32,99,108,97,117,115,101,32,111,102,32,70,117,110,32,40,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,99,114,101,97,116,101,100,32,115,101,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32,70,117,110,32,116,111,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,41,44,32,97,110,100,32,116,104,97,116,32,70,117,110,32,100,111,101,115,32,110,111,116,104,105,110,103,32,98,117,116,32,115,101,108,101,99,116,105,110,103,44,32,100,117,112,108,105,99,97,116,105,110,103,44,32,111,114,32,114,101,97,114,114,97,110,103,105,110,103,32,112,97,114,116,115,32,111,102,32,116,104,101,32,101,108,101,109,101,110,116,115,46>>]}]},{li,[],[{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,97,32,83,101,116,70,117,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,32,73,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,88,41,194,160,45,62,32,101,108,101,109,101,110,116,40,73,44,194,160,88,41,194,160,101,110,100,125>>]},<<44,32,98,117,116,32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,44,32,97,115,32,105,116,32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,110,100,108,101,32,116,104,105,115,32,99,97,115,101,32,101,118,101,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,108,121,46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,32,111,102,32,83,101,116,70,117,110,115,58>>]},{pre,[],[{code,[],[<<102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,10,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,49,44,32,83,41,32,101,110,100,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,65,41,32,45,62,32,65,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,44,67,125,41,32,45,62,32,123,67,44,65,125,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,44,123,95,44,67,125,125,41,32,45,62,32,67,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,44,123,95,44,123,95,44,69,125,61,67,125,125,41,32,45,62,32,123,69,44,123,69,44,67,125,125,32,101,110,100,125,10,50>>]}]},{p,[],[<<84,104,101,32,111,114,100,101,114,32,105,110,32,119,104,105,99,104,32,97,32,83,101,116,70,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,101,100,44,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,46>>]},{p,[],[<<84,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,105,115,32,100,111,109,105,110,97,116,101,100,32,98,121,32,116,104,101,32,116,105,109,101,32,105,116,32,116,97,107,101,115,32,116,111,32,115,111,114,116,32,108,105,115,116,115,46,32,87,104,101,110,32,110,111,32,115,111,114,116,105,110,103,32,105,115,32,110,101,101,100,101,100,44,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,105,115,32,105,110,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,112,114,111,112,111,114,116,105,111,110,97,108,32,116,111,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,115,105,122,101,115,32,111,102,32,116,104,101,32,105,110,112,117,116,32,97,114,103,117,109,101,110,116,115,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,46,32,65,32,102,101,119,32,102,117,110,99,116,105,111,110,115,32,101,120,101,99,117,116,101,32,105,110,32,99,111,110,115,116,97,110,116,32,116,105,109,101,58,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,101,109,112,116,121,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,101,109,112,116,121,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,115,111,102,115,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,115,111,102,115,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,111,95,101,120,116,101,114,110,97,108,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,111,95,101,120,116,101,114,110,97,108,47,49>>]}]},<<32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,121,112,101,47,49>>]}]},<<46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,101,120,105,116,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32>>,{code,[],[<<98,97,100,95,102,117,110,99,116,105,111,110>>]},<<44,32,111,114,32>>,{code,[],[<<116,121,112,101,95,109,105,115,109,97,116,99,104>>]},<<32,109,101,115,115,97,103,101,32,119,104,101,110,32,103,105,118,101,110,32,98,97,100,108,121,32,102,111,114,109,101,100,32,97,114,103,117,109,101,110,116,115,32,111,114,32,115,101,116,115,32,116,104,101,32,116,121,112,101,115,32,111,102,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,46>>]},{p,[],[<<87,104,101,110,32,99,111,109,112,97,114,105,110,103,32,101,120,116,101,114,110,97,108,32,115,101,116,115,44,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<61,61,47,50>>]},<<32,105,115,32,117,115,101,100,46>>]},{h2,[],[<<83,101,101,32,65,108,115,111>>]},{p,[],[{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,99,116,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,103,114,97,112,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,103,114,97,112,104,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,111,114,100,100,105,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,114,100,100,105,99,116,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,111,114,100,115,101,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,114,100,115,101,116,115,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,116,115,40,51,41>>]}]}]}]},#{name => <<115,111,102,115>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,115,111,102,115,46,120,109,108],types => #{{a_function,0} => {attribute,120,type,{a_function,{user_type,120,relation,[]},[]}},{a_set,0} => {attribute,124,opaque,{a_set,{type,124,record,[{atom,124,'Set'}]},[]}},{anyset,0} => {attribute,117,type,{anyset,{type,117,union,[{user_type,117,ordset,[]},{user_type,117,a_set,[]}]},[]}},{binary_relation,0} => {attribute,118,type,{binary_relation,{user_type,118,relation,[]},[]}},{external_set,0} => {attribute,119,type,{external_set,{type,119,term,[]},[]}},{family,0} => {attribute,121,type,{family,{user_type,121,a_function,[]},[]}},{ordset,0} => {attribute,122,opaque,{ordset,{type,122,record,[{atom,122,'OrdSet'}]},[]}},{relation,0} => {attribute,123,type,{relation,{user_type,123,a_set,[]},[]}},{set_fun,0} => {attribute,126,type,{set_fun,{type,126,union,[{type,126,pos_integer,[]},{type,127,tuple,[{atom,127,external},{type,127,'fun',[{type,127,product,[{user_type,127,external_set,[]}]},{user_type,127,external_set,[]}]}]},{type,128,'fun',[{type,128,product,[{user_type,128,anyset,[]}]},{user_type,128,anyset,[]}]}]},[]}},{set_of_sets,0} => {attribute,125,type,{set_of_sets,{user_type,125,a_set,[]},[]}},{spec_fun,0} => {attribute,129,type,{spec_fun,{type,129,union,[{type,129,tuple,[{atom,129,external},{type,129,'fun',[{type,129,product,[{user_type,129,external_set,[]}]},{type,129,boolean,[]}]}]},{type,130,'fun',[{type,130,product,[{user_type,130,anyset,[]}]},{type,130,boolean,[]}]}]},[]}},{tuple_of,1} => {attribute,133,type,{tuple_of,{type,133,tuple,any},[{var,133,'_T'}]}},{type,0} => {attribute,131,type,{type,{type,131,term,[]},[]}}}},[{{function,a_function,2},[{file,[115,111,102,115,46,101,114,108]},{location,277}],[<<97,95,102,117,110,99,116,105,111,110,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,53,56>>,equiv => {function,a_function,1},signature => [{attribute,277,spec,{{a_function,2},[{type,277,bounded_fun,[{type,277,'fun',[{type,277,product,[{var,277,'Tuples'},{var,277,'Type'}]},{var,277,'Function'}]},[{type,278,constraint,[{atom,278,is_subtype},[{var,278,'Function'},{user_type,278,a_function,[]}]]},{type,279,constraint,[{atom,279,is_subtype},[{var,279,'Tuples'},{type,279,list,[{type,279,tuple,any}]}]]},{type,280,constraint,[{atom,280,is_subtype},[{var,280,'Type'},{user_type,280,type,[]}]]}]]}]}}]}},{{function,a_function,1},[{file,[115,111,102,115,46,101,114,108]},{location,265}],[<<97,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<46,32>>,{code,[],[<<97,95,102,117,110,99,116,105,111,110,40,70,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,70,44,194,160,84,41>>]},<<32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,102,117,110,99,116,105,111,110,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,97,116,111,109,125,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,121,112,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,53,56>>,signature => [{attribute,265,spec,{{a_function,1},[{type,265,bounded_fun,[{type,265,'fun',[{type,265,product,[{var,265,'Tuples'}]},{var,265,'Function'}]},[{type,266,constraint,[{atom,266,is_subtype},[{var,266,'Function'},{user_type,266,a_function,[]}]]},{type,267,constraint,[{atom,267,is_subtype},[{var,267,'Tuples'},{type,267,list,[{type,267,tuple,any}]}]]}]]}]}}]}},{{function,canonical_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,577}],[<<99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,40,69,44,194,160,83,101,116,41,32,115,117,99,104,32,116,104,97,116,32,83,101,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,97,110,100,32,69,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,46,32,73,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,97,32,115,101,116,32,88,32,97,110,100,32,82,32,105,115,32,116,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,32,105,110,100,117,99,101,100,32,98,121,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<44,32,116,104,101,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,108,97,116,105,111,110,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,97,110,111,110,105,99,97,108,95,109,97,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,97,110,111,110,105,99,97,108,32,109,97,112>>]},<<32,102,114,111,109,32,88,32,111,110,116,111,32,116,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,101,115,32,119,105,116,104,32,114,101,115,112,101,99,116,32,116,111,32,82,46>>]},{pre,[],[{code,[],[<<49,62,32,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,44,98,93,44,91,98,44,99,93,93,41,44,10,67,82,32,61,32,115,111,102,115,58,99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,40,83,115,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,67,82,41,46,10,91,123,97,44,91,97,44,98,93,125,44,123,98,44,91,97,44,98,93,125,44,123,98,44,91,98,44,99,93,125,44,123,99,44,91,98,44,99,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,55,50>>,signature => [{attribute,577,spec,{{canonical_relation,1},[{type,577,bounded_fun,[{type,577,'fun',[{type,577,product,[{var,577,'SetOfSets'}]},{var,577,'BinRel'}]},[{type,578,constraint,[{atom,578,is_subtype},[{var,578,'BinRel'},{user_type,578,binary_relation,[]}]]},{type,579,constraint,[{atom,579,is_subtype},[{var,579,'SetOfSets'},{user_type,579,set_of_sets,[]}]]}]]}]}}]}},{{function,composite,2},[{file,[115,111,102,115,46,101,114,108]},{location,844}],[<<99,111,109,112,111,115,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,109,112,111,115,105,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,109,112,111,115,105,116,101>>]},<<32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{code,[],[<<70,117,110,99,116,105,111,110,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,97,95,102,117,110,99,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,50,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,97,95,102,117,110,99,116,105,111,110,40,91,123,49,44,120,125,44,123,50,44,121,125,44,123,51,44,122,125,93,41,44,10,70,32,61,32,115,111,102,115,58,99,111,109,112,111,115,105,116,101,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,120,125,44,123,98,44,121,125,44,123,99,44,121,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,57,50>>,signature => [{attribute,844,spec,{{composite,2},[{type,844,bounded_fun,[{type,844,'fun',[{type,844,product,[{var,844,'Function1'},{var,844,'Function2'}]},{var,844,'Function3'}]},[{type,845,constraint,[{atom,845,is_subtype},[{var,845,'Function1'},{user_type,845,a_function,[]}]]},{type,846,constraint,[{atom,846,is_subtype},[{var,846,'Function2'},{user_type,846,a_function,[]}]]},{type,847,constraint,[{atom,847,is_subtype},[{var,847,'Function3'},{user_type,847,a_function,[]}]]}]]}]}}]}},{{function,constant_function,2},[{file,[115,111,102,115,46,101,114,108]},{location,465}],[<<99,111,110,115,116,97,110,116,95,102,117,110,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<32,116,104,97,116,32,109,97,112,115,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,115,101,116,32>>,{code,[],[<<83,101,116>>]},<<32,111,110,116,111,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,69,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,49,41,44,10,82,32,61,32,115,111,102,115,58,99,111,110,115,116,97,110,116,95,102,117,110,99,116,105,111,110,40,83,44,32,69,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,97,44,49,125,44,123,98,44,49,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,48,56>>,signature => [{attribute,465,spec,{{constant_function,2},[{type,465,bounded_fun,[{type,465,'fun',[{type,465,product,[{var,465,'Set'},{var,465,'AnySet'}]},{var,465,'Function'}]},[{type,466,constraint,[{atom,466,is_subtype},[{var,466,'AnySet'},{user_type,466,anyset,[]}]]},{type,467,constraint,[{atom,467,is_subtype},[{var,467,'Function'},{user_type,467,a_function,[]}]]},{type,468,constraint,[{atom,468,is_subtype},[{var,468,'Set'},{user_type,468,a_set,[]}]]}]]}]}}]}},{{function,converse,1},[{file,[115,111,102,115,46,101,114,108]},{location,707}],[<<99,111,110,118,101,114,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,97,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,99,111,110,118,101,114,115,101,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,97,44,49,125,44,123,97,44,51,125,44,123,98,44,50,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,50,52>>,signature => [{attribute,707,spec,{{converse,1},[{type,707,bounded_fun,[{type,707,'fun',[{type,707,product,[{var,707,'BinRel1'}]},{var,707,'BinRel2'}]},[{type,708,constraint,[{atom,708,is_subtype},[{var,708,'BinRel1'},{user_type,708,binary_relation,[]}]]},{type,709,constraint,[{atom,709,is_subtype},[{var,709,'BinRel2'},{user_type,709,binary_relation,[]}]]}]]}]}}]}},{{function,difference,2},[{file,[115,111,102,115,46,101,114,108]},{location,398}],[<<100,105,102,102,101,114,101,110,99,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,102,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,104,101,32,115,101,116,115,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,51,56>>,signature => [{attribute,398,spec,{{difference,2},[{type,398,bounded_fun,[{type,398,'fun',[{type,398,product,[{var,398,'Set1'},{var,398,'Set2'}]},{var,398,'Set3'}]},[{type,399,constraint,[{atom,399,is_subtype},[{var,399,'Set1'},{user_type,399,a_set,[]}]]},{type,400,constraint,[{atom,400,is_subtype},[{var,400,'Set2'},{user_type,400,a_set,[]}]]},{type,401,constraint,[{atom,401,is_subtype},[{var,401,'Set3'},{user_type,401,a_set,[]}]]}]]}]}}]}},{{function,digraph_to_family,2},[{file,[115,111,102,115,46,101,114,108]},{location,1520}],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,52,55>>,equiv => {function,digraph_to_family,1},signature => [{attribute,1520,spec,{{digraph_to_family,2},[{type,1520,bounded_fun,[{type,1520,'fun',[{type,1520,product,[{var,1520,'Graph'},{var,1520,'Type'}]},{var,1520,'Family'}]},[{type,1521,constraint,[{atom,1521,is_subtype},[{var,1521,'Graph'},{remote_type,1521,[{atom,1521,digraph},{atom,1521,graph},[]]}]]},{type,1522,constraint,[{atom,1522,is_subtype},[{var,1522,'Family'},{user_type,1522,family,[]}]]},{type,1523,constraint,[{atom,1523,is_subtype},[{var,1523,'Type'},{user_type,1523,type,[]}]]}]]}]}}]}},{{function,digraph_to_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1511}],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,102,114,111,109,32,116,104,101,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,32>>,{code,[],[<<71,114,97,112,104>>]},<<46,32,69,97,99,104,32,118,101,114,116,101,120,32,97,32,111,102,32>>,{code,[],[<<71,114,97,112,104>>]},<<32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,112,97,105,114,32,40,97,44,194,160,123,98,91,49,93,44,194,160,46,46,46,44,194,160,98,91,110,93,125,41,44,32,119,104,101,114,101,32,116,104,101,32,98,91,105,93,58,115,32,97,114,101,32,116,104,101,32,111,117,116,45,110,101,105,103,104,98,111,114,115,32,111,102,32,97,46,32,73,102,32,110,111,32,116,121,112,101,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32,91,123,97,116,111,109,44,194,160,91,97,116,111,109,93,125,93,32,105,115,32,117,115,101,100,32,97,115,32,116,121,112,101,32,111,102,32,116,104,101,32,102,97,109,105,108,121,46,32,73,116,32,105,115,32,97,115,115,117,109,101,100,32,116,104,97,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,116,104,101,32,102,97,109,105,108,121,46>>]},{p,[],[<<73,102,32,71,32,105,115,32,97,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,44,32,105,116,32,104,111,108,100,115,32,116,104,97,116,32,116,104,101,32,118,101,114,116,105,99,101,115,32,97,110,100,32,101,100,103,101,115,32,111,102,32,71,32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,118,101,114,116,105,99,101,115,32,97,110,100,32,101,100,103,101,115,32,111,102,32>>,{code,[],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,40,100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,40,71,41,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,52,55>>,signature => [{attribute,1511,spec,{{digraph_to_family,1},[{type,1511,bounded_fun,[{type,1511,'fun',[{type,1511,product,[{var,1511,'Graph'}]},{var,1511,'Family'}]},[{type,1512,constraint,[{atom,1512,is_subtype},[{var,1512,'Graph'},{remote_type,1512,[{atom,1512,digraph},{atom,1512,graph},[]]}]]},{type,1513,constraint,[{atom,1513,is_subtype},[{var,1513,'Family'},{user_type,1513,family,[]}]]}]]}]}}]}},{{function,domain,1},[{file,[115,111,102,115,46,101,114,108]},{location,612}],[<<100,111,109,97,105,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,100,111,109,97,105,110,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,49,44,50,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,54,55>>,signature => [{attribute,612,spec,{{domain,1},[{type,612,bounded_fun,[{type,612,'fun',[{type,612,product,[{var,612,'BinRel'}]},{var,612,'Set'}]},[{type,613,constraint,[{atom,613,is_subtype},[{var,613,'BinRel'},{user_type,613,binary_relation,[]}]]},{type,614,constraint,[{atom,614,is_subtype},[{var,614,'Set'},{user_type,614,a_set,[]}]]}]]}]}}]}},{{function,drestriction,2},[{file,[115,111,102,115,46,101,114,108]},{location,833}],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,116,111,32>>,{code,[],[<<83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,52,44,54,93,41,44,10,82,50,32,61,32,115,111,102,115,58,100,114,101,115,116,114,105,99,116,105,111,110,40,82,49,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,97,125,44,123,51,44,99,125,93>>]}]},{p,[],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,40,82,44,194,160,83,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<100,105,102,102,101,114,101,110,99,101,40,82,44,194,160,114,101,115,116,114,105,99,116,105,111,110,40,82,44,194,160,83,41,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,56,49>>,signature => [{attribute,833,spec,{{drestriction,2},[{type,833,bounded_fun,[{type,833,'fun',[{type,833,product,[{var,833,'BinRel1'},{var,833,'Set'}]},{var,833,'BinRel2'}]},[{type,834,constraint,[{atom,834,is_subtype},[{var,834,'BinRel1'},{user_type,834,binary_relation,[]}]]},{type,835,constraint,[{atom,835,is_subtype},[{var,835,'BinRel2'},{user_type,835,binary_relation,[]}]]},{type,836,constraint,[{atom,836,is_subtype},[{var,836,'Set'},{user_type,836,a_set,[]}]]}]]}]}}]}},{{function,drestriction,3},[{file,[115,111,102,115,46,101,114,108]},{location,960}],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,100,111,32,110,111,116,32,103,105,118,101,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,65,44,66,44,67,125,41,32,45,62,32,123,66,44,67,125,32,101,110,100,125,44,10,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,97,97,44,49,125,44,123,98,44,98,98,44,50,125,44,123,99,44,99,99,44,51,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,98,98,44,50,125,44,123,99,99,44,51,125,44,123,100,100,44,52,125,93,41,44,10,82,51,32,61,32,115,111,102,115,58,100,114,101,115,116,114,105,99,116,105,111,110,40,83,101,116,70,117,110,44,32,82,49,44,32,82,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,46,10,91,123,97,44,97,97,44,49,125,93>>]}]},{p,[],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<100,105,102,102,101,114,101,110,99,101,40,83,49,44,194,160,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,48,48>>,signature => [{attribute,960,spec,{{drestriction,3},[{type,960,bounded_fun,[{type,960,'fun',[{type,960,product,[{var,960,'SetFun'},{var,960,'Set1'},{var,960,'Set2'}]},{var,960,'Set3'}]},[{type,961,constraint,[{atom,961,is_subtype},[{var,961,'SetFun'},{user_type,961,set_fun,[]}]]},{type,962,constraint,[{atom,962,is_subtype},[{var,962,'Set1'},{user_type,962,a_set,[]}]]},{type,963,constraint,[{atom,963,is_subtype},[{var,963,'Set2'},{user_type,963,a_set,[]}]]},{type,964,constraint,[{atom,964,is_subtype},[{var,964,'Set3'},{user_type,964,a_set,[]}]]}]]}]}}]}},{{function,empty_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,178}],[<<101,109,112,116,121,95,115,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116>>]},<<46,32>>,{code,[],[<<101,109,112,116,121,95,115,101,116,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,91,93,44,194,160,91,39,95,39,93,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,50,48>>,signature => [{attribute,178,spec,{{empty_set,0},[{type,178,bounded_fun,[{type,178,'fun',[{type,178,product,[]},{var,178,'Set'}]},[{type,179,constraint,[{atom,179,is_subtype},[{var,179,'Set'},{user_type,179,a_set,[]}]]}]]}]}}]}},{{function,extension,3},[{file,[115,111,102,115,46,101,114,108]},{location,779}],[<<101,120,116,101,110,115,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,110,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,110,115,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,115,117,99,104,32,116,104,97,116,32,102,111,114,32,101,97,99,104,32,101,108,101,109,101,110,116,32,69,32,105,110,32>>,{code,[],[<<83,101,116>>]},<<32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<44,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,112,97,105,114,32,40,69,44,194,160>>,{code,[],[<<65,110,121,83,101,116>>]},<<41,46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,115,101,116,40,91,98,44,99,93,41,44,10,65,32,61,32,115,111,102,115,58,101,109,112,116,121,95,115,101,116,40,41,44,10,82,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,93,41,44,10,88,32,61,32,115,111,102,115,58,101,120,116,101,110,115,105,111,110,40,82,44,32,83,44,32,65,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,88,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,44,123,99,44,91,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,51,48>>,signature => [{attribute,779,spec,{{extension,3},[{type,779,bounded_fun,[{type,779,'fun',[{type,779,product,[{var,779,'BinRel1'},{var,779,'Set'},{var,779,'AnySet'}]},{var,779,'BinRel2'}]},[{type,780,constraint,[{atom,780,is_subtype},[{var,780,'AnySet'},{user_type,780,anyset,[]}]]},{type,781,constraint,[{atom,781,is_subtype},[{var,781,'BinRel1'},{user_type,781,binary_relation,[]}]]},{type,782,constraint,[{atom,782,is_subtype},[{var,782,'BinRel2'},{user_type,782,binary_relation,[]}]]},{type,783,constraint,[{atom,783,is_subtype},[{var,783,'Set'},{user_type,783,a_set,[]}]]}]]}]}}]}},{{function,family,2},[{file,[115,111,102,115,46,101,114,108]},{location,302}],[<<102,97,109,105,108,121,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,53,48>>,equiv => {function,family,1},signature => [{attribute,302,spec,{{family,2},[{type,302,bounded_fun,[{type,302,'fun',[{type,302,product,[{var,302,'Tuples'},{var,302,'Type'}]},{var,302,'Family'}]},[{type,303,constraint,[{atom,303,is_subtype},[{var,303,'Family'},{user_type,303,family,[]}]]},{type,304,constraint,[{atom,304,is_subtype},[{var,304,'Tuples'},{type,304,list,[{type,304,tuple,any}]}]]},{type,305,constraint,[{atom,305,is_subtype},[{var,305,'Type'},{user_type,305,type,[]}]]}]]}]}}]}},{{function,family,1},[{file,[115,111,102,115,46,101,114,108]},{location,290}],[<<102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115>>]},<<46,32>>,{code,[],[<<102,97,109,105,108,121,40,70,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,70,44,194,160,84,41>>]},<<32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,102,97,109,105,108,121,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,91,97,116,111,109,93,125,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,102,97,109,105,108,121,32,116,121,112,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,53,48>>,signature => [{attribute,290,spec,{{family,1},[{type,290,bounded_fun,[{type,290,'fun',[{type,290,product,[{var,290,'Tuples'}]},{var,290,'Family'}]},[{type,291,constraint,[{atom,291,is_subtype},[{var,291,'Family'},{user_type,291,family,[]}]]},{type,292,constraint,[{atom,292,is_subtype},[{var,292,'Tuples'},{type,292,list,[{type,292,tuple,any}]}]]}]]}]}}]}},{{function,family_difference,2},[{file,[115,111,102,115,46,101,114,108]},{location,1385}],[<<102,97,109,105,108,121,95,100,105,102,102,101,114,101,110,99,101,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,101,113,117,97,108,32,116,111,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,102,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,109,97,112,115,32,105,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,97,109,105,108,121,49,91,105,93>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,54,44,55,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,100,105,102,102,101,114,101,110,99,101,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,54,52>>,signature => [{attribute,1385,spec,{{family_difference,2},[{type,1385,bounded_fun,[{type,1385,'fun',[{type,1385,product,[{var,1385,'Family1'},{var,1385,'Family2'}]},{var,1385,'Family3'}]},[{type,1386,constraint,[{atom,1386,is_subtype},[{var,1386,'Family1'},{user_type,1386,family,[]}]]},{type,1387,constraint,[{atom,1387,is_subtype},[{var,1387,'Family2'},{user_type,1387,family,[]}]]},{type,1388,constraint,[{atom,1388,is_subtype},[{var,1388,'Family3'},{user_type,1388,family,[]}]]}]]}]}}]}},{{function,family_domain,1},[{file,[115,111,102,115,46,101,114,108]},{location,1341}],[<<102,97,109,105,108,121,95,100,111,109,97,105,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49,91,105,93>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,100,111,109,97,105,110,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,44,123,99,44,91,52,44,53,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,56,53>>,signature => [{attribute,1341,spec,{{family_domain,1},[{type,1341,bounded_fun,[{type,1341,'fun',[{type,1341,product,[{var,1341,'Family1'}]},{var,1341,'Family2'}]},[{type,1342,constraint,[{atom,1342,is_subtype},[{var,1342,'Family1'},{user_type,1342,family,[]}]]},{type,1343,constraint,[{atom,1343,is_subtype},[{var,1343,'Family2'},{user_type,1343,family,[]}]]}]]}]}}]}},{{function,family_field,1},[{file,[115,111,102,115,46,101,114,108]},{location,1365}],[<<102,97,109,105,108,121,95,102,105,101,108,100,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,102,105,101,108,100,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,49,44,50,44,51,44,97,44,98,44,99,93,125,44,123,98,44,91,93,125,44,123,99,44,91,52,44,53,44,100,44,101,93,125,93>>]}]},{p,[],[{code,[],[<<102,97,109,105,108,121,95,102,105,101,108,100,40,70,97,109,105,108,121,49,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,97,109,105,108,121,95,117,110,105,111,110,40,102,97,109,105,108,121,95,100,111,109,97,105,110,40,70,97,109,105,108,121,49,41,44,32,102,97,109,105,108,121,95,114,97,110,103,101,40,70,97,109,105,108,121,49,41,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,48,54>>,signature => [{attribute,1365,spec,{{family_field,1},[{type,1365,bounded_fun,[{type,1365,'fun',[{type,1365,product,[{var,1365,'Family1'}]},{var,1365,'Family2'}]},[{type,1366,constraint,[{atom,1366,is_subtype},[{var,1366,'Family1'},{user_type,1366,family,[]}]]},{type,1367,constraint,[{atom,1367,is_subtype},[{var,1367,'Family2'},{user_type,1367,family,[]}]]}]]}]}}]}},{{function,family_intersection,1},[{file,[115,111,102,115,46,101,114,108]},{location,1325}],[<<102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,110,32,101,109,112,116,121,32,115,101,116,32,102,111,114,32,115,111,109,101,32,105,44,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,44,51,93,44,91,50,44,51,44,52,93,93,125,44,123,98,44,91,91,120,44,121,44,122,93,44,91,120,44,121,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,40,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,50,44,51,93,125,44,123,98,44,91,120,44,121,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,51,48>>,signature => [{attribute,1325,spec,{{family_intersection,1},[{type,1325,bounded_fun,[{type,1325,'fun',[{type,1325,product,[{var,1325,'Family1'}]},{var,1325,'Family2'}]},[{type,1326,constraint,[{atom,1326,is_subtype},[{var,1326,'Family1'},{user_type,1326,family,[]}]]},{type,1327,constraint,[{atom,1327,is_subtype},[{var,1327,'Family2'},{user_type,1327,family,[]}]]}]]}]}}]}},{{function,family_intersection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1378}],[<<102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<58,115,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<58,115,32,105,110,100,101,120,32,115,101,116,115,44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,44,123,99,44,91,53,44,54,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,98,44,91,52,93,125,44,123,99,44,91,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,53,52>>,signature => [{attribute,1378,spec,{{family_intersection,2},[{type,1378,bounded_fun,[{type,1378,'fun',[{type,1378,product,[{var,1378,'Family1'},{var,1378,'Family2'}]},{var,1378,'Family3'}]},[{type,1379,constraint,[{atom,1379,is_subtype},[{var,1379,'Family1'},{user_type,1379,family,[]}]]},{type,1380,constraint,[{atom,1380,is_subtype},[{var,1380,'Family2'},{user_type,1380,family,[]}]]},{type,1381,constraint,[{atom,1381,is_subtype},[{var,1381,'Family3'},{user_type,1381,family,[]}]]}]]}]}}]}},{{function,family_projection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1451}],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,99,97,108,108,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,119,105,116,104,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,93,44,91,50,44,51,93,93,125,44,123,98,44,91,91,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,40,102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,44,32,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,55,52>>,signature => [{attribute,1451,spec,{{family_projection,2},[{type,1451,bounded_fun,[{type,1451,'fun',[{type,1451,product,[{var,1451,'SetFun'},{var,1451,'Family1'}]},{var,1451,'Family2'}]},[{type,1452,constraint,[{atom,1452,is_subtype},[{var,1452,'SetFun'},{user_type,1452,set_fun,[]}]]},{type,1453,constraint,[{atom,1453,is_subtype},[{var,1453,'Family1'},{user_type,1453,family,[]}]]},{type,1454,constraint,[{atom,1454,is_subtype},[{var,1454,'Family2'},{user_type,1454,family,[]}]]}]]}]}}]}},{{function,family_range,1},[{file,[115,111,102,115,46,101,114,108]},{location,1353}],[<<102,97,109,105,108,121,95,114,97,110,103,101,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,97,110,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,97,110,103,101>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,114,97,110,103,101,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,97,44,98,44,99,93,125,44,123,98,44,91,93,125,44,123,99,44,91,100,44,101,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,57,51>>,signature => [{attribute,1353,spec,{{family_range,1},[{type,1353,bounded_fun,[{type,1353,'fun',[{type,1353,product,[{var,1353,'Family1'}]},{var,1353,'Family2'}]},[{type,1354,constraint,[{atom,1354,is_subtype},[{var,1354,'Family1'},{user_type,1354,family,[]}]]},{type,1355,constraint,[{atom,1355,is_subtype},[{var,1355,'Family2'},{user_type,1355,family,[]}]]}]]}]}}]}},{{function,family_specification,2},[{file,[115,111,102,115,46,101,114,108]},{location,1265}],[<<102,97,109,105,108,121,95,115,112,101,99,105,102,105,99,97,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,116,111,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,105,32,111,102,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,102,111,114,32,119,104,105,99,104,32>>,{code,[],[<<70,117,110>>]},<<32,97,112,112,108,105,101,100,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,50,125>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,117,110,50>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,49,44,50,93,125,44,123,99,44,91,49,93,125,93,41,44,10,83,112,101,99,70,117,110,32,61,32,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,110,111,95,101,108,101,109,101,110,116,115,40,83,41,32,61,58,61,32,50,32,101,110,100,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,115,112,101,99,105,102,105,99,97,116,105,111,110,40,83,112,101,99,70,117,110,44,32,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,98,44,91,49,44,50,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,49,52>>,signature => [{attribute,1265,spec,{{family_specification,2},[{type,1265,bounded_fun,[{type,1265,'fun',[{type,1265,product,[{var,1265,'Fun'},{var,1265,'Family1'}]},{var,1265,'Family2'}]},[{type,1266,constraint,[{atom,1266,is_subtype},[{var,1266,'Fun'},{user_type,1266,spec_fun,[]}]]},{type,1267,constraint,[{atom,1267,is_subtype},[{var,1267,'Family1'},{user_type,1267,family,[]}]]},{type,1268,constraint,[{atom,1268,is_subtype},[{var,1268,'Family2'},{user_type,1268,family,[]}]]}]]}]}}]}},{{function,family_to_digraph,2},[{file,[115,111,102,115,46,101,114,108]},{location,1489}],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,51,57>>,equiv => {function,family_to_digraph,1},signature => [{attribute,1489,spec,{{family_to_digraph,2},[{type,1489,bounded_fun,[{type,1489,'fun',[{type,1489,product,[{var,1489,'Family'},{var,1489,'GraphType'}]},{var,1489,'Graph'}]},[{type,1490,constraint,[{atom,1490,is_subtype},[{var,1490,'Graph'},{remote_type,1490,[{atom,1490,digraph},{atom,1490,graph},[]]}]]},{type,1491,constraint,[{atom,1491,is_subtype},[{var,1491,'Family'},{user_type,1491,family,[]}]]},{type,1492,constraint,[{atom,1492,is_subtype},[{var,1492,'GraphType'},{type,1492,list,[{remote_type,1492,[{atom,1492,digraph},{atom,1492,d_type},[]]}]}]]}]]}]}}]}},{{function,family_to_digraph,1},[{file,[115,111,102,115,46,101,114,108]},{location,1479}],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,32,102,114,111,109,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46,32,70,111,114,32,101,97,99,104,32,112,97,105,114,32,40,97,44,194,160,123,98,91,49,93,44,194,160,46,46,46,44,194,160,98,91,110,93,125,41,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<44,32,118,101,114,116,101,120,32,97,32,97,110,100,32,116,104,101,32,101,100,103,101,115,32,40,97,44,194,160,98,91,105,93,41,32,102,111,114,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,32,97,114,101,32,97,100,100,101,100,32,116,111,32,97,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,46>>]},{p,[],[<<73,102,32,110,111,32,103,114,97,112,104,32,116,121,112,101,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,100,105,103,114,97,112,104,35,110,101,119,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,105,103,114,97,112,104,58,110,101,119,47,48>>]}]},<<32,105,115,32,117,115,101,100,32,102,111,114,32,99,114,101,97,116,105,110,103,32,116,104,101,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,44,32,111,116,104,101,114,119,105,115,101,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<71,114,97,112,104,84,121,112,101>>]},<<32,105,115,32,112,97,115,115,101,100,32,111,110,32,97,115,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,100,105,103,114,97,112,104,35,110,101,119,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,105,103,114,97,112,104,58,110,101,119,47,49>>]}]},<<46>>]},{p,[],[<<73,116,32,70,32,105,115,32,97,32,102,97,109,105,108,121,44,32,105,116,32,104,111,108,100,115,32,116,104,97,116,32,70,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,40,102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,40,70,41,44,194,160,116,121,112,101,40,70,41,41>>]},<<46,32,69,113,117,97,108,105,116,121,32,104,111,108,100,115,32,105,102,32>>,{code,[],[<<117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41>>]},<<32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<100,111,109,97,105,110,40,70,41>>]},<<46>>]},{p,[],[<<67,114,101,97,116,105,110,103,32,97,32,99,121,99,108,101,32,105,110,32,97,110,32,97,99,121,99,108,105,99,32,103,114,97,112,104,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<99,121,99,108,105,99>>]},<<32,109,101,115,115,97,103,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,51,57>>,signature => [{attribute,1479,spec,{{family_to_digraph,1},[{type,1479,bounded_fun,[{type,1479,'fun',[{type,1479,product,[{var,1479,'Family'}]},{var,1479,'Graph'}]},[{type,1480,constraint,[{atom,1480,is_subtype},[{var,1480,'Graph'},{remote_type,1480,[{atom,1480,digraph},{atom,1480,graph},[]]}]]},{type,1481,constraint,[{atom,1481,is_subtype},[{var,1481,'Family'},{user_type,1481,family,[]}]]}]]}]}}]}},{{function,family_to_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,1253}],[<<102,97,109,105,108,121,95,116,111,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,112,97,105,114,115,32,40,105,44,194,160,120,41,32,115,117,99,104,32,116,104,97,116,32,105,32,98,101,108,111,110,103,115,32,116,111,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,97,110,100,32,120,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,93,125,44,32,123,98,44,91,49,93,125,44,32,123,99,44,91,50,44,51,93,125,93,41,44,10,82,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,116,111,95,114,101,108,97,116,105,111,110,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,98,44,49,125,44,123,99,44,50,125,44,123,99,44,51,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,54,53>>,signature => [{attribute,1253,spec,{{family_to_relation,1},[{type,1253,bounded_fun,[{type,1253,'fun',[{type,1253,product,[{var,1253,'Family'}]},{var,1253,'BinRel'}]},[{type,1254,constraint,[{atom,1254,is_subtype},[{var,1254,'Family'},{user_type,1254,family,[]}]]},{type,1255,constraint,[{atom,1255,is_subtype},[{var,1255,'BinRel'},{user_type,1255,binary_relation,[]}]]}]]}]}}]}},{{function,family_union,1},[{file,[115,111,102,115,46,101,114,108]},{location,1314}],[<<102,97,109,105,108,121,95,117,110,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,102,111,114,32,101,97,99,104,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,93,44,91,50,44,51,93,93,125,44,123,98,44,91,91,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,117,110,105,111,110,40,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,93>>]}]},{p,[],[{code,[],[<<102,97,109,105,108,121,95,117,110,105,111,110,40,70,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,40,102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,44,194,160,70,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,56,51>>,signature => [{attribute,1314,spec,{{family_union,1},[{type,1314,bounded_fun,[{type,1314,'fun',[{type,1314,product,[{var,1314,'Family1'}]},{var,1314,'Family2'}]},[{type,1315,constraint,[{atom,1315,is_subtype},[{var,1315,'Family1'},{user_type,1315,family,[]}]]},{type,1316,constraint,[{atom,1316,is_subtype},[{var,1316,'Family2'},{user_type,1316,family,[]}]]}]]}]}}]}},{{function,family_union,2},[{file,[115,111,102,115,46,101,114,108]},{location,1371}],[<<102,97,109,105,108,121,95,117,110,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<58,115,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<58,115,32,105,110,100,101,120,32,115,101,116,115,44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,102,32,98,111,116,104,32,109,97,112,32,105,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,111,114,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,44,123,99,44,91,53,44,54,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,117,110,105,111,110,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,44,53,93,125,44,123,99,44,91,53,44,54,44,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,48,54>>,signature => [{attribute,1371,spec,{{family_union,2},[{type,1371,bounded_fun,[{type,1371,'fun',[{type,1371,product,[{var,1371,'Family1'},{var,1371,'Family2'}]},{var,1371,'Family3'}]},[{type,1372,constraint,[{atom,1372,is_subtype},[{var,1372,'Family1'},{user_type,1372,family,[]}]]},{type,1373,constraint,[{atom,1373,is_subtype},[{var,1373,'Family2'},{user_type,1373,family,[]}]]},{type,1374,constraint,[{atom,1374,is_subtype},[{var,1374,'Family3'},{user_type,1374,family,[]}]]}]]}]}}]}},{{function,field,1},[{file,[115,111,102,115,46,101,114,108]},{location,632}],[<<102,105,101,108,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,102,105,101,108,100,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,49,44,50,44,97,44,98,44,99,93>>]}]},{p,[],[{code,[],[<<102,105,101,108,100,40,82,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<117,110,105,111,110,40,100,111,109,97,105,110,40,82,41,44,32,114,97,110,103,101,40,82,41,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,50,56>>,signature => [{attribute,632,spec,{{field,1},[{type,632,bounded_fun,[{type,632,'fun',[{type,632,product,[{var,632,'BinRel'}]},{var,632,'Set'}]},[{type,633,constraint,[{atom,633,is_subtype},[{var,633,'BinRel'},{user_type,633,binary_relation,[]}]]},{type,634,constraint,[{atom,634,is_subtype},[{var,634,'Set'},{user_type,634,a_set,[]}]]}]]}]}}]}},{{function,from_external,2},[{file,[115,111,102,115,46,101,114,108]},{location,169}],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,115,101,116,32,102,114,111,109,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32>>,{code,[],[<<69,120,116,101,114,110,97,108,83,101,116>>]},<<32,97,110,100,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<46,32,73,116,32,105,115,32,97,115,115,117,109,101,100,32,116,104,97,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32>>,{code,[],[<<69,120,116,101,114,110,97,108,83,101,116>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,52,52>>,signature => [{attribute,169,spec,{{from_external,2},[{type,169,bounded_fun,[{type,169,'fun',[{type,169,product,[{var,169,'ExternalSet'},{var,169,'Type'}]},{var,169,'AnySet'}]},[{type,170,constraint,[{atom,170,is_subtype},[{var,170,'ExternalSet'},{user_type,170,external_set,[]}]]},{type,171,constraint,[{atom,171,is_subtype},[{var,171,'AnySet'},{user_type,171,anyset,[]}]]},{type,172,constraint,[{atom,172,is_subtype},[{var,172,'Type'},{user_type,172,type,[]}]]}]]}]}}]}},{{function,from_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,220}],[<<102,114,111,109,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,101,116,115,32,111,102,32,108,105,115,116,32>>,{code,[],[<<76,105,115,116,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,120,44,51,125,44,123,121,44,52,125,93,41,44,10,83,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,83,49,44,83,50,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,91,123,97,44,49,125,44,123,98,44,50,125,93,44,91,123,120,44,51,125,44,123,121,44,52,125,93,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,53,55>>,signature => [{attribute,220,spec,{{from_sets,1},[{type,220,bounded_fun,[{type,220,'fun',[{type,220,product,[{var,220,'ListOfSets'}]},{var,220,'Set'}]},[{type,221,constraint,[{atom,221,is_subtype},[{var,221,'Set'},{user_type,221,a_set,[]}]]},{type,222,constraint,[{atom,222,is_subtype},[{var,222,'ListOfSets'},{type,222,list,[{user_type,222,anyset,[]}]}]]}]]}]}}]}},{{function,from_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,220}],[<<102,114,111,109,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,101,116,115,32,111,102,32,116,104,101,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,55,51>>,signature => [{attribute,220,spec,{{from_sets,1},[{type,223,bounded_fun,[{type,223,'fun',[{type,223,product,[{var,223,'TupleOfSets'}]},{var,223,'Ordset'}]},[{type,224,constraint,[{atom,224,is_subtype},[{var,224,'Ordset'},{user_type,224,ordset,[]}]]},{type,225,constraint,[{atom,225,is_subtype},[{var,225,'TupleOfSets'},{user_type,225,tuple_of,[{user_type,225,anyset,[]}]}]]}]]}]}}]}},{{function,from_term,2},[{file,[115,111,102,115,46,101,114,108]},{location,155}],[<<102,114,111,109,95,116,101,114,109,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,56,51>>,equiv => {function,from_term,1},signature => [{attribute,155,spec,{{from_term,2},[{type,155,bounded_fun,[{type,155,'fun',[{type,155,product,[{var,155,'Term'},{var,155,'Type'}]},{var,155,'AnySet'}]},[{type,156,constraint,[{atom,156,is_subtype},[{var,156,'AnySet'},{user_type,156,anyset,[]}]]},{type,157,constraint,[{atom,157,is_subtype},[{var,157,'Term'},{type,157,term,[]}]]},{type,158,constraint,[{atom,158,is_subtype},[{var,158,'Type'},{user_type,158,type,[]}]]}]]}]}}]}},{{function,from_term,1},[{file,[115,111,102,115,46,101,114,108]},{location,143}],[<<102,114,111,109,95,116,101,114,109,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<102,114,111,109,95,116,101,114,109>>}],[]},<<67,114,101,97,116,101,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,101,116,115>>]},<<32,98,121,32,116,114,97,118,101,114,115,105,110,103,32,116,101,114,109,32>>,{code,[],[<<84,101,114,109>>]},<<44,32,115,111,114,116,105,110,103,32,108,105,115,116,115,44,32,114,101,109,111,118,105,110,103,32,100,117,112,108,105,99,97,116,101,115,44,32,97,110,100,32,100,101,114,105,118,105,110,103,32,111,114,32,118,101,114,105,102,121,105,110,103,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,102,111,114,32,116,104,101,32,115,111,32,111,98,116,97,105,110,101,100,32,101,120,116,101,114,110,97,108,32,115,101,116,46,32,65,110,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,108,105,109,105,116,32,116,104,101,32,100,101,112,116,104,32,111,102,32,116,104,101,32,116,114,97,118,101,114,115,97,108,59,32,97,110,32,97,116,111,109,105,99,32,116,121,112,101,32,115,116,111,112,115,32,116,104,101,32,116,114,97,118,101,114,115,97,108,44,32,97,115,32,115,104,111,119,110,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,119,104,101,114,101,32>>,{code,[],[<<34,102,111,111,34>>]},<<32,97,110,100,32>>,{code,[],[<<123,34,102,111,111,34,125>>]},<<32,97,114,101,32,108,101,102,116,32,117,110,109,111,100,105,102,105,101,100,58>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,123,34,102,111,111,34,125,44,91,49,44,49,93,125,44,123,34,102,111,111,34,44,91,50,44,50,93,125,93,44,10,91,123,97,116,111,109,44,91,97,116,111,109,93,125,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,123,123,34,102,111,111,34,125,44,91,49,93,125,44,123,34,102,111,111,34,44,91,50,93,125,93>>]}]},{p,[],[{code,[],[<<102,114,111,109,95,116,101,114,109>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,99,114,101,97,116,105,110,103,32,97,116,111,109,105,99,32,111,114,32,111,114,100,101,114,101,100,32,115,101,116,115,46,32,84,104,101,32,111,110,108,121,32,112,117,114,112,111,115,101,32,111,102,32,115,117,99,104,32,97,32,115,101,116,32,105,115,32,116,104,97,116,32,111,102,32,108,97,116,101,114,32,98,117,105,108,100,105,110,103,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,44,32,97,115,32,97,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,32,116,104,97,116,32>>,{em,[],[<<100,111>>]},<<32,97,110,121,116,104,105,110,103,32,111,112,101,114,97,116,101,32,111,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,46,32,67,114,101,97,116,105,110,103,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,32,102,114,111,109,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,111,114,100,101,114,101,100,32,115,101,116,115,32,99,97,110,32,98,101,32,116,104,101,32,119,97,121,32,116,111,32,103,111,32,105,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,98,105,103,32,97,110,100,32,111,110,101,32,100,111,101,115,32,110,111,116,32,119,97,110,116,32,116,111,32,119,97,115,116,101,32,104,101,97,112,32,98,121,32,114,101,98,117,105,108,100,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,115,104,111,119,115,32,116,104,97,116,32,97,32,115,101,116,32,99,97,110,32,98,101,32,98,117,105,108,116,32,34,108,97,121,101,114,32,98,121,32,108,97,121,101,114,34,58>>]},{pre,[],[{code,[],[<<49,62,32,65,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,97,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,51,93,41,44,10,80,49,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,123,65,44,83,125,41,44,10,80,50,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,123,98,44,91,54,44,53,44,52,93,125,41,44,10,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,80,49,44,80,50,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,115,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,52,44,53,44,54,93,125,93>>]}]},{p,[],[<<79,116,104,101,114,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,99,114,101,97,116,101,32,115,101,116,115,32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,115,101,116,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,115,101,116,115,47,49>>]}]},<<46,32,83,112,101,99,105,97,108,32,99,97,115,101,115,32,111,102,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,47,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,97,95,102,117,110,99,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,95,102,117,110,99,116,105,111,110,47,49,44,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,109,112,116,121,95,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,109,112,116,121,95,115,101,116,47,48>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,97,109,105,108,121,47,49,44,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,108,97,116,105,111,110,47,49,44,50>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,101,116,47,49,44,50>>]}]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,56,51>>,signature => [{attribute,143,spec,{{from_term,1},[{type,143,bounded_fun,[{type,143,'fun',[{type,143,product,[{var,143,'Term'}]},{var,143,'AnySet'}]},[{type,144,constraint,[{atom,144,is_subtype},[{var,144,'AnySet'},{user_type,144,anyset,[]}]]},{type,145,constraint,[{atom,145,is_subtype},[{var,145,'Term'},{type,145,term,[]}]]}]]}]}}]}},{{function,image,2},[{file,[115,111,102,115,46,101,114,108]},{location,717}],[<<105,109,97,103,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32,115,101,116,32>>,{code,[],[<<83,101,116,49>>]},<<32,117,110,100,101,114,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,50,44,99,125,44,123,51,44,100,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,105,109,97,103,101,40,82,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,97,44,98,44,99,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,51,51>>,signature => [{attribute,717,spec,{{image,2},[{type,717,bounded_fun,[{type,717,'fun',[{type,717,product,[{var,717,'BinRel'},{var,717,'Set1'}]},{var,717,'Set2'}]},[{type,718,constraint,[{atom,718,is_subtype},[{var,718,'BinRel'},{user_type,718,binary_relation,[]}]]},{type,719,constraint,[{atom,719,is_subtype},[{var,719,'Set1'},{user_type,719,a_set,[]}]]},{type,720,constraint,[{atom,720,is_subtype},[{var,720,'Set2'},{user_type,720,a_set,[]}]]}]]}]}}]}},{{function,intersection,1},[{file,[115,111,102,115,46,101,114,108]},{location,563}],[<<105,110,116,101,114,115,101,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]},{p,[],[<<73,110,116,101,114,115,101,99,116,105,110,103,32,97,110,32,101,109,112,116,121,32,115,101,116,32,111,102,32,115,101,116,115,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,52,57>>,signature => [{attribute,563,spec,{{intersection,1},[{type,563,bounded_fun,[{type,563,'fun',[{type,563,product,[{var,563,'SetOfSets'}]},{var,563,'Set'}]},[{type,564,constraint,[{atom,564,is_subtype},[{var,564,'Set'},{user_type,564,a_set,[]}]]},{type,565,constraint,[{atom,565,is_subtype},[{var,565,'SetOfSets'},{user_type,565,set_of_sets,[]}]]}]]}]}}]}},{{function,intersection,2},[{file,[115,111,102,115,46,101,114,108]},{location,388}],[<<105,110,116,101,114,115,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,54,49>>,signature => [{attribute,388,spec,{{intersection,2},[{type,388,bounded_fun,[{type,388,'fun',[{type,388,product,[{var,388,'Set1'},{var,388,'Set2'}]},{var,388,'Set3'}]},[{type,389,constraint,[{atom,389,is_subtype},[{var,389,'Set1'},{user_type,389,a_set,[]}]]},{type,390,constraint,[{atom,390,is_subtype},[{var,390,'Set2'},{user_type,390,a_set,[]}]]},{type,391,constraint,[{atom,391,is_subtype},[{var,391,'Set3'},{user_type,391,a_set,[]}]]}]]}]}}]}},{{function,intersection_of_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1299}],[<<105,110,116,101,114,115,101,99,116,105,111,110,95,111,102,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46>>]},{p,[],[<<73,110,116,101,114,115,101,99,116,105,110,103,32,97,110,32,101,109,112,116,121,32,102,97,109,105,108,121,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,48,44,50,44,52,93,125,44,123,98,44,91,48,44,49,44,50,93,125,44,123,99,44,91,50,44,51,93,125,93,41,44,10,83,32,61,32,115,111,102,115,58,105,110,116,101,114,115,101,99,116,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,50,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,55,49>>,signature => [{attribute,1299,spec,{{intersection_of_family,1},[{type,1299,bounded_fun,[{type,1299,'fun',[{type,1299,product,[{var,1299,'Family'}]},{var,1299,'Set'}]},[{type,1300,constraint,[{atom,1300,is_subtype},[{var,1300,'Family'},{user_type,1300,family,[]}]]},{type,1301,constraint,[{atom,1301,is_subtype},[{var,1301,'Set'},{user_type,1301,a_set,[]}]]}]]}]}}]}},{{function,inverse,1},[{file,[115,111,102,115,46,101,114,108]},{location,872}],[<<105,110,118,101,114,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,118,101,114,115,101>>]},<<32,111,102,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70,117,110,99,116,105,111,110,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,105,110,118,101,114,115,101,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,51,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,56,56>>,signature => [{attribute,872,spec,{{inverse,1},[{type,872,bounded_fun,[{type,872,'fun',[{type,872,product,[{var,872,'Function1'}]},{var,872,'Function2'}]},[{type,873,constraint,[{atom,873,is_subtype},[{var,873,'Function1'},{user_type,873,a_function,[]}]]},{type,874,constraint,[{atom,874,is_subtype},[{var,874,'Function2'},{user_type,874,a_function,[]}]]}]]}]}}]}},{{function,inverse_image,2},[{file,[115,111,102,115,46,101,114,108]},{location,734}],[<<105,110,118,101,114,115,101,95,105,109,97,103,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,118,101,114,115,101,95,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,118,101,114,115,101,32,105,109,97,103,101>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,117,110,100,101,114,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,50,44,99,125,44,123,51,44,100,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,99,44,100,44,101,93,41,44,10,83,50,32,61,32,115,111,102,115,58,105,110,118,101,114,115,101,95,105,109,97,103,101,40,82,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,50,44,51,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,48,50>>,signature => [{attribute,734,spec,{{inverse_image,2},[{type,734,bounded_fun,[{type,734,'fun',[{type,734,product,[{var,734,'BinRel'},{var,734,'Set1'}]},{var,734,'Set2'}]},[{type,735,constraint,[{atom,735,is_subtype},[{var,735,'BinRel'},{user_type,735,binary_relation,[]}]]},{type,736,constraint,[{atom,736,is_subtype},[{var,736,'Set1'},{user_type,736,a_set,[]}]]},{type,737,constraint,[{atom,737,is_subtype},[{var,737,'Set2'},{user_type,737,a_set,[]}]]}]]}]}}]}},{{function,is_a_function,1},[{file,[115,111,102,115,46,101,114,108]},{location,812}],[<<105,115,95,97,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<32,111,114,32,116,104,101,32,117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,49,57>>,signature => [{attribute,812,spec,{{is_a_function,1},[{type,812,bounded_fun,[{type,812,'fun',[{type,812,product,[{var,812,'BinRel'}]},{var,812,'Bool'}]},[{type,813,constraint,[{atom,813,is_subtype},[{var,813,'Bool'},{type,813,boolean,[]}]]},{type,814,constraint,[{atom,814,is_subtype},[{var,814,'BinRel'},{user_type,814,binary_relation,[]}]]}]]}]}}]}},{{function,is_disjoint,2},[{file,[115,111,102,115,46,101,114,108]},{location,535}],[<<105,115,95,100,105,115,106,111,105,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,115,106,111,105,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,115,106,111,105,110,116>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,50,57>>,signature => [{attribute,535,spec,{{is_disjoint,2},[{type,535,bounded_fun,[{type,535,'fun',[{type,535,product,[{var,535,'Set1'},{var,535,'Set2'}]},{var,535,'Bool'}]},[{type,536,constraint,[{atom,536,is_subtype},[{var,536,'Bool'},{type,536,boolean,[]}]]},{type,537,constraint,[{atom,537,is_subtype},[{var,537,'Set1'},{user_type,537,a_set,[]}]]},{type,538,constraint,[{atom,538,is_subtype},[{var,538,'Set2'},{user_type,538,a_set,[]}]]}]]}]}}]}},{{function,is_empty_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,527}],[<<105,115,95,101,109,112,116,121,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,105,115,32,97,110,32,101,109,112,116,121,32,117,110,111,114,100,101,114,101,100,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,52,48>>,signature => [{attribute,527,spec,{{is_empty_set,1},[{type,527,bounded_fun,[{type,527,'fun',[{type,527,product,[{var,527,'AnySet'}]},{var,527,'Bool'}]},[{type,528,constraint,[{atom,528,is_subtype},[{var,528,'AnySet'},{user_type,528,anyset,[]}]]},{type,529,constraint,[{atom,529,is_subtype},[{var,529,'Bool'},{type,529,boolean,[]}]]}]]}]}}]}},{{function,is_equal,2},[{file,[115,111,102,115,46,101,114,108]},{location,480}],[<<105,115,95,101,113,117,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<65,110,121,83,101,116,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,113,117,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,113,117,97,108>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,115,104,111,119,115,32,116,104,97,116,32>>,{code,[],[<<61,61,47,50>>]},<<32,105,115,32,117,115,101,100,32,119,104,101,110,32,99,111,109,112,97,114,105,110,103,32,115,101,116,115,32,102,111,114,32,101,113,117,97,108,105,116,121,58>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,46,48,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,49,93,41,44,10,115,111,102,115,58,105,115,95,101,113,117,97,108,40,83,49,44,32,83,50,41,46,10,116,114,117,101>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,52,57>>,signature => [{attribute,480,spec,{{is_equal,2},[{type,480,bounded_fun,[{type,480,'fun',[{type,480,product,[{var,480,'AnySet1'},{var,480,'AnySet2'}]},{var,480,'Bool'}]},[{type,481,constraint,[{atom,481,is_subtype},[{var,481,'AnySet1'},{user_type,481,anyset,[]}]]},{type,482,constraint,[{atom,482,is_subtype},[{var,482,'AnySet2'},{user_type,482,anyset,[]}]]},{type,483,constraint,[{atom,483,is_subtype},[{var,483,'Bool'},{type,483,boolean,[]}]]}]]}]}}]}},{{function,is_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,519}],[<<105,115,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,105,115,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,105,115,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,111,114,32,97,110,32,97,116,111,109,105,99,32,115,101,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,54,54>>,signature => [{attribute,519,spec,{{is_set,1},[{type,519,bounded_fun,[{type,519,'fun',[{type,519,product,[{var,519,'AnySet'}]},{var,519,'Bool'}]},[{type,520,constraint,[{atom,520,is_subtype},[{var,520,'AnySet'},{user_type,520,anyset,[]}]]},{type,521,constraint,[{atom,521,is_subtype},[{var,521,'Bool'},{type,521,boolean,[]}]]}]]}]}}]}},{{function,is_sofs_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,509}],[<<105,115,95,115,111,102,115,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<44,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,44,32,111,114,32,97,110,32,97,116,111,109,105,99,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,55,55>>,signature => [{attribute,509,spec,{{is_sofs_set,1},[{type,509,bounded_fun,[{type,509,'fun',[{type,509,product,[{var,509,'Term'}]},{var,509,'Bool'}]},[{type,510,constraint,[{atom,510,is_subtype},[{var,510,'Bool'},{type,510,boolean,[]}]]},{type,511,constraint,[{atom,511,is_subtype},[{var,511,'Term'},{type,511,term,[]}]]}]]}]}}]}},{{function,is_subset,2},[{file,[115,111,102,115,46,101,114,108]},{location,499}],[<<105,115,95,115,117,98,115,101,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,117,98,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,117,98,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,50>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,56,55>>,signature => [{attribute,499,spec,{{is_subset,2},[{type,499,bounded_fun,[{type,499,'fun',[{type,499,product,[{var,499,'Set1'},{var,499,'Set2'}]},{var,499,'Bool'}]},[{type,500,constraint,[{atom,500,is_subtype},[{var,500,'Bool'},{type,500,boolean,[]}]]},{type,501,constraint,[{atom,501,is_subtype},[{var,501,'Set1'},{user_type,501,a_set,[]}]]},{type,502,constraint,[{atom,502,is_subtype},[{var,502,'Set2'},{user_type,502,a_set,[]}]]}]]}]}}]}},{{function,is_type,1},[{file,[115,111,102,115,46,101,114,108]},{location,183}],[<<105,115,95,116,121,112,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,101,114,109,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,57,55>>,signature => [{attribute,183,spec,{{is_type,1},[{type,183,bounded_fun,[{type,183,'fun',[{type,183,product,[{var,183,'Term'}]},{var,183,'Bool'}]},[{type,184,constraint,[{atom,184,is_subtype},[{var,184,'Bool'},{type,184,boolean,[]}]]},{type,185,constraint,[{atom,185,is_subtype},[{var,185,'Term'},{type,185,term,[]}]]}]]}]}}]}},{{function,join,4},[{file,[115,111,102,115,46,101,114,108]},{location,1206}],[<<106,111,105,110,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,110,97,116,117,114,97,108,95,106,111,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,97,116,117,114,97,108,32,106,111,105,110>>]},<<32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,115,32>>,{code,[],[<<82,101,108,97,116,105,111,110,49>>]},<<32,97,110,100,32>>,{code,[],[<<82,101,108,97,116,105,111,110,50>>]},<<32,111,110,32,99,111,111,114,100,105,110,97,116,101,115,32>>,{code,[],[<<73>>]},<<32,97,110,100,32>>,{code,[],[<<74>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,120,44,49,125,44,123,98,44,121,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,102,44,103,125,44,123,49,44,104,44,105,125,44,123,50,44,51,44,52,125,93,41,44,10,74,32,61,32,115,111,102,115,58,106,111,105,110,40,82,49,44,32,51,44,32,82,50,44,32,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,74,41,46,10,91,123,97,44,120,44,49,44,102,44,103,125,44,123,97,44,120,44,49,44,104,44,105,125,44,123,98,44,121,44,50,44,51,44,52,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,48,54>>,signature => [{attribute,1206,spec,{{join,4},[{type,1206,bounded_fun,[{type,1206,'fun',[{type,1206,product,[{var,1206,'Relation1'},{var,1206,'I'},{var,1206,'Relation2'},{var,1206,'J'}]},{var,1206,'Relation3'}]},[{type,1207,constraint,[{atom,1207,is_subtype},[{var,1207,'Relation1'},{user_type,1207,relation,[]}]]},{type,1208,constraint,[{atom,1208,is_subtype},[{var,1208,'Relation2'},{user_type,1208,relation,[]}]]},{type,1209,constraint,[{atom,1209,is_subtype},[{var,1209,'Relation3'},{user_type,1209,relation,[]}]]},{type,1210,constraint,[{atom,1210,is_subtype},[{var,1210,'I'},{type,1210,pos_integer,[]}]]},{type,1211,constraint,[{atom,1211,is_subtype},[{var,1211,'J'},{type,1211,pos_integer,[]}]]}]]}]}}]}},{{function,multiple_relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,1190}],[<<109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<84,117,112,108,101,79,102,66,105,110,82,101,108,115>>]},<<32,105,115,32,97,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32,123,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,125,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,117,108,116,105,112,108,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,105,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,105,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,51,125,93,41,44,10,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,98,125,44,123,98,44,99,125,44,123,99,44,97,125,93,41,44,10,77,80,32,61,32,115,111,102,115,58,109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,123,82,105,44,32,82,105,125,44,32,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,114,97,110,103,101,40,77,80,41,41,46,10,91,123,49,44,50,125,44,123,50,44,51,125,44,123,51,44,49,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,50,51>>,signature => [{attribute,1190,spec,{{multiple_relative_product,2},[{type,1190,bounded_fun,[{type,1190,'fun',[{type,1190,product,[{var,1190,'TupleOfBinRels'},{var,1190,'BinRel1'}]},{var,1190,'BinRel2'}]},[{type,1191,constraint,[{atom,1191,is_subtype},[{var,1191,'TupleOfBinRels'},{user_type,1191,tuple_of,[{var,1191,'BinRel'}]}]]},{type,1192,constraint,[{atom,1192,is_subtype},[{var,1192,'BinRel'},{user_type,1192,binary_relation,[]}]]},{type,1193,constraint,[{atom,1193,is_subtype},[{var,1193,'BinRel1'},{user_type,1193,binary_relation,[]}]]},{type,1194,constraint,[{atom,1194,is_subtype},[{var,1194,'BinRel2'},{user_type,1194,binary_relation,[]}]]}]]}]}}]}},{{function,no_elements,1},[{file,[115,111,102,115,46,101,114,108]},{location,349}],[<<110,111,95,101,108,101,109,101,110,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,52,52>>,signature => [{attribute,349,spec,{{no_elements,1},[{type,349,bounded_fun,[{type,349,'fun',[{type,349,product,[{var,349,'ASet'}]},{var,349,'NoElements'}]},[{type,350,constraint,[{atom,350,is_subtype},[{var,350,'ASet'},{type,350,union,[{user_type,350,a_set,[]},{user_type,350,ordset,[]}]}]]},{type,351,constraint,[{atom,351,is_subtype},[{var,351,'NoElements'},{type,351,non_neg_integer,[]}]]}]]}]}}]}},{{function,partition,1},[{file,[115,111,102,115,46,101,114,108]},{location,1091}],[<<112,97,114,116,105,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,121,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32,115,97,109,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,101,116,115,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,44,98,44,99,93,44,91,100,44,101,44,102,93,44,91,103,44,104,44,105,93,93,41,44,10,83,101,116,115,50,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,98,44,99,44,100,93,44,91,101,44,102,44,103,93,44,91,104,44,105,44,106,93,93,41,44,10,80,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,115,111,102,115,58,117,110,105,111,110,40,83,101,116,115,49,44,32,83,101,116,115,50,41,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,91,97,93,44,91,98,44,99,93,44,91,100,93,44,91,101,44,102,93,44,91,103,93,44,91,104,44,105,93,44,91,106,93,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,53,51>>,signature => [{attribute,1091,spec,{{partition,1},[{type,1091,bounded_fun,[{type,1091,'fun',[{type,1091,product,[{var,1091,'SetOfSets'}]},{var,1091,'Partition'}]},[{type,1092,constraint,[{atom,1092,is_subtype},[{var,1092,'SetOfSets'},{user_type,1092,set_of_sets,[]}]]},{type,1093,constraint,[{atom,1093,is_subtype},[{var,1093,'Partition'},{user_type,1093,a_set,[]}]]}]]}]}}]}},{{function,partition,2},[{file,[115,111,102,115,46,101,114,108]},{location,1099}],[<<112,97,114,116,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,32,114,101,115,117,108,116,115,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,97,114,101,32,101,113,117,97,108,46>>]},{pre,[],[{code,[],[<<49,62,32,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,93,44,91,98,93,44,91,99,44,100,93,44,91,101,44,102,93,93,41,44,10,83,101,116,70,117,110,32,61,32,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,115,111,102,115,58,110,111,95,101,108,101,109,101,110,116,115,40,83,41,41,32,101,110,100,44,10,80,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,83,101,116,70,117,110,44,32,83,115,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,91,91,97,93,44,91,98,93,93,44,91,91,99,44,100,93,44,91,101,44,102,93,93,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,55,48>>,signature => [{attribute,1099,spec,{{partition,2},[{type,1099,bounded_fun,[{type,1099,'fun',[{type,1099,product,[{var,1099,'SetFun'},{var,1099,'Set'}]},{var,1099,'Partition'}]},[{type,1100,constraint,[{atom,1100,is_subtype},[{var,1100,'SetFun'},{user_type,1100,set_fun,[]}]]},{type,1101,constraint,[{atom,1101,is_subtype},[{var,1101,'Partition'},{user_type,1101,a_set,[]}]]},{type,1102,constraint,[{atom,1102,is_subtype},[{var,1102,'Set'},{user_type,1102,a_set,[]}]]}]]}]}}]}},{{function,partition,3},[{file,[115,111,102,115,46,101,114,108]},{location,1118}],[<<112,97,114,116,105,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,97,105,114,32,111,102,32,115,101,116,115,32,116,104,97,116,44,32,114,101,103,97,114,100,101,100,32,97,115,32,99,111,110,115,116,105,116,117,116,105,110,103,32,97,32,115,101,116,44,32,102,111,114,109,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<46,32,73,102,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,103,105,118,101,115,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<44,32,116,104,101,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,51>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,52>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,52,44,54,93,41,44,10,123,82,50,44,82,51,125,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,49,44,32,82,49,44,32,83,41,44,10,123,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,44,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,125,46,10,123,91,123,50,44,98,125,93,44,91,123,49,44,97,125,44,123,51,44,99,125,93,125>>]}]},{p,[],[{code,[],[<<112,97,114,116,105,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<123,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,44,32,100,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,125>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,56,54>>,signature => [{attribute,1118,spec,{{partition,3},[{type,1118,bounded_fun,[{type,1118,'fun',[{type,1118,product,[{var,1118,'SetFun'},{var,1118,'Set1'},{var,1118,'Set2'}]},{type,1118,tuple,[{var,1118,'Set3'},{var,1118,'Set4'}]}]},[{type,1119,constraint,[{atom,1119,is_subtype},[{var,1119,'SetFun'},{user_type,1119,set_fun,[]}]]},{type,1120,constraint,[{atom,1120,is_subtype},[{var,1120,'Set1'},{user_type,1120,a_set,[]}]]},{type,1121,constraint,[{atom,1121,is_subtype},[{var,1121,'Set2'},{user_type,1121,a_set,[]}]]},{type,1122,constraint,[{atom,1122,is_subtype},[{var,1122,'Set3'},{user_type,1122,a_set,[]}]]},{type,1123,constraint,[{atom,1123,is_subtype},[{var,1123,'Set4'},{user_type,1123,a_set,[]}]]}]]}]}}]}},{{function,partition_family,2},[{file,[115,111,102,115,46,101,114,108]},{location,1404}],[<<112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,119,104,101,114,101,32,116,104,101,32,105,110,100,101,120,101,100,32,115,101,116,32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,32,114,101,115,117,108,116,115,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,105,46,32,84,104,105,115,32,105,32,105,115,32,116,104,101,32,105,110,100,101,120,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,109,97,112,115,32,111,110,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,113,117,105,118,97,108,101,110,99,101,95,99,108,97,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,97,44,97,44,97,125,44,123,97,44,97,44,98,44,98,125,44,123,97,44,98,44,98,44,98,125,93,41,44,10,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,44,67,44,95,125,41,32,45,62,32,123,65,44,67,125,32,101,110,100,125,44,10,70,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,40,83,101,116,70,117,110,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,123,97,44,97,125,44,91,123,97,44,97,44,97,44,97,125,93,125,44,123,123,97,44,98,125,44,91,123,97,44,97,44,98,44,98,125,44,123,97,44,98,44,98,44,98,125,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,48,57>>,signature => [{attribute,1404,spec,{{partition_family,2},[{type,1404,bounded_fun,[{type,1404,'fun',[{type,1404,product,[{var,1404,'SetFun'},{var,1404,'Set'}]},{var,1404,'Family'}]},[{type,1405,constraint,[{atom,1405,is_subtype},[{var,1405,'Family'},{user_type,1405,family,[]}]]},{type,1406,constraint,[{atom,1406,is_subtype},[{var,1406,'SetFun'},{user_type,1406,set_fun,[]}]]},{type,1407,constraint,[{atom,1407,is_subtype},[{var,1407,'Set'},{user_type,1407,a_set,[]}]]}]]}]}}]}},{{function,product,1},[{file,[115,111,102,115,46,101,114,108]},{location,444}],[<<112,114,111,100,117,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32,111,102,32,115,101,116,115,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46,32,73,102,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<82,101,108,97,116,105,111,110>>]},<<44,32,116,104,101,110,32,120,91,105,93,32,105,115,32,100,114,97,119,110,32,102,114,111,109,32,101,108,101,109,101,110,116,32,105,32,111,102,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,51,32,61,32,115,111,102,115,58,115,101,116,40,91,120,44,121,93,41,44,10,80,51,32,61,32,115,111,102,115,58,112,114,111,100,117,99,116,40,123,83,49,44,83,50,44,83,51,125,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,51,41,46,10,91,123,97,44,49,44,120,125,44,123,97,44,49,44,121,125,44,123,97,44,50,44,120,125,44,123,97,44,50,44,121,125,44,123,98,44,49,44,120,125,44,123,98,44,49,44,121,125,44,123,98,44,50,44,120,125,44,123,98,44,50,44,121,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,51,48>>,signature => [{attribute,444,spec,{{product,1},[{type,444,bounded_fun,[{type,444,'fun',[{type,444,product,[{var,444,'TupleOfSets'}]},{var,444,'Relation'}]},[{type,445,constraint,[{atom,445,is_subtype},[{var,445,'Relation'},{user_type,445,relation,[]}]]},{type,446,constraint,[{atom,446,is_subtype},[{var,446,'TupleOfSets'},{user_type,446,tuple_of,[{user_type,446,a_set,[]}]}]]}]]}]}}]}},{{function,product,2},[{file,[115,111,102,115,46,101,114,108]},{location,430}],[<<112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,82,32,61,32,115,111,102,115,58,112,114,111,100,117,99,116,40,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,97,125,44,123,50,44,98,125,93>>]}]},{p,[],[{code,[],[<<112,114,111,100,117,99,116,40,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<112,114,111,100,117,99,116,40,123,83,49,44,194,160,83,50,125,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,52,57>>,signature => [{attribute,430,spec,{{product,2},[{type,430,bounded_fun,[{type,430,'fun',[{type,430,product,[{var,430,'Set1'},{var,430,'Set2'}]},{var,430,'BinRel'}]},[{type,431,constraint,[{atom,431,is_subtype},[{var,431,'BinRel'},{user_type,431,binary_relation,[]}]]},{type,432,constraint,[{atom,432,is_subtype},[{var,432,'Set1'},{user_type,432,a_set,[]}]]},{type,433,constraint,[{atom,433,is_subtype},[{var,433,'Set2'},{user_type,433,a_set,[]}]]}]]}]}}]}},{{function,projection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1029}],[<<112,114,111,106,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,101,116,32,99,114,101,97,116,101,100,32,98,121,32,115,117,98,115,116,105,116,117,116,105,110,103,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,98,121,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,105,115,32,97,32,110,117,109,98,101,114,32,105,194,160,62,61,194,160,49,32,97,110,100,32>>,{code,[],[<<83,101,116,49>>]},<<32,105,115,32,97,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,115,101,116,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,114,111,106,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,114,111,106,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,111,110,116,111,32,99,111,111,114,100,105,110,97,116,101,32,105,46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,97,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,50,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,97,44,98,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,54,55>>,signature => [{attribute,1029,spec,{{projection,2},[{type,1029,bounded_fun,[{type,1029,'fun',[{type,1029,product,[{var,1029,'SetFun'},{var,1029,'Set1'}]},{var,1029,'Set2'}]},[{type,1030,constraint,[{atom,1030,is_subtype},[{var,1030,'SetFun'},{user_type,1030,set_fun,[]}]]},{type,1031,constraint,[{atom,1031,is_subtype},[{var,1031,'Set1'},{user_type,1031,a_set,[]}]]},{type,1032,constraint,[{atom,1032,is_subtype},[{var,1032,'Set2'},{user_type,1032,a_set,[]}]]}]]}]}}]}},{{function,range,1},[{file,[115,111,102,115,46,101,114,108]},{location,622}],[<<114,97,110,103,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,97,110,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,97,110,103,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,114,97,110,103,101,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,97,44,98,44,99,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,56,54>>,signature => [{attribute,622,spec,{{range,1},[{type,622,bounded_fun,[{type,622,'fun',[{type,622,product,[{var,622,'BinRel'}]},{var,622,'Set'}]},[{type,623,constraint,[{atom,623,is_subtype},[{var,623,'BinRel'},{user_type,623,binary_relation,[]}]]},{type,624,constraint,[{atom,624,is_subtype},[{var,624,'Set'},{user_type,624,a_set,[]}]]}]]}]}}]}},{{function,relation,2},[{file,[115,111,102,115,46,101,114,108]},{location,255}],[<<114,101,108,97,116,105,111,110,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,48,48>>,equiv => {function,relation,1},signature => [{attribute,255,spec,{{relation,2},[{type,255,bounded_fun,[{type,255,'fun',[{type,255,product,[{var,255,'Tuples'},{var,255,'Type'}]},{var,255,'Relation'}]},[{type,256,constraint,[{atom,256,is_subtype},[{var,256,'N'},{type,256,integer,[]}]]},{type,257,constraint,[{atom,257,is_subtype},[{var,257,'Type'},{type,257,union,[{var,257,'N'},{user_type,257,type,[]}]}]]},{type,258,constraint,[{atom,258,is_subtype},[{var,258,'Relation'},{user_type,258,relation,[]}]]},{type,259,constraint,[{atom,259,is_subtype},[{var,259,'Tuples'},{type,259,list,[{type,259,tuple,any}]}]]}]]}]}}]}},{{function,relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,243}],[<<114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,111,110>>]},<<46,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,82,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,82,44,194,160,84,41>>]},<<44,32,105,102,32,84,32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,114,101,108,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,78,44,32,116,104,101,110,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,46,46,46,44,194,160,97,116,111,109,125,93,41>>]},<<44,32,119,104,101,114,101,32,116,104,101,32,116,117,112,108,101,32,115,105,122,101,32,105,115,32,78,44,32,105,115,32,117,115,101,100,32,97,115,32,116,121,112,101,32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,46,32,73,102,32,110,111,32,116,121,112,101,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,102,105,114,115,116,32,116,117,112,108,101,32,111,102,32>>,{code,[],[<<84,117,112,108,101,115>>]},<<32,105,115,32,117,115,101,100,32,105,102,32,116,104,101,114,101,32,105,115,32,115,117,99,104,32,97,32,116,117,112,108,101,46,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,91,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,91,93,44,194,160,50,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,48,48>>,signature => [{attribute,243,spec,{{relation,1},[{type,243,bounded_fun,[{type,243,'fun',[{type,243,product,[{var,243,'Tuples'}]},{var,243,'Relation'}]},[{type,244,constraint,[{atom,244,is_subtype},[{var,244,'Relation'},{user_type,244,relation,[]}]]},{type,245,constraint,[{atom,245,is_subtype},[{var,245,'Tuples'},{type,245,list,[{type,245,tuple,any}]}]]}]]}]}}]}},{{function,relation_to_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,600}],[<<114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,101,113,117,97,108,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,105,32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,98,44,49,125,44,123,99,44,50,125,44,123,99,44,51,125,93,41,44,10,70,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,98,44,91,49,93,125,44,123,99,44,91,50,44,51,93,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,49,57>>,signature => [{attribute,600,spec,{{relation_to_family,1},[{type,600,bounded_fun,[{type,600,'fun',[{type,600,product,[{var,600,'BinRel'}]},{var,600,'Family'}]},[{type,601,constraint,[{atom,601,is_subtype},[{var,601,'Family'},{user_type,601,family,[]}]]},{type,602,constraint,[{atom,602,is_subtype},[{var,602,'BinRel'},{user_type,602,binary_relation,[]}]]}]]}]}}]}},{{function,relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,657}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,51,55>>,equiv => {function,relative_product,1},signature => [{attribute,657,spec,{{relative_product,2},[{type,657,bounded_fun,[{type,657,'fun',[{type,657,product,[{var,657,'ListOfBinRels'},{var,657,'BinRel1'}]},{var,657,'BinRel2'}]},[{type,658,constraint,[{atom,658,is_subtype},[{var,658,'ListOfBinRels'},{type,658,nonempty_list,[{var,658,'BinRel'}]}]]},{type,659,constraint,[{atom,659,is_subtype},[{var,659,'BinRel'},{user_type,659,binary_relation,[]}]]},{type,660,constraint,[{atom,660,is_subtype},[{var,660,'BinRel1'},{user_type,660,binary_relation,[]}]]},{type,661,constraint,[{atom,661,is_subtype},[{var,661,'BinRel2'},{user_type,661,binary_relation,[]}]]}]]}]}}]}},{{function,relative_product,1},[{file,[115,111,102,115,46,101,114,108]},{location,641}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<76,105,115,116,79,102,66,105,110,82,101,108,115>>]},<<32,105,115,32,97,32,110,111,110,45,101,109,112,116,121,32,108,105,115,116,32,91,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,93,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,117,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,105,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,111,109,105,116,116,101,100,44,32,116,104,101,32,114,101,108,97,116,105,111,110,32,111,102,32,101,113,117,97,108,105,116,121,32,98,101,116,119,101,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,114,97,110,103,101,115,32,111,102,32,82,91,105,93,44,32,114,97,110,103,101,194,160,82,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,114,97,110,103,101,194,160,82,91,110,93,44,32,105,115,32,117,115,101,100,32,105,110,115,116,101,97,100,32,40,105,110,116,117,105,116,105,118,101,108,121,44,32,110,111,116,104,105,110,103,32,105,115,32,34,108,111,115,116,34,41,46>>]},{pre,[],[{code,[],[<<49,62,32,84,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,97,97,125,44,123,50,44,98,125,93,41,44,10,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,117,125,44,123,50,44,118,125,44,123,51,44,99,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,91,84,82,44,32,82,49,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,123,97,44,117,125,125,44,123,49,44,123,97,97,44,117,125,125,44,123,50,44,123,98,44,118,125,125,93>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,91,82,49,93,44,194,160,82,50,41>>]},<<32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,82,49,44,194,160,82,50,41>>]},<<59,32,116,104,101,32,108,105,115,116,32,111,102,32,111,110,101,32,101,108,101,109,101,110,116,32,105,115,32,110,111,116,32,105,100,101,110,116,105,102,105,101,100,32,119,105,116,104,32,116,104,101,32,101,108,101,109,101,110,116,32,105,116,115,101,108,102,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,51,55>>,signature => [{attribute,641,spec,{{relative_product,1},[{type,641,bounded_fun,[{type,641,'fun',[{type,641,product,[{var,641,'ListOfBinRels'}]},{var,641,'BinRel2'}]},[{type,642,constraint,[{atom,642,is_subtype},[{var,642,'ListOfBinRels'},{type,642,nonempty_list,[{var,642,'BinRel'}]}]]},{type,643,constraint,[{atom,643,is_subtype},[{var,643,'BinRel'},{user_type,643,binary_relation,[]}]]},{type,644,constraint,[{atom,644,is_subtype},[{var,644,'BinRel2'},{user_type,644,binary_relation,[]}]]}]]}]}}]}},{{function,relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,657}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,54,56>>,signature => [{attribute,657,spec,{{relative_product,2},[{type,662,bounded_fun,[{type,662,'fun',[{type,662,product,[{var,662,'BinRel1'},{var,662,'BinRel2'}]},{var,662,'BinRel3'}]},[{type,663,constraint,[{atom,663,is_subtype},[{var,663,'BinRel1'},{user_type,663,binary_relation,[]}]]},{type,664,constraint,[{atom,664,is_subtype},[{var,664,'BinRel2'},{user_type,664,binary_relation,[]}]]},{type,665,constraint,[{atom,665,is_subtype},[{var,665,'BinRel3'},{user_type,665,binary_relation,[]}]]}]]}]}}]}},{{function,relative_product1,2},[{file,[115,111,102,115,46,101,114,108]},{location,685}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,97,97,125,44,123,50,44,98,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,117,125,44,123,50,44,118,125,44,123,51,44,99,125,93,41,44,10,82,51,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,82,49,44,32,82,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,46,10,91,123,97,44,117,125,44,123,97,97,44,117,125,44,123,98,44,118,125,93>>]}]},{p,[],[{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,82,49,44,194,160,82,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,99,111,110,118,101,114,115,101,40,82,49,41,44,194,160,82,50,41>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,55,57>>,signature => [{attribute,685,spec,{{relative_product1,2},[{type,685,bounded_fun,[{type,685,'fun',[{type,685,product,[{var,685,'BinRel1'},{var,685,'BinRel2'}]},{var,685,'BinRel3'}]},[{type,686,constraint,[{atom,686,is_subtype},[{var,686,'BinRel1'},{user_type,686,binary_relation,[]}]]},{type,687,constraint,[{atom,687,is_subtype},[{var,687,'BinRel2'},{user_type,687,binary_relation,[]}]]},{type,688,constraint,[{atom,688,is_subtype},[{var,688,'BinRel3'},{user_type,688,binary_relation,[]}]]}]]}]}}]}},{{function,restriction,2},[{file,[115,111,102,115,46,101,114,108]},{location,826}],[<<114,101,115,116,114,105,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,116,111,32>>,{code,[],[<<83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,52,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,115,116,114,105,99,116,105,111,110,40,82,49,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,97,125,44,123,50,44,98,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,48,48>>,signature => [{attribute,826,spec,{{restriction,2},[{type,826,bounded_fun,[{type,826,'fun',[{type,826,product,[{var,826,'BinRel1'},{var,826,'Set'}]},{var,826,'BinRel2'}]},[{type,827,constraint,[{atom,827,is_subtype},[{var,827,'BinRel1'},{user_type,827,binary_relation,[]}]]},{type,828,constraint,[{atom,828,is_subtype},[{var,828,'BinRel2'},{user_type,828,binary_relation,[]}]]},{type,829,constraint,[{atom,829,is_subtype},[{var,829,'Set'},{user_type,829,a_set,[]}]]}]]}]}}]}},{{function,restriction,3},[{file,[115,111,102,115,46,101,114,108]},{location,892}],[<<114,101,115,116,114,105,99,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,103,105,118,101,115,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,98,44,99,44,100,93,41,44,10,83,51,32,61,32,115,111,102,115,58,114,101,115,116,114,105,99,116,105,111,110,40,50,44,32,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,51,41,46,10,91,123,50,44,98,125,44,123,51,44,99,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,49,54>>,signature => [{attribute,892,spec,{{restriction,3},[{type,892,bounded_fun,[{type,892,'fun',[{type,892,product,[{var,892,'SetFun'},{var,892,'Set1'},{var,892,'Set2'}]},{var,892,'Set3'}]},[{type,893,constraint,[{atom,893,is_subtype},[{var,893,'SetFun'},{user_type,893,set_fun,[]}]]},{type,894,constraint,[{atom,894,is_subtype},[{var,894,'Set1'},{user_type,894,a_set,[]}]]},{type,895,constraint,[{atom,895,is_subtype},[{var,895,'Set2'},{user_type,895,a_set,[]}]]},{type,896,constraint,[{atom,896,is_subtype},[{var,896,'Set3'},{user_type,896,a_set,[]}]]}]]}]}}]}},{{function,set,2},[{file,[115,111,102,115,46,101,114,108]},{location,204}],[<<115,101,116,47,50>>],#{},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,51,50>>,equiv => {function,set,1},signature => [{attribute,204,spec,{{set,2},[{type,204,bounded_fun,[{type,204,'fun',[{type,204,product,[{var,204,'Terms'},{var,204,'Type'}]},{var,204,'Set'}]},[{type,205,constraint,[{atom,205,is_subtype},[{var,205,'Set'},{user_type,205,a_set,[]}]]},{type,206,constraint,[{atom,206,is_subtype},[{var,206,'Terms'},{type,206,list,[{type,206,term,[]}]}]]},{type,207,constraint,[{atom,207,is_subtype},[{var,207,'Type'},{user_type,207,type,[]}]]}]]}]}}]}},{{function,set,1},[{file,[115,111,102,115,46,101,114,108]},{location,195}],[<<115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<46,32>>,{code,[],[<<115,101,116,40,76,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,76,44,194,160,84,41>>]},<<44,32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,97,116,111,109,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,115,101,116,32,116,121,112,101,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,51,50>>,signature => [{attribute,195,spec,{{set,1},[{type,195,bounded_fun,[{type,195,'fun',[{type,195,product,[{var,195,'Terms'}]},{var,195,'Set'}]},[{type,196,constraint,[{atom,196,is_subtype},[{var,196,'Set'},{user_type,196,a_set,[]}]]},{type,197,constraint,[{atom,197,is_subtype},[{var,197,'Terms'},{type,197,list,[{type,197,term,[]}]}]]}]]}]}}]}},{{function,specification,2},[{file,[115,111,102,115,46,101,114,108]},{location,359}],[<<115,112,101,99,105,102,105,99,97,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,101,116,32,99,111,110,116,97,105,110,105,110,103,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,102,111,114,32,119,104,105,99,104,32>>,{code,[],[<<70,117,110>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,50,125>>]},<<44,32>>,{code,[],[<<70,117,110,50>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,101,97,99,104,32,101,108,101,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,120,44,49,125,44,123,120,44,50,125,44,123,121,44,51,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,82,49,44,82,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,112,101,99,105,102,105,99,97,116,105,111,110,40,102,117,110,32,115,111,102,115,58,105,115,95,97,95,102,117,110,99,116,105,111,110,47,49,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,91,123,97,44,49,125,44,123,98,44,50,125,93,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,52,53>>,signature => [{attribute,359,spec,{{specification,2},[{type,359,bounded_fun,[{type,359,'fun',[{type,359,product,[{var,359,'Fun'},{var,359,'Set1'}]},{var,359,'Set2'}]},[{type,360,constraint,[{atom,360,is_subtype},[{var,360,'Fun'},{user_type,360,spec_fun,[]}]]},{type,361,constraint,[{atom,361,is_subtype},[{var,361,'Set1'},{user_type,361,a_set,[]}]]},{type,362,constraint,[{atom,362,is_subtype},[{var,362,'Set2'},{user_type,362,a_set,[]}]]}]]}]}}]}},{{function,strict_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,752}],[<<115,116,114,105,99,116,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,116,114,105,99,116,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,114,105,99,116,32,114,101,108,97,116,105,111,110>>]},<<32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,49,125,44,123,49,44,50,125,44,123,50,44,49,125,44,123,50,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,115,116,114,105,99,116,95,114,101,108,97,116,105,111,110,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,50,125,44,123,50,44,49,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,54,54>>,signature => [{attribute,752,spec,{{strict_relation,1},[{type,752,bounded_fun,[{type,752,'fun',[{type,752,product,[{var,752,'BinRel1'}]},{var,752,'BinRel2'}]},[{type,753,constraint,[{atom,753,is_subtype},[{var,753,'BinRel1'},{user_type,753,binary_relation,[]}]]},{type,754,constraint,[{atom,754,is_subtype},[{var,754,'BinRel2'},{user_type,754,binary_relation,[]}]]}]]}]}}]}},{{function,substitution,2},[{file,[115,111,102,115,46,101,114,108]},{location,1048}],[<<115,117,98,115,116,105,116,117,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,102,117,110,99,116,105,111,110,44,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,119,104,105,99,104,32,105,115,32>>,{code,[],[<<83,101,116,49>>]},<<46,32,84,104,101,32,118,97,108,117,101,32,111,102,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,76,32,61,32,91,123,97,44,49,125,44,123,98,44,50,125,93,46,10,91,123,97,44,49,125,44,123,98,44,50,125,93,10,50,62,32,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,49,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,97,44,98,93,10,51,62,32,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,49,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,123,123,97,44,49,125,44,97,125,44,123,123,98,44,50,125,44,98,125,93,10,52,62,32,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,125,61,69,41,32,45,62,32,123,69,44,65,125,32,101,110,100,125,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,83,101,116,70,117,110,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,123,123,97,44,49,125,44,97,125,44,123,123,98,44,50,125,44,98,125,93>>]}]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,111,110,32,111,102,32,101,113,117,97,108,105,116,121,32,98,101,116,119,101,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,123,97,44,98,44,99,125,58>>]},{pre,[],[{code,[],[<<49,62,32,73,32,61,32,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,102,117,110,40,65,41,32,45,62,32,65,32,101,110,100,44,32,115,111,102,115,58,115,101,116,40,91,97,44,98,44,99,93,41,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,73,41,46,10,91,123,97,44,97,125,44,123,98,44,98,125,44,123,99,44,99,125,93>>]}]},{p,[],[<<76,101,116,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,98,101,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,109,97,112,115,32,101,97,99,104,32,101,108,101,109,101,110,116,32>>,{code,[],[<<83,101,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,111,110,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,58>>]},{pre,[],[{code,[],[<<105,109,97,103,101,115,40,83,101,116,79,102,83,101,116,115,44,32,66,105,110,82,101,108,41,32,45,62,10,32,32,32,70,117,110,32,61,32,102,117,110,40,83,101,116,41,32,45,62,32,115,111,102,115,58,105,109,97,103,101,40,66,105,110,82,101,108,44,32,83,101,116,41,32,101,110,100,44,10,32,32,32,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,70,117,110,44,32,83,101,116,79,102,83,101,116,115,41,46>>]}]},{p,[],[<<69,120,116,101,114,110,97,108,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,115,111,114,116,101,100,32,108,105,115,116,115,46,32,83,111,44,32,99,114,101,97,116,105,110,103,32,116,104,101,32,105,109,97,103,101,32,111,102,32,97,32,115,101,116,32,117,110,100,101,114,32,97,32,114,101,108,97,116,105,111,110,32,82,32,99,97,110,32,116,114,97,118,101,114,115,101,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,82,32,40,116,111,32,116,104,97,116,32,99,111,109,101,115,32,116,104,101,32,115,111,114,116,105,110,103,32,111,102,32,114,101,115,117,108,116,115,44,32,116,104,101,32,105,109,97,103,101,41,46,32,73,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,109,97,103,101,47,50>>]}]},<<44,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,116,114,97,118,101,114,115,101,100,32,111,110,99,101,32,102,111,114,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,116,97,107,101,32,116,111,111,32,108,111,110,103,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,102,102,105,99,105,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,117,110,100,101,114,32,116,104,101,32,97,115,115,117,109,112,116,105,111,110,32,116,104,97,116,32,116,104,101,32,105,109,97,103,101,32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,110,111,110,45,101,109,112,116,121,58>>]},{pre,[],[{code,[],[<<105,109,97,103,101,115,50,40,83,101,116,79,102,83,101,116,115,44,32,66,105,110,82,101,108,41,32,45,62,10,32,32,32,67,82,32,61,32,115,111,102,115,58,99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,40,83,101,116,79,102,83,101,116,115,41,44,10,32,32,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,67,82,44,32,66,105,110,82,101,108,41,44,10,32,32,32,115,111,102,115,58,114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,40,82,41,46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,56,50>>,signature => [{attribute,1048,spec,{{substitution,2},[{type,1048,bounded_fun,[{type,1048,'fun',[{type,1048,product,[{var,1048,'SetFun'},{var,1048,'Set1'}]},{var,1048,'Set2'}]},[{type,1049,constraint,[{atom,1049,is_subtype},[{var,1049,'SetFun'},{user_type,1049,set_fun,[]}]]},{type,1050,constraint,[{atom,1050,is_subtype},[{var,1050,'Set1'},{user_type,1050,a_set,[]}]]},{type,1051,constraint,[{atom,1051,is_subtype},[{var,1051,'Set2'},{user_type,1051,a_set,[]}]]}]]}]}}]}},{{function,symdiff,2},[{file,[115,111,102,115,46,101,114,108]},{location,408}],[<<115,121,109,100,105,102,102,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,121,109,109,101,116,114,105,99,95,100,105,102,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,121,109,109,101,116,114,105,99,32,100,105,102,102,101,114,101,110,99,101>>]},<<32,40,111,114,32,116,104,101,32,66,111,111,108,101,97,110,32,115,117,109,41,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,51,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,51,44,52,93,41,44,10,80,32,61,32,115,111,102,115,58,115,121,109,100,105,102,102,40,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,49,44,52,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,51,49>>,signature => [{attribute,408,spec,{{symdiff,2},[{type,408,bounded_fun,[{type,408,'fun',[{type,408,product,[{var,408,'Set1'},{var,408,'Set2'}]},{var,408,'Set3'}]},[{type,409,constraint,[{atom,409,is_subtype},[{var,409,'Set1'},{user_type,409,a_set,[]}]]},{type,410,constraint,[{atom,410,is_subtype},[{var,410,'Set2'},{user_type,410,a_set,[]}]]},{type,411,constraint,[{atom,411,is_subtype},[{var,411,'Set3'},{user_type,411,a_set,[]}]]}]]}]}}]}},{{function,symmetric_partition,2},[{file,[115,111,102,115,46,101,114,108]},{location,418}],[<<115,121,109,109,101,116,114,105,99,95,112,97,114,116,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,114,105,112,108,101,32,111,102,32,115,101,116,115,58>>]},{ul,[],[{li,[],[{code,[],[<<83,101,116,51>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{li,[],[{code,[],[<<83,101,116,52>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{li,[],[{code,[],[<<83,101,116,53>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,50>>]},<<32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,49>>]},<<46>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,52,55>>,signature => [{attribute,418,spec,{{symmetric_partition,2},[{type,418,bounded_fun,[{type,418,'fun',[{type,418,product,[{var,418,'Set1'},{var,418,'Set2'}]},{type,418,tuple,[{var,418,'Set3'},{var,418,'Set4'},{var,418,'Set5'}]}]},[{type,419,constraint,[{atom,419,is_subtype},[{var,419,'Set1'},{user_type,419,a_set,[]}]]},{type,420,constraint,[{atom,420,is_subtype},[{var,420,'Set2'},{user_type,420,a_set,[]}]]},{type,421,constraint,[{atom,421,is_subtype},[{var,421,'Set3'},{user_type,421,a_set,[]}]]},{type,422,constraint,[{atom,422,is_subtype},[{var,422,'Set4'},{user_type,422,a_set,[]}]]},{type,423,constraint,[{atom,423,is_subtype},[{var,423,'Set5'},{user_type,423,a_set,[]}]]}]]}]}}]}},{{function,to_external,1},[{file,[115,111,102,115,46,101,114,108]},{location,319}],[<<116,111,95,101,120,116,101,114,110,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32,97,110,32,97,116,111,109,105,99,44,32,111,114,100,101,114,101,100,44,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,54,56>>,signature => [{attribute,319,spec,{{to_external,1},[{type,319,bounded_fun,[{type,319,'fun',[{type,319,product,[{var,319,'AnySet'}]},{var,319,'ExternalSet'}]},[{type,320,constraint,[{atom,320,is_subtype},[{var,320,'ExternalSet'},{user_type,320,external_set,[]}]]},{type,321,constraint,[{atom,321,is_subtype},[{var,321,'AnySet'},{user_type,321,anyset,[]}]]}]]}]}}]}},{{function,to_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,335}],[<<116,111,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<32,97,115,32,97,32,116,117,112,108,101,32,111,102,32,115,101,116,115,44,32,97,110,100,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<32,97,115,32,97,32,115,111,114,116,101,100,32,108,105,115,116,32,111,102,32,115,101,116,115,32,119,105,116,104,111,117,116,32,100,117,112,108,105,99,97,116,101,115,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,55,55>>,signature => [{attribute,335,spec,{{to_sets,1},[{type,335,bounded_fun,[{type,335,'fun',[{type,335,product,[{var,335,'ASet'}]},{var,335,'Sets'}]},[{type,336,constraint,[{atom,336,is_subtype},[{var,336,'ASet'},{type,336,union,[{user_type,336,a_set,[]},{user_type,336,ordset,[]}]}]]},{type,337,constraint,[{atom,337,is_subtype},[{var,337,'Sets'},{type,337,union,[{user_type,337,tuple_of,[{var,337,'AnySet'}]},{type,337,list,[{var,337,'AnySet'}]}]}]]},{type,338,constraint,[{atom,338,is_subtype},[{var,338,'AnySet'},{user_type,338,anyset,[]}]]}]]}]}}]}},{{function,type,1},[{file,[115,111,102,115,46,101,114,108]},{location,327}],[<<116,121,112,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,111,102,32,97,110,32,97,116,111,109,105,99,44,32,111,114,100,101,114,101,100,44,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,56,56>>,signature => [{attribute,327,spec,{{type,1},[{type,327,bounded_fun,[{type,327,'fun',[{type,327,product,[{var,327,'AnySet'}]},{var,327,'Type'}]},[{type,328,constraint,[{atom,328,is_subtype},[{var,328,'AnySet'},{user_type,328,anyset,[]}]]},{type,329,constraint,[{atom,329,is_subtype},[{var,329,'Type'},{user_type,329,type,[]}]]}]]}]}}]}},{{function,union,1},[{file,[115,111,102,115,46,101,114,108]},{location,553}],[<<117,110,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,57,55>>,signature => [{attribute,553,spec,{{union,1},[{type,553,bounded_fun,[{type,553,'fun',[{type,553,product,[{var,553,'SetOfSets'}]},{var,553,'Set'}]},[{type,554,constraint,[{atom,554,is_subtype},[{var,554,'Set'},{user_type,554,a_set,[]}]]},{type,555,constraint,[{atom,555,is_subtype},[{var,555,'SetOfSets'},{user_type,555,set_of_sets,[]}]]}]]}]}}]}},{{function,union,2},[{file,[115,111,102,115,46,101,114,108]},{location,378}],[<<117,110,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,48,54>>,signature => [{attribute,378,spec,{{union,2},[{type,378,bounded_fun,[{type,378,'fun',[{type,378,product,[{var,378,'Set1'},{var,378,'Set2'}]},{var,378,'Set3'}]},[{type,379,constraint,[{atom,379,is_subtype},[{var,379,'Set1'},{user_type,379,a_set,[]}]]},{type,380,constraint,[{atom,380,is_subtype},[{var,380,'Set2'},{user_type,380,a_set,[]}]]},{type,381,constraint,[{atom,381,is_subtype},[{var,381,'Set3'},{user_type,381,a_set,[]}]]}]]}]}}]}},{{function,union_of_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1288}],[<<117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,48,44,50,44,52,93,125,44,123,98,44,91,48,44,49,44,50,93,125,44,123,99,44,91,50,44,51,93,125,93,41,44,10,83,32,61,32,115,111,102,115,58,117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,48,44,49,44,50,44,51,44,52,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,49,53>>,signature => [{attribute,1288,spec,{{union_of_family,1},[{type,1288,bounded_fun,[{type,1288,'fun',[{type,1288,product,[{var,1288,'Family'}]},{var,1288,'Set'}]},[{type,1289,constraint,[{atom,1289,is_subtype},[{var,1289,'Family'},{user_type,1289,family,[]}]]},{type,1290,constraint,[{atom,1290,is_subtype},[{var,1290,'Set'},{user_type,1290,a_set,[]}]]}]]}]}}]}},{{function,weak_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,763}],[<<119,101,97,107,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,83,32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,119,101,97,107,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<119,101,97,107,32,114,101,108,97,116,105,111,110>>]},<<32,87,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46,32,76,101,116,32,70,32,98,101,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46,32,84,104,101,32,115,117,98,115,101,116,32,83,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,32,83,32,121,32,105,102,32,120,32,87,32,121,32,102,111,114,32,115,111,109,101,32,120,32,105,110,32,70,32,97,110,100,32,102,111,114,32,115,111,109,101,32,121,32,105,110,32,70,46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,49,125,44,123,49,44,50,125,44,123,51,44,49,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,119,101,97,107,95,114,101,108,97,116,105,111,110,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,49,125,44,123,49,44,50,125,44,123,50,44,50,125,44,123,51,44,49,125,44,123,51,44,51,125,93>>]}]}]},#{edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,50,57>>,signature => [{attribute,763,spec,{{weak_relation,1},[{type,763,bounded_fun,[{type,763,'fun',[{type,763,product,[{var,763,'BinRel1'}]},{var,763,'BinRel2'}]},[{type,764,constraint,[{atom,764,is_subtype},[{var,764,'BinRel1'},{user_type,764,binary_relation,[]}]]},{type,765,constraint,[{atom,765,is_subtype},[{var,765,'BinRel2'},{user_type,765,binary_relation,[]}]]}]]}]}}]}},{{type,anyset,0},[{file,[115,111,102,115,46,101,114,108]},{location,117}],[<<45,116,121,112,101,32,97,110,121,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,121,32,107,105,110,100,32,111,102,32,115,101,116,32,40,97,108,115,111,32,105,110,99,108,117,100,101,100,32,97,114,101,32,116,104,101,32,97,116,111,109,105,99,32,115,101,116,115,41,46>>]}]},#{signature => [{attribute,117,type,{anyset,{type,117,union,[{user_type,117,ordset,[]},{user_type,117,a_set,[]}]},[]}}]}},{{type,binary_relation,0},[{file,[115,111,102,115,46,101,114,108]},{location,118}],[<<45,116,121,112,101,32,98,105,110,97,114,121,95,114,101,108,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,98,105,110,97,114,121,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<98,105,110,97,114,121,32,114,101,108,97,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,118,type,{binary_relation,{user_type,118,relation,[]},[]}}]}},{{type,external_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,119}],[<<45,116,121,112,101,32,101,120,116,101,114,110,97,108,95,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,119,type,{external_set,{type,119,term,[]},[]}}]}},{{type,family,0},[{file,[115,111,102,115,46,101,114,108]},{location,121}],[<<45,116,121,112,101,32,102,97,109,105,108,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,40,111,102,32,115,117,98,115,101,116,115,41,46>>]}]},#{signature => [{attribute,121,type,{family,{user_type,121,a_function,[]},[]}}]}},{{type,a_function,0},[{file,[115,111,102,115,46,101,114,108]},{location,120}],[<<45,116,121,112,101,32,97,95,102,117,110,99,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,120,type,{a_function,{user_type,120,relation,[]},[]}}]}},{{type,ordset,0},[{file,[115,111,102,115,46,101,114,108]},{location,122}],[<<45,116,121,112,101,32,111,114,100,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,122,opaque,{ordset,{type,122,record,[{atom,122,'OrdSet'}]},[]}}]}},{{type,relation,0},[{file,[115,111,102,115,46,101,114,108]},{location,123}],[<<45,116,121,112,101,32,114,101,108,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,110,95,97,114,121,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,45,97,114,121,32,114,101,108,97,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,123,type,{relation,{user_type,123,a_set,[]},[]}}]}},{{type,a_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,124}],[<<45,116,121,112,101,32,97,95,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,124,opaque,{a_set,{type,124,record,[{atom,124,'Set'}]},[]}}]}},{{type,set_of_sets,0},[{file,[115,111,102,115,46,101,114,108]},{location,125}],[<<45,116,121,112,101,32,115,101,116,95,111,102,95,115,101,116,115,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,111,102,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,46>>]}]},#{signature => [{attribute,125,type,{set_of_sets,{user_type,125,a_set,[]},[]}}]}},{{type,set_fun,0},[{file,[115,111,102,115,46,101,114,108]},{location,126}],[<<45,116,121,112,101,32,115,101,116,95,102,117,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,95,102,117,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,101,116,70,117,110>>]},<<46>>]}]},#{signature => [{attribute,126,type,{set_fun,{type,126,union,[{type,126,pos_integer,[]},{type,127,tuple,[{atom,127,external},{type,127,'fun',[{type,127,product,[{user_type,127,external_set,[]}]},{user_type,127,external_set,[]}]}]},{type,128,'fun',[{type,128,product,[{user_type,128,anyset,[]}]},{user_type,128,anyset,[]}]}]},[]}}]}},{{type,spec_fun,0},[{file,[115,111,102,115,46,101,114,108]},{location,129}],[<<45,116,121,112,101,32,115,112,101,99,95,102,117,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,129,type,{spec_fun,{type,129,union,[{type,129,tuple,[{atom,129,external},{type,129,'fun',[{type,129,product,[{user_type,129,external_set,[]}]},{type,129,boolean,[]}]}]},{type,130,'fun',[{type,130,product,[{user_type,130,anyset,[]}]},{type,130,boolean,[]}]}]},[]}}]}},{{type,type,0},[{file,[115,111,102,115,46,101,114,108]},{location,131}],[<<45,116,121,112,101,32,116,121,112,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<46>>]}]},#{signature => [{attribute,131,type,{type,{type,131,term,[]},[]}}]}},{{type,tuple_of,1},[{file,[115,111,102,115,46,101,114,108]},{location,133}],[<<116,117,112,108,101,95,111,102,40,84,41>>],#{<<101,110>> => [{p,[],[<<65,32,116,117,112,108,101,32,119,104,101,114,101,32,116,104,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84>>]},<<46>>]}]},#{signature => [{attribute,133,type,{tuple_of,{type,133,tuple,any},[{var,133,'_T'}]}}]}}]}. \ No newline at end of file +{docs_v1,[{file,[115,111,102,115,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,#{<<101,110>> => [{p,[],[<<84,104,105,115,32,109,111,100,117,108,101,32,112,114,111,118,105,100,101,115,32,111,112,101,114,97,116,105,111,110,115,32,111,110,32,102,105,110,105,116,101,32,115,101,116,115,32,97,110,100,32,114,101,108,97,116,105,111,110,115,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,115,101,116,115,46,32,73,110,116,117,105,116,105,118,101,108,121,44,32,97,32,115,101,116,32,105,115,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,101,108,101,109,101,110,116,115,59,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32,116,104,101,32,115,101,116,44,32,97,110,100,32,116,104,101,32,115,101,116,32,99,111,110,116,97,105,110,115,32,101,118,101,114,121,32,101,108,101,109,101,110,116,46>>]},{p,[],[<<84,104,101,32,100,97,116,97,32,114,101,112,114,101,115,101,110,116,105,110,103,32>>,{code,[],[<<115,111,102,115>>]},<<32,97,115,32,117,115,101,100,32,98,121,32,116,104,105,115,32,109,111,100,117,108,101,32,105,115,32,116,111,32,98,101,32,114,101,103,97,114,100,101,100,32,97,115,32,111,112,97,113,117,101,32,98,121,32,111,116,104,101,114,32,109,111,100,117,108,101,115,46,32,73,110,32,97,98,115,116,114,97,99,116,32,116,101,114,109,115,44,32,116,104,101,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,105,115,32,97,32,99,111,109,112,111,115,105,116,101,32,116,121,112,101,32,111,102,32,101,120,105,115,116,105,110,103,32,69,114,108,97,110,103,32,116,101,114,109,115,46,32,83,101,101,32,110,111,116,101,32,111,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,111,95,117,115,101,114,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<100,97,116,97,32,116,121,112,101,115>>]},<<46,32,65,110,121,32,99,111,100,101,32,97,115,115,117,109,105,110,103,32,107,110,111,119,108,101,100,103,101,32,111,102,32,116,104,101,32,102,111,114,109,97,116,32,105,115,32,114,117,110,110,105,110,103,32,111,110,32,116,104,105,110,32,105,99,101,46>>]},{p,[],[<<71,105,118,101,110,32,97,32,115,101,116,32,65,32,97,110,100,32,97,32,115,101,110,116,101,110,99,101,32,83,40,120,41,44,32,119,104,101,114,101,32,120,32,105,115,32,97,32,102,114,101,101,32,118,97,114,105,97,98,108,101,44,32,97,32,110,101,119,32,115,101,116,32,66,32,119,104,111,115,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,101,120,97,99,116,108,121,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,102,111,114,32,119,104,105,99,104,32,83,40,120,41,32,104,111,108,100,115,32,99,97,110,32,98,101,32,102,111,114,109,101,100,44,32,116,104,105,115,32,105,115,32,100,101,110,111,116,101,100,32,66,194,160,61,32,123,120,194,160,105,110,194,160,65,194,160,58,32,83,40,120,41,125,46,32,83,101,110,116,101,110,99,101,115,32,97,114,101,32,101,120,112,114,101,115,115,101,100,32,117,115,105,110,103,32,116,104,101,32,108,111,103,105,99,97,108,32,111,112,101,114,97,116,111,114,115,32,34,102,111,114,32,115,111,109,101,34,32,40,111,114,32,34,116,104,101,114,101,32,101,120,105,115,116,115,34,41,44,32,34,102,111,114,32,97,108,108,34,44,32,34,97,110,100,34,44,32,34,111,114,34,44,32,34,110,111,116,34,46,32,73,102,32,116,104,101,32,101,120,105,115,116,101,110,99,101,32,111,102,32,97,32,115,101,116,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,116,104,101,32,115,112,101,99,105,102,105,101,100,32,101,108,101,109,101,110,116,115,32,105,115,32,107,110,111,119,110,32,40,97,115,32,105,115,32,97,108,119,97,121,115,32,116,104,101,32,99,97,115,101,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,41,44,32,116,104,105,115,32,105,115,32,100,101,110,111,116,101,100,32,66,194,160,61,32,123,120,194,160,58,32,83,40,120,41,125,46>>]},{ul,[],[{li,[],[{p,[],[<<84,104,101,32>>,{em,[],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,97,44,32,98,44,32,97,110,100,32,99,32,105,115,32,100,101,110,111,116,101,100,32,123,97,44,194,160,98,44,194,160,99,125,46,32,84,104,105,115,32,110,111,116,97,116,105,111,110,32,105,115,32,110,111,116,32,116,111,32,98,101,32,99,111,110,102,117,115,101,100,32,119,105,116,104,32,116,117,112,108,101,115,46>>]},{p,[],[<<84,104,101,32>>,{em,[],[<<111,114,100,101,114,101,100,32,112,97,105,114>>]},<<32,111,102,32,97,32,97,110,100,32,98,44,32,119,105,116,104,32,102,105,114,115,116,32>>,{em,[],[<<99,111,111,114,100,105,110,97,116,101>>]},<<32,97,32,97,110,100,32,115,101,99,111,110,100,32,99,111,111,114,100,105,110,97,116,101,32,98,44,32,105,115,32,100,101,110,111,116,101,100,32,40,97,44,194,160,98,41,46,32,65,110,32,111,114,100,101,114,101,100,32,112,97,105,114,32,105,115,32,97,110,32>>,{em,[],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<32,111,102,32,116,119,111,32,101,108,101,109,101,110,116,115,46,32,73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,111,114,100,101,114,101,100,32,115,101,116,115,32,99,97,110,32,99,111,110,116,97,105,110,32,111,110,101,44,32,116,119,111,44,32,111,114,32,109,111,114,101,32,101,108,101,109,101,110,116,115,44,32,97,110,100,32,112,97,114,101,110,116,104,101,115,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,101,110,99,108,111,115,101,32,116,104,101,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[<<85,110,111,114,100,101,114,101,100,32,115,101,116,115,32,97,110,100,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,111,114,116,104,111,103,111,110,97,108,44,32,97,103,97,105,110,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,59,32,116,104,101,114,101,32,105,115,32,110,111,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,101,113,117,97,108,32,116,111,32,97,110,121,32,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},{li,[],[{p,[],[<<84,104,101,32>>,{em,[],[<<101,109,112,116,121,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,115,32,110,111,32,101,108,101,109,101,110,116,115,46>>]},{p,[],[<<83,101,116,32,65,32,105,115,32>>,{a,[{id,<<101,113,117,97,108>>}],[]},{em,[],[<<101,113,117,97,108>>]},<<32,116,111,32,115,101,116,32,66,32,105,102,32,116,104,101,121,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,101,108,101,109,101,110,116,115,44,32,119,104,105,99,104,32,105,115,32,100,101,110,111,116,101,100,32,65,194,160,61,194,160,66,46,32,84,119,111,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,101,113,117,97,108,32,105,102,32,116,104,101,121,32,99,111,110,116,97,105,110,32,116,104,101,32,115,97,109,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,97,110,100,32,104,97,118,101,32,101,113,117,97,108,32,101,108,101,109,101,110,116,115,32,97,116,32,101,97,99,104,32,99,111,111,114,100,105,110,97,116,101,46>>]},{p,[],[<<83,101,116,32,66,32,105,115,32,97,32>>,{a,[{id,<<115,117,98,115,101,116>>}],[]},{em,[],[<<115,117,98,115,101,116>>]},<<32,111,102,32,115,101,116,32,65,32,105,102,32,65,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,66,32,99,111,110,116,97,105,110,115,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<117,110,105,111,110>>}],[]},{em,[],[<<117,110,105,111,110>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,97,110,100,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,66,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<105,110,116,101,114,115,101,99,116,105,111,110>>}],[]},{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,66,46>>]},{p,[],[<<84,119,111,32,115,101,116,115,32,97,114,101,32>>,{a,[{id,<<100,105,115,106,111,105,110,116>>}],[]},{em,[],[<<100,105,115,106,111,105,110,116>>]},<<32,105,102,32,116,104,101,105,114,32,105,110,116,101,114,115,101,99,116,105,111,110,32,105,115,32,116,104,101,32,101,109,112,116,121,32,115,101,116,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<100,105,102,102,101,114,101,110,99,101>>}],[]},{em,[],[<<100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,65,32,97,110,100,32,66,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,65,32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32,66,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<115,121,109,109,101,116,114,105,99,95,100,105,102,102,101,114,101,110,99,101>>}],[]},{em,[],[<<115,121,109,109,101,116,114,105,99,32,100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,116,104,111,115,101,32,101,108,101,109,101,110,116,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,101,105,116,104,101,114,32,111,102,32,116,104,101,32,116,119,111,32,115,101,116,115,44,32,98,117,116,32,110,111,116,32,98,111,116,104,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<117,110,105,111,110,95,110>>}],[]},{em,[],[<<117,110,105,111,110>>]},<<32,111,102,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,115,101,116,115,32,105,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,116,104,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,97,116,32,108,101,97,115,116,32,111,110,101,32,115,101,116,32,111,102,32,116,104,101,32,99,111,108,108,101,99,116,105,111,110,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<105,110,116,101,114,115,101,99,116,105,111,110,95,110>>}],[]},{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,97,32,110,111,110,45,101,109,112,116,121,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,115,101,116,115,32,105,115,32,116,104,101,32,115,101,116,32,116,104,97,116,32,99,111,110,116,97,105,110,115,32,97,108,108,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32,101,118,101,114,121,32,115,101,116,32,111,102,32,116,104,101,32,99,111,108,108,101,99,116,105,111,110,46>>]}]},{li,[],[{p,[],[<<84,104,101,32>>,{a,[{id,<<67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,119,111,32,115,101,116,115,32,88,32,97,110,100,32,89,44,32,100,101,110,111,116,101,100,32,88,194,160,195,151,194,160,89,44,32,105,115,32,116,104,101,32,115,101,116,32,123,97,194,160,58,32,97,194,160,61,32,40,120,44,194,160,121,41,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,88,32,97,110,100,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,89,125,46>>]},{p,[],[<<65,32>>,{a,[{id,<<114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<114,101,108,97,116,105,111,110>>]},<<32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,88,194,160,195,151,194,160,89,46,32,76,101,116,32,82,32,98,101,32,97,32,114,101,108,97,116,105,111,110,46,32,84,104,101,32,102,97,99,116,32,116,104,97,116,32,40,120,44,194,160,121,41,32,98,101,108,111,110,103,115,32,116,111,32,82,32,105,115,32,119,114,105,116,116,101,110,32,97,115,32,120,194,160,82,194,160,121,46,32,65,115,32,114,101,108,97,116,105,111,110,115,32,97,114,101,32,115,101,116,115,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,115,32,111,102,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,40,115,117,98,115,101,116,44,32,117,110,105,111,110,44,32,97,110,100,32,115,111,32,111,110,41,32,97,112,112,108,121,32,116,111,32,114,101,108,97,116,105,111,110,115,32,97,115,32,119,101,108,108,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<100,111,109,97,105,110>>}],[]},{em,[],[<<100,111,109,97,105,110>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,120,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,89,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<114,97,110,103,101>>}],[]},{em,[],[<<114,97,110,103,101>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,121,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,88,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<99,111,110,118,101,114,115,101>>}],[]},{em,[],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,97,194,160,58,32,97,194,160,61,32,40,121,44,194,160,120,41,32,102,111,114,32,115,111,109,101,32,40,120,44,194,160,121,41,194,160,105,110,194,160,82,125,46>>]},{p,[],[<<73,102,32,65,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,88,44,32,116,104,101,32>>,{a,[{id,<<105,109,97,103,101>>}],[]},{em,[],[<<105,109,97,103,101>>]},<<32,111,102,32,65,32,117,110,100,101,114,32,82,32,105,115,32,116,104,101,32,115,101,116,32,123,121,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,120,194,160,105,110,194,160,65,125,46,32,73,102,32,66,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,89,44,32,116,104,101,32>>,{a,[{id,<<105,110,118,101,114,115,101,95,105,109,97,103,101>>}],[]},{em,[],[<<105,110,118,101,114,115,101,32,105,109,97,103,101>>]},<<32,111,102,32,66,32,105,115,32,116,104,101,32,115,101,116,32,123,120,194,160,58,32,120,194,160,82,194,160,121,32,102,111,114,32,115,111,109,101,32,121,194,160,105,110,194,160,66,125,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,88,32,116,111,32,89,44,32,97,110,100,32,83,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,89,32,116,111,32,90,44,32,116,104,101,32>>,{a,[{id,<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,82,32,97,110,100,32,83,32,105,115,32,116,104,101,32,114,101,108,97,116,105,111,110,32,84,32,102,114,111,109,32,88,32,116,111,32,90,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,84,194,160,122,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,121,32,105,110,32,89,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,194,160,121,32,97,110,100,32,121,194,160,83,194,160,122,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<114,101,115,116,114,105,99,116,105,111,110>>}],[]},{em,[],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32,82,32,116,111,32,65,32,105,115,32,116,104,101,32,115,101,116,32,83,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,83,194,160,121,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,120,32,105,110,32,65,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,194,160,121,46>>]},{p,[],[<<73,102,32,83,32,105,115,32,97,32,114,101,115,116,114,105,99,116,105,111,110,32,111,102,32,82,32,116,111,32,65,44,32,116,104,101,110,32,82,32,105,115,32,97,110,32>>,{a,[{id,<<101,120,116,101,110,115,105,111,110>>}],[]},{em,[],[<<101,120,116,101,110,115,105,111,110>>]},<<32,111,102,32,83,32,116,111,32,88,46>>]},{p,[],[<<73,102,32,88,194,160,61,194,160,89,44,32,116,104,101,110,32,82,32,105,115,32,99,97,108,108,101,100,32,97,32,114,101,108,97,116,105,111,110,32>>,{em,[],[<<105,110>>]},<<32,88,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<102,105,101,108,100>>}],[]},{em,[],[<<102,105,101,108,100>>]},<<32,111,102,32,97,32,114,101,108,97,116,105,111,110,32,82,32,105,110,32,88,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,82,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,111,102,32,82,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,105,102,32,83,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,83,194,160,121,32,105,102,32,120,194,160,82,194,160,121,32,97,110,100,32,110,111,116,32,120,194,160,61,194,160,121,44,32,116,104,101,110,32,83,32,105,115,32,116,104,101,32>>,{a,[{id,<<115,116,114,105,99,116,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<115,116,114,105,99,116>>]},<<32,114,101,108,97,116,105,111,110,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,82,46,32,67,111,110,118,101,114,115,101,108,121,44,32,105,102,32,83,32,105,115,32,97,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,105,102,32,82,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,82,194,160,121,32,105,102,32,120,194,160,83,194,160,121,32,111,114,32,120,194,160,61,194,160,121,44,32,116,104,101,110,32,82,32,105,115,32,116,104,101,32>>,{a,[{id,<<119,101,97,107,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<119,101,97,107>>]},<<32,114,101,108,97,116,105,111,110,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,83,46>>]},{p,[],[<<65,32,114,101,108,97,116,105,111,110,32,82,32,105,110,32,88,32,105,115,32>>,{em,[],[<<114,101,102,108,101,120,105,118,101>>]},<<32,105,102,32,120,194,160,82,194,160,120,32,102,111,114,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,120,32,111,102,32,88,44,32,105,116,32,105,115,32>>,{em,[],[<<115,121,109,109,101,116,114,105,99>>]},<<32,105,102,32,120,194,160,82,194,160,121,32,105,109,112,108,105,101,115,32,116,104,97,116,32,121,194,160,82,194,160,120,44,32,97,110,100,32,105,116,32,105,115,32>>,{em,[],[<<116,114,97,110,115,105,116,105,118,101>>]},<<32,105,102,32,120,194,160,82,194,160,121,32,97,110,100,32,121,194,160,82,194,160,122,32,105,109,112,108,121,32,116,104,97,116,32,120,194,160,82,194,160,122,46>>]}]},{li,[],[{p,[],[<<65,32>>,{a,[{id,<<102,117,110,99,116,105,111,110>>}],[]},{em,[],[<<102,117,110,99,116,105,111,110>>]},<<32,70,32,105,115,32,97,32,114,101,108,97,116,105,111,110,44,32,97,32,115,117,98,115,101,116,32,111,102,32,88,194,160,195,151,194,160,89,44,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,32,105,115,32,101,113,117,97,108,32,116,111,32,88,32,97,110,100,32,115,117,99,104,32,116,104,97,116,32,102,111,114,32,101,118,101,114,121,32,120,32,105,110,32,88,32,116,104,101,114,101,32,105,115,32,97,32,117,110,105,113,117,101,32,101,108,101,109,101,110,116,32,121,32,105,110,32,89,32,119,105,116,104,32,40,120,44,194,160,121,41,32,105,110,32,70,46,32,84,104,101,32,108,97,116,116,101,114,32,99,111,110,100,105,116,105,111,110,32,99,97,110,32,98,101,32,102,111,114,109,117,108,97,116,101,100,32,97,115,32,102,111,108,108,111,119,115,58,32,105,102,32,120,194,160,70,194,160,121,32,97,110,100,32,120,194,160,70,194,160,122,44,32,116,104,101,110,32,121,194,160,61,194,160,122,46,32,73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,105,116,32,105,115,32,110,111,116,32,114,101,113,117,105,114,101,100,32,116,104,97,116,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,32,105,115,32,101,113,117,97,108,32,116,111,32,88,32,102,111,114,32,97,32,114,101,108,97,116,105,111,110,32,116,111,32,98,101,32,99,111,110,115,105,100,101,114,101,100,32,97,32,102,117,110,99,116,105,111,110,46>>]},{p,[],[<<73,110,115,116,101,97,100,32,111,102,32,119,114,105,116,105,110,103,32,40,120,44,194,160,121,41,194,160,105,110,194,160,70,32,111,114,32,120,194,160,70,194,160,121,44,32,119,101,32,119,114,105,116,101,32,70,40,120,41,194,160,61,194,160,121,32,119,104,101,110,32,70,32,105,115,32,97,32,102,117,110,99,116,105,111,110,44,32,97,110,100,32,115,97,121,32,116,104,97,116,32,70,32,109,97,112,115,32,120,32,111,110,116,111,32,121,44,32,111,114,32,116,104,97,116,32,116,104,101,32,118,97,108,117,101,32,111,102,32,70,32,97,116,32,120,32,105,115,32,121,46>>]},{p,[],[<<65,115,32,102,117,110,99,116,105,111,110,115,32,97,114,101,32,114,101,108,97,116,105,111,110,115,44,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,115,32,111,102,32,116,104,101,32,108,97,115,116,32,105,116,101,109,32,40,100,111,109,97,105,110,44,32,114,97,110,103,101,44,32,97,110,100,32,115,111,32,111,110,41,32,97,112,112,108,121,32,116,111,32,102,117,110,99,116,105,111,110,115,32,97,115,32,119,101,108,108,46>>]},{p,[],[<<73,102,32,116,104,101,32,99,111,110,118,101,114,115,101,32,111,102,32,97,32,102,117,110,99,116,105,111,110,32,70,32,105,115,32,97,32,102,117,110,99,116,105,111,110,32,70,39,44,32,116,104,101,110,32,70,39,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{a,[{id,<<105,110,118,101,114,115,101>>}],[]},{em,[],[<<105,110,118,101,114,115,101>>]},<<32,111,102,32,70,46>>]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,116,119,111,32,102,117,110,99,116,105,111,110,115,32,70,49,32,97,110,100,32,70,50,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{a,[{id,<<99,111,109,112,111,115,105,116,101>>}],[]},{em,[],[<<99,111,109,112,111,115,105,116,101>>]},<<32,111,102,32,70,49,32,97,110,100,32,70,50,32,105,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,70,49,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,70,50,46>>]}]},{li,[],[{p,[],[<<83,111,109,101,116,105,109,101,115,44,32,119,104,101,110,32,116,104,101,32,114,97,110,103,101,32,111,102,32,97,32,102,117,110,99,116,105,111,110,32,105,115,32,109,111,114,101,32,105,109,112,111,114,116,97,110,116,32,116,104,97,110,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,116,115,101,108,102,44,32,116,104,101,32,102,117,110,99,116,105,111,110,32,105,115,32,99,97,108,108,101,100,32,97,32>>,{em,[],[<<102,97,109,105,108,121>>]},<<46>>]},{p,[],[<<84,104,101,32,100,111,109,97,105,110,32,111,102,32,97,32,102,97,109,105,108,121,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<105,110,100,101,120,32,115,101,116>>]},<<44,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<105,110,100,101,120,101,100,32,115,101,116>>]},<<46>>]},{p,[],[<<73,102,32,120,32,105,115,32,97,32,102,97,109,105,108,121,32,102,114,111,109,32,73,32,116,111,32,88,44,32,116,104,101,110,32,120,91,105,93,32,100,101,110,111,116,101,115,32,116,104,101,32,118,97,108,117,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,32,97,116,32,105,110,100,101,120,32,105,46,32,84,104,101,32,110,111,116,97,116,105,111,110,32,34,97,32,102,97,109,105,108,121,32,105,110,32,88,34,32,105,115,32,117,115,101,100,32,102,111,114,32,115,117,99,104,32,97,32,102,97,109,105,108,121,46>>]},{p,[],[<<87,104,101,110,32,116,104,101,32,105,110,100,101,120,101,100,32,115,101,116,32,105,115,32,97,32,115,101,116,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,97,32,115,101,116,32,88,44,32,119,101,32,99,97,108,108,32,120,32,97,32>>,{a,[{id,<<102,97,109,105,108,121>>}],[]},{em,[],[<<102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115>>]},<<32,111,102,32,88,46>>]},{p,[],[<<73,102,32,120,32,105,115,32,97,32,102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,88,44,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,120,32,105,115,32,99,97,108,108,101,100,32,116,104,101,32>>,{em,[],[<<117,110,105,111,110,32,111,102,32,116,104,101,32,102,97,109,105,108,121>>]},<<32,120,46>>]},{p,[],[<<73,102,32,120,32,105,115,32,110,111,110,45,101,109,112,116,121,32,40,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,110,111,110,45,101,109,112,116,121,41,44,32,116,104,101,32>>,{em,[],[<<105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32,102,97,109,105,108,121>>]},<<32,120,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,120,46>>]},{p,[],[<<73,110,32,116,104,105,115,32,109,111,100,117,108,101,44,32,116,104,101,32,111,110,108,121,32,102,97,109,105,108,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,97,114,101,32,102,97,109,105,108,105,101,115,32,111,102,32,115,117,98,115,101,116,115,32,111,102,32,115,111,109,101,32,115,101,116,32,88,59,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,116,104,101,32,119,111,114,100,32,34,102,97,109,105,108,121,34,32,105,115,32,117,115,101,100,32,102,111,114,32,115,117,99,104,32,102,97,109,105,108,105,101,115,32,111,102,32,115,117,98,115,101,116,115,46>>]}]},{li,[],[{p,[],[<<65,32>>,{a,[{id,<<112,97,114,116,105,116,105,111,110>>}],[]},{em,[],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,97,32,115,101,116,32,88,32,105,115,32,97,32,99,111,108,108,101,99,116,105,111,110,32,83,32,111,102,32,110,111,110,45,101,109,112,116,121,32,115,117,98,115,101,116,115,32,111,102,32,88,32,119,104,111,115,101,32,117,110,105,111,110,32,105,115,32,88,32,97,110,100,32,119,104,111,115,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,112,97,105,114,119,105,115,101,32,100,105,115,106,111,105,110,116,46>>]},{p,[],[<<65,32,114,101,108,97,116,105,111,110,32,105,110,32,97,32,115,101,116,32,105,115,32,97,110,32>>,{em,[],[<<101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110>>]},<<32,105,102,32,105,116,32,105,115,32,114,101,102,108,101,120,105,118,101,44,32,115,121,109,109,101,116,114,105,99,44,32,97,110,100,32,116,114,97,110,115,105,116,105,118,101,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,97,110,100,32,120,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,88,44,32,116,104,101,32>>,{a,[{id,<<101,113,117,105,118,97,108,101,110,99,101,95,99,108,97,115,115>>}],[]},{em,[],[<<101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115>>]},<<32,111,102,32,120,32,119,105,116,104,32,114,101,115,112,101,99,116,32,116,111,32,82,32,105,115,32,116,104,101,32,115,101,116,32,111,102,32,97,108,108,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,121,32,111,102,32,88,32,102,111,114,32,119,104,105,99,104,32,120,194,160,82,194,160,121,32,104,111,108,100,115,46,32,84,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,101,115,32,99,111,110,115,116,105,116,117,116,101,32,97,32,112,97,114,116,105,116,105,111,110,105,110,103,32,111,102,32,88,46,32,67,111,110,118,101,114,115,101,108,121,44,32,105,102,32,67,32,105,115,32,97,32,112,97,114,116,105,116,105,111,110,32,111,102,32,88,44,32,116,104,101,32,114,101,108,97,116,105,111,110,32,116,104,97,116,32,104,111,108,100,115,32,102,111,114,32,97,110,121,32,116,119,111,32,101,108,101,109,101,110,116,115,32,111,102,32,88,32,105,102,32,116,104,101,121,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32,115,97,109,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,44,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,100,117,99,101,100,32,98,121,32,116,104,101,32,112,97,114,116,105,116,105,111,110,32,67,46>>]},{p,[],[<<73,102,32,82,32,105,115,32,97,110,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,44,32,116,104,101,32>>,{a,[{id,<<99,97,110,111,110,105,99,97,108,95,109,97,112>>}],[]},{em,[],[<<99,97,110,111,110,105,99,97,108,32,109,97,112>>]},<<32,105,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,109,97,112,115,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,111,102,32,88,32,111,110,116,111,32,105,116,115,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,46>>]}]},{li,[],[{p,[],[{a,[{id,<<98,105,110,97,114,121,95,114,101,108,97,116,105,111,110>>}],[]},<<82,101,108,97,116,105,111,110,115,32,97,115,32,100,101,102,105,110,101,100,32,97,98,111,118,101,32,40,97,115,32,115,101,116,115,32,111,102,32,111,114,100,101,114,101,100,32,112,97,105,114,115,41,32,97,114,101,32,102,114,111,109,32,110,111,119,32,111,110,32,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32>>,{em,[],[<<98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115>>]},<<46>>]},{p,[],[<<87,101,32,99,97,108,108,32,97,32,115,101,116,32,111,102,32,111,114,100,101,114,101,100,32,115,101,116,115,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,97,110,32>>,{a,[{id,<<110,95,97,114,121,95,114,101,108,97,116,105,111,110>>}],[]},{em,[],[<<40,110,45,97,114,121,41,32,114,101,108,97,116,105,111,110>>]},<<44,32,97,110,100,32,115,97,121,32,116,104,97,116,32,116,104,101,32,114,101,108,97,116,105,111,110,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32,116,104,101,32>>,{a,[{id,<<67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>}],[]},<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116,32,88,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,88,91,110,93,44,32,119,104,101,114,101,32,120,91,105,93,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,88,91,105,93,44,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<112,114,111,106,101,99,116,105,111,110>>}],[]},{em,[],[<<112,114,111,106,101,99,116,105,111,110>>]},<<32,111,102,32,97,110,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,111,110,116,111,32,99,111,111,114,100,105,110,97,116,101,32,105,32,105,115,32,116,104,101,32,115,101,116,32,123,120,91,105,93,194,160,58,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,105,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,105,110,32,82,32,102,111,114,32,115,111,109,101,32,120,91,106,93,194,160,105,110,194,160,88,91,106,93,44,32,49,194,160,60,61,194,160,106,194,160,60,61,194,160,110,32,97,110,100,32,110,111,116,32,105,194,160,61,194,160,106,125,46,32,84,104,101,32,112,114,111,106,101,99,116,105,111,110,115,32,111,102,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,111,110,116,111,32,116,104,101,32,102,105,114,115,116,32,97,110,100,32,115,101,99,111,110,100,32,99,111,111,114,100,105,110,97,116,101,115,32,97,114,101,32,116,104,101,32,100,111,109,97,105,110,32,97,110,100,32,116,104,101,32,114,97,110,103,101,32,111,102,32,82,44,32,114,101,115,112,101,99,116,105,118,101,108,121,46>>]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,99,97,110,32,98,101,32,103,101,110,101,114,97,108,105,122,101,100,32,116,111,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,115,32,102,111,108,108,111,119,115,46,32,76,101,116,32,84,82,32,98,101,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,102,114,111,109,32,88,32,116,111,32,89,91,105,93,32,97,110,100,32,83,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,40,89,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,89,91,110,93,41,32,116,111,32,90,46,32,84,104,101,32>>,{a,[{id,<<116,117,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,84,82,32,97,110,100,32,83,32,105,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,84,32,102,114,111,109,32,88,32,116,111,32,90,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,194,160,84,194,160,122,32,105,102,32,97,110,100,32,111,110,108,121,32,105,102,32,116,104,101,114,101,32,101,120,105,115,116,115,32,97,110,32,101,108,101,109,101,110,116,32,121,91,105,93,32,105,110,32,89,91,105,93,32,102,111,114,32,101,97,99,104,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,32,115,117,99,104,32,116,104,97,116,32,120,194,160,82,91,105,93,194,160,121,91,105,93,32,97,110,100,32,40,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,110,93,41,194,160,83,194,160,122,46,32,78,111,119,32,108,101,116,32,84,82,32,98,101,32,97,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,102,114,111,109,32,88,91,105,93,32,116,111,32,89,91,105,93,32,97,110,100,32,83,32,97,32,115,117,98,115,101,116,32,111,102,32,88,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,88,91,110,93,46,32,84,104,101,32>>,{a,[{id,<<109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>}],[]},{em,[],[<<109,117,108,116,105,112,108,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,84,82,32,97,110,100,32,83,32,105,115,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,116,104,101,32,115,101,116,32,123,122,194,160,58,32,122,194,160,61,32,40,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,44,32,40,121,91,49,93,44,46,46,46,44,121,91,110,93,41,41,32,102,111,114,32,115,111,109,101,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,194,160,105,110,194,160,83,32,97,110,100,32,102,111,114,32,115,111,109,101,32,40,120,91,105,93,44,194,160,121,91,105,93,41,32,105,110,32,82,91,105,93,44,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,125,46>>]},{p,[],[<<84,104,101,32>>,{a,[{id,<<110,97,116,117,114,97,108,95,106,111,105,110>>}],[]},{em,[],[<<110,97,116,117,114,97,108,32,106,111,105,110>>]},<<32,111,102,32,97,110,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32,82,32,97,110,100,32,97,110,32,109,45,97,114,121,32,114,101,108,97,116,105,111,110,32,83,32,111,110,32,99,111,111,114,100,105,110,97,116,101,32,105,32,97,110,100,32,106,32,105,115,32,100,101,102,105,110,101,100,32,116,111,32,98,101,32,116,104,101,32,115,101,116,32,123,122,194,160,58,32,122,194,160,61,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,44,194,160,32,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,106,45,49,93,44,194,160,121,91,106,43,49,93,44,194,160,46,46,46,44,194,160,121,91,109,93,41,32,102,111,114,32,115,111,109,101,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,194,160,105,110,194,160,82,32,97,110,100,32,102,111,114,32,115,111,109,101,32,40,121,91,49,93,44,194,160,46,46,46,44,194,160,121,91,109,93,41,194,160,105,110,194,160,83,32,115,117,99,104,32,116,104,97,116,32,120,91,105,93,194,160,61,194,160,121,91,106,93,125,46>>]}]},{li,[],[{p,[],[{a,[{id,<<115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>}],[]},<<84,104,101,32,115,101,116,115,32,114,101,99,111,103,110,105,122,101,100,32,98,121,32,116,104,105,115,32,109,111,100,117,108,101,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,32,83,101,116,115,44,32,119,104,105,99,104,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,116,104,101,32,115,109,97,108,108,101,115,116,32,115,101,116,32,115,117,99,104,32,116,104,97,116,58>>]},{ul,[],[{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,97,116,111,109,32,84,44,32,101,120,99,101,112,116,32,39,95,39,44,32,97,110,100,32,102,111,114,32,101,118,101,114,121,32,116,101,114,109,32,88,44,32,40,84,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<97,116,111,109,105,99,32,115,101,116,115>>]},<<41,46>>]}]},{li,[],[{p,[],[<<40,91,39,95,39,93,44,194,160,91,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40,116,104,101,32>>,{em,[],[<<117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116>>]},<<41,46>>]}]},{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,116,117,112,108,101,32,84,194,160,61,32,123,84,91,49,93,44,194,160,46,46,46,44,194,160,84,91,110,93,125,32,97,110,100,32,102,111,114,32,101,118,101,114,121,32,116,117,112,108,101,32,88,194,160,61,32,123,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,125,44,32,105,102,32,40,84,91,105,93,44,194,160,88,91,105,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,102,111,114,32,101,118,101,114,121,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,44,32,116,104,101,110,32,40,84,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<111,114,100,101,114,101,100,32,115,101,116,115>>]},<<41,46>>]}]},{li,[],[{p,[],[<<70,111,114,32,101,118,101,114,121,32,116,101,114,109,32,84,44,32,105,102,32,88,32,105,115,32,116,104,101,32,101,109,112,116,121,32,108,105,115,116,32,111,114,32,97,32,110,111,110,45,101,109,112,116,121,32,115,111,114,116,101,100,32,108,105,115,116,32,91,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,93,32,119,105,116,104,111,117,116,32,100,117,112,108,105,99,97,116,101,115,32,115,117,99,104,32,116,104,97,116,32,40,84,44,194,160,88,91,105,93,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,102,111,114,32,101,118,101,114,121,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,44,32,116,104,101,110,32,40,91,84,93,44,194,160,88,41,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,115,32,40>>,{em,[],[<<116,121,112,101,100,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115>>]},<<41,46>>]}]}]},{p,[],[<<65,110,32>>,{a,[{id,<<101,120,116,101,114,110,97,108,95,115,101,116>>}],[]},{em,[],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,83,101,116,115,46>>]},{p,[],[<<65,32>>,{a,[{id,<<116,121,112,101>>}],[]},{em,[],[<<116,121,112,101>>]},<<32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,83,101,116,115,46>>]},{p,[],[<<73,102,32,83,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,40,84,44,194,160,88,41,32,111,102,32,83,101,116,115,44,32,116,104,101,110,32,84,32,105,115,32,97,32>>,{a,[{id,<<118,97,108,105,100,95,116,121,112,101>>}],[]},{em,[],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32,88,44,32,84,32,105,115,32,116,104,101,32,116,121,112,101,32,111,102,32,83,44,32,97,110,100,32,88,32,105,115,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,83,46,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,116,101,114,109,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,116,101,114,109,47,50>>]}]},<<32,99,114,101,97,116,101,115,32,97,32,115,101,116,32,102,114,111,109,32,97,32,116,121,112,101,32,97,110,100,32,97,110,32,69,114,108,97,110,103,32,116,101,114,109,32,116,117,114,110,101,100,32,105,110,116,111,32,97,110,32,101,120,116,101,114,110,97,108,32,115,101,116,46>>]},{p,[],[<<84,104,101,32,115,101,116,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,83,101,116,115,32,97,114,101,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,114,97,110,103,101,32,111,102,32,102,117,110,99,116,105,111,110,32,83,101,116,32,102,114,111,109,32,83,101,116,115,32,116,111,32,69,114,108,97,110,103,32,116,101,114,109,115,32,97,110,100,32,115,101,116,115,32,111,102,32,69,114,108,97,110,103,32,116,101,114,109,115,58>>]},{ul,[],[{li,[],[<<83,101,116,40,84,44,84,101,114,109,41,194,160,61,32,84,101,114,109,44,32,119,104,101,114,101,32,84,32,105,115,32,97,110,32,97,116,111,109>>]},{li,[],[<<83,101,116,40,123,84,91,49,93,44,194,160,46,46,46,44,194,160,84,91,110,93,125,44,194,160,123,88,91,49,93,44,194,160,46,46,46,44,32,194,160,88,91,110,93,125,41,194,160,61,32,40,83,101,116,40,84,91,49,93,44,194,160,88,91,49,93,41,44,194,160,46,46,46,44,194,160,32,83,101,116,40,84,91,110,93,44,194,160,88,91,110,93,41,41>>]},{li,[],[<<83,101,116,40,91,84,93,44,194,160,91,88,91,49,93,44,194,160,46,46,46,44,194,160,88,91,110,93,93,41,194,160,61,32,123,83,101,116,40,84,44,194,160,88,91,49,93,41,44,194,160,46,46,46,44,194,160,83,101,116,40,84,44,194,160,88,91,110,93,41,125>>]},{li,[],[<<83,101,116,40,91,84,93,44,194,160,91,93,41,194,160,61,32,123,125>>]}]},{p,[],[<<87,104,101,110,32,116,104,101,114,101,32,105,115,32,110,111,32,114,105,115,107,32,111,102,32,99,111,110,102,117,115,105,111,110,44,32,101,108,101,109,101,110,116,115,32,111,102,32,83,101,116,115,32,97,114,101,32,105,100,101,110,116,105,102,105,101,100,32,119,105,116,104,32,116,104,101,32,115,101,116,115,32,116,104,101,121,32,114,101,112,114,101,115,101,110,116,46,32,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102,32,85,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,99,97,108,108,105,110,103,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<117,110,105,111,110,47,50>>]}]},<<32,119,105,116,104,32,83,49,32,97,110,100,32,83,50,32,97,115,32,97,114,103,117,109,101,110,116,115,44,32,116,104,101,110,32,85,32,105,115,32,115,97,105,100,32,116,111,32,98,101,32,116,104,101,32,117,110,105,111,110,32,111,102,32,83,49,32,97,110,100,32,83,50,46,32,65,32,109,111,114,101,32,112,114,101,99,105,115,101,32,102,111,114,109,117,108,97,116,105,111,110,32,105,115,32,116,104,97,116,32,83,101,116,40,85,41,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32,83,101,116,40,83,49,41,32,97,110,100,32,83,101,116,40,83,50,41,46>>]}]}]},{p,[],[<<84,104,101,32,116,121,112,101,115,32,97,114,101,32,117,115,101,100,32,116,111,32,105,109,112,108,101,109,101,110,116,32,116,104,101,32,118,97,114,105,111,117,115,32,99,111,110,100,105,116,105,111,110,115,32,116,104,97,116,32,115,101,116,115,32,109,117,115,116,32,102,117,108,102,105,108,108,46,32,65,115,32,97,110,32,101,120,97,109,112,108,101,44,32,99,111,110,115,105,100,101,114,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,116,119,111,32,115,101,116,115,32,82,32,97,110,100,32,83,44,32,97,110,100,32,114,101,99,97,108,108,32,116,104,97,116,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,32,111,102,32,82,32,97,110,100,32,83,32,105,115,32,100,101,102,105,110,101,100,32,105,102,32,82,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,116,111,32,89,32,97,110,100,32,83,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,89,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,105,109,112,108,101,109,101,110,116,115,32,116,104,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>]}]},<<44,32,99,104,101,99,107,115,32,116,104,97,116,32,116,104,101,32,97,114,103,117,109,101,110,116,115,32,114,101,112,114,101,115,101,110,116,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,98,121,32,109,97,116,99,104,105,110,103,32,91,123,65,44,66,125,93,32,97,103,97,105,110,115,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,102,105,114,115,116,32,97,114,103,117,109,101,110,116,32,40,65,114,103,49,32,115,97,121,41,44,32,97,110,100,32,91,123,67,44,68,125,93,32,97,103,97,105,110,115,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,40,65,114,103,50,32,115,97,121,41,46,32,84,104,101,32,102,97,99,116,32,116,104,97,116,32,91,123,65,44,66,125,93,32,109,97,116,99,104,101,115,32,116,104,101,32,116,121,112,101,32,111,102,32,65,114,103,49,32,105,115,32,116,111,32,98,101,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,65,114,103,49,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,88,32,116,111,32,89,44,32,119,104,101,114,101,32,88,32,105,115,32,100,101,102,105,110,101,100,32,97,115,32,97,108,108,32,115,101,116,115,32,83,101,116,40,120,41,32,102,111,114,32,115,111,109,101,32,101,108,101,109,101,110,116,32,120,32,105,110,32,83,101,116,115,32,116,104,101,32,116,121,112,101,32,111,102,32,119,104,105,99,104,32,105,115,32,65,44,32,97,110,100,32,115,105,109,105,108,97,114,108,121,32,102,111,114,32,89,46,32,73,110,32,116,104,101,32,115,97,109,101,32,119,97,121,32,65,114,103,50,32,105,115,32,105,110,116,101,114,112,114,101,116,101,100,32,97,115,32,114,101,112,114,101,115,101,110,116,105,110,103,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,114,111,109,32,87,32,116,111,32,90,46,32,70,105,110,97,108,108,121,32,105,116,32,105,115,32,99,104,101,99,107,101,100,32,116,104,97,116,32,66,32,109,97,116,99,104,101,115,32,67,44,32,119,104,105,99,104,32,105,115,32,115,117,102,102,105,99,105,101,110,116,32,116,111,32,101,110,115,117,114,101,32,116,104,97,116,32,87,32,105,115,32,101,113,117,97,108,32,116,111,32,89,46,32,84,104,101,32,117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116,32,105,115,32,104,97,110,100,108,101,100,32,115,101,112,97,114,97,116,101,108,121,58,32,105,116,115,32,116,121,112,101,44,32,91,39,95,39,93,44,32,109,97,116,99,104,101,115,32,116,104,101,32,116,121,112,101,32,111,102,32,97,110,121,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]},{p,[],[<<65,32,102,101,119,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,40>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,114,101,115,116,114,105,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,51>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,97,114,116,105,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,114,111,106,101,99,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<112,114,111,106,101,99,116,105,111,110,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110,47,51>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,115,116,114,105,99,116,105,111,110,47,51>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,117,98,115,116,105,116,117,116,105,111,110,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,117,98,115,116,105,116,117,116,105,111,110,47,50>>]}]},<<41,32,97,99,99,101,112,116,32,97,110,32,69,114,108,97,110,103,32,102,117,110,99,116,105,111,110,32,97,115,32,97,32,109,101,97,110,115,32,116,111,32,109,111,100,105,102,121,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,97,32,103,105,118,101,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32>>,{a,[{id,<<115,101,116,95,102,117,110>>}],[]},<<83,117,99,104,32,97,32,102,117,110,99,116,105,111,110,44,32,99,97,108,108,101,100,32,83,101,116,70,117,110,32,105,110,32,116,104,101,32,102,111,108,108,111,119,105,110,103,44,32,99,97,110,32,98,101,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,102,117,110,99,116,105,111,110,97,108,32,111,98,106,101,99,116,32,40,102,117,110,41,44,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,125>>]},<<44,32,111,114,32,97,110,32,105,110,116,101,103,101,114,58>>]},{ul,[],[{li,[],[{p,[],[<<73,102,32,83,101,116,70,117,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,102,117,110,44,32,116,104,101,32,102,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,115,115,117,109,101,100,32,116,111,32,98,101,32,97,32,115,101,116,46>>]}]},{li,[],[{p,[],[<<73,102,32,83,101,116,70,117,110,32,105,115,32,115,112,101,99,105,102,105,101,100,32,97,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,32,70,117,110,125>>]},<<44,32,70,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,32,118,97,108,117,101,32,105,115,32,97,115,115,117,109,101,100,32,116,111,32,98,101,32,97,110,32,101,120,116,101,114,110,97,108,32,115,101,116,46,32,83,101,108,101,99,116,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,97,115,32,101,120,116,101,114,110,97,108,32,115,101,116,115,32,97,110,100,32,97,115,115,101,109,98,108,105,110,103,32,97,32,110,101,119,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,102,114,111,109,32,97,32,108,105,115,116,32,111,102,32,101,120,116,101,114,110,97,108,32,115,101,116,115,32,105,115,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,32,116,104,97,110,32,109,111,100,105,102,121,105,110,103,32,101,97,99,104,32,101,108,101,109,101,110,116,32,97,115,32,97,32,115,101,116,46,32,72,111,119,101,118,101,114,44,32,116,104,105,115,32,111,112,116,105,109,105,122,97,116,105,111,110,32,99,97,110,32,111,110,108,121,32,98,101,32,117,115,101,100,32,119,104,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,97,114,101,32,97,116,111,109,105,99,32,111,114,32,111,114,100,101,114,101,100,32,115,101,116,115,46,32,73,116,32,109,117,115,116,32,97,108,115,111,32,98,101,32,116,104,101,32,99,97,115,101,32,116,104,97,116,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,101,108,101,109,101,110,116,115,32,109,97,116,99,104,101,115,32,115,111,109,101,32,99,108,97,117,115,101,32,111,102,32,70,117,110,32,40,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,99,114,101,97,116,101,100,32,115,101,116,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32,70,117,110,32,116,111,32,116,104,101,32,116,121,112,101,32,111,102,32,116,104,101,32,103,105,118,101,110,32,115,101,116,41,44,32,97,110,100,32,116,104,97,116,32,70,117,110,32,100,111,101,115,32,110,111,116,104,105,110,103,32,98,117,116,32,115,101,108,101,99,116,105,110,103,44,32,100,117,112,108,105,99,97,116,105,110,103,44,32,111,114,32,114,101,97,114,114,97,110,103,105,110,103,32,112,97,114,116,115,32,111,102,32,116,104,101,32,101,108,101,109,101,110,116,115,46>>]}]},{li,[],[{p,[],[<<83,112,101,99,105,102,121,105,110,103,32,97,32,83,101,116,70,117,110,32,97,115,32,97,110,32,105,110,116,101,103,101,114,32,73,32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,112,101,99,105,102,121,105,110,103,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,88,41,194,160,45,62,32,101,108,101,109,101,110,116,40,73,44,194,160,88,41,194,160,101,110,100,125>>]},<<44,32,98,117,116,32,105,115,32,116,111,32,98,101,32,112,114,101,102,101,114,114,101,100,44,32,97,115,32,105,116,32,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98,108,101,32,116,111,32,104,97,110,100,108,101,32,116,104,105,115,32,99,97,115,101,32,101,118,101,110,32,109,111,114,101,32,101,102,102,105,99,105,101,110,116,108,121,46>>]}]}]},{p,[],[<<69,120,97,109,112,108,101,115,32,111,102,32,83,101,116,70,117,110,115,58>>]},{pre,[],[{code,[],[<<102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,10,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,49,44,32,83,41,32,101,110,100,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,65,41,32,45,62,32,65,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,44,67,125,41,32,45,62,32,123,67,44,65,125,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,44,123,95,44,67,125,125,41,32,45,62,32,67,32,101,110,100,125,10,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,44,123,95,44,123,95,44,69,125,61,67,125,125,41,32,45,62,32,123,69,44,123,69,44,67,125,125,32,101,110,100,125,10,50>>]}]},{p,[],[<<84,104,101,32,111,114,100,101,114,32,105,110,32,119,104,105,99,104,32,97,32,83,101,116,70,117,110,32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32,105,115,32,110,111,116,32,115,112,101,99,105,102,105,101,100,44,32,97,110,100,32,99,97,110,32,99,104,97,110,103,101,32,105,110,32,102,117,116,117,114,101,32,118,101,114,115,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,46>>]},{p,[],[<<84,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,105,115,32,100,111,109,105,110,97,116,101,100,32,98,121,32,116,104,101,32,116,105,109,101,32,105,116,32,116,97,107,101,115,32,116,111,32,115,111,114,116,32,108,105,115,116,115,46,32,87,104,101,110,32,110,111,32,115,111,114,116,105,110,103,32,105,115,32,110,101,101,100,101,100,44,32,116,104,101,32,101,120,101,99,117,116,105,111,110,32,116,105,109,101,32,105,115,32,105,110,32,116,104,101,32,119,111,114,115,116,32,99,97,115,101,32,112,114,111,112,111,114,116,105,111,110,97,108,32,116,111,32,116,104,101,32,115,117,109,32,111,102,32,116,104,101,32,115,105,122,101,115,32,111,102,32,116,104,101,32,105,110,112,117,116,32,97,114,103,117,109,101,110,116,115,32,97,110,100,32,116,104,101,32,114,101,116,117,114,110,101,100,32,118,97,108,117,101,46,32,65,32,102,101,119,32,102,117,110,99,116,105,111,110,115,32,101,120,101,99,117,116,101,32,105,110,32,99,111,110,115,116,97,110,116,32,116,105,109,101,58,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,101,109,112,116,121,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,101,109,112,116,121,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,115,95,115,111,102,115,95,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,115,95,115,111,102,115,95,115,101,116,47,49>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,111,95,101,120,116,101,114,110,97,108,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,111,95,101,120,116,101,114,110,97,108,47,49>>]}]},<<32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<116,121,112,101,47,49>>]}]},<<46>>]},{p,[],[<<84,104,101,32,102,117,110,99,116,105,111,110,115,32,111,102,32,116,104,105,115,32,109,111,100,117,108,101,32,101,120,105,116,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<44,32>>,{code,[],[<<98,97,100,95,102,117,110,99,116,105,111,110>>]},<<44,32,111,114,32>>,{code,[],[<<116,121,112,101,95,109,105,115,109,97,116,99,104>>]},<<32,109,101,115,115,97,103,101,32,119,104,101,110,32,103,105,118,101,110,32,98,97,100,108,121,32,102,111,114,109,101,100,32,97,114,103,117,109,101,110,116,115,32,111,114,32,115,101,116,115,32,116,104,101,32,116,121,112,101,115,32,111,102,32,119,104,105,99,104,32,97,114,101,32,110,111,116,32,99,111,109,112,97,116,105,98,108,101,46>>]},{p,[],[<<87,104,101,110,32,99,111,109,112,97,114,105,110,103,32,101,120,116,101,114,110,97,108,32,115,101,116,115,44,32,111,112,101,114,97,116,111,114,32>>,{code,[],[<<61,61,47,50>>]},<<32,105,115,32,117,115,101,100,46>>]},{h2,[],[<<83,101,101,32,65,108,115,111>>]},{p,[],[{a,[{href,<<115,116,100,108,105,98,58,100,105,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,99,116,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,100,105,103,114,97,112,104>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<100,105,103,114,97,112,104,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,111,114,100,100,105,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,114,100,100,105,99,116,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,111,114,100,115,101,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<111,114,100,115,101,116,115,40,51,41>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,101,116,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[{code,[],[<<115,101,116,115,40,51,41>>]}]}]}]},#{name => <<115,111,102,115>>,otp_doc_vsn => {1,0,0},source => [46,46,47,120,109,108,47,115,111,102,115,46,120,109,108],types => #{{a_function,0} => {attribute,{120,2},type,{a_function,{user_type,{120,23},relation,[]},[]}},{a_set,0} => {attribute,{124,2},opaque,{a_set,{type,{124,20},record,[{atom,{124,22},'Set'}]},[]}},{anyset,0} => {attribute,{117,2},type,{anyset,{type,{117,19},union,[{user_type,{117,19},ordset,[]},{user_type,{117,30},a_set,[]}]},[]}},{binary_relation,0} => {attribute,{118,2},type,{binary_relation,{user_type,{118,28},relation,[]},[]}},{external_set,0} => {attribute,{119,2},type,{external_set,{type,{119,25},term,[]},[]}},{family,0} => {attribute,{121,2},type,{family,{user_type,{121,19},a_function,[]},[]}},{ordset,0} => {attribute,{122,2},opaque,{ordset,{type,{122,21},record,[{atom,{122,23},'OrdSet'}]},[]}},{relation,0} => {attribute,{123,2},type,{relation,{user_type,{123,21},a_set,[]},[]}},{set_fun,0} => {attribute,{126,2},type,{set_fun,{type,{126,20},union,[{type,{126,20},pos_integer,[]},{type,{127,20},tuple,[{atom,{127,21},external},{type,{127,35},'fun',[{type,{127,35},product,[{user_type,{127,36},external_set,[]}]},{user_type,{127,55},external_set,[]}]}]},{type,{128,24},'fun',[{type,{128,24},product,[{user_type,{128,25},anyset,[]}]},{user_type,{128,38},anyset,[]}]}]},[]}},{set_of_sets,0} => {attribute,{125,2},type,{set_of_sets,{user_type,{125,24},a_set,[]},[]}},{spec_fun,0} => {attribute,{129,2},type,{spec_fun,{type,{129,21},union,[{type,{129,21},tuple,[{atom,{129,22},external},{type,{129,36},'fun',[{type,{129,36},product,[{user_type,{129,37},external_set,[]}]},{type,{129,56},boolean,[]}]}]},{type,{130,25},'fun',[{type,{130,25},product,[{user_type,{130,26},anyset,[]}]},{type,{130,39},boolean,[]}]}]},[]}},{tuple_of,1} => {attribute,{133,2},type,{tuple_of,{type,{133,23},tuple,any},[{var,{133,16},'_T'}]}},{type,0} => {attribute,{131,2},type,{type,{type,{131,17},term,[]},[]}}}},[{{function,fam2rel,1},[{file,[115,111,102,115,46,101,114,108]},{location,0}],[<<102,97,109,50,114,101,108,47,49>>],hidden,#{}},{{function,rel2fam,1},[{file,[115,111,102,115,46,101,114,108]},{location,0}],[<<114,101,108,50,102,97,109,47,49>>],hidden,#{}},{{function,a_function,2},[{file,[115,111,102,115,46,101,114,108]},{location,277}],[<<97,95,102,117,110,99,116,105,111,110,47,50>>],#{},#{signature => [{attribute,{277,2},spec,{{a_function,2},[{type,{277,17},bounded_fun,[{type,{277,17},'fun',[{type,{277,17},product,[{var,{277,18},'Tuples'},{var,{277,26},'Type'}]},{var,{277,35},'Function'}]},[{type,{278,7},constraint,[{atom,{278,7},is_subtype},[{var,{278,7},'Function'},{user_type,{278,19},a_function,[]}]]},{type,{279,7},constraint,[{atom,{279,7},is_subtype},[{var,{279,7},'Tuples'},{type,{279,17},list,[{type,{279,18},tuple,any}]}]]},{type,{280,7},constraint,[{atom,{280,7},is_subtype},[{var,{280,7},'Type'},{user_type,{280,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,54,54>>,equiv => {function,a_function,1}}},{{function,a_function,1},[{file,[115,111,102,115,46,101,114,108]},{location,265}],[<<97,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<46,32>>,{code,[],[<<97,95,102,117,110,99,116,105,111,110,40,70,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,70,44,194,160,84,41>>]},<<32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,102,117,110,99,116,105,111,110,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,97,116,111,109,125,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,102,117,110,99,116,105,111,110,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{265,2},spec,{{a_function,1},[{type,{265,17},bounded_fun,[{type,{265,17},'fun',[{type,{265,17},product,[{var,{265,18},'Tuples'}]},{var,{265,29},'Function'}]},[{type,{266,7},constraint,[{atom,{266,7},is_subtype},[{var,{266,7},'Function'},{user_type,{266,19},a_function,[]}]]},{type,{267,7},constraint,[{atom,{267,7},is_subtype},[{var,{267,7},'Tuples'},{type,{267,17},list,[{type,{267,18},tuple,any}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,54,54>>}},{{function,canonical_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,577}],[<<99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,40,69,44,194,160,83,101,116,41,32,115,117,99,104,32,116,104,97,116,32,83,101,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,97,110,100,32,69,32,98,101,108,111,110,103,115,32,116,111,32,83,101,116,46,32,73,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,97,32,115,101,116,32,88,32,97,110,100,32,82,32,105,115,32,116,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,114,101,108,97,116,105,111,110,32,105,110,32,88,32,105,110,100,117,99,101,100,32,98,121,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<44,32,116,104,101,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,114,101,108,97,116,105,111,110,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,97,110,111,110,105,99,97,108,95,109,97,112>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,97,110,111,110,105,99,97,108,32,109,97,112>>]},<<32,102,114,111,109,32,88,32,111,110,116,111,32,116,104,101,32,101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115,101,115,32,119,105,116,104,32,114,101,115,112,101,99,116,32,116,111,32,82,46>>]},{pre,[],[{code,[],[<<49,62,32,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,44,98,93,44,91,98,44,99,93,93,41,44,10,67,82,32,61,32,115,111,102,115,58,99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,40,83,115,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,67,82,41,46,10,91,123,97,44,91,97,44,98,93,125,44,123,98,44,91,97,44,98,93,125,44,123,98,44,91,98,44,99,93,125,44,123,99,44,91,98,44,99,93,125,93>>]}]}]},#{signature => [{attribute,{577,2},spec,{{canonical_relation,1},[{type,{577,25},bounded_fun,[{type,{577,25},'fun',[{type,{577,25},product,[{var,{577,26},'SetOfSets'}]},{var,{577,40},'BinRel'}]},[{type,{578,7},constraint,[{atom,{578,7},is_subtype},[{var,{578,7},'BinRel'},{user_type,{578,17},binary_relation,[]}]]},{type,{579,7},constraint,[{atom,{579,7},is_subtype},[{var,{579,7},'SetOfSets'},{user_type,{579,20},set_of_sets,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,52,56,48>>}},{{function,composite,2},[{file,[115,111,102,115,46,101,114,108]},{location,844}],[<<99,111,109,112,111,115,105,116,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,109,112,111,115,105,116,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,109,112,111,115,105,116,101>>]},<<32,111,102,32,116,104,101,32,102,117,110,99,116,105,111,110,115,32>>,{code,[],[<<70,117,110,99,116,105,111,110,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,117,110,99,116,105,111,110,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,97,95,102,117,110,99,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,50,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,97,95,102,117,110,99,116,105,111,110,40,91,123,49,44,120,125,44,123,50,44,121,125,44,123,51,44,122,125,93,41,44,10,70,32,61,32,115,111,102,115,58,99,111,109,112,111,115,105,116,101,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,120,125,44,123,98,44,121,125,44,123,99,44,121,125,93>>]}]}]},#{signature => [{attribute,{844,2},spec,{{composite,2},[{type,{844,16},bounded_fun,[{type,{844,16},'fun',[{type,{844,16},product,[{var,{844,17},'Function1'},{var,{844,28},'Function2'}]},{var,{844,42},'Function3'}]},[{type,{845,7},constraint,[{atom,{845,7},is_subtype},[{var,{845,7},'Function1'},{user_type,{845,20},a_function,[]}]]},{type,{846,7},constraint,[{atom,{846,7},is_subtype},[{var,{846,7},'Function2'},{user_type,{846,20},a_function,[]}]]},{type,{847,7},constraint,[{atom,{847,7},is_subtype},[{var,{847,7},'Function3'},{user_type,{847,20},a_function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,48,48>>}},{{function,constant_function,2},[{file,[115,111,102,115,46,101,114,108]},{location,465}],[<<99,111,110,115,116,97,110,116,95,102,117,110,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<32,116,104,97,116,32,109,97,112,115,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32,115,101,116,32>>,{code,[],[<<83,101,116>>]},<<32,111,110,116,111,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,69,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,49,41,44,10,82,32,61,32,115,111,102,115,58,99,111,110,115,116,97,110,116,95,102,117,110,99,116,105,111,110,40,83,44,32,69,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,97,44,49,125,44,123,98,44,49,125,93>>]}]}]},#{signature => [{attribute,{465,2},spec,{{constant_function,2},[{type,{465,24},bounded_fun,[{type,{465,24},'fun',[{type,{465,24},product,[{var,{465,25},'Set'},{var,{465,30},'AnySet'}]},{var,{465,41},'Function'}]},[{type,{466,7},constraint,[{atom,{466,7},is_subtype},[{var,{466,7},'AnySet'},{user_type,{466,17},anyset,[]}]]},{type,{467,7},constraint,[{atom,{467,7},is_subtype},[{var,{467,7},'Function'},{user_type,{467,19},a_function,[]}]]},{type,{468,7},constraint,[{atom,{468,7},is_subtype},[{var,{468,7},'Set'},{user_type,{468,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,49,54>>}},{{function,converse,1},[{file,[115,111,102,115,46,101,114,108]},{location,707}],[<<99,111,110,118,101,114,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,97,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,99,111,110,118,101,114,115,101,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,97,44,49,125,44,123,97,44,51,125,44,123,98,44,50,125,93>>]}]}]},#{signature => [{attribute,{707,2},spec,{{converse,1},[{type,{707,15},bounded_fun,[{type,{707,15},'fun',[{type,{707,15},product,[{var,{707,16},'BinRel1'}]},{var,{707,28},'BinRel2'}]},[{type,{708,7},constraint,[{atom,{708,7},is_subtype},[{var,{708,7},'BinRel1'},{user_type,{708,18},binary_relation,[]}]]},{type,{709,7},constraint,[{atom,{709,7},is_subtype},[{var,{709,7},'BinRel2'},{user_type,{709,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,51,50>>}},{{function,difference,2},[{file,[115,111,102,115,46,101,114,108]},{location,398}],[<<100,105,102,102,101,114,101,110,99,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,102,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,102,102,101,114,101,110,99,101>>]},<<32,111,102,32,116,104,101,32,115,101,116,115,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{signature => [{attribute,{398,2},spec,{{difference,2},[{type,{398,17},bounded_fun,[{type,{398,17},'fun',[{type,{398,17},product,[{var,{398,18},'Set1'},{var,{398,24},'Set2'}]},{var,{398,33},'Set3'}]},[{type,{399,7},constraint,[{atom,{399,7},is_subtype},[{var,{399,7},'Set1'},{user_type,{399,15},a_set,[]}]]},{type,{400,7},constraint,[{atom,{400,7},is_subtype},[{var,{400,7},'Set2'},{user_type,{400,15},a_set,[]}]]},{type,{401,7},constraint,[{atom,{401,7},is_subtype},[{var,{401,7},'Set3'},{user_type,{401,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,52,54>>}},{{function,digraph_to_family,2},[{file,[115,111,102,115,46,101,114,108]},{location,1520}],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,47,50>>],#{},#{signature => [{attribute,{1520,2},spec,{{digraph_to_family,2},[{type,{1520,24},bounded_fun,[{type,{1520,24},'fun',[{type,{1520,24},product,[{var,{1520,25},'Graph'},{var,{1520,32},'Type'}]},{var,{1520,41},'Family'}]},[{type,{1521,7},constraint,[{atom,{1521,7},is_subtype},[{var,{1521,7},'Graph'},{remote_type,{1521,16},[{atom,{1521,16},digraph},{atom,{1521,24},graph},[]]}]]},{type,{1522,7},constraint,[{atom,{1522,7},is_subtype},[{var,{1522,7},'Family'},{user_type,{1522,17},family,[]}]]},{type,{1523,7},constraint,[{atom,{1523,7},is_subtype},[{var,{1523,7},'Type'},{user_type,{1523,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,53,53>>,equiv => {function,digraph_to_family,1}}},{{function,digraph_to_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1511}],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,102,114,111,109,32,116,104,101,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,32>>,{code,[],[<<71,114,97,112,104>>]},<<46,32,69,97,99,104,32,118,101,114,116,101,120,32,97,32,111,102,32>>,{code,[],[<<71,114,97,112,104>>]},<<32,105,115,32,114,101,112,114,101,115,101,110,116,101,100,32,98,121,32,97,32,112,97,105,114,32,40,97,44,194,160,123,98,91,49,93,44,194,160,46,46,46,44,194,160,98,91,110,93,125,41,44,32,119,104,101,114,101,32,116,104,101,32,98,91,105,93,58,115,32,97,114,101,32,116,104,101,32,111,117,116,45,110,101,105,103,104,98,111,114,115,32,111,102,32,97,46,32,73,102,32,110,111,32,116,121,112,101,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32,91,123,97,116,111,109,44,194,160,91,97,116,111,109,93,125,93,32,105,115,32,117,115,101,100,32,97,115,32,116,121,112,101,32,111,102,32,116,104,101,32,102,97,109,105,108,121,46,32,73,116,32,105,115,32,97,115,115,117,109,101,100,32,116,104,97,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32,116,104,101,32,101,120,116,101,114,110,97,108,32,115,101,116,32,111,102,32,116,104,101,32,102,97,109,105,108,121,46>>]},{p,[],[<<73,102,32,71,32,105,115,32,97,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,44,32,105,116,32,104,111,108,100,115,32,116,104,97,116,32,116,104,101,32,118,101,114,116,105,99,101,115,32,97,110,100,32,101,100,103,101,115,32,111,102,32,71,32,97,114,101,32,116,104,101,32,115,97,109,101,32,97,115,32,116,104,101,32,118,101,114,116,105,99,101,115,32,97,110,100,32,101,100,103,101,115,32,111,102,32>>,{code,[],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,40,100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,40,71,41,41>>]},<<46>>]}]},#{signature => [{attribute,{1511,2},spec,{{digraph_to_family,1},[{type,{1511,24},bounded_fun,[{type,{1511,24},'fun',[{type,{1511,24},product,[{var,{1511,25},'Graph'}]},{var,{1511,35},'Family'}]},[{type,{1512,7},constraint,[{atom,{1512,7},is_subtype},[{var,{1512,7},'Graph'},{remote_type,{1512,16},[{atom,{1512,16},digraph},{atom,{1512,24},graph},[]]}]]},{type,{1513,7},constraint,[{atom,{1513,7},is_subtype},[{var,{1513,7},'Family'},{user_type,{1513,17},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,53,53>>}},{{function,domain,1},[{file,[115,111,102,115,46,101,114,108]},{location,612}],[<<100,111,109,97,105,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,100,111,109,97,105,110,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,49,44,50,93>>]}]}]},#{signature => [{attribute,{612,2},spec,{{domain,1},[{type,{612,13},bounded_fun,[{type,{612,13},'fun',[{type,{612,13},product,[{var,{612,14},'BinRel'}]},{var,{612,25},'Set'}]},[{type,{613,7},constraint,[{atom,{613,7},is_subtype},[{var,{613,7},'BinRel'},{user_type,{613,17},binary_relation,[]}]]},{type,{614,7},constraint,[{atom,{614,7},is_subtype},[{var,{614,7},'Set'},{user_type,{614,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,55,53>>}},{{function,drestriction,2},[{file,[115,111,102,115,46,101,114,108]},{location,833}],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,116,111,32>>,{code,[],[<<83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,52,44,54,93,41,44,10,82,50,32,61,32,115,111,102,115,58,100,114,101,115,116,114,105,99,116,105,111,110,40,82,49,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,97,125,44,123,51,44,99,125,93>>]}]},{p,[],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,40,82,44,194,160,83,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<100,105,102,102,101,114,101,110,99,101,40,82,44,194,160,114,101,115,116,114,105,99,116,105,111,110,40,82,44,194,160,83,41,41>>]},<<46>>]}]},#{signature => [{attribute,{833,2},spec,{{drestriction,2},[{type,{833,19},bounded_fun,[{type,{833,19},'fun',[{type,{833,19},product,[{var,{833,20},'BinRel1'},{var,{833,29},'Set'}]},{var,{833,37},'BinRel2'}]},[{type,{834,7},constraint,[{atom,{834,7},is_subtype},[{var,{834,7},'BinRel1'},{user_type,{834,18},binary_relation,[]}]]},{type,{835,7},constraint,[{atom,{835,7},is_subtype},[{var,{835,7},'BinRel2'},{user_type,{835,18},binary_relation,[]}]]},{type,{836,7},constraint,[{atom,{836,7},is_subtype},[{var,{836,7},'Set'},{user_type,{836,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,53,56,57>>}},{{function,drestriction,3},[{file,[115,111,102,115,46,101,114,108]},{location,960}],[<<100,114,101,115,116,114,105,99,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,100,111,32,110,111,116,32,103,105,118,101,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,95,65,44,66,44,67,125,41,32,45,62,32,123,66,44,67,125,32,101,110,100,125,44,10,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,97,97,44,49,125,44,123,98,44,98,98,44,50,125,44,123,99,44,99,99,44,51,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,98,98,44,50,125,44,123,99,99,44,51,125,44,123,100,100,44,52,125,93,41,44,10,82,51,32,61,32,115,111,102,115,58,100,114,101,115,116,114,105,99,116,105,111,110,40,83,101,116,70,117,110,44,32,82,49,44,32,82,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,46,10,91,123,97,44,97,97,44,49,125,93>>]}]},{p,[],[{code,[],[<<100,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<100,105,102,102,101,114,101,110,99,101,40,83,49,44,194,160,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,41>>]},<<46>>]}]},#{signature => [{attribute,{960,2},spec,{{drestriction,3},[{type,{960,19},bounded_fun,[{type,{960,19},'fun',[{type,{960,19},product,[{var,{960,20},'SetFun'},{var,{960,28},'Set1'},{var,{960,34},'Set2'}]},{var,{960,43},'Set3'}]},[{type,{961,7},constraint,[{atom,{961,7},is_subtype},[{var,{961,7},'SetFun'},{user_type,{961,17},set_fun,[]}]]},{type,{962,7},constraint,[{atom,{962,7},is_subtype},[{var,{962,7},'Set1'},{user_type,{962,15},a_set,[]}]]},{type,{963,7},constraint,[{atom,{963,7},is_subtype},[{var,{963,7},'Set2'},{user_type,{963,15},a_set,[]}]]},{type,{964,7},constraint,[{atom,{964,7},is_subtype},[{var,{964,7},'Set3'},{user_type,{964,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,48,56>>}},{{function,empty_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,178}],[<<101,109,112,116,121,95,115,101,116,47,48>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116>>]},<<46,32>>,{code,[],[<<101,109,112,116,121,95,115,101,116,40,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,91,93,44,194,160,91,39,95,39,93,41>>]},<<46>>]}]},#{signature => [{attribute,{178,2},spec,{{empty_set,0},[{type,{178,16},bounded_fun,[{type,{178,16},'fun',[{type,{178,16},product,[]},{var,{178,22},'Set'}]},[{type,{179,7},constraint,[{atom,{179,7},is_subtype},[{var,{179,7},'Set'},{user_type,{179,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,50,56>>}},{{function,extension,3},[{file,[115,111,102,115,46,101,114,108]},{location,779}],[<<101,120,116,101,110,115,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,110,115,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,110,115,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,115,117,99,104,32,116,104,97,116,32,102,111,114,32,101,97,99,104,32,101,108,101,109,101,110,116,32,69,32,105,110,32>>,{code,[],[<<83,101,116>>]},<<32,116,104,97,116,32,100,111,101,115,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<44,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,112,97,105,114,32,40,69,44,194,160>>,{code,[],[<<65,110,121,83,101,116>>]},<<41,46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,115,101,116,40,91,98,44,99,93,41,44,10,65,32,61,32,115,111,102,115,58,101,109,112,116,121,95,115,101,116,40,41,44,10,82,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,93,41,44,10,88,32,61,32,115,111,102,115,58,101,120,116,101,110,115,105,111,110,40,82,44,32,83,44,32,65,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,88,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,44,123,99,44,91,93,125,93>>]}]}]},#{signature => [{attribute,{779,2},spec,{{extension,3},[{type,{779,16},bounded_fun,[{type,{779,16},'fun',[{type,{779,16},product,[{var,{779,17},'BinRel1'},{var,{779,26},'Set'},{var,{779,31},'AnySet'}]},{var,{779,42},'BinRel2'}]},[{type,{780,7},constraint,[{atom,{780,7},is_subtype},[{var,{780,7},'AnySet'},{user_type,{780,17},anyset,[]}]]},{type,{781,7},constraint,[{atom,{781,7},is_subtype},[{var,{781,7},'BinRel1'},{user_type,{781,18},binary_relation,[]}]]},{type,{782,7},constraint,[{atom,{782,7},is_subtype},[{var,{782,7},'BinRel2'},{user_type,{782,18},binary_relation,[]}]]},{type,{783,7},constraint,[{atom,{783,7},is_subtype},[{var,{783,7},'Set'},{user_type,{783,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,51,56>>}},{{function,family,2},[{file,[115,111,102,115,46,101,114,108]},{location,302}],[<<102,97,109,105,108,121,47,50>>],#{},#{signature => [{attribute,{302,2},spec,{{family,2},[{type,{302,13},bounded_fun,[{type,{302,13},'fun',[{type,{302,13},product,[{var,{302,14},'Tuples'},{var,{302,22},'Type'}]},{var,{302,31},'Family'}]},[{type,{303,7},constraint,[{atom,{303,7},is_subtype},[{var,{303,7},'Family'},{user_type,{303,17},family,[]}]]},{type,{304,7},constraint,[{atom,{304,7},is_subtype},[{var,{304,7},'Tuples'},{type,{304,17},list,[{type,{304,18},tuple,any}]}]]},{type,{305,7},constraint,[{atom,{305,7},is_subtype},[{var,{305,7},'Type'},{user_type,{305,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,53,56>>,equiv => {function,family,1}}},{{function,family,1},[{file,[115,111,102,115,46,101,114,108]},{location,290}],[<<102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121,32,111,102,32,115,117,98,115,101,116,115>>]},<<46,32>>,{code,[],[<<102,97,109,105,108,121,40,70,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,70,44,194,160,84,41>>]},<<32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,102,97,109,105,108,121,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,91,97,116,111,109,93,125,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,102,97,109,105,108,121,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{290,2},spec,{{family,1},[{type,{290,13},bounded_fun,[{type,{290,13},'fun',[{type,{290,13},product,[{var,{290,14},'Tuples'}]},{var,{290,25},'Family'}]},[{type,{291,7},constraint,[{atom,{291,7},is_subtype},[{var,{291,7},'Family'},{user_type,{291,17},family,[]}]]},{type,{292,7},constraint,[{atom,{292,7},is_subtype},[{var,{292,7},'Tuples'},{type,{292,17},list,[{type,{292,18},tuple,any}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,53,56>>}},{{function,family_difference,2},[{file,[115,111,102,115,46,101,114,108]},{location,1385}],[<<102,97,109,105,108,121,95,100,105,102,102,101,114,101,110,99,101,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,101,113,117,97,108,32,116,111,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98,101,116,119,101,101,110,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,102,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,109,97,112,115,32,105,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,97,109,105,108,121,49,91,105,93>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,54,44,55,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,100,105,102,102,101,114,101,110,99,101,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,93,125,93>>]}]}]},#{signature => [{attribute,{1385,2},spec,{{family_difference,2},[{type,{1385,24},bounded_fun,[{type,{1385,24},'fun',[{type,{1385,24},product,[{var,{1385,25},'Family1'},{var,{1385,34},'Family2'}]},{var,{1385,46},'Family3'}]},[{type,{1386,7},constraint,[{atom,{1386,7},is_subtype},[{var,{1386,7},'Family1'},{user_type,{1386,18},family,[]}]]},{type,{1387,7},constraint,[{atom,{1387,7},is_subtype},[{var,{1387,7},'Family2'},{user_type,{1387,18},family,[]}]]},{type,{1388,7},constraint,[{atom,{1388,7},is_subtype},[{var,{1388,7},'Family3'},{user_type,{1388,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,55,50>>}},{{function,family_domain,1},[{file,[115,111,102,115,46,101,114,108]},{location,1341}],[<<102,97,109,105,108,121,95,100,111,109,97,105,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49,91,105,93>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,100,111,109,97,105,110,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,44,123,99,44,91,52,44,53,93,125,93>>]}]}]},#{signature => [{attribute,{1341,2},spec,{{family_domain,1},[{type,{1341,20},bounded_fun,[{type,{1341,20},'fun',[{type,{1341,20},product,[{var,{1341,21},'Family1'}]},{var,{1341,33},'Family2'}]},[{type,{1342,7},constraint,[{atom,{1342,7},is_subtype},[{var,{1342,7},'Family1'},{user_type,{1342,18},family,[]}]]},{type,{1343,7},constraint,[{atom,{1343,7},is_subtype},[{var,{1343,7},'Family2'},{user_type,{1343,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,54,57,51>>}},{{function,family_field,1},[{file,[115,111,102,115,46,101,114,108]},{location,1365}],[<<102,97,109,105,108,121,95,102,105,101,108,100,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,102,105,101,108,100,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,49,44,50,44,51,44,97,44,98,44,99,93,125,44,123,98,44,91,93,125,44,123,99,44,91,52,44,53,44,100,44,101,93,125,93>>]}]},{p,[],[{code,[],[<<102,97,109,105,108,121,95,102,105,101,108,100,40,70,97,109,105,108,121,49,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,97,109,105,108,121,95,117,110,105,111,110,40,102,97,109,105,108,121,95,100,111,109,97,105,110,40,70,97,109,105,108,121,49,41,44,32,102,97,109,105,108,121,95,114,97,110,103,101,40,70,97,109,105,108,121,49,41,41>>]},<<46>>]}]},#{signature => [{attribute,{1365,2},spec,{{family_field,1},[{type,{1365,19},bounded_fun,[{type,{1365,19},'fun',[{type,{1365,19},product,[{var,{1365,20},'Family1'}]},{var,{1365,32},'Family2'}]},[{type,{1366,7},constraint,[{atom,{1366,7},is_subtype},[{var,{1366,7},'Family1'},{user_type,{1366,18},family,[]}]]},{type,{1367,7},constraint,[{atom,{1367,7},is_subtype},[{var,{1367,7},'Family2'},{user_type,{1367,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,49,52>>}},{{function,family_intersection,1},[{file,[115,111,102,115,46,101,114,108]},{location,1325}],[<<102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,110,32,101,109,112,116,121,32,115,101,116,32,102,111,114,32,115,111,109,101,32,105,44,32,116,104,101,32,112,114,111,99,101,115,115,32,101,120,105,116,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,44,51,93,44,91,50,44,51,44,52,93,93,125,44,123,98,44,91,91,120,44,121,44,122,93,44,91,120,44,121,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,40,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,50,44,51,93,125,44,123,98,44,91,120,44,121,93,125,93>>]}]}]},#{signature => [{attribute,{1325,2},spec,{{family_intersection,1},[{type,{1325,26},bounded_fun,[{type,{1325,26},'fun',[{type,{1325,26},product,[{var,{1325,27},'Family1'}]},{var,{1325,39},'Family2'}]},[{type,{1326,7},constraint,[{atom,{1326,7},is_subtype},[{var,{1326,7},'Family1'},{user_type,{1326,18},family,[]}]]},{type,{1327,7},constraint,[{atom,{1327,7},is_subtype},[{var,{1327,7},'Family2'},{user_type,{1327,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,51,56>>}},{{function,family_intersection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1378}],[<<102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<58,115,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<58,115,32,105,110,100,101,120,32,115,101,116,115,44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,44,123,99,44,91,53,44,54,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,105,110,116,101,114,115,101,99,116,105,111,110,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,98,44,91,52,93,125,44,123,99,44,91,93,125,93>>]}]}]},#{signature => [{attribute,{1378,2},spec,{{family_intersection,2},[{type,{1378,26},bounded_fun,[{type,{1378,26},'fun',[{type,{1378,26},product,[{var,{1378,27},'Family1'},{var,{1378,36},'Family2'}]},{var,{1378,48},'Family3'}]},[{type,{1379,7},constraint,[{atom,{1379,7},is_subtype},[{var,{1379,7},'Family1'},{user_type,{1379,18},family,[]}]]},{type,{1380,7},constraint,[{atom,{1380,7},is_subtype},[{var,{1380,7},'Family2'},{user_type,{1380,18},family,[]}]]},{type,{1381,7},constraint,[{atom,{1381,7},is_subtype},[{var,{1381,7},'Family3'},{user_type,{1381,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,54,50>>}},{{function,family_projection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1451}],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,99,97,108,108,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,119,105,116,104,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,115,32,97,114,103,117,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,93,44,91,50,44,51,93,93,125,44,123,98,44,91,91,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,40,102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,44,32,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,93>>]}]}]},#{signature => [{attribute,{1451,2},spec,{{family_projection,2},[{type,{1451,24},bounded_fun,[{type,{1451,24},'fun',[{type,{1451,24},product,[{var,{1451,25},'SetFun'},{var,{1451,33},'Family1'}]},{var,{1451,45},'Family2'}]},[{type,{1452,7},constraint,[{atom,{1452,7},is_subtype},[{var,{1452,7},'SetFun'},{user_type,{1452,17},set_fun,[]}]]},{type,{1453,7},constraint,[{atom,{1453,7},is_subtype},[{var,{1453,7},'Family1'},{user_type,{1453,18},family,[]}]]},{type,{1454,7},constraint,[{atom,{1454,7},is_subtype},[{var,{1454,7},'Family2'},{user_type,{1454,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,55,56,50>>}},{{function,family_range,1},[{file,[115,111,102,115,46,101,114,108]},{location,1353}],[<<102,97,109,105,108,121,95,114,97,110,103,101,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,102,111,114,32,101,118,101,114,121,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,97,110,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,97,110,103,101>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,82,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,125,44,123,98,44,91,93,125,44,123,99,44,91,123,52,44,100,125,44,123,53,44,101,125,93,125,93,41,44,10,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,114,97,110,103,101,40,70,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,97,44,91,97,44,98,44,99,93,125,44,123,98,44,91,93,125,44,123,99,44,91,100,44,101,93,125,93>>]}]}]},#{signature => [{attribute,{1353,2},spec,{{family_range,1},[{type,{1353,19},bounded_fun,[{type,{1353,19},'fun',[{type,{1353,19},product,[{var,{1353,20},'Family1'}]},{var,{1353,32},'Family2'}]},[{type,{1354,7},constraint,[{atom,{1354,7},is_subtype},[{var,{1354,7},'Family1'},{user_type,{1354,18},family,[]}]]},{type,{1355,7},constraint,[{atom,{1355,7},is_subtype},[{var,{1355,7},'Family2'},{user_type,{1355,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,48,49>>}},{{function,family_specification,2},[{file,[115,111,102,115,46,101,114,108]},{location,1265}],[<<102,97,109,105,108,121,95,115,112,101,99,105,102,105,99,97,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,116,111,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,105,32,111,102,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,102,111,114,32,119,104,105,99,104,32>>,{code,[],[<<70,117,110>>]},<<32,97,112,112,108,105,101,100,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,50,125>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,117,110,50>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,49,44,50,93,125,44,123,99,44,91,49,93,125,93,41,44,10,83,112,101,99,70,117,110,32,61,32,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,110,111,95,101,108,101,109,101,110,116,115,40,83,41,32,61,58,61,32,50,32,101,110,100,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,115,112,101,99,105,102,105,99,97,116,105,111,110,40,83,112,101,99,70,117,110,44,32,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,98,44,91,49,44,50,93,125,93>>]}]}]},#{signature => [{attribute,{1265,2},spec,{{family_specification,2},[{type,{1265,27},bounded_fun,[{type,{1265,27},'fun',[{type,{1265,27},product,[{var,{1265,28},'Fun'},{var,{1265,33},'Family1'}]},{var,{1265,45},'Family2'}]},[{type,{1266,7},constraint,[{atom,{1266,7},is_subtype},[{var,{1266,7},'Fun'},{user_type,{1266,14},spec_fun,[]}]]},{type,{1267,7},constraint,[{atom,{1267,7},is_subtype},[{var,{1267,7},'Family1'},{user_type,{1267,18},family,[]}]]},{type,{1268,7},constraint,[{atom,{1268,7},is_subtype},[{var,{1268,7},'Family2'},{user_type,{1268,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,50,50>>}},{{function,family_to_digraph,2},[{file,[115,111,102,115,46,101,114,108]},{location,1489}],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,47,50>>],#{},#{signature => [{attribute,{1489,2},spec,{{family_to_digraph,2},[{type,{1489,24},bounded_fun,[{type,{1489,24},'fun',[{type,{1489,24},product,[{var,{1489,25},'Family'},{var,{1489,33},'GraphType'}]},{var,{1489,47},'Graph'}]},[{type,{1490,7},constraint,[{atom,{1490,7},is_subtype},[{var,{1490,7},'Graph'},{remote_type,{1490,16},[{atom,{1490,16},digraph},{atom,{1490,24},graph},[]]}]]},{type,{1491,7},constraint,[{atom,{1491,7},is_subtype},[{var,{1491,7},'Family'},{user_type,{1491,17},family,[]}]]},{type,{1492,7},constraint,[{atom,{1492,7},is_subtype},[{var,{1492,7},'GraphType'},{type,{1492,20},list,[{remote_type,{1492,21},[{atom,{1492,21},digraph},{atom,{1492,29},d_type},[]]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,52,55>>,equiv => {function,family_to_digraph,1}}},{{function,family_to_digraph,1},[{file,[115,111,102,115,46,101,114,108]},{location,1479}],[<<102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,32,102,114,111,109,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46,32,70,111,114,32,101,97,99,104,32,112,97,105,114,32,40,97,44,194,160,123,98,91,49,93,44,194,160,46,46,46,44,194,160,98,91,110,93,125,41,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<44,32,118,101,114,116,101,120,32,97,32,97,110,100,32,116,104,101,32,101,100,103,101,115,32,40,97,44,194,160,98,91,105,93,41,32,102,111,114,32,49,194,160,60,61,194,160,105,194,160,60,61,194,160,110,32,97,114,101,32,97,100,100,101,100,32,116,111,32,97,32,110,101,119,108,121,32,99,114,101,97,116,101,100,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,46>>]},{p,[],[<<73,102,32,110,111,32,103,114,97,112,104,32,116,121,112,101,32,105,115,32,115,112,101,99,105,102,105,101,100,44,32>>,{a,[{href,<<115,116,100,108,105,98,58,100,105,103,114,97,112,104,35,110,101,119,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,105,103,114,97,112,104,58,110,101,119,47,48>>]}]},<<32,105,115,32,117,115,101,100,32,102,111,114,32,99,114,101,97,116,105,110,103,32,116,104,101,32,100,105,114,101,99,116,101,100,32,103,114,97,112,104,44,32,111,116,104,101,114,119,105,115,101,32,97,114,103,117,109,101,110,116,32>>,{code,[],[<<71,114,97,112,104,84,121,112,101>>]},<<32,105,115,32,112,97,115,115,101,100,32,111,110,32,97,115,32,115,101,99,111,110,100,32,97,114,103,117,109,101,110,116,32,116,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,100,105,103,114,97,112,104,35,110,101,119,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<100,105,103,114,97,112,104,58,110,101,119,47,49>>]}]},<<46>>]},{p,[],[<<73,116,32,70,32,105,115,32,97,32,102,97,109,105,108,121,44,32,105,116,32,104,111,108,100,115,32,116,104,97,116,32,70,32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<100,105,103,114,97,112,104,95,116,111,95,102,97,109,105,108,121,40,102,97,109,105,108,121,95,116,111,95,100,105,103,114,97,112,104,40,70,41,44,194,160,116,121,112,101,40,70,41,41>>]},<<46,32,69,113,117,97,108,105,116,121,32,104,111,108,100,115,32,105,102,32>>,{code,[],[<<117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41>>]},<<32,105,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<100,111,109,97,105,110,40,70,41>>]},<<46>>]},{p,[],[<<67,114,101,97,116,105,110,103,32,97,32,99,121,99,108,101,32,105,110,32,97,110,32,97,99,121,99,108,105,99,32,103,114,97,112,104,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<99,121,99,108,105,99>>]},<<32,109,101,115,115,97,103,101,46>>]}]},#{signature => [{attribute,{1479,2},spec,{{family_to_digraph,1},[{type,{1479,24},bounded_fun,[{type,{1479,24},'fun',[{type,{1479,24},product,[{var,{1479,25},'Family'}]},{var,{1479,36},'Graph'}]},[{type,{1480,7},constraint,[{atom,{1480,7},is_subtype},[{var,{1480,7},'Graph'},{remote_type,{1480,16},[{atom,{1480,16},digraph},{atom,{1480,24},graph},[]]}]]},{type,{1481,7},constraint,[{atom,{1481,7},is_subtype},[{var,{1481,7},'Family'},{user_type,{1481,17},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,52,55>>}},{{function,family_to_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,1253}],[<<102,97,109,105,108,121,95,116,111,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32,99,111,110,116,97,105,110,105,110,103,32,97,108,108,32,112,97,105,114,115,32,40,105,44,194,160,120,41,32,115,117,99,104,32,116,104,97,116,32,105,32,98,101,108,111,110,103,115,32,116,111,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,97,110,100,32,120,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,93,125,44,32,123,98,44,91,49,93,125,44,32,123,99,44,91,50,44,51,93,125,93,41,44,10,82,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,116,111,95,114,101,108,97,116,105,111,110,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,98,44,49,125,44,123,99,44,50,125,44,123,99,44,51,125,93>>]}]}]},#{signature => [{attribute,{1253,2},spec,{{family_to_relation,1},[{type,{1253,25},bounded_fun,[{type,{1253,25},'fun',[{type,{1253,25},product,[{var,{1253,26},'Family'}]},{var,{1253,37},'BinRel'}]},[{type,{1254,7},constraint,[{atom,{1254,7},is_subtype},[{var,{1254,7},'Family'},{user_type,{1254,17},family,[]}]]},{type,{1255,7},constraint,[{atom,{1255,7},is_subtype},[{var,{1255,7},'BinRel'},{user_type,{1255,17},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,55,51>>}},{{function,family_union,1},[{file,[115,111,102,115,46,101,114,108]},{location,1314}],[<<102,97,109,105,108,121,95,117,110,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,105,115,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,102,111,114,32,101,97,99,104,32,105,32,105,110,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,119,105,116,104,32,116,104,101,32,115,97,109,101,32,105,110,100,101,120,32,115,101,116,32,97,115,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,115,117,99,104,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,97,44,91,91,49,44,50,93,44,91,50,44,51,93,93,125,44,123,98,44,91,91,93,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,117,110,105,111,110,40,70,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,50,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,93,125,93>>]}]},{p,[],[{code,[],[<<102,97,109,105,108,121,95,117,110,105,111,110,40,70,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,97,109,105,108,121,95,112,114,111,106,101,99,116,105,111,110,40,102,117,110,32,115,111,102,115,58,117,110,105,111,110,47,49,44,194,160,70,41>>]},<<46>>]}]},#{signature => [{attribute,{1314,2},spec,{{family_union,1},[{type,{1314,19},bounded_fun,[{type,{1314,19},'fun',[{type,{1314,19},product,[{var,{1314,20},'Family1'}]},{var,{1314,32},'Family2'}]},[{type,{1315,7},constraint,[{atom,{1315,7},is_subtype},[{var,{1315,7},'Family1'},{user_type,{1315,18},family,[]}]]},{type,{1316,7},constraint,[{atom,{1316,7},is_subtype},[{var,{1316,7},'Family2'},{user_type,{1316,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,56,57,49>>}},{{function,family_union,2},[{file,[115,111,102,115,46,101,114,108]},{location,1371}],[<<102,97,109,105,108,121,95,117,110,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,105,101,115>>]},<<44,32,116,104,101,110,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<32,105,115,32,116,104,101,32,102,97,109,105,108,121,32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<58,115,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<58,115,32,105,110,100,101,120,32,115,101,116,115,44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,51>>]},<<91,105,93,32,105,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,32,105,102,32,98,111,116,104,32,109,97,112,32,105,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,97,109,105,108,121,49>>]},<<91,105,93,32,111,114,32>>,{code,[],[<<70,97,109,105,108,121,50>>]},<<91,105,93,46>>]},{pre,[],[{code,[],[<<49,62,32,70,49,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,93,125,44,123,99,44,91,53,44,54,93,125,93,41,44,10,70,50,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,98,44,91,52,44,53,93,125,44,123,99,44,91,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93,41,44,10,70,51,32,61,32,115,111,102,115,58,102,97,109,105,108,121,95,117,110,105,111,110,40,70,49,44,32,70,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,51,41,46,10,91,123,97,44,91,49,44,50,93,125,44,123,98,44,91,51,44,52,44,53,93,125,44,123,99,44,91,53,44,54,44,55,44,56,93,125,44,123,100,44,91,57,44,49,48,93,125,93>>]}]}]},#{signature => [{attribute,{1371,2},spec,{{family_union,2},[{type,{1371,19},bounded_fun,[{type,{1371,19},'fun',[{type,{1371,19},product,[{var,{1371,20},'Family1'},{var,{1371,29},'Family2'}]},{var,{1371,41},'Family3'}]},[{type,{1372,7},constraint,[{atom,{1372,7},is_subtype},[{var,{1372,7},'Family1'},{user_type,{1372,18},family,[]}]]},{type,{1373,7},constraint,[{atom,{1373,7},is_subtype},[{var,{1373,7},'Family2'},{user_type,{1373,18},family,[]}]]},{type,{1374,7},constraint,[{atom,{1374,7},is_subtype},[{var,{1374,7},'Family3'},{user_type,{1374,18},family,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,49,52>>}},{{function,field,1},[{file,[115,111,102,115,46,101,114,108]},{location,632}],[<<102,105,101,108,100,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,102,105,101,108,100,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,49,44,50,44,97,44,98,44,99,93>>]}]},{p,[],[{code,[],[<<102,105,101,108,100,40,82,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<117,110,105,111,110,40,100,111,109,97,105,110,40,82,41,44,32,114,97,110,103,101,40,82,41,41>>]},<<46>>]}]},#{signature => [{attribute,{632,2},spec,{{field,1},[{type,{632,12},bounded_fun,[{type,{632,12},'fun',[{type,{632,12},product,[{var,{632,13},'BinRel'}]},{var,{632,24},'Set'}]},[{type,{633,7},constraint,[{atom,{633,7},is_subtype},[{var,{633,7},'BinRel'},{user_type,{633,17},binary_relation,[]}]]},{type,{634,7},constraint,[{atom,{634,7},is_subtype},[{var,{634,7},'Set'},{user_type,{634,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,51,54>>}},{{function,from_external,2},[{file,[115,111,102,115,46,101,114,108]},{location,169}],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32,115,101,116,32,102,114,111,109,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32>>,{code,[],[<<69,120,116,101,114,110,97,108,83,101,116>>]},<<32,97,110,100,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<46,32,73,116,32,105,115,32,97,115,115,117,109,101,100,32,116,104,97,116,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,111,102,32>>,{code,[],[<<69,120,116,101,114,110,97,108,83,101,116>>]},<<46>>]}]},#{signature => [{attribute,{169,2},spec,{{from_external,2},[{type,{169,20},bounded_fun,[{type,{169,20},'fun',[{type,{169,20},product,[{var,{169,21},'ExternalSet'},{var,{169,34},'Type'}]},{var,{169,43},'AnySet'}]},[{type,{170,7},constraint,[{atom,{170,7},is_subtype},[{var,{170,7},'ExternalSet'},{user_type,{170,22},external_set,[]}]]},{type,{171,7},constraint,[{atom,{171,7},is_subtype},[{var,{171,7},'AnySet'},{user_type,{171,17},anyset,[]}]]},{type,{172,7},constraint,[{atom,{172,7},is_subtype},[{var,{172,7},'Type'},{user_type,{172,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,53,50>>}},{{function,from_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,220}],[<<102,114,111,109,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,101,116,115,32,111,102,32,108,105,115,116,32>>,{code,[],[<<76,105,115,116,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,120,44,51,125,44,123,121,44,52,125,93,41,44,10,83,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,83,49,44,83,50,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,91,123,97,44,49,125,44,123,98,44,50,125,93,44,91,123,120,44,51,125,44,123,121,44,52,125,93,93>>]}]}]},#{signature => [{attribute,{220,2},spec,{{from_sets,1},[{type,{220,16},bounded_fun,[{type,{220,16},'fun',[{type,{220,16},product,[{var,{220,17},'ListOfSets'}]},{var,{220,32},'Set'}]},[{type,{221,7},constraint,[{atom,{221,7},is_subtype},[{var,{221,7},'Set'},{user_type,{221,14},a_set,[]}]]},{type,{222,7},constraint,[{atom,{222,7},is_subtype},[{var,{222,7},'ListOfSets'},{type,{222,21},list,[{user_type,{222,22},anyset,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,54,53>>}},{{function,from_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,220}],[<<102,114,111,109,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,101,32,115,101,116,115,32,111,102,32,116,104,101,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46>>]}]},#{signature => [{attribute,{220,2},spec,{{from_sets,1},[{type,{223,16},bounded_fun,[{type,{223,16},'fun',[{type,{223,16},product,[{var,{223,17},'TupleOfSets'}]},{var,{223,33},'Ordset'}]},[{type,{224,7},constraint,[{atom,{224,7},is_subtype},[{var,{224,7},'Ordset'},{user_type,{224,17},ordset,[]}]]},{type,{225,7},constraint,[{atom,{225,7},is_subtype},[{var,{225,7},'TupleOfSets'},{user_type,{225,22},tuple_of,[{user_type,{225,31},anyset,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,56,49>>}},{{function,from_term,2},[{file,[115,111,102,115,46,101,114,108]},{location,155}],[<<102,114,111,109,95,116,101,114,109,47,50>>],#{},#{signature => [{attribute,{155,2},spec,{{from_term,2},[{type,{155,16},bounded_fun,[{type,{155,16},'fun',[{type,{155,16},product,[{var,{155,17},'Term'},{var,{155,23},'Type'}]},{var,{155,32},'AnySet'}]},[{type,{156,7},constraint,[{atom,{156,7},is_subtype},[{var,{156,7},'AnySet'},{user_type,{156,17},anyset,[]}]]},{type,{157,7},constraint,[{atom,{157,7},is_subtype},[{var,{157,7},'Term'},{type,{157,15},term,[]}]]},{type,{158,7},constraint,[{atom,{158,7},is_subtype},[{var,{158,7},'Type'},{user_type,{158,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,57,49>>,equiv => {function,from_term,1}}},{{function,from_term,1},[{file,[115,111,102,115,46,101,114,108]},{location,143}],[<<102,114,111,109,95,116,101,114,109,47,49>>],#{<<101,110>> => [{p,[],[{a,[{id,<<102,114,111,109,95,116,101,114,109>>}],[]},<<67,114,101,97,116,101,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,101,116,115>>]},<<32,98,121,32,116,114,97,118,101,114,115,105,110,103,32,116,101,114,109,32>>,{code,[],[<<84,101,114,109>>]},<<44,32,115,111,114,116,105,110,103,32,108,105,115,116,115,44,32,114,101,109,111,118,105,110,103,32,100,117,112,108,105,99,97,116,101,115,44,32,97,110,100,32,100,101,114,105,118,105,110,103,32,111,114,32,118,101,114,105,102,121,105,110,103,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,118,97,108,105,100,95,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<118,97,108,105,100,32,116,121,112,101>>]},<<32,102,111,114,32,116,104,101,32,115,111,32,111,98,116,97,105,110,101,100,32,101,120,116,101,114,110,97,108,32,115,101,116,46,32,65,110,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32>>,{code,[],[<<84,121,112,101>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,108,105,109,105,116,32,116,104,101,32,100,101,112,116,104,32,111,102,32,116,104,101,32,116,114,97,118,101,114,115,97,108,59,32,97,110,32,97,116,111,109,105,99,32,116,121,112,101,32,115,116,111,112,115,32,116,104,101,32,116,114,97,118,101,114,115,97,108,44,32,97,115,32,115,104,111,119,110,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,119,104,101,114,101,32>>,{code,[],[<<34,102,111,111,34>>]},<<32,97,110,100,32>>,{code,[],[<<123,34,102,111,111,34,125>>]},<<32,97,114,101,32,108,101,102,116,32,117,110,109,111,100,105,102,105,101,100,58>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,123,34,102,111,111,34,125,44,91,49,44,49,93,125,44,123,34,102,111,111,34,44,91,50,44,50,93,125,93,44,10,91,123,97,116,111,109,44,91,97,116,111,109,93,125,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,123,123,34,102,111,111,34,125,44,91,49,93,125,44,123,34,102,111,111,34,44,91,50,93,125,93>>]}]},{p,[],[{code,[],[<<102,114,111,109,95,116,101,114,109>>]},<<32,99,97,110,32,98,101,32,117,115,101,100,32,102,111,114,32,99,114,101,97,116,105,110,103,32,97,116,111,109,105,99,32,111,114,32,111,114,100,101,114,101,100,32,115,101,116,115,46,32,84,104,101,32,111,110,108,121,32,112,117,114,112,111,115,101,32,111,102,32,115,117,99,104,32,97,32,115,101,116,32,105,115,32,116,104,97,116,32,111,102,32,108,97,116,101,114,32,98,117,105,108,100,105,110,103,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,44,32,97,115,32,97,108,108,32,102,117,110,99,116,105,111,110,115,32,105,110,32,116,104,105,115,32,109,111,100,117,108,101,32,116,104,97,116,32>>,{em,[],[<<100,111>>]},<<32,97,110,121,116,104,105,110,103,32,111,112,101,114,97,116,101,32,111,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,46,32,67,114,101,97,116,105,110,103,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,32,102,114,111,109,32,97,32,99,111,108,108,101,99,116,105,111,110,32,111,102,32,111,114,100,101,114,101,100,32,115,101,116,115,32,99,97,110,32,98,101,32,116,104,101,32,119,97,121,32,116,111,32,103,111,32,105,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,98,105,103,32,97,110,100,32,111,110,101,32,100,111,101,115,32,110,111,116,32,119,97,110,116,32,116,111,32,119,97,115,116,101,32,104,101,97,112,32,98,121,32,114,101,98,117,105,108,100,105,110,103,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,115,104,111,119,115,32,116,104,97,116,32,97,32,115,101,116,32,99,97,110,32,98,101,32,98,117,105,108,116,32,34,108,97,121,101,114,32,98,121,32,108,97,121,101,114,34,58>>]},{pre,[],[{code,[],[<<49,62,32,65,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,97,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,51,93,41,44,10,80,49,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,123,65,44,83,125,41,44,10,80,50,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,123,98,44,91,54,44,53,44,52,93,125,41,44,10,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,80,49,44,80,50,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,115,41,46,10,91,123,97,44,91,49,44,50,44,51,93,125,44,123,98,44,91,52,44,53,44,54,93,125,93>>]}]},{p,[],[<<79,116,104,101,114,32,102,117,110,99,116,105,111,110,115,32,116,104,97,116,32,99,114,101,97,116,101,32,115,101,116,115,32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,101,120,116,101,114,110,97,108,47,50>>]}]},<<32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,114,111,109,95,115,101,116,115,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,114,111,109,95,115,101,116,115,47,49>>]}]},<<46,32,83,112,101,99,105,97,108,32,99,97,115,101,115,32,111,102,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,47,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,97,95,102,117,110,99,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<97,95,102,117,110,99,116,105,111,110,47,49,44,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,109,112,116,121,95,115,101,116,47,48>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<101,109,112,116,121,95,115,101,116,47,48>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<102,97,109,105,108,121,47,49,44,50>>]}]},<<44,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,111,110,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<114,101,108,97,116,105,111,110,47,49,44,50>>]}]},<<44,32,97,110,100,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,47,49>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<115,101,116,47,49,44,50>>]}]},<<46>>]}]},#{signature => [{attribute,{143,2},spec,{{from_term,1},[{type,{143,16},bounded_fun,[{type,{143,16},'fun',[{type,{143,16},product,[{var,{143,17},'Term'}]},{var,{143,26},'AnySet'}]},[{type,{144,7},constraint,[{atom,{144,7},is_subtype},[{var,{144,7},'AnySet'},{user_type,{144,17},anyset,[]}]]},{type,{145,7},constraint,[{atom,{145,7},is_subtype},[{var,{145,7},'Term'},{type,{145,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,57,57,49>>}},{{function,image,2},[{file,[115,111,102,115,46,101,114,108]},{location,717}],[<<105,109,97,103,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32,115,101,116,32>>,{code,[],[<<83,101,116,49>>]},<<32,117,110,100,101,114,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,50,44,99,125,44,123,51,44,100,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,105,109,97,103,101,40,82,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,97,44,98,44,99,93>>]}]}]},#{signature => [{attribute,{717,2},spec,{{image,2},[{type,{717,12},bounded_fun,[{type,{717,12},'fun',[{type,{717,12},product,[{var,{717,13},'BinRel'},{var,{717,21},'Set1'}]},{var,{717,30},'Set2'}]},[{type,{718,7},constraint,[{atom,{718,7},is_subtype},[{var,{718,7},'BinRel'},{user_type,{718,17},binary_relation,[]}]]},{type,{719,7},constraint,[{atom,{719,7},is_subtype},[{var,{719,7},'Set1'},{user_type,{719,15},a_set,[]}]]},{type,{720,7},constraint,[{atom,{720,7},is_subtype},[{var,{720,7},'Set2'},{user_type,{720,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,52,49>>}},{{function,intersection,1},[{file,[115,111,102,115,46,101,114,108]},{location,563}],[<<105,110,116,101,114,115,101,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]},{p,[],[<<73,110,116,101,114,115,101,99,116,105,110,103,32,97,110,32,101,109,112,116,121,32,115,101,116,32,111,102,32,115,101,116,115,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]}]},#{signature => [{attribute,{563,2},spec,{{intersection,1},[{type,{563,19},bounded_fun,[{type,{563,19},'fun',[{type,{563,19},product,[{var,{563,20},'SetOfSets'}]},{var,{563,34},'Set'}]},[{type,{564,7},constraint,[{atom,{564,7},is_subtype},[{var,{564,7},'Set'},{user_type,{564,14},a_set,[]}]]},{type,{565,7},constraint,[{atom,{565,7},is_subtype},[{var,{565,7},'SetOfSets'},{user_type,{565,20},set_of_sets,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,53,55>>}},{{function,intersection,2},[{file,[115,111,102,115,46,101,114,108]},{location,388}],[<<105,110,116,101,114,115,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,116,101,114,115,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,116,101,114,115,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{signature => [{attribute,{388,2},spec,{{intersection,2},[{type,{388,19},bounded_fun,[{type,{388,19},'fun',[{type,{388,19},product,[{var,{388,20},'Set1'},{var,{388,26},'Set2'}]},{var,{388,35},'Set3'}]},[{type,{389,7},constraint,[{atom,{389,7},is_subtype},[{var,{389,7},'Set1'},{user_type,{389,15},a_set,[]}]]},{type,{390,7},constraint,[{atom,{390,7},is_subtype},[{var,{390,7},'Set2'},{user_type,{390,15},a_set,[]}]]},{type,{391,7},constraint,[{atom,{391,7},is_subtype},[{var,{391,7},'Set3'},{user_type,{391,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,54,57>>}},{{function,intersection_of_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1299}],[<<105,110,116,101,114,115,101,99,116,105,111,110,95,111,102,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,105,110,116,101,114,115,101,99,116,105,111,110,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46>>]},{p,[],[<<73,110,116,101,114,115,101,99,116,105,110,103,32,97,110,32,101,109,112,116,121,32,102,97,109,105,108,121,32,101,120,105,116,115,32,116,104,101,32,112,114,111,99,101,115,115,32,119,105,116,104,32,97,32>>,{code,[],[<<98,97,100,97,114,103>>]},<<32,109,101,115,115,97,103,101,46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,48,44,50,44,52,93,125,44,123,98,44,91,48,44,49,44,50,93,125,44,123,99,44,91,50,44,51,93,125,93,41,44,10,83,32,61,32,115,111,102,115,58,105,110,116,101,114,115,101,99,116,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,50,93>>]}]}]},#{signature => [{attribute,{1299,2},spec,{{intersection_of_family,1},[{type,{1299,29},bounded_fun,[{type,{1299,29},'fun',[{type,{1299,29},product,[{var,{1299,30},'Family'}]},{var,{1299,41},'Set'}]},[{type,{1300,7},constraint,[{atom,{1300,7},is_subtype},[{var,{1300,7},'Family'},{user_type,{1300,17},family,[]}]]},{type,{1301,7},constraint,[{atom,{1301,7},is_subtype},[{var,{1301,7},'Set'},{user_type,{1301,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,55,57>>}},{{function,inverse,1},[{file,[115,111,102,115,46,101,114,108]},{location,872}],[<<105,110,118,101,114,115,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,118,101,114,115,101>>]},<<32,111,102,32,102,117,110,99,116,105,111,110,32>>,{code,[],[<<70,117,110,99,116,105,111,110,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,105,110,118,101,114,115,101,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,51,125,93>>]}]}]},#{signature => [{attribute,{872,2},spec,{{inverse,1},[{type,{872,14},bounded_fun,[{type,{872,14},'fun',[{type,{872,14},product,[{var,{872,15},'Function1'}]},{var,{872,29},'Function2'}]},[{type,{873,7},constraint,[{atom,{873,7},is_subtype},[{var,{873,7},'Function1'},{user_type,{873,20},a_function,[]}]]},{type,{874,7},constraint,[{atom,{874,7},is_subtype},[{var,{874,7},'Function2'},{user_type,{874,20},a_function,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,48,57,54>>}},{{function,inverse_image,2},[{file,[115,111,102,115,46,101,114,108]},{location,734}],[<<105,110,118,101,114,115,101,95,105,109,97,103,101,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,110,118,101,114,115,101,95,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,110,118,101,114,115,101,32,105,109,97,103,101>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,117,110,100,101,114,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,50,44,99,125,44,123,51,44,100,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,99,44,100,44,101,93,41,44,10,83,50,32,61,32,115,111,102,115,58,105,110,118,101,114,115,101,95,105,109,97,103,101,40,82,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,50,44,51,93>>]}]}]},#{signature => [{attribute,{734,2},spec,{{inverse_image,2},[{type,{734,20},bounded_fun,[{type,{734,20},'fun',[{type,{734,20},product,[{var,{734,21},'BinRel'},{var,{734,29},'Set1'}]},{var,{734,38},'Set2'}]},[{type,{735,7},constraint,[{atom,{735,7},is_subtype},[{var,{735,7},'BinRel'},{user_type,{735,17},binary_relation,[]}]]},{type,{736,7},constraint,[{atom,{736,7},is_subtype},[{var,{736,7},'Set1'},{user_type,{736,15},a_set,[]}]]},{type,{737,7},constraint,[{atom,{737,7},is_subtype},[{var,{737,7},'Set2'},{user_type,{737,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,49,48>>}},{{function,is_a_function,1},[{file,[115,111,102,115,46,101,114,108]},{location,812}],[<<105,115,95,97,95,102,117,110,99,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<32,111,114,32,116,104,101,32,117,110,116,121,112,101,100,32,101,109,112,116,121,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{812,2},spec,{{is_a_function,1},[{type,{812,20},bounded_fun,[{type,{812,20},'fun',[{type,{812,20},product,[{var,{812,21},'BinRel'}]},{var,{812,32},'Bool'}]},[{type,{813,7},constraint,[{atom,{813,7},is_subtype},[{var,{813,7},'Bool'},{type,{813,15},boolean,[]}]]},{type,{814,7},constraint,[{atom,{814,7},is_subtype},[{var,{814,7},'BinRel'},{user_type,{814,17},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,50,55>>}},{{function,is_disjoint,2},[{file,[115,111,102,115,46,101,114,108]},{location,535}],[<<105,115,95,100,105,115,106,111,105,110,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,105,115,106,111,105,110,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,105,115,106,111,105,110,116>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{535,2},spec,{{is_disjoint,2},[{type,{535,18},bounded_fun,[{type,{535,18},'fun',[{type,{535,18},product,[{var,{535,19},'Set1'},{var,{535,25},'Set2'}]},{var,{535,34},'Bool'}]},[{type,{536,7},constraint,[{atom,{536,7},is_subtype},[{var,{536,7},'Bool'},{type,{536,15},boolean,[]}]]},{type,{537,7},constraint,[{atom,{537,7},is_subtype},[{var,{537,7},'Set1'},{user_type,{537,15},a_set,[]}]]},{type,{538,7},constraint,[{atom,{538,7},is_subtype},[{var,{538,7},'Set2'},{user_type,{538,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,51,55>>}},{{function,is_empty_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,527}],[<<105,115,95,101,109,112,116,121,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,105,115,32,97,110,32,101,109,112,116,121,32,117,110,111,114,100,101,114,101,100,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{527,2},spec,{{is_empty_set,1},[{type,{527,19},bounded_fun,[{type,{527,19},'fun',[{type,{527,19},product,[{var,{527,20},'AnySet'}]},{var,{527,31},'Bool'}]},[{type,{528,7},constraint,[{atom,{528,7},is_subtype},[{var,{528,7},'AnySet'},{user_type,{528,17},anyset,[]}]]},{type,{529,7},constraint,[{atom,{529,7},is_subtype},[{var,{529,7},'Bool'},{type,{529,15},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,52,56>>}},{{function,is_equal,2},[{file,[115,111,102,115,46,101,114,108]},{location,480}],[<<105,115,95,101,113,117,97,108,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<65,110,121,83,101,116,50>>]},<<32,97,114,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,113,117,97,108>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,113,117,97,108>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,120,97,109,112,108,101,32,115,104,111,119,115,32,116,104,97,116,32>>,{code,[],[<<61,61,47,50>>]},<<32,105,115,32,117,115,101,100,32,119,104,101,110,32,99,111,109,112,97,114,105,110,103,32,115,101,116,115,32,102,111,114,32,101,113,117,97,108,105,116,121,58>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,46,48,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,49,93,41,44,10,115,111,102,115,58,105,115,95,101,113,117,97,108,40,83,49,44,32,83,50,41,46,10,116,114,117,101>>]}]}]},#{signature => [{attribute,{480,2},spec,{{is_equal,2},[{type,{480,15},bounded_fun,[{type,{480,15},'fun',[{type,{480,15},product,[{var,{480,16},'AnySet1'},{var,{480,25},'AnySet2'}]},{var,{480,37},'Bool'}]},[{type,{481,7},constraint,[{atom,{481,7},is_subtype},[{var,{481,7},'AnySet1'},{user_type,{481,18},anyset,[]}]]},{type,{482,7},constraint,[{atom,{482,7},is_subtype},[{var,{482,7},'AnySet2'},{user_type,{482,18},anyset,[]}]]},{type,{483,7},constraint,[{atom,{483,7},is_subtype},[{var,{483,7},'Bool'},{type,{483,15},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,53,55>>}},{{function,is_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,519}],[<<105,115,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,97,112,112,101,97,114,115,32,116,111,32,98,101,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<44,32,97,110,100,32>>,{code,[],[<<102,97,108,115,101>>]},<<32,105,102,32>>,{code,[],[<<65,110,121,83,101,116>>]},<<32,105,115,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,32,111,114,32,97,110,32,97,116,111,109,105,99,32,115,101,116,32,111,114,32,97,110,121,32,111,116,104,101,114,32,116,101,114,109,46,32,78,111,116,101,32,116,104,97,116,32,116,104,101,32,116,101,115,116,32,105,115,32,115,104,97,108,108,111,119,32,97,110,100,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,114,101,116,117,114,110,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,97,110,121,32,116,101,114,109,32,116,104,97,116,32,99,111,105,110,99,105,100,101,115,32,119,105,116,104,32,116,104,101,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32,83,101,101,32,97,108,115,111,32,110,111,116,101,32,111,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,111,95,117,115,101,114,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<100,97,116,97,32,116,121,112,101,115>>]},<<46>>]}]},#{signature => [{attribute,{519,2},spec,{{is_set,1},[{type,{519,13},bounded_fun,[{type,{519,13},'fun',[{type,{519,13},product,[{var,{519,14},'AnySet'}]},{var,{519,25},'Bool'}]},[{type,{520,7},constraint,[{atom,{520,7},is_subtype},[{var,{520,7},'AnySet'},{user_type,{520,17},anyset,[]}]]},{type,{521,7},constraint,[{atom,{521,7},is_subtype},[{var,{521,7},'Bool'},{type,{521,15},boolean,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,55,52>>}},{{function,is_sofs_set,1},[{file,[115,111,102,115,46,101,114,108]},{location,509}],[<<105,115,95,115,111,102,115,95,115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<84,101,114,109>>]},<<32,97,112,112,101,97,114,115,32,116,111,32,98,101,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<44,32,97,110,32,111,114,100,101,114,101,100,32,115,101,116,44,32,111,114,32,97,110,32,97,116,111,109,105,99,32,115,101,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46,32,78,111,116,101,32,116,104,97,116,32,116,104,105,115,32,102,117,110,99,116,105,111,110,32,119,105,108,108,32,114,101,116,117,114,110,32>>,{code,[],[<<116,114,117,101>>]},<<32,102,111,114,32,97,110,121,32,116,101,114,109,32,116,104,97,116,32,99,111,105,110,99,105,100,101,115,32,119,105,116,104,32,116,104,101,32,114,101,112,114,101,115,101,110,116,97,116,105,111,110,32,111,102,32,97,32>>,{code,[],[<<115,111,102,115>>]},<<32,115,101,116,46,32,83,101,101,32,97,108,115,111,32,110,111,116,101,32,111,110,32>>,{a,[{href,<<115,121,115,116,101,109,47,114,101,102,101,114,101,110,99,101,95,109,97,110,117,97,108,58,100,97,116,97,95,116,121,112,101,115,35,110,111,95,117,115,101,114,95,116,121,112,101,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,103,117,105,100,101>>}],[<<100,97,116,97,32,116,121,112,101,115>>]},<<46>>]}]},#{signature => [{attribute,{509,2},spec,{{is_sofs_set,1},[{type,{509,18},bounded_fun,[{type,{509,18},'fun',[{type,{509,18},product,[{var,{509,19},'Term'}]},{var,{509,28},'Bool'}]},[{type,{510,7},constraint,[{atom,{510,7},is_subtype},[{var,{510,7},'Bool'},{type,{510,15},boolean,[]}]]},{type,{511,7},constraint,[{atom,{511,7},is_subtype},[{var,{511,7},'Term'},{type,{511,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,49,57,49>>}},{{function,is_subset,2},[{file,[115,111,102,115,46,101,114,108]},{location,499}],[<<105,115,95,115,117,98,115,101,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,117,98,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,117,98,115,101,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,50>>]},<<44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<102,97,108,115,101>>]},<<46>>]}]},#{signature => [{attribute,{499,2},spec,{{is_subset,2},[{type,{499,16},bounded_fun,[{type,{499,16},'fun',[{type,{499,16},product,[{var,{499,17},'Set1'},{var,{499,23},'Set2'}]},{var,{499,32},'Bool'}]},[{type,{500,7},constraint,[{atom,{500,7},is_subtype},[{var,{500,7},'Bool'},{type,{500,15},boolean,[]}]]},{type,{501,7},constraint,[{atom,{501,7},is_subtype},[{var,{501,7},'Set1'},{user_type,{501,15},a_set,[]}]]},{type,{502,7},constraint,[{atom,{502,7},is_subtype},[{var,{502,7},'Set2'},{user_type,{502,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,48,54>>}},{{function,is_type,1},[{file,[115,111,102,115,46,101,114,108]},{location,183}],[<<105,115,95,116,121,112,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<32,105,102,32,116,101,114,109,32>>,{code,[],[<<84,101,114,109>>]},<<32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<46>>]}]},#{signature => [{attribute,{183,2},spec,{{is_type,1},[{type,{183,14},bounded_fun,[{type,{183,14},'fun',[{type,{183,14},product,[{var,{183,15},'Term'}]},{var,{183,24},'Bool'}]},[{type,{184,7},constraint,[{atom,{184,7},is_subtype},[{var,{184,7},'Bool'},{type,{184,15},boolean,[]}]]},{type,{185,7},constraint,[{atom,{185,7},is_subtype},[{var,{185,7},'Term'},{type,{185,15},term,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,49,54>>}},{{function,join,4},[{file,[115,111,102,115,46,101,114,108]},{location,1206}],[<<106,111,105,110,47,52>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,110,97,116,117,114,97,108,95,106,111,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,97,116,117,114,97,108,32,106,111,105,110>>]},<<32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,115,32>>,{code,[],[<<82,101,108,97,116,105,111,110,49>>]},<<32,97,110,100,32>>,{code,[],[<<82,101,108,97,116,105,111,110,50>>]},<<32,111,110,32,99,111,111,114,100,105,110,97,116,101,115,32>>,{code,[],[<<73>>]},<<32,97,110,100,32>>,{code,[],[<<74>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,120,44,49,125,44,123,98,44,121,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,102,44,103,125,44,123,49,44,104,44,105,125,44,123,50,44,51,44,52,125,93,41,44,10,74,32,61,32,115,111,102,115,58,106,111,105,110,40,82,49,44,32,51,44,32,82,50,44,32,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,74,41,46,10,91,123,97,44,120,44,49,44,102,44,103,125,44,123,97,44,120,44,49,44,104,44,105,125,44,123,98,44,121,44,50,44,51,44,52,125,93>>]}]}]},#{signature => [{attribute,{1206,2},spec,{{join,4},[{type,{1206,11},bounded_fun,[{type,{1206,11},'fun',[{type,{1206,11},product,[{var,{1206,12},'Relation1'},{var,{1206,23},'I'},{var,{1206,26},'Relation2'},{var,{1206,37},'J'}]},{var,{1206,43},'Relation3'}]},[{type,{1207,7},constraint,[{atom,{1207,7},is_subtype},[{var,{1207,7},'Relation1'},{user_type,{1207,20},relation,[]}]]},{type,{1208,7},constraint,[{atom,{1208,7},is_subtype},[{var,{1208,7},'Relation2'},{user_type,{1208,20},relation,[]}]]},{type,{1209,7},constraint,[{atom,{1209,7},is_subtype},[{var,{1209,7},'Relation3'},{user_type,{1209,20},relation,[]}]]},{type,{1210,7},constraint,[{atom,{1210,7},is_subtype},[{var,{1210,7},'I'},{type,{1210,12},pos_integer,[]}]]},{type,{1211,7},constraint,[{atom,{1211,7},is_subtype},[{var,{1211,7},'J'},{type,{1211,12},pos_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,50,53>>}},{{function,multiple_relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,1190}],[<<109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<84,117,112,108,101,79,102,66,105,110,82,101,108,115>>]},<<32,105,115,32,97,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32,123,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,125,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<109,117,108,116,105,112,108,101,32,114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,105,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,105,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,44,123,99,44,51,125,93,41,44,10,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,98,125,44,123,98,44,99,125,44,123,99,44,97,125,93,41,44,10,77,80,32,61,32,115,111,102,115,58,109,117,108,116,105,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,123,82,105,44,32,82,105,125,44,32,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,114,97,110,103,101,40,77,80,41,41,46,10,91,123,49,44,50,125,44,123,50,44,51,125,44,123,51,44,49,125,93>>]}]}]},#{signature => [{attribute,{1190,2},spec,{{multiple_relative_product,2},[{type,{1190,32},bounded_fun,[{type,{1190,32},'fun',[{type,{1190,32},product,[{var,{1190,33},'TupleOfBinRels'},{var,{1190,49},'BinRel1'}]},{var,{1190,61},'BinRel2'}]},[{type,{1191,7},constraint,[{atom,{1191,7},is_subtype},[{var,{1191,7},'TupleOfBinRels'},{user_type,{1191,25},tuple_of,[{var,{1191,34},'BinRel'}]}]]},{type,{1192,7},constraint,[{atom,{1192,7},is_subtype},[{var,{1192,7},'BinRel'},{user_type,{1192,17},binary_relation,[]}]]},{type,{1193,7},constraint,[{atom,{1193,7},is_subtype},[{var,{1193,7},'BinRel1'},{user_type,{1193,18},binary_relation,[]}]]},{type,{1194,7},constraint,[{atom,{1194,7},is_subtype},[{var,{1194,7},'BinRel2'},{user_type,{1194,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,52,50>>}},{{function,no_elements,1},[{file,[115,111,102,115,46,101,114,108]},{location,349}],[<<110,111,95,101,108,101,109,101,110,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,110,117,109,98,101,114,32,111,102,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<46>>]}]},#{signature => [{attribute,{349,2},spec,{{no_elements,1},[{type,{349,18},bounded_fun,[{type,{349,18},'fun',[{type,{349,18},product,[{var,{349,19},'ASet'}]},{var,{349,28},'NoElements'}]},[{type,{350,7},constraint,[{atom,{350,7},is_subtype},[{var,{350,7},'ASet'},{type,{350,15},union,[{user_type,{350,15},a_set,[]},{user_type,{350,25},ordset,[]}]}]]},{type,{351,7},constraint,[{atom,{351,7},is_subtype},[{var,{351,7},'NoElements'},{type,{351,21},non_neg_integer,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,54,51>>}},{{function,partition,1},[{file,[115,111,102,115,46,101,114,108]},{location,1091}],[<<112,97,114,116,105,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,117,110,105,111,110,32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,121,32,98,101,108,111,110,103,32,116,111,32,116,104,101,32,115,97,109,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,101,116,115,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,44,98,44,99,93,44,91,100,44,101,44,102,93,44,91,103,44,104,44,105,93,93,41,44,10,83,101,116,115,50,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,98,44,99,44,100,93,44,91,101,44,102,44,103,93,44,91,104,44,105,44,106,93,93,41,44,10,80,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,115,111,102,115,58,117,110,105,111,110,40,83,101,116,115,49,44,32,83,101,116,115,50,41,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,91,97,93,44,91,98,44,99,93,44,91,100,93,44,91,101,44,102,93,44,91,103,93,44,91,104,44,105,93,44,91,106,93,93>>]}]}]},#{signature => [{attribute,{1091,2},spec,{{partition,1},[{type,{1091,16},bounded_fun,[{type,{1091,16},'fun',[{type,{1091,16},product,[{var,{1091,17},'SetOfSets'}]},{var,{1091,31},'Partition'}]},[{type,{1092,7},constraint,[{atom,{1092,7},is_subtype},[{var,{1092,7},'SetOfSets'},{user_type,{1092,20},set_of_sets,[]}]]},{type,{1093,7},constraint,[{atom,{1093,7},is_subtype},[{var,{1093,7},'Partition'},{user_type,{1093,20},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,55,50>>}},{{function,partition,2},[{file,[115,111,102,115,46,101,114,108]},{location,1099}],[<<112,97,114,116,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,32,114,101,115,117,108,116,115,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,97,114,101,32,101,113,117,97,108,46>>]},{pre,[],[{code,[],[<<49,62,32,83,115,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,91,97,93,44,91,98,93,44,91,99,44,100,93,44,91,101,44,102,93,93,41,44,10,83,101,116,70,117,110,32,61,32,102,117,110,40,83,41,32,45,62,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,115,111,102,115,58,110,111,95,101,108,101,109,101,110,116,115,40,83,41,41,32,101,110,100,44,10,80,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,83,101,116,70,117,110,44,32,83,115,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,91,91,97,93,44,91,98,93,93,44,91,91,99,44,100,93,44,91,101,44,102,93,93,93>>]}]}]},#{signature => [{attribute,{1099,2},spec,{{partition,2},[{type,{1099,16},bounded_fun,[{type,{1099,16},'fun',[{type,{1099,16},product,[{var,{1099,17},'SetFun'},{var,{1099,25},'Set'}]},{var,{1099,33},'Partition'}]},[{type,{1100,7},constraint,[{atom,{1100,7},is_subtype},[{var,{1100,7},'SetFun'},{user_type,{1100,17},set_fun,[]}]]},{type,{1101,7},constraint,[{atom,{1101,7},is_subtype},[{var,{1101,7},'Partition'},{user_type,{1101,20},a_set,[]}]]},{type,{1102,7},constraint,[{atom,{1102,7},is_subtype},[{var,{1102,7},'Set'},{user_type,{1102,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,50,56,57>>}},{{function,partition,3},[{file,[115,111,102,115,46,101,114,108]},{location,1118}],[<<112,97,114,116,105,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,112,97,105,114,32,111,102,32,115,101,116,115,32,116,104,97,116,44,32,114,101,103,97,114,100,101,100,32,97,115,32,99,111,110,115,116,105,116,117,116,105,110,103,32,97,32,115,101,116,44,32,102,111,114,109,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<46,32,73,102,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,103,105,118,101,115,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<44,32,116,104,101,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,51>>]},<<44,32,111,116,104,101,114,119,105,115,101,32,116,104,101,32,101,108,101,109,101,110,116,32,98,101,108,111,110,103,115,32,116,111,32>>,{code,[],[<<83,101,116,52>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,52,44,54,93,41,44,10,123,82,50,44,82,51,125,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,40,49,44,32,82,49,44,32,83,41,44,10,123,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,44,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,125,46,10,123,91,123,50,44,98,125,93,44,91,123,49,44,97,125,44,123,51,44,99,125,93,125>>]}]},{p,[],[{code,[],[<<112,97,114,116,105,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<123,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,44,32,100,114,101,115,116,114,105,99,116,105,111,110,40,70,44,194,160,83,49,44,194,160,83,50,41,125>>]},<<46>>]}]},#{signature => [{attribute,{1118,2},spec,{{partition,3},[{type,{1118,16},bounded_fun,[{type,{1118,16},'fun',[{type,{1118,16},product,[{var,{1118,17},'SetFun'},{var,{1118,25},'Set1'},{var,{1118,31},'Set2'}]},{type,{1118,40},tuple,[{var,{1118,41},'Set3'},{var,{1118,47},'Set4'}]}]},[{type,{1119,7},constraint,[{atom,{1119,7},is_subtype},[{var,{1119,7},'SetFun'},{user_type,{1119,17},set_fun,[]}]]},{type,{1120,7},constraint,[{atom,{1120,7},is_subtype},[{var,{1120,7},'Set1'},{user_type,{1120,15},a_set,[]}]]},{type,{1121,7},constraint,[{atom,{1121,7},is_subtype},[{var,{1121,7},'Set2'},{user_type,{1121,15},a_set,[]}]]},{type,{1122,7},constraint,[{atom,{1122,7},is_subtype},[{var,{1122,7},'Set3'},{user_type,{1122,15},a_set,[]}]]},{type,{1123,7},constraint,[{atom,{1123,7},is_subtype},[{var,{1123,7},'Set4'},{user_type,{1123,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,48,53>>}},{{function,partition_family,2},[{file,[115,111,102,115,46,101,114,108]},{location,1404}],[<<112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,119,104,101,114,101,32,116,104,101,32,105,110,100,101,120,101,100,32,115,101,116,32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,97,114,116,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,97,114,116,105,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,119,111,32,101,108,101,109,101,110,116,115,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,101,113,117,97,108,32,105,102,32,116,104,101,32,114,101,115,117,108,116,115,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,97,114,101,32,116,104,101,32,115,97,109,101,32,118,97,108,117,101,32,105,46,32,84,104,105,115,32,105,32,105,115,32,116,104,101,32,105,110,100,101,120,32,116,104,97,116,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,109,97,112,115,32,111,110,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,113,117,105,118,97,108,101,110,99,101,95,99,108,97,115,115>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,113,117,105,118,97,108,101,110,99,101,32,99,108,97,115,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,97,44,97,44,97,125,44,123,97,44,97,44,98,44,98,125,44,123,97,44,98,44,98,44,98,125,93,41,44,10,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,44,67,44,95,125,41,32,45,62,32,123,65,44,67,125,32,101,110,100,125,44,10,70,32,61,32,115,111,102,115,58,112,97,114,116,105,116,105,111,110,95,102,97,109,105,108,121,40,83,101,116,70,117,110,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,123,97,44,97,125,44,91,123,97,44,97,44,97,44,97,125,93,125,44,123,123,97,44,98,125,44,91,123,97,44,97,44,98,44,98,125,44,123,97,44,98,44,98,44,98,125,93,125,93>>]}]}]},#{signature => [{attribute,{1404,2},spec,{{partition_family,2},[{type,{1404,23},bounded_fun,[{type,{1404,23},'fun',[{type,{1404,23},product,[{var,{1404,24},'SetFun'},{var,{1404,32},'Set'}]},{var,{1404,40},'Family'}]},[{type,{1405,7},constraint,[{atom,{1405,7},is_subtype},[{var,{1405,7},'Family'},{user_type,{1405,17},family,[]}]]},{type,{1406,7},constraint,[{atom,{1406,7},is_subtype},[{var,{1406,7},'SetFun'},{user_type,{1406,17},set_fun,[]}]]},{type,{1407,7},constraint,[{atom,{1407,7},is_subtype},[{var,{1407,7},'Set'},{user_type,{1407,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,50,56>>}},{{function,product,1},[{file,[115,111,102,115,46,101,114,108]},{location,444}],[<<112,114,111,100,117,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,110,111,110,45,101,109,112,116,121,32,116,117,112,108,101,32,111,102,32,115,101,116,115,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46,32,73,102,32,40,120,91,49,93,44,194,160,46,46,46,44,194,160,120,91,110,93,41,32,105,115,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,110,45,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<82,101,108,97,116,105,111,110>>]},<<44,32,116,104,101,110,32,120,91,105,93,32,105,115,32,100,114,97,119,110,32,102,114,111,109,32,101,108,101,109,101,110,116,32,105,32,111,102,32>>,{code,[],[<<84,117,112,108,101,79,102,83,101,116,115>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,51,32,61,32,115,111,102,115,58,115,101,116,40,91,120,44,121,93,41,44,10,80,51,32,61,32,115,111,102,115,58,112,114,111,100,117,99,116,40,123,83,49,44,83,50,44,83,51,125,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,51,41,46,10,91,123,97,44,49,44,120,125,44,123,97,44,49,44,121,125,44,123,97,44,50,44,120,125,44,123,97,44,50,44,121,125,44,123,98,44,49,44,120,125,44,123,98,44,49,44,121,125,44,123,98,44,50,44,120,125,44,123,98,44,50,44,121,125,93>>]}]}]},#{signature => [{attribute,{444,2},spec,{{product,1},[{type,{444,14},bounded_fun,[{type,{444,14},'fun',[{type,{444,14},product,[{var,{444,15},'TupleOfSets'}]},{var,{444,31},'Relation'}]},[{type,{445,7},constraint,[{atom,{445,7},is_subtype},[{var,{445,7},'Relation'},{user_type,{445,19},relation,[]}]]},{type,{446,7},constraint,[{atom,{446,7},is_subtype},[{var,{446,7},'TupleOfSets'},{user_type,{446,22},tuple_of,[{user_type,{446,31},a_set,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,52,57>>}},{{function,product,2},[{file,[115,111,102,115,46,101,114,108]},{location,430}],[<<112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,97,44,98,93,41,44,10,82,32,61,32,115,111,102,115,58,112,114,111,100,117,99,116,40,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,41,46,10,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,97,125,44,123,50,44,98,125,93>>]}]},{p,[],[{code,[],[<<112,114,111,100,117,99,116,40,83,49,44,194,160,83,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<112,114,111,100,117,99,116,40,123,83,49,44,194,160,83,50,125,41>>]},<<46>>]}]},#{signature => [{attribute,{430,2},spec,{{product,2},[{type,{430,14},bounded_fun,[{type,{430,14},'fun',[{type,{430,14},product,[{var,{430,15},'Set1'},{var,{430,21},'Set2'}]},{var,{430,30},'BinRel'}]},[{type,{431,7},constraint,[{atom,{431,7},is_subtype},[{var,{431,7},'BinRel'},{user_type,{431,17},binary_relation,[]}]]},{type,{432,7},constraint,[{atom,{432,7},is_subtype},[{var,{432,7},'Set1'},{user_type,{432,15},a_set,[]}]]},{type,{433,7},constraint,[{atom,{433,7},is_subtype},[{var,{433,7},'Set2'},{user_type,{433,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,54,56>>}},{{function,projection,2},[{file,[115,111,102,115,46,101,114,108]},{location,1029}],[<<112,114,111,106,101,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,101,116,32,99,114,101,97,116,101,100,32,98,121,32,115,117,98,115,116,105,116,117,116,105,110,103,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,98,121,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,46>>]},{p,[],[<<73,102,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,105,115,32,97,32,110,117,109,98,101,114,32,105,194,160,62,61,194,160,49,32,97,110,100,32>>,{code,[],[<<83,101,116,49>>]},<<32,105,115,32,97,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32,116,104,101,32,114,101,116,117,114,110,101,100,32,115,101,116,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,112,114,111,106,101,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<112,114,111,106,101,99,116,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,111,110,116,111,32,99,111,111,114,100,105,110,97,116,101,32,105,46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,102,114,111,109,95,116,101,114,109,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,97,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,50,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,97,44,98,93>>]}]}]},#{signature => [{attribute,{1029,2},spec,{{projection,2},[{type,{1029,17},bounded_fun,[{type,{1029,17},'fun',[{type,{1029,17},product,[{var,{1029,18},'SetFun'},{var,{1029,26},'Set1'}]},{var,{1029,35},'Set2'}]},[{type,{1030,7},constraint,[{atom,{1030,7},is_subtype},[{var,{1030,7},'SetFun'},{user_type,{1030,17},set_fun,[]}]]},{type,{1031,7},constraint,[{atom,{1031,7},is_subtype},[{var,{1031,7},'Set1'},{user_type,{1031,15},a_set,[]}]]},{type,{1032,7},constraint,[{atom,{1032,7},is_subtype},[{var,{1032,7},'Set2'},{user_type,{1032,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,51,56,54>>}},{{function,range,1},[{file,[115,111,102,115,46,101,114,108]},{location,622}],[<<114,97,110,103,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,97,110,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,97,110,103,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,98,125,44,123,50,44,98,125,44,123,50,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,114,97,110,103,101,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,97,44,98,44,99,93>>]}]}]},#{signature => [{attribute,{622,2},spec,{{range,1},[{type,{622,12},bounded_fun,[{type,{622,12},'fun',[{type,{622,12},product,[{var,{622,13},'BinRel'}]},{var,{622,24},'Set'}]},[{type,{623,7},constraint,[{atom,{623,7},is_subtype},[{var,{623,7},'BinRel'},{user_type,{623,17},binary_relation,[]}]]},{type,{624,7},constraint,[{atom,{624,7},is_subtype},[{var,{624,7},'Set'},{user_type,{624,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,48,53>>}},{{function,relation,2},[{file,[115,111,102,115,46,101,114,108]},{location,255}],[<<114,101,108,97,116,105,111,110,47,50>>],#{},#{signature => [{attribute,{255,2},spec,{{relation,2},[{type,{255,15},bounded_fun,[{type,{255,15},'fun',[{type,{255,15},product,[{var,{255,16},'Tuples'},{var,{255,24},'Type'}]},{var,{255,33},'Relation'}]},[{type,{256,7},constraint,[{atom,{256,7},is_subtype},[{var,{256,7},'N'},{type,{256,12},integer,[]}]]},{type,{257,7},constraint,[{atom,{257,7},is_subtype},[{var,{257,7},'Type'},{type,{257,15},union,[{var,{257,15},'N'},{user_type,{257,19},type,[]}]}]]},{type,{258,7},constraint,[{atom,{258,7},is_subtype},[{var,{258,7},'Relation'},{user_type,{258,19},relation,[]}]]},{type,{259,7},constraint,[{atom,{259,7},is_subtype},[{var,{259,7},'Tuples'},{type,{259,17},list,[{type,{259,18},tuple,any}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,49,57>>,equiv => {function,relation,1}}},{{function,relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,243}],[<<114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,111,110>>]},<<46,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,82,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,82,44,194,160,84,41>>]},<<44,32,105,102,32,84,32,105,115,32,97,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,97,110,100,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,32,114,101,108,97,116,105,111,110,46,32,73,102,32>>,{code,[],[<<84,121,112,101>>]},<<32,105,115,32,97,110,32,105,110,116,101,103,101,114,32,78,44,32,116,104,101,110,32>>,{code,[],[<<91,123,97,116,111,109,44,194,160,46,46,46,44,194,160,97,116,111,109,125,93,41>>]},<<44,32,119,104,101,114,101,32,116,104,101,32,116,117,112,108,101,32,115,105,122,101,32,105,115,32,78,44,32,105,115,32,117,115,101,100,32,97,115,32,116,121,112,101,32,111,102,32,116,104,101,32,114,101,108,97,116,105,111,110,46,32,73,102,32,110,111,32,116,121,112,101,32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32,116,104,101,32,115,105,122,101,32,111,102,32,116,104,101,32,102,105,114,115,116,32,116,117,112,108,101,32,111,102,32>>,{code,[],[<<84,117,112,108,101,115>>]},<<32,105,115,32,117,115,101,100,32,105,102,32,116,104,101,114,101,32,105,115,32,115,117,99,104,32,97,32,116,117,112,108,101,46,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,91,93,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,108,97,116,105,111,110,40,91,93,44,194,160,50,41>>]},<<46>>]}]},#{signature => [{attribute,{243,2},spec,{{relation,1},[{type,{243,15},bounded_fun,[{type,{243,15},'fun',[{type,{243,15},product,[{var,{243,16},'Tuples'}]},{var,{243,27},'Relation'}]},[{type,{244,7},constraint,[{atom,{244,7},is_subtype},[{var,{244,7},'Relation'},{user_type,{244,19},relation,[]}]]},{type,{245,7},constraint,[{atom,{245,7},is_subtype},[{var,{245,7},'Tuples'},{type,{245,17},list,[{type,{245,18},tuple,any}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,49,57>>}},{{function,relation_to_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,600}],[<<114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<32,115,117,99,104,32,116,104,97,116,32,116,104,101,32,105,110,100,101,120,32,115,101,116,32,105,115,32,101,113,117,97,108,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,100,111,109,97,105,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<100,111,109,97,105,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<44,32,97,110,100,32>>,{code,[],[<<70,97,109,105,108,121>>]},<<91,105,93,32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,105,32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,98,44,49,125,44,123,99,44,50,125,44,123,99,44,51,125,93,41,44,10,70,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,40,82,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,70,41,46,10,91,123,98,44,91,49,93,125,44,123,99,44,91,50,44,51,93,125,93>>]}]}]},#{signature => [{attribute,{600,2},spec,{{relation_to_family,1},[{type,{600,25},bounded_fun,[{type,{600,25},'fun',[{type,{600,25},product,[{var,{600,26},'BinRel'}]},{var,{600,37},'Family'}]},[{type,{601,7},constraint,[{atom,{601,7},is_subtype},[{var,{601,7},'Family'},{user_type,{601,17},family,[]}]]},{type,{602,7},constraint,[{atom,{602,7},is_subtype},[{var,{602,7},'BinRel'},{user_type,{602,17},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,51,56>>}},{{function,relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,657}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{},#{signature => [{attribute,{657,2},spec,{{relative_product,2},[{type,{657,23},bounded_fun,[{type,{657,23},'fun',[{type,{657,23},product,[{var,{657,24},'ListOfBinRels'},{var,{657,39},'BinRel1'}]},{var,{657,51},'BinRel2'}]},[{type,{658,7},constraint,[{atom,{658,7},is_subtype},[{var,{658,7},'ListOfBinRels'},{type,{658,24},nonempty_list,[{var,{658,25},'BinRel'}]}]]},{type,{659,7},constraint,[{atom,{659,7},is_subtype},[{var,{659,7},'BinRel'},{user_type,{659,17},binary_relation,[]}]]},{type,{660,7},constraint,[{atom,{660,7},is_subtype},[{var,{660,7},'BinRel1'},{user_type,{660,18},binary_relation,[]}]]},{type,{661,7},constraint,[{atom,{661,7},is_subtype},[{var,{661,7},'BinRel2'},{user_type,{661,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,53,54>>,equiv => {function,relative_product,1}}},{{function,relative_product,1},[{file,[115,111,102,115,46,101,114,108]},{location,641}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,49>>],#{<<101,110>> => [{p,[],[<<73,102,32>>,{code,[],[<<76,105,115,116,79,102,66,105,110,82,101,108,115>>]},<<32,105,115,32,97,32,110,111,110,45,101,109,112,116,121,32,108,105,115,116,32,91,82,91,49,93,44,194,160,46,46,46,44,194,160,82,91,110,93,93,32,111,102,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,44,32,116,104,101,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<32,105,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,117,112,108,101,95,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32,40,82,91,105,93,44,194,160,46,46,46,44,194,160,82,91,110,93,41,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{p,[],[<<73,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,105,115,32,111,109,105,116,116,101,100,44,32,116,104,101,32,114,101,108,97,116,105,111,110,32,111,102,32,101,113,117,97,108,105,116,121,32,98,101,116,119,101,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,67,97,114,116,101,115,105,97,110,95,112,114,111,100,117,99,116,95,116,117,112,108,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<67,97,114,116,101,115,105,97,110,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,114,97,110,103,101,115,32,111,102,32,82,91,105,93,44,32,114,97,110,103,101,194,160,82,91,49,93,194,160,195,151,194,160,46,46,46,194,160,195,151,194,160,114,97,110,103,101,194,160,82,91,110,93,44,32,105,115,32,117,115,101,100,32,105,110,115,116,101,97,100,32,40,105,110,116,117,105,116,105,118,101,108,121,44,32,110,111,116,104,105,110,103,32,105,115,32,34,108,111,115,116,34,41,46>>]},{pre,[],[{code,[],[<<49,62,32,84,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,97,97,125,44,123,50,44,98,125,93,41,44,10,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,117,125,44,123,50,44,118,125,44,123,51,44,99,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,91,84,82,44,32,82,49,93,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,123,97,44,117,125,125,44,123,49,44,123,97,97,44,117,125,125,44,123,50,44,123,98,44,118,125,125,93>>]}]},{p,[],[<<78,111,116,105,99,101,32,116,104,97,116,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,91,82,49,93,44,194,160,82,50,41>>]},<<32,105,115,32,100,105,102,102,101,114,101,110,116,32,102,114,111,109,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,82,49,44,194,160,82,50,41>>]},<<59,32,116,104,101,32,108,105,115,116,32,111,102,32,111,110,101,32,101,108,101,109,101,110,116,32,105,115,32,110,111,116,32,105,100,101,110,116,105,102,105,101,100,32,119,105,116,104,32,116,104,101,32,101,108,101,109,101,110,116,32,105,116,115,101,108,102,46>>]}]},#{signature => [{attribute,{641,2},spec,{{relative_product,1},[{type,{641,23},bounded_fun,[{type,{641,23},'fun',[{type,{641,23},product,[{var,{641,24},'ListOfBinRels'}]},{var,{641,42},'BinRel2'}]},[{type,{642,7},constraint,[{atom,{642,7},is_subtype},[{var,{642,7},'ListOfBinRels'},{type,{642,24},nonempty_list,[{var,{642,25},'BinRel'}]}]]},{type,{643,7},constraint,[{atom,{643,7},is_subtype},[{var,{643,7},'BinRel'},{user_type,{643,17},binary_relation,[]}]]},{type,{644,7},constraint,[{atom,{644,7},is_subtype},[{var,{644,7},'BinRel2'},{user_type,{644,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,53,54>>}},{{function,relative_product,2},[{file,[115,111,102,115,46,101,114,108]},{location,657}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,115,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<46>>]}]},#{signature => [{attribute,{657,2},spec,{{relative_product,2},[{type,{662,23},bounded_fun,[{type,{662,23},'fun',[{type,{662,23},product,[{var,{662,24},'BinRel1'},{var,{662,33},'BinRel2'}]},{var,{662,45},'BinRel3'}]},[{type,{663,7},constraint,[{atom,{663,7},is_subtype},[{var,{663,7},'BinRel1'},{user_type,{663,18},binary_relation,[]}]]},{type,{664,7},constraint,[{atom,{664,7},is_subtype},[{var,{664,7},'BinRel2'},{user_type,{664,18},binary_relation,[]}]]},{type,{665,7},constraint,[{atom,{665,7},is_subtype},[{var,{665,7},'BinRel3'},{user_type,{665,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,56,55>>}},{{function,relative_product1,2},[{file,[115,111,102,115,46,101,114,108]},{location,685}],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,108,97,116,105,118,101,32,112,114,111,100,117,99,116>>]},<<32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,99,111,110,118,101,114,115,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<99,111,110,118,101,114,115,101>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,97,110,100,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,49,44,97,97,125,44,123,50,44,98,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,117,125,44,123,50,44,118,125,44,123,51,44,99,125,93,41,44,10,82,51,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,82,49,44,32,82,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,51,41,46,10,91,123,97,44,117,125,44,123,97,97,44,117,125,44,123,98,44,118,125,93>>]}]},{p,[],[{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,82,49,44,194,160,82,50,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,40,99,111,110,118,101,114,115,101,40,82,49,41,44,194,160,82,50,41>>]},<<46>>]}]},#{signature => [{attribute,{685,2},spec,{{relative_product1,2},[{type,{685,24},bounded_fun,[{type,{685,24},'fun',[{type,{685,24},product,[{var,{685,25},'BinRel1'},{var,{685,34},'BinRel2'}]},{var,{685,46},'BinRel3'}]},[{type,{686,7},constraint,[{atom,{686,7},is_subtype},[{var,{686,7},'BinRel1'},{user_type,{686,18},binary_relation,[]}]]},{type,{687,7},constraint,[{atom,{687,7},is_subtype},[{var,{687,7},'BinRel2'},{user_type,{687,18},binary_relation,[]}]]},{type,{688,7},constraint,[{atom,{688,7},is_subtype},[{var,{688,7},'BinRel3'},{user_type,{688,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,52,57,56>>}},{{function,restriction,2},[{file,[115,111,102,115,46,101,114,108]},{location,826}],[<<114,101,115,116,114,105,99,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,114,101,115,116,114,105,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<114,101,115,116,114,105,99,116,105,111,110>>]},<<32,111,102,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<32,116,111,32>>,{code,[],[<<83,101,116>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,52,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,115,116,114,105,99,116,105,111,110,40,82,49,44,32,83,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,97,125,44,123,50,44,98,125,93>>]}]}]},#{signature => [{attribute,{826,2},spec,{{restriction,2},[{type,{826,18},bounded_fun,[{type,{826,18},'fun',[{type,{826,18},product,[{var,{826,19},'BinRel1'},{var,{826,28},'Set'}]},{var,{826,36},'BinRel2'}]},[{type,{827,7},constraint,[{atom,{827,7},is_subtype},[{var,{827,7},'BinRel1'},{user_type,{827,18},binary_relation,[]}]]},{type,{828,7},constraint,[{atom,{828,7},is_subtype},[{var,{828,7},'BinRel2'},{user_type,{828,18},binary_relation,[]}]]},{type,{829,7},constraint,[{atom,{829,7},is_subtype},[{var,{829,7},'Set'},{user_type,{829,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,49,57>>}},{{function,restriction,3},[{file,[115,111,102,115,46,101,114,108]},{location,892}],[<<114,101,115,116,114,105,99,116,105,111,110,47,51>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,99,111,110,116,97,105,110,105,110,103,32,116,104,111,115,101,32,101,108,101,109,101,110,116,115,32,116,104,97,116,32,103,105,118,101,115,32,97,110,32,101,108,101,109,101,110,116,32,105,110,32>>,{code,[],[<<83,101,116,50>>]},<<32,97,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,97,125,44,123,50,44,98,125,44,123,51,44,99,125,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,98,44,99,44,100,93,41,44,10,83,51,32,61,32,115,111,102,115,58,114,101,115,116,114,105,99,116,105,111,110,40,50,44,32,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,51,41,46,10,91,123,50,44,98,125,44,123,51,44,99,125,93>>]}]}]},#{signature => [{attribute,{892,2},spec,{{restriction,3},[{type,{892,18},bounded_fun,[{type,{892,18},'fun',[{type,{892,18},product,[{var,{892,19},'SetFun'},{var,{892,27},'Set1'},{var,{892,33},'Set2'}]},{var,{892,42},'Set3'}]},[{type,{893,7},constraint,[{atom,{893,7},is_subtype},[{var,{893,7},'SetFun'},{user_type,{893,17},set_fun,[]}]]},{type,{894,7},constraint,[{atom,{894,7},is_subtype},[{var,{894,7},'Set1'},{user_type,{894,15},a_set,[]}]]},{type,{895,7},constraint,[{atom,{895,7},is_subtype},[{var,{895,7},'Set2'},{user_type,{895,15},a_set,[]}]]},{type,{896,7},constraint,[{atom,{896,7},is_subtype},[{var,{896,7},'Set3'},{user_type,{896,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,51,53>>}},{{function,set,2},[{file,[115,111,102,115,46,101,114,108]},{location,204}],[<<115,101,116,47,50>>],#{},#{signature => [{attribute,{204,2},spec,{{set,2},[{type,{204,10},bounded_fun,[{type,{204,10},'fun',[{type,{204,10},product,[{var,{204,11},'Terms'},{var,{204,18},'Type'}]},{var,{204,27},'Set'}]},[{type,{205,7},constraint,[{atom,{205,7},is_subtype},[{var,{205,7},'Set'},{user_type,{205,14},a_set,[]}]]},{type,{206,7},constraint,[{atom,{206,7},is_subtype},[{var,{206,7},'Terms'},{type,{206,16},list,[{type,{206,17},term,[]}]}]]},{type,{207,7},constraint,[{atom,{207,7},is_subtype},[{var,{207,7},'Type'},{user_type,{207,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,53,49>>,equiv => {function,set,1}}},{{function,set,1},[{file,[115,111,102,115,46,101,114,108]},{location,195}],[<<115,101,116,47,49>>],#{<<101,110>> => [{p,[],[<<67,114,101,97,116,101,115,32,97,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<46,32>>,{code,[],[<<115,101,116,40,76,44,194,160,84,41>>]},<<32,105,115,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32>>,{code,[],[<<102,114,111,109,95,116,101,114,109,40,76,44,194,160,84,41>>]},<<44,32,105,102,32,116,104,101,32,114,101,115,117,108,116,32,105,115,32,97,110,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46,32,73,102,32,110,111,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,105,115,32,101,120,112,108,105,99,105,116,108,121,32,115,112,101,99,105,102,105,101,100,44,32>>,{code,[],[<<91,97,116,111,109,93>>]},<<32,105,115,32,117,115,101,100,32,97,115,32,116,104,101,32,115,101,116,32,116,121,112,101,46>>]}]},#{signature => [{attribute,{195,2},spec,{{set,1},[{type,{195,10},bounded_fun,[{type,{195,10},'fun',[{type,{195,10},product,[{var,{195,11},'Terms'}]},{var,{195,21},'Set'}]},[{type,{196,7},constraint,[{atom,{196,7},is_subtype},[{var,{196,7},'Set'},{user_type,{196,14},a_set,[]}]]},{type,{197,7},constraint,[{atom,{197,7},is_subtype},[{var,{197,7},'Terms'},{type,{197,16},list,[{type,{197,17},term,[]}]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,53,49>>}},{{function,specification,2},[{file,[115,111,102,115,46,101,114,108]},{location,359}],[<<115,112,101,99,105,102,105,99,97,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,115,101,116,32,99,111,110,116,97,105,110,105,110,103,32,101,118,101,114,121,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,102,111,114,32,119,104,105,99,104,32>>,{code,[],[<<70,117,110>>]},<<32,114,101,116,117,114,110,115,32>>,{code,[],[<<116,114,117,101>>]},<<46,32,73,102,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,32,116,117,112,108,101,32>>,{code,[],[<<123,101,120,116,101,114,110,97,108,44,194,160,70,117,110,50,125>>]},<<44,32>>,{code,[],[<<70,117,110,50>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,44,32,111,116,104,101,114,119,105,115,101,32>>,{code,[],[<<70,117,110>>]},<<32,105,115,32,97,112,112,108,105,101,100,32,116,111,32,101,97,99,104,32,101,108,101,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,97,44,49,125,44,123,98,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,120,44,49,125,44,123,120,44,50,125,44,123,121,44,51,125,93,41,44,10,83,49,32,61,32,115,111,102,115,58,102,114,111,109,95,115,101,116,115,40,91,82,49,44,82,50,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,112,101,99,105,102,105,99,97,116,105,111,110,40,102,117,110,32,115,111,102,115,58,105,115,95,97,95,102,117,110,99,116,105,111,110,47,49,44,32,83,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,50,41,46,10,91,91,123,97,44,49,125,44,123,98,44,50,125,93,93>>]}]}]},#{signature => [{attribute,{359,2},spec,{{specification,2},[{type,{359,20},bounded_fun,[{type,{359,20},'fun',[{type,{359,20},product,[{var,{359,21},'Fun'},{var,{359,26},'Set1'}]},{var,{359,35},'Set2'}]},[{type,{360,7},constraint,[{atom,{360,7},is_subtype},[{var,{360,7},'Fun'},{user_type,{360,14},spec_fun,[]}]]},{type,{361,7},constraint,[{atom,{361,7},is_subtype},[{var,{361,7},'Set1'},{user_type,{361,15},a_set,[]}]]},{type,{362,7},constraint,[{atom,{362,7},is_subtype},[{var,{362,7},'Set2'},{user_type,{362,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,54,52>>}},{{function,strict_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,752}],[<<115,116,114,105,99,116,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,116,114,105,99,116,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,116,114,105,99,116,32,114,101,108,97,116,105,111,110>>]},<<32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,49,125,44,123,49,44,50,125,44,123,50,44,49,125,44,123,50,44,50,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,115,116,114,105,99,116,95,114,101,108,97,116,105,111,110,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,50,125,44,123,50,44,49,125,93>>]}]}]},#{signature => [{attribute,{752,2},spec,{{strict_relation,1},[{type,{752,22},bounded_fun,[{type,{752,22},'fun',[{type,{752,22},product,[{var,{752,23},'BinRel1'}]},{var,{752,35},'BinRel2'}]},[{type,{753,7},constraint,[{atom,{753,7},is_subtype},[{var,{753,7},'BinRel1'},{user_type,{753,18},binary_relation,[]}]]},{type,{754,7},constraint,[{atom,{754,7},is_subtype},[{var,{754,7},'BinRel2'},{user_type,{754,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,53,56,53>>}},{{function,substitution,2},[{file,[115,111,102,115,46,101,114,108]},{location,1048}],[<<115,117,98,115,116,105,116,117,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,102,117,110,99,116,105,111,110,44,32,116,104,101,32,100,111,109,97,105,110,32,111,102,32,119,104,105,99,104,32,105,115,32>>,{code,[],[<<83,101,116,49>>]},<<46,32,84,104,101,32,118,97,108,117,101,32,111,102,32,97,110,32,101,108,101,109,101,110,116,32,111,102,32,116,104,101,32,100,111,109,97,105,110,32,105,115,32,116,104,101,32,114,101,115,117,108,116,32,111,102,32,97,112,112,108,121,105,110,103,32>>,{code,[],[<<83,101,116,70,117,110>>]},<<32,116,111,32,116,104,101,32,101,108,101,109,101,110,116,46>>]},{pre,[],[{code,[],[<<49,62,32,76,32,61,32,91,123,97,44,49,125,44,123,98,44,50,125,93,46,10,91,123,97,44,49,125,44,123,98,44,50,125,93,10,50,62,32,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,49,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,97,44,98,93,10,51,62,32,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,49,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,123,123,97,44,49,125,44,97,125,44,123,123,98,44,50,125,44,98,125,93,10,52,62,32,83,101,116,70,117,110,32,61,32,123,101,120,116,101,114,110,97,108,44,32,102,117,110,40,123,65,44,95,125,61,69,41,32,45,62,32,123,69,44,65,125,32,101,110,100,125,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,115,111,102,115,58,112,114,111,106,101,99,116,105,111,110,40,83,101,116,70,117,110,44,115,111,102,115,58,114,101,108,97,116,105,111,110,40,76,41,41,41,46,10,91,123,123,97,44,49,125,44,97,125,44,123,123,98,44,50,125,44,98,125,93>>]}]},{p,[],[<<84,104,101,32,114,101,108,97,116,105,111,110,32,111,102,32,101,113,117,97,108,105,116,121,32,98,101,116,119,101,101,110,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,123,97,44,98,44,99,125,58>>]},{pre,[],[{code,[],[<<49,62,32,73,32,61,32,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,102,117,110,40,65,41,32,45,62,32,65,32,101,110,100,44,32,115,111,102,115,58,115,101,116,40,91,97,44,98,44,99,93,41,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,73,41,46,10,91,123,97,44,97,125,44,123,98,44,98,125,44,123,99,44,99,125,93>>]}]},{p,[],[<<76,101,116,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,98,101,32,97,32,115,101,116,32,111,102,32,115,101,116,115,32,97,110,100,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,97,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,46,32,84,104,101,32,102,117,110,99,116,105,111,110,32,116,104,97,116,32,109,97,112,115,32,101,97,99,104,32,101,108,101,109,101,110,116,32>>,{code,[],[<<83,101,116>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,111,110,116,111,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<105,109,97,103,101>>]},<<32,111,102,32>>,{code,[],[<<83,101,116>>]},<<32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,114,101,116,117,114,110,101,100,32,98,121,32,116,104,101,32,102,111,108,108,111,119,105,110,103,32,102,117,110,99,116,105,111,110,58>>]},{pre,[],[{code,[],[<<105,109,97,103,101,115,40,83,101,116,79,102,83,101,116,115,44,32,66,105,110,82,101,108,41,32,45,62,10,32,32,32,70,117,110,32,61,32,102,117,110,40,83,101,116,41,32,45,62,32,115,111,102,115,58,105,109,97,103,101,40,66,105,110,82,101,108,44,32,83,101,116,41,32,101,110,100,44,10,32,32,32,115,111,102,115,58,115,117,98,115,116,105,116,117,116,105,111,110,40,70,117,110,44,32,83,101,116,79,102,83,101,116,115,41,46>>]}]},{p,[],[<<69,120,116,101,114,110,97,108,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,32,97,114,101,32,114,101,112,114,101,115,101,110,116,101,100,32,97,115,32,115,111,114,116,101,100,32,108,105,115,116,115,46,32,83,111,44,32,99,114,101,97,116,105,110,103,32,116,104,101,32,105,109,97,103,101,32,111,102,32,97,32,115,101,116,32,117,110,100,101,114,32,97,32,114,101,108,97,116,105,111,110,32,82,32,99,97,110,32,116,114,97,118,101,114,115,101,32,97,108,108,32,101,108,101,109,101,110,116,115,32,111,102,32,82,32,40,116,111,32,116,104,97,116,32,99,111,109,101,115,32,116,104,101,32,115,111,114,116,105,110,103,32,111,102,32,114,101,115,117,108,116,115,44,32,116,104,101,32,105,109,97,103,101,41,46,32,73,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,105,109,97,103,101,47,50>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,109,102,97>>}],[{code,[],[<<105,109,97,103,101,47,50>>]}]},<<44,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,116,114,97,118,101,114,115,101,100,32,111,110,99,101,32,102,111,114,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<44,32,119,104,105,99,104,32,99,97,110,32,116,97,107,101,32,116,111,111,32,108,111,110,103,46,32,84,104,101,32,102,111,108,108,111,119,105,110,103,32,101,102,102,105,99,105,101,110,116,32,102,117,110,99,116,105,111,110,32,99,97,110,32,98,101,32,117,115,101,100,32,105,110,115,116,101,97,100,32,117,110,100,101,114,32,116,104,101,32,97,115,115,117,109,112,116,105,111,110,32,116,104,97,116,32,116,104,101,32,105,109,97,103,101,32,111,102,32,101,97,99,104,32,101,108,101,109,101,110,116,32,111,102,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<32,117,110,100,101,114,32>>,{code,[],[<<66,105,110,82,101,108>>]},<<32,105,115,32,110,111,110,45,101,109,112,116,121,58>>]},{pre,[],[{code,[],[<<105,109,97,103,101,115,50,40,83,101,116,79,102,83,101,116,115,44,32,66,105,110,82,101,108,41,32,45,62,10,32,32,32,67,82,32,61,32,115,111,102,115,58,99,97,110,111,110,105,99,97,108,95,114,101,108,97,116,105,111,110,40,83,101,116,79,102,83,101,116,115,41,44,10,32,32,32,82,32,61,32,115,111,102,115,58,114,101,108,97,116,105,118,101,95,112,114,111,100,117,99,116,49,40,67,82,44,32,66,105,110,82,101,108,41,44,10,32,32,32,115,111,102,115,58,114,101,108,97,116,105,111,110,95,116,111,95,102,97,109,105,108,121,40,82,41,46>>]}]}]},#{signature => [{attribute,{1048,2},spec,{{substitution,2},[{type,{1048,19},bounded_fun,[{type,{1048,19},'fun',[{type,{1048,19},product,[{var,{1048,20},'SetFun'},{var,{1048,28},'Set1'}]},{var,{1048,37},'Set2'}]},[{type,{1049,7},constraint,[{atom,{1049,7},is_subtype},[{var,{1049,7},'SetFun'},{user_type,{1049,17},set_fun,[]}]]},{type,{1050,7},constraint,[{atom,{1050,7},is_subtype},[{var,{1050,7},'Set1'},{user_type,{1050,15},a_set,[]}]]},{type,{1051,7},constraint,[{atom,{1051,7},is_subtype},[{var,{1051,7},'Set2'},{user_type,{1051,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,48,49>>}},{{function,symdiff,2},[{file,[115,111,102,115,46,101,114,108]},{location,408}],[<<115,121,109,100,105,102,102,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,121,109,109,101,116,114,105,99,95,100,105,102,102,101,114,101,110,99,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<115,121,109,109,101,116,114,105,99,32,100,105,102,102,101,114,101,110,99,101>>]},<<32,40,111,114,32,116,104,101,32,66,111,111,108,101,97,110,32,115,117,109,41,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,83,49,32,61,32,115,111,102,115,58,115,101,116,40,91,49,44,50,44,51,93,41,44,10,83,50,32,61,32,115,111,102,115,58,115,101,116,40,91,50,44,51,44,52,93,41,44,10,80,32,61,32,115,111,102,115,58,115,121,109,100,105,102,102,40,83,49,44,32,83,50,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,80,41,46,10,91,49,44,52,93>>]}]}]},#{signature => [{attribute,{408,2},spec,{{symdiff,2},[{type,{408,14},bounded_fun,[{type,{408,14},'fun',[{type,{408,14},product,[{var,{408,15},'Set1'},{var,{408,21},'Set2'}]},{var,{408,30},'Set3'}]},[{type,{409,7},constraint,[{atom,{409,7},is_subtype},[{var,{409,7},'Set1'},{user_type,{409,15},a_set,[]}]]},{type,{410,7},constraint,[{atom,{410,7},is_subtype},[{var,{410,7},'Set2'},{user_type,{410,15},a_set,[]}]]},{type,{411,7},constraint,[{atom,{411,7},is_subtype},[{var,{411,7},'Set3'},{user_type,{411,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,53,48>>}},{{function,symmetric_partition,2},[{file,[115,111,102,115,46,101,114,108]},{location,418}],[<<115,121,109,109,101,116,114,105,99,95,112,97,114,116,105,116,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,116,114,105,112,108,101,32,111,102,32,115,101,116,115,58>>]},{ul,[],[{li,[],[{code,[],[<<83,101,116,51>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{li,[],[{code,[],[<<83,101,116,52>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,116,104,97,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]},{li,[],[{code,[],[<<83,101,116,53>>]},<<32,99,111,110,116,97,105,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32>>,{code,[],[<<83,101,116,50>>]},<<32,116,104,97,116,32,100,111,32,110,111,116,32,98,101,108,111,110,103,32,116,111,32>>,{code,[],[<<83,101,116,49>>]},<<46>>]}]}]},#{signature => [{attribute,{418,2},spec,{{symmetric_partition,2},[{type,{418,26},bounded_fun,[{type,{418,26},'fun',[{type,{418,26},product,[{var,{418,27},'Set1'},{var,{418,33},'Set2'}]},{type,{418,42},tuple,[{var,{418,43},'Set3'},{var,{418,49},'Set4'},{var,{418,55},'Set5'}]}]},[{type,{419,7},constraint,[{atom,{419,7},is_subtype},[{var,{419,7},'Set1'},{user_type,{419,15},a_set,[]}]]},{type,{420,7},constraint,[{atom,{420,7},is_subtype},[{var,{420,7},'Set2'},{user_type,{420,15},a_set,[]}]]},{type,{421,7},constraint,[{atom,{421,7},is_subtype},[{var,{421,7},'Set3'},{user_type,{421,15},a_set,[]}]]},{type,{422,7},constraint,[{atom,{422,7},is_subtype},[{var,{422,7},'Set4'},{user_type,{422,15},a_set,[]}]]},{type,{423,7},constraint,[{atom,{423,7},is_subtype},[{var,{423,7},'Set5'},{user_type,{423,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,54,54>>}},{{function,to_external,1},[{file,[115,111,102,115,46,101,114,108]},{location,319}],[<<116,111,95,101,120,116,101,114,110,97,108,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<32,111,102,32,97,110,32,97,116,111,109,105,99,44,32,111,114,100,101,114,101,100,44,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},#{signature => [{attribute,{319,2},spec,{{to_external,1},[{type,{319,18},bounded_fun,[{type,{319,18},'fun',[{type,{319,18},product,[{var,{319,19},'AnySet'}]},{var,{319,30},'ExternalSet'}]},[{type,{320,7},constraint,[{atom,{320,7},is_subtype},[{var,{320,7},'ExternalSet'},{user_type,{320,22},external_set,[]}]]},{type,{321,7},constraint,[{atom,{321,7},is_subtype},[{var,{321,7},'AnySet'},{user_type,{321,17},anyset,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,56,55>>}},{{function,to_sets,1},[{file,[115,111,102,115,46,101,114,108]},{location,335}],[<<116,111,95,115,101,116,115,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<32,97,115,32,97,32,116,117,112,108,101,32,111,102,32,115,101,116,115,44,32,97,110,100,32,116,104,101,32,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,32,117,110,111,114,100,101,114,101,100,32,115,101,116,32>>,{code,[],[<<65,83,101,116>>]},<<32,97,115,32,97,32,115,111,114,116,101,100,32,108,105,115,116,32,111,102,32,115,101,116,115,32,119,105,116,104,111,117,116,32,100,117,112,108,105,99,97,116,101,115,46>>]}]},#{signature => [{attribute,{335,2},spec,{{to_sets,1},[{type,{335,14},bounded_fun,[{type,{335,14},'fun',[{type,{335,14},product,[{var,{335,15},'ASet'}]},{var,{335,24},'Sets'}]},[{type,{336,7},constraint,[{atom,{336,7},is_subtype},[{var,{336,7},'ASet'},{type,{336,15},union,[{user_type,{336,15},a_set,[]},{user_type,{336,25},ordset,[]}]}]]},{type,{337,7},constraint,[{atom,{337,7},is_subtype},[{var,{337,7},'Sets'},{type,{337,15},union,[{user_type,{337,15},tuple_of,[{var,{337,24},'AnySet'}]},{type,{337,34},list,[{var,{337,35},'AnySet'}]}]}]]},{type,{338,7},constraint,[{atom,{338,7},is_subtype},[{var,{338,7},'AnySet'},{user_type,{338,17},anyset,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,54,57,54>>}},{{function,type,1},[{file,[115,111,102,115,46,101,114,108]},{location,327}],[<<116,121,112,101,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<32,111,102,32,97,110,32,97,116,111,109,105,99,44,32,111,114,100,101,114,101,100,44,32,111,114,32,117,110,111,114,100,101,114,101,100,32,115,101,116,46>>]}]},#{signature => [{attribute,{327,2},spec,{{type,1},[{type,{327,11},bounded_fun,[{type,{327,11},'fun',[{type,{327,11},product,[{var,{327,12},'AnySet'}]},{var,{327,23},'Type'}]},[{type,{328,7},constraint,[{atom,{328,7},is_subtype},[{var,{328,7},'AnySet'},{user_type,{328,17},anyset,[]}]]},{type,{329,7},constraint,[{atom,{329,7},is_subtype},[{var,{329,7},'Type'},{user_type,{329,15},type,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,48,55>>}},{{function,union,1},[{file,[115,111,102,115,46,101,114,108]},{location,553}],[<<117,110,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110,95,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32,116,104,101,32,115,101,116,32,111,102,32,115,101,116,115,32>>,{code,[],[<<83,101,116,79,102,83,101,116,115>>]},<<46>>]}]},#{signature => [{attribute,{553,2},spec,{{union,1},[{type,{553,12},bounded_fun,[{type,{553,12},'fun',[{type,{553,12},product,[{var,{553,13},'SetOfSets'}]},{var,{553,27},'Set'}]},[{type,{554,7},constraint,[{atom,{554,7},is_subtype},[{var,{554,7},'Set'},{user_type,{554,14},a_set,[]}]]},{type,{555,7},constraint,[{atom,{555,7},is_subtype},[{var,{555,7},'SetOfSets'},{user_type,{555,20},set_of_sets,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,49,54>>}},{{function,union,2},[{file,[115,111,102,115,46,101,114,108]},{location,378}],[<<117,110,105,111,110,47,50>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,117,110,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,105,111,110>>]},<<32,111,102,32>>,{code,[],[<<83,101,116,49>>]},<<32,97,110,100,32>>,{code,[],[<<83,101,116,50>>]},<<46>>]}]},#{signature => [{attribute,{378,2},spec,{{union,2},[{type,{378,12},bounded_fun,[{type,{378,12},'fun',[{type,{378,12},product,[{var,{378,13},'Set1'},{var,{378,19},'Set2'}]},{var,{378,28},'Set3'}]},[{type,{379,7},constraint,[{atom,{379,7},is_subtype},[{var,{379,7},'Set1'},{user_type,{379,15},a_set,[]}]]},{type,{380,7},constraint,[{atom,{380,7},is_subtype},[{var,{380,7},'Set2'},{user_type,{380,15},a_set,[]}]]},{type,{381,7},constraint,[{atom,{381,7},is_subtype},[{var,{381,7},'Set3'},{user_type,{381,15},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,50,53>>}},{{function,union_of_family,1},[{file,[115,111,102,115,46,101,114,108]},{location,1288}],[<<117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,116,104,101,32,117,110,105,111,110,32,111,102,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32>>,{code,[],[<<70,97,109,105,108,121>>]},<<46>>]},{pre,[],[{code,[],[<<49,62,32,70,32,61,32,115,111,102,115,58,102,97,109,105,108,121,40,91,123,97,44,91,48,44,50,44,52,93,125,44,123,98,44,91,48,44,49,44,50,93,125,44,123,99,44,91,50,44,51,93,125,93,41,44,10,83,32,61,32,115,111,102,115,58,117,110,105,111,110,95,111,102,95,102,97,109,105,108,121,40,70,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,83,41,46,10,91,48,44,49,44,50,44,51,44,52,93>>]}]}]},#{signature => [{attribute,{1288,2},spec,{{union_of_family,1},[{type,{1288,22},bounded_fun,[{type,{1288,22},'fun',[{type,{1288,22},product,[{var,{1288,23},'Family'}]},{var,{1288,34},'Set'}]},[{type,{1289,7},constraint,[{atom,{1289,7},is_subtype},[{var,{1289,7},'Family'},{user_type,{1289,17},family,[]}]]},{type,{1290,7},constraint,[{atom,{1290,7},is_subtype},[{var,{1290,7},'Set'},{user_type,{1290,14},a_set,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,51,52>>}},{{function,weak_relation,1},[{file,[115,111,102,115,46,101,114,108]},{location,763}],[<<119,101,97,107,95,114,101,108,97,116,105,111,110,47,49>>],#{<<101,110>> => [{p,[],[<<82,101,116,117,114,110,115,32,97,32,115,117,98,115,101,116,32,83,32,111,102,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,119,101,97,107,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<119,101,97,107,32,114,101,108,97,116,105,111,110>>]},<<32,87,32,99,111,114,114,101,115,112,111,110,100,105,110,103,32,116,111,32,116,104,101,32,98,105,110,97,114,121,32,114,101,108,97,116,105,111,110,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46,32,76,101,116,32,70,32,98,101,32,116,104,101,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,105,101,108,100>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,105,101,108,100>>]},<<32,111,102,32>>,{code,[],[<<66,105,110,82,101,108,49>>]},<<46,32,84,104,101,32,115,117,98,115,101,116,32,83,32,105,115,32,100,101,102,105,110,101,100,32,115,111,32,116,104,97,116,32,120,32,83,32,121,32,105,102,32,120,32,87,32,121,32,102,111,114,32,115,111,109,101,32,120,32,105,110,32,70,32,97,110,100,32,102,111,114,32,115,111,109,101,32,121,32,105,110,32,70,46>>]},{pre,[],[{code,[],[<<49,62,32,82,49,32,61,32,115,111,102,115,58,114,101,108,97,116,105,111,110,40,91,123,49,44,49,125,44,123,49,44,50,125,44,123,51,44,49,125,93,41,44,10,82,50,32,61,32,115,111,102,115,58,119,101,97,107,95,114,101,108,97,116,105,111,110,40,82,49,41,44,10,115,111,102,115,58,116,111,95,101,120,116,101,114,110,97,108,40,82,50,41,46,10,91,123,49,44,49,125,44,123,49,44,50,125,44,123,50,44,50,125,44,123,51,44,49,125,44,123,51,44,51,125,93>>]}]}]},#{signature => [{attribute,{763,2},spec,{{weak_relation,1},[{type,{763,20},bounded_fun,[{type,{763,20},'fun',[{type,{763,20},product,[{var,{763,21},'BinRel1'}]},{var,{763,33},'BinRel2'}]},[{type,{764,7},constraint,[{atom,{764,7},is_subtype},[{var,{764,7},'BinRel1'},{user_type,{764,18},binary_relation,[]}]]},{type,{765,7},constraint,[{atom,{765,7},is_subtype},[{var,{765,7},'BinRel2'},{user_type,{765,18},binary_relation,[]}]]}]]}]}}],edit_url => <<104,116,116,112,115,58,47,47,103,105,116,104,117,98,46,99,111,109,47,101,114,108,97,110,103,47,111,116,112,47,101,100,105,116,47,109,97,105,110,116,47,108,105,98,47,115,116,100,108,105,98,47,100,111,99,47,115,114,99,47,115,111,102,115,46,120,109,108,35,76,49,55,52,56>>}},{{type,anyset,0},[{file,[115,111,102,115,46,101,114,108]},{location,117}],[<<45,116,121,112,101,32,97,110,121,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,121,32,107,105,110,100,32,111,102,32,115,101,116,32,40,97,108,115,111,32,105,110,99,108,117,100,101,100,32,97,114,101,32,116,104,101,32,97,116,111,109,105,99,32,115,101,116,115,41,46>>]}]},#{signature => [{attribute,{117,2},type,{anyset,{type,{117,19},union,[{user_type,{117,19},ordset,[]},{user_type,{117,30},a_set,[]}]},[]}}]}},{{type,binary_relation,0},[{file,[115,111,102,115,46,101,114,108]},{location,118}],[<<45,116,121,112,101,32,98,105,110,97,114,121,95,114,101,108,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,98,105,110,97,114,121,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<98,105,110,97,114,121,32,114,101,108,97,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,{118,2},type,{binary_relation,{user_type,{118,28},relation,[]},[]}}]}},{{type,external_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,119}],[<<45,116,121,112,101,32,101,120,116,101,114,110,97,108,95,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,101,120,116,101,114,110,97,108,95,115,101,116>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<101,120,116,101,114,110,97,108,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,{119,2},type,{external_set,{type,{119,25},term,[]},[]}}]}},{{type,family,0},[{file,[115,111,102,115,46,101,114,108]},{location,121}],[<<45,116,121,112,101,32,102,97,109,105,108,121,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,97,109,105,108,121>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,97,109,105,108,121>>]},<<32,40,111,102,32,115,117,98,115,101,116,115,41,46>>]}]},#{signature => [{attribute,{121,2},type,{family,{user_type,{121,19},a_function,[]},[]}}]}},{{type,a_function,0},[{file,[115,111,102,115,46,101,114,108]},{location,120}],[<<45,116,121,112,101,32,97,95,102,117,110,99,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,102,117,110,99,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<102,117,110,99,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,{120,2},type,{a_function,{user_type,{120,23},relation,[]},[]}}]}},{{type,ordset,0},[{file,[115,111,102,115,46,101,114,108]},{location,122}],[<<45,116,121,112,101,32,111,114,100,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<111,114,100,101,114,101,100,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,{122,2},opaque,{ordset,{type,{122,21},record,[{atom,{122,23},'OrdSet'}]},[]}}]}},{{type,relation,0},[{file,[115,111,102,115,46,101,114,108]},{location,123}],[<<45,116,121,112,101,32,114,101,108,97,116,105,111,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,110,95,97,114,121,95,114,101,108,97,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<110,45,97,114,121,32,114,101,108,97,116,105,111,110>>]},<<46>>]}]},#{signature => [{attribute,{123,2},type,{relation,{user_type,{123,21},a_set,[]},[]}}]}},{{type,a_set,0},[{file,[115,111,102,115,46,101,114,108]},{location,124}],[<<45,116,121,112,101,32,97,95,115,101,116,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<46>>]}]},#{signature => [{attribute,{124,2},opaque,{a_set,{type,{124,20},record,[{atom,{124,22},'Set'}]},[]}}]}},{{type,set_of_sets,0},[{file,[115,111,102,115,46,101,114,108]},{location,125}],[<<45,116,121,112,101,32,115,101,116,95,111,102,95,115,101,116,115,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,110,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,115,95,100,101,102,105,110,105,116,105,111,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<117,110,111,114,100,101,114,101,100,32,115,101,116>>]},<<32,111,102,32,117,110,111,114,100,101,114,101,100,32,115,101,116,115,46>>]}]},#{signature => [{attribute,{125,2},type,{set_of_sets,{user_type,{125,24},a_set,[]},[]}}]}},{{type,set_fun,0},[{file,[115,111,102,115,46,101,114,108]},{location,126}],[<<45,116,121,112,101,32,115,101,116,95,102,117,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,115,101,116,95,102,117,110>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<83,101,116,70,117,110>>]},<<46>>]}]},#{signature => [{attribute,{126,2},type,{set_fun,{type,{126,20},union,[{type,{126,20},pos_integer,[]},{type,{127,20},tuple,[{atom,{127,21},external},{type,{127,35},'fun',[{type,{127,35},product,[{user_type,{127,36},external_set,[]}]},{user_type,{127,55},external_set,[]}]}]},{type,{128,24},'fun',[{type,{128,24},product,[{user_type,{128,25},anyset,[]}]},{user_type,{128,38},anyset,[]}]}]},[]}}]}},{{type,spec_fun,0},[{file,[115,111,102,115,46,101,114,108]},{location,129}],[<<45,116,121,112,101,32,115,112,101,99,95,102,117,110,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{},#{signature => [{attribute,{129,2},type,{spec_fun,{type,{129,21},union,[{type,{129,21},tuple,[{atom,{129,22},external},{type,{129,36},'fun',[{type,{129,36},product,[{user_type,{129,37},external_set,[]}]},{type,{129,56},boolean,[]}]}]},{type,{130,25},'fun',[{type,{130,25},product,[{user_type,{130,26},anyset,[]}]},{type,{130,39},boolean,[]}]}]},[]}}]}},{{type,type,0},[{file,[115,111,102,115,46,101,114,108]},{location,131}],[<<45,116,121,112,101,32,116,121,112,101,40,41,32,58,58,32,116,101,114,109,40,41,46>>],#{<<101,110>> => [{p,[],[<<65,32>>,{a,[{href,<<115,116,100,108,105,98,58,115,111,102,115,35,116,121,112,101>>},{rel,<<104,116,116,112,115,58,47,47,101,114,108,97,110,103,46,111,114,103,47,100,111,99,47,108,105,110,107,47,115,101,101,101,114,108>>}],[<<116,121,112,101>>]},<<46>>]}]},#{signature => [{attribute,{131,2},type,{type,{type,{131,17},term,[]},[]}}]}},{{type,tuple_of,1},[{file,[115,111,102,115,46,101,114,108]},{location,0}],[<<116,117,112,108,101,95,111,102,40,84,41>>],#{<<101,110>> => [{p,[],[<<65,32,116,117,112,108,101,32,119,104,101,114,101,32,116,104,101,32,101,108,101,109,101,110,116,115,32,97,114,101,32,111,102,32,116,121,112,101,32>>,{code,[],[<<84>>]},<<46>>]}]},#{}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re.txt index 21a3dbf48754..2d8a293de20c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re.txt @@ -1645,9 +1645,6 @@ alpha: Letters - ascii: - Character codes 0-127 - blank: Space or tab only @@ -1681,6 +1678,12 @@ xdigit: Hexadecimal digits + There is another character class, ascii, that erroneously + matches Latin-1 characters instead of the 0-127 range specified by + POSIX. This cannot be fixed without altering the behaviour of + other classes, so we recommend matching the range with [\\0-\x7f] + instead. + The default "space" characters are HT (9), LF (10), VT (11), FF (12), CR (13), and space (32). If locale-specific matching is taking place, the list of space characters may be different; there diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_grun_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_grun_3_func.txt new file mode 100644 index 000000000000..6f0af3fc677e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_grun_3_func.txt @@ -0,0 +1,5 @@ + +  grun/3 + + The documentation for grun/3 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_internal_run_4_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_internal_run_4_func.txt new file mode 100644 index 000000000000..d896aabce3d1 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_internal_run_4_func.txt @@ -0,0 +1,6 @@ + +  internal_run/4 + + The documentation for internal_run/4 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_3_func.txt index 5f472a27c099..6bbe4b2eaedb 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_3_func.txt @@ -3,6 +3,7 @@  when  Subject :: iodata() | unicode:charlist(),  RE :: mp() | iodata(), -  Replacement :: iodata() | unicode:charlist(). +  Replacement :: +  iodata() | unicode:charlist() | replace_fun(). Same as replace(Subject, RE, Replacement, []). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_4_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_4_func.txt index 4795d589e704..b6b326c1d55d 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_4_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_4_func.txt @@ -4,7 +4,8 @@  when  Subject :: iodata() | unicode:charlist(),  RE :: mp() | iodata() | unicode:charlist(), -  Replacement :: iodata() | unicode:charlist(), +  Replacement :: +  iodata() | unicode:charlist() | replace_fun(),  Options :: [Option],  Option ::  anchored | global | notbol | noteol | @@ -21,8 +22,8 @@  CompileOpt :: compile_option(),  NLSpec :: cr | crlf | lf | anycrlf | any. - Replaces the matched part of the Subject string with the - contents of Replacement. + Replaces the matched part of the Subject string with  + Replacement. The permissible options are the same as for run/3, except that option capture is not allowed. Instead a {return, ReturnType} @@ -37,12 +38,13 @@ to this function, both the regular expression and Subject are to specified as valid Unicode charlist()s. - The replacement string can contain the special character &, - which inserts the whole matching expression in the result, and the - special sequence \N (where N is an integer > 0), \gN, or \g{ - N}, resulting in the subexpression number N, is inserted in the - result. If no subexpression with that number is generated by the - regular expression, nothing is inserted. + If the replacement is given as a string, it can contain the + special character &, which inserts the whole matching expression + in the result, and the special sequence \N (where N is an + integer > 0), \gN, or \g{N}, resulting in the subexpression + number N, is inserted in the result. If no subexpression with that + number is generated by the regular expression, nothing is + inserted. To insert an & or a \ in the result, precede it with a \. Notice that Erlang already gives a special meaning to \ in literal @@ -65,5 +67,40 @@ "ab[&]d" + If the replacement is given as a fun, it will be called with the + whole matching expression as the first argument and a list of + subexpression matches in the order in which they appear in the + regular expression. The returned value will be inserted in the + result. + + Example: + + re:replace("abcd", ".(.)", fun(Whole, [<>]) -> <<$#, Whole/binary, $-, (C - $a + $A), $#>> end, [{return, list}]). + + gives + + "#ab-B#cd" + + Note: + Non-matching optional subexpressions will not be included in + the list of subexpression matches if they are the last + subexpressions in the regular expression. + + Example: + + The regular expression "(a)(b)?(c)?" ("a", optionally + followed by "b", optionally followed by "c") will create the + following subexpression lists: + + • [<<"a">>, <<"b">>, <<"c">>] when applied to the string  + "abc" + + • [<<"a">>, <<>>, <<"c">>] when applied to the string  + "acx" + + • [<<"a">>, <<"b">>] when applied to the string "abx" + + • [<<"a">>] when applied to the string "axx" + As with run/3, compilation errors raise the badarg exception.  compile/2 can be used to get more information about the error. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_fun_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_fun_0_type.txt new file mode 100644 index 000000000000..9d139cac6af4 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_replace_fun_0_type.txt @@ -0,0 +1,5 @@ + + -type replace_fun() :: +  fun((binary(), [binary()]) -> iodata() | unicode:charlist()). + + There is no documentation for replace_fun/0 diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_type.txt index 2da7c993a8e0..ee7b48eb2bea 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_type.txt @@ -13,3 +13,6 @@ These types are documented in this module:  {newline, nl_spec()} |  bsr_anycrlf | bsr_unicode | no_start_optimize | ucp |  never_utf. + + -type replace_fun() :: +  fun((binary(), [binary()]) -> iodata() | unicode:charlist()). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_ucompile_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_ucompile_2_func.txt new file mode 100644 index 000000000000..148c48a4b028 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_ucompile_2_func.txt @@ -0,0 +1,5 @@ + +  ucompile/2 + + The documentation for ucompile/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_urun_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_urun_3_func.txt new file mode 100644 index 000000000000..ddfb951486ec --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_re_urun_3_func.txt @@ -0,0 +1,5 @@ + +  urun/3 + + The documentation for urun/3 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs.txt index 6a15acf04564..692e4b4ff608 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs.txt @@ -6,6 +6,12 @@ elements; every element belongs to the set, and the set contains every element. + The data representing sofs as used by this module is to be + regarded as opaque by other modules. In abstract terms, the + representation is a composite type of existing Erlang terms. See + note on data types. Any code assuming knowledge of the format is + running on thin ice. + Given a set A and a sentence S(x), where x is a free variable, a new set B whose elements are exactly those elements of A for which S(x) holds can be formed, this is denoted B = {x in A : S(x)}. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_fam2rel_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_fam2rel_1_func.txt new file mode 100644 index 000000000000..1eafcb4078c3 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_fam2rel_1_func.txt @@ -0,0 +1,5 @@ + +  fam2rel/1 + + The documentation for fam2rel/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_from_sets_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_from_sets_1_func.txt index 365a3d53849a..c3b7d802cc62 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_from_sets_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_from_sets_1_func.txt @@ -1,9 +1,4 @@ - -spec from_sets(TupleOfSets) -> Ordset -  when -  Ordset :: ordset(), -  TupleOfSets :: tuple_of(anyset()). - -spec from_sets(ListOfSets) -> Set  when Set :: a_set(), ListOfSets :: [anyset()]. @@ -15,3 +10,11 @@ S = sofs:from_sets([S1,S2]), sofs:to_external(S). [[{a,1},{b,2}],[{x,3},{y,4}]] + + -spec from_sets(TupleOfSets) -> Ordset +  when +  Ordset :: ordset(), +  TupleOfSets :: tuple_of(anyset()). + + Returns the ordered set containing the sets of the non-empty + tuple TupleOfSets. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_set_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_set_1_func.txt index fdbfefd286a9..9d8a8ee7757a 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_set_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_set_1_func.txt @@ -1,5 +1,8 @@ -spec is_set(AnySet) -> Bool when AnySet :: anyset(), Bool :: boolean(). - Returns true if AnySet is an unordered set, and false if  - AnySet is an ordered set or an atomic set. + Returns true if AnySet appears to be an unordered set, and  + false if AnySet is an ordered set or an atomic set or any other + term. Note that the test is shallow and this function will return  + true for any term that coincides with the representation of an + unordered set. See also note on data types. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_sofs_set_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_sofs_set_1_func.txt index 351cd92e0e1a..c510929f9d0c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_sofs_set_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_is_sofs_set_1_func.txt @@ -1,5 +1,7 @@ -spec is_sofs_set(Term) -> Bool when Bool :: boolean(), Term :: term(). - Returns true if Term is an unordered set, an ordered set, or - an atomic set, otherwise false. + Returns true if Term appears to be an unordered set, an + ordered set, or an atomic set, otherwise false. Note that this + function will return true for any term that coincides with the + representation of a sofs set. See also note on data types. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_rel2fam_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_rel2fam_1_func.txt new file mode 100644 index 000000000000..d41d2c6c1801 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_rel2fam_1_func.txt @@ -0,0 +1,5 @@ + +  rel2fam/1 + + The documentation for rel2fam/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_tuple_of_1_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_tuple_of_1_type.txt index 7d953de0e7dc..38069a070720 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_tuple_of_1_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_tuple_of_1_type.txt @@ -1,4 +1,4 @@ - -type tuple_of(_T) :: tuple(). +  tuple_of(T) A tuple where the elements are of type T. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_type.txt index c3f31f2fd853..bed79d0171af 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/stdlib_sofs_type.txt @@ -31,4 +31,4 @@ These types are documented in this module: -type type() :: term(). - -type tuple_of(_T) :: tuple(). +  tuple_of(T) diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang.txt index a2fb62f0d0b1..b275eb19daad 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang.txt @@ -1,16 +1,21 @@  erlang - By convention, most Built-In Functions (BIFs) are included in this - module. Some of the BIFs are viewed more or less as part of the - Erlang programming language and are auto-imported. Thus, it is - not necessary to specify the module name. For example, the calls  + By convention, most Built-In Functions (BIFs) and all predefined + types are included in this module. Some of the BIFs and all of the + predefined types are viewed more or less as part of the Erlang + programming language and are auto-imported. Thus, it is not + necessary to specify the module name. For example, the calls  atom_to_list(erlang) and erlang:atom_to_list(erlang) are identical. Auto-imported BIFs are listed without module prefix. BIFs listed with module prefix are not auto-imported. + Predefined types are listed in the Predefined datatypes section + of this reference manual and in the Types and Function + Specifications section of the Erlang Reference Manual. + BIFs can fail for various reasons. All BIFs fail with reason  badarg if they are called with arguments of an incorrect type. The other reasons are described in the description of each diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_!_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_!_2_func.txt new file mode 100644 index 000000000000..222e8527641c --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_!_2_func.txt @@ -0,0 +1,5 @@ + +  '!'/2 + + The documentation for '!'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_++_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_++_2_func.txt new file mode 100644 index 000000000000..5dcd568da562 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_++_2_func.txt @@ -0,0 +1,5 @@ + +  '++'/2 + + The documentation for '++'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_1_func.txt new file mode 100644 index 000000000000..e3ecf4bf3c24 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_1_func.txt @@ -0,0 +1,5 @@ + +  '+'/1 + + The documentation for '+'/1 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_2_func.txt new file mode 100644 index 000000000000..bf738628fcac --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_+_2_func.txt @@ -0,0 +1,5 @@ + +  '+'/2 + + The documentation for '+'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_--_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_--_2_func.txt new file mode 100644 index 000000000000..797d1d5b4505 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_--_2_func.txt @@ -0,0 +1,5 @@ + +  '--'/2 + + The documentation for '--'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_1_func.txt new file mode 100644 index 000000000000..51cf37438652 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_1_func.txt @@ -0,0 +1,5 @@ + +  '-'/1 + + The documentation for '-'/1 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_2_func.txt new file mode 100644 index 000000000000..797a700c8696 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_-_2_func.txt @@ -0,0 +1,5 @@ + +  '-'/2 + + The documentation for '-'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_0_func.txt index 0b0446302fbe..150c8604b9b8 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_0_func.txt @@ -2,7 +2,7 @@ -spec alias() -> Alias when Alias :: reference(). Since: - OTP @OTP-16718@ + OTP 24.0 Create an alias which can be used when sending messages to the process that created the alias. When the alias has been @@ -19,3 +19,36 @@ The alias will be automatically deactivated when a reply message sent via the alias is received. The alias can also still be deactivated via a call to unalias/1. + + Example: + + server() -> + receive + {request, AliasReqId, Request} -> + Result = perform_request(Request), + AliasReqId ! {reply, AliasReqId, Result} + end, + server(). + + client(ServerPid, Request) -> + AliasReqId = alias([reply]), + ServerPid ! {request, AliasReqId, Request}, + %% Alias will be automatically deactivated if we receive a reply + %% since we used the 'reply' option... + receive + {reply, AliasReqId, Result} -> Result + after 5000 -> + unalias(AliasReqId), + %% Flush message queue in case the reply arrived + %% just before the alias was deactivated... + receive {reply, AliasReqId, Result} -> Result + after 0 -> exit(timeout) + end + end. + + + Note that both the server and the client in this example must be + executing on at least OTP 24 systems in order for this to work. + + For more information on process aliases see the Process Aliases + section of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_1_func.txt index 291db25ac30e..03aa38c1cd9c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alias_1_func.txt @@ -5,7 +5,7 @@  Opts :: [explicit_unalias | reply]. Since: - OTP @OTP-16718@ + OTP 24.0 Create an alias which can be used when sending messages to the process that created the alias. When the alias has been @@ -22,3 +22,36 @@ The alias will be automatically deactivated when a reply message sent via the alias is received. The alias can also still be deactivated via a call to unalias/1. + + Example: + + server() -> + receive + {request, AliasReqId, Request} -> + Result = perform_request(Request), + AliasReqId ! {reply, AliasReqId, Result} + end, + server(). + + client(ServerPid, Request) -> + AliasReqId = alias([reply]), + ServerPid ! {request, AliasReqId, Request}, + %% Alias will be automatically deactivated if we receive a reply + %% since we used the 'reply' option... + receive + {reply, AliasReqId, Result} -> Result + after 5000 -> + unalias(AliasReqId), + %% Flush message queue in case the reply arrived + %% just before the alias was deactivated... + receive {reply, AliasReqId, Result} -> Result + after 0 -> exit(timeout) + end + end. + + + Note that both the server and the client in this example must be + executing on at least OTP 24 systems in order for this to work. + + For more information on process aliases see the Process Aliases + section of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_info_1_func.txt new file mode 100644 index 000000000000..110bd44e5360 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_info_1_func.txt @@ -0,0 +1,6 @@ + +  alloc_info/1 + + The documentation for alloc_info/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_sizes_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_sizes_1_func.txt new file mode 100644 index 000000000000..e2abffaa6e50 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_alloc_sizes_1_func.txt @@ -0,0 +1,6 @@ + +  alloc_sizes/1 + + The documentation for alloc_sizes/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_and_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_and_2_func.txt new file mode 100644 index 000000000000..820cf8347533 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_and_2_func.txt @@ -0,0 +1,5 @@ + +  'and'/2 + + The documentation for 'and'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_any_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_any_0_type.txt new file mode 100644 index 000000000000..99d9f7affa8a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_any_0_type.txt @@ -0,0 +1,4 @@ + + -type any() :: any(). + + All possible Erlang terms. Synonym for term(). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_append_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_append_2_func.txt new file mode 100644 index 000000000000..a65746afaf96 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_append_2_func.txt @@ -0,0 +1,5 @@ + +  append/2 + + The documentation for append/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_arity_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_arity_0_type.txt new file mode 100644 index 000000000000..0ff062f3dc6b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_arity_0_type.txt @@ -0,0 +1,4 @@ + + -type arity() :: arity(). + + The arity of a function or type. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_0_type.txt new file mode 100644 index 000000000000..44e92c956057 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_0_type.txt @@ -0,0 +1,4 @@ + + -type atom() :: atom(). + + An Erlang atom. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_to_binary_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_to_binary_2_func.txt index 28c97262c1cc..71413f11a8a5 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_to_binary_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_atom_to_binary_2_func.txt @@ -10,7 +10,7 @@ characters are encoded using UTF-8 where characters may require multiple bytes. - Note: + Change: As from Erlang/OTP 20, atoms can contain any Unicode character and atom_to_binary(Atom, latin1) may fail if the text representation for Atom contains a Unicode character > 255. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_band_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_band_2_func.txt new file mode 100644 index 000000000000..f3781ac0e0bc --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_band_2_func.txt @@ -0,0 +1,5 @@ + +  'band'/2 + + The documentation for 'band'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_0_type.txt new file mode 100644 index 000000000000..25e2353a9a67 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_0_type.txt @@ -0,0 +1,5 @@ + + -type binary() :: <<_:_*8>>. + + An Erlang binary, that is, a bitstring with a size divisible by + 8. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_atom_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_atom_2_func.txt index e86900006dac..1c6454304b77 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_atom_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_atom_2_func.txt @@ -8,13 +8,10 @@ Encoding is utf8 or unicode, the binary must contain valid UTF-8 sequences. - Note: + Change: As from Erlang/OTP 20, binary_to_atom(Binary, utf8) is - capable of encoding any Unicode character. Earlier versions + capable of decoding any Unicode character. Earlier versions would fail if the binary contained Unicode characters > 255. - For more information about Unicode support in atoms, see the - note on UTF-8 encoded atoms in section "External Term Format" - in the User's Guide. Note: The number of characters that are permitted in an atom name is diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_1_func.txt index 53488792d3bc..413260f6a8a9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_1_func.txt @@ -11,7 +11,10 @@ hello Warning: - When decoding binaries from untrusted sources, consider using  - binary_to_term/2 to prevent Denial of Service attacks. + When decoding binaries from untrusted sources, the untrusted + source may submit data in a way to create resources, such as + atoms and remote references, that cannot be garbage collected + and lead to Denial of Service attack. In such cases, consider + using binary_to_term/2 with the safe option. See also term_to_binary/1 and binary_to_term/2. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_2_func.txt index 026b8d18cb92..60e6109348c0 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_binary_to_term_2_func.txt @@ -16,7 +16,7 @@ source. When enabled, it prevents decoding data that can be used to - attack the Erlang system. In the event of receiving unsafe + attack the Erlang runtime. In the event of receiving unsafe data, decoding fails with a badarg error. This prevents creation of new atoms directly, creation of new @@ -33,6 +33,14 @@ > binary_to_term(<<131,100,0,5,"hello">>, [safe]). hello + Warning: + The safe option ensures the data is safely processed by + the Erlang runtime but it does not guarantee the data is + safe to your application. You must always validate data + from untrusted sources. If the binary is stored or + transits through untrusted sources, you should also + consider cryptographically signing it. + used: Changes the return value to {Term, Used} where Used is the number of bytes actually read from Binary. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bitstring_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bitstring_0_type.txt new file mode 100644 index 000000000000..71ffcc1f02c1 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bitstring_0_type.txt @@ -0,0 +1,4 @@ + + -type bitstring() :: <<_:_*1>>. + + An Erlang bitstring. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bnot_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bnot_1_func.txt new file mode 100644 index 000000000000..7fb3acadcccf --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bnot_1_func.txt @@ -0,0 +1,5 @@ + +  'bnot'/1 + + The documentation for 'bnot'/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_boolean_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_boolean_0_type.txt new file mode 100644 index 000000000000..1cda883d3bac --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_boolean_0_type.txt @@ -0,0 +1,4 @@ + + -type boolean() :: true | false. + + A boolean value. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bor_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bor_2_func.txt new file mode 100644 index 000000000000..698de2bfe3b3 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bor_2_func.txt @@ -0,0 +1,5 @@ + +  'bor'/2 + + The documentation for 'bor'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsl_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsl_2_func.txt new file mode 100644 index 000000000000..65b26f4c0398 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsl_2_func.txt @@ -0,0 +1,5 @@ + +  'bsl'/2 + + The documentation for 'bsl'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsr_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsr_2_func.txt new file mode 100644 index 000000000000..6b6849672f79 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bsr_2_func.txt @@ -0,0 +1,5 @@ + +  'bsr'/2 + + The documentation for 'bsr'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bxor_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bxor_2_func.txt new file mode 100644 index 000000000000..76aa3fbe7e5b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_bxor_2_func.txt @@ -0,0 +1,5 @@ + +  'bxor'/2 + + The documentation for 'bxor'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_byte_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_byte_0_type.txt new file mode 100644 index 000000000000..6f6c6b4b28c5 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_byte_0_type.txt @@ -0,0 +1,4 @@ + + -type byte() :: 0..255. + + A byte of data represented by an integer. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_call_on_load_function_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_call_on_load_function_1_func.txt new file mode 100644 index 000000000000..abf49640cc84 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_call_on_load_function_1_func.txt @@ -0,0 +1,6 @@ + +  call_on_load_function/1 + + The documentation for call_on_load_function/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_char_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_char_0_type.txt new file mode 100644 index 000000000000..e0c2f2333f80 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_char_0_type.txt @@ -0,0 +1,5 @@ + + -type char() :: 0..1114111. + + An ASCII character or a unicode codepoint presented by an + integer. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_check_process_code_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_check_process_code_3_func.txt index 42497e39ce56..c0e6da2c317f 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_check_process_code_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_check_process_code_3_func.txt @@ -58,7 +58,7 @@ collected to determine the operation result, and the operation was requested by passing option {allow_gc, false}. - Note: + Change: Up until ERTS version 8.*, the check process code operation checks for all types of references to the old code. That is, direct references (e.g. return addresses on the process diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_decode_packet_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_decode_packet_3_func.txt index 702ef8125e4f..ce97517bf3b9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_decode_packet_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_decode_packet_3_func.txt @@ -169,6 +169,9 @@ The variants http_bin and httph_bin return strings ( HttpString) as binaries instead of lists. + Since OTP 26.0, Host may be an IPv6 address enclosed in [], + as defined in RFC2732 . + Options: {packet_size, integer() >= 0}: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_delay_trap_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_delay_trap_2_func.txt new file mode 100644 index 000000000000..6e1f78dcaa4a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_delay_trap_2_func.txt @@ -0,0 +1,6 @@ + +  delay_trap/2 + + The documentation for delay_trap/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_1_func.txt index c67ac6c999f5..35cff119e6d6 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_1_func.txt @@ -16,6 +16,11 @@ demonitor(MonitorRef) if this cleanup is wanted. Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + + Change: Before Erlang/OTP R11B (ERTS 5.5) demonitor/1 behaved completely asynchronously, that is, the monitor was active until the "demonitor signal" reached the monitored entity. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_2_func.txt index 3f2de9014fde..c6e1bd00c7aa 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_demonitor_2_func.txt @@ -44,7 +44,7 @@ If option info is combined with option flush, false is returned if a flush was needed, otherwise true. - Note: + Change: More options can be added in a future release. Failures: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_1_func.txt index 77ef6f1321cc..eb8a662906d4 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_1_func.txt @@ -4,4 +4,6 @@ Prints a text representation of Term on the standard output. Warning: - This BIF is intended for debugging only. + This BIF is intended for debugging only. The printed + representation may contain internal details that do not match + the high-level representation of the term in Erlang. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_nl_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_nl_0_func.txt new file mode 100644 index 000000000000..4378ba670f5e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_nl_0_func.txt @@ -0,0 +1,6 @@ + +  display_nl/0 + + The documentation for display_nl/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_1_func.txt new file mode 100644 index 000000000000..2d5267009aff --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_1_func.txt @@ -0,0 +1,6 @@ + +  display_string/1 + + The documentation for display_string/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_2_func.txt new file mode 100644 index 000000000000..e4777a8b4082 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_display_string_2_func.txt @@ -0,0 +1,6 @@ + +  display_string/2 + + The documentation for display_string/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_1_func.txt index 93228fd6e013..182a8e0ef142 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_1_func.txt @@ -28,7 +28,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_notification_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_notification_1_func.txt index 5f2e5b7212d7..02197ca80519 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_notification_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_data_notification_1_func.txt @@ -21,7 +21,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_opt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_opt_2_func.txt index 1f7cf3782f1e..7e9050f105e4 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_opt_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_get_opt_2_func.txt @@ -19,7 +19,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_input_handler_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_input_handler_2_func.txt index 05201a2dc0ef..0e8202aa109d 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_input_handler_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_input_handler_2_func.txt @@ -11,7 +11,7 @@ channel identified by DHandle. Once this function has been called, InputHandler is the only process allowed to call  erlang:dist_ctrl_put_data(DHandle, Data) with the DHandle - identifing this distribution channel. + identifying this distribution channel. Note: Only the process registered as distribution controller for the @@ -20,7 +20,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_put_data_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_put_data_2_func.txt index 65c6b53d1032..1279f67fa38b 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_put_data_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_put_data_2_func.txt @@ -22,7 +22,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_set_opt_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_set_opt_3_func.txt index 355a006814c1..70c5a443342c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_set_opt_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_ctrl_set_opt_3_func.txt @@ -35,7 +35,7 @@ This function is used when implementing an alternative distribution carrier using processes as distribution controllers.  - DHandle is retrived via the callback f_handshake_complete. More - information can be found in the documentation of ERTS User's + DHandle is retrieved via the callback f_handshake_complete. + More information can be found in the documentation of ERTS User's Guide ➜ How to implement an Alternative Carrier for the Erlang Distribution ➜ Distribution Module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_get_stat_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_get_stat_1_func.txt new file mode 100644 index 000000000000..141fe118ae82 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_get_stat_1_func.txt @@ -0,0 +1,6 @@ + +  dist_get_stat/1 + + The documentation for dist_get_stat/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_handle_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_handle_0_type.txt index 9bcad3af7485..e2a5c6426588 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_handle_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dist_handle_0_type.txt @@ -1,4 +1,4 @@ -opaque dist_handle()  - An opaque handle identifing a distribution channel. + An opaque handle identifying a distribution channel. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_div_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_div_2_func.txt new file mode 100644 index 000000000000..1b349e7ecf14 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_div_2_func.txt @@ -0,0 +1,5 @@ + +  'div'/2 + + The documentation for 'div'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dmonitor_node_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dmonitor_node_3_func.txt new file mode 100644 index 000000000000..a8ae9050634f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dmonitor_node_3_func.txt @@ -0,0 +1,6 @@ + +  dmonitor_node/3 + + The documentation for dmonitor_node/3 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_append_vm_tag_data_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_append_vm_tag_data_1_func.txt new file mode 100644 index 000000000000..456b93faba0a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_append_vm_tag_data_1_func.txt @@ -0,0 +1,6 @@ + +  dt_append_vm_tag_data/1 + + The documentation for dt_append_vm_tag_data/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_0_func.txt new file mode 100644 index 000000000000..0b06a2134f40 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_0_func.txt @@ -0,0 +1,6 @@ + +  dt_get_tag/0 + + The documentation for dt_get_tag/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_data_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_data_0_func.txt new file mode 100644 index 000000000000..b7f39991ef25 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_get_tag_data_0_func.txt @@ -0,0 +1,6 @@ + +  dt_get_tag_data/0 + + The documentation for dt_get_tag_data/0 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_prepend_vm_tag_data_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_prepend_vm_tag_data_1_func.txt new file mode 100644 index 000000000000..59c18346496c --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_prepend_vm_tag_data_1_func.txt @@ -0,0 +1,6 @@ + +  dt_prepend_vm_tag_data/1 + + The documentation for dt_prepend_vm_tag_data/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_put_tag_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_put_tag_1_func.txt new file mode 100644 index 000000000000..83906151a7f5 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_put_tag_1_func.txt @@ -0,0 +1,6 @@ + +  dt_put_tag/1 + + The documentation for dt_put_tag/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_restore_tag_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_restore_tag_1_func.txt new file mode 100644 index 000000000000..bf52d2f5d285 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_restore_tag_1_func.txt @@ -0,0 +1,6 @@ + +  dt_restore_tag/1 + + The documentation for dt_restore_tag/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_spread_tag_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_spread_tag_1_func.txt new file mode 100644 index 000000000000..6a8496bc588e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_dt_spread_tag_1_func.txt @@ -0,0 +1,6 @@ + +  dt_spread_tag/1 + + The documentation for dt_spread_tag/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqcoloneq_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqcoloneq_2_func.txt new file mode 100644 index 000000000000..00c8120ad8a5 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqcoloneq_2_func.txt @@ -0,0 +1,5 @@ + +  '=:='/2 + + The documentation for '=:='/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqeq_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqeq_2_func.txt new file mode 100644 index 000000000000..eab30981c216 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqeq_2_func.txt @@ -0,0 +1,5 @@ + +  '=='/2 + + The documentation for '=='/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqlt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqlt_2_func.txt new file mode 100644 index 000000000000..fce7453bc22e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqlt_2_func.txt @@ -0,0 +1,5 @@ + +  '=<'/2 + + The documentation for '=<'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqslasheq_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqslasheq_2_func.txt new file mode 100644 index 000000000000..69dfca83fc69 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_eqslasheq_2_func.txt @@ -0,0 +1,5 @@ + +  '=/='/2 + + The documentation for '=/='/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_1_func.txt index 6324d2884e1e..18c0010a758b 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_1_func.txt @@ -1,15 +1,14 @@ -spec error(Reason) -> no_return() when Reason :: term(). - Raises an exception of class error with the reason Reason, - where Reason is any term. The error reason is {Reason, Where}, - where Where is a list of the functions most recently called (the - current function first). As evaluating this function causes an - exception to be thrown, it has no return value. The intent of the - exception class error is to signal that an unexpected error has - happened (for example, a function is called with a parameter that - has an incorrect type). See the guide about errors and error - handling for additional information. Example: + Raises an exception of class error with the reason Reason. As + evaluating this function causes an exception to be thrown, it has + no return value. + + The intent of the exception class error is to signal that an + unexpected error has happened (for example, a function is called + with a parameter that has an incorrect type). See the guide about + errors and error handling for additional information. Example: > catch error(foobar). {'EXIT',{foobar,[{shell,apply_fun,3, diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_2_func.txt index 0b91e45030d5..9a87a345bb89 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_2_func.txt @@ -1,19 +1,19 @@ -spec error(Reason, Args) -> no_return() -  when Reason :: term(), Args :: [term()]. +  when Reason :: term(), Args :: [term()] | none. - Raises an exception of class error with the reason Reason, - where Reason is any term. The error reason is {Reason, Where}, - where Where is a list of the functions most recently called (the - current function first). Args is expected to be the list of - arguments for the current function; it is used to provide the - arguments for the current function in the term Where. As - evaluating this function causes an exception to be raised, it has - no return value. The intent of the exception class error is to - signal that an unexpected error has happened (for example, a - function is called with a parameter that has an incorrect type). - See the guide about errors and error handling for additional - information. Example: + Raises an exception of class error with the reason Reason.  + Args is expected to be the list of arguments for the current + function or the atom none. If it is a list, it is used to + provide the arguments for the current function in the stack + back-trace. If it is none, the arity of the calling function is + used in the stacktrace. As evaluating this function causes an + exception to be raised, it has no return value. + + The intent of the exception class error is to signal that an + unexpected error has happened (for example, a function is called + with a parameter that has an incorrect type). See the guide about + errors and error handling for additional information. Example: test.erl: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_3_func.txt index 0af05f72c5ad..73f183013f99 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_error_3_func.txt @@ -2,7 +2,7 @@ -spec error(Reason, Args, Options) -> no_return()  when  Reason :: term(), -  Args :: [term()], +  Args :: [term()] | none,  Options :: [Option],  Option :: {error_info, ErrorInfoMap},  ErrorInfoMap :: @@ -11,18 +11,27 @@  function => atom()}. Since: - 24.0 + OTP 24.0 - Raises an exception of class error with the reason Reason, - where Reason is any term. Args is expected to be the list of - arguments for the current function; it is used to provide the - arguments for the current function in the stack back-trace. If the  - {error_info, ErrorInfoMap} option is given, it will be injected - into the stacktrace. + Raises an exception of class error with the reason Reason.  + Args is expected to be the list of arguments for the current + function or the atom none. If it is a list, it is used to + provide the arguments for the current function in the stack + back-trace. If it is none, the arity of the calling function is + used in the stacktrace. As evaluating this function causes an + exception to be raised, it has no return value. - As evaluating this function causes an exception to be raised, it - has no return value. The intent of the exception class error is - to signal that an unexpected error has happened (for example, a - function is called with a parameter that has an incorrect type). - See the guide about errors and error handling for additional - information. + If the error_info option is given, the ErrorInfoMap will be + inserted into the stacktrace. The information given in the  + ErrorInfoMap is to be used by error formatters such as erl_error + to provide more context around an error. + + The default module of the ErrorInfoMap is the module that the + call to error/3 is made. The default function is format_error. + See format_error/2 for more details on how this + Module:Function/2 is to be used + + The intent of the exception class error is to signal that an + unexpected error has happened (for example, a function is called + with a parameter that has an incorrect type). See the guide about + errors and error handling for additional information. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_1_func.txt index f97e38039c5b..481fd9f793cf 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_1_func.txt @@ -1,13 +1,17 @@ -spec exit(Reason) -> no_return() when Reason :: term(). - Raises an exception of class exit with exit reason Reason, - where Reason is any term. As evaluating this function causes an - exception to be raised, it has no return value. This function - should be used when the intent is to stop the current process. - This function differ from erlang:error/1 and erlang:error/2 by - causing an exception of a different class and by having a reason - that does not include the list of functions from the call stack. + Raises an exception of class exit with exit reason Reason. As + evaluating this function causes an exception to be raised, it has + no return value. + + The intent of the exception class exit is that the current + process should be stopped (for example when a message telling a + process to stop is received). + + This function differ from error/1,2,3 by causing an exception of + a different class and by having a reason that does not include the + list of functions from the call stack. See the guide about errors and error handling for additional information. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_2_func.txt index 126f2488787a..b02fdf3ad373 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_2_func.txt @@ -65,3 +65,8 @@ a process sends an exit signal with reason normal to another process. This is arguably strange but this behavior is kept for backward compatibility reasons. + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_signal_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_signal_2_func.txt new file mode 100644 index 000000000000..e952dad6a890 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_exit_signal_2_func.txt @@ -0,0 +1,6 @@ + +  exit_signal/2 + + The documentation for exit_signal/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_external_size_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_external_size_2_func.txt index 1ec8b02b073a..30292e157092 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_external_size_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_external_size_2_func.txt @@ -3,8 +3,11 @@  when  Term :: term(),  Options :: -  [{minor_version, -  Version :: non_neg_integer()}]. +  [compressed | +  {compressed, Level :: 0..9} | +  deterministic | +  {minor_version, Version :: 0..2} | +  local]. Since: OTP R14B04 diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_after_on_load_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_after_on_load_2_func.txt new file mode 100644 index 000000000000..63b677da2390 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_after_on_load_2_func.txt @@ -0,0 +1,6 @@ + +  finish_after_on_load/2 + + The documentation for finish_after_on_load/2 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_loading_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_loading_1_func.txt new file mode 100644 index 000000000000..c22cf49f7de2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_finish_loading_1_func.txt @@ -0,0 +1,6 @@ + +  finish_loading/1 + + The documentation for finish_loading/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_0_type.txt new file mode 100644 index 000000000000..e1df49edf455 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_0_type.txt @@ -0,0 +1,4 @@ + + -type float() :: float(). + + An Erlang float. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_binary_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_binary_2_func.txt index b7a690fee918..2f7a559f77eb 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_binary_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_binary_2_func.txt @@ -6,7 +6,7 @@  Option ::  {decimals, Decimals :: 0..253} |  {scientific, Decimals :: 0..249} | -  compact. +  compact | short. Since: OTP R16B @@ -21,3 +21,9 @@ <<"7.12">> > float_to_binary(7.12, [{scientific, 3}]). <<"7.120e+00">> + > float_to_binary(7.12, [short]). + <<"7.12">> + > float_to_binary(0.1+0.2, [short]). + <<"0.30000000000000004">> + > float_to_binary(0.1+0.2) + <<"3.00000000000000044409e-01">> diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_list_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_list_2_func.txt index bfe4abe53a98..14dbc3763e4c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_list_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_float_to_list_2_func.txt @@ -6,7 +6,7 @@  Option ::  {decimals, Decimals :: 0..253} |  {scientific, Decimals :: 0..249} | -  compact. +  compact | short. Since: OTP R16B @@ -29,6 +29,16 @@ using scientific notation with Decimals digits of precision. + • If option short is specified, the float is formatted with + the smallest number of digits that still guarantees that F + =:= list_to_float(float_to_list(F, [short])). When the + float is inside the range (-2⁵³, 2⁵³), the notation that + yields the smallest number of characters is used (scientific + notation or normal decimal notation). Floats outside the + range (-2⁵³, 2⁵³) are always formatted using scientific + notation to avoid confusing results when doing arithmetic + operations. + • If Options is [], the function behaves as  float_to_list/1. @@ -40,6 +50,10 @@ "7.12" > float_to_list(7.12, [{scientific, 3}]). "7.120e+00" + > float_to_list(7.12, [short]). + "7.12" + > float_to_list(0.1+0.2, [short]). + "0.30000000000000004" > float_to_list(0.1+0.2) "3.00000000000000044409e-01" diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_format_cpu_topology_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_format_cpu_topology_1_func.txt new file mode 100644 index 000000000000..7ef9f0481c6b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_format_cpu_topology_1_func.txt @@ -0,0 +1,6 @@ + +  format_cpu_topology/1 + + The documentation for format_cpu_topology/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_1_func.txt index 36533bd69b58..afb6073b844c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_1_func.txt @@ -78,6 +78,12 @@ is performed for local functions that do not capture the environment). + Change: + In Erlang/OTP 27, we plan to change the return value so + that it always points to the local init process, + regardless of which process or node the fun was originally + created on. See Upcoming Potential Incompatibilities . + {index, Index}: Index (an integer) is an index into the module fun table. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_mfa_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_mfa_1_func.txt new file mode 100644 index 000000000000..26bd5c979a93 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_info_mfa_1_func.txt @@ -0,0 +1,6 @@ + +  fun_info_mfa/1 + + The documentation for fun_info_mfa/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_to_list_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_to_list_1_func.txt index 259eafe909f8..f50ff7ad5de9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_to_list_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_fun_to_list_1_func.txt @@ -30,7 +30,7 @@ environment into account. See erlang:fun_info/1 for how to get the environment of a fun. - Note: + Change: The output of fun_to_list/1 can differ between Erlang implementations and may change in future versions. @@ -59,7 +59,7 @@ {#Fun,#Fun} Explanation: The string representations differ because the funs - come from different fun experssions. + come from different fun expressions. > {fun() -> 1 end, fun() -> 1 end}. > {#Fun,#Fun} diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_0_type.txt new file mode 100644 index 000000000000..0c3d189c7d18 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_0_type.txt @@ -0,0 +1,4 @@ + + -type function() :: fun(). + + An Erlang fun. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_exported_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_exported_3_func.txt index 4ea9703aa4f4..0b7f45f6fb49 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_exported_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_function_exported_3_func.txt @@ -5,11 +5,7 @@  Function :: atom(),  Arity :: arity(). - Returns true if the module Module is loaded and contains an + Returns true if the module Module is current and contains an exported function Function/Arity, or if there is a BIF (a built-in function implemented in C) with the specified name, otherwise returns false. - - Note: - This function used to return false for BIFs before - Erlang/OTP 18.0. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_garbage_collect_message_area_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_garbage_collect_message_area_0_func.txt new file mode 100644 index 000000000000..4ffd915f60ad --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_garbage_collect_message_area_0_func.txt @@ -0,0 +1,6 @@ + +  garbage_collect_message_area/0 + + The documentation for garbage_collect_message_area/0 is hidden. + This probably means that it is internal and not to be used by + other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gather_gc_info_result_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gather_gc_info_result_1_func.txt new file mode 100644 index 000000000000..594193be733d --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gather_gc_info_result_1_func.txt @@ -0,0 +1,6 @@ + +  gather_gc_info_result/1 + + The documentation for gather_gc_info_result/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_0_func.txt index 3714bf35f37a..db71ca98117e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_0_func.txt @@ -2,4 +2,4 @@ -spec erlang:get_cookie() -> Cookie | nocookie when Cookie :: atom(). Returns the magic cookie of the local node if the node is alive, - otherwise the atom nocookie. + otherwise the atom nocookie. This value is set by set_cookie/1. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_1_func.txt new file mode 100644 index 000000000000..b9e041c61df7 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_cookie_1_func.txt @@ -0,0 +1,10 @@ + + -spec erlang:get_cookie(Node) -> Cookie | nocookie +  when Node :: node(), Cookie :: atom(). + +Since: + OTP 24.1 + + Returns the magic cookie for node Node if the local node is + alive, otherwise the atom nocookie. This value is set by  + set_cookie/2. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_1_func.txt new file mode 100644 index 000000000000..15653bba3ef6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_1_func.txt @@ -0,0 +1,6 @@ + +  get_module_info/1 + + The documentation for get_module_info/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_2_func.txt new file mode 100644 index 000000000000..831a63cadb1f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_get_module_info_2_func.txt @@ -0,0 +1,6 @@ + +  get_module_info/2 + + The documentation for get_module_info/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_group_leader_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_group_leader_2_func.txt index 592d6bd6e5d2..0c58ffcfb8fe 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_group_leader_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_group_leader_2_func.txt @@ -10,5 +10,14 @@ supervision tree, because OTP assumes the group leader of their processes is their application master. + Setting the group leader follows the signal ordering guarantees + described in the Processes Chapter in the Erlang Reference + Manual. + See also group_leader/0 and OTP design principles related to starting and stopping applications. + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gt_2_func.txt new file mode 100644 index 000000000000..013f679ceb54 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gt_2_func.txt @@ -0,0 +1,5 @@ + +  '>'/2 + + The documentation for '>'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gteq_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gteq_2_func.txt new file mode 100644 index 000000000000..16f4e2b4e517 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_gteq_2_func.txt @@ -0,0 +1,5 @@ + +  '>='/2 + + The documentation for '>='/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_0_func.txt index 7b39cf8471c0..5fed60591dff 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_0_func.txt @@ -1,7 +1,7 @@ -spec halt() -> no_return(). - The same as halt(0, []). Example: + The same as calling halt(0, []). Example: > halt(). os_prompt% diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_1_func.txt index a6ed42864c66..d503e7f1a6b9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_1_func.txt @@ -1,10 +1,20 @@ - -spec halt(Status) -> no_return() -  when Status :: non_neg_integer() | abort | string(). + -spec halt(Status :: non_neg_integer()) -> no_return(). - The same as halt(Status, []). Example: + The same as calling halt(Status, []). Example: > halt(17). os_prompt% echo $? 17 os_prompt% + + -spec halt(Abort :: abort) -> no_return(). + +Since: + OTP R15B01 + + The same as calling halt(abort, []). + + -spec halt(CrashDumpSlogan :: string()) -> no_return(). + + The same as calling halt(CrashDumpSlogan, []). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_2_func.txt index 7ba5d3ececcd..7eae2e5323d9 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_halt_2_func.txt @@ -1,42 +1,89 @@ - -spec halt(Status, Options) -> no_return() -  when -  Status :: non_neg_integer() | abort | string(), -  Options :: [Option], -  Option :: {flush, boolean()}. + -spec halt(Status :: non_neg_integer(), Options :: halt_options()) -> +  no_return(). Since: OTP R15B01 - Status must be a non-negative integer, a string, or the atom  - abort. Halts the Erlang runtime system. Has no return value. - Depending on Status, the following occurs: - - integer(): - The runtime system exits with integer value Status as status - code to the calling environment (OS). - Note: - On many platforms, the OS supports only status codes - 0-255. A too large status code is truncated by clearing - the high bits. - - string(): - An Erlang crash dump is produced with Status as slogan. Then - the runtime system exits with status code 1. The string will - be truncated if longer than 200 characters. - Note: - Before ERTS 9.1 (OTP-20.1) only code points in the range - 0-255 was accepted in the string. Now any unicode string - is valid. - - abort: - The runtime system aborts producing a core dump, if that is - enabled in the OS. - - For integer Status, the Erlang runtime system closes all ports - and allows async threads to finish their operations before - exiting. To exit without such flushing, use Option as  - {flush,false}. - - For statuses string() and abort, option flush is ignored and - flushing is not done. + Types: + -type halt_options() :: [{flush, boolean()}]. + + Halt the runtime system with status code Status. + + Note: + On many platforms, the OS supports only status codes 0-255. A + too large status code is truncated by clearing the high bits. + + Currently the following options are valid: + + {flush, EnableFlushing}: + If EnableFlushing equals true, which also is the default + behavior, the runtime system will perform the following + operations before terminating: + + • Flush all outstanding output. + + • Send all Erlang ports exit signals and wait for them to + exit. + + • Wait for all async threads to complete all outstanding + async jobs. + + • Call all installed NIF on halt callbacks. + + • Wait for all ongoing NIF calls with the delay halt + setting enabled to return. + + • Call all installed atexit/on_exit callbacks. + + If EnableFlushing equals false, the runtime system will + terminate immediately without performing any of the above + listed operations. + + Change: + Runtime systems prior to OTP 26.0 called all installed  + atexit/on_exit callbacks also when flush was + disabled, but as of OTP 26.0 this is no longer the case. + + -spec halt(Abort :: abort, Options :: halt_options()) -> no_return(). + +Since: + OTP R15B01 + + Types: + -type halt_options() :: [{flush, boolean()}]. + + Halt the Erlang runtime system by aborting and produce a core dump + if core dumping has been enabled in the environment that the + runtime system is executing in. + + Note: + The {flush, boolean()} option will be ignored, and flushing + will be disabled. + + -spec halt(CrashDumpSlogan :: string(), Options :: halt_options()) -> +  no_return(). + +Since: + OTP R15B01 + + Types: + -type halt_options() :: [{flush, boolean()}]. + + Halt the Erlang runtime system and generate an Erlang crash dump. + The string CrashDumpSlogan will be used as slogan in the Erlang + crash dump created. The slogan will be trunkated if  + CrashDumpSlogan is longer than 1023 characters. + + Note: + The {flush, boolean()} option will be ignored, and flushing + will be disabled. + + Behavior changes compared to earlier versions: + + • Before OTP 24.2, the slogan was truncated if  + CrashDumpSlogan was longer than 200 characters. Now it will + be truncated if longer than 1023 characters. + + • Before OTP 20.1, only code points in the range 0-255 were + accepted in the slogan. Now any Unicode string is valid. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_has_prepared_code_on_load_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_has_prepared_code_on_load_1_func.txt new file mode 100644 index 000000000000..c012053e6daa --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_has_prepared_code_on_load_1_func.txt @@ -0,0 +1,6 @@ + +  has_prepared_code_on_load/1 + + The documentation for has_prepared_code_on_load/1 is hidden. + This probably means that it is internal and not to be used by + other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hd_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hd_1_func.txt index a653367801f9..cae15018876e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hd_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hd_1_func.txt @@ -1,12 +1,19 @@ - -spec hd(List) -> term() when List :: [term(), ...]. + -spec hd(List) -> Head +  when List :: nonempty_maybe_improper_list(), Head :: term(). - Returns the head of List, that is, the first element, for - example: + Returns the head of List, that is, the first element. + + It works with improper lists. + + Examples: > hd([1,2,3,4,5]). 1 + > hd([first, second, third, so_on | improper_end]). + first + Allowed in guard tests. - Failure: badarg if List is the empty list []. + Failure: badarg if List is an empty list []. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hibernate_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hibernate_3_func.txt index bc61de77bd2d..92b9b0302bcf 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hibernate_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_hibernate_3_func.txt @@ -13,7 +13,8 @@ resumes in Module:Function with the arguments specified by Args with the call stack emptied, meaning that the process terminates when that function returns. Thus erlang:hibernate/3 never - returns to its caller. + returns to its caller. The resume function Module:Function/Arity + must be exported (Arity =:= length(Args)). If the process has any message in its message queue, the process is awakened immediately in the same way as described earlier. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_identifier_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_identifier_0_type.txt new file mode 100644 index 000000000000..f7f5ac68767a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_identifier_0_type.txt @@ -0,0 +1,5 @@ + + -type identifier() :: pid() | port() | reference(). + + An unique identifier for some entity, for example a process, + port or monitor. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_integer_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_integer_0_type.txt new file mode 100644 index 000000000000..2b9b3bab4a71 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_integer_0_type.txt @@ -0,0 +1,4 @@ + + -type integer() :: integer(). + + An Erlang integer. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iodata_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iodata_0_type.txt new file mode 100644 index 000000000000..ba46c3331ddf --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iodata_0_type.txt @@ -0,0 +1,11 @@ + + -type iodata() :: iolist() | binary(). + + A binary or list containing bytes and/or iodata. This datatype is + used to represent data that is meant to be output using any I/O + module. For example: file:write/2 or gen_tcp:send/2. + + To convert an iodata() term to binary() you can use + iolist_to_binary/2. To transcode a string() or + unicode:chardata() to iodata() you can use + unicode:characters_to_binary/1. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_0_type.txt new file mode 100644 index 000000000000..aa17b96ab85e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_0_type.txt @@ -0,0 +1,10 @@ + + -type iolist() :: +  maybe_improper_list(byte() | binary() | iolist(), +  binary() | []). + + A list containing bytes and/or iodata. This datatype is used to + represent data that is meant to be output using any I/O module. + For example: file:write/2 or gen_tcp:send/2. + + In most use cases you want to use iodata() instead of this type. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_to_iovec_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_to_iovec_1_func.txt index e362ef610a36..83cb5ad81cfa 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_to_iovec_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_iolist_to_iovec_1_func.txt @@ -8,4 +8,27 @@ OTP 20.1 Returns an iovec that is made from the integers and binaries in  - IoListOrBinary. + IoListOrBinary. This function is useful when you want to flatten + an iolist but you do not need a single binary. This can be useful + for passing the data to nif functions such as enif_inspect_iovec + or do more efficient message passing. The advantage of using this + function over iolist_to_binary/1 is that it does not have to + copy off-heap binaries. Example: + + > Bin1 = <<1,2,3>>. + <<1,2,3>> + > Bin2 = <<4,5>>. + <<4,5>> + > Bin3 = <<6>>. + <<6>> + %% If you pass small binaries and integers it works as iolist_to_binary + > erlang:iolist_to_iovec([Bin1,1,[2,3,Bin2],4|Bin3]). + [<<1,2,3,1,2,3,4,5,4,6>>] + %% If you pass larger binaries, they are split and returned in a form + %% optimized for calling the C function writev. + > erlang:iolist_to_iovec([<<1>>,<<2:8096>>,<<3:8096>>]). + [<<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,...>>, + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + ...>>, + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...>>] diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_alive_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_alive_0_func.txt index da183ed5767d..3b6efe0c9150 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_alive_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_alive_0_func.txt @@ -10,5 +10,5 @@ • "erl -sname SHORTNAME". A node can also be alive if it has got a name from a call to  - net_kernel:start/1 and has not been stopped by a call to  + net_kernel:start/2 and has not been stopped by a call to  net_kernel:stop/0. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_process_alive_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_process_alive_1_func.txt index 919d6b4f68bc..e8a9970a4d32 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_process_alive_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_is_process_alive_1_func.txt @@ -19,6 +19,5 @@ is_process_alive(P2Pid), % P2 is not alive (the call above always return false) - See the documentation about communication in Erlang and - erlang:exit/2 for more information about signals and exit - singnals. + See the documentation about signals and erlang:exit/2 for more + information about signals and exit signals. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_link_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_link_1_func.txt index 6286448237b1..3210677f6075 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_link_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_link_1_func.txt @@ -1,25 +1,56 @@ -spec link(PidOrPort) -> true when PidOrPort :: pid() | port(). - Creates a link between the calling process and another process (or - port) PidOrPort. If the link already exists or a process - attempts to create a link to itself, nothing is done. Returns  - true if the link is set up. + Sets up and activates a link between the calling process and + another process or a port identified by PidOrPort. We will from + here on call the identified process or port linkee. If the linkee + is a port, it must reside on the same node as the caller. - If PidOrPort does not exist and checking it is cheap, a noproc - error is raised. Currently, checking is cheap if the PidOrPort - is local and the caller does not trap exits (see process_flag/2  - ). + If one of the participants of a link terminates, it will send an + exit signal to the other participant. The exit signal will + contain the exit reason of the terminated participant. Other + cases when exit signals are triggered due to a link are when no + linkee exist (noproc exit reason) and when the connection + between linked processes on different nodes is lost or cannot be + established (noconnection exit reason). - Apart from any exit signals from the linked process itself, two - special exit signals may be sent to the calling process: + An existing link can be removed by calling unlink/1. For more + information on links and exit signals due to links, see the + Processes chapter in the Erlang Reference Manual: - • noproc is sent immediately if PidOrPort does not exist at - the time of linking (if the caller is trapping exits or  - PidOrPort is remote). + • Links - • noconnection if PidOrPort is remote and a connection - between the nodes could not be established or was severed. + • Sending Exit Signals - See Processes ➜ Links in the Erlang Reference Manual for more - details. + • Receiving Exit Signals + + For historical reasons, link/1 has a strange semi-synchronous + behavior when it is "cheap" to check if the linkee exists or not, + and the caller does not trap exits. If the above is true and the + linkee does not exist, link/1 will raise a noproc error + exception. The expected behavior would instead have been that  + link/1 returned true, and the caller later was sent an exit + signal with noproc exit reason, but this is unfortunately not + the case. The noproc exception is not to be confused with an + exit signal with exit reason noproc. Currently it is "cheap" to + check if the linkee exists when it is supposed to reside on the + same node as the calling process. + + The link setup and activation is performed asynchronously. If the + link already exists, or if the caller attempts to create a link to + itself, nothing is done. A detailed description of the link + protocol can be found in the Distribution Protocol chapter of + the ERTS User's Guide. + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + + Failure: + + • badarg if PidOrPort does not identify a process or a node + local port. + + • noproc linkee does not exist and it is "cheap" to check if + it exists as described above. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_0_type.txt new file mode 100644 index 000000000000..54807c427c5f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_0_type.txt @@ -0,0 +1,4 @@ + + -type list() :: [any()]. + + An Erlang list containing terms of any type. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_1_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_1_type.txt new file mode 100644 index 000000000000..3fdedd543bc9 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_1_type.txt @@ -0,0 +1,4 @@ + + -type list(ContentType) :: [ContentType]. + + An Erlang list containing terms of the type ContentType. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_atom_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_atom_1_func.txt index 30a6bb2b2aad..c77d5233d46c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_atom_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_atom_1_func.txt @@ -5,10 +5,7 @@ As from Erlang/OTP 20, String may contain any Unicode character. Earlier versions allowed only ISO-latin-1 characters as the - implementation did not allow Unicode characters above 255. For - more information on Unicode support in atoms, see note on UTF-8 - encoded atoms in section "External Term Format" in the User's - Guide. + implementation did not allow Unicode characters above 255. Note: The number of characters that are permitted in an atom name is diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_existing_atom_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_existing_atom_1_func.txt index d89f63af15c9..315d160be9be 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_existing_atom_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_list_to_existing_atom_1_func.txt @@ -2,7 +2,9 @@ -spec list_to_existing_atom(String) -> atom() when String :: string(). Returns the atom whose text representation is String, but only - if there already exists such atom. + if there already exists such atom. An atom exists if it has been + created by the run-time system by either loading code or creating + a term in which the atom is part. Failure: badarg if there does not already exist an atom whose text representation is String. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_module_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_module_2_func.txt index 6b3d2b5a1fb0..bc192d5502eb 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_module_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_module_2_func.txt @@ -3,7 +3,9 @@  when  Module :: module(),  Binary :: binary(), -  Reason :: badfile | not_purged | on_load. +  Reason :: +  badfile | not_purged | on_load | +  {features_not_allowed, [atom()]}. If Binary contains the object code for module Module, this BIF loads that object code. If the code for module Module already @@ -23,6 +25,16 @@ Binary contains a module that cannot be loaded because old code for this module already exists. + on_load: + The code in Binary contains an on_load declaration that + must be executed before Binary can become the current code. + Any previous current code for Module will remain until the  + on_load call has finished. + + not_allowed: + The code in Binary has been compiled with features that are + currently not enabled in the runtime system. + Warning: This BIF is intended for the code server (see code(3)) and is not to be used elsewhere. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_nif_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_nif_2_func.txt index 1b98c6c1784e..50b8bf45d14b 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_nif_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_load_nif_2_func.txt @@ -45,3 +45,11 @@ old_code: The call to load_nif/2 was made from the old code of a module that has been upgraded; this is not allowed. + + If the -nifs() attribute is used (which is recommended), all + NIFs in the dynamic library much be declared as such for  + load_nif/2 to succeed. On the other hand, all functions declared + with the -nifs() attribute do not have to be implemented by the + dynamic library. This allows a target independent Erlang file to + contain fallback implementations for functions that may lack NIF + support depending on target OS/hardware platform. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_lt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_lt_2_func.txt new file mode 100644 index 000000000000..64323d56c231 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_lt_2_func.txt @@ -0,0 +1,5 @@ + +  '<'/2 + + The documentation for '<'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_fun_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_fun_3_func.txt new file mode 100644 index 000000000000..b88f7a06ac99 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_fun_3_func.txt @@ -0,0 +1,5 @@ + +  make_fun/3 + + The documentation for make_fun/3 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_ref_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_ref_0_func.txt index b282e3b375e7..64f347e9c377 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_ref_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_make_ref_0_func.txt @@ -5,7 +5,7 @@ connected nodes. Warning: - Known issue: When a node is restarted multiple times with the + Before OTP-23 when a node is restarted multiple times with the same node name, references created on a newer node can be mistaken for a reference created on an older node with the same node name. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_map_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_map_0_type.txt new file mode 100644 index 000000000000..33cd36bd086e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_map_0_type.txt @@ -0,0 +1,5 @@ + + -type map() :: #{any() => any()}. + + An Erlang map containing any number of key and value + associations. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_2_func.txt index e0a94dec4717..0dbd5d01f09e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_2_func.txt @@ -21,3 +21,8 @@ > max("abc", "b"). "b" + + Allowed in guard tests. + + Change: + Allowed in guards tests from Erlang/OTP 26. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_heap_size_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_heap_size_0_type.txt index f928dc17633c..8fc66541fdd8 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_heap_size_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_max_heap_size_0_type.txt @@ -4,7 +4,8 @@  non_neg_integer() |  #{size => non_neg_integer(),  kill => boolean(), -  error_logger => boolean()}. +  error_logger => boolean(), +  include_shared_binaries => boolean()}. Process max heap size configuration. For more info see  process_flag(max_heap_size, MaxHeapSize) diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_0_type.txt new file mode 100644 index 000000000000..f432632fd965 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_0_type.txt @@ -0,0 +1,5 @@ + + -type maybe_improper_list() :: maybe_improper_list(any(), any()). + + An Erlang list that is not guaranteed to end with a [], and + where the list elements can be of any type. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_2_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_2_type.txt new file mode 100644 index 000000000000..b7aaf7bc2c06 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_maybe_improper_list_2_type.txt @@ -0,0 +1,6 @@ + + -type maybe_improper_list(ContentType, TerminationType) :: +  maybe_improper_list(ContentType, TerminationType). + + An Erlang list, that is not guaranteed to end with a [], and + where the list elements are of the type ContentType. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_0_func.txt index e440dfd550b2..d9fcd3099bfd 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_0_func.txt @@ -59,13 +59,6 @@ This memory is part of the memory presented as system memory. - low: - Only on 64-bit halfword emulator. The total amount of memory - allocated in low memory areas that are restricted to < 4 GB, - although the system can have more memory. - - Can be removed in a future release of the halfword emulator. - maximum: The maximum total amount of memory allocated since the emulator was started. This tuple is only present when the @@ -118,7 +111,7 @@ dynamically allocated memory blocks can be much larger than the total size of the dynamically allocated memory blocks. - Note: + Change: As from ERTS 5.6.4, erlang:memory/0 requires that all  erts_alloc(3) allocators are enabled (default behavior). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_1_func.txt index b62ac1f4a1f4..537d838a8288 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_memory_1_func.txt @@ -13,7 +13,7 @@ memory_type() atoms, in which case a corresponding list of  {memory_type(), Size :: integer >= 0} tuples is returned. - Note: + Change: As from ERTS 5.6.4, erlang:memory/1 requires that all  erts_alloc(3) allocators are enabled (default behavior). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_message_queue_data_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_message_queue_data_0_type.txt index c4789ef677ff..5799c41b4d1a 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_message_queue_data_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_message_queue_data_0_type.txt @@ -5,5 +5,5 @@ -type message_queue_data() :: off_heap | on_heap. - Process message queue data configuration. For more info see  - process_flag(message_queue_data, MQD) + Process message queue data configuration. For more information, + see process_flag(message_queue_data, MQD) diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_mfa_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_mfa_0_type.txt new file mode 100644 index 000000000000..acc57bebf0e6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_mfa_0_type.txt @@ -0,0 +1,5 @@ + + -type mfa() :: {module(), atom(), arity()}. + + A three-tuple representing a Module:Function/Arity function + signature. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_min_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_min_2_func.txt index aa936913213d..906f783f2984 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_min_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_min_2_func.txt @@ -21,3 +21,8 @@ > min("abc", "b"). "abc" + + Allowed in guard tests. + + Change: + Allowed in guards tests from Erlang/OTP 26. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_0_type.txt new file mode 100644 index 000000000000..f7274e1ffc0e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_0_type.txt @@ -0,0 +1,4 @@ + + -type module() :: atom(). + + An Erlang module represented by an atom. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_loaded_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_loaded_1_func.txt index c2907f5d2949..72721b620388 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_loaded_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_module_loaded_1_func.txt @@ -1,9 +1,5 @@ -spec module_loaded(Module) -> boolean() when Module :: module(). - Returns true if the module Module is loaded, otherwise false. - It does not attempt to load the module. - - Warning: - This BIF is intended for the code server (see code(3)) and - is not to be used elsewhere. + Returns true if the module Module is loaded as current code; + otherwise, false. It does not attempt to load the module. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_2_func.txt index c88c266702d2..6837141c8802 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_2_func.txt @@ -54,8 +54,8 @@ Object: The monitored entity, which triggered the event. When - monitoring a local process or port, Object will be equal to - the pid() or port() that was being monitored. When + monitoring a process or a local port, Object will be equal + to the pid() or port() that was being monitored. When monitoring process or port by name, Object will have format  {RegisteredName, Node} where RegisteredName is the name which has been used with monitor/2 call and Node is local @@ -74,7 +74,7 @@ remote), an atom RegisteredName or a tuple {RegisteredName, Node} for a registered process, located elsewhere. - Note: + Change: Before ERTS 10.0 (OTP 21.0), monitoring a process could fail with badarg if the monitored process resided on a primitive node (such as erl_interface or jinterface), @@ -151,3 +151,8 @@ If or when monitor/2 is extended, other possible values for  Tag, Object, and Info in the monitor message will be introduced. + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_3_func.txt index 35cab15b0def..d2568b9d0136 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_3_func.txt @@ -10,7 +10,7 @@  when MonitorRef :: reference(). Since: - OTP @OTP-16718@ + OTP 24.0 Types: -type monitor_port_identifier() :: port() | registered_name(). @@ -59,8 +59,86 @@ removed using the unalias/1 BIF, the monitor will still be left active. + Example: + + server() -> + receive + {request, AliasReqId, Request} -> + Result = perform_request(Request), + AliasReqId ! {reply, AliasReqId, Result} + end, + server(). + + client(ServerPid, Request) -> + AliasMonReqId = monitor(process, ServerPid, [{alias, reply_demonitor}]), + ServerPid ! {request, AliasMonReqId, Request}, + %% Alias as well as monitor will be automatically deactivated if we + %% receive a reply or a 'DOWN' message since we used 'reply_demonitor' + %% as unalias option... + receive + {reply, AliasMonReqId, Result} -> + Result; + {'DOWN', AliasMonReqId, process, ServerPid, ExitReason} -> + error(ExitReason) + end. + + + Note that both the server and the client in this example must + be executing on at least OTP 24 systems in order for this to + work. + + For more information on process aliases see the Process + Aliases section of the Erlang Reference Manual. + {tag, UserDefinedTag}: Replace the default Tag with UserDefinedTag in the monitor message delivered when the monitor is triggered. For example, when monitoring a process, the 'DOWN' tag in the down message will be replaced by UserDefinedTag. + + An example of how the {tag, UserDefinedTag} option can be + used in order to enable the new selective receive + optimization, introduced in OTP 24, when making multiple + requests to different servers: + + server() -> + receive + {request, From, ReqId, Request} -> + Result = perform_request(Request), + From ! {reply, self(), ReqId, Result} + end, + server(). + + client(ServerPids, Request) when is_list(ServerPids) -> + ReqId = make_ref(), + lists:foreach(fun (ServerPid) -> + _ = monitor(process, ServerPid, + [{tag, {'DOWN', ReqId}}]), + ServerPid ! {request, self(), ReqId, Request} + end, + ServerPids), + receive_replies(ReqId, length(ServerPids), []). + + receive_replies(_ReqId, 0, Acc) -> + Acc; + receive_replies(ReqId, N, Acc) -> + %% The compiler will detect that we match on the 'ReqId' + %% reference in all clauses, and will enable the selective + %% receive optimization which makes the receive able to + %% skip past all messages present in the message queue at + %% the time when the 'ReqId' reference was created... + Res = receive + {reply, ServerPid, ReqId, Result} -> + %% Here we typically would have deactivated the + %% monitor by a call to demonitor(Mon, [flush]) but + %% we ignore this in this example for simplicity... + {ok, ServerPid, Result}; + {{'DOWN', ReqId}, _Mon, process, ServerPid, ExitReason} -> + {error, ServerPid, ExitReason} + end, + receive_replies(ReqId, N-1, [Res | Acc]). + + + In order for this example to work as intended, the client must + be executing on at least an OTP 24 system, but the servers may + execute on older systems. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_node_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_node_2_func.txt index c137ca38fd13..89561c41adaf 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_node_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_monitor_node_2_func.txt @@ -17,6 +17,12 @@ to Node, an attempt is made to create one. If this fails, a  nodedown message is delivered. + The delivery of the nodedown signal is not ordered with respect + to other link or monitor signals from the node that goes down. If + you need a guarantee that all signals from the remote node has + been delivered before the nodedown signal is sent, you should + use net_kernel:monitor_nodes/1. + Nodes connected through hidden connections can be monitored as any other nodes. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_neg_integer_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_neg_integer_0_type.txt new file mode 100644 index 000000000000..bce7a55517bd --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_neg_integer_0_type.txt @@ -0,0 +1,4 @@ + + -type neg_integer() :: neg_integer(). + + A negative integer. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nif_resource_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nif_resource_0_type.txt index 7cc1f2598b0e..6c2cf4ced7c5 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nif_resource_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nif_resource_0_type.txt @@ -1,4 +1,4 @@ -opaque nif_resource()  - An opaque handle identifing a NIF resource object . + An opaque handle identifying a NIF resource object . diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nil_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nil_0_type.txt new file mode 100644 index 000000000000..3f20bcd23d61 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nil_0_type.txt @@ -0,0 +1,4 @@ + + -type nil() :: []. + + The empty list(). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_no_return_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_no_return_0_type.txt new file mode 100644 index 000000000000..660047e34553 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_no_return_0_type.txt @@ -0,0 +1,5 @@ + + -type no_return() :: none(). + + The type used to show that a function will never return a value, + that is it will always throw an exception. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_node_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_node_0_type.txt new file mode 100644 index 000000000000..b6d6364aca9f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_node_0_type.txt @@ -0,0 +1,4 @@ + + -type node() :: atom(). + + An Erlang node represented by an atom. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nodes_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nodes_2_func.txt new file mode 100644 index 000000000000..fb55ad6686d1 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nodes_2_func.txt @@ -0,0 +1,81 @@ + + -spec nodes(Arg, InfoOpts) -> [NodeInfo] +  when +  NodeType :: +  visible | hidden | connected | this | known, +  Arg :: NodeType | [NodeType], +  InfoOpts :: +  #{connection_id => boolean(), +  node_type => boolean()}, +  NodeTypeInfo :: visible | hidden | this | known, +  ConnectionId :: undefined | integer(), +  Info :: +  #{connection_id => ConnectionId, +  node_type => NodeTypeInfo}, +  NodeInfo :: {node(), Info}. + +Since: + OTP 25.1 + + Returns a list of NodeInfo tuples. The first element is the node + name. Nodes to be included in the list are determined by the first + argument Arg in the same way as for nodes(Arg). The second + element of NodeInfo tuples is a map containing further + information about the node identified by the first element. The + information present in this map is determined by the InfoOpts + map passed as the second argument. Currently the following + associations are allowed in the InfoOpts map: + + connection_id => boolean(): + If the value of the association equals true, the Info map + in the returned result will contain the key connection_id + associated with the value ConnectionId. If ConnectionId + equals undefined, the node is not connected to the node + which the caller is executing on, or is the node which the + caller is executing on. If ConnectionId is an integer, the + node is currently connected to the node which the caller is + executing on. + + The integer connection identifier value together with a node + name identifies a specific connection instance to the node + with that node name. The connection identifier value is node + local. That is, on the other node the connection identifier + will not be the same value. If a connection is taken down + and then taken up again, the connection identifier value will + change for the connection to that node. The amount of values + for connection identifiers are limited, so it is possible to + see the same value for different instances, but quite + unlikely. It is undefined how the value change between two + consecutive connection instances. + + node_type => boolean(): + If the value of the association equals true, the Info map + in the returned result will contain the key node_type + associated with the value NodeTypeInfo. Currently the + following node types exist: + + visible: + The node is connected to the node of the calling process + through an ordinary visible connection. That is, the node + name would appear in the result returned by nodes/0. + + hidden: + The node is connected to the node of the calling process + through a hidden connection. That is, the node name would + not appear in the result returned by nodes/0. + + this: + This is the node of the calling process. + + known: + The node is not connected but known to the node of the + calling process. + + Example: + + (a@localhost)1> nodes([this, connected], #{connection_id=>true, node_type=>true}). + [{c@localhost,#{connection_id => 13892108,node_type => hidden}}, + {b@localhost,#{connection_id => 3067553,node_type => visible}}, + {a@localhost,#{connection_id => undefined,node_type => this}}] + (a@localhost)2> + diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_non_neg_integer_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_non_neg_integer_0_type.txt new file mode 100644 index 000000000000..f07d7a4ee5f5 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_non_neg_integer_0_type.txt @@ -0,0 +1,4 @@ + + -type non_neg_integer() :: non_neg_integer(). + + A non-negative integer, that is any positive integer or 0. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_none_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_none_0_type.txt new file mode 100644 index 000000000000..bcefabd3551f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_none_0_type.txt @@ -0,0 +1,6 @@ + + -type none() :: none(). + + This type is used to show that a function will never return a + value; that is it will always throw an exception. In a spec, use  + no_return() for the sake of clarity. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_binary_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_binary_0_type.txt new file mode 100644 index 000000000000..9df59ae11ada --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_binary_0_type.txt @@ -0,0 +1,4 @@ + + -type nonempty_binary() :: <<_:8, _:_*8>>. + + A binary() that contains some data. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_bitstring_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_bitstring_0_type.txt new file mode 100644 index 000000000000..e25e9fda6b0e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_bitstring_0_type.txt @@ -0,0 +1,4 @@ + + -type nonempty_bitstring() :: <<_:1, _:_*1>>. + + A bitstring() that contains some data. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_improper_list_2_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_improper_list_2_type.txt new file mode 100644 index 000000000000..6c6cef0861d6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_improper_list_2_type.txt @@ -0,0 +1,5 @@ + + -type nonempty_improper_list(ContentType, TerminationType) :: +  nonempty_improper_list(ContentType, TerminationType). + + A maybe_improper_list/2 that contains some items. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_0_type.txt new file mode 100644 index 000000000000..266d82dc9bec --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_0_type.txt @@ -0,0 +1,4 @@ + + -type nonempty_list() :: [any(), ...]. + + A list() that contains some items. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_1_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_1_type.txt new file mode 100644 index 000000000000..418464808912 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_list_1_type.txt @@ -0,0 +1,4 @@ + + -type nonempty_list(ContentType) :: [ContentType, ...]. + + A list(ContentType) that contains some items. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_0_type.txt new file mode 100644 index 000000000000..ea43e2683a0f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_0_type.txt @@ -0,0 +1,5 @@ + + -type nonempty_maybe_improper_list() :: +  nonempty_maybe_improper_list(any(), any()). + + A maybe_improper_list() that contains some items. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_2_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_2_type.txt new file mode 100644 index 000000000000..49d5acbb14c0 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_maybe_improper_list_2_type.txt @@ -0,0 +1,6 @@ + + -type nonempty_maybe_improper_list(ContentType, TerminationType) :: +  nonempty_maybe_improper_list(ContentType, TerminationType). + + A maybe_improper_list(ContentType, TerminationType) that + contains some items. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_string_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_string_0_type.txt new file mode 100644 index 000000000000..05e01446b33d --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_nonempty_string_0_type.txt @@ -0,0 +1,4 @@ + + -type nonempty_string() :: [char(), ...]. + + A string() that contains some characters. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_not_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_not_1_func.txt new file mode 100644 index 000000000000..bc2eb813050a --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_not_1_func.txt @@ -0,0 +1,5 @@ + +  'not'/1 + + The documentation for 'not'/1 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_number_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_number_0_type.txt new file mode 100644 index 000000000000..ead7a9e2ddad --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_number_0_type.txt @@ -0,0 +1,4 @@ + + -type number() :: integer() | float(). + + An Erlang number. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_open_port_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_open_port_2_func.txt index 06de9057862f..27e1b9f204d5 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_open_port_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_open_port_2_func.txt @@ -36,7 +36,7 @@ Returns a port identifier as the result of opening a new Erlang port. A port can be seen as an external Erlang process. - The name of the executable as well as the arguments specifed in  + The name of the executable as well as the arguments specified in  cd, env, args, and arg0 are subject to Unicode filename translation if the system is running in Unicode filename mode. To avoid translation or to force, for example UTF-8, supply the @@ -154,7 +154,7 @@ the name of an environment variable, and Val is the value it is to have in the spawned port process. Both Name and Val must be strings. The one exception is Val being the atom  - false (in analogy with os:getenv/1, which removes the + false (in analogy with os:getenv/1), which removes the environment variable. For information about encoding requirements, see documentation diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_or_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_or_2_func.txt new file mode 100644 index 000000000000..5d8fcc2497bf --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_or_2_func.txt @@ -0,0 +1,5 @@ + +  'or'/2 + + The documentation for 'or'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pid_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pid_0_type.txt new file mode 100644 index 000000000000..0a2d75b25986 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pid_0_type.txt @@ -0,0 +1,4 @@ + + -type pid() :: pid(). + + An Erlang process identifier. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_0_type.txt new file mode 100644 index 000000000000..5484e96380e2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_0_type.txt @@ -0,0 +1,4 @@ + + -type port() :: port(). + + An Erlang port identifier. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_call_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_call_2_func.txt new file mode 100644 index 000000000000..bb00bda40fec --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_call_2_func.txt @@ -0,0 +1,5 @@ + +  port_call/2 + + The documentation for port_call/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_command_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_command_3_func.txt index 0387c7e68018..21f4a6e49334 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_command_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_command_3_func.txt @@ -28,7 +28,7 @@ The calling process is not suspended if the port is busy, instead the port command is aborted and false is returned. - Note: + Change: More options can be added in a future release. Failures: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_get_data_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_get_data_1_func.txt new file mode 100644 index 000000000000..090db5838be0 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_get_data_1_func.txt @@ -0,0 +1,6 @@ + +  port_get_data/1 + + The documentation for port_get_data/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_info_2_func.txt index af2f9e10fe53..12f396fb46df 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_info_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_info_2_func.txt @@ -1,44 +1,62 @@ - -spec erlang:port_info(Port, memory) -> {memory, Bytes} | undefined -  when -  Port :: port() | atom(), -  Bytes :: non_neg_integer(). + -spec erlang:port_info(Port, connected) -> {connected, Pid} | undefined +  when Port :: port() | atom(), Pid :: pid(). -Since: - OTP R16B + Pid is the process identifier of the process connected to the + port. - -spec erlang:port_info(Port, parallelism) -> -  {parallelism, Boolean} | undefined -  when -  Port :: port() | atom(), -  Boolean :: boolean(). + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. -Since: - OTP R16B + Failure: badarg if Port is not a local port identifier, or an + atom. - -spec erlang:port_info(Port, queue_size) -> -  {queue_size, Bytes} | undefined + -spec erlang:port_info(Port, id) -> {id, Index} | undefined  when  Port :: port() | atom(), -  Bytes :: non_neg_integer(). +  Index :: non_neg_integer(). -Since: - OTP R16B + Index is the internal index of the port. This index can be used + to separate ports. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. -spec erlang:port_info(Port, input) -> {input, Bytes} | undefined  when  Port :: port() | atom(),  Bytes :: non_neg_integer(). - -spec erlang:port_info(Port, output) -> {output, Bytes} | undefined -  when -  Port :: port() | atom(), -  Bytes :: non_neg_integer(). + Bytes is the total number of bytes read from the port. - -spec erlang:port_info(Port, id) -> {id, Index} | undefined -  when -  Port :: port() | atom(), -  Index :: non_neg_integer(). + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, links) -> {links, Pids} | undefined +  when Port :: port() | atom(), Pids :: [pid()]. + + Pids is a list of the process identifiers of the processes that + the port is linked to. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. -spec erlang:port_info(Port, locking) -> {locking, Locking} | undefined  when @@ -49,6 +67,43 @@ Since: OTP R16B + Locking is one of the following: + + • port_level (port-specific locking) + + • driver_level (driver-specific locking) + + Notice that these results are highly implementation-specific and + can change in a future release. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, memory) -> {memory, Bytes} | undefined +  when +  Port :: port() | atom(), +  Bytes :: non_neg_integer(). + +Since: + OTP R16B + + Bytes is the total number of bytes allocated for this port by the + runtime system. The port itself can have allocated memory that is + not included in Bytes. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + -spec erlang:port_info(Port, monitors) ->  {monitors, Monitors} | undefined  when @@ -58,9 +113,48 @@ Since: OTP R16B + Monitors represent processes monitored by this port. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, monitored_by) -> +  {monitored_by, MonitoredBy} | undefined +  when +  Port :: port() | atom(), +  MonitoredBy :: [pid()]. + +Since: + OTP 19.0 + + Returns list of pids that are monitoring given port at the moment. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + -spec erlang:port_info(Port, name) -> {name, Name} | undefined  when Port :: port() | atom(), Name :: string(). + Name is the command name set by open_port/2. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + -spec erlang:port_info(Port, os_pid) -> {os_pid, OsPid} | undefined  when  Port :: port() | atom(), @@ -69,29 +163,78 @@ Since: OTP R16B - -spec erlang:port_info(Port, connected) -> {connected, Pid} | undefined -  when Port :: port() | atom(), Pid :: pid(). + OsPid is the process identifier (or equivalent) of an OS process + created with open_port({spawn | spawn_executable, Command}, + Options). If the port is not the result of spawning an OS + process, the value is undefined. - -spec erlang:port_info(Port, links) -> {links, Pids} | undefined -  when Port :: port() | atom(), Pids :: [pid()]. + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. - -spec erlang:port_info(Port, registered_name) -> -  {registered_name, RegisteredName} | -  [] | undefined + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, output) -> {output, Bytes} | undefined  when  Port :: port() | atom(), -  RegisteredName :: atom(). +  Bytes :: non_neg_integer(). - -spec erlang:port_info(Port, monitored_by) -> -  {monitored_by, MonitoredBy} | undefined + Bytes is the total number of bytes written to the port from + Erlang processes using port_command/2, port_command/3, or  + Port ! {Owner, {command, Data}. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, parallelism) -> +  {parallelism, Boolean} | undefined  when  Port :: port() | atom(), -  MonitoredBy :: [pid()]. +  Boolean :: boolean(). Since: - OTP 19.0 + OTP R16B - Returns list of pids that are monitoring given port at the moment. + Boolean corresponds to the port parallelism hint used by this + port. For more information, see option parallelism of  + open_port/2. + + -spec erlang:port_info(Port, queue_size) -> +  {queue_size, Bytes} | undefined +  when +  Port :: port() | atom(), +  Bytes :: non_neg_integer(). + +Since: + OTP R16B + + Bytes is the total number of bytes queued by the port using the + ERTS driver queue implementation. + + If the port identified by Port is not open, undefined is + returned. If the port is closed and the calling process was + previously linked to the port, the exit signal from the port is + guaranteed to be delivered before port_info/2 returns undefined. + + Failure: badarg if Port is not a local port identifier, or an + atom. + + -spec erlang:port_info(Port, registered_name) -> +  {registered_name, RegisteredName} | +  [] | undefined +  when +  Port :: port() | atom(), +  RegisteredName :: atom(). + + RegisteredName is the registered name of the port. If the port + has no registered name, [] is returned. If the port identified by Port is not open, undefined is returned. If the port is closed and the calling process was diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_set_data_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_set_data_2_func.txt new file mode 100644 index 000000000000..d27a36b7e899 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_port_set_data_2_func.txt @@ -0,0 +1,6 @@ + +  port_set_data/2 + + The documentation for port_set_data/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pos_integer_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pos_integer_0_type.txt new file mode 100644 index 000000000000..a8cfd39cc8a6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pos_integer_0_type.txt @@ -0,0 +1,4 @@ + + -type pos_integer() :: pos_integer(). + + An integer greater than zero. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_posixtime_to_universaltime_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_posixtime_to_universaltime_1_func.txt new file mode 100644 index 000000000000..6f39b81c4392 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_posixtime_to_universaltime_1_func.txt @@ -0,0 +1,6 @@ + +  posixtime_to_universaltime/1 + + The documentation for posixtime_to_universaltime/1 is hidden. + This probably means that it is internal and not to be used by + other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pre_loaded_0_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pre_loaded_0_func.txt index 795a78ef0ec1..efaf2aaba9dd 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pre_loaded_0_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_pre_loaded_0_func.txt @@ -1,7 +1,7 @@ -spec pre_loaded() -> [module()]. - Returns a list of Erlang modules that are preloaded in the system. - As all loading of code is done through the file system, the file - system must have been loaded previously. Hence, at least the - module init must be preloaded. + Returns a list of Erlang modules that are preloaded in the + run-time system. Pre-loaded modules are Erlang modules that are + needed to bootstrap the system to load the first Erlang modules + from either disk or by using erl_boot_server. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_prepare_loading_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_prepare_loading_2_func.txt new file mode 100644 index 000000000000..4b551a5b919c --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_prepare_loading_2_func.txt @@ -0,0 +1,6 @@ + +  prepare_loading/2 + + The documentation for prepare_loading/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_flag_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_flag_2_func.txt index dac53ad065ba..5019146c4498 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_flag_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_flag_2_func.txt @@ -1,29 +1,109 @@ - -spec process_flag(save_calls, N) -> OldN -  when N :: 0..10000, OldN :: 0..10000. + -spec process_flag(async_dist, Boolean) -> OldBoolean +  when Boolean :: boolean(), OldBoolean :: boolean(). - -spec process_flag(min_bin_vheap_size, MinBinVHeapSize) -> -  OldMinBinVHeapSize +Since: + OTP 25.3 + + Enable or disable fully asynchronous distributed signaling for + the calling process. When disabled, which is the default, the + process sending a distributed signal will block in the send + operation if the buffer for the distribution channel reach the + distribution buffer busy limit. The process will remain blocked + until the buffer shrinks enough. This might in some cases take a + substantial amount of time. When async_dist is enabled, send + operations of distributed signals will always buffer the signal on + the outgoing distribution channel and then immediately return. + That is, these send operations will never block the sending + process. + + Note: + Since no flow control is enforced by the runtime system when  + async_dist process flag is enabled, you need to make sure + that flow control for such data is implemented, or that the + amount of such data is known to always be limited. Unlimited + signaling with async_dist enabled in the absence of flow + control will typically cause the sending runtime system to + crash on an out of memory condition. + + Blocking due to disabled async_dist can be monitored by  + erlang:system_monitor() using the busy_dist_port option. Only + data buffered by processes which (at the time of sending a signal) + have disabled async_dist will be counted when determining + whether or not an operation should block the caller. + + The async_dist flag can also be set on a new process when + spawning it using the spawn_opt() BIF with the option  + {async_dist, Enable}. The default async_dist flag to use on + newly spawned processes can be set by passing the command line + argument +pad  when starting the runtime system. If the  + +pad  command line argument is not passed, the default + value of the async_dist flag will be false. + + You can inspect the state of the async_dist process flag of a + process by calling process_info(Pid, async_dist). + + Returns the old value of the async_dist flag. + + -spec process_flag(trap_exit, Boolean) -> OldBoolean +  when Boolean :: boolean(), OldBoolean :: boolean(). + + When trap_exit is set to true, exit signals arriving to a + process are converted to {'EXIT', From, Reason} messages, which + can be received as ordinary messages. If trap_exit is set to  + false, the process exits if it receives an exit signal other than  + normal and the exit signal is propagated to its linked processes. + Application processes are normally not to trap exits. + + Returns the old value of the flag. + + See also exit/2. + + -spec process_flag(error_handler, Module) -> OldModule +  when Module :: atom(), OldModule :: atom(). + + Used by a process to redefine the error handler for undefined + function calls and undefined registered processes. Inexperienced + users are not to use this flag, as code auto-loading depends on + the correct operation of the error handling module. + + Returns the old value of the flag. + + -spec process_flag(fullsweep_after, FullsweepAfter) -> OldFullsweepAfter  when -  MinBinVHeapSize :: non_neg_integer(), -  OldMinBinVHeapSize :: non_neg_integer(). +  FullsweepAfter :: non_neg_integer(), +  OldFullsweepAfter :: non_neg_integer(). Since: - OTP R13B04 + OTP 24.0 + + Changes the maximum number of generational collections before + forcing a fullsweep for the calling process. + + Returns the old value of the flag. -spec process_flag(min_heap_size, MinHeapSize) -> OldMinHeapSize  when  MinHeapSize :: non_neg_integer(),  OldMinHeapSize :: non_neg_integer(). - -spec process_flag(sensitive, Boolean) -> OldBoolean -  when Boolean :: boolean(), OldBoolean :: boolean(). + Changes the minimum heap size for the calling process. - -spec process_flag(error_handler, Module) -> OldModule -  when Module :: atom(), OldModule :: atom(). + Returns the old value of the flag. - -spec process_flag(trap_exit, Boolean) -> OldBoolean -  when Boolean :: boolean(), OldBoolean :: boolean(). + -spec process_flag(min_bin_vheap_size, MinBinVHeapSize) -> +  OldMinBinVHeapSize +  when +  MinBinVHeapSize :: non_neg_integer(), +  OldMinBinVHeapSize :: non_neg_integer(). + +Since: + OTP R13B04 + + Changes the minimum binary virtual heap size for the calling + process. + + Returns the old value of the flag. -spec process_flag(max_heap_size, MaxHeapSize) -> OldMaxHeapSize  when @@ -33,6 +113,84 @@ Since: OTP 19.0 + Types: + -type max_heap_size() :: + Size :: + non_neg_integer() | + #{size => non_neg_integer(), + kill => boolean(), + error_logger => boolean(), + include_shared_binaries => boolean()}. + + This flag sets the maximum heap size for the calling process. If  + MaxHeapSize is an integer, the system default values for kill + and error_logger are used. + + For details on how the heap grows, see Sizing the heap in the + ERTS internal documentation. + + size: + The maximum size in words of the process. If set to zero, the + heap size limit is disabled. badarg is be thrown if the + value is smaller than min_heap_size. The size check is only + done when a garbage collection is triggered. + + size is the entire heap of the process when garbage + collection is triggered. This includes all generational heaps, + the process stack, any messages that are considered to be + part of the heap, and any extra memory that the garbage + collector needs during collection. + + size is the same as can be retrieved using  + erlang:process_info(Pid, total_heap_size), or by adding  + heap_block_size, old_heap_block_size and mbuf_size from  + erlang:process_info(Pid, garbage_collection_info). + + kill: + When set to true, the runtime system sends an untrappable + exit signal with reason kill to the process if the maximum + heap size is reached. The garbage collection that triggered + the kill is not completed, instead the process exits as soon + as possible. When set to false, no exit signal is sent to + the process, instead it continues executing. + + If kill is not defined in the map, the system default will + be used. The default system default is true. It can be + changed by either option +hmaxk in erl(1), or  + erlang:system_flag(max_heap_size, MaxHeapSize). + + error_logger: + When set to true, the runtime system logs an error event via  + logger, containing details about the process when the maximum + heap size is reached. One log event is sent each time the + limit is reached. + + If error_logger is not defined in the map, the system + default is used. The default system default is true. It can + be changed by either the option +hmaxel int erl(1), or  + erlang:system_flag(max_heap_size, MaxHeapSize). + + include_shared_binaries: + When set to true, off-heap binaries are included in the + total sum compared against the size limit. Off-heap binaries + are typically larger binaries that may be shared between + processes. The size of a shared binary is included by all + processes that are referring it. Also, the entire size of a + large binary may be included even if only a smaller part of it + is referred by the process. + + If include_shared_binaries is not defined in the map, the + system default is used. The default system default is false. + It can be changed by either the option +hmaxib in erl(1), + or erlang:system_flag(max_heap_size, MaxHeapSize). + + The heap size of a process is quite hard to predict, especially + the amount of memory that is used during the garbage collection. + When contemplating using this option, it is recommended to first + run it in production with kill set to false and inspect the + log events to see what the normal peak sizes of the processes in + the system is and then tune the value accordingly. + -spec process_flag(message_queue_data, MQD) -> OldMQD  when  MQD :: message_queue_data(), @@ -41,6 +199,40 @@ Since: OTP 19.0 + Types: + -type message_queue_data() :: off_heap | on_heap. + + Determines how messages in the message queue are stored, as + follows: + + off_heap: + All messages in the message queue will be stored outside the + process heap. This implies that no messages in the message + queue will be part of a garbage collection of the process. + + on_heap: + All messages in the message queue will eventually be placed on + the process heap. They can, however, be temporarily stored off + the heap. This is how messages have always been stored up + until ERTS 8.0. + + The default value of the message_queue_data process flag is + determined by the command-line argument +hmqd in erl(1). + + If the process may potentially accumulate a large number of + messages in its queue it is recommended to set the flag value to  + off_heap. This is due to the fact that the garbage collection of + a process that has a large number of messages stored on the heap + can become extremely expensive and the process can consume large + amounts of memory. The performance of the actual message passing + is, however, generally better when the flag value is on_heap. + + Changing the flag value causes any existing messages to be moved. + The move operation is initiated, but not necessarily completed, by + the time the function returns. + + Returns the old value of the flag. + -spec process_flag(priority, Level) -> OldLevel  when  Level :: priority_level(), @@ -108,3 +300,62 @@ on priority normal. Returns the old value of the flag. + + -spec process_flag(save_calls, N) -> OldN +  when N :: 0..10000, OldN :: 0..10000. + + N must be an integer in the interval 0..10000. If N > 0, call + saving is made active for the process. This means that information + about the N most recent global function calls, BIF calls, sends, + and receives made by the process are saved in a list, which can be + retrieved with process_info(Pid, last_calls). A global function + call is one in which the module of the function is explicitly + mentioned. Only a fixed amount of information is saved, as + follows: + + • A tuple {Module, Function, Arity} for function calls + + • The atoms send, 'receive', and timeout for sends and + receives ('receive' when a message is received and  + timeout when a receive times out) + + If N = 0, call saving is disabled for the process, which is the + default. Whenever the size of the call saving list is set, its + contents are reset. + + Returns the old value of the flag. + + -spec process_flag(sensitive, Boolean) -> OldBoolean +  when Boolean :: boolean(), OldBoolean :: boolean(). + + Sets or clears flag sensitive for the current process. When a + process has been marked as sensitive by calling  + process_flag(sensitive, true), features in the runtime system + that can be used for examining the data or inner working of the + process are silently disabled. + + Features that are disabled include (but are not limited to) the + following: + + • Tracing. Trace flags can still be set for the process, but + no trace messages of any kind are generated. (If flag  + sensitive is turned off, trace messages are again generated + if any trace flags are set.) + + • Sequential tracing. The sequential trace token is propagated + as usual, but no sequential trace messages are generated. + + process_info/1,2 cannot be used to read out the message queue or + the process dictionary (both are returned as empty lists). + + Stack back-traces cannot be displayed for the process. + + In crash dumps, the stack, messages, and the process dictionary + are omitted. + + If {save_calls,N} has been set for the process, no function + calls are saved to the call saving list. (The call saving list is + not cleared. Also, send, receive, and time-out events are still + added to the list.) + + Returns the old value of the flag. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_1_func.txt index d9b372dd6507..283d5b120e63 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_1_func.txt @@ -11,10 +11,12 @@ non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), - error_logger => boolean()}. + error_logger => boolean(), + include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. -type priority_level() :: low | normal | high | max. -type process_info_result_item() :: + {async_dist, Enabled :: boolean()} | {backtrace, Bin :: binary()} | {binary, BinInfo :: @@ -59,6 +61,7 @@ port() | {RegName :: atom(), Node :: node()}}]} | {message_queue_data, MQD :: message_queue_data()} | + {parent, pid() | undefined} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | {registered_name, [] | (Atom :: atom())} | diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_2_func.txt index 8a5af38f1cde..7abc2b28c9f2 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_process_info_2_func.txt @@ -18,20 +18,23 @@ non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), - error_logger => boolean()}. + error_logger => boolean(), + include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. -type priority_level() :: low | normal | high | max. -type process_info_item() :: - backtrace | binary | catchlevel | current_function | - current_location | current_stacktrace | dictionary | - error_handler | garbage_collection | garbage_collection_info | - group_leader | heap_size | initial_call | links | last_calls | - memory | message_queue_len | messages | min_heap_size | + async_dist | backtrace | binary | catchlevel | + current_function | current_location | current_stacktrace | + dictionary | error_handler | garbage_collection | + garbage_collection_info | group_leader | heap_size | + initial_call | links | last_calls | memory | + message_queue_len | messages | min_heap_size | min_bin_vheap_size | monitored_by | monitors | - message_queue_data | priority | reductions | registered_name | - sequential_trace_token | stack_size | status | suspending | - total_heap_size | trace | trap_exit. + message_queue_data | parent | priority | reductions | + registered_name | sequential_trace_token | stack_size | + status | suspending | total_heap_size | trace | trap_exit. -type process_info_result_item() :: + {async_dist, Enabled :: boolean()} | {backtrace, Bin :: binary()} | {binary, BinInfo :: @@ -76,6 +79,7 @@ port() | {RegName :: atom(), Node :: node()}}]} | {message_queue_data, MQD :: message_queue_data()} | + {parent, pid() | undefined} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | {registered_name, [] | (Atom :: atom())} | @@ -117,6 +121,10 @@ Items in the same order as the Items were included in ItemList. Valid Items can be included multiple times in ItemList. + Getting process information follows the signal ordering guarantees + described in the Processes Chapter in the Erlang Reference + Manual. + Note: If registered_name is part of ItemList and the process has no name registered, a {registered_name, []}, InfoTuple @@ -126,6 +134,11 @@ Valid InfoTuples with corresponding Items: + {async_dist, Enabled}: + Since: OTP 25.3 + + Current value of the async_dist process flag. + {backtrace, Bin}: Binary Bin contains the same information as the output from  erlang:process_display(Pid, backtrace). Use binary_to_list/1 @@ -138,8 +151,8 @@ implementation BinInfo is a list of tuples. The tuples contain; BinaryId, BinarySize, BinaryRefcCount. - The message queue is on the heap depending on the process flag  - message_queue_data. + Depending on the value of the message_queue_data process + flag the message queue may be stored on the heap. {catchlevel, CatchLevel}: CatchLevel is the number of currently active catches in this @@ -251,10 +264,16 @@ the local node name. {message_queue_data, MQD}: - Returns the current state of process flag message_queue_data.  - MQD is either off_heap or on_heap. For more information, - see the documentation of process_flag(message_queue_data, - MQD). + MQD is the current value of the message_queue_data process + flag, which can be either off_heap or on_heap. For more + information, see the documentation of  + process_flag(message_queue_data, MQD). + + {parent, Pid}: + Pid is the identifier of the parent process, the one that + spawned current process. When the process does not have a + parent undefined is returned. Only the initial process ( + init) on a node lacks a parent, though. {priority, Level}: Level is the current priority level for the process. For more diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_purge_module_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_purge_module_1_func.txt index d335c7edec75..64137ede3a39 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_purge_module_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_purge_module_1_func.txt @@ -9,7 +9,7 @@ This BIF is intended for the code server (see code(3)) and is not to be used elsewhere. - Note: + Change: As from ERTS 8.0 (Erlang/OTP 19), any lingering processes that still execute the old code is killed by this function. In earlier versions, such incorrect use could cause much more diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_raise_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_raise_3_func.txt index 407a06aab411..e661585ba643 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_raise_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_raise_3_func.txt @@ -3,14 +3,13 @@  when  Class :: error | exit | throw,  Reason :: term(), -  Stacktrace :: raise_stacktrace(). +  Stacktrace :: +  raise_stacktrace() | stacktrace(). Types: -type raise_stacktrace() :: [{module(), atom(), arity() | [term()]} | - {function(), [term()]}] | - [{module(), atom(), arity() | [term()], [{atom(), term()}]} | - {function(), [term()], [{atom(), term()}]}]. + {function(), arity() | [term()]}]. Raises an exception of the specified class, reason, and call stack backtrace (stacktrace). @@ -31,12 +30,12 @@ end That is, a list of four-tuples {Module, Function, Arity | Args, - Location}, where Module and Function are atoms, and the third - element is an integer arity or an argument list. The stacktrace - can also contain {Fun, Args, Location} tuples, where Fun is a - local fun and Args is an argument list. + ExtraInfo}, where Module and Function are atoms, and the + third element is an integer arity or an argument list. The + stacktrace can also contain {Fun, Args, ExtraInfo} tuples, where  + Fun is a local fun and Args is an argument list. - Element Location at the end is optional. Omitting it is + Element ExtraInfo at the end is optional. Omitting it is equivalent to specifying an empty list. The stacktrace is used as the exception stacktrace for the calling diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_reference_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_reference_0_type.txt new file mode 100644 index 000000000000..e2ded8970eef --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_reference_0_type.txt @@ -0,0 +1,4 @@ + + -type reference() :: reference(). + + An Erlang reference. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_register_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_register_2_func.txt index aa1ea7ef8d03..b4b5c8a543d8 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_register_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_register_2_func.txt @@ -2,14 +2,19 @@ -spec register(RegName, PidOrPort) -> true  when RegName :: atom(), PidOrPort :: port() | pid(). - Associates the name RegName with a process identifier (pid) or a - port identifier. RegName, which must be an atom, can be used - instead of the pid or port identifier in send operator (RegName ! - Message). Example: + Registers the name RegName with a process identifier (pid) or a + port identifier in the name registry. RegName, which must be + an atom, can be used instead of the pid or port identifier in send + operator (RegName ! Message) and most other BIFs that take a pid + or port identifies as an argument. Example: > register(db, Pid). true + The registered name is considered a Directly Visible Erlang + Resource and is automatically unregistered when the process + terminates. + Failures: badarg: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_rem_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_rem_2_func.txt new file mode 100644 index 000000000000..d1f2d8eb5e6f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_rem_2_func.txt @@ -0,0 +1,5 @@ + +  'rem'/2 + + The documentation for 'rem'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_2_func.txt index 67721a962ccf..bd75d4131d3d 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_2_func.txt @@ -1,22 +1,20 @@ - -spec erlang:send(Dest, Msg) -> Msg when Dest :: dst(), Msg :: term(). - - Types: - -type dst() :: - pid() | - reference() | - port() | - (RegName :: atom()) | - {RegName :: atom(), Node :: node()}. + -spec erlang:send(Dest, Msg) -> Msg +  when Dest :: send_destination(), Msg :: term(). Sends a message and returns Msg. This is the same as using the send operator: Dest ! Msg. - Dest can be a remote or local process identifier, a (local) port, - a locally registered name, or a tuple {RegName, Node} for a - registered name at another node. + Dest can be a remote or local process identifier, an alias, a + (local) port, a locally registered name, or a tuple {RegName, + Node} for a registered name at another node. The function fails with a badarg run-time error if Dest is an atom name, but this name is not registered. This is the only case when send fails for an unreachable destination Dest (of correct type). + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_3_func.txt index 670a7ca72090..b8356593099b 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_3_func.txt @@ -1,19 +1,11 @@ -spec erlang:send(Dest, Msg, Options) -> Res  when -  Dest :: dst(), +  Dest :: send_destination(),  Msg :: term(),  Options :: [nosuspend | noconnect],  Res :: ok | nosuspend | noconnect. - Types: - -type dst() :: - pid() | - reference() | - port() | - (RegName :: atom()) | - {RegName :: atom(), Node :: node()}. - Either sends a message and returns ok, or does not send the message but returns something else (see below). Otherwise the same as erlang:send/2. For more detailed explanation and warnings, @@ -29,5 +21,10 @@ If the destination node would have to be auto-connected to do the send, noconnect is returned instead. + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + Warning: As with erlang:send_nosuspend/2,3: use with extreme care. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_destination_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_destination_0_type.txt new file mode 100644 index 000000000000..8d93b48399d2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_destination_0_type.txt @@ -0,0 +1,12 @@ + + -type send_destination() :: +  pid() | +  reference() | +  port() | +  (RegName :: atom()) | +  {RegName :: atom(), Node :: node()}. + + The destination for a send operation, can be a remote or local + process identifier, a (local) port, a reference denoting a process + alias, a locally registered name, or a tuple {RegName, Node} for + a registered name at another node. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_2_func.txt index 53d26831ab47..2c23e175209e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_2_func.txt @@ -1,14 +1,8 @@ -spec erlang:send_nosuspend(Dest, Msg) -> boolean() -  when Dest :: dst(), Msg :: term(). - - Types: - -type dst() :: - pid() | - reference() | - port() | - (RegName :: atom()) | - {RegName :: atom(), Node :: node()}. +  when +  Dest :: send_destination(), +  Msg :: term(). The same as erlang:send(Dest, Msg, [nosuspend]), but returns  true if the message was sent and false if the message was not diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_3_func.txt index fad064a8f284..28b45e10439b 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_send_nosuspend_3_func.txt @@ -1,18 +1,10 @@ -spec erlang:send_nosuspend(Dest, Msg, Options) -> boolean()  when -  Dest :: dst(), +  Dest :: send_destination(),  Msg :: term(),  Options :: [noconnect]. - Types: - -type dst() :: - pid() | - reference() | - port() | - (RegName :: atom()) | - {RegName :: atom(), Node :: node()}. - The same as erlang:send(Dest, Msg, [nosuspend | Options]), but with a Boolean return value. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_2_func.txt new file mode 100644 index 000000000000..eac7f6352cde --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_2_func.txt @@ -0,0 +1,5 @@ + +  seq_trace/2 + + The documentation for seq_trace/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_info_1_func.txt new file mode 100644 index 000000000000..6dc372826e6e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_info_1_func.txt @@ -0,0 +1,6 @@ + +  seq_trace_info/1 + + The documentation for seq_trace_info/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_1_func.txt new file mode 100644 index 000000000000..d0ae337121d2 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_1_func.txt @@ -0,0 +1,6 @@ + +  seq_trace_print/1 + + The documentation for seq_trace_print/1 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_2_func.txt new file mode 100644 index 000000000000..54905aa1a936 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_seq_trace_print_2_func.txt @@ -0,0 +1,6 @@ + +  seq_trace_print/2 + + The documentation for seq_trace_print/2 is hidden. This probably + means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_1_func.txt new file mode 100644 index 000000000000..322f3a22144e --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_1_func.txt @@ -0,0 +1,14 @@ + + -spec erlang:set_cookie(Cookie) -> true when Cookie :: atom(). + +Since: + OTP 24.1 + + Sets the magic cookie of the local node to the atom Cookie, + which is also the cookie for all nodes that have no explicit + cookie set with set_cookie/2 Cookie (see section Distributed + Erlang in the Erlang Reference Manual in System Documentation). + + You can get this value using get_cookie/0. + + Failure: function_clause if the local node is not alive. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_2_func.txt index 841be9c7cd58..4e4cec45dc31 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cookie_2_func.txt @@ -2,9 +2,12 @@ -spec erlang:set_cookie(Node, Cookie) -> true  when Node :: node(), Cookie :: atom(). - Sets the magic cookie of Node to the atom Cookie. If Node is - the local node, the function also sets the cookie of all other - unknown nodes to Cookie (see section Distributed Erlang in the - Erlang Reference Manual in System Documentation). + Sets the magic cookie for Node to the atom Cookie. If Node + is the local node, the function sets the cookie of all other nodes + (that have no explicit cookie set with this function) to Cookie + (see section Distributed Erlang in the Erlang Reference Manual + in System Documentation). + + You can get this value using get_cookie/1. Failure: function_clause if the local node is not alive. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cpu_topology_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cpu_topology_1_func.txt new file mode 100644 index 000000000000..1b44778f1a6b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_set_cpu_topology_1_func.txt @@ -0,0 +1,6 @@ + +  set_cpu_topology/1 + + The documentation for set_cpu_topology/1 is hidden. This + probably means that it is internal and not to be used by other + applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_2_func.txt new file mode 100644 index 000000000000..93491f778698 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_2_func.txt @@ -0,0 +1,5 @@ + +  setnode/2 + + The documentation for setnode/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_3_func.txt new file mode 100644 index 000000000000..0e2112a100a7 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_setnode_3_func.txt @@ -0,0 +1,5 @@ + +  setnode/3 + + The documentation for setnode/3 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slash_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slash_2_func.txt new file mode 100644 index 000000000000..688a861491f6 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slash_2_func.txt @@ -0,0 +1,5 @@ + +  '/'/2 + + The documentation for '/'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slasheq_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slasheq_2_func.txt new file mode 100644 index 000000000000..37d8260593aa --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_slasheq_2_func.txt @@ -0,0 +1,5 @@ + +  '/='/2 + + The documentation for '/='/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_2_func.txt index 95095e59dd89..60dd47981ac4 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_2_func.txt @@ -10,7 +10,8 @@ non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), - error_logger => boolean()}. + error_logger => boolean(), + include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. -type priority_level() :: low | normal | high | max. -type spawn_opt_option() :: @@ -21,7 +22,8 @@ {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()} | {max_heap_size, Size :: max_heap_size()} | - {message_queue_data, MQD :: message_queue_data()}. + {message_queue_data, MQD :: message_queue_data()} | + {async_dist, Enabled :: boolean()}. Returns the process identifier (pid) of a new process started by the application of Fun to the empty list []. Otherwise works diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_4_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_4_func.txt index 7a7ab7a819a4..e734f66f23ce 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_4_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_4_func.txt @@ -15,7 +15,8 @@ non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), - error_logger => boolean()}. + error_logger => boolean(), + include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. -type priority_level() :: low | normal | high | max. -type spawn_opt_option() :: @@ -26,7 +27,8 @@ {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()} | {max_heap_size, Size :: max_heap_size()} | - {message_queue_data, MQD :: message_queue_data()}. + {message_queue_data, MQD :: message_queue_data()} | + {async_dist, Enabled :: boolean()}. Works as spawn/3, except that an extra option list is specified when creating the process. @@ -125,8 +127,16 @@ process_flag(max_heap_size, Size). {message_queue_data, MQD}: - Sets the state of the message_queue_data process flag. MQD - is to be either off_heap or on_heap. The default  - message_queue_data process flag is determined by command-line - argument +hmqd in erl(1). For more information, see the - documentation of process_flag(message_queue_data, MQD). + Sets the value of the message_queue_data process flag. MQD + can be either off_heap or on_heap. The default value of + the message_queue_data process flag is determined by the + command-line argument +hmqd in erl(1). For more + information, see the documentation of  + process_flag(message_queue_data, MQD). + + {async_dist, Enabled}: + Since: OTP 25.3 + + Set the async_dist process flag of the spawned process. This + option will override the default value set by the command line + argument +pad . diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_option_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_option_0_type.txt index 3767db3c6b1f..bad83f1f6f75 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_option_0_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_opt_option_0_type.txt @@ -7,6 +7,7 @@  {min_heap_size, Size :: non_neg_integer()} |  {min_bin_vheap_size, VSize :: non_neg_integer()} |  {max_heap_size, Size :: max_heap_size()} | -  {message_queue_data, MQD :: message_queue_data()}. +  {message_queue_data, MQD :: message_queue_data()} | +  {async_dist, Enabled :: boolean()}. Options for spawn_opt(). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_2_func.txt index 828bb5e02949..afd4cfc4114c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_2_func.txt @@ -1,13 +1,4 @@ - -spec spawn_request(Node, Fun) -> ReqId -  when -  Node :: node(), -  Fun :: function(), -  ReqId :: reference(). - -Since: - OTP 23.0 - -spec spawn_request(Fun, Options) -> ReqId  when  Fun :: function(), @@ -25,3 +16,15 @@ The same as the call spawn_request(node(),Fun,Options). That is, a spawn request on the local node. + + -spec spawn_request(Node, Fun) -> ReqId +  when +  Node :: node(), +  Fun :: function(), +  ReqId :: reference(). + +Since: + OTP 23.0 + + The same as the call spawn_request(Node,Fun,[]). That is, a + spawn request with no options. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_3_func.txt index 33ccccd7ee4e..08a636a80871 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_3_func.txt @@ -19,6 +19,18 @@ Since: OTP 23.0 + The same as spawn_request(Node,erlang,apply,[Fun,[]],Options). + That is, a spawn request using the fun Fun of arity zero as + entry point. + + This function will fail with a badarg exception if: + + • Node is not an atom. + + • Fun is not a fun of arity zero. + + • Options is not a proper list of terms. + -spec spawn_request(Module, Function, Args) -> ReqId  when  Module :: module(), diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_4_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_4_func.txt index 484449ed3621..ba1a502ad699 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_4_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_4_func.txt @@ -10,6 +10,9 @@ Since: OTP 23.0 + The same as the call spawn_request(Node,Module,Function,Args,[]). + That is, a spawn request with no options. + -spec spawn_request(Module, Function, Args, Options) -> ReqId  when  Module :: module(), diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_5_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_5_func.txt index 3ebc26ed5a19..905a5cf441e1 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_5_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_spawn_request_5_func.txt @@ -157,6 +157,10 @@ Options for the local node of current OTP version can be found in the documentation of spawn_opt/4. + If a spawn reply message is delivered, it is guaranteed to be + delivered before any other signals from the newly spawned process + are delivered to the process issuing the spawn request. + This function will fail with a badarg exception if: • Node is not an atom. @@ -177,3 +181,8 @@ A spawn request can be abandoned by calling  spawn_request_abandon/1. + + Note: + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_0_type.txt new file mode 100644 index 000000000000..9d02af6aa5bc --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_0_type.txt @@ -0,0 +1,10 @@ + + -type stacktrace() :: +  [{module(), +  atom(), +  arity() | [term()], +  [stacktrace_extrainfo()]} | +  {function(), arity() | [term()], [stacktrace_extrainfo()]}]. + + An Erlang stacktrace as described by Errors and Error Handling + section in the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_extrainfo_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_extrainfo_0_type.txt new file mode 100644 index 000000000000..acdcdd1eb454 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_stacktrace_extrainfo_0_type.txt @@ -0,0 +1,10 @@ + + -type stacktrace_extrainfo() :: +  {line, pos_integer()} | +  {file, unicode:chardata()} | +  {error_info, +  #{module => module(), function => atom(), cause => term()}} | +  {atom(), term()}. + + An Erlang stacktrace as described by Errors and Error Handling + section in the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_star_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_star_2_func.txt new file mode 100644 index 000000000000..ff7f8595a1bd --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_star_2_func.txt @@ -0,0 +1,5 @@ + +  '*'/2 + + The documentation for '*'/2 is hidden. This probably means that + it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_statistics_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_statistics_1_func.txt index e54fa13ce6a0..e574f906784e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_statistics_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_statistics_1_func.txt @@ -1,4 +1,93 @@ + -spec statistics(active_tasks) -> [ActiveTasks] +  when ActiveTasks :: non_neg_integer(). + +Since: + OTP 18.3 + + Returns the same as statistics(active_tasks_all) with the + exception that no information about the dirty IO run queue and its + associated schedulers is part of the result. That is, only tasks + that are expected to be CPU bound are part of the result. + + -spec statistics(active_tasks_all) -> [ActiveTasks] +  when ActiveTasks :: non_neg_integer(). + +Since: + OTP 20.0 + + Returns a list where each element represents the amount of active + processes and ports on each run queue and its associated + schedulers. That is, the number of processes and ports that are + ready to run, or are currently running. Values for normal run + queues and their associated schedulers are located first in the + resulting list. The first element corresponds to scheduler number + 1 and so on. If support for dirty schedulers exist, an element + with the value for the dirty CPU run queue and its associated + dirty CPU schedulers follow and then as last element the value for + the the dirty IO run queue and its associated dirty IO schedulers + follow. The information is not gathered atomically. That is, the + result is not necessarily a consistent snapshot of the state, but + instead quite efficiently gathered. + + Note: + Each normal scheduler has one run queue that it manages. If + dirty schedulers schedulers are supported, all dirty CPU + schedulers share one run queue, and all dirty IO schedulers + share one run queue. That is, we have multiple normal run + queues, one dirty CPU run queue and one dirty IO run queue. + Work can not migrate between the different types of run + queues. Only work in normal run queues can migrate to other + normal run queues. This has to be taken into account when + evaluating the result. + + See also statistics(total_active_tasks),  + statistics(run_queue_lengths), statistics(run_queue_lengths_all),  + statistics(total_run_queue_lengths), and  + statistics(total_run_queue_lengths_all). + + -spec statistics(context_switches) -> {ContextSwitches, 0} +  when ContextSwitches :: non_neg_integer(). + + Returns the total number of context switches since the system + started. + + -spec statistics(exact_reductions) -> +  {Total_Exact_Reductions, +  Exact_Reductions_Since_Last_Call} +  when +  Total_Exact_Reductions :: non_neg_integer(), +  Exact_Reductions_Since_Last_Call :: +  non_neg_integer(). + + Returns the number of exact reductions. + + Note: + statistics(exact_reductions) is a more expensive operation + than statistics(reductions). + + -spec statistics(garbage_collection) -> +  {Number_of_GCs, Words_Reclaimed, 0} +  when +  Number_of_GCs :: non_neg_integer(), +  Words_Reclaimed :: non_neg_integer(). + + Returns information about garbage collection, for example: + + > statistics(garbage_collection). + {85,23961,0} + + This information can be invalid for some implementations. + + -spec statistics(io) -> {{input, Input}, {output, Output}} +  when +  Input :: non_neg_integer(), +  Output :: non_neg_integer(). + + Returns Input, which is the total number of bytes received + through ports, and Output, which is the total number of bytes + output to ports. + -spec statistics(microstate_accounting) -> [MSAcc_Thread] | undefined  when  MSAcc_Thread :: @@ -19,26 +108,195 @@ Since: OTP 19.0 - -spec statistics(io) -> {{input, Input}, {output, Output}} -  when -  Input :: non_neg_integer(), -  Output :: non_neg_integer(). + Microstate accounting can be used to measure how much time the + Erlang runtime system spends doing various tasks. It is designed + to be as lightweight as possible, but some overhead exists when + this is enabled. Microstate accounting is meant to be a profiling + tool to help finding performance bottlenecks. To start/stop/ + reset microstate accounting, use system flag  + microstate_accounting. - -spec statistics(scheduler_wall_time) -> -  [{SchedulerId, ActiveTime, TotalTime}] | undefined + statistics(microstate_accounting) returns a list of maps + representing some of the OS threads within ERTS. Each map contains  + type and id fields that can be used to identify what thread it + is, and also a counters field that contains data about how much + time has been spent in the various states. + + Example: + + > erlang:statistics(microstate_accounting). + [#{counters => #{aux => 1899182914, + check_io => 2605863602, + emulator => 45731880463, + gc => 1512206910, + other => 5421338456, + port => 221631, + sleep => 5150294100}, + id => 1, + type => scheduler}|...] + + The time unit is the same as returned by os:perf_counter/0. So, + to convert it to milliseconds, you can do something like this: + + lists:map( + fun(#{ counters := Cnt } = M) -> + MsCnt = maps:map(fun(_K, PerfCount) -> + erlang:convert_time_unit(PerfCount, perf_counter, 1000) + end, Cnt), + M#{ counters := MsCnt } + end, erlang:statistics(microstate_accounting)). + + Notice that these values are not guaranteed to be the exact time + spent in each state. This is because of various optimisation done + to keep the overhead as small as possible. + + MSAcc_Thread_Types: + + scheduler: + The main execution threads that do most of the work. See erl + +S for more details. + + dirty_cpu_scheduler: + The threads for long running cpu intensive work. See erl + +SDcpu for more details. + + dirty_io_scheduler: + The threads for long running I/O work. See erl +SDio for + more details. + + async: + Async threads are used by various linked-in drivers (mainly + the file drivers) do offload non-CPU intensive work. See erl + +A for more details. + + aux: + Takes care of any work that is not specifically assigned to a + scheduler. + + poll: + Does the IO polling for the emulator. See erl +IOt for more + details. + + The following MSAcc_Thread_States are available. All states are + exclusive, meaning that a thread cannot be in two states at once. + So, if you add the numbers of all counters in a thread, you get + the total runtime for that thread. + + aux: + Time spent handling auxiliary jobs. + + check_io: + Time spent checking for new I/O events. + + emulator: + Time spent executing Erlang processes. + + gc: + Time spent doing garbage collection. When extra states are + enabled this is the time spent doing non-fullsweep garbage + collections. + + other: + Time spent doing unaccounted things. + + port: + Time spent executing ports. + + sleep: + Time spent sleeping. + + More fine-grained MSAcc_Thread_States can be added through + configure (such as ./configure --with-microstate-accounting=extra + ). Enabling these states causes performance degradation when + microstate accounting is turned off and increases the overhead + when it is turned on. + + alloc: + Time spent managing memory. Without extra states this time is + spread out over all other states. + + bif: + Time spent in BIFs. Without extra states this time is part of + the emulator state. + + busy_wait: + Time spent busy waiting. This is also the state where a + scheduler no longer reports that it is active when using  + statistics(scheduler_wall_time). So, if you add all other + states but this and sleep, and then divide that by all time in + the thread, you should get something very similar to the  + scheduler_wall_time fraction. Without extra states this time + is part of the other state. + + ets: + Time spent executing ETS BIFs. Without extra states this time + is part of the emulator state. + + gc_full: + Time spent doing fullsweep garbage collection. Without extra + states this time is part of the gc state. + + nif: + Time spent in NIFs. Without extra states this time is part of + the emulator state. + + send: + Time spent sending messages (processes only). Without extra + states this time is part of the emulator state. + + timers: + Time spent managing timers. Without extra states this time is + part of the other state. + + The utility module msacc(3) can be used to more easily analyse + these statistics. + + Returns undefined if system flag microstate_accounting is + turned off. + + The list of thread information is unsorted and can appear in + different order between calls. + + Note: + The threads and states are subject to change without any prior + notice. + + -spec statistics(reductions) -> +  {Total_Reductions, Reductions_Since_Last_Call}  when -  SchedulerId :: pos_integer(), -  ActiveTime :: non_neg_integer(), -  TotalTime :: non_neg_integer(). +  Total_Reductions :: non_neg_integer(), +  Reductions_Since_Last_Call :: non_neg_integer(). -Since: - OTP R15B01 + Returns information about reductions, for example: - -spec statistics(active_tasks_all) -> [ActiveTasks] -  when ActiveTasks :: non_neg_integer(). + > statistics(reductions). + {2046,11} + + Change: + As from ERTS 5.5 (Erlang/OTP R11B), this value does not + include reductions performed in current time slices of + currently scheduled processes. If an exact value is wanted, + use statistics(exact_reductions). + + -spec statistics(run_queue) -> non_neg_integer(). + + Returns the total length of all normal and dirty CPU run queues. + That is, queued work that is expected to be CPU bound. The + information is gathered atomically. That is, the result is a + consistent snapshot of the state, but this operation is much more + expensive compared to statistics(total_run_queue_lengths), + especially when a large amount of schedulers is used. + + -spec statistics(run_queue_lengths) -> [RunQueueLength] +  when RunQueueLength :: non_neg_integer(). Since: - OTP 20.0 + OTP 18.3 + + Returns the same as statistics(run_queue_lengths_all) with the + exception that no information about the dirty IO run queue is part + of the result. That is, only run queues with work that is expected + to be CPU bound is part of the result. -spec statistics(run_queue_lengths_all) -> [RunQueueLength]  when RunQueueLength :: non_neg_integer(). @@ -46,55 +304,191 @@ Since: OTP 20.0 - -spec statistics(garbage_collection) -> -  {Number_of_GCs, Words_Reclaimed, 0} -  when -  Number_of_GCs :: non_neg_integer(), -  Words_Reclaimed :: non_neg_integer(). + Returns a list where each element represents the amount of + processes and ports ready to run for each run queue. Values for + normal run queues are located first in the resulting list. The + first element corresponds to the normal run queue of scheduler + number 1 and so on. If support for dirty schedulers exist, values + for the dirty CPU run queue and the dirty IO run queue follow (in + that order) at the end. The information is not gathered + atomically. That is, the result is not necessarily a consistent + snapshot of the state, but instead quite efficiently gathered. - -spec statistics(reductions) -> -  {Total_Reductions, Reductions_Since_Last_Call} -  when -  Total_Reductions :: non_neg_integer(), -  Reductions_Since_Last_Call :: non_neg_integer(). + Note: + Each normal scheduler has one run queue that it manages. If + dirty schedulers schedulers are supported, all dirty CPU + schedulers share one run queue, and all dirty IO schedulers + share one run queue. That is, we have multiple normal run + queues, one dirty CPU run queue and one dirty IO run queue. + Work can not migrate between the different types of run + queues. Only work in normal run queues can migrate to other + normal run queues. This has to be taken into account when + evaluating the result. + + See also statistics(run_queue_lengths),  + statistics(total_run_queue_lengths_all),  + statistics(total_run_queue_lengths), statistics(active_tasks),  + statistics(active_tasks_all), and statistics(total_active_tasks),  + statistics(total_active_tasks_all). -spec statistics(runtime) -> {Total_Run_Time, Time_Since_Last_Call}  when  Total_Run_Time :: non_neg_integer(),  Time_Since_Last_Call :: non_neg_integer(). - -spec statistics(wall_clock) -> -  {Total_Wallclock_Time, -  Wallclock_Time_Since_Last_Call} -  when -  Total_Wallclock_Time :: non_neg_integer(), -  Wallclock_Time_Since_Last_Call :: -  non_neg_integer(). + Returns information about runtime, in milliseconds. - -spec statistics(exact_reductions) -> -  {Total_Exact_Reductions, -  Exact_Reductions_Since_Last_Call} -  when -  Total_Exact_Reductions :: non_neg_integer(), -  Exact_Reductions_Since_Last_Call :: -  non_neg_integer(). + This is the sum of the runtime for all threads in the Erlang + runtime system and can therefore be greater than the wall clock + time. - -spec statistics(active_tasks) -> [ActiveTasks] -  when ActiveTasks :: non_neg_integer(). + Warning: + This value might wrap due to limitations in the underlying + functionality provided by the operating system that is used. -Since: - OTP 18.3 + Example: - -spec statistics(run_queue_lengths) -> [RunQueueLength] -  when RunQueueLength :: non_neg_integer(). + > statistics(runtime). + {1690,1620} + + -spec statistics(scheduler_wall_time) -> +  [{SchedulerId, ActiveTime, TotalTime}] | undefined +  when +  SchedulerId :: pos_integer(), +  ActiveTime :: non_neg_integer(), +  TotalTime :: non_neg_integer(). Since: - OTP 18.3 + OTP R15B01 - -spec statistics(run_queue) -> non_neg_integer(). + Returns information describing how much time normal and dirty + CPU schedulers in the system have been busy. This value is + normally a better indicator of how much load an Erlang node is + under instead of looking at the CPU utilization provided by tools + such as top or sysstat. This is because scheduler_wall_time + also includes time where the scheduler is waiting for some other + reasource (such as an internal mutex) to be available but does not + use the CPU. In order to better understand what a scheduler is + busy doing you can use microstate accounting. - -spec statistics(context_switches) -> {ContextSwitches, 0} -  when ContextSwitches :: non_neg_integer(). + The definition of a busy scheduler is when it is not idle and not + busy waiting for new work, that is: + + • Executing process code + + • Executing linked-in driver or NIF code + + • Executing BIFs, or any other runtime handling + + • Garbage collecting + + • Handling any other memory management + + Notice that a scheduler can also be busy even if the OS has + scheduled out the scheduler thread. + + Note: + It is recommended to use the module scheduler instead of + this function directly as it provides an easier way to get the + information that you usually want. + + If enabled this function returns a list of tuples with  + {SchedulerId, ActiveTime, TotalTime}, where SchedulerId is an + integer ID of the scheduler, ActiveTime is the duration the + scheduler has been busy, and TotalTime is the total time + duration since scheduler_wall_time activation for the specific + scheduler. The time unit returned is undefined and can be subject + to change between releases, OSs, and system restarts.  + scheduler_wall_time is only to be used to calculate relative + values for scheduler utilization. The ActiveTime can never + exceed TotalTime. The list of scheduler information is unsorted + and can appear in different order between calls. + + The disabled this function returns undefined. + + The activation time can differ significantly between schedulers. + Currently dirty schedulers are activated at system start while + normal schedulers are activated some time after the  + scheduler_wall_time functionality is enabled. + + Only information about schedulers that are expected to handle CPU + bound work is included in the return values from this function. If + you also want information about dirty I/O schedulers, use  + statistics(scheduler_wall_time_all) instead. + + Normal schedulers will have scheduler identifiers in the range 1 + =< SchedulerId =< erlang:system_info(schedulers). Dirty CPU + schedulers will have scheduler identifiers in the range  + erlang:system_info(schedulers) < SchedulerId =< + erlang:system_info(schedulers) +  + erlang:system_info(dirty_cpu_schedulers). + + Note: + The different types of schedulers handle specific types of + jobs. Every job is assigned to a specific scheduler type. Jobs + can migrate between different schedulers of the same type, but + never between schedulers of different types. This fact has to + be taken under consideration when evaluating the result + returned. + + You can use scheduler_wall_time to calculate scheduler + utilization. First you take a sample of the values returned by  + erlang:statistics(scheduler_wall_time). + + > erlang:system_flag(scheduler_wall_time, true). + false + > Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), ok. + ok + + Some time later the user takes another snapshot and calculates + scheduler utilization per scheduler, for example: + + > Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), ok. + ok + > lists:map(fun({{I, A0, T0}, {I, A1, T1}}) -> + {I, (A1 - A0)/(T1 - T0)} end, lists:zip(Ts0,Ts1)). + [{1,0.9743474730177548}, + {2,0.9744843782751444}, + {3,0.9995902361669045}, + {4,0.9738012596572161}, + {5,0.9717956667018103}, + {6,0.9739235846420741}, + {7,0.973237033077876}, + {8,0.9741297293248656}] + + Using the same snapshots to calculate a total scheduler + utilization: + + > {A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) -> + {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), + TotalSchedulerUtilization = A/T. + 0.9769136803764825 + + Total scheduler utilization will equal 1.0 when all schedulers + have been active all the time between the two measurements. + + Another (probably more) useful value is to calculate total + scheduler utilization weighted against maximum amount of available + CPU time: + + > WeightedSchedulerUtilization = (TotalSchedulerUtilization + * (erlang:system_info(schedulers) + + erlang:system_info(dirty_cpu_schedulers))) + / erlang:system_info(logical_processors_available). + 0.9769136803764825 + + This weighted scheduler utilization will reach 1.0 when + schedulers are active the same amount of time as maximum available + CPU time. If more schedulers exist than available logical + processors, this value may be greater than 1.0. + + As of ERTS version 9.0, the Erlang runtime system will as default + have more schedulers than logical processors. This due to the + dirty schedulers. + + Note: + scheduler_wall_time is by default disabled. To enable it, use  + erlang:system_flag(scheduler_wall_time, true). -spec statistics(scheduler_wall_time_all) ->  [{SchedulerId, ActiveTime, TotalTime}] | undefined @@ -106,24 +500,49 @@ Since: OTP 20.0 + The same as statistics(scheduler_wall_time), except that it also + include information about all dirty I/O schedulers. + + Dirty IO schedulers will have scheduler identifiers in the range  + erlang:system_info(schedulers) +  + erlang:system_info(dirty_cpu_schedulers) < SchedulerId =< + erlang:system_info(schedulers) + + erlang:system_info(dirty_cpu_schedulers) +  + erlang:system_info(dirty_io_schedulers). + + Note: + Note that work executing on dirty I/O schedulers are expected + to mainly wait for I/O. That is, when you get high scheduler + utilization on dirty I/O schedulers, CPU utilization is not + expected to be high due to this work. + -spec statistics(total_active_tasks) -> ActiveTasks  when ActiveTasks :: non_neg_integer(). Since: OTP 18.3 + The same as calling lists:sum(statistics(active_tasks)), but + more efficient. + -spec statistics(total_active_tasks_all) -> ActiveTasks  when ActiveTasks :: non_neg_integer(). Since: OTP 20.0 + The same as calling lists:sum(statistics(active_tasks_all)), + but more efficient. + -spec statistics(total_run_queue_lengths) -> TotalRunQueueLengths  when TotalRunQueueLengths :: non_neg_integer(). Since: OTP 18.3 + The same as calling lists:sum(statistics(run_queue_lengths)), + but more efficient. + -spec statistics(total_run_queue_lengths_all) -> TotalRunQueueLengths  when TotalRunQueueLengths :: non_neg_integer(). @@ -132,3 +551,15 @@ The same as calling lists:sum(statistics(run_queue_lengths_all)), but more efficient. + + -spec statistics(wall_clock) -> +  {Total_Wallclock_Time, +  Wallclock_Time_Since_Last_Call} +  when +  Total_Wallclock_Time :: non_neg_integer(), +  Wallclock_Time_Since_Last_Call :: +  non_neg_integer(). + + Returns information about wall clock. wall_clock can be used in + the same manner as runtime, except that real time is measured as + opposed to runtime or CPU time. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_string_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_string_0_type.txt new file mode 100644 index 000000000000..fee694adbc2b --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_string_0_type.txt @@ -0,0 +1,5 @@ + + -type string() :: [char()]. + + A character string represented by a list of ASCII characters or + unicode codepoints. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_subtract_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_subtract_2_func.txt new file mode 100644 index 000000000000..b3e9734abf88 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_subtract_2_func.txt @@ -0,0 +1,5 @@ + +  subtract/2 + + The documentation for subtract/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_suspend_process_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_suspend_process_2_func.txt index 7f22bae23c52..8b604b502525 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_suspend_process_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_suspend_process_2_func.txt @@ -55,7 +55,7 @@ process that issued this request, have called  resume_process(Suspendee) before getting the reply. - Appart from the reply message, the {asynchronous, ReplyTag} + Apart from the reply message, the {asynchronous, ReplyTag} option behaves exactly the same as the asynchronous option without reply tag. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_flag_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_flag_2_func.txt index ed9417d79ecf..b46fb4474c51 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_flag_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_flag_2_func.txt @@ -1,52 +1,61 @@ - -spec erlang:system_flag(time_offset, finalize) -> OldState + -spec erlang:system_flag(backtrace_depth, Depth) -> OldDepth  when -  OldState :: -  preliminary | final | volatile. +  Depth :: non_neg_integer(), +  OldDepth :: non_neg_integer(). -Since: - OTP 18.0 + Sets the maximum depth of call stack back-traces in the exit + reason element of 'EXIT' tuples. The flag also limits the + stacktrace depth returned by process_info item  + current_stacktrace. - -spec erlang:system_flag(multi_scheduling, BlockState) -> OldBlockState -  when -  BlockState :: -  block | unblock | block_normal | -  unblock_normal, -  OldBlockState :: -  blocked | disabled | enabled. + Returns the old value of the flag. - -spec erlang:system_flag(fullsweep_after, Number) -> OldNumber + -spec erlang:system_flag(cpu_topology, CpuTopology) -> OldCpuTopology  when -  Number :: non_neg_integer(), -  OldNumber :: non_neg_integer(). +  CpuTopology :: cpu_topology(), +  OldCpuTopology :: cpu_topology(). - -spec erlang:system_flag(erts_alloc, {Alloc, F, V}) -> ok | notsup -  when -  Alloc :: atom(), -  F :: atom(), -  V :: integer(). + Types: + -type cpu_topology() :: [LevelEntry :: level_entry()] | undefined. + -type info_list() :: []. + -type level_entry() :: + {LevelTag :: level_tag(), SubLevel :: sub_level()} | + {LevelTag :: level_tag(), + InfoList :: info_list(), + SubLevel :: sub_level()}. + -type level_tag() :: core | node | processor | thread. + -type sub_level() :: + [LevelEntry :: level_entry()] | + (LogicalCpuId :: {logical, non_neg_integer()}). -Since: - OTP 20.2.3 + Warning: + This argument is deprecated. Instead of using this argument, + use command-line argument +sct in erl(1). - -spec erlang:system_flag(min_bin_vheap_size, MinBinVHeapSize) -> -  OldMinBinVHeapSize -  when -  MinBinVHeapSize :: non_neg_integer(), -  OldMinBinVHeapSize :: non_neg_integer(). + When this argument is removed, a final CPU topology to use is + determined at emulator boot time. -Since: - OTP R13B04 + Sets the user-defined CpuTopology. The user-defined CPU topology + overrides any automatically detected CPU topology. By passing  + undefined as CpuTopology, the system reverts to the CPU + topology automatically detected. The returned value equals the + value returned from erlang:system_info(cpu_topology) before the + change was made. - -spec erlang:system_flag(min_heap_size, MinHeapSize) -> OldMinHeapSize -  when -  MinHeapSize :: non_neg_integer(), -  OldMinHeapSize :: non_neg_integer(). + Returns the old value of the flag. - -spec erlang:system_flag(backtrace_depth, Depth) -> OldDepth -  when -  Depth :: non_neg_integer(), -  OldDepth :: non_neg_integer(). + The CPU topology is used when binding schedulers to logical + processors. If schedulers are already bound when the CPU topology + is changed, the schedulers are sent a request to rebind according + to the new CPU topology. + + The user-defined CPU topology can also be set by passing + command-line argument +sct to erl(1). + + For information on type CpuTopology and more, see  + erlang:system_info(cpu_topology) as well as command-line flags  + +sct and +sbt in erl(1). -spec erlang:system_flag(dirty_cpu_schedulers_online,  DirtyCPUSchedulersOnline) -> @@ -60,32 +69,63 @@ Since: OTP 17.0 - -spec erlang:system_flag(schedulers_online, SchedulersOnline) -> -  OldSchedulersOnline -  when -  SchedulersOnline :: pos_integer(), -  OldSchedulersOnline :: pos_integer(). + Sets the number of dirty CPU schedulers online. Range is 1 <= + DirtyCPUSchedulersOnline <= N, where N is the smallest of the + return values of erlang:system_info(dirty_cpu_schedulers) and  + erlang:system_info(schedulers_online). - -spec erlang:system_flag(system_logger, Logger) -> PrevLogger + Returns the old value of the flag. + + The number of dirty CPU schedulers online can change if the number + of schedulers online changes. For example, if 12 schedulers and 6 + dirty CPU schedulers are online, and system_flag/2 is used to + set the number of schedulers online to 6, then the number of dirty + CPU schedulers online is automatically decreased by half as well, + down to 3. Similarly, the number of dirty CPU schedulers online + increases proportionally to increases in the number of schedulers + online. + + For more information, see  + erlang:system_info(dirty_cpu_schedulers) and  + erlang:system_info(dirty_cpu_schedulers_online). + + -spec erlang:system_flag(erts_alloc, {Alloc, F, V}) -> ok | notsup  when -  Logger :: logger | undefined | pid(), -  PrevLogger :: logger | undefined | pid(). +  Alloc :: atom(), +  F :: atom(), +  V :: integer(). Since: - OTP 21.3 + OTP 20.2.3 - -spec erlang:system_flag(trace_control_word, TCW) -> OldTCW -  when -  TCW :: non_neg_integer(), -  OldTCW :: non_neg_integer(). + Sets system flags for erts_alloc(3). Alloc is the allocator to + affect, for example binary_alloc. F is the flag to change and  + V is the new value. - -spec erlang:system_flag(scheduler_wall_time, Boolean) -> OldBoolean + Only a subset of all erts_alloc flags can be changed at run + time. This subset is currently only the flag sbct. + + Returns ok if the flag was set or notsup if not supported by  + erts_alloc. + + -spec erlang:system_flag(fullsweep_after, Number) -> OldNumber  when -  Boolean :: boolean(), -  OldBoolean :: boolean(). +  Number :: non_neg_integer(), +  OldNumber :: non_neg_integer(). -Since: - OTP R15B01 + Sets system flag fullsweep_after. Number is a non-negative + integer indicating how many times generational garbage collections + can be done without forcing a fullsweep collection. The value + applies to new processes, while processes already running are not + affected. + + Returns the old value of the flag. + + In low-memory systems (especially without virtual memory), setting + the value to 0 can help to conserve memory. + + This value can also be set through (OS) environment variable  + ERL_FULLSWEEP_AFTER. -spec erlang:system_flag(microstate_accounting, Action) -> OldState  when @@ -95,10 +135,41 @@ Since: OTP 19.0 - -spec erlang:system_flag(cpu_topology, CpuTopology) -> OldCpuTopology + Turns on/off microstate accounting measurements. When passing + reset, all counters are reset to 0. + + For more information see statistics(microstate_accounting). + + -spec erlang:system_flag(min_heap_size, MinHeapSize) -> OldMinHeapSize  when -  CpuTopology :: cpu_topology(), -  OldCpuTopology :: cpu_topology(). +  MinHeapSize :: non_neg_integer(), +  OldMinHeapSize :: non_neg_integer(). + + Sets the default minimum heap size for processes. The size is + specified in words. The new min_heap_size effects only processes + spawned after the change of min_heap_size has been made.  + min_heap_size can be set for individual processes by using  + spawn_opt/4 or process_flag/2. + + Returns the old value of the flag. + + -spec erlang:system_flag(min_bin_vheap_size, MinBinVHeapSize) -> +  OldMinBinVHeapSize +  when +  MinBinVHeapSize :: non_neg_integer(), +  OldMinBinVHeapSize :: non_neg_integer(). + +Since: + OTP R13B04 + + Sets the default minimum binary virtual heap size for processes. + The size is specified in words. The new min_bin_vhheap_size + effects only processes spawned after the change of  + min_bin_vheap_size has been made. min_bin_vheap_size can be set + for individual processes by using spawn_opt/2,3,4 or  + process_flag/2. + + Returns the old value of the flag. -spec erlang:system_flag(max_heap_size, MaxHeapSize) -> OldMaxHeapSize  when @@ -108,6 +179,113 @@ Since: OTP 19.0 + Types: + -type max_heap_size() :: + Size :: + non_neg_integer() | + #{size => non_neg_integer(), + kill => boolean(), + error_logger => boolean(), + include_shared_binaries => boolean()}. + + Sets the default maximum heap size settings for processes. The + size is specified in words. The new max_heap_size effects only + processes spawned after the change has been made. max_heap_size + can be set for individual processes using spawn_opt/2,3,4 or  + process_flag/2. + + Returns the old value of the flag. + + For details on how the heap grows, see Sizing the heap in the + ERTS internal documentation. + + -spec erlang:system_flag(multi_scheduling, BlockState) -> OldBlockState +  when +  BlockState :: +  block | unblock | block_normal | +  unblock_normal, +  OldBlockState :: +  blocked | disabled | enabled. + + If multi-scheduling is enabled, more than one scheduler thread is + used by the emulator. Multi-scheduling can be blocked in two + different ways. Either all schedulers but one is blocked, or all + normal schedulers but one is blocked. When only normal schedulers + are blocked, dirty schedulers are free to continue to schedule + processes. + + If BlockState =:= block, multi-scheduling is blocked. That is, + one and only one scheduler thread will execute. If BlockState =:= + unblock and no one else blocks multi-scheduling, and this process + has blocked only once, multi-scheduling is unblocked. + + If BlockState =:= block_normal, normal multi-scheduling is + blocked. That is, only one normal scheduler thread will execute, + but multiple dirty schedulers can execute. If BlockState =:= + unblock_normal and no one else blocks normal multi-scheduling, + and this process has blocked only once, normal multi-scheduling is + unblocked. + + One process can block multi-scheduling and normal multi-scheduling + multiple times. If a process has blocked multiple times, it must + unblock exactly as many times as it has blocked before it has + released its multi-scheduling block. If a process that has blocked + multi-scheduling or normal multi-scheduling exits, it + automatically releases its blocking of multi-scheduling and normal + multi-scheduling. + + The return values are disabled, blocked, blocked_normal, or  + enabled. The returned value describes the state just after the + call to erlang:system_flag(multi_scheduling, BlockState) has + been made. For information about the return values, see  + erlang:system_info(multi_scheduling). + + Note: + Blocking of multi-scheduling and normal multi-scheduling is + normally not needed. If you feel that you need to use these + features, consider it a few more times again. Blocking + multi-scheduling is only to be used as a last resort, as it is + most likely a very inefficient way to solve the problem. + + See also erlang:system_info(multi_scheduling),  + erlang:system_info(normal_multi_scheduling_blockers),  + erlang:system_info(multi_scheduling_blockers), and  + erlang:system_info(schedulers). + + -spec erlang:system_flag(outstanding_system_requests_limit, NewLimit) -> +  OldLimit +  when +  NewLimit :: 1..134217727, +  OldLimit :: 1..134217727. + +Since: + OTP 24.2 + + Sets a limit on the amount of outstanding requests made by a + system process orchestrating system wide changes. Currently there + are two such processes: + + The Code Purger: + The code purger orchestrates checking of references to old + code before old code is removed from the system. + + The Literal Area Collector: + The literal area collector orchestrates copying of references + from old literal areas before removal of such areas from the + system. + + Each of these processes are allowed to have as many outstanding + requests as this limit is set to. By default this limit is set to + twice the amount of schedulers on the system. This will ensure + that schedulers will have enough work scheduled to perform these + operations as quickly as possible at the same time as other work + will be interleaved with this work. Currently used limit can be + checked by calling  + erlang:system_info(outstanding_system_requests_limit). + + This limit can also be set by passing the command line argument  + +zosrl  to erl. + -spec erlang:system_flag(scheduler_bind_type, How) -> OldBindType  when  How :: @@ -212,3 +390,133 @@ For more information, see erlang:system_info(scheduler_bind_type),  erlang:system_info(scheduler_bindings), as well as command-line flags +sbt and +sct in erl(1). + + -spec erlang:system_flag(scheduler_wall_time, Boolean) -> OldBoolean +  when +  Boolean :: boolean(), +  OldBoolean :: boolean(). + +Since: + OTP R15B01 + + Try enable or disable scheduler wall time measurements by passing  + Boolean as either true or false. + + For more information about how to use scheduler wall time + measurements, see statistics(scheduler_wall_time). + + Scheduler wall time measurements has a node global state. It is + either enabled for all processes on the node or disabled for all + processes. Each process has a logical counter initialized as zero. + A call with Boolean as true will increase that counter one + step for the calling process. A call with false will decrease it + one step unless it already is zero. The node global state for  + scheduler_wall_time will be enabled as long as there is at least + one process alive with a counter value larger than zero. When a + process terminates, its counter will also disappear. To ensure  + scheduler_wall_time is kept enabled, the process that enabled it + must therefore be kept alive. + + Returns the old value of the node global state, true if + scheduler wall time measurements were enabled, false if it were + disabled. + + Scheduler wall time measurements do consume some cpu overhead and + should not be left turned on unless used. + + -spec erlang:system_flag(schedulers_online, SchedulersOnline) -> +  OldSchedulersOnline +  when +  SchedulersOnline :: pos_integer(), +  OldSchedulersOnline :: pos_integer(). + + Sets the number of schedulers online. Range is 1 <= + SchedulersOnline <= erlang:system_info(schedulers). + + Returns the old value of the flag. + + If the emulator was built with support for dirty schedulers, + changing the number of schedulers online can also change the + number of dirty CPU schedulers online. For example, if 12 + schedulers and 6 dirty CPU schedulers are online, and  + system_flag/2 is used to set the number of schedulers online to + 6, then the number of dirty CPU schedulers online is automatically + decreased by half as well, down to 3. Similarly, the number of + dirty CPU schedulers online increases proportionally to increases + in the number of schedulers online. + + For more information, see erlang:system_info(schedulers) and  + erlang:system_info(schedulers_online). + + -spec erlang:system_flag(system_logger, Logger) -> PrevLogger +  when +  Logger :: logger | undefined | pid(), +  PrevLogger :: logger | undefined | pid(). + +Since: + OTP 21.3 + + Sets the process that will receive the logging messages generated + by ERTS. If set to undefined, all logging messages generated by + ERTS will be dropped. The messages will be in the format: + + {log,Level,Format,ArgList,Metadata} where + + Level = atom(), + Format = string(), + ArgList = list(term()), + Metadata = #{ pid => pid(), + group_leader => pid(), + time := logger:timestamp(), + error_logger := #{ emulator := true, tag := atom() } + + + If the system_logger process dies, this flag will be reset to  + logger. + + The default is the process named logger. + + Returns the old value of the flag. + + Note: + This function is designed to be used by the KERNEL logger. + Be careful if you change it to something else as log messages + may be lost. If you want to intercept emulator log messages, + do it by adding a specialized handler to the KERNEL logger. + + -spec erlang:system_flag(trace_control_word, TCW) -> OldTCW +  when +  TCW :: non_neg_integer(), +  OldTCW :: non_neg_integer(). + + Sets the value of the node trace control word to TCW, which is + to be an unsigned integer. For more information, see function  + set_tcw in section "Match Specifications in Erlang" in the User's + Guide. + + Returns the old value of the flag. + + -spec erlang:system_flag(time_offset, finalize) -> OldState +  when +  OldState :: +  preliminary | final | volatile. + +Since: + OTP 18.0 + + Finalizes the time offset when single time warp mode is used. + If another time warp mode is used, the time offset state is left + unchanged. + + Returns the old state identifier, that is: + + • If preliminary is returned, finalization was performed and + the time offset is now final. + + • If final is returned, the time offset was already in the + final state. This either because another  + erlang:system_flag(time_offset, finalize) call or because + no time warp mode is used. + + • If volatile is returned, the time offset cannot be + finalized because multi-time warp mode is used. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_info_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_info_1_func.txt index 958bee44a144..9ecf3bad8ff8 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_info_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_system_info_1_func.txt @@ -1,4 +1,54 @@ + -spec erlang:system_info(sequential_tracer) -> +  {sequential_tracer, +  pid() | port() | {module(), term()} | false}. + + Returns information about the current system. The documentation of + this function is broken into the following sections in order to + make it easier to navigate. + + Memory Allocation: + allocated_areas, allocator, alloc_util_allocators,  + allocator_sizes + + CPU Topology: + cpu_topology, logical_processors, cpu_quota,  + update_cpu_info + + Process Information: + fullsweep_after, garbage_collection, heap_sizes,  + heap_type, max_heap_size, message_queue_data,  + min_heap_size, min_bin_vheap_size, procs + + System Limits: + atom_count, atom_limit, ets_count, ets_limit,  + port_count, port_limit, process_count, process_limit + + System Time: + end_time, os_monotonic_time_source, os_system_time_source,  + start_time, time_correction, time_offset, time_warp_mode,  + tolerant_timeofday + + Scheduler Information: + dirty_cpu_schedulers, dirty_cpu_schedulers_online,  + dirty_io_schedulers, multi_scheduling,  + multi_scheduling_blockers, normal_multi_scheduling_blockers,  + scheduler_bind_type, scheduler_bindings, scheduler_id,  + schedulers, smp_support, threads, thread_pool_size + + Distribution Information: + async_dist, creation, delayed_node_table_gc, dist,  + dist_buf_busy_limit, dist_ctrl + + System Information: + c_compiler_used, check_io, compat_rel, debug_compiled,  + driver_version, dynamic_trace, dynamic_trace_probes,  + emu_flavor, emu_type, info, kernel_poll, loaded,  + machine, modified_timing_level, nif_version, otp_release,  + outstanding_system_requests_limit, port_parallelism,  + system_architecture, system_logger, system_version,  + trace_control_word, version, wordsize + -spec erlang:system_info(allocated_areas) -> [tuple()];  (allocator) ->  {Allocator, Version, Features, Settings} @@ -16,126 +66,231 @@  ({allocator_sizes, Alloc}) -> [_]  when Alloc :: atom(). - -spec erlang:system_info(creation) -> integer(); -  (delayed_node_table_gc) -> -  infinity | non_neg_integer(); -  (dist) -> binary(); -  (dist_buf_busy_limit) -> non_neg_integer(); -  (dist_ctrl) -> -  {Node :: node(), -  ControllingEntity :: port() | pid()}. + Returns various information about the memory allocators of the + current system (emulator) as specified by Item: -Since: - OTP 18.0,OTP R14B01 + allocated_areas: + Returns a list of tuples with information about miscellaneous + allocated memory areas. - -spec erlang:system_info(atom_count) -> pos_integer(); -  (atom_limit) -> pos_integer(); -  (ets_count) -> pos_integer(); -  (ets_limit) -> pos_integer(); -  (port_count) -> non_neg_integer(); -  (port_limit) -> pos_integer(); -  (process_count) -> pos_integer(); -  (process_limit) -> pos_integer(). + Each tuple contains an atom describing the type of memory as + first element and the amount of allocated memory in bytes as + second element. When information about allocated and used + memory is present, also a third element is present, containing + the amount of used memory in bytes. -Since: - OTP 20.0,OTP 21.1,OTP R16B,OTP R16B03 + erlang:system_info(allocated_areas) is intended for + debugging, and the content is highly implementation-dependent. + The content of the results therefore changes when needed + without prior notice. - -spec erlang:system_info(c_compiler_used) -> {atom(), term()}; -  (check_io) -> [_]; -  (compat_rel) -> integer(); -  (debug_compiled) -> boolean(); -  (driver_version) -> string(); -  (dynamic_trace) -> none | dtrace | systemtap; -  (dynamic_trace_probes) -> boolean(); -  (emu_flavor) -> emu | jit; -  (emu_type) -> -  opt | debug | gcov | valgrind | gprof | -  lcnt | frmptr; -  (info) -> binary(); -  (kernel_poll) -> boolean(); -  (loaded) -> binary(); -  (machine) -> string(); -  (modified_timing_level) -> integer() | undefined; -  (nif_version) -> string(); -  (otp_release) -> string(); -  (port_parallelism) -> boolean(); -  (system_architecture) -> string(); -  (system_logger) -> logger | undefined | pid(); -  (system_version) -> string(); -  (trace_control_word) -> non_neg_integer(); -  (version) -> string(); -  (wordsize | -  {wordsize, internal} | -  {wordsize, external}) -> -  4 | 8. + Notice that the sum of these values is not the total amount + of memory allocated by the emulator. Some values are part of + other values, and some memory areas are not part of the + result. For information about the total amount of memory + allocated by the emulator, see erlang:memory/0,1. -Since: - OTP 17.4,OTP 21.3,OTP 24.0,OTP R15B01,OTP R16B + allocator: + Returns {Allocator, Version, Features, Settings, where: - -spec erlang:system_info(dirty_cpu_schedulers) -> non_neg_integer(); -  (dirty_cpu_schedulers_online) -> -  non_neg_integer(); -  (dirty_io_schedulers) -> non_neg_integer(); -  (multi_scheduling) -> -  disabled | blocked | blocked_normal | -  enabled; -  (multi_scheduling_blockers) -> [Pid :: pid()]; -  (normal_multi_scheduling_blockers) -> -  [Pid :: pid()]; -  (scheduler_bind_type) -> -  spread | processor_spread | thread_spread | -  thread_no_node_processor_spread | -  no_node_processor_spread | -  no_node_thread_spread | no_spread | unbound; -  (scheduler_bindings) -> tuple(); -  (scheduler_id) -> SchedulerId :: pos_integer(); -  (schedulers | schedulers_online) -> -  pos_integer(); -  (smp_support) -> boolean(); -  (threads) -> boolean(); -  (thread_pool_size) -> non_neg_integer(). + • Allocator corresponds to the malloc() implementation + used. If Allocator equals undefined, the malloc() + implementation used cannot be identified. glibc can be + identified. -Since: - OTP 17.0,OTP 19.0 + • Version is a list of integers (but not a string) + representing the version of the malloc() + implementation used. - -spec erlang:system_info(end_time) -> non_neg_integer(); -  (os_monotonic_time_source) -> [{atom(), term()}]; -  (os_system_time_source) -> [{atom(), term()}]; -  (start_time) -> integer(); -  (time_correction) -> true | false; -  (time_offset) -> preliminary | final | volatile; -  (time_warp_mode) -> -  no_time_warp | single_time_warp | -  multi_time_warp; -  (tolerant_timeofday) -> enabled | disabled. + • Features is a list of atoms representing the allocation + features used. -Since: - OTP 17.1,OTP 18.0 + • Settings is a list of subsystems, their configurable + parameters, and used values. Settings can differ between + different combinations of platforms, allocators, and + allocation features. Memory sizes are given in bytes. + + See also "System Flags Effecting erts_alloc" in erts_alloc(3). + + {allocator, Alloc}: + Returns information about the specified allocator. As from + ERTS 5.6.1, the return value is a list of {instance, + InstanceNo, InstanceInfo} tuples, where InstanceInfo + contains information about a specific instance of the + allocator. If Alloc is not a recognized allocator,  + undefined is returned. If Alloc is disabled, false is + returned. + + Notice that the information returned is highly + implementation-dependent and can be changed or removed at any + time without prior notice. It was initially intended as a tool + when developing new allocators, but as it can be of interest + for others it has been briefly documented. - -spec erlang:system_info(version) -> string(). + The recognized allocators are listed in erts_alloc(3). + Information about super carriers can be obtained from ERTS 8.0 + with {allocator, erts_mmap} or from ERTS 5.10.4; the + returned list when calling with {allocator, mseg_alloc} also + includes an {erts_mmap, _} tuple as one element in the list. + + After reading the erts_alloc(3) documentation, the returned + information more or less speaks for itself, but it can be + worth explaining some things. Call counts are presented by two + values, the first value is giga calls, and the second value is + calls. mbcs and sbcs denote multi-block carriers, and + single-block carriers, respectively. Sizes are presented in + bytes. When a size is not presented, it is the amount of + something. Sizes and amounts are often presented by three + values: + + • The first is the current value. + + • The second is the maximum value since the last call to  + erlang:system_info({allocator, Alloc}). + + • The third is the maximum value since the emulator was + started. + + If only one value is present, it is the current value.  + fix_alloc memory block types are presented by two values. The + first value is the memory pool size and the second value is + the used memory size. + + alloc_util_allocators: + Returns a list of the names of all allocators using the ERTS + internal alloc_util framework as atoms. For more + information, see section The alloc_util framework in  + erts_alloc(3). + + {allocator_sizes, Alloc}: + Returns various size information for the specified allocator. + The information returned is a subset of the information + returned by erlang:system_info({allocator, Alloc}). -spec erlang:system_info(cpu_topology) -> CpuTopology  when CpuTopology :: cpu_topology();  ({cpu_topology, defined | detected | used}) ->  CpuTopology  when CpuTopology :: cpu_topology(); -  (logical_processors | -  logical_processors_available | -  logical_processors_online) -> -  unknown | pos_integer(); -  (update_cpu_info) -> changed | unchanged. +  (creation) -> integer(); +  (machine) -> string(); +  (version) -> string(). Since: OTP R14B - -spec erlang:system_info(fullsweep_after) -> -  {fullsweep_after, non_neg_integer()}; -  (garbage_collection) -> [{atom(), integer()}]; + Types: + -type cpu_topology() :: [LevelEntry :: level_entry()] | undefined. + All LevelEntrys of a list must contain the same  + LevelTag, except on the top level where both node and  + processorLevelTags can coexist. + -type info_list() :: []. + The info_list() can be extended in a future release. + -type level_entry() :: + {LevelTag :: level_tag(), SubLevel :: sub_level()} | + {LevelTag :: level_tag(), + InfoList :: info_list(), + SubLevel :: sub_level()}. + {LevelTag, SubLevel} == {LevelTag, [], SubLevel} + -type level_tag() :: core | node | processor | thread. + More LevelTags can be introduced in a future release. + -type sub_level() :: + [LevelEntry :: level_entry()] | + (LogicalCpuId :: {logical, non_neg_integer()}). + + Returns various information about the CPU topology of the current + system (emulator) as specified by Item: + + cpu_topology: + Returns the CpuTopology currently used by the emulator. The + CPU topology is used when binding schedulers to logical + processors. The CPU topology used is the user-defined CPU + topology, if such exists, otherwise the automatically + detected CPU topology, if such exists. If no CPU topology + exists, undefined is returned. + + node refers to Non-Uniform Memory Access (NUMA) nodes.  + thread refers to hardware threads (for example, Intel + hyper-threads). + + A level in term CpuTopology can be omitted if only one entry + exists and InfoList is empty. + + thread can only be a sublevel to core. core can be a + sublevel to processor or node. processor can be on the + top level or a sublevel to node. node can be on the top + level or a sublevel to processor. That is, NUMA nodes can be + processor internal or processor external. A CPU topology can + consist of a mix of processor internal and external NUMA + nodes, as long as each logical CPU belongs to one NUMA node. + Cache hierarchy is not part of the CpuTopology type, but + will be in a future release. Other things can also make it + into the CPU topology in a future release. So, expect the  + CpuTopology type to change. + + {cpu_topology, defined}: + Returns the user-defined CpuTopology. For more information, + see command-line flag +sct in erl(1) and argument  + cpu_topology. + + {cpu_topology, detected}: + Returns the automatically detected CpuTopologyy. The + emulator detects the CPU topology on some newer Linux, + Solaris, FreeBSD, and Windows systems. On Windows system with + more than 32 logical processors, the CPU topology is not + detected. + + For more information, see argument cpu_topology. + + {cpu_topology, used}: + Returns CpuTopology used by the emulator. For more + information, see argument cpu_topology. + + logical_processors: + Returns the detected number of logical processors configured + in the system. The return value is either an integer, or the + atom unknown if the emulator cannot detect the configured + logical processors. + + logical_processors_available: + Returns the detected number of logical processors available to + the Erlang runtime system. The return value is either an + integer, or the atom unknown if the emulator cannot detect + the available logical processors. The number of available + logical processors is less than or equal to the number of + logical processors online. + + logical_processors_online: + Returns the detected number of logical processors online on + the system. The return value is either an integer, or the atom  + unknown if the emulator cannot detect logical processors + online. The number of logical processors online is less than + or equal to the number of logical processors configured. + + cpu_quota: + Returns the detected CPU quota the emulator is limited by. The + return value is an integer saying how many processors' worth + of runtime we get (between 1 and the number of logical + processors), or the atom unknown if the emulator cannot + detect a quota. + + update_cpu_info: + The runtime system rereads the CPU information available and + updates its internally stored information about the detected + CPU topology and the number of logical processors configured, + online, available, and cpu quota. + + If the CPU information has changed since the last time it was + read, the atom changed is returned, otherwise the atom  + unchanged. If the CPU information has changed, you probably + want to adjust the number of schedulers online. You + typically want to have as many schedulers online as logical + processors available. + + -spec erlang:system_info(garbage_collection) -> [{atom(), integer()}];  (heap_sizes) -> [non_neg_integer()];  (heap_type) -> private; -  (max_heap_size) -> -  {max_heap_size, -  MaxHeapSize :: max_heap_size()}; +  (info) -> binary();  (message_queue_data) -> message_queue_data();  (min_heap_size) ->  {min_heap_size, @@ -143,7 +298,12 @@  (min_bin_vheap_size) ->  {min_bin_vheap_size,  MinBinVHeapSize :: pos_integer()}; -  (procs) -> binary(). +  (modified_timing_level) -> integer() | undefined; +  (scheduler_bind_type) -> +  spread | processor_spread | thread_spread | +  thread_no_node_processor_spread | +  no_node_processor_spread | +  no_node_thread_spread | no_spread | unbound. Since: OTP 19.0,OTP R13B04 @@ -154,7 +314,8 @@ non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), - error_logger => boolean()}. + error_logger => boolean(), + include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. Returns information about the default process heap settings: @@ -191,17 +352,18 @@ Returns {max_heap_size, MaxHeapSize}, where MaxHeapSize is the current system-wide maximum heap size settings for spawned processes. This setting can be set using the command-line - flags +hmax, +hmaxk and +hmaxel in erl(1). It can also - be changed at runtime using erlang:system_flag(max_heap_size, - MaxHeapSize). For more details about the max_heap_size - process flag, see process_flag(max_heap_size, MaxHeapSize). + flags +hmax, +hmaxk, +hmaxel and +hmaxibl in erl(1). + It can also be changed at runtime using  + erlang:system_flag(max_heap_size, MaxHeapSize). For more + details about the max_heap_size process flag, see  + process_flag(max_heap_size, MaxHeapSize). message_queue_data: Returns the default value of the message_queue_data process - flag, which is either off_heap or on_heap. This default is - set by command-line argument +hmqd in erl(1). For more - information on the message_queue_data process flag, see - documentation of process_flag(message_queue_data, MQD). + flag, which can be either off_heap or on_heap. The default + value is set by the command-line argument +hmqd in erl(1). + For more information, see the documentation of  + process_flag(message_queue_data, MQD). min_heap_size: Returns {min_heap_size, MinHeapSize}, where MinHeapSize is @@ -218,3 +380,674 @@ information formatted as in Erlang crash dumps. For more information, see section How to interpret the Erlang crash dumps in the User's Guide. + + -spec erlang:system_info(atom_count) -> pos_integer(); +  (atom_limit) -> pos_integer(); +  (ets_limit) -> pos_integer(); +  (fullsweep_after) -> +  {fullsweep_after, non_neg_integer()}; +  (port_count) -> non_neg_integer(); +  (port_limit) -> pos_integer(); +  (process_count) -> pos_integer(); +  (process_limit) -> pos_integer(). + +Since: + OTP 20.0,OTP 21.1,OTP R16B,OTP R16B03 + + Returns information about the current system (emulator) limits as + specified by Item: + + atom_count: + Returns the number of atoms currently existing at the local + node. The value is given as an integer. + + atom_limit: + Returns the maximum number of atoms allowed. This limit can be + increased at startup by passing command-line flag +t to  + erl(1). + + ets_count: + Returns the number of ETS tables currently existing at the + local node. + + ets_limit: + Returns the limit for number of ETS tables. This limit is + partially obsolete and number of tables are only limited by + available memory. + + port_count: + Returns the number of ports currently existing at the local + node. The value is given as an integer. This is the same value + as returned by length(erlang:ports()), but more efficient. + + port_limit: + Returns the maximum number of simultaneously existing ports at + the local node as an integer. This limit can be configured at + startup by using command-line flag +Q in erl(1). + + process_count: + Returns the number of processes currently existing at the + local node. The value is given as an integer. This is the same + value as returned by length(processes()), but more + efficient. + + process_limit: + Returns the maximum number of simultaneously existing + processes at the local node. The value is given as an integer. + This limit can be configured at startup by using command-line + flag +P in erl(1). + + -spec erlang:system_info(ets_count) -> pos_integer(); +  (os_system_time_source) -> [{atom(), term()}]; +  (outstanding_system_requests_limit) -> +  1..134217727; +  (system_architecture) -> string(); +  (time_offset) -> preliminary | final | volatile; +  (time_warp_mode) -> +  no_time_warp | single_time_warp | +  multi_time_warp; +  (tolerant_timeofday) -> enabled | disabled; +  (trace_control_word) -> non_neg_integer(). + +Since: + OTP 17.1,OTP 18.0 + + Returns information about the current system (emulator) time as + specified by Item: + + end_time: + The last Erlang monotonic time in native time unit that + can be represented internally in the current Erlang runtime + system instance. The time between the start time and the end + time is at least a quarter of a millennium. + + os_monotonic_time_source: + Returns a list containing information about the source of OS + monotonic time that is used by the runtime system. + + If [] is returned, no OS monotonic time is available. The + list contains two-tuples with Keys as first element, and  + Values as second element. The order of these tuples is + undefined. The following tuples can be part of the list, but + more tuples can be introduced in the future: + + {function, Function}: + Function is the name of the function used. This tuple + always exists if OS monotonic time is available to the + runtime system. + + {clock_id, ClockId}: + This tuple only exists if Function can be used with + different clocks. ClockId corresponds to the clock + identifier used when calling Function. + + {resolution, OsMonotonicTimeResolution}: + Highest possible resolution of current OS monotonic time + source as parts per second. If no resolution information + can be retrieved from the OS, OsMonotonicTimeResolution + is set to the resolution of the time unit of Functions + return value. That is, the actual resolution can be lower + than OsMonotonicTimeResolution. Notice that the + resolution does not say anything about the accuracy or + whether the precision aligns with the resolution. You + do, however, know that the precision is not better than  + OsMonotonicTimeResolution. + + {extended, Extended}: + Extended equals yes if the range of time values has + been extended; otherwise Extended equals no. The range + must be extended if Function returns values that wrap + fast. This typically is the case when the return value is + a 32-bit value. + + {parallel, Parallel}: + Parallel equals yes if Function is called in parallel + from multiple threads. If it is not called in parallel, + because calls must be serialized, Parallel equals no. + + {time, OsMonotonicTime}: + OsMonotonicTime equals current OS monotonic time in  + native time unit. + + os_system_time_source: + Returns a list containing information about the source of OS + system time that is used by the runtime system. + + The list contains two-tuples with Keys as first element, and  + Values as second element. The order of these tuples is + undefined. The following tuples can be part of the list, but + more tuples can be introduced in the future: + + {function, Function}: + Function is the name of the function used. + + {clock_id, ClockId}: + Exists only if Function can be used with different + clocks. ClockId corresponds to the clock identifier used + when calling Function. + + {resolution, OsSystemTimeResolution}: + Highest possible resolution of current OS system time + source as parts per second. If no resolution information + can be retrieved from the OS, OsSystemTimeResolution is + set to the resolution of the time unit of Functions + return value. That is, the actual resolution can be lower + than OsSystemTimeResolution. Notice that the resolution + does not say anything about the accuracy or whether the + precision do align with the resolution. You do, however, + know that the precision is not better than  + OsSystemTimeResolution. + + {parallel, Parallel}: + Parallel equals yes if Function is called in parallel + from multiple threads. If it is not called in parallel, + because calls needs to be serialized, Parallel equals  + no. + + {time, OsSystemTime}: + OsSystemTime equals current OS system time in native + time unit. + + start_time: + The Erlang monotonic time in native time unit at the + time when current Erlang runtime system instance started. + + See also erlang:system_info(end_time). + + time_correction: + Returns a boolean value indicating whether time correction + is enabled or not. + + time_offset: + Returns the state of the time offset: + + preliminary: + The time offset is preliminary, and will be changed and + finalized later. The preliminary time offset is used + during the preliminary phase of the single time warp mode. + + final: + The time offset is final. This either because no time + warp mode is used, or because the time offset have been + finalized when single time warp mode is used. + + volatile: + The time offset is volatile. That is, it can change at any + time. This is because multi-time warp mode is used. + + time_warp_mode: + Returns a value identifying the time warp mode that is used: + + no_time_warp: + The no time warp mode is used. + + single_time_warp: + The single time warp mode is used. + + multi_time_warp: + The multi-time warp mode is used. + + tolerant_timeofday: + Returns whether a pre ERTS 7.0 backwards compatible + compensation for sudden changes of system time is enabled or  + disabled. Such compensation is enabled when the time + offset is final, and time correction is enabled. + + -spec erlang:system_info(dirty_cpu_schedulers_online) -> +  non_neg_integer(); +  (dirty_io_schedulers) -> non_neg_integer(); +  (dist) -> binary(); +  (multi_scheduling_blockers) -> [Pid :: pid()]; +  (nif_version) -> string(); +  (otp_release) -> string(); +  (scheduler_bindings) -> tuple(); +  (scheduler_id) -> SchedulerId :: pos_integer(); +  (schedulers | schedulers_online) -> +  pos_integer(); +  (smp_support) -> boolean(); +  (start_time) -> integer(); +  (thread_pool_size) -> non_neg_integer(); +  (time_correction) -> true | false. + +Since: + OTP 17.0,OTP 19.0 + + Returns information about schedulers, scheduling and threads in + the current system as specified by Item: + + dirty_cpu_schedulers: + Returns the number of dirty CPU scheduler threads used by the + emulator. Dirty CPU schedulers execute CPU-bound native + functions, such as NIFs, linked-in driver code, and BIFs that + cannot be managed cleanly by the normal emulator schedulers. + + The number of dirty CPU scheduler threads is determined at + emulator boot time and cannot be changed after that. However, + the number of dirty CPU scheduler threads online can be + changed at any time. The number of dirty CPU schedulers can be + set at startup by passing command-line flag +SDcpu or  + +SDPcpu in erl(1). + + See also erlang:system_flag(dirty_cpu_schedulers_online, + DirtyCPUSchedulersOnline),  + erlang:system_info(dirty_cpu_schedulers_online),  + erlang:system_info(dirty_io_schedulers),  + erlang:system_info(schedulers),  + erlang:system_info(schedulers_online), and  + erlang:system_flag(schedulers_online, SchedulersOnline). + + dirty_cpu_schedulers_online: + Returns the number of dirty CPU schedulers online. The return + value satisfies 1 <= DirtyCPUSchedulersOnline <= N, where N + is the smallest of the return values of  + erlang:system_info(dirty_cpu_schedulers) and  + erlang:system_info(schedulers_online). + + The number of dirty CPU schedulers online can be set at + startup by passing command-line flag +SDcpu in erl(1). + + For more information, see  + erlang:system_info(dirty_cpu_schedulers),  + erlang:system_info(dirty_io_schedulers),  + erlang:system_info(schedulers_online), and  + erlang:system_flag(dirty_cpu_schedulers_online, + DirtyCPUSchedulersOnline). + + dirty_io_schedulers: + Returns the number of dirty I/O schedulers as an integer. + Dirty I/O schedulers execute I/O-bound native functions, such + as NIFs and linked-in driver code, which cannot be managed + cleanly by the normal emulator schedulers. + + This value can be set at startup by passing command-line + argument +SDio in erl(1). + + For more information, see  + erlang:system_info(dirty_cpu_schedulers),  + erlang:system_info(dirty_cpu_schedulers_online), and  + erlang:system_flag(dirty_cpu_schedulers_online, + DirtyCPUSchedulersOnline). + + multi_scheduling: + Returns one of the following: + + disabled: + The emulator has been started with only one scheduler + thread. + + blocked: + The emulator has more than one scheduler thread, but all + scheduler threads except one are blocked. That is, only + one scheduler thread schedules Erlang processes and + executes Erlang code. + + blocked_normal: + The emulator has more than one scheduler thread, but all + normal scheduler threads except one are blocked. Notice + that dirty schedulers are not blocked, and can schedule + Erlang processes and execute native code. + + enabled: + The emulator has more than one scheduler thread, and no + scheduler threads are blocked. That is, all available + scheduler threads schedule Erlang processes and execute + Erlang code. + + See also erlang:system_flag(multi_scheduling, BlockState),  + erlang:system_info(multi_scheduling_blockers),  + erlang:system_info(normal_multi_scheduling_blockers), and  + erlang:system_info(schedulers). + + multi_scheduling_blockers: + Returns a list of Pids when multi-scheduling is blocked, + otherwise the empty list is returned. The Pids in the list + represent all the processes currently blocking + multi-scheduling. A Pid occurs only once in the list, even + if the corresponding process has blocked multiple times. + + See also erlang:system_flag(multi_scheduling, BlockState),  + erlang:system_info(multi_scheduling),  + erlang:system_info(normal_multi_scheduling_blockers), and  + erlang:system_info(schedulers). + + normal_multi_scheduling_blockers: + Returns a list of Pids when normal multi-scheduling is + blocked (that is, all normal schedulers but one is blocked), + otherwise the empty list is returned. The Pids in the list + represent all the processes currently blocking normal + multi-scheduling. A Pid occurs only once in the list, even + if the corresponding process has blocked multiple times. + + See also erlang:system_flag(multi_scheduling, BlockState),  + erlang:system_info(multi_scheduling),  + erlang:system_info(multi_scheduling_blockers), and  + erlang:system_info(schedulers). + + scheduler_bind_type: + Returns information about how the user has requested + schedulers to be bound or not bound. + + Notice that although a user has requested schedulers to be + bound, they can silently have failed to bind. To inspect the + scheduler bindings, call  + erlang:system_info(scheduler_bindings). + + For more information, see command-line argument +sbt in  + erl(1) and erlang:system_info(scheduler_bindings). + + scheduler_bindings: + Returns information about the currently used scheduler + bindings. + + A tuple of a size equal to erlang:system_info(schedulers) is + returned. The tuple elements are integers or the atom unbound. + Logical processor identifiers are represented as integers. The  + Nth element of the tuple equals the current binding for the + scheduler with the scheduler identifier equal to N. For + example, if the schedulers are bound,  + element(erlang:system_info(scheduler_id), + erlang:system_info(scheduler_bindings)) returns the + identifier of the logical processor that the calling process + is executing on. + + Notice that only schedulers online can be bound to logical + processors. + + For more information, see command-line argument +sbt in  + erl(1) and erlang:system_info(schedulers_online). + + scheduler_id: + Returns the scheduler ID (SchedulerId) of the scheduler + thread that the calling process is executing on. SchedulerId + is a positive integer, where 1 <= SchedulerId <= + erlang:system_info(schedulers). + + See also erlang:system_info(schedulers). + + schedulers: + Returns the number of scheduler threads used by the emulator. + Scheduler threads online schedules Erlang processes and Erlang + ports, and execute Erlang code and Erlang linked-in driver + code. + + The number of scheduler threads is determined at emulator boot + time and cannot be changed later. However, the number of + schedulers online can be changed at any time. + + See also erlang:system_flag(schedulers_online, + SchedulersOnline), erlang:system_info(schedulers_online),  + erlang:system_info(scheduler_id),  + erlang:system_flag(multi_scheduling, BlockState),  + erlang:system_info(multi_scheduling),  + erlang:system_info(normal_multi_scheduling_blockers) and  + erlang:system_info(multi_scheduling_blockers). + + schedulers_online: + Returns the number of schedulers online. The scheduler + identifiers of schedulers online satisfy the relationship 1 + <= SchedulerId <= erlang:system_info(schedulers_online). + + For more information, see erlang:system_info(schedulers) and  + erlang:system_flag(schedulers_online, SchedulersOnline). + + smp_support: + Returns true. + + threads: + Returns true. + + thread_pool_size: + Returns the number of async threads in the async thread pool + used for asynchronous driver calls (  + erl_driver:driver_async()). The value is given as an integer. + + -spec erlang:system_info(debug_compiled) -> boolean(); +  (dirty_cpu_schedulers) -> non_neg_integer(); +  (dist_buf_busy_limit) -> non_neg_integer(); +  (dist_ctrl) -> +  [{Node :: node(), +  ControllingEntity :: port() | pid()}]; +  (driver_version) -> string(); +  (overview) -> boolean(). + +Since: + OTP 18.0,OTP 25.3,OTP R14B01 + + Returns information about Erlang Distribution in the current + system as specified by Item: + + async_dist: + Since: OTP 25.3 + + Returns the value of the command line argument +pad + which the runtime system use. This value determines the + default async_dist value for newly spawned processes. + + creation: + Returns the "creation" value of the local node as an integer. + The creation is changed when a node is restarted. The creation + of a node is stored in process identifiers, port identifiers, + and references. This makes it possible to distinguish between + identifiers from different incarnations of a node. Creation + values are currently 32-bit positive integers, but this may + change in future releases. If the node is not alive, 0 is + returned. + + delayed_node_table_gc: + Returns the amount of time in seconds garbage collection of an + entry in a node table is delayed. This limit can be set on + startup by passing command-line flag +zdntgc to erl(1). + For more information, see the documentation of the + command-line flag. + + dist: + Returns a binary containing a string of distribution + information formatted as in Erlang crash dumps. For more + information, see section How to interpret the Erlang crash + dumps in the User's Guide. + + dist_buf_busy_limit: + Returns the value of the distribution buffer busy limit in + bytes. This limit can be set at startup by passing + command-line flag +zdbbl to erl(1). + + dist_ctrl: + Returns a list of tuples {Node, ControllingEntity}, one + entry for each connected remote node. Node is the node name + and ControllingEntity is the port or process identifier + responsible for the communication to that node. More + specifically, ControllingEntity for nodes connected through + TCP/IP (the normal case) is the socket used in communication + with the specific node. + + -spec erlang:system_info(c_compiler_used) -> {atom(), term()}; +  (check_io) -> [_]; +  (compat_rel) -> integer(); +  (delayed_node_table_gc) -> +  infinity | non_neg_integer(); +  (dynamic_trace) -> none | dtrace | systemtap; +  (dynamic_trace_probes) -> boolean(); +  (eager_check_io) -> boolean(); +  (emu_type) -> +  opt | debug | gcov | valgrind | gprof | +  lcnt | frmptr; +  (end_time) -> non_neg_integer(); +  (kernel_poll) -> boolean(); +  (loaded) -> binary(); +  (logical_processors | +  logical_processors_available | +  logical_processors_online) -> +  unknown | pos_integer(); +  (max_heap_size) -> +  {max_heap_size, +  MaxHeapSize :: max_heap_size()}; +  (multi_scheduling) -> +  disabled | blocked | blocked_normal | +  enabled; +  (normal_multi_scheduling_blockers) -> +  [Pid :: pid()]; +  (os_monotonic_time_source) -> [{atom(), term()}]; +  (port_parallelism) -> boolean(); +  (port_count) -> non_neg_integer(); +  (system_logger) -> logger | undefined | pid(); +  (system_version) -> string(); +  (threads) -> boolean(); +  (update_cpu_info) -> changed | unchanged; +  (wordsize | +  {wordsize, internal} | +  {wordsize, external}) -> +  4 | 8; +  (async_dist) -> boolean(). + +Since: + OTP 17.4,OTP 21.3,OTP 24.0,OTP 24.2,OTP R15B01,OTP R16B + + Returns various information about the current system (emulator) as + specified by Item: + + build_type: + Deprecated, use emu_type instead + + c_compiler_used: + Returns a two-tuple describing the C compiler used when + compiling the runtime system. The first element is an atom + describing the name of the compiler, or undefined if + unknown. The second element is a term describing the version + of the compiler, or undefined if unknown. + + check_io: + Returns a list containing miscellaneous information about the + emulators internal I/O checking. Notice that the content of + the returned list can vary between platforms and over time. It + is only guaranteed that a list is returned. + + compat_rel: + Returns the compatibility mode of the local node as an + integer. The integer returned represents the Erlang/OTP + release that the current emulator has been set to be backward + compatible with. The compatibility mode can be configured at + startup by using command-line flag +R in erl(1). + + debug_compiled: + Returns true if the emulator has been debug-compiled, + otherwise false. + + driver_version: + Returns a string containing the Erlang driver version used by + the runtime system. It has the form ".". + + dynamic_trace: + Returns an atom describing the dynamic trace framework + compiled into the virtual machine. It can be dtrace,  + systemtap, or none. For a commercial or standard build, it + is always none. The other return values indicate a custom + configuration (for example, ./configure + --with-dynamic-trace=dtrace). For more information about + dynamic tracing, see dyntrace(3) manual page and the  + README.dtrace/README.systemtap files in the Erlang source + code top directory. + + dynamic_trace_probes: + Returns a boolean() indicating if dynamic trace probes ( + dtrace or systemtap) are built into the emulator. This can + only be true if the virtual machine was built for dynamic + tracing (that is, system_info(dynamic_trace) returns dtrace + or systemtap). + + emu_flavor: + Returns an atom describing the flavor of the runtime system. + This will be either emu or jit. Possible return values can + be added or removed at any time without prior notice. + + emu_type: + Returns an atom describing the build type of the runtime + system. This is normally the atom opt for optimized. Other + possible return values are debug, gcov, valgrind, gprof, + and lcnt. Possible return values can be added or removed at + any time without prior notice. + + info: + Returns a binary containing a string of miscellaneous system + information formatted as in Erlang crash dumps. For more + information, see section How to interpret the Erlang crash + dumps in the User's Guide. + + kernel_poll: + Returns true if the emulator uses some kind of kernel-poll + implementation, otherwise false. + + loaded: + Returns a binary containing a string of loaded module + information formatted as in Erlang crash dumps. For more + information, see section How to interpret the Erlang crash + dumps in the User's Guide. + + machine: + Returns a string containing the Erlang machine name. + + modified_timing_level: + Returns the modified timing-level (an integer) if modified + timing is enabled, otherwise undefined. For more information + about modified timing, see command-line flag +T in erl(1) + + nif_version: + Returns a string containing the version of the Erlang NIF + interface used by the runtime system. It is on the form + ".". + + otp_release: + Returns a string containing the OTP release number of the OTP + release that the currently executing ERTS application is part + of. + + As from Erlang/OTP 17, the OTP release number corresponds to + the major OTP version number. No erlang:system_info() + argument gives the exact OTP version. This is because the + exact OTP version in the general case is difficult to + determine. For more information, see the description of + versions in System principles in System Documentation. + + outstanding_system_requests_limit: + Returns the limit on the amount of outstanding requests made + by a system process orchestrating system wide changes. See  + erlang:system_flag(outstanding_system_requests_limit, Limit) + for more information. + + port_parallelism: + Returns the default port parallelism scheduling hint used. For + more information, see command-line argument +spp in erl(1). + + system_architecture: + Returns a string containing the processor and OS architecture + the emulator is built for. + + system_logger: + Returns the current system_logger as set by  + erlang:system_flag(system_logger, _). + + system_version: + Returns a string containing version number and some important + properties, such as the number of schedulers. + + trace_control_word: + Returns the value of the node trace control word. For more + information, see function get_tcw in section Match + Specifications in Erlang in the User's Guide. + + version: + Returns a string containing the version number of the + emulator. + + wordsize: + Same as {wordsize, internal}. + + {wordsize, internal}: + Returns the size of Erlang term words in bytes as an integer, + that is, 4 is returned on a 32-bit architecture, and 8 is + returned on a 64-bit architecture. + + {wordsize, external}: + Returns the true word size of the emulator, that is, the size + of a pointer. The value is given in bytes as an integer. On a + pure 32-bit architecture, 4 is returned. On a 64-bit + architecture, 8 is returned. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_0_type.txt new file mode 100644 index 000000000000..275c5aa8c334 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_0_type.txt @@ -0,0 +1,4 @@ + + -type term() :: any(). + + All possible Erlang terms. Synonym for any(). diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_binary_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_binary_2_func.txt index 5c2cc9e708de..4730f4ebe24c 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_binary_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_binary_2_func.txt @@ -5,60 +5,146 @@  Options ::  [compressed |  {compressed, Level :: 0..9} | -  {minor_version, Version :: 0..2}]. +  deterministic | +  {minor_version, Version :: 0..2} | +  local]. Returns a binary data object that is the result of encoding Term according to the Erlang external term format. - If option compressed is provided, the external term format is - compressed. The compressed format is automatically recognized by  - binary_to_term/1 as from Erlang/OTP R7B. + Currently supported options: - A compression level can be specified by giving option  - {compressed, Level}. Level is an integer with range 0..9, - where: + compressed: + Compress the external term format. The compressed format is + automatically recognized by binary_to_term/1 as from + Erlang/OTP R7B. - • 0 - No compression is done (it is the same as giving no  - compressed option). + {compressed, Level}: + Compress the external term format to a given level. The + compression level is specified by Level which is an integer + in the range 0..9, where: - • 1 - Takes least time but may not compress as well as the - higher levels. + 0: + No compression is done (it is the same as giving no  + compressed option). - • 6 - Default level when option compressed is provided. + 1: + Takes least time but may not compress as well as the + higher levels. - • 9 - Takes most time and tries to produce a smaller result. - Notice "tries" in the preceding sentence; depending on the - input term, level 9 compression either does or does not - produce a smaller result than level 1 compression. + 6: + Default level when option compressed is provided. - Option {minor_version, Version} can be used to control some - encoding details. This option was introduced in Erlang/OTP R11B-4. - The valid values for Version are: + 9: + Takes most time and tries to produce a smaller result. + Notice "tries" in the preceding sentence; depending on the + input term, level 9 compression either does or does not + produce a smaller result than level 1 compression. - 0: - Floats are encoded using a textual representation. This option - is useful to ensure that releases before Erlang/OTP R11B-4 can - decode resulting binary. + {minor_version, Version}: (since R11B-4) + The option can be used to control some encoding details. Valid + values for Version are: - This version encode atoms that can be represented by a latin1 - string using latin1 encoding while only atoms that cannot be - represented by latin1 are encoded using utf8. + 0: + Floats are encoded using a textual representation. - 1: - This is as of Erlang/OTP 17.0 the default. It forces any - floats in the term to be encoded in a more space-efficient and - exact way (namely in the 64-bit IEEE format, rather than - converted to a textual representation). As from Erlang/OTP - R11B-4, binary_to_term/1 can decode this representation. + Atoms that can be represented by a latin1 string are + encoded using latin1 while only atoms that cannot be + represented by latin1 are encoded using utf8. - This version encode atoms that can be represented by a latin1 - string using latin1 encoding while only atoms that cannot be - represented by latin1 are encoded using utf8. + 1: + Floats are encoded in a more space-efficient and exact way + (namely in the 64-bit IEEE format, rather than converted + to a textual representation). As from Erlang/OTP R11B-4,  + binary_to_term/1 can decode this representation. - 2: - Drops usage of the latin1 atom encoding and unconditionally - use utf8 encoding for all atoms. This will be changed to the - default in a future major release of Erlang/OTP. Erlang/OTP - systems as of R16B can decode this representation. + Atoms that can be represented by a latin1 string are + encoded using latin1 while only atoms that cannot be + represented by latin1 are encoded using utf8. + + 2: + This is as of Erlang/OTP 26.0 the default. Atoms are + unconditionally encoded using utf8. Erlang/OTP systems as + of R16B can decode this representation. + + deterministic: (since OTP 24.1) + This option can be used to ensure that, within the same major + release of Erlang/OTP, the same encoded representation is + returned for the same term. There is still no guarantee that + the encoded representation remains the same between major + releases of Erlang/OTP. + + This option cannot be combined with the local option. + + local: (since OTP 26.0) + This option will cause encoding of Term to an alternative + local version of the external term format which when decoded + by the same runtime system instance will produce a term + identical to the encoded term even when the node name and/or + creation of the current runtime system instance have changed + between encoding and decoding. When encoding without the  + local option, local identifiers such as pids, ports and + references will not be the same if node name and/or creation + of the current runtime system instance changed between + encoding and decoding. This since such identifiers refer to a + specific node by node name and creation. + + Node name and creation of a runtime system instance change + when the distribution is started or stopped. The distribution + is started when the runtime system is started using the -name + or -sname command line arguments. Note that the actual start + of the distribution happens after other code in the startup + phase has begun executing. The distribution can also be + started by calling net_kernel:start/2 and stopped by calling  + net_kernel:stop/1 if it has not been started via the command + line. + + The decoding of a term encoded with the local option, using + for example binary_to_term(), will try to verify that the + term actually was encoded by the same runtime system instance, + and will in the vast majority of cases fail if the encoding + was performed by another runtime system instance. You should + however not trust that this verification will work in all + cases. You should make sure to only decode terms encoded + with the local option on the same Erlang runtime system + instance as the one that encoded the terms. + + Since it is only the runtime system that encoded a term using + the local option that can decode it, the local encoding is + typically pieced together with something else to produce a + reply to where the local encoding originates from. If a term + encoded using the local option is stripped of its leading + version number, it can be added as part of a larger term (for + example as an element in a tuple) when encoding on the + external term format using, for example, ei. In the ei + case, you would strip it of the version number using  + ei_decode_version() and then add the remaining local encoding + to what you are encoding using for example ei_x_append_buf(). + + A good example of when you want to use the local option, is + when you want to make a request from a process to a port + driver and utilize the selective receive optimization when + receiving the reply. In this scenario you want to create a + reference, serialize the reference on the external term format + using the local option, pass this to the driver in the + request, and then wait for the reply message in a selective + receive matching on the reference. The driver should send the + reply using either erl_drv_output_term() or  + erl_drv_send_term() using the term type ERL_DRV_EXT2TERM + for the, in the request, previously received reference on the + external term format. Note that you should not strip the + leading version number from the local encoding when using the + term type ERL_DRV_EXT2TERM of this functionality. If you in + this example do not encode the reference using the local + option, and the distribution is started or stopped while the + request is ongoing, the process that made the request will + hang indefinitely since the reference in the reply message + will never match. + + This option cannot be combined with the deterministic + option. + + For more information see the LOCAL_EXT tag in the + documentation of the external term format. See also binary_to_term/1. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_iovec_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_iovec_2_func.txt index 176c8eef0969..f10eda5c1e7d 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_iovec_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_term_to_iovec_2_func.txt @@ -5,7 +5,9 @@  Options ::  [compressed |  {compressed, Level :: 0..9} | -  {minor_version, Version :: 0..2}]. +  deterministic | +  {minor_version, Version :: 0..2} | +  local]. Since: OTP 23.0 diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_timeout_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_timeout_0_type.txt new file mode 100644 index 000000000000..df22bfd787a0 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_timeout_0_type.txt @@ -0,0 +1,4 @@ + + -type timeout() :: infinity | non_neg_integer(). + + A timeout value that can be passed to a receive expression. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tl_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tl_1_func.txt index 703e6e9578f6..f18c28c9c8e5 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tl_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tl_1_func.txt @@ -1,8 +1,13 @@ - -spec tl(List) -> term() when List :: nonempty_maybe_improper_list(). + -spec tl(List) -> Tail +  when List :: nonempty_maybe_improper_list(), Tail :: term(). Returns the tail of List, that is, the list minus the first - element, for example: + element + + It works with improper lists. + + Examples: > tl([geesties, guilies, beasties]). [guilies, beasties] @@ -18,4 +23,4 @@ Allowed in guard tests. - Failure: badarg if List is the empty list []. + Failure: badarg if List is an empty list []. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_3_func.txt index 1712d8dca3c9..46b04a1c4a95 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_3_func.txt @@ -328,9 +328,6 @@ {trace, PidPort, getting_unlinked, Pid2}: When PidPort gets unlinked from a process Pid2. - {trace, Pid, exit, Reason}: - When Pid exits with reason Reason. - {trace, Port, open, Pid, Driver}: When Pid opens a new port Port with the running Driver. @@ -412,6 +409,12 @@ The total size of binaries allowed in the virtual old heap in the process before doing a garbage collection. + wordsize: + For the gc_minor_start event it is the size of the need + that triggered the GC. For the corresponding gc_minor_end + event it is the size of reclaimed memory = start  + heap_size - end heap_size. + All sizes are in words. {trace, Pid, gc_max_heap_size, Info}: diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_info_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_info_2_func.txt index eb15ee678713..0cc4bcadf483 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_info_2_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_info_2_func.txt @@ -13,7 +13,8 @@  Item ::  flags | tracer | traced |  match_spec | meta | meta_match_spec | -  call_count | call_time | all, +  call_count | call_time | +  call_memory | all,  Res :: trace_info_return(). Types: @@ -31,7 +32,7 @@ {meta, module(), term()} | {meta_match_spec, trace_match_spec() | false | undefined} | {call_count, non_neg_integer() | boolean() | undefined} | - {call_time, + {call_time | call_memory, [{pid(), non_neg_integer(), non_neg_integer(), @@ -63,7 +64,7 @@ flags: Returns a list of atoms indicating what kind of traces is enabled for the process. The list is empty if no traces are - enabled, and one or more of the followings atoms if traces are + enabled, and one or more of the following atoms if traces are enabled: send, 'receive', set_on_spawn, call,  return_to, procs, ports, set_on_first_spawn,  set_on_link, running, running_procs, running_ports,  @@ -125,6 +126,19 @@ See also erlang:trace_pattern/3. + call_memory: + Returns the accumulated number of words allocated by this + function. Accumulation stops at the next memory traced + function: if there are outer, middle and inner functions + each allocating 3 words, but only outer is traced, it will + report 9 allocated words. If outer and inner are traced, 6 + words are reported for outer and 3 for inner. When + function is not traced, false is returned. Returned tuple is  + [{Pid, Count, Words}], for each process that executed the + function. + + See also erlang:trace_pattern/3. + all: Returns a list containing the {Item, Value} tuples for all other items, or returns false if no tracing is active for diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_pattern_3_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_pattern_3_func.txt index 058a61129d90..ad3ce0273d47 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_pattern_3_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_trace_pattern_3_func.txt @@ -1,6 +1,5 @@ - -spec erlang:trace_pattern('receive', MatchSpec, []) -> -  non_neg_integer() + -spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer()  when  MatchSpec ::  (MatchSpecList :: @@ -10,7 +9,83 @@ Since: OTP 19.0 - -spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer() + Types: + -type match_variable() :: atom(). + Approximation of '$1' | '$2' | '$3' | ... + -type trace_match_spec() :: + [{[term()] | '_' | match_variable(), [term()], [term()]}]. + + Sets trace pattern for message sending. Must be combined with  + erlang:trace/3 to set the send trace flag for one or more + processes. By default all messages sent from send traced + processes are traced. To limit traced send events based on the + message content, the sender and/or the receiver, use  + erlang:trace_pattern/3. + + Argument MatchSpec can take the following forms: + + MatchSpecList: + A list of match specifications. The matching is done on the + list [Receiver, Msg]. Receiver is the process or port + identity of the receiver and Msg is the message term. The + pid of the sending process can be accessed with the guard + function self/0. An empty list is the same as true. For + more information, see section Match Specifications in Erlang + in the User's Guide. + + true: + Enables tracing for all sent messages (from send traced + processes). Any match specification is removed. This is the + default. + + false: + Disables tracing for all sent messages. Any match + specification is removed. + + Argument FlagList must be [] for send tracing. + + The return value is always 1. + + Examples: + + Only trace messages to a specific process Pid: + + > erlang:trace_pattern(send, [{[Pid, '_'],[],[]}], []). + 1 + + Only trace messages matching {reply, _}: + + > erlang:trace_pattern(send, [{['_', {reply,'_'}],[],[]}], []). + 1 + + Only trace messages sent to the sender itself: + + > erlang:trace_pattern(send, [{['$1', '_'],[{'=:=','$1',{self}}],[]}], []). + 1 + + Only trace messages sent to other nodes: + + > erlang:trace_pattern(send, [{['$1', '_'],[{'=/=',{node,'$1'},{node}}],[]}], []). + 1 + + Note: + A match specification for send trace can use all guard and + body functions except caller. + + Fails by raising an error exception with an error reason of: + + badarg: + If an argument is invalid. + + system_limit: + If a match specification passed as argument has excessive + nesting which causes scheduler stack exhaustion for the + scheduler that the calling process is executing on. Scheduler + stack size can be configured when starting the runtime + system. + + -spec erlang:trace_pattern('receive', MatchSpec, []) -> +  non_neg_integer()  when  MatchSpec ::  (MatchSpecList :: @@ -20,6 +95,80 @@ Since: OTP 19.0 + Types: + -type match_variable() :: atom(). + Approximation of '$1' | '$2' | '$3' | ... + -type trace_match_spec() :: + [{[term()] | '_' | match_variable(), [term()], [term()]}]. + + Sets trace pattern for message receiving. Must be combined with  + erlang:trace/3 to set the 'receive' trace flag for one or more + processes. By default all messages received by 'receive' traced + processes are traced. To limit traced receive events based on the + message content, the sender and/or the receiver, use  + erlang:trace_pattern/3. + + Argument MatchSpec can take the following forms: + + MatchSpecList: + A list of match specifications. The matching is done on the + list [Node, Sender, Msg]. Node is the node name of the + sender. Sender is the process or port identity of the + sender, or the atom undefined if the sender is not known + (which can be the case for remote senders). Msg is the + message term. The pid of the receiving process can be accessed + with the guard function self/0. An empty list is the same as  + true. For more information, see section Match Specifications + in Erlang in the User's Guide. + + true: + Enables tracing for all received messages (to 'receive' + traced processes). Any match specification is removed. This + is the default. + + false: + Disables tracing for all received messages. Any match + specification is removed. + + Argument FlagList must be [] for receive tracing. + + The return value is always 1. + + Examples: + + Only trace messages from a specific process Pid: + + > erlang:trace_pattern('receive', [{['_',Pid, '_'],[],[]}], []). + 1 + + Only trace messages matching {reply, _}: + + > erlang:trace_pattern('receive', [{['_','_', {reply,'_'}],[],[]}], []). + 1 + + Only trace messages from other nodes: + + > erlang:trace_pattern('receive', [{['$1', '_', '_'],[{'=/=','$1',{node}}],[]}], []). + 1 + + Note: + A match specification for 'receive' trace can use all guard + and body functions except caller, is_seq_trace,  + get_seq_token, set_seq_token, enable_trace,  + disable_trace, trace, silent, and process_dump. + + Fails by raising an error exception with an error reason of: + + badarg: + If an argument is invalid. + + system_limit: + If a match specification passed as argument has excessive + nesting which causes scheduler stack exhaustion for the + scheduler that the calling process is executing on. Scheduler + stack size can be configured when starting the runtime + system. + -spec erlang:trace_pattern(MFA, MatchSpec, FlagList) ->  non_neg_integer()  when @@ -40,7 +189,7 @@ global | local | meta | {meta, Pid :: pid()} | {meta, TracerModule :: module(), TracerState :: term()} | - call_count | call_time. + call_count | call_time | call_memory. -type trace_pattern_mfa() :: {atom(), atom(), arity() | '_'} | on_load. Enables or disables call tracing for one or more functions. Must @@ -103,14 +252,14 @@ Match Specifications in Erlang in the User's Guide. restart: - For the FlagList options call_count and call_time: - restarts the existing counters. The behavior is undefined for - other FlagList options. + For the FlagList options call_count, call_time and  + call_memory: restarts the existing counters. The behavior is + undefined for other FlagList options. pause: - For the FlagList options call_count and call_time: - pauses the existing counters. The behavior is undefined for - other FlagList options. + For the FlagList options call_count, call_time and  + call_memory: pauses the existing counters. The behavior is + undefined for other FlagList options. Parameter FlagList is a list of options. The following are the valid options: @@ -170,6 +319,17 @@ To read the counter value, use erlang:trace_info/2. + call_memory: + Starts (MatchSpec == true) or stops (MatchSpec == false) + call memory tracing for all types of function calls. + + If call memory tracing is started while already running, + counters and allocations restart from zero. To pause running + counters, use MatchSpec == pause. Paused and running + counters can be restarted from zero with MatchSpec == restart. + + To read the counter value, use erlang:trace_info/2. + The options global and local are mutually exclusive, and  global is the default (if no options are specified). The options  call_count and meta perform a kind of local tracing, and cannot diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tuple_0_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tuple_0_type.txt new file mode 100644 index 000000000000..c077d1d4badd --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_tuple_0_type.txt @@ -0,0 +1,4 @@ + + -type tuple() :: tuple(). + + An Erlang tuple. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_type.txt index 89aa1c4acce7..59132eb9259e 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_type.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_type.txt @@ -2,6 +2,100 @@ These types are documented in this module: + -type any() :: any(). + + -type arity() :: arity(). + + -type atom() :: atom(). + + -type binary() :: <<_:_*8>>. + + -type bitstring() :: <<_:_*1>>. + + -type boolean() :: true | false. + + -type byte() :: 0..255. + + -type char() :: 0..1114111. + + -type float() :: float(). + + -type function() :: fun(). + + -type identifier() :: pid() | port() | reference(). + + -type integer() :: integer(). + + -type iodata() :: iolist() | binary(). + + -type iolist() :: +  maybe_improper_list(byte() | binary() | iolist(), +  binary() | []). + + -type list() :: [any()]. + + -type list(ContentType) :: [ContentType]. + + -type map() :: #{any() => any()}. + + -type maybe_improper_list() :: maybe_improper_list(any(), any()). + + -type maybe_improper_list(ContentType, TerminationType) :: +  maybe_improper_list(ContentType, TerminationType). + + -type mfa() :: {module(), atom(), arity()}. + + -type module() :: atom(). + + -type neg_integer() :: neg_integer(). + + -type nil() :: []. + + -type no_return() :: none(). + + -type node() :: atom(). + + -type non_neg_integer() :: non_neg_integer(). + + -type none() :: none(). + + -type nonempty_binary() :: <<_:8, _:_*8>>. + + -type nonempty_bitstring() :: <<_:1, _:_*1>>. + + -type nonempty_improper_list(ContentType, TerminationType) :: +  nonempty_improper_list(ContentType, TerminationType). + + -type nonempty_list() :: [any(), ...]. + + -type nonempty_list(ContentType) :: [ContentType, ...]. + + -type nonempty_maybe_improper_list() :: +  nonempty_maybe_improper_list(any(), any()). + + -type nonempty_maybe_improper_list(ContentType, TerminationType) :: +  nonempty_maybe_improper_list(ContentType, TerminationType). + + -type nonempty_string() :: [char(), ...]. + + -type number() :: integer() | float(). + + -type pid() :: pid(). + + -type port() :: port(). + + -type pos_integer() :: pos_integer(). + + -type reference() :: reference(). + + -type string() :: [char()]. + + -type term() :: any(). + + -type timeout() :: infinity | non_neg_integer(). + + -type tuple() :: tuple(). + -type ext_binary() :: binary(). -type ext_iovec() :: iovec(). @@ -40,7 +134,8 @@ These types are documented in this module:  {min_heap_size, Size :: non_neg_integer()} |  {min_bin_vheap_size, VSize :: non_neg_integer()} |  {max_heap_size, Size :: max_heap_size()} | -  {message_queue_data, MQD :: message_queue_data()}. +  {message_queue_data, MQD :: message_queue_data()} | +  {async_dist, Enabled :: boolean()}. -type priority_level() :: low | normal | high | max. @@ -49,6 +144,28 @@ These types are documented in this module:  non_neg_integer() |  #{size => non_neg_integer(),  kill => boolean(), -  error_logger => boolean()}. +  error_logger => boolean(), +  include_shared_binaries => boolean()}. -type message_queue_data() :: off_heap | on_heap. + + -type stacktrace_extrainfo() :: +  {line, pos_integer()} | +  {file, unicode:chardata()} | +  {error_info, +  #{module => module(), function => atom(), cause => term()}} | +  {atom(), term()}. + + -type stacktrace() :: +  [{module(), +  atom(), +  arity() | [term()], +  [stacktrace_extrainfo()]} | +  {function(), arity() | [term()], [stacktrace_extrainfo()]}]. + + -type send_destination() :: +  pid() | +  reference() | +  port() | +  (RegName :: atom()) | +  {RegName :: atom(), Node :: node()}. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unalias_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unalias_1_func.txt index d4e54f415653..308c28a1e496 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unalias_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unalias_1_func.txt @@ -2,7 +2,7 @@ -spec unalias(Alias) -> boolean() when Alias :: reference(). Since: - OTP @OTP-16718@ + OTP 24.0 Deactivate the alias Alias previously created by the calling process. An alias can for example be created via alias/0, or  @@ -11,3 +11,6 @@ Returns true if Alias was a currently active alias for current processes; otherwise, false. + + For more information on process aliases see the Process Aliases + section of the Erlang Reference Manual. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_universaltime_to_posixtime_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_universaltime_to_posixtime_1_func.txt new file mode 100644 index 000000000000..a7498761494c --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_universaltime_to_posixtime_1_func.txt @@ -0,0 +1,6 @@ + +  universaltime_to_posixtime/1 + + The documentation for universaltime_to_posixtime/1 is hidden. + This probably means that it is internal and not to be used by + other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unlink_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unlink_1_func.txt index 23fecba59cbb..0e9b8253e033 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unlink_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unlink_1_func.txt @@ -1,23 +1,31 @@ -spec unlink(Id) -> true when Id :: pid() | port(). - Removes the link, if there is one, between the calling process and - the process or port referred to by Id. + Removes a link between the calling process and another process or + a port identified by Id. We will from here on call the + identified process or port unlinkee. - Returns true and does not fail, even if there is no link to Id, - or if Id does not exist. + A link can be set up using the link/1 BIF. For more information + on links and exit signals due to links, see the Processes + chapter in the Erlang Reference Manual: - Once unlink(Id) has returned, it is guaranteed that the link - between the caller and the entity referred to by Id has no - effect on the caller in the future (unless the link is setup - again). If the caller is trapping exits, an {'EXIT', Id, _} - message from the link can have been placed in the caller's message - queue before the call. + • Links + + • Sending Exit Signals + + • Receiving Exit Signals - Notice that the {'EXIT', Id, _} message can be the result of the - link, but can also be the result of Id calling exit/2. - Therefore, it can be appropriate to clean up the message queue - when trapping exits after the call to unlink(Id), as follows: + Once unlink(Id) has returned, it is guaranteed that the link + between the caller and the unlinkee has no effect on the caller in + the future (unless the link is setup again). Note that if the + caller is trapping exits, an {'EXIT', Id, ExitReason} message + due to the link may have been placed in the message queue of the + caller before the unlink(Id) call completed. Also note that the  + {'EXIT', Id, ExitReason} message may be the result of the link, + but may also be the result of the unlikee sending the caller an + exit signal by calling the exit/2 BIF. Therefore, it may or may + not be appropriate to clean up the message queue after a call to  + unlink(Id) as follows, when trapping exits: unlink(Id), receive @@ -27,13 +35,15 @@ true end + The link removal is performed asynchronously. If such a link does + not exist, nothing is done. A detailed description of the link + protocol can be found in the Distribution Protocol chapter of + the ERTS User's Guide. + Note: - Before Erlang/OTP R11B (ERTS 5.5) unlink/1 behaved - completely asynchronously, that is, the link was active until - the "unlink signal" reached the linked entity. This had an - undesirable effect, as you could never know when you were - guaranteed not to be effected by the link. - - The current behavior can be viewed as two combined operations: - asynchronously send an "unlink signal" to the linked entity - and ignore any future results of the link. + For some important information about distributed signals, see + the Blocking Signaling Over Distribution section in the + Processes chapter of the Erlang Reference Manual. + + Failure: badarg if Id does not identify a process or a node + local port. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unregister_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unregister_1_func.txt index 4e25c97d02b0..3697bac815e5 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unregister_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_unregister_1_func.txt @@ -1,12 +1,17 @@ -spec unregister(RegName) -> true when RegName :: atom(). - Removes the registered name RegName associated with a process - identifier or a port identifier, for example: + Removes the registered name RegName associated with a process + identifier or a port identifier from the name registry. For + example: > unregister(db). true + Keep in mind that you can still receive signals associated with + the registered name after it has been unregistered as the sender + may have looked up the name before sending to it. + Users are advised not to unregister system processes. Failure: badarg if RegName is not a registered name. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_whereis_1_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_whereis_1_func.txt index 757ec8a7e1f8..6a432f954cf7 100644 --- a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_whereis_1_func.txt +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_whereis_1_func.txt @@ -2,9 +2,9 @@ -spec whereis(RegName) -> pid() | port() | undefined  when RegName :: atom(). - Returns the process identifier or port identifier with the - registered name RegName. Returns undefined if the name is not - registered. Example: + Returns the process identifier or port identifier with the  + registered name RegName from the name registry. Returns  + undefined if the name is not registered. Example: > whereis(db). <0.43.0> diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_xor_2_func.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_xor_2_func.txt new file mode 100644 index 000000000000..3a833a1dfb51 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_erlang_xor_2_func.txt @@ -0,0 +1,5 @@ + +  'xor'/2 + + The documentation for 'xor'/2 is hidden. This probably means + that it is internal and not to be used by other applications. diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE.txt new file mode 100644 index 000000000000..3c3f49196d8f --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE.txt @@ -0,0 +1,4 @@ + + shell_docs_SUITE + + There is no documentation for shell_docs_SUITE diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_cb.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_cb.txt new file mode 100644 index 000000000000..917fb3b6a706 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_cb.txt @@ -0,0 +1,3 @@ + shell_docs_SUITE + +There are no callbacks in this module diff --git a/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_type.txt b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_type.txt new file mode 100644 index 000000000000..ad4b50628086 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/unknown_shell_docs_SUITE_type.txt @@ -0,0 +1,3 @@ + shell_docs_SUITE + +There are no types in this module diff --git a/lib/stdlib/test/shell_docs_SUITE_data/user_drv.docs_v1 b/lib/stdlib/test/shell_docs_SUITE_data/user_drv.docs_v1 new file mode 100644 index 000000000000..d14fa35185c9 --- /dev/null +++ b/lib/stdlib/test/shell_docs_SUITE_data/user_drv.docs_v1 @@ -0,0 +1 @@ +{docs_v1,[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],erlang,<<97,112,112,108,105,99,97,116,105,111,110,47,101,114,108,97,110,103,43,104,116,109,108>>,hidden,#{otp_doc_vsn => {1,0,0}},[{{function,callback_mode,0},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<99,97,108,108,98,97,99,107,95,109,111,100,101,47,48>>],hidden,#{}},{{function,init,1},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<105,110,105,116,47,49>>],hidden,#{}},{{function,init,3},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<105,110,105,116,47,51>>],hidden,#{}},{{function,server,3},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,101,114,118,101,114,47,51>>],hidden,#{}},{{function,start,0},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,116,97,114,116,47,48>>],hidden,#{}},{{function,start,1},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,116,97,114,116,47,49>>],hidden,#{}},{{function,start_shell,0},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,116,97,114,116,95,115,104,101,108,108,47,48>>],hidden,#{}},{{function,start_shell,1},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,116,97,114,116,95,115,104,101,108,108,47,49>>],hidden,#{}},{{function,switch_loop,3},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<115,119,105,116,99,104,95,108,111,111,112,47,51>>],hidden,#{}},{{function,whereis_group,0},[{file,[117,115,101,114,95,100,114,118,46,101,114,108]},{location,0}],[<<119,104,101,114,101,105,115,95,103,114,111,117,112,47,48>>],hidden,#{}}]}. \ No newline at end of file diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl index 7e05723036da..938b6ba3e3bb 100644 --- a/lib/stdlib/test/stdlib_SUITE.erl +++ b/lib/stdlib/test/stdlib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2021. 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. @@ -27,7 +27,7 @@ init_per_testcase/2, end_per_testcase/2, app_test/1, appup_test/1, assert_test/1]). --compile(r21). +-compile(r22). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -46,7 +46,19 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. - +init_per_testcase(appup_test, Config) -> + %% We check if the test results were released using a version + %% of Erlang/OTP that was a tagged version or not. On a non-tagged + %% version this testcase most likely will fail. + case file:read_file( + filename:join( + proplists:get_value(data_dir,Config), "otp_version_tickets")) of + {ok,<<"DEVELOPMENT",_/binary>>} -> + {skip, "This is a development version, test might fail " + "because of incorrect version numbers"}; + {ok,S} -> + Config + end; init_per_testcase(_Case, Config) -> Config. end_per_testcase(_Case, _Config) -> @@ -65,8 +77,6 @@ app_test(Config) when is_list(Config) -> appup_test(_Config) -> appup_tests(stdlib,create_test_vsns(stdlib)). -appup_tests(_App,{[],[]}) -> - {skip,"no previous releases available"}; appup_tests(App,{OkVsns0,NokVsns}) -> application:load(App), {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()), @@ -79,8 +89,7 @@ appup_tests(App,{OkVsns0,NokVsns}) -> OkVsns0 -> OkVsns0; Ok -> - ct:log("Current version, ~p, is same as in previous release.~n" - "Removing this from the list of ok versions.", + ct:log("Removed current version ~p from the list of ok versions to test.", [Vsn]), Ok end, @@ -95,57 +104,46 @@ appup_tests(App,{OkVsns0,NokVsns}) -> ok. create_test_vsns(App) -> - ThisMajor = erlang:system_info(otp_release), - FirstMajor = previous_major(ThisMajor), - SecondMajor = previous_major(previous_major(FirstMajor)), - Ok = app_vsn(App,[ThisMajor,FirstMajor]), - Nok0 = app_vsn(App,[SecondMajor]), + S = otp_vsns:read_state(), + Rel = list_to_integer(erlang:system_info(otp_release)), + AppStr = atom_to_list(App), + Ok = ok_app_vsns(S, Rel, AppStr), + Nok0 = nok_app_vsns(S, Rel, AppStr, hd(Ok)), Nok = case Ok of - [Ok1|_] -> - [Ok1 ++ ",1" | Nok0]; % illegal - _ -> - Nok0 - end, - {Ok,Nok}. - -previous_major("17") -> - "r16b"; -previous_major("r16b") -> - "r15b"; -previous_major(Rel) -> - integer_to_list(list_to_integer(Rel)-1). - -app_vsn(App,[R|Rs]) -> - OldRel = - case test_server:is_release_available(R) of - true -> - {release,R}; - false -> - case ct:get_config({otp_releases,list_to_atom(R)}) of - undefined -> - false; - Prog0 -> - case os:find_executable(Prog0) of - false -> - false; - Prog -> - {prog,Prog} - end - end - end, - case OldRel of - false -> - app_vsn(App,Rs); - _ -> - {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]), - _ = rpc:call(N,application,load,[App]), - As = rpc:call(N,application,loaded_applications,[]), - {_,_,V} = lists:keyfind(App,1,As), - test_server:stop_node(N), - [V|app_vsn(App,Rs)] - end; -app_vsn(_App,[]) -> - []. + [Ok1|_] -> + [Ok1 ++ ",1" | Nok0]; % illegal + _ -> + Nok0 + end, + {Ok, Nok}. + +ok_app_vsns(S, Rel, AppStr) -> + AppVsns0 = get_rel_app_vsns(S, Rel-2, AppStr), + AppVsns1 = get_rel_app_vsns(S, Rel-1, AppStr), + AppVsns2 = try + get_rel_app_vsns(S, Rel, AppStr) + catch + _:_ -> [] + end, + lists:usort(AppVsns2 ++ AppVsns1 ++ AppVsns0). + +nok_app_vsns(S, Rel, AppStr, EarliestOkVsn) -> + AppVsns0 = get_rel_app_vsns(S, Rel-4, AppStr), + AppVsns1 = get_rel_app_vsns(S, Rel-3, AppStr), + %% Earliest OK version may exist in not OK versions + %% as well if there were no application version bump + %% between two releases, so we need to remove it + %% if that is the case... + lists:usort(AppVsns1 ++ AppVsns0) -- EarliestOkVsn. + +get_rel_app_vsns(S, Rel, App) -> + RelStr = integer_to_list(Rel), + OtpVsns = otp_vsns:branch_vsns(S, "maint-"++RelStr), + lists:map(fun (OtpVsn) -> + AppVsn = otp_vsns:app_vsn(S, OtpVsn, App), + [_, Vsn] = string:lexemes(AppVsn, "-"), + Vsn + end, OtpVsns). check_appup([Vsn|Vsns],Instrs,Expected) -> case systools_relup:appup_search_for_version(Vsn, Instrs) of diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl index 81764a59130e..4ccbdb9b57da 100644 --- a/lib/stdlib/test/stdlib_bench_SUITE.erl +++ b/lib/stdlib/test/stdlib_bench_SUITE.erl @@ -52,7 +52,7 @@ groups() -> encode_list, encode_list_to_string, mime_binary_decode, mime_binary_decode_to_string, mime_list_decode, mime_list_decode_to_string]}, - {io, [{repeat, 5}], [double_random_to_list]}, + {io, [{repeat, 5}], [double_random_to_list, double_random_to_list_array]}, {gen_server, [{repeat,5}], cases(gen_server)}, {gen_statem, [{repeat,3}], cases(gen_statem)}, {gen_server_comparison, [], @@ -283,14 +283,17 @@ mbb(N, Acc) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(MAX_DOUBLE, (1 bsl 62) - 1). --define(DOUBLE_SAMPLE, 10000). +-define(DOUBLE_SAMPLE, 100000). -define(SMALL_DIGITS, 6). double_random_to_list(_Config) -> - comment(test_double(io_lib_format, fwrite_g, 0)). + comment(test_double(0)). + +double_random_to_list_array(_Config) -> + comment(test_double_array(0)). double_small_digit_to_list(_Config) -> - comment(test_double(io_lib_format, fwrite_g, ?SMALL_DIGITS)). + comment(test_double(?SMALL_DIGITS)). double(0) -> Int = rand:uniform(?MAX_DOUBLE), @@ -319,17 +322,34 @@ exp10(Acc, 0) -> exp10(Acc, X) -> exp10(Acc, X - 1). -test_double(Mod, Fun, SmallDigits) -> - test_double(?DOUBLE_SAMPLE, Mod, Fun, SmallDigits). -test_double(Iter, Mod, Fun, SmallDigits) -> - F = fun() -> loop_double(Iter, Mod, Fun, SmallDigits) end, +test_double(Samples) when is_list(Samples) -> + F = fun() -> loop_double(Samples) end, {Time, ok} = timer:tc(fun() -> lspawn(F) end), - report_mfa(Iter, Time, Mod). + report_mfa(?DOUBLE_SAMPLE, Time, io_lib_format); +test_double(SmallDigits) when is_integer(SmallDigits) -> + rand:seed(exsplus, {1201,855653,380975}), + Samples = [double(SmallDigits) || _ <- lists:seq(1, ?DOUBLE_SAMPLE)], + test_double(Samples). + +loop_double([]) -> garbage_collect(), ok; +loop_double([Sample | Rest]) -> + _ = io_lib_format:fwrite_g(Sample), + loop_double(Rest). + +test_double_array(SmallDigits) when is_integer(SmallDigits) -> + rand:seed(exsplus, {1201,855653,380975}), + Samples = [double(SmallDigits) || _ <- lists:seq(1, ?DOUBLE_SAMPLE)], + Samples_array = array:from_list(Samples), + test_double_array(?DOUBLE_SAMPLE - 1, Samples_array). +test_double_array(Iter, Samples_array) -> + F = fun() -> loop_double_array(Iter, Samples_array) end, + {Time, ok} = timer:tc(fun() -> lspawn(F) end), + report_mfa(?DOUBLE_SAMPLE, Time, io_lib_format). -loop_double(0, _M, _F, _SmallDigits) -> garbage_collect(), ok; -loop_double(N, M, F, SmallDigits) -> - _ = apply(M, F, [double(SmallDigits)]), - loop_double(N - 1, M, F, SmallDigits). +loop_double_array(0, _Samples_array) -> garbage_collect(), ok; +loop_double_array(Iter, Samples_array) -> + _ = io_lib_format:fwrite_g(array:get(Iter, Samples_array)), + loop_double_array(Iter - 1, Samples_array). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/test/stdlib_gh.spec b/lib/stdlib/test/stdlib_gh.spec new file mode 100644 index 000000000000..147c9209bd39 --- /dev/null +++ b/lib/stdlib/test/stdlib_gh.spec @@ -0,0 +1,9 @@ +{suites,"../stdlib_test",all}. +{skip_groups,"../stdlib_test",stdlib_bench_SUITE, + [binary,base64,gen_server,gen_statem,unicode], + "Benchmark only"}. +{skip_groups,"../stdlib_test",ets_SUITE, + [benchmark], + "Benchmark only"}. +{skip_cases, "../stdlib_test", gen_server_SUITE, + [multicall_remote_old1],"Broken in docker"}. diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl index 39e4f2c6f8bb..5a75c930dd68 100644 --- a/lib/stdlib/test/string_SUITE.erl +++ b/lib/stdlib/test/string_SUITE.erl @@ -643,21 +643,33 @@ cd_gc(_) -> [] = string:next_codepoint(""), [] = string:next_codepoint(<<>>), [] = string:next_codepoint([<<>>]), + [$a|""] = string:next_codepoint("a"), + [$a|<<>>] = string:next_codepoint(<<"a">>), + [$a|[<<>>,$b]] = string:next_codepoint([<<"a">>,$b]), "abcd" = string:next_codepoint("abcd"), - [$e,778] = string:next_codepoint([$e,778]), + [$e|[778]] = string:next_codepoint([$e,778]), [$e|<<204,138>>] = string:next_codepoint(<<$e,778/utf8>>), - [778|_] = string:next_codepoint(tl(string:next_codepoint(<<$e,778/utf8>>))), + [778|<<>>] = string:next_codepoint(tl(string:next_codepoint(<<$e,778/utf8>>))), [0|<<128,1>>] = string:next_codepoint(<<0,128,1>>), {error,<<128,1>>} = string:next_codepoint(<<128,1>>), + [128021|<<>>] = string:next_codepoint(<<128021/utf8>>), %% Dog + [128021|<<8205/utf8>>] = string:next_codepoint(<<128021/utf8,8205/utf8>>), %% Dog + ZWJ + [128021|<<8205/utf8,129466/utf8>>] = string:next_codepoint(<<128021/utf8,8205/utf8,129466/utf8>>), %% Dog + ZWJ + Service vest == Service dog [] = string:next_grapheme(""), [] = string:next_grapheme(<<>>), [] = string:next_grapheme([<<>>]), + [$a|""] = string:next_grapheme("a"), + [$a|<<>>] = string:next_grapheme(<<"a">>), + [$a|[<<>>,$b]] = string:next_grapheme([<<"a">>,$b]), "abcd" = string:next_grapheme("abcd"), - [[$e,778]] = string:next_grapheme([$e,778]), - [[$e,778]] = string:next_grapheme(<<$e,778/utf8>>), + [[$e,778]|""] = string:next_grapheme([$e,778]), + [[$e,778]|<<>>] = string:next_grapheme(<<$e,778/utf8>>), [0|<<128,1>>] = string:next_grapheme(<<0,128,1>>), {error,<<128,1>>} = string:next_grapheme(<<128,1>>), + [128021|<<>>] = string:next_grapheme(<<128021/utf8>>), %% Dog + [[128021,8205]|<<>>] = string:next_grapheme(<<128021/utf8,8205/utf8>>), %% Dog + ZWJ + [[128021,8205,129466]|<<>>] = string:next_grapheme(<<128021/utf8,8205/utf8,129466/utf8>>), %% Dog + ZWJ + Service vest == Service dog ok. diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index a0415eda33ac..f7f3aa0ba352 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -30,7 +30,7 @@ %% Internal export -export([init/1, terminate_all_children/1, - middle9212/0, gen_server9212/0, handle_info/2]). + middle9212/0, gen_server9212/0, handle_info/2, start_registered_name/1]). %% API tests -export([ sup_start_normal/1, sup_start_ignore_init/1, @@ -90,7 +90,7 @@ hanging_restart_loop_simple/1, code_change/1, code_change_map/1, code_change_simple/1, code_change_simple_map/1, order_of_children/1, scale_start_stop_many_children/1, - format_log_1/1, format_log_2/1]). + format_log_1/1, format_log_2/1, already_started_outside_supervisor/1]). %%------------------------------------------------------------------------- @@ -119,7 +119,7 @@ all() -> hanging_restart_loop_rest_for_one, hanging_restart_loop_simple, code_change, code_change_map, code_change_simple, code_change_simple_map, order_of_children, scale_start_stop_many_children, - format_log_1, format_log_2]. + format_log_1, format_log_2, already_started_outside_supervisor]. groups() -> [{sup_start, [], @@ -200,7 +200,7 @@ start_link(InitResult) -> %% Simulate different supervisors callback. init(fail) -> - erlang:error({badmatch,2}); + erlang:error(fail); init(InitResult) -> InitResult. @@ -227,7 +227,7 @@ sup_start_normal(Config) when is_list(Config) -> sup_start_ignore_init(Config) when is_list(Config) -> process_flag(trap_exit, true), ignore = start_link(ignore), - check_exit_reason(normal). + check_no_exit(100). %%------------------------------------------------------------------------- %% Tests what happens if init-callback returns ignore. @@ -325,15 +325,20 @@ sup_start_ignore_permanent_child_start_child_simple(Config) %% Tests what happens if init-callback returns a invalid value. sup_start_error_return(Config) when is_list(Config) -> process_flag(trap_exit, true), - {error, Term} = start_link(invalid), - check_exit_reason(Term). + %% The bad return is processed in supervisor:init/1 + InitResult = invalid, + {error, {bad_return, {?MODULE, init, InitResult}}} = + start_link(InitResult), + check_no_exit(100). %%------------------------------------------------------------------------- %% Tests what happens if init-callback fails. sup_start_fail(Config) when is_list(Config) -> process_flag(trap_exit, true), - {error, Term} = start_link(fail), - check_exit_reason(Term). + %% The exception is processed in gen_server:init_it/2 + ErrorReason = fail, + {error, {ErrorReason, _Stacktrace}} = start_link(ErrorReason), + check_no_exit(100). %%------------------------------------------------------------------------- %% Test what happens when the start function for a child returns @@ -914,7 +919,7 @@ child_specs_map(Config) when is_list(Config) -> B7 = CS0#{type => wrker}, B8 = CS0#{modules => dy}, B9 = CS0#{modules => [1,2,3]}, - B10 = CS0#{significant => maybe}, + B10 = CS0#{significant => 'maybe'}, {error, missing_id} = supervisor:start_child(sup_test, B1), {error, missing_start} = supervisor:start_child(sup_test, B2), @@ -942,7 +947,7 @@ child_specs_map(Config) when is_list(Config) -> {error, {invalid_modules,dy}} = supervisor:check_childspecs([B8]), {error, {invalid_module, 1}} = supervisor:check_childspecs([B9]), - {error, {invalid_significant, maybe}} = + {error, {invalid_significant, 'maybe'}} = supervisor:check_childspecs([B10]), CSFilter = fun (CS) -> maps:filter(fun (_, V) -> V =/= undefined end, CS) end, @@ -2628,7 +2633,7 @@ order_of_children(_Config) -> [{ok,[_]} = dbg:p(P,procs) || P <- Expected1], terminate(Pid3, abnormal), receive {exited,ExitedPids1} -> - dbg:stop_clear(), + dbg:stop(), case ExitedPids1 of Expected1 -> ok; _ -> ct:fail({faulty_termination_order, @@ -2636,7 +2641,7 @@ order_of_children(_Config) -> {got,ExitedPids1}}) end after 3000 -> - dbg:stop_clear(), + dbg:stop(), ct:fail({shutdown_fail,timeout}) end, @@ -2657,7 +2662,7 @@ order_of_children(_Config) -> [{ok,[_]} = dbg:p(P,procs) || P <- Expected2], exit(SupPid,shutdown), receive {exited,ExitedPids2} -> - dbg:stop_clear(), + dbg:stop(), case ExitedPids2 of Expected2 -> ok; _ -> ct:fail({faulty_termination_order, @@ -2665,7 +2670,7 @@ order_of_children(_Config) -> {got,ExitedPids2}}) end after 3000 -> - dbg:stop_clear(), + dbg:stop(), ct:fail({shutdown_fail,timeout}) end, ok. @@ -3672,6 +3677,31 @@ significant_upgrade_child(_Config) -> ok. +%% Test trying to start a child that uses an already registered name. +already_started_outside_supervisor(_Config) -> + %% Avoid inter-testcase flakiness + ensure_supervisor_is_stopped(), + process_flag(trap_exit, true), + {ok, SupPid} = start_link({ok, {#{}, []}}), + RegName = registered_name, + Child = #{id => child, + start => {?MODULE, start_registered_name, [RegName]}, + restart => transient, + significant => false}, + %% We start another process and register the name. + Pid = spawn_link(fun() -> + true = register(RegName, self()), + receive + die -> ok + end + end), + {error, {already_started, P}} = supervisor:start_child(SupPid, Child), + Pid = P, + terminate(SupPid, shutdown), + Pid ! die, + ok = check_exit([SupPid]), + ok. + %%------------------------------------------------------------------------- terminate(Pid, Reason) when Reason =/= supervisor -> terminate(dummy, Pid, dummy, Reason). @@ -3749,18 +3779,29 @@ check_exit([Pid | Pids], Timeout) -> error end. -check_exit_reason(Reason) -> +check_exit_reason(Pid, Reason) when is_pid(Pid) -> receive - {'EXIT', _, Reason} -> + {'EXIT', Pid, Reason} -> ok; - {'EXIT', _, Else} -> + {'EXIT', Pid, Else} -> ct:fail({bad_exit_reason, Else}) end. -check_exit_reason(Pid, Reason) -> +check_no_exit(Timeout) -> receive - {'EXIT', Pid, Reason} -> - ok; - {'EXIT', Pid, Else} -> - ct:fail({bad_exit_reason, Else}) + {'EXIT', Pid, _} = Exit when is_pid(Pid) -> + ct:fail({unexpected_message, Exit}) + after Timeout -> + ok + end. + +start_registered_name(Name) -> + supervisor:start_link({local, Name}, ?MODULE, []). + +ensure_supervisor_is_stopped() -> + case whereis(sup_test) of + undefined -> + ok; + Pid -> + terminate(Pid, shutdown) end. diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl index d055eb88cc6f..294741574c7c 100644 --- a/lib/stdlib/test/tar_SUITE.erl +++ b/lib/stdlib/test/tar_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2020. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -26,7 +26,7 @@ create_long_names/1, bad_tar/1, errors/1, extract_from_binary/1, extract_from_binary_compressed/1, extract_filtered/1, extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1, - memory/1,unicode/1,read_other_implementations/1, + memory/1,unicode/1,read_other_implementations/1,bsdtgz/1, sparse/1, init/1, leading_slash/1, dotdot/1, roundtrip_metadata/1, apply_file_info_opts/1, incompatible_options/1]). @@ -42,7 +42,7 @@ all() -> extract_from_binary_compressed, extract_from_open_file, extract_filtered, symlinks, open_add_close, cooked_compressed, memory, unicode, - read_other_implementations, + read_other_implementations, bsdtgz, sparse,init,leading_slash,dotdot,roundtrip_metadata, apply_file_info_opts,incompatible_options]. @@ -113,8 +113,8 @@ borderline_test(Size, TempDir, IsUstar) -> Name = filename:join(TempDir, Prefix++SizeList), %% Create a file and archive it. - X0 = erlang:monotonic_time(), - ok = file:write_file(Name, random_byte_list(X0, Size)), + RandomBytes = rand:bytes(Size), + ok = file:write_file(Name, RandomBytes), ok = erl_tar:create(Archive, [Name]), ok = file:delete(Name), @@ -125,7 +125,7 @@ borderline_test(Size, TempDir, IsUstar) -> %% Verify contents of extracted file. {ok, Bin} = file:read_file(Name), - true = match_byte_list(X0, binary_to_list(Bin)), + RandomBytes = Bin, %% Verify that Unix tar can read it. case IsUstar of @@ -199,34 +199,6 @@ make_cmd(Cmd) -> {unix, _} -> lists:concat(["sh -c '", Cmd, "'"]) end. -%% Verifies a random byte list. - -match_byte_list(X0, [Byte|Rest]) -> - X = next_random(X0), - case (X bsr 26) band 16#ff of - Byte -> match_byte_list(X, Rest); - _ -> false - end; -match_byte_list(_, []) -> - true. - -%% Generates a random byte list. - -random_byte_list(X0, Count) -> - random_byte_list(X0, Count, []). - -random_byte_list(X0, Count, Result) when Count > 0-> - X = next_random(X0), - random_byte_list(X, Count-1, [(X bsr 26) band 16#ff|Result]); -random_byte_list(_X, 0, Result) -> - lists:reverse(Result). - -%% This RNG is from line 21 on page 102 in Knuth: The Art of Computer Programming, -%% Volume II, Seminumerical Algorithms. - -next_random(X) -> - (X*17059465+1) band 16#fffffffff. - %% Test the 'atomic' operations: create/extract/table, on compressed %% and uncompressed archives. %% Also test the 'cooked' option. @@ -891,6 +863,17 @@ do_read_other_implementations([File|Rest], DataDir) -> {ok, _} = erl_tar:extract(Full, [memory]), do_read_other_implementations(Rest, DataDir). +%% test block padding with compressed tar from bsdtar or tape +bsdtgz(Config) when is_list(Config) -> + DataDir = proplists:get_value(data_dir, Config), + File = "example_pad.tgz", + Full = filename:join(DataDir, File), + io:format("~nTrying ~s", [File]), + Table = ["autofs.conf","rpc"], + {ok, Table} = erl_tar:table(Full, [compressed]), + {ok, Bin} = file:read_file(Full), + {ok, Table} = erl_tar:table({binary, Bin}, [compressed]), + verify_ports(Config). %% Test handling of sparse files sparse(Config) when is_list(Config) -> @@ -914,23 +897,20 @@ do_sparse([Name|Rest], DataDir, PrivDir) -> %% Test filenames with characters outside the US ASCII range. unicode(Config) when is_list(Config) -> - run_unicode_node(Config, "+fnu"), + run_unicode_node(Config, ["+fnu"]), case has_transparent_naming() of true -> - run_unicode_node(Config, "+fnl"); + run_unicode_node(Config, ["+fnl"]); false -> ok end. -run_unicode_node(Config, Option) -> +run_unicode_node(Config, Args) -> PrivDir = proplists:get_value(priv_dir, Config), - Pa = filename:dirname(code:which(?MODULE)), - Args = Option ++ " -pa "++Pa, - io:format("~s\n", [Args]), - Node = start_node(unicode, Args), + {ok, Peer, Node} = ?CT_PEER(Args), ok = rpc:call(Node, erlang, apply, [fun() -> do_unicode(PrivDir) end,[]]), - true = test_server:stop_node(Node), + peer:stop(Peer), ok. has_transparent_naming() -> @@ -942,21 +922,25 @@ has_transparent_naming() -> do_unicode(PrivDir) -> ok = file:set_cwd(PrivDir), - ok = file:make_dir("unicöde"), - - Names = lists:sort(unicode_create_files()), - Tar = "unicöde.tar", - ok = erl_tar:create(Tar, ["unicöde"], []), - - %% Unicode filenames require PAX format. - false = is_ustar(Tar), - {ok,Names0} = erl_tar:table(Tar, []), - Names = lists:sort(Names0), - _ = [ok = file:delete(Name) || Name <- Names], - ok = erl_tar:extract(Tar), - _ = [{ok,_} = file:read_file(Name) || Name <- Names], - _ = [ok = file:delete(Name) || Name <- Names], - ok = file:del_dir("unicöde"), + case file:make_dir("unicöde") of + ok -> + Names = lists:sort(unicode_create_files()), + Tar = "unicöde.tar", + ok = erl_tar:create(Tar, ["unicöde"], []), + + %% Unicode filenames require PAX format. + false = is_ustar(Tar), + {ok,Names0} = erl_tar:table(Tar, []), + Names = lists:sort(Names0), + _ = [ok = file:delete(Name) || Name <- Names], + ok = erl_tar:extract(Tar), + _ = [{ok,_} = file:read_file(Name) || Name <- Names], + _ = [ok = file:delete(Name) || Name <- Names], + ok = file:del_dir("unicöde"); + {error,eilseq} -> + %% The FS (eg zfs) does not support transparent naming + ok + end, ok. unicode_create_files() -> @@ -1014,7 +998,7 @@ roundtrip_metadata(Config) -> do_roundtrip_metadata(Dir, File) -> Tar = filename:join(Dir, atom_to_list(?FUNCTION_NAME)++".tar"), - BeamFile = code:which(compile), + BeamFile = code:which(?MODULE), {ok,Fd} = erl_tar:open(Tar, [write]), ok = erl_tar:add(Fd, BeamFile, File, []), ok = erl_tar:close(Fd), @@ -1131,17 +1115,6 @@ make_temp_dir(Base, I) -> {error,eexist} -> make_temp_dir(Base, I+1) end. -start_node(Name, Args) -> - [_,Host] = string:tokens(atom_to_list(node()), "@"), - ct:log("Trying to start ~w@~s~n", [Name,Host]), - case test_server:start_node(Name, peer, [{args,Args}]) of - {error,Reason} -> - ct:fail(Reason); - {ok,Node} -> - ct:log("Node ~p started~n", [Node]), - Node - end. - %% Test that the given tar file is a plain USTAR archive, %% without any PAX extensions. is_ustar(File) -> diff --git a/lib/stdlib/test/tar_SUITE_data/example_pad.tgz b/lib/stdlib/test/tar_SUITE_data/example_pad.tgz new file mode 100644 index 000000000000..508ab1b46105 Binary files /dev/null and b/lib/stdlib/test/tar_SUITE_data/example_pad.tgz differ diff --git a/lib/stdlib/test/timer_SUITE.erl b/lib/stdlib/test/timer_SUITE.erl index 9062cbae8044..d6211acf9d79 100644 --- a/lib/stdlib/test/timer_SUITE.erl +++ b/lib/stdlib/test/timer_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -132,7 +132,7 @@ big_loop(C, N, Pids) -> %%Pids2=Pids1, %% wait a little while - timer:sleep(rand:uniform(200)*3), + ok = timer:sleep(rand:uniform(200)*3), %% spawn zero, one or two nrev to get some load ;-/ Pids3 = start_nrev(Pids2, rand:uniform(100)), @@ -168,7 +168,7 @@ s_a_t(C, TimeOut) -> a_t(C, TimeOut) -> start_watchdog(self(), TimeOut), Start = system_time(), - timer:send_after(TimeOut, self(), now), + {ok, _} = timer:send_after(TimeOut, self(), now), receive now -> Stop = system_time(), @@ -202,12 +202,12 @@ i_wait(Start, Prev, Times, TimeOut, Times, Ref, C) -> interval -> Now = system_time(), report_interval(C, {final,Times}, Start, Prev, Now, TimeOut), - timer:cancel(Ref), + {ok, cancel} = timer:cancel(Ref), exit(done); watchdog -> Now = system_time(), report_interval(C, {final,Times}, Start, Prev, Now, TimeOut), - timer:cancel(Ref), + {ok, cancel} = timer:cancel(Ref), ok = io:format("Internal watchdog timeout (i), not good!!~n", []), exit(done) @@ -358,7 +358,7 @@ system_time() -> %% ------------------------------------------------------- %% do_nrev(Sleep) -> - timer:sleep(Sleep), + ok = timer:sleep(Sleep), test(1000,"abcdefghijklmnopqrstuvxyz1234"), exit(done). diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl index 1a582ae95a36..761689dc5114 100644 --- a/lib/stdlib/test/timer_simple_SUITE.erl +++ b/lib/stdlib/test/timer_simple_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2022. 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. @@ -21,54 +21,202 @@ -module(timer_simple_SUITE). +%% This test suite matches on opaque tref() return values from the *_after +%% and *_interval functions, namely {instant, _}, {send_local, _}, {once, _} +%% and {interval, _}. +%% If the implementation changes, the test suite has to be changed accordingly. + %% external -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, - apply_after/1, - send_after1/1, - send_after2/1, - send_after3/1, - exit_after1/1, - exit_after2/1, - kill_after1/1, - kill_after2/1, - apply_interval/1, - send_interval1/1, - send_interval2/1, - send_interval3/1, - send_interval4/1, - cancel1/1, - cancel2/1, - tc/1, - unique_refs/1, - timer_perf/1]). + init_per_group/2,end_per_group/2, + init_per_testcase/2, + apply_after1/1, + apply_after2/1, + apply_after3/1, + apply_after4/1, + apply_after_invalid_args/1, + send_after1/1, + send_after2/1, + send_after3/1, + send_after4/1, + send_after5/1, + send_after6/1, + send_after7/1, + send_after_invalid_args/1, + exit_after1/1, + exit_after2/1, + exit_after3/1, + exit_after4/1, + kill_after1/1, + kill_after2/1, + kill_after3/1, + apply_interval1/1, + apply_interval2/1, + apply_interval_invalid_args/1, + apply_repeatedly1/1, + apply_repeatedly2/1, + apply_repeatedly_invalid_args/1, + send_interval1/1, + send_interval2/1, + send_interval3/1, + send_interval4/1, + send_interval5/1, + send_interval_invalid_args/1, + cancel1/1, + cancel2/1, + cancel3/1, + cancel4/1, + cancel5/1, + cancel6/1, + cancel_invalid_args/1, + sleep1/1, + sleep2/1, + tc/1, + unexpected1/1, + unexpected2/1, + unexpected3/1, + nonexistent1/1, + nonexistent2/1, + timer_perf/1]). %% internal -export([forever/0, - do_nrev/2, - send/2, - timer/4, - timer/5]). + do_nrev/2, + send/2, + timer/4, + timer/5]). -include_lib("common_test/include/ct.hrl"). --define(MAXREF, (1 bsl 18)). --define(REFMARG, 30). - suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,10}}]. -all() -> - [apply_after, send_after1, send_after2, send_after3, - exit_after1, exit_after2, kill_after1, kill_after2, - apply_interval, send_interval1, send_interval2, - send_interval3, send_interval4, cancel1, cancel2, tc, - unique_refs, timer_perf]. +all() -> + [ + {group, apply_after}, + {group, send_after}, + {group, exit_after}, + {group, kill_after}, + {group, apply_interval}, + {group, apply_repeatedly}, + {group, send_interval}, + {group, cancel}, + {group, sleep}, + {group, misc} + ]. groups() -> - []. + [ + { + apply_after, + [], + [ + apply_after1, + apply_after2, + apply_after3, + apply_after4, + apply_after_invalid_args + ] + }, + { + send_after, + [], + [ + send_after1, + send_after2, + send_after3, + send_after4, + send_after5, + send_after6, + send_after7, + send_after_invalid_args + ] + }, + { + exit_after, + [], + [ + exit_after1, + exit_after2, + exit_after3, + exit_after4 + ] + }, + { + kill_after, + [], + [ + kill_after1, + kill_after2, + kill_after3 + ] + }, + { + apply_interval, + [], + [ + apply_interval1, + apply_interval2, + apply_interval_invalid_args + ] + }, + { + apply_repeatedly, + [], + [ + apply_repeatedly1, + apply_repeatedly2, + apply_repeatedly_invalid_args + ] + }, + { + send_interval, + [], + [ + send_interval1, + send_interval2, + send_interval3, + send_interval4, + send_interval5, + send_interval_invalid_args + ] + }, + { + cancel, + [], + [ + cancel1, + cancel2, + cancel3, + cancel4, + cancel5, + cancel6, + cancel_invalid_args + ] + }, + { + sleep, + [], + [ + sleep1, + sleep2 + ] + }, + { + misc, + [], + [ + tc, + unexpected1, + unexpected2, + unexpected3, + nonexistent1, + nonexistent2, + timer_perf + ] + } + ]. init_per_suite(Config) -> Config. @@ -84,57 +232,162 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_, Config) when is_list(Config) -> - timer:start(), + ok = timer:start(), Config. %% Testing timer interface!! -%% Test of apply_after, with sending of message. -apply_after(Config) when is_list(Config) -> - timer:apply_after(500, ?MODULE, send, [self(), ok_apply]), - ok = get_mess(1000, ok_apply). +%% Test of apply_after with time = 0, with sending of message. +apply_after1(Config) when is_list(Config) -> + Msg = make_ref(), + {ok, {instant, _}} = timer:apply_after(0, ?MODULE, send, [self(), Msg]), + ok = get_mess(1000, Msg). + +%% Test of apply_after with time = 500, with sending of message. +apply_after2(Config) when is_list(Config) -> + Msg = make_ref(), + {ok, {once, _}} = timer:apply_after(500, ?MODULE, send, [self(), Msg]), + ok = get_mess(1000, Msg). + +%% Test that a request starts the timer server if it is not running. +apply_after3(Config) when is_list(Config) -> + ok = supervisor:terminate_child(kernel_sup, timer_server), + Msg = make_ref(), + timer:apply_after(100, erlang, send, [self(), Msg]), + ok = get_mess(500, Msg), + {timer_server, Pid, worker, [timer]} = lists:keyfind(timer_server, 1, supervisor:which_children(kernel_sup)), + true = is_pid(Pid). + +%% Test that a request starts the timer server if it is not running. +apply_after4(Config) when is_list(Config) -> + ok = supervisor:terminate_child(kernel_sup, timer_server), + ok = supervisor:delete_child(kernel_sup, timer_server), + Msg = make_ref(), + timer:apply_after(100, erlang, send, [self(), Msg]), + ok = get_mess(500, Msg), + {timer_server, Pid, worker, [timer]} = lists:keyfind(timer_server, 1, supervisor:which_children(kernel_sup)), + true = is_pid(Pid). + +%% Test that apply_after rejects invalid arguments. +apply_after_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:apply_after(-1, foo, bar, []), + {error, badarg} = timer:apply_after(0, "foo", bar, []), + {error, badarg} = timer:apply_after(0, foo, "bar", []), + {error, badarg} = timer:apply_after(0, foo, bar, baz), + ok. %% Test of send_after with time = 0. send_after1(Config) when is_list(Config) -> - timer:send_after(0, ok_send1), - ok = get_mess(1000, ok_send1). + Msg = make_ref(), + {ok, {instant, _}} = timer:send_after(0, Msg), + ok = get_mess(1000, Msg). -%% Test of send_after with time = 500. +%% Test of send_after with time = 0 using a registered name. send_after2(Config) when is_list(Config) -> - timer:send_after(500, self(), ok_send2), - ok = get_mess(2000, ok_send2). + Msg = make_ref(), + Name = register_name(self()), + {ok, {instant, _}} = timer:send_after(0, Name, Msg), + ok = get_mess(1000, Msg), + unregister(Name). + +%% Test of send_after with time = 0 using a registered name +%% and node. +send_after3(Config) when is_list(Config) -> + Msg = make_ref(), + Name = register_name(self()), + {ok, {instant, _}} = timer:send_after(0, {Name, node()}, Msg), + ok = get_mess(1000, Msg), + unregister(Name). + +%% Test of send_after with time = 500. +send_after4(Config) when is_list(Config) -> + Msg = make_ref(), + {ok, {send_local, _}} = timer:send_after(500, self(), Msg), + ok = get_mess(2000, Msg). %% Test of send_after with time = 500, with receiver a registered %% process. [OTP-2735] -send_after3(Config) when is_list(Config) -> - Name = list_to_atom(pid_to_list(self())), +send_after5(Config) when is_list(Config) -> + Msg = make_ref(), + Name = register_name(self()), + {ok, {once, _}} = timer:send_after(500, Name, Msg), + ok = get_mess(2000, Msg), + unregister(Name). + +%% Test of send_after with time = 500 using a registered process +%% and node. +send_after6(Config) when is_list(Config) -> + Msg = make_ref(), + Name = register_name(self()), + {ok, {once, _}} = timer:send_after(500, {Name, node()}, Msg), + ok = get_mess(2000, Msg), + unregister(Name). + +%% Test that send_after works if the destination is a registered +%% name which gets registered after the timer is started. +send_after7(Config) when is_list(Config) -> + Msg = make_ref(), + Name = make_name(), + {ok, {once, _}} = timer:send_after(500, Name, Msg), register(Name, self()), - timer:send_after(500, Name, ok_send3), - ok = get_mess(2000, ok_send3), + ok = get_mess(2000, Msg), unregister(Name). +%% Test that send_after rejects invalid arguments. +send_after_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:send_after(-1, test), + {error, badarg} = timer:send_after(-1, self(), test), + {error, badarg} = timer:send_after(-1, ?MODULE, test), + {error, badarg} = timer:send_after(0, "", test), + ok. + %% Test of exit_after with time = 1000. exit_after1(Config) when is_list(Config) -> + Msg = make_ref(), process_flag(trap_exit, true), Pid = spawn_link(?MODULE, forever, []), - timer:exit_after(1000, Pid, exit_test1), - ok = get_mess(5000, {'EXIT', Pid, exit_test1}). + {ok, {once, _}} = timer:exit_after(1000, Pid, Msg), + ok = get_mess(5000, {'EXIT', Pid, Msg}). %% Test of exit_after with time = 1000. The process to exit is the %% name of a registered process. [OTP-2735] exit_after2(Config) when is_list(Config) -> + Msg = make_ref(), process_flag(trap_exit, true), Pid = spawn_link(?MODULE, forever, []), - Name = list_to_atom(pid_to_list(Pid)), - register(Name, Pid), - timer:exit_after(1000, Name, exit_test2), - ok = get_mess(2000, {'EXIT', Pid, exit_test2}). + Name = register_name(Pid), + {ok, {once, _}} = timer:exit_after(1000, Name, Msg), + ok = get_mess(2000, {'EXIT', Pid, Msg}). + +%% Test of exit_after for sending an exit to self. +exit_after3(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Msg = make_ref(), + Pid = spawn_link( + fun () -> + {ok, {once, _}} = timer:exit_after(1000, Msg), + forever() + end + ), + ok = get_mess(2000, {'EXIT', Pid, Msg}). + +%% Test that using exit_after to a non-existent +%% process does not crash the timer server. +exit_after4(Config) when is_list(Config) -> + Mon = monitor(process, timer_server), + timer:exit_after(0, make_name(), make_ref()), + receive + {'DOWN', Mon, process, _, _} -> + error(timer_server_crashed) + after 1000 -> + ok + end. %% Test of kill_after with time = 1000. kill_after1(Config) when is_list(Config) -> process_flag(trap_exit, true), Pid = spawn_link(?MODULE, forever, []), - timer:kill_after(1000, Pid), + {ok, {once, _}} = timer:kill_after(1000, Pid), ok = get_mess(2000, {'EXIT', Pid, killed}). %% Test of kill_after with time = 1000. The process to exit is the @@ -142,114 +395,370 @@ kill_after1(Config) when is_list(Config) -> kill_after2(Config) when is_list(Config) -> process_flag(trap_exit, true), Pid = spawn_link(?MODULE, forever, []), - Name = list_to_atom(pid_to_list(Pid)), - register(Name, Pid), - timer:kill_after(1000, Name), + Name = register_name(Pid), + {ok, {once, _}} = timer:kill_after(1000, Name), + ok = get_mess(2000, {'EXIT', Pid, killed}). + +%% Test of kill_after for self-killing. +kill_after3(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Pid = spawn_link( + fun () -> + {ok, {once, _}} = timer:kill_after(1000), + forever() + end + ), ok = get_mess(2000, {'EXIT', Pid, killed}). %% Test of apply_interval by sending messages. Receive %% 3 messages, cancel the timer, and check that we do %% not get any more messages. -apply_interval(Config) when is_list(Config) -> +apply_interval1(Config) when is_list(Config) -> + Msg = make_ref(), {ok, Ref} = timer:apply_interval(1000, ?MODULE, send, - [self(), apply_int]), - ok = get_mess(1500, apply_int, 3), - timer:cancel(Ref), - nor = get_mess(1000, apply_int). + [self(), Msg]), + ok = get_mess(1500, Msg, 3), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg). + +%% Test apply_interval with the execution time of the action +%% longer than the timer interval. The timer should not wait for +%% the action to complete, ie start another action while the +%% previously started action is still running. +apply_interval2(Config) when is_list(Config) -> + Msg = make_ref(), + Self = self(), + {ok, Ref} = timer:apply_interval(500, erlang, apply, + [fun() -> + Self ! Msg, + receive after 1000 -> ok end + end, []]), + receive after 1800 -> ok end, + {ok, cancel} = timer:cancel(Ref), + ok = get_mess(1000, Msg, 3), + nor = get_mess(1000, Msg). + +%% Test that apply_interval rejects invalid arguments. +apply_interval_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:apply_interval(-1, foo, bar, []), + {error, badarg} = timer:apply_interval(0, "foo", bar, []), + {error, badarg} = timer:apply_interval(0, foo, "bar", []), + {error, badarg} = timer:apply_interval(0, foo, bar, baz), + ok. + +%% Test of apply_repeatedly by sending messages. Receive +%% 3 messages, cancel the timer, and check that we do +%% not get any more messages. In a case like this, ie where +%% the execution time of the action is shorter than the timer +%% interval, this should behave the same as apply_interval. +apply_repeatedly1(Config) when is_list(Config) -> + Msg = make_ref(), + {ok, Ref} = timer:apply_repeatedly(1000, ?MODULE, send, + [self(), Msg]), + ok = get_mess(1500, Msg, 3), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg). + +%% Test apply_repeatedly with the execution time of the action +%% longer than the timer interval. The timer should wait for +%% the action to complete, ie not start another action until it +%% has completed. +apply_repeatedly2(Config) when is_list(Config) -> + Msg = make_ref(), + Self = self(), + {ok, Ref} = timer:apply_repeatedly(1, erlang, apply, + [fun() -> + Self ! Msg, + receive after 1000 -> ok end + end, []]), + receive after 2500 -> ok end, + {ok, cancel} = timer:cancel(Ref), + ok = get_mess(1000, Msg, 3), + nor = get_mess(1000, Msg). + +%% Test that apply_repeatedly rejects invalid arguments. +apply_repeatedly_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:apply_repeatedly(-1, foo, bar, []), + {error, badarg} = timer:apply_repeatedly(0, "foo", bar, []), + {error, badarg} = timer:apply_repeatedly(0, foo, "bar", []), + {error, badarg} = timer:apply_repeatedly(0, foo, bar, baz), + ok. %% Test of send_interval/2. Receive 5 messages, cancel the timer, and %% check that we do not get any more messages. send_interval1(Config) when is_list(Config) -> - {ok, Ref} = timer:send_interval(1000, send_int), - ok = get_mess(1500, send_int, 5), - timer:cancel(Ref), - nor = get_mess(1000, send_int). % We should receive only five + Msg = make_ref(), + {ok, Ref} = timer:send_interval(1000, Msg), + ok = get_mess(1500, Msg, 5), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg). % We should receive only five %% Test of send_interval/3. Receive 2 messages, cancel the timer, and %% check that we do not get any more messages. send_interval2(Config) when is_list(Config) -> - {ok, Ref} = timer:send_interval(1000, self(), send_int2), - ok = get_mess(1500, send_int2, 2), - timer:cancel(Ref), - nor = get_mess(1000, send_int2). % We should receive only two + Msg = make_ref(), + {ok, Ref} = timer:send_interval(1000, self(), Msg), + ok = get_mess(1500, Msg, 2), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg). % We should receive only two %% Test of send_interval/3. Receive 2 messages, cancel the timer, and %% check that we do not get any more messages. The receiver is the %% name of a registered process. [OTP-2735] send_interval3(Config) when is_list(Config) -> process_flag(trap_exit, true), - Name = list_to_atom(pid_to_list(self())), - register(Name, self()), - {ok, Ref} = timer:send_interval(1000, Name, send_int3), - ok = get_mess(1500, send_int3, 2), - timer:cancel(Ref), - nor = get_mess(1000, send_int3), % We should receive only two + Msg = make_ref(), + Name = register_name(self()), + {ok, Ref} = timer:send_interval(1000, Name, Msg), + ok = get_mess(1500, Msg, 2), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg), % We should receive only two + unregister(Name). + +%% Test of send_interval/3 using a registered name and node. +send_interval4(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Msg = make_ref(), + Name = register_name(self()), + {ok, Ref} = timer:send_interval(1000, {Name, node()}, Msg), + ok = get_mess(1500, Msg, 2), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(1000, Msg), % We should receive only two unregister(Name). %% Test that send interval stops sending msg when the receiving %% process terminates. -send_interval4(Config) when is_list(Config) -> - timer:send_interval(500, one_time_only), +send_interval5(Config) when is_list(Config) -> + Msg1 = make_ref(), + {ok, {interval, Ref}} = timer:send_interval(500, Msg1), receive - one_time_only -> ok + Msg1 -> ok end, - timer_server ! {'EXIT', self(), normal}, % Should remove the timer - timer:send_after(600, send_intv_ok), - send_intv_ok = receive - Msg -> Msg - end. + timer_server ! {'DOWN', Ref, process, self(), test}, + Msg2 = make_ref(), + {ok, {send_local, _}} = timer:send_after(600, Msg2), + Msg2 = receive + TmpMsg -> TmpMsg + end. -%% Test that we can cancel a timer. +%% Test that send_interval rejects invalid arguments. +send_interval_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:send_interval(-1, test), + {error, badarg} = timer:send_interval(-1, self(), test), + {error, badarg} = timer:send_interval(-1, ?MODULE, test), + {error, badarg} = timer:send_interval(0, "", test), + ok. + +%% Test that we can cancel an instant timer cancel1(Config) when is_list(Config) -> - {ok, Ref} = timer:send_after(1000, this_should_be_canceled), - timer:cancel(Ref), - nor = get_mess(2000, this_should_be_canceled). % We should rec 0 msgs + Msg = make_ref(), + {ok, Ref} = timer:send_after(0, Msg), + {ok, cancel} = timer:cancel(Ref), + ok = get_mess(0, Msg). % We should rec 1 msg as it got sent immediately -%% Test cancel/1 with bad argument. +%% Test that we can cancel a send-once timer. cancel2(Config) when is_list(Config) -> - {error, badarg} = timer:cancel(no_reference). + Msg = make_ref(), + {ok, Ref} = timer:send_after(1000, Msg), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(2000, Msg). % We should rec 0 msgs + +%% Test that we can cancel an apply-once timer. +cancel3(Config) when is_list(Config) -> + Msg = make_ref(), + {ok, Ref} = timer:apply_after(1000, erlang, send, [self(), Msg]), + {ok, cancel} = timer:cancel(Ref), + nor = get_mess(2000, Msg). + +%% Test that we can cancel a send-interval timer. +cancel4(Config) when is_list(Config) -> + Msg1 = make_ref(), + {ok, Ref} = timer:send_interval(500, Msg1), + receive + Msg1 -> ok + end, + {ok, cancel} = timer:cancel(Ref), + Msg2 = make_ref(), + {ok, {send_local, _}} = timer:send_after(600, Msg2), + Msg2 = receive + TmpMsg -> TmpMsg + end. + +%% Test that we can cancel an apply-interval timer. +cancel5(Config) when is_list(Config) -> + Msg1 = make_ref(), + {ok, Ref} = timer:apply_interval(500, erlang, send, [self(), Msg1]), + receive + Msg1 -> ok + end, + {ok, cancel} = timer:cancel(Ref), + Msg2 = make_ref(), + {ok, {send_local, _}} = timer:send_after(600, Msg2), + Msg2 = receive + TmpMsg -> TmpMsg + end. + +%% Test that cancelling non-existent timers does not crash the +%% timer server. +cancel6(Config) when is_list(Config) -> + lists:foreach( + fun (TimerType) -> + Mon = monitor(process, timer_server), + {ok, cancel} = timer:cancel({TimerType, make_ref()}), + receive + {'DOWN', Mon, process, _, _} -> + error({timer_server_crashed, {cancel, TimerType}}) + after 500 -> + ok + end, + demonitor(Mon) + end, + [once, instant, interval, send_local] + ). + +%% Test that cancel rejects invalid arguments. +cancel_invalid_args(Config) when is_list(Config) -> + {error, badarg} = timer:cancel(no_reference), + {error, badarg} = timer:cancel({foo, make_ref()}), + {error, badarg} = timer:cancel({once, foo}), + {error, badarg} = timer:cancel({interval, foo}), + {error, badarg} = timer:cancel({instant, foo}), + ok. + +%% Test that sleep pauses the calling process for +%% at least the given time. +sleep1(Config) when is_list(Config) -> + T0 = erlang:monotonic_time(millisecond), + ok = timer:sleep(1000), + T1 = erlang:monotonic_time(millisecond), + true = T1 - T0 >= 1000, + ok. + +%% Test that sleep accepts times >(2^32)-1, which is +%% the maximum time for the after clause of a receive +%% operation, at the time of this writing. +sleep2(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Pid = spawn_link( + fun () -> + {ok, {once, _}} = timer:kill_after(1000), + ok = timer:sleep(16#ffffffff+1) + end + ), + ok = get_mess(2000, {'EXIT', Pid, killed}). + +%% Test that unexpected calls do not crash the timer server. +unexpected1(Config) when is_list(Config) -> + Mon = monitor(process, timer_server), + try + gen_server:call(timer_server, foo, 100) + of + _ -> + error(timeout_expected) + catch + exit:{timeout, _} -> + ok + end, + receive + {'DOWN', Mon, process, _, _} -> + error(timer_server_crashed) + after 500 -> + ok + end, + demonitor(Mon). + +%% Test that unexpected casts do not crash the timer server. +unexpected2(Config) when is_list(Config) -> + Mon = monitor(process, timer_server), + gen_server:cast(timer_server, foo), + receive + {'DOWN', Mon, process, _, _} -> + error(timer_server_crashed) + after 500 -> + ok + end, + demonitor(Mon). + +%% Test that unexpected info messages do not crash the timer server. +unexpected3(Config) when is_list(Config) -> + Mon = monitor(process, timer_server), + timer_server ! foo, + receive + {'DOWN', Mon, process, _, _} -> + error(timer_server_crashed) + after 500 -> + ok + end, + demonitor(Mon). + +%% Test that timeouts of one-shot timers the timer server does not +%% know are not executed. +nonexistent1(Config) when is_list(Config) -> + Msg = make_ref(), + timer_server ! {timeout, make_ref(), {apply_once, {erlang, send, [self(), Msg]}}}, + nor = get_mess(1000, Msg). + +%% Test that timeouts of interval timers the timer server does not +%% know are not executed. +nonexistent2(Config) when is_list(Config) -> + Msg = make_ref(), + timer_server ! {timeout, make_ref, {apply_interval, erlang:monotonic_time(millisecond), 1000, make_ref(), {erlang, send, [self(), Msg]}}}, + nor = get_mess(1000, Msg). %% Test sleep/1 and tc/3. tc(Config) when is_list(Config) -> %% This should test both sleep and tc/3 {Res1, ok} = timer:tc(timer, sleep, [500]), - ok = if - Res1 < 500*1000 -> {too_early, Res1}; % Too early - Res1 > 800*1000 -> {too_late, Res1}; % Too much time - true -> ok - end, + ok = if + Res1 < 500*1000 -> {too_early, Res1}; % Too early + Res1 > 800*1000 -> {too_late, Res1}; % Too much time + true -> ok + end, %% tc/2 - {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]), - ok = if - Res2 < 500*1000 -> {too_early, Res2}; % Too early - Res2 > 800*1000 -> {too_late, Res2}; % Too much time - true -> ok - end, + {Res2, ok} = timer:tc(fun(T) -> ok = timer:sleep(T) end, [500]), + ok = if + Res2 < 500*1000 -> {too_early, Res2}; % Too early + Res2 > 800*1000 -> {too_late, Res2}; % Too much time + true -> ok + end, %% tc/1 - {Res3, ok} = timer:tc(fun() -> timer:sleep(500) end), - ok = if - Res3 < 500*1000 -> {too_early, Res3}; % Too early - Res3 > 800*1000 -> {too_late, Res3}; % Too much time - true -> ok - end, + {Res3, ok} = timer:tc(fun() -> ok = timer:sleep(500) end), + ok = if + Res3 < 500*1000 -> {too_early, Res3}; % Too early + Res3 > 800*1000 -> {too_late, Res3}; % Too much time + true -> ok + end, + + %% tc/4 + {Res4, ok} = timer:tc(timer, sleep, [500], millisecond), + ok = if + Res4 < 500 -> {too_early, Res4}; + Res4 > 800 -> {too_late, Res4}; + true -> ok + end, %% Check that timer:tc don't catch errors + ok = try timer:tc(erlang, exit, [foo], second) + catch exit:foo -> ok + end, + ok = try timer:tc(erlang, exit, [foo]) - catch exit:foo -> ok - end, + catch exit:foo -> ok + end, ok = try timer:tc(fun(Reason) -> 1 = Reason end, [foo]) - catch error:{badmatch,_} -> ok - end, + catch error:{badmatch,_} -> ok + end, ok = try timer:tc(fun() -> throw(foo) end) - catch foo -> ok - end, + catch foo -> ok + end, %% Check that return values are propageted Self = self(), + {_, Self} = timer:tc(erlang, self, [], second), {_, Self} = timer:tc(erlang, self, []), {_, Self} = timer:tc(fun(P) -> P end, [self()]), {_, Self} = timer:tc(fun() -> self() end), @@ -263,70 +772,17 @@ tc(Config) when is_list(Config) -> if MyRes == TimerRes -> ok end, ok. -%% Test that cancellations of one-shot timers do not accidentally -%% cancel interval timers. [OTP-2771]. -unique_refs(Config) when is_list(Config) -> - ITimers = repeat_send_interval(10), % 10 interval timers - eat_refs(?MAXREF - ?REFMARG), - set_and_cancel_one_shots(?REFMARG), - NumLeft = num_timers(), - io:format("~w timers left, should be 10\n", [NumLeft]), - cancel(ITimers), - receive_nisse(), - 10 = NumLeft. - - -repeat_send_interval(0) -> - []; -repeat_send_interval(M) -> - {ok, Ref} = timer:send_interval(6000,self(), nisse), - [Ref| repeat_send_interval(M - 1)]. - -eat_refs(0) -> - 0; -eat_refs(N) -> - _ = make_ref(), - eat_refs(N-1). - -set_and_cancel_one_shots(0) -> - 0; -set_and_cancel_one_shots(N) -> - {ok, Ref} = timer:send_after(7000, self(), kalle), - %% Cancel twice - timer:cancel(Ref), - timer:cancel(Ref), - set_and_cancel_one_shots(N-1). - -cancel([T| Ts]) -> - timer:cancel(T), - cancel(Ts); -cancel([]) -> - ok. - -num_timers() -> - {{_, TotalTimers},{_, _IntervalTimers}} = timer:get_status(), - TotalTimers. - -receive_nisse() -> - receive - nisse -> - receive_nisse() - after 0 -> - ok - end. - - get_mess(Time, Mess) -> get_mess(Time, Mess, 1). get_mess(_, _, 0) -> ok; % Received get_mess(Time, Mess, N) -> receive - Mess -> get_mess(Time, Mess, N-1) - after Time - -> nor % Not Received + Mess -> get_mess(Time, Mess, N-1) + after Time -> + nor % Not Received end. forever() -> - timer:sleep(1000), + ok = timer:sleep(1000), forever(). @@ -343,7 +799,7 @@ performance(Mod) -> {Y,Mo,D} = date(), {H,M,S} = time(), io:format("Testing module '~p' Date: ~w/~w/~w ~w:~w:~w~n", - [Mod,Y,Mo,D,H,M,S]), + [Mod,Y,Mo,D,H,M,S]), Result = big_test(Mod), report_result(Result). @@ -367,15 +823,15 @@ wait([], Res, N, _) -> {Res, N}; wait(Pids, ResList, N, M) -> receive - {Pid, ok, Res, T} -> - wait(lists:delete(Pid, Pids), [{T, Res} | ResList], N, M); - {Pid, Error}-> - ct:fail(Error), - wait(lists:delete(Pid, Pids), ResList, N+1, M); - {'EXIT', Pid, normal} -> - wait(lists:delete(Pid, Pids), ResList, N, M); - {'EXIT', Pid, Reason} -> - ct:fail({Pid,Reason}) + {Pid, ok, Res, T} -> + wait(lists:delete(Pid, Pids), [{T, Res} | ResList], N, M); + {Pid, Error}-> + ct:fail(Error), + wait(lists:delete(Pid, Pids), ResList, N+1, M); + {'EXIT', Pid, normal} -> + wait(lists:delete(Pid, Pids), ResList, N, M); + {'EXIT', Pid, Reason} -> + ct:fail({Pid,Reason}) end. spawn_timers(0, _, _, _) -> @@ -390,13 +846,13 @@ timer(apply, Mod, T, Pid) -> Before = system_time(), {ok, Ref} = apply(Mod, apply_after, [T, ?MODULE, send, [self(), done]]), receive - done -> - After = system_time(), - Pid ! {self(), ok, (After-Before) div 1000, T} + done -> + After = system_time(), + Pid ! {self(), ok, (After-Before) div 1000, T} after T*3 + 300 -> % Watch dog - io:format("WARNING TIMER WATCHDOG timed out: ~w ~n", [T]), - timer:cancel(Ref), - Pid ! {self(), watch_dog_timed_out} + io:format("WARNING TIMER WATCHDOG timed out: ~w ~n", [T]), + {ok, cancel} = timer:cancel(Ref), + Pid ! {self(), watch_dog_timed_out} end. timer(interval, Mod, T, Pid, NumIter) -> @@ -412,17 +868,17 @@ timer_irec(_Start, T, {N, N}, Res, {Pid, Mod, Ref}) -> Pid ! {self(), ok, {N, Tot, Tot div N, Min, Max}, T}; timer_irec(Start, T, {N, Max}, Res, {Pid, Mod, Ref}) -> receive - done -> - Now = system_time(), - Elapsed = (Now - (Start + (N*T*1000))) div 1000, - timer_irec(Start, T, - {N+1, Max}, - [Elapsed | Res], - {Pid, Mod, Ref}) + done -> + Now = system_time(), + Elapsed = (Now - (Start + (N*T*1000))) div 1000, + timer_irec(Start, T, + {N+1, Max}, + [Elapsed | Res], + {Pid, Mod, Ref}) after T*3 + 300 -> - apply(Mod, cancel, [Ref]), - io:format("WARNING: TIMER WATCHDOG timed out ~w~n",[T]), - Pid ! {self(), timer_watchdog_timed_out_in_interlval_test} + apply(Mod, cancel, [Ref]), + io:format("WARNING: TIMER WATCHDOG timed out ~w~n",[T]), + Pid ! {self(), timer_watchdog_timed_out_in_interlval_test} end. %% ------------------------------------------------------- %% @@ -498,11 +954,11 @@ calc_a_val(List) -> New = lists:sort(List), {{T1, S}, {T2, M}, {T3, L}} = split(New), S2 = {length(S), lists:max(S), lists:min(S), - lists:sum(S) div length(S)}, + lists:sum(S) div length(S)}, M2 = {length(M), lists:max(M), lists:min(M), - lists:sum(M) div length(M)}, + lists:sum(M) div length(M)}, L2 = {length(L), lists:max(L), lists:min(L), - lists:sum(L) div length(L)}, + lists:sum(L) div length(L)}, [{T1, S2}, {T2, M2}, {T3, L2}]. calc_i_val(List) -> @@ -547,17 +1003,27 @@ print_aval([]) -> io:format("~n~n", []); print_aval([{T, {L, Max, Min, Aver}}|R]) -> io:format("~5w ~8w ~6w ~6w ~8w ~n", - [T,L,Max,Min,Aver]), + [T,L,Max,Min,Aver]), print_aval(R). print_ival([]) -> io:format("~n", []); print_ival([{T, {Len, Num, - {MaxT, MinT, AverT}, - {MaxI, MinI, AverI}}}|R]) -> + {MaxT, MinT, AverT}, + {MaxI, MinI, AverI}}}|R]) -> io:format("~5w ~6w ~10w ~8w ~6w ~6w ~6w ~6w ~6w~n", - [T,Len,Num,MaxT,MinT,AverT, MaxI, MinI, AverI]), + [T,Len,Num,MaxT,MinT,AverT, MaxI, MinI, AverI]), print_ival(R). send(Pid, Msg) -> Pid ! Msg. + +%% Create a unique name and register it to the given process. +register_name(Pid) -> + Name = make_name(), + register(Name, Pid), + Name. + +%% Create a unique name. +make_name() -> + list_to_atom(ref_to_list(make_ref())). diff --git a/lib/stdlib/test/tty.cover b/lib/stdlib/test/tty.cover new file mode 120000 index 000000000000..841833897bae --- /dev/null +++ b/lib/stdlib/test/tty.cover @@ -0,0 +1 @@ +../../../lib/kernel/test/tty.cover \ No newline at end of file diff --git a/lib/stdlib/test/unicode_util_SUITE.erl b/lib/stdlib/test/unicode_util_SUITE.erl index e4f3e5f3797b..42a119fba997 100644 --- a/lib/stdlib/test/unicode_util_SUITE.erl +++ b/lib/stdlib/test/unicode_util_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017-2020. All Rights Reserved. +%% Copyright Ericsson AB 2017-2023. 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. @@ -27,6 +27,7 @@ nfd/1, nfc/1, nfkd/1, nfkc/1, whitespace/1, get/1, + lookup/1, count/1]). -export([debug/0, id/1, bin_split/1, uc_loaded_size/0, @@ -45,6 +46,7 @@ all() -> nfd, nfc, nfkd, nfkc, whitespace, get, + lookup, count ]. @@ -90,7 +92,7 @@ casefold(_) -> whitespace(_) -> WS = unicode_util:whitespace(), WS = lists:filter(fun unicode_util:is_whitespace/1, WS), - %% TODO add more tests + false = unicode_util:is_whitespace($A), ok. cp(_) -> @@ -101,6 +103,15 @@ cp(_) -> "hejsan" = fetch(["hej"|<<"san">>], Get), {error, <<128>>} = Get(<<128>>), {error, [<<128>>, 0]} = Get([<<128>>, 0]), + + {'EXIT', _} = catch Get([-1]), + {'EXIT', _} = catch Get([-1, $a]), + {'EXIT', _} = catch Get([foo, $a]), + {'EXIT', _} = catch Get([-1, $a]), + {'EXIT', _} = catch Get([[], -1]), + {'EXIT', _} = catch Get([[-1], $a]), + {'EXIT', _} = catch Get([[-1, $a], $a]), + ok. gc(Config) -> @@ -113,6 +124,15 @@ gc(Config) -> {error, <<128>>} = Get(<<128>>), {error, [<<128>>, 0]} = Get([<<128>>, 0]), + {'EXIT', _} = catch Get([-1]), + {'EXIT', _} = catch Get([-1, $a]), + {'EXIT', _} = catch Get([foo, $a]), + {'EXIT', _} = catch Get([-1, $a]), + {'EXIT', _} = catch Get([[], -1]), + {'EXIT', _} = catch Get([[-1], $a]), + {'EXIT', _} = catch Get([[-1, $a], $a]), + {'EXIT', _} = catch Get([<<$a>>, [-1, $a], $a]), %% Current impl + 0 = fold(fun verify_gc/3, 0, DataDir ++ "/GraphemeBreakTest.txt"), ok. @@ -324,6 +344,29 @@ verify_nfkc(Data0, LineNo, _Acc) -> get(_) -> add_get_tests. +lookup(Config) -> + DataDir = proplists:get_value(data_dir, Config), + {ok, Bin} = file:read_file(filename:join(DataDir, "unicode_table.bin")), + 0 = check_category(0, binary_to_term(Bin), 0), + ok. + +check_category(Id, [{Id, {_, _, _, What}}|Rest], Es) -> + case maps:get(category, unicode_util:lookup(Id)) of + What -> check_category(Id+1, Rest, Es); + _Err -> + io:format("~w Exp: ~w Got ~w~n",[Id, What, _Err]), exit(_Err), + check_category(Id+1, Rest, Es+1) + end; +check_category(Id, [{Next,_}|_] = Rest, Es) -> + case maps:get(category, unicode_util:lookup(Id)) of + {other, not_assigned} -> check_category(max(Id+1,Next-1), Rest, Es); + Err -> io:format("~w Exp: {other, not_assigned} Got ~w~n",[Id,Err]), + check_category(max(Id+1,Next-1), Rest, Es+1) + end; +check_category(_Id, [], Es) -> + Es. + + count(Config) -> Parent = self(), Exec = fun() -> diff --git a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt index 5baf292a071a..3c73f97b7b82 100644 --- a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt +++ b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt @@ -1,11 +1,11 @@ -# GraphemeBreakTest-13.0.0.txt -# Date: 2019-11-15, 19:49:10 GMT -# © 2019 Unicode®, Inc. +# GraphemeBreakTest-15.0.0.txt +# Date: 2022-02-26, 00:38:37 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # Default Grapheme_Cluster_Break Test # diff --git a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt index d8666c458fc1..3122a2e21ec5 100644 --- a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt +++ b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt @@ -1,11 +1,11 @@ -# LineBreakTest-13.0.0.txt -# Date: 2019-11-21, 16:13:36 GMT -# © 2019 Unicode®, Inc. +# LineBreakTest-15.0.0.txt +# Date: 2022-02-26, 00:38:39 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # Default Line_Break Test # @@ -1846,9 +1846,9 @@ × AC00 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × AC00 × 0308 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × AC00 × 0308 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] -× AC00 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC00 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × AC00 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× AC00 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC00 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × AC00 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × AC00 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × AC00 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] @@ -2018,9 +2018,9 @@ × AC01 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × AC01 × 0308 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × AC01 × 0308 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] -× AC01 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC01 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × AC01 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× AC01 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC01 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × AC01 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × AC01 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × AC01 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] @@ -3050,9 +3050,9 @@ × 1100 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 1100 × 0308 ÷ 2329 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 1100 × 0308 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] -× 1100 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1100 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 1100 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 1100 × 0308 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1100 × 0308 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 1100 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 1100 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 1100 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] @@ -3222,9 +3222,9 @@ × 11A8 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 11A8 × 0308 ÷ 2329 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 11A8 × 0308 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] -× 11A8 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 11A8 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 11A8 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 11A8 × 0308 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 11A8 × 0308 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 11A8 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 11A8 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 11A8 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] @@ -3394,9 +3394,9 @@ × 1160 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 1160 × 0308 ÷ 2329 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] × 1160 × 0308 × 0020 ÷ 2329 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT-POINTING ANGLE BRACKET (OP) ÷ [0.3] -× 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 1160 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 1160 × 0308 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1160 × 0308 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] PERCENT SIGN (PO) ÷ [0.3] × 1160 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 1160 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 1160 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] @@ -4538,13 +4538,13 @@ × 0024 × 0020 ÷ 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0024 × 0308 × 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] × 0024 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0024 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0024 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0024 × 0020 ÷ AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0024 × 0308 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0024 × 0308 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0024 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0024 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0024 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0024 × 0020 ÷ AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0024 × 0308 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0024 × 0308 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0024 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0024 × 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0024 × 0020 ÷ 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] @@ -4566,17 +4566,17 @@ × 0024 × 0020 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0024 × 0308 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] × 0024 × 0308 × 0020 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0024 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0024 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0024 × 0020 ÷ 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0024 × 0308 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0024 × 0308 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0024 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0024 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0024 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0024 × 0020 ÷ 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0024 × 0308 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0024 × 0308 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0024 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0024 × 0020 ÷ 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0024 × 0308 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0024 × 0308 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0024 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0024 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [6.0] (LF) ÷ [0.3] × 0024 × 0020 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [6.0] (LF) ÷ [0.3] @@ -5838,9 +5838,9 @@ × 261D × 0020 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] × 261D × 0308 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] × 261D × 0308 × 0020 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] -× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.21] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] × 261D × 0020 ÷ 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] -× 261D × 0308 × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 0308 × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.21] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] × 261D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] × 261D × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.02] RIGHT PARENTHESIS (CP_CP30) ÷ [0.3] × 261D × 0020 × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP_CP30) ÷ [0.3] @@ -7452,9 +7452,9 @@ × 1160 × 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 11A8 × 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1160 × 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [22.0] ONE DOT LEADER (IN) ÷ [0.3] -× 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.01] PERCENT SIGN (PO) ÷ [0.3] +× 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.21] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] × 0066 × 0069 × 006E × 0061 × 006C ÷ # × [0.3] LATIN SMALL LETTER F (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER L (AL) ÷ [0.3] × 0063 × 0061 × 006E × 0027 × 0074 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [19.01] APOSTROPHE (QU) × [19.02] LATIN SMALL LETTER T (AL) ÷ [0.3] × 0063 × 0061 × 006E × 2019 × 0074 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [19.01] RIGHT SINGLE QUOTATION MARK (QU) × [19.02] LATIN SMALL LETTER T (AL) ÷ [0.3] @@ -7678,7 +7678,9 @@ × 1F1F7 × 1F1FA ÷ 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) ÷ [30.13] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] × 1F1F7 × 1F1FA × 200B ÷ 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [8.0] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.12] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] × 05D0 × 002D × 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.02] HYPHEN-MINUS (HY) × [21.1] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F02C × 1F3FF ÷ # × [0.3] (Other) × [30.22] EMOJI MODIFIER FITZPATRICK TYPE-6 (EM) ÷ [0.3] +× 00A9 ÷ 1F3FF ÷ # × [0.3] COPYRIGHT SIGN (AL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (EM) ÷ [0.3] # -# Lines: 7652 +# Lines: 7654 # # EOF diff --git a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt index fa9b0d954c81..e75b4801c9b1 100644 --- a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt +++ b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt @@ -1,11 +1,11 @@ -# NormalizationTest-13.0.0.txt -# Date: 2019-09-08, 23:31:12 GMT -# © 2019 Unicode®, Inc. +# NormalizationTest-15.0.0.txt +# Date: 2022-04-02, 01:29:09 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # Normalization Test Suite # Format: @@ -2409,6 +2409,9 @@ A69C;A69C;A69C;044A;044A; # (ꚜ; ꚜ; ꚜ; ъ; ъ; ) MODIFIER LETTER CYRILLIC HARD SIGN A69D;A69D;A69D;044C;044C; # (ꚝ; ꚝ; ꚝ; ь; ь; ) MODIFIER LETTER CYRILLIC SOFT SIGN A770;A770;A770;A76F;A76F; # (ꝰ; ꝰ; ꝰ; ꝯ; ꝯ; ) MODIFIER LETTER US +A7F2;A7F2;A7F2;0043;0043; # (ꟲ; ꟲ; ꟲ; C; C; ) MODIFIER LETTER CAPITAL C +A7F3;A7F3;A7F3;0046;0046; # (ꟳ; ꟳ; ꟳ; F; F; ) MODIFIER LETTER CAPITAL F +A7F4;A7F4;A7F4;0051;0051; # (ꟴ; ꟴ; ꟴ; Q; Q; ) MODIFIER LETTER CAPITAL Q A7F8;A7F8;A7F8;0126;0126; # (ꟸ; ꟸ; ꟸ; Ħ; Ħ; ) MODIFIER LETTER CAPITAL H WITH STROKE A7F9;A7F9;A7F9;0153;0153; # (ꟹ; ꟹ; ꟹ; œ; œ; ) MODIFIER LETTER SMALL LIGATURE OE AB5C;AB5C;AB5C;A727;A727; # (ꭜ; ꭜ; ꭜ; ꜧ; ꜧ; ) MODIFIER LETTER SMALL HENG @@ -15127,6 +15130,62 @@ FFEB;FFEB;FFEB;2192;2192; # (→; →; →; →; →; ) HALFWIDTH RIGHTWARDS ARR FFEC;FFEC;FFEC;2193;2193; # (↓; ↓; ↓; ↓; ↓; ) HALFWIDTH DOWNWARDS ARROW FFED;FFED;FFED;25A0;25A0; # (■; ■; ■; ■; ■; ) HALFWIDTH BLACK SQUARE FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE +10781;10781;10781;02D0;02D0; # (𐞁; 𐞁; 𐞁; ː; ː; ) MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON +10782;10782;10782;02D1;02D1; # (𐞂; 𐞂; 𐞂; ˑ; ˑ; ) MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON +10783;10783;10783;00E6;00E6; # (𐞃; 𐞃; 𐞃; æ; æ; ) MODIFIER LETTER SMALL AE +10784;10784;10784;0299;0299; # (𐞄; 𐞄; 𐞄; ʙ; ʙ; ) MODIFIER LETTER SMALL CAPITAL B +10785;10785;10785;0253;0253; # (𐞅; 𐞅; 𐞅; ɓ; ɓ; ) MODIFIER LETTER SMALL B WITH HOOK +10787;10787;10787;02A3;02A3; # (𐞇; 𐞇; 𐞇; ʣ; ʣ; ) MODIFIER LETTER SMALL DZ DIGRAPH +10788;10788;10788;AB66;AB66; # (𐞈; 𐞈; 𐞈; ꭦ; ꭦ; ) MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK +10789;10789;10789;02A5;02A5; # (𐞉; 𐞉; 𐞉; ʥ; ʥ; ) MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL +1078A;1078A;1078A;02A4;02A4; # (𐞊; 𐞊; 𐞊; ʤ; ʤ; ) MODIFIER LETTER SMALL DEZH DIGRAPH +1078B;1078B;1078B;0256;0256; # (𐞋; 𐞋; 𐞋; ɖ; ɖ; ) MODIFIER LETTER SMALL D WITH TAIL +1078C;1078C;1078C;0257;0257; # (𐞌; 𐞌; 𐞌; ɗ; ɗ; ) MODIFIER LETTER SMALL D WITH HOOK +1078D;1078D;1078D;1D91;1D91; # (𐞍; 𐞍; 𐞍; ᶑ; ᶑ; ) MODIFIER LETTER SMALL D WITH HOOK AND TAIL +1078E;1078E;1078E;0258;0258; # (𐞎; 𐞎; 𐞎; ɘ; ɘ; ) MODIFIER LETTER SMALL REVERSED E +1078F;1078F;1078F;025E;025E; # (𐞏; 𐞏; 𐞏; ɞ; ɞ; ) MODIFIER LETTER SMALL CLOSED REVERSED OPEN E +10790;10790;10790;02A9;02A9; # (𐞐; 𐞐; 𐞐; ʩ; ʩ; ) MODIFIER LETTER SMALL FENG DIGRAPH +10791;10791;10791;0264;0264; # (𐞑; 𐞑; 𐞑; ɤ; ɤ; ) MODIFIER LETTER SMALL RAMS HORN +10792;10792;10792;0262;0262; # (𐞒; 𐞒; 𐞒; ɢ; ɢ; ) MODIFIER LETTER SMALL CAPITAL G +10793;10793;10793;0260;0260; # (𐞓; 𐞓; 𐞓; ɠ; ɠ; ) MODIFIER LETTER SMALL G WITH HOOK +10794;10794;10794;029B;029B; # (𐞔; 𐞔; 𐞔; ʛ; ʛ; ) MODIFIER LETTER SMALL CAPITAL G WITH HOOK +10795;10795;10795;0127;0127; # (𐞕; 𐞕; 𐞕; ħ; ħ; ) MODIFIER LETTER SMALL H WITH STROKE +10796;10796;10796;029C;029C; # (𐞖; 𐞖; 𐞖; ʜ; ʜ; ) MODIFIER LETTER SMALL CAPITAL H +10797;10797;10797;0267;0267; # (𐞗; 𐞗; 𐞗; ɧ; ɧ; ) MODIFIER LETTER SMALL HENG WITH HOOK +10798;10798;10798;0284;0284; # (𐞘; 𐞘; 𐞘; ʄ; ʄ; ) MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK +10799;10799;10799;02AA;02AA; # (𐞙; 𐞙; 𐞙; ʪ; ʪ; ) MODIFIER LETTER SMALL LS DIGRAPH +1079A;1079A;1079A;02AB;02AB; # (𐞚; 𐞚; 𐞚; ʫ; ʫ; ) MODIFIER LETTER SMALL LZ DIGRAPH +1079B;1079B;1079B;026C;026C; # (𐞛; 𐞛; 𐞛; ɬ; ɬ; ) MODIFIER LETTER SMALL L WITH BELT +1079C;1079C;1079C;1DF04;1DF04; # (𐞜; 𐞜; 𐞜; 𝼄; 𝼄; ) MODIFIER LETTER SMALL CAPITAL L WITH BELT +1079D;1079D;1079D;A78E;A78E; # (𐞝; 𐞝; 𐞝; ꞎ; ꞎ; ) MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT +1079E;1079E;1079E;026E;026E; # (𐞞; 𐞞; 𐞞; ɮ; ɮ; ) MODIFIER LETTER SMALL LEZH +1079F;1079F;1079F;1DF05;1DF05; # (𐞟; 𐞟; 𐞟; 𝼅; 𝼅; ) MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK +107A0;107A0;107A0;028E;028E; # (𐞠; 𐞠; 𐞠; ʎ; ʎ; ) MODIFIER LETTER SMALL TURNED Y +107A1;107A1;107A1;1DF06;1DF06; # (𐞡; 𐞡; 𐞡; 𝼆; 𝼆; ) MODIFIER LETTER SMALL TURNED Y WITH BELT +107A2;107A2;107A2;00F8;00F8; # (𐞢; 𐞢; 𐞢; ø; ø; ) MODIFIER LETTER SMALL O WITH STROKE +107A3;107A3;107A3;0276;0276; # (𐞣; 𐞣; 𐞣; ɶ; ɶ; ) MODIFIER LETTER SMALL CAPITAL OE +107A4;107A4;107A4;0277;0277; # (𐞤; 𐞤; 𐞤; ɷ; ɷ; ) MODIFIER LETTER SMALL CLOSED OMEGA +107A5;107A5;107A5;0071;0071; # (𐞥; 𐞥; 𐞥; q; q; ) MODIFIER LETTER SMALL Q +107A6;107A6;107A6;027A;027A; # (𐞦; 𐞦; 𐞦; ɺ; ɺ; ) MODIFIER LETTER SMALL TURNED R WITH LONG LEG +107A7;107A7;107A7;1DF08;1DF08; # (𐞧; 𐞧; 𐞧; 𝼈; 𝼈; ) MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK +107A8;107A8;107A8;027D;027D; # (𐞨; 𐞨; 𐞨; ɽ; ɽ; ) MODIFIER LETTER SMALL R WITH TAIL +107A9;107A9;107A9;027E;027E; # (𐞩; 𐞩; 𐞩; ɾ; ɾ; ) MODIFIER LETTER SMALL R WITH FISHHOOK +107AA;107AA;107AA;0280;0280; # (𐞪; 𐞪; 𐞪; ʀ; ʀ; ) MODIFIER LETTER SMALL CAPITAL R +107AB;107AB;107AB;02A8;02A8; # (𐞫; 𐞫; 𐞫; ʨ; ʨ; ) MODIFIER LETTER SMALL TC DIGRAPH WITH CURL +107AC;107AC;107AC;02A6;02A6; # (𐞬; 𐞬; 𐞬; ʦ; ʦ; ) MODIFIER LETTER SMALL TS DIGRAPH +107AD;107AD;107AD;AB67;AB67; # (𐞭; 𐞭; 𐞭; ꭧ; ꭧ; ) MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK +107AE;107AE;107AE;02A7;02A7; # (𐞮; 𐞮; 𐞮; ʧ; ʧ; ) MODIFIER LETTER SMALL TESH DIGRAPH +107AF;107AF;107AF;0288;0288; # (𐞯; 𐞯; 𐞯; ʈ; ʈ; ) MODIFIER LETTER SMALL T WITH RETROFLEX HOOK +107B0;107B0;107B0;2C71;2C71; # (𐞰; 𐞰; 𐞰; ⱱ; ⱱ; ) MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2;107B2;107B2;028F;028F; # (𐞲; 𐞲; 𐞲; ʏ; ʏ; ) MODIFIER LETTER SMALL CAPITAL Y +107B3;107B3;107B3;02A1;02A1; # (𐞳; 𐞳; 𐞳; ʡ; ʡ; ) MODIFIER LETTER GLOTTAL STOP WITH STROKE +107B4;107B4;107B4;02A2;02A2; # (𐞴; 𐞴; 𐞴; ʢ; ʢ; ) MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE +107B5;107B5;107B5;0298;0298; # (𐞵; 𐞵; 𐞵; ʘ; ʘ; ) MODIFIER LETTER BILABIAL CLICK +107B6;107B6;107B6;01C0;01C0; # (𐞶; 𐞶; 𐞶; ǀ; ǀ; ) MODIFIER LETTER DENTAL CLICK +107B7;107B7;107B7;01C1;01C1; # (𐞷; 𐞷; 𐞷; ǁ; ǁ; ) MODIFIER LETTER LATERAL CLICK +107B8;107B8;107B8;01C2;01C2; # (𐞸; 𐞸; 𐞸; ǂ; ǂ; ) MODIFIER LETTER ALVEOLAR CLICK +107B9;107B9;107B9;1DF0A;1DF0A; # (𐞹; 𐞹; 𐞹; 𝼊; 𝼊; ) MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK +107BA;107BA;107BA;1DF1E;1DF1E; # (𐞺; 𐞺; 𐞺; 𝼞; 𝼞; ) MODIFIER LETTER SMALL S WITH CURL 1109A;1109A;11099 110BA;1109A;11099 110BA; # (𑂚; 𑂚; 𑂙◌𑂺; 𑂚; 𑂙◌𑂺; ) KAITHI LETTER DDDHA 1109C;1109C;1109B 110BA;1109C;1109B 110BA; # (𑂜; 𑂜; 𑂛◌𑂺; 𑂜; 𑂛◌𑂺; ) KAITHI LETTER RHA 110AB;110AB;110A5 110BA;110AB;110A5 110BA; # (𑂫; 𑂫; 𑂥◌𑂺; 𑂫; 𑂥◌𑂺; ) KAITHI LETTER VA @@ -16149,6 +16208,68 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 1D7FD;1D7FD;1D7FD;0037;0037; # (𝟽; 𝟽; 𝟽; 7; 7; ) MATHEMATICAL MONOSPACE DIGIT SEVEN 1D7FE;1D7FE;1D7FE;0038;0038; # (𝟾; 𝟾; 𝟾; 8; 8; ) MATHEMATICAL MONOSPACE DIGIT EIGHT 1D7FF;1D7FF;1D7FF;0039;0039; # (𝟿; 𝟿; 𝟿; 9; 9; ) MATHEMATICAL MONOSPACE DIGIT NINE +1E030;1E030;1E030;0430;0430; # (𞀰; 𞀰; 𞀰; а; а; ) MODIFIER LETTER CYRILLIC SMALL A +1E031;1E031;1E031;0431;0431; # (𞀱; 𞀱; 𞀱; б; б; ) MODIFIER LETTER CYRILLIC SMALL BE +1E032;1E032;1E032;0432;0432; # (𞀲; 𞀲; 𞀲; в; в; ) MODIFIER LETTER CYRILLIC SMALL VE +1E033;1E033;1E033;0433;0433; # (𞀳; 𞀳; 𞀳; г; г; ) MODIFIER LETTER CYRILLIC SMALL GHE +1E034;1E034;1E034;0434;0434; # (𞀴; 𞀴; 𞀴; д; д; ) MODIFIER LETTER CYRILLIC SMALL DE +1E035;1E035;1E035;0435;0435; # (𞀵; 𞀵; 𞀵; е; е; ) MODIFIER LETTER CYRILLIC SMALL IE +1E036;1E036;1E036;0436;0436; # (𞀶; 𞀶; 𞀶; ж; ж; ) MODIFIER LETTER CYRILLIC SMALL ZHE +1E037;1E037;1E037;0437;0437; # (𞀷; 𞀷; 𞀷; з; з; ) MODIFIER LETTER CYRILLIC SMALL ZE +1E038;1E038;1E038;0438;0438; # (𞀸; 𞀸; 𞀸; и; и; ) MODIFIER LETTER CYRILLIC SMALL I +1E039;1E039;1E039;043A;043A; # (𞀹; 𞀹; 𞀹; к; к; ) MODIFIER LETTER CYRILLIC SMALL KA +1E03A;1E03A;1E03A;043B;043B; # (𞀺; 𞀺; 𞀺; л; л; ) MODIFIER LETTER CYRILLIC SMALL EL +1E03B;1E03B;1E03B;043C;043C; # (𞀻; 𞀻; 𞀻; м; м; ) MODIFIER LETTER CYRILLIC SMALL EM +1E03C;1E03C;1E03C;043E;043E; # (𞀼; 𞀼; 𞀼; о; о; ) MODIFIER LETTER CYRILLIC SMALL O +1E03D;1E03D;1E03D;043F;043F; # (𞀽; 𞀽; 𞀽; п; п; ) MODIFIER LETTER CYRILLIC SMALL PE +1E03E;1E03E;1E03E;0440;0440; # (𞀾; 𞀾; 𞀾; р; р; ) MODIFIER LETTER CYRILLIC SMALL ER +1E03F;1E03F;1E03F;0441;0441; # (𞀿; 𞀿; 𞀿; с; с; ) MODIFIER LETTER CYRILLIC SMALL ES +1E040;1E040;1E040;0442;0442; # (𞁀; 𞁀; 𞁀; т; т; ) MODIFIER LETTER CYRILLIC SMALL TE +1E041;1E041;1E041;0443;0443; # (𞁁; 𞁁; 𞁁; у; у; ) MODIFIER LETTER CYRILLIC SMALL U +1E042;1E042;1E042;0444;0444; # (𞁂; 𞁂; 𞁂; ф; ф; ) MODIFIER LETTER CYRILLIC SMALL EF +1E043;1E043;1E043;0445;0445; # (𞁃; 𞁃; 𞁃; х; х; ) MODIFIER LETTER CYRILLIC SMALL HA +1E044;1E044;1E044;0446;0446; # (𞁄; 𞁄; 𞁄; ц; ц; ) MODIFIER LETTER CYRILLIC SMALL TSE +1E045;1E045;1E045;0447;0447; # (𞁅; 𞁅; 𞁅; ч; ч; ) MODIFIER LETTER CYRILLIC SMALL CHE +1E046;1E046;1E046;0448;0448; # (𞁆; 𞁆; 𞁆; ш; ш; ) MODIFIER LETTER CYRILLIC SMALL SHA +1E047;1E047;1E047;044B;044B; # (𞁇; 𞁇; 𞁇; ы; ы; ) MODIFIER LETTER CYRILLIC SMALL YERU +1E048;1E048;1E048;044D;044D; # (𞁈; 𞁈; 𞁈; э; э; ) MODIFIER LETTER CYRILLIC SMALL E +1E049;1E049;1E049;044E;044E; # (𞁉; 𞁉; 𞁉; ю; ю; ) MODIFIER LETTER CYRILLIC SMALL YU +1E04A;1E04A;1E04A;A689;A689; # (𞁊; 𞁊; 𞁊; ꚉ; ꚉ; ) MODIFIER LETTER CYRILLIC SMALL DZZE +1E04B;1E04B;1E04B;04D9;04D9; # (𞁋; 𞁋; 𞁋; ә; ә; ) MODIFIER LETTER CYRILLIC SMALL SCHWA +1E04C;1E04C;1E04C;0456;0456; # (𞁌; 𞁌; 𞁌; і; і; ) MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I +1E04D;1E04D;1E04D;0458;0458; # (𞁍; 𞁍; 𞁍; ј; ј; ) MODIFIER LETTER CYRILLIC SMALL JE +1E04E;1E04E;1E04E;04E9;04E9; # (𞁎; 𞁎; 𞁎; ө; ө; ) MODIFIER LETTER CYRILLIC SMALL BARRED O +1E04F;1E04F;1E04F;04AF;04AF; # (𞁏; 𞁏; 𞁏; ү; ү; ) MODIFIER LETTER CYRILLIC SMALL STRAIGHT U +1E050;1E050;1E050;04CF;04CF; # (𞁐; 𞁐; 𞁐; ӏ; ӏ; ) MODIFIER LETTER CYRILLIC SMALL PALOCHKA +1E051;1E051;1E051;0430;0430; # (𞁑; 𞁑; 𞁑; а; а; ) CYRILLIC SUBSCRIPT SMALL LETTER A +1E052;1E052;1E052;0431;0431; # (𞁒; 𞁒; 𞁒; б; б; ) CYRILLIC SUBSCRIPT SMALL LETTER BE +1E053;1E053;1E053;0432;0432; # (𞁓; 𞁓; 𞁓; в; в; ) CYRILLIC SUBSCRIPT SMALL LETTER VE +1E054;1E054;1E054;0433;0433; # (𞁔; 𞁔; 𞁔; г; г; ) CYRILLIC SUBSCRIPT SMALL LETTER GHE +1E055;1E055;1E055;0434;0434; # (𞁕; 𞁕; 𞁕; д; д; ) CYRILLIC SUBSCRIPT SMALL LETTER DE +1E056;1E056;1E056;0435;0435; # (𞁖; 𞁖; 𞁖; е; е; ) CYRILLIC SUBSCRIPT SMALL LETTER IE +1E057;1E057;1E057;0436;0436; # (𞁗; 𞁗; 𞁗; ж; ж; ) CYRILLIC SUBSCRIPT SMALL LETTER ZHE +1E058;1E058;1E058;0437;0437; # (𞁘; 𞁘; 𞁘; з; з; ) CYRILLIC SUBSCRIPT SMALL LETTER ZE +1E059;1E059;1E059;0438;0438; # (𞁙; 𞁙; 𞁙; и; и; ) CYRILLIC SUBSCRIPT SMALL LETTER I +1E05A;1E05A;1E05A;043A;043A; # (𞁚; 𞁚; 𞁚; к; к; ) CYRILLIC SUBSCRIPT SMALL LETTER KA +1E05B;1E05B;1E05B;043B;043B; # (𞁛; 𞁛; 𞁛; л; л; ) CYRILLIC SUBSCRIPT SMALL LETTER EL +1E05C;1E05C;1E05C;043E;043E; # (𞁜; 𞁜; 𞁜; о; о; ) CYRILLIC SUBSCRIPT SMALL LETTER O +1E05D;1E05D;1E05D;043F;043F; # (𞁝; 𞁝; 𞁝; п; п; ) CYRILLIC SUBSCRIPT SMALL LETTER PE +1E05E;1E05E;1E05E;0441;0441; # (𞁞; 𞁞; 𞁞; с; с; ) CYRILLIC SUBSCRIPT SMALL LETTER ES +1E05F;1E05F;1E05F;0443;0443; # (𞁟; 𞁟; 𞁟; у; у; ) CYRILLIC SUBSCRIPT SMALL LETTER U +1E060;1E060;1E060;0444;0444; # (𞁠; 𞁠; 𞁠; ф; ф; ) CYRILLIC SUBSCRIPT SMALL LETTER EF +1E061;1E061;1E061;0445;0445; # (𞁡; 𞁡; 𞁡; х; х; ) CYRILLIC SUBSCRIPT SMALL LETTER HA +1E062;1E062;1E062;0446;0446; # (𞁢; 𞁢; 𞁢; ц; ц; ) CYRILLIC SUBSCRIPT SMALL LETTER TSE +1E063;1E063;1E063;0447;0447; # (𞁣; 𞁣; 𞁣; ч; ч; ) CYRILLIC SUBSCRIPT SMALL LETTER CHE +1E064;1E064;1E064;0448;0448; # (𞁤; 𞁤; 𞁤; ш; ш; ) CYRILLIC SUBSCRIPT SMALL LETTER SHA +1E065;1E065;1E065;044A;044A; # (𞁥; 𞁥; 𞁥; ъ; ъ; ) CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN +1E066;1E066;1E066;044B;044B; # (𞁦; 𞁦; 𞁦; ы; ы; ) CYRILLIC SUBSCRIPT SMALL LETTER YERU +1E067;1E067;1E067;0491;0491; # (𞁧; 𞁧; 𞁧; ґ; ґ; ) CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN +1E068;1E068;1E068;0456;0456; # (𞁨; 𞁨; 𞁨; і; і; ) CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I +1E069;1E069;1E069;0455;0455; # (𞁩; 𞁩; 𞁩; ѕ; ѕ; ) CYRILLIC SUBSCRIPT SMALL LETTER DZE +1E06A;1E06A;1E06A;045F;045F; # (𞁪; 𞁪; 𞁪; џ; џ; ) CYRILLIC SUBSCRIPT SMALL LETTER DZHE +1E06B;1E06B;1E06B;04AB;04AB; # (𞁫; 𞁫; 𞁫; ҫ; ҫ; ) MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER +1E06C;1E06C;1E06C;A651;A651; # (𞁬; 𞁬; 𞁬; ꙑ; ꙑ; ) MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER +1E06D;1E06D;1E06D;04B1;04B1; # (𞁭; 𞁭; 𞁭; ұ; ұ; ) MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE 1EE00;1EE00;1EE00;0627;0627; # (𞸀; 𞸀; 𞸀; ا; ا; ) ARABIC MATHEMATICAL ALEF 1EE01;1EE01;1EE01;0628;0628; # (𞸁; 𞸁; 𞸁; ب; ب; ) ARABIC MATHEMATICAL BEH 1EE02;1EE02;1EE02;062C;062C; # (𞸂; 𞸂; 𞸂; ج; ج; ) ARABIC MATHEMATICAL JEEM @@ -17025,66 +17146,66 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0314 0315 0300 05AE 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062;0061 05AE 0314 0300 0315 0062; # (a◌̔◌̕◌̀◌֮b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; a◌֮◌̔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING REVERSED COMMA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 035C 0315 0300 0315 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062; # (a◌͜◌̕◌̀◌̕b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B 0061 0315 035C 0315 0300 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062;00E0 0315 0315 035C 0062;0061 0300 0315 0315 035C 0062; # (a◌̕◌͜◌̕◌̀b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; à◌̕◌̕◌͜b; a◌̀◌̕◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B -0061 059A 0316 302A 0316 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062; # (a◌֚◌̖◌〪◌̖b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B -0061 0316 059A 0316 302A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062;0061 302A 0316 0316 059A 0062; # (a◌̖◌֚◌̖◌〪b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; a◌〪◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0317 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062;0061 302A 0316 0317 059A 0062; # (a◌֚◌̖◌〪◌̗b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; a◌〪◌̖◌̗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ACUTE ACCENT BELOW, LATIN SMALL LETTER B -0061 0317 059A 0316 302A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062;0061 302A 0317 0316 059A 0062; # (a◌̗◌֚◌̖◌〪b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; a◌〪◌̗◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0318 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062;0061 302A 0316 0318 059A 0062; # (a◌֚◌̖◌〪◌̘b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; a◌〪◌̖◌̘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT TACK BELOW, LATIN SMALL LETTER B -0061 0318 059A 0316 302A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062;0061 302A 0318 0316 059A 0062; # (a◌̘◌֚◌̖◌〪b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; a◌〪◌̘◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0319 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062;0061 302A 0316 0319 059A 0062; # (a◌֚◌̖◌〪◌̙b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; a◌〪◌̖◌̙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT TACK BELOW, LATIN SMALL LETTER B -0061 0319 059A 0316 302A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062;0061 302A 0319 0316 059A 0062; # (a◌̙◌֚◌̖◌〪b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; a◌〪◌̙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0316 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062; # (a◌֚◌̖◌᷺◌̖b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B +0061 0316 059A 0316 1DFA 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062;0061 1DFA 0316 0316 059A 0062; # (a◌̖◌֚◌̖◌᷺b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; a◌᷺◌̖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0317 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062;0061 1DFA 0316 0317 059A 0062; # (a◌֚◌̖◌᷺◌̗b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; a◌᷺◌̖◌̗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ACUTE ACCENT BELOW, LATIN SMALL LETTER B +0061 0317 059A 0316 1DFA 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062;0061 1DFA 0317 0316 059A 0062; # (a◌̗◌֚◌̖◌᷺b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; a◌᷺◌̗◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ACUTE ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0318 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062;0061 1DFA 0316 0318 059A 0062; # (a◌֚◌̖◌᷺◌̘b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; a◌᷺◌̖◌̘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT TACK BELOW, LATIN SMALL LETTER B +0061 0318 059A 0316 1DFA 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062;0061 1DFA 0318 0316 059A 0062; # (a◌̘◌֚◌̖◌᷺b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; a◌᷺◌̘◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0319 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062;0061 1DFA 0316 0319 059A 0062; # (a◌֚◌̖◌᷺◌̙b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; a◌᷺◌̖◌̙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT TACK BELOW, LATIN SMALL LETTER B +0061 0319 059A 0316 1DFA 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062;0061 1DFA 0319 0316 059A 0062; # (a◌̙◌֚◌̖◌᷺b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; a◌᷺◌̙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 035C 0315 0300 031A 0062;00E0 0315 031A 035C 0062;0061 0300 0315 031A 035C 0062;00E0 0315 031A 035C 0062;0061 0300 0315 031A 035C 0062; # (a◌͜◌̕◌̀◌̚b; à◌̕◌̚◌͜b; a◌̀◌̕◌̚◌͜b; à◌̕◌̚◌͜b; a◌̀◌̕◌̚◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING LEFT ANGLE ABOVE, LATIN SMALL LETTER B 0061 031A 035C 0315 0300 0062;00E0 031A 0315 035C 0062;0061 0300 031A 0315 035C 0062;00E0 031A 0315 035C 0062;0061 0300 031A 0315 035C 0062; # (a◌̚◌͜◌̕◌̀b; à◌̚◌̕◌͜b; a◌̀◌̚◌̕◌͜b; à◌̚◌̕◌͜b; a◌̀◌̚◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE ABOVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B -0061 302A 031B 1DCE 031B 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062; # (a◌〪◌̛◌᷎◌̛b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING HORN, LATIN SMALL LETTER B -0061 031B 302A 031B 1DCE 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062;0061 1DCE 031B 031B 302A 0062; # (a◌̛◌〪◌̛◌᷎b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; a◌᷎◌̛◌̛◌〪b; ) LATIN SMALL LETTER A, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 059A 0316 302A 031C 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062;0061 302A 0316 031C 059A 0062; # (a◌֚◌̖◌〪◌̜b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; a◌〪◌̖◌̜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT HALF RING BELOW, LATIN SMALL LETTER B -0061 031C 059A 0316 302A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062;0061 302A 031C 0316 059A 0062; # (a◌̜◌֚◌̖◌〪b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; a◌〪◌̜◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 031D 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062;0061 302A 0316 031D 059A 0062; # (a◌֚◌̖◌〪◌̝b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; a◌〪◌̖◌̝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING UP TACK BELOW, LATIN SMALL LETTER B -0061 031D 059A 0316 302A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062;0061 302A 031D 0316 059A 0062; # (a◌̝◌֚◌̖◌〪b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; a◌〪◌̝◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UP TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 031E 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062;0061 302A 0316 031E 059A 0062; # (a◌֚◌̖◌〪◌̞b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; a◌〪◌̖◌̞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOWN TACK BELOW, LATIN SMALL LETTER B -0061 031E 059A 0316 302A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062;0061 302A 031E 0316 059A 0062; # (a◌̞◌֚◌̖◌〪b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; a◌〪◌̞◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOWN TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 031F 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062;0061 302A 0316 031F 059A 0062; # (a◌֚◌̖◌〪◌̟b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; a◌〪◌̖◌̟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING PLUS SIGN BELOW, LATIN SMALL LETTER B -0061 031F 059A 0316 302A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062;0061 302A 031F 0316 059A 0062; # (a◌̟◌֚◌̖◌〪b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; a◌〪◌̟◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0320 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062;0061 302A 0316 0320 059A 0062; # (a◌֚◌̖◌〪◌̠b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; a◌〪◌̖◌̠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MINUS SIGN BELOW, LATIN SMALL LETTER B -0061 0320 059A 0316 302A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062;0061 302A 0320 0316 059A 0062; # (a◌̠◌֚◌̖◌〪b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; a◌〪◌̠◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MINUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 031B 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062; # (a◌᷺◌̛◌᷎◌̛b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING HORN, LATIN SMALL LETTER B +0061 031B 1DFA 031B 1DCE 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062;0061 1DCE 031B 031B 1DFA 0062; # (a◌̛◌᷺◌̛◌᷎b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; a◌᷎◌̛◌̛◌᷺b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031C 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062;0061 1DFA 0316 031C 059A 0062; # (a◌֚◌̖◌᷺◌̜b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; a◌᷺◌̖◌̜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT HALF RING BELOW, LATIN SMALL LETTER B +0061 031C 059A 0316 1DFA 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062;0061 1DFA 031C 0316 059A 0062; # (a◌̜◌֚◌̖◌᷺b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; a◌᷺◌̜◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031D 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062;0061 1DFA 0316 031D 059A 0062; # (a◌֚◌̖◌᷺◌̝b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; a◌᷺◌̖◌̝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING UP TACK BELOW, LATIN SMALL LETTER B +0061 031D 059A 0316 1DFA 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062;0061 1DFA 031D 0316 059A 0062; # (a◌̝◌֚◌̖◌᷺b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; a◌᷺◌̝◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UP TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031E 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062;0061 1DFA 0316 031E 059A 0062; # (a◌֚◌̖◌᷺◌̞b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; a◌᷺◌̖◌̞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOWN TACK BELOW, LATIN SMALL LETTER B +0061 031E 059A 0316 1DFA 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062;0061 1DFA 031E 0316 059A 0062; # (a◌̞◌֚◌̖◌᷺b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; a◌᷺◌̞◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOWN TACK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 031F 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062;0061 1DFA 0316 031F 059A 0062; # (a◌֚◌̖◌᷺◌̟b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; a◌᷺◌̖◌̟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING PLUS SIGN BELOW, LATIN SMALL LETTER B +0061 031F 059A 0316 1DFA 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062;0061 1DFA 031F 0316 059A 0062; # (a◌̟◌֚◌̖◌᷺b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; a◌᷺◌̟◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0320 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062;0061 1DFA 0316 0320 059A 0062; # (a◌֚◌̖◌᷺◌̠b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; a◌᷺◌̖◌̠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MINUS SIGN BELOW, LATIN SMALL LETTER B +0061 0320 059A 0316 1DFA 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062;0061 1DFA 0320 0316 059A 0062; # (a◌̠◌֚◌̖◌᷺b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; a◌᷺◌̠◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MINUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 1DCE 0321 0F74 0321 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062; # (a◌᷎◌̡◌ུ◌̡b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B 0061 0321 1DCE 0321 0F74 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062;0061 0F74 0321 0321 1DCE 0062; # (a◌̡◌᷎◌̡◌ུb; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; a◌ུ◌̡◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING PALATALIZED HOOK BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B 0061 1DCE 0321 0F74 0322 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062;0061 0F74 0321 0322 1DCE 0062; # (a◌᷎◌̡◌ུ◌̢b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; a◌ུ◌̡◌̢◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING RETROFLEX HOOK BELOW, LATIN SMALL LETTER B 0061 0322 1DCE 0321 0F74 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062;0061 0F74 0322 0321 1DCE 0062; # (a◌̢◌᷎◌̡◌ུb; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; a◌ུ◌̢◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING RETROFLEX HOOK BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B -0061 059A 0316 302A 0323 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062;0061 302A 0316 0323 059A 0062; # (a◌֚◌̖◌〪◌̣b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; a◌〪◌̖◌̣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOT BELOW, LATIN SMALL LETTER B -0061 0323 059A 0316 302A 0062;1EA1 302A 0316 059A 0062;0061 302A 0323 0316 059A 0062;1EA1 302A 0316 059A 0062;0061 302A 0323 0316 059A 0062; # (a◌̣◌֚◌̖◌〪b; ạ◌〪◌̖◌֚b; a◌〪◌̣◌̖◌֚b; ạ◌〪◌̖◌֚b; a◌〪◌̣◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0324 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062;0061 302A 0316 0324 059A 0062; # (a◌֚◌̖◌〪◌̤b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; a◌〪◌̖◌̤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DIAERESIS BELOW, LATIN SMALL LETTER B -0061 0324 059A 0316 302A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062;0061 302A 0324 0316 059A 0062; # (a◌̤◌֚◌̖◌〪b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; a◌〪◌̤◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0325 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062;0061 302A 0316 0325 059A 0062; # (a◌֚◌̖◌〪◌̥b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; a◌〪◌̖◌̥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RING BELOW, LATIN SMALL LETTER B -0061 0325 059A 0316 302A 0062;1E01 302A 0316 059A 0062;0061 302A 0325 0316 059A 0062;1E01 302A 0316 059A 0062;0061 302A 0325 0316 059A 0062; # (a◌̥◌֚◌̖◌〪b; ḁ◌〪◌̖◌֚b; a◌〪◌̥◌̖◌֚b; ḁ◌〪◌̖◌֚b; a◌〪◌̥◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0326 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062;0061 302A 0316 0326 059A 0062; # (a◌֚◌̖◌〪◌̦b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; a◌〪◌̖◌̦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING COMMA BELOW, LATIN SMALL LETTER B -0061 0326 059A 0316 302A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062;0061 302A 0326 0316 059A 0062; # (a◌̦◌֚◌̖◌〪b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; a◌〪◌̦◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING COMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0323 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062;0061 1DFA 0316 0323 059A 0062; # (a◌֚◌̖◌᷺◌̣b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; a◌᷺◌̖◌̣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 0323 059A 0316 1DFA 0062;1EA1 1DFA 0316 059A 0062;0061 1DFA 0323 0316 059A 0062;1EA1 1DFA 0316 059A 0062;0061 1DFA 0323 0316 059A 0062; # (a◌̣◌֚◌̖◌᷺b; ạ◌᷺◌̖◌֚b; a◌᷺◌̣◌̖◌֚b; ạ◌᷺◌̖◌֚b; a◌᷺◌̣◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0324 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062;0061 1DFA 0316 0324 059A 0062; # (a◌֚◌̖◌᷺◌̤b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; a◌᷺◌̖◌̤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DIAERESIS BELOW, LATIN SMALL LETTER B +0061 0324 059A 0316 1DFA 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062;0061 1DFA 0324 0316 059A 0062; # (a◌̤◌֚◌̖◌᷺b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; a◌᷺◌̤◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DIAERESIS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0325 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062;0061 1DFA 0316 0325 059A 0062; # (a◌֚◌̖◌᷺◌̥b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; a◌᷺◌̖◌̥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RING BELOW, LATIN SMALL LETTER B +0061 0325 059A 0316 1DFA 0062;1E01 1DFA 0316 059A 0062;0061 1DFA 0325 0316 059A 0062;1E01 1DFA 0316 059A 0062;0061 1DFA 0325 0316 059A 0062; # (a◌̥◌֚◌̖◌᷺b; ḁ◌᷺◌̖◌֚b; a◌᷺◌̥◌̖◌֚b; ḁ◌᷺◌̖◌֚b; a◌᷺◌̥◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0326 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062;0061 1DFA 0316 0326 059A 0062; # (a◌֚◌̖◌᷺◌̦b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; a◌᷺◌̖◌̦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING COMMA BELOW, LATIN SMALL LETTER B +0061 0326 059A 0316 1DFA 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062;0061 1DFA 0326 0316 059A 0062; # (a◌̦◌֚◌̖◌᷺b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; a◌᷺◌̦◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING COMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 1DCE 0321 0F74 0327 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062;0061 0F74 0321 0327 1DCE 0062; # (a◌᷎◌̡◌ུ◌̧b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; a◌ུ◌̡◌̧◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING CEDILLA, LATIN SMALL LETTER B 0061 0327 1DCE 0321 0F74 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062;0061 0F74 0327 0321 1DCE 0062; # (a◌̧◌᷎◌̡◌ུb; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; a◌ུ◌̧◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING CEDILLA, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B 0061 1DCE 0321 0F74 0328 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062;0061 0F74 0321 0328 1DCE 0062; # (a◌᷎◌̡◌ུ◌̨b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; a◌ུ◌̡◌̨◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING OGONEK, LATIN SMALL LETTER B 0061 0328 1DCE 0321 0F74 0062;0105 0F74 0321 1DCE 0062;0061 0F74 0328 0321 1DCE 0062;0105 0F74 0321 1DCE 0062;0061 0F74 0328 0321 1DCE 0062; # (a◌̨◌᷎◌̡◌ུb; ą◌ུ◌̡◌᷎b; a◌ུ◌̨◌̡◌᷎b; ą◌ུ◌̡◌᷎b; a◌ུ◌̨◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B -0061 059A 0316 302A 0329 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062;0061 302A 0316 0329 059A 0062; # (a◌֚◌̖◌〪◌̩b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; a◌〪◌̖◌̩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING VERTICAL LINE BELOW, LATIN SMALL LETTER B -0061 0329 059A 0316 302A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062;0061 302A 0329 0316 059A 0062; # (a◌̩◌֚◌̖◌〪b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; a◌〪◌̩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062;0061 302A 0316 032A 059A 0062; # (a◌֚◌̖◌〪◌̪b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; a◌〪◌̖◌̪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING BRIDGE BELOW, LATIN SMALL LETTER B -0061 032A 059A 0316 302A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062;0061 302A 032A 0316 059A 0062; # (a◌̪◌֚◌̖◌〪b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; a◌〪◌̪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032B 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062;0061 302A 0316 032B 059A 0062; # (a◌֚◌̖◌〪◌̫b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; a◌〪◌̖◌̫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED DOUBLE ARCH BELOW, LATIN SMALL LETTER B -0061 032B 059A 0316 302A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062;0061 302A 032B 0316 059A 0062; # (a◌̫◌֚◌̖◌〪b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; a◌〪◌̫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032C 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062;0061 302A 0316 032C 059A 0062; # (a◌֚◌̖◌〪◌̬b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; a◌〪◌̖◌̬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CARON BELOW, LATIN SMALL LETTER B -0061 032C 059A 0316 302A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062;0061 302A 032C 0316 059A 0062; # (a◌̬◌֚◌̖◌〪b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; a◌〪◌̬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CARON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032D 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062;0061 302A 0316 032D 059A 0062; # (a◌֚◌̖◌〪◌̭b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; a◌〪◌̖◌̭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CIRCUMFLEX ACCENT BELOW, LATIN SMALL LETTER B -0061 032D 059A 0316 302A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062;0061 302A 032D 0316 059A 0062; # (a◌̭◌֚◌̖◌〪b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; a◌〪◌̭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032E 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062;0061 302A 0316 032E 059A 0062; # (a◌֚◌̖◌〪◌̮b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; a◌〪◌̖◌̮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING BREVE BELOW, LATIN SMALL LETTER B -0061 032E 059A 0316 302A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062;0061 302A 032E 0316 059A 0062; # (a◌̮◌֚◌̖◌〪b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; a◌〪◌̮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 032F 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062;0061 302A 0316 032F 059A 0062; # (a◌֚◌̖◌〪◌̯b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; a◌〪◌̖◌̯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED BREVE BELOW, LATIN SMALL LETTER B -0061 032F 059A 0316 302A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062;0061 302A 032F 0316 059A 0062; # (a◌̯◌֚◌̖◌〪b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; a◌〪◌̯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0330 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062;0061 302A 0316 0330 059A 0062; # (a◌֚◌̖◌〪◌̰b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; a◌〪◌̖◌̰◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TILDE BELOW, LATIN SMALL LETTER B -0061 0330 059A 0316 302A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062;0061 302A 0330 0316 059A 0062; # (a◌̰◌֚◌̖◌〪b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; a◌〪◌̰◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0331 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062;0061 302A 0316 0331 059A 0062; # (a◌֚◌̖◌〪◌̱b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; a◌〪◌̖◌̱◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MACRON BELOW, LATIN SMALL LETTER B -0061 0331 059A 0316 302A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062;0061 302A 0331 0316 059A 0062; # (a◌̱◌֚◌̖◌〪b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; a◌〪◌̱◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0332 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062;0061 302A 0316 0332 059A 0062; # (a◌֚◌̖◌〪◌̲b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; a◌〪◌̖◌̲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LOW LINE, LATIN SMALL LETTER B -0061 0332 059A 0316 302A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062;0061 302A 0332 0316 059A 0062; # (a◌̲◌֚◌̖◌〪b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; a◌〪◌̲◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0333 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062;0061 302A 0316 0333 059A 0062; # (a◌֚◌̖◌〪◌̳b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; a◌〪◌̖◌̳◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE LOW LINE, LATIN SMALL LETTER B -0061 0333 059A 0316 302A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062;0061 302A 0333 0316 059A 0062; # (a◌̳◌֚◌̖◌〪b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; a◌〪◌̳◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0329 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062;0061 1DFA 0316 0329 059A 0062; # (a◌֚◌̖◌᷺◌̩b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; a◌᷺◌̖◌̩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0329 059A 0316 1DFA 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062;0061 1DFA 0329 0316 059A 0062; # (a◌̩◌֚◌̖◌᷺b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; a◌᷺◌̩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062;0061 1DFA 0316 032A 059A 0062; # (a◌֚◌̖◌᷺◌̪b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; a◌᷺◌̖◌̪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING BRIDGE BELOW, LATIN SMALL LETTER B +0061 032A 059A 0316 1DFA 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062;0061 1DFA 032A 0316 059A 0062; # (a◌̪◌֚◌̖◌᷺b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; a◌᷺◌̪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032B 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062;0061 1DFA 0316 032B 059A 0062; # (a◌֚◌̖◌᷺◌̫b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; a◌᷺◌̖◌̫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED DOUBLE ARCH BELOW, LATIN SMALL LETTER B +0061 032B 059A 0316 1DFA 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062;0061 1DFA 032B 0316 059A 0062; # (a◌̫◌֚◌̖◌᷺b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; a◌᷺◌̫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032C 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062;0061 1DFA 0316 032C 059A 0062; # (a◌֚◌̖◌᷺◌̬b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; a◌᷺◌̖◌̬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CARON BELOW, LATIN SMALL LETTER B +0061 032C 059A 0316 1DFA 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062;0061 1DFA 032C 0316 059A 0062; # (a◌̬◌֚◌̖◌᷺b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; a◌᷺◌̬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CARON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032D 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062;0061 1DFA 0316 032D 059A 0062; # (a◌֚◌̖◌᷺◌̭b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; a◌᷺◌̖◌̭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CIRCUMFLEX ACCENT BELOW, LATIN SMALL LETTER B +0061 032D 059A 0316 1DFA 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062;0061 1DFA 032D 0316 059A 0062; # (a◌̭◌֚◌̖◌᷺b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; a◌᷺◌̭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CIRCUMFLEX ACCENT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032E 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062;0061 1DFA 0316 032E 059A 0062; # (a◌֚◌̖◌᷺◌̮b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; a◌᷺◌̖◌̮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING BREVE BELOW, LATIN SMALL LETTER B +0061 032E 059A 0316 1DFA 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062;0061 1DFA 032E 0316 059A 0062; # (a◌̮◌֚◌̖◌᷺b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; a◌᷺◌̮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 032F 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062;0061 1DFA 0316 032F 059A 0062; # (a◌֚◌̖◌᷺◌̯b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; a◌᷺◌̖◌̯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED BREVE BELOW, LATIN SMALL LETTER B +0061 032F 059A 0316 1DFA 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062;0061 1DFA 032F 0316 059A 0062; # (a◌̯◌֚◌̖◌᷺b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; a◌᷺◌̯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BREVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0330 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062;0061 1DFA 0316 0330 059A 0062; # (a◌֚◌̖◌᷺◌̰b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; a◌᷺◌̖◌̰◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE BELOW, LATIN SMALL LETTER B +0061 0330 059A 0316 1DFA 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062;0061 1DFA 0330 0316 059A 0062; # (a◌̰◌֚◌̖◌᷺b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; a◌᷺◌̰◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0331 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062;0061 1DFA 0316 0331 059A 0062; # (a◌֚◌̖◌᷺◌̱b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; a◌᷺◌̖◌̱◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON BELOW, LATIN SMALL LETTER B +0061 0331 059A 0316 1DFA 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062;0061 1DFA 0331 0316 059A 0062; # (a◌̱◌֚◌̖◌᷺b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; a◌᷺◌̱◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0332 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062;0061 1DFA 0316 0332 059A 0062; # (a◌֚◌̖◌᷺◌̲b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; a◌᷺◌̖◌̲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LOW LINE, LATIN SMALL LETTER B +0061 0332 059A 0316 1DFA 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062;0061 1DFA 0332 0316 059A 0062; # (a◌̲◌֚◌̖◌᷺b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; a◌᷺◌̲◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0333 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062;0061 1DFA 0316 0333 059A 0062; # (a◌֚◌̖◌᷺◌̳b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; a◌᷺◌̖◌̳◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE LOW LINE, LATIN SMALL LETTER B +0061 0333 059A 0316 1DFA 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062;0061 1DFA 0333 0316 059A 0062; # (a◌̳◌֚◌̖◌᷺b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; a◌᷺◌̳◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE LOW LINE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 16FF0 0334 0334 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062; # (a𖿰◌̴◌̴b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 0334 16FF0 0334 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062;0061 0334 0334 16FF0 0062; # (a◌̴𖿰◌̴b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; a◌̴◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING TILDE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 0335 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062;0061 0334 0335 16FF0 0062; # (a𖿰◌̴◌̵b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; a◌̴◌̵𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING SHORT STROKE OVERLAY, LATIN SMALL LETTER B @@ -17095,14 +17216,14 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0337 16FF0 0334 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062;0061 0337 0334 16FF0 0062; # (a◌̷𖿰◌̴b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; a◌̷◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING SHORT SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 0338 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062;0061 0334 0338 16FF0 0062; # (a𖿰◌̴◌̸b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; a◌̴◌̸𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG SOLIDUS OVERLAY, LATIN SMALL LETTER B 0061 0338 16FF0 0334 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062;0061 0338 0334 16FF0 0062; # (a◌̸𖿰◌̴b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; a◌̸◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 059A 0316 302A 0339 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062;0061 302A 0316 0339 059A 0062; # (a◌֚◌̖◌〪◌̹b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; a◌〪◌̖◌̹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT HALF RING BELOW, LATIN SMALL LETTER B -0061 0339 059A 0316 302A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062;0061 302A 0339 0316 059A 0062; # (a◌̹◌֚◌̖◌〪b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; a◌〪◌̹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 033A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062;0061 302A 0316 033A 059A 0062; # (a◌֚◌̖◌〪◌̺b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; a◌〪◌̖◌̺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING INVERTED BRIDGE BELOW, LATIN SMALL LETTER B -0061 033A 059A 0316 302A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062;0061 302A 033A 0316 059A 0062; # (a◌̺◌֚◌̖◌〪b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; a◌〪◌̺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 033B 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062;0061 302A 0316 033B 059A 0062; # (a◌֚◌̖◌〪◌̻b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; a◌〪◌̖◌̻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING SQUARE BELOW, LATIN SMALL LETTER B -0061 033B 059A 0316 302A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062;0061 302A 033B 0316 059A 0062; # (a◌̻◌֚◌̖◌〪b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; a◌〪◌̻◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SQUARE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 033C 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062;0061 302A 0316 033C 059A 0062; # (a◌֚◌̖◌〪◌̼b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; a◌〪◌̖◌̼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING SEAGULL BELOW, LATIN SMALL LETTER B -0061 033C 059A 0316 302A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062;0061 302A 033C 0316 059A 0062; # (a◌̼◌֚◌̖◌〪b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; a◌〪◌̼◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SEAGULL BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0339 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062;0061 1DFA 0316 0339 059A 0062; # (a◌֚◌̖◌᷺◌̹b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; a◌᷺◌̖◌̹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT HALF RING BELOW, LATIN SMALL LETTER B +0061 0339 059A 0316 1DFA 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062;0061 1DFA 0339 0316 059A 0062; # (a◌̹◌֚◌̖◌᷺b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; a◌᷺◌̹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062;0061 1DFA 0316 033A 059A 0062; # (a◌֚◌̖◌᷺◌̺b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; a◌᷺◌̖◌̺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 033A 059A 0316 1DFA 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062;0061 1DFA 033A 0316 059A 0062; # (a◌̺◌֚◌̖◌᷺b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; a◌᷺◌̺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033B 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062;0061 1DFA 0316 033B 059A 0062; # (a◌֚◌̖◌᷺◌̻b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; a◌᷺◌̖◌̻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SQUARE BELOW, LATIN SMALL LETTER B +0061 033B 059A 0316 1DFA 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062;0061 1DFA 033B 0316 059A 0062; # (a◌̻◌֚◌̖◌᷺b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; a◌᷺◌̻◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SQUARE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 033C 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062;0061 1DFA 0316 033C 059A 0062; # (a◌֚◌̖◌᷺◌̼b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; a◌᷺◌̖◌̼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SEAGULL BELOW, LATIN SMALL LETTER B +0061 033C 059A 0316 1DFA 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062;0061 1DFA 033C 0316 059A 0062; # (a◌̼◌֚◌̖◌᷺b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; a◌᷺◌̼◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SEAGULL BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 033D 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062;00E0 05AE 033D 0315 0062;0061 05AE 0300 033D 0315 0062; # (a◌̕◌̀◌֮◌̽b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; à◌֮◌̽◌̕b; a◌֮◌̀◌̽◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING X ABOVE, LATIN SMALL LETTER B 0061 033D 0315 0300 05AE 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062;0061 05AE 033D 0300 0315 0062; # (a◌̽◌̕◌̀◌֮b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; a◌֮◌̽◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING X ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 033E 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062;00E0 05AE 033E 0315 0062;0061 05AE 0300 033E 0315 0062; # (a◌̕◌̀◌֮◌̾b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; à◌֮◌̾◌̕b; a◌֮◌̀◌̾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING VERTICAL TILDE, LATIN SMALL LETTER B @@ -17123,44 +17244,44 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0345 0345 035D 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062;0061 035D 0345 0345 0062; # (a◌ͅ◌ͅ◌͝b; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; a◌͝◌ͅ◌ͅb; ) LATIN SMALL LETTER A, COMBINING GREEK YPOGEGRAMMENI, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, LATIN SMALL LETTER B 0061 0315 0300 05AE 0346 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062;00E0 05AE 0346 0315 0062;0061 05AE 0300 0346 0315 0062; # (a◌̕◌̀◌֮◌͆b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; à◌֮◌͆◌̕b; a◌֮◌̀◌͆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BRIDGE ABOVE, LATIN SMALL LETTER B 0061 0346 0315 0300 05AE 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062;0061 05AE 0346 0300 0315 0062; # (a◌͆◌̕◌̀◌֮b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; a◌֮◌͆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0347 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062;0061 302A 0316 0347 059A 0062; # (a◌֚◌̖◌〪◌͇b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; a◌〪◌̖◌͇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING EQUALS SIGN BELOW, LATIN SMALL LETTER B -0061 0347 059A 0316 302A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062;0061 302A 0347 0316 059A 0062; # (a◌͇◌֚◌̖◌〪b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; a◌〪◌͇◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING EQUALS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0348 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062;0061 302A 0316 0348 059A 0062; # (a◌֚◌̖◌〪◌͈b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; a◌〪◌̖◌͈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE VERTICAL LINE BELOW, LATIN SMALL LETTER B -0061 0348 059A 0316 302A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062;0061 302A 0348 0316 059A 0062; # (a◌͈◌֚◌̖◌〪b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; a◌〪◌͈◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0349 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062;0061 302A 0316 0349 059A 0062; # (a◌֚◌̖◌〪◌͉b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; a◌〪◌̖◌͉◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT ANGLE BELOW, LATIN SMALL LETTER B -0061 0349 059A 0316 302A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062;0061 302A 0349 0316 059A 0062; # (a◌͉◌֚◌̖◌〪b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; a◌〪◌͉◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0347 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062;0061 1DFA 0316 0347 059A 0062; # (a◌֚◌̖◌᷺◌͇b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; a◌᷺◌̖◌͇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING EQUALS SIGN BELOW, LATIN SMALL LETTER B +0061 0347 059A 0316 1DFA 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062;0061 1DFA 0347 0316 059A 0062; # (a◌͇◌֚◌̖◌᷺b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; a◌᷺◌͇◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING EQUALS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0348 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062;0061 1DFA 0316 0348 059A 0062; # (a◌֚◌̖◌᷺◌͈b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; a◌᷺◌̖◌͈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE VERTICAL LINE BELOW, LATIN SMALL LETTER B +0061 0348 059A 0316 1DFA 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062;0061 1DFA 0348 0316 059A 0062; # (a◌͈◌֚◌̖◌᷺b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; a◌᷺◌͈◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0349 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062;0061 1DFA 0316 0349 059A 0062; # (a◌֚◌̖◌᷺◌͉b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; a◌᷺◌̖◌͉◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ANGLE BELOW, LATIN SMALL LETTER B +0061 0349 059A 0316 1DFA 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062;0061 1DFA 0349 0316 059A 0062; # (a◌͉◌֚◌̖◌᷺b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; a◌᷺◌͉◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ANGLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 034A 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062;00E0 05AE 034A 0315 0062;0061 05AE 0300 034A 0315 0062; # (a◌̕◌̀◌֮◌͊b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; à◌֮◌͊◌̕b; a◌֮◌̀◌͊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING NOT TILDE ABOVE, LATIN SMALL LETTER B 0061 034A 0315 0300 05AE 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062;0061 05AE 034A 0300 0315 0062; # (a◌͊◌̕◌̀◌֮b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; a◌֮◌͊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING NOT TILDE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 034B 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062;00E0 05AE 034B 0315 0062;0061 05AE 0300 034B 0315 0062; # (a◌̕◌̀◌֮◌͋b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; à◌֮◌͋◌̕b; a◌֮◌̀◌͋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING HOMOTHETIC ABOVE, LATIN SMALL LETTER B 0061 034B 0315 0300 05AE 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062;0061 05AE 034B 0300 0315 0062; # (a◌͋◌̕◌̀◌֮b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; a◌֮◌͋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING HOMOTHETIC ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 034C 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062;00E0 05AE 034C 0315 0062;0061 05AE 0300 034C 0315 0062; # (a◌̕◌̀◌֮◌͌b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; à◌֮◌͌◌̕b; a◌֮◌̀◌͌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ALMOST EQUAL TO ABOVE, LATIN SMALL LETTER B 0061 034C 0315 0300 05AE 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062;0061 05AE 034C 0300 0315 0062; # (a◌͌◌̕◌̀◌֮b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; a◌֮◌͌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 034D 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062;0061 302A 0316 034D 059A 0062; # (a◌֚◌̖◌〪◌͍b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; a◌〪◌̖◌͍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT RIGHT ARROW BELOW, LATIN SMALL LETTER B -0061 034D 059A 0316 302A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062;0061 302A 034D 0316 059A 0062; # (a◌͍◌֚◌̖◌〪b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; a◌〪◌͍◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 034E 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062;0061 302A 0316 034E 059A 0062; # (a◌֚◌̖◌〪◌͎b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; a◌〪◌̖◌͎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING UPWARDS ARROW BELOW, LATIN SMALL LETTER B -0061 034E 059A 0316 302A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062;0061 302A 034E 0316 059A 0062; # (a◌͎◌֚◌̖◌〪b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; a◌〪◌͎◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UPWARDS ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 034D 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062;0061 1DFA 0316 034D 059A 0062; # (a◌֚◌̖◌᷺◌͍b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; a◌᷺◌̖◌͍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT RIGHT ARROW BELOW, LATIN SMALL LETTER B +0061 034D 059A 0316 1DFA 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062;0061 1DFA 034D 0316 059A 0062; # (a◌͍◌֚◌̖◌᷺b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; a◌᷺◌͍◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 034E 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062;0061 1DFA 0316 034E 059A 0062; # (a◌֚◌̖◌᷺◌͎b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; a◌᷺◌̖◌͎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING UPWARDS ARROW BELOW, LATIN SMALL LETTER B +0061 034E 059A 0316 1DFA 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062;0061 1DFA 034E 0316 059A 0062; # (a◌͎◌֚◌̖◌᷺b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; a◌᷺◌͎◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING UPWARDS ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0350 0062;00E0 05AE 0350 0315 0062;0061 05AE 0300 0350 0315 0062;00E0 05AE 0350 0315 0062;0061 05AE 0300 0350 0315 0062; # (a◌̕◌̀◌֮◌͐b; à◌֮◌͐◌̕b; a◌֮◌̀◌͐◌̕b; à◌֮◌͐◌̕b; a◌֮◌̀◌͐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B 0061 0350 0315 0300 05AE 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062;0061 05AE 0350 0300 0315 0062; # (a◌͐◌̕◌̀◌֮b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; a◌֮◌͐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0351 0062;00E0 05AE 0351 0315 0062;0061 05AE 0300 0351 0315 0062;00E0 05AE 0351 0315 0062;0061 05AE 0300 0351 0315 0062; # (a◌̕◌̀◌֮◌͑b; à◌֮◌͑◌̕b; a◌֮◌̀◌͑◌̕b; à◌֮◌͑◌̕b; a◌֮◌̀◌͑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT HALF RING ABOVE, LATIN SMALL LETTER B 0061 0351 0315 0300 05AE 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062;0061 05AE 0351 0300 0315 0062; # (a◌͑◌̕◌̀◌֮b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; a◌֮◌͑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT HALF RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0352 0062;00E0 05AE 0352 0315 0062;0061 05AE 0300 0352 0315 0062;00E0 05AE 0352 0315 0062;0061 05AE 0300 0352 0315 0062; # (a◌̕◌̀◌֮◌͒b; à◌֮◌͒◌̕b; a◌֮◌̀◌͒◌̕b; à◌֮◌͒◌̕b; a◌֮◌̀◌͒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING FERMATA, LATIN SMALL LETTER B 0061 0352 0315 0300 05AE 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062;0061 05AE 0352 0300 0315 0062; # (a◌͒◌̕◌̀◌֮b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; a◌֮◌͒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING FERMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0353 0062;0061 302A 0316 0353 059A 0062;0061 302A 0316 0353 059A 0062;0061 302A 0316 0353 059A 0062;0061 302A 0316 0353 059A 0062; # (a◌֚◌̖◌〪◌͓b; a◌〪◌̖◌͓◌֚b; a◌〪◌̖◌͓◌֚b; a◌〪◌̖◌͓◌֚b; a◌〪◌̖◌͓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING X BELOW, LATIN SMALL LETTER B -0061 0353 059A 0316 302A 0062;0061 302A 0353 0316 059A 0062;0061 302A 0353 0316 059A 0062;0061 302A 0353 0316 059A 0062;0061 302A 0353 0316 059A 0062; # (a◌͓◌֚◌̖◌〪b; a◌〪◌͓◌̖◌֚b; a◌〪◌͓◌̖◌֚b; a◌〪◌͓◌̖◌֚b; a◌〪◌͓◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0354 0062;0061 302A 0316 0354 059A 0062;0061 302A 0316 0354 059A 0062;0061 302A 0316 0354 059A 0062;0061 302A 0316 0354 059A 0062; # (a◌֚◌̖◌〪◌͔b; a◌〪◌̖◌͔◌֚b; a◌〪◌̖◌͔◌֚b; a◌〪◌̖◌͔◌֚b; a◌〪◌̖◌͔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 0354 059A 0316 302A 0062;0061 302A 0354 0316 059A 0062;0061 302A 0354 0316 059A 0062;0061 302A 0354 0316 059A 0062;0061 302A 0354 0316 059A 0062; # (a◌͔◌֚◌̖◌〪b; a◌〪◌͔◌̖◌֚b; a◌〪◌͔◌̖◌֚b; a◌〪◌͔◌̖◌֚b; a◌〪◌͔◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0355 0062;0061 302A 0316 0355 059A 0062;0061 302A 0316 0355 059A 0062;0061 302A 0316 0355 059A 0062;0061 302A 0316 0355 059A 0062; # (a◌֚◌̖◌〪◌͕b; a◌〪◌̖◌͕◌֚b; a◌〪◌̖◌͕◌֚b; a◌〪◌̖◌͕◌֚b; a◌〪◌̖◌͕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 0355 059A 0316 302A 0062;0061 302A 0355 0316 059A 0062;0061 302A 0355 0316 059A 0062;0061 302A 0355 0316 059A 0062;0061 302A 0355 0316 059A 0062; # (a◌͕◌֚◌̖◌〪b; a◌〪◌͕◌̖◌֚b; a◌〪◌͕◌̖◌֚b; a◌〪◌͕◌̖◌֚b; a◌〪◌͕◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0356 0062;0061 302A 0316 0356 059A 0062;0061 302A 0316 0356 059A 0062;0061 302A 0316 0356 059A 0062;0061 302A 0316 0356 059A 0062; # (a◌֚◌̖◌〪◌͖b; a◌〪◌̖◌͖◌֚b; a◌〪◌̖◌͖◌֚b; a◌〪◌̖◌͖◌֚b; a◌〪◌̖◌͖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 0356 059A 0316 302A 0062;0061 302A 0356 0316 059A 0062;0061 302A 0356 0316 059A 0062;0061 302A 0356 0316 059A 0062;0061 302A 0356 0316 059A 0062; # (a◌͖◌֚◌̖◌〪b; a◌〪◌͖◌̖◌֚b; a◌〪◌͖◌̖◌֚b; a◌〪◌͖◌̖◌֚b; a◌〪◌͖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0353 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062;0061 1DFA 0316 0353 059A 0062; # (a◌֚◌̖◌᷺◌͓b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; a◌᷺◌̖◌͓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING X BELOW, LATIN SMALL LETTER B +0061 0353 059A 0316 1DFA 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062;0061 1DFA 0353 0316 059A 0062; # (a◌͓◌֚◌̖◌᷺b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; a◌᷺◌͓◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0354 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062;0061 1DFA 0316 0354 059A 0062; # (a◌֚◌̖◌᷺◌͔b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; a◌᷺◌̖◌͔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0354 059A 0316 1DFA 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062;0061 1DFA 0354 0316 059A 0062; # (a◌͔◌֚◌̖◌᷺b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; a◌᷺◌͔◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0355 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062;0061 1DFA 0316 0355 059A 0062; # (a◌֚◌̖◌᷺◌͕b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; a◌᷺◌̖◌͕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0355 059A 0316 1DFA 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062;0061 1DFA 0355 0316 059A 0062; # (a◌͕◌֚◌̖◌᷺b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; a◌᷺◌͕◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0356 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062;0061 1DFA 0316 0356 059A 0062; # (a◌֚◌̖◌᷺◌͖b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; a◌᷺◌̖◌͖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 0356 059A 0316 1DFA 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062;0061 1DFA 0356 0316 059A 0062; # (a◌͖◌֚◌̖◌᷺b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; a◌᷺◌͖◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0357 0062;00E0 05AE 0357 0315 0062;0061 05AE 0300 0357 0315 0062;00E0 05AE 0357 0315 0062;0061 05AE 0300 0357 0315 0062; # (a◌̕◌̀◌֮◌͗b; à◌֮◌͗◌̕b; a◌֮◌̀◌͗◌̕b; à◌֮◌͗◌̕b; a◌֮◌̀◌͗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT HALF RING ABOVE, LATIN SMALL LETTER B 0061 0357 0315 0300 05AE 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062;0061 05AE 0357 0300 0315 0062; # (a◌͗◌̕◌̀◌֮b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; a◌֮◌͗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT HALF RING ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 035C 0315 0300 0358 0062;00E0 0315 0358 035C 0062;0061 0300 0315 0358 035C 0062;00E0 0315 0358 035C 0062;0061 0300 0315 0358 035C 0062; # (a◌͜◌̕◌̀◌͘b; à◌̕◌͘◌͜b; a◌̀◌̕◌͘◌͜b; à◌̕◌͘◌͜b; a◌̀◌̕◌͘◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING DOT ABOVE RIGHT, LATIN SMALL LETTER B 0061 0358 035C 0315 0300 0062;00E0 0358 0315 035C 0062;0061 0300 0358 0315 035C 0062;00E0 0358 0315 035C 0062;0061 0300 0358 0315 035C 0062; # (a◌͘◌͜◌̕◌̀b; à◌͘◌̕◌͜b; a◌̀◌͘◌̕◌͜b; à◌͘◌̕◌͜b; a◌̀◌͘◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B -0061 059A 0316 302A 0359 0062;0061 302A 0316 0359 059A 0062;0061 302A 0316 0359 059A 0062;0061 302A 0316 0359 059A 0062;0061 302A 0316 0359 059A 0062; # (a◌֚◌̖◌〪◌͙b; a◌〪◌̖◌͙◌֚b; a◌〪◌̖◌͙◌֚b; a◌〪◌̖◌͙◌֚b; a◌〪◌̖◌͙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ASTERISK BELOW, LATIN SMALL LETTER B -0061 0359 059A 0316 302A 0062;0061 302A 0359 0316 059A 0062;0061 302A 0359 0316 059A 0062;0061 302A 0359 0316 059A 0062;0061 302A 0359 0316 059A 0062; # (a◌͙◌֚◌̖◌〪b; a◌〪◌͙◌̖◌֚b; a◌〪◌͙◌̖◌֚b; a◌〪◌͙◌̖◌֚b; a◌〪◌͙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ASTERISK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 035A 0062;0061 302A 0316 035A 059A 0062;0061 302A 0316 035A 059A 0062;0061 302A 0316 035A 059A 0062;0061 302A 0316 035A 059A 0062; # (a◌֚◌̖◌〪◌͚b; a◌〪◌̖◌͚◌֚b; a◌〪◌̖◌͚◌֚b; a◌〪◌̖◌͚◌֚b; a◌〪◌̖◌͚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE RING BELOW, LATIN SMALL LETTER B -0061 035A 059A 0316 302A 0062;0061 302A 035A 0316 059A 0062;0061 302A 035A 0316 059A 0062;0061 302A 035A 0316 059A 0062;0061 302A 035A 0316 059A 0062; # (a◌͚◌֚◌̖◌〪b; a◌〪◌͚◌̖◌֚b; a◌〪◌͚◌̖◌֚b; a◌〪◌͚◌̖◌֚b; a◌〪◌͚◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0359 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062;0061 1DFA 0316 0359 059A 0062; # (a◌֚◌̖◌᷺◌͙b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; a◌᷺◌̖◌͙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ASTERISK BELOW, LATIN SMALL LETTER B +0061 0359 059A 0316 1DFA 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062;0061 1DFA 0359 0316 059A 0062; # (a◌͙◌֚◌̖◌᷺b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; a◌᷺◌͙◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ASTERISK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 035A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062;0061 1DFA 0316 035A 059A 0062; # (a◌֚◌̖◌᷺◌͚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; a◌᷺◌̖◌͚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE RING BELOW, LATIN SMALL LETTER B +0061 035A 059A 0316 1DFA 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062;0061 1DFA 035A 0316 059A 0062; # (a◌͚◌֚◌̖◌᷺b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; a◌᷺◌͚◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 035B 0062;00E0 05AE 035B 0315 0062;0061 05AE 0300 035B 0315 0062;00E0 05AE 035B 0315 0062;0061 05AE 0300 035B 0315 0062; # (a◌̕◌̀◌֮◌͛b; à◌֮◌͛◌̕b; a◌֮◌̀◌͛◌̕b; à◌֮◌͛◌̕b; a◌֮◌̀◌͛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ZIGZAG ABOVE, LATIN SMALL LETTER B 0061 035B 0315 0300 05AE 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062;0061 05AE 035B 0300 0315 0062; # (a◌͛◌̕◌̀◌֮b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; a◌֮◌͛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ZIGZAG ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 035D 035C 0315 035C 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062;0061 0315 035C 035C 035D 0062; # (a◌͝◌͜◌̕◌͜b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; a◌̕◌͜◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B @@ -17213,8 +17334,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0486 0315 0300 05AE 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062;0061 05AE 0486 0300 0315 0062; # (a◌҆◌̕◌̀◌֮b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; a◌֮◌҆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PSILI PNEUMATA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0487 0062;00E0 05AE 0487 0315 0062;0061 05AE 0300 0487 0315 0062;00E0 05AE 0487 0315 0062;0061 05AE 0300 0487 0315 0062; # (a◌̕◌̀◌֮◌҇b; à◌֮◌҇◌̕b; a◌֮◌̀◌҇◌̕b; à◌֮◌҇◌̕b; a◌֮◌̀◌҇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC POKRYTIE, LATIN SMALL LETTER B 0061 0487 0315 0300 05AE 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062;0061 05AE 0487 0300 0315 0062; # (a◌҇◌̕◌̀◌֮b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; a◌֮◌҇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC POKRYTIE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0591 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062;0061 302A 0316 0591 059A 0062; # (a◌֚◌̖◌〪◌֑b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; a◌〪◌̖◌֑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT ETNAHTA, LATIN SMALL LETTER B -0061 0591 059A 0316 302A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062;0061 302A 0591 0316 059A 0062; # (a◌֑◌֚◌̖◌〪b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; a◌〪◌֑◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ETNAHTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0591 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062;0061 1DFA 0316 0591 059A 0062; # (a◌֚◌̖◌᷺◌֑b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; a◌᷺◌̖◌֑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT ETNAHTA, LATIN SMALL LETTER B +0061 0591 059A 0316 1DFA 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062;0061 1DFA 0591 0316 059A 0062; # (a◌֑◌֚◌̖◌᷺b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; a◌᷺◌֑◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ETNAHTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0592 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062;00E0 05AE 0592 0315 0062;0061 05AE 0300 0592 0315 0062; # (a◌̕◌̀◌֮◌֒b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; à◌֮◌֒◌̕b; a◌֮◌̀◌֒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SEGOL, LATIN SMALL LETTER B 0061 0592 0315 0300 05AE 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062;0061 05AE 0592 0300 0315 0062; # (a◌֒◌̕◌̀◌֮b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; a◌֮◌֒◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT SEGOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0593 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062;00E0 05AE 0593 0315 0062;0061 05AE 0300 0593 0315 0062; # (a◌̕◌̀◌֮◌֓b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; à◌֮◌֓◌̕b; a◌֮◌̀◌֓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT SHALSHELET, LATIN SMALL LETTER B @@ -17223,8 +17344,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0594 0315 0300 05AE 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062;0061 05AE 0594 0300 0315 0062; # (a◌֔◌̕◌̀◌֮b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; a◌֮◌֔◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF QATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0595 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062;00E0 05AE 0595 0315 0062;0061 05AE 0300 0595 0315 0062; # (a◌̕◌̀◌֮◌֕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; à◌֮◌֕◌̕b; a◌֮◌̀◌֕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZAQEF GADOL, LATIN SMALL LETTER B 0061 0595 0315 0300 05AE 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062;0061 05AE 0595 0300 0315 0062; # (a◌֕◌̕◌̀◌֮b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; a◌֮◌֕◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZAQEF GADOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0596 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062;0061 302A 0316 0596 059A 0062; # (a◌֚◌̖◌〪◌֖b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; a◌〪◌̖◌֖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT TIPEHA, LATIN SMALL LETTER B -0061 0596 059A 0316 302A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062;0061 302A 0596 0316 059A 0062; # (a◌֖◌֚◌̖◌〪b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; a◌〪◌֖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TIPEHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0596 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062;0061 1DFA 0316 0596 059A 0062; # (a◌֚◌̖◌᷺◌֖b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; a◌᷺◌̖◌֖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT TIPEHA, LATIN SMALL LETTER B +0061 0596 059A 0316 1DFA 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062;0061 1DFA 0596 0316 059A 0062; # (a◌֖◌֚◌̖◌᷺b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; a◌᷺◌֖◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TIPEHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0597 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062;00E0 05AE 0597 0315 0062;0061 05AE 0300 0597 0315 0062; # (a◌̕◌̀◌֮◌֗b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; à◌֮◌֗◌̕b; a◌֮◌̀◌֗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT REVIA, LATIN SMALL LETTER B 0061 0597 0315 0300 05AE 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062;0061 05AE 0597 0300 0315 0062; # (a◌֗◌̕◌̀◌֮b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; a◌֮◌֗◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT REVIA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0598 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062;00E0 05AE 0598 0315 0062;0061 05AE 0300 0598 0315 0062; # (a◌̕◌̀◌֮◌֘b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; à◌֮◌֘◌̕b; a◌֮◌̀◌֘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ZARQA, LATIN SMALL LETTER B @@ -17233,8 +17354,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0599 0315 0300 05AE 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062;0061 05AE 0599 0300 0315 0062; # (a◌֙◌̕◌̀◌֮b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; a◌֮◌֙◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PASHTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 302E 059A 0316 059A 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a〮◌֚◌̖◌֚b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; ) LATIN SMALL LETTER A, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, HEBREW ACCENT YETIV, LATIN SMALL LETTER B 0061 059A 302E 059A 0316 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062;0061 0316 059A 059A 302E 0062; # (a◌֚〮◌֚◌̖b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; a◌̖◌֚◌֚〮b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B -0061 059A 0316 302A 059B 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062;0061 302A 0316 059B 059A 0062; # (a◌֚◌̖◌〪◌֛b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; a◌〪◌̖◌֛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT TEVIR, LATIN SMALL LETTER B -0061 059B 059A 0316 302A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062;0061 302A 059B 0316 059A 0062; # (a◌֛◌֚◌̖◌〪b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; a◌〪◌֛◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TEVIR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 059B 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062;0061 1DFA 0316 059B 059A 0062; # (a◌֚◌̖◌᷺◌֛b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; a◌᷺◌̖◌֛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT TEVIR, LATIN SMALL LETTER B +0061 059B 059A 0316 1DFA 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062;0061 1DFA 059B 0316 059A 0062; # (a◌֛◌֚◌̖◌᷺b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; a◌᷺◌֛◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT TEVIR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 059C 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062;00E0 05AE 059C 0315 0062;0061 05AE 0300 059C 0315 0062; # (a◌̕◌̀◌֮◌֜b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; à◌֮◌֜◌̕b; a◌֮◌̀◌֜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH, LATIN SMALL LETTER B 0061 059C 0315 0300 05AE 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062;0061 05AE 059C 0300 0315 0062; # (a◌֜◌̕◌̀◌֮b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; a◌֮◌֜◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT GERESH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 059D 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062;00E0 05AE 059D 0315 0062;0061 05AE 0300 059D 0315 0062; # (a◌̕◌̀◌֮◌֝b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; à◌֮◌֝◌̕b; a◌֮◌̀◌֝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT GERESH MUQDAM, LATIN SMALL LETTER B @@ -17247,24 +17368,24 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 05A0 0315 0300 05AE 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062;0061 05AE 05A0 0300 0315 0062; # (a◌֠◌̕◌̀◌֮b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; a◌֮◌֠◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA GEDOLA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 05A1 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062;00E0 05AE 05A1 0315 0062;0061 05AE 0300 05A1 0315 0062; # (a◌̕◌̀◌֮◌֡b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; à◌֮◌֡◌̕b; a◌֮◌̀◌֡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT PAZER, LATIN SMALL LETTER B 0061 05A1 0315 0300 05AE 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062;0061 05AE 05A1 0300 0315 0062; # (a◌֡◌̕◌̀◌֮b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; a◌֮◌֡◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT PAZER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 05A2 0062;0061 302A 0316 05A2 059A 0062;0061 302A 0316 05A2 059A 0062;0061 302A 0316 05A2 059A 0062;0061 302A 0316 05A2 059A 0062; # (a◌֚◌̖◌〪◌֢b; a◌〪◌̖◌֢◌֚b; a◌〪◌̖◌֢◌֚b; a◌〪◌̖◌֢◌֚b; a◌〪◌̖◌֢◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT ATNAH HAFUKH, LATIN SMALL LETTER B -0061 05A2 059A 0316 302A 0062;0061 302A 05A2 0316 059A 0062;0061 302A 05A2 0316 059A 0062;0061 302A 05A2 0316 059A 0062;0061 302A 05A2 0316 059A 0062; # (a◌֢◌֚◌̖◌〪b; a◌〪◌֢◌̖◌֚b; a◌〪◌֢◌̖◌֚b; a◌〪◌֢◌̖◌֚b; a◌〪◌֢◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ATNAH HAFUKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 05A3 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062;0061 302A 0316 05A3 059A 0062; # (a◌֚◌̖◌〪◌֣b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; a◌〪◌̖◌֣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MUNAH, LATIN SMALL LETTER B -0061 05A3 059A 0316 302A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062;0061 302A 05A3 0316 059A 0062; # (a◌֣◌֚◌̖◌〪b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; a◌〪◌֣◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MUNAH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 05A4 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062;0061 302A 0316 05A4 059A 0062; # (a◌֚◌̖◌〪◌֤b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; a◌〪◌̖◌֤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MAHAPAKH, LATIN SMALL LETTER B -0061 05A4 059A 0316 302A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062;0061 302A 05A4 0316 059A 0062; # (a◌֤◌֚◌̖◌〪b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; a◌〪◌֤◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MAHAPAKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 05A5 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062;0061 302A 0316 05A5 059A 0062; # (a◌֚◌̖◌〪◌֥b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; a◌〪◌̖◌֥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MERKHA, LATIN SMALL LETTER B -0061 05A5 059A 0316 302A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062;0061 302A 05A5 0316 059A 0062; # (a◌֥◌֚◌̖◌〪b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; a◌〪◌֥◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 05A6 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062;0061 302A 0316 05A6 059A 0062; # (a◌֚◌̖◌〪◌֦b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; a◌〪◌̖◌֦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT MERKHA KEFULA, LATIN SMALL LETTER B -0061 05A6 059A 0316 302A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062;0061 302A 05A6 0316 059A 0062; # (a◌֦◌֚◌̖◌〪b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; a◌〪◌֦◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA KEFULA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 05A7 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062;0061 302A 0316 05A7 059A 0062; # (a◌֚◌̖◌〪◌֧b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; a◌〪◌̖◌֧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT DARGA, LATIN SMALL LETTER B -0061 05A7 059A 0316 302A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062;0061 302A 05A7 0316 059A 0062; # (a◌֧◌֚◌̖◌〪b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; a◌〪◌֧◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT DARGA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A2 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062;0061 1DFA 0316 05A2 059A 0062; # (a◌֚◌̖◌᷺◌֢b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; a◌᷺◌̖◌֢◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT ATNAH HAFUKH, LATIN SMALL LETTER B +0061 05A2 059A 0316 1DFA 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062;0061 1DFA 05A2 0316 059A 0062; # (a◌֢◌֚◌̖◌᷺b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; a◌᷺◌֢◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT ATNAH HAFUKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A3 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062;0061 1DFA 0316 05A3 059A 0062; # (a◌֚◌̖◌᷺◌֣b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; a◌᷺◌̖◌֣◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MUNAH, LATIN SMALL LETTER B +0061 05A3 059A 0316 1DFA 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062;0061 1DFA 05A3 0316 059A 0062; # (a◌֣◌֚◌̖◌᷺b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; a◌᷺◌֣◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MUNAH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A4 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062;0061 1DFA 0316 05A4 059A 0062; # (a◌֚◌̖◌᷺◌֤b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; a◌᷺◌̖◌֤◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MAHAPAKH, LATIN SMALL LETTER B +0061 05A4 059A 0316 1DFA 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062;0061 1DFA 05A4 0316 059A 0062; # (a◌֤◌֚◌̖◌᷺b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; a◌᷺◌֤◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MAHAPAKH, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A5 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062;0061 1DFA 0316 05A5 059A 0062; # (a◌֚◌̖◌᷺◌֥b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; a◌᷺◌̖◌֥◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MERKHA, LATIN SMALL LETTER B +0061 05A5 059A 0316 1DFA 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062;0061 1DFA 05A5 0316 059A 0062; # (a◌֥◌֚◌̖◌᷺b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; a◌᷺◌֥◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A6 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062;0061 1DFA 0316 05A6 059A 0062; # (a◌֚◌̖◌᷺◌֦b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; a◌᷺◌̖◌֦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT MERKHA KEFULA, LATIN SMALL LETTER B +0061 05A6 059A 0316 1DFA 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062;0061 1DFA 05A6 0316 059A 0062; # (a◌֦◌֚◌̖◌᷺b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; a◌᷺◌֦◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT MERKHA KEFULA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05A7 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062;0061 1DFA 0316 05A7 059A 0062; # (a◌֚◌̖◌᷺◌֧b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; a◌᷺◌̖◌֧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT DARGA, LATIN SMALL LETTER B +0061 05A7 059A 0316 1DFA 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062;0061 1DFA 05A7 0316 059A 0062; # (a◌֧◌֚◌̖◌᷺b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; a◌᷺◌֧◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT DARGA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 05A8 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062;00E0 05AE 05A8 0315 0062;0061 05AE 0300 05A8 0315 0062; # (a◌̕◌̀◌֮◌֨b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; à◌֮◌֨◌̕b; a◌֮◌̀◌֨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT QADMA, LATIN SMALL LETTER B 0061 05A8 0315 0300 05AE 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062;0061 05AE 05A8 0300 0315 0062; # (a◌֨◌̕◌̀◌֮b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; a◌֮◌֨◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT QADMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 05A9 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062;00E0 05AE 05A9 0315 0062;0061 05AE 0300 05A9 0315 0062; # (a◌̕◌̀◌֮◌֩b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; à◌֮◌֩◌̕b; a◌֮◌̀◌֩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT TELISHA QETANA, LATIN SMALL LETTER B 0061 05A9 0315 0300 05AE 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062;0061 05AE 05A9 0300 0315 0062; # (a◌֩◌̕◌̀◌֮b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; a◌֮◌֩◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT TELISHA QETANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 05AA 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062;0061 302A 0316 05AA 059A 0062; # (a◌֚◌̖◌〪◌֪b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; a◌〪◌̖◌֪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW ACCENT YERAH BEN YOMO, LATIN SMALL LETTER B -0061 05AA 059A 0316 302A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062;0061 302A 05AA 0316 059A 0062; # (a◌֪◌֚◌̖◌〪b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; a◌〪◌֪◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YERAH BEN YOMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05AA 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062;0061 1DFA 0316 05AA 059A 0062; # (a◌֚◌̖◌᷺◌֪b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; a◌᷺◌̖◌֪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW ACCENT YERAH BEN YOMO, LATIN SMALL LETTER B +0061 05AA 059A 0316 1DFA 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062;0061 1DFA 05AA 0316 059A 0062; # (a◌֪◌֚◌̖◌᷺b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; a◌᷺◌֪◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YERAH BEN YOMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 05AB 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062;00E0 05AE 05AB 0315 0062;0061 05AE 0300 05AB 0315 0062; # (a◌̕◌̀◌֮◌֫b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; à◌֮◌֫◌̕b; a◌֮◌̀◌֫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT OLE, LATIN SMALL LETTER B 0061 05AB 0315 0300 05AE 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062;0061 05AE 05AB 0300 0315 0062; # (a◌֫◌̕◌̀◌֮b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; a◌֮◌֫◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW ACCENT OLE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 05AC 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062;00E0 05AE 05AC 0315 0062;0061 05AE 0300 05AC 0315 0062; # (a◌̕◌̀◌֮◌֬b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; à◌֮◌֬◌̕b; a◌֮◌̀◌֬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW ACCENT ILUY, LATIN SMALL LETTER B @@ -17311,8 +17432,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 05C2 FB1E 05C2 05C1 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062;0061 05C1 05C2 05C2 FB1E 0062; # (a◌ׂ◌ﬞ◌ׂ◌ׁb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; a◌ׁ◌ׂ◌ׂ◌ﬞb; ) LATIN SMALL LETTER A, HEBREW POINT SIN DOT, HEBREW POINT JUDEO-SPANISH VARIKA, HEBREW POINT SIN DOT, HEBREW POINT SHIN DOT, LATIN SMALL LETTER B 0061 0315 0300 05AE 05C4 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062;00E0 05AE 05C4 0315 0062;0061 05AE 0300 05C4 0315 0062; # (a◌̕◌̀◌֮◌ׄb; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; à◌֮◌ׄ◌̕b; a◌֮◌̀◌ׄ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HEBREW MARK UPPER DOT, LATIN SMALL LETTER B 0061 05C4 0315 0300 05AE 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062;0061 05AE 05C4 0300 0315 0062; # (a◌ׄ◌̕◌̀◌֮b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; a◌֮◌ׄ◌̀◌̕b; ) LATIN SMALL LETTER A, HEBREW MARK UPPER DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 05C5 0062;0061 302A 0316 05C5 059A 0062;0061 302A 0316 05C5 059A 0062;0061 302A 0316 05C5 059A 0062;0061 302A 0316 05C5 059A 0062; # (a◌֚◌̖◌〪◌ׅb; a◌〪◌̖◌ׅ◌֚b; a◌〪◌̖◌ׅ◌֚b; a◌〪◌̖◌ׅ◌֚b; a◌〪◌̖◌ׅ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, HEBREW MARK LOWER DOT, LATIN SMALL LETTER B -0061 05C5 059A 0316 302A 0062;0061 302A 05C5 0316 059A 0062;0061 302A 05C5 0316 059A 0062;0061 302A 05C5 0316 059A 0062;0061 302A 05C5 0316 059A 0062; # (a◌ׅ◌֚◌̖◌〪b; a◌〪◌ׅ◌̖◌֚b; a◌〪◌ׅ◌̖◌֚b; a◌〪◌ׅ◌̖◌֚b; a◌〪◌ׅ◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW MARK LOWER DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 05C5 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062;0061 1DFA 0316 05C5 059A 0062; # (a◌֚◌̖◌᷺◌ׅb; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; a◌᷺◌̖◌ׅ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, HEBREW MARK LOWER DOT, LATIN SMALL LETTER B +0061 05C5 059A 0316 1DFA 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062;0061 1DFA 05C5 0316 059A 0062; # (a◌ׅ◌֚◌̖◌᷺b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; a◌᷺◌ׅ◌̖◌֚b; ) LATIN SMALL LETTER A, HEBREW MARK LOWER DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 05B9 05B8 05B7 05C7 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062;0061 05B7 05B8 05C7 05B9 0062; # (a◌ֹ◌ָ◌ַ◌ׇb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; a◌ַ◌ָ◌ׇ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, HEBREW POINT QAMATS QATAN, LATIN SMALL LETTER B 0061 05C7 05B9 05B8 05B7 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062;0061 05B7 05C7 05B8 05B9 0062; # (a◌ׇ◌ֹ◌ָ◌ַb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; a◌ַ◌ׇ◌ָ◌ֹb; ) LATIN SMALL LETTER A, HEBREW POINT QAMATS QATAN, HEBREW POINT HOLAM, HEBREW POINT QAMATS, HEBREW POINT PATAH, LATIN SMALL LETTER B 0061 0315 0300 05AE 0610 0062;00E0 05AE 0610 0315 0062;0061 05AE 0300 0610 0315 0062;00E0 05AE 0610 0315 0062;0061 05AE 0300 0610 0315 0062; # (a◌̕◌̀◌֮◌ؐb; à◌֮◌ؐ◌̕b; a◌֮◌̀◌ؐ◌̕b; à◌֮◌ؐ◌̕b; a◌֮◌̀◌ؐ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM, LATIN SMALL LETTER B @@ -17357,10 +17478,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0653 0315 0300 05AE 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062;0061 05AE 0653 0300 0315 0062; # (a◌ٓ◌̕◌̀◌֮b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; a◌֮◌ٓ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MADDAH ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0654 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062;00E0 05AE 0654 0315 0062;0061 05AE 0300 0654 0315 0062; # (a◌̕◌̀◌֮◌ٔb; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; à◌֮◌ٔ◌̕b; a◌֮◌̀◌ٔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC HAMZA ABOVE, LATIN SMALL LETTER B 0061 0654 0315 0300 05AE 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062;0061 05AE 0654 0300 0315 0062; # (a◌ٔ◌̕◌̀◌֮b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; a◌֮◌ٔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC HAMZA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0655 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062;0061 302A 0316 0655 059A 0062; # (a◌֚◌̖◌〪◌ٕb; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; a◌〪◌̖◌ٕ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC HAMZA BELOW, LATIN SMALL LETTER B -0061 0655 059A 0316 302A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062;0061 302A 0655 0316 059A 0062; # (a◌ٕ◌֚◌̖◌〪b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; a◌〪◌ٕ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0656 0062;0061 302A 0316 0656 059A 0062;0061 302A 0316 0656 059A 0062;0061 302A 0316 0656 059A 0062;0061 302A 0316 0656 059A 0062; # (a◌֚◌̖◌〪◌ٖb; a◌〪◌̖◌ٖ◌֚b; a◌〪◌̖◌ٖ◌֚b; a◌〪◌̖◌ٖ◌֚b; a◌〪◌̖◌ٖ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SUBSCRIPT ALEF, LATIN SMALL LETTER B -0061 0656 059A 0316 302A 0062;0061 302A 0656 0316 059A 0062;0061 302A 0656 0316 059A 0062;0061 302A 0656 0316 059A 0062;0061 302A 0656 0316 059A 0062; # (a◌ٖ◌֚◌̖◌〪b; a◌〪◌ٖ◌̖◌֚b; a◌〪◌ٖ◌̖◌֚b; a◌〪◌ٖ◌̖◌֚b; a◌〪◌ٖ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SUBSCRIPT ALEF, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0655 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062;0061 1DFA 0316 0655 059A 0062; # (a◌֚◌̖◌᷺◌ٕb; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; a◌᷺◌̖◌ٕ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC HAMZA BELOW, LATIN SMALL LETTER B +0061 0655 059A 0316 1DFA 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062;0061 1DFA 0655 0316 059A 0062; # (a◌ٕ◌֚◌̖◌᷺b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; a◌᷺◌ٕ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0656 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062;0061 1DFA 0316 0656 059A 0062; # (a◌֚◌̖◌᷺◌ٖb; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; a◌᷺◌̖◌ٖ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SUBSCRIPT ALEF, LATIN SMALL LETTER B +0061 0656 059A 0316 1DFA 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062;0061 1DFA 0656 0316 059A 0062; # (a◌ٖ◌֚◌̖◌᷺b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; a◌᷺◌ٖ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SUBSCRIPT ALEF, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0657 0062;00E0 05AE 0657 0315 0062;0061 05AE 0300 0657 0315 0062;00E0 05AE 0657 0315 0062;0061 05AE 0300 0657 0315 0062; # (a◌̕◌̀◌֮◌ٗb; à◌֮◌ٗ◌̕b; a◌֮◌̀◌ٗ◌̕b; à◌֮◌ٗ◌̕b; a◌֮◌̀◌ٗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC INVERTED DAMMA, LATIN SMALL LETTER B 0061 0657 0315 0300 05AE 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062;0061 05AE 0657 0300 0315 0062; # (a◌ٗ◌̕◌̀◌֮b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; a◌֮◌ٗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC INVERTED DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0658 0062;00E0 05AE 0658 0315 0062;0061 05AE 0300 0658 0315 0062;00E0 05AE 0658 0315 0062;0061 05AE 0300 0658 0315 0062; # (a◌̕◌̀◌֮◌٘b; à◌֮◌٘◌̕b; a◌֮◌̀◌٘◌̕b; à◌֮◌٘◌̕b; a◌֮◌̀◌٘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MARK NOON GHUNNA, LATIN SMALL LETTER B @@ -17371,14 +17492,14 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 065A 0315 0300 05AE 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062;0061 05AE 065A 0300 0315 0062; # (a◌ٚ◌̕◌̀◌֮b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; a◌֮◌ٚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN SMALL V ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 065B 0062;00E0 05AE 065B 0315 0062;0061 05AE 0300 065B 0315 0062;00E0 05AE 065B 0315 0062;0061 05AE 0300 065B 0315 0062; # (a◌̕◌̀◌֮◌ٛb; à◌֮◌ٛ◌̕b; a◌֮◌̀◌ٛ◌̕b; à◌֮◌ٛ◌̕b; a◌֮◌̀◌ٛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC VOWEL SIGN INVERTED SMALL V ABOVE, LATIN SMALL LETTER B 0061 065B 0315 0300 05AE 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062;0061 05AE 065B 0300 0315 0062; # (a◌ٛ◌̕◌̀◌֮b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; a◌֮◌ٛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN INVERTED SMALL V ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 065C 0062;0061 302A 0316 065C 059A 0062;0061 302A 0316 065C 059A 0062;0061 302A 0316 065C 059A 0062;0061 302A 0316 065C 059A 0062; # (a◌֚◌̖◌〪◌ٜb; a◌〪◌̖◌ٜ◌֚b; a◌〪◌̖◌ٜ◌֚b; a◌〪◌̖◌ٜ◌֚b; a◌〪◌̖◌ٜ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC VOWEL SIGN DOT BELOW, LATIN SMALL LETTER B -0061 065C 059A 0316 302A 0062;0061 302A 065C 0316 059A 0062;0061 302A 065C 0316 059A 0062;0061 302A 065C 0316 059A 0062;0061 302A 065C 0316 059A 0062; # (a◌ٜ◌֚◌̖◌〪b; a◌〪◌ٜ◌̖◌֚b; a◌〪◌ٜ◌̖◌֚b; a◌〪◌ٜ◌̖◌֚b; a◌〪◌ٜ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 065C 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062;0061 1DFA 0316 065C 059A 0062; # (a◌֚◌̖◌᷺◌ٜb; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; a◌᷺◌̖◌ٜ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC VOWEL SIGN DOT BELOW, LATIN SMALL LETTER B +0061 065C 059A 0316 1DFA 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062;0061 1DFA 065C 0316 059A 0062; # (a◌ٜ◌֚◌̖◌᷺b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; a◌᷺◌ٜ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC VOWEL SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 065D 0062;00E0 05AE 065D 0315 0062;0061 05AE 0300 065D 0315 0062;00E0 05AE 065D 0315 0062;0061 05AE 0300 065D 0315 0062; # (a◌̕◌̀◌֮◌ٝb; à◌֮◌ٝ◌̕b; a◌֮◌̀◌ٝ◌̕b; à◌֮◌ٝ◌̕b; a◌֮◌̀◌ٝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC REVERSED DAMMA, LATIN SMALL LETTER B 0061 065D 0315 0300 05AE 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062;0061 05AE 065D 0300 0315 0062; # (a◌ٝ◌̕◌̀◌֮b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; a◌֮◌ٝ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC REVERSED DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 065E 0062;00E0 05AE 065E 0315 0062;0061 05AE 0300 065E 0315 0062;00E0 05AE 065E 0315 0062;0061 05AE 0300 065E 0315 0062; # (a◌̕◌̀◌֮◌ٞb; à◌֮◌ٞ◌̕b; a◌֮◌̀◌ٞ◌̕b; à◌֮◌ٞ◌̕b; a◌֮◌̀◌ٞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC FATHA WITH TWO DOTS, LATIN SMALL LETTER B 0061 065E 0315 0300 05AE 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062;0061 05AE 065E 0300 0315 0062; # (a◌ٞ◌̕◌̀◌֮b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; a◌֮◌ٞ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH TWO DOTS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 065F 0062;0061 302A 0316 065F 059A 0062;0061 302A 0316 065F 059A 0062;0061 302A 0316 065F 059A 0062;0061 302A 0316 065F 059A 0062; # (a◌֚◌̖◌〪◌ٟb; a◌〪◌̖◌ٟ◌֚b; a◌〪◌̖◌ٟ◌֚b; a◌〪◌̖◌ٟ◌֚b; a◌〪◌̖◌ٟ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC WAVY HAMZA BELOW, LATIN SMALL LETTER B -0061 065F 059A 0316 302A 0062;0061 302A 065F 0316 059A 0062;0061 302A 065F 0316 059A 0062;0061 302A 065F 0316 059A 0062;0061 302A 065F 0316 059A 0062; # (a◌ٟ◌֚◌̖◌〪b; a◌〪◌ٟ◌̖◌֚b; a◌〪◌ٟ◌̖◌֚b; a◌〪◌ٟ◌̖◌֚b; a◌〪◌ٟ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC WAVY HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 065F 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062;0061 1DFA 0316 065F 059A 0062; # (a◌֚◌̖◌᷺◌ٟb; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; a◌᷺◌̖◌ٟ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC WAVY HAMZA BELOW, LATIN SMALL LETTER B +0061 065F 059A 0316 1DFA 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062;0061 1DFA 065F 0316 059A 0062; # (a◌ٟ◌֚◌̖◌᷺b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; a◌᷺◌ٟ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC WAVY HAMZA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0711 0670 0652 0670 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ܑ◌ٰ◌ْ◌ٰb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B 0061 0670 0711 0670 0652 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062;0061 0652 0670 0670 0711 0062; # (a◌ٰ◌ܑ◌ٰ◌ْb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; a◌ْ◌ٰ◌ٰ◌ܑb; ) LATIN SMALL LETTER A, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, ARABIC SUKUN, LATIN SMALL LETTER B 0061 0315 0300 05AE 06D6 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062;00E0 05AE 06D6 0315 0062;0061 05AE 0300 06D6 0315 0062; # (a◌̕◌̀◌֮◌ۖb; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; à◌֮◌ۖ◌̕b; a◌֮◌̀◌ۖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA, LATIN SMALL LETTER B @@ -17403,74 +17524,74 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 06E1 0315 0300 05AE 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062;0061 05AE 06E1 0300 0315 0062; # (a◌ۡ◌̕◌̀◌֮b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; a◌֮◌ۡ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH DOTLESS HEAD OF KHAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 06E2 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062;00E0 05AE 06E2 0315 0062;0061 05AE 0300 06E2 0315 0062; # (a◌̕◌̀◌֮◌ۢb; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; à◌֮◌ۢ◌̕b; a◌֮◌̀◌ۢ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MEEM ISOLATED FORM, LATIN SMALL LETTER B 0061 06E2 0315 0300 05AE 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062;0061 05AE 06E2 0300 0315 0062; # (a◌ۢ◌̕◌̀◌֮b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; a◌֮◌ۢ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MEEM ISOLATED FORM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 06E3 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062;0061 302A 0316 06E3 059A 0062; # (a◌֚◌̖◌〪◌ۣb; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; a◌〪◌̖◌ۣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW SEEN, LATIN SMALL LETTER B -0061 06E3 059A 0316 302A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062;0061 302A 06E3 0316 059A 0062; # (a◌ۣ◌֚◌̖◌〪b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; a◌〪◌ۣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW SEEN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06E3 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062;0061 1DFA 0316 06E3 059A 0062; # (a◌֚◌̖◌᷺◌ۣb; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; a◌᷺◌̖◌ۣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW SEEN, LATIN SMALL LETTER B +0061 06E3 059A 0316 1DFA 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062;0061 1DFA 06E3 0316 059A 0062; # (a◌ۣ◌֚◌̖◌᷺b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; a◌᷺◌ۣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW SEEN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 06E4 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062;00E0 05AE 06E4 0315 0062;0061 05AE 0300 06E4 0315 0062; # (a◌̕◌̀◌֮◌ۤb; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; à◌֮◌ۤ◌̕b; a◌֮◌̀◌ۤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH MADDA, LATIN SMALL LETTER B 0061 06E4 0315 0300 05AE 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062;0061 05AE 06E4 0300 0315 0062; # (a◌ۤ◌̕◌̀◌֮b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; a◌֮◌ۤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 06E7 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062;00E0 05AE 06E7 0315 0062;0061 05AE 0300 06E7 0315 0062; # (a◌̕◌̀◌֮◌ۧb; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; à◌֮◌ۧ◌̕b; a◌֮◌̀◌ۧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH YEH, LATIN SMALL LETTER B 0061 06E7 0315 0300 05AE 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062;0061 05AE 06E7 0300 0315 0062; # (a◌ۧ◌̕◌̀◌֮b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; a◌֮◌ۧ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 06E8 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062;00E0 05AE 06E8 0315 0062;0061 05AE 0300 06E8 0315 0062; # (a◌̕◌̀◌֮◌ۨb; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; à◌֮◌ۨ◌̕b; a◌֮◌̀◌ۨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH NOON, LATIN SMALL LETTER B 0061 06E8 0315 0300 05AE 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062;0061 05AE 06E8 0300 0315 0062; # (a◌ۨ◌̕◌̀◌֮b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; a◌֮◌ۨ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH NOON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 06EA 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062;0061 302A 0316 06EA 059A 0062; # (a◌֚◌̖◌〪◌۪b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; a◌〪◌̖◌۪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC EMPTY CENTRE LOW STOP, LATIN SMALL LETTER B -0061 06EA 059A 0316 302A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062;0061 302A 06EA 0316 059A 0062; # (a◌۪◌֚◌̖◌〪b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; a◌〪◌۪◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE LOW STOP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06EA 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062;0061 1DFA 0316 06EA 059A 0062; # (a◌֚◌̖◌᷺◌۪b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; a◌᷺◌̖◌۪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC EMPTY CENTRE LOW STOP, LATIN SMALL LETTER B +0061 06EA 059A 0316 1DFA 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062;0061 1DFA 06EA 0316 059A 0062; # (a◌۪◌֚◌̖◌᷺b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; a◌᷺◌۪◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE LOW STOP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 06EB 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062;00E0 05AE 06EB 0315 0062;0061 05AE 0300 06EB 0315 0062; # (a◌̕◌̀◌֮◌۫b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; à◌֮◌۫◌̕b; a◌֮◌̀◌۫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC EMPTY CENTRE HIGH STOP, LATIN SMALL LETTER B 0061 06EB 0315 0300 05AE 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062;0061 05AE 06EB 0300 0315 0062; # (a◌۫◌̕◌̀◌֮b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; a◌֮◌۫◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC EMPTY CENTRE HIGH STOP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 06EC 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062;00E0 05AE 06EC 0315 0062;0061 05AE 0300 06EC 0315 0062; # (a◌̕◌̀◌֮◌۬b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; à◌֮◌۬◌̕b; a◌֮◌̀◌۬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, LATIN SMALL LETTER B 0061 06EC 0315 0300 05AE 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062;0061 05AE 06EC 0300 0315 0062; # (a◌۬◌̕◌̀◌֮b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; a◌֮◌۬◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 06ED 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062;0061 302A 0316 06ED 059A 0062; # (a◌֚◌̖◌〪◌ۭb; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; a◌〪◌̖◌ۭ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW MEEM, LATIN SMALL LETTER B -0061 06ED 059A 0316 302A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062;0061 302A 06ED 0316 059A 0062; # (a◌ۭ◌֚◌̖◌〪b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; a◌〪◌ۭ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW MEEM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 06ED 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062;0061 1DFA 0316 06ED 059A 0062; # (a◌֚◌̖◌᷺◌ۭb; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; a◌᷺◌̖◌ۭ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW MEEM, LATIN SMALL LETTER B +0061 06ED 059A 0316 1DFA 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062;0061 1DFA 06ED 0316 059A 0062; # (a◌ۭ◌֚◌̖◌᷺b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; a◌᷺◌ۭ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW MEEM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0C55 0711 0670 0711 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ౕ◌ܑ◌ٰ◌ܑb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, SYRIAC LETTER SUPERSCRIPT ALAPH, LATIN SMALL LETTER B 0061 0711 0C55 0711 0670 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062;0061 0670 0711 0711 0C55 0062; # (a◌ܑ◌ౕ◌ܑ◌ٰb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; a◌ٰ◌ܑ◌ܑ◌ౕb; ) LATIN SMALL LETTER A, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, ARABIC LETTER SUPERSCRIPT ALEF, LATIN SMALL LETTER B 0061 0315 0300 05AE 0730 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062;00E0 05AE 0730 0315 0062;0061 05AE 0300 0730 0315 0062; # (a◌̕◌̀◌֮◌ܰb; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; à◌֮◌ܰ◌̕b; a◌֮◌̀◌ܰ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA ABOVE, LATIN SMALL LETTER B 0061 0730 0315 0300 05AE 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062;0061 05AE 0730 0300 0315 0062; # (a◌ܰ◌̕◌̀◌֮b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; a◌֮◌ܰ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0731 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062;0061 302A 0316 0731 059A 0062; # (a◌֚◌̖◌〪◌ܱb; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; a◌〪◌̖◌ܱ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC PTHAHA BELOW, LATIN SMALL LETTER B -0061 0731 059A 0316 302A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062;0061 302A 0731 0316 059A 0062; # (a◌ܱ◌֚◌̖◌〪b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; a◌〪◌ܱ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0731 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062;0061 1DFA 0316 0731 059A 0062; # (a◌֚◌̖◌᷺◌ܱb; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; a◌᷺◌̖◌ܱ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC PTHAHA BELOW, LATIN SMALL LETTER B +0061 0731 059A 0316 1DFA 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062;0061 1DFA 0731 0316 059A 0062; # (a◌ܱ◌֚◌̖◌᷺b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; a◌᷺◌ܱ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0732 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062;00E0 05AE 0732 0315 0062;0061 05AE 0300 0732 0315 0062; # (a◌̕◌̀◌֮◌ܲb; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; à◌֮◌ܲ◌̕b; a◌֮◌̀◌ܲ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC PTHAHA DOTTED, LATIN SMALL LETTER B 0061 0732 0315 0300 05AE 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062;0061 05AE 0732 0300 0315 0062; # (a◌ܲ◌̕◌̀◌֮b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; a◌֮◌ܲ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC PTHAHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0733 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062;00E0 05AE 0733 0315 0062;0061 05AE 0300 0733 0315 0062; # (a◌̕◌̀◌֮◌ܳb; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; à◌֮◌ܳ◌̕b; a◌֮◌̀◌ܳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA ABOVE, LATIN SMALL LETTER B 0061 0733 0315 0300 05AE 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062;0061 05AE 0733 0300 0315 0062; # (a◌ܳ◌̕◌̀◌֮b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; a◌֮◌ܳ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0734 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062;0061 302A 0316 0734 059A 0062; # (a◌֚◌̖◌〪◌ܴb; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; a◌〪◌̖◌ܴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC ZQAPHA BELOW, LATIN SMALL LETTER B -0061 0734 059A 0316 302A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062;0061 302A 0734 0316 059A 0062; # (a◌ܴ◌֚◌̖◌〪b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; a◌〪◌ܴ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0734 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062;0061 1DFA 0316 0734 059A 0062; # (a◌֚◌̖◌᷺◌ܴb; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; a◌᷺◌̖◌ܴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC ZQAPHA BELOW, LATIN SMALL LETTER B +0061 0734 059A 0316 1DFA 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062;0061 1DFA 0734 0316 059A 0062; # (a◌ܴ◌֚◌̖◌᷺b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; a◌᷺◌ܴ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0735 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062;00E0 05AE 0735 0315 0062;0061 05AE 0300 0735 0315 0062; # (a◌̕◌̀◌֮◌ܵb; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; à◌֮◌ܵ◌̕b; a◌֮◌̀◌ܵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ZQAPHA DOTTED, LATIN SMALL LETTER B 0061 0735 0315 0300 05AE 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062;0061 05AE 0735 0300 0315 0062; # (a◌ܵ◌̕◌̀◌֮b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; a◌֮◌ܵ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ZQAPHA DOTTED, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0736 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062;00E0 05AE 0736 0315 0062;0061 05AE 0300 0736 0315 0062; # (a◌̕◌̀◌֮◌ܶb; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; à◌֮◌ܶ◌̕b; a◌֮◌̀◌ܶ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RBASA ABOVE, LATIN SMALL LETTER B 0061 0736 0315 0300 05AE 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062;0061 05AE 0736 0300 0315 0062; # (a◌ܶ◌̕◌̀◌֮b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; a◌֮◌ܶ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0737 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062;0061 302A 0316 0737 059A 0062; # (a◌֚◌̖◌〪◌ܷb; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; a◌〪◌̖◌ܷ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC RBASA BELOW, LATIN SMALL LETTER B -0061 0737 059A 0316 302A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062;0061 302A 0737 0316 059A 0062; # (a◌ܷ◌֚◌̖◌〪b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; a◌〪◌ܷ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0738 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062;0061 302A 0316 0738 059A 0062; # (a◌֚◌̖◌〪◌ܸb; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; a◌〪◌̖◌ܸ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC DOTTED ZLAMA HORIZONTAL, LATIN SMALL LETTER B -0061 0738 059A 0316 302A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062;0061 302A 0738 0316 059A 0062; # (a◌ܸ◌֚◌̖◌〪b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; a◌〪◌ܸ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA HORIZONTAL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0739 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062;0061 302A 0316 0739 059A 0062; # (a◌֚◌̖◌〪◌ܹb; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; a◌〪◌̖◌ܹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC DOTTED ZLAMA ANGULAR, LATIN SMALL LETTER B -0061 0739 059A 0316 302A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062;0061 302A 0739 0316 059A 0062; # (a◌ܹ◌֚◌̖◌〪b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; a◌〪◌ܹ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA ANGULAR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0737 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062;0061 1DFA 0316 0737 059A 0062; # (a◌֚◌̖◌᷺◌ܷb; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; a◌᷺◌̖◌ܷ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC RBASA BELOW, LATIN SMALL LETTER B +0061 0737 059A 0316 1DFA 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062;0061 1DFA 0737 0316 059A 0062; # (a◌ܷ◌֚◌̖◌᷺b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; a◌᷺◌ܷ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0738 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062;0061 1DFA 0316 0738 059A 0062; # (a◌֚◌̖◌᷺◌ܸb; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; a◌᷺◌̖◌ܸ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC DOTTED ZLAMA HORIZONTAL, LATIN SMALL LETTER B +0061 0738 059A 0316 1DFA 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062;0061 1DFA 0738 0316 059A 0062; # (a◌ܸ◌֚◌̖◌᷺b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; a◌᷺◌ܸ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA HORIZONTAL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0739 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062;0061 1DFA 0316 0739 059A 0062; # (a◌֚◌̖◌᷺◌ܹb; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; a◌᷺◌̖◌ܹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC DOTTED ZLAMA ANGULAR, LATIN SMALL LETTER B +0061 0739 059A 0316 1DFA 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062;0061 1DFA 0739 0316 059A 0062; # (a◌ܹ◌֚◌̖◌᷺b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; a◌᷺◌ܹ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC DOTTED ZLAMA ANGULAR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 073A 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062;00E0 05AE 073A 0315 0062;0061 05AE 0300 073A 0315 0062; # (a◌̕◌̀◌֮◌ܺb; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; à◌֮◌ܺ◌̕b; a◌֮◌̀◌ܺ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC HBASA ABOVE, LATIN SMALL LETTER B 0061 073A 0315 0300 05AE 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062;0061 05AE 073A 0300 0315 0062; # (a◌ܺ◌̕◌̀◌֮b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; a◌֮◌ܺ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC HBASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 073B 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062;0061 302A 0316 073B 059A 0062; # (a◌֚◌̖◌〪◌ܻb; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; a◌〪◌̖◌ܻ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC HBASA BELOW, LATIN SMALL LETTER B -0061 073B 059A 0316 302A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062;0061 302A 073B 0316 059A 0062; # (a◌ܻ◌֚◌̖◌〪b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; a◌〪◌ܻ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 073C 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062;0061 302A 0316 073C 059A 0062; # (a◌֚◌̖◌〪◌ܼb; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; a◌〪◌̖◌ܼ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC HBASA-ESASA DOTTED, LATIN SMALL LETTER B -0061 073C 059A 0316 302A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062;0061 302A 073C 0316 059A 0062; # (a◌ܼ◌֚◌̖◌〪b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; a◌〪◌ܼ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA-ESASA DOTTED, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073B 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062;0061 1DFA 0316 073B 059A 0062; # (a◌֚◌̖◌᷺◌ܻb; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; a◌᷺◌̖◌ܻ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC HBASA BELOW, LATIN SMALL LETTER B +0061 073B 059A 0316 1DFA 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062;0061 1DFA 073B 0316 059A 0062; # (a◌ܻ◌֚◌̖◌᷺b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; a◌᷺◌ܻ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073C 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062;0061 1DFA 0316 073C 059A 0062; # (a◌֚◌̖◌᷺◌ܼb; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; a◌᷺◌̖◌ܼ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC HBASA-ESASA DOTTED, LATIN SMALL LETTER B +0061 073C 059A 0316 1DFA 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062;0061 1DFA 073C 0316 059A 0062; # (a◌ܼ◌֚◌̖◌᷺b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; a◌᷺◌ܼ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC HBASA-ESASA DOTTED, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 073D 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062;00E0 05AE 073D 0315 0062;0061 05AE 0300 073D 0315 0062; # (a◌̕◌̀◌֮◌ܽb; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; à◌֮◌ܽ◌̕b; a◌֮◌̀◌ܽ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC ESASA ABOVE, LATIN SMALL LETTER B 0061 073D 0315 0300 05AE 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062;0061 05AE 073D 0300 0315 0062; # (a◌ܽ◌̕◌̀◌֮b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; a◌֮◌ܽ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC ESASA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 073E 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062;0061 302A 0316 073E 059A 0062; # (a◌֚◌̖◌〪◌ܾb; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; a◌〪◌̖◌ܾ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC ESASA BELOW, LATIN SMALL LETTER B -0061 073E 059A 0316 302A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062;0061 302A 073E 0316 059A 0062; # (a◌ܾ◌֚◌̖◌〪b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; a◌〪◌ܾ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ESASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 073E 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062;0061 1DFA 0316 073E 059A 0062; # (a◌֚◌̖◌᷺◌ܾb; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; a◌᷺◌̖◌ܾ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC ESASA BELOW, LATIN SMALL LETTER B +0061 073E 059A 0316 1DFA 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062;0061 1DFA 073E 0316 059A 0062; # (a◌ܾ◌֚◌̖◌᷺b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; a◌᷺◌ܾ◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC ESASA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 073F 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062;00E0 05AE 073F 0315 0062;0061 05AE 0300 073F 0315 0062; # (a◌̕◌̀◌֮◌ܿb; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; à◌֮◌ܿ◌̕b; a◌֮◌̀◌ܿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC RWAHA, LATIN SMALL LETTER B 0061 073F 0315 0300 05AE 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062;0061 05AE 073F 0300 0315 0062; # (a◌ܿ◌̕◌̀◌֮b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; a◌֮◌ܿ◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC RWAHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0740 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062;00E0 05AE 0740 0315 0062;0061 05AE 0300 0740 0315 0062; # (a◌̕◌̀◌֮◌݀b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; à◌֮◌݀◌̕b; a◌֮◌̀◌݀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC FEMININE DOT, LATIN SMALL LETTER B 0061 0740 0315 0300 05AE 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062;0061 05AE 0740 0300 0315 0062; # (a◌݀◌̕◌̀◌֮b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; a◌֮◌݀◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC FEMININE DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0741 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062;00E0 05AE 0741 0315 0062;0061 05AE 0300 0741 0315 0062; # (a◌̕◌̀◌֮◌݁b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; à◌֮◌݁◌̕b; a◌֮◌̀◌݁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC QUSHSHAYA, LATIN SMALL LETTER B 0061 0741 0315 0300 05AE 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062;0061 05AE 0741 0300 0315 0062; # (a◌݁◌̕◌̀◌֮b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; a◌֮◌݁◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC QUSHSHAYA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0742 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062;0061 302A 0316 0742 059A 0062; # (a◌֚◌̖◌〪◌݂b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; a◌〪◌̖◌݂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC RUKKAKHA, LATIN SMALL LETTER B -0061 0742 059A 0316 302A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062;0061 302A 0742 0316 059A 0062; # (a◌݂◌֚◌̖◌〪b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; a◌〪◌݂◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RUKKAKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0742 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062;0061 1DFA 0316 0742 059A 0062; # (a◌֚◌̖◌᷺◌݂b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; a◌᷺◌̖◌݂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC RUKKAKHA, LATIN SMALL LETTER B +0061 0742 059A 0316 1DFA 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062;0061 1DFA 0742 0316 059A 0062; # (a◌݂◌֚◌̖◌᷺b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; a◌᷺◌݂◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC RUKKAKHA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0743 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062;00E0 05AE 0743 0315 0062;0061 05AE 0300 0743 0315 0062; # (a◌̕◌̀◌֮◌݃b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; à◌֮◌݃◌̕b; a◌֮◌̀◌݃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC TWO VERTICAL DOTS ABOVE, LATIN SMALL LETTER B 0061 0743 0315 0300 05AE 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062;0061 05AE 0743 0300 0315 0062; # (a◌݃◌̕◌̀◌֮b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; a◌֮◌݃◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0744 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062;0061 302A 0316 0744 059A 0062; # (a◌֚◌̖◌〪◌݄b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; a◌〪◌̖◌݄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC TWO VERTICAL DOTS BELOW, LATIN SMALL LETTER B -0061 0744 059A 0316 302A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062;0061 302A 0744 0316 059A 0062; # (a◌݄◌֚◌̖◌〪b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; a◌〪◌݄◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0744 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062;0061 1DFA 0316 0744 059A 0062; # (a◌֚◌̖◌᷺◌݄b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; a◌᷺◌̖◌݄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC TWO VERTICAL DOTS BELOW, LATIN SMALL LETTER B +0061 0744 059A 0316 1DFA 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062;0061 1DFA 0744 0316 059A 0062; # (a◌݄◌֚◌̖◌᷺b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; a◌᷺◌݄◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC TWO VERTICAL DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0745 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062;00E0 05AE 0745 0315 0062;0061 05AE 0300 0745 0315 0062; # (a◌̕◌̀◌֮◌݅b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; à◌֮◌݅◌̕b; a◌֮◌̀◌݅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC THREE DOTS ABOVE, LATIN SMALL LETTER B 0061 0745 0315 0300 05AE 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062;0061 05AE 0745 0300 0315 0062; # (a◌݅◌̕◌̀◌֮b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; a◌֮◌݅◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0746 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062;0061 302A 0316 0746 059A 0062; # (a◌֚◌̖◌〪◌݆b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; a◌〪◌̖◌݆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC THREE DOTS BELOW, LATIN SMALL LETTER B -0061 0746 059A 0316 302A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062;0061 302A 0746 0316 059A 0062; # (a◌݆◌֚◌̖◌〪b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; a◌〪◌݆◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0746 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062;0061 1DFA 0316 0746 059A 0062; # (a◌֚◌̖◌᷺◌݆b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; a◌᷺◌̖◌݆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC THREE DOTS BELOW, LATIN SMALL LETTER B +0061 0746 059A 0316 1DFA 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062;0061 1DFA 0746 0316 059A 0062; # (a◌݆◌֚◌̖◌᷺b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; a◌᷺◌݆◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0747 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062;00E0 05AE 0747 0315 0062;0061 05AE 0300 0747 0315 0062; # (a◌̕◌̀◌֮◌݇b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; à◌֮◌݇◌̕b; a◌֮◌̀◌݇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC OBLIQUE LINE ABOVE, LATIN SMALL LETTER B 0061 0747 0315 0300 05AE 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062;0061 05AE 0747 0300 0315 0062; # (a◌݇◌̕◌̀◌֮b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; a◌֮◌݇◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0748 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062;0061 302A 0316 0748 059A 0062; # (a◌֚◌̖◌〪◌݈b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; a◌〪◌̖◌݈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SYRIAC OBLIQUE LINE BELOW, LATIN SMALL LETTER B -0061 0748 059A 0316 302A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062;0061 302A 0748 0316 059A 0062; # (a◌݈◌֚◌̖◌〪b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; a◌〪◌݈◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0748 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062;0061 1DFA 0316 0748 059A 0062; # (a◌֚◌̖◌᷺◌݈b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; a◌᷺◌̖◌݈◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SYRIAC OBLIQUE LINE BELOW, LATIN SMALL LETTER B +0061 0748 059A 0316 1DFA 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062;0061 1DFA 0748 0316 059A 0062; # (a◌݈◌֚◌̖◌᷺b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; a◌᷺◌݈◌̖◌֚b; ) LATIN SMALL LETTER A, SYRIAC OBLIQUE LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0749 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062;00E0 05AE 0749 0315 0062;0061 05AE 0300 0749 0315 0062; # (a◌̕◌̀◌֮◌݉b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; à◌֮◌݉◌̕b; a◌֮◌̀◌݉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC MUSIC, LATIN SMALL LETTER B 0061 0749 0315 0300 05AE 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062;0061 05AE 0749 0300 0315 0062; # (a◌݉◌̕◌̀◌֮b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; a◌֮◌݉◌̀◌̕b; ) LATIN SMALL LETTER A, SYRIAC MUSIC, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 074A 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062;00E0 05AE 074A 0315 0062;0061 05AE 0300 074A 0315 0062; # (a◌̕◌̀◌֮◌݊b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; à◌֮◌݊◌̕b; a◌֮◌̀◌݊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SYRIAC BARREKH, LATIN SMALL LETTER B @@ -17489,12 +17610,12 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 07F0 0315 0300 05AE 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062;0061 05AE 07F0 0300 0315 0062; # (a◌߰◌̕◌̀◌֮b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; a◌֮◌߰◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG LOW TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 07F1 0062;00E0 05AE 07F1 0315 0062;0061 05AE 0300 07F1 0315 0062;00E0 05AE 07F1 0315 0062;0061 05AE 0300 07F1 0315 0062; # (a◌̕◌̀◌֮◌߱b; à◌֮◌߱◌̕b; a◌֮◌̀◌߱◌̕b; à◌֮◌߱◌̕b; a◌֮◌̀◌߱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING LONG RISING TONE, LATIN SMALL LETTER B 0061 07F1 0315 0300 05AE 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062;0061 05AE 07F1 0300 0315 0062; # (a◌߱◌̕◌̀◌֮b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; a◌֮◌߱◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING LONG RISING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 07F2 0062;0061 302A 0316 07F2 059A 0062;0061 302A 0316 07F2 059A 0062;0061 302A 0316 07F2 059A 0062;0061 302A 0316 07F2 059A 0062; # (a◌֚◌̖◌〪◌߲b; a◌〪◌̖◌߲◌֚b; a◌〪◌̖◌߲◌֚b; a◌〪◌̖◌߲◌֚b; a◌〪◌̖◌߲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, NKO COMBINING NASALIZATION MARK, LATIN SMALL LETTER B -0061 07F2 059A 0316 302A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062; # (a◌߲◌֚◌̖◌〪b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; ) LATIN SMALL LETTER A, NKO COMBINING NASALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 07F2 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062;0061 1DFA 0316 07F2 059A 0062; # (a◌֚◌̖◌᷺◌߲b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; a◌᷺◌̖◌߲◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, NKO COMBINING NASALIZATION MARK, LATIN SMALL LETTER B +0061 07F2 059A 0316 1DFA 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062;0061 1DFA 07F2 0316 059A 0062; # (a◌߲◌֚◌̖◌᷺b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; a◌᷺◌߲◌̖◌֚b; ) LATIN SMALL LETTER A, NKO COMBINING NASALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 07F3 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062; # (a◌̕◌̀◌֮◌߳b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING DOUBLE DOT ABOVE, LATIN SMALL LETTER B 0061 07F3 0315 0300 05AE 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062; # (a◌߳◌̕◌̀◌֮b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING DOUBLE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 07FD 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062; # (a◌֚◌̖◌〪◌߽b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, NKO DANTAYALAN, LATIN SMALL LETTER B -0061 07FD 059A 0316 302A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062; # (a◌߽◌֚◌̖◌〪b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; ) LATIN SMALL LETTER A, NKO DANTAYALAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 07FD 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062;0061 1DFA 0316 07FD 059A 0062; # (a◌֚◌̖◌᷺◌߽b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; a◌᷺◌̖◌߽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, NKO DANTAYALAN, LATIN SMALL LETTER B +0061 07FD 059A 0316 1DFA 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062;0061 1DFA 07FD 0316 059A 0062; # (a◌߽◌֚◌̖◌᷺b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; a◌᷺◌߽◌̖◌֚b; ) LATIN SMALL LETTER A, NKO DANTAYALAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0816 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062; # (a◌̕◌̀◌֮◌ࠖb; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN, LATIN SMALL LETTER B 0061 0816 0315 0300 05AE 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062; # (a◌ࠖ◌̕◌̀◌֮b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK IN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0817 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062; # (a◌̕◌̀◌֮◌ࠗb; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN-ALAF, LATIN SMALL LETTER B @@ -17537,14 +17658,48 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 082C 0315 0300 05AE 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062;0061 05AE 082C 0300 0315 0062; # (a◌ࠬ◌̕◌̀◌֮b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; a◌֮◌ࠬ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN VOWEL SIGN SUKUN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 082D 0062;00E0 05AE 082D 0315 0062;0061 05AE 0300 082D 0315 0062;00E0 05AE 082D 0315 0062;0061 05AE 0300 082D 0315 0062; # (a◌̕◌̀◌֮◌࠭b; à◌֮◌࠭◌̕b; a◌֮◌̀◌࠭◌̕b; à◌֮◌࠭◌̕b; a◌֮◌̀◌࠭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK NEQUDAA, LATIN SMALL LETTER B 0061 082D 0315 0300 05AE 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062;0061 05AE 082D 0300 0315 0062; # (a◌࠭◌̕◌̀◌֮b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; a◌֮◌࠭◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK NEQUDAA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0859 0062;0061 302A 0316 0859 059A 0062;0061 302A 0316 0859 059A 0062;0061 302A 0316 0859 059A 0062;0061 302A 0316 0859 059A 0062; # (a◌֚◌̖◌〪◌࡙b; a◌〪◌̖◌࡙◌֚b; a◌〪◌̖◌࡙◌֚b; a◌〪◌̖◌࡙◌֚b; a◌〪◌̖◌࡙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC AFFRICATION MARK, LATIN SMALL LETTER B -0061 0859 059A 0316 302A 0062;0061 302A 0859 0316 059A 0062;0061 302A 0859 0316 059A 0062;0061 302A 0859 0316 059A 0062;0061 302A 0859 0316 059A 0062; # (a◌࡙◌֚◌̖◌〪b; a◌〪◌࡙◌̖◌֚b; a◌〪◌࡙◌̖◌֚b; a◌〪◌࡙◌̖◌֚b; a◌〪◌࡙◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC AFFRICATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 085A 0062;0061 302A 0316 085A 059A 0062;0061 302A 0316 085A 059A 0062;0061 302A 0316 085A 059A 0062;0061 302A 0316 085A 059A 0062; # (a◌֚◌̖◌〪◌࡚b; a◌〪◌̖◌࡚◌֚b; a◌〪◌̖◌࡚◌֚b; a◌〪◌̖◌࡚◌֚b; a◌〪◌̖◌࡚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC VOCALIZATION MARK, LATIN SMALL LETTER B -0061 085A 059A 0316 302A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌〪b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 085B 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062; # (a◌֚◌̖◌〪◌࡛b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B -0061 085B 059A 0316 302A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌〪b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 08D3 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062; # (a◌֚◌̖◌〪◌࣓b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW WAW, LATIN SMALL LETTER B -0061 08D3 059A 0316 302A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062; # (a◌࣓◌֚◌̖◌〪b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WAW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0859 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062;0061 1DFA 0316 0859 059A 0062; # (a◌֚◌̖◌᷺◌࡙b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; a◌᷺◌̖◌࡙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC AFFRICATION MARK, LATIN SMALL LETTER B +0061 0859 059A 0316 1DFA 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062;0061 1DFA 0859 0316 059A 0062; # (a◌࡙◌֚◌̖◌᷺b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; a◌᷺◌࡙◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC AFFRICATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 085A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062;0061 1DFA 0316 085A 059A 0062; # (a◌֚◌̖◌᷺◌࡚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; a◌᷺◌̖◌࡚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC VOCALIZATION MARK, LATIN SMALL LETTER B +0061 085A 059A 0316 1DFA 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062;0061 1DFA 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌᷺b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; a◌᷺◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 085B 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062;0061 1DFA 0316 085B 059A 0062; # (a◌֚◌̖◌᷺◌࡛b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; a◌᷺◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B +0061 085B 059A 0316 1DFA 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062;0061 1DFA 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌᷺b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; a◌᷺◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 0898 0062;00E0 05AE 0898 0315 0062;0061 05AE 0300 0898 0315 0062;00E0 05AE 0898 0315 0062;0061 05AE 0300 0898 0315 0062; # (a◌̕◌̀◌֮◌࢘b; à◌֮◌࢘◌̕b; a◌֮◌̀◌࢘◌̕b; à◌֮◌࢘◌̕b; a◌֮◌̀◌࢘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AL-JUZ, LATIN SMALL LETTER B +0061 0898 0315 0300 05AE 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062;0061 05AE 0898 0300 0315 0062; # (a◌࢘◌̕◌̀◌֮b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; a◌֮◌࢘◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AL-JUZ, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0899 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062;0061 1DFA 0316 0899 059A 0062; # (a◌֚◌̖◌᷺◌࢙b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; a◌᷺◌̖◌࢙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD ISHMAAM, LATIN SMALL LETTER B +0061 0899 059A 0316 1DFA 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062;0061 1DFA 0899 0316 059A 0062; # (a◌࢙◌֚◌̖◌᷺b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; a◌᷺◌࢙◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD ISHMAAM, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 089A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062;0061 1DFA 0316 089A 059A 0062; # (a◌֚◌̖◌᷺◌࢚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; a◌᷺◌̖◌࢚◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD IMAALA, LATIN SMALL LETTER B +0061 089A 059A 0316 1DFA 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062;0061 1DFA 089A 0316 059A 0062; # (a◌࢚◌֚◌̖◌᷺b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; a◌᷺◌࢚◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD IMAALA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 089B 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062;0061 1DFA 0316 089B 059A 0062; # (a◌֚◌̖◌᷺◌࢛b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; a◌᷺◌̖◌࢛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD TASHEEL, LATIN SMALL LETTER B +0061 089B 059A 0316 1DFA 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062;0061 1DFA 089B 0316 059A 0062; # (a◌࢛◌֚◌̖◌᷺b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; a◌᷺◌࢛◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD TASHEEL, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 089C 0062;00E0 05AE 089C 0315 0062;0061 05AE 0300 089C 0315 0062;00E0 05AE 089C 0315 0062;0061 05AE 0300 089C 0315 0062; # (a◌̕◌̀◌֮◌࢜b; à◌֮◌࢜◌̕b; a◌֮◌̀◌࢜◌̕b; à◌֮◌࢜◌̕b; a◌֮◌̀◌࢜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC MADDA WAAJIB, LATIN SMALL LETTER B +0061 089C 0315 0300 05AE 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062;0061 05AE 089C 0300 0315 0062; # (a◌࢜◌̕◌̀◌֮b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; a◌֮◌࢜◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC MADDA WAAJIB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089D 0062;00E0 05AE 089D 0315 0062;0061 05AE 0300 089D 0315 0062;00E0 05AE 089D 0315 0062;0061 05AE 0300 089D 0315 0062; # (a◌̕◌̀◌֮◌࢝b; à◌֮◌࢝◌̕b; a◌֮◌̀◌࢝◌̕b; à◌֮◌࢝◌̕b; a◌֮◌̀◌࢝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SUPERSCRIPT ALEF MOKHASSAS, LATIN SMALL LETTER B +0061 089D 0315 0300 05AE 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062;0061 05AE 089D 0300 0315 0062; # (a◌࢝◌̕◌̀◌֮b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; a◌֮◌࢝◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SUPERSCRIPT ALEF MOKHASSAS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089E 0062;00E0 05AE 089E 0315 0062;0061 05AE 0300 089E 0315 0062;00E0 05AE 089E 0315 0062;0061 05AE 0300 089E 0315 0062; # (a◌̕◌̀◌֮◌࢞b; à◌֮◌࢞◌̕b; a◌֮◌̀◌࢞◌̕b; à◌֮◌࢞◌̕b; a◌֮◌̀◌࢞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLED MADDA, LATIN SMALL LETTER B +0061 089E 0315 0300 05AE 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062;0061 05AE 089E 0300 0315 0062; # (a◌࢞◌̕◌̀◌֮b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; a◌֮◌࢞◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DOUBLED MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 089F 0062;00E0 05AE 089F 0315 0062;0061 05AE 0300 089F 0315 0062;00E0 05AE 089F 0315 0062;0061 05AE 0300 089F 0315 0062; # (a◌̕◌̀◌֮◌࢟b; à◌֮◌࢟◌̕b; a◌֮◌̀◌࢟◌̕b; à◌֮◌࢟◌̕b; a◌֮◌̀◌࢟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC HALF MADDA OVER MADDA, LATIN SMALL LETTER B +0061 089F 0315 0300 05AE 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062;0061 05AE 089F 0300 0315 0062; # (a◌࢟◌̕◌̀◌֮b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; a◌֮◌࢟◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC HALF MADDA OVER MADDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CA 0062;00E0 05AE 08CA 0315 0062;0061 05AE 0300 08CA 0315 0062;00E0 05AE 08CA 0315 0062;0061 05AE 0300 08CA 0315 0062; # (a◌̕◌̀◌֮◌࣊b; à◌֮◌࣊◌̕b; a◌֮◌̀◌࣊◌̕b; à◌֮◌࣊◌̕b; a◌֮◌̀◌࣊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH FARSI YEH, LATIN SMALL LETTER B +0061 08CA 0315 0300 05AE 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062;0061 05AE 08CA 0300 0315 0062; # (a◌࣊◌̕◌̀◌֮b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; a◌֮◌࣊◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH FARSI YEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CB 0062;00E0 05AE 08CB 0315 0062;0061 05AE 0300 08CB 0315 0062;00E0 05AE 08CB 0315 0062;0061 05AE 0300 08CB 0315 0062; # (a◌̕◌̀◌֮◌࣋b; à◌֮◌࣋◌̕b; a◌֮◌̀◌࣋◌̕b; à◌֮◌࣋◌̕b; a◌֮◌̀◌࣋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW, LATIN SMALL LETTER B +0061 08CB 0315 0300 05AE 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062;0061 05AE 08CB 0300 0315 0062; # (a◌࣋◌̕◌̀◌֮b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; a◌֮◌࣋◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CC 0062;00E0 05AE 08CC 0315 0062;0061 05AE 0300 08CC 0315 0062;00E0 05AE 08CC 0315 0062;0061 05AE 0300 08CC 0315 0062; # (a◌̕◌̀◌֮◌࣌b; à◌֮◌࣌◌̕b; a◌֮◌̀◌࣌◌̕b; à◌֮◌࣌◌̕b; a◌֮◌̀◌࣌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD SAH, LATIN SMALL LETTER B +0061 08CC 0315 0300 05AE 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062;0061 05AE 08CC 0300 0315 0062; # (a◌࣌◌̕◌̀◌֮b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; a◌֮◌࣌◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD SAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CD 0062;00E0 05AE 08CD 0315 0062;0061 05AE 0300 08CD 0315 0062;00E0 05AE 08CD 0315 0062;0061 05AE 0300 08CD 0315 0062; # (a◌̕◌̀◌֮◌࣍b; à◌֮◌࣍◌̕b; a◌֮◌̀◌࣍◌̕b; à◌֮◌࣍◌̕b; a◌֮◌̀◌࣍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH ZAH, LATIN SMALL LETTER B +0061 08CD 0315 0300 05AE 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062;0061 05AE 08CD 0300 0315 0062; # (a◌࣍◌̕◌̀◌֮b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; a◌֮◌࣍◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH ZAH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08CE 0062;00E0 05AE 08CE 0315 0062;0061 05AE 0300 08CE 0315 0062;00E0 05AE 08CE 0315 0062;0061 05AE 0300 08CE 0315 0062; # (a◌̕◌̀◌֮◌࣎b; à◌֮◌࣎◌̕b; a◌֮◌̀◌࣎◌̕b; à◌֮◌࣎◌̕b; a◌֮◌̀◌࣎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC LARGE ROUND DOT ABOVE, LATIN SMALL LETTER B +0061 08CE 0315 0300 05AE 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062;0061 05AE 08CE 0300 0315 0062; # (a◌࣎◌̕◌̀◌֮b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; a◌֮◌࣎◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08CF 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062;0061 1DFA 0316 08CF 059A 0062; # (a◌֚◌̖◌᷺◌࣏b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; a◌᷺◌̖◌࣏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE ROUND DOT BELOW, LATIN SMALL LETTER B +0061 08CF 059A 0316 1DFA 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062;0061 1DFA 08CF 0316 059A 0062; # (a◌࣏◌֚◌̖◌᷺b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; a◌᷺◌࣏◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D0 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062;0061 1DFA 0316 08D0 059A 0062; # (a◌֚◌̖◌᷺◌࣐b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; a◌᷺◌̖◌࣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SUKUN BELOW, LATIN SMALL LETTER B +0061 08D0 059A 0316 1DFA 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062;0061 1DFA 08D0 0316 059A 0062; # (a◌࣐◌֚◌̖◌᷺b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; a◌᷺◌࣐◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SUKUN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D1 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062;0061 1DFA 0316 08D1 059A 0062; # (a◌֚◌̖◌᷺◌࣑b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; a◌᷺◌̖◌࣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE CIRCLE BELOW, LATIN SMALL LETTER B +0061 08D1 059A 0316 1DFA 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062;0061 1DFA 08D1 0316 059A 0062; # (a◌࣑◌֚◌̖◌᷺b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; a◌᷺◌࣑◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE CIRCLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D2 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062;0061 1DFA 0316 08D2 059A 0062; # (a◌֚◌̖◌᷺◌࣒b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; a◌᷺◌̖◌࣒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW, LATIN SMALL LETTER B +0061 08D2 059A 0316 1DFA 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062;0061 1DFA 08D2 0316 059A 0062; # (a◌࣒◌֚◌̖◌᷺b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; a◌᷺◌࣒◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08D3 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062;0061 1DFA 0316 08D3 059A 0062; # (a◌֚◌̖◌᷺◌࣓b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; a◌᷺◌̖◌࣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WAW, LATIN SMALL LETTER B +0061 08D3 059A 0316 1DFA 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062;0061 1DFA 08D3 0316 059A 0062; # (a◌࣓◌֚◌̖◌᷺b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; a◌᷺◌࣓◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WAW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08D4 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062; # (a◌̕◌̀◌֮◌ࣔb; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AR-RUB, LATIN SMALL LETTER B 0061 08D4 0315 0300 05AE 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062; # (a◌ࣔ◌̕◌̀◌֮b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AR-RUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08D5 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062; # (a◌̕◌̀◌֮◌ࣕb; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SAD, LATIN SMALL LETTER B @@ -17573,32 +17728,32 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 08E0 0315 0300 05AE 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062; # (a◌࣠◌̕◌̀◌֮b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH FOOTNOTE MARKER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E1 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062; # (a◌̕◌̀◌֮◌࣡b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SIGN SAFHA, LATIN SMALL LETTER B 0061 08E1 0315 0300 05AE 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062; # (a◌࣡◌̕◌̀◌֮b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SIGN SAFHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08E3 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062; # (a◌֚◌̖◌〪◌ࣣb; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC TURNED DAMMA BELOW, LATIN SMALL LETTER B -0061 08E3 059A 0316 302A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062; # (a◌ࣣ◌֚◌̖◌〪b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TURNED DAMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E3 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062;0061 1DFA 0316 08E3 059A 0062; # (a◌֚◌̖◌᷺◌ࣣb; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; a◌᷺◌̖◌ࣣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TURNED DAMMA BELOW, LATIN SMALL LETTER B +0061 08E3 059A 0316 1DFA 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062;0061 1DFA 08E3 0316 059A 0062; # (a◌ࣣ◌֚◌̖◌᷺b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; a◌᷺◌ࣣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TURNED DAMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E4 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062; # (a◌̕◌̀◌֮◌ࣤb; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY FATHA, LATIN SMALL LETTER B 0061 08E4 0315 0300 05AE 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062; # (a◌ࣤ◌̕◌̀◌֮b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY FATHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E5 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062; # (a◌̕◌̀◌֮◌ࣥb; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY DAMMA, LATIN SMALL LETTER B 0061 08E5 0315 0300 05AE 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062;0061 05AE 08E5 0300 0315 0062; # (a◌ࣥ◌̕◌̀◌֮b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; a◌֮◌ࣥ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY DAMMA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08E6 0062;0061 302A 0316 08E6 059A 0062;0061 302A 0316 08E6 059A 0062;0061 302A 0316 08E6 059A 0062;0061 302A 0316 08E6 059A 0062; # (a◌֚◌̖◌〪◌ࣦb; a◌〪◌̖◌ࣦ◌֚b; a◌〪◌̖◌ࣦ◌֚b; a◌〪◌̖◌ࣦ◌֚b; a◌〪◌̖◌ࣦ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC CURLY KASRA, LATIN SMALL LETTER B -0061 08E6 059A 0316 302A 0062;0061 302A 08E6 0316 059A 0062;0061 302A 08E6 0316 059A 0062;0061 302A 08E6 0316 059A 0062;0061 302A 08E6 0316 059A 0062; # (a◌ࣦ◌֚◌̖◌〪b; a◌〪◌ࣦ◌̖◌֚b; a◌〪◌ࣦ◌̖◌֚b; a◌〪◌ࣦ◌̖◌֚b; a◌〪◌ࣦ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E6 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062;0061 1DFA 0316 08E6 059A 0062; # (a◌֚◌̖◌᷺◌ࣦb; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; a◌᷺◌̖◌ࣦ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC CURLY KASRA, LATIN SMALL LETTER B +0061 08E6 059A 0316 1DFA 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062;0061 1DFA 08E6 0316 059A 0062; # (a◌ࣦ◌֚◌̖◌᷺b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; a◌᷺◌ࣦ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E7 0062;00E0 05AE 08E7 0315 0062;0061 05AE 0300 08E7 0315 0062;00E0 05AE 08E7 0315 0062;0061 05AE 0300 08E7 0315 0062; # (a◌̕◌̀◌֮◌ࣧb; à◌֮◌ࣧ◌̕b; a◌֮◌̀◌ࣧ◌̕b; à◌֮◌ࣧ◌̕b; a◌֮◌̀◌ࣧ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY FATHATAN, LATIN SMALL LETTER B 0061 08E7 0315 0300 05AE 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062;0061 05AE 08E7 0300 0315 0062; # (a◌ࣧ◌̕◌̀◌֮b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; a◌֮◌ࣧ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY FATHATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E8 0062;00E0 05AE 08E8 0315 0062;0061 05AE 0300 08E8 0315 0062;00E0 05AE 08E8 0315 0062;0061 05AE 0300 08E8 0315 0062; # (a◌̕◌̀◌֮◌ࣨb; à◌֮◌ࣨ◌̕b; a◌֮◌̀◌ࣨ◌̕b; à◌֮◌ࣨ◌̕b; a◌֮◌̀◌ࣨ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY DAMMATAN, LATIN SMALL LETTER B 0061 08E8 0315 0300 05AE 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062;0061 05AE 08E8 0300 0315 0062; # (a◌ࣨ◌̕◌̀◌֮b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; a◌֮◌ࣨ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY DAMMATAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08E9 0062;0061 302A 0316 08E9 059A 0062;0061 302A 0316 08E9 059A 0062;0061 302A 0316 08E9 059A 0062;0061 302A 0316 08E9 059A 0062; # (a◌֚◌̖◌〪◌ࣩb; a◌〪◌̖◌ࣩ◌֚b; a◌〪◌̖◌ࣩ◌֚b; a◌〪◌̖◌ࣩ◌֚b; a◌〪◌̖◌ࣩ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC CURLY KASRATAN, LATIN SMALL LETTER B -0061 08E9 059A 0316 302A 0062;0061 302A 08E9 0316 059A 0062;0061 302A 08E9 0316 059A 0062;0061 302A 08E9 0316 059A 0062;0061 302A 08E9 0316 059A 0062; # (a◌ࣩ◌֚◌̖◌〪b; a◌〪◌ࣩ◌̖◌֚b; a◌〪◌ࣩ◌̖◌֚b; a◌〪◌ࣩ◌̖◌֚b; a◌〪◌ࣩ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRATAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08E9 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062;0061 1DFA 0316 08E9 059A 0062; # (a◌֚◌̖◌᷺◌ࣩb; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; a◌᷺◌̖◌ࣩ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC CURLY KASRATAN, LATIN SMALL LETTER B +0061 08E9 059A 0316 1DFA 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062;0061 1DFA 08E9 0316 059A 0062; # (a◌ࣩ◌֚◌̖◌᷺b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; a◌᷺◌ࣩ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC CURLY KASRATAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08EA 0062;00E0 05AE 08EA 0315 0062;0061 05AE 0300 08EA 0315 0062;00E0 05AE 08EA 0315 0062;0061 05AE 0300 08EA 0315 0062; # (a◌̕◌̀◌֮◌࣪b; à◌֮◌࣪◌̕b; a◌֮◌̀◌࣪◌̕b; à◌֮◌࣪◌̕b; a◌֮◌̀◌࣪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE ONE DOT ABOVE, LATIN SMALL LETTER B 0061 08EA 0315 0300 05AE 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062;0061 05AE 08EA 0300 0315 0062; # (a◌࣪◌̕◌̀◌֮b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; a◌֮◌࣪◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE ONE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08EB 0062;00E0 05AE 08EB 0315 0062;0061 05AE 0300 08EB 0315 0062;00E0 05AE 08EB 0315 0062;0061 05AE 0300 08EB 0315 0062; # (a◌̕◌̀◌֮◌࣫b; à◌֮◌࣫◌̕b; a◌֮◌̀◌࣫◌̕b; à◌֮◌࣫◌̕b; a◌֮◌̀◌࣫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE TWO DOTS ABOVE, LATIN SMALL LETTER B 0061 08EB 0315 0300 05AE 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062;0061 05AE 08EB 0300 0315 0062; # (a◌࣫◌̕◌̀◌֮b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; a◌֮◌࣫◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08EC 0062;00E0 05AE 08EC 0315 0062;0061 05AE 0300 08EC 0315 0062;00E0 05AE 08EC 0315 0062;0061 05AE 0300 08EC 0315 0062; # (a◌̕◌̀◌֮◌࣬b; à◌֮◌࣬◌̕b; a◌֮◌̀◌࣬◌̕b; à◌֮◌࣬◌̕b; a◌֮◌̀◌࣬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC TONE LOOP ABOVE, LATIN SMALL LETTER B 0061 08EC 0315 0300 05AE 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062;0061 05AE 08EC 0300 0315 0062; # (a◌࣬◌̕◌̀◌֮b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; a◌֮◌࣬◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC TONE LOOP ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08ED 0062;0061 302A 0316 08ED 059A 0062;0061 302A 0316 08ED 059A 0062;0061 302A 0316 08ED 059A 0062;0061 302A 0316 08ED 059A 0062; # (a◌֚◌̖◌〪◌࣭b; a◌〪◌̖◌࣭◌֚b; a◌〪◌̖◌࣭◌֚b; a◌〪◌̖◌࣭◌֚b; a◌〪◌̖◌࣭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC TONE ONE DOT BELOW, LATIN SMALL LETTER B -0061 08ED 059A 0316 302A 0062;0061 302A 08ED 0316 059A 0062;0061 302A 08ED 0316 059A 0062;0061 302A 08ED 0316 059A 0062;0061 302A 08ED 0316 059A 0062; # (a◌࣭◌֚◌̖◌〪b; a◌〪◌࣭◌̖◌֚b; a◌〪◌࣭◌̖◌֚b; a◌〪◌࣭◌̖◌֚b; a◌〪◌࣭◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE ONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 08EE 0062;0061 302A 0316 08EE 059A 0062;0061 302A 0316 08EE 059A 0062;0061 302A 0316 08EE 059A 0062;0061 302A 0316 08EE 059A 0062; # (a◌֚◌̖◌〪◌࣮b; a◌〪◌̖◌࣮◌֚b; a◌〪◌̖◌࣮◌֚b; a◌〪◌̖◌࣮◌֚b; a◌〪◌̖◌࣮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B -0061 08EE 059A 0316 302A 0062;0061 302A 08EE 0316 059A 0062;0061 302A 08EE 0316 059A 0062;0061 302A 08EE 0316 059A 0062;0061 302A 08EE 0316 059A 0062; # (a◌࣮◌֚◌̖◌〪b; a◌〪◌࣮◌̖◌֚b; a◌〪◌࣮◌̖◌֚b; a◌〪◌࣮◌̖◌֚b; a◌〪◌࣮◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 08EF 0062;0061 302A 0316 08EF 059A 0062;0061 302A 0316 08EF 059A 0062;0061 302A 0316 08EF 059A 0062;0061 302A 0316 08EF 059A 0062; # (a◌֚◌̖◌〪◌࣯b; a◌〪◌̖◌࣯◌֚b; a◌〪◌̖◌࣯◌֚b; a◌〪◌̖◌࣯◌֚b; a◌〪◌̖◌࣯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC TONE LOOP BELOW, LATIN SMALL LETTER B -0061 08EF 059A 0316 302A 0062;0061 302A 08EF 0316 059A 0062;0061 302A 08EF 0316 059A 0062;0061 302A 08EF 0316 059A 0062;0061 302A 08EF 0316 059A 0062; # (a◌࣯◌֚◌̖◌〪b; a◌〪◌࣯◌̖◌֚b; a◌〪◌࣯◌̖◌֚b; a◌〪◌࣯◌̖◌֚b; a◌〪◌࣯◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE LOOP BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08ED 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062;0061 1DFA 0316 08ED 059A 0062; # (a◌֚◌̖◌᷺◌࣭b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; a◌᷺◌̖◌࣭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE ONE DOT BELOW, LATIN SMALL LETTER B +0061 08ED 059A 0316 1DFA 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062;0061 1DFA 08ED 0316 059A 0062; # (a◌࣭◌֚◌̖◌᷺b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; a◌᷺◌࣭◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE ONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08EE 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062;0061 1DFA 0316 08EE 059A 0062; # (a◌֚◌̖◌᷺◌࣮b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; a◌᷺◌̖◌࣮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B +0061 08EE 059A 0316 1DFA 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062;0061 1DFA 08EE 0316 059A 0062; # (a◌࣮◌֚◌̖◌᷺b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; a◌᷺◌࣮◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08EF 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062;0061 1DFA 0316 08EF 059A 0062; # (a◌֚◌̖◌᷺◌࣯b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; a◌᷺◌̖◌࣯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC TONE LOOP BELOW, LATIN SMALL LETTER B +0061 08EF 059A 0316 1DFA 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062;0061 1DFA 08EF 0316 059A 0062; # (a◌࣯◌֚◌̖◌᷺b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; a◌᷺◌࣯◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TONE LOOP BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 064C 064B FB1E 08F0 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062;0061 FB1E 064B 08F0 064C 0062; # (a◌ٌ◌ً◌ﬞ◌ࣰb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; a◌ﬞ◌ً◌ࣰ◌ٌb; ) LATIN SMALL LETTER A, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, ARABIC OPEN FATHATAN, LATIN SMALL LETTER B 0061 08F0 064C 064B FB1E 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062;0061 FB1E 08F0 064B 064C 0062; # (a◌ࣰ◌ٌ◌ً◌ﬞb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; a◌ﬞ◌ࣰ◌ً◌ٌb; ) LATIN SMALL LETTER A, ARABIC OPEN FATHATAN, ARABIC DAMMATAN, ARABIC FATHATAN, HEBREW POINT JUDEO-SPANISH VARIKA, LATIN SMALL LETTER B 0061 064D 064C 064B 08F1 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062;0061 064B 064C 08F1 064D 0062; # (a◌ٍ◌ٌ◌ً◌ࣱb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; a◌ً◌ٌ◌ࣱ◌ٍb; ) LATIN SMALL LETTER A, ARABIC KASRATAN, ARABIC DAMMATAN, ARABIC FATHATAN, ARABIC OPEN DAMMATAN, LATIN SMALL LETTER B @@ -17611,16 +17766,16 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 08F4 0315 0300 05AE 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062;0061 05AE 08F4 0300 0315 0062; # (a◌ࣴ◌̕◌̀◌֮b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; a◌֮◌ࣴ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH RING, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08F5 0062;00E0 05AE 08F5 0315 0062;0061 05AE 0300 08F5 0315 0062;00E0 05AE 08F5 0315 0062;0061 05AE 0300 08F5 0315 0062; # (a◌̕◌̀◌֮◌ࣵb; à◌֮◌ࣵ◌̕b; a◌֮◌̀◌ࣵ◌̕b; à◌֮◌ࣵ◌̕b; a◌֮◌̀◌ࣵ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC FATHA WITH DOT ABOVE, LATIN SMALL LETTER B 0061 08F5 0315 0300 05AE 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062;0061 05AE 08F5 0300 0315 0062; # (a◌ࣵ◌̕◌̀◌֮b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; a◌֮◌ࣵ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC FATHA WITH DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08F6 0062;0061 302A 0316 08F6 059A 0062;0061 302A 0316 08F6 059A 0062;0061 302A 0316 08F6 059A 0062;0061 302A 0316 08F6 059A 0062; # (a◌֚◌̖◌〪◌ࣶb; a◌〪◌̖◌ࣶ◌֚b; a◌〪◌̖◌ࣶ◌֚b; a◌〪◌̖◌ࣶ◌֚b; a◌〪◌̖◌ࣶ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC KASRA WITH DOT BELOW, LATIN SMALL LETTER B -0061 08F6 059A 0316 302A 0062;0061 302A 08F6 0316 059A 0062;0061 302A 08F6 0316 059A 0062;0061 302A 08F6 0316 059A 0062;0061 302A 08F6 0316 059A 0062; # (a◌ࣶ◌֚◌̖◌〪b; a◌〪◌ࣶ◌̖◌֚b; a◌〪◌ࣶ◌̖◌֚b; a◌〪◌ࣶ◌̖◌֚b; a◌〪◌ࣶ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC KASRA WITH DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08F6 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062;0061 1DFA 0316 08F6 059A 0062; # (a◌֚◌̖◌᷺◌ࣶb; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; a◌᷺◌̖◌ࣶ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC KASRA WITH DOT BELOW, LATIN SMALL LETTER B +0061 08F6 059A 0316 1DFA 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062;0061 1DFA 08F6 0316 059A 0062; # (a◌ࣶ◌֚◌̖◌᷺b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; a◌᷺◌ࣶ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC KASRA WITH DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08F7 0062;00E0 05AE 08F7 0315 0062;0061 05AE 0300 08F7 0315 0062;00E0 05AE 08F7 0315 0062;0061 05AE 0300 08F7 0315 0062; # (a◌̕◌̀◌֮◌ࣷb; à◌֮◌ࣷ◌̕b; a◌֮◌̀◌ࣷ◌̕b; à◌֮◌ࣷ◌̕b; a◌֮◌̀◌ࣷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC LEFT ARROWHEAD ABOVE, LATIN SMALL LETTER B 0061 08F7 0315 0300 05AE 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062;0061 05AE 08F7 0300 0315 0062; # (a◌ࣷ◌̕◌̀◌֮b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; a◌֮◌ࣷ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC LEFT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08F8 0062;00E0 05AE 08F8 0315 0062;0061 05AE 0300 08F8 0315 0062;00E0 05AE 08F8 0315 0062;0061 05AE 0300 08F8 0315 0062; # (a◌̕◌̀◌֮◌ࣸb; à◌֮◌ࣸ◌̕b; a◌֮◌̀◌ࣸ◌̕b; à◌֮◌ࣸ◌̕b; a◌֮◌̀◌ࣸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B 0061 08F8 0315 0300 05AE 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062;0061 05AE 08F8 0300 0315 0062; # (a◌ࣸ◌̕◌̀◌֮b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; a◌֮◌ࣸ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 08F9 0062;0061 302A 0316 08F9 059A 0062;0061 302A 0316 08F9 059A 0062;0061 302A 0316 08F9 059A 0062;0061 302A 0316 08F9 059A 0062; # (a◌֚◌̖◌〪◌ࣹb; a◌〪◌̖◌ࣹ◌֚b; a◌〪◌̖◌ࣹ◌֚b; a◌〪◌̖◌ࣹ◌֚b; a◌〪◌̖◌ࣹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 08F9 059A 0316 302A 0062;0061 302A 08F9 0316 059A 0062;0061 302A 08F9 0316 059A 0062;0061 302A 08F9 0316 059A 0062;0061 302A 08F9 0316 059A 0062; # (a◌ࣹ◌֚◌̖◌〪b; a◌〪◌ࣹ◌̖◌֚b; a◌〪◌ࣹ◌̖◌֚b; a◌〪◌ࣹ◌̖◌֚b; a◌〪◌ࣹ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 08FA 0062;0061 302A 0316 08FA 059A 0062;0061 302A 0316 08FA 059A 0062;0061 302A 0316 08FA 059A 0062;0061 302A 0316 08FA 059A 0062; # (a◌֚◌̖◌〪◌ࣺb; a◌〪◌̖◌ࣺ◌֚b; a◌〪◌̖◌ࣺ◌֚b; a◌〪◌̖◌ࣺ◌֚b; a◌〪◌̖◌ࣺ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 08FA 059A 0316 302A 0062;0061 302A 08FA 0316 059A 0062;0061 302A 08FA 0316 059A 0062;0061 302A 08FA 0316 059A 0062;0061 302A 08FA 0316 059A 0062; # (a◌ࣺ◌֚◌̖◌〪b; a◌〪◌ࣺ◌̖◌֚b; a◌〪◌ࣺ◌̖◌֚b; a◌〪◌ࣺ◌̖◌֚b; a◌〪◌ࣺ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08F9 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062;0061 1DFA 0316 08F9 059A 0062; # (a◌֚◌̖◌᷺◌ࣹb; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; a◌᷺◌̖◌ࣹ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC LEFT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 08F9 059A 0316 1DFA 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062;0061 1DFA 08F9 0316 059A 0062; # (a◌ࣹ◌֚◌̖◌᷺b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; a◌᷺◌ࣹ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC LEFT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 08FA 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062;0061 1DFA 0316 08FA 059A 0062; # (a◌֚◌̖◌᷺◌ࣺb; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; a◌᷺◌̖◌ࣺ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC RIGHT ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 08FA 059A 0316 1DFA 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062;0061 1DFA 08FA 0316 059A 0062; # (a◌ࣺ◌֚◌̖◌᷺b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; a◌᷺◌ࣺ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC RIGHT ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 08FB 0062;00E0 05AE 08FB 0315 0062;0061 05AE 0300 08FB 0315 0062;00E0 05AE 08FB 0315 0062;0061 05AE 0300 08FB 0315 0062; # (a◌̕◌̀◌֮◌ࣻb; à◌֮◌ࣻ◌̕b; a◌֮◌̀◌ࣻ◌̕b; à◌֮◌ࣻ◌̕b; a◌֮◌̀◌ࣻ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE, LATIN SMALL LETTER B 0061 08FB 0315 0300 05AE 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062;0061 05AE 08FB 0300 0315 0062; # (a◌ࣻ◌̕◌̀◌֮b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; a◌֮◌ࣻ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08FC 0062;00E0 05AE 08FC 0315 0062;0061 05AE 0300 08FC 0315 0062;00E0 05AE 08FC 0315 0062;0061 05AE 0300 08FC 0315 0062; # (a◌̕◌̀◌֮◌ࣼb; à◌֮◌ࣼ◌̕b; a◌֮◌̀◌ࣼ◌̕b; à◌֮◌ࣼ◌̕b; a◌֮◌̀◌ࣼ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT, LATIN SMALL LETTER B @@ -17637,8 +17792,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 094D 05B0 094D 3099 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062;0061 3099 094D 094D 05B0 0062; # (a◌्◌ְ◌्◌゙b; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; a◌゙◌्◌्◌ְb; ) LATIN SMALL LETTER A, DEVANAGARI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 0951 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062;00E0 05AE 0951 0315 0062;0061 05AE 0300 0951 0315 0062; # (a◌̕◌̀◌֮◌॑b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; à◌֮◌॑◌̕b; a◌֮◌̀◌॑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI STRESS SIGN UDATTA, LATIN SMALL LETTER B 0061 0951 0315 0300 05AE 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062;0061 05AE 0951 0300 0315 0062; # (a◌॑◌̕◌̀◌֮b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; a◌֮◌॑◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN UDATTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0952 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062;0061 302A 0316 0952 059A 0062; # (a◌֚◌̖◌〪◌॒b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; a◌〪◌̖◌॒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, DEVANAGARI STRESS SIGN ANUDATTA, LATIN SMALL LETTER B -0061 0952 059A 0316 302A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062;0061 302A 0952 0316 059A 0062; # (a◌॒◌֚◌̖◌〪b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; a◌〪◌॒◌̖◌֚b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0952 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062;0061 1DFA 0316 0952 059A 0062; # (a◌֚◌̖◌᷺◌॒b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; a◌᷺◌̖◌॒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, DEVANAGARI STRESS SIGN ANUDATTA, LATIN SMALL LETTER B +0061 0952 059A 0316 1DFA 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062;0061 1DFA 0952 0316 059A 0062; # (a◌॒◌֚◌̖◌᷺b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; a◌᷺◌॒◌̖◌֚b; ) LATIN SMALL LETTER A, DEVANAGARI STRESS SIGN ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 0953 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062;00E0 05AE 0953 0315 0062;0061 05AE 0300 0953 0315 0062; # (a◌̕◌̀◌֮◌॓b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; à◌֮◌॓◌̕b; a◌֮◌̀◌॓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI GRAVE ACCENT, LATIN SMALL LETTER B 0061 0953 0315 0300 05AE 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062;0061 05AE 0953 0300 0315 0062; # (a◌॓◌̕◌̀◌֮b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; a◌֮◌॓◌̀◌̕b; ) LATIN SMALL LETTER A, DEVANAGARI GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0954 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062;00E0 05AE 0954 0315 0062;0061 05AE 0300 0954 0315 0062; # (a◌̕◌̀◌֮◌॔b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; à◌֮◌॔◌̕b; a◌֮◌̀◌॔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, DEVANAGARI ACUTE ACCENT, LATIN SMALL LETTER B @@ -17663,6 +17818,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0B4D 05B0 094D 3099 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062;0061 3099 0B4D 094D 05B0 0062; # (a◌୍◌ְ◌्◌゙b; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; a◌゙◌୍◌्◌ְb; ) LATIN SMALL LETTER A, ORIYA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 0BCD 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062;0061 3099 094D 0BCD 05B0 0062; # (a◌ְ◌्◌゙◌்b; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; a◌゙◌्◌்◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAMIL SIGN VIRAMA, LATIN SMALL LETTER B 0061 0BCD 05B0 094D 3099 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062;0061 3099 0BCD 094D 05B0 0062; # (a◌்◌ְ◌्◌゙b; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; a◌゙◌்◌्◌ְb; ) LATIN SMALL LETTER A, TAMIL SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 16FF0 0C3C 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062;0061 16FF0 093C 0C3C 3099 0062; # (a◌゙◌𖿰़◌఼b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; a𖿰◌़◌఼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, TELUGU SIGN NUKTA, LATIN SMALL LETTER B +0061 0C3C 3099 093C 16FF0 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062;0061 16FF0 0C3C 093C 3099 0062; # (a◌఼◌゙◌𖿰़b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; a𖿰◌఼◌़◌゙b; ) LATIN SMALL LETTER A, TELUGU SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B 0061 05B0 094D 3099 0C4D 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062;0061 3099 094D 0C4D 05B0 0062; # (a◌ְ◌्◌゙◌్b; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; a◌゙◌्◌్◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TELUGU SIGN VIRAMA, LATIN SMALL LETTER B 0061 0C4D 05B0 094D 3099 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062;0061 3099 0C4D 094D 05B0 0062; # (a◌్◌ְ◌्◌゙b; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; a◌゙◌్◌्◌ְb; ) LATIN SMALL LETTER A, TELUGU SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0C56 0C55 0711 0C55 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062;0061 0711 0C55 0C55 0C56 0062; # (a◌ౖ◌ౕ◌ܑ◌ౕb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; a◌ܑ◌ౕ◌ౕ◌ౖb; ) LATIN SMALL LETTER A, TELUGU AI LENGTH MARK, TELUGU LENGTH MARK, SYRIAC LETTER SUPERSCRIPT ALAPH, TELUGU LENGTH MARK, LATIN SMALL LETTER B @@ -17709,16 +17866,16 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0ECA 0F71 0EC8 0EB8 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062;0061 0EB8 0ECA 0EC8 0F71 0062; # (a◌໊◌ཱ◌່◌ຸb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; a◌ຸ◌໊◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI TI, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B 0061 0F71 0EC8 0EB8 0ECB 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062;0061 0EB8 0EC8 0ECB 0F71 0062; # (a◌ཱ◌່◌ຸ◌໋b; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; a◌ຸ◌່◌໋◌ཱb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LAO TONE MAI CATAWA, LATIN SMALL LETTER B 0061 0ECB 0F71 0EC8 0EB8 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062;0061 0EB8 0ECB 0EC8 0F71 0062; # (a◌໋◌ཱ◌່◌ຸb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; a◌ຸ◌໋◌່◌ཱb; ) LATIN SMALL LETTER A, LAO TONE MAI CATAWA, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LAO VOWEL SIGN U, LATIN SMALL LETTER B -0061 059A 0316 302A 0F18 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062;0061 302A 0316 0F18 059A 0062; # (a◌֚◌̖◌〪◌༘b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; a◌〪◌̖◌༘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, LATIN SMALL LETTER B -0061 0F18 059A 0316 302A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062;0061 302A 0F18 0316 059A 0062; # (a◌༘◌֚◌̖◌〪b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; a◌〪◌༘◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0F19 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062;0061 302A 0316 0F19 059A 0062; # (a◌֚◌̖◌〪◌༙b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; a◌〪◌̖◌༙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, LATIN SMALL LETTER B -0061 0F19 059A 0316 302A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062;0061 302A 0F19 0316 059A 0062; # (a◌༙◌֚◌̖◌〪b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; a◌〪◌༙◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0F35 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062;0061 302A 0316 0F35 059A 0062; # (a◌֚◌̖◌〪◌༵b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; a◌〪◌̖◌༵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN MARK NGAS BZUNG NYI ZLA, LATIN SMALL LETTER B -0061 0F35 059A 0316 302A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062;0061 302A 0F35 0316 059A 0062; # (a◌༵◌֚◌̖◌〪b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; a◌〪◌༵◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG NYI ZLA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 0F37 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062;0061 302A 0316 0F37 059A 0062; # (a◌֚◌̖◌〪◌༷b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; a◌〪◌̖◌༷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN MARK NGAS BZUNG SGOR RTAGS, LATIN SMALL LETTER B -0061 0F37 059A 0316 302A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062;0061 302A 0F37 0316 059A 0062; # (a◌༷◌֚◌̖◌〪b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; a◌〪◌༷◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG SGOR RTAGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 302A 031B 1DCE 0F39 0062;0061 1DCE 031B 0F39 302A 0062;0061 1DCE 031B 0F39 302A 0062;0061 1DCE 031B 0F39 302A 0062;0061 1DCE 031B 0F39 302A 0062; # (a◌〪◌̛◌᷎◌༹b; a◌᷎◌̛◌༹◌〪b; a◌᷎◌̛◌༹◌〪b; a◌᷎◌̛◌༹◌〪b; a◌᷎◌̛◌༹◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, TIBETAN MARK TSA -PHRU, LATIN SMALL LETTER B -0061 0F39 302A 031B 1DCE 0062;0061 1DCE 0F39 031B 302A 0062;0061 1DCE 0F39 031B 302A 0062;0061 1DCE 0F39 031B 302A 0062;0061 1DCE 0F39 031B 302A 0062; # (a◌༹◌〪◌̛◌᷎b; a◌᷎◌༹◌̛◌〪b; a◌᷎◌༹◌̛◌〪b; a◌᷎◌༹◌̛◌〪b; a◌᷎◌༹◌̛◌〪b; ) LATIN SMALL LETTER A, TIBETAN MARK TSA -PHRU, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F18 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062;0061 1DFA 0316 0F18 059A 0062; # (a◌֚◌̖◌᷺◌༘b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; a◌᷺◌̖◌༘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, LATIN SMALL LETTER B +0061 0F18 059A 0316 1DFA 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062;0061 1DFA 0F18 0316 059A 0062; # (a◌༘◌֚◌̖◌᷺b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; a◌᷺◌༘◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN -KHYUD PA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F19 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062;0061 1DFA 0316 0F19 059A 0062; # (a◌֚◌̖◌᷺◌༙b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; a◌᷺◌̖◌༙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, LATIN SMALL LETTER B +0061 0F19 059A 0316 1DFA 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062;0061 1DFA 0F19 0316 059A 0062; # (a◌༙◌֚◌̖◌᷺b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; a◌᷺◌༙◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F35 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062;0061 1DFA 0316 0F35 059A 0062; # (a◌֚◌̖◌᷺◌༵b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; a◌᷺◌̖◌༵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN MARK NGAS BZUNG NYI ZLA, LATIN SMALL LETTER B +0061 0F35 059A 0316 1DFA 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062;0061 1DFA 0F35 0316 059A 0062; # (a◌༵◌֚◌̖◌᷺b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; a◌᷺◌༵◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG NYI ZLA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0F37 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062;0061 1DFA 0316 0F37 059A 0062; # (a◌֚◌̖◌᷺◌༷b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; a◌᷺◌̖◌༷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN MARK NGAS BZUNG SGOR RTAGS, LATIN SMALL LETTER B +0061 0F37 059A 0316 1DFA 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062;0061 1DFA 0F37 0316 059A 0062; # (a◌༷◌֚◌̖◌᷺b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; a◌᷺◌༷◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN MARK NGAS BZUNG SGOR RTAGS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 0F39 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062;0061 1DCE 031B 0F39 1DFA 0062; # (a◌᷺◌̛◌᷎◌༹b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; a◌᷎◌̛◌༹◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, TIBETAN MARK TSA -PHRU, LATIN SMALL LETTER B +0061 0F39 1DFA 031B 1DCE 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062;0061 1DCE 0F39 031B 1DFA 0062; # (a◌༹◌᷺◌̛◌᷎b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; a◌᷎◌༹◌̛◌᷺b; ) LATIN SMALL LETTER A, TIBETAN MARK TSA -PHRU, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B 0061 0F72 0F71 0EC8 0F71 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ི◌ཱ◌່◌ཱb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, TIBETAN VOWEL SIGN AA, LATIN SMALL LETTER B 0061 0F71 0F72 0F71 0EC8 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062;0061 0EC8 0F71 0F71 0F72 0062; # (a◌ཱ◌ི◌ཱ◌່b; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; a◌່◌ཱ◌ཱ◌ིb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, LAO TONE MAI EK, LATIN SMALL LETTER B 0061 0F74 0F72 0F71 0F72 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062;0061 0F71 0F72 0F72 0F74 0062; # (a◌ུ◌ི◌ཱ◌ིb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; a◌ཱ◌ི◌ི◌ུb; ) LATIN SMALL LETTER A, TIBETAN VOWEL SIGN U, TIBETAN VOWEL SIGN I, TIBETAN VOWEL SIGN AA, TIBETAN VOWEL SIGN I, LATIN SMALL LETTER B @@ -17745,16 +17902,16 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0F86 0315 0300 05AE 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062;0061 05AE 0F86 0300 0315 0062; # (a◌྆◌̕◌̀◌֮b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; a◌֮◌྆◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN LCI RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 0F87 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062;00E0 05AE 0F87 0315 0062;0061 05AE 0300 0F87 0315 0062; # (a◌̕◌̀◌֮◌྇b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; à◌֮◌྇◌̕b; a◌֮◌̀◌྇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TIBETAN SIGN YANG RTAGS, LATIN SMALL LETTER B 0061 0F87 0315 0300 05AE 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062;0061 05AE 0F87 0300 0315 0062; # (a◌྇◌̕◌̀◌֮b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; a◌֮◌྇◌̀◌̕b; ) LATIN SMALL LETTER A, TIBETAN SIGN YANG RTAGS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 0FC6 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062;0061 302A 0316 0FC6 059A 0062; # (a◌֚◌̖◌〪◌࿆b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; a◌〪◌̖◌࿆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TIBETAN SYMBOL PADMA GDAN, LATIN SMALL LETTER B -0061 0FC6 059A 0316 302A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062;0061 302A 0FC6 0316 059A 0062; # (a◌࿆◌֚◌̖◌〪b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; a◌〪◌࿆◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN SYMBOL PADMA GDAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 0FC6 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062;0061 1DFA 0316 0FC6 059A 0062; # (a◌֚◌̖◌᷺◌࿆b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; a◌᷺◌̖◌࿆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TIBETAN SYMBOL PADMA GDAN, LATIN SMALL LETTER B +0061 0FC6 059A 0316 1DFA 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062;0061 1DFA 0FC6 0316 059A 0062; # (a◌࿆◌֚◌̖◌᷺b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; a◌᷺◌࿆◌̖◌֚b; ) LATIN SMALL LETTER A, TIBETAN SYMBOL PADMA GDAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 3099 093C 16FF0 1037 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062;0061 16FF0 093C 1037 3099 0062; # (a◌゙◌𖿰़◌့b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; a𖿰◌़◌့◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, MYANMAR SIGN DOT BELOW, LATIN SMALL LETTER B 0061 1037 3099 093C 16FF0 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062;0061 16FF0 1037 093C 3099 0062; # (a◌့◌゙◌𖿰़b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; a𖿰◌့◌़◌゙b; ) LATIN SMALL LETTER A, MYANMAR SIGN DOT BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B 0061 05B0 094D 3099 1039 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062;0061 3099 094D 1039 05B0 0062; # (a◌ְ◌्◌゙◌္b; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; a◌゙◌्◌္◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MYANMAR SIGN VIRAMA, LATIN SMALL LETTER B 0061 1039 05B0 094D 3099 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062;0061 3099 1039 094D 05B0 0062; # (a◌္◌ְ◌्◌゙b; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; a◌゙◌္◌्◌ְb; ) LATIN SMALL LETTER A, MYANMAR SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 103A 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062;0061 3099 094D 103A 05B0 0062; # (a◌ְ◌्◌゙◌်b; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; a◌゙◌्◌်◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MYANMAR SIGN ASAT, LATIN SMALL LETTER B 0061 103A 05B0 094D 3099 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062;0061 3099 103A 094D 05B0 0062; # (a◌်◌ְ◌्◌゙b; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; a◌゙◌်◌्◌ְb; ) LATIN SMALL LETTER A, MYANMAR SIGN ASAT, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 108D 0062;0061 302A 0316 108D 059A 0062;0061 302A 0316 108D 059A 0062;0061 302A 0316 108D 059A 0062;0061 302A 0316 108D 059A 0062; # (a◌֚◌̖◌〪◌ႍb; a◌〪◌̖◌ႍ◌֚b; a◌〪◌̖◌ႍ◌֚b; a◌〪◌̖◌ႍ◌֚b; a◌〪◌̖◌ႍ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, LATIN SMALL LETTER B -0061 108D 059A 0316 302A 0062;0061 302A 108D 0316 059A 0062;0061 302A 108D 0316 059A 0062;0061 302A 108D 0316 059A 0062;0061 302A 108D 0316 059A 0062; # (a◌ႍ◌֚◌̖◌〪b; a◌〪◌ႍ◌̖◌֚b; a◌〪◌ႍ◌̖◌֚b; a◌〪◌ႍ◌̖◌֚b; a◌〪◌ႍ◌̖◌֚b; ) LATIN SMALL LETTER A, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 108D 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062;0061 1DFA 0316 108D 059A 0062; # (a◌֚◌̖◌᷺◌ႍb; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; a◌᷺◌̖◌ႍ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, LATIN SMALL LETTER B +0061 108D 059A 0316 1DFA 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062;0061 1DFA 108D 0316 059A 0062; # (a◌ႍ◌֚◌̖◌᷺b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; a◌᷺◌ႍ◌̖◌֚b; ) LATIN SMALL LETTER A, MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 135D 0062;00E0 05AE 135D 0315 0062;0061 05AE 0300 135D 0315 0062;00E0 05AE 135D 0315 0062;0061 05AE 0300 135D 0315 0062; # (a◌̕◌̀◌֮◌፝b; à◌֮◌፝◌̕b; a◌֮◌̀◌፝◌̕b; à◌֮◌፝◌̕b; a◌֮◌̀◌፝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK, LATIN SMALL LETTER B 0061 135D 0315 0300 05AE 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062;0061 05AE 135D 0300 0315 0062; # (a◌፝◌̕◌̀◌֮b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; a◌֮◌፝◌̀◌̕b; ) LATIN SMALL LETTER A, ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 135E 0062;00E0 05AE 135E 0315 0062;0061 05AE 0300 135E 0315 0062;00E0 05AE 135E 0315 0062;0061 05AE 0300 135E 0315 0062; # (a◌̕◌̀◌֮◌፞b; à◌֮◌፞◌̕b; a◌֮◌̀◌፞◌̕b; à◌֮◌፞◌̕b; a◌֮◌̀◌፞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ETHIOPIC COMBINING VOWEL LENGTH MARK, LATIN SMALL LETTER B @@ -17763,8 +17920,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 135F 0315 0300 05AE 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062;0061 05AE 135F 0300 0315 0062; # (a◌፟◌̕◌̀◌֮b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; a◌֮◌፟◌̀◌̕b; ) LATIN SMALL LETTER A, ETHIOPIC COMBINING GEMINATION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 05B0 094D 3099 1714 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062;0061 3099 094D 1714 05B0 0062; # (a◌ְ◌्◌゙◌᜔b; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; a◌゙◌्◌᜔◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAGALOG SIGN VIRAMA, LATIN SMALL LETTER B 0061 1714 05B0 094D 3099 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062;0061 3099 1714 094D 05B0 0062; # (a◌᜔◌ְ◌्◌゙b; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; a◌゙◌᜔◌्◌ְb; ) LATIN SMALL LETTER A, TAGALOG SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B -0061 05B0 094D 3099 1734 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062; # (a◌ְ◌्◌゙◌᜴b; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; a◌゙◌्◌᜴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, HANUNOO SIGN PAMUDPOD, LATIN SMALL LETTER B -0061 1734 05B0 094D 3099 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062; # (a◌᜴◌ְ◌्◌゙b; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; a◌゙◌᜴◌्◌ְb; ) LATIN SMALL LETTER A, HANUNOO SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1715 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062;0061 3099 094D 1715 05B0 0062; # (a◌ְ◌्◌゙᜕b; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; a◌゙◌्᜕◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAGALOG SIGN PAMUDPOD, LATIN SMALL LETTER B +0061 1715 05B0 094D 3099 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062;0061 3099 1715 094D 05B0 0062; # (a᜕◌ְ◌्◌゙b; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; a◌゙᜕◌्◌ְb; ) LATIN SMALL LETTER A, TAGALOG SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 1734 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062;0061 3099 094D 1734 05B0 0062; # (a◌ְ◌्◌゙᜴b; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; a◌゙◌्᜴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, HANUNOO SIGN PAMUDPOD, LATIN SMALL LETTER B +0061 1734 05B0 094D 3099 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062;0061 3099 1734 094D 05B0 0062; # (a᜴◌ְ◌्◌゙b; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; a◌゙᜴◌्◌ְb; ) LATIN SMALL LETTER A, HANUNOO SIGN PAMUDPOD, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 17D2 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062;0061 3099 094D 17D2 05B0 0062; # (a◌ְ◌्◌゙◌្b; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; a◌゙◌्◌្◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHMER SIGN COENG, LATIN SMALL LETTER B 0061 17D2 05B0 094D 3099 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062;0061 3099 17D2 094D 05B0 0062; # (a◌្◌ְ◌्◌゙b; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; a◌゙◌្◌्◌ְb; ) LATIN SMALL LETTER A, KHMER SIGN COENG, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 17DD 0062;00E0 05AE 17DD 0315 0062;0061 05AE 0300 17DD 0315 0062;00E0 05AE 17DD 0315 0062;0061 05AE 0300 17DD 0315 0062; # (a◌̕◌̀◌֮◌៝b; à◌֮◌៝◌̕b; a◌֮◌̀◌៝◌̕b; à◌֮◌៝◌̕b; a◌֮◌̀◌៝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHMER SIGN ATTHACAN, LATIN SMALL LETTER B @@ -17775,12 +17934,12 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1939 302E 059A 0316 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062;0061 0316 1939 059A 302E 0062; # (a◌᤹〮◌֚◌̖b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; a◌̖◌᤹◌֚〮b; ) LATIN SMALL LETTER A, LIMBU SIGN MUKPHRENG, HANGUL SINGLE DOT TONE MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, LATIN SMALL LETTER B 0061 0315 0300 05AE 193A 0062;00E0 05AE 193A 0315 0062;0061 05AE 0300 193A 0315 0062;00E0 05AE 193A 0315 0062;0061 05AE 0300 193A 0315 0062; # (a◌̕◌̀◌֮◌᤺b; à◌֮◌᤺◌̕b; a◌֮◌̀◌᤺◌̕b; à◌֮◌᤺◌̕b; a◌֮◌̀◌᤺◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LIMBU SIGN KEMPHRENG, LATIN SMALL LETTER B 0061 193A 0315 0300 05AE 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062;0061 05AE 193A 0300 0315 0062; # (a◌᤺◌̕◌̀◌֮b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; a◌֮◌᤺◌̀◌̕b; ) LATIN SMALL LETTER A, LIMBU SIGN KEMPHRENG, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 193B 0062;0061 302A 0316 193B 059A 0062;0061 302A 0316 193B 059A 0062;0061 302A 0316 193B 059A 0062;0061 302A 0316 193B 059A 0062; # (a◌֚◌̖◌〪◌᤻b; a◌〪◌̖◌᤻◌֚b; a◌〪◌̖◌᤻◌֚b; a◌〪◌̖◌᤻◌֚b; a◌〪◌̖◌᤻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LIMBU SIGN SA-I, LATIN SMALL LETTER B -0061 193B 059A 0316 302A 0062;0061 302A 193B 0316 059A 0062;0061 302A 193B 0316 059A 0062;0061 302A 193B 0316 059A 0062;0061 302A 193B 0316 059A 0062; # (a◌᤻◌֚◌̖◌〪b; a◌〪◌᤻◌̖◌֚b; a◌〪◌᤻◌̖◌֚b; a◌〪◌᤻◌̖◌֚b; a◌〪◌᤻◌̖◌֚b; ) LATIN SMALL LETTER A, LIMBU SIGN SA-I, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 193B 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062;0061 1DFA 0316 193B 059A 0062; # (a◌֚◌̖◌᷺◌᤻b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; a◌᷺◌̖◌᤻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LIMBU SIGN SA-I, LATIN SMALL LETTER B +0061 193B 059A 0316 1DFA 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062;0061 1DFA 193B 0316 059A 0062; # (a◌᤻◌֚◌̖◌᷺b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; a◌᷺◌᤻◌̖◌֚b; ) LATIN SMALL LETTER A, LIMBU SIGN SA-I, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1A17 0062;00E0 05AE 1A17 0315 0062;0061 05AE 0300 1A17 0315 0062;00E0 05AE 1A17 0315 0062;0061 05AE 0300 1A17 0315 0062; # (a◌̕◌̀◌֮◌ᨗb; à◌֮◌ᨗ◌̕b; a◌֮◌̀◌ᨗ◌̕b; à◌֮◌ᨗ◌̕b; a◌֮◌̀◌ᨗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BUGINESE VOWEL SIGN I, LATIN SMALL LETTER B 0061 1A17 0315 0300 05AE 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062;0061 05AE 1A17 0300 0315 0062; # (a◌ᨗ◌̕◌̀◌֮b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; a◌֮◌ᨗ◌̀◌̕b; ) LATIN SMALL LETTER A, BUGINESE VOWEL SIGN I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1A18 0062;0061 302A 0316 1A18 059A 0062;0061 302A 0316 1A18 059A 0062;0061 302A 0316 1A18 059A 0062;0061 302A 0316 1A18 059A 0062; # (a◌֚◌̖◌〪◌ᨘb; a◌〪◌̖◌ᨘ◌֚b; a◌〪◌̖◌ᨘ◌֚b; a◌〪◌̖◌ᨘ◌֚b; a◌〪◌̖◌ᨘ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, BUGINESE VOWEL SIGN U, LATIN SMALL LETTER B -0061 1A18 059A 0316 302A 0062;0061 302A 1A18 0316 059A 0062;0061 302A 1A18 0316 059A 0062;0061 302A 1A18 0316 059A 0062;0061 302A 1A18 0316 059A 0062; # (a◌ᨘ◌֚◌̖◌〪b; a◌〪◌ᨘ◌̖◌֚b; a◌〪◌ᨘ◌̖◌֚b; a◌〪◌ᨘ◌̖◌֚b; a◌〪◌ᨘ◌̖◌֚b; ) LATIN SMALL LETTER A, BUGINESE VOWEL SIGN U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1A18 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062;0061 1DFA 0316 1A18 059A 0062; # (a◌֚◌̖◌᷺◌ᨘb; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; a◌᷺◌̖◌ᨘ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, BUGINESE VOWEL SIGN U, LATIN SMALL LETTER B +0061 1A18 059A 0316 1DFA 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062;0061 1DFA 1A18 0316 059A 0062; # (a◌ᨘ◌֚◌̖◌᷺b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; a◌᷺◌ᨘ◌̖◌֚b; ) LATIN SMALL LETTER A, BUGINESE VOWEL SIGN U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 05B0 094D 3099 1A60 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062;0061 3099 094D 1A60 05B0 0062; # (a◌ְ◌्◌゙◌᩠b; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; a◌゙◌्◌᩠◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TAI THAM SIGN SAKOT, LATIN SMALL LETTER B 0061 1A60 05B0 094D 3099 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062;0061 3099 1A60 094D 05B0 0062; # (a◌᩠◌ְ◌्◌゙b; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; a◌゙◌᩠◌्◌ְb; ) LATIN SMALL LETTER A, TAI THAM SIGN SAKOT, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 1A75 0062;00E0 05AE 1A75 0315 0062;0061 05AE 0300 1A75 0315 0062;00E0 05AE 1A75 0315 0062;0061 05AE 0300 1A75 0315 0062; # (a◌̕◌̀◌֮◌᩵b; à◌֮◌᩵◌̕b; a◌֮◌̀◌᩵◌̕b; à◌֮◌᩵◌̕b; a◌֮◌̀◌᩵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN TONE-1, LATIN SMALL LETTER B @@ -17799,8 +17958,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1A7B 0315 0300 05AE 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062;0061 05AE 1A7B 0300 0315 0062; # (a◌᩻◌̕◌̀◌֮b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; a◌֮◌᩻◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN MAI SAM, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1A7C 0062;00E0 05AE 1A7C 0315 0062;0061 05AE 0300 1A7C 0315 0062;00E0 05AE 1A7C 0315 0062;0061 05AE 0300 1A7C 0315 0062; # (a◌̕◌̀◌֮◌᩼b; à◌֮◌᩼◌̕b; a◌֮◌̀◌᩼◌̕b; à◌֮◌᩼◌̕b; a◌֮◌̀◌᩼◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI THAM SIGN KHUEN-LUE KARAN, LATIN SMALL LETTER B 0061 1A7C 0315 0300 05AE 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062;0061 05AE 1A7C 0300 0315 0062; # (a◌᩼◌̕◌̀◌֮b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; a◌֮◌᩼◌̀◌̕b; ) LATIN SMALL LETTER A, TAI THAM SIGN KHUEN-LUE KARAN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1A7F 0062;0061 302A 0316 1A7F 059A 0062;0061 302A 0316 1A7F 059A 0062;0061 302A 0316 1A7F 059A 0062;0061 302A 0316 1A7F 059A 0062; # (a◌֚◌̖◌〪◌᩿b; a◌〪◌̖◌᩿◌֚b; a◌〪◌̖◌᩿◌֚b; a◌〪◌̖◌᩿◌֚b; a◌〪◌̖◌᩿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TAI THAM COMBINING CRYPTOGRAMMIC DOT, LATIN SMALL LETTER B -0061 1A7F 059A 0316 302A 0062;0061 302A 1A7F 0316 059A 0062;0061 302A 1A7F 0316 059A 0062;0061 302A 1A7F 0316 059A 0062;0061 302A 1A7F 0316 059A 0062; # (a◌᩿◌֚◌̖◌〪b; a◌〪◌᩿◌̖◌֚b; a◌〪◌᩿◌̖◌֚b; a◌〪◌᩿◌̖◌֚b; a◌〪◌᩿◌̖◌֚b; ) LATIN SMALL LETTER A, TAI THAM COMBINING CRYPTOGRAMMIC DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1A7F 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062;0061 1DFA 0316 1A7F 059A 0062; # (a◌֚◌̖◌᷺◌᩿b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; a◌᷺◌̖◌᩿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TAI THAM COMBINING CRYPTOGRAMMIC DOT, LATIN SMALL LETTER B +0061 1A7F 059A 0316 1DFA 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062;0061 1DFA 1A7F 0316 059A 0062; # (a◌᩿◌֚◌̖◌᷺b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; a◌᷺◌᩿◌̖◌֚b; ) LATIN SMALL LETTER A, TAI THAM COMBINING CRYPTOGRAMMIC DOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1AB0 0062;00E0 05AE 1AB0 0315 0062;0061 05AE 0300 1AB0 0315 0062;00E0 05AE 1AB0 0315 0062;0061 05AE 0300 1AB0 0315 0062; # (a◌̕◌̀◌֮◌᪰b; à◌֮◌᪰◌̕b; a◌֮◌̀◌᪰◌̕b; à◌֮◌᪰◌̕b; a◌֮◌̀◌᪰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLED CIRCUMFLEX ACCENT, LATIN SMALL LETTER B 0061 1AB0 0315 0300 05AE 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062;0061 05AE 1AB0 0300 0315 0062; # (a◌᪰◌̕◌̀◌֮b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; a◌֮◌᪰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLED CIRCUMFLEX ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1AB1 0062;00E0 05AE 1AB1 0315 0062;0061 05AE 0300 1AB1 0315 0062;00E0 05AE 1AB1 0315 0062;0061 05AE 0300 1AB1 0315 0062; # (a◌̕◌̀◌֮◌᪱b; à◌֮◌᪱◌̕b; a◌֮◌̀◌᪱◌̕b; à◌֮◌᪱◌̕b; a◌֮◌̀◌᪱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DIAERESIS-RING, LATIN SMALL LETTER B @@ -17811,36 +17970,64 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1AB3 0315 0300 05AE 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062;0061 05AE 1AB3 0300 0315 0062; # (a◌᪳◌̕◌̀◌֮b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; a◌֮◌᪳◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOWNWARDS ARROW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1AB4 0062;00E0 05AE 1AB4 0315 0062;0061 05AE 0300 1AB4 0315 0062;00E0 05AE 1AB4 0315 0062;0061 05AE 0300 1AB4 0315 0062; # (a◌̕◌̀◌֮◌᪴b; à◌֮◌᪴◌̕b; a◌֮◌̀◌᪴◌̕b; à◌֮◌᪴◌̕b; a◌֮◌̀◌᪴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TRIPLE DOT, LATIN SMALL LETTER B 0061 1AB4 0315 0300 05AE 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062;0061 05AE 1AB4 0300 0315 0062; # (a◌᪴◌̕◌̀◌֮b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; a◌֮◌᪴◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TRIPLE DOT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1AB5 0062;0061 302A 0316 1AB5 059A 0062;0061 302A 0316 1AB5 059A 0062;0061 302A 0316 1AB5 059A 0062;0061 302A 0316 1AB5 059A 0062; # (a◌֚◌̖◌〪◌᪵b; a◌〪◌̖◌᪵◌֚b; a◌〪◌̖◌᪵◌֚b; a◌〪◌̖◌᪵◌֚b; a◌〪◌̖◌᪵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING X-X BELOW, LATIN SMALL LETTER B -0061 1AB5 059A 0316 302A 0062;0061 302A 1AB5 0316 059A 0062;0061 302A 1AB5 0316 059A 0062;0061 302A 1AB5 0316 059A 0062;0061 302A 1AB5 0316 059A 0062; # (a◌᪵◌֚◌̖◌〪b; a◌〪◌᪵◌̖◌֚b; a◌〪◌᪵◌̖◌֚b; a◌〪◌᪵◌̖◌֚b; a◌〪◌᪵◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X-X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1AB6 0062;0061 302A 0316 1AB6 059A 0062;0061 302A 0316 1AB6 059A 0062;0061 302A 0316 1AB6 059A 0062;0061 302A 0316 1AB6 059A 0062; # (a◌֚◌̖◌〪◌᪶b; a◌〪◌̖◌᪶◌֚b; a◌〪◌̖◌᪶◌֚b; a◌〪◌̖◌᪶◌֚b; a◌〪◌̖◌᪶◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING WIGGLY LINE BELOW, LATIN SMALL LETTER B -0061 1AB6 059A 0316 302A 0062;0061 302A 1AB6 0316 059A 0062;0061 302A 1AB6 0316 059A 0062;0061 302A 1AB6 0316 059A 0062;0061 302A 1AB6 0316 059A 0062; # (a◌᪶◌֚◌̖◌〪b; a◌〪◌᪶◌̖◌֚b; a◌〪◌᪶◌̖◌֚b; a◌〪◌᪶◌̖◌֚b; a◌〪◌᪶◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIGGLY LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1AB7 0062;0061 302A 0316 1AB7 059A 0062;0061 302A 0316 1AB7 059A 0062;0061 302A 0316 1AB7 059A 0062;0061 302A 0316 1AB7 059A 0062; # (a◌֚◌̖◌〪◌᪷b; a◌〪◌̖◌᪷◌֚b; a◌〪◌̖◌᪷◌֚b; a◌〪◌̖◌᪷◌֚b; a◌〪◌̖◌᪷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING OPEN MARK BELOW, LATIN SMALL LETTER B -0061 1AB7 059A 0316 302A 0062;0061 302A 1AB7 0316 059A 0062;0061 302A 1AB7 0316 059A 0062;0061 302A 1AB7 0316 059A 0062;0061 302A 1AB7 0316 059A 0062; # (a◌᪷◌֚◌̖◌〪b; a◌〪◌᪷◌̖◌֚b; a◌〪◌᪷◌̖◌֚b; a◌〪◌᪷◌̖◌֚b; a◌〪◌᪷◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1AB8 0062;0061 302A 0316 1AB8 059A 0062;0061 302A 0316 1AB8 059A 0062;0061 302A 0316 1AB8 059A 0062;0061 302A 0316 1AB8 059A 0062; # (a◌֚◌̖◌〪◌᪸b; a◌〪◌̖◌᪸◌֚b; a◌〪◌̖◌᪸◌֚b; a◌〪◌̖◌᪸◌֚b; a◌〪◌̖◌᪸◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING DOUBLE OPEN MARK BELOW, LATIN SMALL LETTER B -0061 1AB8 059A 0316 302A 0062;0061 302A 1AB8 0316 059A 0062;0061 302A 1AB8 0316 059A 0062;0061 302A 1AB8 0316 059A 0062;0061 302A 1AB8 0316 059A 0062; # (a◌᪸◌֚◌̖◌〪b; a◌〪◌᪸◌̖◌֚b; a◌〪◌᪸◌̖◌֚b; a◌〪◌᪸◌̖◌֚b; a◌〪◌᪸◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1AB9 0062;0061 302A 0316 1AB9 059A 0062;0061 302A 0316 1AB9 059A 0062;0061 302A 0316 1AB9 059A 0062;0061 302A 0316 1AB9 059A 0062; # (a◌֚◌̖◌〪◌᪹b; a◌〪◌̖◌᪹◌֚b; a◌〪◌̖◌᪹◌֚b; a◌〪◌̖◌᪹◌֚b; a◌〪◌̖◌᪹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LIGHT CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B -0061 1AB9 059A 0316 302A 0062;0061 302A 1AB9 0316 059A 0062;0061 302A 1AB9 0316 059A 0062;0061 302A 1AB9 0316 059A 0062;0061 302A 1AB9 0316 059A 0062; # (a◌᪹◌֚◌̖◌〪b; a◌〪◌᪹◌̖◌֚b; a◌〪◌᪹◌̖◌֚b; a◌〪◌᪹◌̖◌֚b; a◌〪◌᪹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGHT CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1ABA 0062;0061 302A 0316 1ABA 059A 0062;0061 302A 0316 1ABA 059A 0062;0061 302A 0316 1ABA 059A 0062;0061 302A 0316 1ABA 059A 0062; # (a◌֚◌̖◌〪◌᪺b; a◌〪◌̖◌᪺◌֚b; a◌〪◌̖◌᪺◌֚b; a◌〪◌̖◌᪺◌֚b; a◌〪◌̖◌᪺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING STRONG CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B -0061 1ABA 059A 0316 302A 0062;0061 302A 1ABA 0316 059A 0062;0061 302A 1ABA 0316 059A 0062;0061 302A 1ABA 0316 059A 0062;0061 302A 1ABA 0316 059A 0062; # (a◌᪺◌֚◌̖◌〪b; a◌〪◌᪺◌̖◌֚b; a◌〪◌᪺◌̖◌֚b; a◌〪◌᪺◌̖◌֚b; a◌〪◌᪺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING STRONG CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB5 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062;0061 1DFA 0316 1AB5 059A 0062; # (a◌֚◌̖◌᷺◌᪵b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; a◌᷺◌̖◌᪵◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING X-X BELOW, LATIN SMALL LETTER B +0061 1AB5 059A 0316 1DFA 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062;0061 1DFA 1AB5 0316 059A 0062; # (a◌᪵◌֚◌̖◌᷺b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; a◌᷺◌᪵◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING X-X BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB6 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062;0061 1DFA 0316 1AB6 059A 0062; # (a◌֚◌̖◌᷺◌᪶b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; a◌᷺◌̖◌᪶◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING WIGGLY LINE BELOW, LATIN SMALL LETTER B +0061 1AB6 059A 0316 1DFA 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062;0061 1DFA 1AB6 0316 059A 0062; # (a◌᪶◌֚◌̖◌᷺b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; a◌᷺◌᪶◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIGGLY LINE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB7 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062;0061 1DFA 0316 1AB7 059A 0062; # (a◌֚◌̖◌᷺◌᪷b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; a◌᷺◌̖◌᪷◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING OPEN MARK BELOW, LATIN SMALL LETTER B +0061 1AB7 059A 0316 1DFA 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062;0061 1DFA 1AB7 0316 059A 0062; # (a◌᪷◌֚◌̖◌᷺b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; a◌᷺◌᪷◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB8 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062;0061 1DFA 0316 1AB8 059A 0062; # (a◌֚◌̖◌᷺◌᪸b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; a◌᷺◌̖◌᪸◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE OPEN MARK BELOW, LATIN SMALL LETTER B +0061 1AB8 059A 0316 1DFA 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062;0061 1DFA 1AB8 0316 059A 0062; # (a◌᪸◌֚◌̖◌᷺b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; a◌᷺◌᪸◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE OPEN MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AB9 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062;0061 1DFA 0316 1AB9 059A 0062; # (a◌֚◌̖◌᷺◌᪹b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; a◌᷺◌̖◌᪹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGHT CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B +0061 1AB9 059A 0316 1DFA 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062;0061 1DFA 1AB9 0316 059A 0062; # (a◌᪹◌֚◌̖◌᷺b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; a◌᷺◌᪹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGHT CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABA 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062;0061 1DFA 0316 1ABA 059A 0062; # (a◌֚◌̖◌᷺◌᪺b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; a◌᷺◌̖◌᪺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING STRONG CENTRALIZATION STROKE BELOW, LATIN SMALL LETTER B +0061 1ABA 059A 0316 1DFA 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062;0061 1DFA 1ABA 0316 059A 0062; # (a◌᪺◌֚◌̖◌᷺b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; a◌᷺◌᪺◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING STRONG CENTRALIZATION STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1ABB 0062;00E0 05AE 1ABB 0315 0062;0061 05AE 0300 1ABB 0315 0062;00E0 05AE 1ABB 0315 0062;0061 05AE 0300 1ABB 0315 0062; # (a◌̕◌̀◌֮◌᪻b; à◌֮◌᪻◌̕b; a◌֮◌̀◌᪻◌̕b; à◌֮◌᪻◌̕b; a◌֮◌̀◌᪻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING PARENTHESES ABOVE, LATIN SMALL LETTER B 0061 1ABB 0315 0300 05AE 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062;0061 05AE 1ABB 0300 0315 0062; # (a◌᪻◌̕◌̀◌֮b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; a◌֮◌᪻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING PARENTHESES ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1ABC 0062;00E0 05AE 1ABC 0315 0062;0061 05AE 0300 1ABC 0315 0062;00E0 05AE 1ABC 0315 0062;0061 05AE 0300 1ABC 0315 0062; # (a◌̕◌̀◌֮◌᪼b; à◌֮◌᪼◌̕b; a◌֮◌̀◌᪼◌̕b; à◌֮◌᪼◌̕b; a◌֮◌̀◌᪼◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE PARENTHESES ABOVE, LATIN SMALL LETTER B 0061 1ABC 0315 0300 05AE 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062;0061 05AE 1ABC 0300 0315 0062; # (a◌᪼◌̕◌̀◌֮b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; a◌֮◌᪼◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PARENTHESES ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1ABD 0062;0061 302A 0316 1ABD 059A 0062;0061 302A 0316 1ABD 059A 0062;0061 302A 0316 1ABD 059A 0062;0061 302A 0316 1ABD 059A 0062; # (a◌֚◌̖◌〪◌᪽b; a◌〪◌̖◌᪽◌֚b; a◌〪◌̖◌᪽◌֚b; a◌〪◌̖◌᪽◌֚b; a◌〪◌̖◌᪽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING PARENTHESES BELOW, LATIN SMALL LETTER B -0061 1ABD 059A 0316 302A 0062;0061 302A 1ABD 0316 059A 0062;0061 302A 1ABD 0316 059A 0062;0061 302A 1ABD 0316 059A 0062;0061 302A 1ABD 0316 059A 0062; # (a◌᪽◌֚◌̖◌〪b; a◌〪◌᪽◌̖◌֚b; a◌〪◌᪽◌̖◌֚b; a◌〪◌᪽◌̖◌֚b; a◌〪◌᪽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PARENTHESES BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1ABF 0062;0061 302A 0316 1ABF 059A 0062;0061 302A 0316 1ABF 059A 0062;0061 302A 0316 1ABF 059A 0062;0061 302A 0316 1ABF 059A 0062; # (a◌֚◌̖◌〪◌ᪿb; a◌〪◌̖◌ᪿ◌֚b; a◌〪◌̖◌ᪿ◌֚b; a◌〪◌̖◌ᪿ◌֚b; a◌〪◌̖◌ᪿ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LATIN SMALL LETTER W BELOW, LATIN SMALL LETTER B -0061 1ABF 059A 0316 302A 0062;0061 302A 1ABF 0316 059A 0062;0061 302A 1ABF 0316 059A 0062;0061 302A 1ABF 0316 059A 0062;0061 302A 1ABF 0316 059A 0062; # (a◌ᪿ◌֚◌̖◌〪b; a◌〪◌ᪿ◌̖◌֚b; a◌〪◌ᪿ◌̖◌֚b; a◌〪◌ᪿ◌̖◌֚b; a◌〪◌ᪿ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1AC0 0062;0061 302A 0316 1AC0 059A 0062;0061 302A 0316 1AC0 059A 0062;0061 302A 0316 1AC0 059A 0062;0061 302A 0316 1AC0 059A 0062; # (a◌֚◌̖◌〪◌ᫀb; a◌〪◌̖◌ᫀ◌֚b; a◌〪◌̖◌ᫀ◌֚b; a◌〪◌̖◌ᫀ◌֚b; a◌〪◌̖◌ᫀ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LATIN SMALL LETTER TURNED W BELOW, LATIN SMALL LETTER B -0061 1AC0 059A 0316 302A 0062;0061 302A 1AC0 0316 059A 0062;0061 302A 1AC0 0316 059A 0062;0061 302A 1AC0 0316 059A 0062;0061 302A 1AC0 0316 059A 0062; # (a◌ᫀ◌֚◌̖◌〪b; a◌〪◌ᫀ◌̖◌֚b; a◌〪◌ᫀ◌̖◌֚b; a◌〪◌ᫀ◌̖◌֚b; a◌〪◌ᫀ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER TURNED W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABD 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062;0061 1DFA 0316 1ABD 059A 0062; # (a◌֚◌̖◌᷺◌᪽b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; a◌᷺◌̖◌᪽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING PARENTHESES BELOW, LATIN SMALL LETTER B +0061 1ABD 059A 0316 1DFA 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062;0061 1DFA 1ABD 0316 059A 0062; # (a◌᪽◌֚◌̖◌᷺b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; a◌᷺◌᪽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING PARENTHESES BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ABF 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062;0061 1DFA 0316 1ABF 059A 0062; # (a◌֚◌̖◌᷺◌ᪿb; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; a◌᷺◌̖◌ᪿ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER W BELOW, LATIN SMALL LETTER B +0061 1ABF 059A 0316 1DFA 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062;0061 1DFA 1ABF 0316 059A 0062; # (a◌ᪿ◌֚◌̖◌᷺b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; a◌᷺◌ᪿ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC0 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062;0061 1DFA 0316 1AC0 059A 0062; # (a◌֚◌̖◌᷺◌ᫀb; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; a◌᷺◌̖◌ᫀ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER TURNED W BELOW, LATIN SMALL LETTER B +0061 1AC0 059A 0316 1DFA 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062;0061 1DFA 1AC0 0316 059A 0062; # (a◌ᫀ◌֚◌̖◌᷺b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; a◌᷺◌ᫀ◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER TURNED W BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC1 0062;00E0 05AE 1AC1 0315 0062;0061 05AE 0300 1AC1 0315 0062;00E0 05AE 1AC1 0315 0062;0061 05AE 0300 1AC1 0315 0062; # (a◌̕◌̀◌֮◌᫁b; à◌֮◌᫁◌̕b; a◌֮◌̀◌᫁◌̕b; à◌֮◌᫁◌̕b; a◌֮◌̀◌᫁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT PARENTHESIS ABOVE LEFT, LATIN SMALL LETTER B +0061 1AC1 0315 0300 05AE 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062;0061 05AE 1AC1 0300 0315 0062; # (a◌᫁◌̕◌̀◌֮b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; a◌֮◌᫁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT PARENTHESIS ABOVE LEFT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC2 0062;00E0 05AE 1AC2 0315 0062;0061 05AE 0300 1AC2 0315 0062;00E0 05AE 1AC2 0315 0062;0061 05AE 0300 1AC2 0315 0062; # (a◌̕◌̀◌֮◌᫂b; à◌֮◌᫂◌̕b; a◌֮◌̀◌᫂◌̕b; à◌֮◌᫂◌̕b; a◌֮◌̀◌᫂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT PARENTHESIS ABOVE RIGHT, LATIN SMALL LETTER B +0061 1AC2 0315 0300 05AE 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062;0061 05AE 1AC2 0300 0315 0062; # (a◌᫂◌̕◌̀◌֮b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; a◌֮◌᫂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING RIGHT PARENTHESIS ABOVE RIGHT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC3 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062;0061 1DFA 0316 1AC3 059A 0062; # (a◌֚◌̖◌᷺◌᫃b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; a◌᷺◌̖◌᫃◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT PARENTHESIS BELOW LEFT, LATIN SMALL LETTER B +0061 1AC3 059A 0316 1DFA 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062;0061 1DFA 1AC3 0316 059A 0062; # (a◌᫃◌֚◌̖◌᷺b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; a◌᷺◌᫃◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT PARENTHESIS BELOW LEFT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1AC4 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062;0061 1DFA 0316 1AC4 059A 0062; # (a◌֚◌̖◌᷺◌᫄b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; a◌᷺◌̖◌᫄◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT PARENTHESIS BELOW RIGHT, LATIN SMALL LETTER B +0061 1AC4 059A 0316 1DFA 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062;0061 1DFA 1AC4 0316 059A 0062; # (a◌᫄◌֚◌̖◌᷺b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; a◌᷺◌᫄◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT PARENTHESIS BELOW RIGHT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC5 0062;00E0 05AE 1AC5 0315 0062;0061 05AE 0300 1AC5 0315 0062;00E0 05AE 1AC5 0315 0062;0061 05AE 0300 1AC5 0315 0062; # (a◌̕◌̀◌֮◌᫅b; à◌֮◌᫅◌̕b; a◌֮◌̀◌᫅◌̕b; à◌֮◌᫅◌̕b; a◌֮◌̀◌᫅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING SQUARE BRACKETS ABOVE, LATIN SMALL LETTER B +0061 1AC5 0315 0300 05AE 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062;0061 05AE 1AC5 0300 0315 0062; # (a◌᫅◌̕◌̀◌֮b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; a◌֮◌᫅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING SQUARE BRACKETS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC6 0062;00E0 05AE 1AC6 0315 0062;0061 05AE 0300 1AC6 0315 0062;00E0 05AE 1AC6 0315 0062;0061 05AE 0300 1AC6 0315 0062; # (a◌̕◌̀◌֮◌᫆b; à◌֮◌᫆◌̕b; a◌֮◌̀◌᫆◌̕b; à◌֮◌᫆◌̕b; a◌֮◌̀◌᫆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING NUMBER SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC6 0315 0300 05AE 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062;0061 05AE 1AC6 0300 0315 0062; # (a◌᫆◌̕◌̀◌֮b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; a◌֮◌᫆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING NUMBER SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC7 0062;00E0 05AE 1AC7 0315 0062;0061 05AE 0300 1AC7 0315 0062;00E0 05AE 1AC7 0315 0062;0061 05AE 0300 1AC7 0315 0062; # (a◌̕◌̀◌֮◌᫇b; à◌֮◌᫇◌̕b; a◌֮◌̀◌᫇◌̕b; à◌֮◌᫇◌̕b; a◌֮◌̀◌᫇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING INVERTED DOUBLE ARCH ABOVE, LATIN SMALL LETTER B +0061 1AC7 0315 0300 05AE 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062;0061 05AE 1AC7 0300 0315 0062; # (a◌᫇◌̕◌̀◌֮b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; a◌֮◌᫇◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING INVERTED DOUBLE ARCH ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC8 0062;00E0 05AE 1AC8 0315 0062;0061 05AE 0300 1AC8 0315 0062;00E0 05AE 1AC8 0315 0062;0061 05AE 0300 1AC8 0315 0062; # (a◌̕◌̀◌֮◌᫈b; à◌֮◌᫈◌̕b; a◌֮◌̀◌᫈◌̕b; à◌֮◌᫈◌̕b; a◌֮◌̀◌᫈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING PLUS SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC8 0315 0300 05AE 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062;0061 05AE 1AC8 0300 0315 0062; # (a◌᫈◌̕◌̀◌֮b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; a◌֮◌᫈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING PLUS SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1AC9 0062;00E0 05AE 1AC9 0315 0062;0061 05AE 0300 1AC9 0315 0062;00E0 05AE 1AC9 0315 0062;0061 05AE 0300 1AC9 0315 0062; # (a◌̕◌̀◌֮◌᫉b; à◌֮◌᫉◌̕b; a◌֮◌̀◌᫉◌̕b; à◌֮◌᫉◌̕b; a◌֮◌̀◌᫉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOUBLE PLUS SIGN ABOVE, LATIN SMALL LETTER B +0061 1AC9 0315 0300 05AE 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062;0061 05AE 1AC9 0300 0315 0062; # (a◌᫉◌̕◌̀◌֮b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; a◌֮◌᫉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PLUS SIGN ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1ACA 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062;0061 1DFA 0316 1ACA 059A 0062; # (a◌֚◌̖◌᷺◌᫊b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; a◌᷺◌̖◌᫊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING DOUBLE PLUS SIGN BELOW, LATIN SMALL LETTER B +0061 1ACA 059A 0316 1DFA 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062;0061 1DFA 1ACA 0316 059A 0062; # (a◌᫊◌֚◌̖◌᷺b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; a◌᷺◌᫊◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING DOUBLE PLUS SIGN BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACB 0062;00E0 05AE 1ACB 0315 0062;0061 05AE 0300 1ACB 0315 0062;00E0 05AE 1ACB 0315 0062;0061 05AE 0300 1ACB 0315 0062; # (a◌̕◌̀◌֮◌᫋b; à◌֮◌᫋◌̕b; a◌֮◌̀◌᫋◌̕b; à◌֮◌᫋◌̕b; a◌֮◌̀◌᫋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING TRIPLE ACUTE ACCENT, LATIN SMALL LETTER B +0061 1ACB 0315 0300 05AE 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062;0061 05AE 1ACB 0300 0315 0062; # (a◌᫋◌̕◌̀◌֮b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; a◌֮◌᫋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING TRIPLE ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACC 0062;00E0 05AE 1ACC 0315 0062;0061 05AE 0300 1ACC 0315 0062;00E0 05AE 1ACC 0315 0062;0061 05AE 0300 1ACC 0315 0062; # (a◌̕◌̀◌֮◌ᫌb; à◌֮◌ᫌ◌̕b; a◌֮◌̀◌ᫌ◌̕b; à◌֮◌ᫌ◌̕b; a◌֮◌̀◌ᫌ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR G, LATIN SMALL LETTER B +0061 1ACC 0315 0300 05AE 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062;0061 05AE 1ACC 0300 0315 0062; # (a◌ᫌ◌̕◌̀◌֮b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; a◌֮◌ᫌ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACD 0062;00E0 05AE 1ACD 0315 0062;0061 05AE 0300 1ACD 0315 0062;00E0 05AE 1ACD 0315 0062;0061 05AE 0300 1ACD 0315 0062; # (a◌̕◌̀◌֮◌ᫍb; à◌֮◌ᫍ◌̕b; a◌֮◌̀◌ᫍ◌̕b; à◌֮◌ᫍ◌̕b; a◌֮◌̀◌ᫍ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR R, LATIN SMALL LETTER B +0061 1ACD 0315 0300 05AE 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062;0061 05AE 1ACD 0300 0315 0062; # (a◌ᫍ◌̕◌̀◌֮b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; a◌֮◌ᫍ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR R, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1ACE 0062;00E0 05AE 1ACE 0315 0062;0061 05AE 0300 1ACE 0315 0062;00E0 05AE 1ACE 0315 0062;0061 05AE 0300 1ACE 0315 0062; # (a◌̕◌̀◌֮◌ᫎb; à◌֮◌ᫎ◌̕b; a◌֮◌̀◌ᫎ◌̕b; à◌֮◌ᫎ◌̕b; a◌֮◌̀◌ᫎ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LATIN SMALL LETTER INSULAR T, LATIN SMALL LETTER B +0061 1ACE 0315 0300 05AE 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062;0061 05AE 1ACE 0300 0315 0062; # (a◌ᫎ◌̕◌̀◌֮b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; a◌֮◌ᫎ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER INSULAR T, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 3099 093C 16FF0 1B34 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062;0061 16FF0 093C 1B34 3099 0062; # (a◌゙◌𖿰़◌᬴b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; a𖿰◌़◌᬴◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, BALINESE SIGN REREKAN, LATIN SMALL LETTER B 0061 1B34 3099 093C 16FF0 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062;0061 16FF0 1B34 093C 3099 0062; # (a◌᬴◌゙◌𖿰़b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; a𖿰◌᬴◌़◌゙b; ) LATIN SMALL LETTER A, BALINESE SIGN REREKAN, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, LATIN SMALL LETTER B 0061 05B0 094D 3099 1B44 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062;0061 3099 094D 1B44 05B0 0062; # (a◌ְ◌्◌゙᭄b; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; a◌゙◌्᭄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BALINESE ADEG ADEG, LATIN SMALL LETTER B 0061 1B44 05B0 094D 3099 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062;0061 3099 1B44 094D 05B0 0062; # (a᭄◌ְ◌्◌゙b; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; a◌゙᭄◌्◌ְb; ) LATIN SMALL LETTER A, BALINESE ADEG ADEG, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 1B6B 0062;00E0 05AE 1B6B 0315 0062;0061 05AE 0300 1B6B 0315 0062;00E0 05AE 1B6B 0315 0062;0061 05AE 0300 1B6B 0315 0062; # (a◌̕◌̀◌֮◌᭫b; à◌֮◌᭫◌̕b; a◌֮◌̀◌᭫◌̕b; à◌֮◌᭫◌̕b; a◌֮◌̀◌᭫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING TEGEH, LATIN SMALL LETTER B 0061 1B6B 0315 0300 05AE 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062;0061 05AE 1B6B 0300 0315 0062; # (a◌᭫◌̕◌̀◌֮b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; a◌֮◌᭫◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING TEGEH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1B6C 0062;0061 302A 0316 1B6C 059A 0062;0061 302A 0316 1B6C 059A 0062;0061 302A 0316 1B6C 059A 0062;0061 302A 0316 1B6C 059A 0062; # (a◌֚◌̖◌〪◌᭬b; a◌〪◌̖◌᭬◌֚b; a◌〪◌̖◌᭬◌֚b; a◌〪◌̖◌᭬◌֚b; a◌〪◌̖◌᭬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, BALINESE MUSICAL SYMBOL COMBINING ENDEP, LATIN SMALL LETTER B -0061 1B6C 059A 0316 302A 0062;0061 302A 1B6C 0316 059A 0062;0061 302A 1B6C 0316 059A 0062;0061 302A 1B6C 0316 059A 0062;0061 302A 1B6C 0316 059A 0062; # (a◌᭬◌֚◌̖◌〪b; a◌〪◌᭬◌̖◌֚b; a◌〪◌᭬◌̖◌֚b; a◌〪◌᭬◌̖◌֚b; a◌〪◌᭬◌̖◌֚b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING ENDEP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1B6C 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062;0061 1DFA 0316 1B6C 059A 0062; # (a◌֚◌̖◌᷺◌᭬b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; a◌᷺◌̖◌᭬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, BALINESE MUSICAL SYMBOL COMBINING ENDEP, LATIN SMALL LETTER B +0061 1B6C 059A 0316 1DFA 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062;0061 1DFA 1B6C 0316 059A 0062; # (a◌᭬◌֚◌̖◌᷺b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; a◌᷺◌᭬◌̖◌֚b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING ENDEP, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1B6D 0062;00E0 05AE 1B6D 0315 0062;0061 05AE 0300 1B6D 0315 0062;00E0 05AE 1B6D 0315 0062;0061 05AE 0300 1B6D 0315 0062; # (a◌̕◌̀◌֮◌᭭b; à◌֮◌᭭◌̕b; a◌֮◌̀◌᭭◌̕b; à◌֮◌᭭◌̕b; a◌֮◌̀◌᭭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPUL, LATIN SMALL LETTER B 0061 1B6D 0315 0300 05AE 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062;0061 05AE 1B6D 0300 0315 0062; # (a◌᭭◌̕◌̀◌֮b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; a◌֮◌᭭◌̀◌̕b; ) LATIN SMALL LETTER A, BALINESE MUSICAL SYMBOL COMBINING KEMPUL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1B6E 0062;00E0 05AE 1B6E 0315 0062;0061 05AE 0300 1B6E 0315 0062;00E0 05AE 1B6E 0315 0062;0061 05AE 0300 1B6E 0315 0062; # (a◌̕◌̀◌֮◌᭮b; à◌֮◌᭮◌̕b; a◌֮◌̀◌᭮◌̕b; à◌֮◌᭮◌̕b; a◌֮◌̀◌᭮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BALINESE MUSICAL SYMBOL COMBINING KEMPLI, LATIN SMALL LETTER B @@ -17875,28 +18062,28 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1CD2 0315 0300 05AE 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062;0061 05AE 1CD2 0300 0315 0062; # (a◌᳒◌̕◌̀◌֮b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; a◌֮◌᳒◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE PRENKHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 16FF0 0334 1CD4 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062;0061 0334 1CD4 16FF0 0062; # (a𖿰◌̴◌᳔b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; a◌̴◌᳔𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN YAJURVEDIC MIDLINE SVARITA, LATIN SMALL LETTER B 0061 1CD4 16FF0 0334 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062;0061 1CD4 0334 16FF0 0062; # (a◌᳔𖿰◌̴b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; a◌᳔◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN YAJURVEDIC MIDLINE SVARITA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 059A 0316 302A 1CD5 0062;0061 302A 0316 1CD5 059A 0062;0061 302A 0316 1CD5 059A 0062;0061 302A 0316 1CD5 059A 0062;0061 302A 0316 1CD5 059A 0062; # (a◌֚◌̖◌〪◌᳕b; a◌〪◌̖◌᳕◌֚b; a◌〪◌̖◌᳕◌֚b; a◌〪◌̖◌᳕◌֚b; a◌〪◌̖◌᳕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, LATIN SMALL LETTER B -0061 1CD5 059A 0316 302A 0062;0061 302A 1CD5 0316 059A 0062;0061 302A 1CD5 0316 059A 0062;0061 302A 1CD5 0316 059A 0062;0061 302A 1CD5 0316 059A 0062; # (a◌᳕◌֚◌̖◌〪b; a◌〪◌᳕◌̖◌֚b; a◌〪◌᳕◌̖◌֚b; a◌〪◌᳕◌̖◌֚b; a◌〪◌᳕◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CD6 0062;0061 302A 0316 1CD6 059A 0062;0061 302A 0316 1CD6 059A 0062;0061 302A 0316 1CD6 059A 0062;0061 302A 0316 1CD6 059A 0062; # (a◌֚◌̖◌〪◌᳖b; a◌〪◌̖◌᳖◌֚b; a◌〪◌̖◌᳖◌֚b; a◌〪◌̖◌᳖◌֚b; a◌〪◌̖◌᳖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, LATIN SMALL LETTER B -0061 1CD6 059A 0316 302A 0062;0061 302A 1CD6 0316 059A 0062;0061 302A 1CD6 0316 059A 0062;0061 302A 1CD6 0316 059A 0062;0061 302A 1CD6 0316 059A 0062; # (a◌᳖◌֚◌̖◌〪b; a◌〪◌᳖◌̖◌֚b; a◌〪◌᳖◌̖◌֚b; a◌〪◌᳖◌̖◌֚b; a◌〪◌᳖◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CD7 0062;0061 302A 0316 1CD7 059A 0062;0061 302A 0316 1CD7 059A 0062;0061 302A 0316 1CD7 059A 0062;0061 302A 0316 1CD7 059A 0062; # (a◌֚◌̖◌〪◌᳗b; a◌〪◌̖◌᳗◌֚b; a◌〪◌̖◌᳗◌֚b; a◌〪◌̖◌᳗◌֚b; a◌〪◌̖◌᳗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, LATIN SMALL LETTER B -0061 1CD7 059A 0316 302A 0062;0061 302A 1CD7 0316 059A 0062;0061 302A 1CD7 0316 059A 0062;0061 302A 1CD7 0316 059A 0062;0061 302A 1CD7 0316 059A 0062; # (a◌᳗◌֚◌̖◌〪b; a◌〪◌᳗◌̖◌֚b; a◌〪◌᳗◌̖◌֚b; a◌〪◌᳗◌̖◌֚b; a◌〪◌᳗◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CD8 0062;0061 302A 0316 1CD8 059A 0062;0061 302A 0316 1CD8 059A 0062;0061 302A 0316 1CD8 059A 0062;0061 302A 0316 1CD8 059A 0062; # (a◌֚◌̖◌〪◌᳘b; a◌〪◌̖◌᳘◌֚b; a◌〪◌̖◌᳘◌֚b; a◌〪◌̖◌᳘◌֚b; a◌〪◌̖◌᳘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE CANDRA BELOW, LATIN SMALL LETTER B -0061 1CD8 059A 0316 302A 0062;0061 302A 1CD8 0316 059A 0062;0061 302A 1CD8 0316 059A 0062;0061 302A 1CD8 0316 059A 0062;0061 302A 1CD8 0316 059A 0062; # (a◌᳘◌֚◌̖◌〪b; a◌〪◌᳘◌̖◌֚b; a◌〪◌᳘◌̖◌֚b; a◌〪◌᳘◌̖◌֚b; a◌〪◌᳘◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE CANDRA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CD9 0062;0061 302A 0316 1CD9 059A 0062;0061 302A 0316 1CD9 059A 0062;0061 302A 0316 1CD9 059A 0062;0061 302A 0316 1CD9 059A 0062; # (a◌֚◌̖◌〪◌᳙b; a◌〪◌̖◌᳙◌֚b; a◌〪◌̖◌᳙◌֚b; a◌〪◌̖◌᳙◌֚b; a◌〪◌̖◌᳙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, LATIN SMALL LETTER B -0061 1CD9 059A 0316 302A 0062;0061 302A 1CD9 0316 059A 0062;0061 302A 1CD9 0316 059A 0062;0061 302A 1CD9 0316 059A 0062;0061 302A 1CD9 0316 059A 0062; # (a◌᳙◌֚◌̖◌〪b; a◌〪◌᳙◌̖◌֚b; a◌〪◌᳙◌̖◌֚b; a◌〪◌᳙◌̖◌֚b; a◌〪◌᳙◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD5 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062;0061 1DFA 0316 1CD5 059A 0062; # (a◌֚◌̖◌᷺◌᳕b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; a◌᷺◌̖◌᳕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD5 059A 0316 1DFA 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062;0061 1DFA 1CD5 0316 059A 0062; # (a◌᳕◌֚◌̖◌᷺b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; a◌᷺◌᳕◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD6 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062;0061 1DFA 0316 1CD6 059A 0062; # (a◌֚◌̖◌᷺◌᳖b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; a◌᷺◌̖◌᳖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD6 059A 0316 1DFA 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062;0061 1DFA 1CD6 0316 059A 0062; # (a◌᳖◌֚◌̖◌᷺b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; a◌᷺◌᳖◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD7 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062;0061 1DFA 0316 1CD7 059A 0062; # (a◌֚◌̖◌᷺◌᳗b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; a◌᷺◌̖◌᳗◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, LATIN SMALL LETTER B +0061 1CD7 059A 0316 1DFA 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062;0061 1DFA 1CD7 0316 059A 0062; # (a◌᳗◌֚◌̖◌᷺b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; a◌᷺◌᳗◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD8 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062;0061 1DFA 0316 1CD8 059A 0062; # (a◌֚◌̖◌᷺◌᳘b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; a◌᷺◌̖◌᳘◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE CANDRA BELOW, LATIN SMALL LETTER B +0061 1CD8 059A 0316 1DFA 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062;0061 1DFA 1CD8 0316 059A 0062; # (a◌᳘◌֚◌̖◌᷺b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; a◌᷺◌᳘◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE CANDRA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CD9 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062;0061 1DFA 0316 1CD9 059A 0062; # (a◌֚◌̖◌᷺◌᳙b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; a◌᷺◌̖◌᳙◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, LATIN SMALL LETTER B +0061 1CD9 059A 0316 1DFA 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062;0061 1DFA 1CD9 0316 059A 0062; # (a◌᳙◌֚◌̖◌᷺b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; a◌᷺◌᳙◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1CDA 0062;00E0 05AE 1CDA 0315 0062;0061 05AE 0300 1CDA 0315 0062;00E0 05AE 1CDA 0315 0062;0061 05AE 0300 1CDA 0315 0062; # (a◌̕◌̀◌֮◌᳚b; à◌֮◌᳚◌̕b; a◌֮◌̀◌᳚◌̕b; à◌֮◌᳚◌̕b; a◌֮◌̀◌᳚◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE DOUBLE SVARITA, LATIN SMALL LETTER B 0061 1CDA 0315 0300 05AE 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062;0061 05AE 1CDA 0300 0315 0062; # (a◌᳚◌̕◌̀◌֮b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; a◌֮◌᳚◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE DOUBLE SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1CDB 0062;00E0 05AE 1CDB 0315 0062;0061 05AE 0300 1CDB 0315 0062;00E0 05AE 1CDB 0315 0062;0061 05AE 0300 1CDB 0315 0062; # (a◌̕◌̀◌֮◌᳛b; à◌֮◌᳛◌̕b; a◌֮◌̀◌᳛◌̕b; à◌֮◌᳛◌̕b; a◌֮◌̀◌᳛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE TRIPLE SVARITA, LATIN SMALL LETTER B 0061 1CDB 0315 0300 05AE 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062;0061 05AE 1CDB 0300 0315 0062; # (a◌᳛◌̕◌̀◌֮b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; a◌֮◌᳛◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE TRIPLE SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1CDC 0062;0061 302A 0316 1CDC 059A 0062;0061 302A 0316 1CDC 059A 0062;0061 302A 0316 1CDC 059A 0062;0061 302A 0316 1CDC 059A 0062; # (a◌֚◌̖◌〪◌᳜b; a◌〪◌̖◌᳜◌֚b; a◌〪◌̖◌᳜◌֚b; a◌〪◌̖◌᳜◌֚b; a◌〪◌̖◌᳜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE KATHAKA ANUDATTA, LATIN SMALL LETTER B -0061 1CDC 059A 0316 302A 0062;0061 302A 1CDC 0316 059A 0062;0061 302A 1CDC 0316 059A 0062;0061 302A 1CDC 0316 059A 0062;0061 302A 1CDC 0316 059A 0062; # (a◌᳜◌֚◌̖◌〪b; a◌〪◌᳜◌̖◌֚b; a◌〪◌᳜◌̖◌֚b; a◌〪◌᳜◌̖◌֚b; a◌〪◌᳜◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE KATHAKA ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CDD 0062;0061 302A 0316 1CDD 059A 0062;0061 302A 0316 1CDD 059A 0062;0061 302A 0316 1CDD 059A 0062;0061 302A 0316 1CDD 059A 0062; # (a◌֚◌̖◌〪◌᳝b; a◌〪◌̖◌᳝◌֚b; a◌〪◌̖◌᳝◌֚b; a◌〪◌̖◌᳝◌֚b; a◌〪◌̖◌᳝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE DOT BELOW, LATIN SMALL LETTER B -0061 1CDD 059A 0316 302A 0062;0061 302A 1CDD 0316 059A 0062;0061 302A 1CDD 0316 059A 0062;0061 302A 1CDD 0316 059A 0062;0061 302A 1CDD 0316 059A 0062; # (a◌᳝◌֚◌̖◌〪b; a◌〪◌᳝◌̖◌֚b; a◌〪◌᳝◌̖◌֚b; a◌〪◌᳝◌̖◌֚b; a◌〪◌᳝◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CDE 0062;0061 302A 0316 1CDE 059A 0062;0061 302A 0316 1CDE 059A 0062;0061 302A 0316 1CDE 059A 0062;0061 302A 0316 1CDE 059A 0062; # (a◌֚◌̖◌〪◌᳞b; a◌〪◌̖◌᳞◌֚b; a◌〪◌̖◌᳞◌֚b; a◌〪◌̖◌᳞◌֚b; a◌〪◌̖◌᳞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B -0061 1CDE 059A 0316 302A 0062;0061 302A 1CDE 0316 059A 0062;0061 302A 1CDE 0316 059A 0062;0061 302A 1CDE 0316 059A 0062;0061 302A 1CDE 0316 059A 0062; # (a◌᳞◌֚◌̖◌〪b; a◌〪◌᳞◌̖◌֚b; a◌〪◌᳞◌̖◌֚b; a◌〪◌᳞◌̖◌֚b; a◌〪◌᳞◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1CDF 0062;0061 302A 0316 1CDF 059A 0062;0061 302A 0316 1CDF 059A 0062;0061 302A 0316 1CDF 059A 0062;0061 302A 0316 1CDF 059A 0062; # (a◌֚◌̖◌〪◌᳟b; a◌〪◌̖◌᳟◌֚b; a◌〪◌̖◌᳟◌֚b; a◌〪◌̖◌᳟◌֚b; a◌〪◌̖◌᳟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC TONE THREE DOTS BELOW, LATIN SMALL LETTER B -0061 1CDF 059A 0316 302A 0062;0061 302A 1CDF 0316 059A 0062;0061 302A 1CDF 0316 059A 0062;0061 302A 1CDF 0316 059A 0062;0061 302A 1CDF 0316 059A 0062; # (a◌᳟◌֚◌̖◌〪b; a◌〪◌᳟◌̖◌֚b; a◌〪◌᳟◌̖◌֚b; a◌〪◌᳟◌̖◌֚b; a◌〪◌᳟◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDC 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062;0061 1DFA 0316 1CDC 059A 0062; # (a◌֚◌̖◌᷺◌᳜b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; a◌᷺◌̖◌᳜◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE KATHAKA ANUDATTA, LATIN SMALL LETTER B +0061 1CDC 059A 0316 1DFA 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062;0061 1DFA 1CDC 0316 059A 0062; # (a◌᳜◌֚◌̖◌᷺b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; a◌᷺◌᳜◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE KATHAKA ANUDATTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDD 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062;0061 1DFA 0316 1CDD 059A 0062; # (a◌֚◌̖◌᷺◌᳝b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; a◌᷺◌̖◌᳝◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE DOT BELOW, LATIN SMALL LETTER B +0061 1CDD 059A 0316 1DFA 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062;0061 1DFA 1CDD 0316 059A 0062; # (a◌᳝◌֚◌̖◌᷺b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; a◌᷺◌᳝◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDE 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062;0061 1DFA 0316 1CDE 059A 0062; # (a◌֚◌̖◌᷺◌᳞b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; a◌᷺◌̖◌᳞◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE TWO DOTS BELOW, LATIN SMALL LETTER B +0061 1CDE 059A 0316 1DFA 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062;0061 1DFA 1CDE 0316 059A 0062; # (a◌᳞◌֚◌̖◌᷺b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; a◌᷺◌᳞◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CDF 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062;0061 1DFA 0316 1CDF 059A 0062; # (a◌֚◌̖◌᷺◌᳟b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; a◌᷺◌̖◌᳟◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC TONE THREE DOTS BELOW, LATIN SMALL LETTER B +0061 1CDF 059A 0316 1DFA 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062;0061 1DFA 1CDF 0316 059A 0062; # (a◌᳟◌֚◌̖◌᷺b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; a◌᷺◌᳟◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC TONE THREE DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1CE0 0062;00E0 05AE 1CE0 0315 0062;0061 05AE 0300 1CE0 0315 0062;00E0 05AE 1CE0 0315 0062;0061 05AE 0300 1CE0 0315 0062; # (a◌̕◌̀◌֮◌᳠b; à◌֮◌᳠◌̕b; a◌֮◌̀◌᳠◌̕b; à◌֮◌᳠◌̕b; a◌֮◌̀◌᳠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA, LATIN SMALL LETTER B 0061 1CE0 0315 0300 05AE 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062;0061 05AE 1CE0 0300 0315 0062; # (a◌᳠◌̕◌̀◌֮b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; a◌֮◌᳠◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 16FF0 0334 1CE2 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062;0061 0334 1CE2 16FF0 0062; # (a𖿰◌̴◌᳢b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; a◌̴◌᳢𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA SVARITA, LATIN SMALL LETTER B @@ -17913,8 +18100,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1CE7 16FF0 0334 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062;0061 1CE7 0334 16FF0 0062; # (a◌᳧𖿰◌̴b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; a◌᳧◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA UDATTA WITH TAIL, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 1CE8 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062;0061 0334 1CE8 16FF0 0062; # (a𖿰◌̴◌᳨b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; a◌̴◌᳨𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, VEDIC SIGN VISARGA ANUDATTA WITH TAIL, LATIN SMALL LETTER B 0061 1CE8 16FF0 0334 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062;0061 1CE8 0334 16FF0 0062; # (a◌᳨𖿰◌̴b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; a◌᳨◌̴𖿰b; ) LATIN SMALL LETTER A, VEDIC SIGN VISARGA ANUDATTA WITH TAIL, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 059A 0316 302A 1CED 0062;0061 302A 0316 1CED 059A 0062;0061 302A 0316 1CED 059A 0062;0061 302A 0316 1CED 059A 0062;0061 302A 0316 1CED 059A 0062; # (a◌֚◌̖◌〪◌᳭b; a◌〪◌̖◌᳭◌֚b; a◌〪◌̖◌᳭◌֚b; a◌〪◌̖◌᳭◌֚b; a◌〪◌̖◌᳭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, VEDIC SIGN TIRYAK, LATIN SMALL LETTER B -0061 1CED 059A 0316 302A 0062;0061 302A 1CED 0316 059A 0062;0061 302A 1CED 0316 059A 0062;0061 302A 1CED 0316 059A 0062;0061 302A 1CED 0316 059A 0062; # (a◌᳭◌֚◌̖◌〪b; a◌〪◌᳭◌̖◌֚b; a◌〪◌᳭◌̖◌֚b; a◌〪◌᳭◌̖◌֚b; a◌〪◌᳭◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC SIGN TIRYAK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1CED 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062;0061 1DFA 0316 1CED 059A 0062; # (a◌֚◌̖◌᷺◌᳭b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; a◌᷺◌̖◌᳭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, VEDIC SIGN TIRYAK, LATIN SMALL LETTER B +0061 1CED 059A 0316 1DFA 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062;0061 1DFA 1CED 0316 059A 0062; # (a◌᳭◌֚◌̖◌᷺b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; a◌᷺◌᳭◌̖◌֚b; ) LATIN SMALL LETTER A, VEDIC SIGN TIRYAK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1CF4 0062;00E0 05AE 1CF4 0315 0062;0061 05AE 0300 1CF4 0315 0062;00E0 05AE 1CF4 0315 0062;0061 05AE 0300 1CF4 0315 0062; # (a◌̕◌̀◌֮◌᳴b; à◌֮◌᳴◌̕b; a◌֮◌̀◌᳴◌̕b; à◌֮◌᳴◌̕b; a◌֮◌̀◌᳴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE CANDRA ABOVE, LATIN SMALL LETTER B 0061 1CF4 0315 0300 05AE 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062;0061 05AE 1CF4 0300 0315 0062; # (a◌᳴◌̕◌̀◌֮b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; a◌֮◌᳴◌̀◌̕b; ) LATIN SMALL LETTER A, VEDIC TONE CANDRA ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1CF8 0062;00E0 05AE 1CF8 0315 0062;0061 05AE 0300 1CF8 0315 0062;00E0 05AE 1CF8 0315 0062;0061 05AE 0300 1CF8 0315 0062; # (a◌̕◌̀◌֮◌᳸b; à◌֮◌᳸◌̕b; a◌֮◌̀◌᳸◌̕b; à◌֮◌᳸◌̕b; a◌֮◌̀◌᳸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, VEDIC TONE RING ABOVE, LATIN SMALL LETTER B @@ -17925,8 +18112,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1DC0 0315 0300 05AE 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062;0061 05AE 1DC0 0300 0315 0062; # (a◌᷀◌̕◌̀◌֮b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; a◌֮◌᷀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOTTED GRAVE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DC1 0062;00E0 05AE 1DC1 0315 0062;0061 05AE 0300 1DC1 0315 0062;00E0 05AE 1DC1 0315 0062;0061 05AE 0300 1DC1 0315 0062; # (a◌̕◌̀◌֮◌᷁b; à◌֮◌᷁◌̕b; a◌֮◌̀◌᷁◌̕b; à◌֮◌᷁◌̕b; a◌֮◌̀◌᷁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DOTTED ACUTE ACCENT, LATIN SMALL LETTER B 0061 1DC1 0315 0300 05AE 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062;0061 05AE 1DC1 0300 0315 0062; # (a◌᷁◌̕◌̀◌֮b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; a◌֮◌᷁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DOTTED ACUTE ACCENT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1DC2 0062;0061 302A 0316 1DC2 059A 0062;0061 302A 0316 1DC2 059A 0062;0061 302A 0316 1DC2 059A 0062;0061 302A 0316 1DC2 059A 0062; # (a◌֚◌̖◌〪◌᷂b; a◌〪◌̖◌᷂◌֚b; a◌〪◌̖◌᷂◌֚b; a◌〪◌̖◌᷂◌֚b; a◌〪◌̖◌᷂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING SNAKE BELOW, LATIN SMALL LETTER B -0061 1DC2 059A 0316 302A 0062;0061 302A 1DC2 0316 059A 0062;0061 302A 1DC2 0316 059A 0062;0061 302A 1DC2 0316 059A 0062;0061 302A 1DC2 0316 059A 0062; # (a◌᷂◌֚◌̖◌〪b; a◌〪◌᷂◌̖◌֚b; a◌〪◌᷂◌̖◌֚b; a◌〪◌᷂◌̖◌֚b; a◌〪◌᷂◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SNAKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DC2 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062;0061 1DFA 0316 1DC2 059A 0062; # (a◌֚◌̖◌᷺◌᷂b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; a◌᷺◌̖◌᷂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING SNAKE BELOW, LATIN SMALL LETTER B +0061 1DC2 059A 0316 1DFA 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062;0061 1DFA 1DC2 0316 059A 0062; # (a◌᷂◌֚◌̖◌᷺b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; a◌᷺◌᷂◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING SNAKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DC3 0062;00E0 05AE 1DC3 0315 0062;0061 05AE 0300 1DC3 0315 0062;00E0 05AE 1DC3 0315 0062;0061 05AE 0300 1DC3 0315 0062; # (a◌̕◌̀◌֮◌᷃b; à◌֮◌᷃◌̕b; a◌֮◌̀◌᷃◌̕b; à◌֮◌᷃◌̕b; a◌֮◌̀◌᷃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING SUSPENSION MARK, LATIN SMALL LETTER B 0061 1DC3 0315 0300 05AE 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062;0061 05AE 1DC3 0300 0315 0062; # (a◌᷃◌̕◌̀◌֮b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; a◌֮◌᷃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING SUSPENSION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DC4 0062;00E0 05AE 1DC4 0315 0062;0061 05AE 0300 1DC4 0315 0062;00E0 05AE 1DC4 0315 0062;0061 05AE 0300 1DC4 0315 0062; # (a◌̕◌̀◌֮◌᷄b; à◌֮◌᷄◌̕b; a◌֮◌̀◌᷄◌̕b; à◌֮◌᷄◌̕b; a◌֮◌̀◌᷄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON-ACUTE, LATIN SMALL LETTER B @@ -17941,8 +18128,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1DC8 0315 0300 05AE 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062;0061 05AE 1DC8 0300 0315 0062; # (a◌᷈◌̕◌̀◌֮b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; a◌֮◌᷈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRAVE-ACUTE-GRAVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DC9 0062;00E0 05AE 1DC9 0315 0062;0061 05AE 0300 1DC9 0315 0062;00E0 05AE 1DC9 0315 0062;0061 05AE 0300 1DC9 0315 0062; # (a◌̕◌̀◌֮◌᷉b; à◌֮◌᷉◌̕b; a◌֮◌̀◌᷉◌̕b; à◌֮◌᷉◌̕b; a◌֮◌̀◌᷉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ACUTE-GRAVE-ACUTE, LATIN SMALL LETTER B 0061 1DC9 0315 0300 05AE 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062;0061 05AE 1DC9 0300 0315 0062; # (a◌᷉◌̕◌̀◌֮b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; a◌֮◌᷉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ACUTE-GRAVE-ACUTE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1DCA 0062;0061 302A 0316 1DCA 059A 0062;0061 302A 0316 1DCA 059A 0062;0061 302A 0316 1DCA 059A 0062;0061 302A 0316 1DCA 059A 0062; # (a◌֚◌̖◌〪◌᷊b; a◌〪◌̖◌᷊◌֚b; a◌〪◌̖◌᷊◌֚b; a◌〪◌̖◌᷊◌֚b; a◌〪◌̖◌᷊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LATIN SMALL LETTER R BELOW, LATIN SMALL LETTER B -0061 1DCA 059A 0316 302A 0062;0061 302A 1DCA 0316 059A 0062;0061 302A 1DCA 0316 059A 0062;0061 302A 1DCA 0316 059A 0062;0061 302A 1DCA 0316 059A 0062; # (a◌᷊◌֚◌̖◌〪b; a◌〪◌᷊◌̖◌֚b; a◌〪◌᷊◌̖◌֚b; a◌〪◌᷊◌̖◌֚b; a◌〪◌᷊◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DCA 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062;0061 1DFA 0316 1DCA 059A 0062; # (a◌֚◌̖◌᷺◌᷊b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; a◌᷺◌̖◌᷊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LATIN SMALL LETTER R BELOW, LATIN SMALL LETTER B +0061 1DCA 059A 0316 1DFA 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062;0061 1DFA 1DCA 0316 059A 0062; # (a◌᷊◌֚◌̖◌᷺b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; a◌᷺◌᷊◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER R BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DCB 0062;00E0 05AE 1DCB 0315 0062;0061 05AE 0300 1DCB 0315 0062;00E0 05AE 1DCB 0315 0062;0061 05AE 0300 1DCB 0315 0062; # (a◌̕◌̀◌֮◌᷋b; à◌֮◌᷋◌̕b; a◌֮◌̀◌᷋◌̕b; à◌֮◌᷋◌̕b; a◌֮◌̀◌᷋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING BREVE-MACRON, LATIN SMALL LETTER B 0061 1DCB 0315 0300 05AE 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062;0061 05AE 1DCB 0300 0315 0062; # (a◌᷋◌̕◌̀◌֮b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; a◌֮◌᷋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING BREVE-MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DCC 0062;00E0 05AE 1DCC 0315 0062;0061 05AE 0300 1DCC 0315 0062;00E0 05AE 1DCC 0315 0062;0061 05AE 0300 1DCC 0315 0062; # (a◌̕◌̀◌֮◌᷌b; à◌֮◌᷌◌̕b; a◌֮◌̀◌᷌◌̕b; à◌֮◌᷌◌̕b; a◌֮◌̀◌᷌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING MACRON-BREVE, LATIN SMALL LETTER B @@ -17951,8 +18138,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1DCD 0345 035D 035C 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062;0061 035C 1DCD 035D 0345 0062; # (a◌᷍◌ͅ◌͝◌͜b; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; a◌͜◌᷍◌͝◌ͅb; ) LATIN SMALL LETTER A, COMBINING DOUBLE CIRCUMFLEX ABOVE, COMBINING GREEK YPOGEGRAMMENI, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, LATIN SMALL LETTER B 0061 031B 1DCE 0321 1DCE 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062; # (a◌̛◌᷎◌̡◌᷎b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; ) LATIN SMALL LETTER A, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B 0061 1DCE 031B 1DCE 0321 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062;0061 0321 1DCE 1DCE 031B 0062; # (a◌᷎◌̛◌᷎◌̡b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; a◌̡◌᷎◌᷎◌̛b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING HORN, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, LATIN SMALL LETTER B -0061 059A 0316 302A 1DCF 0062;0061 302A 0316 1DCF 059A 0062;0061 302A 0316 1DCF 059A 0062;0061 302A 0316 1DCF 059A 0062;0061 302A 0316 1DCF 059A 0062; # (a◌֚◌̖◌〪◌᷏b; a◌〪◌̖◌᷏◌֚b; a◌〪◌̖◌᷏◌֚b; a◌〪◌̖◌᷏◌֚b; a◌〪◌̖◌᷏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ZIGZAG BELOW, LATIN SMALL LETTER B -0061 1DCF 059A 0316 302A 0062;0061 302A 1DCF 0316 059A 0062;0061 302A 1DCF 0316 059A 0062;0061 302A 1DCF 0316 059A 0062;0061 302A 1DCF 0316 059A 0062; # (a◌᷏◌֚◌̖◌〪b; a◌〪◌᷏◌̖◌֚b; a◌〪◌᷏◌̖◌֚b; a◌〪◌᷏◌̖◌֚b; a◌〪◌᷏◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ZIGZAG BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DCF 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062;0061 1DFA 0316 1DCF 059A 0062; # (a◌֚◌̖◌᷺◌᷏b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; a◌᷺◌̖◌᷏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ZIGZAG BELOW, LATIN SMALL LETTER B +0061 1DCF 059A 0316 1DFA 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062;0061 1DFA 1DCF 0316 059A 0062; # (a◌᷏◌֚◌̖◌᷺b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; a◌᷺◌᷏◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ZIGZAG BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 1DCE 0321 0F74 1DD0 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062;0061 0F74 0321 1DD0 1DCE 0062; # (a◌᷎◌̡◌ུ◌᷐b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; a◌ུ◌̡◌᷐◌᷎b; ) LATIN SMALL LETTER A, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, COMBINING IS BELOW, LATIN SMALL LETTER B 0061 1DD0 1DCE 0321 0F74 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062;0061 0F74 1DD0 0321 1DCE 0062; # (a◌᷐◌᷎◌̡◌ུb; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; a◌ུ◌᷐◌̡◌᷎b; ) LATIN SMALL LETTER A, COMBINING IS BELOW, COMBINING OGONEK ABOVE, COMBINING PALATALIZED HOOK BELOW, TIBETAN VOWEL SIGN U, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DD1 0062;00E0 05AE 1DD1 0315 0062;0061 05AE 0300 1DD1 0315 0062;00E0 05AE 1DD1 0315 0062;0061 05AE 0300 1DD1 0315 0062; # (a◌̕◌̀◌֮◌᷑b; à◌֮◌᷑◌̕b; a◌֮◌̀◌᷑◌̕b; à◌֮◌᷑◌̕b; a◌֮◌̀◌᷑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING UR ABOVE, LATIN SMALL LETTER B @@ -18035,18 +18222,20 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1DF7 0300 05AE 1D16D 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062; # (a◌᷷◌̀◌𝅭֮b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B 0061 0300 05AE 1D16D 1DF8 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062; # (a◌̀◌𝅭֮◌᷸b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING DOT ABOVE LEFT, LATIN SMALL LETTER B 0061 1DF8 0300 05AE 1D16D 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062; # (a◌᷸◌̀◌𝅭֮b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B -0061 059A 0316 302A 1DF9 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062; # (a◌֚◌̖◌〪◌᷹b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING WIDE INVERTED BRIDGE BELOW, LATIN SMALL LETTER B -0061 1DF9 059A 0316 302A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062; # (a◌᷹◌֚◌̖◌〪b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIDE INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DF9 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062;0061 1DFA 0316 1DF9 059A 0062; # (a◌֚◌̖◌᷺◌᷹b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; a◌᷺◌̖◌᷹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING WIDE INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 1DF9 059A 0316 1DFA 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062;0061 1DFA 1DF9 0316 059A 0062; # (a◌᷹◌֚◌̖◌᷺b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; a◌᷺◌᷹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIDE INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0316 1DFA 031B 1DFA 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062; # (a◌̖◌᷺◌̛◌᷺b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 1DFA 0316 1DFA 031B 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062;0061 031B 1DFA 1DFA 0316 0062; # (a◌᷺◌̖◌᷺◌̛b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; a◌̛◌᷺◌᷺◌̖b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DFB 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062; # (a◌̕◌̀◌֮◌᷻b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DELETION MARK, LATIN SMALL LETTER B 0061 1DFB 0315 0300 05AE 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062; # (a◌᷻◌̕◌̀◌֮b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DELETION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 035D 035C 0315 1DFC 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062; # (a◌͝◌͜◌̕◌᷼b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE INVERTED BREVE BELOW, LATIN SMALL LETTER B 0061 1DFC 035D 035C 0315 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062; # (a◌᷼◌͝◌͜◌̕b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE INVERTED BREVE BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B -0061 059A 0316 302A 1DFD 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062; # (a◌֚◌̖◌〪◌᷽b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ALMOST EQUAL TO BELOW, LATIN SMALL LETTER B -0061 1DFD 059A 0316 302A 0062;0061 302A 1DFD 0316 059A 0062;0061 302A 1DFD 0316 059A 0062;0061 302A 1DFD 0316 059A 0062;0061 302A 1DFD 0316 059A 0062; # (a◌᷽◌֚◌̖◌〪b; a◌〪◌᷽◌̖◌֚b; a◌〪◌᷽◌̖◌֚b; a◌〪◌᷽◌̖◌֚b; a◌〪◌᷽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DFD 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062;0061 1DFA 0316 1DFD 059A 0062; # (a◌֚◌̖◌᷺◌᷽b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; a◌᷺◌̖◌᷽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING ALMOST EQUAL TO BELOW, LATIN SMALL LETTER B +0061 1DFD 059A 0316 1DFA 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062;0061 1DFA 1DFD 0316 059A 0062; # (a◌᷽◌֚◌̖◌᷺b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; a◌᷺◌᷽◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING ALMOST EQUAL TO BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DFE 0062;00E0 05AE 1DFE 0315 0062;0061 05AE 0300 1DFE 0315 0062;00E0 05AE 1DFE 0315 0062;0061 05AE 0300 1DFE 0315 0062; # (a◌̕◌̀◌֮◌᷾b; à◌֮◌᷾◌̕b; a◌֮◌̀◌᷾◌̕b; à◌֮◌᷾◌̕b; a◌֮◌̀◌᷾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT ARROWHEAD ABOVE, LATIN SMALL LETTER B 0061 1DFE 0315 0300 05AE 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062;0061 05AE 1DFE 0300 0315 0062; # (a◌᷾◌̕◌̀◌֮b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; a◌֮◌᷾◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROWHEAD ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1DFF 0062;0061 302A 0316 1DFF 059A 0062;0061 302A 0316 1DFF 059A 0062;0061 302A 0316 1DFF 059A 0062;0061 302A 0316 1DFF 059A 0062; # (a◌֚◌̖◌〪◌᷿b; a◌〪◌̖◌᷿◌֚b; a◌〪◌̖◌᷿◌֚b; a◌〪◌̖◌᷿◌֚b; a◌〪◌̖◌᷿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, LATIN SMALL LETTER B -0061 1DFF 059A 0316 302A 0062;0061 302A 1DFF 0316 059A 0062;0061 302A 1DFF 0316 059A 0062;0061 302A 1DFF 0316 059A 0062;0061 302A 1DFF 0316 059A 0062; # (a◌᷿◌֚◌̖◌〪b; a◌〪◌᷿◌̖◌֚b; a◌〪◌᷿◌̖◌֚b; a◌〪◌᷿◌̖◌֚b; a◌〪◌᷿◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1DFF 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062;0061 1DFA 0316 1DFF 059A 0062; # (a◌֚◌̖◌᷺◌᷿b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; a◌᷺◌̖◌᷿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, LATIN SMALL LETTER B +0061 1DFF 059A 0316 1DFA 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062;0061 1DFA 1DFF 0316 059A 0062; # (a◌᷿◌֚◌̖◌᷺b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; a◌᷺◌᷿◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 20D0 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062;00E0 05AE 20D0 0315 0062;0061 05AE 0300 20D0 0315 0062; # (a◌̕◌̀◌֮◌⃐b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; à◌֮◌⃐◌̕b; a◌֮◌̀◌⃐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING LEFT HARPOON ABOVE, LATIN SMALL LETTER B 0061 20D0 0315 0300 05AE 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062;0061 05AE 20D0 0300 0315 0062; # (a◌⃐◌̕◌̀◌֮b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; a◌֮◌⃐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LEFT HARPOON ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 20D1 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062;00E0 05AE 20D1 0315 0062;0061 05AE 0300 20D1 0315 0062; # (a◌̕◌̀◌֮◌⃑b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; à◌֮◌⃑◌̕b; a◌֮◌̀◌⃑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING RIGHT HARPOON ABOVE, LATIN SMALL LETTER B @@ -18081,22 +18270,22 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 20E6 16FF0 0334 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062;0061 20E6 0334 16FF0 0062; # (a◌⃦𖿰◌̴b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; a◌⃦◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING DOUBLE VERTICAL STROKE OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 0315 0300 05AE 20E7 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062;00E0 05AE 20E7 0315 0062;0061 05AE 0300 20E7 0315 0062; # (a◌̕◌̀◌֮◌⃧b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; à◌֮◌⃧◌̕b; a◌֮◌̀◌⃧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ANNUITY SYMBOL, LATIN SMALL LETTER B 0061 20E7 0315 0300 05AE 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062;0061 05AE 20E7 0300 0315 0062; # (a◌⃧◌̕◌̀◌֮b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; a◌֮◌⃧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ANNUITY SYMBOL, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 20E8 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062;0061 302A 0316 20E8 059A 0062; # (a◌֚◌̖◌〪◌⃨b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; a◌〪◌̖◌⃨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TRIPLE UNDERDOT, LATIN SMALL LETTER B -0061 20E8 059A 0316 302A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062;0061 302A 20E8 0316 059A 0062; # (a◌⃨◌֚◌̖◌〪b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; a◌〪◌⃨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TRIPLE UNDERDOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20E8 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062;0061 1DFA 0316 20E8 059A 0062; # (a◌֚◌̖◌᷺◌⃨b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; a◌᷺◌̖◌⃨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TRIPLE UNDERDOT, LATIN SMALL LETTER B +0061 20E8 059A 0316 1DFA 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062;0061 1DFA 20E8 0316 059A 0062; # (a◌⃨◌֚◌̖◌᷺b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; a◌᷺◌⃨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TRIPLE UNDERDOT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 20E9 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062;00E0 05AE 20E9 0315 0062;0061 05AE 0300 20E9 0315 0062; # (a◌̕◌̀◌֮◌⃩b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; à◌֮◌⃩◌̕b; a◌֮◌̀◌⃩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING WIDE BRIDGE ABOVE, LATIN SMALL LETTER B 0061 20E9 0315 0300 05AE 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062;0061 05AE 20E9 0300 0315 0062; # (a◌⃩◌̕◌̀◌֮b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; a◌֮◌⃩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING WIDE BRIDGE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 16FF0 0334 20EA 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062;0061 0334 20EA 16FF0 0062; # (a𖿰◌̴◌⃪b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; a◌̴◌⃪𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LEFTWARDS ARROW OVERLAY, LATIN SMALL LETTER B 0061 20EA 16FF0 0334 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062;0061 20EA 0334 16FF0 0062; # (a◌⃪𖿰◌̴b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; a◌⃪◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS ARROW OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 20EB 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062;0061 0334 20EB 16FF0 0062; # (a𖿰◌̴◌⃫b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; a◌̴◌⃫𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, COMBINING LONG DOUBLE SOLIDUS OVERLAY, LATIN SMALL LETTER B 0061 20EB 16FF0 0334 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062;0061 20EB 0334 16FF0 0062; # (a◌⃫𖿰◌̴b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; a◌⃫◌̴𖿰b; ) LATIN SMALL LETTER A, COMBINING LONG DOUBLE SOLIDUS OVERLAY, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 059A 0316 302A 20EC 0062;0061 302A 0316 20EC 059A 0062;0061 302A 0316 20EC 059A 0062;0061 302A 0316 20EC 059A 0062;0061 302A 0316 20EC 059A 0062; # (a◌֚◌̖◌〪◌⃬b; a◌〪◌̖◌⃬◌֚b; a◌〪◌̖◌⃬◌֚b; a◌〪◌̖◌⃬◌֚b; a◌〪◌̖◌⃬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B -0061 20EC 059A 0316 302A 0062;0061 302A 20EC 0316 059A 0062;0061 302A 20EC 0316 059A 0062;0061 302A 20EC 0316 059A 0062;0061 302A 20EC 0316 059A 0062; # (a◌⃬◌֚◌̖◌〪b; a◌〪◌⃬◌̖◌֚b; a◌〪◌⃬◌̖◌֚b; a◌〪◌⃬◌̖◌֚b; a◌〪◌⃬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 20ED 0062;0061 302A 0316 20ED 059A 0062;0061 302A 0316 20ED 059A 0062;0061 302A 0316 20ED 059A 0062;0061 302A 0316 20ED 059A 0062; # (a◌֚◌̖◌〪◌⃭b; a◌〪◌̖◌⃭◌֚b; a◌〪◌̖◌⃭◌֚b; a◌〪◌̖◌⃭◌֚b; a◌〪◌̖◌⃭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B -0061 20ED 059A 0316 302A 0062;0061 302A 20ED 0316 059A 0062;0061 302A 20ED 0316 059A 0062;0061 302A 20ED 0316 059A 0062;0061 302A 20ED 0316 059A 0062; # (a◌⃭◌֚◌̖◌〪b; a◌〪◌⃭◌̖◌֚b; a◌〪◌⃭◌̖◌֚b; a◌〪◌⃭◌̖◌֚b; a◌〪◌⃭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 20EE 0062;0061 302A 0316 20EE 059A 0062;0061 302A 0316 20EE 059A 0062;0061 302A 0316 20EE 059A 0062;0061 302A 0316 20EE 059A 0062; # (a◌֚◌̖◌〪◌⃮b; a◌〪◌̖◌⃮◌֚b; a◌〪◌̖◌⃮◌֚b; a◌〪◌̖◌⃮◌֚b; a◌〪◌̖◌⃮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LEFT ARROW BELOW, LATIN SMALL LETTER B -0061 20EE 059A 0316 302A 0062;0061 302A 20EE 0316 059A 0062;0061 302A 20EE 0316 059A 0062;0061 302A 20EE 0316 059A 0062;0061 302A 20EE 0316 059A 0062; # (a◌⃮◌֚◌̖◌〪b; a◌〪◌⃮◌̖◌֚b; a◌〪◌⃮◌̖◌֚b; a◌〪◌⃮◌̖◌֚b; a◌〪◌⃮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 20EF 0062;0061 302A 0316 20EF 059A 0062;0061 302A 0316 20EF 059A 0062;0061 302A 0316 20EF 059A 0062;0061 302A 0316 20EF 059A 0062; # (a◌֚◌̖◌〪◌⃯b; a◌〪◌̖◌⃯◌֚b; a◌〪◌̖◌⃯◌֚b; a◌〪◌̖◌⃯◌֚b; a◌〪◌̖◌⃯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING RIGHT ARROW BELOW, LATIN SMALL LETTER B -0061 20EF 059A 0316 302A 0062;0061 302A 20EF 0316 059A 0062;0061 302A 20EF 0316 059A 0062;0061 302A 20EF 0316 059A 0062;0061 302A 20EF 0316 059A 0062; # (a◌⃯◌֚◌̖◌〪b; a◌〪◌⃯◌̖◌֚b; a◌〪◌⃯◌̖◌֚b; a◌〪◌⃯◌̖◌֚b; a◌〪◌⃯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EC 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062;0061 1DFA 0316 20EC 059A 0062; # (a◌֚◌̖◌᷺◌⃬b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; a◌᷺◌̖◌⃬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B +0061 20EC 059A 0316 1DFA 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062;0061 1DFA 20EC 0316 059A 0062; # (a◌⃬◌֚◌̖◌᷺b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; a◌᷺◌⃬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20ED 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062;0061 1DFA 0316 20ED 059A 0062; # (a◌֚◌̖◌᷺◌⃭b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; a◌᷺◌̖◌⃭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, LATIN SMALL LETTER B +0061 20ED 059A 0316 1DFA 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062;0061 1DFA 20ED 0316 059A 0062; # (a◌⃭◌֚◌̖◌᷺b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; a◌᷺◌⃭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EE 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062;0061 1DFA 0316 20EE 059A 0062; # (a◌֚◌̖◌᷺◌⃮b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; a◌᷺◌̖◌⃮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LEFT ARROW BELOW, LATIN SMALL LETTER B +0061 20EE 059A 0316 1DFA 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062;0061 1DFA 20EE 0316 059A 0062; # (a◌⃮◌֚◌̖◌᷺b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; a◌᷺◌⃮◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LEFT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 20EF 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062;0061 1DFA 0316 20EF 059A 0062; # (a◌֚◌̖◌᷺◌⃯b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; a◌᷺◌̖◌⃯◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING RIGHT ARROW BELOW, LATIN SMALL LETTER B +0061 20EF 059A 0316 1DFA 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062;0061 1DFA 20EF 0316 059A 0062; # (a◌⃯◌֚◌̖◌᷺b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; a◌᷺◌⃯◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING RIGHT ARROW BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 20F0 0062;00E0 05AE 20F0 0315 0062;0061 05AE 0300 20F0 0315 0062;00E0 05AE 20F0 0315 0062;0061 05AE 0300 20F0 0315 0062; # (a◌̕◌̀◌֮◌⃰b; à◌֮◌⃰◌̕b; a◌֮◌̀◌⃰◌̕b; à◌֮◌⃰◌̕b; a◌֮◌̀◌⃰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING ASTERISK ABOVE, LATIN SMALL LETTER B 0061 20F0 0315 0300 05AE 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062;0061 05AE 20F0 0300 0315 0062; # (a◌⃰◌̕◌̀◌֮b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; a◌֮◌⃰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING ASTERISK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 2CEF 0062;00E0 05AE 2CEF 0315 0062;0061 05AE 0300 2CEF 0315 0062;00E0 05AE 2CEF 0315 0062;0061 05AE 0300 2CEF 0315 0062; # (a◌̕◌̀◌֮◌⳯b; à◌֮◌⳯◌̕b; a◌֮◌̀◌⳯◌̕b; à◌֮◌⳯◌̕b; a◌֮◌̀◌⳯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COPTIC COMBINING NI ABOVE, LATIN SMALL LETTER B @@ -18171,8 +18360,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 2DFE 0315 0300 05AE 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062;0061 05AE 2DFE 0300 0315 0062; # (a◌ⷾ◌̕◌̀◌֮b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; a◌֮◌ⷾ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 2DFF 0062;00E0 05AE 2DFF 0315 0062;0061 05AE 0300 2DFF 0315 0062;00E0 05AE 2DFF 0315 0062;0061 05AE 0300 2DFF 0315 0062; # (a◌̕◌̀◌֮◌ⷿb; à◌֮◌ⷿ◌̕b; a◌֮◌̀◌ⷿ◌̕b; à◌֮◌ⷿ◌̕b; a◌֮◌̀◌ⷿ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IOTIFIED BIG YUS, LATIN SMALL LETTER B 0061 2DFF 0315 0300 05AE 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062;0061 05AE 2DFF 0300 0315 0062; # (a◌ⷿ◌̕◌̀◌֮b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; a◌֮◌ⷿ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IOTIFIED BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 0316 302A 031B 302A 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062; # (a◌̖◌〪◌̛◌〪b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 302A 0316 302A 031B 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062;0061 031B 302A 302A 0316 0062; # (a◌〪◌̖◌〪◌̛b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; a◌̛◌〪◌〪◌̖b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, LATIN SMALL LETTER B +0061 0316 1DFA 031B 302A 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062;0061 031B 1DFA 302A 0316 0062; # (a◌̖◌᷺◌̛◌〪b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; a◌̛◌᷺◌〪◌̖b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 302A 0316 1DFA 031B 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062;0061 031B 302A 1DFA 0316 0062; # (a◌〪◌̖◌᷺◌̛b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; a◌̛◌〪◌᷺◌̖b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING HORN, LATIN SMALL LETTER B 0061 0300 05AE 1D16D 302B 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062;00E0 1D16D 05AE 302B 0062;0061 1D16D 05AE 302B 0300 0062; # (a◌̀◌𝅭֮◌〫b; à𝅭◌֮◌〫b; a𝅭◌֮◌〫◌̀b; à𝅭◌֮◌〫b; a𝅭◌֮◌〫◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, IDEOGRAPHIC RISING TONE MARK, LATIN SMALL LETTER B 0061 302B 0300 05AE 1D16D 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062;00E0 1D16D 302B 05AE 0062;0061 1D16D 302B 05AE 0300 0062; # (a◌〫◌̀◌𝅭֮b; à𝅭◌〫◌֮b; a𝅭◌〫◌֮◌̀b; à𝅭◌〫◌֮b; a𝅭◌〫◌֮◌̀b; ) LATIN SMALL LETTER A, IDEOGRAPHIC RISING TONE MARK, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B 0061 035C 0315 0300 302C 0062;00E0 0315 302C 035C 0062;0061 0300 0315 302C 035C 0062;00E0 0315 302C 035C 0062;0061 0300 0315 302C 035C 0062; # (a◌͜◌̕◌̀◌〬b; à◌̕◌〬◌͜b; a◌̀◌̕◌〬◌͜b; à◌̕◌〬◌͜b; a◌̀◌̕◌〬◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, IDEOGRAPHIC DEPARTING TONE MARK, LATIN SMALL LETTER B @@ -18259,12 +18448,12 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 A8F0 0315 0300 05AE 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062;0061 05AE A8F0 0300 0315 0062; # (a◌꣰◌̕◌̀◌֮b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; a◌֮◌꣰◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI LETTER VI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE A8F1 0062;00E0 05AE A8F1 0315 0062;0061 05AE 0300 A8F1 0315 0062;00E0 05AE A8F1 0315 0062;0061 05AE 0300 A8F1 0315 0062; # (a◌̕◌̀◌֮◌꣱b; à◌֮◌꣱◌̕b; a◌֮◌̀◌꣱◌̕b; à◌֮◌꣱◌̕b; a◌֮◌̀◌꣱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DEVANAGARI SIGN AVAGRAHA, LATIN SMALL LETTER B 0061 A8F1 0315 0300 05AE 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062;0061 05AE A8F1 0300 0315 0062; # (a◌꣱◌̕◌̀◌֮b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; a◌֮◌꣱◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DEVANAGARI SIGN AVAGRAHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A A92B 0062;0061 302A 0316 A92B 059A 0062;0061 302A 0316 A92B 059A 0062;0061 302A 0316 A92B 059A 0062;0061 302A 0316 A92B 059A 0062; # (a◌֚◌̖◌〪◌꤫b; a◌〪◌̖◌꤫◌֚b; a◌〪◌̖◌꤫◌֚b; a◌〪◌̖◌꤫◌֚b; a◌〪◌̖◌꤫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, KAYAH LI TONE PLOPHU, LATIN SMALL LETTER B -0061 A92B 059A 0316 302A 0062;0061 302A A92B 0316 059A 0062;0061 302A A92B 0316 059A 0062;0061 302A A92B 0316 059A 0062;0061 302A A92B 0316 059A 0062; # (a◌꤫◌֚◌̖◌〪b; a◌〪◌꤫◌̖◌֚b; a◌〪◌꤫◌̖◌֚b; a◌〪◌꤫◌̖◌֚b; a◌〪◌꤫◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A A92C 0062;0061 302A 0316 A92C 059A 0062;0061 302A 0316 A92C 059A 0062;0061 302A 0316 A92C 059A 0062;0061 302A 0316 A92C 059A 0062; # (a◌֚◌̖◌〪◌꤬b; a◌〪◌̖◌꤬◌֚b; a◌〪◌̖◌꤬◌֚b; a◌〪◌̖◌꤬◌֚b; a◌〪◌̖◌꤬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, KAYAH LI TONE CALYA, LATIN SMALL LETTER B -0061 A92C 059A 0316 302A 0062;0061 302A A92C 0316 059A 0062;0061 302A A92C 0316 059A 0062;0061 302A A92C 0316 059A 0062;0061 302A A92C 0316 059A 0062; # (a◌꤬◌֚◌̖◌〪b; a◌〪◌꤬◌̖◌֚b; a◌〪◌꤬◌̖◌֚b; a◌〪◌꤬◌̖◌֚b; a◌〪◌꤬◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A A92D 0062;0061 302A 0316 A92D 059A 0062;0061 302A 0316 A92D 059A 0062;0061 302A 0316 A92D 059A 0062;0061 302A 0316 A92D 059A 0062; # (a◌֚◌̖◌〪◌꤭b; a◌〪◌̖◌꤭◌֚b; a◌〪◌̖◌꤭◌֚b; a◌〪◌̖◌꤭◌֚b; a◌〪◌̖◌꤭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, KAYAH LI TONE CALYA PLOPHU, LATIN SMALL LETTER B -0061 A92D 059A 0316 302A 0062;0061 302A A92D 0316 059A 0062;0061 302A A92D 0316 059A 0062;0061 302A A92D 0316 059A 0062;0061 302A A92D 0316 059A 0062; # (a◌꤭◌֚◌̖◌〪b; a◌〪◌꤭◌̖◌֚b; a◌〪◌꤭◌̖◌֚b; a◌〪◌꤭◌̖◌֚b; a◌〪◌꤭◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92B 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062;0061 1DFA 0316 A92B 059A 0062; # (a◌֚◌̖◌᷺◌꤫b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; a◌᷺◌̖◌꤫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE PLOPHU, LATIN SMALL LETTER B +0061 A92B 059A 0316 1DFA 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062;0061 1DFA A92B 0316 059A 0062; # (a◌꤫◌֚◌̖◌᷺b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; a◌᷺◌꤫◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92C 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062;0061 1DFA 0316 A92C 059A 0062; # (a◌֚◌̖◌᷺◌꤬b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; a◌᷺◌̖◌꤬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE CALYA, LATIN SMALL LETTER B +0061 A92C 059A 0316 1DFA 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062;0061 1DFA A92C 0316 059A 0062; # (a◌꤬◌֚◌̖◌᷺b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; a◌᷺◌꤬◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA A92D 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062;0061 1DFA 0316 A92D 059A 0062; # (a◌֚◌̖◌᷺◌꤭b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; a◌᷺◌̖◌꤭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KAYAH LI TONE CALYA PLOPHU, LATIN SMALL LETTER B +0061 A92D 059A 0316 1DFA 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062;0061 1DFA A92D 0316 059A 0062; # (a◌꤭◌֚◌̖◌᷺b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; a◌᷺◌꤭◌̖◌֚b; ) LATIN SMALL LETTER A, KAYAH LI TONE CALYA PLOPHU, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 05B0 094D 3099 A953 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062;0061 3099 094D A953 05B0 0062; # (a◌ְ◌्◌゙꥓b; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; a◌゙◌्꥓◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, REJANG VIRAMA, LATIN SMALL LETTER B 0061 A953 05B0 094D 3099 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062;0061 3099 A953 094D 05B0 0062; # (a꥓◌ְ◌्◌゙b; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; a◌゙꥓◌्◌ְb; ) LATIN SMALL LETTER A, REJANG VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 3099 093C 16FF0 A9B3 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062;0061 16FF0 093C A9B3 3099 0062; # (a◌゙◌𖿰़◌꦳b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; a𖿰◌़◌꦳◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, JAVANESE SIGN CECAK TELU, LATIN SMALL LETTER B @@ -18277,8 +18466,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 AAB2 0315 0300 05AE 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062;0061 05AE AAB2 0300 0315 0062; # (a◌ꪲ◌̕◌̀◌֮b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; a◌֮◌ꪲ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE AAB3 0062;00E0 05AE AAB3 0315 0062;0061 05AE 0300 AAB3 0315 0062;00E0 05AE AAB3 0315 0062;0061 05AE 0300 AAB3 0315 0062; # (a◌̕◌̀◌֮◌ꪳb; à◌֮◌ꪳ◌̕b; a◌֮◌̀◌ꪳ◌̕b; à◌֮◌ꪳ◌̕b; a◌֮◌̀◌ꪳ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL UE, LATIN SMALL LETTER B 0061 AAB3 0315 0300 05AE 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062;0061 05AE AAB3 0300 0315 0062; # (a◌ꪳ◌̕◌̀◌֮b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; a◌֮◌ꪳ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET VOWEL UE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A AAB4 0062;0061 302A 0316 AAB4 059A 0062;0061 302A 0316 AAB4 059A 0062;0061 302A 0316 AAB4 059A 0062;0061 302A 0316 AAB4 059A 0062; # (a◌֚◌̖◌〪◌ꪴb; a◌〪◌̖◌ꪴ◌֚b; a◌〪◌̖◌ꪴ◌֚b; a◌〪◌̖◌ꪴ◌֚b; a◌〪◌̖◌ꪴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, TAI VIET VOWEL U, LATIN SMALL LETTER B -0061 AAB4 059A 0316 302A 0062;0061 302A AAB4 0316 059A 0062;0061 302A AAB4 0316 059A 0062;0061 302A AAB4 0316 059A 0062;0061 302A AAB4 0316 059A 0062; # (a◌ꪴ◌֚◌̖◌〪b; a◌〪◌ꪴ◌̖◌֚b; a◌〪◌ꪴ◌̖◌֚b; a◌〪◌ꪴ◌̖◌֚b; a◌〪◌ꪴ◌̖◌֚b; ) LATIN SMALL LETTER A, TAI VIET VOWEL U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA AAB4 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062;0061 1DFA 0316 AAB4 059A 0062; # (a◌֚◌̖◌᷺◌ꪴb; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; a◌᷺◌̖◌ꪴ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, TAI VIET VOWEL U, LATIN SMALL LETTER B +0061 AAB4 059A 0316 1DFA 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062;0061 1DFA AAB4 0316 059A 0062; # (a◌ꪴ◌֚◌̖◌᷺b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; a◌᷺◌ꪴ◌̖◌֚b; ) LATIN SMALL LETTER A, TAI VIET VOWEL U, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE AAB7 0062;00E0 05AE AAB7 0315 0062;0061 05AE 0300 AAB7 0315 0062;00E0 05AE AAB7 0315 0062;0061 05AE 0300 AAB7 0315 0062; # (a◌̕◌̀◌֮◌ꪷb; à◌֮◌ꪷ◌̕b; a◌֮◌̀◌ꪷ◌̕b; à◌֮◌ꪷ◌̕b; a◌֮◌̀◌ꪷ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET MAI KHIT, LATIN SMALL LETTER B 0061 AAB7 0315 0300 05AE 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062;0061 05AE AAB7 0300 0315 0062; # (a◌ꪷ◌̕◌̀◌֮b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; a◌֮◌ꪷ◌̀◌̕b; ) LATIN SMALL LETTER A, TAI VIET MAI KHIT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE AAB8 0062;00E0 05AE AAB8 0315 0062;0061 05AE 0300 AAB8 0315 0062;00E0 05AE AAB8 0315 0062;0061 05AE 0300 AAB8 0315 0062; # (a◌̕◌̀◌֮◌ꪸb; à◌֮◌ꪸ◌̕b; a◌֮◌̀◌ꪸ◌̕b; à◌֮◌ꪸ◌̕b; a◌֮◌̀◌ꪸ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TAI VIET VOWEL IA, LATIN SMALL LETTER B @@ -18309,28 +18498,28 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 FE25 0315 0300 05AE 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062;0061 05AE FE25 0300 0315 0062; # (a◌︥◌̕◌̀◌֮b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; a◌֮◌︥◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE FE26 0062;00E0 05AE FE26 0315 0062;0061 05AE 0300 FE26 0315 0062;00E0 05AE FE26 0315 0062;0061 05AE 0300 FE26 0315 0062; # (a◌̕◌̀◌֮◌︦b; à◌֮◌︦◌̕b; a◌֮◌̀◌︦◌̕b; à◌֮◌︦◌̕b; a◌֮◌̀◌︦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CONJOINING MACRON, LATIN SMALL LETTER B 0061 FE26 0315 0300 05AE 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062;0061 05AE FE26 0300 0315 0062; # (a◌︦◌̕◌̀◌֮b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; a◌֮◌︦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A FE27 0062;0061 302A 0316 FE27 059A 0062;0061 302A 0316 FE27 059A 0062;0061 302A 0316 FE27 059A 0062;0061 302A 0316 FE27 059A 0062; # (a◌֚◌̖◌〪◌︧b; a◌〪◌̖◌︧◌֚b; a◌〪◌̖◌︧◌֚b; a◌〪◌̖◌︧◌֚b; a◌〪◌̖◌︧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LIGATURE LEFT HALF BELOW, LATIN SMALL LETTER B -0061 FE27 059A 0316 302A 0062;0061 302A FE27 0316 059A 0062;0061 302A FE27 0316 059A 0062;0061 302A FE27 0316 059A 0062;0061 302A FE27 0316 059A 0062; # (a◌︧◌֚◌̖◌〪b; a◌〪◌︧◌̖◌֚b; a◌〪◌︧◌̖◌֚b; a◌〪◌︧◌̖◌֚b; a◌〪◌︧◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE28 0062;0061 302A 0316 FE28 059A 0062;0061 302A 0316 FE28 059A 0062;0061 302A 0316 FE28 059A 0062;0061 302A 0316 FE28 059A 0062; # (a◌֚◌̖◌〪◌︨b; a◌〪◌̖◌︨◌֚b; a◌〪◌̖◌︨◌֚b; a◌〪◌̖◌︨◌֚b; a◌〪◌̖◌︨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING LIGATURE RIGHT HALF BELOW, LATIN SMALL LETTER B -0061 FE28 059A 0316 302A 0062;0061 302A FE28 0316 059A 0062;0061 302A FE28 0316 059A 0062;0061 302A FE28 0316 059A 0062;0061 302A FE28 0316 059A 0062; # (a◌︨◌֚◌̖◌〪b; a◌〪◌︨◌̖◌֚b; a◌〪◌︨◌̖◌֚b; a◌〪◌︨◌̖◌֚b; a◌〪◌︨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE29 0062;0061 302A 0316 FE29 059A 0062;0061 302A 0316 FE29 059A 0062;0061 302A 0316 FE29 059A 0062;0061 302A 0316 FE29 059A 0062; # (a◌֚◌̖◌〪◌︩b; a◌〪◌̖◌︩◌֚b; a◌〪◌̖◌︩◌֚b; a◌〪◌̖◌︩◌֚b; a◌〪◌̖◌︩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TILDE LEFT HALF BELOW, LATIN SMALL LETTER B -0061 FE29 059A 0316 302A 0062;0061 302A FE29 0316 059A 0062;0061 302A FE29 0316 059A 0062;0061 302A FE29 0316 059A 0062;0061 302A FE29 0316 059A 0062; # (a◌︩◌֚◌̖◌〪b; a◌〪◌︩◌̖◌֚b; a◌〪◌︩◌̖◌֚b; a◌〪◌︩◌̖◌֚b; a◌〪◌︩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE2A 0062;0061 302A 0316 FE2A 059A 0062;0061 302A 0316 FE2A 059A 0062;0061 302A 0316 FE2A 059A 0062;0061 302A 0316 FE2A 059A 0062; # (a◌֚◌̖◌〪◌︪b; a◌〪◌̖◌︪◌֚b; a◌〪◌̖◌︪◌֚b; a◌〪◌̖◌︪◌֚b; a◌〪◌̖◌︪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING TILDE RIGHT HALF BELOW, LATIN SMALL LETTER B -0061 FE2A 059A 0316 302A 0062;0061 302A FE2A 0316 059A 0062;0061 302A FE2A 0316 059A 0062;0061 302A FE2A 0316 059A 0062;0061 302A FE2A 0316 059A 0062; # (a◌︪◌֚◌̖◌〪b; a◌〪◌︪◌̖◌֚b; a◌〪◌︪◌̖◌֚b; a◌〪◌︪◌̖◌֚b; a◌〪◌︪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE2B 0062;0061 302A 0316 FE2B 059A 0062;0061 302A 0316 FE2B 059A 0062;0061 302A 0316 FE2B 059A 0062;0061 302A 0316 FE2B 059A 0062; # (a◌֚◌̖◌〪◌︫b; a◌〪◌̖◌︫◌֚b; a◌〪◌̖◌︫◌֚b; a◌〪◌̖◌︫◌֚b; a◌〪◌̖◌︫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MACRON LEFT HALF BELOW, LATIN SMALL LETTER B -0061 FE2B 059A 0316 302A 0062;0061 302A FE2B 0316 059A 0062;0061 302A FE2B 0316 059A 0062;0061 302A FE2B 0316 059A 0062;0061 302A FE2B 0316 059A 0062; # (a◌︫◌֚◌̖◌〪b; a◌〪◌︫◌̖◌֚b; a◌〪◌︫◌̖◌֚b; a◌〪◌︫◌̖◌֚b; a◌〪◌︫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE2C 0062;0061 302A 0316 FE2C 059A 0062;0061 302A 0316 FE2C 059A 0062;0061 302A 0316 FE2C 059A 0062;0061 302A 0316 FE2C 059A 0062; # (a◌֚◌̖◌〪◌︬b; a◌〪◌̖◌︬◌֚b; a◌〪◌̖◌︬◌֚b; a◌〪◌̖◌︬◌֚b; a◌〪◌̖◌︬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING MACRON RIGHT HALF BELOW, LATIN SMALL LETTER B -0061 FE2C 059A 0316 302A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062; # (a◌︬◌֚◌̖◌〪b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A FE2D 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062; # (a◌֚◌̖◌〪◌︭b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CONJOINING MACRON BELOW, LATIN SMALL LETTER B -0061 FE2D 059A 0316 302A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062; # (a◌︭◌֚◌̖◌〪b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE27 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062;0061 1DFA 0316 FE27 059A 0062; # (a◌֚◌̖◌᷺◌︧b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; a◌᷺◌̖◌︧◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGATURE LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE27 059A 0316 1DFA 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062;0061 1DFA FE27 0316 059A 0062; # (a◌︧◌֚◌̖◌᷺b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; a◌᷺◌︧◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE28 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062;0061 1DFA 0316 FE28 059A 0062; # (a◌֚◌̖◌᷺◌︨b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; a◌᷺◌̖◌︨◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING LIGATURE RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE28 059A 0316 1DFA 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062;0061 1DFA FE28 0316 059A 0062; # (a◌︨◌֚◌̖◌᷺b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; a◌᷺◌︨◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING LIGATURE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE29 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062;0061 1DFA 0316 FE29 059A 0062; # (a◌֚◌̖◌᷺◌︩b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; a◌᷺◌̖◌︩◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE29 059A 0316 1DFA 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062;0061 1DFA FE29 0316 059A 0062; # (a◌︩◌֚◌̖◌᷺b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; a◌᷺◌︩◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062;0061 1DFA 0316 FE2A 059A 0062; # (a◌֚◌̖◌᷺◌︪b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; a◌᷺◌̖◌︪◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING TILDE RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE2A 059A 0316 1DFA 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062;0061 1DFA FE2A 0316 059A 0062; # (a◌︪◌֚◌̖◌᷺b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; a◌᷺◌︪◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING TILDE RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2B 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062;0061 1DFA 0316 FE2B 059A 0062; # (a◌֚◌̖◌᷺◌︫b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; a◌᷺◌̖◌︫◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON LEFT HALF BELOW, LATIN SMALL LETTER B +0061 FE2B 059A 0316 1DFA 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062;0061 1DFA FE2B 0316 059A 0062; # (a◌︫◌֚◌̖◌᷺b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; a◌᷺◌︫◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON LEFT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2C 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062;0061 1DFA 0316 FE2C 059A 0062; # (a◌֚◌̖◌᷺◌︬b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; a◌᷺◌̖◌︬◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING MACRON RIGHT HALF BELOW, LATIN SMALL LETTER B +0061 FE2C 059A 0316 1DFA 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062;0061 1DFA FE2C 0316 059A 0062; # (a◌︬◌֚◌̖◌᷺b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; a◌᷺◌︬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA FE2D 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062;0061 1DFA 0316 FE2D 059A 0062; # (a◌֚◌̖◌᷺◌︭b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; a◌᷺◌̖◌︭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COMBINING CONJOINING MACRON BELOW, LATIN SMALL LETTER B +0061 FE2D 059A 0316 1DFA 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062;0061 1DFA FE2D 0316 059A 0062; # (a◌︭◌֚◌̖◌᷺b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; a◌᷺◌︭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE FE2E 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062; # (a◌̕◌̀◌֮◌︮b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO LEFT HALF, LATIN SMALL LETTER B 0061 FE2E 0315 0300 05AE 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062; # (a◌︮◌̕◌̀◌֮b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE FE2F 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062; # (a◌̕◌̀◌֮◌︯b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO RIGHT HALF, LATIN SMALL LETTER B 0061 FE2F 0315 0300 05AE 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062; # (a◌︯◌̕◌̀◌֮b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 101FD 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062; # (a◌֚◌̖◌〪◌𐇽b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, LATIN SMALL LETTER B -0061 101FD 059A 0316 302A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062; # (a◌𐇽◌֚◌̖◌〪b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; ) LATIN SMALL LETTER A, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 102E0 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062; # (a◌֚◌̖◌〪◌𐋠b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COPTIC EPACT THOUSANDS MARK, LATIN SMALL LETTER B -0061 102E0 059A 0316 302A 0062;0061 302A 102E0 0316 059A 0062;0061 302A 102E0 0316 059A 0062;0061 302A 102E0 0316 059A 0062;0061 302A 102E0 0316 059A 0062; # (a◌𐋠◌֚◌̖◌〪b; a◌〪◌𐋠◌̖◌֚b; a◌〪◌𐋠◌̖◌֚b; a◌〪◌𐋠◌̖◌֚b; a◌〪◌𐋠◌̖◌֚b; ) LATIN SMALL LETTER A, COPTIC EPACT THOUSANDS MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 101FD 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062;0061 1DFA 0316 101FD 059A 0062; # (a◌֚◌̖◌᷺◌𐇽b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; a◌᷺◌̖◌𐇽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, LATIN SMALL LETTER B +0061 101FD 059A 0316 1DFA 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062;0061 1DFA 101FD 0316 059A 0062; # (a◌𐇽◌֚◌̖◌᷺b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; a◌᷺◌𐇽◌̖◌֚b; ) LATIN SMALL LETTER A, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 102E0 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062;0061 1DFA 0316 102E0 059A 0062; # (a◌֚◌̖◌᷺◌𐋠b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; a◌᷺◌̖◌𐋠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, COPTIC EPACT THOUSANDS MARK, LATIN SMALL LETTER B +0061 102E0 059A 0316 1DFA 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062;0061 1DFA 102E0 0316 059A 0062; # (a◌𐋠◌֚◌̖◌᷺b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; a◌᷺◌𐋠◌̖◌֚b; ) LATIN SMALL LETTER A, COPTIC EPACT THOUSANDS MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 10376 0062;00E0 05AE 10376 0315 0062;0061 05AE 0300 10376 0315 0062;00E0 05AE 10376 0315 0062;0061 05AE 0300 10376 0315 0062; # (a◌̕◌̀◌֮◌𐍶b; à◌֮◌𐍶◌̕b; a◌֮◌̀◌𐍶◌̕b; à◌֮◌𐍶◌̕b; a◌֮◌̀◌𐍶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER AN, LATIN SMALL LETTER B 0061 10376 0315 0300 05AE 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062;0061 05AE 10376 0300 0315 0062; # (a◌𐍶◌̕◌̀◌֮b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; a◌֮◌𐍶◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER AN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10377 0062;00E0 05AE 10377 0315 0062;0061 05AE 0300 10377 0315 0062;00E0 05AE 10377 0315 0062;0061 05AE 0300 10377 0315 0062; # (a◌̕◌̀◌֮◌𐍷b; à◌֮◌𐍷◌̕b; a◌֮◌̀◌𐍷◌̕b; à◌֮◌𐍷◌̕b; a◌֮◌̀◌𐍷◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER DOI, LATIN SMALL LETTER B @@ -18341,22 +18530,22 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 10379 0315 0300 05AE 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062;0061 05AE 10379 0300 0315 0062; # (a◌𐍹◌̕◌̀◌֮b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; a◌֮◌𐍹◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER NENOE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1037A 0062;00E0 05AE 1037A 0315 0062;0061 05AE 0300 1037A 0315 0062;00E0 05AE 1037A 0315 0062;0061 05AE 0300 1037A 0315 0062; # (a◌̕◌̀◌֮◌𐍺b; à◌֮◌𐍺◌̕b; a◌֮◌̀◌𐍺◌̕b; à◌֮◌𐍺◌̕b; a◌֮◌̀◌𐍺◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING OLD PERMIC LETTER SII, LATIN SMALL LETTER B 0061 1037A 0315 0300 05AE 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062;0061 05AE 1037A 0300 0315 0062; # (a◌𐍺◌̕◌̀◌֮b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; a◌֮◌𐍺◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING OLD PERMIC LETTER SII, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 10A0D 0062;0061 302A 0316 10A0D 059A 0062;0061 302A 0316 10A0D 059A 0062;0061 302A 0316 10A0D 059A 0062;0061 302A 0316 10A0D 059A 0062; # (a◌֚◌̖◌〪◌𐨍b; a◌〪◌̖◌𐨍◌֚b; a◌〪◌̖◌𐨍◌֚b; a◌〪◌̖◌𐨍◌֚b; a◌〪◌̖◌𐨍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, KHAROSHTHI SIGN DOUBLE RING BELOW, LATIN SMALL LETTER B -0061 10A0D 059A 0316 302A 0062;0061 302A 10A0D 0316 059A 0062;0061 302A 10A0D 0316 059A 0062;0061 302A 10A0D 0316 059A 0062;0061 302A 10A0D 0316 059A 0062; # (a◌𐨍◌֚◌̖◌〪b; a◌〪◌𐨍◌̖◌֚b; a◌〪◌𐨍◌̖◌֚b; a◌〪◌𐨍◌̖◌֚b; a◌〪◌𐨍◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10A0D 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062;0061 1DFA 0316 10A0D 059A 0062; # (a◌֚◌̖◌᷺◌𐨍b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; a◌᷺◌̖◌𐨍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KHAROSHTHI SIGN DOUBLE RING BELOW, LATIN SMALL LETTER B +0061 10A0D 059A 0316 1DFA 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062;0061 1DFA 10A0D 0316 059A 0062; # (a◌𐨍◌֚◌̖◌᷺b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; a◌᷺◌𐨍◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOUBLE RING BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 10A0F 0062;00E0 05AE 10A0F 0315 0062;0061 05AE 0300 10A0F 0315 0062;00E0 05AE 10A0F 0315 0062;0061 05AE 0300 10A0F 0315 0062; # (a◌̕◌̀◌֮◌𐨏b; à◌֮◌𐨏◌̕b; a◌֮◌̀◌𐨏◌̕b; à◌֮◌𐨏◌̕b; a◌֮◌̀◌𐨏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHAROSHTHI SIGN VISARGA, LATIN SMALL LETTER B 0061 10A0F 0315 0300 05AE 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062;0061 05AE 10A0F 0300 0315 0062; # (a◌𐨏◌̕◌̀◌֮b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; a◌֮◌𐨏◌̀◌̕b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN VISARGA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10A38 0062;00E0 05AE 10A38 0315 0062;0061 05AE 0300 10A38 0315 0062;00E0 05AE 10A38 0315 0062;0061 05AE 0300 10A38 0315 0062; # (a◌̕◌̀◌֮◌𐨸b; à◌֮◌𐨸◌̕b; a◌֮◌̀◌𐨸◌̕b; à◌֮◌𐨸◌̕b; a◌֮◌̀◌𐨸◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, KHAROSHTHI SIGN BAR ABOVE, LATIN SMALL LETTER B 0061 10A38 0315 0300 05AE 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062;0061 05AE 10A38 0300 0315 0062; # (a◌𐨸◌̕◌̀◌֮b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; a◌֮◌𐨸◌̀◌̕b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN BAR ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 16FF0 0334 10A39 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062;0061 0334 10A39 16FF0 0062; # (a𖿰◌̴◌𐨹b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; a◌̴◌𐨹𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, KHAROSHTHI SIGN CAUDA, LATIN SMALL LETTER B 0061 10A39 16FF0 0334 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062;0061 10A39 0334 16FF0 0062; # (a◌𐨹𖿰◌̴b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; a◌𐨹◌̴𖿰b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN CAUDA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 059A 0316 302A 10A3A 0062;0061 302A 0316 10A3A 059A 0062;0061 302A 0316 10A3A 059A 0062;0061 302A 0316 10A3A 059A 0062;0061 302A 0316 10A3A 059A 0062; # (a◌֚◌̖◌〪◌𐨺b; a◌〪◌̖◌𐨺◌֚b; a◌〪◌̖◌𐨺◌֚b; a◌〪◌̖◌𐨺◌֚b; a◌〪◌̖◌𐨺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, KHAROSHTHI SIGN DOT BELOW, LATIN SMALL LETTER B -0061 10A3A 059A 0316 302A 0062;0061 302A 10A3A 0316 059A 0062;0061 302A 10A3A 0316 059A 0062;0061 302A 10A3A 0316 059A 0062;0061 302A 10A3A 0316 059A 0062; # (a◌𐨺◌֚◌̖◌〪b; a◌〪◌𐨺◌̖◌֚b; a◌〪◌𐨺◌̖◌֚b; a◌〪◌𐨺◌̖◌֚b; a◌〪◌𐨺◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10A3A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062;0061 1DFA 0316 10A3A 059A 0062; # (a◌֚◌̖◌᷺◌𐨺b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; a◌᷺◌̖◌𐨺◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, KHAROSHTHI SIGN DOT BELOW, LATIN SMALL LETTER B +0061 10A3A 059A 0316 1DFA 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062;0061 1DFA 10A3A 0316 059A 0062; # (a◌𐨺◌֚◌̖◌᷺b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; a◌᷺◌𐨺◌̖◌֚b; ) LATIN SMALL LETTER A, KHAROSHTHI SIGN DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 05B0 094D 3099 10A3F 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062;0061 3099 094D 10A3F 05B0 0062; # (a◌ְ◌्◌゙◌𐨿b; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; a◌゙◌्◌𐨿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHAROSHTHI VIRAMA, LATIN SMALL LETTER B 0061 10A3F 05B0 094D 3099 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062;0061 3099 10A3F 094D 05B0 0062; # (a◌𐨿◌ְ◌्◌゙b; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; a◌゙◌𐨿◌्◌ְb; ) LATIN SMALL LETTER A, KHAROSHTHI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 10AE5 0062;00E0 05AE 10AE5 0315 0062;0061 05AE 0300 10AE5 0315 0062;00E0 05AE 10AE5 0315 0062;0061 05AE 0300 10AE5 0315 0062; # (a◌̕◌̀◌֮◌𐫥b; à◌֮◌𐫥◌̕b; a◌֮◌̀◌𐫥◌̕b; à◌֮◌𐫥◌̕b; a◌֮◌̀◌𐫥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MANICHAEAN ABBREVIATION MARK ABOVE, LATIN SMALL LETTER B 0061 10AE5 0315 0300 05AE 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062; # (a◌𐫥◌̕◌̀◌֮b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 10AE6 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062; # (a◌֚◌̖◌〪◌𐫦b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANICHAEAN ABBREVIATION MARK BELOW, LATIN SMALL LETTER B -0061 10AE6 059A 0316 302A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062; # (a◌𐫦◌֚◌̖◌〪b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10AE6 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062;0061 1DFA 0316 10AE6 059A 0062; # (a◌֚◌̖◌᷺◌𐫦b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; a◌᷺◌̖◌𐫦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MANICHAEAN ABBREVIATION MARK BELOW, LATIN SMALL LETTER B +0061 10AE6 059A 0316 1DFA 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062;0061 1DFA 10AE6 0316 059A 0062; # (a◌𐫦◌֚◌̖◌᷺b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; a◌᷺◌𐫦◌̖◌֚b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 10D24 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062; # (a◌̕◌̀◌֮◌𐴤b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN HARBAHAY, LATIN SMALL LETTER B 0061 10D24 0315 0300 05AE 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062; # (a◌𐴤◌̕◌̀◌֮b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN HARBAHAY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10D25 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062; # (a◌̕◌̀◌֮◌𐴥b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TAHALA, LATIN SMALL LETTER B @@ -18369,30 +18558,46 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 10EAB 0315 0300 05AE 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062;0061 05AE 10EAB 0300 0315 0062; # (a◌𐺫◌̕◌̀◌֮b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; a◌֮◌𐺫◌̀◌̕b; ) LATIN SMALL LETTER A, YEZIDI COMBINING HAMZA MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10EAC 0062;00E0 05AE 10EAC 0315 0062;0061 05AE 0300 10EAC 0315 0062;00E0 05AE 10EAC 0315 0062;0061 05AE 0300 10EAC 0315 0062; # (a◌̕◌̀◌֮◌𐺬b; à◌֮◌𐺬◌̕b; a◌֮◌̀◌𐺬◌̕b; à◌֮◌𐺬◌̕b; a◌֮◌̀◌𐺬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, YEZIDI COMBINING MADDA MARK, LATIN SMALL LETTER B 0061 10EAC 0315 0300 05AE 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062;0061 05AE 10EAC 0300 0315 0062; # (a◌𐺬◌̕◌̀◌֮b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; a◌֮◌𐺬◌̀◌̕b; ) LATIN SMALL LETTER A, YEZIDI COMBINING MADDA MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 10F46 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062; # (a◌֚◌̖◌〪◌𐽆b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING DOT BELOW, LATIN SMALL LETTER B -0061 10F46 059A 0316 302A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062; # (a◌𐽆◌֚◌̖◌〪b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 10F47 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062; # (a◌֚◌̖◌〪◌𐽇b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B -0061 10F47 059A 0316 302A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062; # (a◌𐽇◌֚◌̖◌〪b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10EFD 0062;0061 1DFA 0316 10EFD 059A 0062;0061 1DFA 0316 10EFD 059A 0062;0061 1DFA 0316 10EFD 059A 0062;0061 1DFA 0316 10EFD 059A 0062; # (a◌֚◌̖◌᷺◌𐻽b; a◌᷺◌̖◌𐻽◌֚b; a◌᷺◌̖◌𐻽◌֚b; a◌᷺◌̖◌𐻽◌֚b; a◌᷺◌̖◌𐻽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD SAKTA, LATIN SMALL LETTER B +0061 10EFD 059A 0316 1DFA 0062;0061 1DFA 10EFD 0316 059A 0062;0061 1DFA 10EFD 0316 059A 0062;0061 1DFA 10EFD 0316 059A 0062;0061 1DFA 10EFD 0316 059A 0062; # (a◌𐻽◌֚◌̖◌᷺b; a◌᷺◌𐻽◌̖◌֚b; a◌᷺◌𐻽◌̖◌֚b; a◌᷺◌𐻽◌̖◌֚b; a◌᷺◌𐻽◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD SAKTA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10EFE 0062;0061 1DFA 0316 10EFE 059A 0062;0061 1DFA 0316 10EFE 059A 0062;0061 1DFA 0316 10EFE 059A 0062;0061 1DFA 0316 10EFE 059A 0062; # (a◌֚◌̖◌᷺◌𐻾b; a◌᷺◌̖◌𐻾◌֚b; a◌᷺◌̖◌𐻾◌֚b; a◌᷺◌̖◌𐻾◌֚b; a◌᷺◌̖◌𐻾◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD QASR, LATIN SMALL LETTER B +0061 10EFE 059A 0316 1DFA 0062;0061 1DFA 10EFE 0316 059A 0062;0061 1DFA 10EFE 0316 059A 0062;0061 1DFA 10EFE 0316 059A 0062;0061 1DFA 10EFE 0316 059A 0062; # (a◌𐻾◌֚◌̖◌᷺b; a◌᷺◌𐻾◌̖◌֚b; a◌᷺◌𐻾◌̖◌֚b; a◌᷺◌𐻾◌̖◌֚b; a◌᷺◌𐻾◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD QASR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10EFF 0062;0061 1DFA 0316 10EFF 059A 0062;0061 1DFA 0316 10EFF 059A 0062;0061 1DFA 0316 10EFF 059A 0062;0061 1DFA 0316 10EFF 059A 0062; # (a◌֚◌̖◌᷺◌𐻿b; a◌᷺◌̖◌𐻿◌֚b; a◌᷺◌̖◌𐻿◌֚b; a◌᷺◌̖◌𐻿◌֚b; a◌᷺◌̖◌𐻿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, ARABIC SMALL LOW WORD MADDA, LATIN SMALL LETTER B +0061 10EFF 059A 0316 1DFA 0062;0061 1DFA 10EFF 0316 059A 0062;0061 1DFA 10EFF 0316 059A 0062;0061 1DFA 10EFF 0316 059A 0062;0061 1DFA 10EFF 0316 059A 0062; # (a◌𐻿◌֚◌̖◌᷺b; a◌᷺◌𐻿◌̖◌֚b; a◌᷺◌𐻿◌̖◌֚b; a◌᷺◌𐻿◌̖◌֚b; a◌᷺◌𐻿◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WORD MADDA, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F46 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062;0061 1DFA 0316 10F46 059A 0062; # (a◌֚◌̖◌᷺◌𐽆b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; a◌᷺◌̖◌𐽆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 10F46 059A 0316 1DFA 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062;0061 1DFA 10F46 0316 059A 0062; # (a◌𐽆◌֚◌̖◌᷺b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; a◌᷺◌𐽆◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F47 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062;0061 1DFA 0316 10F47 059A 0062; # (a◌֚◌̖◌᷺◌𐽇b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; a◌᷺◌̖◌𐽇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B +0061 10F47 059A 0316 1DFA 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062;0061 1DFA 10F47 0316 059A 0062; # (a◌𐽇◌֚◌̖◌᷺b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; a◌᷺◌𐽇◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 10F48 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062; # (a◌̕◌̀◌֮◌𐽈b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING DOT ABOVE, LATIN SMALL LETTER B 0061 10F48 0315 0300 05AE 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062; # (a◌𐽈◌̕◌̀◌֮b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10F49 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062; # (a◌̕◌̀◌֮◌𐽉b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B 0061 10F49 0315 0300 05AE 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062; # (a◌𐽉◌̕◌̀◌֮b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 10F4A 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062; # (a◌̕◌̀◌֮◌𐽊b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING CURVE ABOVE, LATIN SMALL LETTER B 0061 10F4A 0315 0300 05AE 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062; # (a◌𐽊◌̕◌̀◌֮b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 10F4B 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062; # (a◌֚◌̖◌〪◌𐽋b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING CURVE BELOW, LATIN SMALL LETTER B -0061 10F4B 059A 0316 302A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062; # (a◌𐽋◌֚◌̖◌〪b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4B 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062;0061 1DFA 0316 10F4B 059A 0062; # (a◌֚◌̖◌᷺◌𐽋b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; a◌᷺◌̖◌𐽋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING CURVE BELOW, LATIN SMALL LETTER B +0061 10F4B 059A 0316 1DFA 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062;0061 1DFA 10F4B 0316 059A 0062; # (a◌𐽋◌֚◌̖◌᷺b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; a◌᷺◌𐽋◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 10F4C 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062; # (a◌̕◌̀◌֮◌𐽌b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING HOOK ABOVE, LATIN SMALL LETTER B 0061 10F4C 0315 0300 05AE 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062; # (a◌𐽌◌̕◌̀◌֮b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 10F4D 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062; # (a◌֚◌̖◌〪◌𐽍b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING HOOK BELOW, LATIN SMALL LETTER B -0061 10F4D 059A 0316 302A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062; # (a◌𐽍◌֚◌̖◌〪b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 10F4E 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062; # (a◌֚◌̖◌〪◌𐽎b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING LONG HOOK BELOW, LATIN SMALL LETTER B -0061 10F4E 059A 0316 302A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062; # (a◌𐽎◌֚◌̖◌〪b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING LONG HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 10F4F 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062; # (a◌֚◌̖◌〪◌𐽏b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING RESH BELOW, LATIN SMALL LETTER B -0061 10F4F 059A 0316 302A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062; # (a◌𐽏◌֚◌̖◌〪b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING RESH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 10F50 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062; # (a◌֚◌̖◌〪◌𐽐b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING STROKE BELOW, LATIN SMALL LETTER B -0061 10F50 059A 0316 302A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062; # (a◌𐽐◌֚◌̖◌〪b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4D 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062;0061 1DFA 0316 10F4D 059A 0062; # (a◌֚◌̖◌᷺◌𐽍b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; a◌᷺◌̖◌𐽍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING HOOK BELOW, LATIN SMALL LETTER B +0061 10F4D 059A 0316 1DFA 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062;0061 1DFA 10F4D 0316 059A 0062; # (a◌𐽍◌֚◌̖◌᷺b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; a◌᷺◌𐽍◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4E 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062;0061 1DFA 0316 10F4E 059A 0062; # (a◌֚◌̖◌᷺◌𐽎b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; a◌᷺◌̖◌𐽎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING LONG HOOK BELOW, LATIN SMALL LETTER B +0061 10F4E 059A 0316 1DFA 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062;0061 1DFA 10F4E 0316 059A 0062; # (a◌𐽎◌֚◌̖◌᷺b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; a◌᷺◌𐽎◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING LONG HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F4F 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062;0061 1DFA 0316 10F4F 059A 0062; # (a◌֚◌̖◌᷺◌𐽏b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; a◌᷺◌̖◌𐽏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING RESH BELOW, LATIN SMALL LETTER B +0061 10F4F 059A 0316 1DFA 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062;0061 1DFA 10F4F 0316 059A 0062; # (a◌𐽏◌֚◌̖◌᷺b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; a◌᷺◌𐽏◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING RESH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F50 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062;0061 1DFA 0316 10F50 059A 0062; # (a◌֚◌̖◌᷺◌𐽐b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; a◌᷺◌̖◌𐽐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, SOGDIAN COMBINING STROKE BELOW, LATIN SMALL LETTER B +0061 10F50 059A 0316 1DFA 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062;0061 1DFA 10F50 0316 059A 0062; # (a◌𐽐◌֚◌̖◌᷺b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; a◌᷺◌𐽐◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F82 0062;00E0 05AE 10F82 0315 0062;0061 05AE 0300 10F82 0315 0062;00E0 05AE 10F82 0315 0062;0061 05AE 0300 10F82 0315 0062; # (a◌̕◌̀◌֮◌𐾂b; à◌֮◌𐾂◌̕b; a◌֮◌̀◌𐾂◌̕b; à◌֮◌𐾂◌̕b; a◌֮◌̀◌𐾂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, OLD UYGHUR COMBINING DOT ABOVE, LATIN SMALL LETTER B +0061 10F82 0315 0300 05AE 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062;0061 05AE 10F82 0300 0315 0062; # (a◌𐾂◌̕◌̀◌֮b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; a◌֮◌𐾂◌̀◌̕b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F83 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062;0061 1DFA 0316 10F83 059A 0062; # (a◌֚◌̖◌᷺◌𐾃b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; a◌᷺◌̖◌𐾃◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, OLD UYGHUR COMBINING DOT BELOW, LATIN SMALL LETTER B +0061 10F83 059A 0316 1DFA 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062;0061 1DFA 10F83 0316 059A 0062; # (a◌𐾃◌֚◌̖◌᷺b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; a◌᷺◌𐾃◌̖◌֚b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 10F84 0062;00E0 05AE 10F84 0315 0062;0061 05AE 0300 10F84 0315 0062;00E0 05AE 10F84 0315 0062;0061 05AE 0300 10F84 0315 0062; # (a◌̕◌̀◌֮◌𐾄b; à◌֮◌𐾄◌̕b; a◌֮◌̀◌𐾄◌̕b; à◌֮◌𐾄◌̕b; a◌֮◌̀◌𐾄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, OLD UYGHUR COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B +0061 10F84 0315 0300 05AE 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062;0061 05AE 10F84 0300 0315 0062; # (a◌𐾄◌̕◌̀◌֮b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; a◌֮◌𐾄◌̀◌̕b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 10F85 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062;0061 1DFA 0316 10F85 059A 0062; # (a◌֚◌̖◌᷺◌𐾅b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; a◌᷺◌̖◌𐾅◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, OLD UYGHUR COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B +0061 10F85 059A 0316 1DFA 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062;0061 1DFA 10F85 0316 059A 0062; # (a◌𐾅◌֚◌̖◌᷺b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; a◌᷺◌𐾅◌̖◌֚b; ) LATIN SMALL LETTER A, OLD UYGHUR COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 05B0 094D 3099 11046 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062; # (a◌ְ◌्◌゙◌𑁆b; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI VIRAMA, LATIN SMALL LETTER B 0061 11046 05B0 094D 3099 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062; # (a◌𑁆◌ְ◌्◌゙b; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11070 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062;0061 3099 094D 11070 05B0 0062; # (a◌ְ◌्◌゙◌𑁰b; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; a◌゙◌्◌𑁰◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI SIGN OLD TAMIL VIRAMA, LATIN SMALL LETTER B +0061 11070 05B0 094D 3099 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062;0061 3099 11070 094D 05B0 0062; # (a◌𑁰◌ְ◌्◌゙b; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; a◌゙◌𑁰◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI SIGN OLD TAMIL VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 1107F 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062; # (a◌ְ◌्◌゙◌𑁿b; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI NUMBER JOINER, LATIN SMALL LETTER B 0061 1107F 05B0 094D 3099 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062;0061 3099 1107F 094D 05B0 0062; # (a◌𑁿◌ְ◌्◌゙b; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; a◌゙◌𑁿◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI NUMBER JOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 110B9 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062;0061 3099 094D 110B9 05B0 0062; # (a◌ְ◌्◌゙◌𑂹b; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; a◌゙◌्◌𑂹◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KAITHI SIGN VIRAMA, LATIN SMALL LETTER B @@ -18503,6 +18708,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 11D45 05B0 094D 3099 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062; # (a◌𑵅◌ְ◌्◌゙b; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 11D97 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062; # (a◌ְ◌्◌゙◌𑶗b; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUNJALA GONDI VIRAMA, LATIN SMALL LETTER B 0061 11D97 05B0 094D 3099 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062; # (a◌𑶗◌ְ◌्◌゙b; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; ) LATIN SMALL LETTER A, GUNJALA GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11F41 0062;0061 3099 094D 11F41 05B0 0062;0061 3099 094D 11F41 05B0 0062;0061 3099 094D 11F41 05B0 0062;0061 3099 094D 11F41 05B0 0062; # (a◌ְ◌्◌゙𑽁b; a◌゙◌्𑽁◌ְb; a◌゙◌्𑽁◌ְb; a◌゙◌्𑽁◌ְb; a◌゙◌्𑽁◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KAWI SIGN KILLER, LATIN SMALL LETTER B +0061 11F41 05B0 094D 3099 0062;0061 3099 11F41 094D 05B0 0062;0061 3099 11F41 094D 05B0 0062;0061 3099 11F41 094D 05B0 0062;0061 3099 11F41 094D 05B0 0062; # (a𑽁◌ְ◌्◌゙b; a◌゙𑽁◌्◌ְb; a◌゙𑽁◌्◌ְb; a◌゙𑽁◌्◌ְb; a◌゙𑽁◌्◌ְb; ) LATIN SMALL LETTER A, KAWI SIGN KILLER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11F42 0062;0061 3099 094D 11F42 05B0 0062;0061 3099 094D 11F42 05B0 0062;0061 3099 094D 11F42 05B0 0062;0061 3099 094D 11F42 05B0 0062; # (a◌ְ◌्◌゙◌𑽂b; a◌゙◌्◌𑽂◌ְb; a◌゙◌्◌𑽂◌ְb; a◌゙◌्◌𑽂◌ְb; a◌゙◌्◌𑽂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KAWI CONJOINER, LATIN SMALL LETTER B +0061 11F42 05B0 094D 3099 0062;0061 3099 11F42 094D 05B0 0062;0061 3099 11F42 094D 05B0 0062;0061 3099 11F42 094D 05B0 0062;0061 3099 11F42 094D 05B0 0062; # (a◌𑽂◌ְ◌्◌゙b; a◌゙◌𑽂◌्◌ְb; a◌゙◌𑽂◌्◌ְb; a◌゙◌𑽂◌्◌ְb; a◌゙◌𑽂◌्◌ְb; ) LATIN SMALL LETTER A, KAWI CONJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 16FF0 0334 16AF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062;0061 0334 16AF0 16FF0 0062; # (a𖿰◌̴◌𖫰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; a◌̴◌𖫰𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH TONE, LATIN SMALL LETTER B 0061 16AF0 16FF0 0334 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062;0061 16AF0 0334 16FF0 0062; # (a◌𖫰𖿰◌̴b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; a◌𖫰◌̴𖿰b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH TONE, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 16AF1 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062;0061 0334 16AF1 16FF0 0062; # (a𖿰◌̴◌𖫱b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; a◌̴◌𖫱𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW TONE, LATIN SMALL LETTER B @@ -18533,10 +18742,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 16FF1 093C 16FF0 0334 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062;0061 0334 16FF1 16FF0 093C 0062; # (a𖿱◌𖿰़◌̴b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; a◌̴𖿱𖿰◌़b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK NHAY, DEVANAGARI SIGN NUKTA, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 1BC9E 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062;0061 0334 1BC9E 16FF0 0062; # (a𖿰◌̴◌𛲞b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; a◌̴◌𛲞𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, DUPLOYAN DOUBLE MARK, LATIN SMALL LETTER B 0061 1BC9E 16FF0 0334 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062;0061 1BC9E 0334 16FF0 0062; # (a◌𛲞𖿰◌̴b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; a◌𛲞◌̴𖿰b; ) LATIN SMALL LETTER A, DUPLOYAN DOUBLE MARK, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D165 0062;0061 1DCE 031B 1D165 302A 0062;0061 1DCE 031B 1D165 302A 0062;0061 1DCE 031B 1D165 302A 0062;0061 1DCE 031B 1D165 302A 0062; # (a◌〪◌̛◌᷎𝅥b; a◌᷎◌̛𝅥◌〪b; a◌᷎◌̛𝅥◌〪b; a◌᷎◌̛𝅥◌〪b; a◌᷎◌̛𝅥◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING STEM, LATIN SMALL LETTER B -0061 1D165 302A 031B 1DCE 0062;0061 1DCE 1D165 031B 302A 0062;0061 1DCE 1D165 031B 302A 0062;0061 1DCE 1D165 031B 302A 0062;0061 1DCE 1D165 031B 302A 0062; # (a𝅥◌〪◌̛◌᷎b; a◌᷎𝅥◌̛◌〪b; a◌᷎𝅥◌̛◌〪b; a◌᷎𝅥◌̛◌〪b; a◌᷎𝅥◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STEM, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D166 0062;0061 1DCE 031B 1D166 302A 0062;0061 1DCE 031B 1D166 302A 0062;0061 1DCE 031B 1D166 302A 0062;0061 1DCE 031B 1D166 302A 0062; # (a◌〪◌̛◌᷎𝅦b; a◌᷎◌̛𝅦◌〪b; a◌᷎◌̛𝅦◌〪b; a◌᷎◌̛𝅦◌〪b; a◌᷎◌̛𝅦◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, LATIN SMALL LETTER B -0061 1D166 302A 031B 1DCE 0062;0061 1DCE 1D166 031B 302A 0062;0061 1DCE 1D166 031B 302A 0062;0061 1DCE 1D166 031B 302A 0062;0061 1DCE 1D166 031B 302A 0062; # (a𝅦◌〪◌̛◌᷎b; a◌᷎𝅦◌̛◌〪b; a◌᷎𝅦◌̛◌〪b; a◌᷎𝅦◌̛◌〪b; a◌᷎𝅦◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D165 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062;0061 1DCE 031B 1D165 1DFA 0062; # (a◌᷺◌̛◌᷎𝅥b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; a◌᷎◌̛𝅥◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING STEM, LATIN SMALL LETTER B +0061 1D165 1DFA 031B 1DCE 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062;0061 1DCE 1D165 031B 1DFA 0062; # (a𝅥◌᷺◌̛◌᷎b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; a◌᷎𝅥◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STEM, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D166 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062;0061 1DCE 031B 1D166 1DFA 0062; # (a◌᷺◌̛◌᷎𝅦b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; a◌᷎◌̛𝅦◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, LATIN SMALL LETTER B +0061 1D166 1DFA 031B 1DCE 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062;0061 1DCE 1D166 031B 1DFA 0062; # (a𝅦◌᷺◌̛◌᷎b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; a◌᷎𝅦◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SPRECHGESANG STEM, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B 0061 16FF0 0334 1D167 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062;0061 0334 1D167 16FF0 0062; # (a𖿰◌̴◌𝅧b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; a◌̴◌𝅧𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-1, LATIN SMALL LETTER B 0061 1D167 16FF0 0334 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062;0061 1D167 0334 16FF0 0062; # (a◌𝅧𖿰◌̴b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; a◌𝅧◌̴𖿰b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-1, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 16FF0 0334 1D168 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062;0061 0334 1D168 16FF0 0062; # (a𖿰◌̴◌𝅨b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; a◌̴◌𝅨𖿰b; ) LATIN SMALL LETTER A, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, MUSICAL SYMBOL COMBINING TREMOLO-2, LATIN SMALL LETTER B @@ -18545,32 +18754,32 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1D169 16FF0 0334 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062;0061 1D169 0334 16FF0 0062; # (a◌𝅩𖿰◌̴b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; a◌𝅩◌̴𖿰b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TREMOLO-3, VIETNAMESE ALTERNATE READING MARK CA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 05AE 1D16D 302E 1D16D 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a◌〮𝅭𝅭֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B 0061 1D16D 05AE 1D16D 302E 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062;0061 302E 1D16D 1D16D 05AE 0062; # (a𝅭◌〮𝅭֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; a〮𝅭𝅭◌֮b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, HANGUL SINGLE DOT TONE MARK, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D16E 0062;0061 1DCE 031B 1D16E 302A 0062;0061 1DCE 031B 1D16E 302A 0062;0061 1DCE 031B 1D16E 302A 0062;0061 1DCE 031B 1D16E 302A 0062; # (a◌〪◌̛◌᷎𝅮b; a◌᷎◌̛𝅮◌〪b; a◌᷎◌̛𝅮◌〪b; a◌᷎◌̛𝅮◌〪b; a◌᷎◌̛𝅮◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-1, LATIN SMALL LETTER B -0061 1D16E 302A 031B 1DCE 0062;0061 1DCE 1D16E 031B 302A 0062;0061 1DCE 1D16E 031B 302A 0062;0061 1DCE 1D16E 031B 302A 0062;0061 1DCE 1D16E 031B 302A 0062; # (a𝅮◌〪◌̛◌᷎b; a◌᷎𝅮◌̛◌〪b; a◌᷎𝅮◌̛◌〪b; a◌᷎𝅮◌̛◌〪b; a◌᷎𝅮◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-1, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D16F 0062;0061 1DCE 031B 1D16F 302A 0062;0061 1DCE 031B 1D16F 302A 0062;0061 1DCE 031B 1D16F 302A 0062;0061 1DCE 031B 1D16F 302A 0062; # (a◌〪◌̛◌᷎𝅯b; a◌᷎◌̛𝅯◌〪b; a◌᷎◌̛𝅯◌〪b; a◌᷎◌̛𝅯◌〪b; a◌᷎◌̛𝅯◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-2, LATIN SMALL LETTER B -0061 1D16F 302A 031B 1DCE 0062;0061 1DCE 1D16F 031B 302A 0062;0061 1DCE 1D16F 031B 302A 0062;0061 1DCE 1D16F 031B 302A 0062;0061 1DCE 1D16F 031B 302A 0062; # (a𝅯◌〪◌̛◌᷎b; a◌᷎𝅯◌̛◌〪b; a◌᷎𝅯◌̛◌〪b; a◌᷎𝅯◌̛◌〪b; a◌᷎𝅯◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-2, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D170 0062;0061 1DCE 031B 1D170 302A 0062;0061 1DCE 031B 1D170 302A 0062;0061 1DCE 031B 1D170 302A 0062;0061 1DCE 031B 1D170 302A 0062; # (a◌〪◌̛◌᷎𝅰b; a◌᷎◌̛𝅰◌〪b; a◌᷎◌̛𝅰◌〪b; a◌᷎◌̛𝅰◌〪b; a◌᷎◌̛𝅰◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-3, LATIN SMALL LETTER B -0061 1D170 302A 031B 1DCE 0062;0061 1DCE 1D170 031B 302A 0062;0061 1DCE 1D170 031B 302A 0062;0061 1DCE 1D170 031B 302A 0062;0061 1DCE 1D170 031B 302A 0062; # (a𝅰◌〪◌̛◌᷎b; a◌᷎𝅰◌̛◌〪b; a◌᷎𝅰◌̛◌〪b; a◌᷎𝅰◌̛◌〪b; a◌᷎𝅰◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-3, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D171 0062;0061 1DCE 031B 1D171 302A 0062;0061 1DCE 031B 1D171 302A 0062;0061 1DCE 031B 1D171 302A 0062;0061 1DCE 031B 1D171 302A 0062; # (a◌〪◌̛◌᷎𝅱b; a◌᷎◌̛𝅱◌〪b; a◌᷎◌̛𝅱◌〪b; a◌᷎◌̛𝅱◌〪b; a◌᷎◌̛𝅱◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-4, LATIN SMALL LETTER B -0061 1D171 302A 031B 1DCE 0062;0061 1DCE 1D171 031B 302A 0062;0061 1DCE 1D171 031B 302A 0062;0061 1DCE 1D171 031B 302A 0062;0061 1DCE 1D171 031B 302A 0062; # (a𝅱◌〪◌̛◌᷎b; a◌᷎𝅱◌̛◌〪b; a◌᷎𝅱◌̛◌〪b; a◌᷎𝅱◌̛◌〪b; a◌᷎𝅱◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-4, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 302A 031B 1DCE 1D172 0062;0061 1DCE 031B 1D172 302A 0062;0061 1DCE 031B 1D172 302A 0062;0061 1DCE 031B 1D172 302A 0062;0061 1DCE 031B 1D172 302A 0062; # (a◌〪◌̛◌᷎𝅲b; a◌᷎◌̛𝅲◌〪b; a◌᷎◌̛𝅲◌〪b; a◌᷎◌̛𝅲◌〪b; a◌᷎◌̛𝅲◌〪b; ) LATIN SMALL LETTER A, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-5, LATIN SMALL LETTER B -0061 1D172 302A 031B 1DCE 0062;0061 1DCE 1D172 031B 302A 0062;0061 1DCE 1D172 031B 302A 0062;0061 1DCE 1D172 031B 302A 0062;0061 1DCE 1D172 031B 302A 0062; # (a𝅲◌〪◌̛◌᷎b; a◌᷎𝅲◌̛◌〪b; a◌᷎𝅲◌̛◌〪b; a◌᷎𝅲◌̛◌〪b; a◌᷎𝅲◌̛◌〪b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-5, IDEOGRAPHIC LEVEL TONE MARK, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B -0061 059A 0316 302A 1D17B 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062;0061 302A 0316 1D17B 059A 0062; # (a◌֚◌̖◌〪◌𝅻b; a◌〪◌̖◌𝅻◌֚b; a◌〪◌̖◌𝅻◌֚b; a◌〪◌̖◌𝅻◌֚b; a◌〪◌̖◌𝅻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING ACCENT, LATIN SMALL LETTER B -0061 1D17B 059A 0316 302A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062;0061 302A 1D17B 0316 059A 0062; # (a◌𝅻◌֚◌̖◌〪b; a◌〪◌𝅻◌̖◌֚b; a◌〪◌𝅻◌̖◌֚b; a◌〪◌𝅻◌̖◌֚b; a◌〪◌𝅻◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D17C 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062;0061 302A 0316 1D17C 059A 0062; # (a◌֚◌̖◌〪◌𝅼b; a◌〪◌̖◌𝅼◌֚b; a◌〪◌̖◌𝅼◌֚b; a◌〪◌̖◌𝅼◌֚b; a◌〪◌̖◌𝅼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING STACCATO, LATIN SMALL LETTER B -0061 1D17C 059A 0316 302A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062;0061 302A 1D17C 0316 059A 0062; # (a◌𝅼◌֚◌̖◌〪b; a◌〪◌𝅼◌̖◌֚b; a◌〪◌𝅼◌̖◌֚b; a◌〪◌𝅼◌̖◌֚b; a◌〪◌𝅼◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D17D 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062;0061 302A 0316 1D17D 059A 0062; # (a◌֚◌̖◌〪◌𝅽b; a◌〪◌̖◌𝅽◌֚b; a◌〪◌̖◌𝅽◌֚b; a◌〪◌̖◌𝅽◌֚b; a◌〪◌̖◌𝅽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING TENUTO, LATIN SMALL LETTER B -0061 1D17D 059A 0316 302A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062;0061 302A 1D17D 0316 059A 0062; # (a◌𝅽◌֚◌̖◌〪b; a◌〪◌𝅽◌̖◌֚b; a◌〪◌𝅽◌̖◌֚b; a◌〪◌𝅽◌̖◌֚b; a◌〪◌𝅽◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TENUTO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D17E 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062;0061 302A 0316 1D17E 059A 0062; # (a◌֚◌̖◌〪◌𝅾b; a◌〪◌̖◌𝅾◌֚b; a◌〪◌̖◌𝅾◌֚b; a◌〪◌̖◌𝅾◌֚b; a◌〪◌̖◌𝅾◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING STACCATISSIMO, LATIN SMALL LETTER B -0061 1D17E 059A 0316 302A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062;0061 302A 1D17E 0316 059A 0062; # (a◌𝅾◌֚◌̖◌〪b; a◌〪◌𝅾◌̖◌֚b; a◌〪◌𝅾◌̖◌֚b; a◌〪◌𝅾◌̖◌֚b; a◌〪◌𝅾◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATISSIMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D17F 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062;0061 302A 0316 1D17F 059A 0062; # (a◌֚◌̖◌〪◌𝅿b; a◌〪◌̖◌𝅿◌֚b; a◌〪◌̖◌𝅿◌֚b; a◌〪◌̖◌𝅿◌֚b; a◌〪◌̖◌𝅿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING MARCATO, LATIN SMALL LETTER B -0061 1D17F 059A 0316 302A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062;0061 302A 1D17F 0316 059A 0062; # (a◌𝅿◌֚◌̖◌〪b; a◌〪◌𝅿◌̖◌֚b; a◌〪◌𝅿◌̖◌֚b; a◌〪◌𝅿◌̖◌֚b; a◌〪◌𝅿◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D180 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062;0061 302A 0316 1D180 059A 0062; # (a◌֚◌̖◌〪◌𝆀b; a◌〪◌̖◌𝆀◌֚b; a◌〪◌̖◌𝆀◌֚b; a◌〪◌̖◌𝆀◌֚b; a◌〪◌̖◌𝆀◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, LATIN SMALL LETTER B -0061 1D180 059A 0316 302A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062;0061 302A 1D180 0316 059A 0062; # (a◌𝆀◌֚◌̖◌〪b; a◌〪◌𝆀◌̖◌֚b; a◌〪◌𝆀◌̖◌֚b; a◌〪◌𝆀◌̖◌֚b; a◌〪◌𝆀◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D181 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062;0061 302A 0316 1D181 059A 0062; # (a◌֚◌̖◌〪◌𝆁b; a◌〪◌̖◌𝆁◌֚b; a◌〪◌̖◌𝆁◌֚b; a◌〪◌̖◌𝆁◌֚b; a◌〪◌̖◌𝆁◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, LATIN SMALL LETTER B -0061 1D181 059A 0316 302A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062;0061 302A 1D181 0316 059A 0062; # (a◌𝆁◌֚◌̖◌〪b; a◌〪◌𝆁◌̖◌֚b; a◌〪◌𝆁◌̖◌֚b; a◌〪◌𝆁◌̖◌֚b; a◌〪◌𝆁◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D182 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062;0061 302A 0316 1D182 059A 0062; # (a◌֚◌̖◌〪◌𝆂b; a◌〪◌̖◌𝆂◌֚b; a◌〪◌̖◌𝆂◌֚b; a◌〪◌̖◌𝆂◌֚b; a◌〪◌̖◌𝆂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING LOURE, LATIN SMALL LETTER B -0061 1D182 059A 0316 302A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062;0061 302A 1D182 0316 059A 0062; # (a◌𝆂◌֚◌̖◌〪b; a◌〪◌𝆂◌̖◌֚b; a◌〪◌𝆂◌̖◌֚b; a◌〪◌𝆂◌̖◌֚b; a◌〪◌𝆂◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING LOURE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D16E 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062;0061 1DCE 031B 1D16E 1DFA 0062; # (a◌᷺◌̛◌᷎𝅮b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; a◌᷎◌̛𝅮◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-1, LATIN SMALL LETTER B +0061 1D16E 1DFA 031B 1DCE 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062;0061 1DCE 1D16E 031B 1DFA 0062; # (a𝅮◌᷺◌̛◌᷎b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; a◌᷎𝅮◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-1, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D16F 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062;0061 1DCE 031B 1D16F 1DFA 0062; # (a◌᷺◌̛◌᷎𝅯b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; a◌᷎◌̛𝅯◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-2, LATIN SMALL LETTER B +0061 1D16F 1DFA 031B 1DCE 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062;0061 1DCE 1D16F 031B 1DFA 0062; # (a𝅯◌᷺◌̛◌᷎b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; a◌᷎𝅯◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-2, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D170 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062;0061 1DCE 031B 1D170 1DFA 0062; # (a◌᷺◌̛◌᷎𝅰b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; a◌᷎◌̛𝅰◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-3, LATIN SMALL LETTER B +0061 1D170 1DFA 031B 1DCE 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062;0061 1DCE 1D170 031B 1DFA 0062; # (a𝅰◌᷺◌̛◌᷎b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; a◌᷎𝅰◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-3, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D171 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062;0061 1DCE 031B 1D171 1DFA 0062; # (a◌᷺◌̛◌᷎𝅱b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; a◌᷎◌̛𝅱◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-4, LATIN SMALL LETTER B +0061 1D171 1DFA 031B 1DCE 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062;0061 1DCE 1D171 031B 1DFA 0062; # (a𝅱◌᷺◌̛◌᷎b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; a◌᷎𝅱◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-4, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 1DFA 031B 1DCE 1D172 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062;0061 1DCE 031B 1D172 1DFA 0062; # (a◌᷺◌̛◌᷎𝅲b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; a◌᷎◌̛𝅲◌᷺b; ) LATIN SMALL LETTER A, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, MUSICAL SYMBOL COMBINING FLAG-5, LATIN SMALL LETTER B +0061 1D172 1DFA 031B 1DCE 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062;0061 1DCE 1D172 031B 1DFA 0062; # (a𝅲◌᷺◌̛◌᷎b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; a◌᷎𝅲◌̛◌᷺b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING FLAG-5, COMBINING DOT BELOW LEFT, COMBINING HORN, COMBINING OGONEK ABOVE, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17B 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062;0061 1DFA 0316 1D17B 059A 0062; # (a◌֚◌̖◌᷺◌𝅻b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; a◌᷺◌̖◌𝅻◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING ACCENT, LATIN SMALL LETTER B +0061 1D17B 059A 0316 1DFA 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062;0061 1DFA 1D17B 0316 059A 0062; # (a◌𝅻◌֚◌̖◌᷺b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; a◌᷺◌𝅻◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17C 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062;0061 1DFA 0316 1D17C 059A 0062; # (a◌֚◌̖◌᷺◌𝅼b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; a◌᷺◌̖◌𝅼◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING STACCATO, LATIN SMALL LETTER B +0061 1D17C 059A 0316 1DFA 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062;0061 1DFA 1D17C 0316 059A 0062; # (a◌𝅼◌֚◌̖◌᷺b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; a◌᷺◌𝅼◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17D 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062;0061 1DFA 0316 1D17D 059A 0062; # (a◌֚◌̖◌᷺◌𝅽b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; a◌᷺◌̖◌𝅽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING TENUTO, LATIN SMALL LETTER B +0061 1D17D 059A 0316 1DFA 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062;0061 1DFA 1D17D 0316 059A 0062; # (a◌𝅽◌֚◌̖◌᷺b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; a◌᷺◌𝅽◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TENUTO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17E 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062;0061 1DFA 0316 1D17E 059A 0062; # (a◌֚◌̖◌᷺◌𝅾b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; a◌᷺◌̖◌𝅾◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING STACCATISSIMO, LATIN SMALL LETTER B +0061 1D17E 059A 0316 1DFA 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062;0061 1DFA 1D17E 0316 059A 0062; # (a◌𝅾◌֚◌̖◌᷺b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; a◌᷺◌𝅾◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING STACCATISSIMO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D17F 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062;0061 1DFA 0316 1D17F 059A 0062; # (a◌֚◌̖◌᷺◌𝅿b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; a◌᷺◌̖◌𝅿◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING MARCATO, LATIN SMALL LETTER B +0061 1D17F 059A 0316 1DFA 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062;0061 1DFA 1D17F 0316 059A 0062; # (a◌𝅿◌֚◌̖◌᷺b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; a◌᷺◌𝅿◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D180 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062;0061 1DFA 0316 1D180 059A 0062; # (a◌֚◌̖◌᷺◌𝆀b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; a◌᷺◌̖◌𝆀◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, LATIN SMALL LETTER B +0061 1D180 059A 0316 1DFA 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062;0061 1DFA 1D180 0316 059A 0062; # (a◌𝆀◌֚◌̖◌᷺b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; a◌᷺◌𝆀◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING MARCATO-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D181 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062;0061 1DFA 0316 1D181 059A 0062; # (a◌֚◌̖◌᷺◌𝆁b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; a◌᷺◌̖◌𝆁◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, LATIN SMALL LETTER B +0061 1D181 059A 0316 1DFA 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062;0061 1DFA 1D181 0316 059A 0062; # (a◌𝆁◌֚◌̖◌᷺b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; a◌᷺◌𝆁◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING ACCENT-STACCATO, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D182 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062;0061 1DFA 0316 1D182 059A 0062; # (a◌֚◌̖◌᷺◌𝆂b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; a◌᷺◌̖◌𝆂◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING LOURE, LATIN SMALL LETTER B +0061 1D182 059A 0316 1DFA 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062;0061 1DFA 1D182 0316 059A 0062; # (a◌𝆂◌֚◌̖◌᷺b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; a◌᷺◌𝆂◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING LOURE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D185 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062;00E0 05AE 1D185 0315 0062;0061 05AE 0300 1D185 0315 0062; # (a◌̕◌̀◌֮◌𝆅b; à◌֮◌𝆅◌̕b; a◌֮◌̀◌𝆅◌̕b; à◌֮◌𝆅◌̕b; a◌֮◌̀◌𝆅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOIT, LATIN SMALL LETTER B 0061 1D185 0315 0300 05AE 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062;0061 05AE 1D185 0300 0315 0062; # (a◌𝆅◌̕◌̀◌֮b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; a◌֮◌𝆅◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOIT, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D186 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062;00E0 05AE 1D186 0315 0062;0061 05AE 0300 1D186 0315 0062; # (a◌̕◌̀◌֮◌𝆆b; à◌֮◌𝆆◌̕b; a◌֮◌̀◌𝆆◌̕b; à◌֮◌𝆆◌̕b; a◌֮◌̀◌𝆆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING RIP, LATIN SMALL LETTER B @@ -18581,10 +18790,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1D188 0315 0300 05AE 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062;0061 05AE 1D188 0300 0315 0062; # (a◌𝆈◌̕◌̀◌֮b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; a◌֮◌𝆈◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING SMEAR, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D189 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062;00E0 05AE 1D189 0315 0062;0061 05AE 0300 1D189 0315 0062; # (a◌̕◌̀◌֮◌𝆉b; à◌֮◌𝆉◌̕b; a◌֮◌̀◌𝆉◌̕b; à◌֮◌𝆉◌̕b; a◌֮◌̀◌𝆉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING BEND, LATIN SMALL LETTER B 0061 1D189 0315 0300 05AE 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062;0061 05AE 1D189 0300 0315 0062; # (a◌𝆉◌̕◌̀◌֮b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; a◌֮◌𝆉◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING BEND, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1D18A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062;0061 302A 0316 1D18A 059A 0062; # (a◌֚◌̖◌〪◌𝆊b; a◌〪◌̖◌𝆊◌֚b; a◌〪◌̖◌𝆊◌֚b; a◌〪◌̖◌𝆊◌֚b; a◌〪◌̖◌𝆊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, LATIN SMALL LETTER B -0061 1D18A 059A 0316 302A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062;0061 302A 1D18A 0316 059A 0062; # (a◌𝆊◌֚◌̖◌〪b; a◌〪◌𝆊◌̖◌֚b; a◌〪◌𝆊◌̖◌֚b; a◌〪◌𝆊◌̖◌֚b; a◌〪◌𝆊◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1D18B 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062;0061 302A 0316 1D18B 059A 0062; # (a◌֚◌̖◌〪◌𝆋b; a◌〪◌̖◌𝆋◌֚b; a◌〪◌̖◌𝆋◌֚b; a◌〪◌̖◌𝆋◌֚b; a◌〪◌̖◌𝆋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, LATIN SMALL LETTER B -0061 1D18B 059A 0316 302A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062;0061 302A 1D18B 0316 059A 0062; # (a◌𝆋◌֚◌̖◌〪b; a◌〪◌𝆋◌̖◌֚b; a◌〪◌𝆋◌̖◌֚b; a◌〪◌𝆋◌̖◌֚b; a◌〪◌𝆋◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D18A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062;0061 1DFA 0316 1D18A 059A 0062; # (a◌֚◌̖◌᷺◌𝆊b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; a◌᷺◌̖◌𝆊◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, LATIN SMALL LETTER B +0061 1D18A 059A 0316 1DFA 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062;0061 1DFA 1D18A 0316 059A 0062; # (a◌𝆊◌֚◌̖◌᷺b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; a◌᷺◌𝆊◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOUBLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1D18B 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062;0061 1DFA 0316 1D18B 059A 0062; # (a◌֚◌̖◌᷺◌𝆋b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; a◌᷺◌̖◌𝆋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, LATIN SMALL LETTER B +0061 1D18B 059A 0316 1DFA 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062;0061 1DFA 1D18B 0316 059A 0062; # (a◌𝆋◌֚◌̖◌᷺b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; a◌᷺◌𝆋◌̖◌֚b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING TRIPLE TONGUE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D1AA 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062;00E0 05AE 1D1AA 0315 0062;0061 05AE 0300 1D1AA 0315 0062; # (a◌̕◌̀◌֮◌𝆪b; à◌֮◌𝆪◌̕b; a◌֮◌̀◌𝆪◌̕b; à◌֮◌𝆪◌̕b; a◌֮◌̀◌𝆪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING DOWN BOW, LATIN SMALL LETTER B 0061 1D1AA 0315 0300 05AE 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062;0061 05AE 1D1AA 0300 0315 0062; # (a◌𝆪◌̕◌̀◌֮b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; a◌֮◌𝆪◌̀◌̕b; ) LATIN SMALL LETTER A, MUSICAL SYMBOL COMBINING DOWN BOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D1AB 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062;00E0 05AE 1D1AB 0315 0062;0061 05AE 0300 1D1AB 0315 0062; # (a◌̕◌̀◌֮◌𝆫b; à◌֮◌𝆫◌̕b; a◌֮◌̀◌𝆫◌̕b; à◌֮◌𝆫◌̕b; a◌֮◌̀◌𝆫◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING UP BOW, LATIN SMALL LETTER B @@ -18675,6 +18884,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1E029 0315 0300 05AE 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062; # (a◌𞀩◌̕◌̀◌֮b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IOTATED BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E02A 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062; # (a◌̕◌̀◌֮◌𞀪b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER FITA, LATIN SMALL LETTER B 0061 1E02A 0315 0300 05AE 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062; # (a◌𞀪◌̕◌̀◌֮b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER FITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E08F 0062;00E0 05AE 1E08F 0315 0062;0061 05AE 0300 1E08F 0315 0062;00E0 05AE 1E08F 0315 0062;0061 05AE 0300 1E08F 0315 0062; # (a◌̕◌̀◌֮◌𞂏b; à◌֮◌𞂏◌̕b; a◌֮◌̀◌𞂏◌̕b; à◌֮◌𞂏◌̕b; a◌֮◌̀◌𞂏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I, LATIN SMALL LETTER B +0061 1E08F 0315 0300 05AE 0062;0061 05AE 1E08F 0300 0315 0062;0061 05AE 1E08F 0300 0315 0062;0061 05AE 1E08F 0300 0315 0062;0061 05AE 1E08F 0300 0315 0062; # (a◌𞂏◌̕◌̀◌֮b; a◌֮◌𞂏◌̀◌̕b; a◌֮◌𞂏◌̀◌̕b; a◌֮◌𞂏◌̀◌̕b; a◌֮◌𞂏◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E130 0062;00E0 05AE 1E130 0315 0062;0061 05AE 0300 1E130 0315 0062;00E0 05AE 1E130 0315 0062;0061 05AE 0300 1E130 0315 0062; # (a◌̕◌̀◌֮◌𞄰b; à◌֮◌𞄰◌̕b; a◌֮◌̀◌𞄰◌̕b; à◌֮◌𞄰◌̕b; a◌֮◌̀◌𞄰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-B, LATIN SMALL LETTER B 0061 1E130 0315 0300 05AE 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062;0061 05AE 1E130 0300 0315 0062; # (a◌𞄰◌̕◌̀◌֮b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; a◌֮◌𞄰◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-B, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E131 0062;00E0 05AE 1E131 0315 0062;0061 05AE 0300 1E131 0315 0062;00E0 05AE 1E131 0315 0062;0061 05AE 0300 1E131 0315 0062; # (a◌̕◌̀◌֮◌𞄱b; à◌֮◌𞄱◌̕b; a◌֮◌̀◌𞄱◌̕b; à◌֮◌𞄱◌̕b; a◌֮◌̀◌𞄱◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-M, LATIN SMALL LETTER B @@ -18689,6 +18900,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1E135 0315 0300 05AE 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062;0061 05AE 1E135 0300 0315 0062; # (a◌𞄵◌̕◌̀◌֮b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; a◌֮◌𞄵◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-G, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E136 0062;00E0 05AE 1E136 0315 0062;0061 05AE 0300 1E136 0315 0062;00E0 05AE 1E136 0315 0062;0061 05AE 0300 1E136 0315 0062; # (a◌̕◌̀◌֮◌𞄶b; à◌֮◌𞄶◌̕b; a◌֮◌̀◌𞄶◌̕b; à◌֮◌𞄶◌̕b; a◌֮◌̀◌𞄶◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NYIAKENG PUACHUE HMONG TONE-D, LATIN SMALL LETTER B 0061 1E136 0315 0300 05AE 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062;0061 05AE 1E136 0300 0315 0062; # (a◌𞄶◌̕◌̀◌֮b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; a◌֮◌𞄶◌̀◌̕b; ) LATIN SMALL LETTER A, NYIAKENG PUACHUE HMONG TONE-D, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E2AE 0062;00E0 05AE 1E2AE 0315 0062;0061 05AE 0300 1E2AE 0315 0062;00E0 05AE 1E2AE 0315 0062;0061 05AE 0300 1E2AE 0315 0062; # (a◌̕◌̀◌֮◌𞊮b; à◌֮◌𞊮◌̕b; a◌֮◌̀◌𞊮◌̕b; à◌֮◌𞊮◌̕b; a◌֮◌̀◌𞊮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, TOTO SIGN RISING TONE, LATIN SMALL LETTER B +0061 1E2AE 0315 0300 05AE 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062;0061 05AE 1E2AE 0300 0315 0062; # (a◌𞊮◌̕◌̀◌֮b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; a◌֮◌𞊮◌̀◌̕b; ) LATIN SMALL LETTER A, TOTO SIGN RISING TONE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E2EC 0062;00E0 05AE 1E2EC 0315 0062;0061 05AE 0300 1E2EC 0315 0062;00E0 05AE 1E2EC 0315 0062;0061 05AE 0300 1E2EC 0315 0062; # (a◌̕◌̀◌֮◌𞋬b; à◌֮◌𞋬◌̕b; a◌֮◌̀◌𞋬◌̕b; à◌֮◌𞋬◌̕b; a◌֮◌̀◌𞋬◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE TUP, LATIN SMALL LETTER B 0061 1E2EC 0315 0300 05AE 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062;0061 05AE 1E2EC 0300 0315 0062; # (a◌𞋬◌̕◌̀◌֮b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; a◌֮◌𞋬◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE TUP, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E2ED 0062;00E0 05AE 1E2ED 0315 0062;0061 05AE 0300 1E2ED 0315 0062;00E0 05AE 1E2ED 0315 0062;0061 05AE 0300 1E2ED 0315 0062; # (a◌̕◌̀◌֮◌𞋭b; à◌֮◌𞋭◌̕b; a◌֮◌̀◌𞋭◌̕b; à◌֮◌𞋭◌̕b; a◌֮◌̀◌𞋭◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE TUPNI, LATIN SMALL LETTER B @@ -18697,20 +18910,28 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1E2EE 0315 0300 05AE 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062;0061 05AE 1E2EE 0300 0315 0062; # (a◌𞋮◌̕◌̀◌֮b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; a◌֮◌𞋮◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE KOI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E2EF 0062;00E0 05AE 1E2EF 0315 0062;0061 05AE 0300 1E2EF 0315 0062;00E0 05AE 1E2EF 0315 0062;0061 05AE 0300 1E2EF 0315 0062; # (a◌̕◌̀◌֮◌𞋯b; à◌֮◌𞋯◌̕b; a◌֮◌̀◌𞋯◌̕b; à◌֮◌𞋯◌̕b; a◌֮◌̀◌𞋯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, WANCHO TONE KOINI, LATIN SMALL LETTER B 0061 1E2EF 0315 0300 05AE 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062;0061 05AE 1E2EF 0300 0315 0062; # (a◌𞋯◌̕◌̀◌֮b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; a◌֮◌𞋯◌̀◌̕b; ) LATIN SMALL LETTER A, WANCHO TONE KOINI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D0 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062; # (a◌֚◌̖◌〪◌𞣐b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER TEENS, LATIN SMALL LETTER B -0061 1E8D0 059A 0316 302A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062; # (a◌𞣐◌֚◌̖◌〪b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D1 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062; # (a◌֚◌̖◌〪◌𞣑b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER TENS, LATIN SMALL LETTER B -0061 1E8D1 059A 0316 302A 0062;0061 302A 1E8D1 0316 059A 0062;0061 302A 1E8D1 0316 059A 0062;0061 302A 1E8D1 0316 059A 0062;0061 302A 1E8D1 0316 059A 0062; # (a◌𞣑◌֚◌̖◌〪b; a◌〪◌𞣑◌̖◌֚b; a◌〪◌𞣑◌̖◌֚b; a◌〪◌𞣑◌̖◌֚b; a◌〪◌𞣑◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D2 0062;0061 302A 0316 1E8D2 059A 0062;0061 302A 0316 1E8D2 059A 0062;0061 302A 0316 1E8D2 059A 0062;0061 302A 0316 1E8D2 059A 0062; # (a◌֚◌̖◌〪◌𞣒b; a◌〪◌̖◌𞣒◌֚b; a◌〪◌̖◌𞣒◌֚b; a◌〪◌̖◌𞣒◌֚b; a◌〪◌̖◌𞣒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, LATIN SMALL LETTER B -0061 1E8D2 059A 0316 302A 0062;0061 302A 1E8D2 0316 059A 0062;0061 302A 1E8D2 0316 059A 0062;0061 302A 1E8D2 0316 059A 0062;0061 302A 1E8D2 0316 059A 0062; # (a◌𞣒◌֚◌̖◌〪b; a◌〪◌𞣒◌̖◌֚b; a◌〪◌𞣒◌̖◌֚b; a◌〪◌𞣒◌̖◌֚b; a◌〪◌𞣒◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D3 0062;0061 302A 0316 1E8D3 059A 0062;0061 302A 0316 1E8D3 059A 0062;0061 302A 0316 1E8D3 059A 0062;0061 302A 0316 1E8D3 059A 0062; # (a◌֚◌̖◌〪◌𞣓b; a◌〪◌̖◌𞣓◌֚b; a◌〪◌̖◌𞣓◌֚b; a◌〪◌̖◌𞣓◌֚b; a◌〪◌̖◌𞣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, LATIN SMALL LETTER B -0061 1E8D3 059A 0316 302A 0062;0061 302A 1E8D3 0316 059A 0062;0061 302A 1E8D3 0316 059A 0062;0061 302A 1E8D3 0316 059A 0062;0061 302A 1E8D3 0316 059A 0062; # (a◌𞣓◌֚◌̖◌〪b; a◌〪◌𞣓◌̖◌֚b; a◌〪◌𞣓◌̖◌֚b; a◌〪◌𞣓◌̖◌֚b; a◌〪◌𞣓◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D4 0062;0061 302A 0316 1E8D4 059A 0062;0061 302A 0316 1E8D4 059A 0062;0061 302A 0316 1E8D4 059A 0062;0061 302A 0316 1E8D4 059A 0062; # (a◌֚◌̖◌〪◌𞣔b; a◌〪◌̖◌𞣔◌֚b; a◌〪◌̖◌𞣔◌֚b; a◌〪◌̖◌𞣔◌֚b; a◌〪◌̖◌𞣔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, LATIN SMALL LETTER B -0061 1E8D4 059A 0316 302A 0062;0061 302A 1E8D4 0316 059A 0062;0061 302A 1E8D4 0316 059A 0062;0061 302A 1E8D4 0316 059A 0062;0061 302A 1E8D4 0316 059A 0062; # (a◌𞣔◌֚◌̖◌〪b; a◌〪◌𞣔◌̖◌֚b; a◌〪◌𞣔◌̖◌֚b; a◌〪◌𞣔◌̖◌֚b; a◌〪◌𞣔◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D5 0062;0061 302A 0316 1E8D5 059A 0062;0061 302A 0316 1E8D5 059A 0062;0061 302A 0316 1E8D5 059A 0062;0061 302A 0316 1E8D5 059A 0062; # (a◌֚◌̖◌〪◌𞣕b; a◌〪◌̖◌𞣕◌֚b; a◌〪◌̖◌𞣕◌֚b; a◌〪◌̖◌𞣕◌֚b; a◌〪◌̖◌𞣕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, LATIN SMALL LETTER B -0061 1E8D5 059A 0316 302A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062; # (a◌𞣕◌֚◌̖◌〪b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B -0061 059A 0316 302A 1E8D6 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062; # (a◌֚◌̖◌〪◌𞣖b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER MILLIONS, LATIN SMALL LETTER B -0061 1E8D6 059A 0316 302A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062; # (a◌𞣖◌֚◌̖◌〪b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER MILLIONS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 035C 0315 0300 1E4EC 0062;00E0 0315 1E4EC 035C 0062;0061 0300 0315 1E4EC 035C 0062;00E0 0315 1E4EC 035C 0062;0061 0300 0315 1E4EC 035C 0062; # (a◌͜◌̕◌̀◌𞓬b; à◌̕◌𞓬◌͜b; a◌̀◌̕◌𞓬◌͜b; à◌̕◌𞓬◌͜b; a◌̀◌̕◌𞓬◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, NAG MUNDARI SIGN MUHOR, LATIN SMALL LETTER B +0061 1E4EC 035C 0315 0300 0062;00E0 1E4EC 0315 035C 0062;0061 0300 1E4EC 0315 035C 0062;00E0 1E4EC 0315 035C 0062;0061 0300 1E4EC 0315 035C 0062; # (a◌𞓬◌͜◌̕◌̀b; à◌𞓬◌̕◌͜b; a◌̀◌𞓬◌̕◌͜b; à◌𞓬◌̕◌͜b; a◌̀◌𞓬◌̕◌͜b; ) LATIN SMALL LETTER A, NAG MUNDARI SIGN MUHOR, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 035C 0315 0300 1E4ED 0062;00E0 0315 1E4ED 035C 0062;0061 0300 0315 1E4ED 035C 0062;00E0 0315 1E4ED 035C 0062;0061 0300 0315 1E4ED 035C 0062; # (a◌͜◌̕◌̀◌𞓭b; à◌̕◌𞓭◌͜b; a◌̀◌̕◌𞓭◌͜b; à◌̕◌𞓭◌͜b; a◌̀◌̕◌𞓭◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, NAG MUNDARI SIGN TOYOR, LATIN SMALL LETTER B +0061 1E4ED 035C 0315 0300 0062;00E0 1E4ED 0315 035C 0062;0061 0300 1E4ED 0315 035C 0062;00E0 1E4ED 0315 035C 0062;0061 0300 1E4ED 0315 035C 0062; # (a◌𞓭◌͜◌̕◌̀b; à◌𞓭◌̕◌͜b; a◌̀◌𞓭◌̕◌͜b; à◌𞓭◌̕◌͜b; a◌̀◌𞓭◌̕◌͜b; ) LATIN SMALL LETTER A, NAG MUNDARI SIGN TOYOR, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E4EE 0062;0061 1DFA 0316 1E4EE 059A 0062;0061 1DFA 0316 1E4EE 059A 0062;0061 1DFA 0316 1E4EE 059A 0062;0061 1DFA 0316 1E4EE 059A 0062; # (a◌֚◌̖◌᷺◌𞓮b; a◌᷺◌̖◌𞓮◌֚b; a◌᷺◌̖◌𞓮◌֚b; a◌᷺◌̖◌𞓮◌֚b; a◌᷺◌̖◌𞓮◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, NAG MUNDARI SIGN IKIR, LATIN SMALL LETTER B +0061 1E4EE 059A 0316 1DFA 0062;0061 1DFA 1E4EE 0316 059A 0062;0061 1DFA 1E4EE 0316 059A 0062;0061 1DFA 1E4EE 0316 059A 0062;0061 1DFA 1E4EE 0316 059A 0062; # (a◌𞓮◌֚◌̖◌᷺b; a◌᷺◌𞓮◌̖◌֚b; a◌᷺◌𞓮◌̖◌֚b; a◌᷺◌𞓮◌̖◌֚b; a◌᷺◌𞓮◌̖◌֚b; ) LATIN SMALL LETTER A, NAG MUNDARI SIGN IKIR, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E4EF 0062;00E0 05AE 1E4EF 0315 0062;0061 05AE 0300 1E4EF 0315 0062;00E0 05AE 1E4EF 0315 0062;0061 05AE 0300 1E4EF 0315 0062; # (a◌̕◌̀◌֮◌𞓯b; à◌֮◌𞓯◌̕b; a◌֮◌̀◌𞓯◌̕b; à◌֮◌𞓯◌̕b; a◌֮◌̀◌𞓯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NAG MUNDARI SIGN SUTUH, LATIN SMALL LETTER B +0061 1E4EF 0315 0300 05AE 0062;0061 05AE 1E4EF 0300 0315 0062;0061 05AE 1E4EF 0300 0315 0062;0061 05AE 1E4EF 0300 0315 0062;0061 05AE 1E4EF 0300 0315 0062; # (a◌𞓯◌̕◌̀◌֮b; a◌֮◌𞓯◌̀◌̕b; a◌֮◌𞓯◌̀◌̕b; a◌֮◌𞓯◌̀◌̕b; a◌֮◌𞓯◌̀◌̕b; ) LATIN SMALL LETTER A, NAG MUNDARI SIGN SUTUH, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D0 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062;0061 1DFA 0316 1E8D0 059A 0062; # (a◌֚◌̖◌᷺◌𞣐b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; a◌᷺◌̖◌𞣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TEENS, LATIN SMALL LETTER B +0061 1E8D0 059A 0316 1DFA 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062;0061 1DFA 1E8D0 0316 059A 0062; # (a◌𞣐◌֚◌̖◌᷺b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; a◌᷺◌𞣐◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D1 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062;0061 1DFA 0316 1E8D1 059A 0062; # (a◌֚◌̖◌᷺◌𞣑b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; a◌᷺◌̖◌𞣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TENS, LATIN SMALL LETTER B +0061 1E8D1 059A 0316 1DFA 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062;0061 1DFA 1E8D1 0316 059A 0062; # (a◌𞣑◌֚◌̖◌᷺b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; a◌᷺◌𞣑◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D2 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062;0061 1DFA 0316 1E8D2 059A 0062; # (a◌֚◌̖◌᷺◌𞣒b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; a◌᷺◌̖◌𞣒◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, LATIN SMALL LETTER B +0061 1E8D2 059A 0316 1DFA 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062;0061 1DFA 1E8D2 0316 059A 0062; # (a◌𞣒◌֚◌̖◌᷺b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; a◌᷺◌𞣒◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDREDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D3 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062;0061 1DFA 0316 1E8D3 059A 0062; # (a◌֚◌̖◌᷺◌𞣓b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; a◌᷺◌̖◌𞣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, LATIN SMALL LETTER B +0061 1E8D3 059A 0316 1DFA 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062;0061 1DFA 1E8D3 0316 059A 0062; # (a◌𞣓◌֚◌̖◌᷺b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; a◌᷺◌𞣓◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D4 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062;0061 1DFA 0316 1E8D4 059A 0062; # (a◌֚◌̖◌᷺◌𞣔b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; a◌᷺◌̖◌𞣔◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, LATIN SMALL LETTER B +0061 1E8D4 059A 0316 1DFA 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062;0061 1DFA 1E8D4 0316 059A 0062; # (a◌𞣔◌֚◌̖◌᷺b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; a◌᷺◌𞣔◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D5 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062;0061 1DFA 0316 1E8D5 059A 0062; # (a◌֚◌̖◌᷺◌𞣕b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; a◌᷺◌̖◌𞣕◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, LATIN SMALL LETTER B +0061 1E8D5 059A 0316 1DFA 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062;0061 1DFA 1E8D5 0316 059A 0062; # (a◌𞣕◌֚◌̖◌᷺b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; a◌᷺◌𞣕◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B +0061 059A 0316 1DFA 1E8D6 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062;0061 1DFA 0316 1E8D6 059A 0062; # (a◌֚◌̖◌᷺◌𞣖b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; a◌᷺◌̖◌𞣖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, MENDE KIKAKUI COMBINING NUMBER MILLIONS, LATIN SMALL LETTER B +0061 1E8D6 059A 0316 1DFA 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062;0061 1DFA 1E8D6 0316 059A 0062; # (a◌𞣖◌֚◌̖◌᷺b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; a◌᷺◌𞣖◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER MILLIONS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, COMBINING DOT BELOW LEFT, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E944 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062; # (a◌̕◌̀◌֮◌𞥄b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM ALIF LENGTHENER, LATIN SMALL LETTER B 0061 1E944 0315 0300 05AE 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062; # (a◌𞥄◌̕◌̀◌֮b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM ALIF LENGTHENER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1E945 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062; # (a◌̕◌̀◌֮◌𞥅b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM VOWEL LENGTHENER, LATIN SMALL LETTER B diff --git a/lib/stdlib/test/unicode_util_SUITE_data/unicode_table.bin b/lib/stdlib/test/unicode_util_SUITE_data/unicode_table.bin new file mode 100644 index 000000000000..9ea04b334d96 Binary files /dev/null and b/lib/stdlib/test/unicode_util_SUITE_data/unicode_table.bin differ diff --git a/lib/stdlib/test/uri_string_SUITE.erl b/lib/stdlib/test/uri_string_SUITE.erl index 96e4a9d41b0f..6a6bff2688c4 100644 --- a/lib/stdlib/test/uri_string_SUITE.erl +++ b/lib/stdlib/test/uri_string_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -20,6 +20,8 @@ -module(uri_string_SUITE). -include_lib("common_test/include/ct.hrl"). +-compile({nowarn_deprecated_function, [{http_uri, encode, 1}]}). +-compile({nowarn_deprecated_function, [{http_uri, decode, 1}]}). -export([all/0, suite/0,groups/0, normalize/1, normalize_map/1, normalize_return_map/1, normalize_negative/1, @@ -53,7 +55,8 @@ interop_query_latin1/1, interop_query_utf8/1, regression_parse/1, regression_recompose/1, regression_normalize/1, recompose_host_relative_path/1, - recompose_host_absolute_path/1 + recompose_host_absolute_path/1, + quote/1 ]). @@ -148,7 +151,8 @@ all() -> regression_recompose, regression_normalize, recompose_host_relative_path, - recompose_host_absolute_path + recompose_host_absolute_path, + quote ]. groups() -> @@ -587,18 +591,22 @@ parse_host_ipv6(_Config) -> {error,invalid_uri,"G"} = uri_string:parse("//[2001:0db8:0000:0000:0000:0000:1428:G7ab]"). parse_port(_Config) -> - #{path:= "/:8042"} = - uri_string:parse("/:8042"), - #{host:= "", port := 8042} = - uri_string:parse("//:8042"), - #{host := "example.com", port:= 8042} = - uri_string:parse("//example.com:8042"), - #{scheme := "foo", path := "/:8042"} = - uri_string:parse("foo:/:8042"), - #{scheme := "foo", host := "", port := 8042} = - uri_string:parse("foo://:8042"), - #{scheme := "foo", host := "example.com", port := 8042} = - uri_string:parse("foo://example.com:8042"). + parse_port_with_param("8042", 8042), + parse_port_with_param("", undefined). + +parse_port_with_param(PortString, Expected) -> + #{path:= "/:" ++ PortString} = + uri_string:parse("/:" ++ PortString), + #{host:= "", port := Expected} = + uri_string:parse("//:" ++ PortString), + #{host := "example.com", port:= Expected} = + uri_string:parse("//example.com:" ++ PortString), + #{scheme := "foo", path := "/:" ++ PortString} = + uri_string:parse("foo:/:" ++ PortString), + #{scheme := "foo", host := "", port := Expected} = + uri_string:parse("foo://:" ++ PortString), + #{scheme := "foo", host := "example.com", port := Expected} = + uri_string:parse("foo://example.com:" ++ PortString). parse_path(_Config) -> #{path := "over/there"} = uri_string:parse("over/there"), @@ -1016,7 +1024,19 @@ normalize(_Config) -> <<"tftp://localhost">> = uri_string:normalize(<<"tftp://localhost:69">>), <<"/foo/%2F/bar">> = - uri_string:normalize(<<"/foo/%2f/%62ar">>). + uri_string:normalize(<<"/foo/%2f/%62ar">>), + <<"https://localhost/">> = + uri_string:normalize(<<"https://localhost">>), + <<"https://localhost/">> = + uri_string:normalize(<<"https://localhost/">>), + <<"https://localhost/">> = + uri_string:normalize(<<"https://localhost:/">>), + <<"https://localhost/">> = + uri_string:normalize(<<"https://localhost:">>), + <<"yeti://localhost/">> = + uri_string:normalize(<<"yeti://localhost:/">>), + <<"yeti://localhost">> = + uri_string:normalize(<<"yeti://localhost:">>). normalize_map(_Config) -> "/a/g" = uri_string:normalize(#{path => "/a/b/c/./../../g"}), @@ -1047,7 +1067,13 @@ normalize_map(_Config) -> uri_string:normalize(#{scheme => <<"tftp">>,port => 69,path => <<>>, host => <<"localhost">>}), "/foo/%2F/bar" = - uri_string:normalize(#{path => "/foo/%2f/%62ar"}). + uri_string:normalize(#{path => "/foo/%2f/%62ar"}), + <<"https://localhost/">> = + uri_string:normalize(#{scheme => <<"https">>,port => undefined,path => <<>>, + host => <<"localhost">>}), + <<"yeti://localhost">> = + uri_string:normalize(#{scheme => <<"yeti">>,port => undefined,path => <<>>, + host => <<"localhost">>}). normalize_return_map(_Config) -> #{scheme := "http",path := "/a/g",host := "localhost-örebro"} = @@ -1332,3 +1358,132 @@ recompose_host_absolute_path(_Config) -> path => [<<"/f">>,<<"oo">>]}), ok. +%%------------------------------------------------------------------------- +%% Quote tests +%%------------------------------------------------------------------------- +quote(_Config) -> + TestQuote = + fun(Unquoted, Quoted) -> + Quoted = uri_string:quote(Unquoted) + end, + + [TestQuote(U, Q) || #{unquoted := U, quoted := Q} <- get_quote_data()], + [TestQuote(U, Q) || #{unquoted_b := U, quoted_b := Q} <- get_quote_data()], + + Head = fun([H | _]) -> H; + (<>) -> H + end, + + TestQuoteUnquote = + fun(Unquoted) -> + %% case below should be removed when functions used are removed + case Head(Unquoted) =< 127 of + true -> + Unquoted = http_uri:decode(http_uri:encode(Unquoted)); + _ -> + ok + end, + Unquoted = uri_string:unquote(uri_string:quote(Unquoted)) + end, + [TestQuoteUnquote(U) || #{unquoted := U} <- get_quote_data()], + [TestQuoteUnquote(U) || #{unquoted_b := U} <- get_quote_data()], + + TestQuoteWithSafeList = + fun(Unquoted, Quoted) -> + Safe = "!$()*", %% characters not encoded by old http_uri:encode + Result = uri_string:quote(Unquoted, Safe), + %% case below should be removed when function used are removed + case Head(Unquoted) =< 127 of + true -> + Result = http_uri:encode(Unquoted); + _ -> + ok + end, + case lists:member(Head(Unquoted), Safe) of + true -> + Unquoted = Result; + false -> + Quoted = Result + end + end, + [TestQuoteWithSafeList(U, Q) || #{unquoted := U, quoted := Q} <- get_quote_data()], + [TestQuoteWithSafeList(U, Q) || #{unquoted_b := U, quoted_b := Q} <- get_quote_data()], + + + ComposePath = fun (PathSegments, Safe) -> + lists:join("/", [uri_string:quote(S, Safe) || + S <- PathSegments]) + end, + + %% / used as data see GH-5368 + ExampleURI1 = "https://internal.api.com/devices/Ethernet0%2F4", + ExampleURI1 = uri_string:recompose( + #{scheme => "https", + host => "internal.api.com", + path => ComposePath(["devices", "Ethernet0/4"], + "")}), + + %% sub-delims as data + %% in this example ComposePath must treat sub-delims and '%' as safe character + %% to avoid re-encoding encoded characters + ExampleURI2 = "yeti://localhost/folder/file.txt,version=1%2C1", + ExampleURI2 = uri_string:recompose( + #{scheme => "yeti", + host => "localhost", + path => ComposePath(["folder", "file.txt,version=" ++ + uri_string:quote("1,1")], + ",=%")}), + + %% percent character as data + ExampleURI3 = "yeti://localhost/folder/file_with_%25.txt", + ExampleURI3 = uri_string:recompose( + #{scheme => "yeti", + host => "localhost", + path => ComposePath(["folder", "file_with_" ++ + uri_string:quote("%") ++ ".txt"], + "%")}), + ok. + +get_quote_data() -> + [%% reserved/gen-delims + #{unquoted => ":", quoted => "%3A", unquoted_b =><<":">>, quoted_b=> <<"%3A">>}, + #{unquoted => "/", quoted => "%2F", unquoted_b =><<"/">>, quoted_b=> <<"%2F">>}, + #{unquoted => "?", quoted => "%3F", unquoted_b =><<"?">>, quoted_b=> <<"%3F">>}, + #{unquoted => "#", quoted => "%23", unquoted_b =><<"#">>, quoted_b=> <<"%23">>}, + #{unquoted => "[", quoted => "%5B", unquoted_b =><<"[">>, quoted_b=> <<"%5B">>}, + #{unquoted => "]", quoted => "%5D", unquoted_b =><<"]">>, quoted_b=> <<"%5D">>}, + #{unquoted => "@", quoted => "%40", unquoted_b =><<"@">>, quoted_b=> <<"%40">>}, + %% reserved/sub-delims + #{unquoted => "!", quoted => "%21", unquoted_b =><<"!">>, quoted_b=> <<"%21">>}, + #{unquoted => "$", quoted => "%24", unquoted_b =><<"$">>, quoted_b=> <<"%24">>}, + #{unquoted => "&", quoted => "%26", unquoted_b =><<"&">>, quoted_b=> <<"%26">>}, + #{unquoted => "'", quoted => "%27", unquoted_b =><<"'">>, quoted_b=> <<"%27">>}, + #{unquoted => "(", quoted => "%28", unquoted_b =><<"(">>, quoted_b=> <<"%28">>}, + #{unquoted => ")", quoted => "%29", unquoted_b =><<")">>, quoted_b=> <<"%29">>}, + #{unquoted => "*", quoted => "%2A", unquoted_b =><<"*">>, quoted_b=> <<"%2A">>}, + #{unquoted => "+", quoted => "%2B", unquoted_b =><<"+">>, quoted_b=> <<"%2B">>}, + #{unquoted => ",", quoted => "%2C", unquoted_b =><<",">>, quoted_b=> <<"%2C">>}, + #{unquoted => ";", quoted => "%3B", unquoted_b =><<";">>, quoted_b=> <<"%3B">>}, + #{unquoted => "=", quoted => "%3D", unquoted_b =><<"=">>, quoted_b=> <<"%3D">>}, + %% other not unreserved + #{unquoted => "<", quoted => "%3C", unquoted_b =><<"<">>, quoted_b=> <<"%3C">>}, + #{unquoted => ">", quoted => "%3E", unquoted_b =><<">">>, quoted_b=> <<"%3E">>}, + #{unquoted => "\"", quoted => "%22", unquoted_b =><<"\"">>, quoted_b=> <<"%22">>}, + #{unquoted => "{", quoted => "%7B", unquoted_b =><<"{">>, quoted_b=> <<"%7B">>}, + #{unquoted => "}", quoted => "%7D", unquoted_b =><<"}">>, quoted_b=> <<"%7D">>}, + #{unquoted => "|", quoted => "%7C", unquoted_b =><<"|">>, quoted_b=> <<"%7C">>}, + #{unquoted => "\\", quoted => "%5C", unquoted_b =><<"\\">>, quoted_b=> <<"%5C">>}, + #{unquoted => "^", quoted => "%5E", unquoted_b =><<"^">>, quoted_b=> <<"%5E">>}, + #{unquoted => "%", quoted => "%25", unquoted_b =><<"%">>, quoted_b=> <<"%25">>}, + #{unquoted => " ", quoted => "%20", unquoted_b =><<" ">>, quoted_b=> <<"%20">>}, + %% non-ASCII + #{unquoted => "örebro", quoted => "%C3%B6rebro", + unquoted_b =><<"örebro"/utf8>>, quoted_b=> <<"%C3%B6rebro">>}, + #{unquoted => "Łódź", quoted => "%C5%81%C3%B3d%C5%BA", + unquoted_b =><<"Łódź"/utf8>>, quoted_b=> <<"%C5%81%C3%B3d%C5%BA">>}, + %% unreserved non alpha, non digit characters + #{unquoted => "-", quoted => "-", unquoted_b =><<"-">>, quoted_b=> <<"-">>}, + #{unquoted => ".", quoted => ".", unquoted_b =><<".">>, quoted_b=> <<".">>}, + #{unquoted => "_", quoted => "_", unquoted_b =><<"_">>, quoted_b=> <<"_">>}, + #{unquoted => "~", quoted => "~", unquoted_b =><<"~">>, quoted_b=> <<"~">>} + ]. diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl index 1709acc52395..97e5c660dd96 100644 --- a/lib/stdlib/test/zip_SUITE.erl +++ b/lib/stdlib/test/zip_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2023. 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. @@ -280,6 +280,8 @@ zip_api(Config) when is_list(Config) -> Name1 = hd(Names), {ok, Data1} = file:read_file(Name1), {ok, {Name1, Data1}} = zip:zip_get(Name1, ZipSrv), + Data1Crc = erlang:crc32(Data1), + {ok, Data1Crc} = zip:zip_get_crc32(Name1, ZipSrv), %% Get all files FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(Name), diff --git a/lib/stdlib/uc_spec/CaseFolding.txt b/lib/stdlib/uc_spec/CaseFolding.txt index 033788b253f7..65aa0fcd6b32 100644 --- a/lib/stdlib/uc_spec/CaseFolding.txt +++ b/lib/stdlib/uc_spec/CaseFolding.txt @@ -1,11 +1,11 @@ -# CaseFolding-13.0.0.txt -# Date: 2019-09-08, 23:30:59 GMT -# © 2019 Unicode®, Inc. +# CaseFolding-15.0.0.txt +# Date: 2022-02-02, 23:35:35 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # Case Folding Properties # @@ -1050,6 +1050,7 @@ 2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC 2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A 2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI 2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR 2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE 2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE @@ -1230,12 +1231,16 @@ A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U +A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G +A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S +A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H AB70; C; 13A0; # CHEROKEE SMALL LETTER A AB71; C; 13A1; # CHEROKEE SMALL LETTER E @@ -1431,6 +1436,41 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA 104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA 104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA +10570; C; 10597; # VITHKUQI CAPITAL LETTER A +10571; C; 10598; # VITHKUQI CAPITAL LETTER BBE +10572; C; 10599; # VITHKUQI CAPITAL LETTER BE +10573; C; 1059A; # VITHKUQI CAPITAL LETTER CE +10574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE +10575; C; 1059C; # VITHKUQI CAPITAL LETTER DE +10576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE +10577; C; 1059E; # VITHKUQI CAPITAL LETTER EI +10578; C; 1059F; # VITHKUQI CAPITAL LETTER E +10579; C; 105A0; # VITHKUQI CAPITAL LETTER FE +1057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA +1057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA +1057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA +1057E; C; 105A5; # VITHKUQI CAPITAL LETTER I +1057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE +10580; C; 105A7; # VITHKUQI CAPITAL LETTER JE +10581; C; 105A8; # VITHKUQI CAPITAL LETTER KA +10582; C; 105A9; # VITHKUQI CAPITAL LETTER LA +10583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA +10584; C; 105AB; # VITHKUQI CAPITAL LETTER ME +10585; C; 105AC; # VITHKUQI CAPITAL LETTER NE +10586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE +10587; C; 105AE; # VITHKUQI CAPITAL LETTER O +10588; C; 105AF; # VITHKUQI CAPITAL LETTER PE +10589; C; 105B0; # VITHKUQI CAPITAL LETTER QA +1058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE +1058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE +1058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE +1058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE +1058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE +10590; C; 105B7; # VITHKUQI CAPITAL LETTER U +10591; C; 105B8; # VITHKUQI CAPITAL LETTER VE +10592; C; 105B9; # VITHKUQI CAPITAL LETTER XE +10594; C; 105BB; # VITHKUQI CAPITAL LETTER Y +10595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE 10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A 10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA 10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB diff --git a/lib/stdlib/uc_spec/CompositionExclusions.txt b/lib/stdlib/uc_spec/CompositionExclusions.txt index 52bbb465bcdf..bbc8bd75d832 100644 --- a/lib/stdlib/uc_spec/CompositionExclusions.txt +++ b/lib/stdlib/uc_spec/CompositionExclusions.txt @@ -1,10 +1,10 @@ -# CompositionExclusions-13.0.0.txt -# Date: 2019-10-15, 18:27:00 GMT [KW, LI] -# © 2019 Unicode®, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# CompositionExclusions-15.0.0.txt +# Date: 2022-05-03, 18:50:00 GMT [KW, LI] +# © 2022 Unicode®, Inc. +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # This file lists the characters for the Composition Exclusion Table # defined in UAX #15, Unicode Normalization Forms. @@ -13,7 +13,7 @@ # Unicode Character Database. # # For more information, see -# http://www.unicode.org/unicode/reports/tr15/#Primary_Exclusion_List_Table +# https://www.unicode.org/reports/tr15/#Primary_Exclusion_List_Table # # For a full derivation of composition exclusions, see the derived property # Full_Composition_Exclusion in DerivedNormalizationProps.txt diff --git a/lib/stdlib/uc_spec/EastAsianWidth.txt b/lib/stdlib/uc_spec/EastAsianWidth.txt new file mode 100644 index 000000000000..38b7076c02f7 --- /dev/null +++ b/lib/stdlib/uc_spec/EastAsianWidth.txt @@ -0,0 +1,2619 @@ +# EastAsianWidth-15.0.0.txt +# Date: 2022-05-24, 17:40:20 GMT [KW, LI] +# © 2022 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see https://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see https://www.unicode.org/reports/tr44/ +# +# East_Asian_Width Property +# +# This file is a normative contributory data file in the +# Unicode Character Database. +# +# The format is two fields separated by a semicolon. +# Field 0: Unicode code point value or range of code point values +# Field 1: East_Asian_Width property, consisting of one of the following values: +# "A", "F", "H", "N", "Na", "W" +# - All code points, assigned or unassigned, that are not listed +# explicitly are given the value "N". +# - The unassigned code points in the following blocks default to "W": +# CJK Unified Ideographs Extension A: U+3400..U+4DBF +# CJK Unified Ideographs: U+4E00..U+9FFF +# CJK Compatibility Ideographs: U+F900..U+FAFF +# - All undesignated code points in Planes 2 and 3, whether inside or +# outside of allocated blocks, default to "W": +# Plane 2: U+20000..U+2FFFD +# Plane 3: U+30000..U+3FFFD +# +# Character ranges are specified as for other property files in the +# Unicode Character Database. +# +# For legacy reasons, there are no spaces before or after the semicolon +# which separates the two fields. The comments following the number sign +# "#" list the General_Category property value or the L& alias of the +# derived value LC, the Unicode character name or names, and, in lines +# with ranges of code points, the code point count in square brackets. +# +# For more information, see UAX #11: East Asian Width, +# at https://www.unicode.org/reports/tr11/ +# +# @missing: 0000..10FFFF; N +0000..001F;N # Cc [32] .. +0020;Na # Zs SPACE +0021..0023;Na # Po [3] EXCLAMATION MARK..NUMBER SIGN +0024;Na # Sc DOLLAR SIGN +0025..0027;Na # Po [3] PERCENT SIGN..APOSTROPHE +0028;Na # Ps LEFT PARENTHESIS +0029;Na # Pe RIGHT PARENTHESIS +002A;Na # Po ASTERISK +002B;Na # Sm PLUS SIGN +002C;Na # Po COMMA +002D;Na # Pd HYPHEN-MINUS +002E..002F;Na # Po [2] FULL STOP..SOLIDUS +0030..0039;Na # Nd [10] DIGIT ZERO..DIGIT NINE +003A..003B;Na # Po [2] COLON..SEMICOLON +003C..003E;Na # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN +003F..0040;Na # Po [2] QUESTION MARK..COMMERCIAL AT +0041..005A;Na # Lu [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z +005B;Na # Ps LEFT SQUARE BRACKET +005C;Na # Po REVERSE SOLIDUS +005D;Na # Pe RIGHT SQUARE BRACKET +005E;Na # Sk CIRCUMFLEX ACCENT +005F;Na # Pc LOW LINE +0060;Na # Sk GRAVE ACCENT +0061..007A;Na # Ll [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z +007B;Na # Ps LEFT CURLY BRACKET +007C;Na # Sm VERTICAL LINE +007D;Na # Pe RIGHT CURLY BRACKET +007E;Na # Sm TILDE +007F;N # Cc +0080..009F;N # Cc [32] .. +00A0;N # Zs NO-BREAK SPACE +00A1;A # Po INVERTED EXCLAMATION MARK +00A2..00A3;Na # Sc [2] CENT SIGN..POUND SIGN +00A4;A # Sc CURRENCY SIGN +00A5;Na # Sc YEN SIGN +00A6;Na # So BROKEN BAR +00A7;A # Po SECTION SIGN +00A8;A # Sk DIAERESIS +00A9;N # So COPYRIGHT SIGN +00AA;A # Lo FEMININE ORDINAL INDICATOR +00AB;N # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC;Na # Sm NOT SIGN +00AD;A # Cf SOFT HYPHEN +00AE;A # So REGISTERED SIGN +00AF;Na # Sk MACRON +00B0;A # So DEGREE SIGN +00B1;A # Sm PLUS-MINUS SIGN +00B2..00B3;A # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE +00B4;A # Sk ACUTE ACCENT +00B5;N # Ll MICRO SIGN +00B6..00B7;A # Po [2] PILCROW SIGN..MIDDLE DOT +00B8;A # Sk CEDILLA +00B9;A # No SUPERSCRIPT ONE +00BA;A # Lo MASCULINE ORDINAL INDICATOR +00BB;N # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BC..00BE;A # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS +00BF;A # Po INVERTED QUESTION MARK +00C0..00C5;N # Lu [6] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER A WITH RING ABOVE +00C6;A # Lu LATIN CAPITAL LETTER AE +00C7..00CF;N # Lu [9] LATIN CAPITAL LETTER C WITH CEDILLA..LATIN CAPITAL LETTER I WITH DIAERESIS +00D0;A # Lu LATIN CAPITAL LETTER ETH +00D1..00D6;N # Lu [6] LATIN CAPITAL LETTER N WITH TILDE..LATIN CAPITAL LETTER O WITH DIAERESIS +00D7;A # Sm MULTIPLICATION SIGN +00D8;A # Lu LATIN CAPITAL LETTER O WITH STROKE +00D9..00DD;N # Lu [5] LATIN CAPITAL LETTER U WITH GRAVE..LATIN CAPITAL LETTER Y WITH ACUTE +00DE..00E1;A # L& [4] LATIN CAPITAL LETTER THORN..LATIN SMALL LETTER A WITH ACUTE +00E2..00E5;N # Ll [4] LATIN SMALL LETTER A WITH CIRCUMFLEX..LATIN SMALL LETTER A WITH RING ABOVE +00E6;A # Ll LATIN SMALL LETTER AE +00E7;N # Ll LATIN SMALL LETTER C WITH CEDILLA +00E8..00EA;A # Ll [3] LATIN SMALL LETTER E WITH GRAVE..LATIN SMALL LETTER E WITH CIRCUMFLEX +00EB;N # Ll LATIN SMALL LETTER E WITH DIAERESIS +00EC..00ED;A # Ll [2] LATIN SMALL LETTER I WITH GRAVE..LATIN SMALL LETTER I WITH ACUTE +00EE..00EF;N # Ll [2] LATIN SMALL LETTER I WITH CIRCUMFLEX..LATIN SMALL LETTER I WITH DIAERESIS +00F0;A # Ll LATIN SMALL LETTER ETH +00F1;N # Ll LATIN SMALL LETTER N WITH TILDE +00F2..00F3;A # Ll [2] LATIN SMALL LETTER O WITH GRAVE..LATIN SMALL LETTER O WITH ACUTE +00F4..00F6;N # Ll [3] LATIN SMALL LETTER O WITH CIRCUMFLEX..LATIN SMALL LETTER O WITH DIAERESIS +00F7;A # Sm DIVISION SIGN +00F8..00FA;A # Ll [3] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER U WITH ACUTE +00FB;N # Ll LATIN SMALL LETTER U WITH CIRCUMFLEX +00FC;A # Ll LATIN SMALL LETTER U WITH DIAERESIS +00FD;N # Ll LATIN SMALL LETTER Y WITH ACUTE +00FE;A # Ll LATIN SMALL LETTER THORN +00FF;N # Ll LATIN SMALL LETTER Y WITH DIAERESIS +0100;N # Lu LATIN CAPITAL LETTER A WITH MACRON +0101;A # Ll LATIN SMALL LETTER A WITH MACRON +0102..0110;N # L& [15] LATIN CAPITAL LETTER A WITH BREVE..LATIN CAPITAL LETTER D WITH STROKE +0111;A # Ll LATIN SMALL LETTER D WITH STROKE +0112;N # Lu LATIN CAPITAL LETTER E WITH MACRON +0113;A # Ll LATIN SMALL LETTER E WITH MACRON +0114..011A;N # L& [7] LATIN CAPITAL LETTER E WITH BREVE..LATIN CAPITAL LETTER E WITH CARON +011B;A # Ll LATIN SMALL LETTER E WITH CARON +011C..0125;N # L& [10] LATIN CAPITAL LETTER G WITH CIRCUMFLEX..LATIN SMALL LETTER H WITH CIRCUMFLEX +0126..0127;A # L& [2] LATIN CAPITAL LETTER H WITH STROKE..LATIN SMALL LETTER H WITH STROKE +0128..012A;N # L& [3] LATIN CAPITAL LETTER I WITH TILDE..LATIN CAPITAL LETTER I WITH MACRON +012B;A # Ll LATIN SMALL LETTER I WITH MACRON +012C..0130;N # L& [5] LATIN CAPITAL LETTER I WITH BREVE..LATIN CAPITAL LETTER I WITH DOT ABOVE +0131..0133;A # L& [3] LATIN SMALL LETTER DOTLESS I..LATIN SMALL LIGATURE IJ +0134..0137;N # L& [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA +0138;A # Ll LATIN SMALL LETTER KRA +0139..013E;N # L& [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON +013F..0142;A # L& [4] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH STROKE +0143;N # Lu LATIN CAPITAL LETTER N WITH ACUTE +0144;A # Ll LATIN SMALL LETTER N WITH ACUTE +0145..0147;N # L& [3] LATIN CAPITAL LETTER N WITH CEDILLA..LATIN CAPITAL LETTER N WITH CARON +0148..014B;A # L& [4] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER ENG +014C;N # Lu LATIN CAPITAL LETTER O WITH MACRON +014D;A # Ll LATIN SMALL LETTER O WITH MACRON +014E..0151;N # L& [4] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH DOUBLE ACUTE +0152..0153;A # L& [2] LATIN CAPITAL LIGATURE OE..LATIN SMALL LIGATURE OE +0154..0165;N # L& [18] LATIN CAPITAL LETTER R WITH ACUTE..LATIN SMALL LETTER T WITH CARON +0166..0167;A # L& [2] LATIN CAPITAL LETTER T WITH STROKE..LATIN SMALL LETTER T WITH STROKE +0168..016A;N # L& [3] LATIN CAPITAL LETTER U WITH TILDE..LATIN CAPITAL LETTER U WITH MACRON +016B;A # Ll LATIN SMALL LETTER U WITH MACRON +016C..017F;N # L& [20] LATIN CAPITAL LETTER U WITH BREVE..LATIN SMALL LETTER LONG S +0180..01BA;N # L& [59] LATIN SMALL LETTER B WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL +01BB;N # Lo LATIN LETTER TWO WITH STROKE +01BC..01BF;N # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN +01C0..01C3;N # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK +01C4..01CD;N # L& [10] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER A WITH CARON +01CE;A # Ll LATIN SMALL LETTER A WITH CARON +01CF;N # Lu LATIN CAPITAL LETTER I WITH CARON +01D0;A # Ll LATIN SMALL LETTER I WITH CARON +01D1;N # Lu LATIN CAPITAL LETTER O WITH CARON +01D2;A # Ll LATIN SMALL LETTER O WITH CARON +01D3;N # Lu LATIN CAPITAL LETTER U WITH CARON +01D4;A # Ll LATIN SMALL LETTER U WITH CARON +01D5;N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D6;A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D7;N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D8;A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01D9;N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DA;A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DB;N # Lu LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DC;A # Ll LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE +01DD..024F;N # L& [115] LATIN SMALL LETTER TURNED E..LATIN SMALL LETTER Y WITH STROKE +0250;N # Ll LATIN SMALL LETTER TURNED A +0251;A # Ll LATIN SMALL LETTER ALPHA +0252..0260;N # Ll [15] LATIN SMALL LETTER TURNED ALPHA..LATIN SMALL LETTER G WITH HOOK +0261;A # Ll LATIN SMALL LETTER SCRIPT G +0262..0293;N # Ll [50] LATIN LETTER SMALL CAPITAL G..LATIN SMALL LETTER EZH WITH CURL +0294;N # Lo LATIN LETTER GLOTTAL STOP +0295..02AF;N # Ll [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +02B0..02C1;N # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C3;N # Sk [2] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER RIGHT ARROWHEAD +02C4;A # Sk MODIFIER LETTER UP ARROWHEAD +02C5;N # Sk MODIFIER LETTER DOWN ARROWHEAD +02C6;N # Lm MODIFIER LETTER CIRCUMFLEX ACCENT +02C7;A # Lm CARON +02C8;N # Lm MODIFIER LETTER VERTICAL LINE +02C9..02CB;A # Lm [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT +02CC;N # Lm MODIFIER LETTER LOW VERTICAL LINE +02CD;A # Lm MODIFIER LETTER LOW MACRON +02CE..02CF;N # Lm [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT +02D0;A # Lm MODIFIER LETTER TRIANGULAR COLON +02D1;N # Lm MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7;N # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02D8..02DB;A # Sk [4] BREVE..OGONEK +02DC;N # Sk SMALL TILDE +02DD;A # Sk DOUBLE ACUTE ACCENT +02DE;N # Sk MODIFIER LETTER RHOTIC HOOK +02DF;A # Sk MODIFIER LETTER CROSS ACCENT +02E0..02E4;N # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02EB;N # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK +02EC;N # Lm MODIFIER LETTER VOICING +02ED;N # Sk MODIFIER LETTER UNASPIRATED +02EE;N # Lm MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF;N # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW +0300..036F;A # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X +0370..0373;N # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI +0374;N # Lm GREEK NUMERAL SIGN +0375;N # Sk GREEK LOWER NUMERAL SIGN +0376..0377;N # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA +037A;N # Lm GREEK YPOGEGRAMMENI +037B..037D;N # Ll [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037E;N # Po GREEK QUESTION MARK +037F;N # Lu GREEK CAPITAL LETTER YOT +0384..0385;N # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS +0386;N # Lu GREEK CAPITAL LETTER ALPHA WITH TONOS +0387;N # Po GREEK ANO TELEIA +0388..038A;N # Lu [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS +038C;N # Lu GREEK CAPITAL LETTER OMICRON WITH TONOS +038E..0390;N # L& [3] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0391..03A1;A # Lu [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO +03A3..03A9;A # Lu [7] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER OMEGA +03AA..03B0;N # L& [7] GREEK CAPITAL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03B1..03C1;A # Ll [17] GREEK SMALL LETTER ALPHA..GREEK SMALL LETTER RHO +03C2;N # Ll GREEK SMALL LETTER FINAL SIGMA +03C3..03C9;A # Ll [7] GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA +03CA..03F5;N # L& [44] GREEK SMALL LETTER IOTA WITH DIALYTIKA..GREEK LUNATE EPSILON SYMBOL +03F6;N # Sm GREEK REVERSED LUNATE EPSILON SYMBOL +03F7..03FF;N # L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400;N # Lu CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401;A # Lu CYRILLIC CAPITAL LETTER IO +0402..040F;N # Lu [14] CYRILLIC CAPITAL LETTER DJE..CYRILLIC CAPITAL LETTER DZHE +0410..044F;A # L& [64] CYRILLIC CAPITAL LETTER A..CYRILLIC SMALL LETTER YA +0450;N # Ll CYRILLIC SMALL LETTER IE WITH GRAVE +0451;A # Ll CYRILLIC SMALL LETTER IO +0452..0481;N # L& [48] CYRILLIC SMALL LETTER DJE..CYRILLIC SMALL LETTER KOPPA +0482;N # So CYRILLIC THOUSANDS SIGN +0483..0487;N # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE +0488..0489;N # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN +048A..04FF;N # L& [118] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER HA WITH STROKE +0500..052F;N # L& [48] CYRILLIC CAPITAL LETTER KOMI DE..CYRILLIC SMALL LETTER EL WITH DESCENDER +0531..0556;N # Lu [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH +0559;N # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING +055A..055F;N # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK +0560..0588;N # Ll [41] ARMENIAN SMALL LETTER TURNED AYB..ARMENIAN SMALL LETTER YI WITH STROKE +0589;N # Po ARMENIAN FULL STOP +058A;N # Pd ARMENIAN HYPHEN +058D..058E;N # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN +058F;N # Sc ARMENIAN DRAM SIGN +0591..05BD;N # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG +05BE;N # Pd HEBREW PUNCTUATION MAQAF +05BF;N # Mn HEBREW POINT RAFE +05C0;N # Po HEBREW PUNCTUATION PASEQ +05C1..05C2;N # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C3;N # Po HEBREW PUNCTUATION SOF PASUQ +05C4..05C5;N # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT +05C6;N # Po HEBREW PUNCTUATION NUN HAFUKHA +05C7;N # Mn HEBREW POINT QAMATS QATAN +05D0..05EA;N # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV +05EF..05F2;N # Lo [4] HEBREW YOD TRIANGLE..HEBREW LIGATURE YIDDISH DOUBLE YOD +05F3..05F4;N # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM +0600..0605;N # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +0606..0608;N # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY +0609..060A;N # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN +060B;N # Sc AFGHANI SIGN +060C..060D;N # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR +060E..060F;N # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA +0610..061A;N # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +061B;N # Po ARABIC SEMICOLON +061C;N # Cf ARABIC LETTER MARK +061D..061F;N # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK +0620..063F;N # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0640;N # Lm ARABIC TATWEEL +0641..064A;N # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH +064B..065F;N # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW +0660..0669;N # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +066A..066D;N # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR +066E..066F;N # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF +0670;N # Mn ARABIC LETTER SUPERSCRIPT ALEF +0671..06D3;N # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D4;N # Po ARABIC FULL STOP +06D5;N # Lo ARABIC LETTER AE +06D6..06DC;N # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06DD;N # Cf ARABIC END OF AYAH +06DE;N # So ARABIC START OF RUB EL HIZB +06DF..06E4;N # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA +06E5..06E6;N # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH +06E7..06E8;N # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06E9;N # So ARABIC PLACE OF SAJDAH +06EA..06ED;N # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +06EE..06EF;N # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V +06F0..06F9;N # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE +06FA..06FC;N # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW +06FD..06FE;N # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN +06FF;N # Lo ARABIC LETTER HEH WITH INVERTED V +0700..070D;N # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS +070F;N # Cf SYRIAC ABBREVIATION MARK +0710;N # Lo SYRIAC LETTER ALAPH +0711;N # Mn SYRIAC LETTER SUPERSCRIPT ALAPH +0712..072F;N # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH +0730..074A;N # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +074D..074F;N # Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE +0750..077F;N # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE +0780..07A5;N # Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU +07A6..07B0;N # Mn [11] THAANA ABAFILI..THAANA SUKUN +07B1;N # Lo THAANA LETTER NAA +07C0..07C9;N # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE +07CA..07EA;N # Lo [33] NKO LETTER A..NKO LETTER JONA RA +07EB..07F3;N # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07F4..07F5;N # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE +07F6;N # So NKO SYMBOL OO DENNEN +07F7..07F9;N # Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK +07FA;N # Lm NKO LAJANYALAN +07FD;N # Mn NKO DANTAYALAN +07FE..07FF;N # Sc [2] NKO DOROME SIGN..NKO TAMAN SIGN +0800..0815;N # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF +0816..0819;N # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH +081A;N # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT +081B..0823;N # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A +0824;N # Lm SAMARITAN MODIFIER LETTER SHORT A +0825..0827;N # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U +0828;N # Lm SAMARITAN MODIFIER LETTER I +0829..082D;N # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA +0830..083E;N # Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU +0840..0858;N # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0859..085B;N # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +085E;N # Po MANDAIC PUNCTUATION +0860..086A;N # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +0870..0887;N # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT +0888;N # Sk ARABIC RAISED ROUND DOT +0889..088E;N # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL +0890..0891;N # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE +0898..089F;N # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +08A0..08C8;N # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF +08C9;N # Lm ARABIC SMALL FARSI YEH +08CA..08E1;N # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA +08E2;N # Cf ARABIC DISPUTED END OF AYAH +08E3..08FF;N # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA +0900..0902;N # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA +0903;N # Mc DEVANAGARI SIGN VISARGA +0904..0939;N # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA +093A;N # Mn DEVANAGARI VOWEL SIGN OE +093B;N # Mc DEVANAGARI VOWEL SIGN OOE +093C;N # Mn DEVANAGARI SIGN NUKTA +093D;N # Lo DEVANAGARI SIGN AVAGRAHA +093E..0940;N # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II +0941..0948;N # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI +0949..094C;N # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +094D;N # Mn DEVANAGARI SIGN VIRAMA +094E..094F;N # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW +0950;N # Lo DEVANAGARI OM +0951..0957;N # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE +0958..0961;N # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL +0962..0963;N # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0964..0965;N # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +0966..096F;N # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +0970;N # Po DEVANAGARI ABBREVIATION SIGN +0971;N # Lm DEVANAGARI SIGN HIGH SPACING DOT +0972..097F;N # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA +0980;N # Lo BENGALI ANJI +0981;N # Mn BENGALI SIGN CANDRABINDU +0982..0983;N # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +0985..098C;N # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L +098F..0990;N # Lo [2] BENGALI LETTER E..BENGALI LETTER AI +0993..09A8;N # Lo [22] BENGALI LETTER O..BENGALI LETTER NA +09AA..09B0;N # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA +09B2;N # Lo BENGALI LETTER LA +09B6..09B9;N # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA +09BC;N # Mn BENGALI SIGN NUKTA +09BD;N # Lo BENGALI SIGN AVAGRAHA +09BE..09C0;N # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II +09C1..09C4;N # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8;N # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CC;N # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +09CD;N # Mn BENGALI SIGN VIRAMA +09CE;N # Lo BENGALI LETTER KHANDA TA +09D7;N # Mc BENGALI AU LENGTH MARK +09DC..09DD;N # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA +09DF..09E1;N # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL +09E2..09E3;N # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +09E6..09EF;N # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE +09F0..09F1;N # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09F2..09F3;N # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN +09F4..09F9;N # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN +09FA;N # So BENGALI ISSHAR +09FB;N # Sc BENGALI GANDA MARK +09FC;N # Lo BENGALI LETTER VEDIC ANUSVARA +09FD;N # Po BENGALI ABBREVIATION SIGN +09FE;N # Mn BENGALI SANDHI MARK +0A01..0A02;N # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI +0A03;N # Mc GURMUKHI SIGN VISARGA +0A05..0A0A;N # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0F..0A10;N # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A13..0A28;N # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A2A..0A30;N # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A32..0A33;N # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA +0A35..0A36;N # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA +0A38..0A39;N # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A3C;N # Mn GURMUKHI SIGN NUKTA +0A3E..0A40;N # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II +0A41..0A42;N # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU +0A47..0A48;N # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D;N # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A51;N # Mn GURMUKHI SIGN UDAAT +0A59..0A5C;N # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA +0A5E;N # Lo GURMUKHI LETTER FA +0A66..0A6F;N # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE +0A70..0A71;N # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK +0A72..0A74;N # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR +0A75;N # Mn GURMUKHI SIGN YAKASH +0A76;N # Po GURMUKHI ABBREVIATION SIGN +0A81..0A82;N # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA +0A83;N # Mc GUJARATI SIGN VISARGA +0A85..0A8D;N # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E +0A8F..0A91;N # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A93..0AA8;N # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA +0AAA..0AB0;N # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA +0AB2..0AB3;N # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB5..0AB9;N # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA +0ABC;N # Mn GUJARATI SIGN NUKTA +0ABD;N # Lo GUJARATI SIGN AVAGRAHA +0ABE..0AC0;N # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II +0AC1..0AC5;N # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC8;N # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +0AC9;N # Mc GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACC;N # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU +0ACD;N # Mn GUJARATI SIGN VIRAMA +0AD0;N # Lo GUJARATI OM +0AE0..0AE1;N # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL +0AE2..0AE3;N # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AE6..0AEF;N # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0AF0;N # Po GUJARATI ABBREVIATION SIGN +0AF1;N # Sc GUJARATI RUPEE SIGN +0AF9;N # Lo GUJARATI LETTER ZHA +0AFA..0AFF;N # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B01;N # Mn ORIYA SIGN CANDRABINDU +0B02..0B03;N # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +0B05..0B0C;N # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0F..0B10;N # Lo [2] ORIYA LETTER E..ORIYA LETTER AI +0B13..0B28;N # Lo [22] ORIYA LETTER O..ORIYA LETTER NA +0B2A..0B30;N # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA +0B32..0B33;N # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA +0B35..0B39;N # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA +0B3C;N # Mn ORIYA SIGN NUKTA +0B3D;N # Lo ORIYA SIGN AVAGRAHA +0B3E;N # Mc ORIYA VOWEL SIGN AA +0B3F;N # Mn ORIYA VOWEL SIGN I +0B40;N # Mc ORIYA VOWEL SIGN II +0B41..0B44;N # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR +0B47..0B48;N # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4C;N # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU +0B4D;N # Mn ORIYA SIGN VIRAMA +0B55..0B56;N # Mn [2] ORIYA SIGN OVERLINE..ORIYA AI LENGTH MARK +0B57;N # Mc ORIYA AU LENGTH MARK +0B5C..0B5D;N # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA +0B5F..0B61;N # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B62..0B63;N # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL +0B66..0B6F;N # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0B70;N # So ORIYA ISSHAR +0B71;N # Lo ORIYA LETTER WA +0B72..0B77;N # No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS +0B82;N # Mn TAMIL SIGN ANUSVARA +0B83;N # Lo TAMIL SIGN VISARGA +0B85..0B8A;N # Lo [6] TAMIL LETTER A..TAMIL LETTER UU +0B8E..0B90;N # Lo [3] TAMIL LETTER E..TAMIL LETTER AI +0B92..0B95;N # Lo [4] TAMIL LETTER O..TAMIL LETTER KA +0B99..0B9A;N # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA +0B9C;N # Lo TAMIL LETTER JA +0B9E..0B9F;N # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA +0BA3..0BA4;N # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA +0BA8..0BAA;N # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA +0BAE..0BB9;N # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA +0BBE..0BBF;N # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I +0BC0;N # Mn TAMIL VOWEL SIGN II +0BC1..0BC2;N # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU +0BC6..0BC8;N # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCC;N # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU +0BCD;N # Mn TAMIL SIGN VIRAMA +0BD0;N # Lo TAMIL OM +0BD7;N # Mc TAMIL AU LENGTH MARK +0BE6..0BEF;N # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE +0BF0..0BF2;N # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND +0BF3..0BF8;N # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN +0BF9;N # Sc TAMIL RUPEE SIGN +0BFA;N # So TAMIL NUMBER SIGN +0C00;N # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01..0C03;N # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04;N # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE +0C05..0C0C;N # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0E..0C10;N # Lo [3] TELUGU LETTER E..TELUGU LETTER AI +0C12..0C28;N # Lo [23] TELUGU LETTER O..TELUGU LETTER NA +0C2A..0C39;N # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA +0C3C;N # Mn TELUGU SIGN NUKTA +0C3D;N # Lo TELUGU SIGN AVAGRAHA +0C3E..0C40;N # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II +0C41..0C44;N # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48;N # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D;N # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56;N # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C58..0C5A;N # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA +0C5D;N # Lo TELUGU LETTER NAKAARA POLLU +0C60..0C61;N # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C62..0C63;N # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C66..0C6F;N # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0C77;N # Po TELUGU SIGN SIDDHAM +0C78..0C7E;N # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR +0C7F;N # So TELUGU SIGN TUUMU +0C80;N # Lo KANNADA SIGN SPACING CANDRABINDU +0C81;N # Mn KANNADA SIGN CANDRABINDU +0C82..0C83;N # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0C84;N # Po KANNADA SIGN SIDDHAM +0C85..0C8C;N # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8E..0C90;N # Lo [3] KANNADA LETTER E..KANNADA LETTER AI +0C92..0CA8;N # Lo [23] KANNADA LETTER O..KANNADA LETTER NA +0CAA..0CB3;N # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA +0CB5..0CB9;N # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA +0CBC;N # Mn KANNADA SIGN NUKTA +0CBD;N # Lo KANNADA SIGN AVAGRAHA +0CBE;N # Mc KANNADA VOWEL SIGN AA +0CBF;N # Mn KANNADA VOWEL SIGN I +0CC0..0CC4;N # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR +0CC6;N # Mn KANNADA VOWEL SIGN E +0CC7..0CC8;N # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB;N # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CCC..0CCD;N # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA +0CD5..0CD6;N # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CDD..0CDE;N # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA +0CE0..0CE1;N # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0CE2..0CE3;N # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0CE6..0CEF;N # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0CF1..0CF2;N # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA +0CF3;N # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT +0D00..0D01;N # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D02..0D03;N # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D04..0D0C;N # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L +0D0E..0D10;N # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI +0D12..0D3A;N # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3B..0D3C;N # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +0D3D;N # Lo MALAYALAM SIGN AVAGRAHA +0D3E..0D40;N # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II +0D41..0D44;N # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR +0D46..0D48;N # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4C;N # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU +0D4D;N # Mn MALAYALAM SIGN VIRAMA +0D4E;N # Lo MALAYALAM LETTER DOT REPH +0D4F;N # So MALAYALAM SIGN PARA +0D54..0D56;N # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL +0D57;N # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E;N # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH +0D5F..0D61;N # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL +0D62..0D63;N # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL +0D66..0D6F;N # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0D70..0D78;N # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS +0D79;N # So MALAYALAM DATE MARK +0D7A..0D7F;N # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K +0D81;N # Mn SINHALA SIGN CANDRABINDU +0D82..0D83;N # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0D85..0D96;N # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D9A..0DB1;N # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB3..0DBB;N # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBD;N # Lo SINHALA LETTER DANTAJA LAYANNA +0DC0..0DC6;N # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0DCA;N # Mn SINHALA SIGN AL-LAKUNA +0DCF..0DD1;N # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2..0DD4;N # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6;N # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF;N # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DE6..0DEF;N # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE +0DF2..0DF3;N # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0DF4;N # Po SINHALA PUNCTUATION KUNDDALIYA +0E01..0E30;N # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A +0E31;N # Mn THAI CHARACTER MAI HAN-AKAT +0E32..0E33;N # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM +0E34..0E3A;N # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E3F;N # Sc THAI CURRENCY SYMBOL BAHT +0E40..0E45;N # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO +0E46;N # Lm THAI CHARACTER MAIYAMOK +0E47..0E4E;N # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN +0E4F;N # Po THAI CHARACTER FONGMAN +0E50..0E59;N # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE +0E5A..0E5B;N # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT +0E81..0E82;N # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG +0E84;N # Lo LAO LETTER KHO TAM +0E86..0E8A;N # Lo [5] LAO LETTER PALI GHA..LAO LETTER SO TAM +0E8C..0EA3;N # Lo [24] LAO LETTER PALI JHA..LAO LETTER LO LING +0EA5;N # Lo LAO LETTER LO LOOT +0EA7..0EB0;N # Lo [10] LAO LETTER WO..LAO VOWEL SIGN A +0EB1;N # Mn LAO VOWEL SIGN MAI KAN +0EB2..0EB3;N # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM +0EB4..0EBC;N # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO +0EBD;N # Lo LAO SEMIVOWEL SIGN NYO +0EC0..0EC4;N # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI +0EC6;N # Lm LAO KO LA +0EC8..0ECE;N # Mn [7] LAO TONE MAI EK..LAO YAMAKKAN +0ED0..0ED9;N # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE +0EDC..0EDF;N # Lo [4] LAO HO NO..LAO LETTER KHMU NYO +0F00;N # Lo TIBETAN SYLLABLE OM +0F01..0F03;N # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA +0F04..0F12;N # Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD +0F13;N # So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN +0F14;N # Po TIBETAN MARK GTER TSHEG +0F15..0F17;N # So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F18..0F19;N # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F1A..0F1F;N # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG +0F20..0F29;N # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +0F2A..0F33;N # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO +0F34;N # So TIBETAN MARK BSDUS RTAGS +0F35;N # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F36;N # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F37;N # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F38;N # So TIBETAN MARK CHE MGO +0F39;N # Mn TIBETAN MARK TSA -PHRU +0F3A;N # Ps TIBETAN MARK GUG RTAGS GYON +0F3B;N # Pe TIBETAN MARK GUG RTAGS GYAS +0F3C;N # Ps TIBETAN MARK ANG KHANG GYON +0F3D;N # Pe TIBETAN MARK ANG KHANG GYAS +0F3E..0F3F;N # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F40..0F47;N # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA +0F49..0F6C;N # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA +0F71..0F7E;N # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO +0F7F;N # Mc TIBETAN SIGN RNAM BCAD +0F80..0F84;N # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA +0F85;N # Po TIBETAN MARK PALUTA +0F86..0F87;N # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0F88..0F8C;N # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN +0F8D..0F97;N # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA +0F99..0FBC;N # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FBE..0FC5;N # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE +0FC6;N # Mn TIBETAN SYMBOL PADMA GDAN +0FC7..0FCC;N # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCE..0FCF;N # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM +0FD0..0FD4;N # Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA +0FD5..0FD8;N # So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS +0FD9..0FDA;N # Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS +1000..102A;N # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU +102B..102C;N # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA +102D..1030;N # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +1031;N # Mc MYANMAR VOWEL SIGN E +1032..1037;N # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW +1038;N # Mc MYANMAR SIGN VISARGA +1039..103A;N # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT +103B..103C;N # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA +103D..103E;N # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA +103F;N # Lo MYANMAR LETTER GREAT SA +1040..1049;N # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +104A..104F;N # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE +1050..1055;N # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL +1056..1057;N # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR +1058..1059;N # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL +105A..105D;N # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE +105E..1060;N # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA +1061;N # Lo MYANMAR LETTER SGAW KAREN SHA +1062..1064;N # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO +1065..1066;N # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA +1067..106D;N # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5 +106E..1070;N # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA +1071..1074;N # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE +1075..1081;N # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA +1082;N # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA +1083..1084;N # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E +1085..1086;N # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y +1087..108C;N # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3 +108D;N # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +108E;N # Lo MYANMAR LETTER RUMAI PALAUNG FA +108F;N # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 +1090..1099;N # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE +109A..109C;N # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A +109D;N # Mn MYANMAR VOWEL SIGN AITON AI +109E..109F;N # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION +10A0..10C5;N # Lu [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10C7;N # Lu GEORGIAN CAPITAL LETTER YN +10CD;N # Lu GEORGIAN CAPITAL LETTER AEN +10D0..10FA;N # Ll [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN +10FB;N # Po GEORGIAN PARAGRAPH SEPARATOR +10FC;N # Lm MODIFIER LETTER GEORGIAN NAR +10FD..10FF;N # Ll [3] GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN +1100..115F;W # Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER +1160..11FF;N # Lo [160] HANGUL JUNGSEONG FILLER..HANGUL JONGSEONG SSANGNIEUN +1200..1248;N # Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA +124A..124D;N # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +1250..1256;N # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1258;N # Lo ETHIOPIC SYLLABLE QHWA +125A..125D;N # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +1260..1288;N # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA +128A..128D;N # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +1290..12B0;N # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA +12B2..12B5;N # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B8..12BE;N # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12C0;N # Lo ETHIOPIC SYLLABLE KXWA +12C2..12C5;N # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C8..12D6;N # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O +12D8..1310;N # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA +1312..1315;N # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1318..135A;N # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA +135D..135F;N # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK +1360..1368;N # Po [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR +1369..137C;N # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND +1380..138F;N # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE +1390..1399;N # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT +13A0..13F5;N # Lu [86] CHEROKEE LETTER A..CHEROKEE LETTER MV +13F8..13FD;N # Ll [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV +1400;N # Pd CANADIAN SYLLABICS HYPHEN +1401..166C;N # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166D;N # So CANADIAN SYLLABICS CHI SIGN +166E;N # Po CANADIAN SYLLABICS FULL STOP +166F..167F;N # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W +1680;N # Zs OGHAM SPACE MARK +1681..169A;N # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH +169B;N # Ps OGHAM FEATHER MARK +169C;N # Pe OGHAM REVERSED FEATHER MARK +16A0..16EA;N # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X +16EB..16ED;N # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +16EE..16F0;N # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +16F1..16F8;N # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC +1700..1711;N # Lo [18] TAGALOG LETTER A..TAGALOG LETTER HA +1712..1714;N # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +1715;N # Mc TAGALOG SIGN PAMUDPOD +171F;N # Lo TAGALOG LETTER ARCHAIC RA +1720..1731;N # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA +1732..1733;N # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U +1734;N # Mc HANUNOO SIGN PAMUDPOD +1735..1736;N # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +1740..1751;N # Lo [18] BUHID LETTER A..BUHID LETTER HA +1752..1753;N # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U +1760..176C;N # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA +176E..1770;N # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA +1772..1773;N # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +1780..17B3;N # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU +17B4..17B5;N # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA +17B6;N # Mc KHMER VOWEL SIGN AA +17B7..17BD;N # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA +17BE..17C5;N # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU +17C6;N # Mn KHMER SIGN NIKAHIT +17C7..17C8;N # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +17C9..17D3;N # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT +17D4..17D6;N # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH +17D7;N # Lm KHMER SIGN LEK TOO +17D8..17DA;N # Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT +17DB;N # Sc KHMER CURRENCY SYMBOL RIEL +17DC;N # Lo KHMER SIGN AVAKRAHASANYA +17DD;N # Mn KHMER SIGN ATTHACAN +17E0..17E9;N # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE +17F0..17F9;N # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON +1800..1805;N # Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS +1806;N # Pd MONGOLIAN TODO SOFT HYPHEN +1807..180A;N # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU +180B..180D;N # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180E;N # Cf MONGOLIAN VOWEL SEPARATOR +180F;N # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR +1810..1819;N # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +1820..1842;N # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI +1843;N # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +1844..1878;N # Lo [53] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER CHA WITH TWO DOTS +1880..1884;N # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886;N # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8;N # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA +18A9;N # Mn MONGOLIAN LETTER ALI GALI DAGALGA +18AA;N # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA +18B0..18F5;N # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S +1900..191E;N # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA +1920..1922;N # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U +1923..1926;N # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU +1927..1928;N # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O +1929..192B;N # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA +1930..1931;N # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA +1932;N # Mn LIMBU SMALL LETTER ANUSVARA +1933..1938;N # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA +1939..193B;N # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I +1940;N # So LIMBU SIGN LOO +1944..1945;N # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1946..194F;N # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE +1950..196D;N # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI +1970..1974;N # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6 +1980..19AB;N # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA +19B0..19C9;N # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2 +19D0..19D9;N # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE +19DA;N # No NEW TAI LUE THAM DIGIT ONE +19DE..19DF;N # So [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV +19E0..19FF;N # So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC +1A00..1A16;N # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA +1A17..1A18;N # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U +1A19..1A1A;N # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O +1A1B;N # Mn BUGINESE VOWEL SIGN AE +1A1E..1A1F;N # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION +1A20..1A54;N # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA +1A55;N # Mc TAI THAM CONSONANT SIGN MEDIAL RA +1A56;N # Mn TAI THAM CONSONANT SIGN MEDIAL LA +1A57;N # Mc TAI THAM CONSONANT SIGN LA TANG LAI +1A58..1A5E;N # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA +1A60;N # Mn TAI THAM SIGN SAKOT +1A61;N # Mc TAI THAM VOWEL SIGN A +1A62;N # Mn TAI THAM VOWEL SIGN MAI SAT +1A63..1A64;N # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA +1A65..1A6C;N # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW +1A6D..1A72;N # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI +1A73..1A7C;N # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN +1A7F;N # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT +1A80..1A89;N # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE +1A90..1A99;N # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE +1AA0..1AA6;N # Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA +1AA7;N # Lm TAI THAM SIGN MAI YAMOK +1AA8..1AAD;N # Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG +1AB0..1ABD;N # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE;N # Me COMBINING PARENTHESES OVERLAY +1ABF..1ACE;N # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T +1B00..1B03;N # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG +1B04;N # Mc BALINESE SIGN BISAH +1B05..1B33;N # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA +1B34;N # Mn BALINESE SIGN REREKAN +1B35;N # Mc BALINESE VOWEL SIGN TEDUNG +1B36..1B3A;N # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA +1B3B;N # Mc BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C;N # Mn BALINESE VOWEL SIGN LA LENGA +1B3D..1B41;N # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42;N # Mn BALINESE VOWEL SIGN PEPET +1B43..1B44;N # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG +1B45..1B4C;N # Lo [8] BALINESE LETTER KAF SASAK..BALINESE LETTER ARCHAIC JNYA +1B50..1B59;N # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE +1B5A..1B60;N # Po [7] BALINESE PANTI..BALINESE PAMENENG +1B61..1B6A;N # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE +1B6B..1B73;N # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +1B74..1B7C;N # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING +1B7D..1B7E;N # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG +1B80..1B81;N # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR +1B82;N # Mc SUNDANESE SIGN PANGWISAD +1B83..1BA0;N # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA +1BA1;N # Mc SUNDANESE CONSONANT SIGN PAMINGKAL +1BA2..1BA5;N # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU +1BA6..1BA7;N # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG +1BA8..1BA9;N # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG +1BAA;N # Mc SUNDANESE SIGN PAMAAEH +1BAB..1BAD;N # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAE..1BAF;N # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA +1BB0..1BB9;N # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE +1BBA..1BBF;N # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M +1BC0..1BE5;N # Lo [38] BATAK LETTER A..BATAK LETTER U +1BE6;N # Mn BATAK SIGN TOMPI +1BE7;N # Mc BATAK VOWEL SIGN E +1BE8..1BE9;N # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE +1BEA..1BEC;N # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O +1BED;N # Mn BATAK VOWEL SIGN KARO O +1BEE;N # Mc BATAK VOWEL SIGN U +1BEF..1BF1;N # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H +1BF2..1BF3;N # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN +1BFC..1BFF;N # Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT +1C00..1C23;N # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A +1C24..1C2B;N # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU +1C2C..1C33;N # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T +1C34..1C35;N # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG +1C36..1C37;N # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA +1C3B..1C3F;N # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK +1C40..1C49;N # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE +1C4D..1C4F;N # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA +1C50..1C59;N # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE +1C5A..1C77;N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH +1C78..1C7D;N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD +1C7E..1C7F;N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88;N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1C90..1CBA;N # Lu [43] GEORGIAN MTAVRULI CAPITAL LETTER AN..GEORGIAN MTAVRULI CAPITAL LETTER AIN +1CBD..1CBF;N # Lu [3] GEORGIAN MTAVRULI CAPITAL LETTER AEN..GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN +1CC0..1CC7;N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA +1CD0..1CD2;N # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA +1CD3;N # Po VEDIC SIGN NIHSHVASA +1CD4..1CE0;N # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA +1CE1;N # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA +1CE2..1CE8;N # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL +1CE9..1CEC;N # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL +1CED;N # Mn VEDIC SIGN TIRYAK +1CEE..1CF3;N # Lo [6] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ROTATED ARDHAVISARGA +1CF4;N # Mn VEDIC TONE CANDRA ABOVE +1CF5..1CF6;N # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7;N # Mc VEDIC SIGN ATIKRAMA +1CF8..1CF9;N # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1CFA;N # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA +1D00..1D2B;N # Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL +1D2C..1D6A;N # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI +1D6B..1D77;N # Ll [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G +1D78;N # Lm MODIFIER LETTER CYRILLIC EN +1D79..1D7F;N # Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE +1D80..1D9A;N # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +1D9B..1DBF;N # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA +1DC0..1DFF;N # Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1E00..1EFF;N # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP +1F00..1F15;N # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18..1F1D;N # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20..1F45;N # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48..1F4D;N # Lu [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50..1F57;N # Ll [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59;N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B;N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D;N # Lu GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F..1F7D;N # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA +1F80..1FB4;N # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6..1FBC;N # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD;N # Sk GREEK KORONIS +1FBE;N # Ll GREEK PROSGEGRAMMENI +1FBF..1FC1;N # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI +1FC2..1FC4;N # Ll [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6..1FCC;N # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD..1FCF;N # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI +1FD0..1FD3;N # Ll [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6..1FDB;N # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA +1FDD..1FDF;N # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI +1FE0..1FEC;N # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA +1FED..1FEF;N # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA +1FF2..1FF4;N # Ll [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6..1FFC;N # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD..1FFE;N # Sk [2] GREEK OXIA..GREEK DASIA +2000..200A;N # Zs [11] EN QUAD..HAIR SPACE +200B..200F;N # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK +2010;A # Pd HYPHEN +2011..2012;N # Pd [2] NON-BREAKING HYPHEN..FIGURE DASH +2013..2015;A # Pd [3] EN DASH..HORIZONTAL BAR +2016;A # Po DOUBLE VERTICAL LINE +2017;N # Po DOUBLE LOW LINE +2018;A # Pi LEFT SINGLE QUOTATION MARK +2019;A # Pf RIGHT SINGLE QUOTATION MARK +201A;N # Ps SINGLE LOW-9 QUOTATION MARK +201B;N # Pi SINGLE HIGH-REVERSED-9 QUOTATION MARK +201C;A # Pi LEFT DOUBLE QUOTATION MARK +201D;A # Pf RIGHT DOUBLE QUOTATION MARK +201E;N # Ps DOUBLE LOW-9 QUOTATION MARK +201F;N # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020..2022;A # Po [3] DAGGER..BULLET +2023;N # Po TRIANGULAR BULLET +2024..2027;A # Po [4] ONE DOT LEADER..HYPHENATION POINT +2028;N # Zl LINE SEPARATOR +2029;N # Zp PARAGRAPH SEPARATOR +202A..202E;N # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +202F;N # Zs NARROW NO-BREAK SPACE +2030;A # Po PER MILLE SIGN +2031;N # Po PER TEN THOUSAND SIGN +2032..2033;A # Po [2] PRIME..DOUBLE PRIME +2034;N # Po TRIPLE PRIME +2035;A # Po REVERSED PRIME +2036..2038;N # Po [3] REVERSED DOUBLE PRIME..CARET +2039;N # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A;N # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B;A # Po REFERENCE MARK +203C..203D;N # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG +203E;A # Po OVERLINE +203F..2040;N # Pc [2] UNDERTIE..CHARACTER TIE +2041..2043;N # Po [3] CARET INSERTION POINT..HYPHEN BULLET +2044;N # Sm FRACTION SLASH +2045;N # Ps LEFT SQUARE BRACKET WITH QUILL +2046;N # Pe RIGHT SQUARE BRACKET WITH QUILL +2047..2051;N # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY +2052;N # Sm COMMERCIAL MINUS SIGN +2053;N # Po SWUNG DASH +2054;N # Pc INVERTED UNDERTIE +2055..205E;N # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS +205F;N # Zs MEDIUM MATHEMATICAL SPACE +2060..2064;N # Cf [5] WORD JOINER..INVISIBLE PLUS +2066..206F;N # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES +2070;N # No SUPERSCRIPT ZERO +2071;N # Lm SUPERSCRIPT LATIN SMALL LETTER I +2074;A # No SUPERSCRIPT FOUR +2075..2079;N # No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE +207A..207C;N # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN +207D;N # Ps SUPERSCRIPT LEFT PARENTHESIS +207E;N # Pe SUPERSCRIPT RIGHT PARENTHESIS +207F;A # Lm SUPERSCRIPT LATIN SMALL LETTER N +2080;N # No SUBSCRIPT ZERO +2081..2084;A # No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR +2085..2089;N # No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE +208A..208C;N # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN +208D;N # Ps SUBSCRIPT LEFT PARENTHESIS +208E;N # Pe SUBSCRIPT RIGHT PARENTHESIS +2090..209C;N # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T +20A0..20A8;N # Sc [9] EURO-CURRENCY SIGN..RUPEE SIGN +20A9;H # Sc WON SIGN +20AA..20AB;N # Sc [2] NEW SHEQEL SIGN..DONG SIGN +20AC;A # Sc EURO SIGN +20AD..20C0;N # Sc [20] KIP SIGN..SOM SIGN +20D0..20DC;N # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE +20DD..20E0;N # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH +20E1;N # Mn COMBINING LEFT RIGHT ARROW ABOVE +20E2..20E4;N # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE +20E5..20F0;N # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE +2100..2101;N # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT +2102;N # Lu DOUBLE-STRUCK CAPITAL C +2103;A # So DEGREE CELSIUS +2104;N # So CENTRE LINE SYMBOL +2105;A # So CARE OF +2106;N # So CADA UNA +2107;N # Lu EULER CONSTANT +2108;N # So SCRUPLE +2109;A # So DEGREE FAHRENHEIT +210A..2112;N # L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L +2113;A # Ll SCRIPT SMALL L +2114;N # So L B BAR SYMBOL +2115;N # Lu DOUBLE-STRUCK CAPITAL N +2116;A # So NUMERO SIGN +2117;N # So SOUND RECORDING COPYRIGHT +2118;N # Sm SCRIPT CAPITAL P +2119..211D;N # Lu [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R +211E..2120;N # So [3] PRESCRIPTION TAKE..SERVICE MARK +2121..2122;A # So [2] TELEPHONE SIGN..TRADE MARK SIGN +2123;N # So VERSICLE +2124;N # Lu DOUBLE-STRUCK CAPITAL Z +2125;N # So OUNCE SIGN +2126;A # Lu OHM SIGN +2127;N # So INVERTED OHM SIGN +2128;N # Lu BLACK-LETTER CAPITAL Z +2129;N # So TURNED GREEK SMALL LETTER IOTA +212A;N # Lu KELVIN SIGN +212B;A # Lu ANGSTROM SIGN +212C..212D;N # Lu [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C +212E;N # So ESTIMATED SYMBOL +212F..2134;N # L& [6] SCRIPT SMALL E..SCRIPT SMALL O +2135..2138;N # Lo [4] ALEF SYMBOL..DALET SYMBOL +2139;N # Ll INFORMATION SOURCE +213A..213B;N # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN +213C..213F;N # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI +2140..2144;N # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y +2145..2149;N # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J +214A;N # So PROPERTY LINE +214B;N # Sm TURNED AMPERSAND +214C..214D;N # So [2] PER SIGN..AKTIESELSKAB +214E;N # Ll TURNED SMALL F +214F;N # So SYMBOL FOR SAMARITAN SOURCE +2150..2152;N # No [3] VULGAR FRACTION ONE SEVENTH..VULGAR FRACTION ONE TENTH +2153..2154;A # No [2] VULGAR FRACTION ONE THIRD..VULGAR FRACTION TWO THIRDS +2155..215A;N # No [6] VULGAR FRACTION ONE FIFTH..VULGAR FRACTION FIVE SIXTHS +215B..215E;A # No [4] VULGAR FRACTION ONE EIGHTH..VULGAR FRACTION SEVEN EIGHTHS +215F;N # No FRACTION NUMERATOR ONE +2160..216B;A # Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE +216C..216F;N # Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND +2170..2179;A # Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN +217A..2182;N # Nl [9] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL TEN THOUSAND +2183..2184;N # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C +2185..2188;N # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND +2189;A # No VULGAR FRACTION ZERO THIRDS +218A..218B;N # So [2] TURNED DIGIT TWO..TURNED DIGIT THREE +2190..2194;A # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW +2195..2199;A # So [5] UP DOWN ARROW..SOUTH WEST ARROW +219A..219B;N # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE +219C..219F;N # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW +21A0;N # Sm RIGHTWARDS TWO HEADED ARROW +21A1..21A2;N # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL +21A3;N # Sm RIGHTWARDS ARROW WITH TAIL +21A4..21A5;N # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR +21A6;N # Sm RIGHTWARDS ARROW FROM BAR +21A7..21AD;N # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW +21AE;N # Sm LEFT RIGHT ARROW WITH STROKE +21AF..21B7;N # So [9] DOWNWARDS ZIGZAG ARROW..CLOCKWISE TOP SEMICIRCLE ARROW +21B8..21B9;A # So [2] NORTH WEST ARROW TO LONG BAR..LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR +21BA..21CD;N # So [20] ANTICLOCKWISE OPEN CIRCLE ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE +21CE..21CF;N # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE +21D0..21D1;N # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW +21D2;A # Sm RIGHTWARDS DOUBLE ARROW +21D3;N # So DOWNWARDS DOUBLE ARROW +21D4;A # Sm LEFT RIGHT DOUBLE ARROW +21D5..21E6;N # So [18] UP DOWN DOUBLE ARROW..LEFTWARDS WHITE ARROW +21E7;A # So UPWARDS WHITE ARROW +21E8..21F3;N # So [12] RIGHTWARDS WHITE ARROW..UP DOWN WHITE ARROW +21F4..21FF;N # Sm [12] RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW +2200;A # Sm FOR ALL +2201;N # Sm COMPLEMENT +2202..2203;A # Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS +2204..2206;N # Sm [3] THERE DOES NOT EXIST..INCREMENT +2207..2208;A # Sm [2] NABLA..ELEMENT OF +2209..220A;N # Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF +220B;A # Sm CONTAINS AS MEMBER +220C..220E;N # Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF +220F;A # Sm N-ARY PRODUCT +2210;N # Sm N-ARY COPRODUCT +2211;A # Sm N-ARY SUMMATION +2212..2214;N # Sm [3] MINUS SIGN..DOT PLUS +2215;A # Sm DIVISION SLASH +2216..2219;N # Sm [4] SET MINUS..BULLET OPERATOR +221A;A # Sm SQUARE ROOT +221B..221C;N # Sm [2] CUBE ROOT..FOURTH ROOT +221D..2220;A # Sm [4] PROPORTIONAL TO..ANGLE +2221..2222;N # Sm [2] MEASURED ANGLE..SPHERICAL ANGLE +2223;A # Sm DIVIDES +2224;N # Sm DOES NOT DIVIDE +2225;A # Sm PARALLEL TO +2226;N # Sm NOT PARALLEL TO +2227..222C;A # Sm [6] LOGICAL AND..DOUBLE INTEGRAL +222D;N # Sm TRIPLE INTEGRAL +222E;A # Sm CONTOUR INTEGRAL +222F..2233;N # Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL +2234..2237;A # Sm [4] THEREFORE..PROPORTION +2238..223B;N # Sm [4] DOT MINUS..HOMOTHETIC +223C..223D;A # Sm [2] TILDE OPERATOR..REVERSED TILDE +223E..2247;N # Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2248;A # Sm ALMOST EQUAL TO +2249..224B;N # Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE +224C;A # Sm ALL EQUAL TO +224D..2251;N # Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO +2252;A # Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF +2253..225F;N # Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO +2260..2261;A # Sm [2] NOT EQUAL TO..IDENTICAL TO +2262..2263;N # Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO +2264..2267;A # Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO +2268..2269;N # Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO +226A..226B;A # Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN +226C..226D;N # Sm [2] BETWEEN..NOT EQUIVALENT TO +226E..226F;A # Sm [2] NOT LESS-THAN..NOT GREATER-THAN +2270..2281;N # Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED +2282..2283;A # Sm [2] SUBSET OF..SUPERSET OF +2284..2285;N # Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF +2286..2287;A # Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO +2288..2294;N # Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP +2295;A # Sm CIRCLED PLUS +2296..2298;N # Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH +2299;A # Sm CIRCLED DOT OPERATOR +229A..22A4;N # Sm [11] CIRCLED RING OPERATOR..DOWN TACK +22A5;A # Sm UP TACK +22A6..22BE;N # Sm [25] ASSERTION..RIGHT ANGLE WITH ARC +22BF;A # Sm RIGHT TRIANGLE +22C0..22FF;N # Sm [64] N-ARY LOGICAL AND..Z NOTATION BAG MEMBERSHIP +2300..2307;N # So [8] DIAMETER SIGN..WAVY LINE +2308;N # Ps LEFT CEILING +2309;N # Pe RIGHT CEILING +230A;N # Ps LEFT FLOOR +230B;N # Pe RIGHT FLOOR +230C..2311;N # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE +2312;A # So ARC +2313..2319;N # So [7] SEGMENT..TURNED NOT SIGN +231A..231B;W # So [2] WATCH..HOURGLASS +231C..231F;N # So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER +2320..2321;N # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL +2322..2328;N # So [7] FROWN..KEYBOARD +2329;W # Ps LEFT-POINTING ANGLE BRACKET +232A;W # Pe RIGHT-POINTING ANGLE BRACKET +232B..237B;N # So [81] ERASE TO THE LEFT..NOT CHECK MARK +237C;N # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D..239A;N # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL +239B..23B3;N # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM +23B4..23DB;N # So [40] TOP SQUARE BRACKET..FUSE +23DC..23E1;N # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET +23E2..23E8;N # So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL +23E9..23EC;W # So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE +23ED..23EF;N # So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR +23F0;W # So ALARM CLOCK +23F1..23F2;N # So [2] STOPWATCH..TIMER CLOCK +23F3;W # So HOURGLASS WITH FLOWING SAND +23F4..23FF;N # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL +2400..2426;N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +2440..244A;N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH +2460..249B;A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP +249C..24E9;A # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z +24EA;N # No CIRCLED DIGIT ZERO +24EB..24FF;A # No [21] NEGATIVE CIRCLED NUMBER ELEVEN..NEGATIVE CIRCLED DIGIT ZERO +2500..254B;A # So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL +254C..254F;N # So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL +2550..2573;A # So [36] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT DIAGONAL CROSS +2574..257F;N # So [12] BOX DRAWINGS LIGHT LEFT..BOX DRAWINGS HEAVY UP AND LIGHT DOWN +2580..258F;A # So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK +2590..2591;N # So [2] RIGHT HALF BLOCK..LIGHT SHADE +2592..2595;A # So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK +2596..259F;N # So [10] QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT +25A0..25A1;A # So [2] BLACK SQUARE..WHITE SQUARE +25A2;N # So WHITE SQUARE WITH ROUNDED CORNERS +25A3..25A9;A # So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL +25AA..25B1;N # So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM +25B2..25B3;A # So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE +25B4..25B5;N # So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE +25B6;A # So BLACK RIGHT-POINTING TRIANGLE +25B7;A # Sm WHITE RIGHT-POINTING TRIANGLE +25B8..25BB;N # So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER +25BC..25BD;A # So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE +25BE..25BF;N # So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE +25C0;A # So BLACK LEFT-POINTING TRIANGLE +25C1;A # Sm WHITE LEFT-POINTING TRIANGLE +25C2..25C5;N # So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER +25C6..25C8;A # So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND +25C9..25CA;N # So [2] FISHEYE..LOZENGE +25CB;A # So WHITE CIRCLE +25CC..25CD;N # So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL +25CE..25D1;A # So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK +25D2..25E1;N # So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE +25E2..25E5;A # So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE +25E6..25EE;N # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK +25EF;A # So LARGE CIRCLE +25F0..25F7;N # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8..25FC;N # Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE +25FD..25FE;W # Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE +25FF;N # Sm LOWER RIGHT TRIANGLE +2600..2604;N # So [5] BLACK SUN WITH RAYS..COMET +2605..2606;A # So [2] BLACK STAR..WHITE STAR +2607..2608;N # So [2] LIGHTNING..THUNDERSTORM +2609;A # So SUN +260A..260D;N # So [4] ASCENDING NODE..OPPOSITION +260E..260F;A # So [2] BLACK TELEPHONE..WHITE TELEPHONE +2610..2613;N # So [4] BALLOT BOX..SALTIRE +2614..2615;W # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE +2616..261B;N # So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX +261C;A # So WHITE LEFT POINTING INDEX +261D;N # So WHITE UP POINTING INDEX +261E;A # So WHITE RIGHT POINTING INDEX +261F..263F;N # So [33] WHITE DOWN POINTING INDEX..MERCURY +2640;A # So FEMALE SIGN +2641;N # So EARTH +2642;A # So MALE SIGN +2643..2647;N # So [5] JUPITER..PLUTO +2648..2653;W # So [12] ARIES..PISCES +2654..265F;N # So [12] WHITE CHESS KING..BLACK CHESS PAWN +2660..2661;A # So [2] BLACK SPADE SUIT..WHITE HEART SUIT +2662;N # So WHITE DIAMOND SUIT +2663..2665;A # So [3] BLACK CLUB SUIT..BLACK HEART SUIT +2666;N # So BLACK DIAMOND SUIT +2667..266A;A # So [4] WHITE CLUB SUIT..EIGHTH NOTE +266B;N # So BEAMED EIGHTH NOTES +266C..266D;A # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN +266E;N # So MUSIC NATURAL SIGN +266F;A # Sm MUSIC SHARP SIGN +2670..267E;N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN +267F;W # So WHEELCHAIR SYMBOL +2680..2692;N # So [19] DIE FACE-1..HAMMER AND PICK +2693;W # So ANCHOR +2694..269D;N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR +269E..269F;A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT +26A0;N # So WARNING SIGN +26A1;W # So HIGH VOLTAGE SIGN +26A2..26A9;N # So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN +26AA..26AB;W # So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE +26AC..26BC;N # So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE +26BD..26BE;W # So [2] SOCCER BALL..BASEBALL +26BF;A # So SQUARED KEY +26C0..26C3;N # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING +26C4..26C5;W # So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD +26C6..26CD;A # So [8] RAIN..DISABLED CAR +26CE;W # So OPHIUCHUS +26CF..26D3;A # So [5] PICK..CHAINS +26D4;W # So NO ENTRY +26D5..26E1;A # So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2 +26E2;N # So ASTRONOMICAL SYMBOL FOR URANUS +26E3;A # So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE +26E4..26E7;N # So [4] PENTAGRAM..INVERTED PENTAGRAM +26E8..26E9;A # So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE +26EA;W # So CHURCH +26EB..26F1;A # So [7] CASTLE..UMBRELLA ON GROUND +26F2..26F3;W # So [2] FOUNTAIN..FLAG IN HOLE +26F4;A # So FERRY +26F5;W # So SAILBOAT +26F6..26F9;A # So [4] SQUARE FOUR CORNERS..PERSON WITH BALL +26FA;W # So TENT +26FB..26FC;A # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL +26FD;W # So FUEL PUMP +26FE..26FF;A # So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700..2704;N # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS +2705;W # So WHITE HEAVY CHECK MARK +2706..2709;N # So [4] TELEPHONE LOCATION SIGN..ENVELOPE +270A..270B;W # So [2] RAISED FIST..RAISED HAND +270C..2727;N # So [28] VICTORY HAND..WHITE FOUR POINTED STAR +2728;W # So SPARKLES +2729..273C;N # So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK +273D;A # So HEAVY TEARDROP-SPOKED ASTERISK +273E..274B;N # So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274C;W # So CROSS MARK +274D;N # So SHADOWED WHITE CIRCLE +274E;W # So NEGATIVE SQUARED CROSS MARK +274F..2752;N # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE +2753..2755;W # So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT +2756;N # So BLACK DIAMOND MINUS WHITE X +2757;W # So HEAVY EXCLAMATION MARK SYMBOL +2758..2767;N # So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET +2768;N # Ps MEDIUM LEFT PARENTHESIS ORNAMENT +2769;N # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT +276A;N # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +276B;N # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +276C;N # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +276D;N # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +276E;N # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +276F;N # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +2770;N # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +2771;N # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +2772;N # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +2773;N # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +2774;N # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT +2775;N # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT +2776..277F;A # No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN +2780..2793;N # No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN +2794;N # So HEAVY WIDE-HEADED RIGHTWARDS ARROW +2795..2797;W # So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN +2798..27AF;N # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B0;W # So CURLY LOOP +27B1..27BE;N # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW +27BF;W # So DOUBLE CURLY LOOP +27C0..27C4;N # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET +27C5;N # Ps LEFT S-SHAPED BAG DELIMITER +27C6;N # Pe RIGHT S-SHAPED BAG DELIMITER +27C7..27E5;N # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK +27E6;Na # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7;Na # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8;Na # Ps MATHEMATICAL LEFT ANGLE BRACKET +27E9;Na # Pe MATHEMATICAL RIGHT ANGLE BRACKET +27EA;Na # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB;Na # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC;Na # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET +27ED;Na # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET +27EE;N # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS +27EF;N # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS +27F0..27FF;N # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW +2800..28FF;N # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 +2900..297F;N # Sm [128] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..DOWN FISH TAIL +2980..2982;N # Sm [3] TRIPLE VERTICAL BAR DELIMITER..Z NOTATION TYPE COLON +2983;N # Ps LEFT WHITE CURLY BRACKET +2984;N # Pe RIGHT WHITE CURLY BRACKET +2985;Na # Ps LEFT WHITE PARENTHESIS +2986;Na # Pe RIGHT WHITE PARENTHESIS +2987;N # Ps Z NOTATION LEFT IMAGE BRACKET +2988;N # Pe Z NOTATION RIGHT IMAGE BRACKET +2989;N # Ps Z NOTATION LEFT BINDING BRACKET +298A;N # Pe Z NOTATION RIGHT BINDING BRACKET +298B;N # Ps LEFT SQUARE BRACKET WITH UNDERBAR +298C;N # Pe RIGHT SQUARE BRACKET WITH UNDERBAR +298D;N # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E;N # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F;N # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990;N # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991;N # Ps LEFT ANGLE BRACKET WITH DOT +2992;N # Pe RIGHT ANGLE BRACKET WITH DOT +2993;N # Ps LEFT ARC LESS-THAN BRACKET +2994;N # Pe RIGHT ARC GREATER-THAN BRACKET +2995;N # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET +2996;N # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET +2997;N # Ps LEFT BLACK TORTOISE SHELL BRACKET +2998;N # Pe RIGHT BLACK TORTOISE SHELL BRACKET +2999..29D7;N # Sm [63] DOTTED FENCE..BLACK HOURGLASS +29D8;N # Ps LEFT WIGGLY FENCE +29D9;N # Pe RIGHT WIGGLY FENCE +29DA;N # Ps LEFT DOUBLE WIGGLY FENCE +29DB;N # Pe RIGHT DOUBLE WIGGLY FENCE +29DC..29FB;N # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS +29FC;N # Ps LEFT-POINTING CURVED ANGLE BRACKET +29FD;N # Pe RIGHT-POINTING CURVED ANGLE BRACKET +29FE..29FF;N # Sm [2] TINY..MINY +2A00..2AFF;N # Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR +2B00..2B1A;N # So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE +2B1B..2B1C;W # So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE +2B1D..2B2F;N # So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE +2B30..2B44;N # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET +2B45..2B46;N # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW +2B47..2B4C;N # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4D..2B4F;N # So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW +2B50;W # So WHITE MEDIUM STAR +2B51..2B54;N # So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON +2B55;W # So HEAVY LARGE CIRCLE +2B56..2B59;A # So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE +2B5A..2B73;N # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B76..2B95;N # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW +2B97..2BFF;N # So [105] SYMBOL FOR TYPE A ELECTRONICS..HELLSCHREIBER PAUSE SYMBOL +2C00..2C5F;N # L& [96] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC SMALL LETTER CAUDATE CHRIVI +2C60..2C7B;N # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E +2C7C..2C7D;N # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V +2C7E..2C7F;N # Lu [2] LATIN CAPITAL LETTER S WITH SWASH TAIL..LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80..2CE4;N # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI +2CE5..2CEA;N # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA +2CEB..2CEE;N # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA +2CEF..2CF1;N # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS +2CF2..2CF3;N # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI +2CF9..2CFC;N # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER +2CFD;N # No COPTIC FRACTION ONE HALF +2CFE..2CFF;N # Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER +2D00..2D25;N # Ll [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE +2D27;N # Ll GEORGIAN SMALL LETTER YN +2D2D;N # Ll GEORGIAN SMALL LETTER AEN +2D30..2D67;N # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO +2D6F;N # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK +2D70;N # Po TIFINAGH SEPARATOR MARK +2D7F;N # Mn TIFINAGH CONSONANT JOINER +2D80..2D96;N # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE +2DA0..2DA6;N # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO +2DA8..2DAE;N # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO +2DB0..2DB6;N # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO +2DB8..2DBE;N # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO +2DC0..2DC6;N # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO +2DC8..2DCE;N # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO +2DD0..2DD6;N # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO +2DD8..2DDE;N # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO +2DE0..2DFF;N # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +2E00..2E01;N # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER +2E02;N # Pi LEFT SUBSTITUTION BRACKET +2E03;N # Pf RIGHT SUBSTITUTION BRACKET +2E04;N # Pi LEFT DOTTED SUBSTITUTION BRACKET +2E05;N # Pf RIGHT DOTTED SUBSTITUTION BRACKET +2E06..2E08;N # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER +2E09;N # Pi LEFT TRANSPOSITION BRACKET +2E0A;N # Pf RIGHT TRANSPOSITION BRACKET +2E0B;N # Po RAISED SQUARE +2E0C;N # Pi LEFT RAISED OMISSION BRACKET +2E0D;N # Pf RIGHT RAISED OMISSION BRACKET +2E0E..2E16;N # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE +2E17;N # Pd DOUBLE OBLIQUE HYPHEN +2E18..2E19;N # Po [2] INVERTED INTERROBANG..PALM BRANCH +2E1A;N # Pd HYPHEN WITH DIAERESIS +2E1B;N # Po TILDE WITH RING ABOVE +2E1C;N # Pi LEFT LOW PARAPHRASE BRACKET +2E1D;N # Pf RIGHT LOW PARAPHRASE BRACKET +2E1E..2E1F;N # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW +2E20;N # Pi LEFT VERTICAL BAR WITH QUILL +2E21;N # Pf RIGHT VERTICAL BAR WITH QUILL +2E22;N # Ps TOP LEFT HALF BRACKET +2E23;N # Pe TOP RIGHT HALF BRACKET +2E24;N # Ps BOTTOM LEFT HALF BRACKET +2E25;N # Pe BOTTOM RIGHT HALF BRACKET +2E26;N # Ps LEFT SIDEWAYS U BRACKET +2E27;N # Pe RIGHT SIDEWAYS U BRACKET +2E28;N # Ps LEFT DOUBLE PARENTHESIS +2E29;N # Pe RIGHT DOUBLE PARENTHESIS +2E2A..2E2E;N # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK +2E2F;N # Lm VERTICAL TILDE +2E30..2E39;N # Po [10] RING POINT..TOP HALF SECTION SIGN +2E3A..2E3B;N # Pd [2] TWO-EM DASH..THREE-EM DASH +2E3C..2E3F;N # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM +2E40;N # Pd DOUBLE HYPHEN +2E41;N # Po REVERSED COMMA +2E42;N # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E4F;N # Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER +2E50..2E51;N # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR +2E52..2E54;N # Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK +2E55;N # Ps LEFT SQUARE BRACKET WITH STROKE +2E56;N # Pe RIGHT SQUARE BRACKET WITH STROKE +2E57;N # Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE +2E58;N # Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE +2E59;N # Ps TOP HALF LEFT PARENTHESIS +2E5A;N # Pe TOP HALF RIGHT PARENTHESIS +2E5B;N # Ps BOTTOM HALF LEFT PARENTHESIS +2E5C;N # Pe BOTTOM HALF RIGHT PARENTHESIS +2E5D;N # Pd OBLIQUE HYPHEN +2E80..2E99;W # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP +2E9B..2EF3;W # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE +2F00..2FD5;W # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE +2FF0..2FFB;W # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +3000;F # Zs IDEOGRAPHIC SPACE +3001..3003;W # Po [3] IDEOGRAPHIC COMMA..DITTO MARK +3004;W # So JAPANESE INDUSTRIAL STANDARD SYMBOL +3005;W # Lm IDEOGRAPHIC ITERATION MARK +3006;W # Lo IDEOGRAPHIC CLOSING MARK +3007;W # Nl IDEOGRAPHIC NUMBER ZERO +3008;W # Ps LEFT ANGLE BRACKET +3009;W # Pe RIGHT ANGLE BRACKET +300A;W # Ps LEFT DOUBLE ANGLE BRACKET +300B;W # Pe RIGHT DOUBLE ANGLE BRACKET +300C;W # Ps LEFT CORNER BRACKET +300D;W # Pe RIGHT CORNER BRACKET +300E;W # Ps LEFT WHITE CORNER BRACKET +300F;W # Pe RIGHT WHITE CORNER BRACKET +3010;W # Ps LEFT BLACK LENTICULAR BRACKET +3011;W # Pe RIGHT BLACK LENTICULAR BRACKET +3012..3013;W # So [2] POSTAL MARK..GETA MARK +3014;W # Ps LEFT TORTOISE SHELL BRACKET +3015;W # Pe RIGHT TORTOISE SHELL BRACKET +3016;W # Ps LEFT WHITE LENTICULAR BRACKET +3017;W # Pe RIGHT WHITE LENTICULAR BRACKET +3018;W # Ps LEFT WHITE TORTOISE SHELL BRACKET +3019;W # Pe RIGHT WHITE TORTOISE SHELL BRACKET +301A;W # Ps LEFT WHITE SQUARE BRACKET +301B;W # Pe RIGHT WHITE SQUARE BRACKET +301C;W # Pd WAVE DASH +301D;W # Ps REVERSED DOUBLE PRIME QUOTATION MARK +301E..301F;W # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK +3020;W # So POSTAL MARK FACE +3021..3029;W # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE +302A..302D;W # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK +302E..302F;W # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK +3030;W # Pd WAVY DASH +3031..3035;W # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF +3036..3037;W # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +3038..303A;W # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY +303B;W # Lm VERTICAL IDEOGRAPHIC ITERATION MARK +303C;W # Lo MASU MARK +303D;W # Po PART ALTERNATION MARK +303E;W # So IDEOGRAPHIC VARIATION INDICATOR +303F;N # So IDEOGRAPHIC HALF FILL SPACE +3041..3096;W # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE +3099..309A;W # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309B..309C;W # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D..309E;W # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +309F;W # Lo HIRAGANA DIGRAPH YORI +30A0;W # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN +30A1..30FA;W # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO +30FB;W # Po KATAKANA MIDDLE DOT +30FC..30FE;W # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK +30FF;W # Lo KATAKANA DIGRAPH KOTO +3105..312F;W # Lo [43] BOPOMOFO LETTER B..BOPOMOFO LETTER NN +3131..318E;W # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE +3190..3191;W # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK +3192..3195;W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK +3196..319F;W # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK +31A0..31BF;W # Lo [32] BOPOMOFO LETTER BU..BOPOMOFO LETTER AH +31C0..31E3;W # So [36] CJK STROKE T..CJK STROKE Q +31F0..31FF;W # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO +3200..321E;W # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU +3220..3229;W # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN +322A..3247;W # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO +3248..324F;A # No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE +3250;W # So PARTNERSHIP SIGN +3251..325F;W # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE +3260..327F;W # So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL +3280..3289;W # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN +328A..32B0;W # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT +32B1..32BF;W # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY +32C0..32FF;W # So [64] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..SQUARE ERA NAME REIWA +3300..33FF;W # So [256] SQUARE APAATO..SQUARE GAL +3400..4DBF;W # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF +4DC0..4DFF;N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION +4E00..9FFF;W # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF +A000..A014;W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E +A015;W # Lm YI SYLLABLE WU +A016..A48C;W # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR +A490..A4C6;W # So [55] YI RADICAL QOT..YI RADICAL KE +A4D0..A4F7;N # Lo [40] LISU LETTER BA..LISU LETTER OE +A4F8..A4FD;N # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU +A4FE..A4FF;N # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP +A500..A60B;N # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG +A60C;N # Lm VAI SYLLABLE LENGTHENER +A60D..A60F;N # Po [3] VAI COMMA..VAI QUESTION MARK +A610..A61F;N # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG +A620..A629;N # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE +A62A..A62B;N # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO +A640..A66D;N # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O +A66E;N # Lo CYRILLIC LETTER MULTIOCULAR O +A66F;N # Mn COMBINING CYRILLIC VZMET +A670..A672;N # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN +A673;N # Po SLAVONIC ASTERISK +A674..A67D;N # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK +A67E;N # Po CYRILLIC KAVYKA +A67F;N # Lm CYRILLIC PAYEROK +A680..A69B;N # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O +A69C..A69D;N # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN +A69E..A69F;N # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E +A6A0..A6E5;N # Lo [70] BAMUM LETTER A..BAMUM LETTER KI +A6E6..A6EF;N # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM +A6F0..A6F1;N # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS +A6F2..A6F7;N # Po [6] BAMUM NJAEMLI..BAMUM QUESTION MARK +A700..A716;N # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717..A71F;N # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721;N # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE +A722..A76F;N # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON +A770;N # Lm MODIFIER LETTER US +A771..A787;N # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T +A788;N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A;N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN +A78B..A78E;N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +A78F;N # Lo LATIN LETTER SINOLOGICAL DOT +A790..A7CA;N # L& [59] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY +A7D0..A7D1;N # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G +A7D3;N # Ll LATIN SMALL LETTER DOUBLE THORN +A7D5..A7D9;N # L& [5] LATIN SMALL LETTER DOUBLE WYNN..LATIN SMALL LETTER SIGMOID S +A7F2..A7F4;N # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q +A7F5..A7F6;N # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H +A7F7;N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I +A7F8..A7F9;N # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE +A7FA;N # Ll LATIN LETTER SMALL CAPITAL TURNED M +A7FB..A7FF;N # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M +A800..A801;N # Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I +A802;N # Mn SYLOTI NAGRI SIGN DVISVARA +A803..A805;N # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O +A806;N # Mn SYLOTI NAGRI SIGN HASANTA +A807..A80A;N # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO +A80B;N # Mn SYLOTI NAGRI SIGN ANUSVARA +A80C..A822;N # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO +A823..A824;N # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I +A825..A826;N # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E +A827;N # Mc SYLOTI NAGRI VOWEL SIGN OO +A828..A82B;N # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4 +A82C;N # Mn SYLOTI NAGRI SIGN ALTERNATE HASANTA +A830..A835;N # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS +A836..A837;N # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK +A838;N # Sc NORTH INDIC RUPEE MARK +A839;N # So NORTH INDIC QUANTITY MARK +A840..A873;N # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU +A874..A877;N # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD +A880..A881;N # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA +A882..A8B3;N # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA +A8B4..A8C3;N # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU +A8C4..A8C5;N # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU +A8CE..A8CF;N # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A8D0..A8D9;N # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE +A8E0..A8F1;N # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA +A8F2..A8F7;N # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA +A8F8..A8FA;N # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET +A8FB;N # Lo DEVANAGARI HEADSTROKE +A8FC;N # Po DEVANAGARI SIGN SIDDHAM +A8FD..A8FE;N # Lo [2] DEVANAGARI JAIN OM..DEVANAGARI LETTER AY +A8FF;N # Mn DEVANAGARI VOWEL SIGN AY +A900..A909;N # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE +A90A..A925;N # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO +A926..A92D;N # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU +A92E..A92F;N # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA +A930..A946;N # Lo [23] REJANG LETTER KA..REJANG LETTER A +A947..A951;N # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R +A952..A953;N # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA +A95F;N # Po REJANG SECTION MARK +A960..A97C;W # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH +A980..A982;N # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR +A983;N # Mc JAVANESE SIGN WIGNYAN +A984..A9B2;N # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA +A9B3;N # Mn JAVANESE SIGN CECAK TELU +A9B4..A9B5;N # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG +A9B6..A9B9;N # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT +A9BA..A9BB;N # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE +A9BC..A9BD;N # Mn [2] JAVANESE VOWEL SIGN PEPET..JAVANESE CONSONANT SIGN KERET +A9BE..A9C0;N # Mc [3] JAVANESE CONSONANT SIGN PENGKAL..JAVANESE PANGKON +A9C1..A9CD;N # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH +A9CF;N # Lm JAVANESE PANGRANGKEP +A9D0..A9D9;N # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE +A9DE..A9DF;N # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN +A9E0..A9E4;N # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA +A9E5;N # Mn MYANMAR SIGN SHAN SAW +A9E6;N # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION +A9E7..A9EF;N # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA +A9F0..A9F9;N # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE +A9FA..A9FE;N # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA +AA00..AA28;N # Lo [41] CHAM LETTER A..CHAM LETTER HA +AA29..AA2E;N # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE +AA2F..AA30;N # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI +AA31..AA32;N # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE +AA33..AA34;N # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA +AA35..AA36;N # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA +AA40..AA42;N # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG +AA43;N # Mn CHAM CONSONANT SIGN FINAL NG +AA44..AA4B;N # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS +AA4C;N # Mn CHAM CONSONANT SIGN FINAL M +AA4D;N # Mc CHAM CONSONANT SIGN FINAL H +AA50..AA59;N # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE +AA5C..AA5F;N # Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA +AA60..AA6F;N # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA +AA70;N # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION +AA71..AA76;N # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM +AA77..AA79;N # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO +AA7A;N # Lo MYANMAR LETTER AITON RA +AA7B;N # Mc MYANMAR SIGN PAO KAREN TONE +AA7C;N # Mn MYANMAR SIGN TAI LAING TONE-2 +AA7D;N # Mc MYANMAR SIGN TAI LAING TONE-5 +AA7E..AA7F;N # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA +AA80..AAAF;N # Lo [48] TAI VIET LETTER LOW KO..TAI VIET LETTER HIGH O +AAB0;N # Mn TAI VIET MAI KANG +AAB1;N # Lo TAI VIET VOWEL AA +AAB2..AAB4;N # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U +AAB5..AAB6;N # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O +AAB7..AAB8;N # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA +AAB9..AABD;N # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN +AABE..AABF;N # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK +AAC0;N # Lo TAI VIET TONE MAI NUENG +AAC1;N # Mn TAI VIET TONE MAI THO +AAC2;N # Lo TAI VIET TONE MAI SONG +AADB..AADC;N # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG +AADD;N # Lm TAI VIET SYMBOL SAM +AADE..AADF;N # Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI +AAE0..AAEA;N # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA +AAEB;N # Mc MEETEI MAYEK VOWEL SIGN II +AAEC..AAED;N # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI +AAEE..AAEF;N # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU +AAF0..AAF1;N # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +AAF2;N # Lo MEETEI MAYEK ANJI +AAF3..AAF4;N # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK +AAF5;N # Mc MEETEI MAYEK VOWEL SIGN VISARGA +AAF6;N # Mn MEETEI MAYEK VIRAMA +AB01..AB06;N # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO +AB09..AB0E;N # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO +AB11..AB16;N # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO +AB20..AB26;N # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO +AB28..AB2E;N # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO +AB30..AB5A;N # Ll [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5B;N # Sk MODIFIER BREVE WITH INVERTED BREVE +AB5C..AB5F;N # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB60..AB68;N # Ll [9] LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER TURNED R WITH MIDDLE TILDE +AB69;N # Lm MODIFIER LETTER SMALL TURNED W +AB6A..AB6B;N # Sk [2] MODIFIER LETTER LEFT TACK..MODIFIER LETTER RIGHT TACK +AB70..ABBF;N # Ll [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA +ABC0..ABE2;N # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM +ABE3..ABE4;N # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP +ABE5;N # Mn MEETEI MAYEK VOWEL SIGN ANAP +ABE6..ABE7;N # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP +ABE8;N # Mn MEETEI MAYEK VOWEL SIGN UNAP +ABE9..ABEA;N # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG +ABEB;N # Po MEETEI MAYEK CHEIKHEI +ABEC;N # Mc MEETEI MAYEK LUM IYEK +ABED;N # Mn MEETEI MAYEK APUN IYEK +ABF0..ABF9;N # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE +AC00..D7A3;W # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH +D7B0..D7C6;N # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +D7CB..D7FB;N # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH +D800..DB7F;N # Cs [896] .. +DB80..DBFF;N # Cs [128] .. +DC00..DFFF;N # Cs [1024] .. +E000..F8FF;A # Co [6400] .. +F900..FA6D;W # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D +FA6E..FA6F;W # Cn [2] .. +FA70..FAD9;W # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 +FADA..FAFF;W # Cn [38] .. +FB00..FB06;N # Ll [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST +FB13..FB17;N # Ll [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH +FB1D;N # Lo HEBREW LETTER YOD WITH HIRIQ +FB1E;N # Mn HEBREW POINT JUDEO-SPANISH VARIKA +FB1F..FB28;N # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV +FB29;N # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A..FB36;N # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH +FB38..FB3C;N # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH +FB3E;N # Lo HEBREW LETTER MEM WITH DAGESH +FB40..FB41;N # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH +FB43..FB44;N # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH +FB46..FB4F;N # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED +FB50..FBB1;N # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBB2..FBC2;N # Sk [17] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL WASLA ABOVE +FBD3..FD3D;N # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD3E;N # Pe ORNATE LEFT PARENTHESIS +FD3F;N # Ps ORNATE RIGHT PARENTHESIS +FD40..FD4F;N # So [16] ARABIC LIGATURE RAHIMAHU ALLAAH..ARABIC LIGATURE RAHIMAHUM ALLAAH +FD50..FD8F;N # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92..FDC7;N # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDCF;N # So ARABIC LIGATURE SALAAMUHU ALAYNAA +FDF0..FDFB;N # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU +FDFC;N # Sc RIAL SIGN +FDFD..FDFF;N # So [3] ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM..ARABIC LIGATURE AZZA WA JALL +FE00..FE0F;A # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 +FE10..FE16;W # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE17;W # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET +FE18;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET +FE19;W # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS +FE20..FE2F;N # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF +FE30;W # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31..FE32;W # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH +FE33..FE34;W # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35;W # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37;W # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39;W # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B;W # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D;W # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F;W # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41;W # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43;W # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE45..FE46;W # Po [2] SESAME DOT..WHITE SESAME DOT +FE47;W # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET +FE48;W # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET +FE49..FE4C;W # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE +FE4D..FE4F;W # Pc [3] DASHED LOW LINE..WAVY LOW LINE +FE50..FE52;W # Po [3] SMALL COMMA..SMALL FULL STOP +FE54..FE57;W # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK +FE58;W # Pd SMALL EM DASH +FE59;W # Ps SMALL LEFT PARENTHESIS +FE5A;W # Pe SMALL RIGHT PARENTHESIS +FE5B;W # Ps SMALL LEFT CURLY BRACKET +FE5C;W # Pe SMALL RIGHT CURLY BRACKET +FE5D;W # Ps SMALL LEFT TORTOISE SHELL BRACKET +FE5E;W # Pe SMALL RIGHT TORTOISE SHELL BRACKET +FE5F..FE61;W # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK +FE62;W # Sm SMALL PLUS SIGN +FE63;W # Pd SMALL HYPHEN-MINUS +FE64..FE66;W # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN +FE68;W # Po SMALL REVERSE SOLIDUS +FE69;W # Sc SMALL DOLLAR SIGN +FE6A..FE6B;W # Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT +FE70..FE74;N # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM +FE76..FEFC;N # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FEFF;N # Cf ZERO WIDTH NO-BREAK SPACE +FF01..FF03;F # Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN +FF04;F # Sc FULLWIDTH DOLLAR SIGN +FF05..FF07;F # Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE +FF08;F # Ps FULLWIDTH LEFT PARENTHESIS +FF09;F # Pe FULLWIDTH RIGHT PARENTHESIS +FF0A;F # Po FULLWIDTH ASTERISK +FF0B;F # Sm FULLWIDTH PLUS SIGN +FF0C;F # Po FULLWIDTH COMMA +FF0D;F # Pd FULLWIDTH HYPHEN-MINUS +FF0E..FF0F;F # Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS +FF10..FF19;F # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE +FF1A..FF1B;F # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON +FF1C..FF1E;F # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN +FF1F..FF20;F # Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT +FF21..FF3A;F # Lu [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z +FF3B;F # Ps FULLWIDTH LEFT SQUARE BRACKET +FF3C;F # Po FULLWIDTH REVERSE SOLIDUS +FF3D;F # Pe FULLWIDTH RIGHT SQUARE BRACKET +FF3E;F # Sk FULLWIDTH CIRCUMFLEX ACCENT +FF3F;F # Pc FULLWIDTH LOW LINE +FF40;F # Sk FULLWIDTH GRAVE ACCENT +FF41..FF5A;F # Ll [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z +FF5B;F # Ps FULLWIDTH LEFT CURLY BRACKET +FF5C;F # Sm FULLWIDTH VERTICAL LINE +FF5D;F # Pe FULLWIDTH RIGHT CURLY BRACKET +FF5E;F # Sm FULLWIDTH TILDE +FF5F;F # Ps FULLWIDTH LEFT WHITE PARENTHESIS +FF60;F # Pe FULLWIDTH RIGHT WHITE PARENTHESIS +FF61;H # Po HALFWIDTH IDEOGRAPHIC FULL STOP +FF62;H # Ps HALFWIDTH LEFT CORNER BRACKET +FF63;H # Pe HALFWIDTH RIGHT CORNER BRACKET +FF64..FF65;H # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT +FF66..FF6F;H # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU +FF70;H # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71..FF9D;H # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N +FF9E..FF9F;H # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFA0..FFBE;H # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH +FFC2..FFC7;H # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E +FFCA..FFCF;H # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE +FFD2..FFD7;H # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU +FFDA..FFDC;H # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I +FFE0..FFE1;F # Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN +FFE2;F # Sm FULLWIDTH NOT SIGN +FFE3;F # Sk FULLWIDTH MACRON +FFE4;F # So FULLWIDTH BROKEN BAR +FFE5..FFE6;F # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN +FFE8;H # So HALFWIDTH FORMS LIGHT VERTICAL +FFE9..FFEC;H # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +FFED..FFEE;H # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE +FFF9..FFFB;N # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR +FFFC;N # So OBJECT REPLACEMENT CHARACTER +FFFD;A # So REPLACEMENT CHARACTER +10000..1000B;N # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE +1000D..10026;N # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO +10028..1003A;N # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO +1003C..1003D;N # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE +1003F..1004D;N # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO +10050..1005D;N # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089 +10080..100FA;N # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305 +10100..10102;N # Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK +10107..10133;N # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND +10137..1013F;N # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT +10140..10174;N # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS +10175..10178;N # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN +10179..10189;N # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN +1018A..1018B;N # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN +1018C..1018E;N # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN +10190..1019C;N # So [13] ROMAN SEXTANS SIGN..ASCIA SYMBOL +101A0;N # So GREEK SYMBOL TAU RHO +101D0..101FC;N # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND +101FD;N # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +10280..1029C;N # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X +102A0..102D0;N # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 +102E0;N # Mn COPTIC EPACT THOUSANDS MARK +102E1..102FB;N # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED +10300..1031F;N # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS +10320..10323;N # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +1032D..1032F;N # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE +10330..10340;N # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +10341;N # Nl GOTHIC LETTER NINETY +10342..10349;N # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL +1034A;N # Nl GOTHIC LETTER NINE HUNDRED +10350..10375;N # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA +10376..1037A;N # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII +10380..1039D;N # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU +1039F;N # Po UGARITIC WORD DIVIDER +103A0..103C3;N # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA +103C8..103CF;N # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH +103D0;N # Po OLD PERSIAN WORD DIVIDER +103D1..103D5;N # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED +10400..1044F;N # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW +10450..1047F;N # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW +10480..1049D;N # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO +104A0..104A9;N # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3;N # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB;N # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA +10500..10527;N # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE +10530..10563;N # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +1056F;N # Po CAUCASIAN ALBANIAN CITATION MARK +10570..1057A;N # Lu [11] VITHKUQI CAPITAL LETTER A..VITHKUQI CAPITAL LETTER GA +1057C..1058A;N # Lu [15] VITHKUQI CAPITAL LETTER HA..VITHKUQI CAPITAL LETTER RE +1058C..10592;N # Lu [7] VITHKUQI CAPITAL LETTER SE..VITHKUQI CAPITAL LETTER XE +10594..10595;N # Lu [2] VITHKUQI CAPITAL LETTER Y..VITHKUQI CAPITAL LETTER ZE +10597..105A1;N # Ll [11] VITHKUQI SMALL LETTER A..VITHKUQI SMALL LETTER GA +105A3..105B1;N # Ll [15] VITHKUQI SMALL LETTER HA..VITHKUQI SMALL LETTER RE +105B3..105B9;N # Ll [7] VITHKUQI SMALL LETTER SE..VITHKUQI SMALL LETTER XE +105BB..105BC;N # Ll [2] VITHKUQI SMALL LETTER Y..VITHKUQI SMALL LETTER ZE +10600..10736;N # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 +10740..10755;N # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10760..10767;N # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807 +10780..10785;N # Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK +10787..107B0;N # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2..107BA;N # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +10800..10805;N # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA +10808;N # Lo CYPRIOT SYLLABLE JO +1080A..10835;N # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO +10837..10838;N # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE +1083C;N # Lo CYPRIOT SYLLABLE ZA +1083F;N # Lo CYPRIOT SYLLABLE ZO +10840..10855;N # Lo [22] IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW +10857;N # Po IMPERIAL ARAMAIC SECTION SIGN +10858..1085F;N # No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND +10860..10876;N # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10877..10878;N # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON +10879..1087F;N # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY +10880..1089E;N # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +108A7..108AF;N # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED +108E0..108F2;N # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH +108F4..108F5;N # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW +108FB..108FF;N # No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED +10900..10915;N # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU +10916..1091B;N # No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE +1091F;N # Po PHOENICIAN WORD SEPARATOR +10920..10939;N # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C +1093F;N # Po LYDIAN TRIANGULAR MARK +10980..1099F;N # Lo [32] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2 +109A0..109B7;N # Lo [24] MEROITIC CURSIVE LETTER A..MEROITIC CURSIVE LETTER DA +109BC..109BD;N # No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF +109BE..109BF;N # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN +109C0..109CF;N # No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY +109D2..109FF;N # No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS +10A00;N # Lo KHAROSHTHI LETTER A +10A01..10A03;N # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R +10A05..10A06;N # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O +10A0C..10A0F;N # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA +10A10..10A13;N # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA +10A15..10A17;N # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA +10A19..10A35;N # Lo [29] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER VHA +10A38..10A3A;N # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW +10A3F;N # Mn KHAROSHTHI VIRAMA +10A40..10A48;N # No [9] KHAROSHTHI DIGIT ONE..KHAROSHTHI FRACTION ONE HALF +10A50..10A58;N # Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES +10A60..10A7C;N # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH +10A7D..10A7E;N # No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY +10A7F;N # Po OLD SOUTH ARABIAN NUMERIC INDICATOR +10A80..10A9C;N # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10A9D..10A9F;N # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY +10AC0..10AC7;N # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC8;N # So MANICHAEAN SIGN UD +10AC9..10AE4;N # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10AE5..10AE6;N # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +10AEB..10AEF;N # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED +10AF0..10AF6;N # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER +10B00..10B35;N # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE +10B39..10B3F;N # Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B40..10B55;N # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW +10B58..10B5F;N # No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND +10B60..10B72;N # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW +10B78..10B7F;N # No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND +10B80..10B91;N # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10B99..10B9C;N # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10BA9..10BAF;N # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED +10C00..10C48;N # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH +10C80..10CB2;N # Lu [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US +10CC0..10CF2;N # Ll [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10CFA..10CFF;N # No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND +10D00..10D23;N # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10D24..10D27;N # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10D30..10D39;N # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10E60..10E7E;N # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS +10E80..10EA9;N # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET +10EAB..10EAC;N # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +10EAD;N # Pd YEZIDI HYPHENATION MARK +10EB0..10EB1;N # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10EFD..10EFF;N # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA +10F00..10F1C;N # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL +10F1D..10F26;N # No [10] OLD SOGDIAN NUMBER ONE..OLD SOGDIAN FRACTION ONE HALF +10F27;N # Lo OLD SOGDIAN LIGATURE AYIN-DALETH +10F30..10F45;N # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN +10F46..10F50;N # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +10F51..10F54;N # No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED +10F55..10F59;N # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10F70..10F81;N # Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH +10F82..10F85;N # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW +10F86..10F89;N # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS +10FB0..10FC4;N # Lo [21] CHORASMIAN LETTER ALEPH..CHORASMIAN LETTER TAW +10FC5..10FCB;N # No [7] CHORASMIAN NUMBER ONE..CHORASMIAN NUMBER ONE HUNDRED +10FE0..10FF6;N # Lo [23] ELYMAIC LETTER ALEPH..ELYMAIC LIGATURE ZAYIN-YODH +11000;N # Mc BRAHMI SIGN CANDRABINDU +11001;N # Mn BRAHMI SIGN ANUSVARA +11002;N # Mc BRAHMI SIGN VISARGA +11003..11037;N # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA +11038..11046;N # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA +11047..1104D;N # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS +11052..11065;N # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND +11066..1106F;N # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +11070;N # Mn BRAHMI SIGN OLD TAMIL VIRAMA +11071..11072;N # Lo [2] BRAHMI LETTER OLD TAMIL SHORT E..BRAHMI LETTER OLD TAMIL SHORT O +11073..11074;N # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O +11075;N # Lo BRAHMI LETTER OLD TAMIL LLA +1107F;N # Mn BRAHMI NUMBER JOINER +11080..11081;N # Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA +11082;N # Mc KAITHI SIGN VISARGA +11083..110AF;N # Lo [45] KAITHI LETTER A..KAITHI LETTER HA +110B0..110B2;N # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II +110B3..110B6;N # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI +110B7..110B8;N # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU +110B9..110BA;N # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA +110BB..110BC;N # Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN +110BD;N # Cf KAITHI NUMBER SIGN +110BE..110C1;N # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA +110C2;N # Mn KAITHI VOWEL SIGN VOCALIC R +110CD;N # Cf KAITHI NUMBER SIGN ABOVE +110D0..110E8;N # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE +110F0..110F9;N # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE +11100..11102;N # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA +11103..11126;N # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA +11127..1112B;N # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU +1112C;N # Mc CHAKMA VOWEL SIGN E +1112D..11134;N # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA +11136..1113F;N # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE +11140..11143;N # Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK +11144;N # Lo CHAKMA LETTER LHAA +11145..11146;N # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI +11147;N # Lo CHAKMA LETTER VAA +11150..11172;N # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA +11173;N # Mn MAHAJANI SIGN NUKTA +11174..11175;N # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK +11176;N # Lo MAHAJANI LIGATURE SHRI +11180..11181;N # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA +11182;N # Mc SHARADA SIGN VISARGA +11183..111B2;N # Lo [48] SHARADA LETTER A..SHARADA LETTER HA +111B3..111B5;N # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II +111B6..111BE;N # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +111BF..111C0;N # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +111C1..111C4;N # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM +111C5..111C8;N # Po [4] SHARADA DANDA..SHARADA SEPARATOR +111C9..111CC;N # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK +111CD;N # Po SHARADA SUTRA MARK +111CE;N # Mc SHARADA VOWEL SIGN PRISHTHAMATRA E +111CF;N # Mn SHARADA SIGN INVERTED CANDRABINDU +111D0..111D9;N # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE +111DA;N # Lo SHARADA EKAM +111DB;N # Po SHARADA SIGN SIDDHAM +111DC;N # Lo SHARADA HEADSTROKE +111DD..111DF;N # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 +111E1..111F4;N # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND +11200..11211;N # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA +11213..1122B;N # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA +1122C..1122E;N # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II +1122F..11231;N # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +11232..11233;N # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU +11234;N # Mn KHOJKI SIGN ANUSVARA +11235;N # Mc KHOJKI SIGN VIRAMA +11236..11237;N # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +11238..1123D;N # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN +1123E;N # Mn KHOJKI SIGN SUKUN +1123F..11240;N # Lo [2] KHOJKI LETTER QA..KHOJKI LETTER SHORT I +11241;N # Mn KHOJKI VOWEL SIGN VOCALIC R +11280..11286;N # Lo [7] MULTANI LETTER A..MULTANI LETTER GA +11288;N # Lo MULTANI LETTER GHA +1128A..1128D;N # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA +1128F..1129D;N # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA +1129F..112A8;N # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA +112A9;N # Po MULTANI SECTION MARK +112B0..112DE;N # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA +112DF;N # Mn KHUDAWADI SIGN ANUSVARA +112E0..112E2;N # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II +112E3..112EA;N # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA +112F0..112F9;N # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +11300..11301;N # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU +11302..11303;N # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +11305..1130C;N # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130F..11310;N # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI +11313..11328;N # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA +1132A..11330;N # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA +11332..11333;N # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA +11335..11339;N # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA +1133B..1133C;N # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA +1133D;N # Lo GRANTHA SIGN AVAGRAHA +1133E..1133F;N # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I +11340;N # Mn GRANTHA VOWEL SIGN II +11341..11344;N # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR +11347..11348;N # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +1134B..1134D;N # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +11350;N # Lo GRANTHA OM +11357;N # Mc GRANTHA AU LENGTH MARK +1135D..11361;N # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11362..11363;N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11366..1136C;N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +11370..11374;N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11400..11434;N # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437;N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F;N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441;N # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444;N # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445;N # Mc NEWA SIGN VISARGA +11446;N # Mn NEWA SIGN NUKTA +11447..1144A;N # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144F;N # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459;N # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145A..1145B;N # Po [2] NEWA DOUBLE COMMA..NEWA PLACEHOLDER MARK +1145D;N # Po NEWA INSERTION SIGN +1145E;N # Mn NEWA SANDHI MARK +1145F..11461;N # Lo [3] NEWA LETTER VEDIC ANUSVARA..NEWA SIGN UPADHMANIYA +11480..114AF;N # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA +114B0..114B2;N # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II +114B3..114B8;N # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL +114B9;N # Mc TIRHUTA VOWEL SIGN E +114BA;N # Mn TIRHUTA VOWEL SIGN SHORT E +114BB..114BE;N # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU +114BF..114C0;N # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA +114C1;N # Mc TIRHUTA SIGN VISARGA +114C2..114C3;N # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +114C4..114C5;N # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG +114C6;N # Po TIRHUTA ABBREVIATION SIGN +114C7;N # Lo TIRHUTA OM +114D0..114D9;N # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE +11580..115AE;N # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA +115AF..115B1;N # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II +115B2..115B5;N # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR +115B8..115BB;N # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +115BC..115BD;N # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +115BE;N # Mc SIDDHAM SIGN VISARGA +115BF..115C0;N # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA +115C1..115D7;N # Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +115D8..115DB;N # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U +115DC..115DD;N # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU +11600..1162F;N # Lo [48] MODI LETTER A..MODI LETTER LLA +11630..11632;N # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II +11633..1163A;N # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI +1163B..1163C;N # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU +1163D;N # Mn MODI SIGN ANUSVARA +1163E;N # Mc MODI SIGN VISARGA +1163F..11640;N # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA +11641..11643;N # Po [3] MODI DANDA..MODI ABBREVIATION SIGN +11644;N # Lo MODI SIGN HUVA +11650..11659;N # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +11660..1166C;N # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT +11680..116AA;N # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA +116AB;N # Mn TAKRI SIGN ANUSVARA +116AC;N # Mc TAKRI SIGN VISARGA +116AD;N # Mn TAKRI VOWEL SIGN AA +116AE..116AF;N # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II +116B0..116B5;N # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU +116B6;N # Mc TAKRI SIGN VIRAMA +116B7;N # Mn TAKRI SIGN NUKTA +116B8;N # Lo TAKRI LETTER ARCHAIC KHA +116B9;N # Po TAKRI ABBREVIATION SIGN +116C0..116C9;N # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE +11700..1171A;N # Lo [27] AHOM LETTER KA..AHOM LETTER ALTERNATE BA +1171D..1171F;N # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA +11720..11721;N # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA +11722..11725;N # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +11726;N # Mc AHOM VOWEL SIGN E +11727..1172B;N # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11730..11739;N # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE +1173A..1173B;N # No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY +1173C..1173E;N # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +1173F;N # So AHOM SYMBOL VI +11740..11746;N # Lo [7] AHOM LETTER CA..AHOM LETTER LLA +11800..1182B;N # Lo [44] DOGRA LETTER A..DOGRA LETTER RRA +1182C..1182E;N # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II +1182F..11837;N # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA +11838;N # Mc DOGRA SIGN VISARGA +11839..1183A;N # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA +1183B;N # Po DOGRA ABBREVIATION SIGN +118A0..118DF;N # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO +118E0..118E9;N # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +118EA..118F2;N # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY +118FF;N # Lo WARANG CITI OM +11900..11906;N # Lo [7] DIVES AKURU LETTER A..DIVES AKURU LETTER E +11909;N # Lo DIVES AKURU LETTER O +1190C..11913;N # Lo [8] DIVES AKURU LETTER KA..DIVES AKURU LETTER JA +11915..11916;N # Lo [2] DIVES AKURU LETTER NYA..DIVES AKURU LETTER TTA +11918..1192F;N # Lo [24] DIVES AKURU LETTER DDA..DIVES AKURU LETTER ZA +11930..11935;N # Mc [6] DIVES AKURU VOWEL SIGN AA..DIVES AKURU VOWEL SIGN E +11937..11938;N # Mc [2] DIVES AKURU VOWEL SIGN AI..DIVES AKURU VOWEL SIGN O +1193B..1193C;N # Mn [2] DIVES AKURU SIGN ANUSVARA..DIVES AKURU SIGN CANDRABINDU +1193D;N # Mc DIVES AKURU SIGN HALANTA +1193E;N # Mn DIVES AKURU VIRAMA +1193F;N # Lo DIVES AKURU PREFIXED NASAL SIGN +11940;N # Mc DIVES AKURU MEDIAL YA +11941;N # Lo DIVES AKURU INITIAL RA +11942;N # Mc DIVES AKURU MEDIAL RA +11943;N # Mn DIVES AKURU SIGN NUKTA +11944..11946;N # Po [3] DIVES AKURU DOUBLE DANDA..DIVES AKURU END OF TEXT MARK +11950..11959;N # Nd [10] DIVES AKURU DIGIT ZERO..DIVES AKURU DIGIT NINE +119A0..119A7;N # Lo [8] NANDINAGARI LETTER A..NANDINAGARI LETTER VOCALIC RR +119AA..119D0;N # Lo [39] NANDINAGARI LETTER E..NANDINAGARI LETTER RRA +119D1..119D3;N # Mc [3] NANDINAGARI VOWEL SIGN AA..NANDINAGARI VOWEL SIGN II +119D4..119D7;N # Mn [4] NANDINAGARI VOWEL SIGN U..NANDINAGARI VOWEL SIGN VOCALIC RR +119DA..119DB;N # Mn [2] NANDINAGARI VOWEL SIGN E..NANDINAGARI VOWEL SIGN AI +119DC..119DF;N # Mc [4] NANDINAGARI VOWEL SIGN O..NANDINAGARI SIGN VISARGA +119E0;N # Mn NANDINAGARI SIGN VIRAMA +119E1;N # Lo NANDINAGARI SIGN AVAGRAHA +119E2;N # Po NANDINAGARI SIGN SIDDHAM +119E3;N # Lo NANDINAGARI HEADSTROKE +119E4;N # Mc NANDINAGARI VOWEL SIGN PRISHTHAMATRA E +11A00;N # Lo ZANABAZAR SQUARE LETTER A +11A01..11A0A;N # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A0B..11A32;N # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A33..11A38;N # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39;N # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A;N # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3B..11A3E;N # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F..11A46;N # Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47;N # Mn ZANABAZAR SQUARE SUBJOINER +11A50;N # Lo SOYOMBO LETTER A +11A51..11A56;N # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58;N # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B;N # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A5C..11A89;N # Lo [46] SOYOMBO LETTER KA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A8A..11A96;N # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97;N # Mc SOYOMBO SIGN VISARGA +11A98..11A99;N # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11A9A..11A9C;N # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9D;N # Lo SOYOMBO MARK PLUTA +11A9E..11AA2;N # Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 +11AB0..11ABF;N # Lo [16] CANADIAN SYLLABICS NATTILIK HI..CANADIAN SYLLABICS SPA +11AC0..11AF8;N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11B00..11B09;N # Po [10] DEVANAGARI HEAD MARK..DEVANAGARI SIGN MINDU +11C00..11C08;N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E;N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F;N # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36;N # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D;N # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E;N # Mc BHAIKSUKI SIGN VISARGA +11C3F;N # Mn BHAIKSUKI SIGN VIRAMA +11C40;N # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45;N # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59;N # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C;N # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70..11C71;N # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F;N # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7;N # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9;N # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0;N # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1;N # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3;N # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4;N # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6;N # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D00..11D06;N # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09;N # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30;N # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D31..11D36;N # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A;N # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D;N # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45;N # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D46;N # Lo MASARAM GONDI REPHA +11D47;N # Mn MASARAM GONDI RA-KARA +11D50..11D59;N # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE +11D60..11D65;N # Lo [6] GUNJALA GONDI LETTER A..GUNJALA GONDI LETTER UU +11D67..11D68;N # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI +11D6A..11D89;N # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA +11D8A..11D8E;N # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU +11D90..11D91;N # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI +11D93..11D94;N # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU +11D95;N # Mn GUNJALA GONDI SIGN ANUSVARA +11D96;N # Mc GUNJALA GONDI SIGN VISARGA +11D97;N # Mn GUNJALA GONDI VIRAMA +11D98;N # Lo GUNJALA GONDI OM +11DA0..11DA9;N # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE +11EE0..11EF2;N # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA +11EF3..11EF4;N # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U +11EF5..11EF6;N # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +11EF7..11EF8;N # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11F00..11F01;N # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA +11F02;N # Lo KAWI SIGN REPHA +11F03;N # Mc KAWI SIGN VISARGA +11F04..11F10;N # Lo [13] KAWI LETTER A..KAWI LETTER O +11F12..11F33;N # Lo [34] KAWI LETTER KA..KAWI LETTER JNYA +11F34..11F35;N # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA +11F36..11F3A;N # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R +11F3E..11F3F;N # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI +11F40;N # Mn KAWI VOWEL SIGN EU +11F41;N # Mc KAWI SIGN KILLER +11F42;N # Mn KAWI CONJOINER +11F43..11F4F;N # Po [13] KAWI DANDA..KAWI PUNCTUATION CLOSING SPIRAL +11F50..11F59;N # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE +11FB0;N # Lo LISU LETTER YHA +11FC0..11FD4;N # No [21] TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH..TAMIL FRACTION DOWNSCALING FACTOR KIIZH +11FD5..11FDC;N # So [8] TAMIL SIGN NEL..TAMIL SIGN MUKKURUNI +11FDD..11FE0;N # Sc [4] TAMIL SIGN KAACU..TAMIL SIGN VARAAKAN +11FE1..11FF1;N # So [17] TAMIL SIGN PAARAM..TAMIL SIGN VAKAIYARAA +11FFF;N # Po TAMIL PUNCTUATION END OF TEXT +12000..12399;N # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U +12400..1246E;N # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +12470..12474;N # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +12480..12543;N # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU +12F90..12FF0;N # Lo [97] CYPRO-MINOAN SIGN CM001..CYPRO-MINOAN SIGN CM114 +12FF1..12FF2;N # Po [2] CYPRO-MINOAN SIGN CM301..CYPRO-MINOAN SIGN CM302 +13000..1342F;N # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D +13430..1343F;N # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE +13440;N # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY +13441..13446;N # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..EGYPTIAN HIEROGLYPH WIDE LOST SIGN +13447..13455;N # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED +14400..14646;N # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +16800..16A38;N # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ +16A40..16A5E;N # Lo [31] MRO LETTER TA..MRO LETTER TEK +16A60..16A69;N # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE +16A6E..16A6F;N # Po [2] MRO DANDA..MRO DOUBLE DANDA +16A70..16ABE;N # Lo [79] TANGSA LETTER OZ..TANGSA LETTER ZA +16AC0..16AC9;N # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE +16AD0..16AED;N # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16AF0..16AF4;N # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16AF5;N # Po BASSA VAH FULL STOP +16B00..16B2F;N # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16B30..16B36;N # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16B37..16B3B;N # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM +16B3C..16B3F;N # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB +16B40..16B43;N # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B44;N # Po PAHAWH HMONG SIGN XAUS +16B45;N # So PAHAWH HMONG SIGN CIM TSOV ROG +16B50..16B59;N # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16B5B..16B61;N # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS +16B63..16B77;N # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B7D..16B8F;N # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16E40..16E7F;N # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y +16E80..16E96;N # No [23] MEDEFAIDRIN DIGIT ZERO..MEDEFAIDRIN DIGIT THREE ALTERNATE FORM +16E97..16E9A;N # Po [4] MEDEFAIDRIN COMMA..MEDEFAIDRIN EXCLAMATION OH +16F00..16F4A;N # Lo [75] MIAO LETTER PA..MIAO LETTER RTE +16F4F;N # Mn MIAO SIGN CONSONANT MODIFIER BAR +16F50;N # Lo MIAO LETTER NASALIZATION +16F51..16F87;N # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI +16F8F..16F92;N # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +16F93..16F9F;N # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FE0..16FE1;W # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +16FE2;W # Po OLD CHINESE HOOK MARK +16FE3;W # Lm OLD CHINESE ITERATION MARK +16FE4;W # Mn KHITAN SMALL SCRIPT FILLER +16FF0..16FF1;W # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +17000..187F7;W # Lo [6136] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F7 +18800..18AFF;W # Lo [768] TANGUT COMPONENT-001..TANGUT COMPONENT-768 +18B00..18CD5;W # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 +18D00..18D08;W # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 +1AFF0..1AFF3;W # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 +1AFF5..1AFFB;W # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 +1AFFD..1AFFE;W # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 +1B000..1B0FF;W # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 +1B100..1B122;W # Lo [35] HENTAIGANA LETTER RE-3..KATAKANA LETTER ARCHAIC WU +1B132;W # Lo HIRAGANA LETTER SMALL KO +1B150..1B152;W # Lo [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO +1B155;W # Lo KATAKANA LETTER SMALL KO +1B164..1B167;W # Lo [4] KATAKANA LETTER SMALL WI..KATAKANA LETTER SMALL N +1B170..1B2FB;W # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB +1BC00..1BC6A;N # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C;N # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88;N # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99;N # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1BC9C;N # So DUPLOYAN SIGN O WITH CROSS +1BC9D..1BC9E;N # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1BC9F;N # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1BCA0..1BCA3;N # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1CF00..1CF2D;N # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT +1CF30..1CF46;N # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG +1CF50..1CFC3;N # So [116] ZNAMENNY NEUME KRYUK..ZNAMENNY NEUME PAUK +1D000..1D0F5;N # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D100..1D126;N # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 +1D129..1D164;N # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D165..1D166;N # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167..1D169;N # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16A..1D16C;N # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3 +1D16D..1D172;N # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +1D173..1D17A;N # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE +1D17B..1D182;N # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE +1D183..1D184;N # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN +1D185..1D18B;N # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D18C..1D1A9;N # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH +1D1AA..1D1AD;N # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1D1AE..1D1EA;N # So [61] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KORON +1D200..1D241;N # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 +1D242..1D244;N # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME +1D245;N # So GREEK MUSICAL LEIMMA +1D2C0..1D2D3;N # No [20] KAKTOVIK NUMERAL ZERO..KAKTOVIK NUMERAL NINETEEN +1D2E0..1D2F3;N # No [20] MAYAN NUMERAL ZERO..MAYAN NUMERAL NINETEEN +1D300..1D356;N # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING +1D360..1D378;N # No [25] COUNTING ROD UNIT DIGIT ONE..TALLY MARK FIVE +1D400..1D454;N # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G +1D456..1D49C;N # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A +1D49E..1D49F;N # Lu [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D +1D4A2;N # Lu MATHEMATICAL SCRIPT CAPITAL G +1D4A5..1D4A6;N # Lu [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K +1D4A9..1D4AC;N # Lu [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q +1D4AE..1D4B9;N # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D +1D4BB;N # Ll MATHEMATICAL SCRIPT SMALL F +1D4BD..1D4C3;N # Ll [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N +1D4C5..1D505;N # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B +1D507..1D50A;N # Lu [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G +1D50D..1D514;N # Lu [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q +1D516..1D51C;N # Lu [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y +1D51E..1D539;N # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B..1D53E;N # Lu [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540..1D544;N # Lu [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546;N # Lu MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A..1D550;N # Lu [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552..1D6A5;N # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A8..1D6C0;N # Lu [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1;N # Sm MATHEMATICAL BOLD NABLA +1D6C2..1D6DA;N # Ll [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA +1D6DB;N # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC..1D6FA;N # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB;N # Sm MATHEMATICAL ITALIC NABLA +1D6FC..1D714;N # Ll [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA +1D715;N # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716..1D734;N # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735;N # Sm MATHEMATICAL BOLD ITALIC NABLA +1D736..1D74E;N # Ll [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F;N # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750..1D76E;N # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F;N # Sm MATHEMATICAL SANS-SERIF BOLD NABLA +1D770..1D788;N # Ll [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789;N # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A..1D7A8;N # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9;N # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA..1D7C2;N # Ll [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3;N # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4..1D7CB;N # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA +1D7CE..1D7FF;N # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1D800..1D9FF;N # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD +1DA00..1DA36;N # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +1DA37..1DA3A;N # So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE +1DA3B..1DA6C;N # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT +1DA6D..1DA74;N # So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING +1DA75;N # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA76..1DA83;N # So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH +1DA84;N # Mn SIGNWRITING LOCATION HEAD NECK +1DA85..1DA86;N # So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS +1DA87..1DA8B;N # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS +1DA9B..1DA9F;N # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 +1DAA1..1DAAF;N # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1DF00..1DF09;N # Ll [10] LATIN SMALL LETTER FENG DIGRAPH WITH TRILL..LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK +1DF0A;N # Lo LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK +1DF0B..1DF1E;N # Ll [20] LATIN SMALL LETTER ESH WITH DOUBLE BAR..LATIN SMALL LETTER S WITH CURL +1DF25..1DF2A;N # Ll [6] LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK..LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK +1E000..1E006;N # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018;N # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021;N # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024;N # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A;N # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E030..1E06D;N # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE +1E08F;N # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +1E100..1E12C;N # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W +1E130..1E136;N # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E137..1E13D;N # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER +1E140..1E149;N # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE +1E14E;N # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ +1E14F;N # So NYIAKENG PUACHUE HMONG CIRCLED CA +1E290..1E2AD;N # Lo [30] TOTO LETTER PA..TOTO LETTER A +1E2AE;N # Mn TOTO SIGN RISING TONE +1E2C0..1E2EB;N # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH +1E2EC..1E2EF;N # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI +1E2F0..1E2F9;N # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE +1E2FF;N # Sc WANCHO NGUN SIGN +1E4D0..1E4EA;N # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL +1E4EB;N # Lm NAG MUNDARI SIGN OJOD +1E4EC..1E4EF;N # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH +1E4F0..1E4F9;N # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE +1E7E0..1E7E6;N # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO +1E7E8..1E7EB;N # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE +1E7ED..1E7EE;N # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE +1E7F0..1E7FE;N # Lo [15] ETHIOPIC SYLLABLE GURAGE QWI..ETHIOPIC SYLLABLE GURAGE PWEE +1E800..1E8C4;N # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E8C7..1E8CF;N # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE +1E8D0..1E8D6;N # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E900..1E943;N # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A;N # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E94B;N # Lm ADLAM NASALIZATION MARK +1E950..1E959;N # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F;N # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK +1EC71..1ECAB;N # No [59] INDIC SIYAQ NUMBER ONE..INDIC SIYAQ NUMBER PREFIXED NINE +1ECAC;N # So INDIC SIYAQ PLACEHOLDER +1ECAD..1ECAF;N # No [3] INDIC SIYAQ FRACTION ONE QUARTER..INDIC SIYAQ FRACTION THREE QUARTERS +1ECB0;N # Sc INDIC SIYAQ RUPEE MARK +1ECB1..1ECB4;N # No [4] INDIC SIYAQ NUMBER ALTERNATE ONE..INDIC SIYAQ ALTERNATE LAKH MARK +1ED01..1ED2D;N # No [45] OTTOMAN SIYAQ NUMBER ONE..OTTOMAN SIYAQ NUMBER NINETY THOUSAND +1ED2E;N # So OTTOMAN SIYAQ MARRATAN +1ED2F..1ED3D;N # No [15] OTTOMAN SIYAQ ALTERNATE NUMBER TWO..OTTOMAN SIYAQ FRACTION ONE SIXTH +1EE00..1EE03;N # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL +1EE05..1EE1F;N # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF +1EE21..1EE22;N # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM +1EE24;N # Lo ARABIC MATHEMATICAL INITIAL HEH +1EE27;N # Lo ARABIC MATHEMATICAL INITIAL HAH +1EE29..1EE32;N # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF +1EE34..1EE37;N # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH +1EE39;N # Lo ARABIC MATHEMATICAL INITIAL DAD +1EE3B;N # Lo ARABIC MATHEMATICAL INITIAL GHAIN +1EE42;N # Lo ARABIC MATHEMATICAL TAILED JEEM +1EE47;N # Lo ARABIC MATHEMATICAL TAILED HAH +1EE49;N # Lo ARABIC MATHEMATICAL TAILED YEH +1EE4B;N # Lo ARABIC MATHEMATICAL TAILED LAM +1EE4D..1EE4F;N # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN +1EE51..1EE52;N # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF +1EE54;N # Lo ARABIC MATHEMATICAL TAILED SHEEN +1EE57;N # Lo ARABIC MATHEMATICAL TAILED KHAH +1EE59;N # Lo ARABIC MATHEMATICAL TAILED DAD +1EE5B;N # Lo ARABIC MATHEMATICAL TAILED GHAIN +1EE5D;N # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5F;N # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE61..1EE62;N # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM +1EE64;N # Lo ARABIC MATHEMATICAL STRETCHED HEH +1EE67..1EE6A;N # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF +1EE6C..1EE72;N # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF +1EE74..1EE77;N # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH +1EE79..1EE7C;N # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7E;N # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE80..1EE89;N # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH +1EE8B..1EE9B;N # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN +1EEA1..1EEA3;N # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA5..1EEA9;N # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAB..1EEBB;N # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +1EEF0..1EEF1;N # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL +1F000..1F003;N # So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND +1F004;W # So MAHJONG TILE RED DRAGON +1F005..1F02B;N # So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK +1F030..1F093;N # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 +1F0A0..1F0AE;N # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES +1F0B1..1F0BF;N # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER +1F0C1..1F0CE;N # So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS +1F0CF;W # So PLAYING CARD BLACK JOKER +1F0D1..1F0F5;N # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 +1F100..1F10A;A # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA +1F10B..1F10C;N # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO +1F10D..1F10F;N # So [3] CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH +1F110..1F12D;A # So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD +1F12E..1F12F;N # So [2] CIRCLED WZ..COPYLEFT SYMBOL +1F130..1F169;A # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F16A..1F16F;N # So [6] RAISED MC SIGN..CIRCLED HUMAN FIGURE +1F170..1F18D;A # So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA +1F18E;W # So NEGATIVE SQUARED AB +1F18F..1F190;A # So [2] NEGATIVE SQUARED WC..SQUARE DJ +1F191..1F19A;W # So [10] SQUARED CL..SQUARED VS +1F19B..1F1AC;A # So [18] SQUARED THREE D..SQUARED VOD +1F1AD;N # So MASK WORK SYMBOL +1F1E6..1F1FF;N # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z +1F200..1F202;W # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA +1F210..1F23B;W # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D +1F240..1F248;W # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +1F250..1F251;W # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT +1F260..1F265;W # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F300..1F320;W # So [33] CYCLONE..SHOOTING STAR +1F321..1F32C;N # So [12] THERMOMETER..WIND BLOWING FACE +1F32D..1F335;W # So [9] HOT DOG..CACTUS +1F336;N # So HOT PEPPER +1F337..1F37C;W # So [70] TULIP..BABY BOTTLE +1F37D;N # So FORK AND KNIFE WITH PLATE +1F37E..1F393;W # So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP +1F394..1F39F;N # So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS +1F3A0..1F3CA;W # So [43] CAROUSEL HORSE..SWIMMER +1F3CB..1F3CE;N # So [4] WEIGHT LIFTER..RACING CAR +1F3CF..1F3D3;W # So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL +1F3D4..1F3DF;N # So [12] SNOW CAPPED MOUNTAIN..STADIUM +1F3E0..1F3F0;W # So [17] HOUSE BUILDING..EUROPEAN CASTLE +1F3F1..1F3F3;N # So [3] WHITE PENNANT..WAVING WHITE FLAG +1F3F4;W # So WAVING BLACK FLAG +1F3F5..1F3F7;N # So [3] ROSETTE..LABEL +1F3F8..1F3FA;W # So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA +1F3FB..1F3FF;W # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F43E;W # So [63] RAT..PAW PRINTS +1F43F;N # So CHIPMUNK +1F440;W # So EYES +1F441;N # So EYE +1F442..1F4FC;W # So [187] EAR..VIDEOCASSETTE +1F4FD..1F4FE;N # So [2] FILM PROJECTOR..PORTABLE STEREO +1F4FF..1F53D;W # So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE +1F53E..1F54A;N # So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE +1F54B..1F54E;W # So [4] KAABA..MENORAH WITH NINE BRANCHES +1F54F;N # So BOWL OF HYGIEIA +1F550..1F567;W # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY +1F568..1F579;N # So [18] RIGHT SPEAKER..JOYSTICK +1F57A;W # So MAN DANCING +1F57B..1F594;N # So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND +1F595..1F596;W # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597..1F5A3;N # So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX +1F5A4;W # So BLACK HEART +1F5A5..1F5FA;N # So [86] DESKTOP COMPUTER..WORLD MAP +1F5FB..1F5FF;W # So [5] MOUNT FUJI..MOYAI +1F600..1F64F;W # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS +1F650..1F67F;N # So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD +1F680..1F6C5;W # So [70] ROCKET..LEFT LUGGAGE +1F6C6..1F6CB;N # So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP +1F6CC;W # So SLEEPING ACCOMMODATION +1F6CD..1F6CF;N # So [3] SHOPPING BAGS..BED +1F6D0..1F6D2;W # So [3] PLACE OF WORSHIP..SHOPPING TROLLEY +1F6D3..1F6D4;N # So [2] STUPA..PAGODA +1F6D5..1F6D7;W # So [3] HINDU TEMPLE..ELEVATOR +1F6DC..1F6DF;W # So [4] WIRELESS..RING BUOY +1F6E0..1F6EA;N # So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE +1F6EB..1F6EC;W # So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING +1F6F0..1F6F3;N # So [4] SATELLITE..PASSENGER SHIP +1F6F4..1F6FC;W # So [9] SCOOTER..ROLLER SKATE +1F700..1F776;N # So [119] ALCHEMICAL SYMBOL FOR QUINTESSENCE..LUNAR ECLIPSE +1F77B..1F77F;N # So [5] HAUMEA..ORCUS +1F780..1F7D9;N # So [90] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..NINE POINTED WHITE STAR +1F7E0..1F7EB;W # So [12] LARGE ORANGE CIRCLE..LARGE BROWN SQUARE +1F7F0;W # So HEAVY EQUALS SIGN +1F800..1F80B;N # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F810..1F847;N # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F850..1F859;N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F860..1F887;N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F890..1F8AD;N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS +1F8B0..1F8B1;N # So [2] ARROW POINTING UPWARDS THEN NORTH WEST..ARROW POINTING RIGHTWARDS THEN CURVING SOUTH WEST +1F900..1F90B;N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F90C..1F93A;W # So [47] PINCHED FINGERS..FENCER +1F93B;N # So MODERN PENTATHLON +1F93C..1F945;W # So [10] WRESTLERS..GOAL NET +1F946;N # So RIFLE +1F947..1F9FF;W # So [185] FIRST PLACE MEDAL..NAZAR AMULET +1FA00..1FA53;N # So [84] NEUTRAL CHESS KING..BLACK CHESS KNIGHT-BISHOP +1FA60..1FA6D;N # So [14] XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER +1FA70..1FA7C;W # So [13] BALLET SHOES..CRUTCH +1FA80..1FA88;W # So [9] YO-YO..FLUTE +1FA90..1FABD;W # So [46] RINGED PLANET..WING +1FABF..1FAC5;W # So [7] GOOSE..PERSON WITH CROWN +1FACE..1FADB;W # So [14] MOOSE..PEA POD +1FAE0..1FAE8;W # So [9] MELTING FACE..SHAKING FACE +1FAF0..1FAF8;W # So [9] HAND WITH INDEX FINGER AND THUMB CROSSED..RIGHTWARDS PUSHING HAND +1FB00..1FB92;N # So [147] BLOCK SEXTANT-1..UPPER HALF INVERSE MEDIUM SHADE AND LOWER HALF BLOCK +1FB94..1FBCA;N # So [55] LEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF BLOCK..WHITE UP-POINTING CHEVRON +1FBF0..1FBF9;N # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE +20000..2A6DF;W # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF +2A6E0..2A6FF;W # Cn [32] .. +2A700..2B739;W # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 +2B73A..2B73F;W # Cn [6] .. +2B740..2B81D;W # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B81E..2B81F;W # Cn [2] .. +2B820..2CEA1;W # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEA2..2CEAF;W # Cn [14] .. +2CEB0..2EBE0;W # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBE1..2F7FF;W # Cn [3103] .. +2F800..2FA1D;W # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D +2FA1E..2FA1F;W # Cn [2] .. +2FA20..2FFFD;W # Cn [1502] .. +30000..3134A;W # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +3134B..3134F;W # Cn [5] .. +31350..323AF;W # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF +323B0..3FFFD;W # Cn [56398] .. +E0001;N # Cf LANGUAGE TAG +E0020..E007F;N # Cf [96] TAG SPACE..CANCEL TAG +E0100..E01EF;A # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 +F0000..FFFFD;A # Co [65534] .. +100000..10FFFD;A # Co [65534] .. + +# EOF diff --git a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt index 6ee92f6eecaa..a12b5eef1efc 100644 --- a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt +++ b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt @@ -1,11 +1,11 @@ -# GraphemeBreakProperty-13.0.0.txt -# Date: 2019-10-21, 14:30:35 GMT -# © 2019 Unicode®, Inc. +# GraphemeBreakProperty-15.0.0.txt +# Date: 2022-04-27, 17:07:38 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # ================================================ @@ -21,6 +21,7 @@ 0600..0605 ; Prepend # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE 06DD ; Prepend # Cf ARABIC END OF AYAH 070F ; Prepend # Cf SYRIAC ABBREVIATION MARK +0890..0891 ; Prepend # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE 08E2 ; Prepend # Cf ARABIC DISPUTED END OF AYAH 0D4E ; Prepend # Lo MALAYALAM LETTER DOT REPH 110BD ; Prepend # Cf KAITHI NUMBER SIGN @@ -31,8 +32,9 @@ 11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA 11A84..11A89 ; Prepend # Lo [6] SOYOMBO SIGN JIHVAMULIYA..SOYOMBO CLUSTER-INITIAL LETTER SA 11D46 ; Prepend # Lo MASARAM GONDI REPHA +11F02 ; Prepend # Lo KAWI SIGN REPHA -# Total code points: 24 +# Total code points: 27 # ================================================ @@ -66,7 +68,7 @@ FEFF ; Control # Cf ZERO WIDTH NO-BREAK SPACE FFF0..FFF8 ; Control # Cn [9] .. FFF9..FFFB ; Control # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR -13430..13438 ; Control # Cf [9] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END SEGMENT +13430..1343F ; Control # Cf [16] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE 1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1D173..1D17A ; Control # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE E0000 ; Control # Cn @@ -75,7 +77,7 @@ E0002..E001F ; Control # Cn [30] .. E0080..E00FF ; Control # Cn [128] .. E01F0..E0FFF ; Control # Cn [3600] .. -# Total code points: 3886 +# Total code points: 3893 # ================================================ @@ -104,7 +106,8 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -08D3..08E1 ; Extend # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA +0898..089F ; Extend # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +08CA..08E1 ; Extend # Mn [24] ARABIC SMALL HIGH FARSI YEH..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE 093C ; Extend # Mn DEVANAGARI SIGN NUKTA @@ -151,6 +154,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0BD7 ; Extend # Mc TAMIL AU LENGTH MARK 0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C04 ; Extend # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE +0C3C ; Extend # Mn TELUGU SIGN NUKTA 0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI 0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA @@ -182,7 +186,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 0E47..0E4E ; Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN 0EB1 ; Extend # Mn LAO VOWEL SIGN MAI KAN 0EB4..0EBC ; Extend # Mn [9] LAO VOWEL SIGN I..LAO SEMIVOWEL SIGN LO -0EC8..0ECD ; Extend # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA +0EC8..0ECE ; Extend # Mn [7] LAO TONE MAI EK..LAO YAMAKKAN 0F18..0F19 ; Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS 0F35 ; Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA 0F37 ; Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS @@ -206,7 +210,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI 135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK 1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA -1732..1734 ; Extend # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD +1732..1733 ; Extend # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U 1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U 1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U 17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA @@ -215,6 +219,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; Extend # Mn KHMER SIGN ATTHACAN 180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180F ; Extend # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR 1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U @@ -232,7 +237,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT 1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY -1ABF..1AC0 ; Extend # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW +1ABF..1ACE ; Extend # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T 1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B34 ; Extend # Mn BALINESE SIGN REREKAN 1B35 ; Extend # Mc BALINESE VOWEL SIGN TEDUNG @@ -256,8 +261,7 @@ E01F0..E0FFF ; Control # Cn [3600] .. 1CED ; Extend # Mn VEDIC SIGN TIRYAK 1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE 1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW -1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DFF ; Extend # Mn [64] COMBINING DOTTED GRAVE ACCENT..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 200C ; Extend # Cf ZERO WIDTH NON-JOINER 20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH @@ -321,12 +325,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI 10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +10EFD..10EFF ; Extend # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW 11001 ; Extend # Mn BRAHMI SIGN ANUSVARA 11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA +11070 ; Extend # Mn BRAHMI SIGN OLD TAMIL VIRAMA +11073..11074 ; Extend # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O 1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA 110B3..110B6 ; Extend # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI 110B9..110BA ; Extend # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA +110C2 ; Extend # Mn KAITHI VOWEL SIGN VOCALIC R 11100..11102 ; Extend # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA 11127..1112B ; Extend # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU 1112D..11134 ; Extend # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA @@ -339,6 +348,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 1123E ; Extend # Mn KHOJKI SIGN SUKUN +11241 ; Extend # Mn KHOJKI VOWEL SIGN VOCALIC R 112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA 112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA 11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU @@ -406,12 +416,20 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11D95 ; Extend # Mn GUNJALA GONDI SIGN ANUSVARA 11D97 ; Extend # Mn GUNJALA GONDI VIRAMA 11EF3..11EF4 ; Extend # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U +11F00..11F01 ; Extend # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA +11F36..11F3A ; Extend # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R +11F40 ; Extend # Mn KAWI VOWEL SIGN EU +11F42 ; Extend # Mn KAWI CONJOINER +13440 ; Extend # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY +13447..13455 ; Extend # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F4F ; Extend # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16FE4 ; Extend # Mn KHITAN SMALL SCRIPT FILLER 1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1CF00..1CF2D ; Extend # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT +1CF30..1CF46 ; Extend # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D165 ; Extend # Mc MUSICAL SYMBOL COMBINING STEM 1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 1D16E..1D172 ; Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 @@ -430,15 +448,18 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI 1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS 1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E08F ; Extend # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I 1E130..1E136 ; Extend # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2AE ; Extend # Mn TOTO SIGN RISING TONE 1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI +1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1984 +# Total code points: 2130 # ================================================ @@ -479,6 +500,7 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 0CC3..0CC4 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR 0CC7..0CC8 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI 0CCA..0CCB ; SpacingMark # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CF3 ; SpacingMark # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT 0D02..0D03 ; SpacingMark # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3F..0D40 ; SpacingMark # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II 0D46..0D48 ; SpacingMark # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI @@ -495,6 +517,8 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 103B..103C ; SpacingMark # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA 1056..1057 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR 1084 ; SpacingMark # Mc MYANMAR VOWEL SIGN SHAN E +1715 ; SpacingMark # Mc TAGALOG SIGN PAMUDPOD +1734 ; SpacingMark # Mc HANUNOO SIGN PAMUDPOD 17B6 ; SpacingMark # Mc KHMER VOWEL SIGN AA 17BE..17C5 ; SpacingMark # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU 17C7..17C8 ; SpacingMark # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU @@ -579,7 +603,6 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 116AC ; SpacingMark # Mc TAKRI SIGN VISARGA 116AE..116AF ; SpacingMark # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA -11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11726 ; SpacingMark # Mc AHOM VOWEL SIGN E 1182C..1182E ; SpacingMark # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II 11838 ; SpacingMark # Mc DOGRA SIGN VISARGA @@ -603,12 +626,16 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11D93..11D94 ; SpacingMark # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU 11D96 ; SpacingMark # Mc GUNJALA GONDI SIGN VISARGA 11EF5..11EF6 ; SpacingMark # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +11F03 ; SpacingMark # Mc KAWI SIGN VISARGA +11F34..11F35 ; SpacingMark # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA +11F3E..11F3F ; SpacingMark # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI +11F41 ; SpacingMark # Mc KAWI SIGN KILLER 16F51..16F87 ; SpacingMark # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI 16FF0..16FF1 ; SpacingMark # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY 1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT -# Total code points: 388 +# Total code points: 395 # ================================================ diff --git a/lib/stdlib/uc_spec/PropList.txt b/lib/stdlib/uc_spec/PropList.txt index 7d2f44c56fab..b49d6460c169 100644 --- a/lib/stdlib/uc_spec/PropList.txt +++ b/lib/stdlib/uc_spec/PropList.txt @@ -1,11 +1,11 @@ -# PropList-13.0.0.txt -# Date: 2019-11-27, 03:13:28 GMT -# © 2019 Unicode®, Inc. +# PropList-15.0.0.txt +# Date: 2022-08-05, 22:17:16 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # ================================================ @@ -54,6 +54,7 @@ 2E1A ; Dash # Pd HYPHEN WITH DIAERESIS 2E3A..2E3B ; Dash # Pd [2] TWO-EM DASH..THREE-EM DASH 2E40 ; Dash # Pd DOUBLE HYPHEN +2E5D ; Dash # Pd OBLIQUE HYPHEN 301C ; Dash # Pd WAVE DASH 3030 ; Dash # Pd WAVY DASH 30A0 ; Dash # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN @@ -63,7 +64,7 @@ FE63 ; Dash # Pd SMALL HYPHEN-MINUS FF0D ; Dash # Pd FULLWIDTH HYPHEN-MINUS 10EAD ; Dash # Pd YEZIDI HYPHENATION MARK -# Total code points: 29 +# Total code points: 30 # ================================================ @@ -126,7 +127,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 05C3 ; Terminal_Punctuation # Po HEBREW PUNCTUATION SOF PASUQ 060C ; Terminal_Punctuation # Po ARABIC COMMA 061B ; Terminal_Punctuation # Po ARABIC SEMICOLON -061E..061F ; Terminal_Punctuation # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK +061D..061F ; Terminal_Punctuation # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK 06D4 ; Terminal_Punctuation # Po ARABIC FULL STOP 0700..070A ; Terminal_Punctuation # Po [11] SYRIAC END OF PARAGRAPH..SYRIAC CONTRACTION 070C ; Terminal_Punctuation # Po SYRIAC HARKLEAN METOBELUS @@ -150,6 +151,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 1AA8..1AAB ; Terminal_Punctuation # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU 1B5A..1B5B ; Terminal_Punctuation # Po [2] BALINESE PANTI..BALINESE PAMADA 1B5D..1B5F ; Terminal_Punctuation # Po [3] BALINESE CARIK PAMUNGKAH..BALINESE CARIK PAREREN +1B7D..1B7E ; Terminal_Punctuation # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG 1C3B..1C3F ; Terminal_Punctuation # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK 1C7E..1C7F ; Terminal_Punctuation # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD 203C..203D ; Terminal_Punctuation # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG @@ -159,6 +161,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET 2E41 ; Terminal_Punctuation # Po REVERSED COMMA 2E4C ; Terminal_Punctuation # Po MEDIEVAL COMMA 2E4E..2E4F ; Terminal_Punctuation # Po [2] PUNCTUS ELEVATUS MARK..CORNISH VERSE DIVIDER +2E53..2E54 ; Terminal_Punctuation # Po [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK 3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK @@ -189,6 +192,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION 10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT 10F55..10F59 ; Terminal_Punctuation # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10F86..10F89 ; Terminal_Punctuation # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS 11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS 110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK @@ -211,6 +215,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 11C41..11C43 ; Terminal_Punctuation # Po [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR 11C71 ; Terminal_Punctuation # Po MARCHEN MARK SHAD 11EF7..11EF8 ; Terminal_Punctuation # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11F43..11F44 ; Terminal_Punctuation # Po [2] KAWI DANDA..KAWI DOUBLE DANDA 12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON 16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP @@ -220,7 +225,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON -# Total code points: 267 +# Total code points: 278 # ================================================ @@ -503,6 +508,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0BD7 ; Other_Alphabetic # Mc TAMIL AU LENGTH MARK 0C00 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 0C01..0C03 ; Other_Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE 0C3E..0C40 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 0C41..0C44 ; Other_Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR 0C46..0C48 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI @@ -520,6 +526,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU 0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0CF3 ; Other_Alphabetic # Mc KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT 0D00..0D01 ; Other_Alphabetic # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II @@ -544,7 +551,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0ECD ; Other_Alphabetic # Mn LAO NIGGAHITA 0F71..0F7E ; Other_Alphabetic # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO 0F7F ; Other_Alphabetic # Mc TIBETAN SIGN RNAM BCAD -0F80..0F81 ; Other_Alphabetic # Mn [2] TIBETAN VOWEL SIGN REVERSED I..TIBETAN VOWEL SIGN REVERSED II +0F80..0F83 ; Other_Alphabetic # Mn [4] TIBETAN VOWEL SIGN REVERSED I..TIBETAN SIGN SNA LDAN 0F8D..0F97 ; Other_Alphabetic # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA 0F99..0FBC ; Other_Alphabetic # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA 102B..102C ; Other_Alphabetic # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA @@ -600,6 +607,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 1A6D..1A72 ; Other_Alphabetic # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI 1A73..1A74 ; Other_Alphabetic # Mn [2] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN MAI KANG 1ABF..1AC0 ; Other_Alphabetic # Mn [2] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER TURNED W BELOW +1ACC..1ACE ; Other_Alphabetic # Mn [3] COMBINING LATIN SMALL LETTER INSULAR G..COMBINING LATIN SMALL LETTER INSULAR T 1B00..1B03 ; Other_Alphabetic # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 1B04 ; Other_Alphabetic # Mc BALINESE SIGN BISAH 1B35 ; Other_Alphabetic # Mc BALINESE VOWEL SIGN TEDUNG @@ -686,10 +694,13 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 11001 ; Other_Alphabetic # Mn BRAHMI SIGN ANUSVARA 11002 ; Other_Alphabetic # Mc BRAHMI SIGN VISARGA 11038..11045 ; Other_Alphabetic # Mn [14] BRAHMI VOWEL SIGN AA..BRAHMI VOWEL SIGN AU +11073..11074 ; Other_Alphabetic # Mn [2] BRAHMI VOWEL SIGN OLD TAMIL SHORT E..BRAHMI VOWEL SIGN OLD TAMIL SHORT O +11080..11081 ; Other_Alphabetic # Mn [2] KAITHI SIGN CANDRABINDU..KAITHI SIGN ANUSVARA 11082 ; Other_Alphabetic # Mc KAITHI SIGN VISARGA 110B0..110B2 ; Other_Alphabetic # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II 110B3..110B6 ; Other_Alphabetic # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI 110B7..110B8 ; Other_Alphabetic # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU +110C2 ; Other_Alphabetic # Mn KAITHI VOWEL SIGN VOCALIC R 11100..11102 ; Other_Alphabetic # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA 11127..1112B ; Other_Alphabetic # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU 1112C ; Other_Alphabetic # Mc CHAKMA VOWEL SIGN E @@ -708,6 +719,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA 11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA 1123E ; Other_Alphabetic # Mn KHOJKI SIGN SUKUN +11241 ; Other_Alphabetic # Mn KHOJKI VOWEL SIGN VOCALIC R 112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA 112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU @@ -800,6 +812,12 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 11D96 ; Other_Alphabetic # Mc GUNJALA GONDI SIGN VISARGA 11EF3..11EF4 ; Other_Alphabetic # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U 11EF5..11EF6 ; Other_Alphabetic # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O +11F00..11F01 ; Other_Alphabetic # Mn [2] KAWI SIGN CANDRABINDU..KAWI SIGN ANUSVARA +11F03 ; Other_Alphabetic # Mc KAWI SIGN VISARGA +11F34..11F35 ; Other_Alphabetic # Mc [2] KAWI VOWEL SIGN AA..KAWI VOWEL SIGN ALTERNATE AA +11F36..11F3A ; Other_Alphabetic # Mn [5] KAWI VOWEL SIGN I..KAWI VOWEL SIGN VOCALIC R +11F3E..11F3F ; Other_Alphabetic # Mc [2] KAWI VOWEL SIGN E..KAWI VOWEL SIGN AI +11F40 ; Other_Alphabetic # Mn KAWI VOWEL SIGN EU 16F4F ; Other_Alphabetic # Mn MIAO SIGN CONSONANT MODIFIER BAR 16F51..16F87 ; Other_Alphabetic # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI 16F8F..16F92 ; Other_Alphabetic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW @@ -810,12 +828,13 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 1E01B..1E021 ; Other_Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI 1E023..1E024 ; Other_Alphabetic # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS 1E026..1E02A ; Other_Alphabetic # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E08F ; Other_Alphabetic # Mn COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I 1E947 ; Other_Alphabetic # Mn ADLAM HAMZA 1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z 1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1398 +# Total code points: 1425 # ================================================ @@ -824,7 +843,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE 3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY 3400..4DBF ; Ideographic # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF -4E00..9FFC ; Ideographic # Lo [20989] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFC +4E00..9FFF ; Ideographic # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 16FE4 ; Ideographic # Mn KHITAN SMALL SCRIPT FILLER @@ -832,15 +851,16 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 18800..18CD5 ; Ideographic # Lo [1238] TANGUT COMPONENT-001..KHITAN SMALL SCRIPT CHARACTER-18CD5 18D00..18D08 ; Ideographic # Lo [9] TANGUT IDEOGRAPH-18D00..TANGUT IDEOGRAPH-18D08 1B170..1B2FB ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB -20000..2A6DD ; Ideographic # Lo [42718] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DD -2A700..2B734 ; Ideographic # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 +20000..2A6DF ; Ideographic # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF +2A700..2B739 ; Ideographic # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 2B740..2B81D ; Ideographic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; Ideographic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 2CEB0..2EBE0 ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 30000..3134A ; Ideographic # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +31350..323AF ; Ideographic # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 101652 +# Total code points: 105854 # ================================================ @@ -885,6 +905,9 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 07EB..07F3 ; Diacritic # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE 07F4..07F5 ; Diacritic # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE 0818..0819 ; Diacritic # Mn [2] SAMARITAN MARK OCCLUSION..SAMARITAN MARK DAGESH +0898..089F ; Diacritic # Mn [8] ARABIC SMALL HIGH WORD AL-JUZ..ARABIC HALF MADDA OVER MADDA +08C9 ; Diacritic # Lm ARABIC SMALL FARSI YEH +08CA..08D2 ; Diacritic # Mn [9] ARABIC SMALL HIGH FARSI YEH..ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW 08E3..08FE ; Diacritic # Mn [28] ARABIC TURNED DAMMA BELOW..ARABIC DAMMA WITH DOT 093C ; Diacritic # Mn DEVANAGARI SIGN NUKTA 094D ; Diacritic # Mn DEVANAGARI SIGN VIRAMA @@ -901,6 +924,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 0B4D ; Diacritic # Mn ORIYA SIGN VIRAMA 0B55 ; Diacritic # Mn ORIYA SIGN OVERLINE 0BCD ; Diacritic # Mn TAMIL SIGN VIRAMA +0C3C ; Diacritic # Mn TELUGU SIGN NUKTA 0C4D ; Diacritic # Mn TELUGU SIGN VIRAMA 0CBC ; Diacritic # Mn KANNADA SIGN NUKTA 0CCD ; Diacritic # Mn KANNADA SIGN VIRAMA @@ -928,12 +952,16 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 108F ; Diacritic # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5 109A..109B ; Diacritic # Mc [2] MYANMAR SIGN KHAMTI TONE-1..MYANMAR SIGN KHAMTI TONE-3 135D..135F ; Diacritic # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK +1714 ; Diacritic # Mn TAGALOG SIGN VIRAMA +1715 ; Diacritic # Mc TAGALOG SIGN PAMUDPOD 17C9..17D3 ; Diacritic # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; Diacritic # Mn KHMER SIGN ATTHACAN 1939..193B ; Diacritic # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I 1A75..1A7C ; Diacritic # Mn [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN 1A7F ; Diacritic # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT 1AB0..1ABD ; Diacritic # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; Diacritic # Me COMBINING PARENTHESES OVERLAY +1AC1..1ACB ; Diacritic # Mn [11] COMBINING LEFT PARENTHESIS ABOVE LEFT..COMBINING TRIPLE ACUTE ACCENT 1B34 ; Diacritic # Mn BALINESE SIGN REREKAN 1B44 ; Diacritic # Mc BALINESE ADEG ADEG 1B6B..1B73 ; Diacritic # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG @@ -952,8 +980,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW -1DF5..1DF9 ; Diacritic # Mn [5] COMBINING UP TACK ABOVE..COMBINING WIDE INVERTED BRIDGE BELOW -1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DF5..1DFF ; Diacritic # Mn [11] COMBINING UP TACK ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1FBD ; Diacritic # Sk GREEK KORONIS 1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI 1FCD..1FCF ; Diacritic # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI @@ -1008,10 +1035,17 @@ FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK FFE3 ; Diacritic # Sk FULLWIDTH MACRON 102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK +10780..10785 ; Diacritic # Lm [6] MODIFIER LETTER SMALL CAPITAL AA..MODIFIER LETTER SMALL B WITH HOOK +10787..107B0 ; Diacritic # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2..107BA ; Diacritic # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL 10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 10D22..10D23 ; Diacritic # Lo [2] HANIFI ROHINGYA MARK SAKIN..HANIFI ROHINGYA MARK NA KHONNA 10D24..10D27 ; Diacritic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +10EFD..10EFF ; Diacritic # Mn [3] ARABIC SMALL LOW WORD SAKTA..ARABIC SMALL LOW WORD MADDA 10F46..10F50 ; Diacritic # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +10F82..10F85 ; Diacritic # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW +11046 ; Diacritic # Mn BRAHMI VIRAMA +11070 ; Diacritic # Mn BRAHMI SIGN OLD TAMIL VIRAMA 110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA 11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA 11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA @@ -1044,23 +1078,31 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 11D42 ; Diacritic # Mn MASARAM GONDI SIGN NUKTA 11D44..11D45 ; Diacritic # Mn [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA 11D97 ; Diacritic # Mn GUNJALA GONDI VIRAMA +13447..13455 ; Diacritic # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED 16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Diacritic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 16FF0..16FF1 ; Diacritic # Mc [2] VIETNAMESE ALTERNATE READING MARK CA..VIETNAMESE ALTERNATE READING MARK NHAY +1AFF0..1AFF3 ; Diacritic # Lm [4] KATAKANA LETTER MINNAN TONE-2..KATAKANA LETTER MINNAN TONE-5 +1AFF5..1AFFB ; Diacritic # Lm [7] KATAKANA LETTER MINNAN TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-5 +1AFFD..1AFFE ; Diacritic # Lm [2] KATAKANA LETTER MINNAN NASALIZED TONE-7..KATAKANA LETTER MINNAN NASALIZED TONE-8 +1CF00..1CF2D ; Diacritic # Mn [46] ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT..ZNAMENNY COMBINING MARK KRYZH ON LEFT +1CF30..1CF46 ; Diacritic # Mn [23] ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO..ZNAMENNY PRIZNAK MODIFIER ROG 1D167..1D169 ; Diacritic # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 1D16D..1D172 ; Diacritic # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 1D17B..1D182 ; Diacritic # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1E030..1E06D ; Diacritic # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE 1E130..1E136 ; Diacritic # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2AE ; Diacritic # Mn TOTO SIGN RISING TONE 1E2EC..1E2EF ; Diacritic # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI 1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 1E944..1E946 ; Diacritic # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK 1E948..1E94A ; Diacritic # Mn [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA -# Total code points: 882 +# Total code points: 1144 # ================================================ @@ -1088,6 +1130,7 @@ AA70 ; Extender # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION AADD ; Extender # Lm TAI VIET SYMBOL SAM AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +10781..10782 ; Extender # Lm [2] MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON..MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON 1135D ; Extender # Lo GRANTHA SIGN PLUTA 115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 11A98 ; Extender # Mn SOYOMBO GEMINATION MARK @@ -1097,7 +1140,7 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND 1E13C..1E13D ; Extender # Lm [2] NYIAKENG PUACHUE HMONG SIGN XW XW..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER 1E944..1E946 ; Extender # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK -# Total code points: 48 +# Total code points: 50 # ================================================ @@ -1108,6 +1151,7 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND 02E0..02E4 ; Other_Lowercase # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP 0345 ; Other_Lowercase # Mn COMBINING GREEK YPOGEGRAMMENI 037A ; Other_Lowercase # Lm GREEK YPOGEGRAMMENI +10FC ; Other_Lowercase # Lm MODIFIER LETTER GEORGIAN NAR 1D2C..1D6A ; Other_Lowercase # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1D78 ; Other_Lowercase # Lm MODIFIER LETTER CYRILLIC EN 1D9B..1DBF ; Other_Lowercase # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA @@ -1119,10 +1163,17 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND 2C7C..2C7D ; Other_Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V A69C..A69D ; Other_Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN A770 ; Other_Lowercase # Lm MODIFIER LETTER US +A7F2..A7F4 ; Other_Lowercase # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q A7F8..A7F9 ; Other_Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE AB5C..AB5F ; Other_Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK +AB69 ; Other_Lowercase # Lm MODIFIER LETTER SMALL TURNED W +10780 ; Other_Lowercase # Lm MODIFIER LETTER SMALL CAPITAL AA +10783..10785 ; Other_Lowercase # Lm [3] MODIFIER LETTER SMALL AE..MODIFIER LETTER SMALL B WITH HOOK +10787..107B0 ; Other_Lowercase # Lm [42] MODIFIER LETTER SMALL DZ DIGRAPH..MODIFIER LETTER SMALL V WITH RIGHT HOOK +107B2..107BA ; Other_Lowercase # Lm [9] MODIFIER LETTER SMALL CAPITAL Y..MODIFIER LETTER SMALL S WITH CURL +1E030..1E06D ; Other_Lowercase # Lm [62] MODIFIER LETTER CYRILLIC SMALL A..MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE -# Total code points: 189 +# Total code points: 311 # ================================================ @@ -1211,7 +1262,7 @@ E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG # ================================================ 3400..4DBF ; Unified_Ideograph # Lo [6592] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DBF -4E00..9FFC ; Unified_Ideograph # Lo [20989] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFC +4E00..9FFF ; Unified_Ideograph # Lo [20992] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FFF FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11 FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 @@ -1219,14 +1270,15 @@ FA1F ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA1F FA21 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA21 FA23..FA24 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24 FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29 -20000..2A6DD ; Unified_Ideograph # Lo [42718] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DD -2A700..2B734 ; Unified_Ideograph # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 +20000..2A6DF ; Unified_Ideograph # Lo [42720] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6DF +2A700..2B739 ; Unified_Ideograph # Lo [4154] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B739 2B740..2B81D ; Unified_Ideograph # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; Unified_Ideograph # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 2CEB0..2EBE0 ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 30000..3134A ; Unified_Ideograph # Lo [4939] CJK UNIFIED IDEOGRAPH-30000..CJK UNIFIED IDEOGRAPH-3134A +31350..323AF ; Unified_Ideograph # Lo [4192] CJK UNIFIED IDEOGRAPH-31350..CJK UNIFIED IDEOGRAPH-323AF -# Total code points: 92856 +# Total code points: 97058 # ================================================ @@ -1291,8 +1343,11 @@ E0001 ; Deprecated # Cf LANGUAGE TAG 1D62A..1D62B ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF ITALIC SMALL I..MATHEMATICAL SANS-SERIF ITALIC SMALL J 1D65E..1D65F ; Soft_Dotted # L& [2] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J 1D692..1D693 ; Soft_Dotted # L& [2] MATHEMATICAL MONOSPACE SMALL I..MATHEMATICAL MONOSPACE SMALL J +1DF1A ; Soft_Dotted # L& LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK +1E04C..1E04D ; Soft_Dotted # Lm [2] MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I..MODIFIER LETTER CYRILLIC SMALL JE +1E068 ; Soft_Dotted # Lm CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I -# Total code points: 46 +# Total code points: 50 # ================================================ @@ -1330,7 +1385,7 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 002E ; Sentence_Terminal # Po FULL STOP 003F ; Sentence_Terminal # Po QUESTION MARK 0589 ; Sentence_Terminal # Po ARMENIAN FULL STOP -061E..061F ; Sentence_Terminal # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK +061D..061F ; Sentence_Terminal # Po [3] ARABIC END OF TEXT MARK..ARABIC QUESTION MARK 06D4 ; Sentence_Terminal # Po ARABIC FULL STOP 0700..0702 ; Sentence_Terminal # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP 07F9 ; Sentence_Terminal # Po NKO EXCLAMATION MARK @@ -1349,12 +1404,14 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET 1AA8..1AAB ; Sentence_Terminal # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU 1B5A..1B5B ; Sentence_Terminal # Po [2] BALINESE PANTI..BALINESE PAMADA 1B5E..1B5F ; Sentence_Terminal # Po [2] BALINESE CARIK SIKI..BALINESE CARIK PAREREN +1B7D..1B7E ; Sentence_Terminal # Po [2] BALINESE PANTI LANTANG..BALINESE PAMADA LANTANG 1C3B..1C3C ; Sentence_Terminal # Po [2] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION NYET THYOOM TA-ROL 1C7E..1C7F ; Sentence_Terminal # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD 203C..203D ; Sentence_Terminal # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG 2047..2049 ; Sentence_Terminal # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK 2E2E ; Sentence_Terminal # Po REVERSED QUESTION MARK 2E3C ; Sentence_Terminal # Po STENOGRAPHIC FULL STOP +2E53..2E54 ; Sentence_Terminal # Po [2] MEDIEVAL EXCLAMATION MARK..MEDIEVAL QUESTION MARK 3002 ; Sentence_Terminal # Po IDEOGRAPHIC FULL STOP A4FF ; Sentence_Terminal # Po LISU PUNCTUATION FULL STOP A60E..A60F ; Sentence_Terminal # Po [2] VAI FULL STOP..VAI QUESTION MARK @@ -1375,6 +1432,7 @@ FF1F ; Sentence_Terminal # Po FULLWIDTH QUESTION MARK FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP 10A56..10A57 ; Sentence_Terminal # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA 10F55..10F59 ; Sentence_Terminal # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT +10F86..10F89 ; Sentence_Terminal # Po [4] OLD UYGHUR PUNCTUATION BAR..OLD UYGHUR PUNCTUATION FOUR DOTS 11047..11048 ; Sentence_Terminal # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA 110BE..110C1 ; Sentence_Terminal # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA 11141..11143 ; Sentence_Terminal # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK @@ -1395,6 +1453,7 @@ FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP 11A9B..11A9C ; Sentence_Terminal # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD 11C41..11C42 ; Sentence_Terminal # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA 11EF7..11EF8 ; Sentence_Terminal # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION +11F43..11F44 ; Sentence_Terminal # Po [2] KAWI DANDA..KAWI DOUBLE DANDA 16A6E..16A6F ; Sentence_Terminal # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; Sentence_Terminal # Po BASSA VAH FULL STOP 16B37..16B38 ; Sentence_Terminal # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB @@ -1403,15 +1462,16 @@ FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP 1BC9F ; Sentence_Terminal # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA88 ; Sentence_Terminal # Po SIGNWRITING FULL STOP -# Total code points: 143 +# Total code points: 154 # ================================================ 180B..180D ; Variation_Selector # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180F ; Variation_Selector # Mn MONGOLIAN FREE VARIATION SELECTOR FOUR FE00..FE0F ; Variation_Selector # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 259 +# Total code points: 260 # ================================================ @@ -1644,8 +1704,17 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK 2E43..2E4F ; Pattern_Syntax # Po [13] DASH WITH LEFT UPTURN..CORNISH VERSE DIVIDER 2E50..2E51 ; Pattern_Syntax # So [2] CROSS PATTY WITH RIGHT CROSSBAR..CROSS PATTY WITH LEFT CROSSBAR -2E52 ; Pattern_Syntax # Po TIRONIAN SIGN CAPITAL ET -2E53..2E7F ; Pattern_Syntax # Cn [45] .. +2E52..2E54 ; Pattern_Syntax # Po [3] TIRONIAN SIGN CAPITAL ET..MEDIEVAL QUESTION MARK +2E55 ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH STROKE +2E56 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH STROKE +2E57 ; Pattern_Syntax # Ps LEFT SQUARE BRACKET WITH DOUBLE STROKE +2E58 ; Pattern_Syntax # Pe RIGHT SQUARE BRACKET WITH DOUBLE STROKE +2E59 ; Pattern_Syntax # Ps TOP HALF LEFT PARENTHESIS +2E5A ; Pattern_Syntax # Pe TOP HALF RIGHT PARENTHESIS +2E5B ; Pattern_Syntax # Ps BOTTOM HALF LEFT PARENTHESIS +2E5C ; Pattern_Syntax # Pe BOTTOM HALF RIGHT PARENTHESIS +2E5D ; Pattern_Syntax # Pd OBLIQUE HYPHEN +2E5E..2E7F ; Pattern_Syntax # Cn [34] .. 3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK 3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET 3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET @@ -1682,11 +1751,12 @@ FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT 0600..0605 ; Prepended_Concatenation_Mark # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE 06DD ; Prepended_Concatenation_Mark # Cf ARABIC END OF AYAH 070F ; Prepended_Concatenation_Mark # Cf SYRIAC ABBREVIATION MARK +0890..0891 ; Prepended_Concatenation_Mark # Cf [2] ARABIC POUND MARK ABOVE..ARABIC PIASTRE MARK ABOVE 08E2 ; Prepended_Concatenation_Mark # Cf ARABIC DISPUTED END OF AYAH 110BD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN 110CD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN ABOVE -# Total code points: 11 +# Total code points: 13 # ================================================ diff --git a/lib/stdlib/uc_spec/README-UPDATE.txt b/lib/stdlib/uc_spec/README-UPDATE.txt index 57fe885b5b4f..0bf611761168 100644 --- a/lib/stdlib/uc_spec/README-UPDATE.txt +++ b/lib/stdlib/uc_spec/README-UPDATE.txt @@ -1,11 +1,51 @@ -When updating the unicode version copy the necessary files to this -directory. -And update the test files in stdlib/test/unicode_util_SUITE_data/* +Unicode 15.0.0 was updated from: +- https://www.unicode.org/Public/15.0.0/ucd/ +- https://www.unicode.org/Public/15.0.0/ucd/auxiliary/ +- https://www.unicode.org/Public/15.0.0/ucd/emoji/ -Unicode 13.0.0 was updated from: -https://www.unicode.org/Public/13.0.0/ucd/ -https://www.unicode.org/Public/13.0.0/ucd/auxiliary/ -https://www.unicode.org/Public/13.0.0/ucd/emoji/ +When updating the Unicode version please follow these steps: -Update the spec_version(..) function in the generator, -gen_unicode_mod.escript +The latest vesrion of the Unicode Character Database can be found at +https://www.unicode.org/Public/UCD/latest/ucd/ + +1. Copy the following files to lib/stdlib/uc_spec/ replacing existing ones. +No subfolder should be created. + - CaseFolding.txt + - CompositionExclusions.txt + - PropList.txt + - SpecialCasing.txt + - UnicodeData.txt + - auxiliary/GraphemeBreakProperty.txt + - emoji/emoji-data.txt + - EastAsianWidth.txt + +2. Copy the following test files to lib/stdlib/test/unicode_util_SUITE_data/ +replacing existing ones. No subfolder should be created. + - NormalizationTest.txt + - auxiliary/GraphemeBreakTest.txt + - auxiliary/LineBreakTest.txt + +3. Update the "spec_version()" function in the generator by replacing the Unicode +version in lib/stdlib/uc_spec/gen_unicode_mod.escript + +4. Read the release notes by visiting https://www.unicode.org/versions/latest/ +and assess if additional changes are necessary in the Erlang code. + +5. Replace all ocurrences of previous version of Unicode with the new one in +this very same file (lib/stdlib/uc_spec/README-UPDATE.txt). +Remember to update these instructions if a new file is added or any other change +is required for future version updates. + +6. Check if the test file needs to be updated: + (cd $ERL_TOP/lib/stdlib/uc_spec; escript gen_unicode_mod.escript update_tests) + If ../test/unicode_util_SUITE_data/unicode_table.bin is updated include it in + the commit. + +7. Run the test for the Unicode suite from the OTP repository root dir. + $ export ERL_TOP=$PWD + $ export PATH=$ERL_TOP/bin:$PATH + $ ./otp_build all -a && ./otp_build tests + $ cd release/tests/test_server + $ erl + erl> ts:install(). + erl> ts:run(stdlib, unicode_SUITE, [batch]). diff --git a/lib/stdlib/uc_spec/SpecialCasing.txt b/lib/stdlib/uc_spec/SpecialCasing.txt index 2a1a5a1d6b17..08d04fa94219 100644 --- a/lib/stdlib/uc_spec/SpecialCasing.txt +++ b/lib/stdlib/uc_spec/SpecialCasing.txt @@ -1,11 +1,11 @@ -# SpecialCasing-13.0.0.txt -# Date: 2019-09-08, 23:31:24 GMT -# © 2019 Unicode®, Inc. +# SpecialCasing-15.0.0.txt +# Date: 2022-02-02, 23:35:52 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Unicode Character Database -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see https://www.unicode.org/reports/tr44/ # # Special Casing # diff --git a/lib/stdlib/uc_spec/UnicodeData.txt b/lib/stdlib/uc_spec/UnicodeData.txt index e22f967bbab8..ea963a7162ce 100644 --- a/lib/stdlib/uc_spec/UnicodeData.txt +++ b/lib/stdlib/uc_spec/UnicodeData.txt @@ -1525,6 +1525,7 @@ 061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;; 061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; 061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;; +061D;ARABIC END OF TEXT MARK;Po;0;AL;;;;;N;;;;; 061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; 061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; 0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;; @@ -2089,6 +2090,47 @@ 0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;; 0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;; 086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;; +0870;ARABIC LETTER ALEF WITH ATTACHED FATHA;Lo;0;AL;;;;;N;;;;; +0871;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA;Lo;0;AL;;;;;N;;;;; +0872;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; +0873;ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE;Lo;0;AL;;;;;N;;;;; +0874;ARABIC LETTER ALEF WITH ATTACHED KASRA;Lo;0;AL;;;;;N;;;;; +0875;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA;Lo;0;AL;;;;;N;;;;; +0876;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +0877;ARABIC LETTER ALEF WITH ATTACHED RIGHT ROUND DOT;Lo;0;AL;;;;;N;;;;; +0878;ARABIC LETTER ALEF WITH ATTACHED LEFT ROUND DOT;Lo;0;AL;;;;;N;;;;; +0879;ARABIC LETTER ALEF WITH ATTACHED ROUND DOT BELOW;Lo;0;AL;;;;;N;;;;; +087A;ARABIC LETTER ALEF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087B;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087C;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087D;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +087E;ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA AND LEFT RING;Lo;0;AL;;;;;N;;;;; +087F;ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE AND LEFT RING;Lo;0;AL;;;;;N;;;;; +0880;ARABIC LETTER ALEF WITH ATTACHED BOTTOM RIGHT KASRA AND LEFT RING;Lo;0;AL;;;;;N;;;;; +0881;ARABIC LETTER ALEF WITH ATTACHED RIGHT HAMZA;Lo;0;AL;;;;;N;;;;; +0882;ARABIC LETTER ALEF WITH ATTACHED LEFT HAMZA;Lo;0;AL;;;;;N;;;;; +0883;ARABIC TATWEEL WITH OVERSTRUCK HAMZA;Lo;0;AL;;;;;N;;;;; +0884;ARABIC TATWEEL WITH OVERSTRUCK WAW;Lo;0;AL;;;;;N;;;;; +0885;ARABIC TATWEEL WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +0886;ARABIC LETTER THIN YEH;Lo;0;AL;;;;;N;;;;; +0887;ARABIC BASELINE ROUND DOT;Lo;0;AL;;;;;N;;;;; +0888;ARABIC RAISED ROUND DOT;Sk;0;AL;;;;;N;;;;; +0889;ARABIC LETTER NOON WITH INVERTED SMALL V;Lo;0;AL;;;;;N;;;;; +088A;ARABIC LETTER HAH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;; +088B;ARABIC LETTER TAH WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;; +088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;; +0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;; +0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;; +0898;ARABIC SMALL HIGH WORD AL-JUZ;Mn;230;NSM;;;;;N;;;;; +0899;ARABIC SMALL LOW WORD ISHMAAM;Mn;220;NSM;;;;;N;;;;; +089A;ARABIC SMALL LOW WORD IMAALA;Mn;220;NSM;;;;;N;;;;; +089B;ARABIC SMALL LOW WORD TASHEEL;Mn;220;NSM;;;;;N;;;;; +089C;ARABIC MADDA WAAJIB;Mn;230;NSM;;;;;N;;;;; +089D;ARABIC SUPERSCRIPT ALEF MOKHASSAS;Mn;230;NSM;;;;;N;;;;; +089E;ARABIC DOUBLED MADDA;Mn;230;NSM;;;;;N;;;;; +089F;ARABIC HALF MADDA OVER MADDA;Mn;230;NSM;;;;;N;;;;; 08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; 08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; 08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; @@ -2110,6 +2152,7 @@ 08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; 08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08B5;ARABIC LETTER QAF WITH DOT BELOW AND NO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; 08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; 08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;; @@ -2128,6 +2171,17 @@ 08C5;ARABIC LETTER JEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; 08C6;ARABIC LETTER JEEM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 08C7;ARABIC LETTER LAM WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;; +08C8;ARABIC LETTER GRAF;Lo;0;AL;;;;;N;;;;; +08C9;ARABIC SMALL FARSI YEH;Lm;0;AL;;;;;N;;;;; +08CA;ARABIC SMALL HIGH FARSI YEH;Mn;230;NSM;;;;;N;;;;; +08CB;ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW;Mn;230;NSM;;;;;N;;;;; +08CC;ARABIC SMALL HIGH WORD SAH;Mn;230;NSM;;;;;N;;;;; +08CD;ARABIC SMALL HIGH ZAH;Mn;230;NSM;;;;;N;;;;; +08CE;ARABIC LARGE ROUND DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +08CF;ARABIC LARGE ROUND DOT BELOW;Mn;220;NSM;;;;;N;;;;; +08D0;ARABIC SUKUN BELOW;Mn;220;NSM;;;;;N;;;;; +08D1;ARABIC LARGE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; +08D2;ARABIC LARGE ROUND DOT INSIDE CIRCLE BELOW;Mn;220;NSM;;;;;N;;;;; 08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;; 08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; 08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; @@ -2786,6 +2840,7 @@ 0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; 0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; 0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; +0C3C;TELUGU SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; 0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; @@ -2806,6 +2861,7 @@ 0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;; 0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;; 0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;; +0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; 0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; 0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; @@ -2901,6 +2957,7 @@ 0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; 0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;; 0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; 0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; @@ -2918,6 +2975,7 @@ 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; 0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +0CF3;KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT;Mc;0;L;;;;;N;;;;; 0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; 0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; @@ -3282,6 +3340,7 @@ 0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; 0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; 0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; +0ECE;LAO YAMAKKAN;Mn;0;NSM;;;;;N;;;;; 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -5258,6 +5317,7 @@ 170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;; 170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;; 170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;; +170D;TAGALOG LETTER RA;Lo;0;L;;;;;N;;;;; 170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;; 170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;; 1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;; @@ -5265,6 +5325,8 @@ 1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; 1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1715;TAGALOG SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; +171F;TAGALOG LETTER ARCHAIC RA;Lo;0;L;;;;;N;;;;; 1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;; 1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;; 1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;; @@ -5285,7 +5347,7 @@ 1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;; 1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; 1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; -1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;; +1734;HANUNOO SIGN PAMUDPOD;Mc;9;L;;;;;N;;;;; 1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; 1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;; 1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;; @@ -5455,6 +5517,7 @@ 180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; 180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; 180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; +180F;MONGOLIAN FREE VARIATION SELECTOR FOUR;Mn;0;NSM;;;;;N;;;;; 1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -6059,6 +6122,20 @@ 1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;; 1ABF;COMBINING LATIN SMALL LETTER W BELOW;Mn;220;NSM;;;;;N;;;;; 1AC0;COMBINING LATIN SMALL LETTER TURNED W BELOW;Mn;220;NSM;;;;;N;;;;; +1AC1;COMBINING LEFT PARENTHESIS ABOVE LEFT;Mn;230;NSM;;;;;N;;;;; +1AC2;COMBINING RIGHT PARENTHESIS ABOVE RIGHT;Mn;230;NSM;;;;;N;;;;; +1AC3;COMBINING LEFT PARENTHESIS BELOW LEFT;Mn;220;NSM;;;;;N;;;;; +1AC4;COMBINING RIGHT PARENTHESIS BELOW RIGHT;Mn;220;NSM;;;;;N;;;;; +1AC5;COMBINING SQUARE BRACKETS ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC6;COMBINING NUMBER SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC7;COMBINING INVERTED DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC8;COMBINING PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1AC9;COMBINING DOUBLE PLUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;; +1ACA;COMBINING DOUBLE PLUS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; +1ACB;COMBINING TRIPLE ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;; +1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;; +1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;; 1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;; 1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;; 1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;; @@ -6135,6 +6212,7 @@ 1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;; 1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;; 1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;; +1B4C;BALINESE LETTER ARCHAIC JNYA;Lo;0;L;;;;;N;;;;; 1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -6180,6 +6258,8 @@ 1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;; 1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;; 1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;; +1B7D;BALINESE PANTI LANTANG;Po;0;L;;;;;N;;;;; +1B7E;BALINESE PAMADA LANTANG;Po;0;L;;;;;N;;;;; 1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;; 1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;; 1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;; @@ -6778,6 +6858,7 @@ 1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; 1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; 1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;; +1DFA;COMBINING DOT BELOW LEFT;Mn;218;NSM;;;;;N;;;;; 1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;; 1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; @@ -7457,6 +7538,7 @@ 20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;; 20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; 20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;; +20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -10300,6 +10382,7 @@ 2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C; 2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D; 2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E; +2C2F;GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI;Lu;0;L;;;;;N;;;;2C5F; 2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00 2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01 2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02 @@ -10347,6 +10430,7 @@ 2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C 2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D 2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E +2C5F;GLAGOLITIC SMALL LETTER CAUDATE CHRIVI;Ll;0;L;;;;;N;;;2C2F;;2C2F 2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61; 2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60 2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B; @@ -10795,6 +10879,17 @@ 2E50;CROSS PATTY WITH RIGHT CROSSBAR;So;0;ON;;;;;N;;;;; 2E51;CROSS PATTY WITH LEFT CROSSBAR;So;0;ON;;;;;N;;;;; 2E52;TIRONIAN SIGN CAPITAL ET;Po;0;ON;;;;;N;;;;; +2E53;MEDIEVAL EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +2E54;MEDIEVAL QUESTION MARK;Po;0;ON;;;;;N;;;;; +2E55;LEFT SQUARE BRACKET WITH STROKE;Ps;0;ON;;;;;Y;;;;; +2E56;RIGHT SQUARE BRACKET WITH STROKE;Pe;0;ON;;;;;Y;;;;; +2E57;LEFT SQUARE BRACKET WITH DOUBLE STROKE;Ps;0;ON;;;;;Y;;;;; +2E58;RIGHT SQUARE BRACKET WITH DOUBLE STROKE;Pe;0;ON;;;;;Y;;;;; +2E59;TOP HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E5A;TOP HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E5B;BOTTOM HALF LEFT PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2E5C;BOTTOM HALF RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2E5D;OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -12204,7 +12299,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;;Lo;0;L;;;;;N;;;;; -9FFC;;Lo;0;L;;;;;N;;;;; +9FFF;;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -14149,6 +14244,8 @@ A7BC;LATIN CAPITAL LETTER GLOTTAL I;Lu;0;L;;;;;N;;;;A7BD; A7BD;LATIN SMALL LETTER GLOTTAL I;Ll;0;L;;;;;N;;;A7BC;;A7BC A7BE;LATIN CAPITAL LETTER GLOTTAL U;Lu;0;L;;;;;N;;;;A7BF; A7BF;LATIN SMALL LETTER GLOTTAL U;Ll;0;L;;;;;N;;;A7BE;;A7BE +A7C0;LATIN CAPITAL LETTER OLD POLISH O;Lu;0;L;;;;;N;;;;A7C1; +A7C1;LATIN SMALL LETTER OLD POLISH O;Ll;0;L;;;;;N;;;A7C0;;A7C0 A7C2;LATIN CAPITAL LETTER ANGLICANA W;Lu;0;L;;;;;N;;;;A7C3; A7C3;LATIN SMALL LETTER ANGLICANA W;Ll;0;L;;;;;N;;;A7C2;;A7C2 A7C4;LATIN CAPITAL LETTER C WITH PALATAL HOOK;Lu;0;L;;;;;N;;;;A794; @@ -14158,6 +14255,17 @@ A7C7;LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7C8; A7C8;LATIN SMALL LETTER D WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C7;;A7C7 A7C9;LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY;Lu;0;L;;;;;N;;;;A7CA; A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9 +A7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1; +A7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0 +A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;;; +A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;;; +A7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7; +A7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6 +A7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9; +A7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8 +A7F2;MODIFIER LETTER CAPITAL C;Lm;0;L; 0043;;;;N;;;;; +A7F3;MODIFIER LETTER CAPITAL F;Lm;0;L; 0046;;;;N;;;;; +A7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L; 0051;;;;N;;;;; A7F5;LATIN CAPITAL LETTER REVERSED HALF H;Lu;0;L;;;;;N;;;;A7F6; A7F6;LATIN SMALL LETTER REVERSED HALF H;Ll;0;L;;;;;N;;;A7F5;;A7F5 A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;; @@ -15794,6 +15902,7 @@ FBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;; FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;; FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;; FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;; +FBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;; FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; @@ -16159,6 +16268,22 @@ FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL; 0627 064B;;;; FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL; 0627 064B;;;;N;;;;; FD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;; FD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;; +FD40;ARABIC LIGATURE RAHIMAHU ALLAAH;So;0;ON;;;;;N;;;;; +FD41;ARABIC LIGATURE RADI ALLAAHU ANH;So;0;ON;;;;;N;;;;; +FD42;ARABIC LIGATURE RADI ALLAAHU ANHAA;So;0;ON;;;;;N;;;;; +FD43;ARABIC LIGATURE RADI ALLAAHU ANHUM;So;0;ON;;;;;N;;;;; +FD44;ARABIC LIGATURE RADI ALLAAHU ANHUMAA;So;0;ON;;;;;N;;;;; +FD45;ARABIC LIGATURE RADI ALLAAHU ANHUNNA;So;0;ON;;;;;N;;;;; +FD46;ARABIC LIGATURE SALLALLAAHU ALAYHI WA-AALIH;So;0;ON;;;;;N;;;;; +FD47;ARABIC LIGATURE ALAYHI AS-SALAAM;So;0;ON;;;;;N;;;;; +FD48;ARABIC LIGATURE ALAYHIM AS-SALAAM;So;0;ON;;;;;N;;;;; +FD49;ARABIC LIGATURE ALAYHIMAA AS-SALAAM;So;0;ON;;;;;N;;;;; +FD4A;ARABIC LIGATURE ALAYHI AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;; +FD4B;ARABIC LIGATURE QUDDISA SIRRAH;So;0;ON;;;;;N;;;;; +FD4C;ARABIC LIGATURE SALLALLAHU ALAYHI WAAALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;; +FD4D;ARABIC LIGATURE ALAYHAA AS-SALAAM;So;0;ON;;;;;N;;;;; +FD4E;ARABIC LIGATURE TABAARAKA WA-TAAALAA;So;0;ON;;;;;N;;;;; +FD4F;ARABIC LIGATURE RAHIMAHUM ALLAAH;So;0;ON;;;;;N;;;;; FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062C 0645;;;;N;;;;; FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; @@ -16277,6 +16402,7 @@ FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;; FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;; +FDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;; FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;; FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;; FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL; 0627 0644 0644 0647;;;;N;;;;; @@ -16291,6 +16417,8 @@ FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL; 0635 0644 06 FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL; 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; FDFC;RIAL SIGN;Sc;0;AL; 0631 06CC 0627 0644;;;;N;;;;; FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;; +FDFE;ARABIC LIGATURE SUBHAANAHU WA TAAALAA;So;0;ON;;;;;N;;;;; +FDFF;ARABIC LIGATURE AZZA WA JALL;So;0;ON;;;;;N;;;;; FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;; FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;; FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;; @@ -17798,6 +17926,76 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;; 10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;; 1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;; +10570;VITHKUQI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;10597; +10571;VITHKUQI CAPITAL LETTER BBE;Lu;0;L;;;;;N;;;;10598; +10572;VITHKUQI CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;10599; +10573;VITHKUQI CAPITAL LETTER CE;Lu;0;L;;;;;N;;;;1059A; +10574;VITHKUQI CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;1059B; +10575;VITHKUQI CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;1059C; +10576;VITHKUQI CAPITAL LETTER DHE;Lu;0;L;;;;;N;;;;1059D; +10577;VITHKUQI CAPITAL LETTER EI;Lu;0;L;;;;;N;;;;1059E; +10578;VITHKUQI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;1059F; +10579;VITHKUQI CAPITAL LETTER FE;Lu;0;L;;;;;N;;;;105A0; +1057A;VITHKUQI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;105A1; +1057C;VITHKUQI CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;105A3; +1057D;VITHKUQI CAPITAL LETTER HHA;Lu;0;L;;;;;N;;;;105A4; +1057E;VITHKUQI CAPITAL LETTER I;Lu;0;L;;;;;N;;;;105A5; +1057F;VITHKUQI CAPITAL LETTER IJE;Lu;0;L;;;;;N;;;;105A6; +10580;VITHKUQI CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;105A7; +10581;VITHKUQI CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;105A8; +10582;VITHKUQI CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;105A9; +10583;VITHKUQI CAPITAL LETTER LLA;Lu;0;L;;;;;N;;;;105AA; +10584;VITHKUQI CAPITAL LETTER ME;Lu;0;L;;;;;N;;;;105AB; +10585;VITHKUQI CAPITAL LETTER NE;Lu;0;L;;;;;N;;;;105AC; +10586;VITHKUQI CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;105AD; +10587;VITHKUQI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;105AE; +10588;VITHKUQI CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;105AF; +10589;VITHKUQI CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;105B0; +1058A;VITHKUQI CAPITAL LETTER RE;Lu;0;L;;;;;N;;;;105B1; +1058C;VITHKUQI CAPITAL LETTER SE;Lu;0;L;;;;;N;;;;105B3; +1058D;VITHKUQI CAPITAL LETTER SHE;Lu;0;L;;;;;N;;;;105B4; +1058E;VITHKUQI CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;105B5; +1058F;VITHKUQI CAPITAL LETTER THE;Lu;0;L;;;;;N;;;;105B6; +10590;VITHKUQI CAPITAL LETTER U;Lu;0;L;;;;;N;;;;105B7; +10591;VITHKUQI CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;105B8; +10592;VITHKUQI CAPITAL LETTER XE;Lu;0;L;;;;;N;;;;105B9; +10594;VITHKUQI CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;105BB; +10595;VITHKUQI CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;105BC; +10597;VITHKUQI SMALL LETTER A;Ll;0;L;;;;;N;;;10570;;10570 +10598;VITHKUQI SMALL LETTER BBE;Ll;0;L;;;;;N;;;10571;;10571 +10599;VITHKUQI SMALL LETTER BE;Ll;0;L;;;;;N;;;10572;;10572 +1059A;VITHKUQI SMALL LETTER CE;Ll;0;L;;;;;N;;;10573;;10573 +1059B;VITHKUQI SMALL LETTER CHE;Ll;0;L;;;;;N;;;10574;;10574 +1059C;VITHKUQI SMALL LETTER DE;Ll;0;L;;;;;N;;;10575;;10575 +1059D;VITHKUQI SMALL LETTER DHE;Ll;0;L;;;;;N;;;10576;;10576 +1059E;VITHKUQI SMALL LETTER EI;Ll;0;L;;;;;N;;;10577;;10577 +1059F;VITHKUQI SMALL LETTER E;Ll;0;L;;;;;N;;;10578;;10578 +105A0;VITHKUQI SMALL LETTER FE;Ll;0;L;;;;;N;;;10579;;10579 +105A1;VITHKUQI SMALL LETTER GA;Ll;0;L;;;;;N;;;1057A;;1057A +105A3;VITHKUQI SMALL LETTER HA;Ll;0;L;;;;;N;;;1057C;;1057C +105A4;VITHKUQI SMALL LETTER HHA;Ll;0;L;;;;;N;;;1057D;;1057D +105A5;VITHKUQI SMALL LETTER I;Ll;0;L;;;;;N;;;1057E;;1057E +105A6;VITHKUQI SMALL LETTER IJE;Ll;0;L;;;;;N;;;1057F;;1057F +105A7;VITHKUQI SMALL LETTER JE;Ll;0;L;;;;;N;;;10580;;10580 +105A8;VITHKUQI SMALL LETTER KA;Ll;0;L;;;;;N;;;10581;;10581 +105A9;VITHKUQI SMALL LETTER LA;Ll;0;L;;;;;N;;;10582;;10582 +105AA;VITHKUQI SMALL LETTER LLA;Ll;0;L;;;;;N;;;10583;;10583 +105AB;VITHKUQI SMALL LETTER ME;Ll;0;L;;;;;N;;;10584;;10584 +105AC;VITHKUQI SMALL LETTER NE;Ll;0;L;;;;;N;;;10585;;10585 +105AD;VITHKUQI SMALL LETTER NJE;Ll;0;L;;;;;N;;;10586;;10586 +105AE;VITHKUQI SMALL LETTER O;Ll;0;L;;;;;N;;;10587;;10587 +105AF;VITHKUQI SMALL LETTER PE;Ll;0;L;;;;;N;;;10588;;10588 +105B0;VITHKUQI SMALL LETTER QA;Ll;0;L;;;;;N;;;10589;;10589 +105B1;VITHKUQI SMALL LETTER RE;Ll;0;L;;;;;N;;;1058A;;1058A +105B3;VITHKUQI SMALL LETTER SE;Ll;0;L;;;;;N;;;1058C;;1058C +105B4;VITHKUQI SMALL LETTER SHE;Ll;0;L;;;;;N;;;1058D;;1058D +105B5;VITHKUQI SMALL LETTER TE;Ll;0;L;;;;;N;;;1058E;;1058E +105B6;VITHKUQI SMALL LETTER THE;Ll;0;L;;;;;N;;;1058F;;1058F +105B7;VITHKUQI SMALL LETTER U;Ll;0;L;;;;;N;;;10590;;10590 +105B8;VITHKUQI SMALL LETTER VE;Ll;0;L;;;;;N;;;10591;;10591 +105B9;VITHKUQI SMALL LETTER XE;Ll;0;L;;;;;N;;;10592;;10592 +105BB;VITHKUQI SMALL LETTER Y;Ll;0;L;;;;;N;;;10594;;10594 +105BC;VITHKUQI SMALL LETTER ZE;Ll;0;L;;;;;N;;;10595;;10595 10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;; 10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;; 10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;; @@ -18139,6 +18337,63 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;; 10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;; 10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;; +10780;MODIFIER LETTER SMALL CAPITAL AA;Lm;0;L;;;;;N;;;;; +10781;MODIFIER LETTER SUPERSCRIPT TRIANGULAR COLON;Lm;0;L; 02D0;;;;N;;;;; +10782;MODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLON;Lm;0;L; 02D1;;;;N;;;;; +10783;MODIFIER LETTER SMALL AE;Lm;0;L; 00E6;;;;N;;;;; +10784;MODIFIER LETTER SMALL CAPITAL B;Lm;0;L; 0299;;;;N;;;;; +10785;MODIFIER LETTER SMALL B WITH HOOK;Lm;0;L; 0253;;;;N;;;;; +10787;MODIFIER LETTER SMALL DZ DIGRAPH;Lm;0;L; 02A3;;;;N;;;;; +10788;MODIFIER LETTER SMALL DZ DIGRAPH WITH RETROFLEX HOOK;Lm;0;L; AB66;;;;N;;;;; +10789;MODIFIER LETTER SMALL DZ DIGRAPH WITH CURL;Lm;0;L; 02A5;;;;N;;;;; +1078A;MODIFIER LETTER SMALL DEZH DIGRAPH;Lm;0;L; 02A4;;;;N;;;;; +1078B;MODIFIER LETTER SMALL D WITH TAIL;Lm;0;L; 0256;;;;N;;;;; +1078C;MODIFIER LETTER SMALL D WITH HOOK;Lm;0;L; 0257;;;;N;;;;; +1078D;MODIFIER LETTER SMALL D WITH HOOK AND TAIL;Lm;0;L; 1D91;;;;N;;;;; +1078E;MODIFIER LETTER SMALL REVERSED E;Lm;0;L; 0258;;;;N;;;;; +1078F;MODIFIER LETTER SMALL CLOSED REVERSED OPEN E;Lm;0;L; 025E;;;;N;;;;; +10790;MODIFIER LETTER SMALL FENG DIGRAPH;Lm;0;L; 02A9;;;;N;;;;; +10791;MODIFIER LETTER SMALL RAMS HORN;Lm;0;L; 0264;;;;N;;;;; +10792;MODIFIER LETTER SMALL CAPITAL G;Lm;0;L; 0262;;;;N;;;;; +10793;MODIFIER LETTER SMALL G WITH HOOK;Lm;0;L; 0260;;;;N;;;;; +10794;MODIFIER LETTER SMALL CAPITAL G WITH HOOK;Lm;0;L; 029B;;;;N;;;;; +10795;MODIFIER LETTER SMALL H WITH STROKE;Lm;0;L; 0127;;;;N;;;;; +10796;MODIFIER LETTER SMALL CAPITAL H;Lm;0;L; 029C;;;;N;;;;; +10797;MODIFIER LETTER SMALL HENG WITH HOOK;Lm;0;L; 0267;;;;N;;;;; +10798;MODIFIER LETTER SMALL DOTLESS J WITH STROKE AND HOOK;Lm;0;L; 0284;;;;N;;;;; +10799;MODIFIER LETTER SMALL LS DIGRAPH;Lm;0;L; 02AA;;;;N;;;;; +1079A;MODIFIER LETTER SMALL LZ DIGRAPH;Lm;0;L; 02AB;;;;N;;;;; +1079B;MODIFIER LETTER SMALL L WITH BELT;Lm;0;L; 026C;;;;N;;;;; +1079C;MODIFIER LETTER SMALL CAPITAL L WITH BELT;Lm;0;L; 1DF04;;;;N;;;;; +1079D;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK AND BELT;Lm;0;L; A78E;;;;N;;;;; +1079E;MODIFIER LETTER SMALL LEZH;Lm;0;L; 026E;;;;N;;;;; +1079F;MODIFIER LETTER SMALL LEZH WITH RETROFLEX HOOK;Lm;0;L; 1DF05;;;;N;;;;; +107A0;MODIFIER LETTER SMALL TURNED Y;Lm;0;L; 028E;;;;N;;;;; +107A1;MODIFIER LETTER SMALL TURNED Y WITH BELT;Lm;0;L; 1DF06;;;;N;;;;; +107A2;MODIFIER LETTER SMALL O WITH STROKE;Lm;0;L; 00F8;;;;N;;;;; +107A3;MODIFIER LETTER SMALL CAPITAL OE;Lm;0;L; 0276;;;;N;;;;; +107A4;MODIFIER LETTER SMALL CLOSED OMEGA;Lm;0;L; 0277;;;;N;;;;; +107A5;MODIFIER LETTER SMALL Q;Lm;0;L; 0071;;;;N;;;;; +107A6;MODIFIER LETTER SMALL TURNED R WITH LONG LEG;Lm;0;L; 027A;;;;N;;;;; +107A7;MODIFIER LETTER SMALL TURNED R WITH LONG LEG AND RETROFLEX HOOK;Lm;0;L; 1DF08;;;;N;;;;; +107A8;MODIFIER LETTER SMALL R WITH TAIL;Lm;0;L; 027D;;;;N;;;;; +107A9;MODIFIER LETTER SMALL R WITH FISHHOOK;Lm;0;L; 027E;;;;N;;;;; +107AA;MODIFIER LETTER SMALL CAPITAL R;Lm;0;L; 0280;;;;N;;;;; +107AB;MODIFIER LETTER SMALL TC DIGRAPH WITH CURL;Lm;0;L; 02A8;;;;N;;;;; +107AC;MODIFIER LETTER SMALL TS DIGRAPH;Lm;0;L; 02A6;;;;N;;;;; +107AD;MODIFIER LETTER SMALL TS DIGRAPH WITH RETROFLEX HOOK;Lm;0;L; AB67;;;;N;;;;; +107AE;MODIFIER LETTER SMALL TESH DIGRAPH;Lm;0;L; 02A7;;;;N;;;;; +107AF;MODIFIER LETTER SMALL T WITH RETROFLEX HOOK;Lm;0;L; 0288;;;;N;;;;; +107B0;MODIFIER LETTER SMALL V WITH RIGHT HOOK;Lm;0;L; 2C71;;;;N;;;;; +107B2;MODIFIER LETTER SMALL CAPITAL Y;Lm;0;L; 028F;;;;N;;;;; +107B3;MODIFIER LETTER GLOTTAL STOP WITH STROKE;Lm;0;L; 02A1;;;;N;;;;; +107B4;MODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKE;Lm;0;L; 02A2;;;;N;;;;; +107B5;MODIFIER LETTER BILABIAL CLICK;Lm;0;L; 0298;;;;N;;;;; +107B6;MODIFIER LETTER DENTAL CLICK;Lm;0;L; 01C0;;;;N;;;;; +107B7;MODIFIER LETTER LATERAL CLICK;Lm;0;L; 01C1;;;;N;;;;; +107B8;MODIFIER LETTER ALVEOLAR CLICK;Lm;0;L; 01C2;;;;N;;;;; +107B9;MODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lm;0;L; 1DF0A;;;;N;;;;; +107BA;MODIFIER LETTER SMALL S WITH CURL;Lm;0;L; 1DF1E;;;;N;;;;; 10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;; 10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;; 10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;; @@ -19140,6 +19395,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10EAD;YEZIDI HYPHENATION MARK;Pd;0;R;;;;;N;;;;; 10EB0;YEZIDI LETTER LAM WITH DOT ABOVE;Lo;0;R;;;;;N;;;;; 10EB1;YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE;Lo;0;R;;;;;N;;;;; +10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;; +10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;; +10EFF;ARABIC SMALL LOW WORD MADDA;Mn;220;NSM;;;;;N;;;;; 10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; 10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;; 10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;; @@ -19222,6 +19480,32 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; 10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;; 10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;; +10F70;OLD UYGHUR LETTER ALEPH;Lo;0;R;;;;;N;;;;; +10F71;OLD UYGHUR LETTER BETH;Lo;0;R;;;;;N;;;;; +10F72;OLD UYGHUR LETTER GIMEL-HETH;Lo;0;R;;;;;N;;;;; +10F73;OLD UYGHUR LETTER WAW;Lo;0;R;;;;;N;;;;; +10F74;OLD UYGHUR LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +10F75;OLD UYGHUR LETTER FINAL HETH;Lo;0;R;;;;;N;;;;; +10F76;OLD UYGHUR LETTER YODH;Lo;0;R;;;;;N;;;;; +10F77;OLD UYGHUR LETTER KAPH;Lo;0;R;;;;;N;;;;; +10F78;OLD UYGHUR LETTER LAMEDH;Lo;0;R;;;;;N;;;;; +10F79;OLD UYGHUR LETTER MEM;Lo;0;R;;;;;N;;;;; +10F7A;OLD UYGHUR LETTER NUN;Lo;0;R;;;;;N;;;;; +10F7B;OLD UYGHUR LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +10F7C;OLD UYGHUR LETTER PE;Lo;0;R;;;;;N;;;;; +10F7D;OLD UYGHUR LETTER SADHE;Lo;0;R;;;;;N;;;;; +10F7E;OLD UYGHUR LETTER RESH;Lo;0;R;;;;;N;;;;; +10F7F;OLD UYGHUR LETTER SHIN;Lo;0;R;;;;;N;;;;; +10F80;OLD UYGHUR LETTER TAW;Lo;0;R;;;;;N;;;;; +10F81;OLD UYGHUR LETTER LESH;Lo;0;R;;;;;N;;;;; +10F82;OLD UYGHUR COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;; +10F83;OLD UYGHUR COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;; +10F84;OLD UYGHUR COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +10F85;OLD UYGHUR COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +10F86;OLD UYGHUR PUNCTUATION BAR;Po;0;R;;;;;N;;;;; +10F87;OLD UYGHUR PUNCTUATION TWO BARS;Po;0;R;;;;;N;;;;; +10F88;OLD UYGHUR PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;; +10F89;OLD UYGHUR PUNCTUATION FOUR DOTS;Po;0;R;;;;;N;;;;; 10FB0;CHORASMIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;; 10FB1;CHORASMIAN LETTER SMALL ALEPH;Lo;0;R;;;;;N;;;;; 10FB2;CHORASMIAN LETTER BETH;Lo;0;R;;;;;N;;;;; @@ -19381,6 +19665,12 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11070;BRAHMI SIGN OLD TAMIL VIRAMA;Mn;9;NSM;;;;;N;;;;; +11071;BRAHMI LETTER OLD TAMIL SHORT E;Lo;0;L;;;;;N;;;;; +11072;BRAHMI LETTER OLD TAMIL SHORT O;Lo;0;L;;;;;N;;;;; +11073;BRAHMI VOWEL SIGN OLD TAMIL SHORT E;Mn;0;NSM;;;;;N;;;;; +11074;BRAHMI VOWEL SIGN OLD TAMIL SHORT O;Mn;0;NSM;;;;;N;;;;; +11075;BRAHMI LETTER OLD TAMIL LLA;Lo;0;L;;;;;N;;;;; 1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;; 11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; @@ -19448,6 +19738,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;; 110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +110C2;KAITHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;; 110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;; 110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;; @@ -19772,6 +20063,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; +1123F;KHOJKI LETTER QA;Lo;0;L;;;;;N;;;;; +11240;KHOJKI LETTER SHORT I;Lo;0;L;;;;;N;;;;; +11241;KHOJKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; 11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; 11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; 11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; @@ -20385,6 +20679,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;; 116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 116B8;TAKRI LETTER ARCHAIC KHA;Lo;0;L;;;;;N;;;;; +116B9;TAKRI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; 116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; 116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; @@ -20453,6 +20748,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;; 1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;; 1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;; +11740;AHOM LETTER CA;Lo;0;L;;;;;N;;;;; +11741;AHOM LETTER TTA;Lo;0;L;;;;;N;;;;; +11742;AHOM LETTER TTHA;Lo;0;L;;;;;N;;;;; +11743;AHOM LETTER DDA;Lo;0;L;;;;;N;;;;; +11744;AHOM LETTER DDHA;Lo;0;L;;;;;N;;;;; +11745;AHOM LETTER NNA;Lo;0;L;;;;;N;;;;; +11746;AHOM LETTER LLA;Lo;0;L;;;;;N;;;;; 11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;; 11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;; 11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;; @@ -20889,6 +21191,22 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;; 11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;; 11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;; +11AB0;CANADIAN SYLLABICS NATTILIK HI;Lo;0;L;;;;;N;;;;; +11AB1;CANADIAN SYLLABICS NATTILIK HII;Lo;0;L;;;;;N;;;;; +11AB2;CANADIAN SYLLABICS NATTILIK HO;Lo;0;L;;;;;N;;;;; +11AB3;CANADIAN SYLLABICS NATTILIK HOO;Lo;0;L;;;;;N;;;;; +11AB4;CANADIAN SYLLABICS NATTILIK HA;Lo;0;L;;;;;N;;;;; +11AB5;CANADIAN SYLLABICS NATTILIK HAA;Lo;0;L;;;;;N;;;;; +11AB6;CANADIAN SYLLABICS NATTILIK SHRI;Lo;0;L;;;;;N;;;;; +11AB7;CANADIAN SYLLABICS NATTILIK SHRII;Lo;0;L;;;;;N;;;;; +11AB8;CANADIAN SYLLABICS NATTILIK SHRO;Lo;0;L;;;;;N;;;;; +11AB9;CANADIAN SYLLABICS NATTILIK SHROO;Lo;0;L;;;;;N;;;;; +11ABA;CANADIAN SYLLABICS NATTILIK SHRA;Lo;0;L;;;;;N;;;;; +11ABB;CANADIAN SYLLABICS NATTILIK SHRAA;Lo;0;L;;;;;N;;;;; +11ABC;CANADIAN SYLLABICS SPE;Lo;0;L;;;;;N;;;;; +11ABD;CANADIAN SYLLABICS SPI;Lo;0;L;;;;;N;;;;; +11ABE;CANADIAN SYLLABICS SPO;Lo;0;L;;;;;N;;;;; +11ABF;CANADIAN SYLLABICS SPA;Lo;0;L;;;;;N;;;;; 11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;; 11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;; 11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;; @@ -20946,6 +21264,16 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; 11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; 11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11B00;DEVANAGARI HEAD MARK;Po;0;L;;;;;N;;;;; +11B01;DEVANAGARI HEAD MARK WITH HEADSTROKE;Po;0;L;;;;;N;;;;; +11B02;DEVANAGARI SIGN BHALE;Po;0;L;;;;;N;;;;; +11B03;DEVANAGARI SIGN BHALE WITH HOOK;Po;0;L;;;;;N;;;;; +11B04;DEVANAGARI SIGN EXTENDED BHALE;Po;0;L;;;;;N;;;;; +11B05;DEVANAGARI SIGN EXTENDED BHALE WITH HOOK;Po;0;L;;;;;N;;;;; +11B06;DEVANAGARI SIGN WESTERN FIVE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;; +11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;; 11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;; 11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;; 11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;; @@ -21274,6 +21602,92 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;; 11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;; 11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;; +11F00;KAWI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11F01;KAWI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11F02;KAWI SIGN REPHA;Lo;0;L;;;;;N;;;;; +11F03;KAWI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11F04;KAWI LETTER A;Lo;0;L;;;;;N;;;;; +11F05;KAWI LETTER AA;Lo;0;L;;;;;N;;;;; +11F06;KAWI LETTER I;Lo;0;L;;;;;N;;;;; +11F07;KAWI LETTER II;Lo;0;L;;;;;N;;;;; +11F08;KAWI LETTER U;Lo;0;L;;;;;N;;;;; +11F09;KAWI LETTER UU;Lo;0;L;;;;;N;;;;; +11F0A;KAWI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11F0B;KAWI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11F0C;KAWI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11F0D;KAWI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +11F0E;KAWI LETTER E;Lo;0;L;;;;;N;;;;; +11F0F;KAWI LETTER AI;Lo;0;L;;;;;N;;;;; +11F10;KAWI LETTER O;Lo;0;L;;;;;N;;;;; +11F12;KAWI LETTER KA;Lo;0;L;;;;;N;;;;; +11F13;KAWI LETTER KHA;Lo;0;L;;;;;N;;;;; +11F14;KAWI LETTER GA;Lo;0;L;;;;;N;;;;; +11F15;KAWI LETTER GHA;Lo;0;L;;;;;N;;;;; +11F16;KAWI LETTER NGA;Lo;0;L;;;;;N;;;;; +11F17;KAWI LETTER CA;Lo;0;L;;;;;N;;;;; +11F18;KAWI LETTER CHA;Lo;0;L;;;;;N;;;;; +11F19;KAWI LETTER JA;Lo;0;L;;;;;N;;;;; +11F1A;KAWI LETTER JHA;Lo;0;L;;;;;N;;;;; +11F1B;KAWI LETTER NYA;Lo;0;L;;;;;N;;;;; +11F1C;KAWI LETTER TTA;Lo;0;L;;;;;N;;;;; +11F1D;KAWI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11F1E;KAWI LETTER DDA;Lo;0;L;;;;;N;;;;; +11F1F;KAWI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11F20;KAWI LETTER NNA;Lo;0;L;;;;;N;;;;; +11F21;KAWI LETTER TA;Lo;0;L;;;;;N;;;;; +11F22;KAWI LETTER THA;Lo;0;L;;;;;N;;;;; +11F23;KAWI LETTER DA;Lo;0;L;;;;;N;;;;; +11F24;KAWI LETTER DHA;Lo;0;L;;;;;N;;;;; +11F25;KAWI LETTER NA;Lo;0;L;;;;;N;;;;; +11F26;KAWI LETTER PA;Lo;0;L;;;;;N;;;;; +11F27;KAWI LETTER PHA;Lo;0;L;;;;;N;;;;; +11F28;KAWI LETTER BA;Lo;0;L;;;;;N;;;;; +11F29;KAWI LETTER BHA;Lo;0;L;;;;;N;;;;; +11F2A;KAWI LETTER MA;Lo;0;L;;;;;N;;;;; +11F2B;KAWI LETTER YA;Lo;0;L;;;;;N;;;;; +11F2C;KAWI LETTER RA;Lo;0;L;;;;;N;;;;; +11F2D;KAWI LETTER LA;Lo;0;L;;;;;N;;;;; +11F2E;KAWI LETTER WA;Lo;0;L;;;;;N;;;;; +11F2F;KAWI LETTER SHA;Lo;0;L;;;;;N;;;;; +11F30;KAWI LETTER SSA;Lo;0;L;;;;;N;;;;; +11F31;KAWI LETTER SA;Lo;0;L;;;;;N;;;;; +11F32;KAWI LETTER HA;Lo;0;L;;;;;N;;;;; +11F33;KAWI LETTER JNYA;Lo;0;L;;;;;N;;;;; +11F34;KAWI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11F35;KAWI VOWEL SIGN ALTERNATE AA;Mc;0;L;;;;;N;;;;; +11F36;KAWI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11F37;KAWI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11F38;KAWI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11F39;KAWI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11F3A;KAWI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11F3E;KAWI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +11F3F;KAWI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11F40;KAWI VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;; +11F41;KAWI SIGN KILLER;Mc;9;L;;;;;N;;;;; +11F42;KAWI CONJOINER;Mn;9;NSM;;;;;N;;;;; +11F43;KAWI DANDA;Po;0;L;;;;;N;;;;; +11F44;KAWI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11F45;KAWI PUNCTUATION SECTION MARKER;Po;0;L;;;;;N;;;;; +11F46;KAWI PUNCTUATION ALTERNATE SECTION MARKER;Po;0;L;;;;;N;;;;; +11F47;KAWI PUNCTUATION FLOWER;Po;0;L;;;;;N;;;;; +11F48;KAWI PUNCTUATION SPACE FILLER;Po;0;L;;;;;N;;;;; +11F49;KAWI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; +11F4A;KAWI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; +11F4B;KAWI PUNCTUATION TRIPLE DOT;Po;0;L;;;;;N;;;;; +11F4C;KAWI PUNCTUATION CIRCLE;Po;0;L;;;;;N;;;;; +11F4D;KAWI PUNCTUATION FILLED CIRCLE;Po;0;L;;;;;N;;;;; +11F4E;KAWI PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;; +11F4F;KAWI PUNCTUATION CLOSING SPIRAL;Po;0;L;;;;;N;;;;; +11F50;KAWI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11F51;KAWI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11F52;KAWI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11F53;KAWI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11F54;KAWI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11F55;KAWI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11F56;KAWI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11F57;KAWI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11F58;KAWI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11F59;KAWI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 11FB0;LISU LETTER YHA;Lo;0;L;;;;;N;;;;; 11FC0;TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH;No;0;L;;;;1/320;N;;;;; 11FC1;TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; @@ -22560,6 +22974,105 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;; 12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;; 12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;; +12F90;CYPRO-MINOAN SIGN CM001;Lo;0;L;;;;;N;;;;; +12F91;CYPRO-MINOAN SIGN CM002;Lo;0;L;;;;;N;;;;; +12F92;CYPRO-MINOAN SIGN CM004;Lo;0;L;;;;;N;;;;; +12F93;CYPRO-MINOAN SIGN CM005;Lo;0;L;;;;;N;;;;; +12F94;CYPRO-MINOAN SIGN CM006;Lo;0;L;;;;;N;;;;; +12F95;CYPRO-MINOAN SIGN CM007;Lo;0;L;;;;;N;;;;; +12F96;CYPRO-MINOAN SIGN CM008;Lo;0;L;;;;;N;;;;; +12F97;CYPRO-MINOAN SIGN CM009;Lo;0;L;;;;;N;;;;; +12F98;CYPRO-MINOAN SIGN CM010;Lo;0;L;;;;;N;;;;; +12F99;CYPRO-MINOAN SIGN CM011;Lo;0;L;;;;;N;;;;; +12F9A;CYPRO-MINOAN SIGN CM012;Lo;0;L;;;;;N;;;;; +12F9B;CYPRO-MINOAN SIGN CM012B;Lo;0;L;;;;;N;;;;; +12F9C;CYPRO-MINOAN SIGN CM013;Lo;0;L;;;;;N;;;;; +12F9D;CYPRO-MINOAN SIGN CM015;Lo;0;L;;;;;N;;;;; +12F9E;CYPRO-MINOAN SIGN CM017;Lo;0;L;;;;;N;;;;; +12F9F;CYPRO-MINOAN SIGN CM019;Lo;0;L;;;;;N;;;;; +12FA0;CYPRO-MINOAN SIGN CM021;Lo;0;L;;;;;N;;;;; +12FA1;CYPRO-MINOAN SIGN CM023;Lo;0;L;;;;;N;;;;; +12FA2;CYPRO-MINOAN SIGN CM024;Lo;0;L;;;;;N;;;;; +12FA3;CYPRO-MINOAN SIGN CM025;Lo;0;L;;;;;N;;;;; +12FA4;CYPRO-MINOAN SIGN CM026;Lo;0;L;;;;;N;;;;; +12FA5;CYPRO-MINOAN SIGN CM027;Lo;0;L;;;;;N;;;;; +12FA6;CYPRO-MINOAN SIGN CM028;Lo;0;L;;;;;N;;;;; +12FA7;CYPRO-MINOAN SIGN CM029;Lo;0;L;;;;;N;;;;; +12FA8;CYPRO-MINOAN SIGN CM030;Lo;0;L;;;;;N;;;;; +12FA9;CYPRO-MINOAN SIGN CM033;Lo;0;L;;;;;N;;;;; +12FAA;CYPRO-MINOAN SIGN CM034;Lo;0;L;;;;;N;;;;; +12FAB;CYPRO-MINOAN SIGN CM035;Lo;0;L;;;;;N;;;;; +12FAC;CYPRO-MINOAN SIGN CM036;Lo;0;L;;;;;N;;;;; +12FAD;CYPRO-MINOAN SIGN CM037;Lo;0;L;;;;;N;;;;; +12FAE;CYPRO-MINOAN SIGN CM038;Lo;0;L;;;;;N;;;;; +12FAF;CYPRO-MINOAN SIGN CM039;Lo;0;L;;;;;N;;;;; +12FB0;CYPRO-MINOAN SIGN CM040;Lo;0;L;;;;;N;;;;; +12FB1;CYPRO-MINOAN SIGN CM041;Lo;0;L;;;;;N;;;;; +12FB2;CYPRO-MINOAN SIGN CM044;Lo;0;L;;;;;N;;;;; +12FB3;CYPRO-MINOAN SIGN CM046;Lo;0;L;;;;;N;;;;; +12FB4;CYPRO-MINOAN SIGN CM047;Lo;0;L;;;;;N;;;;; +12FB5;CYPRO-MINOAN SIGN CM049;Lo;0;L;;;;;N;;;;; +12FB6;CYPRO-MINOAN SIGN CM050;Lo;0;L;;;;;N;;;;; +12FB7;CYPRO-MINOAN SIGN CM051;Lo;0;L;;;;;N;;;;; +12FB8;CYPRO-MINOAN SIGN CM052;Lo;0;L;;;;;N;;;;; +12FB9;CYPRO-MINOAN SIGN CM053;Lo;0;L;;;;;N;;;;; +12FBA;CYPRO-MINOAN SIGN CM054;Lo;0;L;;;;;N;;;;; +12FBB;CYPRO-MINOAN SIGN CM055;Lo;0;L;;;;;N;;;;; +12FBC;CYPRO-MINOAN SIGN CM056;Lo;0;L;;;;;N;;;;; +12FBD;CYPRO-MINOAN SIGN CM058;Lo;0;L;;;;;N;;;;; +12FBE;CYPRO-MINOAN SIGN CM059;Lo;0;L;;;;;N;;;;; +12FBF;CYPRO-MINOAN SIGN CM060;Lo;0;L;;;;;N;;;;; +12FC0;CYPRO-MINOAN SIGN CM061;Lo;0;L;;;;;N;;;;; +12FC1;CYPRO-MINOAN SIGN CM062;Lo;0;L;;;;;N;;;;; +12FC2;CYPRO-MINOAN SIGN CM063;Lo;0;L;;;;;N;;;;; +12FC3;CYPRO-MINOAN SIGN CM064;Lo;0;L;;;;;N;;;;; +12FC4;CYPRO-MINOAN SIGN CM066;Lo;0;L;;;;;N;;;;; +12FC5;CYPRO-MINOAN SIGN CM067;Lo;0;L;;;;;N;;;;; +12FC6;CYPRO-MINOAN SIGN CM068;Lo;0;L;;;;;N;;;;; +12FC7;CYPRO-MINOAN SIGN CM069;Lo;0;L;;;;;N;;;;; +12FC8;CYPRO-MINOAN SIGN CM070;Lo;0;L;;;;;N;;;;; +12FC9;CYPRO-MINOAN SIGN CM071;Lo;0;L;;;;;N;;;;; +12FCA;CYPRO-MINOAN SIGN CM072;Lo;0;L;;;;;N;;;;; +12FCB;CYPRO-MINOAN SIGN CM073;Lo;0;L;;;;;N;;;;; +12FCC;CYPRO-MINOAN SIGN CM074;Lo;0;L;;;;;N;;;;; +12FCD;CYPRO-MINOAN SIGN CM075;Lo;0;L;;;;;N;;;;; +12FCE;CYPRO-MINOAN SIGN CM075B;Lo;0;L;;;;;N;;;;; +12FCF;CYPRO-MINOAN SIGN CM076;Lo;0;L;;;;;N;;;;; +12FD0;CYPRO-MINOAN SIGN CM078;Lo;0;L;;;;;N;;;;; +12FD1;CYPRO-MINOAN SIGN CM079;Lo;0;L;;;;;N;;;;; +12FD2;CYPRO-MINOAN SIGN CM080;Lo;0;L;;;;;N;;;;; +12FD3;CYPRO-MINOAN SIGN CM081;Lo;0;L;;;;;N;;;;; +12FD4;CYPRO-MINOAN SIGN CM082;Lo;0;L;;;;;N;;;;; +12FD5;CYPRO-MINOAN SIGN CM083;Lo;0;L;;;;;N;;;;; +12FD6;CYPRO-MINOAN SIGN CM084;Lo;0;L;;;;;N;;;;; +12FD7;CYPRO-MINOAN SIGN CM085;Lo;0;L;;;;;N;;;;; +12FD8;CYPRO-MINOAN SIGN CM086;Lo;0;L;;;;;N;;;;; +12FD9;CYPRO-MINOAN SIGN CM087;Lo;0;L;;;;;N;;;;; +12FDA;CYPRO-MINOAN SIGN CM088;Lo;0;L;;;;;N;;;;; +12FDB;CYPRO-MINOAN SIGN CM089;Lo;0;L;;;;;N;;;;; +12FDC;CYPRO-MINOAN SIGN CM090;Lo;0;L;;;;;N;;;;; +12FDD;CYPRO-MINOAN SIGN CM091;Lo;0;L;;;;;N;;;;; +12FDE;CYPRO-MINOAN SIGN CM092;Lo;0;L;;;;;N;;;;; +12FDF;CYPRO-MINOAN SIGN CM094;Lo;0;L;;;;;N;;;;; +12FE0;CYPRO-MINOAN SIGN CM095;Lo;0;L;;;;;N;;;;; +12FE1;CYPRO-MINOAN SIGN CM096;Lo;0;L;;;;;N;;;;; +12FE2;CYPRO-MINOAN SIGN CM097;Lo;0;L;;;;;N;;;;; +12FE3;CYPRO-MINOAN SIGN CM098;Lo;0;L;;;;;N;;;;; +12FE4;CYPRO-MINOAN SIGN CM099;Lo;0;L;;;;;N;;;;; +12FE5;CYPRO-MINOAN SIGN CM100;Lo;0;L;;;;;N;;;;; +12FE6;CYPRO-MINOAN SIGN CM101;Lo;0;L;;;;;N;;;;; +12FE7;CYPRO-MINOAN SIGN CM102;Lo;0;L;;;;;N;;;;; +12FE8;CYPRO-MINOAN SIGN CM103;Lo;0;L;;;;;N;;;;; +12FE9;CYPRO-MINOAN SIGN CM104;Lo;0;L;;;;;N;;;;; +12FEA;CYPRO-MINOAN SIGN CM105;Lo;0;L;;;;;N;;;;; +12FEB;CYPRO-MINOAN SIGN CM107;Lo;0;L;;;;;N;;;;; +12FEC;CYPRO-MINOAN SIGN CM108;Lo;0;L;;;;;N;;;;; +12FED;CYPRO-MINOAN SIGN CM109;Lo;0;L;;;;;N;;;;; +12FEE;CYPRO-MINOAN SIGN CM110;Lo;0;L;;;;;N;;;;; +12FEF;CYPRO-MINOAN SIGN CM112;Lo;0;L;;;;;N;;;;; +12FF0;CYPRO-MINOAN SIGN CM114;Lo;0;L;;;;;N;;;;; +12FF1;CYPRO-MINOAN SIGN CM301;Po;0;L;;;;;N;;;;; +12FF2;CYPRO-MINOAN SIGN CM302;Po;0;L;;;;;N;;;;; 13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; 13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; 13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; @@ -23631,6 +24144,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;; 1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;; 1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;; +1342F;EGYPTIAN HIEROGLYPH V011D;Lo;0;L;;;;;N;;;;; 13430;EGYPTIAN HIEROGLYPH VERTICAL JOINER;Cf;0;L;;;;;N;;;;; 13431;EGYPTIAN HIEROGLYPH HORIZONTAL JOINER;Cf;0;L;;;;;N;;;;; 13432;EGYPTIAN HIEROGLYPH INSERT AT TOP START;Cf;0;L;;;;;N;;;;; @@ -23640,6 +24154,35 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 13436;EGYPTIAN HIEROGLYPH OVERLAY MIDDLE;Cf;0;L;;;;;N;;;;; 13437;EGYPTIAN HIEROGLYPH BEGIN SEGMENT;Cf;0;L;;;;;N;;;;; 13438;EGYPTIAN HIEROGLYPH END SEGMENT;Cf;0;L;;;;;N;;;;; +13439;EGYPTIAN HIEROGLYPH INSERT AT MIDDLE;Cf;0;L;;;;;N;;;;; +1343A;EGYPTIAN HIEROGLYPH INSERT AT TOP;Cf;0;L;;;;;N;;;;; +1343B;EGYPTIAN HIEROGLYPH INSERT AT BOTTOM;Cf;0;L;;;;;N;;;;; +1343C;EGYPTIAN HIEROGLYPH BEGIN ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343D;EGYPTIAN HIEROGLYPH END ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343E;EGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; +1343F;EGYPTIAN HIEROGLYPH END WALLED ENCLOSURE;Cf;0;L;;;;;N;;;;; +13440;EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY;Mn;0;NSM;;;;;N;;;;; +13441;EGYPTIAN HIEROGLYPH FULL BLANK;Lo;0;L;;;;;N;;;;; +13442;EGYPTIAN HIEROGLYPH HALF BLANK;Lo;0;L;;;;;N;;;;; +13443;EGYPTIAN HIEROGLYPH LOST SIGN;Lo;0;L;;;;;N;;;;; +13444;EGYPTIAN HIEROGLYPH HALF LOST SIGN;Lo;0;L;;;;;N;;;;; +13445;EGYPTIAN HIEROGLYPH TALL LOST SIGN;Lo;0;L;;;;;N;;;;; +13446;EGYPTIAN HIEROGLYPH WIDE LOST SIGN;Lo;0;L;;;;;N;;;;; +13447;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START;Mn;0;NSM;;;;;N;;;;; +13448;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START;Mn;0;NSM;;;;;N;;;;; +13449;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START;Mn;0;NSM;;;;;N;;;;; +1344A;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP END;Mn;0;NSM;;;;;N;;;;; +1344B;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP;Mn;0;NSM;;;;;N;;;;; +1344C;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP END;Mn;0;NSM;;;;;N;;;;; +1344D;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND TOP;Mn;0;NSM;;;;;N;;;;; +1344E;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM END;Mn;0;NSM;;;;;N;;;;; +1344F;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM END;Mn;0;NSM;;;;;N;;;;; +13450;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM;Mn;0;NSM;;;;;N;;;;; +13451;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT START AND BOTTOM;Mn;0;NSM;;;;;N;;;;; +13452;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT END;Mn;0;NSM;;;;;N;;;;; +13453;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND END;Mn;0;NSM;;;;;N;;;;; +13454;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM AND END;Mn;0;NSM;;;;;N;;;;; +13455;EGYPTIAN HIEROGLYPH MODIFIER DAMAGED;Mn;0;NSM;;;;;N;;;;; 14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;; 14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;; 14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;; @@ -24835,6 +25378,95 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 16A6E;MRO DANDA;Po;0;L;;;;;N;;;;; 16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;; +16A70;TANGSA LETTER OZ;Lo;0;L;;;;;N;;;;; +16A71;TANGSA LETTER OC;Lo;0;L;;;;;N;;;;; +16A72;TANGSA LETTER OQ;Lo;0;L;;;;;N;;;;; +16A73;TANGSA LETTER OX;Lo;0;L;;;;;N;;;;; +16A74;TANGSA LETTER AZ;Lo;0;L;;;;;N;;;;; +16A75;TANGSA LETTER AC;Lo;0;L;;;;;N;;;;; +16A76;TANGSA LETTER AQ;Lo;0;L;;;;;N;;;;; +16A77;TANGSA LETTER AX;Lo;0;L;;;;;N;;;;; +16A78;TANGSA LETTER VZ;Lo;0;L;;;;;N;;;;; +16A79;TANGSA LETTER VC;Lo;0;L;;;;;N;;;;; +16A7A;TANGSA LETTER VQ;Lo;0;L;;;;;N;;;;; +16A7B;TANGSA LETTER VX;Lo;0;L;;;;;N;;;;; +16A7C;TANGSA LETTER EZ;Lo;0;L;;;;;N;;;;; +16A7D;TANGSA LETTER EC;Lo;0;L;;;;;N;;;;; +16A7E;TANGSA LETTER EQ;Lo;0;L;;;;;N;;;;; +16A7F;TANGSA LETTER EX;Lo;0;L;;;;;N;;;;; +16A80;TANGSA LETTER IZ;Lo;0;L;;;;;N;;;;; +16A81;TANGSA LETTER IC;Lo;0;L;;;;;N;;;;; +16A82;TANGSA LETTER IQ;Lo;0;L;;;;;N;;;;; +16A83;TANGSA LETTER IX;Lo;0;L;;;;;N;;;;; +16A84;TANGSA LETTER UZ;Lo;0;L;;;;;N;;;;; +16A85;TANGSA LETTER UC;Lo;0;L;;;;;N;;;;; +16A86;TANGSA LETTER UQ;Lo;0;L;;;;;N;;;;; +16A87;TANGSA LETTER UX;Lo;0;L;;;;;N;;;;; +16A88;TANGSA LETTER AWZ;Lo;0;L;;;;;N;;;;; +16A89;TANGSA LETTER AWC;Lo;0;L;;;;;N;;;;; +16A8A;TANGSA LETTER AWQ;Lo;0;L;;;;;N;;;;; +16A8B;TANGSA LETTER AWX;Lo;0;L;;;;;N;;;;; +16A8C;TANGSA LETTER UIZ;Lo;0;L;;;;;N;;;;; +16A8D;TANGSA LETTER UIC;Lo;0;L;;;;;N;;;;; +16A8E;TANGSA LETTER UIQ;Lo;0;L;;;;;N;;;;; +16A8F;TANGSA LETTER UIX;Lo;0;L;;;;;N;;;;; +16A90;TANGSA LETTER FINAL NG;Lo;0;L;;;;;N;;;;; +16A91;TANGSA LETTER LONG UEX;Lo;0;L;;;;;N;;;;; +16A92;TANGSA LETTER SHORT UEZ;Lo;0;L;;;;;N;;;;; +16A93;TANGSA LETTER SHORT AWX;Lo;0;L;;;;;N;;;;; +16A94;TANGSA LETTER UEC;Lo;0;L;;;;;N;;;;; +16A95;TANGSA LETTER UEZ;Lo;0;L;;;;;N;;;;; +16A96;TANGSA LETTER UEQ;Lo;0;L;;;;;N;;;;; +16A97;TANGSA LETTER UEX;Lo;0;L;;;;;N;;;;; +16A98;TANGSA LETTER UIUZ;Lo;0;L;;;;;N;;;;; +16A99;TANGSA LETTER UIUC;Lo;0;L;;;;;N;;;;; +16A9A;TANGSA LETTER UIUQ;Lo;0;L;;;;;N;;;;; +16A9B;TANGSA LETTER UIUX;Lo;0;L;;;;;N;;;;; +16A9C;TANGSA LETTER MZ;Lo;0;L;;;;;N;;;;; +16A9D;TANGSA LETTER MC;Lo;0;L;;;;;N;;;;; +16A9E;TANGSA LETTER MQ;Lo;0;L;;;;;N;;;;; +16A9F;TANGSA LETTER MX;Lo;0;L;;;;;N;;;;; +16AA0;TANGSA LETTER KA;Lo;0;L;;;;;N;;;;; +16AA1;TANGSA LETTER KHA;Lo;0;L;;;;;N;;;;; +16AA2;TANGSA LETTER GA;Lo;0;L;;;;;N;;;;; +16AA3;TANGSA LETTER NGA;Lo;0;L;;;;;N;;;;; +16AA4;TANGSA LETTER SA;Lo;0;L;;;;;N;;;;; +16AA5;TANGSA LETTER YA;Lo;0;L;;;;;N;;;;; +16AA6;TANGSA LETTER WA;Lo;0;L;;;;;N;;;;; +16AA7;TANGSA LETTER PA;Lo;0;L;;;;;N;;;;; +16AA8;TANGSA LETTER NYA;Lo;0;L;;;;;N;;;;; +16AA9;TANGSA LETTER PHA;Lo;0;L;;;;;N;;;;; +16AAA;TANGSA LETTER BA;Lo;0;L;;;;;N;;;;; +16AAB;TANGSA LETTER MA;Lo;0;L;;;;;N;;;;; +16AAC;TANGSA LETTER NA;Lo;0;L;;;;;N;;;;; +16AAD;TANGSA LETTER HA;Lo;0;L;;;;;N;;;;; +16AAE;TANGSA LETTER LA;Lo;0;L;;;;;N;;;;; +16AAF;TANGSA LETTER HTA;Lo;0;L;;;;;N;;;;; +16AB0;TANGSA LETTER TA;Lo;0;L;;;;;N;;;;; +16AB1;TANGSA LETTER DA;Lo;0;L;;;;;N;;;;; +16AB2;TANGSA LETTER RA;Lo;0;L;;;;;N;;;;; +16AB3;TANGSA LETTER NHA;Lo;0;L;;;;;N;;;;; +16AB4;TANGSA LETTER SHA;Lo;0;L;;;;;N;;;;; +16AB5;TANGSA LETTER CA;Lo;0;L;;;;;N;;;;; +16AB6;TANGSA LETTER TSA;Lo;0;L;;;;;N;;;;; +16AB7;TANGSA LETTER GHA;Lo;0;L;;;;;N;;;;; +16AB8;TANGSA LETTER HTTA;Lo;0;L;;;;;N;;;;; +16AB9;TANGSA LETTER THA;Lo;0;L;;;;;N;;;;; +16ABA;TANGSA LETTER XA;Lo;0;L;;;;;N;;;;; +16ABB;TANGSA LETTER FA;Lo;0;L;;;;;N;;;;; +16ABC;TANGSA LETTER DHA;Lo;0;L;;;;;N;;;;; +16ABD;TANGSA LETTER CHA;Lo;0;L;;;;;N;;;;; +16ABE;TANGSA LETTER ZA;Lo;0;L;;;;;N;;;;; +16AC0;TANGSA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +16AC1;TANGSA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +16AC2;TANGSA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +16AC3;TANGSA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +16AC4;TANGSA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +16AC5;TANGSA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +16AC6;TANGSA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +16AC7;TANGSA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +16AC8;TANGSA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +16AC9;TANGSA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;; 16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;; 16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;; @@ -26487,6 +27119,19 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;; 18D00;;Lo;0;L;;;;;N;;;;; 18D08;;Lo;0;L;;;;;N;;;;; +1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;; +1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;; +1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;; +1AFF3;KATAKANA LETTER MINNAN TONE-5;Lm;0;L;;;;;N;;;;; +1AFF5;KATAKANA LETTER MINNAN TONE-7;Lm;0;L;;;;;N;;;;; +1AFF6;KATAKANA LETTER MINNAN TONE-8;Lm;0;L;;;;;N;;;;; +1AFF7;KATAKANA LETTER MINNAN NASALIZED TONE-1;Lm;0;L;;;;;N;;;;; +1AFF8;KATAKANA LETTER MINNAN NASALIZED TONE-2;Lm;0;L;;;;;N;;;;; +1AFF9;KATAKANA LETTER MINNAN NASALIZED TONE-3;Lm;0;L;;;;;N;;;;; +1AFFA;KATAKANA LETTER MINNAN NASALIZED TONE-4;Lm;0;L;;;;;N;;;;; +1AFFB;KATAKANA LETTER MINNAN NASALIZED TONE-5;Lm;0;L;;;;;N;;;;; +1AFFD;KATAKANA LETTER MINNAN NASALIZED TONE-7;Lm;0;L;;;;;N;;;;; +1AFFE;KATAKANA LETTER MINNAN NASALIZED TONE-8;Lm;0;L;;;;;N;;;;; 1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; 1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; 1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;; @@ -26774,9 +27419,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;; 1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;; 1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;; +1B11F;HIRAGANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; +1B120;KATAKANA LETTER ARCHAIC YI;Lo;0;L;;;;;N;;;;; +1B121;KATAKANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; +1B122;KATAKANA LETTER ARCHAIC WU;Lo;0;L;;;;;N;;;;; +1B132;HIRAGANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; 1B150;HIRAGANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; 1B151;HIRAGANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; 1B152;HIRAGANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; +1B155;KATAKANA LETTER SMALL KO;Lo;0;L;;;;;N;;;;; 1B164;KATAKANA LETTER SMALL WI;Lo;0;L;;;;;N;;;;; 1B165;KATAKANA LETTER SMALL WE;Lo;0;L;;;;;N;;;;; 1B166;KATAKANA LETTER SMALL WO;Lo;0;L;;;;;N;;;;; @@ -27324,6 +27975,191 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;; 1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;; 1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;; +1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF03;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF04;ZNAMENNY COMBINING MARK NIZKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF05;ZNAMENNY COMBINING MARK SREDNE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF06;ZNAMENNY COMBINING MARK MALO POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF07;ZNAMENNY COMBINING MARK POVYSHE ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF08;ZNAMENNY COMBINING MARK VYSOKO ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF09;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0A;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0B;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF0C;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0D;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0E;ZNAMENNY COMBINING MARK TSATA ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF0F;ZNAMENNY COMBINING MARK GORAZDO NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF10;ZNAMENNY COMBINING MARK NIZKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF11;ZNAMENNY COMBINING MARK SREDNE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF12;ZNAMENNY COMBINING MARK MALO POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF13;ZNAMENNY COMBINING MARK POVYSHE ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF14;ZNAMENNY COMBINING MARK VYSOKO ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF15;ZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF16;ZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF17;ZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON RIGHT;Mn;0;NSM;;;;;N;;;;; +1CF18;ZNAMENNY COMBINING MARK TSATA S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF19;ZNAMENNY COMBINING MARK MALO POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1A;ZNAMENNY COMBINING MARK STRANNO MALO POVYSHE;Mn;0;NSM;;;;;N;;;;; +1CF1B;ZNAMENNY COMBINING MARK POVYSHE S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1C;ZNAMENNY COMBINING MARK POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; +1CF1D;ZNAMENNY COMBINING MARK VYSOKO S KRYZHEM;Mn;0;NSM;;;;;N;;;;; +1CF1E;ZNAMENNY COMBINING MARK MALO POVYSHE STRANNO;Mn;0;NSM;;;;;N;;;;; +1CF1F;ZNAMENNY COMBINING MARK GORAZDO VYSOKO;Mn;0;NSM;;;;;N;;;;; +1CF20;ZNAMENNY COMBINING MARK ZELO;Mn;0;NSM;;;;;N;;;;; +1CF21;ZNAMENNY COMBINING MARK ON;Mn;0;NSM;;;;;N;;;;; +1CF22;ZNAMENNY COMBINING MARK RAVNO;Mn;0;NSM;;;;;N;;;;; +1CF23;ZNAMENNY COMBINING MARK TIKHAYA;Mn;0;NSM;;;;;N;;;;; +1CF24;ZNAMENNY COMBINING MARK BORZAYA;Mn;0;NSM;;;;;N;;;;; +1CF25;ZNAMENNY COMBINING MARK UDARKA;Mn;0;NSM;;;;;N;;;;; +1CF26;ZNAMENNY COMBINING MARK PODVERTKA;Mn;0;NSM;;;;;N;;;;; +1CF27;ZNAMENNY COMBINING MARK LOMKA;Mn;0;NSM;;;;;N;;;;; +1CF28;ZNAMENNY COMBINING MARK KUPNAYA;Mn;0;NSM;;;;;N;;;;; +1CF29;ZNAMENNY COMBINING MARK KACHKA;Mn;0;NSM;;;;;N;;;;; +1CF2A;ZNAMENNY COMBINING MARK ZEVOK;Mn;0;NSM;;;;;N;;;;; +1CF2B;ZNAMENNY COMBINING MARK SKOBA;Mn;0;NSM;;;;;N;;;;; +1CF2C;ZNAMENNY COMBINING MARK RAZSEKA;Mn;0;NSM;;;;;N;;;;; +1CF2D;ZNAMENNY COMBINING MARK KRYZH ON LEFT;Mn;0;NSM;;;;;N;;;;; +1CF30;ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO;Mn;0;NSM;;;;;N;;;;; +1CF31;ZNAMENNY COMBINING TONAL RANGE MARK SVETLO;Mn;0;NSM;;;;;N;;;;; +1CF32;ZNAMENNY COMBINING TONAL RANGE MARK TRESVETLO;Mn;0;NSM;;;;;N;;;;; +1CF33;ZNAMENNY COMBINING MARK ZADERZHKA;Mn;0;NSM;;;;;N;;;;; +1CF34;ZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKA;Mn;0;NSM;;;;;N;;;;; +1CF35;ZNAMENNY COMBINING MARK OTSECHKA;Mn;0;NSM;;;;;N;;;;; +1CF36;ZNAMENNY COMBINING MARK PODCHASHIE;Mn;0;NSM;;;;;N;;;;; +1CF37;ZNAMENNY COMBINING MARK PODCHASHIE WITH VERTICAL STROKE;Mn;0;NSM;;;;;N;;;;; +1CF38;ZNAMENNY COMBINING MARK CHASHKA;Mn;0;NSM;;;;;N;;;;; +1CF39;ZNAMENNY COMBINING MARK CHASHKA POLNAYA;Mn;0;NSM;;;;;N;;;;; +1CF3A;ZNAMENNY COMBINING MARK OBLACHKO;Mn;0;NSM;;;;;N;;;;; +1CF3B;ZNAMENNY COMBINING MARK SOROCHYA NOZHKA;Mn;0;NSM;;;;;N;;;;; +1CF3C;ZNAMENNY COMBINING MARK TOCHKA;Mn;0;NSM;;;;;N;;;;; +1CF3D;ZNAMENNY COMBINING MARK DVOETOCHIE;Mn;0;NSM;;;;;N;;;;; +1CF3E;ZNAMENNY COMBINING ATTACHING VERTICAL OMET;Mn;0;NSM;;;;;N;;;;; +1CF3F;ZNAMENNY COMBINING MARK CURVED OMET;Mn;0;NSM;;;;;N;;;;; +1CF40;ZNAMENNY COMBINING MARK KRYZH;Mn;0;NSM;;;;;N;;;;; +1CF41;ZNAMENNY COMBINING LOWER TONAL RANGE INDICATOR;Mn;0;NSM;;;;;N;;;;; +1CF42;ZNAMENNY PRIZNAK MODIFIER LEVEL-2;Mn;0;NSM;;;;;N;;;;; +1CF43;ZNAMENNY PRIZNAK MODIFIER LEVEL-3;Mn;0;NSM;;;;;N;;;;; +1CF44;ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIP;Mn;0;NSM;;;;;N;;;;; +1CF45;ZNAMENNY PRIZNAK MODIFIER KRYZH;Mn;0;NSM;;;;;N;;;;; +1CF46;ZNAMENNY PRIZNAK MODIFIER ROG;Mn;0;NSM;;;;;N;;;;; +1CF50;ZNAMENNY NEUME KRYUK;So;0;L;;;;;N;;;;; +1CF51;ZNAMENNY NEUME KRYUK TIKHY;So;0;L;;;;;N;;;;; +1CF52;ZNAMENNY NEUME PARAKLIT;So;0;L;;;;;N;;;;; +1CF53;ZNAMENNY NEUME DVA V CHELNU;So;0;L;;;;;N;;;;; +1CF54;ZNAMENNY NEUME KLYUCH;So;0;L;;;;;N;;;;; +1CF55;ZNAMENNY NEUME ZANOZHEK;So;0;L;;;;;N;;;;; +1CF56;ZNAMENNY NEUME STOPITSA;So;0;L;;;;;N;;;;; +1CF57;ZNAMENNY NEUME STOPITSA S OCHKOM;So;0;L;;;;;N;;;;; +1CF58;ZNAMENNY NEUME PEREVODKA;So;0;L;;;;;N;;;;; +1CF59;ZNAMENNY NEUME PEREVODKA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF5A;ZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKA;So;0;L;;;;;N;;;;; +1CF5B;ZNAMENNY NEUME CHELYUSTKA;So;0;L;;;;;N;;;;; +1CF5C;ZNAMENNY NEUME PALKA;So;0;L;;;;;N;;;;; +1CF5D;ZNAMENNY NEUME ZAPYATAYA;So;0;L;;;;;N;;;;; +1CF5E;ZNAMENNY NEUME GOLUBCHIK BORZY;So;0;L;;;;;N;;;;; +1CF5F;ZNAMENNY NEUME GOLUBCHIK TIKHY;So;0;L;;;;;N;;;;; +1CF60;ZNAMENNY NEUME GOLUBCHIK MRACHNY;So;0;L;;;;;N;;;;; +1CF61;ZNAMENNY NEUME GOLUBCHIK SVETLY;So;0;L;;;;;N;;;;; +1CF62;ZNAMENNY NEUME GOLUBCHIK TRESVETLY;So;0;L;;;;;N;;;;; +1CF63;ZNAMENNY NEUME VRAKHIYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF64;ZNAMENNY NEUME VRAKHIYA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF65;ZNAMENNY NEUME VRAKHIYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF66;ZNAMENNY NEUME VRAKHIYA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF67;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF68;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF69;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF6A;ZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF6B;ZNAMENNY NEUME DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CF6C;ZNAMENNY NEUME REVERSED CHELYUSTKA;So;0;L;;;;;N;;;;; +1CF6D;ZNAMENNY NEUME DERBITSA;So;0;L;;;;;N;;;;; +1CF6E;ZNAMENNY NEUME KHAMILO;So;0;L;;;;;N;;;;; +1CF6F;ZNAMENNY NEUME CHASHKA;So;0;L;;;;;N;;;;; +1CF70;ZNAMENNY NEUME PODCHASHIE;So;0;L;;;;;N;;;;; +1CF71;ZNAMENNY NEUME SKAMEYTSA MRACHNAYA;So;0;L;;;;;N;;;;; +1CF72;ZNAMENNY NEUME SKAMEYTSA SVETLAYA;So;0;L;;;;;N;;;;; +1CF73;ZNAMENNY NEUME SKAMEYTSA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CF74;ZNAMENNY NEUME SKAMEYTSA TIKHAYA;So;0;L;;;;;N;;;;; +1CF75;ZNAMENNY NEUME DEMESTVENNY KLYUCH;So;0;L;;;;;N;;;;; +1CF76;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF77;ZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF78;ZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYA;So;0;L;;;;;N;;;;; +1CF79;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA PROSTAYA;So;0;L;;;;;N;;;;; +1CF7A;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CF7B;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF7C;ZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CF7D;ZNAMENNY NEUME SLOZHITIE;So;0;L;;;;;N;;;;; +1CF7E;ZNAMENNY NEUME SLOZHITIE S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF7F;ZNAMENNY NEUME SLOZHITIE ZAKRYTOE;So;0;L;;;;;N;;;;; +1CF80;ZNAMENNY NEUME SLOZHITIE S KRYZHEM;So;0;L;;;;;N;;;;; +1CF81;ZNAMENNY NEUME KRYZH;So;0;L;;;;;N;;;;; +1CF82;ZNAMENNY NEUME ROG;So;0;L;;;;;N;;;;; +1CF83;ZNAMENNY NEUME FITA;So;0;L;;;;;N;;;;; +1CF84;ZNAMENNY NEUME KOBYLA;So;0;L;;;;;N;;;;; +1CF85;ZNAMENNY NEUME ZMEYTSA;So;0;L;;;;;N;;;;; +1CF86;ZNAMENNY NEUME STATYA;So;0;L;;;;;N;;;;; +1CF87;ZNAMENNY NEUME STATYA S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF88;ZNAMENNY NEUME STATYA S KRYZHEM;So;0;L;;;;;N;;;;; +1CF89;ZNAMENNY NEUME STATYA S ZAPYATOY I KRYZHEM;So;0;L;;;;;N;;;;; +1CF8A;ZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOY;So;0;L;;;;;N;;;;; +1CF8B;ZNAMENNY NEUME STATYA ZAKRYTAYA;So;0;L;;;;;N;;;;; +1CF8C;ZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOY;So;0;L;;;;;N;;;;; +1CF8D;ZNAMENNY NEUME STATYA S ROGOM;So;0;L;;;;;N;;;;; +1CF8E;ZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMI;So;0;L;;;;;N;;;;; +1CF8F;ZNAMENNY NEUME STATYA S ZAPYATOY I PODCHASHIEM;So;0;L;;;;;N;;;;; +1CF90;ZNAMENNY NEUME POLKULIZMY;So;0;L;;;;;N;;;;; +1CF91;ZNAMENNY NEUME STATYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF92;ZNAMENNY NEUME STRELA PROSTAYA;So;0;L;;;;;N;;;;; +1CF93;ZNAMENNY NEUME STRELA MRACHNOTIKHAYA;So;0;L;;;;;N;;;;; +1CF94;ZNAMENNY NEUME STRELA KRYZHEVAYA;So;0;L;;;;;N;;;;; +1CF95;ZNAMENNY NEUME STRELA POLUPOVODNAYA;So;0;L;;;;;N;;;;; +1CF96;ZNAMENNY NEUME STRELA POVODNAYA;So;0;L;;;;;N;;;;; +1CF97;ZNAMENNY NEUME STRELA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF98;ZNAMENNY NEUME STRELA KLYUCHEPOVODNAYA;So;0;L;;;;;N;;;;; +1CF99;ZNAMENNY NEUME STRELA KLYUCHENEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CF9A;ZNAMENNY NEUME STRELA TIKHAYA PUTNAYA;So;0;L;;;;;N;;;;; +1CF9B;ZNAMENNY NEUME STRELA DVOECHELNAYA;So;0;L;;;;;N;;;;; +1CF9C;ZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CF9D;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA;So;0;L;;;;;N;;;;; +1CF9E;ZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CF9F;ZNAMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYA;So;0;L;;;;;N;;;;; +1CFA0;ZNAMENNY NEUME STRELA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA1;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA2;ZNAMENNY NEUME STRELA GROMNAYA;So;0;L;;;;;N;;;;; +1CFA3;ZNAMENNY NEUME STRELA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFA4;ZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFA5;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CFA6;ZNAMENNY NEUME STRELA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFA7;ZNAMENNY NEUME MECHIK;So;0;L;;;;;N;;;;; +1CFA8;ZNAMENNY NEUME MECHIK POVODNY;So;0;L;;;;;N;;;;; +1CFA9;ZNAMENNY NEUME MECHIK KLYUCHEVOY;So;0;L;;;;;N;;;;; +1CFAA;ZNAMENNY NEUME MECHIK KLYUCHEPOVODNY;So;0;L;;;;;N;;;;; +1CFAB;ZNAMENNY NEUME MECHIK KLYUCHENEPOSTOYANNY;So;0;L;;;;;N;;;;; +1CFAC;ZNAMENNY NEUME STRELA TRYASOGLASNAYA;So;0;L;;;;;N;;;;; +1CFAD;ZNAMENNY NEUME STRELA TRYASOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFAE;ZNAMENNY NEUME STRELA TRYASOSTRELNAYA;So;0;L;;;;;N;;;;; +1CFAF;ZNAMENNY NEUME OSOKA;So;0;L;;;;;N;;;;; +1CFB0;ZNAMENNY NEUME OSOKA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB1;ZNAMENNY NEUME OSOKA TRESVETLAYA;So;0;L;;;;;N;;;;; +1CFB2;ZNAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB3;ZNAMENNY NEUME OSOKA KLYUCHEVAYA SVETLAYA;So;0;L;;;;;N;;;;; +1CFB4;ZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYA;So;0;L;;;;;N;;;;; +1CFB5;ZNAMENNY NEUME STRELA KRYUKOVAYA;So;0;L;;;;;N;;;;; +1CFB6;ZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFB7;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFB8;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFB9;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMNAYA;So;0;L;;;;;N;;;;; +1CFBA;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA;So;0;L;;;;;N;;;;; +1CFBB;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYA;So;0;L;;;;;N;;;;; +1CFBC;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA;So;0;L;;;;;N;;;;; +1CFBD;ZNAMENNY NEUME STRELA KRYUKOVAYA GROMOKRYZHEVAYA POVODNAYA;So;0;L;;;;;N;;;;; +1CFBE;ZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKA;So;0;L;;;;;N;;;;; +1CFBF;ZNAMENNY NEUME KUFISMA;So;0;L;;;;;N;;;;; +1CFC0;ZNAMENNY NEUME OBLAKO;So;0;L;;;;;N;;;;; +1CFC1;ZNAMENNY NEUME DUDA;So;0;L;;;;;N;;;;; +1CFC2;ZNAMENNY NEUME NEMKA;So;0;L;;;;;N;;;;; +1CFC3;ZNAMENNY NEUME PAUK;So;0;L;;;;;N;;;;; 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; 1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; 1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; @@ -27801,6 +28637,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;; 1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;; 1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;; +1D1E9;MUSICAL SYMBOL SORI;So;0;ON;;;;;N;;;;; +1D1EA;MUSICAL SYMBOL KORON;So;0;ON;;;;;N;;;;; 1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;; 1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;; 1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;; @@ -27871,6 +28709,26 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;; 1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;; 1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;; +1D2C0;KAKTOVIK NUMERAL ZERO;No;0;L;;;;0;N;;;;; +1D2C1;KAKTOVIK NUMERAL ONE;No;0;L;;;;1;N;;;;; +1D2C2;KAKTOVIK NUMERAL TWO;No;0;L;;;;2;N;;;;; +1D2C3;KAKTOVIK NUMERAL THREE;No;0;L;;;;3;N;;;;; +1D2C4;KAKTOVIK NUMERAL FOUR;No;0;L;;;;4;N;;;;; +1D2C5;KAKTOVIK NUMERAL FIVE;No;0;L;;;;5;N;;;;; +1D2C6;KAKTOVIK NUMERAL SIX;No;0;L;;;;6;N;;;;; +1D2C7;KAKTOVIK NUMERAL SEVEN;No;0;L;;;;7;N;;;;; +1D2C8;KAKTOVIK NUMERAL EIGHT;No;0;L;;;;8;N;;;;; +1D2C9;KAKTOVIK NUMERAL NINE;No;0;L;;;;9;N;;;;; +1D2CA;KAKTOVIK NUMERAL TEN;No;0;L;;;;10;N;;;;; +1D2CB;KAKTOVIK NUMERAL ELEVEN;No;0;L;;;;11;N;;;;; +1D2CC;KAKTOVIK NUMERAL TWELVE;No;0;L;;;;12;N;;;;; +1D2CD;KAKTOVIK NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;; +1D2CE;KAKTOVIK NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;; +1D2CF;KAKTOVIK NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;; +1D2D0;KAKTOVIK NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;; +1D2D1;KAKTOVIK NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;; +1D2D2;KAKTOVIK NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;; +1D2D3;KAKTOVIK NUMERAL NINETEEN;No;0;L;;;;19;N;;;;; 1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;; 1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;; 1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;; @@ -29671,6 +30529,43 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; 1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; 1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; +1DF00;LATIN SMALL LETTER FENG DIGRAPH WITH TRILL;Ll;0;L;;;;;N;;;;; +1DF01;LATIN SMALL LETTER REVERSED SCRIPT G;Ll;0;L;;;;;N;;;;; +1DF02;LATIN LETTER SMALL CAPITAL TURNED G;Ll;0;L;;;;;N;;;;; +1DF03;LATIN SMALL LETTER REVERSED K;Ll;0;L;;;;;N;;;;; +1DF04;LATIN LETTER SMALL CAPITAL L WITH BELT;Ll;0;L;;;;;N;;;;; +1DF05;LATIN SMALL LETTER LEZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF06;LATIN SMALL LETTER TURNED Y WITH BELT;Ll;0;L;;;;;N;;;;; +1DF07;LATIN SMALL LETTER REVERSED ENG;Ll;0;L;;;;;N;;;;; +1DF08;LATIN SMALL LETTER TURNED R WITH LONG LEG AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF09;LATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF0A;LATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOK;Lo;0;L;;;;;N;;;;; +1DF0B;LATIN SMALL LETTER ESH WITH DOUBLE BAR;Ll;0;L;;;;;N;;;;; +1DF0C;LATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURL;Ll;0;L;;;;;N;;;;; +1DF0D;LATIN SMALL LETTER TURNED T WITH CURL;Ll;0;L;;;;;N;;;;; +1DF0E;LATIN LETTER INVERTED GLOTTAL STOP WITH CURL;Ll;0;L;;;;;N;;;;; +1DF0F;LATIN LETTER STRETCHED C WITH CURL;Ll;0;L;;;;;N;;;;; +1DF10;LATIN LETTER SMALL CAPITAL TURNED K;Ll;0;L;;;;;N;;;;; +1DF11;LATIN SMALL LETTER L WITH FISHHOOK;Ll;0;L;;;;;N;;;;; +1DF12;LATIN SMALL LETTER DEZH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF13;LATIN SMALL LETTER L WITH BELT AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF14;LATIN SMALL LETTER ENG WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF15;LATIN SMALL LETTER TURNED R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF16;LATIN SMALL LETTER R WITH FISHHOOK AND PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF17;LATIN SMALL LETTER TESH DIGRAPH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF18;LATIN SMALL LETTER EZH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;; +1DF19;LATIN SMALL LETTER DEZH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1A;LATIN SMALL LETTER I WITH STROKE AND RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1B;LATIN SMALL LETTER O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1C;LATIN SMALL LETTER TESH DIGRAPH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1D;LATIN SMALL LETTER C WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;; +1DF1E;LATIN SMALL LETTER S WITH CURL;Ll;0;L;;;;;N;;;;; +1DF25;LATIN SMALL LETTER D WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF26;LATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF27;LATIN SMALL LETTER N WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF28;LATIN SMALL LETTER R WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF29;LATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; +1DF2A;LATIN SMALL LETTER T WITH MID-HEIGHT LEFT HOOK;Ll;0;L;;;;;N;;;;; 1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;; 1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;; 1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;; @@ -29709,6 +30604,69 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; 1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;; 1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; +1E030;MODIFIER LETTER CYRILLIC SMALL A;Lm;0;L; 0430;;;;N;;;;; +1E031;MODIFIER LETTER CYRILLIC SMALL BE;Lm;0;L; 0431;;;;N;;;;; +1E032;MODIFIER LETTER CYRILLIC SMALL VE;Lm;0;L; 0432;;;;N;;;;; +1E033;MODIFIER LETTER CYRILLIC SMALL GHE;Lm;0;L; 0433;;;;N;;;;; +1E034;MODIFIER LETTER CYRILLIC SMALL DE;Lm;0;L; 0434;;;;N;;;;; +1E035;MODIFIER LETTER CYRILLIC SMALL IE;Lm;0;L; 0435;;;;N;;;;; +1E036;MODIFIER LETTER CYRILLIC SMALL ZHE;Lm;0;L; 0436;;;;N;;;;; +1E037;MODIFIER LETTER CYRILLIC SMALL ZE;Lm;0;L; 0437;;;;N;;;;; +1E038;MODIFIER LETTER CYRILLIC SMALL I;Lm;0;L; 0438;;;;N;;;;; +1E039;MODIFIER LETTER CYRILLIC SMALL KA;Lm;0;L; 043A;;;;N;;;;; +1E03A;MODIFIER LETTER CYRILLIC SMALL EL;Lm;0;L; 043B;;;;N;;;;; +1E03B;MODIFIER LETTER CYRILLIC SMALL EM;Lm;0;L; 043C;;;;N;;;;; +1E03C;MODIFIER LETTER CYRILLIC SMALL O;Lm;0;L; 043E;;;;N;;;;; +1E03D;MODIFIER LETTER CYRILLIC SMALL PE;Lm;0;L; 043F;;;;N;;;;; +1E03E;MODIFIER LETTER CYRILLIC SMALL ER;Lm;0;L; 0440;;;;N;;;;; +1E03F;MODIFIER LETTER CYRILLIC SMALL ES;Lm;0;L; 0441;;;;N;;;;; +1E040;MODIFIER LETTER CYRILLIC SMALL TE;Lm;0;L; 0442;;;;N;;;;; +1E041;MODIFIER LETTER CYRILLIC SMALL U;Lm;0;L; 0443;;;;N;;;;; +1E042;MODIFIER LETTER CYRILLIC SMALL EF;Lm;0;L; 0444;;;;N;;;;; +1E043;MODIFIER LETTER CYRILLIC SMALL HA;Lm;0;L; 0445;;;;N;;;;; +1E044;MODIFIER LETTER CYRILLIC SMALL TSE;Lm;0;L; 0446;;;;N;;;;; +1E045;MODIFIER LETTER CYRILLIC SMALL CHE;Lm;0;L; 0447;;;;N;;;;; +1E046;MODIFIER LETTER CYRILLIC SMALL SHA;Lm;0;L; 0448;;;;N;;;;; +1E047;MODIFIER LETTER CYRILLIC SMALL YERU;Lm;0;L; 044B;;;;N;;;;; +1E048;MODIFIER LETTER CYRILLIC SMALL E;Lm;0;L; 044D;;;;N;;;;; +1E049;MODIFIER LETTER CYRILLIC SMALL YU;Lm;0;L; 044E;;;;N;;;;; +1E04A;MODIFIER LETTER CYRILLIC SMALL DZZE;Lm;0;L; A689;;;;N;;;;; +1E04B;MODIFIER LETTER CYRILLIC SMALL SCHWA;Lm;0;L; 04D9;;;;N;;;;; +1E04C;MODIFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I;Lm;0;L; 0456;;;;N;;;;; +1E04D;MODIFIER LETTER CYRILLIC SMALL JE;Lm;0;L; 0458;;;;N;;;;; +1E04E;MODIFIER LETTER CYRILLIC SMALL BARRED O;Lm;0;L; 04E9;;;;N;;;;; +1E04F;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U;Lm;0;L; 04AF;;;;N;;;;; +1E050;MODIFIER LETTER CYRILLIC SMALL PALOCHKA;Lm;0;L; 04CF;;;;N;;;;; +1E051;CYRILLIC SUBSCRIPT SMALL LETTER A;Lm;0;L; 0430;;;;N;;;;; +1E052;CYRILLIC SUBSCRIPT SMALL LETTER BE;Lm;0;L; 0431;;;;N;;;;; +1E053;CYRILLIC SUBSCRIPT SMALL LETTER VE;Lm;0;L; 0432;;;;N;;;;; +1E054;CYRILLIC SUBSCRIPT SMALL LETTER GHE;Lm;0;L; 0433;;;;N;;;;; +1E055;CYRILLIC SUBSCRIPT SMALL LETTER DE;Lm;0;L; 0434;;;;N;;;;; +1E056;CYRILLIC SUBSCRIPT SMALL LETTER IE;Lm;0;L; 0435;;;;N;;;;; +1E057;CYRILLIC SUBSCRIPT SMALL LETTER ZHE;Lm;0;L; 0436;;;;N;;;;; +1E058;CYRILLIC SUBSCRIPT SMALL LETTER ZE;Lm;0;L; 0437;;;;N;;;;; +1E059;CYRILLIC SUBSCRIPT SMALL LETTER I;Lm;0;L; 0438;;;;N;;;;; +1E05A;CYRILLIC SUBSCRIPT SMALL LETTER KA;Lm;0;L; 043A;;;;N;;;;; +1E05B;CYRILLIC SUBSCRIPT SMALL LETTER EL;Lm;0;L; 043B;;;;N;;;;; +1E05C;CYRILLIC SUBSCRIPT SMALL LETTER O;Lm;0;L; 043E;;;;N;;;;; +1E05D;CYRILLIC SUBSCRIPT SMALL LETTER PE;Lm;0;L; 043F;;;;N;;;;; +1E05E;CYRILLIC SUBSCRIPT SMALL LETTER ES;Lm;0;L; 0441;;;;N;;;;; +1E05F;CYRILLIC SUBSCRIPT SMALL LETTER U;Lm;0;L; 0443;;;;N;;;;; +1E060;CYRILLIC SUBSCRIPT SMALL LETTER EF;Lm;0;L; 0444;;;;N;;;;; +1E061;CYRILLIC SUBSCRIPT SMALL LETTER HA;Lm;0;L; 0445;;;;N;;;;; +1E062;CYRILLIC SUBSCRIPT SMALL LETTER TSE;Lm;0;L; 0446;;;;N;;;;; +1E063;CYRILLIC SUBSCRIPT SMALL LETTER CHE;Lm;0;L; 0447;;;;N;;;;; +1E064;CYRILLIC SUBSCRIPT SMALL LETTER SHA;Lm;0;L; 0448;;;;N;;;;; +1E065;CYRILLIC SUBSCRIPT SMALL LETTER HARD SIGN;Lm;0;L; 044A;;;;N;;;;; +1E066;CYRILLIC SUBSCRIPT SMALL LETTER YERU;Lm;0;L; 044B;;;;N;;;;; +1E067;CYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTURN;Lm;0;L; 0491;;;;N;;;;; +1E068;CYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Lm;0;L; 0456;;;;N;;;;; +1E069;CYRILLIC SUBSCRIPT SMALL LETTER DZE;Lm;0;L; 0455;;;;N;;;;; +1E06A;CYRILLIC SUBSCRIPT SMALL LETTER DZHE;Lm;0;L; 045F;;;;N;;;;; +1E06B;MODIFIER LETTER CYRILLIC SMALL ES WITH DESCENDER;Lm;0;L; 04AB;;;;N;;;;; +1E06C;MODIFIER LETTER CYRILLIC SMALL YERU WITH BACK YER;Lm;0;L; A651;;;;N;;;;; +1E06D;MODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKE;Lm;0;L; 04B1;;;;N;;;;; +1E08F;COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Mn;230;NSM;;;;;N;;;;; 1E100;NYIAKENG PUACHUE HMONG LETTER MA;Lo;0;L;;;;;N;;;;; 1E101;NYIAKENG PUACHUE HMONG LETTER TSA;Lo;0;L;;;;;N;;;;; 1E102;NYIAKENG PUACHUE HMONG LETTER NTA;Lo;0;L;;;;;N;;;;; @@ -29780,6 +30738,37 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E149;NYIAKENG PUACHUE HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1E14E;NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ;Lo;0;L;;;;;N;;;;; 1E14F;NYIAKENG PUACHUE HMONG CIRCLED CA;So;0;L;;;;;N;;;;; +1E290;TOTO LETTER PA;Lo;0;L;;;;;N;;;;; +1E291;TOTO LETTER BA;Lo;0;L;;;;;N;;;;; +1E292;TOTO LETTER TA;Lo;0;L;;;;;N;;;;; +1E293;TOTO LETTER DA;Lo;0;L;;;;;N;;;;; +1E294;TOTO LETTER KA;Lo;0;L;;;;;N;;;;; +1E295;TOTO LETTER GA;Lo;0;L;;;;;N;;;;; +1E296;TOTO LETTER MA;Lo;0;L;;;;;N;;;;; +1E297;TOTO LETTER NA;Lo;0;L;;;;;N;;;;; +1E298;TOTO LETTER NGA;Lo;0;L;;;;;N;;;;; +1E299;TOTO LETTER SA;Lo;0;L;;;;;N;;;;; +1E29A;TOTO LETTER CHA;Lo;0;L;;;;;N;;;;; +1E29B;TOTO LETTER YA;Lo;0;L;;;;;N;;;;; +1E29C;TOTO LETTER WA;Lo;0;L;;;;;N;;;;; +1E29D;TOTO LETTER JA;Lo;0;L;;;;;N;;;;; +1E29E;TOTO LETTER HA;Lo;0;L;;;;;N;;;;; +1E29F;TOTO LETTER RA;Lo;0;L;;;;;N;;;;; +1E2A0;TOTO LETTER LA;Lo;0;L;;;;;N;;;;; +1E2A1;TOTO LETTER I;Lo;0;L;;;;;N;;;;; +1E2A2;TOTO LETTER BREATHY I;Lo;0;L;;;;;N;;;;; +1E2A3;TOTO LETTER IU;Lo;0;L;;;;;N;;;;; +1E2A4;TOTO LETTER BREATHY IU;Lo;0;L;;;;;N;;;;; +1E2A5;TOTO LETTER U;Lo;0;L;;;;;N;;;;; +1E2A6;TOTO LETTER E;Lo;0;L;;;;;N;;;;; +1E2A7;TOTO LETTER BREATHY E;Lo;0;L;;;;;N;;;;; +1E2A8;TOTO LETTER EO;Lo;0;L;;;;;N;;;;; +1E2A9;TOTO LETTER BREATHY EO;Lo;0;L;;;;;N;;;;; +1E2AA;TOTO LETTER O;Lo;0;L;;;;;N;;;;; +1E2AB;TOTO LETTER AE;Lo;0;L;;;;;N;;;;; +1E2AC;TOTO LETTER BREATHY AE;Lo;0;L;;;;;N;;;;; +1E2AD;TOTO LETTER A;Lo;0;L;;;;;N;;;;; +1E2AE;TOTO SIGN RISING TONE;Mn;230;NSM;;;;;N;;;;; 1E2C0;WANCHO LETTER AA;Lo;0;L;;;;;N;;;;; 1E2C1;WANCHO LETTER A;Lo;0;L;;;;;N;;;;; 1E2C2;WANCHO LETTER BA;Lo;0;L;;;;;N;;;;; @@ -29839,6 +30828,76 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E2F8;WANCHO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1E2F9;WANCHO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 1E2FF;WANCHO NGUN SIGN;Sc;0;ET;;;;;N;;;;; +1E4D0;NAG MUNDARI LETTER O;Lo;0;L;;;;;N;;;;; +1E4D1;NAG MUNDARI LETTER OP;Lo;0;L;;;;;N;;;;; +1E4D2;NAG MUNDARI LETTER OL;Lo;0;L;;;;;N;;;;; +1E4D3;NAG MUNDARI LETTER OY;Lo;0;L;;;;;N;;;;; +1E4D4;NAG MUNDARI LETTER ONG;Lo;0;L;;;;;N;;;;; +1E4D5;NAG MUNDARI LETTER A;Lo;0;L;;;;;N;;;;; +1E4D6;NAG MUNDARI LETTER AJ;Lo;0;L;;;;;N;;;;; +1E4D7;NAG MUNDARI LETTER AB;Lo;0;L;;;;;N;;;;; +1E4D8;NAG MUNDARI LETTER ANY;Lo;0;L;;;;;N;;;;; +1E4D9;NAG MUNDARI LETTER AH;Lo;0;L;;;;;N;;;;; +1E4DA;NAG MUNDARI LETTER I;Lo;0;L;;;;;N;;;;; +1E4DB;NAG MUNDARI LETTER IS;Lo;0;L;;;;;N;;;;; +1E4DC;NAG MUNDARI LETTER IDD;Lo;0;L;;;;;N;;;;; +1E4DD;NAG MUNDARI LETTER IT;Lo;0;L;;;;;N;;;;; +1E4DE;NAG MUNDARI LETTER IH;Lo;0;L;;;;;N;;;;; +1E4DF;NAG MUNDARI LETTER U;Lo;0;L;;;;;N;;;;; +1E4E0;NAG MUNDARI LETTER UC;Lo;0;L;;;;;N;;;;; +1E4E1;NAG MUNDARI LETTER UD;Lo;0;L;;;;;N;;;;; +1E4E2;NAG MUNDARI LETTER UK;Lo;0;L;;;;;N;;;;; +1E4E3;NAG MUNDARI LETTER UR;Lo;0;L;;;;;N;;;;; +1E4E4;NAG MUNDARI LETTER E;Lo;0;L;;;;;N;;;;; +1E4E5;NAG MUNDARI LETTER ENN;Lo;0;L;;;;;N;;;;; +1E4E6;NAG MUNDARI LETTER EG;Lo;0;L;;;;;N;;;;; +1E4E7;NAG MUNDARI LETTER EM;Lo;0;L;;;;;N;;;;; +1E4E8;NAG MUNDARI LETTER EN;Lo;0;L;;;;;N;;;;; +1E4E9;NAG MUNDARI LETTER ETT;Lo;0;L;;;;;N;;;;; +1E4EA;NAG MUNDARI LETTER ELL;Lo;0;L;;;;;N;;;;; +1E4EB;NAG MUNDARI SIGN OJOD;Lm;0;L;;;;;N;;;;; +1E4EC;NAG MUNDARI SIGN MUHOR;Mn;232;NSM;;;;;N;;;;; +1E4ED;NAG MUNDARI SIGN TOYOR;Mn;232;NSM;;;;;N;;;;; +1E4EE;NAG MUNDARI SIGN IKIR;Mn;220;NSM;;;;;N;;;;; +1E4EF;NAG MUNDARI SIGN SUTUH;Mn;230;NSM;;;;;N;;;;; +1E4F0;NAG MUNDARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1E4F1;NAG MUNDARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1E4F2;NAG MUNDARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1E4F3;NAG MUNDARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1E4F4;NAG MUNDARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1E4F5;NAG MUNDARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1E4F6;NAG MUNDARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1E4F7;NAG MUNDARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1E4F8;NAG MUNDARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1E4F9;NAG MUNDARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;; +1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;; +1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;; +1E7E3;ETHIOPIC SYLLABLE HHYAA;Lo;0;L;;;;;N;;;;; +1E7E4;ETHIOPIC SYLLABLE HHYEE;Lo;0;L;;;;;N;;;;; +1E7E5;ETHIOPIC SYLLABLE HHYE;Lo;0;L;;;;;N;;;;; +1E7E6;ETHIOPIC SYLLABLE HHYO;Lo;0;L;;;;;N;;;;; +1E7E8;ETHIOPIC SYLLABLE GURAGE HHWA;Lo;0;L;;;;;N;;;;; +1E7E9;ETHIOPIC SYLLABLE HHWI;Lo;0;L;;;;;N;;;;; +1E7EA;ETHIOPIC SYLLABLE HHWEE;Lo;0;L;;;;;N;;;;; +1E7EB;ETHIOPIC SYLLABLE HHWE;Lo;0;L;;;;;N;;;;; +1E7ED;ETHIOPIC SYLLABLE GURAGE MWI;Lo;0;L;;;;;N;;;;; +1E7EE;ETHIOPIC SYLLABLE GURAGE MWEE;Lo;0;L;;;;;N;;;;; +1E7F0;ETHIOPIC SYLLABLE GURAGE QWI;Lo;0;L;;;;;N;;;;; +1E7F1;ETHIOPIC SYLLABLE GURAGE QWEE;Lo;0;L;;;;;N;;;;; +1E7F2;ETHIOPIC SYLLABLE GURAGE QWE;Lo;0;L;;;;;N;;;;; +1E7F3;ETHIOPIC SYLLABLE GURAGE BWI;Lo;0;L;;;;;N;;;;; +1E7F4;ETHIOPIC SYLLABLE GURAGE BWEE;Lo;0;L;;;;;N;;;;; +1E7F5;ETHIOPIC SYLLABLE GURAGE KWI;Lo;0;L;;;;;N;;;;; +1E7F6;ETHIOPIC SYLLABLE GURAGE KWEE;Lo;0;L;;;;;N;;;;; +1E7F7;ETHIOPIC SYLLABLE GURAGE KWE;Lo;0;L;;;;;N;;;;; +1E7F8;ETHIOPIC SYLLABLE GURAGE GWI;Lo;0;L;;;;;N;;;;; +1E7F9;ETHIOPIC SYLLABLE GURAGE GWEE;Lo;0;L;;;;;N;;;;; +1E7FA;ETHIOPIC SYLLABLE GURAGE GWE;Lo;0;L;;;;;N;;;;; +1E7FB;ETHIOPIC SYLLABLE GURAGE FWI;Lo;0;L;;;;;N;;;;; +1E7FC;ETHIOPIC SYLLABLE GURAGE FWEE;Lo;0;L;;;;;N;;;;; +1E7FD;ETHIOPIC SYLLABLE GURAGE PWI;Lo;0;L;;;;;N;;;;; +1E7FE;ETHIOPIC SYLLABLE GURAGE PWEE;Lo;0;L;;;;;N;;;;; 1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; 1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; 1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; @@ -31886,6 +32945,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;; 1F6D6;HUT;So;0;ON;;;;;N;;;;; 1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;; +1F6DC;WIRELESS;So;0;ON;;;;;N;;;;; +1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;; +1F6DE;WHEEL;So;0;ON;;;;;N;;;;; +1F6DF;RING BUOY;So;0;ON;;;;;N;;;;; 1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; 1F6E1;SHIELD;So;0;ON;;;;;N;;;;; 1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; @@ -32028,6 +33091,14 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;; 1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;; 1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;; +1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;; +1F775;OCCULTATION;So;0;ON;;;;;N;;;;; +1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;; +1F77B;HAUMEA;So;0;ON;;;;;N;;;;; +1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;; +1F77D;GONGGONG;So;0;ON;;;;;N;;;;; +1F77E;QUAOAR;So;0;ON;;;;;N;;;;; +1F77F;ORCUS;So;0;ON;;;;;N;;;;; 1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; 1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; 1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; @@ -32117,6 +33188,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;; 1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;; 1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;; +1F7D9;NINE POINTED WHITE STAR;So;0;ON;;;;;N;;;;; 1F7E0;LARGE ORANGE CIRCLE;So;0;ON;;;;;N;;;;; 1F7E1;LARGE YELLOW CIRCLE;So;0;ON;;;;;N;;;;; 1F7E2;LARGE GREEN CIRCLE;So;0;ON;;;;;N;;;;; @@ -32129,6 +33201,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F7E9;LARGE GREEN SQUARE;So;0;ON;;;;;N;;;;; 1F7EA;LARGE PURPLE SQUARE;So;0;ON;;;;;N;;;;; 1F7EB;LARGE BROWN SQUARE;So;0;ON;;;;;N;;;;; +1F7F0;HEAVY EQUALS SIGN;So;0;ON;;;;;N;;;;; 1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; 1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; 1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;; @@ -32400,6 +33473,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F976;FREEZING FACE;So;0;ON;;;;;N;;;;; 1F977;NINJA;So;0;ON;;;;;N;;;;; 1F978;DISGUISED FACE;So;0;ON;;;;;N;;;;; +1F979;FACE HOLDING BACK TEARS;So;0;ON;;;;;N;;;;; 1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;; 1F97B;SARI;So;0;ON;;;;;N;;;;; 1F97C;LAB COAT;So;0;ON;;;;;N;;;;; @@ -32482,6 +33556,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F9C9;MATE DRINK;So;0;ON;;;;;N;;;;; 1F9CA;ICE CUBE;So;0;ON;;;;;N;;;;; 1F9CB;BUBBLE TEA;So;0;ON;;;;;N;;;;; +1F9CC;TROLL;So;0;ON;;;;;N;;;;; 1F9CD;STANDING PERSON;So;0;ON;;;;;N;;;;; 1F9CE;KNEELING PERSON;So;0;ON;;;;;N;;;;; 1F9CF;DEAF PERSON;So;0;ON;;;;;N;;;;; @@ -32636,9 +33711,14 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FA72;BRIEFS;So;0;ON;;;;;N;;;;; 1FA73;SHORTS;So;0;ON;;;;;N;;;;; 1FA74;THONG SANDAL;So;0;ON;;;;;N;;;;; +1FA75;LIGHT BLUE HEART;So;0;ON;;;;;N;;;;; +1FA76;GREY HEART;So;0;ON;;;;;N;;;;; +1FA77;PINK HEART;So;0;ON;;;;;N;;;;; 1FA78;DROP OF BLOOD;So;0;ON;;;;;N;;;;; 1FA79;ADHESIVE BANDAGE;So;0;ON;;;;;N;;;;; 1FA7A;STETHOSCOPE;So;0;ON;;;;;N;;;;; +1FA7B;X-RAY;So;0;ON;;;;;N;;;;; +1FA7C;CRUTCH;So;0;ON;;;;;N;;;;; 1FA80;YO-YO;So;0;ON;;;;;N;;;;; 1FA81;KITE;So;0;ON;;;;;N;;;;; 1FA82;PARACHUTE;So;0;ON;;;;;N;;;;; @@ -32646,6 +33726,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FA84;MAGIC WAND;So;0;ON;;;;;N;;;;; 1FA85;PINATA;So;0;ON;;;;;N;;;;; 1FA86;NESTING DOLLS;So;0;ON;;;;;N;;;;; +1FA87;MARACAS;So;0;ON;;;;;N;;;;; +1FA88;FLUTE;So;0;ON;;;;;N;;;;; 1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;; 1FA91;CHAIR;So;0;ON;;;;;N;;;;; 1FA92;RAZOR;So;0;ON;;;;;N;;;;; @@ -32671,6 +33753,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FAA6;HEADSTONE;So;0;ON;;;;;N;;;;; 1FAA7;PLACARD;So;0;ON;;;;;N;;;;; 1FAA8;ROCK;So;0;ON;;;;;N;;;;; +1FAA9;MIRROR BALL;So;0;ON;;;;;N;;;;; +1FAAA;IDENTIFICATION CARD;So;0;ON;;;;;N;;;;; +1FAAB;LOW BATTERY;So;0;ON;;;;;N;;;;; +1FAAC;HAMSA;So;0;ON;;;;;N;;;;; +1FAAD;FOLDING HAND FAN;So;0;ON;;;;;N;;;;; +1FAAE;HAIR PICK;So;0;ON;;;;;N;;;;; +1FAAF;KHANDA;So;0;ON;;;;;N;;;;; 1FAB0;FLY;So;0;ON;;;;;N;;;;; 1FAB1;WORM;So;0;ON;;;;;N;;;;; 1FAB2;BEETLE;So;0;ON;;;;;N;;;;; @@ -32678,9 +33767,22 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FAB4;POTTED PLANT;So;0;ON;;;;;N;;;;; 1FAB5;WOOD;So;0;ON;;;;;N;;;;; 1FAB6;FEATHER;So;0;ON;;;;;N;;;;; +1FAB7;LOTUS;So;0;ON;;;;;N;;;;; +1FAB8;CORAL;So;0;ON;;;;;N;;;;; +1FAB9;EMPTY NEST;So;0;ON;;;;;N;;;;; +1FABA;NEST WITH EGGS;So;0;ON;;;;;N;;;;; +1FABB;HYACINTH;So;0;ON;;;;;N;;;;; +1FABC;JELLYFISH;So;0;ON;;;;;N;;;;; +1FABD;WING;So;0;ON;;;;;N;;;;; +1FABF;GOOSE;So;0;ON;;;;;N;;;;; 1FAC0;ANATOMICAL HEART;So;0;ON;;;;;N;;;;; 1FAC1;LUNGS;So;0;ON;;;;;N;;;;; 1FAC2;PEOPLE HUGGING;So;0;ON;;;;;N;;;;; +1FAC3;PREGNANT MAN;So;0;ON;;;;;N;;;;; +1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;; +1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;; +1FACE;MOOSE;So;0;ON;;;;;N;;;;; +1FACF;DONKEY;So;0;ON;;;;;N;;;;; 1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;; 1FAD1;BELL PEPPER;So;0;ON;;;;;N;;;;; 1FAD2;OLIVE;So;0;ON;;;;;N;;;;; @@ -32688,6 +33790,29 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FAD4;TAMALE;So;0;ON;;;;;N;;;;; 1FAD5;FONDUE;So;0;ON;;;;;N;;;;; 1FAD6;TEAPOT;So;0;ON;;;;;N;;;;; +1FAD7;POURING LIQUID;So;0;ON;;;;;N;;;;; +1FAD8;BEANS;So;0;ON;;;;;N;;;;; +1FAD9;JAR;So;0;ON;;;;;N;;;;; +1FADA;GINGER ROOT;So;0;ON;;;;;N;;;;; +1FADB;PEA POD;So;0;ON;;;;;N;;;;; +1FAE0;MELTING FACE;So;0;ON;;;;;N;;;;; +1FAE1;SALUTING FACE;So;0;ON;;;;;N;;;;; +1FAE2;FACE WITH OPEN EYES AND HAND OVER MOUTH;So;0;ON;;;;;N;;;;; +1FAE3;FACE WITH PEEKING EYE;So;0;ON;;;;;N;;;;; +1FAE4;FACE WITH DIAGONAL MOUTH;So;0;ON;;;;;N;;;;; +1FAE5;DOTTED LINE FACE;So;0;ON;;;;;N;;;;; +1FAE6;BITING LIP;So;0;ON;;;;;N;;;;; +1FAE7;BUBBLES;So;0;ON;;;;;N;;;;; +1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;; +1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;; +1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;; +1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;; +1FAF3;PALM DOWN HAND;So;0;ON;;;;;N;;;;; +1FAF4;PALM UP HAND;So;0;ON;;;;;N;;;;; +1FAF5;INDEX POINTING AT THE VIEWER;So;0;ON;;;;;N;;;;; +1FAF6;HEART HANDS;So;0;ON;;;;;N;;;;; +1FAF7;LEFTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; +1FAF8;RIGHTWARDS PUSHING HAND;So;0;ON;;;;;N;;;;; 1FB00;BLOCK SEXTANT-1;So;0;ON;;;;;N;;;;; 1FB01;BLOCK SEXTANT-2;So;0;ON;;;;;N;;;;; 1FB02;BLOCK SEXTANT-12;So;0;ON;;;;;N;;;;; @@ -32901,9 +34026,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; 1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; -2A6DD;;Lo;0;L;;;;;N;;;;; +2A6DF;;Lo;0;L;;;;;N;;;;; 2A700;;Lo;0;L;;;;;N;;;;; -2B734;;Lo;0;L;;;;;N;;;;; +2B739;;Lo;0;L;;;;;N;;;;; 2B740;;Lo;0;L;;;;;N;;;;; 2B81D;;Lo;0;L;;;;;N;;;;; 2B820;;Lo;0;L;;;;;N;;;;; @@ -33454,6 +34579,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; 30000;;Lo;0;L;;;;;N;;;;; 3134A;;Lo;0;L;;;;;N;;;;; +31350;;Lo;0;L;;;;;N;;;;; +323AF;;Lo;0;L;;;;;N;;;;; E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; diff --git a/lib/stdlib/uc_spec/emoji-data.txt b/lib/stdlib/uc_spec/emoji-data.txt index 5d7dc1b15619..999a43677993 100644 --- a/lib/stdlib/uc_spec/emoji-data.txt +++ b/lib/stdlib/uc_spec/emoji-data.txt @@ -1,13 +1,13 @@ # emoji-data.txt -# Date: 2020-01-28, 20:52:38 GMT -# © 2020 Unicode®, Inc. +# Date: 2022-08-02, 00:26:10 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Emoji Data for UTS #51 -# Version: 13.0 +# Used with Emoji Version 15.0 and subsequent minor revisions (if any) # -# For documentation and usage, see http://www.unicode.org/reports/tr51 +# For documentation and usage, see https://www.unicode.org/reports/tr51 # # Format: # ; # @@ -19,10 +19,9 @@ # ================================================ -# All omitted code points have Emoji=No -# @missing: 0000..10FFFF ; Emoji ; No +# All omitted code points have Emoji=No -0023 ; Emoji # E0.0 [1] (#️) number sign +0023 ; Emoji # E0.0 [1] (#️) hash sign 002A ; Emoji # E0.0 [1] (*️) asterisk 0030..0039 ; Emoji # E0.0 [10] (0️..9️) digit zero..digit nine 00A9 ; Emoji # E0.6 [1] (©️) copyright @@ -119,8 +118,8 @@ 2747 ; Emoji # E0.6 [1] (❇️) sparkle 274C ; Emoji # E0.6 [1] (❌) cross mark 274E ; Emoji # E0.6 [1] (❎) cross mark button -2753..2755 ; Emoji # E0.6 [3] (❓..❕) question mark..white exclamation mark -2757 ; Emoji # E0.6 [1] (❗) exclamation mark +2753..2755 ; Emoji # E0.6 [3] (❓..❕) red question mark..white exclamation mark +2757 ; Emoji # E0.6 [1] (❗) red exclamation mark 2763 ; Emoji # E1.0 [1] (❣️) heart exclamation 2764 ; Emoji # E0.6 [1] (❤️) red heart 2795..2797 ; Emoji # E0.6 [3] (➕..➗) plus..divide @@ -239,7 +238,7 @@ 1F509 ; Emoji # E1.0 [1] (🔉) speaker medium volume 1F50A..1F514 ; Emoji # E0.6 [11] (🔊..🔔) speaker high volume..bell 1F515 ; Emoji # E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Emoji # E0.6 [22] (🔖..🔫) bookmark..pistol +1F516..1F52B ; Emoji # E0.6 [22] (🔖..🔫) bookmark..water pistol 1F52C..1F52D ; Emoji # E1.0 [2] (🔬..🔭) microscope..telescope 1F52E..1F53D ; Emoji # E0.6 [16] (🔮..🔽) crystal ball..downwards button 1F549..1F54A ; Emoji # E0.7 [2] (🕉️..🕊️) om..dove @@ -294,7 +293,7 @@ 1F62E..1F62F ; Emoji # E1.0 [2] (😮..😯) face with open mouth..hushed face 1F630..1F633 ; Emoji # E0.6 [4] (😰..😳) anxious face with sweat..flushed face 1F634 ; Emoji # E1.0 [1] (😴) sleeping face -1F635 ; Emoji # E0.6 [1] (😵) dizzy face +1F635 ; Emoji # E0.6 [1] (😵) face with crossed-out eyes 1F636 ; Emoji # E1.0 [1] (😶) face without mouth 1F637..1F640 ; Emoji # E0.6 [10] (😷..🙀) face with medical mask..weary cat 1F641..1F644 ; Emoji # E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes @@ -341,6 +340,8 @@ 1F6D1..1F6D2 ; Emoji # E3.0 [2] (🛑..🛒) stop sign..shopping cart 1F6D5 ; Emoji # E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Emoji # E13.0 [2] (🛖..🛗) hut..elevator +1F6DC ; Emoji # E15.0 [1] (🛜) wireless +1F6DD..1F6DF ; Emoji # E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6E0..1F6E5 ; Emoji # E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat 1F6E9 ; Emoji # E0.7 [1] (🛩️) small airplane 1F6EB..1F6EC ; Emoji # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival @@ -352,6 +353,7 @@ 1F6FA ; Emoji # E12.0 [1] (🛺) auto rickshaw 1F6FB..1F6FC ; Emoji # E13.0 [2] (🛻..🛼) pickup truck..roller skate 1F7E0..1F7EB ; Emoji # E12.0 [12] (🟠..🟫) orange circle..brown square +1F7F0 ; Emoji # E14.0 [1] (🟰) heavy equals sign 1F90C ; Emoji # E13.0 [1] (🤌) pinched fingers 1F90D..1F90F ; Emoji # E12.0 [3] (🤍..🤏) white heart..pinching hand 1F910..1F918 ; Emoji # E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns @@ -375,6 +377,7 @@ 1F972 ; Emoji # E13.0 [1] (🥲) smiling face with tear 1F973..1F976 ; Emoji # E11.0 [4] (🥳..🥶) partying face..cold face 1F977..1F978 ; Emoji # E13.0 [2] (🥷..🥸) ninja..disguised face +1F979 ; Emoji # E14.0 [1] (🥹) face holding back tears 1F97A ; Emoji # E11.0 [1] (🥺) pleading face 1F97B ; Emoji # E12.0 [1] (🥻) sari 1F97C..1F97F ; Emoji # E11.0 [4] (🥼..🥿) lab coat..flat shoe @@ -392,26 +395,42 @@ 1F9C1..1F9C2 ; Emoji # E11.0 [2] (🧁..🧂) cupcake..salt 1F9C3..1F9CA ; Emoji # E12.0 [8] (🧃..🧊) beverage box..ice 1F9CB ; Emoji # E13.0 [1] (🧋) bubble tea +1F9CC ; Emoji # E14.0 [1] (🧌) troll 1F9CD..1F9CF ; Emoji # E12.0 [3] (🧍..🧏) person standing..deaf person 1F9D0..1F9E6 ; Emoji # E5.0 [23] (🧐..🧦) face with monocle..socks 1F9E7..1F9FF ; Emoji # E11.0 [25] (🧧..🧿) red envelope..nazar amulet 1FA70..1FA73 ; Emoji # E12.0 [4] (🩰..🩳) ballet shoes..shorts 1FA74 ; Emoji # E13.0 [1] (🩴) thong sandal +1FA75..1FA77 ; Emoji # E15.0 [3] (🩵..🩷) light blue heart..pink heart 1FA78..1FA7A ; Emoji # E12.0 [3] (🩸..🩺) drop of blood..stethoscope +1FA7B..1FA7C ; Emoji # E14.0 [2] (🩻..🩼) x-ray..crutch 1FA80..1FA82 ; Emoji # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls +1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute 1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock +1FAA9..1FAAC ; Emoji # E14.0 [4] (🪩..🪬) mirror ball..hamsa +1FAAD..1FAAF ; Emoji # E15.0 [3] (🪭..🪯) folding hand fan..khanda 1FAB0..1FAB6 ; Emoji # E13.0 [7] (🪰..🪶) fly..feather +1FAB7..1FABA ; Emoji # E14.0 [4] (🪷..🪺) lotus..nest with eggs +1FABB..1FABD ; Emoji # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABF ; Emoji # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging +1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot +1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar +1FADA..1FADB ; Emoji # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles +1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face +1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands +1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1367 +# Total elements: 1424 # ================================================ -# All omitted code points have Emoji_Presentation=No -# @missing: 0000..10FFFF ; Emoji_Presentation ; No +# All omitted code points have Emoji_Presentation=No 231A..231B ; Emoji_Presentation # E0.6 [2] (⌚..⌛) watch..hourglass done 23E9..23EC ; Emoji_Presentation # E0.6 [4] (⏩..⏬) fast-forward button..fast down button @@ -438,8 +457,8 @@ 2728 ; Emoji_Presentation # E0.6 [1] (✨) sparkles 274C ; Emoji_Presentation # E0.6 [1] (❌) cross mark 274E ; Emoji_Presentation # E0.6 [1] (❎) cross mark button -2753..2755 ; Emoji_Presentation # E0.6 [3] (❓..❕) question mark..white exclamation mark -2757 ; Emoji_Presentation # E0.6 [1] (❗) exclamation mark +2753..2755 ; Emoji_Presentation # E0.6 [3] (❓..❕) red question mark..white exclamation mark +2757 ; Emoji_Presentation # E0.6 [1] (❗) red exclamation mark 2795..2797 ; Emoji_Presentation # E0.6 [3] (➕..➗) plus..divide 27B0 ; Emoji_Presentation # E0.6 [1] (➰) curly loop 27BF ; Emoji_Presentation # E1.0 [1] (➿) double curly loop @@ -533,7 +552,7 @@ 1F509 ; Emoji_Presentation # E1.0 [1] (🔉) speaker medium volume 1F50A..1F514 ; Emoji_Presentation # E0.6 [11] (🔊..🔔) speaker high volume..bell 1F515 ; Emoji_Presentation # E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Emoji_Presentation # E0.6 [22] (🔖..🔫) bookmark..pistol +1F516..1F52B ; Emoji_Presentation # E0.6 [22] (🔖..🔫) bookmark..water pistol 1F52C..1F52D ; Emoji_Presentation # E1.0 [2] (🔬..🔭) microscope..telescope 1F52E..1F53D ; Emoji_Presentation # E0.6 [16] (🔮..🔽) crystal ball..downwards button 1F54B..1F54E ; Emoji_Presentation # E1.0 [4] (🕋..🕎) kaaba..menorah @@ -569,7 +588,7 @@ 1F62E..1F62F ; Emoji_Presentation # E1.0 [2] (😮..😯) face with open mouth..hushed face 1F630..1F633 ; Emoji_Presentation # E0.6 [4] (😰..😳) anxious face with sweat..flushed face 1F634 ; Emoji_Presentation # E1.0 [1] (😴) sleeping face -1F635 ; Emoji_Presentation # E0.6 [1] (😵) dizzy face +1F635 ; Emoji_Presentation # E0.6 [1] (😵) face with crossed-out eyes 1F636 ; Emoji_Presentation # E1.0 [1] (😶) face without mouth 1F637..1F640 ; Emoji_Presentation # E0.6 [10] (😷..🙀) face with medical mask..weary cat 1F641..1F644 ; Emoji_Presentation # E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes @@ -614,6 +633,8 @@ 1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (🛑..🛒) stop sign..shopping cart 1F6D5 ; Emoji_Presentation # E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (🛖..🛗) hut..elevator +1F6DC ; Emoji_Presentation # E15.0 [1] (🛜) wireless +1F6DD..1F6DF ; Emoji_Presentation # E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival 1F6F4..1F6F6 ; Emoji_Presentation # E3.0 [3] (🛴..🛶) kick scooter..canoe 1F6F7..1F6F8 ; Emoji_Presentation # E5.0 [2] (🛷..🛸) sled..flying saucer @@ -621,6 +642,7 @@ 1F6FA ; Emoji_Presentation # E12.0 [1] (🛺) auto rickshaw 1F6FB..1F6FC ; Emoji_Presentation # E13.0 [2] (🛻..🛼) pickup truck..roller skate 1F7E0..1F7EB ; Emoji_Presentation # E12.0 [12] (🟠..🟫) orange circle..brown square +1F7F0 ; Emoji_Presentation # E14.0 [1] (🟰) heavy equals sign 1F90C ; Emoji_Presentation # E13.0 [1] (🤌) pinched fingers 1F90D..1F90F ; Emoji_Presentation # E12.0 [3] (🤍..🤏) white heart..pinching hand 1F910..1F918 ; Emoji_Presentation # E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns @@ -644,6 +666,7 @@ 1F972 ; Emoji_Presentation # E13.0 [1] (🥲) smiling face with tear 1F973..1F976 ; Emoji_Presentation # E11.0 [4] (🥳..🥶) partying face..cold face 1F977..1F978 ; Emoji_Presentation # E13.0 [2] (🥷..🥸) ninja..disguised face +1F979 ; Emoji_Presentation # E14.0 [1] (🥹) face holding back tears 1F97A ; Emoji_Presentation # E11.0 [1] (🥺) pleading face 1F97B ; Emoji_Presentation # E12.0 [1] (🥻) sari 1F97C..1F97F ; Emoji_Presentation # E11.0 [4] (🥼..🥿) lab coat..flat shoe @@ -661,26 +684,42 @@ 1F9C1..1F9C2 ; Emoji_Presentation # E11.0 [2] (🧁..🧂) cupcake..salt 1F9C3..1F9CA ; Emoji_Presentation # E12.0 [8] (🧃..🧊) beverage box..ice 1F9CB ; Emoji_Presentation # E13.0 [1] (🧋) bubble tea +1F9CC ; Emoji_Presentation # E14.0 [1] (🧌) troll 1F9CD..1F9CF ; Emoji_Presentation # E12.0 [3] (🧍..🧏) person standing..deaf person 1F9D0..1F9E6 ; Emoji_Presentation # E5.0 [23] (🧐..🧦) face with monocle..socks 1F9E7..1F9FF ; Emoji_Presentation # E11.0 [25] (🧧..🧿) red envelope..nazar amulet 1FA70..1FA73 ; Emoji_Presentation # E12.0 [4] (🩰..🩳) ballet shoes..shorts 1FA74 ; Emoji_Presentation # E13.0 [1] (🩴) thong sandal +1FA75..1FA77 ; Emoji_Presentation # E15.0 [3] (🩵..🩷) light blue heart..pink heart 1FA78..1FA7A ; Emoji_Presentation # E12.0 [3] (🩸..🩺) drop of blood..stethoscope +1FA7B..1FA7C ; Emoji_Presentation # E14.0 [2] (🩻..🩼) x-ray..crutch 1FA80..1FA82 ; Emoji_Presentation # E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls +1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute 1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock +1FAA9..1FAAC ; Emoji_Presentation # E14.0 [4] (🪩..🪬) mirror ball..hamsa +1FAAD..1FAAF ; Emoji_Presentation # E15.0 [3] (🪭..🪯) folding hand fan..khanda 1FAB0..1FAB6 ; Emoji_Presentation # E13.0 [7] (🪰..🪶) fly..feather +1FAB7..1FABA ; Emoji_Presentation # E14.0 [4] (🪷..🪺) lotus..nest with eggs +1FABB..1FABD ; Emoji_Presentation # E15.0 [3] (🪻..🪽) hyacinth..wing +1FABF ; Emoji_Presentation # E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging +1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot +1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar +1FADA..1FADB ; Emoji_Presentation # E15.0 [2] (🫚..🫛) ginger root..pea pod +1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles +1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face +1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands +1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 1148 +# Total elements: 1205 # ================================================ -# All omitted code points have Emoji_Modifier=No -# @missing: 0000..10FFFF ; Emoji_Modifier ; No +# All omitted code points have Emoji_Modifier=No 1F3FB..1F3FF ; Emoji_Modifier # E1.0 [5] (🏻..🏿) light skin tone..dark skin tone @@ -688,8 +727,7 @@ # ================================================ -# All omitted code points have Emoji_Modifier_Base=No -# @missing: 0000..10FFFF ; Emoji_Modifier_Base ; No +# All omitted code points have Emoji_Modifier_Base=No 261D ; Emoji_Modifier_Base # E0.6 [1] (☝️) index pointing up 26F9 ; Emoji_Modifier_Base # E0.7 [1] (⛹️) person bouncing ball @@ -738,15 +776,17 @@ 1F9BB ; Emoji_Modifier_Base # E12.0 [1] (🦻) ear with hearing aid 1F9CD..1F9CF ; Emoji_Modifier_Base # E12.0 [3] (🧍..🧏) person standing..deaf person 1F9D1..1F9DD ; Emoji_Modifier_Base # E5.0 [13] (🧑..🧝) person..elf +1FAC3..1FAC5 ; Emoji_Modifier_Base # E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAF0..1FAF6 ; Emoji_Modifier_Base # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands +1FAF7..1FAF8 ; Emoji_Modifier_Base # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand -# Total elements: 122 +# Total elements: 134 # ================================================ -# All omitted code points have Emoji_Component=No -# @missing: 0000..10FFFF ; Emoji_Component ; No +# All omitted code points have Emoji_Component=No -0023 ; Emoji_Component # E0.0 [1] (#️) number sign +0023 ; Emoji_Component # E0.0 [1] (#️) hash sign 002A ; Emoji_Component # E0.0 [1] (*️) asterisk 0030..0039 ; Emoji_Component # E0.0 [10] (0️..9️) digit zero..digit nine 200D ; Emoji_Component # E0.0 [1] (‍) zero width joiner @@ -761,8 +801,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c # ================================================ -# All omitted code points have Extended_Pictographic=No -# @missing: 0000..10FFFF ; Extended_Pictographic ; No +# All omitted code points have Extended_Pictographic=No 00A9 ; Extended_Pictographic# E0.6 [1] (©️) copyright 00AE ; Extended_Pictographic# E0.6 [1] (®️) registered @@ -902,8 +941,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 2747 ; Extended_Pictographic# E0.6 [1] (❇️) sparkle 274C ; Extended_Pictographic# E0.6 [1] (❌) cross mark 274E ; Extended_Pictographic# E0.6 [1] (❎) cross mark button -2753..2755 ; Extended_Pictographic# E0.6 [3] (❓..❕) question mark..white exclamation mark -2757 ; Extended_Pictographic# E0.6 [1] (❗) exclamation mark +2753..2755 ; Extended_Pictographic# E0.6 [3] (❓..❕) red question mark..white exclamation mark +2757 ; Extended_Pictographic# E0.6 [1] (❗) red exclamation mark 2763 ; Extended_Pictographic# E1.0 [1] (❣️) heart exclamation 2764 ; Extended_Pictographic# E0.6 [1] (❤️) red heart 2765..2767 ; Extended_Pictographic# E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET @@ -1041,7 +1080,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F509 ; Extended_Pictographic# E1.0 [1] (🔉) speaker medium volume 1F50A..1F514 ; Extended_Pictographic# E0.6 [11] (🔊..🔔) speaker high volume..bell 1F515 ; Extended_Pictographic# E1.0 [1] (🔕) bell with slash -1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..pistol +1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..water pistol 1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (🔬..🔭) microscope..telescope 1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (🔮..🔽) crystal ball..downwards button 1F546..1F548 ; Extended_Pictographic# E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS @@ -1117,7 +1156,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F62E..1F62F ; Extended_Pictographic# E1.0 [2] (😮..😯) face with open mouth..hushed face 1F630..1F633 ; Extended_Pictographic# E0.6 [4] (😰..😳) anxious face with sweat..flushed face 1F634 ; Extended_Pictographic# E1.0 [1] (😴) sleeping face -1F635 ; Extended_Pictographic# E0.6 [1] (😵) dizzy face +1F635 ; Extended_Pictographic# E0.6 [1] (😵) face with crossed-out eyes 1F636 ; Extended_Pictographic# E1.0 [1] (😶) face without mouth 1F637..1F640 ; Extended_Pictographic# E0.6 [10] (😷..🙀) face with medical mask..weary cat 1F641..1F644 ; Extended_Pictographic# E1.0 [4] (🙁..🙄) slightly frowning face..face with rolling eyes @@ -1166,7 +1205,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (🛓..🛔) STUPA..PAGODA 1F6D5 ; Extended_Pictographic# E12.0 [1] (🛕) hindu temple 1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (🛖..🛗) hut..elevator -1F6D8..1F6DF ; Extended_Pictographic# E0.0 [8] (🛘..🛟) .. +1F6D8..1F6DB ; Extended_Pictographic# E0.0 [4] (🛘..🛛) .. +1F6DC ; Extended_Pictographic# E15.0 [1] (🛜) wireless +1F6DD..1F6DF ; Extended_Pictographic# E14.0 [3] (🛝..🛟) playground slide..ring buoy 1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat 1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE 1F6E9 ; Extended_Pictographic# E0.7 [1] (🛩️) small airplane @@ -1182,10 +1223,12 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F6FA ; Extended_Pictographic# E12.0 [1] (🛺) auto rickshaw 1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (🛻..🛼) pickup truck..roller skate 1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (🛽..🛿) .. -1F774..1F77F ; Extended_Pictographic# E0.0 [12] (🝴..🝿) .. +1F774..1F77F ; Extended_Pictographic# E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS 1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (🟕..🟟) CIRCLED TRIANGLE.. 1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (🟠..🟫) orange circle..brown square -1F7EC..1F7FF ; Extended_Pictographic# E0.0 [20] (🟬..🟿) .. +1F7EC..1F7EF ; Extended_Pictographic# E0.0 [4] (🟬..🟯) .. +1F7F0 ; Extended_Pictographic# E14.0 [1] (🟰) heavy equals sign +1F7F1..1F7FF ; Extended_Pictographic# E0.0 [15] (🟱..🟿) .. 1F80C..1F80F ; Extended_Pictographic# E0.0 [4] (🠌..🠏) .. 1F848..1F84F ; Extended_Pictographic# E0.0 [8] (🡈..🡏) .. 1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (🡚..🡟) .. @@ -1214,7 +1257,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F972 ; Extended_Pictographic# E13.0 [1] (🥲) smiling face with tear 1F973..1F976 ; Extended_Pictographic# E11.0 [4] (🥳..🥶) partying face..cold face 1F977..1F978 ; Extended_Pictographic# E13.0 [2] (🥷..🥸) ninja..disguised face -1F979 ; Extended_Pictographic# E0.0 [1] (🥹) +1F979 ; Extended_Pictographic# E14.0 [1] (🥹) face holding back tears 1F97A ; Extended_Pictographic# E11.0 [1] (🥺) pleading face 1F97B ; Extended_Pictographic# E12.0 [1] (🥻) sari 1F97C..1F97F ; Extended_Pictographic# E11.0 [4] (🥼..🥿) lab coat..flat shoe @@ -1232,28 +1275,44 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (󠀠..󠁿) tag space..c 1F9C1..1F9C2 ; Extended_Pictographic# E11.0 [2] (🧁..🧂) cupcake..salt 1F9C3..1F9CA ; Extended_Pictographic# E12.0 [8] (🧃..🧊) beverage box..ice 1F9CB ; Extended_Pictographic# E13.0 [1] (🧋) bubble tea -1F9CC ; Extended_Pictographic# E0.0 [1] (🧌) +1F9CC ; Extended_Pictographic# E14.0 [1] (🧌) troll 1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (🧍..🧏) person standing..deaf person 1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (🧐..🧦) face with monocle..socks 1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (🧧..🧿) red envelope..nazar amulet 1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (🨀..🩯) NEUTRAL CHESS KING.. 1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (🩰..🩳) ballet shoes..shorts 1FA74 ; Extended_Pictographic# E13.0 [1] (🩴) thong sandal -1FA75..1FA77 ; Extended_Pictographic# E0.0 [3] (🩵..🩷) .. +1FA75..1FA77 ; Extended_Pictographic# E15.0 [3] (🩵..🩷) light blue heart..pink heart 1FA78..1FA7A ; Extended_Pictographic# E12.0 [3] (🩸..🩺) drop of blood..stethoscope -1FA7B..1FA7F ; Extended_Pictographic# E0.0 [5] (🩻..🩿) .. +1FA7B..1FA7C ; Extended_Pictographic# E14.0 [2] (🩻..🩼) x-ray..crutch +1FA7D..1FA7F ; Extended_Pictographic# E0.0 [3] (🩽..🩿) .. 1FA80..1FA82 ; Extended_Pictographic# E12.0 [3] (🪀..🪂) yo-yo..parachute 1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls -1FA87..1FA8F ; Extended_Pictographic# E0.0 [9] (🪇..🪏) .. +1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute +1FA89..1FA8F ; Extended_Pictographic# E0.0 [7] (🪉..🪏) .. 1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo 1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock -1FAA9..1FAAF ; Extended_Pictographic# E0.0 [7] (🪩..🪯) .. +1FAA9..1FAAC ; Extended_Pictographic# E14.0 [4] (🪩..🪬) mirror ball..hamsa +1FAAD..1FAAF ; Extended_Pictographic# E15.0 [3] (🪭..🪯) folding hand fan..khanda 1FAB0..1FAB6 ; Extended_Pictographic# E13.0 [7] (🪰..🪶) fly..feather -1FAB7..1FABF ; Extended_Pictographic# E0.0 [9] (🪷..🪿) .. +1FAB7..1FABA ; Extended_Pictographic# E14.0 [4] (🪷..🪺) lotus..nest with eggs +1FABB..1FABD ; Extended_Pictographic# E15.0 [3] (🪻..🪽) hyacinth..wing +1FABE ; Extended_Pictographic# E0.0 [1] (🪾) +1FABF ; Extended_Pictographic# E15.0 [1] (🪿) goose 1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging -1FAC3..1FACF ; Extended_Pictographic# E0.0 [13] (🫃..🫏) .. +1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown +1FAC6..1FACD ; Extended_Pictographic# E0.0 [8] (🫆..🫍) .. +1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey 1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot -1FAD7..1FAFF ; Extended_Pictographic# E0.0 [41] (🫗..🫿) .. +1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar +1FADA..1FADB ; Extended_Pictographic# E15.0 [2] (🫚..🫛) ginger root..pea pod +1FADC..1FADF ; Extended_Pictographic# E0.0 [4] (🫜..🫟) .. +1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles +1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face +1FAE9..1FAEF ; Extended_Pictographic# E0.0 [7] (🫩..🫯) .. +1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands +1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand +1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (🫹..🫿) .. 1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (🰀..🿽) .. # Total elements: 3537 diff --git a/lib/stdlib/uc_spec/gen_unicode_mod.escript b/lib/stdlib/uc_spec/gen_unicode_mod.escript index 8239b0d5a107..a6ac3b0e60ab 100644 --- a/lib/stdlib/uc_spec/gen_unicode_mod.escript +++ b/lib/stdlib/uc_spec/gen_unicode_mod.escript @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017-2021. All Rights Reserved. +%% Copyright Ericsson AB 2017-2022. 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. @@ -23,55 +23,69 @@ -mode(compile). --record(cp, {name, class, dec, comp, cs}). +-record(cp, {name, class, dec, comp, cs, cat}). -define(MOD, "unicode_util"). -main(_) -> +main(Args) -> %% Parse main table - {ok, UD} = file:open("../uc_spec/UnicodeData.txt", [read, raw, {read_ahead, 1000000}]), + UD = file_open("../uc_spec/UnicodeData.txt"), Data0 = foldl(fun parse_unicode_data/2, [], UD), Data1 = array:from_orddict(lists:reverse(Data0)), ok = file:close(UD), %% Special Casing table - {ok, SC} = file:open("../uc_spec/SpecialCasing.txt", [read, raw, {read_ahead, 1000000}]), + SC = file_open("../uc_spec/SpecialCasing.txt"), Data2 = foldl(fun parse_special_casing/2, Data1, SC), ok = file:close(SC), %% Casing Folding table - {ok, CF} = file:open("../uc_spec/CaseFolding.txt", [read, raw, {read_ahead, 1000000}]), + CF = file_open("../uc_spec/CaseFolding.txt"), Data = foldl(fun parse_case_folding/2, Data2, CF), ok = file:close(CF), %% Normalization - {ok, ExclF} = file:open("../uc_spec/CompositionExclusions.txt", [read, raw, {read_ahead, 1000000}]), + ExclF = file_open("../uc_spec/CompositionExclusions.txt"), ExclData = foldl(fun parse_comp_excl/2, Data, ExclF), ok = file:close(ExclF), %% GraphemeBreakProperty table - {ok, Emoji} = file:open("../uc_spec/emoji-data.txt", [read, raw, {read_ahead, 1000000}]), + Emoji = file_open("../uc_spec/emoji-data.txt"), Props00 = foldl(fun parse_properties/2, [], Emoji), %% Filter Extended_Pictographic class which we are interested in. Props0 = [EP || {extended_pictographic, _} = EP <- Props00], ok = file:close(Emoji), - {ok, GBPF} = file:open("../uc_spec/GraphemeBreakProperty.txt", [read, raw, {read_ahead, 1000000}]), + GBPF = file_open("../uc_spec/GraphemeBreakProperty.txt"), Props1 = foldl(fun parse_properties/2, Props0, GBPF), ok = file:close(GBPF), - {ok, PropF} = file:open("../uc_spec/PropList.txt", [read, raw, {read_ahead, 1000000}]), + PropF = file_open("../uc_spec/PropList.txt"), Props2 = foldl(fun parse_properties/2, Props1, PropF), ok = file:close(PropF), Props = sofs:to_external(sofs:relation_to_family(sofs:relation(Props2))), + WidthF = file_open("../uc_spec/EastAsianWidth.txt"), + WideCs = foldl(fun parse_widths/2, [], WidthF), + ok = file:close(WidthF), + %% Make module + UpdateTests = case Args of + ["update_tests"] -> true; + _ -> false + end, + {ok, Out} = file:open(?MOD++".erl", [write]), - gen_file(Out, Data, ExclData, maps:from_list(Props)), + gen_file(Out, Data, ExclData, maps:from_list(Props), WideCs, UpdateTests), ok = file:close(Out), ok. +file_open(File) -> + {ok, Fd} = file:open(File, [read, raw, {read_ahead, 1000000}]), + Fd. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% parse_unicode_data(Line0, Acc) -> Line = string:chomp(Line0), - [CodePoint,Name,_Cat,Class,_BiDi,Decomp, + [CodePoint,Name,Cat,Class,_BiDi,Decomp, _N1,_N2,_N3,_BDMirror,_Uni1,_Iso|Case] = tokens(Line, ";"), {Dec,Comp} = case to_decomp(Decomp) of {_, _} = Compabil -> {[], Compabil}; @@ -79,7 +93,7 @@ parse_unicode_data(Line0, Acc) -> end, [{hex_to_int(CodePoint), #cp{name=list_to_binary(Name),class=to_class(Class), - dec=Dec, comp=Comp, cs=to_case(Case)}} + dec=Dec, comp=Comp, cs=to_case(Case), cat=Cat}} |Acc]. to_class(String) -> @@ -152,7 +166,62 @@ parse_properties(Line0, Acc) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_file(Fd, Data, ExclData, Props) -> +%% Pick ranges that are wide when seen from a non East Asian context, +%% That way we can minimize the data, every other code point is considered narrow. +%% We loose information but hopefully keep the important width for a standard +%% terminal. +parse_widths(Line0, Acc) -> + [{WidthClass, {From, _To}=Range}] = parse_properties(Line0, []), + case is_default_width(From, WidthClass) of + {true, narrow} -> + Acc; + {false, narrow} -> + [Range|Acc]; + {true, RuleRange} -> + [RuleRange|Acc] +%%% {false, rule_execption} -> i.e. narrow codepoint in wide range +%%% Should not happen in current specs + end. + +is_default_width(Index, WD) -> + if + 16#3400 =< Index, Index =< 16#4DBF -> + if WD =:= w orelse WD =:= f -> + {true, {16#3400, 16#4DBF}}; + true -> + {false, rule_execption} + end; + 16#4E00 =< Index, Index =< 16#9FFF -> + if WD =:= w orelse WD =:= f -> + {true, {16#4E00, 16#9FFF}}; + true -> + {false, rule_execption} + end; + 16#F900 =< Index, Index =< 16#FAFF -> + if WD =:= w orelse WD =:= f -> + {true, {16#F900, 16#FAFF}}; + true -> + {false, rule_execption} + end; + 16#20000 =< Index, Index =< 16#2FFFD -> + if WD =:= w orelse WD =:= f -> + {true, {16#20000, 16#2FFFD}}; + true -> + {false, rule_execption} + end; + 16#30000 =< Index, Index =< 16#3FFFD -> + if WD =:= w orelse WD =:= f -> + {true, {16#30000, 16#3FFFD}}; + true -> + {false, rule_execption} + end; + true -> + {WD =:= n orelse WD =:= na orelse WD == h orelse WD =:= a, narrow} + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +gen_file(Fd, Data, ExclData, Props, WideCs, UpdateTests) -> gen_header(Fd), gen_static(Fd), gen_norm(Fd), @@ -161,7 +230,8 @@ gen_file(Fd, Data, ExclData, Props) -> gen_gc(Fd, Props), gen_compose_pairs(Fd, ExclData, Data), gen_case_table(Fd, Data), - gen_unicode_table(Fd, Data), + gen_unicode_table(Fd, Data, UpdateTests), + gen_width_table(Fd, WideCs), ok. gen_header(Fd) -> @@ -173,26 +243,32 @@ gen_header(Fd) -> io:put_chars(Fd, "-export([whitespace/0, is_whitespace/1]).\n"), io:put_chars(Fd, "-export([uppercase/1, lowercase/1, titlecase/1, casefold/1]).\n\n"), io:put_chars(Fd, "-export([spec_version/0, lookup/1, get_case/1]).\n"), + io:put_chars(Fd, "-export([is_wide/1]).\n"), io:put_chars(Fd, "-compile({inline, [class/1]}).\n"), io:put_chars(Fd, "-compile(nowarn_unused_vars).\n"), io:put_chars(Fd, "-dialyzer({no_improper_lists, [cp/1, gc/1, gc_prepend/2]}).\n"), - io:put_chars(Fd, "-type gc() :: char()|[char()].\n\n\n"), + io:put_chars(Fd, "-type gc() :: char()|[char()].\n\n"), + io:put_chars(Fd, "-define(IS_CP(CP), (is_integer(CP) andalso 0 =< CP andalso CP < 16#110000)).\n\n\n"), ok. gen_static(Fd) -> io:put_chars(Fd, "-spec lookup(char()) -> #{'canon':=[{byte(),char()}], 'ccc':=byte(), " - "'compat':=[] | {atom(),[{byte(),char()}]}}.\n"), - io:put_chars(Fd, "lookup(Codepoint) ->\n" - " {CCC,Can,Comp} = unicode_table(Codepoint),\n" - " #{ccc=>CCC, canon=>Can, compat=>Comp}.\n\n"), + "'compat':=[] | {atom(),[{byte(),char()}]}, 'category':={atom(),atom()}}.\n"), + io:put_chars(Fd, "lookup(Codepoint) when ?IS_CP(Codepoint) ->\n" + " {CCC,Can,Comp,Cat} = unicode_table(Codepoint),\n" + " #{ccc=>CCC, canon=>Can, compat=>Comp, category=>category(Codepoint,Cat)}.\n\n"), + io:put_chars(Fd, "-spec get_case(char()) -> #{'fold':=gc(), 'lower':=gc(), 'title':=gc(), 'upper':=gc()}.\n"), - io:put_chars(Fd, "get_case(Codepoint) ->\n" + io:put_chars(Fd, "get_case(Codepoint) when ?IS_CP(Codepoint) ->\n" " case case_table(Codepoint) of\n" " {U,L} -> #{upper=>U,lower=>L,title=>U,fold=>L};\n" " {U,L,T,F} -> #{upper=>U,lower=>L,title=>T,fold=>F}\n" " end.\n\n"), - io:put_chars(Fd, "spec_version() -> {13,0}.\n\n\n"), - io:put_chars(Fd, "class(Codepoint) -> {CCC,_,_} = unicode_table(Codepoint),\n CCC.\n\n"), + + io:put_chars(Fd, "spec_version() -> {15,0}.\n\n\n"), + io:put_chars(Fd, "class(Codepoint) when ?IS_CP(Codepoint) -> \n" + " {CCC,_,_,_} = unicode_table(Codepoint),\n CCC.\n\n"), + io:put_chars(Fd, "-spec uppercase(unicode:chardata()) -> " "maybe_improper_list(gc(),unicode:chardata()).\n"), io:put_chars(Fd, "uppercase(Str0) ->\n"), @@ -217,6 +293,7 @@ gen_static(Fd) -> io:put_chars(Fd, " [] -> [];\n"), io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"), io:put_chars(Fd, " end.\n\n"), + io:put_chars(Fd, "-spec titlecase(unicode:chardata()) -> " "maybe_improper_list(gc(),unicode:chardata()).\n"), io:put_chars(Fd, "titlecase(Str0) ->\n"), @@ -229,6 +306,7 @@ gen_static(Fd) -> io:put_chars(Fd, " [] -> [];\n"), io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"), io:put_chars(Fd, " end.\n\n"), + io:put_chars(Fd, "-spec casefold(unicode:chardata()) -> " "maybe_improper_list(gc(),unicode:chardata()).\n"), io:put_chars(Fd, "casefold(Str0) ->\n"), @@ -242,6 +320,19 @@ gen_static(Fd) -> io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"), io:put_chars(Fd, " end.\n\n"), + io:put_chars(Fd, "%% Returns true if the character is considered wide in non east asian context.\n"), + io:put_chars(Fd, "-spec is_wide(gc()) -> boolean().\n"), + io:put_chars(Fd, "is_wide(C) when ?IS_CP(C) ->\n"), + io:put_chars(Fd, " is_wide_cp(C);\n"), + io:put_chars(Fd, "is_wide([_, 16#FE0E|Cs]) -> true; %% Presentation sequence\n"), + io:put_chars(Fd, "is_wide([_, 16#FE0F|Cs]) -> true; %% Presentation sequence\n"), + io:put_chars(Fd, "is_wide([C|Cs]) when ?IS_CP(C) ->\n"), + io:put_chars(Fd, " is_wide_cp(C) orelse is_wide(Cs);\n"), + io:put_chars(Fd, "is_wide([]) ->\n false.\n\n"), + + io:put_chars(Fd, "category(CP, lookup_category) ->\n" + " cat_translate(lookup_category(CP));\n" + "category(_, Def) -> cat_translate(Def).\n\n"), ok. gen_norm(Fd) -> @@ -249,7 +340,7 @@ gen_norm(Fd) -> "-spec nfd(unicode:chardata()) -> maybe_improper_list(gc(),unicode:chardata()) | {error, unicode:chardata()}.\n" "nfd(Str0) ->\n" " case gc(Str0) of\n" - " [GC|R] when GC < 128 -> [GC|R];\n" + " [GC|R] when is_integer(GC), 0 =< GC, GC < 128 -> [GC|R];\n" " [GC|Str] -> [decompose(GC)|Str];\n" " [] -> [];\n" " {error,_}=Error -> Error\n end.\n\n" @@ -259,7 +350,7 @@ gen_norm(Fd) -> "-spec nfkd(unicode:chardata()) -> maybe_improper_list(gc(),unicode:chardata()) | {error, unicode:chardata()}.\n" "nfkd(Str0) ->\n" " case gc(Str0) of\n" - " [GC|R] when GC < 128 -> [GC|R];\n" + " [GC|R] when is_integer(GC), 0 =< GC, GC < 128 -> [GC|R];\n" " [GC|Str] -> [decompose_compat(GC)|Str];\n" " [] -> [];\n" " {error,_}=Error -> Error\n end.\n\n" @@ -269,7 +360,7 @@ gen_norm(Fd) -> "-spec nfc(unicode:chardata()) -> maybe_improper_list(gc(),unicode:chardata()) | {error, unicode:chardata()}.\n" "nfc(Str0) ->\n" " case gc(Str0) of\n" - " [GC|R] when GC < 256 -> [GC|R];\n" + " [GC|R] when is_integer(GC), 0 =< GC, GC < 256 -> [GC|R];\n" " [GC|Str] -> [compose(decompose(GC))|Str];\n" " [] -> [];\n" " {error,_}=Error -> Error\n end.\n\n" @@ -279,7 +370,7 @@ gen_norm(Fd) -> "-spec nfkc(unicode:chardata()) -> maybe_improper_list(gc(),unicode:chardata()) | {error, unicode:chardata()}.\n" "nfkc(Str0) ->\n" " case gc(Str0) of\n" - " [GC|R] when GC < 128 -> [GC|R];\n" + " [GC|R] when is_integer(GC), 0 =< GC, GC < 128 -> [GC|R];\n" " [GC|Str] -> [compose_compat_0(decompose_compat(GC))|Str];\n" " [] -> [];\n" " {error,_}=Error -> Error\n end.\n\n" @@ -288,13 +379,13 @@ gen_norm(Fd) -> io:put_chars(Fd, "decompose(CP) when is_integer(CP), CP < 16#AC00, 16#D7A3 > CP ->\n" " case unicode_table(CP) of\n" - " {_,[],_} -> CP;\n" - " {_,CPs,_} -> canonical_order(CPs)\n" + " {_,[],_,_} -> CP;\n" + " {_,CPs,_,_} -> canonical_order(CPs)\n" " end;\n" "decompose(CP) ->\n" " canonical_order(decompose_1(CP)).\n" "\n" - "decompose_1(CP) when 16#AC00 =< CP, CP =< 16#D7A3 ->\n" + "decompose_1(CP) when is_integer(CP), 16#AC00 =< CP, CP =< 16#D7A3 ->\n" " Syll = CP-16#AC00,\n" " T = 28,\n" " N = 588,\n" @@ -306,8 +397,8 @@ gen_norm(Fd) -> " end;\n" "decompose_1(CP) when is_integer(CP) ->\n" " case unicode_table(CP) of\n" - " {CCC, [],_} -> [{CCC,CP}];\n" - " {_, CPs, _} -> CPs\n" + " {CCC, [],_,_} -> [{CCC,CP}];\n" + " {_,CPs,_,_} -> CPs\n" " end;\n" "decompose_1([CP|CPs]) ->\n" " decompose_1(CP) ++ decompose_1(CPs);\n" @@ -331,14 +422,14 @@ gen_norm(Fd) -> io:put_chars(Fd, "decompose_compat(CP) when is_integer(CP), CP < 16#AC00, 16#D7A3 > CP ->\n" " case unicode_table(CP) of\n" - " {_, [], []} -> CP;\n" - " {_, _, {_,CPs}} -> canonical_order(CPs);\n" - " {_, CPs, _} -> canonical_order(CPs)\n" + " {_, [], [], _} -> CP;\n" + " {_, _, {_,CPs}, _} -> canonical_order(CPs);\n" + " {_, CPs, _, _} -> canonical_order(CPs)\n" " end;\n" "decompose_compat(CP) ->\n" " canonical_order(decompose_compat_1(CP)).\n" "\n" - "decompose_compat_1(CP) when 16#AC00 =< CP, CP =< 16#D7A3 ->\n" + "decompose_compat_1(CP) when is_integer(CP), 16#AC00 =< CP, CP =< 16#D7A3 ->\n" " Syll = CP-16#AC00,\n" " T = 28,\n" " N = 588,\n" @@ -350,23 +441,24 @@ gen_norm(Fd) -> " end;\n" "decompose_compat_1(CP) when is_integer(CP) ->\n" " case unicode_table(CP) of\n" - " {CCC, [], []} -> [{CCC,CP}];\n" - " {_, _, {_,CPs}} -> CPs;\n" - " {_, CPs, _} -> CPs\n" + " {CCC, [], [], _} -> [{CCC,CP}];\n" + " {_, _, {_,CPs}, _} -> CPs;\n" + " {_, CPs, _, _} -> CPs\n" " end;\n" "decompose_compat_1([CP|CPs]) ->\n" " decompose_compat_1(CP) ++ decompose_compat_1(CPs);\n" - "decompose_compat_1([]) -> [].\n"), + "decompose_compat_1([]) -> [].\n\n"), io:put_chars(Fd, "compose(CP) when is_integer(CP) -> CP;\n" "compose([Lead,Vowel|Trail]) %% Hangul\n" - " when 16#1100 =< Lead, Lead =< 16#1112 ->\n" + " when is_integer(Lead), 16#1100 =< Lead, Lead =< 16#1112, is_integer(Vowel) ->\n" " if 16#1161 =< Vowel, Vowel =< 16#1175 ->\n" " CP = 16#AC00 + ((Lead - 16#1100) * 588) + ((Vowel - 16#1161) * 28),\n" " case Trail of\n" - " [T|Acc] when 16#11A7 =< T, T =< 16#11C2 -> nolist(CP+T-16#11A7,Acc);\n" + " [T|Acc] when is_integer(T), 16#11A7 =< T, T =< 16#11C2 ->" + " nolist(CP+T-16#11A7,Acc);\n" " Acc -> nolist(CP,Acc)\n" " end;\n" " true ->\n" @@ -408,11 +500,12 @@ gen_norm(Fd) -> " end.\n\n" "compose_compat(CP) when is_integer(CP) -> CP;\n" "compose_compat([Lead,Vowel|Trail]) %% Hangul\n" - " when 16#1100 =< Lead, Lead =< 16#1112 ->\n" + " when is_integer(Lead), 16#1100 =< Lead, Lead =< 16#1112, is_integer(Vowel) ->\n" " if 16#1161 =< Vowel, Vowel =< 16#1175 ->\n" " CP = 16#AC00 + ((Lead - 16#1100) * 588) + ((Vowel - 16#1161) * 28),\n" " case Trail of\n" - " [T|Acc] when 16#11A7 =< T, T =< 16#11C2 -> nolist(CP+T-16#11A7,Acc);\n" + " [T|Acc] when is_integer(T), 16#11A7 =< T, T =< 16#11C2 ->" + " nolist(CP+T-16#11A7,Acc);\n" " Acc -> nolist(CP,Acc)\n" " end;\n" " true ->\n" @@ -462,7 +555,7 @@ gen_ws(Fd, Props) -> gen_cp(Fd) -> io:put_chars(Fd, "-spec cp(String::unicode:chardata()) ->" " maybe_improper_list() | {error, unicode:chardata()}.\n"), - io:put_chars(Fd, "cp([C|_]=L) when is_integer(C) -> L;\n"), + io:put_chars(Fd, "cp([C|_]=L) when ?IS_CP(C) -> L;\n"), io:put_chars(Fd, "cp([List]) -> cp(List);\n"), io:put_chars(Fd, "cp([List|R]) -> cpl(List, R);\n"), io:put_chars(Fd, "cp([]) -> [];\n"), @@ -470,8 +563,8 @@ gen_cp(Fd) -> io:put_chars(Fd, "cp(<<>>) -> [];\n"), io:put_chars(Fd, "cp(<>) -> {error,R}.\n"), io:put_chars(Fd, "\n"), - io:put_chars(Fd, "cpl([C], R) when is_integer(C) -> [C|cpl_1_cont(R)];\n"), - io:put_chars(Fd, "cpl([C|T], R) when is_integer(C) -> [C|cpl_cont(T, R)];\n"), + io:put_chars(Fd, "cpl([C], R) when ?IS_CP(C) -> [C|cpl_1_cont(R)];\n"), + io:put_chars(Fd, "cpl([C|T], R) when ?IS_CP(C) -> [C|cpl_cont(T, R)];\n"), io:put_chars(Fd, "cpl([List], R) -> cpl(List, R);\n"), io:put_chars(Fd, "cpl([List|T], R) -> cpl(List, [T|R]);\n"), io:put_chars(Fd, "cpl([], R) -> cp(R);\n"), @@ -542,18 +635,18 @@ gen_gc(Fd, GBP) -> " maybe_improper_list() | {error, unicode:chardata()}.\n"), io:put_chars(Fd, "gc([]=R) -> R;\n" - "gc([CP]=R) when is_integer(CP) -> R;\n" + "gc([CP]=R) when ?IS_CP(CP) -> R;\n" "gc([$\\r=CP|R0]) ->\n" " case cp(R0) of % Don't break CRLF\n" " [$\\n|R1] -> [[$\\r,$\\n]|R1];\n" " T -> [CP|T]\n" " end;\n" - "gc([CP1|T1]=T) when CP1 < 256 ->\n" + "gc([CP1|T1]=T) when ?IS_CP(CP1), CP1 < 256 ->\n" " case T1 of\n" - " [CP2|_] when CP2 < 256 -> T; %% Ascii Fast path\n" + " [CP2|_] when is_integer(CP2), 0 =< CP2, CP2 < 256 -> T; %% Ascii Fast path\n" " _ -> %% Keep the tail binary.\n" " case cp_no_bin(T1) of\n" - " [CP2|_]=T3 when CP2 < 256 -> [CP1|T3]; %% Asciii Fast path\n" + " [CP2|_]=T3 when is_integer(CP2), 0 =< CP2, CP2 < 256 -> [CP1|T3]; %% Asciii Fast path\n" " binary_found -> gc_1(T);\n" " T4 -> gc_1([CP1|T4])\n" " end\n" @@ -568,7 +661,7 @@ gen_gc(Fd, GBP) -> " end;\n" " true -> gc_1([CP1|Rest])\n" " end;\n" - "gc([CP|_]=T) when is_integer(CP) -> gc_1(T);\n" + "gc([CP|_]=T) when ?IS_CP(CP) -> gc_1(T);\n" "gc(Str) ->\n" " case cp(Str) of\n" " {error,_}=Error -> Error;\n" @@ -596,13 +689,14 @@ gen_gc(Fd, GBP) -> io:put_chars(Fd, "\n%% Optimize Latin-1\n"), [GenExtP(CP) || CP <- merge_ranges(ExtendedPictographicLow)], - io:format(Fd, - "gc_1([CP|R]=R0) when CP < 256 ->\n" - " case R of\n" - " [CP2|_] when CP2 < 256 -> R0;\n" - " _ -> gc_extend(cp(R), R, CP)\n" - " end;\n", - []), + io:put_chars(Fd, + "gc_1([CP|R]=R0) when is_integer(CP), 0 =< CP, CP < 256 ->\n" + " case R of\n" + " [CP2|_] when is_integer(CP2), 0 =< CP2, CP2 < 256 -> R0;\n" + " _ -> gc_extend(cp(R), R, CP)\n" + " end;\n" + "gc_1([CP|_]) when not ?IS_CP(CP) ->\n" + " error({badarg,CP});\n"), io:put_chars(Fd, "\n%% Continue control\n"), [GenControl(CP) || CP <- Crs], %% One clause per CP @@ -623,7 +717,7 @@ gen_gc(Fd, GBP) -> GenHangulT = fun(Range) -> io:format(Fd, "gc_1~s gc_h_T(R1,[CP]);\n", [gen_clause(Range)]) end, [GenHangulT(CP) || CP <- merge_ranges(maps:get(t,GBP))], io:put_chars(Fd, "%% Handle Hangul LV and LVT special, since they are large\n"), - io:put_chars(Fd, "gc_1([CP|_]=R0) when 44000 < CP, CP < 56000 -> gc_h_lv_lvt(R0, R0, []);\n"), + io:put_chars(Fd, "gc_1([CP|_]=R0) when is_integer(CP), 44000 < CP, CP < 56000 -> gc_h_lv_lvt(R0, R0, []);\n"), io:put_chars(Fd, "\n%% Handle Regional\n"), GenRegional = fun(Range) -> io:format(Fd, "gc_1~s gc_regional(R1,CP);\n", [gen_clause(Range)]) end, @@ -671,7 +765,7 @@ gen_gc(Fd, GBP) -> " false -> [CP0|T0]; % losing work done on T\n" " _TrueOrZWJ -> gc_extend2(cp(T), T, [CP,CP0])\n" " end;\n" - "gc_extend([], _, CP) -> [CP];\n" + "gc_extend([], T0, CP) -> [CP|T0];\n" "gc_extend({error,R}, _, CP) -> [CP|R].\n\n"), io:put_chars(Fd, "gc_extend2([CP|T], T0, Acc) ->\n" @@ -679,8 +773,8 @@ gen_gc(Fd, GBP) -> " false -> [lists:reverse(Acc)|T0]; % losing work done on T\n" " _TrueOrZWJ -> gc_extend2(cp(T), T, [CP|Acc])\n" " end;\n" - "gc_extend2([], _, Acc) ->\n" - " [lists:reverse(Acc)];\n" + "gc_extend2([], T0, Acc) ->\n" + " [lists:reverse(Acc)|T0];\n" "gc_extend2({error,R}, _, Acc) ->\n" " [lists:reverse(Acc)] ++ [R].\n\n" ), @@ -705,10 +799,10 @@ gen_gc(Fd, GBP) -> " _ -> [lists:reverse(Acc)|T0]\n" " end\n" " end;\n" - "gc_ext_pict([], _T0, Acc) ->\n" + "gc_ext_pict([], T0, Acc) ->\n" " case Acc of\n" - " [A] -> [A];\n" - " _ -> [lists:reverse(Acc)]\n" + " [A] -> [A|T0];\n" + " _ -> [lists:reverse(Acc)|T0]\n" " end;\n" "gc_ext_pict({error,R}, T, Acc) ->\n" " gc_ext_pict([], T, Acc) ++ [R].\n\n"), @@ -722,10 +816,10 @@ gen_gc(Fd, GBP) -> " _ -> [lists:reverse(Acc)|T0]\n" " end\n" " end;\n" - "gc_ext_pict_zwj([], _, Acc) ->\n" + "gc_ext_pict_zwj([], T0, Acc) ->\n" " case Acc of\n" - " [A] -> [A];\n" - " _ -> [lists:reverse(Acc)]\n" + " [A] -> [A|T0];\n" + " _ -> [lists:reverse(Acc)|T0]\n" " end;\n" "gc_ext_pict_zwj({error,R}, T, Acc) ->\n" " gc_ext_pict_zwj([], T, Acc) ++ [R].\n\n"), @@ -739,7 +833,9 @@ gen_gc(Fd, GBP) -> [{RLess,RLarge}] = merge_ranges(maps:get(regional_indicator,GBP)), io:put_chars(Fd,"gc_regional(R0, CP0) ->\n" " case cp(R0) of\n"), - io:format(Fd, " [CP|R1] when ~w =< CP,CP =< ~w-> gc_extend2(cp(R1),R1,[CP,CP0]);~n",[RLess, RLarge]), + io:format(Fd, " [CP|R1] when is_integer(CP), ~w =< CP, CP =< ~w ->\n" + " gc_extend2(cp(R1),R1,[CP,CP0]);~n", + [RLess, RLarge]), io:put_chars(Fd," R1 -> gc_extend(R1, R0, CP0)\n" " end.\n\n"), @@ -780,6 +876,7 @@ gen_gc(Fd, GBP) -> " _ -> gc_extend2(R1, R0, Acc)\n" " end\n end.\n\n"), io:put_chars(Fd, "%% Handle Hangul LV\n"), + io:put_chars(Fd, "gc_h_lv_lvt([CP|_], _R0, _Acc) when not ?IS_CP(CP) -> error(badarg);\n"), GenHangulLV = fun(Range) -> io:format(Fd, "gc_h_lv_lvt~s gc_h_V(R1,[CP|Acc]);\n", [gen_clause2(Range)]) end, [GenHangulLV(CP) || CP <- merge_ranges(maps:get(lv,GBP))], @@ -806,50 +903,241 @@ gen_compose_pairs(Fd, ExclData, Data) -> [io:format(Fd, "compose_pair(~w,~w) -> ~w;~n", [A,B,CP]) || {[A,B],CP} <- lists:sort(DeCmp2)], io:put_chars(Fd, "compose_pair(_,_) -> false.\n\n"), - io:put_chars(Fd, "nolist(CP, []) -> CP;\nnolist(CP,L) -> [CP|L].\n\n"), + io:put_chars(Fd, "nolist(CP, []) when ?IS_CP(CP) -> CP;\n" + "nolist(CP, L) when ?IS_CP(CP) -> [CP|L].\n\n"), ok. gen_case_table(Fd, Data) -> - Case = array:foldr(fun(CP, #cp{cs={U0,L0,T0,F0}}, Acc) -> - U = def_cp(U0,CP), - L = def_cp(L0,CP), - T = def_cp(T0,CP), - F = def_cp(F0,CP), - case T =:= U andalso F =:= L of - true -> - [{CP,{U,L}}|Acc]; - false -> - [{CP,{U,L,T,F}}|Acc] - end; - (_CP, _, Acc) -> Acc - end, [], Data), + HC = fun(CP, #cp{cs=Cs}, Acc) -> + case case_data(CP, Cs) of + default -> Acc; + CaseData -> [{CP,CaseData}|Acc] + end + end, + Case = array:sparse_foldr(HC, [], Data), [io:format(Fd, "case_table(~w) -> ~w;\n", [CP, Map])|| {CP,Map} <- Case], io:format(Fd, "case_table(CP) -> {CP, CP}.\n\n",[]), ok. +case_data(CP, {U0,L0,T0,F0}) -> + U = def_cp(U0,CP), + L = def_cp(L0,CP), + T = def_cp(T0,CP), + F = def_cp(F0,CP), + case T =:= U andalso F =:= L of + true -> {U,L}; + false -> {U,L,T,F} + end; +case_data(_, _) -> + default. + def_cp([], CP) -> CP; def_cp(CP, _) -> CP. -gen_unicode_table(Fd, Data) -> - FixCanon = fun(_, #cp{class=CCC, dec=Dec, comp=Comp}) -> +gen_unicode_table(Fd, Data, UpdateTests) -> + FixCanon = fun(_, #cp{class=CCC, dec=Dec, comp=Comp, cat=Cat}) -> Canon = decompose(Dec,Data), - #{ccc=>CCC, canonical=>Canon, compat=>Comp} + #{ccc=>CCC, canonical=>Canon, compat=>Comp, cat=>Cat} end, AofMaps0 = array:sparse_map(FixCanon, Data), - FixCompat = fun(_, #{ccc:=CCC, canonical:=Canon, compat:=Comp}) -> + FixCompat = fun(_, #{ccc:=CCC, canonical:=Canon, compat:=Comp, cat:=Cat}) -> Compat = decompose_compat(Canon, Comp, AofMaps0), - {CCC, Canon, Compat} + {CCC, Canon, Compat, category(Cat)} end, AofMaps1 = array:sparse_map(FixCompat, AofMaps0), Dict0 = array:sparse_to_orddict(AofMaps1), - Def = {0, [], []}, - Dict = lists:filter(fun({_, Map}) -> Map =/= Def end, Dict0), + Def = {0, [], [], lookup_category}, + {NonDef, CatTable} = lists:partition(fun({_, {0,[],[],_Cat}}) -> false; + (_) -> true + end, Dict0), + + %% Export testfile + case UpdateTests of + true -> + Dict1 = lists:map(fun({Id,{CCC, Canon, Compat, Cat}}) -> + {_, ECat} = lists:keyfind(Cat, 1, category_translate()), + {Id, {CCC, Canon, Compat, ECat}} + end, Dict0), + TestFile = "../test/unicode_util_SUITE_data/unicode_table.bin", + io:format("Updating: ~s~n", [TestFile]), + file:write_file(TestFile, term_to_binary(Dict1, [compressed])); + false -> + ignore + end, - [io:format(Fd, "unicode_table(~w) -> ~w;~n", [CP, Map]) || {CP,Map} <- Dict], + [io:format(Fd, "unicode_table(~w) -> ~w;~n", [CP, Map]) || {CP,Map} <- NonDef], io:format(Fd, "unicode_table(_) -> ~w.~n~n",[Def]), + + [io:format(Fd, "cat_translate(~w) -> ~w;~n", [Cat, EC]) || {Cat,EC} <- category_translate()], + io:format(Fd, "cat_translate(Cat) -> error({internal_error, Cat}).~n~n",[]), + gen_category(Fd, CatTable, Data), + ok. + +category([C,Sub]) -> + list_to_atom([C-$A+$a, Sub]). + +category_translate() -> + [{lu, {letter, uppercase}}, % Letter, Uppercase + {ll, {letter, lowercase}}, % Letter, Lowercase + {lt, {letter, titlecase}}, % Letter, Titlecase + {mn, {mark, non_spacing}}, % Mark, Non-Spacing + {mc, {mark, spacing_combining}}, % Mark, Spacing Combining + {me, {mark, enclosing}}, % Mark, Enclosing + {nd, {number, decimal}}, % Number, Decimal Digit + {nl, {number, letter}}, % Number, Letter + {no, {number, other}}, % Number, Other + {zs, {separator, space}}, % Separator, Space + {zl, {separator, line}}, % Separator, Line + {zp, {separator, paragraph}}, % Separator, Paragraph + {cc, {other, control}}, % Other, Control + {cf, {other, format}}, % Other, Format + {cs, {other, surrogate}}, % Other, Surrogate + {co, {other, private}}, % Other, Private Use + {cn, {other, not_assigned}}, % Other, Not Assigned (no characters in the file have this property) + {lm, {letter, modifier}}, % Letter, Modifier + {lo, {letter, other}}, % Letter, Other + {pc, {punctuation, connector}}, % Punctuation, Connector + {pd, {punctuation, dash}}, % Punctuation, Dash + {ps, {punctuation, open}}, % Punctuation, Open + {pe, {punctuation, close}}, % Punctuation, Close + {pi, {punctuation, initial}}, % Punctuation, Initial quote (may behave like Ps or Pe depending on usage) + {pf, {punctuation, final}}, % Punctuation, Final quote (may behave like Ps or Pe depending on usage) + {po, {punctuation, other}}, % Punctuation, Other + {sm, {symbol, math}}, % Symbol, Math + {sc, {symbol, currency}}, % Symbol, Currency + {sk, {symbol, modifier}}, % Symbol, Modifier + {so, {symbol, other}}]. % Symbol, Other + +gen_category(Fd, [{CP, {_, _, _, Cat}}|Rest], All) -> + gen_category(Fd, Rest, Cat, CP, CP, All, []). + +gen_category(Fd, [{CP, {_, _, _, NextCat}}|Rest], Cat, Start, End, All, Acc) + when End+1 =:= CP -> + IsLetterCat = letter_cat(NextCat, Cat), + if NextCat =:= Cat -> + gen_category(Fd, Rest, Cat, Start, CP, All, Acc); + IsLetterCat -> + gen_category(Fd, Rest, letter, Start, CP, All, Acc); + Start =:= End -> + io:format(Fd, "lookup_category(~w) -> ~w;~n", [Start, Cat]), + gen_category(Fd, Rest, NextCat, CP, CP, All, Acc); + true -> + case Cat of + letter -> + io:format(Fd, "lookup_category(CP) when ~w =< CP, CP =< ~w-> subcat_letter(CP);~n", + [Start, End]), + gen_category(Fd, Rest, NextCat, CP, CP, All, + lists:reverse(lists:seq(Start, End)) ++ Acc); + _ -> + io:format(Fd, "lookup_category(CP) when ~w =< CP, CP =< ~w-> ~w;~n", [Start, End, Cat]), + gen_category(Fd, Rest, NextCat, CP, CP, All, Acc) + end + end; +gen_category(Fd, [{CP, {_, _, _, NewCat}}|Rest]=Cont, Cat, Start, End, All, Acc) -> + case array:get(End+1, All) of + undefined -> + if Start =:= End -> + io:format(Fd, "lookup_category(~w) -> ~w;~n", [Start, Cat]), + gen_category(Fd, Rest, NewCat, CP, CP, All, Acc); + true -> + case Cat of + letter -> + io:format(Fd, "lookup_category(CP) when ~w =< CP, CP =< ~w-> subcat_letter(CP);~n", + [Start, End]), + gen_category(Fd, Rest, NewCat, CP, CP, All, + lists:reverse(lists:seq(Start, End)) ++ Acc); + _ -> + io:format(Fd, "lookup_category(CP) when ~w =< CP, CP =< ~w -> ~w;~n", + [Start, End, Cat]), + gen_category(Fd, Rest, NewCat, CP, CP, All, Acc) + end + end; + _ -> %% We can make ranges larger by setting already assigned category + gen_category(Fd, Cont, Cat, Start, End+1, All, Acc) + end; +gen_category(Fd, [], Cat, Start, End, All, Acc) -> + case Start =:= End of + true -> + io:format(Fd, "lookup_category(~w) -> ~w;~n", [Start, Cat]); + false -> + io:format(Fd, "lookup_category(CP) when ~w =< CP, CP =< ~w -> ~w;~n", [Start, End, Cat]) + end, + io:put_chars(Fd, "lookup_category(Cp) -> cn.\n\n"), + gen_letter(Fd, lists:reverse(Acc), All), ok. +letter_cat(lm, _) -> + false; +letter_cat(_, lm) -> + false; +letter_cat(L1, L2) -> + is_letter(L1) andalso (L2 =:= letter orelse is_letter(L2)). + +is_letter(LC) -> + lists:member(LC, [lu,ll,lt,lo,lm]). + +gen_letter(Fd, Letters, All) -> + gen_letter(Fd, Letters, All, []). +gen_letter(Fd, [CP|Rest], All, Acc) -> + case array:get(CP, All) of + undefined -> + gen_letter(Fd, Rest, All, Acc); + #cp{cat=Cat0, cs=Cs} -> + case {category(Cat0), case_table(CP,case_data(CP, Cs))} of + {Sub,Sub} -> + gen_letter(Fd, Rest, All, Acc); + {lm,_} -> + gen_letter(Fd, Rest, All, Acc); + {Cat, _Dbg} -> + case is_letter(Cat) of + true -> + gen_letter(Fd, Rest, All, [{CP, Cat}|Acc]); + false -> + gen_letter(Fd, Rest, All, Acc) + end + end + end; +gen_letter(Fd, [], _, Acc) -> + [{Start, Cat}|SCletters] = lists:reverse(Acc), + subcat_letter(Fd, SCletters, Start, Start, Cat), + io:put_chars(Fd, + "subcat_letter(CP) ->\n" + " case case_table(CP) of\n" + " {CP, CP} -> lo; %{letter,other};\n" + " {CP, _} -> lu; %{letter,uppercase};\n" + " {_, CP} -> ll; %{letter,lowercase};\n" + " {_, _, CP, _} -> lt; %{letter,titlecase};\n" + " {CP, _, _, _} -> lu; %{letter,uppercase};\n" + " {_,CP,_,_} -> ll %{letter,lowercase}\n" + " end.\n\n"). + +subcat_letter(Fd, [{CP, Cat}|R], Start, End, Cat) when End+1 =:= CP -> + subcat_letter(Fd, R, Start, CP, Cat); +subcat_letter(Fd, Rest, Start, Start, Cat) -> + io:format(Fd, "subcat_letter(~w) -> ~w;\n",[Start,Cat]), + case Rest of + [] -> ok; + [{CP, NewCat}|R] -> subcat_letter(Fd, R, CP, CP, NewCat) + end; +subcat_letter(Fd, Rest, Start, End, Cat) -> + io:format(Fd, "subcat_letter(CP) when ~w =< CP, CP =< ~w -> ~w;\n",[Start,End,Cat]), + case Rest of + [] -> ok; + [{CP, NewCat}|R] -> subcat_letter(Fd, R, CP, CP, NewCat) + end. + +case_table(CP, CaseData) -> + case CaseData of + {CP, CP} -> lo; + {CP, _} -> lu; + {_, CP} -> ll; + {_, _, CP, _} -> lt; + {CP, _, _, _} -> lu; + {_,CP,_,_} -> ll; + default -> lo + end. + decompose([], _Data) -> []; decompose([CP|CPs], Data) when is_integer(CP) -> case array:get(CP,Data) of @@ -883,35 +1171,41 @@ decompose_compat([{_,CP}|CPs], Data) -> decompose_compat([CP|CPs], Data). +gen_width_table(Fd, WideChars) -> + MergedWCs = merge_ranges(WideChars), + Write = fun(Range) -> io:format(Fd, "is_wide_cp~s true;~n", [gen_single_clause(Range)]) end, + [Write(Range) || Range <- MergedWCs], + io:format(Fd, "is_wide_cp(_) -> false.~n", []). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_clause({R0, undefined}) -> io_lib:format("([~w=CP|R1]=R0) ->", [R0]); gen_clause({R0, R1}) -> - io_lib:format("([CP|R1]=R0) when ~w =< CP, CP =< ~w ->", [R0,R1]). + io_lib:format("([CP|R1]=R0) when is_integer(CP), ~w =< CP, CP =< ~w ->", [R0,R1]). gen_clause2({R0, undefined}) -> io_lib:format("([~w=CP|R1], R0, Acc) ->", [R0]); gen_clause2({R0, R1}) -> - io_lib:format("([CP|R1], R0, Acc) when ~w =< CP, CP =< ~w ->", [R0,R1]). + io_lib:format("([CP|R1], R0, Acc) when is_integer(CP), ~w =< CP, CP =< ~w ->", [R0,R1]). gen_case_clause({R0, undefined}) -> io_lib:format("[~w=CP|R1] ->", [R0]); gen_case_clause({R0, R1}) -> - io_lib:format("[CP|R1] when ~w =< CP, CP =< ~w ->", [R0,R1]). + io_lib:format("[CP|R1] when is_integer(CP), ~w =< CP, CP =< ~w ->", [R0,R1]). gen_single_clause({R0, undefined}) -> io_lib:format("(~w) ->", [R0]); gen_single_clause({R0, R1}) -> - io_lib:format("(CP) when ~w =< CP, CP =< ~w ->", [R0,R1]). + io_lib:format("(CP) when is_integer(CP), ~w =< CP, CP =< ~w ->", [R0,R1]). merge_ranges(List) -> merge_ranges(List, true). merge_ranges(List, Opt) -> - Res0 = merge_ranges_1(lists:sort(List), []), + Res0 = merge_ranges_1(lists:usort(List), []), case Opt of split -> split_ranges(Res0,[]); % One clause per CP diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index f51b35f698cd..d4fc23fc153c 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 3.17.2.4 +STDLIB_VSN = 5.1.1 diff --git a/lib/syntax_tools/doc/Makefile b/lib/syntax_tools/doc/Makefile index 87604c4e7f4f..87b7660c2627 100644 --- a/lib/syntax_tools/doc/Makefile +++ b/lib/syntax_tools/doc/Makefile @@ -57,7 +57,7 @@ info: -debug opt: +$(TYPES): clean: diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml index b3629d44779f..f01a8b73c3dc 100644 --- a/lib/syntax_tools/doc/src/notes.xml +++ b/lib/syntax_tools/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 20072021 + 20072022 Ericsson AB. All Rights Reserved. @@ -32,6 +32,79 @@

    This document describes the changes made to the Syntax_Tools application.

    +
    Syntax_Tools 3.1 + +
    Improvements and New Features + + +

    Map comprehensions as suggested in EEP 58 has now been + implemented.

    +

    + Own Id: OTP-18413 Aux Id: EEP-58, PR-6727

    +
    +
    +
    + +
    + +
    Syntax_Tools 3.0.1 + +
    Fixed Bugs and Malfunctions + + +

    erl_syntax_lib:annotate_bindings/1,2 will now + properly annotate named functions and their + arguments.

    +

    + Own Id: OTP-18380 Aux Id: PR-6523, GH-4733

    +
    +
    +
    + +
    + +
    Syntax_Tools 3.0 + +
    Fixed Bugs and Malfunctions + + +

    The erl_syntax_lib:analyze_attribute/1 function + would return {Name, {Name, Value}} instead of + {Name, Value} (which is the documented return + value).

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17894 Aux Id: PR-5509

    +
    +
    +
    + + +
    Improvements and New Features + + +

    + Added support for configurable features as described in + EEP-60. Features can be enabled/disabled during + compilation with options (-enable-feature Feature, + -disable-feature Feature and +{feature, + Feature, enable|disable}) to erlc as well as + with directives (-feature(Feature, + enable|disable).) in the file. Similar options can be + used to erl for enabling/disabling features + allowed at runtime. The new maybe expression + (EEP-49) is fully supported as the feature + maybe_expr. The features support is documented in + the reference manual.

    +

    + Own Id: OTP-17988

    +
    +
    +
    + +
    +
    Syntax_Tools 2.6
    Fixed Bugs and Malfunctions @@ -860,7 +933,7 @@

    - Miscellanous updates.

    + Miscellaneous updates.

    Own Id: OTP-8038

    diff --git a/lib/syntax_tools/examples/Makefile b/lib/syntax_tools/examples/Makefile index f5e96a82858e..0712898f6529 100644 --- a/lib/syntax_tools/examples/Makefile +++ b/lib/syntax_tools/examples/Makefile @@ -37,7 +37,7 @@ EXAMPLE_FILES = demo.erl # ---------------------------------------------------- # Make Rules # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile index af6a472f3da9..dc0ac617342a 100644 --- a/lib/syntax_tools/src/Makefile +++ b/lib/syntax_tools/src/Makefile @@ -50,7 +50,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE) # Targets # ---------------------------------------------------- -debug opt: $(OBJECTS) +$(TYPES): $(OBJECTS) all: $(OBJECTS) diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl index eacfbc5d6b98..40f67b56608b 100644 --- a/lib/syntax_tools/src/epp_dodger.erl +++ b/lib/syntax_tools/src/epp_dodger.erl @@ -430,7 +430,14 @@ quick_parse_form(Dev, L0, Options) -> parse_form(Dev, L0, Parser, Options) -> NoFail = proplists:get_bool(no_fail, Options), Opt = #opt{clever = proplists:get_bool(clever, Options)}, - case io:scan_erl_form(Dev, "", L0) of + + %% This as the *potential* to read options for enabling/disabling + %% features for the parsing of the file. + {ok, {_Ftrs, ResWordFun}} = + erl_features:keyword_fun(Options, + fun erl_scan:f_reserved_word/1), + + case io:scan_erl_form(Dev, "", L0, [{reserved_word_fun,ResWordFun}]) of {ok, Ts, L1} -> case catch {ok, Parser(Ts, Opt)} of {'EXIT', Term} -> @@ -504,10 +511,14 @@ quickscan_form([{'-', _Anno}, {'if', AnnoA} | _Ts]) -> kill_form(AnnoA); quickscan_form([{'-', _Anno}, {atom, AnnoA, elif} | _Ts]) -> kill_form(AnnoA); -quickscan_form([{'-', _Anno}, {atom, AnnoA, else} | _Ts]) -> +quickscan_form([{'-', _Anno}, {atom, AnnoA, 'else'} | _Ts]) -> + kill_form(AnnoA); +quickscan_form([{'-', _Anno}, {'else', AnnoA} | _Ts]) -> kill_form(AnnoA); quickscan_form([{'-', _Anno}, {atom, AnnoA, endif} | _Ts]) -> kill_form(AnnoA); +quickscan_form([{'-', _Anno}, {atom, AnnoA, feature} | _Ts]) -> + kill_form(AnnoA); quickscan_form([{'-', Anno}, {'?', _}, {Type, _, _}=N | [{'(', _} | _]=Ts]) when Type =:= atom; Type =:= var -> %% minus, macro and open parenthesis at start of form - assume that @@ -648,9 +659,12 @@ scan_form([{'-', _Anno}, {'if', AnnoA} | Ts], Opt) -> scan_form([{'-', _Anno}, {atom, AnnoA, elif} | Ts], Opt) -> [{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA}, {atom, AnnoA, 'elif'} | scan_macros(Ts, Opt)]; -scan_form([{'-', _Anno}, {atom, AnnoA, else} | Ts], Opt) -> +scan_form([{'-', _Anno}, {atom, AnnoA, 'else'} | Ts], Opt) -> + [{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA}, + {atom, AnnoA, 'else'} | scan_macros(Ts, Opt)]; +scan_form([{'-', _Anno}, {'else', AnnoA} | Ts], Opt) -> [{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA}, - {atom, AnnoA, else} | scan_macros(Ts, Opt)]; + {atom, AnnoA, 'else'} | scan_macros(Ts, Opt)]; scan_form([{'-', _Anno}, {atom, AnnoA, endif} | Ts], Opt) -> [{atom, AnnoA, ?pp_form}, {'(', AnnoA}, {')', AnnoA}, {'->', AnnoA}, {atom, AnnoA, endif} | scan_macros(Ts, Opt)]; diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index af1f2b4d1116..89ff4bf13487 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -54,7 +54,7 @@ -type hook() :: 'none' | fun((erl_syntax:syntaxTree(), _, _) -> prettypr:document()). -type clause_t() :: 'case_expr' | 'fun_expr' - | 'if_expr' | 'receive_expr' | 'try_expr' + | 'if_expr' | 'maybe_expr' | 'receive_expr' | 'try_expr' | {'function', prettypr:document()} | 'spec'. @@ -588,6 +588,8 @@ lay_2(Node, Ctxt) -> make_if_clause(D1, D2, D3, Ctxt); case_expr -> make_case_clause(D1, D2, D3, Ctxt); + maybe_expr -> + make_case_clause(D1, D2, D3, Ctxt); receive_expr -> make_case_clause(D1, D2, D3, Ctxt); try_expr -> @@ -648,6 +650,34 @@ lay_2(Node, Ctxt) -> set_prec(Ctxt, PrecR)), beside(D1, beside(text(":"), D2)); + maybe_expr -> + Ctxt1 = reset_prec(Ctxt), + D1 = vertical(seq(erl_syntax:maybe_expr_body(Node), + floating(text(",")), Ctxt1, fun lay/2)), + Es0 = [text("end")], + Es1 = case erl_syntax:maybe_expr_else(Node) of + none -> Es0; + ElseNode -> + ElseCs = erl_syntax:else_expr_clauses(ElseNode), + D3 = lay_clauses(ElseCs, maybe_expr, Ctxt1), + [text("else"), + nest(Ctxt1#ctxt.break_indent, D3) + | Es0] + end, + sep([par([text("maybe"), nest(Ctxt1#ctxt.break_indent, D1), + hd(Es1)]) | tl(Es1)]); + + maybe_match_expr -> + {PrecL, Prec, PrecR} = inop_prec('='), + D1 = lay(erl_syntax:maybe_match_expr_pattern(Node), + set_prec(Ctxt, PrecL)), + D2 = lay(erl_syntax:maybe_match_expr_body(Node), + set_prec(Ctxt, PrecR)), + D3 = follow(beside(D1, floating(text(" ?="))), D2, + Ctxt#ctxt.break_indent), + maybe_parentheses(D3, Prec, Ctxt); + + %% %% The rest is in alphabetical order (except map and types) %% @@ -759,7 +789,7 @@ lay_2(Node, Ctxt) -> nest(Ctxt1#ctxt.break_indent, sep(Es)), text("end")]); - catch_expr -> + 'catch_expr' -> %Quoted to help Emacs. {Prec, PrecR} = preop_prec('catch'), D = lay(erl_syntax:catch_expr_body(Node), set_prec(Ctxt, PrecR)), @@ -801,7 +831,7 @@ lay_2(Node, Ctxt) -> sep(seq(erl_syntax:disjunction_body(Node), floating(text(";")), reset_prec(Ctxt), fun lay/2)); - + error_marker -> E = erl_syntax:error_marker_info(Node), beside(text("** "), @@ -828,6 +858,12 @@ lay_2(Node, Ctxt) -> D2 = lay(erl_syntax:binary_generator_body(Node), Ctxt1), par([D1, beside(text("<= "), D2)], Ctxt1#ctxt.break_indent); + map_generator -> + Ctxt1 = reset_prec(Ctxt), + D1 = lay(erl_syntax:map_generator_pattern(Node), Ctxt1), + D2 = lay(erl_syntax:map_generator_body(Node), Ctxt1), + par([D1, beside(text("<- "), D2)], Ctxt1#ctxt.break_indent); + implicit_fun -> D = lay(erl_syntax:implicit_fun_name(Node), reset_prec(Ctxt)), @@ -853,6 +889,15 @@ lay_2(Node, Ctxt) -> par([D1, beside(floating(text(" || ")), beside(D2, floating(text(" >>"))))])); + map_comp -> + Ctxt1 = set_prec(Ctxt, max_prec()), + D1 = lay(erl_syntax:map_comp_template(Node), Ctxt1), + D2 = par(seq(erl_syntax:map_comp_body(Node), + floating(text(",")), Ctxt1, + fun lay/2)), + beside(floating(text("#{")), + par([D1, beside(floating(text("|| ")), + beside(D2, floating(text("}"))))])); macro -> %% This is formatted similar to a normal function call, but %% prefixed with a "?". diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 354b65c9a384..1958865b3b38 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -193,6 +193,8 @@ constraint_body/1, disjunction/1, disjunction_body/1, + else_expr/1, + else_expr_clauses/1, eof_marker/0, error_marker/1, error_marker_info/1, @@ -244,6 +246,9 @@ macro/2, macro_arguments/1, macro_name/1, + map_comp/2, + map_comp_template/1, + map_comp_body/1, map_expr/1, map_expr/2, map_expr_argument/1, @@ -254,6 +259,9 @@ map_field_exact/2, map_field_exact_name/1, map_field_exact_value/1, + map_generator/2, + map_generator_body/1, + map_generator_pattern/1, map_type/0, map_type/1, map_type_fields/1, @@ -266,6 +274,13 @@ match_expr/2, match_expr_body/1, match_expr_pattern/1, + maybe_expr/1, + maybe_expr/2, + maybe_expr_body/1, + maybe_expr_else/1, + maybe_match_expr/2, + maybe_match_expr_pattern/1, + maybe_match_expr_body/1, module_qualifier/2, module_qualifier_argument/1, module_qualifier_body/1, @@ -505,13 +520,14 @@ %% constrained_function_type %% constraint %% disjunction -%% eof_marker %% +%% else_expr +%% eof_marker %% error_marker +%% %% float %% form_list %% fun_expr -%% %% fun_type %% function %% function_type @@ -535,6 +551,9 @@ %% map_type_assoc %% map_type_exact %% match_expr +%% +%% maybe_expr +%% maybe_match_expr %% module_qualifier %% %% named_fun_expr @@ -597,6 +616,7 @@ %% @see constrained_function_type/2 %% @see constraint/2 %% @see disjunction/1 +%% @see else_expr/1 %% @see eof_marker/0 %% @see error_marker/1 %% @see float/1 @@ -623,6 +643,9 @@ %% @see map_type_assoc/2 %% @see map_type_exact/2 %% @see match_expr/2 +%% @see maybe_expr/1 +%% @see maybe_expr/2 +%% @see maybe_match_expr/2 %% @see module_qualifier/2 %% @see named_fun_expr/2 %% @see nil/0 @@ -683,6 +706,9 @@ type(Node) -> {'fun', _, {function, _, _}} -> implicit_fun; {'fun', _, {function, _, _, _}} -> implicit_fun; {'if', _, _} -> if_expr; + {'maybe', _, _} -> maybe_expr; + {'maybe', _, _, _} -> maybe_expr; + {'else', _, _} -> else_expr; {'receive', _, _, _, _} -> receive_expr; {'receive', _, _} -> receive_expr; {attribute, _, _, _} -> attribute; @@ -695,13 +721,16 @@ type(Node) -> {function, _, _, _, _} -> function; {b_generate, _, _, _} -> binary_generator; {generate, _, _, _} -> generator; + {m_generate, _, _, _} -> map_generator; {lc, _, _, _} -> list_comp; - {bc, _, _, _} -> binary_comp; + {bc, _, _, _} -> binary_comp; + {mc, _, _, _} -> map_comp; {match, _, _, _} -> match_expr; {map, _, _, _} -> map_expr; {map, _, _} -> map_expr; {map_field_assoc, _, _, _} -> map_field_assoc; {map_field_exact, _, _, _} -> map_field_exact; + {maybe_match, _, _, _} -> maybe_match_expr; {op, _, _, _, _} -> infix_expr; {op, _, _, _} -> prefix_expr; {record, _, _, _, _} -> record_expr; @@ -4134,6 +4163,71 @@ match_expr_body(Node) -> end. +%% ===================================================================== +%% @doc Creates an abstract maybe-expression, as used in maybe +%% blocks. The result represents +%% "Pattern ?= Body". +%% +%% @see maybe_match_expr_pattern/1 +%% @see maybe_match_expr_body/1 +%% @see maybe_expr/2 + +-record(maybe_match_expr, {pattern :: syntaxTree(), body :: syntaxTree()}). + +%% type(Node) = maybe_expr +%% data(Node) = #maybe_expr{pattern :: Pattern, body :: Body} +%% +%% Pattern = Body = syntaxTree() +%% +%% `erl_parse' representation: +%% +%% {maybe_match, Pos, Pattern, Body} +%% +%% Pattern = Body = erl_parse() +%% + +-spec maybe_match_expr(syntaxTree(), syntaxTree()) -> syntaxTree(). + +maybe_match_expr(Pattern, Body) -> + tree(maybe_match_expr, #maybe_match_expr{pattern = Pattern, body = Body}). + +revert_maybe_match_expr(Node) -> + Pos = get_pos(Node), + Pattern = maybe_match_expr_pattern(Node), + Body = maybe_match_expr_body(Node), + {maybe_match, Pos, Pattern, Body}. + +%% ===================================================================== +%% @doc Returns the pattern subtree of a `maybe_expr' node. +%% +%% @see maybe_match_expr/2 + +-spec maybe_match_expr_pattern(syntaxTree()) -> syntaxTree(). + +maybe_match_expr_pattern(Node) -> + case unwrap(Node) of + {maybe_match, _, Pattern, _} -> + Pattern; + Node1 -> + (data(Node1))#maybe_match_expr.pattern + end. + + +%% ===================================================================== +%% @doc Returns the body subtree of a `maybe_expr' node. +%% +%% @see maybe_match_expr/2 + +-spec maybe_match_expr_body(syntaxTree()) -> syntaxTree(). + +maybe_match_expr_body(Node) -> + case unwrap(Node) of + {maybe_match, _, _, Body} -> + Body; + Node1 -> + (data(Node1))#maybe_match_expr.body + end. + %% ===================================================================== %% @doc Creates an abstract operator. The name of the operator is the %% character sequence represented by `Name'. This is @@ -6052,6 +6146,72 @@ binary_comp_body(Node) -> (data(Node1))#binary_comp.body end. +%% ===================================================================== +%% @doc Creates an abstract map comprehension. If `Body' is +%% `[E1, ..., En]', the result represents +%% "#{Template || E1, ..., En}". +%% +%% @see map_comp_template/1 +%% @see map_comp_body/1 +%% @see generator/2 + +-record(map_comp, {template :: syntaxTree(), body :: [syntaxTree()]}). + +%% type(Node) = map_comp +%% data(Node) = #map_comp{template :: Template, body :: Body} +%% +%% Template = Node = syntaxTree() +%% Body = [syntaxTree()] +%% +%% `erl_parse' representation: +%% +%% {mc, Pos, Template, Body} +%% +%% Template = erl_parse() +%% Body = [erl_parse()] \ [] + +-spec map_comp(syntaxTree(), [syntaxTree()]) -> syntaxTree(). + +map_comp(Template, Body) -> + tree(map_comp, #map_comp{template = Template, body = Body}). + +revert_map_comp(Node) -> + Pos = get_pos(Node), + Template = map_comp_template(Node), + Body = map_comp_body(Node), + {mc, Pos, Template, Body}. + + +%% ===================================================================== +%% @doc Returns the template subtree of a `map_comp' node. +%% +%% @see map_comp/2 + +-spec map_comp_template(syntaxTree()) -> syntaxTree(). + +map_comp_template(Node) -> + case unwrap(Node) of + {mc, _, Template, _} -> + Template; + Node1 -> + (data(Node1))#map_comp.template + end. + + +%% ===================================================================== +%% @doc Returns the list of body subtrees of a `map_comp' node. +%% +%% @see map_comp/2 + +-spec map_comp_body(syntaxTree()) -> [syntaxTree()]. + +map_comp_body(Node) -> + case unwrap(Node) of + {mc, _, _, Body} -> + Body; + Node1 -> + (data(Node1))#map_comp.body + end. %% ===================================================================== %% @doc Creates an abstract generator. The result represents @@ -6185,6 +6345,72 @@ binary_generator_body(Node) -> end. +%% ===================================================================== +%% @doc Creates an abstract map_generator. The result represents +%% "Pattern <- Body". +%% +%% @see map_generator_pattern/1 +%% @see map_generator_body/1 +%% @see list_comp/2 +%% @see map_comp/2 + +-record(map_generator, {pattern :: syntaxTree(), body :: syntaxTree()}). + +%% type(Node) = map_generator +%% data(Node) = #map_generator{pattern :: Pattern, body :: Body} +%% +%% Pattern = Argument = syntaxTree() +%% +%% `erl_parse' representation: +%% +%% {m_generate, Pos, Pattern, Body} +%% +%% Pattern = Body = erl_parse() + +-spec map_generator(syntaxTree(), syntaxTree()) -> syntaxTree(). + +map_generator(Pattern, Body) -> + tree(map_generator, #map_generator{pattern = Pattern, body = Body}). + +revert_map_generator(Node) -> + Pos = get_pos(Node), + Pattern = map_generator_pattern(Node), + Body = map_generator_body(Node), + {m_generate, Pos, Pattern, Body}. + + +%% ===================================================================== +%% @doc Returns the pattern subtree of a `generator' node. +%% +%% @see map_generator/2 + +-spec map_generator_pattern(syntaxTree()) -> syntaxTree(). + +map_generator_pattern(Node) -> + case unwrap(Node) of + {m_generate, _, Pattern, _} -> + Pattern; + Node1 -> + (data(Node1))#map_generator.pattern + end. + + +%% ===================================================================== +%% @doc Returns the body subtree of a `generator' node. +%% +%% @see map_generator/2 + +-spec map_generator_body(syntaxTree()) -> syntaxTree(). + +map_generator_body(Node) -> + case unwrap(Node) of + {m_generate, _, _, Body} -> + Body; + Node1 -> + (data(Node1))#map_generator.body + end. + + %% ===================================================================== %% @doc Creates an abstract block expression. If `Body' is %% `[B1, ..., Bn]', the result represents "begin @@ -6361,6 +6587,130 @@ case_expr_clauses(Node) -> (data(Node1))#case_expr.clauses end. +%% ===================================================================== +%% @doc Creates an abstract else-expression. If `Clauses' is `[C1, +%% ..., Cn]', the result represents "else C1; ...; Cn +%% end". More exactly, if each `Ci' represents +%% "(Pi) Gi -> Bi", then the +%% result represents "else G1 -> B1; ...; +%% Pn Gn -> Bn end". +%% +%% @see maybe_expr/2 +%% @see else_expr_clauses/1 +%% @see clause/3 + +else_expr(Clauses) -> + tree(else_expr, Clauses). + +revert_else_expr(Node) -> + Pos = get_pos(Node), + Clauses = else_expr_clauses(Node), + {'else', Pos, Clauses}. + +%% ===================================================================== +%% @doc Returns the list of clause subtrees of an `else_expr' node. +%% +%% @see else_expr/1 + +-spec else_expr_clauses(syntaxTree()) -> [syntaxTree()]. + +else_expr_clauses(Node) -> + case unwrap(Node) of + {'else', _, Clauses} -> + Clauses; + Node1 -> + data(Node1) + end. + +%% ===================================================================== +%% @equiv maybe_expr(Body, none) + +-spec maybe_expr([syntaxTree()]) -> syntaxTree(). + +maybe_expr(Body) -> + maybe_expr(Body, none). + +%% ===================================================================== +%% @doc Creates an abstract maybe-expression. If `Body' is `[B1, ..., +%% Bn]', and `OptionalElse' is `none', the result represents +%% "maybe B1, ..., Bn end". If `Body' +%% is `[B1, ..., Bn]', and `OptionalElse' reprsents an `else_expr' node +%% with clauses `[C1, ..., Cn]', the result represents "maybe +%% B1, ..., Bn else C1; ..., Cn +%% end". +%% +%% See `clause' for documentation on `erl_parse' clauses. +%% +%% @see maybe_expr_body/1 +%% @see maybe_expr_else/1 + +-record(maybe_expr, {body :: [syntaxTree()], + 'else' = none :: 'none' | syntaxTree()}). + +%% type(Node) = maybe_expr +%% data(Node) = #maybe_expr{body :: Body, 'else' :: 'none' | Else} +%% +%% Body = [syntaxTree()] +%% Else = syntaxTree() +%% +%% `erl_parse' representation: +%% +%% {block, Pos, Body} +%% {block, Pos, Body, Else} +%% +%% Body = [erl_parse()] \ [] +%% Else = {'else', Pos, Clauses} +%% Clauses = [Clause] \ [] +%% Clause = {clause, ...} + +-spec maybe_expr([syntaxTree()], 'none' | syntaxTree()) -> syntaxTree(). + +maybe_expr(Body, OptionalElse) -> + tree(maybe_expr, #maybe_expr{body = Body, + 'else' = OptionalElse}). +revert_maybe_expr(Node) -> + Pos = get_pos(Node), + Body = maybe_expr_body(Node), + case maybe_expr_else(Node) of + none -> + {'maybe', Pos, Body}; + Else -> + {'maybe', Pos, Body, Else} + end. + +%% ===================================================================== +%% @doc Returns the list of body subtrees of a `maybe_expr' node. +%% +%% @see maybe_expr/2 + +-spec maybe_expr_body(syntaxTree()) -> [syntaxTree()]. + +maybe_expr_body(Node) -> + case unwrap(Node) of + {'maybe', _, Body} -> + Body; + {'maybe', _, Body, _Else} -> + Body; + Node1 -> + (data(Node1))#maybe_expr.body + end. + +%% ===================================================================== +%% @doc Returns the else subtree of a `maybe_expr' node. +%% +%% @see maybe_expr/2 + +-spec maybe_expr_else(syntaxTree()) -> 'none' | syntaxTree(). + +maybe_expr_else(Node) -> + case unwrap(Node) of + {'maybe', _, _Body} -> + none; + {'maybe', _, _Body, Else} -> + Else; + Node1 -> + (data(Node1))#maybe_expr.'else' + end. %% ===================================================================== %% @equiv receive_expr(Clauses, none, []) @@ -7310,7 +7660,7 @@ concrete(Node) -> eval_bits:expr_grp(Fs, [], fun(F, _) -> {value, concrete(F), []} - end, [], true), + end), B; arity_qualifier -> A = erl_syntax:arity_qualifier_argument(Node), @@ -7470,9 +7820,9 @@ revert_root(Node) -> revert_bitstring_type(Node); block_expr -> revert_block_expr(Node); - case_expr -> + 'case_expr' -> %Quoted to help Emacs. revert_case_expr(Node); - catch_expr -> + 'catch_expr' -> %Quoted to help Emacs. revert_catch_expr(Node); char -> revert_char(Node); @@ -7482,6 +7832,8 @@ revert_root(Node) -> revert_constrained_function_type(Node); constraint -> revert_constraint(Node); + else_expr -> + revert_else_expr(Node); eof_marker -> revert_eof_marker(Node); error_marker -> @@ -7512,12 +7864,16 @@ revert_root(Node) -> revert_list(Node); list_comp -> revert_list_comp(Node); + map_comp -> + revert_map_comp(Node); map_expr -> revert_map_expr(Node); map_field_assoc -> revert_map_field_assoc(Node); map_field_exact -> revert_map_field_exact(Node); + map_generator -> + revert_map_generator(Node); map_type -> revert_map_type(Node); map_type_assoc -> @@ -7526,6 +7882,10 @@ revert_root(Node) -> revert_map_type_exact(Node); match_expr -> revert_match_expr(Node); + maybe_match_expr -> + revert_maybe_match_expr(Node); + maybe_expr -> + revert_maybe_expr(Node); module_qualifier -> revert_module_qualifier(Node); named_fun_expr -> @@ -7730,7 +8090,7 @@ subtrees(T) -> case_expr -> [[case_expr_argument(T)], case_expr_clauses(T)]; - catch_expr -> + 'catch_expr' -> %Quoted to help Emacs. [[catch_expr_body(T)]]; class_qualifier -> [[class_qualifier_argument(T)], @@ -7755,6 +8115,8 @@ subtrees(T) -> constraint_body(T)]; disjunction -> [disjunction_body(T)]; + else_expr -> + [else_expr_clauses(T)]; form_list -> [form_list_elements(T)]; fun_expr -> @@ -7799,6 +8161,8 @@ subtrees(T) -> As -> [[macro_name(T)], As] end; + map_comp -> + [[map_comp_template(T)], map_comp_body(T)]; map_expr -> case map_expr_argument(T) of none -> @@ -7812,6 +8176,9 @@ subtrees(T) -> map_field_exact -> [[map_field_exact_name(T)], [map_field_exact_value(T)]]; + map_generator -> + [[map_generator_pattern(T)], + [map_generator_body(T)]]; map_type -> [map_type_fields(T)]; map_type_assoc -> @@ -7823,6 +8190,17 @@ subtrees(T) -> match_expr -> [[match_expr_pattern(T)], [match_expr_body(T)]]; + maybe_expr -> + case maybe_expr_else(T) of + none -> + [maybe_expr_body(T)]; + E -> + [maybe_expr_body(T), + [E]] + end; + maybe_match_expr -> + [[maybe_match_expr_pattern(T)], + [maybe_match_expr_body(T)]]; module_qualifier -> [[module_qualifier_argument(T)], [module_qualifier_body(T)]]; @@ -7962,6 +8340,7 @@ make_tree(constrained_function_type, [[F],C]) -> constrained_function_type(F, C); make_tree(constraint, [[N], Ts]) -> constraint(N, Ts); make_tree(disjunction, [E]) -> disjunction(E); +make_tree(else_expr, [E]) -> else_expr(E); make_tree(form_list, [E]) -> form_list(E); make_tree(fun_expr, [C]) -> fun_expr(C); make_tree(function, [[N], C]) -> function(N, C); @@ -7977,14 +8356,19 @@ make_tree(list, [P, [S]]) -> list(P, S); make_tree(list_comp, [[T], B]) -> list_comp(T, B); make_tree(macro, [[N]]) -> macro(N); make_tree(macro, [[N], A]) -> macro(N, A); +make_tree(map_comp, [[T], B]) -> map_comp(T, B); make_tree(map_expr, [Fs]) -> map_expr(Fs); make_tree(map_expr, [[E], Fs]) -> map_expr(E, Fs); make_tree(map_field_assoc, [[K], [V]]) -> map_field_assoc(K, V); make_tree(map_field_exact, [[K], [V]]) -> map_field_exact(K, V); +make_tree(map_generator, [[P], [E]]) -> map_generator(P, E); make_tree(map_type, [Fs]) -> map_type(Fs); make_tree(map_type_assoc, [[N],[V]]) -> map_type_assoc(N, V); make_tree(map_type_exact, [[N],[V]]) -> map_type_exact(N, V); make_tree(match_expr, [[P], [E]]) -> match_expr(P, E); +make_tree(maybe_expr, [Body]) -> maybe_expr(Body); +make_tree(maybe_expr, [Body, [Else]]) -> maybe_expr(Body, Else); +make_tree(maybe_match_expr, [[P], [E]]) -> maybe_match_expr(P, E); make_tree(named_fun_expr, [[N], C]) -> named_fun_expr(N, C); make_tree(module_qualifier, [[M], [N]]) -> module_qualifier(M, N); make_tree(parentheses, [[E]]) -> parentheses(E); diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl index 618500723591..caaa322dfbe2 100644 --- a/lib/syntax_tools/src/erl_syntax_lib.erl +++ b/lib/syntax_tools/src/erl_syntax_lib.erl @@ -332,8 +332,8 @@ variables_2([], S) -> -define(MINIMUM_RANGE, 100). -define(START_RANGE_FACTOR, 100). -define(MAX_RETRIES, 3). % retries before enlarging range --define(ENLARGE_ENUM, 8). % range enlargment enumerator --define(ENLARGE_DENOM, 1). % range enlargment denominator +-define(ENLARGE_ENUM, 8). % range enlargement enumerator +-define(ENLARGE_DENOM, 1). % range enlargement denominator default_variable_name(N) -> list_to_atom("V" ++ integer_to_list(N)). @@ -538,6 +538,8 @@ vann(Tree, Env) -> vann_function(Tree, Env); fun_expr -> vann_fun_expr(Tree, Env); + named_fun_expr -> + vann_named_fun_expr(Tree, Env); list_comp -> vann_list_comp(Tree, Env); binary_comp -> @@ -583,6 +585,18 @@ vann_fun_expr(Tree, Env) -> Bound = [], {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. +vann_named_fun_expr(Tree, Env) -> + N = erl_syntax:named_fun_expr_name(Tree), + NBound = [erl_syntax:variable_name(N)], + NFree = [], + N1 = ann_bindings(N, Env, NBound, NFree), + Env1 = ordsets:union(Env, NBound), + Cs = erl_syntax:named_fun_expr_clauses(Tree), + {Cs1, {_, Free}} = vann_clauses(Cs, Env1), + Tree1 = rewrite(Tree, erl_syntax:named_fun_expr(N1,Cs1)), + Bound = [], + {ann_bindings(Tree1, Env, Bound, Free), Bound, Free}. + vann_match_expr(Tree, Env) -> E = erl_syntax:match_expr_body(Tree), {E1, Bound1, Free1} = vann(E, Env), @@ -1106,7 +1120,7 @@ collect_attribute(file, _, Info) -> Info; collect_attribute(record, {R, L}, Info) -> finfo_add_record(R, L, Info); -collect_attribute(_, {N, V}, Info) -> +collect_attribute(N, V, Info) -> finfo_add_attribute(N, V, Info). %% Abstract datatype for collecting module information. @@ -1254,7 +1268,7 @@ analyze_form(Node) -> %% @doc Analyzes an attribute node. If `Node' represents a %% preprocessor directive, the atom `preprocessor' is %% returned. Otherwise, if `Node' represents a module -%% attribute "`-Name...'", a tuple `{Name, +%% attribute "`-Name...'", a tuple `{Name, %% Info}' is returned, where `Info' depends on %% `Name', as follows: %%
    @@ -1314,7 +1328,7 @@ analyze_attribute(Node) -> ifndef -> preprocessor; 'if' -> preprocessor; elif -> preprocessor; - else -> preprocessor; + 'else' -> preprocessor; endif -> preprocessor; A -> {A, analyze_attribute(A, Node)} @@ -1335,7 +1349,8 @@ analyze_attribute(record, Node) -> analyze_record_attribute(Node); analyze_attribute(_, Node) -> %% A "wild" attribute (such as e.g. a `compile' directive). - analyze_wild_attribute(Node). + {_, Info} = analyze_wild_attribute(Node), + Info. %% ===================================================================== @@ -1632,8 +1647,8 @@ analyze_wild_attribute(Node) -> %% `Node' represents "`-record(Name, {...}).'", %% where `Fields' is a list of pairs `{Label, %% {Default, Type}}' for each field "`Label'", "`Label = -%% Default'", "`Label :: Type'", or -%% "`Label = Default :: Type'" in the declaration, +%% Default'", "`Label :: Type'", or +%% "`Label = Default :: Type'" in the declaration, %% listed in left-to-right %% order. If the field has no default-value declaration, the value for %% `Default' will be the atom `none'. If the field has no type declaration, @@ -1708,7 +1723,7 @@ analyze_record_attribute_tuple(Node) -> %% For a `record_expr' node, `Info' represents %% the record name and the list of descriptors for the involved fields, %% listed in the order they appear. A field descriptor is a pair -%% `{Label, Value}', if `Node' represents "`Label = Value'". +%% `{Label, Value}', if `Node' represents "`Label = Value'". %% For a `record_access' node, %% `Info' represents the record name and the field name. For a %% `record_index_expr' node, `Info' represents the @@ -1783,9 +1798,8 @@ analyze_record_expr(Node) -> %% %% @doc Returns the label, value-expression, and type of a record field %% specifier. The result is a pair `{Label, {Default, Type}}', if -%% `Node' represents "`Label'", "`Label = Default'", -%% "`Label :: Type'", or -%% "`Label = Default :: Type'". +%% `Node' represents "`Label'", "`Label = Default'", +%% "`Label :: Type'", or "`Label = Default :: Type'". %% If the field has no value-expression, the value for %% `Default' will be the atom `none'. If the field has no type, %% the value for `Type' will be the atom `none'. @@ -1862,7 +1876,7 @@ analyze_file_attribute(Node) -> %% %% @doc Returns the name and arity of a function definition. The result %% is a pair `{Name, A}' if `Node' represents a -%% function definition "`Name(P_1, ..., P_A) -> +%% function definition "`Name(P_1, ..., P_A) -> %% ...'". %% %% The evaluation throws `syntax_error' if @@ -1895,7 +1909,7 @@ analyze_function(Node) -> %% ModuleName = atom() %% %% @doc Returns the name of an implicit fun expression "`fun -%% F'". The result is a representation of the function +%% F'". The result is a representation of the function %% name `F'. (Cf. `analyze_function_name/1'.) %% %% The evaluation throws `syntax_error' if @@ -1925,7 +1939,7 @@ analyze_implicit_fun(Node) -> %% @doc Returns the name of a called function. The result is a %% representation of the name of the applied function `F/A', %% if `Node' represents a function application -%% "`F(X_1, ..., X_A)'". If the +%% "`F(X_1, ..., X_A)'". If the %% function is not explicitly named (i.e., `F' is given by %% some expression), only the arity `A' is returned. %% @@ -1966,10 +1980,10 @@ analyze_application(Node) -> %% @doc Returns the name of a used type. The result is a %% representation of the name of the used pre-defined or local type `N/A', %% if `Node' represents a local (user) type application -%% "`N(T_1, ..., T_A)'", or +%% "`N(T_1, ..., T_A)'", or %% a representation of the name of the used remote type `M:N/A' %% if `Node' represents a remote user type application -%% "`M:N(T_1, ..., T_A)'". +%% "`M:N(T_1, ..., T_A)'". %% %% The evaluation throws `syntax_error' if `Node' does not represent a %% well-formed (user) type application expression. diff --git a/lib/syntax_tools/src/merl.erl b/lib/syntax_tools/src/merl.erl index 97ef68ce4c04..28cd1283e989 100644 --- a/lib/syntax_tools/src/merl.erl +++ b/lib/syntax_tools/src/merl.erl @@ -467,7 +467,7 @@ quote(Text) -> %% @doc Parse text. Takes an initial scanner starting position as first %% argument. %% -%% The macro `?Q(Text)' expands to `merl:quote(?LINE, Text, Env)'. +%% The macro `?Q(Text)' expands to `merl:quote(?LINE, Text)'. %% %% @see quote/1 diff --git a/lib/syntax_tools/src/prettypr.erl b/lib/syntax_tools/src/prettypr.erl index 1f2dfffbdbdd..caafa9b8b917 100644 --- a/lib/syntax_tools/src/prettypr.erl +++ b/lib/syntax_tools/src/prettypr.erl @@ -432,7 +432,7 @@ follow(D1, D2) -> %% document() %% %% @doc Separates two documents by either a single space, or a line -%% break and intentation. In other words, one of the layouts +%% break and indentation. In other words, one of the layouts %% ```abc def''' %% or %% ```abc diff --git a/lib/syntax_tools/src/syntax_tools.app.src b/lib/syntax_tools/src/syntax_tools.app.src index 9bbf20d5a5d9..a6eeeba5dc1a 100644 --- a/lib/syntax_tools/src/syntax_tools.app.src +++ b/lib/syntax_tools/src/syntax_tools.app.src @@ -16,4 +16,4 @@ {applications, [stdlib]}, {env, []}, {runtime_dependencies, - ["compiler-7.0","erts-9.0","kernel-5.0","stdlib-3.4"]}]}. + ["compiler-7.0","erts-9.0","kernel-5.0","stdlib-4.0"]}]}. diff --git a/lib/syntax_tools/test/Makefile b/lib/syntax_tools/test/Makefile index 4ace8602230d..deee5ab8142e 100644 --- a/lib/syntax_tools/test/Makefile +++ b/lib/syntax_tools/test/Makefile @@ -27,6 +27,7 @@ RELSYSDIR = $(RELEASE_PATH)/syntax_tools_test ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -40,7 +41,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \ >> $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl index 3246ce701070..3553f7a71f5d 100644 --- a/lib/syntax_tools/test/syntax_tools_SUITE.erl +++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl @@ -27,7 +27,7 @@ revert_map_type/1,wrapped_subtrees/1, t_abstract_type/1,t_erl_parse_type/1,t_type/1, t_epp_dodger/1,t_epp_dodger_clever/1, - t_comment_scan/1,t_prettypr/1]). + t_comment_scan/1,t_prettypr/1,test_named_fun_bind_ann/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -36,7 +36,7 @@ all() -> wrapped_subtrees, t_abstract_type,t_erl_parse_type,t_type, t_epp_dodger,t_epp_dodger_clever, - t_comment_scan,t_prettypr]. + t_comment_scan,t_prettypr,test_named_fun_bind_ann]. groups() -> []. @@ -106,7 +106,8 @@ revert(Config) when is_list(Config) -> test_server:timetrap_cancel(Dog). revert_file(File, Path) -> - case epp:parse_file(File, Path, []) of + case epp:parse_file(File, [{includes,Path}, + res_word_option()]) of {ok,Fs0} -> Fs1 = erl_syntax:form_list(Fs0), Fs2 = erl_syntax_lib:map(fun (Node) -> Node end, Fs1), @@ -350,11 +351,37 @@ t_comment_scan(Config) when is_list(Config) -> t_prettypr(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), - Filenames = ["type_specs.erl", - "specs_and_funs.erl"], + Filenames = test_files(), ok = test_prettypr(Filenames,DataDir,PrivDir), ok. +%% Test bug (#4733) fix for annotating bindings for named fun expressions +test_named_fun_bind_ann(Config) when is_list(Config) -> + Fn = {named_fun,{6,5}, + 'F', + [{clause,{6,9}, + [{var,{6,11},'Test'}], + [], + [{var,{7,13},'Test'}]}]}, + AnnT = erl_syntax_lib:annotate_bindings(Fn, []), + [Env, Bound, Free] = erl_syntax:get_ann(AnnT), + {'env',[]} = Env, + {'bound',[]} = Bound, + {'free',[]} = Free, + + NameVar = erl_syntax:named_fun_expr_name(AnnT), + Name = erl_syntax:variable_name(NameVar), + [NEnv, NBound, NFree] = erl_syntax:get_ann(NameVar), + {'env',[]} = NEnv, + {'bound',[Name]} = NBound, + {'free',[]} = NFree, + + [Clause] = erl_syntax:named_fun_expr_clauses(AnnT), + [CEnv, CBound, CFree] = erl_syntax:get_ann(Clause), + {'env',[Name]} = CEnv, + {'bound',['Test']} = CBound, + {'free', []} = CFree. + test_files(Config) -> DataDir = ?config(data_dir, Config), [ filename:join(DataDir,Filename) || Filename <- test_files() ]. @@ -391,15 +418,16 @@ test_comment_scan([File|Files],DataDir) -> test_prettypr([],_,_) -> ok; test_prettypr([File|Files],DataDir,PrivDir) -> Filename = filename:join(DataDir,File), + Options = [res_word_option()], io:format("Parsing ~p~n", [Filename]), - {ok, Fs0} = epp:parse_file(Filename, [], []), + {ok, Fs0} = epp:parse_file(Filename, Options), Fs = erl_syntax:form_list(Fs0), PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]), io:put_chars(PP), OutFile = filename:join(PrivDir, File), ok = file:write_file(OutFile,unicode:characters_to_binary(PP)), io:format("Parsing OutFile: ~ts~n", [OutFile]), - {ok, Fs2} = epp:parse_file(OutFile, [], []), + {ok, Fs2} = epp:parse_file(OutFile, Options), case [Error || {error, _} = Error <- Fs2] of [] -> ok; @@ -408,22 +436,23 @@ test_prettypr([File|Files],DataDir,PrivDir) -> end, test_prettypr(Files,DataDir,PrivDir). - test_epp_dodger([], _, _) -> ok; test_epp_dodger([Filename|Files],DataDir,PrivDir) -> io:format("Parsing ~p~n", [Filename]), + Options = [{feature, maybe_expr, enable}], InFile = filename:join(DataDir, Filename), - Parsers = [{fun epp_dodger:parse_file/1,parse_file}, - {fun epp_dodger:quick_parse_file/1,quick_parse_file}, + Parsers = [{fun(File) -> epp_dodger:parse_file(File, Options) end,parse_file}, + {fun(File) -> epp_dodger:quick_parse_file(File, + Options) end,quick_parse_file}, {fun (File) -> {ok,Dev} = file:open(File,[read]), - Res = epp_dodger:parse(Dev), + Res = epp_dodger:parse(Dev, Options), file:close(File), Res end, parse}, {fun (File) -> {ok,Dev} = file:open(File,[read]), - Res = epp_dodger:quick_parse(Dev), + Res = epp_dodger:quick_parse(Dev, Options), file:close(File), Res end, quick_parse}], @@ -617,3 +646,9 @@ p_run_loop(Test, List, N, Refs0, Errors0) -> Refs = Refs0 -- [Ref], p_run_loop(Test, List, N, Refs, Errors) end. + +res_word_option() -> + Options = [{feature, maybe_expr, enable}], + {ok, {_Ftrs, ResWordFun}} = + erl_features:keyword_fun(Options, fun erl_scan:f_reserved_word/1), + {reserved_word_fun, ResWordFun}. diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl index 07c419b4b787..daa95b6a259e 100644 --- a/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl +++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/syntax_tools_SUITE_test_module.erl @@ -8,6 +8,7 @@ sub_word/2,sub_word/3,left/2,left/3,right/2,right/3, sub_string/2,sub_string/3,centre/2,centre/3, join/2]). -export([to_upper/1, to_lower/1]). +-export([eep49/0, eep58/0]). -import(lists,[reverse/1,member/2]). @@ -235,8 +236,8 @@ substr1(String, _L) when is_list(String) -> []. %Be nice! substr2(String, 1) when is_list(String) -> String; substr2([_|String], S) -> substr2(String, S-1). -%% tokens(String, Seperators). -%% Return a list of tokens seperated by characters in Seperators. +%% tokens(String, Separators). +%% Return a list of tokens separated by characters in Separators. -spec tokens(String, SeparatorList) -> Tokens when String :: string(), @@ -538,3 +539,54 @@ join([], Sep) when is_list(Sep) -> []; join([H|T], Sep) -> H ++ lists:append([Sep ++ X || X <- T]). + +eep49() -> + maybe ok ?= ok end, + + {a,b} = + maybe + {ok,A} ?= {ok,a}, + {ok,B} ?= {ok,b}, + {A,B} + end, + + maybe + ok ?= {ok,x} + else + error -> error; + {error,_} -> error + end, + + maybe + ok ?= {ok,x} + else + error -> error + end, + + maybe + {ok,X} ?= {ok,x}, + {ok,Y} ?= {ok,y}, + {X,Y} + else + error -> error; + {error,_} -> error + end, + + maybe + {ok,X2} ?= {ok,x}, + {ok,Y2} ?= {ok,y}, + {X2,Y2} + else + error -> error + end, + + ok. + +%% EEP-58: Map comprehensions. +eep58() -> + Seq = lists:seq(1, 10), + Map = #{{key,I} => I || I <- Seq}, + MapDouble = #{K => 2 * V || K := V <- Map}, + MapDouble = maps:from_list([{{key,I}, 2 * I} || I <- Seq]), + + ok. diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk index 87a6cb015844..acc6cd01b71d 100644 --- a/lib/syntax_tools/vsn.mk +++ b/lib/syntax_tools/vsn.mk @@ -1 +1 @@ -SYNTAX_TOOLS_VSN = 2.6 +SYNTAX_TOOLS_VSN = 3.1 diff --git a/lib/tftp/doc/src/notes.xml b/lib/tftp/doc/src/notes.xml index 71d22fbd9740..81fda3733652 100644 --- a/lib/tftp/doc/src/notes.xml +++ b/lib/tftp/doc/src/notes.xml @@ -33,7 +33,59 @@ notes.xml
    -
    Tftp 1.0.3 +
    Tftp 1.1 + +
    Improvements and New Features + + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    Tftp 1.0.4 + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Tftp 1.0.3
    Fixed Bugs and Malfunctions diff --git a/lib/tftp/src/Makefile b/lib/tftp/src/Makefile index 4ece9ffe2850..cfcb1ea1343b 100644 --- a/lib/tftp/src/Makefile +++ b/lib/tftp/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2021. All Rights Reserved. +# Copyright Ericsson AB 2005-2022. 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. @@ -80,7 +80,7 @@ ERL_COMPILE_FLAGS += \ $(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES) -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(BEHAVIOUR_TARGET_FILES) diff --git a/lib/tftp/src/tftp.app.src b/lib/tftp/src/tftp.app.src index 49b95e0e7b8f..2f6b4793a278 100644 --- a/lib/tftp/src/tftp.app.src +++ b/lib/tftp/src/tftp.app.src @@ -18,5 +18,5 @@ tftp_logger, tftp_sup ]}, - {runtime_dependencies, ["erts-6.0","stdlib-3.5","kernel-6.0"]} + {runtime_dependencies, ["erts-6.0","stdlib-5.0","kernel-6.0"]} ]}. diff --git a/lib/tftp/src/tftp.erl b/lib/tftp/src/tftp.erl index 31e4c651e80f..a32d0dca9cf8 100644 --- a/lib/tftp/src/tftp.erl +++ b/lib/tftp/src/tftp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2018. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -79,7 +79,7 @@ %%% setuid_socket_wrap. Then the command line argument %%% "-tftpd_69 22" will trigger the prebound file %%% descriptor 22 to be used instead of opening port 69. -%%% The UDP option {udp, [{fd, 22}]} autmatically be added. +%%% The UDP option {udp, [{fd, 22}]} automatically be added. %%% See init:get_argument/ about command line arguments and %%% gen_udp:open/2 about UDP options. %%% @@ -107,7 +107,7 @@ %%% usage is when used in conjunction with setuid_socket_wrap %%% to be able to open privileged sockets. For example if the %%% file descriptor 22 has been opened by setuid_socket_wrap -%%% and you have choosen my_tftp_fd as init argument, the +%%% and you have chosen my_tftp_fd as init argument, the %%% command line should like this "erl -my_tftp_fd 22" and %%% FileDesc should be set to my_tftpd_fd. This would %%% automatically imply {fd, 22} to be set as UDP option. diff --git a/lib/tftp/src/tftp_binary.erl b/lib/tftp/src/tftp_binary.erl index 3438ba235b3c..dda64b425296 100644 --- a/lib/tftp/src/tftp_binary.erl +++ b/lib/tftp/src/tftp_binary.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2018. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -53,7 +53,7 @@ prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(I blksize = lookup_blksize(AcceptedOptions), bin = Filename, is_network_ascii = IsNetworkAscii, - count = size(Filename), + count = byte_size(Filename), is_native_ascii = IsNativeAscii}, {ok, AcceptedOptions, State}; {ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Filename =:= binary -> @@ -115,11 +115,11 @@ open(Peer, Access, Filename, Mode, NegotiatedOptions, State) -> read(#read_state{bin = Bin} = State) when is_binary(Bin) -> BlkSize = State#read_state.blksize, if - size(Bin) >= BlkSize -> + byte_size(Bin) >= BlkSize -> <> = Bin, State2 = State#read_state{bin = Bin2}, {more, Block, State2}; - size(Bin) < BlkSize -> + byte_size(Bin) < BlkSize -> {last, Bin, State#read_state.count} end; read(State) -> @@ -132,7 +132,7 @@ read(State) -> %%------------------------------------------------------------------- write(Bin, #write_state{list = List} = State) when is_binary(Bin), is_list(List) -> - Size = size(Bin), + Size = byte_size(Bin), BlkSize = State#write_state.blksize, if Size =:= BlkSize -> @@ -182,7 +182,7 @@ do_handle_options(Access, Bin, [{Key, Val} | T]) -> "tsize" -> case Access of read when Val =:= "0", is_binary(Bin) -> - Tsize = integer_to_list(size(Bin)), + Tsize = integer_to_list(byte_size(Bin)), [{Key, Tsize} | do_handle_options(Access, Bin, T)]; _ -> handle_integer(Access, Bin, Key, Val, T, 0, infinity) diff --git a/lib/tftp/src/tftp_engine.erl b/lib/tftp/src/tftp_engine.erl index 811f91b8bd75..4e55fec63e9b 100644 --- a/lib/tftp/src/tftp_engine.erl +++ b/lib/tftp/src/tftp_engine.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2021. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -714,7 +714,9 @@ pre_terminate(Config, Req, Result) -> if Req#tftp_msg_req.local_filename =/= undefined, Config#config.parent_pid =/= undefined -> - proc_lib:init_ack(Result), + %% Ugly trick relying on that we will exit soon; + %% the parent will wait for us to exit before returning Result + _ = catch proc_lib:init_fail(Result, {throw, ok}), unlink(Config#config.parent_pid), Config#config{parent_pid = undefined, polite_ack = true}; true -> @@ -739,7 +741,9 @@ terminate(Config, Req, Result) -> Req#tftp_msg_req.local_filename =/= undefined -> %% Client close_port(Config, client, Req), - proc_lib:init_ack(Result2), + %% Ugly trick relying on that we will exit soon; + %% the parent will wait for us to exit before returning Result + _ = catch proc_lib:init_fail(Result2, {throw, ok}), unlink(Config#config.parent_pid), exit(normal); true -> @@ -1001,7 +1005,7 @@ do_callback(read = Fun, Config, Callback, Req) NextBlockNo = Callback#callback.block_no + 1, case catch safe_apply(Callback#callback.module, Fun, Args) of {more, Bin, NewState} when is_binary(Bin) -> - Count = Callback#callback.count + size(Bin), + Count = Callback#callback.count + byte_size(Bin), Callback2 = Callback#callback{state = NewState, block_no = NextBlockNo, count = Count}, @@ -1035,7 +1039,7 @@ do_callback({write = Fun, Bin}, Config, Callback, Req) NextBlockNo = Callback#callback.block_no + 1, case catch safe_apply(Callback#callback.module, Fun, Args) of {more, NewState} -> - Count = Callback#callback.count + size(Bin), + Count = Callback#callback.count + byte_size(Bin), Callback2 = Callback#callback{state = NewState, block_no = NextBlockNo, count = Count}, @@ -1112,9 +1116,9 @@ do_callback({abort, Error}, _Config, undefined, _Req) when is_record(Error, tftp peer_info(#config{udp_host = Host, udp_port = Port}) -> if - is_tuple(Host), size(Host) =:= 4 -> + tuple_size(Host) =:= 4 -> {inet, tftp_lib:host_to_string(Host), Port}; - is_tuple(Host), size(Host) =:= 8 -> + tuple_size(Host) =:= 8 -> {inet6, tftp_lib:host_to_string(Host), Port}; true -> {undefined, Host, Port} @@ -1336,7 +1340,7 @@ print_debug_info(#config{debug_level = Level} = Config, Who, Where, Data) -> end. do_print_debug_info(Config, Who, Where, #tftp_msg_data{data = Bin} = Msg) when is_binary(Bin) -> - Msg2 = Msg#tftp_msg_data{data = {bytes, size(Bin)}}, + Msg2 = Msg#tftp_msg_data{data = {bytes, byte_size(Bin)}}, do_print_debug_info(Config, Who, Where, Msg2); do_print_debug_info(Config, Who, Where, #tftp_msg_req{local_filename = Filename} = Msg) when is_binary(Filename) -> Msg2 = Msg#tftp_msg_req{local_filename = binary}, diff --git a/lib/tftp/src/tftp_file.erl b/lib/tftp/src/tftp_file.erl index 5922fc9418c2..b6fb97bfb53e 100644 --- a/lib/tftp/src/tftp_file.erl +++ b/lib/tftp/src/tftp_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2018. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -67,7 +67,7 @@ %% PeerType = inet | inet6 %% PeerHost = ip_address() %% PeerPort = integer() -%% Acess = read | write +%% Access = read | write %% Filename = string() %% Mode = string() %% SuggestedOptions = [{Key, Value}] @@ -118,7 +118,7 @@ prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(I %% PeerType = inet | inet6 %% PeerHost = ip_address() %% PeerPort = integer() -%% Acess = read | write +%% Access = read | write %% Filename = string() %% Mode = string() %% SuggestedOptions = [{Key, Value}] @@ -135,10 +135,10 @@ prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(I %% %% Opens a file for read or write access. %% -%% On the client side where the open/4 call has been preceeded by a +%% On the client side where the open/4 call has been preceded by a %% call to prepare/4, all options must be accepted or rejected. -%% On the server side, where there are no preceeding prepare/4 call, -%% noo new options may be added, but the ones that are present as +%% On the server side, where there are no preceding prepare/4 call, +%% no new options may be added, but the ones that are present as %% SuggestedOptions may be omitted or replaced with new values %% in the AcceptedOptions. %%------------------------------------------------------------------- @@ -211,12 +211,12 @@ file_error(Reason) when is_atom(Reason) -> read(#state{access = read} = State) -> BlkSize = State#state.blksize, case file:read(State#state.fd, BlkSize) of - {ok, Bin} when is_binary(Bin), size(Bin) =:= BlkSize -> - Count = State#state.count + size(Bin), + {ok, Bin} when is_binary(Bin), byte_size(Bin) =:= BlkSize -> + Count = State#state.count + byte_size(Bin), {more, Bin, State#state{count = Count}}; - {ok, Bin} when is_binary(Bin), size(Bin) < BlkSize -> + {ok, Bin} when is_binary(Bin), byte_size(Bin) < BlkSize -> _ = file:close(State#state.fd), - Count = State#state.count + size(Bin), + Count = State#state.count + byte_size(Bin), {last, Bin, Count}; eof -> {last, <<>>, State#state.count}; @@ -248,7 +248,7 @@ read(State) -> %%------------------------------------------------------------------- write(Bin, #state{access = write} = State) when is_binary(Bin) -> - Size = size(Bin), + Size = byte_size(Bin), BlkSize = State#state.blksize, case file:write(State#state.fd, Bin) of ok when Size =:= BlkSize-> diff --git a/lib/tftp/src/tftp_lib.erl b/lib/tftp/src/tftp_lib.erl index 407a273f58a7..7c55462c48a7 100644 --- a/lib/tftp/src/tftp_lib.erl +++ b/lib/tftp/src/tftp_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2018. All Rights Reserved. +%% Copyright Ericsson AB 2005-2023. 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. @@ -94,9 +94,9 @@ do_parse_config([{Key, Val} | Tail], Config) when is_record(Config, config) -> if is_list(Val) -> do_parse_config(Tail, Config#config{udp_host = Val}); - is_tuple(Val), size(Val) =:= 4 -> + tuple_size(Val) =:= 4 -> do_parse_config(Tail, Config#config{udp_host = Val}); - is_tuple(Val), size(Val) =:= 8 -> + tuple_size(Val) =:= 8 -> do_parse_config(Tail, Config#config{udp_host = Val}); true -> exit({badarg, {Key, Val}}) diff --git a/lib/tftp/test/Makefile b/lib/tftp/test/Makefile index 77ec425bac9c..a3caf4532141 100644 --- a/lib/tftp/test/Makefile +++ b/lib/tftp/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -152,6 +152,7 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin ERL_COMPILE_FLAGS += \ $(INCLUDES) \ $(TFTP_FLAGS) +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets @@ -161,7 +162,7 @@ ERL_COMPILE_FLAGS += \ # 1) TFTP_PRIV_DIR must be created # ---------------------------------------------------- -tests debug opt: $(BUILDTARGET) +tests $(TYPES): $(BUILDTARGET) targets: $(TARGET_FILES) diff --git a/lib/tftp/vsn.mk b/lib/tftp/vsn.mk index d762b85845e8..8c81f083ccd6 100644 --- a/lib/tftp/vsn.mk +++ b/lib/tftp/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = tftp -TFTP_VSN = 1.0.3 +TFTP_VSN = 1.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(TFTP_VSN)$(PRE_VSN)" diff --git a/lib/tools/Makefile b/lib/tools/Makefile index b8625d8074a9..ebdac6156d1d 100644 --- a/lib/tools/Makefile +++ b/lib/tools/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2022. 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. @@ -24,7 +24,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # ---------------------------------------------------- -SUB_DIRECTORIES = c_src src doc/src examples emacs +SUB_DIRECTORIES = src doc/src examples emacs include vsn.mk VSN = $(TOOLS_VSN) @@ -37,5 +37,6 @@ SPECIAL_TARGETS = include $(ERL_TOP)/make/otp_subdir.mk DIA_PLT_APPS=compiler runtime_tools +TEST_NEEDS_RELEASE=true include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/tools/c_src/Makefile b/lib/tools/c_src/Makefile deleted file mode 100644 index 0cdc50e6f5a7..000000000000 --- a/lib/tools/c_src/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Invoke with GNU make or clearmake -C gnu. -# - -include $(ERL_TOP)/make/run_make.mk - diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in deleted file mode 100644 index 878aa2cde61b..000000000000 --- a/lib/tools/c_src/Makefile.in +++ /dev/null @@ -1,221 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2009-2020. 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% -# - -include $(ERL_TOP)/make/output.mk -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/erts/include/internal/$(TARGET)/ethread.mk - -USING_VC=@MIXED_VC@ - -CC=@CC@ -LD=@LD@ -AR=@AR@ -RANLIB=@RANLIB@ -MKDIR=@MKDIR@ -INSTALL=@INSTALL@ -INSTALL_DIR=@INSTALL_DIR@ -INSTALL_DATA=@INSTALL_DATA@ -INSTALL_PROGRAM=@INSTALL_PROGRAM@ -LDFLAGS=@LDFLAGS@ - -ifeq ($(TYPE),debug) -CFLAGS = @DEBUG_CFLAGS@ -DDEBUG -TYPEMARKER=.debug -PRE_LD = -ifeq ($(TARGET),win32) -LDFLAGS += -g -endif -else -override TYPE=opt -CFLAGS = @CFLAGS@ -PRE_LD = -TYPEMARKER = -endif - -ifeq ($(findstring -D_GNU_SOURCE,$(CFLAGS)),) -THR_DEFS = $(ETHR_DEFS) -else -# Remove duplicate -D_GNU_SOURCE -THR_DEFS = $(filter-out -D_GNU_SOURCE%, $(ETHR_DEFS)) -endif - -LIBS=@LIBS@ -CREATE_DIRS= - -TT_DIR=$(TARGET)/$(TYPE) - -BIN_DIR=../bin/$(TARGET) -OBJ_DIR=../obj/$(TT_DIR) - -CREATE_DIRS += $(BIN_DIR) $(OBJ_DIR) - -PROGS= -DRIVERS= - - -# -# emem sources, objects, includes, libs, etc... -# - - -ifneq ($(strip $(ETHR_LIB_NAME)),) -# Need ethread package for emem -PROGS += $(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@ -endif - -EMEM_OBJ_DIR=$(OBJ_DIR)/emem -CREATE_DIRS += $(EMEM_OBJ_DIR) - -EMEM_INCLUDES = -I$(ERL_TOP)/erts/include \ - -I$(ERL_TOP)/erts/include/$(TARGET) \ - -I$(ERL_TOP)/erts/include/internal \ - -I$(ERL_TOP)/erts/include/internal/$(TARGET) - -EMEM_HEADERS = erl_memory_trace_block_table.h -EMEM_SRCS = erl_memory.c erl_memory_trace_block_table.c - -EMEM_CFLAGS = $(THR_DEFS) $(subst O2,O3, $(CFLAGS)) $(EMEM_INCLUDES) -EMEM_LDFLAGS = $(LDFLAGS) - -ifeq ($(USING_VC), yes) -ifeq ($(TYPE),debug) -MT_LIB=MDd -else -MT_LIB=MD -endif - -EMEM_CFLAGS += -$(MT_LIB) -EMEM_LDFLAGS += -$(MT_LIB) -EMEM_ERTS_LIB=erts_$(MT_LIB)$(TYPEMARKER) - -else - -EMEM_ERTS_LIB=erts_r$(TYPEMARKER) - -endif - -EMEM_ETHR_LIBS=$(subst -l$(ETHR_LIB_NAME),-l$(ETHR_LIB_NAME)$(TYPEMARKER),$(subst -lerts_internal_r,-lerts_internal_r$(TYPEMARKER),$(ETHR_LIBS))) - -EMEM_LIBS = $(LIBS) \ - -L$(ERL_TOP)/erts/lib/$(TARGET) \ - -L$(ERL_TOP)/erts/lib/internal/$(TARGET) \ - -l$(EMEM_ERTS_LIB) \ - $(EMEM_ETHR_LIBS) - -EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o))) - -ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE - -# -# Misc targets -# - -_create_dirs := $(shell mkdir -p $(CREATE_DIRS)) - -all: $(PROGS) $(DRIVERS) - -$(ERTS_LIB): - $(make_verbose)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) - - -docs: - -clean: - $(RM) -r ../obj/* - $(RM) -r ../bin/* - $(RM) ./*~ - -.PHONY: all erts_lib docs clean - -# -# Object targets -# - -$(EMEM_OBJ_DIR)/%.o: %.c - $(V_CC) $(EMEM_CFLAGS) -o $@ -c $< - -# -# Driver targets -# - -# -# Program targets -# - -$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB) - $(ld_verbose)$(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS) - -# -# Release targets -# -include $(ERL_TOP)/make/otp_release_targets.mk -include ../vsn.mk -RELSYSDIR = $(RELEASE_PATH)/lib/tools-$(TOOLS_VSN) - -release_spec: all - $(INSTALL_DIR) "$(RELSYSDIR)/c_src" - $(INSTALL_DATA) $(EMEM_SRCS) $(EMEM_HEADERS) "$(RELSYSDIR)/c_src" -ifneq ($(PROGS),) - $(INSTALL_DIR) "$(RELSYSDIR)/bin" - $(INSTALL_PROGRAM) $(PROGS) "$(RELSYSDIR)/bin" -endif - -release_docs_spec: - -.PHONY: release_spec release_docs_spec - -# -# Make dependencies -# - -ifeq ($(USING_VC), yes) -DEP_CC=@EMU_CC@ -else -DEP_CC=$(CC) -endif - -SED_REPL_EMEM_OBJ_DIR=s|^\([^:]*\)\.o:|$$(EMEM_OBJ_DIR)/\1.o:|g -SED_REPL_OBJ_DIR=s|^\([^:]*\)\.o:|$$(OBJ_DIR)/\1.o:|g -SED_REPL_TT_DIR=s|$(TT_DIR)/|$$(TT_DIR)/|g -SED_REPL_TARGET=s|$(TARGET)/|$$(TARGET)/|g -SED_REPL_ERL_TOP=s|$(ERL_TOP)/|$$(ERL_TOP)/|g - -SED_EMEM_DEPEND=sed '$(SED_REPL_EMEM_OBJ_DIR);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET);$(SED_REPL_ERL_TOP)' -SED_DEPEND=sed '$(SED_REPL_OBJ_DIR);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET);$(SED_REPL_ERL_TOP)' - -DEPEND_MK=depend.mk - -dep depend: - [ $(v_p) == 0 ] && echo " GEN "$(DEPEND_MK) - $(V_colon)@echo "Generating dependency file $(DEPEND_MK)..." - @echo "# Generated dependency rules." > $(DEPEND_MK); - @echo "# Do *not* edit this file; instead, run 'make depend'." \ - >> $(DEPEND_MK); - @echo "# " >> $(DEPEND_MK); - @echo "# emem objects..." >> $(DEPEND_MK); - $(DEP_CC) -MM $(EMEM_CFLAGS) $(EMEM_SRCS) \ - | $(SED_EMEM_DEPEND) >> $(DEPEND_MK) - @echo "# EOF" >> $(DEPEND_MK); - -.PHONY: dep depend - -include $(DEPEND_MK) - -# eof diff --git a/lib/tools/c_src/depend.mk b/lib/tools/c_src/depend.mk deleted file mode 100644 index 01da30e7c6f8..000000000000 --- a/lib/tools/c_src/depend.mk +++ /dev/null @@ -1,17 +0,0 @@ -# Generated dependency rules. -# Do *not* edit this file; instead, run 'make depend'. -# -# emem objects... -$(EMEM_OBJ_DIR)/erl_memory.o: erl_memory.c \ - $(ERL_TOP)/erts/include/erl_fixed_size_int_types.h \ - $(ERL_TOP)/erts/include/$(TARGET)/erl_int_sizes_config.h \ - $(ERL_TOP)/erts/include/erl_memory_trace_parser.h \ - erl_memory_trace_block_table.h \ - $(ERL_TOP)/erts/include/internal/ethread.h \ - $(ERL_TOP)/erts/include/internal/$(TARGET)/ethread_header_config.h -$(EMEM_OBJ_DIR)/erl_memory_trace_block_table.o: erl_memory_trace_block_table.c \ - erl_memory_trace_block_table.h \ - $(ERL_TOP)/erts/include/erl_fixed_size_int_types.h \ - $(ERL_TOP)/erts/include/$(TARGET)/erl_int_sizes_config.h \ - $(ERL_TOP)/erts/include/erl_memory_trace_parser.h -# EOF diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c deleted file mode 100644 index bbd4b3f2efe8..000000000000 --- a/lib/tools/c_src/erl_memory.c +++ /dev/null @@ -1,2947 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2021. 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% - */ - -/* - * Description: - * - * Author: Rickard Green - */ - -/* Headers to include ... */ - -#ifdef __WIN32__ -# include -# undef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# include -typedef int socklen_t; -#else -# if defined(__linux__) && defined(__GNUC__) -# define _GNU_SOURCE 1 -# endif -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include -#include -#include - -#include "erl_fixed_size_int_types.h" -#include "erl_memory_trace_parser.h" -#include "erl_memory_trace_block_table.h" -#include "ethread.h" - -/* Increment when changes are made */ -#define EMEM_VSN_STR "0.9" - -/* Features not fully implemented yet */ -#define EMEM_A_SWITCH 0 -#define EMEM_C_SWITCH 0 -#define EMEM_c_SWITCH 0 -#define EMEM_d_SWITCH 0 - -/* Some system specific defines ... */ -#ifdef __WIN32__ -# define ssize_t int -# define GET_SOCK_ERRNO() (WSAGetLastError() - WSABASEERR) -# define IS_INVALID_SOCKET(X) ((X) == INVALID_SOCKET) -# ifdef __GNUC__ -# define INLINE __inline__ -# else -# define INLINE __forceinline -# endif -# define DIR_SEP_CHAR '\\' -#else -# define SOCKET int -# define closesocket close -# define GET_SOCK_ERRNO() (errno ? errno : INT_MAX) -# define INVALID_SOCKET (-1) -# define IS_INVALID_SOCKET(X) ((X) < 0) -# ifdef __GNUC__ -# define INLINE __inline__ -# else -# define INLINE -# endif -# define DIR_SEP_CHAR '/' -#endif - -#define EM_ERL_CMD_FILE_NAME "erl_cmd.txt" -#define EM_OUTPUT_FILE_SUFFIX ".emem" - -#define PRINT_OPERATIONS 0 - -/* In VC++, noreturn is a declspec that has to be before the types, - * but in GNUC it is an attribute to be placed between return type - * and function name, hence __decl_noreturn __noreturn - * - * at some platforms (e.g. Android) __noreturn is defined at sys/cdef.h - */ -#if __GNUC__ -# define __decl_noreturn -# ifndef __noreturn -# define __noreturn __attribute__((noreturn)) -# endif -#else -# if defined(__WIN32__) && defined(_MSC_VER) -# define __noreturn -# define __decl_noreturn __declspec(noreturn) -# else -# define __noreturn -# define __decl_noreturn -# endif -#endif - -/* Our own assert() ... */ -#ifdef DEBUG -#define ASSERT(A) ((A) ? (void)1 : assert_failed(__FILE__, __LINE__, #A)) -#include -__decl_noreturn static void __noreturn assert_failed(char *f, int l, char *a) -{ - fprintf(stderr, "%s:%d: Assertion failed: %s\n", f, l, a); - abort(); -} - -#else -#define ASSERT(A) ((void) 1) -#endif - -#define ERR_RET(X) return (X) -#if 1 -# undef ERR_RET -# define ERR_RET(X) abort() -#endif - -/* #define HARD_DEBUG */ - - -#define EM_EXIT_RESULT (EMTBT_MIN_ERROR - 1) -#define EM_TRUNCATED_TRACE_ERROR (EMTBT_MIN_ERROR - 2) -#define EM_INTERNAL_ERROR (EMTBT_MIN_ERROR - 3) - -#define EM_DEFAULT_BUF_SZ 8192 - -#define EM_LINES_UNTIL_HEADER 20 -#define EM_NO_OF_OPS 400 -#define EM_MAX_CONSECUTIVE_TRACE_READS 10 -#define EM_MAX_NO_OF_TRACE_BUFS 1280 -#define EM_MIN_TRACE_READ_SIZE (EM_DEFAULT_BUF_SZ/20) -#define EM_TIME_FIELD_WIDTH 11 - -__decl_noreturn static void __noreturn error(int res); -__decl_noreturn static void __noreturn error_msg(int res, char *msg); - -typedef struct { - usgnd_int_max size; - usgnd_int_max min_size; - usgnd_int_max max_size; - usgnd_int_max max_ever_size; - usgnd_int_max no; - usgnd_int_max min_no; - usgnd_int_max max_no; - usgnd_int_max max_ever_no; - usgnd_int_max allocs; - usgnd_int_max reallocs; - usgnd_int_max frees; -} em_mem_info; - -typedef struct em_buffer_ { - struct em_buffer_ *next; - int write; - char *data; - char *data_end; - char *end; - size_t size; - char start[EM_DEFAULT_BUF_SZ]; -} em_buffer; - -typedef struct { - int no_writer; - int no_reader; - size_t tot_buf_size; - size_t max_buf_size; - char *name; - em_buffer *first; - em_buffer *last; - ethr_mutex mutex; - ethr_cond cond; - int used_def_buf_a; - em_buffer def_buf_a; - int used_def_buf_b; - em_buffer def_buf_b; -} em_buf_queue; - -typedef struct { - char *ptr; - size_t size; -} em_area; - -typedef struct { - char *name; - int ix; -} em_output_types; - -typedef struct { - - /* Memory allocation functions */ - void * (*alloc)(size_t); - void * (*realloc)(void *, size_t); - void (*free)(void *); - - emtbt_table *block_table; - emtbt_table **carrier_table; - - struct { - em_mem_info total; - em_mem_info *btype; - em_mem_info *allctr; - em_mem_info **allctr_prv_crr; - em_mem_info **allctr_usd_crr; - - struct { - usgnd_int_32 secs; - usgnd_int_32 usecs; - } stop_time; - emtp_op_type stop_reason; - usgnd_int_32 exit_status; - } info; - - /* Input ... */ - struct { - usgnd_int_16 listen_port; - SOCKET socket; - usgnd_int_max total_trace_size; - int error; - char *error_descr; - em_buf_queue queue; - } input; - - /* Output ... */ - struct { - usgnd_int_32 next_print; - usgnd_int_32 next_print_inc; - char *header; - size_t header_size; - size_t values_per_object; - size_t values_per_line; - size_t field_width; - int verbose; - int total; - int all_allctrs; - int no_allctrs; - em_output_types *allctrs; - int all_btypes; - int no_btypes; - em_output_types *btypes; - int max_min_values; - int block_counts; - int op_counts; - int lines_until_header; - FILE *stream; - char *file_name; -#if EMEM_d_SWITCH - char *dir_name; - FILE *erl_cmd_file; - struct { - ethr_mutex *mutex; - ethr_cond *cond; - } go; -#endif - em_buf_queue queue; - } output; - - /* Trace info */ - emtp_state *trace_state; - emtp_info trace_info; - -} em_state; - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * Threads... * - * * -\* */ - -static INLINE void -mutex_init(ethr_mutex *mtx) -{ - int res = ethr_mutex_init(mtx); - if (res) - error_msg(res, "Mutex init"); -} - -static INLINE void -mutex_destroy(ethr_mutex *mtx) -{ - int res = ethr_mutex_destroy(mtx); - if (res) - error_msg(res, "Mutex destroy"); -} - -static INLINE void -mutex_lock(ethr_mutex *mtx) -{ - ethr_mutex_lock(mtx); -} - -static INLINE void -mutex_unlock(ethr_mutex *mtx) -{ - ethr_mutex_unlock(mtx); -} - -static INLINE void -cond_init(ethr_cond *cnd) -{ - int res = ethr_cond_init(cnd); - if (res) - error_msg(res, "Cond init"); -} - -static INLINE void -cond_destroy(ethr_cond *cnd) -{ - int res = ethr_cond_destroy(cnd); - if (res) - error_msg(res, "Cond destroy"); -} - -static INLINE void -cond_wait(ethr_cond *cnd, ethr_mutex *mtx) -{ - int res = ethr_cond_wait(cnd, mtx); - if (res != 0 && res != EINTR) - error_msg(res, "Cond wait"); -} - -static INLINE void -cond_signal(ethr_cond *cnd) -{ - ethr_cond_signal(cnd); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * Buffer queues * - * * -\* */ - -static INLINE void -reset_buffer(em_buffer *b, size_t size) -{ - b->write = 1; - b->next = NULL; - if (size) { - b->size = size; - b->end = b->start + size; - } - b->data_end = b->data = b->start; -} - -static void -init_queue(em_state *state, em_buf_queue *queue) -{ - reset_buffer(&queue->def_buf_a, EM_DEFAULT_BUF_SZ); - reset_buffer(&queue->def_buf_b, EM_DEFAULT_BUF_SZ); - queue->first = NULL; - queue->last = NULL; - queue->no_writer = 0; - queue->no_reader = 0; - queue->tot_buf_size = 0; - queue->max_buf_size = ~0; - queue->name = ""; - queue->used_def_buf_a = 0; - queue->used_def_buf_b = 0; - mutex_init(&queue->mutex); - cond_init(&queue->cond); -} - -static void -destroy_queue(em_state *state, em_buf_queue *queue) -{ - while (queue->first) { - em_buffer *buf = queue->first; - queue->first = queue->first->next; - if (buf != &queue->def_buf_a && buf != &queue->def_buf_b) - (*state->free)((void *) buf); - } - mutex_destroy(&queue->mutex); - cond_destroy(&queue->cond); -} - -static void -disconnect_queue_writer(em_buf_queue *queue) -{ - mutex_lock(&queue->mutex); - queue->no_writer = 1; - cond_signal(&queue->cond); - mutex_unlock(&queue->mutex); -} - -static void -disconnect_queue_reader(em_buf_queue *queue) -{ - mutex_lock(&queue->mutex); - queue->no_reader = 1; - cond_signal(&queue->cond); - mutex_unlock(&queue->mutex); -} - -static int -is_queue_writer_disconnected(em_buf_queue *queue) -{ - int res; - mutex_lock(&queue->mutex); - res = queue->no_writer; - mutex_unlock(&queue->mutex); - return res; -} - -static int -is_queue_reader_disconnected(em_buf_queue *queue) -{ - int res; - mutex_lock(&queue->mutex); - res = queue->no_reader; - mutex_unlock(&queue->mutex); - return res; -} - -static INLINE void -dequeue(em_state *state, em_buf_queue *queue) -{ - em_buffer *buf; - - ASSERT(queue->first); - ASSERT(queue->tot_buf_size > 0); - - buf = queue->first; - queue->first = buf->next; - if (!queue->first) - queue->last = NULL; - - ASSERT(queue->tot_buf_size >= buf->size); - queue->tot_buf_size -= buf->size; - - if (buf == &queue->def_buf_a) - queue->used_def_buf_a = 0; - else if (buf == &queue->def_buf_b) - queue->used_def_buf_b = 0; - else - (*state->free)((void *) buf); - -} - - -static INLINE em_buffer * -enqueue(em_state *state, em_buf_queue *queue, size_t min_size) -{ - em_buffer *buf; - - if (min_size > EM_DEFAULT_BUF_SZ) - goto alloc_buf; - - if (!queue->used_def_buf_a) { - buf = &queue->def_buf_a; - queue->used_def_buf_a = 1; - reset_buffer(buf, 0); - } - else if (!queue->used_def_buf_b) { - buf = &queue->def_buf_b; - queue->used_def_buf_b = 1; - reset_buffer(buf, 0); - } - else { - size_t bsize; - alloc_buf: - - bsize = EM_DEFAULT_BUF_SZ; - if (bsize < min_size) - bsize = min_size; - - buf = (em_buffer *) (*state->alloc)(sizeof(em_buffer) - + (sizeof(char) - * (bsize-EM_DEFAULT_BUF_SZ))); - if (!buf) - error(ENOMEM); - buf->size = bsize; - reset_buffer(buf, bsize); - } - - if (queue->last) { - ASSERT(queue->first); - queue->last->write = 0; - queue->last->next = buf; - } - else { - ASSERT(!queue->first); - queue->first = buf; - } - - queue->tot_buf_size += buf->size; - queue->last = buf; - - return buf; -} - -static void -get_next_read_area(em_area *area, em_state *state, em_buf_queue *queue) -{ - mutex_lock(&queue->mutex); - - while (!queue->first || queue->first->data == queue->first->data_end) { - if (queue->first && (!queue->first->write - || queue->first->data == queue->first->end)) { - dequeue(state, queue); - continue; - } - - if (queue->no_writer) { - area->ptr = NULL; - area->size = 0; - mutex_unlock(&queue->mutex); - return; - } - cond_wait(&queue->cond, &queue->mutex); - } - - ASSERT(queue->first->data < queue->first->data_end); - - area->ptr = queue->first->data; - area->size = queue->first->data_end - queue->first->data; - - queue->first->data = queue->first->data_end; - - mutex_unlock(&queue->mutex); -} - -static INLINE void -wrote_area_aux(em_area *area, em_state *state, em_buf_queue *queue, int do_lock) -{ - em_buffer *buf; - - if (do_lock) - mutex_lock(&queue->mutex); - - buf = queue->last; - - ASSERT(area->ptr); - ASSERT(area->size); - - ASSERT(buf); - ASSERT(buf->data_end == area->ptr); - ASSERT(buf->end >= area->ptr + area->size); - - buf->data_end = area->ptr + area->size; - - area->ptr = NULL; - area->size = 0; - - cond_signal(&queue->cond); - - if (do_lock) - mutex_unlock(&queue->mutex); -} - -static INLINE void -wrote_area(em_area *area, em_state *state, em_buf_queue *queue) -{ - wrote_area_aux(area, state, queue, 1); -} - -static void -get_next_write_area(em_area *area, em_state *state, em_buf_queue *queue, - size_t size) -{ - em_buffer *buf; - - mutex_lock(&queue->mutex); - - ASSERT(!area->size || area->ptr); - - if (area->size) - wrote_area_aux(area, state, queue, 0); - - buf = ((queue->last && queue->last->end - queue->last->data_end >= size) - ? queue->last - : enqueue(state, queue, size)); - - ASSERT(buf); - ASSERT(buf->end - buf->data_end >= size); - area->ptr = buf->data_end; - area->size = buf->end - buf->data_end; - - if (queue->tot_buf_size > queue->max_buf_size) { - fprintf(stderr, - "emem: Maximum %s buffer size (%lu) exceeded. " - "Terminating...\n", - queue->name, - (unsigned long) queue->max_buf_size); - exit(1); - } - - mutex_unlock(&queue->mutex); - -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * Output * - * * -\* */ - -static INLINE size_t -write_str(char **dstpp, char *srcp) -{ - size_t i = 0; - if (dstpp) - while (srcp[i]) - *((*dstpp)++) = srcp[i++]; - else - while (srcp[i]) i++; - return i; -} - - -static size_t -write_strings(char **ptr, - char **strings, - char *first_line_prefix, - char *line_prefix, - size_t max_line_size) -{ - size_t size; - size_t tot_size = 0; - size_t line_size = 0; - size_t line_prefix_size; - sgnd_int_32 ix; - - tot_size = line_size = line_prefix_size = write_str(ptr, first_line_prefix); - - for (ix = 0; strings[ix]; ix++) { - size = write_str(NULL, strings[ix]); - if (line_size + 1 + size > max_line_size) { - tot_size += write_str(ptr, "\n"); - tot_size += write_str(ptr, line_prefix); - line_size = line_prefix_size; - } - tot_size += write_str(ptr, " "); - tot_size += ptr ? write_str(ptr, strings[ix]) : size; - line_size += 1 + size; - } - - tot_size += write_str(ptr, "\n"); - - return tot_size; -} - -static size_t -write_title(char **bufp, size_t *overflow, size_t width, char *str) -{ - size_t i, sz, ws; - char *p, *endp; - - /* - * Writes at least one '|' character at the beginning. - * Right aligns "str". - * If "str" is larger than "width - 1" and overflow is NULL, - * then "str" is trucated; otherwise, string is not truncated. - */ - - if (width <= 0) - return 0; - - if (!bufp && !overflow) - return width; - - sz = strlen(str) + 1; - if (sz > width) { - ws = 0; - if (overflow) - *overflow += sz - width; - else - sz = width; - } - else { - ws = width - sz; - if (overflow) { - if (ws >= *overflow) { - ws -= *overflow; - *overflow = 0; - } - else { - *overflow -= ws; - ws = 0; - } - } - sz += ws; - } - if (!bufp) - return sz; - - p = *bufp; - endp = p + width; - - *(p++) = '|'; - while (ws > 1) { - ws--; - *(p++) = ' '; - } - - i = 0; - while (str[i] && (overflow || p < endp)) - *(p++) = str[i++]; - - while (ws) { - ws--; - *(p++) = ' '; - } - - ASSERT(overflow || p == endp); - ASSERT(sz == (size_t) (p - *bufp)); - *bufp = p; - return sz; -} - -static size_t -write_obj_sub_titles(em_state *state, char **bufp, size_t *overflow) -{ - size_t field_width = state->output.field_width; - size_t size = write_title(bufp, overflow, field_width, "size"); - if (state->output.max_min_values) { - size += write_title(bufp, overflow, field_width, "min size"); - size += write_title(bufp, overflow, field_width, "max size"); - } - if (state->output.block_counts) { - size += write_title(bufp, overflow, field_width, "no"); - if (state->output.max_min_values) { - size += write_title(bufp, overflow, field_width, "min no"); - size += write_title(bufp, overflow, field_width, "max no"); - } - } - if (state->output.op_counts) { - size += write_title(bufp, overflow, field_width, "alloc()"); - size += write_title(bufp, overflow, field_width, "realloc()"); - size += write_title(bufp, overflow, field_width, "free()"); - } - - return size; -} - -static size_t -write_header(em_state *state, char *ptr, int trunc) -{ -#define MIN_LTEXT_SZ 18 -#define HEADER_EOL_STR "|\n" - char *p; - char **pp; - int i; - size_t overflow; - size_t *ofp; - size_t obj_size = state->output.values_per_object*state->output.field_width; - size_t size = 0; - int have_seg_crr = state->trace_info.have_segment_carrier_info; - - if (ptr) { - p = ptr; - pp = &p; - } - else { - p = NULL; - pp = NULL; - } - - overflow = 0; - ofp = trunc ? NULL : &overflow; - - size += write_title(pp, ofp, EM_TIME_FIELD_WIDTH, "time"); - - if (state->output.total) { - int no = 1; - if (have_seg_crr) { - if (state->info.allctr_prv_crr[state->trace_info.segment_ix]) - no++; - if (state->info.allctr_usd_crr[state->trace_info.segment_ix]) - no++; - } - size += write_title(pp, ofp, (have_seg_crr ? 3 : 1)*obj_size, "total"); - } - - for (i = 0; i < state->output.no_allctrs; i++) { - int no = 1; - if (state->info.allctr_prv_crr[state->output.allctrs[i].ix]) - no++; - if (state->info.allctr_usd_crr[state->output.allctrs[i].ix]) - no++; - size += write_title(pp, ofp, no*obj_size, state->output.allctrs[i].name); - } - - for (i = 0; i < state->output.no_btypes; i++) - size += write_title(pp, ofp, obj_size, state->output.btypes[i].name); - - size += write_str(pp, HEADER_EOL_STR); - - overflow = 0; - size += write_title(pp, ofp, EM_TIME_FIELD_WIDTH, ""); - - if (state->output.total) { - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "alcd blks" - : "allocated blocks")); - if (have_seg_crr) { - if (state->info.allctr_prv_crr[state->trace_info.segment_ix]) - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "mpd segs" - : "mapped segments")); - if (state->info.allctr_usd_crr[state->trace_info.segment_ix]) - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "chd segs" - : "cached segments")); - } - } - - for (i = 0; i < state->output.no_allctrs; i++) { - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "alcd blks" - : "allocated blocks")); - if (state->info.allctr_prv_crr[state->output.allctrs[i].ix]) - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "prvd crrs" - : "provided carriers")); - if (state->info.allctr_usd_crr[state->output.allctrs[i].ix]) - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "usd crrs" - : "used carriers")); - } - for (i = 0; i < state->output.no_btypes; i++) - size += write_title(pp, ofp, obj_size, (obj_size <= MIN_LTEXT_SZ - ? "alcd blks" - : "allocated blocks")); - - - size += write_str(pp, HEADER_EOL_STR); - overflow = 0; - size += write_title(pp, ofp, EM_TIME_FIELD_WIDTH, ""); - - if (state->output.total) { - size += write_obj_sub_titles(state, pp, ofp); - if (have_seg_crr) { - if (state->info.allctr_prv_crr[state->trace_info.segment_ix]) - size += write_obj_sub_titles(state, pp, ofp); - if (state->info.allctr_usd_crr[state->trace_info.segment_ix]) - size += write_obj_sub_titles(state, pp, ofp); - } - } - - for (i = 0; i < state->output.no_allctrs; i++) { - size += write_obj_sub_titles(state, pp, ofp); - if (state->info.allctr_prv_crr[state->output.allctrs[i].ix]) - size += write_obj_sub_titles(state, pp, ofp); - if (state->info.allctr_usd_crr[state->output.allctrs[i].ix]) - size += write_obj_sub_titles(state, pp, ofp); - } - - for (i = 0; i < state->output.no_btypes; i++) - size += write_obj_sub_titles(state, pp, ofp); - - size += write_str(pp, HEADER_EOL_STR); -#undef MIN_LTEXT_SZ -#undef HEADER_EOL_STR - return size; -} - -static INLINE void -write_mem_info(em_state *state, char **p, em_mem_info *mi) -{ - int fw = state->output.field_width - 1; - *p += sprintf(*p, "%*" USGND_INT_MAX_FSTR " ", fw, mi->size); - if (state->output.max_min_values) - *p += sprintf(*p, - "%*" USGND_INT_MAX_FSTR - " %*" USGND_INT_MAX_FSTR " ", - fw, mi->min_size, - fw, mi->max_size); - if (state->output.block_counts) { - *p += sprintf(*p, "%*" USGND_INT_MAX_FSTR " ", fw, mi->no); - if (state->output.max_min_values) - *p += sprintf(*p, - "%*" USGND_INT_MAX_FSTR - " %*" USGND_INT_MAX_FSTR " ", - fw, mi->min_no, - fw, mi->max_no); - } - if (state->output.op_counts) - *p += sprintf(*p, - "%*" USGND_INT_MAX_FSTR - " %*" USGND_INT_MAX_FSTR - " %*" USGND_INT_MAX_FSTR " ", - fw, mi->allocs, - fw, mi->reallocs, - fw, mi->frees); - - /* Update max ever values */ - if (mi->max_ever_size < mi->max_size) - mi->max_ever_size = mi->max_size; - if (mi->max_ever_no < mi->max_no) - mi->max_ever_no = mi->max_no; - /* Reset max/min values */ - mi->max_size = mi->min_size = mi->size; - mi->max_no = mi->min_no = mi->no; -} - -static INLINE void -write_max_ever_mem_info(em_state *state, char **p, em_mem_info *mi) -{ - int fw = state->output.field_width - 1; - *p += sprintf(*p, "%*" USGND_INT_MAX_FSTR " ", fw, mi->max_ever_size); - if (state->output.max_min_values) - *p += sprintf(*p, "%*s %*s ", fw, "", fw, ""); - if (state->output.block_counts) { - *p += sprintf(*p, "%*" USGND_INT_MAX_FSTR " ", fw, mi->max_ever_no); - if (state->output.max_min_values) - *p += sprintf(*p, "%*s %*s ", fw, "", fw, ""); - } - if (state->output.op_counts) - *p += sprintf(*p, "%*s %*s %*s ", fw, "", fw, "", fw, ""); -} - -static void -print_string(em_state *state, char *str) -{ - em_area area = {NULL, 0}; - char *p; - - /* Get area */ - - get_next_write_area(&area,state,&state->output.queue,write_str(NULL,str)); - - p = area.ptr; - area.size = write_str(&p, str); - - /* Leave area */ - - wrote_area(&area, state, &state->output.queue); - -} - -static int -print_emu_arg(em_state *state) -{ - em_area area = {NULL, 0}; - char hostname[100]; - char carg[22]; - struct sockaddr_in saddr; - struct hostent *hp; - struct in_addr iaddr; - usgnd_int_16 port; - socklen_t saddr_size = sizeof(saddr); - size_t size; - char *format = "> Emulator command line argument: +Mit %s\n"; - -#ifdef __clang_analyzer__ - /* CodeChecker does not seem to understand getsockname writes to saddr */ - memset(&saddr, 0, sizeof(saddr)); -#endif - if (getsockname(state->input.socket, - (struct sockaddr *) &saddr, - &saddr_size) != 0) - goto error; - - port = ntohs(saddr.sin_port); - - ASSERT(state->input.listen_port == 0 || state->input.listen_port == port); - - state->input.listen_port = port; - - if (gethostname(hostname, sizeof(hostname)) != 0) - goto error; - - hp = gethostbyname(hostname); - if (!hp) - goto error; - - if (hp->h_addr_list) { - (void) memcpy(&iaddr.s_addr, *hp->h_addr_list, sizeof(iaddr.s_addr)); - (void) sprintf(carg, "%s:%d", inet_ntoa(iaddr), (int) port); - } - else - (void) sprintf(carg, "127.0.0.1:%d", (int) port); - -#if EMEM_d_SWITCH - - if (state->output.erl_cmd_file) { - fprintf(state->output.erl_cmd_file, "+Mit %s\n", carg); - fclose(state->output.erl_cmd_file); - state->output.erl_cmd_file = NULL; - } - -#endif - - size = strlen(format) + strlen(carg); - - /* Get area */ - - get_next_write_area(&area, state, &state->output.queue, size); - - area.size = sprintf(area.ptr, format, carg); - - /* Leave area */ - - wrote_area(&area, state, &state->output.queue); - - return 0; - - error: - return GET_SOCK_ERRNO(); -} - -static size_t -write_allocator_info(em_state *state, char *ptr) -{ - usgnd_int_32 aix, i, j; - char *header = "> Allocator information:\n"; - char *allctr_str = "> * Allocator:"; - char *crr_prv_str = "> * Carrier providers:"; - char *blk_tp_str = "> * Block types:"; - char *line_prefix = "> "; - size_t size = 0; - char **strings; - size_t strings_size; - size_t max_line_size = 80; - char *p = ptr; - char **pp = ptr ? &p : NULL; - - strings_size = state->trace_info.max_block_type_ix + 1; - if (strings_size < state->trace_info.max_allocator_ix + 1) - strings_size = state->trace_info.max_allocator_ix + 1; - - strings = (char **) (*state->alloc)((strings_size + 1)*sizeof(char *)); - if (!strings) - error(ENOMEM); - - size += write_str(pp, header); - - for (aix = 0; aix <= state->trace_info.max_allocator_ix; aix++) { - emtp_allocator *allctr = state->trace_info.allocator[aix]; - if (!allctr->valid) - continue; - - strings[0] = allctr->name; - strings[1] = NULL; - size += write_strings(pp,strings,allctr_str,line_prefix,max_line_size); - - i = 0; - if (allctr->carrier.provider) - for (j = 0; j < allctr->carrier.no_providers; j++) { - usgnd_int_32 cpix = allctr->carrier.provider[j]; - if (cpix == state->trace_info.segment_ix) - strings[i++] = "segment"; - else - strings[i++] = state->trace_info.allocator[cpix]->name; - } - strings[i] = NULL; - size += write_strings(pp,strings,crr_prv_str,line_prefix,max_line_size); - - i = 0; - for (j = 0; j <= state->trace_info.max_block_type_ix; j++) - if (state->trace_info.block_type[j]->allocator == aix) - strings[i++] = state->trace_info.block_type[j]->name; - strings[i] = NULL; - size += write_strings(pp,strings,blk_tp_str,line_prefix,max_line_size); - } - - (*state->free)((void *) strings); - - return size; -} - -static void -print_main_header(em_state *state) -{ -#if HAVE_INT_64 -#define MAX_WORD_SZ_STR "64" -#else -#define MAX_WORD_SZ_STR "32" -#endif - em_area area = {NULL, 0}; - char *format1 = - "> emem version: " EMEM_VSN_STR "\n" - "> Nodename: %s\n" - "> Hostname: %s\n" - "> Pid: %s\n" - "> Start time (UTC): "; - char *format2 = "%4.4" USGND_INT_32_FSTR - "-%2.2" USGND_INT_32_FSTR "-%2.2" USGND_INT_32_FSTR - " %2.2" USGND_INT_32_FSTR ":%2.2" USGND_INT_32_FSTR - ":%2.2" USGND_INT_32_FSTR ".%6.6" USGND_INT_32_FSTR "\n"; - char *format3 = - "> Trace parser version: %" USGND_INT_32_FSTR ".%" USGND_INT_32_FSTR - "\n" - "> Actual trace version: %" USGND_INT_32_FSTR ".%" USGND_INT_32_FSTR - "\n" - "> Maximum trace word size: " MAX_WORD_SZ_STR " bits\n" - "> Actual trace word size: %d bits\n"; - size_t size = (strlen(format1) + - (state->trace_info.start_time.month - ? (strlen(format2) + 7*10) - : 1) - + strlen(format3) - + strlen(state->trace_info.nodename) - + strlen(state->trace_info.hostname) - + strlen(state->trace_info.pid) - + 5*10 + 1); - - if (state->output.verbose) { - size += write_allocator_info(state, NULL); - } - - size += write_header(state, NULL, 0); - - /* Get area */ - get_next_write_area(&area, state, &state->output.queue, size); - - area.size = sprintf(area.ptr, - format1, - state->trace_info.nodename, - state->trace_info.hostname, - state->trace_info.pid); - if (state->trace_info.start_time.month) - area.size += sprintf(area.ptr + area.size, - format2, - state->trace_info.start_time.year, - state->trace_info.start_time.month, - state->trace_info.start_time.day, - state->trace_info.start_time.hour, - state->trace_info.start_time.minute, - state->trace_info.start_time.second, - state->trace_info.start_time.micro_second); - else - *(area.ptr + area.size++) = '\n'; - area.size += sprintf(area.ptr + area.size, - format3, - state->trace_info.version.parser.major, - state->trace_info.version.parser.minor, - state->trace_info.version.trace.major, - state->trace_info.version.trace.minor, - state->trace_info.bits); - - if (state->output.verbose) { - area.size += write_allocator_info(state, area.ptr + area.size); - } - - area.size += write_header(state, area.ptr + area.size, 0); - - /* Leave area */ - wrote_area(&area, state, &state->output.queue); -#undef MAX_WORD_SZ_STR -} - -static void -print_main_footer(em_state *state) -{ - em_area area = {NULL, 0}; - char *p; - int i; - char *stop_str = - "> Trace stopped\n"; - char *exit_str = - "> Emulator exited with code: %" USGND_INT_32_FSTR "\n"; - char *format = - "> Total trace size: %" USGND_INT_MAX_FSTR " bytes\n" - "> Average band width used: %" USGND_INT_MAX_FSTR " Kbit/s\n"; - size_t size; - usgnd_int_max tsz = state->input.total_trace_size; - usgnd_int_32 secs = state->info.stop_time.secs; - usgnd_int_32 usecs = state->info.stop_time.usecs; - usgnd_int_max bw; - - /* Max size of the max value line. Each value can at most use 21 - characters: largest possible usgnd_int_64 (20 digits) and one - white space. */ - size = state->output.values_per_line*21 + 1; - - switch (state->info.stop_reason) { - case EMTP_STOP: - size += strlen(stop_str) + 1; - break; - case EMTP_EXIT: - size += strlen(exit_str); - size += 10; /* Enough for one unsgn_int_32 */ - size++; - break; - default: - break; - } - size += strlen(format); - size += 2*20; /* Enough for two unsgn_int_64 */ - size += 2; - - bw = (tsz + 1023)/1024; - bw *= 1000; - bw /= secs*1000 + usecs/1000; - bw *= 8; - - /* Get area */ - - get_next_write_area(&area, state, &state->output.queue, size); - - p = area.ptr; - - p += sprintf(p, "> %-*s", EM_TIME_FIELD_WIDTH - 2, "Maximum:"); - - if (state->output.total) { - int six = state->trace_info.segment_ix; - write_max_ever_mem_info(state, &p, &state->info.total); - if (state->trace_info.have_segment_carrier_info) { - if (state->info.allctr_prv_crr[six]) - write_max_ever_mem_info(state, - &p, - state->info.allctr_prv_crr[six]); - if (state->info.allctr_usd_crr[six]) - write_max_ever_mem_info(state, - &p, - state->info.allctr_usd_crr[six]); - } - } - for (i = 0; i < state->output.no_allctrs; i++) { - int ix = state->output.allctrs[i].ix; - write_max_ever_mem_info(state, &p, &state->info.allctr[ix]); - if (state->info.allctr_prv_crr[ix]) - write_max_ever_mem_info(state, - &p, - state->info.allctr_prv_crr[ix]); - if (state->info.allctr_usd_crr[ix]) - write_max_ever_mem_info(state, - &p, - state->info.allctr_usd_crr[ix]); - } - for (i = 0; i < state->output.no_btypes; i++) - write_max_ever_mem_info(state, - &p, - &state->info.btype[state->output.btypes[i].ix]); - - p += sprintf(p, "\n"); - - switch (state->info.stop_reason) { - case EMTP_STOP: - p += sprintf(p, "%s", stop_str); - break; - case EMTP_EXIT: - p += sprintf(p, exit_str, state->info.exit_status); - break; - default: - break; - } - - p += sprintf(p, format, tsz, bw); - - area.size = p - area.ptr; - - ASSERT(area.size <= size); - - /* Leave area */ - - wrote_area(&area, state, &state->output.queue); - -} - -static void -print_info(em_state *state, usgnd_int_32 secs, char *extra) -{ - char *p; - int i; - size_t size; - em_area area = {NULL, 0}; - - /* Get area */ - - size = 0; - if (!state->output.lines_until_header) - size += state->output.header_size; - - /* Max size of one line of values. Each value can at most use 21 - characters: largest possible usgnd_int_64 (20 digits) and one white - space. */ - size += state->output.values_per_line*21 + 1; - - if (extra) - size += write_str(NULL, extra); - - get_next_write_area(&area, state, &state->output.queue, size); - - /* Write to area */ - - p = area.ptr; - - if (!state->output.lines_until_header) { - memcpy((void *) area.ptr, - (void *) state->output.header, - state->output.header_size); - p += state->output.header_size; - state->output.lines_until_header = EM_LINES_UNTIL_HEADER; - } - else - state->output.lines_until_header--; - - p += sprintf(p, "%*" USGND_INT_32_FSTR " ", EM_TIME_FIELD_WIDTH - 1, secs); - - if (state->output.total) { - int six = state->trace_info.segment_ix; - write_mem_info(state, &p, &state->info.total); - if (state->trace_info.have_segment_carrier_info) { - if (state->info.allctr_prv_crr[six]) - write_mem_info(state, &p, state->info.allctr_prv_crr[six]); - if (state->info.allctr_usd_crr[six]) - write_mem_info(state, &p, state->info.allctr_usd_crr[six]); - } - } - for (i = 0; i < state->output.no_allctrs; i++) { - int ix = state->output.allctrs[i].ix; - write_mem_info(state, &p, &state->info.allctr[ix]); - if (state->info.allctr_prv_crr[ix]) - write_mem_info(state, &p, state->info.allctr_prv_crr[ix]); - if (state->info.allctr_usd_crr[ix]) - write_mem_info(state, &p, state->info.allctr_usd_crr[ix]); - } - for (i = 0; i < state->output.no_btypes; i++) - write_mem_info(state, - &p, - &state->info.btype[state->output.btypes[i].ix]); - - p += sprintf(p, "\n"); - - if (extra) - p += write_str(&p, extra); - - ASSERT(area.size >= p - area.ptr); - area.size = p - area.ptr; - - /* Leave area */ - - wrote_area(&area, state, &state->output.queue); -} - -static void -reset_mem_info(em_mem_info *mi) -{ - mi->size = 0; - mi->min_size = 0; - mi->max_size = 0; - mi->max_ever_size = 0; - mi->no = 0; - mi->min_no = 0; - mi->max_no = 0; - mi->max_ever_no = 0; - mi->allocs = 0; - mi->reallocs = 0; - mi->frees = 0; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * State creation and destruction * - * * -\* */ - -static void -destroy_state(em_state *state) -{ - int i; - void (*freep)(void *); - - freep = state->free; - - if (state->block_table) - emtbt_destroy_table(state->block_table); - - if (state->carrier_table) { - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - if (state->carrier_table[i]) - emtbt_destroy_table(state->carrier_table[i]); - state->carrier_table--; - (*freep)((void *) state->carrier_table); - } - - if (state->info.btype) { - state->info.btype--; - (*freep)((void *) state->info.btype); - } - - if (state->info.allctr) { - state->info.allctr--; - (*freep)((void *) state->info.allctr); - } - - if (state->info.allctr_prv_crr) { - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - if (state->info.allctr_prv_crr[i]) - (*freep)((void *) state->info.allctr_prv_crr[i]); - state->info.allctr_prv_crr--; - (*freep)((void *) state->info.allctr_prv_crr); - } - - - if (state->info.allctr_usd_crr) { - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - if (state->info.allctr_usd_crr[i]) - (*freep)((void *) state->info.allctr_usd_crr[i]); - state->info.allctr_usd_crr--; - (*freep)((void *) state->info.allctr_usd_crr); - } - - emtp_state_destroy(state->trace_state); - destroy_queue(state, &state->input.queue); - - if (state->output.btypes) - (*freep)((void *) state->output.btypes); - if (state->output.allctrs) - (*freep)((void *) state->output.allctrs); - destroy_queue(state, &state->output.queue); - -#if EMEM_d_SWITCH - - if (state->output.go.mutex) { - mutex_destroy(state->output.go.mutex); - (*state->free)((void *) state->output.go.mutex); - state->output.go.mutex = NULL; - } - if (state->output.go.cond) { - cond_destroy(state->output.go.cond); - (*state->free)((void *) state->output.go.cond); - state->output.go.cond = NULL; - } - -#endif - - if (!IS_INVALID_SOCKET(state->input.socket)) { - closesocket(state->input.socket); - state->input.socket = INVALID_SOCKET; - } - - (*freep)((void *) state); -} - -static em_state * -new_state(void * (*alloc)(size_t), - void * (*realloc)(void *, size_t), - void (*free)(void *)) -{ - em_state *state = NULL; - - state = (*alloc)(sizeof(em_state)); - if (!state) - goto error; - - /* Stuff that might fail (used after the error label) */ - - state->trace_state = NULL; - - /* Init state ... */ - - state->alloc = alloc; - state->realloc = realloc; - state->free = free; - - state->block_table = NULL; - state->carrier_table = NULL; - - reset_mem_info(&state->info.total); - state->info.btype = NULL; - state->info.allctr = NULL; - - state->info.allctr_prv_crr = NULL; - state->info.allctr_usd_crr = NULL; - - state->info.stop_time.secs = 0; - state->info.stop_time.usecs = 0; - state->info.stop_reason = EMTP_UNDEF; - state->info.exit_status = 0; - - state->output.next_print = 0; - state->output.next_print_inc = 10; - state->output.header = NULL; - state->output.header_size = 0; - state->output.values_per_object = 0; - state->output.values_per_line = 0; - state->output.field_width = 11; - state->output.verbose = 0; - state->output.total = 0; - state->output.all_allctrs = 0; - state->output.no_allctrs = 0; - state->output.allctrs = NULL; - state->output.all_btypes = 0; - state->output.no_btypes = 0; - state->output.btypes = NULL; - state->output.max_min_values = 0; - state->output.block_counts = 0; - state->output.op_counts = 0; - state->output.lines_until_header = EM_LINES_UNTIL_HEADER; - -#if PRINT_OPERATIONS - state->output.stream = stderr; -#else - state->output.stream = stdout; -#endif - state->output.file_name = NULL; -#if EMEM_d_SWITCH - state->output.dir_name = NULL; - state->output.erl_cmd_file = NULL; - state->output.go.mutex = NULL; - state->output.go.cond = NULL; -#endif - - init_queue(state, &state->output.queue); - state->output.queue.max_buf_size = 10*1024*1024; - state->output.queue.name = "output"; - - state->trace_state = emtp_state_new(alloc, realloc, free); - if (!state->trace_state) - goto error; - - state->trace_info.version.parser.major = 0; - state->trace_info.version.parser.minor = 0; - state->trace_info.version.trace.major = 0; - state->trace_info.version.trace.minor = 0; - state->trace_info.bits = 0; - state->trace_info.max_allocator_ix = 0; - state->trace_info.allocator = NULL; - state->trace_info.max_block_type_ix = 0; - state->trace_info.block_type = NULL; - - state->input.listen_port = 0; - state->input.socket = INVALID_SOCKET; - state->input.total_trace_size = 0; - state->input.error = 0; - state->input.error_descr = NULL; - - init_queue(state, &state->input.queue); - state->input.queue.max_buf_size = 10*1024*1024; - state->input.queue.name = "input"; - - return state; - - error: - if (state) { - if (state->trace_state) - emtp_state_destroy(state->trace_state); - (*free)(state); - } - return NULL; -} - - -static emtbt_table * -mk_block_table(em_state *state) -{ - return emtbt_new_table(state->trace_info.bits == 64, - state->alloc, - state->realloc, - state->free); -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * * - * * -\* */ -#if PRINT_OPERATIONS -void print_op(em_state *state, emtp_operation *op); -#endif - -static INLINE void -update_max_values(em_mem_info *mi) -{ - if (mi->max_size < mi->size) - mi->max_size = mi->size; - if (mi->max_no < mi->no) - mi->max_no = mi->no; -} - -static INLINE void -update_min_values(em_mem_info *mi) -{ - if (mi->min_size > mi->size) - mi->min_size = mi->size; - if (mi->min_no > mi->no) - mi->min_no = mi->no; -} - -static INLINE void -update_alloc_op(em_mem_info *mi, usgnd_int_max size) -{ - mi->allocs++; - mi->size += size; - mi->no++; - update_max_values(mi); -} - -static INLINE void -update_realloc_op(em_mem_info *mi, - usgnd_int_max size, - usgnd_int_max prev_size, - int no_change) -{ - mi->reallocs++; - ASSERT(mi->size >= prev_size); - mi->size -= prev_size; - mi->size += size; - if (no_change) { - if (no_change > 0) - mi->no++; - else { - ASSERT(mi->no > 0); - mi->no--; - } - } - update_max_values(mi); - update_min_values(mi); -} - -static INLINE void -update_free_op(em_mem_info *mi, usgnd_int_max prev_size) -{ - mi->frees++; - ASSERT(mi->size >= prev_size); - mi->size -= prev_size; - ASSERT(mi->no > 0); - mi->no--; - update_min_values(mi); -} - -static int -insert_operations(em_state *state, emtp_operation ops[], size_t len) -{ - emtbt_table *crr_table; - emtbt_block old_blk; - usgnd_int_32 prev_size; - usgnd_int_max size; - size_t i; - int res; - int aix, btix, crrix; - - for (i = 0; i < len; i++) { - - while (state->output.next_print <= ops[i].time.secs) { - print_info(state, state->output.next_print, NULL); - state->output.next_print += state->output.next_print_inc; - } - - switch (ops[i].type) { - - case EMTP_ALLOC: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - btix = (int) ops[i].u.block.type; - aix = state->trace_info.block_type[btix]->allocator; - - if (!ops[i].u.block.new_ptr) - continue; - - res = emtbt_alloc_op(state->block_table, &ops[i]); - if (res != 0) - ERR_RET(res); - - size = ops[i].u.block.new_size; - - update_alloc_op(&state->info.btype[btix], size); - update_alloc_op(&state->info.allctr[aix], size); - update_alloc_op(&state->info.total, size); - break; - - case EMTP_REALLOC: { - int no; -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - - res = emtbt_realloc_op(state->block_table, &ops[i], &old_blk); - if (res != 0) - ERR_RET(res); - - size = ops[i].u.block.new_size; - prev_size = old_blk.size; - - if (!ops[i].u.block.prev_ptr) - btix = (int) ops[i].u.block.type; - else - btix = (int) old_blk.type; - aix = state->trace_info.block_type[btix]->allocator; - - no = ((!old_blk.pointer && ops[i].u.block.new_ptr) - ? 1 - : ((old_blk.pointer && !ops[i].u.block.new_size) - ? -1 - : 0)); - - update_realloc_op(&state->info.btype[btix], size, prev_size, no); - update_realloc_op(&state->info.allctr[aix], size, prev_size, no); - update_realloc_op(&state->info.total, size, prev_size, no); - - break; - } - case EMTP_FREE: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - - if (!ops[i].u.block.prev_ptr) - continue; - - res = emtbt_free_op(state->block_table, &ops[i], &old_blk); - if (res != 0) - ERR_RET(res); - - prev_size = old_blk.size; - btix = (int) old_blk.type; - aix = state->trace_info.block_type[btix]->allocator; - - - update_free_op(&state->info.btype[btix], prev_size); - update_free_op(&state->info.allctr[aix], prev_size); - update_free_op(&state->info.total, prev_size); - - break; - - case EMTP_CARRIER_ALLOC: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - - aix = (int) ops[i].u.block.type; - - crrix = (int) ops[i].u.block.carrier_type; - if (!state->carrier_table[crrix]) { - state->carrier_table[crrix] = mk_block_table(state); - if (!state->carrier_table[crrix]) - ERR_RET(ENOMEM); - } - crr_table = state->carrier_table[crrix]; - - if (!ops[i].u.block.new_ptr) - continue; - - res = emtbt_alloc_op(crr_table, &ops[i]); - if (res != 0) - ERR_RET(res); - - size = ops[i].u.block.new_size; - - if (state->info.allctr_usd_crr[aix]) - update_alloc_op(state->info.allctr_usd_crr[aix], size); - if (state->info.allctr_prv_crr[crrix]) - update_alloc_op(state->info.allctr_prv_crr[crrix], size); - update_alloc_op(&state->info.allctr[crrix], size); - - break; - - case EMTP_CARRIER_REALLOC: { - int no; -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - - crrix = (int) ops[i].u.block.carrier_type; - if (!state->carrier_table[crrix]) { - state->carrier_table[crrix] = mk_block_table(state); - if (!state->carrier_table[crrix]) - ERR_RET(ENOMEM); - } - crr_table = state->carrier_table[crrix]; - - res = emtbt_realloc_op(crr_table, &ops[i], &old_blk); - if (res != 0) - ERR_RET(res); - - size = ops[i].u.block.new_size; - prev_size = old_blk.size; - - if (!ops[i].u.block.prev_ptr) - aix = (int) ops[i].u.block.type; - else - aix = (int) old_blk.type; - - - no = ((!old_blk.pointer && ops[i].u.block.new_ptr) - ? 1 - : ((old_blk.pointer && !ops[i].u.block.new_size) - ? -1 - : 0)); - - if (state->info.allctr_usd_crr[aix]) - update_realloc_op(state->info.allctr_usd_crr[aix], - size, - prev_size, - no); - if (state->info.allctr_prv_crr[crrix]) - update_realloc_op(state->info.allctr_prv_crr[crrix], - size, - prev_size, - no); - update_realloc_op(&state->info.allctr[crrix], - size, - prev_size, - no); - break; - } - case EMTP_CARRIER_FREE: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - - crrix = (int) ops[i].u.block.carrier_type; - crr_table = state->carrier_table[crrix]; - if (!crr_table) - ERR_RET(EMTBT_FREE_NOBLK_ERROR); - - if (!ops[i].u.block.prev_ptr) - continue; - - res = emtbt_free_op(crr_table, &ops[i], &old_blk); - if (res != 0) - ERR_RET(res); - - prev_size = old_blk.size; - aix = (int) old_blk.type; - - if (state->info.allctr_usd_crr[aix]) - update_free_op(state->info.allctr_usd_crr[aix], prev_size); - if (state->info.allctr_prv_crr[crrix]) - update_free_op(state->info.allctr_prv_crr[crrix], prev_size); - update_free_op(&state->info.allctr[crrix], prev_size); - - break; - - case EMTP_STOP: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - state->info.stop_reason = EMTP_STOP; - state->info.stop_time.secs = ops[i].time.secs; - state->info.stop_time.usecs = ops[i].time.usecs; - print_info(state, ops[i].time.secs, NULL); - return EM_EXIT_RESULT; - case EMTP_EXIT: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - state->info.stop_reason = EMTP_EXIT; - state->info.exit_status = ops[i].u.exit_status; - state->info.stop_time.secs = ops[i].time.secs; - state->info.stop_time.usecs = ops[i].time.usecs; - print_info(state, ops[i].time.secs, NULL); - return EM_EXIT_RESULT; - default: -#if PRINT_OPERATIONS - print_op(state, &ops[i]); -#endif - /* Ignore not understood operation */ - break; - } - } - return 0; -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * * - * * -\* */ - -static const char * -error_string(int error) -{ - const char *str; - const char *error_str; - static const char unknown_error[] = "Unknown error"; - - error_str = unknown_error; - - if (error > 0) { - const char *str = strerror(error); - if (str) - error_str = str; - } - else if (error < 0) { - str = emtp_error_string(error); - if (!str) { - str = emtbt_error_string(error); - if (!str) { - switch (error) { - case EM_TRUNCATED_TRACE_ERROR: - error_str = "Truncated trace"; - break; - case EM_INTERNAL_ERROR: - error_str = "emem internal error"; - break; - default: - break; - } - } - } - - if (str) - error_str = str; - } - - return error_str; -} - -__decl_noreturn static void __noreturn -error(int res) -{ - error_msg(res, NULL); -} - -__decl_noreturn static void __noreturn -error_msg(int res, char *msg) -{ - fprintf(stderr, - "emem: %s%sFatal error: %s (%d)\n", - msg ? msg : "", - msg ? ": ": "", - error_string(res), - res); - exit(1); -} - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * * - * * -\* */ - -#if EMEM_d_SWITCH - -static size_t -write_output_filename(char *ptr, - char *dirname, - char *nodename, - char *hostname, - char *datetime, - char *pid) -{ - size_t sz = 0; - char *p = ptr; - char **pp = ptr ? &p : NULL; - sz += write_str(pp, dirname); - if (pp) *((*pp)++) = DIR_SEP_CHAR; - sz++; - sz += write_str(pp, nodename); - sz += write_str(pp, "_"); - sz += write_str(pp, hostname); - sz += write_str(pp, "_"); - sz += write_str(pp, datetime); - sz += write_str(pp, "_"); - sz += write_str(pp, pid); - sz += write_str(pp, EM_OUTPUT_FILE_SUFFIX); - if (pp) *((*pp)++) = '\0'; - sz++; - return sz; -} - -static char * -make_output_filename(em_state *state) -{ - char *fname; - size_t fname_size; - char *nodename = state->trace_info.nodename; - char *hostname = state->trace_info.hostname; - char *pid = state->trace_info.pid; - char dt_buf[20]; - char *date_time = NULL; - - if (*nodename == '\0') - nodename = "nonode"; - if (*hostname == '\0') - hostname = "nohost"; - if (!state->trace_info.start_time.day) - date_time = "notime"; - else { - sprintf(dt_buf, - "%d-%2.2d-%2.2d_%2.2d.%2.2d.%2.2d", - state->trace_info.start_time.year % 10000, - state->trace_info.start_time.month % 100, - state->trace_info.start_time.day % 100, - state->trace_info.start_time.hour % 100, - state->trace_info.start_time.minute % 100, - state->trace_info.start_time.second % 100); - date_time = &dt_buf[0]; - } - if (*pid == '\0') - pid = "nopid"; - - fname = (*state->alloc)(write_output_filename(NULL, - state->output.dir_name, - nodename, - hostname, - date_time, - pid)); - if (!fname) - return NULL; - - (void) write_output_filename(fname, - state->output.dir_name, - nodename, - hostname, - date_time, - pid); - return fname; -} - -#endif - -static int -complete_state(em_state *state) -{ - int i, j, vpo, vpl; - void * (*allocp)(size_t); - void * (*reallocp)(void *, size_t); - size_t size = sizeof(emtp_info); - - if (!emtp_get_info(&state->trace_info, &size, state->trace_state) - || size < sizeof(emtp_info)) - return EM_INTERNAL_ERROR; - -#if EMEM_d_SWITCH - - if (!state->output.stream) { - char *fname = make_filename(state); - mutex_lock(state->output.go.mutex); - state->output.stream = fopen(fname, "w"); - if (!state->output.stream) { - disconnect_queue_reader(&state->input.queue); - disconnect_queue_writer(&state->output.queue); - } - cond_signal(state->output.go.cond); - mutex_unlock(state->output.go.mutex); - (*state->free)((void *) fname); - if (!state->output.stream) - return EIO; - } - -#endif - - allocp = state->alloc; - reallocp = state->realloc; - - state->carrier_table = (*allocp)((state->trace_info.max_allocator_ix+2) - * sizeof(emtbt_table *)); - if (!state->carrier_table) - return ENOMEM; - state->carrier_table++; - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - state->carrier_table[i] = NULL; - - - state->block_table = mk_block_table(state); - state->info.btype = (*allocp)((state->trace_info.max_block_type_ix+2) - * sizeof(em_mem_info)); - state->info.allctr = (*allocp)((state->trace_info.max_allocator_ix+2) - * sizeof(em_mem_info)); - if (!state->block_table || !state->info.btype || !state->info.allctr) - return ENOMEM; - - state->info.btype++; - state->info.allctr++; - - state->info.allctr_prv_crr - = (*allocp)((state->trace_info.max_allocator_ix+2) - * sizeof(em_mem_info *)); - if (!state->info.allctr_prv_crr) - return ENOMEM; - state->info.allctr_prv_crr++; - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - state->info.allctr_prv_crr[i] = NULL; - - state->info.allctr_usd_crr - = (*allocp)((state->trace_info.max_allocator_ix+2) - * sizeof(em_mem_info *)); - if (!state->info.allctr_usd_crr) - return ENOMEM; - state->info.allctr_usd_crr++; - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) - state->info.allctr_usd_crr[i] = NULL; - - if (state->output.all_btypes) { - if (state->output.btypes) - (*state->free)((void *) state->output.btypes); - state->output.no_btypes = state->trace_info.max_block_type_ix + 2; - state->output.btypes = (*allocp)(state->output.no_btypes - * sizeof(em_output_types)); - if (!state->output.btypes) - return ENOMEM; - } - - if (state->output.all_allctrs) { - if (state->output.allctrs) - (*state->free)((void *) state->output.allctrs); - state->output.no_allctrs = state->trace_info.max_allocator_ix + 2; - state->output.allctrs = (*allocp)(state->output.no_allctrs - * sizeof(em_output_types)); - if (!state->output.allctrs) - return ENOMEM; - } - - for (i = -1; i <= state->trace_info.max_block_type_ix; i++) { - /* Save block type if we should print info about it */ - emtp_block_type *btp = state->trace_info.block_type[i]; - reset_mem_info(&state->info.btype[i]); - if (state->output.no_btypes) { - if (state->output.all_btypes) { - state->output.btypes[i+1].name = btp->name; - state->output.btypes[i+1].ix = btp->valid ? i : -1; - } - else { - for (j = 0; j < state->output.no_btypes; j++) - if (strcmp(btp->name, state->output.btypes[j].name) == 0) { - state->output.btypes[j].ix = i; - break; - } - } - } - } - - /* Remove invalid block types */ - if (state->output.no_btypes) { - for (i = 0, j = 0; i < state->output.no_btypes; i++) { - if (state->output.btypes[i].ix >= 0) { - state->output.btypes[j].name = state->output.btypes[i].name; - state->output.btypes[j].ix = state->output.btypes[i].ix; - j++; - } - } - state->output.no_btypes = j; - } - - for (i = -1; i <= state->trace_info.max_allocator_ix; i++) { - /* Save allocator if we should print info about it */ - emtp_allocator *ap = state->trace_info.allocator[i]; - reset_mem_info(&state->info.allctr[i]); - if (state->output.no_allctrs) { - if (state->output.all_allctrs) { - state->output.allctrs[i+1].name = ap->name; - state->output.allctrs[i+1].ix = ap->valid ? i : -1; - } - else { - for (j = 0; j < state->output.no_allctrs; j++) - if (strcmp(ap->name, state->output.allctrs[j].name) == 0) { - state->output.allctrs[j].ix = i; - break; - } - } - } - - /* Allocate em_mem_info if used carrier info is available */ - if (ap->flags & EMTP_ALLOCATOR_FLAG_HAVE_USED_CARRIERS_INFO - || (i == state->trace_info.segment_ix - && state->trace_info.have_segment_carrier_info)) { - state->info.allctr_usd_crr[i] - = (em_mem_info *) (*allocp)(sizeof(em_mem_info)); - if (!state->info.allctr_usd_crr[i]) - return ENOMEM; - reset_mem_info(state->info.allctr_usd_crr[i]); - } - - /* Allocate em_mem_info for carrier providers */ - if (ap->carrier.provider) { - sgnd_int_32 j; - for (j = 0; j < ap->carrier.no_providers; j++) { - sgnd_int_32 crr_prvdr = ap->carrier.provider[j]; - if (!state->info.allctr_prv_crr[crr_prvdr]) { - state->info.allctr_prv_crr[crr_prvdr] - = (em_mem_info *) (*allocp)(sizeof(em_mem_info)); - if (!state->info.allctr_prv_crr[crr_prvdr]) - return ENOMEM; - reset_mem_info(state->info.allctr_prv_crr[crr_prvdr]); - } - } - } - } - - /* Remove invalid allocators */ - if (state->output.no_allctrs) { - for (i = 0, j = 0; i < state->output.no_allctrs; i++) { - if (state->output.allctrs[i].ix >= 0) { - state->output.allctrs[j].name = state->output.allctrs[i].name; - state->output.allctrs[j].ix = state->output.allctrs[i].ix; - j++; - } - } - state->output.no_allctrs = j; - } - - if (state->output.no_btypes) { - state->output.btypes = (*reallocp)(state->output.btypes, - sizeof(em_output_types) - * state->output.no_btypes); - if (!state->output.btypes) - return ENOMEM; - } - - if (state->output.no_allctrs) { - state->output.allctrs = (*reallocp)(state->output.allctrs, - sizeof(em_output_types) - * state->output.no_allctrs); - if (!state->output.allctrs) - return ENOMEM; - } - - - vpo = 1; - if (state->output.max_min_values) - vpo += 2; - if (state->output.block_counts) { - vpo++; - if (state->output.max_min_values) - vpo += 2; - } - if (state->output.op_counts) - vpo += 3; - - state->output.values_per_object = vpo; - - vpl = 0; - vpl++; /* time */ - if (state->output.total) { - vpl += vpo; /* total allocated */ - if (state->trace_info.have_segment_carrier_info) { - vpl += vpo; /* total carriers */ - vpl += vpo; /* cached carriers */ - } - } - for (i = 0; i < state->output.no_allctrs; i++) { - vpl += vpo; /* allocated */ - if (state->trace_info.have_carrier_info) { - if (state->info.allctr_prv_crr[state->output.allctrs[i].ix]) - vpl += vpo; /* provided carriers */ - vpl += vpo; /* used carriers */ - } - } - vpl += state->output.no_btypes*vpo; /* allocated */ - - state->output.values_per_line = vpl; - - state->output.header_size = write_header(state, NULL, 1); - state->output.header = (*state->alloc)(state->output.header_size + 1); - if (!state->output.header) - return ENOMEM; - size = write_header(state, state->output.header, 1); - ASSERT(state->output.header_size == size); - return 0; -} - -static int -process_trace(em_state *state) -{ - emtp_operation ops[EM_NO_OF_OPS]; - int res; - size_t ops_len; - em_area area; - - while (1) { - get_next_read_area(&area, state, &state->input.queue); - if (!area.size) - return EM_TRUNCATED_TRACE_ERROR; - res = emtp_parse(state->trace_state, - (usgnd_int_8 **)&area.ptr, &area.size, - NULL, 0, NULL); - if (res == EMTP_HEADER_PARSED) - break; - if (res == EMTP_NEED_MORE_TRACE) - continue; - - if (res < 0) - return res; - else - return EM_TRUNCATED_TRACE_ERROR; - } - - res = complete_state(state); - if (res != 0) - return res; - - print_main_header(state); - - while (1) { - if (!area.size) { - get_next_read_area(&area, state, &state->input.queue); - if (!area.size) - return EM_TRUNCATED_TRACE_ERROR; - - } - - - while (area.size) { - ops_len = EM_NO_OF_OPS; - res = emtp_parse(state->trace_state, - (usgnd_int_8 **)&area.ptr, &area.size, - ops, sizeof(emtp_operation), &ops_len); - if (res < 0) - return res; - - res = insert_operations(state, ops, ops_len); - if (res != 0) - return res; - - } - - } - -} - -static void -usage(char *sw, char *error) -{ - FILE *filep = stdout; -#ifdef __WIN32__ -#define SW_CHAR "/" -#else -#define SW_CHAR "-" -#endif - - if (error) { - ASSERT(sw); - filep = stderr; - fprintf(filep, "emem: %s: %s\n", sw, error); - } - fprintf(filep, - "Usage: emem " -#if EMEM_A_SWITCH - "[" SW_CHAR "A ] " -#endif - "[" SW_CHAR "a ] " - "[" SW_CHAR "b ] " -#if EMEM_C_SWITCH - "[" SW_CHAR "C ] " -#endif -#if EMEM_c_SWITCH - "[" SW_CHAR "c ] " -#endif - "{" -#if EMEM_d_SWITCH - SW_CHAR "d |" -#endif - SW_CHAR "f } " - "[" SW_CHAR "h] " - "[" SW_CHAR "i ] " - "[" SW_CHAR "m] " - "[" SW_CHAR "n] " - "[" SW_CHAR "o] " - "{" SW_CHAR "p } " - "[" SW_CHAR "t] " - "[" SW_CHAR "v] " - "\n"); - if (error) - exit(1); - else { - fprintf(filep, - "\n" - " [] - switch is allowed any number of times\n" - " {} - switch is allowed at most one time\n" -#if EMEM_d_SWITCH - " | - exclusive or\n" -#endif - "\n" - " Switches:\n" -#if EMEM_A_SWITCH - " " SW_CHAR "a - display info about Allocator and all block types using \n" -#endif - " " SW_CHAR "a - display info about allocator \n" - " " SW_CHAR "b - display info about block type \n" -#if EMEM_C_SWITCH - " " SW_CHAR "C - display info about class and all block types in class \n" -#endif -#if EMEM_c_SWITCH - " " SW_CHAR "b - display info about class \n" -#endif -#if EMEM_d_SWITCH - " " SW_CHAR "d - run as daemon and set output directory to \n" -#endif - " " SW_CHAR "f - set output file to \n" - " " SW_CHAR "h - display help and exit\n" - " " SW_CHAR "i - set display interval to seconds\n" - " " SW_CHAR "m - display max/min values\n" - " " SW_CHAR "n - display block/carrier/segment count values\n" - " " SW_CHAR "o - display operation count values\n" - " " SW_CHAR "p

    - set listen port to

    \n" - " " SW_CHAR "t - display info about total values\n" - " " SW_CHAR "v - verbose output\n"); - exit(0); - } - -#undef SW_CHAR -} - - -static void -parse_args(em_state *state, int argc, char *argv[]) -{ - int port; - int i; - - i = 1; - while (i < argc) { - if ((argv[i][0] != '-' && argv[i][0] != '/') || argv[i][2] != '\0') { - unknown_switch: - usage(argv[i], "unknown switch"); - } - - switch (argv[i][1]) { -#if EMEM_A_SWITCH - case 'A': /* TODO: Allocator + blocktypes using allocator */ -#endif - case 'a': - if (i + 1 >= argc) - usage(argv[i], "missing allocator"); - i++; - if (state->output.all_allctrs || strcmp(argv[i],"all") == 0) { - state->output.all_allctrs = 1; - break; - } - - if (!state->output.allctrs) - state->output.allctrs - = (*state->alloc)(sizeof(em_output_types)*argc/2); - if (!state->output.allctrs) - error(ENOMEM); - state->output.allctrs[state->output.no_allctrs].name = argv[i]; - state->output.allctrs[state->output.no_allctrs].ix = -1; - state->output.no_allctrs++; - break; - case 'b': - if (i + 1 >= argc) - usage(argv[i], "missing block type"); - i++; - if (state->output.all_btypes || strcmp(argv[i],"all") == 0) { - state->output.all_btypes = 1; - break; - } - - if (!state->output.btypes) - state->output.btypes - = (*state->alloc)(sizeof(em_output_types)*argc/2); - if (!state->output.btypes) - error(ENOMEM); - state->output.btypes[state->output.no_btypes].name = argv[i]; - state->output.btypes[state->output.no_btypes].ix = -1; - state->output.no_btypes++; - break; -#if EMEM_C_SWITCH -#endif -#if EMEM_c_SWITCH - case 'c': - break; -#endif -#if EMEM_d_SWITCH - case 'd': { - char *p; - char *fname; - if (state->output.dir_name) - usage(argv[i], "directory already set"); - if (state->output.file_name) - usage(argv[i], "file name already set"); - if (i + 1 >= argc) - usage(argv[i], "missing directory name"); - state->output.dir_name = argv[i+1]; - fname = (*state->alloc)(strlen(state->output.dir_name) - + 1 - + strlen(EM_ERL_CMD_FILE_NAME) - + 1); - state->output.go.mutex = (*state->alloc)(sizeof(ethr_mutex)); - state->output.go.cond = (*state->alloc)(sizeof(ethr_cond)); - if (!fname || !state->output.go.mutex || !state->output.go.cond) - error(ENOMEM); - p = fname; - (void) write_str(&p, state->output.dir_name); - *(p++) = DIR_SEP_CHAR; - (void) write_str(&p, EM_ERL_CMD_FILE_NAME); - *(p++) = '\0'; - state->output.erl_cmd_file = fopen(fname, "w"); - if (!state->output.erl_cmd_file) - usage(argv[i], "cannot create files in directory"); - (*state->free)((void *) fname); - state->output.stream = NULL; - mutex_init(state->output.go.mutex); - cond_init(state->output.go.cond); - i++; - break; - } -#endif - case 'f': -#if EMEM_d_SWITCH - if (state->output.dir_name) - usage(argv[i], "directory already set"); -#endif - if (state->output.file_name) - usage(argv[i], "file name already set"); - if (i + 1 >= argc) - usage(argv[i], "missing file name"); - state->output.file_name = argv[i+1]; - state->output.stream = fopen(state->output.file_name, "w"); - if (!state->output.stream) - usage(argv[i], "cannot create file"); - if (setvbuf(state->output.stream, NULL, _IONBF, 0) != 0) { - fprintf(stderr, - "emem: failed to set file %s in unbuffered mode\n", - state->output.file_name); - exit(1); - } - i++; - break; - case 'h': - usage(NULL, NULL); - break; - case 'i': { - int interval; - if (argv[i][2]) - goto unknown_switch; - - if (i + 1 >= argc) - usage(argv[i], "missing interval"); - interval = atoi(argv[i+1]); - if (interval < 1) - usage(argv[i], "bad interval"); - i++; - state->output.next_print_inc = interval; - break; - } - case 'm': - state->output.max_min_values = 1; - break; - case 'n': - state->output.block_counts = 1; - break; - case 'o': - state->output.op_counts = 1; - break; - case 'p': - if (state->input.listen_port) - usage(argv[i], "port already set"); - if (i + 1 >= argc) - usage(argv[i], "missing port number"); - port = atoi(argv[i+1]); - if (port <= 1024 || port >= (1 << 16)) - usage(argv[i], "bad port number"); - i++; - state->input.listen_port = (usgnd_int_16) port; - break; - case 't': - state->output.total = 1; - break; - case 'v': - state->output.verbose = 1; - break; - default: - goto unknown_switch; - } - i++; - } - - if (!state->output.allctrs && !state->output.btypes) - state->output.total = 1; -} - -static int -init_connection(em_state *state) -{ - int res; - SOCKET lsock; - SOCKET sock = INVALID_SOCKET; - struct sockaddr_in my_addr; - socklen_t oth_addr_len; - struct sockaddr_in oth_addr; -#ifdef __WIN32__ - WORD wVersionRequested = MAKEWORD(2,0); - WSADATA wsaData; - - if (WSAStartup(wVersionRequested, &wsaData) != 0) - return EIO; - - if ((LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) - return EIO; -#endif - - do_socket: - sock = socket(AF_INET, SOCK_STREAM, 0); - if (IS_INVALID_SOCKET(sock)) { - res = GET_SOCK_ERRNO(); - if (res == EINTR) - goto do_socket; - goto error; - } - - memset((void *) &my_addr, 0, sizeof(struct sockaddr_in)); - - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - my_addr.sin_port = htons(state->input.listen_port); - - do_bind: - if (bind(sock, (struct sockaddr*) &my_addr, sizeof(my_addr)) < 0) { - res = GET_SOCK_ERRNO(); - if (res == EINTR) - goto do_bind; - goto error; - } - - do_listen: - if (listen(sock, 1) < 0) { - res = GET_SOCK_ERRNO(); - if (res == EINTR) - goto do_listen; - goto error; - } - - lsock = sock; - state->input.socket = sock; - - res = print_emu_arg(state); - if (res != 0) - goto error; - - print_string(state, "> Waiting for emulator to connect... "); - - do_accept: - oth_addr_len = sizeof(oth_addr); - sock = accept(lsock, (struct sockaddr *) &oth_addr, &oth_addr_len); - if (IS_INVALID_SOCKET(sock)) { - res = GET_SOCK_ERRNO(); - if (res == EINTR) - goto do_accept; - sock = lsock; - goto error; - } - - print_string(state, "connected\n"); - - closesocket(lsock); - state->input.socket = sock; - - return 0; - - error: - if (!IS_INVALID_SOCKET(sock)) { - closesocket(sock); - state->input.socket = INVALID_SOCKET; - } - return res; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * IO threads * - * * -\* */ - -/* - * The input thread reads from a socket and puts the received data - * in the input buffer queue. - * - * Note: There is intentionally no flow control. If the emem program - * cannot process data as fast as it arrives, it is supposed - * to crash when hitting the maximum buffersize; otherwise, - * the traced emulator would be slowed down. - */ -static void * -input_thread_func(void *arg) -{ - int res; - char *edescr = NULL; - ssize_t recv_sz; - usgnd_int_max total_trace_size = 0; - em_state *state = (em_state *) arg; - em_area area = {NULL, 0}; - SOCKET sock = state->input.socket; - em_buf_queue *queue = &state->input.queue; - - while(1) { - get_next_write_area(&area, - state, - queue, - EM_MIN_TRACE_READ_SIZE); - - if (!area.ptr) { - res = ENOMEM; - edescr = "Input alloc"; - goto stop; - } - - do_recv: - if (is_queue_reader_disconnected(queue)) { - res = 0; - edescr = "Input"; - goto stop; - } - recv_sz = recv(sock, (void *) area.ptr, area.size, 0); - if (recv_sz <= 0) { - res = GET_SOCK_ERRNO(); - if (res == EINTR) - goto do_recv; - edescr = "Input recv"; - goto stop; - } - area.size = (size_t) recv_sz; - total_trace_size += (usgnd_int_max) recv_sz; - } - - stop: - state->input.error = res; - state->input.error_descr = edescr; - state->input.total_trace_size = total_trace_size; - disconnect_queue_writer(queue); - if (!IS_INVALID_SOCKET(state->input.socket)) { - closesocket(sock); - state->input.socket = INVALID_SOCKET; - } - return NULL; -} - - -static void * -output_thread_func(void *arg) -{ - em_state *state = (em_state *) arg; - em_area area = {NULL, 0}; - -#if EMEM_d_SWITCH - - if (state->output.go.mutex) { - mutex_lock(state->output.go.mutex); - while (!state->output.stream - && !is_queue_writer_disconnected(&state->output.queue)) - cond_wait(state->output.go.cond, state->output.go.mutex); - mutex_unlock(state->output.go.mutex); - - mutex_destroy(state->output.go.mutex); - (*state->free)((void *) state->output.go.mutex); - state->output.go.mutex = NULL; - cond_destroy(state->output.go.cond); - (*state->free)((void *) state->output.go.cond); - state->output.go.cond = NULL; - } - -#endif - - while (1) { - get_next_read_area(&area, state, &state->output.queue); - if (!area.size) { - disconnect_queue_reader(&state->output.queue); - if (is_queue_writer_disconnected(&state->output.queue)) - goto stop; - else - error_msg(EIO, "Output queue"); - } - if (fwrite((void *) area.ptr, - sizeof(char), - area.size, - state->output.stream) != area.size) { - disconnect_queue_reader(&state->output.queue); - error_msg(0, "Write"); - } - } - - stop: - if (state->output.stream != stdout && state->output.stream != stderr) - fclose(state->output.stream); - return NULL; -} - - -int -main(int argc, char *argv[]) -{ - int res, ires, jres; - ethr_tid input_tid; - ethr_tid output_tid; - em_state *state; - - /* set stdout in unbuffered mode */ - if (setvbuf(stdout, NULL, _IONBF, 0) != 0) { - fprintf(stderr, "emem: failed to set stdout in unbuffered mode\n"); - exit(1); - } - - if (ethr_init(NULL) != 0 || ethr_late_init(NULL) != 0) { - fprintf(stderr, "emem: failed to initialize thread package\n"); - exit(1); - } - - state = new_state(malloc, realloc, free); - if (!state) - error(ENOMEM); - - parse_args(state, argc, argv); - - res = ethr_thr_create(&output_tid, - output_thread_func, - (void *) state, - NULL); - if (res != 0) - error_msg(res, "Output thread create"); - -#ifdef DEBUG - print_string(state, "> [debug]\n"); -#endif - - res = init_connection(state); - if (res != 0) - error_msg(res, "Initialize connection"); - - res = ethr_thr_create(&input_tid, - input_thread_func, - (void *) state, - NULL); - if (res != 0) - error_msg(res, "Input thread create"); - - res = process_trace(state); - - disconnect_queue_reader(&state->input.queue); - - jres = ethr_thr_join(input_tid, NULL); - if (jres != 0) - error_msg(jres, "Input thread join"); - - if (res == EM_EXIT_RESULT) - print_main_footer(state); - disconnect_queue_writer(&state->output.queue); - - jres = ethr_thr_join(output_tid, NULL); - if (jres != 0) - error_msg(jres, "Output thread join"); - - ires = state->input.error; - - destroy_state(state); - -#ifdef __WIN32__ - WSACleanup(); -#endif - - switch (res) { - case EM_EXIT_RESULT: - break; - case EM_TRUNCATED_TRACE_ERROR: - error_msg(ires, state->input.error_descr); - break; - default: - error(res); - break; - } - - return 0; -} - - -#if PRINT_OPERATIONS -void -print_op(em_state *state, emtp_operation *op) -{ - -#if 0 - printf("%5" USGND_INT_32_FSTR ":%6.6" USGND_INT_32_FSTR " ", - op->time.secs, op->time.usecs); -#endif - if (state->trace_info.version.parser.major >= 2) { - - switch (op->type) { - case EMTP_ALLOC: - printf(" %" USGND_INT_MAX_FSTR " = alloc(%" USGND_INT_16_FSTR - ", %" USGND_INT_MAX_FSTR ")\n", - op->u.block.new_ptr, - op->u.block.type, - op->u.block.new_size); - break; - case EMTP_REALLOC: - printf(" %" USGND_INT_MAX_FSTR " = realloc(%" USGND_INT_16_FSTR - ", %" USGND_INT_MAX_FSTR ", %" USGND_INT_MAX_FSTR ")\n", - op->u.block.new_ptr, - op->u.block.type, - op->u.block.prev_ptr, - op->u.block.new_size); - break; - case EMTP_FREE: - printf(" free(%" USGND_INT_16_FSTR ", %" USGND_INT_MAX_FSTR ")" - "\n", - op->u.block.type, - op->u.block.prev_ptr); - break; - case EMTP_CARRIER_ALLOC: - printf(" %" USGND_INT_MAX_FSTR " = carrier_alloc(%" - USGND_INT_16_FSTR ", %" USGND_INT_16_FSTR ", %" - USGND_INT_MAX_FSTR ")\n", - op->u.block.new_ptr, - op->u.block.carrier_type, - op->u.block.type, - op->u.block.new_size); - break; - case EMTP_CARRIER_REALLOC: - printf(" %" USGND_INT_MAX_FSTR " = carrier_realloc(%" - USGND_INT_16_FSTR ", %" USGND_INT_16_FSTR ", %" - USGND_INT_MAX_FSTR ", %" USGND_INT_MAX_FSTR ")\n", - op->u.block.new_ptr, - op->u.block.carrier_type, - op->u.block.type, - op->u.block.prev_ptr, - op->u.block.new_size); - case EMTP_CARRIER_FREE: - printf(" carrier_free(%" USGND_INT_16_FSTR ", %" USGND_INT_16_FSTR - ", %" USGND_INT_MAX_FSTR ")\n", - op->u.block.carrier_type, - op->u.block.type, - op->u.block.prev_ptr); - break; - default: - printf(" op = %d\n", op->type); - break; - } - - } - else { - - switch (op->type) { - case EMTP_ALLOC: - printf(" %" USGND_INT_MAX_FSTR " = alloc(%" USGND_INT_MAX_FSTR ")" - "\n", - op->u.block.new_ptr, - op->u.block.new_size); - break; - case EMTP_REALLOC: - printf(" %" USGND_INT_MAX_FSTR " = realloc(%" USGND_INT_MAX_FSTR - ", %" USGND_INT_MAX_FSTR ")\n", - op->u.block.new_ptr, - op->u.block.prev_ptr, - op->u.block.new_size); - break; - case EMTP_FREE: - printf(" free(%" USGND_INT_MAX_FSTR ")\n", - op->u.block.prev_ptr); - break; - default: - printf(" op = %d\n", op->type); - break; - } - } - fflush(stdout); -} -#endif diff --git a/lib/tools/c_src/erl_memory_trace_block_table.c b/lib/tools/c_src/erl_memory_trace_block_table.c deleted file mode 100644 index ca7cb45a0ee9..000000000000 --- a/lib/tools/c_src/erl_memory_trace_block_table.c +++ /dev/null @@ -1,762 +0,0 @@ -/* ``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. - * - * The Initial Developer of the Original Code is Ericsson Utvecklings AB. - * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings - * AB. All Rights Reserved.'' - * - * $Id$ - */ - - -/* - * Description: - * - * Author: Rickard Green - */ - -/* Headers to include ... */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "erl_memory_trace_block_table.h" -#include - -#undef HARD_DEBUG -#undef REALLY_HARD_DEBUG -#ifdef DEBUG -# define HARD_DEBUG 0 -# define REALLY_HARD_DEBUG 0 -#else -# define HARD_DEBUG 0 -# define REALLY_HARD_DEBUG 0 -#endif - -/* Some system specific defines ... */ -#if defined(__WIN32__) && !defined(__GNUC__) -# define INLINE __forceinline -#else -# ifdef __GNUC__ -# define INLINE __inline__ -# else -# define INLINE -# endif -#endif - -/* Our own assert() ... */ -#ifdef DEBUG -#define ASSERT(A) ((void) ((A) ? 1 : assert_failed(__FILE__, __LINE__, #A))) -#include -static int assert_failed(char *f, int l, char *a) -{ - fprintf(stderr, "%s:%d: Assertion failed: %s\n", f, l, a); - abort(); - return 0; -} - -#else -#define ASSERT(A) ((void) 1) -#endif - - -#define EMTBT_BLOCKS_PER_POOL 1000 - -typedef struct emtbt_block_pool_ { - struct emtbt_block_pool_ *next; - emtbt_block blocks[1]; -} emtbt_block_pool; - -struct emtbt_table_ { - void * (*alloc)(size_t); - void * (*realloc)(void *, size_t); - void (*free)(void *); - int is_64_bit; - int no_blocks; - int no_of_buckets; - int max_used_buckets; - int min_used_buckets; - int used_buckets; - int current_size_index; - emtbt_block *blocks; - emtbt_block ** buckets; - - - /* Fixed size allocation of blocks */ - emtbt_block_pool *block_pools; - emtbt_block *free_blocks; - int blocks_per_pool; - -}; - - -static emtbt_block null_blk = {0}; - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ - * Block table * - * * -\* */ - -#if HARD_DEBUG -static void check_table(emtbt_table *table); -#endif - -static emtbt_block * -block_alloc_new_pool(emtbt_table *tab) -{ - size_t size; - emtbt_block_pool *poolp; - - size = sizeof(emtbt_block_pool) - sizeof(emtbt_block); - size += tab->blocks_per_pool*sizeof(emtbt_block); - - poolp = (*tab->alloc)(size); - - if (poolp) { - int i; - emtbt_block *blks; - - poolp->next = tab->block_pools; - tab->block_pools = poolp; - - blks = (emtbt_block *) poolp->blocks; - - for (i = 1; i < tab->blocks_per_pool - 1; i++) - blks[i].next = &blks[i + 1]; - blks[tab->blocks_per_pool - 1].next = NULL; - tab->free_blocks = &blks[1]; - - return &blks[0]; - } - return NULL; -} - -static INLINE emtbt_block * -block_alloc(emtbt_table *tab) -{ - emtbt_block *res; -#if HARD_DEBUG - check_table(tab); -#endif - - if (tab->free_blocks) { - res = tab->free_blocks; - tab->free_blocks = tab->free_blocks->next; - } - else { - res = block_alloc_new_pool(tab); - } - -#ifdef DEBUG - res->next = ((emtbt_block *) 0xfffffff0); - res->prev = ((emtbt_block *) 0xfffffff0); - res->bucket = ((emtbt_block **) 0xfffffff0); -#endif - -#if HARD_DEBUG - check_table(tab); -#endif - - return res; -} - -static INLINE void -block_free(emtbt_table *tab, emtbt_block *bp) -{ - -#if HARD_DEBUG - check_table(tab); -#endif - - bp->next = tab->free_blocks; - tab->free_blocks = bp; - -#if HARD_DEBUG - check_table(tab); -#endif - - -} - -#define PRIME0 ((usgnd_int_32) 268438039) -#define PRIME1 ((usgnd_int_32) 268440479) -#define PRIME2 ((usgnd_int_32) 268439161) -#define PRIME3 ((usgnd_int_32) 268437017) - -#define MK_HASH(H, P, IS64) \ -do { \ - (H) = (P) & 0xff; \ - (H) *= PRIME0; \ - (H) += ((P) >> 8) & 0xff; \ - (H) *= PRIME1; \ - (H) += ((P) >> 16) & 0xff; \ - (H) *= PRIME2; \ - (H) += ((P) >> 24) & 0xff; \ - (H) *= PRIME3; \ - if ((IS64)) { \ - (H) += ((P) >> 32) & 0xff; \ - (H) *= PRIME0; \ - (H) += ((P) >> 40) & 0xff; \ - (H) *= PRIME1; \ - (H) += ((P) >> 48) & 0xff; \ - (H) *= PRIME2; \ - (H) += ((P) >> 56) & 0xff; \ - (H) *= PRIME3; \ - } \ -} while (0) - -static const int table_sizes[] = { - 3203, - 4813, - 6421, - 9643, - 12853, - 19289, - 25717, - 51437, - 102877, - 205759, - 411527, - 823117, - 1646237, - 3292489, - 6584983, - 13169977, - 26339969, - 52679969 -}; - -#if HARD_DEBUG - -static void -check_table(emtbt_table *table) -{ - int no_blocks; - emtbt_block *block, *prev_block; - - no_blocks = 0; - block = table->blocks; - ASSERT(!block || !block->prev); - prev_block = NULL; - while (block) { - usgnd_int_32 hash; - MK_HASH(hash, block->pointer, table->is_64_bit); - ASSERT(hash == block->hash); - ASSERT(block->bucket - table->buckets - == hash % table->no_of_buckets); - ASSERT(!prev_block || prev_block == block->prev); - prev_block = block; - block = block->next; - no_blocks++; - ASSERT(table->no_blocks >= no_blocks); - } - - ASSERT(table->no_blocks == no_blocks); - -#if REALLY_HARD_DEBUG - { - int i; - for (i = 0; i < table->no_of_buckets; i++) { - int bucket_end_found; - emtbt_block **bucket; - if (!table->buckets[i]) - continue; - bucket_end_found = 0; - bucket = &table->buckets[i]; - for (block = table->blocks; block; block = block->next) { - if (block->bucket == bucket) { - if (!block->prev || block->prev->bucket != bucket) - ASSERT(*bucket == block); - if (!block->next || block->next->bucket != bucket) - bucket_end_found++; - } - } - ASSERT(bucket_end_found); - } - } -#endif - -} - -#endif - -static INLINE void -link_block(emtbt_table *table, emtbt_block **bucket, emtbt_block *block) -{ - ASSERT(bucket); - - block->bucket = bucket; - if (*bucket) { - block->next = *bucket; - block->prev = (*bucket)->prev; - if (block->prev) - block->prev->next = block; - else - table->blocks = block; - block->next->prev = block; - } - else { - block->next = table->blocks; - block->prev = NULL; - if (table->blocks) - table->blocks->prev = block; - table->blocks = block; - table->used_buckets++; - - } - *bucket = block; - table->no_blocks++; - -#if HARD_DEBUG - check_table(table); -#endif - -} - -static int -resize_table(emtbt_table *table, int new_no_of_buckets) -{ -#ifdef DEBUG - int org_no_blocks; -#endif - int i; - emtbt_block *block; - emtbt_block **buckets; - - if (new_no_of_buckets < table->no_of_buckets) { - /* shrink never fails */ - buckets = (emtbt_block **) (*table->realloc)(table->buckets, - (sizeof(emtbt_block *) - * new_no_of_buckets)); - if (!buckets) - return 1; - } - else if (new_no_of_buckets > table->no_of_buckets) { - (*table->free)((void *) table->buckets); - buckets = (emtbt_block **) (*table->alloc)((sizeof(emtbt_block *) - * new_no_of_buckets)); - if (!buckets) - return 0; - } - else - return 1; - - table->buckets = buckets; - table->no_of_buckets = new_no_of_buckets; - table->max_used_buckets = (4*new_no_of_buckets)/5; - table->min_used_buckets = new_no_of_buckets/5; - table->used_buckets = 0; - -#ifdef DEBUG - org_no_blocks = table->no_blocks; -#endif - - table->no_blocks = 0; - - - for (i = 0; i < new_no_of_buckets; i++) - buckets[i] = NULL; - - block = table->blocks; - table->blocks = NULL; - - while (block) { - emtbt_block *next_block = block->next; - link_block(table,&table->buckets[block->hash%new_no_of_buckets],block); - block = next_block; - } - - ASSERT(org_no_blocks == table->no_blocks); - - return 1; -} - -static INLINE int -grow_table(emtbt_table *table) -{ - if (table->current_size_index < sizeof(table_sizes)/sizeof(int)) { - int new_size; - table->current_size_index++; - new_size = table_sizes[table->current_size_index]; - ASSERT(new_size > 0); - return resize_table(table, new_size); - } - return 1; -} - -static INLINE void -shrink_table(emtbt_table *table) -{ - if (table->current_size_index > 0) { - int new_size; - table->current_size_index--; - new_size = table_sizes[table->current_size_index]; - ASSERT(new_size > 0); - (void) resize_table(table, new_size); - } -} - -static INLINE emtbt_block * -peek_block(emtbt_table *table, usgnd_int_max ptr) -{ - emtbt_block **bucket; - emtbt_block *block; - usgnd_int_32 hash; - - MK_HASH(hash, ptr, table->is_64_bit); - - bucket = &table->buckets[hash % table->no_of_buckets]; - block = *bucket; - if (!block) - return NULL; - - while (block->bucket == bucket) { - ASSERT(block); - if (block->pointer == ptr) - return block; - if (!block->next) - break; - block = block->next; - } - return NULL; -} - -static INLINE int -insert_block(emtbt_table *table, emtbt_block *block) -{ - emtbt_block **bucket; - emtbt_block *tmp_block; - usgnd_int_32 hash; - usgnd_int_max p; - -#if HARD_DEBUG - check_table(table); -#endif - - if (table->used_buckets >= table->max_used_buckets) { - if(!grow_table(table)) - return -1; - } - - p = block->pointer; - - MK_HASH(hash, p, table->is_64_bit); - block->hash = hash; - - bucket = &table->buckets[hash % table->no_of_buckets]; - tmp_block = *bucket; - if (tmp_block) { - while (tmp_block->bucket == bucket) { - if (tmp_block->pointer == p) - return 0; - if (!tmp_block->next) - break; - tmp_block = tmp_block->next; - } - } - - link_block(table, bucket, block); - - ASSERT(block == peek_block(table, p)); - - - return 1; -} - -static INLINE void -delete_block(emtbt_table *table, emtbt_block *block) -{ - emtbt_block **bucket; - - if (!block) - return; - -#if HARD_DEBUG - check_table(table); -#endif - - bucket = block->bucket; - ASSERT(bucket); - - if (block->prev) - block->prev->next = block->next; - else - table->blocks = block->next; - - if (block->next) - block->next->prev = block->prev; - - if (block == *bucket) { - ASSERT(!block->prev || block->prev->bucket != bucket); - if (block->next && block->next->bucket == bucket) - *bucket = block->next; - else { - ASSERT(table->used_buckets > 0); - *bucket = NULL; - table->used_buckets--; - } - } -#ifdef DEBUG - - block->next = ((emtbt_block *) 0xfffffff0); - block->prev = ((emtbt_block *) 0xfffffff0); - block->bucket = ((emtbt_block **) 0xfffffff0); -#endif - - ASSERT(table->no_blocks > 0); - table->no_blocks--; - - if (table->used_buckets < table->min_used_buckets) - shrink_table(table); - -#if HARD_DEBUG - check_table(table); -#endif - -} - -static INLINE emtbt_block * -fetch_block(emtbt_table *table, usgnd_int_max ptr) -{ - emtbt_block *block; - - block = peek_block(table, ptr); - delete_block(table, block); - return block; -} - - -const char *emtbt_error_string(int error) -{ - switch (error) { - case EMTBT_ALLOC_XBLK_ERROR: - return "Allocation to an already existing block"; - case EMTBT_REALLOC_NOBLK_ERROR: - return "Reallocation of non-existing block"; - case EMTBT_REALLOC_XBLK_ERROR: - return "Reallocation to an already existing block"; - case EMTBT_REALLOC_BLK_TYPE_MISMATCH: - return "Block types mismatch when reallocating"; - case EMTBT_FREE_NOBLK_ERROR: - return "Deallocation of non-existing block"; - case EMTBT_FREE_BLK_TYPE_MISMATCH: - return "Block types mismatch when deallocating"; - case EMTBT_INTERNAL_ERROR: - return "Block table internal error"; - default: - return NULL; - } - - -} - - -emtbt_table * -emtbt_new_table(int is_64_bit, - void * (*alloc)(size_t), - void * (*realloc)(void *, size_t), - void (*free)(void *)) -{ - emtbt_table *tab = (*alloc)(sizeof(emtbt_table)); - if (tab) { - tab->alloc = alloc; - tab->realloc = realloc; - tab->free = free; - tab->is_64_bit = is_64_bit; - tab->no_blocks = 0; - tab->no_of_buckets = 0; - tab->max_used_buckets = 0; - tab->min_used_buckets = 0; - tab->used_buckets = 0; - tab->current_size_index = 0; - tab->blocks = NULL; - tab->buckets = NULL; - - tab->block_pools = NULL; - tab->free_blocks = NULL; - tab->blocks_per_pool = EMTBT_BLOCKS_PER_POOL; - - } - return tab; -} - -void -emtbt_destroy_table(emtbt_table *tab) -{ - void (*freep)(void *); - emtbt_block_pool *poolp1, *poolp2; - - freep = tab->free; - - /* Free block pools */ - poolp1 = tab->block_pools; - while (poolp1) { - poolp2 = poolp1; - poolp1 = poolp1->next; - (*freep)((void *) poolp2); - } - - if (tab->buckets) - (*freep)((void *) tab->buckets); - - (*freep)((void *) tab); -} - - -#define CP_BLK(TO, FROM) \ -do { \ - (TO)->time.secs = (FROM)->time.secs; \ - (TO)->time.usecs = (FROM)->time.usecs; \ - (TO)->type = (FROM)->type; \ - (TO)->pointer = (FROM)->pointer; \ - (TO)->size = (FROM)->size; \ -} while (0) - -int -emtbt_alloc_op(emtbt_table *tab, emtp_operation *op) -{ - int res; - emtbt_block *blk; - - blk = block_alloc(tab); - if (!blk) - return ENOMEM; - - blk->time.secs = op->time.secs; - blk->time.usecs = op->time.usecs; - blk->type = op->u.block.type; - blk->pointer = op->u.block.new_ptr; - blk->size = op->u.block.new_size; - - res = insert_block(tab, blk); - if (res < 0) - return ENOMEM; - else if (res == 0) - return EMTBT_ALLOC_XBLK_ERROR; - return 0; -} - -int -emtbt_realloc_op(emtbt_table *tab, emtp_operation *op, emtbt_block *old_blk) -{ - int res; - emtbt_block *blk; - - if (!op->u.block.new_size) { - /* freed block */ - - blk = fetch_block(tab, op->u.block.prev_ptr); - if (!blk) - return EMTBT_REALLOC_NOBLK_ERROR; - - CP_BLK(old_blk, blk); - block_free(tab, blk); - } - else { - - if (!op->u.block.new_ptr) { - /* failed operation */ - if (!op->u.block.prev_ptr) - CP_BLK(old_blk, &null_blk); - else { - blk = peek_block(tab, op->u.block.prev_ptr); - if (!blk) - return EMTBT_REALLOC_NOBLK_ERROR; - CP_BLK(old_blk, blk); -#if 0 - if (blk->type != op->u.block.type) - return EMTBT_REALLOC_BLK_TYPE_MISMATCH; -#endif - } - } - else if (!op->u.block.prev_ptr) { - /* new block */ - - CP_BLK(old_blk, &null_blk); - blk = block_alloc(tab); - if (!blk) - return ENOMEM; - blk->type = op->u.block.type; - blk->pointer = op->u.block.new_ptr; - blk->time.secs = op->time.secs; - blk->time.usecs = op->time.usecs; - blk->size = op->u.block.new_size; - - res = insert_block(tab, blk); - if (res < 0) - return ENOMEM; - else if (res == 0) - return EMTBT_REALLOC_XBLK_ERROR; - } - else if (op->u.block.new_ptr == op->u.block.prev_ptr) { - /* resized block */ - blk = peek_block(tab, op->u.block.prev_ptr); - if (!blk) - return EMTBT_REALLOC_NOBLK_ERROR; - CP_BLK(old_blk, blk); - blk->time.secs = op->time.secs; - blk->time.usecs = op->time.usecs; - blk->size = op->u.block.new_size; -#if 0 - if (blk->type != op->u.block.type) - return EMTBT_REALLOC_BLK_TYPE_MISMATCH; -#endif - } - else { - /* moved block */ - blk = fetch_block(tab, op->u.block.prev_ptr); - if (!blk) - return EMTBT_REALLOC_NOBLK_ERROR; - CP_BLK(old_blk, blk); - blk->time.secs = op->time.secs; - blk->time.usecs = op->time.usecs; - blk->pointer = op->u.block.new_ptr; - blk->size = op->u.block.new_size; - res = insert_block(tab, blk); - if (res < 0) - return ENOMEM; - else if (res == 0) - return EMTBT_REALLOC_XBLK_ERROR; -#if 0 - if (blk->type != op->u.block.type) - return EMTBT_REALLOC_BLK_TYPE_MISMATCH; -#endif - } - } - return 0; - -} - - -int -emtbt_free_op(emtbt_table *tab, emtp_operation *op, emtbt_block *old_blk) -{ - emtbt_block *blk; - - if (!op->u.block.prev_ptr) - CP_BLK(old_blk, &null_blk); - else { - - blk = fetch_block(tab, op->u.block.prev_ptr); - if (!blk) - return EMTBT_FREE_NOBLK_ERROR; - - CP_BLK(old_blk, blk); - block_free(tab, blk); -#if 0 - if (blk->type != op->u.block.type) - return EMTBT_FREE_BLK_TYPE_MISMATCH; -#endif - } - return 0; -} diff --git a/lib/tools/c_src/erl_memory_trace_block_table.h b/lib/tools/c_src/erl_memory_trace_block_table.h deleted file mode 100644 index ead3afc8fb73..000000000000 --- a/lib/tools/c_src/erl_memory_trace_block_table.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ``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. - * - * The Initial Developer of the Original Code is Ericsson Utvecklings AB. - * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings - * AB. All Rights Reserved.'' - * - * $Id$ - */ - - -/* - * Description: - * - * Author: Rickard Green - */ - -#ifndef ERL_MEMORY_TRACE_BLOCK_TABLE_H__ -#define ERL_MEMORY_TRACE_BLOCK_TABLE_H__ - -#include -#include "erl_fixed_size_int_types.h" -#include "erl_memory_trace_parser.h" - - -#define EMTBT_ALLOC_XBLK_ERROR (EMTP_MIN_ERROR - 1) -#define EMTBT_REALLOC_NOBLK_ERROR (EMTP_MIN_ERROR - 2) -#define EMTBT_REALLOC_XBLK_ERROR (EMTP_MIN_ERROR - 3) -#define EMTBT_REALLOC_BLK_TYPE_MISMATCH (EMTP_MIN_ERROR - 4) -#define EMTBT_FREE_NOBLK_ERROR (EMTP_MIN_ERROR - 5) -#define EMTBT_FREE_BLK_TYPE_MISMATCH (EMTP_MIN_ERROR - 6) -#define EMTBT_INTERNAL_ERROR (EMTP_MIN_ERROR - 7) - -#define EMTBT_MIN_ERROR EMTBT_INTERNAL_ERROR - - -typedef struct emtbt_block_ { - - struct emtbt_block_ * next; - struct emtbt_block_ * prev; - usgnd_int_32 hash; - struct emtbt_block_ ** bucket; - - struct { - usgnd_int_32 secs; - usgnd_int_32 usecs; - } time; - usgnd_int_16 type; - usgnd_int_max pointer; - usgnd_int_max size; -} emtbt_block; - -typedef struct emtbt_table_ emtbt_table; - -const char *emtbt_error_string(int); -emtbt_table *emtbt_new_table(int, - void * (*)(size_t), - void * (*)(void *, size_t), - void (*)(void *)); -void emtbt_destroy_table(emtbt_table *); -int emtbt_alloc_op(emtbt_table *tab, emtp_operation *op); -int emtbt_realloc_op(emtbt_table *, emtp_operation *, emtbt_block *); -int emtbt_free_op(emtbt_table *, emtp_operation *, emtbt_block *); - -#endif diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile index 63218e793fc7..6b1e2b050f52 100644 --- a/lib/tools/doc/src/Makefile +++ b/lib/tools/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -38,7 +38,6 @@ XML_REF3_FILES = \ fprof.xml \ cprof.xml \ lcnt.xml \ - instrument.xml \ make.xml \ tags.xml \ xref.xml \ diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml index 9bcaa9227dfe..c9c7d2e6fc06 100644 --- a/lib/tools/doc/src/cover.xml +++ b/lib/tools/doc/src/cover.xml @@ -5,7 +5,7 @@

    2001 - 2020 + 2022 Ericsson AB, All Rights Reserved @@ -110,7 +110,7 @@

    If the connection to a remote node goes down, the main node will mark it as lost. If the node comes back it will be added again. If the remote node was alive during the disconnected - periode, cover data from before and during this periode will be + period, cover data from before and during this period will be included in the analysis.

    diff --git a/lib/tools/doc/src/cprof_chapter.xml b/lib/tools/doc/src/cprof_chapter.xml index af13b8d8d737..671f9717a6de 100644 --- a/lib/tools/doc/src/cprof_chapter.xml +++ b/lib/tools/doc/src/cprof_chapter.xml @@ -4,7 +4,7 @@
    - 20022021 + 20022022 Ericsson AB. All Rights Reserved. @@ -37,7 +37,7 @@

    cprof uses breakpoints similar to local call trace, but containing counters, to collect profiling - data. Therfore there is no need for special compilation of any + data. Therefore there is no need for special compilation of any module to be profiled.

    cprof presents all profiled modules in decreasing total @@ -96,33 +96,38 @@

    From the Erlang shell:

     1> cprof:start(), cprof:pause(). % Stop counters just after start
    -3476
    +8492
     2> cprof:analyse().
    -{30,
    - [{erl_eval,11,
    -            [{{erl_eval,expr,3},3},
    -             {{erl_eval,'-merge_bindings/2-fun-0-',2},2},
    -             {{erl_eval,expand_module_name,2},1},
    -             {{erl_eval,merge_bindings,2},1},
    -             {{erl_eval,binding,2},1},
    -             {{erl_eval,expr_list,5},1},
    -             {{erl_eval,expr_list,3},1},
    -             {{erl_eval,exprs,4},1}]},
    -  {orddict,8,
    -           [{{orddict,find,2},6},
    -            {{orddict,dict_to_list,1},1},
    -            {{orddict,to_list,1},1}]},
    -  {packages,7,[{{packages,is_segmented_1,1},6},
    -               {{packages,is_segmented,1},1}]},
    -  {lists,4,[{{lists,foldl,3},3},{{lists,reverse,1},1}]}]}
    +{539,
    + [{shell,155,
    +         [{{shell,prep_check,1},55},
    +          {{shell,used_records,4},45},
    +          {{shell,used_records,1},45},
    +          {{shell,used_record_defs,2},1},
    +          {{shell,record_defs,2},1},
    +          {{shell,record_bindings,2},1},
    +          {{shell,exprs,7},1},
    +          {{shell,expr,4},1},
    +          {{shell,expand_records,2},1},
    +          {{shell,check_command,2},1},
    +          {{shell,apply_fun,3},1},
    +          {{shell,'-exprs/7-lc$^0/1-0-',1},1},
    +          {{shell,'-eval_loop/3-fun-0-',3},1}]},
    +  %% Information about many modules omitted.
    +                     .
    +                     .
    +                     .
    +  %% Here is the last part.
    +  {erts_internal,2,[{{erts_internal,trace_pattern,3},2}]},
    +  {otp_internal,1,[{{otp_internal,obsolete,3},1}]},
    +  {maps,1,[{{maps,from_list,1},1}]},
    +  {erl_internal,1,[{{erl_internal,bif,3},1}]}]}
     3> cprof:analyse(cprof).
     {cprof,3,[{{cprof,tr,2},2},{{cprof,pause,0},1}]}
     4> cprof:stop().
    -3476
    -

    The example showed the background work that the shell performs - just to interpret the first command line. Most work is done by - erl_eval and orddict. -

    +8586 +

    The example showed some of the background work that the shell + performs just to interpret the first command line.

    What is captured in this example is the part of the work the shell does while interpreting the command line that occurs between the actual calls to cprof:start() and @@ -138,17 +143,17 @@ 1 2> cprof:analyse(calendar). {calendar,9, - [{{calendar,df,2},1}, - {{calendar,dm,1},1}, - {{calendar,dy,1},1}, - {{calendar,last_day_of_the_month1,2},1}, + [{{calendar,last_day_of_the_month1,2},1}, {{calendar,last_day_of_the_month,2},1}, {{calendar,is_leap_year1,1},1}, {{calendar,is_leap_year,1},1}, + {{calendar,dy,1},1}, + {{calendar,dm,1},1}, + {{calendar,df,2},1}, {{calendar,day_of_the_week,3},1}, {{calendar,date_to_gregorian_days,3},1}]} 3> cprof:stop(). -3271 +8648

    The example tells us that "Aktiebolaget LM Ericsson & Co" was registered on a Monday (since the return value of the first command is 1), and that the calendar module @@ -164,66 +169,70 @@

    Write a module:

     -module(sort).
    -      
     -export([do/1]).
    -      
    +
     do(N) ->
         cprof:stop(),
         cprof:start(),
         do(N, []).
    -      
    +
     do(0, L) ->
         R = lists:sort(L),
         cprof:pause(),
         R;
     do(N, L) ->
    -    do(N-1, [random:uniform(256)-1 | L]).
    + do(N-1, [rand:uniform(256)-1 | L]).

    From the Erlang shell:

     1> c(sort).
     {ok,sort}
    -2> l(random).
    -{module,random}
    +2> rand:seed(default, 42), ok.
    +ok.
     3> sort:do(1000).
    -[0,0,1,1,1,1,1,1,2,2,2,3,3,3,3,3,4,4,4,5,5,5,5,6,6,6,6,6,6|...]
    +[0,0,0,1,1,1,1,2,2,3,3,4,4,4,4,5,5,5,6,6,6,6,7,7,7,7,7,8,8|...]
     4> cprof:analyse().
    -{9050,
    - [{lists_sort,6047,
    -              [{{lists_sort,merge3_2,6},923},
    -               {{lists_sort,merge3_1,6},879},
    -               {{lists_sort,split_2,5},661},
    -               {{lists_sort,rmerge3_1,6},580},
    -               {{lists_sort,rmerge3_2,6},543},
    -               {{lists_sort,merge3_12_3,6},531},
    -               {{lists_sort,merge3_21_3,6},383},
    -               {{lists_sort,split_2_1,6},338},
    -               {{lists_sort,rmerge3_21_3,6},299},
    -               {{lists_sort,rmerge3_12_3,6},205},
    -               {{lists_sort,rmerge2_2,4},180},
    -               {{lists_sort,rmerge2_1,4},171},
    -               {{lists_sort,merge2_1,4},127},
    -               {{lists_sort,merge2_2,4},121},
    -               {{lists_sort,mergel,2},79},
    -               {{lists_sort,rmergel,2},27}]},
    -  {random,2001,
    -          [{{random,uniform,1},1000},
    -           {{random,uniform,0},1000},
    -           {{random,seed0,0},1}]},
    +{13180,
    + [{lists,6173,
    +         [{{lists,rmerge3_1,6},1045},
    +          {{lists,rmerge3_2,6},977},
    +          {{lists,split_1,5},652},
    +          {{lists,merge3_1,6},579},
    +          {{lists,merge3_2,6},577},
    +          {{lists,rmerge3_12_3,6},511},
    +          {{lists,split_1_1,6},347},
    +          {{lists,merge3_12_3,6},310},
    +          {{lists,rmerge3_21_3,6},282},
    +          {{lists,merge3_21_3,6},221},
    +          {{lists,merge2_1,4},154},
    +          {{lists,merge2_2,5},138},
    +          {{lists,reverse,2},106},
    +          {{lists,rmerge2_2,5},87},
    +          {{lists,rmergel,2},81},
    +          {{lists,rmerge2_1,4},75},
    +          {{lists,mergel,2},28},
    +          {{lists,keyfind,3},2},
    +          {{lists,sort,1},1}]},
    +  {rand,5000,
    +        [{{rand,uniform_s,2},1000},
    +         {{rand,uniform,1},1000},
    +         {{rand,seed_put,1},1000},
    +         {{rand,seed_get,0},1000},
    +         {{rand,exsss_uniform,2},1000}]},
    +  {erlang,1004,
    +          [{{erlang,put,2},1000},
    +           {{erlang,trace_pattern,3},2},
    +           {{erlang,ensure_tracer_module_loaded,2},2}]},
       {sort,1001,[{{sort,do,2},1001}]},
    -  {lists,1,[{{lists,sort,1},1}]}]}
    +  {erts_internal,2,[{{erts_internal,trace_pattern,3},2}]}]}
     5> cprof:stop().
    -5369
    +12625

    The example shows some details of how lists:sort/1 - works. It used 6047 function calls in the module - lists_sort to complete the work. -

    -

    This time, since the shell was not involved, no other work was - done in the system during the profiling. If you retry the same - example with a freshly started Erlang emulator, but omit the - command l(random), the analysis will show a lot more - function calls done by code_server and others to - automatically load the module random. + works. It used 6173 function calls in the module + lists to complete the work.

    +

    This time, since the shell was not involved in starting and + stopping cprof, no other work was done in the system during + the profiling.

    diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml index b10624751f09..a1e25b5505ba 100644 --- a/lib/tools/doc/src/eprof.xml +++ b/lib/tools/doc/src/eprof.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962022 Ericsson AB. All Rights Reserved. @@ -74,7 +74,7 @@

    Stops profiling started with start_profiling/1 or - prifile/1.

    + profile/1.

    diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml index c145b0bcba3a..63b75cf6e743 100644 --- a/lib/tools/doc/src/erlang_mode.xml +++ b/lib/tools/doc/src/erlang_mode.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -107,25 +107,25 @@
    - Edit - Moving the marker + Edit - Moving the point - C-a M-a + M-C-a (erlang-beginning-of-function) - Move the point to the beginning of the current or preceding Erlang function. With an - numeric argument (ex C-u 2 C-a M-a) the function + numeric argument (ex C-u 2 M-C-a) the function skips backwards over this many Erlang functions. Should the argument be negative the point is moved to the beginning of a function below the current function. - M-C-a (erlang-beginning-of-clause) - As + C-c M-a (erlang-beginning-of-clause) - As above but move point to the beginning of the current or preceding Erlang clause. - C-a M-e (erlang-end-of-function) + M-C-e (erlang-end-of-function) - Move to the end of the current or following Erlang function. With - an numeric argument (ex C-u 2 C-a M-e) the function + an numeric argument (ex C-u 2 M-C-e) the function skips backwards over this many Erlang functions. Should the argument be negative the point is moved to the end of a function below the current function. - M-C-e (erlang-end-of-clause) - As above + C-c M-e (erlang-end-of-clause) - As above but move point to the end of the current or following Erlang clause. @@ -134,11 +134,11 @@
    Edit - Marking - C-c M-h (erlang-mark-function) - Put the + M-C-h (erlang-mark-function) - Put the region around the current Erlang function. The point is placed in the beginning and the mark at the end of the function. - M-C-h (erlang-mark-clause) Put the region + C-c M-h (erlang-mark-clause) Put the region around the current Erlang clause. The point is placed in the beginning and the mark at the end of the function. diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml index e7e7ad69f3a9..4e4e466fc727 100644 --- a/lib/tools/doc/src/fprof.xml +++ b/lib/tools/doc/src/fprof.xml @@ -4,7 +4,7 @@
    - 20012021 + 20012022 Ericsson AB. All Rights Reserved. @@ -485,7 +485,7 @@ Includes a section containing call statistics for all calls regardless of process, in the analysis. {totals, false} - Supresses the totals section in the analysis, which is + Suppresses the totals section in the analysis, which is the default. details | {details, true} Prints call statistics for each process in the @@ -686,7 +686,7 @@ create_file_slow(FD, M, N) -> {{fprof,apply_start_stop,4}, 1, 0.000, 0.000}], { suspend, 299, 32.002, 0.000}, % [ ]}. -

    We find no particulary long suspend times, so no function seems +

    We find no particularly long suspend times, so no function seems to have waited in a receive statement. Actually, prim_file:drv_command/4 contains a receive statement, but in this test program, the message lies in the process receive diff --git a/lib/tools/doc/src/fprof_chapter.xml b/lib/tools/doc/src/fprof_chapter.xml index 65ffcede1a36..b07eef2637a3 100644 --- a/lib/tools/doc/src/fprof_chapter.xml +++ b/lib/tools/doc/src/fprof_chapter.xml @@ -4,7 +4,7 @@

    - 20012021 + 20012022 Ericsson AB. All Rights Reserved. @@ -37,7 +37,7 @@ processes.

    fprof uses tracing with timestamps to collect profiling - data. Therfore there is no need for special compilation of any + data. Therefore there is no need for special compilation of any module to be profiled.

    fprof presents wall clock times from the host machine OS, diff --git a/lib/tools/doc/src/lcnt_chapter.xml b/lib/tools/doc/src/lcnt_chapter.xml index c8afd7063d1b..a9628525c920 100644 --- a/lib/tools/doc/src/lcnt_chapter.xml +++ b/lib/tools/doc/src/lcnt_chapter.xml @@ -4,7 +4,7 @@

    - 20092021 + 20092022 Ericsson AB. All Rights Reserved. @@ -42,7 +42,7 @@ completed its access to the resource and unlocked it. The lcnt tool measures these lock conflicts.

    - Locks have an inherent cost in execution time and memory space. It takes time initialize, destroy, aquiring or releasing locks. To decrease lock contention it + Locks have an inherent cost in execution time and memory space. It takes time initialize, destroy, acquiring or releasing locks. To decrease lock contention it some times necessary to use finer grained locking strategies. This will usually also increase the locking overhead and hence there is a tradeoff between lock contention and overhead. In general, lock contention increases with the number of threads running concurrently. The lcnt tool does not measure locking overhead.

    diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 0680f28f71a5..babc9fde4d61 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -31,6 +31,43 @@

    This document describes the changes made to the Tools application.

    +
    Tools 3.6 + +
    Improvements and New Features + + +

    Map comprehensions as suggested in EEP 58 has now been + implemented.

    +

    + Own Id: OTP-18413 Aux Id: EEP-58, PR-6727

    +
    + +

    The instrument module has been moved from + tools to runtime_tools.

    +

    + Own Id: OTP-18487 Aux Id: PR-6829

    +
    +
    +
    + +
    + +
    Tools 3.5.3 + +
    Improvements and New Features + + +

    + Removed the previously undocumented and unsupported + emem tool.

    +

    + Own Id: OTP-17892 Aux Id: PR-5591

    +
    +
    +
    + +
    +
    Tools 3.5.2
    Fixed Bugs and Malfunctions diff --git a/lib/tools/doc/src/notes_history.xml b/lib/tools/doc/src/notes_history.xml index d955cbde69cf..7ef93d6fbfbb 100644 --- a/lib/tools/doc/src/notes_history.xml +++ b/lib/tools/doc/src/notes_history.xml @@ -4,7 +4,7 @@
    - 20062016 + 20062022 Ericsson AB. All Rights Reserved. @@ -91,7 +91,7 @@

    Own Id: OTP-4594

    -

    Improvments for support of Emacs 21 contributed by Dave +

    Improvements for support of Emacs 21 contributed by Dave Love. The bulk of the changes are actually cosmetic commentary/doc fixes. The significant ones make it play better with Emacs 21 with up-to-date facilities. In diff --git a/lib/tools/doc/src/part.xml b/lib/tools/doc/src/part.xml index 796047fe8d1a..13e24140011f 100644 --- a/lib/tools/doc/src/part.xml +++ b/lib/tools/doc/src/part.xml @@ -4,7 +4,7 @@

    - 19962016 + 19962023 Ericsson AB. All Rights Reserved. @@ -53,9 +53,6 @@ Erlang programs. Uses trace to file to minimize runtime performance impact, and displays time for calling and called functions. - instrument - Utility functions for obtaining and analysing resource usage - in an instrumented Erlang runtime system. lcnt A lock profiling tool for the Erlang runtime system. make diff --git a/lib/tools/doc/src/ref_man.xml b/lib/tools/doc/src/ref_man.xml index d2131e7a936f..c2962eeb84c9 100644 --- a/lib/tools/doc/src/ref_man.xml +++ b/lib/tools/doc/src/ref_man.xml @@ -4,7 +4,7 @@
    - 19962016 + 19962023 Ericsson AB. All Rights Reserved. @@ -53,10 +53,6 @@ performance impact, and displays time for calling and called functions. - instrument - Utility functions for obtaining and analysing resource usage - in an instrumented Erlang runtime system. - lcnt A lock profiling tool for the Erlang runtime system. @@ -75,7 +71,6 @@ - diff --git a/lib/tools/doc/src/specs.xml b/lib/tools/doc/src/specs.xml index 4f7223e2bcf5..143b54f0a94e 100644 --- a/lib/tools/doc/src/specs.xml +++ b/lib/tools/doc/src/specs.xml @@ -8,6 +8,5 @@ - diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile index c19ad3668c0f..279ae5f80555 100644 --- a/lib/tools/emacs/Makefile +++ b/lib/tools/emacs/Makefile @@ -59,7 +59,7 @@ ELC_FILES = $(EMACS_FILES:%=%.elc) # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) $(EL_FILES) +$(TYPES): $(TARGET_FILES) $(EL_FILES) clean: rm -f $(TARGET_FILES) $(ELC_FILES) diff --git a/lib/tools/emacs/README b/lib/tools/emacs/README index cc107dcd4115..8916e65250a2 100644 --- a/lib/tools/emacs/README +++ b/lib/tools/emacs/README @@ -34,13 +34,13 @@ variable. If HOME is not set, Emacs will look for the .emacs file in C:\. Below is a complete example of what should be added to a user's .emacs -provided that OTP is installed in the directory C:\Program -Files\erl-: +provided that OTP is installed in the directory "C:\Program +Files\Erlang OTP": (setq load-path (cons "C:/Program Files/erl/lib/tools-/emacs" load-path)) - (setq erlang-root-dir "C:/Program Files/erl") - (setq exec-path (cons "C:/Program Files/erl/bin" exec-path)) + (setq erlang-root-dir "C:/Program Files/Erlang OTP") + (setq exec-path (cons "C:/Program Files/Erlang OTP/bin" exec-path)) (require 'erlang-start) diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el index 1130bc0cdeb0..f7c69daaa12f 100644 --- a/lib/tools/emacs/erlang-eunit.el +++ b/lib/tools/emacs/erlang-eunit.el @@ -1,7 +1,7 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2009-2021. All Rights Reserved. +;; Copyright Ericsson AB 2009-2022. 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. @@ -36,7 +36,7 @@ a source file. The first directory in the list will be used, if there is no match.") (defvar erlang-eunit-autosave nil - "*Set to non-nil to automtically save unsaved buffers before running tests. + "*Set to non-nil to automatically save unsaved buffers before running tests. This is useful, reducing the save-compile-load-test cycle to one keychord.") (defvar erlang-eunit-recent-info '((mode . nil) (module . nil) (test . nil) (cover . nil)) diff --git a/lib/tools/emacs/erlang-skels-old.el b/lib/tools/emacs/erlang-skels-old.el index 4087bc301362..7d503c4bc1e7 100644 --- a/lib/tools/emacs/erlang-skels-old.el +++ b/lib/tools/emacs/erlang-skels-old.el @@ -1,7 +1,7 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2010-2016. All Rights Reserved. +;; Copyright Ericsson AB 2010-2022. 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. @@ -368,7 +368,7 @@ Please see the function `tempo-define-template'.") "%% supervisor_bridge callbacks" n (erlang-skel-double-separator 2) (erlang-skel-separator 2) - "%% Funcion: init(Args) -> {ok, Pid, State} |" n + "%% Function: init(Args) -> {ok, Pid, State} |" n "%% ignore |" n "%% {error, Reason} " n "%% Description:Creates a supervisor_bridge process, linked to the calling" n diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el index 3202f4379084..f61f156f9d6d 100644 --- a/lib/tools/emacs/erlang-skels.el +++ b/lib/tools/emacs/erlang-skels.el @@ -1,7 +1,7 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2010-2020. All Rights Reserved. +;; Copyright Ericsson AB 2010-2023. 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. @@ -70,6 +70,8 @@ erlang-skel-ct-test-suite-s erlang-skel-header) ("Large Common Test suite" "ct-test-suite-l" erlang-skel-ct-test-suite-l erlang-skel-header) + ("Common Test Hook" "ct-hook" + erlang-skel-ct-hook erlang-skel-header) ("Erlang TS test suite" "ts-test-suite" erlang-skel-ts-test-suite erlang-skel-header) ) @@ -1845,6 +1847,107 @@ Please see the function `tempo-define-template'.") "*The template of a library module. Please see the function `tempo-define-template'.") +(defvar erlang-skel-ct-hook + '((erlang-skel-include erlang-skel-normal-header) + "%% Mandatory callbacks" n + "-export([init/2])." n + n + "%% Optional callbacks" n + "-export([id/1])." n + n + "-export([pre_init_per_suite/3])." n + "-export([post_init_per_suite/4])." n + n + "-export([pre_end_per_suite/3])." n + "-export([post_end_per_suite/4])." n + n + "-export([pre_init_per_group/4])." n + "-export([post_init_per_group/5])." n + n + "-export([pre_end_per_group/4])." n + "-export([post_end_per_group/5])." n + n + "-export([pre_init_per_testcase/4])." n + "-export([post_init_per_testcase/5])." n + n + "-export([pre_end_per_testcase/4])." n + "-export([post_end_per_testcase/5])." n + n + "-export([on_tc_fail/4])." n + "-export([on_tc_skip/4])." n + n + "-export([terminate/1])." n + n + "%% The hook state is threaded through all callbacks," n + "%% but can be anything the hook needs, replace as desired." n + "-record(state, { cases=0, suites=0, groups=0, skips=0, fails=0 })." n + n + "%% Return a unique id for this CTH." n + "id(Opts) ->" n + " %% A reference is the default implementation, this can be removed" n + " %% or some value can be read from Opts instead." n + " erlang:make_ref()." n + n + "%% Always called before any other callback function, once per installed hook." n + "init(Id, Opts) ->" n + " {ok, #state{}}." n + n + "pre_init_per_suite(Suite, Config, State) ->" n + " {Config, State}." n + n + "post_init_per_suite(Suite, Config, Return, State) ->" n + " {Return, State}." n + n + "pre_end_per_suite(Suite, Config, State) ->" n + " {Config, State}." n + n + "post_end_per_suite(Suite, Config, Return, State) ->" n + " {Return, State#state{suites = State#state.suites + 1}}." n + n + "pre_init_per_group(Suite, Group, Config, State) ->" n + " {Config, State}." n + n + "post_init_per_group(Suite, Group, Config, Return, State) ->" n + " {Return, State}." n + n + "pre_end_per_group(Suite, Group, Config, State) ->" n + " {Config, State}." n + n + "post_end_per_group(Suite, Group, Config, Return, State) ->" n + " {Return, State#state{groups = State#state.groups + 1}}." n + n + "pre_init_per_testcase(Suite, TC, Config, State) ->" n + " {Config, State}." n + n + "%% Called after each init_per_testcase (immediately before the test case)." n + "post_init_per_testcase(Suite, TC, Config, Return, State) ->" n + " {Return, State}." n + n + "%% Called before each end_per_testcase (immediately after the test case)." n + "pre_end_per_testcase(Suite, TC, Config, State) ->" n + " {Config, State}." n + n + "post_end_per_testcase(Suite, TC, Config, Return, State) ->" n + " {Return, State#state{cases = State#state.cases + 1}}." n + n + "%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group," n + "%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed." n + "on_tc_fail(Suite, TC, Reason, State) ->" n + " State#state{fails = State#state.fails + 1}." n + n + "%% Called when a test case is skipped by either user action" n + "%% or due to an init function failing." n + "on_tc_skip(Suite, TC, Reason, State) ->" n + " State#state{skips = State#state.skips + 1}." n + n + "%% Called when the scope of the CTH is done" n + "terminate(State) ->" n + " logger:notice(\"~s is done: ~p~n\", [?MODULE, State])." n + n + ) + "*The template of a library module. + Please see the function `tempo-define-template'.") + ;; Skeleton code: ;; This code is based on the package `tempo' which is part of modern diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el index c35f280bf42d..a19f72e24338 100644 --- a/lib/tools/emacs/erlang-start.el +++ b/lib/tools/emacs/erlang-start.el @@ -74,9 +74,9 @@ "Find manual page for NAME, where NAME is module:function." t) (autoload 'erlang-find-tag "erlang" - "Like `find-tag'. Capable of retreiving Erlang modules.") + "Like `find-tag'. Capable of retrieving Erlang modules.") (autoload 'erlang-find-tag-other-window "erlang" - "Like `find-tag-other-window'. Capable of retreiving Erlang modules.") + "Like `find-tag-other-window'. Capable of retrieving Erlang modules.") ;; ;; Declare functions in "erlang-edoc.el". diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 7216d6b6fdf1..a21f1df25ace 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -9,7 +9,7 @@ ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 1996-2021. All Rights Reserved. +;; Copyright Ericsson AB 1996-2023. 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. @@ -678,6 +678,8 @@ resulting regexp is surrounded by \\_< and \\_>." "of" "receive" "try" + "maybe" + "else" "when") "Erlang reserved keywords")) @@ -926,7 +928,6 @@ resulting regexp is surrounded by \\_< and \\_>." "delay_trap" "delete_element" "display" - "display_nl" "display_string" "dist_get_stat" "dist_ctrl_get_data" @@ -1466,8 +1467,8 @@ Other commands: (modify-syntax-entry ?\n ">" table) (modify-syntax-entry ?\" "\"" table) (modify-syntax-entry ?# "." table) - ;; (modify-syntax-entry ?$ "\\" table) ;; Creates problems with indention afterwards - ;; (modify-syntax-entry ?$ "'" table) ;; Creates syntax highlighting and indention problems + ;; (modify-syntax-entry ?$ "\\" table) ;; Creates problems with indentation afterwards + ;; (modify-syntax-entry ?$ "'" table) ;; Creates syntax highlighting and indentation problems (modify-syntax-entry ?$ "/" table) ;; Misses the corner case "string that ends with $" ;; we have to live with that for now..it is the best alternative ;; that can be worked around with "string that ends with \$" @@ -2730,13 +2731,13 @@ Value is list (stack token-start token-type in-what)." ;; Word constituent: check and handle keywords. ((= cs ?w) - (cond ((looking-at "\\(end\\|after\\)[^_a-zA-Z0-9]") + (cond ((looking-at "\\(end\\|after\\|else\\)[^_a-zA-Z0-9]") ;; Must pop top icr layer, `after' will push a new ;; layer next. (progn (while (and stack (eq (car (car stack)) '->)) (erlang-pop stack)) - (if (and stack (memq (car (car stack)) '(icr begin fun try))) + (if (and stack (memq (car (car stack)) '(icr begin fun try maybe))) (erlang-pop stack)))) ((looking-at "catch\\b.*of") t) @@ -2746,7 +2747,7 @@ Value is list (stack token-start token-type in-what)." (progn (while (and stack (eq (car (car stack)) '->)) (erlang-pop stack)) - (if (and stack (memq (car (car stack)) '(icr begin try))) + (if (and stack (memq (car (car stack)) '(icr begin try maybe))) (erlang-pop stack)))) ) (cond ((looking-at "\\(if\\|case\\|receive\\)[^_a-zA-Z0-9]") @@ -2768,7 +2769,7 @@ Value is list (stack token-start token-type in-what)." ((looking-at "\\(fun\\)[^_a-zA-Z0-9]") ;; Push a new layer if we are defining a `fun' - ;; expression, not when we are refering an existing + ;; expression, not when we are referring an existing ;; function. 'fun's defines are only indented one level now. (if (save-excursion (goto-char (match-end 1)) @@ -2783,6 +2784,11 @@ Value is list (stack token-start token-type in-what)." (erlang-push (list 'fun token (current-column)) stack))) ((looking-at "\\(begin\\)[^_a-zA-Z0-9]") (erlang-push (list 'begin token (current-column)) stack)) + ((looking-at "\\(maybe\\)[^_a-zA-Z0-9]") + (erlang-push (list 'begin token (current-column)) stack)) + ((looking-at "\\(else\\)[^_a-zA-Z0-9]") + (erlang-push (list 'icr token (current-column)) stack)) + ;; Normal when case ;;((looking-at "when\\s ") ;;((looking-at "when\\s *\\($\\|%\\)") @@ -2820,7 +2826,7 @@ Value is list (stack token-start token-type in-what)." (forward-char 1)) (t ;; Maybe a character literal, quote the next char to avoid - ;; situations as $" being seen as the begining of a string. + ;; situations as $" being seen as the beginning of a string. ;; Note the quoting something in the middle of a string is harmless. (quote (following-char)) (forward-char 1)))) @@ -2875,7 +2881,7 @@ Value is list (stack token-start token-type in-what)." (erlang-pop stack)) (cond ((eq (car (car stack)) '<<) (erlang-pop stack)) - ((memq (car (car stack)) '(icr begin fun)) + ((memq (car (car stack)) '(icr begin maybe fun)) (error "Missing `end'")) (t (error "Unbalanced parentheses"))) @@ -2947,6 +2953,8 @@ Value is list (stack token-start token-type in-what)." )) ((eq (car (car stack)) 'begin) (error "Missing `end'")) + ((eq (car (car stack)) 'maybe) + (error "Missing `end'")) (t (error "Unbalanced parenthesis")) ) @@ -3045,10 +3053,10 @@ Return nil if inside string, t if in a comment." (if (memq (following-char) '(?% ?\n)) (+ (nth 2 stack-top) erlang-indent-level) (current-column)))))))) - ((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\)[^_a-zA-Z0-9]")) + ((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\|}\\)[^_a-zA-Z0-9]")) (nth 2 (car (cdr stack)))) ;; Real indentation, where operators create extra indentation etc. - ((memq (car stack-top) '(-> || try begin)) + ((memq (car stack-top) '(-> || try begin maybe)) (if (looking-at "\\(of\\)[^_a-zA-Z0-9]") (nth 2 stack-top) (goto-char (nth 1 stack-top)) @@ -3060,6 +3068,8 @@ Return nil if inside string, t if in a comment." (cond ((null (cdr stack))) ; Top level in function. ((eq (car stack-top) 'begin) (setq skip 5)) + ((eq (car stack-top) 'maybe) + (setq skip 5)) ((eq (car stack-top) 'try) (setq skip 5)) ((eq (car stack-top) '->) @@ -3073,7 +3083,7 @@ Return nil if inside string, t if in a comment." (let ((base (erlang-indent-find-base stack indent-point off skip))) ;; Special cases (goto-char indent-point) - (cond ((looking-at "\\(;\\|end\\|after\\)\\($\\|[^_a-zA-Z0-9]\\)") + (cond ((looking-at "\\(;\\|end\\|after\\|else\\)\\($\\|[^_a-zA-Z0-9]\\)") (if (eq (car stack-top) '->) (erlang-pop stack)) (cond ((and stack (looking-at ";")) @@ -3222,11 +3232,16 @@ Return nil if inside string, t if in a comment." (progn (if (memq (car stack-top) '(-> ||)) (erlang-pop stack)) - ;; Take parent identation + offset, + ;; Take parent indentation + offset, ;; else just erlang-indent-level if no parent (if stack - (+ (caddr (car stack)) - offset) + (progn + (goto-char (- (nth 1 (car stack)) 1)) + (if (looking-at "#{") + (+ (caddr (car stack)) + (- offset 1)) + (+ (caddr (car stack)) + offset))) erlang-indent-level)) (erlang-skip-blank indent-point) (current-column))) @@ -3324,8 +3339,8 @@ This assumes that the preceding expression is either simple (defun erlang-at-keyword () "Are we looking at an Erlang keyword which will increase indentation?" - (looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|" - "of\\|receive\\|after\\|catch\\|try\\)\\b"))) + (looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|maybe\\|" + "of\\|receive\\|after\\|catch\\|try\\|else\\)\\b"))) (defun erlang-at-operator () "Are we looking at an Erlang operator?" @@ -6068,7 +6083,7 @@ unless the optional NO-DISPLAY is non-nil." erlang-compile-erlang-function module-name (inferior-erlang-format-comma-opts opts)) - (let (;; Hopefully, noone else will ever use these... + (let (;; Hopefully, no one else will ever use these... (tmpvar "Tmp7236") (tmpvar2 "Tmp8742")) (format diff --git a/lib/tools/emacs/erlang_appwiz.el b/lib/tools/emacs/erlang_appwiz.el index b71c18073911..1928ea027971 100644 --- a/lib/tools/emacs/erlang_appwiz.el +++ b/lib/tools/emacs/erlang_appwiz.el @@ -23,7 +23,7 @@ ;;(defvar erlang-skel-makefile-src ;; '((erlang-skel-include erlang-skel-nomodule-header) ;; "CC_ROOT := $(shell pwd | sed 's/erts.*$$//')" n -;; "AUTOCONF := $(CC_ROOT)/erts/autoconf" n +;; "AUTOCONF := $(CC_ROOT)/make/autoconf" n ;; "TARGET := $(shell $(AUTOCONF)/config.guess)" ;; "include $(CC_ROOT)/internal_tools/make/$(TARGET)/otp.mk" n ;; n @@ -272,7 +272,7 @@ creating the root directory and for naming application files." erlang-skel-normal-header erlang-skel-header) ("Large Header" "large-header" erlang-skel-large-header erlang-skel-header) - ("No Moudle Header" "nomodule-header" + ("No Module Header" "nomodule-header" erlang-skel-nomodule-header erlang-skel-header) () ("Small Server" "small-server" @@ -302,7 +302,7 @@ The first element is the name which shows up in the menu. The second is the `tempo' identfier (The string \"erlang-\" will be added in front of it). The third is the skeleton descriptor, a variable containing `tempo' attributes as described in the function -`tempo-define-template'. The optinal fourth elements denotes a +`tempo-define-template'. The optional fourth elements denotes a function which should be called when the menu is selected. Functions corresponding to every template will be created. The name @@ -310,7 +310,7 @@ of the function will be `tempo-template-erlang-X' where `X' is the tempo identifier as specified in the second argument of the elements in this list. -A list with zero elemets means that the a horisontal line should +A list with zero elements means that the a horisontal line should be placed in the menu.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -451,7 +451,7 @@ Example: ((\"Yellow\" function-yellow) (\"Blue\" function-blue))) nil - (\"Region Funtion\" spook-function midnight-variable)) + (\"Region Function\" spook-function midnight-variable)) Call the function `erlang-menu-init' after modifying this variable.") diff --git a/lib/tools/emacs/internal_doc/emacs.sgml b/lib/tools/emacs/internal_doc/emacs.sgml index 802f70fbea58..3fdb05b70101 100644 --- a/lib/tools/emacs/internal_doc/emacs.sgml +++ b/lib/tools/emacs/internal_doc/emacs.sgml @@ -2729,8 +2729,8 @@ individual user configures their Emacs Init files to use it.

    If we assume that OTP has been installed in -OTP_ROOT, the editing mode can be found in -OTP_ROOT/misc/emacs. +$OTPROOT, the editing mode can be found in +$OTPROOT/misc/emacs.

    The erlang.el file found in the installation directory is already @@ -2777,15 +2777,15 @@ Emacs will look for the .emacs file in C:\. Extending the load path

    The directory with the editing mode, -OTP_ROOT/misc/emacs, must be in the load path for Emacs. +$OTPROOT/misc/emacs, must be in the load path for Emacs.

    Add the following line to the selected initialization file (replace - OTP_ROOT with the name of the installation + OTPROOT with the name of the installation directory for OTP, keep the quote characters):

    - (setq load-path (cons "OTP_ROOT/misc/emacs" load-path)) + (setq load-path (cons "OTPROOT/misc/emacs" load-path)) @@ -2805,12 +2805,12 @@ an escape character.

    Some functions in the Erlang editing mode require that the OTP installation directory is known. The following is an example where we -assume that they are installed in the directory OTP_ROOT, +assume that they are installed in the directory $OTPROOT, change this to reflect the location on your system.

    - (setq erlang-root-dir "OTP_ROOT") + (setq erlang-root-dir "OTPROOT")
    @@ -2832,11 +2832,11 @@ platform for details.

    You can also extend the execution path for Emacs as described -below. If the executable is located in OTP_ROOT/bin then you +below. If the executable is located in $OTPROOT/bin then you add the following line to you Emacs Init file: - (setq exec-path (cons "OTP_ROOT/bin" exec-path)) + (setq exec-path (cons "OTPROOT/bin" exec-path))

    @@ -2923,7 +2923,7 @@ Restart the Emacs and load or create an Erlang file (with the .erl extension). If the installation was performed correctly the mode line should contain the word "Erlang". Select the "Version" menu item in the "Erlang" menu, check that the version number matches the version in -found in the files in OTP_ROOT/misc/emacs. +found in the files in $OTPROOT/misc/emacs.

    diff --git a/lib/tools/examples/Makefile b/lib/tools/examples/Makefile index 0fcc66d874c2..a5e0473f64f7 100644 --- a/lib/tools/examples/Makefile +++ b/lib/tools/examples/Makefile @@ -39,7 +39,7 @@ EXAMPLE_FILES = xref_examples.erl # Targets # ---------------------------------------------------- -debug opt: +$(TYPES): clean: diff --git a/lib/tools/obj/.gitignore b/lib/tools/obj/.gitignore deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile index cc5bee9a8f80..254e0c7196a1 100644 --- a/lib/tools/src/Makefile +++ b/lib/tools/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2018. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -41,7 +41,6 @@ MODULES= \ fprof \ cprof \ lcnt \ - instrument \ make \ tags \ xref \ @@ -84,7 +83,7 @@ ERL_COMPILE_FLAGS += -Werror # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) +$(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) clean: rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 83ccde524f8b..fe9518b3cb7b 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2021. All Rights Reserved. +%% Copyright Ericsson AB 2001-2023. 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. @@ -336,6 +336,8 @@ filter_options(Options) -> {d, _Macro, _Value} -> true; export_all -> true; tuple_calls -> true; + {feature,_,enable} -> true; %FIXME: To be removed. + {feature,_,disable} -> true; %FIXME: To be removed. _ -> false end end, @@ -430,7 +432,7 @@ get_mods_and_beams([{Module,File}|ModFiles],Acc) -> %% Duplicate, but same file so ignore get_mods_and_beams(ModFiles,Acc); {ok,Module,_OtherFile} -> - %% Duplicate and differnet file - error + %% Duplicate and different file - error get_mods_and_beams(ModFiles,[{error,{duplicate,Module}}|Acc]); _ -> get_mods_and_beams(ModFiles,[{ok,Module,File}|Acc]) @@ -1863,6 +1865,10 @@ expand({bc,Anno,Expr,Qs}, Vs, N) -> {ExpandedExpr,N2} = expand(Expr, Vs, N), {ExpandedQs,N3} = expand_qualifiers(Qs, Vs, N2), {{bc,Anno,ExpandedExpr,ExpandedQs},N3}; +expand({mc,Anno,Expr,Qs}, Vs, N) -> + {ExpandedExpr,N2} = expand(Expr, Vs, N), + {ExpandedQs,N3} = expand_qualifiers(Qs, Vs, N2), + {{mc,Anno,ExpandedExpr,ExpandedQs},N3}; expand({op,_Anno,'andalso',ExprL,ExprR}, Vs, N) -> {ExpandedExprL,N2} = expand(ExprL, Vs, N), {ExpandedExprR,N3} = expand(ExprR, Vs, N2), @@ -1958,7 +1964,7 @@ munge({function,Anno,Function,Arity,Clauses},Vars,_MainFile,on) -> {MungedClauses, Vars3} = munge_clauses(Clauses, Vars2), {{function,Anno,Function,Arity,MungedClauses},Vars3,on}; munge(Form={attribute,_,file,{MainFile,_}},Vars,MainFile,_Switch) -> - {Form,Vars,on}; % Switch on tranformation! + {Form,Vars,on}; % Switch on transformation! munge(Form={attribute,_,file,{_InclFile,_}},Vars,_MainFile,_Switch) -> {Form,Vars,off}; % Switch off transformation! munge({attribute,_,compile,{parse_transform,_}},_Vars,_MainFile,_Switch) -> @@ -2169,6 +2175,10 @@ munge_expr({match,Anno,ExprL,ExprR}, Vars) -> {MungedExprL, Vars2} = munge_expr(ExprL, Vars), {MungedExprR, Vars3} = munge_expr(ExprR, Vars2), {{match,Anno,MungedExprL,MungedExprR}, Vars3}; +munge_expr({maybe_match,Anno,ExprL,ExprR}, Vars) -> + {MungedExprL, Vars2} = munge_expr(ExprL, Vars), + {MungedExprR, Vars3} = munge_expr(ExprR, Vars2), + {{maybe_match,Anno,MungedExprL,MungedExprR}, Vars3}; munge_expr({tuple,Anno,Exprs}, Vars) -> {MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []), {{tuple,Anno,MungedExprs}, Vars2}; @@ -2233,6 +2243,11 @@ munge_expr({bc,Anno,Expr,Qs}, Vars) -> {MungedExpr,Vars2} = munge_expr(?BLOCK1(Expr), Vars), {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{bc,Anno,MungedExpr,MungedQs}, Vars3}; +munge_expr({mc,Anno,{map_field_assoc,FAnno,K,V},Qs}, Vars) -> + Expr = {map_field_assoc,FAnno,?BLOCK1(K),?BLOCK1(V)}, + {MungedExpr,Vars2} = munge_expr(Expr, Vars), + {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), + {{mc,Anno,MungedExpr,MungedQs}, Vars3}; munge_expr({block,Anno,Body}, Vars) -> {MungedBody, Vars2} = munge_body(Body, Vars), {{block,Anno,MungedBody}, Vars2}; @@ -2260,6 +2275,13 @@ munge_expr({'try',Anno,Body,Clauses,CatchClauses,After}, Vars) -> {MungedAfter, Vars4} = munge_body(After, Vars3), {{'try',Anno,MungedBody,MungedClauses,MungedCatchClauses,MungedAfter}, Vars4}; +munge_expr({'maybe',Anno,Exprs}, Vars) -> + {MungedExprs, Vars2} = munge_body(Exprs, Vars), + {{'maybe',Anno,MungedExprs}, Vars2}; +munge_expr({'maybe',MaybeAnno,Exprs,{'else',ElseAnno,Clauses}}, Vars) -> + {MungedExprs, Vars2} = munge_body(Exprs, Vars), + {MungedClauses, Vars3} = munge_clauses(Clauses, Vars2), + {{'maybe',MaybeAnno,MungedExprs,{'else',ElseAnno,MungedClauses}}, Vars3}; munge_expr({'fun',Anno,{clauses,Clauses}}, Vars) -> {MungedClauses,Vars2}=munge_clauses(Clauses, Vars), {{'fun',Anno,{clauses,MungedClauses}}, Vars2}; @@ -2298,6 +2320,10 @@ munge_qs([{b_generate,Anno,Pattern,Expr}|Qs], Vars, MQs) -> A = element(2, Expr), {MExpr, Vars2} = munge_expr(Expr, Vars), munge_qs1(Qs, A, {b_generate,Anno,Pattern,MExpr}, Vars, Vars2, MQs); +munge_qs([{m_generate,Anno,Pattern,Expr}|Qs], Vars, MQs) -> + A = element(2, Expr), + {MExpr, Vars2} = munge_expr(Expr, Vars), + munge_qs1(Qs, A, {m_generate,Anno,Pattern,MExpr}, Vars, Vars2, MQs); munge_qs([Expr|Qs], Vars, MQs) -> A = element(2, Expr), {MungedExpr, Vars2} = munge_expr(Expr, Vars), diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl index 0d24120b835d..bc2a0a3ac4cd 100644 --- a/lib/tools/src/fprof.erl +++ b/lib/tools/src/fprof.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2020. All Rights Reserved. +%% Copyright Ericsson AB 2001-2022. 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. @@ -21,7 +21,7 @@ %%%---------------------------------------------------------------------- %%% File : fprof.erl %%% Author : Raimo Niskanen -%%% Purpose : File tracing profiling tool wich accumulated times. +%%% Purpose : File tracing profiling tool which accumulated times. %%% Created : 18 Jun 2001 by Raimo Niskanen %%%---------------------------------------------------------------------- diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl index 978c78038df3..f9b0ba80e0d2 100644 --- a/lib/tools/src/lcnt.erl +++ b/lib/tools/src/lcnt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2020. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -893,7 +893,7 @@ clean_id_creation(Id) when is_port(Id) -> <<131, PortTag, AtomTag>> = H, LL = atomlen_bits(AtomTag), CL = creation_bits(PortTag), - <> = Rest, + <> = Rest, Bin2 = list_to_binary([H, <>, Node, Ids, <<0:CL>>]), binary_to_term(Bin2); clean_id_creation(Id) -> @@ -901,8 +901,7 @@ clean_id_creation(Id) -> -define(PID_EXT, $g). -define(NEW_PID_EXT, $X). --define(PORT_EXT, $f). --define(NEW_PORT_EXT, $Y). +-define(V4_PORT_EXT, $x). -define(ATOM_EXT, $d). -define(SMALL_ATOM_EXT, $s). -define(ATOM_UTF8_EXT, $v). @@ -915,8 +914,7 @@ atomlen_bits(?SMALL_ATOM_UTF8_EXT) -> 8. creation_bits(?PID_EXT) -> 8; creation_bits(?NEW_PID_EXT) -> 32; -creation_bits(?PORT_EXT) -> 8; -creation_bits(?NEW_PORT_EXT) -> 32. +creation_bits(?V4_PORT_EXT) -> 32. %% serializer diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl index df110185a2fc..2287196484d2 100644 --- a/lib/tools/src/tags.erl +++ b/lib/tools/src/tags.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2022. 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. @@ -59,7 +59,7 @@ %% directories in `DirList'. %% %% subdir(Dir [, Options]) -- Descend recursively down `Dir' and create -%% a TAGS file convering all files found. +%% a TAGS file covering all files found. %% subdirs(DirList [, Options]) %% -- Dito, for all directories in `DirList'. %% diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src index f0c7ec1ead35..e3b8bb021575 100644 --- a/lib/tools/src/tools.app.src +++ b/lib/tools/src/tools.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2020. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. 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. @@ -24,7 +24,6 @@ cprof, eprof, fprof, - instrument, lcnt, make, tags, diff --git a/lib/tools/src/xref.erl b/lib/tools/src/xref.erl index 2da8899ec83d..40549d8fc75f 100644 --- a/lib/tools/src/xref.erl +++ b/lib/tools/src/xref.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2020. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -83,11 +83,11 @@ | {'unused', [mfa()]}, NoDebugInfoResult :: {'deprecated', [xmfa()]} | {'undefined', [xmfa()]}, - Reason :: {'cover_compiled', Module} + Reason :: {'cover_compiled', Module :: module()} | {'file_error', file(), file_error()} - | {'interpreted', Module} + | {'interpreted', Module :: module()} | {'invalid_filename', term()} - | {'no_such_module', Module} + | {'no_such_module', Module :: module()} | beam_lib:chnk_rsn(). %% No user variables have been assigned digraphs, so there is no diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl index 383bb5e8d318..5eeb7fa8b568 100644 --- a/lib/tools/src/xref_reader.erl +++ b/lib/tools/src/xref_reader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2023. 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. @@ -77,10 +77,6 @@ forms([], S) -> F -> [{M, F, 0}] end, - #xrefr{def_at = DefAt, - l_call_at = LCallAt, x_call_at = XCallAt, - el = LC, ex = XC, x = X, df = Depr, on_load = OnLoad, - lattrs = AL, xattrs = AX, battrs = B, unresolved = U} = S, Attrs = {lists:reverse(AL), lists:reverse(AX), lists:reverse(B)}, {ok, M, {DefAt, LCallAt, XCallAt, LC, XC, X, Attrs, Depr, OL}, U}. diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile index 350b93697893..bfa18874458e 100644 --- a/lib/tools/test/Makefile +++ b/lib/tools/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2020. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -24,10 +24,8 @@ MODULES = \ cover_SUITE \ eprof_SUITE \ emacs_SUITE \ - emem_SUITE \ fprof_SUITE \ cprof_SUITE \ - instrument_SUITE \ lcnt_SUITE \ make_SUITE \ tools_SUITE \ @@ -55,6 +53,7 @@ RELSYSDIR = $(RELEASE_PATH)/tools_test # ---------------------------------------------------- ERL_MAKE_FLAGS += ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) EBIN = . @@ -67,7 +66,7 @@ make_emakefile: $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ > $(EMAKEFILE) -tests debug opt: make_emakefile +tests $(TYPES): make_emakefile erl $(ERL_MAKE_FLAGS) -make clean: diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index 1393c9d1e149..ac792380a9d6 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2021. All Rights Reserved. +%% Copyright Ericsson AB 2001-2023. 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. @@ -25,14 +25,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}, - {timetrap,{minutes,5}}]. + {timetrap,{minutes,2}}]. all() -> NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273, otp_8340,otp_8188,compile_beam_opts,eep37, analyse_no_beam, line_0, compile_beam_no_file, compile_beam_missing_backend, - otp_13277, otp_13289, guard_in_lc, gh_4796], + otp_13277, otp_13289, guard_in_lc, gh_4796, + eep49], StartStop = [start, compile, analyse, misc, stop, distribution, reconnect, die_and_reconnect, dont_reconnect_after_stop, stop_node_after_disconnect, @@ -440,14 +441,14 @@ distribution(Config) when is_list(Config) -> DataDir = proplists:get_value(data_dir, Config), ok = file:set_cwd(DataDir), - {ok,N1} = test_server:start_node(cover_SUITE_distribution1,slave,[]), - {ok,N2} = test_server:start_node(cover_SUITE_distribution2,slave,[]), - {ok,N3} = test_server:start_node(cover_SUITE_distribution3,slave,[]), - {ok,N4} = test_server:start_node(cover_SUITE_distribution4,slave,[]), + {ok,P1,N1} = ?CT_PEER(), + {ok,P2,N2} = ?CT_PEER(), + {ok,P3,N3} = ?CT_PEER(), + {ok,P4,N4} = ?CT_PEER(), %% Check that an already compiled module is loaded on new nodes {ok,f} = cover:compile(f), - {ok,[_,_,_,_]} = cover:start(nodes()), + {ok,[_,_,_,_]} = cover:start([N1,N2,N3,N4]), cover_compiled = code:which(f), cover_compiled = rpc:call(N1,code,which,[f]), cover_compiled = rpc:call(N2,code,which,[f]), @@ -474,7 +475,7 @@ distribution(Config) when is_list(Config) -> %% this is lost when the node is killed rpc:call(N3,f,f2,[]), - rpc:call(N3,erlang,halt,[]), + peer:stop(P3), %% this should be visible in analyse rpc:call(N1,f,f1,[]), @@ -514,7 +515,7 @@ distribution(Config) when is_list(Config) -> %% Check that flush collects data so calls are not lost if node is killed rpc:call(N4,f,f2,[]), ok = cover:flush(N4), - rpc:call(N4,erlang,halt,[]), + peer:stop(P4), check_f_calls(1,3), %% Check that stop() unloads on all nodes @@ -535,8 +536,8 @@ distribution(Config) when is_list(Config) -> %% Cleanup Files = lsfiles(), remove(files(Files, ".beam")), - test_server:stop_node(N1), - test_server:stop_node(N2). + peer:stop(P1), + peer:stop(P2). %% Test that a lost node is reconnected reconnect(Config) -> @@ -547,19 +548,17 @@ reconnect(Config) -> {ok,b} = compile:file(b), {ok,f} = compile:file(f), - {ok,N1} = test_server:start_node(cover_SUITE_reconnect,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok,P1,N1} = ?CT_PEER(#{connection => 0, args => ["-pa", DataDir]}), {ok,a} = cover:compile(a), {ok,f} = cover:compile(f), - {ok,[N1]} = cover:start(nodes()), + {ok,[N1]} = cover:start([N1]), %% Some calls to check later rpc:call(N1,f,f1,[]), cover:flush(N1), rpc:call(N1,f,f1,[]), - %% This will cause first casue the N1 node to initiate a + %% This will cause first cause the N1 node to initiate a %% disconnect and then call f:f2() when nodes() =:= [] on N1. rpc:cast(N1,f,call_f2_when_isolated,[]), timer:sleep(500), % allow some to detect disconnect and for f:f2() call @@ -590,7 +589,7 @@ reconnect(Config) -> check_f_calls(2,1), cover:stop(), - test_server:stop_node(N1), + peer:stop(P1), ok. %% Test that a lost node is reconnected - also if it has been dead @@ -600,13 +599,10 @@ die_and_reconnect(Config) -> {ok,f} = compile:file(f), - NodeName = cover_SUITE_die_and_reconnect, - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok, P1, N1} = ?CT_PEER(#{name => ?CT_PEER_NAME(), args => ["-pa", DataDir]}), %% {ok,a} = cover:compile(a), {ok,f} = cover:compile(f), - {ok,[N1]} = cover:start(nodes()), + {ok,[N1]} = cover:start([N1]), %% Some calls to check later rpc:call(N1,f,f1,[]), @@ -614,15 +610,13 @@ die_and_reconnect(Config) -> rpc:call(N1,f,f1,[]), %% Kill the node - rpc:call(N1,erlang,halt,[]), + peer:stop(P1), cover_which_nodes([]), check_f_calls(1,0), % only the first call - before the flush %% Restart the node and check that cover reconnects - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok,P2,N1} = ?CT_PEER(#{name => N1, args => ["-pa", DataDir]}), timer:sleep(100), [N1] = cover:which_nodes(), % we are reconnected cover_compiled = rpc:call(N1,code,which,[f]), @@ -634,7 +628,7 @@ die_and_reconnect(Config) -> check_f_calls(2,0), cover:stop(), - test_server:stop_node(N1), + peer:stop(P2), ok. %% Test that a stopped node is not marked as lost, i.e. that it is not @@ -645,27 +639,23 @@ dont_reconnect_after_stop(Config) -> {ok,f} = compile:file(f), - NodeName = cover_SUITE_dont_reconnect_after_stop, - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok, P1, N1} = ?CT_PEER(#{name => ?CT_PEER_NAME(), args => ["-pa", DataDir], + start_cover => false}), {ok,f} = cover:compile(f), - {ok,[N1]} = cover:start(nodes()), + {ok,[N1]} = cover:start([N1]), %% A call to check later rpc:call(N1,f,f1,[]), %% Stop cover on the node, then terminate the node cover:stop(N1), - rpc:call(N1,erlang,halt,[]), + peer:stop(P1), cover_which_nodes([]), check_f_calls(1,0), %% Restart the node and check that cover does not reconnect - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok, P2, N1} = ?CT_PEER(#{name => N1, args => ["-pa", DataDir], start_cover => false}), timer:sleep(300), cover_which_nodes([]), Beam = rpc:call(N1,code,which,[f]), @@ -679,7 +669,7 @@ dont_reconnect_after_stop(Config) -> check_f_calls(1,0), cover:stop(), - test_server:stop_node(N1), + peer:stop(P2), ok. %% Test that a node which is stopped while it is marked as lost is not @@ -690,19 +680,17 @@ stop_node_after_disconnect(Config) -> {ok,f} = compile:file(f), - NodeName = cover_SUITE_stop_node_after_disconnect, - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok, P1, N1} = ?CT_PEER(#{name => ?CT_PEER_NAME(), args => ["-pa", DataDir], + start_cover => false}), {ok,f} = cover:compile(f), - {ok,[N1]} = cover:start(nodes()), + {ok,[N1]} = cover:start([N1]), %% A call to check later rpc:call(N1,f,f1,[]), %% Flush the node, then terminate the node to make it marked as lost cover:flush(N1), - rpc:call(N1,erlang,halt,[]), + peer:stop(P1), check_f_calls(1,0), @@ -710,9 +698,7 @@ stop_node_after_disconnect(Config) -> cover:stop(N1), %% Restart the node and check that cover does not reconnect - {ok,N1} = test_server:start_node(NodeName,peer, - [{args," -pa " ++ DataDir}, - {start_cover,false}]), + {ok, P2, N1} = ?CT_PEER(#{name => N1, args => ["-pa", DataDir], start_cover => false}), timer:sleep(300), cover_which_nodes([]), Beam = rpc:call(N1,code,which,[f]), @@ -726,7 +712,7 @@ stop_node_after_disconnect(Config) -> check_f_calls(1,0), cover:stop(), - test_server:stop_node(N1), + peer:stop(P2), ok. distribution_performance(Config) -> @@ -742,18 +728,14 @@ distribution_performance(Config) -> % test_server:break(""), - NodeName = cover_SUITE_distribution_performance, - {ok,N1} = test_server:start_node(NodeName,peer,[{start_cover,false}]), + {ok, P1, N1} = ?CT_PEER(), %% CFun = fun() -> %% [{ok,_} = cover:compile_beam(Mod) || Mod <- Mods] %% end, CFun = fun() -> cover:compile_beam(Mods) end, - {CT,_CA} = timer:tc(CFun), - % erlang:display(_CA), - erlang:display({compile,CT}), + {_CT, _CA} = timer:tc(CFun), - {SNT,_} = timer:tc(fun() -> {ok,[N1]} = cover:start(nodes()) end), - erlang:display({start_node,SNT}), + {ok,[N1]} = cover:start([N1]), [1 = rpc:call(N1,Mod,f1,[1]) || Mod <- Mods], @@ -769,16 +751,14 @@ distribution_performance(Config) -> % Fun = fun() -> cover:reset() end, - {AT,_A} = timer:tc(Fun), - erlang:display({analyse,AT}), + {_AT, _A} = timer:tc(Fun), % erlang:display(lists:sort([X || X={_MFA,N} <- lists:append([L || {ok,L}<-A]), N=/=0])), %% fprof:apply(Fun, [],[{procs,[whereis(cover_server)]}]), %% fprof:profile(), %% fprof:analyse(dest,[]), - {SNT2,_} = timer:tc(fun() -> test_server:stop_node(N1) end), - erlang:display({stop_node,SNT2}), + peer:stop(P1), code:del_path(Dir), Files = filelib:wildcard(AllFiles), @@ -861,7 +841,7 @@ export_import(Config) when is_list(Config) -> ok = cover:stop(), %% Check that same data exists after import and that info is written about - %% data comming from imported file + %% data coming from imported file ok = cover:import("f_exported"), test_server:capture_start(), check_f_calls(1,0), @@ -946,11 +926,11 @@ export_import(Config) when is_list(Config) -> otp_5031(Config) when is_list(Config) -> ct:timetrap({seconds, 10}), - {ok,N1} = test_server:start_node(cover_SUITE_otp_5031,slave,[]), + {ok,Peer,N1} = ?CT_PEER(), {ok,[N1]} = cover:start(N1), {error,not_main_node} = rpc:call(N1,cover,modules,[]), cover:stop(), - test_server:stop_node(N1), + peer:stop(Peer), ok. %% Test the \'Exclude Included Functions\' functionality @@ -1005,7 +985,7 @@ otp_6115(Config) when is_list(Config) -> {ok, f1} = cover:compile(f1), %% This test used to ensure that a process containing a - %% fun refering to cover compiled code was killed. + %% fun referring to cover compiled code was killed. %% check_process_code may however ignore funs as of ERTS %% version 8.1. The test has therefore been rewritten to %% check that a process with a direct reference (in this @@ -1159,13 +1139,13 @@ otp_8270(Config) when is_list(Config) -> PrivDir = proplists:get_value(priv_dir, Config), - As = [{args," -pa " ++ PrivDir}], - {ok,N1} = test_server:start_node(cover_n1,slave,As), - {ok,N2} = test_server:start_node(cover_n2,slave,As), - {ok,N3} = test_server:start_node(cover_n3,slave,As), + As = ["-pa", PrivDir], + {ok,P1,N1} = ?CT_PEER(As), + {ok,P2,N2} = ?CT_PEER(As), + {ok,P3,N3} = ?CT_PEER(As), timer:sleep(500), - {ok,[_,_,_]} = cover:start(nodes()), + {ok,[_,_,_]} = cover:start([N1,N2,N3]), Test = <<"-module(m).\n" "-compile(export_all).\n" @@ -1203,9 +1183,9 @@ otp_8270(Config) when is_list(Config) -> {N3,true} = {N3,is_list(N3_info)}, exit(Pid1,kill), - test_server:stop_node(N1), - test_server:stop_node(N2), - test_server:stop_node(N3), + peer:stop(P1), + peer:stop(P2), + peer:stop(P3), ok. %% OTP-8273. Bug. @@ -1542,6 +1522,25 @@ comprehension_8188(Cf) -> " <<_>> <= << 1, 2 >>,\n" % 2 " true >>.\n" % 4 "two() -> 2">>, Cf), % 1 + + [{{t,1},1}, + {{t,2},2}, + {{t,3},2}, + {{t,5},1}, + {{t,8},3}, + {{t,9},2}, + {{t,10},1}] = + analyse_expr(<<"#{\n" %1 + " K + 1 =>\n" %2 + "X * 2 ||\n" %2 + " K := X <-\n" + " #{1 => 1,\n" %1 + " 2 => two(),\n" + " 3 => 3},\n" + " X > 1,\n" %3 + " true}. \n" %2 + " two() -> 2">>, Cf), %1 + ok. eep37(Config) when is_list(Config) -> @@ -1607,7 +1606,7 @@ cover_clauses(Config) when is_list(Config) -> -export([clauses/0]). clauses() -> ok. ">>, - File = cc_mod(cover_clauses, Test, Config), + _File = cc_mod(cover_clauses, Test, Config), ok. %% Take compiler options from beam in cover:compile_beam @@ -1835,9 +1834,9 @@ local_only(Config) -> %% Make sure that it is not possible to run cover on %% slave nodes. - {ok,Name} = test_server:start_node(?FUNCTION_NAME, slave, []), + {ok,Peer,Name} = ?CT_PEER(), {error,local_only} = cover:start([Name]), - test_server:stop_node(Name), + peer:stop(Peer), ok. %% ERL-943; We should not crash on startup when multiple servers race to @@ -1895,6 +1894,63 @@ gh_4796(Config) -> ok = file:delete(File), ok = gh_4796:test(). +%% Test the maybe ... else ... end construct. +eep49(Config) -> + ok = file:set_cwd(proplists:get_value(priv_dir, Config)), + + File = "t.erl", + Test = <<"-module(t). + -feature(maybe_expr,enable). + -export([t/0]). + + t() -> + t1(), %6 + + {a,b} = t2({ok,a}, {ok,b}), %8 + error = t2({ok,a}, error), %9 + whatever = t2(whatever, thing), %10 + + {a,b} = t3({ok,a}, {ok,b}), %12 + error = t3({ok,a}, {error,wrong}), %13 + {'EXIT',{{else_clause,whatever},_}} = catch t3(whatever, thing), %14 + + ok. %16 + + t1() -> + maybe %19 + ok %20 + end. + + t2(X, Y) -> + maybe %24 + {ok,A} ?= X, %25 + {ok,B} ?= Y, %26 + {A,B} %27 + end. + + t3(X, Y) -> + maybe %31 + {ok,A} ?= X, %32 + {ok,B} ?= Y, %33 + {A,B} %34 + else + {error,_} -> + error %37 + end. + ">>, + ok = file:write_file(File, Test), + {ok, t} = cover:compile(File), + ok = t:t(), + {ok,[{{t,6},1}, {{t,8},1}, {{t,9},1}, {{t,10},1}, {{t,12},1}, + {{t,13},1}, {{t,14},1}, {{t,16},1}, + {{t,19},1}, {{t,20},1}, + {{t,24},3}, {{t,25},3}, {{t,26},2}, {{t,27},1}, + {{t,31},3}, {{t,32},3}, {{t,33},2}, {{t,34},1}, {{t,37},1} + ]} = cover:analyse(t, calls, line), + ok = file:delete(File), + ok. + + %%--Auxiliary------------------------------------------------------------ analyse_expr(Expr, Config) -> diff --git a/lib/tools/test/cprof_SUITE.erl b/lib/tools/test/cprof_SUITE.erl index 8eb7476f577a..d27371414ab3 100644 --- a/lib/tools/test/cprof_SUITE.erl +++ b/lib/tools/test/cprof_SUITE.erl @@ -203,9 +203,8 @@ on_load_test(Config) -> N2 = cprof:pause(), {Module,0,[]} = cprof:analyse(Module), M4__4 = M*4 - 4, - M10_7 = M*10 - 7, - {?MODULE,M10_7,[{{?MODULE,succ,1},M4__4}, - {{?MODULE,'-fun.succ/1-',1},M4__4}, + M6_3 = M*6 - 3, + {?MODULE,M6_3,[{{?MODULE,succ,1},M4__4}, {{?MODULE,seq_r,4},M}, {{?MODULE,seq,3},M}, {{?MODULE,seq_r,3},1}]} @@ -234,11 +233,10 @@ modules_test(Config) -> N = cprof:pause(), Lr = lists:reverse(L), M4_4 = M*4 - 4, - M10_7 = M*10 - 7, + M6_3 = M*6 - 3, M2__1 = M*2 + 1, {Tot,ModList} = cprof:analyse(), - {value,{?MODULE,M10_7,[{{?MODULE,succ,1},M4_4}, - {{?MODULE,'-fun.succ/1-',1},M4_4}, + {value,{?MODULE,M6_3,[{{?MODULE,succ,1},M4_4}, {{?MODULE,seq_r,4},M}, {{?MODULE,seq,3},M}, {{?MODULE,seq_r,3},1}]}} = diff --git a/lib/tools/test/emacs_SUITE_data/comments b/lib/tools/test/emacs_SUITE_data/comments index ff974ca295ab..b16d398643a6 100644 --- a/lib/tools/test/emacs_SUITE_data/comments +++ b/lib/tools/test/emacs_SUITE_data/comments @@ -3,11 +3,11 @@ %%% 3 comment chars: always left indented %%% 2 comment chars: Context indented -%%% 1 comment char: Rigth indented +%%% 1 comment char: Right indented %%% left %% context dependent - % rigth + % right func() -> %%% left @@ -15,7 +15,7 @@ func() -> % right indented case get(foo) of undefined -> - %% Testing indention + %% Testing indentation ok; %% Catch all Other -> diff --git a/lib/tools/test/emacs_SUITE_data/comprehensions b/lib/tools/test/emacs_SUITE_data/comprehensions index 45279850a5a8..002c9140ade2 100644 --- a/lib/tools/test/emacs_SUITE_data/comprehensions +++ b/lib/tools/test/emacs_SUITE_data/comprehensions @@ -45,3 +45,18 @@ binary(B) -> true = (X rem 2) >>, ok. + +maps(Map) -> + New1 = #{ V => K || + K := V <- Map}, + + New2 = #{ V = K || K := V <- Map, + true =:= V + }, + + New3 = #{ + V => K + || + K := V <- + Map + }. diff --git a/lib/tools/test/emacs_SUITE_data/funcs b/lib/tools/test/emacs_SUITE_data/funcs index 877f9820051f..820905687d78 100644 --- a/lib/tools/test/emacs_SUITE_data/funcs +++ b/lib/tools/test/emacs_SUITE_data/funcs @@ -128,7 +128,7 @@ match6(M6A, funs(1) when X -> - %% Changed fun to one indention level + %% Changed fun to one indentation level %% 'when' and several clause forces a depth of '4' Var = spawn(fun(X, _) when X == 2; diff --git a/lib/tools/test/emacs_SUITE_data/highlight b/lib/tools/test/emacs_SUITE_data/highlight index 0719f6516a22..58d6bd9c0df8 100644 --- a/lib/tools/test/emacs_SUITE_data/highlight +++ b/lib/tools/test/emacs_SUITE_data/highlight @@ -69,10 +69,10 @@ highlighting(X) % Function definitions should be highlighted not_a_guard:is_list([]), %% Other Types - atom, % not (currently) hightlighted + atom, % not (currently) highlighted 234234, 234.43, - [list, are, not, higlighted], + [list, are, not, highlighted], {nor, is, tuple}, ok. diff --git a/lib/tools/test/emacs_SUITE_data/icr b/lib/tools/test/emacs_SUITE_data/icr index 8445c1a74daa..ecfe23c5a196 100644 --- a/lib/tools/test/emacs_SUITE_data/icr +++ b/lib/tools/test/emacs_SUITE_data/icr @@ -155,3 +155,42 @@ indent_receive() -> 5*43 end, ok. + +indent_maybe(1) -> + begin + maybe_should_be_indented_as_begin, + end, + maybe + 1 = foo(X), + 2 ?= asd(X), + line_with_break = + foo(X+1), + line_with_break ?= + foo(X+1) + end, + ok; +indent_maybe(1) -> + maybe + 2 ?= foo(X), + 3 ?= bar(Y) + else + %% else indented as a standard icr (if-case-receive) + {error, Z} when Z == 1 -> + error1; + {error, Z} + when Z == 2 -> + error2 + end; +indent_maybe(3) -> + maybe + 2 ?= foo(x), + maybe + nested ?= foo(y) + else + error -> + ok + end + else + error -> ok + end. + diff --git a/lib/tools/test/emem_SUITE.erl b/lib/tools/test/emem_SUITE.erl deleted file mode 100644 index 968b36088374..000000000000 --- a/lib/tools/test/emem_SUITE.erl +++ /dev/null @@ -1,654 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2021. 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(emem_SUITE). - --export([all/0, suite/0, - init_per_testcase/2, end_per_testcase/2, - init_per_suite/1, end_per_suite/1, - receive_and_save_trace/2, send_trace/2]). - --export([live_node/1, - 'sparc_sunos5.8_32b_emt2.0'/1, - 'pc_win2000_32b_emt2.0'/1, - 'pc.smp_linux2.2.19pre17_32b_emt2.0'/1, - 'powerpc_darwin7.7.0_32b_emt2.0'/1, - 'alpha_osf1v5.1_64b_emt2.0'/1, - 'sparc_sunos5.8_64b_emt2.0'/1, - 'sparc_sunos5.8_32b_emt1.0'/1, - 'pc_win2000_32b_emt1.0'/1, - 'powerpc_darwin7.7.0_32b_emt1.0'/1, - 'alpha_osf1v5.1_64b_emt1.0'/1, - 'sparc_sunos5.8_64b_emt1.0'/1]). - --include_lib("kernel/include/file.hrl"). --include_lib("common_test/include/ct.hrl"). - --define(EMEM_64_32_COMMENT, - "64 bit trace; this build of emem can only handle 32 bit traces"). - --record(emem_res, {nodename, - hostname, - pid, - start_time, - trace_version, - max_word_size, - word_size, - last_values, - maximum, - exit_code}). - -%% -%% Exported suite functions -%% - -suite() -> - [{ct_hooks,[ts_install_cth]}, - {timetrap,{minutes,5}}]. - -all() -> - case test_server:is_debug() of - true -> {skip, "Not run when debug compiled"}; - false -> test_cases() - end. - - -test_cases() -> - [live_node, 'sparc_sunos5.8_32b_emt2.0', - 'pc_win2000_32b_emt2.0', - 'pc.smp_linux2.2.19pre17_32b_emt2.0', - 'powerpc_darwin7.7.0_32b_emt2.0', - 'alpha_osf1v5.1_64b_emt2.0', - 'sparc_sunos5.8_64b_emt2.0', - 'sparc_sunos5.8_32b_emt1.0', 'pc_win2000_32b_emt1.0', - 'powerpc_darwin7.7.0_32b_emt1.0', - 'alpha_osf1v5.1_64b_emt1.0', - 'sparc_sunos5.8_64b_emt1.0']. - -init_per_testcase(Case, Config) when is_list(Config) -> - case maybe_skip(Config) of - {skip, _}=Skip -> - Skip; - ok -> - %% Until emem is completely stable we run these tests in a working - %% directory with an ignore_core_files file which will make the - %% search for core files ignore cores generated by this suite. - ignore_cores:setup(?MODULE, Case, [{testcase, Case}|Config]) - end. - -end_per_testcase(_Case, Config) when is_list(Config) -> - ignore_cores:restore(Config), - ok. - -maybe_skip(Config) -> - DataDir = proplists:get_value(data_dir, Config), - case filelib:is_dir(DataDir) of - false -> - {skip, "No data directory"}; - true -> - case proplists:get_value(emem, Config) of - undefined -> - {skip, "emem not found"}; - _ -> - ok - end - end. - -init_per_suite(Config) when is_list(Config) -> - BinDir = filename:join([code:lib_dir(tools), "bin"]), - Target = erlang:system_info(system_architecture), - Res = (catch begin - case check_dir(filename:join([BinDir, Target])) of - not_found -> ok; - TDir -> - check_emem(TDir, debug), - check_emem(TDir, opt) - end, - check_emem(BinDir, opt), - "" - end), - Res ++ ignore_cores:init(Config). - -end_per_suite(Config) when is_list(Config) -> - Config1 = lists:keydelete(emem, 1, Config), - Config2 = lists:keydelete(emem_comment, 1, Config1), - ignore_cores:fini(Config2). - -%% -%% -%% Test cases -%% -%% - -live_node(Config) when is_list(Config) -> - {ok, EmuFlag, Port} = start_emem(Config), - Nodename = mk_nodename(Config), - {ok, Node} = start_node(Nodename, EmuFlag), - NP = spawn(Node, - fun () -> - receive go -> ok end, - I = spawn(fun () -> ignorer end), - GC = fun () -> - GCP = fun (P) -> - garbage_collect(P) - end, - lists:foreach(GCP, processes()) - end, - Seq = fun () -> I ! lists:seq(1, 1000000) end, - spawn_link(Seq), - B1 = <<0:10000000>>, - spawn_link(Seq), - B2 = <<0:10000000>>, - spawn_link(Seq), - B3 = <<0:10000000>>, - I ! {B1, B2, B3}, - GC(), - GC(), - GC() - end), - MRef = erlang:monitor(process, NP), - NP ! go, - receive - {'DOWN', MRef, process, NP, Reason} -> - spawn(Node, fun () -> halt(17) end), - normal = Reason - end, - Res = get_emem_result(Port), - {ok, Hostname} = inet:gethostname(), - ShortHostname = short_hostname(Hostname), - {true, _} = has_prefix(Nodename, Res#emem_res.nodename), - ShortHostname = short_hostname(Res#emem_res.hostname), - Bits = case erlang:system_info(wordsize) of - 4 -> "32 bits"; - 8 -> "64 bits" - end, - Bits = Res#emem_res.word_size, - "17" = Res#emem_res.exit_code, - emem_comment(Config). - -'sparc_sunos5.8_32b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "gorbag" = Res#emem_res.hostname, - "17074" = Res#emem_res.pid, - "2005-01-14 17:28:37.881980" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["15", "2665739", "8992", "548986", "16131", "539994", - "4334192", "1", "99", "15", "98", - "0", "0", "49", "0", "49"] = Res#emem_res.last_values, - ["5972061", "9662", "7987824", "5", - "2375680", "3"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - -'pc_win2000_32b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "E-788FCF5191B54" = Res#emem_res.hostname, - "504" = Res#emem_res.pid, - "2005-01-24 17:27:28.224000" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["11", "2932575", "8615", "641087", "68924", "632472"] - = Res#emem_res.last_values, - ["5434206", "9285"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - -'pc.smp_linux2.2.19pre17_32b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "four-roses" = Res#emem_res.hostname, - "20689" = Res#emem_res.pid, - "2005-01-20 13:11:26.143077" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["49", "2901817", "9011", "521610", "10875", "512599", - "5392096", "2", "120", "10", "118", - "0", "0", "59", "0", "59"] = Res#emem_res.last_values, - ["6182918", "9681", - "9062112", "6", - "2322432", "3"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - - -'powerpc_darwin7.7.0_32b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "grima" = Res#emem_res.hostname, - "13021" = Res#emem_res.pid, - "2005-01-20 15:08:17.568668" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["9", "2784323", "8641", "531105", "15893", "522464"] - = Res#emem_res.last_values, - ["6150376", "9311"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - -'alpha_osf1v5.1_64b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "thorin" = Res#emem_res.hostname, - "224630" = Res#emem_res.pid, - "2005-01-20 22:38:01.299632" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "64 bits" = Res#emem_res.word_size, - case Res#emem_res.max_word_size of - "32 bits" -> - emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ["22", - "6591992", "8625", "516785", "14805", "508160", - "11429184", "5", "127", "254", "122", - "0", "0", "61", "0", "61"] = Res#emem_res.last_values, - ["7041775", "9295", - "11593024", "7", - "2097152", "3"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config) - end. - -'sparc_sunos5.8_64b_emt2.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "test_server" = Res#emem_res.nodename, - "gorbag" = Res#emem_res.hostname, - "10907" = Res#emem_res.pid, - "2005-01-20 13:48:34.677068" = Res#emem_res.start_time, - "2.0" = Res#emem_res.trace_version, - "64 bits" = Res#emem_res.word_size, - case Res#emem_res.max_word_size of - "32 bits" -> - emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ["16", - "5032887", "8657", "530635", "14316", "521978", - "8627140", "5", "139", "19", "134", - "0", "0", "67", "0", "67"] = Res#emem_res.last_values, - ["11695070", "9324", - "16360388", "10", - "4136960", "3"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config) - end. - -'sparc_sunos5.8_32b_emt1.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "" = Res#emem_res.nodename, - "" = Res#emem_res.hostname, - "" = Res#emem_res.pid, - "" = Res#emem_res.start_time, - "1.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["11", "2558261", "8643", "560610", "15325", "551967"] - = Res#emem_res.last_values, - ["2791121", "9317"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - -'pc_win2000_32b_emt1.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "" = Res#emem_res.nodename, - "" = Res#emem_res.hostname, - "" = Res#emem_res.pid, - "" = Res#emem_res.start_time, - "1.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["6", "2965248", "8614", "640897", "68903", "632283"] - = Res#emem_res.last_values, - ["3147090", "9283"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - - -'powerpc_darwin7.7.0_32b_emt1.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "" = Res#emem_res.nodename, - "" = Res#emem_res.hostname, - "" = Res#emem_res.pid, - "" = Res#emem_res.start_time, - "1.0" = Res#emem_res.trace_version, - "32 bits" = Res#emem_res.word_size, - ["8", "2852991", "8608", "529662", "15875", "521054"] - = Res#emem_res.last_values, - ["3173335", "9278"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config). - -'alpha_osf1v5.1_64b_emt1.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "" = Res#emem_res.nodename, - "" = Res#emem_res.hostname, - "" = Res#emem_res.pid, - "" = Res#emem_res.start_time, - "1.0" = Res#emem_res.trace_version, - "64 bits" = Res#emem_res.word_size, - case Res#emem_res.max_word_size of - "32 bits" -> - emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ["22", - "6820094", "8612", "515518", "14812", "506906"] - = Res#emem_res.last_values, - ["7292413", "9282"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config) - end. - -'sparc_sunos5.8_64b_emt1.0'(Config) when is_list(Config) -> - Res = run_emem_on_casefile(Config), - "" = Res#emem_res.nodename, - "" = Res#emem_res.hostname, - "" = Res#emem_res.pid, - "" = Res#emem_res.start_time, - "1.0" = Res#emem_res.trace_version, - "64 bits" = Res#emem_res.word_size, - case Res#emem_res.max_word_size of - "32 bits" -> - emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ["15", - "4965746", "8234", "543940", "14443", "535706"] - = Res#emem_res.last_values, - ["11697645", "8908"] = Res#emem_res.maximum, - "0" = Res#emem_res.exit_code, - emem_comment(Config) - end. - -%% -%% -%% Auxiliary functions -%% -%% - -receive_and_save_trace(PortNumber, FileName) when is_integer(PortNumber), - is_list(FileName) -> - {ok, F} = file:open(FileName, [write, compressed]), - {ok, LS} = gen_tcp:listen(PortNumber, [inet, {reuseaddr,true}, binary]), - {ok, S} = gen_tcp:accept(LS), - gen_tcp:close(LS), - receive_loop(S,F). - -receive_loop(Socket, File) -> - receive - {tcp, Socket, Data} -> - ok = file:write(File, Data), - receive_loop(Socket, File); - {tcp_closed, Socket} -> - file:close(File), - ok; - {tcp_error, Socket, Reason} -> - file:close(File), - {error, Reason} - end. - -send_trace({Host, PortNumber}, FileName) when is_list(Host), - is_integer(PortNumber), - is_list(FileName) -> - {ok, F} = file:open(FileName, [read, compressed]), - {ok, S} = gen_tcp:connect(Host, PortNumber, [inet,{packet, 0}]), - send_loop(S, F); -send_trace(EmuFlag, FileName) when is_list(EmuFlag), - is_list(FileName) -> - ["+Mit", IpAddrStr, PortNoStr] = string:tokens(EmuFlag, " :"), - send_trace({IpAddrStr, list_to_integer(PortNoStr)}, FileName). - -send_loop(Socket, File) -> - case file:read(File, 128) of - {ok, Data} -> - case gen_tcp:send(Socket, Data) of - ok -> send_loop(Socket, File); - Error -> - gen_tcp:close(Socket), - file:close(File), - Error - end; - eof -> - gen_tcp:close(Socket), - file:close(File), - ok; - Error -> - gen_tcp:close(Socket), - file:close(File), - Error - end. - -check_emem(Dir, Type) when is_atom(Type) -> - ExeSuffix = case os:type() of - {win32, _} -> ".exe"; - _ -> "" - end, - TypeSuffix = case Type of - opt -> ""; - _ -> "." ++ atom_to_list(Type) - end, - Emem = "emem" ++ TypeSuffix ++ ExeSuffix, - case check_file(filename:join([Dir, Emem])) of - not_found -> ok; - File -> - Comment = case Type of - opt -> ""; - _ -> "[emem " ++ atom_to_list(Type) ++ " compiled]" - end, - throw([{emem, File}, {emem_comment, Comment}]) - end. - -check_dir(DirName) -> - case file:read_file_info(DirName) of - {ok, #file_info {type = directory, access = A}} when A == read; - A == read_write -> - DirName; - _ -> - not_found - end. - -check_file(FileName) -> - case file:read_file_info(FileName) of - {ok, #file_info {type = regular, access = A}} when A == read; - A == read_write -> - FileName; - _ -> - not_found - end. - -emem_comment(Config) when is_list(Config) -> - emem_comment(Config, ""). - -emem_comment(Config, ExtraComment) - when is_list(Config), is_list(ExtraComment) -> - case {proplists:get_value(emem_comment, Config), ExtraComment} of - {"", ""} -> ok; - {"", XC} -> {comment, XC}; - {EmemC, ""} -> {comment, EmemC}; - {EmemC, XC} -> {comment, EmemC ++ " " ++ XC} - end. - -run_emem_on_casefile(Config) -> - CaseName = atom_to_list(proplists:get_value(testcase, Config)), - File = filename:join([proplists:get_value(data_dir, Config), CaseName ++ ".gz"]), - case check_file(File) of - not_found -> - ct:fail({error, {filenotfound, File}}); - _ -> - ok - end, - {ok, EmuFlag, Port} = start_emem(Config), - Parent = self(), - Ref = make_ref(), - spawn_link(fun () -> - SRes = send_trace(EmuFlag, File), - Parent ! {Ref, SRes} - end), - Res = get_emem_result(Port), - receive - {Ref, ok} -> - ok; - {Ref, SendError} -> - io:format("Send result: ~p~n", [SendError]) - end, - Res. - -get_emem_result(Port) -> - {Res, LV} = get_emem_result(Port, {#emem_res{}, []}), - Res#emem_res{last_values = string:tokens(LV, " ")}. - -get_emem_result(Port, {_EmemRes, _LastValues} = Res) -> - case get_emem_line(Port) of - eof -> - Res; - Line -> - get_emem_result(Port, parse_emem_line(Line, Res)) - end. - -parse_emem_main_header_footer_line(Line, {ER, LV} = Res) -> - - %% Header - case has_prefix("> Nodename:", Line) of - {true, NN} -> - throw({ER#emem_res{nodename = strip(NN)}, LV}); - false -> ok - end, - case has_prefix("> Hostname:", Line) of - {true, HN} -> - throw({ER#emem_res{hostname = strip(HN)}, LV}); - false -> ok - end, - case has_prefix("> Pid:", Line) of - {true, P} -> - throw({ER#emem_res{pid = strip(P)}, LV}); - false -> ok - end, - case has_prefix("> Start time (UTC):", Line) of - {true, ST} -> - throw({ER#emem_res{start_time = strip(ST)}, LV}); - false -> ok - end, - case has_prefix("> Actual trace version:", Line) of - {true, TV} -> - throw({ER#emem_res{trace_version = strip(TV)}, LV}); - false -> ok - end, - case has_prefix("> Maximum trace word size:", Line) of - {true, MWS} -> - throw({ER#emem_res{max_word_size = strip(MWS)}, LV}); - false -> ok - end, - case has_prefix("> Actual trace word size:", Line) of - {true, WS} -> - throw({ER#emem_res{word_size = strip(WS)}, LV}); - false -> ok - end, - - %% Footer - case has_prefix("> Maximum:", Line) of - {true, M} -> - throw({ER#emem_res{maximum = string:tokens(M," ")}, LV}); - false -> ok - end, - case has_prefix("> Emulator exited with code:", Line) of - {true, EC} -> - throw({ER#emem_res{exit_code = strip(EC)}, LV}); - false -> ok - end, - Res. - -parse_emem_header_line(_Line, {_ER, _LV} = Res) -> - Res. - -parse_emem_value_line(Line, {EmemRes, _OldLastValues}) -> - {EmemRes, Line}. - -parse_emem_line("", Res) -> - Res; -parse_emem_line(Line, Res) -> - [Prefix | _] = Line, - case Prefix of - $> -> catch parse_emem_main_header_footer_line(Line, Res); - $| -> catch parse_emem_header_line(Line, Res); - _ -> catch parse_emem_value_line(Line, Res) - end. - -start_emem(Config) when is_list(Config) -> - Emem = proplists:get_value(emem, Config), - Cd = case ignore_cores:dir(Config) of - false -> []; - Dir -> [{cd, Dir}] - end, - case open_port({spawn, Emem ++ " -t -n -o -i 1"}, - Cd ++ [{line, 1024}, eof]) of - Port when is_port(Port) -> {ok, read_emu_flag(Port), Port}; - Error -> ct:fail(Error) - end. - -read_emu_flag(Port) -> - Line = case get_emem_line(Port) of - eof -> ct:fail(unexpected_end_of_file); - L -> L - end, - case has_prefix("> Emulator command line argument:", Line) of - {true, EmuFlag} -> EmuFlag; - false -> read_emu_flag(Port) - end. - -get_emem_line(Port, Acc) -> - receive - {Port, {data, {eol, Data}}} -> - Res = case Acc of - [] -> Data; - _ -> lists:flatten([Acc|Data]) - end, - io:format("~s", [Res]), - Res; - {Port, {data, {noeol, Data}}} -> - get_emem_line(Port, [Acc|Data]); - {Port, eof} -> - port_close(Port), - eof - end. - -get_emem_line(Port) -> - get_emem_line(Port, []). - -short_hostname([]) -> - []; -short_hostname([$.|_]) -> - []; -short_hostname([C|Cs]) -> - [C | short_hostname(Cs)]. - -has_prefix([], List) when is_list(List) -> - {true, List}; -has_prefix([P|Xs], [P|Ys]) -> - has_prefix(Xs, Ys); -has_prefix(_, _) -> - false. - -strip(Str) -> string:strip(Str). - -mk_nodename(Config) -> - Us = erlang:monotonic_time(), - atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) - ++ integer_to_list(Us). - -start_node(Name, Args) -> - Pa = filename:dirname(code:which(?MODULE)), - test_server:start_node(Name, peer, [{args, Args ++ " -pa " ++ Pa}]). diff --git a/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl b/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl index 4e0c4d311896..89eb81f7cf44 100644 --- a/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl +++ b/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl @@ -22,10 +22,10 @@ %%% This module implements a priority queue as defined in %%% "Priority Queues and the STL" by Mark Nelson in Dr.Dobb's Journal, Jan 1996 %%% see http://web2.airmail.net/markn/articles/pq_stl/priority.htm for more -%%% information. (A heap implementation is planned aswell) +%%% information. (A heap implementation is planned as well) %%%---------------------------------------------------------------------- %%% The items of the queue is kept priority sorted, and because of that, -%%% a push() operation costs more than a pop() operation (wich only +%%% a push() operation costs more than a pop() operation (which only %%% needs to return the top item of the queue(read: list)). %%%---------------------------------------------------------------------- %%% The priority queue can be deceptively nice to use when creating for diff --git a/lib/tools/test/make_SUITE.erl b/lib/tools/test/make_SUITE.erl index 02da4f4ace66..8d8e5d7559af 100644 --- a/lib/tools/test/make_SUITE.erl +++ b/lib/tools/test/make_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2021. 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. @@ -58,16 +58,6 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_,Config) -> Config. -end_per_testcase(netload,_Config) -> - %% Stop slave - in case of failure - Nodes = nodes(), - case [N || N <- Nodes, - "make_SUITE_netload" == hd(string:lexemes(atom_to_list(N),"@"))] of - [Node] -> - ct_slave:stop(Node); - _ -> - ok - end; end_per_testcase(_,_Config) -> ok. @@ -114,12 +104,12 @@ netload(Config) -> code:purge(test1), code:delete(test1), false = code:is_loaded(test1), - {ok,Node} = ct_slave:start(make_SUITE_netload), + {ok,Peer,Node} = ?CT_PEER(), up_to_date = make:files([test1], [netload]), timer:sleep(1000), % async, so give some time {file,F} = code:is_loaded(test1), {file,F} = rpc:call(Node,code,is_loaded,[test1]), - ct_slave:stop(Node), + peer:stop(Peer), file:set_cwd(Current), ensure_no_messages(), ok. diff --git a/lib/tools/test/prof_bench_SUITE.erl b/lib/tools/test/prof_bench_SUITE.erl index 28473872bdd0..798f2b7dabdb 100644 --- a/lib/tools/test/prof_bench_SUITE.erl +++ b/lib/tools/test/prof_bench_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2021. All Rights Reserved. +%% Copyright Ericsson AB 2001-2022. 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. @@ -32,18 +32,28 @@ suite() -> - [{timetrap,{minutes,15}}]. + [{timetrap,{minutes,30}}]. all() -> [overhead]. init_per_suite(Config) -> - case {whereis(cover_server) =/= undefined, - erlang:system_info(wordsize)} - of - {true, _} -> {skip, "Cover is running"}; - {_, 4} -> {skip, "Can't run on 32-bit as files will be large"}; - {false, 8} -> Config + case whereis(cover_server) of + undefined -> + application:ensure_all_started(os_mon), + Free = disk_free(proplists:get_value(priv_dir, Config)), + if + Free >= 16_000_000 -> + %% The size of the log files is about 4 Gb. + %% The disk has at least 4 times that amount free. + Config; + true -> + %% There might not be sufficient disk space free. + io:format("Free disk space: ~p Kb\n", [Free]), + {skip, "Insufficient free disk space"} + end; + Pid when is_pid(Pid) -> + {skip, "Cover is running"} end. end_per_suite(Config) -> @@ -51,6 +61,23 @@ end_per_suite(Config) -> file:delete(LogFile), ok. +%% Return amount disk space free in Kbs for the disk that Path +%% is located on. +disk_free(Path) -> + Data = disksup:get_disk_data(), + + %% What partitions could Data be mounted on? + Partitions = + [D || {P, _Tot, _Perc}=D <- Data, + lists:prefix(filename:nativename(P), filename:nativename(Path))], + + %% Sorting in descending order places the partition with the most specific + %% path first. + case lists:sort(fun erlang:'>='/2, Partitions) of + [{_,Tot, Perc} | _] -> round(Tot * (1-(Perc/100))); + [] -> error + end. + %%%--------------------------------------------------------------------- %% ct:run_test([{suite, prof_bench_SUITE}]). @@ -83,20 +110,6 @@ overhead(Config) -> data = [{name, cover_overhead}, {value, NormTime / CoverTime * 100}]}). -%% overhead(Config) -> -%% LogFile = filename:join(proplists:get_value(priv_dir, Config), "fprof.trace"), -%% SofsCopy = filename:join(proplists:get_value(data_dir, Config), "sofs_copy.erl"), -%% TC = fun() -> compile:file(SofsCopy, [binary]) end, -%% _Warmup = timer:tc(TC), - -%% [{ok,{EProfTime,{ok,sofs_copy,_}}} = eprof:profile([], timer, tc, [TC]) -%% || _ <- lists:seq(1,10)], -%% %% [fprof:apply(timer, tc, [TC], [{file, LogFile}]) || _ <- lists:seq(1,10)], -%% {FProfTime,{ok,sofs_copy,_}} = fprof:apply(timer, tc, [TC], [{file, LogFile}]), -%% {NormTime,{ok, sofs_copy, _}} = timer:tc(TC), - - %% ct:pal("FProf: ~p Norm: ~p Ratio: ~p",[FProfTime, NormTime, FProfTime / NormTime]). - cprof_apply(M, F, A) -> cprof:start(), Res = apply(M, F, A), diff --git a/lib/tools/test/tools.spec.win b/lib/tools/test/tools.spec.win index b43d542ff1ed..93d5930472e2 100644 --- a/lib/tools/test/tools.spec.win +++ b/lib/tools/test/tools.spec.win @@ -1,2 +1 @@ {topcase, {dir, "../tools_test"}}. -{skip, {emem_SUITE, "Not on windows, yet. FIXME!!!"}}. diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl index 75ad7a6ff1a1..3824b54b5243 100644 --- a/lib/tools/test/xref_SUITE.erl +++ b/lib/tools/test/xref_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2021. All Rights Reserved. +%% Copyright Ericsson AB 2000-2022. 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. @@ -1679,7 +1679,7 @@ fun_mfa(Conf) when is_list(Conf) -> ok = file:delete(Beam), ok. -%% fun M:F/A with varibles. +%% fun M:F/A with variables. fun_mfa_vars(Conf) when is_list(Conf) -> Dir = ?copydir, File = fname(Dir, "fun_mfa_vars.erl"), diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 4d10ec0d2a26..cfff79e80d44 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 3.5.2 +TOOLS_VSN = 3.6 diff --git a/lib/wx/.gitignore b/lib/wx/.gitignore index 09564b499e3a..aa95f9ad4c4f 100644 --- a/lib/wx/.gitignore +++ b/lib/wx/.gitignore @@ -3,6 +3,7 @@ wx_test_case_info doc/html/* api_gen/wx_doxygen.log* api_gen/wx_*_api.dump +priv/WebView2Loader.dll %% Don't delete links to man src when git clean -dfX %% api_gen/gl_man? diff --git a/lib/wx/Makefile b/lib/wx/Makefile index c73baa9f6e5f..b77a7808c5ad 100644 --- a/lib/wx/Makefile +++ b/lib/wx/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -19,18 +19,17 @@ # include ./vsn.mk +include ./config.mk -ifdef TERTIARY_BOOTSTRAP - INSIDE_ERLSRC = true +ifdef BOOTSTRAP SUBDIRS = src else # Normal build - include ./config.mk SUBDIRS = src ifeq ($(CAN_BUILD_DRIVER), true) SUBDIRS += c_src endif SUBDIRS += examples doc/src -endif #TERTIARY_BOOTSTRAP +endif #BOOTSTRAP CLEANDIRS = $(SUBDIRS) api_gen @@ -41,4 +40,6 @@ SUB_DIRECTORIES=$(SUBDIRS) include $(ERL_TOP)/make/otp_subdir.mk +TEST_NEEDS_RELEASE=true + include $(ERL_TOP)/make/app_targets.mk diff --git a/lib/wx/api_gen/README b/lib/wx/api_gen/README index 394469030c02..364dbdd9f254 100644 --- a/lib/wx/api_gen/README +++ b/lib/wx/api_gen/README @@ -15,7 +15,7 @@ CONFIGURATION: Adding/changing stuff/classes should be done by updating wxapi.conf and running make. Sometimes the code generator will require changes, - I havn't thought of everything yet. + I haven't thought of everything yet. RUNNING: I use the following alias wxgen='make GL_DIR=/home/dgud/opengl WX_DIR=/home/dgud/src/wxWidgets' diff --git a/lib/wx/api_gen/apidiff.escript b/lib/wx/api_gen/apidiff.escript index 952c5453de78..61328e6e3e78 100644 --- a/lib/wx/api_gen/apidiff.escript +++ b/lib/wx/api_gen/apidiff.escript @@ -207,7 +207,7 @@ write([{#f{c=wxShowEvent,f=getShow},_}|Rest], P, K) -> write([{#f{c=wxSingleChoiceDialog,f=singleChoiceDialog, a=[]},_}|Rest], P, K) -> write(Rest, P, K+1); write([{#f{c=wxSizer,f=recalcSizes},_}|Rest], P, K) -> - io:format("Removed wxSizer:recalcSizer() was an wxWidgets internal function now deprected~n", []), + io:format("Removed wxSizer:recalcSizer() was an wxWidgets internal function now deprecated~n", []), write(Rest, P, K+1); write([{#f{c=wxSizerItem,f=setWindow},_}|Rest], P, K) -> io:format("Removed depr wxSizerItem:setWindow() use assignWindow~n", []), diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl index 7a609158c7d1..eef715b83ad1 100644 --- a/lib/wx/api_gen/gl_gen.erl +++ b/lib/wx/api_gen/gl_gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -358,7 +358,10 @@ handle_arg_opt({c_only,Opt},P) -> P#arg{where=c, alt=Opt}; handle_arg_opt(list_binary, P) -> P#arg{alt=list_binary}; handle_arg_opt(string, P=#arg{type=T}) -> P#arg{type=T#type{base=string}}; handle_arg_opt({string,Max,Sz}, P=#arg{type=T}) -> - P#arg{type=T#type{base=string, size={Max,Sz}}}. + P#arg{type=T#type{base=string, size={Max,Sz}}}; +handle_arg_opt({size, Sz}, P=#arg{type=T}) -> + P#arg{type=T#type{size={Sz,Sz}}}. + parse_type([], _Os) -> void; parse_type(C, Os) -> diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl index fa5ce4a91f2e..06fc6c9e5886 100644 --- a/lib/wx/api_gen/gl_gen_erl.erl +++ b/lib/wx/api_gen/gl_gen_erl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -88,7 +88,8 @@ gl_api(Fs, _GluNifs) -> w("-on_load(init_nif/0).~n",[]), w("~n-export([~s]).~n~n", [args(fun(EF) -> EF end, ",", ExportList, 60)]), - w("-export([get_interface/0, rec/1, lookup_func/0]).\n",[]), + w("-export([get_interface/0, rec/1, lookup_func/1]).\n",[]), + w("-nifs([lookup_func_nif/1]).\n",[]), w("-define(nif_stub,nif_stub_error(?LINE)).~n", []), w("%% @hidden~n", []), w("nif_stub_error(Line) ->~n" @@ -117,7 +118,9 @@ gl_api(Fs, _GluNifs) -> w(" error_logger:error_report([{gl, error}, {message, lists:flatten(Err)}]),~n", []), w(" rec(Op)~n", []), w(" end.~n~n", []), - w("lookup_func() -> ?nif_stub.\n\n",[]), + w("lookup_func(functions) -> lookup_func_nif(1);\n",[]), + w("lookup_func(function_names) -> lookup_func_nif(2).\n\n",[]), + w("lookup_func_nif(_Func) -> ?nif_stub.\n\n",[]), w("~n", []), w("~n", []), @@ -149,7 +152,7 @@ glu_api(Fs) -> w("%% @doc General purpose polygon triangulation.~n",[]), w("%% The first argument is the normal and the second a list of~n" - "%% vertex positions. Returned is a list of indecies of the vertices~n" + "%% vertex positions. Returned is a list of indices of the vertices~n" "%% and a binary (64bit native float) containing an array of~n" "%% vertex positions, it starts with the vertices in Vs and~n" "%% may contain newly created vertices in the end.~n", []), @@ -379,6 +382,8 @@ spec_arg_type2(T=#type{single={list, _Max}}) -> "[" ++ spec_arg_type3(T) ++ "]"; spec_arg_type2(T=#type{single={list,_,_}}) -> "[" ++ spec_arg_type3(T) ++ "]"; +spec_arg_type2(T=#type{single={list,_,_,_}}) -> + "[" ++ spec_arg_type3(T) ++ "]"; spec_arg_type2(T=#type{single={tuple_list,Sz}}) -> "[{" ++ args(fun spec_arg_type3/1, ",", lists:duplicate(Sz,T)) ++ "}]". diff --git a/lib/wx/api_gen/gl_gen_nif.erl b/lib/wx/api_gen/gl_gen_nif.erl index cd8fdba7cdd3..a84bf454a545 100644 --- a/lib/wx/api_gen/gl_gen_nif.erl +++ b/lib/wx/api_gen/gl_gen_nif.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -422,8 +422,8 @@ decode_var(P=#arg{name=Name, in=true, alt=Alt, decode_var(P=#arg{name=Name, in=false, - type=#type{name=T, base=Base, size=Szs}}, Argc) - when Base =:= binary; Base =:= string -> + type=#type{name=T, base=Base, size=Szs, single=Single}}, Argc) + when not is_tuple(Single), (Base =:= binary orelse Base =:= string) -> Sz = case Szs of {Max,_} when is_integer(Max) -> integer_to_list(Max); {Max,_} -> Max; @@ -454,6 +454,19 @@ decode_var(P=#arg{name=Name, in=false, type=#type{name=T,single={list,Sz,_}}}, A w(" std::vector <~s> ~s (~s);\n", [T, Name, Sz]), w(" std::vector ~s_ts (~s);\n", [Name, Sz]), {P,Argc}; +decode_var(P=#arg{name=Name, in=false, + type=#type{base=Base, name=T,single={list,Sz,_,_}, size=Size}}, Argc) -> + case Base of + string -> + {BinSize, _} = Size, + w(" ~s = (unsigned char *) enif_alloc((int) ~s*sizeof(~s));\n", [Name,BinSize,T]), + w(" unsigned char *~s_ptr = ~s;\n", [Name,Name]), + store_free(Name ++ "_ptr"); + _ -> + exit({?LINE, Base, P}) + end, + w(" std::vector ~s_ts (~s);\n", [Name, Sz]), + {P,Argc}; decode_var(P=#arg{name=Name, in=true, type=#type{name="GLUquadric"}}, Argc) -> w(" if(!egl_get_ptr(env, argv[~w], (void **) &~s)) Badarg(~w,\"~s\");~n", [Argc, Name,?OP,Name]), @@ -576,10 +589,6 @@ build_ret(Name,_Q,#type{name=T,base=Base,size=Sz,single=true}) Ptr -> io_lib:format(" enif_make_uint64(env, (egl_uint64_t) ~s)", [Name]); true -> io_lib:format(" enif_make_int64(env, (egl_int64_t) ~s)", [Name]) end; -build_ret(Name,_Q,#type{base=string,single=true}) -> - io_lib:format(" enif_make_string(env, (const char *) ~s, ERL_NIF_LATIN1)",[Name]); -build_ret(Name,_Q,#type{base=string,size={_,_OutSz}}) -> - io_lib:format(" enif_make_string(env, (const char *) ~s, ERL_NIF_LATIN1)",[Name]); build_ret(Name,_Q,#type{name=_T,base=float,size=Sz,single=true}) -> if Sz =< 4 -> io_lib:format(" enif_make_double(env, (double) ~s)", [Name]); true -> io_lib:format(" enif_make_double(env, ~s)", [Name]) @@ -602,6 +611,12 @@ build_ret(Name,false,#type{single={list,Sz}}) when Sz >= 10, is_integer(Sz) -> io_lib:format(" enif_make_list_from_array(env, ~s_ts, ~w)",[Name, Sz]); build_ret(Name,false,#type{single={list,_,Sz}}) -> io_lib:format(" enif_make_list_from_array(env, ~s_ts.data(), ~s)",[Name, Sz]); +build_ret(Name,false,#type{single={list,_,Sz,_}}) -> + io_lib:format(" enif_make_list_from_array(env, ~s_ts.data(), ~s)",[Name, Sz]); +build_ret(Name,_Q,#type{base=string,single=true}) -> + io_lib:format(" enif_make_string(env, (const char *) ~s, ERL_NIF_LATIN1)",[Name]); +build_ret(Name,_Q,#type{base=string,size={_,_OutSz}}) -> + io_lib:format(" enif_make_string(env, (const char *) ~s, ERL_NIF_LATIN1)",[Name]); build_ret(Name,_Q,T=#type{}) -> io:format("{~p, {~p, {single,{tuple,X}}}}.~n", [get(current_func),Name]), io:format(" ~p~n",[T]). @@ -615,6 +630,12 @@ prepare_ret(#arg{name=Name, type=#type{single={list,_,Sz}}=T}) -> Fetch = build_ret(Name ++ "[ri]", false, T#type{single=true}), w(" for(int ri=0; ri < (int) ~s; ri++)\n" " ~s_ts[ri] = ~s;\n",[Sz, Name, Fetch]); +prepare_ret(#arg{name=Name, type=#type{single={list,_,Sz,Lengths}}=T}) -> + Fetch = build_ret(Name, false, T#type{single=true}), + w(" for(int ri=0; ri < (int) ~s; ri++) {\n" + " ~s_ts[ri] = ~s;\n",[Sz, Name, Fetch]), + w(" ~s += ~s[ri];\n" + " }\n", [Name, Lengths]); prepare_ret(_) -> ok. diff --git a/lib/wx/api_gen/glapi.conf b/lib/wx/api_gen/glapi.conf index e8304c31fe90..b7b8ede1b7df 100644 --- a/lib/wx/api_gen/glapi.conf +++ b/lib/wx/api_gen/glapi.conf @@ -483,24 +483,16 @@ {"glDebugMessageControl", [{"count", {c_only, {length, "ids"}}}, {"ids", {single, list}}]}. -{"glDebugMessageInsertARB", {"length", {c_only, {size, "buf"}}}}. - -{"glGetDebugMessageLogARB", [{"sources", {single, {list, "count", "result"}}}, - {"types", {single, {list, "count", "result"}}}, - {"ids", {single, {list, "count", "result"}}}, - {"severities", {single, {list, "count", "result"}}}, - {"lengths", [{c_only, undefined}, {single, {list, "count", "result"}}]}, - {"messageLog", [{string, "bufSize", "result"} - %%,{single, {list, "bufsize", "result"}} - ]}]}. +{"glDebugMessageInsert", {"length", {c_only, {size, "buf"}}}}. {"glGetDebugMessageLog", [{"sources", {single, {list, "count", "result"}}}, {"types", {single, {list, "count", "result"}}}, {"ids", {single, {list, "count", "result"}}}, {"severities", {single, {list, "count", "result"}}}, {"lengths", [{c_only, undefined}, {single, {list, "count", "result"}}]}, - {"messageLog", [{string, "bufSize", "result"} - %%,{single, {list, "bufsize", "result"}} + {"messageLog", [ + {single, {list, "count", "result", "lengths"}}, + {size, "bufSize"} ]}]}. diff --git a/lib/wx/api_gen/wx_doxygen.conf b/lib/wx/api_gen/wx_doxygen.conf index b50e1b8af344..74041c819a4e 100644 --- a/lib/wx/api_gen/wx_doxygen.conf +++ b/lib/wx/api_gen/wx_doxygen.conf @@ -80,7 +80,7 @@ ALIASES += beginFlagTable="
    " ALIASES += flag{1}="
    \li \1:
    " ALIASES += endFlagTable="
    \n" -# apperance +# appearance ALIASES += appearance{1}="\htmlonly \1 \endhtmlonly" ALIASES += genericAppearance{1}="\htmlonly \1 \endhtmlonly" diff --git a/lib/wx/api_gen/wx_extra/added_func.h b/lib/wx/api_gen/wx_extra/added_func.h index 654cc8b43007..bf18a16c6c10 100644 --- a/lib/wx/api_gen/wx_extra/added_func.h +++ b/lib/wx/api_gen/wx_extra/added_func.h @@ -28,7 +28,7 @@ class WXDLLIMPEXP_ADV wxTreeCtrlBase : public wxControl static bool IsTreeItemIdOk(wxTreeItemId id); }; -// The generater needs constructors (is this still valid?) +// The generator needs constructors (is this still valid?) class WXDLLIMPEXP_ADV wxGridCellBoolRenderer : public wxGridCellRenderer { public: @@ -49,7 +49,7 @@ class wxMenuBar { static bool GetAutoWindowMenu() { return s_macAutoWindowMenu ; } }; -// Deprectated functions in 3.1 +// Deprecated functions in 3.1 class wxWindow { public: @@ -95,3 +95,9 @@ class wxAuiNotebookEvent : public wxBookCtrlEvent { void SetDragSource(wxAuiNotebook* s) { m_dragSource = s; } wxAuiNotebook* GetDragSource() const { return m_dragSource; } }; + +class wxGLCanvas : public wxWindow +{ +public: + bool CreateSurface(); +}; diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl index 8d0d97e8f023..628e22aa9e14 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl @@ -13,10 +13,10 @@ %% (in another process) to handle the event. The callback should be of %% arity 2. fun(EventRecord::wx(), EventObject::wxObject()). %% -%% Beware that the callback will be in executed in new process each time. +%% Beware that the callback will be executed in a new process each time. %% %%
    -%% The orginal documentation. +%% The original documentation. %% %% -module(wxEvtHandler). @@ -51,8 +51,9 @@ connect(This, EventType) -> %% {skip, boolean()}, If skip is true further event_handlers will be called. %% This is not used if the 'callback' option is used. %% Default false. +%% callback Use `wx_object' callback `handle_sync_event/3'. %% {callback, function()} Use a callback fun(EventRecord::wx(), EventObject::wxObject()) -%% to process the event. Default not specfied i.e. a message will +%% to process the event. Default not specified i.e. a message will %% be delivered to the process calling this function. %% {userData, term()} An erlang term that will be sent with the event. Default: []. -spec connect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> 'ok' when diff --git a/lib/wx/api_gen/wx_extra/wxe_evth.h b/lib/wx/api_gen/wx_extra/wxe_evth.h index 2d4d7276a84c..7b9b189381c3 100644 --- a/lib/wx/api_gen/wx_extra/wxe_evth.h +++ b/lib/wx/api_gen/wx_extra/wxe_evth.h @@ -55,7 +55,7 @@ class wxeEvtHandler : public wxObject callback: @verbatim {callback,function()} @endverbatim Use a callback @verbatim fun(EventRecord::wx(),EventObject::wxObject()) @endverbatim - to process the event. Default not specfied i.e. a message will + to process the event. Default not specified i.e. a message will be delivered to the process calling this function. userData: @verbatim {userData,term()} @endverbatim diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl index 3fabcd9e2ae3..477e09d31841 100644 --- a/lib/wx/api_gen/wx_gen.erl +++ b/lib/wx/api_gen/wx_gen.erl @@ -649,7 +649,7 @@ parse_param(#xmlElement{name=declname,content=[C]},_Opts,T) -> parse_param(#xmlElement{name=defval,content=[#xmlText{value=Def}]},_Opts,T) -> T#param{def=string:strip(Def)}; parse_param(#xmlElement{name=defval,content=Other},_Opts,T) -> - %% For defaults = (modifer wxType *) NULL + %% For defaults = (modifier wxType *) NULL Def0 = foldr(fun(#xmlText{value=V}, Acc) -> V ++ Acc; (#xmlElement{content=[#xmlText{value=V}]},Acc) -> V ++ Acc @@ -1523,7 +1523,7 @@ enum_file(File) -> parse_enums(Files) -> DontSearch = ["wxchar","filefn", "platform", "strconv", "filename", "buffer", "string", "debug", "platinfo"], - %% Arg need to patch some specials, atleast for wx-2.6 + %% Arg need to patch some specials, at least for wx-2.6 ExtraSearch = ["layout", "utils", "added__func"], io:format("~nParse Enums~n~n", []), parse_enums(Files ++ ExtraSearch,gb_sets:from_list(DontSearch)). diff --git a/lib/wx/api_gen/wx_gen.hrl b/lib/wx/api_gen/wx_gen.hrl index 252de3d0c98f..c7d1ee8022c5 100644 --- a/lib/wx/api_gen/wx_gen.hrl +++ b/lib/wx/api_gen/wx_gen.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -26,7 +26,7 @@ file = undefined, options = undefined, abstract = false, - id, % Unique integer identifer + id, % Unique integer identifier doc }). diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl index 28b357f33140..6b07689a1ed6 100644 --- a/lib/wx/api_gen/wx_gen_erl.erl +++ b/lib/wx/api_gen/wx_gen_erl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -1016,7 +1016,8 @@ gen_enums_ints() -> w("-record(wxMouseState, {x :: integer(), y :: integer(),~n" " leftDown :: boolean(), middleDown :: boolean(), rightDown :: boolean(), ~n" " controlDown :: boolean(), shiftDown :: boolean(),~n" - " altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean()~n" + " altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean(),~n" + " aux1Down :: boolean(), aux2Down :: boolean()~n" " }).~n", []), w("-record(wxHtmlLinkInfo, {~n" " href :: unicode:chardata(), target :: unicode:chardata()~n" diff --git a/lib/wx/api_gen/wx_gen_nif.erl b/lib/wx/api_gen/wx_gen_nif.erl index ab4850c6a975..e768f483feb4 100644 --- a/lib/wx/api_gen/wx_gen_nif.erl +++ b/lib/wx/api_gen/wx_gen_nif.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -1460,7 +1460,9 @@ gen_macros() -> w("#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE~n"), w("#include ~n"), w("#endif~n"), - + w("#if wxUSE_GLCANVAS_EGL && !wxCHECK_VERSION(3,2,3)~n"), + w("#include ~n"), + w("#endif~n"), w("~n~n", []), w("#ifndef wxICON_DEFAULT_BITMAP_TYPE~n",[]), diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf index 544ea869b796..be9529d40c19 100644 --- a/lib/wx/api_gen/wxapi.conf +++ b/lib/wx/api_gen/wxapi.conf @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -109,7 +109,10 @@ {'WXK_BROWSER', {test_if, "wxCHECK_VERSION(3,1,0)"}}, {'WXK_VOLUME', {test_if, "wxCHECK_VERSION(3,1,0)"}}, {'WXK_MEDIA', {test_if, "wxCHECK_VERSION(3,1,0)"}}, - {'WXK_LAUNCH', {test_if, "wxCHECK_VERSION(3,1,0)"}}, + {'WXK_LAUNCH', {test_if, "wxCHECK_VERSION(3,2,0)"}}, + + %% Varies in 3.1 and 3.2 + wxDF_MAX, {wxTOUCH, {test_if, "wxCHECK_VERSION(3,1,1)"}}, @@ -653,6 +656,8 @@ {'SetAutoWindowMenu', [{test_if, "defined(__WXMAC__)"}]}, {'GetAutoWindowMenu', [{test_if, "defined(__WXMAC__)"}]}, {'OSXGetAppleMenu', [{test_if, "defined(__WXMAC__)"}]}, + {'MacGetCommonMenuBar', [{test_if, "defined(__WXMAC__)"}]}, + {'MacSetCommonMenuBar', [{test_if, "defined(__WXMAC__)"}]}, 'IsEnabled',%'Refresh', 'Remove','Replace','SetHelpString', 'SetLabel', @@ -1437,11 +1442,23 @@ {pre_hook, [{erl, "{ok, _} = wxe_master:init_opengl(),"}]} ]}, {'SetCurrent', [{post_hook,[{c, "setActiveGL(memenv, Ecmd.caller, This, context)"}]}]}, + {'CreateSurface', [{test_if, "wxUSE_GLCANVAS_EGL"}, + {pre_hook, + [{c, %% Workaround for EGL and 3.2.* crashes + "\n#if !wxCHECK_VERSION(3,2,3)\n" + " if(!This) throw wxe_badarg(0);\n" + " if(This->GetEGLSurface() != EGL_NO_SURFACE)\n" + " eglDestroySurface(This->GetEGLDisplay(), This->GetEGLSurface());\n" + "#endif\n" + }]} + ]}, + 'IsDisplaySupported', 'SwapBuffers']}. {class, wxGLContext, object, [{ifdef, wxUSE_GLCANVAS}], [{'wxGLContext', [{"ctxAttrs", nowhere}]}, - {'SetCurrent', [{post_hook,[{c, "setActiveGL(memenv, Ecmd.caller, win, This)"}]}]} + {'SetCurrent', [{post_hook,[{c, "setActiveGL(memenv, Ecmd.caller, win, This)"}]}]}, + {'IsOK', [{test_if, "wxCHECK_VERSION(3,1,0)"}]} ]}. {class, wxAuiManager, wxEvtHandler, [{ifdef, wxUSE_AUI}], @@ -1473,7 +1490,7 @@ 'RightDockable','Row','SafeSet','SetFlag','Show','ToolbarPane', 'Top','TopDockable','Window', %% Extended func - %% These are not initilized by default and thus cause crashes + %% These are not initialized by default and thus cause crashes %% {'GetName', %% [{pre_hook, [{c, "#if 0\n"}]}, %% {post_hook, [{c, "#endif\n if(!This) throw wxe_badarg(0);\n wxString Result = This->name"}]}]}, @@ -1655,17 +1672,19 @@ %%, wxEVT_MAGNIFY % 3.1 ]}], ['AltDown','Button','ButtonDClick','ButtonDown','ButtonUp','CmdDown','ControlDown', - 'Dragging', 'Entering', 'GetButton', 'GetPosition', + 'Dragging', 'Entering', 'GetButton', 'GetPosition', 'GetLogicalPosition', 'GetLinesPerAction', 'GetWheelRotation', 'GetWheelDelta', 'GetX', 'GetY', 'IsButton', 'IsPageScroll', 'Leaving', - 'LeftDClick', 'LeftDown', 'LeftIsDown', 'LeftUp', - 'MetaDown', - 'MiddleDClick', 'MiddleDown', 'MiddleIsDown', 'MiddleUp', - 'Moving', - 'RightDClick', 'RightDown', 'RightIsDown', 'RightUp', + 'LeftDClick', 'LeftDown', 'LeftIsDown', 'LeftUp', + 'MetaDown', + 'MiddleDClick', 'MiddleDown', 'MiddleIsDown', 'MiddleUp', + 'Moving', + 'RightDClick', 'RightDown', 'RightIsDown', 'RightUp', 'ShiftDown', - 'GetWheelAxis' + 'GetWheelAxis', + 'Aux1DClick', 'Aux1Down', 'Aux1Up', + 'Aux2DClick', 'Aux2Down', 'Aux2Up' ]}. {class, wxSetCursorEvent, wxEvent, @@ -2236,7 +2255,7 @@ {class, wxTaskBarIcon, wxEvtHandler, [], [{wxTaskBarIcon, [{where, taylormade}]},'~wxTaskBarIcon', - %%'CreatePopupMenu', virtual overrided is a callback + %%'CreatePopupMenu', virtual overridden is a callback %% 'IsIconInstalled', 'IsOk', not available on mac 'PopupMenu','RemoveIcon','SetIcon']}. diff --git a/lib/wx/autoconf/config.guess b/lib/wx/autoconf/config.guess deleted file mode 100755 index 1972fda8eb05..000000000000 --- a/lib/wx/autoconf/config.guess +++ /dev/null @@ -1,1700 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright 1992-2021 Free Software Foundation, Inc. - -timestamp='2021-01-25' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). -# -# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. -# -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess -# -# Please send patches to . - - -me=$(echo "$0" | sed -e 's,.*/,,') - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright 1992-2021 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -tmp= -# shellcheck disable=SC2172 -trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 - -set_cc_for_build() { - # prevent multiple calls if $tmp is already set - test "$tmp" && return 0 - : "${TMPDIR=/tmp}" - # shellcheck disable=SC2039 - { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } - dummy=$tmp/dummy - case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in - ,,) echo "int x;" > "$dummy.c" - for driver in cc gcc c89 c99 ; do - if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$driver" - break - fi - done - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; - esac -} - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if test -f /.attbin/uname ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown -UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown -UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown -UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown - -case "$UNAME_SYSTEM" in -Linux|GNU|GNU/*) - LIBC=unknown - - set_cc_for_build - cat <<-EOF > "$dummy.c" - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #elif defined(__GLIBC__) - LIBC=gnu - #else - #include - /* First heuristic to detect musl libc. */ - #ifdef __DEFINED_va_list - LIBC=musl - #endif - #endif - EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" - - # Second heuristic to detect musl libc. - if [ "$LIBC" = unknown ] && - command -v ldd >/dev/null && - ldd --version 2>&1 | grep -q ^musl; then - LIBC=musl - fi - - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - if [ "$LIBC" = unknown ]; then - LIBC=gnu - fi - ;; -esac - -# Note: order is significant - the case branches are not exclusive. - -case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ - /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ - echo unknown)) - case "$UNAME_MACHINE_ARCH" in - aarch64eb) machine=aarch64_be-unknown ;; - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - earmv*) - arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,') - endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p') - machine="${arch}${endian}"-unknown - ;; - *) machine="$UNAME_MACHINE_ARCH"-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently (or will in the future) and ABI. - case "$UNAME_MACHINE_ARCH" in - earm*) - os=netbsdelf - ;; - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # Determine ABI tags. - case "$UNAME_MACHINE_ARCH" in - earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr") - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "$UNAME_VERSION" in - Debian*) - release='-gnu' - ;; - *) - release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2) - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi-}" - exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') - echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') - echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" - exit ;; - *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') - echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" - exit ;; - *:MidnightBSD:*:*) - echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" - exit ;; - *:ekkoBSD:*:*) - echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" - exit ;; - *:SolidBSD:*:*) - echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" - exit ;; - *:OS108:*:*) - echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd"$UNAME_RELEASE" - exit ;; - *:MirBSD:*:*) - echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" - exit ;; - *:Sortix:*:*) - echo "$UNAME_MACHINE"-unknown-sortix - exit ;; - *:Twizzler:*:*) - echo "$UNAME_MACHINE"-unknown-twizzler - exit ;; - *:Redox:*:*) - echo "$UNAME_MACHINE"-unknown-redox - exit ;; - mips:OSF1:*.*) - echo mips-dec-osf1 - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') - ;; - *5.*) - UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE=alpha ;; - "EV4.5 (21064)") - UNAME_MACHINE=alpha ;; - "LCA4 (21066/21068)") - UNAME_MACHINE=alpha ;; - "EV5 (21164)") - UNAME_MACHINE=alphaev5 ;; - "EV5.6 (21164A)") - UNAME_MACHINE=alphaev56 ;; - "EV5.6 (21164PC)") - UNAME_MACHINE=alphapca56 ;; - "EV5.7 (21164PC)") - UNAME_MACHINE=alphapca57 ;; - "EV6 (21264)") - UNAME_MACHINE=alphaev6 ;; - "EV6.7 (21264A)") - UNAME_MACHINE=alphaev67 ;; - "EV6.8CB (21264C)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8AL (21264B)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8CX (21264D)") - UNAME_MACHINE=alphaev68 ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE=alphaev69 ;; - "EV7 (21364)") - UNAME_MACHINE=alphaev7 ;; - "EV7.9 (21364A)") - UNAME_MACHINE=alphaev79 ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix"$UNAME_RELEASE" - exit ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "$( (/bin/universe) 2>/dev/null)" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case $(/usr/bin/uname -p) in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" - exit ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux"$UNAME_RELEASE" - exit ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - set_cc_for_build - SUN_ARCH=i386 - # If there is a compiler, see if it is configured for 64-bit objects. - # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. - # This test works for both compilers. - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 - fi - fi - echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; - sun4*:SunOS:*:*) - case "$(/usr/bin/arch -k)" in - Series*|S4*) - UNAME_RELEASE=$(uname -v) - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos"$UNAME_RELEASE" - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) - test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "$(/bin/arch)" in - sun3) - echo m68k-sun-sunos"$UNAME_RELEASE" - ;; - sun4) - echo sparc-sun-sunos"$UNAME_RELEASE" - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos"$UNAME_RELEASE" - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint"$UNAME_RELEASE" - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint"$UNAME_RELEASE" - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint"$UNAME_RELEASE" - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten"$UNAME_RELEASE" - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten"$UNAME_RELEASE" - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix"$UNAME_RELEASE" - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix"$UNAME_RELEASE" - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix"$UNAME_RELEASE" - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') && - SYSTEM_NAME=$("$dummy" "$dummyarg") && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos"$UNAME_RELEASE" - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=$(/usr/bin/uname -p) - if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 - then - if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ - test "$TARGET_BINARY_INTERFACE"x = x - then - echo m88k-dg-dgux"$UNAME_RELEASE" - else - echo m88k-dg-dguxbcs"$UNAME_RELEASE" - fi - else - echo i586-dg-dgux"$UNAME_RELEASE" - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if test -x /usr/bin/oslevel ; then - IBM_REV=$(/usr/bin/oslevel) - else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" - fi - echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[4567]) - IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }') - if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if test -x /usr/bin/lslpp ; then - IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/) - else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" - fi - echo "$IBM_ARCH"-ibm-aix"$IBM_REV" - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - case "$UNAME_MACHINE" in - 9000/31?) HP_ARCH=m68000 ;; - 9000/[34]??) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if test -x /usr/bin/getconf; then - sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null) - sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null) - case "$sc_cpu_version" in - 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 - 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "$sc_kernel_bits" in - 32) HP_ARCH=hppa2.0n ;; - 64) HP_ARCH=hppa2.0w ;; - '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 - esac ;; - esac - fi - if test "$HP_ARCH" = ""; then - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy") - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if test "$HP_ARCH" = hppa2.0w - then - set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH=hppa2.0w - else - HP_ARCH=hppa64 - fi - fi - echo "$HP_ARCH"-hp-hpux"$HPUX_REV" - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') - echo ia64-hp-hpux"$HPUX_REV" - exit ;; - 3050*:HI-UX:*:*) - set_cc_for_build - sed 's/^ //' << EOF > "$dummy.c" - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if test -x /usr/sbin/sysversion ; then - echo "$UNAME_MACHINE"-unknown-osf1mk - else - echo "$UNAME_MACHINE"-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') - FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi"$UNAME_RELEASE" - exit ;; - *:BSD/OS:*:*) - echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" - exit ;; - arm:FreeBSD:*:*) - UNAME_PROCESSOR=$(uname -p) - set_cc_for_build - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi - else - echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf - fi - exit ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=$(/usr/bin/uname -p) - case "$UNAME_PROCESSOR" in - amd64) - UNAME_PROCESSOR=x86_64 ;; - i386) - UNAME_PROCESSOR=i586 ;; - esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; - i*:CYGWIN*:*) - echo "$UNAME_MACHINE"-pc-cygwin - exit ;; - *:MINGW64*:*) - echo "$UNAME_MACHINE"-pc-mingw64 - exit ;; - *:MINGW*:*) - echo "$UNAME_MACHINE"-pc-mingw32 - exit ;; - *:MSYS*:*) - echo "$UNAME_MACHINE"-pc-msys - exit ;; - i*:PW*:*) - echo "$UNAME_MACHINE"-pc-pw32 - exit ;; - *:Interix*:*) - case "$UNAME_MACHINE" in - x86) - echo i586-pc-interix"$UNAME_RELEASE" - exit ;; - authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix"$UNAME_RELEASE" - exit ;; - IA64) - echo ia64-unknown-interix"$UNAME_RELEASE" - exit ;; - esac ;; - i*:UWIN*:*) - echo "$UNAME_MACHINE"-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-pc-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" - exit ;; - *:GNU:*:*) - # the GNU system - echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" - exit ;; - *:Minix:*:*) - echo "$UNAME_MACHINE"-unknown-minix - exit ;; - aarch64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - alpha:Linux:*:*) - case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arm*:Linux:*:*) - set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi - else - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf - fi - fi - exit ;; - avr32*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - cris:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; - crisv32:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; - e2k:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - frv:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - hexagon:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - i*86:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; - ia64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - m68*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - mips:Linux:*:* | mips64:Linux:*:*) - set_cc_for_build - IS_GLIBC=0 - test x"${LIBC}" = xgnu && IS_GLIBC=1 - sed 's/^ //' << EOF > "$dummy.c" - #undef CPU - #undef mips - #undef mipsel - #undef mips64 - #undef mips64el - #if ${IS_GLIBC} && defined(_ABI64) - LIBCABI=gnuabi64 - #else - #if ${IS_GLIBC} && defined(_ABIN32) - LIBCABI=gnuabin32 - #else - LIBCABI=${LIBC} - #endif - #endif - - #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa64r6 - #else - #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 - CPU=mipsisa32r6 - #else - #if defined(__mips64) - CPU=mips64 - #else - CPU=mips - #endif - #endif - #endif - - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - MIPS_ENDIAN=el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - MIPS_ENDIAN= - #else - MIPS_ENDIAN= - #endif - #endif -EOF - eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" - test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } - ;; - mips64el:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" - exit ;; - or32:Linux:*:* | or1k*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - padre:Linux:*:*) - echo sparc-unknown-linux-"$LIBC" - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-"$LIBC" - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in - PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; - PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; - *) echo hppa-unknown-linux-"$LIBC" ;; - esac - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-"$LIBC" - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-"$LIBC" - exit ;; - ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-"$LIBC" - exit ;; - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-"$LIBC" - exit ;; - riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" - exit ;; - sh64*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - sh*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - tile*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - vax:Linux:*:*) - echo "$UNAME_MACHINE"-dec-linux-"$LIBC" - exit ;; - x86_64:Linux:*:*) - set_cc_for_build - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI="$LIBC"x32 - fi - fi - echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" - exit ;; - xtensa*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo "$UNAME_MACHINE"-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo "$UNAME_MACHINE"-unknown-stop - exit ;; - i*86:atheos:*:*) - echo "$UNAME_MACHINE"-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo "$UNAME_MACHINE"-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos"$UNAME_RELEASE" - exit ;; - i*86:*DOS:*:*) - echo "$UNAME_MACHINE"-pc-msdosdjgpp - exit ;; - i*86:*:4.*:*) - UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" - else - echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case $(/bin/uname -X | grep "^Machine") in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=$(sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" - else - echo "$UNAME_MACHINE"-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configure will decide that - # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos"$UNAME_RELEASE" - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos"$UNAME_RELEASE" - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos"$UNAME_RELEASE" - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos"$UNAME_RELEASE" - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv"$UNAME_RELEASE" - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - echo "$UNAME_MACHINE"-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo "$UNAME_MACHINE"-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux"$UNAME_RELEASE" - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if test -d /usr/nec; then - echo mips-nec-sysv"$UNAME_RELEASE" - else - echo mips-unknown-sysv"$UNAME_RELEASE" - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux"$UNAME_RELEASE" - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux"$UNAME_RELEASE" - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux"$UNAME_RELEASE" - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux"$UNAME_RELEASE" - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux"$UNAME_RELEASE" - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux"$UNAME_RELEASE" - exit ;; - SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux"$UNAME_RELEASE" - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody"$UNAME_RELEASE" - exit ;; - *:Rhapsody:*:*) - echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" - exit ;; - arm64:Darwin:*:*) - echo aarch64-apple-darwin"$UNAME_RELEASE" - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=$(uname -p) - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - if command -v xcode-select > /dev/null 2> /dev/null && \ - ! xcode-select --print-path > /dev/null 2> /dev/null ; then - # Avoid executing cc if there is no toolchain installed as - # cc will be a stub that puts up a graphical alert - # prompting the user to install developer tools. - CC_FOR_BUILD=no_compiler_found - else - set_cc_for_build - fi - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc - if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_PPC >/dev/null - then - UNAME_PROCESSOR=powerpc - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # uname -m returns i386 or x86_64 - UNAME_PROCESSOR=$UNAME_MACHINE - fi - echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=$(uname -p) - if test "$UNAME_PROCESSOR" = x86; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-*:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSR-*:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSV-*:NONSTOP_KERNEL:*:*) - echo nsv-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSX-*:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk"$UNAME_RELEASE" - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - # shellcheck disable=SC2154 - if test "$cputype" = 386; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo "$UNAME_MACHINE"-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux"$UNAME_RELEASE" - exit ;; - *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=$( (uname -p) 2>/dev/null) - case "$UNAME_MACHINE" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" - exit ;; - i*86:rdos:*:*) - echo "$UNAME_MACHINE"-pc-rdos - exit ;; - *:AROS:*:*) - echo "$UNAME_MACHINE"-unknown-aros - exit ;; - x86_64:VMkernel:*:*) - echo "$UNAME_MACHINE"-unknown-esx - exit ;; - amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; - *:Unleashed:*:*) - echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" - exit ;; -esac - -# No uname command or uname output not recognized. -set_cc_for_build -cat > "$dummy.c" < -#include -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#include -#if defined(_SIZE_T_) || defined(SIGLOST) -#include -#endif -#endif -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null); - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); -#endif - -#if defined (vax) -#if !defined (ultrix) -#include -#if defined (BSD) -#if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -#else -#if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#endif -#else - printf ("vax-dec-bsd\n"); exit (0); -#endif -#else -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname un; - uname (&un); - printf ("vax-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("vax-dec-ultrix\n"); exit (0); -#endif -#endif -#endif -#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) -#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) -#if defined(_SIZE_T_) || defined(SIGLOST) - struct utsname *un; - uname (&un); - printf ("mips-dec-ultrix%s\n", un.release); exit (0); -#else - printf ("mips-dec-ultrix\n"); exit (0); -#endif -#endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. -test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } - -echo "$0: unable to guess system type" >&2 - -case "$UNAME_MACHINE:$UNAME_SYSTEM" in - mips:Linux | mips64:Linux) - # If we got here on MIPS GNU/Linux, output extra information. - cat >&2 <&2 <&2 </dev/null || echo unknown) -uname -r = $( (uname -r) 2>/dev/null || echo unknown) -uname -s = $( (uname -s) 2>/dev/null || echo unknown) -uname -v = $( (uname -v) 2>/dev/null || echo unknown) - -/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null) -/bin/uname -X = $( (/bin/uname -X) 2>/dev/null) - -hostinfo = $( (hostinfo) 2>/dev/null) -/bin/universe = $( (/bin/universe) 2>/dev/null) -/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null) -/bin/arch = $( (/bin/arch) 2>/dev/null) -/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null) -/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null) - -UNAME_MACHINE = "$UNAME_MACHINE" -UNAME_RELEASE = "$UNAME_RELEASE" -UNAME_SYSTEM = "$UNAME_SYSTEM" -UNAME_VERSION = "$UNAME_VERSION" -EOF -fi - -exit 1 - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/lib/wx/autoconf/config.sub b/lib/wx/autoconf/config.sub deleted file mode 100755 index 63c1f1c8b5e2..000000000000 --- a/lib/wx/autoconf/config.sub +++ /dev/null @@ -1,1860 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2021 Free Software Foundation, Inc. - -timestamp='2021-01-08' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to . -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=$(echo "$0" | sed -e 's,.*/,,') - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2021 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo "$1" - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Split fields of configuration type -# shellcheck disable=SC2162 -IFS="-" read field1 field2 field3 field4 <&2 - exit 1 - ;; - *-*-*-*) - basic_machine=$field1-$field2 - basic_os=$field3-$field4 - ;; - *-*-*) - # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two - # parts - maybe_os=$field2-$field3 - case $maybe_os in - nto-qnx* | linux-* | uclinux-uclibc* \ - | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ - | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) - basic_machine=$field1 - basic_os=$maybe_os - ;; - android-linux) - basic_machine=$field1-unknown - basic_os=linux-android - ;; - *) - basic_machine=$field1-$field2 - basic_os=$field3 - ;; - esac - ;; - *-*) - # A lone config we happen to match not fitting any pattern - case $field1-$field2 in - decstation-3100) - basic_machine=mips-dec - basic_os= - ;; - *-*) - # Second component is usually, but not always the OS - case $field2 in - # Prevent following clause from handling this valid os - sun*os*) - basic_machine=$field1 - basic_os=$field2 - ;; - # Manufacturers - dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ - | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ - | unicom* | ibm* | next | hp | isi* | apollo | altos* \ - | convergent* | ncr* | news | 32* | 3600* | 3100* \ - | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ - | ultra | tti* | harris | dolphin | highlevel | gould \ - | cbm | ns | masscomp | apple | axis | knuth | cray \ - | microblaze* | sim | cisco \ - | oki | wec | wrs | winbond) - basic_machine=$field1-$field2 - basic_os= - ;; - *) - basic_machine=$field1 - basic_os=$field2 - ;; - esac - ;; - esac - ;; - *) - # Convert single-component short-hands not valid as part of - # multi-component configurations. - case $field1 in - 386bsd) - basic_machine=i386-pc - basic_os=bsd - ;; - a29khif) - basic_machine=a29k-amd - basic_os=udi - ;; - adobe68k) - basic_machine=m68010-adobe - basic_os=scout - ;; - alliant) - basic_machine=fx80-alliant - basic_os= - ;; - altos | altos3068) - basic_machine=m68k-altos - basic_os= - ;; - am29k) - basic_machine=a29k-none - basic_os=bsd - ;; - amdahl) - basic_machine=580-amdahl - basic_os=sysv - ;; - amiga) - basic_machine=m68k-unknown - basic_os= - ;; - amigaos | amigados) - basic_machine=m68k-unknown - basic_os=amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - basic_os=sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - basic_os=sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - basic_os=bsd - ;; - aros) - basic_machine=i386-pc - basic_os=aros - ;; - aux) - basic_machine=m68k-apple - basic_os=aux - ;; - balance) - basic_machine=ns32k-sequent - basic_os=dynix - ;; - blackfin) - basic_machine=bfin-unknown - basic_os=linux - ;; - cegcc) - basic_machine=arm-unknown - basic_os=cegcc - ;; - convex-c1) - basic_machine=c1-convex - basic_os=bsd - ;; - convex-c2) - basic_machine=c2-convex - basic_os=bsd - ;; - convex-c32) - basic_machine=c32-convex - basic_os=bsd - ;; - convex-c34) - basic_machine=c34-convex - basic_os=bsd - ;; - convex-c38) - basic_machine=c38-convex - basic_os=bsd - ;; - cray) - basic_machine=j90-cray - basic_os=unicos - ;; - crds | unos) - basic_machine=m68k-crds - basic_os= - ;; - da30) - basic_machine=m68k-da30 - basic_os= - ;; - decstation | pmax | pmin | dec3100 | decstatn) - basic_machine=mips-dec - basic_os= - ;; - delta88) - basic_machine=m88k-motorola - basic_os=sysv3 - ;; - dicos) - basic_machine=i686-pc - basic_os=dicos - ;; - djgpp) - basic_machine=i586-pc - basic_os=msdosdjgpp - ;; - ebmon29k) - basic_machine=a29k-amd - basic_os=ebmon - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - basic_os=ose - ;; - gmicro) - basic_machine=tron-gmicro - basic_os=sysv - ;; - go32) - basic_machine=i386-pc - basic_os=go32 - ;; - h8300hms) - basic_machine=h8300-hitachi - basic_os=hms - ;; - h8300xray) - basic_machine=h8300-hitachi - basic_os=xray - ;; - h8500hms) - basic_machine=h8500-hitachi - basic_os=hms - ;; - harris) - basic_machine=m88k-harris - basic_os=sysv3 - ;; - hp300 | hp300hpux) - basic_machine=m68k-hp - basic_os=hpux - ;; - hp300bsd) - basic_machine=m68k-hp - basic_os=bsd - ;; - hppaosf) - basic_machine=hppa1.1-hp - basic_os=osf - ;; - hppro) - basic_machine=hppa1.1-hp - basic_os=proelf - ;; - i386mach) - basic_machine=i386-mach - basic_os=mach - ;; - isi68 | isi) - basic_machine=m68k-isi - basic_os=sysv - ;; - m68knommu) - basic_machine=m68k-unknown - basic_os=linux - ;; - magnum | m3230) - basic_machine=mips-mips - basic_os=sysv - ;; - merlin) - basic_machine=ns32k-utek - basic_os=sysv - ;; - mingw64) - basic_machine=x86_64-pc - basic_os=mingw64 - ;; - mingw32) - basic_machine=i686-pc - basic_os=mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - basic_os=mingw32ce - ;; - monitor) - basic_machine=m68k-rom68k - basic_os=coff - ;; - morphos) - basic_machine=powerpc-unknown - basic_os=morphos - ;; - moxiebox) - basic_machine=moxie-unknown - basic_os=moxiebox - ;; - msdos) - basic_machine=i386-pc - basic_os=msdos - ;; - msys) - basic_machine=i686-pc - basic_os=msys - ;; - mvs) - basic_machine=i370-ibm - basic_os=mvs - ;; - nacl) - basic_machine=le32-unknown - basic_os=nacl - ;; - ncr3000) - basic_machine=i486-ncr - basic_os=sysv4 - ;; - netbsd386) - basic_machine=i386-pc - basic_os=netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - basic_os=linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - basic_os=newsos - ;; - news1000) - basic_machine=m68030-sony - basic_os=newsos - ;; - necv70) - basic_machine=v70-nec - basic_os=sysv - ;; - nh3000) - basic_machine=m68k-harris - basic_os=cxux - ;; - nh[45]000) - basic_machine=m88k-harris - basic_os=cxux - ;; - nindy960) - basic_machine=i960-intel - basic_os=nindy - ;; - mon960) - basic_machine=i960-intel - basic_os=mon960 - ;; - nonstopux) - basic_machine=mips-compaq - basic_os=nonstopux - ;; - os400) - basic_machine=powerpc-ibm - basic_os=os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - basic_os=ose - ;; - os68k) - basic_machine=m68k-none - basic_os=os68k - ;; - paragon) - basic_machine=i860-intel - basic_os=osf - ;; - parisc) - basic_machine=hppa-unknown - basic_os=linux - ;; - psp) - basic_machine=mipsallegrexel-sony - basic_os=psp - ;; - pw32) - basic_machine=i586-unknown - basic_os=pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - basic_os=rdos - ;; - rdos32) - basic_machine=i386-pc - basic_os=rdos - ;; - rom68k) - basic_machine=m68k-rom68k - basic_os=coff - ;; - sa29200) - basic_machine=a29k-amd - basic_os=udi - ;; - sei) - basic_machine=mips-sei - basic_os=seiux - ;; - sequent) - basic_machine=i386-sequent - basic_os= - ;; - sps7) - basic_machine=m68k-bull - basic_os=sysv2 - ;; - st2000) - basic_machine=m68k-tandem - basic_os= - ;; - stratus) - basic_machine=i860-stratus - basic_os=sysv4 - ;; - sun2) - basic_machine=m68000-sun - basic_os= - ;; - sun2os3) - basic_machine=m68000-sun - basic_os=sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - basic_os=sunos4 - ;; - sun3) - basic_machine=m68k-sun - basic_os= - ;; - sun3os3) - basic_machine=m68k-sun - basic_os=sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - basic_os=sunos4 - ;; - sun4) - basic_machine=sparc-sun - basic_os= - ;; - sun4os3) - basic_machine=sparc-sun - basic_os=sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - basic_os=sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - basic_os=solaris2 - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - basic_os= - ;; - sv1) - basic_machine=sv1-cray - basic_os=unicos - ;; - symmetry) - basic_machine=i386-sequent - basic_os=dynix - ;; - t3e) - basic_machine=alphaev5-cray - basic_os=unicos - ;; - t90) - basic_machine=t90-cray - basic_os=unicos - ;; - toad1) - basic_machine=pdp10-xkl - basic_os=tops20 - ;; - tpf) - basic_machine=s390x-ibm - basic_os=tpf - ;; - udi29k) - basic_machine=a29k-amd - basic_os=udi - ;; - ultra3) - basic_machine=a29k-nyu - basic_os=sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - basic_os=none - ;; - vaxv) - basic_machine=vax-dec - basic_os=sysv - ;; - vms) - basic_machine=vax-dec - basic_os=vms - ;; - vsta) - basic_machine=i386-pc - basic_os=vsta - ;; - vxworks960) - basic_machine=i960-wrs - basic_os=vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - basic_os=vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - basic_os=vxworks - ;; - xbox) - basic_machine=i686-pc - basic_os=mingw32 - ;; - ymp) - basic_machine=ymp-cray - basic_os=unicos - ;; - *) - basic_machine=$1 - basic_os= - ;; - esac - ;; -esac - -# Decode 1-component or ad-hoc basic machines -case $basic_machine in - # Here we handle the default manufacturer of certain CPU types. It is in - # some cases the only manufacturer, in others, it is the most popular. - w89k) - cpu=hppa1.1 - vendor=winbond - ;; - op50n) - cpu=hppa1.1 - vendor=oki - ;; - op60c) - cpu=hppa1.1 - vendor=oki - ;; - ibm*) - cpu=i370 - vendor=ibm - ;; - orion105) - cpu=clipper - vendor=highlevel - ;; - mac | mpw | mac-mpw) - cpu=m68k - vendor=apple - ;; - pmac | pmac-mpw) - cpu=powerpc - vendor=apple - ;; - - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - cpu=m68000 - vendor=att - ;; - 3b*) - cpu=we32k - vendor=att - ;; - bluegene*) - cpu=powerpc - vendor=ibm - basic_os=cnk - ;; - decsystem10* | dec10*) - cpu=pdp10 - vendor=dec - basic_os=tops10 - ;; - decsystem20* | dec20*) - cpu=pdp10 - vendor=dec - basic_os=tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - cpu=m68k - vendor=motorola - ;; - dpx2*) - cpu=m68k - vendor=bull - basic_os=sysv3 - ;; - encore | umax | mmax) - cpu=ns32k - vendor=encore - ;; - elxsi) - cpu=elxsi - vendor=elxsi - basic_os=${basic_os:-bsd} - ;; - fx2800) - cpu=i860 - vendor=alliant - ;; - genix) - cpu=ns32k - vendor=ns - ;; - h3050r* | hiux*) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - cpu=m68000 - vendor=hp - ;; - hp9k3[2-9][0-9]) - cpu=m68k - vendor=hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - cpu=hppa1.1 - vendor=hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - cpu=hppa1.0 - vendor=hp - ;; - i*86v32) - cpu=$(echo "$1" | sed -e 's/86.*/86/') - vendor=pc - basic_os=sysv32 - ;; - i*86v4*) - cpu=$(echo "$1" | sed -e 's/86.*/86/') - vendor=pc - basic_os=sysv4 - ;; - i*86v) - cpu=$(echo "$1" | sed -e 's/86.*/86/') - vendor=pc - basic_os=sysv - ;; - i*86sol2) - cpu=$(echo "$1" | sed -e 's/86.*/86/') - vendor=pc - basic_os=solaris2 - ;; - j90 | j90-cray) - cpu=j90 - vendor=cray - basic_os=${basic_os:-unicos} - ;; - iris | iris4d) - cpu=mips - vendor=sgi - case $basic_os in - irix*) - ;; - *) - basic_os=irix4 - ;; - esac - ;; - miniframe) - cpu=m68000 - vendor=convergent - ;; - *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) - cpu=m68k - vendor=atari - basic_os=mint - ;; - news-3600 | risc-news) - cpu=mips - vendor=sony - basic_os=newsos - ;; - next | m*-next) - cpu=m68k - vendor=next - case $basic_os in - openstep*) - ;; - nextstep*) - ;; - ns2*) - basic_os=nextstep2 - ;; - *) - basic_os=nextstep3 - ;; - esac - ;; - np1) - cpu=np1 - vendor=gould - ;; - op50n-* | op60c-*) - cpu=hppa1.1 - vendor=oki - basic_os=proelf - ;; - pa-hitachi) - cpu=hppa1.1 - vendor=hitachi - basic_os=hiuxwe2 - ;; - pbd) - cpu=sparc - vendor=tti - ;; - pbb) - cpu=m68k - vendor=tti - ;; - pc532) - cpu=ns32k - vendor=pc532 - ;; - pn) - cpu=pn - vendor=gould - ;; - power) - cpu=power - vendor=ibm - ;; - ps2) - cpu=i386 - vendor=ibm - ;; - rm[46]00) - cpu=mips - vendor=siemens - ;; - rtpc | rtpc-*) - cpu=romp - vendor=ibm - ;; - sde) - cpu=mipsisa32 - vendor=sde - basic_os=${basic_os:-elf} - ;; - simso-wrs) - cpu=sparclite - vendor=wrs - basic_os=vxworks - ;; - tower | tower-32) - cpu=m68k - vendor=ncr - ;; - vpp*|vx|vx-*) - cpu=f301 - vendor=fujitsu - ;; - w65) - cpu=w65 - vendor=wdc - ;; - w89k-*) - cpu=hppa1.1 - vendor=winbond - basic_os=proelf - ;; - none) - cpu=none - vendor=none - ;; - leon|leon[3-9]) - cpu=sparc - vendor=$basic_machine - ;; - leon-*|leon[3-9]-*) - cpu=sparc - vendor=$(echo "$basic_machine" | sed 's/-.*//') - ;; - - *-*) - # shellcheck disable=SC2162 - IFS="-" read cpu vendor <&2 - exit 1 - ;; - esac - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $vendor in - digital*) - vendor=dec - ;; - commodore*) - vendor=cbm - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if test x$basic_os != x -then - -# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just -# set os. -case $basic_os in - gnu/linux*) - kernel=linux - os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') - ;; - os2-emx) - kernel=os2 - os=$(echo $basic_os | sed -e 's|os2-emx|emx|') - ;; - nto-qnx*) - kernel=nto - os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') - ;; - *-*) - # shellcheck disable=SC2162 - IFS="-" read kernel os <&2 - exit 1 - ;; -esac - -# As a final step for OS-related things, validate the OS-kernel combination -# (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) - ;; - uclinux-uclibc* ) - ;; - -dietlibc* | -newlib* | -musl* | -uclibc* ) - # These are just libc implementations, not actual OSes, and thus - # require a kernel. - echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 - exit 1 - ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) - ;; - vxworks-simlinux | vxworks-simwindows | vxworks-spe) - ;; - nto-qnx*) - ;; - os2-emx) - ;; - *-eabi* | *-gnueabi*) - ;; - -*) - # Blank kernel with real OS is always fine. - ;; - *-*) - echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 - exit 1 - ;; -esac - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -case $vendor in - unknown) - case $cpu-$os in - *-riscix*) - vendor=acorn - ;; - *-sunos*) - vendor=sun - ;; - *-cnk* | *-aix*) - vendor=ibm - ;; - *-beos*) - vendor=be - ;; - *-hpux*) - vendor=hp - ;; - *-mpeix*) - vendor=hp - ;; - *-hiux*) - vendor=hitachi - ;; - *-unos*) - vendor=crds - ;; - *-dgux*) - vendor=dg - ;; - *-luna*) - vendor=omron - ;; - *-genix*) - vendor=ns - ;; - *-clix*) - vendor=intergraph - ;; - *-mvs* | *-opened*) - vendor=ibm - ;; - *-os400*) - vendor=ibm - ;; - s390-* | s390x-*) - vendor=ibm - ;; - *-ptx*) - vendor=sequent - ;; - *-tpf*) - vendor=ibm - ;; - *-vxsim* | *-vxworks* | *-windiss*) - vendor=wrs - ;; - *-aux*) - vendor=apple - ;; - *-hms*) - vendor=hitachi - ;; - *-mpw* | *-macos*) - vendor=apple - ;; - *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) - vendor=atari - ;; - *-vos*) - vendor=stratus - ;; - esac - ;; -esac - -echo "$cpu-$vendor-${kernel:+$kernel-}$os" -exit - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/lib/wx/autoconf/install-sh b/lib/wx/autoconf/install-sh deleted file mode 100755 index ec298b537402..000000000000 --- a/lib/wx/autoconf/install-sh +++ /dev/null @@ -1,541 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2020-11-14.01; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -# Create dirs (including intermediate dirs) using mode 755. -# This is like GNU 'install' as of coreutils 8.32 (2020). -mkdir_umask=22 - -backupsuffix= -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -p pass -p to $cpprog. - -s $stripprog installed files. - -S SUFFIX attempt to back up existing files, with suffix SUFFIX. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG - -By default, rm is invoked with -f; when overridden with RMPROG, -it's up to you to specify -f if you want it. - -If -S is not specified, no backups are attempted. - -Email bug reports to bug-automake@gnu.org. -Automake home page: https://www.gnu.org/software/automake/ -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -p) cpprog="$cpprog -p";; - - -s) stripcmd=$stripprog;; - - -S) backupsuffix="$2" - shift;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - # Don't chown directories that already exist. - if test $dstdir_status = 0; then - chowncmd="" - fi - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dstbase=`basename "$src"` - case $dst in - */) dst=$dst$dstbase;; - *) dst=$dst/$dstbase;; - esac - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - case $dstdir in - */) dstdirslash=$dstdir;; - *) dstdirslash=$dstdir/;; - esac - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - # The $RANDOM variable is not portable (e.g., dash). Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap ' - ret=$? - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null - exit $ret - ' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p'. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=${dstdirslash}_inst.$$_ - rmtmp=${dstdirslash}_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && - { test -z "$stripcmd" || { - # Create $dsttmp read-write so that cp doesn't create it read-only, - # which would cause strip to fail. - if test -z "$doit"; then - : >"$dsttmp" # No need to fork-exec 'touch'. - else - $doit touch "$dsttmp" - fi - } - } && - $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # If $backupsuffix is set, and the file being installed - # already exists, attempt a backup. Don't worry if it fails, - # e.g., if mv doesn't support -f. - if test -n "$backupsuffix" && test -f "$dst"; then - $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null - fi - - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in index 8a638b740ad0..01dd47d4b8ee 100644 --- a/lib/wx/c_src/Makefile.in +++ b/lib/wx/c_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2023. 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. @@ -97,25 +97,25 @@ RESCOMP = @WX_RESCOMP@ ifeq (@WX_HAVE_STATIC_LIBS@,true) OPT_WX_LIBS = @WX_LIBS_STATIC@ -DEBUG_WX_LIBS = @DEBUG_WX_LIBS_STATIC@ +DEBUG_WX_LIBS = @DEBUG_WX_LIBS_STATIC@ @GLIB_LIBS@ else -OPT_WX_LIBS = @WX_LIBS@ -DEBUG_WX_LIBS = @DEBUG_WX_LIBS@ +OPT_WX_LIBS = @WX_LIBS@ @GLIB_LIBS@ +DEBUG_WX_LIBS = @DEBUG_WX_LIBS@ @GLIB_LIBS@ endif ifeq ($(TYPE),debug) WX_CFLAGS = @DEBUG_WX_CFLAGS@ CFLAGS = @DEBUG_CFLAGS@ WX_CXX_FLAGS = @DEBUG_WX_CXXFLAGS@ -CXX_FLAGS = @DEBUG_CXXFLAGS@ -CXX_NO_OPT_FLAGS = @DEBUG_CXXFLAGS@ +CXX_FLAGS = @DEBUG_CXXFLAGS@ @GLIB_CFLAGS@ +CXX_NO_OPT_FLAGS = @DEBUG_CXXFLAGS@ @GLIB_CFLAGS@ WX_LIBS = $(DEBUG_WX_LIBS) else WX_CFLAGS = @WX_CFLAGS@ CFLAGS = @CFLAGS@ WX_CXX_FLAGS = @WX_CXXFLAGS@ -CXX_FLAGS = @CXXFLAGS@ -CXX_NO_OPT_FLAGS = @CXXNOOPTFLAGS@ +CXX_FLAGS = @CXXFLAGS@ @GLIB_CFLAGS@ +CXX_NO_OPT_FLAGS = @CXXNOOPTFLAGS@ @GLIB_CFLAGS@ WX_LIBS = $(OPT_WX_LIBS) endif @@ -130,8 +130,8 @@ CXX_O_NO_OPT = $(V_CXX) -c $(CXX_NO_OPT_FLAGS) $(WX_CXX_FLAGS) $(COMMON_CFLA opt: $(TARGET_DIR)/wxe_driver$(SO_EXT) $(TARGET_DIR)/erl_gl$(SO_EXT) $(WEBVIEW_LOADER_DLL_DEST) -debug: - @${MAKE} TYPE=debug +$(filter-out opt, $(TYPES)): + @${MAKE} TYPE=$@ opt clean: rm -f $(OBJECTS) @@ -182,7 +182,7 @@ $(TARGET_DIR)/wxe_driver$(SO_EXT): $(WX_OBJECTS) $(TARGET_DIR)/erl_gl$(SO_EXT): $(GL_OBJECTS) $(V_at)mkdir -p $(TARGET_DIR) - $(V_CC) $(LDFLAGS) $(GL_OBJECTS) $(GL_LIBS) -o $@ + $(V_CXX) $(LDFLAGS) $(GL_OBJECTS) $(GL_LIBS) -o $@ $(WEBVIEW_LOADER_DLL_DEST): $(WEBVIEW_LOADER_DLL_ORIG) $(INSTALL_PROGRAM) $< $@ @@ -199,7 +199,11 @@ release_spec: opt $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) "$(RELSYSDIR)/priv/" $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) "$(RELSYSDIR)/priv/" ifneq ($(WEBVIEW_LOADER_DLL_ORIG),) - $(INSTALL_PROGRAM) $(WEBVIEW_LOADER_DLL_DEST) "$(RELSYSDIR)/priv/" + $(INSTALL_PROGRAM) $(WEBVIEW_LOADER_DLL_DEST) "$(RELSYSDIR)/priv/" +endif +ifeq ($(SYS_TYPE),win32) + $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver.pdb "$(RELSYSDIR)/priv/" + $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl.pdb "$(RELSYSDIR)/priv/" endif release_docs_spec: diff --git a/lib/wx/c_src/egl_impl.c b/lib/wx/c_src/egl_impl.c index 2703f55408e9..868b32ab790b 100644 --- a/lib/wx/c_src/egl_impl.c +++ b/lib/wx/c_src/egl_impl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2021. All Rights Reserved. + * Copyright Ericsson AB 2011-2023. 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. @@ -51,7 +51,7 @@ ERL_NIF_TERM EGL_ATOM_BADARG; static ErlNifFunc egl_funcs[] = { - {"lookup_func", 0, egl_lookup_func_func} + {"lookup_func_nif", 1, egl_lookup_func_func} }; static int egl_init(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM arg) { @@ -142,9 +142,22 @@ void * egl_lookup_func(int op) return gl_fns[op-GLE_LIB_START].nif_cb; } +const char * egl_lookup_func_desc(int op) +{ + return gl_fns[op-GLE_LIB_START].name; +} + + ERL_NIF_TERM egl_lookup_func_func(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - egl_uword func = (egl_uword) egl_lookup_func; + egl_uword func = 0; + unsigned int which; + if(!(enif_get_uint(env, argv[0], &which)) && !(which == 1 || which == 2)) + return enif_make_badarg(env); + if(which == 1) + func = (egl_uword) egl_lookup_func; + if(which == 2) + func = (egl_uword) egl_lookup_func_desc; if(sizeof(void *) == sizeof(unsigned int)) return enif_make_uint(env, (unsigned int) func); else @@ -279,7 +292,7 @@ int egl_load_functions() { } /* ******************************************************************************* - * GLU Tesselation special + * GLU Tessellation special * ******************************************************************************/ static GLUtesselator* tess; @@ -355,7 +368,7 @@ egl_ogla_error(GLenum errorCode) { // const GLubyte *err; // err = gluErrorString(errorCode); - // fprintf(stderr, "Tesselation error: %d: %s\r\n", (int) errorCode, err); + // fprintf(stderr, "Tessellation error: %d: %s\r\n", (int) errorCode, err); } void init_tess() diff --git a/lib/wx/c_src/egl_impl.h b/lib/wx/c_src/egl_impl.h index 21bcf696446d..5a7c76b28951 100644 --- a/lib/wx/c_src/egl_impl.h +++ b/lib/wx/c_src/egl_impl.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2021. All Rights Reserved. + * Copyright Ericsson AB 2010-2022. 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. @@ -29,10 +29,10 @@ #include #include #include -#elif defined(HAVE_GL_GL_H) +#elif defined(HAVE_GL_GL_H) && defined(HAVE_GL_GLU_H) #include # include -#elif defined(HAVE_OPENGL_GL_H) +#elif defined(HAVE_OPENGL_GL_H) && defined(HAVE_OPENGL_GLU_H) #include #include #endif diff --git a/lib/wx/c_src/gen/gl_nif.cpp b/lib/wx/c_src/gen/gl_nif.cpp index 57e3196d9847..efe09af3f7b0 100644 --- a/lib/wx/c_src/gen/gl_nif.cpp +++ b/lib/wx/c_src/gen/gl_nif.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -11518,15 +11518,13 @@ void ecb_glDebugMessageInsert(ErlNifEnv* env, ErlNifPid *self, ERL_NIF_TERM argv GLenum type; GLuint id; GLenum severity; - GLsizei length; ErlNifBinary buf; if(!enif_get_uint(env, argv[0], &source)) Badarg(5803,"source"); if(!enif_get_uint(env, argv[1], &type)) Badarg(5803,"type"); if(!enif_get_uint(env, argv[2], &id)) Badarg(5803,"id"); if(!enif_get_uint(env, argv[3], &severity)) Badarg(5803,"severity"); - if(!enif_get_int(env, argv[4], &length)) Badarg(5803,"length"); - if(!enif_inspect_binary(env, argv[5], &buf)) Badarg(5803,"buf"); - weglDebugMessageInsert(source,type,id,severity,length,(GLchar *) buf.data); + if(!enif_inspect_binary(env, argv[4], &buf)) Badarg(5803,"buf"); + weglDebugMessageInsert(source,type,id,severity,(GLsizei) buf.size,(GLchar *) buf.data); } void ecb_glGetDebugMessageLog(ErlNifEnv* env, ErlNifPid *self, ERL_NIF_TERM argv[]) @@ -11549,6 +11547,8 @@ void ecb_glGetDebugMessageLog(ErlNifEnv* env, ErlNifPid *self, ERL_NIF_TERM argv std::vector lengths (count); std::vector lengths_ts (count); messageLog = (unsigned char *) enif_alloc((int) bufSize*sizeof(GLchar)); + unsigned char *messageLog_ptr = messageLog; + std::vector messageLog_ts (count); result = weglGetDebugMessageLog(count,bufSize,sources.data(),types.data(),ids.data(),severities.data(),lengths.data(),(GLchar *) messageLog); for(int ri=0; ri < (int) result; ri++) sources_ts[ri] = enif_make_int(env, sources[ri]); @@ -11558,16 +11558,20 @@ void ecb_glGetDebugMessageLog(ErlNifEnv* env, ErlNifPid *self, ERL_NIF_TERM argv ids_ts[ri] = enif_make_int(env, ids[ri]); for(int ri=0; ri < (int) result; ri++) severities_ts[ri] = enif_make_int(env, severities[ri]); + for(int ri=0; ri < (int) result; ri++) { + messageLog_ts[ri] = enif_make_string(env, (const char *) messageLog, ERL_NIF_LATIN1); + messageLog += lengths[ri]; + } reply = enif_make_tuple6(env, enif_make_int(env, result), enif_make_list_from_array(env, sources_ts.data(), result), enif_make_list_from_array(env, types_ts.data(), result), enif_make_list_from_array(env, ids_ts.data(), result), enif_make_list_from_array(env, severities_ts.data(), result), - enif_make_string(env, (const char *) messageLog, ERL_NIF_LATIN1) ); + enif_make_list_from_array(env, messageLog_ts.data(), result) ); enif_send(NULL, self, env, enif_make_tuple2(env, EGL_ATOM_REPLY, reply)); - enif_free(messageLog); + enif_free(messageLog_ptr); } void ecb_glPushDebugGroup(ErlNifEnv* env, ErlNifPid *self, ERL_NIF_TERM argv[]) diff --git a/lib/wx/c_src/gen/wxe_func_table.cpp b/lib/wx/c_src/gen/wxe_func_table.cpp index 6538bf4f2a24..a044031472ca 100644 --- a/lib/wx/c_src/gen/wxe_func_table.cpp +++ b/lib/wx/c_src/gen/wxe_func_table.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2022. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -964,6 +964,12 @@ extern void wxMenuBar_GetAutoWindowMenu(WxeApp *app, wxeMemEnv *memenv, wxeComma #if defined(__WXMAC__) extern void wxMenuBar_OSXGetAppleMenu(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #endif // defined(__WXMAC__) +#if defined(__WXMAC__) +extern void wxMenuBar_MacGetCommonMenuBar(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +#endif // defined(__WXMAC__) +#if defined(__WXMAC__) +extern void wxMenuBar_MacSetCommonMenuBar(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +#endif // defined(__WXMAC__) extern void wxMenuBar_IsEnabled(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxMenuBar_Remove(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxMenuBar_Replace(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); @@ -2449,6 +2455,12 @@ extern void wxGLCanvas_new(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #if wxUSE_GLCANVAS extern void wxGLCanvas_SetCurrent(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #endif // wxUSE_GLCANVAS +#if wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL +extern void wxGLCanvas_CreateSurface(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +#endif // wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL +#if wxUSE_GLCANVAS +extern void wxGLCanvas_IsDisplaySupported(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +#endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS extern void wxGLCanvas_SwapBuffers(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #endif // wxUSE_GLCANVAS @@ -2460,6 +2472,9 @@ extern void wxGLContext_new(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #if wxUSE_GLCANVAS extern void wxGLContext_SetCurrent(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); #endif // wxUSE_GLCANVAS +#if wxUSE_GLCANVAS && wxCHECK_VERSION(3,1,0) +extern void wxGLContext_IsOK(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +#endif // wxUSE_GLCANVAS && wxCHECK_VERSION(3,1,0) #if wxUSE_GLCANVAS #endif // wxUSE_GLCANVAS #if wxUSE_AUI @@ -2983,6 +2998,12 @@ extern void wxMouseEvent_RightIsDown(WxeApp *app, wxeMemEnv *memenv, wxeCommand& extern void wxMouseEvent_RightUp(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxMouseEvent_ShiftDown(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxMouseEvent_GetWheelAxis(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux1DClick(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux1Down(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux1Up(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux2DClick(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux2Down(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); +extern void wxMouseEvent_Aux2Up(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxSetCursorEvent_GetCursor(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxSetCursorEvent_GetX(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); extern void wxSetCursorEvent_GetY(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd); @@ -5362,3714 +5383,3745 @@ wxe_fns_t wxe_fns[] = #else {NULL, "wxMenuBar", "oSXGetAppleMenu", 0}, // 873 #endif // defined(__WXMAC__) - {wxMenuBar_IsEnabled, "wxMenuBar", "isEnabled", 2}, // 874 - {wxMenuBar_Remove, "wxMenuBar", "remove", 2}, // 875 - {wxMenuBar_Replace, "wxMenuBar", "replace", 4}, // 876 - {wxMenuBar_SetHelpString, "wxMenuBar", "setHelpString", 3}, // 877 - {wxMenuBar_SetLabel, "wxMenuBar", "setLabel", 3}, // 878 - {wxMenuBar_SetMenuLabel, "wxMenuBar", "setMenuLabel", 3}, // 879 - {wxControl_GetLabel, "wxControl", "getLabel", 1}, // 880 - {wxControl_SetLabel, "wxControl", "setLabel", 2}, // 881 - {wxControlWithItems_Append_1, "wxControlWithItems", "append", 2}, // 882 - {wxControlWithItems_Append_2, "wxControlWithItems", "append", 3}, // 883 - {wxControlWithItems_appendStrings_1, "wxControlWithItems", "appendStrings", 2}, // 884 - {wxControlWithItems_appendStrings_2, "wxControlWithItems", "appendStrings", 3}, // 885 - {wxControlWithItems_Clear, "wxControlWithItems", "clear", 1}, // 886 - {wxControlWithItems_Delete, "wxControlWithItems", "delete", 2}, // 887 - {wxControlWithItems_FindString, "wxControlWithItems", "findString", 3}, // 888 - {wxControlWithItems_getClientData, "wxControlWithItems", "getClientData", 2}, // 889 - {wxControlWithItems_setClientData, "wxControlWithItems", "setClientData", 3}, // 890 - {wxControlWithItems_GetCount, "wxControlWithItems", "getCount", 1}, // 891 - {wxControlWithItems_GetSelection, "wxControlWithItems", "getSelection", 1}, // 892 - {wxControlWithItems_GetString, "wxControlWithItems", "getString", 2}, // 893 - {wxControlWithItems_GetStringSelection, "wxControlWithItems", "getStringSelection", 1}, // 894 - {wxControlWithItems_Insert_2, "wxControlWithItems", "insert", 3}, // 895 - {wxControlWithItems_Insert_3, "wxControlWithItems", "insert", 4}, // 896 - {wxControlWithItems_insertStrings_2, "wxControlWithItems", "insertStrings", 3}, // 897 - {wxControlWithItems_insertStrings_3, "wxControlWithItems", "insertStrings", 4}, // 898 - {wxControlWithItems_IsEmpty, "wxControlWithItems", "isEmpty", 1}, // 899 - {wxControlWithItems_Select, "wxControlWithItems", "select", 2}, // 900 - {wxControlWithItems_SetSelection, "wxControlWithItems", "setSelection", 2}, // 901 - {wxControlWithItems_SetString, "wxControlWithItems", "setString", 3}, // 902 - {wxControlWithItems_SetStringSelection, "wxControlWithItems", "setStringSelection", 2}, // 903 - {wxMenu_new_0, "wxMenu", "new", 0}, // 904 - {wxMenu_new_1, "wxMenu", "new", 1}, // 905 - {wxMenu_new_2, "wxMenu", "new", 2}, // 906 - {NULL, "wxMenu", "destroy", 1}, // 907 obj destructor wxMenu_destruct - {wxMenu_Append_3, "wxMenu", "append", 4}, // 908 - {wxMenu_Append_4, "wxMenu", "append", 5}, // 909 - {wxMenu_Append_1, "wxMenu", "append", 2}, // 910 - {wxMenu_AppendCheckItem, "wxMenu", "appendCheckItem", 4}, // 911 - {wxMenu_AppendRadioItem, "wxMenu", "appendRadioItem", 4}, // 912 - {wxMenu_AppendSeparator, "wxMenu", "appendSeparator", 1}, // 913 - {wxMenu_Break, "wxMenu", "break", 1}, // 914 - {wxMenu_Check, "wxMenu", "check", 3}, // 915 - {wxMenu_Delete_1_0, "wxMenu", "delete", 2}, // 916 - {wxMenu_Delete_1_1, "wxMenu", "delete", 2}, // 917 - {wxMenu_Destroy_1_0, "wxMenu", "'Destroy'", 2}, // 918 - {wxMenu_Destroy_1_1, "wxMenu", "'Destroy'", 2}, // 919 - {wxMenu_Enable, "wxMenu", "enable", 3}, // 920 - {wxMenu_FindItem_1, "wxMenu", "findItem", 2}, // 921 - {wxMenu_FindItem_2, "wxMenu", "findItem", 2}, // 922 - {wxMenu_FindItemByPosition, "wxMenu", "findItemByPosition", 2}, // 923 - {wxMenu_GetHelpString, "wxMenu", "getHelpString", 2}, // 924 - {wxMenu_GetLabel, "wxMenu", "getLabel", 2}, // 925 - {wxMenu_GetMenuItemCount, "wxMenu", "getMenuItemCount", 1}, // 926 - {NULL, "", "", 0}, // 927 - {wxMenu_GetMenuItems, "wxMenu", "getMenuItems", 1}, // 928 - {wxMenu_GetTitle, "wxMenu", "getTitle", 1}, // 929 - {wxMenu_Insert_2, "wxMenu", "insert", 3}, // 930 - {wxMenu_Insert_3, "wxMenu", "insert", 4}, // 931 - {wxMenu_Insert_5, "wxMenu", "insert", 6}, // 932 - {wxMenu_InsertCheckItem, "wxMenu", "insertCheckItem", 5}, // 933 - {wxMenu_InsertRadioItem, "wxMenu", "insertRadioItem", 5}, // 934 - {wxMenu_InsertSeparator, "wxMenu", "insertSeparator", 2}, // 935 - {wxMenu_IsChecked, "wxMenu", "isChecked", 2}, // 936 - {wxMenu_IsEnabled, "wxMenu", "isEnabled", 2}, // 937 - {wxMenu_Prepend_1, "wxMenu", "prepend", 2}, // 938 - {wxMenu_Prepend_2, "wxMenu", "prepend", 3}, // 939 - {wxMenu_Prepend_4, "wxMenu", "prepend", 5}, // 940 - {wxMenu_PrependCheckItem, "wxMenu", "prependCheckItem", 4}, // 941 - {wxMenu_PrependRadioItem, "wxMenu", "prependRadioItem", 4}, // 942 - {wxMenu_PrependSeparator, "wxMenu", "prependSeparator", 1}, // 943 - {wxMenu_Remove_1_0, "wxMenu", "remove", 2}, // 944 - {wxMenu_Remove_1_1, "wxMenu", "remove", 2}, // 945 - {wxMenu_SetHelpString, "wxMenu", "setHelpString", 3}, // 946 - {wxMenu_SetLabel, "wxMenu", "setLabel", 3}, // 947 - {wxMenu_SetTitle, "wxMenu", "setTitle", 2}, // 948 - {wxMenuItem_new, "wxMenuItem", "new", 1}, // 949 - {NULL, "wxMenuItem", "destroy", 1}, // 950 obj destructor wxMenuItem_destruct - {wxMenuItem_Check, "wxMenuItem", "check", 2}, // 951 - {wxMenuItem_Enable, "wxMenuItem", "enable", 2}, // 952 - {wxMenuItem_GetBitmap, "wxMenuItem", "getBitmap", 1}, // 953 - {wxMenuItem_GetHelp, "wxMenuItem", "getHelp", 1}, // 954 - {wxMenuItem_GetId, "wxMenuItem", "getId", 1}, // 955 - {wxMenuItem_GetKind, "wxMenuItem", "getKind", 1}, // 956 - {wxMenuItem_GetLabelText, "wxMenuItem", "getLabelText", 1}, // 957 - {wxMenuItem_GetItemLabel, "wxMenuItem", "getItemLabel", 1}, // 958 - {wxMenuItem_GetItemLabelText, "wxMenuItem", "getItemLabelText", 1}, // 959 - {wxMenuItem_GetMenu, "wxMenuItem", "getMenu", 1}, // 960 - {wxMenuItem_GetSubMenu, "wxMenuItem", "getSubMenu", 1}, // 961 - {wxMenuItem_IsCheckable, "wxMenuItem", "isCheckable", 1}, // 962 - {wxMenuItem_IsChecked, "wxMenuItem", "isChecked", 1}, // 963 - {wxMenuItem_IsEnabled, "wxMenuItem", "isEnabled", 1}, // 964 - {wxMenuItem_IsSeparator, "wxMenuItem", "isSeparator", 1}, // 965 - {wxMenuItem_IsSubMenu, "wxMenuItem", "isSubMenu", 1}, // 966 - {wxMenuItem_SetBitmap, "wxMenuItem", "setBitmap", 2}, // 967 - {wxMenuItem_SetHelp, "wxMenuItem", "setHelp", 2}, // 968 - {wxMenuItem_SetMenu, "wxMenuItem", "setMenu", 2}, // 969 - {wxMenuItem_SetSubMenu, "wxMenuItem", "setSubMenu", 2}, // 970 - {wxMenuItem_SetItemLabel, "wxMenuItem", "setItemLabel", 2}, // 971 - {wxToolBar_AddControl, "wxToolBar", "addControl", 3}, // 972 - {wxToolBar_AddSeparator, "wxToolBar", "addSeparator", 1}, // 973 - {wxToolBar_AddTool_1, "wxToolBar", "addTool", 2}, // 974 - {wxToolBar_AddTool_4, "wxToolBar", "addTool", 5}, // 975 - {wxToolBar_AddTool_5, "wxToolBar", "addTool", 6}, // 976 - {wxToolBar_AddCheckTool, "wxToolBar", "addCheckTool", 5}, // 977 - {wxToolBar_AddRadioTool, "wxToolBar", "addRadioTool", 5}, // 978 - {wxToolBar_AddStretchableSpace, "wxToolBar", "addStretchableSpace", 1}, // 979 - {wxToolBar_InsertStretchableSpace, "wxToolBar", "insertStretchableSpace", 2}, // 980 - {wxToolBar_DeleteTool, "wxToolBar", "deleteTool", 2}, // 981 - {wxToolBar_DeleteToolByPos, "wxToolBar", "deleteToolByPos", 2}, // 982 - {wxToolBar_EnableTool, "wxToolBar", "enableTool", 3}, // 983 - {wxToolBar_FindById, "wxToolBar", "findById", 2}, // 984 - {wxToolBar_FindControl, "wxToolBar", "findControl", 2}, // 985 - {wxToolBar_FindToolForPosition, "wxToolBar", "findToolForPosition", 3}, // 986 - {wxToolBar_GetToolSize, "wxToolBar", "getToolSize", 1}, // 987 - {wxToolBar_GetToolBitmapSize, "wxToolBar", "getToolBitmapSize", 1}, // 988 - {wxToolBar_GetMargins, "wxToolBar", "getMargins", 1}, // 989 - {wxToolBar_GetToolEnabled, "wxToolBar", "getToolEnabled", 2}, // 990 - {wxToolBar_GetToolLongHelp, "wxToolBar", "getToolLongHelp", 2}, // 991 - {wxToolBar_GetToolPacking, "wxToolBar", "getToolPacking", 1}, // 992 - {wxToolBar_GetToolPos, "wxToolBar", "getToolPos", 2}, // 993 - {wxToolBar_GetToolSeparation, "wxToolBar", "getToolSeparation", 1}, // 994 - {wxToolBar_GetToolShortHelp, "wxToolBar", "getToolShortHelp", 2}, // 995 - {wxToolBar_GetToolState, "wxToolBar", "getToolState", 2}, // 996 - {wxToolBar_InsertControl, "wxToolBar", "insertControl", 4}, // 997 - {wxToolBar_InsertSeparator, "wxToolBar", "insertSeparator", 2}, // 998 - {wxToolBar_InsertTool_5, "wxToolBar", "insertTool", 6}, // 999 - {wxToolBar_InsertTool_2, "wxToolBar", "insertTool", 3}, // 1000 - {wxToolBar_Realize, "wxToolBar", "realize", 1}, // 1001 - {wxToolBar_RemoveTool, "wxToolBar", "removeTool", 2}, // 1002 - {wxToolBar_SetMargins, "wxToolBar", "setMargins", 3}, // 1003 - {wxToolBar_SetToolBitmapSize, "wxToolBar", "setToolBitmapSize", 2}, // 1004 - {wxToolBar_SetToolLongHelp, "wxToolBar", "setToolLongHelp", 3}, // 1005 - {wxToolBar_SetToolPacking, "wxToolBar", "setToolPacking", 2}, // 1006 - {wxToolBar_SetToolShortHelp, "wxToolBar", "setToolShortHelp", 3}, // 1007 - {wxToolBar_SetToolSeparation, "wxToolBar", "setToolSeparation", 2}, // 1008 - {wxToolBar_ToggleTool, "wxToolBar", "toggleTool", 3}, // 1009 - {wxStatusBar_new_0, "wxStatusBar", "new", 0}, // 1010 - {wxStatusBar_new_2, "wxStatusBar", "new", 2}, // 1011 - {NULL, "wxStatusBar", "destroy", 1}, // 1012 obj destructor wxStatusBar_destruct - {wxStatusBar_Create, "wxStatusBar", "create", 3}, // 1013 - {wxStatusBar_GetFieldRect, "wxStatusBar", "getFieldRect", 2}, // 1014 - {wxStatusBar_GetFieldsCount, "wxStatusBar", "getFieldsCount", 1}, // 1015 - {wxStatusBar_GetStatusText, "wxStatusBar", "getStatusText", 2}, // 1016 - {wxStatusBar_PopStatusText, "wxStatusBar", "popStatusText", 2}, // 1017 - {wxStatusBar_PushStatusText, "wxStatusBar", "pushStatusText", 3}, // 1018 - {wxStatusBar_SetFieldsCount, "wxStatusBar", "setFieldsCount", 3}, // 1019 - {wxStatusBar_SetMinHeight, "wxStatusBar", "setMinHeight", 2}, // 1020 - {wxStatusBar_SetStatusText, "wxStatusBar", "setStatusText", 3}, // 1021 - {wxStatusBar_SetStatusWidths, "wxStatusBar", "setStatusWidths", 2}, // 1022 - {wxStatusBar_SetStatusStyles, "wxStatusBar", "setStatusStyles", 2}, // 1023 - {wxBitmap_new_0, "wxBitmap", "new", 0}, // 1024 - {NULL, "", "", 0}, // 1025 - {wxBitmap_new_4, "wxBitmap", "new", 4}, // 1026 - {wxBitmap_new_3, "wxBitmap", "new", 3}, // 1027 - {wxBitmap_new_2_1, "wxBitmap", "new", 2}, // 1028 - {wxBitmap_new_2_0, "wxBitmap", "new", 2}, // 1029 - {wxBitmap_new_2_2, "wxBitmap", "new", 2}, // 1030 - {wxBitmap_new_2_3, "wxBitmap", "new", 1}, // 1031 - {NULL, "wxBitmap", "destroy", 1}, // 1032 obj destructor wxBitmap_destruct - {wxBitmap_ConvertToImage, "wxBitmap", "convertToImage", 1}, // 1033 - {wxBitmap_CopyFromIcon, "wxBitmap", "copyFromIcon", 2}, // 1034 - {wxBitmap_Create_3_0, "wxBitmap", "create", 4}, // 1035 - {wxBitmap_Create_2, "wxBitmap", "create", 3}, // 1036 - {wxBitmap_Create_3_1, "wxBitmap", "create", 4}, // 1037 - {wxBitmap_GetDepth, "wxBitmap", "getDepth", 1}, // 1038 - {wxBitmap_GetHeight, "wxBitmap", "getHeight", 1}, // 1039 - {wxBitmap_GetPalette, "wxBitmap", "getPalette", 1}, // 1040 - {wxBitmap_GetMask, "wxBitmap", "getMask", 1}, // 1041 - {wxBitmap_GetWidth, "wxBitmap", "getWidth", 1}, // 1042 - {wxBitmap_GetSubBitmap, "wxBitmap", "getSubBitmap", 2}, // 1043 - {wxBitmap_LoadFile, "wxBitmap", "loadFile", 3}, // 1044 - {wxBitmap_IsOk, "wxBitmap", "isOk", 1}, // 1045 - {wxBitmap_SaveFile, "wxBitmap", "saveFile", 4}, // 1046 - {wxBitmap_SetDepth, "wxBitmap", "setDepth", 2}, // 1047 - {wxBitmap_SetHeight, "wxBitmap", "setHeight", 2}, // 1048 - {wxBitmap_SetMask, "wxBitmap", "setMask", 2}, // 1049 - {wxBitmap_SetPalette, "wxBitmap", "setPalette", 2}, // 1050 - {wxBitmap_SetWidth, "wxBitmap", "setWidth", 2}, // 1051 - {wxIcon_new_0, "wxIcon", "new", 0}, // 1052 - {wxIcon_new_1, "wxIcon", "new", 1}, // 1053 - {wxIcon_new_2, "wxIcon", "new", 2}, // 1054 - {wxIcon_CopyFromBitmap, "wxIcon", "copyFromBitmap", 2}, // 1055 - {NULL, "wxIcon", "destroy", 1}, // 1056 obj destructor wxIcon_destruct - {wxIconBundle_new_0, "wxIconBundle", "new", 0}, // 1057 - {wxIconBundle_new_1_1, "wxIconBundle", "new", 1}, // 1058 - {wxIconBundle_new_2, "wxIconBundle", "new", 2}, // 1059 - {NULL, "", "", 0}, // 1060 - {wxIconBundle_new_1_0, "wxIconBundle", "new", 1}, // 1061 - {wxIconBundle_destruct, "wxIconBundle", "destroy", 1}, // 1062 - {wxIconBundle_AddIcon_1_0, "wxIconBundle", "addIcon", 2}, // 1063 - {wxIconBundle_AddIcon_2, "wxIconBundle", "addIcon", 3}, // 1064 - {wxIconBundle_AddIcon_1_1, "wxIconBundle", "addIcon", 2}, // 1065 - {wxIconBundle_GetIcon_2, "wxIconBundle", "getIcon", 3}, // 1066 - {wxIconBundle_GetIcon_1, "wxIconBundle", "getIcon", 2}, // 1067 - {wxCursor_new_0, "wxCursor", "new", 0}, // 1068 - {wxCursor_new_2, "wxCursor", "new", 2}, // 1069 - {wxCursor_new_1_1, "wxCursor", "new", 1}, // 1070 - {wxCursor_new_1_0, "wxCursor", "new", 1}, // 1071 - {NULL, "", "", 0}, // 1072 - {NULL, "wxCursor", "destroy", 1}, // 1073 obj destructor wxCursor_destruct - {wxCursor_IsOk, "wxCursor", "isOk", 1}, // 1074 - {wxMask_new_0, "wxMask", "new", 0}, // 1075 - {wxMask_new_2_0, "wxMask", "new", 2}, // 1076 - {wxMask_new_1, "wxMask", "new", 1}, // 1077 - {wxMask_new_2_1, "wxMask", "new", 2}, // 1078 - {NULL, "wxMask", "destroy", 1}, // 1079 obj destructor wxMask_destruct - {wxMask_Create_2_0, "wxMask", "create", 3}, // 1080 - {wxMask_Create_1, "wxMask", "create", 2}, // 1081 - {wxMask_Create_2_1, "wxMask", "create", 3}, // 1082 - {wxImage_new_0, "wxImage", "new", 0}, // 1083 - {wxImage_new_3_1, "wxImage", "new", 3}, // 1084 - {wxImage_new_2_2, "wxImage", "new", 2}, // 1085 - {wxImage_new_3_0, "wxImage", "new", 3}, // 1086 - {wxImage_new_2_1, "wxImage", "new", 2}, // 1087 - {wxImage_new_4, "wxImage", "new", 4}, // 1088 - {wxImage_new_3_3, "wxImage", "new", 3}, // 1089 - {wxImage_new_2_0, "wxImage", "new", 2}, // 1090 - {wxImage_new_3_2, "wxImage", "new", 3}, // 1091 - {NULL, "wxImage", "destroy", 1}, // 1092 obj destructor wxImage_destruct - {wxImage_Blur, "wxImage", "blur", 2}, // 1093 - {wxImage_BlurHorizontal, "wxImage", "blurHorizontal", 2}, // 1094 - {wxImage_BlurVertical, "wxImage", "blurVertical", 2}, // 1095 - {wxImage_ConvertAlphaToMask_1, "wxImage", "convertAlphaToMask", 2}, // 1096 - {wxImage_ConvertAlphaToMask_4, "wxImage", "convertAlphaToMask", 5}, // 1097 - {wxImage_ConvertToGreyscale_3, "wxImage", "convertToGreyscale", 4}, // 1098 - {wxImage_ConvertToGreyscale_0, "wxImage", "convertToGreyscale", 1}, // 1099 - {wxImage_ConvertToMono, "wxImage", "convertToMono", 4}, // 1100 - {wxImage_Copy, "wxImage", "copy", 1}, // 1101 - {wxImage_Create_3_1, "wxImage", "create", 4}, // 1102 - {wxImage_Create_2_1, "wxImage", "create", 3}, // 1103 - {wxImage_Create_3_0, "wxImage", "create", 4}, // 1104 - {wxImage_Create_2_0, "wxImage", "create", 3}, // 1105 - {wxImage_Create_4, "wxImage", "create", 5}, // 1106 - {wxImage_Create_3_2, "wxImage", "create", 4}, // 1107 - {wxImage_Destroy, "wxImage", "'Destroy'", 1}, // 1108 - {wxImage_FindFirstUnusedColour, "wxImage", "findFirstUnusedColour", 2}, // 1109 - {wxImage_GetImageExtWildcard, "wxImage", "getImageExtWildcard", 0}, // 1110 - {wxImage_GetAlpha_0, "wxImage", "getAlpha", 1}, // 1111 - {wxImage_GetAlpha_2, "wxImage", "getAlpha", 3}, // 1112 - {wxImage_GetBlue, "wxImage", "getBlue", 3}, // 1113 - {wxImage_GetData, "wxImage", "getData", 1}, // 1114 - {wxImage_GetGreen, "wxImage", "getGreen", 3}, // 1115 - {wxImage_GetImageCount, "wxImage", "getImageCount", 2}, // 1116 - {wxImage_GetHeight, "wxImage", "getHeight", 1}, // 1117 - {wxImage_GetMaskBlue, "wxImage", "getMaskBlue", 1}, // 1118 - {wxImage_GetMaskGreen, "wxImage", "getMaskGreen", 1}, // 1119 - {wxImage_GetMaskRed, "wxImage", "getMaskRed", 1}, // 1120 - {wxImage_GetOrFindMaskColour, "wxImage", "getOrFindMaskColour", 1}, // 1121 - {wxImage_GetPalette, "wxImage", "getPalette", 1}, // 1122 - {wxImage_GetRed, "wxImage", "getRed", 3}, // 1123 - {wxImage_GetSubImage, "wxImage", "getSubImage", 2}, // 1124 - {wxImage_GetWidth, "wxImage", "getWidth", 1}, // 1125 - {wxImage_HasAlpha, "wxImage", "hasAlpha", 1}, // 1126 - {wxImage_HasMask, "wxImage", "hasMask", 1}, // 1127 - {wxImage_GetOption, "wxImage", "getOption", 2}, // 1128 - {wxImage_GetOptionInt, "wxImage", "getOptionInt", 2}, // 1129 - {wxImage_HasOption, "wxImage", "hasOption", 2}, // 1130 - {wxImage_InitAlpha, "wxImage", "initAlpha", 1}, // 1131 - {wxImage_InitStandardHandlers, "wxImage", "initStandardHandlers", 0}, // 1132 - {wxImage_IsTransparent, "wxImage", "isTransparent", 4}, // 1133 - {wxImage_LoadFile_2, "wxImage", "loadFile", 3}, // 1134 - {wxImage_LoadFile_3, "wxImage", "loadFile", 4}, // 1135 - {wxImage_IsOk, "wxImage", "isOk", 1}, // 1136 - {wxImage_RemoveHandler, "wxImage", "removeHandler", 1}, // 1137 - {wxImage_Mirror, "wxImage", "mirror", 2}, // 1138 - {wxImage_Replace, "wxImage", "replace", 7}, // 1139 - {wxImage_Rescale, "wxImage", "rescale", 4}, // 1140 - {wxImage_Resize, "wxImage", "resize", 4}, // 1141 - {wxImage_Rotate, "wxImage", "rotate", 4}, // 1142 - {wxImage_RotateHue, "wxImage", "rotateHue", 2}, // 1143 - {wxImage_Rotate90, "wxImage", "rotate90", 2}, // 1144 - {wxImage_SaveFile_2_0, "wxImage", "saveFile", 3}, // 1145 - {wxImage_SaveFile_2_1, "wxImage", "saveFile", 3}, // 1146 - {wxImage_SaveFile_1, "wxImage", "saveFile", 2}, // 1147 - {wxImage_Scale, "wxImage", "scale", 4}, // 1148 - {wxImage_Size, "wxImage", "size", 4}, // 1149 - {wxImage_SetAlpha_1, "wxImage", "setAlpha", 2}, // 1150 - {wxImage_SetAlpha_3, "wxImage", "setAlpha", 4}, // 1151 - {wxImage_SetData_1, "wxImage", "setData", 2}, // 1152 - {wxImage_SetData_3, "wxImage", "setData", 4}, // 1153 - {wxImage_SetMask, "wxImage", "setMask", 2}, // 1154 - {wxImage_SetMaskColour, "wxImage", "setMaskColour", 4}, // 1155 - {wxImage_SetMaskFromImage, "wxImage", "setMaskFromImage", 5}, // 1156 - {wxImage_SetOption_2_1, "wxImage", "setOption", 3}, // 1157 - {wxImage_SetOption_2_0, "wxImage", "setOption", 3}, // 1158 - {wxImage_SetPalette, "wxImage", "setPalette", 2}, // 1159 - {wxImage_SetRGB_5, "wxImage", "setRGB", 6}, // 1160 - {wxImage_SetRGB_4, "wxImage", "setRGB", 5}, // 1161 - {wxBrush_new_0, "wxBrush", "new", 0}, // 1162 - {wxBrush_new_2, "wxBrush", "new", 2}, // 1163 - {NULL, "", "", 0}, // 1164 - {wxBrush_new_1, "wxBrush", "new", 1}, // 1165 - {NULL, "wxBrush", "destroy", 1}, // 1166 obj destructor wxBrush_destruct - {wxBrush_GetColour, "wxBrush", "getColour", 1}, // 1167 - {wxBrush_GetStipple, "wxBrush", "getStipple", 1}, // 1168 - {wxBrush_GetStyle, "wxBrush", "getStyle", 1}, // 1169 - {wxBrush_IsHatch, "wxBrush", "isHatch", 1}, // 1170 - {wxBrush_IsOk, "wxBrush", "isOk", 1}, // 1171 - {wxBrush_SetColour_1, "wxBrush", "setColour", 2}, // 1172 - {wxBrush_SetColour_3, "wxBrush", "setColour", 4}, // 1173 - {wxBrush_SetStipple, "wxBrush", "setStipple", 2}, // 1174 - {wxBrush_SetStyle, "wxBrush", "setStyle", 2}, // 1175 - {wxPen_new_0, "wxPen", "new", 0}, // 1176 - {wxPen_new_2, "wxPen", "new", 2}, // 1177 - {wxPen_new_1, "wxPen", "new", 1}, // 1178 - {NULL, "wxPen", "destroy", 1}, // 1179 obj destructor wxPen_destruct - {wxPen_GetCap, "wxPen", "getCap", 1}, // 1180 - {wxPen_GetColour, "wxPen", "getColour", 1}, // 1181 - {wxPen_GetJoin, "wxPen", "getJoin", 1}, // 1182 - {wxPen_GetStyle, "wxPen", "getStyle", 1}, // 1183 - {wxPen_GetWidth, "wxPen", "getWidth", 1}, // 1184 - {wxPen_IsOk, "wxPen", "isOk", 1}, // 1185 - {wxPen_SetCap, "wxPen", "setCap", 2}, // 1186 - {wxPen_SetColour_1, "wxPen", "setColour", 2}, // 1187 - {wxPen_SetColour_3, "wxPen", "setColour", 4}, // 1188 - {wxPen_SetJoin, "wxPen", "setJoin", 2}, // 1189 - {wxPen_SetStyle, "wxPen", "setStyle", 2}, // 1190 - {wxPen_SetWidth, "wxPen", "setWidth", 2}, // 1191 - {wxRegion_new_0, "wxRegion", "new", 0}, // 1192 - {wxRegion_new_4, "wxRegion", "new", 4}, // 1193 - {wxRegion_new_2, "wxRegion", "new", 2}, // 1194 - {wxRegion_new_1_0, "wxRegion", "new", 1}, // 1195 - {NULL, "", "", 0}, // 1196 - {wxRegion_new_1_1, "wxRegion", "new", 1}, // 1197 +#if defined(__WXMAC__) + {wxMenuBar_MacGetCommonMenuBar, "wxMenuBar", "macGetCommonMenuBar", 0}, // 874 +#else + {NULL, "wxMenuBar", "macGetCommonMenuBar", 0}, // 874 +#endif // defined(__WXMAC__) +#if defined(__WXMAC__) + {wxMenuBar_MacSetCommonMenuBar, "wxMenuBar", "macSetCommonMenuBar", 1}, // 875 +#else + {NULL, "wxMenuBar", "macSetCommonMenuBar", 0}, // 875 +#endif // defined(__WXMAC__) + {wxMenuBar_IsEnabled, "wxMenuBar", "isEnabled", 2}, // 876 + {wxMenuBar_Remove, "wxMenuBar", "remove", 2}, // 877 + {wxMenuBar_Replace, "wxMenuBar", "replace", 4}, // 878 + {wxMenuBar_SetHelpString, "wxMenuBar", "setHelpString", 3}, // 879 + {wxMenuBar_SetLabel, "wxMenuBar", "setLabel", 3}, // 880 + {wxMenuBar_SetMenuLabel, "wxMenuBar", "setMenuLabel", 3}, // 881 + {wxControl_GetLabel, "wxControl", "getLabel", 1}, // 882 + {wxControl_SetLabel, "wxControl", "setLabel", 2}, // 883 + {wxControlWithItems_Append_1, "wxControlWithItems", "append", 2}, // 884 + {wxControlWithItems_Append_2, "wxControlWithItems", "append", 3}, // 885 + {wxControlWithItems_appendStrings_1, "wxControlWithItems", "appendStrings", 2}, // 886 + {wxControlWithItems_appendStrings_2, "wxControlWithItems", "appendStrings", 3}, // 887 + {wxControlWithItems_Clear, "wxControlWithItems", "clear", 1}, // 888 + {wxControlWithItems_Delete, "wxControlWithItems", "delete", 2}, // 889 + {wxControlWithItems_FindString, "wxControlWithItems", "findString", 3}, // 890 + {wxControlWithItems_getClientData, "wxControlWithItems", "getClientData", 2}, // 891 + {wxControlWithItems_setClientData, "wxControlWithItems", "setClientData", 3}, // 892 + {wxControlWithItems_GetCount, "wxControlWithItems", "getCount", 1}, // 893 + {wxControlWithItems_GetSelection, "wxControlWithItems", "getSelection", 1}, // 894 + {wxControlWithItems_GetString, "wxControlWithItems", "getString", 2}, // 895 + {wxControlWithItems_GetStringSelection, "wxControlWithItems", "getStringSelection", 1}, // 896 + {wxControlWithItems_Insert_2, "wxControlWithItems", "insert", 3}, // 897 + {wxControlWithItems_Insert_3, "wxControlWithItems", "insert", 4}, // 898 + {wxControlWithItems_insertStrings_2, "wxControlWithItems", "insertStrings", 3}, // 899 + {wxControlWithItems_insertStrings_3, "wxControlWithItems", "insertStrings", 4}, // 900 + {wxControlWithItems_IsEmpty, "wxControlWithItems", "isEmpty", 1}, // 901 + {wxControlWithItems_Select, "wxControlWithItems", "select", 2}, // 902 + {wxControlWithItems_SetSelection, "wxControlWithItems", "setSelection", 2}, // 903 + {wxControlWithItems_SetString, "wxControlWithItems", "setString", 3}, // 904 + {wxControlWithItems_SetStringSelection, "wxControlWithItems", "setStringSelection", 2}, // 905 + {wxMenu_new_0, "wxMenu", "new", 0}, // 906 + {wxMenu_new_1, "wxMenu", "new", 1}, // 907 + {wxMenu_new_2, "wxMenu", "new", 2}, // 908 + {NULL, "wxMenu", "destroy", 1}, // 909 obj destructor wxMenu_destruct + {wxMenu_Append_3, "wxMenu", "append", 4}, // 910 + {wxMenu_Append_4, "wxMenu", "append", 5}, // 911 + {wxMenu_Append_1, "wxMenu", "append", 2}, // 912 + {wxMenu_AppendCheckItem, "wxMenu", "appendCheckItem", 4}, // 913 + {wxMenu_AppendRadioItem, "wxMenu", "appendRadioItem", 4}, // 914 + {wxMenu_AppendSeparator, "wxMenu", "appendSeparator", 1}, // 915 + {wxMenu_Break, "wxMenu", "break", 1}, // 916 + {wxMenu_Check, "wxMenu", "check", 3}, // 917 + {wxMenu_Delete_1_0, "wxMenu", "delete", 2}, // 918 + {wxMenu_Delete_1_1, "wxMenu", "delete", 2}, // 919 + {wxMenu_Destroy_1_0, "wxMenu", "'Destroy'", 2}, // 920 + {wxMenu_Destroy_1_1, "wxMenu", "'Destroy'", 2}, // 921 + {wxMenu_Enable, "wxMenu", "enable", 3}, // 922 + {wxMenu_FindItem_1, "wxMenu", "findItem", 2}, // 923 + {wxMenu_FindItem_2, "wxMenu", "findItem", 2}, // 924 + {wxMenu_FindItemByPosition, "wxMenu", "findItemByPosition", 2}, // 925 + {wxMenu_GetHelpString, "wxMenu", "getHelpString", 2}, // 926 + {wxMenu_GetLabel, "wxMenu", "getLabel", 2}, // 927 + {wxMenu_GetMenuItemCount, "wxMenu", "getMenuItemCount", 1}, // 928 + {NULL, "", "", 0}, // 929 + {wxMenu_GetMenuItems, "wxMenu", "getMenuItems", 1}, // 930 + {wxMenu_GetTitle, "wxMenu", "getTitle", 1}, // 931 + {wxMenu_Insert_2, "wxMenu", "insert", 3}, // 932 + {wxMenu_Insert_3, "wxMenu", "insert", 4}, // 933 + {wxMenu_Insert_5, "wxMenu", "insert", 6}, // 934 + {wxMenu_InsertCheckItem, "wxMenu", "insertCheckItem", 5}, // 935 + {wxMenu_InsertRadioItem, "wxMenu", "insertRadioItem", 5}, // 936 + {wxMenu_InsertSeparator, "wxMenu", "insertSeparator", 2}, // 937 + {wxMenu_IsChecked, "wxMenu", "isChecked", 2}, // 938 + {wxMenu_IsEnabled, "wxMenu", "isEnabled", 2}, // 939 + {wxMenu_Prepend_1, "wxMenu", "prepend", 2}, // 940 + {wxMenu_Prepend_2, "wxMenu", "prepend", 3}, // 941 + {wxMenu_Prepend_4, "wxMenu", "prepend", 5}, // 942 + {wxMenu_PrependCheckItem, "wxMenu", "prependCheckItem", 4}, // 943 + {wxMenu_PrependRadioItem, "wxMenu", "prependRadioItem", 4}, // 944 + {wxMenu_PrependSeparator, "wxMenu", "prependSeparator", 1}, // 945 + {wxMenu_Remove_1_0, "wxMenu", "remove", 2}, // 946 + {wxMenu_Remove_1_1, "wxMenu", "remove", 2}, // 947 + {wxMenu_SetHelpString, "wxMenu", "setHelpString", 3}, // 948 + {wxMenu_SetLabel, "wxMenu", "setLabel", 3}, // 949 + {wxMenu_SetTitle, "wxMenu", "setTitle", 2}, // 950 + {wxMenuItem_new, "wxMenuItem", "new", 1}, // 951 + {NULL, "wxMenuItem", "destroy", 1}, // 952 obj destructor wxMenuItem_destruct + {wxMenuItem_Check, "wxMenuItem", "check", 2}, // 953 + {wxMenuItem_Enable, "wxMenuItem", "enable", 2}, // 954 + {wxMenuItem_GetBitmap, "wxMenuItem", "getBitmap", 1}, // 955 + {wxMenuItem_GetHelp, "wxMenuItem", "getHelp", 1}, // 956 + {wxMenuItem_GetId, "wxMenuItem", "getId", 1}, // 957 + {wxMenuItem_GetKind, "wxMenuItem", "getKind", 1}, // 958 + {wxMenuItem_GetLabelText, "wxMenuItem", "getLabelText", 1}, // 959 + {wxMenuItem_GetItemLabel, "wxMenuItem", "getItemLabel", 1}, // 960 + {wxMenuItem_GetItemLabelText, "wxMenuItem", "getItemLabelText", 1}, // 961 + {wxMenuItem_GetMenu, "wxMenuItem", "getMenu", 1}, // 962 + {wxMenuItem_GetSubMenu, "wxMenuItem", "getSubMenu", 1}, // 963 + {wxMenuItem_IsCheckable, "wxMenuItem", "isCheckable", 1}, // 964 + {wxMenuItem_IsChecked, "wxMenuItem", "isChecked", 1}, // 965 + {wxMenuItem_IsEnabled, "wxMenuItem", "isEnabled", 1}, // 966 + {wxMenuItem_IsSeparator, "wxMenuItem", "isSeparator", 1}, // 967 + {wxMenuItem_IsSubMenu, "wxMenuItem", "isSubMenu", 1}, // 968 + {wxMenuItem_SetBitmap, "wxMenuItem", "setBitmap", 2}, // 969 + {wxMenuItem_SetHelp, "wxMenuItem", "setHelp", 2}, // 970 + {wxMenuItem_SetMenu, "wxMenuItem", "setMenu", 2}, // 971 + {wxMenuItem_SetSubMenu, "wxMenuItem", "setSubMenu", 2}, // 972 + {wxMenuItem_SetItemLabel, "wxMenuItem", "setItemLabel", 2}, // 973 + {wxToolBar_AddControl, "wxToolBar", "addControl", 3}, // 974 + {wxToolBar_AddSeparator, "wxToolBar", "addSeparator", 1}, // 975 + {wxToolBar_AddTool_1, "wxToolBar", "addTool", 2}, // 976 + {wxToolBar_AddTool_4, "wxToolBar", "addTool", 5}, // 977 + {wxToolBar_AddTool_5, "wxToolBar", "addTool", 6}, // 978 + {wxToolBar_AddCheckTool, "wxToolBar", "addCheckTool", 5}, // 979 + {wxToolBar_AddRadioTool, "wxToolBar", "addRadioTool", 5}, // 980 + {wxToolBar_AddStretchableSpace, "wxToolBar", "addStretchableSpace", 1}, // 981 + {wxToolBar_InsertStretchableSpace, "wxToolBar", "insertStretchableSpace", 2}, // 982 + {wxToolBar_DeleteTool, "wxToolBar", "deleteTool", 2}, // 983 + {wxToolBar_DeleteToolByPos, "wxToolBar", "deleteToolByPos", 2}, // 984 + {wxToolBar_EnableTool, "wxToolBar", "enableTool", 3}, // 985 + {wxToolBar_FindById, "wxToolBar", "findById", 2}, // 986 + {wxToolBar_FindControl, "wxToolBar", "findControl", 2}, // 987 + {wxToolBar_FindToolForPosition, "wxToolBar", "findToolForPosition", 3}, // 988 + {wxToolBar_GetToolSize, "wxToolBar", "getToolSize", 1}, // 989 + {wxToolBar_GetToolBitmapSize, "wxToolBar", "getToolBitmapSize", 1}, // 990 + {wxToolBar_GetMargins, "wxToolBar", "getMargins", 1}, // 991 + {wxToolBar_GetToolEnabled, "wxToolBar", "getToolEnabled", 2}, // 992 + {wxToolBar_GetToolLongHelp, "wxToolBar", "getToolLongHelp", 2}, // 993 + {wxToolBar_GetToolPacking, "wxToolBar", "getToolPacking", 1}, // 994 + {wxToolBar_GetToolPos, "wxToolBar", "getToolPos", 2}, // 995 + {wxToolBar_GetToolSeparation, "wxToolBar", "getToolSeparation", 1}, // 996 + {wxToolBar_GetToolShortHelp, "wxToolBar", "getToolShortHelp", 2}, // 997 + {wxToolBar_GetToolState, "wxToolBar", "getToolState", 2}, // 998 + {wxToolBar_InsertControl, "wxToolBar", "insertControl", 4}, // 999 + {wxToolBar_InsertSeparator, "wxToolBar", "insertSeparator", 2}, // 1000 + {wxToolBar_InsertTool_5, "wxToolBar", "insertTool", 6}, // 1001 + {wxToolBar_InsertTool_2, "wxToolBar", "insertTool", 3}, // 1002 + {wxToolBar_Realize, "wxToolBar", "realize", 1}, // 1003 + {wxToolBar_RemoveTool, "wxToolBar", "removeTool", 2}, // 1004 + {wxToolBar_SetMargins, "wxToolBar", "setMargins", 3}, // 1005 + {wxToolBar_SetToolBitmapSize, "wxToolBar", "setToolBitmapSize", 2}, // 1006 + {wxToolBar_SetToolLongHelp, "wxToolBar", "setToolLongHelp", 3}, // 1007 + {wxToolBar_SetToolPacking, "wxToolBar", "setToolPacking", 2}, // 1008 + {wxToolBar_SetToolShortHelp, "wxToolBar", "setToolShortHelp", 3}, // 1009 + {wxToolBar_SetToolSeparation, "wxToolBar", "setToolSeparation", 2}, // 1010 + {wxToolBar_ToggleTool, "wxToolBar", "toggleTool", 3}, // 1011 + {wxStatusBar_new_0, "wxStatusBar", "new", 0}, // 1012 + {wxStatusBar_new_2, "wxStatusBar", "new", 2}, // 1013 + {NULL, "wxStatusBar", "destroy", 1}, // 1014 obj destructor wxStatusBar_destruct + {wxStatusBar_Create, "wxStatusBar", "create", 3}, // 1015 + {wxStatusBar_GetFieldRect, "wxStatusBar", "getFieldRect", 2}, // 1016 + {wxStatusBar_GetFieldsCount, "wxStatusBar", "getFieldsCount", 1}, // 1017 + {wxStatusBar_GetStatusText, "wxStatusBar", "getStatusText", 2}, // 1018 + {wxStatusBar_PopStatusText, "wxStatusBar", "popStatusText", 2}, // 1019 + {wxStatusBar_PushStatusText, "wxStatusBar", "pushStatusText", 3}, // 1020 + {wxStatusBar_SetFieldsCount, "wxStatusBar", "setFieldsCount", 3}, // 1021 + {wxStatusBar_SetMinHeight, "wxStatusBar", "setMinHeight", 2}, // 1022 + {wxStatusBar_SetStatusText, "wxStatusBar", "setStatusText", 3}, // 1023 + {wxStatusBar_SetStatusWidths, "wxStatusBar", "setStatusWidths", 2}, // 1024 + {wxStatusBar_SetStatusStyles, "wxStatusBar", "setStatusStyles", 2}, // 1025 + {wxBitmap_new_0, "wxBitmap", "new", 0}, // 1026 + {NULL, "", "", 0}, // 1027 + {wxBitmap_new_4, "wxBitmap", "new", 4}, // 1028 + {wxBitmap_new_3, "wxBitmap", "new", 3}, // 1029 + {wxBitmap_new_2_1, "wxBitmap", "new", 2}, // 1030 + {wxBitmap_new_2_0, "wxBitmap", "new", 2}, // 1031 + {wxBitmap_new_2_2, "wxBitmap", "new", 2}, // 1032 + {wxBitmap_new_2_3, "wxBitmap", "new", 1}, // 1033 + {NULL, "wxBitmap", "destroy", 1}, // 1034 obj destructor wxBitmap_destruct + {wxBitmap_ConvertToImage, "wxBitmap", "convertToImage", 1}, // 1035 + {wxBitmap_CopyFromIcon, "wxBitmap", "copyFromIcon", 2}, // 1036 + {wxBitmap_Create_3_0, "wxBitmap", "create", 4}, // 1037 + {wxBitmap_Create_2, "wxBitmap", "create", 3}, // 1038 + {wxBitmap_Create_3_1, "wxBitmap", "create", 4}, // 1039 + {wxBitmap_GetDepth, "wxBitmap", "getDepth", 1}, // 1040 + {wxBitmap_GetHeight, "wxBitmap", "getHeight", 1}, // 1041 + {wxBitmap_GetPalette, "wxBitmap", "getPalette", 1}, // 1042 + {wxBitmap_GetMask, "wxBitmap", "getMask", 1}, // 1043 + {wxBitmap_GetWidth, "wxBitmap", "getWidth", 1}, // 1044 + {wxBitmap_GetSubBitmap, "wxBitmap", "getSubBitmap", 2}, // 1045 + {wxBitmap_LoadFile, "wxBitmap", "loadFile", 3}, // 1046 + {wxBitmap_IsOk, "wxBitmap", "isOk", 1}, // 1047 + {wxBitmap_SaveFile, "wxBitmap", "saveFile", 4}, // 1048 + {wxBitmap_SetDepth, "wxBitmap", "setDepth", 2}, // 1049 + {wxBitmap_SetHeight, "wxBitmap", "setHeight", 2}, // 1050 + {wxBitmap_SetMask, "wxBitmap", "setMask", 2}, // 1051 + {wxBitmap_SetPalette, "wxBitmap", "setPalette", 2}, // 1052 + {wxBitmap_SetWidth, "wxBitmap", "setWidth", 2}, // 1053 + {wxIcon_new_0, "wxIcon", "new", 0}, // 1054 + {wxIcon_new_1, "wxIcon", "new", 1}, // 1055 + {wxIcon_new_2, "wxIcon", "new", 2}, // 1056 + {wxIcon_CopyFromBitmap, "wxIcon", "copyFromBitmap", 2}, // 1057 + {NULL, "wxIcon", "destroy", 1}, // 1058 obj destructor wxIcon_destruct + {wxIconBundle_new_0, "wxIconBundle", "new", 0}, // 1059 + {wxIconBundle_new_1_1, "wxIconBundle", "new", 1}, // 1060 + {wxIconBundle_new_2, "wxIconBundle", "new", 2}, // 1061 + {NULL, "", "", 0}, // 1062 + {wxIconBundle_new_1_0, "wxIconBundle", "new", 1}, // 1063 + {wxIconBundle_destruct, "wxIconBundle", "destroy", 1}, // 1064 + {wxIconBundle_AddIcon_1_0, "wxIconBundle", "addIcon", 2}, // 1065 + {wxIconBundle_AddIcon_2, "wxIconBundle", "addIcon", 3}, // 1066 + {wxIconBundle_AddIcon_1_1, "wxIconBundle", "addIcon", 2}, // 1067 + {wxIconBundle_GetIcon_2, "wxIconBundle", "getIcon", 3}, // 1068 + {wxIconBundle_GetIcon_1, "wxIconBundle", "getIcon", 2}, // 1069 + {wxCursor_new_0, "wxCursor", "new", 0}, // 1070 + {wxCursor_new_2, "wxCursor", "new", 2}, // 1071 + {wxCursor_new_1_1, "wxCursor", "new", 1}, // 1072 + {wxCursor_new_1_0, "wxCursor", "new", 1}, // 1073 + {NULL, "", "", 0}, // 1074 + {NULL, "wxCursor", "destroy", 1}, // 1075 obj destructor wxCursor_destruct + {wxCursor_IsOk, "wxCursor", "isOk", 1}, // 1076 + {wxMask_new_0, "wxMask", "new", 0}, // 1077 + {wxMask_new_2_0, "wxMask", "new", 2}, // 1078 + {wxMask_new_1, "wxMask", "new", 1}, // 1079 + {wxMask_new_2_1, "wxMask", "new", 2}, // 1080 + {NULL, "wxMask", "destroy", 1}, // 1081 obj destructor wxMask_destruct + {wxMask_Create_2_0, "wxMask", "create", 3}, // 1082 + {wxMask_Create_1, "wxMask", "create", 2}, // 1083 + {wxMask_Create_2_1, "wxMask", "create", 3}, // 1084 + {wxImage_new_0, "wxImage", "new", 0}, // 1085 + {wxImage_new_3_1, "wxImage", "new", 3}, // 1086 + {wxImage_new_2_2, "wxImage", "new", 2}, // 1087 + {wxImage_new_3_0, "wxImage", "new", 3}, // 1088 + {wxImage_new_2_1, "wxImage", "new", 2}, // 1089 + {wxImage_new_4, "wxImage", "new", 4}, // 1090 + {wxImage_new_3_3, "wxImage", "new", 3}, // 1091 + {wxImage_new_2_0, "wxImage", "new", 2}, // 1092 + {wxImage_new_3_2, "wxImage", "new", 3}, // 1093 + {NULL, "wxImage", "destroy", 1}, // 1094 obj destructor wxImage_destruct + {wxImage_Blur, "wxImage", "blur", 2}, // 1095 + {wxImage_BlurHorizontal, "wxImage", "blurHorizontal", 2}, // 1096 + {wxImage_BlurVertical, "wxImage", "blurVertical", 2}, // 1097 + {wxImage_ConvertAlphaToMask_1, "wxImage", "convertAlphaToMask", 2}, // 1098 + {wxImage_ConvertAlphaToMask_4, "wxImage", "convertAlphaToMask", 5}, // 1099 + {wxImage_ConvertToGreyscale_3, "wxImage", "convertToGreyscale", 4}, // 1100 + {wxImage_ConvertToGreyscale_0, "wxImage", "convertToGreyscale", 1}, // 1101 + {wxImage_ConvertToMono, "wxImage", "convertToMono", 4}, // 1102 + {wxImage_Copy, "wxImage", "copy", 1}, // 1103 + {wxImage_Create_3_1, "wxImage", "create", 4}, // 1104 + {wxImage_Create_2_1, "wxImage", "create", 3}, // 1105 + {wxImage_Create_3_0, "wxImage", "create", 4}, // 1106 + {wxImage_Create_2_0, "wxImage", "create", 3}, // 1107 + {wxImage_Create_4, "wxImage", "create", 5}, // 1108 + {wxImage_Create_3_2, "wxImage", "create", 4}, // 1109 + {wxImage_Destroy, "wxImage", "'Destroy'", 1}, // 1110 + {wxImage_FindFirstUnusedColour, "wxImage", "findFirstUnusedColour", 2}, // 1111 + {wxImage_GetImageExtWildcard, "wxImage", "getImageExtWildcard", 0}, // 1112 + {wxImage_GetAlpha_0, "wxImage", "getAlpha", 1}, // 1113 + {wxImage_GetAlpha_2, "wxImage", "getAlpha", 3}, // 1114 + {wxImage_GetBlue, "wxImage", "getBlue", 3}, // 1115 + {wxImage_GetData, "wxImage", "getData", 1}, // 1116 + {wxImage_GetGreen, "wxImage", "getGreen", 3}, // 1117 + {wxImage_GetImageCount, "wxImage", "getImageCount", 2}, // 1118 + {wxImage_GetHeight, "wxImage", "getHeight", 1}, // 1119 + {wxImage_GetMaskBlue, "wxImage", "getMaskBlue", 1}, // 1120 + {wxImage_GetMaskGreen, "wxImage", "getMaskGreen", 1}, // 1121 + {wxImage_GetMaskRed, "wxImage", "getMaskRed", 1}, // 1122 + {wxImage_GetOrFindMaskColour, "wxImage", "getOrFindMaskColour", 1}, // 1123 + {wxImage_GetPalette, "wxImage", "getPalette", 1}, // 1124 + {wxImage_GetRed, "wxImage", "getRed", 3}, // 1125 + {wxImage_GetSubImage, "wxImage", "getSubImage", 2}, // 1126 + {wxImage_GetWidth, "wxImage", "getWidth", 1}, // 1127 + {wxImage_HasAlpha, "wxImage", "hasAlpha", 1}, // 1128 + {wxImage_HasMask, "wxImage", "hasMask", 1}, // 1129 + {wxImage_GetOption, "wxImage", "getOption", 2}, // 1130 + {wxImage_GetOptionInt, "wxImage", "getOptionInt", 2}, // 1131 + {wxImage_HasOption, "wxImage", "hasOption", 2}, // 1132 + {wxImage_InitAlpha, "wxImage", "initAlpha", 1}, // 1133 + {wxImage_InitStandardHandlers, "wxImage", "initStandardHandlers", 0}, // 1134 + {wxImage_IsTransparent, "wxImage", "isTransparent", 4}, // 1135 + {wxImage_LoadFile_2, "wxImage", "loadFile", 3}, // 1136 + {wxImage_LoadFile_3, "wxImage", "loadFile", 4}, // 1137 + {wxImage_IsOk, "wxImage", "isOk", 1}, // 1138 + {wxImage_RemoveHandler, "wxImage", "removeHandler", 1}, // 1139 + {wxImage_Mirror, "wxImage", "mirror", 2}, // 1140 + {wxImage_Replace, "wxImage", "replace", 7}, // 1141 + {wxImage_Rescale, "wxImage", "rescale", 4}, // 1142 + {wxImage_Resize, "wxImage", "resize", 4}, // 1143 + {wxImage_Rotate, "wxImage", "rotate", 4}, // 1144 + {wxImage_RotateHue, "wxImage", "rotateHue", 2}, // 1145 + {wxImage_Rotate90, "wxImage", "rotate90", 2}, // 1146 + {wxImage_SaveFile_2_0, "wxImage", "saveFile", 3}, // 1147 + {wxImage_SaveFile_2_1, "wxImage", "saveFile", 3}, // 1148 + {wxImage_SaveFile_1, "wxImage", "saveFile", 2}, // 1149 + {wxImage_Scale, "wxImage", "scale", 4}, // 1150 + {wxImage_Size, "wxImage", "size", 4}, // 1151 + {wxImage_SetAlpha_1, "wxImage", "setAlpha", 2}, // 1152 + {wxImage_SetAlpha_3, "wxImage", "setAlpha", 4}, // 1153 + {wxImage_SetData_1, "wxImage", "setData", 2}, // 1154 + {wxImage_SetData_3, "wxImage", "setData", 4}, // 1155 + {wxImage_SetMask, "wxImage", "setMask", 2}, // 1156 + {wxImage_SetMaskColour, "wxImage", "setMaskColour", 4}, // 1157 + {wxImage_SetMaskFromImage, "wxImage", "setMaskFromImage", 5}, // 1158 + {wxImage_SetOption_2_1, "wxImage", "setOption", 3}, // 1159 + {wxImage_SetOption_2_0, "wxImage", "setOption", 3}, // 1160 + {wxImage_SetPalette, "wxImage", "setPalette", 2}, // 1161 + {wxImage_SetRGB_5, "wxImage", "setRGB", 6}, // 1162 + {wxImage_SetRGB_4, "wxImage", "setRGB", 5}, // 1163 + {wxBrush_new_0, "wxBrush", "new", 0}, // 1164 + {wxBrush_new_2, "wxBrush", "new", 2}, // 1165 + {NULL, "", "", 0}, // 1166 + {wxBrush_new_1, "wxBrush", "new", 1}, // 1167 + {NULL, "wxBrush", "destroy", 1}, // 1168 obj destructor wxBrush_destruct + {wxBrush_GetColour, "wxBrush", "getColour", 1}, // 1169 + {wxBrush_GetStipple, "wxBrush", "getStipple", 1}, // 1170 + {wxBrush_GetStyle, "wxBrush", "getStyle", 1}, // 1171 + {wxBrush_IsHatch, "wxBrush", "isHatch", 1}, // 1172 + {wxBrush_IsOk, "wxBrush", "isOk", 1}, // 1173 + {wxBrush_SetColour_1, "wxBrush", "setColour", 2}, // 1174 + {wxBrush_SetColour_3, "wxBrush", "setColour", 4}, // 1175 + {wxBrush_SetStipple, "wxBrush", "setStipple", 2}, // 1176 + {wxBrush_SetStyle, "wxBrush", "setStyle", 2}, // 1177 + {wxPen_new_0, "wxPen", "new", 0}, // 1178 + {wxPen_new_2, "wxPen", "new", 2}, // 1179 + {wxPen_new_1, "wxPen", "new", 1}, // 1180 + {NULL, "wxPen", "destroy", 1}, // 1181 obj destructor wxPen_destruct + {wxPen_GetCap, "wxPen", "getCap", 1}, // 1182 + {wxPen_GetColour, "wxPen", "getColour", 1}, // 1183 + {wxPen_GetJoin, "wxPen", "getJoin", 1}, // 1184 + {wxPen_GetStyle, "wxPen", "getStyle", 1}, // 1185 + {wxPen_GetWidth, "wxPen", "getWidth", 1}, // 1186 + {wxPen_IsOk, "wxPen", "isOk", 1}, // 1187 + {wxPen_SetCap, "wxPen", "setCap", 2}, // 1188 + {wxPen_SetColour_1, "wxPen", "setColour", 2}, // 1189 + {wxPen_SetColour_3, "wxPen", "setColour", 4}, // 1190 + {wxPen_SetJoin, "wxPen", "setJoin", 2}, // 1191 + {wxPen_SetStyle, "wxPen", "setStyle", 2}, // 1192 + {wxPen_SetWidth, "wxPen", "setWidth", 2}, // 1193 + {wxRegion_new_0, "wxRegion", "new", 0}, // 1194 + {wxRegion_new_4, "wxRegion", "new", 4}, // 1195 + {wxRegion_new_2, "wxRegion", "new", 2}, // 1196 + {wxRegion_new_1_0, "wxRegion", "new", 1}, // 1197 {NULL, "", "", 0}, // 1198 - {NULL, "wxRegion", "destroy", 1}, // 1199 obj destructor wxRegion_destruct - {wxRegion_Clear, "wxRegion", "clear", 1}, // 1200 - {wxRegion_Contains_2, "wxRegion", "contains", 3}, // 1201 - {wxRegion_Contains_1_0, "wxRegion", "contains", 2}, // 1202 - {wxRegion_Contains_4, "wxRegion", "contains", 5}, // 1203 - {wxRegion_Contains_1_1, "wxRegion", "contains", 2}, // 1204 - {wxRegion_ConvertToBitmap, "wxRegion", "convertToBitmap", 1}, // 1205 - {wxRegion_GetBox, "wxRegion", "getBox", 1}, // 1206 - {wxRegion_Intersect_4, "wxRegion", "intersect", 5}, // 1207 - {wxRegion_Intersect_1_0, "wxRegion", "intersect", 2}, // 1208 - {wxRegion_Intersect_1_1, "wxRegion", "intersect", 2}, // 1209 - {wxRegion_IsEmpty, "wxRegion", "isEmpty", 1}, // 1210 - {wxRegion_Subtract_1_0, "wxRegion", "subtract", 2}, // 1211 - {wxRegion_Subtract_1_1, "wxRegion", "subtract", 2}, // 1212 - {wxRegion_Offset_2, "wxRegion", "offset", 3}, // 1213 - {wxRegion_Offset_1, "wxRegion", "offset", 2}, // 1214 - {wxRegion_Union_4, "wxRegion", "union", 5}, // 1215 - {wxRegion_Union_1_1, "wxRegion", "union", 2}, // 1216 - {wxRegion_Union_1_0, "wxRegion", "union", 2}, // 1217 - {NULL, "", "", 0}, // 1218 - {wxRegion_Union_3, "wxRegion", "union", 4}, // 1219 - {wxRegion_Xor_4, "wxRegion", "'Xor'", 5}, // 1220 - {wxRegion_Xor_1_0, "wxRegion", "'Xor'", 2}, // 1221 - {wxRegion_Xor_1_1, "wxRegion", "'Xor'", 2}, // 1222 - {wxAcceleratorTable_new_0, "wxAcceleratorTable", "new", 0}, // 1223 - {wxAcceleratorTable_new_2, "wxAcceleratorTable", "new", 2}, // 1224 - {NULL, "", "", 0}, // 1225 - {NULL, "wxAcceleratorTable", "destroy", 1}, // 1226 obj destructor wxAcceleratorTable_destruct - {wxAcceleratorTable_IsOk, "wxAcceleratorTable", "isOk", 1}, // 1227 - {wxAcceleratorEntry_new_1_0, "wxAcceleratorEntry", "new", 1}, // 1228 - {wxAcceleratorEntry_new_1_1, "wxAcceleratorEntry", "new", 1}, // 1229 - {wxAcceleratorEntry_GetCommand, "wxAcceleratorEntry", "getCommand", 1}, // 1230 - {wxAcceleratorEntry_GetFlags, "wxAcceleratorEntry", "getFlags", 1}, // 1231 - {wxAcceleratorEntry_GetKeyCode, "wxAcceleratorEntry", "getKeyCode", 1}, // 1232 - {wxAcceleratorEntry_Set, "wxAcceleratorEntry", "set", 5}, // 1233 - {wxAcceleratorEntry_destroy, "wxAcceleratorEntry", "'Destroy'", 1}, // 1234 - {NULL, "", "", 0}, // 1235 - {wxCaret_new_3, "wxCaret", "new", 3}, // 1236 - {wxCaret_new_2, "wxCaret", "new", 2}, // 1237 - {wxCaret_Create_3, "wxCaret", "create", 4}, // 1238 - {wxCaret_Create_2, "wxCaret", "create", 3}, // 1239 - {wxCaret_GetBlinkTime, "wxCaret", "getBlinkTime", 0}, // 1240 - {NULL, "", "", 0}, // 1241 - {wxCaret_GetPosition, "wxCaret", "getPosition", 1}, // 1242 + {wxRegion_new_1_1, "wxRegion", "new", 1}, // 1199 + {NULL, "", "", 0}, // 1200 + {NULL, "wxRegion", "destroy", 1}, // 1201 obj destructor wxRegion_destruct + {wxRegion_Clear, "wxRegion", "clear", 1}, // 1202 + {wxRegion_Contains_2, "wxRegion", "contains", 3}, // 1203 + {wxRegion_Contains_1_0, "wxRegion", "contains", 2}, // 1204 + {wxRegion_Contains_4, "wxRegion", "contains", 5}, // 1205 + {wxRegion_Contains_1_1, "wxRegion", "contains", 2}, // 1206 + {wxRegion_ConvertToBitmap, "wxRegion", "convertToBitmap", 1}, // 1207 + {wxRegion_GetBox, "wxRegion", "getBox", 1}, // 1208 + {wxRegion_Intersect_4, "wxRegion", "intersect", 5}, // 1209 + {wxRegion_Intersect_1_0, "wxRegion", "intersect", 2}, // 1210 + {wxRegion_Intersect_1_1, "wxRegion", "intersect", 2}, // 1211 + {wxRegion_IsEmpty, "wxRegion", "isEmpty", 1}, // 1212 + {wxRegion_Subtract_1_0, "wxRegion", "subtract", 2}, // 1213 + {wxRegion_Subtract_1_1, "wxRegion", "subtract", 2}, // 1214 + {wxRegion_Offset_2, "wxRegion", "offset", 3}, // 1215 + {wxRegion_Offset_1, "wxRegion", "offset", 2}, // 1216 + {wxRegion_Union_4, "wxRegion", "union", 5}, // 1217 + {wxRegion_Union_1_1, "wxRegion", "union", 2}, // 1218 + {wxRegion_Union_1_0, "wxRegion", "union", 2}, // 1219 + {NULL, "", "", 0}, // 1220 + {wxRegion_Union_3, "wxRegion", "union", 4}, // 1221 + {wxRegion_Xor_4, "wxRegion", "'Xor'", 5}, // 1222 + {wxRegion_Xor_1_0, "wxRegion", "'Xor'", 2}, // 1223 + {wxRegion_Xor_1_1, "wxRegion", "'Xor'", 2}, // 1224 + {wxAcceleratorTable_new_0, "wxAcceleratorTable", "new", 0}, // 1225 + {wxAcceleratorTable_new_2, "wxAcceleratorTable", "new", 2}, // 1226 + {NULL, "", "", 0}, // 1227 + {NULL, "wxAcceleratorTable", "destroy", 1}, // 1228 obj destructor wxAcceleratorTable_destruct + {wxAcceleratorTable_IsOk, "wxAcceleratorTable", "isOk", 1}, // 1229 + {wxAcceleratorEntry_new_1_0, "wxAcceleratorEntry", "new", 1}, // 1230 + {wxAcceleratorEntry_new_1_1, "wxAcceleratorEntry", "new", 1}, // 1231 + {wxAcceleratorEntry_GetCommand, "wxAcceleratorEntry", "getCommand", 1}, // 1232 + {wxAcceleratorEntry_GetFlags, "wxAcceleratorEntry", "getFlags", 1}, // 1233 + {wxAcceleratorEntry_GetKeyCode, "wxAcceleratorEntry", "getKeyCode", 1}, // 1234 + {wxAcceleratorEntry_Set, "wxAcceleratorEntry", "set", 5}, // 1235 + {wxAcceleratorEntry_destroy, "wxAcceleratorEntry", "'Destroy'", 1}, // 1236 + {NULL, "", "", 0}, // 1237 + {wxCaret_new_3, "wxCaret", "new", 3}, // 1238 + {wxCaret_new_2, "wxCaret", "new", 2}, // 1239 + {wxCaret_Create_3, "wxCaret", "create", 4}, // 1240 + {wxCaret_Create_2, "wxCaret", "create", 3}, // 1241 + {wxCaret_GetBlinkTime, "wxCaret", "getBlinkTime", 0}, // 1242 {NULL, "", "", 0}, // 1243 - {wxCaret_GetSize, "wxCaret", "getSize", 1}, // 1244 - {wxCaret_GetWindow, "wxCaret", "getWindow", 1}, // 1245 - {wxCaret_Hide, "wxCaret", "hide", 1}, // 1246 - {wxCaret_IsOk, "wxCaret", "isOk", 1}, // 1247 - {wxCaret_IsVisible, "wxCaret", "isVisible", 1}, // 1248 - {wxCaret_Move_2, "wxCaret", "move", 3}, // 1249 - {wxCaret_Move_1, "wxCaret", "move", 2}, // 1250 - {wxCaret_SetBlinkTime, "wxCaret", "setBlinkTime", 1}, // 1251 - {wxCaret_SetSize_2, "wxCaret", "setSize", 3}, // 1252 - {wxCaret_SetSize_1, "wxCaret", "setSize", 2}, // 1253 - {wxCaret_Show, "wxCaret", "show", 2}, // 1254 - {wxCaret_destroy, "wxCaret", "'Destroy'", 1}, // 1255 - {wxSizer_Add_2_0, "wxSizer", "add", 3}, // 1256 - {wxSizer_Add_2_1, "wxSizer", "add", 3}, // 1257 - {NULL, "", "", 0}, // 1258 - {NULL, "", "", 0}, // 1259 - {wxSizer_Add_3_0, "wxSizer", "add", 4}, // 1260 - {wxSizer_Add_3_1, "wxSizer", "add", 4}, // 1261 - {wxSizer_AddSpacer, "wxSizer", "addSpacer", 2}, // 1262 - {wxSizer_AddStretchSpacer, "wxSizer", "addStretchSpacer", 2}, // 1263 - {wxSizer_CalcMin, "wxSizer", "calcMin", 1}, // 1264 - {wxSizer_Clear, "wxSizer", "clear", 2}, // 1265 - {wxSizer_Detach_1_0, "wxSizer", "detach", 2}, // 1266 - {NULL, "", "", 0}, // 1267 - {wxSizer_Detach_1_1, "wxSizer", "detach", 2}, // 1268 - {wxSizer_Fit, "wxSizer", "fit", 2}, // 1269 - {wxSizer_FitInside, "wxSizer", "fitInside", 2}, // 1270 - {NULL, "", "", 0}, // 1271 - {wxSizer_GetChildren, "wxSizer", "getChildren", 1}, // 1272 - {wxSizer_GetItem_2, "wxSizer", "getItem", 3}, // 1273 - {NULL, "", "", 0}, // 1274 - {wxSizer_GetItem_1, "wxSizer", "getItem", 2}, // 1275 - {wxSizer_GetSize, "wxSizer", "getSize", 1}, // 1276 - {wxSizer_GetPosition, "wxSizer", "getPosition", 1}, // 1277 - {wxSizer_GetMinSize, "wxSizer", "getMinSize", 1}, // 1278 - {wxSizer_Hide_2, "wxSizer", "hide", 3}, // 1279 - {NULL, "", "", 0}, // 1280 - {wxSizer_Hide_1, "wxSizer", "hide", 2}, // 1281 - {wxSizer_Insert_3_0, "wxSizer", "insert", 4}, // 1282 - {wxSizer_Insert_3_1, "wxSizer", "insert", 4}, // 1283 - {NULL, "", "", 0}, // 1284 - {NULL, "", "", 0}, // 1285 - {wxSizer_Insert_4_0, "wxSizer", "insert", 5}, // 1286 - {wxSizer_Insert_4_1, "wxSizer", "insert", 5}, // 1287 - {wxSizer_Insert_2, "wxSizer", "insert", 3}, // 1288 - {wxSizer_InsertSpacer, "wxSizer", "insertSpacer", 3}, // 1289 - {wxSizer_InsertStretchSpacer, "wxSizer", "insertStretchSpacer", 3}, // 1290 - {wxSizer_IsShown_1_0, "wxSizer", "isShown", 2}, // 1291 - {NULL, "", "", 0}, // 1292 - {wxSizer_IsShown_1_1, "wxSizer", "isShown", 2}, // 1293 - {wxSizer_Layout, "wxSizer", "layout", 1}, // 1294 - {wxSizer_Prepend_2_0, "wxSizer", "prepend", 3}, // 1295 - {wxSizer_Prepend_2_1, "wxSizer", "prepend", 3}, // 1296 - {NULL, "", "", 0}, // 1297 - {NULL, "", "", 0}, // 1298 - {wxSizer_Prepend_3_0, "wxSizer", "prepend", 4}, // 1299 - {wxSizer_Prepend_3_1, "wxSizer", "prepend", 4}, // 1300 - {wxSizer_Prepend_1, "wxSizer", "prepend", 2}, // 1301 - {wxSizer_PrependSpacer, "wxSizer", "prependSpacer", 2}, // 1302 - {wxSizer_PrependStretchSpacer, "wxSizer", "prependStretchSpacer", 2}, // 1303 - {wxSizer_Remove_1_1, "wxSizer", "remove", 2}, // 1304 - {wxSizer_Remove_1_0, "wxSizer", "remove", 2}, // 1305 - {wxSizer_Replace_3, "wxSizer", "replace", 4}, // 1306 - {NULL, "", "", 0}, // 1307 - {wxSizer_Replace_2, "wxSizer", "replace", 3}, // 1308 - {wxSizer_SetDimension_4, "wxSizer", "setDimension", 5}, // 1309 - {wxSizer_SetDimension_2, "wxSizer", "setDimension", 3}, // 1310 - {wxSizer_SetMinSize_1, "wxSizer", "setMinSize", 2}, // 1311 - {wxSizer_SetMinSize_2, "wxSizer", "setMinSize", 3}, // 1312 - {wxSizer_SetItemMinSize_3_0, "wxSizer", "setItemMinSize", 4}, // 1313 - {wxSizer_SetItemMinSize_2_0, "wxSizer", "setItemMinSize", 3}, // 1314 - {NULL, "", "", 0}, // 1315 - {NULL, "", "", 0}, // 1316 - {wxSizer_SetItemMinSize_3_1, "wxSizer", "setItemMinSize", 4}, // 1317 - {wxSizer_SetItemMinSize_2_1, "wxSizer", "setItemMinSize", 3}, // 1318 - {wxSizer_SetSizeHints, "wxSizer", "setSizeHints", 2}, // 1319 - {wxSizer_Show_2_0, "wxSizer", "show", 3}, // 1320 - {NULL, "", "", 0}, // 1321 - {wxSizer_Show_2_1, "wxSizer", "show", 3}, // 1322 - {wxSizer_Show_1, "wxSizer", "show", 2}, // 1323 - {wxSizer_ShowItems, "wxSizer", "showItems", 2}, // 1324 - {wxSizerFlags_new, "wxSizerFlags", "new", 1}, // 1325 - {wxSizerFlags_Align, "wxSizerFlags", "align", 2}, // 1326 - {wxSizerFlags_Border_2, "wxSizerFlags", "border", 3}, // 1327 - {wxSizerFlags_Border_1, "wxSizerFlags", "border", 2}, // 1328 - {wxSizerFlags_Center, "wxSizerFlags", "center", 1}, // 1329 - {wxSizerFlags_Expand, "wxSizerFlags", "expand", 1}, // 1330 - {wxSizerFlags_Left, "wxSizerFlags", "left", 1}, // 1331 - {wxSizerFlags_Proportion, "wxSizerFlags", "proportion", 2}, // 1332 - {wxSizerFlags_Right, "wxSizerFlags", "right", 1}, // 1333 - {wxSizerFlags_destroy, "wxSizerFlags", "'Destroy'", 1}, // 1334 - {wxSizerItem_new_3, "wxSizerItem", "new", 3}, // 1335 - {wxSizerItem_new_2_0, "wxSizerItem", "new", 2}, // 1336 - {wxSizerItem_new_2_1, "wxSizerItem", "new", 2}, // 1337 - {NULL, "", "", 0}, // 1338 - {NULL, "", "", 0}, // 1339 - {NULL, "wxSizerItem", "destroy", 1}, // 1340 obj destructor wxSizerItem_destruct - {wxSizerItem_CalcMin, "wxSizerItem", "calcMin", 1}, // 1341 - {wxSizerItem_DeleteWindows, "wxSizerItem", "deleteWindows", 1}, // 1342 - {wxSizerItem_DetachSizer, "wxSizerItem", "detachSizer", 1}, // 1343 - {wxSizerItem_GetBorder, "wxSizerItem", "getBorder", 1}, // 1344 - {wxSizerItem_GetFlag, "wxSizerItem", "getFlag", 1}, // 1345 - {wxSizerItem_GetMinSize, "wxSizerItem", "getMinSize", 1}, // 1346 - {wxSizerItem_GetPosition, "wxSizerItem", "getPosition", 1}, // 1347 - {wxSizerItem_GetProportion, "wxSizerItem", "getProportion", 1}, // 1348 - {wxSizerItem_GetRatio, "wxSizerItem", "getRatio", 1}, // 1349 - {wxSizerItem_GetRect, "wxSizerItem", "getRect", 1}, // 1350 - {wxSizerItem_GetSize, "wxSizerItem", "getSize", 1}, // 1351 - {wxSizerItem_GetSizer, "wxSizerItem", "getSizer", 1}, // 1352 - {wxSizerItem_GetSpacer, "wxSizerItem", "getSpacer", 1}, // 1353 - {wxSizerItem_GetUserData, "wxSizerItem", "getUserData", 1}, // 1354 - {wxSizerItem_GetWindow, "wxSizerItem", "getWindow", 1}, // 1355 - {wxSizerItem_IsSizer, "wxSizerItem", "isSizer", 1}, // 1356 - {wxSizerItem_IsShown, "wxSizerItem", "isShown", 1}, // 1357 - {wxSizerItem_IsSpacer, "wxSizerItem", "isSpacer", 1}, // 1358 - {wxSizerItem_IsWindow, "wxSizerItem", "isWindow", 1}, // 1359 - {wxSizerItem_SetBorder, "wxSizerItem", "setBorder", 2}, // 1360 - {wxSizerItem_SetDimension, "wxSizerItem", "setDimension", 3}, // 1361 - {wxSizerItem_SetFlag, "wxSizerItem", "setFlag", 2}, // 1362 - {wxSizerItem_SetInitSize, "wxSizerItem", "setInitSize", 3}, // 1363 - {wxSizerItem_SetMinSize_1, "wxSizerItem", "setMinSize", 2}, // 1364 - {wxSizerItem_SetMinSize_2, "wxSizerItem", "setMinSize", 3}, // 1365 - {wxSizerItem_SetProportion, "wxSizerItem", "setProportion", 2}, // 1366 - {wxSizerItem_SetRatio_2, "wxSizerItem", "setRatio", 3}, // 1367 - {wxSizerItem_SetRatio_1_1, "wxSizerItem", "setRatio", 2}, // 1368 - {wxSizerItem_SetRatio_1_0, "wxSizerItem", "setRatio", 2}, // 1369 - {wxSizerItem_AssignSizer, "wxSizerItem", "assignSizer", 2}, // 1370 - {wxSizerItem_AssignSpacer_1, "wxSizerItem", "assignSpacer", 2}, // 1371 - {wxSizerItem_AssignSpacer_2, "wxSizerItem", "assignSpacer", 3}, // 1372 - {wxSizerItem_AssignWindow, "wxSizerItem", "assignWindow", 2}, // 1373 - {wxSizerItem_Show, "wxSizerItem", "show", 2}, // 1374 - {wxBoxSizer_new, "wxBoxSizer", "new", 1}, // 1375 - {wxBoxSizer_GetOrientation, "wxBoxSizer", "getOrientation", 1}, // 1376 - {NULL, "wxBoxSizer", "'Destroy'", 1}, // 1377 obj destructor wxBoxSizer_destroy - {wxStaticBoxSizer_new_2, "wxStaticBoxSizer", "new", 2}, // 1378 - {wxStaticBoxSizer_new_3, "wxStaticBoxSizer", "new", 3}, // 1379 - {wxStaticBoxSizer_GetStaticBox, "wxStaticBoxSizer", "getStaticBox", 1}, // 1380 - {NULL, "wxStaticBoxSizer", "'Destroy'", 1}, // 1381 obj destructor wxStaticBoxSizer_destroy - {wxGridSizer_new_3_0, "wxGridSizer", "new", 3}, // 1382 - {wxGridSizer_new_2, "wxGridSizer", "new", 2}, // 1383 - {wxGridSizer_new_4, "wxGridSizer", "new", 4}, // 1384 - {wxGridSizer_new_3_1, "wxGridSizer", "new", 3}, // 1385 - {wxGridSizer_GetCols, "wxGridSizer", "getCols", 1}, // 1386 - {wxGridSizer_GetHGap, "wxGridSizer", "getHGap", 1}, // 1387 - {wxGridSizer_GetRows, "wxGridSizer", "getRows", 1}, // 1388 - {wxGridSizer_GetVGap, "wxGridSizer", "getVGap", 1}, // 1389 - {wxGridSizer_SetCols, "wxGridSizer", "setCols", 2}, // 1390 - {wxGridSizer_SetHGap, "wxGridSizer", "setHGap", 2}, // 1391 - {wxGridSizer_SetRows, "wxGridSizer", "setRows", 2}, // 1392 - {wxGridSizer_SetVGap, "wxGridSizer", "setVGap", 2}, // 1393 - {NULL, "wxGridSizer", "'Destroy'", 1}, // 1394 obj destructor wxGridSizer_destroy - {wxFlexGridSizer_new_3_0, "wxFlexGridSizer", "new", 3}, // 1395 - {wxFlexGridSizer_new_2, "wxFlexGridSizer", "new", 2}, // 1396 - {wxFlexGridSizer_new_4, "wxFlexGridSizer", "new", 4}, // 1397 - {wxFlexGridSizer_new_3_1, "wxFlexGridSizer", "new", 3}, // 1398 - {wxFlexGridSizer_AddGrowableCol, "wxFlexGridSizer", "addGrowableCol", 3}, // 1399 - {wxFlexGridSizer_AddGrowableRow, "wxFlexGridSizer", "addGrowableRow", 3}, // 1400 - {wxFlexGridSizer_GetFlexibleDirection, "wxFlexGridSizer", "getFlexibleDirection", 1}, // 1401 - {wxFlexGridSizer_GetNonFlexibleGrowMode, "wxFlexGridSizer", "getNonFlexibleGrowMode", 1}, // 1402 - {wxFlexGridSizer_RemoveGrowableCol, "wxFlexGridSizer", "removeGrowableCol", 2}, // 1403 - {wxFlexGridSizer_RemoveGrowableRow, "wxFlexGridSizer", "removeGrowableRow", 2}, // 1404 - {wxFlexGridSizer_SetFlexibleDirection, "wxFlexGridSizer", "setFlexibleDirection", 2}, // 1405 - {wxFlexGridSizer_SetNonFlexibleGrowMode, "wxFlexGridSizer", "setNonFlexibleGrowMode", 2}, // 1406 - {NULL, "wxFlexGridSizer", "'Destroy'", 1}, // 1407 obj destructor wxFlexGridSizer_destroy - {wxGridBagSizer_new, "wxGridBagSizer", "new", 1}, // 1408 - {wxGridBagSizer_Add_3, "wxGridBagSizer", "add", 4}, // 1409 - {NULL, "", "", 0}, // 1410 - {wxGridBagSizer_Add_1, "wxGridBagSizer", "add", 2}, // 1411 - {wxGridBagSizer_Add_4, "wxGridBagSizer", "add", 5}, // 1412 - {wxGridBagSizer_CalcMin, "wxGridBagSizer", "calcMin", 1}, // 1413 - {wxGridBagSizer_CheckForIntersection_2, "wxGridBagSizer", "checkForIntersection", 3}, // 1414 - {wxGridBagSizer_CheckForIntersection_3, "wxGridBagSizer", "checkForIntersection", 4}, // 1415 - {wxGridBagSizer_FindItem, "wxGridBagSizer", "findItem", 2}, // 1416 - {NULL, "", "", 0}, // 1417 - {wxGridBagSizer_FindItemAtPoint, "wxGridBagSizer", "findItemAtPoint", 2}, // 1418 - {wxGridBagSizer_FindItemAtPosition, "wxGridBagSizer", "findItemAtPosition", 2}, // 1419 - {wxGridBagSizer_FindItemWithData, "wxGridBagSizer", "findItemWithData", 2}, // 1420 - {wxGridBagSizer_GetCellSize, "wxGridBagSizer", "getCellSize", 3}, // 1421 - {wxGridBagSizer_GetEmptyCellSize, "wxGridBagSizer", "getEmptyCellSize", 1}, // 1422 - {wxGridBagSizer_GetItemPosition_1_0, "wxGridBagSizer", "getItemPosition", 2}, // 1423 - {NULL, "", "", 0}, // 1424 - {wxGridBagSizer_GetItemPosition_1_1, "wxGridBagSizer", "getItemPosition", 2}, // 1425 - {wxGridBagSizer_GetItemSpan_1_0, "wxGridBagSizer", "getItemSpan", 2}, // 1426 - {NULL, "", "", 0}, // 1427 - {wxGridBagSizer_GetItemSpan_1_1, "wxGridBagSizer", "getItemSpan", 2}, // 1428 - {wxGridBagSizer_SetEmptyCellSize, "wxGridBagSizer", "setEmptyCellSize", 2}, // 1429 - {wxGridBagSizer_SetItemPosition_2_0, "wxGridBagSizer", "setItemPosition", 3}, // 1430 - {NULL, "", "", 0}, // 1431 - {wxGridBagSizer_SetItemPosition_2_1, "wxGridBagSizer", "setItemPosition", 3}, // 1432 - {wxGridBagSizer_SetItemSpan_2_0, "wxGridBagSizer", "setItemSpan", 3}, // 1433 - {NULL, "", "", 0}, // 1434 - {wxGridBagSizer_SetItemSpan_2_1, "wxGridBagSizer", "setItemSpan", 3}, // 1435 - {NULL, "wxGridBagSizer", "'Destroy'", 1}, // 1436 obj destructor wxGridBagSizer_destroy - {wxStdDialogButtonSizer_new, "wxStdDialogButtonSizer", "new", 0}, // 1437 - {wxStdDialogButtonSizer_AddButton, "wxStdDialogButtonSizer", "addButton", 2}, // 1438 - {wxStdDialogButtonSizer_Realize, "wxStdDialogButtonSizer", "realize", 1}, // 1439 - {wxStdDialogButtonSizer_SetAffirmativeButton, "wxStdDialogButtonSizer", "setAffirmativeButton", 2}, // 1440 - {wxStdDialogButtonSizer_SetCancelButton, "wxStdDialogButtonSizer", "setCancelButton", 2}, // 1441 - {wxStdDialogButtonSizer_SetNegativeButton, "wxStdDialogButtonSizer", "setNegativeButton", 2}, // 1442 - {NULL, "wxStdDialogButtonSizer", "'Destroy'", 1}, // 1443 obj destructor wxStdDialogButtonSizer_destroy - {wxFont_new_0, "wxFont", "new", 0}, // 1444 - {wxFont_new_1_1, "wxFont", "new", 1}, // 1445 - {wxFont_new_5_0, "wxFont", "new", 5}, // 1446 - {wxFont_new_5_1, "wxFont", "new", 5}, // 1447 - {wxFont_new_1_0, "wxFont", "new", 1}, // 1448 - {NULL, "wxFont", "destroy", 1}, // 1449 obj destructor wxFont_destruct - {wxFont_IsFixedWidth, "wxFont", "isFixedWidth", 1}, // 1450 - {wxFont_GetDefaultEncoding, "wxFont", "getDefaultEncoding", 0}, // 1451 - {wxFont_GetFaceName, "wxFont", "getFaceName", 1}, // 1452 - {wxFont_GetFamily, "wxFont", "getFamily", 1}, // 1453 - {wxFont_GetNativeFontInfoDesc, "wxFont", "getNativeFontInfoDesc", 1}, // 1454 - {wxFont_GetNativeFontInfoUserDesc, "wxFont", "getNativeFontInfoUserDesc", 1}, // 1455 - {wxFont_GetPointSize, "wxFont", "getPointSize", 1}, // 1456 - {wxFont_GetStyle, "wxFont", "getStyle", 1}, // 1457 - {wxFont_GetUnderlined, "wxFont", "getUnderlined", 1}, // 1458 - {wxFont_GetWeight, "wxFont", "getWeight", 1}, // 1459 - {wxFont_IsOk, "wxFont", "isOk", 1}, // 1460 - {wxFont_SetDefaultEncoding, "wxFont", "setDefaultEncoding", 1}, // 1461 - {wxFont_SetFaceName, "wxFont", "setFaceName", 2}, // 1462 - {wxFont_SetFamily, "wxFont", "setFamily", 2}, // 1463 - {wxFont_SetPointSize, "wxFont", "setPointSize", 2}, // 1464 - {wxFont_SetStyle, "wxFont", "setStyle", 2}, // 1465 - {wxFont_SetUnderlined, "wxFont", "setUnderlined", 2}, // 1466 - {wxFont_SetWeight, "wxFont", "setWeight", 2}, // 1467 - {wxToolTip_Enable, "wxToolTip", "enable", 1}, // 1468 - {wxToolTip_SetDelay, "wxToolTip", "setDelay", 1}, // 1469 - {wxToolTip_new, "wxToolTip", "new", 1}, // 1470 - {wxToolTip_SetTip, "wxToolTip", "setTip", 2}, // 1471 - {wxToolTip_GetTip, "wxToolTip", "getTip", 1}, // 1472 - {wxToolTip_GetWindow, "wxToolTip", "getWindow", 1}, // 1473 - {NULL, "wxToolTip", "'Destroy'", 1}, // 1474 obj destructor wxToolTip_destroy - {wxButton_new_0, "wxButton", "new", 0}, // 1475 - {wxButton_new_3, "wxButton", "new", 3}, // 1476 - {wxButton_Create, "wxButton", "create", 4}, // 1477 - {wxButton_GetDefaultSize_STAT_0, "wxButton", "getDefaultSize", 0}, // 1478 + {wxCaret_GetPosition, "wxCaret", "getPosition", 1}, // 1244 + {NULL, "", "", 0}, // 1245 + {wxCaret_GetSize, "wxCaret", "getSize", 1}, // 1246 + {wxCaret_GetWindow, "wxCaret", "getWindow", 1}, // 1247 + {wxCaret_Hide, "wxCaret", "hide", 1}, // 1248 + {wxCaret_IsOk, "wxCaret", "isOk", 1}, // 1249 + {wxCaret_IsVisible, "wxCaret", "isVisible", 1}, // 1250 + {wxCaret_Move_2, "wxCaret", "move", 3}, // 1251 + {wxCaret_Move_1, "wxCaret", "move", 2}, // 1252 + {wxCaret_SetBlinkTime, "wxCaret", "setBlinkTime", 1}, // 1253 + {wxCaret_SetSize_2, "wxCaret", "setSize", 3}, // 1254 + {wxCaret_SetSize_1, "wxCaret", "setSize", 2}, // 1255 + {wxCaret_Show, "wxCaret", "show", 2}, // 1256 + {wxCaret_destroy, "wxCaret", "'Destroy'", 1}, // 1257 + {wxSizer_Add_2_0, "wxSizer", "add", 3}, // 1258 + {wxSizer_Add_2_1, "wxSizer", "add", 3}, // 1259 + {NULL, "", "", 0}, // 1260 + {NULL, "", "", 0}, // 1261 + {wxSizer_Add_3_0, "wxSizer", "add", 4}, // 1262 + {wxSizer_Add_3_1, "wxSizer", "add", 4}, // 1263 + {wxSizer_AddSpacer, "wxSizer", "addSpacer", 2}, // 1264 + {wxSizer_AddStretchSpacer, "wxSizer", "addStretchSpacer", 2}, // 1265 + {wxSizer_CalcMin, "wxSizer", "calcMin", 1}, // 1266 + {wxSizer_Clear, "wxSizer", "clear", 2}, // 1267 + {wxSizer_Detach_1_0, "wxSizer", "detach", 2}, // 1268 + {NULL, "", "", 0}, // 1269 + {wxSizer_Detach_1_1, "wxSizer", "detach", 2}, // 1270 + {wxSizer_Fit, "wxSizer", "fit", 2}, // 1271 + {wxSizer_FitInside, "wxSizer", "fitInside", 2}, // 1272 + {NULL, "", "", 0}, // 1273 + {wxSizer_GetChildren, "wxSizer", "getChildren", 1}, // 1274 + {wxSizer_GetItem_2, "wxSizer", "getItem", 3}, // 1275 + {NULL, "", "", 0}, // 1276 + {wxSizer_GetItem_1, "wxSizer", "getItem", 2}, // 1277 + {wxSizer_GetSize, "wxSizer", "getSize", 1}, // 1278 + {wxSizer_GetPosition, "wxSizer", "getPosition", 1}, // 1279 + {wxSizer_GetMinSize, "wxSizer", "getMinSize", 1}, // 1280 + {wxSizer_Hide_2, "wxSizer", "hide", 3}, // 1281 + {NULL, "", "", 0}, // 1282 + {wxSizer_Hide_1, "wxSizer", "hide", 2}, // 1283 + {wxSizer_Insert_3_0, "wxSizer", "insert", 4}, // 1284 + {wxSizer_Insert_3_1, "wxSizer", "insert", 4}, // 1285 + {NULL, "", "", 0}, // 1286 + {NULL, "", "", 0}, // 1287 + {wxSizer_Insert_4_0, "wxSizer", "insert", 5}, // 1288 + {wxSizer_Insert_4_1, "wxSizer", "insert", 5}, // 1289 + {wxSizer_Insert_2, "wxSizer", "insert", 3}, // 1290 + {wxSizer_InsertSpacer, "wxSizer", "insertSpacer", 3}, // 1291 + {wxSizer_InsertStretchSpacer, "wxSizer", "insertStretchSpacer", 3}, // 1292 + {wxSizer_IsShown_1_0, "wxSizer", "isShown", 2}, // 1293 + {NULL, "", "", 0}, // 1294 + {wxSizer_IsShown_1_1, "wxSizer", "isShown", 2}, // 1295 + {wxSizer_Layout, "wxSizer", "layout", 1}, // 1296 + {wxSizer_Prepend_2_0, "wxSizer", "prepend", 3}, // 1297 + {wxSizer_Prepend_2_1, "wxSizer", "prepend", 3}, // 1298 + {NULL, "", "", 0}, // 1299 + {NULL, "", "", 0}, // 1300 + {wxSizer_Prepend_3_0, "wxSizer", "prepend", 4}, // 1301 + {wxSizer_Prepend_3_1, "wxSizer", "prepend", 4}, // 1302 + {wxSizer_Prepend_1, "wxSizer", "prepend", 2}, // 1303 + {wxSizer_PrependSpacer, "wxSizer", "prependSpacer", 2}, // 1304 + {wxSizer_PrependStretchSpacer, "wxSizer", "prependStretchSpacer", 2}, // 1305 + {wxSizer_Remove_1_1, "wxSizer", "remove", 2}, // 1306 + {wxSizer_Remove_1_0, "wxSizer", "remove", 2}, // 1307 + {wxSizer_Replace_3, "wxSizer", "replace", 4}, // 1308 + {NULL, "", "", 0}, // 1309 + {wxSizer_Replace_2, "wxSizer", "replace", 3}, // 1310 + {wxSizer_SetDimension_4, "wxSizer", "setDimension", 5}, // 1311 + {wxSizer_SetDimension_2, "wxSizer", "setDimension", 3}, // 1312 + {wxSizer_SetMinSize_1, "wxSizer", "setMinSize", 2}, // 1313 + {wxSizer_SetMinSize_2, "wxSizer", "setMinSize", 3}, // 1314 + {wxSizer_SetItemMinSize_3_0, "wxSizer", "setItemMinSize", 4}, // 1315 + {wxSizer_SetItemMinSize_2_0, "wxSizer", "setItemMinSize", 3}, // 1316 + {NULL, "", "", 0}, // 1317 + {NULL, "", "", 0}, // 1318 + {wxSizer_SetItemMinSize_3_1, "wxSizer", "setItemMinSize", 4}, // 1319 + {wxSizer_SetItemMinSize_2_1, "wxSizer", "setItemMinSize", 3}, // 1320 + {wxSizer_SetSizeHints, "wxSizer", "setSizeHints", 2}, // 1321 + {wxSizer_Show_2_0, "wxSizer", "show", 3}, // 1322 + {NULL, "", "", 0}, // 1323 + {wxSizer_Show_2_1, "wxSizer", "show", 3}, // 1324 + {wxSizer_Show_1, "wxSizer", "show", 2}, // 1325 + {wxSizer_ShowItems, "wxSizer", "showItems", 2}, // 1326 + {wxSizerFlags_new, "wxSizerFlags", "new", 1}, // 1327 + {wxSizerFlags_Align, "wxSizerFlags", "align", 2}, // 1328 + {wxSizerFlags_Border_2, "wxSizerFlags", "border", 3}, // 1329 + {wxSizerFlags_Border_1, "wxSizerFlags", "border", 2}, // 1330 + {wxSizerFlags_Center, "wxSizerFlags", "center", 1}, // 1331 + {wxSizerFlags_Expand, "wxSizerFlags", "expand", 1}, // 1332 + {wxSizerFlags_Left, "wxSizerFlags", "left", 1}, // 1333 + {wxSizerFlags_Proportion, "wxSizerFlags", "proportion", 2}, // 1334 + {wxSizerFlags_Right, "wxSizerFlags", "right", 1}, // 1335 + {wxSizerFlags_destroy, "wxSizerFlags", "'Destroy'", 1}, // 1336 + {wxSizerItem_new_3, "wxSizerItem", "new", 3}, // 1337 + {wxSizerItem_new_2_0, "wxSizerItem", "new", 2}, // 1338 + {wxSizerItem_new_2_1, "wxSizerItem", "new", 2}, // 1339 + {NULL, "", "", 0}, // 1340 + {NULL, "", "", 0}, // 1341 + {NULL, "wxSizerItem", "destroy", 1}, // 1342 obj destructor wxSizerItem_destruct + {wxSizerItem_CalcMin, "wxSizerItem", "calcMin", 1}, // 1343 + {wxSizerItem_DeleteWindows, "wxSizerItem", "deleteWindows", 1}, // 1344 + {wxSizerItem_DetachSizer, "wxSizerItem", "detachSizer", 1}, // 1345 + {wxSizerItem_GetBorder, "wxSizerItem", "getBorder", 1}, // 1346 + {wxSizerItem_GetFlag, "wxSizerItem", "getFlag", 1}, // 1347 + {wxSizerItem_GetMinSize, "wxSizerItem", "getMinSize", 1}, // 1348 + {wxSizerItem_GetPosition, "wxSizerItem", "getPosition", 1}, // 1349 + {wxSizerItem_GetProportion, "wxSizerItem", "getProportion", 1}, // 1350 + {wxSizerItem_GetRatio, "wxSizerItem", "getRatio", 1}, // 1351 + {wxSizerItem_GetRect, "wxSizerItem", "getRect", 1}, // 1352 + {wxSizerItem_GetSize, "wxSizerItem", "getSize", 1}, // 1353 + {wxSizerItem_GetSizer, "wxSizerItem", "getSizer", 1}, // 1354 + {wxSizerItem_GetSpacer, "wxSizerItem", "getSpacer", 1}, // 1355 + {wxSizerItem_GetUserData, "wxSizerItem", "getUserData", 1}, // 1356 + {wxSizerItem_GetWindow, "wxSizerItem", "getWindow", 1}, // 1357 + {wxSizerItem_IsSizer, "wxSizerItem", "isSizer", 1}, // 1358 + {wxSizerItem_IsShown, "wxSizerItem", "isShown", 1}, // 1359 + {wxSizerItem_IsSpacer, "wxSizerItem", "isSpacer", 1}, // 1360 + {wxSizerItem_IsWindow, "wxSizerItem", "isWindow", 1}, // 1361 + {wxSizerItem_SetBorder, "wxSizerItem", "setBorder", 2}, // 1362 + {wxSizerItem_SetDimension, "wxSizerItem", "setDimension", 3}, // 1363 + {wxSizerItem_SetFlag, "wxSizerItem", "setFlag", 2}, // 1364 + {wxSizerItem_SetInitSize, "wxSizerItem", "setInitSize", 3}, // 1365 + {wxSizerItem_SetMinSize_1, "wxSizerItem", "setMinSize", 2}, // 1366 + {wxSizerItem_SetMinSize_2, "wxSizerItem", "setMinSize", 3}, // 1367 + {wxSizerItem_SetProportion, "wxSizerItem", "setProportion", 2}, // 1368 + {wxSizerItem_SetRatio_2, "wxSizerItem", "setRatio", 3}, // 1369 + {wxSizerItem_SetRatio_1_1, "wxSizerItem", "setRatio", 2}, // 1370 + {wxSizerItem_SetRatio_1_0, "wxSizerItem", "setRatio", 2}, // 1371 + {wxSizerItem_AssignSizer, "wxSizerItem", "assignSizer", 2}, // 1372 + {wxSizerItem_AssignSpacer_1, "wxSizerItem", "assignSpacer", 2}, // 1373 + {wxSizerItem_AssignSpacer_2, "wxSizerItem", "assignSpacer", 3}, // 1374 + {wxSizerItem_AssignWindow, "wxSizerItem", "assignWindow", 2}, // 1375 + {wxSizerItem_Show, "wxSizerItem", "show", 2}, // 1376 + {wxBoxSizer_new, "wxBoxSizer", "new", 1}, // 1377 + {wxBoxSizer_GetOrientation, "wxBoxSizer", "getOrientation", 1}, // 1378 + {NULL, "wxBoxSizer", "'Destroy'", 1}, // 1379 obj destructor wxBoxSizer_destroy + {wxStaticBoxSizer_new_2, "wxStaticBoxSizer", "new", 2}, // 1380 + {wxStaticBoxSizer_new_3, "wxStaticBoxSizer", "new", 3}, // 1381 + {wxStaticBoxSizer_GetStaticBox, "wxStaticBoxSizer", "getStaticBox", 1}, // 1382 + {NULL, "wxStaticBoxSizer", "'Destroy'", 1}, // 1383 obj destructor wxStaticBoxSizer_destroy + {wxGridSizer_new_3_0, "wxGridSizer", "new", 3}, // 1384 + {wxGridSizer_new_2, "wxGridSizer", "new", 2}, // 1385 + {wxGridSizer_new_4, "wxGridSizer", "new", 4}, // 1386 + {wxGridSizer_new_3_1, "wxGridSizer", "new", 3}, // 1387 + {wxGridSizer_GetCols, "wxGridSizer", "getCols", 1}, // 1388 + {wxGridSizer_GetHGap, "wxGridSizer", "getHGap", 1}, // 1389 + {wxGridSizer_GetRows, "wxGridSizer", "getRows", 1}, // 1390 + {wxGridSizer_GetVGap, "wxGridSizer", "getVGap", 1}, // 1391 + {wxGridSizer_SetCols, "wxGridSizer", "setCols", 2}, // 1392 + {wxGridSizer_SetHGap, "wxGridSizer", "setHGap", 2}, // 1393 + {wxGridSizer_SetRows, "wxGridSizer", "setRows", 2}, // 1394 + {wxGridSizer_SetVGap, "wxGridSizer", "setVGap", 2}, // 1395 + {NULL, "wxGridSizer", "'Destroy'", 1}, // 1396 obj destructor wxGridSizer_destroy + {wxFlexGridSizer_new_3_0, "wxFlexGridSizer", "new", 3}, // 1397 + {wxFlexGridSizer_new_2, "wxFlexGridSizer", "new", 2}, // 1398 + {wxFlexGridSizer_new_4, "wxFlexGridSizer", "new", 4}, // 1399 + {wxFlexGridSizer_new_3_1, "wxFlexGridSizer", "new", 3}, // 1400 + {wxFlexGridSizer_AddGrowableCol, "wxFlexGridSizer", "addGrowableCol", 3}, // 1401 + {wxFlexGridSizer_AddGrowableRow, "wxFlexGridSizer", "addGrowableRow", 3}, // 1402 + {wxFlexGridSizer_GetFlexibleDirection, "wxFlexGridSizer", "getFlexibleDirection", 1}, // 1403 + {wxFlexGridSizer_GetNonFlexibleGrowMode, "wxFlexGridSizer", "getNonFlexibleGrowMode", 1}, // 1404 + {wxFlexGridSizer_RemoveGrowableCol, "wxFlexGridSizer", "removeGrowableCol", 2}, // 1405 + {wxFlexGridSizer_RemoveGrowableRow, "wxFlexGridSizer", "removeGrowableRow", 2}, // 1406 + {wxFlexGridSizer_SetFlexibleDirection, "wxFlexGridSizer", "setFlexibleDirection", 2}, // 1407 + {wxFlexGridSizer_SetNonFlexibleGrowMode, "wxFlexGridSizer", "setNonFlexibleGrowMode", 2}, // 1408 + {NULL, "wxFlexGridSizer", "'Destroy'", 1}, // 1409 obj destructor wxFlexGridSizer_destroy + {wxGridBagSizer_new, "wxGridBagSizer", "new", 1}, // 1410 + {wxGridBagSizer_Add_3, "wxGridBagSizer", "add", 4}, // 1411 + {NULL, "", "", 0}, // 1412 + {wxGridBagSizer_Add_1, "wxGridBagSizer", "add", 2}, // 1413 + {wxGridBagSizer_Add_4, "wxGridBagSizer", "add", 5}, // 1414 + {wxGridBagSizer_CalcMin, "wxGridBagSizer", "calcMin", 1}, // 1415 + {wxGridBagSizer_CheckForIntersection_2, "wxGridBagSizer", "checkForIntersection", 3}, // 1416 + {wxGridBagSizer_CheckForIntersection_3, "wxGridBagSizer", "checkForIntersection", 4}, // 1417 + {wxGridBagSizer_FindItem, "wxGridBagSizer", "findItem", 2}, // 1418 + {NULL, "", "", 0}, // 1419 + {wxGridBagSizer_FindItemAtPoint, "wxGridBagSizer", "findItemAtPoint", 2}, // 1420 + {wxGridBagSizer_FindItemAtPosition, "wxGridBagSizer", "findItemAtPosition", 2}, // 1421 + {wxGridBagSizer_FindItemWithData, "wxGridBagSizer", "findItemWithData", 2}, // 1422 + {wxGridBagSizer_GetCellSize, "wxGridBagSizer", "getCellSize", 3}, // 1423 + {wxGridBagSizer_GetEmptyCellSize, "wxGridBagSizer", "getEmptyCellSize", 1}, // 1424 + {wxGridBagSizer_GetItemPosition_1_0, "wxGridBagSizer", "getItemPosition", 2}, // 1425 + {NULL, "", "", 0}, // 1426 + {wxGridBagSizer_GetItemPosition_1_1, "wxGridBagSizer", "getItemPosition", 2}, // 1427 + {wxGridBagSizer_GetItemSpan_1_0, "wxGridBagSizer", "getItemSpan", 2}, // 1428 + {NULL, "", "", 0}, // 1429 + {wxGridBagSizer_GetItemSpan_1_1, "wxGridBagSizer", "getItemSpan", 2}, // 1430 + {wxGridBagSizer_SetEmptyCellSize, "wxGridBagSizer", "setEmptyCellSize", 2}, // 1431 + {wxGridBagSizer_SetItemPosition_2_0, "wxGridBagSizer", "setItemPosition", 3}, // 1432 + {NULL, "", "", 0}, // 1433 + {wxGridBagSizer_SetItemPosition_2_1, "wxGridBagSizer", "setItemPosition", 3}, // 1434 + {wxGridBagSizer_SetItemSpan_2_0, "wxGridBagSizer", "setItemSpan", 3}, // 1435 + {NULL, "", "", 0}, // 1436 + {wxGridBagSizer_SetItemSpan_2_1, "wxGridBagSizer", "setItemSpan", 3}, // 1437 + {NULL, "wxGridBagSizer", "'Destroy'", 1}, // 1438 obj destructor wxGridBagSizer_destroy + {wxStdDialogButtonSizer_new, "wxStdDialogButtonSizer", "new", 0}, // 1439 + {wxStdDialogButtonSizer_AddButton, "wxStdDialogButtonSizer", "addButton", 2}, // 1440 + {wxStdDialogButtonSizer_Realize, "wxStdDialogButtonSizer", "realize", 1}, // 1441 + {wxStdDialogButtonSizer_SetAffirmativeButton, "wxStdDialogButtonSizer", "setAffirmativeButton", 2}, // 1442 + {wxStdDialogButtonSizer_SetCancelButton, "wxStdDialogButtonSizer", "setCancelButton", 2}, // 1443 + {wxStdDialogButtonSizer_SetNegativeButton, "wxStdDialogButtonSizer", "setNegativeButton", 2}, // 1444 + {NULL, "wxStdDialogButtonSizer", "'Destroy'", 1}, // 1445 obj destructor wxStdDialogButtonSizer_destroy + {wxFont_new_0, "wxFont", "new", 0}, // 1446 + {wxFont_new_1_1, "wxFont", "new", 1}, // 1447 + {wxFont_new_5_0, "wxFont", "new", 5}, // 1448 + {wxFont_new_5_1, "wxFont", "new", 5}, // 1449 + {wxFont_new_1_0, "wxFont", "new", 1}, // 1450 + {NULL, "wxFont", "destroy", 1}, // 1451 obj destructor wxFont_destruct + {wxFont_IsFixedWidth, "wxFont", "isFixedWidth", 1}, // 1452 + {wxFont_GetDefaultEncoding, "wxFont", "getDefaultEncoding", 0}, // 1453 + {wxFont_GetFaceName, "wxFont", "getFaceName", 1}, // 1454 + {wxFont_GetFamily, "wxFont", "getFamily", 1}, // 1455 + {wxFont_GetNativeFontInfoDesc, "wxFont", "getNativeFontInfoDesc", 1}, // 1456 + {wxFont_GetNativeFontInfoUserDesc, "wxFont", "getNativeFontInfoUserDesc", 1}, // 1457 + {wxFont_GetPointSize, "wxFont", "getPointSize", 1}, // 1458 + {wxFont_GetStyle, "wxFont", "getStyle", 1}, // 1459 + {wxFont_GetUnderlined, "wxFont", "getUnderlined", 1}, // 1460 + {wxFont_GetWeight, "wxFont", "getWeight", 1}, // 1461 + {wxFont_IsOk, "wxFont", "isOk", 1}, // 1462 + {wxFont_SetDefaultEncoding, "wxFont", "setDefaultEncoding", 1}, // 1463 + {wxFont_SetFaceName, "wxFont", "setFaceName", 2}, // 1464 + {wxFont_SetFamily, "wxFont", "setFamily", 2}, // 1465 + {wxFont_SetPointSize, "wxFont", "setPointSize", 2}, // 1466 + {wxFont_SetStyle, "wxFont", "setStyle", 2}, // 1467 + {wxFont_SetUnderlined, "wxFont", "setUnderlined", 2}, // 1468 + {wxFont_SetWeight, "wxFont", "setWeight", 2}, // 1469 + {wxToolTip_Enable, "wxToolTip", "enable", 1}, // 1470 + {wxToolTip_SetDelay, "wxToolTip", "setDelay", 1}, // 1471 + {wxToolTip_new, "wxToolTip", "new", 1}, // 1472 + {wxToolTip_SetTip, "wxToolTip", "setTip", 2}, // 1473 + {wxToolTip_GetTip, "wxToolTip", "getTip", 1}, // 1474 + {wxToolTip_GetWindow, "wxToolTip", "getWindow", 1}, // 1475 + {NULL, "wxToolTip", "'Destroy'", 1}, // 1476 obj destructor wxToolTip_destroy + {wxButton_new_0, "wxButton", "new", 0}, // 1477 + {wxButton_new_3, "wxButton", "new", 3}, // 1478 + {wxButton_Create, "wxButton", "create", 4}, // 1479 + {wxButton_GetDefaultSize_STAT_0, "wxButton", "getDefaultSize", 0}, // 1480 #if wxCHECK_VERSION(3,1,3) - {wxButton_GetDefaultSize_STAT_1, "wxButton", "getDefaultSize", 1}, // 1479 + {wxButton_GetDefaultSize_STAT_1, "wxButton", "getDefaultSize", 1}, // 1481 #else - {NULL, "wxButton", "getDefaultSize", 0}, // 1479 + {NULL, "wxButton", "getDefaultSize", 0}, // 1481 #endif // wxCHECK_VERSION(3,1,3) - {wxButton_SetDefault, "wxButton", "setDefault", 1}, // 1480 - {wxButton_SetLabel, "wxButton", "setLabel", 2}, // 1481 - {wxButton_GetBitmapDisabled, "wxButton", "getBitmapDisabled", 1}, // 1482 - {wxButton_GetBitmapFocus, "wxButton", "getBitmapFocus", 1}, // 1483 - {wxButton_GetBitmapLabel, "wxButton", "getBitmapLabel", 1}, // 1484 - {wxButton_SetBitmapDisabled, "wxButton", "setBitmapDisabled", 2}, // 1485 - {wxButton_SetBitmapFocus, "wxButton", "setBitmapFocus", 2}, // 1486 - {wxButton_SetBitmapLabel, "wxButton", "setBitmapLabel", 2}, // 1487 - {NULL, "wxButton", "'Destroy'", 1}, // 1488 obj destructor wxButton_destroy - {wxBitmapButton_new_0, "wxBitmapButton", "new", 0}, // 1489 - {wxBitmapButton_new_4, "wxBitmapButton", "new", 4}, // 1490 - {wxBitmapButton_Create, "wxBitmapButton", "create", 5}, // 1491 - {wxBitmapButton_NewCloseButton, "wxBitmapButton", "newCloseButton", 2}, // 1492 - {NULL, "wxBitmapButton", "'Destroy'", 1}, // 1493 obj destructor wxBitmapButton_destroy - {wxToggleButton_new_0, "wxToggleButton", "new", 0}, // 1494 - {wxToggleButton_new_4, "wxToggleButton", "new", 4}, // 1495 - {NULL, "wxToggleButton", "destroy", 1}, // 1496 obj destructor wxToggleButton_destruct - {wxToggleButton_Create, "wxToggleButton", "create", 5}, // 1497 - {wxToggleButton_GetValue, "wxToggleButton", "getValue", 1}, // 1498 - {wxToggleButton_SetValue, "wxToggleButton", "setValue", 2}, // 1499 - {wxCalendarCtrl_new_0, "wxCalendarCtrl", "new", 0}, // 1500 - {wxCalendarCtrl_new_3, "wxCalendarCtrl", "new", 3}, // 1501 - {wxCalendarCtrl_Create, "wxCalendarCtrl", "create", 4}, // 1502 - {NULL, "wxCalendarCtrl", "destroy", 1}, // 1503 obj destructor wxCalendarCtrl_destruct - {wxCalendarCtrl_SetDate, "wxCalendarCtrl", "setDate", 2}, // 1504 - {wxCalendarCtrl_GetDate, "wxCalendarCtrl", "getDate", 1}, // 1505 + {wxButton_SetDefault, "wxButton", "setDefault", 1}, // 1482 + {wxButton_SetLabel, "wxButton", "setLabel", 2}, // 1483 + {wxButton_GetBitmapDisabled, "wxButton", "getBitmapDisabled", 1}, // 1484 + {wxButton_GetBitmapFocus, "wxButton", "getBitmapFocus", 1}, // 1485 + {wxButton_GetBitmapLabel, "wxButton", "getBitmapLabel", 1}, // 1486 + {wxButton_SetBitmapDisabled, "wxButton", "setBitmapDisabled", 2}, // 1487 + {wxButton_SetBitmapFocus, "wxButton", "setBitmapFocus", 2}, // 1488 + {wxButton_SetBitmapLabel, "wxButton", "setBitmapLabel", 2}, // 1489 + {NULL, "wxButton", "'Destroy'", 1}, // 1490 obj destructor wxButton_destroy + {wxBitmapButton_new_0, "wxBitmapButton", "new", 0}, // 1491 + {wxBitmapButton_new_4, "wxBitmapButton", "new", 4}, // 1492 + {wxBitmapButton_Create, "wxBitmapButton", "create", 5}, // 1493 + {wxBitmapButton_NewCloseButton, "wxBitmapButton", "newCloseButton", 2}, // 1494 + {NULL, "wxBitmapButton", "'Destroy'", 1}, // 1495 obj destructor wxBitmapButton_destroy + {wxToggleButton_new_0, "wxToggleButton", "new", 0}, // 1496 + {wxToggleButton_new_4, "wxToggleButton", "new", 4}, // 1497 + {NULL, "wxToggleButton", "destroy", 1}, // 1498 obj destructor wxToggleButton_destruct + {wxToggleButton_Create, "wxToggleButton", "create", 5}, // 1499 + {wxToggleButton_GetValue, "wxToggleButton", "getValue", 1}, // 1500 + {wxToggleButton_SetValue, "wxToggleButton", "setValue", 2}, // 1501 + {wxCalendarCtrl_new_0, "wxCalendarCtrl", "new", 0}, // 1502 + {wxCalendarCtrl_new_3, "wxCalendarCtrl", "new", 3}, // 1503 + {wxCalendarCtrl_Create, "wxCalendarCtrl", "create", 4}, // 1504 + {NULL, "wxCalendarCtrl", "destroy", 1}, // 1505 obj destructor wxCalendarCtrl_destruct + {wxCalendarCtrl_SetDate, "wxCalendarCtrl", "setDate", 2}, // 1506 + {wxCalendarCtrl_GetDate, "wxCalendarCtrl", "getDate", 1}, // 1507 #if !wxCHECK_VERSION(2,9,0) - {wxCalendarCtrl_EnableYearChange, "wxCalendarCtrl", "enableYearChange", 2}, // 1506 + {wxCalendarCtrl_EnableYearChange, "wxCalendarCtrl", "enableYearChange", 2}, // 1508 #else - {NULL, "wxCalendarCtrl", "enableYearChange", 0}, // 1506 + {NULL, "wxCalendarCtrl", "enableYearChange", 0}, // 1508 #endif // !wxCHECK_VERSION(2,9,0) - {wxCalendarCtrl_EnableMonthChange, "wxCalendarCtrl", "enableMonthChange", 2}, // 1507 - {wxCalendarCtrl_EnableHolidayDisplay, "wxCalendarCtrl", "enableHolidayDisplay", 2}, // 1508 - {wxCalendarCtrl_SetHeaderColours, "wxCalendarCtrl", "setHeaderColours", 3}, // 1509 - {wxCalendarCtrl_GetHeaderColourFg, "wxCalendarCtrl", "getHeaderColourFg", 1}, // 1510 - {wxCalendarCtrl_GetHeaderColourBg, "wxCalendarCtrl", "getHeaderColourBg", 1}, // 1511 - {wxCalendarCtrl_SetHighlightColours, "wxCalendarCtrl", "setHighlightColours", 3}, // 1512 - {wxCalendarCtrl_GetHighlightColourFg, "wxCalendarCtrl", "getHighlightColourFg", 1}, // 1513 - {wxCalendarCtrl_GetHighlightColourBg, "wxCalendarCtrl", "getHighlightColourBg", 1}, // 1514 - {wxCalendarCtrl_SetHolidayColours, "wxCalendarCtrl", "setHolidayColours", 3}, // 1515 - {wxCalendarCtrl_GetHolidayColourFg, "wxCalendarCtrl", "getHolidayColourFg", 1}, // 1516 - {wxCalendarCtrl_GetHolidayColourBg, "wxCalendarCtrl", "getHolidayColourBg", 1}, // 1517 - {wxCalendarCtrl_GetAttr, "wxCalendarCtrl", "getAttr", 2}, // 1518 - {wxCalendarCtrl_SetAttr, "wxCalendarCtrl", "setAttr", 3}, // 1519 - {wxCalendarCtrl_SetHoliday, "wxCalendarCtrl", "setHoliday", 2}, // 1520 - {wxCalendarCtrl_ResetAttr, "wxCalendarCtrl", "resetAttr", 2}, // 1521 - {wxCalendarCtrl_HitTest, "wxCalendarCtrl", "hitTest", 2}, // 1522 - {wxCalendarDateAttr_new_1, "wxCalendarDateAttr", "new", 1}, // 1523 - {wxCalendarDateAttr_new_2, "wxCalendarDateAttr", "new", 2}, // 1524 - {wxCalendarDateAttr_SetTextColour, "wxCalendarDateAttr", "setTextColour", 2}, // 1525 - {wxCalendarDateAttr_SetBackgroundColour, "wxCalendarDateAttr", "setBackgroundColour", 2}, // 1526 - {wxCalendarDateAttr_SetBorderColour, "wxCalendarDateAttr", "setBorderColour", 2}, // 1527 - {wxCalendarDateAttr_SetFont, "wxCalendarDateAttr", "setFont", 2}, // 1528 - {wxCalendarDateAttr_SetBorder, "wxCalendarDateAttr", "setBorder", 2}, // 1529 - {wxCalendarDateAttr_SetHoliday, "wxCalendarDateAttr", "setHoliday", 2}, // 1530 - {wxCalendarDateAttr_HasTextColour, "wxCalendarDateAttr", "hasTextColour", 1}, // 1531 - {wxCalendarDateAttr_HasBackgroundColour, "wxCalendarDateAttr", "hasBackgroundColour", 1}, // 1532 - {wxCalendarDateAttr_HasBorderColour, "wxCalendarDateAttr", "hasBorderColour", 1}, // 1533 - {wxCalendarDateAttr_HasFont, "wxCalendarDateAttr", "hasFont", 1}, // 1534 - {wxCalendarDateAttr_HasBorder, "wxCalendarDateAttr", "hasBorder", 1}, // 1535 - {wxCalendarDateAttr_IsHoliday, "wxCalendarDateAttr", "isHoliday", 1}, // 1536 - {wxCalendarDateAttr_GetTextColour, "wxCalendarDateAttr", "getTextColour", 1}, // 1537 - {wxCalendarDateAttr_GetBackgroundColour, "wxCalendarDateAttr", "getBackgroundColour", 1}, // 1538 - {wxCalendarDateAttr_GetBorderColour, "wxCalendarDateAttr", "getBorderColour", 1}, // 1539 - {wxCalendarDateAttr_GetFont, "wxCalendarDateAttr", "getFont", 1}, // 1540 - {wxCalendarDateAttr_GetBorder, "wxCalendarDateAttr", "getBorder", 1}, // 1541 - {wxCalendarDateAttr_destroy, "wxCalendarDateAttr", "'Destroy'", 1}, // 1542 - {wxCheckBox_new_0, "wxCheckBox", "new", 0}, // 1543 - {wxCheckBox_new_4, "wxCheckBox", "new", 4}, // 1544 - {NULL, "wxCheckBox", "destroy", 1}, // 1545 obj destructor wxCheckBox_destruct - {wxCheckBox_Create, "wxCheckBox", "create", 5}, // 1546 - {wxCheckBox_GetValue, "wxCheckBox", "getValue", 1}, // 1547 - {wxCheckBox_Get3StateValue, "wxCheckBox", "get3StateValue", 1}, // 1548 - {wxCheckBox_Is3rdStateAllowedForUser, "wxCheckBox", "is3rdStateAllowedForUser", 1}, // 1549 - {wxCheckBox_Is3State, "wxCheckBox", "is3State", 1}, // 1550 - {wxCheckBox_IsChecked, "wxCheckBox", "isChecked", 1}, // 1551 - {wxCheckBox_SetValue, "wxCheckBox", "setValue", 2}, // 1552 - {wxCheckBox_Set3StateValue, "wxCheckBox", "set3StateValue", 2}, // 1553 - {wxCheckListBox_new_0, "wxCheckListBox", "new", 0}, // 1554 - {NULL, "", "", 0}, // 1555 - {wxCheckListBox_new_3, "wxCheckListBox", "new", 3}, // 1556 - {NULL, "wxCheckListBox", "destroy", 1}, // 1557 obj destructor wxCheckListBox_destruct - {wxCheckListBox_Check, "wxCheckListBox", "check", 3}, // 1558 - {wxCheckListBox_IsChecked, "wxCheckListBox", "isChecked", 2}, // 1559 - {wxChoice_new_0, "wxChoice", "new", 0}, // 1560 - {NULL, "", "", 0}, // 1561 - {wxChoice_new_3, "wxChoice", "new", 3}, // 1562 - {NULL, "wxChoice", "destroy", 1}, // 1563 obj destructor wxChoice_destruct - {NULL, "", "", 0}, // 1564 - {wxChoice_Create, "wxChoice", "create", 7}, // 1565 - {wxChoice_Delete, "wxChoice", "delete", 2}, // 1566 - {wxChoice_GetColumns, "wxChoice", "getColumns", 1}, // 1567 - {wxChoice_SetColumns, "wxChoice", "setColumns", 2}, // 1568 - {wxComboBox_new_0, "wxComboBox", "new", 0}, // 1569 - {NULL, "", "", 0}, // 1570 - {wxComboBox_new_3, "wxComboBox", "new", 3}, // 1571 - {NULL, "wxComboBox", "destroy", 1}, // 1572 obj destructor wxComboBox_destruct - {NULL, "", "", 0}, // 1573 - {wxComboBox_Create, "wxComboBox", "create", 8}, // 1574 - {wxComboBox_CanCopy, "wxComboBox", "canCopy", 1}, // 1575 - {wxComboBox_CanCut, "wxComboBox", "canCut", 1}, // 1576 - {wxComboBox_CanPaste, "wxComboBox", "canPaste", 1}, // 1577 - {wxComboBox_CanRedo, "wxComboBox", "canRedo", 1}, // 1578 - {wxComboBox_CanUndo, "wxComboBox", "canUndo", 1}, // 1579 - {wxComboBox_Copy, "wxComboBox", "copy", 1}, // 1580 - {wxComboBox_Cut, "wxComboBox", "cut", 1}, // 1581 - {wxComboBox_GetInsertionPoint, "wxComboBox", "getInsertionPoint", 1}, // 1582 - {wxComboBox_GetLastPosition, "wxComboBox", "getLastPosition", 1}, // 1583 - {wxComboBox_GetValue, "wxComboBox", "getValue", 1}, // 1584 - {wxComboBox_Paste, "wxComboBox", "paste", 1}, // 1585 - {wxComboBox_Redo, "wxComboBox", "redo", 1}, // 1586 - {wxComboBox_Replace, "wxComboBox", "replace", 4}, // 1587 - {wxComboBox_Remove, "wxComboBox", "remove", 3}, // 1588 - {wxComboBox_SetInsertionPoint, "wxComboBox", "setInsertionPoint", 2}, // 1589 - {wxComboBox_SetInsertionPointEnd, "wxComboBox", "setInsertionPointEnd", 1}, // 1590 - {wxComboBox_SetSelection_2, "wxComboBox", "setSelection", 3}, // 1591 - {wxComboBox_SetSelection_1, "wxComboBox", "setSelection", 2}, // 1592 - {wxComboBox_SetValue, "wxComboBox", "setValue", 2}, // 1593 - {wxComboBox_Undo, "wxComboBox", "undo", 1}, // 1594 - {wxGauge_new_0, "wxGauge", "new", 0}, // 1595 - {wxGauge_new_4, "wxGauge", "new", 4}, // 1596 - {NULL, "wxGauge", "destroy", 1}, // 1597 obj destructor wxGauge_destruct - {wxGauge_Create, "wxGauge", "create", 5}, // 1598 - {wxGauge_GetRange, "wxGauge", "getRange", 1}, // 1599 - {wxGauge_GetValue, "wxGauge", "getValue", 1}, // 1600 - {wxGauge_IsVertical, "wxGauge", "isVertical", 1}, // 1601 - {wxGauge_SetRange, "wxGauge", "setRange", 2}, // 1602 - {wxGauge_SetValue, "wxGauge", "setValue", 2}, // 1603 - {wxGauge_Pulse, "wxGauge", "pulse", 1}, // 1604 - {wxGenericDirCtrl_new_0, "wxGenericDirCtrl", "new", 0}, // 1605 - {wxGenericDirCtrl_new_2, "wxGenericDirCtrl", "new", 2}, // 1606 - {NULL, "wxGenericDirCtrl", "destroy", 1}, // 1607 obj destructor wxGenericDirCtrl_destruct - {wxGenericDirCtrl_Create, "wxGenericDirCtrl", "create", 3}, // 1608 - {wxGenericDirCtrl_Init, "wxGenericDirCtrl", "init", 1}, // 1609 - {wxGenericDirCtrl_CollapseTree, "wxGenericDirCtrl", "collapseTree", 1}, // 1610 - {wxGenericDirCtrl_ExpandPath, "wxGenericDirCtrl", "expandPath", 2}, // 1611 - {wxGenericDirCtrl_GetDefaultPath, "wxGenericDirCtrl", "getDefaultPath", 1}, // 1612 - {wxGenericDirCtrl_GetPath_0, "wxGenericDirCtrl", "getPath", 1}, // 1613 - {wxGenericDirCtrl_GetPath_1, "wxGenericDirCtrl", "getPath", 2}, // 1614 - {wxGenericDirCtrl_GetFilePath, "wxGenericDirCtrl", "getFilePath", 1}, // 1615 - {wxGenericDirCtrl_GetFilter, "wxGenericDirCtrl", "getFilter", 1}, // 1616 - {wxGenericDirCtrl_GetFilterIndex, "wxGenericDirCtrl", "getFilterIndex", 1}, // 1617 - {wxGenericDirCtrl_GetRootId, "wxGenericDirCtrl", "getRootId", 1}, // 1618 - {wxGenericDirCtrl_GetTreeCtrl, "wxGenericDirCtrl", "getTreeCtrl", 1}, // 1619 - {wxGenericDirCtrl_ReCreateTree, "wxGenericDirCtrl", "reCreateTree", 1}, // 1620 - {wxGenericDirCtrl_SetDefaultPath, "wxGenericDirCtrl", "setDefaultPath", 2}, // 1621 - {wxGenericDirCtrl_SetFilter, "wxGenericDirCtrl", "setFilter", 2}, // 1622 - {wxGenericDirCtrl_SetFilterIndex, "wxGenericDirCtrl", "setFilterIndex", 2}, // 1623 - {wxGenericDirCtrl_SetPath, "wxGenericDirCtrl", "setPath", 2}, // 1624 - {wxStaticBox_new_0, "wxStaticBox", "new", 0}, // 1625 - {wxStaticBox_new_4, "wxStaticBox", "new", 4}, // 1626 - {NULL, "wxStaticBox", "destroy", 1}, // 1627 obj destructor wxStaticBox_destruct - {wxStaticBox_Create, "wxStaticBox", "create", 5}, // 1628 - {wxStaticLine_new_0, "wxStaticLine", "new", 0}, // 1629 - {wxStaticLine_new_2, "wxStaticLine", "new", 2}, // 1630 - {wxStaticLine_Create, "wxStaticLine", "create", 3}, // 1631 - {wxStaticLine_IsVertical, "wxStaticLine", "isVertical", 1}, // 1632 - {wxStaticLine_GetDefaultSize, "wxStaticLine", "getDefaultSize", 0}, // 1633 - {NULL, "wxStaticLine", "'Destroy'", 1}, // 1634 obj destructor wxStaticLine_destroy - {wxListBox_new_0, "wxListBox", "new", 0}, // 1635 - {NULL, "", "", 0}, // 1636 - {wxListBox_new_3, "wxListBox", "new", 3}, // 1637 - {NULL, "wxListBox", "destroy", 1}, // 1638 obj destructor wxListBox_destruct - {NULL, "", "", 0}, // 1639 - {wxListBox_Create, "wxListBox", "create", 7}, // 1640 - {wxListBox_Deselect, "wxListBox", "deselect", 2}, // 1641 - {wxListBox_GetSelections, "wxListBox", "getSelections", 1}, // 1642 - {wxListBox_InsertItems, "wxListBox", "insertItems", 3}, // 1643 - {wxListBox_IsSelected, "wxListBox", "isSelected", 2}, // 1644 - {NULL, "", "", 0}, // 1645 - {NULL, "", "", 0}, // 1646 - {wxListBox_Set, "wxListBox", "set", 2}, // 1647 - {wxListBox_HitTest_1, "wxListBox", "hitTest", 2}, // 1648 - {wxListBox_HitTest_2, "wxListBox", "hitTest", 3}, // 1649 - {wxListBox_SetFirstItem_1_0, "wxListBox", "setFirstItem", 2}, // 1650 - {wxListBox_SetFirstItem_1_1, "wxListBox", "setFirstItem", 2}, // 1651 - {wxListCtrl_new_0, "wxListCtrl", "new", 0}, // 1652 - {NULL, "wxListCtrl", "new", 2}, // 1653 TaylorMade erl only wxListCtrl_new_2 - {NULL, "wxListCtrl", "destroy", 1}, // 1654 obj destructor wxListCtrl_destruct - {wxListCtrl_Arrange, "wxListCtrl", "arrange", 2}, // 1655 - {wxListCtrl_AssignImageList, "wxListCtrl", "assignImageList", 3}, // 1656 - {wxListCtrl_ClearAll, "wxListCtrl", "clearAll", 1}, // 1657 - {wxListCtrl_Create, "wxListCtrl", "create", 3}, // 1658 - {wxListCtrl_DeleteAllItems, "wxListCtrl", "deleteAllItems", 1}, // 1659 - {wxListCtrl_DeleteColumn, "wxListCtrl", "deleteColumn", 2}, // 1660 - {wxListCtrl_DeleteItem, "wxListCtrl", "deleteItem", 2}, // 1661 - {wxListCtrl_EditLabel, "wxListCtrl", "editLabel", 2}, // 1662 - {wxListCtrl_EnsureVisible, "wxListCtrl", "ensureVisible", 2}, // 1663 - {wxListCtrl_FindItem_3_0, "wxListCtrl", "findItem", 4}, // 1664 - {wxListCtrl_FindItem_3_1, "wxListCtrl", "findItem", 4}, // 1665 - {wxListCtrl_GetColumn, "wxListCtrl", "getColumn", 3}, // 1666 - {wxListCtrl_GetColumnCount, "wxListCtrl", "getColumnCount", 1}, // 1667 - {wxListCtrl_GetColumnWidth, "wxListCtrl", "getColumnWidth", 2}, // 1668 - {wxListCtrl_GetCountPerPage, "wxListCtrl", "getCountPerPage", 1}, // 1669 - {wxListCtrl_GetEditControl, "wxListCtrl", "getEditControl", 1}, // 1670 - {wxListCtrl_GetImageList, "wxListCtrl", "getImageList", 2}, // 1671 - {wxListCtrl_GetItem, "wxListCtrl", "getItem", 2}, // 1672 - {wxListCtrl_GetItemBackgroundColour, "wxListCtrl", "getItemBackgroundColour", 2}, // 1673 - {wxListCtrl_GetItemCount, "wxListCtrl", "getItemCount", 1}, // 1674 - {wxListCtrl_GetItemData, "wxListCtrl", "getItemData", 2}, // 1675 - {wxListCtrl_GetItemFont, "wxListCtrl", "getItemFont", 2}, // 1676 - {wxListCtrl_GetItemPosition, "wxListCtrl", "getItemPosition", 2}, // 1677 - {wxListCtrl_GetItemRect, "wxListCtrl", "getItemRect", 3}, // 1678 - {wxListCtrl_GetItemSpacing, "wxListCtrl", "getItemSpacing", 1}, // 1679 - {wxListCtrl_GetItemState, "wxListCtrl", "getItemState", 3}, // 1680 - {wxListCtrl_GetItemText, "wxListCtrl", "getItemText", 3}, // 1681 - {wxListCtrl_GetItemTextColour, "wxListCtrl", "getItemTextColour", 2}, // 1682 - {wxListCtrl_GetNextItem, "wxListCtrl", "getNextItem", 3}, // 1683 - {wxListCtrl_GetSelectedItemCount, "wxListCtrl", "getSelectedItemCount", 1}, // 1684 - {wxListCtrl_GetTextColour, "wxListCtrl", "getTextColour", 1}, // 1685 - {wxListCtrl_GetTopItem, "wxListCtrl", "getTopItem", 1}, // 1686 - {wxListCtrl_GetViewRect, "wxListCtrl", "getViewRect", 1}, // 1687 - {wxListCtrl_HitTest, "wxListCtrl", "hitTest", 2}, // 1688 - {wxListCtrl_InsertColumn_2, "wxListCtrl", "insertColumn", 3}, // 1689 - {wxListCtrl_InsertColumn_3, "wxListCtrl", "insertColumn", 4}, // 1690 - {wxListCtrl_InsertItem_1, "wxListCtrl", "insertItem", 2}, // 1691 - {wxListCtrl_InsertItem_2_1, "wxListCtrl", "insertItem", 3}, // 1692 - {wxListCtrl_InsertItem_2_0, "wxListCtrl", "insertItem", 3}, // 1693 - {wxListCtrl_InsertItem_3, "wxListCtrl", "insertItem", 4}, // 1694 - {wxListCtrl_RefreshItem, "wxListCtrl", "refreshItem", 2}, // 1695 - {wxListCtrl_RefreshItems, "wxListCtrl", "refreshItems", 3}, // 1696 - {wxListCtrl_ScrollList, "wxListCtrl", "scrollList", 3}, // 1697 - {wxListCtrl_SetBackgroundColour, "wxListCtrl", "setBackgroundColour", 2}, // 1698 - {wxListCtrl_SetColumn, "wxListCtrl", "setColumn", 3}, // 1699 - {wxListCtrl_SetColumnWidth, "wxListCtrl", "setColumnWidth", 3}, // 1700 - {wxListCtrl_SetImageList, "wxListCtrl", "setImageList", 3}, // 1701 - {wxListCtrl_SetItem_1, "wxListCtrl", "setItem", 2}, // 1702 - {wxListCtrl_SetItem_4, "wxListCtrl", "setItem", 5}, // 1703 - {wxListCtrl_SetItemBackgroundColour, "wxListCtrl", "setItemBackgroundColour", 3}, // 1704 - {wxListCtrl_SetItemCount, "wxListCtrl", "setItemCount", 2}, // 1705 - {wxListCtrl_SetItemData, "wxListCtrl", "setItemData", 3}, // 1706 - {wxListCtrl_SetItemFont, "wxListCtrl", "setItemFont", 3}, // 1707 - {wxListCtrl_SetItemImage, "wxListCtrl", "setItemImage", 4}, // 1708 - {wxListCtrl_SetItemColumnImage, "wxListCtrl", "setItemColumnImage", 4}, // 1709 - {wxListCtrl_SetItemPosition, "wxListCtrl", "setItemPosition", 3}, // 1710 - {wxListCtrl_SetItemState, "wxListCtrl", "setItemState", 4}, // 1711 - {wxListCtrl_SetItemText, "wxListCtrl", "setItemText", 3}, // 1712 - {wxListCtrl_SetItemTextColour, "wxListCtrl", "setItemTextColour", 3}, // 1713 - {wxListCtrl_SetSingleStyle, "wxListCtrl", "setSingleStyle", 3}, // 1714 - {wxListCtrl_SetTextColour, "wxListCtrl", "setTextColour", 2}, // 1715 - {wxListCtrl_SetWindowStyleFlag, "wxListCtrl", "setWindowStyleFlag", 2}, // 1716 - {wxListCtrl_SortItems, "wxListCtrl", "sortItems", 2}, // 1717 - {wxListView_ClearColumnImage, "wxListView", "clearColumnImage", 2}, // 1718 - {wxListView_Focus, "wxListView", "focus", 2}, // 1719 - {wxListView_GetFirstSelected, "wxListView", "getFirstSelected", 1}, // 1720 - {wxListView_GetFocusedItem, "wxListView", "getFocusedItem", 1}, // 1721 - {wxListView_GetNextSelected, "wxListView", "getNextSelected", 2}, // 1722 - {wxListView_IsSelected, "wxListView", "isSelected", 2}, // 1723 - {wxListView_Select, "wxListView", "select", 3}, // 1724 - {wxListView_SetColumnImage, "wxListView", "setColumnImage", 3}, // 1725 - {wxListItem_new_0, "wxListItem", "new", 0}, // 1726 - {wxListItem_new_1, "wxListItem", "new", 1}, // 1727 - {wxListItem_Clear, "wxListItem", "clear", 1}, // 1728 - {wxListItem_GetAlign, "wxListItem", "getAlign", 1}, // 1729 - {wxListItem_GetBackgroundColour, "wxListItem", "getBackgroundColour", 1}, // 1730 - {wxListItem_GetColumn, "wxListItem", "getColumn", 1}, // 1731 - {wxListItem_GetFont, "wxListItem", "getFont", 1}, // 1732 - {wxListItem_GetId, "wxListItem", "getId", 1}, // 1733 - {wxListItem_GetImage, "wxListItem", "getImage", 1}, // 1734 - {wxListItem_GetMask, "wxListItem", "getMask", 1}, // 1735 - {wxListItem_GetState, "wxListItem", "getState", 1}, // 1736 - {wxListItem_GetText, "wxListItem", "getText", 1}, // 1737 - {wxListItem_GetTextColour, "wxListItem", "getTextColour", 1}, // 1738 - {wxListItem_GetWidth, "wxListItem", "getWidth", 1}, // 1739 - {wxListItem_SetAlign, "wxListItem", "setAlign", 2}, // 1740 - {wxListItem_SetBackgroundColour, "wxListItem", "setBackgroundColour", 2}, // 1741 - {wxListItem_SetColumn, "wxListItem", "setColumn", 2}, // 1742 - {wxListItem_SetFont, "wxListItem", "setFont", 2}, // 1743 - {wxListItem_SetId, "wxListItem", "setId", 2}, // 1744 - {wxListItem_SetImage, "wxListItem", "setImage", 2}, // 1745 - {wxListItem_SetMask, "wxListItem", "setMask", 2}, // 1746 - {wxListItem_SetState, "wxListItem", "setState", 2}, // 1747 - {wxListItem_SetStateMask, "wxListItem", "setStateMask", 2}, // 1748 - {wxListItem_SetText, "wxListItem", "setText", 2}, // 1749 - {wxListItem_SetTextColour, "wxListItem", "setTextColour", 2}, // 1750 - {wxListItem_SetWidth, "wxListItem", "setWidth", 2}, // 1751 - {NULL, "wxListItem", "'Destroy'", 1}, // 1752 obj destructor wxListItem_destroy - {wxListItemAttr_new_0, "wxListItemAttr", "new", 0}, // 1753 - {wxListItemAttr_new_3, "wxListItemAttr", "new", 3}, // 1754 - {wxListItemAttr_GetBackgroundColour, "wxListItemAttr", "getBackgroundColour", 1}, // 1755 - {wxListItemAttr_GetFont, "wxListItemAttr", "getFont", 1}, // 1756 - {wxListItemAttr_GetTextColour, "wxListItemAttr", "getTextColour", 1}, // 1757 - {wxListItemAttr_HasBackgroundColour, "wxListItemAttr", "hasBackgroundColour", 1}, // 1758 - {wxListItemAttr_HasFont, "wxListItemAttr", "hasFont", 1}, // 1759 - {wxListItemAttr_HasTextColour, "wxListItemAttr", "hasTextColour", 1}, // 1760 - {wxListItemAttr_SetBackgroundColour, "wxListItemAttr", "setBackgroundColour", 2}, // 1761 - {wxListItemAttr_SetFont, "wxListItemAttr", "setFont", 2}, // 1762 - {wxListItemAttr_SetTextColour, "wxListItemAttr", "setTextColour", 2}, // 1763 - {wxListItemAttr_destroy, "wxListItemAttr", "'Destroy'", 1}, // 1764 - {wxImageList_new_0, "wxImageList", "new", 0}, // 1765 - {wxImageList_new_3, "wxImageList", "new", 3}, // 1766 - {wxImageList_Add_2_0, "wxImageList", "add", 3}, // 1767 - {NULL, "", "", 0}, // 1768 - {wxImageList_Add_2_1, "wxImageList", "add", 3}, // 1769 - {wxImageList_Add_1, "wxImageList", "add", 2}, // 1770 - {wxImageList_Create, "wxImageList", "create", 4}, // 1771 - {wxImageList_Draw, "wxImageList", "draw", 6}, // 1772 - {wxImageList_GetBitmap, "wxImageList", "getBitmap", 2}, // 1773 - {wxImageList_GetIcon, "wxImageList", "getIcon", 2}, // 1774 - {wxImageList_GetImageCount, "wxImageList", "getImageCount", 1}, // 1775 - {wxImageList_GetSize, "wxImageList", "getSize", 2}, // 1776 - {NULL, "", "", 0}, // 1777 - {wxImageList_Remove, "wxImageList", "remove", 2}, // 1778 - {wxImageList_RemoveAll, "wxImageList", "removeAll", 1}, // 1779 - {wxImageList_Replace_3, "wxImageList", "replace", 4}, // 1780 - {NULL, "", "", 0}, // 1781 - {wxImageList_Replace_2, "wxImageList", "replace", 3}, // 1782 - {NULL, "wxImageList", "'Destroy'", 1}, // 1783 obj destructor wxImageList_destroy - {wxTextAttr_new_0, "wxTextAttr", "new", 0}, // 1784 - {wxTextAttr_new_2, "wxTextAttr", "new", 2}, // 1785 - {wxTextAttr_new_1, "wxTextAttr", "new", 1}, // 1786 - {wxTextAttr_GetAlignment, "wxTextAttr", "getAlignment", 1}, // 1787 - {wxTextAttr_GetBackgroundColour, "wxTextAttr", "getBackgroundColour", 1}, // 1788 - {wxTextAttr_GetFont, "wxTextAttr", "getFont", 1}, // 1789 - {wxTextAttr_GetFontEncoding, "wxTextAttr", "getFontEncoding", 1}, // 1790 - {wxTextAttr_GetFontFaceName, "wxTextAttr", "getFontFaceName", 1}, // 1791 - {wxTextAttr_GetFontSize, "wxTextAttr", "getFontSize", 1}, // 1792 - {wxTextAttr_GetFontStyle, "wxTextAttr", "getFontStyle", 1}, // 1793 - {wxTextAttr_GetFontUnderlined, "wxTextAttr", "getFontUnderlined", 1}, // 1794 - {wxTextAttr_GetFontWeight, "wxTextAttr", "getFontWeight", 1}, // 1795 - {wxTextAttr_GetLeftIndent, "wxTextAttr", "getLeftIndent", 1}, // 1796 - {wxTextAttr_GetLeftSubIndent, "wxTextAttr", "getLeftSubIndent", 1}, // 1797 - {wxTextAttr_GetRightIndent, "wxTextAttr", "getRightIndent", 1}, // 1798 - {wxTextAttr_GetTabs, "wxTextAttr", "getTabs", 1}, // 1799 - {wxTextAttr_GetTextColour, "wxTextAttr", "getTextColour", 1}, // 1800 - {wxTextAttr_HasBackgroundColour, "wxTextAttr", "hasBackgroundColour", 1}, // 1801 - {wxTextAttr_HasFont, "wxTextAttr", "hasFont", 1}, // 1802 - {wxTextAttr_HasTextColour, "wxTextAttr", "hasTextColour", 1}, // 1803 - {wxTextAttr_GetFlags, "wxTextAttr", "getFlags", 1}, // 1804 - {wxTextAttr_IsDefault, "wxTextAttr", "isDefault", 1}, // 1805 - {wxTextAttr_SetAlignment, "wxTextAttr", "setAlignment", 2}, // 1806 - {wxTextAttr_SetBackgroundColour, "wxTextAttr", "setBackgroundColour", 2}, // 1807 - {wxTextAttr_SetFlags, "wxTextAttr", "setFlags", 2}, // 1808 - {wxTextAttr_SetFont, "wxTextAttr", "setFont", 3}, // 1809 - {wxTextAttr_SetFontEncoding, "wxTextAttr", "setFontEncoding", 2}, // 1810 - {wxTextAttr_SetFontFaceName, "wxTextAttr", "setFontFaceName", 2}, // 1811 - {wxTextAttr_SetFontFamily, "wxTextAttr", "setFontFamily", 2}, // 1812 - {wxTextAttr_SetFontSize, "wxTextAttr", "setFontSize", 2}, // 1813 - {wxTextAttr_SetFontPointSize, "wxTextAttr", "setFontPointSize", 2}, // 1814 - {wxTextAttr_SetFontPixelSize, "wxTextAttr", "setFontPixelSize", 2}, // 1815 - {wxTextAttr_SetFontStyle, "wxTextAttr", "setFontStyle", 2}, // 1816 - {wxTextAttr_SetFontUnderlined, "wxTextAttr", "setFontUnderlined", 2}, // 1817 - {wxTextAttr_SetFontWeight, "wxTextAttr", "setFontWeight", 2}, // 1818 - {wxTextAttr_SetLeftIndent, "wxTextAttr", "setLeftIndent", 3}, // 1819 - {wxTextAttr_SetRightIndent, "wxTextAttr", "setRightIndent", 2}, // 1820 - {wxTextAttr_SetTabs, "wxTextAttr", "setTabs", 2}, // 1821 - {wxTextAttr_SetTextColour, "wxTextAttr", "setTextColour", 2}, // 1822 - {wxTextAttr_destroy, "wxTextAttr", "'Destroy'", 1}, // 1823 - {wxTextCtrl_new_0, "wxTextCtrl", "new", 0}, // 1824 - {wxTextCtrl_new_3, "wxTextCtrl", "new", 3}, // 1825 - {NULL, "wxTextCtrl", "destroy", 1}, // 1826 obj destructor wxTextCtrl_destruct - {wxTextCtrl_AppendText, "wxTextCtrl", "appendText", 2}, // 1827 - {wxTextCtrl_CanCopy, "wxTextCtrl", "canCopy", 1}, // 1828 - {wxTextCtrl_CanCut, "wxTextCtrl", "canCut", 1}, // 1829 - {wxTextCtrl_CanPaste, "wxTextCtrl", "canPaste", 1}, // 1830 - {wxTextCtrl_CanRedo, "wxTextCtrl", "canRedo", 1}, // 1831 - {wxTextCtrl_CanUndo, "wxTextCtrl", "canUndo", 1}, // 1832 - {wxTextCtrl_Clear, "wxTextCtrl", "clear", 1}, // 1833 - {wxTextCtrl_Copy, "wxTextCtrl", "copy", 1}, // 1834 - {wxTextCtrl_Create, "wxTextCtrl", "create", 4}, // 1835 - {wxTextCtrl_Cut, "wxTextCtrl", "cut", 1}, // 1836 - {wxTextCtrl_DiscardEdits, "wxTextCtrl", "discardEdits", 1}, // 1837 - {wxTextCtrl_ChangeValue, "wxTextCtrl", "changeValue", 2}, // 1838 - {wxTextCtrl_EmulateKeyPress, "wxTextCtrl", "emulateKeyPress", 2}, // 1839 - {wxTextCtrl_GetDefaultStyle, "wxTextCtrl", "getDefaultStyle", 1}, // 1840 - {wxTextCtrl_GetInsertionPoint, "wxTextCtrl", "getInsertionPoint", 1}, // 1841 - {wxTextCtrl_GetLastPosition, "wxTextCtrl", "getLastPosition", 1}, // 1842 - {wxTextCtrl_GetLineLength, "wxTextCtrl", "getLineLength", 2}, // 1843 - {wxTextCtrl_GetLineText, "wxTextCtrl", "getLineText", 2}, // 1844 - {wxTextCtrl_GetNumberOfLines, "wxTextCtrl", "getNumberOfLines", 1}, // 1845 - {wxTextCtrl_GetRange, "wxTextCtrl", "getRange", 3}, // 1846 - {wxTextCtrl_GetSelection, "wxTextCtrl", "getSelection", 1}, // 1847 - {wxTextCtrl_GetStringSelection, "wxTextCtrl", "getStringSelection", 1}, // 1848 - {wxTextCtrl_GetStyle, "wxTextCtrl", "getStyle", 3}, // 1849 - {wxTextCtrl_GetValue, "wxTextCtrl", "getValue", 1}, // 1850 - {wxTextCtrl_IsEditable, "wxTextCtrl", "isEditable", 1}, // 1851 - {wxTextCtrl_IsModified, "wxTextCtrl", "isModified", 1}, // 1852 - {wxTextCtrl_IsMultiLine, "wxTextCtrl", "isMultiLine", 1}, // 1853 - {wxTextCtrl_IsSingleLine, "wxTextCtrl", "isSingleLine", 1}, // 1854 - {wxTextCtrl_LoadFile, "wxTextCtrl", "loadFile", 3}, // 1855 - {wxTextCtrl_MarkDirty, "wxTextCtrl", "markDirty", 1}, // 1856 - {wxTextCtrl_Paste, "wxTextCtrl", "paste", 1}, // 1857 - {wxTextCtrl_PositionToXY, "wxTextCtrl", "positionToXY", 2}, // 1858 - {wxTextCtrl_Redo, "wxTextCtrl", "redo", 1}, // 1859 - {wxTextCtrl_Remove, "wxTextCtrl", "remove", 3}, // 1860 - {wxTextCtrl_Replace, "wxTextCtrl", "replace", 4}, // 1861 - {wxTextCtrl_SaveFile, "wxTextCtrl", "saveFile", 2}, // 1862 - {wxTextCtrl_SetDefaultStyle, "wxTextCtrl", "setDefaultStyle", 2}, // 1863 - {wxTextCtrl_SetEditable, "wxTextCtrl", "setEditable", 2}, // 1864 - {wxTextCtrl_SetInsertionPoint, "wxTextCtrl", "setInsertionPoint", 2}, // 1865 - {wxTextCtrl_SetInsertionPointEnd, "wxTextCtrl", "setInsertionPointEnd", 1}, // 1866 - {wxTextCtrl_SetMaxLength, "wxTextCtrl", "setMaxLength", 2}, // 1867 - {wxTextCtrl_SetSelection, "wxTextCtrl", "setSelection", 3}, // 1868 - {wxTextCtrl_SetStyle, "wxTextCtrl", "setStyle", 4}, // 1869 - {wxTextCtrl_SetValue, "wxTextCtrl", "setValue", 2}, // 1870 - {wxTextCtrl_ShowPosition, "wxTextCtrl", "showPosition", 2}, // 1871 - {wxTextCtrl_Undo, "wxTextCtrl", "undo", 1}, // 1872 - {wxTextCtrl_WriteText, "wxTextCtrl", "writeText", 2}, // 1873 - {wxTextCtrl_XYToPosition, "wxTextCtrl", "xYToPosition", 3}, // 1874 - {wxBookCtrlBase_AddPage, "wxBookCtrlBase", "addPage", 4}, // 1875 - {wxBookCtrlBase_InsertPage, "wxBookCtrlBase", "insertPage", 5}, // 1876 - {wxBookCtrlBase_DeletePage, "wxBookCtrlBase", "deletePage", 2}, // 1877 - {wxBookCtrlBase_RemovePage, "wxBookCtrlBase", "removePage", 2}, // 1878 - {wxBookCtrlBase_DeleteAllPages, "wxBookCtrlBase", "deleteAllPages", 1}, // 1879 - {wxBookCtrlBase_GetPage, "wxBookCtrlBase", "getPage", 2}, // 1880 - {wxBookCtrlBase_GetPageCount, "wxBookCtrlBase", "getPageCount", 1}, // 1881 - {wxBookCtrlBase_GetCurrentPage, "wxBookCtrlBase", "getCurrentPage", 1}, // 1882 - {wxBookCtrlBase_AdvanceSelection, "wxBookCtrlBase", "advanceSelection", 2}, // 1883 - {wxBookCtrlBase_SetSelection, "wxBookCtrlBase", "setSelection", 2}, // 1884 - {wxBookCtrlBase_GetSelection, "wxBookCtrlBase", "getSelection", 1}, // 1885 - {wxBookCtrlBase_ChangeSelection, "wxBookCtrlBase", "changeSelection", 2}, // 1886 - {wxBookCtrlBase_HitTest, "wxBookCtrlBase", "hitTest", 2}, // 1887 - {wxBookCtrlBase_GetPageText, "wxBookCtrlBase", "getPageText", 2}, // 1888 - {wxBookCtrlBase_SetPageText, "wxBookCtrlBase", "setPageText", 3}, // 1889 - {wxNotebook_new_0, "wxNotebook", "new", 0}, // 1890 - {wxNotebook_new_3, "wxNotebook", "new", 3}, // 1891 - {NULL, "wxNotebook", "destroy", 1}, // 1892 obj destructor wxNotebook_destruct - {wxNotebook_AssignImageList, "wxNotebook", "assignImageList", 2}, // 1893 - {wxNotebook_Create, "wxNotebook", "create", 4}, // 1894 - {wxNotebook_GetImageList, "wxNotebook", "getImageList", 1}, // 1895 - {wxNotebook_GetPageImage, "wxNotebook", "getPageImage", 2}, // 1896 - {wxNotebook_GetRowCount, "wxNotebook", "getRowCount", 1}, // 1897 - {wxNotebook_GetThemeBackgroundColour, "wxNotebook", "getThemeBackgroundColour", 1}, // 1898 - {wxNotebook_SetImageList, "wxNotebook", "setImageList", 2}, // 1899 - {wxNotebook_SetPadding, "wxNotebook", "setPadding", 2}, // 1900 - {wxNotebook_SetPageSize, "wxNotebook", "setPageSize", 2}, // 1901 - {wxNotebook_SetPageImage, "wxNotebook", "setPageImage", 3}, // 1902 - {wxChoicebook_new_0, "wxChoicebook", "new", 0}, // 1903 - {wxChoicebook_new_3, "wxChoicebook", "new", 3}, // 1904 - {wxChoicebook_AddPage, "wxChoicebook", "addPage", 4}, // 1905 - {wxChoicebook_AdvanceSelection, "wxChoicebook", "advanceSelection", 2}, // 1906 - {wxChoicebook_AssignImageList, "wxChoicebook", "assignImageList", 2}, // 1907 - {wxChoicebook_Create, "wxChoicebook", "create", 4}, // 1908 - {wxChoicebook_DeleteAllPages, "wxChoicebook", "deleteAllPages", 1}, // 1909 - {wxChoicebook_GetCurrentPage, "wxChoicebook", "getCurrentPage", 1}, // 1910 - {wxChoicebook_GetImageList, "wxChoicebook", "getImageList", 1}, // 1911 - {wxChoicebook_GetPage, "wxChoicebook", "getPage", 2}, // 1912 - {wxChoicebook_GetPageCount, "wxChoicebook", "getPageCount", 1}, // 1913 - {wxChoicebook_GetPageImage, "wxChoicebook", "getPageImage", 2}, // 1914 - {wxChoicebook_GetPageText, "wxChoicebook", "getPageText", 2}, // 1915 - {wxChoicebook_GetSelection, "wxChoicebook", "getSelection", 1}, // 1916 - {wxChoicebook_HitTest, "wxChoicebook", "hitTest", 2}, // 1917 - {wxChoicebook_InsertPage, "wxChoicebook", "insertPage", 5}, // 1918 - {wxChoicebook_SetImageList, "wxChoicebook", "setImageList", 2}, // 1919 - {wxChoicebook_SetPageSize, "wxChoicebook", "setPageSize", 2}, // 1920 - {wxChoicebook_SetPageImage, "wxChoicebook", "setPageImage", 3}, // 1921 - {wxChoicebook_SetPageText, "wxChoicebook", "setPageText", 3}, // 1922 - {wxChoicebook_SetSelection, "wxChoicebook", "setSelection", 2}, // 1923 - {wxChoicebook_ChangeSelection, "wxChoicebook", "changeSelection", 2}, // 1924 - {NULL, "wxChoicebook", "'Destroy'", 1}, // 1925 obj destructor wxChoicebook_destroy - {wxToolbook_new_0, "wxToolbook", "new", 0}, // 1926 - {wxToolbook_new_3, "wxToolbook", "new", 3}, // 1927 - {wxToolbook_AddPage, "wxToolbook", "addPage", 4}, // 1928 - {wxToolbook_AdvanceSelection, "wxToolbook", "advanceSelection", 2}, // 1929 - {wxToolbook_AssignImageList, "wxToolbook", "assignImageList", 2}, // 1930 - {wxToolbook_Create, "wxToolbook", "create", 4}, // 1931 - {wxToolbook_DeleteAllPages, "wxToolbook", "deleteAllPages", 1}, // 1932 - {wxToolbook_GetCurrentPage, "wxToolbook", "getCurrentPage", 1}, // 1933 - {wxToolbook_GetImageList, "wxToolbook", "getImageList", 1}, // 1934 - {wxToolbook_GetPage, "wxToolbook", "getPage", 2}, // 1935 - {wxToolbook_GetPageCount, "wxToolbook", "getPageCount", 1}, // 1936 - {wxToolbook_GetPageImage, "wxToolbook", "getPageImage", 2}, // 1937 - {wxToolbook_GetPageText, "wxToolbook", "getPageText", 2}, // 1938 - {wxToolbook_GetSelection, "wxToolbook", "getSelection", 1}, // 1939 - {wxToolbook_HitTest, "wxToolbook", "hitTest", 2}, // 1940 - {wxToolbook_InsertPage, "wxToolbook", "insertPage", 5}, // 1941 - {wxToolbook_SetImageList, "wxToolbook", "setImageList", 2}, // 1942 - {wxToolbook_SetPageSize, "wxToolbook", "setPageSize", 2}, // 1943 - {wxToolbook_SetPageImage, "wxToolbook", "setPageImage", 3}, // 1944 - {wxToolbook_SetPageText, "wxToolbook", "setPageText", 3}, // 1945 - {wxToolbook_SetSelection, "wxToolbook", "setSelection", 2}, // 1946 - {wxToolbook_ChangeSelection, "wxToolbook", "changeSelection", 2}, // 1947 - {NULL, "wxToolbook", "'Destroy'", 1}, // 1948 obj destructor wxToolbook_destroy - {wxListbook_new_0, "wxListbook", "new", 0}, // 1949 - {wxListbook_new_3, "wxListbook", "new", 3}, // 1950 - {wxListbook_AddPage, "wxListbook", "addPage", 4}, // 1951 - {wxListbook_AdvanceSelection, "wxListbook", "advanceSelection", 2}, // 1952 - {wxListbook_AssignImageList, "wxListbook", "assignImageList", 2}, // 1953 - {wxListbook_Create, "wxListbook", "create", 4}, // 1954 - {wxListbook_DeleteAllPages, "wxListbook", "deleteAllPages", 1}, // 1955 - {wxListbook_GetCurrentPage, "wxListbook", "getCurrentPage", 1}, // 1956 - {wxListbook_GetImageList, "wxListbook", "getImageList", 1}, // 1957 - {wxListbook_GetPage, "wxListbook", "getPage", 2}, // 1958 - {wxListbook_GetPageCount, "wxListbook", "getPageCount", 1}, // 1959 - {wxListbook_GetPageImage, "wxListbook", "getPageImage", 2}, // 1960 - {wxListbook_GetPageText, "wxListbook", "getPageText", 2}, // 1961 - {wxListbook_GetSelection, "wxListbook", "getSelection", 1}, // 1962 - {wxListbook_HitTest, "wxListbook", "hitTest", 2}, // 1963 - {wxListbook_InsertPage, "wxListbook", "insertPage", 5}, // 1964 - {wxListbook_SetImageList, "wxListbook", "setImageList", 2}, // 1965 - {wxListbook_SetPageSize, "wxListbook", "setPageSize", 2}, // 1966 - {wxListbook_SetPageImage, "wxListbook", "setPageImage", 3}, // 1967 - {wxListbook_SetPageText, "wxListbook", "setPageText", 3}, // 1968 - {wxListbook_SetSelection, "wxListbook", "setSelection", 2}, // 1969 - {wxListbook_ChangeSelection, "wxListbook", "changeSelection", 2}, // 1970 - {NULL, "wxListbook", "'Destroy'", 1}, // 1971 obj destructor wxListbook_destroy - {wxTreebook_new_0, "wxTreebook", "new", 0}, // 1972 - {wxTreebook_new_3, "wxTreebook", "new", 3}, // 1973 - {NULL, "wxTreebook", "destroy", 1}, // 1974 obj destructor wxTreebook_destruct - {wxTreebook_AddPage, "wxTreebook", "addPage", 4}, // 1975 - {wxTreebook_AdvanceSelection, "wxTreebook", "advanceSelection", 2}, // 1976 - {wxTreebook_AssignImageList, "wxTreebook", "assignImageList", 2}, // 1977 - {wxTreebook_Create, "wxTreebook", "create", 4}, // 1978 - {wxTreebook_DeleteAllPages, "wxTreebook", "deleteAllPages", 1}, // 1979 - {wxTreebook_GetCurrentPage, "wxTreebook", "getCurrentPage", 1}, // 1980 - {wxTreebook_GetImageList, "wxTreebook", "getImageList", 1}, // 1981 - {wxTreebook_GetPage, "wxTreebook", "getPage", 2}, // 1982 - {wxTreebook_GetPageCount, "wxTreebook", "getPageCount", 1}, // 1983 - {wxTreebook_GetPageImage, "wxTreebook", "getPageImage", 2}, // 1984 - {wxTreebook_GetPageText, "wxTreebook", "getPageText", 2}, // 1985 - {wxTreebook_GetSelection, "wxTreebook", "getSelection", 1}, // 1986 - {wxTreebook_ExpandNode, "wxTreebook", "expandNode", 3}, // 1987 - {wxTreebook_IsNodeExpanded, "wxTreebook", "isNodeExpanded", 2}, // 1988 - {wxTreebook_HitTest, "wxTreebook", "hitTest", 2}, // 1989 - {wxTreebook_InsertPage, "wxTreebook", "insertPage", 5}, // 1990 - {wxTreebook_InsertSubPage, "wxTreebook", "insertSubPage", 5}, // 1991 - {wxTreebook_SetImageList, "wxTreebook", "setImageList", 2}, // 1992 - {wxTreebook_SetPageSize, "wxTreebook", "setPageSize", 2}, // 1993 - {wxTreebook_SetPageImage, "wxTreebook", "setPageImage", 3}, // 1994 - {wxTreebook_SetPageText, "wxTreebook", "setPageText", 3}, // 1995 - {wxTreebook_SetSelection, "wxTreebook", "setSelection", 2}, // 1996 - {wxTreebook_ChangeSelection, "wxTreebook", "changeSelection", 2}, // 1997 - {wxTreeCtrl_new_0, "wxTreeCtrl", "new", 0}, // 1998 - {wxTreeCtrl_new_2, "wxTreeCtrl", "new", 2}, // 1999 - {NULL, "wxTreeCtrl", "destroy", 1}, // 2000 obj destructor wxTreeCtrl_destruct - {wxTreeCtrl_AddRoot, "wxTreeCtrl", "addRoot", 3}, // 2001 - {wxTreeCtrl_AppendItem, "wxTreeCtrl", "appendItem", 4}, // 2002 - {wxTreeCtrl_AssignImageList, "wxTreeCtrl", "assignImageList", 2}, // 2003 - {wxTreeCtrl_AssignStateImageList, "wxTreeCtrl", "assignStateImageList", 2}, // 2004 - {wxTreeCtrl_Collapse, "wxTreeCtrl", "collapse", 2}, // 2005 - {wxTreeCtrl_CollapseAndReset, "wxTreeCtrl", "collapseAndReset", 2}, // 2006 - {wxTreeCtrl_Create, "wxTreeCtrl", "create", 3}, // 2007 - {wxTreeCtrl_Delete, "wxTreeCtrl", "delete", 2}, // 2008 - {wxTreeCtrl_DeleteAllItems, "wxTreeCtrl", "deleteAllItems", 1}, // 2009 - {wxTreeCtrl_DeleteChildren, "wxTreeCtrl", "deleteChildren", 2}, // 2010 - {wxTreeCtrl_EditLabel, "wxTreeCtrl", "editLabel", 2}, // 2011 - {wxTreeCtrl_EnsureVisible, "wxTreeCtrl", "ensureVisible", 2}, // 2012 - {wxTreeCtrl_Expand, "wxTreeCtrl", "expand", 2}, // 2013 - {wxTreeCtrl_GetBoundingRect, "wxTreeCtrl", "getBoundingRect", 3}, // 2014 - {wxTreeCtrl_GetChildrenCount, "wxTreeCtrl", "getChildrenCount", 3}, // 2015 - {wxTreeCtrl_GetCount, "wxTreeCtrl", "getCount", 1}, // 2016 - {wxTreeCtrl_GetEditControl, "wxTreeCtrl", "getEditControl", 1}, // 2017 - {wxTreeCtrl_GetFirstChild, "wxTreeCtrl", "getFirstChild", 2}, // 2018 - {wxTreeCtrl_GetNextChild, "wxTreeCtrl", "getNextChild", 3}, // 2019 - {wxTreeCtrl_GetFirstVisibleItem, "wxTreeCtrl", "getFirstVisibleItem", 1}, // 2020 - {wxTreeCtrl_GetImageList, "wxTreeCtrl", "getImageList", 1}, // 2021 - {wxTreeCtrl_GetIndent, "wxTreeCtrl", "getIndent", 1}, // 2022 - {wxTreeCtrl_GetItemBackgroundColour, "wxTreeCtrl", "getItemBackgroundColour", 2}, // 2023 - {wxTreeCtrl_GetItemData, "wxTreeCtrl", "getItemData", 2}, // 2024 - {wxTreeCtrl_GetItemFont, "wxTreeCtrl", "getItemFont", 2}, // 2025 - {wxTreeCtrl_GetItemImage, "wxTreeCtrl", "getItemImage", 3}, // 2026 - {wxTreeCtrl_GetItemText, "wxTreeCtrl", "getItemText", 2}, // 2027 - {wxTreeCtrl_GetItemTextColour, "wxTreeCtrl", "getItemTextColour", 2}, // 2028 - {wxTreeCtrl_GetLastChild, "wxTreeCtrl", "getLastChild", 2}, // 2029 - {wxTreeCtrl_GetNextSibling, "wxTreeCtrl", "getNextSibling", 2}, // 2030 - {wxTreeCtrl_GetNextVisible, "wxTreeCtrl", "getNextVisible", 2}, // 2031 - {wxTreeCtrl_GetItemParent, "wxTreeCtrl", "getItemParent", 2}, // 2032 - {wxTreeCtrl_GetPrevSibling, "wxTreeCtrl", "getPrevSibling", 2}, // 2033 - {wxTreeCtrl_GetPrevVisible, "wxTreeCtrl", "getPrevVisible", 2}, // 2034 - {wxTreeCtrl_GetRootItem, "wxTreeCtrl", "getRootItem", 1}, // 2035 - {wxTreeCtrl_GetSelection, "wxTreeCtrl", "getSelection", 1}, // 2036 - {wxTreeCtrl_GetSelections, "wxTreeCtrl", "getSelections", 1}, // 2037 - {wxTreeCtrl_GetStateImageList, "wxTreeCtrl", "getStateImageList", 1}, // 2038 - {wxTreeCtrl_HitTest, "wxTreeCtrl", "hitTest", 2}, // 2039 - {wxTreeCtrl_InsertItem, "wxTreeCtrl", "insertItem", 5}, // 2040 - {NULL, "", "", 0}, // 2041 - {wxTreeCtrl_IsBold, "wxTreeCtrl", "isBold", 2}, // 2042 - {wxTreeCtrl_IsExpanded, "wxTreeCtrl", "isExpanded", 2}, // 2043 - {wxTreeCtrl_IsSelected, "wxTreeCtrl", "isSelected", 2}, // 2044 - {wxTreeCtrl_IsVisible, "wxTreeCtrl", "isVisible", 2}, // 2045 - {wxTreeCtrl_ItemHasChildren, "wxTreeCtrl", "itemHasChildren", 2}, // 2046 - {wxTreeCtrl_IsTreeItemIdOk, "wxTreeCtrl", "isTreeItemIdOk", 1}, // 2047 - {wxTreeCtrl_PrependItem, "wxTreeCtrl", "prependItem", 4}, // 2048 - {wxTreeCtrl_ScrollTo, "wxTreeCtrl", "scrollTo", 2}, // 2049 - {wxTreeCtrl_SelectItem, "wxTreeCtrl", "selectItem", 3}, // 2050 - {wxTreeCtrl_SetIndent, "wxTreeCtrl", "setIndent", 2}, // 2051 - {wxTreeCtrl_SetImageList, "wxTreeCtrl", "setImageList", 2}, // 2052 - {wxTreeCtrl_SetItemBackgroundColour, "wxTreeCtrl", "setItemBackgroundColour", 3}, // 2053 - {wxTreeCtrl_SetItemBold, "wxTreeCtrl", "setItemBold", 3}, // 2054 - {wxTreeCtrl_SetItemData, "wxTreeCtrl", "setItemData", 3}, // 2055 - {wxTreeCtrl_SetItemDropHighlight, "wxTreeCtrl", "setItemDropHighlight", 3}, // 2056 - {wxTreeCtrl_SetItemFont, "wxTreeCtrl", "setItemFont", 3}, // 2057 - {wxTreeCtrl_SetItemHasChildren, "wxTreeCtrl", "setItemHasChildren", 3}, // 2058 - {wxTreeCtrl_SetItemImage, "wxTreeCtrl", "setItemImage", 4}, // 2059 - {wxTreeCtrl_SetItemText, "wxTreeCtrl", "setItemText", 3}, // 2060 - {wxTreeCtrl_SetItemTextColour, "wxTreeCtrl", "setItemTextColour", 3}, // 2061 - {wxTreeCtrl_SetStateImageList, "wxTreeCtrl", "setStateImageList", 2}, // 2062 - {wxTreeCtrl_SetWindowStyle, "wxTreeCtrl", "setWindowStyle", 2}, // 2063 - {wxTreeCtrl_SortChildren, "wxTreeCtrl", "sortChildren", 2}, // 2064 - {wxTreeCtrl_Toggle, "wxTreeCtrl", "toggle", 2}, // 2065 - {wxTreeCtrl_ToggleItemSelection, "wxTreeCtrl", "toggleItemSelection", 2}, // 2066 - {wxTreeCtrl_Unselect, "wxTreeCtrl", "unselect", 1}, // 2067 - {wxTreeCtrl_UnselectAll, "wxTreeCtrl", "unselectAll", 1}, // 2068 - {wxTreeCtrl_UnselectItem, "wxTreeCtrl", "unselectItem", 2}, // 2069 - {wxScrollBar_new_0, "wxScrollBar", "new", 0}, // 2070 - {wxScrollBar_new_3, "wxScrollBar", "new", 3}, // 2071 - {NULL, "wxScrollBar", "destroy", 1}, // 2072 obj destructor wxScrollBar_destruct - {wxScrollBar_Create, "wxScrollBar", "create", 4}, // 2073 - {wxScrollBar_GetRange, "wxScrollBar", "getRange", 1}, // 2074 - {wxScrollBar_GetPageSize, "wxScrollBar", "getPageSize", 1}, // 2075 - {wxScrollBar_GetThumbPosition, "wxScrollBar", "getThumbPosition", 1}, // 2076 - {wxScrollBar_GetThumbSize, "wxScrollBar", "getThumbSize", 1}, // 2077 - {wxScrollBar_SetThumbPosition, "wxScrollBar", "setThumbPosition", 2}, // 2078 - {wxScrollBar_SetScrollbar, "wxScrollBar", "setScrollbar", 6}, // 2079 - {wxSpinButton_new_0, "wxSpinButton", "new", 0}, // 2080 - {wxSpinButton_new_2, "wxSpinButton", "new", 2}, // 2081 - {NULL, "wxSpinButton", "destroy", 1}, // 2082 obj destructor wxSpinButton_destruct - {wxSpinButton_Create, "wxSpinButton", "create", 3}, // 2083 - {wxSpinButton_GetMax, "wxSpinButton", "getMax", 1}, // 2084 - {wxSpinButton_GetMin, "wxSpinButton", "getMin", 1}, // 2085 - {wxSpinButton_GetValue, "wxSpinButton", "getValue", 1}, // 2086 - {wxSpinButton_SetRange, "wxSpinButton", "setRange", 3}, // 2087 - {wxSpinButton_SetValue, "wxSpinButton", "setValue", 2}, // 2088 - {wxSpinCtrl_new_0, "wxSpinCtrl", "new", 0}, // 2089 - {wxSpinCtrl_new_2, "wxSpinCtrl", "new", 2}, // 2090 - {wxSpinCtrl_Create, "wxSpinCtrl", "create", 3}, // 2091 - {wxSpinCtrl_SetValue_1_1, "wxSpinCtrl", "setValue", 2}, // 2092 - {wxSpinCtrl_SetValue_1_0, "wxSpinCtrl", "setValue", 2}, // 2093 - {wxSpinCtrl_GetValue, "wxSpinCtrl", "getValue", 1}, // 2094 - {wxSpinCtrl_SetRange, "wxSpinCtrl", "setRange", 3}, // 2095 - {wxSpinCtrl_SetSelection, "wxSpinCtrl", "setSelection", 3}, // 2096 - {wxSpinCtrl_GetMin, "wxSpinCtrl", "getMin", 1}, // 2097 - {wxSpinCtrl_GetMax, "wxSpinCtrl", "getMax", 1}, // 2098 - {NULL, "wxSpinCtrl", "'Destroy'", 1}, // 2099 obj destructor wxSpinCtrl_destroy - {wxStaticText_new_0, "wxStaticText", "new", 0}, // 2100 - {wxStaticText_new_4, "wxStaticText", "new", 4}, // 2101 - {wxStaticText_Create, "wxStaticText", "create", 5}, // 2102 - {wxStaticText_GetLabel, "wxStaticText", "getLabel", 1}, // 2103 - {wxStaticText_SetLabel, "wxStaticText", "setLabel", 2}, // 2104 - {wxStaticText_Wrap, "wxStaticText", "wrap", 2}, // 2105 - {NULL, "wxStaticText", "'Destroy'", 1}, // 2106 obj destructor wxStaticText_destroy - {wxStaticBitmap_new_0, "wxStaticBitmap", "new", 0}, // 2107 - {wxStaticBitmap_new_4, "wxStaticBitmap", "new", 4}, // 2108 - {wxStaticBitmap_Create, "wxStaticBitmap", "create", 5}, // 2109 - {wxStaticBitmap_GetBitmap, "wxStaticBitmap", "getBitmap", 1}, // 2110 - {wxStaticBitmap_SetBitmap, "wxStaticBitmap", "setBitmap", 2}, // 2111 - {NULL, "wxStaticBitmap", "'Destroy'", 1}, // 2112 obj destructor wxStaticBitmap_destroy - {wxRadioBox_new, "wxRadioBox", "new", 7}, // 2113 - {NULL, "wxRadioBox", "destroy", 1}, // 2114 obj destructor wxRadioBox_destruct - {wxRadioBox_Create, "wxRadioBox", "create", 8}, // 2115 - {wxRadioBox_Enable_1, "wxRadioBox", "enable", 2}, // 2116 - {wxRadioBox_Enable_2, "wxRadioBox", "enable", 3}, // 2117 - {wxRadioBox_GetSelection, "wxRadioBox", "getSelection", 1}, // 2118 - {wxRadioBox_GetString, "wxRadioBox", "getString", 2}, // 2119 - {wxRadioBox_SetSelection, "wxRadioBox", "setSelection", 2}, // 2120 - {wxRadioBox_Show, "wxRadioBox", "show", 3}, // 2121 - {wxRadioBox_GetColumnCount, "wxRadioBox", "getColumnCount", 1}, // 2122 - {wxRadioBox_GetItemHelpText, "wxRadioBox", "getItemHelpText", 2}, // 2123 - {wxRadioBox_GetItemToolTip, "wxRadioBox", "getItemToolTip", 2}, // 2124 - {wxRadioBox_GetItemFromPoint, "wxRadioBox", "getItemFromPoint", 2}, // 2125 - {wxRadioBox_GetRowCount, "wxRadioBox", "getRowCount", 1}, // 2126 - {wxRadioBox_IsItemEnabled, "wxRadioBox", "isItemEnabled", 2}, // 2127 - {wxRadioBox_IsItemShown, "wxRadioBox", "isItemShown", 2}, // 2128 - {wxRadioBox_SetItemHelpText, "wxRadioBox", "setItemHelpText", 3}, // 2129 - {wxRadioBox_SetItemToolTip, "wxRadioBox", "setItemToolTip", 3}, // 2130 - {wxRadioButton_new_0, "wxRadioButton", "new", 0}, // 2131 - {wxRadioButton_new_4, "wxRadioButton", "new", 4}, // 2132 - {NULL, "wxRadioButton", "destroy", 1}, // 2133 obj destructor wxRadioButton_destruct - {wxRadioButton_Create, "wxRadioButton", "create", 5}, // 2134 - {wxRadioButton_GetValue, "wxRadioButton", "getValue", 1}, // 2135 - {wxRadioButton_SetValue, "wxRadioButton", "setValue", 2}, // 2136 - {wxSlider_new_0, "wxSlider", "new", 0}, // 2137 - {wxSlider_new_6, "wxSlider", "new", 6}, // 2138 - {NULL, "wxSlider", "destroy", 1}, // 2139 obj destructor wxSlider_destruct - {wxSlider_Create, "wxSlider", "create", 7}, // 2140 - {wxSlider_GetLineSize, "wxSlider", "getLineSize", 1}, // 2141 - {wxSlider_GetMax, "wxSlider", "getMax", 1}, // 2142 - {wxSlider_GetMin, "wxSlider", "getMin", 1}, // 2143 - {wxSlider_GetPageSize, "wxSlider", "getPageSize", 1}, // 2144 - {wxSlider_GetThumbLength, "wxSlider", "getThumbLength", 1}, // 2145 - {wxSlider_GetValue, "wxSlider", "getValue", 1}, // 2146 - {wxSlider_SetLineSize, "wxSlider", "setLineSize", 2}, // 2147 - {wxSlider_SetPageSize, "wxSlider", "setPageSize", 2}, // 2148 - {wxSlider_SetRange, "wxSlider", "setRange", 3}, // 2149 - {wxSlider_SetThumbLength, "wxSlider", "setThumbLength", 2}, // 2150 - {wxSlider_SetValue, "wxSlider", "setValue", 2}, // 2151 - {wxDialog_new_0, "wxDialog", "new", 0}, // 2152 - {wxDialog_new_4, "wxDialog", "new", 4}, // 2153 - {NULL, "wxDialog", "destroy", 1}, // 2154 obj destructor wxDialog_destruct - {wxDialog_Create, "wxDialog", "create", 5}, // 2155 - {wxDialog_CreateButtonSizer, "wxDialog", "createButtonSizer", 2}, // 2156 - {wxDialog_CreateStdDialogButtonSizer, "wxDialog", "createStdDialogButtonSizer", 2}, // 2157 - {wxDialog_EndModal, "wxDialog", "endModal", 2}, // 2158 - {wxDialog_GetAffirmativeId, "wxDialog", "getAffirmativeId", 1}, // 2159 - {wxDialog_GetReturnCode, "wxDialog", "getReturnCode", 1}, // 2160 - {wxDialog_IsModal, "wxDialog", "isModal", 1}, // 2161 - {wxDialog_SetAffirmativeId, "wxDialog", "setAffirmativeId", 2}, // 2162 - {wxDialog_SetReturnCode, "wxDialog", "setReturnCode", 2}, // 2163 - {wxDialog_Show, "wxDialog", "show", 2}, // 2164 - {wxDialog_ShowModal, "wxDialog", "showModal", 1}, // 2165 - {wxColourDialog_new_0, "wxColourDialog", "new", 0}, // 2166 - {wxColourDialog_new_2, "wxColourDialog", "new", 2}, // 2167 - {NULL, "wxColourDialog", "destroy", 1}, // 2168 obj destructor wxColourDialog_destruct - {wxColourDialog_Create, "wxColourDialog", "create", 3}, // 2169 - {wxColourDialog_GetColourData, "wxColourDialog", "getColourData", 1}, // 2170 - {wxColourData_new, "wxColourData", "new", 0}, // 2171 - {NULL, "wxColourData", "destroy", 1}, // 2172 obj destructor wxColourData_destruct - {wxColourData_GetChooseFull, "wxColourData", "getChooseFull", 1}, // 2173 - {wxColourData_GetColour, "wxColourData", "getColour", 1}, // 2174 - {wxColourData_GetCustomColour, "wxColourData", "getCustomColour", 2}, // 2175 - {wxColourData_SetChooseFull, "wxColourData", "setChooseFull", 2}, // 2176 - {wxColourData_SetColour, "wxColourData", "setColour", 2}, // 2177 - {wxColourData_SetCustomColour, "wxColourData", "setCustomColour", 3}, // 2178 - {wxPalette_new_0, "wxPalette", "new", 0}, // 2179 - {wxPalette_new_1, "wxPalette", "new", 1}, // 2180 - {wxPalette_new_4, "wxPalette", "new", 3}, // 2181 - {NULL, "wxPalette", "destroy", 1}, // 2182 obj destructor wxPalette_destruct - {wxPalette_Create, "wxPalette", "create", 4}, // 2183 - {wxPalette_GetColoursCount, "wxPalette", "getColoursCount", 1}, // 2184 - {wxPalette_GetPixel, "wxPalette", "getPixel", 4}, // 2185 - {wxPalette_GetRGB, "wxPalette", "getRGB", 2}, // 2186 - {wxPalette_IsOk, "wxPalette", "isOk", 1}, // 2187 - {wxDirDialog_new, "wxDirDialog", "new", 2}, // 2188 - {NULL, "wxDirDialog", "destroy", 1}, // 2189 obj destructor wxDirDialog_destruct - {wxDirDialog_GetPath, "wxDirDialog", "getPath", 1}, // 2190 - {wxDirDialog_GetMessage, "wxDirDialog", "getMessage", 1}, // 2191 - {wxDirDialog_SetMessage, "wxDirDialog", "setMessage", 2}, // 2192 - {wxDirDialog_SetPath, "wxDirDialog", "setPath", 2}, // 2193 - {wxFileDialog_new, "wxFileDialog", "new", 2}, // 2194 - {NULL, "wxFileDialog", "destroy", 1}, // 2195 obj destructor wxFileDialog_destruct - {wxFileDialog_GetDirectory, "wxFileDialog", "getDirectory", 1}, // 2196 - {wxFileDialog_GetFilename, "wxFileDialog", "getFilename", 1}, // 2197 - {wxFileDialog_GetFilenames, "wxFileDialog", "getFilenames", 1}, // 2198 - {wxFileDialog_GetFilterIndex, "wxFileDialog", "getFilterIndex", 1}, // 2199 - {wxFileDialog_GetMessage, "wxFileDialog", "getMessage", 1}, // 2200 - {wxFileDialog_GetPath, "wxFileDialog", "getPath", 1}, // 2201 - {wxFileDialog_GetPaths, "wxFileDialog", "getPaths", 1}, // 2202 - {wxFileDialog_GetWildcard, "wxFileDialog", "getWildcard", 1}, // 2203 - {wxFileDialog_SetDirectory, "wxFileDialog", "setDirectory", 2}, // 2204 - {wxFileDialog_SetFilename, "wxFileDialog", "setFilename", 2}, // 2205 - {wxFileDialog_SetFilterIndex, "wxFileDialog", "setFilterIndex", 2}, // 2206 - {wxFileDialog_SetMessage, "wxFileDialog", "setMessage", 2}, // 2207 - {wxFileDialog_SetPath, "wxFileDialog", "setPath", 2}, // 2208 - {wxFileDialog_SetWildcard, "wxFileDialog", "setWildcard", 2}, // 2209 - {wxPickerBase_SetInternalMargin, "wxPickerBase", "setInternalMargin", 2}, // 2210 - {wxPickerBase_GetInternalMargin, "wxPickerBase", "getInternalMargin", 1}, // 2211 - {wxPickerBase_SetTextCtrlProportion, "wxPickerBase", "setTextCtrlProportion", 2}, // 2212 - {wxPickerBase_SetPickerCtrlProportion, "wxPickerBase", "setPickerCtrlProportion", 2}, // 2213 - {wxPickerBase_GetTextCtrlProportion, "wxPickerBase", "getTextCtrlProportion", 1}, // 2214 - {wxPickerBase_GetPickerCtrlProportion, "wxPickerBase", "getPickerCtrlProportion", 1}, // 2215 - {wxPickerBase_HasTextCtrl, "wxPickerBase", "hasTextCtrl", 1}, // 2216 - {wxPickerBase_GetTextCtrl, "wxPickerBase", "getTextCtrl", 1}, // 2217 - {wxPickerBase_IsTextCtrlGrowable, "wxPickerBase", "isTextCtrlGrowable", 1}, // 2218 - {wxPickerBase_SetPickerCtrlGrowable, "wxPickerBase", "setPickerCtrlGrowable", 2}, // 2219 - {wxPickerBase_SetTextCtrlGrowable, "wxPickerBase", "setTextCtrlGrowable", 2}, // 2220 - {wxPickerBase_IsPickerCtrlGrowable, "wxPickerBase", "isPickerCtrlGrowable", 1}, // 2221 - {wxFilePickerCtrl_new_0, "wxFilePickerCtrl", "new", 0}, // 2222 - {wxFilePickerCtrl_new_3, "wxFilePickerCtrl", "new", 3}, // 2223 - {wxFilePickerCtrl_Create, "wxFilePickerCtrl", "create", 4}, // 2224 - {wxFilePickerCtrl_GetPath, "wxFilePickerCtrl", "getPath", 1}, // 2225 - {wxFilePickerCtrl_SetPath, "wxFilePickerCtrl", "setPath", 2}, // 2226 - {NULL, "wxFilePickerCtrl", "'Destroy'", 1}, // 2227 obj destructor wxFilePickerCtrl_destroy - {wxDirPickerCtrl_new_0, "wxDirPickerCtrl", "new", 0}, // 2228 - {wxDirPickerCtrl_new_3, "wxDirPickerCtrl", "new", 3}, // 2229 - {wxDirPickerCtrl_Create, "wxDirPickerCtrl", "create", 4}, // 2230 - {wxDirPickerCtrl_GetPath, "wxDirPickerCtrl", "getPath", 1}, // 2231 - {wxDirPickerCtrl_SetPath, "wxDirPickerCtrl", "setPath", 2}, // 2232 - {NULL, "wxDirPickerCtrl", "'Destroy'", 1}, // 2233 obj destructor wxDirPickerCtrl_destroy - {wxColourPickerCtrl_new_0, "wxColourPickerCtrl", "new", 0}, // 2234 - {wxColourPickerCtrl_new_3, "wxColourPickerCtrl", "new", 3}, // 2235 - {wxColourPickerCtrl_Create, "wxColourPickerCtrl", "create", 4}, // 2236 - {wxColourPickerCtrl_GetColour, "wxColourPickerCtrl", "getColour", 1}, // 2237 - {wxColourPickerCtrl_SetColour_1_1, "wxColourPickerCtrl", "setColour", 2}, // 2238 - {wxColourPickerCtrl_SetColour_1_0, "wxColourPickerCtrl", "setColour", 2}, // 2239 - {NULL, "wxColourPickerCtrl", "'Destroy'", 1}, // 2240 obj destructor wxColourPickerCtrl_destroy - {wxDatePickerCtrl_new_0, "wxDatePickerCtrl", "new", 0}, // 2241 - {wxDatePickerCtrl_new_3, "wxDatePickerCtrl", "new", 3}, // 2242 - {wxDatePickerCtrl_GetRange, "wxDatePickerCtrl", "getRange", 3}, // 2243 - {wxDatePickerCtrl_GetValue, "wxDatePickerCtrl", "getValue", 1}, // 2244 - {wxDatePickerCtrl_SetRange, "wxDatePickerCtrl", "setRange", 3}, // 2245 - {wxDatePickerCtrl_SetValue, "wxDatePickerCtrl", "setValue", 2}, // 2246 - {NULL, "wxDatePickerCtrl", "'Destroy'", 1}, // 2247 obj destructor wxDatePickerCtrl_destroy - {wxFontPickerCtrl_new_0, "wxFontPickerCtrl", "new", 0}, // 2248 - {wxFontPickerCtrl_new_3, "wxFontPickerCtrl", "new", 3}, // 2249 - {wxFontPickerCtrl_Create, "wxFontPickerCtrl", "create", 4}, // 2250 - {wxFontPickerCtrl_GetSelectedFont, "wxFontPickerCtrl", "getSelectedFont", 1}, // 2251 - {wxFontPickerCtrl_SetSelectedFont, "wxFontPickerCtrl", "setSelectedFont", 2}, // 2252 - {wxFontPickerCtrl_GetMaxPointSize, "wxFontPickerCtrl", "getMaxPointSize", 1}, // 2253 - {wxFontPickerCtrl_SetMaxPointSize, "wxFontPickerCtrl", "setMaxPointSize", 2}, // 2254 - {NULL, "wxFontPickerCtrl", "'Destroy'", 1}, // 2255 obj destructor wxFontPickerCtrl_destroy - {wxFindReplaceDialog_new_0, "wxFindReplaceDialog", "new", 0}, // 2256 - {wxFindReplaceDialog_new_4, "wxFindReplaceDialog", "new", 4}, // 2257 - {NULL, "wxFindReplaceDialog", "destroy", 1}, // 2258 obj destructor wxFindReplaceDialog_destruct - {wxFindReplaceDialog_Create, "wxFindReplaceDialog", "create", 5}, // 2259 - {wxFindReplaceDialog_GetData, "wxFindReplaceDialog", "getData", 1}, // 2260 - {wxFindReplaceData_new, "wxFindReplaceData", "new", 1}, // 2261 - {wxFindReplaceData_GetFindString, "wxFindReplaceData", "getFindString", 1}, // 2262 - {wxFindReplaceData_GetReplaceString, "wxFindReplaceData", "getReplaceString", 1}, // 2263 - {wxFindReplaceData_GetFlags, "wxFindReplaceData", "getFlags", 1}, // 2264 - {wxFindReplaceData_SetFlags, "wxFindReplaceData", "setFlags", 2}, // 2265 - {wxFindReplaceData_SetFindString, "wxFindReplaceData", "setFindString", 2}, // 2266 - {wxFindReplaceData_SetReplaceString, "wxFindReplaceData", "setReplaceString", 2}, // 2267 - {NULL, "wxFindReplaceData", "'Destroy'", 1}, // 2268 obj destructor wxFindReplaceData_destroy - {NULL, "", "", 0}, // 2269 - {wxMultiChoiceDialog_new, "wxMultiChoiceDialog", "new", 5}, // 2270 - {wxMultiChoiceDialog_GetSelections, "wxMultiChoiceDialog", "getSelections", 1}, // 2271 - {wxMultiChoiceDialog_SetSelections, "wxMultiChoiceDialog", "setSelections", 2}, // 2272 - {NULL, "wxMultiChoiceDialog", "'Destroy'", 1}, // 2273 obj destructor wxMultiChoiceDialog_destroy - {NULL, "", "", 0}, // 2274 - {wxSingleChoiceDialog_new, "wxSingleChoiceDialog", "new", 5}, // 2275 - {wxSingleChoiceDialog_GetSelection, "wxSingleChoiceDialog", "getSelection", 1}, // 2276 - {wxSingleChoiceDialog_GetStringSelection, "wxSingleChoiceDialog", "getStringSelection", 1}, // 2277 - {wxSingleChoiceDialog_SetSelection, "wxSingleChoiceDialog", "setSelection", 2}, // 2278 - {NULL, "wxSingleChoiceDialog", "'Destroy'", 1}, // 2279 obj destructor wxSingleChoiceDialog_destroy - {wxTextEntryDialog_new_0, "wxTextEntryDialog", "new", 0}, // 2280 - {wxTextEntryDialog_new_3, "wxTextEntryDialog", "new", 3}, // 2281 - {NULL, "wxTextEntryDialog", "destroy", 1}, // 2282 obj destructor wxTextEntryDialog_destruct - {wxTextEntryDialog_GetValue, "wxTextEntryDialog", "getValue", 1}, // 2283 - {wxTextEntryDialog_SetValue, "wxTextEntryDialog", "setValue", 2}, // 2284 - {wxPasswordEntryDialog_new, "wxPasswordEntryDialog", "new", 3}, // 2285 - {NULL, "wxPasswordEntryDialog", "'Destroy'", 1}, // 2286 obj destructor wxPasswordEntryDialog_destroy - {wxFontData_new_0, "wxFontData", "new", 0}, // 2287 - {wxFontData_new_1, "wxFontData", "new", 1}, // 2288 - {wxFontData_EnableEffects, "wxFontData", "enableEffects", 2}, // 2289 - {wxFontData_GetAllowSymbols, "wxFontData", "getAllowSymbols", 1}, // 2290 - {wxFontData_GetColour, "wxFontData", "getColour", 1}, // 2291 - {wxFontData_GetChosenFont, "wxFontData", "getChosenFont", 1}, // 2292 - {wxFontData_GetEnableEffects, "wxFontData", "getEnableEffects", 1}, // 2293 - {wxFontData_GetInitialFont, "wxFontData", "getInitialFont", 1}, // 2294 - {wxFontData_GetShowHelp, "wxFontData", "getShowHelp", 1}, // 2295 - {wxFontData_SetAllowSymbols, "wxFontData", "setAllowSymbols", 2}, // 2296 - {wxFontData_SetChosenFont, "wxFontData", "setChosenFont", 2}, // 2297 - {wxFontData_SetColour, "wxFontData", "setColour", 2}, // 2298 - {wxFontData_SetInitialFont, "wxFontData", "setInitialFont", 2}, // 2299 - {wxFontData_SetRange, "wxFontData", "setRange", 3}, // 2300 - {wxFontData_SetShowHelp, "wxFontData", "setShowHelp", 2}, // 2301 - {NULL, "wxFontData", "'Destroy'", 1}, // 2302 obj destructor wxFontData_destroy - {wxFontDialog_new_0, "wxFontDialog", "new", 0}, // 2303 - {NULL, "", "", 0}, // 2304 - {wxFontDialog_new_2, "wxFontDialog", "new", 2}, // 2305 + {wxCalendarCtrl_EnableMonthChange, "wxCalendarCtrl", "enableMonthChange", 2}, // 1509 + {wxCalendarCtrl_EnableHolidayDisplay, "wxCalendarCtrl", "enableHolidayDisplay", 2}, // 1510 + {wxCalendarCtrl_SetHeaderColours, "wxCalendarCtrl", "setHeaderColours", 3}, // 1511 + {wxCalendarCtrl_GetHeaderColourFg, "wxCalendarCtrl", "getHeaderColourFg", 1}, // 1512 + {wxCalendarCtrl_GetHeaderColourBg, "wxCalendarCtrl", "getHeaderColourBg", 1}, // 1513 + {wxCalendarCtrl_SetHighlightColours, "wxCalendarCtrl", "setHighlightColours", 3}, // 1514 + {wxCalendarCtrl_GetHighlightColourFg, "wxCalendarCtrl", "getHighlightColourFg", 1}, // 1515 + {wxCalendarCtrl_GetHighlightColourBg, "wxCalendarCtrl", "getHighlightColourBg", 1}, // 1516 + {wxCalendarCtrl_SetHolidayColours, "wxCalendarCtrl", "setHolidayColours", 3}, // 1517 + {wxCalendarCtrl_GetHolidayColourFg, "wxCalendarCtrl", "getHolidayColourFg", 1}, // 1518 + {wxCalendarCtrl_GetHolidayColourBg, "wxCalendarCtrl", "getHolidayColourBg", 1}, // 1519 + {wxCalendarCtrl_GetAttr, "wxCalendarCtrl", "getAttr", 2}, // 1520 + {wxCalendarCtrl_SetAttr, "wxCalendarCtrl", "setAttr", 3}, // 1521 + {wxCalendarCtrl_SetHoliday, "wxCalendarCtrl", "setHoliday", 2}, // 1522 + {wxCalendarCtrl_ResetAttr, "wxCalendarCtrl", "resetAttr", 2}, // 1523 + {wxCalendarCtrl_HitTest, "wxCalendarCtrl", "hitTest", 2}, // 1524 + {wxCalendarDateAttr_new_1, "wxCalendarDateAttr", "new", 1}, // 1525 + {wxCalendarDateAttr_new_2, "wxCalendarDateAttr", "new", 2}, // 1526 + {wxCalendarDateAttr_SetTextColour, "wxCalendarDateAttr", "setTextColour", 2}, // 1527 + {wxCalendarDateAttr_SetBackgroundColour, "wxCalendarDateAttr", "setBackgroundColour", 2}, // 1528 + {wxCalendarDateAttr_SetBorderColour, "wxCalendarDateAttr", "setBorderColour", 2}, // 1529 + {wxCalendarDateAttr_SetFont, "wxCalendarDateAttr", "setFont", 2}, // 1530 + {wxCalendarDateAttr_SetBorder, "wxCalendarDateAttr", "setBorder", 2}, // 1531 + {wxCalendarDateAttr_SetHoliday, "wxCalendarDateAttr", "setHoliday", 2}, // 1532 + {wxCalendarDateAttr_HasTextColour, "wxCalendarDateAttr", "hasTextColour", 1}, // 1533 + {wxCalendarDateAttr_HasBackgroundColour, "wxCalendarDateAttr", "hasBackgroundColour", 1}, // 1534 + {wxCalendarDateAttr_HasBorderColour, "wxCalendarDateAttr", "hasBorderColour", 1}, // 1535 + {wxCalendarDateAttr_HasFont, "wxCalendarDateAttr", "hasFont", 1}, // 1536 + {wxCalendarDateAttr_HasBorder, "wxCalendarDateAttr", "hasBorder", 1}, // 1537 + {wxCalendarDateAttr_IsHoliday, "wxCalendarDateAttr", "isHoliday", 1}, // 1538 + {wxCalendarDateAttr_GetTextColour, "wxCalendarDateAttr", "getTextColour", 1}, // 1539 + {wxCalendarDateAttr_GetBackgroundColour, "wxCalendarDateAttr", "getBackgroundColour", 1}, // 1540 + {wxCalendarDateAttr_GetBorderColour, "wxCalendarDateAttr", "getBorderColour", 1}, // 1541 + {wxCalendarDateAttr_GetFont, "wxCalendarDateAttr", "getFont", 1}, // 1542 + {wxCalendarDateAttr_GetBorder, "wxCalendarDateAttr", "getBorder", 1}, // 1543 + {wxCalendarDateAttr_destroy, "wxCalendarDateAttr", "'Destroy'", 1}, // 1544 + {wxCheckBox_new_0, "wxCheckBox", "new", 0}, // 1545 + {wxCheckBox_new_4, "wxCheckBox", "new", 4}, // 1546 + {NULL, "wxCheckBox", "destroy", 1}, // 1547 obj destructor wxCheckBox_destruct + {wxCheckBox_Create, "wxCheckBox", "create", 5}, // 1548 + {wxCheckBox_GetValue, "wxCheckBox", "getValue", 1}, // 1549 + {wxCheckBox_Get3StateValue, "wxCheckBox", "get3StateValue", 1}, // 1550 + {wxCheckBox_Is3rdStateAllowedForUser, "wxCheckBox", "is3rdStateAllowedForUser", 1}, // 1551 + {wxCheckBox_Is3State, "wxCheckBox", "is3State", 1}, // 1552 + {wxCheckBox_IsChecked, "wxCheckBox", "isChecked", 1}, // 1553 + {wxCheckBox_SetValue, "wxCheckBox", "setValue", 2}, // 1554 + {wxCheckBox_Set3StateValue, "wxCheckBox", "set3StateValue", 2}, // 1555 + {wxCheckListBox_new_0, "wxCheckListBox", "new", 0}, // 1556 + {NULL, "", "", 0}, // 1557 + {wxCheckListBox_new_3, "wxCheckListBox", "new", 3}, // 1558 + {NULL, "wxCheckListBox", "destroy", 1}, // 1559 obj destructor wxCheckListBox_destruct + {wxCheckListBox_Check, "wxCheckListBox", "check", 3}, // 1560 + {wxCheckListBox_IsChecked, "wxCheckListBox", "isChecked", 2}, // 1561 + {wxChoice_new_0, "wxChoice", "new", 0}, // 1562 + {NULL, "", "", 0}, // 1563 + {wxChoice_new_3, "wxChoice", "new", 3}, // 1564 + {NULL, "wxChoice", "destroy", 1}, // 1565 obj destructor wxChoice_destruct + {NULL, "", "", 0}, // 1566 + {wxChoice_Create, "wxChoice", "create", 7}, // 1567 + {wxChoice_Delete, "wxChoice", "delete", 2}, // 1568 + {wxChoice_GetColumns, "wxChoice", "getColumns", 1}, // 1569 + {wxChoice_SetColumns, "wxChoice", "setColumns", 2}, // 1570 + {wxComboBox_new_0, "wxComboBox", "new", 0}, // 1571 + {NULL, "", "", 0}, // 1572 + {wxComboBox_new_3, "wxComboBox", "new", 3}, // 1573 + {NULL, "wxComboBox", "destroy", 1}, // 1574 obj destructor wxComboBox_destruct + {NULL, "", "", 0}, // 1575 + {wxComboBox_Create, "wxComboBox", "create", 8}, // 1576 + {wxComboBox_CanCopy, "wxComboBox", "canCopy", 1}, // 1577 + {wxComboBox_CanCut, "wxComboBox", "canCut", 1}, // 1578 + {wxComboBox_CanPaste, "wxComboBox", "canPaste", 1}, // 1579 + {wxComboBox_CanRedo, "wxComboBox", "canRedo", 1}, // 1580 + {wxComboBox_CanUndo, "wxComboBox", "canUndo", 1}, // 1581 + {wxComboBox_Copy, "wxComboBox", "copy", 1}, // 1582 + {wxComboBox_Cut, "wxComboBox", "cut", 1}, // 1583 + {wxComboBox_GetInsertionPoint, "wxComboBox", "getInsertionPoint", 1}, // 1584 + {wxComboBox_GetLastPosition, "wxComboBox", "getLastPosition", 1}, // 1585 + {wxComboBox_GetValue, "wxComboBox", "getValue", 1}, // 1586 + {wxComboBox_Paste, "wxComboBox", "paste", 1}, // 1587 + {wxComboBox_Redo, "wxComboBox", "redo", 1}, // 1588 + {wxComboBox_Replace, "wxComboBox", "replace", 4}, // 1589 + {wxComboBox_Remove, "wxComboBox", "remove", 3}, // 1590 + {wxComboBox_SetInsertionPoint, "wxComboBox", "setInsertionPoint", 2}, // 1591 + {wxComboBox_SetInsertionPointEnd, "wxComboBox", "setInsertionPointEnd", 1}, // 1592 + {wxComboBox_SetSelection_2, "wxComboBox", "setSelection", 3}, // 1593 + {wxComboBox_SetSelection_1, "wxComboBox", "setSelection", 2}, // 1594 + {wxComboBox_SetValue, "wxComboBox", "setValue", 2}, // 1595 + {wxComboBox_Undo, "wxComboBox", "undo", 1}, // 1596 + {wxGauge_new_0, "wxGauge", "new", 0}, // 1597 + {wxGauge_new_4, "wxGauge", "new", 4}, // 1598 + {NULL, "wxGauge", "destroy", 1}, // 1599 obj destructor wxGauge_destruct + {wxGauge_Create, "wxGauge", "create", 5}, // 1600 + {wxGauge_GetRange, "wxGauge", "getRange", 1}, // 1601 + {wxGauge_GetValue, "wxGauge", "getValue", 1}, // 1602 + {wxGauge_IsVertical, "wxGauge", "isVertical", 1}, // 1603 + {wxGauge_SetRange, "wxGauge", "setRange", 2}, // 1604 + {wxGauge_SetValue, "wxGauge", "setValue", 2}, // 1605 + {wxGauge_Pulse, "wxGauge", "pulse", 1}, // 1606 + {wxGenericDirCtrl_new_0, "wxGenericDirCtrl", "new", 0}, // 1607 + {wxGenericDirCtrl_new_2, "wxGenericDirCtrl", "new", 2}, // 1608 + {NULL, "wxGenericDirCtrl", "destroy", 1}, // 1609 obj destructor wxGenericDirCtrl_destruct + {wxGenericDirCtrl_Create, "wxGenericDirCtrl", "create", 3}, // 1610 + {wxGenericDirCtrl_Init, "wxGenericDirCtrl", "init", 1}, // 1611 + {wxGenericDirCtrl_CollapseTree, "wxGenericDirCtrl", "collapseTree", 1}, // 1612 + {wxGenericDirCtrl_ExpandPath, "wxGenericDirCtrl", "expandPath", 2}, // 1613 + {wxGenericDirCtrl_GetDefaultPath, "wxGenericDirCtrl", "getDefaultPath", 1}, // 1614 + {wxGenericDirCtrl_GetPath_0, "wxGenericDirCtrl", "getPath", 1}, // 1615 + {wxGenericDirCtrl_GetPath_1, "wxGenericDirCtrl", "getPath", 2}, // 1616 + {wxGenericDirCtrl_GetFilePath, "wxGenericDirCtrl", "getFilePath", 1}, // 1617 + {wxGenericDirCtrl_GetFilter, "wxGenericDirCtrl", "getFilter", 1}, // 1618 + {wxGenericDirCtrl_GetFilterIndex, "wxGenericDirCtrl", "getFilterIndex", 1}, // 1619 + {wxGenericDirCtrl_GetRootId, "wxGenericDirCtrl", "getRootId", 1}, // 1620 + {wxGenericDirCtrl_GetTreeCtrl, "wxGenericDirCtrl", "getTreeCtrl", 1}, // 1621 + {wxGenericDirCtrl_ReCreateTree, "wxGenericDirCtrl", "reCreateTree", 1}, // 1622 + {wxGenericDirCtrl_SetDefaultPath, "wxGenericDirCtrl", "setDefaultPath", 2}, // 1623 + {wxGenericDirCtrl_SetFilter, "wxGenericDirCtrl", "setFilter", 2}, // 1624 + {wxGenericDirCtrl_SetFilterIndex, "wxGenericDirCtrl", "setFilterIndex", 2}, // 1625 + {wxGenericDirCtrl_SetPath, "wxGenericDirCtrl", "setPath", 2}, // 1626 + {wxStaticBox_new_0, "wxStaticBox", "new", 0}, // 1627 + {wxStaticBox_new_4, "wxStaticBox", "new", 4}, // 1628 + {NULL, "wxStaticBox", "destroy", 1}, // 1629 obj destructor wxStaticBox_destruct + {wxStaticBox_Create, "wxStaticBox", "create", 5}, // 1630 + {wxStaticLine_new_0, "wxStaticLine", "new", 0}, // 1631 + {wxStaticLine_new_2, "wxStaticLine", "new", 2}, // 1632 + {wxStaticLine_Create, "wxStaticLine", "create", 3}, // 1633 + {wxStaticLine_IsVertical, "wxStaticLine", "isVertical", 1}, // 1634 + {wxStaticLine_GetDefaultSize, "wxStaticLine", "getDefaultSize", 0}, // 1635 + {NULL, "wxStaticLine", "'Destroy'", 1}, // 1636 obj destructor wxStaticLine_destroy + {wxListBox_new_0, "wxListBox", "new", 0}, // 1637 + {NULL, "", "", 0}, // 1638 + {wxListBox_new_3, "wxListBox", "new", 3}, // 1639 + {NULL, "wxListBox", "destroy", 1}, // 1640 obj destructor wxListBox_destruct + {NULL, "", "", 0}, // 1641 + {wxListBox_Create, "wxListBox", "create", 7}, // 1642 + {wxListBox_Deselect, "wxListBox", "deselect", 2}, // 1643 + {wxListBox_GetSelections, "wxListBox", "getSelections", 1}, // 1644 + {wxListBox_InsertItems, "wxListBox", "insertItems", 3}, // 1645 + {wxListBox_IsSelected, "wxListBox", "isSelected", 2}, // 1646 + {NULL, "", "", 0}, // 1647 + {NULL, "", "", 0}, // 1648 + {wxListBox_Set, "wxListBox", "set", 2}, // 1649 + {wxListBox_HitTest_1, "wxListBox", "hitTest", 2}, // 1650 + {wxListBox_HitTest_2, "wxListBox", "hitTest", 3}, // 1651 + {wxListBox_SetFirstItem_1_0, "wxListBox", "setFirstItem", 2}, // 1652 + {wxListBox_SetFirstItem_1_1, "wxListBox", "setFirstItem", 2}, // 1653 + {wxListCtrl_new_0, "wxListCtrl", "new", 0}, // 1654 + {NULL, "wxListCtrl", "new", 2}, // 1655 TaylorMade erl only wxListCtrl_new_2 + {NULL, "wxListCtrl", "destroy", 1}, // 1656 obj destructor wxListCtrl_destruct + {wxListCtrl_Arrange, "wxListCtrl", "arrange", 2}, // 1657 + {wxListCtrl_AssignImageList, "wxListCtrl", "assignImageList", 3}, // 1658 + {wxListCtrl_ClearAll, "wxListCtrl", "clearAll", 1}, // 1659 + {wxListCtrl_Create, "wxListCtrl", "create", 3}, // 1660 + {wxListCtrl_DeleteAllItems, "wxListCtrl", "deleteAllItems", 1}, // 1661 + {wxListCtrl_DeleteColumn, "wxListCtrl", "deleteColumn", 2}, // 1662 + {wxListCtrl_DeleteItem, "wxListCtrl", "deleteItem", 2}, // 1663 + {wxListCtrl_EditLabel, "wxListCtrl", "editLabel", 2}, // 1664 + {wxListCtrl_EnsureVisible, "wxListCtrl", "ensureVisible", 2}, // 1665 + {wxListCtrl_FindItem_3_0, "wxListCtrl", "findItem", 4}, // 1666 + {wxListCtrl_FindItem_3_1, "wxListCtrl", "findItem", 4}, // 1667 + {wxListCtrl_GetColumn, "wxListCtrl", "getColumn", 3}, // 1668 + {wxListCtrl_GetColumnCount, "wxListCtrl", "getColumnCount", 1}, // 1669 + {wxListCtrl_GetColumnWidth, "wxListCtrl", "getColumnWidth", 2}, // 1670 + {wxListCtrl_GetCountPerPage, "wxListCtrl", "getCountPerPage", 1}, // 1671 + {wxListCtrl_GetEditControl, "wxListCtrl", "getEditControl", 1}, // 1672 + {wxListCtrl_GetImageList, "wxListCtrl", "getImageList", 2}, // 1673 + {wxListCtrl_GetItem, "wxListCtrl", "getItem", 2}, // 1674 + {wxListCtrl_GetItemBackgroundColour, "wxListCtrl", "getItemBackgroundColour", 2}, // 1675 + {wxListCtrl_GetItemCount, "wxListCtrl", "getItemCount", 1}, // 1676 + {wxListCtrl_GetItemData, "wxListCtrl", "getItemData", 2}, // 1677 + {wxListCtrl_GetItemFont, "wxListCtrl", "getItemFont", 2}, // 1678 + {wxListCtrl_GetItemPosition, "wxListCtrl", "getItemPosition", 2}, // 1679 + {wxListCtrl_GetItemRect, "wxListCtrl", "getItemRect", 3}, // 1680 + {wxListCtrl_GetItemSpacing, "wxListCtrl", "getItemSpacing", 1}, // 1681 + {wxListCtrl_GetItemState, "wxListCtrl", "getItemState", 3}, // 1682 + {wxListCtrl_GetItemText, "wxListCtrl", "getItemText", 3}, // 1683 + {wxListCtrl_GetItemTextColour, "wxListCtrl", "getItemTextColour", 2}, // 1684 + {wxListCtrl_GetNextItem, "wxListCtrl", "getNextItem", 3}, // 1685 + {wxListCtrl_GetSelectedItemCount, "wxListCtrl", "getSelectedItemCount", 1}, // 1686 + {wxListCtrl_GetTextColour, "wxListCtrl", "getTextColour", 1}, // 1687 + {wxListCtrl_GetTopItem, "wxListCtrl", "getTopItem", 1}, // 1688 + {wxListCtrl_GetViewRect, "wxListCtrl", "getViewRect", 1}, // 1689 + {wxListCtrl_HitTest, "wxListCtrl", "hitTest", 2}, // 1690 + {wxListCtrl_InsertColumn_2, "wxListCtrl", "insertColumn", 3}, // 1691 + {wxListCtrl_InsertColumn_3, "wxListCtrl", "insertColumn", 4}, // 1692 + {wxListCtrl_InsertItem_1, "wxListCtrl", "insertItem", 2}, // 1693 + {wxListCtrl_InsertItem_2_1, "wxListCtrl", "insertItem", 3}, // 1694 + {wxListCtrl_InsertItem_2_0, "wxListCtrl", "insertItem", 3}, // 1695 + {wxListCtrl_InsertItem_3, "wxListCtrl", "insertItem", 4}, // 1696 + {wxListCtrl_RefreshItem, "wxListCtrl", "refreshItem", 2}, // 1697 + {wxListCtrl_RefreshItems, "wxListCtrl", "refreshItems", 3}, // 1698 + {wxListCtrl_ScrollList, "wxListCtrl", "scrollList", 3}, // 1699 + {wxListCtrl_SetBackgroundColour, "wxListCtrl", "setBackgroundColour", 2}, // 1700 + {wxListCtrl_SetColumn, "wxListCtrl", "setColumn", 3}, // 1701 + {wxListCtrl_SetColumnWidth, "wxListCtrl", "setColumnWidth", 3}, // 1702 + {wxListCtrl_SetImageList, "wxListCtrl", "setImageList", 3}, // 1703 + {wxListCtrl_SetItem_1, "wxListCtrl", "setItem", 2}, // 1704 + {wxListCtrl_SetItem_4, "wxListCtrl", "setItem", 5}, // 1705 + {wxListCtrl_SetItemBackgroundColour, "wxListCtrl", "setItemBackgroundColour", 3}, // 1706 + {wxListCtrl_SetItemCount, "wxListCtrl", "setItemCount", 2}, // 1707 + {wxListCtrl_SetItemData, "wxListCtrl", "setItemData", 3}, // 1708 + {wxListCtrl_SetItemFont, "wxListCtrl", "setItemFont", 3}, // 1709 + {wxListCtrl_SetItemImage, "wxListCtrl", "setItemImage", 4}, // 1710 + {wxListCtrl_SetItemColumnImage, "wxListCtrl", "setItemColumnImage", 4}, // 1711 + {wxListCtrl_SetItemPosition, "wxListCtrl", "setItemPosition", 3}, // 1712 + {wxListCtrl_SetItemState, "wxListCtrl", "setItemState", 4}, // 1713 + {wxListCtrl_SetItemText, "wxListCtrl", "setItemText", 3}, // 1714 + {wxListCtrl_SetItemTextColour, "wxListCtrl", "setItemTextColour", 3}, // 1715 + {wxListCtrl_SetSingleStyle, "wxListCtrl", "setSingleStyle", 3}, // 1716 + {wxListCtrl_SetTextColour, "wxListCtrl", "setTextColour", 2}, // 1717 + {wxListCtrl_SetWindowStyleFlag, "wxListCtrl", "setWindowStyleFlag", 2}, // 1718 + {wxListCtrl_SortItems, "wxListCtrl", "sortItems", 2}, // 1719 + {wxListView_ClearColumnImage, "wxListView", "clearColumnImage", 2}, // 1720 + {wxListView_Focus, "wxListView", "focus", 2}, // 1721 + {wxListView_GetFirstSelected, "wxListView", "getFirstSelected", 1}, // 1722 + {wxListView_GetFocusedItem, "wxListView", "getFocusedItem", 1}, // 1723 + {wxListView_GetNextSelected, "wxListView", "getNextSelected", 2}, // 1724 + {wxListView_IsSelected, "wxListView", "isSelected", 2}, // 1725 + {wxListView_Select, "wxListView", "select", 3}, // 1726 + {wxListView_SetColumnImage, "wxListView", "setColumnImage", 3}, // 1727 + {wxListItem_new_0, "wxListItem", "new", 0}, // 1728 + {wxListItem_new_1, "wxListItem", "new", 1}, // 1729 + {wxListItem_Clear, "wxListItem", "clear", 1}, // 1730 + {wxListItem_GetAlign, "wxListItem", "getAlign", 1}, // 1731 + {wxListItem_GetBackgroundColour, "wxListItem", "getBackgroundColour", 1}, // 1732 + {wxListItem_GetColumn, "wxListItem", "getColumn", 1}, // 1733 + {wxListItem_GetFont, "wxListItem", "getFont", 1}, // 1734 + {wxListItem_GetId, "wxListItem", "getId", 1}, // 1735 + {wxListItem_GetImage, "wxListItem", "getImage", 1}, // 1736 + {wxListItem_GetMask, "wxListItem", "getMask", 1}, // 1737 + {wxListItem_GetState, "wxListItem", "getState", 1}, // 1738 + {wxListItem_GetText, "wxListItem", "getText", 1}, // 1739 + {wxListItem_GetTextColour, "wxListItem", "getTextColour", 1}, // 1740 + {wxListItem_GetWidth, "wxListItem", "getWidth", 1}, // 1741 + {wxListItem_SetAlign, "wxListItem", "setAlign", 2}, // 1742 + {wxListItem_SetBackgroundColour, "wxListItem", "setBackgroundColour", 2}, // 1743 + {wxListItem_SetColumn, "wxListItem", "setColumn", 2}, // 1744 + {wxListItem_SetFont, "wxListItem", "setFont", 2}, // 1745 + {wxListItem_SetId, "wxListItem", "setId", 2}, // 1746 + {wxListItem_SetImage, "wxListItem", "setImage", 2}, // 1747 + {wxListItem_SetMask, "wxListItem", "setMask", 2}, // 1748 + {wxListItem_SetState, "wxListItem", "setState", 2}, // 1749 + {wxListItem_SetStateMask, "wxListItem", "setStateMask", 2}, // 1750 + {wxListItem_SetText, "wxListItem", "setText", 2}, // 1751 + {wxListItem_SetTextColour, "wxListItem", "setTextColour", 2}, // 1752 + {wxListItem_SetWidth, "wxListItem", "setWidth", 2}, // 1753 + {NULL, "wxListItem", "'Destroy'", 1}, // 1754 obj destructor wxListItem_destroy + {wxListItemAttr_new_0, "wxListItemAttr", "new", 0}, // 1755 + {wxListItemAttr_new_3, "wxListItemAttr", "new", 3}, // 1756 + {wxListItemAttr_GetBackgroundColour, "wxListItemAttr", "getBackgroundColour", 1}, // 1757 + {wxListItemAttr_GetFont, "wxListItemAttr", "getFont", 1}, // 1758 + {wxListItemAttr_GetTextColour, "wxListItemAttr", "getTextColour", 1}, // 1759 + {wxListItemAttr_HasBackgroundColour, "wxListItemAttr", "hasBackgroundColour", 1}, // 1760 + {wxListItemAttr_HasFont, "wxListItemAttr", "hasFont", 1}, // 1761 + {wxListItemAttr_HasTextColour, "wxListItemAttr", "hasTextColour", 1}, // 1762 + {wxListItemAttr_SetBackgroundColour, "wxListItemAttr", "setBackgroundColour", 2}, // 1763 + {wxListItemAttr_SetFont, "wxListItemAttr", "setFont", 2}, // 1764 + {wxListItemAttr_SetTextColour, "wxListItemAttr", "setTextColour", 2}, // 1765 + {wxListItemAttr_destroy, "wxListItemAttr", "'Destroy'", 1}, // 1766 + {wxImageList_new_0, "wxImageList", "new", 0}, // 1767 + {wxImageList_new_3, "wxImageList", "new", 3}, // 1768 + {wxImageList_Add_2_0, "wxImageList", "add", 3}, // 1769 + {NULL, "", "", 0}, // 1770 + {wxImageList_Add_2_1, "wxImageList", "add", 3}, // 1771 + {wxImageList_Add_1, "wxImageList", "add", 2}, // 1772 + {wxImageList_Create, "wxImageList", "create", 4}, // 1773 + {wxImageList_Draw, "wxImageList", "draw", 6}, // 1774 + {wxImageList_GetBitmap, "wxImageList", "getBitmap", 2}, // 1775 + {wxImageList_GetIcon, "wxImageList", "getIcon", 2}, // 1776 + {wxImageList_GetImageCount, "wxImageList", "getImageCount", 1}, // 1777 + {wxImageList_GetSize, "wxImageList", "getSize", 2}, // 1778 + {NULL, "", "", 0}, // 1779 + {wxImageList_Remove, "wxImageList", "remove", 2}, // 1780 + {wxImageList_RemoveAll, "wxImageList", "removeAll", 1}, // 1781 + {wxImageList_Replace_3, "wxImageList", "replace", 4}, // 1782 + {NULL, "", "", 0}, // 1783 + {wxImageList_Replace_2, "wxImageList", "replace", 3}, // 1784 + {NULL, "wxImageList", "'Destroy'", 1}, // 1785 obj destructor wxImageList_destroy + {wxTextAttr_new_0, "wxTextAttr", "new", 0}, // 1786 + {wxTextAttr_new_2, "wxTextAttr", "new", 2}, // 1787 + {wxTextAttr_new_1, "wxTextAttr", "new", 1}, // 1788 + {wxTextAttr_GetAlignment, "wxTextAttr", "getAlignment", 1}, // 1789 + {wxTextAttr_GetBackgroundColour, "wxTextAttr", "getBackgroundColour", 1}, // 1790 + {wxTextAttr_GetFont, "wxTextAttr", "getFont", 1}, // 1791 + {wxTextAttr_GetFontEncoding, "wxTextAttr", "getFontEncoding", 1}, // 1792 + {wxTextAttr_GetFontFaceName, "wxTextAttr", "getFontFaceName", 1}, // 1793 + {wxTextAttr_GetFontSize, "wxTextAttr", "getFontSize", 1}, // 1794 + {wxTextAttr_GetFontStyle, "wxTextAttr", "getFontStyle", 1}, // 1795 + {wxTextAttr_GetFontUnderlined, "wxTextAttr", "getFontUnderlined", 1}, // 1796 + {wxTextAttr_GetFontWeight, "wxTextAttr", "getFontWeight", 1}, // 1797 + {wxTextAttr_GetLeftIndent, "wxTextAttr", "getLeftIndent", 1}, // 1798 + {wxTextAttr_GetLeftSubIndent, "wxTextAttr", "getLeftSubIndent", 1}, // 1799 + {wxTextAttr_GetRightIndent, "wxTextAttr", "getRightIndent", 1}, // 1800 + {wxTextAttr_GetTabs, "wxTextAttr", "getTabs", 1}, // 1801 + {wxTextAttr_GetTextColour, "wxTextAttr", "getTextColour", 1}, // 1802 + {wxTextAttr_HasBackgroundColour, "wxTextAttr", "hasBackgroundColour", 1}, // 1803 + {wxTextAttr_HasFont, "wxTextAttr", "hasFont", 1}, // 1804 + {wxTextAttr_HasTextColour, "wxTextAttr", "hasTextColour", 1}, // 1805 + {wxTextAttr_GetFlags, "wxTextAttr", "getFlags", 1}, // 1806 + {wxTextAttr_IsDefault, "wxTextAttr", "isDefault", 1}, // 1807 + {wxTextAttr_SetAlignment, "wxTextAttr", "setAlignment", 2}, // 1808 + {wxTextAttr_SetBackgroundColour, "wxTextAttr", "setBackgroundColour", 2}, // 1809 + {wxTextAttr_SetFlags, "wxTextAttr", "setFlags", 2}, // 1810 + {wxTextAttr_SetFont, "wxTextAttr", "setFont", 3}, // 1811 + {wxTextAttr_SetFontEncoding, "wxTextAttr", "setFontEncoding", 2}, // 1812 + {wxTextAttr_SetFontFaceName, "wxTextAttr", "setFontFaceName", 2}, // 1813 + {wxTextAttr_SetFontFamily, "wxTextAttr", "setFontFamily", 2}, // 1814 + {wxTextAttr_SetFontSize, "wxTextAttr", "setFontSize", 2}, // 1815 + {wxTextAttr_SetFontPointSize, "wxTextAttr", "setFontPointSize", 2}, // 1816 + {wxTextAttr_SetFontPixelSize, "wxTextAttr", "setFontPixelSize", 2}, // 1817 + {wxTextAttr_SetFontStyle, "wxTextAttr", "setFontStyle", 2}, // 1818 + {wxTextAttr_SetFontUnderlined, "wxTextAttr", "setFontUnderlined", 2}, // 1819 + {wxTextAttr_SetFontWeight, "wxTextAttr", "setFontWeight", 2}, // 1820 + {wxTextAttr_SetLeftIndent, "wxTextAttr", "setLeftIndent", 3}, // 1821 + {wxTextAttr_SetRightIndent, "wxTextAttr", "setRightIndent", 2}, // 1822 + {wxTextAttr_SetTabs, "wxTextAttr", "setTabs", 2}, // 1823 + {wxTextAttr_SetTextColour, "wxTextAttr", "setTextColour", 2}, // 1824 + {wxTextAttr_destroy, "wxTextAttr", "'Destroy'", 1}, // 1825 + {wxTextCtrl_new_0, "wxTextCtrl", "new", 0}, // 1826 + {wxTextCtrl_new_3, "wxTextCtrl", "new", 3}, // 1827 + {NULL, "wxTextCtrl", "destroy", 1}, // 1828 obj destructor wxTextCtrl_destruct + {wxTextCtrl_AppendText, "wxTextCtrl", "appendText", 2}, // 1829 + {wxTextCtrl_CanCopy, "wxTextCtrl", "canCopy", 1}, // 1830 + {wxTextCtrl_CanCut, "wxTextCtrl", "canCut", 1}, // 1831 + {wxTextCtrl_CanPaste, "wxTextCtrl", "canPaste", 1}, // 1832 + {wxTextCtrl_CanRedo, "wxTextCtrl", "canRedo", 1}, // 1833 + {wxTextCtrl_CanUndo, "wxTextCtrl", "canUndo", 1}, // 1834 + {wxTextCtrl_Clear, "wxTextCtrl", "clear", 1}, // 1835 + {wxTextCtrl_Copy, "wxTextCtrl", "copy", 1}, // 1836 + {wxTextCtrl_Create, "wxTextCtrl", "create", 4}, // 1837 + {wxTextCtrl_Cut, "wxTextCtrl", "cut", 1}, // 1838 + {wxTextCtrl_DiscardEdits, "wxTextCtrl", "discardEdits", 1}, // 1839 + {wxTextCtrl_ChangeValue, "wxTextCtrl", "changeValue", 2}, // 1840 + {wxTextCtrl_EmulateKeyPress, "wxTextCtrl", "emulateKeyPress", 2}, // 1841 + {wxTextCtrl_GetDefaultStyle, "wxTextCtrl", "getDefaultStyle", 1}, // 1842 + {wxTextCtrl_GetInsertionPoint, "wxTextCtrl", "getInsertionPoint", 1}, // 1843 + {wxTextCtrl_GetLastPosition, "wxTextCtrl", "getLastPosition", 1}, // 1844 + {wxTextCtrl_GetLineLength, "wxTextCtrl", "getLineLength", 2}, // 1845 + {wxTextCtrl_GetLineText, "wxTextCtrl", "getLineText", 2}, // 1846 + {wxTextCtrl_GetNumberOfLines, "wxTextCtrl", "getNumberOfLines", 1}, // 1847 + {wxTextCtrl_GetRange, "wxTextCtrl", "getRange", 3}, // 1848 + {wxTextCtrl_GetSelection, "wxTextCtrl", "getSelection", 1}, // 1849 + {wxTextCtrl_GetStringSelection, "wxTextCtrl", "getStringSelection", 1}, // 1850 + {wxTextCtrl_GetStyle, "wxTextCtrl", "getStyle", 3}, // 1851 + {wxTextCtrl_GetValue, "wxTextCtrl", "getValue", 1}, // 1852 + {wxTextCtrl_IsEditable, "wxTextCtrl", "isEditable", 1}, // 1853 + {wxTextCtrl_IsModified, "wxTextCtrl", "isModified", 1}, // 1854 + {wxTextCtrl_IsMultiLine, "wxTextCtrl", "isMultiLine", 1}, // 1855 + {wxTextCtrl_IsSingleLine, "wxTextCtrl", "isSingleLine", 1}, // 1856 + {wxTextCtrl_LoadFile, "wxTextCtrl", "loadFile", 3}, // 1857 + {wxTextCtrl_MarkDirty, "wxTextCtrl", "markDirty", 1}, // 1858 + {wxTextCtrl_Paste, "wxTextCtrl", "paste", 1}, // 1859 + {wxTextCtrl_PositionToXY, "wxTextCtrl", "positionToXY", 2}, // 1860 + {wxTextCtrl_Redo, "wxTextCtrl", "redo", 1}, // 1861 + {wxTextCtrl_Remove, "wxTextCtrl", "remove", 3}, // 1862 + {wxTextCtrl_Replace, "wxTextCtrl", "replace", 4}, // 1863 + {wxTextCtrl_SaveFile, "wxTextCtrl", "saveFile", 2}, // 1864 + {wxTextCtrl_SetDefaultStyle, "wxTextCtrl", "setDefaultStyle", 2}, // 1865 + {wxTextCtrl_SetEditable, "wxTextCtrl", "setEditable", 2}, // 1866 + {wxTextCtrl_SetInsertionPoint, "wxTextCtrl", "setInsertionPoint", 2}, // 1867 + {wxTextCtrl_SetInsertionPointEnd, "wxTextCtrl", "setInsertionPointEnd", 1}, // 1868 + {wxTextCtrl_SetMaxLength, "wxTextCtrl", "setMaxLength", 2}, // 1869 + {wxTextCtrl_SetSelection, "wxTextCtrl", "setSelection", 3}, // 1870 + {wxTextCtrl_SetStyle, "wxTextCtrl", "setStyle", 4}, // 1871 + {wxTextCtrl_SetValue, "wxTextCtrl", "setValue", 2}, // 1872 + {wxTextCtrl_ShowPosition, "wxTextCtrl", "showPosition", 2}, // 1873 + {wxTextCtrl_Undo, "wxTextCtrl", "undo", 1}, // 1874 + {wxTextCtrl_WriteText, "wxTextCtrl", "writeText", 2}, // 1875 + {wxTextCtrl_XYToPosition, "wxTextCtrl", "xYToPosition", 3}, // 1876 + {wxBookCtrlBase_AddPage, "wxBookCtrlBase", "addPage", 4}, // 1877 + {wxBookCtrlBase_InsertPage, "wxBookCtrlBase", "insertPage", 5}, // 1878 + {wxBookCtrlBase_DeletePage, "wxBookCtrlBase", "deletePage", 2}, // 1879 + {wxBookCtrlBase_RemovePage, "wxBookCtrlBase", "removePage", 2}, // 1880 + {wxBookCtrlBase_DeleteAllPages, "wxBookCtrlBase", "deleteAllPages", 1}, // 1881 + {wxBookCtrlBase_GetPage, "wxBookCtrlBase", "getPage", 2}, // 1882 + {wxBookCtrlBase_GetPageCount, "wxBookCtrlBase", "getPageCount", 1}, // 1883 + {wxBookCtrlBase_GetCurrentPage, "wxBookCtrlBase", "getCurrentPage", 1}, // 1884 + {wxBookCtrlBase_AdvanceSelection, "wxBookCtrlBase", "advanceSelection", 2}, // 1885 + {wxBookCtrlBase_SetSelection, "wxBookCtrlBase", "setSelection", 2}, // 1886 + {wxBookCtrlBase_GetSelection, "wxBookCtrlBase", "getSelection", 1}, // 1887 + {wxBookCtrlBase_ChangeSelection, "wxBookCtrlBase", "changeSelection", 2}, // 1888 + {wxBookCtrlBase_HitTest, "wxBookCtrlBase", "hitTest", 2}, // 1889 + {wxBookCtrlBase_GetPageText, "wxBookCtrlBase", "getPageText", 2}, // 1890 + {wxBookCtrlBase_SetPageText, "wxBookCtrlBase", "setPageText", 3}, // 1891 + {wxNotebook_new_0, "wxNotebook", "new", 0}, // 1892 + {wxNotebook_new_3, "wxNotebook", "new", 3}, // 1893 + {NULL, "wxNotebook", "destroy", 1}, // 1894 obj destructor wxNotebook_destruct + {wxNotebook_AssignImageList, "wxNotebook", "assignImageList", 2}, // 1895 + {wxNotebook_Create, "wxNotebook", "create", 4}, // 1896 + {wxNotebook_GetImageList, "wxNotebook", "getImageList", 1}, // 1897 + {wxNotebook_GetPageImage, "wxNotebook", "getPageImage", 2}, // 1898 + {wxNotebook_GetRowCount, "wxNotebook", "getRowCount", 1}, // 1899 + {wxNotebook_GetThemeBackgroundColour, "wxNotebook", "getThemeBackgroundColour", 1}, // 1900 + {wxNotebook_SetImageList, "wxNotebook", "setImageList", 2}, // 1901 + {wxNotebook_SetPadding, "wxNotebook", "setPadding", 2}, // 1902 + {wxNotebook_SetPageSize, "wxNotebook", "setPageSize", 2}, // 1903 + {wxNotebook_SetPageImage, "wxNotebook", "setPageImage", 3}, // 1904 + {wxChoicebook_new_0, "wxChoicebook", "new", 0}, // 1905 + {wxChoicebook_new_3, "wxChoicebook", "new", 3}, // 1906 + {wxChoicebook_AddPage, "wxChoicebook", "addPage", 4}, // 1907 + {wxChoicebook_AdvanceSelection, "wxChoicebook", "advanceSelection", 2}, // 1908 + {wxChoicebook_AssignImageList, "wxChoicebook", "assignImageList", 2}, // 1909 + {wxChoicebook_Create, "wxChoicebook", "create", 4}, // 1910 + {wxChoicebook_DeleteAllPages, "wxChoicebook", "deleteAllPages", 1}, // 1911 + {wxChoicebook_GetCurrentPage, "wxChoicebook", "getCurrentPage", 1}, // 1912 + {wxChoicebook_GetImageList, "wxChoicebook", "getImageList", 1}, // 1913 + {wxChoicebook_GetPage, "wxChoicebook", "getPage", 2}, // 1914 + {wxChoicebook_GetPageCount, "wxChoicebook", "getPageCount", 1}, // 1915 + {wxChoicebook_GetPageImage, "wxChoicebook", "getPageImage", 2}, // 1916 + {wxChoicebook_GetPageText, "wxChoicebook", "getPageText", 2}, // 1917 + {wxChoicebook_GetSelection, "wxChoicebook", "getSelection", 1}, // 1918 + {wxChoicebook_HitTest, "wxChoicebook", "hitTest", 2}, // 1919 + {wxChoicebook_InsertPage, "wxChoicebook", "insertPage", 5}, // 1920 + {wxChoicebook_SetImageList, "wxChoicebook", "setImageList", 2}, // 1921 + {wxChoicebook_SetPageSize, "wxChoicebook", "setPageSize", 2}, // 1922 + {wxChoicebook_SetPageImage, "wxChoicebook", "setPageImage", 3}, // 1923 + {wxChoicebook_SetPageText, "wxChoicebook", "setPageText", 3}, // 1924 + {wxChoicebook_SetSelection, "wxChoicebook", "setSelection", 2}, // 1925 + {wxChoicebook_ChangeSelection, "wxChoicebook", "changeSelection", 2}, // 1926 + {NULL, "wxChoicebook", "'Destroy'", 1}, // 1927 obj destructor wxChoicebook_destroy + {wxToolbook_new_0, "wxToolbook", "new", 0}, // 1928 + {wxToolbook_new_3, "wxToolbook", "new", 3}, // 1929 + {wxToolbook_AddPage, "wxToolbook", "addPage", 4}, // 1930 + {wxToolbook_AdvanceSelection, "wxToolbook", "advanceSelection", 2}, // 1931 + {wxToolbook_AssignImageList, "wxToolbook", "assignImageList", 2}, // 1932 + {wxToolbook_Create, "wxToolbook", "create", 4}, // 1933 + {wxToolbook_DeleteAllPages, "wxToolbook", "deleteAllPages", 1}, // 1934 + {wxToolbook_GetCurrentPage, "wxToolbook", "getCurrentPage", 1}, // 1935 + {wxToolbook_GetImageList, "wxToolbook", "getImageList", 1}, // 1936 + {wxToolbook_GetPage, "wxToolbook", "getPage", 2}, // 1937 + {wxToolbook_GetPageCount, "wxToolbook", "getPageCount", 1}, // 1938 + {wxToolbook_GetPageImage, "wxToolbook", "getPageImage", 2}, // 1939 + {wxToolbook_GetPageText, "wxToolbook", "getPageText", 2}, // 1940 + {wxToolbook_GetSelection, "wxToolbook", "getSelection", 1}, // 1941 + {wxToolbook_HitTest, "wxToolbook", "hitTest", 2}, // 1942 + {wxToolbook_InsertPage, "wxToolbook", "insertPage", 5}, // 1943 + {wxToolbook_SetImageList, "wxToolbook", "setImageList", 2}, // 1944 + {wxToolbook_SetPageSize, "wxToolbook", "setPageSize", 2}, // 1945 + {wxToolbook_SetPageImage, "wxToolbook", "setPageImage", 3}, // 1946 + {wxToolbook_SetPageText, "wxToolbook", "setPageText", 3}, // 1947 + {wxToolbook_SetSelection, "wxToolbook", "setSelection", 2}, // 1948 + {wxToolbook_ChangeSelection, "wxToolbook", "changeSelection", 2}, // 1949 + {NULL, "wxToolbook", "'Destroy'", 1}, // 1950 obj destructor wxToolbook_destroy + {wxListbook_new_0, "wxListbook", "new", 0}, // 1951 + {wxListbook_new_3, "wxListbook", "new", 3}, // 1952 + {wxListbook_AddPage, "wxListbook", "addPage", 4}, // 1953 + {wxListbook_AdvanceSelection, "wxListbook", "advanceSelection", 2}, // 1954 + {wxListbook_AssignImageList, "wxListbook", "assignImageList", 2}, // 1955 + {wxListbook_Create, "wxListbook", "create", 4}, // 1956 + {wxListbook_DeleteAllPages, "wxListbook", "deleteAllPages", 1}, // 1957 + {wxListbook_GetCurrentPage, "wxListbook", "getCurrentPage", 1}, // 1958 + {wxListbook_GetImageList, "wxListbook", "getImageList", 1}, // 1959 + {wxListbook_GetPage, "wxListbook", "getPage", 2}, // 1960 + {wxListbook_GetPageCount, "wxListbook", "getPageCount", 1}, // 1961 + {wxListbook_GetPageImage, "wxListbook", "getPageImage", 2}, // 1962 + {wxListbook_GetPageText, "wxListbook", "getPageText", 2}, // 1963 + {wxListbook_GetSelection, "wxListbook", "getSelection", 1}, // 1964 + {wxListbook_HitTest, "wxListbook", "hitTest", 2}, // 1965 + {wxListbook_InsertPage, "wxListbook", "insertPage", 5}, // 1966 + {wxListbook_SetImageList, "wxListbook", "setImageList", 2}, // 1967 + {wxListbook_SetPageSize, "wxListbook", "setPageSize", 2}, // 1968 + {wxListbook_SetPageImage, "wxListbook", "setPageImage", 3}, // 1969 + {wxListbook_SetPageText, "wxListbook", "setPageText", 3}, // 1970 + {wxListbook_SetSelection, "wxListbook", "setSelection", 2}, // 1971 + {wxListbook_ChangeSelection, "wxListbook", "changeSelection", 2}, // 1972 + {NULL, "wxListbook", "'Destroy'", 1}, // 1973 obj destructor wxListbook_destroy + {wxTreebook_new_0, "wxTreebook", "new", 0}, // 1974 + {wxTreebook_new_3, "wxTreebook", "new", 3}, // 1975 + {NULL, "wxTreebook", "destroy", 1}, // 1976 obj destructor wxTreebook_destruct + {wxTreebook_AddPage, "wxTreebook", "addPage", 4}, // 1977 + {wxTreebook_AdvanceSelection, "wxTreebook", "advanceSelection", 2}, // 1978 + {wxTreebook_AssignImageList, "wxTreebook", "assignImageList", 2}, // 1979 + {wxTreebook_Create, "wxTreebook", "create", 4}, // 1980 + {wxTreebook_DeleteAllPages, "wxTreebook", "deleteAllPages", 1}, // 1981 + {wxTreebook_GetCurrentPage, "wxTreebook", "getCurrentPage", 1}, // 1982 + {wxTreebook_GetImageList, "wxTreebook", "getImageList", 1}, // 1983 + {wxTreebook_GetPage, "wxTreebook", "getPage", 2}, // 1984 + {wxTreebook_GetPageCount, "wxTreebook", "getPageCount", 1}, // 1985 + {wxTreebook_GetPageImage, "wxTreebook", "getPageImage", 2}, // 1986 + {wxTreebook_GetPageText, "wxTreebook", "getPageText", 2}, // 1987 + {wxTreebook_GetSelection, "wxTreebook", "getSelection", 1}, // 1988 + {wxTreebook_ExpandNode, "wxTreebook", "expandNode", 3}, // 1989 + {wxTreebook_IsNodeExpanded, "wxTreebook", "isNodeExpanded", 2}, // 1990 + {wxTreebook_HitTest, "wxTreebook", "hitTest", 2}, // 1991 + {wxTreebook_InsertPage, "wxTreebook", "insertPage", 5}, // 1992 + {wxTreebook_InsertSubPage, "wxTreebook", "insertSubPage", 5}, // 1993 + {wxTreebook_SetImageList, "wxTreebook", "setImageList", 2}, // 1994 + {wxTreebook_SetPageSize, "wxTreebook", "setPageSize", 2}, // 1995 + {wxTreebook_SetPageImage, "wxTreebook", "setPageImage", 3}, // 1996 + {wxTreebook_SetPageText, "wxTreebook", "setPageText", 3}, // 1997 + {wxTreebook_SetSelection, "wxTreebook", "setSelection", 2}, // 1998 + {wxTreebook_ChangeSelection, "wxTreebook", "changeSelection", 2}, // 1999 + {wxTreeCtrl_new_0, "wxTreeCtrl", "new", 0}, // 2000 + {wxTreeCtrl_new_2, "wxTreeCtrl", "new", 2}, // 2001 + {NULL, "wxTreeCtrl", "destroy", 1}, // 2002 obj destructor wxTreeCtrl_destruct + {wxTreeCtrl_AddRoot, "wxTreeCtrl", "addRoot", 3}, // 2003 + {wxTreeCtrl_AppendItem, "wxTreeCtrl", "appendItem", 4}, // 2004 + {wxTreeCtrl_AssignImageList, "wxTreeCtrl", "assignImageList", 2}, // 2005 + {wxTreeCtrl_AssignStateImageList, "wxTreeCtrl", "assignStateImageList", 2}, // 2006 + {wxTreeCtrl_Collapse, "wxTreeCtrl", "collapse", 2}, // 2007 + {wxTreeCtrl_CollapseAndReset, "wxTreeCtrl", "collapseAndReset", 2}, // 2008 + {wxTreeCtrl_Create, "wxTreeCtrl", "create", 3}, // 2009 + {wxTreeCtrl_Delete, "wxTreeCtrl", "delete", 2}, // 2010 + {wxTreeCtrl_DeleteAllItems, "wxTreeCtrl", "deleteAllItems", 1}, // 2011 + {wxTreeCtrl_DeleteChildren, "wxTreeCtrl", "deleteChildren", 2}, // 2012 + {wxTreeCtrl_EditLabel, "wxTreeCtrl", "editLabel", 2}, // 2013 + {wxTreeCtrl_EnsureVisible, "wxTreeCtrl", "ensureVisible", 2}, // 2014 + {wxTreeCtrl_Expand, "wxTreeCtrl", "expand", 2}, // 2015 + {wxTreeCtrl_GetBoundingRect, "wxTreeCtrl", "getBoundingRect", 3}, // 2016 + {wxTreeCtrl_GetChildrenCount, "wxTreeCtrl", "getChildrenCount", 3}, // 2017 + {wxTreeCtrl_GetCount, "wxTreeCtrl", "getCount", 1}, // 2018 + {wxTreeCtrl_GetEditControl, "wxTreeCtrl", "getEditControl", 1}, // 2019 + {wxTreeCtrl_GetFirstChild, "wxTreeCtrl", "getFirstChild", 2}, // 2020 + {wxTreeCtrl_GetNextChild, "wxTreeCtrl", "getNextChild", 3}, // 2021 + {wxTreeCtrl_GetFirstVisibleItem, "wxTreeCtrl", "getFirstVisibleItem", 1}, // 2022 + {wxTreeCtrl_GetImageList, "wxTreeCtrl", "getImageList", 1}, // 2023 + {wxTreeCtrl_GetIndent, "wxTreeCtrl", "getIndent", 1}, // 2024 + {wxTreeCtrl_GetItemBackgroundColour, "wxTreeCtrl", "getItemBackgroundColour", 2}, // 2025 + {wxTreeCtrl_GetItemData, "wxTreeCtrl", "getItemData", 2}, // 2026 + {wxTreeCtrl_GetItemFont, "wxTreeCtrl", "getItemFont", 2}, // 2027 + {wxTreeCtrl_GetItemImage, "wxTreeCtrl", "getItemImage", 3}, // 2028 + {wxTreeCtrl_GetItemText, "wxTreeCtrl", "getItemText", 2}, // 2029 + {wxTreeCtrl_GetItemTextColour, "wxTreeCtrl", "getItemTextColour", 2}, // 2030 + {wxTreeCtrl_GetLastChild, "wxTreeCtrl", "getLastChild", 2}, // 2031 + {wxTreeCtrl_GetNextSibling, "wxTreeCtrl", "getNextSibling", 2}, // 2032 + {wxTreeCtrl_GetNextVisible, "wxTreeCtrl", "getNextVisible", 2}, // 2033 + {wxTreeCtrl_GetItemParent, "wxTreeCtrl", "getItemParent", 2}, // 2034 + {wxTreeCtrl_GetPrevSibling, "wxTreeCtrl", "getPrevSibling", 2}, // 2035 + {wxTreeCtrl_GetPrevVisible, "wxTreeCtrl", "getPrevVisible", 2}, // 2036 + {wxTreeCtrl_GetRootItem, "wxTreeCtrl", "getRootItem", 1}, // 2037 + {wxTreeCtrl_GetSelection, "wxTreeCtrl", "getSelection", 1}, // 2038 + {wxTreeCtrl_GetSelections, "wxTreeCtrl", "getSelections", 1}, // 2039 + {wxTreeCtrl_GetStateImageList, "wxTreeCtrl", "getStateImageList", 1}, // 2040 + {wxTreeCtrl_HitTest, "wxTreeCtrl", "hitTest", 2}, // 2041 + {wxTreeCtrl_InsertItem, "wxTreeCtrl", "insertItem", 5}, // 2042 + {NULL, "", "", 0}, // 2043 + {wxTreeCtrl_IsBold, "wxTreeCtrl", "isBold", 2}, // 2044 + {wxTreeCtrl_IsExpanded, "wxTreeCtrl", "isExpanded", 2}, // 2045 + {wxTreeCtrl_IsSelected, "wxTreeCtrl", "isSelected", 2}, // 2046 + {wxTreeCtrl_IsVisible, "wxTreeCtrl", "isVisible", 2}, // 2047 + {wxTreeCtrl_ItemHasChildren, "wxTreeCtrl", "itemHasChildren", 2}, // 2048 + {wxTreeCtrl_IsTreeItemIdOk, "wxTreeCtrl", "isTreeItemIdOk", 1}, // 2049 + {wxTreeCtrl_PrependItem, "wxTreeCtrl", "prependItem", 4}, // 2050 + {wxTreeCtrl_ScrollTo, "wxTreeCtrl", "scrollTo", 2}, // 2051 + {wxTreeCtrl_SelectItem, "wxTreeCtrl", "selectItem", 3}, // 2052 + {wxTreeCtrl_SetIndent, "wxTreeCtrl", "setIndent", 2}, // 2053 + {wxTreeCtrl_SetImageList, "wxTreeCtrl", "setImageList", 2}, // 2054 + {wxTreeCtrl_SetItemBackgroundColour, "wxTreeCtrl", "setItemBackgroundColour", 3}, // 2055 + {wxTreeCtrl_SetItemBold, "wxTreeCtrl", "setItemBold", 3}, // 2056 + {wxTreeCtrl_SetItemData, "wxTreeCtrl", "setItemData", 3}, // 2057 + {wxTreeCtrl_SetItemDropHighlight, "wxTreeCtrl", "setItemDropHighlight", 3}, // 2058 + {wxTreeCtrl_SetItemFont, "wxTreeCtrl", "setItemFont", 3}, // 2059 + {wxTreeCtrl_SetItemHasChildren, "wxTreeCtrl", "setItemHasChildren", 3}, // 2060 + {wxTreeCtrl_SetItemImage, "wxTreeCtrl", "setItemImage", 4}, // 2061 + {wxTreeCtrl_SetItemText, "wxTreeCtrl", "setItemText", 3}, // 2062 + {wxTreeCtrl_SetItemTextColour, "wxTreeCtrl", "setItemTextColour", 3}, // 2063 + {wxTreeCtrl_SetStateImageList, "wxTreeCtrl", "setStateImageList", 2}, // 2064 + {wxTreeCtrl_SetWindowStyle, "wxTreeCtrl", "setWindowStyle", 2}, // 2065 + {wxTreeCtrl_SortChildren, "wxTreeCtrl", "sortChildren", 2}, // 2066 + {wxTreeCtrl_Toggle, "wxTreeCtrl", "toggle", 2}, // 2067 + {wxTreeCtrl_ToggleItemSelection, "wxTreeCtrl", "toggleItemSelection", 2}, // 2068 + {wxTreeCtrl_Unselect, "wxTreeCtrl", "unselect", 1}, // 2069 + {wxTreeCtrl_UnselectAll, "wxTreeCtrl", "unselectAll", 1}, // 2070 + {wxTreeCtrl_UnselectItem, "wxTreeCtrl", "unselectItem", 2}, // 2071 + {wxScrollBar_new_0, "wxScrollBar", "new", 0}, // 2072 + {wxScrollBar_new_3, "wxScrollBar", "new", 3}, // 2073 + {NULL, "wxScrollBar", "destroy", 1}, // 2074 obj destructor wxScrollBar_destruct + {wxScrollBar_Create, "wxScrollBar", "create", 4}, // 2075 + {wxScrollBar_GetRange, "wxScrollBar", "getRange", 1}, // 2076 + {wxScrollBar_GetPageSize, "wxScrollBar", "getPageSize", 1}, // 2077 + {wxScrollBar_GetThumbPosition, "wxScrollBar", "getThumbPosition", 1}, // 2078 + {wxScrollBar_GetThumbSize, "wxScrollBar", "getThumbSize", 1}, // 2079 + {wxScrollBar_SetThumbPosition, "wxScrollBar", "setThumbPosition", 2}, // 2080 + {wxScrollBar_SetScrollbar, "wxScrollBar", "setScrollbar", 6}, // 2081 + {wxSpinButton_new_0, "wxSpinButton", "new", 0}, // 2082 + {wxSpinButton_new_2, "wxSpinButton", "new", 2}, // 2083 + {NULL, "wxSpinButton", "destroy", 1}, // 2084 obj destructor wxSpinButton_destruct + {wxSpinButton_Create, "wxSpinButton", "create", 3}, // 2085 + {wxSpinButton_GetMax, "wxSpinButton", "getMax", 1}, // 2086 + {wxSpinButton_GetMin, "wxSpinButton", "getMin", 1}, // 2087 + {wxSpinButton_GetValue, "wxSpinButton", "getValue", 1}, // 2088 + {wxSpinButton_SetRange, "wxSpinButton", "setRange", 3}, // 2089 + {wxSpinButton_SetValue, "wxSpinButton", "setValue", 2}, // 2090 + {wxSpinCtrl_new_0, "wxSpinCtrl", "new", 0}, // 2091 + {wxSpinCtrl_new_2, "wxSpinCtrl", "new", 2}, // 2092 + {wxSpinCtrl_Create, "wxSpinCtrl", "create", 3}, // 2093 + {wxSpinCtrl_SetValue_1_1, "wxSpinCtrl", "setValue", 2}, // 2094 + {wxSpinCtrl_SetValue_1_0, "wxSpinCtrl", "setValue", 2}, // 2095 + {wxSpinCtrl_GetValue, "wxSpinCtrl", "getValue", 1}, // 2096 + {wxSpinCtrl_SetRange, "wxSpinCtrl", "setRange", 3}, // 2097 + {wxSpinCtrl_SetSelection, "wxSpinCtrl", "setSelection", 3}, // 2098 + {wxSpinCtrl_GetMin, "wxSpinCtrl", "getMin", 1}, // 2099 + {wxSpinCtrl_GetMax, "wxSpinCtrl", "getMax", 1}, // 2100 + {NULL, "wxSpinCtrl", "'Destroy'", 1}, // 2101 obj destructor wxSpinCtrl_destroy + {wxStaticText_new_0, "wxStaticText", "new", 0}, // 2102 + {wxStaticText_new_4, "wxStaticText", "new", 4}, // 2103 + {wxStaticText_Create, "wxStaticText", "create", 5}, // 2104 + {wxStaticText_GetLabel, "wxStaticText", "getLabel", 1}, // 2105 + {wxStaticText_SetLabel, "wxStaticText", "setLabel", 2}, // 2106 + {wxStaticText_Wrap, "wxStaticText", "wrap", 2}, // 2107 + {NULL, "wxStaticText", "'Destroy'", 1}, // 2108 obj destructor wxStaticText_destroy + {wxStaticBitmap_new_0, "wxStaticBitmap", "new", 0}, // 2109 + {wxStaticBitmap_new_4, "wxStaticBitmap", "new", 4}, // 2110 + {wxStaticBitmap_Create, "wxStaticBitmap", "create", 5}, // 2111 + {wxStaticBitmap_GetBitmap, "wxStaticBitmap", "getBitmap", 1}, // 2112 + {wxStaticBitmap_SetBitmap, "wxStaticBitmap", "setBitmap", 2}, // 2113 + {NULL, "wxStaticBitmap", "'Destroy'", 1}, // 2114 obj destructor wxStaticBitmap_destroy + {wxRadioBox_new, "wxRadioBox", "new", 7}, // 2115 + {NULL, "wxRadioBox", "destroy", 1}, // 2116 obj destructor wxRadioBox_destruct + {wxRadioBox_Create, "wxRadioBox", "create", 8}, // 2117 + {wxRadioBox_Enable_1, "wxRadioBox", "enable", 2}, // 2118 + {wxRadioBox_Enable_2, "wxRadioBox", "enable", 3}, // 2119 + {wxRadioBox_GetSelection, "wxRadioBox", "getSelection", 1}, // 2120 + {wxRadioBox_GetString, "wxRadioBox", "getString", 2}, // 2121 + {wxRadioBox_SetSelection, "wxRadioBox", "setSelection", 2}, // 2122 + {wxRadioBox_Show, "wxRadioBox", "show", 3}, // 2123 + {wxRadioBox_GetColumnCount, "wxRadioBox", "getColumnCount", 1}, // 2124 + {wxRadioBox_GetItemHelpText, "wxRadioBox", "getItemHelpText", 2}, // 2125 + {wxRadioBox_GetItemToolTip, "wxRadioBox", "getItemToolTip", 2}, // 2126 + {wxRadioBox_GetItemFromPoint, "wxRadioBox", "getItemFromPoint", 2}, // 2127 + {wxRadioBox_GetRowCount, "wxRadioBox", "getRowCount", 1}, // 2128 + {wxRadioBox_IsItemEnabled, "wxRadioBox", "isItemEnabled", 2}, // 2129 + {wxRadioBox_IsItemShown, "wxRadioBox", "isItemShown", 2}, // 2130 + {wxRadioBox_SetItemHelpText, "wxRadioBox", "setItemHelpText", 3}, // 2131 + {wxRadioBox_SetItemToolTip, "wxRadioBox", "setItemToolTip", 3}, // 2132 + {wxRadioButton_new_0, "wxRadioButton", "new", 0}, // 2133 + {wxRadioButton_new_4, "wxRadioButton", "new", 4}, // 2134 + {NULL, "wxRadioButton", "destroy", 1}, // 2135 obj destructor wxRadioButton_destruct + {wxRadioButton_Create, "wxRadioButton", "create", 5}, // 2136 + {wxRadioButton_GetValue, "wxRadioButton", "getValue", 1}, // 2137 + {wxRadioButton_SetValue, "wxRadioButton", "setValue", 2}, // 2138 + {wxSlider_new_0, "wxSlider", "new", 0}, // 2139 + {wxSlider_new_6, "wxSlider", "new", 6}, // 2140 + {NULL, "wxSlider", "destroy", 1}, // 2141 obj destructor wxSlider_destruct + {wxSlider_Create, "wxSlider", "create", 7}, // 2142 + {wxSlider_GetLineSize, "wxSlider", "getLineSize", 1}, // 2143 + {wxSlider_GetMax, "wxSlider", "getMax", 1}, // 2144 + {wxSlider_GetMin, "wxSlider", "getMin", 1}, // 2145 + {wxSlider_GetPageSize, "wxSlider", "getPageSize", 1}, // 2146 + {wxSlider_GetThumbLength, "wxSlider", "getThumbLength", 1}, // 2147 + {wxSlider_GetValue, "wxSlider", "getValue", 1}, // 2148 + {wxSlider_SetLineSize, "wxSlider", "setLineSize", 2}, // 2149 + {wxSlider_SetPageSize, "wxSlider", "setPageSize", 2}, // 2150 + {wxSlider_SetRange, "wxSlider", "setRange", 3}, // 2151 + {wxSlider_SetThumbLength, "wxSlider", "setThumbLength", 2}, // 2152 + {wxSlider_SetValue, "wxSlider", "setValue", 2}, // 2153 + {wxDialog_new_0, "wxDialog", "new", 0}, // 2154 + {wxDialog_new_4, "wxDialog", "new", 4}, // 2155 + {NULL, "wxDialog", "destroy", 1}, // 2156 obj destructor wxDialog_destruct + {wxDialog_Create, "wxDialog", "create", 5}, // 2157 + {wxDialog_CreateButtonSizer, "wxDialog", "createButtonSizer", 2}, // 2158 + {wxDialog_CreateStdDialogButtonSizer, "wxDialog", "createStdDialogButtonSizer", 2}, // 2159 + {wxDialog_EndModal, "wxDialog", "endModal", 2}, // 2160 + {wxDialog_GetAffirmativeId, "wxDialog", "getAffirmativeId", 1}, // 2161 + {wxDialog_GetReturnCode, "wxDialog", "getReturnCode", 1}, // 2162 + {wxDialog_IsModal, "wxDialog", "isModal", 1}, // 2163 + {wxDialog_SetAffirmativeId, "wxDialog", "setAffirmativeId", 2}, // 2164 + {wxDialog_SetReturnCode, "wxDialog", "setReturnCode", 2}, // 2165 + {wxDialog_Show, "wxDialog", "show", 2}, // 2166 + {wxDialog_ShowModal, "wxDialog", "showModal", 1}, // 2167 + {wxColourDialog_new_0, "wxColourDialog", "new", 0}, // 2168 + {wxColourDialog_new_2, "wxColourDialog", "new", 2}, // 2169 + {NULL, "wxColourDialog", "destroy", 1}, // 2170 obj destructor wxColourDialog_destruct + {wxColourDialog_Create, "wxColourDialog", "create", 3}, // 2171 + {wxColourDialog_GetColourData, "wxColourDialog", "getColourData", 1}, // 2172 + {wxColourData_new, "wxColourData", "new", 0}, // 2173 + {NULL, "wxColourData", "destroy", 1}, // 2174 obj destructor wxColourData_destruct + {wxColourData_GetChooseFull, "wxColourData", "getChooseFull", 1}, // 2175 + {wxColourData_GetColour, "wxColourData", "getColour", 1}, // 2176 + {wxColourData_GetCustomColour, "wxColourData", "getCustomColour", 2}, // 2177 + {wxColourData_SetChooseFull, "wxColourData", "setChooseFull", 2}, // 2178 + {wxColourData_SetColour, "wxColourData", "setColour", 2}, // 2179 + {wxColourData_SetCustomColour, "wxColourData", "setCustomColour", 3}, // 2180 + {wxPalette_new_0, "wxPalette", "new", 0}, // 2181 + {wxPalette_new_1, "wxPalette", "new", 1}, // 2182 + {wxPalette_new_4, "wxPalette", "new", 3}, // 2183 + {NULL, "wxPalette", "destroy", 1}, // 2184 obj destructor wxPalette_destruct + {wxPalette_Create, "wxPalette", "create", 4}, // 2185 + {wxPalette_GetColoursCount, "wxPalette", "getColoursCount", 1}, // 2186 + {wxPalette_GetPixel, "wxPalette", "getPixel", 4}, // 2187 + {wxPalette_GetRGB, "wxPalette", "getRGB", 2}, // 2188 + {wxPalette_IsOk, "wxPalette", "isOk", 1}, // 2189 + {wxDirDialog_new, "wxDirDialog", "new", 2}, // 2190 + {NULL, "wxDirDialog", "destroy", 1}, // 2191 obj destructor wxDirDialog_destruct + {wxDirDialog_GetPath, "wxDirDialog", "getPath", 1}, // 2192 + {wxDirDialog_GetMessage, "wxDirDialog", "getMessage", 1}, // 2193 + {wxDirDialog_SetMessage, "wxDirDialog", "setMessage", 2}, // 2194 + {wxDirDialog_SetPath, "wxDirDialog", "setPath", 2}, // 2195 + {wxFileDialog_new, "wxFileDialog", "new", 2}, // 2196 + {NULL, "wxFileDialog", "destroy", 1}, // 2197 obj destructor wxFileDialog_destruct + {wxFileDialog_GetDirectory, "wxFileDialog", "getDirectory", 1}, // 2198 + {wxFileDialog_GetFilename, "wxFileDialog", "getFilename", 1}, // 2199 + {wxFileDialog_GetFilenames, "wxFileDialog", "getFilenames", 1}, // 2200 + {wxFileDialog_GetFilterIndex, "wxFileDialog", "getFilterIndex", 1}, // 2201 + {wxFileDialog_GetMessage, "wxFileDialog", "getMessage", 1}, // 2202 + {wxFileDialog_GetPath, "wxFileDialog", "getPath", 1}, // 2203 + {wxFileDialog_GetPaths, "wxFileDialog", "getPaths", 1}, // 2204 + {wxFileDialog_GetWildcard, "wxFileDialog", "getWildcard", 1}, // 2205 + {wxFileDialog_SetDirectory, "wxFileDialog", "setDirectory", 2}, // 2206 + {wxFileDialog_SetFilename, "wxFileDialog", "setFilename", 2}, // 2207 + {wxFileDialog_SetFilterIndex, "wxFileDialog", "setFilterIndex", 2}, // 2208 + {wxFileDialog_SetMessage, "wxFileDialog", "setMessage", 2}, // 2209 + {wxFileDialog_SetPath, "wxFileDialog", "setPath", 2}, // 2210 + {wxFileDialog_SetWildcard, "wxFileDialog", "setWildcard", 2}, // 2211 + {wxPickerBase_SetInternalMargin, "wxPickerBase", "setInternalMargin", 2}, // 2212 + {wxPickerBase_GetInternalMargin, "wxPickerBase", "getInternalMargin", 1}, // 2213 + {wxPickerBase_SetTextCtrlProportion, "wxPickerBase", "setTextCtrlProportion", 2}, // 2214 + {wxPickerBase_SetPickerCtrlProportion, "wxPickerBase", "setPickerCtrlProportion", 2}, // 2215 + {wxPickerBase_GetTextCtrlProportion, "wxPickerBase", "getTextCtrlProportion", 1}, // 2216 + {wxPickerBase_GetPickerCtrlProportion, "wxPickerBase", "getPickerCtrlProportion", 1}, // 2217 + {wxPickerBase_HasTextCtrl, "wxPickerBase", "hasTextCtrl", 1}, // 2218 + {wxPickerBase_GetTextCtrl, "wxPickerBase", "getTextCtrl", 1}, // 2219 + {wxPickerBase_IsTextCtrlGrowable, "wxPickerBase", "isTextCtrlGrowable", 1}, // 2220 + {wxPickerBase_SetPickerCtrlGrowable, "wxPickerBase", "setPickerCtrlGrowable", 2}, // 2221 + {wxPickerBase_SetTextCtrlGrowable, "wxPickerBase", "setTextCtrlGrowable", 2}, // 2222 + {wxPickerBase_IsPickerCtrlGrowable, "wxPickerBase", "isPickerCtrlGrowable", 1}, // 2223 + {wxFilePickerCtrl_new_0, "wxFilePickerCtrl", "new", 0}, // 2224 + {wxFilePickerCtrl_new_3, "wxFilePickerCtrl", "new", 3}, // 2225 + {wxFilePickerCtrl_Create, "wxFilePickerCtrl", "create", 4}, // 2226 + {wxFilePickerCtrl_GetPath, "wxFilePickerCtrl", "getPath", 1}, // 2227 + {wxFilePickerCtrl_SetPath, "wxFilePickerCtrl", "setPath", 2}, // 2228 + {NULL, "wxFilePickerCtrl", "'Destroy'", 1}, // 2229 obj destructor wxFilePickerCtrl_destroy + {wxDirPickerCtrl_new_0, "wxDirPickerCtrl", "new", 0}, // 2230 + {wxDirPickerCtrl_new_3, "wxDirPickerCtrl", "new", 3}, // 2231 + {wxDirPickerCtrl_Create, "wxDirPickerCtrl", "create", 4}, // 2232 + {wxDirPickerCtrl_GetPath, "wxDirPickerCtrl", "getPath", 1}, // 2233 + {wxDirPickerCtrl_SetPath, "wxDirPickerCtrl", "setPath", 2}, // 2234 + {NULL, "wxDirPickerCtrl", "'Destroy'", 1}, // 2235 obj destructor wxDirPickerCtrl_destroy + {wxColourPickerCtrl_new_0, "wxColourPickerCtrl", "new", 0}, // 2236 + {wxColourPickerCtrl_new_3, "wxColourPickerCtrl", "new", 3}, // 2237 + {wxColourPickerCtrl_Create, "wxColourPickerCtrl", "create", 4}, // 2238 + {wxColourPickerCtrl_GetColour, "wxColourPickerCtrl", "getColour", 1}, // 2239 + {wxColourPickerCtrl_SetColour_1_1, "wxColourPickerCtrl", "setColour", 2}, // 2240 + {wxColourPickerCtrl_SetColour_1_0, "wxColourPickerCtrl", "setColour", 2}, // 2241 + {NULL, "wxColourPickerCtrl", "'Destroy'", 1}, // 2242 obj destructor wxColourPickerCtrl_destroy + {wxDatePickerCtrl_new_0, "wxDatePickerCtrl", "new", 0}, // 2243 + {wxDatePickerCtrl_new_3, "wxDatePickerCtrl", "new", 3}, // 2244 + {wxDatePickerCtrl_GetRange, "wxDatePickerCtrl", "getRange", 3}, // 2245 + {wxDatePickerCtrl_GetValue, "wxDatePickerCtrl", "getValue", 1}, // 2246 + {wxDatePickerCtrl_SetRange, "wxDatePickerCtrl", "setRange", 3}, // 2247 + {wxDatePickerCtrl_SetValue, "wxDatePickerCtrl", "setValue", 2}, // 2248 + {NULL, "wxDatePickerCtrl", "'Destroy'", 1}, // 2249 obj destructor wxDatePickerCtrl_destroy + {wxFontPickerCtrl_new_0, "wxFontPickerCtrl", "new", 0}, // 2250 + {wxFontPickerCtrl_new_3, "wxFontPickerCtrl", "new", 3}, // 2251 + {wxFontPickerCtrl_Create, "wxFontPickerCtrl", "create", 4}, // 2252 + {wxFontPickerCtrl_GetSelectedFont, "wxFontPickerCtrl", "getSelectedFont", 1}, // 2253 + {wxFontPickerCtrl_SetSelectedFont, "wxFontPickerCtrl", "setSelectedFont", 2}, // 2254 + {wxFontPickerCtrl_GetMaxPointSize, "wxFontPickerCtrl", "getMaxPointSize", 1}, // 2255 + {wxFontPickerCtrl_SetMaxPointSize, "wxFontPickerCtrl", "setMaxPointSize", 2}, // 2256 + {NULL, "wxFontPickerCtrl", "'Destroy'", 1}, // 2257 obj destructor wxFontPickerCtrl_destroy + {wxFindReplaceDialog_new_0, "wxFindReplaceDialog", "new", 0}, // 2258 + {wxFindReplaceDialog_new_4, "wxFindReplaceDialog", "new", 4}, // 2259 + {NULL, "wxFindReplaceDialog", "destroy", 1}, // 2260 obj destructor wxFindReplaceDialog_destruct + {wxFindReplaceDialog_Create, "wxFindReplaceDialog", "create", 5}, // 2261 + {wxFindReplaceDialog_GetData, "wxFindReplaceDialog", "getData", 1}, // 2262 + {wxFindReplaceData_new, "wxFindReplaceData", "new", 1}, // 2263 + {wxFindReplaceData_GetFindString, "wxFindReplaceData", "getFindString", 1}, // 2264 + {wxFindReplaceData_GetReplaceString, "wxFindReplaceData", "getReplaceString", 1}, // 2265 + {wxFindReplaceData_GetFlags, "wxFindReplaceData", "getFlags", 1}, // 2266 + {wxFindReplaceData_SetFlags, "wxFindReplaceData", "setFlags", 2}, // 2267 + {wxFindReplaceData_SetFindString, "wxFindReplaceData", "setFindString", 2}, // 2268 + {wxFindReplaceData_SetReplaceString, "wxFindReplaceData", "setReplaceString", 2}, // 2269 + {NULL, "wxFindReplaceData", "'Destroy'", 1}, // 2270 obj destructor wxFindReplaceData_destroy + {NULL, "", "", 0}, // 2271 + {wxMultiChoiceDialog_new, "wxMultiChoiceDialog", "new", 5}, // 2272 + {wxMultiChoiceDialog_GetSelections, "wxMultiChoiceDialog", "getSelections", 1}, // 2273 + {wxMultiChoiceDialog_SetSelections, "wxMultiChoiceDialog", "setSelections", 2}, // 2274 + {NULL, "wxMultiChoiceDialog", "'Destroy'", 1}, // 2275 obj destructor wxMultiChoiceDialog_destroy + {NULL, "", "", 0}, // 2276 + {wxSingleChoiceDialog_new, "wxSingleChoiceDialog", "new", 5}, // 2277 + {wxSingleChoiceDialog_GetSelection, "wxSingleChoiceDialog", "getSelection", 1}, // 2278 + {wxSingleChoiceDialog_GetStringSelection, "wxSingleChoiceDialog", "getStringSelection", 1}, // 2279 + {wxSingleChoiceDialog_SetSelection, "wxSingleChoiceDialog", "setSelection", 2}, // 2280 + {NULL, "wxSingleChoiceDialog", "'Destroy'", 1}, // 2281 obj destructor wxSingleChoiceDialog_destroy + {wxTextEntryDialog_new_0, "wxTextEntryDialog", "new", 0}, // 2282 + {wxTextEntryDialog_new_3, "wxTextEntryDialog", "new", 3}, // 2283 + {NULL, "wxTextEntryDialog", "destroy", 1}, // 2284 obj destructor wxTextEntryDialog_destruct + {wxTextEntryDialog_GetValue, "wxTextEntryDialog", "getValue", 1}, // 2285 + {wxTextEntryDialog_SetValue, "wxTextEntryDialog", "setValue", 2}, // 2286 + {wxPasswordEntryDialog_new, "wxPasswordEntryDialog", "new", 3}, // 2287 + {NULL, "wxPasswordEntryDialog", "'Destroy'", 1}, // 2288 obj destructor wxPasswordEntryDialog_destroy + {wxFontData_new_0, "wxFontData", "new", 0}, // 2289 + {wxFontData_new_1, "wxFontData", "new", 1}, // 2290 + {wxFontData_EnableEffects, "wxFontData", "enableEffects", 2}, // 2291 + {wxFontData_GetAllowSymbols, "wxFontData", "getAllowSymbols", 1}, // 2292 + {wxFontData_GetColour, "wxFontData", "getColour", 1}, // 2293 + {wxFontData_GetChosenFont, "wxFontData", "getChosenFont", 1}, // 2294 + {wxFontData_GetEnableEffects, "wxFontData", "getEnableEffects", 1}, // 2295 + {wxFontData_GetInitialFont, "wxFontData", "getInitialFont", 1}, // 2296 + {wxFontData_GetShowHelp, "wxFontData", "getShowHelp", 1}, // 2297 + {wxFontData_SetAllowSymbols, "wxFontData", "setAllowSymbols", 2}, // 2298 + {wxFontData_SetChosenFont, "wxFontData", "setChosenFont", 2}, // 2299 + {wxFontData_SetColour, "wxFontData", "setColour", 2}, // 2300 + {wxFontData_SetInitialFont, "wxFontData", "setInitialFont", 2}, // 2301 + {wxFontData_SetRange, "wxFontData", "setRange", 3}, // 2302 + {wxFontData_SetShowHelp, "wxFontData", "setShowHelp", 2}, // 2303 + {NULL, "wxFontData", "'Destroy'", 1}, // 2304 obj destructor wxFontData_destroy + {wxFontDialog_new_0, "wxFontDialog", "new", 0}, // 2305 {NULL, "", "", 0}, // 2306 - {wxFontDialog_Create, "wxFontDialog", "create", 3}, // 2307 - {wxFontDialog_GetFontData, "wxFontDialog", "getFontData", 1}, // 2308 - {NULL, "", "", 0}, // 2309 - {NULL, "wxFontDialog", "'Destroy'", 1}, // 2310 obj destructor wxFontDialog_destroy - {wxProgressDialog_new, "wxProgressDialog", "new", 3}, // 2311 - {wxProgressDialog_Resume, "wxProgressDialog", "resume", 1}, // 2312 - {wxProgressDialog_Update, "wxProgressDialog", "update", 3}, // 2313 - {NULL, "wxProgressDialog", "'Destroy'", 1}, // 2314 obj destructor wxProgressDialog_destroy - {wxMessageDialog_new, "wxMessageDialog", "new", 3}, // 2315 - {NULL, "wxMessageDialog", "'Destroy'", 1}, // 2316 obj destructor wxMessageDialog_destroy - {wxPageSetupDialog_new, "wxPageSetupDialog", "new", 2}, // 2317 - {NULL, "wxPageSetupDialog", "destroy", 1}, // 2318 obj destructor wxPageSetupDialog_destruct - {wxPageSetupDialog_GetPageSetupData, "wxPageSetupDialog", "getPageSetupData", 1}, // 2319 - {wxPageSetupDialog_ShowModal, "wxPageSetupDialog", "showModal", 1}, // 2320 - {wxPageSetupDialogData_new_0, "wxPageSetupDialogData", "new", 0}, // 2321 - {NULL, "", "", 0}, // 2322 - {wxPageSetupDialogData_new_1, "wxPageSetupDialogData", "new", 1}, // 2323 - {NULL, "wxPageSetupDialogData", "destroy", 1}, // 2324 obj destructor wxPageSetupDialogData_destruct - {wxPageSetupDialogData_EnableHelp, "wxPageSetupDialogData", "enableHelp", 2}, // 2325 - {wxPageSetupDialogData_EnableMargins, "wxPageSetupDialogData", "enableMargins", 2}, // 2326 - {wxPageSetupDialogData_EnableOrientation, "wxPageSetupDialogData", "enableOrientation", 2}, // 2327 - {wxPageSetupDialogData_EnablePaper, "wxPageSetupDialogData", "enablePaper", 2}, // 2328 - {wxPageSetupDialogData_EnablePrinter, "wxPageSetupDialogData", "enablePrinter", 2}, // 2329 - {wxPageSetupDialogData_GetDefaultMinMargins, "wxPageSetupDialogData", "getDefaultMinMargins", 1}, // 2330 - {wxPageSetupDialogData_GetEnableMargins, "wxPageSetupDialogData", "getEnableMargins", 1}, // 2331 - {wxPageSetupDialogData_GetEnableOrientation, "wxPageSetupDialogData", "getEnableOrientation", 1}, // 2332 - {wxPageSetupDialogData_GetEnablePaper, "wxPageSetupDialogData", "getEnablePaper", 1}, // 2333 - {wxPageSetupDialogData_GetEnablePrinter, "wxPageSetupDialogData", "getEnablePrinter", 1}, // 2334 - {wxPageSetupDialogData_GetEnableHelp, "wxPageSetupDialogData", "getEnableHelp", 1}, // 2335 - {wxPageSetupDialogData_GetDefaultInfo, "wxPageSetupDialogData", "getDefaultInfo", 1}, // 2336 - {wxPageSetupDialogData_GetMarginTopLeft, "wxPageSetupDialogData", "getMarginTopLeft", 1}, // 2337 - {wxPageSetupDialogData_GetMarginBottomRight, "wxPageSetupDialogData", "getMarginBottomRight", 1}, // 2338 - {wxPageSetupDialogData_GetMinMarginTopLeft, "wxPageSetupDialogData", "getMinMarginTopLeft", 1}, // 2339 - {wxPageSetupDialogData_GetMinMarginBottomRight, "wxPageSetupDialogData", "getMinMarginBottomRight", 1}, // 2340 - {wxPageSetupDialogData_GetPaperId, "wxPageSetupDialogData", "getPaperId", 1}, // 2341 - {wxPageSetupDialogData_GetPaperSize, "wxPageSetupDialogData", "getPaperSize", 1}, // 2342 - {NULL, "", "", 0}, // 2343 - {wxPageSetupDialogData_GetPrintData, "wxPageSetupDialogData", "getPrintData", 1}, // 2344 - {wxPageSetupDialogData_IsOk, "wxPageSetupDialogData", "isOk", 1}, // 2345 - {wxPageSetupDialogData_SetDefaultInfo, "wxPageSetupDialogData", "setDefaultInfo", 2}, // 2346 - {wxPageSetupDialogData_SetDefaultMinMargins, "wxPageSetupDialogData", "setDefaultMinMargins", 2}, // 2347 - {wxPageSetupDialogData_SetMarginTopLeft, "wxPageSetupDialogData", "setMarginTopLeft", 2}, // 2348 - {wxPageSetupDialogData_SetMarginBottomRight, "wxPageSetupDialogData", "setMarginBottomRight", 2}, // 2349 - {wxPageSetupDialogData_SetMinMarginTopLeft, "wxPageSetupDialogData", "setMinMarginTopLeft", 2}, // 2350 - {wxPageSetupDialogData_SetMinMarginBottomRight, "wxPageSetupDialogData", "setMinMarginBottomRight", 2}, // 2351 - {wxPageSetupDialogData_SetPaperId, "wxPageSetupDialogData", "setPaperId", 2}, // 2352 - {wxPageSetupDialogData_SetPaperSize, "wxPageSetupDialogData", "setPaperSize", 2}, // 2353 - {wxPageSetupDialogData_SetPrintData, "wxPageSetupDialogData", "setPrintData", 2}, // 2354 - {wxPrintDialog_new_2_0, "wxPrintDialog", "new", 2}, // 2355 - {wxPrintDialog_new_2_1, "wxPrintDialog", "new", 2}, // 2356 - {NULL, "wxPrintDialog", "destroy", 1}, // 2357 obj destructor wxPrintDialog_destruct - {wxPrintDialog_GetPrintDialogData, "wxPrintDialog", "getPrintDialogData", 1}, // 2358 - {wxPrintDialog_GetPrintDC, "wxPrintDialog", "getPrintDC", 1}, // 2359 - {wxPrintDialogData_new_0, "wxPrintDialogData", "new", 0}, // 2360 - {wxPrintDialogData_new_1, "wxPrintDialogData", "new", 1}, // 2361 - {NULL, "", "", 0}, // 2362 - {NULL, "wxPrintDialogData", "destroy", 1}, // 2363 obj destructor wxPrintDialogData_destruct - {wxPrintDialogData_EnableHelp, "wxPrintDialogData", "enableHelp", 2}, // 2364 - {wxPrintDialogData_EnablePageNumbers, "wxPrintDialogData", "enablePageNumbers", 2}, // 2365 - {wxPrintDialogData_EnablePrintToFile, "wxPrintDialogData", "enablePrintToFile", 2}, // 2366 - {wxPrintDialogData_EnableSelection, "wxPrintDialogData", "enableSelection", 2}, // 2367 - {wxPrintDialogData_GetAllPages, "wxPrintDialogData", "getAllPages", 1}, // 2368 - {wxPrintDialogData_GetCollate, "wxPrintDialogData", "getCollate", 1}, // 2369 - {wxPrintDialogData_GetFromPage, "wxPrintDialogData", "getFromPage", 1}, // 2370 - {wxPrintDialogData_GetMaxPage, "wxPrintDialogData", "getMaxPage", 1}, // 2371 - {wxPrintDialogData_GetMinPage, "wxPrintDialogData", "getMinPage", 1}, // 2372 - {wxPrintDialogData_GetNoCopies, "wxPrintDialogData", "getNoCopies", 1}, // 2373 - {wxPrintDialogData_GetPrintData, "wxPrintDialogData", "getPrintData", 1}, // 2374 - {wxPrintDialogData_GetPrintToFile, "wxPrintDialogData", "getPrintToFile", 1}, // 2375 - {wxPrintDialogData_GetSelection, "wxPrintDialogData", "getSelection", 1}, // 2376 - {wxPrintDialogData_GetToPage, "wxPrintDialogData", "getToPage", 1}, // 2377 - {wxPrintDialogData_IsOk, "wxPrintDialogData", "isOk", 1}, // 2378 - {wxPrintDialogData_SetCollate, "wxPrintDialogData", "setCollate", 2}, // 2379 - {wxPrintDialogData_SetFromPage, "wxPrintDialogData", "setFromPage", 2}, // 2380 - {wxPrintDialogData_SetMaxPage, "wxPrintDialogData", "setMaxPage", 2}, // 2381 - {wxPrintDialogData_SetMinPage, "wxPrintDialogData", "setMinPage", 2}, // 2382 - {wxPrintDialogData_SetNoCopies, "wxPrintDialogData", "setNoCopies", 2}, // 2383 - {wxPrintDialogData_SetPrintData, "wxPrintDialogData", "setPrintData", 2}, // 2384 - {wxPrintDialogData_SetPrintToFile, "wxPrintDialogData", "setPrintToFile", 2}, // 2385 - {wxPrintDialogData_SetSelection, "wxPrintDialogData", "setSelection", 2}, // 2386 - {wxPrintDialogData_SetToPage, "wxPrintDialogData", "setToPage", 2}, // 2387 - {wxPrintData_new_0, "wxPrintData", "new", 0}, // 2388 - {wxPrintData_new_1, "wxPrintData", "new", 1}, // 2389 - {NULL, "wxPrintData", "destroy", 1}, // 2390 obj destructor wxPrintData_destruct - {wxPrintData_GetCollate, "wxPrintData", "getCollate", 1}, // 2391 - {wxPrintData_GetBin, "wxPrintData", "getBin", 1}, // 2392 - {wxPrintData_GetColour, "wxPrintData", "getColour", 1}, // 2393 - {wxPrintData_GetDuplex, "wxPrintData", "getDuplex", 1}, // 2394 - {wxPrintData_GetNoCopies, "wxPrintData", "getNoCopies", 1}, // 2395 - {wxPrintData_GetOrientation, "wxPrintData", "getOrientation", 1}, // 2396 - {wxPrintData_GetPaperId, "wxPrintData", "getPaperId", 1}, // 2397 - {wxPrintData_GetPrinterName, "wxPrintData", "getPrinterName", 1}, // 2398 - {wxPrintData_GetQuality, "wxPrintData", "getQuality", 1}, // 2399 - {wxPrintData_IsOk, "wxPrintData", "isOk", 1}, // 2400 - {wxPrintData_SetBin, "wxPrintData", "setBin", 2}, // 2401 - {wxPrintData_SetCollate, "wxPrintData", "setCollate", 2}, // 2402 - {wxPrintData_SetColour, "wxPrintData", "setColour", 2}, // 2403 - {wxPrintData_SetDuplex, "wxPrintData", "setDuplex", 2}, // 2404 - {wxPrintData_SetNoCopies, "wxPrintData", "setNoCopies", 2}, // 2405 - {wxPrintData_SetOrientation, "wxPrintData", "setOrientation", 2}, // 2406 - {wxPrintData_SetPaperId, "wxPrintData", "setPaperId", 2}, // 2407 - {wxPrintData_SetPrinterName, "wxPrintData", "setPrinterName", 2}, // 2408 - {wxPrintData_SetQuality, "wxPrintData", "setQuality", 2}, // 2409 - {wxPrintPreview_new_2, "wxPrintPreview", "new", 2}, // 2410 - {wxPrintPreview_new_3, "wxPrintPreview", "new", 3}, // 2411 - {NULL, "wxPrintPreview", "destroy", 1}, // 2412 obj destructor wxPrintPreview_destruct - {wxPrintPreview_GetCanvas, "wxPrintPreview", "getCanvas", 1}, // 2413 - {wxPrintPreview_GetCurrentPage, "wxPrintPreview", "getCurrentPage", 1}, // 2414 - {wxPrintPreview_GetFrame, "wxPrintPreview", "getFrame", 1}, // 2415 - {wxPrintPreview_GetMaxPage, "wxPrintPreview", "getMaxPage", 1}, // 2416 - {wxPrintPreview_GetMinPage, "wxPrintPreview", "getMinPage", 1}, // 2417 - {wxPrintPreview_GetPrintout, "wxPrintPreview", "getPrintout", 1}, // 2418 - {wxPrintPreview_GetPrintoutForPrinting, "wxPrintPreview", "getPrintoutForPrinting", 1}, // 2419 - {wxPrintPreview_IsOk, "wxPrintPreview", "isOk", 1}, // 2420 - {wxPrintPreview_PaintPage, "wxPrintPreview", "paintPage", 3}, // 2421 - {wxPrintPreview_Print, "wxPrintPreview", "print", 2}, // 2422 - {wxPrintPreview_RenderPage, "wxPrintPreview", "renderPage", 2}, // 2423 - {wxPrintPreview_SetCanvas, "wxPrintPreview", "setCanvas", 2}, // 2424 - {wxPrintPreview_SetCurrentPage, "wxPrintPreview", "setCurrentPage", 2}, // 2425 - {wxPrintPreview_SetFrame, "wxPrintPreview", "setFrame", 2}, // 2426 - {wxPrintPreview_SetPrintout, "wxPrintPreview", "setPrintout", 2}, // 2427 - {wxPrintPreview_SetZoom, "wxPrintPreview", "setZoom", 2}, // 2428 - {wxPreviewFrame_new, "wxPreviewFrame", "new", 3}, // 2429 - {NULL, "wxPreviewFrame", "destroy", 1}, // 2430 obj destructor wxPreviewFrame_destruct - {wxPreviewFrame_CreateControlBar, "wxPreviewFrame", "createControlBar", 1}, // 2431 - {wxPreviewFrame_CreateCanvas, "wxPreviewFrame", "createCanvas", 1}, // 2432 - {wxPreviewFrame_Initialize, "wxPreviewFrame", "initialize", 1}, // 2433 - {wxPreviewFrame_OnCloseWindow, "wxPreviewFrame", "onCloseWindow", 2}, // 2434 - {wxPreviewControlBar_new, "wxPreviewControlBar", "new", 4}, // 2435 - {NULL, "wxPreviewControlBar", "destroy", 1}, // 2436 obj destructor wxPreviewControlBar_destruct - {wxPreviewControlBar_CreateButtons, "wxPreviewControlBar", "createButtons", 1}, // 2437 - {wxPreviewControlBar_GetPrintPreview, "wxPreviewControlBar", "getPrintPreview", 1}, // 2438 - {wxPreviewControlBar_GetZoomControl, "wxPreviewControlBar", "getZoomControl", 1}, // 2439 - {wxPreviewControlBar_SetZoomControl, "wxPreviewControlBar", "setZoomControl", 2}, // 2440 - {wxPrinter_new, "wxPrinter", "new", 1}, // 2441 - {wxPrinter_CreateAbortWindow, "wxPrinter", "createAbortWindow", 3}, // 2442 - {wxPrinter_GetAbort, "wxPrinter", "getAbort", 1}, // 2443 - {wxPrinter_GetLastError, "wxPrinter", "getLastError", 0}, // 2444 - {wxPrinter_GetPrintDialogData, "wxPrinter", "getPrintDialogData", 1}, // 2445 - {wxPrinter_Print, "wxPrinter", "print", 4}, // 2446 - {wxPrinter_PrintDialog, "wxPrinter", "printDialog", 2}, // 2447 - {wxPrinter_ReportError, "wxPrinter", "reportError", 4}, // 2448 - {wxPrinter_Setup, "wxPrinter", "setup", 2}, // 2449 - {NULL, "wxPrinter", "'Destroy'", 1}, // 2450 obj destructor wxPrinter_destroy - {wxXmlResource_new_2, "wxXmlResource", "new", 2}, // 2451 - {wxXmlResource_new_1, "wxXmlResource", "new", 1}, // 2452 - {NULL, "wxXmlResource", "destroy", 1}, // 2453 obj destructor wxXmlResource_destruct - {wxXmlResource_AttachUnknownControl, "wxXmlResource", "attachUnknownControl", 4}, // 2454 - {wxXmlResource_ClearHandlers, "wxXmlResource", "clearHandlers", 1}, // 2455 - {wxXmlResource_CompareVersion, "wxXmlResource", "compareVersion", 5}, // 2456 - {wxXmlResource_Get, "wxXmlResource", "get", 0}, // 2457 - {wxXmlResource_GetFlags, "wxXmlResource", "getFlags", 1}, // 2458 - {wxXmlResource_GetVersion, "wxXmlResource", "getVersion", 1}, // 2459 - {wxXmlResource_GetXRCID, "wxXmlResource", "getXRCID", 2}, // 2460 - {wxXmlResource_InitAllHandlers, "wxXmlResource", "initAllHandlers", 1}, // 2461 - {wxXmlResource_Load, "wxXmlResource", "load", 2}, // 2462 - {wxXmlResource_LoadBitmap, "wxXmlResource", "loadBitmap", 2}, // 2463 - {wxXmlResource_LoadDialog_2, "wxXmlResource", "loadDialog", 3}, // 2464 - {wxXmlResource_LoadDialog_3, "wxXmlResource", "loadDialog", 4}, // 2465 - {wxXmlResource_LoadFrame_2, "wxXmlResource", "loadFrame", 3}, // 2466 - {wxXmlResource_LoadFrame_3, "wxXmlResource", "loadFrame", 4}, // 2467 - {wxXmlResource_LoadIcon, "wxXmlResource", "loadIcon", 2}, // 2468 - {wxXmlResource_LoadMenu, "wxXmlResource", "loadMenu", 2}, // 2469 - {wxXmlResource_LoadMenuBar_2, "wxXmlResource", "loadMenuBar", 3}, // 2470 - {wxXmlResource_LoadMenuBar_1, "wxXmlResource", "loadMenuBar", 2}, // 2471 - {wxXmlResource_LoadPanel_2, "wxXmlResource", "loadPanel", 3}, // 2472 - {wxXmlResource_LoadPanel_3, "wxXmlResource", "loadPanel", 4}, // 2473 - {wxXmlResource_LoadToolBar, "wxXmlResource", "loadToolBar", 3}, // 2474 - {wxXmlResource_Set, "wxXmlResource", "set", 1}, // 2475 - {wxXmlResource_SetFlags, "wxXmlResource", "setFlags", 2}, // 2476 - {wxXmlResource_Unload, "wxXmlResource", "unload", 2}, // 2477 - {NULL, "wxXmlResource", "xrcctrl", 3}, // 2478 TaylorMade erl only wxXmlResource_xrcctrl - {wxHtmlEasyPrinting_new, "wxHtmlEasyPrinting", "new", 1}, // 2479 - {wxHtmlEasyPrinting_GetPrintData, "wxHtmlEasyPrinting", "getPrintData", 1}, // 2480 - {wxHtmlEasyPrinting_GetPageSetupData, "wxHtmlEasyPrinting", "getPageSetupData", 1}, // 2481 - {wxHtmlEasyPrinting_PreviewFile, "wxHtmlEasyPrinting", "previewFile", 2}, // 2482 - {wxHtmlEasyPrinting_PreviewText, "wxHtmlEasyPrinting", "previewText", 3}, // 2483 - {wxHtmlEasyPrinting_PrintFile, "wxHtmlEasyPrinting", "printFile", 2}, // 2484 - {wxHtmlEasyPrinting_PrintText, "wxHtmlEasyPrinting", "printText", 3}, // 2485 - {wxHtmlEasyPrinting_PageSetup, "wxHtmlEasyPrinting", "pageSetup", 1}, // 2486 - {wxHtmlEasyPrinting_SetFonts, "wxHtmlEasyPrinting", "setFonts", 4}, // 2487 - {wxHtmlEasyPrinting_SetHeader, "wxHtmlEasyPrinting", "setHeader", 3}, // 2488 - {wxHtmlEasyPrinting_SetFooter, "wxHtmlEasyPrinting", "setFooter", 3}, // 2489 - {NULL, "wxHtmlEasyPrinting", "'Destroy'", 1}, // 2490 obj destructor wxHtmlEasyPrinting_destroy + {wxFontDialog_new_2, "wxFontDialog", "new", 2}, // 2307 + {NULL, "", "", 0}, // 2308 + {wxFontDialog_Create, "wxFontDialog", "create", 3}, // 2309 + {wxFontDialog_GetFontData, "wxFontDialog", "getFontData", 1}, // 2310 + {NULL, "", "", 0}, // 2311 + {NULL, "wxFontDialog", "'Destroy'", 1}, // 2312 obj destructor wxFontDialog_destroy + {wxProgressDialog_new, "wxProgressDialog", "new", 3}, // 2313 + {wxProgressDialog_Resume, "wxProgressDialog", "resume", 1}, // 2314 + {wxProgressDialog_Update, "wxProgressDialog", "update", 3}, // 2315 + {NULL, "wxProgressDialog", "'Destroy'", 1}, // 2316 obj destructor wxProgressDialog_destroy + {wxMessageDialog_new, "wxMessageDialog", "new", 3}, // 2317 + {NULL, "wxMessageDialog", "'Destroy'", 1}, // 2318 obj destructor wxMessageDialog_destroy + {wxPageSetupDialog_new, "wxPageSetupDialog", "new", 2}, // 2319 + {NULL, "wxPageSetupDialog", "destroy", 1}, // 2320 obj destructor wxPageSetupDialog_destruct + {wxPageSetupDialog_GetPageSetupData, "wxPageSetupDialog", "getPageSetupData", 1}, // 2321 + {wxPageSetupDialog_ShowModal, "wxPageSetupDialog", "showModal", 1}, // 2322 + {wxPageSetupDialogData_new_0, "wxPageSetupDialogData", "new", 0}, // 2323 + {NULL, "", "", 0}, // 2324 + {wxPageSetupDialogData_new_1, "wxPageSetupDialogData", "new", 1}, // 2325 + {NULL, "wxPageSetupDialogData", "destroy", 1}, // 2326 obj destructor wxPageSetupDialogData_destruct + {wxPageSetupDialogData_EnableHelp, "wxPageSetupDialogData", "enableHelp", 2}, // 2327 + {wxPageSetupDialogData_EnableMargins, "wxPageSetupDialogData", "enableMargins", 2}, // 2328 + {wxPageSetupDialogData_EnableOrientation, "wxPageSetupDialogData", "enableOrientation", 2}, // 2329 + {wxPageSetupDialogData_EnablePaper, "wxPageSetupDialogData", "enablePaper", 2}, // 2330 + {wxPageSetupDialogData_EnablePrinter, "wxPageSetupDialogData", "enablePrinter", 2}, // 2331 + {wxPageSetupDialogData_GetDefaultMinMargins, "wxPageSetupDialogData", "getDefaultMinMargins", 1}, // 2332 + {wxPageSetupDialogData_GetEnableMargins, "wxPageSetupDialogData", "getEnableMargins", 1}, // 2333 + {wxPageSetupDialogData_GetEnableOrientation, "wxPageSetupDialogData", "getEnableOrientation", 1}, // 2334 + {wxPageSetupDialogData_GetEnablePaper, "wxPageSetupDialogData", "getEnablePaper", 1}, // 2335 + {wxPageSetupDialogData_GetEnablePrinter, "wxPageSetupDialogData", "getEnablePrinter", 1}, // 2336 + {wxPageSetupDialogData_GetEnableHelp, "wxPageSetupDialogData", "getEnableHelp", 1}, // 2337 + {wxPageSetupDialogData_GetDefaultInfo, "wxPageSetupDialogData", "getDefaultInfo", 1}, // 2338 + {wxPageSetupDialogData_GetMarginTopLeft, "wxPageSetupDialogData", "getMarginTopLeft", 1}, // 2339 + {wxPageSetupDialogData_GetMarginBottomRight, "wxPageSetupDialogData", "getMarginBottomRight", 1}, // 2340 + {wxPageSetupDialogData_GetMinMarginTopLeft, "wxPageSetupDialogData", "getMinMarginTopLeft", 1}, // 2341 + {wxPageSetupDialogData_GetMinMarginBottomRight, "wxPageSetupDialogData", "getMinMarginBottomRight", 1}, // 2342 + {wxPageSetupDialogData_GetPaperId, "wxPageSetupDialogData", "getPaperId", 1}, // 2343 + {wxPageSetupDialogData_GetPaperSize, "wxPageSetupDialogData", "getPaperSize", 1}, // 2344 + {NULL, "", "", 0}, // 2345 + {wxPageSetupDialogData_GetPrintData, "wxPageSetupDialogData", "getPrintData", 1}, // 2346 + {wxPageSetupDialogData_IsOk, "wxPageSetupDialogData", "isOk", 1}, // 2347 + {wxPageSetupDialogData_SetDefaultInfo, "wxPageSetupDialogData", "setDefaultInfo", 2}, // 2348 + {wxPageSetupDialogData_SetDefaultMinMargins, "wxPageSetupDialogData", "setDefaultMinMargins", 2}, // 2349 + {wxPageSetupDialogData_SetMarginTopLeft, "wxPageSetupDialogData", "setMarginTopLeft", 2}, // 2350 + {wxPageSetupDialogData_SetMarginBottomRight, "wxPageSetupDialogData", "setMarginBottomRight", 2}, // 2351 + {wxPageSetupDialogData_SetMinMarginTopLeft, "wxPageSetupDialogData", "setMinMarginTopLeft", 2}, // 2352 + {wxPageSetupDialogData_SetMinMarginBottomRight, "wxPageSetupDialogData", "setMinMarginBottomRight", 2}, // 2353 + {wxPageSetupDialogData_SetPaperId, "wxPageSetupDialogData", "setPaperId", 2}, // 2354 + {wxPageSetupDialogData_SetPaperSize, "wxPageSetupDialogData", "setPaperSize", 2}, // 2355 + {wxPageSetupDialogData_SetPrintData, "wxPageSetupDialogData", "setPrintData", 2}, // 2356 + {wxPrintDialog_new_2_0, "wxPrintDialog", "new", 2}, // 2357 + {wxPrintDialog_new_2_1, "wxPrintDialog", "new", 2}, // 2358 + {NULL, "wxPrintDialog", "destroy", 1}, // 2359 obj destructor wxPrintDialog_destruct + {wxPrintDialog_GetPrintDialogData, "wxPrintDialog", "getPrintDialogData", 1}, // 2360 + {wxPrintDialog_GetPrintDC, "wxPrintDialog", "getPrintDC", 1}, // 2361 + {wxPrintDialogData_new_0, "wxPrintDialogData", "new", 0}, // 2362 + {wxPrintDialogData_new_1, "wxPrintDialogData", "new", 1}, // 2363 + {NULL, "", "", 0}, // 2364 + {NULL, "wxPrintDialogData", "destroy", 1}, // 2365 obj destructor wxPrintDialogData_destruct + {wxPrintDialogData_EnableHelp, "wxPrintDialogData", "enableHelp", 2}, // 2366 + {wxPrintDialogData_EnablePageNumbers, "wxPrintDialogData", "enablePageNumbers", 2}, // 2367 + {wxPrintDialogData_EnablePrintToFile, "wxPrintDialogData", "enablePrintToFile", 2}, // 2368 + {wxPrintDialogData_EnableSelection, "wxPrintDialogData", "enableSelection", 2}, // 2369 + {wxPrintDialogData_GetAllPages, "wxPrintDialogData", "getAllPages", 1}, // 2370 + {wxPrintDialogData_GetCollate, "wxPrintDialogData", "getCollate", 1}, // 2371 + {wxPrintDialogData_GetFromPage, "wxPrintDialogData", "getFromPage", 1}, // 2372 + {wxPrintDialogData_GetMaxPage, "wxPrintDialogData", "getMaxPage", 1}, // 2373 + {wxPrintDialogData_GetMinPage, "wxPrintDialogData", "getMinPage", 1}, // 2374 + {wxPrintDialogData_GetNoCopies, "wxPrintDialogData", "getNoCopies", 1}, // 2375 + {wxPrintDialogData_GetPrintData, "wxPrintDialogData", "getPrintData", 1}, // 2376 + {wxPrintDialogData_GetPrintToFile, "wxPrintDialogData", "getPrintToFile", 1}, // 2377 + {wxPrintDialogData_GetSelection, "wxPrintDialogData", "getSelection", 1}, // 2378 + {wxPrintDialogData_GetToPage, "wxPrintDialogData", "getToPage", 1}, // 2379 + {wxPrintDialogData_IsOk, "wxPrintDialogData", "isOk", 1}, // 2380 + {wxPrintDialogData_SetCollate, "wxPrintDialogData", "setCollate", 2}, // 2381 + {wxPrintDialogData_SetFromPage, "wxPrintDialogData", "setFromPage", 2}, // 2382 + {wxPrintDialogData_SetMaxPage, "wxPrintDialogData", "setMaxPage", 2}, // 2383 + {wxPrintDialogData_SetMinPage, "wxPrintDialogData", "setMinPage", 2}, // 2384 + {wxPrintDialogData_SetNoCopies, "wxPrintDialogData", "setNoCopies", 2}, // 2385 + {wxPrintDialogData_SetPrintData, "wxPrintDialogData", "setPrintData", 2}, // 2386 + {wxPrintDialogData_SetPrintToFile, "wxPrintDialogData", "setPrintToFile", 2}, // 2387 + {wxPrintDialogData_SetSelection, "wxPrintDialogData", "setSelection", 2}, // 2388 + {wxPrintDialogData_SetToPage, "wxPrintDialogData", "setToPage", 2}, // 2389 + {wxPrintData_new_0, "wxPrintData", "new", 0}, // 2390 + {wxPrintData_new_1, "wxPrintData", "new", 1}, // 2391 + {NULL, "wxPrintData", "destroy", 1}, // 2392 obj destructor wxPrintData_destruct + {wxPrintData_GetCollate, "wxPrintData", "getCollate", 1}, // 2393 + {wxPrintData_GetBin, "wxPrintData", "getBin", 1}, // 2394 + {wxPrintData_GetColour, "wxPrintData", "getColour", 1}, // 2395 + {wxPrintData_GetDuplex, "wxPrintData", "getDuplex", 1}, // 2396 + {wxPrintData_GetNoCopies, "wxPrintData", "getNoCopies", 1}, // 2397 + {wxPrintData_GetOrientation, "wxPrintData", "getOrientation", 1}, // 2398 + {wxPrintData_GetPaperId, "wxPrintData", "getPaperId", 1}, // 2399 + {wxPrintData_GetPrinterName, "wxPrintData", "getPrinterName", 1}, // 2400 + {wxPrintData_GetQuality, "wxPrintData", "getQuality", 1}, // 2401 + {wxPrintData_IsOk, "wxPrintData", "isOk", 1}, // 2402 + {wxPrintData_SetBin, "wxPrintData", "setBin", 2}, // 2403 + {wxPrintData_SetCollate, "wxPrintData", "setCollate", 2}, // 2404 + {wxPrintData_SetColour, "wxPrintData", "setColour", 2}, // 2405 + {wxPrintData_SetDuplex, "wxPrintData", "setDuplex", 2}, // 2406 + {wxPrintData_SetNoCopies, "wxPrintData", "setNoCopies", 2}, // 2407 + {wxPrintData_SetOrientation, "wxPrintData", "setOrientation", 2}, // 2408 + {wxPrintData_SetPaperId, "wxPrintData", "setPaperId", 2}, // 2409 + {wxPrintData_SetPrinterName, "wxPrintData", "setPrinterName", 2}, // 2410 + {wxPrintData_SetQuality, "wxPrintData", "setQuality", 2}, // 2411 + {wxPrintPreview_new_2, "wxPrintPreview", "new", 2}, // 2412 + {wxPrintPreview_new_3, "wxPrintPreview", "new", 3}, // 2413 + {NULL, "wxPrintPreview", "destroy", 1}, // 2414 obj destructor wxPrintPreview_destruct + {wxPrintPreview_GetCanvas, "wxPrintPreview", "getCanvas", 1}, // 2415 + {wxPrintPreview_GetCurrentPage, "wxPrintPreview", "getCurrentPage", 1}, // 2416 + {wxPrintPreview_GetFrame, "wxPrintPreview", "getFrame", 1}, // 2417 + {wxPrintPreview_GetMaxPage, "wxPrintPreview", "getMaxPage", 1}, // 2418 + {wxPrintPreview_GetMinPage, "wxPrintPreview", "getMinPage", 1}, // 2419 + {wxPrintPreview_GetPrintout, "wxPrintPreview", "getPrintout", 1}, // 2420 + {wxPrintPreview_GetPrintoutForPrinting, "wxPrintPreview", "getPrintoutForPrinting", 1}, // 2421 + {wxPrintPreview_IsOk, "wxPrintPreview", "isOk", 1}, // 2422 + {wxPrintPreview_PaintPage, "wxPrintPreview", "paintPage", 3}, // 2423 + {wxPrintPreview_Print, "wxPrintPreview", "print", 2}, // 2424 + {wxPrintPreview_RenderPage, "wxPrintPreview", "renderPage", 2}, // 2425 + {wxPrintPreview_SetCanvas, "wxPrintPreview", "setCanvas", 2}, // 2426 + {wxPrintPreview_SetCurrentPage, "wxPrintPreview", "setCurrentPage", 2}, // 2427 + {wxPrintPreview_SetFrame, "wxPrintPreview", "setFrame", 2}, // 2428 + {wxPrintPreview_SetPrintout, "wxPrintPreview", "setPrintout", 2}, // 2429 + {wxPrintPreview_SetZoom, "wxPrintPreview", "setZoom", 2}, // 2430 + {wxPreviewFrame_new, "wxPreviewFrame", "new", 3}, // 2431 + {NULL, "wxPreviewFrame", "destroy", 1}, // 2432 obj destructor wxPreviewFrame_destruct + {wxPreviewFrame_CreateControlBar, "wxPreviewFrame", "createControlBar", 1}, // 2433 + {wxPreviewFrame_CreateCanvas, "wxPreviewFrame", "createCanvas", 1}, // 2434 + {wxPreviewFrame_Initialize, "wxPreviewFrame", "initialize", 1}, // 2435 + {wxPreviewFrame_OnCloseWindow, "wxPreviewFrame", "onCloseWindow", 2}, // 2436 + {wxPreviewControlBar_new, "wxPreviewControlBar", "new", 4}, // 2437 + {NULL, "wxPreviewControlBar", "destroy", 1}, // 2438 obj destructor wxPreviewControlBar_destruct + {wxPreviewControlBar_CreateButtons, "wxPreviewControlBar", "createButtons", 1}, // 2439 + {wxPreviewControlBar_GetPrintPreview, "wxPreviewControlBar", "getPrintPreview", 1}, // 2440 + {wxPreviewControlBar_GetZoomControl, "wxPreviewControlBar", "getZoomControl", 1}, // 2441 + {wxPreviewControlBar_SetZoomControl, "wxPreviewControlBar", "setZoomControl", 2}, // 2442 + {wxPrinter_new, "wxPrinter", "new", 1}, // 2443 + {wxPrinter_CreateAbortWindow, "wxPrinter", "createAbortWindow", 3}, // 2444 + {wxPrinter_GetAbort, "wxPrinter", "getAbort", 1}, // 2445 + {wxPrinter_GetLastError, "wxPrinter", "getLastError", 0}, // 2446 + {wxPrinter_GetPrintDialogData, "wxPrinter", "getPrintDialogData", 1}, // 2447 + {wxPrinter_Print, "wxPrinter", "print", 4}, // 2448 + {wxPrinter_PrintDialog, "wxPrinter", "printDialog", 2}, // 2449 + {wxPrinter_ReportError, "wxPrinter", "reportError", 4}, // 2450 + {wxPrinter_Setup, "wxPrinter", "setup", 2}, // 2451 + {NULL, "wxPrinter", "'Destroy'", 1}, // 2452 obj destructor wxPrinter_destroy + {wxXmlResource_new_2, "wxXmlResource", "new", 2}, // 2453 + {wxXmlResource_new_1, "wxXmlResource", "new", 1}, // 2454 + {NULL, "wxXmlResource", "destroy", 1}, // 2455 obj destructor wxXmlResource_destruct + {wxXmlResource_AttachUnknownControl, "wxXmlResource", "attachUnknownControl", 4}, // 2456 + {wxXmlResource_ClearHandlers, "wxXmlResource", "clearHandlers", 1}, // 2457 + {wxXmlResource_CompareVersion, "wxXmlResource", "compareVersion", 5}, // 2458 + {wxXmlResource_Get, "wxXmlResource", "get", 0}, // 2459 + {wxXmlResource_GetFlags, "wxXmlResource", "getFlags", 1}, // 2460 + {wxXmlResource_GetVersion, "wxXmlResource", "getVersion", 1}, // 2461 + {wxXmlResource_GetXRCID, "wxXmlResource", "getXRCID", 2}, // 2462 + {wxXmlResource_InitAllHandlers, "wxXmlResource", "initAllHandlers", 1}, // 2463 + {wxXmlResource_Load, "wxXmlResource", "load", 2}, // 2464 + {wxXmlResource_LoadBitmap, "wxXmlResource", "loadBitmap", 2}, // 2465 + {wxXmlResource_LoadDialog_2, "wxXmlResource", "loadDialog", 3}, // 2466 + {wxXmlResource_LoadDialog_3, "wxXmlResource", "loadDialog", 4}, // 2467 + {wxXmlResource_LoadFrame_2, "wxXmlResource", "loadFrame", 3}, // 2468 + {wxXmlResource_LoadFrame_3, "wxXmlResource", "loadFrame", 4}, // 2469 + {wxXmlResource_LoadIcon, "wxXmlResource", "loadIcon", 2}, // 2470 + {wxXmlResource_LoadMenu, "wxXmlResource", "loadMenu", 2}, // 2471 + {wxXmlResource_LoadMenuBar_2, "wxXmlResource", "loadMenuBar", 3}, // 2472 + {wxXmlResource_LoadMenuBar_1, "wxXmlResource", "loadMenuBar", 2}, // 2473 + {wxXmlResource_LoadPanel_2, "wxXmlResource", "loadPanel", 3}, // 2474 + {wxXmlResource_LoadPanel_3, "wxXmlResource", "loadPanel", 4}, // 2475 + {wxXmlResource_LoadToolBar, "wxXmlResource", "loadToolBar", 3}, // 2476 + {wxXmlResource_Set, "wxXmlResource", "set", 1}, // 2477 + {wxXmlResource_SetFlags, "wxXmlResource", "setFlags", 2}, // 2478 + {wxXmlResource_Unload, "wxXmlResource", "unload", 2}, // 2479 + {NULL, "wxXmlResource", "xrcctrl", 3}, // 2480 TaylorMade erl only wxXmlResource_xrcctrl + {wxHtmlEasyPrinting_new, "wxHtmlEasyPrinting", "new", 1}, // 2481 + {wxHtmlEasyPrinting_GetPrintData, "wxHtmlEasyPrinting", "getPrintData", 1}, // 2482 + {wxHtmlEasyPrinting_GetPageSetupData, "wxHtmlEasyPrinting", "getPageSetupData", 1}, // 2483 + {wxHtmlEasyPrinting_PreviewFile, "wxHtmlEasyPrinting", "previewFile", 2}, // 2484 + {wxHtmlEasyPrinting_PreviewText, "wxHtmlEasyPrinting", "previewText", 3}, // 2485 + {wxHtmlEasyPrinting_PrintFile, "wxHtmlEasyPrinting", "printFile", 2}, // 2486 + {wxHtmlEasyPrinting_PrintText, "wxHtmlEasyPrinting", "printText", 3}, // 2487 + {wxHtmlEasyPrinting_PageSetup, "wxHtmlEasyPrinting", "pageSetup", 1}, // 2488 + {wxHtmlEasyPrinting_SetFonts, "wxHtmlEasyPrinting", "setFonts", 4}, // 2489 + {wxHtmlEasyPrinting_SetHeader, "wxHtmlEasyPrinting", "setHeader", 3}, // 2490 + {wxHtmlEasyPrinting_SetFooter, "wxHtmlEasyPrinting", "setFooter", 3}, // 2491 + {NULL, "wxHtmlEasyPrinting", "'Destroy'", 1}, // 2492 obj destructor wxHtmlEasyPrinting_destroy +#if wxUSE_GLCANVAS + {wxGLCanvas_new, "wxGLCanvas", "new", 2}, // 2493 +#else + {NULL, "wxGLCanvas", "new", 0}, // 2493 +#endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS - {wxGLCanvas_new, "wxGLCanvas", "new", 2}, // 2491 + {wxGLCanvas_SetCurrent, "wxGLCanvas", "setCurrent", 2}, // 2494 #else - {NULL, "wxGLCanvas", "new", 0}, // 2491 + {NULL, "wxGLCanvas", "setCurrent", 0}, // 2494 #endif // wxUSE_GLCANVAS +#if wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL + {wxGLCanvas_CreateSurface, "wxGLCanvas", "createSurface", 1}, // 2495 +#else + {NULL, "wxGLCanvas", "createSurface", 0}, // 2495 +#endif // wxUSE_GLCANVAS && wxUSE_GLCANVAS_EGL #if wxUSE_GLCANVAS - {wxGLCanvas_SetCurrent, "wxGLCanvas", "setCurrent", 2}, // 2492 + {wxGLCanvas_IsDisplaySupported, "wxGLCanvas", "isDisplaySupported", 1}, // 2496 #else - {NULL, "wxGLCanvas", "setCurrent", 0}, // 2492 + {NULL, "wxGLCanvas", "isDisplaySupported", 0}, // 2496 #endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS - {wxGLCanvas_SwapBuffers, "wxGLCanvas", "swapBuffers", 1}, // 2493 + {wxGLCanvas_SwapBuffers, "wxGLCanvas", "swapBuffers", 1}, // 2497 #else - {NULL, "wxGLCanvas", "swapBuffers", 0}, // 2493 + {NULL, "wxGLCanvas", "swapBuffers", 0}, // 2497 #endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS - {NULL, "wxGLCanvas", "'Destroy'", 1}, // 2494 obj destructor wxGLCanvas_destroy + {NULL, "wxGLCanvas", "'Destroy'", 1}, // 2498 obj destructor wxGLCanvas_destroy #else - {NULL, "wxGLCanvas", "'Destroy'", 0}, // 2494 + {NULL, "wxGLCanvas", "'Destroy'", 0}, // 2498 #endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS - {wxGLContext_new, "wxGLContext", "new", 2}, // 2495 + {wxGLContext_new, "wxGLContext", "new", 2}, // 2499 #else - {NULL, "wxGLContext", "new", 0}, // 2495 + {NULL, "wxGLContext", "new", 0}, // 2499 #endif // wxUSE_GLCANVAS #if wxUSE_GLCANVAS - {wxGLContext_SetCurrent, "wxGLContext", "setCurrent", 2}, // 2496 + {wxGLContext_SetCurrent, "wxGLContext", "setCurrent", 2}, // 2500 #else - {NULL, "wxGLContext", "setCurrent", 0}, // 2496 + {NULL, "wxGLContext", "setCurrent", 0}, // 2500 #endif // wxUSE_GLCANVAS +#if wxUSE_GLCANVAS && wxCHECK_VERSION(3,1,0) + {wxGLContext_IsOK, "wxGLContext", "isOK", 1}, // 2501 +#else + {NULL, "wxGLContext", "isOK", 0}, // 2501 +#endif // wxUSE_GLCANVAS && wxCHECK_VERSION(3,1,0) #if wxUSE_GLCANVAS - {NULL, "wxGLContext", "'Destroy'", 1}, // 2497 obj destructor wxGLContext_destroy + {NULL, "wxGLContext", "'Destroy'", 1}, // 2502 obj destructor wxGLContext_destroy #else - {NULL, "wxGLContext", "'Destroy'", 0}, // 2497 + {NULL, "wxGLContext", "'Destroy'", 0}, // 2502 #endif // wxUSE_GLCANVAS #if wxUSE_AUI - {wxAuiManager_new, "wxAuiManager", "new", 1}, // 2498 + {wxAuiManager_new, "wxAuiManager", "new", 1}, // 2503 #else - {NULL, "wxAuiManager", "new", 0}, // 2498 + {NULL, "wxAuiManager", "new", 0}, // 2503 #endif // wxUSE_AUI #if wxUSE_AUI - {NULL, "wxAuiManager", "destroy", 1}, // 2499 obj destructor wxAuiManager_destruct + {NULL, "wxAuiManager", "destroy", 1}, // 2504 obj destructor wxAuiManager_destruct #else - {NULL, "wxAuiManager", "destroy", 0}, // 2499 + {NULL, "wxAuiManager", "destroy", 0}, // 2504 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_AddPane_2_1, "wxAuiManager", "addPane", 3}, // 2500 + {wxAuiManager_AddPane_2_1, "wxAuiManager", "addPane", 3}, // 2505 #else - {NULL, "wxAuiManager", "addPane", 0}, // 2500 + {NULL, "wxAuiManager", "addPane", 0}, // 2505 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_AddPane_2_0, "wxAuiManager", "addPane", 3}, // 2501 + {wxAuiManager_AddPane_2_0, "wxAuiManager", "addPane", 3}, // 2506 #else - {NULL, "wxAuiManager", "addPane", 0}, // 2501 + {NULL, "wxAuiManager", "addPane", 0}, // 2506 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_AddPane_3, "wxAuiManager", "addPane", 4}, // 2502 + {wxAuiManager_AddPane_3, "wxAuiManager", "addPane", 4}, // 2507 #else - {NULL, "wxAuiManager", "addPane", 0}, // 2502 + {NULL, "wxAuiManager", "addPane", 0}, // 2507 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_DetachPane, "wxAuiManager", "detachPane", 2}, // 2503 + {wxAuiManager_DetachPane, "wxAuiManager", "detachPane", 2}, // 2508 #else - {NULL, "wxAuiManager", "detachPane", 0}, // 2503 + {NULL, "wxAuiManager", "detachPane", 0}, // 2508 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetAllPanes, "wxAuiManager", "getAllPanes", 1}, // 2504 + {wxAuiManager_GetAllPanes, "wxAuiManager", "getAllPanes", 1}, // 2509 #else - {NULL, "wxAuiManager", "getAllPanes", 0}, // 2504 + {NULL, "wxAuiManager", "getAllPanes", 0}, // 2509 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetArtProvider, "wxAuiManager", "getArtProvider", 1}, // 2505 + {wxAuiManager_GetArtProvider, "wxAuiManager", "getArtProvider", 1}, // 2510 #else - {NULL, "wxAuiManager", "getArtProvider", 0}, // 2505 + {NULL, "wxAuiManager", "getArtProvider", 0}, // 2510 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetDockSizeConstraint, "wxAuiManager", "getDockSizeConstraint", 1}, // 2506 + {wxAuiManager_GetDockSizeConstraint, "wxAuiManager", "getDockSizeConstraint", 1}, // 2511 #else - {NULL, "wxAuiManager", "getDockSizeConstraint", 0}, // 2506 + {NULL, "wxAuiManager", "getDockSizeConstraint", 0}, // 2511 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetFlags, "wxAuiManager", "getFlags", 1}, // 2507 + {wxAuiManager_GetFlags, "wxAuiManager", "getFlags", 1}, // 2512 #else - {NULL, "wxAuiManager", "getFlags", 0}, // 2507 + {NULL, "wxAuiManager", "getFlags", 0}, // 2512 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetManagedWindow, "wxAuiManager", "getManagedWindow", 1}, // 2508 + {wxAuiManager_GetManagedWindow, "wxAuiManager", "getManagedWindow", 1}, // 2513 #else - {NULL, "wxAuiManager", "getManagedWindow", 0}, // 2508 + {NULL, "wxAuiManager", "getManagedWindow", 0}, // 2513 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetManager, "wxAuiManager", "getManager", 1}, // 2509 + {wxAuiManager_GetManager, "wxAuiManager", "getManager", 1}, // 2514 #else - {NULL, "wxAuiManager", "getManager", 0}, // 2509 + {NULL, "wxAuiManager", "getManager", 0}, // 2514 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetPane_1_1, "wxAuiManager", "getPane", 2}, // 2510 + {wxAuiManager_GetPane_1_1, "wxAuiManager", "getPane", 2}, // 2515 #else - {NULL, "wxAuiManager", "getPane", 0}, // 2510 + {NULL, "wxAuiManager", "getPane", 0}, // 2515 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_GetPane_1_0, "wxAuiManager", "getPane", 2}, // 2511 + {wxAuiManager_GetPane_1_0, "wxAuiManager", "getPane", 2}, // 2516 #else - {NULL, "wxAuiManager", "getPane", 0}, // 2511 + {NULL, "wxAuiManager", "getPane", 0}, // 2516 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_HideHint, "wxAuiManager", "hideHint", 1}, // 2512 + {wxAuiManager_HideHint, "wxAuiManager", "hideHint", 1}, // 2517 #else - {NULL, "wxAuiManager", "hideHint", 0}, // 2512 + {NULL, "wxAuiManager", "hideHint", 0}, // 2517 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_InsertPane, "wxAuiManager", "insertPane", 4}, // 2513 + {wxAuiManager_InsertPane, "wxAuiManager", "insertPane", 4}, // 2518 #else - {NULL, "wxAuiManager", "insertPane", 0}, // 2513 + {NULL, "wxAuiManager", "insertPane", 0}, // 2518 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_LoadPaneInfo, "wxAuiManager", "loadPaneInfo", 3}, // 2514 + {wxAuiManager_LoadPaneInfo, "wxAuiManager", "loadPaneInfo", 3}, // 2519 #else - {NULL, "wxAuiManager", "loadPaneInfo", 0}, // 2514 + {NULL, "wxAuiManager", "loadPaneInfo", 0}, // 2519 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_LoadPerspective, "wxAuiManager", "loadPerspective", 3}, // 2515 + {wxAuiManager_LoadPerspective, "wxAuiManager", "loadPerspective", 3}, // 2520 #else - {NULL, "wxAuiManager", "loadPerspective", 0}, // 2515 + {NULL, "wxAuiManager", "loadPerspective", 0}, // 2520 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SavePaneInfo, "wxAuiManager", "savePaneInfo", 2}, // 2516 + {wxAuiManager_SavePaneInfo, "wxAuiManager", "savePaneInfo", 2}, // 2521 #else - {NULL, "wxAuiManager", "savePaneInfo", 0}, // 2516 + {NULL, "wxAuiManager", "savePaneInfo", 0}, // 2521 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SavePerspective, "wxAuiManager", "savePerspective", 1}, // 2517 + {wxAuiManager_SavePerspective, "wxAuiManager", "savePerspective", 1}, // 2522 #else - {NULL, "wxAuiManager", "savePerspective", 0}, // 2517 + {NULL, "wxAuiManager", "savePerspective", 0}, // 2522 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SetArtProvider, "wxAuiManager", "setArtProvider", 2}, // 2518 + {wxAuiManager_SetArtProvider, "wxAuiManager", "setArtProvider", 2}, // 2523 #else - {NULL, "wxAuiManager", "setArtProvider", 0}, // 2518 + {NULL, "wxAuiManager", "setArtProvider", 0}, // 2523 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SetDockSizeConstraint, "wxAuiManager", "setDockSizeConstraint", 3}, // 2519 + {wxAuiManager_SetDockSizeConstraint, "wxAuiManager", "setDockSizeConstraint", 3}, // 2524 #else - {NULL, "wxAuiManager", "setDockSizeConstraint", 0}, // 2519 + {NULL, "wxAuiManager", "setDockSizeConstraint", 0}, // 2524 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SetFlags, "wxAuiManager", "setFlags", 2}, // 2520 + {wxAuiManager_SetFlags, "wxAuiManager", "setFlags", 2}, // 2525 #else - {NULL, "wxAuiManager", "setFlags", 0}, // 2520 + {NULL, "wxAuiManager", "setFlags", 0}, // 2525 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_SetManagedWindow, "wxAuiManager", "setManagedWindow", 2}, // 2521 + {wxAuiManager_SetManagedWindow, "wxAuiManager", "setManagedWindow", 2}, // 2526 #else - {NULL, "wxAuiManager", "setManagedWindow", 0}, // 2521 + {NULL, "wxAuiManager", "setManagedWindow", 0}, // 2526 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_ShowHint, "wxAuiManager", "showHint", 2}, // 2522 + {wxAuiManager_ShowHint, "wxAuiManager", "showHint", 2}, // 2527 #else - {NULL, "wxAuiManager", "showHint", 0}, // 2522 + {NULL, "wxAuiManager", "showHint", 0}, // 2527 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_UnInit, "wxAuiManager", "unInit", 1}, // 2523 + {wxAuiManager_UnInit, "wxAuiManager", "unInit", 1}, // 2528 #else - {NULL, "wxAuiManager", "unInit", 0}, // 2523 + {NULL, "wxAuiManager", "unInit", 0}, // 2528 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiManager_Update, "wxAuiManager", "update", 1}, // 2524 + {wxAuiManager_Update, "wxAuiManager", "update", 1}, // 2529 #else - {NULL, "wxAuiManager", "update", 0}, // 2524 + {NULL, "wxAuiManager", "update", 0}, // 2529 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_new_0, "wxAuiPaneInfo", "new", 0}, // 2525 + {wxAuiPaneInfo_new_0, "wxAuiPaneInfo", "new", 0}, // 2530 #else - {NULL, "wxAuiPaneInfo", "new", 0}, // 2525 + {NULL, "wxAuiPaneInfo", "new", 0}, // 2530 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_new_1, "wxAuiPaneInfo", "new", 1}, // 2526 + {wxAuiPaneInfo_new_1, "wxAuiPaneInfo", "new", 1}, // 2531 #else - {NULL, "wxAuiPaneInfo", "new", 0}, // 2526 + {NULL, "wxAuiPaneInfo", "new", 0}, // 2531 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_BestSize_1, "wxAuiPaneInfo", "bestSize", 2}, // 2527 + {wxAuiPaneInfo_BestSize_1, "wxAuiPaneInfo", "bestSize", 2}, // 2532 #else - {NULL, "wxAuiPaneInfo", "bestSize", 0}, // 2527 + {NULL, "wxAuiPaneInfo", "bestSize", 0}, // 2532 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_BestSize_2, "wxAuiPaneInfo", "bestSize", 3}, // 2528 + {wxAuiPaneInfo_BestSize_2, "wxAuiPaneInfo", "bestSize", 3}, // 2533 #else - {NULL, "wxAuiPaneInfo", "bestSize", 0}, // 2528 + {NULL, "wxAuiPaneInfo", "bestSize", 0}, // 2533 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Bottom, "wxAuiPaneInfo", "bottom", 1}, // 2529 + {wxAuiPaneInfo_Bottom, "wxAuiPaneInfo", "bottom", 1}, // 2534 #else - {NULL, "wxAuiPaneInfo", "bottom", 0}, // 2529 + {NULL, "wxAuiPaneInfo", "bottom", 0}, // 2534 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_BottomDockable, "wxAuiPaneInfo", "bottomDockable", 2}, // 2530 + {wxAuiPaneInfo_BottomDockable, "wxAuiPaneInfo", "bottomDockable", 2}, // 2535 #else - {NULL, "wxAuiPaneInfo", "bottomDockable", 0}, // 2530 + {NULL, "wxAuiPaneInfo", "bottomDockable", 0}, // 2535 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Caption, "wxAuiPaneInfo", "caption", 2}, // 2531 + {wxAuiPaneInfo_Caption, "wxAuiPaneInfo", "caption", 2}, // 2536 #else - {NULL, "wxAuiPaneInfo", "caption", 0}, // 2531 + {NULL, "wxAuiPaneInfo", "caption", 0}, // 2536 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_CaptionVisible, "wxAuiPaneInfo", "captionVisible", 2}, // 2532 + {wxAuiPaneInfo_CaptionVisible, "wxAuiPaneInfo", "captionVisible", 2}, // 2537 #else - {NULL, "wxAuiPaneInfo", "captionVisible", 0}, // 2532 + {NULL, "wxAuiPaneInfo", "captionVisible", 0}, // 2537 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Centre, "wxAuiPaneInfo", "centre", 1}, // 2533 + {wxAuiPaneInfo_Centre, "wxAuiPaneInfo", "centre", 1}, // 2538 #else - {NULL, "wxAuiPaneInfo", "centre", 0}, // 2533 + {NULL, "wxAuiPaneInfo", "centre", 0}, // 2538 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_CentrePane, "wxAuiPaneInfo", "centrePane", 1}, // 2534 + {wxAuiPaneInfo_CentrePane, "wxAuiPaneInfo", "centrePane", 1}, // 2539 #else - {NULL, "wxAuiPaneInfo", "centrePane", 0}, // 2534 + {NULL, "wxAuiPaneInfo", "centrePane", 0}, // 2539 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_CloseButton, "wxAuiPaneInfo", "closeButton", 2}, // 2535 + {wxAuiPaneInfo_CloseButton, "wxAuiPaneInfo", "closeButton", 2}, // 2540 #else - {NULL, "wxAuiPaneInfo", "closeButton", 0}, // 2535 + {NULL, "wxAuiPaneInfo", "closeButton", 0}, // 2540 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_DefaultPane, "wxAuiPaneInfo", "defaultPane", 1}, // 2536 + {wxAuiPaneInfo_DefaultPane, "wxAuiPaneInfo", "defaultPane", 1}, // 2541 #else - {NULL, "wxAuiPaneInfo", "defaultPane", 0}, // 2536 + {NULL, "wxAuiPaneInfo", "defaultPane", 0}, // 2541 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_DestroyOnClose, "wxAuiPaneInfo", "destroyOnClose", 2}, // 2537 + {wxAuiPaneInfo_DestroyOnClose, "wxAuiPaneInfo", "destroyOnClose", 2}, // 2542 #else - {NULL, "wxAuiPaneInfo", "destroyOnClose", 0}, // 2537 + {NULL, "wxAuiPaneInfo", "destroyOnClose", 0}, // 2542 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Direction, "wxAuiPaneInfo", "direction", 2}, // 2538 + {wxAuiPaneInfo_Direction, "wxAuiPaneInfo", "direction", 2}, // 2543 #else - {NULL, "wxAuiPaneInfo", "direction", 0}, // 2538 + {NULL, "wxAuiPaneInfo", "direction", 0}, // 2543 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Dock, "wxAuiPaneInfo", "dock", 1}, // 2539 + {wxAuiPaneInfo_Dock, "wxAuiPaneInfo", "dock", 1}, // 2544 #else - {NULL, "wxAuiPaneInfo", "dock", 0}, // 2539 + {NULL, "wxAuiPaneInfo", "dock", 0}, // 2544 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Dockable, "wxAuiPaneInfo", "dockable", 2}, // 2540 + {wxAuiPaneInfo_Dockable, "wxAuiPaneInfo", "dockable", 2}, // 2545 #else - {NULL, "wxAuiPaneInfo", "dockable", 0}, // 2540 + {NULL, "wxAuiPaneInfo", "dockable", 0}, // 2545 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Fixed, "wxAuiPaneInfo", "fixed", 1}, // 2541 + {wxAuiPaneInfo_Fixed, "wxAuiPaneInfo", "fixed", 1}, // 2546 #else - {NULL, "wxAuiPaneInfo", "fixed", 0}, // 2541 + {NULL, "wxAuiPaneInfo", "fixed", 0}, // 2546 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Float, "wxAuiPaneInfo", "float", 1}, // 2542 + {wxAuiPaneInfo_Float, "wxAuiPaneInfo", "float", 1}, // 2547 #else - {NULL, "wxAuiPaneInfo", "float", 0}, // 2542 + {NULL, "wxAuiPaneInfo", "float", 0}, // 2547 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Floatable, "wxAuiPaneInfo", "floatable", 2}, // 2543 + {wxAuiPaneInfo_Floatable, "wxAuiPaneInfo", "floatable", 2}, // 2548 #else - {NULL, "wxAuiPaneInfo", "floatable", 0}, // 2543 + {NULL, "wxAuiPaneInfo", "floatable", 0}, // 2548 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_FloatingPosition_1, "wxAuiPaneInfo", "floatingPosition", 2}, // 2544 + {wxAuiPaneInfo_FloatingPosition_1, "wxAuiPaneInfo", "floatingPosition", 2}, // 2549 #else - {NULL, "wxAuiPaneInfo", "floatingPosition", 0}, // 2544 + {NULL, "wxAuiPaneInfo", "floatingPosition", 0}, // 2549 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_FloatingPosition_2, "wxAuiPaneInfo", "floatingPosition", 3}, // 2545 + {wxAuiPaneInfo_FloatingPosition_2, "wxAuiPaneInfo", "floatingPosition", 3}, // 2550 #else - {NULL, "wxAuiPaneInfo", "floatingPosition", 0}, // 2545 + {NULL, "wxAuiPaneInfo", "floatingPosition", 0}, // 2550 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_FloatingSize_1, "wxAuiPaneInfo", "floatingSize", 2}, // 2546 + {wxAuiPaneInfo_FloatingSize_1, "wxAuiPaneInfo", "floatingSize", 2}, // 2551 #else - {NULL, "wxAuiPaneInfo", "floatingSize", 0}, // 2546 + {NULL, "wxAuiPaneInfo", "floatingSize", 0}, // 2551 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_FloatingSize_2, "wxAuiPaneInfo", "floatingSize", 3}, // 2547 + {wxAuiPaneInfo_FloatingSize_2, "wxAuiPaneInfo", "floatingSize", 3}, // 2552 #else - {NULL, "wxAuiPaneInfo", "floatingSize", 0}, // 2547 + {NULL, "wxAuiPaneInfo", "floatingSize", 0}, // 2552 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Gripper, "wxAuiPaneInfo", "gripper", 2}, // 2548 + {wxAuiPaneInfo_Gripper, "wxAuiPaneInfo", "gripper", 2}, // 2553 #else - {NULL, "wxAuiPaneInfo", "gripper", 0}, // 2548 + {NULL, "wxAuiPaneInfo", "gripper", 0}, // 2553 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GripperTop, "wxAuiPaneInfo", "gripperTop", 2}, // 2549 + {wxAuiPaneInfo_GripperTop, "wxAuiPaneInfo", "gripperTop", 2}, // 2554 #else - {NULL, "wxAuiPaneInfo", "gripperTop", 0}, // 2549 + {NULL, "wxAuiPaneInfo", "gripperTop", 0}, // 2554 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasBorder, "wxAuiPaneInfo", "hasBorder", 1}, // 2550 + {wxAuiPaneInfo_HasBorder, "wxAuiPaneInfo", "hasBorder", 1}, // 2555 #else - {NULL, "wxAuiPaneInfo", "hasBorder", 0}, // 2550 + {NULL, "wxAuiPaneInfo", "hasBorder", 0}, // 2555 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasCaption, "wxAuiPaneInfo", "hasCaption", 1}, // 2551 + {wxAuiPaneInfo_HasCaption, "wxAuiPaneInfo", "hasCaption", 1}, // 2556 #else - {NULL, "wxAuiPaneInfo", "hasCaption", 0}, // 2551 + {NULL, "wxAuiPaneInfo", "hasCaption", 0}, // 2556 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasCloseButton, "wxAuiPaneInfo", "hasCloseButton", 1}, // 2552 + {wxAuiPaneInfo_HasCloseButton, "wxAuiPaneInfo", "hasCloseButton", 1}, // 2557 #else - {NULL, "wxAuiPaneInfo", "hasCloseButton", 0}, // 2552 + {NULL, "wxAuiPaneInfo", "hasCloseButton", 0}, // 2557 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasFlag, "wxAuiPaneInfo", "hasFlag", 2}, // 2553 + {wxAuiPaneInfo_HasFlag, "wxAuiPaneInfo", "hasFlag", 2}, // 2558 #else - {NULL, "wxAuiPaneInfo", "hasFlag", 0}, // 2553 + {NULL, "wxAuiPaneInfo", "hasFlag", 0}, // 2558 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasGripper, "wxAuiPaneInfo", "hasGripper", 1}, // 2554 + {wxAuiPaneInfo_HasGripper, "wxAuiPaneInfo", "hasGripper", 1}, // 2559 #else - {NULL, "wxAuiPaneInfo", "hasGripper", 0}, // 2554 + {NULL, "wxAuiPaneInfo", "hasGripper", 0}, // 2559 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasGripperTop, "wxAuiPaneInfo", "hasGripperTop", 1}, // 2555 + {wxAuiPaneInfo_HasGripperTop, "wxAuiPaneInfo", "hasGripperTop", 1}, // 2560 #else - {NULL, "wxAuiPaneInfo", "hasGripperTop", 0}, // 2555 + {NULL, "wxAuiPaneInfo", "hasGripperTop", 0}, // 2560 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasMaximizeButton, "wxAuiPaneInfo", "hasMaximizeButton", 1}, // 2556 + {wxAuiPaneInfo_HasMaximizeButton, "wxAuiPaneInfo", "hasMaximizeButton", 1}, // 2561 #else - {NULL, "wxAuiPaneInfo", "hasMaximizeButton", 0}, // 2556 + {NULL, "wxAuiPaneInfo", "hasMaximizeButton", 0}, // 2561 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasMinimizeButton, "wxAuiPaneInfo", "hasMinimizeButton", 1}, // 2557 + {wxAuiPaneInfo_HasMinimizeButton, "wxAuiPaneInfo", "hasMinimizeButton", 1}, // 2562 #else - {NULL, "wxAuiPaneInfo", "hasMinimizeButton", 0}, // 2557 + {NULL, "wxAuiPaneInfo", "hasMinimizeButton", 0}, // 2562 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_HasPinButton, "wxAuiPaneInfo", "hasPinButton", 1}, // 2558 + {wxAuiPaneInfo_HasPinButton, "wxAuiPaneInfo", "hasPinButton", 1}, // 2563 #else - {NULL, "wxAuiPaneInfo", "hasPinButton", 0}, // 2558 + {NULL, "wxAuiPaneInfo", "hasPinButton", 0}, // 2563 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Hide, "wxAuiPaneInfo", "hide", 1}, // 2559 + {wxAuiPaneInfo_Hide, "wxAuiPaneInfo", "hide", 1}, // 2564 #else - {NULL, "wxAuiPaneInfo", "hide", 0}, // 2559 + {NULL, "wxAuiPaneInfo", "hide", 0}, // 2564 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsBottomDockable, "wxAuiPaneInfo", "isBottomDockable", 1}, // 2560 + {wxAuiPaneInfo_IsBottomDockable, "wxAuiPaneInfo", "isBottomDockable", 1}, // 2565 #else - {NULL, "wxAuiPaneInfo", "isBottomDockable", 0}, // 2560 + {NULL, "wxAuiPaneInfo", "isBottomDockable", 0}, // 2565 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsDocked, "wxAuiPaneInfo", "isDocked", 1}, // 2561 + {wxAuiPaneInfo_IsDocked, "wxAuiPaneInfo", "isDocked", 1}, // 2566 #else - {NULL, "wxAuiPaneInfo", "isDocked", 0}, // 2561 + {NULL, "wxAuiPaneInfo", "isDocked", 0}, // 2566 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsFixed, "wxAuiPaneInfo", "isFixed", 1}, // 2562 + {wxAuiPaneInfo_IsFixed, "wxAuiPaneInfo", "isFixed", 1}, // 2567 #else - {NULL, "wxAuiPaneInfo", "isFixed", 0}, // 2562 + {NULL, "wxAuiPaneInfo", "isFixed", 0}, // 2567 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsFloatable, "wxAuiPaneInfo", "isFloatable", 1}, // 2563 + {wxAuiPaneInfo_IsFloatable, "wxAuiPaneInfo", "isFloatable", 1}, // 2568 #else - {NULL, "wxAuiPaneInfo", "isFloatable", 0}, // 2563 + {NULL, "wxAuiPaneInfo", "isFloatable", 0}, // 2568 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsFloating, "wxAuiPaneInfo", "isFloating", 1}, // 2564 + {wxAuiPaneInfo_IsFloating, "wxAuiPaneInfo", "isFloating", 1}, // 2569 #else - {NULL, "wxAuiPaneInfo", "isFloating", 0}, // 2564 + {NULL, "wxAuiPaneInfo", "isFloating", 0}, // 2569 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsLeftDockable, "wxAuiPaneInfo", "isLeftDockable", 1}, // 2565 + {wxAuiPaneInfo_IsLeftDockable, "wxAuiPaneInfo", "isLeftDockable", 1}, // 2570 #else - {NULL, "wxAuiPaneInfo", "isLeftDockable", 0}, // 2565 + {NULL, "wxAuiPaneInfo", "isLeftDockable", 0}, // 2570 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsMovable, "wxAuiPaneInfo", "isMovable", 1}, // 2566 + {wxAuiPaneInfo_IsMovable, "wxAuiPaneInfo", "isMovable", 1}, // 2571 #else - {NULL, "wxAuiPaneInfo", "isMovable", 0}, // 2566 + {NULL, "wxAuiPaneInfo", "isMovable", 0}, // 2571 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsOk, "wxAuiPaneInfo", "isOk", 1}, // 2567 + {wxAuiPaneInfo_IsOk, "wxAuiPaneInfo", "isOk", 1}, // 2572 #else - {NULL, "wxAuiPaneInfo", "isOk", 0}, // 2567 + {NULL, "wxAuiPaneInfo", "isOk", 0}, // 2572 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsResizable, "wxAuiPaneInfo", "isResizable", 1}, // 2568 + {wxAuiPaneInfo_IsResizable, "wxAuiPaneInfo", "isResizable", 1}, // 2573 #else - {NULL, "wxAuiPaneInfo", "isResizable", 0}, // 2568 + {NULL, "wxAuiPaneInfo", "isResizable", 0}, // 2573 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsRightDockable, "wxAuiPaneInfo", "isRightDockable", 1}, // 2569 + {wxAuiPaneInfo_IsRightDockable, "wxAuiPaneInfo", "isRightDockable", 1}, // 2574 #else - {NULL, "wxAuiPaneInfo", "isRightDockable", 0}, // 2569 + {NULL, "wxAuiPaneInfo", "isRightDockable", 0}, // 2574 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsShown, "wxAuiPaneInfo", "isShown", 1}, // 2570 + {wxAuiPaneInfo_IsShown, "wxAuiPaneInfo", "isShown", 1}, // 2575 #else - {NULL, "wxAuiPaneInfo", "isShown", 0}, // 2570 + {NULL, "wxAuiPaneInfo", "isShown", 0}, // 2575 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsToolbar, "wxAuiPaneInfo", "isToolbar", 1}, // 2571 + {wxAuiPaneInfo_IsToolbar, "wxAuiPaneInfo", "isToolbar", 1}, // 2576 #else - {NULL, "wxAuiPaneInfo", "isToolbar", 0}, // 2571 + {NULL, "wxAuiPaneInfo", "isToolbar", 0}, // 2576 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_IsTopDockable, "wxAuiPaneInfo", "isTopDockable", 1}, // 2572 + {wxAuiPaneInfo_IsTopDockable, "wxAuiPaneInfo", "isTopDockable", 1}, // 2577 #else - {NULL, "wxAuiPaneInfo", "isTopDockable", 0}, // 2572 + {NULL, "wxAuiPaneInfo", "isTopDockable", 0}, // 2577 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Layer, "wxAuiPaneInfo", "layer", 2}, // 2573 + {wxAuiPaneInfo_Layer, "wxAuiPaneInfo", "layer", 2}, // 2578 #else - {NULL, "wxAuiPaneInfo", "layer", 0}, // 2573 + {NULL, "wxAuiPaneInfo", "layer", 0}, // 2578 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Left, "wxAuiPaneInfo", "left", 1}, // 2574 + {wxAuiPaneInfo_Left, "wxAuiPaneInfo", "left", 1}, // 2579 #else - {NULL, "wxAuiPaneInfo", "left", 0}, // 2574 + {NULL, "wxAuiPaneInfo", "left", 0}, // 2579 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_LeftDockable, "wxAuiPaneInfo", "leftDockable", 2}, // 2575 + {wxAuiPaneInfo_LeftDockable, "wxAuiPaneInfo", "leftDockable", 2}, // 2580 #else - {NULL, "wxAuiPaneInfo", "leftDockable", 0}, // 2575 + {NULL, "wxAuiPaneInfo", "leftDockable", 0}, // 2580 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MaxSize_1, "wxAuiPaneInfo", "maxSize", 2}, // 2576 + {wxAuiPaneInfo_MaxSize_1, "wxAuiPaneInfo", "maxSize", 2}, // 2581 #else - {NULL, "wxAuiPaneInfo", "maxSize", 0}, // 2576 + {NULL, "wxAuiPaneInfo", "maxSize", 0}, // 2581 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MaxSize_2, "wxAuiPaneInfo", "maxSize", 3}, // 2577 + {wxAuiPaneInfo_MaxSize_2, "wxAuiPaneInfo", "maxSize", 3}, // 2582 #else - {NULL, "wxAuiPaneInfo", "maxSize", 0}, // 2577 + {NULL, "wxAuiPaneInfo", "maxSize", 0}, // 2582 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MaximizeButton, "wxAuiPaneInfo", "maximizeButton", 2}, // 2578 + {wxAuiPaneInfo_MaximizeButton, "wxAuiPaneInfo", "maximizeButton", 2}, // 2583 #else - {NULL, "wxAuiPaneInfo", "maximizeButton", 0}, // 2578 + {NULL, "wxAuiPaneInfo", "maximizeButton", 0}, // 2583 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MinSize_1, "wxAuiPaneInfo", "minSize", 2}, // 2579 + {wxAuiPaneInfo_MinSize_1, "wxAuiPaneInfo", "minSize", 2}, // 2584 #else - {NULL, "wxAuiPaneInfo", "minSize", 0}, // 2579 + {NULL, "wxAuiPaneInfo", "minSize", 0}, // 2584 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MinSize_2, "wxAuiPaneInfo", "minSize", 3}, // 2580 + {wxAuiPaneInfo_MinSize_2, "wxAuiPaneInfo", "minSize", 3}, // 2585 #else - {NULL, "wxAuiPaneInfo", "minSize", 0}, // 2580 + {NULL, "wxAuiPaneInfo", "minSize", 0}, // 2585 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_MinimizeButton, "wxAuiPaneInfo", "minimizeButton", 2}, // 2581 + {wxAuiPaneInfo_MinimizeButton, "wxAuiPaneInfo", "minimizeButton", 2}, // 2586 #else - {NULL, "wxAuiPaneInfo", "minimizeButton", 0}, // 2581 + {NULL, "wxAuiPaneInfo", "minimizeButton", 0}, // 2586 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Movable, "wxAuiPaneInfo", "movable", 2}, // 2582 + {wxAuiPaneInfo_Movable, "wxAuiPaneInfo", "movable", 2}, // 2587 #else - {NULL, "wxAuiPaneInfo", "movable", 0}, // 2582 + {NULL, "wxAuiPaneInfo", "movable", 0}, // 2587 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Name, "wxAuiPaneInfo", "name", 2}, // 2583 + {wxAuiPaneInfo_Name, "wxAuiPaneInfo", "name", 2}, // 2588 #else - {NULL, "wxAuiPaneInfo", "name", 0}, // 2583 + {NULL, "wxAuiPaneInfo", "name", 0}, // 2588 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_PaneBorder, "wxAuiPaneInfo", "paneBorder", 2}, // 2584 + {wxAuiPaneInfo_PaneBorder, "wxAuiPaneInfo", "paneBorder", 2}, // 2589 #else - {NULL, "wxAuiPaneInfo", "paneBorder", 0}, // 2584 + {NULL, "wxAuiPaneInfo", "paneBorder", 0}, // 2589 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_PinButton, "wxAuiPaneInfo", "pinButton", 2}, // 2585 + {wxAuiPaneInfo_PinButton, "wxAuiPaneInfo", "pinButton", 2}, // 2590 #else - {NULL, "wxAuiPaneInfo", "pinButton", 0}, // 2585 + {NULL, "wxAuiPaneInfo", "pinButton", 0}, // 2590 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Position, "wxAuiPaneInfo", "position", 2}, // 2586 + {wxAuiPaneInfo_Position, "wxAuiPaneInfo", "position", 2}, // 2591 #else - {NULL, "wxAuiPaneInfo", "position", 0}, // 2586 + {NULL, "wxAuiPaneInfo", "position", 0}, // 2591 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Resizable, "wxAuiPaneInfo", "resizable", 2}, // 2587 + {wxAuiPaneInfo_Resizable, "wxAuiPaneInfo", "resizable", 2}, // 2592 #else - {NULL, "wxAuiPaneInfo", "resizable", 0}, // 2587 + {NULL, "wxAuiPaneInfo", "resizable", 0}, // 2592 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Right, "wxAuiPaneInfo", "right", 1}, // 2588 + {wxAuiPaneInfo_Right, "wxAuiPaneInfo", "right", 1}, // 2593 #else - {NULL, "wxAuiPaneInfo", "right", 0}, // 2588 + {NULL, "wxAuiPaneInfo", "right", 0}, // 2593 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_RightDockable, "wxAuiPaneInfo", "rightDockable", 2}, // 2589 + {wxAuiPaneInfo_RightDockable, "wxAuiPaneInfo", "rightDockable", 2}, // 2594 #else - {NULL, "wxAuiPaneInfo", "rightDockable", 0}, // 2589 + {NULL, "wxAuiPaneInfo", "rightDockable", 0}, // 2594 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Row, "wxAuiPaneInfo", "row", 2}, // 2590 + {wxAuiPaneInfo_Row, "wxAuiPaneInfo", "row", 2}, // 2595 #else - {NULL, "wxAuiPaneInfo", "row", 0}, // 2590 + {NULL, "wxAuiPaneInfo", "row", 0}, // 2595 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_SafeSet, "wxAuiPaneInfo", "safeSet", 2}, // 2591 + {wxAuiPaneInfo_SafeSet, "wxAuiPaneInfo", "safeSet", 2}, // 2596 #else - {NULL, "wxAuiPaneInfo", "safeSet", 0}, // 2591 + {NULL, "wxAuiPaneInfo", "safeSet", 0}, // 2596 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_SetFlag, "wxAuiPaneInfo", "setFlag", 3}, // 2592 + {wxAuiPaneInfo_SetFlag, "wxAuiPaneInfo", "setFlag", 3}, // 2597 #else - {NULL, "wxAuiPaneInfo", "setFlag", 0}, // 2592 + {NULL, "wxAuiPaneInfo", "setFlag", 0}, // 2597 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Show, "wxAuiPaneInfo", "show", 2}, // 2593 + {wxAuiPaneInfo_Show, "wxAuiPaneInfo", "show", 2}, // 2598 #else - {NULL, "wxAuiPaneInfo", "show", 0}, // 2593 + {NULL, "wxAuiPaneInfo", "show", 0}, // 2598 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_ToolbarPane, "wxAuiPaneInfo", "toolbarPane", 1}, // 2594 + {wxAuiPaneInfo_ToolbarPane, "wxAuiPaneInfo", "toolbarPane", 1}, // 2599 #else - {NULL, "wxAuiPaneInfo", "toolbarPane", 0}, // 2594 + {NULL, "wxAuiPaneInfo", "toolbarPane", 0}, // 2599 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Top, "wxAuiPaneInfo", "top", 1}, // 2595 + {wxAuiPaneInfo_Top, "wxAuiPaneInfo", "top", 1}, // 2600 #else - {NULL, "wxAuiPaneInfo", "top", 0}, // 2595 + {NULL, "wxAuiPaneInfo", "top", 0}, // 2600 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_TopDockable, "wxAuiPaneInfo", "topDockable", 2}, // 2596 + {wxAuiPaneInfo_TopDockable, "wxAuiPaneInfo", "topDockable", 2}, // 2601 #else - {NULL, "wxAuiPaneInfo", "topDockable", 0}, // 2596 + {NULL, "wxAuiPaneInfo", "topDockable", 0}, // 2601 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_Window, "wxAuiPaneInfo", "window", 2}, // 2597 + {wxAuiPaneInfo_Window, "wxAuiPaneInfo", "window", 2}, // 2602 #else - {NULL, "wxAuiPaneInfo", "window", 0}, // 2597 + {NULL, "wxAuiPaneInfo", "window", 0}, // 2602 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetWindow, "wxAuiPaneInfo", "getWindow", 1}, // 2598 + {wxAuiPaneInfo_GetWindow, "wxAuiPaneInfo", "getWindow", 1}, // 2603 #else - {NULL, "wxAuiPaneInfo", "getWindow", 0}, // 2598 + {NULL, "wxAuiPaneInfo", "getWindow", 0}, // 2603 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetFrame, "wxAuiPaneInfo", "getFrame", 1}, // 2599 + {wxAuiPaneInfo_GetFrame, "wxAuiPaneInfo", "getFrame", 1}, // 2604 #else - {NULL, "wxAuiPaneInfo", "getFrame", 0}, // 2599 + {NULL, "wxAuiPaneInfo", "getFrame", 0}, // 2604 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetDirection, "wxAuiPaneInfo", "getDirection", 1}, // 2600 + {wxAuiPaneInfo_GetDirection, "wxAuiPaneInfo", "getDirection", 1}, // 2605 #else - {NULL, "wxAuiPaneInfo", "getDirection", 0}, // 2600 + {NULL, "wxAuiPaneInfo", "getDirection", 0}, // 2605 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetLayer, "wxAuiPaneInfo", "getLayer", 1}, // 2601 + {wxAuiPaneInfo_GetLayer, "wxAuiPaneInfo", "getLayer", 1}, // 2606 #else - {NULL, "wxAuiPaneInfo", "getLayer", 0}, // 2601 + {NULL, "wxAuiPaneInfo", "getLayer", 0}, // 2606 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetRow, "wxAuiPaneInfo", "getRow", 1}, // 2602 + {wxAuiPaneInfo_GetRow, "wxAuiPaneInfo", "getRow", 1}, // 2607 #else - {NULL, "wxAuiPaneInfo", "getRow", 0}, // 2602 + {NULL, "wxAuiPaneInfo", "getRow", 0}, // 2607 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetPosition, "wxAuiPaneInfo", "getPosition", 1}, // 2603 + {wxAuiPaneInfo_GetPosition, "wxAuiPaneInfo", "getPosition", 1}, // 2608 #else - {NULL, "wxAuiPaneInfo", "getPosition", 0}, // 2603 + {NULL, "wxAuiPaneInfo", "getPosition", 0}, // 2608 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetFloatingPosition, "wxAuiPaneInfo", "getFloatingPosition", 1}, // 2604 + {wxAuiPaneInfo_GetFloatingPosition, "wxAuiPaneInfo", "getFloatingPosition", 1}, // 2609 #else - {NULL, "wxAuiPaneInfo", "getFloatingPosition", 0}, // 2604 + {NULL, "wxAuiPaneInfo", "getFloatingPosition", 0}, // 2609 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_GetFloatingSize, "wxAuiPaneInfo", "getFloatingSize", 1}, // 2605 + {wxAuiPaneInfo_GetFloatingSize, "wxAuiPaneInfo", "getFloatingSize", 1}, // 2610 #else - {NULL, "wxAuiPaneInfo", "getFloatingSize", 0}, // 2605 + {NULL, "wxAuiPaneInfo", "getFloatingSize", 0}, // 2610 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiPaneInfo_destroy, "wxAuiPaneInfo", "'Destroy'", 1}, // 2606 + {wxAuiPaneInfo_destroy, "wxAuiPaneInfo", "'Destroy'", 1}, // 2611 #else - {NULL, "wxAuiPaneInfo", "'Destroy'", 0}, // 2606 + {NULL, "wxAuiPaneInfo", "'Destroy'", 0}, // 2611 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_new_0, "wxAuiNotebook", "new", 0}, // 2607 + {wxAuiNotebook_new_0, "wxAuiNotebook", "new", 0}, // 2612 #else - {NULL, "wxAuiNotebook", "new", 0}, // 2607 + {NULL, "wxAuiNotebook", "new", 0}, // 2612 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_new_2, "wxAuiNotebook", "new", 2}, // 2608 + {wxAuiNotebook_new_2, "wxAuiNotebook", "new", 2}, // 2613 #else - {NULL, "wxAuiNotebook", "new", 0}, // 2608 + {NULL, "wxAuiNotebook", "new", 0}, // 2613 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_AddPage_3, "wxAuiNotebook", "addPage", 4}, // 2609 + {wxAuiNotebook_AddPage_3, "wxAuiNotebook", "addPage", 4}, // 2614 #else - {NULL, "wxAuiNotebook", "addPage", 0}, // 2609 + {NULL, "wxAuiNotebook", "addPage", 0}, // 2614 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_AddPage_4, "wxAuiNotebook", "addPage", 5}, // 2610 + {wxAuiNotebook_AddPage_4, "wxAuiNotebook", "addPage", 5}, // 2615 #else - {NULL, "wxAuiNotebook", "addPage", 0}, // 2610 + {NULL, "wxAuiNotebook", "addPage", 0}, // 2615 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_Create_2, "wxAuiNotebook", "create", 3}, // 2611 + {wxAuiNotebook_Create_2, "wxAuiNotebook", "create", 3}, // 2616 #else - {NULL, "wxAuiNotebook", "create", 0}, // 2611 + {NULL, "wxAuiNotebook", "create", 0}, // 2616 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_Create_3, "wxAuiNotebook", "create", 4}, // 2612 + {wxAuiNotebook_Create_3, "wxAuiNotebook", "create", 4}, // 2617 #else - {NULL, "wxAuiNotebook", "create", 0}, // 2612 + {NULL, "wxAuiNotebook", "create", 0}, // 2617 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_DeletePage, "wxAuiNotebook", "deletePage", 2}, // 2613 + {wxAuiNotebook_DeletePage, "wxAuiNotebook", "deletePage", 2}, // 2618 #else - {NULL, "wxAuiNotebook", "deletePage", 0}, // 2613 + {NULL, "wxAuiNotebook", "deletePage", 0}, // 2618 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetArtProvider, "wxAuiNotebook", "getArtProvider", 1}, // 2614 + {wxAuiNotebook_GetArtProvider, "wxAuiNotebook", "getArtProvider", 1}, // 2619 #else - {NULL, "wxAuiNotebook", "getArtProvider", 0}, // 2614 + {NULL, "wxAuiNotebook", "getArtProvider", 0}, // 2619 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetPage, "wxAuiNotebook", "getPage", 2}, // 2615 + {wxAuiNotebook_GetPage, "wxAuiNotebook", "getPage", 2}, // 2620 #else - {NULL, "wxAuiNotebook", "getPage", 0}, // 2615 + {NULL, "wxAuiNotebook", "getPage", 0}, // 2620 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetPageBitmap, "wxAuiNotebook", "getPageBitmap", 2}, // 2616 + {wxAuiNotebook_GetPageBitmap, "wxAuiNotebook", "getPageBitmap", 2}, // 2621 #else - {NULL, "wxAuiNotebook", "getPageBitmap", 0}, // 2616 + {NULL, "wxAuiNotebook", "getPageBitmap", 0}, // 2621 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetPageCount, "wxAuiNotebook", "getPageCount", 1}, // 2617 + {wxAuiNotebook_GetPageCount, "wxAuiNotebook", "getPageCount", 1}, // 2622 #else - {NULL, "wxAuiNotebook", "getPageCount", 0}, // 2617 + {NULL, "wxAuiNotebook", "getPageCount", 0}, // 2622 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetPageIndex, "wxAuiNotebook", "getPageIndex", 2}, // 2618 + {wxAuiNotebook_GetPageIndex, "wxAuiNotebook", "getPageIndex", 2}, // 2623 #else - {NULL, "wxAuiNotebook", "getPageIndex", 0}, // 2618 + {NULL, "wxAuiNotebook", "getPageIndex", 0}, // 2623 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetPageText, "wxAuiNotebook", "getPageText", 2}, // 2619 + {wxAuiNotebook_GetPageText, "wxAuiNotebook", "getPageText", 2}, // 2624 #else - {NULL, "wxAuiNotebook", "getPageText", 0}, // 2619 + {NULL, "wxAuiNotebook", "getPageText", 0}, // 2624 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_GetSelection, "wxAuiNotebook", "getSelection", 1}, // 2620 + {wxAuiNotebook_GetSelection, "wxAuiNotebook", "getSelection", 1}, // 2625 #else - {NULL, "wxAuiNotebook", "getSelection", 0}, // 2620 + {NULL, "wxAuiNotebook", "getSelection", 0}, // 2625 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_InsertPage_4, "wxAuiNotebook", "insertPage", 5}, // 2621 + {wxAuiNotebook_InsertPage_4, "wxAuiNotebook", "insertPage", 5}, // 2626 #else - {NULL, "wxAuiNotebook", "insertPage", 0}, // 2621 + {NULL, "wxAuiNotebook", "insertPage", 0}, // 2626 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_InsertPage_5, "wxAuiNotebook", "insertPage", 6}, // 2622 + {wxAuiNotebook_InsertPage_5, "wxAuiNotebook", "insertPage", 6}, // 2627 #else - {NULL, "wxAuiNotebook", "insertPage", 0}, // 2622 + {NULL, "wxAuiNotebook", "insertPage", 0}, // 2627 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_RemovePage, "wxAuiNotebook", "removePage", 2}, // 2623 + {wxAuiNotebook_RemovePage, "wxAuiNotebook", "removePage", 2}, // 2628 #else - {NULL, "wxAuiNotebook", "removePage", 0}, // 2623 + {NULL, "wxAuiNotebook", "removePage", 0}, // 2628 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetArtProvider, "wxAuiNotebook", "setArtProvider", 2}, // 2624 + {wxAuiNotebook_SetArtProvider, "wxAuiNotebook", "setArtProvider", 2}, // 2629 #else - {NULL, "wxAuiNotebook", "setArtProvider", 0}, // 2624 + {NULL, "wxAuiNotebook", "setArtProvider", 0}, // 2629 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetFont, "wxAuiNotebook", "setFont", 2}, // 2625 + {wxAuiNotebook_SetFont, "wxAuiNotebook", "setFont", 2}, // 2630 #else - {NULL, "wxAuiNotebook", "setFont", 0}, // 2625 + {NULL, "wxAuiNotebook", "setFont", 0}, // 2630 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetPageBitmap, "wxAuiNotebook", "setPageBitmap", 3}, // 2626 + {wxAuiNotebook_SetPageBitmap, "wxAuiNotebook", "setPageBitmap", 3}, // 2631 #else - {NULL, "wxAuiNotebook", "setPageBitmap", 0}, // 2626 + {NULL, "wxAuiNotebook", "setPageBitmap", 0}, // 2631 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetPageText, "wxAuiNotebook", "setPageText", 3}, // 2627 + {wxAuiNotebook_SetPageText, "wxAuiNotebook", "setPageText", 3}, // 2632 #else - {NULL, "wxAuiNotebook", "setPageText", 0}, // 2627 + {NULL, "wxAuiNotebook", "setPageText", 0}, // 2632 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetSelection, "wxAuiNotebook", "setSelection", 2}, // 2628 + {wxAuiNotebook_SetSelection, "wxAuiNotebook", "setSelection", 2}, // 2633 #else - {NULL, "wxAuiNotebook", "setSelection", 0}, // 2628 + {NULL, "wxAuiNotebook", "setSelection", 0}, // 2633 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetTabCtrlHeight, "wxAuiNotebook", "setTabCtrlHeight", 2}, // 2629 + {wxAuiNotebook_SetTabCtrlHeight, "wxAuiNotebook", "setTabCtrlHeight", 2}, // 2634 #else - {NULL, "wxAuiNotebook", "setTabCtrlHeight", 0}, // 2629 + {NULL, "wxAuiNotebook", "setTabCtrlHeight", 0}, // 2634 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiNotebook_SetUniformBitmapSize, "wxAuiNotebook", "setUniformBitmapSize", 2}, // 2630 + {wxAuiNotebook_SetUniformBitmapSize, "wxAuiNotebook", "setUniformBitmapSize", 2}, // 2635 #else - {NULL, "wxAuiNotebook", "setUniformBitmapSize", 0}, // 2630 + {NULL, "wxAuiNotebook", "setUniformBitmapSize", 0}, // 2635 #endif // wxUSE_AUI #if wxUSE_AUI - {NULL, "wxAuiNotebook", "'Destroy'", 1}, // 2631 obj destructor wxAuiNotebook_destroy + {NULL, "wxAuiNotebook", "'Destroy'", 1}, // 2636 obj destructor wxAuiNotebook_destroy #else - {NULL, "wxAuiNotebook", "'Destroy'", 0}, // 2631 + {NULL, "wxAuiNotebook", "'Destroy'", 0}, // 2636 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetFlags, "wxAuiTabArt", "setFlags", 2}, // 2632 + {wxAuiTabArt_SetFlags, "wxAuiTabArt", "setFlags", 2}, // 2637 #else - {NULL, "wxAuiTabArt", "setFlags", 0}, // 2632 + {NULL, "wxAuiTabArt", "setFlags", 0}, // 2637 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetMeasuringFont, "wxAuiTabArt", "setMeasuringFont", 2}, // 2633 + {wxAuiTabArt_SetMeasuringFont, "wxAuiTabArt", "setMeasuringFont", 2}, // 2638 #else - {NULL, "wxAuiTabArt", "setMeasuringFont", 0}, // 2633 + {NULL, "wxAuiTabArt", "setMeasuringFont", 0}, // 2638 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetNormalFont, "wxAuiTabArt", "setNormalFont", 2}, // 2634 + {wxAuiTabArt_SetNormalFont, "wxAuiTabArt", "setNormalFont", 2}, // 2639 #else - {NULL, "wxAuiTabArt", "setNormalFont", 0}, // 2634 + {NULL, "wxAuiTabArt", "setNormalFont", 0}, // 2639 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetSelectedFont, "wxAuiTabArt", "setSelectedFont", 2}, // 2635 + {wxAuiTabArt_SetSelectedFont, "wxAuiTabArt", "setSelectedFont", 2}, // 2640 #else - {NULL, "wxAuiTabArt", "setSelectedFont", 0}, // 2635 + {NULL, "wxAuiTabArt", "setSelectedFont", 0}, // 2640 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetColour, "wxAuiTabArt", "setColour", 2}, // 2636 + {wxAuiTabArt_SetColour, "wxAuiTabArt", "setColour", 2}, // 2641 #else - {NULL, "wxAuiTabArt", "setColour", 0}, // 2636 + {NULL, "wxAuiTabArt", "setColour", 0}, // 2641 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiTabArt_SetActiveColour, "wxAuiTabArt", "setActiveColour", 2}, // 2637 + {wxAuiTabArt_SetActiveColour, "wxAuiTabArt", "setActiveColour", 2}, // 2642 #else - {NULL, "wxAuiTabArt", "setActiveColour", 0}, // 2637 + {NULL, "wxAuiTabArt", "setActiveColour", 0}, // 2642 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_GetColour, "wxAuiDockArt", "getColour", 2}, // 2638 + {wxAuiDockArt_GetColour, "wxAuiDockArt", "getColour", 2}, // 2643 #else - {NULL, "wxAuiDockArt", "getColour", 0}, // 2638 + {NULL, "wxAuiDockArt", "getColour", 0}, // 2643 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_GetFont, "wxAuiDockArt", "getFont", 2}, // 2639 + {wxAuiDockArt_GetFont, "wxAuiDockArt", "getFont", 2}, // 2644 #else - {NULL, "wxAuiDockArt", "getFont", 0}, // 2639 + {NULL, "wxAuiDockArt", "getFont", 0}, // 2644 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_GetMetric, "wxAuiDockArt", "getMetric", 2}, // 2640 + {wxAuiDockArt_GetMetric, "wxAuiDockArt", "getMetric", 2}, // 2645 #else - {NULL, "wxAuiDockArt", "getMetric", 0}, // 2640 + {NULL, "wxAuiDockArt", "getMetric", 0}, // 2645 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_SetColour, "wxAuiDockArt", "setColour", 3}, // 2641 + {wxAuiDockArt_SetColour, "wxAuiDockArt", "setColour", 3}, // 2646 #else - {NULL, "wxAuiDockArt", "setColour", 0}, // 2641 + {NULL, "wxAuiDockArt", "setColour", 0}, // 2646 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_SetFont, "wxAuiDockArt", "setFont", 3}, // 2642 + {wxAuiDockArt_SetFont, "wxAuiDockArt", "setFont", 3}, // 2647 #else - {NULL, "wxAuiDockArt", "setFont", 0}, // 2642 + {NULL, "wxAuiDockArt", "setFont", 0}, // 2647 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiDockArt_SetMetric, "wxAuiDockArt", "setMetric", 3}, // 2643 + {wxAuiDockArt_SetMetric, "wxAuiDockArt", "setMetric", 3}, // 2648 #else - {NULL, "wxAuiDockArt", "setMetric", 0}, // 2643 + {NULL, "wxAuiDockArt", "setMetric", 0}, // 2648 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiSimpleTabArt_new, "wxAuiSimpleTabArt", "new", 0}, // 2644 + {wxAuiSimpleTabArt_new, "wxAuiSimpleTabArt", "new", 0}, // 2649 #else - {NULL, "wxAuiSimpleTabArt", "new", 0}, // 2644 + {NULL, "wxAuiSimpleTabArt", "new", 0}, // 2649 #endif // wxUSE_AUI #if wxUSE_AUI - {wxAuiSimpleTabArt_destroy, "wxAuiSimpleTabArt", "'Destroy'", 1}, // 2645 + {wxAuiSimpleTabArt_destroy, "wxAuiSimpleTabArt", "'Destroy'", 1}, // 2650 #else - {NULL, "wxAuiSimpleTabArt", "'Destroy'", 0}, // 2645 + {NULL, "wxAuiSimpleTabArt", "'Destroy'", 0}, // 2650 #endif // wxUSE_AUI - {wxMDIParentFrame_new_0, "wxMDIParentFrame", "new", 0}, // 2646 - {wxMDIParentFrame_new_4, "wxMDIParentFrame", "new", 4}, // 2647 - {NULL, "wxMDIParentFrame", "destroy", 1}, // 2648 obj destructor wxMDIParentFrame_destruct - {wxMDIParentFrame_ActivateNext, "wxMDIParentFrame", "activateNext", 1}, // 2649 - {wxMDIParentFrame_ActivatePrevious, "wxMDIParentFrame", "activatePrevious", 1}, // 2650 - {wxMDIParentFrame_ArrangeIcons, "wxMDIParentFrame", "arrangeIcons", 1}, // 2651 - {wxMDIParentFrame_Cascade, "wxMDIParentFrame", "cascade", 1}, // 2652 - {wxMDIParentFrame_Create, "wxMDIParentFrame", "create", 5}, // 2653 - {wxMDIParentFrame_GetActiveChild, "wxMDIParentFrame", "getActiveChild", 1}, // 2654 - {wxMDIParentFrame_GetClientWindow, "wxMDIParentFrame", "getClientWindow", 1}, // 2655 - {wxMDIParentFrame_Tile, "wxMDIParentFrame", "tile", 2}, // 2656 - {wxMDIChildFrame_new_0, "wxMDIChildFrame", "new", 0}, // 2657 - {wxMDIChildFrame_new_4, "wxMDIChildFrame", "new", 4}, // 2658 - {NULL, "wxMDIChildFrame", "destroy", 1}, // 2659 obj destructor wxMDIChildFrame_destruct - {wxMDIChildFrame_Activate, "wxMDIChildFrame", "activate", 1}, // 2660 - {wxMDIChildFrame_Create, "wxMDIChildFrame", "create", 5}, // 2661 - {wxMDIChildFrame_Maximize, "wxMDIChildFrame", "maximize", 2}, // 2662 - {wxMDIChildFrame_Restore, "wxMDIChildFrame", "restore", 1}, // 2663 - {wxMDIClientWindow_new, "wxMDIClientWindow", "new", 0}, // 2664 - {wxMDIClientWindow_CreateClient, "wxMDIClientWindow", "createClient", 3}, // 2665 - {NULL, "wxMDIClientWindow", "'Destroy'", 1}, // 2666 obj destructor wxMDIClientWindow_destroy - {wxLayoutAlgorithm_new, "wxLayoutAlgorithm", "new", 0}, // 2667 - {NULL, "wxLayoutAlgorithm", "destroy", 1}, // 2668 obj destructor wxLayoutAlgorithm_destruct - {wxLayoutAlgorithm_LayoutFrame, "wxLayoutAlgorithm", "layoutFrame", 3}, // 2669 - {wxLayoutAlgorithm_LayoutMDIFrame, "wxLayoutAlgorithm", "layoutMDIFrame", 3}, // 2670 - {wxLayoutAlgorithm_LayoutWindow, "wxLayoutAlgorithm", "layoutWindow", 3}, // 2671 - {wxEvent_GetId, "wxEvent", "getId", 1}, // 2672 - {wxEvent_GetSkipped, "wxEvent", "getSkipped", 1}, // 2673 - {wxEvent_GetTimestamp, "wxEvent", "getTimestamp", 1}, // 2674 - {wxEvent_IsCommandEvent, "wxEvent", "isCommandEvent", 1}, // 2675 - {wxEvent_ResumePropagation, "wxEvent", "resumePropagation", 2}, // 2676 - {wxEvent_ShouldPropagate, "wxEvent", "shouldPropagate", 1}, // 2677 - {wxEvent_Skip, "wxEvent", "skip", 2}, // 2678 - {wxEvent_StopPropagation, "wxEvent", "stopPropagation", 1}, // 2679 - {wxCommandEvent_getClientData, "wxCommandEvent", "getClientData", 1}, // 2680 - {wxCommandEvent_GetExtraLong, "wxCommandEvent", "getExtraLong", 1}, // 2681 - {wxCommandEvent_GetInt, "wxCommandEvent", "getInt", 1}, // 2682 - {wxCommandEvent_GetSelection, "wxCommandEvent", "getSelection", 1}, // 2683 - {wxCommandEvent_GetString, "wxCommandEvent", "getString", 1}, // 2684 - {wxCommandEvent_IsChecked, "wxCommandEvent", "isChecked", 1}, // 2685 - {wxCommandEvent_IsSelection, "wxCommandEvent", "isSelection", 1}, // 2686 - {wxCommandEvent_SetInt, "wxCommandEvent", "setInt", 2}, // 2687 - {wxCommandEvent_SetString, "wxCommandEvent", "setString", 2}, // 2688 - {wxScrollEvent_GetOrientation, "wxScrollEvent", "getOrientation", 1}, // 2689 - {wxScrollEvent_GetPosition, "wxScrollEvent", "getPosition", 1}, // 2690 - {wxScrollWinEvent_GetOrientation, "wxScrollWinEvent", "getOrientation", 1}, // 2691 - {wxScrollWinEvent_GetPosition, "wxScrollWinEvent", "getPosition", 1}, // 2692 - {wxMouseEvent_AltDown, "wxMouseEvent", "altDown", 1}, // 2693 - {wxMouseEvent_Button, "wxMouseEvent", "button", 2}, // 2694 - {wxMouseEvent_ButtonDClick, "wxMouseEvent", "buttonDClick", 2}, // 2695 - {wxMouseEvent_ButtonDown, "wxMouseEvent", "buttonDown", 2}, // 2696 - {wxMouseEvent_ButtonUp, "wxMouseEvent", "buttonUp", 2}, // 2697 - {wxMouseEvent_CmdDown, "wxMouseEvent", "cmdDown", 1}, // 2698 - {wxMouseEvent_ControlDown, "wxMouseEvent", "controlDown", 1}, // 2699 - {wxMouseEvent_Dragging, "wxMouseEvent", "dragging", 1}, // 2700 - {wxMouseEvent_Entering, "wxMouseEvent", "entering", 1}, // 2701 - {wxMouseEvent_GetButton, "wxMouseEvent", "getButton", 1}, // 2702 - {wxMouseEvent_GetPosition, "wxMouseEvent", "getPosition", 1}, // 2703 - {NULL, "", "", 0}, // 2704 - {wxMouseEvent_GetLogicalPosition, "wxMouseEvent", "getLogicalPosition", 2}, // 2705 - {wxMouseEvent_GetLinesPerAction, "wxMouseEvent", "getLinesPerAction", 1}, // 2706 - {wxMouseEvent_GetWheelRotation, "wxMouseEvent", "getWheelRotation", 1}, // 2707 - {wxMouseEvent_GetWheelDelta, "wxMouseEvent", "getWheelDelta", 1}, // 2708 - {wxMouseEvent_GetX, "wxMouseEvent", "getX", 1}, // 2709 - {wxMouseEvent_GetY, "wxMouseEvent", "getY", 1}, // 2710 - {wxMouseEvent_IsButton, "wxMouseEvent", "isButton", 1}, // 2711 - {wxMouseEvent_IsPageScroll, "wxMouseEvent", "isPageScroll", 1}, // 2712 - {wxMouseEvent_Leaving, "wxMouseEvent", "leaving", 1}, // 2713 - {wxMouseEvent_LeftDClick, "wxMouseEvent", "leftDClick", 1}, // 2714 - {wxMouseEvent_LeftDown, "wxMouseEvent", "leftDown", 1}, // 2715 - {wxMouseEvent_LeftIsDown, "wxMouseEvent", "leftIsDown", 1}, // 2716 - {wxMouseEvent_LeftUp, "wxMouseEvent", "leftUp", 1}, // 2717 - {wxMouseEvent_MetaDown, "wxMouseEvent", "metaDown", 1}, // 2718 - {wxMouseEvent_MiddleDClick, "wxMouseEvent", "middleDClick", 1}, // 2719 - {wxMouseEvent_MiddleDown, "wxMouseEvent", "middleDown", 1}, // 2720 - {wxMouseEvent_MiddleIsDown, "wxMouseEvent", "middleIsDown", 1}, // 2721 - {wxMouseEvent_MiddleUp, "wxMouseEvent", "middleUp", 1}, // 2722 - {wxMouseEvent_Moving, "wxMouseEvent", "moving", 1}, // 2723 - {wxMouseEvent_RightDClick, "wxMouseEvent", "rightDClick", 1}, // 2724 - {wxMouseEvent_RightDown, "wxMouseEvent", "rightDown", 1}, // 2725 - {wxMouseEvent_RightIsDown, "wxMouseEvent", "rightIsDown", 1}, // 2726 - {wxMouseEvent_RightUp, "wxMouseEvent", "rightUp", 1}, // 2727 - {wxMouseEvent_ShiftDown, "wxMouseEvent", "shiftDown", 1}, // 2728 - {wxMouseEvent_GetWheelAxis, "wxMouseEvent", "getWheelAxis", 1}, // 2729 - {wxSetCursorEvent_GetCursor, "wxSetCursorEvent", "getCursor", 1}, // 2730 - {wxSetCursorEvent_GetX, "wxSetCursorEvent", "getX", 1}, // 2731 - {wxSetCursorEvent_GetY, "wxSetCursorEvent", "getY", 1}, // 2732 - {wxSetCursorEvent_HasCursor, "wxSetCursorEvent", "hasCursor", 1}, // 2733 - {wxSetCursorEvent_SetCursor, "wxSetCursorEvent", "setCursor", 2}, // 2734 - {wxKeyEvent_AltDown, "wxKeyEvent", "altDown", 1}, // 2735 - {wxKeyEvent_CmdDown, "wxKeyEvent", "cmdDown", 1}, // 2736 - {wxKeyEvent_ControlDown, "wxKeyEvent", "controlDown", 1}, // 2737 - {wxKeyEvent_GetKeyCode, "wxKeyEvent", "getKeyCode", 1}, // 2738 - {wxKeyEvent_GetModifiers, "wxKeyEvent", "getModifiers", 1}, // 2739 - {wxKeyEvent_GetPosition, "wxKeyEvent", "getPosition", 1}, // 2740 - {NULL, "", "", 0}, // 2741 - {wxKeyEvent_GetRawKeyCode, "wxKeyEvent", "getRawKeyCode", 1}, // 2742 - {wxKeyEvent_GetRawKeyFlags, "wxKeyEvent", "getRawKeyFlags", 1}, // 2743 - {wxKeyEvent_GetUnicodeKey, "wxKeyEvent", "getUnicodeKey", 1}, // 2744 - {wxKeyEvent_GetX, "wxKeyEvent", "getX", 1}, // 2745 - {wxKeyEvent_GetY, "wxKeyEvent", "getY", 1}, // 2746 - {wxKeyEvent_HasModifiers, "wxKeyEvent", "hasModifiers", 1}, // 2747 - {wxKeyEvent_MetaDown, "wxKeyEvent", "metaDown", 1}, // 2748 - {wxKeyEvent_ShiftDown, "wxKeyEvent", "shiftDown", 1}, // 2749 - {wxSizeEvent_GetSize, "wxSizeEvent", "getSize", 1}, // 2750 - {wxSizeEvent_GetRect, "wxSizeEvent", "getRect", 1}, // 2751 - {wxMoveEvent_GetPosition, "wxMoveEvent", "getPosition", 1}, // 2752 - {wxMoveEvent_GetRect, "wxMoveEvent", "getRect", 1}, // 2753 - {wxEraseEvent_GetDC, "wxEraseEvent", "getDC", 1}, // 2754 - {wxFocusEvent_GetWindow, "wxFocusEvent", "getWindow", 1}, // 2755 - {wxChildFocusEvent_GetWindow, "wxChildFocusEvent", "getWindow", 1}, // 2756 - {wxMenuEvent_GetMenu, "wxMenuEvent", "getMenu", 1}, // 2757 - {wxMenuEvent_GetMenuId, "wxMenuEvent", "getMenuId", 1}, // 2758 - {wxMenuEvent_IsPopup, "wxMenuEvent", "isPopup", 1}, // 2759 - {wxCloseEvent_CanVeto, "wxCloseEvent", "canVeto", 1}, // 2760 - {wxCloseEvent_GetLoggingOff, "wxCloseEvent", "getLoggingOff", 1}, // 2761 - {wxCloseEvent_SetCanVeto, "wxCloseEvent", "setCanVeto", 2}, // 2762 - {wxCloseEvent_SetLoggingOff, "wxCloseEvent", "setLoggingOff", 2}, // 2763 - {wxCloseEvent_Veto, "wxCloseEvent", "veto", 2}, // 2764 - {wxShowEvent_SetShow, "wxShowEvent", "setShow", 2}, // 2765 - {wxShowEvent_IsShown, "wxShowEvent", "isShown", 1}, // 2766 - {wxIconizeEvent_IsIconized, "wxIconizeEvent", "isIconized", 1}, // 2767 - {wxJoystickEvent_ButtonDown, "wxJoystickEvent", "buttonDown", 2}, // 2768 - {wxJoystickEvent_ButtonIsDown, "wxJoystickEvent", "buttonIsDown", 2}, // 2769 - {wxJoystickEvent_ButtonUp, "wxJoystickEvent", "buttonUp", 2}, // 2770 - {wxJoystickEvent_GetButtonChange, "wxJoystickEvent", "getButtonChange", 1}, // 2771 - {wxJoystickEvent_GetButtonState, "wxJoystickEvent", "getButtonState", 1}, // 2772 - {wxJoystickEvent_GetJoystick, "wxJoystickEvent", "getJoystick", 1}, // 2773 - {wxJoystickEvent_GetPosition, "wxJoystickEvent", "getPosition", 1}, // 2774 - {wxJoystickEvent_GetZPosition, "wxJoystickEvent", "getZPosition", 1}, // 2775 - {wxJoystickEvent_IsButton, "wxJoystickEvent", "isButton", 1}, // 2776 - {wxJoystickEvent_IsMove, "wxJoystickEvent", "isMove", 1}, // 2777 - {wxJoystickEvent_IsZMove, "wxJoystickEvent", "isZMove", 1}, // 2778 - {wxUpdateUIEvent_CanUpdate, "wxUpdateUIEvent", "canUpdate", 1}, // 2779 - {wxUpdateUIEvent_Check, "wxUpdateUIEvent", "check", 2}, // 2780 - {wxUpdateUIEvent_Enable, "wxUpdateUIEvent", "enable", 2}, // 2781 - {wxUpdateUIEvent_Show, "wxUpdateUIEvent", "show", 2}, // 2782 - {wxUpdateUIEvent_GetChecked, "wxUpdateUIEvent", "getChecked", 1}, // 2783 - {wxUpdateUIEvent_GetEnabled, "wxUpdateUIEvent", "getEnabled", 1}, // 2784 - {wxUpdateUIEvent_GetShown, "wxUpdateUIEvent", "getShown", 1}, // 2785 - {wxUpdateUIEvent_GetSetChecked, "wxUpdateUIEvent", "getSetChecked", 1}, // 2786 - {wxUpdateUIEvent_GetSetEnabled, "wxUpdateUIEvent", "getSetEnabled", 1}, // 2787 - {wxUpdateUIEvent_GetSetShown, "wxUpdateUIEvent", "getSetShown", 1}, // 2788 - {wxUpdateUIEvent_GetSetText, "wxUpdateUIEvent", "getSetText", 1}, // 2789 - {wxUpdateUIEvent_GetText, "wxUpdateUIEvent", "getText", 1}, // 2790 - {wxUpdateUIEvent_GetMode, "wxUpdateUIEvent", "getMode", 0}, // 2791 - {wxUpdateUIEvent_GetUpdateInterval, "wxUpdateUIEvent", "getUpdateInterval", 0}, // 2792 - {wxUpdateUIEvent_ResetUpdateTime, "wxUpdateUIEvent", "resetUpdateTime", 0}, // 2793 - {wxUpdateUIEvent_SetMode, "wxUpdateUIEvent", "setMode", 1}, // 2794 - {wxUpdateUIEvent_SetText, "wxUpdateUIEvent", "setText", 2}, // 2795 - {wxUpdateUIEvent_SetUpdateInterval, "wxUpdateUIEvent", "setUpdateInterval", 1}, // 2796 - {wxMouseCaptureChangedEvent_GetCapturedWindow, "wxMouseCaptureChangedEvent", "getCapturedWindow", 1}, // 2797 - {wxPaletteChangedEvent_SetChangedWindow, "wxPaletteChangedEvent", "setChangedWindow", 2}, // 2798 - {wxPaletteChangedEvent_GetChangedWindow, "wxPaletteChangedEvent", "getChangedWindow", 1}, // 2799 - {wxQueryNewPaletteEvent_SetPaletteRealized, "wxQueryNewPaletteEvent", "setPaletteRealized", 2}, // 2800 - {wxQueryNewPaletteEvent_GetPaletteRealized, "wxQueryNewPaletteEvent", "getPaletteRealized", 1}, // 2801 - {wxNavigationKeyEvent_GetDirection, "wxNavigationKeyEvent", "getDirection", 1}, // 2802 - {wxNavigationKeyEvent_SetDirection, "wxNavigationKeyEvent", "setDirection", 2}, // 2803 - {wxNavigationKeyEvent_IsWindowChange, "wxNavigationKeyEvent", "isWindowChange", 1}, // 2804 - {wxNavigationKeyEvent_SetWindowChange, "wxNavigationKeyEvent", "setWindowChange", 2}, // 2805 - {wxNavigationKeyEvent_IsFromTab, "wxNavigationKeyEvent", "isFromTab", 1}, // 2806 - {wxNavigationKeyEvent_SetFromTab, "wxNavigationKeyEvent", "setFromTab", 2}, // 2807 - {wxNavigationKeyEvent_GetCurrentFocus, "wxNavigationKeyEvent", "getCurrentFocus", 1}, // 2808 - {wxNavigationKeyEvent_SetCurrentFocus, "wxNavigationKeyEvent", "setCurrentFocus", 2}, // 2809 - {wxHelpEvent_GetOrigin, "wxHelpEvent", "getOrigin", 1}, // 2810 - {wxHelpEvent_GetPosition, "wxHelpEvent", "getPosition", 1}, // 2811 - {wxHelpEvent_SetOrigin, "wxHelpEvent", "setOrigin", 2}, // 2812 - {wxHelpEvent_SetPosition, "wxHelpEvent", "setPosition", 2}, // 2813 - {wxContextMenuEvent_GetPosition, "wxContextMenuEvent", "getPosition", 1}, // 2814 - {wxContextMenuEvent_SetPosition, "wxContextMenuEvent", "setPosition", 2}, // 2815 - {wxIdleEvent_GetMode, "wxIdleEvent", "getMode", 0}, // 2816 - {wxIdleEvent_RequestMore, "wxIdleEvent", "requestMore", 2}, // 2817 - {wxIdleEvent_MoreRequested, "wxIdleEvent", "moreRequested", 1}, // 2818 - {wxIdleEvent_SetMode, "wxIdleEvent", "setMode", 1}, // 2819 - {wxGridEvent_AltDown, "wxGridEvent", "altDown", 1}, // 2820 - {wxGridEvent_ControlDown, "wxGridEvent", "controlDown", 1}, // 2821 - {wxGridEvent_GetCol, "wxGridEvent", "getCol", 1}, // 2822 - {wxGridEvent_GetPosition, "wxGridEvent", "getPosition", 1}, // 2823 - {wxGridEvent_GetRow, "wxGridEvent", "getRow", 1}, // 2824 - {wxGridEvent_MetaDown, "wxGridEvent", "metaDown", 1}, // 2825 - {wxGridEvent_Selecting, "wxGridEvent", "selecting", 1}, // 2826 - {wxGridEvent_ShiftDown, "wxGridEvent", "shiftDown", 1}, // 2827 - {wxNotifyEvent_Allow, "wxNotifyEvent", "allow", 1}, // 2828 - {wxNotifyEvent_IsAllowed, "wxNotifyEvent", "isAllowed", 1}, // 2829 - {wxNotifyEvent_Veto, "wxNotifyEvent", "veto", 1}, // 2830 - {wxSashEvent_GetEdge, "wxSashEvent", "getEdge", 1}, // 2831 - {wxSashEvent_GetDragRect, "wxSashEvent", "getDragRect", 1}, // 2832 - {wxSashEvent_GetDragStatus, "wxSashEvent", "getDragStatus", 1}, // 2833 - {wxListEvent_GetCacheFrom, "wxListEvent", "getCacheFrom", 1}, // 2834 - {wxListEvent_GetCacheTo, "wxListEvent", "getCacheTo", 1}, // 2835 - {wxListEvent_GetKeyCode, "wxListEvent", "getKeyCode", 1}, // 2836 - {wxListEvent_GetIndex, "wxListEvent", "getIndex", 1}, // 2837 - {wxListEvent_GetColumn, "wxListEvent", "getColumn", 1}, // 2838 - {wxListEvent_GetPoint, "wxListEvent", "getPoint", 1}, // 2839 - {wxListEvent_GetLabel, "wxListEvent", "getLabel", 1}, // 2840 - {wxListEvent_GetText, "wxListEvent", "getText", 1}, // 2841 - {wxListEvent_GetImage, "wxListEvent", "getImage", 1}, // 2842 - {wxListEvent_GetData, "wxListEvent", "getData", 1}, // 2843 - {wxListEvent_GetMask, "wxListEvent", "getMask", 1}, // 2844 - {wxListEvent_GetItem, "wxListEvent", "getItem", 1}, // 2845 - {wxListEvent_IsEditCancelled, "wxListEvent", "isEditCancelled", 1}, // 2846 - {wxDateEvent_GetDate, "wxDateEvent", "getDate", 1}, // 2847 - {wxCalendarEvent_GetWeekDay, "wxCalendarEvent", "getWeekDay", 1}, // 2848 - {wxCalendarEvent_GetDate, "wxCalendarEvent", "getDate", 1}, // 2849 - {wxFileDirPickerEvent_GetPath, "wxFileDirPickerEvent", "getPath", 1}, // 2850 - {wxColourPickerEvent_GetColour, "wxColourPickerEvent", "getColour", 1}, // 2851 - {wxFontPickerEvent_GetFont, "wxFontPickerEvent", "getFont", 1}, // 2852 - {wxStyledTextEvent_GetPosition, "wxStyledTextEvent", "getPosition", 1}, // 2853 - {wxStyledTextEvent_GetKey, "wxStyledTextEvent", "getKey", 1}, // 2854 - {wxStyledTextEvent_GetModifiers, "wxStyledTextEvent", "getModifiers", 1}, // 2855 - {wxStyledTextEvent_GetModificationType, "wxStyledTextEvent", "getModificationType", 1}, // 2856 - {wxStyledTextEvent_GetText, "wxStyledTextEvent", "getText", 1}, // 2857 - {wxStyledTextEvent_GetLength, "wxStyledTextEvent", "getLength", 1}, // 2858 - {wxStyledTextEvent_GetLinesAdded, "wxStyledTextEvent", "getLinesAdded", 1}, // 2859 - {wxStyledTextEvent_GetLine, "wxStyledTextEvent", "getLine", 1}, // 2860 - {wxStyledTextEvent_GetFoldLevelNow, "wxStyledTextEvent", "getFoldLevelNow", 1}, // 2861 - {wxStyledTextEvent_GetFoldLevelPrev, "wxStyledTextEvent", "getFoldLevelPrev", 1}, // 2862 - {wxStyledTextEvent_GetMargin, "wxStyledTextEvent", "getMargin", 1}, // 2863 - {wxStyledTextEvent_GetMessage, "wxStyledTextEvent", "getMessage", 1}, // 2864 - {wxStyledTextEvent_GetWParam, "wxStyledTextEvent", "getWParam", 1}, // 2865 - {wxStyledTextEvent_GetLParam, "wxStyledTextEvent", "getLParam", 1}, // 2866 - {wxStyledTextEvent_GetListType, "wxStyledTextEvent", "getListType", 1}, // 2867 - {wxStyledTextEvent_GetX, "wxStyledTextEvent", "getX", 1}, // 2868 - {wxStyledTextEvent_GetY, "wxStyledTextEvent", "getY", 1}, // 2869 - {wxStyledTextEvent_GetDragText, "wxStyledTextEvent", "getDragText", 1}, // 2870 - {wxStyledTextEvent_GetDragAllowMove, "wxStyledTextEvent", "getDragAllowMove", 1}, // 2871 - {wxStyledTextEvent_GetDragResult, "wxStyledTextEvent", "getDragResult", 1}, // 2872 - {wxStyledTextEvent_GetShift, "wxStyledTextEvent", "getShift", 1}, // 2873 - {wxStyledTextEvent_GetControl, "wxStyledTextEvent", "getControl", 1}, // 2874 - {wxStyledTextEvent_GetAlt, "wxStyledTextEvent", "getAlt", 1}, // 2875 - {utils_wxGetKeyState, "utils", "getKeyState", 1}, // 2876 - {utils_wxGetMousePosition, "utils", "getMousePosition", 0}, // 2877 - {utils_wxGetMouseState, "utils", "getMouseState", 0}, // 2878 - {utils_wxSetDetectableAutoRepeat, "utils", "setDetectableAutoRepeat", 1}, // 2879 - {utils_wxBell, "utils", "bell", 0}, // 2880 - {utils_wxFindMenuItemId, "utils", "findMenuItemId", 3}, // 2881 - {utils_wxFindWindowAtPoint, "utils", "findWindowAtPoint", 1}, // 2882 - {utils_wxBeginBusyCursor, "utils", "beginBusyCursor", 1}, // 2883 - {utils_wxEndBusyCursor, "utils", "endBusyCursor", 0}, // 2884 - {utils_wxIsBusy, "utils", "isBusy", 0}, // 2885 - {utils_wxShutdown, "utils", "shutdown", 1}, // 2886 - {utils_wxShell, "utils", "shell", 1}, // 2887 - {utils_wxLaunchDefaultBrowser, "utils", "launchDefaultBrowser", 2}, // 2888 - {utils_wxGetEmailAddress, "utils", "getEmailAddress", 0}, // 2889 - {utils_wxGetUserId, "utils", "getUserId", 0}, // 2890 - {utils_wxGetHomeDir, "utils", "getHomeDir", 0}, // 2891 - {utils_wxNewId, "utils", "newId", 0}, // 2892 - {utils_wxRegisterId, "utils", "registerId", 1}, // 2893 - {utils_wxGetCurrentId, "utils", "getCurrentId", 0}, // 2894 - {utils_wxGetOsDescription, "utils", "getOsDescription", 0}, // 2895 - {utils_wxIsPlatformLittleEndian, "utils", "isPlatformLittleEndian", 0}, // 2896 - {utils_wxIsPlatform64Bit, "utils", "isPlatform64Bit", 0}, // 2897 - {gdicmn_wxDisplaySize, "gdicmn", "displaySize", 0}, // 2898 - {gdicmn_wxSetCursor, "gdicmn", "setCursor", 1}, // 2899 - {wxPrintout_new, "wxPrintout", "new", 3}, // 2900 - {NULL, "wxPrintout", "destroy", 1}, // 2901 obj destructor wxPrintout_destruct - {wxPrintout_GetDC, "wxPrintout", "getDC", 1}, // 2902 - {wxPrintout_GetPageSizeMM, "wxPrintout", "getPageSizeMM", 1}, // 2903 - {wxPrintout_GetPageSizePixels, "wxPrintout", "getPageSizePixels", 1}, // 2904 - {wxPrintout_GetPaperRectPixels, "wxPrintout", "getPaperRectPixels", 1}, // 2905 - {wxPrintout_GetPPIPrinter, "wxPrintout", "getPPIPrinter", 1}, // 2906 - {wxPrintout_GetPPIScreen, "wxPrintout", "getPPIScreen", 1}, // 2907 - {wxPrintout_GetTitle, "wxPrintout", "getTitle", 1}, // 2908 - {wxPrintout_IsPreview, "wxPrintout", "isPreview", 1}, // 2909 - {wxPrintout_FitThisSizeToPaper, "wxPrintout", "fitThisSizeToPaper", 2}, // 2910 - {wxPrintout_FitThisSizeToPage, "wxPrintout", "fitThisSizeToPage", 2}, // 2911 - {wxPrintout_FitThisSizeToPageMargins, "wxPrintout", "fitThisSizeToPageMargins", 3}, // 2912 - {wxPrintout_MapScreenSizeToPaper, "wxPrintout", "mapScreenSizeToPaper", 1}, // 2913 - {wxPrintout_MapScreenSizeToPage, "wxPrintout", "mapScreenSizeToPage", 1}, // 2914 - {wxPrintout_MapScreenSizeToPageMargins, "wxPrintout", "mapScreenSizeToPageMargins", 2}, // 2915 - {wxPrintout_MapScreenSizeToDevice, "wxPrintout", "mapScreenSizeToDevice", 1}, // 2916 - {wxPrintout_GetLogicalPaperRect, "wxPrintout", "getLogicalPaperRect", 1}, // 2917 - {wxPrintout_GetLogicalPageRect, "wxPrintout", "getLogicalPageRect", 1}, // 2918 - {wxPrintout_GetLogicalPageMarginsRect, "wxPrintout", "getLogicalPageMarginsRect", 2}, // 2919 - {wxPrintout_SetLogicalOrigin, "wxPrintout", "setLogicalOrigin", 3}, // 2920 - {wxPrintout_OffsetLogicalOrigin, "wxPrintout", "offsetLogicalOrigin", 3}, // 2921 - {wxStyledTextCtrl_new_2, "wxStyledTextCtrl", "new", 2}, // 2922 - {wxStyledTextCtrl_new_0, "wxStyledTextCtrl", "new", 0}, // 2923 - {NULL, "wxStyledTextCtrl", "destroy", 1}, // 2924 obj destructor wxStyledTextCtrl_destruct - {wxStyledTextCtrl_Create, "wxStyledTextCtrl", "create", 3}, // 2925 - {wxStyledTextCtrl_AddText, "wxStyledTextCtrl", "addText", 2}, // 2926 - {wxStyledTextCtrl_InsertText, "wxStyledTextCtrl", "insertText", 3}, // 2927 - {wxStyledTextCtrl_ClearAll, "wxStyledTextCtrl", "clearAll", 1}, // 2928 - {wxStyledTextCtrl_ClearDocumentStyle, "wxStyledTextCtrl", "clearDocumentStyle", 1}, // 2929 - {wxStyledTextCtrl_GetLength, "wxStyledTextCtrl", "getLength", 1}, // 2930 - {wxStyledTextCtrl_GetCharAt, "wxStyledTextCtrl", "getCharAt", 2}, // 2931 - {wxStyledTextCtrl_GetCurrentPos, "wxStyledTextCtrl", "getCurrentPos", 1}, // 2932 - {wxStyledTextCtrl_GetAnchor, "wxStyledTextCtrl", "getAnchor", 1}, // 2933 - {wxStyledTextCtrl_GetStyleAt, "wxStyledTextCtrl", "getStyleAt", 2}, // 2934 - {wxStyledTextCtrl_Redo, "wxStyledTextCtrl", "redo", 1}, // 2935 - {wxStyledTextCtrl_SetUndoCollection, "wxStyledTextCtrl", "setUndoCollection", 2}, // 2936 - {wxStyledTextCtrl_SelectAll, "wxStyledTextCtrl", "selectAll", 1}, // 2937 - {wxStyledTextCtrl_SetSavePoint, "wxStyledTextCtrl", "setSavePoint", 1}, // 2938 - {wxStyledTextCtrl_CanRedo, "wxStyledTextCtrl", "canRedo", 1}, // 2939 - {wxStyledTextCtrl_MarkerLineFromHandle, "wxStyledTextCtrl", "markerLineFromHandle", 2}, // 2940 - {wxStyledTextCtrl_MarkerDeleteHandle, "wxStyledTextCtrl", "markerDeleteHandle", 2}, // 2941 - {wxStyledTextCtrl_GetUndoCollection, "wxStyledTextCtrl", "getUndoCollection", 1}, // 2942 - {wxStyledTextCtrl_GetViewWhiteSpace, "wxStyledTextCtrl", "getViewWhiteSpace", 1}, // 2943 - {wxStyledTextCtrl_SetViewWhiteSpace, "wxStyledTextCtrl", "setViewWhiteSpace", 2}, // 2944 - {wxStyledTextCtrl_PositionFromPoint, "wxStyledTextCtrl", "positionFromPoint", 2}, // 2945 - {wxStyledTextCtrl_PositionFromPointClose, "wxStyledTextCtrl", "positionFromPointClose", 3}, // 2946 - {wxStyledTextCtrl_GotoLine, "wxStyledTextCtrl", "gotoLine", 2}, // 2947 - {wxStyledTextCtrl_GotoPos, "wxStyledTextCtrl", "gotoPos", 2}, // 2948 - {wxStyledTextCtrl_SetAnchor, "wxStyledTextCtrl", "setAnchor", 2}, // 2949 - {wxStyledTextCtrl_GetCurLine, "wxStyledTextCtrl", "getCurLine", 1}, // 2950 - {wxStyledTextCtrl_GetEndStyled, "wxStyledTextCtrl", "getEndStyled", 1}, // 2951 - {wxStyledTextCtrl_ConvertEOLs, "wxStyledTextCtrl", "convertEOLs", 2}, // 2952 - {wxStyledTextCtrl_GetEOLMode, "wxStyledTextCtrl", "getEOLMode", 1}, // 2953 - {wxStyledTextCtrl_SetEOLMode, "wxStyledTextCtrl", "setEOLMode", 2}, // 2954 - {wxStyledTextCtrl_StartStyling, "wxStyledTextCtrl", "startStyling", 2}, // 2955 - {wxStyledTextCtrl_SetStyling, "wxStyledTextCtrl", "setStyling", 3}, // 2956 - {wxStyledTextCtrl_GetBufferedDraw, "wxStyledTextCtrl", "getBufferedDraw", 1}, // 2957 - {wxStyledTextCtrl_SetBufferedDraw, "wxStyledTextCtrl", "setBufferedDraw", 2}, // 2958 - {wxStyledTextCtrl_SetTabWidth, "wxStyledTextCtrl", "setTabWidth", 2}, // 2959 - {wxStyledTextCtrl_GetTabWidth, "wxStyledTextCtrl", "getTabWidth", 1}, // 2960 - {wxStyledTextCtrl_SetCodePage, "wxStyledTextCtrl", "setCodePage", 2}, // 2961 - {wxStyledTextCtrl_MarkerDefine, "wxStyledTextCtrl", "markerDefine", 4}, // 2962 - {wxStyledTextCtrl_MarkerSetForeground, "wxStyledTextCtrl", "markerSetForeground", 3}, // 2963 - {wxStyledTextCtrl_MarkerSetBackground, "wxStyledTextCtrl", "markerSetBackground", 3}, // 2964 - {wxStyledTextCtrl_MarkerAdd, "wxStyledTextCtrl", "markerAdd", 3}, // 2965 - {wxStyledTextCtrl_MarkerDelete, "wxStyledTextCtrl", "markerDelete", 3}, // 2966 - {wxStyledTextCtrl_MarkerDeleteAll, "wxStyledTextCtrl", "markerDeleteAll", 2}, // 2967 - {wxStyledTextCtrl_MarkerGet, "wxStyledTextCtrl", "markerGet", 2}, // 2968 - {wxStyledTextCtrl_MarkerNext, "wxStyledTextCtrl", "markerNext", 3}, // 2969 - {wxStyledTextCtrl_MarkerPrevious, "wxStyledTextCtrl", "markerPrevious", 3}, // 2970 - {wxStyledTextCtrl_MarkerDefineBitmap, "wxStyledTextCtrl", "markerDefineBitmap", 3}, // 2971 - {wxStyledTextCtrl_MarkerAddSet, "wxStyledTextCtrl", "markerAddSet", 3}, // 2972 - {wxStyledTextCtrl_MarkerSetAlpha, "wxStyledTextCtrl", "markerSetAlpha", 3}, // 2973 - {wxStyledTextCtrl_SetMarginType, "wxStyledTextCtrl", "setMarginType", 3}, // 2974 - {wxStyledTextCtrl_GetMarginType, "wxStyledTextCtrl", "getMarginType", 2}, // 2975 - {wxStyledTextCtrl_SetMarginWidth, "wxStyledTextCtrl", "setMarginWidth", 3}, // 2976 - {wxStyledTextCtrl_GetMarginWidth, "wxStyledTextCtrl", "getMarginWidth", 2}, // 2977 - {wxStyledTextCtrl_SetMarginMask, "wxStyledTextCtrl", "setMarginMask", 3}, // 2978 - {wxStyledTextCtrl_GetMarginMask, "wxStyledTextCtrl", "getMarginMask", 2}, // 2979 - {wxStyledTextCtrl_SetMarginSensitive, "wxStyledTextCtrl", "setMarginSensitive", 3}, // 2980 - {wxStyledTextCtrl_GetMarginSensitive, "wxStyledTextCtrl", "getMarginSensitive", 2}, // 2981 - {wxStyledTextCtrl_StyleClearAll, "wxStyledTextCtrl", "styleClearAll", 1}, // 2982 - {wxStyledTextCtrl_StyleSetForeground, "wxStyledTextCtrl", "styleSetForeground", 3}, // 2983 - {wxStyledTextCtrl_StyleSetBackground, "wxStyledTextCtrl", "styleSetBackground", 3}, // 2984 - {wxStyledTextCtrl_StyleSetBold, "wxStyledTextCtrl", "styleSetBold", 3}, // 2985 - {wxStyledTextCtrl_StyleSetItalic, "wxStyledTextCtrl", "styleSetItalic", 3}, // 2986 - {wxStyledTextCtrl_StyleSetSize, "wxStyledTextCtrl", "styleSetSize", 3}, // 2987 - {wxStyledTextCtrl_StyleSetFaceName, "wxStyledTextCtrl", "styleSetFaceName", 3}, // 2988 - {wxStyledTextCtrl_StyleSetEOLFilled, "wxStyledTextCtrl", "styleSetEOLFilled", 3}, // 2989 - {wxStyledTextCtrl_StyleResetDefault, "wxStyledTextCtrl", "styleResetDefault", 1}, // 2990 - {wxStyledTextCtrl_StyleSetUnderline, "wxStyledTextCtrl", "styleSetUnderline", 3}, // 2991 - {wxStyledTextCtrl_StyleSetCase, "wxStyledTextCtrl", "styleSetCase", 3}, // 2992 - {wxStyledTextCtrl_StyleSetHotSpot, "wxStyledTextCtrl", "styleSetHotSpot", 3}, // 2993 - {wxStyledTextCtrl_SetSelForeground, "wxStyledTextCtrl", "setSelForeground", 3}, // 2994 - {wxStyledTextCtrl_SetSelBackground, "wxStyledTextCtrl", "setSelBackground", 3}, // 2995 - {wxStyledTextCtrl_GetSelAlpha, "wxStyledTextCtrl", "getSelAlpha", 1}, // 2996 - {wxStyledTextCtrl_SetSelAlpha, "wxStyledTextCtrl", "setSelAlpha", 2}, // 2997 - {wxStyledTextCtrl_SetCaretForeground, "wxStyledTextCtrl", "setCaretForeground", 2}, // 2998 - {wxStyledTextCtrl_CmdKeyAssign, "wxStyledTextCtrl", "cmdKeyAssign", 4}, // 2999 - {wxStyledTextCtrl_CmdKeyClear, "wxStyledTextCtrl", "cmdKeyClear", 3}, // 3000 - {wxStyledTextCtrl_CmdKeyClearAll, "wxStyledTextCtrl", "cmdKeyClearAll", 1}, // 3001 - {wxStyledTextCtrl_SetStyleBytes, "wxStyledTextCtrl", "setStyleBytes", 2}, // 3002 - {wxStyledTextCtrl_StyleSetVisible, "wxStyledTextCtrl", "styleSetVisible", 3}, // 3003 - {wxStyledTextCtrl_GetCaretPeriod, "wxStyledTextCtrl", "getCaretPeriod", 1}, // 3004 - {wxStyledTextCtrl_SetCaretPeriod, "wxStyledTextCtrl", "setCaretPeriod", 2}, // 3005 - {wxStyledTextCtrl_SetWordChars, "wxStyledTextCtrl", "setWordChars", 2}, // 3006 - {wxStyledTextCtrl_BeginUndoAction, "wxStyledTextCtrl", "beginUndoAction", 1}, // 3007 - {wxStyledTextCtrl_EndUndoAction, "wxStyledTextCtrl", "endUndoAction", 1}, // 3008 - {wxStyledTextCtrl_IndicatorSetStyle, "wxStyledTextCtrl", "indicatorSetStyle", 3}, // 3009 - {wxStyledTextCtrl_IndicatorGetStyle, "wxStyledTextCtrl", "indicatorGetStyle", 2}, // 3010 - {wxStyledTextCtrl_IndicatorSetForeground, "wxStyledTextCtrl", "indicatorSetForeground", 3}, // 3011 - {wxStyledTextCtrl_IndicatorGetForeground, "wxStyledTextCtrl", "indicatorGetForeground", 2}, // 3012 - {wxStyledTextCtrl_SetWhitespaceForeground, "wxStyledTextCtrl", "setWhitespaceForeground", 3}, // 3013 - {wxStyledTextCtrl_SetWhitespaceBackground, "wxStyledTextCtrl", "setWhitespaceBackground", 3}, // 3014 - {wxStyledTextCtrl_GetStyleBits, "wxStyledTextCtrl", "getStyleBits", 1}, // 3015 - {wxStyledTextCtrl_SetLineState, "wxStyledTextCtrl", "setLineState", 3}, // 3016 - {wxStyledTextCtrl_GetLineState, "wxStyledTextCtrl", "getLineState", 2}, // 3017 - {wxStyledTextCtrl_GetMaxLineState, "wxStyledTextCtrl", "getMaxLineState", 1}, // 3018 - {wxStyledTextCtrl_GetCaretLineVisible, "wxStyledTextCtrl", "getCaretLineVisible", 1}, // 3019 - {wxStyledTextCtrl_SetCaretLineVisible, "wxStyledTextCtrl", "setCaretLineVisible", 2}, // 3020 - {wxStyledTextCtrl_GetCaretLineBackground, "wxStyledTextCtrl", "getCaretLineBackground", 1}, // 3021 - {wxStyledTextCtrl_SetCaretLineBackground, "wxStyledTextCtrl", "setCaretLineBackground", 2}, // 3022 - {wxStyledTextCtrl_AutoCompShow, "wxStyledTextCtrl", "autoCompShow", 3}, // 3023 - {wxStyledTextCtrl_AutoCompCancel, "wxStyledTextCtrl", "autoCompCancel", 1}, // 3024 - {wxStyledTextCtrl_AutoCompActive, "wxStyledTextCtrl", "autoCompActive", 1}, // 3025 - {wxStyledTextCtrl_AutoCompPosStart, "wxStyledTextCtrl", "autoCompPosStart", 1}, // 3026 - {wxStyledTextCtrl_AutoCompComplete, "wxStyledTextCtrl", "autoCompComplete", 1}, // 3027 - {wxStyledTextCtrl_AutoCompStops, "wxStyledTextCtrl", "autoCompStops", 2}, // 3028 - {wxStyledTextCtrl_AutoCompSetSeparator, "wxStyledTextCtrl", "autoCompSetSeparator", 2}, // 3029 - {wxStyledTextCtrl_AutoCompGetSeparator, "wxStyledTextCtrl", "autoCompGetSeparator", 1}, // 3030 - {wxStyledTextCtrl_AutoCompSelect, "wxStyledTextCtrl", "autoCompSelect", 2}, // 3031 - {wxStyledTextCtrl_AutoCompSetCancelAtStart, "wxStyledTextCtrl", "autoCompSetCancelAtStart", 2}, // 3032 - {wxStyledTextCtrl_AutoCompGetCancelAtStart, "wxStyledTextCtrl", "autoCompGetCancelAtStart", 1}, // 3033 - {wxStyledTextCtrl_AutoCompSetFillUps, "wxStyledTextCtrl", "autoCompSetFillUps", 2}, // 3034 - {wxStyledTextCtrl_AutoCompSetChooseSingle, "wxStyledTextCtrl", "autoCompSetChooseSingle", 2}, // 3035 - {wxStyledTextCtrl_AutoCompGetChooseSingle, "wxStyledTextCtrl", "autoCompGetChooseSingle", 1}, // 3036 - {wxStyledTextCtrl_AutoCompSetIgnoreCase, "wxStyledTextCtrl", "autoCompSetIgnoreCase", 2}, // 3037 - {wxStyledTextCtrl_AutoCompGetIgnoreCase, "wxStyledTextCtrl", "autoCompGetIgnoreCase", 1}, // 3038 - {wxStyledTextCtrl_UserListShow, "wxStyledTextCtrl", "userListShow", 3}, // 3039 - {wxStyledTextCtrl_AutoCompSetAutoHide, "wxStyledTextCtrl", "autoCompSetAutoHide", 2}, // 3040 - {wxStyledTextCtrl_AutoCompGetAutoHide, "wxStyledTextCtrl", "autoCompGetAutoHide", 1}, // 3041 - {wxStyledTextCtrl_AutoCompSetDropRestOfWord, "wxStyledTextCtrl", "autoCompSetDropRestOfWord", 2}, // 3042 - {wxStyledTextCtrl_AutoCompGetDropRestOfWord, "wxStyledTextCtrl", "autoCompGetDropRestOfWord", 1}, // 3043 - {wxStyledTextCtrl_RegisterImage, "wxStyledTextCtrl", "registerImage", 3}, // 3044 - {wxStyledTextCtrl_ClearRegisteredImages, "wxStyledTextCtrl", "clearRegisteredImages", 1}, // 3045 - {wxStyledTextCtrl_AutoCompGetTypeSeparator, "wxStyledTextCtrl", "autoCompGetTypeSeparator", 1}, // 3046 - {wxStyledTextCtrl_AutoCompSetTypeSeparator, "wxStyledTextCtrl", "autoCompSetTypeSeparator", 2}, // 3047 - {wxStyledTextCtrl_AutoCompSetMaxWidth, "wxStyledTextCtrl", "autoCompSetMaxWidth", 2}, // 3048 - {wxStyledTextCtrl_AutoCompGetMaxWidth, "wxStyledTextCtrl", "autoCompGetMaxWidth", 1}, // 3049 - {wxStyledTextCtrl_AutoCompSetMaxHeight, "wxStyledTextCtrl", "autoCompSetMaxHeight", 2}, // 3050 - {wxStyledTextCtrl_AutoCompGetMaxHeight, "wxStyledTextCtrl", "autoCompGetMaxHeight", 1}, // 3051 - {wxStyledTextCtrl_SetIndent, "wxStyledTextCtrl", "setIndent", 2}, // 3052 - {wxStyledTextCtrl_GetIndent, "wxStyledTextCtrl", "getIndent", 1}, // 3053 - {wxStyledTextCtrl_SetUseTabs, "wxStyledTextCtrl", "setUseTabs", 2}, // 3054 - {wxStyledTextCtrl_GetUseTabs, "wxStyledTextCtrl", "getUseTabs", 1}, // 3055 - {wxStyledTextCtrl_SetLineIndentation, "wxStyledTextCtrl", "setLineIndentation", 3}, // 3056 - {wxStyledTextCtrl_GetLineIndentation, "wxStyledTextCtrl", "getLineIndentation", 2}, // 3057 - {wxStyledTextCtrl_GetLineIndentPosition, "wxStyledTextCtrl", "getLineIndentPosition", 2}, // 3058 - {wxStyledTextCtrl_GetColumn, "wxStyledTextCtrl", "getColumn", 2}, // 3059 - {wxStyledTextCtrl_SetUseHorizontalScrollBar, "wxStyledTextCtrl", "setUseHorizontalScrollBar", 2}, // 3060 - {wxStyledTextCtrl_GetUseHorizontalScrollBar, "wxStyledTextCtrl", "getUseHorizontalScrollBar", 1}, // 3061 - {wxStyledTextCtrl_SetIndentationGuides, "wxStyledTextCtrl", "setIndentationGuides", 2}, // 3062 - {wxStyledTextCtrl_GetIndentationGuides, "wxStyledTextCtrl", "getIndentationGuides", 1}, // 3063 - {wxStyledTextCtrl_SetHighlightGuide, "wxStyledTextCtrl", "setHighlightGuide", 2}, // 3064 - {wxStyledTextCtrl_GetHighlightGuide, "wxStyledTextCtrl", "getHighlightGuide", 1}, // 3065 - {wxStyledTextCtrl_GetLineEndPosition, "wxStyledTextCtrl", "getLineEndPosition", 2}, // 3066 - {wxStyledTextCtrl_GetCodePage, "wxStyledTextCtrl", "getCodePage", 1}, // 3067 - {wxStyledTextCtrl_GetCaretForeground, "wxStyledTextCtrl", "getCaretForeground", 1}, // 3068 - {wxStyledTextCtrl_GetReadOnly, "wxStyledTextCtrl", "getReadOnly", 1}, // 3069 - {wxStyledTextCtrl_SetCurrentPos, "wxStyledTextCtrl", "setCurrentPos", 2}, // 3070 - {wxStyledTextCtrl_SetSelectionStart, "wxStyledTextCtrl", "setSelectionStart", 2}, // 3071 - {wxStyledTextCtrl_GetSelectionStart, "wxStyledTextCtrl", "getSelectionStart", 1}, // 3072 - {wxStyledTextCtrl_SetSelectionEnd, "wxStyledTextCtrl", "setSelectionEnd", 2}, // 3073 - {wxStyledTextCtrl_GetSelectionEnd, "wxStyledTextCtrl", "getSelectionEnd", 1}, // 3074 - {wxStyledTextCtrl_SetPrintMagnification, "wxStyledTextCtrl", "setPrintMagnification", 2}, // 3075 - {wxStyledTextCtrl_GetPrintMagnification, "wxStyledTextCtrl", "getPrintMagnification", 1}, // 3076 - {wxStyledTextCtrl_SetPrintColourMode, "wxStyledTextCtrl", "setPrintColourMode", 2}, // 3077 - {wxStyledTextCtrl_GetPrintColourMode, "wxStyledTextCtrl", "getPrintColourMode", 1}, // 3078 - {wxStyledTextCtrl_FindText, "wxStyledTextCtrl", "findText", 5}, // 3079 - {wxStyledTextCtrl_FormatRange, "wxStyledTextCtrl", "formatRange", 8}, // 3080 - {wxStyledTextCtrl_GetFirstVisibleLine, "wxStyledTextCtrl", "getFirstVisibleLine", 1}, // 3081 - {wxStyledTextCtrl_GetLine, "wxStyledTextCtrl", "getLine", 2}, // 3082 - {wxStyledTextCtrl_GetLineCount, "wxStyledTextCtrl", "getLineCount", 1}, // 3083 - {wxStyledTextCtrl_SetMarginLeft, "wxStyledTextCtrl", "setMarginLeft", 2}, // 3084 - {wxStyledTextCtrl_GetMarginLeft, "wxStyledTextCtrl", "getMarginLeft", 1}, // 3085 - {wxStyledTextCtrl_SetMarginRight, "wxStyledTextCtrl", "setMarginRight", 2}, // 3086 - {wxStyledTextCtrl_GetMarginRight, "wxStyledTextCtrl", "getMarginRight", 1}, // 3087 - {wxStyledTextCtrl_GetModify, "wxStyledTextCtrl", "getModify", 1}, // 3088 - {wxStyledTextCtrl_SetSelection, "wxStyledTextCtrl", "setSelection", 3}, // 3089 - {wxStyledTextCtrl_GetSelectedText, "wxStyledTextCtrl", "getSelectedText", 1}, // 3090 - {wxStyledTextCtrl_GetTextRange, "wxStyledTextCtrl", "getTextRange", 3}, // 3091 - {wxStyledTextCtrl_HideSelection, "wxStyledTextCtrl", "hideSelection", 2}, // 3092 - {wxStyledTextCtrl_LineFromPosition, "wxStyledTextCtrl", "lineFromPosition", 2}, // 3093 - {wxStyledTextCtrl_PositionFromLine, "wxStyledTextCtrl", "positionFromLine", 2}, // 3094 - {wxStyledTextCtrl_LineScroll, "wxStyledTextCtrl", "lineScroll", 3}, // 3095 - {wxStyledTextCtrl_EnsureCaretVisible, "wxStyledTextCtrl", "ensureCaretVisible", 1}, // 3096 - {wxStyledTextCtrl_ReplaceSelection, "wxStyledTextCtrl", "replaceSelection", 2}, // 3097 - {wxStyledTextCtrl_SetReadOnly, "wxStyledTextCtrl", "setReadOnly", 2}, // 3098 - {wxStyledTextCtrl_CanPaste, "wxStyledTextCtrl", "canPaste", 1}, // 3099 - {wxStyledTextCtrl_CanUndo, "wxStyledTextCtrl", "canUndo", 1}, // 3100 - {wxStyledTextCtrl_EmptyUndoBuffer, "wxStyledTextCtrl", "emptyUndoBuffer", 1}, // 3101 - {wxStyledTextCtrl_Undo, "wxStyledTextCtrl", "undo", 1}, // 3102 - {wxStyledTextCtrl_Cut, "wxStyledTextCtrl", "cut", 1}, // 3103 - {wxStyledTextCtrl_Copy, "wxStyledTextCtrl", "copy", 1}, // 3104 - {wxStyledTextCtrl_Paste, "wxStyledTextCtrl", "paste", 1}, // 3105 - {wxStyledTextCtrl_Clear, "wxStyledTextCtrl", "clear", 1}, // 3106 - {wxStyledTextCtrl_SetText, "wxStyledTextCtrl", "setText", 2}, // 3107 - {wxStyledTextCtrl_GetText, "wxStyledTextCtrl", "getText", 1}, // 3108 - {wxStyledTextCtrl_GetTextLength, "wxStyledTextCtrl", "getTextLength", 1}, // 3109 - {wxStyledTextCtrl_GetOvertype, "wxStyledTextCtrl", "getOvertype", 1}, // 3110 - {wxStyledTextCtrl_SetCaretWidth, "wxStyledTextCtrl", "setCaretWidth", 2}, // 3111 - {wxStyledTextCtrl_GetCaretWidth, "wxStyledTextCtrl", "getCaretWidth", 1}, // 3112 - {wxStyledTextCtrl_SetTargetStart, "wxStyledTextCtrl", "setTargetStart", 2}, // 3113 - {wxStyledTextCtrl_GetTargetStart, "wxStyledTextCtrl", "getTargetStart", 1}, // 3114 - {wxStyledTextCtrl_SetTargetEnd, "wxStyledTextCtrl", "setTargetEnd", 2}, // 3115 - {wxStyledTextCtrl_GetTargetEnd, "wxStyledTextCtrl", "getTargetEnd", 1}, // 3116 - {wxStyledTextCtrl_ReplaceTarget, "wxStyledTextCtrl", "replaceTarget", 2}, // 3117 - {wxStyledTextCtrl_SearchInTarget, "wxStyledTextCtrl", "searchInTarget", 2}, // 3118 - {wxStyledTextCtrl_SetSearchFlags, "wxStyledTextCtrl", "setSearchFlags", 2}, // 3119 - {wxStyledTextCtrl_GetSearchFlags, "wxStyledTextCtrl", "getSearchFlags", 1}, // 3120 - {wxStyledTextCtrl_CallTipShow, "wxStyledTextCtrl", "callTipShow", 3}, // 3121 - {wxStyledTextCtrl_CallTipCancel, "wxStyledTextCtrl", "callTipCancel", 1}, // 3122 - {wxStyledTextCtrl_CallTipActive, "wxStyledTextCtrl", "callTipActive", 1}, // 3123 - {wxStyledTextCtrl_CallTipPosAtStart, "wxStyledTextCtrl", "callTipPosAtStart", 1}, // 3124 - {wxStyledTextCtrl_CallTipSetHighlight, "wxStyledTextCtrl", "callTipSetHighlight", 3}, // 3125 - {wxStyledTextCtrl_CallTipSetBackground, "wxStyledTextCtrl", "callTipSetBackground", 2}, // 3126 - {wxStyledTextCtrl_CallTipSetForeground, "wxStyledTextCtrl", "callTipSetForeground", 2}, // 3127 - {wxStyledTextCtrl_CallTipSetForegroundHighlight, "wxStyledTextCtrl", "callTipSetForegroundHighlight", 2}, // 3128 - {wxStyledTextCtrl_CallTipUseStyle, "wxStyledTextCtrl", "callTipUseStyle", 2}, // 3129 - {wxStyledTextCtrl_VisibleFromDocLine, "wxStyledTextCtrl", "visibleFromDocLine", 2}, // 3130 - {wxStyledTextCtrl_DocLineFromVisible, "wxStyledTextCtrl", "docLineFromVisible", 2}, // 3131 - {wxStyledTextCtrl_WrapCount, "wxStyledTextCtrl", "wrapCount", 2}, // 3132 - {wxStyledTextCtrl_SetFoldLevel, "wxStyledTextCtrl", "setFoldLevel", 3}, // 3133 - {wxStyledTextCtrl_GetFoldLevel, "wxStyledTextCtrl", "getFoldLevel", 2}, // 3134 - {wxStyledTextCtrl_GetLastChild, "wxStyledTextCtrl", "getLastChild", 3}, // 3135 - {wxStyledTextCtrl_GetFoldParent, "wxStyledTextCtrl", "getFoldParent", 2}, // 3136 - {wxStyledTextCtrl_ShowLines, "wxStyledTextCtrl", "showLines", 3}, // 3137 - {wxStyledTextCtrl_HideLines, "wxStyledTextCtrl", "hideLines", 3}, // 3138 - {wxStyledTextCtrl_GetLineVisible, "wxStyledTextCtrl", "getLineVisible", 2}, // 3139 - {wxStyledTextCtrl_SetFoldExpanded, "wxStyledTextCtrl", "setFoldExpanded", 3}, // 3140 - {wxStyledTextCtrl_GetFoldExpanded, "wxStyledTextCtrl", "getFoldExpanded", 2}, // 3141 - {wxStyledTextCtrl_ToggleFold, "wxStyledTextCtrl", "toggleFold", 2}, // 3142 - {wxStyledTextCtrl_EnsureVisible, "wxStyledTextCtrl", "ensureVisible", 2}, // 3143 - {wxStyledTextCtrl_SetFoldFlags, "wxStyledTextCtrl", "setFoldFlags", 2}, // 3144 - {wxStyledTextCtrl_EnsureVisibleEnforcePolicy, "wxStyledTextCtrl", "ensureVisibleEnforcePolicy", 2}, // 3145 - {wxStyledTextCtrl_SetTabIndents, "wxStyledTextCtrl", "setTabIndents", 2}, // 3146 - {wxStyledTextCtrl_GetTabIndents, "wxStyledTextCtrl", "getTabIndents", 1}, // 3147 - {wxStyledTextCtrl_SetBackSpaceUnIndents, "wxStyledTextCtrl", "setBackSpaceUnIndents", 2}, // 3148 - {wxStyledTextCtrl_GetBackSpaceUnIndents, "wxStyledTextCtrl", "getBackSpaceUnIndents", 1}, // 3149 - {wxStyledTextCtrl_SetMouseDwellTime, "wxStyledTextCtrl", "setMouseDwellTime", 2}, // 3150 - {wxStyledTextCtrl_GetMouseDwellTime, "wxStyledTextCtrl", "getMouseDwellTime", 1}, // 3151 - {wxStyledTextCtrl_WordStartPosition, "wxStyledTextCtrl", "wordStartPosition", 3}, // 3152 - {wxStyledTextCtrl_WordEndPosition, "wxStyledTextCtrl", "wordEndPosition", 3}, // 3153 - {wxStyledTextCtrl_SetWrapMode, "wxStyledTextCtrl", "setWrapMode", 2}, // 3154 - {wxStyledTextCtrl_GetWrapMode, "wxStyledTextCtrl", "getWrapMode", 1}, // 3155 - {wxStyledTextCtrl_SetWrapVisualFlags, "wxStyledTextCtrl", "setWrapVisualFlags", 2}, // 3156 - {wxStyledTextCtrl_GetWrapVisualFlags, "wxStyledTextCtrl", "getWrapVisualFlags", 1}, // 3157 - {wxStyledTextCtrl_SetWrapVisualFlagsLocation, "wxStyledTextCtrl", "setWrapVisualFlagsLocation", 2}, // 3158 - {wxStyledTextCtrl_GetWrapVisualFlagsLocation, "wxStyledTextCtrl", "getWrapVisualFlagsLocation", 1}, // 3159 - {wxStyledTextCtrl_SetWrapStartIndent, "wxStyledTextCtrl", "setWrapStartIndent", 2}, // 3160 - {wxStyledTextCtrl_GetWrapStartIndent, "wxStyledTextCtrl", "getWrapStartIndent", 1}, // 3161 - {wxStyledTextCtrl_SetLayoutCache, "wxStyledTextCtrl", "setLayoutCache", 2}, // 3162 - {wxStyledTextCtrl_GetLayoutCache, "wxStyledTextCtrl", "getLayoutCache", 1}, // 3163 - {wxStyledTextCtrl_SetScrollWidth, "wxStyledTextCtrl", "setScrollWidth", 2}, // 3164 - {wxStyledTextCtrl_GetScrollWidth, "wxStyledTextCtrl", "getScrollWidth", 1}, // 3165 - {wxStyledTextCtrl_TextWidth, "wxStyledTextCtrl", "textWidth", 3}, // 3166 - {wxStyledTextCtrl_GetEndAtLastLine, "wxStyledTextCtrl", "getEndAtLastLine", 1}, // 3167 - {wxStyledTextCtrl_TextHeight, "wxStyledTextCtrl", "textHeight", 2}, // 3168 - {wxStyledTextCtrl_SetUseVerticalScrollBar, "wxStyledTextCtrl", "setUseVerticalScrollBar", 2}, // 3169 - {wxStyledTextCtrl_GetUseVerticalScrollBar, "wxStyledTextCtrl", "getUseVerticalScrollBar", 1}, // 3170 - {wxStyledTextCtrl_AppendText, "wxStyledTextCtrl", "appendText", 2}, // 3171 - {wxStyledTextCtrl_GetTwoPhaseDraw, "wxStyledTextCtrl", "getTwoPhaseDraw", 1}, // 3172 - {wxStyledTextCtrl_SetTwoPhaseDraw, "wxStyledTextCtrl", "setTwoPhaseDraw", 2}, // 3173 - {wxStyledTextCtrl_TargetFromSelection, "wxStyledTextCtrl", "targetFromSelection", 1}, // 3174 - {wxStyledTextCtrl_LinesJoin, "wxStyledTextCtrl", "linesJoin", 1}, // 3175 - {wxStyledTextCtrl_LinesSplit, "wxStyledTextCtrl", "linesSplit", 2}, // 3176 - {wxStyledTextCtrl_SetFoldMarginColour, "wxStyledTextCtrl", "setFoldMarginColour", 3}, // 3177 - {wxStyledTextCtrl_SetFoldMarginHiColour, "wxStyledTextCtrl", "setFoldMarginHiColour", 3}, // 3178 - {wxStyledTextCtrl_LineDown, "wxStyledTextCtrl", "lineDown", 1}, // 3179 - {wxStyledTextCtrl_LineDownExtend, "wxStyledTextCtrl", "lineDownExtend", 1}, // 3180 - {wxStyledTextCtrl_LineUp, "wxStyledTextCtrl", "lineUp", 1}, // 3181 - {wxStyledTextCtrl_LineUpExtend, "wxStyledTextCtrl", "lineUpExtend", 1}, // 3182 - {wxStyledTextCtrl_CharLeft, "wxStyledTextCtrl", "charLeft", 1}, // 3183 - {wxStyledTextCtrl_CharLeftExtend, "wxStyledTextCtrl", "charLeftExtend", 1}, // 3184 - {wxStyledTextCtrl_CharRight, "wxStyledTextCtrl", "charRight", 1}, // 3185 - {wxStyledTextCtrl_CharRightExtend, "wxStyledTextCtrl", "charRightExtend", 1}, // 3186 - {wxStyledTextCtrl_WordLeft, "wxStyledTextCtrl", "wordLeft", 1}, // 3187 - {wxStyledTextCtrl_WordLeftExtend, "wxStyledTextCtrl", "wordLeftExtend", 1}, // 3188 - {wxStyledTextCtrl_WordRight, "wxStyledTextCtrl", "wordRight", 1}, // 3189 - {wxStyledTextCtrl_WordRightExtend, "wxStyledTextCtrl", "wordRightExtend", 1}, // 3190 - {wxStyledTextCtrl_Home, "wxStyledTextCtrl", "home", 1}, // 3191 - {wxStyledTextCtrl_HomeExtend, "wxStyledTextCtrl", "homeExtend", 1}, // 3192 - {wxStyledTextCtrl_LineEnd, "wxStyledTextCtrl", "lineEnd", 1}, // 3193 - {wxStyledTextCtrl_LineEndExtend, "wxStyledTextCtrl", "lineEndExtend", 1}, // 3194 - {wxStyledTextCtrl_DocumentStart, "wxStyledTextCtrl", "documentStart", 1}, // 3195 - {wxStyledTextCtrl_DocumentStartExtend, "wxStyledTextCtrl", "documentStartExtend", 1}, // 3196 - {wxStyledTextCtrl_DocumentEnd, "wxStyledTextCtrl", "documentEnd", 1}, // 3197 - {wxStyledTextCtrl_DocumentEndExtend, "wxStyledTextCtrl", "documentEndExtend", 1}, // 3198 - {wxStyledTextCtrl_PageUp, "wxStyledTextCtrl", "pageUp", 1}, // 3199 - {wxStyledTextCtrl_PageUpExtend, "wxStyledTextCtrl", "pageUpExtend", 1}, // 3200 - {wxStyledTextCtrl_PageDown, "wxStyledTextCtrl", "pageDown", 1}, // 3201 - {wxStyledTextCtrl_PageDownExtend, "wxStyledTextCtrl", "pageDownExtend", 1}, // 3202 - {wxStyledTextCtrl_EditToggleOvertype, "wxStyledTextCtrl", "editToggleOvertype", 1}, // 3203 - {wxStyledTextCtrl_Cancel, "wxStyledTextCtrl", "cancel", 1}, // 3204 - {wxStyledTextCtrl_DeleteBack, "wxStyledTextCtrl", "deleteBack", 1}, // 3205 - {wxStyledTextCtrl_Tab, "wxStyledTextCtrl", "tab", 1}, // 3206 - {wxStyledTextCtrl_BackTab, "wxStyledTextCtrl", "backTab", 1}, // 3207 - {wxStyledTextCtrl_NewLine, "wxStyledTextCtrl", "newLine", 1}, // 3208 - {wxStyledTextCtrl_FormFeed, "wxStyledTextCtrl", "formFeed", 1}, // 3209 - {wxStyledTextCtrl_VCHome, "wxStyledTextCtrl", "vCHome", 1}, // 3210 - {wxStyledTextCtrl_VCHomeExtend, "wxStyledTextCtrl", "vCHomeExtend", 1}, // 3211 - {wxStyledTextCtrl_ZoomIn, "wxStyledTextCtrl", "zoomIn", 1}, // 3212 - {wxStyledTextCtrl_ZoomOut, "wxStyledTextCtrl", "zoomOut", 1}, // 3213 - {wxStyledTextCtrl_DelWordLeft, "wxStyledTextCtrl", "delWordLeft", 1}, // 3214 - {wxStyledTextCtrl_DelWordRight, "wxStyledTextCtrl", "delWordRight", 1}, // 3215 - {wxStyledTextCtrl_LineCut, "wxStyledTextCtrl", "lineCut", 1}, // 3216 - {wxStyledTextCtrl_LineDelete, "wxStyledTextCtrl", "lineDelete", 1}, // 3217 - {wxStyledTextCtrl_LineTranspose, "wxStyledTextCtrl", "lineTranspose", 1}, // 3218 - {wxStyledTextCtrl_LineDuplicate, "wxStyledTextCtrl", "lineDuplicate", 1}, // 3219 - {wxStyledTextCtrl_LowerCase, "wxStyledTextCtrl", "lowerCase", 1}, // 3220 - {wxStyledTextCtrl_UpperCase, "wxStyledTextCtrl", "upperCase", 1}, // 3221 - {wxStyledTextCtrl_LineScrollDown, "wxStyledTextCtrl", "lineScrollDown", 1}, // 3222 - {wxStyledTextCtrl_LineScrollUp, "wxStyledTextCtrl", "lineScrollUp", 1}, // 3223 - {wxStyledTextCtrl_DeleteBackNotLine, "wxStyledTextCtrl", "deleteBackNotLine", 1}, // 3224 - {wxStyledTextCtrl_HomeDisplay, "wxStyledTextCtrl", "homeDisplay", 1}, // 3225 - {wxStyledTextCtrl_HomeDisplayExtend, "wxStyledTextCtrl", "homeDisplayExtend", 1}, // 3226 - {wxStyledTextCtrl_LineEndDisplay, "wxStyledTextCtrl", "lineEndDisplay", 1}, // 3227 - {wxStyledTextCtrl_LineEndDisplayExtend, "wxStyledTextCtrl", "lineEndDisplayExtend", 1}, // 3228 - {wxStyledTextCtrl_HomeWrapExtend, "wxStyledTextCtrl", "homeWrapExtend", 1}, // 3229 - {wxStyledTextCtrl_LineEndWrap, "wxStyledTextCtrl", "lineEndWrap", 1}, // 3230 - {wxStyledTextCtrl_LineEndWrapExtend, "wxStyledTextCtrl", "lineEndWrapExtend", 1}, // 3231 - {wxStyledTextCtrl_VCHomeWrap, "wxStyledTextCtrl", "vCHomeWrap", 1}, // 3232 - {wxStyledTextCtrl_VCHomeWrapExtend, "wxStyledTextCtrl", "vCHomeWrapExtend", 1}, // 3233 - {wxStyledTextCtrl_LineCopy, "wxStyledTextCtrl", "lineCopy", 1}, // 3234 - {wxStyledTextCtrl_MoveCaretInsideView, "wxStyledTextCtrl", "moveCaretInsideView", 1}, // 3235 - {wxStyledTextCtrl_LineLength, "wxStyledTextCtrl", "lineLength", 2}, // 3236 - {wxStyledTextCtrl_BraceHighlight, "wxStyledTextCtrl", "braceHighlight", 3}, // 3237 - {wxStyledTextCtrl_BraceBadLight, "wxStyledTextCtrl", "braceBadLight", 2}, // 3238 - {wxStyledTextCtrl_BraceMatch, "wxStyledTextCtrl", "braceMatch", 2}, // 3239 - {wxStyledTextCtrl_GetViewEOL, "wxStyledTextCtrl", "getViewEOL", 1}, // 3240 - {wxStyledTextCtrl_SetViewEOL, "wxStyledTextCtrl", "setViewEOL", 2}, // 3241 - {wxStyledTextCtrl_SetModEventMask, "wxStyledTextCtrl", "setModEventMask", 2}, // 3242 - {wxStyledTextCtrl_GetEdgeColumn, "wxStyledTextCtrl", "getEdgeColumn", 1}, // 3243 - {wxStyledTextCtrl_SetEdgeColumn, "wxStyledTextCtrl", "setEdgeColumn", 2}, // 3244 - {wxStyledTextCtrl_SetEdgeMode, "wxStyledTextCtrl", "setEdgeMode", 2}, // 3245 - {wxStyledTextCtrl_GetEdgeMode, "wxStyledTextCtrl", "getEdgeMode", 1}, // 3246 - {wxStyledTextCtrl_GetEdgeColour, "wxStyledTextCtrl", "getEdgeColour", 1}, // 3247 - {wxStyledTextCtrl_SetEdgeColour, "wxStyledTextCtrl", "setEdgeColour", 2}, // 3248 - {wxStyledTextCtrl_SearchAnchor, "wxStyledTextCtrl", "searchAnchor", 1}, // 3249 - {wxStyledTextCtrl_SearchNext, "wxStyledTextCtrl", "searchNext", 3}, // 3250 - {wxStyledTextCtrl_SearchPrev, "wxStyledTextCtrl", "searchPrev", 3}, // 3251 - {wxStyledTextCtrl_LinesOnScreen, "wxStyledTextCtrl", "linesOnScreen", 1}, // 3252 - {wxStyledTextCtrl_UsePopUp, "wxStyledTextCtrl", "usePopUp", 2}, // 3253 - {wxStyledTextCtrl_SelectionIsRectangle, "wxStyledTextCtrl", "selectionIsRectangle", 1}, // 3254 - {wxStyledTextCtrl_SetZoom, "wxStyledTextCtrl", "setZoom", 2}, // 3255 - {wxStyledTextCtrl_GetZoom, "wxStyledTextCtrl", "getZoom", 1}, // 3256 - {wxStyledTextCtrl_GetModEventMask, "wxStyledTextCtrl", "getModEventMask", 1}, // 3257 - {wxStyledTextCtrl_SetSTCFocus, "wxStyledTextCtrl", "setSTCFocus", 2}, // 3258 - {wxStyledTextCtrl_GetSTCFocus, "wxStyledTextCtrl", "getSTCFocus", 1}, // 3259 - {wxStyledTextCtrl_SetStatus, "wxStyledTextCtrl", "setStatus", 2}, // 3260 - {wxStyledTextCtrl_GetStatus, "wxStyledTextCtrl", "getStatus", 1}, // 3261 - {wxStyledTextCtrl_SetMouseDownCaptures, "wxStyledTextCtrl", "setMouseDownCaptures", 2}, // 3262 - {wxStyledTextCtrl_GetMouseDownCaptures, "wxStyledTextCtrl", "getMouseDownCaptures", 1}, // 3263 - {wxStyledTextCtrl_SetSTCCursor, "wxStyledTextCtrl", "setSTCCursor", 2}, // 3264 - {wxStyledTextCtrl_GetSTCCursor, "wxStyledTextCtrl", "getSTCCursor", 1}, // 3265 - {wxStyledTextCtrl_SetControlCharSymbol, "wxStyledTextCtrl", "setControlCharSymbol", 2}, // 3266 - {wxStyledTextCtrl_GetControlCharSymbol, "wxStyledTextCtrl", "getControlCharSymbol", 1}, // 3267 - {wxStyledTextCtrl_WordPartLeft, "wxStyledTextCtrl", "wordPartLeft", 1}, // 3268 - {wxStyledTextCtrl_WordPartLeftExtend, "wxStyledTextCtrl", "wordPartLeftExtend", 1}, // 3269 - {wxStyledTextCtrl_WordPartRight, "wxStyledTextCtrl", "wordPartRight", 1}, // 3270 - {wxStyledTextCtrl_WordPartRightExtend, "wxStyledTextCtrl", "wordPartRightExtend", 1}, // 3271 - {wxStyledTextCtrl_SetVisiblePolicy, "wxStyledTextCtrl", "setVisiblePolicy", 3}, // 3272 - {wxStyledTextCtrl_DelLineLeft, "wxStyledTextCtrl", "delLineLeft", 1}, // 3273 - {wxStyledTextCtrl_DelLineRight, "wxStyledTextCtrl", "delLineRight", 1}, // 3274 - {wxStyledTextCtrl_GetXOffset, "wxStyledTextCtrl", "getXOffset", 1}, // 3275 - {wxStyledTextCtrl_ChooseCaretX, "wxStyledTextCtrl", "chooseCaretX", 1}, // 3276 - {wxStyledTextCtrl_SetXCaretPolicy, "wxStyledTextCtrl", "setXCaretPolicy", 3}, // 3277 - {wxStyledTextCtrl_SetYCaretPolicy, "wxStyledTextCtrl", "setYCaretPolicy", 3}, // 3278 - {wxStyledTextCtrl_GetPrintWrapMode, "wxStyledTextCtrl", "getPrintWrapMode", 1}, // 3279 - {wxStyledTextCtrl_SetHotspotActiveForeground, "wxStyledTextCtrl", "setHotspotActiveForeground", 3}, // 3280 - {wxStyledTextCtrl_SetHotspotActiveBackground, "wxStyledTextCtrl", "setHotspotActiveBackground", 3}, // 3281 - {wxStyledTextCtrl_SetHotspotActiveUnderline, "wxStyledTextCtrl", "setHotspotActiveUnderline", 2}, // 3282 - {wxStyledTextCtrl_SetHotspotSingleLine, "wxStyledTextCtrl", "setHotspotSingleLine", 2}, // 3283 - {wxStyledTextCtrl_ParaDownExtend, "wxStyledTextCtrl", "paraDownExtend", 1}, // 3284 - {wxStyledTextCtrl_ParaUp, "wxStyledTextCtrl", "paraUp", 1}, // 3285 - {wxStyledTextCtrl_ParaUpExtend, "wxStyledTextCtrl", "paraUpExtend", 1}, // 3286 - {wxStyledTextCtrl_PositionBefore, "wxStyledTextCtrl", "positionBefore", 2}, // 3287 - {wxStyledTextCtrl_PositionAfter, "wxStyledTextCtrl", "positionAfter", 2}, // 3288 - {wxStyledTextCtrl_CopyRange, "wxStyledTextCtrl", "copyRange", 3}, // 3289 - {wxStyledTextCtrl_CopyText, "wxStyledTextCtrl", "copyText", 3}, // 3290 - {wxStyledTextCtrl_SetSelectionMode, "wxStyledTextCtrl", "setSelectionMode", 2}, // 3291 - {wxStyledTextCtrl_GetSelectionMode, "wxStyledTextCtrl", "getSelectionMode", 1}, // 3292 - {wxStyledTextCtrl_LineDownRectExtend, "wxStyledTextCtrl", "lineDownRectExtend", 1}, // 3293 - {wxStyledTextCtrl_LineUpRectExtend, "wxStyledTextCtrl", "lineUpRectExtend", 1}, // 3294 - {wxStyledTextCtrl_CharLeftRectExtend, "wxStyledTextCtrl", "charLeftRectExtend", 1}, // 3295 - {wxStyledTextCtrl_CharRightRectExtend, "wxStyledTextCtrl", "charRightRectExtend", 1}, // 3296 - {wxStyledTextCtrl_HomeRectExtend, "wxStyledTextCtrl", "homeRectExtend", 1}, // 3297 - {wxStyledTextCtrl_VCHomeRectExtend, "wxStyledTextCtrl", "vCHomeRectExtend", 1}, // 3298 - {wxStyledTextCtrl_LineEndRectExtend, "wxStyledTextCtrl", "lineEndRectExtend", 1}, // 3299 - {wxStyledTextCtrl_PageUpRectExtend, "wxStyledTextCtrl", "pageUpRectExtend", 1}, // 3300 - {wxStyledTextCtrl_PageDownRectExtend, "wxStyledTextCtrl", "pageDownRectExtend", 1}, // 3301 - {wxStyledTextCtrl_StutteredPageUp, "wxStyledTextCtrl", "stutteredPageUp", 1}, // 3302 - {wxStyledTextCtrl_StutteredPageUpExtend, "wxStyledTextCtrl", "stutteredPageUpExtend", 1}, // 3303 - {wxStyledTextCtrl_StutteredPageDown, "wxStyledTextCtrl", "stutteredPageDown", 1}, // 3304 - {wxStyledTextCtrl_StutteredPageDownExtend, "wxStyledTextCtrl", "stutteredPageDownExtend", 1}, // 3305 - {wxStyledTextCtrl_WordLeftEnd, "wxStyledTextCtrl", "wordLeftEnd", 1}, // 3306 - {wxStyledTextCtrl_WordLeftEndExtend, "wxStyledTextCtrl", "wordLeftEndExtend", 1}, // 3307 - {wxStyledTextCtrl_WordRightEnd, "wxStyledTextCtrl", "wordRightEnd", 1}, // 3308 - {wxStyledTextCtrl_WordRightEndExtend, "wxStyledTextCtrl", "wordRightEndExtend", 1}, // 3309 - {wxStyledTextCtrl_SetWhitespaceChars, "wxStyledTextCtrl", "setWhitespaceChars", 2}, // 3310 - {wxStyledTextCtrl_SetCharsDefault, "wxStyledTextCtrl", "setCharsDefault", 1}, // 3311 - {wxStyledTextCtrl_AutoCompGetCurrent, "wxStyledTextCtrl", "autoCompGetCurrent", 1}, // 3312 - {wxStyledTextCtrl_Allocate, "wxStyledTextCtrl", "allocate", 2}, // 3313 - {wxStyledTextCtrl_FindColumn, "wxStyledTextCtrl", "findColumn", 3}, // 3314 - {wxStyledTextCtrl_GetCaretSticky, "wxStyledTextCtrl", "getCaretSticky", 1}, // 3315 - {wxStyledTextCtrl_SetCaretSticky, "wxStyledTextCtrl", "setCaretSticky", 2}, // 3316 - {wxStyledTextCtrl_ToggleCaretSticky, "wxStyledTextCtrl", "toggleCaretSticky", 1}, // 3317 - {wxStyledTextCtrl_SetPasteConvertEndings, "wxStyledTextCtrl", "setPasteConvertEndings", 2}, // 3318 - {wxStyledTextCtrl_GetPasteConvertEndings, "wxStyledTextCtrl", "getPasteConvertEndings", 1}, // 3319 - {wxStyledTextCtrl_SelectionDuplicate, "wxStyledTextCtrl", "selectionDuplicate", 1}, // 3320 - {wxStyledTextCtrl_SetCaretLineBackAlpha, "wxStyledTextCtrl", "setCaretLineBackAlpha", 2}, // 3321 - {wxStyledTextCtrl_GetCaretLineBackAlpha, "wxStyledTextCtrl", "getCaretLineBackAlpha", 1}, // 3322 - {wxStyledTextCtrl_StartRecord, "wxStyledTextCtrl", "startRecord", 1}, // 3323 - {wxStyledTextCtrl_StopRecord, "wxStyledTextCtrl", "stopRecord", 1}, // 3324 - {wxStyledTextCtrl_SetLexer, "wxStyledTextCtrl", "setLexer", 2}, // 3325 - {wxStyledTextCtrl_GetLexer, "wxStyledTextCtrl", "getLexer", 1}, // 3326 - {wxStyledTextCtrl_Colourise, "wxStyledTextCtrl", "colourise", 3}, // 3327 - {wxStyledTextCtrl_SetProperty, "wxStyledTextCtrl", "setProperty", 3}, // 3328 - {wxStyledTextCtrl_SetKeyWords, "wxStyledTextCtrl", "setKeyWords", 3}, // 3329 - {wxStyledTextCtrl_SetLexerLanguage, "wxStyledTextCtrl", "setLexerLanguage", 2}, // 3330 - {wxStyledTextCtrl_GetProperty, "wxStyledTextCtrl", "getProperty", 2}, // 3331 - {wxStyledTextCtrl_GetStyleBitsNeeded, "wxStyledTextCtrl", "getStyleBitsNeeded", 1}, // 3332 - {wxStyledTextCtrl_GetCurrentLine, "wxStyledTextCtrl", "getCurrentLine", 1}, // 3333 - {wxStyledTextCtrl_StyleSetSpec, "wxStyledTextCtrl", "styleSetSpec", 3}, // 3334 - {wxStyledTextCtrl_StyleSetFont, "wxStyledTextCtrl", "styleSetFont", 3}, // 3335 - {wxStyledTextCtrl_StyleSetFontAttr, "wxStyledTextCtrl", "styleSetFontAttr", 8}, // 3336 - {wxStyledTextCtrl_StyleSetCharacterSet, "wxStyledTextCtrl", "styleSetCharacterSet", 3}, // 3337 - {wxStyledTextCtrl_StyleSetFontEncoding, "wxStyledTextCtrl", "styleSetFontEncoding", 3}, // 3338 - {wxStyledTextCtrl_CmdKeyExecute, "wxStyledTextCtrl", "cmdKeyExecute", 2}, // 3339 - {wxStyledTextCtrl_SetMargins, "wxStyledTextCtrl", "setMargins", 3}, // 3340 - {wxStyledTextCtrl_GetSelection, "wxStyledTextCtrl", "getSelection", 1}, // 3341 - {wxStyledTextCtrl_PointFromPosition, "wxStyledTextCtrl", "pointFromPosition", 2}, // 3342 - {wxStyledTextCtrl_ScrollToLine, "wxStyledTextCtrl", "scrollToLine", 2}, // 3343 - {wxStyledTextCtrl_ScrollToColumn, "wxStyledTextCtrl", "scrollToColumn", 2}, // 3344 - {wxStyledTextCtrl_SetVScrollBar, "wxStyledTextCtrl", "setVScrollBar", 2}, // 3345 - {wxStyledTextCtrl_SetHScrollBar, "wxStyledTextCtrl", "setHScrollBar", 2}, // 3346 - {wxStyledTextCtrl_GetLastKeydownProcessed, "wxStyledTextCtrl", "getLastKeydownProcessed", 1}, // 3347 - {wxStyledTextCtrl_SetLastKeydownProcessed, "wxStyledTextCtrl", "setLastKeydownProcessed", 2}, // 3348 - {wxStyledTextCtrl_SaveFile, "wxStyledTextCtrl", "saveFile", 2}, // 3349 - {wxStyledTextCtrl_LoadFile, "wxStyledTextCtrl", "loadFile", 2}, // 3350 - {wxStyledTextCtrl_DoDragOver, "wxStyledTextCtrl", "doDragOver", 4}, // 3351 - {wxStyledTextCtrl_DoDropText, "wxStyledTextCtrl", "doDropText", 4}, // 3352 - {wxStyledTextCtrl_GetUseAntiAliasing, "wxStyledTextCtrl", "getUseAntiAliasing", 1}, // 3353 - {wxStyledTextCtrl_AddTextRaw, "wxStyledTextCtrl", "addTextRaw", 3}, // 3354 - {wxStyledTextCtrl_InsertTextRaw, "wxStyledTextCtrl", "insertTextRaw", 3}, // 3355 - {wxStyledTextCtrl_GetCurLineRaw, "wxStyledTextCtrl", "getCurLineRaw", 1}, // 3356 - {wxStyledTextCtrl_GetLineRaw, "wxStyledTextCtrl", "getLineRaw", 2}, // 3357 - {wxStyledTextCtrl_GetSelectedTextRaw, "wxStyledTextCtrl", "getSelectedTextRaw", 1}, // 3358 - {wxStyledTextCtrl_GetTextRangeRaw, "wxStyledTextCtrl", "getTextRangeRaw", 3}, // 3359 - {wxStyledTextCtrl_SetTextRaw, "wxStyledTextCtrl", "setTextRaw", 2}, // 3360 - {wxStyledTextCtrl_GetTextRaw, "wxStyledTextCtrl", "getTextRaw", 1}, // 3361 - {wxStyledTextCtrl_AppendTextRaw, "wxStyledTextCtrl", "appendTextRaw", 3}, // 3362 - {wxArtProvider_GetBitmap, "wxArtProvider", "getBitmap", 2}, // 3363 - {wxArtProvider_GetIcon, "wxArtProvider", "getIcon", 2}, // 3364 - {wxTreeEvent_GetKeyCode, "wxTreeEvent", "getKeyCode", 1}, // 3365 - {wxTreeEvent_GetItem, "wxTreeEvent", "getItem", 1}, // 3366 - {wxTreeEvent_GetKeyEvent, "wxTreeEvent", "getKeyEvent", 1}, // 3367 - {wxTreeEvent_GetLabel, "wxTreeEvent", "getLabel", 1}, // 3368 - {wxTreeEvent_GetOldItem, "wxTreeEvent", "getOldItem", 1}, // 3369 - {wxTreeEvent_GetPoint, "wxTreeEvent", "getPoint", 1}, // 3370 - {wxTreeEvent_IsEditCancelled, "wxTreeEvent", "isEditCancelled", 1}, // 3371 - {wxTreeEvent_SetToolTip, "wxTreeEvent", "setToolTip", 2}, // 3372 - {wxBookCtrlEvent_GetOldSelection, "wxBookCtrlEvent", "getOldSelection", 1}, // 3373 - {wxBookCtrlEvent_GetSelection, "wxBookCtrlEvent", "getSelection", 1}, // 3374 - {wxBookCtrlEvent_SetOldSelection, "wxBookCtrlEvent", "setOldSelection", 2}, // 3375 - {wxBookCtrlEvent_SetSelection, "wxBookCtrlEvent", "setSelection", 2}, // 3376 - {wxFileDataObject_new, "wxFileDataObject", "new", 0}, // 3377 - {wxFileDataObject_AddFile, "wxFileDataObject", "addFile", 2}, // 3378 - {wxFileDataObject_GetFilenames, "wxFileDataObject", "getFilenames", 1}, // 3379 - {wxFileDataObject_destroy, "wxFileDataObject", "'Destroy'", 1}, // 3380 - {wxTextDataObject_new, "wxTextDataObject", "new", 1}, // 3381 - {wxTextDataObject_GetTextLength, "wxTextDataObject", "getTextLength", 1}, // 3382 - {wxTextDataObject_GetText, "wxTextDataObject", "getText", 1}, // 3383 - {wxTextDataObject_SetText, "wxTextDataObject", "setText", 2}, // 3384 - {wxTextDataObject_destroy, "wxTextDataObject", "'Destroy'", 1}, // 3385 - {wxBitmapDataObject_new_1_1, "wxBitmapDataObject", "new", 1}, // 3386 - {wxBitmapDataObject_new_1_0, "wxBitmapDataObject", "new", 1}, // 3387 - {wxBitmapDataObject_GetBitmap, "wxBitmapDataObject", "getBitmap", 1}, // 3388 - {wxBitmapDataObject_SetBitmap, "wxBitmapDataObject", "setBitmap", 2}, // 3389 - {wxBitmapDataObject_destroy, "wxBitmapDataObject", "'Destroy'", 1}, // 3390 - {wxClipboard_new, "wxClipboard", "new", 0}, // 3391 - {NULL, "wxClipboard", "destroy", 1}, // 3392 obj destructor wxClipboard_destruct - {wxClipboard_AddData, "wxClipboard", "addData", 2}, // 3393 - {wxClipboard_Clear, "wxClipboard", "clear", 1}, // 3394 - {wxClipboard_Close, "wxClipboard", "close", 1}, // 3395 - {wxClipboard_Flush, "wxClipboard", "flush", 1}, // 3396 - {wxClipboard_GetData, "wxClipboard", "getData", 2}, // 3397 - {wxClipboard_IsOpened, "wxClipboard", "isOpened", 1}, // 3398 - {wxClipboard_Open, "wxClipboard", "open", 1}, // 3399 - {wxClipboard_SetData, "wxClipboard", "setData", 2}, // 3400 - {wxClipboard_UsePrimarySelection, "wxClipboard", "usePrimarySelection", 2}, // 3401 - {wxClipboard_IsSupported, "wxClipboard", "isSupported", 2}, // 3402 - {wxClipboard_Get, "wxClipboard", "get", 0}, // 3403 - {wxSpinEvent_GetPosition, "wxSpinEvent", "getPosition", 1}, // 3404 - {wxSpinEvent_SetPosition, "wxSpinEvent", "setPosition", 2}, // 3405 - {wxSplitterWindow_new_0, "wxSplitterWindow", "new", 0}, // 3406 - {wxSplitterWindow_new_2, "wxSplitterWindow", "new", 2}, // 3407 - {NULL, "wxSplitterWindow", "destroy", 1}, // 3408 obj destructor wxSplitterWindow_destruct - {wxSplitterWindow_Create, "wxSplitterWindow", "create", 3}, // 3409 - {wxSplitterWindow_GetMinimumPaneSize, "wxSplitterWindow", "getMinimumPaneSize", 1}, // 3410 - {wxSplitterWindow_GetSashGravity, "wxSplitterWindow", "getSashGravity", 1}, // 3411 - {wxSplitterWindow_GetSashPosition, "wxSplitterWindow", "getSashPosition", 1}, // 3412 - {wxSplitterWindow_GetSplitMode, "wxSplitterWindow", "getSplitMode", 1}, // 3413 - {wxSplitterWindow_GetWindow1, "wxSplitterWindow", "getWindow1", 1}, // 3414 - {wxSplitterWindow_GetWindow2, "wxSplitterWindow", "getWindow2", 1}, // 3415 - {wxSplitterWindow_Initialize, "wxSplitterWindow", "initialize", 2}, // 3416 - {wxSplitterWindow_IsSplit, "wxSplitterWindow", "isSplit", 1}, // 3417 - {wxSplitterWindow_ReplaceWindow, "wxSplitterWindow", "replaceWindow", 3}, // 3418 - {wxSplitterWindow_SetSashGravity, "wxSplitterWindow", "setSashGravity", 2}, // 3419 - {wxSplitterWindow_SetSashPosition, "wxSplitterWindow", "setSashPosition", 3}, // 3420 - {wxSplitterWindow_SetMinimumPaneSize, "wxSplitterWindow", "setMinimumPaneSize", 2}, // 3421 - {wxSplitterWindow_SetSplitMode, "wxSplitterWindow", "setSplitMode", 2}, // 3422 - {wxSplitterWindow_SplitHorizontally, "wxSplitterWindow", "splitHorizontally", 4}, // 3423 - {wxSplitterWindow_SplitVertically, "wxSplitterWindow", "splitVertically", 4}, // 3424 - {wxSplitterWindow_Unsplit, "wxSplitterWindow", "unsplit", 2}, // 3425 - {wxSplitterWindow_UpdateSize, "wxSplitterWindow", "updateSize", 1}, // 3426 - {wxSplitterEvent_GetSashPosition, "wxSplitterEvent", "getSashPosition", 1}, // 3427 - {wxSplitterEvent_GetX, "wxSplitterEvent", "getX", 1}, // 3428 - {wxSplitterEvent_GetY, "wxSplitterEvent", "getY", 1}, // 3429 - {wxSplitterEvent_GetWindowBeingRemoved, "wxSplitterEvent", "getWindowBeingRemoved", 1}, // 3430 - {wxSplitterEvent_SetSashPosition, "wxSplitterEvent", "setSashPosition", 2}, // 3431 - {wxHtmlWindow_new_0, "wxHtmlWindow", "new", 0}, // 3432 - {wxHtmlWindow_new_2, "wxHtmlWindow", "new", 2}, // 3433 - {wxHtmlWindow_AppendToPage, "wxHtmlWindow", "appendToPage", 2}, // 3434 - {wxHtmlWindow_GetOpenedAnchor, "wxHtmlWindow", "getOpenedAnchor", 1}, // 3435 - {wxHtmlWindow_GetOpenedPage, "wxHtmlWindow", "getOpenedPage", 1}, // 3436 - {wxHtmlWindow_GetOpenedPageTitle, "wxHtmlWindow", "getOpenedPageTitle", 1}, // 3437 - {wxHtmlWindow_GetRelatedFrame, "wxHtmlWindow", "getRelatedFrame", 1}, // 3438 - {wxHtmlWindow_HistoryBack, "wxHtmlWindow", "historyBack", 1}, // 3439 - {wxHtmlWindow_HistoryCanBack, "wxHtmlWindow", "historyCanBack", 1}, // 3440 - {wxHtmlWindow_HistoryCanForward, "wxHtmlWindow", "historyCanForward", 1}, // 3441 - {wxHtmlWindow_HistoryClear, "wxHtmlWindow", "historyClear", 1}, // 3442 - {wxHtmlWindow_HistoryForward, "wxHtmlWindow", "historyForward", 1}, // 3443 - {wxHtmlWindow_LoadFile, "wxHtmlWindow", "loadFile", 2}, // 3444 - {wxHtmlWindow_LoadPage, "wxHtmlWindow", "loadPage", 2}, // 3445 - {wxHtmlWindow_SelectAll, "wxHtmlWindow", "selectAll", 1}, // 3446 - {wxHtmlWindow_SelectionToText, "wxHtmlWindow", "selectionToText", 1}, // 3447 - {wxHtmlWindow_SelectLine, "wxHtmlWindow", "selectLine", 2}, // 3448 - {wxHtmlWindow_SelectWord, "wxHtmlWindow", "selectWord", 2}, // 3449 - {wxHtmlWindow_SetBorders, "wxHtmlWindow", "setBorders", 2}, // 3450 - {wxHtmlWindow_SetFonts, "wxHtmlWindow", "setFonts", 4}, // 3451 - {wxHtmlWindow_SetPage, "wxHtmlWindow", "setPage", 2}, // 3452 - {wxHtmlWindow_SetRelatedFrame, "wxHtmlWindow", "setRelatedFrame", 3}, // 3453 - {wxHtmlWindow_SetRelatedStatusBar_1, "wxHtmlWindow", "setRelatedStatusBar", 2}, // 3454 - {wxHtmlWindow_SetRelatedStatusBar_2, "wxHtmlWindow", "setRelatedStatusBar", 3}, // 3455 - {wxHtmlWindow_ToText, "wxHtmlWindow", "toText", 1}, // 3456 - {NULL, "wxHtmlWindow", "'Destroy'", 1}, // 3457 obj destructor wxHtmlWindow_destroy - {wxHtmlLinkEvent_GetLinkInfo, "wxHtmlLinkEvent", "getLinkInfo", 1}, // 3458 - {wxSystemSettings_GetColour, "wxSystemSettings", "getColour", 1}, // 3459 - {wxSystemSettings_GetFont, "wxSystemSettings", "getFont", 1}, // 3460 - {wxSystemSettings_GetMetric, "wxSystemSettings", "getMetric", 2}, // 3461 - {wxSystemSettings_GetScreenType, "wxSystemSettings", "getScreenType", 0}, // 3462 - {wxSystemOptions_GetOption, "wxSystemOptions", "getOption", 1}, // 3463 - {wxSystemOptions_GetOptionInt, "wxSystemOptions", "getOptionInt", 1}, // 3464 - {wxSystemOptions_HasOption, "wxSystemOptions", "hasOption", 1}, // 3465 - {wxSystemOptions_IsFalse, "wxSystemOptions", "isFalse", 1}, // 3466 - {wxSystemOptions_SetOption_2_1, "wxSystemOptions", "setOption", 2}, // 3467 - {wxSystemOptions_SetOption_2_0, "wxSystemOptions", "setOption", 2}, // 3468 - {wxAuiNotebookEvent_SetSelection, "wxAuiNotebookEvent", "setSelection", 2}, // 3469 - {wxAuiNotebookEvent_GetSelection, "wxAuiNotebookEvent", "getSelection", 1}, // 3470 - {wxAuiNotebookEvent_SetOldSelection, "wxAuiNotebookEvent", "setOldSelection", 2}, // 3471 - {wxAuiNotebookEvent_GetOldSelection, "wxAuiNotebookEvent", "getOldSelection", 1}, // 3472 - {wxAuiNotebookEvent_SetDragSource, "wxAuiNotebookEvent", "setDragSource", 2}, // 3473 - {wxAuiNotebookEvent_GetDragSource, "wxAuiNotebookEvent", "getDragSource", 1}, // 3474 - {wxAuiManagerEvent_SetManager, "wxAuiManagerEvent", "setManager", 2}, // 3475 - {wxAuiManagerEvent_GetManager, "wxAuiManagerEvent", "getManager", 1}, // 3476 - {wxAuiManagerEvent_SetPane, "wxAuiManagerEvent", "setPane", 2}, // 3477 - {wxAuiManagerEvent_GetPane, "wxAuiManagerEvent", "getPane", 1}, // 3478 - {wxAuiManagerEvent_SetButton, "wxAuiManagerEvent", "setButton", 2}, // 3479 - {wxAuiManagerEvent_GetButton, "wxAuiManagerEvent", "getButton", 1}, // 3480 - {wxAuiManagerEvent_SetDC, "wxAuiManagerEvent", "setDC", 2}, // 3481 - {wxAuiManagerEvent_GetDC, "wxAuiManagerEvent", "getDC", 1}, // 3482 - {wxAuiManagerEvent_Veto, "wxAuiManagerEvent", "veto", 2}, // 3483 - {wxAuiManagerEvent_GetVeto, "wxAuiManagerEvent", "getVeto", 1}, // 3484 - {wxAuiManagerEvent_SetCanVeto, "wxAuiManagerEvent", "setCanVeto", 2}, // 3485 - {wxAuiManagerEvent_CanVeto, "wxAuiManagerEvent", "canVeto", 1}, // 3486 - {wxLogNull_new, "wxLogNull", "new", 0}, // 3487 - {wxLogNull_destruct, "wxLogNull", "destroy", 1}, // 3488 - {wxTaskBarIcon_new, "wxTaskBarIcon", "new", 1}, // 3489 - {NULL, "wxTaskBarIcon", "destroy", 1}, // 3490 obj destructor wxTaskBarIcon_destruct - {wxTaskBarIcon_PopupMenu, "wxTaskBarIcon", "popupMenu", 2}, // 3491 - {wxTaskBarIcon_RemoveIcon, "wxTaskBarIcon", "removeIcon", 1}, // 3492 - {wxTaskBarIcon_SetIcon, "wxTaskBarIcon", "setIcon", 3}, // 3493 - {wxLocale_new_0, "wxLocale", "new", 0}, // 3494 - {wxLocale_new_2_0, "wxLocale", "new", 2}, // 3495 - {wxLocale_new_2_1, "wxLocale", "new", 2}, // 3496 - {wxLocale_destruct, "wxLocale", "destroy", 1}, // 3497 - {wxLocale_Init_1, "wxLocale", "init", 2}, // 3498 - {wxLocale_Init_2, "wxLocale", "init", 3}, // 3499 - {wxLocale_AddCatalog_1, "wxLocale", "addCatalog", 2}, // 3500 - {wxLocale_AddCatalog_2, "wxLocale", "addCatalog", 3}, // 3501 - {wxLocale_AddCatalog_3, "wxLocale", "addCatalog", 4}, // 3502 - {wxLocale_AddCatalogLookupPathPrefix, "wxLocale", "addCatalogLookupPathPrefix", 1}, // 3503 - {wxLocale_GetCanonicalName, "wxLocale", "getCanonicalName", 1}, // 3504 - {wxLocale_GetLanguage, "wxLocale", "getLanguage", 1}, // 3505 - {wxLocale_GetLanguageName, "wxLocale", "getLanguageName", 1}, // 3506 - {wxLocale_GetLocale, "wxLocale", "getLocale", 1}, // 3507 - {wxLocale_GetName, "wxLocale", "getName", 1}, // 3508 - {wxLocale_GetString_2, "wxLocale", "getString", 3}, // 3509 - {wxLocale_GetString_4, "wxLocale", "getString", 5}, // 3510 - {wxLocale_GetHeaderValue, "wxLocale", "getHeaderValue", 3}, // 3511 - {wxLocale_GetSysName, "wxLocale", "getSysName", 1}, // 3512 - {wxLocale_GetSystemEncoding, "wxLocale", "getSystemEncoding", 0}, // 3513 - {wxLocale_GetSystemEncodingName, "wxLocale", "getSystemEncodingName", 0}, // 3514 - {wxLocale_GetSystemLanguage, "wxLocale", "getSystemLanguage", 0}, // 3515 - {wxLocale_IsLoaded, "wxLocale", "isLoaded", 2}, // 3516 - {wxLocale_IsOk, "wxLocale", "isOk", 1}, // 3517 - {wxActivateEvent_GetActive, "wxActivateEvent", "getActive", 1}, // 3518 + {wxMDIParentFrame_new_0, "wxMDIParentFrame", "new", 0}, // 2651 + {wxMDIParentFrame_new_4, "wxMDIParentFrame", "new", 4}, // 2652 + {NULL, "wxMDIParentFrame", "destroy", 1}, // 2653 obj destructor wxMDIParentFrame_destruct + {wxMDIParentFrame_ActivateNext, "wxMDIParentFrame", "activateNext", 1}, // 2654 + {wxMDIParentFrame_ActivatePrevious, "wxMDIParentFrame", "activatePrevious", 1}, // 2655 + {wxMDIParentFrame_ArrangeIcons, "wxMDIParentFrame", "arrangeIcons", 1}, // 2656 + {wxMDIParentFrame_Cascade, "wxMDIParentFrame", "cascade", 1}, // 2657 + {wxMDIParentFrame_Create, "wxMDIParentFrame", "create", 5}, // 2658 + {wxMDIParentFrame_GetActiveChild, "wxMDIParentFrame", "getActiveChild", 1}, // 2659 + {wxMDIParentFrame_GetClientWindow, "wxMDIParentFrame", "getClientWindow", 1}, // 2660 + {wxMDIParentFrame_Tile, "wxMDIParentFrame", "tile", 2}, // 2661 + {wxMDIChildFrame_new_0, "wxMDIChildFrame", "new", 0}, // 2662 + {wxMDIChildFrame_new_4, "wxMDIChildFrame", "new", 4}, // 2663 + {NULL, "wxMDIChildFrame", "destroy", 1}, // 2664 obj destructor wxMDIChildFrame_destruct + {wxMDIChildFrame_Activate, "wxMDIChildFrame", "activate", 1}, // 2665 + {wxMDIChildFrame_Create, "wxMDIChildFrame", "create", 5}, // 2666 + {wxMDIChildFrame_Maximize, "wxMDIChildFrame", "maximize", 2}, // 2667 + {wxMDIChildFrame_Restore, "wxMDIChildFrame", "restore", 1}, // 2668 + {wxMDIClientWindow_new, "wxMDIClientWindow", "new", 0}, // 2669 + {wxMDIClientWindow_CreateClient, "wxMDIClientWindow", "createClient", 3}, // 2670 + {NULL, "wxMDIClientWindow", "'Destroy'", 1}, // 2671 obj destructor wxMDIClientWindow_destroy + {wxLayoutAlgorithm_new, "wxLayoutAlgorithm", "new", 0}, // 2672 + {NULL, "wxLayoutAlgorithm", "destroy", 1}, // 2673 obj destructor wxLayoutAlgorithm_destruct + {wxLayoutAlgorithm_LayoutFrame, "wxLayoutAlgorithm", "layoutFrame", 3}, // 2674 + {wxLayoutAlgorithm_LayoutMDIFrame, "wxLayoutAlgorithm", "layoutMDIFrame", 3}, // 2675 + {wxLayoutAlgorithm_LayoutWindow, "wxLayoutAlgorithm", "layoutWindow", 3}, // 2676 + {wxEvent_GetId, "wxEvent", "getId", 1}, // 2677 + {wxEvent_GetSkipped, "wxEvent", "getSkipped", 1}, // 2678 + {wxEvent_GetTimestamp, "wxEvent", "getTimestamp", 1}, // 2679 + {wxEvent_IsCommandEvent, "wxEvent", "isCommandEvent", 1}, // 2680 + {wxEvent_ResumePropagation, "wxEvent", "resumePropagation", 2}, // 2681 + {wxEvent_ShouldPropagate, "wxEvent", "shouldPropagate", 1}, // 2682 + {wxEvent_Skip, "wxEvent", "skip", 2}, // 2683 + {wxEvent_StopPropagation, "wxEvent", "stopPropagation", 1}, // 2684 + {wxCommandEvent_getClientData, "wxCommandEvent", "getClientData", 1}, // 2685 + {wxCommandEvent_GetExtraLong, "wxCommandEvent", "getExtraLong", 1}, // 2686 + {wxCommandEvent_GetInt, "wxCommandEvent", "getInt", 1}, // 2687 + {wxCommandEvent_GetSelection, "wxCommandEvent", "getSelection", 1}, // 2688 + {wxCommandEvent_GetString, "wxCommandEvent", "getString", 1}, // 2689 + {wxCommandEvent_IsChecked, "wxCommandEvent", "isChecked", 1}, // 2690 + {wxCommandEvent_IsSelection, "wxCommandEvent", "isSelection", 1}, // 2691 + {wxCommandEvent_SetInt, "wxCommandEvent", "setInt", 2}, // 2692 + {wxCommandEvent_SetString, "wxCommandEvent", "setString", 2}, // 2693 + {wxScrollEvent_GetOrientation, "wxScrollEvent", "getOrientation", 1}, // 2694 + {wxScrollEvent_GetPosition, "wxScrollEvent", "getPosition", 1}, // 2695 + {wxScrollWinEvent_GetOrientation, "wxScrollWinEvent", "getOrientation", 1}, // 2696 + {wxScrollWinEvent_GetPosition, "wxScrollWinEvent", "getPosition", 1}, // 2697 + {wxMouseEvent_AltDown, "wxMouseEvent", "altDown", 1}, // 2698 + {wxMouseEvent_Button, "wxMouseEvent", "button", 2}, // 2699 + {wxMouseEvent_ButtonDClick, "wxMouseEvent", "buttonDClick", 2}, // 2700 + {wxMouseEvent_ButtonDown, "wxMouseEvent", "buttonDown", 2}, // 2701 + {wxMouseEvent_ButtonUp, "wxMouseEvent", "buttonUp", 2}, // 2702 + {wxMouseEvent_CmdDown, "wxMouseEvent", "cmdDown", 1}, // 2703 + {wxMouseEvent_ControlDown, "wxMouseEvent", "controlDown", 1}, // 2704 + {wxMouseEvent_Dragging, "wxMouseEvent", "dragging", 1}, // 2705 + {wxMouseEvent_Entering, "wxMouseEvent", "entering", 1}, // 2706 + {wxMouseEvent_GetButton, "wxMouseEvent", "getButton", 1}, // 2707 + {wxMouseEvent_GetPosition, "wxMouseEvent", "getPosition", 1}, // 2708 + {NULL, "", "", 0}, // 2709 + {wxMouseEvent_GetLogicalPosition, "wxMouseEvent", "getLogicalPosition", 2}, // 2710 + {wxMouseEvent_GetLinesPerAction, "wxMouseEvent", "getLinesPerAction", 1}, // 2711 + {wxMouseEvent_GetWheelRotation, "wxMouseEvent", "getWheelRotation", 1}, // 2712 + {wxMouseEvent_GetWheelDelta, "wxMouseEvent", "getWheelDelta", 1}, // 2713 + {wxMouseEvent_GetX, "wxMouseEvent", "getX", 1}, // 2714 + {wxMouseEvent_GetY, "wxMouseEvent", "getY", 1}, // 2715 + {wxMouseEvent_IsButton, "wxMouseEvent", "isButton", 1}, // 2716 + {wxMouseEvent_IsPageScroll, "wxMouseEvent", "isPageScroll", 1}, // 2717 + {wxMouseEvent_Leaving, "wxMouseEvent", "leaving", 1}, // 2718 + {wxMouseEvent_LeftDClick, "wxMouseEvent", "leftDClick", 1}, // 2719 + {wxMouseEvent_LeftDown, "wxMouseEvent", "leftDown", 1}, // 2720 + {wxMouseEvent_LeftIsDown, "wxMouseEvent", "leftIsDown", 1}, // 2721 + {wxMouseEvent_LeftUp, "wxMouseEvent", "leftUp", 1}, // 2722 + {wxMouseEvent_MetaDown, "wxMouseEvent", "metaDown", 1}, // 2723 + {wxMouseEvent_MiddleDClick, "wxMouseEvent", "middleDClick", 1}, // 2724 + {wxMouseEvent_MiddleDown, "wxMouseEvent", "middleDown", 1}, // 2725 + {wxMouseEvent_MiddleIsDown, "wxMouseEvent", "middleIsDown", 1}, // 2726 + {wxMouseEvent_MiddleUp, "wxMouseEvent", "middleUp", 1}, // 2727 + {wxMouseEvent_Moving, "wxMouseEvent", "moving", 1}, // 2728 + {wxMouseEvent_RightDClick, "wxMouseEvent", "rightDClick", 1}, // 2729 + {wxMouseEvent_RightDown, "wxMouseEvent", "rightDown", 1}, // 2730 + {wxMouseEvent_RightIsDown, "wxMouseEvent", "rightIsDown", 1}, // 2731 + {wxMouseEvent_RightUp, "wxMouseEvent", "rightUp", 1}, // 2732 + {wxMouseEvent_ShiftDown, "wxMouseEvent", "shiftDown", 1}, // 2733 + {wxMouseEvent_GetWheelAxis, "wxMouseEvent", "getWheelAxis", 1}, // 2734 + {wxMouseEvent_Aux1DClick, "wxMouseEvent", "aux1DClick", 1}, // 2735 + {wxMouseEvent_Aux1Down, "wxMouseEvent", "aux1Down", 1}, // 2736 + {wxMouseEvent_Aux1Up, "wxMouseEvent", "aux1Up", 1}, // 2737 + {wxMouseEvent_Aux2DClick, "wxMouseEvent", "aux2DClick", 1}, // 2738 + {wxMouseEvent_Aux2Down, "wxMouseEvent", "aux2Down", 1}, // 2739 + {wxMouseEvent_Aux2Up, "wxMouseEvent", "aux2Up", 1}, // 2740 + {wxSetCursorEvent_GetCursor, "wxSetCursorEvent", "getCursor", 1}, // 2741 + {wxSetCursorEvent_GetX, "wxSetCursorEvent", "getX", 1}, // 2742 + {wxSetCursorEvent_GetY, "wxSetCursorEvent", "getY", 1}, // 2743 + {wxSetCursorEvent_HasCursor, "wxSetCursorEvent", "hasCursor", 1}, // 2744 + {wxSetCursorEvent_SetCursor, "wxSetCursorEvent", "setCursor", 2}, // 2745 + {wxKeyEvent_AltDown, "wxKeyEvent", "altDown", 1}, // 2746 + {wxKeyEvent_CmdDown, "wxKeyEvent", "cmdDown", 1}, // 2747 + {wxKeyEvent_ControlDown, "wxKeyEvent", "controlDown", 1}, // 2748 + {wxKeyEvent_GetKeyCode, "wxKeyEvent", "getKeyCode", 1}, // 2749 + {wxKeyEvent_GetModifiers, "wxKeyEvent", "getModifiers", 1}, // 2750 + {wxKeyEvent_GetPosition, "wxKeyEvent", "getPosition", 1}, // 2751 + {NULL, "", "", 0}, // 2752 + {wxKeyEvent_GetRawKeyCode, "wxKeyEvent", "getRawKeyCode", 1}, // 2753 + {wxKeyEvent_GetRawKeyFlags, "wxKeyEvent", "getRawKeyFlags", 1}, // 2754 + {wxKeyEvent_GetUnicodeKey, "wxKeyEvent", "getUnicodeKey", 1}, // 2755 + {wxKeyEvent_GetX, "wxKeyEvent", "getX", 1}, // 2756 + {wxKeyEvent_GetY, "wxKeyEvent", "getY", 1}, // 2757 + {wxKeyEvent_HasModifiers, "wxKeyEvent", "hasModifiers", 1}, // 2758 + {wxKeyEvent_MetaDown, "wxKeyEvent", "metaDown", 1}, // 2759 + {wxKeyEvent_ShiftDown, "wxKeyEvent", "shiftDown", 1}, // 2760 + {wxSizeEvent_GetSize, "wxSizeEvent", "getSize", 1}, // 2761 + {wxSizeEvent_GetRect, "wxSizeEvent", "getRect", 1}, // 2762 + {wxMoveEvent_GetPosition, "wxMoveEvent", "getPosition", 1}, // 2763 + {wxMoveEvent_GetRect, "wxMoveEvent", "getRect", 1}, // 2764 + {wxEraseEvent_GetDC, "wxEraseEvent", "getDC", 1}, // 2765 + {wxFocusEvent_GetWindow, "wxFocusEvent", "getWindow", 1}, // 2766 + {wxChildFocusEvent_GetWindow, "wxChildFocusEvent", "getWindow", 1}, // 2767 + {wxMenuEvent_GetMenu, "wxMenuEvent", "getMenu", 1}, // 2768 + {wxMenuEvent_GetMenuId, "wxMenuEvent", "getMenuId", 1}, // 2769 + {wxMenuEvent_IsPopup, "wxMenuEvent", "isPopup", 1}, // 2770 + {wxCloseEvent_CanVeto, "wxCloseEvent", "canVeto", 1}, // 2771 + {wxCloseEvent_GetLoggingOff, "wxCloseEvent", "getLoggingOff", 1}, // 2772 + {wxCloseEvent_SetCanVeto, "wxCloseEvent", "setCanVeto", 2}, // 2773 + {wxCloseEvent_SetLoggingOff, "wxCloseEvent", "setLoggingOff", 2}, // 2774 + {wxCloseEvent_Veto, "wxCloseEvent", "veto", 2}, // 2775 + {wxShowEvent_SetShow, "wxShowEvent", "setShow", 2}, // 2776 + {wxShowEvent_IsShown, "wxShowEvent", "isShown", 1}, // 2777 + {wxIconizeEvent_IsIconized, "wxIconizeEvent", "isIconized", 1}, // 2778 + {wxJoystickEvent_ButtonDown, "wxJoystickEvent", "buttonDown", 2}, // 2779 + {wxJoystickEvent_ButtonIsDown, "wxJoystickEvent", "buttonIsDown", 2}, // 2780 + {wxJoystickEvent_ButtonUp, "wxJoystickEvent", "buttonUp", 2}, // 2781 + {wxJoystickEvent_GetButtonChange, "wxJoystickEvent", "getButtonChange", 1}, // 2782 + {wxJoystickEvent_GetButtonState, "wxJoystickEvent", "getButtonState", 1}, // 2783 + {wxJoystickEvent_GetJoystick, "wxJoystickEvent", "getJoystick", 1}, // 2784 + {wxJoystickEvent_GetPosition, "wxJoystickEvent", "getPosition", 1}, // 2785 + {wxJoystickEvent_GetZPosition, "wxJoystickEvent", "getZPosition", 1}, // 2786 + {wxJoystickEvent_IsButton, "wxJoystickEvent", "isButton", 1}, // 2787 + {wxJoystickEvent_IsMove, "wxJoystickEvent", "isMove", 1}, // 2788 + {wxJoystickEvent_IsZMove, "wxJoystickEvent", "isZMove", 1}, // 2789 + {wxUpdateUIEvent_CanUpdate, "wxUpdateUIEvent", "canUpdate", 1}, // 2790 + {wxUpdateUIEvent_Check, "wxUpdateUIEvent", "check", 2}, // 2791 + {wxUpdateUIEvent_Enable, "wxUpdateUIEvent", "enable", 2}, // 2792 + {wxUpdateUIEvent_Show, "wxUpdateUIEvent", "show", 2}, // 2793 + {wxUpdateUIEvent_GetChecked, "wxUpdateUIEvent", "getChecked", 1}, // 2794 + {wxUpdateUIEvent_GetEnabled, "wxUpdateUIEvent", "getEnabled", 1}, // 2795 + {wxUpdateUIEvent_GetShown, "wxUpdateUIEvent", "getShown", 1}, // 2796 + {wxUpdateUIEvent_GetSetChecked, "wxUpdateUIEvent", "getSetChecked", 1}, // 2797 + {wxUpdateUIEvent_GetSetEnabled, "wxUpdateUIEvent", "getSetEnabled", 1}, // 2798 + {wxUpdateUIEvent_GetSetShown, "wxUpdateUIEvent", "getSetShown", 1}, // 2799 + {wxUpdateUIEvent_GetSetText, "wxUpdateUIEvent", "getSetText", 1}, // 2800 + {wxUpdateUIEvent_GetText, "wxUpdateUIEvent", "getText", 1}, // 2801 + {wxUpdateUIEvent_GetMode, "wxUpdateUIEvent", "getMode", 0}, // 2802 + {wxUpdateUIEvent_GetUpdateInterval, "wxUpdateUIEvent", "getUpdateInterval", 0}, // 2803 + {wxUpdateUIEvent_ResetUpdateTime, "wxUpdateUIEvent", "resetUpdateTime", 0}, // 2804 + {wxUpdateUIEvent_SetMode, "wxUpdateUIEvent", "setMode", 1}, // 2805 + {wxUpdateUIEvent_SetText, "wxUpdateUIEvent", "setText", 2}, // 2806 + {wxUpdateUIEvent_SetUpdateInterval, "wxUpdateUIEvent", "setUpdateInterval", 1}, // 2807 + {wxMouseCaptureChangedEvent_GetCapturedWindow, "wxMouseCaptureChangedEvent", "getCapturedWindow", 1}, // 2808 + {wxPaletteChangedEvent_SetChangedWindow, "wxPaletteChangedEvent", "setChangedWindow", 2}, // 2809 + {wxPaletteChangedEvent_GetChangedWindow, "wxPaletteChangedEvent", "getChangedWindow", 1}, // 2810 + {wxQueryNewPaletteEvent_SetPaletteRealized, "wxQueryNewPaletteEvent", "setPaletteRealized", 2}, // 2811 + {wxQueryNewPaletteEvent_GetPaletteRealized, "wxQueryNewPaletteEvent", "getPaletteRealized", 1}, // 2812 + {wxNavigationKeyEvent_GetDirection, "wxNavigationKeyEvent", "getDirection", 1}, // 2813 + {wxNavigationKeyEvent_SetDirection, "wxNavigationKeyEvent", "setDirection", 2}, // 2814 + {wxNavigationKeyEvent_IsWindowChange, "wxNavigationKeyEvent", "isWindowChange", 1}, // 2815 + {wxNavigationKeyEvent_SetWindowChange, "wxNavigationKeyEvent", "setWindowChange", 2}, // 2816 + {wxNavigationKeyEvent_IsFromTab, "wxNavigationKeyEvent", "isFromTab", 1}, // 2817 + {wxNavigationKeyEvent_SetFromTab, "wxNavigationKeyEvent", "setFromTab", 2}, // 2818 + {wxNavigationKeyEvent_GetCurrentFocus, "wxNavigationKeyEvent", "getCurrentFocus", 1}, // 2819 + {wxNavigationKeyEvent_SetCurrentFocus, "wxNavigationKeyEvent", "setCurrentFocus", 2}, // 2820 + {wxHelpEvent_GetOrigin, "wxHelpEvent", "getOrigin", 1}, // 2821 + {wxHelpEvent_GetPosition, "wxHelpEvent", "getPosition", 1}, // 2822 + {wxHelpEvent_SetOrigin, "wxHelpEvent", "setOrigin", 2}, // 2823 + {wxHelpEvent_SetPosition, "wxHelpEvent", "setPosition", 2}, // 2824 + {wxContextMenuEvent_GetPosition, "wxContextMenuEvent", "getPosition", 1}, // 2825 + {wxContextMenuEvent_SetPosition, "wxContextMenuEvent", "setPosition", 2}, // 2826 + {wxIdleEvent_GetMode, "wxIdleEvent", "getMode", 0}, // 2827 + {wxIdleEvent_RequestMore, "wxIdleEvent", "requestMore", 2}, // 2828 + {wxIdleEvent_MoreRequested, "wxIdleEvent", "moreRequested", 1}, // 2829 + {wxIdleEvent_SetMode, "wxIdleEvent", "setMode", 1}, // 2830 + {wxGridEvent_AltDown, "wxGridEvent", "altDown", 1}, // 2831 + {wxGridEvent_ControlDown, "wxGridEvent", "controlDown", 1}, // 2832 + {wxGridEvent_GetCol, "wxGridEvent", "getCol", 1}, // 2833 + {wxGridEvent_GetPosition, "wxGridEvent", "getPosition", 1}, // 2834 + {wxGridEvent_GetRow, "wxGridEvent", "getRow", 1}, // 2835 + {wxGridEvent_MetaDown, "wxGridEvent", "metaDown", 1}, // 2836 + {wxGridEvent_Selecting, "wxGridEvent", "selecting", 1}, // 2837 + {wxGridEvent_ShiftDown, "wxGridEvent", "shiftDown", 1}, // 2838 + {wxNotifyEvent_Allow, "wxNotifyEvent", "allow", 1}, // 2839 + {wxNotifyEvent_IsAllowed, "wxNotifyEvent", "isAllowed", 1}, // 2840 + {wxNotifyEvent_Veto, "wxNotifyEvent", "veto", 1}, // 2841 + {wxSashEvent_GetEdge, "wxSashEvent", "getEdge", 1}, // 2842 + {wxSashEvent_GetDragRect, "wxSashEvent", "getDragRect", 1}, // 2843 + {wxSashEvent_GetDragStatus, "wxSashEvent", "getDragStatus", 1}, // 2844 + {wxListEvent_GetCacheFrom, "wxListEvent", "getCacheFrom", 1}, // 2845 + {wxListEvent_GetCacheTo, "wxListEvent", "getCacheTo", 1}, // 2846 + {wxListEvent_GetKeyCode, "wxListEvent", "getKeyCode", 1}, // 2847 + {wxListEvent_GetIndex, "wxListEvent", "getIndex", 1}, // 2848 + {wxListEvent_GetColumn, "wxListEvent", "getColumn", 1}, // 2849 + {wxListEvent_GetPoint, "wxListEvent", "getPoint", 1}, // 2850 + {wxListEvent_GetLabel, "wxListEvent", "getLabel", 1}, // 2851 + {wxListEvent_GetText, "wxListEvent", "getText", 1}, // 2852 + {wxListEvent_GetImage, "wxListEvent", "getImage", 1}, // 2853 + {wxListEvent_GetData, "wxListEvent", "getData", 1}, // 2854 + {wxListEvent_GetMask, "wxListEvent", "getMask", 1}, // 2855 + {wxListEvent_GetItem, "wxListEvent", "getItem", 1}, // 2856 + {wxListEvent_IsEditCancelled, "wxListEvent", "isEditCancelled", 1}, // 2857 + {wxDateEvent_GetDate, "wxDateEvent", "getDate", 1}, // 2858 + {wxCalendarEvent_GetWeekDay, "wxCalendarEvent", "getWeekDay", 1}, // 2859 + {wxCalendarEvent_GetDate, "wxCalendarEvent", "getDate", 1}, // 2860 + {wxFileDirPickerEvent_GetPath, "wxFileDirPickerEvent", "getPath", 1}, // 2861 + {wxColourPickerEvent_GetColour, "wxColourPickerEvent", "getColour", 1}, // 2862 + {wxFontPickerEvent_GetFont, "wxFontPickerEvent", "getFont", 1}, // 2863 + {wxStyledTextEvent_GetPosition, "wxStyledTextEvent", "getPosition", 1}, // 2864 + {wxStyledTextEvent_GetKey, "wxStyledTextEvent", "getKey", 1}, // 2865 + {wxStyledTextEvent_GetModifiers, "wxStyledTextEvent", "getModifiers", 1}, // 2866 + {wxStyledTextEvent_GetModificationType, "wxStyledTextEvent", "getModificationType", 1}, // 2867 + {wxStyledTextEvent_GetText, "wxStyledTextEvent", "getText", 1}, // 2868 + {wxStyledTextEvent_GetLength, "wxStyledTextEvent", "getLength", 1}, // 2869 + {wxStyledTextEvent_GetLinesAdded, "wxStyledTextEvent", "getLinesAdded", 1}, // 2870 + {wxStyledTextEvent_GetLine, "wxStyledTextEvent", "getLine", 1}, // 2871 + {wxStyledTextEvent_GetFoldLevelNow, "wxStyledTextEvent", "getFoldLevelNow", 1}, // 2872 + {wxStyledTextEvent_GetFoldLevelPrev, "wxStyledTextEvent", "getFoldLevelPrev", 1}, // 2873 + {wxStyledTextEvent_GetMargin, "wxStyledTextEvent", "getMargin", 1}, // 2874 + {wxStyledTextEvent_GetMessage, "wxStyledTextEvent", "getMessage", 1}, // 2875 + {wxStyledTextEvent_GetWParam, "wxStyledTextEvent", "getWParam", 1}, // 2876 + {wxStyledTextEvent_GetLParam, "wxStyledTextEvent", "getLParam", 1}, // 2877 + {wxStyledTextEvent_GetListType, "wxStyledTextEvent", "getListType", 1}, // 2878 + {wxStyledTextEvent_GetX, "wxStyledTextEvent", "getX", 1}, // 2879 + {wxStyledTextEvent_GetY, "wxStyledTextEvent", "getY", 1}, // 2880 + {wxStyledTextEvent_GetDragText, "wxStyledTextEvent", "getDragText", 1}, // 2881 + {wxStyledTextEvent_GetDragAllowMove, "wxStyledTextEvent", "getDragAllowMove", 1}, // 2882 + {wxStyledTextEvent_GetDragResult, "wxStyledTextEvent", "getDragResult", 1}, // 2883 + {wxStyledTextEvent_GetShift, "wxStyledTextEvent", "getShift", 1}, // 2884 + {wxStyledTextEvent_GetControl, "wxStyledTextEvent", "getControl", 1}, // 2885 + {wxStyledTextEvent_GetAlt, "wxStyledTextEvent", "getAlt", 1}, // 2886 + {utils_wxGetKeyState, "utils", "getKeyState", 1}, // 2887 + {utils_wxGetMousePosition, "utils", "getMousePosition", 0}, // 2888 + {utils_wxGetMouseState, "utils", "getMouseState", 0}, // 2889 + {utils_wxSetDetectableAutoRepeat, "utils", "setDetectableAutoRepeat", 1}, // 2890 + {utils_wxBell, "utils", "bell", 0}, // 2891 + {utils_wxFindMenuItemId, "utils", "findMenuItemId", 3}, // 2892 + {utils_wxFindWindowAtPoint, "utils", "findWindowAtPoint", 1}, // 2893 + {utils_wxBeginBusyCursor, "utils", "beginBusyCursor", 1}, // 2894 + {utils_wxEndBusyCursor, "utils", "endBusyCursor", 0}, // 2895 + {utils_wxIsBusy, "utils", "isBusy", 0}, // 2896 + {utils_wxShutdown, "utils", "shutdown", 1}, // 2897 + {utils_wxShell, "utils", "shell", 1}, // 2898 + {utils_wxLaunchDefaultBrowser, "utils", "launchDefaultBrowser", 2}, // 2899 + {utils_wxGetEmailAddress, "utils", "getEmailAddress", 0}, // 2900 + {utils_wxGetUserId, "utils", "getUserId", 0}, // 2901 + {utils_wxGetHomeDir, "utils", "getHomeDir", 0}, // 2902 + {utils_wxNewId, "utils", "newId", 0}, // 2903 + {utils_wxRegisterId, "utils", "registerId", 1}, // 2904 + {utils_wxGetCurrentId, "utils", "getCurrentId", 0}, // 2905 + {utils_wxGetOsDescription, "utils", "getOsDescription", 0}, // 2906 + {utils_wxIsPlatformLittleEndian, "utils", "isPlatformLittleEndian", 0}, // 2907 + {utils_wxIsPlatform64Bit, "utils", "isPlatform64Bit", 0}, // 2908 + {gdicmn_wxDisplaySize, "gdicmn", "displaySize", 0}, // 2909 + {gdicmn_wxSetCursor, "gdicmn", "setCursor", 1}, // 2910 + {wxPrintout_new, "wxPrintout", "new", 3}, // 2911 + {NULL, "wxPrintout", "destroy", 1}, // 2912 obj destructor wxPrintout_destruct + {wxPrintout_GetDC, "wxPrintout", "getDC", 1}, // 2913 + {wxPrintout_GetPageSizeMM, "wxPrintout", "getPageSizeMM", 1}, // 2914 + {wxPrintout_GetPageSizePixels, "wxPrintout", "getPageSizePixels", 1}, // 2915 + {wxPrintout_GetPaperRectPixels, "wxPrintout", "getPaperRectPixels", 1}, // 2916 + {wxPrintout_GetPPIPrinter, "wxPrintout", "getPPIPrinter", 1}, // 2917 + {wxPrintout_GetPPIScreen, "wxPrintout", "getPPIScreen", 1}, // 2918 + {wxPrintout_GetTitle, "wxPrintout", "getTitle", 1}, // 2919 + {wxPrintout_IsPreview, "wxPrintout", "isPreview", 1}, // 2920 + {wxPrintout_FitThisSizeToPaper, "wxPrintout", "fitThisSizeToPaper", 2}, // 2921 + {wxPrintout_FitThisSizeToPage, "wxPrintout", "fitThisSizeToPage", 2}, // 2922 + {wxPrintout_FitThisSizeToPageMargins, "wxPrintout", "fitThisSizeToPageMargins", 3}, // 2923 + {wxPrintout_MapScreenSizeToPaper, "wxPrintout", "mapScreenSizeToPaper", 1}, // 2924 + {wxPrintout_MapScreenSizeToPage, "wxPrintout", "mapScreenSizeToPage", 1}, // 2925 + {wxPrintout_MapScreenSizeToPageMargins, "wxPrintout", "mapScreenSizeToPageMargins", 2}, // 2926 + {wxPrintout_MapScreenSizeToDevice, "wxPrintout", "mapScreenSizeToDevice", 1}, // 2927 + {wxPrintout_GetLogicalPaperRect, "wxPrintout", "getLogicalPaperRect", 1}, // 2928 + {wxPrintout_GetLogicalPageRect, "wxPrintout", "getLogicalPageRect", 1}, // 2929 + {wxPrintout_GetLogicalPageMarginsRect, "wxPrintout", "getLogicalPageMarginsRect", 2}, // 2930 + {wxPrintout_SetLogicalOrigin, "wxPrintout", "setLogicalOrigin", 3}, // 2931 + {wxPrintout_OffsetLogicalOrigin, "wxPrintout", "offsetLogicalOrigin", 3}, // 2932 + {wxStyledTextCtrl_new_2, "wxStyledTextCtrl", "new", 2}, // 2933 + {wxStyledTextCtrl_new_0, "wxStyledTextCtrl", "new", 0}, // 2934 + {NULL, "wxStyledTextCtrl", "destroy", 1}, // 2935 obj destructor wxStyledTextCtrl_destruct + {wxStyledTextCtrl_Create, "wxStyledTextCtrl", "create", 3}, // 2936 + {wxStyledTextCtrl_AddText, "wxStyledTextCtrl", "addText", 2}, // 2937 + {wxStyledTextCtrl_InsertText, "wxStyledTextCtrl", "insertText", 3}, // 2938 + {wxStyledTextCtrl_ClearAll, "wxStyledTextCtrl", "clearAll", 1}, // 2939 + {wxStyledTextCtrl_ClearDocumentStyle, "wxStyledTextCtrl", "clearDocumentStyle", 1}, // 2940 + {wxStyledTextCtrl_GetLength, "wxStyledTextCtrl", "getLength", 1}, // 2941 + {wxStyledTextCtrl_GetCharAt, "wxStyledTextCtrl", "getCharAt", 2}, // 2942 + {wxStyledTextCtrl_GetCurrentPos, "wxStyledTextCtrl", "getCurrentPos", 1}, // 2943 + {wxStyledTextCtrl_GetAnchor, "wxStyledTextCtrl", "getAnchor", 1}, // 2944 + {wxStyledTextCtrl_GetStyleAt, "wxStyledTextCtrl", "getStyleAt", 2}, // 2945 + {wxStyledTextCtrl_Redo, "wxStyledTextCtrl", "redo", 1}, // 2946 + {wxStyledTextCtrl_SetUndoCollection, "wxStyledTextCtrl", "setUndoCollection", 2}, // 2947 + {wxStyledTextCtrl_SelectAll, "wxStyledTextCtrl", "selectAll", 1}, // 2948 + {wxStyledTextCtrl_SetSavePoint, "wxStyledTextCtrl", "setSavePoint", 1}, // 2949 + {wxStyledTextCtrl_CanRedo, "wxStyledTextCtrl", "canRedo", 1}, // 2950 + {wxStyledTextCtrl_MarkerLineFromHandle, "wxStyledTextCtrl", "markerLineFromHandle", 2}, // 2951 + {wxStyledTextCtrl_MarkerDeleteHandle, "wxStyledTextCtrl", "markerDeleteHandle", 2}, // 2952 + {wxStyledTextCtrl_GetUndoCollection, "wxStyledTextCtrl", "getUndoCollection", 1}, // 2953 + {wxStyledTextCtrl_GetViewWhiteSpace, "wxStyledTextCtrl", "getViewWhiteSpace", 1}, // 2954 + {wxStyledTextCtrl_SetViewWhiteSpace, "wxStyledTextCtrl", "setViewWhiteSpace", 2}, // 2955 + {wxStyledTextCtrl_PositionFromPoint, "wxStyledTextCtrl", "positionFromPoint", 2}, // 2956 + {wxStyledTextCtrl_PositionFromPointClose, "wxStyledTextCtrl", "positionFromPointClose", 3}, // 2957 + {wxStyledTextCtrl_GotoLine, "wxStyledTextCtrl", "gotoLine", 2}, // 2958 + {wxStyledTextCtrl_GotoPos, "wxStyledTextCtrl", "gotoPos", 2}, // 2959 + {wxStyledTextCtrl_SetAnchor, "wxStyledTextCtrl", "setAnchor", 2}, // 2960 + {wxStyledTextCtrl_GetCurLine, "wxStyledTextCtrl", "getCurLine", 1}, // 2961 + {wxStyledTextCtrl_GetEndStyled, "wxStyledTextCtrl", "getEndStyled", 1}, // 2962 + {wxStyledTextCtrl_ConvertEOLs, "wxStyledTextCtrl", "convertEOLs", 2}, // 2963 + {wxStyledTextCtrl_GetEOLMode, "wxStyledTextCtrl", "getEOLMode", 1}, // 2964 + {wxStyledTextCtrl_SetEOLMode, "wxStyledTextCtrl", "setEOLMode", 2}, // 2965 + {wxStyledTextCtrl_StartStyling, "wxStyledTextCtrl", "startStyling", 2}, // 2966 + {wxStyledTextCtrl_SetStyling, "wxStyledTextCtrl", "setStyling", 3}, // 2967 + {wxStyledTextCtrl_GetBufferedDraw, "wxStyledTextCtrl", "getBufferedDraw", 1}, // 2968 + {wxStyledTextCtrl_SetBufferedDraw, "wxStyledTextCtrl", "setBufferedDraw", 2}, // 2969 + {wxStyledTextCtrl_SetTabWidth, "wxStyledTextCtrl", "setTabWidth", 2}, // 2970 + {wxStyledTextCtrl_GetTabWidth, "wxStyledTextCtrl", "getTabWidth", 1}, // 2971 + {wxStyledTextCtrl_SetCodePage, "wxStyledTextCtrl", "setCodePage", 2}, // 2972 + {wxStyledTextCtrl_MarkerDefine, "wxStyledTextCtrl", "markerDefine", 4}, // 2973 + {wxStyledTextCtrl_MarkerSetForeground, "wxStyledTextCtrl", "markerSetForeground", 3}, // 2974 + {wxStyledTextCtrl_MarkerSetBackground, "wxStyledTextCtrl", "markerSetBackground", 3}, // 2975 + {wxStyledTextCtrl_MarkerAdd, "wxStyledTextCtrl", "markerAdd", 3}, // 2976 + {wxStyledTextCtrl_MarkerDelete, "wxStyledTextCtrl", "markerDelete", 3}, // 2977 + {wxStyledTextCtrl_MarkerDeleteAll, "wxStyledTextCtrl", "markerDeleteAll", 2}, // 2978 + {wxStyledTextCtrl_MarkerGet, "wxStyledTextCtrl", "markerGet", 2}, // 2979 + {wxStyledTextCtrl_MarkerNext, "wxStyledTextCtrl", "markerNext", 3}, // 2980 + {wxStyledTextCtrl_MarkerPrevious, "wxStyledTextCtrl", "markerPrevious", 3}, // 2981 + {wxStyledTextCtrl_MarkerDefineBitmap, "wxStyledTextCtrl", "markerDefineBitmap", 3}, // 2982 + {wxStyledTextCtrl_MarkerAddSet, "wxStyledTextCtrl", "markerAddSet", 3}, // 2983 + {wxStyledTextCtrl_MarkerSetAlpha, "wxStyledTextCtrl", "markerSetAlpha", 3}, // 2984 + {wxStyledTextCtrl_SetMarginType, "wxStyledTextCtrl", "setMarginType", 3}, // 2985 + {wxStyledTextCtrl_GetMarginType, "wxStyledTextCtrl", "getMarginType", 2}, // 2986 + {wxStyledTextCtrl_SetMarginWidth, "wxStyledTextCtrl", "setMarginWidth", 3}, // 2987 + {wxStyledTextCtrl_GetMarginWidth, "wxStyledTextCtrl", "getMarginWidth", 2}, // 2988 + {wxStyledTextCtrl_SetMarginMask, "wxStyledTextCtrl", "setMarginMask", 3}, // 2989 + {wxStyledTextCtrl_GetMarginMask, "wxStyledTextCtrl", "getMarginMask", 2}, // 2990 + {wxStyledTextCtrl_SetMarginSensitive, "wxStyledTextCtrl", "setMarginSensitive", 3}, // 2991 + {wxStyledTextCtrl_GetMarginSensitive, "wxStyledTextCtrl", "getMarginSensitive", 2}, // 2992 + {wxStyledTextCtrl_StyleClearAll, "wxStyledTextCtrl", "styleClearAll", 1}, // 2993 + {wxStyledTextCtrl_StyleSetForeground, "wxStyledTextCtrl", "styleSetForeground", 3}, // 2994 + {wxStyledTextCtrl_StyleSetBackground, "wxStyledTextCtrl", "styleSetBackground", 3}, // 2995 + {wxStyledTextCtrl_StyleSetBold, "wxStyledTextCtrl", "styleSetBold", 3}, // 2996 + {wxStyledTextCtrl_StyleSetItalic, "wxStyledTextCtrl", "styleSetItalic", 3}, // 2997 + {wxStyledTextCtrl_StyleSetSize, "wxStyledTextCtrl", "styleSetSize", 3}, // 2998 + {wxStyledTextCtrl_StyleSetFaceName, "wxStyledTextCtrl", "styleSetFaceName", 3}, // 2999 + {wxStyledTextCtrl_StyleSetEOLFilled, "wxStyledTextCtrl", "styleSetEOLFilled", 3}, // 3000 + {wxStyledTextCtrl_StyleResetDefault, "wxStyledTextCtrl", "styleResetDefault", 1}, // 3001 + {wxStyledTextCtrl_StyleSetUnderline, "wxStyledTextCtrl", "styleSetUnderline", 3}, // 3002 + {wxStyledTextCtrl_StyleSetCase, "wxStyledTextCtrl", "styleSetCase", 3}, // 3003 + {wxStyledTextCtrl_StyleSetHotSpot, "wxStyledTextCtrl", "styleSetHotSpot", 3}, // 3004 + {wxStyledTextCtrl_SetSelForeground, "wxStyledTextCtrl", "setSelForeground", 3}, // 3005 + {wxStyledTextCtrl_SetSelBackground, "wxStyledTextCtrl", "setSelBackground", 3}, // 3006 + {wxStyledTextCtrl_GetSelAlpha, "wxStyledTextCtrl", "getSelAlpha", 1}, // 3007 + {wxStyledTextCtrl_SetSelAlpha, "wxStyledTextCtrl", "setSelAlpha", 2}, // 3008 + {wxStyledTextCtrl_SetCaretForeground, "wxStyledTextCtrl", "setCaretForeground", 2}, // 3009 + {wxStyledTextCtrl_CmdKeyAssign, "wxStyledTextCtrl", "cmdKeyAssign", 4}, // 3010 + {wxStyledTextCtrl_CmdKeyClear, "wxStyledTextCtrl", "cmdKeyClear", 3}, // 3011 + {wxStyledTextCtrl_CmdKeyClearAll, "wxStyledTextCtrl", "cmdKeyClearAll", 1}, // 3012 + {wxStyledTextCtrl_SetStyleBytes, "wxStyledTextCtrl", "setStyleBytes", 2}, // 3013 + {wxStyledTextCtrl_StyleSetVisible, "wxStyledTextCtrl", "styleSetVisible", 3}, // 3014 + {wxStyledTextCtrl_GetCaretPeriod, "wxStyledTextCtrl", "getCaretPeriod", 1}, // 3015 + {wxStyledTextCtrl_SetCaretPeriod, "wxStyledTextCtrl", "setCaretPeriod", 2}, // 3016 + {wxStyledTextCtrl_SetWordChars, "wxStyledTextCtrl", "setWordChars", 2}, // 3017 + {wxStyledTextCtrl_BeginUndoAction, "wxStyledTextCtrl", "beginUndoAction", 1}, // 3018 + {wxStyledTextCtrl_EndUndoAction, "wxStyledTextCtrl", "endUndoAction", 1}, // 3019 + {wxStyledTextCtrl_IndicatorSetStyle, "wxStyledTextCtrl", "indicatorSetStyle", 3}, // 3020 + {wxStyledTextCtrl_IndicatorGetStyle, "wxStyledTextCtrl", "indicatorGetStyle", 2}, // 3021 + {wxStyledTextCtrl_IndicatorSetForeground, "wxStyledTextCtrl", "indicatorSetForeground", 3}, // 3022 + {wxStyledTextCtrl_IndicatorGetForeground, "wxStyledTextCtrl", "indicatorGetForeground", 2}, // 3023 + {wxStyledTextCtrl_SetWhitespaceForeground, "wxStyledTextCtrl", "setWhitespaceForeground", 3}, // 3024 + {wxStyledTextCtrl_SetWhitespaceBackground, "wxStyledTextCtrl", "setWhitespaceBackground", 3}, // 3025 + {wxStyledTextCtrl_GetStyleBits, "wxStyledTextCtrl", "getStyleBits", 1}, // 3026 + {wxStyledTextCtrl_SetLineState, "wxStyledTextCtrl", "setLineState", 3}, // 3027 + {wxStyledTextCtrl_GetLineState, "wxStyledTextCtrl", "getLineState", 2}, // 3028 + {wxStyledTextCtrl_GetMaxLineState, "wxStyledTextCtrl", "getMaxLineState", 1}, // 3029 + {wxStyledTextCtrl_GetCaretLineVisible, "wxStyledTextCtrl", "getCaretLineVisible", 1}, // 3030 + {wxStyledTextCtrl_SetCaretLineVisible, "wxStyledTextCtrl", "setCaretLineVisible", 2}, // 3031 + {wxStyledTextCtrl_GetCaretLineBackground, "wxStyledTextCtrl", "getCaretLineBackground", 1}, // 3032 + {wxStyledTextCtrl_SetCaretLineBackground, "wxStyledTextCtrl", "setCaretLineBackground", 2}, // 3033 + {wxStyledTextCtrl_AutoCompShow, "wxStyledTextCtrl", "autoCompShow", 3}, // 3034 + {wxStyledTextCtrl_AutoCompCancel, "wxStyledTextCtrl", "autoCompCancel", 1}, // 3035 + {wxStyledTextCtrl_AutoCompActive, "wxStyledTextCtrl", "autoCompActive", 1}, // 3036 + {wxStyledTextCtrl_AutoCompPosStart, "wxStyledTextCtrl", "autoCompPosStart", 1}, // 3037 + {wxStyledTextCtrl_AutoCompComplete, "wxStyledTextCtrl", "autoCompComplete", 1}, // 3038 + {wxStyledTextCtrl_AutoCompStops, "wxStyledTextCtrl", "autoCompStops", 2}, // 3039 + {wxStyledTextCtrl_AutoCompSetSeparator, "wxStyledTextCtrl", "autoCompSetSeparator", 2}, // 3040 + {wxStyledTextCtrl_AutoCompGetSeparator, "wxStyledTextCtrl", "autoCompGetSeparator", 1}, // 3041 + {wxStyledTextCtrl_AutoCompSelect, "wxStyledTextCtrl", "autoCompSelect", 2}, // 3042 + {wxStyledTextCtrl_AutoCompSetCancelAtStart, "wxStyledTextCtrl", "autoCompSetCancelAtStart", 2}, // 3043 + {wxStyledTextCtrl_AutoCompGetCancelAtStart, "wxStyledTextCtrl", "autoCompGetCancelAtStart", 1}, // 3044 + {wxStyledTextCtrl_AutoCompSetFillUps, "wxStyledTextCtrl", "autoCompSetFillUps", 2}, // 3045 + {wxStyledTextCtrl_AutoCompSetChooseSingle, "wxStyledTextCtrl", "autoCompSetChooseSingle", 2}, // 3046 + {wxStyledTextCtrl_AutoCompGetChooseSingle, "wxStyledTextCtrl", "autoCompGetChooseSingle", 1}, // 3047 + {wxStyledTextCtrl_AutoCompSetIgnoreCase, "wxStyledTextCtrl", "autoCompSetIgnoreCase", 2}, // 3048 + {wxStyledTextCtrl_AutoCompGetIgnoreCase, "wxStyledTextCtrl", "autoCompGetIgnoreCase", 1}, // 3049 + {wxStyledTextCtrl_UserListShow, "wxStyledTextCtrl", "userListShow", 3}, // 3050 + {wxStyledTextCtrl_AutoCompSetAutoHide, "wxStyledTextCtrl", "autoCompSetAutoHide", 2}, // 3051 + {wxStyledTextCtrl_AutoCompGetAutoHide, "wxStyledTextCtrl", "autoCompGetAutoHide", 1}, // 3052 + {wxStyledTextCtrl_AutoCompSetDropRestOfWord, "wxStyledTextCtrl", "autoCompSetDropRestOfWord", 2}, // 3053 + {wxStyledTextCtrl_AutoCompGetDropRestOfWord, "wxStyledTextCtrl", "autoCompGetDropRestOfWord", 1}, // 3054 + {wxStyledTextCtrl_RegisterImage, "wxStyledTextCtrl", "registerImage", 3}, // 3055 + {wxStyledTextCtrl_ClearRegisteredImages, "wxStyledTextCtrl", "clearRegisteredImages", 1}, // 3056 + {wxStyledTextCtrl_AutoCompGetTypeSeparator, "wxStyledTextCtrl", "autoCompGetTypeSeparator", 1}, // 3057 + {wxStyledTextCtrl_AutoCompSetTypeSeparator, "wxStyledTextCtrl", "autoCompSetTypeSeparator", 2}, // 3058 + {wxStyledTextCtrl_AutoCompSetMaxWidth, "wxStyledTextCtrl", "autoCompSetMaxWidth", 2}, // 3059 + {wxStyledTextCtrl_AutoCompGetMaxWidth, "wxStyledTextCtrl", "autoCompGetMaxWidth", 1}, // 3060 + {wxStyledTextCtrl_AutoCompSetMaxHeight, "wxStyledTextCtrl", "autoCompSetMaxHeight", 2}, // 3061 + {wxStyledTextCtrl_AutoCompGetMaxHeight, "wxStyledTextCtrl", "autoCompGetMaxHeight", 1}, // 3062 + {wxStyledTextCtrl_SetIndent, "wxStyledTextCtrl", "setIndent", 2}, // 3063 + {wxStyledTextCtrl_GetIndent, "wxStyledTextCtrl", "getIndent", 1}, // 3064 + {wxStyledTextCtrl_SetUseTabs, "wxStyledTextCtrl", "setUseTabs", 2}, // 3065 + {wxStyledTextCtrl_GetUseTabs, "wxStyledTextCtrl", "getUseTabs", 1}, // 3066 + {wxStyledTextCtrl_SetLineIndentation, "wxStyledTextCtrl", "setLineIndentation", 3}, // 3067 + {wxStyledTextCtrl_GetLineIndentation, "wxStyledTextCtrl", "getLineIndentation", 2}, // 3068 + {wxStyledTextCtrl_GetLineIndentPosition, "wxStyledTextCtrl", "getLineIndentPosition", 2}, // 3069 + {wxStyledTextCtrl_GetColumn, "wxStyledTextCtrl", "getColumn", 2}, // 3070 + {wxStyledTextCtrl_SetUseHorizontalScrollBar, "wxStyledTextCtrl", "setUseHorizontalScrollBar", 2}, // 3071 + {wxStyledTextCtrl_GetUseHorizontalScrollBar, "wxStyledTextCtrl", "getUseHorizontalScrollBar", 1}, // 3072 + {wxStyledTextCtrl_SetIndentationGuides, "wxStyledTextCtrl", "setIndentationGuides", 2}, // 3073 + {wxStyledTextCtrl_GetIndentationGuides, "wxStyledTextCtrl", "getIndentationGuides", 1}, // 3074 + {wxStyledTextCtrl_SetHighlightGuide, "wxStyledTextCtrl", "setHighlightGuide", 2}, // 3075 + {wxStyledTextCtrl_GetHighlightGuide, "wxStyledTextCtrl", "getHighlightGuide", 1}, // 3076 + {wxStyledTextCtrl_GetLineEndPosition, "wxStyledTextCtrl", "getLineEndPosition", 2}, // 3077 + {wxStyledTextCtrl_GetCodePage, "wxStyledTextCtrl", "getCodePage", 1}, // 3078 + {wxStyledTextCtrl_GetCaretForeground, "wxStyledTextCtrl", "getCaretForeground", 1}, // 3079 + {wxStyledTextCtrl_GetReadOnly, "wxStyledTextCtrl", "getReadOnly", 1}, // 3080 + {wxStyledTextCtrl_SetCurrentPos, "wxStyledTextCtrl", "setCurrentPos", 2}, // 3081 + {wxStyledTextCtrl_SetSelectionStart, "wxStyledTextCtrl", "setSelectionStart", 2}, // 3082 + {wxStyledTextCtrl_GetSelectionStart, "wxStyledTextCtrl", "getSelectionStart", 1}, // 3083 + {wxStyledTextCtrl_SetSelectionEnd, "wxStyledTextCtrl", "setSelectionEnd", 2}, // 3084 + {wxStyledTextCtrl_GetSelectionEnd, "wxStyledTextCtrl", "getSelectionEnd", 1}, // 3085 + {wxStyledTextCtrl_SetPrintMagnification, "wxStyledTextCtrl", "setPrintMagnification", 2}, // 3086 + {wxStyledTextCtrl_GetPrintMagnification, "wxStyledTextCtrl", "getPrintMagnification", 1}, // 3087 + {wxStyledTextCtrl_SetPrintColourMode, "wxStyledTextCtrl", "setPrintColourMode", 2}, // 3088 + {wxStyledTextCtrl_GetPrintColourMode, "wxStyledTextCtrl", "getPrintColourMode", 1}, // 3089 + {wxStyledTextCtrl_FindText, "wxStyledTextCtrl", "findText", 5}, // 3090 + {wxStyledTextCtrl_FormatRange, "wxStyledTextCtrl", "formatRange", 8}, // 3091 + {wxStyledTextCtrl_GetFirstVisibleLine, "wxStyledTextCtrl", "getFirstVisibleLine", 1}, // 3092 + {wxStyledTextCtrl_GetLine, "wxStyledTextCtrl", "getLine", 2}, // 3093 + {wxStyledTextCtrl_GetLineCount, "wxStyledTextCtrl", "getLineCount", 1}, // 3094 + {wxStyledTextCtrl_SetMarginLeft, "wxStyledTextCtrl", "setMarginLeft", 2}, // 3095 + {wxStyledTextCtrl_GetMarginLeft, "wxStyledTextCtrl", "getMarginLeft", 1}, // 3096 + {wxStyledTextCtrl_SetMarginRight, "wxStyledTextCtrl", "setMarginRight", 2}, // 3097 + {wxStyledTextCtrl_GetMarginRight, "wxStyledTextCtrl", "getMarginRight", 1}, // 3098 + {wxStyledTextCtrl_GetModify, "wxStyledTextCtrl", "getModify", 1}, // 3099 + {wxStyledTextCtrl_SetSelection, "wxStyledTextCtrl", "setSelection", 3}, // 3100 + {wxStyledTextCtrl_GetSelectedText, "wxStyledTextCtrl", "getSelectedText", 1}, // 3101 + {wxStyledTextCtrl_GetTextRange, "wxStyledTextCtrl", "getTextRange", 3}, // 3102 + {wxStyledTextCtrl_HideSelection, "wxStyledTextCtrl", "hideSelection", 2}, // 3103 + {wxStyledTextCtrl_LineFromPosition, "wxStyledTextCtrl", "lineFromPosition", 2}, // 3104 + {wxStyledTextCtrl_PositionFromLine, "wxStyledTextCtrl", "positionFromLine", 2}, // 3105 + {wxStyledTextCtrl_LineScroll, "wxStyledTextCtrl", "lineScroll", 3}, // 3106 + {wxStyledTextCtrl_EnsureCaretVisible, "wxStyledTextCtrl", "ensureCaretVisible", 1}, // 3107 + {wxStyledTextCtrl_ReplaceSelection, "wxStyledTextCtrl", "replaceSelection", 2}, // 3108 + {wxStyledTextCtrl_SetReadOnly, "wxStyledTextCtrl", "setReadOnly", 2}, // 3109 + {wxStyledTextCtrl_CanPaste, "wxStyledTextCtrl", "canPaste", 1}, // 3110 + {wxStyledTextCtrl_CanUndo, "wxStyledTextCtrl", "canUndo", 1}, // 3111 + {wxStyledTextCtrl_EmptyUndoBuffer, "wxStyledTextCtrl", "emptyUndoBuffer", 1}, // 3112 + {wxStyledTextCtrl_Undo, "wxStyledTextCtrl", "undo", 1}, // 3113 + {wxStyledTextCtrl_Cut, "wxStyledTextCtrl", "cut", 1}, // 3114 + {wxStyledTextCtrl_Copy, "wxStyledTextCtrl", "copy", 1}, // 3115 + {wxStyledTextCtrl_Paste, "wxStyledTextCtrl", "paste", 1}, // 3116 + {wxStyledTextCtrl_Clear, "wxStyledTextCtrl", "clear", 1}, // 3117 + {wxStyledTextCtrl_SetText, "wxStyledTextCtrl", "setText", 2}, // 3118 + {wxStyledTextCtrl_GetText, "wxStyledTextCtrl", "getText", 1}, // 3119 + {wxStyledTextCtrl_GetTextLength, "wxStyledTextCtrl", "getTextLength", 1}, // 3120 + {wxStyledTextCtrl_GetOvertype, "wxStyledTextCtrl", "getOvertype", 1}, // 3121 + {wxStyledTextCtrl_SetCaretWidth, "wxStyledTextCtrl", "setCaretWidth", 2}, // 3122 + {wxStyledTextCtrl_GetCaretWidth, "wxStyledTextCtrl", "getCaretWidth", 1}, // 3123 + {wxStyledTextCtrl_SetTargetStart, "wxStyledTextCtrl", "setTargetStart", 2}, // 3124 + {wxStyledTextCtrl_GetTargetStart, "wxStyledTextCtrl", "getTargetStart", 1}, // 3125 + {wxStyledTextCtrl_SetTargetEnd, "wxStyledTextCtrl", "setTargetEnd", 2}, // 3126 + {wxStyledTextCtrl_GetTargetEnd, "wxStyledTextCtrl", "getTargetEnd", 1}, // 3127 + {wxStyledTextCtrl_ReplaceTarget, "wxStyledTextCtrl", "replaceTarget", 2}, // 3128 + {wxStyledTextCtrl_SearchInTarget, "wxStyledTextCtrl", "searchInTarget", 2}, // 3129 + {wxStyledTextCtrl_SetSearchFlags, "wxStyledTextCtrl", "setSearchFlags", 2}, // 3130 + {wxStyledTextCtrl_GetSearchFlags, "wxStyledTextCtrl", "getSearchFlags", 1}, // 3131 + {wxStyledTextCtrl_CallTipShow, "wxStyledTextCtrl", "callTipShow", 3}, // 3132 + {wxStyledTextCtrl_CallTipCancel, "wxStyledTextCtrl", "callTipCancel", 1}, // 3133 + {wxStyledTextCtrl_CallTipActive, "wxStyledTextCtrl", "callTipActive", 1}, // 3134 + {wxStyledTextCtrl_CallTipPosAtStart, "wxStyledTextCtrl", "callTipPosAtStart", 1}, // 3135 + {wxStyledTextCtrl_CallTipSetHighlight, "wxStyledTextCtrl", "callTipSetHighlight", 3}, // 3136 + {wxStyledTextCtrl_CallTipSetBackground, "wxStyledTextCtrl", "callTipSetBackground", 2}, // 3137 + {wxStyledTextCtrl_CallTipSetForeground, "wxStyledTextCtrl", "callTipSetForeground", 2}, // 3138 + {wxStyledTextCtrl_CallTipSetForegroundHighlight, "wxStyledTextCtrl", "callTipSetForegroundHighlight", 2}, // 3139 + {wxStyledTextCtrl_CallTipUseStyle, "wxStyledTextCtrl", "callTipUseStyle", 2}, // 3140 + {wxStyledTextCtrl_VisibleFromDocLine, "wxStyledTextCtrl", "visibleFromDocLine", 2}, // 3141 + {wxStyledTextCtrl_DocLineFromVisible, "wxStyledTextCtrl", "docLineFromVisible", 2}, // 3142 + {wxStyledTextCtrl_WrapCount, "wxStyledTextCtrl", "wrapCount", 2}, // 3143 + {wxStyledTextCtrl_SetFoldLevel, "wxStyledTextCtrl", "setFoldLevel", 3}, // 3144 + {wxStyledTextCtrl_GetFoldLevel, "wxStyledTextCtrl", "getFoldLevel", 2}, // 3145 + {wxStyledTextCtrl_GetLastChild, "wxStyledTextCtrl", "getLastChild", 3}, // 3146 + {wxStyledTextCtrl_GetFoldParent, "wxStyledTextCtrl", "getFoldParent", 2}, // 3147 + {wxStyledTextCtrl_ShowLines, "wxStyledTextCtrl", "showLines", 3}, // 3148 + {wxStyledTextCtrl_HideLines, "wxStyledTextCtrl", "hideLines", 3}, // 3149 + {wxStyledTextCtrl_GetLineVisible, "wxStyledTextCtrl", "getLineVisible", 2}, // 3150 + {wxStyledTextCtrl_SetFoldExpanded, "wxStyledTextCtrl", "setFoldExpanded", 3}, // 3151 + {wxStyledTextCtrl_GetFoldExpanded, "wxStyledTextCtrl", "getFoldExpanded", 2}, // 3152 + {wxStyledTextCtrl_ToggleFold, "wxStyledTextCtrl", "toggleFold", 2}, // 3153 + {wxStyledTextCtrl_EnsureVisible, "wxStyledTextCtrl", "ensureVisible", 2}, // 3154 + {wxStyledTextCtrl_SetFoldFlags, "wxStyledTextCtrl", "setFoldFlags", 2}, // 3155 + {wxStyledTextCtrl_EnsureVisibleEnforcePolicy, "wxStyledTextCtrl", "ensureVisibleEnforcePolicy", 2}, // 3156 + {wxStyledTextCtrl_SetTabIndents, "wxStyledTextCtrl", "setTabIndents", 2}, // 3157 + {wxStyledTextCtrl_GetTabIndents, "wxStyledTextCtrl", "getTabIndents", 1}, // 3158 + {wxStyledTextCtrl_SetBackSpaceUnIndents, "wxStyledTextCtrl", "setBackSpaceUnIndents", 2}, // 3159 + {wxStyledTextCtrl_GetBackSpaceUnIndents, "wxStyledTextCtrl", "getBackSpaceUnIndents", 1}, // 3160 + {wxStyledTextCtrl_SetMouseDwellTime, "wxStyledTextCtrl", "setMouseDwellTime", 2}, // 3161 + {wxStyledTextCtrl_GetMouseDwellTime, "wxStyledTextCtrl", "getMouseDwellTime", 1}, // 3162 + {wxStyledTextCtrl_WordStartPosition, "wxStyledTextCtrl", "wordStartPosition", 3}, // 3163 + {wxStyledTextCtrl_WordEndPosition, "wxStyledTextCtrl", "wordEndPosition", 3}, // 3164 + {wxStyledTextCtrl_SetWrapMode, "wxStyledTextCtrl", "setWrapMode", 2}, // 3165 + {wxStyledTextCtrl_GetWrapMode, "wxStyledTextCtrl", "getWrapMode", 1}, // 3166 + {wxStyledTextCtrl_SetWrapVisualFlags, "wxStyledTextCtrl", "setWrapVisualFlags", 2}, // 3167 + {wxStyledTextCtrl_GetWrapVisualFlags, "wxStyledTextCtrl", "getWrapVisualFlags", 1}, // 3168 + {wxStyledTextCtrl_SetWrapVisualFlagsLocation, "wxStyledTextCtrl", "setWrapVisualFlagsLocation", 2}, // 3169 + {wxStyledTextCtrl_GetWrapVisualFlagsLocation, "wxStyledTextCtrl", "getWrapVisualFlagsLocation", 1}, // 3170 + {wxStyledTextCtrl_SetWrapStartIndent, "wxStyledTextCtrl", "setWrapStartIndent", 2}, // 3171 + {wxStyledTextCtrl_GetWrapStartIndent, "wxStyledTextCtrl", "getWrapStartIndent", 1}, // 3172 + {wxStyledTextCtrl_SetLayoutCache, "wxStyledTextCtrl", "setLayoutCache", 2}, // 3173 + {wxStyledTextCtrl_GetLayoutCache, "wxStyledTextCtrl", "getLayoutCache", 1}, // 3174 + {wxStyledTextCtrl_SetScrollWidth, "wxStyledTextCtrl", "setScrollWidth", 2}, // 3175 + {wxStyledTextCtrl_GetScrollWidth, "wxStyledTextCtrl", "getScrollWidth", 1}, // 3176 + {wxStyledTextCtrl_TextWidth, "wxStyledTextCtrl", "textWidth", 3}, // 3177 + {wxStyledTextCtrl_GetEndAtLastLine, "wxStyledTextCtrl", "getEndAtLastLine", 1}, // 3178 + {wxStyledTextCtrl_TextHeight, "wxStyledTextCtrl", "textHeight", 2}, // 3179 + {wxStyledTextCtrl_SetUseVerticalScrollBar, "wxStyledTextCtrl", "setUseVerticalScrollBar", 2}, // 3180 + {wxStyledTextCtrl_GetUseVerticalScrollBar, "wxStyledTextCtrl", "getUseVerticalScrollBar", 1}, // 3181 + {wxStyledTextCtrl_AppendText, "wxStyledTextCtrl", "appendText", 2}, // 3182 + {wxStyledTextCtrl_GetTwoPhaseDraw, "wxStyledTextCtrl", "getTwoPhaseDraw", 1}, // 3183 + {wxStyledTextCtrl_SetTwoPhaseDraw, "wxStyledTextCtrl", "setTwoPhaseDraw", 2}, // 3184 + {wxStyledTextCtrl_TargetFromSelection, "wxStyledTextCtrl", "targetFromSelection", 1}, // 3185 + {wxStyledTextCtrl_LinesJoin, "wxStyledTextCtrl", "linesJoin", 1}, // 3186 + {wxStyledTextCtrl_LinesSplit, "wxStyledTextCtrl", "linesSplit", 2}, // 3187 + {wxStyledTextCtrl_SetFoldMarginColour, "wxStyledTextCtrl", "setFoldMarginColour", 3}, // 3188 + {wxStyledTextCtrl_SetFoldMarginHiColour, "wxStyledTextCtrl", "setFoldMarginHiColour", 3}, // 3189 + {wxStyledTextCtrl_LineDown, "wxStyledTextCtrl", "lineDown", 1}, // 3190 + {wxStyledTextCtrl_LineDownExtend, "wxStyledTextCtrl", "lineDownExtend", 1}, // 3191 + {wxStyledTextCtrl_LineUp, "wxStyledTextCtrl", "lineUp", 1}, // 3192 + {wxStyledTextCtrl_LineUpExtend, "wxStyledTextCtrl", "lineUpExtend", 1}, // 3193 + {wxStyledTextCtrl_CharLeft, "wxStyledTextCtrl", "charLeft", 1}, // 3194 + {wxStyledTextCtrl_CharLeftExtend, "wxStyledTextCtrl", "charLeftExtend", 1}, // 3195 + {wxStyledTextCtrl_CharRight, "wxStyledTextCtrl", "charRight", 1}, // 3196 + {wxStyledTextCtrl_CharRightExtend, "wxStyledTextCtrl", "charRightExtend", 1}, // 3197 + {wxStyledTextCtrl_WordLeft, "wxStyledTextCtrl", "wordLeft", 1}, // 3198 + {wxStyledTextCtrl_WordLeftExtend, "wxStyledTextCtrl", "wordLeftExtend", 1}, // 3199 + {wxStyledTextCtrl_WordRight, "wxStyledTextCtrl", "wordRight", 1}, // 3200 + {wxStyledTextCtrl_WordRightExtend, "wxStyledTextCtrl", "wordRightExtend", 1}, // 3201 + {wxStyledTextCtrl_Home, "wxStyledTextCtrl", "home", 1}, // 3202 + {wxStyledTextCtrl_HomeExtend, "wxStyledTextCtrl", "homeExtend", 1}, // 3203 + {wxStyledTextCtrl_LineEnd, "wxStyledTextCtrl", "lineEnd", 1}, // 3204 + {wxStyledTextCtrl_LineEndExtend, "wxStyledTextCtrl", "lineEndExtend", 1}, // 3205 + {wxStyledTextCtrl_DocumentStart, "wxStyledTextCtrl", "documentStart", 1}, // 3206 + {wxStyledTextCtrl_DocumentStartExtend, "wxStyledTextCtrl", "documentStartExtend", 1}, // 3207 + {wxStyledTextCtrl_DocumentEnd, "wxStyledTextCtrl", "documentEnd", 1}, // 3208 + {wxStyledTextCtrl_DocumentEndExtend, "wxStyledTextCtrl", "documentEndExtend", 1}, // 3209 + {wxStyledTextCtrl_PageUp, "wxStyledTextCtrl", "pageUp", 1}, // 3210 + {wxStyledTextCtrl_PageUpExtend, "wxStyledTextCtrl", "pageUpExtend", 1}, // 3211 + {wxStyledTextCtrl_PageDown, "wxStyledTextCtrl", "pageDown", 1}, // 3212 + {wxStyledTextCtrl_PageDownExtend, "wxStyledTextCtrl", "pageDownExtend", 1}, // 3213 + {wxStyledTextCtrl_EditToggleOvertype, "wxStyledTextCtrl", "editToggleOvertype", 1}, // 3214 + {wxStyledTextCtrl_Cancel, "wxStyledTextCtrl", "cancel", 1}, // 3215 + {wxStyledTextCtrl_DeleteBack, "wxStyledTextCtrl", "deleteBack", 1}, // 3216 + {wxStyledTextCtrl_Tab, "wxStyledTextCtrl", "tab", 1}, // 3217 + {wxStyledTextCtrl_BackTab, "wxStyledTextCtrl", "backTab", 1}, // 3218 + {wxStyledTextCtrl_NewLine, "wxStyledTextCtrl", "newLine", 1}, // 3219 + {wxStyledTextCtrl_FormFeed, "wxStyledTextCtrl", "formFeed", 1}, // 3220 + {wxStyledTextCtrl_VCHome, "wxStyledTextCtrl", "vCHome", 1}, // 3221 + {wxStyledTextCtrl_VCHomeExtend, "wxStyledTextCtrl", "vCHomeExtend", 1}, // 3222 + {wxStyledTextCtrl_ZoomIn, "wxStyledTextCtrl", "zoomIn", 1}, // 3223 + {wxStyledTextCtrl_ZoomOut, "wxStyledTextCtrl", "zoomOut", 1}, // 3224 + {wxStyledTextCtrl_DelWordLeft, "wxStyledTextCtrl", "delWordLeft", 1}, // 3225 + {wxStyledTextCtrl_DelWordRight, "wxStyledTextCtrl", "delWordRight", 1}, // 3226 + {wxStyledTextCtrl_LineCut, "wxStyledTextCtrl", "lineCut", 1}, // 3227 + {wxStyledTextCtrl_LineDelete, "wxStyledTextCtrl", "lineDelete", 1}, // 3228 + {wxStyledTextCtrl_LineTranspose, "wxStyledTextCtrl", "lineTranspose", 1}, // 3229 + {wxStyledTextCtrl_LineDuplicate, "wxStyledTextCtrl", "lineDuplicate", 1}, // 3230 + {wxStyledTextCtrl_LowerCase, "wxStyledTextCtrl", "lowerCase", 1}, // 3231 + {wxStyledTextCtrl_UpperCase, "wxStyledTextCtrl", "upperCase", 1}, // 3232 + {wxStyledTextCtrl_LineScrollDown, "wxStyledTextCtrl", "lineScrollDown", 1}, // 3233 + {wxStyledTextCtrl_LineScrollUp, "wxStyledTextCtrl", "lineScrollUp", 1}, // 3234 + {wxStyledTextCtrl_DeleteBackNotLine, "wxStyledTextCtrl", "deleteBackNotLine", 1}, // 3235 + {wxStyledTextCtrl_HomeDisplay, "wxStyledTextCtrl", "homeDisplay", 1}, // 3236 + {wxStyledTextCtrl_HomeDisplayExtend, "wxStyledTextCtrl", "homeDisplayExtend", 1}, // 3237 + {wxStyledTextCtrl_LineEndDisplay, "wxStyledTextCtrl", "lineEndDisplay", 1}, // 3238 + {wxStyledTextCtrl_LineEndDisplayExtend, "wxStyledTextCtrl", "lineEndDisplayExtend", 1}, // 3239 + {wxStyledTextCtrl_HomeWrapExtend, "wxStyledTextCtrl", "homeWrapExtend", 1}, // 3240 + {wxStyledTextCtrl_LineEndWrap, "wxStyledTextCtrl", "lineEndWrap", 1}, // 3241 + {wxStyledTextCtrl_LineEndWrapExtend, "wxStyledTextCtrl", "lineEndWrapExtend", 1}, // 3242 + {wxStyledTextCtrl_VCHomeWrap, "wxStyledTextCtrl", "vCHomeWrap", 1}, // 3243 + {wxStyledTextCtrl_VCHomeWrapExtend, "wxStyledTextCtrl", "vCHomeWrapExtend", 1}, // 3244 + {wxStyledTextCtrl_LineCopy, "wxStyledTextCtrl", "lineCopy", 1}, // 3245 + {wxStyledTextCtrl_MoveCaretInsideView, "wxStyledTextCtrl", "moveCaretInsideView", 1}, // 3246 + {wxStyledTextCtrl_LineLength, "wxStyledTextCtrl", "lineLength", 2}, // 3247 + {wxStyledTextCtrl_BraceHighlight, "wxStyledTextCtrl", "braceHighlight", 3}, // 3248 + {wxStyledTextCtrl_BraceBadLight, "wxStyledTextCtrl", "braceBadLight", 2}, // 3249 + {wxStyledTextCtrl_BraceMatch, "wxStyledTextCtrl", "braceMatch", 2}, // 3250 + {wxStyledTextCtrl_GetViewEOL, "wxStyledTextCtrl", "getViewEOL", 1}, // 3251 + {wxStyledTextCtrl_SetViewEOL, "wxStyledTextCtrl", "setViewEOL", 2}, // 3252 + {wxStyledTextCtrl_SetModEventMask, "wxStyledTextCtrl", "setModEventMask", 2}, // 3253 + {wxStyledTextCtrl_GetEdgeColumn, "wxStyledTextCtrl", "getEdgeColumn", 1}, // 3254 + {wxStyledTextCtrl_SetEdgeColumn, "wxStyledTextCtrl", "setEdgeColumn", 2}, // 3255 + {wxStyledTextCtrl_SetEdgeMode, "wxStyledTextCtrl", "setEdgeMode", 2}, // 3256 + {wxStyledTextCtrl_GetEdgeMode, "wxStyledTextCtrl", "getEdgeMode", 1}, // 3257 + {wxStyledTextCtrl_GetEdgeColour, "wxStyledTextCtrl", "getEdgeColour", 1}, // 3258 + {wxStyledTextCtrl_SetEdgeColour, "wxStyledTextCtrl", "setEdgeColour", 2}, // 3259 + {wxStyledTextCtrl_SearchAnchor, "wxStyledTextCtrl", "searchAnchor", 1}, // 3260 + {wxStyledTextCtrl_SearchNext, "wxStyledTextCtrl", "searchNext", 3}, // 3261 + {wxStyledTextCtrl_SearchPrev, "wxStyledTextCtrl", "searchPrev", 3}, // 3262 + {wxStyledTextCtrl_LinesOnScreen, "wxStyledTextCtrl", "linesOnScreen", 1}, // 3263 + {wxStyledTextCtrl_UsePopUp, "wxStyledTextCtrl", "usePopUp", 2}, // 3264 + {wxStyledTextCtrl_SelectionIsRectangle, "wxStyledTextCtrl", "selectionIsRectangle", 1}, // 3265 + {wxStyledTextCtrl_SetZoom, "wxStyledTextCtrl", "setZoom", 2}, // 3266 + {wxStyledTextCtrl_GetZoom, "wxStyledTextCtrl", "getZoom", 1}, // 3267 + {wxStyledTextCtrl_GetModEventMask, "wxStyledTextCtrl", "getModEventMask", 1}, // 3268 + {wxStyledTextCtrl_SetSTCFocus, "wxStyledTextCtrl", "setSTCFocus", 2}, // 3269 + {wxStyledTextCtrl_GetSTCFocus, "wxStyledTextCtrl", "getSTCFocus", 1}, // 3270 + {wxStyledTextCtrl_SetStatus, "wxStyledTextCtrl", "setStatus", 2}, // 3271 + {wxStyledTextCtrl_GetStatus, "wxStyledTextCtrl", "getStatus", 1}, // 3272 + {wxStyledTextCtrl_SetMouseDownCaptures, "wxStyledTextCtrl", "setMouseDownCaptures", 2}, // 3273 + {wxStyledTextCtrl_GetMouseDownCaptures, "wxStyledTextCtrl", "getMouseDownCaptures", 1}, // 3274 + {wxStyledTextCtrl_SetSTCCursor, "wxStyledTextCtrl", "setSTCCursor", 2}, // 3275 + {wxStyledTextCtrl_GetSTCCursor, "wxStyledTextCtrl", "getSTCCursor", 1}, // 3276 + {wxStyledTextCtrl_SetControlCharSymbol, "wxStyledTextCtrl", "setControlCharSymbol", 2}, // 3277 + {wxStyledTextCtrl_GetControlCharSymbol, "wxStyledTextCtrl", "getControlCharSymbol", 1}, // 3278 + {wxStyledTextCtrl_WordPartLeft, "wxStyledTextCtrl", "wordPartLeft", 1}, // 3279 + {wxStyledTextCtrl_WordPartLeftExtend, "wxStyledTextCtrl", "wordPartLeftExtend", 1}, // 3280 + {wxStyledTextCtrl_WordPartRight, "wxStyledTextCtrl", "wordPartRight", 1}, // 3281 + {wxStyledTextCtrl_WordPartRightExtend, "wxStyledTextCtrl", "wordPartRightExtend", 1}, // 3282 + {wxStyledTextCtrl_SetVisiblePolicy, "wxStyledTextCtrl", "setVisiblePolicy", 3}, // 3283 + {wxStyledTextCtrl_DelLineLeft, "wxStyledTextCtrl", "delLineLeft", 1}, // 3284 + {wxStyledTextCtrl_DelLineRight, "wxStyledTextCtrl", "delLineRight", 1}, // 3285 + {wxStyledTextCtrl_GetXOffset, "wxStyledTextCtrl", "getXOffset", 1}, // 3286 + {wxStyledTextCtrl_ChooseCaretX, "wxStyledTextCtrl", "chooseCaretX", 1}, // 3287 + {wxStyledTextCtrl_SetXCaretPolicy, "wxStyledTextCtrl", "setXCaretPolicy", 3}, // 3288 + {wxStyledTextCtrl_SetYCaretPolicy, "wxStyledTextCtrl", "setYCaretPolicy", 3}, // 3289 + {wxStyledTextCtrl_GetPrintWrapMode, "wxStyledTextCtrl", "getPrintWrapMode", 1}, // 3290 + {wxStyledTextCtrl_SetHotspotActiveForeground, "wxStyledTextCtrl", "setHotspotActiveForeground", 3}, // 3291 + {wxStyledTextCtrl_SetHotspotActiveBackground, "wxStyledTextCtrl", "setHotspotActiveBackground", 3}, // 3292 + {wxStyledTextCtrl_SetHotspotActiveUnderline, "wxStyledTextCtrl", "setHotspotActiveUnderline", 2}, // 3293 + {wxStyledTextCtrl_SetHotspotSingleLine, "wxStyledTextCtrl", "setHotspotSingleLine", 2}, // 3294 + {wxStyledTextCtrl_ParaDownExtend, "wxStyledTextCtrl", "paraDownExtend", 1}, // 3295 + {wxStyledTextCtrl_ParaUp, "wxStyledTextCtrl", "paraUp", 1}, // 3296 + {wxStyledTextCtrl_ParaUpExtend, "wxStyledTextCtrl", "paraUpExtend", 1}, // 3297 + {wxStyledTextCtrl_PositionBefore, "wxStyledTextCtrl", "positionBefore", 2}, // 3298 + {wxStyledTextCtrl_PositionAfter, "wxStyledTextCtrl", "positionAfter", 2}, // 3299 + {wxStyledTextCtrl_CopyRange, "wxStyledTextCtrl", "copyRange", 3}, // 3300 + {wxStyledTextCtrl_CopyText, "wxStyledTextCtrl", "copyText", 3}, // 3301 + {wxStyledTextCtrl_SetSelectionMode, "wxStyledTextCtrl", "setSelectionMode", 2}, // 3302 + {wxStyledTextCtrl_GetSelectionMode, "wxStyledTextCtrl", "getSelectionMode", 1}, // 3303 + {wxStyledTextCtrl_LineDownRectExtend, "wxStyledTextCtrl", "lineDownRectExtend", 1}, // 3304 + {wxStyledTextCtrl_LineUpRectExtend, "wxStyledTextCtrl", "lineUpRectExtend", 1}, // 3305 + {wxStyledTextCtrl_CharLeftRectExtend, "wxStyledTextCtrl", "charLeftRectExtend", 1}, // 3306 + {wxStyledTextCtrl_CharRightRectExtend, "wxStyledTextCtrl", "charRightRectExtend", 1}, // 3307 + {wxStyledTextCtrl_HomeRectExtend, "wxStyledTextCtrl", "homeRectExtend", 1}, // 3308 + {wxStyledTextCtrl_VCHomeRectExtend, "wxStyledTextCtrl", "vCHomeRectExtend", 1}, // 3309 + {wxStyledTextCtrl_LineEndRectExtend, "wxStyledTextCtrl", "lineEndRectExtend", 1}, // 3310 + {wxStyledTextCtrl_PageUpRectExtend, "wxStyledTextCtrl", "pageUpRectExtend", 1}, // 3311 + {wxStyledTextCtrl_PageDownRectExtend, "wxStyledTextCtrl", "pageDownRectExtend", 1}, // 3312 + {wxStyledTextCtrl_StutteredPageUp, "wxStyledTextCtrl", "stutteredPageUp", 1}, // 3313 + {wxStyledTextCtrl_StutteredPageUpExtend, "wxStyledTextCtrl", "stutteredPageUpExtend", 1}, // 3314 + {wxStyledTextCtrl_StutteredPageDown, "wxStyledTextCtrl", "stutteredPageDown", 1}, // 3315 + {wxStyledTextCtrl_StutteredPageDownExtend, "wxStyledTextCtrl", "stutteredPageDownExtend", 1}, // 3316 + {wxStyledTextCtrl_WordLeftEnd, "wxStyledTextCtrl", "wordLeftEnd", 1}, // 3317 + {wxStyledTextCtrl_WordLeftEndExtend, "wxStyledTextCtrl", "wordLeftEndExtend", 1}, // 3318 + {wxStyledTextCtrl_WordRightEnd, "wxStyledTextCtrl", "wordRightEnd", 1}, // 3319 + {wxStyledTextCtrl_WordRightEndExtend, "wxStyledTextCtrl", "wordRightEndExtend", 1}, // 3320 + {wxStyledTextCtrl_SetWhitespaceChars, "wxStyledTextCtrl", "setWhitespaceChars", 2}, // 3321 + {wxStyledTextCtrl_SetCharsDefault, "wxStyledTextCtrl", "setCharsDefault", 1}, // 3322 + {wxStyledTextCtrl_AutoCompGetCurrent, "wxStyledTextCtrl", "autoCompGetCurrent", 1}, // 3323 + {wxStyledTextCtrl_Allocate, "wxStyledTextCtrl", "allocate", 2}, // 3324 + {wxStyledTextCtrl_FindColumn, "wxStyledTextCtrl", "findColumn", 3}, // 3325 + {wxStyledTextCtrl_GetCaretSticky, "wxStyledTextCtrl", "getCaretSticky", 1}, // 3326 + {wxStyledTextCtrl_SetCaretSticky, "wxStyledTextCtrl", "setCaretSticky", 2}, // 3327 + {wxStyledTextCtrl_ToggleCaretSticky, "wxStyledTextCtrl", "toggleCaretSticky", 1}, // 3328 + {wxStyledTextCtrl_SetPasteConvertEndings, "wxStyledTextCtrl", "setPasteConvertEndings", 2}, // 3329 + {wxStyledTextCtrl_GetPasteConvertEndings, "wxStyledTextCtrl", "getPasteConvertEndings", 1}, // 3330 + {wxStyledTextCtrl_SelectionDuplicate, "wxStyledTextCtrl", "selectionDuplicate", 1}, // 3331 + {wxStyledTextCtrl_SetCaretLineBackAlpha, "wxStyledTextCtrl", "setCaretLineBackAlpha", 2}, // 3332 + {wxStyledTextCtrl_GetCaretLineBackAlpha, "wxStyledTextCtrl", "getCaretLineBackAlpha", 1}, // 3333 + {wxStyledTextCtrl_StartRecord, "wxStyledTextCtrl", "startRecord", 1}, // 3334 + {wxStyledTextCtrl_StopRecord, "wxStyledTextCtrl", "stopRecord", 1}, // 3335 + {wxStyledTextCtrl_SetLexer, "wxStyledTextCtrl", "setLexer", 2}, // 3336 + {wxStyledTextCtrl_GetLexer, "wxStyledTextCtrl", "getLexer", 1}, // 3337 + {wxStyledTextCtrl_Colourise, "wxStyledTextCtrl", "colourise", 3}, // 3338 + {wxStyledTextCtrl_SetProperty, "wxStyledTextCtrl", "setProperty", 3}, // 3339 + {wxStyledTextCtrl_SetKeyWords, "wxStyledTextCtrl", "setKeyWords", 3}, // 3340 + {wxStyledTextCtrl_SetLexerLanguage, "wxStyledTextCtrl", "setLexerLanguage", 2}, // 3341 + {wxStyledTextCtrl_GetProperty, "wxStyledTextCtrl", "getProperty", 2}, // 3342 + {wxStyledTextCtrl_GetStyleBitsNeeded, "wxStyledTextCtrl", "getStyleBitsNeeded", 1}, // 3343 + {wxStyledTextCtrl_GetCurrentLine, "wxStyledTextCtrl", "getCurrentLine", 1}, // 3344 + {wxStyledTextCtrl_StyleSetSpec, "wxStyledTextCtrl", "styleSetSpec", 3}, // 3345 + {wxStyledTextCtrl_StyleSetFont, "wxStyledTextCtrl", "styleSetFont", 3}, // 3346 + {wxStyledTextCtrl_StyleSetFontAttr, "wxStyledTextCtrl", "styleSetFontAttr", 8}, // 3347 + {wxStyledTextCtrl_StyleSetCharacterSet, "wxStyledTextCtrl", "styleSetCharacterSet", 3}, // 3348 + {wxStyledTextCtrl_StyleSetFontEncoding, "wxStyledTextCtrl", "styleSetFontEncoding", 3}, // 3349 + {wxStyledTextCtrl_CmdKeyExecute, "wxStyledTextCtrl", "cmdKeyExecute", 2}, // 3350 + {wxStyledTextCtrl_SetMargins, "wxStyledTextCtrl", "setMargins", 3}, // 3351 + {wxStyledTextCtrl_GetSelection, "wxStyledTextCtrl", "getSelection", 1}, // 3352 + {wxStyledTextCtrl_PointFromPosition, "wxStyledTextCtrl", "pointFromPosition", 2}, // 3353 + {wxStyledTextCtrl_ScrollToLine, "wxStyledTextCtrl", "scrollToLine", 2}, // 3354 + {wxStyledTextCtrl_ScrollToColumn, "wxStyledTextCtrl", "scrollToColumn", 2}, // 3355 + {wxStyledTextCtrl_SetVScrollBar, "wxStyledTextCtrl", "setVScrollBar", 2}, // 3356 + {wxStyledTextCtrl_SetHScrollBar, "wxStyledTextCtrl", "setHScrollBar", 2}, // 3357 + {wxStyledTextCtrl_GetLastKeydownProcessed, "wxStyledTextCtrl", "getLastKeydownProcessed", 1}, // 3358 + {wxStyledTextCtrl_SetLastKeydownProcessed, "wxStyledTextCtrl", "setLastKeydownProcessed", 2}, // 3359 + {wxStyledTextCtrl_SaveFile, "wxStyledTextCtrl", "saveFile", 2}, // 3360 + {wxStyledTextCtrl_LoadFile, "wxStyledTextCtrl", "loadFile", 2}, // 3361 + {wxStyledTextCtrl_DoDragOver, "wxStyledTextCtrl", "doDragOver", 4}, // 3362 + {wxStyledTextCtrl_DoDropText, "wxStyledTextCtrl", "doDropText", 4}, // 3363 + {wxStyledTextCtrl_GetUseAntiAliasing, "wxStyledTextCtrl", "getUseAntiAliasing", 1}, // 3364 + {wxStyledTextCtrl_AddTextRaw, "wxStyledTextCtrl", "addTextRaw", 3}, // 3365 + {wxStyledTextCtrl_InsertTextRaw, "wxStyledTextCtrl", "insertTextRaw", 3}, // 3366 + {wxStyledTextCtrl_GetCurLineRaw, "wxStyledTextCtrl", "getCurLineRaw", 1}, // 3367 + {wxStyledTextCtrl_GetLineRaw, "wxStyledTextCtrl", "getLineRaw", 2}, // 3368 + {wxStyledTextCtrl_GetSelectedTextRaw, "wxStyledTextCtrl", "getSelectedTextRaw", 1}, // 3369 + {wxStyledTextCtrl_GetTextRangeRaw, "wxStyledTextCtrl", "getTextRangeRaw", 3}, // 3370 + {wxStyledTextCtrl_SetTextRaw, "wxStyledTextCtrl", "setTextRaw", 2}, // 3371 + {wxStyledTextCtrl_GetTextRaw, "wxStyledTextCtrl", "getTextRaw", 1}, // 3372 + {wxStyledTextCtrl_AppendTextRaw, "wxStyledTextCtrl", "appendTextRaw", 3}, // 3373 + {wxArtProvider_GetBitmap, "wxArtProvider", "getBitmap", 2}, // 3374 + {wxArtProvider_GetIcon, "wxArtProvider", "getIcon", 2}, // 3375 + {wxTreeEvent_GetKeyCode, "wxTreeEvent", "getKeyCode", 1}, // 3376 + {wxTreeEvent_GetItem, "wxTreeEvent", "getItem", 1}, // 3377 + {wxTreeEvent_GetKeyEvent, "wxTreeEvent", "getKeyEvent", 1}, // 3378 + {wxTreeEvent_GetLabel, "wxTreeEvent", "getLabel", 1}, // 3379 + {wxTreeEvent_GetOldItem, "wxTreeEvent", "getOldItem", 1}, // 3380 + {wxTreeEvent_GetPoint, "wxTreeEvent", "getPoint", 1}, // 3381 + {wxTreeEvent_IsEditCancelled, "wxTreeEvent", "isEditCancelled", 1}, // 3382 + {wxTreeEvent_SetToolTip, "wxTreeEvent", "setToolTip", 2}, // 3383 + {wxBookCtrlEvent_GetOldSelection, "wxBookCtrlEvent", "getOldSelection", 1}, // 3384 + {wxBookCtrlEvent_GetSelection, "wxBookCtrlEvent", "getSelection", 1}, // 3385 + {wxBookCtrlEvent_SetOldSelection, "wxBookCtrlEvent", "setOldSelection", 2}, // 3386 + {wxBookCtrlEvent_SetSelection, "wxBookCtrlEvent", "setSelection", 2}, // 3387 + {wxFileDataObject_new, "wxFileDataObject", "new", 0}, // 3388 + {wxFileDataObject_AddFile, "wxFileDataObject", "addFile", 2}, // 3389 + {wxFileDataObject_GetFilenames, "wxFileDataObject", "getFilenames", 1}, // 3390 + {wxFileDataObject_destroy, "wxFileDataObject", "'Destroy'", 1}, // 3391 + {wxTextDataObject_new, "wxTextDataObject", "new", 1}, // 3392 + {wxTextDataObject_GetTextLength, "wxTextDataObject", "getTextLength", 1}, // 3393 + {wxTextDataObject_GetText, "wxTextDataObject", "getText", 1}, // 3394 + {wxTextDataObject_SetText, "wxTextDataObject", "setText", 2}, // 3395 + {wxTextDataObject_destroy, "wxTextDataObject", "'Destroy'", 1}, // 3396 + {wxBitmapDataObject_new_1_1, "wxBitmapDataObject", "new", 1}, // 3397 + {wxBitmapDataObject_new_1_0, "wxBitmapDataObject", "new", 1}, // 3398 + {wxBitmapDataObject_GetBitmap, "wxBitmapDataObject", "getBitmap", 1}, // 3399 + {wxBitmapDataObject_SetBitmap, "wxBitmapDataObject", "setBitmap", 2}, // 3400 + {wxBitmapDataObject_destroy, "wxBitmapDataObject", "'Destroy'", 1}, // 3401 + {wxClipboard_new, "wxClipboard", "new", 0}, // 3402 + {NULL, "wxClipboard", "destroy", 1}, // 3403 obj destructor wxClipboard_destruct + {wxClipboard_AddData, "wxClipboard", "addData", 2}, // 3404 + {wxClipboard_Clear, "wxClipboard", "clear", 1}, // 3405 + {wxClipboard_Close, "wxClipboard", "close", 1}, // 3406 + {wxClipboard_Flush, "wxClipboard", "flush", 1}, // 3407 + {wxClipboard_GetData, "wxClipboard", "getData", 2}, // 3408 + {wxClipboard_IsOpened, "wxClipboard", "isOpened", 1}, // 3409 + {wxClipboard_Open, "wxClipboard", "open", 1}, // 3410 + {wxClipboard_SetData, "wxClipboard", "setData", 2}, // 3411 + {wxClipboard_UsePrimarySelection, "wxClipboard", "usePrimarySelection", 2}, // 3412 + {wxClipboard_IsSupported, "wxClipboard", "isSupported", 2}, // 3413 + {wxClipboard_Get, "wxClipboard", "get", 0}, // 3414 + {wxSpinEvent_GetPosition, "wxSpinEvent", "getPosition", 1}, // 3415 + {wxSpinEvent_SetPosition, "wxSpinEvent", "setPosition", 2}, // 3416 + {wxSplitterWindow_new_0, "wxSplitterWindow", "new", 0}, // 3417 + {wxSplitterWindow_new_2, "wxSplitterWindow", "new", 2}, // 3418 + {NULL, "wxSplitterWindow", "destroy", 1}, // 3419 obj destructor wxSplitterWindow_destruct + {wxSplitterWindow_Create, "wxSplitterWindow", "create", 3}, // 3420 + {wxSplitterWindow_GetMinimumPaneSize, "wxSplitterWindow", "getMinimumPaneSize", 1}, // 3421 + {wxSplitterWindow_GetSashGravity, "wxSplitterWindow", "getSashGravity", 1}, // 3422 + {wxSplitterWindow_GetSashPosition, "wxSplitterWindow", "getSashPosition", 1}, // 3423 + {wxSplitterWindow_GetSplitMode, "wxSplitterWindow", "getSplitMode", 1}, // 3424 + {wxSplitterWindow_GetWindow1, "wxSplitterWindow", "getWindow1", 1}, // 3425 + {wxSplitterWindow_GetWindow2, "wxSplitterWindow", "getWindow2", 1}, // 3426 + {wxSplitterWindow_Initialize, "wxSplitterWindow", "initialize", 2}, // 3427 + {wxSplitterWindow_IsSplit, "wxSplitterWindow", "isSplit", 1}, // 3428 + {wxSplitterWindow_ReplaceWindow, "wxSplitterWindow", "replaceWindow", 3}, // 3429 + {wxSplitterWindow_SetSashGravity, "wxSplitterWindow", "setSashGravity", 2}, // 3430 + {wxSplitterWindow_SetSashPosition, "wxSplitterWindow", "setSashPosition", 3}, // 3431 + {wxSplitterWindow_SetMinimumPaneSize, "wxSplitterWindow", "setMinimumPaneSize", 2}, // 3432 + {wxSplitterWindow_SetSplitMode, "wxSplitterWindow", "setSplitMode", 2}, // 3433 + {wxSplitterWindow_SplitHorizontally, "wxSplitterWindow", "splitHorizontally", 4}, // 3434 + {wxSplitterWindow_SplitVertically, "wxSplitterWindow", "splitVertically", 4}, // 3435 + {wxSplitterWindow_Unsplit, "wxSplitterWindow", "unsplit", 2}, // 3436 + {wxSplitterWindow_UpdateSize, "wxSplitterWindow", "updateSize", 1}, // 3437 + {wxSplitterEvent_GetSashPosition, "wxSplitterEvent", "getSashPosition", 1}, // 3438 + {wxSplitterEvent_GetX, "wxSplitterEvent", "getX", 1}, // 3439 + {wxSplitterEvent_GetY, "wxSplitterEvent", "getY", 1}, // 3440 + {wxSplitterEvent_GetWindowBeingRemoved, "wxSplitterEvent", "getWindowBeingRemoved", 1}, // 3441 + {wxSplitterEvent_SetSashPosition, "wxSplitterEvent", "setSashPosition", 2}, // 3442 + {wxHtmlWindow_new_0, "wxHtmlWindow", "new", 0}, // 3443 + {wxHtmlWindow_new_2, "wxHtmlWindow", "new", 2}, // 3444 + {wxHtmlWindow_AppendToPage, "wxHtmlWindow", "appendToPage", 2}, // 3445 + {wxHtmlWindow_GetOpenedAnchor, "wxHtmlWindow", "getOpenedAnchor", 1}, // 3446 + {wxHtmlWindow_GetOpenedPage, "wxHtmlWindow", "getOpenedPage", 1}, // 3447 + {wxHtmlWindow_GetOpenedPageTitle, "wxHtmlWindow", "getOpenedPageTitle", 1}, // 3448 + {wxHtmlWindow_GetRelatedFrame, "wxHtmlWindow", "getRelatedFrame", 1}, // 3449 + {wxHtmlWindow_HistoryBack, "wxHtmlWindow", "historyBack", 1}, // 3450 + {wxHtmlWindow_HistoryCanBack, "wxHtmlWindow", "historyCanBack", 1}, // 3451 + {wxHtmlWindow_HistoryCanForward, "wxHtmlWindow", "historyCanForward", 1}, // 3452 + {wxHtmlWindow_HistoryClear, "wxHtmlWindow", "historyClear", 1}, // 3453 + {wxHtmlWindow_HistoryForward, "wxHtmlWindow", "historyForward", 1}, // 3454 + {wxHtmlWindow_LoadFile, "wxHtmlWindow", "loadFile", 2}, // 3455 + {wxHtmlWindow_LoadPage, "wxHtmlWindow", "loadPage", 2}, // 3456 + {wxHtmlWindow_SelectAll, "wxHtmlWindow", "selectAll", 1}, // 3457 + {wxHtmlWindow_SelectionToText, "wxHtmlWindow", "selectionToText", 1}, // 3458 + {wxHtmlWindow_SelectLine, "wxHtmlWindow", "selectLine", 2}, // 3459 + {wxHtmlWindow_SelectWord, "wxHtmlWindow", "selectWord", 2}, // 3460 + {wxHtmlWindow_SetBorders, "wxHtmlWindow", "setBorders", 2}, // 3461 + {wxHtmlWindow_SetFonts, "wxHtmlWindow", "setFonts", 4}, // 3462 + {wxHtmlWindow_SetPage, "wxHtmlWindow", "setPage", 2}, // 3463 + {wxHtmlWindow_SetRelatedFrame, "wxHtmlWindow", "setRelatedFrame", 3}, // 3464 + {wxHtmlWindow_SetRelatedStatusBar_1, "wxHtmlWindow", "setRelatedStatusBar", 2}, // 3465 + {wxHtmlWindow_SetRelatedStatusBar_2, "wxHtmlWindow", "setRelatedStatusBar", 3}, // 3466 + {wxHtmlWindow_ToText, "wxHtmlWindow", "toText", 1}, // 3467 + {NULL, "wxHtmlWindow", "'Destroy'", 1}, // 3468 obj destructor wxHtmlWindow_destroy + {wxHtmlLinkEvent_GetLinkInfo, "wxHtmlLinkEvent", "getLinkInfo", 1}, // 3469 + {wxSystemSettings_GetColour, "wxSystemSettings", "getColour", 1}, // 3470 + {wxSystemSettings_GetFont, "wxSystemSettings", "getFont", 1}, // 3471 + {wxSystemSettings_GetMetric, "wxSystemSettings", "getMetric", 2}, // 3472 + {wxSystemSettings_GetScreenType, "wxSystemSettings", "getScreenType", 0}, // 3473 + {wxSystemOptions_GetOption, "wxSystemOptions", "getOption", 1}, // 3474 + {wxSystemOptions_GetOptionInt, "wxSystemOptions", "getOptionInt", 1}, // 3475 + {wxSystemOptions_HasOption, "wxSystemOptions", "hasOption", 1}, // 3476 + {wxSystemOptions_IsFalse, "wxSystemOptions", "isFalse", 1}, // 3477 + {wxSystemOptions_SetOption_2_1, "wxSystemOptions", "setOption", 2}, // 3478 + {wxSystemOptions_SetOption_2_0, "wxSystemOptions", "setOption", 2}, // 3479 + {wxAuiNotebookEvent_SetSelection, "wxAuiNotebookEvent", "setSelection", 2}, // 3480 + {wxAuiNotebookEvent_GetSelection, "wxAuiNotebookEvent", "getSelection", 1}, // 3481 + {wxAuiNotebookEvent_SetOldSelection, "wxAuiNotebookEvent", "setOldSelection", 2}, // 3482 + {wxAuiNotebookEvent_GetOldSelection, "wxAuiNotebookEvent", "getOldSelection", 1}, // 3483 + {wxAuiNotebookEvent_SetDragSource, "wxAuiNotebookEvent", "setDragSource", 2}, // 3484 + {wxAuiNotebookEvent_GetDragSource, "wxAuiNotebookEvent", "getDragSource", 1}, // 3485 + {wxAuiManagerEvent_SetManager, "wxAuiManagerEvent", "setManager", 2}, // 3486 + {wxAuiManagerEvent_GetManager, "wxAuiManagerEvent", "getManager", 1}, // 3487 + {wxAuiManagerEvent_SetPane, "wxAuiManagerEvent", "setPane", 2}, // 3488 + {wxAuiManagerEvent_GetPane, "wxAuiManagerEvent", "getPane", 1}, // 3489 + {wxAuiManagerEvent_SetButton, "wxAuiManagerEvent", "setButton", 2}, // 3490 + {wxAuiManagerEvent_GetButton, "wxAuiManagerEvent", "getButton", 1}, // 3491 + {wxAuiManagerEvent_SetDC, "wxAuiManagerEvent", "setDC", 2}, // 3492 + {wxAuiManagerEvent_GetDC, "wxAuiManagerEvent", "getDC", 1}, // 3493 + {wxAuiManagerEvent_Veto, "wxAuiManagerEvent", "veto", 2}, // 3494 + {wxAuiManagerEvent_GetVeto, "wxAuiManagerEvent", "getVeto", 1}, // 3495 + {wxAuiManagerEvent_SetCanVeto, "wxAuiManagerEvent", "setCanVeto", 2}, // 3496 + {wxAuiManagerEvent_CanVeto, "wxAuiManagerEvent", "canVeto", 1}, // 3497 + {wxLogNull_new, "wxLogNull", "new", 0}, // 3498 + {wxLogNull_destruct, "wxLogNull", "destroy", 1}, // 3499 + {wxTaskBarIcon_new, "wxTaskBarIcon", "new", 1}, // 3500 + {NULL, "wxTaskBarIcon", "destroy", 1}, // 3501 obj destructor wxTaskBarIcon_destruct + {wxTaskBarIcon_PopupMenu, "wxTaskBarIcon", "popupMenu", 2}, // 3502 + {wxTaskBarIcon_RemoveIcon, "wxTaskBarIcon", "removeIcon", 1}, // 3503 + {wxTaskBarIcon_SetIcon, "wxTaskBarIcon", "setIcon", 3}, // 3504 + {wxLocale_new_0, "wxLocale", "new", 0}, // 3505 + {wxLocale_new_2_0, "wxLocale", "new", 2}, // 3506 + {wxLocale_new_2_1, "wxLocale", "new", 2}, // 3507 + {wxLocale_destruct, "wxLocale", "destroy", 1}, // 3508 + {wxLocale_Init_1, "wxLocale", "init", 2}, // 3509 + {wxLocale_Init_2, "wxLocale", "init", 3}, // 3510 + {wxLocale_AddCatalog_1, "wxLocale", "addCatalog", 2}, // 3511 + {wxLocale_AddCatalog_2, "wxLocale", "addCatalog", 3}, // 3512 + {wxLocale_AddCatalog_3, "wxLocale", "addCatalog", 4}, // 3513 + {wxLocale_AddCatalogLookupPathPrefix, "wxLocale", "addCatalogLookupPathPrefix", 1}, // 3514 + {wxLocale_GetCanonicalName, "wxLocale", "getCanonicalName", 1}, // 3515 + {wxLocale_GetLanguage, "wxLocale", "getLanguage", 1}, // 3516 + {wxLocale_GetLanguageName, "wxLocale", "getLanguageName", 1}, // 3517 + {wxLocale_GetLocale, "wxLocale", "getLocale", 1}, // 3518 + {wxLocale_GetName, "wxLocale", "getName", 1}, // 3519 + {wxLocale_GetString_2, "wxLocale", "getString", 3}, // 3520 + {wxLocale_GetString_4, "wxLocale", "getString", 5}, // 3521 + {wxLocale_GetHeaderValue, "wxLocale", "getHeaderValue", 3}, // 3522 + {wxLocale_GetSysName, "wxLocale", "getSysName", 1}, // 3523 + {wxLocale_GetSystemEncoding, "wxLocale", "getSystemEncoding", 0}, // 3524 + {wxLocale_GetSystemEncodingName, "wxLocale", "getSystemEncodingName", 0}, // 3525 + {wxLocale_GetSystemLanguage, "wxLocale", "getSystemLanguage", 0}, // 3526 + {wxLocale_IsLoaded, "wxLocale", "isLoaded", 2}, // 3527 + {wxLocale_IsOk, "wxLocale", "isOk", 1}, // 3528 + {wxActivateEvent_GetActive, "wxActivateEvent", "getActive", 1}, // 3529 #if wxUSE_POPUPWIN - {wxPopupWindow_new_0, "wxPopupWindow", "new", 0}, // 3519 + {wxPopupWindow_new_0, "wxPopupWindow", "new", 0}, // 3530 #else - {NULL, "wxPopupWindow", "new", 0}, // 3519 + {NULL, "wxPopupWindow", "new", 0}, // 3530 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupWindow_new_2, "wxPopupWindow", "new", 2}, // 3520 + {wxPopupWindow_new_2, "wxPopupWindow", "new", 2}, // 3531 #else - {NULL, "wxPopupWindow", "new", 0}, // 3520 + {NULL, "wxPopupWindow", "new", 0}, // 3531 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupWindow_Create, "wxPopupWindow", "create", 3}, // 3521 + {wxPopupWindow_Create, "wxPopupWindow", "create", 3}, // 3532 #else - {NULL, "wxPopupWindow", "create", 0}, // 3521 + {NULL, "wxPopupWindow", "create", 0}, // 3532 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupWindow_Position, "wxPopupWindow", "position", 3}, // 3522 + {wxPopupWindow_Position, "wxPopupWindow", "position", 3}, // 3533 #else - {NULL, "wxPopupWindow", "position", 0}, // 3522 + {NULL, "wxPopupWindow", "position", 0}, // 3533 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {NULL, "wxPopupWindow", "'Destroy'", 1}, // 3523 obj destructor wxPopupWindow_destroy + {NULL, "wxPopupWindow", "'Destroy'", 1}, // 3534 obj destructor wxPopupWindow_destroy #else - {NULL, "wxPopupWindow", "'Destroy'", 0}, // 3523 + {NULL, "wxPopupWindow", "'Destroy'", 0}, // 3534 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupTransientWindow_new_0, "wxPopupTransientWindow", "new", 0}, // 3524 + {wxPopupTransientWindow_new_0, "wxPopupTransientWindow", "new", 0}, // 3535 #else - {NULL, "wxPopupTransientWindow", "new", 0}, // 3524 + {NULL, "wxPopupTransientWindow", "new", 0}, // 3535 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupTransientWindow_new_2, "wxPopupTransientWindow", "new", 2}, // 3525 + {wxPopupTransientWindow_new_2, "wxPopupTransientWindow", "new", 2}, // 3536 #else - {NULL, "wxPopupTransientWindow", "new", 0}, // 3525 + {NULL, "wxPopupTransientWindow", "new", 0}, // 3536 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupTransientWindow_Popup, "wxPopupTransientWindow", "popup", 2}, // 3526 + {wxPopupTransientWindow_Popup, "wxPopupTransientWindow", "popup", 2}, // 3537 #else - {NULL, "wxPopupTransientWindow", "popup", 0}, // 3526 + {NULL, "wxPopupTransientWindow", "popup", 0}, // 3537 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {wxPopupTransientWindow_Dismiss, "wxPopupTransientWindow", "dismiss", 1}, // 3527 + {wxPopupTransientWindow_Dismiss, "wxPopupTransientWindow", "dismiss", 1}, // 3538 #else - {NULL, "wxPopupTransientWindow", "dismiss", 0}, // 3527 + {NULL, "wxPopupTransientWindow", "dismiss", 0}, // 3538 #endif // wxUSE_POPUPWIN #if wxUSE_POPUPWIN - {NULL, "wxPopupTransientWindow", "'Destroy'", 1}, // 3528 obj destructor wxPopupTransientWindow_destroy + {NULL, "wxPopupTransientWindow", "'Destroy'", 1}, // 3539 obj destructor wxPopupTransientWindow_destroy #else - {NULL, "wxPopupTransientWindow", "'Destroy'", 0}, // 3528 + {NULL, "wxPopupTransientWindow", "'Destroy'", 0}, // 3539 #endif // wxUSE_POPUPWIN - {wxOverlay_new, "wxOverlay", "new", 0}, // 3529 - {wxOverlay_destruct, "wxOverlay", "destroy", 1}, // 3530 - {wxOverlay_Reset, "wxOverlay", "reset", 1}, // 3531 - {wxDCOverlay_new_6, "wxDCOverlay", "new", 6}, // 3532 - {wxDCOverlay_new_2, "wxDCOverlay", "new", 2}, // 3533 - {wxDCOverlay_destruct, "wxDCOverlay", "destroy", 1}, // 3534 - {wxDCOverlay_Clear, "wxDCOverlay", "clear", 1}, // 3535 - {wxDropFilesEvent_GetPosition, "wxDropFilesEvent", "getPosition", 1}, // 3536 - {wxDropFilesEvent_GetNumberOfFiles, "wxDropFilesEvent", "getNumberOfFiles", 1}, // 3537 - {wxDropFilesEvent_GetFiles, "wxDropFilesEvent", "getFiles", 1}, // 3538 + {wxOverlay_new, "wxOverlay", "new", 0}, // 3540 + {wxOverlay_destruct, "wxOverlay", "destroy", 1}, // 3541 + {wxOverlay_Reset, "wxOverlay", "reset", 1}, // 3542 + {wxDCOverlay_new_6, "wxDCOverlay", "new", 6}, // 3543 + {wxDCOverlay_new_2, "wxDCOverlay", "new", 2}, // 3544 + {wxDCOverlay_destruct, "wxDCOverlay", "destroy", 1}, // 3545 + {wxDCOverlay_Clear, "wxDCOverlay", "clear", 1}, // 3546 + {wxDropFilesEvent_GetPosition, "wxDropFilesEvent", "getPosition", 1}, // 3547 + {wxDropFilesEvent_GetNumberOfFiles, "wxDropFilesEvent", "getNumberOfFiles", 1}, // 3548 + {wxDropFilesEvent_GetFiles, "wxDropFilesEvent", "getFiles", 1}, // 3549 #if wxUSE_DISPLAY - {wxDisplay_new_0, "wxDisplay", "new", 0}, // 3539 + {wxDisplay_new_0, "wxDisplay", "new", 0}, // 3550 #else - {NULL, "wxDisplay", "new", 0}, // 3539 + {NULL, "wxDisplay", "new", 0}, // 3550 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_new_1_0, "wxDisplay", "new", 1}, // 3540 + {wxDisplay_new_1_0, "wxDisplay", "new", 1}, // 3551 #else - {NULL, "wxDisplay", "new", 0}, // 3540 + {NULL, "wxDisplay", "new", 0}, // 3551 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY && wxCHECK_VERSION(3,1,3) - {wxDisplay_new_1_1, "wxDisplay", "new", 1}, // 3541 + {wxDisplay_new_1_1, "wxDisplay", "new", 1}, // 3552 #else - {NULL, "wxDisplay", "new", 0}, // 3541 + {NULL, "wxDisplay", "new", 0}, // 3552 #endif // wxUSE_DISPLAY && wxCHECK_VERSION(3,1,3) #if wxUSE_DISPLAY - {wxDisplay_destruct, "wxDisplay", "destroy", 1}, // 3542 + {wxDisplay_destruct, "wxDisplay", "destroy", 1}, // 3553 #else - {NULL, "wxDisplay", "destroy", 0}, // 3542 + {NULL, "wxDisplay", "destroy", 0}, // 3553 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_IsOk, "wxDisplay", "isOk", 1}, // 3543 + {wxDisplay_IsOk, "wxDisplay", "isOk", 1}, // 3554 #else - {NULL, "wxDisplay", "isOk", 0}, // 3543 + {NULL, "wxDisplay", "isOk", 0}, // 3554 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetClientArea, "wxDisplay", "getClientArea", 1}, // 3544 + {wxDisplay_GetClientArea, "wxDisplay", "getClientArea", 1}, // 3555 #else - {NULL, "wxDisplay", "getClientArea", 0}, // 3544 + {NULL, "wxDisplay", "getClientArea", 0}, // 3555 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetGeometry, "wxDisplay", "getGeometry", 1}, // 3545 + {wxDisplay_GetGeometry, "wxDisplay", "getGeometry", 1}, // 3556 #else - {NULL, "wxDisplay", "getGeometry", 0}, // 3545 + {NULL, "wxDisplay", "getGeometry", 0}, // 3556 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetName, "wxDisplay", "getName", 1}, // 3546 + {wxDisplay_GetName, "wxDisplay", "getName", 1}, // 3557 #else - {NULL, "wxDisplay", "getName", 0}, // 3546 + {NULL, "wxDisplay", "getName", 0}, // 3557 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_IsPrimary, "wxDisplay", "isPrimary", 1}, // 3547 + {wxDisplay_IsPrimary, "wxDisplay", "isPrimary", 1}, // 3558 #else - {NULL, "wxDisplay", "isPrimary", 0}, // 3547 + {NULL, "wxDisplay", "isPrimary", 0}, // 3558 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetCount, "wxDisplay", "getCount", 0}, // 3548 + {wxDisplay_GetCount, "wxDisplay", "getCount", 0}, // 3559 #else - {NULL, "wxDisplay", "getCount", 0}, // 3548 + {NULL, "wxDisplay", "getCount", 0}, // 3559 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetFromPoint, "wxDisplay", "getFromPoint", 1}, // 3549 + {wxDisplay_GetFromPoint, "wxDisplay", "getFromPoint", 1}, // 3560 #else - {NULL, "wxDisplay", "getFromPoint", 0}, // 3549 + {NULL, "wxDisplay", "getFromPoint", 0}, // 3560 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY - {wxDisplay_GetFromWindow, "wxDisplay", "getFromWindow", 1}, // 3550 + {wxDisplay_GetFromWindow, "wxDisplay", "getFromWindow", 1}, // 3561 #else - {NULL, "wxDisplay", "getFromWindow", 0}, // 3550 + {NULL, "wxDisplay", "getFromWindow", 0}, // 3561 #endif // wxUSE_DISPLAY #if wxUSE_DISPLAY && wxCHECK_VERSION(3,1,2) - {wxDisplay_GetPPI, "wxDisplay", "getPPI", 1}, // 3551 + {wxDisplay_GetPPI, "wxDisplay", "getPPI", 1}, // 3562 #else - {NULL, "wxDisplay", "getPPI", 0}, // 3551 + {NULL, "wxDisplay", "getPPI", 0}, // 3562 #endif // wxUSE_DISPLAY && wxCHECK_VERSION(3,1,2) #if wxUSE_GRAPHICS_CONTEXT - {wxGCDC_new_1, "wxGCDC", "new", 1}, // 3552 + {wxGCDC_new_1, "wxGCDC", "new", 1}, // 3563 #else - {NULL, "wxGCDC", "new", 0}, // 3552 + {NULL, "wxGCDC", "new", 0}, // 3563 #endif // wxUSE_GRAPHICS_CONTEXT - {NULL, "", "", 0}, // 3553 - {NULL, "", "", 0}, // 3554 + {NULL, "", "", 0}, // 3564 + {NULL, "", "", 0}, // 3565 #if wxUSE_GRAPHICS_CONTEXT - {wxGCDC_new_0, "wxGCDC", "new", 0}, // 3555 + {wxGCDC_new_0, "wxGCDC", "new", 0}, // 3566 #else - {NULL, "wxGCDC", "new", 0}, // 3555 + {NULL, "wxGCDC", "new", 0}, // 3566 #endif // wxUSE_GRAPHICS_CONTEXT #if wxUSE_GRAPHICS_CONTEXT - {NULL, "wxGCDC", "destroy", 1}, // 3556 obj destructor wxGCDC_destruct + {NULL, "wxGCDC", "destroy", 1}, // 3567 obj destructor wxGCDC_destruct #else - {NULL, "wxGCDC", "destroy", 0}, // 3556 + {NULL, "wxGCDC", "destroy", 0}, // 3567 #endif // wxUSE_GRAPHICS_CONTEXT #if wxUSE_GRAPHICS_CONTEXT - {wxGCDC_GetGraphicsContext, "wxGCDC", "getGraphicsContext", 1}, // 3557 + {wxGCDC_GetGraphicsContext, "wxGCDC", "getGraphicsContext", 1}, // 3568 #else - {NULL, "wxGCDC", "getGraphicsContext", 0}, // 3557 + {NULL, "wxGCDC", "getGraphicsContext", 0}, // 3568 #endif // wxUSE_GRAPHICS_CONTEXT #if wxUSE_GRAPHICS_CONTEXT - {wxGCDC_SetGraphicsContext, "wxGCDC", "setGraphicsContext", 2}, // 3558 + {wxGCDC_SetGraphicsContext, "wxGCDC", "setGraphicsContext", 2}, // 3569 #else - {NULL, "wxGCDC", "setGraphicsContext", 0}, // 3558 + {NULL, "wxGCDC", "setGraphicsContext", 0}, // 3569 #endif // wxUSE_GRAPHICS_CONTEXT - {wxNotificationMessage_new_0, "wxNotificationMessage", "new", 0}, // 3559 - {wxNotificationMessage_new_2, "wxNotificationMessage", "new", 2}, // 3560 - {NULL, "wxNotificationMessage", "destroy", 1}, // 3561 obj destructor wxNotificationMessage_destruct + {wxNotificationMessage_new_0, "wxNotificationMessage", "new", 0}, // 3570 + {wxNotificationMessage_new_2, "wxNotificationMessage", "new", 2}, // 3571 + {NULL, "wxNotificationMessage", "destroy", 1}, // 3572 obj destructor wxNotificationMessage_destruct #if wxCHECK_VERSION(3,1,0) - {wxNotificationMessage_AddAction, "wxNotificationMessage", "addAction", 3}, // 3562 + {wxNotificationMessage_AddAction, "wxNotificationMessage", "addAction", 3}, // 3573 #else - {NULL, "wxNotificationMessage", "addAction", 0}, // 3562 + {NULL, "wxNotificationMessage", "addAction", 0}, // 3573 #endif // wxCHECK_VERSION(3,1,0) - {wxNotificationMessage_Close, "wxNotificationMessage", "close", 1}, // 3563 - {wxNotificationMessage_SetFlags, "wxNotificationMessage", "setFlags", 2}, // 3564 + {wxNotificationMessage_Close, "wxNotificationMessage", "close", 1}, // 3574 + {wxNotificationMessage_SetFlags, "wxNotificationMessage", "setFlags", 2}, // 3575 #if wxCHECK_VERSION(3,1,0) - {wxNotificationMessage_SetIcon, "wxNotificationMessage", "setIcon", 2}, // 3565 + {wxNotificationMessage_SetIcon, "wxNotificationMessage", "setIcon", 2}, // 3576 #else - {NULL, "wxNotificationMessage", "setIcon", 0}, // 3565 + {NULL, "wxNotificationMessage", "setIcon", 0}, // 3576 #endif // wxCHECK_VERSION(3,1,0) - {wxNotificationMessage_SetMessage, "wxNotificationMessage", "setMessage", 2}, // 3566 - {wxNotificationMessage_SetParent, "wxNotificationMessage", "setParent", 2}, // 3567 - {wxNotificationMessage_SetTitle, "wxNotificationMessage", "setTitle", 2}, // 3568 - {wxNotificationMessage_Show, "wxNotificationMessage", "show", 2}, // 3569 + {wxNotificationMessage_SetMessage, "wxNotificationMessage", "setMessage", 2}, // 3577 + {wxNotificationMessage_SetParent, "wxNotificationMessage", "setParent", 2}, // 3578 + {wxNotificationMessage_SetTitle, "wxNotificationMessage", "setTitle", 2}, // 3579 + {wxNotificationMessage_Show, "wxNotificationMessage", "show", 2}, // 3580 #if __WXMSW__ - {wxNotificationMessage_UseTaskBarIcon, "wxNotificationMessage", "useTaskBarIcon", 1}, // 3570 + {wxNotificationMessage_UseTaskBarIcon, "wxNotificationMessage", "useTaskBarIcon", 1}, // 3581 #else - {NULL, "wxNotificationMessage", "useTaskBarIcon", 0}, // 3570 + {NULL, "wxNotificationMessage", "useTaskBarIcon", 0}, // 3581 #endif // __WXMSW__ #if __WXMSW__ && wxCHECK_VERSION(3,1,0) - {wxNotificationMessage_MSWUseToasts, "wxNotificationMessage", "mSWUseToasts", 1}, // 3571 + {wxNotificationMessage_MSWUseToasts, "wxNotificationMessage", "mSWUseToasts", 1}, // 3582 #else - {NULL, "wxNotificationMessage", "mSWUseToasts", 0}, // 3571 + {NULL, "wxNotificationMessage", "mSWUseToasts", 0}, // 3582 #endif // __WXMSW__ && wxCHECK_VERSION(3,1,0) - {NULL, "", "", 0}, // 3572 + {NULL, "", "", 0}, // 3583 #if WXE_WEBVIEW - {wxWebView_New, "wxWebView", "new", 3}, // 3573 + {wxWebView_New, "wxWebView", "new", 3}, // 3584 #else - {NULL, "wxWebView", "new", 0}, // 3573 + {NULL, "wxWebView", "new", 0}, // 3584 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetCurrentTitle, "wxWebView", "getCurrentTitle", 1}, // 3574 + {wxWebView_GetCurrentTitle, "wxWebView", "getCurrentTitle", 1}, // 3585 #else - {NULL, "wxWebView", "getCurrentTitle", 0}, // 3574 + {NULL, "wxWebView", "getCurrentTitle", 0}, // 3585 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetCurrentURL, "wxWebView", "getCurrentURL", 1}, // 3575 + {wxWebView_GetCurrentURL, "wxWebView", "getCurrentURL", 1}, // 3586 #else - {NULL, "wxWebView", "getCurrentURL", 0}, // 3575 + {NULL, "wxWebView", "getCurrentURL", 0}, // 3586 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetPageSource, "wxWebView", "getPageSource", 1}, // 3576 + {wxWebView_GetPageSource, "wxWebView", "getPageSource", 1}, // 3587 #else - {NULL, "wxWebView", "getPageSource", 0}, // 3576 + {NULL, "wxWebView", "getPageSource", 0}, // 3587 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetPageText, "wxWebView", "getPageText", 1}, // 3577 + {wxWebView_GetPageText, "wxWebView", "getPageText", 1}, // 3588 #else - {NULL, "wxWebView", "getPageText", 0}, // 3577 + {NULL, "wxWebView", "getPageText", 0}, // 3588 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_IsBusy, "wxWebView", "isBusy", 1}, // 3578 + {wxWebView_IsBusy, "wxWebView", "isBusy", 1}, // 3589 #else - {NULL, "wxWebView", "isBusy", 0}, // 3578 + {NULL, "wxWebView", "isBusy", 0}, // 3589 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_IsEditable, "wxWebView", "isEditable", 1}, // 3579 + {wxWebView_IsEditable, "wxWebView", "isEditable", 1}, // 3590 #else - {NULL, "wxWebView", "isEditable", 0}, // 3579 + {NULL, "wxWebView", "isEditable", 0}, // 3590 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_LoadURL, "wxWebView", "loadURL", 2}, // 3580 + {wxWebView_LoadURL, "wxWebView", "loadURL", 2}, // 3591 #else - {NULL, "wxWebView", "loadURL", 0}, // 3580 + {NULL, "wxWebView", "loadURL", 0}, // 3591 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Print, "wxWebView", "print", 1}, // 3581 + {wxWebView_Print, "wxWebView", "print", 1}, // 3592 #else - {NULL, "wxWebView", "print", 0}, // 3581 + {NULL, "wxWebView", "print", 0}, // 3592 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Reload, "wxWebView", "reload", 2}, // 3582 + {wxWebView_Reload, "wxWebView", "reload", 2}, // 3593 #else - {NULL, "wxWebView", "reload", 0}, // 3582 + {NULL, "wxWebView", "reload", 0}, // 3593 #endif // WXE_WEBVIEW #if WXE_WEBVIEW && wxCHECK_VERSION(3,1,1) - {wxWebView_RunScript, "wxWebView", "runScript", 2}, // 3583 + {wxWebView_RunScript, "wxWebView", "runScript", 2}, // 3594 #else - {NULL, "wxWebView", "runScript", 0}, // 3583 + {NULL, "wxWebView", "runScript", 0}, // 3594 #endif // WXE_WEBVIEW && wxCHECK_VERSION(3,1,1) #if WXE_WEBVIEW - {wxWebView_SetEditable, "wxWebView", "setEditable", 2}, // 3584 + {wxWebView_SetEditable, "wxWebView", "setEditable", 2}, // 3595 #else - {NULL, "wxWebView", "setEditable", 0}, // 3584 + {NULL, "wxWebView", "setEditable", 0}, // 3595 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_SetPage, "wxWebView", "setPage", 3}, // 3585 + {wxWebView_SetPage, "wxWebView", "setPage", 3}, // 3596 #else - {NULL, "wxWebView", "setPage", 0}, // 3585 + {NULL, "wxWebView", "setPage", 0}, // 3596 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Stop, "wxWebView", "stop", 1}, // 3586 + {wxWebView_Stop, "wxWebView", "stop", 1}, // 3597 #else - {NULL, "wxWebView", "stop", 0}, // 3586 + {NULL, "wxWebView", "stop", 0}, // 3597 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanCopy, "wxWebView", "canCopy", 1}, // 3587 + {wxWebView_CanCopy, "wxWebView", "canCopy", 1}, // 3598 #else - {NULL, "wxWebView", "canCopy", 0}, // 3587 + {NULL, "wxWebView", "canCopy", 0}, // 3598 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanCut, "wxWebView", "canCut", 1}, // 3588 + {wxWebView_CanCut, "wxWebView", "canCut", 1}, // 3599 #else - {NULL, "wxWebView", "canCut", 0}, // 3588 + {NULL, "wxWebView", "canCut", 0}, // 3599 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanPaste, "wxWebView", "canPaste", 1}, // 3589 + {wxWebView_CanPaste, "wxWebView", "canPaste", 1}, // 3600 #else - {NULL, "wxWebView", "canPaste", 0}, // 3589 + {NULL, "wxWebView", "canPaste", 0}, // 3600 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Copy, "wxWebView", "copy", 1}, // 3590 + {wxWebView_Copy, "wxWebView", "copy", 1}, // 3601 #else - {NULL, "wxWebView", "copy", 0}, // 3590 + {NULL, "wxWebView", "copy", 0}, // 3601 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Cut, "wxWebView", "cut", 1}, // 3591 + {wxWebView_Cut, "wxWebView", "cut", 1}, // 3602 #else - {NULL, "wxWebView", "cut", 0}, // 3591 + {NULL, "wxWebView", "cut", 0}, // 3602 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Paste, "wxWebView", "paste", 1}, // 3592 + {wxWebView_Paste, "wxWebView", "paste", 1}, // 3603 #else - {NULL, "wxWebView", "paste", 0}, // 3592 + {NULL, "wxWebView", "paste", 0}, // 3603 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_EnableContextMenu, "wxWebView", "enableContextMenu", 2}, // 3593 + {wxWebView_EnableContextMenu, "wxWebView", "enableContextMenu", 2}, // 3604 #else - {NULL, "wxWebView", "enableContextMenu", 0}, // 3593 + {NULL, "wxWebView", "enableContextMenu", 0}, // 3604 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_IsContextMenuEnabled, "wxWebView", "isContextMenuEnabled", 1}, // 3594 + {wxWebView_IsContextMenuEnabled, "wxWebView", "isContextMenuEnabled", 1}, // 3605 #else - {NULL, "wxWebView", "isContextMenuEnabled", 0}, // 3594 + {NULL, "wxWebView", "isContextMenuEnabled", 0}, // 3605 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanGoBack, "wxWebView", "canGoBack", 1}, // 3595 + {wxWebView_CanGoBack, "wxWebView", "canGoBack", 1}, // 3606 #else - {NULL, "wxWebView", "canGoBack", 0}, // 3595 + {NULL, "wxWebView", "canGoBack", 0}, // 3606 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanGoForward, "wxWebView", "canGoForward", 1}, // 3596 + {wxWebView_CanGoForward, "wxWebView", "canGoForward", 1}, // 3607 #else - {NULL, "wxWebView", "canGoForward", 0}, // 3596 + {NULL, "wxWebView", "canGoForward", 0}, // 3607 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_ClearHistory, "wxWebView", "clearHistory", 1}, // 3597 + {wxWebView_ClearHistory, "wxWebView", "clearHistory", 1}, // 3608 #else - {NULL, "wxWebView", "clearHistory", 0}, // 3597 + {NULL, "wxWebView", "clearHistory", 0}, // 3608 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_EnableHistory, "wxWebView", "enableHistory", 2}, // 3598 + {wxWebView_EnableHistory, "wxWebView", "enableHistory", 2}, // 3609 #else - {NULL, "wxWebView", "enableHistory", 0}, // 3598 + {NULL, "wxWebView", "enableHistory", 0}, // 3609 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GoBack, "wxWebView", "goBack", 1}, // 3599 + {wxWebView_GoBack, "wxWebView", "goBack", 1}, // 3610 #else - {NULL, "wxWebView", "goBack", 0}, // 3599 + {NULL, "wxWebView", "goBack", 0}, // 3610 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GoForward, "wxWebView", "goForward", 1}, // 3600 + {wxWebView_GoForward, "wxWebView", "goForward", 1}, // 3611 #else - {NULL, "wxWebView", "goForward", 0}, // 3600 + {NULL, "wxWebView", "goForward", 0}, // 3611 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_ClearSelection, "wxWebView", "clearSelection", 1}, // 3601 + {wxWebView_ClearSelection, "wxWebView", "clearSelection", 1}, // 3612 #else - {NULL, "wxWebView", "clearSelection", 0}, // 3601 + {NULL, "wxWebView", "clearSelection", 0}, // 3612 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_DeleteSelection, "wxWebView", "deleteSelection", 1}, // 3602 + {wxWebView_DeleteSelection, "wxWebView", "deleteSelection", 1}, // 3613 #else - {NULL, "wxWebView", "deleteSelection", 0}, // 3602 + {NULL, "wxWebView", "deleteSelection", 0}, // 3613 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetSelectedSource, "wxWebView", "getSelectedSource", 1}, // 3603 + {wxWebView_GetSelectedSource, "wxWebView", "getSelectedSource", 1}, // 3614 #else - {NULL, "wxWebView", "getSelectedSource", 0}, // 3603 + {NULL, "wxWebView", "getSelectedSource", 0}, // 3614 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetSelectedText, "wxWebView", "getSelectedText", 1}, // 3604 + {wxWebView_GetSelectedText, "wxWebView", "getSelectedText", 1}, // 3615 #else - {NULL, "wxWebView", "getSelectedText", 0}, // 3604 + {NULL, "wxWebView", "getSelectedText", 0}, // 3615 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_HasSelection, "wxWebView", "hasSelection", 1}, // 3605 + {wxWebView_HasSelection, "wxWebView", "hasSelection", 1}, // 3616 #else - {NULL, "wxWebView", "hasSelection", 0}, // 3605 + {NULL, "wxWebView", "hasSelection", 0}, // 3616 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_SelectAll, "wxWebView", "selectAll", 1}, // 3606 + {wxWebView_SelectAll, "wxWebView", "selectAll", 1}, // 3617 #else - {NULL, "wxWebView", "selectAll", 0}, // 3606 + {NULL, "wxWebView", "selectAll", 0}, // 3617 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanRedo, "wxWebView", "canRedo", 1}, // 3607 + {wxWebView_CanRedo, "wxWebView", "canRedo", 1}, // 3618 #else - {NULL, "wxWebView", "canRedo", 0}, // 3607 + {NULL, "wxWebView", "canRedo", 0}, // 3618 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanUndo, "wxWebView", "canUndo", 1}, // 3608 + {wxWebView_CanUndo, "wxWebView", "canUndo", 1}, // 3619 #else - {NULL, "wxWebView", "canUndo", 0}, // 3608 + {NULL, "wxWebView", "canUndo", 0}, // 3619 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Redo, "wxWebView", "redo", 1}, // 3609 + {wxWebView_Redo, "wxWebView", "redo", 1}, // 3620 #else - {NULL, "wxWebView", "redo", 0}, // 3609 + {NULL, "wxWebView", "redo", 0}, // 3620 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Undo, "wxWebView", "undo", 1}, // 3610 + {wxWebView_Undo, "wxWebView", "undo", 1}, // 3621 #else - {NULL, "wxWebView", "undo", 0}, // 3610 + {NULL, "wxWebView", "undo", 0}, // 3621 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_Find, "wxWebView", "find", 3}, // 3611 + {wxWebView_Find, "wxWebView", "find", 3}, // 3622 #else - {NULL, "wxWebView", "find", 0}, // 3611 + {NULL, "wxWebView", "find", 0}, // 3622 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_CanSetZoomType, "wxWebView", "canSetZoomType", 2}, // 3612 + {wxWebView_CanSetZoomType, "wxWebView", "canSetZoomType", 2}, // 3623 #else - {NULL, "wxWebView", "canSetZoomType", 0}, // 3612 + {NULL, "wxWebView", "canSetZoomType", 0}, // 3623 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetZoom, "wxWebView", "getZoom", 1}, // 3613 + {wxWebView_GetZoom, "wxWebView", "getZoom", 1}, // 3624 #else - {NULL, "wxWebView", "getZoom", 0}, // 3613 + {NULL, "wxWebView", "getZoom", 0}, // 3624 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_GetZoomType, "wxWebView", "getZoomType", 1}, // 3614 + {wxWebView_GetZoomType, "wxWebView", "getZoomType", 1}, // 3625 #else - {NULL, "wxWebView", "getZoomType", 0}, // 3614 + {NULL, "wxWebView", "getZoomType", 0}, // 3625 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_SetZoom, "wxWebView", "setZoom", 2}, // 3615 + {wxWebView_SetZoom, "wxWebView", "setZoom", 2}, // 3626 #else - {NULL, "wxWebView", "setZoom", 0}, // 3615 + {NULL, "wxWebView", "setZoom", 0}, // 3626 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebView_SetZoomType, "wxWebView", "setZoomType", 2}, // 3616 + {wxWebView_SetZoomType, "wxWebView", "setZoomType", 2}, // 3627 #else - {NULL, "wxWebView", "setZoomType", 0}, // 3616 + {NULL, "wxWebView", "setZoomType", 0}, // 3627 #endif // WXE_WEBVIEW #if WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) - {wxWebView_GetZoomFactor, "wxWebView", "getZoomFactor", 1}, // 3617 + {wxWebView_GetZoomFactor, "wxWebView", "getZoomFactor", 1}, // 3628 #else - {NULL, "wxWebView", "getZoomFactor", 0}, // 3617 + {NULL, "wxWebView", "getZoomFactor", 0}, // 3628 #endif // WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) #if WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) - {wxWebView_SetZoomFactor, "wxWebView", "setZoomFactor", 2}, // 3618 + {wxWebView_SetZoomFactor, "wxWebView", "setZoomFactor", 2}, // 3629 #else - {NULL, "wxWebView", "setZoomFactor", 0}, // 3618 + {NULL, "wxWebView", "setZoomFactor", 0}, // 3629 #endif // WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) #if WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) - {wxWebView_IsBackendAvailable, "wxWebView", "isBackendAvailable", 1}, // 3619 + {wxWebView_IsBackendAvailable, "wxWebView", "isBackendAvailable", 1}, // 3630 #else - {NULL, "wxWebView", "isBackendAvailable", 0}, // 3619 + {NULL, "wxWebView", "isBackendAvailable", 0}, // 3630 #endif // WXE_WEBVIEW && wxCHECK_VERSION(3,1,4) #if WXE_WEBVIEW - {wxWebViewEvent_GetString, "wxWebViewEvent", "getString", 1}, // 3620 + {wxWebViewEvent_GetString, "wxWebViewEvent", "getString", 1}, // 3631 #else - {NULL, "wxWebViewEvent", "getString", 0}, // 3620 + {NULL, "wxWebViewEvent", "getString", 0}, // 3631 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebViewEvent_GetInt, "wxWebViewEvent", "getInt", 1}, // 3621 + {wxWebViewEvent_GetInt, "wxWebViewEvent", "getInt", 1}, // 3632 #else - {NULL, "wxWebViewEvent", "getInt", 0}, // 3621 + {NULL, "wxWebViewEvent", "getInt", 0}, // 3632 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebViewEvent_GetTarget, "wxWebViewEvent", "getTarget", 1}, // 3622 + {wxWebViewEvent_GetTarget, "wxWebViewEvent", "getTarget", 1}, // 3633 #else - {NULL, "wxWebViewEvent", "getTarget", 0}, // 3622 + {NULL, "wxWebViewEvent", "getTarget", 0}, // 3633 #endif // WXE_WEBVIEW #if WXE_WEBVIEW - {wxWebViewEvent_GetURL, "wxWebViewEvent", "getURL", 1}, // 3623 + {wxWebViewEvent_GetURL, "wxWebViewEvent", "getURL", 1}, // 3634 #else - {NULL, "wxWebViewEvent", "getURL", 0}, // 3623 + {NULL, "wxWebViewEvent", "getURL", 0}, // 3634 #endif // WXE_WEBVIEW }; diff --git a/lib/wx/c_src/gen/wxe_init.cpp b/lib/wx/c_src/gen/wxe_init.cpp index 12b0b418b036..d29e8cb19a03 100644 --- a/lib/wx/c_src/gen/wxe_init.cpp +++ b/lib/wx/c_src/gen/wxe_init.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -5895,17 +5895,17 @@ void WxeApp::init_consts(wxeMetaCommand& event) { #else { enif_make_atom(rt.env,"wxKeyCode"), "wxk_MEDIA_PLAY_PAUSE", WXE_ATOM_undefined }, #endif -#if wxCHECK_VERSION(3,1,0) +#if wxCHECK_VERSION(3,2,0) { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_MAIL", rt.make_int(WXK_LAUNCH_MAIL) }, #else { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_MAIL", WXE_ATOM_undefined }, #endif -#if wxCHECK_VERSION(3,1,0) +#if wxCHECK_VERSION(3,2,0) { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_APP1", rt.make_int(WXK_LAUNCH_APP1) }, #else { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_APP1", WXE_ATOM_undefined }, #endif -#if wxCHECK_VERSION(3,1,0) +#if wxCHECK_VERSION(3,2,0) { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_APP2", rt.make_int(WXK_LAUNCH_APP2) }, #else { enif_make_atom(rt.env,"wxKeyCode"), "wxk_LAUNCH_APP2", WXE_ATOM_undefined }, @@ -6664,6 +6664,12 @@ void WxeApp::init_consts(wxeMetaCommand& event) { { enif_make_atom(rt.env,"wxStandardID"), "wxID_MDI_WINDOW_PREV", rt.make_int(wxID_MDI_WINDOW_PREV) }, { enif_make_atom(rt.env,"wxStandardID"), "wxID_MDI_WINDOW_NEXT", rt.make_int(wxID_MDI_WINDOW_NEXT) }, { enif_make_atom(rt.env,"wxStandardID"), "wxID_MDI_WINDOW_LAST", rt.make_int(wxID_MDI_WINDOW_LAST) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_MENU_FIRST", rt.make_int(wxID_OSX_MENU_FIRST) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_HIDE", rt.make_int(wxID_OSX_HIDE) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_HIDEOTHERS", rt.make_int(wxID_OSX_HIDEOTHERS) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_SHOWALL", rt.make_int(wxID_OSX_SHOWALL) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_SERVICES", rt.make_int(wxID_OSX_SERVICES) }, + { enif_make_atom(rt.env,"wxStandardID"), "wxID_OSX_MENU_LAST", rt.make_int(wxID_OSX_MENU_LAST) }, { enif_make_atom(rt.env,"wxStandardID"), "wxID_FILEDLGG", rt.make_int(wxID_FILEDLGG) }, { enif_make_atom(rt.env,"wxStandardID"), "wxID_FILECTRL", rt.make_int(wxID_FILECTRL) }, { enif_make_atom(rt.env,"wxStandardID"), "wxID_HIGHEST", rt.make_int(wxID_HIGHEST) }, diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h index d8e8a0f7eac4..0d514a1709a2 100644 --- a/lib/wx/c_src/gen/wxe_macros.h +++ b/lib/wx/c_src/gen/wxe_macros.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -73,6 +73,9 @@ #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE #include #endif +#if wxUSE_GLCANVAS_EGL && !wxCHECK_VERSION(3,2,3) +#include +#endif #ifndef wxICON_DEFAULT_BITMAP_TYPE diff --git a/lib/wx/c_src/gen/wxe_wrapper_3.cpp b/lib/wx/c_src/gen/wxe_wrapper_3.cpp index e2e063fd3177..4f6fe807a567 100644 --- a/lib/wx/c_src/gen/wxe_wrapper_3.cpp +++ b/lib/wx/c_src/gen/wxe_wrapper_3.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -2620,6 +2620,51 @@ void wxGLCanvas_SetCurrent(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) } +#if wxUSE_GLCANVAS_EGL +// wxGLCanvas::CreateSurface +void wxGLCanvas_CreateSurface(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxGLCanvas *This; + This = (wxGLCanvas *) memenv->getPtr(env, argv[0], "This"); + +#if !wxCHECK_VERSION(3,2,3) + if(!This) throw wxe_badarg(0); + if(This->GetEGLSurface() != EGL_NO_SURFACE) + eglDestroySurface(This->GetEGLDisplay(), This->GetEGLSurface()); +#endif +; + if(!This) throw wxe_badarg("This"); + bool Result = This->CreateSurface(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +#endif +// wxGLCanvas::IsDisplaySupported +void wxGLCanvas_IsDisplaySupported(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + int attribList_tmp; + unsigned int attribListLen; + ERL_NIF_TERM attribListHead, attribListTail; + if(!enif_get_list_length(env, argv[0], &attribListLen)) Badarg("attribList"); + std::vector attribList; + attribListTail = argv[0]; + while(!enif_is_empty_list(env, attribListTail)) { + if(!enif_get_list_cell(env, attribListTail, &attribListHead, &attribListTail)) Badarg("attribList"); + if(!enif_get_int(env, attribListHead, &attribList_tmp)) Badarg("attribList"); + attribList.push_back( (int) attribList_tmp); + }; + bool Result = wxGLCanvas::IsDisplaySupported(attribList.data()); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + // wxGLCanvas::SwapBuffers void wxGLCanvas_SwapBuffers(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) { @@ -2680,6 +2725,22 @@ void wxGLContext_SetCurrent(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) } +#if wxCHECK_VERSION(3,1,0) +// wxGLContext::IsOK +void wxGLContext_IsOK(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxGLContext *This; + This = (wxGLContext *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->IsOK(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +#endif #endif // wxUSE_GLCANVAS // wxGauge::wxGauge void wxGauge_new_0(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) diff --git a/lib/wx/c_src/gen/wxe_wrapper_5.cpp b/lib/wx/c_src/gen/wxe_wrapper_5.cpp index d9d7248a8418..b2616e151e4b 100644 --- a/lib/wx/c_src/gen/wxe_wrapper_5.cpp +++ b/lib/wx/c_src/gen/wxe_wrapper_5.cpp @@ -1909,6 +1909,30 @@ void wxMenuBar_OSXGetAppleMenu(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) } +#endif +#if defined(__WXMAC__) +// wxMenuBar::MacGetCommonMenuBar +void wxMenuBar_MacGetCommonMenuBar(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + wxMenuBar * Result = (wxMenuBar*)wxMenuBar::MacGetCommonMenuBar(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_ref(app->getRef((void *)Result,memenv), "wxMenuBar")); + +} + +#endif +#if defined(__WXMAC__) +// wxMenuBar::MacSetCommonMenuBar +void wxMenuBar_MacSetCommonMenuBar(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMenuBar *menubar; + menubar = (wxMenuBar *) memenv->getPtr(env, argv[0], "menubar"); + wxMenuBar::MacSetCommonMenuBar(menubar); + +} + #endif // wxMenuBar::IsEnabled void wxMenuBar_IsEnabled(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) @@ -3166,6 +3190,90 @@ void wxMouseEvent_GetWheelAxis(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) } +// wxMouseEvent::Aux1DClick +void wxMouseEvent_Aux1DClick(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux1DClick(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +// wxMouseEvent::Aux1Down +void wxMouseEvent_Aux1Down(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux1Down(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +// wxMouseEvent::Aux1Up +void wxMouseEvent_Aux1Up(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux1Up(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +// wxMouseEvent::Aux2DClick +void wxMouseEvent_Aux2DClick(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux2DClick(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +// wxMouseEvent::Aux2Down +void wxMouseEvent_Aux2Down(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux2Down(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + +// wxMouseEvent::Aux2Up +void wxMouseEvent_Aux2Up(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) +{ + ErlNifEnv *env = Ecmd.env; + ERL_NIF_TERM * argv = Ecmd.args; + wxMouseEvent *This; + This = (wxMouseEvent *) memenv->getPtr(env, argv[0], "This"); + if(!This) throw wxe_badarg("This"); + bool Result = This->Aux2Up(); + wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true); + rt.send( rt.make_bool(Result)); + +} + // wxMoveEvent::GetPosition void wxMoveEvent_GetPosition(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd) { diff --git a/lib/wx/c_src/wxe_callback_impl.cpp b/lib/wx/c_src/wxe_callback_impl.cpp index 50f6c0166c68..16458f6fa6bb 100644 --- a/lib/wx/c_src/wxe_callback_impl.cpp +++ b/lib/wx/c_src/wxe_callback_impl.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2022. 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. @@ -46,7 +46,7 @@ wxeEvtListener::wxeEvtListener(ErlNifPid caller, int req, ERL_NIF_TERM req_type, } wxeEvtListener::~wxeEvtListener() { - // enif_fprintf(stderr, "CBD Deleteing %p %T\r\n", this, class_name); fflush(stderr); + // enif_fprintf(stderr, "CBD Deleting %p %T\r\n", this, class_name); fflush(stderr); if(user_data) { delete user_data; } diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp index 46c4cc76794d..e2327cfb54f0 100644 --- a/lib/wx/c_src/wxe_gl.cpp +++ b/lib/wx/c_src/wxe_gl.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2022. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -44,16 +44,25 @@ int egl_initiated = 0; wxeGLC glc; typedef void * (*WXE_GL_LOOKUP) (int); -WXE_GL_LOOKUP wxe_gl_lookup_func = NULL; +void * wxe_not_loaded(int x); +WXE_GL_LOOKUP wxe_gl_lookup_func = (WXE_GL_LOOKUP) wxe_not_loaded; typedef void * (*WXE_GL_FUNC) (ErlNifEnv*, ErlNifPid*, const ERL_NIF_TERM argv[]); +typedef const char * (*WXE_GL_FUNC_NAME) (int); +WXE_GL_FUNC_NAME wxe_gl_lookup_func_name; + extern "C" { -void wxe_initOpenGL(void * fptr) { +void wxe_initOpenGL(void * fptr, void *name_fptr) { wxe_gl_lookup_func = (WXE_GL_LOOKUP) fptr; + wxe_gl_lookup_func_name = (WXE_GL_FUNC_NAME) name_fptr; enif_set_pid_undefined(&gl_active_pid); } } +void * wxe_not_loaded(int x) { + return NULL; +} + ErlNifUInt64 wxe_make_hash(ErlNifEnv *env, ErlNifPid *pid) { ERL_NIF_TERM term = enif_make_pid(env, pid); @@ -113,9 +122,23 @@ void no_context(wxeCommand *event) { enif_clear_env(event->env); } -void gl_dispatch(wxeCommand *event) { +void gl_print_cmd(wxeCommand *event) +{ + int i; + const char *func = wxe_gl_lookup_func_name(event->op); + enif_fprintf(stderr, " %T %d %s(", event->caller, event->op, func); + for(i=0; i < event->argc; i++) { + wx_print_term(event->env, event->args[i]); + if(i < event->argc - 1) + enif_fprintf(stderr, ", "); + } + enif_fprintf(stderr, ")\r\n"); +} + +void gl_dispatch(wxeCommand *event) +{ WXE_GL_FUNC fptr; - if(egl_initiated) { + if((fptr = (WXE_GL_FUNC) wxe_gl_lookup_func(event->op))) { if(enif_compare_pids(&(event->caller),&gl_active_pid) != 0) { ErlNifUInt64 caller_index = wxe_make_hash(event->env, &(event->caller)); wxe_glc * current = glc[caller_index]; @@ -131,12 +154,10 @@ void gl_dispatch(wxeCommand *event) { return; } } - } else { - no_context(event); - return; - } - if((fptr = (WXE_GL_FUNC) wxe_gl_lookup_func(event->op))) { // enif_fprintf(stderr, "GL: caller %T gl_active %T %d\r\n", event->caller, gl_active_pid, event->op); + if(wxe_debug) { + gl_print_cmd(event); + } fptr(event->env, &event->caller, event->args); } else { enif_send(NULL, &event->caller, event->env, diff --git a/lib/wx/c_src/wxe_gl.h b/lib/wx/c_src/wxe_gl.h index 6c57e1b6457e..12aea9bb8c60 100644 --- a/lib/wx/c_src/wxe_gl.h +++ b/lib/wx/c_src/wxe_gl.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -27,7 +27,7 @@ void setActiveGL(wxeMemEnv *memenv, ErlNifPid caller, wxGLCanvas *canvas, wxGLCo void deleteActiveGL(wxGLCanvas *canvas); void gl_dispatch(wxeCommand *); extern "C" { - void wxe_initOpenGL(void * fptr); + void wxe_initOpenGL(void * fptr, void *name_fptr); } diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp index 69a9c65c2736..d8cca316542f 100644 --- a/lib/wx/c_src/wxe_helpers.cpp +++ b/lib/wx/c_src/wxe_helpers.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2014-2021. All Rights Reserved. + * Copyright Ericsson AB 2014-2022. 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. @@ -107,7 +107,7 @@ void wxeFifo::DelQueue(unsigned int i) void wxeFifo::DeleteCmd(wxeCommand *orig) { - orig->op = -2; // Assert: will crash if op is negativ + orig->op = -2; // Assert: will crash if op is negative enif_clear_env(orig->env); free.push_back(orig); } @@ -136,6 +136,6 @@ void wxeFifo::Append(wxeCommand *orig) curr->env = orig->env; orig->env = temp; curr->me_ref = orig->me_ref; - orig->op = -1; // Assert: will crash if op is negativ + orig->op = -1; // Assert: will crash if op is negative m_q.push_back(curr); } diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index fd71fed4aa1c..5ea13715244f 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2022. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -33,6 +33,10 @@ #include #undef private +#ifdef HAVE_GLIB + #include +#endif + #include "wxe_impl.h" #include "wxe_events.h" #include "wxe_return.h" @@ -109,32 +113,68 @@ void meta_command(ErlNifEnv *env, int what, wxe_me_ref *mp) { void send_msg(const char * type, const wxString * msg) { WxeApp * app = (WxeApp *) wxTheApp; wxeReturn rt = wxeReturn(app->global_me, init_caller); + ErlNifEnv *env = enif_alloc_env(); + rt.env = env; ERL_NIF_TERM emsg = enif_make_tuple3(rt.env, rt.make_atom((char *) "wxe_driver"), rt.make_atom((char *) type), rt.make(msg)); rt.send(emsg); + enif_free_env(env); +} + +void wx_print_term(ErlNifEnv * env, ERL_NIF_TERM t) +{ + if(enif_is_binary(env, t)) { + ErlNifBinary bin; + enif_inspect_binary(env, t, &bin); + if(bin.size > 128) { + enif_fprintf(stderr, "<<...LARGE BIN>"); + } else { + enif_fprintf(stderr, "%T", t); + } + } else { + enif_fprintf(stderr, "%T", t); + } } + + void print_cmd(wxeCommand& event) { int i; wxe_fns_t *func = &wxe_fns[event.op]; enif_fprintf(stderr, " %T %d %s::%s(", event.caller, event.op, func->cname, func->fname); - for(i=0; i < event.argc-1; i++) { - enif_fprintf(stderr, "%T,", event.args[i]); - } - if(i > 0) { - enif_fprintf(stderr, "%T)\r\n", event.args[i]); - } else { - enif_fprintf(stderr, ")\r\n"); + for(i=0; i < event.argc; i++) { + wx_print_term(event.env, event.args[i]); + if(i < event.argc - 1) + enif_fprintf(stderr, ", "); } + enif_fprintf(stderr, ")\r\n"); } + /* ************************************************************ * Init WxeApp the application emulator * ************************************************************/ +#ifdef HAVE_GLIB +static GLogWriterOutput wxe_log_glib(GLogLevelFlags log_level, + const GLogField *fields, + gsize n_fields, + gpointer user_data) +{ + for (gsize i = 0; i < n_fields; i++) { + if(strcmp(fields[i].key, "MESSAGE") == 0) { + wxString msg; + msg.Printf(wxT("GTK: %s"), (char *) fields[i].value); + send_msg("debug", &msg); + } + } + return G_LOG_WRITER_HANDLED; +} +#endif + bool WxeApp::OnInit() { @@ -167,6 +207,10 @@ bool WxeApp::OnInit() (wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close); #endif +#ifdef HAVE_GLIB + g_log_set_writer_func(wxe_log_glib, NULL, NULL); +#endif + SetExitOnFrameDelete(false); enif_mutex_lock(wxe_status_m); @@ -199,6 +243,18 @@ void WxeApp::MacReopenApp() { wxString empty; send_msg("reopen_app", &empty); } + +// See: https://github.com/wxWidgets/wxWidgets/blob/v3.1.5/src/osx/cocoa/utils.mm#L76:L93 +bool WxeApp::OSXIsGUIApplication() { + char val_buf[8]; + size_t val_len = 7; + int res = enif_getenv("WX_MACOS_NON_GUI_APP", val_buf, &val_len); + if (res == 0) { + return FALSE; + } else { + return TRUE; + } +} #endif void WxeApp::shutdown(wxeMetaCommand& Ecmd) { @@ -634,7 +690,7 @@ void WxeApp::destroyMemEnv(wxeMetaCommand &Ecmd) delete refd; ptr2ref.erase(it); } // overridden allocs deletes meta-data in clearPtr - } else { // Not alloced in erl just delete references + } else { // Not allocated in erl just delete references if(refd->ref >= global_me->next) { // if it is not part of global ptrs delete refd; ptr2ref.erase(it); diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h index 16487f3c0dca..a99c30a25471 100644 --- a/lib/wx/c_src/wxe_impl.h +++ b/lib/wx/c_src/wxe_impl.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -64,6 +64,7 @@ class WxeApp : public wxApp virtual void MacOpenURL(const wxString &url); virtual void MacNewFile(); virtual void MacReopenApp(); + virtual bool OSXIsGUIApplication(); #endif void init_consts(wxeMetaCommand& event); @@ -114,4 +115,7 @@ typedef struct { extern wxe_fns_t wxe_fns[]; +void wx_print_term(ErlNifEnv * env, ERL_NIF_TERM t); + + #endif //_WXE_IMPL_H diff --git a/lib/wx/c_src/wxe_nif.c b/lib/wx/c_src/wxe_nif.c index eaab733807dd..a7d3fea8859c 100644 --- a/lib/wx/c_src/wxe_nif.c +++ b/lib/wx/c_src/wxe_nif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2017-2021. All Rights Reserved. + * Copyright Ericsson AB 2017-2023. 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. @@ -65,7 +65,7 @@ ERL_NIF_TERM WXE_ATOM_wxPrintDialogData; ErlNifResourceType* wxeMemEnvRt = NULL; int wxe_debug = 0; -extern void wxe_initOpenGL(void * fptr); +extern void wxe_initOpenGL(void * fptr, void *debug); // void destroyMemEnv(wxeMemEnv *memenv); @@ -127,9 +127,13 @@ static ERL_NIF_TERM wx_setup_cmd(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar static ERL_NIF_TERM wx_init_opengl(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { void * fptr; + void * debug; if(!get_ptr(env, argv[0], &fptr)) return enif_make_badarg(env); - wxe_initOpenGL(fptr); + if(!get_ptr(env, argv[1], &debug)) + return enif_make_badarg(env); + + wxe_initOpenGL(fptr, debug); return WXE_ATOM_ok; } @@ -197,7 +201,8 @@ static ErlNifFunc nif_funcs[] = {"queue_cmd",12, wx_setup_cmd}, {"queue_cmd",13, wx_setup_cmd}, {"queue_cmd",14, wx_setup_cmd}, - {"init_opengl", 1, wx_init_opengl}, + {"queue_cmd",15, wx_setup_cmd}, + {"init_opengl", 2, wx_init_opengl}, {"make_env", 0, wxe_make_env}, {"delete_env", 1, wxe_delete_env}, {"debug_driver", 1, wxe_debug_driver}, diff --git a/lib/wx/c_src/wxe_nif.h b/lib/wx/c_src/wxe_nif.h index 3e934bdd6b53..e466182ccf6f 100644 --- a/lib/wx/c_src/wxe_nif.h +++ b/lib/wx/c_src/wxe_nif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2019-2021. All Rights Reserved. + * Copyright Ericsson AB 2019-2022. 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. @@ -38,7 +38,7 @@ extern ERL_NIF_TERM WXE_ATOM__wx_invoke_cb_; extern ERL_NIF_TERM WXE_ATOM_define; extern ERL_NIF_TERM WXE_ATOM_global; -/* Used for comparsions */ +/* Used for comparisons */ extern ERL_NIF_TERM WXE_ATOM_wxWindow; extern ERL_NIF_TERM WXE_ATOM_wxSizer; @@ -116,3 +116,7 @@ void stop_native_gui(ErlNifEnv *); /* wxe_ps_init */ void * wxe_ps_init(); void * wxe_ps_init2(); + +#ifdef _MACOSX +int is_packaged_app(); +#endif diff --git a/lib/wx/c_src/wxe_return.cpp b/lib/wx/c_src/wxe_return.cpp index b86df17933a2..8728dafcf950 100644 --- a/lib/wx/c_src/wxe_return.cpp +++ b/lib/wx/c_src/wxe_return.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2021. All Rights Reserved. + * Copyright Ericsson AB 2008-2023. 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. @@ -43,8 +43,11 @@ wxeReturn::~wxeReturn () { int wxeReturn::send(ERL_NIF_TERM msg) { int res; if(wxe_debug) { - if(isResult) - enif_fprintf(stderr, "return to %T: %T\r\n", caller, msg); + if(isResult) { + enif_fprintf(stderr, "return to %T: ", caller); + wx_print_term(env, msg); + enif_fprintf(stderr, "\r\n"); + } } if(isResult) { res = enif_send(NULL, &caller, env, @@ -409,7 +412,7 @@ ERL_NIF_TERM wxeReturn::make(wxGBSpan val) { INLINE ERL_NIF_TERM wxeReturn::make(wxMouseState val) { - return enif_make_tuple(env, 11, + return enif_make_tuple(env, 13, enif_make_atom(env, "wxMouseState"), // TODO not int? enif_make_uint(env, val.GetX()), @@ -421,7 +424,9 @@ ERL_NIF_TERM wxeReturn::make(wxMouseState val) { make_bool(val.ShiftDown()), make_bool(val.AltDown()), make_bool(val.MetaDown()), - make_bool(val.CmdDown()) + make_bool(val.CmdDown()), + make_bool(val.Aux1IsDown()), + make_bool(val.Aux2IsDown()) ); } diff --git a/lib/wx/config.mk.in b/lib/wx/config.mk.in index 2fa09209d2e6..51bab82ea4d5 100644 --- a/lib/wx/config.mk.in +++ b/lib/wx/config.mk.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2021. 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. @@ -17,20 +17,12 @@ # # %CopyrightEnd% # -INSIDE_ERLSRC = @WX_BUILDING_INSIDE_ERLSRC@ SYS_TYPE = @WXERL_SYS_TYPE@ CAN_BUILD_DRIVER = @WXERL_CAN_BUILD_DRIVER@ VSN = $(WX_VSN) -ifeq ($(INSIDE_ERLSRC), true) - include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk RELSYSDIR = $(RELEASE_PATH)/lib/wx-$(VSN) - -else -INSTALLDIR=@ERLANG_ROOT_DIR@/lib -endif - diff --git a/lib/wx/configure b/lib/wx/configure index 6cb5ce03b48c..a75252c8f02d 100755 --- a/lib/wx/configure +++ b/lib/wx/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +221,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +253,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +292,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +310,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +332,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +341,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +380,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +398,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +430,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +459,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +503,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +517,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +534,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,49 +606,45 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS WXERL_SYS_TYPE @@ -649,15 +676,14 @@ WX_CFLAGS WX_CPPFLAGS WX_CONFIG_PATH ERLANG_ROOT_DIR -WX_BUILDING_INSIDE_ERLSRC ERLC DEBUG_CXXFLAGS DEBUG_CFLAGS GL_LIBS OBJC_CFLAGS OBJC_CC -EGREP -GREP +GLIB_LIBS +GLIB_CFLAGS MIXED_MINGW MIXED_VC CPP @@ -673,6 +699,10 @@ LDFLAGS CFLAGS CC TARGET +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -728,7 +758,6 @@ with_wxdir with_wx_config with_wx_prefix with_wx_exec_prefix -enable_sanitizers ' ac_precious_vars='build_alias host_alias @@ -810,8 +839,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -852,9 +879,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -878,9 +905,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1091,9 +1118,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1107,9 +1134,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1153,9 +1180,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1171,7 +1198,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1235,7 +1262,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1353,6 +1380,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1360,13 +1388,6 @@ if test -n "$ac_init_help"; then cat <<\_ACEOF -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-sanitizers[=comma-separated list of sanitizers] - Default=address,undefined - Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) @@ -1410,9 +1431,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1440,7 +1461,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1448,7 +1470,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1458,9 +1480,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1477,14 +1499,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1492,14 +1514,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1515,14 +1538,14 @@ fi ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1530,14 +1553,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1559,7 +1583,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1567,14 +1591,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1586,8 +1611,8 @@ fi # ac_fn_c_try_run LINENO # ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -1597,25 +1622,26 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status @@ -1640,7 +1666,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -1650,14 +1676,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1667,9 +1694,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -1677,14 +1705,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -1694,14 +1722,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -1711,9 +1740,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -1721,14 +1751,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -1736,7 +1766,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -1746,12 +1776,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -1761,12 +1792,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -1794,9 +1825,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 &5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1948,17 +1895,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1980,17 +1928,18 @@ fi ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -1998,12 +1947,13 @@ if (sizeof ($2)) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -2011,29 +1961,50 @@ if (sizeof (($2))) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop eval "$3=yes" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2066,8 +2037,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2102,7 +2077,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2137,11 +2112,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2152,8 +2129,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2177,7 +2154,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2185,14 +2162,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2200,15 +2177,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2216,8 +2193,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2231,63 +2208,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2297,192 +2259,854 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +# Test code for whether the C++ compiler supports C++98 (global declarations) +ac_cxx_conftest_cxx98_globals=' +// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are to reject old compilers that +// lack the unsuffixed header files. +#include +#include + +// and are *not* freestanding headers in C++98. +extern void assert (int); +namespace std { + extern int strcmp (const char *, const char *); +} + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::exception; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + // Extra parentheses suppress a warning when building autoconf itself, + // due to lint rules shared with more typical C programs. + assert (!(strcmp) (s, "test")); + } +} + +template struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template T add(U u) { return static_cast(u) + val; } +}; + +} // anonymous namespace +' + +# Test code for whether the C++ compiler supports C++98 (body of main) +ac_cxx_conftest_cxx98_main=' + assert (argc); + assert (! argv[0]); +{ + test_exception_syntax (); + test_template tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); +} +' + +# Test code for whether the C++ compiler supports C++11 (global declarations) +ac_cxx_conftest_cxx11_globals=' +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif + +namespace cxx11test +{ + constexpr int get_val() { return 20; } + + struct testinit + { + int i; + double d; + }; + + class delegate + { + public: + delegate(int n) : n(n) {} + delegate(): delegate(2354) {} + + virtual int getval() { return this->n; }; + protected: + int n; + }; + + class overridden : public delegate + { + public: + overridden(int n): delegate(n) {} + virtual int getval() override final { return this->n * 2; } + }; + + class nocopy + { + public: + nocopy(int i): i(i) {} + nocopy() = default; + nocopy(const nocopy&) = delete; + nocopy & operator=(const nocopy&) = delete; + private: + int i; + }; + + // for testing lambda expressions + template Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template auto sum(V first) -> V + { + return first; + } + template auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } +} +' + +# Test code for whether the C++ compiler supports C++11 (body of main) +ac_cxx_conftest_cxx11_main=' +{ + // Test auto and decltype + auto a1 = 6538; + auto a2 = 48573953.4; + auto a3 = "String literal"; + + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + + decltype(a2) a4 = 34895.034; +} +{ + // Test constexpr + short sa[cxx11test::get_val()] = { 0 }; +} +{ + // Test initializer lists + cxx11test::testinit il = { 4323, 435234.23544 }; +} +{ + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } +} +{ + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); +} +{ + // Test use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); +} +{ + // Test constructor delegation + cxx11test::delegate d1; + cxx11test::delegate d2(); + cxx11test::delegate d3(45); +} +{ + // Test override and final + cxx11test::overridden o1(55464); +} +{ + // Test nullptr + char *c = nullptr; +} +{ + // Test template brackets + test_template<::test_template> v(test_template(12)); +} +{ + // Unicode literals + char const *utf8 = u8"UTF-8 string \u2500"; + char16_t const *utf16 = u"UTF-8 string \u2500"; + char32_t const *utf32 = U"UTF-32 string \u2500"; +} +' + +# Test code for whether the C compiler supports C++11 (complete). +ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} +${ac_cxx_conftest_cxx11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + ${ac_cxx_conftest_cxx11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C++98 (complete). +ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_aux_dir= -for ac_dir in $srcdir/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in $srcdir/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -## Delete previous failed configure results -if test -f ./CONF_INFO; then - rm ./CONF_INFO -fi -if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then - as_fn_error $? "ERL_TOP is not set" "$LINENO" 5 -else - erl_top=${ERL_TOP} - ac_aux_dir= -for ac_dir in $erl_top/erts/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in $erl_top/erts/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - WX_BUILDING_INSIDE_ERLSRC=true -fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## Delete previous failed configure results +if test -f ./CONF_INFO; then + rm ./CONF_INFO +fi + + # Check whether --with-wx was given. -if test "${with_wx+set}" = set; then : +if test ${with_wx+y} +then : withval=$with_wx; fi -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2501,21 +3125,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2534,10 +3159,108 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=win32 + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 fi + case $host_os in mingw32) if test "X$host" = "X"; then @@ -2551,6 +3274,15 @@ esac TARGET=$host + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2559,11 +3291,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2571,11 +3304,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2586,11 +3323,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2599,11 +3336,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2611,11 +3349,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2626,11 +3368,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2638,8 +3380,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2652,11 +3394,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2664,11 +3407,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2679,11 +3426,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2692,11 +3439,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2705,15 +3453,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2729,33 +3481,144 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 fi +done + done +IFS=$as_save_IFS + fi fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2763,11 +3626,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2778,28 +3645,25 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - test -n "$CC" && break - done fi -if test -z "$CC"; then +if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2807,11 +3671,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2822,50 +3690,48 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - - test -n "$ac_ct_CC" && break -done - if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi +else + CC="$ac_cv_prog_CC" fi fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2875,7 +3741,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -2883,7 +3749,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2895,9 +3761,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -2918,11 +3784,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2939,7 +3806,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2955,44 +3822,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -3006,15 +3875,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3023,7 +3892,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3035,8 +3904,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3044,10 +3913,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3055,39 +3924,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3101,11 +3971,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3114,31 +3985,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3148,29 +4020,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3179,57 +4055,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3244,94 +4123,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3340,6 +4269,12 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3350,15 +4285,16 @@ if test -z "$CXX"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else @@ -3366,11 +4302,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3381,11 +4321,11 @@ fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3394,15 +4334,16 @@ fi fi if test -z "$CXX"; then ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else @@ -3410,11 +4351,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3425,11 +4370,11 @@ fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3441,8 +4386,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -3452,7 +4397,7 @@ fi fi fi # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do @@ -3462,7 +4407,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3472,20 +4417,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +printf %s "checking whether the compiler supports GNU C++... " >&6; } +if test ${ac_cv_cxx_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3495,29 +4441,33 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi -ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +printf %s "checking whether $CXX accepts -g... " >&6; } +if test ${ac_cv_prog_cxx_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no @@ -3526,57 +4476,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes -else +else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : -else +else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then @@ -3591,6 +4544,100 @@ else CXXFLAGS= fi fi +ac_prog_cxx_stdcxx=no +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 +printf %s "checking for $CXX option to enable C++11 features... " >&6; } +if test ${ac_cv_prog_cxx_11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_11=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx11_program +_ACEOF +for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx11" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx11" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 + ac_prog_cxx_stdcxx=cxx11 +fi +fi +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 +printf %s "checking for $CXX option to enable C++98 features... " >&6; } +if test ${ac_cv_prog_cxx_98+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_98=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx98_program +_ACEOF +for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx98=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx98" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx98" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx98" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx98" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 + ac_prog_cxx_stdcxx=cxx98 +fi +fi + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3600,11 +4647,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else @@ -3612,11 +4660,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3627,11 +4679,11 @@ fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3640,11 +4692,12 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else @@ -3652,11 +4705,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3667,11 +4724,11 @@ fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then @@ -3679,8 +4736,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -3694,40 +4751,36 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -3739,10 +4792,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -3752,7 +4806,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : break fi @@ -3764,29 +4819,24 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -3798,10 +4848,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -3811,11 +4862,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi @@ -3840,19 +4892,20 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #error "broken C++" #endif int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : -else +else $as_nop CXX=; fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3865,15 +4918,15 @@ if test "X$CXX" = X ; then if test X"$with_wx" = X"yes" ; then as_fn_error $? "Can not find C++ compiler" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can not find C++ compiler" >&5 -$as_echo "$as_me: WARNING: Can not find C++ compiler" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Can not find C++ compiler" >&5 +printf "%s\n" "$as_me: WARNING: Can not find C++ compiler" >&2;} fi fi WXERL_CAN_BUILD_DRIVER=false -{ $as_echo "$as_me:${as_lineno-$LINENO}: Building for $host_os" >&5 -$as_echo "$as_me: Building for $host_os" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Building for $host_os" >&5 +printf "%s\n" "$as_me: Building for $host_os" >&6;} WXERL_CAN_BUILD_DRIVER=true @@ -3887,398 +4940,169 @@ MIXED_VSL=no MIXED_VC=no MIXED_MINGW=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 -$as_echo_n "checking for mixed mingw-gcc and native VC++ environment... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 +printf %s "checking for mixed mingw-gcc and native VC++ environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then if test -x /usr/bin/msys-?.0.dll; then CFLAGS="$CFLAGS -O2" MIXED_MSYS=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 -$as_echo "MSYS and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 +printf "%s\n" "MSYS and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" MIXED_CYGWIN=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 -$as_echo "Cygwin and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 +printf "%s\n" "Cygwin and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /bin/wslpath; then CFLAGS="$CFLAGS -O2" MIXED_WSL=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 -$as_echo "WSL and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 +printf "%s\n" "WSL and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$MIXED_MSYS" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 -$as_echo_n "checking for mixed cygwin and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 +printf %s "checking for mixed cygwin and native MinGW environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then if test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 -$as_echo_n "checking for mixed MSYS and native MinGW environment... " >&6; } - if test "x$GCC" = x"yes"; then - if test -x /usr/bin/msys-=.0.dll; then - CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - MIXED_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } - as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 -$as_echo_n "checking if we mix cygwin with any native compiler... " >&6; } -if test "X$MIXED_CYGWIN" = "Xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 -$as_echo_n "checking if we mix msys with another native compiler... " >&6; } -if test "X$MIXED_MSYS" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 -$as_echo_n "checking if we mix WSL with another native compiler... " >&6; } -if test "X$MIXED_WSL" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -fi - - -USER_CFLAGS=$CFLAGS - -if test X"$MIXED_VC" = X"yes" ; then - CFLAGS="-Owx" -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi else - ac_cv_path_EGREP=$EGREP -fi - - fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 +printf %s "checking for mixed MSYS and native MinGW environment... " >&6; } + if test "x$GCC" = x"yes"; then + if test -x /usr/bin/msys-=.0.dll; then + CFLAGS="$CFLAGS -O2" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + MIXED_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } + as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 +printf %s "checking if we mix cygwin with any native compiler... " >&6; } +if test "X$MIXED_CYGWIN" = "Xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 +printf %s "checking if we mix msys with another native compiler... " >&6; } +if test "X$MIXED_MSYS" = "Xyes" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - ac_cv_header_stdc=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 +printf %s "checking if we mix WSL with another native compiler... " >&6; } +if test "X$MIXED_WSL" = "Xyes" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - ac_cv_header_stdc=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f conftest* fi -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : +USER_CFLAGS=$CFLAGS -else - ac_cv_header_stdc=no +if test X"$MIXED_VC" = X"yes" ; then + CFLAGS="-Owx" fi -rm -f conftest* -fi -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then -$as_echo "#define STDC_HEADERS 1" >>confdefs.h -fi -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF -fi -done +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h +fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -4287,14 +5111,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h @@ -4303,44 +5125,46 @@ PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT" OBJC_CC=$CC OBJC_CFLAGS="" CXXFLAGS="" -case $host_os in - darwin*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Checking wxWidgets for min version:" >&5 -$as_echo_n "checking Checking wxWidgets for min version:... " >&6; } +case $host_os in #( + darwin*) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Checking wxWidgets for min version:" >&5 +printf %s "checking Checking wxWidgets for min version:... " >&6; } WX_CC=`wx-config --cc` MAC_MIN=`echo "$WX_CC" | sed 's/^[^ ]*\ *//'` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAC_MIN" >&5 -$as_echo "$MAC_MIN" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAC_MIN" >&5 +printf "%s\n" "$MAC_MIN" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -ObjC" >&5 -$as_echo_n "checking if compiler accepts -ObjC... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -ObjC" >&5 +printf %s "checking if compiler accepts -ObjC... " >&6; } CFLAGS="$CFLAGS -ObjC" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : accept_objc_flag=true -else +else $as_nop accept_objc_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test "X$accept_objc_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } C_ONLY_FLAGS="-ObjC" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Cocoa compliant Objective C compiler" >&5 -$as_echo_n "checking for a Cocoa compliant Objective C compiler... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a Cocoa compliant Objective C compiler" >&5 +printf %s "checking for a Cocoa compliant Objective C compiler... " >&6; } SEARCHFOR="" SEARCHFORXX="" save_IFS=$IFS @@ -4369,20 +5193,20 @@ $as_echo_n "checking for a Cocoa compliant Objective C compiler... " >&6; } done IFS=$save_IFS if test X$APPLE_CC = X -o X$APPLE_CXX = X; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } echo "Can not find compiler to compile Cocoa applications" >> ./CONF_INFO WXERL_CAN_BUILD_DRIVER=false if test X"$with_wx" = X"yes" ; then as_fn_error $? "Can not find compiler to compile Cocoa applications" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can not find compiler to compile Cocoa applications" >&5 -$as_echo "$as_me: WARNING: Can not find compiler to compile Cocoa applications" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Can not find compiler to compile Cocoa applications" >&5 +printf "%s\n" "$as_me: WARNING: Can not find compiler to compile Cocoa applications" >&2;} fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $APPLE_CC ($APPLE_CXX)" >&5 -$as_echo "$APPLE_CC ($APPLE_CXX)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $APPLE_CC ($APPLE_CXX)" >&5 +printf "%s\n" "$APPLE_CC ($APPLE_CXX)" >&6; } CC=$APPLE_CC CXX=$APPLE_CXX #CXXFLAGS="-x c++ $CXXFLAGS" @@ -4392,34 +5216,46 @@ $as_echo "$APPLE_CC ($APPLE_CXX)" >&6; } fi CFLAGS="$USER_CFLAGS $MAC_MIN -Wno-deprecated-declarations" CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" - ;; - mingw32) + ;; #( + mingw32) : + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Reverting to 32-bit time_t" >&5 -$as_echo "$as_me: WARNING: Reverting to 32-bit time_t" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Reverting to 32-bit time_t" >&5 +printf "%s\n" "$as_me: WARNING: Reverting to 32-bit time_t" >&2;} CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" - ;; - win32) + ;; #( + win32) : + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" - ;; - *) - CFLAGS="$CFLAGS -Wno-deprecated-declarations" - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE $PTHR_CFLAGS" - ;; + ;; #( + *) : + + GLIB_CFLAGS=`pkg-config --silence-errors --cflags glib-2.0` + GLIB_LIBS=`pkg-config --silence-errors --libs glib-2.0` + if test X"$GLIB_CFLAGS" != X ; then + HAVE_GLIB="-DHAVE_GLIB=1" + fi + CFLAGS="$CFLAGS -Wno-deprecated-declarations" + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE $PTHR_CFLAGS $HAVE_GLIB" + ;; esac + + + +EXTRA_LDFLAGS= + case $host_os in darwin*) - LDFLAGS="$MAC_MIN -bundle -flat_namespace -undefined warning -fPIC $LDFLAGS" - # Check sizof_void_p as future will hold 64bit MacOS wx - if test $ac_cv_sizeof_void_p = 4; then - LDFLAGS="-m32 $LDFLAGS" - fi + # beam.smp has not been built yet, so we must not use the + # -bundle_loader option in the configuration tests. + LDFLAGS="$MAC_MIN -bundle $LDFLAGS" + EXTRA_LDFLAGS=" -bundle_loader ${ERL_TOP}/bin/$host/beam.smp" GL_LIBS="-framework OpenGL" ;; win32) @@ -4458,198 +5294,202 @@ case $host_os in esac -if test "x$GCC" = xyes -a X"$host_os" != X"win32" ; then +if test "x$GCC" = xyes -a X"$host_os" != X"win32" +then : + CXXNOOPT="-O1" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-move-loop-invariants to CXXNOOPT (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -fno-move-loop-invariants to CXXNOOPT (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-move-loop-invariants to CXXNOOPT (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-move-loop-invariants to CXXNOOPT (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-fno-move-loop-invariants $CXXNOOPT"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } CXXNOOPT="-fno-move-loop-invariants $CXXNOOPT" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-var-tracking-assignments to CXXNOOPT (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -fno-var-tracking-assignments to CXXNOOPT (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-var-tracking-assignments to CXXNOOPT (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-var-tracking-assignments to CXXNOOPT (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-fno-var-tracking-assignments $CXXNOOPT"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } CXXNOOPT="-fno-var-tracking-assignments $CXXNOOPT" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -if test X"$host_os" != X"win32" ; then - for ac_header in GL/gl.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" -if test "x$ac_cv_header_GL_gl_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GL_H 1 -_ACEOF +fi -else - for ac_header in OpenGL/gl.h + +if test X"$host_os" != X"win32" +then : + + for ac_header in GL/gl.h do : - ac_fn_c_check_header_mongrel "$LINENO" "OpenGL/gl.h" "ac_cv_header_OpenGL_gl_h" "$ac_includes_default" -if test "x$ac_cv_header_OpenGL_gl_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_OPENGL_GL_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" +if test "x$ac_cv_header_GL_gl_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GL_H 1" >>confdefs.h -fi +else $as_nop + ac_fn_c_check_header_compile "$LINENO" "OpenGL/gl.h" "ac_cv_header_OpenGL_gl_h" "$ac_includes_default" +if test "x$ac_cv_header_OpenGL_gl_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENGL_GL_H 1" >>confdefs.h -done +fi fi done + if test X"$ac_cv_header_GL_gl_h" != Xyes && test X"$ac_cv_header_OpenGL_gl_h" != Xyes +then : - if test X"$ac_cv_header_GL_gl_h" != Xyes && - test X"$ac_cv_header_OpenGL_gl_h" != Xyes - then saved_CPPFLAGS="$CPPFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: Checking for OpenGL headers in /usr/X11R6" >&5 -$as_echo "$as_me: Checking for OpenGL headers in /usr/X11R6" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Checking for OpenGL headers in /usr/X11R6" >&5 +printf "%s\n" "$as_me: Checking for OpenGL headers in /usr/X11R6" >&6;} CPPFLAGS="-isystem /usr/X11R6/include $CPPFLAGS" $as_unset ac_cv_header_GL_gl_h - for ac_header in GL/gl.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" -if test "x$ac_cv_header_GL_gl_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GL_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" +if test "x$ac_cv_header_GL_gl_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GL_H 1" >>confdefs.h fi -done + if test X"$ac_cv_header_GL_gl_h" != Xyes +then : - if test X"$ac_cv_header_GL_gl_h" != Xyes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Checking for OpenGL headers in /usr/local" >&5 -$as_echo "$as_me: Checking for OpenGL headers in /usr/local" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Checking for OpenGL headers in /usr/local" >&5 +printf "%s\n" "$as_me: Checking for OpenGL headers in /usr/local" >&6;} CPPFLAGS="-isystem /usr/local/include $saved_CPPFLAGS" $as_unset ac_cv_header_GL_gl_h - for ac_header in GL/gl.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" -if test "x$ac_cv_header_GL_gl_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GL_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" +if test "x$ac_cv_header_GL_gl_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GL_H 1" >>confdefs.h fi -done + if test X"$ac_cv_header_GL_gl_h" != Xyes +then : - if test X"$ac_cv_header_GL_gl_h" != Xyes ; then echo "No OpenGL headers found, wx will NOT be usable" >> ./CONF_INFO WXERL_CAN_BUILD_DRIVER=false if test X"$with_wx" = X"yes" ; then as_fn_error $? "No OpenGL headers found, wx will NOT be usable" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No OpenGL headers found, wx will NOT be usable" >&5 -$as_echo "$as_me: WARNING: No OpenGL headers found, wx will NOT be usable" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No OpenGL headers found, wx will NOT be usable" >&5 +printf "%s\n" "$as_me: WARNING: No OpenGL headers found, wx will NOT be usable" >&2;} fi CPPFLAGS="$saved_CPPFLAGS" - else + +else $as_nop + GL_LIBS="-L/usr/local/lib $GL_LIBS" - fi - else + +fi + +else $as_nop + GL_LIBS="-L/usr/X11R6/lib $GL_LIBS" - fi - fi -else - for ac_header in gl/gl.h -do : - ac_fn_c_check_header_compile "$LINENO" "gl/gl.h" "ac_cv_header_gl_gl_h" "#include + +fi + +fi + +else $as_nop + + ac_fn_c_check_header_compile "$LINENO" "gl/gl.h" "ac_cv_header_gl_gl_h" "#include " -if test "x$ac_cv_header_gl_gl_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GL_H 1 -_ACEOF +if test "x$ac_cv_header_gl_gl_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GL_H 1" >>confdefs.h fi -done fi -if test X"$host_os" != X"win32" ; then - for ac_header in GL/glu.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "GL/glu.h" "ac_cv_header_GL_glu_h" "$ac_includes_default" -if test "x$ac_cv_header_GL_glu_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GLU_H 1 -_ACEOF +if test X"$host_os" != X"win32" +then : -else - for ac_header in OpenGL/glu.h + for ac_header in GL/glu.h do : - ac_fn_c_check_header_mongrel "$LINENO" "OpenGL/glu.h" "ac_cv_header_OpenGL_glu_h" "$ac_includes_default" -if test "x$ac_cv_header_OpenGL_glu_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_OPENGL_GLU_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "GL/glu.h" "ac_cv_header_GL_glu_h" "$ac_includes_default" +if test "x$ac_cv_header_GL_glu_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GLU_H 1" >>confdefs.h -fi +else $as_nop + ac_fn_c_check_header_compile "$LINENO" "OpenGL/glu.h" "ac_cv_header_OpenGL_glu_h" "$ac_includes_default" +if test "x$ac_cv_header_OpenGL_glu_h" = xyes +then : + printf "%s\n" "#define HAVE_OPENGL_GLU_H 1" >>confdefs.h -done +fi fi done - if test X"$ac_cv_header_GL_glu_h" != Xyes && test X"$ac_cv_header_OpenGL_glu_h" != Xyes then @@ -4658,24 +5498,22 @@ done if test X"$with_wx" = X"yes" ; then as_fn_error $? "No GLU headers found, wx will NOT be usable" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No GLU headers found, wx will NOT be usable" >&5 -$as_echo "$as_me: WARNING: No GLU headers found, wx will NOT be usable" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: No GLU headers found, wx will NOT be usable" >&5 +printf "%s\n" "$as_me: WARNING: No GLU headers found, wx will NOT be usable" >&2;} fi fi -else - for ac_header in gl/glu.h -do : - ac_fn_c_check_header_compile "$LINENO" "gl/glu.h" "ac_cv_header_gl_glu_h" "#include + +else $as_nop + + ac_fn_c_check_header_compile "$LINENO" "gl/glu.h" "ac_cv_header_gl_glu_h" "#include " -if test "x$ac_cv_header_gl_glu_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GL_GLU_H 1 -_ACEOF +if test "x$ac_cv_header_gl_glu_h" = xyes +then : + printf "%s\n" "#define HAVE_GL_GLU_H 1" >>confdefs.h fi -done fi @@ -4698,18 +5536,22 @@ ERLANG_ROOT_DIR=$ERL_TOP +if test "$cross_compiling" = "yes" +then : -if test "$cross_compiling" = "yes"; then echo "Cross compilation of the wx driver is not supported yet, wx will NOT be usable" >> ./CONF_INFO WXERL_CAN_BUILD_DRIVER=false if test X"$with_wx" = X"yes" ; then as_fn_error $? "Cross compilation of the wx driver is not supported yet, wx will NOT be usable" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cross compilation of the wx driver is not supported yet, wx will NOT be usable" >&5 -$as_echo "$as_me: WARNING: Cross compilation of the wx driver is not supported yet, wx will NOT be usable" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cross compilation of the wx driver is not supported yet, wx will NOT be usable" >&5 +printf "%s\n" "$as_me: WARNING: Cross compilation of the wx driver is not supported yet, wx will NOT be usable" >&2;} fi -elif test X"$MIXED_VC" = X"no"; then + +elif test X"$MIXED_VC" = X"no" +then : + @@ -4763,30 +5605,34 @@ elif test X"$MIXED_VC" = X"no"; then # Check whether --with-wxdir was given. -if test "${with_wxdir+set}" = set; then : +if test ${with_wxdir+y} +then : withval=$with_wxdir; wx_config_name="$withval/wx-config" wx_config_args="--inplace" fi # Check whether --with-wx-config was given. -if test "${with_wx_config+set}" = set; then : +if test ${with_wx_config+y} +then : withval=$with_wx_config; wx_config_name="$withval" fi # Check whether --with-wx-prefix was given. -if test "${with_wx_prefix+set}" = set; then : +if test ${with_wx_prefix+y} +then : withval=$with_wx_prefix; wx_config_prefix="$withval" -else +else $as_nop wx_config_prefix="" fi # Check whether --with-wx-exec-prefix was given. -if test "${with_wx_exec_prefix+set}" = set; then : +if test ${with_wx_exec_prefix+y} +then : withval=$with_wx_exec_prefix; wx_config_exec_prefix="$withval" -else +else $as_nop wx_config_exec_prefix="" fi @@ -4815,19 +5661,20 @@ fi fi if test -x "$WX_CONFIG_NAME" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 -$as_echo_n "checking for wx-config... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 +printf %s "checking for wx-config... " >&6; } WX_CONFIG_PATH="$WX_CONFIG_NAME" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args. set dummy $WX_CONFIG_NAME; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_WX_CONFIG_PATH+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_WX_CONFIG_PATH+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $WX_CONFIG_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path. @@ -4838,11 +5685,15 @@ as_dummy=""$WX_LOOKUP_PATH:$PATH"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_WX_CONFIG_PATH="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_WX_CONFIG_PATH="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4855,11 +5706,11 @@ esac fi WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH if test -n "$WX_CONFIG_PATH"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4870,11 +5721,11 @@ fi min_wx_version=$reqwx if test -z "--unicode" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version... " >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode)" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode)" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version (--unicode)... " >&6; } fi WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args --unicode" @@ -4916,19 +5767,19 @@ $as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode)... " > if test -n "$wx_ver_ok"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 -$as_echo "yes (version $WX_VERSION)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 +printf "%s\n" "yes (version $WX_VERSION)" >&6; } WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs core,base,html,webview` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 -$as_echo_n "checking for wxWidgets static library... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 +printf %s "checking for wxWidgets static library... " >&6; } WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs core,base,html,webview 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi wx_has_cppflags="" @@ -4985,11 +5836,11 @@ $as_echo "yes" >&6; } else if test "x$WX_VERSION" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 -$as_echo "no (version $WX_VERSION is not new enough)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 +printf "%s\n" "no (version $WX_VERSION is not new enough)" >&6; } fi WX_CFLAGS="" @@ -5022,8 +5873,8 @@ $as_echo "no (version $WX_VERSION is not new enough)" >&6; } if test X"$with_wx" = X"yes" ; then as_fn_error $? "$wx_error_message" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $wx_error_message" >&5 -$as_echo "$as_me: WARNING: $wx_error_message" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $wx_error_message" >&5 +printf "%s\n" "$as_me: WARNING: $wx_error_message" >&2;} fi @@ -5059,8 +5910,8 @@ $as_echo "$as_me: WARNING: $wx_error_message" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxwidgets webview" >&5 -$as_echo_n "checking for wxwidgets webview... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxwidgets webview" >&5 +printf %s "checking for wxwidgets webview... " >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5079,7 +5930,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu #include "wx/webview.h" int -main () +main (void) { wxWebView::New(); @@ -5088,12 +5939,13 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : +if ac_fn_cxx_try_link "$LINENO" +then : HAVE_WEBVIEW_SUPPORT=yes -else +else $as_nop HAVE_WEBVIEW_SUPPORT=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$saved_CXXFLAGS @@ -5104,15 +5956,15 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_WEBVIEW_SUPPORT" >&5 -$as_echo "$HAVE_WEBVIEW_SUPPORT" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_WEBVIEW_SUPPORT" >&5 +printf "%s\n" "$HAVE_WEBVIEW_SUPPORT" >&6; } if test X"$HAVE_WEBVIEW_SUPPORT" != X"yes" ; then WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui echo "wxWidgets was not compiled with --enable-webview or wxWebView developer package is not installed, wxWebView will NOT be available" >> ./CONF_INFO else WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui,webview - $as_echo "#define WXE_WEBVIEW 1" >>confdefs.h + printf "%s\n" "#define WXE_WEBVIEW 1" >>confdefs.h fi @@ -5140,19 +5992,20 @@ $as_echo "$HAVE_WEBVIEW_SUPPORT" >&6; } fi if test -x "$WX_CONFIG_NAME" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 -$as_echo_n "checking for wx-config... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 +printf %s "checking for wx-config... " >&6; } WX_CONFIG_PATH="$WX_CONFIG_NAME" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args. set dummy $WX_CONFIG_NAME; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_WX_CONFIG_PATH+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_WX_CONFIG_PATH+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $WX_CONFIG_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path. @@ -5163,11 +6016,15 @@ as_dummy=""$WX_LOOKUP_PATH:$PATH"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_WX_CONFIG_PATH="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_WX_CONFIG_PATH="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5180,11 +6037,11 @@ esac fi WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH if test -n "$WX_CONFIG_PATH"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5195,11 +6052,11 @@ fi min_wx_version=$reqwx if test -z "--unicode --debug=yes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version... " >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode --debug=yes)" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode --debug=yes)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode --debug=yes)" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version (--unicode --debug=yes)... " >&6; } fi WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args --unicode --debug=yes" @@ -5241,19 +6098,19 @@ $as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode --debug if test -n "$wx_ver_ok"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 -$as_echo "yes (version $WX_VERSION)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 +printf "%s\n" "yes (version $WX_VERSION)" >&6; } WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $WXELIBS` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 -$as_echo_n "checking for wxWidgets static library... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 +printf %s "checking for wxWidgets static library... " >&6; } WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $WXELIBS 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi wx_has_cppflags="" @@ -5310,11 +6167,11 @@ $as_echo "yes" >&6; } else if test "x$WX_VERSION" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 -$as_echo "no (version $WX_VERSION is not new enough)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 +printf "%s\n" "no (version $WX_VERSION is not new enough)" >&6; } fi WX_CFLAGS="" @@ -5377,14 +6234,14 @@ $as_echo "no (version $WX_VERSION is not new enough)" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for debug build of wxWidgets" >&5 -$as_echo_n "checking for debug build of wxWidgets... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for debug build of wxWidgets" >&5 +printf %s "checking for debug build of wxWidgets... " >&6; } if test "$wxWinWithGLDBG" = 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; fi DEBUG_WX_CFLAGS=$WX_CFLAGS @@ -5419,19 +6276,20 @@ $as_echo "no" >&6; }; fi if test -x "$WX_CONFIG_NAME" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 -$as_echo_n "checking for wx-config... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 +printf %s "checking for wx-config... " >&6; } WX_CONFIG_PATH="$WX_CONFIG_NAME" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args. set dummy $WX_CONFIG_NAME; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_WX_CONFIG_PATH+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_WX_CONFIG_PATH+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $WX_CONFIG_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path. @@ -5442,11 +6300,15 @@ as_dummy=""$WX_LOOKUP_PATH:$PATH"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_WX_CONFIG_PATH="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_WX_CONFIG_PATH="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5459,11 +6321,11 @@ esac fi WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH if test -n "$WX_CONFIG_PATH"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 -$as_echo "$WX_CONFIG_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5474,11 +6336,11 @@ fi min_wx_version=$reqwx if test -z "--unicode --debug=no" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version... " >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode --debug=no)" >&5 -$as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode --debug=no)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version (--unicode --debug=no)" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version (--unicode --debug=no)... " >&6; } fi WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args --unicode --debug=no" @@ -5520,19 +6382,19 @@ $as_echo_n "checking for wxWidgets version >= $min_wx_version (--unicode --debug if test -n "$wx_ver_ok"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 -$as_echo "yes (version $WX_VERSION)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 +printf "%s\n" "yes (version $WX_VERSION)" >&6; } WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $WXELIBS` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 -$as_echo_n "checking for wxWidgets static library... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 +printf %s "checking for wxWidgets static library... " >&6; } WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $WXELIBS 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi wx_has_cppflags="" @@ -5589,11 +6451,11 @@ $as_echo "yes" >&6; } else if test "x$WX_VERSION" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 -$as_echo "no (version $WX_VERSION is not new enough)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 +printf "%s\n" "no (version $WX_VERSION is not new enough)" >&6; } fi WX_CFLAGS="" @@ -5656,14 +6518,14 @@ $as_echo "no (version $WX_VERSION is not new enough)" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for standard build of wxWidgets" >&5 -$as_echo_n "checking for standard build of wxWidgets... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for standard build of wxWidgets" >&5 +printf %s "checking for standard build of wxWidgets... " >&6; } if test "$wxWinWithGL" = 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; fi if test "x$WX_LIBS_STATIC" = "x"; then @@ -5713,7 +6575,7 @@ $as_echo "no" >&6; }; is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is $reqwx or above." "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: wxWidgets must be installed on your system. Please check that wx-config is in path, the directory @@ -5721,7 +6583,7 @@ $as_echo "no" >&6; }; 'wx-config --libs' or 'wx-config --static --libs' command) is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is $reqwx or above." >&5 -$as_echo "$as_me: WARNING: +printf "%s\n" "$as_me: WARNING: wxWidgets must be installed on your system. Please check that wx-config is in path, the directory @@ -5732,13 +6594,15 @@ $as_echo "$as_me: WARNING: fi fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets in standard locations" >&5 -$as_echo_n "checking for wxWidgets in standard locations... " >&6; } + +else $as_nop + #else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets in standard locations" >&5 +printf %s "checking for wxWidgets in standard locations... " >&6; } echo # Check whether --with-wxdir was given. - { $as_echo "$as_me:${as_lineno-$LINENO}: OptionCheck: $with_wxdir $with_wx_prefix" >&5 -$as_echo "$as_me: OptionCheck: $with_wxdir $with_wx_prefix" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OptionCheck: $with_wxdir $with_wx_prefix" >&5 +printf "%s\n" "$as_me: OptionCheck: $with_wxdir $with_wx_prefix" >&6;} if test "${with_wxdir+set}" = set; then : withval=$with_wxdir; CWXWIN0=$withval @@ -5791,8 +6655,8 @@ $as_echo "$as_me: OptionCheck: $with_wxdir $with_wx_prefix" >&6;} CWXPATH="$CWXWIN0 $CWXWIN1 $CWXWIN2 $CWX_DOCUMENTED $CWXWIN3 $CWXWIN4" for dir in $CWXPATH; do - { $as_echo "$as_me:${as_lineno-$LINENO}: Checking: $dir" >&5 -$as_echo "$as_me: Checking: $dir" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Checking: $dir" >&5 +printf "%s\n" "$as_me: Checking: $dir" >&6;} if test -f $dir/include/wx/wx.h; then WXINCLUDE_MSVC=$dir/include/msvc WXINCLUDE_PLAIN=$dir/include @@ -5815,37 +6679,37 @@ $as_echo "$as_me: Checking: $dir" >&6;} WX_LIBS_STATIC="$WX_LIBS_STATIC -l$lib" done WXDIR=$dir - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Found: $dir" >&5 -$as_echo "Found: $dir" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Found: $dir" >&5 +printf "%s\n" "Found: $dir" >&6; } break fi fi done if test -z "$WX_LIBS_STATIC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } echo "Cannot find core lib version for wxWidgets" >> ./CONF_INFO WXERL_CAN_BUILD_DRIVER=false if test X"$with_wx" = X"yes" ; then as_fn_error $? "Cannot find core lib version for wxWidgets" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find core lib version for wxWidgets" >&5 -$as_echo "$as_me: WARNING: Cannot find core lib version for wxWidgets" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find core lib version for wxWidgets" >&5 +printf "%s\n" "$as_me: WARNING: Cannot find core lib version for wxWidgets" >&2;} fi fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for edge webview loader" >&5 -$as_echo_n "checking for edge webview loader... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for edge webview loader" >&5 +printf %s "checking for edge webview loader... " >&6; } WEBVIEW_DLL=$WXDIR/3rdparty/webview2/build/native/$WX_ARCH/WebView2Loader.dll if test -f "$WEBVIEW_DLL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WEBVIEW_DLL" >&5 -$as_echo "$WEBVIEW_DLL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WEBVIEW_DLL" >&5 +printf "%s\n" "$WEBVIEW_DLL" >&6; } WX_WEBVIEW_DLL=$WEBVIEW_DLL else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found in $WEBVIEW_DLL" >&5 -$as_echo "not found in $WEBVIEW_DLL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found in $WEBVIEW_DLL" >&5 +printf "%s\n" "not found in $WEBVIEW_DLL" >&6; } WX_WEBVIEW_DLL= fi @@ -5856,17 +6720,20 @@ $as_echo "not found in $WEBVIEW_DLL" >&6; } - $as_echo "#define WXE_WEBVIEW 1" >>confdefs.h + printf "%s\n" "#define WXE_WEBVIEW 1" >>confdefs.h + fi -if test "$WXERL_CAN_BUILD_DRIVER" != "false"; then +if test "$WXERL_CAN_BUILD_DRIVER" != "false" +then : -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxwidgets 3.0 compatibility " >&5 -$as_echo_n "checking for wxwidgets 3.0 compatibility ... " >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxwidgets 3.0 compatibility " >&5 +printf %s "checking for wxwidgets 3.0 compatibility ... " >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5882,7 +6749,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include "wx/wx.h" int -main () +main (void) { #if wxMAJOR_VERSION > 2 && (wxMINOR_VERSION == 0 || WXWIN_COMPATIBILITY_3_0 == 1) @@ -5895,12 +6762,13 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : HAVE_COMPAT30_SUPPORT=yes -else +else $as_nop HAVE_COMPAT30_SUPPORT=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$saved_CXXFLAGS ac_ext=c @@ -5909,8 +6777,8 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_COMPAT30_SUPPORT" >&5 -$as_echo "$HAVE_COMPAT30_SUPPORT" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_COMPAT30_SUPPORT" >&5 +printf "%s\n" "$HAVE_COMPAT30_SUPPORT" >&6; } if test X"$HAVE_COMPAT30_SUPPORT" != X"yes" ; then echo "wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" >> ./CONF_INFO @@ -5918,14 +6786,14 @@ if test X"$HAVE_COMPAT30_SUPPORT" != X"yes" ; then if test X"$with_wx" = X"yes" ; then as_fn_error $? "wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" >&5 -$as_echo "$as_me: WARNING: wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" >&5 +printf "%s\n" "$as_me: WARNING: wxWidgets was not compiled with --enable-compat30, wx will NOT be useable" >&2;} fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxwidgets opengl support" >&5 -$as_echo_n "checking for wxwidgets opengl support... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxwidgets opengl support" >&5 +printf %s "checking for wxwidgets opengl support... " >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5941,7 +6809,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include "wx/wx.h" int -main () +main (void) { #if wxUSE_GLCANVAS @@ -5954,15 +6822,16 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : HAVE_GL_SUPPORT=yes -$as_echo "#define HAVE_GL_SUPPORT 1" >>confdefs.h +printf "%s\n" "#define HAVE_GL_SUPPORT 1" >>confdefs.h -else +else $as_nop HAVE_GL_SUPPORT=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$saved_CXXFLAGS ac_ext=c @@ -5971,8 +6840,8 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GL_SUPPORT" >&5 -$as_echo "$HAVE_GL_SUPPORT" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_GL_SUPPORT" >&5 +printf "%s\n" "$HAVE_GL_SUPPORT" >&6; } if test X"$HAVE_GL_SUPPORT" != X"yes" ; then @@ -5981,8 +6850,8 @@ if test X"$HAVE_GL_SUPPORT" != X"yes" ; then if test X"$with_wx" = X"yes" ; then as_fn_error $? "wxWidgets don't have gl support, wx will NOT be useable" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: wxWidgets don't have gl support, wx will NOT be useable" >&5 -$as_echo "$as_me: WARNING: wxWidgets don't have gl support, wx will NOT be useable" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: wxWidgets don't have gl support, wx will NOT be useable" >&5 +printf "%s\n" "$as_me: WARNING: wxWidgets don't have gl support, wx will NOT be useable" >&2;} fi fi @@ -5998,11 +6867,10 @@ ac_fn_c_check_type "$LINENO" "GLintptr" "ac_cv_type_GLintptr" "#ifdef WIN32 #endif " -if test "x$ac_cv_type_GLintptr" = xyes; then : +if test "x$ac_cv_type_GLintptr" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLINTPTR 1 -_ACEOF +printf "%s\n" "#define HAVE_GLINTPTR 1" >>confdefs.h fi @@ -6016,11 +6884,10 @@ ac_fn_c_check_type "$LINENO" "GLintptrARB" "ac_cv_type_GLintptrARB" "#ifdef WIN3 #endif " -if test "x$ac_cv_type_GLintptrARB" = xyes; then : +if test "x$ac_cv_type_GLintptrARB" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLINTPTRARB 1 -_ACEOF +printf "%s\n" "#define HAVE_GLINTPTRARB 1" >>confdefs.h fi @@ -6034,11 +6901,10 @@ ac_fn_c_check_type "$LINENO" "GLchar" "ac_cv_type_GLchar" "#ifdef WIN32 #endif " -if test "x$ac_cv_type_GLchar" = xyes; then : +if test "x$ac_cv_type_GLchar" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLCHAR 1 -_ACEOF +printf "%s\n" "#define HAVE_GLCHAR 1" >>confdefs.h fi @@ -6052,11 +6918,10 @@ ac_fn_c_check_type "$LINENO" "GLcharARB" "ac_cv_type_GLcharARB" "#ifdef WIN32 #endif " -if test "x$ac_cv_type_GLcharARB" = xyes; then : +if test "x$ac_cv_type_GLcharARB" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLCHARARB 1 -_ACEOF +printf "%s\n" "#define HAVE_GLCHARARB 1" >>confdefs.h fi @@ -6070,11 +6935,10 @@ ac_fn_c_check_type "$LINENO" "GLhalfARB" "ac_cv_type_GLhalfARB" "#ifdef WIN32 #endif " -if test "x$ac_cv_type_GLhalfARB" = xyes; then : +if test "x$ac_cv_type_GLhalfARB" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLHALFARB 1 -_ACEOF +printf "%s\n" "#define HAVE_GLHALFARB 1" >>confdefs.h fi @@ -6088,18 +6952,17 @@ ac_fn_c_check_type "$LINENO" "GLint64EXT" "ac_cv_type_GLint64EXT" "#ifdef WIN32 #endif " -if test "x$ac_cv_type_GLint64EXT" = xyes; then : +if test "x$ac_cv_type_GLint64EXT" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_GLINT64EXT 1 -_ACEOF +printf "%s\n" "#define HAVE_GLINT64EXT 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking GLU Callbacks uses Tiger Style" >&5 -$as_echo_n "checking GLU Callbacks uses Tiger Style... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking GLU Callbacks uses Tiger Style" >&5 +printf %s "checking GLU Callbacks uses Tiger Style... " >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6126,7 +6989,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext void CALLBACK foo() {}; int -main () +main (void) { GLUtesselator* tess; @@ -6136,26 +6999,29 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : TESS_CB_TIGER_STYLE=yes -$as_echo "#define TESS_CB_TIGER_STYLE 1" >>confdefs.h +printf "%s\n" "#define TESS_CB_TIGER_STYLE 1" >>confdefs.h -else +else $as_nop TESS_CB_TIGER_STYLE=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESS_CB_TIGER_STYLE" >&5 -$as_echo "$TESS_CB_TIGER_STYLE" >&6; } +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TESS_CB_TIGER_STYLE" >&5 +printf "%s\n" "$TESS_CB_TIGER_STYLE" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can link wxwidgets programs" >&5 -$as_echo_n "checking if we can link wxwidgets programs... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can link wxwidgets programs" >&5 +printf %s "checking if we can link wxwidgets programs... " >&6; } saved_LIBS=$LIBS if test X"$WX_HAVE_STATIC_LIBS" = X"true" ; then LIBS=$WX_LIBS_STATIC +else + LIBS=$WX_LIBS fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6178,16 +7044,17 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext IMPLEMENT_APP(MyApp) _ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : +if ac_fn_cxx_try_link "$LINENO" +then : CAN_LINK_WX=yes -else +else $as_nop CAN_LINK_WX=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$saved_CXXFLAGS @@ -6198,8 +7065,8 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CAN_LINK_WX" >&5 -$as_echo "$CAN_LINK_WX" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CAN_LINK_WX" >&5 +printf "%s\n" "$CAN_LINK_WX" >&6; } if test X"$CAN_LINK_WX" != X"yes" ; then echo "Can not link wx program are all developer packages installed?" >> ./CONF_INFO @@ -6207,100 +7074,101 @@ if test X"$CAN_LINK_WX" != X"yes" ; then if test X"$with_wx" = X"yes" ; then as_fn_error $? "Can not link wx program are all developer packages installed?" "$LINENO" 5 else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can not link wx program are all developer packages installed?" >&5 -$as_echo "$as_me: WARNING: Can not link wx program are all developer packages installed?" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Can not link wx program are all developer packages installed?" >&5 +printf "%s\n" "$as_me: WARNING: Can not link wx program are all developer packages installed?" >&2;} fi fi + fi +LDFLAGS="$LDFLAGS$EXTRA_LDFLAGS" + -if test "x$GCC" = xyes; then +if test "x$GCC" = xyes +then : + # Treat certain GCC warnings as errors - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to CFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $CFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } CFLAGS="-Werror=return-type $CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CXXFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to CXXFLAGS (via CFLAGS)... " >&6; } +fi + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to CXXFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to CXXFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $CXXFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } CXXFLAGS="-Werror=return-type $CXXFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi -fi +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi -# Check whether --enable-sanitizers was given. -if test "${enable_sanitizers+set}" = set; then : - enableval=$enable_sanitizers; -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=address,undefined" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -CXXFLAGS="$CXXFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" fi - ############################################################################# @@ -6317,12 +7185,7 @@ esac - -if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then - WXERL_SYS_TYPE=`erl -noshell -eval 'io:format("~s~n",[erlang:system_info(system_architecture)])' -s erlang halt` -else - WXERL_SYS_TYPE=$TARGET -fi +WXERL_SYS_TYPE=$TARGET @@ -6360,8 +7223,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -6391,15 +7254,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -6413,8 +7276,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -6467,7 +7330,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -6483,8 +7346,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -6507,14 +7370,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -6524,46 +7389,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -6572,13 +7437,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -6587,8 +7445,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -6600,30 +7462,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -6636,13 +7478,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -6669,18 +7512,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -6692,12 +7537,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -6728,7 +7574,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -6750,6 +7596,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -6763,6 +7613,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -6804,7 +7660,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -6813,7 +7669,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6876,7 +7732,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -6925,14 +7781,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -6969,21 +7827,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -7011,7 +7869,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -7025,7 +7883,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -7051,7 +7909,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -7279,7 +8137,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -7287,17 +8145,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -7314,7 +8172,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -7338,9 +8196,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -7393,8 +8251,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -7436,9 +8294,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -7485,8 +8343,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi @@ -7497,3 +8355,4 @@ fi + diff --git a/lib/wx/configure.ac b/lib/wx/configure.ac new file mode 100644 index 000000000000..db930a7e8496 --- /dev/null +++ b/lib/wx/configure.ac @@ -0,0 +1,759 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 2008-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% + +AC_INIT + +m4_include([otp.m4]) + +AC_CONFIG_AUX_DIR([${ERL_TOP}/make/autoconf]) + +AC_PREREQ([2.71]) + +## Delete previous failed configure results +if test -f ./CONF_INFO; then + rm ./CONF_INFO +fi + +AC_DEFUN([WX_MSG_ERROR], +[ echo "$1" >> ./CONF_INFO + WXERL_CAN_BUILD_DRIVER=false + if test X"$with_wx" = X"yes" ; then + AC_MSG_ERROR([$1]) + else + AC_MSG_WARN([$1]) + fi +]) + +AC_ARG_WITH(wx, +[ --with-wxdir=PATH specify location of wxWidgets include and lib + --with-wx use wxWidgets (default) + --without-wx don't use wxWidgets]) + +ERL_CANONICAL_SYSTEM_TYPE + +case $host_os in + mingw32) + if test "X$host" = "X"; then + host=win32 + fi + ;; + *) + ;; +esac + +TARGET=$host +AC_SUBST(TARGET) + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_RANLIB +AC_PROG_CPP + +AC_LANG_PUSH([C++]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[#ifndef __cplusplus + #error "broken C++" + #endif]])],, + [CXX=;]) +AC_LANG_POP([C++]) +if test "X$CXX" = X ; then + WX_MSG_ERROR([Can not find C++ compiler]) +fi +WXERL_CAN_BUILD_DRIVER=false + +AC_MSG_NOTICE(Building for [$host_os]) +WXERL_CAN_BUILD_DRIVER=true + +LM_WINDOWS_ENVIRONMENT + +USER_CFLAGS=$CFLAGS + +if test X"$MIXED_VC" = X"yes" ; then + CFLAGS="-Owx" +fi + +AC_CHECK_SIZEOF(void *) + +PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT" + +OBJC_CC=$CC +OBJC_CFLAGS="" +CXXFLAGS="" +dnl NOTE: CPPFLAGS will be included in CFLAGS at the end +AS_CASE([$host_os], + + [darwin*], + [ + AC_MSG_CHECKING([Checking wxWidgets for min version:]) + WX_CC=`wx-config --cc` + MAC_MIN=`echo "$WX_CC" | sed 's/^[[^ ]]*\ *//'` + AC_MSG_RESULT([$MAC_MIN]) + + AC_MSG_CHECKING([if compiler accepts -ObjC]) + CFLAGS="$CFLAGS -ObjC" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[;]])],[accept_objc_flag=true],[accept_objc_flag=false]) + if test "X$accept_objc_flag" = "Xtrue"; then + AC_MSG_RESULT([yes]) + C_ONLY_FLAGS="-ObjC" + else + dnl We are probably trying to build with a non-Apple gcc, + dnl which is good as long as we do not try to build Cocoa + dnl code. We need an Apple compiler for just that (Objective C) + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([for a Cocoa compliant Objective C compiler]) + SEARCHFOR="" + SEARCHFORXX="" + save_IFS=$IFS + IFS=: + set $PATH + IFS=$save_IFS + while test X"$1" != X""; do + dnl Add all possible paths to a real apple gcc + SEARCHFOR="$1/gcc-apple-4.2 $SEARCHFOR" + SEARCHFORXX="$1/g++-apple-4.2 $SEARCHFORXX" + shift + done + dnl Add LLVM compilers, they will work in this case + SEARCHFOR="/usr/bin/clang /usr/bin/gcc $SEARCHFOR" + SEARCHFORXX="/usr/bin/clang /usr/bin/g++ $SEARCHFORXX" + APPLE_CC="" + APPLE_CXX="" + dnl SEARCHFOR is reversed, so we want to find the last existing + dnl executable in the list + IFS=" " + set $SEARCHFORXX + for x in $SEARCHFOR; do + if test -x $x; then + APPLE_CC=$x + fi + if test -x "$1"; then + APPLE_CXX="$1" + fi + shift + done + IFS=$save_IFS + if test X$APPLE_CC = X -o X$APPLE_CXX = X; then + AC_MSG_RESULT([no]) + dnl Complete failure, we cannot build Cocoa code + WX_MSG_ERROR([Can not find compiler to compile Cocoa applications]) + else + dnl We think we found an Apple compiler and will add + dnl Apple specific options + AC_MSG_RESULT([$APPLE_CC ($APPLE_CXX)]) + dnl We should use this compiler for all of wx - hack... + CC=$APPLE_CC + CXX=$APPLE_CXX + dnl Both clang and gcc accept these flags... + #CXXFLAGS="-x c++ $CXXFLAGS" + OBJC_CC=$APPLE_CC + OBJC_CFLAGS="-ObjC" + fi + fi + CFLAGS="$USER_CFLAGS $MAC_MIN -Wno-deprecated-declarations" + CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" + ], + + [mingw32], + [ + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" + AC_MSG_WARN([Reverting to 32-bit time_t]) + CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" + ], + + [win32], + [ + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" + ], + + [ + GLIB_CFLAGS=`pkg-config --silence-errors --cflags glib-2.0` + GLIB_LIBS=`pkg-config --silence-errors --libs glib-2.0` + if test X"$GLIB_CFLAGS" != X ; then + HAVE_GLIB="-DHAVE_GLIB=1" + fi + CFLAGS="$CFLAGS -Wno-deprecated-declarations" + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE $PTHR_CFLAGS $HAVE_GLIB" + ]) + +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + +AC_SUBST(OBJC_CC) +AC_SUBST(OBJC_CFLAGS) + +EXTRA_LDFLAGS= + +case $host_os in + darwin*) + # beam.smp has not been built yet, so we must not use the + # -bundle_loader option in the configuration tests. + LDFLAGS="$MAC_MIN -bundle $LDFLAGS" + EXTRA_LDFLAGS=" -bundle_loader ${ERL_TOP}/bin/$host/beam.smp" + GL_LIBS="-framework OpenGL" + ;; + win32) + LDFLAGS="-dll $LDFLAGS" + GL_LIBS="-lglu32 -lOpengl32" + ;; + mingw32) + LDFLAGS="-shared -fPIC $LDFLAGS" + GL_LIBS="-lglu32 -lOpengl32" + ;; + *) + LDFLAGS="-shared -fPIC $LDFLAGS" + GL_LIBS="-lGL -lGLU" + ;; +esac + +dnl ---------------------------------------------------------------------- +dnl Include CPPFLAGS in CFLAGS +dnl ---------------------------------------------------------------------- + +case $host_os in + mingw32) + DEBUG_CFLAGS="-g -Wall -DDEBUG $CFLAGS" + CFLAGS="-g -Wall -O2 $CFLAGS -fomit-frame-pointer -fno-strict-aliasing" + ;; + win32) + DEBUG_CFLAGS="-g -Wall $CFLAGS -DDEBUG" + CFLAGS="-g -Wall -O2 $CFLAGS" + ;; + darwin*) + DEBUG_CFLAGS="-g -Wall -fPIC $CFLAGS -DDEBUG" + # omit-frame-pointer causes seg faults with 10.9 and clang + CFLAGS="-g -Wall -fPIC $CFLAGS -fno-strict-aliasing" + ;; + *) + DEBUG_CFLAGS="-g -Wall -fPIC $CFLAGS -DDEBUG" + CFLAGS="-Wall -fPIC $CFLAGS -fomit-frame-pointer -fno-strict-aliasing" + ;; +esac + +dnl +dnl Use -O1 -fno-move-loop-invariants for wxe_funcs.cpp to reduce +dnl compilation time +dnl + +AS_IF([test "x$GCC" = xyes -a X"$host_os" != X"win32"], + [ + CXXNOOPT="-O1" + LM_TRY_ENABLE_CFLAG([-fno-move-loop-invariants], [CXXNOOPT]) + LM_TRY_ENABLE_CFLAG([-fno-var-tracking-assignments], [CXXNOOPT]) + ]) + +dnl +dnl Opengl tests +dnl + +AS_IF([test X"$host_os" != X"win32"], + [ + AC_CHECK_HEADERS([GL/gl.h], [], + [AC_CHECK_HEADERS([OpenGL/gl.h])]) + AS_IF([test X"$ac_cv_header_GL_gl_h" != Xyes && test X"$ac_cv_header_OpenGL_gl_h" != Xyes], + [ + saved_CPPFLAGS="$CPPFLAGS" + AC_MSG_NOTICE(Checking for OpenGL headers in /usr/X11R6) + CPPFLAGS="-isystem /usr/X11R6/include $CPPFLAGS" + $as_unset ac_cv_header_GL_gl_h + AC_CHECK_HEADERS([GL/gl.h]) + AS_IF([test X"$ac_cv_header_GL_gl_h" != Xyes], + [ + AC_MSG_NOTICE(Checking for OpenGL headers in /usr/local) + CPPFLAGS="-isystem /usr/local/include $saved_CPPFLAGS" + $as_unset ac_cv_header_GL_gl_h + AC_CHECK_HEADERS([GL/gl.h]) + AS_IF([test X"$ac_cv_header_GL_gl_h" != Xyes], + [ + WX_MSG_ERROR([No OpenGL headers found, wx will NOT be usable]) + CPPFLAGS="$saved_CPPFLAGS" + ], + [ + GL_LIBS="-L/usr/local/lib $GL_LIBS" + ]) + ], + [ + GL_LIBS="-L/usr/X11R6/lib $GL_LIBS" + ]) + ]) + ], + [ + AC_CHECK_HEADERS([gl/gl.h],[],[],[#include ]) + ]) + +AS_IF([test X"$host_os" != X"win32"], + [ + AC_CHECK_HEADERS([GL/glu.h], [], + [AC_CHECK_HEADERS([OpenGL/glu.h])]) + if test X"$ac_cv_header_GL_glu_h" != Xyes && + test X"$ac_cv_header_OpenGL_glu_h" != Xyes + then + WX_MSG_ERROR([No GLU headers found, wx will NOT be usable]) + fi + ], + [ + AC_CHECK_HEADERS([gl/glu.h],[],[],[#include ]) + ]) + +AC_SUBST(GL_LIBS) + +DEBUG_CXXFLAGS="$CXXFLAGS $DEBUG_CFLAGS $CPPFLAGS" +DEBUG_CFLAGS="$DEBUG_CFLAGS $CPPFLAGS $C_ONLY_FLAGS" + +CXXNOOPTFLAGS="$CXXFLAGS $CFLAGS $CPPFLAGS $CXXNOOPT" +CXXFLAGS="$CXXFLAGS $CFLAGS $CPPFLAGS" +CFLAGS="$CFLAGS $CPPFLAGS $C_ONLY_FLAGS" + +AC_SUBST(DEBUG_CFLAGS) +AC_SUBST(DEBUG_CXXFLAGS) + +ERLC=erlc +ERL=erl +ERLANG_ROOT_DIR=$ERL_TOP +AC_SUBST(ERLC) + +AC_SUBST(ERLANG_ROOT_DIR) + +dnl +dnl Check for wxwidgets +dnl +AS_IF( + [test "$cross_compiling" = "yes"], + [ + WX_MSG_ERROR([Cross compilation of the wx driver is not supported yet, wx will NOT be usable]) + ], + + [test X"$MIXED_VC" = X"no"], + [ + m4_include(wxwin-nothrow.m4) + + AM_OPTIONS_WXCONFIG + reqwx=3.0.2 + AM_PATH_WXCONFIG($reqwx, [], [], [core,base,html,webview], [--unicode]) + AC_MSG_CHECKING(for wxwidgets webview) + AC_LANG_PUSH(C++) + saved_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" + saved_LIBS=$LIBS + LIBS=$WX_LIBS + + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ + #include "wx/wx.h" + #include "wx/webview.h" + ]], [[ + wxWebView::New(); + ]])], + HAVE_WEBVIEW_SUPPORT=yes, HAVE_WEBVIEW_SUPPORT=no) + + CXXFLAGS=$saved_CXXFLAGS + LIBS=$saved_LIBS + AC_LANG_POP(C++) + AC_MSG_RESULT($HAVE_WEBVIEW_SUPPORT) + + if test X"$HAVE_WEBVIEW_SUPPORT" != X"yes" ; then + WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui + echo "wxWidgets was not compiled with --enable-webview or wxWebView developer package is not installed, wxWebView will NOT be available" >> ./CONF_INFO + else + WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui,webview + AC_DEFINE([WXE_WEBVIEW]) + fi + + # Try to find debug libs first + AM_PATH_WXCONFIG($reqwx, wxWinWithGLDBG=1, wxWinWithGLDBG=0, [$WXELIBS], [--unicode --debug=yes]) + + AC_MSG_CHECKING(for debug build of wxWidgets) + if test "$wxWinWithGLDBG" = 1; then + AC_MSG_RESULT(yes); + else + AC_MSG_RESULT(no); + fi + + DEBUG_WX_CFLAGS=$WX_CFLAGS + DEBUG_WX_CXXFLAGS=$WX_CXXFLAGS + DEBUG_WX_LIBS=$WX_LIBS + DEBUG_WX_LIBS_STATIC=$WX_LIBS_STATIC + AC_SUBST(DEBUG_WX_CFLAGS) + AC_SUBST(DEBUG_WX_CXXFLAGS) + AC_SUBST(DEBUG_WX_LIBS) + AC_SUBST(DEBUG_WX_LIBS_STATIC) + + AM_PATH_WXCONFIG($reqwx, wxWinWithGL=1, wxWinWithGL=0, [$WXELIBS], [--unicode --debug=no]) + + AC_MSG_CHECKING(for standard build of wxWidgets) + if test "$wxWinWithGL" = 1; then + AC_MSG_RESULT(yes); + else + AC_MSG_RESULT(no); + fi + + if test "x$WX_LIBS_STATIC" = "x"; then + WX_HAVE_STATIC_LIBS=false + else + WX_HAVE_STATIC_LIBS=true + fi + + wxWin=0 + + if test "$wxWinWithGLDBG" = 1; then + if test "$wxWinWithGL" = 1; then + wxWin=1 + FORCED_DEBUG_BUILD=false + else + wxWin=1 + FORCED_DEBUG_BUILD=debug + WX_CFLAGS=$DEBUG_WX_CFLAGS + WX_CXXFLAGS=$DEBUG_WX_CXXFLAGS + WX_LIBS=$DEBUG_WX_LIBS + WX_LIBS_STATIC=$DEBUG_WX_LIBS_STATIC + fi + elif test "$wxWinWithGL" = 1; then + wxWin=1 + FORCED_DEBUG_BUILD=false + fi + AC_SUBST(FORCED_DEBUG_BUILD) + RC_FILE_TYPE=o + + if test "$wxWin" != 1; then + WX_MSG_ERROR([ + wxWidgets must be installed on your system. + + Please check that wx-config is in path, the directory + where wxWidgets libraries are installed (returned by + 'wx-config --libs' or 'wx-config --static --libs' command) + is in LD_LIBRARY_PATH or equivalent variable and + wxWidgets version is $reqwx or above.]) + fi + ], + + [ #else + AC_MSG_CHECKING(for wxWidgets in standard locations) + echo + # Check whether --with-wxdir was given. + AC_MSG_NOTICE(OptionCheck: [$with_wxdir $with_wx_prefix]) + + if test "${with_wxdir+set}" = set; then : + withval=$with_wxdir; CWXWIN0=$withval + else + # Check whether --with-wx-prefix was given. + if test "${with_wx_prefix+set}" = set; then : + withval=$with_wx_prefix; CWXWIN0=$withval + else + CWXWIN0="" + fi + fi + + CWXWIN_CONFIG=`win32_path.sh -u $wx_config_name 2>/dev/null` + CWXWIN1=`dirname $CWXWIN_CONFIG 2>/dev/null` + CWXWIN2=`dirname $CWXWIN1 2>/dev/null` + + if test -z "$PROGRAMFILES" ; then + PROGRAMFILES="c:/Program Files" + fi + + CWXWIN_PROG=`win32_path.sh -u "$PROGRAMFILES" 2>/dev/null` + + CWXWIN3="$CWXWIN_PROG/wxWidgets-3.*.* + CWXWIN4="$CWXWIN_PROG/wxMSW-3.*.* + + DOC_OPT1=/opt/local/pgm + DOC_OPT2=/mnt/c/opt/local/pgm + CWX_DOCUMENTED="$DOC_OPT1/wxWidgets-3.*.* $DOC_OPT1/wxMSW-3.*.*" + CWX_DOCUMENTED="$DOC_OPT2/wxWidgets-3.*.* $DOC_OPT2/wxMSW-3.*.* $CWX_DOCUMENTED" + + case $ac_cv_sizeof_void_p in + 8) + VC_LIB=lib/vc_x64_lib + WX_ARCH=x64 + DOC_OPT64_1=/opt/local64/pgm + DOC_OPT64_2=/mnt/c/opt/local64/pgm + CWX_DOCUMENTED="$DOC_OPT64_1/wxWidgets-3.*.* $DOC_OPT64_1/wxMSW-3.*.* $CWX_DOCUMENTED" + CWX_DOCUMENTED="$DOC_OPT64_2/wxWidgets-3.*.* $DOC_OPT64_2/wxMSW-3.*.* $CWX_DOCUMENTED" + ;; + *) + VC_LIB=lib/vc_lib + WX_ARCH=x86 + DOC_OPT3=/opt/local32/pgm + DOC_OPT4=/mnt/c/opt/local32/pgm + CWX_DOCUMENTED="$DOC_OPT3/wxWidgets-3.*.* $DOC_OPT3/wxMSW-3.*.* $CWX_DOCUMENTED" + CWX_DOCUMENTED="$DOC_OPT4/wxWidgets-3.*.* $DOC_OPT4/wxMSW-3.*.* $CWX_DOCUMENTED" + ;; + esac + + CWXPATH="$CWXWIN0 $CWXWIN1 $CWXWIN2 $CWX_DOCUMENTED $CWXWIN3 $CWXWIN4" + + for dir in $CWXPATH; do + AC_MSG_NOTICE(Checking: [$dir]) + if test -f $dir/include/wx/wx.h; then + WXINCLUDE_MSVC=$dir/include/msvc + WXINCLUDE_PLAIN=$dir/include + WX_CFLAGS="-EHsc -D_UNICODE -DUNICODE -I$WXINCLUDE_MSVC -I$WXINCLUDE_PLAIN -D__WXMSW__" + WX_CXXFLAGS="-TP $WX_CFLAGS" + WX_LIBDIR=$dir/$VC_LIB + WX_RESCOMP="rc.sh -I$WXINCLUDE_PLAIN -D __WIN32__" + RC_FILE_TYPE=res + base=`ls $WX_LIBDIR/wxbase*.lib 2> /dev/null | egrep 'wxbase[[0-9]]*u\.lib'` + corelib_number=`echo $base | sed 's,.*\([[0-9]].\)u\.lib,\1,'` + if test '!' -z "$corelib_number"; then + WXLIBNO=$corelib_number + WX_LIBS0="wxmsw${WXLIBNO}u_stc wxmsw${WXLIBNO}u_xrc wxmsw${WXLIBNO}u_html" + WX_LIBS1="wxmsw${WXLIBNO}u_adv wxbase${WXLIBNO}u_xml wxmsw${WXLIBNO}u_core" + WX_LIBS2="wxbase${WXLIBNO}u wxmsw${WXLIBNO}u_gl wxmsw${WXLIBNO}u_aui" + WX_LIBS3="wxregexu wxexpat wxtiff wxjpeg wxpng wxzlib" + WX_SYSLIBS="winspool winmm oleaut32 ole32 gdiplus" + WX_LIBS_STATIC="-L$WX_LIBDIR" + for lib in $WX_LIBS0 $WX_LIBS1 $WX_LIBS2 $WX_LIBS3 $WX_SYSLIBS; do + WX_LIBS_STATIC="$WX_LIBS_STATIC -l$lib" + done + WXDIR=$dir + AC_MSG_RESULT([Found: $dir]) + break + fi + fi + done + + if test -z "$WX_LIBS_STATIC"; then + AC_MSG_RESULT([failed]) + WX_MSG_ERROR([Cannot find core lib version for wxWidgets]) + fi + + AC_MSG_CHECKING(for edge webview loader) + WEBVIEW_DLL=$WXDIR/3rdparty/webview2/build/native/$WX_ARCH/WebView2Loader.dll + if test -f "$WEBVIEW_DLL"; then + AC_MSG_RESULT([$WEBVIEW_DLL]) + WX_WEBVIEW_DLL=$WEBVIEW_DLL + else + AC_MSG_RESULT(not found in $WEBVIEW_DLL) + WX_WEBVIEW_DLL= + fi + + + WX_HAVE_STATIC_LIBS=true + AC_SUBST(WX_CFLAGS) + AC_SUBST(WX_CXXFLAGS) + AC_SUBST(WX_LIBS_STATIC) + AC_SUBST(WX_RESCOMP) + AC_SUBST(WX_WEBVIEW_DLL) + AC_DEFINE([WXE_WEBVIEW]) + ]) + +AS_IF([test "$WXERL_CAN_BUILD_DRIVER" != "false"], +[ + +AC_SUBST(WX_HAVE_STATIC_LIBS) +AC_SUBST(RC_FILE_TYPE) + +AC_MSG_CHECKING(for wxwidgets 3.0 compatibility ) +AC_LANG_PUSH(C++) +saved_CXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include "wx/wx.h" + ]], [[ + #if wxMAJOR_VERSION > 2 && (wxMINOR_VERSION == 0 || WXWIN_COMPATIBILITY_3_0 == 1) + ; + #else + #error barf + #endif + ]])], + HAVE_COMPAT30_SUPPORT=yes, HAVE_COMPAT30_SUPPORT=no) + +CXXFLAGS=$saved_CXXFLAGS +AC_LANG_POP(C++) +AC_MSG_RESULT($HAVE_COMPAT30_SUPPORT) + +if test X"$HAVE_COMPAT30_SUPPORT" != X"yes" ; then + WX_MSG_ERROR([wxWidgets was not compiled with --enable-compat30, wx will NOT be useable]) +fi + +AC_MSG_CHECKING(for wxwidgets opengl support) +AC_LANG_PUSH(C++) +saved_CXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #include "wx/wx.h" + ]], [[ + #if wxUSE_GLCANVAS + ; + #else + #error barf + #endif + ]])], +[HAVE_GL_SUPPORT=yes + AC_DEFINE(HAVE_GL_SUPPORT, [1], [Define if wxwidgets have gl support])], + HAVE_GL_SUPPORT=no) + +CXXFLAGS=$saved_CXXFLAGS +AC_LANG_POP(C++) +AC_MSG_RESULT($HAVE_GL_SUPPORT) +AC_SUBST(HAVE_GL_SUPPORT) + +if test X"$HAVE_GL_SUPPORT" != X"yes" ; then + WX_MSG_ERROR([wxWidgets don't have gl support, wx will NOT be useable]) +fi + +dnl Check for GLintptr +dnl We define the types glext.h so we don't depend on glext.h is updated +dnl to the latest version, but some systems defined them in gl.h +dnl i.e Darwin and Solaris. + +AC_CHECK_TYPES([GLintptr, GLintptrARB, GLchar, + GLcharARB, GLhalfARB, GLint64EXT], + [], [], + [#ifdef WIN32 + # include + # include + #elif defined(HAVE_GL_GL_H) + # include + #elif defined(HAVE_OPENGL_GL_H) + # include + #endif + ]) + +AC_MSG_CHECKING(GLU Callbacks uses Tiger Style) +AC_LANG_PUSH(C++) +saved_CXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" + +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #ifdef WIN32 + # include + # include + #elif defined(HAVE_GL_GL_H) + # include + #elif defined(HAVE_OPENGL_GL_H) + # include + #endif + #ifndef CALLBACK + # define CALLBACK + #endif + void CALLBACK foo() {}; + ]], [[ + GLUtesselator* tess; + gluTessCallback(tess,GLU_TESS_VERTEX,(GLvoid (*)(...)) foo); + ]])],[TESS_CB_TIGER_STYLE=yes + AC_DEFINE(TESS_CB_TIGER_STYLE, [1], [GLU Callbacks are Tiger style])],[TESS_CB_TIGER_STYLE=no]) +AC_MSG_RESULT($TESS_CB_TIGER_STYLE) +AC_SUBST(TESS_CB_TIGER_STYLE) + +dnl +dnl Check that we can link all the libraries +dnl + +AC_MSG_CHECKING(if we can link wxwidgets programs) +saved_LIBS=$LIBS + +if test X"$WX_HAVE_STATIC_LIBS" = X"true" ; then + LIBS=$WX_LIBS_STATIC +else + LIBS=$WX_LIBS +fi + +AC_LINK_IFELSE([AC_LANG_SOURCE([[ + #include "wx/wx.h" + #include "wx/stc/stc.h" + + + class MyApp : public wxApp + { + virtual bool OnInit() { + // Test that we have a FromUTF8 + // it isn't in too old wxWidgets versions + wxString test = wxString::FromUTF8((const char *)"foo"); + wxStyledTextCtrl * foo = new wxStyledTextCtrl(); + return foo; + }; + }; + IMPLEMENT_APP(MyApp) + ]])], + [ + CAN_LINK_WX=yes + ], + [ + CAN_LINK_WX=no + ]) + +CXXFLAGS=$saved_CXXFLAGS +LIBS=$saved_LIBS +AC_LANG_POP(C++) +AC_MSG_RESULT($CAN_LINK_WX) + +if test X"$CAN_LINK_WX" != X"yes" ; then + WX_MSG_ERROR([Can not link wx program are all developer packages installed?]) +fi + +]) dnl - if test "$WXERL_CAN_BUILD_DRIVER" != "false" + +LDFLAGS="$LDFLAGS$EXTRA_LDFLAGS" + +AC_SUBST(WXERL_CAN_BUILD_DRIVER) + +AS_IF([test "x$GCC" = xyes], + [ + # Treat certain GCC warnings as errors + LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) + LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CXXFLAGS]) + ]) + +############################################################################# + +dnl + +case $host_os in + mingw32|win32) + RUN_ERL=werl + SO_EXT=.dll;; + *) + RUN_ERL=erl + SO_EXT=.so;; +esac + +AC_SUBST(SO_EXT) +AC_SUBST(RUN_ERL) +AC_SUBST(CXXNOOPTFLAGS) + +WXERL_SYS_TYPE=$TARGET + +AC_SUBST(WXERL_SYS_TYPE) + +mkdir -p $WXERL_SYS_TYPE +CONFIG_STATUS=$WXERL_SYS_TYPE/config.status + +dnl + +AC_CONFIG_FILES([ + config.mk + c_src/Makefile + ]) + +AC_OUTPUT + +CORES=`ls core* 2>/dev/null` +if test X"$CORES" != X"" ; then + echo "Configure dumped core files" > ignore_core_files +fi + + + diff --git a/lib/wx/configure.in b/lib/wx/configure.in deleted file mode 100644 index 4d1e331ea3f1..000000000000 --- a/lib/wx/configure.in +++ /dev/null @@ -1,765 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -*-m4-*- - -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 2008-2022. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% - -AC_INIT() - -AC_CONFIG_AUX_DIRS($srcdir/autoconf) - -AC_PREREQ(2.59) - -## Delete previous failed configure results -if test -f ./CONF_INFO; then - rm ./CONF_INFO -fi - -AC_DEFUN([WX_MSG_ERROR], -[ echo "$1" >> ./CONF_INFO - WXERL_CAN_BUILD_DRIVER=false - if test X"$with_wx" = X"yes" ; then - AC_MSG_ERROR([$1]) - else - AC_MSG_WARN([$1]) - fi -]) - - -if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then - AC_MSG_ERROR([ERL_TOP is not set]) -else - erl_top=${ERL_TOP} - AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf) - WX_BUILDING_INSIDE_ERLSRC=true -fi - -AC_ARG_WITH(wx, -[ --with-wxdir=PATH specify location of wxWidgets include and lib - --with-wx use wxWidgets (default) - --without-wx don't use wxWidgets]) - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -else - host_os=win32 -fi - -case $host_os in - mingw32) - if test "X$host" = "X"; then - host=win32 - fi - ;; - *) - ;; -esac - -TARGET=$host -AC_SUBST(TARGET) - -AC_PROG_CC -AC_PROG_CXX -AC_PROG_RANLIB -AC_PROG_CPP - -AC_LANG_PUSH([C++]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#ifndef __cplusplus - #error "broken C++" - #endif]])],, - [CXX=;]) -AC_LANG_POP([C++]) -if test "X$CXX" = X ; then - WX_MSG_ERROR([Can not find C++ compiler]) -fi -WXERL_CAN_BUILD_DRIVER=false - -AC_MSG_NOTICE(Building for [$host_os]) -WXERL_CAN_BUILD_DRIVER=true - -LM_WINDOWS_ENVIRONMENT - -USER_CFLAGS=$CFLAGS - -if test X"$MIXED_VC" = X"yes" ; then - CFLAGS="-Owx" -fi - -AC_CHECK_SIZEOF(void *) - -PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT" - -OBJC_CC=$CC -OBJC_CFLAGS="" -CXXFLAGS="" -dnl NOTE: CPPFLAGS will be included in CFLAGS at the end -case $host_os in - darwin*) - AC_MSG_CHECKING([Checking wxWidgets for min version:]) - WX_CC=`wx-config --cc` - MAC_MIN=`echo "$WX_CC" | sed 's/^[[^ ]]*\ *//'` - AC_MSG_RESULT([$MAC_MIN]) - - AC_MSG_CHECKING([if compiler accepts -ObjC]) - CFLAGS="$CFLAGS -ObjC" - AC_TRY_COMPILE([],[;], accept_objc_flag=true, accept_objc_flag=false) - if test "X$accept_objc_flag" = "Xtrue"; then - AC_MSG_RESULT([yes]) - C_ONLY_FLAGS="-ObjC" - else - dnl We are probably trying to build with a non-Apple gcc, - dnl which is good as long as we do not try to build Cocoa - dnl code. We need an Apple compiler for just that (Objective C) - AC_MSG_RESULT([no]) - AC_MSG_CHECKING([for a Cocoa compliant Objective C compiler]) - SEARCHFOR="" - SEARCHFORXX="" - save_IFS=$IFS - IFS=: - set $PATH - IFS=$save_IFS - while test X"$1" != X""; do - dnl Add all possible paths to a real apple gcc - SEARCHFOR="$1/gcc-apple-4.2 $SEARCHFOR" - SEARCHFORXX="$1/g++-apple-4.2 $SEARCHFORXX" - shift - done - dnl Add LLVM compilers, they will work in this case - SEARCHFOR="/usr/bin/clang /usr/bin/gcc $SEARCHFOR" - SEARCHFORXX="/usr/bin/clang /usr/bin/g++ $SEARCHFORXX" - APPLE_CC="" - APPLE_CXX="" - dnl SEARCHFOR is reversed, so we want to find the last existing - dnl executable in the list - IFS=" " - set $SEARCHFORXX - for x in $SEARCHFOR; do - if test -x $x; then - APPLE_CC=$x - fi - if test -x "$1"; then - APPLE_CXX="$1" - fi - shift - done - IFS=$save_IFS - if test X$APPLE_CC = X -o X$APPLE_CXX = X; then - AC_MSG_RESULT([no]) - dnl Complete failure, we cannot build Cocoa code - WX_MSG_ERROR([Can not find compiler to compile Cocoa applications]) - else - dnl We think we found an Apple compiler and will add - dnl Apple specific options - AC_MSG_RESULT([$APPLE_CC ($APPLE_CXX)]) - dnl We should use this compiler for all of wx - hack... - CC=$APPLE_CC - CXX=$APPLE_CXX - dnl Both clang and gcc accept these flags... - #CXXFLAGS="-x c++ $CXXFLAGS" - OBJC_CC=$APPLE_CC - OBJC_CFLAGS="-ObjC" - fi - fi - CFLAGS="$USER_CFLAGS $MAC_MIN -Wno-deprecated-declarations" - CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" - ;; - mingw32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" - AC_MSG_WARN([Reverting to 32-bit time_t]) - CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" - ;; - win32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" - ;; - *) - CFLAGS="$CFLAGS -Wno-deprecated-declarations" - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE $PTHR_CFLAGS" - ;; -esac - -AC_SUBST(OBJC_CC) -AC_SUBST(OBJC_CFLAGS) - -case $host_os in - darwin*) - LDFLAGS="$MAC_MIN -bundle -flat_namespace -undefined warning -fPIC $LDFLAGS" - # Check sizof_void_p as future will hold 64bit MacOS wx - if test $ac_cv_sizeof_void_p = 4; then - LDFLAGS="-m32 $LDFLAGS" - fi - GL_LIBS="-framework OpenGL" - ;; - win32) - LDFLAGS="-dll $LDFLAGS" - GL_LIBS="-lglu32 -lOpengl32" - ;; - mingw32) - LDFLAGS="-shared -fPIC $LDFLAGS" - GL_LIBS="-lglu32 -lOpengl32" - ;; - *) - LDFLAGS="-shared -fPIC $LDFLAGS" - GL_LIBS="-lGL -lGLU" - ;; -esac - -dnl ---------------------------------------------------------------------- -dnl Include CPPFLAGS in CFLAGS -dnl ---------------------------------------------------------------------- - -case $host_os in - mingw32) - DEBUG_CFLAGS="-g -Wall -DDEBUG $CFLAGS" - CFLAGS="-g -Wall -O2 $CFLAGS -fomit-frame-pointer -fno-strict-aliasing" - ;; - win32) - DEBUG_CFLAGS="-g -Wall $CFLAGS -DDEBUG" - CFLAGS="-g -Wall -O2 $CFLAGS" - ;; - darwin*) - DEBUG_CFLAGS="-g -Wall -fPIC $CFLAGS -DDEBUG" - # omit-frame-pointer causes seg faults with 10.9 and clang - CFLAGS="-g -Wall -fPIC $CFLAGS -fno-strict-aliasing" - ;; - *) - DEBUG_CFLAGS="-g -Wall -fPIC $CFLAGS -DDEBUG" - CFLAGS="-Wall -fPIC $CFLAGS -fomit-frame-pointer -fno-strict-aliasing" - ;; -esac - -dnl -dnl Use -O1 -fno-move-loop-invariants for wxe_funcs.cpp to reduce -dnl compilation time -dnl - -if test "x$GCC" = xyes -a X"$host_os" != X"win32" ; then - CXXNOOPT="-O1" - LM_TRY_ENABLE_CFLAG([-fno-move-loop-invariants], [CXXNOOPT]) - LM_TRY_ENABLE_CFLAG([-fno-var-tracking-assignments], [CXXNOOPT]) -fi - -dnl -dnl Opengl tests -dnl - -if test X"$host_os" != X"win32" ; then - AC_CHECK_HEADERS([GL/gl.h], [], - [AC_CHECK_HEADERS([OpenGL/gl.h])]) - if test X"$ac_cv_header_GL_gl_h" != Xyes && - test X"$ac_cv_header_OpenGL_gl_h" != Xyes - then - saved_CPPFLAGS="$CPPFLAGS" - AC_MSG_NOTICE(Checking for OpenGL headers in /usr/X11R6) - CPPFLAGS="-isystem /usr/X11R6/include $CPPFLAGS" - $as_unset ac_cv_header_GL_gl_h - AC_CHECK_HEADERS([GL/gl.h]) - if test X"$ac_cv_header_GL_gl_h" != Xyes ; then - AC_MSG_NOTICE(Checking for OpenGL headers in /usr/local) - CPPFLAGS="-isystem /usr/local/include $saved_CPPFLAGS" - $as_unset ac_cv_header_GL_gl_h - AC_CHECK_HEADERS([GL/gl.h]) - if test X"$ac_cv_header_GL_gl_h" != Xyes ; then - WX_MSG_ERROR([No OpenGL headers found, wx will NOT be usable]) - CPPFLAGS="$saved_CPPFLAGS" - else - GL_LIBS="-L/usr/local/lib $GL_LIBS" - fi - else - GL_LIBS="-L/usr/X11R6/lib $GL_LIBS" - fi - fi -else - AC_CHECK_HEADERS([gl/gl.h],[],[],[#include ]) -fi - -if test X"$host_os" != X"win32" ; then - AC_CHECK_HEADERS([GL/glu.h], [], - [AC_CHECK_HEADERS([OpenGL/glu.h])]) - if test X"$ac_cv_header_GL_glu_h" != Xyes && - test X"$ac_cv_header_OpenGL_glu_h" != Xyes - then - WX_MSG_ERROR([No GLU headers found, wx will NOT be usable]) - fi -else - AC_CHECK_HEADERS([gl/glu.h],[],[],[#include ]) -fi - -AC_SUBST(GL_LIBS) - -DEBUG_CXXFLAGS="$CXXFLAGS $DEBUG_CFLAGS $CPPFLAGS" -DEBUG_CFLAGS="$DEBUG_CFLAGS $CPPFLAGS $C_ONLY_FLAGS" - -CXXNOOPTFLAGS="$CXXFLAGS $CFLAGS $CPPFLAGS $CXXNOOPT" -CXXFLAGS="$CXXFLAGS $CFLAGS $CPPFLAGS" -CFLAGS="$CFLAGS $CPPFLAGS $C_ONLY_FLAGS" - -AC_SUBST(DEBUG_CFLAGS) -AC_SUBST(DEBUG_CXXFLAGS) - -ERLC=erlc -ERL=erl -ERLANG_ROOT_DIR=$ERL_TOP -AC_SUBST(ERLC) - -AC_SUBST(WX_BUILDING_INSIDE_ERLSRC) -AC_SUBST(ERLANG_ROOT_DIR) - -dnl -dnl Check for wxwidgets -dnl -if test "$cross_compiling" = "yes"; then - WX_MSG_ERROR([Cross compilation of the wx driver is not supported yet, wx will NOT be usable]) -elif test X"$MIXED_VC" = X"no"; then - m4_include(wxwin-nothrow.m4) - - AM_OPTIONS_WXCONFIG - reqwx=3.0.2 - AM_PATH_WXCONFIG($reqwx, [], [], [core,base,html,webview], [--unicode]) - AC_MSG_CHECKING(for wxwidgets webview) - AC_LANG_PUSH(C++) - saved_CXXFLAGS=$CXXFLAGS - CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" - saved_LIBS=$LIBS - LIBS=$WX_LIBS - - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ - #include "wx/wx.h" - #include "wx/webview.h" - ]], [[ - wxWebView::New(); - ]])], - HAVE_WEBVIEW_SUPPORT=yes, HAVE_WEBVIEW_SUPPORT=no) - - CXXFLAGS=$saved_CXXFLAGS - LIBS=$saved_LIBS - AC_LANG_POP(C++) - AC_MSG_RESULT($HAVE_WEBVIEW_SUPPORT) - - if test X"$HAVE_WEBVIEW_SUPPORT" != X"yes" ; then - WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui - echo "wxWidgets was not compiled with --enable-webview or wxWebView developer package is not installed, wxWebView will NOT be available" >> ./CONF_INFO - else - WXELIBS=stc,xrc,html,adv,xml,core,base,gl,aui,webview - AC_DEFINE([WXE_WEBVIEW]) - fi - - # Try to find debug libs first - AM_PATH_WXCONFIG($reqwx, wxWinWithGLDBG=1, wxWinWithGLDBG=0, [$WXELIBS], [--unicode --debug=yes]) - - AC_MSG_CHECKING(for debug build of wxWidgets) - if test "$wxWinWithGLDBG" = 1; then - AC_MSG_RESULT(yes); - else - AC_MSG_RESULT(no); - fi - - DEBUG_WX_CFLAGS=$WX_CFLAGS - DEBUG_WX_CXXFLAGS=$WX_CXXFLAGS - DEBUG_WX_LIBS=$WX_LIBS - DEBUG_WX_LIBS_STATIC=$WX_LIBS_STATIC - AC_SUBST(DEBUG_WX_CFLAGS) - AC_SUBST(DEBUG_WX_CXXFLAGS) - AC_SUBST(DEBUG_WX_LIBS) - AC_SUBST(DEBUG_WX_LIBS_STATIC) - - AM_PATH_WXCONFIG($reqwx, wxWinWithGL=1, wxWinWithGL=0, [$WXELIBS], [--unicode --debug=no]) - - AC_MSG_CHECKING(for standard build of wxWidgets) - if test "$wxWinWithGL" = 1; then - AC_MSG_RESULT(yes); - else - AC_MSG_RESULT(no); - fi - - if test "x$WX_LIBS_STATIC" = "x"; then - WX_HAVE_STATIC_LIBS=false - else - WX_HAVE_STATIC_LIBS=true - fi - - wxWin=0 - - if test "$wxWinWithGLDBG" = 1; then - if test "$wxWinWithGL" = 1; then - wxWin=1 - FORCED_DEBUG_BUILD=false - else - wxWin=1 - FORCED_DEBUG_BUILD=debug - WX_CFLAGS=$DEBUG_WX_CFLAGS - WX_CXXFLAGS=$DEBUG_WX_CXXFLAGS - WX_LIBS=$DEBUG_WX_LIBS - WX_LIBS_STATIC=$DEBUG_WX_LIBS_STATIC - fi - elif test "$wxWinWithGL" = 1; then - wxWin=1 - FORCED_DEBUG_BUILD=false - fi - AC_SUBST(FORCED_DEBUG_BUILD) - RC_FILE_TYPE=o - - if test "$wxWin" != 1; then - WX_MSG_ERROR([ - wxWidgets must be installed on your system. - - Please check that wx-config is in path, the directory - where wxWidgets libraries are installed (returned by - 'wx-config --libs' or 'wx-config --static --libs' command) - is in LD_LIBRARY_PATH or equivalent variable and - wxWidgets version is $reqwx or above.]) - fi -else - AC_MSG_CHECKING(for wxWidgets in standard locations) - echo - # Check whether --with-wxdir was given. - AC_MSG_NOTICE(OptionCheck: [$with_wxdir $with_wx_prefix]) - - if test "${with_wxdir+set}" = set; then : - withval=$with_wxdir; CWXWIN0=$withval - else - # Check whether --with-wx-prefix was given. - if test "${with_wx_prefix+set}" = set; then : - withval=$with_wx_prefix; CWXWIN0=$withval - else - CWXWIN0="" - fi - fi - - CWXWIN_CONFIG=`win32_path.sh -u $wx_config_name 2>/dev/null` - CWXWIN1=`dirname $CWXWIN_CONFIG 2>/dev/null` - CWXWIN2=`dirname $CWXWIN1 2>/dev/null` - - if test -z "$PROGRAMFILES" ; then - PROGRAMFILES="c:/Program Files" - fi - - CWXWIN_PROG=`win32_path.sh -u "$PROGRAMFILES" 2>/dev/null` - - CWXWIN3="$CWXWIN_PROG/wxWidgets-3.*.* - CWXWIN4="$CWXWIN_PROG/wxMSW-3.*.* - - DOC_OPT1=/opt/local/pgm - DOC_OPT2=/mnt/c/opt/local/pgm - CWX_DOCUMENTED="$DOC_OPT1/wxWidgets-3.*.* $DOC_OPT1/wxMSW-3.*.*" - CWX_DOCUMENTED="$DOC_OPT2/wxWidgets-3.*.* $DOC_OPT2/wxMSW-3.*.* $CWX_DOCUMENTED" - - case $ac_cv_sizeof_void_p in - 8) - VC_LIB=lib/vc_x64_lib - WX_ARCH=x64 - DOC_OPT64_1=/opt/local64/pgm - DOC_OPT64_2=/mnt/c/opt/local64/pgm - CWX_DOCUMENTED="$DOC_OPT64_1/wxWidgets-3.*.* $DOC_OPT64_1/wxMSW-3.*.* $CWX_DOCUMENTED" - CWX_DOCUMENTED="$DOC_OPT64_2/wxWidgets-3.*.* $DOC_OPT64_2/wxMSW-3.*.* $CWX_DOCUMENTED" - ;; - *) - VC_LIB=lib/vc_lib - WX_ARCH=x86 - DOC_OPT3=/opt/local32/pgm - DOC_OPT4=/mnt/c/opt/local32/pgm - CWX_DOCUMENTED="$DOC_OPT3/wxWidgets-3.*.* $DOC_OPT3/wxMSW-3.*.* $CWX_DOCUMENTED" - CWX_DOCUMENTED="$DOC_OPT4/wxWidgets-3.*.* $DOC_OPT4/wxMSW-3.*.* $CWX_DOCUMENTED" - ;; - esac - - CWXPATH="$CWXWIN0 $CWXWIN1 $CWXWIN2 $CWX_DOCUMENTED $CWXWIN3 $CWXWIN4" - - for dir in $CWXPATH; do - AC_MSG_NOTICE(Checking: [$dir]) - if test -f $dir/include/wx/wx.h; then - WXINCLUDE_MSVC=$dir/include/msvc - WXINCLUDE_PLAIN=$dir/include - WX_CFLAGS="-EHsc -D_UNICODE -DUNICODE -I$WXINCLUDE_MSVC -I$WXINCLUDE_PLAIN -D__WXMSW__" - WX_CXXFLAGS="-TP $WX_CFLAGS" - WX_LIBDIR=$dir/$VC_LIB - WX_RESCOMP="rc.sh -I$WXINCLUDE_PLAIN -D __WIN32__" - RC_FILE_TYPE=res - base=`ls $WX_LIBDIR/wxbase*.lib 2> /dev/null | egrep 'wxbase[[0-9]]*u\.lib'` - corelib_number=`echo $base | sed 's,.*\([[0-9]].\)u\.lib,\1,'` - if test '!' -z "$corelib_number"; then - WXLIBNO=$corelib_number - WX_LIBS0="wxmsw${WXLIBNO}u_stc wxmsw${WXLIBNO}u_xrc wxmsw${WXLIBNO}u_html" - WX_LIBS1="wxmsw${WXLIBNO}u_adv wxbase${WXLIBNO}u_xml wxmsw${WXLIBNO}u_core" - WX_LIBS2="wxbase${WXLIBNO}u wxmsw${WXLIBNO}u_gl wxmsw${WXLIBNO}u_aui" - WX_LIBS3="wxregexu wxexpat wxtiff wxjpeg wxpng wxzlib" - WX_SYSLIBS="winspool winmm oleaut32 ole32 gdiplus" - WX_LIBS_STATIC="-L$WX_LIBDIR" - for lib in $WX_LIBS0 $WX_LIBS1 $WX_LIBS2 $WX_LIBS3 $WX_SYSLIBS; do - WX_LIBS_STATIC="$WX_LIBS_STATIC -l$lib" - done - WXDIR=$dir - AC_MSG_RESULT([Found: $dir]) - break - fi - fi - done - - if test -z "$WX_LIBS_STATIC"; then - AC_MSG_RESULT([failed]) - WX_MSG_ERROR([Cannot find core lib version for wxWidgets]) - fi - - AC_MSG_CHECKING(for edge webview loader) - WEBVIEW_DLL=$WXDIR/3rdparty/webview2/build/native/$WX_ARCH/WebView2Loader.dll - if test -f "$WEBVIEW_DLL"; then - AC_MSG_RESULT([$WEBVIEW_DLL]) - WX_WEBVIEW_DLL=$WEBVIEW_DLL - else - AC_MSG_RESULT(not found in $WEBVIEW_DLL) - WX_WEBVIEW_DLL= - fi - - - WX_HAVE_STATIC_LIBS=true - AC_SUBST(WX_CFLAGS) - AC_SUBST(WX_CXXFLAGS) - AC_SUBST(WX_LIBS_STATIC) - AC_SUBST(WX_RESCOMP) - AC_SUBST(WX_WEBVIEW_DLL) - AC_DEFINE([WXE_WEBVIEW]) -fi - -if test "$WXERL_CAN_BUILD_DRIVER" != "false"; then - -AC_SUBST(WX_HAVE_STATIC_LIBS) -AC_SUBST(RC_FILE_TYPE) - -AC_MSG_CHECKING(for wxwidgets 3.0 compatibility ) -AC_LANG_PUSH(C++) -saved_CXXFLAGS=$CXXFLAGS -CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" - -AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[ - #include "wx/wx.h" - ]], [[ - #if wxMAJOR_VERSION > 2 && (wxMINOR_VERSION == 0 || WXWIN_COMPATIBILITY_3_0 == 1) - ; - #else - #error barf - #endif - ]])], - HAVE_COMPAT30_SUPPORT=yes, HAVE_COMPAT30_SUPPORT=no) - -CXXFLAGS=$saved_CXXFLAGS -AC_LANG_POP(C++) -AC_MSG_RESULT($HAVE_COMPAT30_SUPPORT) - -if test X"$HAVE_COMPAT30_SUPPORT" != X"yes" ; then - WX_MSG_ERROR([wxWidgets was not compiled with --enable-compat30, wx will NOT be useable]) -fi - -AC_MSG_CHECKING(for wxwidgets opengl support) -AC_LANG_PUSH(C++) -saved_CXXFLAGS=$CXXFLAGS -CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" - -AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[ - #include "wx/wx.h" - ]], [[ - #if wxUSE_GLCANVAS - ; - #else - #error barf - #endif - ]])], -[HAVE_GL_SUPPORT=yes - AC_DEFINE(HAVE_GL_SUPPORT, [1], [Define if wxwidgets have gl support])], - HAVE_GL_SUPPORT=no) - -CXXFLAGS=$saved_CXXFLAGS -AC_LANG_POP(C++) -AC_MSG_RESULT($HAVE_GL_SUPPORT) -AC_SUBST(HAVE_GL_SUPPORT) - -if test X"$HAVE_GL_SUPPORT" != X"yes" ; then - WX_MSG_ERROR([wxWidgets don't have gl support, wx will NOT be useable]) -fi - -dnl Check for GLintptr -dnl We define the types glext.h so we don't depend on glext.h is updated -dnl to the latest version, but some systems defined them in gl.h -dnl i.e Darwin and Solaris. - -AC_CHECK_TYPES([GLintptr, GLintptrARB, GLchar, - GLcharARB, GLhalfARB, GLint64EXT], - [], [], - [#ifdef WIN32 - # include - # include - #elif defined(HAVE_GL_GL_H) - # include - #elif defined(HAVE_OPENGL_GL_H) - # include - #endif - ]) - -AC_MSG_CHECKING(GLU Callbacks uses Tiger Style) -AC_LANG_PUSH(C++) -saved_CXXFLAGS=$CXXFLAGS -CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" - -AC_TRY_COMPILE([ - #ifdef WIN32 - # include - # include - #elif defined(HAVE_GL_GL_H) - # include - #elif defined(HAVE_OPENGL_GL_H) - # include - #endif - #ifndef CALLBACK - # define CALLBACK - #endif - void CALLBACK foo() {}; - ], - [ - GLUtesselator* tess; - gluTessCallback(tess,GLU_TESS_VERTEX,(GLvoid (*)(...)) foo); - ], - [TESS_CB_TIGER_STYLE=yes - AC_DEFINE(TESS_CB_TIGER_STYLE, [1], [GLU Callbacks are Tiger style])], - TESS_CB_TIGER_STYLE=no) -AC_MSG_RESULT($TESS_CB_TIGER_STYLE) -AC_SUBST(TESS_CB_TIGER_STYLE) - -dnl -dnl Check that we can link all the libraries -dnl - -AC_MSG_CHECKING(if we can link wxwidgets programs) -saved_LIBS=$LIBS - -if test X"$WX_HAVE_STATIC_LIBS" = X"true" ; then - LIBS=$WX_LIBS_STATIC -fi - -AC_LINK_IFELSE([AC_LANG_SOURCE([ - #include "wx/wx.h" - #include "wx/stc/stc.h" - ]) - - class MyApp : public wxApp - { - virtual bool OnInit() { - // Test that we have a FromUTF8 - // it isn't in too old wxWidgets versions - wxString test = wxString::FromUTF8((const char *)"foo"); - wxStyledTextCtrl * foo = new wxStyledTextCtrl(); - return foo; - }; - }; - IMPLEMENT_APP(MyApp) - ], - [ - CAN_LINK_WX=yes - ], - [ - CAN_LINK_WX=no - ]) - -CXXFLAGS=$saved_CXXFLAGS -LIBS=$saved_LIBS -AC_LANG_POP(C++) -AC_MSG_RESULT($CAN_LINK_WX) - -if test X"$CAN_LINK_WX" != X"yes" ; then - WX_MSG_ERROR([Can not link wx program are all developer packages installed?]) -fi - -fi dnl - if test "$WXERL_CAN_BUILD_DRIVER" != "false" - -AC_SUBST(WXERL_CAN_BUILD_DRIVER) - -if test "x$GCC" = xyes; then - # Treat certain GCC warnings as errors - LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) - LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CXXFLAGS]) -fi - -dnl ---------------------------------------------------------------------- -dnl Enable -fsanitize= flags. -dnl ---------------------------------------------------------------------- - -m4_define(DEFAULT_SANITIZERS, [address,undefined]) -AC_ARG_ENABLE( - sanitizers, - AS_HELP_STRING( - [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], - [Default=DEFAULT_SANITIZERS]), -[ -case "$enableval" in - no) sanitizers= ;; - yes) sanitizers="-fsanitize=DEFAULT_SANITIZERS" ;; - *) sanitizers="-fsanitize=$enableval" ;; -esac -CFLAGS="$CFLAGS $sanitizers" -CXXFLAGS="$CXXFLAGS $sanitizers" -LDFLAGS="$LDFLAGS $sanitizers" -]) - -############################################################################# - -dnl - -case $host_os in - mingw32|win32) - RUN_ERL=werl - SO_EXT=.dll;; - *) - RUN_ERL=erl - SO_EXT=.so;; -esac - -AC_SUBST(SO_EXT) -AC_SUBST(RUN_ERL) -AC_SUBST(CXXNOOPTFLAGS) - - -if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then - dnl Find driver directory name according to erlang - WXERL_SYS_TYPE=`erl -noshell -eval 'io:format("~s~n",[[erlang:system_info(system_architecture)]])' -s erlang halt` -else - WXERL_SYS_TYPE=$TARGET -fi - -AC_SUBST(WXERL_SYS_TYPE) - -mkdir -p $WXERL_SYS_TYPE -CONFIG_STATUS=$WXERL_SYS_TYPE/config.status - -dnl - -AC_CONFIG_FILES([ - config.mk - c_src/Makefile - ]) - -AC_OUTPUT - -CORES=`ls core* 2>/dev/null` -if test X"$CORES" != X"" ; then - echo "Configure dumped core files" > ignore_core_files -fi - - - diff --git a/lib/wx/doc/src/gl.xml b/lib/wx/doc/src/gl.xml index 224c9d90f307..1f35f8fa8987 100644 --- a/lib/wx/doc/src/gl.xml +++ b/lib/wx/doc/src/gl.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202023 Ericsson AB. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); @@ -928,10 +928,10 @@

    External documentation.

    - + inject an application-supplied message into the debug message queue -

    gl:debugMessageInsert/6 inserts a user-supplied message into the debug output queue. Source specifies the source that will be used to classify the message and must be ?GL_DEBUG_SOURCE_APPLICATION or ?GL_DEBUG_SOURCE_THIRD_PARTY. All other sources are reserved for use by the GL implementation. Type indicates the type of the message to be inserted and may be one of ?GL_DEBUG_TYPE_ERROR, ?GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, ?GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, ?GL_DEBUG_TYPE_PORTABILITY, ?GL_DEBUG_TYPE_PERFORMANCE, ?GL_DEBUG_TYPE_MARKER, ?GL_DEBUG_TYPE_PUSH_GROUP, ?GL_DEBUG_TYPE_POP_GROUP, or ?GL_DEBUG_TYPE_OTHER. Severity indicates the severity of the message and may be ?GL_DEBUG_SEVERITY_LOW, ?GL_DEBUG_SEVERITY_MEDIUM, ?GL_DEBUG_SEVERITY_HIGH or ?GL_DEBUG_SEVERITY_NOTIFICATION. Id is available for application defined use and may be any value. This value will be recorded and used to identify the message.

    +

    gl:debugMessageInsert/5 inserts a user-supplied message into the debug output queue. Source specifies the source that will be used to classify the message and must be ?GL_DEBUG_SOURCE_APPLICATION or ?GL_DEBUG_SOURCE_THIRD_PARTY. All other sources are reserved for use by the GL implementation. Type indicates the type of the message to be inserted and may be one of ?GL_DEBUG_TYPE_ERROR, ?GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, ?GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, ?GL_DEBUG_TYPE_PORTABILITY, ?GL_DEBUG_TYPE_PERFORMANCE, ?GL_DEBUG_TYPE_MARKER, ?GL_DEBUG_TYPE_PUSH_GROUP, ?GL_DEBUG_TYPE_POP_GROUP, or ?GL_DEBUG_TYPE_OTHER. Severity indicates the severity of the message and may be ?GL_DEBUG_SEVERITY_LOW, ?GL_DEBUG_SEVERITY_MEDIUM, ?GL_DEBUG_SEVERITY_HIGH or ?GL_DEBUG_SEVERITY_NOTIFICATION. Id is available for application defined use and may be any value. This value will be recorded and used to identify the message.

    External documentation.

    @@ -1798,11 +1798,8 @@ - retrieve information about implementation-dependent support for internal formats - -

    gl:getInternalformativ/4 and gl:getInternalformati64v/4 retrieve information about implementation-dependent support for internal formats. Target indicates the target with which the internal format will be used and must be one of ?GL_RENDERBUFFER, ?GL_TEXTURE_2D_MULTISAMPLE, or ?GL_TEXTURE_2D_MULTISAMPLE_ARRAY, corresponding to usage as a renderbuffer, two-dimensional multisample texture or two-dimensional multisample array texture, respectively.

    - -

    External documentation.

    + +

    No documentation available.

    diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml index cab451fa192a..84954e7f59fb 100644 --- a/lib/wx/doc/src/notes.xml +++ b/lib/wx/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 20092021 + 20092022 Ericsson AB. All Rights Reserved. @@ -32,6 +32,109 @@

    This document describes the changes made to the wxErlang application.

    +
    Wx 2.3.1 + +
    Fixed Bugs and Malfunctions + + +

    The wx application would fail to build on macOS + with Xcode 15.

    +

    + Own Id: OTP-18768 Aux Id: PR-7670

    +
    +
    +
    + +
    + +
    Wx 2.3 + +
    Improvements and New Features + + +

    Runtime dependencies have been updated.

    +

    + Own Id: OTP-18350

    +
    + +

    The implementation has been fixed to use + proc_lib:init_fail/2,3 where appropriate, instead + of proc_lib:init_ack/1,2.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

    +
    +
    +
    + +
    + +
    Wx 2.2.2 + +
    Fixed Bugs and Malfunctions + + +

    + Improve debug prints from the nifs. Some minor fixes for + wxWidgets-3.2. Fixed OpenGL debug functions.

    +

    + Own Id: OTP-18512

    +
    +
    +
    + +
    + +
    Wx 2.2.1 + +
    Fixed Bugs and Malfunctions + + +

    + Added environment variable WX_MACOS_NON_GUI_APP to + allow user to override OSXIsGUIApplication + behavior.

    +

    + Own Id: OTP-18213 Aux Id: PR-6113

    +
    +
    +
    + +
    + +
    Wx 2.2 + +
    Improvements and New Features + + +

    + Input for configure scripts adapted to + autoconf 2.71.

    +

    + Own Id: OTP-17414 Aux Id: PR-4967

    +
    + +

    + Added aux1Down and aux2Down fields to the + wxMouseState record. Since one record have been + changed a recompilation of user code might be required.

    +

    + *** POTENTIAL INCOMPATIBILITY ***

    +

    + Own Id: OTP-17950

    +
    + +

    + Add mac specific menubar functions.

    +

    + Own Id: OTP-18008 Aux Id: PR-5816

    +
    +
    +
    + +
    +
    Wx 2.1.4
    Fixed Bugs and Malfunctions @@ -281,7 +384,7 @@

    Fixed wx initialization on mac, top level menus did not - always work on newer MacOS versions. The menues will not + always work on newer MacOS versions. The menus will not work until wxWidgets-3.1.5 is released and used on these MacOS versions.

    @@ -1061,7 +1164,7 @@

    Wx on MacOS X generated complains on stderr about certain - cocoa functions not beeing called from the "Main thread". + cocoa functions not being called from the "Main thread". This is now corrected.

    Own Id: OTP-9081

    @@ -1239,7 +1342,7 @@

    wxHtmlWindow class implemented.

    All exceptions - from callbacks are now catched and written to the + from callbacks are now caught and written to the log.

    Some defines where wrong in 'wx.hrl'.

    wx:batch/1 and friends could hang forever if for instance a breakpoint was set inside the fun. That diff --git a/lib/wx/doc/src/wx.xml b/lib/wx/doc/src/wx.xml index 982343cda401..a405b0a274d8 100644 --- a/lib/wx/doc/src/wx.xml +++ b/lib/wx/doc/src/wx.xml @@ -141,6 +141,47 @@ wxGBPosition={r,c},wxGBSpan={rs,cs},wxGridCellCoords={r,c}.

    another process wx environment.

    +subscribe_events() -> ok +Adds the calling process to the list of of processes that are +listening to wx application events. + + +

    + Adds the calling process to the list of of processes that are listening to + wx application events. +

    + +

    + At the moment these are all MacOSX specific events corresponding to + MacNewFile() + and friends from wxWidgets + wxApp: +

    + + + +

    {new_file, ""}

    +
    + +

    {open_file, Filename}

    +
    + +

    {print_file, Filename}

    +
    + +

    {open_url, Url}

    +
    + +

    {reopen_app, ""}

    +
    +
    + +

    + The call always returns ok but will have sent any already received + events to the calling process. +

    +
    + null() -> wx_object() Returns the null object. @@ -287,4 +328,4 @@ library.

    - \ No newline at end of file + diff --git a/lib/wx/doc/src/wxEvtHandler.xml b/lib/wx/doc/src/wxEvtHandler.xml index c38da3e127cb..fdc96971cad0 100644 --- a/lib/wx/doc/src/wxEvtHandler.xml +++ b/lib/wx/doc/src/wxEvtHandler.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202022 wxWidgets team. Licensed under the wxWindows Free Documentation Licence, Version 3 @@ -48,7 +48,7 @@

    id:{id, integer()} The identifier (or first of the identifier range) to be associated with this event handler. Default is ?wxID_ANY

    lastid:{lastId,integer()} The second part of the identifier range. If used 'id' must be set as the starting identifier range. Default is ?wxID_ANY

    skip:{skip,boolean()} If skip is true further event_handlers will be called. This is not used if the 'callback' option is used. Default is false. -

    callback:{callback,function()} Use a callbackfun(EventRecord::wx(),EventObject::wxObject()) to process the event. Default not specfied i.e. a message will be delivered to the process calling this function. +

    callback:{callback,function()} Use a callbackfun(EventRecord::wx(),EventObject::wxObject()) to process the event. Default not specified i.e. a message will be delivered to the process calling this function.

    userData:{userData,term()} An erlang term that will be sent with the event. Default: [].

    diff --git a/lib/wx/doc/src/wxGLCanvas.xml b/lib/wx/doc/src/wxGLCanvas.xml index 2ccfb6e137bb..00c10cd1f1e0 100644 --- a/lib/wx/doc/src/wxGLCanvas.xml +++ b/lib/wx/doc/src/wxGLCanvas.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202023 wxWidgets team. Licensed under the wxWindows Free Documentation Licence, Version 3 @@ -56,6 +56,21 @@

    + + + + + + + + + Determines if a canvas having the specified attributes is available. +

    Determines if a canvas having the specified attributes is available. +

    This only applies for visual attributes, not rendering context attributes. Please, use the new form of this method, using wxGLAttributes (not implemented in wx). +

    Return: true if attributes are supported. +

    +
    + Swaps the double-buffer of this window, making the back-buffer the front-buffer and vice versa, so that the output of the previous OpenGL commands is displayed on the window. diff --git a/lib/wx/doc/src/wxGLContext.xml b/lib/wx/doc/src/wxGLContext.xml index 60214ff35b7b..8aa99999f85c 100644 --- a/lib/wx/doc/src/wxGLContext.xml +++ b/lib/wx/doc/src/wxGLContext.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202023 wxWidgets team. Licensed under the wxWindows Free Documentation Licence, Version 3 @@ -21,7 +21,7 @@

    Binding (making current) a rendering context with another instance of a wxGLCanvas however works only if the both wxGLCanvas instances were created with the same attributes.

    OpenGL version 3 introduced a new type of specification profile, the modern core profile. The old compatibility profile maintains all legacy features. Since wxWidgets 3.1.0 you can choose the type of context and even ask for a specified OGL version number. However, its advised to use only core profile as the compatibility profile may run a bit slower.

    OpenGL core profile specification defines several flags at context creation that determine not only the type of context but also some features. Some of these flags can be set in the list of attributes used at wxGLCanvas ctor. But since wxWidgets 3.1.0 it is strongly encouraged to use the new mechanism: setting the context attributes with a wxGLContextAttrs (not implemented in wx) object and the canvas attributes with a wxGLAttributes (not implemented in wx) object. -

    The best way of knowing if your OpenGL environment supports a specific type of context is creating a wxGLContext instance and checking wxGLContext::IsOK() (not implemented in wx). If it returns false, then simply delete that instance and create a new one with other attributes. +

    The best way of knowing if your OpenGL environment supports a specific type of context is creating a wxGLContext instance and checking isOK/1. If it returns false, then simply delete that instance and create a new one with other attributes.

    wxHAS_OPENGL_ES is defined on platforms that only have this implementation available (e.g. the iPhone) and don't support the full specification.

    See: wxGLCanvas, wxGLContextAttrs (not implemented in wx), wxGLAttributes (not implemented in wx)

    @@ -50,6 +50,15 @@

    + + + Checks if the underlying OpenGL rendering context was correctly created by the system with the requested attributes. +

    Checks if the underlying OpenGL rendering context was correctly created by the system with the requested attributes. +

    If this function returns false then the wxGLContext object is useless and should be deleted and recreated with different attributes. +

    Since: 3.1.0 +

    +
    + Destructor diff --git a/lib/wx/doc/src/wxMenuBar.xml b/lib/wx/doc/src/wxMenuBar.xml index 2b8172997823..0f4431dc3219 100644 --- a/lib/wx/doc/src/wxMenuBar.xml +++ b/lib/wx/doc/src/wxMenuBar.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202022 wxWidgets team. Licensed under the wxWindows Free Documentation Licence, Version 3 @@ -207,6 +207,23 @@

    + + + Enables you to get the global menubar on Mac, that is, the menubar displayed when the app is running without any frames open. +

    Enables you to get the global menubar on Mac, that is, the menubar displayed when the app is running without any frames open. +

    Return: The global menubar. +

    Remark: Only exists on Mac, other platforms do not have this method. +

    Only for:wxosx

    +
    + + + + Enables you to set the global menubar on Mac, that is, the menubar displayed when the app is running without any frames open. +

    Enables you to set the global menubar on Mac, that is, the menubar displayed when the app is running without any frames open. +

    Remark: Only exists on Mac, other platforms do not have this method. +

    Only for:wxosx

    +
    + Determines whether an item is enabled. diff --git a/lib/wx/doc/src/wxMouseEvent.xml b/lib/wx/doc/src/wxMouseEvent.xml index 5c690102e42c..2f9297be8352 100644 --- a/lib/wx/doc/src/wxMouseEvent.xml +++ b/lib/wx/doc/src/wxMouseEvent.xml @@ -7,7 +7,7 @@
    - 20202021 + 20202022 wxWidgets team. Licensed under the wxWindows Free Documentation Licence, Version 3 @@ -322,5 +322,47 @@

    Notice that before wxWidgets 2.9.4 this method returned int.

    + + + + Returns true if the event was a first extra button double click. +

    Returns true if the event was a first extra button double click. +

    +
    + + + + Returns true if the first extra button mouse button changed to down. +

    Returns true if the first extra button mouse button changed to down. +

    +
    + + + + Returns true if the first extra button mouse button changed to up. +

    Returns true if the first extra button mouse button changed to up. +

    +
    + + + + Returns true if the event was a second extra button double click. +

    Returns true if the event was a second extra button double click. +

    +
    + + + + Returns true if the second extra button mouse button changed to down. +

    Returns true if the second extra button mouse button changed to down. +

    +
    + + + + Returns true if the second extra button mouse button changed to up. +

    Returns true if the second extra button mouse button changed to up. +

    +
    diff --git a/lib/wx/examples/demo/Makefile b/lib/wx/examples/demo/Makefile index d1c2d23a712b..123c54580f26 100644 --- a/lib/wx/examples/demo/Makefile +++ b/lib/wx/examples/demo/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2021. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -62,7 +62,7 @@ TESTTARGETS = $(TESTMODS:%=%.beam) TESTSRC = $(TESTMODS:%=%.erl) # Targets -opt debug: $(TESTTARGETS) +$(TYPES): $(TESTTARGETS) clean: rm -f $(TESTTARGETS) rm -f *~ core erl_crash.dump diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl index 6e1465973ac1..dfcec2ef1c5a 100644 --- a/lib/wx/examples/demo/demo.erl +++ b/lib/wx/examples/demo/demo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -82,7 +82,7 @@ init(Options) -> wxMenuBar:append(MB, Help, "&Help"), wxFrame:setMenuBar(Frame,MB), - wxFrame:connect(Frame, command_menu_selected), + wxFrame:connect(Frame, command_menu_selected, [{skip, true}]), wxFrame:connect(Frame, close_window), _SB = wxFrame:createStatusBar(Frame,[]), diff --git a/lib/wx/examples/demo/demo_html_tagger.erl b/lib/wx/examples/demo/demo_html_tagger.erl index cc24cbaa67fb..08f42820a3d3 100644 --- a/lib/wx/examples/demo/demo_html_tagger.erl +++ b/lib/wx/examples/demo/demo_html_tagger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2015. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -23,7 +23,7 @@ %% That's because this program uses some pretty dodgy techniques to %% get at the data it requires. -%% I use epp_dodger to parse the file and the new imporved erl_scan +%% I use epp_dodger to parse the file and the new improved erl_scan %% find the exact values of the tokens %% epp_dodger returns an objects of type erl_syntax which are pretty diff --git a/lib/wx/examples/demo/ex_sashWindow.erl b/lib/wx/examples/demo/ex_sashWindow.erl index 63528f65d121..80d036448223 100644 --- a/lib/wx/examples/demo/ex_sashWindow.erl +++ b/lib/wx/examples/demo/ex_sashWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -65,7 +65,7 @@ do_init(Config) -> Win2 = wxPanel:new(BottomSash, []), wxStaticText:new(Win2, ?wxID_ANY, "This is the bottom sash", []), - %% Make the bottom edge of the top sash dragable + %% Make the bottom edge of the top sash draggable wxSashWindow:setSashVisible(TopSash, ?wxSASH_BOTTOM, true), wxPanel:connect(Panel, sash_dragged), wxPanel:connect(Panel, size), diff --git a/lib/wx/examples/demo/ex_sizers.erl b/lib/wx/examples/demo/ex_sizers.erl index 800f17f014e0..8b0baf4b16d9 100644 --- a/lib/wx/examples/demo/ex_sizers.erl +++ b/lib/wx/examples/demo/ex_sizers.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -59,7 +59,7 @@ do_init(Config) -> "Weighting Factor", "Edge Affinity", "Spacer", - "Centering In Avalible Space", + "Centering In Available Space", "Simple Border", "East And West Border", "North And South Border", @@ -149,7 +149,7 @@ create_example(Parent, Example) -> north_and_south_border(Panel); "Simple Border" -> simple_border(Panel); - "Centering In Avalible Space" -> + "Centering In Available Space" -> centering_in_avalible_space(Panel); "Spacer" -> spacer(Panel); diff --git a/lib/wx/examples/demo/ex_splitterWindow.erl b/lib/wx/examples/demo/ex_splitterWindow.erl index 14f63600a339..153a0da61a00 100644 --- a/lib/wx/examples/demo/ex_splitterWindow.erl +++ b/lib/wx/examples/demo/ex_splitterWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2016. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -54,14 +54,14 @@ do_init(Config) -> Splitter = wxSplitterWindow:new(Panel, []), - Win1 = wxTextCtrl:new(Splitter, 1, [{value, "Splitted Window 1"}, + Win1 = wxTextCtrl:new(Splitter, 1, [{value, "Split Window 1"}, {style, ?wxDEFAULT bor ?wxTE_MULTILINE}]), - Win2 = wxTextCtrl:new(Splitter, 1, [{value, "Splitted Window 1"}, + Win2 = wxTextCtrl:new(Splitter, 1, [{value, "Split Window 1"}, {style, ?wxDEFAULT bor ?wxTE_MULTILINE}]), wxSplitterWindow:splitVertically(Splitter, Win1, Win2), wxSplitterWindow:setSashGravity(Splitter, 0.5), - %% Set pane-size =/= 0 to not unsplit on doubleclick + %% Set pane-size =/= 0 to not unsplit on double-click %% on the splitter wxSplitterWindow:setMinimumPaneSize(Splitter,50), diff --git a/lib/wx/examples/simple/Makefile b/lib/wx/examples/simple/Makefile index 075528533ae8..16ac01d40df5 100644 --- a/lib/wx/examples/simple/Makefile +++ b/lib/wx/examples/simple/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2021. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -31,7 +31,7 @@ TESTTARGETS = $(TESTMODS:%=%.beam) TESTSRC = $(TESTMODS:%=%.erl) # Targets -opt debug: $(TESTTARGETS) +$(TYPES): $(TESTTARGETS) clean: rm -f $(TESTTARGETS) rm -f *~ core erl_crash.dump diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl index 829c88a3d503..4a5e9b4729b5 100644 --- a/lib/wx/examples/simple/menu.erl +++ b/lib/wx/examples/simple/menu.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -309,7 +309,7 @@ create_help_menu() -> HelpMenu = wxMenu:new(), % unlike wxwidgets the stock menu items still need text to be given, % although help text does appear - % Note the keybord accelerator + % Note the keyboard accelerator wxMenu:append(HelpMenu, wxMenuItem:new([ {id, ?menuID_HELP_ABOUT}, %{text, "&About\tF1"}, diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl index 45efc06462c2..5741243530b0 100644 --- a/lib/wx/examples/simple/minimal.erl +++ b/lib/wx/examples/simple/minimal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2018. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -55,7 +55,7 @@ create_window(Wx) -> % unlike wxwidgets the stock menu items still need text to be given, % although help text does appear _QuitMenuItem = wxMenu:append(FileM, ?wxID_EXIT, "&Quit"), - % Note the keybord accelerator + % Note the keyboard accelerator _AboutMenuItem = wxMenu:append(HelpM, ?wxID_ABOUT, "&About...\tF1"), wxMenu:appendSeparator(HelpM), diff --git a/lib/wx/examples/sudoku/Makefile b/lib/wx/examples/sudoku/Makefile index e6f35c689a4b..ccdcb7cd9f2c 100644 --- a/lib/wx/examples/sudoku/Makefile +++ b/lib/wx/examples/sudoku/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -31,7 +31,7 @@ TESTTARGETS = $(TESTMODS:%=%.beam) TESTSRC = $(TESTMODS:%=%.erl) # Targets -opt debug: $(TESTTARGETS) +$(TYPES): $(TESTTARGETS) clean: rm -f $(TESTTARGETS) rm -f *~ core erl_crash.dump diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl index c2e918bb2dd6..1b61fb439080 100644 --- a/lib/wx/include/wx.hrl +++ b/lib/wx/include/wx.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -315,7 +315,8 @@ -record(wxMouseState, {x :: integer(), y :: integer(), leftDown :: boolean(), middleDown :: boolean(), rightDown :: boolean(), controlDown :: boolean(), shiftDown :: boolean(), - altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean() + altDown :: boolean(), metaDown :: boolean(), cmdDown :: boolean(), + aux1Down :: boolean(), aux2Down :: boolean() }). -record(wxHtmlLinkInfo, { href :: unicode:chardata(), target :: unicode:chardata() @@ -902,7 +903,7 @@ -define(wxDF_LOCALE, 16). -define(wxDF_PRIVATE, 20). -define(wxDF_HTML, 30). --define(wxDF_MAX, 31). +-define(wxDF_MAX, wxe_util:get_const(wxDF_MAX)). %%% From "defs.h": wxDeprecatedGUIConstants -define(wxDEFAULT, 70). -define(wxDECORATIVE, 71). @@ -1432,6 +1433,12 @@ -define(wxID_MDI_WINDOW_PREV, (?wxID_MDI_WINDOW_FIRST+4)). -define(wxID_MDI_WINDOW_NEXT, (?wxID_MDI_WINDOW_FIRST+5)). -define(wxID_MDI_WINDOW_LAST, ?wxID_MDI_WINDOW_NEXT). +-define(wxID_OSX_MENU_FIRST, 5250). +-define(wxID_OSX_HIDE, ?wxID_OSX_MENU_FIRST). +-define(wxID_OSX_HIDEOTHERS, (?wxID_OSX_MENU_FIRST+1)). +-define(wxID_OSX_SHOWALL, (?wxID_OSX_MENU_FIRST+2)). +-define(wxID_OSX_SERVICES, (?wxID_OSX_MENU_FIRST+3)). +-define(wxID_OSX_MENU_LAST, ?wxID_OSX_SERVICES). -define(wxID_FILEDLGG, 5900). -define(wxID_FILECTRL, 5950). -define(wxID_HIGHEST, 5999). diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile index 7e2eb38f2f7c..b055dfed4a05 100644 --- a/lib/wx/src/Makefile +++ b/lib/wx/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2021. All Rights Reserved. +# Copyright Ericsson AB 2008-2022. 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. @@ -19,7 +19,7 @@ # include ../vsn.mk -ifdef TERTIARY_BOOTSTRAP +ifdef BOOTSTRAP VSN = $(WX_VSN) include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -75,7 +75,7 @@ APPUP_TARGET = $(EBIN)/$(APPUP_FILE) ifdef TERTIARY_BOOTSTRAP opt: $(EBIN)/wx_object.beam else - debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + $(TYPES): $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) endif clean: diff --git a/lib/wx/src/gen/gl.erl b/lib/wx/src/gen/gl.erl index 87e25efaa54c..283af4a869ae 100644 --- a/lib/wx/src/gen/gl.erl +++ b/lib/wx/src/gen/gl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -238,7 +238,7 @@ texStorage2DMultisample/6,texStorage3DMultisample/7,textureView/8, bindVertexBuffer/4,vertexAttribFormat/5,vertexAttribIFormat/4,vertexAttribLFormat/4, vertexAttribBinding/2,vertexBindingDivisor/2,debugMessageControl/5, - debugMessageInsert/6,getDebugMessageLog/2,pushDebugGroup/4,popDebugGroup/0, + debugMessageInsert/5,getDebugMessageLog/2,pushDebugGroup/4,popDebugGroup/0, objectPtrLabel/3,bufferStorage/4,clearTexImage/5,clearTexSubImage/11, bindBuffersBase/3,bindBuffersRange/5,bindTextures/2,bindSamplers/2, bindImageTextures/2,bindVertexBuffers/4,clipControl/2,createTransformFeedbacks/1, @@ -299,7 +299,8 @@ bindAttribLocationARB/3,getActiveAttribARB/3,getAttribLocationARB/2, blendBarrierKHR/0,maxShaderCompilerThreadsKHR/1,depthBoundsEXT/2]). --export([get_interface/0, rec/1, lookup_func/0]). +-export([get_interface/0, rec/1, lookup_func/1]). +-nifs([lookup_func_nif/1]). -define(nif_stub,nif_stub_error(?LINE)). %% @hidden nif_stub_error(Line) -> @@ -331,7 +332,10 @@ rec(Op) -> rec(Op) end. -lookup_func() -> ?nif_stub. +lookup_func(functions) -> lookup_func_nif(1); +lookup_func(function_names) -> lookup_func_nif(2). + +lookup_func_nif(_Func) -> ?nif_stub. @@ -5115,15 +5119,14 @@ debugMessageControl(Source,Type,Severity,Ids,Enabled) when is_integer(Source),is IF:queue_cmd(Source,Type,Severity,Count,Ids,Enabled,5802), ok. --spec debugMessageInsert(Source, Type, Id, Severity, Length, Buf) -> 'ok' - when Source::enum(), Type::enum(), Id::i(), Severity::enum(), Length::i(), Buf::string(). -debugMessageInsert(Source,Type,Id,Severity,Length,Buf) when is_integer(Source),is_integer(Type),is_integer(Id),is_integer(Severity),is_integer(Length),is_list(Buf) -> +-spec debugMessageInsert(Source::enum(), Type::enum(), Id::i(), Severity::enum(), Buf::string()) -> 'ok'. +debugMessageInsert(Source,Type,Id,Severity,Buf) when is_integer(Source),is_integer(Type),is_integer(Id),is_integer(Severity),is_list(Buf) -> IF = get_interface(), BufBin = unicode:characters_to_binary([Buf|[0]]), - IF:queue_cmd(Source,Type,Id,Severity,Length,BufBin,5803), + IF:queue_cmd(Source,Type,Id,Severity,BufBin,5803), ok. --spec getDebugMessageLog(Count::i(), BufSize::i()) -> {i(),Sources::[enum()],Types::[enum()],Ids::[i()],Severities::[enum()],MessageLog::string()}. +-spec getDebugMessageLog(Count::i(), BufSize::i()) -> {i(),Sources::[enum()],Types::[enum()],Ids::[i()],Severities::[enum()],MessageLog::[string()]}. getDebugMessageLog(Count,BufSize) when is_integer(Count),is_integer(BufSize) -> IF = get_interface(), IF:queue_cmd(Count,BufSize,5804), diff --git a/lib/wx/src/gen/glu.erl b/lib/wx/src/gen/glu.erl index 6d4d390205cb..15a80237fadb 100644 --- a/lib/wx/src/gen/glu.erl +++ b/lib/wx/src/gen/glu.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -55,7 +55,7 @@ %% @doc General purpose polygon triangulation. %% The first argument is the normal and the second a list of -%% vertex positions. Returned is a list of indecies of the vertices +%% vertex positions. Returned is a list of indices of the vertices %% and a binary (64bit native float) containing an array of %% vertex positions, it starts with the vertices in Vs and %% may contain newly created vertices in the end. diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl index 824ff6213318..bafd91ee516e 100644 --- a/lib/wx/src/gen/wxEvtHandler.erl +++ b/lib/wx/src/gen/wxEvtHandler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -33,10 +33,10 @@ %% (in another process) to handle the event. The callback should be of %% arity 2. fun(EventRecord::wx(), EventObject::wxObject()). %% -%% Beware that the callback will be in executed in new process each time. +%% Beware that the callback will be executed in a new process each time. %% %% -%% The orginal documentation. +%% The original documentation. %% %% -module(wxEvtHandler). @@ -71,8 +71,9 @@ connect(This, EventType) -> %% {skip, boolean()}, If skip is true further event_handlers will be called. %% This is not used if the 'callback' option is used. %% Default false. +%% callback Use `wx_object' callback `handle_sync_event/3'. %% {callback, function()} Use a callback fun(EventRecord::wx(), EventObject::wxObject()) -%% to process the event. Default not specfied i.e. a message will +%% to process the event. Default not specified i.e. a message will %% be delivered to the process calling this function. %% {userData, term()} An erlang term that will be sent with the event. Default: []. -spec connect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> 'ok' when diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl index 29a54f527dc4..3a6cc682bed3 100644 --- a/lib/wx/src/gen/wxGLCanvas.erl +++ b/lib/wx/src/gen/wxGLCanvas.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -20,7 +20,8 @@ -module(wxGLCanvas). -include("wxe.hrl"). --export([destroy/1,new/1,new/2,setCurrent/2,swapBuffers/1]). +-export([createSurface/1,destroy/1,isDisplaySupported/1,new/1,new/2,setCurrent/2, + swapBuffers/1]). %% inherited exports -export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, @@ -112,6 +113,22 @@ setCurrent(#wx_ref{type=ThisT}=This,#wx_ref{type=ContextT}=Context) -> wxe_util:queue_cmd(This,Context,?get_env(),?wxGLCanvas_SetCurrent), wxe_util:rec(?wxGLCanvas_SetCurrent). +%% @doc See external documentation. +-spec createSurface(This) -> boolean() when + This::wxGLCanvas(). +createSurface(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxGLCanvas), + wxe_util:queue_cmd(This,?get_env(),?wxGLCanvas_CreateSurface), + wxe_util:rec(?wxGLCanvas_CreateSurface). + +%% @doc See external documentation. +-spec isDisplaySupported(AttribList) -> boolean() when + AttribList::[integer()]. +isDisplaySupported(AttribList) + when is_list(AttribList) -> + wxe_util:queue_cmd(AttribList,?get_env(),?wxGLCanvas_IsDisplaySupported), + wxe_util:rec(?wxGLCanvas_IsDisplaySupported). + %% @doc See external documentation. -spec swapBuffers(This) -> boolean() when This::wxGLCanvas(). diff --git a/lib/wx/src/gen/wxGLContext.erl b/lib/wx/src/gen/wxGLContext.erl index 2308c658ef1b..00016ee6b60b 100644 --- a/lib/wx/src/gen/wxGLContext.erl +++ b/lib/wx/src/gen/wxGLContext.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -20,7 +20,7 @@ -module(wxGLContext). -include("wxe.hrl"). --export([destroy/1,new/1,new/2,setCurrent/2]). +-export([destroy/1,isOK/1,new/1,new/2,setCurrent/2]). %% inherited exports -export([parent_class/1]). @@ -60,6 +60,14 @@ setCurrent(#wx_ref{type=ThisT}=This,#wx_ref{type=WinT}=Win) -> wxe_util:queue_cmd(This,Win,?get_env(),?wxGLContext_SetCurrent), wxe_util:rec(?wxGLContext_SetCurrent). +%% @doc See external documentation. +-spec isOK(This) -> boolean() when + This::wxGLContext(). +isOK(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxGLContext), + wxe_util:queue_cmd(This,?get_env(),?wxGLContext_IsOK), + wxe_util:rec(?wxGLContext_IsOK). + %% @doc Destroys this object, do not use object again -spec destroy(This::wxGLContext()) -> 'ok'. destroy(Obj=#wx_ref{type=Type}) -> diff --git a/lib/wx/src/gen/wxMenuBar.erl b/lib/wx/src/gen/wxMenuBar.erl index b151def69da8..ca637e905368 100644 --- a/lib/wx/src/gen/wxMenuBar.erl +++ b/lib/wx/src/gen/wxMenuBar.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -23,8 +23,9 @@ -export([append/3,check/3,destroy/1,enable/3,enableTop/3,findItem/2,findMenu/2, findMenuItem/3,getAutoWindowMenu/0,getHelpString/2,getLabel/2,getLabelTop/2, getMenu/2,getMenuCount/1,getMenuLabel/2,getMenuLabelText/2,insert/4, - isChecked/2,isEnabled/2,new/0,new/1,oSXGetAppleMenu/1,remove/2,replace/4, - setAutoWindowMenu/1,setHelpString/3,setLabel/3,setLabelTop/3,setMenuLabel/3]). + isChecked/2,isEnabled/2,macGetCommonMenuBar/0,macSetCommonMenuBar/1, + new/0,new/1,oSXGetAppleMenu/1,remove/2,replace/4,setAutoWindowMenu/1, + setHelpString/3,setLabel/3,setLabelTop/3,setMenuLabel/3]). %% inherited exports -export([cacheBestSize/2,canSetTransparent/1,captureMouse/1,center/1,center/2, @@ -253,6 +254,19 @@ oSXGetAppleMenu(#wx_ref{type=ThisT}=This) -> wxe_util:queue_cmd(This,?get_env(),?wxMenuBar_OSXGetAppleMenu), wxe_util:rec(?wxMenuBar_OSXGetAppleMenu). +%% @doc See external documentation. +-spec macGetCommonMenuBar() -> wxMenuBar(). +macGetCommonMenuBar() -> + wxe_util:queue_cmd(?get_env(), ?wxMenuBar_MacGetCommonMenuBar), + wxe_util:rec(?wxMenuBar_MacGetCommonMenuBar). + +%% @doc See external documentation. +-spec macSetCommonMenuBar(Menubar) -> 'ok' when + Menubar::wxMenuBar(). +macSetCommonMenuBar(#wx_ref{type=MenubarT}=Menubar) -> + ?CLASS(MenubarT,wxMenuBar), + wxe_util:queue_cmd(Menubar,?get_env(),?wxMenuBar_MacSetCommonMenuBar). + %% @doc See external documentation. -spec isEnabled(This, Id) -> boolean() when This::wxMenuBar(), Id::integer(). diff --git a/lib/wx/src/gen/wxMouseEvent.erl b/lib/wx/src/gen/wxMouseEvent.erl index 897db7f29def..85f18521176a 100644 --- a/lib/wx/src/gen/wxMouseEvent.erl +++ b/lib/wx/src/gen/wxMouseEvent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2020. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -20,7 +20,8 @@ -module(wxMouseEvent). -include("wxe.hrl"). --export([altDown/1,button/2,buttonDClick/1,buttonDClick/2,buttonDown/1,buttonDown/2, +-export([altDown/1,aux1DClick/1,aux1Down/1,aux1Up/1,aux2DClick/1,aux2Down/1, + aux2Up/1,button/2,buttonDClick/1,buttonDClick/2,buttonDown/1,buttonDown/2, buttonUp/1,buttonUp/2,cmdDown/1,controlDown/1,dragging/1,entering/1, getButton/1,getLinesPerAction/1,getLogicalPosition/2,getPosition/1, getWheelAxis/1,getWheelDelta/1,getWheelRotation/1,getX/1,getY/1,isButton/1, @@ -374,6 +375,54 @@ getWheelAxis(#wx_ref{type=ThisT}=This) -> wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_GetWheelAxis), wxe_util:rec(?wxMouseEvent_GetWheelAxis). +%% @doc See external documentation. +-spec aux1DClick(This) -> boolean() when + This::wxMouseEvent(). +aux1DClick(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux1DClick), + wxe_util:rec(?wxMouseEvent_Aux1DClick). + +%% @doc See
    external documentation. +-spec aux1Down(This) -> boolean() when + This::wxMouseEvent(). +aux1Down(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux1Down), + wxe_util:rec(?wxMouseEvent_Aux1Down). + +%% @doc See external documentation. +-spec aux1Up(This) -> boolean() when + This::wxMouseEvent(). +aux1Up(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux1Up), + wxe_util:rec(?wxMouseEvent_Aux1Up). + +%% @doc See external documentation. +-spec aux2DClick(This) -> boolean() when + This::wxMouseEvent(). +aux2DClick(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux2DClick), + wxe_util:rec(?wxMouseEvent_Aux2DClick). + +%% @doc See external documentation. +-spec aux2Down(This) -> boolean() when + This::wxMouseEvent(). +aux2Down(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux2Down), + wxe_util:rec(?wxMouseEvent_Aux2Down). + +%% @doc See external documentation. +-spec aux2Up(This) -> boolean() when + This::wxMouseEvent(). +aux2Up(#wx_ref{type=ThisT}=This) -> + ?CLASS(ThisT,wxMouseEvent), + wxe_util:queue_cmd(This,?get_env(),?wxMouseEvent_Aux2Up), + wxe_util:rec(?wxMouseEvent_Aux2Up). + %% From wxEvent %% @hidden stopPropagation(This) -> wxEvent:stopPropagation(This). diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl index bf21c0560594..86b9114b0939 100644 --- a/lib/wx/src/gen/wxe_funcs.hrl +++ b/lib/wx/src/gen/wxe_funcs.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -757,2692 +757,2703 @@ -define(wxMenuBar_SetAutoWindowMenu, 871). -define(wxMenuBar_GetAutoWindowMenu, 872). -define(wxMenuBar_OSXGetAppleMenu, 873). --define(wxMenuBar_IsEnabled, 874). --define(wxMenuBar_Remove, 875). --define(wxMenuBar_Replace, 876). --define(wxMenuBar_SetHelpString, 877). --define(wxMenuBar_SetLabel, 878). --define(wxMenuBar_SetMenuLabel, 879). --define(wxControl_GetLabel, 880). --define(wxControl_SetLabel, 881). --define(wxControlWithItems_Append_1, 882). --define(wxControlWithItems_Append_2, 883). --define(wxControlWithItems_appendStrings_1, 884). --define(wxControlWithItems_appendStrings_2, 885). --define(wxControlWithItems_Clear, 886). --define(wxControlWithItems_Delete, 887). --define(wxControlWithItems_FindString, 888). --define(wxControlWithItems_getClientData, 889). --define(wxControlWithItems_setClientData, 890). --define(wxControlWithItems_GetCount, 891). --define(wxControlWithItems_GetSelection, 892). --define(wxControlWithItems_GetString, 893). --define(wxControlWithItems_GetStringSelection, 894). --define(wxControlWithItems_Insert_2, 895). --define(wxControlWithItems_Insert_3, 896). --define(wxControlWithItems_insertStrings_2, 897). --define(wxControlWithItems_insertStrings_3, 898). --define(wxControlWithItems_IsEmpty, 899). --define(wxControlWithItems_Select, 900). --define(wxControlWithItems_SetSelection, 901). --define(wxControlWithItems_SetString, 902). --define(wxControlWithItems_SetStringSelection, 903). --define(wxMenu_new_0, 904). --define(wxMenu_new_1, 905). --define(wxMenu_new_2, 906). --define(wxMenu_destruct, 907). --define(wxMenu_Append_3, 908). --define(wxMenu_Append_4, 909). --define(wxMenu_Append_1, 910). --define(wxMenu_AppendCheckItem, 911). --define(wxMenu_AppendRadioItem, 912). --define(wxMenu_AppendSeparator, 913). --define(wxMenu_Break, 914). --define(wxMenu_Check, 915). --define(wxMenu_Delete_1_0, 916). --define(wxMenu_Delete_1_1, 917). --define(wxMenu_Destroy_1_0, 918). --define(wxMenu_Destroy_1_1, 919). --define(wxMenu_Enable, 920). --define(wxMenu_FindItem_1, 921). --define(wxMenu_FindItem_2, 922). --define(wxMenu_FindItemByPosition, 923). --define(wxMenu_GetHelpString, 924). --define(wxMenu_GetLabel, 925). --define(wxMenu_GetMenuItemCount, 926). --define(wxMenu_GetMenuItems, 928). --define(wxMenu_GetTitle, 929). --define(wxMenu_Insert_2, 930). --define(wxMenu_Insert_3, 931). --define(wxMenu_Insert_5, 932). --define(wxMenu_InsertCheckItem, 933). --define(wxMenu_InsertRadioItem, 934). --define(wxMenu_InsertSeparator, 935). --define(wxMenu_IsChecked, 936). --define(wxMenu_IsEnabled, 937). --define(wxMenu_Prepend_1, 938). --define(wxMenu_Prepend_2, 939). --define(wxMenu_Prepend_4, 940). --define(wxMenu_PrependCheckItem, 941). --define(wxMenu_PrependRadioItem, 942). --define(wxMenu_PrependSeparator, 943). --define(wxMenu_Remove_1_0, 944). --define(wxMenu_Remove_1_1, 945). --define(wxMenu_SetHelpString, 946). --define(wxMenu_SetLabel, 947). --define(wxMenu_SetTitle, 948). --define(wxMenuItem_new, 949). --define(wxMenuItem_destruct, 950). --define(wxMenuItem_Check, 951). --define(wxMenuItem_Enable, 952). --define(wxMenuItem_GetBitmap, 953). --define(wxMenuItem_GetHelp, 954). --define(wxMenuItem_GetId, 955). --define(wxMenuItem_GetKind, 956). --define(wxMenuItem_GetLabelText, 957). --define(wxMenuItem_GetItemLabel, 958). --define(wxMenuItem_GetItemLabelText, 959). --define(wxMenuItem_GetMenu, 960). --define(wxMenuItem_GetSubMenu, 961). --define(wxMenuItem_IsCheckable, 962). --define(wxMenuItem_IsChecked, 963). --define(wxMenuItem_IsEnabled, 964). --define(wxMenuItem_IsSeparator, 965). --define(wxMenuItem_IsSubMenu, 966). --define(wxMenuItem_SetBitmap, 967). --define(wxMenuItem_SetHelp, 968). --define(wxMenuItem_SetMenu, 969). --define(wxMenuItem_SetSubMenu, 970). --define(wxMenuItem_SetItemLabel, 971). --define(wxToolBar_AddControl, 972). --define(wxToolBar_AddSeparator, 973). --define(wxToolBar_AddTool_1, 974). --define(wxToolBar_AddTool_4, 975). --define(wxToolBar_AddTool_5, 976). --define(wxToolBar_AddCheckTool, 977). --define(wxToolBar_AddRadioTool, 978). --define(wxToolBar_AddStretchableSpace, 979). --define(wxToolBar_InsertStretchableSpace, 980). --define(wxToolBar_DeleteTool, 981). --define(wxToolBar_DeleteToolByPos, 982). --define(wxToolBar_EnableTool, 983). --define(wxToolBar_FindById, 984). --define(wxToolBar_FindControl, 985). --define(wxToolBar_FindToolForPosition, 986). --define(wxToolBar_GetToolSize, 987). --define(wxToolBar_GetToolBitmapSize, 988). --define(wxToolBar_GetMargins, 989). --define(wxToolBar_GetToolEnabled, 990). --define(wxToolBar_GetToolLongHelp, 991). --define(wxToolBar_GetToolPacking, 992). --define(wxToolBar_GetToolPos, 993). --define(wxToolBar_GetToolSeparation, 994). --define(wxToolBar_GetToolShortHelp, 995). --define(wxToolBar_GetToolState, 996). --define(wxToolBar_InsertControl, 997). --define(wxToolBar_InsertSeparator, 998). --define(wxToolBar_InsertTool_5, 999). --define(wxToolBar_InsertTool_2, 1000). --define(wxToolBar_Realize, 1001). --define(wxToolBar_RemoveTool, 1002). --define(wxToolBar_SetMargins, 1003). --define(wxToolBar_SetToolBitmapSize, 1004). --define(wxToolBar_SetToolLongHelp, 1005). --define(wxToolBar_SetToolPacking, 1006). --define(wxToolBar_SetToolShortHelp, 1007). --define(wxToolBar_SetToolSeparation, 1008). --define(wxToolBar_ToggleTool, 1009). --define(wxStatusBar_new_0, 1010). --define(wxStatusBar_new_2, 1011). --define(wxStatusBar_destruct, 1012). --define(wxStatusBar_Create, 1013). --define(wxStatusBar_GetFieldRect, 1014). --define(wxStatusBar_GetFieldsCount, 1015). --define(wxStatusBar_GetStatusText, 1016). --define(wxStatusBar_PopStatusText, 1017). --define(wxStatusBar_PushStatusText, 1018). --define(wxStatusBar_SetFieldsCount, 1019). --define(wxStatusBar_SetMinHeight, 1020). --define(wxStatusBar_SetStatusText, 1021). --define(wxStatusBar_SetStatusWidths, 1022). --define(wxStatusBar_SetStatusStyles, 1023). --define(wxBitmap_new_0, 1024). --define(wxBitmap_new_4, 1026). --define(wxBitmap_new_3, 1027). --define(wxBitmap_new_2_1, 1028). --define(wxBitmap_new_2_0, 1029). --define(wxBitmap_new_2_2, 1030). --define(wxBitmap_new_2_3, 1031). --define(wxBitmap_destruct, 1032). --define(wxBitmap_ConvertToImage, 1033). --define(wxBitmap_CopyFromIcon, 1034). --define(wxBitmap_Create_3_0, 1035). --define(wxBitmap_Create_2, 1036). --define(wxBitmap_Create_3_1, 1037). --define(wxBitmap_GetDepth, 1038). --define(wxBitmap_GetHeight, 1039). --define(wxBitmap_GetPalette, 1040). --define(wxBitmap_GetMask, 1041). --define(wxBitmap_GetWidth, 1042). --define(wxBitmap_GetSubBitmap, 1043). --define(wxBitmap_LoadFile, 1044). --define(wxBitmap_IsOk, 1045). --define(wxBitmap_SaveFile, 1046). --define(wxBitmap_SetDepth, 1047). --define(wxBitmap_SetHeight, 1048). --define(wxBitmap_SetMask, 1049). --define(wxBitmap_SetPalette, 1050). --define(wxBitmap_SetWidth, 1051). --define(wxIcon_new_0, 1052). --define(wxIcon_new_1, 1053). --define(wxIcon_new_2, 1054). --define(wxIcon_CopyFromBitmap, 1055). --define(wxIcon_destruct, 1056). --define(wxIconBundle_new_0, 1057). --define(wxIconBundle_new_1_1, 1058). --define(wxIconBundle_new_2, 1059). --define(wxIconBundle_new_1_0, 1061). --define(wxIconBundle_destruct, 1062). --define(wxIconBundle_AddIcon_1_0, 1063). --define(wxIconBundle_AddIcon_2, 1064). --define(wxIconBundle_AddIcon_1_1, 1065). --define(wxIconBundle_GetIcon_2, 1066). --define(wxIconBundle_GetIcon_1, 1067). --define(wxCursor_new_0, 1068). --define(wxCursor_new_2, 1069). --define(wxCursor_new_1_1, 1070). --define(wxCursor_new_1_0, 1071). --define(wxCursor_destruct, 1073). --define(wxCursor_IsOk, 1074). --define(wxMask_new_0, 1075). --define(wxMask_new_2_0, 1076). --define(wxMask_new_1, 1077). --define(wxMask_new_2_1, 1078). --define(wxMask_destruct, 1079). --define(wxMask_Create_2_0, 1080). --define(wxMask_Create_1, 1081). --define(wxMask_Create_2_1, 1082). --define(wxImage_new_0, 1083). --define(wxImage_new_3_1, 1084). --define(wxImage_new_2_2, 1085). --define(wxImage_new_3_0, 1086). --define(wxImage_new_2_1, 1087). --define(wxImage_new_4, 1088). --define(wxImage_new_3_3, 1089). --define(wxImage_new_2_0, 1090). --define(wxImage_new_3_2, 1091). --define(wxImage_destruct, 1092). --define(wxImage_Blur, 1093). --define(wxImage_BlurHorizontal, 1094). --define(wxImage_BlurVertical, 1095). --define(wxImage_ConvertAlphaToMask_1, 1096). --define(wxImage_ConvertAlphaToMask_4, 1097). --define(wxImage_ConvertToGreyscale_3, 1098). --define(wxImage_ConvertToGreyscale_0, 1099). --define(wxImage_ConvertToMono, 1100). --define(wxImage_Copy, 1101). --define(wxImage_Create_3_1, 1102). --define(wxImage_Create_2_1, 1103). --define(wxImage_Create_3_0, 1104). --define(wxImage_Create_2_0, 1105). --define(wxImage_Create_4, 1106). --define(wxImage_Create_3_2, 1107). --define(wxImage_Destroy, 1108). --define(wxImage_FindFirstUnusedColour, 1109). --define(wxImage_GetImageExtWildcard, 1110). --define(wxImage_GetAlpha_0, 1111). --define(wxImage_GetAlpha_2, 1112). --define(wxImage_GetBlue, 1113). --define(wxImage_GetData, 1114). --define(wxImage_GetGreen, 1115). --define(wxImage_GetImageCount, 1116). --define(wxImage_GetHeight, 1117). --define(wxImage_GetMaskBlue, 1118). --define(wxImage_GetMaskGreen, 1119). --define(wxImage_GetMaskRed, 1120). --define(wxImage_GetOrFindMaskColour, 1121). --define(wxImage_GetPalette, 1122). --define(wxImage_GetRed, 1123). --define(wxImage_GetSubImage, 1124). --define(wxImage_GetWidth, 1125). --define(wxImage_HasAlpha, 1126). --define(wxImage_HasMask, 1127). --define(wxImage_GetOption, 1128). --define(wxImage_GetOptionInt, 1129). --define(wxImage_HasOption, 1130). --define(wxImage_InitAlpha, 1131). --define(wxImage_InitStandardHandlers, 1132). --define(wxImage_IsTransparent, 1133). --define(wxImage_LoadFile_2, 1134). --define(wxImage_LoadFile_3, 1135). --define(wxImage_IsOk, 1136). --define(wxImage_RemoveHandler, 1137). --define(wxImage_Mirror, 1138). --define(wxImage_Replace, 1139). --define(wxImage_Rescale, 1140). --define(wxImage_Resize, 1141). --define(wxImage_Rotate, 1142). --define(wxImage_RotateHue, 1143). --define(wxImage_Rotate90, 1144). --define(wxImage_SaveFile_2_0, 1145). --define(wxImage_SaveFile_2_1, 1146). --define(wxImage_SaveFile_1, 1147). --define(wxImage_Scale, 1148). --define(wxImage_Size, 1149). --define(wxImage_SetAlpha_1, 1150). --define(wxImage_SetAlpha_3, 1151). --define(wxImage_SetData_1, 1152). --define(wxImage_SetData_3, 1153). --define(wxImage_SetMask, 1154). --define(wxImage_SetMaskColour, 1155). --define(wxImage_SetMaskFromImage, 1156). --define(wxImage_SetOption_2_1, 1157). --define(wxImage_SetOption_2_0, 1158). --define(wxImage_SetPalette, 1159). --define(wxImage_SetRGB_5, 1160). --define(wxImage_SetRGB_4, 1161). --define(wxBrush_new_0, 1162). --define(wxBrush_new_2, 1163). --define(wxBrush_new_1, 1165). --define(wxBrush_destruct, 1166). --define(wxBrush_GetColour, 1167). --define(wxBrush_GetStipple, 1168). --define(wxBrush_GetStyle, 1169). --define(wxBrush_IsHatch, 1170). --define(wxBrush_IsOk, 1171). --define(wxBrush_SetColour_1, 1172). --define(wxBrush_SetColour_3, 1173). --define(wxBrush_SetStipple, 1174). --define(wxBrush_SetStyle, 1175). --define(wxPen_new_0, 1176). --define(wxPen_new_2, 1177). --define(wxPen_new_1, 1178). --define(wxPen_destruct, 1179). --define(wxPen_GetCap, 1180). --define(wxPen_GetColour, 1181). --define(wxPen_GetJoin, 1182). --define(wxPen_GetStyle, 1183). --define(wxPen_GetWidth, 1184). --define(wxPen_IsOk, 1185). --define(wxPen_SetCap, 1186). --define(wxPen_SetColour_1, 1187). --define(wxPen_SetColour_3, 1188). --define(wxPen_SetJoin, 1189). --define(wxPen_SetStyle, 1190). --define(wxPen_SetWidth, 1191). --define(wxRegion_new_0, 1192). --define(wxRegion_new_4, 1193). --define(wxRegion_new_2, 1194). --define(wxRegion_new_1_0, 1195). --define(wxRegion_new_1_1, 1197). --define(wxRegion_destruct, 1199). --define(wxRegion_Clear, 1200). --define(wxRegion_Contains_2, 1201). --define(wxRegion_Contains_1_0, 1202). --define(wxRegion_Contains_4, 1203). --define(wxRegion_Contains_1_1, 1204). --define(wxRegion_ConvertToBitmap, 1205). --define(wxRegion_GetBox, 1206). --define(wxRegion_Intersect_4, 1207). --define(wxRegion_Intersect_1_0, 1208). --define(wxRegion_Intersect_1_1, 1209). --define(wxRegion_IsEmpty, 1210). --define(wxRegion_Subtract_1_0, 1211). --define(wxRegion_Subtract_1_1, 1212). --define(wxRegion_Offset_2, 1213). --define(wxRegion_Offset_1, 1214). --define(wxRegion_Union_4, 1215). --define(wxRegion_Union_1_1, 1216). --define(wxRegion_Union_1_0, 1217). --define(wxRegion_Union_3, 1219). --define(wxRegion_Xor_4, 1220). --define(wxRegion_Xor_1_0, 1221). --define(wxRegion_Xor_1_1, 1222). --define(wxAcceleratorTable_new_0, 1223). --define(wxAcceleratorTable_new_2, 1224). --define(wxAcceleratorTable_destruct, 1226). --define(wxAcceleratorTable_IsOk, 1227). --define(wxAcceleratorEntry_new_1_0, 1228). --define(wxAcceleratorEntry_new_1_1, 1229). --define(wxAcceleratorEntry_GetCommand, 1230). --define(wxAcceleratorEntry_GetFlags, 1231). --define(wxAcceleratorEntry_GetKeyCode, 1232). --define(wxAcceleratorEntry_Set, 1233). --define(wxAcceleratorEntry_destroy, 1234). --define(wxCaret_new_3, 1236). --define(wxCaret_new_2, 1237). --define(wxCaret_Create_3, 1238). --define(wxCaret_Create_2, 1239). --define(wxCaret_GetBlinkTime, 1240). --define(wxCaret_GetPosition, 1242). --define(wxCaret_GetSize, 1244). --define(wxCaret_GetWindow, 1245). --define(wxCaret_Hide, 1246). --define(wxCaret_IsOk, 1247). --define(wxCaret_IsVisible, 1248). --define(wxCaret_Move_2, 1249). --define(wxCaret_Move_1, 1250). --define(wxCaret_SetBlinkTime, 1251). --define(wxCaret_SetSize_2, 1252). --define(wxCaret_SetSize_1, 1253). --define(wxCaret_Show, 1254). --define(wxCaret_destroy, 1255). --define(wxSizer_Add_2_0, 1256). --define(wxSizer_Add_2_1, 1257). --define(wxSizer_Add_3_0, 1260). --define(wxSizer_Add_3_1, 1261). --define(wxSizer_AddSpacer, 1262). --define(wxSizer_AddStretchSpacer, 1263). --define(wxSizer_CalcMin, 1264). --define(wxSizer_Clear, 1265). --define(wxSizer_Detach_1_0, 1266). --define(wxSizer_Detach_1_1, 1268). --define(wxSizer_Fit, 1269). --define(wxSizer_FitInside, 1270). --define(wxSizer_GetChildren, 1272). --define(wxSizer_GetItem_2, 1273). --define(wxSizer_GetItem_1, 1275). --define(wxSizer_GetSize, 1276). --define(wxSizer_GetPosition, 1277). --define(wxSizer_GetMinSize, 1278). --define(wxSizer_Hide_2, 1279). --define(wxSizer_Hide_1, 1281). --define(wxSizer_Insert_3_0, 1282). --define(wxSizer_Insert_3_1, 1283). --define(wxSizer_Insert_4_0, 1286). --define(wxSizer_Insert_4_1, 1287). --define(wxSizer_Insert_2, 1288). --define(wxSizer_InsertSpacer, 1289). --define(wxSizer_InsertStretchSpacer, 1290). --define(wxSizer_IsShown_1_0, 1291). --define(wxSizer_IsShown_1_1, 1293). --define(wxSizer_Layout, 1294). --define(wxSizer_Prepend_2_0, 1295). --define(wxSizer_Prepend_2_1, 1296). --define(wxSizer_Prepend_3_0, 1299). --define(wxSizer_Prepend_3_1, 1300). --define(wxSizer_Prepend_1, 1301). --define(wxSizer_PrependSpacer, 1302). --define(wxSizer_PrependStretchSpacer, 1303). --define(wxSizer_Remove_1_1, 1304). --define(wxSizer_Remove_1_0, 1305). --define(wxSizer_Replace_3, 1306). --define(wxSizer_Replace_2, 1308). --define(wxSizer_SetDimension_4, 1309). --define(wxSizer_SetDimension_2, 1310). --define(wxSizer_SetMinSize_1, 1311). --define(wxSizer_SetMinSize_2, 1312). --define(wxSizer_SetItemMinSize_3_0, 1313). --define(wxSizer_SetItemMinSize_2_0, 1314). --define(wxSizer_SetItemMinSize_3_1, 1317). --define(wxSizer_SetItemMinSize_2_1, 1318). --define(wxSizer_SetSizeHints, 1319). --define(wxSizer_Show_2_0, 1320). --define(wxSizer_Show_2_1, 1322). --define(wxSizer_Show_1, 1323). --define(wxSizer_ShowItems, 1324). --define(wxSizerFlags_new, 1325). --define(wxSizerFlags_Align, 1326). --define(wxSizerFlags_Border_2, 1327). --define(wxSizerFlags_Border_1, 1328). --define(wxSizerFlags_Center, 1329). --define(wxSizerFlags_Expand, 1330). --define(wxSizerFlags_Left, 1331). --define(wxSizerFlags_Proportion, 1332). --define(wxSizerFlags_Right, 1333). --define(wxSizerFlags_destroy, 1334). --define(wxSizerItem_new_3, 1335). --define(wxSizerItem_new_2_0, 1336). --define(wxSizerItem_new_2_1, 1337). --define(wxSizerItem_destruct, 1340). --define(wxSizerItem_CalcMin, 1341). --define(wxSizerItem_DeleteWindows, 1342). --define(wxSizerItem_DetachSizer, 1343). --define(wxSizerItem_GetBorder, 1344). --define(wxSizerItem_GetFlag, 1345). --define(wxSizerItem_GetMinSize, 1346). --define(wxSizerItem_GetPosition, 1347). --define(wxSizerItem_GetProportion, 1348). --define(wxSizerItem_GetRatio, 1349). --define(wxSizerItem_GetRect, 1350). --define(wxSizerItem_GetSize, 1351). --define(wxSizerItem_GetSizer, 1352). --define(wxSizerItem_GetSpacer, 1353). --define(wxSizerItem_GetUserData, 1354). --define(wxSizerItem_GetWindow, 1355). --define(wxSizerItem_IsSizer, 1356). --define(wxSizerItem_IsShown, 1357). --define(wxSizerItem_IsSpacer, 1358). --define(wxSizerItem_IsWindow, 1359). --define(wxSizerItem_SetBorder, 1360). --define(wxSizerItem_SetDimension, 1361). --define(wxSizerItem_SetFlag, 1362). --define(wxSizerItem_SetInitSize, 1363). --define(wxSizerItem_SetMinSize_1, 1364). --define(wxSizerItem_SetMinSize_2, 1365). --define(wxSizerItem_SetProportion, 1366). --define(wxSizerItem_SetRatio_2, 1367). --define(wxSizerItem_SetRatio_1_1, 1368). --define(wxSizerItem_SetRatio_1_0, 1369). --define(wxSizerItem_AssignSizer, 1370). --define(wxSizerItem_AssignSpacer_1, 1371). --define(wxSizerItem_AssignSpacer_2, 1372). --define(wxSizerItem_AssignWindow, 1373). --define(wxSizerItem_Show, 1374). --define(wxBoxSizer_new, 1375). --define(wxBoxSizer_GetOrientation, 1376). --define(wxBoxSizer_destroy, 1377). --define(wxStaticBoxSizer_new_2, 1378). --define(wxStaticBoxSizer_new_3, 1379). --define(wxStaticBoxSizer_GetStaticBox, 1380). --define(wxStaticBoxSizer_destroy, 1381). --define(wxGridSizer_new_3_0, 1382). --define(wxGridSizer_new_2, 1383). --define(wxGridSizer_new_4, 1384). --define(wxGridSizer_new_3_1, 1385). --define(wxGridSizer_GetCols, 1386). --define(wxGridSizer_GetHGap, 1387). --define(wxGridSizer_GetRows, 1388). --define(wxGridSizer_GetVGap, 1389). --define(wxGridSizer_SetCols, 1390). --define(wxGridSizer_SetHGap, 1391). --define(wxGridSizer_SetRows, 1392). --define(wxGridSizer_SetVGap, 1393). --define(wxGridSizer_destroy, 1394). --define(wxFlexGridSizer_new_3_0, 1395). --define(wxFlexGridSizer_new_2, 1396). --define(wxFlexGridSizer_new_4, 1397). --define(wxFlexGridSizer_new_3_1, 1398). --define(wxFlexGridSizer_AddGrowableCol, 1399). --define(wxFlexGridSizer_AddGrowableRow, 1400). --define(wxFlexGridSizer_GetFlexibleDirection, 1401). --define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1402). --define(wxFlexGridSizer_RemoveGrowableCol, 1403). --define(wxFlexGridSizer_RemoveGrowableRow, 1404). --define(wxFlexGridSizer_SetFlexibleDirection, 1405). --define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1406). --define(wxFlexGridSizer_destroy, 1407). --define(wxGridBagSizer_new, 1408). --define(wxGridBagSizer_Add_3, 1409). --define(wxGridBagSizer_Add_1, 1411). --define(wxGridBagSizer_Add_4, 1412). --define(wxGridBagSizer_CalcMin, 1413). --define(wxGridBagSizer_CheckForIntersection_2, 1414). --define(wxGridBagSizer_CheckForIntersection_3, 1415). --define(wxGridBagSizer_FindItem, 1416). --define(wxGridBagSizer_FindItemAtPoint, 1418). --define(wxGridBagSizer_FindItemAtPosition, 1419). --define(wxGridBagSizer_FindItemWithData, 1420). --define(wxGridBagSizer_GetCellSize, 1421). --define(wxGridBagSizer_GetEmptyCellSize, 1422). --define(wxGridBagSizer_GetItemPosition_1_0, 1423). --define(wxGridBagSizer_GetItemPosition_1_1, 1425). --define(wxGridBagSizer_GetItemSpan_1_0, 1426). --define(wxGridBagSizer_GetItemSpan_1_1, 1428). --define(wxGridBagSizer_SetEmptyCellSize, 1429). --define(wxGridBagSizer_SetItemPosition_2_0, 1430). --define(wxGridBagSizer_SetItemPosition_2_1, 1432). --define(wxGridBagSizer_SetItemSpan_2_0, 1433). --define(wxGridBagSizer_SetItemSpan_2_1, 1435). --define(wxGridBagSizer_destroy, 1436). --define(wxStdDialogButtonSizer_new, 1437). --define(wxStdDialogButtonSizer_AddButton, 1438). --define(wxStdDialogButtonSizer_Realize, 1439). --define(wxStdDialogButtonSizer_SetAffirmativeButton, 1440). --define(wxStdDialogButtonSizer_SetCancelButton, 1441). --define(wxStdDialogButtonSizer_SetNegativeButton, 1442). --define(wxStdDialogButtonSizer_destroy, 1443). --define(wxFont_new_0, 1444). --define(wxFont_new_1_1, 1445). --define(wxFont_new_5_0, 1446). --define(wxFont_new_5_1, 1447). --define(wxFont_new_1_0, 1448). --define(wxFont_destruct, 1449). --define(wxFont_IsFixedWidth, 1450). --define(wxFont_GetDefaultEncoding, 1451). --define(wxFont_GetFaceName, 1452). --define(wxFont_GetFamily, 1453). --define(wxFont_GetNativeFontInfoDesc, 1454). --define(wxFont_GetNativeFontInfoUserDesc, 1455). --define(wxFont_GetPointSize, 1456). --define(wxFont_GetStyle, 1457). --define(wxFont_GetUnderlined, 1458). --define(wxFont_GetWeight, 1459). --define(wxFont_IsOk, 1460). --define(wxFont_SetDefaultEncoding, 1461). --define(wxFont_SetFaceName, 1462). --define(wxFont_SetFamily, 1463). --define(wxFont_SetPointSize, 1464). --define(wxFont_SetStyle, 1465). --define(wxFont_SetUnderlined, 1466). --define(wxFont_SetWeight, 1467). --define(wxToolTip_Enable, 1468). --define(wxToolTip_SetDelay, 1469). --define(wxToolTip_new, 1470). --define(wxToolTip_SetTip, 1471). --define(wxToolTip_GetTip, 1472). --define(wxToolTip_GetWindow, 1473). --define(wxToolTip_destroy, 1474). --define(wxButton_new_0, 1475). --define(wxButton_new_3, 1476). --define(wxButton_Create, 1477). --define(wxButton_GetDefaultSize_STAT_0, 1478). --define(wxButton_GetDefaultSize_STAT_1, 1479). --define(wxButton_SetDefault, 1480). --define(wxButton_SetLabel, 1481). --define(wxButton_GetBitmapDisabled, 1482). --define(wxButton_GetBitmapFocus, 1483). --define(wxButton_GetBitmapLabel, 1484). --define(wxButton_SetBitmapDisabled, 1485). --define(wxButton_SetBitmapFocus, 1486). --define(wxButton_SetBitmapLabel, 1487). --define(wxButton_destroy, 1488). --define(wxBitmapButton_new_0, 1489). --define(wxBitmapButton_new_4, 1490). --define(wxBitmapButton_Create, 1491). --define(wxBitmapButton_NewCloseButton, 1492). --define(wxBitmapButton_destroy, 1493). --define(wxToggleButton_new_0, 1494). --define(wxToggleButton_new_4, 1495). --define(wxToggleButton_destruct, 1496). --define(wxToggleButton_Create, 1497). --define(wxToggleButton_GetValue, 1498). --define(wxToggleButton_SetValue, 1499). --define(wxCalendarCtrl_new_0, 1500). --define(wxCalendarCtrl_new_3, 1501). --define(wxCalendarCtrl_Create, 1502). --define(wxCalendarCtrl_destruct, 1503). --define(wxCalendarCtrl_SetDate, 1504). --define(wxCalendarCtrl_GetDate, 1505). --define(wxCalendarCtrl_EnableYearChange, 1506). --define(wxCalendarCtrl_EnableMonthChange, 1507). --define(wxCalendarCtrl_EnableHolidayDisplay, 1508). --define(wxCalendarCtrl_SetHeaderColours, 1509). --define(wxCalendarCtrl_GetHeaderColourFg, 1510). --define(wxCalendarCtrl_GetHeaderColourBg, 1511). --define(wxCalendarCtrl_SetHighlightColours, 1512). --define(wxCalendarCtrl_GetHighlightColourFg, 1513). --define(wxCalendarCtrl_GetHighlightColourBg, 1514). --define(wxCalendarCtrl_SetHolidayColours, 1515). --define(wxCalendarCtrl_GetHolidayColourFg, 1516). --define(wxCalendarCtrl_GetHolidayColourBg, 1517). --define(wxCalendarCtrl_GetAttr, 1518). --define(wxCalendarCtrl_SetAttr, 1519). --define(wxCalendarCtrl_SetHoliday, 1520). --define(wxCalendarCtrl_ResetAttr, 1521). --define(wxCalendarCtrl_HitTest, 1522). --define(wxCalendarDateAttr_new_1, 1523). --define(wxCalendarDateAttr_new_2, 1524). --define(wxCalendarDateAttr_SetTextColour, 1525). --define(wxCalendarDateAttr_SetBackgroundColour, 1526). --define(wxCalendarDateAttr_SetBorderColour, 1527). --define(wxCalendarDateAttr_SetFont, 1528). --define(wxCalendarDateAttr_SetBorder, 1529). --define(wxCalendarDateAttr_SetHoliday, 1530). --define(wxCalendarDateAttr_HasTextColour, 1531). --define(wxCalendarDateAttr_HasBackgroundColour, 1532). --define(wxCalendarDateAttr_HasBorderColour, 1533). --define(wxCalendarDateAttr_HasFont, 1534). --define(wxCalendarDateAttr_HasBorder, 1535). --define(wxCalendarDateAttr_IsHoliday, 1536). --define(wxCalendarDateAttr_GetTextColour, 1537). --define(wxCalendarDateAttr_GetBackgroundColour, 1538). --define(wxCalendarDateAttr_GetBorderColour, 1539). --define(wxCalendarDateAttr_GetFont, 1540). --define(wxCalendarDateAttr_GetBorder, 1541). --define(wxCalendarDateAttr_destroy, 1542). --define(wxCheckBox_new_0, 1543). --define(wxCheckBox_new_4, 1544). --define(wxCheckBox_destruct, 1545). --define(wxCheckBox_Create, 1546). --define(wxCheckBox_GetValue, 1547). --define(wxCheckBox_Get3StateValue, 1548). --define(wxCheckBox_Is3rdStateAllowedForUser, 1549). --define(wxCheckBox_Is3State, 1550). --define(wxCheckBox_IsChecked, 1551). --define(wxCheckBox_SetValue, 1552). --define(wxCheckBox_Set3StateValue, 1553). --define(wxCheckListBox_new_0, 1554). --define(wxCheckListBox_new_3, 1556). --define(wxCheckListBox_destruct, 1557). --define(wxCheckListBox_Check, 1558). --define(wxCheckListBox_IsChecked, 1559). --define(wxChoice_new_0, 1560). --define(wxChoice_new_3, 1562). --define(wxChoice_destruct, 1563). --define(wxChoice_Create, 1565). --define(wxChoice_Delete, 1566). --define(wxChoice_GetColumns, 1567). --define(wxChoice_SetColumns, 1568). --define(wxComboBox_new_0, 1569). --define(wxComboBox_new_3, 1571). --define(wxComboBox_destruct, 1572). --define(wxComboBox_Create, 1574). --define(wxComboBox_CanCopy, 1575). --define(wxComboBox_CanCut, 1576). --define(wxComboBox_CanPaste, 1577). --define(wxComboBox_CanRedo, 1578). --define(wxComboBox_CanUndo, 1579). --define(wxComboBox_Copy, 1580). --define(wxComboBox_Cut, 1581). --define(wxComboBox_GetInsertionPoint, 1582). --define(wxComboBox_GetLastPosition, 1583). --define(wxComboBox_GetValue, 1584). --define(wxComboBox_Paste, 1585). --define(wxComboBox_Redo, 1586). --define(wxComboBox_Replace, 1587). --define(wxComboBox_Remove, 1588). --define(wxComboBox_SetInsertionPoint, 1589). --define(wxComboBox_SetInsertionPointEnd, 1590). --define(wxComboBox_SetSelection_2, 1591). --define(wxComboBox_SetSelection_1, 1592). --define(wxComboBox_SetValue, 1593). --define(wxComboBox_Undo, 1594). --define(wxGauge_new_0, 1595). --define(wxGauge_new_4, 1596). --define(wxGauge_destruct, 1597). --define(wxGauge_Create, 1598). --define(wxGauge_GetRange, 1599). --define(wxGauge_GetValue, 1600). --define(wxGauge_IsVertical, 1601). --define(wxGauge_SetRange, 1602). --define(wxGauge_SetValue, 1603). --define(wxGauge_Pulse, 1604). --define(wxGenericDirCtrl_new_0, 1605). --define(wxGenericDirCtrl_new_2, 1606). --define(wxGenericDirCtrl_destruct, 1607). --define(wxGenericDirCtrl_Create, 1608). --define(wxGenericDirCtrl_Init, 1609). --define(wxGenericDirCtrl_CollapseTree, 1610). --define(wxGenericDirCtrl_ExpandPath, 1611). --define(wxGenericDirCtrl_GetDefaultPath, 1612). --define(wxGenericDirCtrl_GetPath_0, 1613). --define(wxGenericDirCtrl_GetPath_1, 1614). --define(wxGenericDirCtrl_GetFilePath, 1615). --define(wxGenericDirCtrl_GetFilter, 1616). --define(wxGenericDirCtrl_GetFilterIndex, 1617). --define(wxGenericDirCtrl_GetRootId, 1618). --define(wxGenericDirCtrl_GetTreeCtrl, 1619). --define(wxGenericDirCtrl_ReCreateTree, 1620). --define(wxGenericDirCtrl_SetDefaultPath, 1621). --define(wxGenericDirCtrl_SetFilter, 1622). --define(wxGenericDirCtrl_SetFilterIndex, 1623). --define(wxGenericDirCtrl_SetPath, 1624). --define(wxStaticBox_new_0, 1625). --define(wxStaticBox_new_4, 1626). --define(wxStaticBox_destruct, 1627). --define(wxStaticBox_Create, 1628). --define(wxStaticLine_new_0, 1629). --define(wxStaticLine_new_2, 1630). --define(wxStaticLine_Create, 1631). --define(wxStaticLine_IsVertical, 1632). --define(wxStaticLine_GetDefaultSize, 1633). --define(wxStaticLine_destroy, 1634). --define(wxListBox_new_0, 1635). --define(wxListBox_new_3, 1637). --define(wxListBox_destruct, 1638). --define(wxListBox_Create, 1640). --define(wxListBox_Deselect, 1641). --define(wxListBox_GetSelections, 1642). --define(wxListBox_InsertItems, 1643). --define(wxListBox_IsSelected, 1644). --define(wxListBox_Set, 1647). --define(wxListBox_HitTest_1, 1648). --define(wxListBox_HitTest_2, 1649). --define(wxListBox_SetFirstItem_1_0, 1650). --define(wxListBox_SetFirstItem_1_1, 1651). --define(wxListCtrl_new_0, 1652). --define(wxListCtrl_new_2, 1653). --define(wxListCtrl_destruct, 1654). --define(wxListCtrl_Arrange, 1655). --define(wxListCtrl_AssignImageList, 1656). --define(wxListCtrl_ClearAll, 1657). --define(wxListCtrl_Create, 1658). --define(wxListCtrl_DeleteAllItems, 1659). --define(wxListCtrl_DeleteColumn, 1660). --define(wxListCtrl_DeleteItem, 1661). --define(wxListCtrl_EditLabel, 1662). --define(wxListCtrl_EnsureVisible, 1663). --define(wxListCtrl_FindItem_3_0, 1664). --define(wxListCtrl_FindItem_3_1, 1665). --define(wxListCtrl_GetColumn, 1666). --define(wxListCtrl_GetColumnCount, 1667). --define(wxListCtrl_GetColumnWidth, 1668). --define(wxListCtrl_GetCountPerPage, 1669). --define(wxListCtrl_GetEditControl, 1670). --define(wxListCtrl_GetImageList, 1671). --define(wxListCtrl_GetItem, 1672). --define(wxListCtrl_GetItemBackgroundColour, 1673). --define(wxListCtrl_GetItemCount, 1674). --define(wxListCtrl_GetItemData, 1675). --define(wxListCtrl_GetItemFont, 1676). --define(wxListCtrl_GetItemPosition, 1677). --define(wxListCtrl_GetItemRect, 1678). --define(wxListCtrl_GetItemSpacing, 1679). --define(wxListCtrl_GetItemState, 1680). --define(wxListCtrl_GetItemText, 1681). --define(wxListCtrl_GetItemTextColour, 1682). --define(wxListCtrl_GetNextItem, 1683). --define(wxListCtrl_GetSelectedItemCount, 1684). --define(wxListCtrl_GetTextColour, 1685). --define(wxListCtrl_GetTopItem, 1686). --define(wxListCtrl_GetViewRect, 1687). --define(wxListCtrl_HitTest, 1688). --define(wxListCtrl_InsertColumn_2, 1689). --define(wxListCtrl_InsertColumn_3, 1690). --define(wxListCtrl_InsertItem_1, 1691). --define(wxListCtrl_InsertItem_2_1, 1692). --define(wxListCtrl_InsertItem_2_0, 1693). --define(wxListCtrl_InsertItem_3, 1694). --define(wxListCtrl_RefreshItem, 1695). --define(wxListCtrl_RefreshItems, 1696). --define(wxListCtrl_ScrollList, 1697). --define(wxListCtrl_SetBackgroundColour, 1698). --define(wxListCtrl_SetColumn, 1699). --define(wxListCtrl_SetColumnWidth, 1700). --define(wxListCtrl_SetImageList, 1701). --define(wxListCtrl_SetItem_1, 1702). --define(wxListCtrl_SetItem_4, 1703). --define(wxListCtrl_SetItemBackgroundColour, 1704). --define(wxListCtrl_SetItemCount, 1705). --define(wxListCtrl_SetItemData, 1706). --define(wxListCtrl_SetItemFont, 1707). --define(wxListCtrl_SetItemImage, 1708). --define(wxListCtrl_SetItemColumnImage, 1709). --define(wxListCtrl_SetItemPosition, 1710). --define(wxListCtrl_SetItemState, 1711). --define(wxListCtrl_SetItemText, 1712). --define(wxListCtrl_SetItemTextColour, 1713). --define(wxListCtrl_SetSingleStyle, 1714). --define(wxListCtrl_SetTextColour, 1715). --define(wxListCtrl_SetWindowStyleFlag, 1716). --define(wxListCtrl_SortItems, 1717). --define(wxListView_ClearColumnImage, 1718). --define(wxListView_Focus, 1719). --define(wxListView_GetFirstSelected, 1720). --define(wxListView_GetFocusedItem, 1721). --define(wxListView_GetNextSelected, 1722). --define(wxListView_IsSelected, 1723). --define(wxListView_Select, 1724). --define(wxListView_SetColumnImage, 1725). --define(wxListItem_new_0, 1726). --define(wxListItem_new_1, 1727). --define(wxListItem_Clear, 1728). --define(wxListItem_GetAlign, 1729). --define(wxListItem_GetBackgroundColour, 1730). --define(wxListItem_GetColumn, 1731). --define(wxListItem_GetFont, 1732). --define(wxListItem_GetId, 1733). --define(wxListItem_GetImage, 1734). --define(wxListItem_GetMask, 1735). --define(wxListItem_GetState, 1736). --define(wxListItem_GetText, 1737). --define(wxListItem_GetTextColour, 1738). --define(wxListItem_GetWidth, 1739). --define(wxListItem_SetAlign, 1740). --define(wxListItem_SetBackgroundColour, 1741). --define(wxListItem_SetColumn, 1742). --define(wxListItem_SetFont, 1743). --define(wxListItem_SetId, 1744). --define(wxListItem_SetImage, 1745). --define(wxListItem_SetMask, 1746). --define(wxListItem_SetState, 1747). --define(wxListItem_SetStateMask, 1748). --define(wxListItem_SetText, 1749). --define(wxListItem_SetTextColour, 1750). --define(wxListItem_SetWidth, 1751). --define(wxListItem_destroy, 1752). --define(wxListItemAttr_new_0, 1753). --define(wxListItemAttr_new_3, 1754). --define(wxListItemAttr_GetBackgroundColour, 1755). --define(wxListItemAttr_GetFont, 1756). --define(wxListItemAttr_GetTextColour, 1757). --define(wxListItemAttr_HasBackgroundColour, 1758). --define(wxListItemAttr_HasFont, 1759). --define(wxListItemAttr_HasTextColour, 1760). --define(wxListItemAttr_SetBackgroundColour, 1761). --define(wxListItemAttr_SetFont, 1762). --define(wxListItemAttr_SetTextColour, 1763). --define(wxListItemAttr_destroy, 1764). --define(wxImageList_new_0, 1765). --define(wxImageList_new_3, 1766). --define(wxImageList_Add_2_0, 1767). --define(wxImageList_Add_2_1, 1769). --define(wxImageList_Add_1, 1770). --define(wxImageList_Create, 1771). --define(wxImageList_Draw, 1772). --define(wxImageList_GetBitmap, 1773). --define(wxImageList_GetIcon, 1774). --define(wxImageList_GetImageCount, 1775). --define(wxImageList_GetSize, 1776). --define(wxImageList_Remove, 1778). --define(wxImageList_RemoveAll, 1779). --define(wxImageList_Replace_3, 1780). --define(wxImageList_Replace_2, 1782). --define(wxImageList_destroy, 1783). --define(wxTextAttr_new_0, 1784). --define(wxTextAttr_new_2, 1785). --define(wxTextAttr_new_1, 1786). --define(wxTextAttr_GetAlignment, 1787). --define(wxTextAttr_GetBackgroundColour, 1788). --define(wxTextAttr_GetFont, 1789). --define(wxTextAttr_GetFontEncoding, 1790). --define(wxTextAttr_GetFontFaceName, 1791). --define(wxTextAttr_GetFontSize, 1792). --define(wxTextAttr_GetFontStyle, 1793). --define(wxTextAttr_GetFontUnderlined, 1794). --define(wxTextAttr_GetFontWeight, 1795). --define(wxTextAttr_GetLeftIndent, 1796). --define(wxTextAttr_GetLeftSubIndent, 1797). --define(wxTextAttr_GetRightIndent, 1798). --define(wxTextAttr_GetTabs, 1799). --define(wxTextAttr_GetTextColour, 1800). --define(wxTextAttr_HasBackgroundColour, 1801). --define(wxTextAttr_HasFont, 1802). --define(wxTextAttr_HasTextColour, 1803). --define(wxTextAttr_GetFlags, 1804). --define(wxTextAttr_IsDefault, 1805). --define(wxTextAttr_SetAlignment, 1806). --define(wxTextAttr_SetBackgroundColour, 1807). --define(wxTextAttr_SetFlags, 1808). --define(wxTextAttr_SetFont, 1809). --define(wxTextAttr_SetFontEncoding, 1810). --define(wxTextAttr_SetFontFaceName, 1811). --define(wxTextAttr_SetFontFamily, 1812). --define(wxTextAttr_SetFontSize, 1813). --define(wxTextAttr_SetFontPointSize, 1814). --define(wxTextAttr_SetFontPixelSize, 1815). --define(wxTextAttr_SetFontStyle, 1816). --define(wxTextAttr_SetFontUnderlined, 1817). --define(wxTextAttr_SetFontWeight, 1818). --define(wxTextAttr_SetLeftIndent, 1819). --define(wxTextAttr_SetRightIndent, 1820). --define(wxTextAttr_SetTabs, 1821). --define(wxTextAttr_SetTextColour, 1822). --define(wxTextAttr_destroy, 1823). --define(wxTextCtrl_new_0, 1824). --define(wxTextCtrl_new_3, 1825). --define(wxTextCtrl_destruct, 1826). --define(wxTextCtrl_AppendText, 1827). --define(wxTextCtrl_CanCopy, 1828). --define(wxTextCtrl_CanCut, 1829). --define(wxTextCtrl_CanPaste, 1830). --define(wxTextCtrl_CanRedo, 1831). --define(wxTextCtrl_CanUndo, 1832). --define(wxTextCtrl_Clear, 1833). --define(wxTextCtrl_Copy, 1834). --define(wxTextCtrl_Create, 1835). --define(wxTextCtrl_Cut, 1836). --define(wxTextCtrl_DiscardEdits, 1837). --define(wxTextCtrl_ChangeValue, 1838). --define(wxTextCtrl_EmulateKeyPress, 1839). --define(wxTextCtrl_GetDefaultStyle, 1840). --define(wxTextCtrl_GetInsertionPoint, 1841). --define(wxTextCtrl_GetLastPosition, 1842). --define(wxTextCtrl_GetLineLength, 1843). --define(wxTextCtrl_GetLineText, 1844). --define(wxTextCtrl_GetNumberOfLines, 1845). --define(wxTextCtrl_GetRange, 1846). --define(wxTextCtrl_GetSelection, 1847). --define(wxTextCtrl_GetStringSelection, 1848). --define(wxTextCtrl_GetStyle, 1849). --define(wxTextCtrl_GetValue, 1850). --define(wxTextCtrl_IsEditable, 1851). --define(wxTextCtrl_IsModified, 1852). --define(wxTextCtrl_IsMultiLine, 1853). --define(wxTextCtrl_IsSingleLine, 1854). --define(wxTextCtrl_LoadFile, 1855). --define(wxTextCtrl_MarkDirty, 1856). --define(wxTextCtrl_Paste, 1857). --define(wxTextCtrl_PositionToXY, 1858). --define(wxTextCtrl_Redo, 1859). --define(wxTextCtrl_Remove, 1860). --define(wxTextCtrl_Replace, 1861). --define(wxTextCtrl_SaveFile, 1862). --define(wxTextCtrl_SetDefaultStyle, 1863). --define(wxTextCtrl_SetEditable, 1864). --define(wxTextCtrl_SetInsertionPoint, 1865). --define(wxTextCtrl_SetInsertionPointEnd, 1866). --define(wxTextCtrl_SetMaxLength, 1867). --define(wxTextCtrl_SetSelection, 1868). --define(wxTextCtrl_SetStyle, 1869). --define(wxTextCtrl_SetValue, 1870). --define(wxTextCtrl_ShowPosition, 1871). --define(wxTextCtrl_Undo, 1872). --define(wxTextCtrl_WriteText, 1873). --define(wxTextCtrl_XYToPosition, 1874). --define(wxBookCtrlBase_AddPage, 1875). --define(wxBookCtrlBase_InsertPage, 1876). --define(wxBookCtrlBase_DeletePage, 1877). --define(wxBookCtrlBase_RemovePage, 1878). --define(wxBookCtrlBase_DeleteAllPages, 1879). --define(wxBookCtrlBase_GetPage, 1880). --define(wxBookCtrlBase_GetPageCount, 1881). --define(wxBookCtrlBase_GetCurrentPage, 1882). --define(wxBookCtrlBase_AdvanceSelection, 1883). --define(wxBookCtrlBase_SetSelection, 1884). --define(wxBookCtrlBase_GetSelection, 1885). --define(wxBookCtrlBase_ChangeSelection, 1886). --define(wxBookCtrlBase_HitTest, 1887). --define(wxBookCtrlBase_GetPageText, 1888). --define(wxBookCtrlBase_SetPageText, 1889). --define(wxNotebook_new_0, 1890). --define(wxNotebook_new_3, 1891). --define(wxNotebook_destruct, 1892). --define(wxNotebook_AssignImageList, 1893). --define(wxNotebook_Create, 1894). --define(wxNotebook_GetImageList, 1895). --define(wxNotebook_GetPageImage, 1896). --define(wxNotebook_GetRowCount, 1897). --define(wxNotebook_GetThemeBackgroundColour, 1898). --define(wxNotebook_SetImageList, 1899). --define(wxNotebook_SetPadding, 1900). --define(wxNotebook_SetPageSize, 1901). --define(wxNotebook_SetPageImage, 1902). --define(wxChoicebook_new_0, 1903). --define(wxChoicebook_new_3, 1904). --define(wxChoicebook_AddPage, 1905). --define(wxChoicebook_AdvanceSelection, 1906). --define(wxChoicebook_AssignImageList, 1907). --define(wxChoicebook_Create, 1908). --define(wxChoicebook_DeleteAllPages, 1909). --define(wxChoicebook_GetCurrentPage, 1910). --define(wxChoicebook_GetImageList, 1911). --define(wxChoicebook_GetPage, 1912). --define(wxChoicebook_GetPageCount, 1913). --define(wxChoicebook_GetPageImage, 1914). --define(wxChoicebook_GetPageText, 1915). --define(wxChoicebook_GetSelection, 1916). --define(wxChoicebook_HitTest, 1917). --define(wxChoicebook_InsertPage, 1918). --define(wxChoicebook_SetImageList, 1919). --define(wxChoicebook_SetPageSize, 1920). --define(wxChoicebook_SetPageImage, 1921). --define(wxChoicebook_SetPageText, 1922). --define(wxChoicebook_SetSelection, 1923). --define(wxChoicebook_ChangeSelection, 1924). --define(wxChoicebook_destroy, 1925). --define(wxToolbook_new_0, 1926). --define(wxToolbook_new_3, 1927). --define(wxToolbook_AddPage, 1928). --define(wxToolbook_AdvanceSelection, 1929). --define(wxToolbook_AssignImageList, 1930). --define(wxToolbook_Create, 1931). --define(wxToolbook_DeleteAllPages, 1932). --define(wxToolbook_GetCurrentPage, 1933). --define(wxToolbook_GetImageList, 1934). --define(wxToolbook_GetPage, 1935). --define(wxToolbook_GetPageCount, 1936). --define(wxToolbook_GetPageImage, 1937). --define(wxToolbook_GetPageText, 1938). --define(wxToolbook_GetSelection, 1939). --define(wxToolbook_HitTest, 1940). --define(wxToolbook_InsertPage, 1941). --define(wxToolbook_SetImageList, 1942). --define(wxToolbook_SetPageSize, 1943). --define(wxToolbook_SetPageImage, 1944). --define(wxToolbook_SetPageText, 1945). --define(wxToolbook_SetSelection, 1946). --define(wxToolbook_ChangeSelection, 1947). --define(wxToolbook_destroy, 1948). --define(wxListbook_new_0, 1949). --define(wxListbook_new_3, 1950). --define(wxListbook_AddPage, 1951). --define(wxListbook_AdvanceSelection, 1952). --define(wxListbook_AssignImageList, 1953). --define(wxListbook_Create, 1954). --define(wxListbook_DeleteAllPages, 1955). --define(wxListbook_GetCurrentPage, 1956). --define(wxListbook_GetImageList, 1957). --define(wxListbook_GetPage, 1958). --define(wxListbook_GetPageCount, 1959). --define(wxListbook_GetPageImage, 1960). --define(wxListbook_GetPageText, 1961). --define(wxListbook_GetSelection, 1962). --define(wxListbook_HitTest, 1963). --define(wxListbook_InsertPage, 1964). --define(wxListbook_SetImageList, 1965). --define(wxListbook_SetPageSize, 1966). --define(wxListbook_SetPageImage, 1967). --define(wxListbook_SetPageText, 1968). --define(wxListbook_SetSelection, 1969). --define(wxListbook_ChangeSelection, 1970). --define(wxListbook_destroy, 1971). --define(wxTreebook_new_0, 1972). --define(wxTreebook_new_3, 1973). --define(wxTreebook_destruct, 1974). --define(wxTreebook_AddPage, 1975). --define(wxTreebook_AdvanceSelection, 1976). --define(wxTreebook_AssignImageList, 1977). --define(wxTreebook_Create, 1978). --define(wxTreebook_DeleteAllPages, 1979). --define(wxTreebook_GetCurrentPage, 1980). --define(wxTreebook_GetImageList, 1981). --define(wxTreebook_GetPage, 1982). --define(wxTreebook_GetPageCount, 1983). --define(wxTreebook_GetPageImage, 1984). --define(wxTreebook_GetPageText, 1985). --define(wxTreebook_GetSelection, 1986). --define(wxTreebook_ExpandNode, 1987). --define(wxTreebook_IsNodeExpanded, 1988). --define(wxTreebook_HitTest, 1989). --define(wxTreebook_InsertPage, 1990). --define(wxTreebook_InsertSubPage, 1991). --define(wxTreebook_SetImageList, 1992). --define(wxTreebook_SetPageSize, 1993). --define(wxTreebook_SetPageImage, 1994). --define(wxTreebook_SetPageText, 1995). --define(wxTreebook_SetSelection, 1996). --define(wxTreebook_ChangeSelection, 1997). --define(wxTreeCtrl_new_0, 1998). --define(wxTreeCtrl_new_2, 1999). --define(wxTreeCtrl_destruct, 2000). --define(wxTreeCtrl_AddRoot, 2001). --define(wxTreeCtrl_AppendItem, 2002). --define(wxTreeCtrl_AssignImageList, 2003). --define(wxTreeCtrl_AssignStateImageList, 2004). --define(wxTreeCtrl_Collapse, 2005). --define(wxTreeCtrl_CollapseAndReset, 2006). --define(wxTreeCtrl_Create, 2007). --define(wxTreeCtrl_Delete, 2008). --define(wxTreeCtrl_DeleteAllItems, 2009). --define(wxTreeCtrl_DeleteChildren, 2010). --define(wxTreeCtrl_EditLabel, 2011). --define(wxTreeCtrl_EnsureVisible, 2012). --define(wxTreeCtrl_Expand, 2013). --define(wxTreeCtrl_GetBoundingRect, 2014). --define(wxTreeCtrl_GetChildrenCount, 2015). --define(wxTreeCtrl_GetCount, 2016). --define(wxTreeCtrl_GetEditControl, 2017). --define(wxTreeCtrl_GetFirstChild, 2018). --define(wxTreeCtrl_GetNextChild, 2019). --define(wxTreeCtrl_GetFirstVisibleItem, 2020). --define(wxTreeCtrl_GetImageList, 2021). --define(wxTreeCtrl_GetIndent, 2022). --define(wxTreeCtrl_GetItemBackgroundColour, 2023). --define(wxTreeCtrl_GetItemData, 2024). --define(wxTreeCtrl_GetItemFont, 2025). --define(wxTreeCtrl_GetItemImage, 2026). --define(wxTreeCtrl_GetItemText, 2027). --define(wxTreeCtrl_GetItemTextColour, 2028). --define(wxTreeCtrl_GetLastChild, 2029). --define(wxTreeCtrl_GetNextSibling, 2030). --define(wxTreeCtrl_GetNextVisible, 2031). --define(wxTreeCtrl_GetItemParent, 2032). --define(wxTreeCtrl_GetPrevSibling, 2033). --define(wxTreeCtrl_GetPrevVisible, 2034). --define(wxTreeCtrl_GetRootItem, 2035). --define(wxTreeCtrl_GetSelection, 2036). --define(wxTreeCtrl_GetSelections, 2037). --define(wxTreeCtrl_GetStateImageList, 2038). --define(wxTreeCtrl_HitTest, 2039). --define(wxTreeCtrl_InsertItem, 2040). --define(wxTreeCtrl_IsBold, 2042). --define(wxTreeCtrl_IsExpanded, 2043). --define(wxTreeCtrl_IsSelected, 2044). --define(wxTreeCtrl_IsVisible, 2045). --define(wxTreeCtrl_ItemHasChildren, 2046). --define(wxTreeCtrl_IsTreeItemIdOk, 2047). --define(wxTreeCtrl_PrependItem, 2048). --define(wxTreeCtrl_ScrollTo, 2049). --define(wxTreeCtrl_SelectItem, 2050). --define(wxTreeCtrl_SetIndent, 2051). --define(wxTreeCtrl_SetImageList, 2052). --define(wxTreeCtrl_SetItemBackgroundColour, 2053). --define(wxTreeCtrl_SetItemBold, 2054). --define(wxTreeCtrl_SetItemData, 2055). --define(wxTreeCtrl_SetItemDropHighlight, 2056). --define(wxTreeCtrl_SetItemFont, 2057). --define(wxTreeCtrl_SetItemHasChildren, 2058). --define(wxTreeCtrl_SetItemImage, 2059). --define(wxTreeCtrl_SetItemText, 2060). --define(wxTreeCtrl_SetItemTextColour, 2061). --define(wxTreeCtrl_SetStateImageList, 2062). --define(wxTreeCtrl_SetWindowStyle, 2063). --define(wxTreeCtrl_SortChildren, 2064). --define(wxTreeCtrl_Toggle, 2065). --define(wxTreeCtrl_ToggleItemSelection, 2066). --define(wxTreeCtrl_Unselect, 2067). --define(wxTreeCtrl_UnselectAll, 2068). --define(wxTreeCtrl_UnselectItem, 2069). --define(wxScrollBar_new_0, 2070). --define(wxScrollBar_new_3, 2071). --define(wxScrollBar_destruct, 2072). --define(wxScrollBar_Create, 2073). --define(wxScrollBar_GetRange, 2074). --define(wxScrollBar_GetPageSize, 2075). --define(wxScrollBar_GetThumbPosition, 2076). --define(wxScrollBar_GetThumbSize, 2077). --define(wxScrollBar_SetThumbPosition, 2078). --define(wxScrollBar_SetScrollbar, 2079). --define(wxSpinButton_new_0, 2080). --define(wxSpinButton_new_2, 2081). --define(wxSpinButton_destruct, 2082). --define(wxSpinButton_Create, 2083). --define(wxSpinButton_GetMax, 2084). --define(wxSpinButton_GetMin, 2085). --define(wxSpinButton_GetValue, 2086). --define(wxSpinButton_SetRange, 2087). --define(wxSpinButton_SetValue, 2088). --define(wxSpinCtrl_new_0, 2089). --define(wxSpinCtrl_new_2, 2090). --define(wxSpinCtrl_Create, 2091). --define(wxSpinCtrl_SetValue_1_1, 2092). --define(wxSpinCtrl_SetValue_1_0, 2093). --define(wxSpinCtrl_GetValue, 2094). --define(wxSpinCtrl_SetRange, 2095). --define(wxSpinCtrl_SetSelection, 2096). --define(wxSpinCtrl_GetMin, 2097). --define(wxSpinCtrl_GetMax, 2098). --define(wxSpinCtrl_destroy, 2099). --define(wxStaticText_new_0, 2100). --define(wxStaticText_new_4, 2101). --define(wxStaticText_Create, 2102). --define(wxStaticText_GetLabel, 2103). --define(wxStaticText_SetLabel, 2104). --define(wxStaticText_Wrap, 2105). --define(wxStaticText_destroy, 2106). --define(wxStaticBitmap_new_0, 2107). --define(wxStaticBitmap_new_4, 2108). --define(wxStaticBitmap_Create, 2109). --define(wxStaticBitmap_GetBitmap, 2110). --define(wxStaticBitmap_SetBitmap, 2111). --define(wxStaticBitmap_destroy, 2112). --define(wxRadioBox_new, 2113). --define(wxRadioBox_destruct, 2114). --define(wxRadioBox_Create, 2115). --define(wxRadioBox_Enable_1, 2116). --define(wxRadioBox_Enable_2, 2117). --define(wxRadioBox_GetSelection, 2118). --define(wxRadioBox_GetString, 2119). --define(wxRadioBox_SetSelection, 2120). --define(wxRadioBox_Show, 2121). --define(wxRadioBox_GetColumnCount, 2122). --define(wxRadioBox_GetItemHelpText, 2123). --define(wxRadioBox_GetItemToolTip, 2124). --define(wxRadioBox_GetItemFromPoint, 2125). --define(wxRadioBox_GetRowCount, 2126). --define(wxRadioBox_IsItemEnabled, 2127). --define(wxRadioBox_IsItemShown, 2128). --define(wxRadioBox_SetItemHelpText, 2129). --define(wxRadioBox_SetItemToolTip, 2130). --define(wxRadioButton_new_0, 2131). --define(wxRadioButton_new_4, 2132). --define(wxRadioButton_destruct, 2133). --define(wxRadioButton_Create, 2134). --define(wxRadioButton_GetValue, 2135). --define(wxRadioButton_SetValue, 2136). --define(wxSlider_new_0, 2137). --define(wxSlider_new_6, 2138). --define(wxSlider_destruct, 2139). --define(wxSlider_Create, 2140). --define(wxSlider_GetLineSize, 2141). --define(wxSlider_GetMax, 2142). --define(wxSlider_GetMin, 2143). --define(wxSlider_GetPageSize, 2144). --define(wxSlider_GetThumbLength, 2145). --define(wxSlider_GetValue, 2146). --define(wxSlider_SetLineSize, 2147). --define(wxSlider_SetPageSize, 2148). --define(wxSlider_SetRange, 2149). --define(wxSlider_SetThumbLength, 2150). --define(wxSlider_SetValue, 2151). --define(wxDialog_new_0, 2152). --define(wxDialog_new_4, 2153). --define(wxDialog_destruct, 2154). --define(wxDialog_Create, 2155). --define(wxDialog_CreateButtonSizer, 2156). --define(wxDialog_CreateStdDialogButtonSizer, 2157). --define(wxDialog_EndModal, 2158). --define(wxDialog_GetAffirmativeId, 2159). --define(wxDialog_GetReturnCode, 2160). --define(wxDialog_IsModal, 2161). --define(wxDialog_SetAffirmativeId, 2162). --define(wxDialog_SetReturnCode, 2163). --define(wxDialog_Show, 2164). --define(wxDialog_ShowModal, 2165). --define(wxColourDialog_new_0, 2166). --define(wxColourDialog_new_2, 2167). --define(wxColourDialog_destruct, 2168). --define(wxColourDialog_Create, 2169). --define(wxColourDialog_GetColourData, 2170). --define(wxColourData_new, 2171). --define(wxColourData_destruct, 2172). --define(wxColourData_GetChooseFull, 2173). --define(wxColourData_GetColour, 2174). --define(wxColourData_GetCustomColour, 2175). --define(wxColourData_SetChooseFull, 2176). --define(wxColourData_SetColour, 2177). --define(wxColourData_SetCustomColour, 2178). --define(wxPalette_new_0, 2179). --define(wxPalette_new_1, 2180). --define(wxPalette_new_4, 2181). --define(wxPalette_destruct, 2182). --define(wxPalette_Create, 2183). --define(wxPalette_GetColoursCount, 2184). --define(wxPalette_GetPixel, 2185). --define(wxPalette_GetRGB, 2186). --define(wxPalette_IsOk, 2187). --define(wxDirDialog_new, 2188). --define(wxDirDialog_destruct, 2189). --define(wxDirDialog_GetPath, 2190). --define(wxDirDialog_GetMessage, 2191). --define(wxDirDialog_SetMessage, 2192). --define(wxDirDialog_SetPath, 2193). --define(wxFileDialog_new, 2194). --define(wxFileDialog_destruct, 2195). --define(wxFileDialog_GetDirectory, 2196). --define(wxFileDialog_GetFilename, 2197). --define(wxFileDialog_GetFilenames, 2198). --define(wxFileDialog_GetFilterIndex, 2199). --define(wxFileDialog_GetMessage, 2200). --define(wxFileDialog_GetPath, 2201). --define(wxFileDialog_GetPaths, 2202). --define(wxFileDialog_GetWildcard, 2203). --define(wxFileDialog_SetDirectory, 2204). --define(wxFileDialog_SetFilename, 2205). --define(wxFileDialog_SetFilterIndex, 2206). --define(wxFileDialog_SetMessage, 2207). --define(wxFileDialog_SetPath, 2208). --define(wxFileDialog_SetWildcard, 2209). --define(wxPickerBase_SetInternalMargin, 2210). --define(wxPickerBase_GetInternalMargin, 2211). --define(wxPickerBase_SetTextCtrlProportion, 2212). --define(wxPickerBase_SetPickerCtrlProportion, 2213). --define(wxPickerBase_GetTextCtrlProportion, 2214). --define(wxPickerBase_GetPickerCtrlProportion, 2215). --define(wxPickerBase_HasTextCtrl, 2216). --define(wxPickerBase_GetTextCtrl, 2217). --define(wxPickerBase_IsTextCtrlGrowable, 2218). --define(wxPickerBase_SetPickerCtrlGrowable, 2219). --define(wxPickerBase_SetTextCtrlGrowable, 2220). --define(wxPickerBase_IsPickerCtrlGrowable, 2221). --define(wxFilePickerCtrl_new_0, 2222). --define(wxFilePickerCtrl_new_3, 2223). --define(wxFilePickerCtrl_Create, 2224). --define(wxFilePickerCtrl_GetPath, 2225). --define(wxFilePickerCtrl_SetPath, 2226). --define(wxFilePickerCtrl_destroy, 2227). --define(wxDirPickerCtrl_new_0, 2228). --define(wxDirPickerCtrl_new_3, 2229). --define(wxDirPickerCtrl_Create, 2230). --define(wxDirPickerCtrl_GetPath, 2231). --define(wxDirPickerCtrl_SetPath, 2232). --define(wxDirPickerCtrl_destroy, 2233). --define(wxColourPickerCtrl_new_0, 2234). --define(wxColourPickerCtrl_new_3, 2235). --define(wxColourPickerCtrl_Create, 2236). --define(wxColourPickerCtrl_GetColour, 2237). --define(wxColourPickerCtrl_SetColour_1_1, 2238). --define(wxColourPickerCtrl_SetColour_1_0, 2239). --define(wxColourPickerCtrl_destroy, 2240). --define(wxDatePickerCtrl_new_0, 2241). --define(wxDatePickerCtrl_new_3, 2242). --define(wxDatePickerCtrl_GetRange, 2243). --define(wxDatePickerCtrl_GetValue, 2244). --define(wxDatePickerCtrl_SetRange, 2245). --define(wxDatePickerCtrl_SetValue, 2246). --define(wxDatePickerCtrl_destroy, 2247). --define(wxFontPickerCtrl_new_0, 2248). --define(wxFontPickerCtrl_new_3, 2249). --define(wxFontPickerCtrl_Create, 2250). --define(wxFontPickerCtrl_GetSelectedFont, 2251). --define(wxFontPickerCtrl_SetSelectedFont, 2252). --define(wxFontPickerCtrl_GetMaxPointSize, 2253). --define(wxFontPickerCtrl_SetMaxPointSize, 2254). --define(wxFontPickerCtrl_destroy, 2255). --define(wxFindReplaceDialog_new_0, 2256). --define(wxFindReplaceDialog_new_4, 2257). --define(wxFindReplaceDialog_destruct, 2258). --define(wxFindReplaceDialog_Create, 2259). --define(wxFindReplaceDialog_GetData, 2260). --define(wxFindReplaceData_new, 2261). --define(wxFindReplaceData_GetFindString, 2262). --define(wxFindReplaceData_GetReplaceString, 2263). --define(wxFindReplaceData_GetFlags, 2264). --define(wxFindReplaceData_SetFlags, 2265). --define(wxFindReplaceData_SetFindString, 2266). --define(wxFindReplaceData_SetReplaceString, 2267). --define(wxFindReplaceData_destroy, 2268). --define(wxMultiChoiceDialog_new, 2270). --define(wxMultiChoiceDialog_GetSelections, 2271). --define(wxMultiChoiceDialog_SetSelections, 2272). --define(wxMultiChoiceDialog_destroy, 2273). --define(wxSingleChoiceDialog_new, 2275). --define(wxSingleChoiceDialog_GetSelection, 2276). --define(wxSingleChoiceDialog_GetStringSelection, 2277). --define(wxSingleChoiceDialog_SetSelection, 2278). --define(wxSingleChoiceDialog_destroy, 2279). --define(wxTextEntryDialog_new_0, 2280). --define(wxTextEntryDialog_new_3, 2281). --define(wxTextEntryDialog_destruct, 2282). --define(wxTextEntryDialog_GetValue, 2283). --define(wxTextEntryDialog_SetValue, 2284). --define(wxPasswordEntryDialog_new, 2285). --define(wxPasswordEntryDialog_destroy, 2286). --define(wxFontData_new_0, 2287). --define(wxFontData_new_1, 2288). --define(wxFontData_EnableEffects, 2289). --define(wxFontData_GetAllowSymbols, 2290). --define(wxFontData_GetColour, 2291). --define(wxFontData_GetChosenFont, 2292). --define(wxFontData_GetEnableEffects, 2293). --define(wxFontData_GetInitialFont, 2294). --define(wxFontData_GetShowHelp, 2295). --define(wxFontData_SetAllowSymbols, 2296). --define(wxFontData_SetChosenFont, 2297). --define(wxFontData_SetColour, 2298). --define(wxFontData_SetInitialFont, 2299). --define(wxFontData_SetRange, 2300). --define(wxFontData_SetShowHelp, 2301). --define(wxFontData_destroy, 2302). --define(wxFontDialog_new_0, 2303). --define(wxFontDialog_new_2, 2305). --define(wxFontDialog_Create, 2307). --define(wxFontDialog_GetFontData, 2308). --define(wxFontDialog_destroy, 2310). --define(wxProgressDialog_new, 2311). --define(wxProgressDialog_Resume, 2312). --define(wxProgressDialog_Update, 2313). --define(wxProgressDialog_destroy, 2314). --define(wxMessageDialog_new, 2315). --define(wxMessageDialog_destroy, 2316). --define(wxPageSetupDialog_new, 2317). --define(wxPageSetupDialog_destruct, 2318). --define(wxPageSetupDialog_GetPageSetupData, 2319). --define(wxPageSetupDialog_ShowModal, 2320). --define(wxPageSetupDialogData_new_0, 2321). --define(wxPageSetupDialogData_new_1, 2323). --define(wxPageSetupDialogData_destruct, 2324). --define(wxPageSetupDialogData_EnableHelp, 2325). --define(wxPageSetupDialogData_EnableMargins, 2326). --define(wxPageSetupDialogData_EnableOrientation, 2327). --define(wxPageSetupDialogData_EnablePaper, 2328). --define(wxPageSetupDialogData_EnablePrinter, 2329). --define(wxPageSetupDialogData_GetDefaultMinMargins, 2330). --define(wxPageSetupDialogData_GetEnableMargins, 2331). --define(wxPageSetupDialogData_GetEnableOrientation, 2332). --define(wxPageSetupDialogData_GetEnablePaper, 2333). --define(wxPageSetupDialogData_GetEnablePrinter, 2334). --define(wxPageSetupDialogData_GetEnableHelp, 2335). --define(wxPageSetupDialogData_GetDefaultInfo, 2336). --define(wxPageSetupDialogData_GetMarginTopLeft, 2337). --define(wxPageSetupDialogData_GetMarginBottomRight, 2338). --define(wxPageSetupDialogData_GetMinMarginTopLeft, 2339). --define(wxPageSetupDialogData_GetMinMarginBottomRight, 2340). --define(wxPageSetupDialogData_GetPaperId, 2341). --define(wxPageSetupDialogData_GetPaperSize, 2342). --define(wxPageSetupDialogData_GetPrintData, 2344). --define(wxPageSetupDialogData_IsOk, 2345). --define(wxPageSetupDialogData_SetDefaultInfo, 2346). --define(wxPageSetupDialogData_SetDefaultMinMargins, 2347). --define(wxPageSetupDialogData_SetMarginTopLeft, 2348). --define(wxPageSetupDialogData_SetMarginBottomRight, 2349). --define(wxPageSetupDialogData_SetMinMarginTopLeft, 2350). --define(wxPageSetupDialogData_SetMinMarginBottomRight, 2351). --define(wxPageSetupDialogData_SetPaperId, 2352). --define(wxPageSetupDialogData_SetPaperSize, 2353). --define(wxPageSetupDialogData_SetPrintData, 2354). --define(wxPrintDialog_new_2_0, 2355). --define(wxPrintDialog_new_2_1, 2356). --define(wxPrintDialog_destruct, 2357). --define(wxPrintDialog_GetPrintDialogData, 2358). --define(wxPrintDialog_GetPrintDC, 2359). --define(wxPrintDialogData_new_0, 2360). --define(wxPrintDialogData_new_1, 2361). --define(wxPrintDialogData_destruct, 2363). --define(wxPrintDialogData_EnableHelp, 2364). --define(wxPrintDialogData_EnablePageNumbers, 2365). --define(wxPrintDialogData_EnablePrintToFile, 2366). --define(wxPrintDialogData_EnableSelection, 2367). --define(wxPrintDialogData_GetAllPages, 2368). --define(wxPrintDialogData_GetCollate, 2369). --define(wxPrintDialogData_GetFromPage, 2370). --define(wxPrintDialogData_GetMaxPage, 2371). --define(wxPrintDialogData_GetMinPage, 2372). --define(wxPrintDialogData_GetNoCopies, 2373). --define(wxPrintDialogData_GetPrintData, 2374). --define(wxPrintDialogData_GetPrintToFile, 2375). --define(wxPrintDialogData_GetSelection, 2376). --define(wxPrintDialogData_GetToPage, 2377). --define(wxPrintDialogData_IsOk, 2378). --define(wxPrintDialogData_SetCollate, 2379). --define(wxPrintDialogData_SetFromPage, 2380). --define(wxPrintDialogData_SetMaxPage, 2381). --define(wxPrintDialogData_SetMinPage, 2382). --define(wxPrintDialogData_SetNoCopies, 2383). --define(wxPrintDialogData_SetPrintData, 2384). --define(wxPrintDialogData_SetPrintToFile, 2385). --define(wxPrintDialogData_SetSelection, 2386). --define(wxPrintDialogData_SetToPage, 2387). --define(wxPrintData_new_0, 2388). --define(wxPrintData_new_1, 2389). --define(wxPrintData_destruct, 2390). --define(wxPrintData_GetCollate, 2391). --define(wxPrintData_GetBin, 2392). --define(wxPrintData_GetColour, 2393). --define(wxPrintData_GetDuplex, 2394). --define(wxPrintData_GetNoCopies, 2395). --define(wxPrintData_GetOrientation, 2396). --define(wxPrintData_GetPaperId, 2397). --define(wxPrintData_GetPrinterName, 2398). --define(wxPrintData_GetQuality, 2399). --define(wxPrintData_IsOk, 2400). --define(wxPrintData_SetBin, 2401). --define(wxPrintData_SetCollate, 2402). --define(wxPrintData_SetColour, 2403). --define(wxPrintData_SetDuplex, 2404). --define(wxPrintData_SetNoCopies, 2405). --define(wxPrintData_SetOrientation, 2406). --define(wxPrintData_SetPaperId, 2407). --define(wxPrintData_SetPrinterName, 2408). --define(wxPrintData_SetQuality, 2409). --define(wxPrintPreview_new_2, 2410). --define(wxPrintPreview_new_3, 2411). --define(wxPrintPreview_destruct, 2412). --define(wxPrintPreview_GetCanvas, 2413). --define(wxPrintPreview_GetCurrentPage, 2414). --define(wxPrintPreview_GetFrame, 2415). --define(wxPrintPreview_GetMaxPage, 2416). --define(wxPrintPreview_GetMinPage, 2417). --define(wxPrintPreview_GetPrintout, 2418). --define(wxPrintPreview_GetPrintoutForPrinting, 2419). --define(wxPrintPreview_IsOk, 2420). --define(wxPrintPreview_PaintPage, 2421). --define(wxPrintPreview_Print, 2422). --define(wxPrintPreview_RenderPage, 2423). --define(wxPrintPreview_SetCanvas, 2424). --define(wxPrintPreview_SetCurrentPage, 2425). --define(wxPrintPreview_SetFrame, 2426). --define(wxPrintPreview_SetPrintout, 2427). --define(wxPrintPreview_SetZoom, 2428). --define(wxPreviewFrame_new, 2429). --define(wxPreviewFrame_destruct, 2430). --define(wxPreviewFrame_CreateControlBar, 2431). --define(wxPreviewFrame_CreateCanvas, 2432). --define(wxPreviewFrame_Initialize, 2433). --define(wxPreviewFrame_OnCloseWindow, 2434). --define(wxPreviewControlBar_new, 2435). --define(wxPreviewControlBar_destruct, 2436). --define(wxPreviewControlBar_CreateButtons, 2437). --define(wxPreviewControlBar_GetPrintPreview, 2438). --define(wxPreviewControlBar_GetZoomControl, 2439). --define(wxPreviewControlBar_SetZoomControl, 2440). --define(wxPrinter_new, 2441). --define(wxPrinter_CreateAbortWindow, 2442). --define(wxPrinter_GetAbort, 2443). --define(wxPrinter_GetLastError, 2444). --define(wxPrinter_GetPrintDialogData, 2445). --define(wxPrinter_Print, 2446). --define(wxPrinter_PrintDialog, 2447). --define(wxPrinter_ReportError, 2448). --define(wxPrinter_Setup, 2449). --define(wxPrinter_destroy, 2450). --define(wxXmlResource_new_2, 2451). --define(wxXmlResource_new_1, 2452). --define(wxXmlResource_destruct, 2453). --define(wxXmlResource_AttachUnknownControl, 2454). --define(wxXmlResource_ClearHandlers, 2455). --define(wxXmlResource_CompareVersion, 2456). --define(wxXmlResource_Get, 2457). --define(wxXmlResource_GetFlags, 2458). --define(wxXmlResource_GetVersion, 2459). --define(wxXmlResource_GetXRCID, 2460). --define(wxXmlResource_InitAllHandlers, 2461). --define(wxXmlResource_Load, 2462). --define(wxXmlResource_LoadBitmap, 2463). --define(wxXmlResource_LoadDialog_2, 2464). --define(wxXmlResource_LoadDialog_3, 2465). --define(wxXmlResource_LoadFrame_2, 2466). --define(wxXmlResource_LoadFrame_3, 2467). --define(wxXmlResource_LoadIcon, 2468). --define(wxXmlResource_LoadMenu, 2469). --define(wxXmlResource_LoadMenuBar_2, 2470). --define(wxXmlResource_LoadMenuBar_1, 2471). --define(wxXmlResource_LoadPanel_2, 2472). --define(wxXmlResource_LoadPanel_3, 2473). --define(wxXmlResource_LoadToolBar, 2474). --define(wxXmlResource_Set, 2475). --define(wxXmlResource_SetFlags, 2476). --define(wxXmlResource_Unload, 2477). --define(wxXmlResource_xrcctrl, 2478). --define(wxHtmlEasyPrinting_new, 2479). --define(wxHtmlEasyPrinting_GetPrintData, 2480). --define(wxHtmlEasyPrinting_GetPageSetupData, 2481). --define(wxHtmlEasyPrinting_PreviewFile, 2482). --define(wxHtmlEasyPrinting_PreviewText, 2483). --define(wxHtmlEasyPrinting_PrintFile, 2484). --define(wxHtmlEasyPrinting_PrintText, 2485). --define(wxHtmlEasyPrinting_PageSetup, 2486). --define(wxHtmlEasyPrinting_SetFonts, 2487). --define(wxHtmlEasyPrinting_SetHeader, 2488). --define(wxHtmlEasyPrinting_SetFooter, 2489). --define(wxHtmlEasyPrinting_destroy, 2490). --define(wxGLCanvas_new, 2491). --define(wxGLCanvas_SetCurrent, 2492). --define(wxGLCanvas_SwapBuffers, 2493). --define(wxGLCanvas_destroy, 2494). --define(wxGLContext_new, 2495). --define(wxGLContext_SetCurrent, 2496). --define(wxGLContext_destroy, 2497). --define(wxAuiManager_new, 2498). --define(wxAuiManager_destruct, 2499). --define(wxAuiManager_AddPane_2_1, 2500). --define(wxAuiManager_AddPane_2_0, 2501). --define(wxAuiManager_AddPane_3, 2502). --define(wxAuiManager_DetachPane, 2503). --define(wxAuiManager_GetAllPanes, 2504). --define(wxAuiManager_GetArtProvider, 2505). --define(wxAuiManager_GetDockSizeConstraint, 2506). --define(wxAuiManager_GetFlags, 2507). --define(wxAuiManager_GetManagedWindow, 2508). --define(wxAuiManager_GetManager, 2509). --define(wxAuiManager_GetPane_1_1, 2510). --define(wxAuiManager_GetPane_1_0, 2511). --define(wxAuiManager_HideHint, 2512). --define(wxAuiManager_InsertPane, 2513). --define(wxAuiManager_LoadPaneInfo, 2514). --define(wxAuiManager_LoadPerspective, 2515). --define(wxAuiManager_SavePaneInfo, 2516). --define(wxAuiManager_SavePerspective, 2517). --define(wxAuiManager_SetArtProvider, 2518). --define(wxAuiManager_SetDockSizeConstraint, 2519). --define(wxAuiManager_SetFlags, 2520). --define(wxAuiManager_SetManagedWindow, 2521). --define(wxAuiManager_ShowHint, 2522). --define(wxAuiManager_UnInit, 2523). --define(wxAuiManager_Update, 2524). --define(wxAuiPaneInfo_new_0, 2525). --define(wxAuiPaneInfo_new_1, 2526). --define(wxAuiPaneInfo_BestSize_1, 2527). --define(wxAuiPaneInfo_BestSize_2, 2528). --define(wxAuiPaneInfo_Bottom, 2529). --define(wxAuiPaneInfo_BottomDockable, 2530). --define(wxAuiPaneInfo_Caption, 2531). --define(wxAuiPaneInfo_CaptionVisible, 2532). --define(wxAuiPaneInfo_Centre, 2533). --define(wxAuiPaneInfo_CentrePane, 2534). --define(wxAuiPaneInfo_CloseButton, 2535). --define(wxAuiPaneInfo_DefaultPane, 2536). --define(wxAuiPaneInfo_DestroyOnClose, 2537). --define(wxAuiPaneInfo_Direction, 2538). --define(wxAuiPaneInfo_Dock, 2539). --define(wxAuiPaneInfo_Dockable, 2540). --define(wxAuiPaneInfo_Fixed, 2541). --define(wxAuiPaneInfo_Float, 2542). --define(wxAuiPaneInfo_Floatable, 2543). --define(wxAuiPaneInfo_FloatingPosition_1, 2544). --define(wxAuiPaneInfo_FloatingPosition_2, 2545). --define(wxAuiPaneInfo_FloatingSize_1, 2546). --define(wxAuiPaneInfo_FloatingSize_2, 2547). --define(wxAuiPaneInfo_Gripper, 2548). --define(wxAuiPaneInfo_GripperTop, 2549). --define(wxAuiPaneInfo_HasBorder, 2550). --define(wxAuiPaneInfo_HasCaption, 2551). --define(wxAuiPaneInfo_HasCloseButton, 2552). --define(wxAuiPaneInfo_HasFlag, 2553). --define(wxAuiPaneInfo_HasGripper, 2554). --define(wxAuiPaneInfo_HasGripperTop, 2555). --define(wxAuiPaneInfo_HasMaximizeButton, 2556). --define(wxAuiPaneInfo_HasMinimizeButton, 2557). --define(wxAuiPaneInfo_HasPinButton, 2558). --define(wxAuiPaneInfo_Hide, 2559). --define(wxAuiPaneInfo_IsBottomDockable, 2560). --define(wxAuiPaneInfo_IsDocked, 2561). --define(wxAuiPaneInfo_IsFixed, 2562). --define(wxAuiPaneInfo_IsFloatable, 2563). --define(wxAuiPaneInfo_IsFloating, 2564). --define(wxAuiPaneInfo_IsLeftDockable, 2565). --define(wxAuiPaneInfo_IsMovable, 2566). --define(wxAuiPaneInfo_IsOk, 2567). --define(wxAuiPaneInfo_IsResizable, 2568). --define(wxAuiPaneInfo_IsRightDockable, 2569). --define(wxAuiPaneInfo_IsShown, 2570). --define(wxAuiPaneInfo_IsToolbar, 2571). --define(wxAuiPaneInfo_IsTopDockable, 2572). --define(wxAuiPaneInfo_Layer, 2573). --define(wxAuiPaneInfo_Left, 2574). --define(wxAuiPaneInfo_LeftDockable, 2575). --define(wxAuiPaneInfo_MaxSize_1, 2576). --define(wxAuiPaneInfo_MaxSize_2, 2577). --define(wxAuiPaneInfo_MaximizeButton, 2578). --define(wxAuiPaneInfo_MinSize_1, 2579). --define(wxAuiPaneInfo_MinSize_2, 2580). --define(wxAuiPaneInfo_MinimizeButton, 2581). --define(wxAuiPaneInfo_Movable, 2582). --define(wxAuiPaneInfo_Name, 2583). --define(wxAuiPaneInfo_PaneBorder, 2584). --define(wxAuiPaneInfo_PinButton, 2585). --define(wxAuiPaneInfo_Position, 2586). --define(wxAuiPaneInfo_Resizable, 2587). --define(wxAuiPaneInfo_Right, 2588). --define(wxAuiPaneInfo_RightDockable, 2589). --define(wxAuiPaneInfo_Row, 2590). --define(wxAuiPaneInfo_SafeSet, 2591). --define(wxAuiPaneInfo_SetFlag, 2592). --define(wxAuiPaneInfo_Show, 2593). --define(wxAuiPaneInfo_ToolbarPane, 2594). --define(wxAuiPaneInfo_Top, 2595). --define(wxAuiPaneInfo_TopDockable, 2596). --define(wxAuiPaneInfo_Window, 2597). --define(wxAuiPaneInfo_GetWindow, 2598). --define(wxAuiPaneInfo_GetFrame, 2599). --define(wxAuiPaneInfo_GetDirection, 2600). --define(wxAuiPaneInfo_GetLayer, 2601). --define(wxAuiPaneInfo_GetRow, 2602). --define(wxAuiPaneInfo_GetPosition, 2603). --define(wxAuiPaneInfo_GetFloatingPosition, 2604). --define(wxAuiPaneInfo_GetFloatingSize, 2605). --define(wxAuiPaneInfo_destroy, 2606). --define(wxAuiNotebook_new_0, 2607). --define(wxAuiNotebook_new_2, 2608). --define(wxAuiNotebook_AddPage_3, 2609). --define(wxAuiNotebook_AddPage_4, 2610). --define(wxAuiNotebook_Create_2, 2611). --define(wxAuiNotebook_Create_3, 2612). --define(wxAuiNotebook_DeletePage, 2613). --define(wxAuiNotebook_GetArtProvider, 2614). --define(wxAuiNotebook_GetPage, 2615). --define(wxAuiNotebook_GetPageBitmap, 2616). --define(wxAuiNotebook_GetPageCount, 2617). --define(wxAuiNotebook_GetPageIndex, 2618). --define(wxAuiNotebook_GetPageText, 2619). --define(wxAuiNotebook_GetSelection, 2620). --define(wxAuiNotebook_InsertPage_4, 2621). --define(wxAuiNotebook_InsertPage_5, 2622). --define(wxAuiNotebook_RemovePage, 2623). --define(wxAuiNotebook_SetArtProvider, 2624). --define(wxAuiNotebook_SetFont, 2625). --define(wxAuiNotebook_SetPageBitmap, 2626). --define(wxAuiNotebook_SetPageText, 2627). --define(wxAuiNotebook_SetSelection, 2628). --define(wxAuiNotebook_SetTabCtrlHeight, 2629). --define(wxAuiNotebook_SetUniformBitmapSize, 2630). --define(wxAuiNotebook_destroy, 2631). --define(wxAuiTabArt_SetFlags, 2632). --define(wxAuiTabArt_SetMeasuringFont, 2633). --define(wxAuiTabArt_SetNormalFont, 2634). --define(wxAuiTabArt_SetSelectedFont, 2635). --define(wxAuiTabArt_SetColour, 2636). --define(wxAuiTabArt_SetActiveColour, 2637). --define(wxAuiDockArt_GetColour, 2638). --define(wxAuiDockArt_GetFont, 2639). --define(wxAuiDockArt_GetMetric, 2640). --define(wxAuiDockArt_SetColour, 2641). --define(wxAuiDockArt_SetFont, 2642). --define(wxAuiDockArt_SetMetric, 2643). --define(wxAuiSimpleTabArt_new, 2644). --define(wxAuiSimpleTabArt_destroy, 2645). --define(wxMDIParentFrame_new_0, 2646). --define(wxMDIParentFrame_new_4, 2647). --define(wxMDIParentFrame_destruct, 2648). --define(wxMDIParentFrame_ActivateNext, 2649). --define(wxMDIParentFrame_ActivatePrevious, 2650). --define(wxMDIParentFrame_ArrangeIcons, 2651). --define(wxMDIParentFrame_Cascade, 2652). --define(wxMDIParentFrame_Create, 2653). --define(wxMDIParentFrame_GetActiveChild, 2654). --define(wxMDIParentFrame_GetClientWindow, 2655). --define(wxMDIParentFrame_Tile, 2656). --define(wxMDIChildFrame_new_0, 2657). --define(wxMDIChildFrame_new_4, 2658). --define(wxMDIChildFrame_destruct, 2659). --define(wxMDIChildFrame_Activate, 2660). --define(wxMDIChildFrame_Create, 2661). --define(wxMDIChildFrame_Maximize, 2662). --define(wxMDIChildFrame_Restore, 2663). --define(wxMDIClientWindow_new, 2664). --define(wxMDIClientWindow_CreateClient, 2665). --define(wxMDIClientWindow_destroy, 2666). --define(wxLayoutAlgorithm_new, 2667). --define(wxLayoutAlgorithm_destruct, 2668). --define(wxLayoutAlgorithm_LayoutFrame, 2669). --define(wxLayoutAlgorithm_LayoutMDIFrame, 2670). --define(wxLayoutAlgorithm_LayoutWindow, 2671). --define(wxEvent_GetId, 2672). --define(wxEvent_GetSkipped, 2673). --define(wxEvent_GetTimestamp, 2674). --define(wxEvent_IsCommandEvent, 2675). --define(wxEvent_ResumePropagation, 2676). --define(wxEvent_ShouldPropagate, 2677). --define(wxEvent_Skip, 2678). --define(wxEvent_StopPropagation, 2679). --define(wxCommandEvent_getClientData, 2680). --define(wxCommandEvent_GetExtraLong, 2681). --define(wxCommandEvent_GetInt, 2682). --define(wxCommandEvent_GetSelection, 2683). --define(wxCommandEvent_GetString, 2684). --define(wxCommandEvent_IsChecked, 2685). --define(wxCommandEvent_IsSelection, 2686). --define(wxCommandEvent_SetInt, 2687). --define(wxCommandEvent_SetString, 2688). --define(wxScrollEvent_GetOrientation, 2689). --define(wxScrollEvent_GetPosition, 2690). --define(wxScrollWinEvent_GetOrientation, 2691). --define(wxScrollWinEvent_GetPosition, 2692). --define(wxMouseEvent_AltDown, 2693). --define(wxMouseEvent_Button, 2694). --define(wxMouseEvent_ButtonDClick, 2695). --define(wxMouseEvent_ButtonDown, 2696). --define(wxMouseEvent_ButtonUp, 2697). --define(wxMouseEvent_CmdDown, 2698). --define(wxMouseEvent_ControlDown, 2699). --define(wxMouseEvent_Dragging, 2700). --define(wxMouseEvent_Entering, 2701). --define(wxMouseEvent_GetButton, 2702). --define(wxMouseEvent_GetPosition, 2703). --define(wxMouseEvent_GetLogicalPosition, 2705). --define(wxMouseEvent_GetLinesPerAction, 2706). --define(wxMouseEvent_GetWheelRotation, 2707). --define(wxMouseEvent_GetWheelDelta, 2708). --define(wxMouseEvent_GetX, 2709). --define(wxMouseEvent_GetY, 2710). --define(wxMouseEvent_IsButton, 2711). --define(wxMouseEvent_IsPageScroll, 2712). --define(wxMouseEvent_Leaving, 2713). --define(wxMouseEvent_LeftDClick, 2714). --define(wxMouseEvent_LeftDown, 2715). --define(wxMouseEvent_LeftIsDown, 2716). --define(wxMouseEvent_LeftUp, 2717). --define(wxMouseEvent_MetaDown, 2718). --define(wxMouseEvent_MiddleDClick, 2719). --define(wxMouseEvent_MiddleDown, 2720). --define(wxMouseEvent_MiddleIsDown, 2721). --define(wxMouseEvent_MiddleUp, 2722). --define(wxMouseEvent_Moving, 2723). --define(wxMouseEvent_RightDClick, 2724). --define(wxMouseEvent_RightDown, 2725). --define(wxMouseEvent_RightIsDown, 2726). --define(wxMouseEvent_RightUp, 2727). --define(wxMouseEvent_ShiftDown, 2728). --define(wxMouseEvent_GetWheelAxis, 2729). --define(wxSetCursorEvent_GetCursor, 2730). --define(wxSetCursorEvent_GetX, 2731). --define(wxSetCursorEvent_GetY, 2732). --define(wxSetCursorEvent_HasCursor, 2733). --define(wxSetCursorEvent_SetCursor, 2734). --define(wxKeyEvent_AltDown, 2735). --define(wxKeyEvent_CmdDown, 2736). --define(wxKeyEvent_ControlDown, 2737). --define(wxKeyEvent_GetKeyCode, 2738). --define(wxKeyEvent_GetModifiers, 2739). --define(wxKeyEvent_GetPosition, 2740). --define(wxKeyEvent_GetRawKeyCode, 2742). --define(wxKeyEvent_GetRawKeyFlags, 2743). --define(wxKeyEvent_GetUnicodeKey, 2744). --define(wxKeyEvent_GetX, 2745). --define(wxKeyEvent_GetY, 2746). --define(wxKeyEvent_HasModifiers, 2747). --define(wxKeyEvent_MetaDown, 2748). --define(wxKeyEvent_ShiftDown, 2749). --define(wxSizeEvent_GetSize, 2750). --define(wxSizeEvent_GetRect, 2751). --define(wxMoveEvent_GetPosition, 2752). --define(wxMoveEvent_GetRect, 2753). --define(wxEraseEvent_GetDC, 2754). --define(wxFocusEvent_GetWindow, 2755). --define(wxChildFocusEvent_GetWindow, 2756). --define(wxMenuEvent_GetMenu, 2757). --define(wxMenuEvent_GetMenuId, 2758). --define(wxMenuEvent_IsPopup, 2759). --define(wxCloseEvent_CanVeto, 2760). --define(wxCloseEvent_GetLoggingOff, 2761). --define(wxCloseEvent_SetCanVeto, 2762). --define(wxCloseEvent_SetLoggingOff, 2763). --define(wxCloseEvent_Veto, 2764). --define(wxShowEvent_SetShow, 2765). --define(wxShowEvent_IsShown, 2766). --define(wxIconizeEvent_IsIconized, 2767). --define(wxJoystickEvent_ButtonDown, 2768). --define(wxJoystickEvent_ButtonIsDown, 2769). --define(wxJoystickEvent_ButtonUp, 2770). --define(wxJoystickEvent_GetButtonChange, 2771). --define(wxJoystickEvent_GetButtonState, 2772). --define(wxJoystickEvent_GetJoystick, 2773). --define(wxJoystickEvent_GetPosition, 2774). --define(wxJoystickEvent_GetZPosition, 2775). --define(wxJoystickEvent_IsButton, 2776). --define(wxJoystickEvent_IsMove, 2777). --define(wxJoystickEvent_IsZMove, 2778). --define(wxUpdateUIEvent_CanUpdate, 2779). --define(wxUpdateUIEvent_Check, 2780). --define(wxUpdateUIEvent_Enable, 2781). --define(wxUpdateUIEvent_Show, 2782). --define(wxUpdateUIEvent_GetChecked, 2783). --define(wxUpdateUIEvent_GetEnabled, 2784). --define(wxUpdateUIEvent_GetShown, 2785). --define(wxUpdateUIEvent_GetSetChecked, 2786). --define(wxUpdateUIEvent_GetSetEnabled, 2787). --define(wxUpdateUIEvent_GetSetShown, 2788). --define(wxUpdateUIEvent_GetSetText, 2789). --define(wxUpdateUIEvent_GetText, 2790). --define(wxUpdateUIEvent_GetMode, 2791). --define(wxUpdateUIEvent_GetUpdateInterval, 2792). --define(wxUpdateUIEvent_ResetUpdateTime, 2793). --define(wxUpdateUIEvent_SetMode, 2794). --define(wxUpdateUIEvent_SetText, 2795). --define(wxUpdateUIEvent_SetUpdateInterval, 2796). --define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2797). --define(wxPaletteChangedEvent_SetChangedWindow, 2798). --define(wxPaletteChangedEvent_GetChangedWindow, 2799). --define(wxQueryNewPaletteEvent_SetPaletteRealized, 2800). --define(wxQueryNewPaletteEvent_GetPaletteRealized, 2801). --define(wxNavigationKeyEvent_GetDirection, 2802). --define(wxNavigationKeyEvent_SetDirection, 2803). --define(wxNavigationKeyEvent_IsWindowChange, 2804). --define(wxNavigationKeyEvent_SetWindowChange, 2805). --define(wxNavigationKeyEvent_IsFromTab, 2806). --define(wxNavigationKeyEvent_SetFromTab, 2807). --define(wxNavigationKeyEvent_GetCurrentFocus, 2808). --define(wxNavigationKeyEvent_SetCurrentFocus, 2809). --define(wxHelpEvent_GetOrigin, 2810). --define(wxHelpEvent_GetPosition, 2811). --define(wxHelpEvent_SetOrigin, 2812). --define(wxHelpEvent_SetPosition, 2813). --define(wxContextMenuEvent_GetPosition, 2814). --define(wxContextMenuEvent_SetPosition, 2815). --define(wxIdleEvent_GetMode, 2816). --define(wxIdleEvent_RequestMore, 2817). --define(wxIdleEvent_MoreRequested, 2818). --define(wxIdleEvent_SetMode, 2819). --define(wxGridEvent_AltDown, 2820). --define(wxGridEvent_ControlDown, 2821). --define(wxGridEvent_GetCol, 2822). --define(wxGridEvent_GetPosition, 2823). --define(wxGridEvent_GetRow, 2824). --define(wxGridEvent_MetaDown, 2825). --define(wxGridEvent_Selecting, 2826). --define(wxGridEvent_ShiftDown, 2827). --define(wxNotifyEvent_Allow, 2828). --define(wxNotifyEvent_IsAllowed, 2829). --define(wxNotifyEvent_Veto, 2830). --define(wxSashEvent_GetEdge, 2831). --define(wxSashEvent_GetDragRect, 2832). --define(wxSashEvent_GetDragStatus, 2833). --define(wxListEvent_GetCacheFrom, 2834). --define(wxListEvent_GetCacheTo, 2835). --define(wxListEvent_GetKeyCode, 2836). --define(wxListEvent_GetIndex, 2837). --define(wxListEvent_GetColumn, 2838). --define(wxListEvent_GetPoint, 2839). --define(wxListEvent_GetLabel, 2840). --define(wxListEvent_GetText, 2841). --define(wxListEvent_GetImage, 2842). --define(wxListEvent_GetData, 2843). --define(wxListEvent_GetMask, 2844). --define(wxListEvent_GetItem, 2845). --define(wxListEvent_IsEditCancelled, 2846). --define(wxDateEvent_GetDate, 2847). --define(wxCalendarEvent_GetWeekDay, 2848). --define(wxCalendarEvent_GetDate, 2849). --define(wxFileDirPickerEvent_GetPath, 2850). --define(wxColourPickerEvent_GetColour, 2851). --define(wxFontPickerEvent_GetFont, 2852). --define(wxStyledTextEvent_GetPosition, 2853). --define(wxStyledTextEvent_GetKey, 2854). --define(wxStyledTextEvent_GetModifiers, 2855). --define(wxStyledTextEvent_GetModificationType, 2856). --define(wxStyledTextEvent_GetText, 2857). --define(wxStyledTextEvent_GetLength, 2858). --define(wxStyledTextEvent_GetLinesAdded, 2859). --define(wxStyledTextEvent_GetLine, 2860). --define(wxStyledTextEvent_GetFoldLevelNow, 2861). --define(wxStyledTextEvent_GetFoldLevelPrev, 2862). --define(wxStyledTextEvent_GetMargin, 2863). --define(wxStyledTextEvent_GetMessage, 2864). --define(wxStyledTextEvent_GetWParam, 2865). --define(wxStyledTextEvent_GetLParam, 2866). --define(wxStyledTextEvent_GetListType, 2867). --define(wxStyledTextEvent_GetX, 2868). --define(wxStyledTextEvent_GetY, 2869). --define(wxStyledTextEvent_GetDragText, 2870). --define(wxStyledTextEvent_GetDragAllowMove, 2871). --define(wxStyledTextEvent_GetDragResult, 2872). --define(wxStyledTextEvent_GetShift, 2873). --define(wxStyledTextEvent_GetControl, 2874). --define(wxStyledTextEvent_GetAlt, 2875). --define(utils_wxGetKeyState, 2876). --define(utils_wxGetMousePosition, 2877). --define(utils_wxGetMouseState, 2878). --define(utils_wxSetDetectableAutoRepeat, 2879). --define(utils_wxBell, 2880). --define(utils_wxFindMenuItemId, 2881). --define(utils_wxFindWindowAtPoint, 2882). --define(utils_wxBeginBusyCursor, 2883). --define(utils_wxEndBusyCursor, 2884). --define(utils_wxIsBusy, 2885). --define(utils_wxShutdown, 2886). --define(utils_wxShell, 2887). --define(utils_wxLaunchDefaultBrowser, 2888). --define(utils_wxGetEmailAddress, 2889). --define(utils_wxGetUserId, 2890). --define(utils_wxGetHomeDir, 2891). --define(utils_wxNewId, 2892). --define(utils_wxRegisterId, 2893). --define(utils_wxGetCurrentId, 2894). --define(utils_wxGetOsDescription, 2895). --define(utils_wxIsPlatformLittleEndian, 2896). --define(utils_wxIsPlatform64Bit, 2897). --define(gdicmn_wxDisplaySize, 2898). --define(gdicmn_wxSetCursor, 2899). --define(wxPrintout_new, 2900). --define(wxPrintout_destruct, 2901). --define(wxPrintout_GetDC, 2902). --define(wxPrintout_GetPageSizeMM, 2903). --define(wxPrintout_GetPageSizePixels, 2904). --define(wxPrintout_GetPaperRectPixels, 2905). --define(wxPrintout_GetPPIPrinter, 2906). --define(wxPrintout_GetPPIScreen, 2907). --define(wxPrintout_GetTitle, 2908). --define(wxPrintout_IsPreview, 2909). --define(wxPrintout_FitThisSizeToPaper, 2910). --define(wxPrintout_FitThisSizeToPage, 2911). --define(wxPrintout_FitThisSizeToPageMargins, 2912). --define(wxPrintout_MapScreenSizeToPaper, 2913). --define(wxPrintout_MapScreenSizeToPage, 2914). --define(wxPrintout_MapScreenSizeToPageMargins, 2915). --define(wxPrintout_MapScreenSizeToDevice, 2916). --define(wxPrintout_GetLogicalPaperRect, 2917). --define(wxPrintout_GetLogicalPageRect, 2918). --define(wxPrintout_GetLogicalPageMarginsRect, 2919). --define(wxPrintout_SetLogicalOrigin, 2920). --define(wxPrintout_OffsetLogicalOrigin, 2921). --define(wxStyledTextCtrl_new_2, 2922). --define(wxStyledTextCtrl_new_0, 2923). --define(wxStyledTextCtrl_destruct, 2924). --define(wxStyledTextCtrl_Create, 2925). --define(wxStyledTextCtrl_AddText, 2926). --define(wxStyledTextCtrl_InsertText, 2927). --define(wxStyledTextCtrl_ClearAll, 2928). --define(wxStyledTextCtrl_ClearDocumentStyle, 2929). --define(wxStyledTextCtrl_GetLength, 2930). --define(wxStyledTextCtrl_GetCharAt, 2931). --define(wxStyledTextCtrl_GetCurrentPos, 2932). --define(wxStyledTextCtrl_GetAnchor, 2933). --define(wxStyledTextCtrl_GetStyleAt, 2934). --define(wxStyledTextCtrl_Redo, 2935). --define(wxStyledTextCtrl_SetUndoCollection, 2936). --define(wxStyledTextCtrl_SelectAll, 2937). --define(wxStyledTextCtrl_SetSavePoint, 2938). --define(wxStyledTextCtrl_CanRedo, 2939). --define(wxStyledTextCtrl_MarkerLineFromHandle, 2940). --define(wxStyledTextCtrl_MarkerDeleteHandle, 2941). --define(wxStyledTextCtrl_GetUndoCollection, 2942). --define(wxStyledTextCtrl_GetViewWhiteSpace, 2943). --define(wxStyledTextCtrl_SetViewWhiteSpace, 2944). --define(wxStyledTextCtrl_PositionFromPoint, 2945). --define(wxStyledTextCtrl_PositionFromPointClose, 2946). --define(wxStyledTextCtrl_GotoLine, 2947). --define(wxStyledTextCtrl_GotoPos, 2948). --define(wxStyledTextCtrl_SetAnchor, 2949). --define(wxStyledTextCtrl_GetCurLine, 2950). --define(wxStyledTextCtrl_GetEndStyled, 2951). --define(wxStyledTextCtrl_ConvertEOLs, 2952). --define(wxStyledTextCtrl_GetEOLMode, 2953). --define(wxStyledTextCtrl_SetEOLMode, 2954). --define(wxStyledTextCtrl_StartStyling, 2955). --define(wxStyledTextCtrl_SetStyling, 2956). --define(wxStyledTextCtrl_GetBufferedDraw, 2957). --define(wxStyledTextCtrl_SetBufferedDraw, 2958). --define(wxStyledTextCtrl_SetTabWidth, 2959). --define(wxStyledTextCtrl_GetTabWidth, 2960). --define(wxStyledTextCtrl_SetCodePage, 2961). --define(wxStyledTextCtrl_MarkerDefine, 2962). --define(wxStyledTextCtrl_MarkerSetForeground, 2963). --define(wxStyledTextCtrl_MarkerSetBackground, 2964). --define(wxStyledTextCtrl_MarkerAdd, 2965). --define(wxStyledTextCtrl_MarkerDelete, 2966). --define(wxStyledTextCtrl_MarkerDeleteAll, 2967). --define(wxStyledTextCtrl_MarkerGet, 2968). --define(wxStyledTextCtrl_MarkerNext, 2969). --define(wxStyledTextCtrl_MarkerPrevious, 2970). --define(wxStyledTextCtrl_MarkerDefineBitmap, 2971). --define(wxStyledTextCtrl_MarkerAddSet, 2972). --define(wxStyledTextCtrl_MarkerSetAlpha, 2973). --define(wxStyledTextCtrl_SetMarginType, 2974). --define(wxStyledTextCtrl_GetMarginType, 2975). --define(wxStyledTextCtrl_SetMarginWidth, 2976). --define(wxStyledTextCtrl_GetMarginWidth, 2977). --define(wxStyledTextCtrl_SetMarginMask, 2978). --define(wxStyledTextCtrl_GetMarginMask, 2979). --define(wxStyledTextCtrl_SetMarginSensitive, 2980). --define(wxStyledTextCtrl_GetMarginSensitive, 2981). --define(wxStyledTextCtrl_StyleClearAll, 2982). --define(wxStyledTextCtrl_StyleSetForeground, 2983). --define(wxStyledTextCtrl_StyleSetBackground, 2984). --define(wxStyledTextCtrl_StyleSetBold, 2985). --define(wxStyledTextCtrl_StyleSetItalic, 2986). --define(wxStyledTextCtrl_StyleSetSize, 2987). --define(wxStyledTextCtrl_StyleSetFaceName, 2988). --define(wxStyledTextCtrl_StyleSetEOLFilled, 2989). --define(wxStyledTextCtrl_StyleResetDefault, 2990). --define(wxStyledTextCtrl_StyleSetUnderline, 2991). --define(wxStyledTextCtrl_StyleSetCase, 2992). --define(wxStyledTextCtrl_StyleSetHotSpot, 2993). --define(wxStyledTextCtrl_SetSelForeground, 2994). --define(wxStyledTextCtrl_SetSelBackground, 2995). --define(wxStyledTextCtrl_GetSelAlpha, 2996). --define(wxStyledTextCtrl_SetSelAlpha, 2997). --define(wxStyledTextCtrl_SetCaretForeground, 2998). --define(wxStyledTextCtrl_CmdKeyAssign, 2999). --define(wxStyledTextCtrl_CmdKeyClear, 3000). --define(wxStyledTextCtrl_CmdKeyClearAll, 3001). --define(wxStyledTextCtrl_SetStyleBytes, 3002). --define(wxStyledTextCtrl_StyleSetVisible, 3003). --define(wxStyledTextCtrl_GetCaretPeriod, 3004). --define(wxStyledTextCtrl_SetCaretPeriod, 3005). --define(wxStyledTextCtrl_SetWordChars, 3006). --define(wxStyledTextCtrl_BeginUndoAction, 3007). --define(wxStyledTextCtrl_EndUndoAction, 3008). --define(wxStyledTextCtrl_IndicatorSetStyle, 3009). --define(wxStyledTextCtrl_IndicatorGetStyle, 3010). --define(wxStyledTextCtrl_IndicatorSetForeground, 3011). --define(wxStyledTextCtrl_IndicatorGetForeground, 3012). --define(wxStyledTextCtrl_SetWhitespaceForeground, 3013). --define(wxStyledTextCtrl_SetWhitespaceBackground, 3014). --define(wxStyledTextCtrl_GetStyleBits, 3015). --define(wxStyledTextCtrl_SetLineState, 3016). --define(wxStyledTextCtrl_GetLineState, 3017). --define(wxStyledTextCtrl_GetMaxLineState, 3018). --define(wxStyledTextCtrl_GetCaretLineVisible, 3019). --define(wxStyledTextCtrl_SetCaretLineVisible, 3020). --define(wxStyledTextCtrl_GetCaretLineBackground, 3021). --define(wxStyledTextCtrl_SetCaretLineBackground, 3022). --define(wxStyledTextCtrl_AutoCompShow, 3023). --define(wxStyledTextCtrl_AutoCompCancel, 3024). --define(wxStyledTextCtrl_AutoCompActive, 3025). --define(wxStyledTextCtrl_AutoCompPosStart, 3026). --define(wxStyledTextCtrl_AutoCompComplete, 3027). --define(wxStyledTextCtrl_AutoCompStops, 3028). --define(wxStyledTextCtrl_AutoCompSetSeparator, 3029). --define(wxStyledTextCtrl_AutoCompGetSeparator, 3030). --define(wxStyledTextCtrl_AutoCompSelect, 3031). --define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3032). --define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3033). --define(wxStyledTextCtrl_AutoCompSetFillUps, 3034). --define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3035). --define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3036). --define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3037). --define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3038). --define(wxStyledTextCtrl_UserListShow, 3039). --define(wxStyledTextCtrl_AutoCompSetAutoHide, 3040). --define(wxStyledTextCtrl_AutoCompGetAutoHide, 3041). --define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3042). --define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3043). --define(wxStyledTextCtrl_RegisterImage, 3044). --define(wxStyledTextCtrl_ClearRegisteredImages, 3045). --define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3046). --define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3047). --define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3048). --define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3049). --define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3050). --define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3051). --define(wxStyledTextCtrl_SetIndent, 3052). --define(wxStyledTextCtrl_GetIndent, 3053). --define(wxStyledTextCtrl_SetUseTabs, 3054). --define(wxStyledTextCtrl_GetUseTabs, 3055). --define(wxStyledTextCtrl_SetLineIndentation, 3056). --define(wxStyledTextCtrl_GetLineIndentation, 3057). --define(wxStyledTextCtrl_GetLineIndentPosition, 3058). --define(wxStyledTextCtrl_GetColumn, 3059). --define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3060). --define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3061). --define(wxStyledTextCtrl_SetIndentationGuides, 3062). --define(wxStyledTextCtrl_GetIndentationGuides, 3063). --define(wxStyledTextCtrl_SetHighlightGuide, 3064). --define(wxStyledTextCtrl_GetHighlightGuide, 3065). --define(wxStyledTextCtrl_GetLineEndPosition, 3066). --define(wxStyledTextCtrl_GetCodePage, 3067). --define(wxStyledTextCtrl_GetCaretForeground, 3068). --define(wxStyledTextCtrl_GetReadOnly, 3069). --define(wxStyledTextCtrl_SetCurrentPos, 3070). --define(wxStyledTextCtrl_SetSelectionStart, 3071). --define(wxStyledTextCtrl_GetSelectionStart, 3072). --define(wxStyledTextCtrl_SetSelectionEnd, 3073). --define(wxStyledTextCtrl_GetSelectionEnd, 3074). --define(wxStyledTextCtrl_SetPrintMagnification, 3075). --define(wxStyledTextCtrl_GetPrintMagnification, 3076). --define(wxStyledTextCtrl_SetPrintColourMode, 3077). --define(wxStyledTextCtrl_GetPrintColourMode, 3078). --define(wxStyledTextCtrl_FindText, 3079). --define(wxStyledTextCtrl_FormatRange, 3080). --define(wxStyledTextCtrl_GetFirstVisibleLine, 3081). --define(wxStyledTextCtrl_GetLine, 3082). --define(wxStyledTextCtrl_GetLineCount, 3083). --define(wxStyledTextCtrl_SetMarginLeft, 3084). --define(wxStyledTextCtrl_GetMarginLeft, 3085). --define(wxStyledTextCtrl_SetMarginRight, 3086). --define(wxStyledTextCtrl_GetMarginRight, 3087). --define(wxStyledTextCtrl_GetModify, 3088). --define(wxStyledTextCtrl_SetSelection, 3089). --define(wxStyledTextCtrl_GetSelectedText, 3090). --define(wxStyledTextCtrl_GetTextRange, 3091). --define(wxStyledTextCtrl_HideSelection, 3092). --define(wxStyledTextCtrl_LineFromPosition, 3093). --define(wxStyledTextCtrl_PositionFromLine, 3094). --define(wxStyledTextCtrl_LineScroll, 3095). --define(wxStyledTextCtrl_EnsureCaretVisible, 3096). --define(wxStyledTextCtrl_ReplaceSelection, 3097). --define(wxStyledTextCtrl_SetReadOnly, 3098). --define(wxStyledTextCtrl_CanPaste, 3099). --define(wxStyledTextCtrl_CanUndo, 3100). --define(wxStyledTextCtrl_EmptyUndoBuffer, 3101). --define(wxStyledTextCtrl_Undo, 3102). --define(wxStyledTextCtrl_Cut, 3103). --define(wxStyledTextCtrl_Copy, 3104). --define(wxStyledTextCtrl_Paste, 3105). --define(wxStyledTextCtrl_Clear, 3106). --define(wxStyledTextCtrl_SetText, 3107). --define(wxStyledTextCtrl_GetText, 3108). --define(wxStyledTextCtrl_GetTextLength, 3109). --define(wxStyledTextCtrl_GetOvertype, 3110). --define(wxStyledTextCtrl_SetCaretWidth, 3111). --define(wxStyledTextCtrl_GetCaretWidth, 3112). --define(wxStyledTextCtrl_SetTargetStart, 3113). --define(wxStyledTextCtrl_GetTargetStart, 3114). --define(wxStyledTextCtrl_SetTargetEnd, 3115). --define(wxStyledTextCtrl_GetTargetEnd, 3116). --define(wxStyledTextCtrl_ReplaceTarget, 3117). --define(wxStyledTextCtrl_SearchInTarget, 3118). --define(wxStyledTextCtrl_SetSearchFlags, 3119). --define(wxStyledTextCtrl_GetSearchFlags, 3120). --define(wxStyledTextCtrl_CallTipShow, 3121). --define(wxStyledTextCtrl_CallTipCancel, 3122). --define(wxStyledTextCtrl_CallTipActive, 3123). --define(wxStyledTextCtrl_CallTipPosAtStart, 3124). --define(wxStyledTextCtrl_CallTipSetHighlight, 3125). --define(wxStyledTextCtrl_CallTipSetBackground, 3126). --define(wxStyledTextCtrl_CallTipSetForeground, 3127). --define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3128). --define(wxStyledTextCtrl_CallTipUseStyle, 3129). --define(wxStyledTextCtrl_VisibleFromDocLine, 3130). --define(wxStyledTextCtrl_DocLineFromVisible, 3131). --define(wxStyledTextCtrl_WrapCount, 3132). --define(wxStyledTextCtrl_SetFoldLevel, 3133). --define(wxStyledTextCtrl_GetFoldLevel, 3134). --define(wxStyledTextCtrl_GetLastChild, 3135). --define(wxStyledTextCtrl_GetFoldParent, 3136). --define(wxStyledTextCtrl_ShowLines, 3137). --define(wxStyledTextCtrl_HideLines, 3138). --define(wxStyledTextCtrl_GetLineVisible, 3139). --define(wxStyledTextCtrl_SetFoldExpanded, 3140). --define(wxStyledTextCtrl_GetFoldExpanded, 3141). --define(wxStyledTextCtrl_ToggleFold, 3142). --define(wxStyledTextCtrl_EnsureVisible, 3143). --define(wxStyledTextCtrl_SetFoldFlags, 3144). --define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3145). --define(wxStyledTextCtrl_SetTabIndents, 3146). --define(wxStyledTextCtrl_GetTabIndents, 3147). --define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3148). --define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3149). --define(wxStyledTextCtrl_SetMouseDwellTime, 3150). --define(wxStyledTextCtrl_GetMouseDwellTime, 3151). --define(wxStyledTextCtrl_WordStartPosition, 3152). --define(wxStyledTextCtrl_WordEndPosition, 3153). --define(wxStyledTextCtrl_SetWrapMode, 3154). --define(wxStyledTextCtrl_GetWrapMode, 3155). --define(wxStyledTextCtrl_SetWrapVisualFlags, 3156). --define(wxStyledTextCtrl_GetWrapVisualFlags, 3157). --define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3158). --define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3159). --define(wxStyledTextCtrl_SetWrapStartIndent, 3160). --define(wxStyledTextCtrl_GetWrapStartIndent, 3161). --define(wxStyledTextCtrl_SetLayoutCache, 3162). --define(wxStyledTextCtrl_GetLayoutCache, 3163). --define(wxStyledTextCtrl_SetScrollWidth, 3164). --define(wxStyledTextCtrl_GetScrollWidth, 3165). --define(wxStyledTextCtrl_TextWidth, 3166). --define(wxStyledTextCtrl_GetEndAtLastLine, 3167). --define(wxStyledTextCtrl_TextHeight, 3168). --define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3169). --define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3170). --define(wxStyledTextCtrl_AppendText, 3171). --define(wxStyledTextCtrl_GetTwoPhaseDraw, 3172). --define(wxStyledTextCtrl_SetTwoPhaseDraw, 3173). --define(wxStyledTextCtrl_TargetFromSelection, 3174). --define(wxStyledTextCtrl_LinesJoin, 3175). --define(wxStyledTextCtrl_LinesSplit, 3176). --define(wxStyledTextCtrl_SetFoldMarginColour, 3177). --define(wxStyledTextCtrl_SetFoldMarginHiColour, 3178). --define(wxStyledTextCtrl_LineDown, 3179). --define(wxStyledTextCtrl_LineDownExtend, 3180). --define(wxStyledTextCtrl_LineUp, 3181). --define(wxStyledTextCtrl_LineUpExtend, 3182). --define(wxStyledTextCtrl_CharLeft, 3183). --define(wxStyledTextCtrl_CharLeftExtend, 3184). --define(wxStyledTextCtrl_CharRight, 3185). --define(wxStyledTextCtrl_CharRightExtend, 3186). --define(wxStyledTextCtrl_WordLeft, 3187). --define(wxStyledTextCtrl_WordLeftExtend, 3188). --define(wxStyledTextCtrl_WordRight, 3189). --define(wxStyledTextCtrl_WordRightExtend, 3190). --define(wxStyledTextCtrl_Home, 3191). --define(wxStyledTextCtrl_HomeExtend, 3192). --define(wxStyledTextCtrl_LineEnd, 3193). --define(wxStyledTextCtrl_LineEndExtend, 3194). --define(wxStyledTextCtrl_DocumentStart, 3195). --define(wxStyledTextCtrl_DocumentStartExtend, 3196). --define(wxStyledTextCtrl_DocumentEnd, 3197). --define(wxStyledTextCtrl_DocumentEndExtend, 3198). --define(wxStyledTextCtrl_PageUp, 3199). --define(wxStyledTextCtrl_PageUpExtend, 3200). --define(wxStyledTextCtrl_PageDown, 3201). --define(wxStyledTextCtrl_PageDownExtend, 3202). --define(wxStyledTextCtrl_EditToggleOvertype, 3203). --define(wxStyledTextCtrl_Cancel, 3204). --define(wxStyledTextCtrl_DeleteBack, 3205). --define(wxStyledTextCtrl_Tab, 3206). --define(wxStyledTextCtrl_BackTab, 3207). --define(wxStyledTextCtrl_NewLine, 3208). --define(wxStyledTextCtrl_FormFeed, 3209). --define(wxStyledTextCtrl_VCHome, 3210). --define(wxStyledTextCtrl_VCHomeExtend, 3211). --define(wxStyledTextCtrl_ZoomIn, 3212). --define(wxStyledTextCtrl_ZoomOut, 3213). --define(wxStyledTextCtrl_DelWordLeft, 3214). --define(wxStyledTextCtrl_DelWordRight, 3215). --define(wxStyledTextCtrl_LineCut, 3216). --define(wxStyledTextCtrl_LineDelete, 3217). --define(wxStyledTextCtrl_LineTranspose, 3218). --define(wxStyledTextCtrl_LineDuplicate, 3219). --define(wxStyledTextCtrl_LowerCase, 3220). --define(wxStyledTextCtrl_UpperCase, 3221). --define(wxStyledTextCtrl_LineScrollDown, 3222). --define(wxStyledTextCtrl_LineScrollUp, 3223). --define(wxStyledTextCtrl_DeleteBackNotLine, 3224). --define(wxStyledTextCtrl_HomeDisplay, 3225). --define(wxStyledTextCtrl_HomeDisplayExtend, 3226). --define(wxStyledTextCtrl_LineEndDisplay, 3227). --define(wxStyledTextCtrl_LineEndDisplayExtend, 3228). --define(wxStyledTextCtrl_HomeWrapExtend, 3229). --define(wxStyledTextCtrl_LineEndWrap, 3230). --define(wxStyledTextCtrl_LineEndWrapExtend, 3231). --define(wxStyledTextCtrl_VCHomeWrap, 3232). --define(wxStyledTextCtrl_VCHomeWrapExtend, 3233). --define(wxStyledTextCtrl_LineCopy, 3234). --define(wxStyledTextCtrl_MoveCaretInsideView, 3235). --define(wxStyledTextCtrl_LineLength, 3236). --define(wxStyledTextCtrl_BraceHighlight, 3237). --define(wxStyledTextCtrl_BraceBadLight, 3238). --define(wxStyledTextCtrl_BraceMatch, 3239). --define(wxStyledTextCtrl_GetViewEOL, 3240). --define(wxStyledTextCtrl_SetViewEOL, 3241). --define(wxStyledTextCtrl_SetModEventMask, 3242). --define(wxStyledTextCtrl_GetEdgeColumn, 3243). --define(wxStyledTextCtrl_SetEdgeColumn, 3244). --define(wxStyledTextCtrl_SetEdgeMode, 3245). --define(wxStyledTextCtrl_GetEdgeMode, 3246). --define(wxStyledTextCtrl_GetEdgeColour, 3247). --define(wxStyledTextCtrl_SetEdgeColour, 3248). --define(wxStyledTextCtrl_SearchAnchor, 3249). --define(wxStyledTextCtrl_SearchNext, 3250). --define(wxStyledTextCtrl_SearchPrev, 3251). --define(wxStyledTextCtrl_LinesOnScreen, 3252). --define(wxStyledTextCtrl_UsePopUp, 3253). --define(wxStyledTextCtrl_SelectionIsRectangle, 3254). --define(wxStyledTextCtrl_SetZoom, 3255). --define(wxStyledTextCtrl_GetZoom, 3256). --define(wxStyledTextCtrl_GetModEventMask, 3257). --define(wxStyledTextCtrl_SetSTCFocus, 3258). --define(wxStyledTextCtrl_GetSTCFocus, 3259). --define(wxStyledTextCtrl_SetStatus, 3260). --define(wxStyledTextCtrl_GetStatus, 3261). --define(wxStyledTextCtrl_SetMouseDownCaptures, 3262). --define(wxStyledTextCtrl_GetMouseDownCaptures, 3263). --define(wxStyledTextCtrl_SetSTCCursor, 3264). --define(wxStyledTextCtrl_GetSTCCursor, 3265). --define(wxStyledTextCtrl_SetControlCharSymbol, 3266). --define(wxStyledTextCtrl_GetControlCharSymbol, 3267). --define(wxStyledTextCtrl_WordPartLeft, 3268). --define(wxStyledTextCtrl_WordPartLeftExtend, 3269). --define(wxStyledTextCtrl_WordPartRight, 3270). --define(wxStyledTextCtrl_WordPartRightExtend, 3271). --define(wxStyledTextCtrl_SetVisiblePolicy, 3272). --define(wxStyledTextCtrl_DelLineLeft, 3273). --define(wxStyledTextCtrl_DelLineRight, 3274). --define(wxStyledTextCtrl_GetXOffset, 3275). --define(wxStyledTextCtrl_ChooseCaretX, 3276). --define(wxStyledTextCtrl_SetXCaretPolicy, 3277). --define(wxStyledTextCtrl_SetYCaretPolicy, 3278). --define(wxStyledTextCtrl_GetPrintWrapMode, 3279). --define(wxStyledTextCtrl_SetHotspotActiveForeground, 3280). --define(wxStyledTextCtrl_SetHotspotActiveBackground, 3281). --define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3282). --define(wxStyledTextCtrl_SetHotspotSingleLine, 3283). --define(wxStyledTextCtrl_ParaDownExtend, 3284). --define(wxStyledTextCtrl_ParaUp, 3285). --define(wxStyledTextCtrl_ParaUpExtend, 3286). --define(wxStyledTextCtrl_PositionBefore, 3287). --define(wxStyledTextCtrl_PositionAfter, 3288). --define(wxStyledTextCtrl_CopyRange, 3289). --define(wxStyledTextCtrl_CopyText, 3290). --define(wxStyledTextCtrl_SetSelectionMode, 3291). --define(wxStyledTextCtrl_GetSelectionMode, 3292). --define(wxStyledTextCtrl_LineDownRectExtend, 3293). --define(wxStyledTextCtrl_LineUpRectExtend, 3294). --define(wxStyledTextCtrl_CharLeftRectExtend, 3295). --define(wxStyledTextCtrl_CharRightRectExtend, 3296). --define(wxStyledTextCtrl_HomeRectExtend, 3297). --define(wxStyledTextCtrl_VCHomeRectExtend, 3298). --define(wxStyledTextCtrl_LineEndRectExtend, 3299). --define(wxStyledTextCtrl_PageUpRectExtend, 3300). --define(wxStyledTextCtrl_PageDownRectExtend, 3301). --define(wxStyledTextCtrl_StutteredPageUp, 3302). --define(wxStyledTextCtrl_StutteredPageUpExtend, 3303). --define(wxStyledTextCtrl_StutteredPageDown, 3304). --define(wxStyledTextCtrl_StutteredPageDownExtend, 3305). --define(wxStyledTextCtrl_WordLeftEnd, 3306). --define(wxStyledTextCtrl_WordLeftEndExtend, 3307). --define(wxStyledTextCtrl_WordRightEnd, 3308). --define(wxStyledTextCtrl_WordRightEndExtend, 3309). --define(wxStyledTextCtrl_SetWhitespaceChars, 3310). --define(wxStyledTextCtrl_SetCharsDefault, 3311). --define(wxStyledTextCtrl_AutoCompGetCurrent, 3312). --define(wxStyledTextCtrl_Allocate, 3313). --define(wxStyledTextCtrl_FindColumn, 3314). --define(wxStyledTextCtrl_GetCaretSticky, 3315). --define(wxStyledTextCtrl_SetCaretSticky, 3316). --define(wxStyledTextCtrl_ToggleCaretSticky, 3317). --define(wxStyledTextCtrl_SetPasteConvertEndings, 3318). --define(wxStyledTextCtrl_GetPasteConvertEndings, 3319). --define(wxStyledTextCtrl_SelectionDuplicate, 3320). --define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3321). --define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3322). --define(wxStyledTextCtrl_StartRecord, 3323). --define(wxStyledTextCtrl_StopRecord, 3324). --define(wxStyledTextCtrl_SetLexer, 3325). --define(wxStyledTextCtrl_GetLexer, 3326). --define(wxStyledTextCtrl_Colourise, 3327). --define(wxStyledTextCtrl_SetProperty, 3328). --define(wxStyledTextCtrl_SetKeyWords, 3329). --define(wxStyledTextCtrl_SetLexerLanguage, 3330). --define(wxStyledTextCtrl_GetProperty, 3331). --define(wxStyledTextCtrl_GetStyleBitsNeeded, 3332). --define(wxStyledTextCtrl_GetCurrentLine, 3333). --define(wxStyledTextCtrl_StyleSetSpec, 3334). --define(wxStyledTextCtrl_StyleSetFont, 3335). --define(wxStyledTextCtrl_StyleSetFontAttr, 3336). --define(wxStyledTextCtrl_StyleSetCharacterSet, 3337). --define(wxStyledTextCtrl_StyleSetFontEncoding, 3338). --define(wxStyledTextCtrl_CmdKeyExecute, 3339). --define(wxStyledTextCtrl_SetMargins, 3340). --define(wxStyledTextCtrl_GetSelection, 3341). --define(wxStyledTextCtrl_PointFromPosition, 3342). --define(wxStyledTextCtrl_ScrollToLine, 3343). --define(wxStyledTextCtrl_ScrollToColumn, 3344). --define(wxStyledTextCtrl_SetVScrollBar, 3345). --define(wxStyledTextCtrl_SetHScrollBar, 3346). --define(wxStyledTextCtrl_GetLastKeydownProcessed, 3347). --define(wxStyledTextCtrl_SetLastKeydownProcessed, 3348). --define(wxStyledTextCtrl_SaveFile, 3349). --define(wxStyledTextCtrl_LoadFile, 3350). --define(wxStyledTextCtrl_DoDragOver, 3351). --define(wxStyledTextCtrl_DoDropText, 3352). --define(wxStyledTextCtrl_GetUseAntiAliasing, 3353). --define(wxStyledTextCtrl_AddTextRaw, 3354). --define(wxStyledTextCtrl_InsertTextRaw, 3355). --define(wxStyledTextCtrl_GetCurLineRaw, 3356). --define(wxStyledTextCtrl_GetLineRaw, 3357). --define(wxStyledTextCtrl_GetSelectedTextRaw, 3358). --define(wxStyledTextCtrl_GetTextRangeRaw, 3359). --define(wxStyledTextCtrl_SetTextRaw, 3360). --define(wxStyledTextCtrl_GetTextRaw, 3361). --define(wxStyledTextCtrl_AppendTextRaw, 3362). --define(wxArtProvider_GetBitmap, 3363). --define(wxArtProvider_GetIcon, 3364). --define(wxTreeEvent_GetKeyCode, 3365). --define(wxTreeEvent_GetItem, 3366). --define(wxTreeEvent_GetKeyEvent, 3367). --define(wxTreeEvent_GetLabel, 3368). --define(wxTreeEvent_GetOldItem, 3369). --define(wxTreeEvent_GetPoint, 3370). --define(wxTreeEvent_IsEditCancelled, 3371). --define(wxTreeEvent_SetToolTip, 3372). --define(wxBookCtrlEvent_GetOldSelection, 3373). --define(wxBookCtrlEvent_GetSelection, 3374). --define(wxBookCtrlEvent_SetOldSelection, 3375). --define(wxBookCtrlEvent_SetSelection, 3376). --define(wxFileDataObject_new, 3377). --define(wxFileDataObject_AddFile, 3378). --define(wxFileDataObject_GetFilenames, 3379). --define(wxFileDataObject_destroy, 3380). --define(wxTextDataObject_new, 3381). --define(wxTextDataObject_GetTextLength, 3382). --define(wxTextDataObject_GetText, 3383). --define(wxTextDataObject_SetText, 3384). --define(wxTextDataObject_destroy, 3385). --define(wxBitmapDataObject_new_1_1, 3386). --define(wxBitmapDataObject_new_1_0, 3387). --define(wxBitmapDataObject_GetBitmap, 3388). --define(wxBitmapDataObject_SetBitmap, 3389). --define(wxBitmapDataObject_destroy, 3390). --define(wxClipboard_new, 3391). --define(wxClipboard_destruct, 3392). --define(wxClipboard_AddData, 3393). --define(wxClipboard_Clear, 3394). --define(wxClipboard_Close, 3395). --define(wxClipboard_Flush, 3396). --define(wxClipboard_GetData, 3397). --define(wxClipboard_IsOpened, 3398). --define(wxClipboard_Open, 3399). --define(wxClipboard_SetData, 3400). --define(wxClipboard_UsePrimarySelection, 3401). --define(wxClipboard_IsSupported, 3402). --define(wxClipboard_Get, 3403). --define(wxSpinEvent_GetPosition, 3404). --define(wxSpinEvent_SetPosition, 3405). --define(wxSplitterWindow_new_0, 3406). --define(wxSplitterWindow_new_2, 3407). --define(wxSplitterWindow_destruct, 3408). --define(wxSplitterWindow_Create, 3409). --define(wxSplitterWindow_GetMinimumPaneSize, 3410). --define(wxSplitterWindow_GetSashGravity, 3411). --define(wxSplitterWindow_GetSashPosition, 3412). --define(wxSplitterWindow_GetSplitMode, 3413). --define(wxSplitterWindow_GetWindow1, 3414). --define(wxSplitterWindow_GetWindow2, 3415). --define(wxSplitterWindow_Initialize, 3416). --define(wxSplitterWindow_IsSplit, 3417). --define(wxSplitterWindow_ReplaceWindow, 3418). --define(wxSplitterWindow_SetSashGravity, 3419). --define(wxSplitterWindow_SetSashPosition, 3420). --define(wxSplitterWindow_SetMinimumPaneSize, 3421). --define(wxSplitterWindow_SetSplitMode, 3422). --define(wxSplitterWindow_SplitHorizontally, 3423). --define(wxSplitterWindow_SplitVertically, 3424). --define(wxSplitterWindow_Unsplit, 3425). --define(wxSplitterWindow_UpdateSize, 3426). --define(wxSplitterEvent_GetSashPosition, 3427). --define(wxSplitterEvent_GetX, 3428). --define(wxSplitterEvent_GetY, 3429). --define(wxSplitterEvent_GetWindowBeingRemoved, 3430). --define(wxSplitterEvent_SetSashPosition, 3431). --define(wxHtmlWindow_new_0, 3432). --define(wxHtmlWindow_new_2, 3433). --define(wxHtmlWindow_AppendToPage, 3434). --define(wxHtmlWindow_GetOpenedAnchor, 3435). --define(wxHtmlWindow_GetOpenedPage, 3436). --define(wxHtmlWindow_GetOpenedPageTitle, 3437). --define(wxHtmlWindow_GetRelatedFrame, 3438). --define(wxHtmlWindow_HistoryBack, 3439). --define(wxHtmlWindow_HistoryCanBack, 3440). --define(wxHtmlWindow_HistoryCanForward, 3441). --define(wxHtmlWindow_HistoryClear, 3442). --define(wxHtmlWindow_HistoryForward, 3443). --define(wxHtmlWindow_LoadFile, 3444). --define(wxHtmlWindow_LoadPage, 3445). --define(wxHtmlWindow_SelectAll, 3446). --define(wxHtmlWindow_SelectionToText, 3447). --define(wxHtmlWindow_SelectLine, 3448). --define(wxHtmlWindow_SelectWord, 3449). --define(wxHtmlWindow_SetBorders, 3450). --define(wxHtmlWindow_SetFonts, 3451). --define(wxHtmlWindow_SetPage, 3452). --define(wxHtmlWindow_SetRelatedFrame, 3453). --define(wxHtmlWindow_SetRelatedStatusBar_1, 3454). --define(wxHtmlWindow_SetRelatedStatusBar_2, 3455). --define(wxHtmlWindow_ToText, 3456). --define(wxHtmlWindow_destroy, 3457). --define(wxHtmlLinkEvent_GetLinkInfo, 3458). --define(wxSystemSettings_GetColour, 3459). --define(wxSystemSettings_GetFont, 3460). --define(wxSystemSettings_GetMetric, 3461). --define(wxSystemSettings_GetScreenType, 3462). --define(wxSystemOptions_GetOption, 3463). --define(wxSystemOptions_GetOptionInt, 3464). --define(wxSystemOptions_HasOption, 3465). --define(wxSystemOptions_IsFalse, 3466). --define(wxSystemOptions_SetOption_2_1, 3467). --define(wxSystemOptions_SetOption_2_0, 3468). --define(wxAuiNotebookEvent_SetSelection, 3469). --define(wxAuiNotebookEvent_GetSelection, 3470). --define(wxAuiNotebookEvent_SetOldSelection, 3471). --define(wxAuiNotebookEvent_GetOldSelection, 3472). --define(wxAuiNotebookEvent_SetDragSource, 3473). --define(wxAuiNotebookEvent_GetDragSource, 3474). --define(wxAuiManagerEvent_SetManager, 3475). --define(wxAuiManagerEvent_GetManager, 3476). --define(wxAuiManagerEvent_SetPane, 3477). --define(wxAuiManagerEvent_GetPane, 3478). --define(wxAuiManagerEvent_SetButton, 3479). --define(wxAuiManagerEvent_GetButton, 3480). --define(wxAuiManagerEvent_SetDC, 3481). --define(wxAuiManagerEvent_GetDC, 3482). --define(wxAuiManagerEvent_Veto, 3483). --define(wxAuiManagerEvent_GetVeto, 3484). --define(wxAuiManagerEvent_SetCanVeto, 3485). --define(wxAuiManagerEvent_CanVeto, 3486). --define(wxLogNull_new, 3487). --define(wxLogNull_destruct, 3488). --define(wxTaskBarIcon_new, 3489). --define(wxTaskBarIcon_destruct, 3490). --define(wxTaskBarIcon_PopupMenu, 3491). --define(wxTaskBarIcon_RemoveIcon, 3492). --define(wxTaskBarIcon_SetIcon, 3493). --define(wxLocale_new_0, 3494). --define(wxLocale_new_2_0, 3495). --define(wxLocale_new_2_1, 3496). --define(wxLocale_destruct, 3497). --define(wxLocale_Init_1, 3498). --define(wxLocale_Init_2, 3499). --define(wxLocale_AddCatalog_1, 3500). --define(wxLocale_AddCatalog_2, 3501). --define(wxLocale_AddCatalog_3, 3502). --define(wxLocale_AddCatalogLookupPathPrefix, 3503). --define(wxLocale_GetCanonicalName, 3504). --define(wxLocale_GetLanguage, 3505). --define(wxLocale_GetLanguageName, 3506). --define(wxLocale_GetLocale, 3507). --define(wxLocale_GetName, 3508). --define(wxLocale_GetString_2, 3509). --define(wxLocale_GetString_4, 3510). --define(wxLocale_GetHeaderValue, 3511). --define(wxLocale_GetSysName, 3512). --define(wxLocale_GetSystemEncoding, 3513). --define(wxLocale_GetSystemEncodingName, 3514). --define(wxLocale_GetSystemLanguage, 3515). --define(wxLocale_IsLoaded, 3516). --define(wxLocale_IsOk, 3517). --define(wxActivateEvent_GetActive, 3518). --define(wxPopupWindow_new_0, 3519). --define(wxPopupWindow_new_2, 3520). --define(wxPopupWindow_Create, 3521). --define(wxPopupWindow_Position, 3522). --define(wxPopupWindow_destroy, 3523). --define(wxPopupTransientWindow_new_0, 3524). --define(wxPopupTransientWindow_new_2, 3525). --define(wxPopupTransientWindow_Popup, 3526). --define(wxPopupTransientWindow_Dismiss, 3527). --define(wxPopupTransientWindow_destroy, 3528). --define(wxOverlay_new, 3529). --define(wxOverlay_destruct, 3530). --define(wxOverlay_Reset, 3531). --define(wxDCOverlay_new_6, 3532). --define(wxDCOverlay_new_2, 3533). --define(wxDCOverlay_destruct, 3534). --define(wxDCOverlay_Clear, 3535). --define(wxDropFilesEvent_GetPosition, 3536). --define(wxDropFilesEvent_GetNumberOfFiles, 3537). --define(wxDropFilesEvent_GetFiles, 3538). --define(wxDisplay_new_0, 3539). --define(wxDisplay_new_1_0, 3540). --define(wxDisplay_new_1_1, 3541). --define(wxDisplay_destruct, 3542). --define(wxDisplay_IsOk, 3543). --define(wxDisplay_GetClientArea, 3544). --define(wxDisplay_GetGeometry, 3545). --define(wxDisplay_GetName, 3546). --define(wxDisplay_IsPrimary, 3547). --define(wxDisplay_GetCount, 3548). --define(wxDisplay_GetFromPoint, 3549). --define(wxDisplay_GetFromWindow, 3550). --define(wxDisplay_GetPPI, 3551). --define(wxGCDC_new_1, 3552). --define(wxGCDC_new_0, 3555). --define(wxGCDC_destruct, 3556). --define(wxGCDC_GetGraphicsContext, 3557). --define(wxGCDC_SetGraphicsContext, 3558). --define(wxNotificationMessage_new_0, 3559). --define(wxNotificationMessage_new_2, 3560). --define(wxNotificationMessage_destruct, 3561). --define(wxNotificationMessage_AddAction, 3562). --define(wxNotificationMessage_Close, 3563). --define(wxNotificationMessage_SetFlags, 3564). --define(wxNotificationMessage_SetIcon, 3565). --define(wxNotificationMessage_SetMessage, 3566). --define(wxNotificationMessage_SetParent, 3567). --define(wxNotificationMessage_SetTitle, 3568). --define(wxNotificationMessage_Show, 3569). --define(wxNotificationMessage_UseTaskBarIcon, 3570). --define(wxNotificationMessage_MSWUseToasts, 3571). --define(wxWebView_New, 3573). --define(wxWebView_GetCurrentTitle, 3574). --define(wxWebView_GetCurrentURL, 3575). --define(wxWebView_GetPageSource, 3576). --define(wxWebView_GetPageText, 3577). --define(wxWebView_IsBusy, 3578). --define(wxWebView_IsEditable, 3579). --define(wxWebView_LoadURL, 3580). --define(wxWebView_Print, 3581). --define(wxWebView_Reload, 3582). --define(wxWebView_RunScript, 3583). --define(wxWebView_SetEditable, 3584). --define(wxWebView_SetPage, 3585). --define(wxWebView_Stop, 3586). --define(wxWebView_CanCopy, 3587). --define(wxWebView_CanCut, 3588). --define(wxWebView_CanPaste, 3589). --define(wxWebView_Copy, 3590). --define(wxWebView_Cut, 3591). --define(wxWebView_Paste, 3592). --define(wxWebView_EnableContextMenu, 3593). --define(wxWebView_IsContextMenuEnabled, 3594). --define(wxWebView_CanGoBack, 3595). --define(wxWebView_CanGoForward, 3596). --define(wxWebView_ClearHistory, 3597). --define(wxWebView_EnableHistory, 3598). --define(wxWebView_GoBack, 3599). --define(wxWebView_GoForward, 3600). --define(wxWebView_ClearSelection, 3601). --define(wxWebView_DeleteSelection, 3602). --define(wxWebView_GetSelectedSource, 3603). --define(wxWebView_GetSelectedText, 3604). --define(wxWebView_HasSelection, 3605). --define(wxWebView_SelectAll, 3606). --define(wxWebView_CanRedo, 3607). --define(wxWebView_CanUndo, 3608). --define(wxWebView_Redo, 3609). --define(wxWebView_Undo, 3610). --define(wxWebView_Find, 3611). --define(wxWebView_CanSetZoomType, 3612). --define(wxWebView_GetZoom, 3613). --define(wxWebView_GetZoomType, 3614). --define(wxWebView_SetZoom, 3615). --define(wxWebView_SetZoomType, 3616). --define(wxWebView_GetZoomFactor, 3617). --define(wxWebView_SetZoomFactor, 3618). --define(wxWebView_IsBackendAvailable, 3619). --define(wxWebViewEvent_GetString, 3620). --define(wxWebViewEvent_GetInt, 3621). --define(wxWebViewEvent_GetTarget, 3622). --define(wxWebViewEvent_GetURL, 3623). +-define(wxMenuBar_MacGetCommonMenuBar, 874). +-define(wxMenuBar_MacSetCommonMenuBar, 875). +-define(wxMenuBar_IsEnabled, 876). +-define(wxMenuBar_Remove, 877). +-define(wxMenuBar_Replace, 878). +-define(wxMenuBar_SetHelpString, 879). +-define(wxMenuBar_SetLabel, 880). +-define(wxMenuBar_SetMenuLabel, 881). +-define(wxControl_GetLabel, 882). +-define(wxControl_SetLabel, 883). +-define(wxControlWithItems_Append_1, 884). +-define(wxControlWithItems_Append_2, 885). +-define(wxControlWithItems_appendStrings_1, 886). +-define(wxControlWithItems_appendStrings_2, 887). +-define(wxControlWithItems_Clear, 888). +-define(wxControlWithItems_Delete, 889). +-define(wxControlWithItems_FindString, 890). +-define(wxControlWithItems_getClientData, 891). +-define(wxControlWithItems_setClientData, 892). +-define(wxControlWithItems_GetCount, 893). +-define(wxControlWithItems_GetSelection, 894). +-define(wxControlWithItems_GetString, 895). +-define(wxControlWithItems_GetStringSelection, 896). +-define(wxControlWithItems_Insert_2, 897). +-define(wxControlWithItems_Insert_3, 898). +-define(wxControlWithItems_insertStrings_2, 899). +-define(wxControlWithItems_insertStrings_3, 900). +-define(wxControlWithItems_IsEmpty, 901). +-define(wxControlWithItems_Select, 902). +-define(wxControlWithItems_SetSelection, 903). +-define(wxControlWithItems_SetString, 904). +-define(wxControlWithItems_SetStringSelection, 905). +-define(wxMenu_new_0, 906). +-define(wxMenu_new_1, 907). +-define(wxMenu_new_2, 908). +-define(wxMenu_destruct, 909). +-define(wxMenu_Append_3, 910). +-define(wxMenu_Append_4, 911). +-define(wxMenu_Append_1, 912). +-define(wxMenu_AppendCheckItem, 913). +-define(wxMenu_AppendRadioItem, 914). +-define(wxMenu_AppendSeparator, 915). +-define(wxMenu_Break, 916). +-define(wxMenu_Check, 917). +-define(wxMenu_Delete_1_0, 918). +-define(wxMenu_Delete_1_1, 919). +-define(wxMenu_Destroy_1_0, 920). +-define(wxMenu_Destroy_1_1, 921). +-define(wxMenu_Enable, 922). +-define(wxMenu_FindItem_1, 923). +-define(wxMenu_FindItem_2, 924). +-define(wxMenu_FindItemByPosition, 925). +-define(wxMenu_GetHelpString, 926). +-define(wxMenu_GetLabel, 927). +-define(wxMenu_GetMenuItemCount, 928). +-define(wxMenu_GetMenuItems, 930). +-define(wxMenu_GetTitle, 931). +-define(wxMenu_Insert_2, 932). +-define(wxMenu_Insert_3, 933). +-define(wxMenu_Insert_5, 934). +-define(wxMenu_InsertCheckItem, 935). +-define(wxMenu_InsertRadioItem, 936). +-define(wxMenu_InsertSeparator, 937). +-define(wxMenu_IsChecked, 938). +-define(wxMenu_IsEnabled, 939). +-define(wxMenu_Prepend_1, 940). +-define(wxMenu_Prepend_2, 941). +-define(wxMenu_Prepend_4, 942). +-define(wxMenu_PrependCheckItem, 943). +-define(wxMenu_PrependRadioItem, 944). +-define(wxMenu_PrependSeparator, 945). +-define(wxMenu_Remove_1_0, 946). +-define(wxMenu_Remove_1_1, 947). +-define(wxMenu_SetHelpString, 948). +-define(wxMenu_SetLabel, 949). +-define(wxMenu_SetTitle, 950). +-define(wxMenuItem_new, 951). +-define(wxMenuItem_destruct, 952). +-define(wxMenuItem_Check, 953). +-define(wxMenuItem_Enable, 954). +-define(wxMenuItem_GetBitmap, 955). +-define(wxMenuItem_GetHelp, 956). +-define(wxMenuItem_GetId, 957). +-define(wxMenuItem_GetKind, 958). +-define(wxMenuItem_GetLabelText, 959). +-define(wxMenuItem_GetItemLabel, 960). +-define(wxMenuItem_GetItemLabelText, 961). +-define(wxMenuItem_GetMenu, 962). +-define(wxMenuItem_GetSubMenu, 963). +-define(wxMenuItem_IsCheckable, 964). +-define(wxMenuItem_IsChecked, 965). +-define(wxMenuItem_IsEnabled, 966). +-define(wxMenuItem_IsSeparator, 967). +-define(wxMenuItem_IsSubMenu, 968). +-define(wxMenuItem_SetBitmap, 969). +-define(wxMenuItem_SetHelp, 970). +-define(wxMenuItem_SetMenu, 971). +-define(wxMenuItem_SetSubMenu, 972). +-define(wxMenuItem_SetItemLabel, 973). +-define(wxToolBar_AddControl, 974). +-define(wxToolBar_AddSeparator, 975). +-define(wxToolBar_AddTool_1, 976). +-define(wxToolBar_AddTool_4, 977). +-define(wxToolBar_AddTool_5, 978). +-define(wxToolBar_AddCheckTool, 979). +-define(wxToolBar_AddRadioTool, 980). +-define(wxToolBar_AddStretchableSpace, 981). +-define(wxToolBar_InsertStretchableSpace, 982). +-define(wxToolBar_DeleteTool, 983). +-define(wxToolBar_DeleteToolByPos, 984). +-define(wxToolBar_EnableTool, 985). +-define(wxToolBar_FindById, 986). +-define(wxToolBar_FindControl, 987). +-define(wxToolBar_FindToolForPosition, 988). +-define(wxToolBar_GetToolSize, 989). +-define(wxToolBar_GetToolBitmapSize, 990). +-define(wxToolBar_GetMargins, 991). +-define(wxToolBar_GetToolEnabled, 992). +-define(wxToolBar_GetToolLongHelp, 993). +-define(wxToolBar_GetToolPacking, 994). +-define(wxToolBar_GetToolPos, 995). +-define(wxToolBar_GetToolSeparation, 996). +-define(wxToolBar_GetToolShortHelp, 997). +-define(wxToolBar_GetToolState, 998). +-define(wxToolBar_InsertControl, 999). +-define(wxToolBar_InsertSeparator, 1000). +-define(wxToolBar_InsertTool_5, 1001). +-define(wxToolBar_InsertTool_2, 1002). +-define(wxToolBar_Realize, 1003). +-define(wxToolBar_RemoveTool, 1004). +-define(wxToolBar_SetMargins, 1005). +-define(wxToolBar_SetToolBitmapSize, 1006). +-define(wxToolBar_SetToolLongHelp, 1007). +-define(wxToolBar_SetToolPacking, 1008). +-define(wxToolBar_SetToolShortHelp, 1009). +-define(wxToolBar_SetToolSeparation, 1010). +-define(wxToolBar_ToggleTool, 1011). +-define(wxStatusBar_new_0, 1012). +-define(wxStatusBar_new_2, 1013). +-define(wxStatusBar_destruct, 1014). +-define(wxStatusBar_Create, 1015). +-define(wxStatusBar_GetFieldRect, 1016). +-define(wxStatusBar_GetFieldsCount, 1017). +-define(wxStatusBar_GetStatusText, 1018). +-define(wxStatusBar_PopStatusText, 1019). +-define(wxStatusBar_PushStatusText, 1020). +-define(wxStatusBar_SetFieldsCount, 1021). +-define(wxStatusBar_SetMinHeight, 1022). +-define(wxStatusBar_SetStatusText, 1023). +-define(wxStatusBar_SetStatusWidths, 1024). +-define(wxStatusBar_SetStatusStyles, 1025). +-define(wxBitmap_new_0, 1026). +-define(wxBitmap_new_4, 1028). +-define(wxBitmap_new_3, 1029). +-define(wxBitmap_new_2_1, 1030). +-define(wxBitmap_new_2_0, 1031). +-define(wxBitmap_new_2_2, 1032). +-define(wxBitmap_new_2_3, 1033). +-define(wxBitmap_destruct, 1034). +-define(wxBitmap_ConvertToImage, 1035). +-define(wxBitmap_CopyFromIcon, 1036). +-define(wxBitmap_Create_3_0, 1037). +-define(wxBitmap_Create_2, 1038). +-define(wxBitmap_Create_3_1, 1039). +-define(wxBitmap_GetDepth, 1040). +-define(wxBitmap_GetHeight, 1041). +-define(wxBitmap_GetPalette, 1042). +-define(wxBitmap_GetMask, 1043). +-define(wxBitmap_GetWidth, 1044). +-define(wxBitmap_GetSubBitmap, 1045). +-define(wxBitmap_LoadFile, 1046). +-define(wxBitmap_IsOk, 1047). +-define(wxBitmap_SaveFile, 1048). +-define(wxBitmap_SetDepth, 1049). +-define(wxBitmap_SetHeight, 1050). +-define(wxBitmap_SetMask, 1051). +-define(wxBitmap_SetPalette, 1052). +-define(wxBitmap_SetWidth, 1053). +-define(wxIcon_new_0, 1054). +-define(wxIcon_new_1, 1055). +-define(wxIcon_new_2, 1056). +-define(wxIcon_CopyFromBitmap, 1057). +-define(wxIcon_destruct, 1058). +-define(wxIconBundle_new_0, 1059). +-define(wxIconBundle_new_1_1, 1060). +-define(wxIconBundle_new_2, 1061). +-define(wxIconBundle_new_1_0, 1063). +-define(wxIconBundle_destruct, 1064). +-define(wxIconBundle_AddIcon_1_0, 1065). +-define(wxIconBundle_AddIcon_2, 1066). +-define(wxIconBundle_AddIcon_1_1, 1067). +-define(wxIconBundle_GetIcon_2, 1068). +-define(wxIconBundle_GetIcon_1, 1069). +-define(wxCursor_new_0, 1070). +-define(wxCursor_new_2, 1071). +-define(wxCursor_new_1_1, 1072). +-define(wxCursor_new_1_0, 1073). +-define(wxCursor_destruct, 1075). +-define(wxCursor_IsOk, 1076). +-define(wxMask_new_0, 1077). +-define(wxMask_new_2_0, 1078). +-define(wxMask_new_1, 1079). +-define(wxMask_new_2_1, 1080). +-define(wxMask_destruct, 1081). +-define(wxMask_Create_2_0, 1082). +-define(wxMask_Create_1, 1083). +-define(wxMask_Create_2_1, 1084). +-define(wxImage_new_0, 1085). +-define(wxImage_new_3_1, 1086). +-define(wxImage_new_2_2, 1087). +-define(wxImage_new_3_0, 1088). +-define(wxImage_new_2_1, 1089). +-define(wxImage_new_4, 1090). +-define(wxImage_new_3_3, 1091). +-define(wxImage_new_2_0, 1092). +-define(wxImage_new_3_2, 1093). +-define(wxImage_destruct, 1094). +-define(wxImage_Blur, 1095). +-define(wxImage_BlurHorizontal, 1096). +-define(wxImage_BlurVertical, 1097). +-define(wxImage_ConvertAlphaToMask_1, 1098). +-define(wxImage_ConvertAlphaToMask_4, 1099). +-define(wxImage_ConvertToGreyscale_3, 1100). +-define(wxImage_ConvertToGreyscale_0, 1101). +-define(wxImage_ConvertToMono, 1102). +-define(wxImage_Copy, 1103). +-define(wxImage_Create_3_1, 1104). +-define(wxImage_Create_2_1, 1105). +-define(wxImage_Create_3_0, 1106). +-define(wxImage_Create_2_0, 1107). +-define(wxImage_Create_4, 1108). +-define(wxImage_Create_3_2, 1109). +-define(wxImage_Destroy, 1110). +-define(wxImage_FindFirstUnusedColour, 1111). +-define(wxImage_GetImageExtWildcard, 1112). +-define(wxImage_GetAlpha_0, 1113). +-define(wxImage_GetAlpha_2, 1114). +-define(wxImage_GetBlue, 1115). +-define(wxImage_GetData, 1116). +-define(wxImage_GetGreen, 1117). +-define(wxImage_GetImageCount, 1118). +-define(wxImage_GetHeight, 1119). +-define(wxImage_GetMaskBlue, 1120). +-define(wxImage_GetMaskGreen, 1121). +-define(wxImage_GetMaskRed, 1122). +-define(wxImage_GetOrFindMaskColour, 1123). +-define(wxImage_GetPalette, 1124). +-define(wxImage_GetRed, 1125). +-define(wxImage_GetSubImage, 1126). +-define(wxImage_GetWidth, 1127). +-define(wxImage_HasAlpha, 1128). +-define(wxImage_HasMask, 1129). +-define(wxImage_GetOption, 1130). +-define(wxImage_GetOptionInt, 1131). +-define(wxImage_HasOption, 1132). +-define(wxImage_InitAlpha, 1133). +-define(wxImage_InitStandardHandlers, 1134). +-define(wxImage_IsTransparent, 1135). +-define(wxImage_LoadFile_2, 1136). +-define(wxImage_LoadFile_3, 1137). +-define(wxImage_IsOk, 1138). +-define(wxImage_RemoveHandler, 1139). +-define(wxImage_Mirror, 1140). +-define(wxImage_Replace, 1141). +-define(wxImage_Rescale, 1142). +-define(wxImage_Resize, 1143). +-define(wxImage_Rotate, 1144). +-define(wxImage_RotateHue, 1145). +-define(wxImage_Rotate90, 1146). +-define(wxImage_SaveFile_2_0, 1147). +-define(wxImage_SaveFile_2_1, 1148). +-define(wxImage_SaveFile_1, 1149). +-define(wxImage_Scale, 1150). +-define(wxImage_Size, 1151). +-define(wxImage_SetAlpha_1, 1152). +-define(wxImage_SetAlpha_3, 1153). +-define(wxImage_SetData_1, 1154). +-define(wxImage_SetData_3, 1155). +-define(wxImage_SetMask, 1156). +-define(wxImage_SetMaskColour, 1157). +-define(wxImage_SetMaskFromImage, 1158). +-define(wxImage_SetOption_2_1, 1159). +-define(wxImage_SetOption_2_0, 1160). +-define(wxImage_SetPalette, 1161). +-define(wxImage_SetRGB_5, 1162). +-define(wxImage_SetRGB_4, 1163). +-define(wxBrush_new_0, 1164). +-define(wxBrush_new_2, 1165). +-define(wxBrush_new_1, 1167). +-define(wxBrush_destruct, 1168). +-define(wxBrush_GetColour, 1169). +-define(wxBrush_GetStipple, 1170). +-define(wxBrush_GetStyle, 1171). +-define(wxBrush_IsHatch, 1172). +-define(wxBrush_IsOk, 1173). +-define(wxBrush_SetColour_1, 1174). +-define(wxBrush_SetColour_3, 1175). +-define(wxBrush_SetStipple, 1176). +-define(wxBrush_SetStyle, 1177). +-define(wxPen_new_0, 1178). +-define(wxPen_new_2, 1179). +-define(wxPen_new_1, 1180). +-define(wxPen_destruct, 1181). +-define(wxPen_GetCap, 1182). +-define(wxPen_GetColour, 1183). +-define(wxPen_GetJoin, 1184). +-define(wxPen_GetStyle, 1185). +-define(wxPen_GetWidth, 1186). +-define(wxPen_IsOk, 1187). +-define(wxPen_SetCap, 1188). +-define(wxPen_SetColour_1, 1189). +-define(wxPen_SetColour_3, 1190). +-define(wxPen_SetJoin, 1191). +-define(wxPen_SetStyle, 1192). +-define(wxPen_SetWidth, 1193). +-define(wxRegion_new_0, 1194). +-define(wxRegion_new_4, 1195). +-define(wxRegion_new_2, 1196). +-define(wxRegion_new_1_0, 1197). +-define(wxRegion_new_1_1, 1199). +-define(wxRegion_destruct, 1201). +-define(wxRegion_Clear, 1202). +-define(wxRegion_Contains_2, 1203). +-define(wxRegion_Contains_1_0, 1204). +-define(wxRegion_Contains_4, 1205). +-define(wxRegion_Contains_1_1, 1206). +-define(wxRegion_ConvertToBitmap, 1207). +-define(wxRegion_GetBox, 1208). +-define(wxRegion_Intersect_4, 1209). +-define(wxRegion_Intersect_1_0, 1210). +-define(wxRegion_Intersect_1_1, 1211). +-define(wxRegion_IsEmpty, 1212). +-define(wxRegion_Subtract_1_0, 1213). +-define(wxRegion_Subtract_1_1, 1214). +-define(wxRegion_Offset_2, 1215). +-define(wxRegion_Offset_1, 1216). +-define(wxRegion_Union_4, 1217). +-define(wxRegion_Union_1_1, 1218). +-define(wxRegion_Union_1_0, 1219). +-define(wxRegion_Union_3, 1221). +-define(wxRegion_Xor_4, 1222). +-define(wxRegion_Xor_1_0, 1223). +-define(wxRegion_Xor_1_1, 1224). +-define(wxAcceleratorTable_new_0, 1225). +-define(wxAcceleratorTable_new_2, 1226). +-define(wxAcceleratorTable_destruct, 1228). +-define(wxAcceleratorTable_IsOk, 1229). +-define(wxAcceleratorEntry_new_1_0, 1230). +-define(wxAcceleratorEntry_new_1_1, 1231). +-define(wxAcceleratorEntry_GetCommand, 1232). +-define(wxAcceleratorEntry_GetFlags, 1233). +-define(wxAcceleratorEntry_GetKeyCode, 1234). +-define(wxAcceleratorEntry_Set, 1235). +-define(wxAcceleratorEntry_destroy, 1236). +-define(wxCaret_new_3, 1238). +-define(wxCaret_new_2, 1239). +-define(wxCaret_Create_3, 1240). +-define(wxCaret_Create_2, 1241). +-define(wxCaret_GetBlinkTime, 1242). +-define(wxCaret_GetPosition, 1244). +-define(wxCaret_GetSize, 1246). +-define(wxCaret_GetWindow, 1247). +-define(wxCaret_Hide, 1248). +-define(wxCaret_IsOk, 1249). +-define(wxCaret_IsVisible, 1250). +-define(wxCaret_Move_2, 1251). +-define(wxCaret_Move_1, 1252). +-define(wxCaret_SetBlinkTime, 1253). +-define(wxCaret_SetSize_2, 1254). +-define(wxCaret_SetSize_1, 1255). +-define(wxCaret_Show, 1256). +-define(wxCaret_destroy, 1257). +-define(wxSizer_Add_2_0, 1258). +-define(wxSizer_Add_2_1, 1259). +-define(wxSizer_Add_3_0, 1262). +-define(wxSizer_Add_3_1, 1263). +-define(wxSizer_AddSpacer, 1264). +-define(wxSizer_AddStretchSpacer, 1265). +-define(wxSizer_CalcMin, 1266). +-define(wxSizer_Clear, 1267). +-define(wxSizer_Detach_1_0, 1268). +-define(wxSizer_Detach_1_1, 1270). +-define(wxSizer_Fit, 1271). +-define(wxSizer_FitInside, 1272). +-define(wxSizer_GetChildren, 1274). +-define(wxSizer_GetItem_2, 1275). +-define(wxSizer_GetItem_1, 1277). +-define(wxSizer_GetSize, 1278). +-define(wxSizer_GetPosition, 1279). +-define(wxSizer_GetMinSize, 1280). +-define(wxSizer_Hide_2, 1281). +-define(wxSizer_Hide_1, 1283). +-define(wxSizer_Insert_3_0, 1284). +-define(wxSizer_Insert_3_1, 1285). +-define(wxSizer_Insert_4_0, 1288). +-define(wxSizer_Insert_4_1, 1289). +-define(wxSizer_Insert_2, 1290). +-define(wxSizer_InsertSpacer, 1291). +-define(wxSizer_InsertStretchSpacer, 1292). +-define(wxSizer_IsShown_1_0, 1293). +-define(wxSizer_IsShown_1_1, 1295). +-define(wxSizer_Layout, 1296). +-define(wxSizer_Prepend_2_0, 1297). +-define(wxSizer_Prepend_2_1, 1298). +-define(wxSizer_Prepend_3_0, 1301). +-define(wxSizer_Prepend_3_1, 1302). +-define(wxSizer_Prepend_1, 1303). +-define(wxSizer_PrependSpacer, 1304). +-define(wxSizer_PrependStretchSpacer, 1305). +-define(wxSizer_Remove_1_1, 1306). +-define(wxSizer_Remove_1_0, 1307). +-define(wxSizer_Replace_3, 1308). +-define(wxSizer_Replace_2, 1310). +-define(wxSizer_SetDimension_4, 1311). +-define(wxSizer_SetDimension_2, 1312). +-define(wxSizer_SetMinSize_1, 1313). +-define(wxSizer_SetMinSize_2, 1314). +-define(wxSizer_SetItemMinSize_3_0, 1315). +-define(wxSizer_SetItemMinSize_2_0, 1316). +-define(wxSizer_SetItemMinSize_3_1, 1319). +-define(wxSizer_SetItemMinSize_2_1, 1320). +-define(wxSizer_SetSizeHints, 1321). +-define(wxSizer_Show_2_0, 1322). +-define(wxSizer_Show_2_1, 1324). +-define(wxSizer_Show_1, 1325). +-define(wxSizer_ShowItems, 1326). +-define(wxSizerFlags_new, 1327). +-define(wxSizerFlags_Align, 1328). +-define(wxSizerFlags_Border_2, 1329). +-define(wxSizerFlags_Border_1, 1330). +-define(wxSizerFlags_Center, 1331). +-define(wxSizerFlags_Expand, 1332). +-define(wxSizerFlags_Left, 1333). +-define(wxSizerFlags_Proportion, 1334). +-define(wxSizerFlags_Right, 1335). +-define(wxSizerFlags_destroy, 1336). +-define(wxSizerItem_new_3, 1337). +-define(wxSizerItem_new_2_0, 1338). +-define(wxSizerItem_new_2_1, 1339). +-define(wxSizerItem_destruct, 1342). +-define(wxSizerItem_CalcMin, 1343). +-define(wxSizerItem_DeleteWindows, 1344). +-define(wxSizerItem_DetachSizer, 1345). +-define(wxSizerItem_GetBorder, 1346). +-define(wxSizerItem_GetFlag, 1347). +-define(wxSizerItem_GetMinSize, 1348). +-define(wxSizerItem_GetPosition, 1349). +-define(wxSizerItem_GetProportion, 1350). +-define(wxSizerItem_GetRatio, 1351). +-define(wxSizerItem_GetRect, 1352). +-define(wxSizerItem_GetSize, 1353). +-define(wxSizerItem_GetSizer, 1354). +-define(wxSizerItem_GetSpacer, 1355). +-define(wxSizerItem_GetUserData, 1356). +-define(wxSizerItem_GetWindow, 1357). +-define(wxSizerItem_IsSizer, 1358). +-define(wxSizerItem_IsShown, 1359). +-define(wxSizerItem_IsSpacer, 1360). +-define(wxSizerItem_IsWindow, 1361). +-define(wxSizerItem_SetBorder, 1362). +-define(wxSizerItem_SetDimension, 1363). +-define(wxSizerItem_SetFlag, 1364). +-define(wxSizerItem_SetInitSize, 1365). +-define(wxSizerItem_SetMinSize_1, 1366). +-define(wxSizerItem_SetMinSize_2, 1367). +-define(wxSizerItem_SetProportion, 1368). +-define(wxSizerItem_SetRatio_2, 1369). +-define(wxSizerItem_SetRatio_1_1, 1370). +-define(wxSizerItem_SetRatio_1_0, 1371). +-define(wxSizerItem_AssignSizer, 1372). +-define(wxSizerItem_AssignSpacer_1, 1373). +-define(wxSizerItem_AssignSpacer_2, 1374). +-define(wxSizerItem_AssignWindow, 1375). +-define(wxSizerItem_Show, 1376). +-define(wxBoxSizer_new, 1377). +-define(wxBoxSizer_GetOrientation, 1378). +-define(wxBoxSizer_destroy, 1379). +-define(wxStaticBoxSizer_new_2, 1380). +-define(wxStaticBoxSizer_new_3, 1381). +-define(wxStaticBoxSizer_GetStaticBox, 1382). +-define(wxStaticBoxSizer_destroy, 1383). +-define(wxGridSizer_new_3_0, 1384). +-define(wxGridSizer_new_2, 1385). +-define(wxGridSizer_new_4, 1386). +-define(wxGridSizer_new_3_1, 1387). +-define(wxGridSizer_GetCols, 1388). +-define(wxGridSizer_GetHGap, 1389). +-define(wxGridSizer_GetRows, 1390). +-define(wxGridSizer_GetVGap, 1391). +-define(wxGridSizer_SetCols, 1392). +-define(wxGridSizer_SetHGap, 1393). +-define(wxGridSizer_SetRows, 1394). +-define(wxGridSizer_SetVGap, 1395). +-define(wxGridSizer_destroy, 1396). +-define(wxFlexGridSizer_new_3_0, 1397). +-define(wxFlexGridSizer_new_2, 1398). +-define(wxFlexGridSizer_new_4, 1399). +-define(wxFlexGridSizer_new_3_1, 1400). +-define(wxFlexGridSizer_AddGrowableCol, 1401). +-define(wxFlexGridSizer_AddGrowableRow, 1402). +-define(wxFlexGridSizer_GetFlexibleDirection, 1403). +-define(wxFlexGridSizer_GetNonFlexibleGrowMode, 1404). +-define(wxFlexGridSizer_RemoveGrowableCol, 1405). +-define(wxFlexGridSizer_RemoveGrowableRow, 1406). +-define(wxFlexGridSizer_SetFlexibleDirection, 1407). +-define(wxFlexGridSizer_SetNonFlexibleGrowMode, 1408). +-define(wxFlexGridSizer_destroy, 1409). +-define(wxGridBagSizer_new, 1410). +-define(wxGridBagSizer_Add_3, 1411). +-define(wxGridBagSizer_Add_1, 1413). +-define(wxGridBagSizer_Add_4, 1414). +-define(wxGridBagSizer_CalcMin, 1415). +-define(wxGridBagSizer_CheckForIntersection_2, 1416). +-define(wxGridBagSizer_CheckForIntersection_3, 1417). +-define(wxGridBagSizer_FindItem, 1418). +-define(wxGridBagSizer_FindItemAtPoint, 1420). +-define(wxGridBagSizer_FindItemAtPosition, 1421). +-define(wxGridBagSizer_FindItemWithData, 1422). +-define(wxGridBagSizer_GetCellSize, 1423). +-define(wxGridBagSizer_GetEmptyCellSize, 1424). +-define(wxGridBagSizer_GetItemPosition_1_0, 1425). +-define(wxGridBagSizer_GetItemPosition_1_1, 1427). +-define(wxGridBagSizer_GetItemSpan_1_0, 1428). +-define(wxGridBagSizer_GetItemSpan_1_1, 1430). +-define(wxGridBagSizer_SetEmptyCellSize, 1431). +-define(wxGridBagSizer_SetItemPosition_2_0, 1432). +-define(wxGridBagSizer_SetItemPosition_2_1, 1434). +-define(wxGridBagSizer_SetItemSpan_2_0, 1435). +-define(wxGridBagSizer_SetItemSpan_2_1, 1437). +-define(wxGridBagSizer_destroy, 1438). +-define(wxStdDialogButtonSizer_new, 1439). +-define(wxStdDialogButtonSizer_AddButton, 1440). +-define(wxStdDialogButtonSizer_Realize, 1441). +-define(wxStdDialogButtonSizer_SetAffirmativeButton, 1442). +-define(wxStdDialogButtonSizer_SetCancelButton, 1443). +-define(wxStdDialogButtonSizer_SetNegativeButton, 1444). +-define(wxStdDialogButtonSizer_destroy, 1445). +-define(wxFont_new_0, 1446). +-define(wxFont_new_1_1, 1447). +-define(wxFont_new_5_0, 1448). +-define(wxFont_new_5_1, 1449). +-define(wxFont_new_1_0, 1450). +-define(wxFont_destruct, 1451). +-define(wxFont_IsFixedWidth, 1452). +-define(wxFont_GetDefaultEncoding, 1453). +-define(wxFont_GetFaceName, 1454). +-define(wxFont_GetFamily, 1455). +-define(wxFont_GetNativeFontInfoDesc, 1456). +-define(wxFont_GetNativeFontInfoUserDesc, 1457). +-define(wxFont_GetPointSize, 1458). +-define(wxFont_GetStyle, 1459). +-define(wxFont_GetUnderlined, 1460). +-define(wxFont_GetWeight, 1461). +-define(wxFont_IsOk, 1462). +-define(wxFont_SetDefaultEncoding, 1463). +-define(wxFont_SetFaceName, 1464). +-define(wxFont_SetFamily, 1465). +-define(wxFont_SetPointSize, 1466). +-define(wxFont_SetStyle, 1467). +-define(wxFont_SetUnderlined, 1468). +-define(wxFont_SetWeight, 1469). +-define(wxToolTip_Enable, 1470). +-define(wxToolTip_SetDelay, 1471). +-define(wxToolTip_new, 1472). +-define(wxToolTip_SetTip, 1473). +-define(wxToolTip_GetTip, 1474). +-define(wxToolTip_GetWindow, 1475). +-define(wxToolTip_destroy, 1476). +-define(wxButton_new_0, 1477). +-define(wxButton_new_3, 1478). +-define(wxButton_Create, 1479). +-define(wxButton_GetDefaultSize_STAT_0, 1480). +-define(wxButton_GetDefaultSize_STAT_1, 1481). +-define(wxButton_SetDefault, 1482). +-define(wxButton_SetLabel, 1483). +-define(wxButton_GetBitmapDisabled, 1484). +-define(wxButton_GetBitmapFocus, 1485). +-define(wxButton_GetBitmapLabel, 1486). +-define(wxButton_SetBitmapDisabled, 1487). +-define(wxButton_SetBitmapFocus, 1488). +-define(wxButton_SetBitmapLabel, 1489). +-define(wxButton_destroy, 1490). +-define(wxBitmapButton_new_0, 1491). +-define(wxBitmapButton_new_4, 1492). +-define(wxBitmapButton_Create, 1493). +-define(wxBitmapButton_NewCloseButton, 1494). +-define(wxBitmapButton_destroy, 1495). +-define(wxToggleButton_new_0, 1496). +-define(wxToggleButton_new_4, 1497). +-define(wxToggleButton_destruct, 1498). +-define(wxToggleButton_Create, 1499). +-define(wxToggleButton_GetValue, 1500). +-define(wxToggleButton_SetValue, 1501). +-define(wxCalendarCtrl_new_0, 1502). +-define(wxCalendarCtrl_new_3, 1503). +-define(wxCalendarCtrl_Create, 1504). +-define(wxCalendarCtrl_destruct, 1505). +-define(wxCalendarCtrl_SetDate, 1506). +-define(wxCalendarCtrl_GetDate, 1507). +-define(wxCalendarCtrl_EnableYearChange, 1508). +-define(wxCalendarCtrl_EnableMonthChange, 1509). +-define(wxCalendarCtrl_EnableHolidayDisplay, 1510). +-define(wxCalendarCtrl_SetHeaderColours, 1511). +-define(wxCalendarCtrl_GetHeaderColourFg, 1512). +-define(wxCalendarCtrl_GetHeaderColourBg, 1513). +-define(wxCalendarCtrl_SetHighlightColours, 1514). +-define(wxCalendarCtrl_GetHighlightColourFg, 1515). +-define(wxCalendarCtrl_GetHighlightColourBg, 1516). +-define(wxCalendarCtrl_SetHolidayColours, 1517). +-define(wxCalendarCtrl_GetHolidayColourFg, 1518). +-define(wxCalendarCtrl_GetHolidayColourBg, 1519). +-define(wxCalendarCtrl_GetAttr, 1520). +-define(wxCalendarCtrl_SetAttr, 1521). +-define(wxCalendarCtrl_SetHoliday, 1522). +-define(wxCalendarCtrl_ResetAttr, 1523). +-define(wxCalendarCtrl_HitTest, 1524). +-define(wxCalendarDateAttr_new_1, 1525). +-define(wxCalendarDateAttr_new_2, 1526). +-define(wxCalendarDateAttr_SetTextColour, 1527). +-define(wxCalendarDateAttr_SetBackgroundColour, 1528). +-define(wxCalendarDateAttr_SetBorderColour, 1529). +-define(wxCalendarDateAttr_SetFont, 1530). +-define(wxCalendarDateAttr_SetBorder, 1531). +-define(wxCalendarDateAttr_SetHoliday, 1532). +-define(wxCalendarDateAttr_HasTextColour, 1533). +-define(wxCalendarDateAttr_HasBackgroundColour, 1534). +-define(wxCalendarDateAttr_HasBorderColour, 1535). +-define(wxCalendarDateAttr_HasFont, 1536). +-define(wxCalendarDateAttr_HasBorder, 1537). +-define(wxCalendarDateAttr_IsHoliday, 1538). +-define(wxCalendarDateAttr_GetTextColour, 1539). +-define(wxCalendarDateAttr_GetBackgroundColour, 1540). +-define(wxCalendarDateAttr_GetBorderColour, 1541). +-define(wxCalendarDateAttr_GetFont, 1542). +-define(wxCalendarDateAttr_GetBorder, 1543). +-define(wxCalendarDateAttr_destroy, 1544). +-define(wxCheckBox_new_0, 1545). +-define(wxCheckBox_new_4, 1546). +-define(wxCheckBox_destruct, 1547). +-define(wxCheckBox_Create, 1548). +-define(wxCheckBox_GetValue, 1549). +-define(wxCheckBox_Get3StateValue, 1550). +-define(wxCheckBox_Is3rdStateAllowedForUser, 1551). +-define(wxCheckBox_Is3State, 1552). +-define(wxCheckBox_IsChecked, 1553). +-define(wxCheckBox_SetValue, 1554). +-define(wxCheckBox_Set3StateValue, 1555). +-define(wxCheckListBox_new_0, 1556). +-define(wxCheckListBox_new_3, 1558). +-define(wxCheckListBox_destruct, 1559). +-define(wxCheckListBox_Check, 1560). +-define(wxCheckListBox_IsChecked, 1561). +-define(wxChoice_new_0, 1562). +-define(wxChoice_new_3, 1564). +-define(wxChoice_destruct, 1565). +-define(wxChoice_Create, 1567). +-define(wxChoice_Delete, 1568). +-define(wxChoice_GetColumns, 1569). +-define(wxChoice_SetColumns, 1570). +-define(wxComboBox_new_0, 1571). +-define(wxComboBox_new_3, 1573). +-define(wxComboBox_destruct, 1574). +-define(wxComboBox_Create, 1576). +-define(wxComboBox_CanCopy, 1577). +-define(wxComboBox_CanCut, 1578). +-define(wxComboBox_CanPaste, 1579). +-define(wxComboBox_CanRedo, 1580). +-define(wxComboBox_CanUndo, 1581). +-define(wxComboBox_Copy, 1582). +-define(wxComboBox_Cut, 1583). +-define(wxComboBox_GetInsertionPoint, 1584). +-define(wxComboBox_GetLastPosition, 1585). +-define(wxComboBox_GetValue, 1586). +-define(wxComboBox_Paste, 1587). +-define(wxComboBox_Redo, 1588). +-define(wxComboBox_Replace, 1589). +-define(wxComboBox_Remove, 1590). +-define(wxComboBox_SetInsertionPoint, 1591). +-define(wxComboBox_SetInsertionPointEnd, 1592). +-define(wxComboBox_SetSelection_2, 1593). +-define(wxComboBox_SetSelection_1, 1594). +-define(wxComboBox_SetValue, 1595). +-define(wxComboBox_Undo, 1596). +-define(wxGauge_new_0, 1597). +-define(wxGauge_new_4, 1598). +-define(wxGauge_destruct, 1599). +-define(wxGauge_Create, 1600). +-define(wxGauge_GetRange, 1601). +-define(wxGauge_GetValue, 1602). +-define(wxGauge_IsVertical, 1603). +-define(wxGauge_SetRange, 1604). +-define(wxGauge_SetValue, 1605). +-define(wxGauge_Pulse, 1606). +-define(wxGenericDirCtrl_new_0, 1607). +-define(wxGenericDirCtrl_new_2, 1608). +-define(wxGenericDirCtrl_destruct, 1609). +-define(wxGenericDirCtrl_Create, 1610). +-define(wxGenericDirCtrl_Init, 1611). +-define(wxGenericDirCtrl_CollapseTree, 1612). +-define(wxGenericDirCtrl_ExpandPath, 1613). +-define(wxGenericDirCtrl_GetDefaultPath, 1614). +-define(wxGenericDirCtrl_GetPath_0, 1615). +-define(wxGenericDirCtrl_GetPath_1, 1616). +-define(wxGenericDirCtrl_GetFilePath, 1617). +-define(wxGenericDirCtrl_GetFilter, 1618). +-define(wxGenericDirCtrl_GetFilterIndex, 1619). +-define(wxGenericDirCtrl_GetRootId, 1620). +-define(wxGenericDirCtrl_GetTreeCtrl, 1621). +-define(wxGenericDirCtrl_ReCreateTree, 1622). +-define(wxGenericDirCtrl_SetDefaultPath, 1623). +-define(wxGenericDirCtrl_SetFilter, 1624). +-define(wxGenericDirCtrl_SetFilterIndex, 1625). +-define(wxGenericDirCtrl_SetPath, 1626). +-define(wxStaticBox_new_0, 1627). +-define(wxStaticBox_new_4, 1628). +-define(wxStaticBox_destruct, 1629). +-define(wxStaticBox_Create, 1630). +-define(wxStaticLine_new_0, 1631). +-define(wxStaticLine_new_2, 1632). +-define(wxStaticLine_Create, 1633). +-define(wxStaticLine_IsVertical, 1634). +-define(wxStaticLine_GetDefaultSize, 1635). +-define(wxStaticLine_destroy, 1636). +-define(wxListBox_new_0, 1637). +-define(wxListBox_new_3, 1639). +-define(wxListBox_destruct, 1640). +-define(wxListBox_Create, 1642). +-define(wxListBox_Deselect, 1643). +-define(wxListBox_GetSelections, 1644). +-define(wxListBox_InsertItems, 1645). +-define(wxListBox_IsSelected, 1646). +-define(wxListBox_Set, 1649). +-define(wxListBox_HitTest_1, 1650). +-define(wxListBox_HitTest_2, 1651). +-define(wxListBox_SetFirstItem_1_0, 1652). +-define(wxListBox_SetFirstItem_1_1, 1653). +-define(wxListCtrl_new_0, 1654). +-define(wxListCtrl_new_2, 1655). +-define(wxListCtrl_destruct, 1656). +-define(wxListCtrl_Arrange, 1657). +-define(wxListCtrl_AssignImageList, 1658). +-define(wxListCtrl_ClearAll, 1659). +-define(wxListCtrl_Create, 1660). +-define(wxListCtrl_DeleteAllItems, 1661). +-define(wxListCtrl_DeleteColumn, 1662). +-define(wxListCtrl_DeleteItem, 1663). +-define(wxListCtrl_EditLabel, 1664). +-define(wxListCtrl_EnsureVisible, 1665). +-define(wxListCtrl_FindItem_3_0, 1666). +-define(wxListCtrl_FindItem_3_1, 1667). +-define(wxListCtrl_GetColumn, 1668). +-define(wxListCtrl_GetColumnCount, 1669). +-define(wxListCtrl_GetColumnWidth, 1670). +-define(wxListCtrl_GetCountPerPage, 1671). +-define(wxListCtrl_GetEditControl, 1672). +-define(wxListCtrl_GetImageList, 1673). +-define(wxListCtrl_GetItem, 1674). +-define(wxListCtrl_GetItemBackgroundColour, 1675). +-define(wxListCtrl_GetItemCount, 1676). +-define(wxListCtrl_GetItemData, 1677). +-define(wxListCtrl_GetItemFont, 1678). +-define(wxListCtrl_GetItemPosition, 1679). +-define(wxListCtrl_GetItemRect, 1680). +-define(wxListCtrl_GetItemSpacing, 1681). +-define(wxListCtrl_GetItemState, 1682). +-define(wxListCtrl_GetItemText, 1683). +-define(wxListCtrl_GetItemTextColour, 1684). +-define(wxListCtrl_GetNextItem, 1685). +-define(wxListCtrl_GetSelectedItemCount, 1686). +-define(wxListCtrl_GetTextColour, 1687). +-define(wxListCtrl_GetTopItem, 1688). +-define(wxListCtrl_GetViewRect, 1689). +-define(wxListCtrl_HitTest, 1690). +-define(wxListCtrl_InsertColumn_2, 1691). +-define(wxListCtrl_InsertColumn_3, 1692). +-define(wxListCtrl_InsertItem_1, 1693). +-define(wxListCtrl_InsertItem_2_1, 1694). +-define(wxListCtrl_InsertItem_2_0, 1695). +-define(wxListCtrl_InsertItem_3, 1696). +-define(wxListCtrl_RefreshItem, 1697). +-define(wxListCtrl_RefreshItems, 1698). +-define(wxListCtrl_ScrollList, 1699). +-define(wxListCtrl_SetBackgroundColour, 1700). +-define(wxListCtrl_SetColumn, 1701). +-define(wxListCtrl_SetColumnWidth, 1702). +-define(wxListCtrl_SetImageList, 1703). +-define(wxListCtrl_SetItem_1, 1704). +-define(wxListCtrl_SetItem_4, 1705). +-define(wxListCtrl_SetItemBackgroundColour, 1706). +-define(wxListCtrl_SetItemCount, 1707). +-define(wxListCtrl_SetItemData, 1708). +-define(wxListCtrl_SetItemFont, 1709). +-define(wxListCtrl_SetItemImage, 1710). +-define(wxListCtrl_SetItemColumnImage, 1711). +-define(wxListCtrl_SetItemPosition, 1712). +-define(wxListCtrl_SetItemState, 1713). +-define(wxListCtrl_SetItemText, 1714). +-define(wxListCtrl_SetItemTextColour, 1715). +-define(wxListCtrl_SetSingleStyle, 1716). +-define(wxListCtrl_SetTextColour, 1717). +-define(wxListCtrl_SetWindowStyleFlag, 1718). +-define(wxListCtrl_SortItems, 1719). +-define(wxListView_ClearColumnImage, 1720). +-define(wxListView_Focus, 1721). +-define(wxListView_GetFirstSelected, 1722). +-define(wxListView_GetFocusedItem, 1723). +-define(wxListView_GetNextSelected, 1724). +-define(wxListView_IsSelected, 1725). +-define(wxListView_Select, 1726). +-define(wxListView_SetColumnImage, 1727). +-define(wxListItem_new_0, 1728). +-define(wxListItem_new_1, 1729). +-define(wxListItem_Clear, 1730). +-define(wxListItem_GetAlign, 1731). +-define(wxListItem_GetBackgroundColour, 1732). +-define(wxListItem_GetColumn, 1733). +-define(wxListItem_GetFont, 1734). +-define(wxListItem_GetId, 1735). +-define(wxListItem_GetImage, 1736). +-define(wxListItem_GetMask, 1737). +-define(wxListItem_GetState, 1738). +-define(wxListItem_GetText, 1739). +-define(wxListItem_GetTextColour, 1740). +-define(wxListItem_GetWidth, 1741). +-define(wxListItem_SetAlign, 1742). +-define(wxListItem_SetBackgroundColour, 1743). +-define(wxListItem_SetColumn, 1744). +-define(wxListItem_SetFont, 1745). +-define(wxListItem_SetId, 1746). +-define(wxListItem_SetImage, 1747). +-define(wxListItem_SetMask, 1748). +-define(wxListItem_SetState, 1749). +-define(wxListItem_SetStateMask, 1750). +-define(wxListItem_SetText, 1751). +-define(wxListItem_SetTextColour, 1752). +-define(wxListItem_SetWidth, 1753). +-define(wxListItem_destroy, 1754). +-define(wxListItemAttr_new_0, 1755). +-define(wxListItemAttr_new_3, 1756). +-define(wxListItemAttr_GetBackgroundColour, 1757). +-define(wxListItemAttr_GetFont, 1758). +-define(wxListItemAttr_GetTextColour, 1759). +-define(wxListItemAttr_HasBackgroundColour, 1760). +-define(wxListItemAttr_HasFont, 1761). +-define(wxListItemAttr_HasTextColour, 1762). +-define(wxListItemAttr_SetBackgroundColour, 1763). +-define(wxListItemAttr_SetFont, 1764). +-define(wxListItemAttr_SetTextColour, 1765). +-define(wxListItemAttr_destroy, 1766). +-define(wxImageList_new_0, 1767). +-define(wxImageList_new_3, 1768). +-define(wxImageList_Add_2_0, 1769). +-define(wxImageList_Add_2_1, 1771). +-define(wxImageList_Add_1, 1772). +-define(wxImageList_Create, 1773). +-define(wxImageList_Draw, 1774). +-define(wxImageList_GetBitmap, 1775). +-define(wxImageList_GetIcon, 1776). +-define(wxImageList_GetImageCount, 1777). +-define(wxImageList_GetSize, 1778). +-define(wxImageList_Remove, 1780). +-define(wxImageList_RemoveAll, 1781). +-define(wxImageList_Replace_3, 1782). +-define(wxImageList_Replace_2, 1784). +-define(wxImageList_destroy, 1785). +-define(wxTextAttr_new_0, 1786). +-define(wxTextAttr_new_2, 1787). +-define(wxTextAttr_new_1, 1788). +-define(wxTextAttr_GetAlignment, 1789). +-define(wxTextAttr_GetBackgroundColour, 1790). +-define(wxTextAttr_GetFont, 1791). +-define(wxTextAttr_GetFontEncoding, 1792). +-define(wxTextAttr_GetFontFaceName, 1793). +-define(wxTextAttr_GetFontSize, 1794). +-define(wxTextAttr_GetFontStyle, 1795). +-define(wxTextAttr_GetFontUnderlined, 1796). +-define(wxTextAttr_GetFontWeight, 1797). +-define(wxTextAttr_GetLeftIndent, 1798). +-define(wxTextAttr_GetLeftSubIndent, 1799). +-define(wxTextAttr_GetRightIndent, 1800). +-define(wxTextAttr_GetTabs, 1801). +-define(wxTextAttr_GetTextColour, 1802). +-define(wxTextAttr_HasBackgroundColour, 1803). +-define(wxTextAttr_HasFont, 1804). +-define(wxTextAttr_HasTextColour, 1805). +-define(wxTextAttr_GetFlags, 1806). +-define(wxTextAttr_IsDefault, 1807). +-define(wxTextAttr_SetAlignment, 1808). +-define(wxTextAttr_SetBackgroundColour, 1809). +-define(wxTextAttr_SetFlags, 1810). +-define(wxTextAttr_SetFont, 1811). +-define(wxTextAttr_SetFontEncoding, 1812). +-define(wxTextAttr_SetFontFaceName, 1813). +-define(wxTextAttr_SetFontFamily, 1814). +-define(wxTextAttr_SetFontSize, 1815). +-define(wxTextAttr_SetFontPointSize, 1816). +-define(wxTextAttr_SetFontPixelSize, 1817). +-define(wxTextAttr_SetFontStyle, 1818). +-define(wxTextAttr_SetFontUnderlined, 1819). +-define(wxTextAttr_SetFontWeight, 1820). +-define(wxTextAttr_SetLeftIndent, 1821). +-define(wxTextAttr_SetRightIndent, 1822). +-define(wxTextAttr_SetTabs, 1823). +-define(wxTextAttr_SetTextColour, 1824). +-define(wxTextAttr_destroy, 1825). +-define(wxTextCtrl_new_0, 1826). +-define(wxTextCtrl_new_3, 1827). +-define(wxTextCtrl_destruct, 1828). +-define(wxTextCtrl_AppendText, 1829). +-define(wxTextCtrl_CanCopy, 1830). +-define(wxTextCtrl_CanCut, 1831). +-define(wxTextCtrl_CanPaste, 1832). +-define(wxTextCtrl_CanRedo, 1833). +-define(wxTextCtrl_CanUndo, 1834). +-define(wxTextCtrl_Clear, 1835). +-define(wxTextCtrl_Copy, 1836). +-define(wxTextCtrl_Create, 1837). +-define(wxTextCtrl_Cut, 1838). +-define(wxTextCtrl_DiscardEdits, 1839). +-define(wxTextCtrl_ChangeValue, 1840). +-define(wxTextCtrl_EmulateKeyPress, 1841). +-define(wxTextCtrl_GetDefaultStyle, 1842). +-define(wxTextCtrl_GetInsertionPoint, 1843). +-define(wxTextCtrl_GetLastPosition, 1844). +-define(wxTextCtrl_GetLineLength, 1845). +-define(wxTextCtrl_GetLineText, 1846). +-define(wxTextCtrl_GetNumberOfLines, 1847). +-define(wxTextCtrl_GetRange, 1848). +-define(wxTextCtrl_GetSelection, 1849). +-define(wxTextCtrl_GetStringSelection, 1850). +-define(wxTextCtrl_GetStyle, 1851). +-define(wxTextCtrl_GetValue, 1852). +-define(wxTextCtrl_IsEditable, 1853). +-define(wxTextCtrl_IsModified, 1854). +-define(wxTextCtrl_IsMultiLine, 1855). +-define(wxTextCtrl_IsSingleLine, 1856). +-define(wxTextCtrl_LoadFile, 1857). +-define(wxTextCtrl_MarkDirty, 1858). +-define(wxTextCtrl_Paste, 1859). +-define(wxTextCtrl_PositionToXY, 1860). +-define(wxTextCtrl_Redo, 1861). +-define(wxTextCtrl_Remove, 1862). +-define(wxTextCtrl_Replace, 1863). +-define(wxTextCtrl_SaveFile, 1864). +-define(wxTextCtrl_SetDefaultStyle, 1865). +-define(wxTextCtrl_SetEditable, 1866). +-define(wxTextCtrl_SetInsertionPoint, 1867). +-define(wxTextCtrl_SetInsertionPointEnd, 1868). +-define(wxTextCtrl_SetMaxLength, 1869). +-define(wxTextCtrl_SetSelection, 1870). +-define(wxTextCtrl_SetStyle, 1871). +-define(wxTextCtrl_SetValue, 1872). +-define(wxTextCtrl_ShowPosition, 1873). +-define(wxTextCtrl_Undo, 1874). +-define(wxTextCtrl_WriteText, 1875). +-define(wxTextCtrl_XYToPosition, 1876). +-define(wxBookCtrlBase_AddPage, 1877). +-define(wxBookCtrlBase_InsertPage, 1878). +-define(wxBookCtrlBase_DeletePage, 1879). +-define(wxBookCtrlBase_RemovePage, 1880). +-define(wxBookCtrlBase_DeleteAllPages, 1881). +-define(wxBookCtrlBase_GetPage, 1882). +-define(wxBookCtrlBase_GetPageCount, 1883). +-define(wxBookCtrlBase_GetCurrentPage, 1884). +-define(wxBookCtrlBase_AdvanceSelection, 1885). +-define(wxBookCtrlBase_SetSelection, 1886). +-define(wxBookCtrlBase_GetSelection, 1887). +-define(wxBookCtrlBase_ChangeSelection, 1888). +-define(wxBookCtrlBase_HitTest, 1889). +-define(wxBookCtrlBase_GetPageText, 1890). +-define(wxBookCtrlBase_SetPageText, 1891). +-define(wxNotebook_new_0, 1892). +-define(wxNotebook_new_3, 1893). +-define(wxNotebook_destruct, 1894). +-define(wxNotebook_AssignImageList, 1895). +-define(wxNotebook_Create, 1896). +-define(wxNotebook_GetImageList, 1897). +-define(wxNotebook_GetPageImage, 1898). +-define(wxNotebook_GetRowCount, 1899). +-define(wxNotebook_GetThemeBackgroundColour, 1900). +-define(wxNotebook_SetImageList, 1901). +-define(wxNotebook_SetPadding, 1902). +-define(wxNotebook_SetPageSize, 1903). +-define(wxNotebook_SetPageImage, 1904). +-define(wxChoicebook_new_0, 1905). +-define(wxChoicebook_new_3, 1906). +-define(wxChoicebook_AddPage, 1907). +-define(wxChoicebook_AdvanceSelection, 1908). +-define(wxChoicebook_AssignImageList, 1909). +-define(wxChoicebook_Create, 1910). +-define(wxChoicebook_DeleteAllPages, 1911). +-define(wxChoicebook_GetCurrentPage, 1912). +-define(wxChoicebook_GetImageList, 1913). +-define(wxChoicebook_GetPage, 1914). +-define(wxChoicebook_GetPageCount, 1915). +-define(wxChoicebook_GetPageImage, 1916). +-define(wxChoicebook_GetPageText, 1917). +-define(wxChoicebook_GetSelection, 1918). +-define(wxChoicebook_HitTest, 1919). +-define(wxChoicebook_InsertPage, 1920). +-define(wxChoicebook_SetImageList, 1921). +-define(wxChoicebook_SetPageSize, 1922). +-define(wxChoicebook_SetPageImage, 1923). +-define(wxChoicebook_SetPageText, 1924). +-define(wxChoicebook_SetSelection, 1925). +-define(wxChoicebook_ChangeSelection, 1926). +-define(wxChoicebook_destroy, 1927). +-define(wxToolbook_new_0, 1928). +-define(wxToolbook_new_3, 1929). +-define(wxToolbook_AddPage, 1930). +-define(wxToolbook_AdvanceSelection, 1931). +-define(wxToolbook_AssignImageList, 1932). +-define(wxToolbook_Create, 1933). +-define(wxToolbook_DeleteAllPages, 1934). +-define(wxToolbook_GetCurrentPage, 1935). +-define(wxToolbook_GetImageList, 1936). +-define(wxToolbook_GetPage, 1937). +-define(wxToolbook_GetPageCount, 1938). +-define(wxToolbook_GetPageImage, 1939). +-define(wxToolbook_GetPageText, 1940). +-define(wxToolbook_GetSelection, 1941). +-define(wxToolbook_HitTest, 1942). +-define(wxToolbook_InsertPage, 1943). +-define(wxToolbook_SetImageList, 1944). +-define(wxToolbook_SetPageSize, 1945). +-define(wxToolbook_SetPageImage, 1946). +-define(wxToolbook_SetPageText, 1947). +-define(wxToolbook_SetSelection, 1948). +-define(wxToolbook_ChangeSelection, 1949). +-define(wxToolbook_destroy, 1950). +-define(wxListbook_new_0, 1951). +-define(wxListbook_new_3, 1952). +-define(wxListbook_AddPage, 1953). +-define(wxListbook_AdvanceSelection, 1954). +-define(wxListbook_AssignImageList, 1955). +-define(wxListbook_Create, 1956). +-define(wxListbook_DeleteAllPages, 1957). +-define(wxListbook_GetCurrentPage, 1958). +-define(wxListbook_GetImageList, 1959). +-define(wxListbook_GetPage, 1960). +-define(wxListbook_GetPageCount, 1961). +-define(wxListbook_GetPageImage, 1962). +-define(wxListbook_GetPageText, 1963). +-define(wxListbook_GetSelection, 1964). +-define(wxListbook_HitTest, 1965). +-define(wxListbook_InsertPage, 1966). +-define(wxListbook_SetImageList, 1967). +-define(wxListbook_SetPageSize, 1968). +-define(wxListbook_SetPageImage, 1969). +-define(wxListbook_SetPageText, 1970). +-define(wxListbook_SetSelection, 1971). +-define(wxListbook_ChangeSelection, 1972). +-define(wxListbook_destroy, 1973). +-define(wxTreebook_new_0, 1974). +-define(wxTreebook_new_3, 1975). +-define(wxTreebook_destruct, 1976). +-define(wxTreebook_AddPage, 1977). +-define(wxTreebook_AdvanceSelection, 1978). +-define(wxTreebook_AssignImageList, 1979). +-define(wxTreebook_Create, 1980). +-define(wxTreebook_DeleteAllPages, 1981). +-define(wxTreebook_GetCurrentPage, 1982). +-define(wxTreebook_GetImageList, 1983). +-define(wxTreebook_GetPage, 1984). +-define(wxTreebook_GetPageCount, 1985). +-define(wxTreebook_GetPageImage, 1986). +-define(wxTreebook_GetPageText, 1987). +-define(wxTreebook_GetSelection, 1988). +-define(wxTreebook_ExpandNode, 1989). +-define(wxTreebook_IsNodeExpanded, 1990). +-define(wxTreebook_HitTest, 1991). +-define(wxTreebook_InsertPage, 1992). +-define(wxTreebook_InsertSubPage, 1993). +-define(wxTreebook_SetImageList, 1994). +-define(wxTreebook_SetPageSize, 1995). +-define(wxTreebook_SetPageImage, 1996). +-define(wxTreebook_SetPageText, 1997). +-define(wxTreebook_SetSelection, 1998). +-define(wxTreebook_ChangeSelection, 1999). +-define(wxTreeCtrl_new_0, 2000). +-define(wxTreeCtrl_new_2, 2001). +-define(wxTreeCtrl_destruct, 2002). +-define(wxTreeCtrl_AddRoot, 2003). +-define(wxTreeCtrl_AppendItem, 2004). +-define(wxTreeCtrl_AssignImageList, 2005). +-define(wxTreeCtrl_AssignStateImageList, 2006). +-define(wxTreeCtrl_Collapse, 2007). +-define(wxTreeCtrl_CollapseAndReset, 2008). +-define(wxTreeCtrl_Create, 2009). +-define(wxTreeCtrl_Delete, 2010). +-define(wxTreeCtrl_DeleteAllItems, 2011). +-define(wxTreeCtrl_DeleteChildren, 2012). +-define(wxTreeCtrl_EditLabel, 2013). +-define(wxTreeCtrl_EnsureVisible, 2014). +-define(wxTreeCtrl_Expand, 2015). +-define(wxTreeCtrl_GetBoundingRect, 2016). +-define(wxTreeCtrl_GetChildrenCount, 2017). +-define(wxTreeCtrl_GetCount, 2018). +-define(wxTreeCtrl_GetEditControl, 2019). +-define(wxTreeCtrl_GetFirstChild, 2020). +-define(wxTreeCtrl_GetNextChild, 2021). +-define(wxTreeCtrl_GetFirstVisibleItem, 2022). +-define(wxTreeCtrl_GetImageList, 2023). +-define(wxTreeCtrl_GetIndent, 2024). +-define(wxTreeCtrl_GetItemBackgroundColour, 2025). +-define(wxTreeCtrl_GetItemData, 2026). +-define(wxTreeCtrl_GetItemFont, 2027). +-define(wxTreeCtrl_GetItemImage, 2028). +-define(wxTreeCtrl_GetItemText, 2029). +-define(wxTreeCtrl_GetItemTextColour, 2030). +-define(wxTreeCtrl_GetLastChild, 2031). +-define(wxTreeCtrl_GetNextSibling, 2032). +-define(wxTreeCtrl_GetNextVisible, 2033). +-define(wxTreeCtrl_GetItemParent, 2034). +-define(wxTreeCtrl_GetPrevSibling, 2035). +-define(wxTreeCtrl_GetPrevVisible, 2036). +-define(wxTreeCtrl_GetRootItem, 2037). +-define(wxTreeCtrl_GetSelection, 2038). +-define(wxTreeCtrl_GetSelections, 2039). +-define(wxTreeCtrl_GetStateImageList, 2040). +-define(wxTreeCtrl_HitTest, 2041). +-define(wxTreeCtrl_InsertItem, 2042). +-define(wxTreeCtrl_IsBold, 2044). +-define(wxTreeCtrl_IsExpanded, 2045). +-define(wxTreeCtrl_IsSelected, 2046). +-define(wxTreeCtrl_IsVisible, 2047). +-define(wxTreeCtrl_ItemHasChildren, 2048). +-define(wxTreeCtrl_IsTreeItemIdOk, 2049). +-define(wxTreeCtrl_PrependItem, 2050). +-define(wxTreeCtrl_ScrollTo, 2051). +-define(wxTreeCtrl_SelectItem, 2052). +-define(wxTreeCtrl_SetIndent, 2053). +-define(wxTreeCtrl_SetImageList, 2054). +-define(wxTreeCtrl_SetItemBackgroundColour, 2055). +-define(wxTreeCtrl_SetItemBold, 2056). +-define(wxTreeCtrl_SetItemData, 2057). +-define(wxTreeCtrl_SetItemDropHighlight, 2058). +-define(wxTreeCtrl_SetItemFont, 2059). +-define(wxTreeCtrl_SetItemHasChildren, 2060). +-define(wxTreeCtrl_SetItemImage, 2061). +-define(wxTreeCtrl_SetItemText, 2062). +-define(wxTreeCtrl_SetItemTextColour, 2063). +-define(wxTreeCtrl_SetStateImageList, 2064). +-define(wxTreeCtrl_SetWindowStyle, 2065). +-define(wxTreeCtrl_SortChildren, 2066). +-define(wxTreeCtrl_Toggle, 2067). +-define(wxTreeCtrl_ToggleItemSelection, 2068). +-define(wxTreeCtrl_Unselect, 2069). +-define(wxTreeCtrl_UnselectAll, 2070). +-define(wxTreeCtrl_UnselectItem, 2071). +-define(wxScrollBar_new_0, 2072). +-define(wxScrollBar_new_3, 2073). +-define(wxScrollBar_destruct, 2074). +-define(wxScrollBar_Create, 2075). +-define(wxScrollBar_GetRange, 2076). +-define(wxScrollBar_GetPageSize, 2077). +-define(wxScrollBar_GetThumbPosition, 2078). +-define(wxScrollBar_GetThumbSize, 2079). +-define(wxScrollBar_SetThumbPosition, 2080). +-define(wxScrollBar_SetScrollbar, 2081). +-define(wxSpinButton_new_0, 2082). +-define(wxSpinButton_new_2, 2083). +-define(wxSpinButton_destruct, 2084). +-define(wxSpinButton_Create, 2085). +-define(wxSpinButton_GetMax, 2086). +-define(wxSpinButton_GetMin, 2087). +-define(wxSpinButton_GetValue, 2088). +-define(wxSpinButton_SetRange, 2089). +-define(wxSpinButton_SetValue, 2090). +-define(wxSpinCtrl_new_0, 2091). +-define(wxSpinCtrl_new_2, 2092). +-define(wxSpinCtrl_Create, 2093). +-define(wxSpinCtrl_SetValue_1_1, 2094). +-define(wxSpinCtrl_SetValue_1_0, 2095). +-define(wxSpinCtrl_GetValue, 2096). +-define(wxSpinCtrl_SetRange, 2097). +-define(wxSpinCtrl_SetSelection, 2098). +-define(wxSpinCtrl_GetMin, 2099). +-define(wxSpinCtrl_GetMax, 2100). +-define(wxSpinCtrl_destroy, 2101). +-define(wxStaticText_new_0, 2102). +-define(wxStaticText_new_4, 2103). +-define(wxStaticText_Create, 2104). +-define(wxStaticText_GetLabel, 2105). +-define(wxStaticText_SetLabel, 2106). +-define(wxStaticText_Wrap, 2107). +-define(wxStaticText_destroy, 2108). +-define(wxStaticBitmap_new_0, 2109). +-define(wxStaticBitmap_new_4, 2110). +-define(wxStaticBitmap_Create, 2111). +-define(wxStaticBitmap_GetBitmap, 2112). +-define(wxStaticBitmap_SetBitmap, 2113). +-define(wxStaticBitmap_destroy, 2114). +-define(wxRadioBox_new, 2115). +-define(wxRadioBox_destruct, 2116). +-define(wxRadioBox_Create, 2117). +-define(wxRadioBox_Enable_1, 2118). +-define(wxRadioBox_Enable_2, 2119). +-define(wxRadioBox_GetSelection, 2120). +-define(wxRadioBox_GetString, 2121). +-define(wxRadioBox_SetSelection, 2122). +-define(wxRadioBox_Show, 2123). +-define(wxRadioBox_GetColumnCount, 2124). +-define(wxRadioBox_GetItemHelpText, 2125). +-define(wxRadioBox_GetItemToolTip, 2126). +-define(wxRadioBox_GetItemFromPoint, 2127). +-define(wxRadioBox_GetRowCount, 2128). +-define(wxRadioBox_IsItemEnabled, 2129). +-define(wxRadioBox_IsItemShown, 2130). +-define(wxRadioBox_SetItemHelpText, 2131). +-define(wxRadioBox_SetItemToolTip, 2132). +-define(wxRadioButton_new_0, 2133). +-define(wxRadioButton_new_4, 2134). +-define(wxRadioButton_destruct, 2135). +-define(wxRadioButton_Create, 2136). +-define(wxRadioButton_GetValue, 2137). +-define(wxRadioButton_SetValue, 2138). +-define(wxSlider_new_0, 2139). +-define(wxSlider_new_6, 2140). +-define(wxSlider_destruct, 2141). +-define(wxSlider_Create, 2142). +-define(wxSlider_GetLineSize, 2143). +-define(wxSlider_GetMax, 2144). +-define(wxSlider_GetMin, 2145). +-define(wxSlider_GetPageSize, 2146). +-define(wxSlider_GetThumbLength, 2147). +-define(wxSlider_GetValue, 2148). +-define(wxSlider_SetLineSize, 2149). +-define(wxSlider_SetPageSize, 2150). +-define(wxSlider_SetRange, 2151). +-define(wxSlider_SetThumbLength, 2152). +-define(wxSlider_SetValue, 2153). +-define(wxDialog_new_0, 2154). +-define(wxDialog_new_4, 2155). +-define(wxDialog_destruct, 2156). +-define(wxDialog_Create, 2157). +-define(wxDialog_CreateButtonSizer, 2158). +-define(wxDialog_CreateStdDialogButtonSizer, 2159). +-define(wxDialog_EndModal, 2160). +-define(wxDialog_GetAffirmativeId, 2161). +-define(wxDialog_GetReturnCode, 2162). +-define(wxDialog_IsModal, 2163). +-define(wxDialog_SetAffirmativeId, 2164). +-define(wxDialog_SetReturnCode, 2165). +-define(wxDialog_Show, 2166). +-define(wxDialog_ShowModal, 2167). +-define(wxColourDialog_new_0, 2168). +-define(wxColourDialog_new_2, 2169). +-define(wxColourDialog_destruct, 2170). +-define(wxColourDialog_Create, 2171). +-define(wxColourDialog_GetColourData, 2172). +-define(wxColourData_new, 2173). +-define(wxColourData_destruct, 2174). +-define(wxColourData_GetChooseFull, 2175). +-define(wxColourData_GetColour, 2176). +-define(wxColourData_GetCustomColour, 2177). +-define(wxColourData_SetChooseFull, 2178). +-define(wxColourData_SetColour, 2179). +-define(wxColourData_SetCustomColour, 2180). +-define(wxPalette_new_0, 2181). +-define(wxPalette_new_1, 2182). +-define(wxPalette_new_4, 2183). +-define(wxPalette_destruct, 2184). +-define(wxPalette_Create, 2185). +-define(wxPalette_GetColoursCount, 2186). +-define(wxPalette_GetPixel, 2187). +-define(wxPalette_GetRGB, 2188). +-define(wxPalette_IsOk, 2189). +-define(wxDirDialog_new, 2190). +-define(wxDirDialog_destruct, 2191). +-define(wxDirDialog_GetPath, 2192). +-define(wxDirDialog_GetMessage, 2193). +-define(wxDirDialog_SetMessage, 2194). +-define(wxDirDialog_SetPath, 2195). +-define(wxFileDialog_new, 2196). +-define(wxFileDialog_destruct, 2197). +-define(wxFileDialog_GetDirectory, 2198). +-define(wxFileDialog_GetFilename, 2199). +-define(wxFileDialog_GetFilenames, 2200). +-define(wxFileDialog_GetFilterIndex, 2201). +-define(wxFileDialog_GetMessage, 2202). +-define(wxFileDialog_GetPath, 2203). +-define(wxFileDialog_GetPaths, 2204). +-define(wxFileDialog_GetWildcard, 2205). +-define(wxFileDialog_SetDirectory, 2206). +-define(wxFileDialog_SetFilename, 2207). +-define(wxFileDialog_SetFilterIndex, 2208). +-define(wxFileDialog_SetMessage, 2209). +-define(wxFileDialog_SetPath, 2210). +-define(wxFileDialog_SetWildcard, 2211). +-define(wxPickerBase_SetInternalMargin, 2212). +-define(wxPickerBase_GetInternalMargin, 2213). +-define(wxPickerBase_SetTextCtrlProportion, 2214). +-define(wxPickerBase_SetPickerCtrlProportion, 2215). +-define(wxPickerBase_GetTextCtrlProportion, 2216). +-define(wxPickerBase_GetPickerCtrlProportion, 2217). +-define(wxPickerBase_HasTextCtrl, 2218). +-define(wxPickerBase_GetTextCtrl, 2219). +-define(wxPickerBase_IsTextCtrlGrowable, 2220). +-define(wxPickerBase_SetPickerCtrlGrowable, 2221). +-define(wxPickerBase_SetTextCtrlGrowable, 2222). +-define(wxPickerBase_IsPickerCtrlGrowable, 2223). +-define(wxFilePickerCtrl_new_0, 2224). +-define(wxFilePickerCtrl_new_3, 2225). +-define(wxFilePickerCtrl_Create, 2226). +-define(wxFilePickerCtrl_GetPath, 2227). +-define(wxFilePickerCtrl_SetPath, 2228). +-define(wxFilePickerCtrl_destroy, 2229). +-define(wxDirPickerCtrl_new_0, 2230). +-define(wxDirPickerCtrl_new_3, 2231). +-define(wxDirPickerCtrl_Create, 2232). +-define(wxDirPickerCtrl_GetPath, 2233). +-define(wxDirPickerCtrl_SetPath, 2234). +-define(wxDirPickerCtrl_destroy, 2235). +-define(wxColourPickerCtrl_new_0, 2236). +-define(wxColourPickerCtrl_new_3, 2237). +-define(wxColourPickerCtrl_Create, 2238). +-define(wxColourPickerCtrl_GetColour, 2239). +-define(wxColourPickerCtrl_SetColour_1_1, 2240). +-define(wxColourPickerCtrl_SetColour_1_0, 2241). +-define(wxColourPickerCtrl_destroy, 2242). +-define(wxDatePickerCtrl_new_0, 2243). +-define(wxDatePickerCtrl_new_3, 2244). +-define(wxDatePickerCtrl_GetRange, 2245). +-define(wxDatePickerCtrl_GetValue, 2246). +-define(wxDatePickerCtrl_SetRange, 2247). +-define(wxDatePickerCtrl_SetValue, 2248). +-define(wxDatePickerCtrl_destroy, 2249). +-define(wxFontPickerCtrl_new_0, 2250). +-define(wxFontPickerCtrl_new_3, 2251). +-define(wxFontPickerCtrl_Create, 2252). +-define(wxFontPickerCtrl_GetSelectedFont, 2253). +-define(wxFontPickerCtrl_SetSelectedFont, 2254). +-define(wxFontPickerCtrl_GetMaxPointSize, 2255). +-define(wxFontPickerCtrl_SetMaxPointSize, 2256). +-define(wxFontPickerCtrl_destroy, 2257). +-define(wxFindReplaceDialog_new_0, 2258). +-define(wxFindReplaceDialog_new_4, 2259). +-define(wxFindReplaceDialog_destruct, 2260). +-define(wxFindReplaceDialog_Create, 2261). +-define(wxFindReplaceDialog_GetData, 2262). +-define(wxFindReplaceData_new, 2263). +-define(wxFindReplaceData_GetFindString, 2264). +-define(wxFindReplaceData_GetReplaceString, 2265). +-define(wxFindReplaceData_GetFlags, 2266). +-define(wxFindReplaceData_SetFlags, 2267). +-define(wxFindReplaceData_SetFindString, 2268). +-define(wxFindReplaceData_SetReplaceString, 2269). +-define(wxFindReplaceData_destroy, 2270). +-define(wxMultiChoiceDialog_new, 2272). +-define(wxMultiChoiceDialog_GetSelections, 2273). +-define(wxMultiChoiceDialog_SetSelections, 2274). +-define(wxMultiChoiceDialog_destroy, 2275). +-define(wxSingleChoiceDialog_new, 2277). +-define(wxSingleChoiceDialog_GetSelection, 2278). +-define(wxSingleChoiceDialog_GetStringSelection, 2279). +-define(wxSingleChoiceDialog_SetSelection, 2280). +-define(wxSingleChoiceDialog_destroy, 2281). +-define(wxTextEntryDialog_new_0, 2282). +-define(wxTextEntryDialog_new_3, 2283). +-define(wxTextEntryDialog_destruct, 2284). +-define(wxTextEntryDialog_GetValue, 2285). +-define(wxTextEntryDialog_SetValue, 2286). +-define(wxPasswordEntryDialog_new, 2287). +-define(wxPasswordEntryDialog_destroy, 2288). +-define(wxFontData_new_0, 2289). +-define(wxFontData_new_1, 2290). +-define(wxFontData_EnableEffects, 2291). +-define(wxFontData_GetAllowSymbols, 2292). +-define(wxFontData_GetColour, 2293). +-define(wxFontData_GetChosenFont, 2294). +-define(wxFontData_GetEnableEffects, 2295). +-define(wxFontData_GetInitialFont, 2296). +-define(wxFontData_GetShowHelp, 2297). +-define(wxFontData_SetAllowSymbols, 2298). +-define(wxFontData_SetChosenFont, 2299). +-define(wxFontData_SetColour, 2300). +-define(wxFontData_SetInitialFont, 2301). +-define(wxFontData_SetRange, 2302). +-define(wxFontData_SetShowHelp, 2303). +-define(wxFontData_destroy, 2304). +-define(wxFontDialog_new_0, 2305). +-define(wxFontDialog_new_2, 2307). +-define(wxFontDialog_Create, 2309). +-define(wxFontDialog_GetFontData, 2310). +-define(wxFontDialog_destroy, 2312). +-define(wxProgressDialog_new, 2313). +-define(wxProgressDialog_Resume, 2314). +-define(wxProgressDialog_Update, 2315). +-define(wxProgressDialog_destroy, 2316). +-define(wxMessageDialog_new, 2317). +-define(wxMessageDialog_destroy, 2318). +-define(wxPageSetupDialog_new, 2319). +-define(wxPageSetupDialog_destruct, 2320). +-define(wxPageSetupDialog_GetPageSetupData, 2321). +-define(wxPageSetupDialog_ShowModal, 2322). +-define(wxPageSetupDialogData_new_0, 2323). +-define(wxPageSetupDialogData_new_1, 2325). +-define(wxPageSetupDialogData_destruct, 2326). +-define(wxPageSetupDialogData_EnableHelp, 2327). +-define(wxPageSetupDialogData_EnableMargins, 2328). +-define(wxPageSetupDialogData_EnableOrientation, 2329). +-define(wxPageSetupDialogData_EnablePaper, 2330). +-define(wxPageSetupDialogData_EnablePrinter, 2331). +-define(wxPageSetupDialogData_GetDefaultMinMargins, 2332). +-define(wxPageSetupDialogData_GetEnableMargins, 2333). +-define(wxPageSetupDialogData_GetEnableOrientation, 2334). +-define(wxPageSetupDialogData_GetEnablePaper, 2335). +-define(wxPageSetupDialogData_GetEnablePrinter, 2336). +-define(wxPageSetupDialogData_GetEnableHelp, 2337). +-define(wxPageSetupDialogData_GetDefaultInfo, 2338). +-define(wxPageSetupDialogData_GetMarginTopLeft, 2339). +-define(wxPageSetupDialogData_GetMarginBottomRight, 2340). +-define(wxPageSetupDialogData_GetMinMarginTopLeft, 2341). +-define(wxPageSetupDialogData_GetMinMarginBottomRight, 2342). +-define(wxPageSetupDialogData_GetPaperId, 2343). +-define(wxPageSetupDialogData_GetPaperSize, 2344). +-define(wxPageSetupDialogData_GetPrintData, 2346). +-define(wxPageSetupDialogData_IsOk, 2347). +-define(wxPageSetupDialogData_SetDefaultInfo, 2348). +-define(wxPageSetupDialogData_SetDefaultMinMargins, 2349). +-define(wxPageSetupDialogData_SetMarginTopLeft, 2350). +-define(wxPageSetupDialogData_SetMarginBottomRight, 2351). +-define(wxPageSetupDialogData_SetMinMarginTopLeft, 2352). +-define(wxPageSetupDialogData_SetMinMarginBottomRight, 2353). +-define(wxPageSetupDialogData_SetPaperId, 2354). +-define(wxPageSetupDialogData_SetPaperSize, 2355). +-define(wxPageSetupDialogData_SetPrintData, 2356). +-define(wxPrintDialog_new_2_0, 2357). +-define(wxPrintDialog_new_2_1, 2358). +-define(wxPrintDialog_destruct, 2359). +-define(wxPrintDialog_GetPrintDialogData, 2360). +-define(wxPrintDialog_GetPrintDC, 2361). +-define(wxPrintDialogData_new_0, 2362). +-define(wxPrintDialogData_new_1, 2363). +-define(wxPrintDialogData_destruct, 2365). +-define(wxPrintDialogData_EnableHelp, 2366). +-define(wxPrintDialogData_EnablePageNumbers, 2367). +-define(wxPrintDialogData_EnablePrintToFile, 2368). +-define(wxPrintDialogData_EnableSelection, 2369). +-define(wxPrintDialogData_GetAllPages, 2370). +-define(wxPrintDialogData_GetCollate, 2371). +-define(wxPrintDialogData_GetFromPage, 2372). +-define(wxPrintDialogData_GetMaxPage, 2373). +-define(wxPrintDialogData_GetMinPage, 2374). +-define(wxPrintDialogData_GetNoCopies, 2375). +-define(wxPrintDialogData_GetPrintData, 2376). +-define(wxPrintDialogData_GetPrintToFile, 2377). +-define(wxPrintDialogData_GetSelection, 2378). +-define(wxPrintDialogData_GetToPage, 2379). +-define(wxPrintDialogData_IsOk, 2380). +-define(wxPrintDialogData_SetCollate, 2381). +-define(wxPrintDialogData_SetFromPage, 2382). +-define(wxPrintDialogData_SetMaxPage, 2383). +-define(wxPrintDialogData_SetMinPage, 2384). +-define(wxPrintDialogData_SetNoCopies, 2385). +-define(wxPrintDialogData_SetPrintData, 2386). +-define(wxPrintDialogData_SetPrintToFile, 2387). +-define(wxPrintDialogData_SetSelection, 2388). +-define(wxPrintDialogData_SetToPage, 2389). +-define(wxPrintData_new_0, 2390). +-define(wxPrintData_new_1, 2391). +-define(wxPrintData_destruct, 2392). +-define(wxPrintData_GetCollate, 2393). +-define(wxPrintData_GetBin, 2394). +-define(wxPrintData_GetColour, 2395). +-define(wxPrintData_GetDuplex, 2396). +-define(wxPrintData_GetNoCopies, 2397). +-define(wxPrintData_GetOrientation, 2398). +-define(wxPrintData_GetPaperId, 2399). +-define(wxPrintData_GetPrinterName, 2400). +-define(wxPrintData_GetQuality, 2401). +-define(wxPrintData_IsOk, 2402). +-define(wxPrintData_SetBin, 2403). +-define(wxPrintData_SetCollate, 2404). +-define(wxPrintData_SetColour, 2405). +-define(wxPrintData_SetDuplex, 2406). +-define(wxPrintData_SetNoCopies, 2407). +-define(wxPrintData_SetOrientation, 2408). +-define(wxPrintData_SetPaperId, 2409). +-define(wxPrintData_SetPrinterName, 2410). +-define(wxPrintData_SetQuality, 2411). +-define(wxPrintPreview_new_2, 2412). +-define(wxPrintPreview_new_3, 2413). +-define(wxPrintPreview_destruct, 2414). +-define(wxPrintPreview_GetCanvas, 2415). +-define(wxPrintPreview_GetCurrentPage, 2416). +-define(wxPrintPreview_GetFrame, 2417). +-define(wxPrintPreview_GetMaxPage, 2418). +-define(wxPrintPreview_GetMinPage, 2419). +-define(wxPrintPreview_GetPrintout, 2420). +-define(wxPrintPreview_GetPrintoutForPrinting, 2421). +-define(wxPrintPreview_IsOk, 2422). +-define(wxPrintPreview_PaintPage, 2423). +-define(wxPrintPreview_Print, 2424). +-define(wxPrintPreview_RenderPage, 2425). +-define(wxPrintPreview_SetCanvas, 2426). +-define(wxPrintPreview_SetCurrentPage, 2427). +-define(wxPrintPreview_SetFrame, 2428). +-define(wxPrintPreview_SetPrintout, 2429). +-define(wxPrintPreview_SetZoom, 2430). +-define(wxPreviewFrame_new, 2431). +-define(wxPreviewFrame_destruct, 2432). +-define(wxPreviewFrame_CreateControlBar, 2433). +-define(wxPreviewFrame_CreateCanvas, 2434). +-define(wxPreviewFrame_Initialize, 2435). +-define(wxPreviewFrame_OnCloseWindow, 2436). +-define(wxPreviewControlBar_new, 2437). +-define(wxPreviewControlBar_destruct, 2438). +-define(wxPreviewControlBar_CreateButtons, 2439). +-define(wxPreviewControlBar_GetPrintPreview, 2440). +-define(wxPreviewControlBar_GetZoomControl, 2441). +-define(wxPreviewControlBar_SetZoomControl, 2442). +-define(wxPrinter_new, 2443). +-define(wxPrinter_CreateAbortWindow, 2444). +-define(wxPrinter_GetAbort, 2445). +-define(wxPrinter_GetLastError, 2446). +-define(wxPrinter_GetPrintDialogData, 2447). +-define(wxPrinter_Print, 2448). +-define(wxPrinter_PrintDialog, 2449). +-define(wxPrinter_ReportError, 2450). +-define(wxPrinter_Setup, 2451). +-define(wxPrinter_destroy, 2452). +-define(wxXmlResource_new_2, 2453). +-define(wxXmlResource_new_1, 2454). +-define(wxXmlResource_destruct, 2455). +-define(wxXmlResource_AttachUnknownControl, 2456). +-define(wxXmlResource_ClearHandlers, 2457). +-define(wxXmlResource_CompareVersion, 2458). +-define(wxXmlResource_Get, 2459). +-define(wxXmlResource_GetFlags, 2460). +-define(wxXmlResource_GetVersion, 2461). +-define(wxXmlResource_GetXRCID, 2462). +-define(wxXmlResource_InitAllHandlers, 2463). +-define(wxXmlResource_Load, 2464). +-define(wxXmlResource_LoadBitmap, 2465). +-define(wxXmlResource_LoadDialog_2, 2466). +-define(wxXmlResource_LoadDialog_3, 2467). +-define(wxXmlResource_LoadFrame_2, 2468). +-define(wxXmlResource_LoadFrame_3, 2469). +-define(wxXmlResource_LoadIcon, 2470). +-define(wxXmlResource_LoadMenu, 2471). +-define(wxXmlResource_LoadMenuBar_2, 2472). +-define(wxXmlResource_LoadMenuBar_1, 2473). +-define(wxXmlResource_LoadPanel_2, 2474). +-define(wxXmlResource_LoadPanel_3, 2475). +-define(wxXmlResource_LoadToolBar, 2476). +-define(wxXmlResource_Set, 2477). +-define(wxXmlResource_SetFlags, 2478). +-define(wxXmlResource_Unload, 2479). +-define(wxXmlResource_xrcctrl, 2480). +-define(wxHtmlEasyPrinting_new, 2481). +-define(wxHtmlEasyPrinting_GetPrintData, 2482). +-define(wxHtmlEasyPrinting_GetPageSetupData, 2483). +-define(wxHtmlEasyPrinting_PreviewFile, 2484). +-define(wxHtmlEasyPrinting_PreviewText, 2485). +-define(wxHtmlEasyPrinting_PrintFile, 2486). +-define(wxHtmlEasyPrinting_PrintText, 2487). +-define(wxHtmlEasyPrinting_PageSetup, 2488). +-define(wxHtmlEasyPrinting_SetFonts, 2489). +-define(wxHtmlEasyPrinting_SetHeader, 2490). +-define(wxHtmlEasyPrinting_SetFooter, 2491). +-define(wxHtmlEasyPrinting_destroy, 2492). +-define(wxGLCanvas_new, 2493). +-define(wxGLCanvas_SetCurrent, 2494). +-define(wxGLCanvas_CreateSurface, 2495). +-define(wxGLCanvas_IsDisplaySupported, 2496). +-define(wxGLCanvas_SwapBuffers, 2497). +-define(wxGLCanvas_destroy, 2498). +-define(wxGLContext_new, 2499). +-define(wxGLContext_SetCurrent, 2500). +-define(wxGLContext_IsOK, 2501). +-define(wxGLContext_destroy, 2502). +-define(wxAuiManager_new, 2503). +-define(wxAuiManager_destruct, 2504). +-define(wxAuiManager_AddPane_2_1, 2505). +-define(wxAuiManager_AddPane_2_0, 2506). +-define(wxAuiManager_AddPane_3, 2507). +-define(wxAuiManager_DetachPane, 2508). +-define(wxAuiManager_GetAllPanes, 2509). +-define(wxAuiManager_GetArtProvider, 2510). +-define(wxAuiManager_GetDockSizeConstraint, 2511). +-define(wxAuiManager_GetFlags, 2512). +-define(wxAuiManager_GetManagedWindow, 2513). +-define(wxAuiManager_GetManager, 2514). +-define(wxAuiManager_GetPane_1_1, 2515). +-define(wxAuiManager_GetPane_1_0, 2516). +-define(wxAuiManager_HideHint, 2517). +-define(wxAuiManager_InsertPane, 2518). +-define(wxAuiManager_LoadPaneInfo, 2519). +-define(wxAuiManager_LoadPerspective, 2520). +-define(wxAuiManager_SavePaneInfo, 2521). +-define(wxAuiManager_SavePerspective, 2522). +-define(wxAuiManager_SetArtProvider, 2523). +-define(wxAuiManager_SetDockSizeConstraint, 2524). +-define(wxAuiManager_SetFlags, 2525). +-define(wxAuiManager_SetManagedWindow, 2526). +-define(wxAuiManager_ShowHint, 2527). +-define(wxAuiManager_UnInit, 2528). +-define(wxAuiManager_Update, 2529). +-define(wxAuiPaneInfo_new_0, 2530). +-define(wxAuiPaneInfo_new_1, 2531). +-define(wxAuiPaneInfo_BestSize_1, 2532). +-define(wxAuiPaneInfo_BestSize_2, 2533). +-define(wxAuiPaneInfo_Bottom, 2534). +-define(wxAuiPaneInfo_BottomDockable, 2535). +-define(wxAuiPaneInfo_Caption, 2536). +-define(wxAuiPaneInfo_CaptionVisible, 2537). +-define(wxAuiPaneInfo_Centre, 2538). +-define(wxAuiPaneInfo_CentrePane, 2539). +-define(wxAuiPaneInfo_CloseButton, 2540). +-define(wxAuiPaneInfo_DefaultPane, 2541). +-define(wxAuiPaneInfo_DestroyOnClose, 2542). +-define(wxAuiPaneInfo_Direction, 2543). +-define(wxAuiPaneInfo_Dock, 2544). +-define(wxAuiPaneInfo_Dockable, 2545). +-define(wxAuiPaneInfo_Fixed, 2546). +-define(wxAuiPaneInfo_Float, 2547). +-define(wxAuiPaneInfo_Floatable, 2548). +-define(wxAuiPaneInfo_FloatingPosition_1, 2549). +-define(wxAuiPaneInfo_FloatingPosition_2, 2550). +-define(wxAuiPaneInfo_FloatingSize_1, 2551). +-define(wxAuiPaneInfo_FloatingSize_2, 2552). +-define(wxAuiPaneInfo_Gripper, 2553). +-define(wxAuiPaneInfo_GripperTop, 2554). +-define(wxAuiPaneInfo_HasBorder, 2555). +-define(wxAuiPaneInfo_HasCaption, 2556). +-define(wxAuiPaneInfo_HasCloseButton, 2557). +-define(wxAuiPaneInfo_HasFlag, 2558). +-define(wxAuiPaneInfo_HasGripper, 2559). +-define(wxAuiPaneInfo_HasGripperTop, 2560). +-define(wxAuiPaneInfo_HasMaximizeButton, 2561). +-define(wxAuiPaneInfo_HasMinimizeButton, 2562). +-define(wxAuiPaneInfo_HasPinButton, 2563). +-define(wxAuiPaneInfo_Hide, 2564). +-define(wxAuiPaneInfo_IsBottomDockable, 2565). +-define(wxAuiPaneInfo_IsDocked, 2566). +-define(wxAuiPaneInfo_IsFixed, 2567). +-define(wxAuiPaneInfo_IsFloatable, 2568). +-define(wxAuiPaneInfo_IsFloating, 2569). +-define(wxAuiPaneInfo_IsLeftDockable, 2570). +-define(wxAuiPaneInfo_IsMovable, 2571). +-define(wxAuiPaneInfo_IsOk, 2572). +-define(wxAuiPaneInfo_IsResizable, 2573). +-define(wxAuiPaneInfo_IsRightDockable, 2574). +-define(wxAuiPaneInfo_IsShown, 2575). +-define(wxAuiPaneInfo_IsToolbar, 2576). +-define(wxAuiPaneInfo_IsTopDockable, 2577). +-define(wxAuiPaneInfo_Layer, 2578). +-define(wxAuiPaneInfo_Left, 2579). +-define(wxAuiPaneInfo_LeftDockable, 2580). +-define(wxAuiPaneInfo_MaxSize_1, 2581). +-define(wxAuiPaneInfo_MaxSize_2, 2582). +-define(wxAuiPaneInfo_MaximizeButton, 2583). +-define(wxAuiPaneInfo_MinSize_1, 2584). +-define(wxAuiPaneInfo_MinSize_2, 2585). +-define(wxAuiPaneInfo_MinimizeButton, 2586). +-define(wxAuiPaneInfo_Movable, 2587). +-define(wxAuiPaneInfo_Name, 2588). +-define(wxAuiPaneInfo_PaneBorder, 2589). +-define(wxAuiPaneInfo_PinButton, 2590). +-define(wxAuiPaneInfo_Position, 2591). +-define(wxAuiPaneInfo_Resizable, 2592). +-define(wxAuiPaneInfo_Right, 2593). +-define(wxAuiPaneInfo_RightDockable, 2594). +-define(wxAuiPaneInfo_Row, 2595). +-define(wxAuiPaneInfo_SafeSet, 2596). +-define(wxAuiPaneInfo_SetFlag, 2597). +-define(wxAuiPaneInfo_Show, 2598). +-define(wxAuiPaneInfo_ToolbarPane, 2599). +-define(wxAuiPaneInfo_Top, 2600). +-define(wxAuiPaneInfo_TopDockable, 2601). +-define(wxAuiPaneInfo_Window, 2602). +-define(wxAuiPaneInfo_GetWindow, 2603). +-define(wxAuiPaneInfo_GetFrame, 2604). +-define(wxAuiPaneInfo_GetDirection, 2605). +-define(wxAuiPaneInfo_GetLayer, 2606). +-define(wxAuiPaneInfo_GetRow, 2607). +-define(wxAuiPaneInfo_GetPosition, 2608). +-define(wxAuiPaneInfo_GetFloatingPosition, 2609). +-define(wxAuiPaneInfo_GetFloatingSize, 2610). +-define(wxAuiPaneInfo_destroy, 2611). +-define(wxAuiNotebook_new_0, 2612). +-define(wxAuiNotebook_new_2, 2613). +-define(wxAuiNotebook_AddPage_3, 2614). +-define(wxAuiNotebook_AddPage_4, 2615). +-define(wxAuiNotebook_Create_2, 2616). +-define(wxAuiNotebook_Create_3, 2617). +-define(wxAuiNotebook_DeletePage, 2618). +-define(wxAuiNotebook_GetArtProvider, 2619). +-define(wxAuiNotebook_GetPage, 2620). +-define(wxAuiNotebook_GetPageBitmap, 2621). +-define(wxAuiNotebook_GetPageCount, 2622). +-define(wxAuiNotebook_GetPageIndex, 2623). +-define(wxAuiNotebook_GetPageText, 2624). +-define(wxAuiNotebook_GetSelection, 2625). +-define(wxAuiNotebook_InsertPage_4, 2626). +-define(wxAuiNotebook_InsertPage_5, 2627). +-define(wxAuiNotebook_RemovePage, 2628). +-define(wxAuiNotebook_SetArtProvider, 2629). +-define(wxAuiNotebook_SetFont, 2630). +-define(wxAuiNotebook_SetPageBitmap, 2631). +-define(wxAuiNotebook_SetPageText, 2632). +-define(wxAuiNotebook_SetSelection, 2633). +-define(wxAuiNotebook_SetTabCtrlHeight, 2634). +-define(wxAuiNotebook_SetUniformBitmapSize, 2635). +-define(wxAuiNotebook_destroy, 2636). +-define(wxAuiTabArt_SetFlags, 2637). +-define(wxAuiTabArt_SetMeasuringFont, 2638). +-define(wxAuiTabArt_SetNormalFont, 2639). +-define(wxAuiTabArt_SetSelectedFont, 2640). +-define(wxAuiTabArt_SetColour, 2641). +-define(wxAuiTabArt_SetActiveColour, 2642). +-define(wxAuiDockArt_GetColour, 2643). +-define(wxAuiDockArt_GetFont, 2644). +-define(wxAuiDockArt_GetMetric, 2645). +-define(wxAuiDockArt_SetColour, 2646). +-define(wxAuiDockArt_SetFont, 2647). +-define(wxAuiDockArt_SetMetric, 2648). +-define(wxAuiSimpleTabArt_new, 2649). +-define(wxAuiSimpleTabArt_destroy, 2650). +-define(wxMDIParentFrame_new_0, 2651). +-define(wxMDIParentFrame_new_4, 2652). +-define(wxMDIParentFrame_destruct, 2653). +-define(wxMDIParentFrame_ActivateNext, 2654). +-define(wxMDIParentFrame_ActivatePrevious, 2655). +-define(wxMDIParentFrame_ArrangeIcons, 2656). +-define(wxMDIParentFrame_Cascade, 2657). +-define(wxMDIParentFrame_Create, 2658). +-define(wxMDIParentFrame_GetActiveChild, 2659). +-define(wxMDIParentFrame_GetClientWindow, 2660). +-define(wxMDIParentFrame_Tile, 2661). +-define(wxMDIChildFrame_new_0, 2662). +-define(wxMDIChildFrame_new_4, 2663). +-define(wxMDIChildFrame_destruct, 2664). +-define(wxMDIChildFrame_Activate, 2665). +-define(wxMDIChildFrame_Create, 2666). +-define(wxMDIChildFrame_Maximize, 2667). +-define(wxMDIChildFrame_Restore, 2668). +-define(wxMDIClientWindow_new, 2669). +-define(wxMDIClientWindow_CreateClient, 2670). +-define(wxMDIClientWindow_destroy, 2671). +-define(wxLayoutAlgorithm_new, 2672). +-define(wxLayoutAlgorithm_destruct, 2673). +-define(wxLayoutAlgorithm_LayoutFrame, 2674). +-define(wxLayoutAlgorithm_LayoutMDIFrame, 2675). +-define(wxLayoutAlgorithm_LayoutWindow, 2676). +-define(wxEvent_GetId, 2677). +-define(wxEvent_GetSkipped, 2678). +-define(wxEvent_GetTimestamp, 2679). +-define(wxEvent_IsCommandEvent, 2680). +-define(wxEvent_ResumePropagation, 2681). +-define(wxEvent_ShouldPropagate, 2682). +-define(wxEvent_Skip, 2683). +-define(wxEvent_StopPropagation, 2684). +-define(wxCommandEvent_getClientData, 2685). +-define(wxCommandEvent_GetExtraLong, 2686). +-define(wxCommandEvent_GetInt, 2687). +-define(wxCommandEvent_GetSelection, 2688). +-define(wxCommandEvent_GetString, 2689). +-define(wxCommandEvent_IsChecked, 2690). +-define(wxCommandEvent_IsSelection, 2691). +-define(wxCommandEvent_SetInt, 2692). +-define(wxCommandEvent_SetString, 2693). +-define(wxScrollEvent_GetOrientation, 2694). +-define(wxScrollEvent_GetPosition, 2695). +-define(wxScrollWinEvent_GetOrientation, 2696). +-define(wxScrollWinEvent_GetPosition, 2697). +-define(wxMouseEvent_AltDown, 2698). +-define(wxMouseEvent_Button, 2699). +-define(wxMouseEvent_ButtonDClick, 2700). +-define(wxMouseEvent_ButtonDown, 2701). +-define(wxMouseEvent_ButtonUp, 2702). +-define(wxMouseEvent_CmdDown, 2703). +-define(wxMouseEvent_ControlDown, 2704). +-define(wxMouseEvent_Dragging, 2705). +-define(wxMouseEvent_Entering, 2706). +-define(wxMouseEvent_GetButton, 2707). +-define(wxMouseEvent_GetPosition, 2708). +-define(wxMouseEvent_GetLogicalPosition, 2710). +-define(wxMouseEvent_GetLinesPerAction, 2711). +-define(wxMouseEvent_GetWheelRotation, 2712). +-define(wxMouseEvent_GetWheelDelta, 2713). +-define(wxMouseEvent_GetX, 2714). +-define(wxMouseEvent_GetY, 2715). +-define(wxMouseEvent_IsButton, 2716). +-define(wxMouseEvent_IsPageScroll, 2717). +-define(wxMouseEvent_Leaving, 2718). +-define(wxMouseEvent_LeftDClick, 2719). +-define(wxMouseEvent_LeftDown, 2720). +-define(wxMouseEvent_LeftIsDown, 2721). +-define(wxMouseEvent_LeftUp, 2722). +-define(wxMouseEvent_MetaDown, 2723). +-define(wxMouseEvent_MiddleDClick, 2724). +-define(wxMouseEvent_MiddleDown, 2725). +-define(wxMouseEvent_MiddleIsDown, 2726). +-define(wxMouseEvent_MiddleUp, 2727). +-define(wxMouseEvent_Moving, 2728). +-define(wxMouseEvent_RightDClick, 2729). +-define(wxMouseEvent_RightDown, 2730). +-define(wxMouseEvent_RightIsDown, 2731). +-define(wxMouseEvent_RightUp, 2732). +-define(wxMouseEvent_ShiftDown, 2733). +-define(wxMouseEvent_GetWheelAxis, 2734). +-define(wxMouseEvent_Aux1DClick, 2735). +-define(wxMouseEvent_Aux1Down, 2736). +-define(wxMouseEvent_Aux1Up, 2737). +-define(wxMouseEvent_Aux2DClick, 2738). +-define(wxMouseEvent_Aux2Down, 2739). +-define(wxMouseEvent_Aux2Up, 2740). +-define(wxSetCursorEvent_GetCursor, 2741). +-define(wxSetCursorEvent_GetX, 2742). +-define(wxSetCursorEvent_GetY, 2743). +-define(wxSetCursorEvent_HasCursor, 2744). +-define(wxSetCursorEvent_SetCursor, 2745). +-define(wxKeyEvent_AltDown, 2746). +-define(wxKeyEvent_CmdDown, 2747). +-define(wxKeyEvent_ControlDown, 2748). +-define(wxKeyEvent_GetKeyCode, 2749). +-define(wxKeyEvent_GetModifiers, 2750). +-define(wxKeyEvent_GetPosition, 2751). +-define(wxKeyEvent_GetRawKeyCode, 2753). +-define(wxKeyEvent_GetRawKeyFlags, 2754). +-define(wxKeyEvent_GetUnicodeKey, 2755). +-define(wxKeyEvent_GetX, 2756). +-define(wxKeyEvent_GetY, 2757). +-define(wxKeyEvent_HasModifiers, 2758). +-define(wxKeyEvent_MetaDown, 2759). +-define(wxKeyEvent_ShiftDown, 2760). +-define(wxSizeEvent_GetSize, 2761). +-define(wxSizeEvent_GetRect, 2762). +-define(wxMoveEvent_GetPosition, 2763). +-define(wxMoveEvent_GetRect, 2764). +-define(wxEraseEvent_GetDC, 2765). +-define(wxFocusEvent_GetWindow, 2766). +-define(wxChildFocusEvent_GetWindow, 2767). +-define(wxMenuEvent_GetMenu, 2768). +-define(wxMenuEvent_GetMenuId, 2769). +-define(wxMenuEvent_IsPopup, 2770). +-define(wxCloseEvent_CanVeto, 2771). +-define(wxCloseEvent_GetLoggingOff, 2772). +-define(wxCloseEvent_SetCanVeto, 2773). +-define(wxCloseEvent_SetLoggingOff, 2774). +-define(wxCloseEvent_Veto, 2775). +-define(wxShowEvent_SetShow, 2776). +-define(wxShowEvent_IsShown, 2777). +-define(wxIconizeEvent_IsIconized, 2778). +-define(wxJoystickEvent_ButtonDown, 2779). +-define(wxJoystickEvent_ButtonIsDown, 2780). +-define(wxJoystickEvent_ButtonUp, 2781). +-define(wxJoystickEvent_GetButtonChange, 2782). +-define(wxJoystickEvent_GetButtonState, 2783). +-define(wxJoystickEvent_GetJoystick, 2784). +-define(wxJoystickEvent_GetPosition, 2785). +-define(wxJoystickEvent_GetZPosition, 2786). +-define(wxJoystickEvent_IsButton, 2787). +-define(wxJoystickEvent_IsMove, 2788). +-define(wxJoystickEvent_IsZMove, 2789). +-define(wxUpdateUIEvent_CanUpdate, 2790). +-define(wxUpdateUIEvent_Check, 2791). +-define(wxUpdateUIEvent_Enable, 2792). +-define(wxUpdateUIEvent_Show, 2793). +-define(wxUpdateUIEvent_GetChecked, 2794). +-define(wxUpdateUIEvent_GetEnabled, 2795). +-define(wxUpdateUIEvent_GetShown, 2796). +-define(wxUpdateUIEvent_GetSetChecked, 2797). +-define(wxUpdateUIEvent_GetSetEnabled, 2798). +-define(wxUpdateUIEvent_GetSetShown, 2799). +-define(wxUpdateUIEvent_GetSetText, 2800). +-define(wxUpdateUIEvent_GetText, 2801). +-define(wxUpdateUIEvent_GetMode, 2802). +-define(wxUpdateUIEvent_GetUpdateInterval, 2803). +-define(wxUpdateUIEvent_ResetUpdateTime, 2804). +-define(wxUpdateUIEvent_SetMode, 2805). +-define(wxUpdateUIEvent_SetText, 2806). +-define(wxUpdateUIEvent_SetUpdateInterval, 2807). +-define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2808). +-define(wxPaletteChangedEvent_SetChangedWindow, 2809). +-define(wxPaletteChangedEvent_GetChangedWindow, 2810). +-define(wxQueryNewPaletteEvent_SetPaletteRealized, 2811). +-define(wxQueryNewPaletteEvent_GetPaletteRealized, 2812). +-define(wxNavigationKeyEvent_GetDirection, 2813). +-define(wxNavigationKeyEvent_SetDirection, 2814). +-define(wxNavigationKeyEvent_IsWindowChange, 2815). +-define(wxNavigationKeyEvent_SetWindowChange, 2816). +-define(wxNavigationKeyEvent_IsFromTab, 2817). +-define(wxNavigationKeyEvent_SetFromTab, 2818). +-define(wxNavigationKeyEvent_GetCurrentFocus, 2819). +-define(wxNavigationKeyEvent_SetCurrentFocus, 2820). +-define(wxHelpEvent_GetOrigin, 2821). +-define(wxHelpEvent_GetPosition, 2822). +-define(wxHelpEvent_SetOrigin, 2823). +-define(wxHelpEvent_SetPosition, 2824). +-define(wxContextMenuEvent_GetPosition, 2825). +-define(wxContextMenuEvent_SetPosition, 2826). +-define(wxIdleEvent_GetMode, 2827). +-define(wxIdleEvent_RequestMore, 2828). +-define(wxIdleEvent_MoreRequested, 2829). +-define(wxIdleEvent_SetMode, 2830). +-define(wxGridEvent_AltDown, 2831). +-define(wxGridEvent_ControlDown, 2832). +-define(wxGridEvent_GetCol, 2833). +-define(wxGridEvent_GetPosition, 2834). +-define(wxGridEvent_GetRow, 2835). +-define(wxGridEvent_MetaDown, 2836). +-define(wxGridEvent_Selecting, 2837). +-define(wxGridEvent_ShiftDown, 2838). +-define(wxNotifyEvent_Allow, 2839). +-define(wxNotifyEvent_IsAllowed, 2840). +-define(wxNotifyEvent_Veto, 2841). +-define(wxSashEvent_GetEdge, 2842). +-define(wxSashEvent_GetDragRect, 2843). +-define(wxSashEvent_GetDragStatus, 2844). +-define(wxListEvent_GetCacheFrom, 2845). +-define(wxListEvent_GetCacheTo, 2846). +-define(wxListEvent_GetKeyCode, 2847). +-define(wxListEvent_GetIndex, 2848). +-define(wxListEvent_GetColumn, 2849). +-define(wxListEvent_GetPoint, 2850). +-define(wxListEvent_GetLabel, 2851). +-define(wxListEvent_GetText, 2852). +-define(wxListEvent_GetImage, 2853). +-define(wxListEvent_GetData, 2854). +-define(wxListEvent_GetMask, 2855). +-define(wxListEvent_GetItem, 2856). +-define(wxListEvent_IsEditCancelled, 2857). +-define(wxDateEvent_GetDate, 2858). +-define(wxCalendarEvent_GetWeekDay, 2859). +-define(wxCalendarEvent_GetDate, 2860). +-define(wxFileDirPickerEvent_GetPath, 2861). +-define(wxColourPickerEvent_GetColour, 2862). +-define(wxFontPickerEvent_GetFont, 2863). +-define(wxStyledTextEvent_GetPosition, 2864). +-define(wxStyledTextEvent_GetKey, 2865). +-define(wxStyledTextEvent_GetModifiers, 2866). +-define(wxStyledTextEvent_GetModificationType, 2867). +-define(wxStyledTextEvent_GetText, 2868). +-define(wxStyledTextEvent_GetLength, 2869). +-define(wxStyledTextEvent_GetLinesAdded, 2870). +-define(wxStyledTextEvent_GetLine, 2871). +-define(wxStyledTextEvent_GetFoldLevelNow, 2872). +-define(wxStyledTextEvent_GetFoldLevelPrev, 2873). +-define(wxStyledTextEvent_GetMargin, 2874). +-define(wxStyledTextEvent_GetMessage, 2875). +-define(wxStyledTextEvent_GetWParam, 2876). +-define(wxStyledTextEvent_GetLParam, 2877). +-define(wxStyledTextEvent_GetListType, 2878). +-define(wxStyledTextEvent_GetX, 2879). +-define(wxStyledTextEvent_GetY, 2880). +-define(wxStyledTextEvent_GetDragText, 2881). +-define(wxStyledTextEvent_GetDragAllowMove, 2882). +-define(wxStyledTextEvent_GetDragResult, 2883). +-define(wxStyledTextEvent_GetShift, 2884). +-define(wxStyledTextEvent_GetControl, 2885). +-define(wxStyledTextEvent_GetAlt, 2886). +-define(utils_wxGetKeyState, 2887). +-define(utils_wxGetMousePosition, 2888). +-define(utils_wxGetMouseState, 2889). +-define(utils_wxSetDetectableAutoRepeat, 2890). +-define(utils_wxBell, 2891). +-define(utils_wxFindMenuItemId, 2892). +-define(utils_wxFindWindowAtPoint, 2893). +-define(utils_wxBeginBusyCursor, 2894). +-define(utils_wxEndBusyCursor, 2895). +-define(utils_wxIsBusy, 2896). +-define(utils_wxShutdown, 2897). +-define(utils_wxShell, 2898). +-define(utils_wxLaunchDefaultBrowser, 2899). +-define(utils_wxGetEmailAddress, 2900). +-define(utils_wxGetUserId, 2901). +-define(utils_wxGetHomeDir, 2902). +-define(utils_wxNewId, 2903). +-define(utils_wxRegisterId, 2904). +-define(utils_wxGetCurrentId, 2905). +-define(utils_wxGetOsDescription, 2906). +-define(utils_wxIsPlatformLittleEndian, 2907). +-define(utils_wxIsPlatform64Bit, 2908). +-define(gdicmn_wxDisplaySize, 2909). +-define(gdicmn_wxSetCursor, 2910). +-define(wxPrintout_new, 2911). +-define(wxPrintout_destruct, 2912). +-define(wxPrintout_GetDC, 2913). +-define(wxPrintout_GetPageSizeMM, 2914). +-define(wxPrintout_GetPageSizePixels, 2915). +-define(wxPrintout_GetPaperRectPixels, 2916). +-define(wxPrintout_GetPPIPrinter, 2917). +-define(wxPrintout_GetPPIScreen, 2918). +-define(wxPrintout_GetTitle, 2919). +-define(wxPrintout_IsPreview, 2920). +-define(wxPrintout_FitThisSizeToPaper, 2921). +-define(wxPrintout_FitThisSizeToPage, 2922). +-define(wxPrintout_FitThisSizeToPageMargins, 2923). +-define(wxPrintout_MapScreenSizeToPaper, 2924). +-define(wxPrintout_MapScreenSizeToPage, 2925). +-define(wxPrintout_MapScreenSizeToPageMargins, 2926). +-define(wxPrintout_MapScreenSizeToDevice, 2927). +-define(wxPrintout_GetLogicalPaperRect, 2928). +-define(wxPrintout_GetLogicalPageRect, 2929). +-define(wxPrintout_GetLogicalPageMarginsRect, 2930). +-define(wxPrintout_SetLogicalOrigin, 2931). +-define(wxPrintout_OffsetLogicalOrigin, 2932). +-define(wxStyledTextCtrl_new_2, 2933). +-define(wxStyledTextCtrl_new_0, 2934). +-define(wxStyledTextCtrl_destruct, 2935). +-define(wxStyledTextCtrl_Create, 2936). +-define(wxStyledTextCtrl_AddText, 2937). +-define(wxStyledTextCtrl_InsertText, 2938). +-define(wxStyledTextCtrl_ClearAll, 2939). +-define(wxStyledTextCtrl_ClearDocumentStyle, 2940). +-define(wxStyledTextCtrl_GetLength, 2941). +-define(wxStyledTextCtrl_GetCharAt, 2942). +-define(wxStyledTextCtrl_GetCurrentPos, 2943). +-define(wxStyledTextCtrl_GetAnchor, 2944). +-define(wxStyledTextCtrl_GetStyleAt, 2945). +-define(wxStyledTextCtrl_Redo, 2946). +-define(wxStyledTextCtrl_SetUndoCollection, 2947). +-define(wxStyledTextCtrl_SelectAll, 2948). +-define(wxStyledTextCtrl_SetSavePoint, 2949). +-define(wxStyledTextCtrl_CanRedo, 2950). +-define(wxStyledTextCtrl_MarkerLineFromHandle, 2951). +-define(wxStyledTextCtrl_MarkerDeleteHandle, 2952). +-define(wxStyledTextCtrl_GetUndoCollection, 2953). +-define(wxStyledTextCtrl_GetViewWhiteSpace, 2954). +-define(wxStyledTextCtrl_SetViewWhiteSpace, 2955). +-define(wxStyledTextCtrl_PositionFromPoint, 2956). +-define(wxStyledTextCtrl_PositionFromPointClose, 2957). +-define(wxStyledTextCtrl_GotoLine, 2958). +-define(wxStyledTextCtrl_GotoPos, 2959). +-define(wxStyledTextCtrl_SetAnchor, 2960). +-define(wxStyledTextCtrl_GetCurLine, 2961). +-define(wxStyledTextCtrl_GetEndStyled, 2962). +-define(wxStyledTextCtrl_ConvertEOLs, 2963). +-define(wxStyledTextCtrl_GetEOLMode, 2964). +-define(wxStyledTextCtrl_SetEOLMode, 2965). +-define(wxStyledTextCtrl_StartStyling, 2966). +-define(wxStyledTextCtrl_SetStyling, 2967). +-define(wxStyledTextCtrl_GetBufferedDraw, 2968). +-define(wxStyledTextCtrl_SetBufferedDraw, 2969). +-define(wxStyledTextCtrl_SetTabWidth, 2970). +-define(wxStyledTextCtrl_GetTabWidth, 2971). +-define(wxStyledTextCtrl_SetCodePage, 2972). +-define(wxStyledTextCtrl_MarkerDefine, 2973). +-define(wxStyledTextCtrl_MarkerSetForeground, 2974). +-define(wxStyledTextCtrl_MarkerSetBackground, 2975). +-define(wxStyledTextCtrl_MarkerAdd, 2976). +-define(wxStyledTextCtrl_MarkerDelete, 2977). +-define(wxStyledTextCtrl_MarkerDeleteAll, 2978). +-define(wxStyledTextCtrl_MarkerGet, 2979). +-define(wxStyledTextCtrl_MarkerNext, 2980). +-define(wxStyledTextCtrl_MarkerPrevious, 2981). +-define(wxStyledTextCtrl_MarkerDefineBitmap, 2982). +-define(wxStyledTextCtrl_MarkerAddSet, 2983). +-define(wxStyledTextCtrl_MarkerSetAlpha, 2984). +-define(wxStyledTextCtrl_SetMarginType, 2985). +-define(wxStyledTextCtrl_GetMarginType, 2986). +-define(wxStyledTextCtrl_SetMarginWidth, 2987). +-define(wxStyledTextCtrl_GetMarginWidth, 2988). +-define(wxStyledTextCtrl_SetMarginMask, 2989). +-define(wxStyledTextCtrl_GetMarginMask, 2990). +-define(wxStyledTextCtrl_SetMarginSensitive, 2991). +-define(wxStyledTextCtrl_GetMarginSensitive, 2992). +-define(wxStyledTextCtrl_StyleClearAll, 2993). +-define(wxStyledTextCtrl_StyleSetForeground, 2994). +-define(wxStyledTextCtrl_StyleSetBackground, 2995). +-define(wxStyledTextCtrl_StyleSetBold, 2996). +-define(wxStyledTextCtrl_StyleSetItalic, 2997). +-define(wxStyledTextCtrl_StyleSetSize, 2998). +-define(wxStyledTextCtrl_StyleSetFaceName, 2999). +-define(wxStyledTextCtrl_StyleSetEOLFilled, 3000). +-define(wxStyledTextCtrl_StyleResetDefault, 3001). +-define(wxStyledTextCtrl_StyleSetUnderline, 3002). +-define(wxStyledTextCtrl_StyleSetCase, 3003). +-define(wxStyledTextCtrl_StyleSetHotSpot, 3004). +-define(wxStyledTextCtrl_SetSelForeground, 3005). +-define(wxStyledTextCtrl_SetSelBackground, 3006). +-define(wxStyledTextCtrl_GetSelAlpha, 3007). +-define(wxStyledTextCtrl_SetSelAlpha, 3008). +-define(wxStyledTextCtrl_SetCaretForeground, 3009). +-define(wxStyledTextCtrl_CmdKeyAssign, 3010). +-define(wxStyledTextCtrl_CmdKeyClear, 3011). +-define(wxStyledTextCtrl_CmdKeyClearAll, 3012). +-define(wxStyledTextCtrl_SetStyleBytes, 3013). +-define(wxStyledTextCtrl_StyleSetVisible, 3014). +-define(wxStyledTextCtrl_GetCaretPeriod, 3015). +-define(wxStyledTextCtrl_SetCaretPeriod, 3016). +-define(wxStyledTextCtrl_SetWordChars, 3017). +-define(wxStyledTextCtrl_BeginUndoAction, 3018). +-define(wxStyledTextCtrl_EndUndoAction, 3019). +-define(wxStyledTextCtrl_IndicatorSetStyle, 3020). +-define(wxStyledTextCtrl_IndicatorGetStyle, 3021). +-define(wxStyledTextCtrl_IndicatorSetForeground, 3022). +-define(wxStyledTextCtrl_IndicatorGetForeground, 3023). +-define(wxStyledTextCtrl_SetWhitespaceForeground, 3024). +-define(wxStyledTextCtrl_SetWhitespaceBackground, 3025). +-define(wxStyledTextCtrl_GetStyleBits, 3026). +-define(wxStyledTextCtrl_SetLineState, 3027). +-define(wxStyledTextCtrl_GetLineState, 3028). +-define(wxStyledTextCtrl_GetMaxLineState, 3029). +-define(wxStyledTextCtrl_GetCaretLineVisible, 3030). +-define(wxStyledTextCtrl_SetCaretLineVisible, 3031). +-define(wxStyledTextCtrl_GetCaretLineBackground, 3032). +-define(wxStyledTextCtrl_SetCaretLineBackground, 3033). +-define(wxStyledTextCtrl_AutoCompShow, 3034). +-define(wxStyledTextCtrl_AutoCompCancel, 3035). +-define(wxStyledTextCtrl_AutoCompActive, 3036). +-define(wxStyledTextCtrl_AutoCompPosStart, 3037). +-define(wxStyledTextCtrl_AutoCompComplete, 3038). +-define(wxStyledTextCtrl_AutoCompStops, 3039). +-define(wxStyledTextCtrl_AutoCompSetSeparator, 3040). +-define(wxStyledTextCtrl_AutoCompGetSeparator, 3041). +-define(wxStyledTextCtrl_AutoCompSelect, 3042). +-define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3043). +-define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3044). +-define(wxStyledTextCtrl_AutoCompSetFillUps, 3045). +-define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3046). +-define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3047). +-define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3048). +-define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3049). +-define(wxStyledTextCtrl_UserListShow, 3050). +-define(wxStyledTextCtrl_AutoCompSetAutoHide, 3051). +-define(wxStyledTextCtrl_AutoCompGetAutoHide, 3052). +-define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3053). +-define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3054). +-define(wxStyledTextCtrl_RegisterImage, 3055). +-define(wxStyledTextCtrl_ClearRegisteredImages, 3056). +-define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3057). +-define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3058). +-define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3059). +-define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3060). +-define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3061). +-define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3062). +-define(wxStyledTextCtrl_SetIndent, 3063). +-define(wxStyledTextCtrl_GetIndent, 3064). +-define(wxStyledTextCtrl_SetUseTabs, 3065). +-define(wxStyledTextCtrl_GetUseTabs, 3066). +-define(wxStyledTextCtrl_SetLineIndentation, 3067). +-define(wxStyledTextCtrl_GetLineIndentation, 3068). +-define(wxStyledTextCtrl_GetLineIndentPosition, 3069). +-define(wxStyledTextCtrl_GetColumn, 3070). +-define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3071). +-define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3072). +-define(wxStyledTextCtrl_SetIndentationGuides, 3073). +-define(wxStyledTextCtrl_GetIndentationGuides, 3074). +-define(wxStyledTextCtrl_SetHighlightGuide, 3075). +-define(wxStyledTextCtrl_GetHighlightGuide, 3076). +-define(wxStyledTextCtrl_GetLineEndPosition, 3077). +-define(wxStyledTextCtrl_GetCodePage, 3078). +-define(wxStyledTextCtrl_GetCaretForeground, 3079). +-define(wxStyledTextCtrl_GetReadOnly, 3080). +-define(wxStyledTextCtrl_SetCurrentPos, 3081). +-define(wxStyledTextCtrl_SetSelectionStart, 3082). +-define(wxStyledTextCtrl_GetSelectionStart, 3083). +-define(wxStyledTextCtrl_SetSelectionEnd, 3084). +-define(wxStyledTextCtrl_GetSelectionEnd, 3085). +-define(wxStyledTextCtrl_SetPrintMagnification, 3086). +-define(wxStyledTextCtrl_GetPrintMagnification, 3087). +-define(wxStyledTextCtrl_SetPrintColourMode, 3088). +-define(wxStyledTextCtrl_GetPrintColourMode, 3089). +-define(wxStyledTextCtrl_FindText, 3090). +-define(wxStyledTextCtrl_FormatRange, 3091). +-define(wxStyledTextCtrl_GetFirstVisibleLine, 3092). +-define(wxStyledTextCtrl_GetLine, 3093). +-define(wxStyledTextCtrl_GetLineCount, 3094). +-define(wxStyledTextCtrl_SetMarginLeft, 3095). +-define(wxStyledTextCtrl_GetMarginLeft, 3096). +-define(wxStyledTextCtrl_SetMarginRight, 3097). +-define(wxStyledTextCtrl_GetMarginRight, 3098). +-define(wxStyledTextCtrl_GetModify, 3099). +-define(wxStyledTextCtrl_SetSelection, 3100). +-define(wxStyledTextCtrl_GetSelectedText, 3101). +-define(wxStyledTextCtrl_GetTextRange, 3102). +-define(wxStyledTextCtrl_HideSelection, 3103). +-define(wxStyledTextCtrl_LineFromPosition, 3104). +-define(wxStyledTextCtrl_PositionFromLine, 3105). +-define(wxStyledTextCtrl_LineScroll, 3106). +-define(wxStyledTextCtrl_EnsureCaretVisible, 3107). +-define(wxStyledTextCtrl_ReplaceSelection, 3108). +-define(wxStyledTextCtrl_SetReadOnly, 3109). +-define(wxStyledTextCtrl_CanPaste, 3110). +-define(wxStyledTextCtrl_CanUndo, 3111). +-define(wxStyledTextCtrl_EmptyUndoBuffer, 3112). +-define(wxStyledTextCtrl_Undo, 3113). +-define(wxStyledTextCtrl_Cut, 3114). +-define(wxStyledTextCtrl_Copy, 3115). +-define(wxStyledTextCtrl_Paste, 3116). +-define(wxStyledTextCtrl_Clear, 3117). +-define(wxStyledTextCtrl_SetText, 3118). +-define(wxStyledTextCtrl_GetText, 3119). +-define(wxStyledTextCtrl_GetTextLength, 3120). +-define(wxStyledTextCtrl_GetOvertype, 3121). +-define(wxStyledTextCtrl_SetCaretWidth, 3122). +-define(wxStyledTextCtrl_GetCaretWidth, 3123). +-define(wxStyledTextCtrl_SetTargetStart, 3124). +-define(wxStyledTextCtrl_GetTargetStart, 3125). +-define(wxStyledTextCtrl_SetTargetEnd, 3126). +-define(wxStyledTextCtrl_GetTargetEnd, 3127). +-define(wxStyledTextCtrl_ReplaceTarget, 3128). +-define(wxStyledTextCtrl_SearchInTarget, 3129). +-define(wxStyledTextCtrl_SetSearchFlags, 3130). +-define(wxStyledTextCtrl_GetSearchFlags, 3131). +-define(wxStyledTextCtrl_CallTipShow, 3132). +-define(wxStyledTextCtrl_CallTipCancel, 3133). +-define(wxStyledTextCtrl_CallTipActive, 3134). +-define(wxStyledTextCtrl_CallTipPosAtStart, 3135). +-define(wxStyledTextCtrl_CallTipSetHighlight, 3136). +-define(wxStyledTextCtrl_CallTipSetBackground, 3137). +-define(wxStyledTextCtrl_CallTipSetForeground, 3138). +-define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3139). +-define(wxStyledTextCtrl_CallTipUseStyle, 3140). +-define(wxStyledTextCtrl_VisibleFromDocLine, 3141). +-define(wxStyledTextCtrl_DocLineFromVisible, 3142). +-define(wxStyledTextCtrl_WrapCount, 3143). +-define(wxStyledTextCtrl_SetFoldLevel, 3144). +-define(wxStyledTextCtrl_GetFoldLevel, 3145). +-define(wxStyledTextCtrl_GetLastChild, 3146). +-define(wxStyledTextCtrl_GetFoldParent, 3147). +-define(wxStyledTextCtrl_ShowLines, 3148). +-define(wxStyledTextCtrl_HideLines, 3149). +-define(wxStyledTextCtrl_GetLineVisible, 3150). +-define(wxStyledTextCtrl_SetFoldExpanded, 3151). +-define(wxStyledTextCtrl_GetFoldExpanded, 3152). +-define(wxStyledTextCtrl_ToggleFold, 3153). +-define(wxStyledTextCtrl_EnsureVisible, 3154). +-define(wxStyledTextCtrl_SetFoldFlags, 3155). +-define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3156). +-define(wxStyledTextCtrl_SetTabIndents, 3157). +-define(wxStyledTextCtrl_GetTabIndents, 3158). +-define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3159). +-define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3160). +-define(wxStyledTextCtrl_SetMouseDwellTime, 3161). +-define(wxStyledTextCtrl_GetMouseDwellTime, 3162). +-define(wxStyledTextCtrl_WordStartPosition, 3163). +-define(wxStyledTextCtrl_WordEndPosition, 3164). +-define(wxStyledTextCtrl_SetWrapMode, 3165). +-define(wxStyledTextCtrl_GetWrapMode, 3166). +-define(wxStyledTextCtrl_SetWrapVisualFlags, 3167). +-define(wxStyledTextCtrl_GetWrapVisualFlags, 3168). +-define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3169). +-define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3170). +-define(wxStyledTextCtrl_SetWrapStartIndent, 3171). +-define(wxStyledTextCtrl_GetWrapStartIndent, 3172). +-define(wxStyledTextCtrl_SetLayoutCache, 3173). +-define(wxStyledTextCtrl_GetLayoutCache, 3174). +-define(wxStyledTextCtrl_SetScrollWidth, 3175). +-define(wxStyledTextCtrl_GetScrollWidth, 3176). +-define(wxStyledTextCtrl_TextWidth, 3177). +-define(wxStyledTextCtrl_GetEndAtLastLine, 3178). +-define(wxStyledTextCtrl_TextHeight, 3179). +-define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3180). +-define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3181). +-define(wxStyledTextCtrl_AppendText, 3182). +-define(wxStyledTextCtrl_GetTwoPhaseDraw, 3183). +-define(wxStyledTextCtrl_SetTwoPhaseDraw, 3184). +-define(wxStyledTextCtrl_TargetFromSelection, 3185). +-define(wxStyledTextCtrl_LinesJoin, 3186). +-define(wxStyledTextCtrl_LinesSplit, 3187). +-define(wxStyledTextCtrl_SetFoldMarginColour, 3188). +-define(wxStyledTextCtrl_SetFoldMarginHiColour, 3189). +-define(wxStyledTextCtrl_LineDown, 3190). +-define(wxStyledTextCtrl_LineDownExtend, 3191). +-define(wxStyledTextCtrl_LineUp, 3192). +-define(wxStyledTextCtrl_LineUpExtend, 3193). +-define(wxStyledTextCtrl_CharLeft, 3194). +-define(wxStyledTextCtrl_CharLeftExtend, 3195). +-define(wxStyledTextCtrl_CharRight, 3196). +-define(wxStyledTextCtrl_CharRightExtend, 3197). +-define(wxStyledTextCtrl_WordLeft, 3198). +-define(wxStyledTextCtrl_WordLeftExtend, 3199). +-define(wxStyledTextCtrl_WordRight, 3200). +-define(wxStyledTextCtrl_WordRightExtend, 3201). +-define(wxStyledTextCtrl_Home, 3202). +-define(wxStyledTextCtrl_HomeExtend, 3203). +-define(wxStyledTextCtrl_LineEnd, 3204). +-define(wxStyledTextCtrl_LineEndExtend, 3205). +-define(wxStyledTextCtrl_DocumentStart, 3206). +-define(wxStyledTextCtrl_DocumentStartExtend, 3207). +-define(wxStyledTextCtrl_DocumentEnd, 3208). +-define(wxStyledTextCtrl_DocumentEndExtend, 3209). +-define(wxStyledTextCtrl_PageUp, 3210). +-define(wxStyledTextCtrl_PageUpExtend, 3211). +-define(wxStyledTextCtrl_PageDown, 3212). +-define(wxStyledTextCtrl_PageDownExtend, 3213). +-define(wxStyledTextCtrl_EditToggleOvertype, 3214). +-define(wxStyledTextCtrl_Cancel, 3215). +-define(wxStyledTextCtrl_DeleteBack, 3216). +-define(wxStyledTextCtrl_Tab, 3217). +-define(wxStyledTextCtrl_BackTab, 3218). +-define(wxStyledTextCtrl_NewLine, 3219). +-define(wxStyledTextCtrl_FormFeed, 3220). +-define(wxStyledTextCtrl_VCHome, 3221). +-define(wxStyledTextCtrl_VCHomeExtend, 3222). +-define(wxStyledTextCtrl_ZoomIn, 3223). +-define(wxStyledTextCtrl_ZoomOut, 3224). +-define(wxStyledTextCtrl_DelWordLeft, 3225). +-define(wxStyledTextCtrl_DelWordRight, 3226). +-define(wxStyledTextCtrl_LineCut, 3227). +-define(wxStyledTextCtrl_LineDelete, 3228). +-define(wxStyledTextCtrl_LineTranspose, 3229). +-define(wxStyledTextCtrl_LineDuplicate, 3230). +-define(wxStyledTextCtrl_LowerCase, 3231). +-define(wxStyledTextCtrl_UpperCase, 3232). +-define(wxStyledTextCtrl_LineScrollDown, 3233). +-define(wxStyledTextCtrl_LineScrollUp, 3234). +-define(wxStyledTextCtrl_DeleteBackNotLine, 3235). +-define(wxStyledTextCtrl_HomeDisplay, 3236). +-define(wxStyledTextCtrl_HomeDisplayExtend, 3237). +-define(wxStyledTextCtrl_LineEndDisplay, 3238). +-define(wxStyledTextCtrl_LineEndDisplayExtend, 3239). +-define(wxStyledTextCtrl_HomeWrapExtend, 3240). +-define(wxStyledTextCtrl_LineEndWrap, 3241). +-define(wxStyledTextCtrl_LineEndWrapExtend, 3242). +-define(wxStyledTextCtrl_VCHomeWrap, 3243). +-define(wxStyledTextCtrl_VCHomeWrapExtend, 3244). +-define(wxStyledTextCtrl_LineCopy, 3245). +-define(wxStyledTextCtrl_MoveCaretInsideView, 3246). +-define(wxStyledTextCtrl_LineLength, 3247). +-define(wxStyledTextCtrl_BraceHighlight, 3248). +-define(wxStyledTextCtrl_BraceBadLight, 3249). +-define(wxStyledTextCtrl_BraceMatch, 3250). +-define(wxStyledTextCtrl_GetViewEOL, 3251). +-define(wxStyledTextCtrl_SetViewEOL, 3252). +-define(wxStyledTextCtrl_SetModEventMask, 3253). +-define(wxStyledTextCtrl_GetEdgeColumn, 3254). +-define(wxStyledTextCtrl_SetEdgeColumn, 3255). +-define(wxStyledTextCtrl_SetEdgeMode, 3256). +-define(wxStyledTextCtrl_GetEdgeMode, 3257). +-define(wxStyledTextCtrl_GetEdgeColour, 3258). +-define(wxStyledTextCtrl_SetEdgeColour, 3259). +-define(wxStyledTextCtrl_SearchAnchor, 3260). +-define(wxStyledTextCtrl_SearchNext, 3261). +-define(wxStyledTextCtrl_SearchPrev, 3262). +-define(wxStyledTextCtrl_LinesOnScreen, 3263). +-define(wxStyledTextCtrl_UsePopUp, 3264). +-define(wxStyledTextCtrl_SelectionIsRectangle, 3265). +-define(wxStyledTextCtrl_SetZoom, 3266). +-define(wxStyledTextCtrl_GetZoom, 3267). +-define(wxStyledTextCtrl_GetModEventMask, 3268). +-define(wxStyledTextCtrl_SetSTCFocus, 3269). +-define(wxStyledTextCtrl_GetSTCFocus, 3270). +-define(wxStyledTextCtrl_SetStatus, 3271). +-define(wxStyledTextCtrl_GetStatus, 3272). +-define(wxStyledTextCtrl_SetMouseDownCaptures, 3273). +-define(wxStyledTextCtrl_GetMouseDownCaptures, 3274). +-define(wxStyledTextCtrl_SetSTCCursor, 3275). +-define(wxStyledTextCtrl_GetSTCCursor, 3276). +-define(wxStyledTextCtrl_SetControlCharSymbol, 3277). +-define(wxStyledTextCtrl_GetControlCharSymbol, 3278). +-define(wxStyledTextCtrl_WordPartLeft, 3279). +-define(wxStyledTextCtrl_WordPartLeftExtend, 3280). +-define(wxStyledTextCtrl_WordPartRight, 3281). +-define(wxStyledTextCtrl_WordPartRightExtend, 3282). +-define(wxStyledTextCtrl_SetVisiblePolicy, 3283). +-define(wxStyledTextCtrl_DelLineLeft, 3284). +-define(wxStyledTextCtrl_DelLineRight, 3285). +-define(wxStyledTextCtrl_GetXOffset, 3286). +-define(wxStyledTextCtrl_ChooseCaretX, 3287). +-define(wxStyledTextCtrl_SetXCaretPolicy, 3288). +-define(wxStyledTextCtrl_SetYCaretPolicy, 3289). +-define(wxStyledTextCtrl_GetPrintWrapMode, 3290). +-define(wxStyledTextCtrl_SetHotspotActiveForeground, 3291). +-define(wxStyledTextCtrl_SetHotspotActiveBackground, 3292). +-define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3293). +-define(wxStyledTextCtrl_SetHotspotSingleLine, 3294). +-define(wxStyledTextCtrl_ParaDownExtend, 3295). +-define(wxStyledTextCtrl_ParaUp, 3296). +-define(wxStyledTextCtrl_ParaUpExtend, 3297). +-define(wxStyledTextCtrl_PositionBefore, 3298). +-define(wxStyledTextCtrl_PositionAfter, 3299). +-define(wxStyledTextCtrl_CopyRange, 3300). +-define(wxStyledTextCtrl_CopyText, 3301). +-define(wxStyledTextCtrl_SetSelectionMode, 3302). +-define(wxStyledTextCtrl_GetSelectionMode, 3303). +-define(wxStyledTextCtrl_LineDownRectExtend, 3304). +-define(wxStyledTextCtrl_LineUpRectExtend, 3305). +-define(wxStyledTextCtrl_CharLeftRectExtend, 3306). +-define(wxStyledTextCtrl_CharRightRectExtend, 3307). +-define(wxStyledTextCtrl_HomeRectExtend, 3308). +-define(wxStyledTextCtrl_VCHomeRectExtend, 3309). +-define(wxStyledTextCtrl_LineEndRectExtend, 3310). +-define(wxStyledTextCtrl_PageUpRectExtend, 3311). +-define(wxStyledTextCtrl_PageDownRectExtend, 3312). +-define(wxStyledTextCtrl_StutteredPageUp, 3313). +-define(wxStyledTextCtrl_StutteredPageUpExtend, 3314). +-define(wxStyledTextCtrl_StutteredPageDown, 3315). +-define(wxStyledTextCtrl_StutteredPageDownExtend, 3316). +-define(wxStyledTextCtrl_WordLeftEnd, 3317). +-define(wxStyledTextCtrl_WordLeftEndExtend, 3318). +-define(wxStyledTextCtrl_WordRightEnd, 3319). +-define(wxStyledTextCtrl_WordRightEndExtend, 3320). +-define(wxStyledTextCtrl_SetWhitespaceChars, 3321). +-define(wxStyledTextCtrl_SetCharsDefault, 3322). +-define(wxStyledTextCtrl_AutoCompGetCurrent, 3323). +-define(wxStyledTextCtrl_Allocate, 3324). +-define(wxStyledTextCtrl_FindColumn, 3325). +-define(wxStyledTextCtrl_GetCaretSticky, 3326). +-define(wxStyledTextCtrl_SetCaretSticky, 3327). +-define(wxStyledTextCtrl_ToggleCaretSticky, 3328). +-define(wxStyledTextCtrl_SetPasteConvertEndings, 3329). +-define(wxStyledTextCtrl_GetPasteConvertEndings, 3330). +-define(wxStyledTextCtrl_SelectionDuplicate, 3331). +-define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3332). +-define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3333). +-define(wxStyledTextCtrl_StartRecord, 3334). +-define(wxStyledTextCtrl_StopRecord, 3335). +-define(wxStyledTextCtrl_SetLexer, 3336). +-define(wxStyledTextCtrl_GetLexer, 3337). +-define(wxStyledTextCtrl_Colourise, 3338). +-define(wxStyledTextCtrl_SetProperty, 3339). +-define(wxStyledTextCtrl_SetKeyWords, 3340). +-define(wxStyledTextCtrl_SetLexerLanguage, 3341). +-define(wxStyledTextCtrl_GetProperty, 3342). +-define(wxStyledTextCtrl_GetStyleBitsNeeded, 3343). +-define(wxStyledTextCtrl_GetCurrentLine, 3344). +-define(wxStyledTextCtrl_StyleSetSpec, 3345). +-define(wxStyledTextCtrl_StyleSetFont, 3346). +-define(wxStyledTextCtrl_StyleSetFontAttr, 3347). +-define(wxStyledTextCtrl_StyleSetCharacterSet, 3348). +-define(wxStyledTextCtrl_StyleSetFontEncoding, 3349). +-define(wxStyledTextCtrl_CmdKeyExecute, 3350). +-define(wxStyledTextCtrl_SetMargins, 3351). +-define(wxStyledTextCtrl_GetSelection, 3352). +-define(wxStyledTextCtrl_PointFromPosition, 3353). +-define(wxStyledTextCtrl_ScrollToLine, 3354). +-define(wxStyledTextCtrl_ScrollToColumn, 3355). +-define(wxStyledTextCtrl_SetVScrollBar, 3356). +-define(wxStyledTextCtrl_SetHScrollBar, 3357). +-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3358). +-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3359). +-define(wxStyledTextCtrl_SaveFile, 3360). +-define(wxStyledTextCtrl_LoadFile, 3361). +-define(wxStyledTextCtrl_DoDragOver, 3362). +-define(wxStyledTextCtrl_DoDropText, 3363). +-define(wxStyledTextCtrl_GetUseAntiAliasing, 3364). +-define(wxStyledTextCtrl_AddTextRaw, 3365). +-define(wxStyledTextCtrl_InsertTextRaw, 3366). +-define(wxStyledTextCtrl_GetCurLineRaw, 3367). +-define(wxStyledTextCtrl_GetLineRaw, 3368). +-define(wxStyledTextCtrl_GetSelectedTextRaw, 3369). +-define(wxStyledTextCtrl_GetTextRangeRaw, 3370). +-define(wxStyledTextCtrl_SetTextRaw, 3371). +-define(wxStyledTextCtrl_GetTextRaw, 3372). +-define(wxStyledTextCtrl_AppendTextRaw, 3373). +-define(wxArtProvider_GetBitmap, 3374). +-define(wxArtProvider_GetIcon, 3375). +-define(wxTreeEvent_GetKeyCode, 3376). +-define(wxTreeEvent_GetItem, 3377). +-define(wxTreeEvent_GetKeyEvent, 3378). +-define(wxTreeEvent_GetLabel, 3379). +-define(wxTreeEvent_GetOldItem, 3380). +-define(wxTreeEvent_GetPoint, 3381). +-define(wxTreeEvent_IsEditCancelled, 3382). +-define(wxTreeEvent_SetToolTip, 3383). +-define(wxBookCtrlEvent_GetOldSelection, 3384). +-define(wxBookCtrlEvent_GetSelection, 3385). +-define(wxBookCtrlEvent_SetOldSelection, 3386). +-define(wxBookCtrlEvent_SetSelection, 3387). +-define(wxFileDataObject_new, 3388). +-define(wxFileDataObject_AddFile, 3389). +-define(wxFileDataObject_GetFilenames, 3390). +-define(wxFileDataObject_destroy, 3391). +-define(wxTextDataObject_new, 3392). +-define(wxTextDataObject_GetTextLength, 3393). +-define(wxTextDataObject_GetText, 3394). +-define(wxTextDataObject_SetText, 3395). +-define(wxTextDataObject_destroy, 3396). +-define(wxBitmapDataObject_new_1_1, 3397). +-define(wxBitmapDataObject_new_1_0, 3398). +-define(wxBitmapDataObject_GetBitmap, 3399). +-define(wxBitmapDataObject_SetBitmap, 3400). +-define(wxBitmapDataObject_destroy, 3401). +-define(wxClipboard_new, 3402). +-define(wxClipboard_destruct, 3403). +-define(wxClipboard_AddData, 3404). +-define(wxClipboard_Clear, 3405). +-define(wxClipboard_Close, 3406). +-define(wxClipboard_Flush, 3407). +-define(wxClipboard_GetData, 3408). +-define(wxClipboard_IsOpened, 3409). +-define(wxClipboard_Open, 3410). +-define(wxClipboard_SetData, 3411). +-define(wxClipboard_UsePrimarySelection, 3412). +-define(wxClipboard_IsSupported, 3413). +-define(wxClipboard_Get, 3414). +-define(wxSpinEvent_GetPosition, 3415). +-define(wxSpinEvent_SetPosition, 3416). +-define(wxSplitterWindow_new_0, 3417). +-define(wxSplitterWindow_new_2, 3418). +-define(wxSplitterWindow_destruct, 3419). +-define(wxSplitterWindow_Create, 3420). +-define(wxSplitterWindow_GetMinimumPaneSize, 3421). +-define(wxSplitterWindow_GetSashGravity, 3422). +-define(wxSplitterWindow_GetSashPosition, 3423). +-define(wxSplitterWindow_GetSplitMode, 3424). +-define(wxSplitterWindow_GetWindow1, 3425). +-define(wxSplitterWindow_GetWindow2, 3426). +-define(wxSplitterWindow_Initialize, 3427). +-define(wxSplitterWindow_IsSplit, 3428). +-define(wxSplitterWindow_ReplaceWindow, 3429). +-define(wxSplitterWindow_SetSashGravity, 3430). +-define(wxSplitterWindow_SetSashPosition, 3431). +-define(wxSplitterWindow_SetMinimumPaneSize, 3432). +-define(wxSplitterWindow_SetSplitMode, 3433). +-define(wxSplitterWindow_SplitHorizontally, 3434). +-define(wxSplitterWindow_SplitVertically, 3435). +-define(wxSplitterWindow_Unsplit, 3436). +-define(wxSplitterWindow_UpdateSize, 3437). +-define(wxSplitterEvent_GetSashPosition, 3438). +-define(wxSplitterEvent_GetX, 3439). +-define(wxSplitterEvent_GetY, 3440). +-define(wxSplitterEvent_GetWindowBeingRemoved, 3441). +-define(wxSplitterEvent_SetSashPosition, 3442). +-define(wxHtmlWindow_new_0, 3443). +-define(wxHtmlWindow_new_2, 3444). +-define(wxHtmlWindow_AppendToPage, 3445). +-define(wxHtmlWindow_GetOpenedAnchor, 3446). +-define(wxHtmlWindow_GetOpenedPage, 3447). +-define(wxHtmlWindow_GetOpenedPageTitle, 3448). +-define(wxHtmlWindow_GetRelatedFrame, 3449). +-define(wxHtmlWindow_HistoryBack, 3450). +-define(wxHtmlWindow_HistoryCanBack, 3451). +-define(wxHtmlWindow_HistoryCanForward, 3452). +-define(wxHtmlWindow_HistoryClear, 3453). +-define(wxHtmlWindow_HistoryForward, 3454). +-define(wxHtmlWindow_LoadFile, 3455). +-define(wxHtmlWindow_LoadPage, 3456). +-define(wxHtmlWindow_SelectAll, 3457). +-define(wxHtmlWindow_SelectionToText, 3458). +-define(wxHtmlWindow_SelectLine, 3459). +-define(wxHtmlWindow_SelectWord, 3460). +-define(wxHtmlWindow_SetBorders, 3461). +-define(wxHtmlWindow_SetFonts, 3462). +-define(wxHtmlWindow_SetPage, 3463). +-define(wxHtmlWindow_SetRelatedFrame, 3464). +-define(wxHtmlWindow_SetRelatedStatusBar_1, 3465). +-define(wxHtmlWindow_SetRelatedStatusBar_2, 3466). +-define(wxHtmlWindow_ToText, 3467). +-define(wxHtmlWindow_destroy, 3468). +-define(wxHtmlLinkEvent_GetLinkInfo, 3469). +-define(wxSystemSettings_GetColour, 3470). +-define(wxSystemSettings_GetFont, 3471). +-define(wxSystemSettings_GetMetric, 3472). +-define(wxSystemSettings_GetScreenType, 3473). +-define(wxSystemOptions_GetOption, 3474). +-define(wxSystemOptions_GetOptionInt, 3475). +-define(wxSystemOptions_HasOption, 3476). +-define(wxSystemOptions_IsFalse, 3477). +-define(wxSystemOptions_SetOption_2_1, 3478). +-define(wxSystemOptions_SetOption_2_0, 3479). +-define(wxAuiNotebookEvent_SetSelection, 3480). +-define(wxAuiNotebookEvent_GetSelection, 3481). +-define(wxAuiNotebookEvent_SetOldSelection, 3482). +-define(wxAuiNotebookEvent_GetOldSelection, 3483). +-define(wxAuiNotebookEvent_SetDragSource, 3484). +-define(wxAuiNotebookEvent_GetDragSource, 3485). +-define(wxAuiManagerEvent_SetManager, 3486). +-define(wxAuiManagerEvent_GetManager, 3487). +-define(wxAuiManagerEvent_SetPane, 3488). +-define(wxAuiManagerEvent_GetPane, 3489). +-define(wxAuiManagerEvent_SetButton, 3490). +-define(wxAuiManagerEvent_GetButton, 3491). +-define(wxAuiManagerEvent_SetDC, 3492). +-define(wxAuiManagerEvent_GetDC, 3493). +-define(wxAuiManagerEvent_Veto, 3494). +-define(wxAuiManagerEvent_GetVeto, 3495). +-define(wxAuiManagerEvent_SetCanVeto, 3496). +-define(wxAuiManagerEvent_CanVeto, 3497). +-define(wxLogNull_new, 3498). +-define(wxLogNull_destruct, 3499). +-define(wxTaskBarIcon_new, 3500). +-define(wxTaskBarIcon_destruct, 3501). +-define(wxTaskBarIcon_PopupMenu, 3502). +-define(wxTaskBarIcon_RemoveIcon, 3503). +-define(wxTaskBarIcon_SetIcon, 3504). +-define(wxLocale_new_0, 3505). +-define(wxLocale_new_2_0, 3506). +-define(wxLocale_new_2_1, 3507). +-define(wxLocale_destruct, 3508). +-define(wxLocale_Init_1, 3509). +-define(wxLocale_Init_2, 3510). +-define(wxLocale_AddCatalog_1, 3511). +-define(wxLocale_AddCatalog_2, 3512). +-define(wxLocale_AddCatalog_3, 3513). +-define(wxLocale_AddCatalogLookupPathPrefix, 3514). +-define(wxLocale_GetCanonicalName, 3515). +-define(wxLocale_GetLanguage, 3516). +-define(wxLocale_GetLanguageName, 3517). +-define(wxLocale_GetLocale, 3518). +-define(wxLocale_GetName, 3519). +-define(wxLocale_GetString_2, 3520). +-define(wxLocale_GetString_4, 3521). +-define(wxLocale_GetHeaderValue, 3522). +-define(wxLocale_GetSysName, 3523). +-define(wxLocale_GetSystemEncoding, 3524). +-define(wxLocale_GetSystemEncodingName, 3525). +-define(wxLocale_GetSystemLanguage, 3526). +-define(wxLocale_IsLoaded, 3527). +-define(wxLocale_IsOk, 3528). +-define(wxActivateEvent_GetActive, 3529). +-define(wxPopupWindow_new_0, 3530). +-define(wxPopupWindow_new_2, 3531). +-define(wxPopupWindow_Create, 3532). +-define(wxPopupWindow_Position, 3533). +-define(wxPopupWindow_destroy, 3534). +-define(wxPopupTransientWindow_new_0, 3535). +-define(wxPopupTransientWindow_new_2, 3536). +-define(wxPopupTransientWindow_Popup, 3537). +-define(wxPopupTransientWindow_Dismiss, 3538). +-define(wxPopupTransientWindow_destroy, 3539). +-define(wxOverlay_new, 3540). +-define(wxOverlay_destruct, 3541). +-define(wxOverlay_Reset, 3542). +-define(wxDCOverlay_new_6, 3543). +-define(wxDCOverlay_new_2, 3544). +-define(wxDCOverlay_destruct, 3545). +-define(wxDCOverlay_Clear, 3546). +-define(wxDropFilesEvent_GetPosition, 3547). +-define(wxDropFilesEvent_GetNumberOfFiles, 3548). +-define(wxDropFilesEvent_GetFiles, 3549). +-define(wxDisplay_new_0, 3550). +-define(wxDisplay_new_1_0, 3551). +-define(wxDisplay_new_1_1, 3552). +-define(wxDisplay_destruct, 3553). +-define(wxDisplay_IsOk, 3554). +-define(wxDisplay_GetClientArea, 3555). +-define(wxDisplay_GetGeometry, 3556). +-define(wxDisplay_GetName, 3557). +-define(wxDisplay_IsPrimary, 3558). +-define(wxDisplay_GetCount, 3559). +-define(wxDisplay_GetFromPoint, 3560). +-define(wxDisplay_GetFromWindow, 3561). +-define(wxDisplay_GetPPI, 3562). +-define(wxGCDC_new_1, 3563). +-define(wxGCDC_new_0, 3566). +-define(wxGCDC_destruct, 3567). +-define(wxGCDC_GetGraphicsContext, 3568). +-define(wxGCDC_SetGraphicsContext, 3569). +-define(wxNotificationMessage_new_0, 3570). +-define(wxNotificationMessage_new_2, 3571). +-define(wxNotificationMessage_destruct, 3572). +-define(wxNotificationMessage_AddAction, 3573). +-define(wxNotificationMessage_Close, 3574). +-define(wxNotificationMessage_SetFlags, 3575). +-define(wxNotificationMessage_SetIcon, 3576). +-define(wxNotificationMessage_SetMessage, 3577). +-define(wxNotificationMessage_SetParent, 3578). +-define(wxNotificationMessage_SetTitle, 3579). +-define(wxNotificationMessage_Show, 3580). +-define(wxNotificationMessage_UseTaskBarIcon, 3581). +-define(wxNotificationMessage_MSWUseToasts, 3582). +-define(wxWebView_New, 3584). +-define(wxWebView_GetCurrentTitle, 3585). +-define(wxWebView_GetCurrentURL, 3586). +-define(wxWebView_GetPageSource, 3587). +-define(wxWebView_GetPageText, 3588). +-define(wxWebView_IsBusy, 3589). +-define(wxWebView_IsEditable, 3590). +-define(wxWebView_LoadURL, 3591). +-define(wxWebView_Print, 3592). +-define(wxWebView_Reload, 3593). +-define(wxWebView_RunScript, 3594). +-define(wxWebView_SetEditable, 3595). +-define(wxWebView_SetPage, 3596). +-define(wxWebView_Stop, 3597). +-define(wxWebView_CanCopy, 3598). +-define(wxWebView_CanCut, 3599). +-define(wxWebView_CanPaste, 3600). +-define(wxWebView_Copy, 3601). +-define(wxWebView_Cut, 3602). +-define(wxWebView_Paste, 3603). +-define(wxWebView_EnableContextMenu, 3604). +-define(wxWebView_IsContextMenuEnabled, 3605). +-define(wxWebView_CanGoBack, 3606). +-define(wxWebView_CanGoForward, 3607). +-define(wxWebView_ClearHistory, 3608). +-define(wxWebView_EnableHistory, 3609). +-define(wxWebView_GoBack, 3610). +-define(wxWebView_GoForward, 3611). +-define(wxWebView_ClearSelection, 3612). +-define(wxWebView_DeleteSelection, 3613). +-define(wxWebView_GetSelectedSource, 3614). +-define(wxWebView_GetSelectedText, 3615). +-define(wxWebView_HasSelection, 3616). +-define(wxWebView_SelectAll, 3617). +-define(wxWebView_CanRedo, 3618). +-define(wxWebView_CanUndo, 3619). +-define(wxWebView_Redo, 3620). +-define(wxWebView_Undo, 3621). +-define(wxWebView_Find, 3622). +-define(wxWebView_CanSetZoomType, 3623). +-define(wxWebView_GetZoom, 3624). +-define(wxWebView_GetZoomType, 3625). +-define(wxWebView_SetZoom, 3626). +-define(wxWebView_SetZoomType, 3627). +-define(wxWebView_GetZoomFactor, 3628). +-define(wxWebView_SetZoomFactor, 3629). +-define(wxWebView_IsBackendAvailable, 3630). +-define(wxWebViewEvent_GetString, 3631). +-define(wxWebViewEvent_GetInt, 3632). +-define(wxWebViewEvent_GetTarget, 3633). +-define(wxWebViewEvent_GetURL, 3634). diff --git a/lib/wx/src/wx.app.src b/lib/wx/src/wx.app.src index 92984f13b556..8b6298fb687f 100644 --- a/lib/wx/src/wx.app.src +++ b/lib/wx/src/wx.app.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2023. 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. @@ -35,5 +35,5 @@ {registered, []}, {applications, [stdlib, kernel]}, {env, []}, - {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]} + {runtime_dependencies, ["stdlib-5.0","kernel-8.0","erts-12.0"]} ]}. diff --git a/lib/wx/src/wx.erl b/lib/wx/src/wx.erl index b04d39de8a01..22fcf1f57b21 100644 --- a/lib/wx/src/wx.erl +++ b/lib/wx/src/wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -149,14 +149,14 @@ set_env(#wx_env{sv=Pid} = Env) -> %% all MacOSX specific events corresponding to MacNewFile() and friends %% from wxWidgets wxApp https://docs.wxwidgets.org/trunk/classwx_app.html %% -%% * `{file_new, ""}` -%% * `{file_open, Filename}` -%% * `{file_print, Filename}` -%% * `{url_open, Url}` +%% * `{new_file, ""}` +%% * `{open_file, Filename}` +%% * `{print_file, Filename}` +%% * `{open_url, Url}` %% * `{reopen_app, ""}` %% %% The call always returns ok but will have sent any already received -%% events to the calling process. +%% events to the calling process. -spec subscribe_events() -> 'ok'. subscribe_events() -> gen_server:call(wxe_master, subscribe_msgs, infinity). diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl index 81d188b26a11..1a2d49faca1f 100644 --- a/lib/wx/src/wx_object.erl +++ b/lib/wx/src/wx_object.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2017. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -235,7 +235,7 @@ start_link(Name, Mod, Args, Options) -> gen_response(gen:start(?MODULE, link, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])). gen_response({ok, Pid}) -> - receive {ack, Pid, Ref = #wx_ref{}} -> Ref end; + receive {started, Pid, Ref = #wx_ref{}} -> Ref end; gen_response(Reply) -> Reply. @@ -407,30 +407,23 @@ init_it(Starter, Parent, Name, Mod, Args, [WxEnv|Options]) -> {#wx_ref{} = Ref, State, Timeout} -> init_it2(Ref, Starter, Parent, Name, State, Mod, Timeout, Debug); {stop, Reason} -> - proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); ignore -> - proc_lib:init_ack(Starter, ignore), - exit(normal); + proc_lib:init_fail(Starter, ignore, {exit, normal}); {'EXIT', Reason} -> - proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); Else -> - Error = {bad_return_value, Else}, - proc_lib:init_ack(Starter, {error, Error}), - exit(Error) + exit({bad_return_value, Else}) end. %% @hidden init_it2(Ref, Starter, Parent, Name, State, Mod, Timeout, Debug) -> ok = wxe_util:register_pid(Ref), case ?CLASS_T(Ref#wx_ref.type, wxWindow) of false -> - Reason = {Ref, "not a wxWindow subclass"}, - proc_lib:init_ack(Starter, {error, Reason}), - exit(Reason); + exit({Ref, "not a wxWindow subclass"}); true -> proc_lib:init_ack(Starter, {ok, self()}), - proc_lib:init_ack(Starter, Ref#wx_ref{state=self()}), + Starter ! {started, self(), Ref#wx_ref{state=self()}}, loop(Parent, Name, State, Mod, Timeout, Debug) end. diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl index c3496a0026c6..f0bb1e64e7aa 100644 --- a/lib/wx/src/wxe_master.erl +++ b/lib/wx/src/wxe_master.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -74,14 +74,15 @@ init_env(SilentStart) -> %%-------------------------------------------------------------------- -%% Initalizes the opengl library +%% Initializes the opengl library %%-------------------------------------------------------------------- init_opengl() -> case get(wx_init_opengl) of true -> {ok, "already initialized"}; _ -> - Opaque = gl:lookup_func(), - {ok, wxe_util:init_opengl(Opaque)} + Opaque = gl:lookup_func(functions), + Debug = gl:lookup_func(function_names), + {ok, wxe_util:init_opengl(Opaque, Debug)} end. %%-------------------------------------------------------------------- @@ -123,7 +124,8 @@ init([SilentStart]) -> wxe_util:setup_consts(), {ok, #state{}} catch _:Error:ST -> - io:format("Error: ~p @ ~p~n",[Error, ST]), + Str = io_lib:format("Error: ~p @ ~p~n",[Error, ST]), + logger:log(error, Str, #{domain => [wx]}), error({error, {Error, "Could not initiate graphics"}}) end. @@ -167,13 +169,13 @@ handle_cast(_Msg, State) -> %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info({wxe_driver, error, Msg}, State) -> - error_logger:error_report([{wx, error}, {message, lists:flatten(Msg)}]), + logger:log(error, "wx: ~s", [Msg], #{domain => [wx]}), {noreply, State}; handle_info({wxe_driver, internal_error, Msg}, State) -> - error_logger:error_report([{wx, internal_error}, {message, lists:flatten(Msg)}]), + logger:log(error, "wx: ~s", [Msg], #{domain => [wx]}), {noreply, State}; handle_info({wxe_driver, debug, Msg}, State) -> - io:format("WX DBG: ~s~n", [Msg]), + logger:log(notice, "wx: ~s", [Msg], #{domain => [wx]}), {noreply, State}; handle_info({wxe_driver, Cmd, File}, State = #state{subscribers=Subs, msgs=Msgs}) when Cmd =:= open_file; Cmd =:= new_file; Cmd =:= print_file; @@ -183,8 +185,8 @@ handle_info({wxe_driver, Cmd, File}, State = #state{subscribers=Subs, msgs=Msgs} handle_info({'DOWN', _Ref, process, Pid, _Info}, State) -> Subs = State#state.subscribers -- [Pid], {noreply, State#state{subscribers=Subs}}; -handle_info(_Info, State) -> - io:format("Unknown message ~p sent to ~p~n",[_Info, ?MODULE]), +handle_info(Info, State) -> + logger:log(notice, "wx: Unexpected Msg: ~p", [Info], #{domain => [wx], line=>?LINE, file=>?MODULE_STRING}), {noreply, State}. %%-------------------------------------------------------------------- diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl index 4cef311bb3ca..4d3de165fdff 100644 --- a/lib/wx/src/wxe_server.erl +++ b/lib/wx/src/wxe_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -41,7 +41,7 @@ %%-record(event, {object, callback, cb_handler}). -define(APPLICATION, wxe). --define(log(S,A), log(?MODULE,?LINE,S,A)). +-define(log(S,A), log(?MODULE_STRING,?LINE,S,A)). -include("wxe.hrl"). -include("../include/wx.hrl"). @@ -210,7 +210,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- log(Mod,Line,Str,Args) -> - error_logger:format("~p:~p: " ++ Str, [Mod,Line|Args]). + logger:log(error, Str, Args, #{domain => [wx], file=>Mod, line=>Line}). handle_connect(Object, #evh{handler=undefined, cb=Callback} = EvData0, From, State0) -> diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl index 1e72f39057e2..217e7118ff6c 100644 --- a/lib/wx/src/wxe_util.erl +++ b/lib/wx/src/wxe_util.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -37,9 +37,16 @@ queue_cmd/11,queue_cmd/12,queue_cmd/13,queue_cmd/14,queue_cmd/15, make_env/0, delete_env/1, get_consts/0, debug_ping/0, debug_driver/1, - init_opengl/1 + init_opengl/2 ]). +-nifs([queue_cmd/1,queue_cmd/2,queue_cmd/3,queue_cmd/4,queue_cmd/5, + queue_cmd/6,queue_cmd/7,queue_cmd/8,queue_cmd/9,queue_cmd/10, + queue_cmd/11,queue_cmd/12,queue_cmd/13,queue_cmd/14,queue_cmd/15, + make_env/0, delete_env/1, debug_driver/1, get_consts_impl/0, + init_opengl/2 + ]). + -export([priv_dir/2, opt_error_log/3, init_nif/1]). -include("wxe.hrl"). @@ -78,7 +85,7 @@ get_consts() -> get_consts_impl(), rec(?WXE_GET_CONSTS). -init_opengl(_) -> ?NIF_ERROR. +init_opengl(_,_) -> ?NIF_ERROR. get_consts_impl() -> ?NIF_ERROR. debug_ping() -> queue_cmd(?WXE_DEBUG_PING). @@ -190,6 +197,6 @@ strip([H|R], Src) -> [H| strip(R, Src)]. opt_error_log(false, Format, Args) -> - error_logger:format(Format, Args); + logger:log(error, Format, Args, #{domain => [wx]}); opt_error_log(true, _Format, _Args) -> ok. diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index fc88558a466f..170738aa3083 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -607,7 +607,7 @@ check_events([{sync_event, #wx{event=#wxPaint{}}, Obj}|Rest], Async, Sync) -> ?mt(wxPaintEvent, Obj), check_events(Rest, Async, Sync+1); check_events([], Async, Sync) -> - case Async > 0 of %% Test sync explictly + case Async > 0 of %% Test sync explicitly true -> ok; false -> {Async, Sync} end. diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index c21a916133d2..5275defce682 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2022. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -87,7 +87,7 @@ calendarCtrl(Config) -> true -> ?log("DateAttr is null~n",[]); false -> - ?log("DateAttr is useable~n",[]), + ?log("DateAttr is usable~n",[]), DateAttr = ?mt(wxCalendarDateAttr, wxCalendarDateAttr:new()), wxCalendarDateAttr:setBackgroundColour(DateAttr, {0,243,0}), wxCalendarCtrl:setAttr(Cal, Day, DateAttr), @@ -244,6 +244,8 @@ clipboard(Config) -> wxTextCtrl:connect(Ctrl, command_text_paste, [{skip, true}]), wxWindow:show(Frame), + BlockWxDialogs = wxLogNull:new(), + CB = ?mt(wxClipboard, wxClipboard:get()), wxClipboard:usePrimarySelection(CB), ?m(false, wx:is_null(CB)), @@ -271,7 +273,10 @@ clipboard(Config) -> Paste = ?mt(wxTextDataObject, wxTextDataObject:new([{text,"From Erlang"}])), case wxClipboard:addData(CB,Paste) of true -> - ?log("Put text on clipboard~n", []); + ?log("Put text on clipboard~n", []), + ?log("Flushing ~n",[]), + wxClipboard:flush(CB), + ?log("Stopping ~n",[]); false -> ?log("Couldn't copy data to clipboard~n",[]) end, @@ -279,9 +284,7 @@ clipboard(Config) -> false -> ?log("Clipboard open failed~n",[]) end, - ?log("Flushing ~n",[]), - wxClipboard:flush(CB), - ?log("Stopping ~n",[]), + wxLogNull:destroy(BlockWxDialogs), wx_test_lib:wx_destroy(Frame,Config). diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl index 28c5b7038370..fb3e5ba5985b 100644 --- a/lib/wx/test/wx_opengl_SUITE.erl +++ b/lib/wx/test/wx_opengl_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2021. All Rights Reserved. +%% Copyright Ericsson AB 2008-2023. 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. @@ -27,7 +27,7 @@ init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). --export([canvas/1, glu_tesselation/1]). +-export([canvas/1, glu_tesselation/1, debugMessage/1]). -include("wx_test_lib.hrl"). -include_lib("wx/include/gl.hrl"). @@ -55,7 +55,7 @@ end_per_testcase(Func,Config) -> suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> - [canvas, glu_tesselation]. + [canvas, glu_tesselation, debugMessage]. groups() -> []. @@ -88,7 +88,7 @@ end_per_group(_GroupName, Config) -> {{7,8,3,2},{0.0,-1.0,0.0}}]). -%% Test we can create a glCanvas and that functions are loaded dynamicly +%% Test we can create a glCanvas and that functions are loaded dynamically canvas(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); canvas(Config) -> WX = ?mr(wx_ref, wx:new()), @@ -101,15 +101,8 @@ canvas(Config) -> %% ?WX_GL_CORE_PROFILE, ?WX_GL_DEPTH_SIZE,24,0]}], Canvas = ?mt(wxGLCanvas, wxGLCanvas:new(Frame, [{style,?wxFULL_REPAINT_ON_RESIZE}|Attrs])), - SetContext = - try %% 3.0 API - Context = wxGLContext:new(Canvas), - fun() -> ?m(true, wxGLCanvas:setCurrent(Canvas, Context)) end - catch _:Reason:ST -> %% 2.8 API - io:format("Using old api: ~p~n ~p~n",[Reason, ST]), - ?m(false, wx:is_null(wxGLCanvas:getContext(Canvas))), - fun() -> ?m(ok, wxGLCanvas:setCurrent(Canvas)) end - end, + Context = wxGLContext:new(Canvas), + SetContext = fun() -> ?m(true, wxGLCanvas:setCurrent(Canvas, Context)) end, wxFrame:connect(Frame, show), ?m(true, wxWindow:show(Frame)), @@ -241,14 +234,8 @@ glu_tesselation(Config) -> after 1000 -> exit(show_timeout) end, - try %% 3.0 API - Context = wxGLContext:new(Canvas), - wxGLCanvas:setCurrent(Canvas, Context) - catch _:Reason:ST -> %% 2.8 API - io:format("Using old api: ~p~n ~p~n",[Reason, ST]), - ?m(false, wx:is_null(wxGLCanvas:getContext(Canvas))), - ?m(ok, wxGLCanvas:setCurrent(Canvas)) - end, + Context = wxGLContext:new(Canvas), + wxGLCanvas:setCurrent(Canvas, Context), Simple = ?m({_,_}, glu:tesselate({0.0,0.0,1.0}, [{-1.0,0.0,0.0},{1.0,0.0,0.0},{0.0,1.0,0.0}])), io:format("Simple ~p~n",[Simple]), @@ -268,4 +255,50 @@ glu_tesselation(Config) -> wx_test_lib:wx_destroy(Frame, Config). - +debugMessage(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); +debugMessage(Config) -> + WX = ?mr(wx_ref, wx:new()), + Frame = wxFrame:new(WX,1,"Hello 3D-World",[]), + case {?wxMAJOR_VERSION, ?wxMINOR_VERSION} of + {WxMajor,WxMinor} when WxMajor >= 3, WxMinor >= 2 -> + Attrs = [{attribList, [?WX_GL_RGBA,?WX_GL_DOUBLEBUFFER,?WX_GL_DEBUG,0]}], + Canvas = ?mt(wxGLCanvas, wxGLCanvas:new(Frame, Attrs)), + wxFrame:connect(Frame, show), + ?m(true, wxWindow:show(Frame)), + + receive #wx{event=#wxShow{}} -> ok + after 1000 -> exit(show_timeout) + end, + + Context = wxGLContext:new(Canvas), + wxGLCanvas:setCurrent(Canvas, Context), + + case {gl:getIntegerv(?GL_MAJOR_VERSION),gl:getIntegerv(?GL_MINOR_VERSION)} of + {[Major|_], [Minor|_]} when Major >= 4, Minor >= 3 -> + io:format("~nVersion: ~p~n", [{Major,Minor}]), + ByteCount = 5000, + Count = 10, + %% Before any log insertion: + A = gl:getDebugMessageLog(Count, ByteCount), + io:format( "A = ~p~n", [ A ] ), + + Msg1 = "Hello!", + gl:debugMessageInsert(?GL_DEBUG_SOURCE_APPLICATION, ?GL_DEBUG_TYPE_ERROR, + 10, ?GL_DEBUG_SEVERITY_HIGH, Msg1), + Msg2 = "Goodbye...", + gl:debugMessageInsert(?GL_DEBUG_SOURCE_APPLICATION, ?GL_DEBUG_TYPE_ERROR, + 11, ?GL_DEBUG_SEVERITY_HIGH, Msg2), + + B = gl:getDebugMessageLog(Count, ByteCount), + io:format("B = ~p~n", [B]), + + C = gl:getDebugMessageLog(Count, ByteCount), + io:format("C = ~p~n", [C]); + Versions -> + io:format("Not supported version: ~p~n", [Versions]) + end; + _ -> ok + end, + wx_test_lib:wx_destroy(Frame, Config). + + diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl index a87f4a83b132..b60b8b81f740 100644 --- a/lib/wx/test/wx_xtra_SUITE.erl +++ b/lib/wx/test/wx_xtra_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2022. 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. @@ -68,7 +68,7 @@ end_per_group(_GroupName, Config) -> %% before wx:destroy is called. destroy_app(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); destroy_app(_Config) -> - %% This is timing releated but we test a couple of times + %% This is timing related but we test a couple of times wx_test_lib:flush(), ?m(ok, destroy_app_test(15)). @@ -102,7 +102,7 @@ destroy_app2(_Config) -> ok. -%% This should work, and does but not when run automaticly on windows +%% This should work, and does but not when run automatically on windows %% for some strange reason (it just hangs), run it last. app_dies(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); app_dies(_Config) -> @@ -160,7 +160,7 @@ oops(Die, Line) when (Die =:= last) orelse (Die =< Line) -> oops(_,_) -> ok. -%% This have happend often enough that I have special code to handle +%% This have happened often enough that I have special code to handle %% this user error (i.e. using the a window twice in an sizer). multiple_add_in_sizer(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo); multiple_add_in_sizer(Config) -> diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk index 51279f250b6d..49636f859be2 100644 --- a/lib/wx/vsn.mk +++ b/lib/wx/vsn.mk @@ -1 +1 @@ -WX_VSN = 2.1.4 +WX_VSN = 2.3.1 diff --git a/lib/xmerl/doc/examples/test_html.erl b/lib/xmerl/doc/examples/test_html.erl index cb8088833c7f..4fe3fe42b43d 100644 --- a/lib/xmerl/doc/examples/test_html.erl +++ b/lib/xmerl/doc/examples/test_html.erl @@ -134,14 +134,14 @@ col(Data, Attrs, [{row,_}, {table,_} | _], E) -> ["", nbsp_if_empty(Data), "\n"]. -tuple_list(List, Attrs, Parents, E) -> +tuple_list(List, Attrs, _Parents, _E) -> Elems = case find_attribute(elements, Attrs) of {value, Es} -> Es; false -> case List of [H|_] -> - lists:seq(1,size(H)); + lists:seq(1,tuple_size(H)); [] -> [] end diff --git a/lib/xmerl/doc/examples/xml/xmerl.xml b/lib/xmerl/doc/examples/xml/xmerl.xml index f02282dbeff9..983a0bfde1f3 100644 --- a/lib/xmerl/doc/examples/xml/xmerl.xml +++ b/lib/xmerl/doc/examples/xml/xmerl.xml @@ -127,7 +127,7 @@ xmerl_scan:file(Filename [ , Options ]) -> #xmlElement{}. e.g. xmerl_eventp.erl) is for customization functions to share one of the local states (in xmerl_eventp.erl, the - continuation function and the fetch function both acces the + continuation function and the fetch function both access the cont_state.) Functions to access user state: @@ -357,7 +357,7 @@ Occurrence ::= '*' | '?' | '+' The accumulator function is called to accumulate the contents of an entity.When parsing very large files, it may - not be desireable to do so.In this case, an acc function can + not be desirable to do so.In this case, an acc function can be provided that simply doesn't accumulate. Note that it is possible to even modify the parsed diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index 2e1b7522b3ec..d15f5566aa52 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -4,7 +4,7 @@
    - 20042021 + 20042023 Ericsson AB. All Rights Reserved. @@ -32,6 +32,150 @@

    This document describes the changes made to the Xmerl application.

    +
    Xmerl 1.3.31.1 + +
    Fixed Bugs and Malfunctions + + +

    New options to xmerl_scan and + xmerl_sax_parser so one can limit the behaviour of + the parsers to avoid some XML security issues.

    + xmerl_scan gets one new option:

    + {allow_entities, Boolean} Gives the + possibility to disallow entities by setting this option + to false (true is default)

    + xmerl_sax_parser gets the following options:

    + disallow_entities Don't + allow entities in document + {entity_recurse_limit, N} Set a + limit on entity recursion depth (default is 3) + {external_entities, AllowedType} + Specify which types of external entities that are + allowed, this also affect external DTD's. The types are + all(default), file and none + {fail_undeclared_ref, Boolean} + Sets the behavior for undeclared references due to + an external file is not parsed (true is + default)

    The old option + skip_external_dtd is still valid and the same as + {external_entities, none} and + {fail_undeclared_ref, false} but just affects + DTD's and not other external references.

    +

    + Own Id: OTP-18595 Aux Id: ERIERL-944

    +
    +
    +
    + +
    + +
    Xmerl 1.3.32 + +
    Fixed Bugs and Malfunctions + + +

    New options to xmerl_scan and + xmerl_sax_parser so one can limit the behaviour of + the parsers to avoid some XML security issues.

    + xmerl_scan gets one new option:

    + {allow_entities, Boolean} Gives + the possibility to disallow entities by setting this + option to false (true is default) +

    xmerl_sax_parser gets the following + options:

    + disallow_entities Don't allow + entities in document + {entity_recurse_limit, N} Set a + limit on entity recursion depth (default is 3) + {external_entities, AllowedType} + Specify which types of external entities that are + allowed, this also affect external DTD's. The types are + all(default), file and none + {fail_undeclared_ref, Boolean} + Sets the behavior for undeclared references due to + an external file is not parsed (true is + default)

    The old option + skip_external_dtd is still valid and the same as + {external_entities, none} and + {fail_undeclared_ref, false} but just affects + DTD's and not other external references.

    +

    + Own Id: OTP-18595 Aux Id: ERIERL-944

    +
    +
    +
    + +
    + +
    Xmerl 1.3.31 + +
    Improvements and New Features + + +

    + Replace size/1 with either tuple_size/1 or byte_size/1

    +

    + The size/1 BIF is not optimized by the JIT, and + its use can result in worse types for Dialyzer.

    +

    + When one knows that the value being tested must be a + tuple, tuple_size/1 should always be preferred.

    +

    + When one knows that the value being tested must be a + binary, byte_size/1 should be preferred. However, + byte_size/1 also accepts a bitstring (rounding up + size to a whole number of bytes), so one must make sure + that the call to byte_size/ is preceded by a call + to is_binary/1 to ensure that bitstrings are + rejected. Note that the compiler removes redundant calls + to is_binary/1, so if one is not sure whether + previous code had made sure that the argument is a + binary, it does not harm to add an is_binary/1 + test immediately before the call to byte_size/1.

    +

    + Own Id: OTP-18432 Aux Id: + GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

    +
    +
    +
    + +
    + +
    Xmerl 1.3.30 + +
    Improvements and New Features + + +

    There is a new configure option, + --enable-deterministic-build, which will apply the + deterministic compiler option when building + Erlang/OTP. The deterministic option has been + improved to eliminate more sources of non-determinism in + several applications.

    +

    + Own Id: OTP-18165 Aux Id: PR-5965

    +
    +
    +
    + +
    + +
    Xmerl 1.3.29 + +
    Improvements and New Features + + +

    + Fixed misspellings in both documentation, comments and + code (internal data structures).

    +

    + Own Id: OTP-17935 Aux Id: PR-5590

    +
    +
    +
    + +
    +
    Xmerl 1.3.28.1
    Fixed Bugs and Malfunctions @@ -84,6 +228,44 @@
    +
    Xmerl 1.3.27.1 + +
    Fixed Bugs and Malfunctions + + +

    New options to xmerl_scan and + xmerl_sax_parser so one can limit the behaviour of + the parsers to avoid some XML security issues.

    + xmerl_scan gets one new option:

    + {allow_entities, Boolean} Gives + the possibility to disallow entities by setting this + option to false (true is default) +

    xmerl_sax_parser gets the following + options:

    + disallow_entities Don't allow + entities in document + {entity_recurse_limit, N} Set a + limit on entity recursion depth (default is 3) + {external_entities, AllowedType} + Specify which types of external entities that are + allowed, this also affect external DTD's. The types are + all(default), file and none + {fail_undeclared_ref, Boolean} + Sets the behavior for undeclared references due to + an external file is not parsed (true is + default)

    The old option + skip_external_dtd is still valid and the same as + {external_entities, none} and + {fail_undeclared_ref, false} but just affects + DTD's and not other external references.

    +

    + Own Id: OTP-18595 Aux Id: ERIERL-944

    +
    +
    +
    + +
    +
    Xmerl 1.3.27
    Fixed Bugs and Malfunctions diff --git a/lib/xmerl/doc/src/xmerl_examples.html b/lib/xmerl/doc/src/xmerl_examples.html index 1305f59d4a3f..7c8ef3d4bbfb 100644 --- a/lib/xmerl/doc/src/xmerl_examples.html +++ b/lib/xmerl/doc/src/xmerl_examples.html @@ -71,7 +71,7 @@

    1.1 User State

    e.g. xmerl_eventp.erl) is for customization functions to share one of the local states (in xmerl_eventp.erl, the - continuation function and the fetch function both acces the + continuation function and the fetch function both access the cont_state.)

    Functions to access user state:

    @@ -310,7 +310,7 @@

    1.7 Accumulator Function

    The accumulator function is called to accumulate the contents of an entity.When parsing very large files, it may - not be desireable to do so.In this case, an acc function can + not be desirable to do so.In this case, an acc function can be provided that simply doesn't accumulate.

    Note that it is possible to even modify the parsed diff --git a/lib/xmerl/include/xmerl.hrl b/lib/xmerl/include/xmerl.hrl index 52a5afc664ac..42a7779f089d 100644 --- a/lib/xmerl/include/xmerl.hrl +++ b/lib/xmerl/include/xmerl.hrl @@ -18,13 +18,13 @@ %% %CopyrightEnd% %% %% Contributor(s): -%% : suggested #xmlDocument{} +%% Michael.Remond: suggested #xmlDocument{} %% %%---------------------------------------------------------------------- %% #0. BASIC INFORMATION %%---------------------------------------------------------------------- %% File: xmerl.hrl -%% Author : Ulf Wiger +%% Author : Ulf Wiger %% Date : 00-09-22 %% Description : Record and macro definitions for xmerl %%---------------------------------------------------------------------- diff --git a/lib/xmerl/include/xmerl_xpath.hrl b/lib/xmerl/include/xmerl_xpath.hrl index e5d697eea508..0775bf3e3c44 100644 --- a/lib/xmerl/include/xmerl_xpath.hrl +++ b/lib/xmerl/include/xmerl_xpath.hrl @@ -22,7 +22,7 @@ %%% #0. BASIC INFORMATION %%%---------------------------------------------------------------------- %%% File: xmerl.hrl -%%% Author : Ulf Wiger +%%% Author : Ulf Wiger %%% Date : 00-09-22 %%% Description : Record and macro definitions for xmerl_xpath %%%---------------------------------------------------------------------- diff --git a/lib/xmerl/include/xmerl_xsd.hrl b/lib/xmerl/include/xmerl_xsd.hrl index e3ee8efd4050..31633d01dafc 100644 --- a/lib/xmerl/include/xmerl_xsd.hrl +++ b/lib/xmerl/include/xmerl_xsd.hrl @@ -51,7 +51,7 @@ global_namespace_nodes=[], checked_namespace_nodes=[{"xml",[],'http://www.w3.org/XML/1998/namespace'}], table, - tab2file=false, %% for debuging of abstract syntax + tab2file=false, %% for debugging of abstract syntax redefine=false, finalDefault, %% undefined | '#all' | [atom()] %% atom() -> extension | @@ -89,7 +89,7 @@ scope, form, %% unqualified | qualified id, - occurance={1,1}, %% {minOccurs,maxOccurs} + occurrence={1,1}, %% {minOccurs,maxOccurs} value_constraint, %% undefined | {default,Value} | {fixed,Value} nillable=false, %% true | false abstract=false, %% true | false @@ -153,7 +153,7 @@ id, ref, %% in this case no name or content content=[], - occurance={1,1} + occurrence={1,1} }). -record(schema_extension,{ base, @@ -189,9 +189,9 @@ %% alterantive, a collection of objects of which only one is chosen. -record(chain,{ content, - occurance={1,1} + occurrence={1,1} }). -record(alternative,{ content, - occurance={0,1} + occurrence={0,1} }). diff --git a/lib/xmerl/src/Makefile b/lib/xmerl/src/Makefile index 51d91907975c..e7e7c8e978b8 100644 --- a/lib/xmerl/src/Makefile +++ b/lib/xmerl/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2016. All Rights Reserved. +# Copyright Ericsson AB 2003-2022. 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. @@ -127,11 +127,16 @@ ERL_COMPILE_FLAGS += \ # +bin_opt_info +ifeq ($(ERL_DETERMINISTIC),yes) + DETERMINISM_FLAG = +deterministic +else + DETERMINISM_FLAG = +endif # ---------------------------------------------------- # Targets # ---------------------------------------------------- -debug opt: $(TARGET_FILES) +$(TYPES): $(TARGET_FILES) docs: #docs: $(DOC_TARGET_FILES) @@ -173,10 +178,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ xmerl_xpath_parse.erl: xmerl_xpath_parse.yrl - $(yecc_verbose)$(ERLC) -o $(ESRC) $< + $(yecc_verbose)$(ERLC) -o $(ESRC) $(DETERMINISM_FLAG) $< xmerl_b64Bin.erl: xmerl_b64Bin.yrl - $(yecc_verbose)$(ERLC) -o $(ESRC) $< + $(yecc_verbose)$(ERLC) -o $(ESRC) $(DETERMINISM_FLAG) $< xmerl_sax_parser_list.erl: xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc $(gen_verbose)cat xmerl_sax_parser_list.erlsrc xmerl_sax_parser_base.erlsrc >$@ diff --git a/lib/xmerl/src/xmerl_eventp.erl b/lib/xmerl/src/xmerl_eventp.erl index 8d7ea25e248c..96bcd49766d3 100644 --- a/lib/xmerl/src/xmerl_eventp.erl +++ b/lib/xmerl/src/xmerl_eventp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2023. 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. @@ -295,8 +295,8 @@ read_chunk(Fd, _Fname, _Sofar) -> -ifndef(no_bitsyntax). -find_good_split(Bin, F, Exception, Fd, Fname, T, S) -> - find_good_split(size(Bin)-1, Bin, F, Exception, Fd, Fname, T, S). +find_good_split(Bin, F, Exception, Fd, Fname, T, S) when is_binary(Bin) -> + find_good_split(byte_size(Bin)-1, Bin, F, Exception, Fd, Fname, T, S). find_good_split(0, B, F, Exception, Fd, Fname, T, S) -> cont2(F, Exception, B, Fd, Fname, T, S); @@ -312,8 +312,8 @@ find_good_split(Size, B, F, Exception, Fd, Fname, T, S) -> -else. -find_good_split(Bin, F, Exception, Fd, Fname, T, S) -> - find_good_split(size(Bin), Bin, F, Exception, Fd, Fname, T, S). +find_good_split(Bin, F, Exception, Fd, Fname, T, S) when is_binary(Bin) -> + find_good_split(byte_size(Bin), Bin, F, Exception, Fd, Fname, T, S). find_good_split(0, B, F, Exception, Fd, Fname, T, S) -> cont2(F, Exception, B, Fd, Fname, T, S); diff --git a/lib/xmerl/src/xmerl_regexp.erl b/lib/xmerl/src/xmerl_regexp.erl index 1bf849667312..46d01ca9fb47 100644 --- a/lib/xmerl/src/xmerl_regexp.erl +++ b/lib/xmerl/src/xmerl_regexp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -510,7 +510,7 @@ gsub_comp([], _P, _RE, _Bef, _Rep) -> no. %% split(String, RegExp) -> {ok,[SubString]} | {error,E}. %% Split a string into substrings where the RegExp describes the -%% field seperator. The RegExp " " is specially treated. +%% field separator. The RegExp " " is specially treated. split(String, " ") -> %This is really special {ok,{regexp,RE}} = parse("[ \t]+"), @@ -1289,7 +1289,7 @@ accept([], _NFA) -> no. %% minimise_dfa(DFA, StartState, FirstState) -> {DFA,StartState}. %% Minimise the DFA by removing equivalent states. We consider a %% state if both the transitions and the their accept state is the -%% same. First repeatedly run throught the DFA state list removing +%% same. First repeatedly run through the DFA state list removing %% equivalent states and updating remaining transitions with %% remaining equivalent state numbers. When no more reductions are %% possible then pack the remaining state numbers to get consecutive diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl index f13012c7cd56..ce338d734336 100644 --- a/lib/xmerl/src/xmerl_sax_parser.erl +++ b/lib/xmerl/src/xmerl_sax_parser.erl @@ -158,7 +158,7 @@ parse_binary(Xml, #xmerl_sax_parser_state{encoding={utf16,big}}=State, F) -> parse_binary(Xml, #xmerl_sax_parser_state{encoding=latin1}=State, F) -> xmerl_sax_parser_latin1:F(Xml, State); parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) -> - ?fatal_error(State, lists:flatten(io_lib:format("Charcter set ~p not supported", [Enc]))). + ?fatal_error(State, lists:flatten(io_lib:format("Character set ~p not supported", [Enc]))). %%---------------------------------------------------------------------- %% Function: initial_state/0 diff --git a/lib/xmerl/src/xmerl_sax_parser.hrl b/lib/xmerl/src/xmerl_sax_parser.hrl index fcc27ee63b62..4d1ff5e05cb9 100644 --- a/lib/xmerl/src/xmerl_sax_parser.hrl +++ b/lib/xmerl/src/xmerl_sax_parser.hrl @@ -47,7 +47,7 @@ -define(is_hex_digit(C), $0 =< C, C =< $9; $a =< C, C =< $f; $A =< C, C =< $F). %%---------------------------------------------------------------------- -%% Definition of XML charcters +%% Definition of XML characters %% %% [2] Char #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] %%---------------------------------------------------------------------- diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc index 39aaeedba875..766f3fb1e252 100644 --- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc @@ -1727,7 +1727,7 @@ parse_reference(?STRING_UNBOUND_REST(C, Rest), State, HaveToExist) -> end; parse_reference(Bytes, State, HaveToExist) -> unicode_incomplete_check([Bytes, State, HaveToExist, fun parse_reference/3], - underfined). + undefined). parse_reference_1(?STRING_EMPTY, State, HaveToExist, Name) -> @@ -1799,7 +1799,7 @@ parse_pe_reference(?STRING_UNBOUND_REST(C, Rest), State) -> end; parse_pe_reference(Bytes, State) -> unicode_incomplete_check([Bytes, State, fun parse_pe_reference/2], - underfined). + undefined). parse_pe_reference_1(?STRING_EMPTY, State, Name) -> @@ -2028,7 +2028,7 @@ normalize_whitespace([], Acc) -> %% State = #xmerl_sax_parser_state{} %% Result : {Rest, State} %% Description: This function starts an parsing of the DTD -%% that sends apropriate events. +%% that sends appropriate events. %% [28] doctypedecl ::= '' %%---------------------------------------------------------------------- @@ -2057,7 +2057,7 @@ parse_doctype(Bytes, State) -> %% Name = string() %% Definition = true |false %% Result : {Rest, State} -%% Description: Gets the DTD name as a parameter and contine parse the DOCTYPE +%% Description: Gets the DTD name as a parameter and continue parse the DOCTYPE %% directive %%---------------------------------------------------------------------- parse_doctype_1(?STRING_EMPTY, State, Name, Definition) -> @@ -3842,7 +3842,7 @@ parse_notation_decl_1(Bytes, State) -> %% PubId = string() %% SysId = string() %% Description: Parse a NOTATION identity. The public id case is a special -%% variant of extenal id where just the public part is allowed. +%% variant of external id where just the public part is allowed. %% This is allowed if the third parameter in parse_external_id/3 %% is true. %% [83] PublicID ::= 'PUBLIC' S PubidLiteral diff --git a/lib/xmerl/src/xmerl_sax_parser_list.erlsrc b/lib/xmerl/src/xmerl_sax_parser_list.erlsrc index ac89896215e5..bb9213bff113 100644 --- a/lib/xmerl/src/xmerl_sax_parser_list.erlsrc +++ b/lib/xmerl/src/xmerl_sax_parser_list.erlsrc @@ -2,7 +2,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2017. All Rights Reserved. +%% Copyright Ericsson AB 2008-2022. 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. @@ -34,7 +34,7 @@ -define(APPEND_STRING(Rest, New), Rest ++ New). -define(TO_INPUT_FORMAT(Val), Val). -%% In the list case we can't use a '++' when matchin against an unbound variable +%% In the list case we can't use a '++' when matching against an unbound variable -define(STRING_UNBOUND_REST(MatchChar, Rest), [MatchChar | Rest]). -define(PARSE_BYTE_ORDER_MARK(Bytes, State), diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index 7d5bef48b926..62b5dd87c717 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -3647,7 +3647,7 @@ scan_entity_value("%" ++ T, S0, Delim, Acc, PEName,Namespace,PENesting) -> ExpRef -> {string_to_char_set(S1#xmerl_scanner.encoding, ExpRef) ,S1} end, - %% single or duoble qoutes are not treated as delimeters + %% single or duoble quotes are not treated as delimiters %% in passages "included in literal" S3 = S2#xmerl_scanner{col=S2#xmerl_scanner.col+1}, {Acc2,_,S4} = scan_entity_value(ExpandedRef,S3,no_delim,Acc, @@ -3688,32 +3688,32 @@ scan_entity_value("&" ++ T, S0, Delim, Acc, PEName,Namespace,PENesting) -> scan_entity_value(T2,S2,Delim,[";",atom_to_list(Name),"&"|Acc],PEName,Namespace,PENesting) end; %% The following clauses is for PE Nesting VC constraint -%% Start delimeter for ConditionalSection +%% Start delimiter for ConditionalSection scan_entity_value(" ?bump_col(3), scan_entity_value(T,S,Delim,[" ?bump_col(1), scan_entity_value(T,S,Delim,["["|Acc],PEName,NS, pe_push("[",PENesting,S)); -%% Start delimeter for comment +%% Start delimiter for comment scan_entity_value(""++ T,S0,Delim,Acc,PEName, parameter=NS,PENesting) -> ?bump_col(3), scan_entity_value(T,S,Delim,["-->"|Acc],PEName,NS, pe_pop("-->",PENesting,S)); -%% Stop delimeter for ConditionalSection +%% Stop delimiter for ConditionalSection scan_entity_value("]]>"++ T,S0,Delim,Acc,PEName, parameter=NS,PENesting) -> ?bump_col(3), scan_entity_value(T,S,Delim,["]]>"|Acc],PEName,NS, pe_pop("]]>",PENesting,S)); -%% Stop delimeter added to match a content start delimeter included +%% Stop delimiter added to match a content start delimiter included scan_entity_value("/>"++ T,S0,Delim,Acc,PEName, parameter=NS,PENesting) -> ?bump_col(2), scan_entity_value(T,S,Delim,["/>"|Acc],PEName,NS, diff --git a/lib/xmerl/src/xmerl_ucs.erl b/lib/xmerl/src/xmerl_ucs.erl index 4b1fc30089e8..cbe97369997d 100644 --- a/lib/xmerl/src/xmerl_ucs.erl +++ b/lib/xmerl/src/xmerl_ucs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2016. All Rights Reserved. +%% Copyright Ericsson AB 2005-2022. 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. @@ -423,7 +423,7 @@ char_to_utf8(Ch) when is_integer(Ch), Ch >= 0 -> %% expand_utf8([Byte]) -> {[UnicodeChar],NumberOfBadBytes} %% Expand UTF8 byte sequences to ISO 10646/Unicode -%% charactes. Any illegal bytes are removed and the number of +%% characters. Any illegal bytes are removed and the number of %% bad bytes are returned. %% %% Reference: diff --git a/lib/xmerl/src/xmerl_validate.erl b/lib/xmerl/src/xmerl_validate.erl index 8b4f5b91a2c7..c6b03a0d91ee 100644 --- a/lib/xmerl/src/xmerl_validate.erl +++ b/lib/xmerl/src/xmerl_validate.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -509,7 +509,7 @@ choice([CH|CHS],[_XML|_T]=XMLS,Rules,WSaction,S)-> {[],XMLS1} -> %% Maybe a sequence with * or ? elements that %% didn't match case CHS of - [] -> % choice has succeded but without matching XMLS1 + [] -> % choice has succeeded but without matching XMLS1 {[],XMLS1}; _ -> % there are more choice alternatives to try with choice(CHS,XMLS1,Rules,WSaction,S) diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl index 6146feba494c..2354f9d6cd0a 100644 --- a/lib/xmerl/src/xmerl_xpath.erl +++ b/lib/xmerl/src/xmerl_xpath.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2022. 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. @@ -601,7 +601,7 @@ match_preceding_sibling(Tok, N, Acc, Context) -> %% "The 'preceding' axis contains all nodes in the same document as the context -%% node that are before the context node in document order, exluding any +%% node that are before the context node in document order, excluding any %% ancestors and excluding attribute nodes and namespace nodes." match_preceding(Tok, N, Acc, Context) -> #xmlNode{parents = Ps, node = Node} = N, diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index 2836bb0e5bab..10ea8df66e82 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2018. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -25,7 +25,7 @@ %% XML Schema study part 0. %% An XML structure is validated by xmerl_xsd:validate/[2,3]. %% @type global_state().

    The global state of the validator. It is -%% representated by the #xsd_state{} record. +%% represented by the #xsd_state{} record. %%

    %% @type option_list().

    Options allow to customize the behaviour of the %% validation. @@ -400,7 +400,7 @@ new_state(Opts) -> %% information as defined elements and types. validate_schema(E=#xmlElement{}, S) -> - %% namespace is always a xmlNamespace record, attributs a list of + %% namespace is always a xmlNamespace record, attributes a list of %% #xmlAttributes and content a list of #xmlElements|#xmlText|... %% Have to save namespace nodes. Use of namespace in paths for @@ -563,7 +563,7 @@ element_content({element,S},El,Env) -> case qualify_NCName(El,S) of no_name -> Ref = particle_ref(El), - {Occ,S2} = occurance(El,{1,1},S), + {Occ,S2} = occurrence(El,{1,1},S), %% 3.3.3 bullet 2.2 S3 = element_forbidden_properties(El,S2), S4 = element_forbidden_content(El#xmlElement.content,S3), @@ -578,7 +578,7 @@ element_content({element,S},El,Env) -> Type2 = remove_annotation(Type), Unique = [X||X={unique,_} <- Type2], Key = [X||X={K,_} <- Type2,K == key orelse K==keyref], - {Occur,S4} = occurance(El,{1,1},S3), + {Occur,S4} = occurrence(El,{1,1},S3), {SE,S5} = element_properties(El#xmlElement.attributes, #schema_element{},El,S4), CM = remove_attributes([X||X={Y,_}<-Type2, @@ -586,14 +586,14 @@ element_content({element,S},El,Env) -> keyref=/=Y,annotation=/=Y]), %% take care of key/keyref later SE2 = SE#schema_element{name=Name,type=CM,uniqueness=Unique, - key=Key, occurance=Occur, + key=Key, occurrence=Occur, scope=S5#xsd_state.scope}, S6 = insert_substitutionGroup(SE2,S5), S7 = save_object({element,SE2},S6), {{element,{Name,Occur}},S7} end; element_content({complexType,S},CT,Env) -> - %% complex type definition without a name is returnd and added to + %% complex type definition without a name is returned and added to %% the content model at this level. A complex type may also contain %% attributes or attribute group references in the end of its content. %%?debug("complexType content: ~p~nenv: ~p~n",[CT,Env]), @@ -677,7 +677,7 @@ element_content({group,S},G,Env) -> %% "Schema Representation Constraint: Individual Component %% Redefinition" Ref = particle_ref(G), - {Occur,S2} = occurance(G,{1,1},S), + {Occur,S2} = occurrence(G,{1,1},S), GRef = {group, {get_QName(Ref,G#xmlElement.namespace,reset_scope(S2)),%%QQQ @@ -694,16 +694,16 @@ element_content({group,S},G,Env) -> end; element_content({all,S},All,Env) -> %% each element occurs 0 or 1 times in any order - %% {all,[{element_name,occurance}]} + %% {all,[{element_name,occurrence}]} %% CM = content_model(Seq#xmlElement.content,S,[all|Env]), - {Occur,S1} = occurance(All,{1,1},S), + {Occur,S1} = occurrence(All,{1,1},S), {CM,S2} = type(All#xmlElement.content,S1,[all|Env]), S3 = check_cm(all,allowed_content(all,Env),CM,S2), {{all,{[X||X = {element,_} <- CM],Occur}},S3}; element_content({sequence,S},Seq,Env) -> - %% {sequence,[{element_name,occurance}]} + %% {sequence,[{element_name,occurrence}]} %% CM = content_model(Seq#xmlElement.content,S,[sequence|Env]), - {Occur,S1} = occurance(Seq,{1,1},S), + {Occur,S1} = occurrence(Seq,{1,1},S), {CM,S2} = type(Seq#xmlElement.content,S1,[sequence|Env]), S3 = check_cm(sequence,allowed_content(sequence,Env),CM,S2), {{sequence,{remove_annotation(CM),Occur}},S3}; @@ -712,12 +712,12 @@ element_content({choice,S},Choice,Env) -> %% (element | group | choice | sequence | any)*) %% returns: {choice,[element_name]} %% CM = content_model(Choice#xmlElement.content,S,[choice|Env]), - {Occur,S1} = occurance(Choice,{1,1},S), + {Occur,S1} = occurrence(Choice,{1,1},S), {CM,S2} = type(Choice#xmlElement.content,S1,[choice|Env]), S3 = check_cm(choice,allowed_content(choice,Env),CM,S2), {{choice,{remove_annotation(CM),Occur}},S3}; element_content({any,S},Any,_Env) -> - {Occur,S1} = occurance(Any,{1,1},S), + {Occur,S1} = occurrence(Any,{1,1},S), NameSpace = wildcard_namespace(Any,S1), PC = processor_contents(Any), ?debug("element_content, any: Any content:~p~n",[Any#xmlElement.content]), @@ -1426,7 +1426,7 @@ check_cm(Kind,S4SCM,ContentModel,S) -> exit({error,{[],?MODULE,{internal_error,Err}}}) end. -check_cm2(Kind,#chain{content=S4SCM,occurance=Occ}, +check_cm2(Kind,#chain{content=S4SCM,occurrence=Occ}, ContentModel,S) -> case occurance_loop(Occ,fun check_chain/1, [S4SCM,ContentModel,Kind,S],0) of @@ -1445,7 +1445,7 @@ check_cm2(Kind,#chain{content=S4SCM,occurance=Occ}, Err = {[],?MODULE,{illegal_content,Reason,Kind}}, {ContentModel,acc_errs(S,Err)} end; -check_cm2(Kind,#alternative{content=S4SCM,occurance=Occ}, +check_cm2(Kind,#alternative{content=S4SCM,occurrence=Occ}, ContentModel,S) -> case occurance_loop(Occ,fun check_alternative/1, [S4SCM,ContentModel,Kind,S],0) of @@ -1621,9 +1621,9 @@ optional({_,{_,{0,_}}}) -> true; %% sequence, all or choice optional({any,{_,{0,_},_}}) -> true; -optional(#chain{occurance={0,_}}) -> +optional(#chain{occurrence={0,_}}) -> true; -optional(#alternative{occurance={0,_}}) -> +optional(#alternative{occurrence={0,_}}) -> true; optional(#chain{content=Content}) -> catch is_optional_content(Content); @@ -1671,10 +1671,10 @@ allowed_content(element,_Parents) -> #chain{content= [#alternative{content= [{simpleType,{1,1}},{complexType,{1,1}}], - occurance={0,1}}, + occurrence={0,1}}, #alternative{content= [{unique,{1,1}},{key,{1,1}},{keyref,{1,1}}], - occurance={0,unbounded}}] + occurrence={0,unbounded}}] }] }; allowed_content(attribute,_Parents) -> @@ -1689,12 +1689,12 @@ allowed_content(complexType,Parents) -> [#alternative{content= [{group,{1,1}},{all,{1,1}}, {choice,{1,1}},{sequence,{1,1}}], - occurance={0,1}}, + occurrence={0,1}}, #chain{content= [#alternative{content= [{attribute,{1,1}}, {attributeGroup,{1,1}}], - occurance={0,unbounded}}, + occurrence={0,unbounded}}, {anyAttribute,{0,1}}] } ] @@ -1714,7 +1714,7 @@ allowed_content(attributeGroup,Parents) -> [#alternative{content= [{attribute,{1,1}}, {attributeGroup,{1,1}}], - occurance={0,unbounded}}, + occurrence={0,unbounded}}, {anyAttribute,{0,1}}]}]} end; allowed_content(group,_Parents) -> @@ -1722,7 +1722,7 @@ allowed_content(group,_Parents) -> [{annotation,{0,1}}, #alternative{content= [{all,{1,1}},{choice,{1,1}},{sequence,{1,1}}], - occurance={0,1}}]}; + occurrence={0,1}}]}; allowed_content(all,_Parents) -> #chain{content=[{annotation,{0,1}},{element,{0,unbounded}}]}; allowed_content(SorC,_Parents) when SorC==sequence;SorC==choice -> @@ -1732,7 +1732,7 @@ allowed_content(SorC,_Parents) when SorC==sequence;SorC==choice -> [{element,{1,1}},{group,{1,1}}, {choice,{1,1}},{sequence,{1,1}}, {any,{1,1}}], - occurance={0,unbounded}}]}; + occurrence={0,unbounded}}]}; %% allowed_content(E,_Parents) %% when E==any;E==selector;E==field;E==notation;E==include;E==import; %% E==anyAttribute -> @@ -1744,7 +1744,7 @@ allowed_content(SorC,_Parents) when SorC==sequence;SorC==choice -> %% [{selector,{1,1}},{selector,{1,unbounded}}]}]}; %% allowed_content(annotation,_Parents) -> %% #alternative{content=[{appinfo,{1,1}},{documentation,{1,1}}], -%% occurance={0,unbounded}}; +%% occurrence={0,unbounded}}; %% allowed_content(E,_Parents) when E==appinfo;E==documentation -> %% {any,{0,unbounded}}; allowed_content(simpleType,_Parents) -> @@ -1771,7 +1771,7 @@ allowed_content(LU,_Parent) when LU==list;LU==union -> %% [#alternative{content= %% [{include,{1,1}},{import,{1,1}}, %% {redefine,{1,1}},{annotation,{1,1}}], -%% occurance={0,1}}, +%% occurrence={0,1}}, %% #chain{content= %% [#alternative{content= %% [#alternative{content= @@ -1781,14 +1781,14 @@ allowed_content(LU,_Parent) when LU==list;LU==union -> %% {attribute,{1,1}}, %% {notation,{1,1}}]}, %% {annotation,{0,unbounded}}], -%% occurance={0,unbounded}}]}; +%% occurrence={0,unbounded}}]}; allowed_content(redefine,_Parents) -> #alternative{content= [{annotation,{1,1}}, #alternative{content= [{simpleType,{1,1}},{complexType,{1,1}}, {group,{1,1}},{attributeGroup,{1,1}}]}], - occurance={0,unbounded}}; + occurrence={0,unbounded}}; allowed_content(E,_Parents) when E==simpleContent; E==complexContent -> #chain{content= @@ -1842,7 +1842,7 @@ allowed_content2(restriction,simpleType) -> {length,{1,1}},{minLength,{1,1}}, {maxLength,{1,1}},{enumeration,{1,1}}, {whiteSpace,{1,1}},{pattern,{1,1}}], - occurance={0,unbounded}}]}]}; + occurrence={0,unbounded}}]}]}; allowed_content2(restriction,simpleContent) -> #chain{content= [{annotation,{0,1}}, @@ -1855,12 +1855,12 @@ allowed_content2(restriction,simpleContent) -> {length,{1,1}},{minLength,{1,1}}, {maxLength,{1,1}},{enumeration,{1,1}}, {whiteSpace,{1,1}},{pattern,{1,1}}], - occurance={0,unbounded}}], - occurance={0,1}}, + occurrence={0,unbounded}}], + occurrence={0,1}}, #chain{content= [#alternative{content= [{attribute,{1,1}},{attributeGroup,{1,1}}], - occurance={0,unbounded}}, + occurrence={0,unbounded}}, {anyAttribute,{0,1}}]}]}; allowed_content2(restriction,complexContent) -> #chain{content= @@ -1868,11 +1868,11 @@ allowed_content2(restriction,complexContent) -> #alternative{content= [{group,{1,1}},{all,{1,1}},{choice,{1,1}}, {sequence,{1,1}}], - occurance={0,1}}, + occurrence={0,1}}, #chain{content= [#alternative{content= [{attribute,{1,1}},{attributeGroup,{1,1}}], - occurance={0,unbounded}}, + occurrence={0,unbounded}}, {anyAttribute,{0,1}}]}]}; allowed_content2(extension,simpleContent) -> #chain{content= @@ -1880,7 +1880,7 @@ allowed_content2(extension,simpleContent) -> #chain{content= [#alternative{content= [{attribute,{1,1}},{attributeGroup,{1,1}}], - occurance={0,unbounded}}, + occurrence={0,unbounded}}, {anyAttribute,{0,1}}]}]}; allowed_content2(extension,complexContent) -> #chain{content= @@ -1889,19 +1889,19 @@ allowed_content2(extension,complexContent) -> [#alternative{content= [{group,{1,1}},{all,{1,1}},{choice,{1,1}}, {sequence,{1,1}}], - occurance={0,1}}, + occurrence={0,1}}, #chain{content= [#alternative{content= [{attribute,{1,1}}, {attributeGroup,{1,1}}], - occurance={0,1}}, + occurrence={0,1}}, {anyAttribute,{0,1}}]}]}]}. set_occurance(Ch = #chain{},Occ) -> - Ch#chain{occurance=Occ}; + Ch#chain{occurrence=Occ}; set_occurance(Alt = #alternative{},Occ) -> - Alt#alternative{occurance=Occ}; + Alt#alternative{occurrence=Occ}; set_occurance({Name,_},Occ) when is_atom(Name) -> {Name,Occ}. %% set_occurance(CM,_) -> @@ -1992,7 +1992,7 @@ save_namespace_definition(NameSpace, checked_namespace_nodes=CNS}) -> %% 1) Have to find a matching namespace in the global list for %% this schema, and get the associated prefix. 2) Then check - %% whether a schema with this prefix - namespace combinaton + %% whether a schema with this prefix - namespace combination %% already is checked, if so do nothing. 3a) If this namespace is %% checked but with another prefix only add the prefix - namespace %% pair to the checked namespace list. 3b) Otherwise add the @@ -2275,7 +2275,7 @@ set_num_el(S=#xsd_state{},#xsd_state{num_el=I}) -> S#xsd_state{num_el=I}. -occurance(El=#xmlElement{attributes=Atts},{Min,Max},S) -> +occurrence(El=#xmlElement{attributes=Atts},{Min,Max},S) -> AttVal=fun(#xmlAttribute{value=V},Sin) -> case catch mk_int_or_atom(V) of {'EXIT',_} -> @@ -2470,7 +2470,7 @@ check_element_type(XML=[#xmlElement{}|_],[{all,{CM,Occ}}|_CMRest], %% 3 often. CMEL may be ((simpleType | complexType)?, (unique | key | keyref)*)) check_element_type(XML=[XMLEl=#xmlElement{}|_],[CMEl|CMRest],Env, Block,S,Checked) -> - %% Three possible releations between XMLEl - CMEl: + %% Three possible relations between XMLEl - CMEl: %% (1) XMLEl matches CMEl. %% (2) XMLEl don't matches CMEl and CMEl is optional. %% (3) XMLEl don't matches CMEl, CMEl mandatory, - error. @@ -2563,12 +2563,12 @@ check_element_type(XML=[XMLEl=#xmlElement{name=Name}|RestXML], CMEl=#schema_element{name=CMName,type=Type}, Env,Block,S,Checked) -> ElName = mk_EII_QName(Name,XMLEl,S#xsd_state{scope=element(2,CMName)}), - {Min,Max} = CMEl#schema_element.occurance, + {Min,Max} = CMEl#schema_element.occurrence, case cmp_name(ElName,CMName,S) of %% substitutionGroup true when S#xsd_state.num_el =< Max -> S1 = id_constraints(CMEl,XMLEl,S), %% If CMEl element has a substitutionGroup we have to - %% switch to the rigth element and type here. + %% switch to the right element and type here. {CMEl2,Type2,S2} = if ElName =:= CMName -> @@ -2705,7 +2705,7 @@ check_element_type(XML=[E=#xmlElement{name=Name}|Rest], end; check_element_type([],CM,_Env,_Block,S,Checked) -> %% #schema_complex_type, any, #schema_group, anyType and lists are - %% catched above. + %% caught above. case CM of #schema_simple_type{} -> {NewVal,S2} = check_type(CM,[],unapplied,S), @@ -2777,7 +2777,7 @@ check_sequence(Seq=[_InstEl=#xmlElement{}|_],[El|Els],Occ={_Min,_Max},Env,S,Chec %% Err; {Ret,UnValRest,S3} -> %% must also take care of more elements of same name - %% decrease occurance in El for the optional measurements + %% decrease occurrence in El for the optional measurements %% when Seq is empty. check_sequence(UnValRest,[decrease_occurance(El)|Els],Occ,Env, count_num_el(set_num_el(S3,S2)), @@ -2835,7 +2835,7 @@ check_choice(XML,[],{0,_},_,S,Checked) -> %% Choice is optional {Checked,XML,set_num_el(S,0)}; check_choice(XML,[],_,_,S,Checked) -> - %% Choice has already matched something, the rest is for somthing + %% Choice has already matched something, the rest is for something %% else to match. case S#xsd_state.num_el > 0 of true -> @@ -3965,7 +3965,7 @@ resolve(E,S) -> load_object(E,S). %% explicit_type checks whether the instance element is of an explicit -%% type pointed out by xsi:type. A type refernced by xsi:type must be +%% type pointed out by xsi:type. A type referenced by xsi:type must be %% the same as, or derived from the instance element's type. Concluded %% from 3.4.6 section "Schema Component Constraint: Type Derivation OK %% (Complex)". @@ -5080,7 +5080,7 @@ load_redefine_object({Kind,Name},S) -> load_object({element,{QN,Occ={Min,_}}},S) when is_integer(Min) -> case load_object({element,QN},S) of - {SE=#schema_element{},S1} -> {SE#schema_element{occurance=Occ},S1}; + {SE=#schema_element{},S1} -> {SE#schema_element{occurrence=Occ},S1}; Other -> Other end; load_object({group,{QN,_Occ={Min,_}}},S) when is_integer(Min) -> @@ -5439,11 +5439,11 @@ format_error({unvalidated_rest,UR}) -> format_error({no_schemas_provided}) -> "Schema: Validator found no schema. A schema must be provided for validation."; format_error({internal_error,Reason}) -> - io_lib:format("An error occured that was unforeseen, due to ~p.",[Reason]); + io_lib:format("An error occurred that was unforeseen, due to ~p.",[Reason]); format_error({internal_error,Reason,Info}) -> - io_lib:format("An error occured that was unforeseen, due to ~p: ~p.",[Reason,Info]); + io_lib:format("An error occurred that was unforeseen, due to ~p: ~p.",[Reason,Info]); format_error({internal_error,Function,Info1,Info2}) -> - io_lib:format("An internal error occured in function ~p with args: ~p,~p.",[Function,Info1,Info2]); + io_lib:format("An internal error occurred in function ~p with args: ~p,~p.",[Function,Info1,Info2]); format_error({illegal_content,Reason,Kind}) -> io_lib:format("Schema: The schema violates the content model allowed for schemas.~nReason: ~p,~nkind of schema element: ~p.",[Reason,Kind]); format_error({no_match,Kind}) -> @@ -5473,7 +5473,7 @@ format_error({no_element_expected_in_group,XML}) -> format_error({element_bad_match,E,Any,_Env}) -> io_lib:format("XML: XML element ~p didn't match into the namespace of schema type any ~p.",[E,Any]); format_error({match_failure,_XML,_CM,_S}) -> - "XML: A combination of XML element(s) and schema definitions that is not known has occured. The implementation doesn't support this structure."; + "XML: A combination of XML element(s) and schema definitions that is not known has occurred. The implementation doesn't support this structure."; format_error({cannot_contain_text,_XMLTxt,CMEl}) -> io_lib:format("XML: The schema structure: ~p doesn't allow text",[CMEl]); format_error({missing_mandatory_elements,MandatoryEls}) -> @@ -5489,7 +5489,7 @@ format_error({element_not_in_all,ElName,E,_CM}) -> format_error({missing_mandatory_elements_in_all,MandatoryEls}) -> io_lib:format("XML: The schema elements ~p were missed in the XML file.",[MandatoryEls]); format_error({failed_validating,E,Any}) -> - io_lib:format("XML: The element ~p at location ~p failed validation. It should hav been matched by an any schema element ~p",[E#xmlElement.name,error_path(E,undefined),Any]); + io_lib:format("XML: The element ~p at location ~p failed validation. It should have been matched by an any schema element ~p",[E#xmlElement.name,error_path(E,undefined),Any]); format_error({schemaLocation_list_failure,Paths}) -> io_lib:format("XML: schemaLocation values consists of one or more pairs of URI references, separated by white space. The first is a namespace name the second a reference to a schema: ~p.",[Paths]); format_error({element_content_not_nil,XMLEl}) -> @@ -5502,7 +5502,7 @@ format_error({default_and_fixed_attributes_mutual_exclusive, Name,Default,Fix}) -> io_lib:format("Schema: It is an error in the schema to assign values for both default and fix for an attribute. Attribute: ~p, default: ~p, fix: ~p.",[Name,Default,Fix]); format_error({schema_error,unexpected_object,_SA,_Err}) -> - "Schema: An unforeseen error case occured, maybee due to an unimplemented feature."; + "Schema: An unforeseen error case occurred, maybe due to an unimplemented feature."; format_error({attribute_not_defined_in_schema,Name}) -> io_lib:format("XML: The attribute ~p is not defined in the provided schema.",[Name]); format_error({disallowed_namespace,Namespace,NS,Name}) -> @@ -5530,9 +5530,9 @@ format_error({key_value_not_unique,KS}) -> format_error({keyref_missed_matching_key,Refer}) -> io_lib:format("Schema: This keyref had no matching key ~p.",[Refer]); format_error({keyref_unexpected_object,_Other}) -> - "Schema: An unforeseen error case occured, unknown failure cause."; + "Schema: An unforeseen error case occurred, unknown failure cause."; format_error({cardinality_of_fields_not_equal,KR,K}) -> - io_lib:format("Schema: keyref and the corresponding key must have same cardinality of their fields. Missmatch in this case keyref: ~p, key: ~p.",[KR,K]); + io_lib:format("Schema: keyref and the corresponding key must have same cardinality of their fields. Mismatch in this case keyref: ~p, key: ~p.",[KR,K]); format_error({could_not_load_keyref,Name}) -> io_lib:format("Schema: The schema didn't define a keyref with the name ~p.",[Name]); format_error({reference_undeclared,Kind,Ref}) -> @@ -5542,7 +5542,7 @@ format_error({cyclic_substitutionGroup,SGs}) -> format_error({substitutionGroup_error,Head,SG}) -> io_lib:format("Schema: Either of substitutionGroup members ~p or ~p is not defined in the provided schema.",[Head,SG]); format_error({cyclic_definition,CA}) -> - io_lib:format("Schema: A forbidden cicular definition was detected ~p.",[CA]); + io_lib:format("Schema: A forbidden circular definition was detected ~p.",[CA]); format_error({type_of_element_not_derived,MemT,HeadT}) -> io_lib:format("Schema: Type in substitutionGroup members should be simpleType or complexType. In this case ~p and ~p were found.",[MemT, HeadT]); format_error({derivation_blocked,BlockTag,Derivation}) -> diff --git a/lib/xmerl/src/xmerl_xsd_type.erl b/lib/xmerl/src/xmerl_xsd_type.erl index 8b73c3af3b63..af4ede8ba47b 100644 --- a/lib/xmerl/src/xmerl_xsd_type.erl +++ b/lib/xmerl/src/xmerl_xsd_type.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2021. All Rights Reserved. +%% Copyright Ericsson AB 2006-2022. 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. @@ -1499,7 +1499,7 @@ get_digit([],_,[],_Str) -> get_digit([],_,_,Str) -> {"0",Str}; get_digit(_,_,_,Str) -> - %% this matches both the case when reaching another delimeter and + %% this matches both the case when reaching another delimiter and %% when the string already are emptied. {"0",Str}. diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile index b90ca772af6c..97180d80516e 100644 --- a/lib/xmerl/test/Makefile +++ b/lib/xmerl/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2021. All Rights Reserved. +# Copyright Ericsson AB 2004-2022. 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. @@ -86,13 +86,14 @@ RELSYSDIR = $(RELEASE_PATH)/xmerl_test # ---------------------------------------------------- ERL_COMPILE_FLAGS += +ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS)) # ---------------------------------------------------- # Targets # ---------------------------------------------------- -tests debug opt: xmerl_test.erl +tests $(TYPES): xmerl_test.erl info: @echo "HRL_FILES: $(HRL_FILES)" diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl index 6dc62f9877a3..cf1728bf2ad4 100644 --- a/lib/xmerl/test/xmerl_SUITE.erl +++ b/lib/xmerl/test/xmerl_SUITE.erl @@ -445,7 +445,7 @@ generate_heading_col(N) -> %% ticket_5998 %% %% A Kleene Closure child in a sequence consumed all following -%% childs. This problem has been fixed. +%% child's. This problem has been fixed. %% ticket_5998(Config) -> DataDir = datadir(Config), @@ -477,7 +477,7 @@ ticket_5998(Config) -> %% ticket_7211 %% %% A Kleene Closure child in a sequence consumed all following -%% childs. This problem has been fixed. +%% child's. This problem has been fixed. %% ticket_7211(Config) -> DataDir = datadir(Config), @@ -507,7 +507,7 @@ ticket_7211(Config) -> %% ticket_7214 %% %% Now validating xhtml1-transitional.dtd. -%% A certain contentspec with a succeding choice, that didn't match +%% A certain contentspec with a succeeding choice, that didn't match %% all content, followed by other child elements caused a %% failure. This is now corrected. %% @@ -607,7 +607,7 @@ ticket_9457_cont(Continue, Exception, GlobalState) -> end. -%% Test that comments are handled correct whith +%% Test that comments are handled correct with ticket_9664_schema(Config) -> {E, _} = xmerl_scan:file(datadir_join(Config,[misc,"ticket_9664_schema.xml"]),[]), {ok, S} = xmerl_xsd:process_schema(datadir_join(Config,[misc,"motorcycles.xsd"])), @@ -620,7 +620,7 @@ ticket_9664_schema(Config) -> {validation, schema}]), ok. -%% Test that comments are handled correct whith +%% Test that comments are handled correct with ticket_9664_dtd(Config) -> {E, _} = xmerl_scan:file(datadir_join(Config,[misc,"ticket_9664_dtd.xml"]),[]), {E, _} = xmerl_scan:file(datadir_join(Config,[misc,"ticket_9664_dtd.xml"]),[{validation, true}]), diff --git a/lib/xmerl/test/xmerl_sax_std_SUITE.erl b/lib/xmerl/test/xmerl_sax_std_SUITE.erl index c1e78887c6f2..54fee16317f2 100644 --- a/lib/xmerl/test/xmerl_sax_std_SUITE.erl +++ b/lib/xmerl/test/xmerl_sax_std_SUITE.erl @@ -1,7 +1,7 @@ %%---------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -3183,7 +3183,7 @@ end_per_testcase(_Func,_Config) -> %% Sections: 3.1 [40] %% Output: valid/sa/out/011.xml %% Description: -%% Test demonstrates mutliple Attibutes within the Start-tag. +%% Test demonstrates multiple Attributes within the Start-tag. 'valid-sa-011'(Config) -> file:set_cwd(datadir(Config)), Path = filename:join([datadir(Config),"xmltest","valid/sa/011.xml"]), @@ -3343,7 +3343,7 @@ end_per_testcase(_Func,_Config) -> %% Output: valid/sa/out/020.xml %% Description: %% Test demonstractes that CDATA sections are valid element content and that -%% everyting between the CDStart and CDEnd is recognized as character data not +%% everything between the CDStart and CDEnd is recognized as character data not %% markup. 'valid-sa-020'(Config) -> file:set_cwd(datadir(Config)), @@ -3486,7 +3486,7 @@ end_per_testcase(_Func,_Config) -> %% Sections: 2.8 [24] %% Output: valid/sa/out/028.xml %% Description: -%% Test demonstrates a valid prolog that uses double quotes as delimeters +%% Test demonstrates a valid prolog that uses double quotes as delimiters %% around the VersionNum. 'valid-sa-028'(Config) -> file:set_cwd(datadir(Config)), @@ -3504,7 +3504,7 @@ end_per_testcase(_Func,_Config) -> %% Sections: 2.8 [24] %% Output: valid/sa/out/029.xml %% Description: -%% Test demonstrates a valid prolog that uses single quotes as delimters +%% Test demonstrates a valid prolog that uses single quotes as delimiter %% around the VersionNum. 'valid-sa-029'(Config) -> file:set_cwd(datadir(Config)), @@ -4675,7 +4675,7 @@ end_per_testcase(_Func,_Config) -> %% Sections: 2.3 2.10 %% Output: valid/sa/out/092.xml %% Description: -%% Test demostrates that extra whitespace is normalized into a single space +%% Test demonstrates that extra whitespace is normalized into a single space %% character. 'valid-sa-092'(Config) -> file:set_cwd(datadir(Config)), @@ -5450,7 +5450,7 @@ end_per_testcase(_Func,_Config) -> %% Entities: both %% Output: valid/not-sa/out/015.xml %% Description: -%% Test demonstrates the use of the conditonal section IGNORE the will ignore +%% Test demonstrates the use of the conditional section IGNORE the will ignore %% its content from being part of the DTD. The keyword is a parameter-entity %% reference. 'valid-not-sa-015'(Config) -> @@ -5697,7 +5697,7 @@ end_per_testcase(_Func,_Config) -> %% Entities: both %% Output: valid/not-sa/out/029.xml %% Description: -%% Test demonstrates the use of the conditonal section IGNORE the will ignore +%% Test demonstrates the use of the conditional section IGNORE the will ignore %% its content from being used. 'valid-not-sa-029'(Config) -> file:set_cwd(datadir(Config)), @@ -5716,7 +5716,7 @@ end_per_testcase(_Func,_Config) -> %% Entities: both %% Output: valid/not-sa/out/030.xml %% Description: -%% Test demonstrates the use of the conditonal section IGNORE the will ignore +%% Test demonstrates the use of the conditional section IGNORE the will ignore %% its content from being used. 'valid-not-sa-030'(Config) -> file:set_cwd(datadir(Config)), @@ -7446,7 +7446,7 @@ optional21(Config) -> %% Description: %% Tests the Element Valid VC (clause 2) for one instance of "children" %% content model, providing no children where one or more are required (an -%% eigth construction of that model). +%% eighth construction of that model). optional22(Config) -> file:set_cwd(datadir(Config)), Path = filename:join([datadir(Config),"sun","invalid/optional22.xml"]), @@ -8910,7 +8910,7 @@ uri01(Config) -> %% Entities: parameter %% Description: %% Valid doctypedecl with EXternalID as Enternal Entity. The external entity -%% contains a parameter entity reference and condtional sections. +%% contains a parameter entity reference and conditional sections. 'o-p31pass2'(Config) -> file:set_cwd(datadir(Config)), Path = filename:join([datadir(Config),"oasis","p31pass2.xml"]), @@ -9812,7 +9812,7 @@ uri01(Config) -> %% Type: invalid %% Sections: 2.9 [32] %% Description: -%% Double quotes can be used as delimeters for the value of a Standalone +%% Double quotes can be used as delimiters for the value of a Standalone %% Document Declaration. 'o-p32pass1'(Config) -> file:set_cwd(datadir(Config)), @@ -9827,7 +9827,7 @@ uri01(Config) -> %% Type: invalid %% Sections: 2.9 [32] %% Description: -%% Single quotes can be used as delimeters for the value of a Standalone +%% Single quotes can be used as delimiters for the value of a Standalone %% Document Declaration. 'o-p32pass2'(Config) -> file:set_cwd(datadir(Config)), @@ -12578,7 +12578,7 @@ uri01(Config) -> %% Type: not-wf %% Sections: 3.3 [53] %% Description: -%% name is requried +%% name is required 'o-p53fail5'(Config) -> file:set_cwd(datadir(Config)), Path = filename:join([datadir(Config),"oasis","p53fail5.xml"]), @@ -12662,7 +12662,7 @@ uri01(Config) -> %% Type: not-wf %% Sections: 3.3.1 [56] %% Description: -%% no ENTITYS type - types must be upper case +%% no ENTITIES type - types must be upper case 'o-p56fail4'(Config) -> file:set_cwd(datadir(Config)), Path = filename:join([datadir(Config),"oasis","p56fail4.xml"]), @@ -27736,7 +27736,7 @@ uri01(Config) -> %% Sections: 3.3.1 %% Output: valid/P58/out/ibm58v01.xml %% Description: -%% Tests NotationType for P58. It shows different patterns fro the NOTATION +%% Tests NotationType for P58. It shows different patterns from the NOTATION %% attribute "attr". 'ibm-valid-P58-ibm58v01'(Config) -> file:set_cwd(datadir(Config)), diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index 4734f88eef51..3f780125a9a9 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -1 +1 @@ -XMERL_VSN = 1.3.28.1 +XMERL_VSN = 1.3.31.1 diff --git a/make/app_targets.mk b/make/app_targets.mk index 468bb6de3cc1..cf7485e3f2e4 100644 --- a/make/app_targets.mk +++ b/make/app_targets.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -22,8 +22,11 @@ APPLICATION ?= $(basename $(notdir $(PWD))) .PHONY: test info gclean dialyzer dialyzer_plt dclean +ifndef NO_TEST_TARGET test: - $(ERL_TOP)/make/test_target_script.sh $(ERL_TOP) + TEST_NEEDS_RELEASE=$(TEST_NEEDS_RELEASE) TYPE=$(TYPE) \ + $(ERL_TOP)/make/test_target_script.sh $(ERL_TOP) +endif info: @echo "$(APPLICATION)_VSN: $(VSN)" diff --git a/lib/common_test/priv/auxdir/config.guess b/make/autoconf/config.guess similarity index 100% rename from lib/common_test/priv/auxdir/config.guess rename to make/autoconf/config.guess diff --git a/lib/common_test/priv/auxdir/config.sub b/make/autoconf/config.sub similarity index 100% rename from lib/common_test/priv/auxdir/config.sub rename to make/autoconf/config.sub diff --git a/lib/common_test/priv/auxdir/install-sh b/make/autoconf/install-sh similarity index 100% rename from lib/common_test/priv/auxdir/install-sh rename to make/autoconf/install-sh diff --git a/make/autoconf/otp.m4 b/make/autoconf/otp.m4 new file mode 100644 index 000000000000..f54310159916 --- /dev/null +++ b/make/autoconf/otp.m4 @@ -0,0 +1,3317 @@ +dnl -*-Autoconf-*- +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1998-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% +dnl + +dnl +dnl otp.m4 +dnl +dnl Local macros that can be used in `configure.ac` files in OTP. To use +dnl any of the macros your `configure.ac` file should include this file +dnl using `m4_include([otp.m4])` after AC_INIT. +dnl +dnl The Local Macros which could be part of autoconf are prefixed LM_, +dnl macros specific dnl to the Erlang system are prefixed ERL_ (this is +dnl not always consistently made...). +dnl + +AC_DEFUN([ERL_CANONICAL_SYSTEM_TYPE], +[ + AC_CANONICAL_HOST + # Adjust for local legacy windows hack... + AS_CASE([$host], + [local-*-windows], + [ + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ]) + + AC_CANONICAL_BUILD + # Adjust for local legacy windows hack... + AS_CASE([$build], + [local-*-windows], + [ + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ]) + + AC_CANONICAL_TARGET + # Adjust for local legacy windows hack... + AS_CASE([$target], + [local-*-windows], + [ + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ]) + + AS_IF([test "$cross_compiling" = "yes" -a "$build" = "$host"], + [AC_MSG_ERROR([ + Cross compiling with the same canonicalized 'host' value + as the canonicalized 'build' value. + + We are cross compiling since the '--host=$host_alias' + and the '--build=$build_alias' arguments differ. When + cross compiling Erlang/OTP, also the canonicalized values of + the '--build' and the '--host' arguments *must* differ. The + canonicalized values of these arguments however both equals: + $host + + You can check the canonical value by passing a value as + argument to the 'make/autoconf/config.sub' script. + ])]) +]) + +AC_DEFUN(LM_PRECIOUS_VARS, +[ + +dnl ERL_TOP +AC_ARG_VAR(ERL_TOP, [Erlang/OTP top source directory]) + +dnl Tools +AC_ARG_VAR(CC, [C compiler]) +AC_ARG_VAR(CFLAGS, [C compiler flags]) +AC_ARG_VAR(STATIC_CFLAGS, [C compiler static flags]) +AC_ARG_VAR(CFLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag passed via C compiler]) +AC_ARG_VAR(CPP, [C/C++ preprocessor]) +AC_ARG_VAR(CPPFLAGS, [C/C++ preprocessor flags]) +AC_ARG_VAR(CXX, [C++ compiler]) +AC_ARG_VAR(CXXFLAGS, [C++ compiler flags]) +AC_ARG_VAR(LD, [linker (is often overridden by configure)]) +AC_ARG_VAR(LDFLAGS, [linker flags (can be risky to set since LD may be overridden by configure)]) +AC_ARG_VAR(LIBS, [libraries]) +AC_ARG_VAR(DED_LD, [linker for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) +AC_ARG_VAR(DED_LDFLAGS, [linker flags for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) +AC_ARG_VAR(DED_LD_FLAG_RUNTIME_LIBRARY_PATH, [runtime library path linker flag for Dynamic Erlang Drivers (set all DED_LD* variables or none)]) +AC_ARG_VAR(LFS_CFLAGS, [large file support C compiler flags (set all LFS_* variables or none)]) +AC_ARG_VAR(LFS_LDFLAGS, [large file support linker flags (set all LFS_* variables or none)]) +AC_ARG_VAR(LFS_LIBS, [large file support libraries (set all LFS_* variables or none)]) +AC_ARG_VAR(RANLIB, [ranlib]) +AC_ARG_VAR(AR, [ar]) +AC_ARG_VAR(GETCONF, [getconf]) + +dnl Cross system root +AC_ARG_VAR(erl_xcomp_sysroot, [Absolute cross system root path (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_isysroot, [Absolute cross system root include path (only used when cross compiling)]) + +dnl Cross compilation variables +AC_ARG_VAR(erl_xcomp_bigendian, [big endian system: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_double_middle_endian, [double-middle-endian system: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_linux_nptl, [have Native POSIX Thread Library: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_linux_usable_sigusrx, [SIGUSR1 and SIGUSR2 can be used: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_linux_usable_sigaltstack, [have working sigaltstack(): yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_poll, [have working poll(): yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_kqueue, [have working kqueue(): yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_putenv_copy, [putenv() stores key-value copy: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_reliable_fpe, [have reliable floating point exceptions: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_getaddrinfo, [have working getaddrinfo() for both IPv4 and IPv6: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_gethrvtime_procfs_ioctl, [have working gethrvtime() which can be used with procfs ioctl(): yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_clock_gettime_cpu_time, [clock_gettime() can be used for retrieving process CPU time: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_after_morecore_hook, [__after_morecore_hook can track malloc()s core memory usage: yes|no (only used when cross compiling)]) +AC_ARG_VAR(erl_xcomp_dlsym_brk_wrappers, [dlsym(RTLD_NEXT, _) brk wrappers can track malloc()s core memory usage: yes|no (only used when cross compiling)]) + +]) + +AC_DEFUN(ERL_XCOMP_SYSROOT_INIT, +[ +erl_xcomp_without_sysroot=no +if test "$cross_compiling" = "yes"; then + test "$erl_xcomp_sysroot" != "" || erl_xcomp_without_sysroot=yes + test "$erl_xcomp_isysroot" != "" || erl_xcomp_isysroot="$erl_xcomp_sysroot" +else + erl_xcomp_sysroot= + erl_xcomp_isysroot= +fi +]) + +AC_DEFUN(LM_CHECK_GETCONF, +[ +AS_IF( + [test "$cross_compiling" != "yes"], + [ + AC_CHECK_PROG([GETCONF], [getconf], [getconf], [false]) + ], + [ + dnl First check if we got a `-getconf' in $PATH + host_getconf="$host_alias-getconf" + AC_CHECK_PROG([GETCONF], [$host_getconf], [$host_getconf], [false]) + AS_IF( + [test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""], + [ + dnl We should perhaps give up if we haven't found it by now, but at + dnl least in one Tilera MDE `getconf' under sysroot is a bourne + dnl shell script which we can use. We try to find `-getconf' + dnl or `getconf' under sysconf, but only under sysconf since + dnl `getconf' in $PATH is almost guaranteed to be for the build + dnl machine. + GETCONF= + prfx="$erl_xcomp_sysroot" + AC_PATH_TOOL([GETCONF], [getconf], [false], + ["$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"]) + ]) + ]) +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_WINDOWS_ENVIRONMENT +dnl +dnl +dnl Tries to determine the windows build environment, i.e. +dnl MIXED_VC or MIXED_MINGW +dnl + +AC_DEFUN(LM_WINDOWS_ENVIRONMENT, +[ + +if test "X$windows_environment_" != "Xchecked"; then +windows_environment_=checked +MIXED_CYGWIN=no +MIXED_MSYS=no +MIXED_VSL=no + +dnl MIXED_VC is Microsoft Visual C++ used as standard compiler +MIXED_VC=no +dnl MIXED_MINGW is mingw(32|64) used as standard compiler +MIXED_MINGW=no + +AC_MSG_CHECKING(for mixed mingw-gcc and native VC++ environment) +if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then + if test -x /usr/bin/msys-?.0.dll; then + CFLAGS="$CFLAGS -O2" + MIXED_MSYS=yes + AC_MSG_RESULT([MSYS and VC]) + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + elif test -x /usr/bin/cygpath; then + CFLAGS="$CFLAGS -O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([Cygwin and VC]) + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + elif test -x /bin/wslpath; then + CFLAGS="$CFLAGS -O2" + MIXED_WSL=yes + AC_MSG_RESULT([WSL and VC]) + MIXED_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not within any known env, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(MIXED_VC) + +if test "x$MIXED_MSYS" != "xyes"; then + AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) + if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="$CFLAGS -O2" + AC_MSG_RESULT([yes]) + MIXED_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi + else + AC_MSG_RESULT([no]) + fi +else + AC_MSG_CHECKING(for mixed MSYS and native MinGW environment) + if test "x$GCC" = x"yes"; then + if test -x /usr/bin/msys-=.0.dll; then + CFLAGS="$CFLAGS -O2" + AC_MSG_RESULT([yes]) + MIXED_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with msys, cannot handle this!) + fi + else + AC_MSG_RESULT([no]) + fi +fi +AC_SUBST(MIXED_MINGW) + +AC_MSG_CHECKING(if we mix cygwin with any native compiler) +if test "X$MIXED_CYGWIN" = "Xyes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING(if we mix msys with another native compiler) +if test "X$MIXED_MSYS" = "Xyes" ; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING(if we mix WSL with another native compiler) +if test "X$MIXED_WSL" = "Xyes" ; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +fi +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_FIND_EMU_CC +dnl +dnl +dnl Tries fairly hard to find a C compiler that can handle jump tables. +dnl Defines the @EMU_CC@ variable for the makefiles and +dnl inserts NO_JUMP_TABLE in the header if one cannot be found... +dnl + +AC_DEFUN(LM_FIND_EMU_CC, + [AC_CACHE_CHECK(for a compiler that handles jumptables, + ac_cv_prog_emu_cc, + [ +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +#if defined(__clang_major__) && __clang_major__ >= 3 + /* clang 3.x or later is fine */ +#elif defined(__llvm__) +#error "this version of llvm is unable to correctly compile beam_emu.c" +#endif + __label__ lbl1; + __label__ lbl2; + extern int magic(void); + int x = magic(); + static void *jtab[2]; + + jtab[0] = &&lbl1; + jtab[1] = &&lbl2; + goto *jtab[x]; +lbl1: + return 1; +lbl2: + return 2; +]])],[ac_cv_prog_emu_cc="$CC"],[ac_cv_prog_emu_cc=no]) + +if test "$ac_cv_prog_emu_cc" = no; then + for ac_progname in emu_cc.sh gcc-4.2 gcc; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_progname"; then + ac_cv_prog_emu_cc="$ac_dir/$ac_progname" + break + fi + done + IFS="$ac_save_ifs" + if test "$ac_cv_prog_emu_cc" != no; then + break + fi + done +fi + +AS_IF([test "$ac_cv_prog_emu_cc" != no], + [ + save_CC="$CC" + save_CFLAGS=$CFLAGS + save_CPPFLAGS=$CPPFLAGS + CC="$ac_cv_prog_emu_cc" + CFLAGS="" + CPPFLAGS="" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +#if defined(__clang_major__) && __clang_major__ >= 3 + /* clang 3.x or later is fine */ +#elif defined(__llvm__) +#error "this version of llvm is unable to correctly compile beam_emu.c" +#endif + __label__ lbl1; + __label__ lbl2; + extern int magic(void); + int x = magic(); + static void *jtab[2]; + + jtab[0] = &&lbl1; + jtab[1] = &&lbl2; + goto *jtab[x]; + lbl1: + return 1; + lbl2: + return 2; + ]])],[ac_cv_prog_emu_cc="$CC"],[ac_cv_prog_emu_cc=no]) + CC=$save_CC + CFLAGS=$save_CFLAGS + CPPFLAGS=$save_CPPFLAGS + ]) +]) +if test "$ac_cv_prog_emu_cc" = no; then + AC_DEFINE(NO_JUMP_TABLE,[],[Defined if no found C compiler can handle jump tables]) + EMU_CC="$CC" +else + EMU_CC="$ac_cv_prog_emu_cc" +fi +AC_SUBST(EMU_CC) +]) + + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_PROG_INSTALL_DIR +dnl +dnl This macro may be used by any OTP application. +dnl +dnl Figure out how to create directories with parents. +dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better) +dnl +dnl We prefer 'install -d', but use 'mkdir -p' if it exists. +dnl If none of these methods works, we give up. +dnl + + +AC_DEFUN(LM_PROG_INSTALL_DIR, +[AC_CACHE_CHECK(how to create a directory including parents, +ac_cv_prog_mkdir_p, +[ +temp_name_base=config.$$ +temp_name=$temp_name_base/x/y/z +$INSTALL -d $temp_name >/dev/null 2>&1 +ac_cv_prog_mkdir_p=none +if test -d $temp_name; then + ac_cv_prog_mkdir_p="$INSTALL -d" +else + mkdir -p $temp_name >/dev/null 2>&1 + if test -d $temp_name; then + ac_cv_prog_mkdir_p="mkdir -p" + fi +fi +rm -fr $temp_name_base +]) + +case "${ac_cv_prog_mkdir_p}" in + none) AC_MSG_ERROR(don't know how create directories with parents) ;; + *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;; +esac +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_PROG_PERL5 +dnl +dnl Try to find perl version 5. If found set PERL to the absolute path +dnl of the program, if not found set PERL to false. +dnl +AC_DEFUN(LM_PROG_PERL5, +[AC_PATH_PROGS(PERL, perl5 perl, false, + /usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH}) +if test "$PERL" = "false"; then + ac_cv_path_PERL=false + PERL=false +dnl AC_MSG_WARN(perl version 5 not found) +fi +])dnl + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_DECL_SO_BSDCOMPAT +dnl +dnl Check if the system has the SO_BSDCOMPAT flag on sockets (linux) +dnl +AC_DEFUN(LM_DECL_SO_BSDCOMPAT, +[AC_CACHE_CHECK([for SO_BSDCOMPAT declaration], ac_cv_decl_so_bsdcompat, +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = SO_BSDCOMPAT;]])],[ac_cv_decl_so_bsdcompat=yes],[ac_cv_decl_so_bsdcompat=no])) + +case "${ac_cv_decl_so_bsdcompat}" in + "yes" ) AC_DEFINE(HAVE_SO_BSDCOMPAT,[], + [Define if you have SO_BSDCOMPAT flag on sockets]) ;; + * ) ;; +esac +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_DECL_INADDR_LOOPBACK +dnl +dnl Try to find declaration of INADDR_LOOPBACK, if nowhere provide a default +dnl + +AC_DEFUN(LM_DECL_INADDR_LOOPBACK, +[AC_CACHE_CHECK([for INADDR_LOOPBACK in netinet/in.h], + ac_cv_decl_inaddr_loopback, +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], [[int i = INADDR_LOOPBACK;]])],[ac_cv_decl_inaddr_loopback=yes],[ac_cv_decl_inaddr_loopback=no]) +]) + +AS_IF( + [test ${ac_cv_decl_inaddr_loopback} = no], + [ + AC_CACHE_CHECK([for INADDR_LOOPBACK in rpc/types.h], + ac_cv_decl_inaddr_loopback_rpc, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = INADDR_LOOPBACK;]])],[ac_cv_decl_inaddr_loopback_rpc=yes],[ac_cv_decl_inaddr_loopback_rpc=no])) + + AS_IF( + [test "${ac_cv_decl_inaddr_loopback_rpc}" = "yes"], + [ + AC_DEFINE(DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H,[], + [Define if you need to include rpc/types.h to get INADDR_LOOPBACK defined]) + ], + [ + AC_CACHE_CHECK([for INADDR_LOOPBACK in winsock2.h], + ac_cv_decl_inaddr_loopback_winsock2, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define WIN32_LEAN_AND_MEAN + #include ]], [[int i = INADDR_LOOPBACK;]])],[ac_cv_decl_inaddr_loopback_winsock2=yes],[ac_cv_decl_inaddr_loopback_winsock2=no])) + case "${ac_cv_decl_inaddr_loopback_winsock2}" in + "yes" ) + AC_DEFINE(DEF_INADDR_LOOPBACK_IN_WINSOCK2_H,[], + [Define if you need to include winsock2.h to get INADDR_LOOPBACK defined]) ;; + * ) + # couldn't find it anywhere + AC_DEFINE(HAVE_NO_INADDR_LOOPBACK,[], + [Define if you don't have a definition of INADDR_LOOPBACK]) ;; + esac + ]) + ]) +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_STRUCT_SOCKADDR_SA_LEN +dnl +dnl Check if the sockaddr structure has the field sa_len +dnl + +AC_DEFUN(LM_STRUCT_SOCKADDR_SA_LEN, +[AC_CACHE_CHECK([whether struct sockaddr has sa_len field], + ac_cv_struct_sockaddr_sa_len, +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], [[struct sockaddr s; s.sa_len = 10;]])],[ac_cv_struct_sockaddr_sa_len=yes],[ac_cv_struct_sockaddr_sa_len=no])) + +dnl FIXME convbreak +case ${ac_cv_struct_sockaddr_sa_len} in + "no" ) AC_DEFINE(NO_SA_LEN,[1],[Define if you dont have salen]) ;; + *) ;; +esac +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_SYS_IPV6 +dnl +dnl Check for ipv6 support and what the in6_addr structure is called. +dnl (early linux used in_addr6 instead of in6_addr) +dnl + +AC_DEFUN(LM_SYS_IPV6, +[AC_MSG_CHECKING(for IP version 6 support) +AC_CACHE_VAL(ac_cv_sys_ipv6_support, +[ok_so_far=yes + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#ifdef __WIN32__ +#include +#include +#else +#include +#endif]], [[struct in6_addr a6; struct sockaddr_in6 s6;]])],[ok_so_far=yes],[ok_so_far=no]) + +AS_IF( + [test $ok_so_far = yes], + [ + ac_cv_sys_ipv6_support=yes + ], + [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#ifdef __WIN32__ +#include +#include +#else +#include +#endif]], [[struct in_addr6 a6; struct sockaddr_in6 s6;]])],[ac_cv_sys_ipv6_support=in_addr6],[ac_cv_sys_ipv6_support=no]) + ]) +])dnl + +dnl +dnl Have to use old style AC_DEFINE due to BC with old autoconf. +dnl + +case ${ac_cv_sys_ipv6_support} in + yes) + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present]) + ;; + in_addr6) + AC_MSG_RESULT([yes (but I am redefining in_addr6 to in6_addr)]) + AC_DEFINE(HAVE_IN6,[1],[Define if ipv6 is present]) + AC_DEFINE(HAVE_IN_ADDR6_STRUCT,[],[Early linux used in_addr6 instead of in6_addr, define if you have this]) + ;; + *) + AC_MSG_RESULT(no) + ;; +esac +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_SYS_MULTICAST +dnl +dnl Check for multicast support. Only checks for multicast options in +dnl setsockopt(), no check is performed that multicasting actually works. +dnl If options are found defines HAVE_MULTICAST_SUPPORT +dnl + +AC_DEFUN(LM_SYS_MULTICAST, +[AC_CACHE_CHECK([for multicast support], ac_cv_sys_multicast_support, +[ +AC_EGREP_CPP(^yes$, +[#include +#include +#include +#if defined(IP_MULTICAST_TTL) && defined(IP_MULTICAST_LOOP) && defined(IP_MULTICAST_IF) && defined(IP_ADD_MEMBERSHIP) && defined(IP_DROP_MEMBERSHIP) +yes +#endif +], ac_cv_sys_multicast_support=yes, ac_cv_sys_multicast_support=no)]) +if test $ac_cv_sys_multicast_support = yes; then + AC_DEFINE(HAVE_MULTICAST_SUPPORT,[1], + [Define if setsockopt() accepts multicast options]) +fi +])dnl + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_DECL_SYS_ERRLIST +dnl +dnl Define SYS_ERRLIST_DECLARED if the variable sys_errlist is declared +dnl in a system header file, stdio.h or errno.h. +dnl + +AC_DEFUN(LM_DECL_SYS_ERRLIST, +[AC_CACHE_CHECK([for sys_errlist declaration in stdio.h or errno.h], + ac_cv_decl_sys_errlist, +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], [[char *msg = *(sys_errlist + 1);]])],[ac_cv_decl_sys_errlist=yes],[ac_cv_decl_sys_errlist=no])]) +if test $ac_cv_decl_sys_errlist = yes; then + AC_DEFINE(SYS_ERRLIST_DECLARED,[], + [define if the variable sys_errlist is declared in a system header file]) +fi +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_CHECK_FUNC_DECL( funname, declaration [, extra includes +dnl [, action-if-found [, action-if-not-found]]] ) +dnl +dnl Checks if the declaration "declaration" of "funname" conflicts +dnl with the header files idea of how the function should be +dnl declared. It is useful on systems which lack prototypes and you +dnl need to provide your own (e.g. when you want to take the address +dnl of a function). The 4'th argument is expanded if conflicting, +dnl the 5'th argument otherwise +dnl +dnl + +AC_DEFUN(LM_CHECK_FUNC_DECL, +[AC_MSG_CHECKING([for conflicting declaration of $1]) +AC_CACHE_VAL(ac_cv_func_decl_$1, +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +$3]], [[$2 +char *c = (char *)$1; +]])],[eval "ac_cv_func_decl_$1=no"],[eval "ac_cv_func_decl_$1=yes"])]) +if eval "test \"`echo '$ac_cv_func_decl_'$1`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$4], , :, [$4]) +else + AC_MSG_RESULT(no) +ifelse([$5], , , [$5 +])dnl +fi +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl AC_DOUBLE_MIDDLE_ENDIAN +dnl +dnl Checks whether doubles are represented in "middle-endian" format. +dnl Sets ac_cv_double_middle_endian={no,yes,unknown} accordingly, +dnl as well as DOUBLE_MIDDLE_ENDIAN. +dnl +dnl + +AC_DEFUN([AC_C_DOUBLE_MIDDLE_ENDIAN], +[AC_CACHE_CHECK(whether double word ordering is middle-endian, ac_cv_c_double_middle_endian, +[# It does not; compile a test program. +AC_RUN_IFELSE( +[AC_LANG_SOURCE([[#include + +int +main(void) +{ + int i = 0; + int zero = 0; + int bigendian; + int zero_index = 0; + + union + { + long int l; + char c[sizeof (long int)]; + } u; + + /* we'll use the one with 32-bit words */ + union + { + double d; + unsigned int c[2]; + } vint; + + union + { + double d; + unsigned long c[2]; + } vlong; + + union + { + double d; + unsigned short c[2]; + } vshort; + + + /* Are we little or big endian? From Harbison&Steele. */ + u.l = 1; + bigendian = (u.c[sizeof (long int) - 1] == 1); + + zero_index = bigendian ? 1 : 0; + + vint.d = 1.0; + vlong.d = 1.0; + vshort.d = 1.0; + + if (sizeof(unsigned int) == 4) + { + if (vint.c[zero_index] != 0) + zero = 1; + } + else if (sizeof(unsigned long) == 4) + { + if (vlong.c[zero_index] != 0) + zero = 1; + } + else if (sizeof(unsigned short) == 4) + { + if (vshort.c[zero_index] != 0) + zero = 1; + } + + exit (zero); +} +]])], + [ac_cv_c_double_middle_endian=no], + [ac_cv_c_double_middle_endian=yes], + [ac_cv_c_double_middle=unknown])]) +case $ac_cv_c_double_middle_endian in + yes) + m4_default([$1], + [AC_DEFINE([DOUBLE_MIDDLE_ENDIAN], 1, + [Define to 1 if your processor stores the words in a double in + middle-endian format (like some ARMs).])]) ;; + no) + $2 ;; + *) + m4_default([$3], + [AC_MSG_WARN([unknown double endianness +presetting ac_cv_c_double_middle_endian=no (or yes) will help])]) ;; +esac +])dnl # AC_C_DOUBLE_MIDDLE_ENDIAN + + +AC_DEFUN(ERL_MONOTONIC_CLOCK, +[ + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur + # and Monterey, since it may step backwards. + if test "$3" = "yes"; then + case $host_os in + darwin*) + default_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW" + low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW_APPROX" + high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_RAW";; + *) + default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_BOOTTIME CLOCK_MONOTONIC" + low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST" + high_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_PRECISE";; + esac + else + case $host_os in + darwin*) + default_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW" + low_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW_APPROX" + high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_RAW";; + *) + default_resolution_clock_gettime_monotonic="CLOCK_HIGHRES CLOCK_UPTIME CLOCK_MONOTONIC" + low_resolution_clock_gettime_monotonic="CLOCK_MONOTONIC_COARSE CLOCK_UPTIME_FAST" + high_resolution_clock_gettime_monotonic="CLOCK_UPTIME_PRECISE";; + esac + fi + + case "$1" in + high_resolution) + check_msg="high resolution " + prefer_resolution_clock_gettime_monotonic="$high_resolution_clock_gettime_monotonic" + ;; + low_resolution) + check_msg="low resolution " + prefer_resolution_clock_gettime_monotonic="$low_resolution_clock_gettime_monotonic" + ;; + custom_resolution) + check_msg="custom resolution " + prefer_resolution_clock_gettime_monotonic="$2" + ;; + *) + check_msg="custom " + prefer_resolution_clock_gettime_monotonic="$2" + ;; + esac + + clock_gettime_lib="" + AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_lib="-lrt"]) + + save_LIBS="$LIBS" + LIBS="$LIBS $clock_gettime_lib" + + if test "$LD_MAY_BE_WEAK" != "no"; then + trust_test="#error May not be there due to weak linking" + else + trust_test="" + fi + + AC_CACHE_CHECK([for clock_gettime(CLOCK_MONOTONIC_RAW, _)], erl_cv_clock_gettime_monotonic_raw, + [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +$trust_test + ]], [[ + struct timespec ts; + long long result; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + result = ((long long) ts.tv_sec) * 1000000000LL + + ((long long) ts.tv_nsec); + ]])],[erl_cv_clock_gettime_monotonic_raw=yes],[erl_cv_clock_gettime_monotonic_raw=no]) + ]) + + AC_CACHE_CHECK([for clock_gettime() with ${check_msg}monotonic clock type], erl_cv_clock_gettime_monotonic_$1, + [ + for clock_type in $prefer_resolution_clock_gettime_monotonic $default_resolution_clock_gettime_monotonic $high_resolution_clock_gettime_monotonic $low_resolution_clock_gettime_monotonic; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +$trust_test + ]], [[ + struct timespec ts; + long long result; + clock_gettime($clock_type,&ts); + result = ((long long) ts.tv_sec) * 1000000000LL + + ((long long) ts.tv_nsec); + ]])],[erl_cv_clock_gettime_monotonic_$1=$clock_type],[erl_cv_clock_gettime_monotonic_$1=no]) + test $erl_cv_clock_gettime_monotonic_$1 = no || break + done + ]) + + LIBS="$save_LIBS" + + AS_IF( + [test "$LD_MAY_BE_WEAK" != "no"], + [ + AC_CHECK_FUNCS([clock_get_attributes gethrtime]) + ], + [ + AC_CHECK_FUNCS([clock_getres clock_get_attributes gethrtime]) + ]) + + AC_CACHE_CHECK([for mach clock_get_time() with monotonic clock type], erl_cv_mach_clock_get_time_monotonic, + [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + kern_return_t res; + clock_serv_t clk_srv; + mach_timespec_t time_spec; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clk_srv); + res = clock_get_time(clk_srv, &time_spec); + mach_port_deallocate(mach_task_self(), clk_srv); + ]])],[erl_cv_mach_clock_get_time_monotonic=yes],[erl_cv_mach_clock_get_time_monotonic=no]) + ]) + + erl_corrected_monotonic_clock=no + case $erl_cv_clock_gettime_monotonic_$1-$ac_cv_func_gethrtime-$erl_cv_mach_clock_get_time_monotonic-$host_os in + *-*-*-win32) + erl_monotonic_clock_func=WindowsAPI + ;; + CLOCK_*-*-*-linux*) + case $erl_cv_clock_gettime_monotonic_$1-$erl_cv_clock_gettime_monotonic_raw in + CLOCK_BOOTTIME-yes|CLOCK_MONOTONIC-yes) + erl_corrected_monotonic_clock=yes + ;; + *) + # We don't trust CLOCK_MONOTONIC to be NTP + # adjusted on linux systems that do not have + # CLOCK_MONOTONIC_RAW (although it seems to + # be...) + ;; + esac + erl_monotonic_clock_func=clock_gettime + ;; + no-no-no-linux*) + erl_monotonic_clock_func=times + ;; + CLOCK_*-*-*-*) + erl_monotonic_clock_func=clock_gettime + ;; + no-yes-*-*) + erl_monotonic_clock_func=gethrtime + ;; + no-no-yes-*) + erl_monotonic_clock_func=mach_clock_get_time + ;; + no-no-no-*) + erl_monotonic_clock_func=none + ;; + esac + + erl_monotonic_clock_low_resolution=no + erl_monotonic_clock_lib= + erl_monotonic_clock_id= + case $erl_monotonic_clock_func in + clock_gettime) + erl_monotonic_clock_id=$erl_cv_clock_gettime_monotonic_$1 + for low_res_id in $low_resolution_clock_gettime_monotonic; do + if test $erl_monotonic_clock_id = $low_res_id; then + erl_monotonic_clock_low_resolution=yes + break + fi + done + erl_monotonic_clock_lib=$clock_gettime_lib + ;; + mach_clock_get_time) + erl_monotonic_clock_id=SYSTEM_CLOCK + ;; + times) + erl_monotonic_clock_low_resolution=yes + ;; + *) + ;; + esac + +]) + +AC_DEFUN(ERL_WALL_CLOCK, +[ + default_resolution_clock_gettime_wall="CLOCK_REALTIME" + low_resolution_clock_gettime_wall="CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST" + high_resolution_clock_gettime_wall="CLOCK_REALTIME_PRECISE" + + case "$1" in + high_resolution) + check_msg="high resolution " + prefer_resolution_clock_gettime_wall="$high_resolution_clock_gettime_wall" + ;; + low_resolution) + check_msg="low resolution " + prefer_resolution_clock_gettime_wall="$low_resolution_clock_gettime_wall" + ;; + custom_resolution) + check_msg="custom resolution " + prefer_resolution_clock_gettime_wall="$2" + ;; + *) + check_msg="" + prefer_resolution_clock_gettime_wall= + ;; + esac + + clock_gettime_lib="" + AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_lib="-lrt"]) + + save_LIBS="$LIBS" + LIBS="$LIBS $clock_gettime_lib" + + if test "$LD_MAY_BE_WEAK" != "no"; then + trust_test="#error May not be there due to weak linking" + else + trust_test="" + fi + + AC_CACHE_CHECK([for clock_gettime() with ${check_msg}wall clock type], erl_cv_clock_gettime_wall_$1, + [ + for clock_type in $prefer_resolution_clock_gettime_wall $default_resolution_clock_gettime_wall $high_resolution_clock_gettime_wall $low_resolution_clock_gettime_wall; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +$trust_test + ]], [[ + struct timespec ts; + long long result; + clock_gettime($clock_type,&ts); + result = ((long long) ts.tv_sec) * 1000000000LL + + ((long long) ts.tv_nsec); + ]])],[erl_cv_clock_gettime_wall_$1=$clock_type],[erl_cv_clock_gettime_wall_$1=no]) + test $erl_cv_clock_gettime_wall_$1 = no || break + done + ]) + + LIBS="$save_LIBS" + + AS_IF([test "$LD_MAY_BE_WEAK" = "no"], + [ + AC_CHECK_FUNCS([clock_getres]) + ]) + + AC_CHECK_FUNCS([clock_get_attributes gettimeofday]) + + AC_CACHE_CHECK([for mach clock_get_time() with wall clock type], erl_cv_mach_clock_get_time_wall, + [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + kern_return_t res; + clock_serv_t clk_srv; + mach_timespec_t time_spec; + + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk_srv); + res = clock_get_time(clk_srv, &time_spec); + mach_port_deallocate(mach_task_self(), clk_srv); + ]])],[erl_cv_mach_clock_get_time_wall=yes],[erl_cv_mach_clock_get_time_wall=no]) + ]) + + erl_wall_clock_lib= + erl_wall_clock_low_resolution=no + erl_wall_clock_id= + case $1-$erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in + *-*-*-*-win32) + erl_wall_clock_func=WindowsAPI + erl_wall_clock_low_resolution=yes + ;; + high_resolution-no-yes-*-*) + erl_wall_clock_func=mach_clock_get_time + erl_wall_clock_id=CALENDAR_CLOCK + ;; + *-CLOCK_*-*-*-*) + erl_wall_clock_func=clock_gettime + erl_wall_clock_lib=$clock_gettime_lib + erl_wall_clock_id=$erl_cv_clock_gettime_wall_$1 + for low_res_id in $low_resolution_clock_gettime_wall; do + if test $erl_wall_clock_id = $low_res_id; then + erl_wall_clock_low_resolution=yes + break + fi + done + ;; + *-no-*-yes-*) + erl_wall_clock_func=gettimeofday + ;; + *) + erl_wall_clock_func=none + ;; + esac +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_CHECK_THR_LIB +dnl +dnl This macro may be used by any OTP application. +dnl +dnl LM_CHECK_THR_LIB sets THR_LIBS, THR_DEFS, and THR_LIB_NAME. It also +dnl checks for some pthread headers which will appear in DEFS or config.h. +dnl + +AC_DEFUN(LM_CHECK_THR_LIB, +[ + +NEED_NPTL_PTHREAD_H=no + +dnl win32? +AC_MSG_CHECKING([for native win32 threads]) +AS_IF( + [test "X$host_os" = "Xwin32"], + [ + AC_MSG_RESULT(yes) + THR_DEFS="-DWIN32_THREADS" + THR_LIBS= + THR_LIB_NAME=win32_threads + THR_LIB_TYPE=win32_threads + ], + [ + AC_MSG_RESULT(no) + THR_DEFS= + THR_LIBS= + THR_LIB_NAME= + THR_LIB_TYPE=posix_unknown + +dnl Try to find POSIX threads + +dnl The usual pthread lib... + AC_CHECK_LIB(pthread, pthread_create, THR_LIBS="-lpthread") + +dnl Very old versions of FreeBSD have pthreads in special c library, c_r... + AS_IF([test "x$THR_LIBS" = "x"], + [ + AC_CHECK_LIB([c_r], [pthread_create], [THR_LIBS="-lc_r"]) + ]) + +dnl QNX has pthreads in standard C library + AS_IF([test "x$THR_LIBS" = "x"], + [ + AC_CHECK_FUNC([pthread_create], [THR_LIBS="none_needed"]) + ]) + +dnl On ofs1 the '-pthread' switch should be used + AS_IF( + [test "x$THR_LIBS" = "x"], + [ + AC_MSG_CHECKING([if the '-pthread' switch can be used]) + saved_cflags=$CFLAGS + CFLAGS="$CFLAGS -pthread" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[pthread_create((void*)0,(void*)0,(void*)0,(void*)0);]])],[THR_DEFS="-pthread" + THR_LIBS="-pthread"],[]) + CFLAGS=$saved_cflags + if test "x$THR_LIBS" != "x"; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + ]) + + AS_IF( + [test "x$THR_LIBS" != "x"], + [ + THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" + THR_LIB_NAME=pthread + if test "x$THR_LIBS" = "xnone_needed"; then + THR_LIBS= + fi + AS_CASE( + [$host_os], + [solaris*], + [ + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" + ], + [linux*], + [ + THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" + + LM_CHECK_GETCONF + AC_MSG_CHECKING(for Native POSIX Thread Library) + libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` + if test $? -eq 0; then + case "$libpthr_vsn" in + *nptl*|*NPTL*) nptl=yes;; + *) nptl=no;; + esac + elif test "$cross_compiling" = "yes"; then + case "$erl_xcomp_linux_nptl" in + "") nptl=cross;; + yes|no) nptl=$erl_xcomp_linux_nptl;; + *) AC_MSG_ERROR([Bad erl_xcomp_linux_nptl value: $erl_xcomp_linux_nptl]);; + esac + else + nptl=no + fi + AC_MSG_RESULT($nptl) + if test $nptl = cross; then + nptl=yes + AC_MSG_WARN([result yes guessed because of cross compilation]) + fi + AS_IF( + [test $nptl = yes], + [ + THR_LIB_TYPE=posix_nptl + need_nptl_incldir=no + AC_CHECK_HEADER([nptl/pthread.h], + [need_nptl_incldir=yes + NEED_NPTL_PTHREAD_H=yes]) + AS_IF( + [test $need_nptl_incldir = yes], + [ + # Ahh... + nptl_path="$C_INCLUDE_PATH:$CPATH" + if test X$cross_compiling != Xyes; then + nptl_path="$nptl_path:/usr/local/include:/usr/include" + else + IROOT="$erl_xcomp_isysroot" + test "$IROOT" != "" || IROOT="$erl_xcomp_sysroot" + test "$IROOT" != "" || AC_MSG_ERROR([Don't know where to search for includes! Please set erl_xcomp_isysroot]) + nptl_path="$nptl_path:$IROOT/usr/local/include:$IROOT/usr/include" + fi + nptl_ws_path= + save_ifs="$IFS"; IFS=":" + for dir in $nptl_path; do + if test "x$dir" != "x"; then + nptl_ws_path="$nptl_ws_path $dir" + fi + done + IFS=$save_ifs + nptl_incldir= + for dir in $nptl_ws_path; do + AC_CHECK_HEADER([$dir/nptl/pthread.h], + [nptl_incldir=$dir/nptl]) + if test "x$nptl_incldir" != "x"; then + THR_DEFS="$THR_DEFS -isystem $nptl_incldir" + break + fi + done + if test "x$nptl_incldir" = "x"; then + AC_MSG_ERROR(Failed to locate nptl system include directory) + fi + ]) + ]) + ]) + + dnl We sometimes need THR_DEFS in order to find certain headers + dnl (at least for pthread.h on osf1). + saved_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $THR_DEFS" + + dnl + dnl Check for headers + dnl + + AC_CHECK_HEADER(pthread.h, + AC_DEFINE(HAVE_PTHREAD_H, 1, \ +[Define if you have the header file.])) + + dnl Some Linuxes have instead of + AC_CHECK_HEADER(pthread/mit/pthread.h, \ + AC_DEFINE(HAVE_MIT_PTHREAD_H, 1, \ +[Define if the pthread.h header file is in pthread/mit directory.])) + + dnl restore CPPFLAGS + CPPFLAGS=$saved_cppflags + + ]) + ]) + +]) + +AC_DEFUN(ERL_INTERNAL_LIBS, +[ + +ERTS_INTERNAL_X_LIBS= + +AC_CHECK_LIB(kstat, kstat_open, +[AC_DEFINE(HAVE_KSTAT, 1, [Define if you have kstat]) +ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat"]) + +AC_SUBST(ERTS_INTERNAL_X_LIBS) + +]) + +AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OP__, +[ + # $1 - atomic_op + + for atomic_bit_size in 32 64 128; do + case $atomic_bit_size in + 32) gcc_atomic_type="$gcc_atomic_type32";; + 64) gcc_atomic_type="$gcc_atomic_type64";; + 128) gcc_atomic_type="$gcc_atomic_type128";; + esac + gcc_atomic_lockfree="int x[[(2*__atomic_always_lock_free(sizeof($gcc_atomic_type), 0))-1]]" + case $1 in + __sync_add_and_fetch | __sync_fetch_and_and | __sync_fetch_and_or) + atomic_call="volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0);" + ;; + __sync_val_compare_and_swap) + atomic_call="volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0, ($gcc_atomic_type) 0);" + ;; + __atomic_store_n) + atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELAXED); $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELEASE);" + ;; + __atomic_load_n) + atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, __ATOMIC_RELAXED); res = $1(&var, __ATOMIC_ACQUIRE);" + ;; + __atomic_add_fetch| __atomic_fetch_and | __atomic_fetch_or) + atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELAXED); res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_ACQUIRE); res = $1(&var, ($gcc_atomic_type) 0, __ATOMIC_RELEASE);" + ;; + __atomic_compare_exchange_n) + atomic_call="$gcc_atomic_lockfree; volatile $gcc_atomic_type var; $gcc_atomic_type val; int res = $1(&var, &val, ($gcc_atomic_type) 0, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); res = $1(&var, &val, ($gcc_atomic_type) 0, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);" + ;; + *) + AC_MSG_ERROR([Internal error: missing implementation for $1]) + ;; + esac + eval atomic${atomic_bit_size}_call=\"$atomic_call\" + done + + AC_CACHE_CHECK([for 32-bit $1()], ethr_cv_32bit_$1, + [ + ethr_cv_32bit_$1=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[$atomic32_call]])],[ethr_cv_32bit_$1=yes],[]) + ]) + AC_CACHE_CHECK([for 64-bit $1()], ethr_cv_64bit_$1, + [ + ethr_cv_64bit_$1=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[$atomic64_call]])],[ethr_cv_64bit_$1=yes],[]) + ]) + AC_CACHE_CHECK([for 128-bit $1()], ethr_cv_128bit_$1, + [ + ethr_cv_128bit_$1=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[$atomic128_call]])],[ethr_cv_128bit_$1=yes],[]) + ]) + + case $ethr_cv_128bit_$1-$ethr_cv_64bit_$1-$ethr_cv_32bit_$1 in + no-no-no) + have_atomic_ops=0;; + no-no-yes) + have_atomic_ops=4;; + no-yes-no) + have_atomic_ops=8;; + no-yes-yes) + have_atomic_ops=12;; + yes-no-no) + have_atomic_ops=16;; + yes-no-yes) + have_atomic_ops=20;; + yes-yes-no) + have_atomic_ops=24;; + yes-yes-yes) + have_atomic_ops=28;; + esac + AC_DEFINE_UNQUOTED([ETHR_HAVE_$1], [$have_atomic_ops], [Define as a bitmask corresponding to the word sizes that $1() can handle on your system]) +]) + +AC_DEFUN(ETHR_CHK_IF_NOOP, +[ + ethr_test_filename="chk_if_$1$3_noop_config1test.$$" + cat > "${ethr_test_filename}.c" < "${ethr_test_filename}.c" </dev/null 2>&1; then + ethr_$1$3_noop=yes + else + ethr_$1$3_noop=no + fi + rm -f "${ethr_test_filename}.c" "${ethr_test_filename}1.o" "${ethr_test_filename}2.o" +]) + +AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OPS, +[ + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(long long) + AC_CHECK_SIZEOF(__int128_t) + + if test "$ac_cv_sizeof_short" = "4"; then + gcc_atomic_type32="short" + elif test "$ac_cv_sizeof_int" = "4"; then + gcc_atomic_type32="int" + elif test "$ac_cv_sizeof_long" = "4"; then + gcc_atomic_type32="long" + else + AC_MSG_ERROR([No 32-bit type found]) + fi + + if test "$ac_cv_sizeof_int" = "8"; then + gcc_atomic_type64="int" + elif test "$ac_cv_sizeof_long" = "8"; then + gcc_atomic_type64="long" + elif test "$ac_cv_sizeof_long_long" = "8"; then + gcc_atomic_type64="long long" + else + AC_MSG_ERROR([No 64-bit type found]) + fi + + if test "$ac_cv_sizeof___int128_t" = "16"; then + gcc_atomic_type128="__int128_t" + else + gcc_atomic_type128="#error " + fi + AC_CACHE_CHECK([for a working __sync_synchronize()], ethr_cv___sync_synchronize, + [ + ethr_cv___sync_synchronize=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ __sync_synchronize(); ]])],[ethr_cv___sync_synchronize=yes],[]) + if test $ethr_cv___sync_synchronize = yes; then + # + # Old gcc versions on at least x86 have a buggy + # __sync_synchronize() which does not emit a + # memory barrier. We try to detect this by + # compiling to assembly with and without + # __sync_synchronize() and compare the results. + # + ETHR_CHK_IF_NOOP(__sync_synchronize, [()], []) + if test $ethr___sync_synchronize_noop = yes; then + # Got a buggy implementation of + # __sync_synchronize... + ethr_cv___sync_synchronize="no; buggy implementation" + fi + fi + ]) + + if test "$ethr_cv___sync_synchronize" = "yes"; then + have_sync_synchronize_value="~0" + else + have_sync_synchronize_value="0" + fi + AC_DEFINE_UNQUOTED([ETHR_HAVE___sync_synchronize], [$have_sync_synchronize_value], [Define as a bitmask corresponding to the word sizes that __sync_synchronize() can handle on your system]) + + ETHR_CHK_GCC_ATOMIC_OP__(__sync_add_and_fetch) + ETHR_CHK_GCC_ATOMIC_OP__(__sync_fetch_and_and) + ETHR_CHK_GCC_ATOMIC_OP__(__sync_fetch_and_or) + ETHR_CHK_GCC_ATOMIC_OP__(__sync_val_compare_and_swap) + + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_store_n) + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_load_n) + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_add_fetch) + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_fetch_and) + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_fetch_or) + ETHR_CHK_GCC_ATOMIC_OP__(__atomic_compare_exchange_n) + + ethr_have_gcc_native_atomics=no + ethr_arm_dbm_sy_instr_val=0 + ethr_arm_dbm_st_instr_val=0 + ethr_arm_dbm_ld_instr_val=0 + ethr_arm_isb_sy_instr_val=0 + ethr_arm_dc_cvau_instr_val=0 + ethr_arm_ic_ivau_instr_val=0 + AS_CASE( + ["$GCC-$host_cpu"], + [yes-arm*|yes-aarch*], + [ + AC_CACHE_CHECK([for ARM 'dmb sy' instruction], ethr_cv_arm_dbm_sy_instr, + [ + ethr_cv_arm_dbm_sy_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__("dmb sy" : : : "memory"); + ]])],[ethr_cv_arm_dbm_sy_instr=yes],[]) + ]) + if test $ethr_cv_arm_dbm_sy_instr = yes; then + ethr_arm_dbm_sy_instr_val=1 + test $ethr_cv_64bit___atomic_compare_exchange_n = yes && + ethr_have_gcc_native_atomics=yes + fi + AC_CACHE_CHECK([for ARM 'dmb st' instruction], ethr_cv_arm_dbm_st_instr, + [ + ethr_cv_arm_dbm_st_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__("dmb st" : : : "memory"); + ]])],[ethr_cv_arm_dbm_st_instr=yes],[]) + ]) + if test $ethr_cv_arm_dbm_st_instr = yes; then + ethr_arm_dbm_st_instr_val=1 + fi + AC_CACHE_CHECK([for ARM 'dmb ld' instruction], ethr_cv_arm_dbm_ld_instr, + [ + ethr_cv_arm_dbm_ld_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__("dmb ld" : : : "memory"); + ]])],[ethr_cv_arm_dbm_ld_instr=yes],[]) + ]) + if test $ethr_cv_arm_dbm_ld_instr = yes; then + ethr_arm_dbm_ld_instr_val=1 + fi + AC_CACHE_CHECK([for ARM 'isb sy' instruction], ethr_cv_arm_isb_sy_instr, + [ + ethr_cv_arm_isb_sy_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__("isb sy\n" : : : "memory"); + ]])],[ethr_cv_arm_isb_sy_instr=yes],[]) + ]) + if test $ethr_cv_arm_isb_sy_instr = yes; then + ethr_arm_isb_sy_instr_val=1 + fi + AC_CACHE_CHECK([for ARM 'dc cvau' instruction], ethr_cv_arm_dc_cvau_instr, + [ + ethr_cv_arm_dc_cvau_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + char data[512]; __asm__ __volatile__("dc cvau, %0\n" :: "r" (data) : "memory"); + ]])],[ethr_cv_arm_dc_cvau_instr=yes],[]) + ]) + if test $ethr_cv_arm_dc_cvau_instr = yes; then + ethr_arm_dc_cvau_instr_val=1 + fi + AC_CACHE_CHECK([for ARM 'ic ivau' instruction], ethr_cv_arm_ic_ivau_instr, + [ + ethr_cv_arm_ic_ivau_instr=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + char data[512]; __asm__ __volatile__("ic ivau, %0\n" :: "r" (data) : "memory"); + ]])],[ethr_cv_arm_ic_ivau_instr=yes],[]) + ]) + if test $ethr_cv_arm_ic_ivau_instr = yes; then + ethr_arm_ic_ivau_instr_val=1 + fi + ]) + + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_INSTRUCTION], [$ethr_arm_dbm_sy_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb sy' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_ST_INSTRUCTION], [$ethr_arm_dbm_st_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb st' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DMB_LD_INSTRUCTION], [$ethr_arm_dbm_ld_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dmb ld' instruction, and are compiling for an ARM processor with ARM DMB instruction support, or not]) + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_ISB_SY_INSTRUCTION], [$ethr_arm_isb_sy_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'isb sy' instruction, and are compiling for an ARM processor with ARM ISB instruction support, or not]) + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION], [$ethr_arm_dc_cvau_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'dc cvau' instruction, and are compiling for an ARM processor with ARM DC instruction support, or not]) + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION], [$ethr_arm_ic_ivau_instr_val], [Define as a boolean indicating whether you have a gcc compatible compiler capable of generating the ARM 'ic ivau' instruction, and are compiling for an ARM processor with ARM IC instruction support, or not]) + + test $ethr_cv_32bit___sync_val_compare_and_swap = yes && + ethr_have_gcc_native_atomics=yes + test $ethr_cv_64bit___sync_val_compare_and_swap = yes && + ethr_have_gcc_native_atomics=yes + if test "$ethr_cv___sync_synchronize" = "yes"; then + test $ethr_cv_64bit___atomic_compare_exchange_n = yes && + ethr_have_gcc_native_atomics=yes + test $ethr_cv_32bit___atomic_compare_exchange_n = yes && + ethr_have_gcc_native_atomics=yes + fi + ethr_have_gcc_atomic_builtins=0 + if test $ethr_have_gcc_native_atomics = yes; then + ethr_native_atomic_implementation=gcc_sync + test $ethr_cv_32bit___atomic_compare_exchange_n = yes && ethr_have_gcc_atomic_builtins=1 + test $ethr_cv_64bit___atomic_compare_exchange_n = yes && ethr_have_gcc_atomic_builtins=1 + test $ethr_have_gcc_atomic_builtins = 1 && ethr_native_atomic_implementation=gcc_atomic_sync + fi + AC_DEFINE_UNQUOTED([ETHR_HAVE_GCC___ATOMIC_BUILTINS], [$ethr_have_gcc_atomic_builtins], [Define as a boolean indicating whether you have a gcc __atomic builtins or not]) + test $ethr_have_gcc_native_atomics = yes && ethr_have_native_atomics=yes +]) + +AC_DEFUN(ETHR_CHK_INTERLOCKED, +[ + ilckd="$1" + case "$2" in + "1") ilckd_call="${ilckd}(var);";; + "2") ilckd_call="${ilckd}(var, ($3) 0);";; + "3") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0);";; + "4") ilckd_call="${ilckd}(var, ($3) 0, ($3) 0, arr);";; + esac + AC_CACHE_CHECK([for ${ilckd}()],ethr_cv_have_$1, + [ethr_cv_have_$1=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #define WIN32_LEAN_AND_MEAN + #include + #include + ]], [[ + volatile $3 *var; + volatile $3 arr[2]; + + $ilckd_call + return 0; + ]])],[ethr_cv_have_$1=yes],[])]) + if [[ "${ethr_cv_have_$1}" = "yes" ]]; then + $4 + else + m4_default([$5], [:]) + fi +]) + +dnl ---------------------------------------------------------------------- +dnl +dnl ERL_FIND_ETHR_LIB +dnl +dnl NOTE! This macro may be changed at any time! Should *only* be used by +dnl ERTS! +dnl +dnl Find a thread library to use. Sets ETHR_LIBS to libraries to link +dnl with, ETHR_X_LIBS to extra libraries to link with (same as ETHR_LIBS +dnl except that the ethread lib itself is not included), ETHR_DEFS to +dnl defines to compile with, ETHR_THR_LIB_BASE to the name of the +dnl thread library which the ethread library is based on, and ETHR_LIB_NAME +dnl to the name of the library where the ethread implementation is located. +dnl ERL_FIND_ETHR_LIB currently searches for 'pthreads', and +dnl 'win32_threads'. If no thread library was found ETHR_LIBS, ETHR_X_LIBS, +dnl ETHR_DEFS, ETHR_THR_LIB_BASE, and ETHR_LIB_NAME are all set to the +dnl empty string. +dnl + +AC_DEFUN(ERL_FIND_ETHR_LIB, +[ + +AC_ARG_ENABLE(native-ethr-impls, + AS_HELP_STRING([--disable-native-ethr-impls], + [disable native ethread implementations]), +[ case "$enableval" in + no) disable_native_ethr_impls=yes ;; + *) disable_native_ethr_impls=no ;; + esac ], disable_native_ethr_impls=no) + +test "X$disable_native_ethr_impls" = "Xyes" && + AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations]) + +AC_ARG_ENABLE(x86-out-of-order, + AS_HELP_STRING([--enable-x86-out-of-order], + [enable x86/x84_64 out of order support (default disabled)])) + +AC_ARG_ENABLE(prefer-gcc-native-ethr-impls, + AS_HELP_STRING([--enable-prefer-gcc-native-ethr-impls], + [prefer gcc native ethread implementations]), +[ case "$enableval" in + yes) enable_prefer_gcc_native_ethr_impls=yes ;; + *) enable_prefer_gcc_native_ethr_impls=no ;; + esac ], enable_prefer_gcc_native_ethr_impls=no) + +test $enable_prefer_gcc_native_ethr_impls = yes && + AC_DEFINE(ETHR_PREFER_GCC_NATIVE_IMPLS, 1, [Define if you prefer gcc native ethread implementations]) + +AC_ARG_ENABLE(trust-gcc-atomic-builtins-memory-barriers, + AS_HELP_STRING([--enable-trust-gcc-atomic-builtins-memory-barriers], + [trust gcc atomic builtins memory barriers]), +[ case "$enableval" in + yes) trust_gcc_atomic_builtins_mbs=1 ;; + *) trust_gcc_atomic_builtins_mbs=0 ;; + esac ], trust_gcc_atomic_builtins_mbs=0) + +AC_DEFINE_UNQUOTED(ETHR_TRUST_GCC_ATOMIC_BUILTINS_MEMORY_BARRIERS, [$trust_gcc_atomic_builtins_mbs], [Define as a boolean indicating whether you trust gcc's __atomic_* builtins memory barrier implementations, or not]) + +AC_ARG_WITH(libatomic_ops, + AS_HELP_STRING([--with-libatomic_ops=PATH], + [specify and prefer usage of libatomic_ops in the ethread library])) + +AC_ARG_WITH(with_sparc_memory_order, + AS_HELP_STRING([--with-sparc-memory-order=TSO|PSO|RMO], + [specify sparc memory order (defaults to RMO)])) + +AC_ARG_ENABLE(ppc-lwsync-instruction, +AS_HELP_STRING([--enable-ppc-lwsync-instruction], [enable use of powerpc lwsync instruction]) +AS_HELP_STRING([--disable-ppc-lwsync-instruction], [disable use of powerpc lwsync instruction]), +[ case "$enableval" in + no) enable_lwsync=no ;; + *) enable_lwsync=yes ;; + esac ], +[ + AC_CHECK_SIZEOF(void *) + case $host_cpu-$ac_cv_sizeof_void_p in + macppc-8|powerpc-8|ppc-8|powerpc64-8|ppc64-8|powerpc64le-8|ppc64le-8|"Power Macintosh"-8) + enable_lwsync=yes;; + *) + enable_lwsync=undefined;; + esac ]) + +case $enable_lwsync in + no) + AC_DEFINE(ETHR_PPC_HAVE_NO_LWSYNC, [1], [Define if you do not have the powerpc lwsync instruction]) + ;; + yes) + AC_DEFINE(ETHR_PPC_HAVE_LWSYNC, [1], [Define if you have the powerpc lwsync instruction]) + ;; + *) + ;; +esac + +LM_CHECK_THR_LIB +ERL_INTERNAL_LIBS + +ERL_MONOTONIC_CLOCK(try_find_pthread_compatible, CLOCK_HIGHRES CLOCK_UPTIME_RAW CLOCK_MONOTONIC, no) + +case $erl_monotonic_clock_func in + clock_gettime) + AC_DEFINE(ETHR_HAVE_CLOCK_GETTIME_MONOTONIC, [1], [Define if you have a clock_gettime() with a monotonic clock]) + ;; + mach_clock_get_time) + AC_DEFINE(ETHR_HAVE_MACH_CLOCK_GET_TIME, [1], [Define if you have a mach clock_get_time() with a monotonic clock]) + ;; + gethrtime) + AC_DEFINE(ETHR_HAVE_GETHRTIME, [1], [Define if you have a monotonic gethrtime()]) + ;; + *) + ;; +esac + +if test "x$erl_monotonic_clock_id" != "x"; then + AC_DEFINE_UNQUOTED(ETHR_MONOTONIC_CLOCK_ID, [$erl_monotonic_clock_id], [Define to the monotonic clock id to use]) +fi + +ethr_native_atomic_implementation=none +ethr_have_native_atomics=no +ethr_have_native_spinlock=no +ETHR_THR_LIB_BASE="$THR_LIB_NAME" +ETHR_THR_LIB_BASE_TYPE="$THR_LIB_TYPE" +ETHR_DEFS="$THR_DEFS" +ETHR_X_LIBS="$THR_LIBS $ERTS_INTERNAL_X_LIBS $erl_monotonic_clock_lib" +ETHR_LIBS= +ETHR_LIB_NAME= + +ethr_modified_default_stack_size= + +AC_ARG_WITH(threadnames, +AS_HELP_STRING([--with-threadnames], [use pthread_setname to set the thread names (default)]) +AS_HELP_STRING([--without-threadnames], + [do not set any thread names]), +[], +[with_threadnames=yes]) + +dnl Name of lib where ethread implementation is located +ethr_lib_name=ethread + +AS_CASE( + ["$THR_LIB_NAME"], + [win32_threads], + [ + ETHR_THR_LIB_BASE_DIR=win + # * _WIN32_WINNT >= 0x0400 is needed for + # TryEnterCriticalSection + # * _WIN32_WINNT >= 0x0403 is needed for + # InitializeCriticalSectionAndSpinCount + # The ethread lib will refuse to build if _WIN32_WINNT < 0x0403. + # + # -D_WIN32_WINNT should have been defined in $CPPFLAGS; fetch it + # and save it in ETHR_DEFS. + found_win32_winnt=no + for cppflag in $CPPFLAGS; do + case $cppflag in + -DWINVER*) + ETHR_DEFS="$ETHR_DEFS $cppflag" + ;; + -D_WIN32_WINNT*) + ETHR_DEFS="$ETHR_DEFS $cppflag" + found_win32_winnt=yes + ;; + *) + ;; + esac + done + if test $found_win32_winnt = no; then + AC_MSG_ERROR([-D_WIN32_WINNT missing in CPPFLAGS]) + fi + + AC_DEFINE(ETHR_WIN32_THREADS, 1, [Define if you have win32 threads]) + + if test "X$disable_native_ethr_impls" = "Xyes"; then + have_interlocked_op=no + ethr_have_native_atomics=no + else + ETHR_CHK_INTERLOCKED([_InterlockedDecrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT, 1, [Define if you have _InterlockedDecrement()])) + ETHR_CHK_INTERLOCKED([_InterlockedDecrement_rel], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT_REL, 1, [Define if you have _InterlockedDecrement_rel()])) + ETHR_CHK_INTERLOCKED([_InterlockedIncrement], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT, 1, [Define if you have _InterlockedIncrement()])) + ETHR_CHK_INTERLOCKED([_InterlockedIncrement_acq], [1], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT_ACQ, 1, [Define if you have _InterlockedIncrement_acq()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD, 1, [Define if you have _InterlockedExchangeAdd()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd_acq], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD_ACQ, 1, [Define if you have _InterlockedExchangeAdd_acq()])) + ETHR_CHK_INTERLOCKED([_InterlockedAnd], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND, 1, [Define if you have _InterlockedAnd()])) + ETHR_CHK_INTERLOCKED([_InterlockedOr], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR, 1, [Define if you have _InterlockedOr()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchange], [2], [long], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE, 1, [Define if you have _InterlockedExchange()])) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange], [3], [long], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE, 1, [Define if you have _InterlockedCompareExchange()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_acq], [3], [long], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ, 1, [Define if you have _InterlockedCompareExchange_acq()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange_rel], [3], [long], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL, 1, [Define if you have _InterlockedCompareExchange_rel()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedDecrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64, 1, [Define if you have _InterlockedDecrement64()])) + ETHR_CHK_INTERLOCKED([_InterlockedDecrement64_rel], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDDECREMENT64_REL, 1, [Define if you have _InterlockedDecrement64_rel()])) + ETHR_CHK_INTERLOCKED([_InterlockedIncrement64], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64, 1, [Define if you have _InterlockedIncrement64()])) + ETHR_CHK_INTERLOCKED([_InterlockedIncrement64_acq], [1], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDINCREMENT64_ACQ, 1, [Define if you have _InterlockedIncrement64_acq()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64, 1, [Define if you have _InterlockedExchangeAdd64()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchangeAdd64_acq], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ, 1, [Define if you have _InterlockedExchangeAdd64_acq()])) + ETHR_CHK_INTERLOCKED([_InterlockedAnd64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDAND64, 1, [Define if you have _InterlockedAnd64()])) + ETHR_CHK_INTERLOCKED([_InterlockedOr64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDOR64, 1, [Define if you have _InterlockedOr64()])) + ETHR_CHK_INTERLOCKED([_InterlockedExchange64], [2], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDEXCHANGE64, 1, [Define if you have _InterlockedExchange64()])) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64], [3], [__int64], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64, 1, [Define if you have _InterlockedCompareExchange64()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_acq], [3], [__int64], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ, 1, [Define if you have _InterlockedCompareExchange64_acq()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange64_rel], [3], [__int64], + [AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL, 1, [Define if you have _InterlockedCompareExchange64_rel()]) + ethr_have_native_atomics=yes]) + ETHR_CHK_INTERLOCKED([_InterlockedCompareExchange128], [4], [__int64], AC_DEFINE_UNQUOTED(ETHR_HAVE__INTERLOCKEDCOMPAREEXCHANGE128, 1, [Define if you have _InterlockedCompareExchange128()])) + fi + if test "$ethr_have_native_atomics" = "yes"; then + ethr_native_atomic_implementation=windows + ethr_have_native_spinlock=yes + fi + ], + [pthread], + [ + ETHR_THR_LIB_BASE_DIR=pthread + AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads]) + case $host_os in + openbsd*) + # The default stack size is insufficient for our needs + # on OpenBSD. We increase it to 256 kilo words. + ethr_modified_default_stack_size=256;; + linux*) + ETHR_DEFS="$ETHR_DEFS -D_GNU_SOURCE" + + if test X$cross_compiling = Xyes; then + case X$erl_xcomp_linux_usable_sigusrx in + X) usable_sigusrx=cross;; + Xyes|Xno) usable_sigusrx=$erl_xcomp_linux_usable_sigusrx;; + *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigusrx value: $erl_xcomp_linux_usable_sigusrx]);; + esac + case X$erl_xcomp_linux_usable_sigaltstack in + X) usable_sigaltstack=cross;; + Xyes|Xno) usable_sigaltstack=$erl_xcomp_linux_usable_sigaltstack;; + *) AC_MSG_ERROR([Bad erl_xcomp_linux_usable_sigaltstack value: $erl_xcomp_linux_usable_sigaltstack]);; + esac + else + # FIXME: Test for actual problems instead of kernel versions + linux_kernel_vsn_=`uname -r` + case $linux_kernel_vsn_ in + [[0-1]].*|2.[[0-1]]|2.[[0-1]].*) + usable_sigusrx=no + usable_sigaltstack=no;; + 2.[[2-3]]|2.[[2-3]].*) + usable_sigusrx=yes + usable_sigaltstack=no;; + *) + usable_sigusrx=yes + usable_sigaltstack=yes;; + esac + fi + + AC_MSG_CHECKING(if SIGUSR1 and SIGUSR2 can be used) + AC_MSG_RESULT($usable_sigusrx) + if test $usable_sigusrx = cross; then + usable_sigusrx=yes + AC_MSG_WARN([result yes guessed because of cross compilation]) + fi + if test $usable_sigusrx = no; then + ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGUSRX" + fi + + AC_MSG_CHECKING(if sigaltstack can be used) + AC_MSG_RESULT($usable_sigaltstack) + if test $usable_sigaltstack = cross; then + usable_sigaltstack=yes + AC_MSG_WARN([result yes guessed because of cross compilation]) + fi + if test $usable_sigaltstack = no; then + ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK" + fi + ;; + *) ;; + esac + + dnl We sometimes need ETHR_DEFS in order to find certain headers + dnl (at least for pthread.h on osf1). + saved_cppflags="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $ETHR_DEFS" + + dnl We need the thread library in order to find some functions + saved_libs="$LIBS" + LIBS="$LIBS $ETHR_X_LIBS" + + dnl + dnl Check for headers + dnl + AC_CHECK_HEADER(pthread.h, \ + AC_DEFINE(ETHR_HAVE_PTHREAD_H, 1, \ +[Define if you have the header file.])) + + dnl Some Linuxes have instead of + AC_CHECK_HEADER(pthread/mit/pthread.h, \ + AC_DEFINE(ETHR_HAVE_MIT_PTHREAD_H, 1, \ +[Define if the pthread.h header file is in pthread/mit directory.])) + + if test $NEED_NPTL_PTHREAD_H = yes; then + AC_DEFINE(ETHR_NEED_NPTL_PTHREAD_H, 1, \ +[Define if you need the header file.]) + fi + + AC_CHECK_HEADER(sched.h, \ + AC_DEFINE(ETHR_HAVE_SCHED_H, 1, \ +[Define if you have the header file.])) + + AC_CHECK_HEADER(sys/time.h, \ + AC_DEFINE(ETHR_HAVE_SYS_TIME_H, 1, \ +[Define if you have the header file.])) + + AC_MSG_CHECKING([for usable PTHREAD_STACK_MIN]) + pthread_stack_min=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#if defined(ETHR_NEED_NPTL_PTHREAD_H) +#include +#elif defined(ETHR_HAVE_MIT_PTHREAD_H) +#include +#elif defined(ETHR_HAVE_PTHREAD_H) +#include +#endif + ]], [[return PTHREAD_STACK_MIN;]])],[pthread_stack_min=yes],[]) + + AC_MSG_RESULT([$pthread_stack_min]) + test $pthread_stack_min != yes || { + AC_DEFINE(ETHR_HAVE_USABLE_PTHREAD_STACK_MIN, 1, [Define if you can use PTHREAD_STACK_MIN]) + } + + dnl + dnl Check for functions + dnl + AC_CHECK_FUNC([pthread_spin_lock], \ + [ethr_have_native_spinlock=yes \ + AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \ +[Define if you have the pthread_spin_lock function.])]) + + have_sched_yield=no + have_librt_sched_yield=no + AC_CHECK_FUNC([sched_yield], [have_sched_yield=yes]) + AS_IF( + [test $have_sched_yield = no], + [ + AC_CHECK_LIB([rt], [sched_yield], + [have_librt_sched_yield=yes + ETHR_X_LIBS="$ETHR_X_LIBS -lrt"]) + ]) + AS_IF( + [test $have_sched_yield = yes || test $have_librt_sched_yield = yes], + [ + AC_DEFINE(ETHR_HAVE_SCHED_YIELD, 1, [Define if you have the sched_yield() function.]) + AC_MSG_CHECKING([whether sched_yield() returns an int]) + sched_yield_ret_int=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #ifdef ETHR_HAVE_SCHED_H + #include + #endif + ]], [[int sched_yield();]])],[sched_yield_ret_int=yes],[]) + AC_MSG_RESULT([$sched_yield_ret_int]) + if test $sched_yield_ret_int = yes; then + AC_DEFINE(ETHR_SCHED_YIELD_RET_INT, 1, [Define if sched_yield() returns an int.]) + fi + ]) + + have_pthread_yield=no + AC_CHECK_FUNC([pthread_yield], [have_pthread_yield=yes]) + AS_IF( + [test $have_pthread_yield = yes], + [ + AC_DEFINE(ETHR_HAVE_PTHREAD_YIELD, 1, [Define if you have the pthread_yield() function.]) + AC_MSG_CHECKING([whether pthread_yield() returns an int]) + pthread_yield_ret_int=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #if defined(ETHR_NEED_NPTL_PTHREAD_H) + #include + #elif defined(ETHR_HAVE_MIT_PTHREAD_H) + #include + #elif defined(ETHR_HAVE_PTHREAD_H) + #include + #endif + ]], [[int pthread_yield();]])],[pthread_yield_ret_int=yes],[]) + AC_MSG_RESULT([$pthread_yield_ret_int]) + if test $pthread_yield_ret_int = yes; then + AC_DEFINE(ETHR_PTHREAD_YIELD_RET_INT, 1, [Define if pthread_yield() returns an int.]) + fi + ]) + + have_pthread_rwlock_init=no + AC_CHECK_FUNC(pthread_rwlock_init, [have_pthread_rwlock_init=yes]) + AS_IF( + [test $have_pthread_rwlock_init = yes], + [ + ethr_have_pthread_rwlockattr_setkind_np=no + AC_CHECK_FUNC(pthread_rwlockattr_setkind_np, + [ethr_have_pthread_rwlockattr_setkind_np=yes]) + + AS_IF( + [test $ethr_have_pthread_rwlockattr_setkind_np = yes], + [ + AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP, 1, \ +[Define if you have the pthread_rwlockattr_setkind_np() function.]) + + AC_MSG_CHECKING([for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP]) + ethr_pthread_rwlock_writer_nonrecursive_initializer_np=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #if defined(ETHR_NEED_NPTL_PTHREAD_H) + #include + #elif defined(ETHR_HAVE_MIT_PTHREAD_H) + #include + #elif defined(ETHR_HAVE_PTHREAD_H) + #include + #endif + ]], [[ + pthread_rwlockattr_t *attr; + return pthread_rwlockattr_setkind_np(attr, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + ]])],[ethr_pthread_rwlock_writer_nonrecursive_initializer_np=yes],[]) + AC_MSG_RESULT([$ethr_pthread_rwlock_writer_nonrecursive_initializer_np]) + if test $ethr_pthread_rwlock_writer_nonrecursive_initializer_np = yes; then + AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 1, \ +[Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock attribute.]) + fi + ]) + ]) + + if test "$force_pthread_rwlocks" = "yes"; then + + AC_DEFINE(ETHR_FORCE_PTHREAD_RWLOCK, 1, \ +[Define if you want to force usage of pthread rwlocks]) + + if test $have_pthread_rwlock_init = yes; then + AC_MSG_WARN([Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues.]) + else + AC_MSG_ERROR([User forced usage of pthread rwlock, but no such implementation was found]) + fi + fi + + AC_CHECK_FUNC(pthread_attr_setguardsize, \ + AC_DEFINE(ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE, 1, \ +[Define if you have the pthread_attr_setguardsize function.])) + + AS_IF( + [test "x$erl_monotonic_clock_id" != "x"], + [ + AC_MSG_CHECKING(whether pthread_cond_timedwait() can use the monotonic clock $erl_monotonic_clock_id for timeout) + pthread_cond_timedwait_monotonic=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #if defined(ETHR_NEED_NPTL_PTHREAD_H) + # include + #elif defined(ETHR_HAVE_MIT_PTHREAD_H) + # include + #elif defined(ETHR_HAVE_PTHREAD_H) + # include + #endif + #include + #ifdef ETHR_HAVE_SYS_TIME_H + # include + #endif + #if defined(ETHR_HAVE_MACH_CLOCK_GET_TIME) + # include + # include + #endif + ]], [[ + int res; + pthread_condattr_t attr; + pthread_cond_t cond; + struct timespec cond_timeout; + pthread_mutex_t mutex; + res = pthread_condattr_init(&attr); + res = pthread_condattr_setclock(&attr, ETHR_MONOTONIC_CLOCK_ID); + res = pthread_cond_init(&cond, &attr); + res = pthread_cond_timedwait(&cond, &mutex, &cond_timeout); + ]])],[pthread_cond_timedwait_monotonic=yes],[]) + AC_MSG_RESULT([$pthread_cond_timedwait_monotonic]) + if test $pthread_cond_timedwait_monotonic = yes; then + AC_DEFINE(ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC, [1], [Define if pthread_cond_timedwait() can be used with a monotonic clock]) + fi + ]) + + linux_futex=no + AC_MSG_CHECKING([for Linux futexes]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include + #include + ]], [[ + int i = 1; + syscall(__NR_futex, (void *) &i, FUTEX_WAKE, 1, + (void*)0,(void*)0, 0); + syscall(__NR_futex, (void *) &i, FUTEX_WAIT, 0, + (void*)0,(void*)0, 0); + return 0; + ]])],[linux_futex=yes],[]) + AC_MSG_RESULT([$linux_futex]) + test $linux_futex = yes && AC_DEFINE(ETHR_HAVE_LINUX_FUTEX, 1, [Define if you have a linux futex implementation.]) + + pthread_setname=no + AC_MSG_CHECKING([for pthread_setname_np]) + old_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define __USE_GNU + #include ]], [[pthread_setname_np(pthread_self(), "name");]])],[pthread_setname=linux],[]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define __USE_GNU + #include ]], [[pthread_set_name_np(pthread_self(), "name");]])],[pthread_setname=bsd],[]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define _DARWIN_C_SOURCE + #include ]], [[pthread_setname_np("name");]])],[pthread_setname=darwin],[]) + AC_MSG_RESULT([$pthread_setname]) + case $with_threadnames-$pthread_setname in + yes-linux) AC_DEFINE(ETHR_HAVE_PTHREAD_SETNAME_NP_2, 1, + [Define if you have linux style pthread_setname_np]);; + yes-bsd) AC_DEFINE(ETHR_HAVE_PTHREAD_SET_NAME_NP_2, 1, + [Define if you have bsd style pthread_set_name_np]);; + yes-darwin) AC_DEFINE(ETHR_HAVE_PTHREAD_SETNAME_NP_1, 1, + [Define if you have darwin style pthread_setname_np]);; + *) ;; + esac + + pthread_getname=no + AC_MSG_CHECKING([for pthread_getname_np]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define __USE_GNU + #define _DARWIN_C_SOURCE + #include ]], [[char buff[256]; pthread_getname_np(pthread_self(), buff, 256);]])],[pthread_getname=linux],[]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define __USE_GNU + #define _DARWIN_C_SOURCE + #include ]], [[char buff[256]; pthread_getname_np(pthread_self(), buff);]])],[pthread_getname=ibm],[]) + AC_MSG_RESULT([$pthread_getname]) + case $pthread_getname in + linux) AC_DEFINE(ETHR_HAVE_PTHREAD_GETNAME_NP_3, 1, + [Define if you have linux style pthread_getname_np]);; + ibm) AC_DEFINE(ETHR_HAVE_PTHREAD_GETNAME_NP_2, 1, + [Define if you have ibm style pthread_getname_np]);; + *) ;; + esac + CFLAGS=$old_CFLAGS + + AS_IF( + [test "X$disable_native_ethr_impls" = "Xyes"], + [ + ethr_have_native_atomics=no + ], + [ + ETHR_CHK_GCC_ATOMIC_OPS([]) + + AC_MSG_CHECKING([for a usable libatomic_ops implementation]) + case "x$with_libatomic_ops" in + xno | xyes | x) + libatomic_ops_include= + ;; + *) + if test -d "${with_libatomic_ops}/include"; then + libatomic_ops_include="-I$with_libatomic_ops/include" + CPPFLAGS="$CPPFLAGS $libatomic_ops_include" + else + AC_MSG_ERROR([libatomic_ops include directory $with_libatomic_ops/include not found]) + fi;; + esac + ethr_have_libatomic_ops=no + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "atomic_ops.h"]], [[ + volatile AO_t x; + AO_t y; + int z; + + AO_nop_full(); +#if defined(AO_HAVE_store) + AO_store(&x, (AO_t) 0); +#elif defined(AO_HAVE_store_release) + AO_store_release(&x, (AO_t) 0); +#else +#error No store +#endif +#if defined(AO_HAVE_load) + z = AO_load(&x); +#elif defined(AO_HAVE_load_acquire) + z = AO_load_acquire(&x); +#else +#error No load +#endif +#if defined(AO_HAVE_compare_and_swap_full) + z = AO_compare_and_swap_full(&x, (AO_t) 0, (AO_t) 1); +#elif defined(AO_HAVE_compare_and_swap_release) + z = AO_compare_and_swap_release(&x, (AO_t) 0, (AO_t) 1); +#elif defined(AO_HAVE_compare_and_swap_acquire) + z = AO_compare_and_swap_acquire(&x, (AO_t) 0, (AO_t) 1); +#elif defined(AO_HAVE_compare_and_swap) + z = AO_compare_and_swap(&x, (AO_t) 0, (AO_t) 1); +#else +#error No compare_and_swap +#endif + ]])],[ethr_have_native_atomics=yes + ethr_native_atomic_implementation=libatomic_ops + ethr_have_libatomic_ops=yes],[]) + AC_MSG_RESULT([$ethr_have_libatomic_ops]) + AS_IF( + [test $ethr_have_libatomic_ops = yes], + [ + AC_CHECK_SIZEOF(AO_t, , + [ + #include + #include "atomic_ops.h" + ]) + AC_DEFINE_UNQUOTED(ETHR_SIZEOF_AO_T, $ac_cv_sizeof_AO_t, [Define to the size of AO_t if libatomic_ops is used]) + + AC_DEFINE(ETHR_HAVE_LIBATOMIC_OPS, 1, [Define if you have libatomic_ops atomic operations]) + if test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then + AC_DEFINE(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS, 1, [Define if you prefer libatomic_ops native ethread implementations]) + fi + ETHR_DEFS="$ETHR_DEFS $libatomic_ops_include" + ], + [test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"], + [ + AC_MSG_ERROR([No usable libatomic_ops implementation found]) + ]) + + case "$host_cpu" in + sparc | sun4u | sparc64 | sun4v) + case "$with_sparc_memory_order" in + "TSO") + AC_DEFINE(ETHR_SPARC_TSO, 1, [Define if only run in Sparc TSO mode]);; + "PSO") + AC_DEFINE(ETHR_SPARC_PSO, 1, [Define if only run in Sparc PSO, or TSO mode]);; + "RMO"|"") + AC_DEFINE(ETHR_SPARC_RMO, 1, [Define if run in Sparc RMO, PSO, or TSO mode]);; + *) + AC_MSG_ERROR([Unsupported Sparc memory order: $with_sparc_memory_order]);; + esac + ethr_native_atomic_implementation=ethread + ethr_have_native_atomics=yes;; + i86pc | i*86 | x86_64 | amd64) + if test "$enable_x86_out_of_order" = "yes"; then + AC_DEFINE(ETHR_X86_OUT_OF_ORDER, 1, [Define if x86/x86_64 out of order instructions should be synchronized]) + fi + ethr_native_atomic_implementation=ethread + ethr_have_native_atomics=yes;; + macppc | ppc | powerpc | "Power Macintosh") + ethr_native_atomic_implementation=ethread + ethr_have_native_atomics=yes;; + tile) + ethr_native_atomic_implementation=ethread + ethr_have_native_atomics=yes;; + *) + ;; + esac + + ]) + + test ethr_have_native_atomics = "yes" && ethr_have_native_spinlock=yes + + dnl Restore LIBS + LIBS=$saved_libs + dnl restore CPPFLAGS + CPPFLAGS=$saved_cppflags + + ]) + +AC_MSG_CHECKING([whether default stack size should be modified]) +if test "x$ethr_modified_default_stack_size" != "x"; then + AC_DEFINE_UNQUOTED(ETHR_MODIFIED_DEFAULT_STACK_SIZE, $ethr_modified_default_stack_size, [Define if you want to modify the default stack size]) + AC_MSG_RESULT([yes; to $ethr_modified_default_stack_size kilo words]) +else + AC_MSG_RESULT([no]) +fi + +if test "x$ETHR_THR_LIB_BASE" != "x"; then + ETHR_DEFS="-DUSE_THREADS $ETHR_DEFS" + ETHR_LIBS="-l$ethr_lib_name -lerts_internal_r $ETHR_X_LIBS" + ETHR_LIB_NAME=$ethr_lib_name +fi + +AC_CHECK_SIZEOF(void *) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF_PTR, $ac_cv_sizeof_void_p, [Define to the size of pointers]) + +AC_CHECK_SIZEOF(int) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF_INT, $ac_cv_sizeof_int, [Define to the size of int]) +AC_CHECK_SIZEOF(long) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG, $ac_cv_sizeof_long, [Define to the size of long]) +AC_CHECK_SIZEOF(long long) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF_LONG_LONG, $ac_cv_sizeof_long_long, [Define to the size of long long]) +AC_CHECK_SIZEOF(__int64) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT64, $ac_cv_sizeof___int64, [Define to the size of __int64]) +AC_CHECK_SIZEOF(__int128_t) +AC_DEFINE_UNQUOTED(ETHR_SIZEOF___INT128_T, $ac_cv_sizeof___int128_t, [Define to the size of __int128_t]) + + +case X$erl_xcomp_bigendian in + X) ;; + Xyes|Xno) ac_cv_c_bigendian=$erl_xcomp_bigendian;; + *) AC_MSG_ERROR([Bad erl_xcomp_bigendian value: $erl_xcomp_bigendian]);; +esac + +AC_C_BIGENDIAN + +if test "$ac_cv_c_bigendian" = "yes"; then + AC_DEFINE(ETHR_BIGENDIAN, 1, [Define if bigendian]) +fi + +case X$erl_xcomp_double_middle_endian in + X) ;; + Xyes|Xno|Xunknown) ac_cv_c_double_middle_endian=$erl_xcomp_double_middle_endian;; + *) AC_MSG_ERROR([Bad erl_xcomp_double_middle_endian value: $erl_xcomp_double_middle_endian]);; +esac + +AC_C_DOUBLE_MIDDLE_ENDIAN + +ETHR_X86_SSE2_ASM=no +AS_CASE( + ["$GCC-$ac_cv_sizeof_void_p-$host_cpu"], + [yes-4-i86pc | yes-4-i*86 | yes-4-x86_64 | yes-4-amd64], + [ + AC_MSG_CHECKING([for gcc sse2 asm support]) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -msse2" + gcc_sse2_asm=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + long long x, *y; + __asm__ __volatile__("movq %1, %0\n\t" : "=x"(x) : "m"(*y) : "memory"); + ]])],[gcc_sse2_asm=yes],[]) + CFLAGS="$save_CFLAGS" + AC_MSG_RESULT([$gcc_sse2_asm]) + if test "$gcc_sse2_asm" = "yes"; then + AC_DEFINE(ETHR_GCC_HAVE_SSE2_ASM_SUPPORT, 1, [Define if you use a gcc that supports -msse2 and understand sse2 specific asm statements]) + ETHR_X86_SSE2_ASM=yes + fi + ]) + +AS_CASE( + ["$GCC-$host_cpu"], + [yes-i86pc | yes-i*86 | yes-x86_64 | yes-amd64], + [ + if test $ac_cv_sizeof_void_p = 4; then + dw_cmpxchg="cmpxchg8b" + else + dw_cmpxchg="cmpxchg16b" + fi + + gcc_dw_cmpxchg_asm=no + gcc_pic_dw_cmpxchg_asm=no + gcc_cflags_pic=no + gcc_cmpxchg8b_pic_no_clobber_ebx=no + gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=no + + save_CFLAGS="$CFLAGS" + + # Check if it works out of the box using passed CFLAGS + # and with -fPIC added to CFLAGS if the passed CFLAGS + # doesn't trigger position independent code + pic_cmpxchg=unknown + while true; do + + case $pic_cmpxchg in + yes) pic_text="pic ";; + *) pic_text="";; + esac + + AC_MSG_CHECKING([for gcc $pic_text$dw_cmpxchg plain asm support]) + + plain_cmpxchg=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + char xchgd; + long new[2], xchg[2], *p; + __asm__ __volatile__( +#if ETHR_SIZEOF_PTR == 4 + "lock; cmpxchg8b %0\n\t" +#else + "lock; cmpxchg16b %0\n\t" +#endif + "setz %3\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "b"(new[0]) + : "cc", "memory"); + ]])],[plain_cmpxchg=yes],[]) + + AC_MSG_RESULT([$plain_cmpxchg]) + + if test $pic_cmpxchg = yes; then + gcc_pic_dw_cmpxchg_asm=$plain_cmpxchg + break + fi + + gcc_dw_cmpxchg_asm=$plain_cmpxchg + + # If not already compiling to position independent + # code add -fPIC to CFLAGS and do it again. This + # since we want also want to know how to compile + # to position independent code since this might + # cause problems with the use of the EBX register + # as input to the asm on 32-bit x86 and old gcc + # compilers (gcc vsn < 5). + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +#if !defined(__PIC__) || !__PIC__ +# error no pic +#endif + ]])],[pic_cmpxchg=yes + gcc_cflags_pic=yes],[pic_cmpxchg=no]) + + if test $pic_cmpxchg = yes; then + gcc_pic_dw_cmpxchg_asm=$gcc_dw_cmpxchg_asm + break + fi + + CFLAGS="$save_CFLAGS -fPIC" + pic_cmpxchg=yes + + done + + AS_IF( + [test $gcc_pic_dw_cmpxchg_asm = no && test $ac_cv_sizeof_void_p = 4], + [ + + AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX workaround]) + + # Check if we can work around it by managing the ebx + # register explicitly in the asm... + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + char xchgd; + long new[2], xchg[2], *p; + __asm__ __volatile__( + "pushl %%ebx\n\t" + "movl %8, %%ebx\n\t" + "lock; cmpxchg8b %0\n\t" + "setz %3\n\t" + "popl %%ebx\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=q"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "c"(new[1]), "r"(new[0]) + : "cc", "memory"); + ]])],[gcc_pic_dw_cmpxchg_asm=yes + gcc_cmpxchg8b_pic_no_clobber_ebx=yes],[]) + + AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) + + AS_IF( + [test $gcc_pic_dw_cmpxchg_asm = no], + [ + + AC_MSG_CHECKING([for gcc pic cmpxchg8b asm support with EBX and register shortage workarounds]) + # If no optimization is enabled we sometimes get a + # register shortage. Check if we can work around + # this... + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + char xchgd; + long new[2], xchg[2], *p; + __asm__ __volatile__( + "pushl %%ebx\n\t" + "movl (%7), %%ebx\n\t" + "movl 4(%7), %%ecx\n\t" + "lock; cmpxchg8b %0\n\t" + "setz %3\n\t" + "popl %%ebx\n\t" + : "=m"(*p), "=d"(xchg[1]), "=a"(xchg[0]), "=c"(xchgd) + : "m"(*p), "1"(xchg[1]), "2"(xchg[0]), "r"(new) + : "cc", "memory"); + + ]])],[gcc_pic_dw_cmpxchg_asm=yes + gcc_cmpxchg8b_pic_no_clobber_ebx=yes + gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage=yes],[]) + + AC_MSG_RESULT([$gcc_pic_dw_cmpxchg_asm]) + ]) + + if test $gcc_cflags_pic = yes; then + gcc_dw_cmpxchg_asm=$gcc_pic_dw_cmpxchg_asm + fi + ]) + + CFLAGS="$save_CFLAGS" + + if test "$gcc_cmpxchg8b_pic_no_clobber_ebx" = "yes"; then + AC_DEFINE(ETHR_CMPXCHG8B_PIC_NO_CLOBBER_EBX, 1, [Define if gcc won't let you clobber ebx with cmpxchg8b and position independent code]) + fi + if test "$gcc_cmpxchg8b_pic_no_clobber_ebx_register_shortage" = "yes"; then + AC_DEFINE(ETHR_CMPXCHG8B_REGISTER_SHORTAGE, 1, [Define if you get a register shortage with cmpxchg8b and position independent code]) + fi + if test "$gcc_dw_cmpxchg_asm" = "yes"; then + AC_DEFINE(ETHR_GCC_HAVE_DW_CMPXCHG_ASM_SUPPORT, 1, [Define if you use a gcc that supports the double word cmpxchg instruction]) + fi + ]) + +AC_DEFINE(ETHR_HAVE_ETHREAD_DEFINES, 1, \ +[Define if you have all ethread defines]) + +AC_SUBST(ETHR_X_LIBS) +AC_SUBST(ETHR_LIBS) +AC_SUBST(ETHR_LIB_NAME) +AC_SUBST(ETHR_DEFS) +AC_SUBST(ETHR_THR_LIB_BASE) +AC_SUBST(ETHR_THR_LIB_BASE_DIR) +AC_SUBST(ETHR_X86_SSE2_ASM) + +]) + + +dnl ---------------------------------------------------------------------- +dnl +dnl ERL_TIME_CORRECTION +dnl +dnl Check for primitives that can be used for implementing +dnl erts_os_monotonic_time() and erts_os_system_time() +dnl + +AC_DEFUN(ERL_TIME_CORRECTION, +[ + +AC_ARG_WITH(clock-resolution, +AS_HELP_STRING([--with-clock-resolution=high|low|default], + [specify wanted clock resolution])) + +AC_ARG_WITH(clock-gettime-realtime-id, +AS_HELP_STRING([--with-clock-gettime-realtime-id=CLOCKID], + [specify clock id to use with clock_gettime() for realtime time)])) + +AC_ARG_WITH(clock-gettime-monotonic-id, +AS_HELP_STRING([--with-clock-gettime-monotonic-id=CLOCKID], + [specify clock id to use with clock_gettime() for monotonic time)])) + +AC_ARG_ENABLE(prefer-elapsed-monotonic-time-during-suspend, +AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend], + [Prefer an OS monotonic time source with elapsed time during suspend]) +AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend], + [Do not prefer an OS monotonic time source with elapsed time during suspend]), +[ case "$enableval" in + yes) prefer_elapsed_monotonic_time_during_suspend=yes ;; + *) prefer_elapsed_monotonic_time_during_suspend=no ;; + esac ], prefer_elapsed_monotonic_time_during_suspend=no) + +AC_ARG_ENABLE(gettimeofday-as-os-system-time, + AS_HELP_STRING([--enable-gettimeofday-as-os-system-time], + [Force usage of gettimeofday() for OS system time]), +[ case "$enableval" in + yes) force_gettimeofday_os_system_time=yes ;; + *) force_gettimeofday_os_system_time=no ;; + esac ], force_gettimeofday_os_system_time=no) + +case "$with_clock_resolution" in + ""|no|yes) + with_clock_resolution=default;; + high|low|default) + ;; + *) + AC_MSG_ERROR([Invalid wanted clock resolution: $with_clock_resolution]) + ;; +esac + +AS_IF( + [test "$force_gettimeofday_os_system_time" = "yes"], + [ + + AC_CHECK_FUNCS([gettimeofday]) + if test "$ac_cv_func_gettimeofday" = "yes"; then + AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()]) + else + AC_MSG_ERROR([No gettimeofday() available]) + fi + ], + [ + # $force_gettimeofday_os_system_time != yes + +case "$with_clock_gettime_realtime_id" in + ""|no) + with_clock_gettime_realtime_id=no + ;; + CLOCK_*CPUTIME*) + AC_MSG_ERROR([Invalid clock_gettime() realtime clock id: Refusing to use the cputime clock id $with_clock_gettime_realtime_id as realtime clock id]) + ;; + CLOCK_MONOTONIC*|CLOCK_BOOTTIME*|CLOCK_UPTIME*|CLOCK_HIGHRES*) + AC_MSG_ERROR([Invalid clock_gettime() realtime clock id: Refusing to use the monotonic clock id $with_clock_gettime_realtime_id as realtime clock id]) + ;; + CLOCK_*) + ;; + *) + AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_realtime_id]) + ;; +esac + +AS_CASE(["$with_clock_resolution-$with_clock_gettime_realtime_id"], + [high-no], + [ + ERL_WALL_CLOCK([high_resolution]) + ], + [low-no], + [ + ERL_WALL_CLOCK([low_resolution]) + ], + [default-no], + [ + ERL_WALL_CLOCK([default_resolution]) + ], + [ + ERL_WALL_CLOCK([custom_resolution], [$with_clock_gettime_realtime_id]) + ]) + +case "$erl_wall_clock_func-$erl_wall_clock_id-$with_clock_gettime_realtime_id" in + *-*-no) + ;; + clock_gettime-$with_clock_gettime_realtime_id-$with_clock_gettime_realtime_id) + ;; + *) + AC_MSG_ERROR([$with_clock_gettime_realtime_id as clock id to clock_gettime() doesn't compile]) + ;; +esac + +case $erl_wall_clock_func in + none) + AC_MSG_ERROR([No wall clock source found]) + ;; + mach_clock_get_time) + AC_DEFINE(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_system_time() using mach clock_get_time()]) + ;; + clock_gettime) + AC_DEFINE(OS_SYSTEM_TIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_system_time() using clock_gettime()]) + ;; + gettimeofday) + AC_DEFINE(OS_SYSTEM_TIME_GETTIMEOFDAY, [1], [Define if you want to implement erts_os_system_time() using gettimeofday()]) + ;; + *) + ;; +esac + +if test "x$erl_wall_clock_id" != "x"; then + AC_DEFINE_UNQUOTED(WALL_CLOCK_ID_STR, ["$erl_wall_clock_id"], [Define as a string of wall clock id to use]) + AC_DEFINE_UNQUOTED(WALL_CLOCK_ID, [$erl_wall_clock_id], [Define to wall clock id to use]) +fi + + ]) # $force_gettimeofday_os_system_time != yes + +case "$with_clock_gettime_monotonic_id" in + ""|no) + with_clock_gettime_monotonic_id=no + ;; + CLOCK_*CPUTIME*) + AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the cputime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) + ;; + CLOCK_REALTIME*|CLOCK_TAI*) + AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use the realtime clock id $with_clock_gettime_monotonic_id as monotonic clock id]) + ;; + CLOCK_MONOTONIC) + case $host_os in + darwin*) + # CLOCK_MONOTONIC is buggy on MacOS (darwin), or at least on Big Sur + # and Monterey, since it may step backwards. + AC_MSG_ERROR([Invalid clock_gettime() monotonic clock id: Refusing to use $with_clock_gettime_monotonic_id as monotonic clock id since it is buggy on MacOS]);; + *) + ;; + esac;; + CLOCK_*) + ;; + *) + AC_MSG_ERROR([Invalid clock_gettime() clock id: $with_clock_gettime_monotonic_id]) + ;; +esac + +AS_CASE(["$with_clock_resolution-$with_clock_gettime_monotonic_id"], + [high-no], + [ + ERL_MONOTONIC_CLOCK([high_resolution], [undefined], [$prefer_elapsed_monotonic_time_during_suspend]) + ], + [low-no], + [ + ERL_MONOTONIC_CLOCK([low_resolution], [undefined], [$prefer_elapsed_monotonic_time_during_suspend]) + ], + [default-no], + [ + ERL_MONOTONIC_CLOCK([default_resolution], [undefined], [$prefer_elapsed_monotonic_time_during_suspend]) + ], + [ + ERL_MONOTONIC_CLOCK([custom_resolution], [$with_clock_gettime_monotonic_id], [$prefer_elapsed_monotonic_time_during_suspend]) + ]) + +case "$erl_monotonic_clock_func-$erl_monotonic_clock_id-$with_clock_gettime_monotonic_id" in + *-*-no) + ;; + clock_gettime-$with_clock_gettime_monotonic_id-$with_clock_gettime_monotonic_id) + ;; + *) + AC_MSG_ERROR([$with_clock_gettime_monotonic_id as clock id to clock_gettime() doesn't compile]) + ;; +esac + +case $erl_monotonic_clock_func in + times) + AC_DEFINE(OS_MONOTONIC_TIME_USING_TIMES, [1], [Define if you want to implement erts_os_monotonic_time() using times()]) + ;; + mach_clock_get_time) + AC_DEFINE(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_monotonic_time() using mach clock_get_time()]) + ;; + clock_gettime) + AC_DEFINE(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_monotonic_time() using clock_gettime()]) + ;; + gethrtime) + AC_DEFINE(OS_MONOTONIC_TIME_USING_GETHRTIME, [1], [Define if you want to implement erts_os_monotonic_time() using gethrtime()]) + ;; + *) + ;; +esac + +if test $erl_corrected_monotonic_clock = yes; then + AC_DEFINE(ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME, [1], [Define if OS monotonic clock is corrected]) +fi + +if test $erl_monotonic_clock_low_resolution = yes; then + AC_DEFINE(ERTS_HAVE_LOW_RESOLUTION_OS_MONOTONIC_LOW, [1], [Define if you have a low resolution OS monotonic clock]) +fi + +xrtlib= +if test "$erl_monotonic_clock_lib" != ""; then + xrtlib="$erl_monotonic_clock_lib" +fi +if test "$erl_wall_clock_lib" != ""; then + xrtlib="$erl_wall_clock_lib" +fi +if test "x$erl_monotonic_clock_id" != "x"; then + AC_DEFINE_UNQUOTED(MONOTONIC_CLOCK_ID_STR, ["$erl_monotonic_clock_id"], [Define as a string of monotonic clock id to use]) + AC_DEFINE_UNQUOTED(MONOTONIC_CLOCK_ID, [$erl_monotonic_clock_id], [Define to monotonic clock id to use]) +fi + +if test $erl_cv_clock_gettime_monotonic_raw = yes; then + AC_DEFINE(HAVE_CLOCK_GETTIME_MONOTONIC_RAW, [1], [Define if you have clock_gettime(CLOCK_MONOTONIC_RAW, _)]) +fi + +ERL_MONOTONIC_CLOCK([high_resolution], [undefined], [no]) + +case $erl_monotonic_clock_low_resolution-$erl_monotonic_clock_func in + no-mach_clock_get_time) + monotonic_hrtime=yes + AC_DEFINE(SYS_HRTIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_hrtime() using mach clock_get_time()]) + ;; + no-clock_gettime) + monotonic_hrtime=yes + AC_DEFINE(SYS_HRTIME_USING_CLOCK_GETTIME, [1], [Define if you want to implement erts_os_hrtime() using clock_gettime()]) + ;; + no-gethrtime) + monotonic_hrtime=yes + AC_DEFINE(SYS_HRTIME_USING_GETHRTIME, [1], [Define if you want to implement erts_os_hrtime() using gethrtime()]) + ;; + *) + monotonic_hrtime=no + ;; +esac + +if test $monotonic_hrtime = yes; then + AC_DEFINE(HAVE_MONOTONIC_ERTS_SYS_HRTIME, [1], [Define if you have a monotonic erts_os_hrtime() implementation]) +fi + +if test "x$erl_monotonic_clock_id" != "x"; then + AC_DEFINE_UNQUOTED(HRTIME_CLOCK_ID_STR, ["$erl_monotonic_clock_id"], [Define as a string of monotonic clock id to use]) + AC_DEFINE_UNQUOTED(HRTIME_CLOCK_ID, [$erl_monotonic_clock_id], [Define to monotonic clock id to use]) +fi + + +dnl +dnl Check if gethrvtime is working, and if to use procfs ioctl +dnl or (yet to be written) write to the procfs ctl file. +dnl + +AC_MSG_CHECKING([if gethrvtime works and how to use it]) +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +/* gethrvtime procfs ioctl test */ +/* These need to be undef:ed to not break activation of + * micro level process accounting on /proc/self + */ +#ifdef _LARGEFILE_SOURCE +# undef _LARGEFILE_SOURCE +#endif +#ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + long msacct = PR_MSACCT; + int fd; + long long start, stop; + int i; + pid_t pid = getpid(); + char proc_self[30] = "/proc/"; + + sprintf(proc_self+strlen(proc_self), "%lu", (unsigned long) pid); + if ( (fd = open(proc_self, O_WRONLY)) == -1) + exit(1); + if (ioctl(fd, PIOCSET, &msacct) < 0) + exit(2); + if (close(fd) < 0) + exit(3); + start = gethrvtime(); + for (i = 0; i < 100; i++) + stop = gethrvtime(); + if (start == 0) + exit(4); + if (start == stop) + exit(5); + exit(0); return 0; +} +]])],[erl_gethrvtime=procfs_ioctl],[erl_gethrvtime=false],[ +case X$erl_xcomp_gethrvtime_procfs_ioctl in + X) + erl_gethrvtime=cross;; + Xyes|Xno) + if test $erl_xcomp_gethrvtime_procfs_ioctl = yes; then + erl_gethrvtime=procfs_ioctl + else + erl_gethrvtime=false + fi;; + *) + AC_MSG_ERROR([Bad erl_xcomp_gethrvtime_procfs_ioctl value: $erl_xcomp_gethrvtime_procfs_ioctl]);; +esac +]) + +LIBRT=$xrtlib +AS_IF([test "$erl_gethrvtime" = "procfs_ioctl"], + [ + AC_DEFINE(HAVE_GETHRVTIME_PROCFS_IOCTL,[1], + [define if gethrvtime() works and uses ioctl() to /proc/self]) + AC_MSG_RESULT(uses ioctl to procfs) + ], + [ + if test $erl_gethrvtime = cross; then + erl_gethrvtime=false + AC_MSG_RESULT(cross) + AC_MSG_WARN([result 'not working' guessed because of cross compilation]) + else + AC_MSG_RESULT(not working) + fi + + dnl + dnl Check if clock_gettime (linux) is working + dnl + + AC_MSG_CHECKING([if clock_gettime can be used to get thread CPU time]) + save_libs=$LIBS + LIBS="-lrt" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + #include + #include + #include + #include + int main() { + long long start, stop; + int i; + struct timespec tp; + + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp) < 0) + exit(1); + start = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; + for (i = 0; i < 100; i++) + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp); + stop = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; + if (start == 0) + exit(4); + if (start == stop) + exit(5); + exit(0); return 0; + } + ]])],[erl_clock_gettime_cpu_time=yes],[erl_clock_gettime_cpu_time=no],[ + case X$erl_xcomp_clock_gettime_cpu_time in + X) erl_clock_gettime_cpu_time=cross;; + Xyes|Xno) erl_clock_gettime_cpu_time=$erl_xcomp_clock_gettime_cpu_time;; + *) AC_MSG_ERROR([Bad erl_xcomp_clock_gettime_cpu_time value: $erl_xcomp_clock_gettime_cpu_time]);; + esac + ]) + LIBS=$save_libs + AC_MSG_RESULT($erl_clock_gettime_cpu_time) + case $erl_clock_gettime_cpu_time in + yes) + AC_DEFINE(HAVE_CLOCK_GETTIME_CPU_TIME,[], + [define if clock_gettime() works for getting thread time]) + LIBRT=-lrt + ;; + cross) + erl_clock_gettime_cpu_time=no + AC_MSG_WARN([result no guessed because of cross compilation]) + ;; + *) + ;; + esac + ]) +AC_SUBST(LIBRT) +])dnl + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_TRY_ENABLE_CFLAG +dnl +dnl +dnl Tries a CFLAG and sees if it can be enabled without compiler errors +dnl $1: textual cflag to add +dnl $2: variable to store the modified CFLAG in +dnl Usage example LM_TRY_ENABLE_CFLAG([-Werror=return-type], [CFLAGS]) +dnl +dnl +AC_DEFUN([LM_TRY_ENABLE_CFLAG], [ + AC_MSG_CHECKING([if we can add $1 to $2 (via CFLAGS)]) + saved_CFLAGS=$CFLAGS; + CFLAGS="$1 $$2"; + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0;]])],[can_enable_flag=true],[can_enable_flag=false]) + CFLAGS=$saved_CFLAGS; + AS_IF( + [test "X$can_enable_flag" = "Xtrue"], + [ + AC_MSG_RESULT([yes]) + AS_VAR_SET($2, "$1 $$2") + ], + [ + AC_MSG_RESULT([no]) + ]) +]) + +AC_DEFUN([LM_CHECK_ENABLE_CFLAG], [ + AC_MSG_CHECKING([whether $CC accepts $1...]) + saved_CFLAGS=$CFLAGS; + CFLAGS="$1 $CFLAGS"; + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0;]])],[can_enable_flag=true],[can_enable_flag=false]) + CFLAGS=$saved_CFLAGS; + AS_IF( + [test "X$can_enable_flag" = "Xtrue"], + [ + AS_VAR_SET($2, true) + AC_MSG_RESULT([yes]) + ], + [ + AS_VAR_SET($2, false) + AC_MSG_RESULT([no]) + ]) +]) + +dnl +dnl LM_CHECK_RUN_CFLAG +dnl +dnl As LM_CHECK_ENABLE_CFLAG but also runs the command. Required for testing +dnl profile-guided optimization, for which the "use" step may require that the +dnl binary created in the "generate" step runs. +dnl +AC_DEFUN([LM_CHECK_RUN_CFLAG], [ + AC_MSG_CHECKING([whether $CC accepts $1...]) + saved_CFLAGS=$CFLAGS; + CFLAGS="$1 $CFLAGS"; + AC_RUN_IFELSE([AC_LANG_SOURCE([[]])],[return 0;],[can_enable_flag=true],[can_enable_flag=false]) + CFLAGS=$saved_CFLAGS; + AS_IF( + [test "X$can_enable_flag" = "Xtrue"], + [ + AS_VAR_SET($2, true) + AC_MSG_RESULT([yes]) + ], + [ + AS_VAR_SET($2, false) + AC_MSG_RESULT([no]) + ]) +]) + +dnl ERL_TRY_LINK_JAVA(CLASSES, FUNCTION-BODY +dnl [ACTION_IF_FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Freely inspired by AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[],[]). (Maybe better to create a +dnl AC_LANG_JAVA instead...) +AC_DEFUN(ERL_TRY_LINK_JAVA, +[java_link='$JAVAC conftest.java 1>&AS_MESSAGE_LOG_FD' +changequote(, )dnl +cat > conftest.java <&AS_MESSAGE_LOG_FD + cat conftest.java 1>&AS_MESSAGE_LOG_FD + echo "configure: PATH was $PATH" 1>&AS_MESSAGE_LOG_FD +ifelse([$4], , , [ rm -rf conftest* + $4 +])dnl + + ]) +rm -f conftest*]) +dnl #define UNSAFE_MASK 0xc0000000 /* Mask for bits that must be constant */ + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_HARDWARE_ARCH +dnl +dnl Determine target hardware in ARCH +dnl +AC_DEFUN([LM_HARDWARE_ARCH], [ + AC_MSG_CHECKING([target hardware architecture]) + if test "x$host_alias" != "x" -a "x$host_cpu" != "x"; then + chk_arch_=$host_cpu + else + chk_arch_=`uname -m` + fi + + case $chk_arch_ in + sun4u) ARCH=ultrasparc;; + sparc64) ARCH=sparc64;; + sun4v) ARCH=ultrasparc;; + i86pc) ARCH=x86;; + i386) ARCH=x86;; + i486) ARCH=x86;; + i586) ARCH=x86;; + i686) ARCH=x86;; + x86_64) ARCH=amd64;; + amd64) ARCH=amd64;; + macppc) ARCH=ppc;; + powerpc) ARCH=ppc;; + ppc) ARCH=ppc;; + ppc64) ARCH=ppc64;; + ppc64le) ARCH=ppc64le;; + powerpc64) ARCH=ppc64;; + powerpc64le) ARCH=ppc64le;; + "Power Macintosh") ARCH=ppc;; + arm64) ARCH=arm64;; + armv5b) ARCH=arm;; + armv5teb) ARCH=arm;; + armv5tel) ARCH=arm;; + armv5tejl) ARCH=arm;; + armv6l) ARCH=arm;; + armv6hl) ARCH=arm;; + armv7l) ARCH=arm;; + armv7hl) ARCH=arm;; + armv8*) ARCH=arm;; + aarch64) ARCH=arm64;; + aarch*) ARCH=arm;; + tile) ARCH=tile;; + e2k) ARCH=e2k;; + *) ARCH=noarch;; + esac + AC_MSG_RESULT($ARCH) + + dnl + dnl Convert between x86 and amd64 based on the compiler's mode. + dnl Ditto between ultrasparc and sparc64. + dnl + AC_MSG_CHECKING(whether compilation mode forces ARCH adjustment) + case "$ARCH-$ac_cv_sizeof_void_p" in + x86-8) + AC_MSG_RESULT(yes: adjusting ARCH=x86 to ARCH=amd64) + ARCH=amd64 + ;; + amd64-4) + AC_MSG_RESULT(yes: adjusting ARCH=amd64 to ARCH=x86) + ARCH=x86 + ;; + ultrasparc-8) + AC_MSG_RESULT(yes: adjusting ARCH=ultrasparc to ARCH=sparc64) + ARCH=sparc64 + ;; + sparc64-4) + AC_MSG_RESULT(yes: adjusting ARCH=sparc64 to ARCH=ultrasparc) + ARCH=ultrasparc + ;; + ppc64-4) + AC_MSG_RESULT(yes: adjusting ARCH=ppc64 to ARCH=ppc) + ARCH=ppc + ;; + ppc-8) + AC_MSG_RESULT(yes: adjusting ARCH=ppc to ARCH=ppc64) + ARCH=ppc64 + ;; + arm-8) + AC_MSG_RESULT(yes: adjusting ARCH=arm to ARCH=arm64) + ARCH=arm64 + ;; + *) + AC_MSG_RESULT(no: ARCH is $ARCH) + ;; + esac + + AC_SUBST(ARCH) +]) + +dnl +dnl-------------------------------------------------------------------- +dnl Dynamic Erlang Drivers +dnl +dnl Linking to produce dynamic Erlang drivers to be loaded by Erlang's +dnl Dynamic Driver Loader and Linker (DDLL). Below the prefix DED is an +dnl abbreviation for `Dynamic Erlang Driver'. +dnl +dnl For DED we need something quite sloppy, which allows undefined references +dnl (notably driver functions) in the resulting shared library. +dnl Example of Makefile rule (and settings of macros): +dnl +dnl LIBS = @LIBS@ +dnl LD = @DED_LD@ +dnl LDFLAGS = @DED_LDFLAGS@ +dnl soname = @ldsoname@ +dnl +dnl my_drv.so: my_drv.o my_utils.o +dnl $(LD) $(LDFLAGS) $(soname) $@ -o $@ $^ -lc $(LIBS) +dnl +dnl-------------------------------------------------------------------- +dnl + +AC_DEFUN(ERL_DED, + [ + +LM_CHECK_THR_LIB + +if test "$THR_DEFS" = ""; then + DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT" +else + DED_THR_DEFS="$THR_DEFS" +fi + +AC_SUBST(DED_THR_DEFS) + +ERL_DED_FLAGS + +]) + +AC_DEFUN(ERL_DED_FLAGS, + [ + +USER_LD=$LD +USER_LDFLAGS="$LDFLAGS" + +DED_CC=$CC +DED_GCC=$GCC + +DED_CFLAGS= +DED_OSTYPE=unix +case $host_os in + linux*) + DED_CFLAGS="-D_GNU_SOURCE" ;; + win32) + DED_CFLAGS="-D_WIN32_WINNT=0x0600 -DWINVER=0x0600" + DED_OSTYPE=win32 ;; + *) + ;; +esac + +DED_WARN_FLAGS="-Wall -Wstrict-prototypes" +case "$host_cpu" in + tile*) + # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs, + # and too strict for our taste. + ;; + *) + DED_WARN_FLAGS="$DED_WARN_FLAGS -Wmissing-prototypes";; +esac + +LM_TRY_ENABLE_CFLAG([-Wdeclaration-after-statement], [DED_WARN_FLAGS]) + +LM_TRY_ENABLE_CFLAG([-Werror=return-type], [DED_WERRORFLAGS]) +LM_TRY_ENABLE_CFLAG([-Werror=implicit], [DED_WERRORFLAGS]) +LM_TRY_ENABLE_CFLAG([-Werror=undef], [DED_WERRORFLAGS]) + +DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$DED_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common" +DED_INCLUDE=$DED_SYS_INCLUDE + +DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS" +AS_IF( + [test "x$GCC" = xyes], + [ + # Use -fno-common for gcc, that is link error if multiple definitions of + # global variables are encountered. This is ISO C compliant. + # Until version 10, gcc has had -fcommon as default, which allows and merges + # such dubious duplicates. + LM_TRY_ENABLE_CFLAG([-fno-common], [DED_CFLAGS]) + + LM_TRY_ENABLE_CFLAG([-fno-strict-aliasing], [DED_CFLAGS]) + + DED_STATIC_CFLAGS="$DED_CFLAGS" + DED_CFLAGS="$DED_CFLAGS -fPIC" + # Remove -fPIE and -fno-PIE + DED_CFLAGS=`echo $DED_CFLAGS | sed 's/-f\(no-\)\?PIE//g'` + ]) + +DED_EXT=so +case $host_os in + win32) DED_EXT=dll;; + darwin*) + DED_CFLAGS="$DED_CFLAGS -fno-common" + DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -fno-common";; + *) + ;; +esac + +DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER" + +if test "$CFLAG_RUNTIME_LIBRARY_PATH" = ""; then + + CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-R" + case $host_os in + darwin*) + CFLAG_RUNTIME_LIBRARY_PATH= + ;; + win32) + CFLAG_RUNTIME_LIBRARY_PATH= + ;; + osf*) + CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-rpath," + ;; + *) + ;; + esac + +fi + +# If DED_LD is set in environment, we expect all DED_LD* variables +# to be specified (cross compiling) +if test "x$DED_LD" = "x"; then + +DED_LDFLAGS_CONFTEST= + +DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-R" +case $host_os in + win32) + DED_LD="ld.sh" + DED_LDFLAGS="-dll" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH= + ;; + solaris2*|sysv4*) + DED_LDFLAGS="-G" + if test X${enable_m64_build} = Xyes; then + DED_LDFLAGS="-64 $DED_LDFLAGS" + fi + ;; + aix*|os400*) + DED_LDFLAGS="-G -bnoentry -bexpall" + ;; + freebsd2*) + # Non-ELF GNU linker + DED_LDFLAGS="-Bshareable" + ;; + darwin*) + # Mach-O linker: a shared lib and a loadable object file is not the same thing. + + if test "X${ERL_DED_FLAT_BUNDLE}" = "Xtrue"; then + # EI sets this variable when building its .so file as beam.smp + # has not been built yet and any ei lib will not + # link to beam.smp anyways + DED_LDFLAGS="-bundle -flat_namespace -undefined suppress" + else + # Cannot use flat namespaces for drivers/nifs as that may cause + # symbols to collide during loading + DED_LDFLAGS="-bundle -bundle_loader ${ERL_TOP}/bin/$host/beam.smp" + fi + # DED_LDFLAGS_CONFTEST is for use in configure tests only. We + # cannot use DED_LDFLAGS in configure tests since beam.smp has not + # been built yet... + DED_LDFLAGS_CONFTEST="-bundle" + if test X${enable_m64_build} = Xyes; then + DED_LDFLAGS="-m64 $DED_LDFLAGS" + else + if test X${enable_m32_build} = Xyes; then + DED_LDFLAGS="-m32 $DED_LDFLAGS" + else + AC_CHECK_SIZEOF(void *) + case "$ac_cv_sizeof_void_p" in + 8) + DED_LDFLAGS="-m64 $DED_LDFLAGS";; + *) + ;; + esac + fi + fi + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + ;; + linux*) + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + DED_LDFLAGS="-shared -Wl,-Bsymbolic" + if test X${enable_m64_build} = Xyes; then + DED_LDFLAGS="-m64 $DED_LDFLAGS" + fi; + if test X${enable_m32_build} = Xyes; then + DED_LDFLAGS="-m32 $DED_LDFLAGS" + fi + ;; + freebsd*) + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + DED_LDFLAGS="-shared" + if test X${enable_m64_build} = Xyes; then + DED_LDFLAGS="-m64 $DED_LDFLAGS" + fi; + if test X${enable_m32_build} = Xyes; then + DED_LDFLAGS="-m32 $DED_LDFLAGS" + fi + ;; + openbsd*) + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + DED_LDFLAGS="-shared" + ;; + osf*) + # NOTE! Whitespace after -rpath is important. + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath " + DED_LDFLAGS="-shared -expect_unresolved '*'" + ;; + *) + # assume GNU linker and ELF + DED_LDFLAGS="-shared" + # GNU linker has no option for 64bit build, should not propagate -m64 + ;; +esac + +if test "$DED_LD" = "" && test "$USER_LD" != ""; then + DED_LD="$USER_LD" + DED_LDFLAGS="$USER_LDFLAGS $DED_LDFLAGS" +fi + +DED_LIBS=$LIBS + +fi # "x$DED_LD" = "x" + +test "$DED_LDFLAGS_CONFTEST" != "" || DED_LDFLAGS_CONFTEST="$DED_LDFLAGS" + +AC_CHECK_TOOL(DED_LD, ld, false) +test "$DED_LD" != "false" || AC_MSG_ERROR([No linker found]) + +AC_MSG_CHECKING(for static compiler flags) +DED_STATIC_CFLAGS="$DED_WERRORFLAGS $DED_WFLAGS $DED_THR_DEFS $DED_STATIC_CFLAGS" +AC_MSG_RESULT([$DED_STATIC_CFLAGS]) +AC_MSG_CHECKING(for basic compiler flags for loadable drivers) +DED_BASIC_CFLAGS=$DED_CFLAGS +AC_MSG_RESULT([$DED_CFLAGS]) +AC_MSG_CHECKING(for compiler flags for loadable drivers) +DED_CFLAGS="$DED_WERRORFLAGS $DED_WARN_FLAGS $DED_THR_DEFS $DED_CFLAGS" +AC_MSG_RESULT([$DED_CFLAGS]) +AC_MSG_CHECKING(for linker for loadable drivers) +AC_MSG_RESULT([$DED_LD]) +AC_MSG_CHECKING(for linker flags for loadable drivers) +AC_MSG_RESULT([$DED_LDFLAGS]) +AC_MSG_CHECKING(for 'runtime library path' linker flag) +if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then + AC_MSG_RESULT([$DED_LD_FLAG_RUNTIME_LIBRARY_PATH]) +else + AC_MSG_RESULT([not found]) +fi + +AC_SUBST(DED_CC) +AC_SUBST(DED_GCC) +AC_SUBST(DED_EXT) +AC_SUBST(DED_SYS_INCLUDE) +AC_SUBST(DED_INCLUDE) +AC_SUBST(DED_BASIC_CFLAGS) +AC_SUBST(DED_CFLAGS) +AC_SUBST(DED_STATIC_CFLAGS) +AC_SUBST(DED_WARN_FLAGS) +AC_SUBST(DED_WERRORFLAGS) +AC_SUBST(DED_LD) +AC_SUBST(DED_LDFLAGS) +AC_SUBST(DED_LD_FLAG_RUNTIME_LIBRARY_PATH) +AC_SUBST(DED_LIBS) +AC_SUBST(DED_OSTYPE) + +]) diff --git a/make/autoconf/win32.config.cache.static b/make/autoconf/win32.config.cache.static new file mode 100755 index 000000000000..8aa795cdc00d --- /dev/null +++ b/make/autoconf/win32.config.cache.static @@ -0,0 +1,359 @@ +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +# ac_cv_build=${ac_cv_build=local-x86-pc-windows} +ac_cv_c_bigendian=${ac_cv_c_bigendian=no} +ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=no} +ac_cv_c_const=${ac_cv_c_const=yes} +# ac_cv_c_double_middle_endian=${ac_cv_c_double_middle_endian=no} +ac_cv_c_undeclared_builtin_options=${ac_cv_c_undeclared_builtin_options='none needed'} +ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=no} +ac_cv_decl_h_errno=${ac_cv_decl_h_errno=no} +ac_cv_decl_inaddr_loopback=${ac_cv_decl_inaddr_loopback=no} +ac_cv_decl_inaddr_loopback_rpc=${ac_cv_decl_inaddr_loopback_rpc=no} +ac_cv_decl_inaddr_loopback_winsock2=${ac_cv_decl_inaddr_loopback_winsock2=yes} +ac_cv_decl_so_bsdcompat=${ac_cv_decl_so_bsdcompat=no} +ac_cv_decl_sys_errlist=${ac_cv_decl_sys_errlist=no} +ac_cv_env_AR_set=set +ac_cv_env_AR_value=ar.sh +ac_cv_env_CCC_set= +ac_cv_env_CCC_value= +ac_cv_env_CC_set=set +ac_cv_env_CC_value=cc.sh +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +# ac_cv_env_CFLAG_RUNTIME_LIBRARY_PATH_set= +# ac_cv_env_CFLAG_RUNTIME_LIBRARY_PATH_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_CXXFLAGS_set= +ac_cv_env_CXXFLAGS_value= +ac_cv_env_CXX_set=set +ac_cv_env_CXX_value=cc.sh +# ac_cv_env_DED_LDFLAGS_set= +# ac_cv_env_DED_LDFLAGS_value= +# ac_cv_env_DED_LD_FLAG_RUNTIME_LIBRARY_PATH_set= +# ac_cv_env_DED_LD_FLAG_RUNTIME_LIBRARY_PATH_value= +# ac_cv_env_DED_LD_set= +# ac_cv_env_DED_LD_value= +# ac_cv_env_ERL_TOP_set=set +# ac_cv_env_ERL_TOP_value=$ERL_TOP +# ac_cv_env_GETCONF_set= +# ac_cv_env_GETCONF_value= +# ac_cv_env_LDFLAGS_set= +# ac_cv_env_LDFLAGS_value= +# ac_cv_env_LD_set= +# ac_cv_env_LD_value= +# ac_cv_env_LFS_CFLAGS_set= +# ac_cv_env_LFS_CFLAGS_value= +# ac_cv_env_LFS_LDFLAGS_set= +# ac_cv_env_LFS_LDFLAGS_value= +# ac_cv_env_LFS_LIBS_set= +# ac_cv_env_LFS_LIBS_value= +# ac_cv_env_LIBS_set= +# ac_cv_env_LIBS_value= +# ac_cv_env_RANLIB_set=set +# ac_cv_env_RANLIB_value=true +# ac_cv_env_STATIC_CFLAGS_set= +# ac_cv_env_STATIC_CFLAGS_value= +# ac_cv_env_YACC_set= +# ac_cv_env_YACC_value= +# ac_cv_env_YFLAGS_set= +# ac_cv_env_YFLAGS_value= +ac_cv_env_build_alias_set=set +ac_cv_env_build_alias_value=local-x86-pc-windows +# ac_cv_env_erl_xcomp_after_morecore_hook_set= +# ac_cv_env_erl_xcomp_after_morecore_hook_value= +# ac_cv_env_erl_xcomp_bigendian_set= +# ac_cv_env_erl_xcomp_bigendian_value= +# ac_cv_env_erl_xcomp_clock_gettime_cpu_time_set= +# ac_cv_env_erl_xcomp_clock_gettime_cpu_time_value= +# ac_cv_env_erl_xcomp_dlsym_brk_wrappers_set= +# ac_cv_env_erl_xcomp_dlsym_brk_wrappers_value= +# ac_cv_env_erl_xcomp_double_middle_endian_set= +# ac_cv_env_erl_xcomp_double_middle_endian_value= +# ac_cv_env_erl_xcomp_getaddrinfo_set= +# ac_cv_env_erl_xcomp_getaddrinfo_value= +# ac_cv_env_erl_xcomp_gethrvtime_procfs_ioctl_set= +# ac_cv_env_erl_xcomp_gethrvtime_procfs_ioctl_value= +# ac_cv_env_erl_xcomp_isysroot_set= +# ac_cv_env_erl_xcomp_isysroot_value= +# ac_cv_env_erl_xcomp_kqueue_set= +# ac_cv_env_erl_xcomp_kqueue_value= +# ac_cv_env_erl_xcomp_linux_nptl_set= +# ac_cv_env_erl_xcomp_linux_nptl_value= +# ac_cv_env_erl_xcomp_linux_usable_sigaltstack_set= +# ac_cv_env_erl_xcomp_linux_usable_sigaltstack_value= +# ac_cv_env_erl_xcomp_linux_usable_sigusrx_set= +# ac_cv_env_erl_xcomp_linux_usable_sigusrx_value= +# ac_cv_env_erl_xcomp_poll_set= +# ac_cv_env_erl_xcomp_poll_value= +# ac_cv_env_erl_xcomp_putenv_copy_set= +# ac_cv_env_erl_xcomp_putenv_copy_value= +# ac_cv_env_erl_xcomp_reliable_fpe_set= +# ac_cv_env_erl_xcomp_reliable_fpe_value= +# ac_cv_env_erl_xcomp_sysroot_set= +# ac_cv_env_erl_xcomp_sysroot_value= +ac_cv_env_host_alias_set=set +ac_cv_env_host_alias_value=local-x86-pc-windows +ac_cv_env_target_alias_set=set +ac_cv_env_target_alias_value=local-x86-pc-windows +ac_cv_exeext=${ac_cv_exeext=.exe} +ac_cv_func___brk=${ac_cv_func___brk=no} +ac_cv_func___sbrk=${ac_cv_func___sbrk=no} +ac_cv_func__brk=${ac_cv_func__brk=no} +ac_cv_func__doprnt=${ac_cv_func__doprnt=no} +ac_cv_func__sbrk=${ac_cv_func__sbrk=no} +ac_cv_func_brk=${ac_cv_func_brk=no} +ac_cv_func_clock_get_attributes=${ac_cv_func_clock_get_attributes=no} +ac_cv_func_clock_getres=${ac_cv_func_clock_getres=no} +ac_cv_func_closefrom=${ac_cv_func_closefrom=no} +ac_cv_func_connect=${ac_cv_func_connect=no} +ac_cv_func_decl_fread=${ac_cv_func_decl_fread=no} +ac_cv_func_dlopen=${ac_cv_func_dlopen=no} +ac_cv_func_dlvsym=${ac_cv_func_dlvsym=no} +ac_cv_func_endprotoent=${ac_cv_func_endprotoent=no} +ac_cv_func_fdatasync=${ac_cv_func_fdatasync=no} +ac_cv_func_finite=${ac_cv_func_finite=no} +ac_cv_func_flockfile=${ac_cv_func_flockfile=no} +ac_cv_func_fpsetmask=${ac_cv_func_fpsetmask=no} +ac_cv_func_fstat=${ac_cv_func_fstat=yes} +ac_cv_func_gethostbyname2=${ac_cv_func_gethostbyname2=no} +ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=no} +ac_cv_func_gethostbyname_r=${ac_cv_func_gethostbyname_r=no} +ac_cv_func_gethostname=${ac_cv_func_gethostname=no} +ac_cv_func_gethrtime=${ac_cv_func_gethrtime=no} +ac_cv_func_getifaddrs=${ac_cv_func_getifaddrs=no} +ac_cv_func_getipnodebyaddr=${ac_cv_func_getipnodebyaddr=no} +ac_cv_func_getipnodebyname=${ac_cv_func_getipnodebyname=no} +ac_cv_func_getprotoent=${ac_cv_func_getprotoent=no} +ac_cv_func_getrusage=${ac_cv_func_getrusage=no} +ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=no} +ac_cv_func_gmtime_r=${ac_cv_func_gmtime_r=no} +ac_cv_func_ieee_handler=${ac_cv_func_ieee_handler=no} +ac_cv_func_if_freenameindex=${ac_cv_func_if_freenameindex=no} +ac_cv_func_if_indextoname=${ac_cv_func_if_indextoname=no} +ac_cv_func_if_nameindex=${ac_cv_func_if_nameindex=no} +ac_cv_func_if_nametoindex=${ac_cv_func_if_nametoindex=no} +ac_cv_func_isinf=${ac_cv_func_isinf=no} +ac_cv_func_isnan=${ac_cv_func_isnan=no} +ac_cv_func_localtime_r=${ac_cv_func_localtime_r=no} +ac_cv_func_log2=${ac_cv_func_log2=yes} +ac_cv_func_madvise=${ac_cv_func_madvise=no} +ac_cv_func_mallopt=${ac_cv_func_mallopt=no} +ac_cv_func_memcpy=${ac_cv_func_memcpy=no} +ac_cv_func_memmove=${ac_cv_func_memmove=no} +ac_cv_func_mlockall=${ac_cv_func_mlockall=no} +ac_cv_func_mmap=${ac_cv_func_mmap=no} +ac_cv_func_mprotect=${ac_cv_func_mprotect=no} +ac_cv_func_mremap=${ac_cv_func_mremap=no} +ac_cv_func_nl_langinfo=${ac_cv_func_nl_langinfo=no} +ac_cv_func_openpty=${ac_cv_func_openpty=no} +ac_cv_func_poll=${ac_cv_func_poll=no} +ac_cv_func_posix2time=${ac_cv_func_posix2time=no} +ac_cv_func_posix_fadvise=${ac_cv_func_posix_fadvise=no} +ac_cv_func_posix_madvise=${ac_cv_func_posix_madvise=no} +ac_cv_func_posix_memalign=${ac_cv_func_posix_memalign=no} +ac_cv_func_ppoll=${ac_cv_func_ppoll=no} +ac_cv_func_pread=${ac_cv_func_pread=no} +ac_cv_func_pwrite=${ac_cv_func_pwrite=no} +ac_cv_func_res_gethostbyname=${ac_cv_func_res_gethostbyname=no} +ac_cv_func_sbrk=${ac_cv_func_sbrk=no} +ac_cv_func_setlocale=${ac_cv_func_setlocale=yes} +ac_cv_func_setns=${ac_cv_func_setns=no} +ac_cv_func_setprotoent=${ac_cv_func_setprotoent=no} +ac_cv_func_setsid=${ac_cv_func_setsid=no} +ac_cv_func_strerror=${ac_cv_func_strerror=yes} +ac_cv_func_strerror_r=${ac_cv_func_strerror_r=no} +ac_cv_func_strftime=${ac_cv_func_strftime=yes} +ac_cv_func_strlcat=${ac_cv_func_strlcat=no} +ac_cv_func_strlcpy=${ac_cv_func_strlcpy=no} +ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp=no} +ac_cv_func_time2posix=${ac_cv_func_time2posix=no} +ac_cv_func_vprintf=${ac_cv_func_vprintf=no} +ac_cv_func_vsyslog=${ac_cv_func_vsyslog=no} +ac_cv_func_writev=${ac_cv_func_writev=no} +ac_cv_have_decl_IN6ADDR_ANY_INIT=${ac_cv_have_decl_IN6ADDR_ANY_INIT=no} +ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT=${ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT=no} +ac_cv_have_decl_IPV6_V6ONLY=${ac_cv_have_decl_IPV6_V6ONLY=no} +ac_cv_have_decl_posix2time=${ac_cv_have_decl_posix2time=no} +ac_cv_have_decl_time2posix=${ac_cv_have_decl_time2posix=no} +ac_cv_header_arpa_nameser_h=${ac_cv_header_arpa_nameser_h=no} +ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=no} +ac_cv_header_dirent_ndir_h=${ac_cv_header_dirent_ndir_h=no} +ac_cv_header_dirent_sys_dir_h=${ac_cv_header_dirent_sys_dir_h=no} +ac_cv_header_dirent_sys_ndir_h=${ac_cv_header_dirent_sys_ndir_h=no} +ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=no} +ac_cv_header_elf_h=${ac_cv_header_elf_h=no} +ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes} +ac_cv_header_ieeefp_h=${ac_cv_header_ieeefp_h=no} +ac_cv_header_ifaddrs_h=${ac_cv_header_ifaddrs_h=no} +ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=yes} +ac_cv_header_langinfo_h=${ac_cv_header_langinfo_h=no} +ac_cv_header_libdlpi_h=${ac_cv_header_libdlpi_h=no} +ac_cv_header_libutil_h=${ac_cv_header_libutil_h=no} +ac_cv_header_limits_h=${ac_cv_header_limits_h=yes} +ac_cv_header_linux_errqueue_h=${ac_cv_header_linux_errqueue_h=no} +ac_cv_header_linux_falloc_h=${ac_cv_header_linux_falloc_h=no} +ac_cv_header_linux_types_h=${ac_cv_header_linux_types_h=no} +ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes} +ac_cv_header_net_errno_h=${ac_cv_header_net_errno_h=no} +ac_cv_header_net_if_dl_h=${ac_cv_header_net_if_dl_h=no} +ac_cv_header_netinet_sctp_h=${ac_cv_header_netinet_sctp_h=no} +ac_cv_header_netpacket_packet_h=${ac_cv_header_netpacket_packet_h=no} +ac_cv_header_poll_h=${ac_cv_header_poll_h=no} +ac_cv_header_pty_h=${ac_cv_header_pty_h=no} +ac_cv_header_sched_h=${ac_cv_header_sched_h=no} +ac_cv_header_sdkddkver_h=${ac_cv_header_sdkddkver_h=yes} +ac_cv_header_setns_h=${ac_cv_header_setns_h=no} +ac_cv_header_stdint_h=${ac_cv_header_stdint_h=yes} +ac_cv_header_stdio_h=${ac_cv_header_stdio_h=yes} +ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes} +ac_cv_header_string_h=${ac_cv_header_string_h=yes} +ac_cv_header_strings_h=${ac_cv_header_strings_h=no} +ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h=no} +ac_cv_header_sys_epoll_h=${ac_cv_header_sys_epoll_h=no} +ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h=no} +ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=no} +ac_cv_header_sys_mman_h=${ac_cv_header_sys_mman_h=no} +ac_cv_header_sys_resource_h=${ac_cv_header_sys_resource_h=no} +ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=no} +ac_cv_header_sys_socketio_h=${ac_cv_header_sys_socketio_h=no} +ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no} +ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes} +ac_cv_header_sys_stropts_h=${ac_cv_header_sys_stropts_h=no} +ac_cv_header_sys_sysctl_h=${ac_cv_header_sys_sysctl_h=no} +ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=no} +ac_cv_header_sys_timerfd_h=${ac_cv_header_sys_timerfd_h=no} +ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes} +ac_cv_header_sys_uio_h=${ac_cv_header_sys_uio_h=no} +ac_cv_header_sys_un_h=${ac_cv_header_sys_un_h=no} +ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=no} +ac_cv_header_syslog_h=${ac_cv_header_syslog_h=no} +ac_cv_header_unistd_h=${ac_cv_header_unistd_h=no} +ac_cv_header_util_h=${ac_cv_header_util_h=no} +ac_cv_header_utmp_h=${ac_cv_header_utmp_h=no} +ac_cv_header_valgrind_valgrind_h=${ac_cv_header_valgrind_valgrind_h=no} +ac_cv_header_windows_h=${ac_cv_header_windows_h=yes} +ac_cv_header_winsock2_h=${ac_cv_header_winsock2_h=yes} +ac_cv_header_ws2tcpip_h=${ac_cv_header_ws2tcpip_h=yes} +ac_cv_host=${ac_cv_host=local-x86-pc-windows} +ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen=no} +ac_cv_lib_dl_dlvsym=${ac_cv_lib_dl_dlvsym=no} +ac_cv_lib_dlpi_dlpi_open=${ac_cv_lib_dlpi_dlpi_open=no} +ac_cv_lib_inet_main=${ac_cv_lib_inet_main=no} +ac_cv_lib_kstat_kstat_open=${ac_cv_lib_kstat_kstat_open=no} +ac_cv_lib_kvm_kvm_open=${ac_cv_lib_kvm_kvm_open=no} +ac_cv_lib_m_sin=${ac_cv_lib_m_sin=no} +ac_cv_lib_nsl_main=${ac_cv_lib_nsl_main=no} +ac_cv_lib_rt_clock_gettime=${ac_cv_lib_rt_clock_gettime=no} +ac_cv_lib_socket_main=${ac_cv_lib_socket_main=yes} +ac_cv_lib_util_openpty=${ac_cv_lib_util_openpty=no} +ac_cv_member_struct_ifreq_ifr_enaddr=${ac_cv_member_struct_ifreq_ifr_enaddr=no} +ac_cv_member_struct_ifreq_ifr_hwaddr=${ac_cv_member_struct_ifreq_ifr_hwaddr=no} +ac_cv_member_struct_ifreq_ifr_ifindex=${ac_cv_member_struct_ifreq_ifr_ifindex=no} +ac_cv_member_struct_ifreq_ifr_index=${ac_cv_member_struct_ifreq_ifr_index=no} +ac_cv_member_struct_ifreq_ifr_map=${ac_cv_member_struct_ifreq_ifr_map=no} +ac_cv_member_struct_sockaddr_dl_sdl_len=${ac_cv_member_struct_sockaddr_dl_sdl_len=no} +ac_cv_member_struct_sockaddr_un_sun_path=${ac_cv_member_struct_sockaddr_un_sun_path=no} +ac_cv_objext=${ac_cv_objext=o} +# ac_cv_path_CP=${ac_cv_path_CP=/bin/cp} +# ac_cv_path_EGREP=${ac_cv_path_EGREP='/usr/bin/grep -E'} +# ac_cv_path_GREP=${ac_cv_path_GREP=/usr/bin/grep} +# ac_cv_path_MKDIR=${ac_cv_path_MKDIR=/bin/mkdir} +# ac_cv_path_PERL=${ac_cv_path_PERL=/usr/bin/perl} +# ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'} +ac_cv_prog_AR=${ac_cv_prog_AR=ar.sh} +ac_cv_prog_CC=${ac_cv_prog_CC=cc.sh} +ac_cv_prog_CPP=${ac_cv_prog_CPP='cc.sh -E'} +ac_cv_prog_GETCONF=${ac_cv_prog_GETCONF=getconf} +ac_cv_prog_JAVAC=${ac_cv_prog_JAVAC=javac.sh} +ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=true} +ac_cv_prog_cc_c11=${ac_cv_prog_cc_c11=no} +ac_cv_prog_cc_c89=${ac_cv_prog_cc_c89=no} +ac_cv_prog_cc_c99=${ac_cv_prog_cc_c99=no} +ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} +ac_cv_prog_cxx_11=${ac_cv_prog_cxx_11=no} +ac_cv_prog_cxx_g=${ac_cv_prog_cxx_g=yes} +ac_cv_prog_cxx_stdcxx=${ac_cv_prog_cxx_stdcxx=} +# ac_cv_prog_emu_cc=${ac_cv_prog_emu_cc=$ERL_TOP/erts/etc/win32/wsl_tools/vc/emu_cc.sh} +# ac_cv_prog_javac_ver_1_6=${ac_cv_prog_javac_ver_1_6=no} +# ac_cv_prog_mkdir_p=${ac_cv_prog_mkdir_p='/usr/bin/install -c -d'} +ac_cv_search_fdatasync=${ac_cv_search_fdatasync=no} +ac_cv_search_opendir=${ac_cv_search_opendir=no} +ac_cv_search_strerror=${ac_cv_search_strerror='none required'} +ac_cv_sizeof__Float16=${ac_cv_sizeof__Float16=0} +ac_cv_sizeof___int128_t=${ac_cv_sizeof___int128_t=0} +ac_cv_sizeof___int64=${ac_cv_sizeof___int64=8} +ac_cv_sizeof_char=${ac_cv_sizeof_char=1} +ac_cv_sizeof_int=${ac_cv_sizeof_int=4} +ac_cv_sizeof_long=${ac_cv_sizeof_long=4} +ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long=8} +ac_cv_sizeof_off_t=${ac_cv_sizeof_off_t=4} +ac_cv_sizeof_short=${ac_cv_sizeof_short=2} +ac_cv_sizeof_size_t=${ac_cv_sizeof_size_t=4} +ac_cv_sizeof_suseconds_t=${ac_cv_sizeof_suseconds_t=0} +ac_cv_sizeof_time_t=${ac_cv_sizeof_time_t=8} +ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=4} +ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no} +ac_cv_struct_tm=${ac_cv_struct_tm=time.h} +# ac_cv_sys_ipv6_support=${ac_cv_sys_ipv6_support=yes} +ac_cv_sys_multicast_support=${ac_cv_sys_multicast_support=no} +ac_cv_target=${ac_cv_target=local-x86-pc-windows} +ac_cv_type_off_t=${ac_cv_type_off_t=yes} +ac_cv_type_pid_t=${ac_cv_type_pid_t=no} +ac_cv_type_size_t=${ac_cv_type_size_t=yes} +erl_cv_clock_gettime_monotonic_default_resolution=${erl_cv_clock_gettime_monotonic_default_resolution=no} +erl_cv_clock_gettime_monotonic_high_resolution=${erl_cv_clock_gettime_monotonic_high_resolution=no} +erl_cv_clock_gettime_monotonic_raw=${erl_cv_clock_gettime_monotonic_raw=no} +erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=${erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=no} +erl_cv_clock_gettime_wall_default_resolution=${erl_cv_clock_gettime_wall_default_resolution=no} +erl_cv_mach_clock_get_time_monotonic=${erl_cv_mach_clock_get_time_monotonic=no} +erl_cv_mach_clock_get_time_wall=${erl_cv_mach_clock_get_time_wall=no} +erts_cv___after_morecore_hook_can_track_malloc=${erts_cv___after_morecore_hook_can_track_malloc=no} +erts_cv_fwrite_unlocked=${erts_cv_fwrite_unlocked=no} +erts_cv_have__end_symbol=${erts_cv_have__end_symbol=no} +erts_cv_have_end_symbol=${erts_cv_have_end_symbol=no} +erts_cv_have_in6addr_any=${erts_cv_have_in6addr_any=no} +erts_cv_have_in6addr_loopback=${erts_cv_have_in6addr_loopback=no} +erts_cv_putc_unlocked=${erts_cv_putc_unlocked=no} +erts_cv_windows_h_includes_winsock2_h=${erts_cv_windows_h_includes_winsock2_h=no} +ethr_cv_have__InterlockedAnd64=${ethr_cv_have__InterlockedAnd64=no} +ethr_cv_have__InterlockedAnd=${ethr_cv_have__InterlockedAnd=yes} +ethr_cv_have__InterlockedCompareExchange128=${ethr_cv_have__InterlockedCompareExchange128=no} +ethr_cv_have__InterlockedCompareExchange64=${ethr_cv_have__InterlockedCompareExchange64=yes} +# ethr_cv_have__InterlockedCompareExchange64_acq=${ethr_cv_have__InterlockedCompareExchange64_acq=no} +# ethr_cv_have__InterlockedCompareExchange64_rel=${ethr_cv_have__InterlockedCompareExchange64_rel=no} +ethr_cv_have__InterlockedCompareExchange=${ethr_cv_have__InterlockedCompareExchange=yes} +# ethr_cv_have__InterlockedCompareExchange_acq=${ethr_cv_have__InterlockedCompareExchange_acq=no} +# ethr_cv_have__InterlockedCompareExchange_rel=${ethr_cv_have__InterlockedCompareExchange_rel=no} +ethr_cv_have__InterlockedDecrement64=${ethr_cv_have__InterlockedDecrement64=no} +# ethr_cv_have__InterlockedDecrement64_rel=${ethr_cv_have__InterlockedDecrement64_rel=no} +ethr_cv_have__InterlockedDecrement=${ethr_cv_have__InterlockedDecrement=yes} +# ethr_cv_have__InterlockedDecrement_rel=${ethr_cv_have__InterlockedDecrement_rel=no} +ethr_cv_have__InterlockedExchange64=${ethr_cv_have__InterlockedExchange64=no} +ethr_cv_have__InterlockedExchange=${ethr_cv_have__InterlockedExchange=yes} +ethr_cv_have__InterlockedExchangeAdd64=${ethr_cv_have__InterlockedExchangeAdd64=no} +# ethr_cv_have__InterlockedExchangeAdd64_acq=${ethr_cv_have__InterlockedExchangeAdd64_acq=no} +ethr_cv_have__InterlockedExchangeAdd=${ethr_cv_have__InterlockedExchangeAdd=yes} +# ethr_cv_have__InterlockedExchangeAdd_acq=${ethr_cv_have__InterlockedExchangeAdd_acq=no} +ethr_cv_have__InterlockedIncrement64=${ethr_cv_have__InterlockedIncrement64=no} +# ethr_cv_have__InterlockedIncrement64_acq=${ethr_cv_have__InterlockedIncrement64_acq=no} +ethr_cv_have__InterlockedIncrement=${ethr_cv_have__InterlockedIncrement=yes} +# ethr_cv_have__InterlockedIncrement_acq=${ethr_cv_have__InterlockedIncrement_acq=no} +ethr_cv_have__InterlockedOr64=${ethr_cv_have__InterlockedOr64=no} +ethr_cv_have__InterlockedOr=${ethr_cv_have__InterlockedOr=yes} +i_cv_fallocate_works=${i_cv_fallocate_works=no} +i_cv_posix_fallocate_works=${i_cv_posix_fallocate_works=no} diff --git a/make/autoconf/win64.config.cache.static b/make/autoconf/win64.config.cache.static new file mode 100755 index 000000000000..a151aa345208 --- /dev/null +++ b/make/autoconf/win64.config.cache.static @@ -0,0 +1,358 @@ +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +# ac_cv_build=${ac_cv_build=local-x86_64-pc-windows} +ac_cv_c_bigendian=${ac_cv_c_bigendian=no} +ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=no} +ac_cv_c_const=${ac_cv_c_const=yes} +# ac_cv_c_double_middle_endian=${ac_cv_c_double_middle_endian=no} +ac_cv_c_undeclared_builtin_options=${ac_cv_c_undeclared_builtin_options='none needed'} +ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=no} +ac_cv_decl_h_errno=${ac_cv_decl_h_errno=no} +ac_cv_decl_inaddr_loopback=${ac_cv_decl_inaddr_loopback=no} +ac_cv_decl_inaddr_loopback_rpc=${ac_cv_decl_inaddr_loopback_rpc=no} +ac_cv_decl_inaddr_loopback_winsock2=${ac_cv_decl_inaddr_loopback_winsock2=yes} +ac_cv_decl_so_bsdcompat=${ac_cv_decl_so_bsdcompat=no} +ac_cv_decl_sys_errlist=${ac_cv_decl_sys_errlist=no} +ac_cv_env_AR_set=set +ac_cv_env_AR_value=ar.sh +ac_cv_env_CCC_set= +ac_cv_env_CCC_value= +ac_cv_env_CC_set=set +ac_cv_env_CC_value=cc.sh +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +# ac_cv_env_CFLAG_RUNTIME_LIBRARY_PATH_set= +# ac_cv_env_CFLAG_RUNTIME_LIBRARY_PATH_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_CXXFLAGS_set= +ac_cv_env_CXXFLAGS_value= +ac_cv_env_CXX_set=set +ac_cv_env_CXX_value=cc.sh +# ac_cv_env_DED_LDFLAGS_set= +# ac_cv_env_DED_LDFLAGS_value= +# ac_cv_env_DED_LD_FLAG_RUNTIME_LIBRARY_PATH_set= +# ac_cv_env_DED_LD_FLAG_RUNTIME_LIBRARY_PATH_value= +# ac_cv_env_DED_LD_set= +# ac_cv_env_DED_LD_value= +# ac_cv_env_ERL_TOP_set=set +# ac_cv_env_ERL_TOP_value=$ERL_TOP +# ac_cv_env_GETCONF_set= +# ac_cv_env_GETCONF_value= +# ac_cv_env_LDFLAGS_set= +# ac_cv_env_LDFLAGS_value= +# ac_cv_env_LD_set= +# ac_cv_env_LD_value= +# ac_cv_env_LFS_CFLAGS_set= +# ac_cv_env_LFS_CFLAGS_value= +# ac_cv_env_LFS_LDFLAGS_set= +# ac_cv_env_LFS_LDFLAGS_value= +# ac_cv_env_LFS_LIBS_set= +# ac_cv_env_LFS_LIBS_value= +# ac_cv_env_LIBS_set= +# ac_cv_env_LIBS_value= +# ac_cv_env_RANLIB_set=set +# ac_cv_env_RANLIB_value=true +# ac_cv_env_STATIC_CFLAGS_set= +# ac_cv_env_STATIC_CFLAGS_value= +# ac_cv_env_YACC_set= +# ac_cv_env_YACC_value= +# ac_cv_env_YFLAGS_set= +# ac_cv_env_YFLAGS_value= +ac_cv_env_build_alias_set=set +ac_cv_env_build_alias_value=local-x86_64-pc-windows +# ac_cv_env_erl_xcomp_after_morecore_hook_set= +# ac_cv_env_erl_xcomp_after_morecore_hook_value= +# ac_cv_env_erl_xcomp_bigendian_set= +# ac_cv_env_erl_xcomp_bigendian_value= +# ac_cv_env_erl_xcomp_clock_gettime_cpu_time_set= +# ac_cv_env_erl_xcomp_clock_gettime_cpu_time_value= +# ac_cv_env_erl_xcomp_dlsym_brk_wrappers_set= +# ac_cv_env_erl_xcomp_dlsym_brk_wrappers_value= +# ac_cv_env_erl_xcomp_double_middle_endian_set= +# ac_cv_env_erl_xcomp_double_middle_endian_value= +# ac_cv_env_erl_xcomp_getaddrinfo_set= +# ac_cv_env_erl_xcomp_getaddrinfo_value= +# ac_cv_env_erl_xcomp_gethrvtime_procfs_ioctl_set= +# ac_cv_env_erl_xcomp_gethrvtime_procfs_ioctl_value= +# ac_cv_env_erl_xcomp_isysroot_set= +# ac_cv_env_erl_xcomp_isysroot_value= +# ac_cv_env_erl_xcomp_kqueue_set= +# ac_cv_env_erl_xcomp_kqueue_value= +# ac_cv_env_erl_xcomp_linux_nptl_set= +# ac_cv_env_erl_xcomp_linux_nptl_value= +# ac_cv_env_erl_xcomp_linux_usable_sigaltstack_set= +# ac_cv_env_erl_xcomp_linux_usable_sigaltstack_value= +# ac_cv_env_erl_xcomp_linux_usable_sigusrx_set= +# ac_cv_env_erl_xcomp_linux_usable_sigusrx_value= +# ac_cv_env_erl_xcomp_poll_set= +# ac_cv_env_erl_xcomp_poll_value= +# ac_cv_env_erl_xcomp_putenv_copy_set= +# ac_cv_env_erl_xcomp_putenv_copy_value= +# ac_cv_env_erl_xcomp_reliable_fpe_set= +# ac_cv_env_erl_xcomp_reliable_fpe_value= +# ac_cv_env_erl_xcomp_sysroot_set= +# ac_cv_env_erl_xcomp_sysroot_value= +ac_cv_env_host_alias_set=set +ac_cv_env_host_alias_value=local-x86_64-pc-windows +ac_cv_env_target_alias_set=set +ac_cv_env_target_alias_value=local-x86_64-pc-windows +ac_cv_exeext=${ac_cv_exeext=.exe} +ac_cv_func___brk=${ac_cv_func___brk=no} +ac_cv_func___sbrk=${ac_cv_func___sbrk=no} +ac_cv_func__brk=${ac_cv_func__brk=no} +ac_cv_func__doprnt=${ac_cv_func__doprnt=no} +ac_cv_func__sbrk=${ac_cv_func__sbrk=no} +ac_cv_func_brk=${ac_cv_func_brk=no} +ac_cv_func_clock_get_attributes=${ac_cv_func_clock_get_attributes=no} +ac_cv_func_clock_getres=${ac_cv_func_clock_getres=no} +ac_cv_func_closefrom=${ac_cv_func_closefrom=no} +ac_cv_func_connect=${ac_cv_func_connect=no} +ac_cv_func_decl_fread=${ac_cv_func_decl_fread=yes} +ac_cv_func_dlopen=${ac_cv_func_dlopen=no} +ac_cv_func_dlvsym=${ac_cv_func_dlvsym=no} +ac_cv_func_endprotoent=${ac_cv_func_endprotoent=no} +ac_cv_func_fdatasync=${ac_cv_func_fdatasync=no} +ac_cv_func_finite=${ac_cv_func_finite=no} +ac_cv_func_flockfile=${ac_cv_func_flockfile=no} +ac_cv_func_fpsetmask=${ac_cv_func_fpsetmask=no} +ac_cv_func_fstat=${ac_cv_func_fstat=yes} +ac_cv_func_gethostbyname2=${ac_cv_func_gethostbyname2=no} +ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=yes} +ac_cv_func_gethostbyname_r=${ac_cv_func_gethostbyname_r=no} +ac_cv_func_gethostname=${ac_cv_func_gethostname=no} +ac_cv_func_gethrtime=${ac_cv_func_gethrtime=no} +ac_cv_func_getifaddrs=${ac_cv_func_getifaddrs=no} +ac_cv_func_getipnodebyaddr=${ac_cv_func_getipnodebyaddr=no} +ac_cv_func_getipnodebyname=${ac_cv_func_getipnodebyname=no} +ac_cv_func_getprotoent=${ac_cv_func_getprotoent=no} +ac_cv_func_getrusage=${ac_cv_func_getrusage=no} +ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=no} +ac_cv_func_gmtime_r=${ac_cv_func_gmtime_r=no} +ac_cv_func_ieee_handler=${ac_cv_func_ieee_handler=no} +ac_cv_func_if_freenameindex=${ac_cv_func_if_freenameindex=no} +ac_cv_func_if_indextoname=${ac_cv_func_if_indextoname=no} +ac_cv_func_if_nameindex=${ac_cv_func_if_nameindex=no} +ac_cv_func_if_nametoindex=${ac_cv_func_if_nametoindex=no} +ac_cv_func_isinf=${ac_cv_func_isinf=no} +ac_cv_func_isnan=${ac_cv_func_isnan=no} +ac_cv_func_localtime_r=${ac_cv_func_localtime_r=no} +ac_cv_func_log2=${ac_cv_func_log2=no} +ac_cv_func_madvise=${ac_cv_func_madvise=no} +ac_cv_func_mallopt=${ac_cv_func_mallopt=no} +ac_cv_func_memcpy=${ac_cv_func_memcpy=no} +ac_cv_func_memmove=${ac_cv_func_memmove=no} +ac_cv_func_mlockall=${ac_cv_func_mlockall=no} +ac_cv_func_mmap=${ac_cv_func_mmap=no} +ac_cv_func_mprotect=${ac_cv_func_mprotect=no} +ac_cv_func_mremap=${ac_cv_func_mremap=no} +ac_cv_func_nl_langinfo=${ac_cv_func_nl_langinfo=no} +ac_cv_func_openpty=${ac_cv_func_openpty=no} +ac_cv_func_poll=${ac_cv_func_poll=no} +ac_cv_func_posix2time=${ac_cv_func_posix2time=no} +ac_cv_func_posix_fadvise=${ac_cv_func_posix_fadvise=no} +ac_cv_func_posix_madvise=${ac_cv_func_posix_madvise=no} +ac_cv_func_posix_memalign=${ac_cv_func_posix_memalign=no} +ac_cv_func_ppoll=${ac_cv_func_ppoll=no} +ac_cv_func_pread=${ac_cv_func_pread=no} +ac_cv_func_pwrite=${ac_cv_func_pwrite=no} +ac_cv_func_res_gethostbyname=${ac_cv_func_res_gethostbyname=no} +ac_cv_func_sbrk=${ac_cv_func_sbrk=no} +ac_cv_func_setlocale=${ac_cv_func_setlocale=yes} +ac_cv_func_setns=${ac_cv_func_setns=no} +ac_cv_func_setprotoent=${ac_cv_func_setprotoent=no} +ac_cv_func_setsid=${ac_cv_func_setsid=no} +ac_cv_func_strerror=${ac_cv_func_strerror=yes} +ac_cv_func_strerror_r=${ac_cv_func_strerror_r=no} +ac_cv_func_strftime=${ac_cv_func_strftime=yes} +ac_cv_func_strlcat=${ac_cv_func_strlcat=no} +ac_cv_func_strlcpy=${ac_cv_func_strlcpy=no} +ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp=no} +ac_cv_func_time2posix=${ac_cv_func_time2posix=no} +ac_cv_func_vprintf=${ac_cv_func_vprintf=no} +ac_cv_func_vsyslog=${ac_cv_func_vsyslog=no} +ac_cv_func_writev=${ac_cv_func_writev=no} +ac_cv_have_decl_IN6ADDR_ANY_INIT=${ac_cv_have_decl_IN6ADDR_ANY_INIT=no} +ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT=${ac_cv_have_decl_IN6ADDR_LOOPBACK_INIT=no} +ac_cv_have_decl_IPV6_V6ONLY=${ac_cv_have_decl_IPV6_V6ONLY=no} +ac_cv_have_decl_posix2time=${ac_cv_have_decl_posix2time=no} +ac_cv_have_decl_time2posix=${ac_cv_have_decl_time2posix=no} +ac_cv_header_arpa_nameser_h=${ac_cv_header_arpa_nameser_h=no} +ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=no} +ac_cv_header_dirent_ndir_h=${ac_cv_header_dirent_ndir_h=no} +ac_cv_header_dirent_sys_dir_h=${ac_cv_header_dirent_sys_dir_h=no} +ac_cv_header_dirent_sys_ndir_h=${ac_cv_header_dirent_sys_ndir_h=no} +ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=no} +ac_cv_header_elf_h=${ac_cv_header_elf_h=no} +ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes} +ac_cv_header_ieeefp_h=${ac_cv_header_ieeefp_h=no} +ac_cv_header_ifaddrs_h=${ac_cv_header_ifaddrs_h=no} +ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=yes} +ac_cv_header_langinfo_h=${ac_cv_header_langinfo_h=no} +ac_cv_header_libdlpi_h=${ac_cv_header_libdlpi_h=no} +ac_cv_header_libutil_h=${ac_cv_header_libutil_h=no} +ac_cv_header_limits_h=${ac_cv_header_limits_h=yes} +ac_cv_header_linux_errqueue_h=${ac_cv_header_linux_errqueue_h=no} +ac_cv_header_linux_falloc_h=${ac_cv_header_linux_falloc_h=no} +ac_cv_header_linux_types_h=${ac_cv_header_linux_types_h=no} +ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes} +ac_cv_header_net_errno_h=${ac_cv_header_net_errno_h=no} +ac_cv_header_net_if_dl_h=${ac_cv_header_net_if_dl_h=no} +ac_cv_header_netinet_sctp_h=${ac_cv_header_netinet_sctp_h=no} +ac_cv_header_netpacket_packet_h=${ac_cv_header_netpacket_packet_h=no} +ac_cv_header_poll_h=${ac_cv_header_poll_h=no} +ac_cv_header_pty_h=${ac_cv_header_pty_h=no} +ac_cv_header_sched_h=${ac_cv_header_sched_h=no} +ac_cv_header_sdkddkver_h=${ac_cv_header_sdkddkver_h=yes} +ac_cv_header_setns_h=${ac_cv_header_setns_h=no} +ac_cv_header_stdint_h=${ac_cv_header_stdint_h=yes} +ac_cv_header_stdio_h=${ac_cv_header_stdio_h=yes} +ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes} +ac_cv_header_string_h=${ac_cv_header_string_h=yes} +ac_cv_header_strings_h=${ac_cv_header_strings_h=no} +ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h=no} +ac_cv_header_sys_epoll_h=${ac_cv_header_sys_epoll_h=no} +ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h=no} +ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=no} +ac_cv_header_sys_mman_h=${ac_cv_header_sys_mman_h=no} +ac_cv_header_sys_resource_h=${ac_cv_header_sys_resource_h=no} +ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=no} +ac_cv_header_sys_socketio_h=${ac_cv_header_sys_socketio_h=no} +ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no} +ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes} +ac_cv_header_sys_stropts_h=${ac_cv_header_sys_stropts_h=no} +ac_cv_header_sys_sysctl_h=${ac_cv_header_sys_sysctl_h=no} +ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=no} +ac_cv_header_sys_timerfd_h=${ac_cv_header_sys_timerfd_h=no} +ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes} +ac_cv_header_sys_uio_h=${ac_cv_header_sys_uio_h=no} +ac_cv_header_sys_un_h=${ac_cv_header_sys_un_h=no} +ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=no} +ac_cv_header_syslog_h=${ac_cv_header_syslog_h=no} +ac_cv_header_unistd_h=${ac_cv_header_unistd_h=no} +ac_cv_header_util_h=${ac_cv_header_util_h=no} +ac_cv_header_utmp_h=${ac_cv_header_utmp_h=no} +ac_cv_header_valgrind_valgrind_h=${ac_cv_header_valgrind_valgrind_h=no} +ac_cv_header_windows_h=${ac_cv_header_windows_h=yes} +ac_cv_header_winsock2_h=${ac_cv_header_winsock2_h=yes} +ac_cv_header_ws2tcpip_h=${ac_cv_header_ws2tcpip_h=yes} +ac_cv_host=${ac_cv_host=local-x86_64-pc-windows} +ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen=no} +ac_cv_lib_dl_dlvsym=${ac_cv_lib_dl_dlvsym=no} +ac_cv_lib_dlpi_dlpi_open=${ac_cv_lib_dlpi_dlpi_open=no} +ac_cv_lib_inet_main=${ac_cv_lib_inet_main=no} +ac_cv_lib_kstat_kstat_open=${ac_cv_lib_kstat_kstat_open=no} +ac_cv_lib_kvm_kvm_open=${ac_cv_lib_kvm_kvm_open=no} +ac_cv_lib_m_sin=${ac_cv_lib_m_sin=no} +ac_cv_lib_rt_clock_gettime=${ac_cv_lib_rt_clock_gettime=no} +ac_cv_lib_socket_main=${ac_cv_lib_socket_main=yes} +ac_cv_lib_util_openpty=${ac_cv_lib_util_openpty=no} +ac_cv_member_struct_ifreq_ifr_enaddr=${ac_cv_member_struct_ifreq_ifr_enaddr=no} +ac_cv_member_struct_ifreq_ifr_hwaddr=${ac_cv_member_struct_ifreq_ifr_hwaddr=no} +ac_cv_member_struct_ifreq_ifr_ifindex=${ac_cv_member_struct_ifreq_ifr_ifindex=no} +ac_cv_member_struct_ifreq_ifr_index=${ac_cv_member_struct_ifreq_ifr_index=no} +ac_cv_member_struct_ifreq_ifr_map=${ac_cv_member_struct_ifreq_ifr_map=no} +ac_cv_member_struct_sockaddr_dl_sdl_len=${ac_cv_member_struct_sockaddr_dl_sdl_len=no} +ac_cv_member_struct_sockaddr_un_sun_path=${ac_cv_member_struct_sockaddr_un_sun_path=no} +ac_cv_objext=${ac_cv_objext=o} +# ac_cv_path_CP=${ac_cv_path_CP=/bin/cp} +# ac_cv_path_EGREP=${ac_cv_path_EGREP='/usr/bin/grep -E'} +# ac_cv_path_GREP=${ac_cv_path_GREP=/usr/bin/grep} +# ac_cv_path_MKDIR=${ac_cv_path_MKDIR=/bin/mkdir} +# ac_cv_path_PERL=${ac_cv_path_PERL=/usr/bin/perl} +# ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'} +ac_cv_prog_AR=${ac_cv_prog_AR=ar.sh} +ac_cv_prog_CC=${ac_cv_prog_CC=cc.sh} +ac_cv_prog_CPP=${ac_cv_prog_CPP='cc.sh -E'} +ac_cv_prog_GETCONF=${ac_cv_prog_GETCONF=getconf} +ac_cv_prog_JAVAC=${ac_cv_prog_JAVAC=javac.sh} +ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=true} +ac_cv_prog_cc_c11=${ac_cv_prog_cc_c11=no} +ac_cv_prog_cc_c89=${ac_cv_prog_cc_c89=no} +ac_cv_prog_cc_c99=${ac_cv_prog_cc_c99=no} +ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} +ac_cv_prog_cxx_11=${ac_cv_prog_cxx_11=no} +ac_cv_prog_cxx_g=${ac_cv_prog_cxx_g=yes} +ac_cv_prog_cxx_stdcxx=${ac_cv_prog_cxx_stdcxx=} +# ac_cv_prog_emu_cc=${ac_cv_prog_emu_cc=$ERL_TOP/git/otp/erts/etc/win32/wsl_tools/vc/emu_cc.sh} +# ac_cv_prog_javac_ver_1_6=${ac_cv_prog_javac_ver_1_6=no} +# ac_cv_prog_mkdir_p=${ac_cv_prog_mkdir_p='/usr/bin/install -c -d'} +ac_cv_search_fdatasync=${ac_cv_search_fdatasync=no} +ac_cv_search_opendir=${ac_cv_search_opendir=no} +ac_cv_search_strerror=${ac_cv_search_strerror='none required'} +ac_cv_sizeof__Float16=${ac_cv_sizeof__Float16=0} +ac_cv_sizeof___int128_t=${ac_cv_sizeof___int128_t=0} +ac_cv_sizeof___int64=${ac_cv_sizeof___int64=8} +ac_cv_sizeof_char=${ac_cv_sizeof_char=1} +ac_cv_sizeof_int=${ac_cv_sizeof_int=4} +ac_cv_sizeof_long=${ac_cv_sizeof_long=4} +ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long=8} +ac_cv_sizeof_off_t=${ac_cv_sizeof_off_t=4} +ac_cv_sizeof_short=${ac_cv_sizeof_short=2} +ac_cv_sizeof_size_t=${ac_cv_sizeof_size_t=8} +ac_cv_sizeof_suseconds_t=${ac_cv_sizeof_suseconds_t=0} +ac_cv_sizeof_time_t=${ac_cv_sizeof_time_t=8} +ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=8} +ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no} +ac_cv_struct_tm=${ac_cv_struct_tm=time.h} +# ac_cv_sys_ipv6_support=${ac_cv_sys_ipv6_support=yes} +ac_cv_sys_multicast_support=${ac_cv_sys_multicast_support=no} +ac_cv_target=${ac_cv_target=local-x86_64-pc-windows} +ac_cv_type_off_t=${ac_cv_type_off_t=yes} +ac_cv_type_pid_t=${ac_cv_type_pid_t=no} +ac_cv_type_size_t=${ac_cv_type_size_t=yes} +erl_cv_clock_gettime_monotonic_default_resolution=${erl_cv_clock_gettime_monotonic_default_resolution=no} +erl_cv_clock_gettime_monotonic_high_resolution=${erl_cv_clock_gettime_monotonic_high_resolution=no} +erl_cv_clock_gettime_monotonic_raw=${erl_cv_clock_gettime_monotonic_raw=no} +erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=${erl_cv_clock_gettime_monotonic_try_find_pthread_compatible=no} +erl_cv_clock_gettime_wall_default_resolution=${erl_cv_clock_gettime_wall_default_resolution=no} +erl_cv_mach_clock_get_time_monotonic=${erl_cv_mach_clock_get_time_monotonic=no} +erl_cv_mach_clock_get_time_wall=${erl_cv_mach_clock_get_time_wall=no} +erts_cv___after_morecore_hook_can_track_malloc=${erts_cv___after_morecore_hook_can_track_malloc=no} +erts_cv_fwrite_unlocked=${erts_cv_fwrite_unlocked=no} +erts_cv_have__end_symbol=${erts_cv_have__end_symbol=no} +erts_cv_have_end_symbol=${erts_cv_have_end_symbol=no} +erts_cv_have_in6addr_any=${erts_cv_have_in6addr_any=no} +erts_cv_have_in6addr_loopback=${erts_cv_have_in6addr_loopback=no} +erts_cv_putc_unlocked=${erts_cv_putc_unlocked=no} +erts_cv_windows_h_includes_winsock2_h=${erts_cv_windows_h_includes_winsock2_h=no} +ethr_cv_have__InterlockedAnd64=${ethr_cv_have__InterlockedAnd64=yes} +ethr_cv_have__InterlockedAnd=${ethr_cv_have__InterlockedAnd=yes} +ethr_cv_have__InterlockedCompareExchange128=${ethr_cv_have__InterlockedCompareExchange128=yes} +ethr_cv_have__InterlockedCompareExchange64=${ethr_cv_have__InterlockedCompareExchange64=yes} +# ethr_cv_have__InterlockedCompareExchange64_acq=${ethr_cv_have__InterlockedCompareExchange64_acq=no} +# ethr_cv_have__InterlockedCompareExchange64_rel=${ethr_cv_have__InterlockedCompareExchange64_rel=no} +ethr_cv_have__InterlockedCompareExchange=${ethr_cv_have__InterlockedCompareExchange=yes} +# ethr_cv_have__InterlockedCompareExchange_acq=${ethr_cv_have__InterlockedCompareExchange_acq=no} +# ethr_cv_have__InterlockedCompareExchange_rel=${ethr_cv_have__InterlockedCompareExchange_rel=no} +ethr_cv_have__InterlockedDecrement64=${ethr_cv_have__InterlockedDecrement64=yes} +# ethr_cv_have__InterlockedDecrement64_rel=${ethr_cv_have__InterlockedDecrement64_rel=no} +ethr_cv_have__InterlockedDecrement=${ethr_cv_have__InterlockedDecrement=yes} +# ethr_cv_have__InterlockedDecrement_rel=${ethr_cv_have__InterlockedDecrement_rel=no} +ethr_cv_have__InterlockedExchange64=${ethr_cv_have__InterlockedExchange64=yes} +ethr_cv_have__InterlockedExchange=${ethr_cv_have__InterlockedExchange=yes} +ethr_cv_have__InterlockedExchangeAdd64=${ethr_cv_have__InterlockedExchangeAdd64=yes} +# ethr_cv_have__InterlockedExchangeAdd64_acq=${ethr_cv_have__InterlockedExchangeAdd64_acq=no} +ethr_cv_have__InterlockedExchangeAdd=${ethr_cv_have__InterlockedExchangeAdd=yes} +# ethr_cv_have__InterlockedExchangeAdd_acq=${ethr_cv_have__InterlockedExchangeAdd_acq=no} +ethr_cv_have__InterlockedIncrement64=${ethr_cv_have__InterlockedIncrement64=yes} +# ethr_cv_have__InterlockedIncrement64_acq=${ethr_cv_have__InterlockedIncrement64_acq=no} +ethr_cv_have__InterlockedIncrement=${ethr_cv_have__InterlockedIncrement=yes} +# ethr_cv_have__InterlockedIncrement_acq=${ethr_cv_have__InterlockedIncrement_acq=no} +ethr_cv_have__InterlockedOr64=${ethr_cv_have__InterlockedOr64=yes} +ethr_cv_have__InterlockedOr=${ethr_cv_have__InterlockedOr=yes} +i_cv_fallocate_works=${i_cv_fallocate_works=no} +i_cv_posix_fallocate_works=${i_cv_posix_fallocate_works=no} diff --git a/make/configure b/make/configure index c44049816ca4..8c21940de2df 100755 --- a/make/configure +++ b/make/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +221,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +253,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +292,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +310,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +332,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +341,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +380,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +398,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +430,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +459,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +503,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +517,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +534,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,49 +606,45 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS DED_OSTYPE @@ -633,8 +660,6 @@ DED_EXT DED_GCC DED_CC DED_THR_DEFS -EGREP -GREP DEFAULT_VERBOSITY OTP_VSN OTP_REL @@ -655,6 +680,10 @@ ac_ct_CC BOOTSTRAP_ONLY CROSS_COMPILING TARGET +target_os +target_vendor +target_cpu +target host_os host_vendor host_cpu @@ -744,7 +773,6 @@ enable_option_checking enable_bootstrap_only enable_parallel_configure enable_dirty_schedulers -enable_plain_emulator with_termcap enable_kernel_poll enable_sctp @@ -767,7 +795,6 @@ enable_m64_build enable_m32_build enable_pie with_libatomic_ops -enable_sanitizers enable_silent_rules ' ac_precious_vars='build_alias @@ -879,8 +906,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -921,9 +946,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -947,9 +972,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1160,9 +1185,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1176,9 +1201,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1222,9 +1247,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1240,7 +1265,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1304,7 +1329,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1422,6 +1447,7 @@ _ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1438,9 +1464,6 @@ Optional Features: disable parallel execution of configure scripts --enable-dirty-schedulers enable dirty scheduler support - --enable-plain-emulator enable threaded non-smp emulator - --disable-plain-emulator - disable threaded non-smp emulator --enable-kernel-poll enable kernel poll support --disable-kernel-poll disable kernel poll support --enable-sctp enable sctp support (default) to on demand load the @@ -1473,8 +1496,6 @@ Optional Features: --enable-m32-build build 32bit binaries using the -m32 flag to (g)cc --enable-pie build position independent executables --disable-pie do no build position independent executables - --enable-sanitizers[=comma-separated list of sanitizers] - Default=address,undefined --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") @@ -1609,9 +1630,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1639,7 +1660,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1647,7 +1669,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1657,9 +1679,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1676,14 +1698,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1691,14 +1713,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1714,14 +1737,14 @@ fi ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1729,14 +1752,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1752,14 +1776,14 @@ fi ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1767,17 +1791,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1798,11 +1823,12 @@ fi ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -1810,16 +1836,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -1837,156 +1856,66 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -} # ac_fn_c_check_header_mongrel +} # ac_fn_c_check_header_compile # ac_fn_c_try_run LINENO # ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -1996,25 +1925,26 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status @@ -2025,37 +1955,6 @@ fi } # ac_fn_c_try_run -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes @@ -2070,7 +1969,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -2080,14 +1979,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2097,9 +1997,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -2107,14 +2008,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -2124,14 +2025,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2141,9 +2043,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -2151,14 +2054,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -2166,7 +2069,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2176,12 +2079,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -2191,12 +2095,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -2224,9 +2128,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2278,8 +2203,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2314,7 +2243,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2349,11 +2278,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2364,8 +2295,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2389,7 +2320,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2397,14 +2328,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2412,15 +2343,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2428,8 +2359,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2443,63 +2374,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2509,85 +2425,808 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +# Test code for whether the C++ compiler supports C++98 (global declarations) +ac_cxx_conftest_cxx98_globals=' +// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are to reject old compilers that +// lack the unsuffixed header files. +#include +#include + +// and are *not* freestanding headers in C++98. +extern void assert (int); +namespace std { + extern int strcmp (const char *, const char *); +} + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::exception; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + // Extra parentheses suppress a warning when building autoconf itself, + // due to lint rules shared with more typical C programs. + assert (!(strcmp) (s, "test")); + } +} + +template struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template T add(U u) { return static_cast(u) + val; } +}; + +} // anonymous namespace +' + +# Test code for whether the C++ compiler supports C++98 (body of main) +ac_cxx_conftest_cxx98_main=' + assert (argc); + assert (! argv[0]); +{ + test_exception_syntax (); + test_template tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); +} +' + +# Test code for whether the C++ compiler supports C++11 (global declarations) +ac_cxx_conftest_cxx11_globals=' +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif + +namespace cxx11test +{ + constexpr int get_val() { return 20; } + + struct testinit + { + int i; + double d; + }; + + class delegate + { + public: + delegate(int n) : n(n) {} + delegate(): delegate(2354) {} + + virtual int getval() { return this->n; }; + protected: + int n; + }; + + class overridden : public delegate + { + public: + overridden(int n): delegate(n) {} + virtual int getval() override final { return this->n * 2; } + }; + + class nocopy + { + public: + nocopy(int i): i(i) {} + nocopy() = default; + nocopy(const nocopy&) = delete; + nocopy & operator=(const nocopy&) = delete; + private: + int i; + }; + + // for testing lambda expressions + template Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template auto sum(V first) -> V + { + return first; + } + template auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } +} +' + +# Test code for whether the C++ compiler supports C++11 (body of main) +ac_cxx_conftest_cxx11_main=' +{ + // Test auto and decltype + auto a1 = 6538; + auto a2 = 48573953.4; + auto a3 = "String literal"; + + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + + decltype(a2) a4 = 34895.034; +} +{ + // Test constexpr + short sa[cxx11test::get_val()] = { 0 }; +} +{ + // Test initializer lists + cxx11test::testinit il = { 4323, 435234.23544 }; +} +{ + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } +} +{ + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); +} +{ + // Test use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); +} +{ + // Test constructor delegation + cxx11test::delegate d1; + cxx11test::delegate d2(); + cxx11test::delegate d3(45); +} +{ + // Test override and final + cxx11test::overridden o1(55464); +} +{ + // Test nullptr + char *c = nullptr; +} +{ + // Test template brackets + test_template<::test_template> v(test_template(12)); +} +{ + // Unicode literals + char const *utf8 = u8"UTF-8 string \u2500"; + char16_t const *utf16 = u"UTF-8 string \u2500"; + char32_t const *utf32 = U"UTF-32 string \u2500"; +} +' + +# Test code for whether the C compiler supports C++11 (complete). +ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} +${ac_cxx_conftest_cxx11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + ${ac_cxx_conftest_cxx11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C++98 (complete). +ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${ERL_TOP}/make/autoconf" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2690,58 +3329,32 @@ esac test "X$ERL_TOP" != "X" || as_fn_error $? "ERL_TOP not set" "$LINENO" 5 -ac_aux_dir= -for ac_dir in ${ERL_TOP}/erts/autoconf "$srcdir"/${ERL_TOP}/erts/autoconf; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in ${ERL_TOP}/erts/autoconf \"$srcdir\"/${ERL_TOP}/erts/autoconf" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - # Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2760,21 +3373,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2793,31 +3407,112 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host else - host_os=$host + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi -TARGET=$host +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac -if test "$cross_compiling" = "yes"; then - if test "$build" = "$host"; then - as_fn_error $? " +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + # Adjust for local legacy windows hack... + case $host in #( + local-*-windows) : + + host=win32 + host_os=win32 + host_vendor= + host_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $build in #( + local-*-windows) : + + build=win32 + build_os=win32 + build_vendor= + build_cpu= + ;; #( + *) : + ;; +esac + + + # Adjust for local legacy windows hack... + case $target in #( + local-*-windows) : + + target=win32 + target_os=win32 + target_vendor= + target_cpu= + ;; #( + *) : + ;; +esac + + if test "$cross_compiling" = "yes" -a "$build" = "$host" +then : + as_fn_error $? " Cross compiling with the same canonicalized 'host' value as the canonicalized 'build' value. We are cross compiling since the '--host=$host_alias' and the '--build=$build_alias' arguments differ. When - cross compiling Erlang/OTP also the canonicalized values of + cross compiling Erlang/OTP, also the canonicalized values of the '--build' and the '--host' arguments *must* differ. The canonicalized values of these arguments however both equals: $host You can check the canonical value by passing a value as - argument to the 'erts/autoconf/config.sub' script. - " "$LINENO" 5 - fi + argument to the 'make/autoconf/config.sub' script. + " "$LINENO" 5 +fi + + +TARGET=$host + + +if test "$cross_compiling" = "yes"; then CROSS_COMPILING=yes else CROSS_COMPILING=no @@ -2825,14 +3520,15 @@ fi # Check whether --enable-bootstrap-only was given. -if test "${enable_bootstrap_only+set}" = set; then : +if test ${enable_bootstrap_only+y} +then : enableval=$enable_bootstrap_only; if test "X$enableval" = "Xyes"; then BOOTSTRAP_ONLY=yes else BOOTSTRAP_ONLY=no fi -else +else $as_nop BOOTSTRAP_ONLY=no fi @@ -2844,6 +3540,15 @@ if test $CROSS_COMPILING = yes -a $BOOTSTRAP_ONLY = yes; then fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2852,11 +3557,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2864,11 +3570,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2879,11 +3589,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2892,11 +3602,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2904,11 +3615,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2919,11 +3634,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2931,8 +3646,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2945,11 +3660,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2957,11 +3673,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2972,11 +3692,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2985,11 +3705,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2998,15 +3719,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3022,18 +3747,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3044,11 +3769,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3056,11 +3782,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3071,11 +3801,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3088,11 +3818,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -3100,11 +3831,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3115,11 +3850,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3131,34 +3866,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi +else + CC="$ac_cv_prog_CC" fi fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3168,7 +4007,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -3176,7 +4015,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3188,9 +4027,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -3211,11 +4050,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -3232,7 +4072,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -3248,44 +4088,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -3299,15 +4141,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3316,7 +4158,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3328,8 +4170,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3337,10 +4179,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3348,39 +4190,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3394,11 +4237,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3407,31 +4251,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3441,29 +4286,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3472,57 +4321,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3537,94 +4389,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3633,6 +4535,12 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3643,15 +4551,16 @@ if test -z "$CXX"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else @@ -3659,11 +4568,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3674,11 +4587,11 @@ fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3687,15 +4600,16 @@ fi fi if test -z "$CXX"; then ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else @@ -3703,11 +4617,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3718,11 +4636,11 @@ fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3734,8 +4652,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -3745,7 +4663,7 @@ fi fi fi # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do @@ -3755,7 +4673,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3765,20 +4683,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +printf %s "checking whether the compiler supports GNU C++... " >&6; } +if test ${ac_cv_cxx_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3788,29 +4707,33 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi -ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +printf %s "checking whether $CXX accepts -g... " >&6; } +if test ${ac_cv_prog_cxx_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no @@ -3819,57 +4742,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes -else +else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : -else +else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then @@ -3884,6 +4810,100 @@ else CXXFLAGS= fi fi +ac_prog_cxx_stdcxx=no +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 +printf %s "checking for $CXX option to enable C++11 features... " >&6; } +if test ${ac_cv_prog_cxx_11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_11=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx11_program +_ACEOF +for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx11" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx11" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 + ac_prog_cxx_stdcxx=cxx11 +fi +fi +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 +printf %s "checking for $CXX option to enable C++98 features... " >&6; } +if test ${ac_cv_prog_cxx_98+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_98=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx98_program +_ACEOF +for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx98=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx98" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx98" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx98" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx98" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 + ac_prog_cxx_stdcxx=cxx98 +fi +fi + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3893,11 +4913,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$LD"; then ac_cv_prog_LD="$LD" # Let the user override the test. else @@ -3905,11 +4926,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LD="${ac_tool_prefix}ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3920,11 +4945,11 @@ fi fi LD=$ac_cv_prog_LD if test -n "$LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -$as_echo "$LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +printf "%s\n" "$LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3933,11 +4958,12 @@ if test -z "$ac_cv_prog_LD"; then ac_ct_LD=$LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_LD"; then ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. else @@ -3945,11 +4971,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LD="ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3960,11 +4990,11 @@ fi fi ac_ct_LD=$ac_cv_prog_ac_ct_LD if test -n "$ac_ct_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 -$as_echo "$ac_ct_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 +printf "%s\n" "$ac_ct_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LD" = x; then @@ -3972,8 +5002,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LD=$ac_ct_LD @@ -3994,111 +5024,111 @@ MIXED_VSL=no MIXED_VC=no MIXED_MINGW=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 -$as_echo_n "checking for mixed mingw-gcc and native VC++ environment... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed mingw-gcc and native VC++ environment" >&5 +printf %s "checking for mixed mingw-gcc and native VC++ environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then if test -x /usr/bin/msys-?.0.dll; then CFLAGS="$CFLAGS -O2" MIXED_MSYS=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 -$as_echo "MSYS and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: MSYS and VC" >&5 +printf "%s\n" "MSYS and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" MIXED_CYGWIN=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 -$as_echo "Cygwin and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Cygwin and VC" >&5 +printf "%s\n" "Cygwin and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" elif test -x /bin/wslpath; then CFLAGS="$CFLAGS -O2" MIXED_WSL=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 -$as_echo "WSL and VC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: WSL and VC" >&5 +printf "%s\n" "WSL and VC" >&6; } MIXED_VC=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_VC" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not within any known env" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$MIXED_MSYS" != "xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 -$as_echo_n "checking for mixed cygwin and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed cygwin and native MinGW environment" >&5 +printf %s "checking for mixed cygwin and native MinGW environment... " >&6; } if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then if test -x /usr/bin/cygpath; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with cygwin" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 -$as_echo_n "checking for mixed MSYS and native MinGW environment... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mixed MSYS and native MinGW environment" >&5 +printf %s "checking for mixed MSYS and native MinGW environment... " >&6; } if test "x$GCC" = x"yes"; then if test -x /usr/bin/msys-=.0.dll; then CFLAGS="$CFLAGS -O2" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } MIXED_MINGW=yes CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MINGW" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 -$as_echo "undeterminable" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: undeterminable" >&5 +printf "%s\n" "undeterminable" >&6; } as_fn_error cannot handle this! "Seems to be mixed windows but not with msys" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 -$as_echo_n "checking if we mix cygwin with any native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix cygwin with any native compiler" >&5 +printf %s "checking if we mix cygwin with any native compiler... " >&6; } if test "X$MIXED_CYGWIN" = "Xyes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 -$as_echo_n "checking if we mix msys with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix msys with another native compiler" >&5 +printf %s "checking if we mix msys with another native compiler... " >&6; } if test "X$MIXED_MSYS" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 -$as_echo_n "checking if we mix WSL with another native compiler... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we mix WSL with another native compiler" >&5 +printf %s "checking if we mix WSL with another native compiler... " >&6; } if test "X$MIXED_WSL" = "Xyes" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi fi @@ -4108,11 +5138,12 @@ _search_path=/bin:/usr/bin:/usr/local/bin:$PATH # Extract the first word of "env", so it can be a program name with args. set dummy env; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ENV+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ENV+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ENV in [\\/]* | ?:[\\/]*) ac_cv_path_ENV="$ENV" # Let the user override the test with a path. @@ -4122,11 +5153,15 @@ else for as_dir in $_search_path do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ENV="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ENV="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4139,11 +5174,11 @@ esac fi ENV=$ac_cv_path_ENV if test -n "$ENV"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENV" >&5 -$as_echo "$ENV" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ENV" >&5 +printf "%s\n" "$ENV" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4154,8 +5189,8 @@ fi # # We need GNU make, complain if we can't find it # -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU make" >&5 -$as_echo_n "checking for GNU make... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU make" >&5 +printf %s "checking for GNU make... " >&6; } # If there is a Makefile created we don't want make to start making, run # in a subdirectory and -f /dev/null MAKE_PROG=x @@ -4184,17 +5219,18 @@ if test X"$MAKE_PROG" = X"x"; then fi rm -rf conftestmake case $MAKE_PROG in - x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + x) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } as_fn_error $? "GNU make is required!" "$LINENO" 5 ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($MAKE_PROG)" >&5 -$as_echo "yes ($MAKE_PROG)" >&6; } + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($MAKE_PROG)" >&5 +printf "%s\n" "yes ($MAKE_PROG)" >&6; } ;; esac -# Find a good install program. We prefer a C program (faster), + + # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install @@ -4208,20 +5244,25 @@ esac # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; @@ -4231,13 +5272,13 @@ case $as_dir/ in #(( # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else @@ -4245,12 +5286,12 @@ case $as_dir/ in #(( echo one > conftest.one echo two > conftest.two mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi @@ -4266,7 +5307,7 @@ IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi - if test "${ac_cv_path_install+set}" = set; then + if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a @@ -4276,8 +5317,8 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -4294,25 +5335,26 @@ if test X"${INSTALL}" = "X${ac_aux_dir}/install-sh -c" && test -f /usr/ucb/insta esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -$as_echo_n "checking whether ln -s works... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -$as_echo "no, using $LN_S" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +printf "%s\n" "no, using $LN_S" >&6; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else @@ -4320,11 +5362,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4335,11 +5381,11 @@ fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4348,11 +5394,12 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else @@ -4360,11 +5407,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4375,11 +5426,11 @@ fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then @@ -4387,8 +5438,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -4401,11 +5452,12 @@ for ac_prog in perl5 perl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PERL+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PERL+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. @@ -4416,11 +5468,15 @@ as_dummy="/usr/local/bin:/opt/local/bin:/usr/local/gnu/bin:${PATH}" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4432,11 +5488,11 @@ esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 -$as_echo "$PERL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf "%s\n" "$PERL" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4456,627 +5512,259 @@ fi # # Get erts version from erts/vsn.mk # -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking ERTS version" >&5 -$as_echo_n "checking ERTS version... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ERTS version" >&5 +printf %s "checking ERTS version... " >&6; } ERTS_VSN=`sed -n "s/^VSN[ ]*=[ ]*\(.*\)/\1/p" < $ERL_TOP/erts/vsn.mk` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERTS_VSN" >&5 -$as_echo "$ERTS_VSN" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ERTS_VSN" >&5 +printf "%s\n" "$ERTS_VSN" >&6; } # # Get OTP release and OTP version from $ERL_TOP/OTP_VERSION # -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking OTP release" >&5 -$as_echo_n "checking OTP release... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OTP release" >&5 +printf %s "checking OTP release... " >&6; } OTP_REL=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTP_REL" >&5 -$as_echo "$OTP_REL" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTP_REL" >&5 +printf "%s\n" "$OTP_REL" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking OTP version" >&5 -$as_echo_n "checking OTP version... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OTP version" >&5 +printf %s "checking OTP version... " >&6; } OTP_VSN=`cat $ERL_TOP/OTP_VERSION` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTP_VSN" >&5 -$as_echo "$OTP_VSN" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTP_VSN" >&5 +printf "%s\n" "$OTP_VSN" >&6; } # Check whether --enable-parallel-configure was given. -if test "${enable_parallel_configure+set}" = set; then : +if test ${enable_parallel_configure+y} +then : enableval=$enable_parallel_configure; fi # Check whether --enable-dirty-schedulers was given. -if test "${enable_dirty_schedulers+set}" = set; then : +if test ${enable_dirty_schedulers+y} +then : enableval=$enable_dirty_schedulers; fi -# Check whether --enable-plain-emulator was given. -if test "${enable_plain_emulator+set}" = set; then : - enableval=$enable_plain_emulator; -fi - - # Check whether --with-termcap was given. -if test "${with_termcap+set}" = set; then : +if test ${with_termcap+y} +then : withval=$with_termcap; fi # Check whether --enable-kernel-poll was given. -if test "${enable_kernel_poll+set}" = set; then : +if test ${enable_kernel_poll+y} +then : enableval=$enable_kernel_poll; fi # Check whether --enable-sctp was given. -if test "${enable_sctp+set}" = set; then : +if test ${enable_sctp+y} +then : enableval=$enable_sctp; fi # Check whether --with-dynamic-trace was given. -if test "${with_dynamic_trace+set}" = set; then : +if test ${with_dynamic_trace+y} +then : withval=$with_dynamic_trace; fi # Check whether --enable-vm-probes was given. -if test "${enable_vm_probes+set}" = set; then : +if test ${enable_vm_probes+y} +then : enableval=$enable_vm_probes; fi # Check whether --with-javac was given. -if test "${with_javac+set}" = set; then : +if test ${with_javac+y} +then : withval=$with_javac; fi # Check whether --enable-megaco_flex_scanner_lineno was given. -if test "${enable_megaco_flex_scanner_lineno+set}" = set; then : +if test ${enable_megaco_flex_scanner_lineno+y} +then : enableval=$enable_megaco_flex_scanner_lineno; fi # Check whether --enable-megaco_reentrant_flex_scanner was given. -if test "${enable_megaco_reentrant_flex_scanner+set}" = set; then : +if test ${enable_megaco_reentrant_flex_scanner+y} +then : enableval=$enable_megaco_reentrant_flex_scanner; fi # Check whether --with-ssl was given. -if test "${with_ssl+set}" = set; then : +if test ${with_ssl+y} +then : withval=$with_ssl; fi # Check whether --with-ssl-incl was given. -if test "${with_ssl_incl+set}" = set; then : +if test ${with_ssl_incl+y} +then : withval=$with_ssl_incl; fi # Check whether --with-ssl-zlib was given. -if test "${with_ssl_zlib+set}" = set; then : +if test ${with_ssl_zlib+y} +then : withval=$with_ssl_zlib; fi # Check whether --with-ssl-lib-subdir was given. -if test "${with_ssl_lib_subdir+set}" = set; then : +if test ${with_ssl_lib_subdir+y} +then : withval=$with_ssl_lib_subdir; fi # Check whether --with-ssl-rpath was given. -if test "${with_ssl_rpath+set}" = set; then : +if test ${with_ssl_rpath+y} +then : withval=$with_ssl_rpath; fi # Check whether --enable-dynamic-ssl-lib was given. -if test "${enable_dynamic_ssl_lib+set}" = set; then : +if test ${enable_dynamic_ssl_lib+y} +then : enableval=$enable_dynamic_ssl_lib; fi # Check whether --enable-fips was given. -if test "${enable_fips+set}" = set; then : +if test ${enable_fips+y} +then : enableval=$enable_fips; fi # Check whether --enable-builtin-zlib was given. -if test "${enable_builtin_zlib+set}" = set; then : +if test ${enable_builtin_zlib+y} +then : enableval=$enable_builtin_zlib; fi # Check whether --enable-esock was given. -if test "${enable_esock+set}" = set; then : +if test ${enable_esock+y} +then : enableval=$enable_esock; fi -# Check whether --enable-sharing-preserving was given. -if test "${enable_sharing_preserving+set}" = set; then : - enableval=$enable_sharing_preserving; -fi - - - -# Check whether --enable-m64-build was given. -if test "${enable_m64_build+set}" = set; then : - enableval=$enable_m64_build; case "$enableval" in - no) enable_m64_build=no ;; - *) enable_m64_build=yes ;; - esac - -else - enable_m64_build=no -fi - - -# Check whether --enable-m32-build was given. -if test "${enable_m32_build+set}" = set; then : - enableval=$enable_m32_build; case "$enableval" in - no) enable_m32_build=no ;; - *) enable_m32_build=yes ;; - esac - -else - enable_m32_build=no -fi - - -# Check whether --enable-pie was given. -if test "${enable_pie+set}" = set; then : - enableval=$enable_pie; -fi - - - -# Check whether --with-libatomic_ops was given. -if test "${with_libatomic_ops+set}" = set; then : - withval=$with_libatomic_ops; -fi - - - -# Check whether --enable-sanitizers was given. -if test "${enable_sanitizers+set}" = set; then : - enableval=$enable_sanitizers; -fi - - -# Check whether --enable-silent-rules was given. -if test "${enable_silent_rules+set}" = set; then : - enableval=$enable_silent_rules; -fi - - -DEFAULT_VERBOSITY=0 -if test X${enable_silent_rules} = Xno; then - DEFAULT_VERBOSITY=1 -fi - - -if test X${enable_m64_build} = Xyes; then - CFLAGS="-m64 $CFLAGS" - export CFLAGS - LDFLAGS="-m64 $LDFLAGS" - export LDFLAGS -fi -if test X${enable_m32_build} = Xyes; then - CFLAGS="-m32 $CFLAGS" - export CFLAGS - LDFLAGS="-m32 $LDFLAGS" - export LDFLAGS -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no +# Check whether --enable-sharing-preserving was given. +if test ${enable_sharing_preserving+y} +then : + enableval=$enable_sharing_preserving; fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : -else - ac_cv_header_stdc=no -fi -rm -f conftest* +# Check whether --enable-m64-build was given. +if test ${enable_m64_build+y} +then : + enableval=$enable_m64_build; case "$enableval" in + no) enable_m64_build=no ;; + *) enable_m64_build=yes ;; + esac +else $as_nop + enable_m64_build=no fi -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : +# Check whether --enable-m32-build was given. +if test ${enable_m32_build+y} +then : + enableval=$enable_m32_build; case "$enableval" in + no) enable_m32_build=no ;; + *) enable_m32_build=yes ;; + esac -else - ac_cv_header_stdc=no +else $as_nop + enable_m32_build=no fi -rm -f conftest* + +# Check whether --enable-pie was given. +if test ${enable_pie+y} +then : + enableval=$enable_pie; fi -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext +# Check whether --with-libatomic_ops was given. +if test ${with_libatomic_ops+y} +then : + withval=$with_libatomic_ops; fi + +# Check whether --enable-silent-rules was given. +if test ${enable_silent_rules+y} +then : + enableval=$enable_silent_rules; fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +DEFAULT_VERBOSITY=0 +if test X${enable_silent_rules} = Xno; then + DEFAULT_VERBOSITY=1 fi -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +if test X${enable_m64_build} = Xyes; then + CFLAGS="-m64 $CFLAGS" + export CFLAGS + LDFLAGS="-m64 $LDFLAGS" + export LDFLAGS +fi +if test X${enable_m32_build} = Xyes; then + CFLAGS="-m32 $CFLAGS" + export CFLAGS + LDFLAGS="-m32 $LDFLAGS" + export LDFLAGS fi + +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi done @@ -5084,31 +5772,48 @@ done + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi + + + + NEED_NPTL_PTHREAD_H=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 -$as_echo_n "checking for native win32 threads... " >&6; } -if test "X$host_os" = "Xwin32"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for native win32 threads" >&5 +printf %s "checking for native win32 threads... " >&6; } +if test "X$host_os" = "Xwin32" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } THR_DEFS="-DWIN32_THREADS" THR_LIBS= THR_LIB_NAME=win32_threads THR_LIB_TYPE=win32_threads -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } THR_DEFS= THR_LIBS= THR_LIB_NAME= THR_LIB_TYPE=posix_unknown - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5117,40 +5822,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread_pthread_create=yes -else +else $as_nop ac_cv_lib_pthread_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : THR_LIBS="-lpthread" fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 -$as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 +printf %s "checking for pthread_create in -lc_r... " >&6; } +if test ${ac_cv_lib_c_r_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5159,96 +5866,112 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_r_pthread_create=yes -else +else $as_nop ac_cv_lib_c_r_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +if test "x$ac_cv_lib_c_r_pthread_create" = xyes +then : THR_LIBS="-lc_r" fi - fi - if test "x$THR_LIBS" = "x"; then - ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes; then : +fi + + if test "x$THR_LIBS" = "x" +then : + + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : THR_LIBS="none_needed" fi - fi - if test "x$THR_LIBS" = "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 -$as_echo_n "checking if the '-pthread' switch can be used... " >&6; } +fi + + if test "x$THR_LIBS" = "x" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the '-pthread' switch can be used" >&5 +printf %s "checking if the '-pthread' switch can be used... " >&6; } saved_cflags=$CFLAGS CFLAGS="$CFLAGS -pthread" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_create((void*)0,(void*)0,(void*)0,(void*)0); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : THR_DEFS="-pthread" THR_LIBS="-pthread" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$saved_cflags if test "x$THR_LIBS" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - fi - if test "x$THR_LIBS" != "x"; then +fi + + if test "x$THR_LIBS" != "x" +then : + THR_DEFS="$THR_DEFS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS" THR_LIB_NAME=pthread if test "x$THR_LIBS" = "xnone_needed"; then THR_LIBS= fi - case $host_os in - solaris*) - THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;; - linux*) + case $host_os in #( + solaris*) : + + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS" + ;; #( + linux*) : + THR_DEFS="$THR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS" -if test "$cross_compiling" != "yes"; then +if test "$cross_compiling" != "yes" +then : + # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -5256,11 +5979,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5272,23 +5999,26 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else + +else $as_nop + host_getconf="$host_alias-getconf" # Extract the first word of "$host_getconf", so it can be a program name with args. set dummy $host_getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$GETCONF"; then ac_cv_prog_GETCONF="$GETCONF" # Let the user override the test. else @@ -5296,11 +6026,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_GETCONF="$host_getconf" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5312,25 +6046,28 @@ fi fi GETCONF=$ac_cv_prog_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != ""; then + if test "$GETCONF" = "false" && test "$erl_xcomp_sysroot" != "" +then : + GETCONF= prfx="$erl_xcomp_sysroot" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}getconf", so it can be a program name with args. set dummy ${ac_tool_prefix}getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_GETCONF="$GETCONF" # Let the user override the test with a path. @@ -5341,11 +6078,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5357,11 +6098,11 @@ esac fi GETCONF=$ac_cv_path_GETCONF if test -n "$GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 -$as_echo "$GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GETCONF" >&5 +printf "%s\n" "$GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5370,11 +6111,12 @@ if test -z "$ac_cv_path_GETCONF"; then ac_pt_GETCONF=$GETCONF # Extract the first word of "getconf", so it can be a program name with args. set dummy getconf; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_GETCONF+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_GETCONF+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_GETCONF in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_GETCONF="$ac_pt_GETCONF" # Let the user override the test with a path. @@ -5385,11 +6127,15 @@ as_dummy=""$prfx/usr/bin:$prfx/bin:$prfx/usr/local/bin"" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_GETCONF="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_GETCONF="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5401,11 +6147,11 @@ esac fi ac_pt_GETCONF=$ac_cv_path_ac_pt_GETCONF if test -n "$ac_pt_GETCONF"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 -$as_echo "$ac_pt_GETCONF" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_GETCONF" >&5 +printf "%s\n" "$ac_pt_GETCONF" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_GETCONF" = x; then @@ -5413,8 +6159,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac GETCONF=$ac_pt_GETCONF @@ -5423,11 +6169,13 @@ else GETCONF="$ac_cv_path_GETCONF" fi - fi + +fi + fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 -$as_echo_n "checking for Native POSIX Thread Library... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Native POSIX Thread Library" >&5 +printf %s "checking for Native POSIX Thread Library... " >&6; } libpthr_vsn=`$GETCONF GNU_LIBPTHREAD_VERSION 2>/dev/null` if test $? -eq 0; then case "$libpthr_vsn" in @@ -5443,24 +6191,28 @@ $as_echo_n "checking for Native POSIX Thread Library... " >&6; } else nptl=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 -$as_echo "$nptl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $nptl" >&5 +printf "%s\n" "$nptl" >&6; } if test $nptl = cross; then nptl=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 -$as_echo "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result yes guessed because of cross compilation" >&5 +printf "%s\n" "$as_me: WARNING: result yes guessed because of cross compilation" >&2;} fi - if test $nptl = yes; then + if test $nptl = yes +then : + THR_LIB_TYPE=posix_nptl need_nptl_incldir=no - ac_fn_c_check_header_mongrel "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_nptl_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "nptl/pthread.h" "ac_cv_header_nptl_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_nptl_pthread_h" = xyes +then : need_nptl_incldir=yes NEED_NPTL_PTHREAD_H=yes fi + if test $need_nptl_incldir = yes +then : - if test $need_nptl_incldir = yes; then # Ahh... nptl_path="$C_INCLUDE_PATH:$CPATH" if test X$cross_compiling != Xyes; then @@ -5481,13 +6233,13 @@ fi IFS=$save_ifs nptl_incldir= for dir in $nptl_ws_path; do - as_ac_Header=`$as_echo "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + as_ac_Header=`printf "%s\n" "ac_cv_header_$dir/nptl/pthread.h" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$dir/nptl/pthread.h" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : nptl_incldir=$dir/nptl fi - if test "x$nptl_incldir" != "x"; then THR_DEFS="$THR_DEFS -isystem $nptl_incldir" break @@ -5496,38 +6248,43 @@ fi if test "x$nptl_incldir" = "x"; then as_fn_error $? "Failed to locate nptl system include directory" "$LINENO" 5 fi - fi - fi - ;; - *) ;; - esac + +fi + +fi + ;; #( + *) : + ;; +esac saved_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $THR_DEFS" - ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : -$as_echo "#define HAVE_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h fi - - ac_fn_c_check_header_mongrel "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "pthread/mit/pthread.h" "ac_cv_header_pthread_mit_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_mit_pthread_h" = xyes +then : \ -$as_echo "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_MIT_PTHREAD_H 1" >>confdefs.h fi - CPPFLAGS=$saved_cppflags - fi + +fi + fi @@ -5571,181 +6328,253 @@ case "$host_cpu" in esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Wdeclaration-after-statement $DED_WARN_FLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WARN_FLAGS="-Wdeclaration-after-statement $DED_WARN_FLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=return-type $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=return-type $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=implicit $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=implicit $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-Werror=undef $DED_WERRORFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_WERRORFLAGS="-Werror=undef $DED_WERRORFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$DED_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common" DED_INCLUDE=$DED_SYS_INCLUDE DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS" -if test "x$GCC" = xyes; then +if test "x$GCC" = xyes +then : + # Use -fno-common for gcc, that is link error if multiple definitions of # global variables are encountered. This is ISO C compliant. # Until version 10, gcc has had -fcommon as default, which allows and merges # such dubious duplicates. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)" >&5 -$as_echo_n "checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)... " >&6; } saved_CFLAGS=$CFLAGS; CFLAGS="-fno-common $DED_CFLAGS"; cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { return 0; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : can_enable_flag=true -else +else $as_nop can_enable_flag=false fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$saved_CFLAGS; - if test "X$can_enable_flag" = "Xtrue"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } DED_CFLAGS="-fno-common $DED_CFLAGS" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -fno-strict-aliasing to DED_CFLAGS (via CFLAGS)" >&5 +printf %s "checking if we can add -fno-strict-aliasing to DED_CFLAGS (via CFLAGS)... " >&6; } + saved_CFLAGS=$CFLAGS; + CFLAGS="-fno-strict-aliasing $DED_CFLAGS"; + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + can_enable_flag=true +else $as_nop + can_enable_flag=false +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$saved_CFLAGS; + if test "X$can_enable_flag" = "Xtrue" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + DED_CFLAGS="-fno-strict-aliasing $DED_CFLAGS" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi DED_STATIC_CFLAGS="$DED_CFLAGS" DED_CFLAGS="$DED_CFLAGS -fPIC" # Remove -fPIE and -fno-PIE DED_CFLAGS=`echo $DED_CFLAGS | sed 's/-f\(no-\)\?PIE//g'` + fi DED_EXT=so @@ -5832,17 +6661,19 @@ case $host_os in # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -5851,14 +6682,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h case "$ac_cv_sizeof_void_p" in @@ -5925,11 +6754,12 @@ test "$DED_LDFLAGS_CONFTEST" != "" || DED_LDFLAGS_CONFTEST="$DED_LDFLAGS" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DED_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DED_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$DED_LD"; then ac_cv_prog_DED_LD="$DED_LD" # Let the user override the test. else @@ -5937,11 +6767,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DED_LD="${ac_tool_prefix}ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5952,11 +6786,11 @@ fi fi DED_LD=$ac_cv_prog_DED_LD if test -n "$DED_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 -$as_echo "$DED_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 +printf "%s\n" "$DED_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5965,11 +6799,12 @@ if test -z "$ac_cv_prog_DED_LD"; then ac_ct_DED_LD=$DED_LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DED_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DED_LD+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_DED_LD"; then ac_cv_prog_ac_ct_DED_LD="$ac_ct_DED_LD" # Let the user override the test. else @@ -5977,11 +6812,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DED_LD="ld" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5992,11 +6831,11 @@ fi fi ac_ct_DED_LD=$ac_cv_prog_ac_ct_DED_LD if test -n "$ac_ct_DED_LD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DED_LD" >&5 -$as_echo "$ac_ct_DED_LD" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DED_LD" >&5 +printf "%s\n" "$ac_ct_DED_LD" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DED_LD" = x; then @@ -6004,8 +6843,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DED_LD=$ac_ct_DED_LD @@ -6016,37 +6855,37 @@ fi test "$DED_LD" != "false" || as_fn_error $? "No linker found" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for static compiler flags" >&5 -$as_echo_n "checking for static compiler flags... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for static compiler flags" >&5 +printf %s "checking for static compiler flags... " >&6; } DED_STATIC_CFLAGS="$DED_WERRORFLAGS $DED_WFLAGS $DED_THR_DEFS $DED_STATIC_CFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_STATIC_CFLAGS" >&5 -$as_echo "$DED_STATIC_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for basic compiler flags for loadable drivers" >&5 -$as_echo_n "checking for basic compiler flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_STATIC_CFLAGS" >&5 +printf "%s\n" "$DED_STATIC_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for basic compiler flags for loadable drivers" >&5 +printf %s "checking for basic compiler flags for loadable drivers... " >&6; } DED_BASIC_CFLAGS=$DED_CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 -$as_echo "$DED_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler flags for loadable drivers" >&5 -$as_echo_n "checking for compiler flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 +printf "%s\n" "$DED_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler flags for loadable drivers" >&5 +printf %s "checking for compiler flags for loadable drivers... " >&6; } DED_CFLAGS="$DED_WERRORFLAGS $DED_WARN_FLAGS $DED_THR_DEFS $DED_CFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 -$as_echo "$DED_CFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker for loadable drivers" >&5 -$as_echo_n "checking for linker for loadable drivers... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 -$as_echo "$DED_LD" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker flags for loadable drivers" >&5 -$as_echo_n "checking for linker flags for loadable drivers... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LDFLAGS" >&5 -$as_echo "$DED_LDFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'runtime library path' linker flag" >&5 -$as_echo_n "checking for 'runtime library path' linker flag... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_CFLAGS" >&5 +printf "%s\n" "$DED_CFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker for loadable drivers" >&5 +printf %s "checking for linker for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD" >&5 +printf "%s\n" "$DED_LD" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker flags for loadable drivers" >&5 +printf %s "checking for linker flags for loadable drivers... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LDFLAGS" >&5 +printf "%s\n" "$DED_LDFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 'runtime library path' linker flag" >&5 +printf %s "checking for 'runtime library path' linker flag... " >&6; } if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&5 -$as_echo "$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&5 +printf "%s\n" "$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } fi @@ -6101,8 +6940,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -6132,15 +6971,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -6154,8 +6993,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -6208,7 +7047,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -6224,8 +7063,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -6248,14 +7087,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -6265,46 +7106,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -6313,13 +7154,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -6328,8 +7162,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -6341,30 +7179,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -6377,13 +7195,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -6410,18 +7229,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -6433,12 +7254,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -6469,7 +7291,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -6491,6 +7313,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -6504,6 +7330,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -6545,7 +7377,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -6554,7 +7386,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6617,7 +7449,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -6666,14 +7498,16 @@ $config_files Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -6711,21 +7545,21 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -6753,7 +7587,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -6767,7 +7601,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -6795,7 +7629,7 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree @@ -7023,7 +7857,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -7031,17 +7865,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -7058,7 +7892,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -7082,9 +7916,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -7141,8 +7975,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -7185,9 +8019,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -7239,7 +8073,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/make/configure.ac b/make/configure.ac new file mode 100644 index 000000000000..654d1c0bc564 --- /dev/null +++ b/make/configure.ac @@ -0,0 +1,374 @@ +dnl Process this file with autoconf to produce a configure script. + +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1998-2023. All Rights Reserved. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. +dnl +dnl %CopyrightEnd% + +AC_PREREQ([2.71])dnl + +AC_INIT + +m4_include([otp.m4]) + +LM_PRECIOUS_VARS + +default_cache_file=./config.cache + +if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then + # The no_recursion variable is not documented, but the only + # action we take on it is disabling caching which is safe! + if test "x$cache_file" != "x$default_cache_file"; then + echo "Ignoring the --cache-file argument since it can cause the system to be erroneously configured" + fi + echo "Disabling caching" + if test -f $cache_file; then + echo "Removing cache file $cache_file" + rm -f $cache_file + fi + cache_file=/dev/null +fi + +case "X$ERL_TOP" in + X) + ;; + X/*) + test -f "$ERL_TOP/erts/emulator/beam/erl_init.c" || { + AC_MSG_ERROR([Invalid \$ERL_TOP]) + } + srcdir="$ERL_TOP";; + *) + AC_MSG_ERROR([\$ERL_TOP needs to be absolute]);; +esac + +dnl How to set srcdir absolute is taken from the GNU Emacs distribution +#### Make srcdir absolute, if it isn't already. It's important to +#### avoid running the path through pwd unnecessary, since pwd can +#### give you automounter prefixes, which can go away. +case "${srcdir}" in + /* ) ;; + . ) + ## We may be able to use the $PWD environment variable to make this + ## absolute. But sometimes PWD is inaccurate. + ## Make sure CDPATH doesn't affect cd (in case PWD is relative). + CDPATH= + if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; + then + srcdir="$PWD" + else + srcdir="`(cd ${srcdir}; pwd)`" + fi + ;; + * ) srcdir="`(cd ${srcdir}; pwd)`" ;; +esac + +# +# Now srcdir is absolute and also the top of Erlang distribution, ERL_TOP. +# +test "X$ERL_TOP" != "X" || AC_MSG_ERROR([ERL_TOP not set]) +AC_SUBST(ERL_TOP) + +dnl +dnl Aux programs are found in erts/autoconf +dnl +AC_CONFIG_AUX_DIRS([${ERL_TOP}/make/autoconf]) + +ERL_CANONICAL_SYSTEM_TYPE + +TARGET=$host +AC_SUBST(TARGET) + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILING=yes +else + CROSS_COMPILING=no +fi +AC_SUBST(CROSS_COMPILING) + +AC_ARG_ENABLE(bootstrap-only, +AS_HELP_STRING([--enable-bootstrap-only], + [enable bootstrap only configuration]), +[ if test "X$enableval" = "Xyes"; then + BOOTSTRAP_ONLY=yes + else + BOOTSTRAP_ONLY=no + fi +], +BOOTSTRAP_ONLY=no) + +AC_SUBST(BOOTSTRAP_ONLY) + +if test $CROSS_COMPILING = yes -a $BOOTSTRAP_ONLY = yes; then + AC_MSG_ERROR([Cannot both cross compile and build a bootstrap system]) +fi + +dnl Checks for programs. + +AC_PROG_CC +AC_PROG_CXX +AC_CHECK_TOOL(LD, [ld]) + +LM_WINDOWS_ENVIRONMENT + +_search_path=/bin:/usr/bin:/usr/local/bin:$PATH + +AC_PATH_PROG(ENV, [env], false, $_search_path) +if test "$ac_cv_path_ENV" = false; then + AC_MSG_ERROR([No 'env' command found]) +fi + +# +# We need GNU make, complain if we can't find it +# +AC_MSG_CHECKING(for GNU make) +# If there is a Makefile created we don't want make to start making, run +# in a subdirectory and -f /dev/null +MAKE_PROG=x +if test X"$CLEARCASE_MAKE_COMPAT" = X"gnu" -a X"$CLEARCASE_ROOT" != X"" ; then + eval clearmake -version 2>&1 | grep clearmake > /dev/null 2>&1 + case $? in + 0) MAKE_PROG="clearmake -V";; + *);; + esac +fi +if test X"$MAKE_PROG" = X"x"; then + mkdir conftestmake + if test -d conftestmake; then + cd conftestmake + for m in make gmake ggmake; do + eval $m --version -f /dev/null 2>&1 | grep GNU > /dev/null 2>&1 + case $? in + 0) MAKE_PROG=$m ; break ;; + *) ;; + esac + done + cd .. + else + AC_MSG_ERROR(could not create subdirectory) + fi +fi +rm -rf conftestmake +case $MAKE_PROG in + x) AC_MSG_RESULT(no) + AC_MSG_ERROR(GNU make is required!) + ;; + *) AC_MSG_RESULT(yes ($MAKE_PROG)) + AC_SUBST(MAKE_PROG) + ;; +esac + +AC_PROG_INSTALL +if test X"${INSTALL}" = "X${ac_aux_dir}/install-sh -c" && test -f /usr/ucb/install ; then + case $host_os in + osf*) ;; + *) INSTALL="/usr/ucb/install -c" ;; + esac +fi + +AC_PROG_LN_S +AC_PROG_RANLIB +LM_PROG_PERL5 +if test "$ac_cv_path_PERL" = false; then + AC_MSG_ERROR([Perl version 5 is required!]) +fi + +# +# Get erts version from erts/vsn.mk +# +AC_MSG_CHECKING([ERTS version]) +[ERTS_VSN=`sed -n "s/^VSN[ ]*=[ ]*\(.*\)/\1/p" < $ERL_TOP/erts/vsn.mk`] +AC_MSG_RESULT([$ERTS_VSN]) +AC_SUBST(ERTS_VSN) + +# +# Get OTP release and OTP version from $ERL_TOP/OTP_VERSION +# +AC_MSG_CHECKING([OTP release]) +[OTP_REL=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`] +AC_MSG_RESULT([$OTP_REL]) +AC_SUBST(OTP_REL) + +AC_MSG_CHECKING([OTP version]) +[OTP_VSN=`cat $ERL_TOP/OTP_VERSION`] +AC_MSG_RESULT([$OTP_VSN]) +AC_SUBST(OTP_VSN) + +AC_ARG_ENABLE(parallel-configure, +AS_HELP_STRING([--disable-parallel-configure], [disable parallel execution of configure scripts])) + +AC_ARG_ENABLE(dirty-schedulers, +AS_HELP_STRING([--enable-dirty-schedulers], [enable dirty scheduler support])) + +AC_ARG_WITH(termcap, +AS_HELP_STRING([--with-termcap], [use termcap (default)]) +AS_HELP_STRING([--without-termcap], + [do not use any termcap libraries (ncurses,curses,termcap,termlib)])) + +AC_ARG_ENABLE(kernel-poll, +AS_HELP_STRING([--enable-kernel-poll], [enable kernel poll support]) +AS_HELP_STRING([--disable-kernel-poll], [disable kernel poll support])) + +AC_ARG_ENABLE(sctp, +AS_HELP_STRING([--enable-sctp], [enable sctp support (default) +to on demand load the SCTP library in runtime]) +AS_HELP_STRING([--enable-sctp=lib], [enable sctp support +to link against the SCTP library]) +AS_HELP_STRING([--disable-sctp], [disable sctp support])) + +AC_ARG_WITH(dynamic-trace, +AS_HELP_STRING([--with-dynamic-trace={dtrace|lttng|systemtap}], + [specify use of dynamic trace framework, dtrace, lttng or systemtap]) +AS_HELP_STRING([--without-dynamic-trace], + [don't enable any dynamic tracing (default)])) +AC_ARG_ENABLE(vm-probes, +AS_HELP_STRING([--enable-vm-probes], + [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)])) +AC_ARG_WITH(javac, +AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) +AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) +AS_HELP_STRING([--without-javac], [don't use any Java compiler])) + +AC_ARG_ENABLE(megaco_flex_scanner_lineno, +AS_HELP_STRING([--disable-megaco-flex-scanner-lineno], + [disable megaco flex scanner lineno])) + +AC_ARG_ENABLE(megaco_reentrant_flex_scanner, +AS_HELP_STRING([--disable-megaco-reentrant-flex-scanner], + [disable reentrant megaco flex scanner])) + +AC_ARG_WITH(ssl, +AS_HELP_STRING([--with-ssl=PATH], [base location of OpenSSL include and lib directories]) +AS_HELP_STRING([--with-ssl], [use SSL (default)]) +AS_HELP_STRING([--without-ssl], [don't use SSL])) + +AC_ARG_WITH(ssl-incl, +AS_HELP_STRING([--with-ssl-incl=PATH], + [base location of OpenSSL include directory (if different than base location specified by --with-ssl=PATH)])) + +AC_ARG_WITH(ssl-zlib, +AS_HELP_STRING([--with-ssl-zlib=PATH], [Path to static zlib library to link the + crypto NIF with. This zlib library is most + often not necessary but might be needed in + order to link the NIF in some cases.])) + +AC_ARG_WITH(ssl-lib-subdir, +AS_HELP_STRING([--with-ssl-lib-subdir=RELATIVE_PATH], + [specify extra OpenSSL lib sub-directory to search in (relative to base directory)])) + +AC_ARG_WITH(ssl-rpath, +AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], + [runtime library path for OpenSSL. Default is 'yes', which equates to a + number of standard locations. If 'no', then no runtime + library paths will be used. Anything else should be a + comma or colon separated list of paths.])) + +AC_ARG_ENABLE(dynamic-ssl-lib, +AS_HELP_STRING([--enable-dynamic-ssl-lib], + [enable using dynamic openssl libraries when linking the crypto NIF]) +AS_HELP_STRING([--disable-dynamic-ssl-lib], + [disable using dynamic openssl libraries when linking the crypto NIF])) + +AC_ARG_ENABLE(fips, +AS_HELP_STRING([--enable-fips], [enable OpenSSL FIPS mode support]) +AS_HELP_STRING([--disable-fips], [disable OpenSSL FIPS mode support (default)])) + +AC_ARG_ENABLE(builtin-zlib, +AS_HELP_STRING([--enable-builtin-zlib], + [force use of our own built-in zlib])) + +AC_ARG_ENABLE(esock, +AS_HELP_STRING([--enable-esock], [enable builtin experimental socket (as a nif) support (default)]) +AS_HELP_STRING([--disable-esock], [disable builtin experimental socket (as a nif) support])) + +AC_ARG_ENABLE(sharing-preserving, +AS_HELP_STRING([--enable-sharing-preserving], + [enable copying of terms without destroying sharing])) + +dnl This functionality has been lost along the way... :( +dnl It could perhaps be nice to reintroduce some day; therefore, +dnl it is not removed just commented out. +dnl +dnl # +dnl # Set Erlang man page directory +dnl # +dnl AC_ARG_ENABLE(erlang-mandir, +dnl [ --disable-erlang-mandir do not install Erlang man pages in a private directory], +dnl [ case "$enableval" in +dnl no) erl_mandir=$mandir ;; +dnl *) erl_mandir='$(erlang_libdir)/man' ;; +dnl esac ], erl_mandir='$(erlang_libdir)/man') +dnl AC_SUBST(erl_mandir) + +AC_ARG_ENABLE(m64-build, +AS_HELP_STRING([--enable-m64-build], + [build 64bit binaries using the -m64 flag to (g)cc]), +[ case "$enableval" in + no) enable_m64_build=no ;; + *) enable_m64_build=yes ;; + esac +],enable_m64_build=no) + +AC_ARG_ENABLE(m32-build, +AS_HELP_STRING([--enable-m32-build], + [build 32bit binaries using the -m32 flag to (g)cc]), +[ case "$enableval" in + no) enable_m32_build=no ;; + *) enable_m32_build=yes ;; + esac +],enable_m32_build=no) + +AC_ARG_ENABLE(pie, +AS_HELP_STRING([--enable-pie], [build position independent executables]) +AS_HELP_STRING([--disable-pie], [do no build position independent executables])) + +AC_ARG_WITH(libatomic_ops, + AS_HELP_STRING([--with-libatomic_ops=PATH], + [specify and prefer usage of libatomic_ops in the ethread library])) + +AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) + +DEFAULT_VERBOSITY=0 +if test X${enable_silent_rules} = Xno; then + DEFAULT_VERBOSITY=1 +fi +AC_SUBST(DEFAULT_VERBOSITY) + +if test X${enable_m64_build} = Xyes; then + CFLAGS="-m64 $CFLAGS" + export CFLAGS + LDFLAGS="-m64 $LDFLAGS" + export LDFLAGS +fi +if test X${enable_m32_build} = Xyes; then + CFLAGS="-m32 $CFLAGS" + export CFLAGS + LDFLAGS="-m32 $LDFLAGS" + export LDFLAGS +fi + +ERL_DED + +AC_CONFIG_FILES([../Makefile output.mk ../make/$host/otp_ded.mk:../make/otp_ded.mk.in]) +AC_CONFIG_FILES([emd2exml], [chmod +x emd2exml]) + +AC_OUTPUT diff --git a/make/configure.in b/make/configure.in deleted file mode 100644 index 660c51e36337..000000000000 --- a/make/configure.in +++ /dev/null @@ -1,410 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. - -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 1998-2021. All Rights Reserved. -dnl -dnl Licensed under the Apache License, Version 2.0 (the "License"); -dnl you may not use this file except in compliance with the License. -dnl You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. -dnl -dnl %CopyrightEnd% - -AC_PREREQ(2.8)dnl - -AC_INIT() - -LM_PRECIOUS_VARS - -default_cache_file=./config.cache - -if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then - # The no_recursion variable is not documented, but the only - # action we take on it is disabling caching which is safe! - if test "x$cache_file" != "x$default_cache_file"; then - echo "Ignoring the --cache-file argument since it can cause the system to be erroneously configured" - fi - echo "Disabling caching" - if test -f $cache_file; then - echo "Removing cache file $cache_file" - rm -f $cache_file - fi - cache_file=/dev/null -fi - -case "X$ERL_TOP" in - X) - ;; - X/*) - test -f "$ERL_TOP/erts/emulator/beam/erl_init.c" || { - AC_MSG_ERROR([Invalid \$ERL_TOP]) - } - srcdir="$ERL_TOP";; - *) - AC_MSG_ERROR([\$ERL_TOP needs to be absolute]);; -esac - -dnl How to set srcdir absolute is taken from the GNU Emacs distribution -#### Make srcdir absolute, if it isn't already. It's important to -#### avoid running the path through pwd unnecessary, since pwd can -#### give you automounter prefixes, which can go away. -case "${srcdir}" in - /* ) ;; - . ) - ## We may be able to use the $PWD environment variable to make this - ## absolute. But sometimes PWD is inaccurate. - ## Make sure CDPATH doesn't affect cd (in case PWD is relative). - CDPATH= - if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; - then - srcdir="$PWD" - else - srcdir="`(cd ${srcdir}; pwd)`" - fi - ;; - * ) srcdir="`(cd ${srcdir}; pwd)`" ;; -esac - -# -# Now srcdir is absolute and also the top of Erlang distribution, ERL_TOP. -# -test "X$ERL_TOP" != "X" || AC_MSG_ERROR([ERL_TOP not set]) -AC_SUBST(ERL_TOP) - -dnl -dnl Aux programs are found in erts/autoconf -dnl -AC_CONFIG_AUX_DIR(${ERL_TOP}/erts/autoconf) - -dnl -dnl Figure out what we are running on. And in violation of autoconf -dnl style assume that $host is also what we are building for. I would -dnl like to get cross compiling working, since we actually have -dnl systems we cross compile for! -dnl - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST - AC_CANONICAL_BUILD -else - host_os=$host -fi - -TARGET=$host -AC_SUBST(TARGET) - -if test "$cross_compiling" = "yes"; then - if test "$build" = "$host"; then - AC_MSG_ERROR([ - Cross compiling with the same canonicalized 'host' value - as the canonicalized 'build' value. - - We are cross compiling since the '--host=$host_alias' - and the '--build=$build_alias' arguments differ. When - cross compiling Erlang/OTP also the canonicalized values of - the '--build' and the '--host' arguments *must* differ. The - canonicalized values of these arguments however both equals: - $host - - You can check the canonical value by passing a value as - argument to the 'erts/autoconf/config.sub' script. - ]) - fi - CROSS_COMPILING=yes -else - CROSS_COMPILING=no -fi -AC_SUBST(CROSS_COMPILING) - -AC_ARG_ENABLE(bootstrap-only, -AS_HELP_STRING([--enable-bootstrap-only], - [enable bootstrap only configuration]), -[ if test "X$enableval" = "Xyes"; then - BOOTSTRAP_ONLY=yes - else - BOOTSTRAP_ONLY=no - fi -], -BOOTSTRAP_ONLY=no) - -AC_SUBST(BOOTSTRAP_ONLY) - -if test $CROSS_COMPILING = yes -a $BOOTSTRAP_ONLY = yes; then - AC_MSG_ERROR([Cannot both cross compile and build a bootstrap system]) -fi - -dnl Checks for programs. - -AC_PROG_CC -AC_PROG_CXX -AC_CHECK_TOOL(LD, [ld]) - -LM_WINDOWS_ENVIRONMENT - -_search_path=/bin:/usr/bin:/usr/local/bin:$PATH - -AC_PATH_PROG(ENV, [env], false, $_search_path) -if test "$ac_cv_path_ENV" = false; then - AC_MSG_ERROR([No 'env' command found]) -fi - -# -# We need GNU make, complain if we can't find it -# -AC_MSG_CHECKING(for GNU make) -# If there is a Makefile created we don't want make to start making, run -# in a subdirectory and -f /dev/null -MAKE_PROG=x -if test X"$CLEARCASE_MAKE_COMPAT" = X"gnu" -a X"$CLEARCASE_ROOT" != X"" ; then - eval clearmake -version 2>&1 | grep clearmake > /dev/null 2>&1 - case $? in - 0) MAKE_PROG="clearmake -V";; - *);; - esac -fi -if test X"$MAKE_PROG" = X"x"; then - mkdir conftestmake - if test -d conftestmake; then - cd conftestmake - for m in make gmake ggmake; do - eval $m --version -f /dev/null 2>&1 | grep GNU > /dev/null 2>&1 - case $? in - 0) MAKE_PROG=$m ; break ;; - *) ;; - esac - done - cd .. - else - AC_MSG_ERROR(could not create subdirectory) - fi -fi -rm -rf conftestmake -case $MAKE_PROG in - x) AC_MSG_RESULT(no) - AC_MSG_ERROR(GNU make is required!) - ;; - *) AC_MSG_RESULT(yes ($MAKE_PROG)) - AC_SUBST(MAKE_PROG) - ;; -esac - -AC_PROG_INSTALL -if test X"${INSTALL}" = "X${ac_aux_dir}/install-sh -c" && test -f /usr/ucb/install ; then - case $host_os in - osf*) ;; - *) INSTALL="/usr/ucb/install -c" ;; - esac -fi - -AC_PROG_LN_S -AC_PROG_RANLIB -LM_PROG_PERL5 -if test "$ac_cv_path_PERL" = false; then - AC_MSG_ERROR([Perl version 5 is required!]) -fi - -# -# Get erts version from erts/vsn.mk -# -AC_MSG_CHECKING([ERTS version]) -[ERTS_VSN=`sed -n "s/^VSN[ ]*=[ ]*\(.*\)/\1/p" < $ERL_TOP/erts/vsn.mk`] -AC_MSG_RESULT([$ERTS_VSN]) -AC_SUBST(ERTS_VSN) - -# -# Get OTP release and OTP version from $ERL_TOP/OTP_VERSION -# -AC_MSG_CHECKING([OTP release]) -[OTP_REL=`cat $ERL_TOP/OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`] -AC_MSG_RESULT([$OTP_REL]) -AC_SUBST(OTP_REL) - -AC_MSG_CHECKING([OTP version]) -[OTP_VSN=`cat $ERL_TOP/OTP_VERSION`] -AC_MSG_RESULT([$OTP_VSN]) -AC_SUBST(OTP_VSN) - -AC_ARG_ENABLE(parallel-configure, -AS_HELP_STRING([--disable-parallel-configure], [disable parallel execution of configure scripts])) - -AC_ARG_ENABLE(dirty-schedulers, -AS_HELP_STRING([--enable-dirty-schedulers], [enable dirty scheduler support])) - -AC_ARG_ENABLE(plain-emulator, -AS_HELP_STRING([--enable-plain-emulator], [enable threaded non-smp emulator]) -AS_HELP_STRING([--disable-plain-emulator], [disable threaded non-smp emulator])) - -AC_ARG_WITH(termcap, -AS_HELP_STRING([--with-termcap], [use termcap (default)]) -AS_HELP_STRING([--without-termcap], - [do not use any termcap libraries (ncurses,curses,termcap,termlib)])) - -AC_ARG_ENABLE(kernel-poll, -AS_HELP_STRING([--enable-kernel-poll], [enable kernel poll support]) -AS_HELP_STRING([--disable-kernel-poll], [disable kernel poll support])) - -AC_ARG_ENABLE(sctp, -AS_HELP_STRING([--enable-sctp], [enable sctp support (default) -to on demand load the SCTP library in runtime]) -AS_HELP_STRING([--enable-sctp=lib], [enable sctp support -to link against the SCTP library]) -AS_HELP_STRING([--disable-sctp], [disable sctp support])) - -AC_ARG_WITH(dynamic-trace, -AS_HELP_STRING([--with-dynamic-trace={dtrace|lttng|systemtap}], - [specify use of dynamic trace framework, dtrace, lttng or systemtap]) -AS_HELP_STRING([--without-dynamic-trace], - [don't enable any dynamic tracing (default)])) -AC_ARG_ENABLE(vm-probes, -AS_HELP_STRING([--enable-vm-probes], - [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)])) -AC_ARG_WITH(javac, -AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) -AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) -AS_HELP_STRING([--without-javac], [don't use any Java compiler])) - -AC_ARG_ENABLE(megaco_flex_scanner_lineno, -AS_HELP_STRING([--disable-megaco-flex-scanner-lineno], - [disable megaco flex scanner lineno])) - -AC_ARG_ENABLE(megaco_reentrant_flex_scanner, -AS_HELP_STRING([--disable-megaco-reentrant-flex-scanner], - [disable reentrant megaco flex scanner])) - -AC_ARG_WITH(ssl, -AS_HELP_STRING([--with-ssl=PATH], [base location of OpenSSL include and lib directories]) -AS_HELP_STRING([--with-ssl], [use SSL (default)]) -AS_HELP_STRING([--without-ssl], [don't use SSL])) - -AC_ARG_WITH(ssl-incl, -AS_HELP_STRING([--with-ssl-incl=PATH], - [base location of OpenSSL include directory (if different than base location specified by --with-ssl=PATH)])) - -AC_ARG_WITH(ssl-zlib, -AS_HELP_STRING([--with-ssl-zlib=PATH], [Path to static zlib library to link the - crypto NIF with. This zlib library is most - often not necessary but might be needed in - order to link the NIF in some cases.])) - -AC_ARG_WITH(ssl-lib-subdir, -AS_HELP_STRING([--with-ssl-lib-subdir=RELATIVE_PATH], - [specify extra OpenSSL lib sub-directory to search in (relative to base directory)])) - -AC_ARG_WITH(ssl-rpath, -AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], - [runtime library path for OpenSSL. Default is 'yes', which equates to a - number of standard locations. If 'no', then no runtime - library paths will be used. Anything else should be a - comma or colon separated list of paths.])) - -AC_ARG_ENABLE(dynamic-ssl-lib, -AS_HELP_STRING([--enable-dynamic-ssl-lib], - [enable using dynamic openssl libraries when linking the crypto NIF]) -AS_HELP_STRING([--disable-dynamic-ssl-lib], - [disable using dynamic openssl libraries when linking the crypto NIF])) - -AC_ARG_ENABLE(fips, -AS_HELP_STRING([--enable-fips], [enable OpenSSL FIPS mode support]) -AS_HELP_STRING([--disable-fips], [disable OpenSSL FIPS mode support (default)])) - -AC_ARG_ENABLE(builtin-zlib, -AS_HELP_STRING([--enable-builtin-zlib], - [force use of our own built-in zlib])) - -AC_ARG_ENABLE(esock, -AS_HELP_STRING([--enable-esock], [enable builtin experimental socket (as a nif) support (default)]) -AS_HELP_STRING([--disable-esock], [disable builtin experimental socket (as a nif) support])) - -AC_ARG_ENABLE(sharing-preserving, -AS_HELP_STRING([--enable-sharing-preserving], - [enable copying of terms without destroying sharing])) - -dnl This functionality has been lost along the way... :( -dnl It could perhaps be nice to reintroduce some day; therefore, -dnl it is not removed just commented out. -dnl -dnl # -dnl # Set Erlang man page directory -dnl # -dnl AC_ARG_ENABLE(erlang-mandir, -dnl [ --disable-erlang-mandir do not install Erlang man pages in a private directory], -dnl [ case "$enableval" in -dnl no) erl_mandir=$mandir ;; -dnl *) erl_mandir='$(erlang_libdir)/man' ;; -dnl esac ], erl_mandir='$(erlang_libdir)/man') -dnl AC_SUBST(erl_mandir) - -AC_ARG_ENABLE(m64-build, -AS_HELP_STRING([--enable-m64-build], - [build 64bit binaries using the -m64 flag to (g)cc]), -[ case "$enableval" in - no) enable_m64_build=no ;; - *) enable_m64_build=yes ;; - esac -],enable_m64_build=no) - -AC_ARG_ENABLE(m32-build, -AS_HELP_STRING([--enable-m32-build], - [build 32bit binaries using the -m32 flag to (g)cc]), -[ case "$enableval" in - no) enable_m32_build=no ;; - *) enable_m32_build=yes ;; - esac -],enable_m32_build=no) - -AC_ARG_ENABLE(pie, -AS_HELP_STRING([--enable-pie], [build position independent executables]) -AS_HELP_STRING([--disable-pie], [do no build position independent executables])) - -AC_ARG_WITH(libatomic_ops, - AS_HELP_STRING([--with-libatomic_ops=PATH], - [specify and prefer usage of libatomic_ops in the ethread library])) - -m4_define(DEFAULT_SANITIZERS, [address,undefined]) -AC_ARG_ENABLE(sanitizers, - AS_HELP_STRING( - [--enable-sanitizers@<:@=comma-separated list of sanitizers@:>@], - [Default=DEFAULT_SANITIZERS])) - -AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) - -DEFAULT_VERBOSITY=0 -if test X${enable_silent_rules} = Xno; then - DEFAULT_VERBOSITY=1 -fi -AC_SUBST(DEFAULT_VERBOSITY) - -if test X${enable_m64_build} = Xyes; then - CFLAGS="-m64 $CFLAGS" - export CFLAGS - LDFLAGS="-m64 $LDFLAGS" - export LDFLAGS -fi -if test X${enable_m32_build} = Xyes; then - CFLAGS="-m32 $CFLAGS" - export CFLAGS - LDFLAGS="-m32 $LDFLAGS" - export LDFLAGS -fi - -ERL_DED - -AC_CONFIG_FILES([../Makefile output.mk ../make/$host/otp_ded.mk:../make/otp_ded.mk.in]) -AC_CONFIG_FILES([emd2exml], [chmod +x emd2exml]) - -AC_OUTPUT diff --git a/make/cross_check_erl b/make/cross_check_erl index fd9af6bae8f4..10bad47f9837 100755 --- a/make/cross_check_erl +++ b/make/cross_check_erl @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2021. All Rights Reserved. +# Copyright Ericsson AB 2010-2022. 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. @@ -118,7 +118,7 @@ test "X$build_otp" = "X$used_otp" || { * ERROR: Trying to cross compile an Erlang/$build_otp system with a different * Erlang/$used_otp system. When cross compiling you should compile * with an Erlang/OTP system of the same release. It is possible, -* however not recomended, to force the cross compilation even though +* however not recommended, to force the cross compilation even though * the wrong Erlang/OTP system is used. For more information on this, * and cross compiling Erlang/$build_otp in general, see the * \$ERL_TOP/xcomp/README file. diff --git a/make/doc.mk b/make/doc.mk index 47bb1c62acfa..247ae4b36ecc 100644 --- a/make/doc.mk +++ b/make/doc.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -30,7 +30,7 @@ RELCHUNKSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) APP_DIR = $(ERL_TOP)/lib/$(APPLICATION) APP_SRC_DIR = $(APP_DIR)/src -APP_EBIN_DIR = $(APP_DIR)/src +APP_EBIN_DIR = $(APP_DIR)/ebin # ---------------------------------------------------- HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ @@ -71,7 +71,7 @@ endif CHUNK_REF3_FILES = $(filter-out $(NO_CHUNKS), $(XML_ALL_REF3_FILES)) CHUNK_FILES = $(CHUNK_REF3_FILES:%.xml=$(CHUNKSDIR)/%.chunk) -ERL_CHUNK_FILES = $(patsubst $(APP_EBIN_DIR)/%.BEAM,$(CHUNKSDIR)/%.chunk,$(wildcard $(APP_EBIN_DIR)/*.beam)) +ERL_CHUNK_FILES = $(patsubst $(APP_EBIN_DIR)/%.beam,$(CHUNKSDIR)/%.chunk,$(wildcard $(APP_EBIN_DIR)/*.beam)) EMPTY_CHUNK_FILES = $(filter-out $(NO_CHUNKS:%.xml=$(CHUNKSDIR)/%.chunk) $(CHUNK_FILES), $(ERL_CHUNK_FILES)) @@ -129,7 +129,7 @@ info: @echo "XML_CHAPTER_FILES: $(XML_CHAPTER_FILES)" @echo "BOOK_FILES: $(BOOK_FILES)" -debug opt lcnt: +$(TYPES): clean clean_docs: clean_xml clean_pdf clean_html clean_man clean_chunks rm -rf $(EXTRA_FILES) @@ -156,9 +156,6 @@ clean_chunks: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -$(RELSYSDIR) $(RELSYSDIR)/doc: - $(INSTALL_DIR) "$@" - release_pdf_spec: pdf $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf" $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf" @@ -206,8 +203,8 @@ ifneq ($(MAN7_FILES),) $(INSTALL_DATA) $(MAN7_FILES) "$(RELEASE_PATH)/man/man7" endif -release_docs_spec: $(RELSYSDIR)/doc $(INFO_FILE) $(DOC_TARGETS:%=release_%_spec) - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) +release_docs_spec: $(INFO_FILE) $(DOC_TARGETS:%=release_%_spec) + $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)" ifneq ($(STANDARDS),) $(INSTALL_DIR) "$(RELEASE_PATH)/doc/standard" $(INSTALL_DATA) $(STANDARDS) "$(RELEASE_PATH)/doc/standard" diff --git a/make/emd2exml.in b/make/emd2exml.in index faed9ebe6904..0180d718bfb8 100755 --- a/make/emd2exml.in +++ b/make/emd2exml.in @@ -5,7 +5,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2021. All Rights Reserved. +%% Copyright Ericsson AB 2010-2022. 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. @@ -317,7 +317,7 @@ parse(#state{line = Line} = S) -> parse(get_line(put_text(S, Line))). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% Auxilary functions +%%% Auxiliary functions %%% %% diff --git a/make/install_bin b/make/install_bin index 3337e68a9fc5..86c453519e38 100755 --- a/make/install_bin +++ b/make/install_bin @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2021. All Rights Reserved. +# Copyright Ericsson AB 2010-2022. 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. @@ -681,7 +681,7 @@ EOF done # Remove after possible old install (done in a separate pass since I think -# the output looks nicer than if mixed). Note that we cannot test for existance +# the output looks nicer than if mixed). Note that we cannot test for existence # in a portable way, so force remove. for file in "$@"; do test "$file" != "" || continue diff --git a/make/otp.mk.in b/make/otp.mk.in index 2443c71a083e..1ed554ee7630 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -4,7 +4,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -47,14 +47,13 @@ CROSS_COMPILING = @CROSS_COMPILING@ # ---------------------------------------------------- DEFAULT_TARGETS = opt debug release release_docs clean docs -TYPES = @TYPES@ +TYPES = opt debug lcnt valgrind asan gcov +DEFAULT_TYPES = @DEFAULT_TYPES@ FLAVORS = @FLAVORS@ PRIMARY_FLAVOR= @PRIMARY_FLAVOR@ USE_PGO = @USE_PGO@ -USE_ESOCK = @USE_ESOCK@ - # Slash separated list of return values from $(origin VAR) # that are untrusted - set default in this file instead. # The list is not space separated since some return values @@ -93,6 +92,8 @@ BITS64 = @BITS64@ OTP_RELEASE = @OTP_RELEASE@ +ERL_DETERMINISTIC = @ERL_DETERMINISTIC@ + # ---------------------------------------------------- # Erlang language section # ---------------------------------------------------- @@ -100,13 +101,15 @@ EMULATOR = beam ifeq ($(ERL_COMPILE_WARNINGS_AS_ERRORS),yes) ERL_COMPILE_FLAGS += -Werror endif -ifdef BOOTSTRAP +ifdef PRIMARY_BOOTSTRAP ERL_COMPILE_FLAGS += +slim else ERL_COMPILE_FLAGS += +debug_info endif -ifeq ($(USE_ESOCK),yes) -ERL_COMPILE_FLAGS += -DUSE_ESOCK=true +ifeq ($(ERL_DETERMINISTIC),yes) + ERL_COMPILE_FLAGS += +deterministic + YRL_FLAGS += +deterministic + XRL_FLAGS += +deterministic endif ERLC_WFLAGS = -W diff --git a/make/otp_patch_solve_forward_merge_version b/make/otp_patch_solve_forward_merge_version index 98d9bcb75a68..d6b24041cf04 100644 --- a/make/otp_patch_solve_forward_merge_version +++ b/make/otp_patch_solve_forward_merge_version @@ -1 +1 @@ -17 +19 diff --git a/make/otp_subdir.mk b/make/otp_subdir.mk index 6ccf727c7551..12dfc5153df1 100644 --- a/make/otp_subdir.mk +++ b/make/otp_subdir.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2022. 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. @@ -19,13 +19,13 @@ # # Make include file for otp -.PHONY: debug opt lcnt release docs release_docs tests release_tests \ - clean depend valgrind asan static_lib +.PHONY: $(TYPES) release docs release_docs tests release_tests \ + clean depend static_lib # # Targets that don't affect documentation directories # -opt debug lcnt release docs release_docs tests release_tests clean depend valgrind asan static_lib xmllint: +$(TYPES) release docs release_docs tests release_tests clean depend static_lib xmllint: @set -e ; \ app_pwd=`pwd` ; \ if test -f vsn.mk; then \ diff --git a/make/otp_version_tickets b/make/otp_version_tickets index e69a6d6a1471..49edb9028ade 100644 --- a/make/otp_version_tickets +++ b/make/otp_version_tickets @@ -1,6 +1,3 @@ -OTP-18617 -OTP-18618 -OTP-18620 -OTP-18643 -OTP-18644 -OTP-18659 +OTP-18768 +OTP-18770 +OTP-18773 diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge index 295f43e3ce28..e69de29bb2d1 100644 --- a/make/otp_version_tickets_in_merge +++ b/make/otp_version_tickets_in_merge @@ -1,2 +0,0 @@ -OTP-17850 -OTP-17922 diff --git a/make/run_make.mk b/make/run_make.mk index 4185927f72c1..271e2e0f366e 100644 --- a/make/run_make.mk +++ b/make/run_make.mk @@ -29,7 +29,7 @@ include $(ERL_TOP)/make/output.mk include $(ERL_TOP)/make/target.mk -.PHONY: valgrind asan +.PHONY: valgrind asan test opt debug valgrind asan gcov gprof lcnt frmptr icount: $(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@ diff --git a/make/target.mk b/make/target.mk index abb586ebee6a..3c66e9437248 100644 --- a/make/target.mk +++ b/make/target.mk @@ -24,7 +24,7 @@ ifeq ($(OVERRIDE_TARGET),) ifeq ($(TARGET),) -TARGET := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +TARGET := $(shell $(ERL_TOP)/make/autoconf/config.guess) else @@ -55,7 +55,7 @@ endif ifneq ($(TARGET),) ifneq ($(TARGET),win32) -override TARGET := $(shell $(ERL_TOP)/erts/autoconf/config.sub $(TARGET)) +override TARGET := $(shell $(ERL_TOP)/make/autoconf/config.sub $(TARGET)) else endif else diff --git a/make/test_target_script.sh b/make/test_target_script.sh index df9d06a427a5..762318549065 100755 --- a/make/test_target_script.sh +++ b/make/test_target_script.sh @@ -3,7 +3,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2021. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -20,7 +20,6 @@ # %CopyrightEnd% # - RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -58,8 +57,13 @@ All tests will require several hours to run. You may want to check the following text file that describes how to run tests for a specific application. + $ERL_TOP/HOWTO/TESTING.md + +You can follow the test results here: + + file://$ERL_TOP/release/tests/test_server/index.html + EOM - echo $ERL_TOP/HOWTO/TESTING.md } print_highlighted_msg_with_printer $YELLOW print_msg } @@ -90,25 +94,6 @@ EOM print_highlighted_msg_with_printer $LIGHT_CYAN print_msg } -print_c_files_warning () { - print_msg () { - cat << EOM - -WARNING - -The test directory contains .c files which means that some test cases -will probably not work correctly when run through "make test". The -text file at the following location describes how one can compile and -run all test cases: - - -EOM - echo $ERL_TOP/HOWTO/TESTING.md - } - print_highlighted_msg_with_printer $YELLOW print_msg -} - - print_on_error_note () { print_msg () { cat << EOM @@ -128,6 +113,24 @@ EOM print_highlighted_msg_with_printer $NC print_msg } +release_erlang () { + local RELEASE_ROOT="${1}" + if ! (cd $ERL_TOP && make release TYPE= release_docs DOC_TARGETS=chunks RELEASE_ROOT="${RELEASE_ROOT}"); then + return 1 + fi + if ! (cd "$RELEASE_ROOT" && ./Install -minimal "`pwd`"); then + return 1 + fi + ## Need to release both TYPE= and TYPE=$TYPE for tests to work + if [ "$TYPE" != "" ]; then + if ! (cd $ERL_TOP && make release TYPE=$TYPE RELEASE_ROOT="${RELEASE_ROOT}"); then + return 1 + fi + fi + export PATH="${RELEASE_ROOT}/bin:$PATH" + return 0 +} + # Check ERL_TOP if [ -d "$1" ] @@ -150,7 +153,6 @@ fi export ERL_TOP=$ERL_TOP - if [ -z "${ARGS}" ] then ARGS="$@" @@ -160,7 +162,7 @@ fi DIR=`pwd` if [ "$DIR" -ef "$ERL_TOP" ] then - TARGET_SYS=`$ERL_TOP/erts/autoconf/config.guess` + TARGET_SYS=`$ERL_TOP/make/autoconf/config.guess` REL_DIR="$ERL_TOP/release/$TARGET_SYS" cd "$REL_DIR" ./Install -minimal "`pwd`" @@ -170,7 +172,7 @@ then echo "The tests will start in a few seconds..." sleep 45 cd "$ERL_TOP/release/tests/test_server" - erl -eval "ts:install(),erlang:halt()" + erl -noinput -eval "ts:install(),erlang:halt()" erl -noinput -eval "ts:run([all_tests,batch]),erlang:halt()" exit $? fi @@ -182,78 +184,153 @@ then exit 1 fi - APPLICATION="`basename $DIR`" + +if [ "$APPLICATION" = "erts" ]; then + APPLICATION="system" +fi + CT_RUN="$ERL_TOP/bin/ct_run" +PATH="${ERL_TOP}/bin/:${PATH}" MAKE_TEST_DIR="`pwd`/make_test_dir" MAKE_TEST_REL_DIR="$MAKE_TEST_DIR/${APPLICATION}_test" MAKE_TEST_CT_LOGS="$MAKE_TEST_DIR/ct_logs" -RELEASE_TEST_SPEC_LOG="$MAKE_TEST_CT_LOGS/release_tests_spec_log" +RELEASE_TEST_SPEC_LOG="$MAKE_TEST_DIR/release_tests_spec_log" +INSTALL_TEST_LOG="$MAKE_TEST_DIR/install_tests_log" +COMPILE_TEST_LOG="$MAKE_TEST_DIR/compile_tests_log" +RELEASE_ROOT=${RELEASE_ROOT:-"${MAKE_TEST_DIR}/Erlang ∅⊤℞"} +RELEASE_LOG="$MAKE_TEST_DIR/release_tests_log" cd test -echo "The tests in test directory for $APPLICATION will be executed with ct_run" + +mkdir -p "$MAKE_TEST_DIR" +mkdir -p "$MAKE_TEST_CT_LOGS" + +# Check that we are running a released erlang when we have to +if [ "$TEST_NEEDS_RELEASE" = "true" ]; then + MSG=$(cat < "${RELEASE_LOG}" 2>&1 + if [ $? != 0 ] + then + print_highlighted_msg $RED "\"make release RELEASE_ROOT=${RELEASE_ROOT}\" failed.\nSee ${RELEASE_LOG} for full logs" + tail -30 "${RELEASE_LOG}" + exit 1 + fi + CT_RUN="${RELEASE_ROOT}/bin/ct_run" + PATH="${RELEASE_ROOT}/bin/":${PATH} +fi + +echo "The tests in test directory for $APPLICATION will be executed with ${CT_RUN}" if [ -z "${ARGS}" ] then if [ ! -d "$MAKE_TEST_DIR" ] then print_all_tests_for_application_notes fi - if find . -type f -name '*.c' | grep -q "." - then - print_c_files_warning - fi fi -mkdir -p "$MAKE_TEST_DIR" -mkdir -p "$MAKE_TEST_REL_DIR" -mkdir -p "$MAKE_TEST_CT_LOGS" -make RELSYSDIR=$MAKE_TEST_REL_DIR release_tests_spec > $RELEASE_TEST_SPEC_LOG 2>&1 +make RELEASE_PATH=$MAKE_TEST_DIR release_tests_spec > $RELEASE_TEST_SPEC_LOG 2>&1 if [ $? != 0 ] then cat $RELEASE_TEST_SPEC_LOG - print_highlighted_msg $RED "\"make RELSYSDIR="$MAKE_TEST_REL_DIR" release_tests_spec\" failed." + print_highlighted_msg $RED "\"make RELEASE_PATH="$MAKE_TEST_DIR" release_tests_spec\" failed." exit 1 fi -SPEC_FLAG="" -SPEC_FILE="" if [ -z "${ARGS}" ] then - SPEC_FLAG="-spec" if [ "${WSLcross}" != "true" ] ; then + SPEC_FILE_POSTFIX="$MAKE_TEST_REL_DIR/${APPLICATION}_${SPEC_POSTFIX}.spec" SPEC_FILE="$MAKE_TEST_REL_DIR/$APPLICATION.spec" else + SPEC_FILE_POSTFIX=`w32_path.sh -m "$MAKE_TEST_REL_DIR/${APPLICATION}_${SPEC_POSTFIX}.spec"` SPEC_FILE=`w32_path.sh -m "$MAKE_TEST_REL_DIR/$APPLICATION.spec"` fi - ARGS="$SPEC_FLAG $SPEC_FILE" + if [ -f "$SPEC_FILE_POSTFIX" ]; then + SPEC_FILE="$SPEC_FILE_POSTFIX" + fi + ARGS="-spec $SPEC_FILE" +fi + +ARGS="${ARGS} ${EXTRA_ARGS}" + +if ([ -n "${TYPE}" ] || [ -n "${FLAVOR}" ]) && [ "${WSLcross}" = "true" ]; then + print_highlighted_msg $RED "Setting TYPE or FLAVOR is not implemented yet for WSL" + exit 1; +fi + +if [ -n "${TYPE}" ]; then + ERL_AFLAGS="${ERL_AFLAGS} -emu_type ${TYPE}" +fi +if [ -n "${FLAVOR}" ]; then + ERL_AFLAGS="${ERL_AFLAGS} -emu_flavor ${FLAVOR}" +fi + +# Compile test server and configure +if [ ! -f "$ERL_TOP/lib/common_test/test_server/variables" ]; then + cd "$ERL_TOP/lib/common_test/test_server" + ( make && erl -noshell -eval "ts:install()." -s init stop ) > "$INSTALL_TEST_LOG" 2>&1 + if [ $? != 0 ] + then + cat "$INSTALL_TEST_LOG" + print_highlighted_msg $RED "\"make && erl -eval 'ts:install()'\" in common_test/test_server failed." + exit 1 + fi fi -# Compile test server -(cd "$ERL_TOP/lib/common_test/test_server" && make) + # Run ct_run cd $MAKE_TEST_REL_DIR +erl -sname test -noshell -pa "$ERL_TOP/lib/common_test/test_server" \ + -eval "ts:compile_datadirs(\"$ERL_TOP/lib/common_test/test_server/variables\",\"*_SUITE_data\")."\ + -s init stop > "$COMPILE_TEST_LOG" 2>&1 + +if [ $? != 0 ] +then + cat "$COMPILE_TEST_LOG" + print_highlighted_msg $RED "\"erl -eval 'ts:compile_datadirs/2'\" failed." + exit 1 +fi + +CT_NODENAME=${CT_NODENAME:-test_server} + if [ "${WSLcross}" != "true" ] then - $CT_RUN -logdir $MAKE_TEST_CT_LOGS\ - -pa "$ERL_TOP/lib/common_test/test_server"\ - ${ARGS}\ - -erl_args\ - -env ERL_CRASH_DUMP "$MAKE_TEST_DIR/${APPLICATION}_erl_crash.dump"\ - -boot start_sasl\ - -sasl errlog_type error\ - -pz "$ERL_TOP/lib/common_test/test_server"\ - -pz "."\ - -ct_test_vars "{net_dir,\"\"}"\ - -noshell\ - -sname test_server\ - -rsh ssh\ + if [ -n "${CTRUN_TIMEOUT}" ]; then + CTRUN_TIMEOUT="timeout -s ABRT --foreground --preserve-status $((${CTRUN_TIMEOUT}+5))m timeout -s USR1 --foreground --preserve-status ${CTRUN_TIMEOUT}m" + fi + ERL_AFLAGS="${ERL_AFLAGS}" $CTRUN_TIMEOUT \ + "${CT_RUN}" -logdir $MAKE_TEST_CT_LOGS \ + -pa "$ERL_TOP/lib/common_test/test_server" \ + -config "$ERL_TOP/lib/common_test/test_server/ts.config" \ + -config "$ERL_TOP/lib/common_test/test_server/ts.unix.config" \ + -exit_status ignore_config \ + ${ARGS} \ + -erl_args \ + -env ERL_CRASH_DUMP "$MAKE_TEST_DIR/${APPLICATION}_erl_crash.dump" \ + -boot start_sasl \ + -sasl errlog_type error \ + -pz "$ERL_TOP/lib/common_test/test_server" \ + -pz "." \ + -ct_test_vars "{net_dir,\"\"}" \ + -noinput \ + -sname ${CT_NODENAME}\ + -rsh ssh \ ${ERL_ARGS} else WIN_MAKE_TEST_CT_LOGS=`w32_path.sh -m "$MAKE_TEST_CT_LOGS"` WIN_MAKE_TEST_DIR=`w32_path.sh -m "$MAKE_TEST_DIR"` WIN_ERL_TOP=`w32_path.sh -m "$ERL_TOP"` - $CT_RUN.exe -logdir $WIN_MAKE_TEST_CT_LOGS\ + "$CT_RUN.exe" -logdir $WIN_MAKE_TEST_CT_LOGS\ -pa "$WIN_ERL_TOP/lib/common_test/test_server"\ + -config "$WIN_ERL_TOP/lib/common_test/test_server/ts.config"\ + -config "$WIN_ERL_TOP/lib/common_test/test_server/ts.win32.config"\ + -exit_status ignore_config \ ${ARGS}\ -erl_args\ -env ERL_CRASH_DUMP "$WIN_MAKE_TEST_DIR/${APPLICATION}_erl_crash.dump"\ @@ -262,8 +339,8 @@ else -pz "$WIN_ERL_TOP/lib/common_test/test_server"\ -pz "."\ -ct_test_vars "{net_dir,\"\"}"\ - -noshell\ - -sname test_server\ + -noinput\ + -sname ${CT_NODENAME}\ -rsh ssh\ ${ERL_ARGS} fi diff --git a/otp_build b/otp_build index 324d64f0dbfe..c9d118c2a4e1 100755 --- a/otp_build +++ b/otp_build @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2021. All Rights Reserved. +# Copyright Ericsson AB 2002-2023. 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. @@ -19,15 +19,13 @@ # %CopyrightEnd% # -USE_AUTOCONF_VERSION=2.69 +USE_AUTOCONF_VERSION=2.71 -aclocal_dirs="make ./lib/crypto ./lib/erl_interface ./lib/odbc ./lib/wx ./lib/megaco" -autoconf_aux_dirs="./lib/common_test/priv/auxdir ./lib/erl_interface/src/auxdir ./lib/common_test/test_server ./lib/wx/autoconf" +autoconf_aux_dirs="./erts/autoconf ./lib/common_test/test_server" -aclocal_master="./erts/aclocal.m4" -install_sh_master="./erts/autoconf/install-sh" -config_guess_master="./erts/autoconf/config.guess" -config_sub_master="./erts/autoconf/config.sub" +install_sh_master="./make/autoconf/install-sh" +config_guess_master="./make/autoconf/config.guess" +config_sub_master="./make/autoconf/config.sub" # Global configuration variables # @@ -58,6 +56,8 @@ usage () echo " release - creates a small release to " echo " release [-a|-s|-t] - creates full release to " echo " tests

    - Build testsuites to " + echo " check [--help|...] - Perform various build checks. See --help for more info" + echo " and options." echo "" echo "-a builds all applications" echo "-s builds a small system (default)" @@ -119,7 +119,7 @@ check_erltop () { ERLTOP_FORCED=false if [ "X$ERL_TOP" = "X" ]; then - if [ -f ./otp_build -a -f ./erts/autoconf/config.guess ]; then + if [ -f ./otp_build -a -f ./make/autoconf/config.guess ]; then ERLTOP_FORCED=true ERL_TOP=`pwd` export ERL_TOP @@ -171,11 +171,13 @@ set_config_flags () # (in the cross compilation case the whole command line as well as # the cross configuration have been moved here). - if target_contains free_source; then - CONFIG_FLAGS="$CONFIG_FLAGS --host=$TARGET" - fi if target_contains win32; then - CONFIG_FLAGS="--build=$BUILDSYS build_alias=win32 --host=win32 --target=win32 $CONFIG_FLAGS" + if [ "$CONFIG_SUBTYPE" = "win64" ]; then + bht_type=local-x86_64-pc-windows + else + bht_type=local-x86-pc-windows + fi + CONFIG_FLAGS="--build=$bht_type --host=$bht_type --target=$bht_type $CONFIG_FLAGS" fi @@ -196,7 +198,8 @@ NL="\ do_update_configure () { get_do_commit $1 - + + export AUTOCONF_VERSION="$USE_AUTOCONF_VERSION" ac_ver_blob=`autoconf --version` if [ $? -ne 0 ]; then echo "ERROR: Failed to check autoconf version! You need to have autoconf of version $USE_AUTOCONF_VERSION in path." 1>&2 @@ -213,10 +216,6 @@ do_update_configure () out_files= - for dir in $aclocal_dirs; do - $install_sh_master -m 644 -t "$dir" "$aclocal_master" - done - install_sh=`basename $install_sh_master` config_guess=`basename $config_guess_master` config_sub=`basename $config_sub_master` @@ -236,7 +235,7 @@ do_update_configure () export TARGET for d in $AUTOCONF_SUBDIRS; do - file="$d/configure.in" + file="$d/configure.ac" [ -f "$file" ] || continue echo "" [ ! -d "$d/autom4te.cache" ] || { @@ -249,12 +248,12 @@ do_update_configure () } echo "=== running autoconf in $d" - ( cd "$d" && autoconf ) || exit 1 + ( cd "$d" && autoconf -B "$ERL_TOP/make/autoconf") || exit 1 out_files="$out_files $d/configure" chdr=`cat "$file" | sed -n "s|.*\(AC_CONFIG_HEADER\).*|\1|p"` [ "$chdr" = "AC_CONFIG_HEADER" ] || continue echo "=== running autoheader in $d" - ( cd "$d" && autoheader ) || exit 1 + ( cd "$d" && autoheader -B "$ERL_TOP/make/autoconf") || exit 1 out_files="$out_files $d/config.h.in" done @@ -350,8 +349,8 @@ try_cross_configure () test "X$build_value" != "X" || build_value="$BUILDSYS" - build_sys=`"$ERL_TOP/erts/autoconf/config.sub" "$build_value"` || exit 1 - host_sys=`"$ERL_TOP/erts/autoconf/config.sub" "$host_value"` || exit 1 + build_sys=`"$ERL_TOP/make/autoconf/config.sub" "$build_value"` || exit 1 + host_sys=`"$ERL_TOP/make/autoconf/config.sub" "$host_value"` || exit 1 test "$host_sys" = "$build_sys" || cross_configure=yes @@ -655,15 +654,15 @@ echo_env_cygwin () echo_setenv AR ar.sh ';' echo_setenv RANLIB true ';' if [ X"$X64" = X"true" ]; then - if [ -f "$ERL_TOP/erts/autoconf/win64.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win64.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win64.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win64.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';' else - if [ -f "$ERL_TOP/erts/autoconf/win32.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win32.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win32.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win32.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';' fi echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';' echo_setenv PATH "$WIN32_WRAPPER_PATH:$P3" ';' @@ -720,15 +719,15 @@ echo_env_msys () echo_setenv AR ar.sh ';' echo_setenv RANLIB true ';' if [ X"$X64" = X"true" ]; then - if [ -f "$ERL_TOP/erts/autoconf/win64.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win64.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win64.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win64.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';' else - if [ -f "$ERL_TOP/erts/autoconf/win32.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win32.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win32.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win32.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';' fi echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';' echo_setenv PATH "$WIN32_WRAPPER_PATH:$P3" ';' @@ -769,15 +768,15 @@ echo_env_wsl () echo_setenv AR ar.sh ';' echo_setenv RANLIB true ';' if [ X"$X64" = X"true" ]; then - if [ -f "$ERL_TOP/erts/autoconf/win64.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win64.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win64.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win64.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';' else - if [ -f "$ERL_TOP/erts/autoconf/win32.config.cache.static" ]; then - echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/erts/autoconf/win32.config.cache.static" ';' + if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then + echo_setenv OVERRIDE_CONFIG_CACHE_STATIC "$ERL_TOP/make/autoconf/win32.config.cache.static" ';' fi - echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/erts/autoconf/win32.config.cache" ';' + echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';' fi echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';' echo_setenv PATH "$WIN32_WRAPPER_PATH:$PATH" ';' @@ -1001,11 +1000,15 @@ do_tests () fi } +do_check () +{ + exec $ERL_TOP/scripts/otp_build_check "$@" +} + do_debuginfo_win32 () { setup_make - (cd erts/emulator && $MAKE MAKE="$MAKE" TARGET=$TARGET FLAVOR=smp debug &&\ - $MAKE MAKE="$MAKE" TARGET=$TARGET FLAVOR=plain debug) || exit 1 + (cd erts/emulator && $MAKE MAKE="$MAKE" TARGET=$TARGET debug) || exit 1 if [ -z "$1" ]; then RELDIR="$ERL_TOP/release/$TARGET" else @@ -1013,7 +1016,7 @@ do_debuginfo_win32 () fi BINDIR="$ERL_TOP/bin/$TARGET" EVSN=`grep '^VSN' erts/vsn.mk | sed 's,^VSN.*=[^0-9]*\([0-9].*\)$,@\1,g;s,^[^@].*,,g;s,^@,,g'` - for f in beam.debug.smp.dll beam.smp.pdb beam.debug.smp.dll.pdb erl.pdb werl.pdb erlexec.pdb; do + for f in beam.debug.smp.dll beam.smp.pdb beam.debug.smp.dll.pdb erl.pdb erlexec.pdb; do if [ -f $BINDIR/$f ]; then rm -f $RELDIR/erts-$EVSN/bin/$f cp $BINDIR/$f $RELDIR/erts-$EVSN/bin/$f @@ -1115,7 +1118,7 @@ unset ${erl_otp_flags} # Target first guess, won't necessarily hold, may be changed for # certain parameters. if [ X"$TARGET" = X"" ]; then - TARGET=`"$ERL_TOP/erts/autoconf/config.guess"` + TARGET=`"$ERL_TOP/make/autoconf/config.guess"` fi BUILDSYS=$TARGET @@ -1221,7 +1224,7 @@ case "$1" in do_configure "$@";; opt) do_boot;; - plain|smp) + smp) if [ $minus_x_flag = false ]; then TYPE=opt fi; @@ -1298,6 +1301,9 @@ case "$1" in echo_env_cross "$2";; env_bootstrap) echo_env_bootstrap;; + check) + shift; + do_check "$@";; *) usage;; esac diff --git a/otp_patch_apply b/otp_patch_apply index bf6062297842..b95ce90ddb95 100755 --- a/otp_patch_apply +++ b/otp_patch_apply @@ -223,7 +223,7 @@ export ERL_TOP="$sdir" test -f "$sdir/otp_build" || error "$ERL_TOP" $invalid_src test -f "$sdir/OTP_VERSION" || error "$ERL_TOP" $invalid_src test -f "$sdir/otp_versions.table" || error "$ERL_TOP" $invalid_src -test -f "$sdir/erts/autoconf/config.guess" || error "$ERL_TOP" $invalid_src +test -f "$sdir/make/autoconf/config.guess" || error "$ERL_TOP" $invalid_src test -f "$sdir/make/verify_runtime_dependencies" || error "$ERL_TOP" $invalid_src test -x "$sdir/bootstrap/bin/erl" || error $not_built test -x "$sdir/bootstrap/bin/erlc" || error $not_built @@ -293,7 +293,7 @@ mkdir=`find_prog mkdir` # Setup build stuff if [ "x$TARGET" = "x" ]; then - TARGET=`$ERL_TOP/erts/autoconf/config.guess` + TARGET=`$ERL_TOP/make/autoconf/config.guess` fi BUILDSYS=$TARGET if [ -z "$MAKE" ]; then diff --git a/otp_versions.table b/otp_versions.table index 4b208a3ca8a7..30f14e0d568d 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,3 +1,30 @@ +OTP-26.1.1 : compiler-8.4.1 stdlib-5.1.1 wx-2.3.1 # asn1-5.2 common_test-1.25.1 crypto-5.3 debugger-5.3.2 dialyzer-5.1.1 diameter-2.3 edoc-1.2 eldap-1.2.11 erl_docgen-1.5.1 erl_interface-5.4 erts-14.1 et-1.7 eunit-2.8.2 ftp-1.2 inets-9.0.2 jinterface-1.14 kernel-9.1 megaco-4.5 mnesia-4.22.1 observer-2.15.1 odbc-2.14.1 os_mon-2.9 parsetools-2.5 public_key-1.14.1 reltool-1.0 runtime_tools-2.0 sasl-4.2.1 snmp-5.15 ssh-5.0.1 ssl-11.0.3 syntax_tools-3.1 tftp-1.1 tools-3.6 xmerl-1.3.31.1 : +OTP-26.1 : asn1-5.2 common_test-1.25.1 compiler-8.4 crypto-5.3 debugger-5.3.2 dialyzer-5.1.1 erl_docgen-1.5.1 erts-14.1 inets-9.0.2 kernel-9.1 megaco-4.5 mnesia-4.22.1 observer-2.15.1 public_key-1.14.1 snmp-5.15 ssl-11.0.3 stdlib-5.1 # diameter-2.3 edoc-1.2 eldap-1.2.11 erl_interface-5.4 et-1.7 eunit-2.8.2 ftp-1.2 jinterface-1.14 odbc-2.14.1 os_mon-2.9 parsetools-2.5 reltool-1.0 runtime_tools-2.0 sasl-4.2.1 ssh-5.0.1 syntax_tools-3.1 tftp-1.1 tools-3.6 wx-2.3 xmerl-1.3.31.1 : +OTP-26.0.2 : compiler-8.3.2 erts-14.0.2 kernel-9.0.2 ssh-5.0.1 ssl-11.0.2 stdlib-5.0.2 # asn1-5.1 common_test-1.25 crypto-5.2 debugger-5.3.1 dialyzer-5.1 diameter-2.3 edoc-1.2 eldap-1.2.11 erl_docgen-1.5 erl_interface-5.4 et-1.7 eunit-2.8.2 ftp-1.2 inets-9.0.1 jinterface-1.14 megaco-4.4.4 mnesia-4.22 observer-2.15 odbc-2.14.1 os_mon-2.9 parsetools-2.5 public_key-1.14 reltool-1.0 runtime_tools-2.0 sasl-4.2.1 snmp-5.14 syntax_tools-3.1 tftp-1.1 tools-3.6 wx-2.3 xmerl-1.3.32 : +OTP-26.0.1 : compiler-8.3.1 erts-14.0.1 inets-9.0.1 kernel-9.0.1 ssl-11.0.1 stdlib-5.0.1 xmerl-1.3.32 # asn1-5.1 common_test-1.25 crypto-5.2 debugger-5.3.1 dialyzer-5.1 diameter-2.3 edoc-1.2 eldap-1.2.11 erl_docgen-1.5 erl_interface-5.4 et-1.7 eunit-2.8.2 ftp-1.2 jinterface-1.14 megaco-4.4.4 mnesia-4.22 observer-2.15 odbc-2.14.1 os_mon-2.9 parsetools-2.5 public_key-1.14 reltool-1.0 runtime_tools-2.0 sasl-4.2.1 snmp-5.14 ssh-5.0 syntax_tools-3.1 tftp-1.1 tools-3.6 wx-2.3 : +OTP-26.0 : asn1-5.1 common_test-1.25 compiler-8.3 crypto-5.2 dialyzer-5.1 diameter-2.3 erl_docgen-1.5 erl_interface-5.4 erts-14.0 et-1.7 ftp-1.2 inets-9.0 jinterface-1.14 kernel-9.0 megaco-4.4.4 mnesia-4.22 observer-2.15 odbc-2.14.1 os_mon-2.9 parsetools-2.5 public_key-1.14 reltool-1.0 runtime_tools-2.0 sasl-4.2.1 snmp-5.14 ssh-5.0 ssl-11.0 stdlib-5.0 syntax_tools-3.1 tftp-1.1 tools-3.6 wx-2.3 # debugger-5.3.1 edoc-1.2 eldap-1.2.11 eunit-2.8.2 xmerl-1.3.31 : +OTP-25.3.2.6 : crypto-5.1.4.1 debugger-5.3.1.2 erts-13.2.2.3 inets-8.3.1.2 kernel-8.5.4.2 mnesia-4.21.4.1 public_key-1.13.3.1 ssl-10.9.1.2 # asn1-5.0.21 common_test-1.24.0.1 compiler-8.2.6.3 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 jinterface-1.13.2 megaco-4.4.3 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 stdlib-4.3.1.2 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31.1 : +OTP-25.3.2.5 : inets-8.3.1.1 # asn1-5.0.21 common_test-1.24.0.1 compiler-8.2.6.3 crypto-5.1.4 debugger-5.3.1.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 erts-13.2.2.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 jinterface-1.13.2 kernel-8.5.4.1 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 ssl-10.9.1.1 stdlib-4.3.1.2 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31.1 : +OTP-25.3.2.4 : common_test-1.24.0.1 # asn1-5.0.21 compiler-8.2.6.3 crypto-5.1.4 debugger-5.3.1.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 erts-13.2.2.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1 jinterface-1.13.2 kernel-8.5.4.1 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 ssl-10.9.1.1 stdlib-4.3.1.2 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31.1 : +OTP-25.3.2.3 : compiler-8.2.6.3 debugger-5.3.1.1 erts-13.2.2.2 kernel-8.5.4.1 ssl-10.9.1.1 stdlib-4.3.1.2 # asn1-5.0.21 common_test-1.24 crypto-5.1.4 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1 jinterface-1.13.2 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31.1 : +OTP-25.3.2.2 : compiler-8.2.6.2 # asn1-5.0.21 common_test-1.24 crypto-5.1.4 debugger-5.3.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 erts-13.2.2.1 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1 jinterface-1.13.2 kernel-8.5.4 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 ssl-10.9.1 stdlib-4.3.1.1 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31.1 : +OTP-25.3.2.1 : compiler-8.2.6.1 erts-13.2.2.1 stdlib-4.3.1.1 xmerl-1.3.31.1 # asn1-5.0.21 common_test-1.24 crypto-5.1.4 debugger-5.3.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1 jinterface-1.13.2 kernel-8.5.4 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.2 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 ssl-10.9.1 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 : +OTP-25.3.2 : compiler-8.2.6 erts-13.2.2 os_mon-2.8.2 # asn1-5.0.21 common_test-1.24 crypto-5.1.4 debugger-5.3.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 eldap-1.2.11 erl_docgen-1.4 erl_interface-5.3.2 et-1.6.5 eunit-2.8.2 ftp-1.1.4 inets-8.3.1 jinterface-1.13.2 kernel-8.5.4 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 snmp-5.13.5 ssh-4.15.3 ssl-10.9.1 stdlib-4.3.1 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 wx-2.2.2 xmerl-1.3.31 : +OTP-25.3.1 : compiler-8.2.5 crypto-5.1.4 eldap-1.2.11 erl_interface-5.3.2 erts-13.2.1 inets-8.3.1 snmp-5.13.5 ssl-10.9.1 stdlib-4.3.1 wx-2.2.2 # asn1-5.0.21 common_test-1.24 debugger-5.3.1 dialyzer-5.0.5 diameter-2.2.7 edoc-1.2 erl_docgen-1.4 et-1.6.5 eunit-2.8.2 ftp-1.1.4 jinterface-1.13.2 kernel-8.5.4 megaco-4.4.3 mnesia-4.21.4 observer-2.14 odbc-2.14 os_mon-2.8.1 parsetools-2.4.1 public_key-1.13.3 reltool-0.9.1 runtime_tools-1.19 sasl-4.2 ssh-4.15.3 syntax_tools-3.0.1 tftp-1.0.4 tools-3.5.3 xmerl-1.3.31 : +OTP-25.3 : common_test-1.24 compiler-8.2.4 crypto-5.1.3 debugger-5.3.1 dialyzer-5.0.5 erl_interface-5.3.1 erts-13.2 eunit-2.8.2 ftp-1.1.4 inets-8.3 jinterface-1.13.2 kernel-8.5.4 megaco-4.4.3 mnesia-4.21.4 os_mon-2.8.1 public_key-1.13.3 reltool-0.9.1 snmp-5.13.4 ssh-4.15.3 ssl-10.9 stdlib-4.3 syntax_tools-3.0.1 tftp-1.0.4 xmerl-1.3.31 # asn1-5.0.21 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 et-1.6.5 observer-2.14 odbc-2.14 parsetools-2.4.1 runtime_tools-1.19 sasl-4.2 tools-3.5.3 wx-2.2.1 : +OTP-25.2.3 : erts-13.1.5 inets-8.2.2 ssh-4.15.2 ssl-10.8.7 # asn1-5.0.21 common_test-1.23.3 compiler-8.2.3 crypto-5.1.2 debugger-5.3 dialyzer-5.0.4 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 eunit-2.8.1 ftp-1.1.3 jinterface-1.13.1 kernel-8.5.3 megaco-4.4.2 mnesia-4.21.3 observer-2.14 odbc-2.14 os_mon-2.8 parsetools-2.4.1 public_key-1.13.2 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13.3 stdlib-4.2 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2.1 xmerl-1.3.30 : +OTP-25.2.2 : ftp-1.1.3 # asn1-5.0.21 common_test-1.23.3 compiler-8.2.3 crypto-5.1.2 debugger-5.3 dialyzer-5.0.4 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 erts-13.1.4 et-1.6.5 eunit-2.8.1 inets-8.2.1 jinterface-1.13.1 kernel-8.5.3 megaco-4.4.2 mnesia-4.21.3 observer-2.14 odbc-2.14 os_mon-2.8 parsetools-2.4.1 public_key-1.13.2 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13.3 ssh-4.15.1 ssl-10.8.6 stdlib-4.2 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2.1 xmerl-1.3.30 : +OTP-25.2.1 : common_test-1.23.3 compiler-8.2.3 erts-13.1.4 inets-8.2.1 kernel-8.5.3 snmp-5.13.3 # asn1-5.0.21 crypto-5.1.2 debugger-5.3 dialyzer-5.0.4 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 eunit-2.8.1 ftp-1.1.2 jinterface-1.13.1 megaco-4.4.2 mnesia-4.21.3 observer-2.14 odbc-2.14 os_mon-2.8 parsetools-2.4.1 public_key-1.13.2 reltool-0.9 runtime_tools-1.19 sasl-4.2 ssh-4.15.1 ssl-10.8.6 stdlib-4.2 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2.1 xmerl-1.3.30 : +OTP-25.2 : common_test-1.23.2 compiler-8.2.2 dialyzer-5.0.4 erts-13.1.3 ftp-1.1.2 inets-8.2 kernel-8.5.2 megaco-4.4.2 mnesia-4.21.3 observer-2.14 os_mon-2.8 public_key-1.13.2 snmp-5.13.2 ssh-4.15.1 ssl-10.8.6 stdlib-4.2 wx-2.2.1 # asn1-5.0.21 crypto-5.1.2 debugger-5.3 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 eunit-2.8.1 jinterface-1.13.1 odbc-2.14 parsetools-2.4.1 reltool-0.9 runtime_tools-1.19 sasl-4.2 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 xmerl-1.3.30 : +OTP-25.1.2.1 : erts-13.1.2.1 snmp-5.13.1.1 # asn1-5.0.21 common_test-1.23.1 compiler-8.2.1 crypto-5.1.2 debugger-5.3 dialyzer-5.0.3 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 eunit-2.8.1 ftp-1.1.1 inets-8.1 jinterface-1.13.1 kernel-8.5.1 megaco-4.4.1 mnesia-4.21.2 observer-2.13 odbc-2.14 os_mon-2.7.1 parsetools-2.4.1 public_key-1.13.1 reltool-0.9 runtime_tools-1.19 sasl-4.2 ssh-4.15 ssl-10.8.5 stdlib-4.1.1 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.30 : +OTP-25.1.2 : erts-13.1.2 mnesia-4.21.2 # asn1-5.0.21 common_test-1.23.1 compiler-8.2.1 crypto-5.1.2 debugger-5.3 dialyzer-5.0.3 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 eunit-2.8.1 ftp-1.1.1 inets-8.1 jinterface-1.13.1 kernel-8.5.1 megaco-4.4.1 observer-2.13 odbc-2.14 os_mon-2.7.1 parsetools-2.4.1 public_key-1.13.1 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13.1 ssh-4.15 ssl-10.8.5 stdlib-4.1.1 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.30 : +OTP-25.1.1 : asn1-5.0.21 dialyzer-5.0.3 erts-13.1.1 eunit-2.8.1 kernel-8.5.1 ssl-10.8.5 stdlib-4.1.1 # common_test-1.23.1 compiler-8.2.1 crypto-5.1.2 debugger-5.3 diameter-2.2.7 edoc-1.2 eldap-1.2.10 erl_docgen-1.4 erl_interface-5.3 et-1.6.5 ftp-1.1.1 inets-8.1 jinterface-1.13.1 megaco-4.4.1 mnesia-4.21.1 observer-2.13 odbc-2.14 os_mon-2.7.1 parsetools-2.4.1 public_key-1.13.1 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13.1 ssh-4.15 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.30 : +OTP-25.1 : asn1-5.0.20 common_test-1.23.1 compiler-8.2.1 crypto-5.1.2 dialyzer-5.0.2 diameter-2.2.7 erl_docgen-1.4 erts-13.1 eunit-2.8 inets-8.1 jinterface-1.13.1 kernel-8.5 megaco-4.4.1 observer-2.13 parsetools-2.4.1 public_key-1.13.1 snmp-5.13.1 ssh-4.15 ssl-10.8.4 stdlib-4.1 xmerl-1.3.30 # debugger-5.3 edoc-1.2 eldap-1.2.10 erl_interface-5.3 et-1.6.5 ftp-1.1.1 mnesia-4.21.1 odbc-2.14 os_mon-2.7.1 reltool-0.9 runtime_tools-1.19 sasl-4.2 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 : +OTP-25.0.4 : erts-13.0.4 kernel-8.4.2 # asn1-5.0.19 common_test-1.23 compiler-8.2 crypto-5.1.1 debugger-5.3 dialyzer-5.0.1 diameter-2.2.6 edoc-1.2 eldap-1.2.10 erl_docgen-1.3 erl_interface-5.3 et-1.6.5 eunit-2.7.1 ftp-1.1.1 inets-8.0 jinterface-1.13 megaco-4.4 mnesia-4.21.1 observer-2.12 odbc-2.14 os_mon-2.7.1 parsetools-2.4 public_key-1.13 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13 ssh-4.14.1 ssl-10.8.3 stdlib-4.0.1 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.29 : +OTP-25.0.3 : erts-13.0.3 ssl-10.8.3 # asn1-5.0.19 common_test-1.23 compiler-8.2 crypto-5.1.1 debugger-5.3 dialyzer-5.0.1 diameter-2.2.6 edoc-1.2 eldap-1.2.10 erl_docgen-1.3 erl_interface-5.3 et-1.6.5 eunit-2.7.1 ftp-1.1.1 inets-8.0 jinterface-1.13 kernel-8.4.1 megaco-4.4 mnesia-4.21.1 observer-2.12 odbc-2.14 os_mon-2.7.1 parsetools-2.4 public_key-1.13 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13 ssh-4.14.1 stdlib-4.0.1 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.29 : +OTP-25.0.2 : erts-13.0.2 ssl-10.8.2 # asn1-5.0.19 common_test-1.23 compiler-8.2 crypto-5.1.1 debugger-5.3 dialyzer-5.0.1 diameter-2.2.6 edoc-1.2 eldap-1.2.10 erl_docgen-1.3 erl_interface-5.3 et-1.6.5 eunit-2.7.1 ftp-1.1.1 inets-8.0 jinterface-1.13 kernel-8.4.1 megaco-4.4 mnesia-4.21.1 observer-2.12 odbc-2.14 os_mon-2.7.1 parsetools-2.4 public_key-1.13 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13 ssh-4.14.1 stdlib-4.0.1 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.29 : +OTP-25.0.1 : crypto-5.1.1 dialyzer-5.0.1 erts-13.0.1 kernel-8.4.1 mnesia-4.21.1 ssh-4.14.1 ssl-10.8.1 stdlib-4.0.1 # asn1-5.0.19 common_test-1.23 compiler-8.2 debugger-5.3 diameter-2.2.6 edoc-1.2 eldap-1.2.10 erl_docgen-1.3 erl_interface-5.3 et-1.6.5 eunit-2.7.1 ftp-1.1.1 inets-8.0 jinterface-1.13 megaco-4.4 observer-2.12 odbc-2.14 os_mon-2.7.1 parsetools-2.4 public_key-1.13 reltool-0.9 runtime_tools-1.19 sasl-4.2 snmp-5.13 syntax_tools-3.0 tftp-1.0.3 tools-3.5.3 wx-2.2 xmerl-1.3.29 : +OTP-25.0 : asn1-5.0.19 common_test-1.23 compiler-8.2 crypto-5.1 debugger-5.3 dialyzer-5.0 diameter-2.2.6 edoc-1.2 erl_docgen-1.3 erl_interface-5.3 erts-13.0 eunit-2.7.1 inets-8.0 jinterface-1.13 kernel-8.4 megaco-4.4 mnesia-4.21 observer-2.12 odbc-2.14 parsetools-2.4 public_key-1.13 runtime_tools-1.19 sasl-4.2 snmp-5.13 ssh-4.14 ssl-10.8 stdlib-4.0 syntax_tools-3.0 tools-3.5.3 wx-2.2 xmerl-1.3.29 # eldap-1.2.10 et-1.6.5 ftp-1.1.1 os_mon-2.7.1 reltool-0.9 tftp-1.0.3 : OTP-24.3.4.13 : compiler-8.1.1.5 debugger-5.2.1.1 erts-12.3.2.13 ssh-4.13.2.3 ssl-10.7.3.8 stdlib-3.17.2.4 # asn1-5.0.18.1 common_test-1.22.1.1 crypto-5.0.6.3 dialyzer-4.4.4.1 diameter-2.2.5 edoc-1.1 eldap-1.2.10 erl_docgen-1.2.1 erl_interface-5.2.2 et-1.6.5 eunit-2.7 ftp-1.1.1 inets-7.5.3.4 jinterface-1.12.2 kernel-8.3.2.3 megaco-4.3 mnesia-4.20.4.2 observer-2.11.1 odbc-2.13.5 os_mon-2.7.1 parsetools-2.3.2 public_key-1.12.0.1 reltool-0.9 runtime_tools-1.18 sasl-4.1.2 snmp-5.12.0.3 syntax_tools-2.6 tftp-1.0.3 tools-3.5.2 wx-2.1.4 xmerl-1.3.28.1 : OTP-24.3.4.12 : compiler-8.1.1.4 erts-12.3.2.12 stdlib-3.17.2.3 xmerl-1.3.28.1 # asn1-5.0.18.1 common_test-1.22.1.1 crypto-5.0.6.3 debugger-5.2.1 dialyzer-4.4.4.1 diameter-2.2.5 edoc-1.1 eldap-1.2.10 erl_docgen-1.2.1 erl_interface-5.2.2 et-1.6.5 eunit-2.7 ftp-1.1.1 inets-7.5.3.4 jinterface-1.12.2 kernel-8.3.2.3 megaco-4.3 mnesia-4.20.4.2 observer-2.11.1 odbc-2.13.5 os_mon-2.7.1 parsetools-2.3.2 public_key-1.12.0.1 reltool-0.9 runtime_tools-1.18 sasl-4.1.2 snmp-5.12.0.3 ssh-4.13.2.2 ssl-10.7.3.7 syntax_tools-2.6 tftp-1.0.3 tools-3.5.2 wx-2.1.4 : OTP-24.3.4.11 : erts-12.3.2.11 inets-7.5.3.4 ssl-10.7.3.7 # asn1-5.0.18.1 common_test-1.22.1.1 compiler-8.1.1.3 crypto-5.0.6.3 debugger-5.2.1 dialyzer-4.4.4.1 diameter-2.2.5 edoc-1.1 eldap-1.2.10 erl_docgen-1.2.1 erl_interface-5.2.2 et-1.6.5 eunit-2.7 ftp-1.1.1 jinterface-1.12.2 kernel-8.3.2.3 megaco-4.3 mnesia-4.20.4.2 observer-2.11.1 odbc-2.13.5 os_mon-2.7.1 parsetools-2.3.2 public_key-1.12.0.1 reltool-0.9 runtime_tools-1.18 sasl-4.1.2 snmp-5.12.0.3 ssh-4.13.2.2 stdlib-3.17.2.2 syntax_tools-2.6 tftp-1.0.3 tools-3.5.2 wx-2.1.4 xmerl-1.3.28 : @@ -34,6 +61,14 @@ OTP-24.0.3 : compiler-8.0.2 dialyzer-4.4.1 erts-12.0.3 inets-7.4.1 ssh-4.12.3 # OTP-24.0.2 : compiler-8.0.1 crypto-5.0.2 erl_docgen-1.1.1 erts-12.0.2 kernel-8.0.1 ssh-4.12.2 ssl-10.4.1 stdlib-3.15.1 # asn1-5.0.16 common_test-1.20.4 debugger-5.1 dialyzer-4.4 diameter-2.2.4 edoc-1.0 eldap-1.2.9 erl_interface-5.0.1 et-1.6.5 eunit-2.6.1 ftp-1.1 inets-7.4 jinterface-1.12 megaco-4.0.1 mnesia-4.19.1 observer-2.9.6 odbc-2.13.5 os_mon-2.7 parsetools-2.3 public_key-1.11 reltool-0.9 runtime_tools-1.16.2 sasl-4.1 snmp-5.9.1 syntax_tools-2.6 tftp-1.0.3 tools-3.5 wx-2.0.1 xmerl-1.3.28 : OTP-24.0.1 : common_test-1.20.4 crypto-5.0.1 erl_interface-5.0.1 erts-12.0.1 megaco-4.0.1 odbc-2.13.5 snmp-5.9.1 ssh-4.12.1 wx-2.0.1 # asn1-5.0.16 compiler-8.0 debugger-5.1 dialyzer-4.4 diameter-2.2.4 edoc-1.0 eldap-1.2.9 erl_docgen-1.1 et-1.6.5 eunit-2.6.1 ftp-1.1 inets-7.4 jinterface-1.12 kernel-8.0 mnesia-4.19.1 observer-2.9.6 os_mon-2.7 parsetools-2.3 public_key-1.11 reltool-0.9 runtime_tools-1.16.2 sasl-4.1 ssl-10.4 stdlib-3.15 syntax_tools-2.6 tftp-1.0.3 tools-3.5 xmerl-1.3.28 : OTP-24.0 : asn1-5.0.16 common_test-1.20.3 compiler-8.0 crypto-5.0 debugger-5.1 dialyzer-4.4 edoc-1.0 erl_docgen-1.1 erl_interface-5.0 erts-12.0 et-1.6.5 eunit-2.6.1 ftp-1.1 inets-7.4 jinterface-1.12 kernel-8.0 megaco-4.0 mnesia-4.19.1 observer-2.9.6 odbc-2.13.4 os_mon-2.7 parsetools-2.3 public_key-1.11 reltool-0.9 runtime_tools-1.16.2 sasl-4.1 snmp-5.9 ssh-4.12 ssl-10.4 stdlib-3.15 syntax_tools-2.6 tftp-1.0.3 tools-3.5 wx-2.0 xmerl-1.3.28 # diameter-2.2.4 eldap-1.2.9 : +OTP-23.3.4.19 : compiler-7.6.9.3 erts-11.2.2.18 stdlib-3.14.2.3 xmerl-1.3.27.1 # asn1-5.0.15.1 common_test-1.20.2.3 crypto-4.9.0.4 debugger-5.0 dialyzer-4.3.1.2 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.3 jinterface-1.11.1.1 kernel-7.3.1.7 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.6 ssl-10.3.1.5 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 : +OTP-23.3.4.18 : dialyzer-4.3.1.2 erts-11.2.2.17 kernel-7.3.1.7 # asn1-5.0.15.1 common_test-1.20.2.3 compiler-7.6.9.2 crypto-4.9.0.4 debugger-5.0 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.3 jinterface-1.11.1.1 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.6 ssl-10.3.1.5 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.17 : erts-11.2.2.16 inets-7.3.2.3 kernel-7.3.1.6 ssl-10.3.1.5 # asn1-5.0.15.1 common_test-1.20.2.3 compiler-7.6.9.2 crypto-4.9.0.4 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 jinterface-1.11.1.1 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.6 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.16 : crypto-4.9.0.4 erts-11.2.2.15 ssl-10.3.1.4 # asn1-5.0.15.1 common_test-1.20.2.3 compiler-7.6.9.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1.1 kernel-7.3.1.5 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.6 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.15 : crypto-4.9.0.3 erts-11.2.2.14 ssh-4.11.1.6 ssl-10.3.1.3 # asn1-5.0.15.1 common_test-1.20.2.3 compiler-7.6.9.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1.1 kernel-7.3.1.5 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.14 : compiler-7.6.9.2 erts-11.2.2.13 # asn1-5.0.15.1 common_test-1.20.2.3 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1.1 kernel-7.3.1.5 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.5 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.13 : erts-11.2.2.12 # asn1-5.0.15.1 common_test-1.20.2.3 compiler-7.6.9.1 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1.1 kernel-7.3.1.5 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.5 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : +OTP-23.3.4.12 : common_test-1.20.2.3 erts-11.2.2.11 jinterface-1.11.1.1 kernel-7.3.1.5 # asn1-5.0.15.1 compiler-7.6.9.1 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.5 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : OTP-23.3.4.11 : erts-11.2.2.10 ssh-4.11.1.5 # asn1-5.0.15.1 common_test-1.20.2.2 compiler-7.6.9.1 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1 kernel-7.3.1.4 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : OTP-23.3.4.10 : erts-11.2.2.9 # asn1-5.0.15.1 common_test-1.20.2.2 compiler-7.6.9.1 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1 kernel-7.3.1.4 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.4 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : OTP-23.3.4.9 : erts-11.2.2.8 # asn1-5.0.15.1 common_test-1.20.2.2 compiler-7.6.9.1 crypto-4.9.0.2 debugger-5.0 dialyzer-4.3.1.1 diameter-2.2.4 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.3.1 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2.2 jinterface-1.11.1 kernel-7.3.1.4 megaco-3.19.5.1 mnesia-4.19 observer-2.9.5 odbc-2.13.3.1 os_mon-2.6.1 parsetools-2.2 public_key-1.10.0.1 reltool-0.8 runtime_tools-1.16.1 sasl-4.0.2 snmp-5.8.0.1 ssh-4.11.1.4 ssl-10.3.1.2 stdlib-3.14.2.2 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3.1 xmerl-1.3.27 : @@ -50,6 +85,7 @@ OTP-23.3.3 : common_test-1.20.2 compiler-7.6.8 erl_interface-4.0.3 kernel-7.3.1 OTP-23.3.2 : asn1-5.0.15 common_test-1.20.1 erts-11.2.1 ssl-10.3.1 stdlib-3.14.2 xmerl-1.3.27 # compiler-7.6.7 crypto-4.9 debugger-5.0 dialyzer-4.3.1 diameter-2.2.3 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.2 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11.1 kernel-7.3 megaco-3.19.5 mnesia-4.19 observer-2.9.5 odbc-2.13.3 os_mon-2.6.1 parsetools-2.2 public_key-1.10 reltool-0.8 runtime_tools-1.16 sasl-4.0.2 snmp-5.8 ssh-4.11.1 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3 : OTP-23.3.1 : ssh-4.11.1 # asn1-5.0.14 common_test-1.20 compiler-7.6.7 crypto-4.9 debugger-5.0 dialyzer-4.3.1 diameter-2.2.3 edoc-0.12 eldap-1.2.9 erl_docgen-1.0.2 erl_interface-4.0.2 erts-11.2 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11.1 kernel-7.3 megaco-3.19.5 mnesia-4.19 observer-2.9.5 odbc-2.13.3 os_mon-2.6.1 parsetools-2.2 public_key-1.10 reltool-0.8 runtime_tools-1.16 sasl-4.0.2 snmp-5.8 ssl-10.3 stdlib-3.14.1 syntax_tools-2.5 tftp-1.0.2 tools-3.4.4 wx-1.9.3 xmerl-1.3.26 : OTP-23.3 : common_test-1.20 compiler-7.6.7 crypto-4.9 dialyzer-4.3.1 eldap-1.2.9 erts-11.2 jinterface-1.11.1 kernel-7.3 mnesia-4.19 odbc-2.13.3 public_key-1.10 runtime_tools-1.16 sasl-4.0.2 snmp-5.8 ssh-4.11 ssl-10.3 stdlib-3.14.1 syntax_tools-2.5 tools-3.4.4 wx-1.9.3 # asn1-5.0.14 debugger-5.0 diameter-2.2.3 edoc-0.12 erl_docgen-1.0.2 erl_interface-4.0.2 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 megaco-3.19.5 observer-2.9.5 os_mon-2.6.1 parsetools-2.2 reltool-0.8 tftp-1.0.2 xmerl-1.3.26 : +OTP-23.2.7.5 : ssl-10.2.4.4 # asn1-5.0.14 common_test-1.19.1 compiler-7.6.6 crypto-4.8.3 debugger-5.0 dialyzer-4.3 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0.2 erl_interface-4.0.2.1 erts-11.1.8 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11 kernel-7.2.1 megaco-3.19.5 mnesia-4.18.1 observer-2.9.5 odbc-2.13.2 os_mon-2.6.1 parsetools-2.2 public_key-1.9.2 reltool-0.8 runtime_tools-1.15.1 sasl-4.0.1 snmp-5.7.3 ssh-4.10.8 stdlib-3.14 syntax_tools-2.4 tftp-1.0.2 tools-3.4.3 wx-1.9.2 xmerl-1.3.26 : OTP-23.2.7.4 : ssl-10.2.4.3 # asn1-5.0.14 common_test-1.19.1 compiler-7.6.6 crypto-4.8.3 debugger-5.0 dialyzer-4.3 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0.2 erl_interface-4.0.2.1 erts-11.1.8 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11 kernel-7.2.1 megaco-3.19.5 mnesia-4.18.1 observer-2.9.5 odbc-2.13.2 os_mon-2.6.1 parsetools-2.2 public_key-1.9.2 reltool-0.8 runtime_tools-1.15.1 sasl-4.0.1 snmp-5.7.3 ssh-4.10.8 stdlib-3.14 syntax_tools-2.4 tftp-1.0.2 tools-3.4.3 wx-1.9.2 xmerl-1.3.26 : OTP-23.2.7.3 : erl_interface-4.0.2.1 # asn1-5.0.14 common_test-1.19.1 compiler-7.6.6 crypto-4.8.3 debugger-5.0 dialyzer-4.3 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0.2 erts-11.1.8 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11 kernel-7.2.1 megaco-3.19.5 mnesia-4.18.1 observer-2.9.5 odbc-2.13.2 os_mon-2.6.1 parsetools-2.2 public_key-1.9.2 reltool-0.8 runtime_tools-1.15.1 sasl-4.0.1 snmp-5.7.3 ssh-4.10.8 ssl-10.2.4.2 stdlib-3.14 syntax_tools-2.4 tftp-1.0.2 tools-3.4.3 wx-1.9.2 xmerl-1.3.26 : OTP-23.2.7.2 : ssl-10.2.4.2 # asn1-5.0.14 common_test-1.19.1 compiler-7.6.6 crypto-4.8.3 debugger-5.0 dialyzer-4.3 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0.2 erl_interface-4.0.2 erts-11.1.8 et-1.6.4 eunit-2.6 ftp-1.0.5 hipe-4.0.1 inets-7.3.2 jinterface-1.11 kernel-7.2.1 megaco-3.19.5 mnesia-4.18.1 observer-2.9.5 odbc-2.13.2 os_mon-2.6.1 parsetools-2.2 public_key-1.9.2 reltool-0.8 runtime_tools-1.15.1 sasl-4.0.1 snmp-5.7.3 ssh-4.10.8 stdlib-3.14 syntax_tools-2.4 tftp-1.0.2 tools-3.4.3 wx-1.9.2 xmerl-1.3.26 : @@ -74,6 +110,8 @@ OTP-23.0.3 : compiler-7.6.2 erts-11.0.3 # asn1-5.0.13 common_test-1.19 crypto-4. OTP-23.0.2 : erts-11.0.2 megaco-3.19.1 # asn1-5.0.13 common_test-1.19 compiler-7.6.1 crypto-4.7 debugger-5.0 dialyzer-4.2 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0 erl_interface-4.0 et-1.6.4 eunit-2.5 ftp-1.0.4 hipe-4.0 inets-7.2 jinterface-1.11 kernel-7.0 mnesia-4.17 observer-2.9.4 odbc-2.13 os_mon-2.5.2 parsetools-2.2 public_key-1.8 reltool-0.8 runtime_tools-1.15 sasl-4.0 snmp-5.6 ssh-4.10 ssl-10.0 stdlib-3.13 syntax_tools-2.3 tftp-1.0.2 tools-3.4 wx-1.9.1 xmerl-1.3.25 : OTP-23.0.1 : compiler-7.6.1 erts-11.0.1 # asn1-5.0.13 common_test-1.19 crypto-4.7 debugger-5.0 dialyzer-4.2 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0 erl_interface-4.0 et-1.6.4 eunit-2.5 ftp-1.0.4 hipe-4.0 inets-7.2 jinterface-1.11 kernel-7.0 megaco-3.19 mnesia-4.17 observer-2.9.4 odbc-2.13 os_mon-2.5.2 parsetools-2.2 public_key-1.8 reltool-0.8 runtime_tools-1.15 sasl-4.0 snmp-5.6 ssh-4.10 ssl-10.0 stdlib-3.13 syntax_tools-2.3 tftp-1.0.2 tools-3.4 wx-1.9.1 xmerl-1.3.25 : OTP-23.0 : asn1-5.0.13 common_test-1.19 compiler-7.6 crypto-4.7 debugger-5.0 dialyzer-4.2 edoc-0.12 erl_docgen-1.0 erl_interface-4.0 erts-11.0 eunit-2.5 hipe-4.0 inets-7.2 jinterface-1.11 kernel-7.0 megaco-3.19 mnesia-4.17 observer-2.9.4 odbc-2.13 os_mon-2.5.2 parsetools-2.2 public_key-1.8 runtime_tools-1.15 sasl-4.0 snmp-5.6 ssh-4.10 ssl-10.0 stdlib-3.13 syntax_tools-2.3 tools-3.4 wx-1.9.1 xmerl-1.3.25 # diameter-2.2.3 eldap-1.2.8 et-1.6.4 ftp-1.0.4 reltool-0.8 tftp-1.0.2 : +OTP-22.3.4.26 : erts-10.7.2.18 # asn1-5.0.12 common_test-1.18.2.2 compiler-7.5.4.3 crypto-4.6.5.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4.1 hipe-3.19.3 inets-7.1.3.3 jinterface-1.10.1 kernel-6.5.2.5 megaco-3.18.8.4 mnesia-4.16.3.1 observer-2.9.3 odbc-2.12.4.1 os_mon-2.5.1.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14.0.1 sasl-3.4.2 snmp-5.5.0.5 ssh-4.9.1.4 ssl-9.6.2.3 stdlib-3.12.1.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1.1 wx-1.9.0.1 xmerl-1.3.24 : +OTP-22.3.4.25 : common_test-1.18.2.2 erts-10.7.2.17 kernel-6.5.2.5 # asn1-5.0.12 compiler-7.5.4.3 crypto-4.6.5.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4.1 hipe-3.19.3 inets-7.1.3.3 jinterface-1.10.1 megaco-3.18.8.4 mnesia-4.16.3.1 observer-2.9.3 odbc-2.12.4.1 os_mon-2.5.1.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14.0.1 sasl-3.4.2 snmp-5.5.0.5 ssh-4.9.1.4 ssl-9.6.2.3 stdlib-3.12.1.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1.1 wx-1.9.0.1 xmerl-1.3.24 : OTP-22.3.4.24 : erts-10.7.2.16 # asn1-5.0.12 common_test-1.18.2.1 compiler-7.5.4.3 crypto-4.6.5.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4.1 hipe-3.19.3 inets-7.1.3.3 jinterface-1.10.1 kernel-6.5.2.4 megaco-3.18.8.4 mnesia-4.16.3.1 observer-2.9.3 odbc-2.12.4.1 os_mon-2.5.1.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14.0.1 sasl-3.4.2 snmp-5.5.0.5 ssh-4.9.1.4 ssl-9.6.2.3 stdlib-3.12.1.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1.1 wx-1.9.0.1 xmerl-1.3.24 : OTP-22.3.4.23 : erts-10.7.2.15 # asn1-5.0.12 common_test-1.18.2.1 compiler-7.5.4.3 crypto-4.6.5.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4.1 hipe-3.19.3 inets-7.1.3.3 jinterface-1.10.1 kernel-6.5.2.4 megaco-3.18.8.4 mnesia-4.16.3.1 observer-2.9.3 odbc-2.12.4.1 os_mon-2.5.1.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14.0.1 sasl-3.4.2 snmp-5.5.0.5 ssh-4.9.1.4 ssl-9.6.2.3 stdlib-3.12.1.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1.1 wx-1.9.0.1 xmerl-1.3.24 : OTP-22.3.4.22 : erts-10.7.2.14 ssh-4.9.1.4 # asn1-5.0.12 common_test-1.18.2.1 compiler-7.5.4.3 crypto-4.6.5.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4.1 hipe-3.19.3 inets-7.1.3.3 jinterface-1.10.1 kernel-6.5.2.4 megaco-3.18.8.4 mnesia-4.16.3.1 observer-2.9.3 odbc-2.12.4.1 os_mon-2.5.1.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14.0.1 sasl-3.4.2 snmp-5.5.0.5 ssl-9.6.2.3 stdlib-3.12.1.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1.1 wx-1.9.0.1 xmerl-1.3.24 : diff --git a/prebuild.delete b/prebuild.delete index 17efc89229c7..d9f704042870 100644 --- a/prebuild.delete +++ b/prebuild.delete @@ -1,4 +1,5 @@ bootstrap/lib bootstrap/target .git +.github scripts diff --git a/scripts/build-otp-tar b/scripts/build-otp-tar index 362d69d50814..6fb251f6e66c 100755 --- a/scripts/build-otp-tar +++ b/scripts/build-otp-tar @@ -422,7 +422,7 @@ fi if [ "x$build_dir" != "x" ]; then - progress "Using already built OTP distibution in: $build_dir" + progress "Using already built OTP distribution in: $build_dir" else @@ -541,7 +541,13 @@ if [ ! -d $src_dir -o ! -f $src_dir/otp_build ]; then fi progress "Checking target directory name" -target_dirname=`$prebld_dir/erts/autoconf/config.guess` +if [ -f "$prebld_dir/make/autoconf/config.guess" ]; then + target_dirname=`$prebld_dir/make/autoconf/config.guess` +elif [ -f "$prebld_dir/erts/autoconf/config.guess" ]; then + target_dirname=`$prebld_dir/erts/autoconf/config.guess` +else + error "Failed to find config.guess" +fi if [ $? -ne 0 ]; then error "Failed to check target directory name" fi @@ -651,7 +657,7 @@ done for kobj in $kobjs; do progress "Keeping $kobj in pre-build-directory" - copy $build_dir/../$kobj $prebld_root/$kobj + copy $build_dir/../$kobj $prebld_root/$(dirname $kobj) done cd $prebld_dir diff --git a/scripts/check_doc_since b/scripts/check_doc_since index ed13bb8e9394..ccdadcec6bcd 100755 --- a/scripts/check_doc_since +++ b/scripts/check_doc_since @@ -608,7 +608,7 @@ sub read_xml_functions { sub read_edoc_functions { my($tag, $module) = @_; - open(FILE, $filename) or die "Cant open erl file \"$filename\"\n"; + open(FILE, $filename) or die "Can't open erl file \"$filename\"\n"; local $/ = undef; my $lines = ; close(FILE); @@ -812,7 +812,7 @@ sub seen_it { } -# Trim leading and traling whitespace +# Trim leading and trailing whitespace sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; diff --git a/scripts/diffable b/scripts/diffable index ce192b375bba..c12748024294 100755 --- a/scripts/diffable +++ b/scripts/diffable @@ -7,7 +7,8 @@ -define(LONG_COMPILE_THRESHOLD, 10000). main(Args0) -> - DefOpts = #{format=>asm,no_compile=>false,legacy=>false,copts=>[]}, + DefOpts = #{erltop=>false,format=>asm,no_compile=>false, + legacy=>false,copts=>[]}, {Args,Opts} = opts(Args0, DefOpts), case Args of [OutDir] -> @@ -28,6 +29,10 @@ usage() -> " --asm)\n" " --co
    diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 0610a15a8a71..fb881a95b27a 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -4,7 +4,7 @@
    - 19972021 + 19972023 Ericsson AB. All Rights Reserved. @@ -267,14 +267,17 @@ init(Parent) -> ... proc_lib:init_ack(Parent, {ok, self()}), loop(...). -

    proc_lib:start_link is synchronous and does not return - until proc_lib:init_ack has been called.

    +

    + proc_lib:start_link is synchronous and does not return + until proc_lib:init_ack or proc_lib:init_fail + has been called, or when the process exits. +

    Debugging -

    To support the debug facilites in sys, a +

    To support the debug facilities in sys, a debug structure is needed. The Deb term is initialized using sys:debug_options/1:

    diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 2d6ea27635da..6c26bd62e4b3 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -4,7 +4,7 @@
    - 20162020 + 20162023 Ericsson AB. All Rights Reserved. @@ -1912,14 +1912,20 @@ do_unlock() -> to implicitly postpone any events to the locked state.

    - A selective receive cannot be used from a gen_statem + A catch-all receive should never be used from a gen_statem behaviour (or from any gen_* behaviour), as the receive statement is within the gen_* engine itself. - It must be there because all sys compatible behaviours must respond to system messages and therefore do that in their engine receive loop, passing non-system messages to the callback module. + Using a catch-all receive may result in system messages + being discarded which in turn may lead to unexpected behaviour. + If a selective receive must be used then great care should be taken to + ensure that only messages pertinent to the operation are received. + Likewise, a callback must return in due time to let the engine + receive loop handle system messages, or they might time out also + leading to unexpected behaviour.

    The @@ -1947,7 +1953,7 @@ do_unlock() ->

    Say you have a state machine specification that uses state enter actions. - Allthough you can code this using inserted events + Although you can code this using inserted events (described in the next section), especially if just one or a few states has got state enter actions, this is a perfect use case for the built in @@ -2528,7 +2534,7 @@ terminate(_Reason, State, _Data) -> the servers can be expected to idle for a while, and the amount of heap memory all these servers need is a problem, then the memory footprint of a server - can be mimimized by hibernating it through + can be minimized by hibernating it through proc_lib:hibernate/3.

    diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 4d1b593c923d..c9aa52669b05 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -4,7 +4,7 @@
    - 19972021 + 19972022 Ericsson AB. All Rights Reserved. @@ -69,7 +69,7 @@ init(_Args) -> restart => permanent, shutdown => brutal_kill, type => worker, - modules => [cg3]}], + modules => [ch3]}], {ok, {SupFlags, ChildSpecs}}.

    The SupFlags variable in the return value from init/1 represents @@ -374,7 +374,7 @@ child_spec() = #{id => child_id(), % mandatory

    Note that this identifier occasionally has been called "name". As far as possible, the terms "identifier" or "id" are now used but in order to keep backwards compatibility, - some occurences of "name" can still be found, for example + some occurrences of "name" can still be found, for example in error messages.

    diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile index 50ed66019aa8..d2155acdecee 100644 --- a/system/doc/efficiency_guide/Makefile +++ b/system/doc/efficiency_guide/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2020. All Rights Reserved. +# Copyright Ericsson AB 2001-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/efficiency_guide # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/efficiency_guide" +RELSYSDIR = $(RELEASE_PATH)/doc/efficiency_guide # ---------------------------------------------------- # Target Specs @@ -112,7 +112,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index c545d22a8a69..7fdb15441278 100644 --- a/system/doc/efficiency_guide/advanced.xml +++ b/system/doc/efficiency_guide/advanced.xml @@ -4,7 +4,7 @@
    - 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -39,7 +39,9 @@

    The unit of measurement is memory words. There exists both a 32-bit and a 64-bit implementation. A word is therefore 4 bytes or - 8 bytes, respectively.

    + 8 bytes, respectively. The value for a running system can be + determined by calling + erlang:system_info(wordsize).

    Data Type @@ -160,6 +162,16 @@ erl(1) manual page in ERTS. + + + Unique Local Process Identifiers on a + Runtime System Instance + + + On a 64 bit system at most 2⁶⁰ - 1 unique process identifiers + can be created and on a 32 bit system at most 2²⁸ - 1. + + Known nodes A remote node Y must be known to node X if there exists @@ -233,6 +245,16 @@ erl(1) manual page in ERTS. + + + Unique Local Port Identifiers on a + Runtime System Instance + + + On a 64 bit system at most 2⁶⁰ - 1 unique port identifiers + can be created and on a 32 bit system at most 2²⁸ - 1. + + Open files and sockets diff --git a/system/doc/efficiency_guide/bench.erl b/system/doc/efficiency_guide/bench.erl index a1be24b051ad..a1e9a71084a9 100644 --- a/system/doc/efficiency_guide/bench.erl +++ b/system/doc/efficiency_guide/bench.erl @@ -424,7 +424,7 @@ create_html_table(File, {Bm, Res}) -> create_html_row(File, Name, ResultDict) end, Order), - %% Tabel end-tags + %% Table end-tags io:put_chars(File, "
    \n"), %% Create link to benchmark source code @@ -435,7 +435,7 @@ create_html_table(File, {Bm, Res}) -> %% create_html_row(File, Name, Dict) -> _ %% File = file() - html file to write data to. %% Name = atom() - Name of benchmark test -%% Dict = dict() - Dictonary where the relative time measures for +%% Dict = dict() - Dictionary where the relative time measures for %% the test can be found. %% %% Creates an actual html table-row. diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 1bcbaa2405e9..025e705933d1 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -5,7 +5,7 @@
    2007 - 2021 + 2023 Ericsson AB, All Rights Reserved @@ -32,7 +32,12 @@ binaryhandling.xml
    -

    Binaries can be efficiently built in the following way:

    +

    This section gives a few examples on how to handle binaries in an + efficient way. The sections that follow take an in-depth look at how + binaries are implemented and how to best take advantages of the + optimizations done by the compiler and runtime system.

    + +

    Binaries can be efficiently built in the following way:

    DO

    my_list_to_binary([], Acc) -> Acc.]]> -

    Binaries can be efficiently matched like this:

    +

    Appending data to a binary as in the example is efficient because + it is specially optimized by the runtime system to avoid copying the + Acc binary every time.

    + +

    Prepending data to a binary in a loop is not efficient:

    + +

    DO NOT

    + + rev_list_to_binary(List, <<>>). + +rev_list_to_binary([H|T], Acc) -> + rev_list_to_binary(T, <>); +rev_list_to_binary([], Acc) -> + Acc.]]> + +

    This is not efficient for long lists because the Acc + binary is copied every time. One way to make the function more + efficient is like this:

    + +

    DO NOT

    + + rev_list_to_binary(lists:reverse(List), <<>>). + +rev_list_to_binary([H|T], Acc) -> + rev_list_to_binary(T, <>); +rev_list_to_binary([], Acc) -> + Acc.]]> + +

    Another way to avoid copying the binary each time is like this:

    + +

    DO

    + + RevTail = rev_list_to_binary(T), + <>; +rev_list_to_binary([]) -> + <<>>.]]> + +

    Note that in each of the DO examples, the binary to be + appended to is always given as the first segment.

    + +

    Binaries can be efficiently matched in the following way:

    DO

    >) -> [].]]>
    Constructing Binaries -

    Appending to a binary or bitstring - is specially optimized by the runtime system:

    +

    Appending to a binary or bitstring in the following way + is specially optimized to avoid copying the binary:

    - > +%% - OR - <>]]> -

    As the runtime system handles the optimization (instead of - the compiler), there are very few circumstances in which the optimization - does not work.

    +

    This optimization is applied by the runtime system in a way + that makes it effective in most circumstances (for exceptions, + see Circumstances That Force + Copying). The optimization in its basic form does not + need any help from the compiler. However, the compiler add hints + to the runtime system when it is safe to apply the optimization in + a more efficient way.

    -

    To explain how it works, let us examine the following code line - by line:

    +

    The compiler support for making the optimization more + efficient was added in Erlang/OTP 26.

    - To explain how the basic optimization works, let us examine the + following code line by line:

    + + >, %% 1 Bin1 = <>, %% 2 Bin2 = <>, %% 3 @@ -163,50 +219,94 @@ Bin3 = <>, %% 4 Bin4 = <>, %% 5 !!! {Bin4,Bin3} %% 6]]> - - Line 1 (marked with the %% 1 comment), assigns - a heap binary to - the Bin0 variable. - - Line 2 is an append operation. As Bin0 - has not been involved in an append operation, - a new refc binary - is created and the contents of Bin0 is copied - into it. The ProcBin part of the refc binary has - its size set to the size of the data stored in the binary, while - the binary object has extra space allocated. - The size of the binary object is either twice the - size of Bin1 or 256, whichever is larger. In this case - it is 256. - - Line 3 is more interesting. - Bin1 has been used in an append operation, - and it has 252 bytes of unused storage at the end, so the 3 new - bytes are stored there. - - Line 4. The same applies here. There are 249 bytes left, - so there is no problem storing another 3 bytes. - - Line 5. Here, something interesting happens. Notice - that the result is not appended to the previous result in Bin3, - but to Bin1. It is expected that Bin4 will be assigned - the value <<0,1,2,3,17>>. It is also expected that - Bin3 will retain its value - (<<0,1,2,3,4,5,6,7,8,9>>). - Clearly, the runtime system cannot write byte 17 into the binary, - because that would change the value of Bin3 to - <<0,1,2,3,4,17,6,7,8,9>>. - - -

    The runtime system sees that Bin1 is the result - from a previous append operation (not from the latest append operation), - so it copies the contents of Bin1 to a new binary, - reserve extra storage, and so on. (Here is not explained how the - runtime system can know that it is not allowed to write into Bin1; - it is left as an exercise to the curious reader to figure out how it is - done by reading the emulator sources, primarily erl_bits.c.)

    + +

    Line 1 (marked with the %% 1 comment), assigns + a heap binary to + the Bin0 variable.

    + +

    Line 2 is an append operation. As Bin0 + has not been involved in an append operation, + a new refc binary + is created and the contents of Bin0 is copied + into it. The ProcBin part of the refc binary has + its size set to the size of the data stored in the binary, while + the binary object has extra space allocated. + The size of the binary object is either twice the + size of Bin1 or 256, whichever is larger. In this case + it is 256.

    + +

    Line 3 is more interesting. + Bin1 has been used in an append operation, + and it has 252 bytes of unused storage at the end, so the 3 new + bytes are stored there.

    + +

    Line 4. The same applies here. There are 249 bytes left, + so there is no problem storing another 3 bytes.

    + +

    Line 5. Here something interesting happens. Notice + that the result is not appended to the previous result in Bin3, + but to Bin1. It is expected that Bin4 will be assigned + the value <<0,1,2,3,17>>. It is also expected that + Bin3 will retain its value + (<<0,1,2,3,4,5,6,7,8,9>>). + Clearly, the runtime system cannot write byte 17 into the binary, + because that would change the value of Bin3 to + <<0,1,2,3,4,17,6,7,8,9>>.

    + +

    To ensure that the value of Bin3 is retained, the + runtime system copies the contents of Bin1 to a + new refc binary before storing the 17 byte.

    + +

    Here is not explained how the runtime system can know that it + is not allowed to write into Bin1; it is left as an + exercise to the curious reader to figure out how it is done by + reading the emulator sources, primarily erl_bits.c.

    +
    +
    +
    + Compiler Support For Constructing Binaries + +

    The compiler support for making the optimization more + efficient was added in Erlang/OTP 26.

    + +

    In the example in the previous section, it was shown that + the runtime system can handle an append operation to a heap + binary by copying it to a refc binary (line 2), and also handle + an append operation to a previous version of the binary by + copying it (line 5). The support for doing that does not come + for free. For example, to make it possible to know when it is + necessary to copy the binary, for every append operation, the + runtime system must create a sub binary.

    + +

    When the compiler can determine that none of those situations + need to be handled and that the append operation cannot possibly + fail, the compiler generates code that causes the runtime system to + apply a more efficient variant of the optimization.

    + +

    Example:

    + + + repack(Bin, <<>>). + +repack(<>, Result) -> + repack(T, <>); +repack(<<>>, Result) -> + Result.]]> +
    + +

    The repack/2 function only keeps a single version of the + binary, so there is never any need to copy the binary. The + compiler rewrites the creation of the empty binary in + repack/1 to instead create a refc binary with 256 bytes + already reserved; thus, the append operation in repack/2 + never needs to handle a binary not prepared for appending.

    + Circumstances That Force Copying

    The optimization of the binary append operation requires that diff --git a/system/doc/efficiency_guide/commoncaveats.xmlsrc b/system/doc/efficiency_guide/commoncaveats.xmlsrc index 47ce3a014fb2..6ea8599e948c 100644 --- a/system/doc/efficiency_guide/commoncaveats.xmlsrc +++ b/system/doc/efficiency_guide/commoncaveats.xmlsrc @@ -39,11 +39,16 @@ marker="erts:erlang#send_after/3">erlang:send_after/3 and erlang:start_timer/3, - is much more efficient than using the timers provided by the - timer module in STDLIB. - The timer module uses a separate process to manage the timers. - That process can easily become overloaded if many processes - create and cancel timers frequently.

    + is more efficient than using the timers provided by the + timer module in STDLIB.

    +

    The timer module uses a separate process to manage the timers. + Before OTP 25, this management overhead was substantial and increasing + with the number of timers, especially when they were short-lived, so the + timer server process could easily become overloaded and unresponsive. + In OTP 25, the timer module was improved by removing most of the management + overhead and the resulting performance penalty. Still, the timer server + remains a single process, and it may at some point become a bottleneck + of an application.

    The functions in the timer module that do not manage timers (such as timer:tc/3 or timer:sleep/1), do not call the @@ -85,7 +90,7 @@

    a list with 10000 elements (or about 20000 heap words) will be copied to the newly created process.

    -

    An unncessary copy of 10000 element list can be bad enough, but it +

    An unnecessary copy of 10000 element list can be bad enough, but it can get even worse if the state record contains shared subterms. Here is a simple example of a term with a shared subterm:

    @@ -192,7 +197,7 @@ multiple_setelement(T0) ->

    The two following setelement/3 calls modify the tuple in place.

    -

    For the optimization to be applied, all the followings conditions +

    For the optimization to be applied, all the following conditions must be true:

    diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 0a8ee7eb3442..f3d6b59e49dc 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -4,7 +4,7 @@
    - 20012017 + 20012022 Ericsson AB. All Rights Reserved. @@ -158,22 +158,23 @@ explicit_map_pairs(Map, Xs0, Ys0) ->
    Function Calls -

    This is an intentionally rough guide to the relative costs of - different calls. It is based on benchmark figures run on - Solaris/Sparc:

    +

    This is a rough hierarchy of the performance of the + different types of function calls:

    Calls to local or external functions (foo(), m:foo()) are the fastest calls. Calling or applying a fun (Fun(), apply(Fun, [])) - is about three times as expensive as calling a local - function. + is just a little slower than external calls. Applying an exported function (Mod:Name(), - apply(Mod, Name, [])) is about twice as expensive as calling - a fun or about six times as expensive as calling a local - function. + apply(Mod, Name, [])) where the number of arguments is known + at compile time is next. + + Applying an exported function (apply(Mod, Name, Args)) + where the number of arguments is not known at compile time is the + least efficient.
    @@ -187,25 +188,8 @@ explicit_map_pairs(Map, Xs0, Ys0) -> in a hash table. It is therefore always slower than a direct call or a fun call.

    -

    It no longer matters (from a performance point of view) - whether you write:

    - - -Module:Function(Arg1, Arg2) - -

    or:

    - - -apply(Module, Function, [Arg1,Arg2]) - -

    The compiler internally rewrites the latter code into the - former.

    - -

    The following code is slightly slower because the shape of the - list of arguments is unknown at compile time.

    - - -apply(Module, Function, Arguments) +

    Caching callback functions into funs may be more efficient + in the long run than apply calls for frequently-used callbacks.

    diff --git a/system/doc/efficiency_guide/maps.xml b/system/doc/efficiency_guide/maps.xml index 140bdd549ae2..fdb84fca78e1 100644 --- a/system/doc/efficiency_guide/maps.xml +++ b/system/doc/efficiency_guide/maps.xml @@ -4,7 +4,7 @@
    - 20212021 + 20212023 Ericsson AB. All Rights Reserved. @@ -37,6 +37,7 @@ finally the functions in the maps module.

    +

    Terminology used in this chapter:

    A map with at most 32 elements will informally be called a @@ -107,10 +108,7 @@ there are default values, sharing of keys between different instances of the map will be less effective, and it is not possible to match multiple elements having default values in one - go. The maps:get/3 function is implemented in Erlang, making it - less efficient than maps:get/2 or the map matching - syntax.

    + go.

    To avoid having to deal with a map that may lack some keys, maps:merge/2 @@ -487,31 +485,43 @@ new() ->

    maps:get/3 -

    maps:get/3 - is implemented in Erlang essentially like this:

    +

    As an optimization, the compiler will rewrite a call to maps:get/3 to Erlang code similar to + the following:

    - case Map of - #{Key := Value} -> Value; - #{} -> Default - end.]]> + Result = case Map of + #{Key := Value} -> Value; + #{} -> Default + end]]>
    -

    Therefore, a call maps:get/3 is more expensive than a - call to maps:get/2.

    +

    This is reasonably efficient, but if a small map is used as an + alternative to using a record it is often better not to rely on default + values as it prevents sharing of keys, which may in the end use more + memory than what you save from not storing default values in the + map.

    -

    If a small map is used as alternative to using a record, - instead of calling maps:get/3 multiple times to handle - default values, consider putting the default values in a map and - merging that map with the other map:

    +

    If default values are nevertheless required, instead of calling + maps:get/3 multiple times, consider putting the default values + in a map and merging that map with the other map:

    Value2, Key2 => Value2, ..., KeyN => ValueN}, MapWithDefaultsApplied = maps:merge(DefaultMap, OtherMap)]]> -

    Whether that is faster than calling maps:get/3 - multiple times depends on the size of the map and the number of - default values.

    +

    This helps share keys between the default map and the one you applied + defaults to, as long as the default map contains all the keys + that will ever be used and not just the ones with default values. + Whether this is faster than calling maps:get/3 multiple times + depends on the size of the map and the number of default values.

    + + +

    + Before OTP 26.0 maps:get/3 was implemented by calling + the function instead of rewriting it as an Erlang expression. It is + now slightly faster but can no longer be traced. +

    +
    @@ -580,7 +590,17 @@ get(Key, Map, Default) ->
    maps:merge/2

    maps:merge/2 - is implemented in C.

    + is implemented in C. For small + maps, the key tuple may be shared with any of the argument + maps if that argument map contains all the keys. Literal key tuples are + prefered if possible.

    + +

    + The sharing of key tuples by maps:merge/2 was introduced in + OTP 26.0. Older versions always contructed a new key tuple on + the callers heap. +

    +
    @@ -660,7 +680,7 @@ get(Key, Map, Default) ->

    If the keys are constants known at compile-time, using the map update syntax with the := operator is more efficient than multiple calls to maps:update/3, - especially for small maps.

    + especially for small maps.

    diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml index ebe1a978e4ab..716614464ada 100644 --- a/system/doc/efficiency_guide/profiling.xml +++ b/system/doc/efficiency_guide/profiling.xml @@ -4,7 +4,7 @@
    - 20012021 + 20012023 Ericsson AB. All Rights Reserved. @@ -85,6 +85,19 @@ is a collection of Erlang profiling and debugging tools. This tool comes with an accompanying E-book called Erlang in Anger. + +

    perf + is a sampling profiler for Linux that provides functionality similar + to fprof but with much lower overhead. Profiling Erlang code + is possible when the emulator has been started with the + +JPperf true emulator flag, and is only available when the JIT + is enabled. +

    +

    For more details about how to run perf see the + perf support + section in the BeamAsm internal documentation. +

    +
    @@ -101,7 +114,7 @@

    When looking at memory usage in a running system the most basic function to get information from is erlang:memory(). It returns the current memory usage - of the system. instrument(3) + of the system. instrument(3) can be used to get a more detailed breakdown of where memory is used.

    Processes, ports and ets tables can then be inspected using their respective info functions, i.e. diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml index a763770e5a1d..593e8f54921a 100644 --- a/system/doc/efficiency_guide/retired_myths.xml +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -5,7 +5,7 @@

    2016 - 2020 + 2021 Ericsson AB, All Rights Reserved @@ -31,7 +31,7 @@ retired_myths.xml
    -

    We belive that the truth finally has caught with the following, +

    We believe that the truth finally has caught with the following, retired myths.

    diff --git a/system/doc/efficiency_guide/tablesDatabases.xml b/system/doc/efficiency_guide/tablesDatabases.xml index 3f77151e551f..ba0d5e2e4024 100644 --- a/system/doc/efficiency_guide/tablesDatabases.xml +++ b/system/doc/efficiency_guide/tablesDatabases.xml @@ -4,7 +4,7 @@
    - 20012016 + 20012021 Ericsson AB. All Rights Reserved. @@ -137,7 +137,7 @@ print_person(PersonId) -> io:format("No person with ID = ~p~n", [PersonID]) end. -%%% Internal functionss +%%% Internal functions print_name(PersonID) -> [Person] = ets:lookup(person, PersonId), io:format("No person ~p~n", [Person#person.name]). diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile index 29f3f7456484..7089ae1f0398 100644 --- a/system/doc/embedded/Makefile +++ b/system/doc/embedded/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2020. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/embedded # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/embedded" +RELSYSDIR = $(RELEASE_PATH)/doc/embedded # ---------------------------------------------------- # Target Specs @@ -100,7 +100,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/embedded/embedded_solaris.xml b/system/doc/embedded/embedded_solaris.xml index eaa334fb39a3..c70e5f26c06a 100644 --- a/system/doc/embedded/embedded_solaris.xml +++ b/system/doc/embedded/embedded_solaris.xml @@ -4,7 +4,7 @@
    - 19972016 + 19972023 Ericsson AB. All Rights Reserved. @@ -163,7 +163,7 @@ esac

    File /export/home/otpuser/otp/bin/start referred to in the above script is precisely the start script described in Starting Erlang. The - script variable OTP_ROOT in that start script + script variable $OTPROOT in that start script corresponds to the following example path used in this section:

    @@ -313,7 +313,7 @@ chmod 644 /etc/syslog.conf.OTP
     	      /priv/bin/mod_syslog. The generic full name
     	      of the binary executable file is thus:

    /lib/os_mon-/priv/bin/mod_syslog]]> +<$OTPROOT>/lib/os_mon-/priv/bin/mod_syslog]]>

    Example: If the path to otp-root is /usr/otp, then the path to the os_mon application is /usr/otp/lib/os_mon-1.0 @@ -327,7 +327,7 @@ chmod 644 /etc/syslog.conf.OTP

    A simple way to do this is to issue the following commands:

    /lib/os_mon-/priv/bin/mod_syslog +cd <$OTPROOT>/lib/os_mon-/priv/bin/mod_syslog chmod 4755 mod_syslog chown root mod_syslog]]> @@ -350,7 +350,7 @@ chown root mod_syslog]]>
    /ebin/os_mon.app.

    The generic full name of the file is thus:

    /lib/os_mon-/ebin/os_mon.app.]]> +<$OTPROOT>/lib/os_mon-/ebin/os_mon.app.]]>

    Example: If the path to otp-root is /usr/otp, then the path to the os_mon application is /usr/otp/lib/os_mon-1.0 (assuming revision 1.0) and diff --git a/system/doc/embedded/intro.xml b/system/doc/embedded/intro.xml index 2b9d35d24c7a..cec321248115 100644 --- a/system/doc/embedded/intro.xml +++ b/system/doc/embedded/intro.xml @@ -5,7 +5,7 @@

    1997 - 2016 + 2021 Ericsson AB, All Rights Reserved @@ -37,7 +37,7 @@

    This manual is a complement to the other manuals and describes how to install, run and maintain Erlang on an embedded system.

    -

    For more informaton about how to install and start Erlang read +

    For more information about how to install and start Erlang read XXXXXXXX.

    diff --git a/system/doc/embedded/target.xml b/system/doc/embedded/target.xml index 754269aa2fdb..73cd424302b2 100644 --- a/system/doc/embedded/target.xml +++ b/system/doc/embedded/target.xml @@ -4,7 +4,7 @@
    - 19962016 + 19962023 Ericsson AB. All Rights Reserved. @@ -149,7 +149,7 @@ esac

    The file /export/home/otpuser/otp/bin/start referred to in the above script, is precisely the script start described in the next chapter of this guide, Starting an Embedded System. The script - variable OTP_ROOT in that start script corresponds to + variable $OTPROOT in that start script corresponds to the example path

     /export/home/otpuser/otp    
    @@ -316,7 +316,7 @@ TERM=sun /priv/bin/mod_syslog. The generic full name of the binary executable file is thus

    /lib/os_mon-/priv/bin/mod_syslog ]]> + <$OTPROOT>/lib/os_mon-/priv/bin/mod_syslog ]]>

    Example: If the path to the otp-root is /usr/otp, thus the path to the os_mon application is /usr/otp/lib/os_mon-1.0 (assuming revision 1.0) and the full name @@ -331,7 +331,7 @@ TERM=sun

    A simple way to do this is to issue the commands

    /lib/os_mon-/priv/bin/mod_syslog + cd <$OTPROOT>/lib/os_mon-/priv/bin/mod_syslog chmod 4755 mod_syslog chown root mod_syslog ]]> @@ -355,7 +355,7 @@ TERM=sun /ebin/os_mon.app.

    The generic full name of the file is thus

    /lib/os_mon-/ebin/os_mon.app. ]]> + <$OTPROOT>/lib/os_mon-/ebin/os_mon.app. ]]>

    Example: If the path to the otp-root is /usr/otp, thus the path to the os_mon application is /usr/otp/lib/os_mon-1.0 (assuming revision 1.0) and the full name of the binary executable file is /usr/otp/lib/os_mon-1.0/ebin/os_mon.app.

    diff --git a/system/doc/general_info/DEPRECATIONS b/system/doc/general_info/DEPRECATIONS index ab304db2a8cc..a576881e5d44 100644 --- a/system/doc/general_info/DEPRECATIONS +++ b/system/doc/general_info/DEPRECATIONS @@ -17,14 +17,33 @@ # is scheduled to be removed in OTP 25. # +# +# Added in OTP 26. +# +file:pid2name/1 since=26 remove=27 +disk_log:inc_wrap_file/1 since=26 remove=28 +dbg:stop_clear/0 since=26 remove=27 + +# +# Added in OTP 25. +# +slave:_/_ since=25 remove=27 +ct_slave:_/_ since=25 remove=27 +httpd_util:encode_hex/1 since=25 remove=26 +httpd_util:decode_hex/1 since=25 remove=26 + +crypto:crypto_dyn_iv_init/3 since=25 remove=27 +crypto:crypto_dyn_iv_update/3 since=25 remove=27 +erts_alloc_config:_/_ since=25 remove=26 + # # Added in OTP 24. # -public_key:ssh_hostkey_fingerprint/1 since=24 remove=26 -public_key:ssh_hostkey_fingerprint/2 since=24 remove=26 -public_key:ssh_decode/2 since=24 remove=26 -public_key:ssh_encode/2 since=24 remove=26 +public_key:ssh_hostkey_fingerprint/1 since=24 remove=25 +public_key:ssh_hostkey_fingerprint/2 since=24 remove=25 +public_key:ssh_decode/2 since=24 remove=25 +public_key:ssh_encode/2 since=24 remove=25 ftp:start_service/1 since=24 remove=26 ftp:stop_service/1 since=24 remove=26 httpd_util:flatlength/1 since=24 remove=26 @@ -57,8 +76,8 @@ ssl:cipher_suites/0 since=21 remove=24 http_uri:parse/1 since=23 remove=25 http_uri:parse/2 since=23 remove=25 -http_uri:encode/1 since=23 remove=25 -http_uri:decode/1 since=23 remove=25 +http_uri:encode/1 since=23 remove=27 +http_uri:decode/1 since=23 remove=27 http_uri:scheme_defaults/0 since=23 remove=25 httpd:parse_query/1 since=23 pg2:_/_ since=23 remove=24 diff --git a/system/doc/general_info/Makefile b/system/doc/general_info/Makefile index 55cac49c1fef..3fadfe712d3e 100644 --- a/system/doc/general_info/Makefile +++ b/system/doc/general_info/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/general_info # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/general_info" +RELSYSDIR = $(RELEASE_PATH)/doc/general_info # ---------------------------------------------------- # Target Specs @@ -108,7 +108,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/general_info/deprecations_23.inc b/system/doc/general_info/deprecations_23.inc index ef1c6ff12fcd..1eb8f3dd5eba 100644 --- a/system/doc/general_info/deprecations_23.inc +++ b/system/doc/general_info/deprecations_23.inc @@ -18,12 +18,12 @@
    ssh

    The public key algorithm 'ssh-rsa is regarded as insecure due - to its usage of SHA1, and is therfore deprecated. + to its usage of SHA1, and is therefore deprecated. It will not be available by default from OTP-24.

    The public key algorithm 'ssh-dss is regarded as insecure due - to its usage of SHA1 and its short key length, and is therfore deprecated. + to its usage of SHA1 and its short key length, and is therefore deprecated. It is not available by default from OTP-23.

    diff --git a/system/doc/general_info/deprecations_24.inc b/system/doc/general_info/deprecations_24.inc index d508aca7d3da..3786cd1c6adc 100644 --- a/system/doc/general_info/deprecations_24.inc +++ b/system/doc/general_info/deprecations_24.inc @@ -4,20 +4,17 @@ Communication over the Erlang distribution without support for large node container data types (version 4) is as of OTP 24 deprecated and is - scheduled for removal - in OTP 26. That is, as of OTP 26, support for large - node container data types will become mandatory. + scheduled for removal in OTP 26. That is, as of OTP 26, support for + large node container data types will become mandatory.

    Old Link Protocol

    - The old - link protocol used when communicating over the Erlang + The old link protocol used when communicating over the Erlang distribution is as of OTP 24 deprecated and support for it is - scheduled for removal - in OTP 26. As of OTP 26, the + scheduled for removal in OTP 26. As of OTP 26, the new link protocol will become mandatory. That is, Erlang nodes will then refuse to connect to nodes not implementing the new diff --git a/system/doc/general_info/removed_26.inc b/system/doc/general_info/removed_26.inc new file mode 100644 index 000000000000..ea6a73bd136c --- /dev/null +++ b/system/doc/general_info/removed_26.inc @@ -0,0 +1,27 @@ +

    + Erlang Distribution Without Large Node Container Support +

    + Communication over the Erlang distribution without support for large + node container + data types (version 4) was as of + OTP 24 deprecated + and support for it was scheduled for removal in OTP 26. That is, as + of OTP 26, support for large node container data types will become + mandatory. This also includes external term format produced by + term_to_binary()/term_to_iovec(). +

    +
    + +
    + Old Link Protocol +

    + The old link protocol used when communicating over the Erlang + distribution was as of + OTP 24 deprecated and support for it was scheduled for + removal in OTP 26. As of OTP 26 the + new + link protocol became mandatory. That is, Erlang nodes + will refuse to connect to nodes not implementing the new + link protocol. +

    +
    diff --git a/system/doc/general_info/scheduled_for_removal_26.inc b/system/doc/general_info/scheduled_for_removal_26.inc deleted file mode 100644 index 1d59136ce5b2..000000000000 --- a/system/doc/general_info/scheduled_for_removal_26.inc +++ /dev/null @@ -1,30 +0,0 @@ -
    - Erlang Distribution Without Large Node Container Support -

    - Communication over the Erlang distribution without support for large - node container - data types (version 4) is as of - OTP 24 deprecated - and support for it is scheduled for removal in OTP 26. That is, as - of OTP 26, support for large node container data types will become - mandatory. -

    -
    - -
    - Old Link Protocol -

    - The old - link protocol used when communicating over the Erlang - distribution is as of - OTP 24 deprecated and support for it is scheduled for - removal in OTP 26. As of OTP 26 the - new - link protocol will become mandatory. That is, Erlang nodes - will then refuse to connect to nodes not implementing the new - link protocol. If you implement the Erlang distribution yourself, you - are, however, encouraged to implement the new link protocol as soon as - possible since the old protocol can cause links to enter an - inconsistent state. -

    -
    diff --git a/system/doc/general_info/scheduled_for_removal_27.inc b/system/doc/general_info/scheduled_for_removal_27.inc new file mode 100644 index 000000000000..e97149d93728 --- /dev/null +++ b/system/doc/general_info/scheduled_for_removal_27.inc @@ -0,0 +1,14 @@ +
    + Vanilla Driver +

    + The old previously documented support for opening a port to an + external resource by passing an atom (or a string) as first + argument to + open_port(), + implemented by the vanilla driver, will be removed in OTP 27. + This functionality was marked as obsolete about two decades ago + and then a few years later the documentation for it was removed. + If this functionality is not used with care it might hang or crash + the runtime system. +

    +
    diff --git a/system/doc/general_info/upcoming_incompatibilities.xml b/system/doc/general_info/upcoming_incompatibilities.xml index 69a0f6de16e0..3b818b54ca11 100644 --- a/system/doc/general_info/upcoming_incompatibilities.xml +++ b/system/doc/general_info/upcoming_incompatibilities.xml @@ -4,7 +4,7 @@
    - 2021 + 20212023 Ericsson AB. All Rights Reserved. @@ -36,101 +36,301 @@
    - OTP 25 + OTP 27 +
    - Distribution flags will become mandatory -

    In OTP 25, more distribution - flags will become mandatory. That is, Erlang nodes - will refuse to connect to nodes not implementing all of the - mandatory distribution flags. If you implement the Erlang - distribution protocol yourself, you will need to implement - support for all mandatory distribution flags in order to - communicate with Erlang nodes running OTP 25.

    -

    The following distribution flags will become mandatory in OTP - 25:

    - - DFLAG_BIT_BINARIES - Support for bitstrings. - DFLAG_EXPORT_PTR_TAG - Support for external funs (fun Module:Name/Arity). - DFLAG_MAP_TAGS - Support for maps. - DFLAG_NEW_FLOATS - Support for the new encoding of floats. - DFLAG_FUN_TAGS - Support for funs, but only in the new format - (NEW_FUN_EXT) because DFLAG_NEW_FUN_TAGS is also - mandatory. - + + Fun creator pid will always be local init process +

    + As of OTP 27, the functions + + erlang:fun_info/1,2 will always say that the local + init process created all funs, regardless of which process or + node the fun was originally created on. +

    +

    + In OTP 28, the {pid,_}element will be removed altogether.

    +
    + +
    + + Feature maybe_expr will be enabled by default +

    + As of OTP 27, the maybe_expr feature will be approved + and enabled by default. That means that code that uses the + unquoted atom maybe will fail to compile. All uses of + maybe as an atom will need to be quoted. Alternatively, as a + short-term solution, the maybe_expr feature can be + disabled. +

    +

    + It is recommend to quote all uses of the atom maybe as soon as + possible. The compiler option warn_keywords can be used to emit + warnings about all occurrences of maybe without quotes. +

    +
    + +
    + + The re module will use a different regular expression engine + +

    The functionality of module re is currently provided by + the PCRE library, which is no longer actively + maintained. Therefore, in OTP 27, we will switch to a different + regular expression library.

    + +

    The source code for PCRE used by the re module has + been modified by the OTP team to ensure that a regular + expression match would yield when matching huge input binaries + and/or when using demanding (back-tracking) regular + expressions. Because of the those modifications, moving to a new + version of PCRE has always been a time-consuming process because + all of the modifications had to be applied by hand again to the + updated PCRE source code.

    + +

    Most likely, the new regular expression library will be RE2. RE2 guarantees + that the match time is linear in the length of input string, and + it also eschews recursion to avoid stack overflow. That should + make it possible to use RE2 without modifying its source + code. For more information about why RE2 is a good choice, see + WhyRE2.

    + +

    Some of implications of this change are:

    + + +

    We expect that the functions in the re module + will continue to be supported, although some of the options are likely + to be dis-continued.

    + +

    It is likely that only pattern matching of UTF8-encoded binaries will be + supported (not Latin1-encoded binaries).

    + +

    In order to guarantee the linear-time performance, + RE2 does not support all the constructs in regular expression + patterns that PCRE do. For example, backreferences and look-around + assertions are not supported. See Syntax + for a description of what RE2 supports.

    + +

    Compiling a regular expression is likely to be + slower, and thus more can be gained by explicitly compiling + the regular expression before matching with it.

    +
    +
    + +
    + + 0.0 and -0.0 will no longer be exactly equal + +

    Currently, the floating point numbers 0.0 and -0.0 + have distinct internal representations. That can be seen if they are + converted to binaries:

    +
    +1> <<0.0/float>>.
    +<<0,0,0,0,0,0,0,0>>
    +2> <<-0.0/float>>.
    +<<128,0,0,0,0,0,0,0>>
    + +

    However, when they are matched against each other or compared + using the =:= operator, they are considered to be + equal. Thus, 0.0 =:= -0.0 currently returns + true.

    + +

    In Erlang/OTP 27, 0.0 =:= -0.0 will return false, and matching + 0.0 against -0.0 will fail. When used as map keys, 0.0 and + -0.0 will be considered to be distinct.

    + +

    The == operator will continue to return true + for 0.0 == -0.0.

    + +

    To help to find code that might need to be revised, in OTP 27 + there will be a new compiler warning when matching against + 0.0 or comparing to that value using the =:= + operator. The warning can be suppressed by matching against + +0.0 instead of 0.0.

    + +

    We plan to introduce the same warning in OTP 26.1, but by default it + will be disabled.

    -
    -
    - OTP 26
    - The distribution flag DFLAG_V4_NC will become mandatory -

    As of OTP 26, the distribution flag DFLAG_V4_NC - will become mandatory. If you implement the Erlang distribution - protocol yourself, you will need to implement support for - DFLAG_V4_NC in order to communicate with Erlang nodes - running OTP 26.

    + + Singleton type variables will become a compile-time error + +

    Before Erlang/OTP 26, the compiler would silenty accept the + following spec:

    + +
    +-spec f(Opts) -> term() when
    +    Opts :: {ok, Unknown} | {error, Unknown}.
    +f(_) -> error.
    + +

    In OTP 26, the compiler emits a warning pointing out that the type variable + Unknown is unbound:

    + +
    +t.erl:6:18: Warning: type variable 'Unknown' is only used once (is unbound)
    +%    6|     Opts :: {ok, Unknown} | {error, Unknown}.
    +%     |                  ^
    + +

    In OTP 27, that warning will become an error.

    - The new link protocol will become mandatory + + Escripts will be compiled by default + +

    Escripts will be compiled by default instead of interpreted. + That means that the compiler application must be available.

    + +

    The old behavior of interpreting escripts can be restored by adding + the following line to the script file:

    +
    +-mode(interpret).
    + +

    In OTP 28, support for interpreting an escript will be removed.

    +
    + +
    + -code_path_choice will default to strict +

    + This command line option controls if paths given in the command + line, boot scripts, and the code server should be interpreted as + is strict or relaxed. +

    +

    + OTP 26 and earlier defaults to relaxed, which means + -pa myapp/ebin would attempt to load -pa myapp/ebin + and -pa myapp/myapp/ebin. The option will default to + strict in OTP 27. +

    +
    + +
    + Archive fallbacks will be removed

    - As of OTP 26, the new link - protocol will become mandatory. That is, Erlang - nodes will then refuse to connect to nodes not implementing - the new link protocol. If you implement the Erlang - distribution yourself, you are, however, encouraged to - implement the new link protocol as soon as possible since the - old protocol can cause links to enter an inconsistent state. + OTP 26 and earlier allows an application to have part of its + directories as regular folders and others as archives. + This functionality was previously used by reltool but it is + no longer the case from OTP 26. Support for archive fallbacks + will be removed from the code server in OTP 27.

    - - Atoms will be encoded as UTF-8 by default + + Triple-Quoted Strings

    - As of OTP 26, the functions - - erlang:term_to_binary/1,2 and - - erlang:term_to_iovec/1,2 will encode all atoms as - UTF-8 by default. The current default behavior is to encode atoms as - Latin-1 if possible. + Before Erlang/OTP 27 a sequence of 3 or more double-quote characters + was grouped in pairs each meaning the empty string and if there was + an odd number the last character was the start of a string. + The empty strings were then concatenated and effectively disappeared.

    - If you implement your own decoding of the Erlang external format you - must either: + In Erlang/OTP 27; 3 or more double-quote characters + are interpreted as the start of a "Triple-Quoted String". See + EEP 64. +

    +

    + Here follows some examples of code that would change meaning. + Note that all these examples before Erlang/OTP 27.0 was strange + since there was no sensible reason to write like that. +

    +
    +"""String Content"""
    +%% Was interpreted as
    +"" "String Content" ""
    +%% Which becomes
    +"String Content"
    +%%
    +%% In OTP 27 it is instead a syntax error since no text is allowed
    +%% on the line after an opening triple-quote
    +      
    +
    +"""
    +String Content
    +"""
    +%% Was interpreted as
    +"" "
    +String Content
    +" ""
    +%% Which becomes
    +"
    +String Content
    +"
    +%%
    +%% In OTP 27 it is instead interpreted as a
    +%% Triple-Quoted String equivalent to
    +"String Content"
    +      
    +
    +""""
    +++ foo() ++
    +""""
    +%% Became
    +"" ++ foo() ++ ""
    +%%
    +%% In OTP 27 it is instead interpreted as a
    +%% Triple-Quoted String (triple-or-more) equivalent to
    +"++ foo() ++"
    +      
    +

    + From Erlang/OTP 26.1 up to 27.0 the compiler issues a warning for + a sequence of 3 or more double-quote characters + since that is almost certainly a mistake or + something like a result of bad automatic code generation. + If a users gets that warning, the code should be corrected + for example by inserting appropriate spaces between + the empty strings, or removing the redundant ones alltogether, + which will have the same meaning before and after Erlang/OTP 27.

    - - -

    - Make sure your implementation supports the UTF-8 encodings - - ATOM_UTF8_EXT and - - SMALL_ATOM_UTF8_EXT. -

    -
    - -

    - Call - erlang:term_to_binary/2 or - - erlang:term_to_iovec/2 - with option {minor_version,1} to force Latin-1 encoding. This - is a more short-term solution as Latin-1 encoding may be phased out - and removed in later OTP releases. -

    -
    -
    + +
    + OTP 28 + +
    + + Fun creator pid will be removed +

    + As of OTP 28, the function erlang:fun_info/1 + will not include the {pid,_} element and the function + erlang:fun_info/2 + will no longer accept pid as the second argument.

    +
    + +
    + + Support for interpreting escripts will be removed + +

    Escripts will be compiled, and it will no longer be possible + to force an escript to be interpreted by using the directive + -mode(interpret).

    +
    +
    + +
    + OTP 29 + +
    + It will no longer be possible to disable feature maybe_expr +

    + As of OTP 29, the maybe_expr feature will become + permanent and no longer possible to disable. All uses of + maybe as an atom will need to be quoted. +

    +

    + It is recommend to quote all uses of the atom maybe as soon as + possible. The compiler option warn_keywords can be used to emit + warnings about all occurrences of maybe without quotes. +

    +
    +
    + diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile index 6a286d6df63f..045e90339904 100644 --- a/system/doc/getting_started/Makefile +++ b/system/doc/getting_started/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/getting_started # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/getting_started" +RELSYSDIR = $(RELEASE_PATH)/doc/getting_started # ---------------------------------------------------- # Target Specs @@ -99,7 +99,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile index 53a1cad319eb..17674c614cf4 100644 --- a/system/doc/installation_guide/Makefile +++ b/system/doc/installation_guide/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2021. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -33,7 +33,7 @@ XMLDIR := $(XMLDIR)/installation_guide # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/installation_guide" +RELSYSDIR = $(RELEASE_PATH)/doc/installation_guide REDIRECT_HTML_RELSYSDIR = $(RELSYSDIR)/source # ---------------------------------------------------- @@ -114,9 +114,8 @@ debug opt: clean clean_docs: rm -f $(GENERATED_XML_FILES) rm -f $(XMLDIR)/*.xml - rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html + rm -f $(HTMLDIR)/*/*.gif $(HTMLDIR)/*/*.html rm -f $(XML_GEN_FILES) - rm -rf $(HTMLDIR) rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ @@ -127,9 +126,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" - $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html $(RELSYSDIR) - $(INSTALL_DIR) $(REDIRECT_HTML_RELSYSDIR) - $(INSTALL_DATA) $(REDIRECT_HTML_FILES) $(REDIRECT_HTML_RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html "$(RELSYSDIR)" + $(INSTALL_DIR) "$(REDIRECT_HTML_RELSYSDIR)" + $(INSTALL_DATA) $(REDIRECT_HTML_FILES) "$(REDIRECT_HTML_RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/installation_guide/install-binary.xml b/system/doc/installation_guide/install-binary.xml index b070c0263363..178969a84281 100644 --- a/system/doc/installation_guide/install-binary.xml +++ b/system/doc/installation_guide/install-binary.xml @@ -4,7 +4,7 @@
    - 20002016 + 20002023 Ericsson AB. All Rights Reserved. @@ -35,7 +35,8 @@
    Windows

    The system is delivered as a Windows Installer executable. - Get it from http://www.erlang.org/download.html

    + Get it from + https://erlang.org/downloads.

    Installing diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile index 40b14485da49..c8e5755ad0d9 100644 --- a/system/doc/oam/Makefile +++ b/system/doc/oam/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2020. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -31,7 +31,7 @@ XMLDIR := $(XMLDIR)/oam # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/oam" +RELSYSDIR = $(RELEASE_PATH)/doc/oam # ---------------------------------------------------- # Target Specs @@ -101,7 +101,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile index 7099d88ebcd5..0a2c18fcae61 100644 --- a/system/doc/programming_examples/Makefile +++ b/system/doc/programming_examples/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2020. All Rights Reserved. +# Copyright Ericsson AB 2003-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/programming_examples # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/programming_examples" +RELSYSDIR = $(RELEASE_PATH)/doc/programming_examples # ---------------------------------------------------- # Target Specs @@ -99,7 +99,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index cc89f3a469db..08587ccff39c 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -4,7 +4,7 @@
    - 20032020 + 20032022 Ericsson AB. All Rights Reserved. @@ -206,7 +206,7 @@ X:4/little-signed-integer-unit:8 matching, this default value is only valid for the last element. All other binary elements in matching must have a size specification.

    -

    The default unit depends on the the type. For integer, +

    The default unit depends on the type. For integer, float, and bitstring it is 1. For binary it is 8.

    The default signedness is unsigned.

    The default endianness is big.

    @@ -311,8 +311,8 @@ foo(N, Bin) ->
    Binding and Using a Size Variable

    There is one exception to the rule that a variable that is - as size must be previously bound. It is possible to match and - bind a variable, and use it as a size within the the same + used as size must be previously bound. It is possible to match and + bind a variable, and use it as a size within the same binary pattern. For example:

    - 20142021 + 20142023 Ericsson AB. All Rights Reserved. @@ -41,7 +41,7 @@ shown without the escape backslash convention.

    -

    Atoms and variables can use all Latin-1 letters.

    +

    Unquoted atoms and variables can use all Latin-1 letters.

    @@ -101,17 +101,35 @@ Character Classes
    -

    In Erlang/OTP R16B the syntax of Erlang tokens was extended to - handle Unicode. The support was limited to - string literals and comments. - More about the usage of Unicode in Erlang source files - can be found in STDLIB's User's - Guide.

    -

    From Erlang/OTP 20, atoms and function names are also allowed - to contain Unicode characters outside the ISO-Latin-1 range. - Module names, application names, and node names are still - restricted to the ISO-Latin-1 range.

    + +

    The following tokens are allowed to also use Unicode characters + outside of the Latin-1 range:

    + + + +

    String literals. Example: "√π"

    +
    + +

    Character literals. Example: $∑

    +
    + +

    Comments in code.

    +
    + +

    Quoted atoms. Example: 'μs'

    +
    + +

    Function names. Example: 's_to_μs'(S) -> S * 1_000_000.

    +
    +
    + +

    Atoms used as module names, application names, and node names are + restricted to the Latin-1 range.

    + +

    Support for Unicode in string literals, character literals, + and comments was introduced in Erlang/OTP R16B. Support for Unicode in + atom and function names was introduced in Erlang/OTP 20.

    +
    Source File Encoding @@ -123,15 +141,17 @@ the matching string is an invalid encoding, it is ignored. The valid encodings are Latin-1 and UTF-8, where the case of the characters can be chosen freely.

    -

    The following example selects UTF-8 as default encoding:

    -
    -%% coding: utf-8
    -

    Two more examples, both selecting Latin-1 as default encoding:

    + +

    The default Erlang source file encoding if no valid + coding comment is present is UTF-8.

    + +

    Two examples, both selecting Latin-1 as the source file encoding:

     %% For this file we have chosen encoding = Latin-1
     %% -*- coding: latin-1 -*-
    -

    The default encoding for Erlang source files is changed from - Latin-1 to UTF-8 since Erlang/OTP 17.0.

    + +

    The default encoding for Erlang source files was changed from + Latin-1 to UTF-8 in Erlang/OTP 17.0.

    diff --git a/system/doc/reference_manual/code_loading.xml b/system/doc/reference_manual/code_loading.xml index b64b2eecf9f0..5bc4332c72d7 100644 --- a/system/doc/reference_manual/code_loading.xml +++ b/system/doc/reference_manual/code_loading.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -157,12 +157,12 @@ loop() -> before the on_load function has finished will be suspended until the on_load function have finished.

    - -

    Before OTP 19, if the on_load function failed, any + +

    Before Erlang/OTP 19, if the on_load function failed, any previously current code would become old, essentially leaving the system without any working and reachable instance of the - module. That problem has been eliminated in OTP 19.

    -
    + module.

    +

    In embedded mode, first all modules are loaded. Then all on_load functions are called. The system is diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index 15983ebbf9a6..4b58c6a5ca81 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -4,7 +4,7 @@

    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -30,7 +30,15 @@ data_types.xml

    Erlang provides a number of data types, which are listed in - this section.

    + this section.

    + + +

    Note that Erlang has no user defined types, only composite + types (data structures) made of Erlang terms. This means that any + function testing for a composite type, typically named + is_type/1, might return true for a term + that coincides with the chosen representation. The corresponding + functions for built in types do not suffer from this.

    Terms @@ -85,8 +93,8 @@

    When working with floats you may not see what you expect when printing or doing arithmetic operations. This is because floats are represented by a fixed number of bits in a base-2 system while - printed floats are represented with a base-10 system. Here are - examples of this phenomenon: + printed floats are represented with a base-10 system. Erlang + uses 64-bit floats. Here are examples of this phenomenon:

     > 0.1+0.2.
    @@ -124,6 +132,9 @@ exactly as floats.

    then you should use a library that handles that or work in cents instead of euros so that you do not need decimal fractions.

    +

    Please also note that Erlang's floats do not exactly match IEEE 754 floats, in that neither Inf nor NaN are supported in Erlang. + Any operation that would result in NaN, +Inf, or -Inf, will instead raise a badarith exception. +

    @@ -297,9 +308,10 @@ adam in STDLIB.

    Read more about maps in Map Expressions.

    - -

    Maps are considered to be experimental during Erlang/OTP R17.

    -
    + +

    Maps were introduced as an experimental feature in Erlang/OTP R17. Their + functionality was extended and became fully supported in Erlang/OTP 18.

    +
    @@ -413,75 +425,109 @@ true Description - \b - Backspace + \b + Backspace (ASCII code 8) - \d - Delete + \d + Delete (ASCII code 127) - \e - Escape + \e + Escape (ASCII code 27) - \f - Form feed + \f + Form Feed (ASCII code 12) - \n - Newline + \n + Line Feed/Newline (ASCII code 10) - \r - Carriage return + \r + Carriage Return (ASCII code 13) - \s - Space + \s + Space (ASCII code 32) - \t - Tab + \t + (Horizontal) Tab (ASCII code 9) - \v - Vertical tab + \v + Vertical Tab (ASCII code 11) - \XYZ, \YZ, \Z + \XYZ, \YZ, \Z Character with octal representation XYZ, YZ or Z - \xXY + \xXY Character with hexadecimal representation XY - \x{X...} + \x{X...} Character with hexadecimal representation; X... is one or more hexadecimal characters - \^a...\^z

    -\^A...\^Z
    + \^a...\^z

    +\^A...\^Z
    Control A to control Z
    - \' + \^@ + NUL (ASCII code 0) + + + \^[ + Escape (ASCII code 27) + + + \^\ + File Separator (ASCII code 28) + + + \^] + Group Separator (ASCII code 29) + + + \^^ + Record Separator (ASCII code 30) + + + \^_ + Unit Separator (ASCII code 31) + + + \^? + Delete (ASCII code 127) + + + \' Single quote - \" + \" Double quote - \\ + \\ Backslash Recognized Escape Sequences + + +

    As of Erlang/OTP 26, the value of $\^? has been + changed to be 127 (Delete), instead of 31. Previous releases + would allow any character following $\^; as of Erlang/OTP + 26, only the documented characters are allowed.

    @@ -525,4 +571,3 @@ hello 7.0
    - diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index cc4746825bf9..ceb6e4c6a114 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -155,7 +155,7 @@ dilbert@uab name from the first node it connects to. In addition these distribution settings will be set:

    -
    -dist_listen false -hidden -dist_auto_connect never
    +
    -dist_listen false -hidden -kernel dist_auto_connect never

    As -dist_auto_connect is set to never, net_kernel:connect_node/1 @@ -167,14 +167,14 @@ dilbert@uab can be made to get a new dynamic node name. The node name may change if the distribution is dropped and then set up again.

    - +

    - The dynamic node name feature is supported from OTP 23. + The dynamic node name feature is supported from Erlang/OTP 23. Both the temporary client node and the first connected peer node - (supplying the dynamic node name) must be at least OTP 23 for it to + (supplying the dynamic node name) must be at least Erlang/OTP 23 for it to work.

    -
    +
    @@ -212,7 +212,7 @@ dilbert@uab in the following text is not very unpredictable. A better one can be generated using primitives in the crypto module, though this still does not make - the inital handshake cryptographically secure. + the initial handshake cryptographically secure. And inter-node communication is still in clear text.

    @@ -230,9 +230,14 @@ dilbert@uab

    At start-up, a node has a random atom assigned as its default magic cookie and the cookie of other nodes is assumed to be nocookie. The first action of the Erlang network - authentication server (auth) is then to read a file named - $HOME/.erlang.cookie. If the file does not exist, it is - created. The UNIX permissions mode of the file is set to octal + authentication server (auth) is then to search for a file named + .erlang.cookie in the + user's home directory and then in + + filename:basedir(user_config, "erlang"). + If none of the files exist, a .erlang.cookie file is created + in the user's home directory. + The UNIX permissions mode of the file is set to octal 400 (read-only by user) and its content is a random string. An atom Cookie is created from the contents of the file and the cookie of the local node is set to this using diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 8dbc620bd040..6b3ba96b6b13 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -4,7 +4,7 @@

    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -138,18 +138,22 @@ member(_Elem, []) -> Name1 [H|T] {error,Reason} -

    Patterns are allowed in clause heads, case and - receive expressions, and match expressions.

    +

    Patterns are allowed in clause heads, + case expressions, + receive expressions, + and + match expressions.

    - Match Operator = in Patterns + + The Compound Pattern Operator

    If Pattern1 and Pattern2 are valid patterns, the following is also a valid pattern:

     Pattern1 = Pattern2

    When matched against a term, both Pattern1 and - Pattern2 are matched against the term. The idea - behind this feature is to avoid reconstruction of terms.

    + Pattern2 are matched against the term. The idea behind + this feature is to avoid reconstruction of terms.

    Example:

     f({connect,From,To,Number,Options}, To) ->
    @@ -163,6 +167,11 @@ f({connect,_,To,_,_} = Signal, To) ->
         ...;
     f(Signal, To) ->
         ignore.
    + +

    The compound pattern operator does not imply that its operands + are matched in any particular order. That means that it is not + legal to bind a variable in Pattern1 and use it in Pattern2, + or vice versa.

    @@ -192,22 +201,121 @@ case {Value, Result} of
    - Match -

    The following matches Expr1, a pattern, against - Expr2:

    + + The Match Operator +

    The following matches Pattern against + Expr:

    -Expr1 = Expr2
    +Pattern = Expr

    If the matching succeeds, any unbound variable in the pattern - becomes bound and the value of Expr2 is returned.

    + becomes bound and the value of Expr is returned.

    +

    If multiple match operators are applied in sequence, they will be + evaluated from right to left.

    If the matching fails, a badmatch run-time error occurs.

    Examples:

    -1> {A, B} = {answer, 42}.
    +1> {A, B} = T = {answer, 42}.
     {answer,42}
     2> A.
     answer
    -3> {C, D} = [1, 2].
    +3> B.
    +42
    +4> T.
    +{answer,42}
    +5> {C, D} = [1, 2].
     ** exception error: no match of right-hand side value [1,2]
    + +

    Because multiple match operators are evaluated from right to left, + it means that:

    + +
    +Pattern1 = Pattern2 = . . . = PatternN = Expression
    + +

    is equivalent to:

    +
    +Temporary = Expression,
    +PatternN = Temporary,
    +   .
    +   .
    +   .,
    +Pattern2 = Temporary,
    +Pattern = Temporary
    +
    + +
    + The Match Operator and the Compound Pattern Operator +

    This is an advanced section, which references to topics not + yet introduced. It can safely be skipped on a first + reading.

    + +

    The = character is used to denote two similar but + distinct operators: the match operator and the compound pattern + operator. Which one is meant is determined by context.

    + +

    The compound pattern operator is used to construct a + compound pattern from two patterns. Compound patterns are accepted + everywhere a pattern is accepted. A compound pattern matches if + all of its constituent patterns match. It is not legal for a + pattern that is part of a compound pattern to use variables (as + keys in map patterns or sizes in binary patterns) bound in other + sub patterns of the same compound pattern.

    +

    Examples:

    + +
    +1> fun(#{Key := Value} = #{key := Key}) -> Value end.
    +* 1:7: variable 'Key' is unbound
    +2> F = fun({A, B} = E) -> {E, A + B} end, F({1,2}).
    +{{1,2},3}
    +3> G = fun(<<A:8,B:8>> = <<C:16>>) -> {A, B, C} end, G(<<42,43>>).
    +{42,43,10795}
    + +

    The match operator is allowed everywhere an expression + is allowed. It is used to match the value of an expression to a pattern. + If multiple match operators are applied in sequence, they will be + evaluated from right to left.

    + +

    Examples:

    +
    +1> M = #{key => key2, key2 => value}.
    +#{key => key2,key2 => value}
    +2> f(Key), #{Key := Value} = #{key := Key} = M, Value.
    +value
    +3> f(Key), #{Key := Value} = (#{key := Key} = M), Value.
    +value
    +4> f(Key), (#{Key := Value} = #{key := Key}) = M, Value.
    +* 1:12: variable 'Key' is unbound
    +5> <<X:Y>> = begin Y = 8, <<42:8>> end, X.
    +42
    + +

    The expression at prompt 2> first matches the value of + variable M against pattern #{key := Key}, binding + variable Key. It then matches the value of M against + pattern #{Key := Value} using variable Key as the + key, binding variable Value.

    + +

    The expression at prompt 3> matches expression + (#{key := Key} = M) against pattern #{Key := + Value}. The expression inside the parentheses is evaluated + first. That is, M is matched against #{key := Key}, + and then the value of M is matched against pattern #{Key + := Value}. That is the same evaluation order as in 2; + therefore, the parentheses are redundant.

    + +

    In the expression at prompt 4> the expression M + is matched against a pattern inside parentheses. Since the + construct inside the parentheses is a pattern, the = that + separates the two patterns is the compound pattern operator + (not the match operator). The match fails because the two + sub patterns are matched at the same time, and the variable + Key is therefore not bound when matching against pattern + #{Key := Value}.

    + +

    In the expression at prompt 5> the expressions + inside the block + expression are evaluated first, binding variable + Y and creating a binary. The binary is then matched + against pattern <<X:Y>> using the value of + Y as the size of the segment.

    @@ -268,13 +376,13 @@ spawn(m, init, []) being auto-imported. In certain situations, such a compile-directive is mandatory.

    -

    Before OTP R14A (ERTS version 5.8), an implicitly +

    Before OTP R14A (ERTS version 5.8), an implicitly qualified function call to a function having the same name as an auto-imported BIF always resulted in the BIF being called. In newer versions of the compiler, the local function is called instead. This is to avoid that future additions to the set of auto-imported BIFs do not silently change the behavior - of old code.

    + of old code.

    However, to avoid that old (pre R14) code changed its behavior when compiled with OTP version R14A or later, the @@ -284,7 +392,7 @@ spawn(m, init, []) your code, you either need to explicitly remove the auto-import using a compiler directive, or replace the call with a fully qualified function call. Otherwise you get a compilation - error. See the following example:

    + error. See the following example:

    -export([length/1,f/1]). @@ -394,6 +502,138 @@ is_valid_signal(Signal) -> end.
    +
    + + Maybe +

    maybe is an experimental feature + introduced in Erlang/OTP 25. By default, it is disabled. To enable + maybe, either use the -feature(maybe_expr,enable) + directive (from within source code), or the compiler option + {feature,maybe_expr,enable}.

    +
    + + + +

    The expressions in a maybe block are evaluated sequentially. If all + expressions are evaluated successfully, the return value of the maybe + block is ExprN. However, execution can be short-circuited by a + conditional match expression:

    + + + +

    ?= is called the conditional match operator. It is only + allowed to be used at the top-level of a maybe block. It + matches the pattern Expr1 against Expr2. If the + matching succeeds, any unbound variable in the pattern becomes + bound. If the expression is the last expression in the + maybe block, it also returns the value of Expr2. If the + matching is unsuccessful, the rest of the expressions in the maybe + block are skipped and the return value of the maybe + block is Expr2.

    + +

    None of the variables bound in a maybe block must be + used in the code that follows the block.

    + +

    Here is an example:

    + + = 0, + {ok, B} ?= b(), + A + B +end]]> + +

    Let us first assume that a() returns {ok,42} and + b() returns {ok,58}. With those return values, all + of the match operators will succeed, and the return value of the + maybe block is A + B, which is equal to 42 + + 58 = 100.

    + +

    Now let us assume that a() returns error. The + conditional match operator in {ok, A} ?= a() fails to + match, and the return value of the maybe block is the + value of the expression that failed to match, namely error. + Similarly, if b() returns wrong, the return value of + the maybe block is wrong.

    + +

    Finally, let us assume that a() returns + -1. Because true = A >= 0 uses the match operator + `=`, a {badmatch,false} run-time error occurs when the + expression fails to match the pattern.

    + +

    The example can be written in a less succient way using nested + case expressions:

    + + + true = A >= 0, + case b() of + {ok, B} -> + A + B; + Other1 -> + Other1 + end; + Other2 -> + Other2 +end]]> + +

    The maybe block can be augmented with else clauses:

    + + + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +end]]> + +

    If a conditional match operator fails, the failed expression is + matched against the patterns in all clauses between the + else and end keywords. If a match succeeds and the + optional guard sequence GuardSeq is true, the corresponding + Body is evaluated. The value returned from the body is the + return value of the maybe block.

    + +

    If there is no matching pattern with a true guard sequence, + an else_clause run-time error occurs.

    + +

    None of the variables bound in a maybe block must be used in + the else clauses. None of the variables bound in the else clauses + must be used in the code that follows the maybe block.

    + +

    Here is the previous example augmented with a else clauses:

    + + = 0, + {ok, B} ?= b(), + A + B +else + error -> error; + wrong -> error +end]]> + +

    The else clauses translate the failing value from + the conditional match operators to the value error. If the + failing value is not one of the recognized values, a + else_clause run-time error occurs.

    +
    +
    Send @@ -804,16 +1044,21 @@ case A >= -1.0 andalso math:sqrt(A+1) > B of OnlyOne = is_atom(L) orelse (is_list(L) andalso length(L) == 1), -

    From Erlang/OTP R13A, Expr2 is no longer required to evaluate to a - Boolean value. As a consequence, andalso and orelse - are now tail-recursive. For instance, the following function is - tail-recursive in Erlang/OTP R13A and later:

    +

    Expr2 is not required to evaluate to a Boolean + value. Because of that, andalso and orelse are + tail-recursive.

    +

    Example 3 (tail-recursive function):

     all(Pred, [Hd|Tail]) ->
         Pred(Hd) andalso all(Pred, Tail);
     all(_, []) ->
         true.
    + +

    Before Erlang/OTP R13A, Expr2 was required to + evaluate to a Boolean value, and as consequence, andalso + and orelse were not + tail-recursive.

    @@ -824,7 +1069,7 @@ Expr1 -- Expr2

    The list concatenation operator ++ appends its second argument to its first and returns the resulting list.

    The list subtraction operator -- produces a list that - is a copy of the first argument. The procedure is a follows: + is a copy of the first argument. The procedure is as follows: for each element in the second argument, the first occurrence of this element (if any) is removed.

    Example:

    @@ -933,7 +1178,7 @@ M4 = #{{"w", 1} => f()}. % compound key associated with an evaluated expression

    If key K does not match any existing keys in map M, an exception - of type badarg is triggered at runtime. If a matching key K + of type badkey is triggered at runtime. If a matching key K is present in map M, its associated value is replaced by the new value V, and the evaluated map expression returns a new map.

    @@ -993,9 +1238,9 @@ M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.
    with the key K, which must exist in the map M. If the variable V is bound, it must match the value associated with K in M.

    -

    Before OTP 23, the expression defining the key +

    Before Erlang/OTP 23, the expression defining the key K was restricted to be either a single variable or a - literal.

    + literal.

    Example:

     1> M = #{"tuple" => {1,2}}.
    @@ -1014,7 +1259,7 @@ M4 = M3#{a := 2, b := 3}.  % 'a' and 'b' was added in `M1` and `M2`.
     	  

    Here keys K1 .. Kn are any expressions with literals or bound variables. If all key expressions - evalute successfully and all keys exist in map + evaluate successfully and all keys exist in map M, all variables in V1 .. Vn is matched to the associated values of their respective keys. @@ -1103,38 +1348,52 @@ handle_call(change, From, #{ state := start } = S) ->

    Bit Syntax Expressions - > +

    + The bit syntax operates on bit strings. + A bit string is a sequence of bits ordered + from the most significant bit to the least significant bit. +

    + > % The empty bit string, zero length +<> <>]]> -

    Each element Ei specifies a segment of - the bit string. Each element Ei is a value, followed by an - optional size expression and an optional type specifier list.

    +

    + Each element Ei specifies a segment of + the bit string. The segments are ordered left to right + from the most significant bit to the least significant bit + of the bit string. +

    +

    + Each segment specification Ei is a value, followed by an + optional size expression + and an optional type specifier list. +

     Ei = Value |
          Value:Size |
          Value/TypeSpecifierList |
          Value:Size/TypeSpecifierList
    -

    Used in a bit string construction, Value is an expression +

    When used in a bit string construction, Value is an expression that is to evaluate to an integer, float, or bit string. If the expression is not a single literal or variable, it is to be enclosed in parentheses.

    -

    Used in a bit string matching, Value must be a variable, +

    When used in a bit string matching, Value must be a variable, or an integer, float, or string.

    Notice that, for example, using a string literal as in >]]> is syntactic sugar for >]]>.

    -

    Used in a bit string construction, Size is an expression +

    When used in a bit string construction, Size is an expression that is to evaluate to an integer.

    -

    Used in a bit string matching, Size must be a +

    When used in a bit string matching, Size must be a guard expression that evaluates to an integer. All variables in the guard expression must be already bound.

    -

    Before OTP 23, Size was restricted to be an - integer or a variable bound to an integer.

    +

    Before Erlang/OTP 23, Size was restricted to be an + integer or a variable bound to an integer.

    The value of Size specifies the size of the segment in units (see below). The default value depends on the type (see @@ -1145,14 +1404,45 @@ Ei = Value | For binary and bitstring it is the whole binary or bit string. -

    In matching, this default value is only - valid for the last element. All other bit string or binary - elements in the matching must have a size specification.

    +

    In matching, the default value for a binary or bit string + segment is only valid for the last element. All other bit string + or binary elements in the matching must have a size + specification.

    + + +

    Binaries

    +

    + A bit string with a length that is a multiple of 8 bits + is known as a binary, which is the most + common and useful type of bit string. +

    +

    + A binary has a canonical representation in memory. + Here follows a sequence of bytes where each byte's + value is its sequence number: +

    +
    <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>
    +

    + Bit strings are a later generalization of binaries, + so many texts and much information about binaries + apply just as well for bit strings. +

    + +

    Example:

    +
    +1> <<A/binary, B/binary>> = <<"abcde">>.
    +* 1:3: a binary field without size is only allowed at the end of a binary pattern
    +2> <<A:3/binary, B/binary>> = <<"abcde">>.
    +<<"abcde">>
    +3> A.
    +<<"abc">>
    +4> B.
    +<<"de">>

    For the utf8, utf16, and utf32 types, Size must not be given. The size of the segment is implicitly determined by the type and value itself.

    - +

    TypeSpecifierList is a list of type specifiers, in any order, separated by hyphens (-). Default values are used for any omitted type specifiers.

    @@ -1170,68 +1460,172 @@ Ei = Value | The default is unsigned. Endianness= big | little | native - Native-endian means that the endianness is resolved at load - time to be either big-endian or little-endian, depending on - what is native for the CPU that the Erlang machine is run on. - Endianness only matters when the Type is either integer, - utf16, utf32, or float. The default is big. - + + Specifies byte level (octet level) endianness (byte order). + Native-endian means that the endianness is resolved at load + time to be either big-endian or little-endian, depending on + what is native for the CPU that the Erlang machine is run on. + Endianness only matters when the Type is either integer, + utf16, utf32, or float. The default is big. +
    <<16#1234:16/little>> = <<16#3412:16>> = <<16#34:8, 16#12:8>>
    +
    Unit= unit:IntegerLiteral - The allowed range is 1..256. Defaults to 1 for integer, - float, and bitstring, and to 8 for binary. - No unit specifier must be given for the types - utf8, utf16, and utf32. - + The allowed range is 1 through 256. Defaults to 1 for integer, + float, and bitstring, and to 8 for binary. + For types bitstring, bits, and bytes, it is not allowed + to specify a unit value different from the default value. + No unit specifier must be given for the types utf8, utf16, + and utf32. + -

    The value of Size multiplied with the unit gives - the number of bits. A segment of type binary must have - a size that is evenly divisible by 8. For a segment of type float - the size must be either 64, 32, or 16.

    - -

    When constructing binaries, if the size N of an integer - segment is too small to contain the given integer, the most significant - bits of the integer are silently discarded and only the N least - significant bits are put into the binary.

    - -

    The types utf8, utf16, and utf32 specifies - encoding/decoding of the Unicode Transformation Formats UTF-8, UTF-16, - and UTF-32, respectively.

    - -

    When constructing a segment of a utf type, Value - must be an integer in the range 0..16#D7FF or - 16#E000....16#10FFFF. Construction - fails with a badarg exception if Value is - outside the allowed ranges. The size of the resulting binary - segment depends on the type or Value, or both:

    - - For utf8, Value is encoded in 1-4 bytes. - For utf16, Value is encoded in 2 or 4 bytes. - For utf32, Value is always be encoded in 4 bytes. - -

    When constructing, a literal string can be given followed - by one of the UTF types, for example: >]]> - which is syntactic sugar for - >]]>.

    +
    + Integer segments +

    The value of Size multiplied with the unit gives the + size of the segment in bits.

    + +

    When constructing bit strings, if the size N of an integer + segment is too small to contain the given integer, the most significant + bits of the integer are silently discarded and only the N least + significant bits are put into the bit string. For example, <<16#ff:4>> + will result in the bit string <<15:4>>.

    +
    -

    A successful match of a segment of a utf type, results - in an integer in the range 0..16#D7FF or 16#E000..16#10FFFF. - The match fails if the returned value falls outside those ranges.

    +
    + Float segments +

    The value of Size multiplied with the unit gives + the size of the segment in bits. The size of a float segment in bits must be + one of 16, 32, or 64.

    -

    A segment of type utf8 matches 1-4 bytes in the binary, - if the binary at the match position contains a valid UTF-8 sequence. - (See RFC-3629 or the Unicode standard.)

    +

    When constructing bit strings, if the size of a float segment is too small + to contain the representation of the given float value, an exception is raised.

    -

    A segment of type utf16 can match 2 or 4 bytes in the binary. - The match fails if the binary at the match position does not contain - a legal UTF-16 encoding of a Unicode code point. (See RFC-2781 or - the Unicode standard.)

    +

    When matching bit strings, matching of float segments fails if the bits of the segment + does not contain the representation of a finite floating point value.

    +
    + +
    + Binary segments +

    In this section, the phrase "binary segment" refers to any + one of the segment types binary, bitstring, + bytes, and bits.

    + +

    + See also the paragraphs about + Binaries. +

    -

    A segment of type utf32 can match 4 bytes in the binary in the - same way as an integer segment matches 32 bits. - The match fails if the resulting integer is outside the legal ranges - mentioned above.

    +

    When constructing binaries and no size is specified for a + binary segment, the entire binary value is interpolated into the + binary being constructed. However, the size in bits of the + binary being interpolated must be evenly divisible by the unit + value for the segment; otherwise an exception is raised.

    + +

    For example, the following examples all succeed:

    + +
    +1> <<(<<"abc">>)/bitstring>>.
    +<<"abc">>
    +2> <<(<<"abc">>)/binary-unit:1>>.
    +<<"abc">>
    +3> <<(<<"abc">>)/binary>>.
    +<<"abc">>
    + +

    The first two examples have a unit value of 1 for the segment, + while the third segment has a unit value of 8.

    + +

    Attempting to interpolate a bit string of size 1 into a + binary segment with unit 8 (the default unit for binary) + fails as shown in this example:

    + +
    +1> <<(<<1:1>>)/binary>>.
    +** exception error: bad argument
    + +

    For the construction to succeed, the unit value of the + segment must be 1:

    + +
    +2> <<(<<1:1>>)/bitstring>>.
    +<<1:1>>
    +3> <<(<<1:1>>)/binary-unit:1>>.
    +<<1:1>>
    + +

    Similarly, when matching a binary segment with no size + specified, the match succeeds if and only if the size in bits of + the rest of the binary is evenly divisible by the unit + value:

    + +
    +1> <<_/binary-unit:16>> = <<"">>.
    +<<>>
    +2> <<_/binary-unit:16>> = <<"a">>.
    +** exception error: no match of right hand side value <<"a">>
    +3> <<_/binary-unit:16>> = <<"ab">>.
    +<<"ab">>
    +4> <<_/binary-unit:16>> = <<"abc">>.
    +** exception error: no match of right hand side value <<"abc">>
    +5> <<_/binary-unit:16>> = <<"abcd">>.
    +<<"abcd">>
    + +

    When a size is explicitly specified for a binary segment, + the segment size in bits is the value of Size multiplied + by the default or explicit unit value.

    + +

    When constructing binaries, the size of the binary being interpolated + into the constructed binary must be at least as large as the size of + the binary segment.

    + +

    Examples:

    +
    +1> <<(<<"abc">>):2/binary>>.
    +<<"ab">>
    +2> <<(<<"a">>):2/binary>>.
    +** exception error: construction of binary failed
    +        *** segment 1 of type 'binary': the value <<"a">> is shorter than the size of the segment
    +
    + +
    + Unicode segments +

    The types utf8, utf16, and utf32 specifies + encoding/decoding of the Unicode Transformation Formats UTF-8, UTF-16, + and UTF-32, respectively.

    + +

    When constructing a segment of a utf type, + Value must be an integer in the range 0 through 16#D7FF + or 16#E000 through 16#10FFFF. Construction fails with a + badarg exception if Value is outside the allowed + ranges. The sizes of the encoded values are as follows:

    + + For utf8, Value is encoded in 1-4 bytes. + For utf16, Value is encoded in 2 or 4 bytes. + For utf32, Value is encoded in 4 bytes. + + +

    When constructing, a literal string can be given followed + by one of the UTF types, for example: >]]> + which is syntactic sugar for + >]]>.

    + +

    A successful match of a segment of a utf type, results + in an integer in the range 0 through 16#D7FF or 16#E000 through 16#10FFFF. + The match fails if the returned value falls outside those ranges.

    + +

    A segment of type utf8 matches 1-4 bytes in the bit string, + if the bit string at the match position contains a valid UTF-8 sequence. + (See RFC-3629 or the Unicode standard.)

    + +

    A segment of type utf16 can match 2 or 4 bytes in the bit string. + The match fails if the bit string at the match position does not contain + a legal UTF-16 encoding of a Unicode code point. (See RFC-2781 or + the Unicode standard.)

    + +

    A segment of type utf32 can match 4 bytes in the bit string in the + same way as an integer segment matches 32 bits. + The match fails if the resulting integer is outside the legal ranges + previously mentioned.

    +

    Examples:

    @@ -1239,6 +1633,7 @@ Ei = Value |
     <<1,17,42>>
     2> Bin2 = <<"abc">>.
     <<97,98,99>>
    +
     3> Bin3 = <<1,17,42:16>>.
     <<1,17,0,42>>
     4> <<A,B,C:16>> = <<1,17,42:16>>.
    @@ -1259,8 +1654,14 @@ Ei = Value |
     <<1,17,2,10:4>>
     12> J.
     <<17,2,10:4>>
    +
     13> <<1024/utf8>>.
     <<208,128>>
    +
    +14> <<1:1,0:7>>.
    +<<128>>
    +15> <<16#123:12/little>> = <<16#231:12>> = <<2:4, 3:4, 1:4>>.
    +<<35,1:4>>
     

    Notice that bit string patterns cannot be nested.

    Notice also that ">]]>" is interpreted as @@ -1315,14 +1716,15 @@ fun Module:Name/Arity

    syntactic sugar for:

     fun (Arg1,...,ArgN) -> Name(Arg1,...,ArgN) end
    -

    In Module:Name/Arity, Module, and Name are atoms - and Arity is an integer. Starting from Erlang/OTP R15, - Module, Name, and Arity can also be variables. - A fun defined in this way refers to the function Name - with arity Arity in the latest version of module - Module. A fun defined in this way is not dependent on - the code for the module in which it is defined. -

    +

    In Module:Name/Arity, Module, and Name are + atoms and Arity is an integer. Module, Name, + and Arity can also be variables. A fun defined in this way + refers to the function Name with arity Arity in the + latest version of module Module. A fun defined in + this way is not dependent on the code for the module in which it + is defined.

    +

    Before Erlang/OTP R15, Module, Name, and Arity were + not allowed to be variables.

    More examples are provided in Programming Examples.

    @@ -1359,10 +1761,27 @@ catch Expr
    returns the value Any.

    Example:

    -5> catch throw(hello).
    +3> catch throw(hello).
     hello

    If throw/1 is not evaluated within a catch, a nocatch run-time error occurs.

    + +

    Before Erlang/OTP 24, the catch operator had + the lowest precedence, making it necessary to add parentheses when + combining it with the match operator:

    +
    +1> A = (catch 42).
    +42
    +2> A.
    +42
    + +

    Starting from Erlang/OTP 24, the parentheses can be omitted:

    +
    +1> A = catch 42.
    +42
    +2> A.
    +42
    +
    @@ -1519,6 +1938,20 @@ catch exit:Reason -> {'EXIT',Reason} error:Reason:Stk -> {'EXIT',{Reason,Stk}} end + +

    Variables bound in the various parts of these expressions have different scopes. + Variables bound just after the try keyword are:

    + + bound in the of section + unsafe in both the catch and after sections, as well as after the whole construct + +

    Variables bound in of section are:

    + + unbound in the catch section + unsafe in both the after section, as well as after the whole construct + +

    Variables bound in the catch section are unsafe in the after section, as well as after the whole construct.

    +

    Variables bound in the after section are unsafe after the whole construct.

    @@ -1536,6 +1969,7 @@ end
    + Block Expressions
     begin
    @@ -1550,99 +1984,204 @@ end
    - List Comprehensions -

    List comprehensions is a feature of many modern functional - programming languages. Subject to certain rules, they provide a - succinct notation for generating elements in a list.

    -

    List comprehensions are analogous to set comprehensions in - Zermelo-Frankel set theory and are called ZF expressions in - Miranda. They are analogous to the setof and - findall predicates in Prolog.

    -

    List comprehensions are written with the following syntax:

    -
    -[Expr || Qualifier1,...,QualifierN]
    + Comprehensions +

    Comprehensions provide a succinct notation for iterating over + one or more terms and constructing a new term. Comprehensions come + in three different flavors, depending on the type of term they + build.

    +

    List comprehensions construct lists. They have the following syntax:

    +
    +[Expr || Qualifier1, . . ., QualifierN]

    Here, Expr is an arbitrary expression, and each - Qualifier is either a generator or a filter.

    - - A generator is written as:

    - -   .

    -ListExpr must be an expression, which evaluates to a - list of terms.
    -A bit string generator is written as:

    - -   .

    -BitStringExpr must be an expression, which evaluates to a - bitstring.
    - A filter is an expression, which evaluates to - true or false. -
    + Qualifier is either a generator or a + filter.

    + +

    Bit string comprehensions construct bit strings or binaries. + They have the following syntax:

    +
    +<< BitStringExpr || Qualifier1, . . ., QualifierN >>
    + +

    BitStringExpr is an expression that evaluates to a bit string. + If BitStringExpr is a function call, it must be + enclosed in parentheses. Each Qualifier is either a + generator or a filter.

    + +

    Map comprehensions construct maps. They have the following syntax:

    +
    +#{KeyExpr => ValueExpr || Qualifier1, . . ., QualifierN}
    +

    Here, KeyExpr and ValueExpr are arbitrary + expressions, and each Qualifier is either a + generator or a filter.

    + +

    Map comprehensions and map generators were introduced + in Erlang/OTP 26.

    + +

    There are three kinds of generators.

    + +

    A list generator has the following syntax:

    + +
    +Pattern <- ListExpr
    + +

    where ListExpr is an expression that evaluates to a + list of terms.

    + +

    A bit string generator has the following syntax:

    + +
    +BitstringPattern <= BitStringExpr
    + +

    where BitStringExpr is an expression that evaluates to a + bit string.

    + +

    A map generator has the following syntax:

    + +
    +KeyPattern := ValuePattern <- MapExpression
    + +

    where MapExpr is an expression that evaluates to a map, + or a map iterator obtained by calling maps:iterator/1 or + maps:iterator/2.

    + +

    A filter is an expression that evaluates to + true or false.

    +

    The variables in the generator patterns shadow previously bound variables, including variables bound in a previous generator pattern.

    -

    A list comprehension returns a list, where the elements are the + +

    Variables bound in a generator expression are not visible outside the expression:

    + +
    +1> [{E,L} || E <- L=[1,2,3]].
    +* 1:5: variable 'L' is unbound
    + +

    A list comprehension returns a list, where the list elements are the result of evaluating Expr for each combination of generator - list elements and bit string generator elements, for which all + elements for which all filters are true.

    + +

    A bit string comprehension returns a bit string, which is + created by concatenating the results of evaluating BitStringExpr for + each combination of bit string generator elements for which all filters are true.

    -

    Example:

    + +

    A map comprehension returns a map, where the + map elements are the result of evaluating KeyExpr and + ValueExpr for each combination of generator elements for + which all filters are true. If the key expressions are not unique, + the last occurrence is stored in the map.

    + +

    Examples:

    + +

    Multiplying each element in a list by two:

     1> [X*2 || X <- [1,2,3]].
     [2,4,6]
    -

    When there are no generators or bit string generators, a list comprehension - returns either a list with one element (the result of evaluating Expr) - if all filters are true or an empty list otherwise.

    + +

    Multiplying each byte in a binary by two, returning a list:

    +
    +1> [X*2 || <<X>> <= <<1,2,3>> >>.
    +[2,4,6]
    + +

    Multiplying each byte in a binary by two:

    + +
    +1> << <<(X*2)>> || <<X>> <= <<1,2,3>> >>.
    +<<2,4,6>>
    + +

    Multiplying each element in a list by two, returning a binary:

    + +
    +1> << <<(X*2)>> || X <- [1,2,3]].
    +<<2,4,6>>
    + +

    Creating a mapping from an integer to its square:

    +
    +1> #{X => X*X || X <- [1,2,3]}.
    +#{1 => 1,2 => 4,3 => 9}
    + +

    Multiplying the value of each element in a map by two:

    +
    +1> #{K => 2*V || K := V <- #{a => 1,b => 2,c => 3}}.
    +#{a => 2,b => 4,c => 6}
    + +

    Filtering a list, keeping odd numbers:

    +
    +1> [X || X <- [1,2,3,4,5], X rem 2 =:= 1].
    +[1,3,5]
    + +

    Filtering a list, keeping only elements that match:

    +
    +1> [X || {_,_}=X <- [{a,b}, [a], {x,y,z}, {1,2}]].
    +[{a,b},{1,2}]
    + +

    Combining elements from two list generators:

    +
    +1> [{P,Q} || P <- [a,b,c], Q <- [1,2]].
    +[{a,1},{a,2},{b,1},{b,2},{c,1},{c,2}]
    +
    + +

    More examples are provided in + + Programming Examples.

    + +

    When there are no generators, a comprehension returns either a + term constructed from a single element (the result of evaluating + Expr) if all filters are true, or a term constructed from + no elements (that is, [] for list comprehension, + <<>> for a bit string comprehension, and + #{} for a map comprehension).

    Example:

     1> [2 || is_integer(2)].
     [2]
     2> [x || is_integer(x)].
     []
    -

    More examples are provided in - - Programming Examples.

    -
    +

    What happens when the filter expression does not evaluate to + a boolean value depends on the expression:

    -
    - Bit String Comprehensions - -

    Bit string comprehensions are - analogous to List Comprehensions. They are used to generate bit strings - efficiently and succinctly.

    -

    Bit string comprehensions are written with - the following syntax:

    -
    -<< BitStringExpr || Qualifier1,...,QualifierN >>
    -

    BitStringExpr is an expression that evalutes to a bit - string. If BitStringExpr is a function call, it must be - enclosed in parentheses. Each Qualifier is either a - generator, a bit string generator or a filter.

    - - A generator is written as:

    -   .

    - ListExpr must be an expression that evaluates to a - list of terms.
    - A bit string generator is written as:

    - -   .

    -BitStringExpr must be an expression that evaluates to a - bitstring.
    - A filter is an expression that evaluates to - true or false. + +

    If the expression is a guard expression, failure + to evaluate or evaluating to a non-boolean value is equivalent + to evaluating to false.

    + +

    If the expression is not a guard expression and + evaluates to a non-Boolean value Val, an exception + {bad_filter, Val} is triggered at runtime. If the + evaluation of the expression raises an exception, it is not + caught by the comprehension.

    -

    The variables in the generator patterns shadow previously bound variables, - including variables bound in a previous generator pattern.

    -

    A bit string comprehension returns a bit string, which is - created by concatenating the results of evaluating BitString - for each combination of bit string generator elements, for which all - filters are true.

    -

    Example:

    + +

    Examples (using a guard expression as filter):

    +
    -1> << << (X*2) >> ||
    -<<X>> <= << 1,2,3 >> >>.
    -<<2,4,6>>
    -

    More examples are provided in - - Programming Examples.

    +1> List = [1,2,a,b,c,3,4]. +[1,2,a,b,c,3,4] +2> [E || E <- List, E rem 2]. +[] +3> [E || E <- List, E rem 2 =:= 0]. +[2,4] + +

    Examples (using a non-guard expression as filter):

    + +
    +1> List = [1,2,a,b,c,3,4].
    +[1,2,a,b,c,3,4]
    +2> FaultyIsEven = fun(E) -> E rem 2 end.
    +#Fun<erl_eval.42.17316486>
    +3> [E || E <- List, FaultyIsEven(E)].
    +** exception error: bad filter 1
    +4> IsEven = fun(E) -> E rem 2 =:= 0 end.
    +#Fun<erl_eval.42.17316486>
    +5> [E || E <- List, IsEven(E)].
    +** exception error: an error occurred when evaluating an arithmetic expression
    +     in operator  rem/2
    +        called as a rem 2
    +6> [E || E <- List, is_integer(E), IsEven(E)].
    +[2,4]
    @@ -1675,7 +2214,7 @@ end Expressions that construct atoms, integer, floats, lists, tuples, records, binaries, and maps Expressions that update a map - The record epxressions Expr#Name.Field and #Name.Field + The record expressions Expr#Name.Field and #Name.Field Calls to the BIFs specified in tables Type Test BIFs and Other BIFs Allowed in Guard Expressions Term comparisons @@ -1773,6 +2312,12 @@ end map_size(Map) + + max(A, B) + + + min(A, B) + node() @@ -1800,6 +2345,9 @@ end Other BIFs Allowed in Guard Expressions +

    The min/2 and max/2 BIFs are allowed to be + used in guards from Erlang/OTP 26.

    +

    If an arithmetic expression, a Boolean expression, a short-circuit expression, or a call to a guard BIF fails (because of invalid arguments), the entire guard fails. If the guard was @@ -1811,7 +2359,7 @@ end

    Operator Precedence -

    Operator precedence in falling priority:

    +

    Operator precedence in descending order:

    : @@ -1827,49 +2375,68 @@ end / * div rem band and - Left associative + Left-associative + - bor bxor bsl bsr or xor - Left associative + Left-associative ++ -- - Right associative + Right-associative == /= =< < >= > =:= =/= -   + Non-associative andalso -   + Left-associative orelse + Left-associative + + + catch   = ! - Right associative + Right-associative - catch -   + ?= + Non-associative Operator Precedence
    +

    Before Erlang/OTP 24, the catch operator had the lowest + precedence.

    +

    The = operator in the table is the + match operator. + The character = can also denote the + compound pattern operator, + which can only be used in patterns.

    +

    ?= is restricted in that it can only be used at + the top-level inside a maybe block.

    +

    When evaluating an expression, the operator with the highest - priority is evaluated first. Operators with the same priority - are evaluated according to their associativity.

    -

    Example:

    -

    The left associative arithmetic operators are evaluated left to + precedence is evaluated first. Operators with the same precedence + are evaluated according to their associativity. Non-associative + operators cannot be combined with operators of the same precedence.

    +

    Examples:

    +

    The left-associative arithmetic operators are evaluated left to right:

     6 + 5 * 4 - 3 / 2 evaluates to
     6 + 20 - 1.5 evaluates to
     26 - 1.5 evaluates to
     24.5
    + +

    The non-associative operators cannot be combined:

    +
    +1> 1 < X < 10.
    +* 1:7: syntax error before: '<'
    - diff --git a/system/doc/reference_manual/features.xml b/system/doc/reference_manual/features.xml new file mode 100644 index 000000000000..e3b12742c6ac --- /dev/null +++ b/system/doc/reference_manual/features.xml @@ -0,0 +1,211 @@ + + + + +
    + + 20222023 + Ericsson AB. 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. + + + + Features + + + + + features.xml +
    +

    + + Introduced in OTP 25, Erlang has the concept of selectable features. + A feature can change, add or remove behaviour of the language and/or + runtime system. Examples can include +

    + + Adding new syntactical constructs to the language + Change the semantics of an existing construct + Change the behaviour of some runtime aspect + +

    + A feature will start out with a status of experimental part of OTP, + making it possible to try out for users and give feedback. The + possibility to try out features is enabled by options to the + compiler, directives in a module and options to the runtime system. + Even when a feature is not experimental it will still be possible to + enable or disable it. This makes it possible to adapt a code base + at a suitable pace instead of being forced when changing to a new + release. +

    +

    + The status of a feature will eventually end up as being either a + permanent part of OTP or rejected, being removed and no longer + selectable. +

    + +
    + Life cycle of features +

    A feature is in one of four possible states:

    + + Experimental + The initial state, is meant for trying out and collecting + feedback. The feature can be enabled but is disabled by + default. + Approved + The feature has been finalised and is now part of OTP. By + default it is enabled, but can be disabled. + Permanent + The feature is now a permanent part of OTP. It can no + longer be disabled. + Rejected + The feature never reached the approved state and will not + be part of OTP. It cannot be enabled. + +

    + After leaving the experimental state, a feature can enter any of + the other three states, and if the next state is approved, the + feature will eventually end up in the permanent state. A feature + can change state only in connection with a release. +

    +

    + A feature may be in the approved state for several releases. +

    + + + State + Default + Configurable + Available + + + Experimental + disabled + yes + yes + + + Approved + enabled + yes + yes + + + Permanent + enabled + no + yes + + + Rejected + disabled + no + no + + Feature States +
    + + Being configurable means the possibility to enable or + disable the feature by means of compiler options and directives + in the file being compiled. + Being available can be seen using the + FEATURE_AVAILABLE macro. + +
    + +
    + Enabling and Disabling Features +

    To use a feature that is in the experimental state, it has to + be enabled during compilation. This can be done in a number of + different ways: +

    + + Options to erlc + Options -enable-feature + and -disable-feature + can be used to enable or disable individal features. + Compiler options + The compiler option {feature, + <feature>, enable|disable} can be used either + as a +<term> option to erlc or in the options + argument to functions in the compile module. + The feature directive + Inside a prefix of a module, one can use a -feature(<feature>, + enable|disable) directive. This is the preferred + method of enabling and disabling features. + + +

    In Erlang/OTP 25, in order to load a module with a feature + enabled, it was necessary to also enable the feature in the runtime. + This was done using option -enable-feature to + erl. This requirement was removed in Erlang/OTP 26.

    +
    +
    + +
    + Preprocessor Additions +

    + To allow for conditional compilation during transitioning of a + code base and/or trying out experimental features feature + predefined macros ?FEATURE_AVAILABLE(Feature) and + ?FEATURE_ENABLED(Feature) are available. +

    +
    + +
    + Information about Existing Features +

    + The module erl_features erl_features exports + a number of functions that can be used to obtain information about + current features as well as the features used when compiling a + module. +

    +

    One can also use the erlc options -list-features + and -describe-feature + <feature> to get information about existing + features. +

    +

    + Additionally, there is the compiler option + warn_keywords + that can be used to find atoms in the code base that might + collide with keywords in features not yet enabled. +

    +
    + +
    + Existing Features +

    + The following configurable features exist: +

    + + maybe_expr (experimental) + + Implementation of the maybe expression + proposed in EEP 49. + +
    +
    diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index f823c6921ba2..79b8132fb0d2 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -95,10 +95,15 @@ Reserved Words

    The following are reserved words in Erlang:

    after and andalso band begin bnot bor bsl bsr bxor case catch - cond div end fun if let not of or orelse receive rem try + cond div end fun if let maybe not of or orelse receive rem try when xor

    Note: cond and let, while reserved, - are currently not used by the language.

    + are currently not used by the language.

    +

    maybe is a reserved word only if feature + maybe_expr is enabled. In Erlang/OTP 25 and 26, + maybe_expr is disabled by default. Starting from + Erlang/OTP 27, maybe_expr is enabled by + default.

    diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index 0943dbd56db8..ab503f740e6a 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -134,7 +134,8 @@ bar(X) ->
    Predefined Macros -

    The following macros are predefined:

    +

    + The following macros are predefined:

    ?MODULE The name of the current module. @@ -154,7 +155,20 @@ bar(X) -> The OTP release that the currently executing ERTS application is part of, as an integer. For details, see erlang:system_info(otp_release). - This macro was introduced in OTP release 21. +

    The ?OTP_RELEASE macro was introduced in Erlang/OTP 21.

    + ?FEATURE_AVAILABLE(Feature) + Expands to true if the feature + Feature is available. The feature might or might not + be enabled. +

    The ?FEATURE_AVAILABLE() macro was introduced in Erlang/OTP 25.

    +
    + ?FEATURE_ENABLED(Feature) + Expands to true if the feature + Feature is enabled. +

    The ?FEATURE_ENABLED() macro was introduced in Erlang/OTP 25.

    +
    @@ -163,7 +177,8 @@ bar(X) ->

    It is possible to overload macros, except for predefined macros. An overloaded macro has more than one definition, each with a different number of arguments.

    -

    The feature was added in Erlang 5.7.5/OTP R13B04.

    +

    Support for overloading of macros was added in Erlang + 5.7.5/OTP R13B04.

    A macro ?Func(Arg1,...,ArgN) with a (possibly empty) list of arguments results in an error message if there is at least one definition of Func with arguments, but none @@ -264,6 +279,27 @@ or select code depending on release.

    +
    + + The -feature() directive + + + +

    + The directive -feature(FeatureName, enable | disable) can + be used to enable or disable the feature + FeatureName. This is the preferred way of enabling + (disabling) features, although it is possible to do it with + options to the compiler as well. +

    +

    + Note that the -feature(..) directive may only appear + before any syntax is used. In practice this means it should + appear before any -export(..) or record definitions. +

    +
    +
    -error() and -warning() directives @@ -306,8 +342,8 @@ version() -> ?VERSION. % erlc t.erl t.erl:5: Warning: -warning("Macro VERSION not defined -- using default version."). -

    The -error() and -warning() directives were added - in OTP 19.

    +

    The -error() and -warning() directives were added + in Erlang/OTP 19.

    diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index f5ea7d158083..360345d4adde 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -129,6 +129,35 @@ fact(0) -> % | Running a Function When a Module is Loaded.

    + -nifs(Functions). + +

    + Specifies which of the functions, defined within the module, that + may be loaded as NIFs with + erlang:load_nif/2. +

    +

    + Functions is a list + [Name1/Arity1, ..., NameN/ArityN], where each + NameI is an atom and ArityI an integer. +

    +

    While not strictly necessary, it is recommended to use -nifs() + attribute in any module that load NIFs, to allow the compiler to make + better decisions regarding optimizations.

    +

    There is no need to add -nifs([]) in modules that do not + load NIFs. The lack of any call to + erlang:load_nif/2, + from within the module, is enough for the compiler to draw the + same conclusion. +

    + +

    + The special meaning for the -nifs() attribute was + introduced in Erlang/OTP 25.0. In previous releases, the + -nifs() was accepted, but had no special meaning. +

    +
    +
    @@ -220,6 +249,30 @@ behaviour_info(callbacks) -> Callbacks.
    +
    + + The feature directive + + +

    + While not a module attribute, but rather a directive (since it + might affect syntax), there is the -feature(..) + directive used for enabling and disabling features. +

    +

    + The syntax is similar to that of an attribute, but has two + arguments: +

    +
    +-feature(FeatureName, enable | disable).
    +

    + Note that the feature directive + can only appear in a prefix of the module. +

    +
    +
    Comments

    Comments can be placed anywhere in a module except within strings @@ -290,9 +343,7 @@ behaviour_info(callbacks) -> Callbacks. md5 -

    Returns a binary representing the MD5 checksum of the module. - If the module has native code loaded, this will be the MD5 of the - native code, not the BEAM bytecode.

    +

    Returns a binary representing the MD5 checksum of the module.

    exports diff --git a/system/doc/reference_manual/opaques.xml b/system/doc/reference_manual/opaques.xml new file mode 100644 index 000000000000..f7d633781c07 --- /dev/null +++ b/system/doc/reference_manual/opaques.xml @@ -0,0 +1,146 @@ + + + + +
    + + 2021 + 2023 + Ericsson AB. 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. + + + + Opaques + Max Heiber + + + + opaques.xml +
    + +
    + Opaque Type Aliases +

    The main use case for opacity in Erlang is to hide the + implementation of a data type, enabling evolving the API while + minimizing the risk of breaking consumers. The runtime does not + check opacity. Dialyzer provides some opacity-checking, but the + rest is up to convention. +

    +

    + This document explains what Erlang opacity is (and the + trade-offs involved) via the example of the sets:set() + data type. This type was defined in the sets + module like this: +

    + -opaque set(Element) :: #set{segs :: segs(Element)}. +

    OTP 24 changed the definition to the following in + this commit. +

    + -opaque set(Element) :: #set{segs :: segs(Element)} | #{Element => ?VALUE}. +

    + And this change was safer and more backwards-compatible than if + the type had been defined with -type instead of + -opaque. Here is why: when a module defines an + -opaque, the contract is that only the defining module + should rely on the definition of the type: no other modules + should rely on the definition. +

    +

    + This means that code that pattern-matched on + set + as a record/tuple technically broke the contract, and opted in to being potentially broken when the definition of + set() + changed. Before OTP 24, this code printed + ok. + In OTP 24 it may error: +

    + +case sets:new() of + Set when is_tuple(Set) -> + io:format("ok") +end. + +

    + When working with an opaque defined in another module, here are some recommendations: +

    + + + + Don't examine the underlying type using pattern-matching, guards, or functions that reveal the type, such as + tuple_size/1 + . + + + Instead, use functions provided by the module for working with the type. For example, + sets + module provides + sets:new/0, + sets:add/2, + sets:is_element/2, and so on. + + + sets:set(a) + is a subtype of + sets:set(a | b) + and not the other way around. Generally, you can rely on the property that + the_opaque(T) + is a subtype of + the_opaque(U) + when T is a subtype of U. + + +

    + When defining your own opaques, here are some recommendations: +

    + + + Since consumers are expected to not rely on the definition of + the opaque type, you must provide functions for constructing, + querying, and deconstructing instances of your opaque type. For + example, sets can be constructed with sets:new/0, + sets:from_list/1, sets:add/2, queried with + sets:is_element/2, and deconstructed + withsets:to_list/1. + + + Don't define an opaque with a type variable in parameter + position. This breaks the normal and expected behavior that + (for example) my_type(a) is a subtype of my_type(a | + b) + + + Add specs to exported functions that use the opaque type + + +

    Note that opaques can be harder to work with for consumers, + since the consumer is expected not to pattern-match and must + instead use functions that the author of the opaque type provides + to use instances of the type.

    +

    + Also, opacity in Erlang is skin-deep: the runtime does not + enforce opacity-checking. So now that sets are implemented in + terms of maps, an is_map/1 check on a set will + pass. The opacity rules are only enforced by convention and by + additional tooling such as Dialyzer, and this enforcement is not + total. A determined consumer of sets can still reveal the + structure of the set, for example by printing, serializing, or + using a set as a term() and inspecting it via functions + like is_map/1 or maps:get/2. Also, Dialyzer must make + some approximations. +

    +
    +
    diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml index 3d3115797336..ec2e3e0306fe 100644 --- a/system/doc/reference_manual/part.xml +++ b/system/doc/reference_manual/part.xml @@ -4,7 +4,7 @@
    - 20032016 + 20032022 Ericsson AB. All Rights Reserved. @@ -35,10 +35,12 @@ + + diff --git a/system/doc/reference_manual/ports.xml b/system/doc/reference_manual/ports.xml index 26ecc084c507..a0d3966f35ac 100644 --- a/system/doc/reference_manual/ports.xml +++ b/system/doc/reference_manual/ports.xml @@ -4,7 +4,7 @@
    - 20042021 + 20042023 Ericsson AB. All Rights Reserved. @@ -103,12 +103,9 @@ Port by sending and receiving messages. (In fact, any process can send the messages to the port, but the port owner must be identified in the message).

    -

    As of Erlang/OTP R16, messages sent to ports are delivered truly - asynchronously. The underlying implementation previously - delivered messages to ports synchronously. Message passing has - however always been documented as an asynchronous operation. Hence, - this is not to be an issue for an Erlang program communicating - with ports, unless false assumptions about ports have been made.

    +

    Messages sent to ports are delivered asynchronously.

    +

    Before Erlang/OTP 16, messages to ports were + delivered synchronously.

    In the following tables of examples, Data must be an I/O list. An I/O list is a binary or a (possibly deep) list of binaries or integers in the range 0..255:

    diff --git a/system/doc/reference_manual/processes.xml b/system/doc/reference_manual/processes.xml index 4c8c5f7e3f3f..4f1228e2104f 100644 --- a/system/doc/reference_manual/processes.xml +++ b/system/doc/reference_manual/processes.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -680,7 +680,10 @@ spawn(Module, Name, Args) -> pid() while it can be trapped if the signal was sent due to a link.

    - Blocking Signaling Over Distribution + + Blocking Signaling Over Distribution + +

    When sending a signal over a distribution channel, the sending @@ -690,18 +693,34 @@ spawn(Module, Name, Args) -> pid() size of the output buffer for the channel reach the distribution buffer busy limit, processes sending on the channel will be suspended until the size of the buffer shrinks below the limit. - The size of the limit can be inspected by calling +

    +

    + Depending on the reason for why the buffer got full, the time it + takes before suspended processes are resumed can vary very + much. A consequence of this can, for example, be that a + timeout in a call to + erpc:call() + is significantly delayed. +

    +

    + Since this functionality has been present for so long, it is not + possible to remove it, but it is possible to enable fully + asynchronous distributed signaling on a per process level + using + process_flag(async_dist, Bool) which can be + used to solve problems occuring due to blocking signaling. + However, note that you need to make sure that flow control for + data sent using fully asynchronous distributed signaling + is implemented, or that the amount of such data is known to + always be limited; otherwise, you may get into a situation with + excessive memory usage. +

    +

    + The size of the distribution buffer busy limit can be + inspected by calling erlang:system_info(dist_buf_busy_limit). - Since this functionality has been present for so long, it is not - possible to remove it, but it is possible to increase the limit - to a point where it more or less never is reached using the - erl command line argument - +zdbbl. Note - that if you do raise the limit like this, you need to take care - of flow control yourself to ensure that you do not get into a - situation with excessive memory usage. -

    +

    @@ -798,7 +817,7 @@ spawn(Module, Name, Args) -> pid()

    noproc in case no process or port was - found when setting up a link in a preceeding + found when setting up a link in a preceding call to the link(PidOrPort) BIF. The process or port identified as sender diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml index d5712bded023..f6ff4173ae69 100644 --- a/system/doc/reference_manual/records.xml +++ b/system/doc/reference_manual/records.xml @@ -4,7 +4,7 @@

    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -151,25 +151,23 @@ is_person(_P) ->
    Nested Records -

    Beginning with Erlang/OTP R14, parentheses when accessing or updating nested - records can be omitted. Assume the following record - definitions:

    +

    Assume the following record definitions:

     -record(nrec0, {name = "nested0"}).
     -record(nrec1, {name = "nested1", nrec0=#nrec0{}}).
     -record(nrec2, {name = "nested2", nrec1=#nrec1{}}).
     
    -N2 = #nrec2{},
    -    
    -

    Before R14, parentheses were needed as follows:

    -
    -"nested0" = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
    -N0n = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0{name = "nested0a"},
    -    
    -

    Since R14, the following can also be written:

    +N2 = #nrec2{}, +

    Accessing or updating nested records can be written without parentheses:

     "nested0" = N2#nrec2.nrec1#nrec1.nrec0#nrec0.name,
    -N0n = N2#nrec2.nrec1#nrec1.nrec0#nrec0{name = "nested0a"},
    + N0n = N2#nrec2.nrec1#nrec1.nrec0#nrec0{name = "nested0a"}, +

    which is equivalent to:

    +
    +"nested0" = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
    +N0n = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0{name = "nested0a"},
    +

    Before Erlang/OTP R14, parentheses were necessary when accessing or updating nested + records.

    diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 0e3d9090991d..8f3ba3b25a22 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -4,7 +4,7 @@
    - 20032021 + 20032023 Ericsson AB. All Rights Reserved. @@ -83,17 +83,32 @@

      atom() | integer()

    - Because of subtype relations that exist between types, types + Because of subtype relations that exist between types, all types, + except dynamic(), form a lattice where the top-most element, any(), denotes the set of all Erlang terms and the bottom-most element, none(), denotes the empty set of terms.

    +

    + To facilitate + gradual typing of Erlang, the type `dynamic()` is provided. + It is similar to + Any + in Python, + any + in TypeScript and + dynamic + in Hack. `any()` and `dynamic()` interact with + success typing + the same way, so Dialyzer doesn't distinguish between them. +

    The set of predefined types and the syntax for types follows:

    Integer values are either integer or character literals or expressions - consisting of possibily nested unary or binary operations that evaluate to + consisting of possibly nested unary or binary operations that evaluate to an integer. Such expressions can also be used in bit strings and ranges.

    @@ -314,11 +329,6 @@ Additional built-in types -

    - Users are not allowed to define types with the same names as the - predefined or built-in ones. This is checked by the compiler and - its violation results in a compilation error. -

    The following built-in list types also exist, @@ -345,7 +355,35 @@ This is described in Type Information in Record Declarations.

    + +
    + Redefining built-in types +

    + Starting from Erlang/OTP 26, is is permitted to define a type + having the same name as a built-in type.

    +

    It is recommended to + avoid deliberately reusing built-in names because it can be + confusing. However, when an Erlang/OTP release introduces a new + type, code that happened to define its own type having the same + name will continue to work. +

    + +

    As an example, imagine that the Erlang/OTP 42 release introduces + a new type gadget() defined like this:

    + +
    +  -type gadget() :: {'gadget', reference()}.
    + +

    Further imagine that some code has its own (different) + definition of gadget(), for example:

    + +
    +  -type gadget() :: #{}.
    + +

    Since redefinitions are allowed, the code will still compile (but + with a warning), and Dialyzer will not emit any additional warnings.

    +
    Type Declarations of User-Defined Types @@ -411,6 +449,7 @@ types are not accessible by other modules anyway - and is always to be exported.

    +

    Read more on Opaques

    @@ -440,7 +479,7 @@ This is checked by the compiler and results in a compilation error if a violation is detected.

    - +

    Before Erlang/OTP 19, for fields without initial values, the singleton type 'undefined' was added to all declared types. In other words, the following two record declarations had identical @@ -457,7 +496,7 @@ This is no longer the case. If you require 'undefined' in your record field type, you must explicitly add it to the typespec, as in the 2nd example.

    -
    +

    Any record, containing type information or not, once defined, can be used as a type using the following syntax: @@ -537,8 +576,7 @@ ; (T4, T5) -> T6.

    A current restriction, which currently results in a warning - (not an error) by the compiler, is that the domains of - the argument types cannot overlap. + by Dialyzer, is that the domains of the argument types cannot overlap. For example, the following specification results in a warning:

    @@ -607,5 +645,13 @@
           of the following form:
         

      -spec my_error(term()) -> no_return().
    + + +

    Erlang uses the shorthand version _ as an anonymous type variable + equivalent to term() or any(). For example, the following function

    +
      -spec Function(string(), _) -> string().
    +

    is equivalent to:

    +
      -spec Function(string(), any()) -> string().
    +
    diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk index 92d232b6289f..8e2af096991b 100644 --- a/system/doc/reference_manual/xmlfiles.mk +++ b/system/doc/reference_manual/xmlfiles.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2018. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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. @@ -27,9 +27,11 @@ REF_MAN_CHAPTER_FILES = \ macros.xml \ records.xml \ errors.xml \ + features.xml \ processes.xml \ distributed.xml \ code_loading.xml \ ports.xml \ character_set.xml \ - typespec.xml + typespec.xml \ + opaques.xml diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile index 8657da0e2cc2..0fdf0f6a328e 100644 --- a/system/doc/system_architecture_intro/Makefile +++ b/system/doc/system_architecture_intro/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2020. All Rights Reserved. +# Copyright Ericsson AB 1997-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/system_architecture_intro # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/system_architecture_intro" +RELSYSDIR = $(RELEASE_PATH)/doc/system_architecture_intro # ---------------------------------------------------- # Target Specs @@ -94,7 +94,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile index 00b220339449..f4df54bda345 100644 --- a/system/doc/system_principles/Makefile +++ b/system/doc/system_principles/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2020. All Rights Reserved. +# Copyright Ericsson AB 1996-2023. 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. @@ -32,7 +32,7 @@ XMLDIR := $(XMLDIR)/system_principles # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc/system_principles" +RELSYSDIR = $(RELEASE_PATH)/doc/system_principles # ---------------------------------------------------- # Target Specs @@ -95,7 +95,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_html_spec: html $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTMLDIR)/*.html \ - $(RELSYSDIR) + "$(RELSYSDIR)" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml index d0c6f5980765..c731e7fb66f3 100644 --- a/system/doc/system_principles/system_principles.xml +++ b/system/doc/system_principles/system_principles.xml @@ -4,7 +4,7 @@
    - 19962020 + 19962023 Ericsson AB. All Rights Reserved. @@ -107,7 +107,7 @@ init:stop() the applications Kernel and STDLIB. start_sasl.boot - Loads the code for and starts the applications Kernel, STDLIB, and - SASL). + SASL. no_dot_erlang.boot - Loads the code for and starts the applications Kernel and STDLIB. Skips loading the file .erlang. Useful for scripts and diff --git a/system/doc/system_principles/upgrade.xml b/system/doc/system_principles/upgrade.xml index 67b58f45ba57..b7fba0944fbe 100644 --- a/system/doc/system_principles/upgrade.xml +++ b/system/doc/system_principles/upgrade.xml @@ -4,7 +4,7 @@
    - 20142021 + 20142023 Ericsson AB. All Rights Reserved. @@ -92,7 +92,7 @@
    Applications that Still do Not Allow Code Upgrade -

    A few applications, such as HiPE, do not support upgrade. +

    A few applications, such as erl_interface, do not support upgrade. This is indicated by an application upgrade file containing only {Vsn,[],[]}. Any attempt at creating a release upgrade file with such input fails. The only way to force an upgrade involving diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile index e294d0b0a78c..fd4b4cd6162e 100644 --- a/system/doc/top/Makefile +++ b/system/doc/top/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2021. All Rights Reserved. +# Copyright Ericsson AB 1999-2023. 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. @@ -31,7 +31,7 @@ APPLICATION=otp-system-documentation # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- -RELSYSDIR = "$(RELEASE_PATH)/doc" +RELSYSDIR = $(RELEASE_PATH)/doc GIF_FILES = @@ -102,14 +102,31 @@ PDFREFDIR= pdf TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf TOPDOC=true +sp := $(subst ,, ) + +## qs translates ' ' to '\ ', sq translates '\ ' to ' ' +## These function are used when the make target is a path that can +## contain spaces. This is needed a the target 'foo bar:' needs to be +## written as 'foo\ bar:' in order for make to interpret it as a single +## target. Unfortunately, when this is done $@ will contain '\ ', which +## means that we have to use sq to remove the escape again. A small example +## looks like this: +## +## $(call qs, /path/with space/file.o): $(call qs, /path/with space/file.c) +## gcc -c -o "$(call sq, $@)" "$(call sq, $^)" +qs = $(subst $(sp),\$(sp),$1) +sq = $(subst \$(sp),$(sp),$1) + ifdef RELEASE_PATH INST_TYPE=rel INST_TYPE_SRC_DIR=$(RELEASE_PATH) # We build to the 'temporary' dir in order to be able to install # results using INSTALL_DATA (in order to get correct access # rights on installed files) +# The temporary folder needs to be in the released system as we do +# not know if we have write permissions in the source release. INST_TYPE_DEST_DIR=$(RELSYSDIR)/temporary -INST_TYPE_DEST_DIR_DEP=$(INST_TYPE_DEST_DIR) +INST_TYPE_DEST_DIR_DEP=$(call qs,$(INST_TYPE_DEST_DIR)) INST_TYPE_JS_DEST_DIR=$(INST_TYPE_DEST_DIR) INST_TYPE_VSN_FILE=$(INST_TYPE_DEST_DIR)/OTP_VERSION else @@ -131,17 +148,17 @@ EBIN = ebin INDEX_SCRIPT = $(EBIN)/erl_html_tools.$(EMULATOR) INDEX_SRC = src/erl_html_tools.erl -INDEX_HTML=$(INST_TYPE_DEST_DIR)/index.html -APPLICATIONS_HTML=$(INST_TYPE_DEST_DIR)/applications.html +INDEX_HTML=$(call qs,$(INST_TYPE_DEST_DIR)/index.html) +APPLICATIONS_HTML=$(call qs,$(INST_TYPE_DEST_DIR)/applications.html) INDEX_FILES = $(INDEX_HTML) $(APPLICATIONS_HTML) -JAVASCRIPT = $(INST_TYPE_JS_DEST_DIR)/erlresolvelinks.js +JAVASCRIPT = $(call qs,$(INST_TYPE_JS_DEST_DIR)/erlresolvelinks.js) JAVASCRIPT_BUILD_SCRIPT = $(EBIN)/erlresolvelinks.$(EMULATOR) JAVASCRIPT_BUILD_SCRIPT_SRC = src/erlresolvelinks.erl MAN_INDEX_SCRIPT = $(EBIN)/otp_man_index.$(EMULATOR) MAN_INDEX_SRC = src/otp_man_index.erl -MAN_INDEX = $(INST_TYPE_DEST_DIR)/man_index.html +MAN_INDEX = $(call qs,$(INST_TYPE_DEST_DIR)/man_index.html) GLOSSARY = $(HTMLDIR)/glossary.html GLOSSARY_SRC = $(ERL_TOP)/system/internal_tools/doctools/src/glossary.erl @@ -156,18 +173,18 @@ TEMPLATES = \ $(INDEX_SCRIPT): $(INDEX_SRC) $(ERLC) -o$(EBIN) +warn_unused_vars $< -$(INST_TYPE_DEST_DIR)/OTP_VERSION: $(INST_TYPE_DEST_DIR_DEP) +$(call qs,$(INST_TYPE_DEST_DIR)/OTP_VERSION): $(INST_TYPE_DEST_DIR_DEP) if test -f "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/OTP_VERSION"; then \ - $(CP) "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/OTP_VERSION" $@; \ + $(CP) "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/OTP_VERSION" "$(call sq,$@)"; \ else \ - $(CP) $(ERL_TOP)/OTP_VERSION $@; \ + $(CP) "$(ERL_TOP)/OTP_VERSION" "$(call sq,$@)"; \ fi # We don't list toc_*.html as targets because we don't know -$(INDEX_HTML) + $(APPLICATIONS_HTML): $(INST_TYPE_DEST_DIR_DEP) $(INDEX_SCRIPT) $(TEMPLATES) $(INST_TYPE_VSN_FILE) +$(INDEX_HTML) + $(APPLICATIONS_HTML): $(INST_TYPE_DEST_DIR_DEP) $(INDEX_SCRIPT) $(TEMPLATES) $(call qs,$(INST_TYPE_VSN_FILE)) echo "Generating index $@" - $(ERL) -noshell -pa $(EBIN) -s erl_html_tools top_index $(INST_TYPE) \ - $(INST_TYPE_SRC_DIR) $(INST_TYPE_DEST_DIR) \ + $(ERL) +pc unicode -noshell -pa $(EBIN) -s erl_html_tools top_index $(INST_TYPE) \ + "$(INST_TYPE_SRC_DIR)" "$(INST_TYPE_DEST_DIR)" \ `cat "$(INST_TYPE_VSN_FILE)"` -s erlang halt @@ -177,8 +194,8 @@ $(JAVASCRIPT_BUILD_SCRIPT): $(JAVASCRIPT_BUILD_SCRIPT_SRC) $(ERLC) -o$(EBIN) +warn_unused_vars $< $(JAVASCRIPT): $(INST_TYPE_DEST_DIR_DEP) $(JAVASCRIPT_BUILD_SCRIPT) - erl -noshell -pa $(EBIN) -run erlresolvelinks make $(ERL_TOP) \ - $(INST_TYPE_SRC_DIR) $(INST_TYPE_JS_DEST_DIR) -s erlang halt + $(ERL) +pc unicode -noshell -pa $(EBIN) -run erlresolvelinks make $(ERL_TOP) \ + "$(INST_TYPE_SRC_DIR)" "$(INST_TYPE_JS_DEST_DIR)" -s erlang halt #-------------------------------------------------------------------------- @@ -186,8 +203,8 @@ $(MAN_INDEX_SCRIPT): $(MAN_INDEX_SRC) $(ERLC) -o$(EBIN) +warn_unused_vars $< $(MAN_INDEX): $(INST_TYPE_DEST_DIR_DEP) $(MAN_INDEX_SCRIPT) - $(ERL) -noshell -pa $(EBIN) -s otp_man_index gen $(INST_TYPE) \ - $(INST_TYPE_SRC_DIR) $@ -s erlang halt + $(ERL) +pc unicode -noshell -pa $(EBIN) -s otp_man_index gen $(INST_TYPE) \ + "$(INST_TYPE_SRC_DIR)" "$(call sq,$@)" -s erlang halt #-------------------------------------------------------------------------- @@ -280,31 +297,31 @@ clean: # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk -$(RELSYSDIR)/temporary: - $(INSTALL_DIR) $(RELSYSDIR)/temporary +$(call qs,$(RELSYSDIR)/temporary): + $(INSTALL_DIR) "$(RELSYSDIR)/temporary" -$(RELSYSDIR)/docbuild: - $(INSTALL_DIR) $(RELSYSDIR)/docbuild +$(call qs,$(RELSYSDIR)/docbuild): + $(INSTALL_DIR) "$(RELSYSDIR)/docbuild" -release_man_spec: man $(RELSYSDIR)/docbuild +release_man_spec: man $(call qs,$(RELSYSDIR)/docbuild) -release_html_spec: html $(RELSYSDIR)/docbuild - $(INSTALL_DATA) $(MAN_INDEX) $(RELSYSDIR) - $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) $(RELSYSDIR)/docbuild - $(INSTALL_DIR) $(RELSYSDIR)/js - $(INSTALL_DATA) $(JAVASCRIPT) $(RELSYSDIR)/js - $(INSTALL_DATA) $(INDEX_FILES) $(RELSYSDIR) +release_html_spec: html $(call qs,$(RELSYSDIR)/docbuild) + $(INSTALL_DATA) $(MAN_INDEX) "$(RELSYSDIR)" + $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) "$(RELSYSDIR)/docbuild" + $(INSTALL_DIR) "$(RELSYSDIR)/js" + $(INSTALL_DATA) $(JAVASCRIPT) "$(RELSYSDIR)/js" + $(INSTALL_DATA) $(INDEX_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(INDEX_SCRIPT) $(JAVASCRIPT_BUILD_SCRIPT) \ $(INDEX_SRC) $(JAVASCRIPT_BUILD_SCRIPT_SRC) \ - $(TEMPLATES) $(RELSYSDIR)/docbuild + $(TEMPLATES) "$(RELSYSDIR)/docbuild" release_pdf_spec: pdf - $(INSTALL_DIR) $(RELSYSDIR)/pdf + $(INSTALL_DIR) "$(RELSYSDIR)/pdf" $(INSTALL_DATA) \ - $(TOP_PDF_FILE) $(RELSYSDIR)/pdf + $(TOP_PDF_FILE) "$(RELSYSDIR)/pdf" release_docs_spec: $(DOC_TARGETS:%=release_%_spec) $(INFO_FILES) $(INSTALL_DATA) $(INFO_FILES) "$(RELEASE_PATH)" - $(RM) -r $(RELSYSDIR)/temporary + $(RM) -r "$(RELSYSDIR)/temporary" release_spec: diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl index 5942861f0f09..59a487ce6332 100644 --- a/system/doc/top/src/erl_html_tools.erl +++ b/system/doc/top/src/erl_html_tools.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2021. All Rights Reserved. +%% Copyright Ericsson AB 2009-2023. 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. @@ -67,18 +67,18 @@ top_index(RootDir) when is_atom(RootDir) -> top_index(Source, RootDir, DestDir, OtpBaseVsn) -> - report("****\nRootDir: ~p", [RootDir]), - report("****\nDestDir: ~p", [DestDir]), - report("****\nOtpBaseVsn: ~p", [OtpBaseVsn]), + report("****\nRootDir: ~tp", [RootDir]), + report("****\nDestDir: ~tp", [DestDir]), + report("****\nOtpBaseVsn: ~tp", [OtpBaseVsn]), put(otp_base_vsn, OtpBaseVsn), Templates = find_templates(["","templates",DestDir]), - report("****\nTemplates: ~p", [Templates]), + report("****\nTemplates: ~tp", [Templates]), Bases = [{"../lib/", filename:join(RootDir,"lib")}, {"../", RootDir}], Groups = find_information(Source, Bases), - report("****\nGroups: ~p", [Groups]), + report("****\nGroups: ~tp", [Groups]), process_templates(Templates, DestDir, Groups). top_index_silent(RootDir, DestDir, OtpBaseVsn) -> @@ -97,7 +97,7 @@ top_index_silent(RootDir, DestDir, OtpBaseVsn) -> process_templates([], _DestDir, _Groups) -> report("\n", []); process_templates([Template | Templates], DestDir, Groups) -> - report("****\nIN-FILE: ~s", [Template]), + report("****\nIN-FILE: ~ts", [Template]), BaseName = filename:basename(Template, ".src"), case lists:reverse(filename:rootname(BaseName)) of "_"++_ -> @@ -127,7 +127,7 @@ process_multi_template_1([{Suffix,Group}|Gs], BaseName, Ext, Template, DestDir, process_multi_template_1([], _, _, _, _, _) -> ok. subst_file(Group, OutFile, Template, Info) -> - report("\nOUTFILE: ~s", [OutFile]), + report("\nOUTFILE: ~ts", [OutFile]), case subst_template(Group, Template, Info) of {ok,Text,_NewInfo} -> case file:open(OutFile, [write]) of @@ -135,10 +135,10 @@ subst_file(Group, OutFile, Template, Info) -> file:write(Stream, Text), file:close(Stream); Error -> - local_error("Can't write to file ~s: ~w", [OutFile,Error]) + local_error("Can't write to file ~ts: ~w", [OutFile,Error]) end; Error -> - local_error("Can't write to file ~s: ~w", [OutFile,Error]) + local_error("Can't write to file ~ts: ~w", [OutFile,Error]) end. @@ -203,11 +203,11 @@ get_app_paths(src, AppDirs, URL) -> {match, [V]} -> V; nomatch -> - exit(io_lib:format("No VSN variable found in ~s\n", + exit(io_lib:format("No VSN variable found in ~ts\n", [VsnFile])) end; {error, Reason} -> - exit(io_lib:format("~p : ~s\n", [Reason, VsnFile])) + exit(io_lib:format("~p : ~ts\n", [Reason, VsnFile])) end, AppURL = URL ++ App ++ "-" ++ VsnStr, {App, VsnStr, AppPath, AppURL ++ "/" ++ Sub1} @@ -261,7 +261,7 @@ find_application_infos([{App, Vsn, AppPath, IndexURL} | Paths]) -> case lists:keysearch("group", 1, Db) of {value, {_, G0}} -> % This value may be in two parts, - % tag and desciption + % tag and description case string:str(G0, " ") of 0 -> {list_to_atom(G0), ""}; diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index 963766d1c514..31c604145b48 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -2,13 +2,13 @@